From 991417aa3ba9a7f0a64ee3d19a06c1f468865130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 10 Nov 2022 16:07:47 +0100 Subject: [PATCH 0001/2777] winevulkan: Add vk.xml version 1.3.235. Proton's build system uses that so we don't have to download the file each build. --- dlls/winevulkan/vk.xml | 22879 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 22879 insertions(+) create mode 100644 dlls/winevulkan/vk.xml diff --git a/dlls/winevulkan/vk.xml b/dlls/winevulkan/vk.xml new file mode 100644 index 00000000000..f116cbff9a5 --- /dev/null +++ b/dlls/winevulkan/vk.xml @@ -0,0 +1,22879 @@ + + + +Copyright 2015-2022 The Khronos Group Inc. + +SPDX-License-Identifier: Apache-2.0 OR MIT + + + +This file, vk.xml, is the Vulkan API Registry. It is a critically important +and normative part of the Vulkan Specification, including a canonical +machine-readable definition of the API, parameter and member validation +language incorporated into the Specification and reference pages, and other +material which is registered by Khronos, such as tags used by extension and +layer authors. The authoritative public version of vk.xml is maintained in +the default branch (currently named main) of the Khronos Vulkan GitHub +project. The authoritative private version is maintained in the default +branch of the member gitlab server. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #include "vk_platform.h" + + WSI extensions + + + + + + + + + + + + In the current header structure, each platform's interfaces + are confined to a platform-specific header (vulkan_xlib.h, + vulkan_win32.h, etc.). These headers are not self-contained, + and should not include native headers (X11/Xlib.h, + windows.h, etc.). Code should either include vulkan.h after + defining the appropriate VK_USE_PLATFORM_platform + macros, or include the required native headers prior to + explicitly including the corresponding platform header. + + To accomplish this, the dependencies of native types require + native headers, but the XML defines the content for those + native headers as empty. The actual native header includes + can be restored by modifying the native header tags above + to #include the header file in the 'name' attribute. + + + + + + + + + + + + + + + + + + + + + + + + + + + // DEPRECATED: This define is deprecated. VK_MAKE_API_VERSION should be used instead. +#define VK_MAKE_VERSION(major, minor, patch) \ + ((((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch))) + // DEPRECATED: This define is deprecated. VK_API_VERSION_MAJOR should be used instead. +#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) + // DEPRECATED: This define is deprecated. VK_API_VERSION_MINOR should be used instead. +#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3FFU) + // DEPRECATED: This define is deprecated. VK_API_VERSION_PATCH should be used instead. +#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) + + #define VK_MAKE_API_VERSION(variant, major, minor, patch) \ + ((((uint32_t)(variant)) << 29) | (((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch))) + #define VK_API_VERSION_VARIANT(version) ((uint32_t)(version) >> 29) + #define VK_API_VERSION_MAJOR(version) (((uint32_t)(version) >> 22) & 0x7FU) + #define VK_API_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3FFU) + #define VK_API_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) + + // DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. +//#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) // Patch version should always be set to 0 + // Vulkan 1.0 version number +#define VK_API_VERSION_1_0 VK_MAKE_API_VERSION(0, 1, 0, 0)// Patch version should always be set to 0 + // Vulkan 1.1 version number +#define VK_API_VERSION_1_1 VK_MAKE_API_VERSION(0, 1, 1, 0)// Patch version should always be set to 0 + // Vulkan 1.2 version number +#define VK_API_VERSION_1_2 VK_MAKE_API_VERSION(0, 1, 2, 0)// Patch version should always be set to 0 + // Vulkan 1.3 version number +#define VK_API_VERSION_1_3 VK_MAKE_API_VERSION(0, 1, 3, 0)// Patch version should always be set to 0 + // Version of this file +#define VK_HEADER_VERSION 235 + // Complete version of this file +#define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(0, 1, 3, VK_HEADER_VERSION) + + +#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; + + +#ifndef VK_USE_64_BIT_PTR_DEFINES + #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #define VK_USE_64_BIT_PTR_DEFINES 1 + #else + #define VK_USE_64_BIT_PTR_DEFINES 0 + #endif +#endif + +#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE + #if (VK_USE_64_BIT_PTR_DEFINES==1) + #if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)) + #define VK_NULL_HANDLE nullptr + #else + #define VK_NULL_HANDLE ((void*)0) + #endif + #else + #define VK_NULL_HANDLE 0ULL + #endif +#endif +#ifndef VK_NULL_HANDLE + #define VK_NULL_HANDLE 0 +#endif + +#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE + #if (VK_USE_64_BIT_PTR_DEFINES==1) + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; + #else + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; + #endif +#endif + + struct ANativeWindow; + struct AHardwareBuffer; + #ifdef __OBJC__ +@class CAMetalLayer; +#else +typedef void CAMetalLayer; +#endif + #ifdef __OBJC__ +@protocol MTLDevice; +typedef id<MTLDevice> MTLDevice_id; +#else +typedef void* MTLDevice_id; +#endif + #ifdef __OBJC__ +@protocol MTLCommandQueue; +typedef id<MTLCommandQueue> MTLCommandQueue_id; +#else +typedef void* MTLCommandQueue_id; +#endif + #ifdef __OBJC__ +@protocol MTLBuffer; +typedef id<MTLBuffer> MTLBuffer_id; +#else +typedef void* MTLBuffer_id; +#endif + #ifdef __OBJC__ +@protocol MTLTexture; +typedef id<MTLTexture> MTLTexture_id; +#else +typedef void* MTLTexture_id; +#endif + #ifdef __OBJC__ +@protocol MTLSharedEvent; +typedef id<MTLSharedEvent> MTLSharedEvent_id; +#else +typedef void* MTLSharedEvent_id; +#endif + typedef struct __IOSurface* IOSurfaceRef; + + typedef uint32_t VkSampleMask; + typedef uint32_t VkBool32; + typedef uint32_t VkFlags; + typedef uint64_t VkFlags64; + typedef uint64_t VkDeviceSize; + typedef uint64_t VkDeviceAddress; + + Basic C types, pulled in via vk_platform.h + + + + + + + + + + + + + + + + Bitmask types + typedef VkFlags VkFramebufferCreateFlags; + typedef VkFlags VkQueryPoolCreateFlags; + typedef VkFlags VkRenderPassCreateFlags; + typedef VkFlags VkSamplerCreateFlags; + typedef VkFlags VkPipelineLayoutCreateFlags; + typedef VkFlags VkPipelineCacheCreateFlags; + typedef VkFlags VkPipelineDepthStencilStateCreateFlags; + typedef VkFlags VkPipelineDynamicStateCreateFlags; + typedef VkFlags VkPipelineColorBlendStateCreateFlags; + typedef VkFlags VkPipelineMultisampleStateCreateFlags; + typedef VkFlags VkPipelineRasterizationStateCreateFlags; + typedef VkFlags VkPipelineViewportStateCreateFlags; + typedef VkFlags VkPipelineTessellationStateCreateFlags; + typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; + typedef VkFlags VkPipelineVertexInputStateCreateFlags; + typedef VkFlags VkPipelineShaderStageCreateFlags; + typedef VkFlags VkDescriptorSetLayoutCreateFlags; + typedef VkFlags VkBufferViewCreateFlags; + typedef VkFlags VkInstanceCreateFlags; + typedef VkFlags VkDeviceCreateFlags; + typedef VkFlags VkDeviceQueueCreateFlags; + typedef VkFlags VkQueueFlags; + typedef VkFlags VkMemoryPropertyFlags; + typedef VkFlags VkMemoryHeapFlags; + typedef VkFlags VkAccessFlags; + typedef VkFlags VkBufferUsageFlags; + typedef VkFlags VkBufferCreateFlags; + typedef VkFlags VkShaderStageFlags; + typedef VkFlags VkImageUsageFlags; + typedef VkFlags VkImageCreateFlags; + typedef VkFlags VkImageViewCreateFlags; + typedef VkFlags VkPipelineCreateFlags; + typedef VkFlags VkColorComponentFlags; + typedef VkFlags VkFenceCreateFlags; + typedef VkFlags VkSemaphoreCreateFlags; + typedef VkFlags VkFormatFeatureFlags; + typedef VkFlags VkQueryControlFlags; + typedef VkFlags VkQueryResultFlags; + typedef VkFlags VkShaderModuleCreateFlags; + typedef VkFlags VkEventCreateFlags; + typedef VkFlags VkCommandPoolCreateFlags; + typedef VkFlags VkCommandPoolResetFlags; + typedef VkFlags VkCommandBufferResetFlags; + typedef VkFlags VkCommandBufferUsageFlags; + typedef VkFlags VkQueryPipelineStatisticFlags; + typedef VkFlags VkMemoryMapFlags; + typedef VkFlags VkImageAspectFlags; + typedef VkFlags VkSparseMemoryBindFlags; + typedef VkFlags VkSparseImageFormatFlags; + typedef VkFlags VkSubpassDescriptionFlags; + typedef VkFlags VkPipelineStageFlags; + typedef VkFlags VkSampleCountFlags; + typedef VkFlags VkAttachmentDescriptionFlags; + typedef VkFlags VkStencilFaceFlags; + typedef VkFlags VkCullModeFlags; + typedef VkFlags VkDescriptorPoolCreateFlags; + typedef VkFlags VkDescriptorPoolResetFlags; + typedef VkFlags VkDependencyFlags; + typedef VkFlags VkSubgroupFeatureFlags; + typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNV; + typedef VkFlags VkIndirectStateFlagsNV; + typedef VkFlags VkGeometryFlagsKHR; + + typedef VkFlags VkGeometryInstanceFlagsKHR; + + typedef VkFlags VkBuildAccelerationStructureFlagsKHR; + + typedef VkFlags VkPrivateDataSlotCreateFlags; + + typedef VkFlags VkAccelerationStructureCreateFlagsKHR; + typedef VkFlags VkDescriptorUpdateTemplateCreateFlags; + + typedef VkFlags VkPipelineCreationFeedbackFlags; + + typedef VkFlags VkPerformanceCounterDescriptionFlagsKHR; + typedef VkFlags VkAcquireProfilingLockFlagsKHR; + typedef VkFlags VkSemaphoreWaitFlags; + + typedef VkFlags VkPipelineCompilerControlFlagsAMD; + typedef VkFlags VkShaderCorePropertiesFlagsAMD; + typedef VkFlags VkDeviceDiagnosticsConfigFlagsNV; + typedef VkFlags64 VkAccessFlags2; + + typedef VkFlags64 VkPipelineStageFlags2; + + typedef VkFlags VkAccelerationStructureMotionInfoFlagsNV; + typedef VkFlags VkAccelerationStructureMotionInstanceFlagsNV; + typedef VkFlags64 VkFormatFeatureFlags2; + + typedef VkFlags VkRenderingFlags; + typedef VkFlags64 VkMemoryDecompressionMethodFlagsNV; + + typedef VkFlags VkBuildMicromapFlagsEXT; + typedef VkFlags VkMicromapCreateFlagsEXT; + + + WSI extensions + typedef VkFlags VkCompositeAlphaFlagsKHR; + typedef VkFlags VkDisplayPlaneAlphaFlagsKHR; + typedef VkFlags VkSurfaceTransformFlagsKHR; + typedef VkFlags VkSwapchainCreateFlagsKHR; + typedef VkFlags VkDisplayModeCreateFlagsKHR; + typedef VkFlags VkDisplaySurfaceCreateFlagsKHR; + typedef VkFlags VkAndroidSurfaceCreateFlagsKHR; + typedef VkFlags VkViSurfaceCreateFlagsNN; + typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; + typedef VkFlags VkWin32SurfaceCreateFlagsKHR; + typedef VkFlags VkXlibSurfaceCreateFlagsKHR; + typedef VkFlags VkXcbSurfaceCreateFlagsKHR; + typedef VkFlags VkDirectFBSurfaceCreateFlagsEXT; + typedef VkFlags VkIOSSurfaceCreateFlagsMVK; + typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; + typedef VkFlags VkMetalSurfaceCreateFlagsEXT; + typedef VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA; + typedef VkFlags VkStreamDescriptorSurfaceCreateFlagsGGP; + typedef VkFlags VkHeadlessSurfaceCreateFlagsEXT; + typedef VkFlags VkScreenSurfaceCreateFlagsQNX; + typedef VkFlags VkPeerMemoryFeatureFlags; + + typedef VkFlags VkMemoryAllocateFlags; + + typedef VkFlags VkDeviceGroupPresentModeFlagsKHR; + + typedef VkFlags VkDebugReportFlagsEXT; + typedef VkFlags VkCommandPoolTrimFlags; + + typedef VkFlags VkExternalMemoryHandleTypeFlagsNV; + typedef VkFlags VkExternalMemoryFeatureFlagsNV; + typedef VkFlags VkExternalMemoryHandleTypeFlags; + + typedef VkFlags VkExternalMemoryFeatureFlags; + + typedef VkFlags VkExternalSemaphoreHandleTypeFlags; + + typedef VkFlags VkExternalSemaphoreFeatureFlags; + + typedef VkFlags VkSemaphoreImportFlags; + + typedef VkFlags VkExternalFenceHandleTypeFlags; + + typedef VkFlags VkExternalFenceFeatureFlags; + + typedef VkFlags VkFenceImportFlags; + + typedef VkFlags VkSurfaceCounterFlagsEXT; + typedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV; + typedef VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT; + typedef VkFlags VkPipelineCoverageToColorStateCreateFlagsNV; + typedef VkFlags VkPipelineCoverageModulationStateCreateFlagsNV; + typedef VkFlags VkPipelineCoverageReductionStateCreateFlagsNV; + typedef VkFlags VkValidationCacheCreateFlagsEXT; + typedef VkFlags VkDebugUtilsMessageSeverityFlagsEXT; + typedef VkFlags VkDebugUtilsMessageTypeFlagsEXT; + typedef VkFlags VkDebugUtilsMessengerCreateFlagsEXT; + typedef VkFlags VkDebugUtilsMessengerCallbackDataFlagsEXT; + typedef VkFlags VkDeviceMemoryReportFlagsEXT; + typedef VkFlags VkPipelineRasterizationConservativeStateCreateFlagsEXT; + typedef VkFlags VkDescriptorBindingFlags; + + typedef VkFlags VkConditionalRenderingFlagsEXT; + typedef VkFlags VkResolveModeFlags; + + typedef VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT; + typedef VkFlags VkPipelineRasterizationDepthClipStateCreateFlagsEXT; + typedef VkFlags VkSwapchainImageUsageFlagsANDROID; + typedef VkFlags VkToolPurposeFlags; + + typedef VkFlags VkSubmitFlags; + + typedef VkFlags VkImageFormatConstraintsFlagsFUCHSIA; + typedef VkFlags VkImageConstraintsInfoFlagsFUCHSIA; + typedef VkFlags VkGraphicsPipelineLibraryFlagsEXT; + typedef VkFlags VkImageCompressionFlagsEXT; + typedef VkFlags VkImageCompressionFixedRateFlagsEXT; + typedef VkFlags VkExportMetalObjectTypeFlagsEXT; + typedef VkFlags VkDeviceAddressBindingFlagsEXT; + typedef VkFlags VkOpticalFlowGridSizeFlagsNV; + typedef VkFlags VkOpticalFlowUsageFlagsNV; + typedef VkFlags VkOpticalFlowSessionCreateFlagsNV; + typedef VkFlags VkOpticalFlowExecuteFlagsNV; + + Video Core extension + typedef VkFlags VkVideoCodecOperationFlagsKHR; + typedef VkFlags VkVideoCapabilityFlagsKHR; + typedef VkFlags VkVideoSessionCreateFlagsKHR; + typedef VkFlags VkVideoSessionParametersCreateFlagsKHR; + typedef VkFlags VkVideoBeginCodingFlagsKHR; + typedef VkFlags VkVideoEndCodingFlagsKHR; + typedef VkFlags VkVideoCodingControlFlagsKHR; + + Video Decode Core extension + typedef VkFlags VkVideoDecodeUsageFlagsKHR; + typedef VkFlags VkVideoDecodeCapabilityFlagsKHR; + typedef VkFlags VkVideoDecodeFlagsKHR; + + Video Decode H.264 extension + typedef VkFlags VkVideoDecodeH264PictureLayoutFlagsEXT; + + Video Encode Core extension + typedef VkFlags VkVideoEncodeFlagsKHR; + typedef VkFlags VkVideoEncodeUsageFlagsKHR; + typedef VkFlags VkVideoEncodeContentFlagsKHR; + typedef VkFlags VkVideoEncodeCapabilityFlagsKHR; + typedef VkFlags VkVideoEncodeRateControlFlagsKHR; + typedef VkFlags VkVideoEncodeRateControlModeFlagsKHR; + typedef VkFlags VkVideoChromaSubsamplingFlagsKHR; + typedef VkFlags VkVideoComponentBitDepthFlagsKHR; + + Video Encode H.264 extension + typedef VkFlags VkVideoEncodeH264CapabilityFlagsEXT; + typedef VkFlags VkVideoEncodeH264InputModeFlagsEXT; + typedef VkFlags VkVideoEncodeH264OutputModeFlagsEXT; + + Video Encode H.265 extension + typedef VkFlags VkVideoEncodeH265CapabilityFlagsEXT; + typedef VkFlags VkVideoEncodeH265InputModeFlagsEXT; + typedef VkFlags VkVideoEncodeH265OutputModeFlagsEXT; + typedef VkFlags VkVideoEncodeH265CtbSizeFlagsEXT; + typedef VkFlags VkVideoEncodeH265TransformBlockSizeFlagsEXT; + + Types which can be void pointers or class pointers, selected at compile time + VK_DEFINE_HANDLE(VkInstance) + VK_DEFINE_HANDLE(VkPhysicalDevice) + VK_DEFINE_HANDLE(VkDevice) + VK_DEFINE_HANDLE(VkQueue) + VK_DEFINE_HANDLE(VkCommandBuffer) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNV) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplate) + + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSamplerYcbcrConversion) + + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkValidationCacheEXT) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureKHR) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNV) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPerformanceConfigurationINTEL) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferCollectionFUCHSIA) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeferredOperationKHR) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPrivateDataSlot) + + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCuModuleNVX) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCuFunctionNVX) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkOpticalFlowSessionNV) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkMicromapEXT) + + WSI extensions + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayModeKHR) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugUtilsMessengerEXT) + + Video extensions + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkVideoSessionKHR) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkVideoSessionParametersKHR) + + Types generated from corresponding enums tags below + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Extensions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WSI extensions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Enumerated types in the header, but not used by the API + + + + + + + + Video Core extensions + + + + + + + + + Video Decode extensions + + + + Video H.264 Decode extensions + + + Video H.265 Decode extensions + + Video Encode extensions + + + + + + + Video H.264 Encode extensions + + + + + + Video H.265 Encode extensions + + + + + + + + The PFN_vk*Function types are used by VkAllocationCallbacks below + typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)( + void* pUserData, + size_t size, + VkInternalAllocationType allocationType, + VkSystemAllocationScope allocationScope); + typedef void (VKAPI_PTR *PFN_vkInternalFreeNotification)( + void* pUserData, + size_t size, + VkInternalAllocationType allocationType, + VkSystemAllocationScope allocationScope); + typedef void* (VKAPI_PTR *PFN_vkReallocationFunction)( + void* pUserData, + void* pOriginal, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope); + typedef void* (VKAPI_PTR *PFN_vkAllocationFunction)( + void* pUserData, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope); + typedef void (VKAPI_PTR *PFN_vkFreeFunction)( + void* pUserData, + void* pMemory); + + The PFN_vkVoidFunction type are used by VkGet*ProcAddr below + typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void); + + The PFN_vkDebugReportCallbackEXT type are used by the DEBUG_REPORT extension + typedef VkBool32 (VKAPI_PTR *PFN_vkDebugReportCallbackEXT)( + VkDebugReportFlagsEXT flags, + VkDebugReportObjectTypeEXT objectType, + uint64_t object, + size_t location, + int32_t messageCode, + const char* pLayerPrefix, + const char* pMessage, + void* pUserData); + + The PFN_vkDebugUtilsMessengerCallbackEXT type are used by the VK_EXT_debug_utils extension + typedef VkBool32 (VKAPI_PTR *PFN_vkDebugUtilsMessengerCallbackEXT)( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData); + + The PFN_vkDeviceMemoryReportCallbackEXT type is used by the VK_EXT_device_memory_report extension + typedef void (VKAPI_PTR *PFN_vkDeviceMemoryReportCallbackEXT)( + const VkDeviceMemoryReportCallbackDataEXT* pCallbackData, + void* pUserData); + + Struct types + + VkStructureType sType + struct VkBaseOutStructure* pNext + + + VkStructureType sType + const struct VkBaseInStructure* pNext + + + int32_t x + int32_t y + + + int32_t x + int32_t y + int32_t z + + + uint32_t width + uint32_t height + + + uint32_t width + uint32_t height + uint32_t depth + + + float x + float y + float width + float height + float minDepth + float maxDepth + + + VkOffset2D offset + VkExtent2D extent + + + VkRect2D rect + uint32_t baseArrayLayer + uint32_t layerCount + + + VkComponentSwizzle r + VkComponentSwizzle g + VkComponentSwizzle b + VkComponentSwizzle a + + + uint32_t apiVersion + uint32_t driverVersion + uint32_t vendorID + uint32_t deviceID + VkPhysicalDeviceType deviceType + char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE] + uint8_t pipelineCacheUUID[VK_UUID_SIZE] + VkPhysicalDeviceLimits limits + VkPhysicalDeviceSparseProperties sparseProperties + + + char extensionName[VK_MAX_EXTENSION_NAME_SIZE]extension name + uint32_t specVersionversion of the extension specification implemented + + + char layerName[VK_MAX_EXTENSION_NAME_SIZE]layer name + uint32_t specVersionversion of the layer specification implemented + uint32_t implementationVersionbuild or release version of the layer's library + char description[VK_MAX_DESCRIPTION_SIZE]Free-form description of the layer + + + VkStructureType sType + const void* pNext + const char* pApplicationName + uint32_t applicationVersion + const char* pEngineName + uint32_t engineVersion + uint32_t apiVersion + + + void* pUserData + PFN_vkAllocationFunction pfnAllocation + PFN_vkReallocationFunction pfnReallocation + PFN_vkFreeFunction pfnFree + PFN_vkInternalAllocationNotification pfnInternalAllocation + PFN_vkInternalFreeNotification pfnInternalFree + + + VkStructureType sType + const void* pNext + VkDeviceQueueCreateFlags flags + uint32_t queueFamilyIndex + uint32_t queueCount + const float* pQueuePriorities + + + VkStructureType sType + const void* pNext + VkDeviceCreateFlags flags + uint32_t queueCreateInfoCount + const VkDeviceQueueCreateInfo* pQueueCreateInfos + uint32_t enabledLayerCount + const char* const* ppEnabledLayerNamesOrdered list of layer names to be enabled + uint32_t enabledExtensionCount + const char* const* ppEnabledExtensionNames + const VkPhysicalDeviceFeatures* pEnabledFeatures + + + VkStructureType sType + const void* pNext + VkInstanceCreateFlags flags + const VkApplicationInfo* pApplicationInfo + uint32_t enabledLayerCount + const char* const* ppEnabledLayerNamesOrdered list of layer names to be enabled + uint32_t enabledExtensionCount + const char* const* ppEnabledExtensionNamesExtension names to be enabled + + + VkQueueFlags queueFlagsQueue flags + uint32_t queueCount + uint32_t timestampValidBits + VkExtent3D minImageTransferGranularityMinimum alignment requirement for image transfers + + + uint32_t memoryTypeCount + VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES] + uint32_t memoryHeapCount + VkMemoryHeap memoryHeaps[VK_MAX_MEMORY_HEAPS] + + + VkStructureType sType + const void* pNext + VkDeviceSize allocationSizeSize of memory allocation + uint32_t memoryTypeIndexIndex of the of the memory type to allocate from + + + VkDeviceSize sizeSpecified in bytes + VkDeviceSize alignmentSpecified in bytes + uint32_t memoryTypeBitsBitmask of the allowed memory type indices into memoryTypes[] for this object + + + VkImageAspectFlags aspectMask + VkExtent3D imageGranularity + VkSparseImageFormatFlags flags + + + VkSparseImageFormatProperties formatProperties + uint32_t imageMipTailFirstLod + VkDeviceSize imageMipTailSizeSpecified in bytes, must be a multiple of sparse block size in bytes / alignment + VkDeviceSize imageMipTailOffsetSpecified in bytes, must be a multiple of sparse block size in bytes / alignment + VkDeviceSize imageMipTailStrideSpecified in bytes, must be a multiple of sparse block size in bytes / alignment + + + VkMemoryPropertyFlags propertyFlagsMemory properties of this memory type + uint32_t heapIndexIndex of the memory heap allocations of this memory type are taken from + + + VkDeviceSize sizeAvailable memory in the heap + VkMemoryHeapFlags flagsFlags for the heap + + + VkStructureType sType + const void* pNext + VkDeviceMemory memoryMapped memory object + VkDeviceSize offsetOffset within the memory object where the range starts + VkDeviceSize sizeSize of the range within the memory object + + + VkFormatFeatureFlags linearTilingFeaturesFormat features in case of linear tiling + VkFormatFeatureFlags optimalTilingFeaturesFormat features in case of optimal tiling + VkFormatFeatureFlags bufferFeaturesFormat features supported by buffers + + + VkExtent3D maxExtentmax image dimensions for this resource type + uint32_t maxMipLevelsmax number of mipmap levels for this resource type + uint32_t maxArrayLayersmax array size for this resource type + VkSampleCountFlags sampleCountssupported sample counts for this resource type + VkDeviceSize maxResourceSizemax size (in bytes) of this resource type + + + VkBuffer bufferBuffer used for this descriptor slot. + VkDeviceSize offsetBase offset from buffer start in bytes to update in the descriptor set. + VkDeviceSize rangeSize in bytes of the buffer resource for this descriptor update. + + + VkSampler samplerSampler to write to the descriptor in case it is a SAMPLER or COMBINED_IMAGE_SAMPLER descriptor. Ignored otherwise. + VkImageView imageViewImage view to write to the descriptor in case it is a SAMPLED_IMAGE, STORAGE_IMAGE, COMBINED_IMAGE_SAMPLER, or INPUT_ATTACHMENT descriptor. Ignored otherwise. + VkImageLayout imageLayoutLayout the image is expected to be in when accessed using this descriptor (only used if imageView is not VK_NULL_HANDLE). + + + VkStructureType sType + const void* pNext + VkDescriptorSet dstSetDestination descriptor set + uint32_t dstBindingBinding within the destination descriptor set to write + uint32_t dstArrayElementArray element within the destination binding to write + uint32_t descriptorCountNumber of descriptors to write (determines the size of the array pointed by pDescriptors) + VkDescriptorType descriptorTypeDescriptor type to write (determines which members of the array pointed by pDescriptors are going to be used) + const VkDescriptorImageInfo* pImageInfoSampler, image view, and layout for SAMPLER, COMBINED_IMAGE_SAMPLER, {SAMPLED,STORAGE}_IMAGE, and INPUT_ATTACHMENT descriptor types. + const VkDescriptorBufferInfo* pBufferInfoRaw buffer, size, and offset for {UNIFORM,STORAGE}_BUFFER[_DYNAMIC] descriptor types. + const VkBufferView* pTexelBufferViewBuffer view to write to the descriptor for {UNIFORM,STORAGE}_TEXEL_BUFFER descriptor types. + + + VkStructureType sType + const void* pNext + VkDescriptorSet srcSetSource descriptor set + uint32_t srcBindingBinding within the source descriptor set to copy from + uint32_t srcArrayElementArray element within the source binding to copy from + VkDescriptorSet dstSetDestination descriptor set + uint32_t dstBindingBinding within the destination descriptor set to copy to + uint32_t dstArrayElementArray element within the destination binding to copy to + uint32_t descriptorCountNumber of descriptors to write (determines the size of the array pointed by pDescriptors) + + + VkStructureType sType + const void* pNext + VkBufferCreateFlags flagsBuffer creation flags + VkDeviceSize sizeSpecified in bytes + VkBufferUsageFlags usageBuffer usage flags + VkSharingMode sharingMode + uint32_t queueFamilyIndexCount + const uint32_t* pQueueFamilyIndices + + + VkStructureType sType + const void* pNext + VkBufferViewCreateFlags flags + VkBuffer buffer + VkFormat formatOptionally specifies format of elements + VkDeviceSize offsetSpecified in bytes + VkDeviceSize rangeView size specified in bytes + + + VkImageAspectFlags aspectMask + uint32_t mipLevel + uint32_t arrayLayer + + + VkImageAspectFlags aspectMask + uint32_t mipLevel + uint32_t baseArrayLayer + uint32_t layerCount + + + VkImageAspectFlags aspectMask + uint32_t baseMipLevel + uint32_t levelCount + uint32_t baseArrayLayer + uint32_t layerCount + + + VkStructureType sType + const void* pNext + VkAccessFlags srcAccessMaskMemory accesses from the source of the dependency to synchronize + VkAccessFlags dstAccessMaskMemory accesses from the destination of the dependency to synchronize + + + VkStructureType sType + const void* pNext + VkAccessFlags srcAccessMaskMemory accesses from the source of the dependency to synchronize + VkAccessFlags dstAccessMaskMemory accesses from the destination of the dependency to synchronize + uint32_t srcQueueFamilyIndexQueue family to transition ownership from + uint32_t dstQueueFamilyIndexQueue family to transition ownership to + VkBuffer bufferBuffer to sync + VkDeviceSize offsetOffset within the buffer to sync + VkDeviceSize sizeAmount of bytes to sync + + + VkStructureType sType + const void* pNext + VkAccessFlags srcAccessMaskMemory accesses from the source of the dependency to synchronize + VkAccessFlags dstAccessMaskMemory accesses from the destination of the dependency to synchronize + VkImageLayout oldLayoutCurrent layout of the image + VkImageLayout newLayoutNew layout to transition the image to + uint32_t srcQueueFamilyIndexQueue family to transition ownership from + uint32_t dstQueueFamilyIndexQueue family to transition ownership to + VkImage imageImage to sync + VkImageSubresourceRange subresourceRangeSubresource range to sync + + + VkStructureType sType + const void* pNext + VkImageCreateFlags flagsImage creation flags + VkImageType imageType + VkFormat format + VkExtent3D extent + uint32_t mipLevels + uint32_t arrayLayers + VkSampleCountFlagBits samples + VkImageTiling tiling + VkImageUsageFlags usageImage usage flags + VkSharingMode sharingModeCross-queue-family sharing mode + uint32_t queueFamilyIndexCountNumber of queue families to share across + const uint32_t* pQueueFamilyIndicesArray of queue family indices to share across + VkImageLayout initialLayoutInitial image layout for all subresources + + + VkDeviceSize offsetSpecified in bytes + VkDeviceSize sizeSpecified in bytes + VkDeviceSize rowPitchSpecified in bytes + VkDeviceSize arrayPitchSpecified in bytes + VkDeviceSize depthPitchSpecified in bytes + + + VkStructureType sType + const void* pNext + VkImageViewCreateFlags flags + VkImage image + VkImageViewType viewType + VkFormat format + VkComponentMapping components + VkImageSubresourceRange subresourceRange + + + VkDeviceSize srcOffsetSpecified in bytes + VkDeviceSize dstOffsetSpecified in bytes + VkDeviceSize sizeSpecified in bytes + + + VkDeviceSize resourceOffsetSpecified in bytes + VkDeviceSize sizeSpecified in bytes + VkDeviceMemory memory + VkDeviceSize memoryOffsetSpecified in bytes + VkSparseMemoryBindFlags flags + + + VkImageSubresource subresource + VkOffset3D offset + VkExtent3D extent + VkDeviceMemory memory + VkDeviceSize memoryOffsetSpecified in bytes + VkSparseMemoryBindFlags flags + + + VkBuffer buffer + uint32_t bindCount + const VkSparseMemoryBind* pBinds + + + VkImage image + uint32_t bindCount + const VkSparseMemoryBind* pBinds + + + VkImage image + uint32_t bindCount + const VkSparseImageMemoryBind* pBinds + + + VkStructureType sType + const void* pNext + uint32_t waitSemaphoreCount + const VkSemaphore* pWaitSemaphores + uint32_t bufferBindCount + const VkSparseBufferMemoryBindInfo* pBufferBinds + uint32_t imageOpaqueBindCount + const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds + uint32_t imageBindCount + const VkSparseImageMemoryBindInfo* pImageBinds + uint32_t signalSemaphoreCount + const VkSemaphore* pSignalSemaphores + + + VkImageSubresourceLayers srcSubresource + VkOffset3D srcOffsetSpecified in pixels for both compressed and uncompressed images + VkImageSubresourceLayers dstSubresource + VkOffset3D dstOffsetSpecified in pixels for both compressed and uncompressed images + VkExtent3D extentSpecified in pixels for both compressed and uncompressed images + + + VkImageSubresourceLayers srcSubresource + VkOffset3D srcOffsets[2]Specified in pixels for both compressed and uncompressed images + VkImageSubresourceLayers dstSubresource + VkOffset3D dstOffsets[2]Specified in pixels for both compressed and uncompressed images + + + VkDeviceSize bufferOffsetSpecified in bytes + uint32_t bufferRowLengthSpecified in texels + uint32_t bufferImageHeight + VkImageSubresourceLayers imageSubresource + VkOffset3D imageOffsetSpecified in pixels for both compressed and uncompressed images + VkExtent3D imageExtentSpecified in pixels for both compressed and uncompressed images + + + VkDeviceAddress srcAddress + VkDeviceAddress dstAddress + VkDeviceSize sizeSpecified in bytes + + + VkDeviceAddress srcAddress + uint32_t bufferRowLengthSpecified in texels + uint32_t bufferImageHeight + VkImageSubresourceLayers imageSubresource + VkOffset3D imageOffsetSpecified in pixels for both compressed and uncompressed images + VkExtent3D imageExtentSpecified in pixels for both compressed and uncompressed images + + + VkImageSubresourceLayers srcSubresource + VkOffset3D srcOffset + VkImageSubresourceLayers dstSubresource + VkOffset3D dstOffset + VkExtent3D extent + + + VkStructureType sType + const void* pNextnoautovalidity because this structure can be either an explicit parameter, or passed in a pNext chain + VkShaderModuleCreateFlags flags + size_t codeSizeSpecified in bytes + const uint32_t* pCodeBinary code of size codeSize + + + uint32_t bindingBinding number for this entry + VkDescriptorType descriptorTypeType of the descriptors in this binding + uint32_t descriptorCountNumber of descriptors in this binding + VkShaderStageFlags stageFlagsShader stages this binding is visible to + const VkSampler* pImmutableSamplersImmutable samplers (used if descriptor type is SAMPLER or COMBINED_IMAGE_SAMPLER, is either NULL or contains count number of elements) + + + VkStructureType sType + const void* pNext + VkDescriptorSetLayoutCreateFlags flags + uint32_t bindingCountNumber of bindings in the descriptor set layout + const VkDescriptorSetLayoutBinding* pBindingsArray of descriptor set layout bindings + + + VkDescriptorType type + uint32_t descriptorCount + + + VkStructureType sType + const void* pNext + VkDescriptorPoolCreateFlags flags + uint32_t maxSets + uint32_t poolSizeCount + const VkDescriptorPoolSize* pPoolSizes + + + VkStructureType sType + const void* pNext + VkDescriptorPool descriptorPool + uint32_t descriptorSetCount + const VkDescriptorSetLayout* pSetLayouts + + + uint32_t constantIDThe SpecConstant ID specified in the BIL + uint32_t offsetOffset of the value in the data block + size_t sizeSize in bytes of the SpecConstant + + + uint32_t mapEntryCountNumber of entries in the map + const VkSpecializationMapEntry* pMapEntriesArray of map entries + size_t dataSizeSize in bytes of pData + const void* pDataPointer to SpecConstant data + + + VkStructureType sType + const void* pNext + VkPipelineShaderStageCreateFlags flags + VkShaderStageFlagBits stageShader stage + VkShaderModule moduleModule containing entry point + const char* pNameNull-terminated entry point name + const VkSpecializationInfo* pSpecializationInfo + + + VkStructureType sType + const void* pNext + VkPipelineCreateFlags flagsPipeline creation flags + VkPipelineShaderStageCreateInfo stage + VkPipelineLayout layoutInterface layout of the pipeline + VkPipeline basePipelineHandleIf VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is nonzero, it specifies the handle of the base pipeline this is a derivative of + int32_t basePipelineIndexIf VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is not -1, it specifies an index into pCreateInfos of the base pipeline this is a derivative of + + + uint32_t bindingVertex buffer binding id + uint32_t strideDistance between vertices in bytes (0 = no advancement) + VkVertexInputRate inputRateThe rate at which the vertex data is consumed + + + uint32_t locationlocation of the shader vertex attrib + uint32_t bindingVertex buffer binding id + VkFormat formatformat of source data + uint32_t offsetOffset of first element in bytes from base of vertex + + + VkStructureType sType + const void* pNext + VkPipelineVertexInputStateCreateFlags flags + uint32_t vertexBindingDescriptionCountnumber of bindings + const VkVertexInputBindingDescription* pVertexBindingDescriptions + uint32_t vertexAttributeDescriptionCountnumber of attributes + const VkVertexInputAttributeDescription* pVertexAttributeDescriptions + + + VkStructureType sType + const void* pNext + VkPipelineInputAssemblyStateCreateFlags flags + VkPrimitiveTopology topology + VkBool32 primitiveRestartEnable + + + VkStructureType sType + const void* pNext + VkPipelineTessellationStateCreateFlags flags + uint32_t patchControlPoints + + + VkStructureType sType + const void* pNext + VkPipelineViewportStateCreateFlags flags + uint32_t viewportCount + const VkViewport* pViewports + uint32_t scissorCount + const VkRect2D* pScissors + + + VkStructureType sType + const void* pNext + VkPipelineRasterizationStateCreateFlags flags + VkBool32 depthClampEnable + VkBool32 rasterizerDiscardEnable + VkPolygonMode polygonModeoptional (GL45) + VkCullModeFlags cullMode + VkFrontFace frontFace + VkBool32 depthBiasEnable + float depthBiasConstantFactor + float depthBiasClamp + float depthBiasSlopeFactor + float lineWidth + + + VkStructureType sType + const void* pNext + VkPipelineMultisampleStateCreateFlags flags + VkSampleCountFlagBits rasterizationSamplesNumber of samples used for rasterization + VkBool32 sampleShadingEnableoptional (GL45) + float minSampleShadingoptional (GL45) + const VkSampleMask* pSampleMaskArray of sampleMask words + VkBool32 alphaToCoverageEnable + VkBool32 alphaToOneEnable + + + VkBool32 blendEnable + VkBlendFactor srcColorBlendFactor + VkBlendFactor dstColorBlendFactor + VkBlendOp colorBlendOp + VkBlendFactor srcAlphaBlendFactor + VkBlendFactor dstAlphaBlendFactor + VkBlendOp alphaBlendOp + VkColorComponentFlags colorWriteMask + + + VkStructureType sType + const void* pNext + VkPipelineColorBlendStateCreateFlags flags + VkBool32 logicOpEnable + VkLogicOp logicOp + uint32_t attachmentCount# of pAttachments + const VkPipelineColorBlendAttachmentState* pAttachments + float blendConstants[4] + + + VkStructureType sType + const void* pNext + VkPipelineDynamicStateCreateFlags flags + uint32_t dynamicStateCount + const VkDynamicState* pDynamicStates + + + VkStencilOp failOp + VkStencilOp passOp + VkStencilOp depthFailOp + VkCompareOp compareOp + uint32_t compareMask + uint32_t writeMask + uint32_t reference + + + VkStructureType sType + const void* pNext + VkPipelineDepthStencilStateCreateFlags flags + VkBool32 depthTestEnable + VkBool32 depthWriteEnable + VkCompareOp depthCompareOp + VkBool32 depthBoundsTestEnableoptional (depth_bounds_test) + VkBool32 stencilTestEnable + VkStencilOpState front + VkStencilOpState back + float minDepthBounds + float maxDepthBounds + + + VkStructureType sType + const void* pNext + VkPipelineCreateFlags flagsPipeline creation flags + uint32_t stageCount + const VkPipelineShaderStageCreateInfo* pStagesOne entry for each active shader stage + const VkPipelineVertexInputStateCreateInfo* pVertexInputState + const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState + const VkPipelineTessellationStateCreateInfo* pTessellationState + const VkPipelineViewportStateCreateInfo* pViewportState + const VkPipelineRasterizationStateCreateInfo* pRasterizationState + const VkPipelineMultisampleStateCreateInfo* pMultisampleState + const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState + const VkPipelineColorBlendStateCreateInfo* pColorBlendState + const VkPipelineDynamicStateCreateInfo* pDynamicState + VkPipelineLayout layoutInterface layout of the pipeline + VkRenderPass renderPass + uint32_t subpass + VkPipeline basePipelineHandleIf VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is nonzero, it specifies the handle of the base pipeline this is a derivative of + int32_t basePipelineIndexIf VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is not -1, it specifies an index into pCreateInfos of the base pipeline this is a derivative of + + + VkStructureType sType + const void* pNext + VkPipelineCacheCreateFlags flags + size_t initialDataSizeSize of initial data to populate cache, in bytes + const void* pInitialDataInitial data to populate cache + + + The fields in this structure are non-normative since structure packing is implementation-defined in C. The specification defines the normative layout. + uint32_t headerSize + VkPipelineCacheHeaderVersion headerVersion + uint32_t vendorID + uint32_t deviceID + uint8_t pipelineCacheUUID[VK_UUID_SIZE] + + + VkShaderStageFlags stageFlagsWhich stages use the range + uint32_t offsetStart of the range, in bytes + uint32_t sizeSize of the range, in bytes + + + VkStructureType sType + const void* pNext + VkPipelineLayoutCreateFlags flags + uint32_t setLayoutCountNumber of descriptor sets interfaced by the pipeline + const VkDescriptorSetLayout* pSetLayoutsArray of setCount number of descriptor set layout objects defining the layout of the + uint32_t pushConstantRangeCountNumber of push-constant ranges used by the pipeline + const VkPushConstantRange* pPushConstantRangesArray of pushConstantRangeCount number of ranges used by various shader stages + + + VkStructureType sType + const void* pNext + VkSamplerCreateFlags flags + VkFilter magFilterFilter mode for magnification + VkFilter minFilterFilter mode for minifiation + VkSamplerMipmapMode mipmapModeMipmap selection mode + VkSamplerAddressMode addressModeU + VkSamplerAddressMode addressModeV + VkSamplerAddressMode addressModeW + float mipLodBias + VkBool32 anisotropyEnable + float maxAnisotropy + VkBool32 compareEnable + VkCompareOp compareOp + float minLod + float maxLod + VkBorderColor borderColor + VkBool32 unnormalizedCoordinates + + + VkStructureType sType + const void* pNext + VkCommandPoolCreateFlags flagsCommand pool creation flags + uint32_t queueFamilyIndex + + + VkStructureType sType + const void* pNext + VkCommandPool commandPool + VkCommandBufferLevel level + uint32_t commandBufferCount + + + VkStructureType sType + const void* pNext + VkRenderPass renderPassRender pass for secondary command buffers + uint32_t subpass + VkFramebuffer framebufferFramebuffer for secondary command buffers + VkBool32 occlusionQueryEnableWhether this secondary command buffer may be executed during an occlusion query + VkQueryControlFlags queryFlagsQuery flags used by this secondary command buffer, if executed during an occlusion query + VkQueryPipelineStatisticFlags pipelineStatisticsPipeline statistics that may be counted for this secondary command buffer + + + VkStructureType sType + const void* pNext + VkCommandBufferUsageFlags flagsCommand buffer usage flags + const VkCommandBufferInheritanceInfo* pInheritanceInfoPointer to inheritance info for secondary command buffers + + + VkStructureType sType + const void* pNext + VkRenderPass renderPass + VkFramebuffer framebuffer + VkRect2D renderArea + uint32_t clearValueCount + const VkClearValue* pClearValues + + + float float32[4] + int32_t int32[4] + uint32_t uint32[4] + + + float depth + uint32_t stencil + + + VkClearColorValue color + VkClearDepthStencilValue depthStencil + + + VkImageAspectFlags aspectMask + uint32_t colorAttachment + VkClearValue clearValue + + + VkAttachmentDescriptionFlags flags + VkFormat format + VkSampleCountFlagBits samples + VkAttachmentLoadOp loadOpLoad operation for color or depth data + VkAttachmentStoreOp storeOpStore operation for color or depth data + VkAttachmentLoadOp stencilLoadOpLoad operation for stencil data + VkAttachmentStoreOp stencilStoreOpStore operation for stencil data + VkImageLayout initialLayout + VkImageLayout finalLayout + + + uint32_t attachment + VkImageLayout layout + + + VkSubpassDescriptionFlags flags + VkPipelineBindPoint pipelineBindPointMust be VK_PIPELINE_BIND_POINT_GRAPHICS for now + uint32_t inputAttachmentCount + const VkAttachmentReference* pInputAttachments + uint32_t colorAttachmentCount + const VkAttachmentReference* pColorAttachments + const VkAttachmentReference* pResolveAttachments + const VkAttachmentReference* pDepthStencilAttachment + uint32_t preserveAttachmentCount + const uint32_t* pPreserveAttachments + + + uint32_t srcSubpass + uint32_t dstSubpass + VkPipelineStageFlags srcStageMask + VkPipelineStageFlags dstStageMask + VkAccessFlags srcAccessMaskMemory accesses from the source of the dependency to synchronize + VkAccessFlags dstAccessMaskMemory accesses from the destination of the dependency to synchronize + VkDependencyFlags dependencyFlags + + + VkStructureType sType + const void* pNext + VkRenderPassCreateFlags flags + uint32_t attachmentCount + const VkAttachmentDescription* pAttachments + uint32_t subpassCount + const VkSubpassDescription* pSubpasses + uint32_t dependencyCount + const VkSubpassDependency* pDependencies + + + VkStructureType sType + const void* pNext + VkEventCreateFlags flagsEvent creation flags + + + VkStructureType sType + const void* pNext + VkFenceCreateFlags flagsFence creation flags + + + VkBool32 robustBufferAccessout of bounds buffer accesses are well defined + VkBool32 fullDrawIndexUint32full 32-bit range of indices for indexed draw calls + VkBool32 imageCubeArrayimage views which are arrays of cube maps + VkBool32 independentBlendblending operations are controlled per-attachment + VkBool32 geometryShadergeometry stage + VkBool32 tessellationShadertessellation control and evaluation stage + VkBool32 sampleRateShadingper-sample shading and interpolation + VkBool32 dualSrcBlendblend operations which take two sources + VkBool32 logicOplogic operations + VkBool32 multiDrawIndirectmulti draw indirect + VkBool32 drawIndirectFirstInstanceindirect drawing can use non-zero firstInstance + VkBool32 depthClampdepth clamping + VkBool32 depthBiasClampdepth bias clamping + VkBool32 fillModeNonSolidpoint and wireframe fill modes + VkBool32 depthBoundsdepth bounds test + VkBool32 wideLineslines with width greater than 1 + VkBool32 largePointspoints with size greater than 1 + VkBool32 alphaToOnethe fragment alpha component can be forced to maximum representable alpha value + VkBool32 multiViewportviewport arrays + VkBool32 samplerAnisotropyanisotropic sampler filtering + VkBool32 textureCompressionETC2ETC texture compression formats + VkBool32 textureCompressionASTC_LDRASTC LDR texture compression formats + VkBool32 textureCompressionBCBC1-7 texture compressed formats + VkBool32 occlusionQueryPreciseprecise occlusion queries returning actual sample counts + VkBool32 pipelineStatisticsQuerypipeline statistics query + VkBool32 vertexPipelineStoresAndAtomicsstores and atomic ops on storage buffers and images are supported in vertex, tessellation, and geometry stages + VkBool32 fragmentStoresAndAtomicsstores and atomic ops on storage buffers and images are supported in the fragment stage + VkBool32 shaderTessellationAndGeometryPointSizetessellation and geometry stages can export point size + VkBool32 shaderImageGatherExtendedimage gather with run-time values and independent offsets + VkBool32 shaderStorageImageExtendedFormatsthe extended set of formats can be used for storage images + VkBool32 shaderStorageImageMultisamplemultisample images can be used for storage images + VkBool32 shaderStorageImageReadWithoutFormatread from storage image does not require format qualifier + VkBool32 shaderStorageImageWriteWithoutFormatwrite to storage image does not require format qualifier + VkBool32 shaderUniformBufferArrayDynamicIndexingarrays of uniform buffers can be accessed with dynamically uniform indices + VkBool32 shaderSampledImageArrayDynamicIndexingarrays of sampled images can be accessed with dynamically uniform indices + VkBool32 shaderStorageBufferArrayDynamicIndexingarrays of storage buffers can be accessed with dynamically uniform indices + VkBool32 shaderStorageImageArrayDynamicIndexingarrays of storage images can be accessed with dynamically uniform indices + VkBool32 shaderClipDistanceclip distance in shaders + VkBool32 shaderCullDistancecull distance in shaders + VkBool32 shaderFloat6464-bit floats (doubles) in shaders + VkBool32 shaderInt6464-bit integers in shaders + VkBool32 shaderInt1616-bit integers in shaders + VkBool32 shaderResourceResidencyshader can use texture operations that return resource residency information (requires sparseNonResident support) + VkBool32 shaderResourceMinLodshader can use texture operations that specify minimum resource LOD + VkBool32 sparseBindingSparse resources support: Resource memory can be managed at opaque page level rather than object level + VkBool32 sparseResidencyBufferSparse resources support: GPU can access partially resident buffers + VkBool32 sparseResidencyImage2DSparse resources support: GPU can access partially resident 2D (non-MSAA non-depth/stencil) images + VkBool32 sparseResidencyImage3DSparse resources support: GPU can access partially resident 3D images + VkBool32 sparseResidency2SamplesSparse resources support: GPU can access partially resident MSAA 2D images with 2 samples + VkBool32 sparseResidency4SamplesSparse resources support: GPU can access partially resident MSAA 2D images with 4 samples + VkBool32 sparseResidency8SamplesSparse resources support: GPU can access partially resident MSAA 2D images with 8 samples + VkBool32 sparseResidency16SamplesSparse resources support: GPU can access partially resident MSAA 2D images with 16 samples + VkBool32 sparseResidencyAliasedSparse resources support: GPU can correctly access data aliased into multiple locations (opt-in) + VkBool32 variableMultisampleRatemultisample rate must be the same for all pipelines in a subpass + VkBool32 inheritedQueriesQueries may be inherited from primary to secondary command buffers + + + VkBool32 residencyStandard2DBlockShapeSparse resources support: GPU will access all 2D (single sample) sparse resources using the standard sparse image block shapes (based on pixel format) + VkBool32 residencyStandard2DMultisampleBlockShapeSparse resources support: GPU will access all 2D (multisample) sparse resources using the standard sparse image block shapes (based on pixel format) + VkBool32 residencyStandard3DBlockShapeSparse resources support: GPU will access all 3D sparse resources using the standard sparse image block shapes (based on pixel format) + VkBool32 residencyAlignedMipSizeSparse resources support: Images with mip level dimensions that are NOT a multiple of the sparse image block dimensions will be placed in the mip tail + VkBool32 residencyNonResidentStrictSparse resources support: GPU can consistently access non-resident regions of a resource, all reads return as if data is 0, writes are discarded + + + resource maximum sizes + uint32_t maxImageDimension1Dmax 1D image dimension + uint32_t maxImageDimension2Dmax 2D image dimension + uint32_t maxImageDimension3Dmax 3D image dimension + uint32_t maxImageDimensionCubemax cubemap image dimension + uint32_t maxImageArrayLayersmax layers for image arrays + uint32_t maxTexelBufferElementsmax texel buffer size (fstexels) + uint32_t maxUniformBufferRangemax uniform buffer range (bytes) + uint32_t maxStorageBufferRangemax storage buffer range (bytes) + uint32_t maxPushConstantsSizemax size of the push constants pool (bytes) + memory limits + uint32_t maxMemoryAllocationCountmax number of device memory allocations supported + uint32_t maxSamplerAllocationCountmax number of samplers that can be allocated on a device + VkDeviceSize bufferImageGranularityGranularity (in bytes) at which buffers and images can be bound to adjacent memory for simultaneous usage + VkDeviceSize sparseAddressSpaceSizeTotal address space available for sparse allocations (bytes) + descriptor set limits + uint32_t maxBoundDescriptorSetsmax number of descriptors sets that can be bound to a pipeline + uint32_t maxPerStageDescriptorSamplersmax number of samplers allowed per-stage in a descriptor set + uint32_t maxPerStageDescriptorUniformBuffersmax number of uniform buffers allowed per-stage in a descriptor set + uint32_t maxPerStageDescriptorStorageBuffersmax number of storage buffers allowed per-stage in a descriptor set + uint32_t maxPerStageDescriptorSampledImagesmax number of sampled images allowed per-stage in a descriptor set + uint32_t maxPerStageDescriptorStorageImagesmax number of storage images allowed per-stage in a descriptor set + uint32_t maxPerStageDescriptorInputAttachmentsmax number of input attachments allowed per-stage in a descriptor set + uint32_t maxPerStageResourcesmax number of resources allowed by a single stage + uint32_t maxDescriptorSetSamplersmax number of samplers allowed in all stages in a descriptor set + uint32_t maxDescriptorSetUniformBuffersmax number of uniform buffers allowed in all stages in a descriptor set + uint32_t maxDescriptorSetUniformBuffersDynamicmax number of dynamic uniform buffers allowed in all stages in a descriptor set + uint32_t maxDescriptorSetStorageBuffersmax number of storage buffers allowed in all stages in a descriptor set + uint32_t maxDescriptorSetStorageBuffersDynamicmax number of dynamic storage buffers allowed in all stages in a descriptor set + uint32_t maxDescriptorSetSampledImagesmax number of sampled images allowed in all stages in a descriptor set + uint32_t maxDescriptorSetStorageImagesmax number of storage images allowed in all stages in a descriptor set + uint32_t maxDescriptorSetInputAttachmentsmax number of input attachments allowed in all stages in a descriptor set + vertex stage limits + uint32_t maxVertexInputAttributesmax number of vertex input attribute slots + uint32_t maxVertexInputBindingsmax number of vertex input binding slots + uint32_t maxVertexInputAttributeOffsetmax vertex input attribute offset added to vertex buffer offset + uint32_t maxVertexInputBindingStridemax vertex input binding stride + uint32_t maxVertexOutputComponentsmax number of output components written by vertex shader + tessellation control stage limits + uint32_t maxTessellationGenerationLevelmax level supported by tessellation primitive generator + uint32_t maxTessellationPatchSizemax patch size (vertices) + uint32_t maxTessellationControlPerVertexInputComponentsmax number of input components per-vertex in TCS + uint32_t maxTessellationControlPerVertexOutputComponentsmax number of output components per-vertex in TCS + uint32_t maxTessellationControlPerPatchOutputComponentsmax number of output components per-patch in TCS + uint32_t maxTessellationControlTotalOutputComponentsmax total number of per-vertex and per-patch output components in TCS + tessellation evaluation stage limits + uint32_t maxTessellationEvaluationInputComponentsmax number of input components per vertex in TES + uint32_t maxTessellationEvaluationOutputComponentsmax number of output components per vertex in TES + geometry stage limits + uint32_t maxGeometryShaderInvocationsmax invocation count supported in geometry shader + uint32_t maxGeometryInputComponentsmax number of input components read in geometry stage + uint32_t maxGeometryOutputComponentsmax number of output components written in geometry stage + uint32_t maxGeometryOutputVerticesmax number of vertices that can be emitted in geometry stage + uint32_t maxGeometryTotalOutputComponentsmax total number of components (all vertices) written in geometry stage + fragment stage limits + uint32_t maxFragmentInputComponentsmax number of input components read in fragment stage + uint32_t maxFragmentOutputAttachmentsmax number of output attachments written in fragment stage + uint32_t maxFragmentDualSrcAttachmentsmax number of output attachments written when using dual source blending + uint32_t maxFragmentCombinedOutputResourcesmax total number of storage buffers, storage images and output buffers + compute stage limits + uint32_t maxComputeSharedMemorySizemax total storage size of work group local storage (bytes) + uint32_t maxComputeWorkGroupCount[3]max num of compute work groups that may be dispatched by a single command (x,y,z) + uint32_t maxComputeWorkGroupInvocationsmax total compute invocations in a single local work group + uint32_t maxComputeWorkGroupSize[3]max local size of a compute work group (x,y,z) + uint32_t subPixelPrecisionBitsnumber bits of subpixel precision in screen x and y + uint32_t subTexelPrecisionBitsnumber bits of precision for selecting texel weights + uint32_t mipmapPrecisionBitsnumber bits of precision for selecting mipmap weights + uint32_t maxDrawIndexedIndexValuemax index value for indexed draw calls (for 32-bit indices) + uint32_t maxDrawIndirectCountmax draw count for indirect drawing calls + float maxSamplerLodBiasmax absolute sampler LOD bias + float maxSamplerAnisotropymax degree of sampler anisotropy + uint32_t maxViewportsmax number of active viewports + uint32_t maxViewportDimensions[2]max viewport dimensions (x,y) + float viewportBoundsRange[2]viewport bounds range (min,max) + uint32_t viewportSubPixelBitsnumber bits of subpixel precision for viewport + size_t minMemoryMapAlignmentmin required alignment of pointers returned by MapMemory (bytes) + VkDeviceSize minTexelBufferOffsetAlignmentmin required alignment for texel buffer offsets (bytes) + VkDeviceSize minUniformBufferOffsetAlignmentmin required alignment for uniform buffer sizes and offsets (bytes) + VkDeviceSize minStorageBufferOffsetAlignmentmin required alignment for storage buffer offsets (bytes) + int32_t minTexelOffsetmin texel offset for OpTextureSampleOffset + uint32_t maxTexelOffsetmax texel offset for OpTextureSampleOffset + int32_t minTexelGatherOffsetmin texel offset for OpTextureGatherOffset + uint32_t maxTexelGatherOffsetmax texel offset for OpTextureGatherOffset + float minInterpolationOffsetfurthest negative offset for interpolateAtOffset + float maxInterpolationOffsetfurthest positive offset for interpolateAtOffset + uint32_t subPixelInterpolationOffsetBitsnumber of subpixel bits for interpolateAtOffset + uint32_t maxFramebufferWidthmax width for a framebuffer + uint32_t maxFramebufferHeightmax height for a framebuffer + uint32_t maxFramebufferLayersmax layer count for a layered framebuffer + VkSampleCountFlags framebufferColorSampleCountssupported color sample counts for a framebuffer + VkSampleCountFlags framebufferDepthSampleCountssupported depth sample counts for a framebuffer + VkSampleCountFlags framebufferStencilSampleCountssupported stencil sample counts for a framebuffer + VkSampleCountFlags framebufferNoAttachmentsSampleCountssupported sample counts for a subpass which uses no attachments + uint32_t maxColorAttachmentsmax number of color attachments per subpass + VkSampleCountFlags sampledImageColorSampleCountssupported color sample counts for a non-integer sampled image + VkSampleCountFlags sampledImageIntegerSampleCountssupported sample counts for an integer image + VkSampleCountFlags sampledImageDepthSampleCountssupported depth sample counts for a sampled image + VkSampleCountFlags sampledImageStencilSampleCountssupported stencil sample counts for a sampled image + VkSampleCountFlags storageImageSampleCountssupported sample counts for a storage image + uint32_t maxSampleMaskWordsmax number of sample mask words + VkBool32 timestampComputeAndGraphicstimestamps on graphics and compute queues + float timestampPeriodnumber of nanoseconds it takes for timestamp query value to increment by 1 + uint32_t maxClipDistancesmax number of clip distances + uint32_t maxCullDistancesmax number of cull distances + uint32_t maxCombinedClipAndCullDistancesmax combined number of user clipping + uint32_t discreteQueuePrioritiesdistinct queue priorities available + float pointSizeRange[2]range (min,max) of supported point sizes + float lineWidthRange[2]range (min,max) of supported line widths + float pointSizeGranularitygranularity of supported point sizes + float lineWidthGranularitygranularity of supported line widths + VkBool32 strictLinesline rasterization follows preferred rules + VkBool32 standardSampleLocationssupports standard sample locations for all supported sample counts + VkDeviceSize optimalBufferCopyOffsetAlignmentoptimal offset of buffer copies + VkDeviceSize optimalBufferCopyRowPitchAlignmentoptimal pitch of buffer copies + VkDeviceSize nonCoherentAtomSizeminimum size and alignment for non-coherent host-mapped device memory access + + + VkStructureType sType + const void* pNext + VkSemaphoreCreateFlags flagsSemaphore creation flags + + + VkStructureType sType + const void* pNext + VkQueryPoolCreateFlags flags + VkQueryType queryType + uint32_t queryCount + VkQueryPipelineStatisticFlags pipelineStatisticsOptional + + + VkStructureType sType + const void* pNext + VkFramebufferCreateFlags flags + VkRenderPass renderPass + uint32_t attachmentCount + const VkImageView* pAttachments + uint32_t width + uint32_t height + uint32_t layers + + + uint32_t vertexCount + uint32_t instanceCount + uint32_t firstVertex + uint32_t firstInstance + + + uint32_t indexCount + uint32_t instanceCount + uint32_t firstIndex + int32_t vertexOffset + uint32_t firstInstance + + + uint32_t x + uint32_t y + uint32_t z + + + uint32_t firstVertex + uint32_t vertexCount + + + uint32_t firstIndex + uint32_t indexCount + int32_t vertexOffset + + + VkStructureType sType + const void* pNext + uint32_t waitSemaphoreCount + const VkSemaphore* pWaitSemaphores + const VkPipelineStageFlags* pWaitDstStageMask + uint32_t commandBufferCount + const VkCommandBuffer* pCommandBuffers + uint32_t signalSemaphoreCount + const VkSemaphore* pSignalSemaphores + + WSI extensions + + VkDisplayKHR displayHandle of the display object + const char* displayNameName of the display + VkExtent2D physicalDimensionsIn millimeters? + VkExtent2D physicalResolutionMax resolution for CRT? + VkSurfaceTransformFlagsKHR supportedTransformsone or more bits from VkSurfaceTransformFlagsKHR + VkBool32 planeReorderPossibleVK_TRUE if the overlay plane's z-order can be changed on this display. + VkBool32 persistentContentVK_TRUE if this is a "smart" display that supports self-refresh/internal buffering. + + + VkDisplayKHR currentDisplayDisplay the plane is currently associated with. Will be VK_NULL_HANDLE if the plane is not in use. + uint32_t currentStackIndexCurrent z-order of the plane. + + + VkExtent2D visibleRegionVisible scanout region. + uint32_t refreshRateNumber of times per second the display is updated. + + + VkDisplayModeKHR displayModeHandle of this display mode. + VkDisplayModeParametersKHR parametersThe parameters this mode uses. + + + VkStructureType sType + const void* pNext + VkDisplayModeCreateFlagsKHR flags + VkDisplayModeParametersKHR parametersThe parameters this mode uses. + + + VkDisplayPlaneAlphaFlagsKHR supportedAlphaTypes of alpha blending supported, if any. + VkOffset2D minSrcPositionDoes the plane have any position and extent restrictions? + VkOffset2D maxSrcPosition + VkExtent2D minSrcExtent + VkExtent2D maxSrcExtent + VkOffset2D minDstPosition + VkOffset2D maxDstPosition + VkExtent2D minDstExtent + VkExtent2D maxDstExtent + + + VkStructureType sType + const void* pNext + VkDisplaySurfaceCreateFlagsKHR flags + VkDisplayModeKHR displayModeThe mode to use when displaying this surface + uint32_t planeIndexThe plane on which this surface appears. Must be between 0 and the value returned by vkGetPhysicalDeviceDisplayPlanePropertiesKHR() in pPropertyCount. + uint32_t planeStackIndexThe z-order of the plane. + VkSurfaceTransformFlagBitsKHR transformTransform to apply to the images as part of the scanout operation + float globalAlphaGlobal alpha value. Must be between 0 and 1, inclusive. Ignored if alphaMode is not VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR + VkDisplayPlaneAlphaFlagBitsKHR alphaModeWhat type of alpha blending to use. Must be a bit from vkGetDisplayPlanePropertiesKHR::supportedAlpha. + VkExtent2D imageExtentsize of the images to use with this surface + + + VkStructureType sType + const void* pNext + VkRect2D srcRectRectangle within the presentable image to read pixel data from when presenting to the display. + VkRect2D dstRectRectangle within the current display mode's visible region to display srcRectangle in. + VkBool32 persistentFor smart displays, use buffered mode. If the display properties member "persistentMode" is VK_FALSE, this member must always be VK_FALSE. + + + uint32_t minImageCountSupported minimum number of images for the surface + uint32_t maxImageCountSupported maximum number of images for the surface, 0 for unlimited + VkExtent2D currentExtentCurrent image width and height for the surface, (0, 0) if undefined + VkExtent2D minImageExtentSupported minimum image width and height for the surface + VkExtent2D maxImageExtentSupported maximum image width and height for the surface + uint32_t maxImageArrayLayersSupported maximum number of image layers for the surface + VkSurfaceTransformFlagsKHR supportedTransforms1 or more bits representing the transforms supported + VkSurfaceTransformFlagBitsKHR currentTransformThe surface's current transform relative to the device's natural orientation + VkCompositeAlphaFlagsKHR supportedCompositeAlpha1 or more bits representing the alpha compositing modes supported + VkImageUsageFlags supportedUsageFlagsSupported image usage flags for the surface + + + VkStructureType sType + const void* pNext + VkAndroidSurfaceCreateFlagsKHR flags + struct ANativeWindow* window + + + VkStructureType sType + const void* pNext + VkViSurfaceCreateFlagsNN flags + void* window + + + VkStructureType sType + const void* pNext + VkWaylandSurfaceCreateFlagsKHR flags + struct wl_display* display + struct wl_surface* surface + + + VkStructureType sType + const void* pNext + VkWin32SurfaceCreateFlagsKHR flags + HINSTANCE hinstance + HWND hwnd + + + VkStructureType sType + const void* pNext + VkXlibSurfaceCreateFlagsKHR flags + Display* dpy + Window window + + + VkStructureType sType + const void* pNext + VkXcbSurfaceCreateFlagsKHR flags + xcb_connection_t* connection + xcb_window_t window + + + VkStructureType sType + const void* pNext + VkDirectFBSurfaceCreateFlagsEXT flags + IDirectFB* dfb + IDirectFBSurface* surface + + + VkStructureType sType + const void* pNext + VkImagePipeSurfaceCreateFlagsFUCHSIA flags + zx_handle_t imagePipeHandle + + + VkStructureType sType + const void* pNext + VkStreamDescriptorSurfaceCreateFlagsGGP flags + GgpStreamDescriptor streamDescriptor + + + VkStructureType sType + const void* pNext + VkScreenSurfaceCreateFlagsQNX flags + struct _screen_context* context + struct _screen_window* window + + + VkFormat formatSupported pair of rendering format + VkColorSpaceKHR colorSpaceand color space for the surface + + + VkStructureType sType + const void* pNext + VkSwapchainCreateFlagsKHR flags + VkSurfaceKHR surfaceThe swapchain's target surface + uint32_t minImageCountMinimum number of presentation images the application needs + VkFormat imageFormatFormat of the presentation images + VkColorSpaceKHR imageColorSpaceColorspace of the presentation images + VkExtent2D imageExtentDimensions of the presentation images + uint32_t imageArrayLayersDetermines the number of views for multiview/stereo presentation + VkImageUsageFlags imageUsageBits indicating how the presentation images will be used + VkSharingMode imageSharingModeSharing mode used for the presentation images + uint32_t queueFamilyIndexCountNumber of queue families having access to the images in case of concurrent sharing mode + const uint32_t* pQueueFamilyIndicesArray of queue family indices having access to the images in case of concurrent sharing mode + VkSurfaceTransformFlagBitsKHR preTransformThe transform, relative to the device's natural orientation, applied to the image content prior to presentation + VkCompositeAlphaFlagBitsKHR compositeAlphaThe alpha blending mode used when compositing this surface with other surfaces in the window system + VkPresentModeKHR presentModeWhich presentation mode to use for presents on this swap chain + VkBool32 clippedSpecifies whether presentable images may be affected by window clip regions + VkSwapchainKHR oldSwapchainExisting swap chain to replace, if any + + + VkStructureType sType + const void* pNext + uint32_t waitSemaphoreCountNumber of semaphores to wait for before presenting + const VkSemaphore* pWaitSemaphoresSemaphores to wait for before presenting + uint32_t swapchainCountNumber of swapchains to present in this call + const VkSwapchainKHR* pSwapchainsSwapchains to present an image from + const uint32_t* pImageIndicesIndices of which presentable images to present + VkResult* pResultsOptional (i.e. if non-NULL) VkResult for each swapchain + + + VkStructureType sType + const void* pNext + VkDebugReportFlagsEXT flagsIndicates which events call this callback + PFN_vkDebugReportCallbackEXT pfnCallbackFunction pointer of a callback function + void* pUserDataUser data provided to callback function + + + VkStructureType sTypeMust be VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT + const void* pNext + uint32_t disabledValidationCheckCountNumber of validation checks to disable + const VkValidationCheckEXT* pDisabledValidationChecksValidation checks to disable + + + VkStructureType sTypeMust be VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT + const void* pNext + uint32_t enabledValidationFeatureCountNumber of validation features to enable + const VkValidationFeatureEnableEXT* pEnabledValidationFeaturesValidation features to enable + uint32_t disabledValidationFeatureCountNumber of validation features to disable + const VkValidationFeatureDisableEXT* pDisabledValidationFeaturesValidation features to disable + + + VkStructureType sType + const void* pNext + VkRasterizationOrderAMD rasterizationOrderRasterization order to use for the pipeline + + + VkStructureType sType + const void* pNext + VkDebugReportObjectTypeEXT objectTypeThe type of the object + uint64_t objectThe handle of the object, cast to uint64_t + const char* pObjectNameName to apply to the object + + + VkStructureType sType + const void* pNext + VkDebugReportObjectTypeEXT objectTypeThe type of the object + uint64_t objectThe handle of the object, cast to uint64_t + uint64_t tagNameThe name of the tag to set on the object + size_t tagSizeThe length in bytes of the tag data + const void* pTagTag data to attach to the object + + + VkStructureType sType + const void* pNext + const char* pMarkerNameName of the debug marker + float color[4]Optional color for debug marker + + + VkStructureType sType + const void* pNext + VkBool32 dedicatedAllocationWhether this image uses a dedicated allocation + + + VkStructureType sType + const void* pNext + VkBool32 dedicatedAllocationWhether this buffer uses a dedicated allocation + + + VkStructureType sType + const void* pNext + VkImage imageImage that this allocation will be bound to + VkBuffer bufferBuffer that this allocation will be bound to + + + VkImageFormatProperties imageFormatProperties + VkExternalMemoryFeatureFlagsNV externalMemoryFeatures + VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes + VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes + + + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlagsNV handleTypes + + + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlagsNV handleTypes + + + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlagsNV handleType + HANDLE handle + + + VkStructureType sType + const void* pNext + const SECURITY_ATTRIBUTES* pAttributes + DWORD dwAccess + + + VkStructureType sType + const void* pNext + uint32_t acquireCount + const VkDeviceMemory* pAcquireSyncs + const uint64_t* pAcquireKeys + const uint32_t* pAcquireTimeoutMilliseconds + uint32_t releaseCount + const VkDeviceMemory* pReleaseSyncs + const uint64_t* pReleaseKeys + + + VkStructureType sType + void* pNext + VkBool32 deviceGeneratedCommands + + + VkStructureType sType + const void* pNext + uint32_t privateDataSlotRequestCount + + + + VkStructureType sType + const void* pNext + VkPrivateDataSlotCreateFlags flags + + + + VkStructureType sType + void* pNext + VkBool32 privateData + + + + VkStructureType sType + void* pNext + uint32_t maxGraphicsShaderGroupCount + uint32_t maxIndirectSequenceCount + uint32_t maxIndirectCommandsTokenCount + uint32_t maxIndirectCommandsStreamCount + uint32_t maxIndirectCommandsTokenOffset + uint32_t maxIndirectCommandsStreamStride + uint32_t minSequencesCountBufferOffsetAlignment + uint32_t minSequencesIndexBufferOffsetAlignment + uint32_t minIndirectCommandsBufferOffsetAlignment + + + VkStructureType sType + void* pNext + uint32_t maxMultiDrawCount + + + VkStructureType sType + const void* pNext + uint32_t stageCount + const VkPipelineShaderStageCreateInfo* pStages + const VkPipelineVertexInputStateCreateInfo* pVertexInputState + const VkPipelineTessellationStateCreateInfo* pTessellationState + + + VkStructureType sType + const void* pNext + uint32_t groupCount + const VkGraphicsShaderGroupCreateInfoNV* pGroups + uint32_t pipelineCount + const VkPipeline* pPipelines + + + uint32_t groupIndex + + + VkDeviceAddress bufferAddress + uint32_t size + VkIndexType indexType + + + VkDeviceAddress bufferAddress + uint32_t size + uint32_t stride + + + uint32_t data + + + VkBuffer buffer + VkDeviceSize offset + + + VkStructureType sType + const void* pNext + VkIndirectCommandsTokenTypeNV tokenType + uint32_t stream + uint32_t offset + uint32_t vertexBindingUnit + VkBool32 vertexDynamicStride + VkPipelineLayout pushconstantPipelineLayout + VkShaderStageFlags pushconstantShaderStageFlags + uint32_t pushconstantOffset + uint32_t pushconstantSize + VkIndirectStateFlagsNV indirectStateFlags + uint32_t indexTypeCount + const VkIndexType* pIndexTypes + const uint32_t* pIndexTypeValues + + + VkStructureType sType + const void* pNext + VkIndirectCommandsLayoutUsageFlagsNV flags + VkPipelineBindPoint pipelineBindPoint + uint32_t tokenCount + const VkIndirectCommandsLayoutTokenNV* pTokens + uint32_t streamCount + const uint32_t* pStreamStrides + + + VkStructureType sType + const void* pNext + VkPipelineBindPoint pipelineBindPoint + VkPipeline pipeline + VkIndirectCommandsLayoutNV indirectCommandsLayout + uint32_t streamCount + const VkIndirectCommandsStreamNV* pStreams + uint32_t sequencesCount + VkBuffer preprocessBuffer + VkDeviceSize preprocessOffset + VkDeviceSize preprocessSize + VkBuffer sequencesCountBuffer + VkDeviceSize sequencesCountOffset + VkBuffer sequencesIndexBuffer + VkDeviceSize sequencesIndexOffset + + + VkStructureType sType + const void* pNext + VkPipelineBindPoint pipelineBindPoint + VkPipeline pipeline + VkIndirectCommandsLayoutNV indirectCommandsLayout + uint32_t maxSequencesCount + + + VkStructureType sType + void* pNext + VkPhysicalDeviceFeatures features + + + + VkStructureType sType + void* pNext + VkPhysicalDeviceProperties properties + + + + VkStructureType sType + void* pNext + VkFormatProperties formatProperties + + + + VkStructureType sType + void* pNext + VkImageFormatProperties imageFormatProperties + + + + VkStructureType sType + const void* pNext + VkFormat format + VkImageType type + VkImageTiling tiling + VkImageUsageFlags usage + VkImageCreateFlags flags + + + + VkStructureType sType + void* pNext + VkQueueFamilyProperties queueFamilyProperties + + + + VkStructureType sType + void* pNext + VkPhysicalDeviceMemoryProperties memoryProperties + + + + VkStructureType sType + void* pNext + VkSparseImageFormatProperties properties + + + + VkStructureType sType + const void* pNext + VkFormat format + VkImageType type + VkSampleCountFlagBits samples + VkImageUsageFlags usage + VkImageTiling tiling + + + + VkStructureType sType + void* pNext + uint32_t maxPushDescriptors + + + uint8_t major + uint8_t minor + uint8_t subminor + uint8_t patch + + + + VkStructureType sType + void* pNext + VkDriverId driverID + char driverName[VK_MAX_DRIVER_NAME_SIZE] + char driverInfo[VK_MAX_DRIVER_INFO_SIZE] + VkConformanceVersion conformanceVersion + + + + VkStructureType sType + const void* pNext + uint32_t swapchainCountCopy of VkPresentInfoKHR::swapchainCount + const VkPresentRegionKHR* pRegionsThe regions that have changed + + + uint32_t rectangleCountNumber of rectangles in pRectangles + const VkRectLayerKHR* pRectanglesArray of rectangles that have changed in a swapchain's image(s) + + + VkOffset2D offsetupper-left corner of a rectangle that has not changed, in pixels of a presentation images + VkExtent2D extentDimensions of a rectangle that has not changed, in pixels of a presentation images + uint32_t layerLayer of a swapchain's image(s), for stereoscopic-3D images + + + VkStructureType sType + void* pNext + VkBool32 variablePointersStorageBuffer + VkBool32 variablePointers + + + + + + VkExternalMemoryFeatureFlags externalMemoryFeatures + VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes + VkExternalMemoryHandleTypeFlags compatibleHandleTypes + + + + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlagBits handleType + + + + VkStructureType sType + void* pNext + VkExternalMemoryProperties externalMemoryProperties + + + + VkStructureType sType + const void* pNext + VkBufferCreateFlags flags + VkBufferUsageFlags usage + VkExternalMemoryHandleTypeFlagBits handleType + + + + VkStructureType sType + void* pNext + VkExternalMemoryProperties externalMemoryProperties + + + + VkStructureType sType + void* pNext + uint8_t deviceUUID[VK_UUID_SIZE] + uint8_t driverUUID[VK_UUID_SIZE] + uint8_t deviceLUID[VK_LUID_SIZE] + uint32_t deviceNodeMask + VkBool32 deviceLUIDValid + + + + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlags handleTypes + + + + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlags handleTypes + + + + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlags handleTypes + + + + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlagBits handleType + HANDLE handle + LPCWSTR name + + + VkStructureType sType + const void* pNext + const SECURITY_ATTRIBUTES* pAttributes + DWORD dwAccess + LPCWSTR name + + + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlagBits handleType + zx_handle_t handle + + + VkStructureType sType + void* pNext + uint32_t memoryTypeBits + + + VkStructureType sType + const void* pNext + VkDeviceMemory memory + VkExternalMemoryHandleTypeFlagBits handleType + + + VkStructureType sType + void* pNext + uint32_t memoryTypeBits + + + VkStructureType sType + const void* pNext + VkDeviceMemory memory + VkExternalMemoryHandleTypeFlagBits handleType + + + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlagBits handleType + int fd + + + VkStructureType sType + void* pNext + uint32_t memoryTypeBits + + + VkStructureType sType + const void* pNext + VkDeviceMemory memory + VkExternalMemoryHandleTypeFlagBits handleType + + + VkStructureType sType + const void* pNext + uint32_t acquireCount + const VkDeviceMemory* pAcquireSyncs + const uint64_t* pAcquireKeys + const uint32_t* pAcquireTimeouts + uint32_t releaseCount + const VkDeviceMemory* pReleaseSyncs + const uint64_t* pReleaseKeys + + + VkStructureType sType + const void* pNext + VkExternalSemaphoreHandleTypeFlagBits handleType + + + + VkStructureType sType + void* pNext + VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes + VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes + VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures + + + + VkStructureType sType + const void* pNext + VkExternalSemaphoreHandleTypeFlags handleTypes + + + + VkStructureType sType + const void* pNext + VkSemaphore semaphore + VkSemaphoreImportFlags flags + VkExternalSemaphoreHandleTypeFlagBits handleType + HANDLE handle + LPCWSTR name + + + VkStructureType sType + const void* pNext + const SECURITY_ATTRIBUTES* pAttributes + DWORD dwAccess + LPCWSTR name + + + VkStructureType sType + const void* pNext + uint32_t waitSemaphoreValuesCount + const uint64_t* pWaitSemaphoreValues + uint32_t signalSemaphoreValuesCount + const uint64_t* pSignalSemaphoreValues + + + VkStructureType sType + const void* pNext + VkSemaphore semaphore + VkExternalSemaphoreHandleTypeFlagBits handleType + + + VkStructureType sType + const void* pNext + VkSemaphore semaphore + VkSemaphoreImportFlags flags + VkExternalSemaphoreHandleTypeFlagBits handleType + int fd + + + VkStructureType sType + const void* pNext + VkSemaphore semaphore + VkExternalSemaphoreHandleTypeFlagBits handleType + + + VkStructureType sType + const void* pNext + VkSemaphore semaphore + VkSemaphoreImportFlags flags + VkExternalSemaphoreHandleTypeFlagBits handleType + zx_handle_t zirconHandle + + + VkStructureType sType + const void* pNext + VkSemaphore semaphore + VkExternalSemaphoreHandleTypeFlagBits handleType + + + VkStructureType sType + const void* pNext + VkExternalFenceHandleTypeFlagBits handleType + + + + VkStructureType sType + void* pNext + VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes + VkExternalFenceHandleTypeFlags compatibleHandleTypes + VkExternalFenceFeatureFlags externalFenceFeatures + + + + VkStructureType sType + const void* pNext + VkExternalFenceHandleTypeFlags handleTypes + + + + VkStructureType sType + const void* pNext + VkFence fence + VkFenceImportFlags flags + VkExternalFenceHandleTypeFlagBits handleType + HANDLE handle + LPCWSTR name + + + VkStructureType sType + const void* pNext + const SECURITY_ATTRIBUTES* pAttributes + DWORD dwAccess + LPCWSTR name + + + VkStructureType sType + const void* pNext + VkFence fence + VkExternalFenceHandleTypeFlagBits handleType + + + VkStructureType sType + const void* pNext + VkFence fence + VkFenceImportFlags flags + VkExternalFenceHandleTypeFlagBits handleType + int fd + + + VkStructureType sType + const void* pNext + VkFence fence + VkExternalFenceHandleTypeFlagBits handleType + + + VkStructureType sType + void* pNext + VkBool32 multiviewMultiple views in a renderpass + VkBool32 multiviewGeometryShaderMultiple views in a renderpass w/ geometry shader + VkBool32 multiviewTessellationShaderMultiple views in a renderpass w/ tessellation shader + + + + VkStructureType sType + void* pNext + uint32_t maxMultiviewViewCountmax number of views in a subpass + uint32_t maxMultiviewInstanceIndexmax instance index for a draw in a multiview subpass + + + + VkStructureType sType + const void* pNext + uint32_t subpassCount + const uint32_t* pViewMasks + uint32_t dependencyCount + const int32_t* pViewOffsets + uint32_t correlationMaskCount + const uint32_t* pCorrelationMasks + + + + VkStructureType sType + void* pNext + uint32_t minImageCountSupported minimum number of images for the surface + uint32_t maxImageCountSupported maximum number of images for the surface, 0 for unlimited + VkExtent2D currentExtentCurrent image width and height for the surface, (0, 0) if undefined + VkExtent2D minImageExtentSupported minimum image width and height for the surface + VkExtent2D maxImageExtentSupported maximum image width and height for the surface + uint32_t maxImageArrayLayersSupported maximum number of image layers for the surface + VkSurfaceTransformFlagsKHR supportedTransforms1 or more bits representing the transforms supported + VkSurfaceTransformFlagBitsKHR currentTransformThe surface's current transform relative to the device's natural orientation + VkCompositeAlphaFlagsKHR supportedCompositeAlpha1 or more bits representing the alpha compositing modes supported + VkImageUsageFlags supportedUsageFlagsSupported image usage flags for the surface + VkSurfaceCounterFlagsEXT supportedSurfaceCounters + + + VkStructureType sType + const void* pNext + VkDisplayPowerStateEXT powerState + + + VkStructureType sType + const void* pNext + VkDeviceEventTypeEXT deviceEvent + + + VkStructureType sType + const void* pNext + VkDisplayEventTypeEXT displayEvent + + + VkStructureType sType + const void* pNext + VkSurfaceCounterFlagsEXT surfaceCounters + + + VkStructureType sType + void* pNext + uint32_t physicalDeviceCount + VkPhysicalDevice physicalDevices[VK_MAX_DEVICE_GROUP_SIZE] + VkBool32 subsetAllocation + + + + VkStructureType sType + const void* pNext + VkMemoryAllocateFlags flags + uint32_t deviceMask + + + + VkStructureType sType + const void* pNext + VkBuffer buffer + VkDeviceMemory memory + VkDeviceSize memoryOffset + + + + VkStructureType sType + const void* pNext + uint32_t deviceIndexCount + const uint32_t* pDeviceIndices + + + + VkStructureType sType + const void* pNext + VkImage image + VkDeviceMemory memory + VkDeviceSize memoryOffset + + + + VkStructureType sType + const void* pNext + uint32_t deviceIndexCount + const uint32_t* pDeviceIndices + uint32_t splitInstanceBindRegionCount + const VkRect2D* pSplitInstanceBindRegions + + + + VkStructureType sType + const void* pNext + uint32_t deviceMask + uint32_t deviceRenderAreaCount + const VkRect2D* pDeviceRenderAreas + + + + VkStructureType sType + const void* pNext + uint32_t deviceMask + + + + VkStructureType sType + const void* pNext + uint32_t waitSemaphoreCount + const uint32_t* pWaitSemaphoreDeviceIndices + uint32_t commandBufferCount + const uint32_t* pCommandBufferDeviceMasks + uint32_t signalSemaphoreCount + const uint32_t* pSignalSemaphoreDeviceIndices + + + + VkStructureType sType + const void* pNext + uint32_t resourceDeviceIndex + uint32_t memoryDeviceIndex + + + + VkStructureType sType + void* pNext + uint32_t presentMask[VK_MAX_DEVICE_GROUP_SIZE] + VkDeviceGroupPresentModeFlagsKHR modes + + + VkStructureType sType + const void* pNext + VkSwapchainKHR swapchain + + + VkStructureType sType + const void* pNext + VkSwapchainKHR swapchain + uint32_t imageIndex + + + VkStructureType sType + const void* pNext + VkSwapchainKHR swapchain + uint64_t timeout + VkSemaphore semaphore + VkFence fence + uint32_t deviceMask + + + VkStructureType sType + const void* pNext + uint32_t swapchainCount + const uint32_t* pDeviceMasks + VkDeviceGroupPresentModeFlagBitsKHR mode + + + VkStructureType sType + const void* pNext + uint32_t physicalDeviceCount + const VkPhysicalDevice* pPhysicalDevices + + + + VkStructureType sType + const void* pNext + VkDeviceGroupPresentModeFlagsKHR modes + + + uint32_t dstBindingBinding within the destination descriptor set to write + uint32_t dstArrayElementArray element within the destination binding to write + uint32_t descriptorCountNumber of descriptors to write + VkDescriptorType descriptorTypeDescriptor type to write + size_t offsetOffset into pData where the descriptors to update are stored + size_t strideStride between two descriptors in pData when writing more than one descriptor + + + + VkStructureType sType + const void* pNext + VkDescriptorUpdateTemplateCreateFlags flags + uint32_t descriptorUpdateEntryCountNumber of descriptor update entries to use for the update template + const VkDescriptorUpdateTemplateEntry* pDescriptorUpdateEntriesDescriptor update entries for the template + VkDescriptorUpdateTemplateType templateType + VkDescriptorSetLayout descriptorSetLayout + VkPipelineBindPoint pipelineBindPoint + VkPipelineLayout pipelineLayoutIf used for push descriptors, this is the only allowed layout + uint32_t set + + + + float x + float y + + + VkStructureType sType + void* pNext + VkBool32 presentIdPresent ID in VkPresentInfoKHR + + + VkStructureType sType + const void* pNext + uint32_t swapchainCountCopy of VkPresentInfoKHR::swapchainCount + const uint64_t* pPresentIdsPresent ID values for each swapchain + + + VkStructureType sType + void* pNext + VkBool32 presentWaitvkWaitForPresentKHR is supported + + + Display primary in chromaticity coordinates + VkStructureType sType + const void* pNext + From SMPTE 2086 + VkXYColorEXT displayPrimaryRedDisplay primary's Red + VkXYColorEXT displayPrimaryGreenDisplay primary's Green + VkXYColorEXT displayPrimaryBlueDisplay primary's Blue + VkXYColorEXT whitePointDisplay primary's Blue + float maxLuminanceDisplay maximum luminance + float minLuminanceDisplay minimum luminance + From CTA 861.3 + float maxContentLightLevelContent maximum luminance + float maxFrameAverageLightLevel + + + VkStructureType sType + void* pNext + VkBool32 localDimmingSupport + + + VkStructureType sType + const void* pNext + VkBool32 localDimmingEnable + + + uint64_t refreshDurationNumber of nanoseconds from the start of one refresh cycle to the next + + + uint32_t presentIDApplication-provided identifier, previously given to vkQueuePresentKHR + uint64_t desiredPresentTimeEarliest time an image should have been presented, previously given to vkQueuePresentKHR + uint64_t actualPresentTimeTime the image was actually displayed + uint64_t earliestPresentTimeEarliest time the image could have been displayed + uint64_t presentMarginHow early vkQueuePresentKHR was processed vs. how soon it needed to be and make earliestPresentTime + + + VkStructureType sType + const void* pNext + uint32_t swapchainCountCopy of VkPresentInfoKHR::swapchainCount + const VkPresentTimeGOOGLE* pTimesThe earliest times to present images + + + uint32_t presentIDApplication-provided identifier + uint64_t desiredPresentTimeEarliest time an image should be presented + + + VkStructureType sType + const void* pNext + VkIOSSurfaceCreateFlagsMVK flags + const void* pView + + + VkStructureType sType + const void* pNext + VkMacOSSurfaceCreateFlagsMVK flags + const void* pView + + + VkStructureType sType + const void* pNext + VkMetalSurfaceCreateFlagsEXT flags + const CAMetalLayer* pLayer + + + float xcoeff + float ycoeff + + + VkStructureType sType + const void* pNext + VkBool32 viewportWScalingEnable + uint32_t viewportCount + const VkViewportWScalingNV* pViewportWScalings + + + VkViewportCoordinateSwizzleNV x + VkViewportCoordinateSwizzleNV y + VkViewportCoordinateSwizzleNV z + VkViewportCoordinateSwizzleNV w + + + VkStructureType sType + const void* pNext + VkPipelineViewportSwizzleStateCreateFlagsNV flags + uint32_t viewportCount + const VkViewportSwizzleNV* pViewportSwizzles + + + VkStructureType sType + void* pNext + uint32_t maxDiscardRectanglesmax number of active discard rectangles + + + VkStructureType sType + const void* pNext + VkPipelineDiscardRectangleStateCreateFlagsEXT flags + VkDiscardRectangleModeEXT discardRectangleMode + uint32_t discardRectangleCount + const VkRect2D* pDiscardRectangles + + + VkStructureType sType + void* pNext + VkBool32 perViewPositionAllComponents + + + uint32_t subpass + uint32_t inputAttachmentIndex + VkImageAspectFlags aspectMask + + + + VkStructureType sType + const void* pNext + uint32_t aspectReferenceCount + const VkInputAttachmentAspectReference* pAspectReferences + + + + VkStructureType sType + const void* pNext + VkSurfaceKHR surface + + + VkStructureType sType + void* pNext + VkSurfaceCapabilitiesKHR surfaceCapabilities + + + VkStructureType sType + void* pNext + VkSurfaceFormatKHR surfaceFormat + + + VkStructureType sType + void* pNext + VkDisplayPropertiesKHR displayProperties + + + VkStructureType sType + void* pNext + VkDisplayPlanePropertiesKHR displayPlaneProperties + + + VkStructureType sType + void* pNext + VkDisplayModePropertiesKHR displayModeProperties + + + VkStructureType sType + const void* pNext + VkDisplayModeKHR mode + uint32_t planeIndex + + + VkStructureType sType + void* pNext + VkDisplayPlaneCapabilitiesKHR capabilities + + + VkStructureType sType + void* pNext + VkImageUsageFlags sharedPresentSupportedUsageFlagsSupported image usage flags if swapchain created using a shared present mode + + + VkStructureType sType + void* pNext + VkBool32 storageBuffer16BitAccess16-bit integer/floating-point variables supported in BufferBlock + VkBool32 uniformAndStorageBuffer16BitAccess16-bit integer/floating-point variables supported in BufferBlock and Block + VkBool32 storagePushConstant1616-bit integer/floating-point variables supported in PushConstant + VkBool32 storageInputOutput1616-bit integer/floating-point variables supported in shader inputs and outputs + + + + VkStructureType sType + void* pNext + uint32_t subgroupSizeThe size of a subgroup for this queue. + VkShaderStageFlags supportedStagesBitfield of what shader stages support subgroup operations + VkSubgroupFeatureFlags supportedOperationsBitfield of what subgroup operations are supported. + VkBool32 quadOperationsInAllStagesFlag to specify whether quad operations are available in all stages. + + + VkStructureType sType + void* pNext + VkBool32 shaderSubgroupExtendedTypesFlag to specify whether subgroup operations with extended types are supported + + + + VkStructureType sType + const void* pNext + VkBuffer buffer + + + + VkStructureType sType + const void* pNext + const VkBufferCreateInfo* pCreateInfo + + + + VkStructureType sType + const void* pNext + VkImage image + + + + VkStructureType sType + const void* pNext + VkImage image + + + + VkStructureType sType + const void* pNext + const VkImageCreateInfo* pCreateInfo + VkImageAspectFlagBits planeAspect + + + + VkStructureType sType + void* pNext + VkMemoryRequirements memoryRequirements + + + + VkStructureType sType + void* pNext + VkSparseImageMemoryRequirements memoryRequirements + + + + VkStructureType sType + void* pNext + VkPointClippingBehavior pointClippingBehavior + + + + VkStructureType sType + void* pNext + VkBool32 prefersDedicatedAllocation + VkBool32 requiresDedicatedAllocation + + + + VkStructureType sType + const void* pNext + VkImage imageImage that this allocation will be bound to + VkBuffer bufferBuffer that this allocation will be bound to + + + + VkStructureType sType + const void* pNext + VkImageUsageFlags usage + + + + VkStructureType sType + const void* pNext + VkTessellationDomainOrigin domainOrigin + + + + VkStructureType sType + const void* pNext + VkSamplerYcbcrConversion conversion + + + + VkStructureType sType + const void* pNext + VkFormat format + VkSamplerYcbcrModelConversion ycbcrModel + VkSamplerYcbcrRange ycbcrRange + VkComponentMapping components + VkChromaLocation xChromaOffset + VkChromaLocation yChromaOffset + VkFilter chromaFilter + VkBool32 forceExplicitReconstruction + + + + VkStructureType sType + const void* pNext + VkImageAspectFlagBits planeAspect + + + + VkStructureType sType + const void* pNext + VkImageAspectFlagBits planeAspect + + + + VkStructureType sType + void* pNext + VkBool32 samplerYcbcrConversionSampler color conversion supported + + + + VkStructureType sType + void* pNext + uint32_t combinedImageSamplerDescriptorCount + + + + VkStructureType sType + void* pNext + VkBool32 supportsTextureGatherLODBiasAMD + + + VkStructureType sType + const void* pNext + VkBuffer buffer + VkDeviceSize offset + VkConditionalRenderingFlagsEXT flags + + + VkStructureType sType + const void* pNext + VkBool32 protectedSubmitSubmit protected command buffers + + + VkStructureType sType + void* pNext + VkBool32 protectedMemory + + + VkStructureType sType + void* pNext + VkBool32 protectedNoFault + + + VkStructureType sType + const void* pNext + VkDeviceQueueCreateFlags flags + uint32_t queueFamilyIndex + uint32_t queueIndex + + + VkStructureType sType + const void* pNext + VkPipelineCoverageToColorStateCreateFlagsNV flags + VkBool32 coverageToColorEnable + uint32_t coverageToColorLocation + + + VkStructureType sType + void* pNext + VkBool32 filterMinmaxSingleComponentFormats + VkBool32 filterMinmaxImageComponentMapping + + + + float x + float y + + + VkStructureType sType + const void* pNext + VkSampleCountFlagBits sampleLocationsPerPixel + VkExtent2D sampleLocationGridSize + uint32_t sampleLocationsCount + const VkSampleLocationEXT* pSampleLocations + + + uint32_t attachmentIndex + VkSampleLocationsInfoEXT sampleLocationsInfo + + + uint32_t subpassIndex + VkSampleLocationsInfoEXT sampleLocationsInfo + + + VkStructureType sType + const void* pNext + uint32_t attachmentInitialSampleLocationsCount + const VkAttachmentSampleLocationsEXT* pAttachmentInitialSampleLocations + uint32_t postSubpassSampleLocationsCount + const VkSubpassSampleLocationsEXT* pPostSubpassSampleLocations + + + VkStructureType sType + const void* pNext + VkBool32 sampleLocationsEnable + VkSampleLocationsInfoEXT sampleLocationsInfo + + + VkStructureType sType + void* pNext + VkSampleCountFlags sampleLocationSampleCounts + VkExtent2D maxSampleLocationGridSize + float sampleLocationCoordinateRange[2] + uint32_t sampleLocationSubPixelBits + VkBool32 variableSampleLocations + + + VkStructureType sType + void* pNext + VkExtent2D maxSampleLocationGridSize + + + VkStructureType sType + const void* pNext + VkSamplerReductionMode reductionMode + + + + VkStructureType sType + void* pNext + VkBool32 advancedBlendCoherentOperations + + + VkStructureType sType + void* pNext + VkBool32 multiDraw + + + VkStructureType sType + void* pNext + uint32_t advancedBlendMaxColorAttachments + VkBool32 advancedBlendIndependentBlend + VkBool32 advancedBlendNonPremultipliedSrcColor + VkBool32 advancedBlendNonPremultipliedDstColor + VkBool32 advancedBlendCorrelatedOverlap + VkBool32 advancedBlendAllOperations + + + VkStructureType sType + const void* pNext + VkBool32 srcPremultiplied + VkBool32 dstPremultiplied + VkBlendOverlapEXT blendOverlap + + + VkStructureType sType + void* pNext + VkBool32 inlineUniformBlock + VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind + + + + VkStructureType sType + void* pNext + uint32_t maxInlineUniformBlockSize + uint32_t maxPerStageDescriptorInlineUniformBlocks + uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks + uint32_t maxDescriptorSetInlineUniformBlocks + uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks + + + + VkStructureType sType + const void* pNext + uint32_t dataSize + const void* pData + + + + VkStructureType sType + const void* pNext + uint32_t maxInlineUniformBlockBindings + + + + VkStructureType sType + const void* pNext + VkPipelineCoverageModulationStateCreateFlagsNV flags + VkCoverageModulationModeNV coverageModulationMode + VkBool32 coverageModulationTableEnable + uint32_t coverageModulationTableCount + const float* pCoverageModulationTable + + + VkStructureType sType + const void* pNext + uint32_t viewFormatCount + const VkFormat* pViewFormats + + + + VkStructureType sType + const void* pNext + VkValidationCacheCreateFlagsEXT flags + size_t initialDataSize + const void* pInitialData + + + VkStructureType sType + const void* pNext + VkValidationCacheEXT validationCache + + + VkStructureType sType + void* pNext + uint32_t maxPerSetDescriptors + VkDeviceSize maxMemoryAllocationSize + + + + VkStructureType sType + void* pNext + VkBool32 maintenance4 + + + + VkStructureType sType + void* pNext + VkDeviceSize maxBufferSize + + + + VkStructureType sType + void* pNext + VkBool32 supported + + + + VkStructureType sType + void* pNext + VkBool32 shaderDrawParameters + + + + VkStructureType sType + void* pNext + VkBool32 shaderFloat1616-bit floats (halfs) in shaders + VkBool32 shaderInt88-bit integers in shaders + + + + + VkStructureType sType + void* pNext + VkShaderFloatControlsIndependence denormBehaviorIndependence + VkShaderFloatControlsIndependence roundingModeIndependence + VkBool32 shaderSignedZeroInfNanPreserveFloat16An implementation can preserve signed zero, nan, inf + VkBool32 shaderSignedZeroInfNanPreserveFloat32An implementation can preserve signed zero, nan, inf + VkBool32 shaderSignedZeroInfNanPreserveFloat64An implementation can preserve signed zero, nan, inf + VkBool32 shaderDenormPreserveFloat16An implementation can preserve denormals + VkBool32 shaderDenormPreserveFloat32An implementation can preserve denormals + VkBool32 shaderDenormPreserveFloat64An implementation can preserve denormals + VkBool32 shaderDenormFlushToZeroFloat16An implementation can flush to zero denormals + VkBool32 shaderDenormFlushToZeroFloat32An implementation can flush to zero denormals + VkBool32 shaderDenormFlushToZeroFloat64An implementation can flush to zero denormals + VkBool32 shaderRoundingModeRTEFloat16An implementation can support RTE + VkBool32 shaderRoundingModeRTEFloat32An implementation can support RTE + VkBool32 shaderRoundingModeRTEFloat64An implementation can support RTE + VkBool32 shaderRoundingModeRTZFloat16An implementation can support RTZ + VkBool32 shaderRoundingModeRTZFloat32An implementation can support RTZ + VkBool32 shaderRoundingModeRTZFloat64An implementation can support RTZ + + + + VkStructureType sType + void* pNext + VkBool32 hostQueryReset + + + + uint64_t consumer + uint64_t producer + + + VkStructureType sType + const void* pNext + const void* handle + int stride + int format + int usage + VkNativeBufferUsage2ANDROID usage2 + + + VkStructureType sType + const void* pNext + VkSwapchainImageUsageFlagsANDROID usage + + + VkStructureType sType + const void* pNext + VkBool32 sharedImage + + + uint32_t numUsedVgprs + uint32_t numUsedSgprs + uint32_t ldsSizePerLocalWorkGroup + size_t ldsUsageSizeInBytes + size_t scratchMemUsageInBytes + + + VkShaderStageFlags shaderStageMask + VkShaderResourceUsageAMD resourceUsage + uint32_t numPhysicalVgprs + uint32_t numPhysicalSgprs + uint32_t numAvailableVgprs + uint32_t numAvailableSgprs + uint32_t computeWorkGroupSize[3] + + + VkStructureType sType + const void* pNext + VkQueueGlobalPriorityKHR globalPriority + + + + VkStructureType sType + void* pNext + VkBool32 globalPriorityQuery + + + + VkStructureType sType + void* pNext + uint32_t priorityCount + VkQueueGlobalPriorityKHR priorities[VK_MAX_GLOBAL_PRIORITY_SIZE_KHR] + + + + VkStructureType sType + const void* pNext + VkObjectType objectType + uint64_t objectHandle + const char* pObjectName + + + VkStructureType sType + const void* pNext + VkObjectType objectType + uint64_t objectHandle + uint64_t tagName + size_t tagSize + const void* pTag + + + VkStructureType sType + const void* pNext + const char* pLabelName + float color[4] + + + VkStructureType sType + const void* pNext + VkDebugUtilsMessengerCreateFlagsEXT flags + VkDebugUtilsMessageSeverityFlagsEXT messageSeverity + VkDebugUtilsMessageTypeFlagsEXT messageType + PFN_vkDebugUtilsMessengerCallbackEXT pfnUserCallback + void* pUserData + + + VkStructureType sType + const void* pNext + VkDebugUtilsMessengerCallbackDataFlagsEXT flags + const char* pMessageIdName + int32_t messageIdNumber + const char* pMessage + uint32_t queueLabelCount + const VkDebugUtilsLabelEXT* pQueueLabels + uint32_t cmdBufLabelCount + const VkDebugUtilsLabelEXT* pCmdBufLabels + uint32_t objectCount + const VkDebugUtilsObjectNameInfoEXT* pObjects + + + VkStructureType sType + void* pNext + VkBool32 deviceMemoryReport + + + VkStructureType sType + const void* pNext + VkDeviceMemoryReportFlagsEXT flags + PFN_vkDeviceMemoryReportCallbackEXT pfnUserCallback + void* pUserData + + + VkStructureType sType + void* pNext + VkDeviceMemoryReportFlagsEXT flags + VkDeviceMemoryReportEventTypeEXT type + uint64_t memoryObjectId + VkDeviceSize size + VkObjectType objectType + uint64_t objectHandle + uint32_t heapIndex + + + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlagBits handleType + void* pHostPointer + + + VkStructureType sType + void* pNext + uint32_t memoryTypeBits + + + VkStructureType sType + void* pNext + VkDeviceSize minImportedHostPointerAlignment + + + VkStructureType sType + void* pNext + float primitiveOverestimationSizeThe size in pixels the primitive is enlarged at each edge during conservative rasterization + float maxExtraPrimitiveOverestimationSizeThe maximum additional overestimation the client can specify in the pipeline state + float extraPrimitiveOverestimationSizeGranularityThe granularity of extra overestimation sizes the implementations supports between 0 and maxExtraOverestimationSize + VkBool32 primitiveUnderestimationtrue if the implementation supports conservative rasterization underestimation mode + VkBool32 conservativePointAndLineRasterizationtrue if conservative rasterization also applies to points and lines + VkBool32 degenerateTrianglesRasterizedtrue if degenerate triangles (those with zero area after snap) are rasterized + VkBool32 degenerateLinesRasterizedtrue if degenerate lines (those with zero length after snap) are rasterized + VkBool32 fullyCoveredFragmentShaderInputVariabletrue if the implementation supports the FullyCoveredEXT SPIR-V builtin fragment shader input variable + VkBool32 conservativeRasterizationPostDepthCoveragetrue if the implementation supports both conservative rasterization and post depth coverage sample coverage mask + + + VkStructureType sType + const void* pNext + VkTimeDomainEXT timeDomain + + + VkStructureType sType + void* pNext + uint32_t shaderEngineCountnumber of shader engines + uint32_t shaderArraysPerEngineCountnumber of shader arrays + uint32_t computeUnitsPerShaderArraynumber of physical CUs per shader array + uint32_t simdPerComputeUnitnumber of SIMDs per compute unit + uint32_t wavefrontsPerSimdnumber of wavefront slots in each SIMD + uint32_t wavefrontSizemaximum number of threads per wavefront + uint32_t sgprsPerSimdnumber of physical SGPRs per SIMD + uint32_t minSgprAllocationminimum number of SGPRs that can be allocated by a wave + uint32_t maxSgprAllocationnumber of available SGPRs + uint32_t sgprAllocationGranularitySGPRs are allocated in groups of this size + uint32_t vgprsPerSimdnumber of physical VGPRs per SIMD + uint32_t minVgprAllocationminimum number of VGPRs that can be allocated by a wave + uint32_t maxVgprAllocationnumber of available VGPRs + uint32_t vgprAllocationGranularityVGPRs are allocated in groups of this size + + + VkStructureType sType + void* pNextPointer to next structure + VkShaderCorePropertiesFlagsAMD shaderCoreFeaturesfeatures supported by the shader core + uint32_t activeComputeUnitCountnumber of active compute units across all shader engines/arrays + + + VkStructureType sType + const void* pNext + VkPipelineRasterizationConservativeStateCreateFlagsEXT flagsReserved + VkConservativeRasterizationModeEXT conservativeRasterizationModeConservative rasterization mode + float extraPrimitiveOverestimationSizeExtra overestimation to add to the primitive + + + VkStructureType sType + void* pNext + VkBool32 shaderInputAttachmentArrayDynamicIndexing + VkBool32 shaderUniformTexelBufferArrayDynamicIndexing + VkBool32 shaderStorageTexelBufferArrayDynamicIndexing + VkBool32 shaderUniformBufferArrayNonUniformIndexing + VkBool32 shaderSampledImageArrayNonUniformIndexing + VkBool32 shaderStorageBufferArrayNonUniformIndexing + VkBool32 shaderStorageImageArrayNonUniformIndexing + VkBool32 shaderInputAttachmentArrayNonUniformIndexing + VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing + VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing + VkBool32 descriptorBindingUniformBufferUpdateAfterBind + VkBool32 descriptorBindingSampledImageUpdateAfterBind + VkBool32 descriptorBindingStorageImageUpdateAfterBind + VkBool32 descriptorBindingStorageBufferUpdateAfterBind + VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind + VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind + VkBool32 descriptorBindingUpdateUnusedWhilePending + VkBool32 descriptorBindingPartiallyBound + VkBool32 descriptorBindingVariableDescriptorCount + VkBool32 runtimeDescriptorArray + + + + VkStructureType sType + void* pNext + uint32_t maxUpdateAfterBindDescriptorsInAllPools + VkBool32 shaderUniformBufferArrayNonUniformIndexingNative + VkBool32 shaderSampledImageArrayNonUniformIndexingNative + VkBool32 shaderStorageBufferArrayNonUniformIndexingNative + VkBool32 shaderStorageImageArrayNonUniformIndexingNative + VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative + VkBool32 robustBufferAccessUpdateAfterBind + VkBool32 quadDivergentImplicitLod + uint32_t maxPerStageDescriptorUpdateAfterBindSamplers + uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers + uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers + uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages + uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages + uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments + uint32_t maxPerStageUpdateAfterBindResources + uint32_t maxDescriptorSetUpdateAfterBindSamplers + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic + uint32_t maxDescriptorSetUpdateAfterBindSampledImages + uint32_t maxDescriptorSetUpdateAfterBindStorageImages + uint32_t maxDescriptorSetUpdateAfterBindInputAttachments + + + + VkStructureType sType + const void* pNext + uint32_t bindingCount + const VkDescriptorBindingFlags* pBindingFlags + + + + VkStructureType sType + const void* pNext + uint32_t descriptorSetCount + const uint32_t* pDescriptorCounts + + + + VkStructureType sType + void* pNext + uint32_t maxVariableDescriptorCount + + + + VkStructureType sType + const void* pNext + VkAttachmentDescriptionFlags flags + VkFormat format + VkSampleCountFlagBits samples + VkAttachmentLoadOp loadOpLoad operation for color or depth data + VkAttachmentStoreOp storeOpStore operation for color or depth data + VkAttachmentLoadOp stencilLoadOpLoad operation for stencil data + VkAttachmentStoreOp stencilStoreOpStore operation for stencil data + VkImageLayout initialLayout + VkImageLayout finalLayout + + + + VkStructureType sType + const void* pNext + uint32_t attachment + VkImageLayout layout + VkImageAspectFlags aspectMask + + + + VkStructureType sType + const void* pNext + VkSubpassDescriptionFlags flags + VkPipelineBindPoint pipelineBindPoint + uint32_t viewMask + uint32_t inputAttachmentCount + const VkAttachmentReference2* pInputAttachments + uint32_t colorAttachmentCount + const VkAttachmentReference2* pColorAttachments + const VkAttachmentReference2* pResolveAttachments + const VkAttachmentReference2* pDepthStencilAttachment + uint32_t preserveAttachmentCount + const uint32_t* pPreserveAttachments + + + + VkStructureType sType + const void* pNext + uint32_t srcSubpass + uint32_t dstSubpass + VkPipelineStageFlags srcStageMask + VkPipelineStageFlags dstStageMask + VkAccessFlags srcAccessMask + VkAccessFlags dstAccessMask + VkDependencyFlags dependencyFlags + int32_t viewOffset + + + + VkStructureType sType + const void* pNext + VkRenderPassCreateFlags flags + uint32_t attachmentCount + const VkAttachmentDescription2* pAttachments + uint32_t subpassCount + const VkSubpassDescription2* pSubpasses + uint32_t dependencyCount + const VkSubpassDependency2* pDependencies + uint32_t correlatedViewMaskCount + const uint32_t* pCorrelatedViewMasks + + + + VkStructureType sType + const void* pNext + VkSubpassContents contents + + + + VkStructureType sType + const void* pNext + + + + VkStructureType sType + void* pNext + VkBool32 timelineSemaphore + + + + VkStructureType sType + void* pNext + uint64_t maxTimelineSemaphoreValueDifference + + + + VkStructureType sType + const void* pNext + VkSemaphoreType semaphoreType + uint64_t initialValue + + + + VkStructureType sType + const void* pNext + uint32_t waitSemaphoreValueCount + const uint64_t* pWaitSemaphoreValues + uint32_t signalSemaphoreValueCount + const uint64_t* pSignalSemaphoreValues + + + + VkStructureType sType + const void* pNext + VkSemaphoreWaitFlags flags + uint32_t semaphoreCount + const VkSemaphore* pSemaphores + const uint64_t* pValues + + + + VkStructureType sType + const void* pNext + VkSemaphore semaphore + uint64_t value + + + + uint32_t binding + uint32_t divisor + + + VkStructureType sType + const void* pNext + uint32_t vertexBindingDivisorCount + const VkVertexInputBindingDivisorDescriptionEXT* pVertexBindingDivisors + + + VkStructureType sType + void* pNext + uint32_t maxVertexAttribDivisormax value of vertex attribute divisor + + + VkStructureType sType + void* pNext + uint32_t pciDomain + uint32_t pciBus + uint32_t pciDevice + uint32_t pciFunction + + + VkStructureType sType + const void* pNext + struct AHardwareBuffer* buffer + + + VkStructureType sType + void* pNext + uint64_t androidHardwareBufferUsage + + + VkStructureType sType + void* pNext + VkDeviceSize allocationSize + uint32_t memoryTypeBits + + + VkStructureType sType + const void* pNext + VkDeviceMemory memory + + + VkStructureType sType + void* pNext + VkFormat format + uint64_t externalFormat + VkFormatFeatureFlags formatFeatures + VkComponentMapping samplerYcbcrConversionComponents + VkSamplerYcbcrModelConversion suggestedYcbcrModel + VkSamplerYcbcrRange suggestedYcbcrRange + VkChromaLocation suggestedXChromaOffset + VkChromaLocation suggestedYChromaOffset + + + VkStructureType sType + const void* pNext + VkBool32 conditionalRenderingEnableWhether this secondary command buffer may be executed during an active conditional rendering + + + VkStructureType sType + void* pNext + uint64_t externalFormat + + + VkStructureType sType + void* pNext + VkBool32 storageBuffer8BitAccess8-bit integer variables supported in StorageBuffer + VkBool32 uniformAndStorageBuffer8BitAccess8-bit integer variables supported in StorageBuffer and Uniform + VkBool32 storagePushConstant88-bit integer variables supported in PushConstant + + + + VkStructureType sType + void* pNext + VkBool32 conditionalRendering + VkBool32 inheritedConditionalRendering + + + VkStructureType sType + void* pNext + VkBool32 vulkanMemoryModel + VkBool32 vulkanMemoryModelDeviceScope + VkBool32 vulkanMemoryModelAvailabilityVisibilityChains + + + + VkStructureType sType + void* pNext + VkBool32 shaderBufferInt64Atomics + VkBool32 shaderSharedInt64Atomics + + + + VkStructureType sType + void* pNext + VkBool32 shaderBufferFloat32Atomics + VkBool32 shaderBufferFloat32AtomicAdd + VkBool32 shaderBufferFloat64Atomics + VkBool32 shaderBufferFloat64AtomicAdd + VkBool32 shaderSharedFloat32Atomics + VkBool32 shaderSharedFloat32AtomicAdd + VkBool32 shaderSharedFloat64Atomics + VkBool32 shaderSharedFloat64AtomicAdd + VkBool32 shaderImageFloat32Atomics + VkBool32 shaderImageFloat32AtomicAdd + VkBool32 sparseImageFloat32Atomics + VkBool32 sparseImageFloat32AtomicAdd + + + VkStructureType sType + void* pNext + VkBool32 shaderBufferFloat16Atomics + VkBool32 shaderBufferFloat16AtomicAdd + VkBool32 shaderBufferFloat16AtomicMinMax + VkBool32 shaderBufferFloat32AtomicMinMax + VkBool32 shaderBufferFloat64AtomicMinMax + VkBool32 shaderSharedFloat16Atomics + VkBool32 shaderSharedFloat16AtomicAdd + VkBool32 shaderSharedFloat16AtomicMinMax + VkBool32 shaderSharedFloat32AtomicMinMax + VkBool32 shaderSharedFloat64AtomicMinMax + VkBool32 shaderImageFloat32AtomicMinMax + VkBool32 sparseImageFloat32AtomicMinMax + + + VkStructureType sType + void* pNext + VkBool32 vertexAttributeInstanceRateDivisor + VkBool32 vertexAttributeInstanceRateZeroDivisor + + + VkStructureType sType + void* pNext + VkPipelineStageFlags checkpointExecutionStageMask + + + VkStructureType sType + void* pNext + VkPipelineStageFlagBits stage + void* pCheckpointMarker + + + VkStructureType sType + void* pNext + VkResolveModeFlags supportedDepthResolveModessupported depth resolve modes + VkResolveModeFlags supportedStencilResolveModessupported stencil resolve modes + VkBool32 independentResolveNonedepth and stencil resolve modes can be set independently if one of them is none + VkBool32 independentResolvedepth and stencil resolve modes can be set independently + + + + VkStructureType sType + const void* pNext + VkResolveModeFlagBits depthResolveModedepth resolve mode + VkResolveModeFlagBits stencilResolveModestencil resolve mode + const VkAttachmentReference2* pDepthStencilResolveAttachmentdepth/stencil resolve attachment + + + + VkStructureType sType + const void* pNext + VkFormat decodeMode + + + VkStructureType sType + void* pNext + VkBool32 decodeModeSharedExponent + + + VkStructureType sType + void* pNext + VkBool32 transformFeedback + VkBool32 geometryStreams + + + VkStructureType sType + void* pNext + uint32_t maxTransformFeedbackStreams + uint32_t maxTransformFeedbackBuffers + VkDeviceSize maxTransformFeedbackBufferSize + uint32_t maxTransformFeedbackStreamDataSize + uint32_t maxTransformFeedbackBufferDataSize + uint32_t maxTransformFeedbackBufferDataStride + VkBool32 transformFeedbackQueries + VkBool32 transformFeedbackStreamsLinesTriangles + VkBool32 transformFeedbackRasterizationStreamSelect + VkBool32 transformFeedbackDraw + + + VkStructureType sType + const void* pNext + VkPipelineRasterizationStateStreamCreateFlagsEXT flags + uint32_t rasterizationStream + + + VkStructureType sType + void* pNext + VkBool32 representativeFragmentTest + + + VkStructureType sType + const void* pNext + VkBool32 representativeFragmentTestEnable + + + VkStructureType sType + void* pNext + VkBool32 exclusiveScissor + + + VkStructureType sType + const void* pNext + uint32_t exclusiveScissorCount + const VkRect2D* pExclusiveScissors + + + VkStructureType sType + void* pNext + VkBool32 cornerSampledImage + + + VkStructureType sType + void* pNext + VkBool32 computeDerivativeGroupQuads + VkBool32 computeDerivativeGroupLinear + + + + VkStructureType sType + void* pNext + VkBool32 imageFootprint + + + VkStructureType sType + void* pNext + VkBool32 dedicatedAllocationImageAliasing + + + VkStructureType sType + void* pNext + VkBool32 indirectCopy + + + VkStructureType sType + void* pNext + VkQueueFlags supportedQueuesBitfield of which queues are supported for indirect copy + + + VkStructureType sType + void* pNext + VkBool32 memoryDecompression + + + VkStructureType sType + void* pNext + VkMemoryDecompressionMethodFlagsNV decompressionMethods + uint64_t maxDecompressionIndirectCount + + + uint32_t shadingRatePaletteEntryCount + const VkShadingRatePaletteEntryNV* pShadingRatePaletteEntries + + + VkStructureType sType + const void* pNext + VkBool32 shadingRateImageEnable + uint32_t viewportCount + const VkShadingRatePaletteNV* pShadingRatePalettes + + + VkStructureType sType + void* pNext + VkBool32 shadingRateImage + VkBool32 shadingRateCoarseSampleOrder + + + VkStructureType sType + void* pNext + VkExtent2D shadingRateTexelSize + uint32_t shadingRatePaletteSize + uint32_t shadingRateMaxCoarseSamples + + + VkStructureType sType + void* pNext + VkBool32 invocationMask + + + uint32_t pixelX + uint32_t pixelY + uint32_t sample + + + VkShadingRatePaletteEntryNV shadingRate + uint32_t sampleCount + uint32_t sampleLocationCount + const VkCoarseSampleLocationNV* pSampleLocations + + + VkStructureType sType + const void* pNext + VkCoarseSampleOrderTypeNV sampleOrderType + uint32_t customSampleOrderCount + const VkCoarseSampleOrderCustomNV* pCustomSampleOrders + + + VkStructureType sType + void* pNext + VkBool32 taskShader + VkBool32 meshShader + + + VkStructureType sType + void* pNext + uint32_t maxDrawMeshTasksCount + uint32_t maxTaskWorkGroupInvocations + uint32_t maxTaskWorkGroupSize[3] + uint32_t maxTaskTotalMemorySize + uint32_t maxTaskOutputCount + uint32_t maxMeshWorkGroupInvocations + uint32_t maxMeshWorkGroupSize[3] + uint32_t maxMeshTotalMemorySize + uint32_t maxMeshOutputVertices + uint32_t maxMeshOutputPrimitives + uint32_t maxMeshMultiviewViewCount + uint32_t meshOutputPerVertexGranularity + uint32_t meshOutputPerPrimitiveGranularity + + + uint32_t taskCount + uint32_t firstTask + + + VkStructureType sType + void* pNext + VkBool32 taskShader + VkBool32 meshShader + VkBool32 multiviewMeshShader + VkBool32 primitiveFragmentShadingRateMeshShader + VkBool32 meshShaderQueries + + + VkStructureType sType + void* pNext + uint32_t maxTaskWorkGroupTotalCount + uint32_t maxTaskWorkGroupCount[3] + uint32_t maxTaskWorkGroupInvocations + uint32_t maxTaskWorkGroupSize[3] + uint32_t maxTaskPayloadSize + uint32_t maxTaskSharedMemorySize + uint32_t maxTaskPayloadAndSharedMemorySize + uint32_t maxMeshWorkGroupTotalCount + uint32_t maxMeshWorkGroupCount[3] + uint32_t maxMeshWorkGroupInvocations + uint32_t maxMeshWorkGroupSize[3] + uint32_t maxMeshSharedMemorySize + uint32_t maxMeshPayloadAndSharedMemorySize + uint32_t maxMeshOutputMemorySize + uint32_t maxMeshPayloadAndOutputMemorySize + uint32_t maxMeshOutputComponents + uint32_t maxMeshOutputVertices + uint32_t maxMeshOutputPrimitives + uint32_t maxMeshOutputLayers + uint32_t maxMeshMultiviewViewCount + uint32_t meshOutputPerVertexGranularity + uint32_t meshOutputPerPrimitiveGranularity + uint32_t maxPreferredTaskWorkGroupInvocations + uint32_t maxPreferredMeshWorkGroupInvocations + VkBool32 prefersLocalInvocationVertexOutput + VkBool32 prefersLocalInvocationPrimitiveOutput + VkBool32 prefersCompactVertexOutput + VkBool32 prefersCompactPrimitiveOutput + + + uint32_t groupCountX + uint32_t groupCountY + uint32_t groupCountZ + + + VkStructureType sType + const void* pNext + VkRayTracingShaderGroupTypeKHR type + uint32_t generalShader + uint32_t closestHitShader + uint32_t anyHitShader + uint32_t intersectionShader + + + VkStructureType sType + const void* pNext + VkRayTracingShaderGroupTypeKHR type + uint32_t generalShader + uint32_t closestHitShader + uint32_t anyHitShader + uint32_t intersectionShader + const void* pShaderGroupCaptureReplayHandle + + + VkStructureType sType + const void* pNext + VkPipelineCreateFlags flagsPipeline creation flags + uint32_t stageCount + const VkPipelineShaderStageCreateInfo* pStagesOne entry for each active shader stage + uint32_t groupCount + const VkRayTracingShaderGroupCreateInfoNV* pGroups + uint32_t maxRecursionDepth + VkPipelineLayout layoutInterface layout of the pipeline + VkPipeline basePipelineHandleIf VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is nonzero, it specifies the handle of the base pipeline this is a derivative of + int32_t basePipelineIndexIf VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is not -1, it specifies an index into pCreateInfos of the base pipeline this is a derivative of + + + VkStructureType sType + const void* pNext + VkPipelineCreateFlags flagsPipeline creation flags + uint32_t stageCount + const VkPipelineShaderStageCreateInfo* pStagesOne entry for each active shader stage + uint32_t groupCount + const VkRayTracingShaderGroupCreateInfoKHR* pGroups + uint32_t maxPipelineRayRecursionDepth + const VkPipelineLibraryCreateInfoKHR* pLibraryInfo + const VkRayTracingPipelineInterfaceCreateInfoKHR* pLibraryInterface + const VkPipelineDynamicStateCreateInfo* pDynamicState + VkPipelineLayout layoutInterface layout of the pipeline + VkPipeline basePipelineHandleIf VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is nonzero, it specifies the handle of the base pipeline this is a derivative of + int32_t basePipelineIndexIf VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is not -1, it specifies an index into pCreateInfos of the base pipeline this is a derivative of + + + VkStructureType sType + const void* pNext + VkBuffer vertexData + VkDeviceSize vertexOffset + uint32_t vertexCount + VkDeviceSize vertexStride + VkFormat vertexFormat + VkBuffer indexData + VkDeviceSize indexOffset + uint32_t indexCount + VkIndexType indexType + VkBuffer transformDataOptional reference to array of floats representing a 3x4 row major affine transformation matrix. + VkDeviceSize transformOffset + + + VkStructureType sType + const void* pNext + VkBuffer aabbData + uint32_t numAABBs + uint32_t strideStride in bytes between AABBs + VkDeviceSize offsetOffset in bytes of the first AABB in aabbData + + + VkGeometryTrianglesNV triangles + VkGeometryAABBNV aabbs + + + VkStructureType sType + const void* pNext + VkGeometryTypeKHR geometryType + VkGeometryDataNV geometry + VkGeometryFlagsKHR flags + + + VkStructureType sType + const void* pNext + VkAccelerationStructureTypeNV type + VkBuildAccelerationStructureFlagsNV flags + uint32_t instanceCount + uint32_t geometryCount + const VkGeometryNV* pGeometries + + + VkStructureType sType + const void* pNext + VkDeviceSize compactedSize + VkAccelerationStructureInfoNV info + + + VkStructureType sType + const void* pNext + VkAccelerationStructureNV accelerationStructure + VkDeviceMemory memory + VkDeviceSize memoryOffset + uint32_t deviceIndexCount + const uint32_t* pDeviceIndices + + + VkStructureType sType + const void* pNext + uint32_t accelerationStructureCount + const VkAccelerationStructureKHR* pAccelerationStructures + + + VkStructureType sType + const void* pNext + uint32_t accelerationStructureCount + const VkAccelerationStructureNV* pAccelerationStructures + + + VkStructureType sType + const void* pNext + VkAccelerationStructureMemoryRequirementsTypeNV type + VkAccelerationStructureNV accelerationStructure + + + VkStructureType sType + void* pNext + VkBool32 accelerationStructure + VkBool32 accelerationStructureCaptureReplay + VkBool32 accelerationStructureIndirectBuild + VkBool32 accelerationStructureHostCommands + VkBool32 descriptorBindingAccelerationStructureUpdateAfterBind + + + VkStructureType sType + void* pNext + VkBool32 rayTracingPipeline + VkBool32 rayTracingPipelineShaderGroupHandleCaptureReplay + VkBool32 rayTracingPipelineShaderGroupHandleCaptureReplayMixed + VkBool32 rayTracingPipelineTraceRaysIndirect + VkBool32 rayTraversalPrimitiveCulling + + + VkStructureType sType + void* pNext + VkBool32 rayQuery + + + VkStructureType sType + void* pNext + uint64_t maxGeometryCount + uint64_t maxInstanceCount + uint64_t maxPrimitiveCount + uint32_t maxPerStageDescriptorAccelerationStructures + uint32_t maxPerStageDescriptorUpdateAfterBindAccelerationStructures + uint32_t maxDescriptorSetAccelerationStructures + uint32_t maxDescriptorSetUpdateAfterBindAccelerationStructures + uint32_t minAccelerationStructureScratchOffsetAlignment + + + VkStructureType sType + void* pNext + uint32_t shaderGroupHandleSize + uint32_t maxRayRecursionDepth + uint32_t maxShaderGroupStride + uint32_t shaderGroupBaseAlignment + uint32_t shaderGroupHandleCaptureReplaySize + uint32_t maxRayDispatchInvocationCount + uint32_t shaderGroupHandleAlignment + uint32_t maxRayHitAttributeSize + + + VkStructureType sType + void* pNext + uint32_t shaderGroupHandleSize + uint32_t maxRecursionDepth + uint32_t maxShaderGroupStride + uint32_t shaderGroupBaseAlignment + uint64_t maxGeometryCount + uint64_t maxInstanceCount + uint64_t maxTriangleCount + uint32_t maxDescriptorSetAccelerationStructures + + + VkDeviceAddress deviceAddress + VkDeviceSize stride + VkDeviceSize size + + + uint32_t width + uint32_t height + uint32_t depth + + + VkDeviceAddress raygenShaderRecordAddress + VkDeviceSize raygenShaderRecordSize + VkDeviceAddress missShaderBindingTableAddress + VkDeviceSize missShaderBindingTableSize + VkDeviceSize missShaderBindingTableStride + VkDeviceAddress hitShaderBindingTableAddress + VkDeviceSize hitShaderBindingTableSize + VkDeviceSize hitShaderBindingTableStride + VkDeviceAddress callableShaderBindingTableAddress + VkDeviceSize callableShaderBindingTableSize + VkDeviceSize callableShaderBindingTableStride + uint32_t width + uint32_t height + uint32_t depth + + + VkStructureType sType + void* pNext + VkBool32 rayTracingMaintenance1 + VkBool32 rayTracingPipelineTraceRaysIndirect2 + + + VkStructureType sType + void* pNext + uint32_t drmFormatModifierCount + VkDrmFormatModifierPropertiesEXT* pDrmFormatModifierProperties + + + uint64_t drmFormatModifier + uint32_t drmFormatModifierPlaneCount + VkFormatFeatureFlags drmFormatModifierTilingFeatures + + + VkStructureType sType + const void* pNext + uint64_t drmFormatModifier + VkSharingMode sharingMode + uint32_t queueFamilyIndexCount + const uint32_t* pQueueFamilyIndices + + + VkStructureType sType + const void* pNext + uint32_t drmFormatModifierCount + const uint64_t* pDrmFormatModifiers + + + VkStructureType sType + const void* pNext + uint64_t drmFormatModifier + uint32_t drmFormatModifierPlaneCount + const VkSubresourceLayout* pPlaneLayouts + + + VkStructureType sType + void* pNext + uint64_t drmFormatModifier + + + VkStructureType sType + const void* pNext + VkImageUsageFlags stencilUsage + + + + VkStructureType sType + const void* pNext + VkMemoryOverallocationBehaviorAMD overallocationBehavior + + + VkStructureType sType + void* pNext + VkBool32 fragmentDensityMap + VkBool32 fragmentDensityMapDynamic + VkBool32 fragmentDensityMapNonSubsampledImages + + + VkStructureType sType + void* pNext + VkBool32 fragmentDensityMapDeferred + + + VkStructureType sType + void* pNext + VkBool32 fragmentDensityMapOffset + + + VkStructureType sType + void* pNext + VkExtent2D minFragmentDensityTexelSize + VkExtent2D maxFragmentDensityTexelSize + VkBool32 fragmentDensityInvocations + + + VkStructureType sType + void* pNext + VkBool32 subsampledLoads + VkBool32 subsampledCoarseReconstructionEarlyAccess + uint32_t maxSubsampledArrayLayers + uint32_t maxDescriptorSetSubsampledSamplers + + + VkStructureType sType + void* pNext + VkExtent2D fragmentDensityOffsetGranularity + + + VkStructureType sType + const void* pNext + VkAttachmentReference fragmentDensityMapAttachment + + + VkStructureType sType + const void* pNext + uint32_t fragmentDensityOffsetCount + const VkOffset2D* pFragmentDensityOffsets + + + VkStructureType sType + void* pNext + VkBool32 scalarBlockLayout + + + + VkStructureType sType + const void* pNext + VkBool32 supportsProtectedRepresents if surface can be protected + + + VkStructureType sType + void* pNext + VkBool32 uniformBufferStandardLayout + + + + VkStructureType sType + void* pNext + VkBool32 depthClipEnable + + + VkStructureType sType + const void* pNext + VkPipelineRasterizationDepthClipStateCreateFlagsEXT flagsReserved + VkBool32 depthClipEnable + + + VkStructureType sType + void* pNext + VkDeviceSize heapBudget[VK_MAX_MEMORY_HEAPS] + VkDeviceSize heapUsage[VK_MAX_MEMORY_HEAPS] + + + VkStructureType sType + void* pNext + VkBool32 memoryPriority + + + VkStructureType sType + const void* pNext + float priority + + + VkStructureType sType + void* pNext + VkBool32 pageableDeviceLocalMemory + + + VkStructureType sType + void* pNext + VkBool32 bufferDeviceAddress + VkBool32 bufferDeviceAddressCaptureReplay + VkBool32 bufferDeviceAddressMultiDevice + + + + VkStructureType sType + void* pNext + VkBool32 bufferDeviceAddress + VkBool32 bufferDeviceAddressCaptureReplay + VkBool32 bufferDeviceAddressMultiDevice + + + + VkStructureType sType + const void* pNext + VkBuffer buffer + + + + + VkStructureType sType + const void* pNext + uint64_t opaqueCaptureAddress + + + + VkStructureType sType + const void* pNext + VkDeviceAddress deviceAddress + + + VkStructureType sType + void* pNext + VkImageViewType imageViewType + + + VkStructureType sType + void* pNext + VkBool32 filterCubicThe combinations of format, image type (and image view type if provided) can be filtered with VK_FILTER_CUBIC_EXT + VkBool32 filterCubicMinmaxThe combination of format, image type (and image view type if provided) can be filtered with VK_FILTER_CUBIC_EXT and ReductionMode of Min or Max + + + VkStructureType sType + void* pNext + VkBool32 imagelessFramebuffer + + + + VkStructureType sType + const void* pNext + uint32_t attachmentImageInfoCount + const VkFramebufferAttachmentImageInfo* pAttachmentImageInfos + + + + VkStructureType sType + const void* pNext + VkImageCreateFlags flagsImage creation flags + VkImageUsageFlags usageImage usage flags + uint32_t width + uint32_t height + uint32_t layerCount + uint32_t viewFormatCount + const VkFormat* pViewFormats + + + + VkStructureType sType + const void* pNext + uint32_t attachmentCount + const VkImageView* pAttachments + + + + VkStructureType sType + void* pNext + VkBool32 textureCompressionASTC_HDR + + + + VkStructureType sType + void* pNext + VkBool32 cooperativeMatrix + VkBool32 cooperativeMatrixRobustBufferAccess + + + VkStructureType sType + void* pNext + VkShaderStageFlags cooperativeMatrixSupportedStages + + + VkStructureType sType + void* pNext + uint32_t MSize + uint32_t NSize + uint32_t KSize + VkComponentTypeNV AType + VkComponentTypeNV BType + VkComponentTypeNV CType + VkComponentTypeNV DType + VkScopeNV scope + + + VkStructureType sType + void* pNext + VkBool32 ycbcrImageArrays + + + VkStructureType sType + const void* pNext + VkImageView imageView + VkDescriptorType descriptorType + VkSampler sampler + + + VkStructureType sType + void* pNext + VkDeviceAddress deviceAddress + VkDeviceSize size + + + VkStructureType sType + const void* pNext + GgpFrameToken frameToken + + + VkPipelineCreationFeedbackFlags flags + uint64_t duration + + + + VkStructureType sType + const void* pNext + VkPipelineCreationFeedback* pPipelineCreationFeedbackOutput pipeline creation feedback. + uint32_t pipelineStageCreationFeedbackCount + VkPipelineCreationFeedback* pPipelineStageCreationFeedbacksOne entry for each shader stage specified in the parent Vk*PipelineCreateInfo struct + + + + VkStructureType sType + void* pNext + VkFullScreenExclusiveEXT fullScreenExclusive + + + VkStructureType sType + const void* pNext + HMONITOR hmonitor + + + VkStructureType sType + void* pNext + VkBool32 fullScreenExclusiveSupported + + + VkStructureType sType + void* pNext + VkBool32 presentBarrier + + + VkStructureType sType + void* pNext + VkBool32 presentBarrierSupported + + + VkStructureType sType + void* pNext + VkBool32 presentBarrierEnable + + + VkStructureType sType + void* pNext + VkBool32 performanceCounterQueryPoolsperformance counters supported in query pools + VkBool32 performanceCounterMultipleQueryPoolsperformance counters from multiple query pools can be accessed in the same primary command buffer + + + VkStructureType sType + void* pNext + VkBool32 allowCommandBufferQueryCopiesFlag to specify whether performance queries are allowed to be used in vkCmdCopyQueryPoolResults + + + VkStructureType sType + void* pNext + VkPerformanceCounterUnitKHR unit + VkPerformanceCounterScopeKHR scope + VkPerformanceCounterStorageKHR storage + uint8_t uuid[VK_UUID_SIZE] + + + VkStructureType sType + void* pNext + VkPerformanceCounterDescriptionFlagsKHR flags + char name[VK_MAX_DESCRIPTION_SIZE] + char category[VK_MAX_DESCRIPTION_SIZE] + char description[VK_MAX_DESCRIPTION_SIZE] + + + VkStructureType sType + const void* pNext + uint32_t queueFamilyIndex + uint32_t counterIndexCount + const uint32_t* pCounterIndices + + + int32_t int32 + int64_t int64 + uint32_t uint32 + uint64_t uint64 + float float32 + double float64 + + + VkStructureType sType + const void* pNext + VkAcquireProfilingLockFlagsKHR flagsAcquire profiling lock flags + uint64_t timeout + + + VkStructureType sType + const void* pNext + uint32_t counterPassIndexIndex for which counter pass to submit + + + VkStructureType sType + const void* pNext + VkHeadlessSurfaceCreateFlagsEXT flags + + + VkStructureType sType + void* pNext + VkBool32 coverageReductionMode + + + VkStructureType sType + const void* pNext + VkPipelineCoverageReductionStateCreateFlagsNV flags + VkCoverageReductionModeNV coverageReductionMode + + + VkStructureType sType + void* pNext + VkCoverageReductionModeNV coverageReductionMode + VkSampleCountFlagBits rasterizationSamples + VkSampleCountFlags depthStencilSamples + VkSampleCountFlags colorSamples + + + VkStructureType sType + void* pNext + VkBool32 shaderIntegerFunctions2 + + + uint32_t value32 + uint64_t value64 + float valueFloat + VkBool32 valueBool + const char* valueString + + + VkPerformanceValueTypeINTEL type + VkPerformanceValueDataINTEL data + + + VkStructureType sType + const void* pNext + void* pUserData + + + VkStructureType sType + const void* pNext + VkQueryPoolSamplingModeINTEL performanceCountersSampling + + + + VkStructureType sType + const void* pNext + uint64_t marker + + + VkStructureType sType + const void* pNext + uint32_t marker + + + VkStructureType sType + const void* pNext + VkPerformanceOverrideTypeINTEL type + VkBool32 enable + uint64_t parameter + + + VkStructureType sType + const void* pNext + VkPerformanceConfigurationTypeINTEL type + + + VkStructureType sType + void* pNext + VkBool32 shaderSubgroupClock + VkBool32 shaderDeviceClock + + + VkStructureType sType + void* pNext + VkBool32 indexTypeUint8 + + + VkStructureType sType + void* pNext + uint32_t shaderSMCount + uint32_t shaderWarpsPerSM + + + VkStructureType sType + void* pNext + VkBool32 shaderSMBuiltins + + + VkStructureType sType + void* pNextPointer to next structure + VkBool32 fragmentShaderSampleInterlock + VkBool32 fragmentShaderPixelInterlock + VkBool32 fragmentShaderShadingRateInterlock + + + VkStructureType sType + void* pNext + VkBool32 separateDepthStencilLayouts + + + + VkStructureType sType + void* pNext + VkImageLayout stencilLayout + + + VkStructureType sType + void* pNext + VkBool32 primitiveTopologyListRestart + VkBool32 primitiveTopologyPatchListRestart + + + + VkStructureType sType + void* pNext + VkImageLayout stencilInitialLayout + VkImageLayout stencilFinalLayout + + + + VkStructureType sType + void* pNext + VkBool32 pipelineExecutableInfo + + + VkStructureType sType + const void* pNext + VkPipeline pipeline + + + + VkStructureType sType + void* pNext + VkShaderStageFlags stages + char name[VK_MAX_DESCRIPTION_SIZE] + char description[VK_MAX_DESCRIPTION_SIZE] + uint32_t subgroupSize + + + VkStructureType sType + const void* pNext + VkPipeline pipeline + uint32_t executableIndex + + + VkBool32 b32 + int64_t i64 + uint64_t u64 + double f64 + + + VkStructureType sType + void* pNext + char name[VK_MAX_DESCRIPTION_SIZE] + char description[VK_MAX_DESCRIPTION_SIZE] + VkPipelineExecutableStatisticFormatKHR format + VkPipelineExecutableStatisticValueKHR value + + + VkStructureType sType + void* pNext + char name[VK_MAX_DESCRIPTION_SIZE] + char description[VK_MAX_DESCRIPTION_SIZE] + VkBool32 isText + size_t dataSize + void* pData + + + VkStructureType sType + void* pNext + VkBool32 shaderDemoteToHelperInvocation + + + + VkStructureType sType + void* pNext + VkBool32 texelBufferAlignment + + + VkStructureType sType + void* pNext + VkDeviceSize storageTexelBufferOffsetAlignmentBytes + VkBool32 storageTexelBufferOffsetSingleTexelAlignment + VkDeviceSize uniformTexelBufferOffsetAlignmentBytes + VkBool32 uniformTexelBufferOffsetSingleTexelAlignment + + + + VkStructureType sType + void* pNext + VkBool32 subgroupSizeControl + VkBool32 computeFullSubgroups + + + + VkStructureType sType + void* pNext + uint32_t minSubgroupSizeThe minimum subgroup size supported by this device + uint32_t maxSubgroupSizeThe maximum subgroup size supported by this device + uint32_t maxComputeWorkgroupSubgroupsThe maximum number of subgroups supported in a workgroup + VkShaderStageFlags requiredSubgroupSizeStagesThe shader stages that support specifying a subgroup size + + + + VkStructureType sType + void* pNext + uint32_t requiredSubgroupSize + + + + VkStructureType sType + void* pNext + VkRenderPass renderPass + uint32_t subpass + + + VkStructureType sType + void* pNext + uint32_t maxSubpassShadingWorkgroupSizeAspectRatio + + + VkStructureType sType + const void* pNext + uint64_t opaqueCaptureAddress + + + + VkStructureType sType + const void* pNext + VkDeviceMemory memory + + + + VkStructureType sType + void* pNext + VkBool32 rectangularLines + VkBool32 bresenhamLines + VkBool32 smoothLines + VkBool32 stippledRectangularLines + VkBool32 stippledBresenhamLines + VkBool32 stippledSmoothLines + + + VkStructureType sType + void* pNext + uint32_t lineSubPixelPrecisionBits + + + VkStructureType sType + const void* pNext + VkLineRasterizationModeEXT lineRasterizationMode + VkBool32 stippledLineEnable + uint32_t lineStippleFactor + uint16_t lineStipplePattern + + + VkStructureType sType + void* pNext + VkBool32 pipelineCreationCacheControl + + + + VkStructureType sType + void* pNext + VkBool32 storageBuffer16BitAccess16-bit integer/floating-point variables supported in BufferBlock + VkBool32 uniformAndStorageBuffer16BitAccess16-bit integer/floating-point variables supported in BufferBlock and Block + VkBool32 storagePushConstant1616-bit integer/floating-point variables supported in PushConstant + VkBool32 storageInputOutput1616-bit integer/floating-point variables supported in shader inputs and outputs + VkBool32 multiviewMultiple views in a renderpass + VkBool32 multiviewGeometryShaderMultiple views in a renderpass w/ geometry shader + VkBool32 multiviewTessellationShaderMultiple views in a renderpass w/ tessellation shader + VkBool32 variablePointersStorageBuffer + VkBool32 variablePointers + VkBool32 protectedMemory + VkBool32 samplerYcbcrConversionSampler color conversion supported + VkBool32 shaderDrawParameters + + + VkStructureType sType + void* pNext + uint8_t deviceUUID[VK_UUID_SIZE] + uint8_t driverUUID[VK_UUID_SIZE] + uint8_t deviceLUID[VK_LUID_SIZE] + uint32_t deviceNodeMask + VkBool32 deviceLUIDValid + uint32_t subgroupSizeThe size of a subgroup for this queue. + VkShaderStageFlags subgroupSupportedStagesBitfield of what shader stages support subgroup operations + VkSubgroupFeatureFlags subgroupSupportedOperationsBitfield of what subgroup operations are supported. + VkBool32 subgroupQuadOperationsInAllStagesFlag to specify whether quad operations are available in all stages. + VkPointClippingBehavior pointClippingBehavior + uint32_t maxMultiviewViewCountmax number of views in a subpass + uint32_t maxMultiviewInstanceIndexmax instance index for a draw in a multiview subpass + VkBool32 protectedNoFault + uint32_t maxPerSetDescriptors + VkDeviceSize maxMemoryAllocationSize + + + VkStructureType sType + void* pNext + VkBool32 samplerMirrorClampToEdge + VkBool32 drawIndirectCount + VkBool32 storageBuffer8BitAccess8-bit integer variables supported in StorageBuffer + VkBool32 uniformAndStorageBuffer8BitAccess8-bit integer variables supported in StorageBuffer and Uniform + VkBool32 storagePushConstant88-bit integer variables supported in PushConstant + VkBool32 shaderBufferInt64Atomics + VkBool32 shaderSharedInt64Atomics + VkBool32 shaderFloat1616-bit floats (halfs) in shaders + VkBool32 shaderInt88-bit integers in shaders + VkBool32 descriptorIndexing + VkBool32 shaderInputAttachmentArrayDynamicIndexing + VkBool32 shaderUniformTexelBufferArrayDynamicIndexing + VkBool32 shaderStorageTexelBufferArrayDynamicIndexing + VkBool32 shaderUniformBufferArrayNonUniformIndexing + VkBool32 shaderSampledImageArrayNonUniformIndexing + VkBool32 shaderStorageBufferArrayNonUniformIndexing + VkBool32 shaderStorageImageArrayNonUniformIndexing + VkBool32 shaderInputAttachmentArrayNonUniformIndexing + VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing + VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing + VkBool32 descriptorBindingUniformBufferUpdateAfterBind + VkBool32 descriptorBindingSampledImageUpdateAfterBind + VkBool32 descriptorBindingStorageImageUpdateAfterBind + VkBool32 descriptorBindingStorageBufferUpdateAfterBind + VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind + VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind + VkBool32 descriptorBindingUpdateUnusedWhilePending + VkBool32 descriptorBindingPartiallyBound + VkBool32 descriptorBindingVariableDescriptorCount + VkBool32 runtimeDescriptorArray + VkBool32 samplerFilterMinmax + VkBool32 scalarBlockLayout + VkBool32 imagelessFramebuffer + VkBool32 uniformBufferStandardLayout + VkBool32 shaderSubgroupExtendedTypes + VkBool32 separateDepthStencilLayouts + VkBool32 hostQueryReset + VkBool32 timelineSemaphore + VkBool32 bufferDeviceAddress + VkBool32 bufferDeviceAddressCaptureReplay + VkBool32 bufferDeviceAddressMultiDevice + VkBool32 vulkanMemoryModel + VkBool32 vulkanMemoryModelDeviceScope + VkBool32 vulkanMemoryModelAvailabilityVisibilityChains + VkBool32 shaderOutputViewportIndex + VkBool32 shaderOutputLayer + VkBool32 subgroupBroadcastDynamicId + + + VkStructureType sType + void* pNext + VkDriverId driverID + char driverName[VK_MAX_DRIVER_NAME_SIZE] + char driverInfo[VK_MAX_DRIVER_INFO_SIZE] + VkConformanceVersion conformanceVersion + VkShaderFloatControlsIndependence denormBehaviorIndependence + VkShaderFloatControlsIndependence roundingModeIndependence + VkBool32 shaderSignedZeroInfNanPreserveFloat16An implementation can preserve signed zero, nan, inf + VkBool32 shaderSignedZeroInfNanPreserveFloat32An implementation can preserve signed zero, nan, inf + VkBool32 shaderSignedZeroInfNanPreserveFloat64An implementation can preserve signed zero, nan, inf + VkBool32 shaderDenormPreserveFloat16An implementation can preserve denormals + VkBool32 shaderDenormPreserveFloat32An implementation can preserve denormals + VkBool32 shaderDenormPreserveFloat64An implementation can preserve denormals + VkBool32 shaderDenormFlushToZeroFloat16An implementation can flush to zero denormals + VkBool32 shaderDenormFlushToZeroFloat32An implementation can flush to zero denormals + VkBool32 shaderDenormFlushToZeroFloat64An implementation can flush to zero denormals + VkBool32 shaderRoundingModeRTEFloat16An implementation can support RTE + VkBool32 shaderRoundingModeRTEFloat32An implementation can support RTE + VkBool32 shaderRoundingModeRTEFloat64An implementation can support RTE + VkBool32 shaderRoundingModeRTZFloat16An implementation can support RTZ + VkBool32 shaderRoundingModeRTZFloat32An implementation can support RTZ + VkBool32 shaderRoundingModeRTZFloat64An implementation can support RTZ + uint32_t maxUpdateAfterBindDescriptorsInAllPools + VkBool32 shaderUniformBufferArrayNonUniformIndexingNative + VkBool32 shaderSampledImageArrayNonUniformIndexingNative + VkBool32 shaderStorageBufferArrayNonUniformIndexingNative + VkBool32 shaderStorageImageArrayNonUniformIndexingNative + VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative + VkBool32 robustBufferAccessUpdateAfterBind + VkBool32 quadDivergentImplicitLod + uint32_t maxPerStageDescriptorUpdateAfterBindSamplers + uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers + uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers + uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages + uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages + uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments + uint32_t maxPerStageUpdateAfterBindResources + uint32_t maxDescriptorSetUpdateAfterBindSamplers + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers + uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers + uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic + uint32_t maxDescriptorSetUpdateAfterBindSampledImages + uint32_t maxDescriptorSetUpdateAfterBindStorageImages + uint32_t maxDescriptorSetUpdateAfterBindInputAttachments + VkResolveModeFlags supportedDepthResolveModessupported depth resolve modes + VkResolveModeFlags supportedStencilResolveModessupported stencil resolve modes + VkBool32 independentResolveNonedepth and stencil resolve modes can be set independently if one of them is none + VkBool32 independentResolvedepth and stencil resolve modes can be set independently + VkBool32 filterMinmaxSingleComponentFormats + VkBool32 filterMinmaxImageComponentMapping + uint64_t maxTimelineSemaphoreValueDifference + VkSampleCountFlags framebufferIntegerColorSampleCounts + + + VkStructureType sType + void* pNext + VkBool32 robustImageAccess + VkBool32 inlineUniformBlock + VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind + VkBool32 pipelineCreationCacheControl + VkBool32 privateData + VkBool32 shaderDemoteToHelperInvocation + VkBool32 shaderTerminateInvocation + VkBool32 subgroupSizeControl + VkBool32 computeFullSubgroups + VkBool32 synchronization2 + VkBool32 textureCompressionASTC_HDR + VkBool32 shaderZeroInitializeWorkgroupMemory + VkBool32 dynamicRendering + VkBool32 shaderIntegerDotProduct + VkBool32 maintenance4 + + + VkStructureType sType + void* pNext + uint32_t minSubgroupSizeThe minimum subgroup size supported by this device + uint32_t maxSubgroupSizeThe maximum subgroup size supported by this device + uint32_t maxComputeWorkgroupSubgroupsThe maximum number of subgroups supported in a workgroup + VkShaderStageFlags requiredSubgroupSizeStagesThe shader stages that support specifying a subgroup size + uint32_t maxInlineUniformBlockSize + uint32_t maxPerStageDescriptorInlineUniformBlocks + uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks + uint32_t maxDescriptorSetInlineUniformBlocks + uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks + uint32_t maxInlineUniformTotalSize + VkBool32 integerDotProduct8BitUnsignedAccelerated + VkBool32 integerDotProduct8BitSignedAccelerated + VkBool32 integerDotProduct8BitMixedSignednessAccelerated + VkBool32 integerDotProduct4x8BitPackedUnsignedAccelerated + VkBool32 integerDotProduct4x8BitPackedSignedAccelerated + VkBool32 integerDotProduct4x8BitPackedMixedSignednessAccelerated + VkBool32 integerDotProduct16BitUnsignedAccelerated + VkBool32 integerDotProduct16BitSignedAccelerated + VkBool32 integerDotProduct16BitMixedSignednessAccelerated + VkBool32 integerDotProduct32BitUnsignedAccelerated + VkBool32 integerDotProduct32BitSignedAccelerated + VkBool32 integerDotProduct32BitMixedSignednessAccelerated + VkBool32 integerDotProduct64BitUnsignedAccelerated + VkBool32 integerDotProduct64BitSignedAccelerated + VkBool32 integerDotProduct64BitMixedSignednessAccelerated + VkBool32 integerDotProductAccumulatingSaturating8BitUnsignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating8BitSignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated + VkBool32 integerDotProductAccumulatingSaturating16BitUnsignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating16BitSignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated + VkBool32 integerDotProductAccumulatingSaturating32BitUnsignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating32BitSignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated + VkBool32 integerDotProductAccumulatingSaturating64BitUnsignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating64BitSignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated + VkDeviceSize storageTexelBufferOffsetAlignmentBytes + VkBool32 storageTexelBufferOffsetSingleTexelAlignment + VkDeviceSize uniformTexelBufferOffsetAlignmentBytes + VkBool32 uniformTexelBufferOffsetSingleTexelAlignment + VkDeviceSize maxBufferSize + + + VkStructureType sType + const void* pNext + VkPipelineCompilerControlFlagsAMD compilerControlFlags + + + VkStructureType sType + void* pNext + VkBool32 deviceCoherentMemory + + + VkStructureType sType + void* pNext + char name[VK_MAX_EXTENSION_NAME_SIZE] + char version[VK_MAX_EXTENSION_NAME_SIZE] + VkToolPurposeFlags purposes + char description[VK_MAX_DESCRIPTION_SIZE] + char layer[VK_MAX_EXTENSION_NAME_SIZE] + + + + VkStructureType sType + const void* pNext + VkClearColorValue customBorderColor + VkFormat format + + + VkStructureType sType + void* pNext + uint32_t maxCustomBorderColorSamplers + + + VkStructureType sType + void* pNext + VkBool32 customBorderColors + VkBool32 customBorderColorWithoutFormat + + + VkStructureType sType + const void* pNext + VkComponentMapping components + VkBool32 srgb + + + VkStructureType sType + void* pNext + VkBool32 borderColorSwizzle + VkBool32 borderColorSwizzleFromImage + + + VkDeviceAddress deviceAddress + void* hostAddress + + + VkDeviceAddress deviceAddress + const void* hostAddress + + + VkStructureType sType + const void* pNext + VkFormat vertexFormat + VkDeviceOrHostAddressConstKHR vertexData + VkDeviceSize vertexStride + uint32_t maxVertex + VkIndexType indexType + VkDeviceOrHostAddressConstKHR indexData + VkDeviceOrHostAddressConstKHR transformData + + + VkStructureType sType + const void* pNext + VkDeviceOrHostAddressConstKHR data + VkDeviceSize stride + + + VkStructureType sType + const void* pNext + VkBool32 arrayOfPointers + VkDeviceOrHostAddressConstKHR data + + + VkAccelerationStructureGeometryTrianglesDataKHR triangles + VkAccelerationStructureGeometryAabbsDataKHR aabbs + VkAccelerationStructureGeometryInstancesDataKHR instances + + + VkStructureType sType + const void* pNext + VkGeometryTypeKHR geometryType + VkAccelerationStructureGeometryDataKHR geometry + VkGeometryFlagsKHR flags + + + VkStructureType sType + const void* pNext + VkAccelerationStructureTypeKHR type + VkBuildAccelerationStructureFlagsKHR flags + VkBuildAccelerationStructureModeKHR mode + VkAccelerationStructureKHR srcAccelerationStructure + VkAccelerationStructureKHR dstAccelerationStructure + uint32_t geometryCount + const VkAccelerationStructureGeometryKHR* pGeometries + const VkAccelerationStructureGeometryKHR* const* ppGeometries + VkDeviceOrHostAddressKHR scratchData + + + uint32_t primitiveCount + uint32_t primitiveOffset + uint32_t firstVertex + uint32_t transformOffset + + + VkStructureType sType + const void* pNext + VkAccelerationStructureCreateFlagsKHR createFlags + VkBuffer buffer + VkDeviceSize offsetSpecified in bytes + VkDeviceSize size + VkAccelerationStructureTypeKHR type + VkDeviceAddress deviceAddress + + + float minX + float minY + float minZ + float maxX + float maxY + float maxZ + + + + float matrix[3][4] + + + + The bitfields in this structure are non-normative since bitfield ordering is implementation-defined in C. The specification defines the normative layout. + VkTransformMatrixKHR transform + uint32_t instanceCustomIndex:24 + uint32_t mask:8 + uint32_t instanceShaderBindingTableRecordOffset:24 + VkGeometryInstanceFlagsKHR flags:8 + uint64_t accelerationStructureReference + + + + VkStructureType sType + const void* pNext + VkAccelerationStructureKHR accelerationStructure + + + VkStructureType sType + const void* pNext + const uint8_t* pVersionData + + + VkStructureType sType + const void* pNext + VkAccelerationStructureKHR src + VkAccelerationStructureKHR dst + VkCopyAccelerationStructureModeKHR mode + + + VkStructureType sType + const void* pNext + VkAccelerationStructureKHR src + VkDeviceOrHostAddressKHR dst + VkCopyAccelerationStructureModeKHR mode + + + VkStructureType sType + const void* pNext + VkDeviceOrHostAddressConstKHR src + VkAccelerationStructureKHR dst + VkCopyAccelerationStructureModeKHR mode + + + VkStructureType sType + const void* pNext + uint32_t maxPipelineRayPayloadSize + uint32_t maxPipelineRayHitAttributeSize + + + VkStructureType sType + const void* pNext + uint32_t libraryCount + const VkPipeline* pLibraries + + + VkStructureType sType + void* pNext + VkBool32 extendedDynamicState + + + VkStructureType sType + void* pNext + VkBool32 extendedDynamicState2 + VkBool32 extendedDynamicState2LogicOp + VkBool32 extendedDynamicState2PatchControlPoints + + + VkStructureType sType + void* pNext + VkBool32 extendedDynamicState3TessellationDomainOrigin + VkBool32 extendedDynamicState3DepthClampEnable + VkBool32 extendedDynamicState3PolygonMode + VkBool32 extendedDynamicState3RasterizationSamples + VkBool32 extendedDynamicState3SampleMask + VkBool32 extendedDynamicState3AlphaToCoverageEnable + VkBool32 extendedDynamicState3AlphaToOneEnable + VkBool32 extendedDynamicState3LogicOpEnable + VkBool32 extendedDynamicState3ColorBlendEnable + VkBool32 extendedDynamicState3ColorBlendEquation + VkBool32 extendedDynamicState3ColorWriteMask + VkBool32 extendedDynamicState3RasterizationStream + VkBool32 extendedDynamicState3ConservativeRasterizationMode + VkBool32 extendedDynamicState3ExtraPrimitiveOverestimationSize + VkBool32 extendedDynamicState3DepthClipEnable + VkBool32 extendedDynamicState3SampleLocationsEnable + VkBool32 extendedDynamicState3ColorBlendAdvanced + VkBool32 extendedDynamicState3ProvokingVertexMode + VkBool32 extendedDynamicState3LineRasterizationMode + VkBool32 extendedDynamicState3LineStippleEnable + VkBool32 extendedDynamicState3DepthClipNegativeOneToOne + VkBool32 extendedDynamicState3ViewportWScalingEnable + VkBool32 extendedDynamicState3ViewportSwizzle + VkBool32 extendedDynamicState3CoverageToColorEnable + VkBool32 extendedDynamicState3CoverageToColorLocation + VkBool32 extendedDynamicState3CoverageModulationMode + VkBool32 extendedDynamicState3CoverageModulationTableEnable + VkBool32 extendedDynamicState3CoverageModulationTable + VkBool32 extendedDynamicState3CoverageReductionMode + VkBool32 extendedDynamicState3RepresentativeFragmentTestEnable + VkBool32 extendedDynamicState3ShadingRateImageEnable + + + VkStructureType sType + void* pNext + VkBool32 dynamicPrimitiveTopologyUnrestricted + + + VkBlendFactor srcColorBlendFactor + VkBlendFactor dstColorBlendFactor + VkBlendOp colorBlendOp + VkBlendFactor srcAlphaBlendFactor + VkBlendFactor dstAlphaBlendFactor + VkBlendOp alphaBlendOp + + + VkBlendOp advancedBlendOp + VkBool32 srcPremultiplied + VkBool32 dstPremultiplied + VkBlendOverlapEXT blendOverlap + VkBool32 clampResults + + + VkStructureType sType + void* pNextPointer to next structure + VkSurfaceTransformFlagBitsKHR transform + + + VkStructureType sType + const void* pNext + VkSurfaceTransformFlagBitsKHR transform + + + VkStructureType sType + void* pNextPointer to next structure + VkSurfaceTransformFlagBitsKHR transform + VkRect2D renderArea + + + VkStructureType sType + void* pNext + VkBool32 diagnosticsConfig + + + VkStructureType sType + const void* pNext + VkDeviceDiagnosticsConfigFlagsNV flags + + + VkStructureType sType + void* pNext + VkBool32 shaderZeroInitializeWorkgroupMemory + + + + VkStructureType sType + void* pNext + VkBool32 shaderSubgroupUniformControlFlow + + + VkStructureType sType + void* pNext + VkBool32 robustBufferAccess2 + VkBool32 robustImageAccess2 + VkBool32 nullDescriptor + + + VkStructureType sType + void* pNext + VkDeviceSize robustStorageBufferAccessSizeAlignment + VkDeviceSize robustUniformBufferAccessSizeAlignment + + + VkStructureType sType + void* pNext + VkBool32 robustImageAccess + + + + VkStructureType sType + void* pNext + VkBool32 workgroupMemoryExplicitLayout + VkBool32 workgroupMemoryExplicitLayoutScalarBlockLayout + VkBool32 workgroupMemoryExplicitLayout8BitAccess + VkBool32 workgroupMemoryExplicitLayout16BitAccess + + + VkStructureType sType + void* pNext + VkBool32 constantAlphaColorBlendFactors + VkBool32 events + VkBool32 imageViewFormatReinterpretation + VkBool32 imageViewFormatSwizzle + VkBool32 imageView2DOn3DImage + VkBool32 multisampleArrayImage + VkBool32 mutableComparisonSamplers + VkBool32 pointPolygons + VkBool32 samplerMipLodBias + VkBool32 separateStencilMaskRef + VkBool32 shaderSampleRateInterpolationFunctions + VkBool32 tessellationIsolines + VkBool32 tessellationPointMode + VkBool32 triangleFans + VkBool32 vertexAttributeAccessBeyondStride + + + VkStructureType sType + void* pNext + uint32_t minVertexInputBindingStrideAlignment + + + VkStructureType sType + void* pNext + VkBool32 formatA4R4G4B4 + VkBool32 formatA4B4G4R4 + + + VkStructureType sType + void* pNext + VkBool32 subpassShading + + + VkStructureType sType + const void* pNext + VkDeviceSize srcOffsetSpecified in bytes + VkDeviceSize dstOffsetSpecified in bytes + VkDeviceSize sizeSpecified in bytes + + + + VkStructureType sType + const void* pNext + VkImageSubresourceLayers srcSubresource + VkOffset3D srcOffsetSpecified in pixels for both compressed and uncompressed images + VkImageSubresourceLayers dstSubresource + VkOffset3D dstOffsetSpecified in pixels for both compressed and uncompressed images + VkExtent3D extentSpecified in pixels for both compressed and uncompressed images + + + + VkStructureType sType + const void* pNext + VkImageSubresourceLayers srcSubresource + VkOffset3D srcOffsets[2]Specified in pixels for both compressed and uncompressed images + VkImageSubresourceLayers dstSubresource + VkOffset3D dstOffsets[2]Specified in pixels for both compressed and uncompressed images + + + + VkStructureType sType + const void* pNext + VkDeviceSize bufferOffsetSpecified in bytes + uint32_t bufferRowLengthSpecified in texels + uint32_t bufferImageHeight + VkImageSubresourceLayers imageSubresource + VkOffset3D imageOffsetSpecified in pixels for both compressed and uncompressed images + VkExtent3D imageExtentSpecified in pixels for both compressed and uncompressed images + + + + VkStructureType sType + const void* pNext + VkImageSubresourceLayers srcSubresource + VkOffset3D srcOffset + VkImageSubresourceLayers dstSubresource + VkOffset3D dstOffset + VkExtent3D extent + + + + VkStructureType sType + const void* pNext + VkBuffer srcBuffer + VkBuffer dstBuffer + uint32_t regionCount + const VkBufferCopy2* pRegions + + + + VkStructureType sType + const void* pNext + VkImage srcImage + VkImageLayout srcImageLayout + VkImage dstImage + VkImageLayout dstImageLayout + uint32_t regionCount + const VkImageCopy2* pRegions + + + + VkStructureType sType + const void* pNext + VkImage srcImage + VkImageLayout srcImageLayout + VkImage dstImage + VkImageLayout dstImageLayout + uint32_t regionCount + const VkImageBlit2* pRegions + VkFilter filter + + + + VkStructureType sType + const void* pNext + VkBuffer srcBuffer + VkImage dstImage + VkImageLayout dstImageLayout + uint32_t regionCount + const VkBufferImageCopy2* pRegions + + + + VkStructureType sType + const void* pNext + VkImage srcImage + VkImageLayout srcImageLayout + VkBuffer dstBuffer + uint32_t regionCount + const VkBufferImageCopy2* pRegions + + + + VkStructureType sType + const void* pNext + VkImage srcImage + VkImageLayout srcImageLayout + VkImage dstImage + VkImageLayout dstImageLayout + uint32_t regionCount + const VkImageResolve2* pRegions + + + + VkStructureType sType + void* pNext + VkBool32 shaderImageInt64Atomics + VkBool32 sparseImageInt64Atomics + + + VkStructureType sType + const void* pNext + const VkAttachmentReference2* pFragmentShadingRateAttachment + VkExtent2D shadingRateAttachmentTexelSize + + + VkStructureType sType + const void* pNext + VkExtent2D fragmentSize + VkFragmentShadingRateCombinerOpKHR combinerOps[2] + + + VkStructureType sType + void* pNext + VkBool32 pipelineFragmentShadingRate + VkBool32 primitiveFragmentShadingRate + VkBool32 attachmentFragmentShadingRate + + + VkStructureType sType + void* pNext + VkExtent2D minFragmentShadingRateAttachmentTexelSize + VkExtent2D maxFragmentShadingRateAttachmentTexelSize + uint32_t maxFragmentShadingRateAttachmentTexelSizeAspectRatio + VkBool32 primitiveFragmentShadingRateWithMultipleViewports + VkBool32 layeredShadingRateAttachments + VkBool32 fragmentShadingRateNonTrivialCombinerOps + VkExtent2D maxFragmentSize + uint32_t maxFragmentSizeAspectRatio + uint32_t maxFragmentShadingRateCoverageSamples + VkSampleCountFlagBits maxFragmentShadingRateRasterizationSamples + VkBool32 fragmentShadingRateWithShaderDepthStencilWrites + VkBool32 fragmentShadingRateWithSampleMask + VkBool32 fragmentShadingRateWithShaderSampleMask + VkBool32 fragmentShadingRateWithConservativeRasterization + VkBool32 fragmentShadingRateWithFragmentShaderInterlock + VkBool32 fragmentShadingRateWithCustomSampleLocations + VkBool32 fragmentShadingRateStrictMultiplyCombiner + + + VkStructureType sType + void* pNext + VkSampleCountFlags sampleCounts + VkExtent2D fragmentSize + + + VkStructureType sType + void* pNext + VkBool32 shaderTerminateInvocation + + + + VkStructureType sType + void* pNext + VkBool32 fragmentShadingRateEnums + VkBool32 supersampleFragmentShadingRates + VkBool32 noInvocationFragmentShadingRates + + + VkStructureType sType + void* pNext + VkSampleCountFlagBits maxFragmentShadingRateInvocationCount + + + VkStructureType sType + const void* pNext + VkFragmentShadingRateTypeNV shadingRateType + VkFragmentShadingRateNV shadingRate + VkFragmentShadingRateCombinerOpKHR combinerOps[2] + + + VkStructureType sType + const void* pNext + VkDeviceSize accelerationStructureSize + VkDeviceSize updateScratchSize + VkDeviceSize buildScratchSize + + + VkStructureType sType + void* pNext + VkBool32 image2DViewOf3D + VkBool32 sampler2DViewOf3D + + + VkStructureType sType + void* pNext + VkBool32 mutableDescriptorType + + + + uint32_t descriptorTypeCount + const VkDescriptorType* pDescriptorTypes + + + + VkStructureType sType + const void* pNext + uint32_t mutableDescriptorTypeListCount + const VkMutableDescriptorTypeListEXT* pMutableDescriptorTypeLists + + + + VkStructureType sType + void* pNext + VkBool32 depthClipControl + + + VkStructureType sType + const void* pNext + VkBool32 negativeOneToOne + + + VkStructureType sType + void* pNext + VkBool32 vertexInputDynamicState + + + VkStructureType sType + void* pNext + VkBool32 externalMemoryRDMA + + + VkStructureType sType + void* pNext + uint32_t binding + uint32_t stride + VkVertexInputRate inputRate + uint32_t divisor + + + VkStructureType sType + void* pNext + uint32_t locationlocation of the shader vertex attrib + uint32_t bindingVertex buffer binding id + VkFormat formatformat of source data + uint32_t offsetOffset of first element in bytes from base of vertex + + + VkStructureType sType + void* pNext + VkBool32 colorWriteEnable + + + VkStructureType sType + const void* pNext + uint32_t attachmentCount# of pAttachments + const VkBool32* pColorWriteEnables + + + VkStructureType sType + const void* pNext + VkPipelineStageFlags2 srcStageMask + VkAccessFlags2 srcAccessMask + VkPipelineStageFlags2 dstStageMask + VkAccessFlags2 dstAccessMask + + + + VkStructureType sType + const void* pNext + VkPipelineStageFlags2 srcStageMask + VkAccessFlags2 srcAccessMask + VkPipelineStageFlags2 dstStageMask + VkAccessFlags2 dstAccessMask + VkImageLayout oldLayout + VkImageLayout newLayout + uint32_t srcQueueFamilyIndex + uint32_t dstQueueFamilyIndex + VkImage image + VkImageSubresourceRange subresourceRange + + + + VkStructureType sType + const void* pNext + VkPipelineStageFlags2 srcStageMask + VkAccessFlags2 srcAccessMask + VkPipelineStageFlags2 dstStageMask + VkAccessFlags2 dstAccessMask + uint32_t srcQueueFamilyIndex + uint32_t dstQueueFamilyIndex + VkBuffer buffer + VkDeviceSize offset + VkDeviceSize size + + + + VkStructureType sType + const void* pNext + VkDependencyFlags dependencyFlags + uint32_t memoryBarrierCount + const VkMemoryBarrier2* pMemoryBarriers + uint32_t bufferMemoryBarrierCount + const VkBufferMemoryBarrier2* pBufferMemoryBarriers + uint32_t imageMemoryBarrierCount + const VkImageMemoryBarrier2* pImageMemoryBarriers + + + + VkStructureType sType + const void* pNext + VkSemaphore semaphore + uint64_t value + VkPipelineStageFlags2 stageMask + uint32_t deviceIndex + + + + VkStructureType sType + const void* pNext + VkCommandBuffer commandBuffer + uint32_t deviceMask + + + + VkStructureType sType + const void* pNext + VkSubmitFlags flags + uint32_t waitSemaphoreInfoCount + const VkSemaphoreSubmitInfo* pWaitSemaphoreInfos + uint32_t commandBufferInfoCount + const VkCommandBufferSubmitInfo* pCommandBufferInfos + uint32_t signalSemaphoreInfoCount + const VkSemaphoreSubmitInfo* pSignalSemaphoreInfos + + + + VkStructureType sType + void* pNext + VkPipelineStageFlags2 checkpointExecutionStageMask + + + VkStructureType sType + void* pNext + VkPipelineStageFlags2 stage + void* pCheckpointMarker + + + VkStructureType sType + void* pNext + VkBool32 synchronization2 + + + + VkStructureType sType + void* pNext + VkBool32 primitivesGeneratedQuery + VkBool32 primitivesGeneratedQueryWithRasterizerDiscard + VkBool32 primitivesGeneratedQueryWithNonZeroStreams + + + VkStructureType sType + void* pNext + VkBool32 legacyDithering + + + VkStructureType sType + void* pNext + VkBool32 multisampledRenderToSingleSampled + + + VkStructureType sType + void* pNext + VkBool32 optimal + + + VkStructureType sType + const void* pNext + VkBool32 multisampledRenderToSingleSampledEnable + VkSampleCountFlagBits rasterizationSamples + + + VkStructureType sType + void* pNext + VkBool32 pipelineProtectedAccess + + + VkStructureType sType + void* pNext + VkVideoCodecOperationFlagsKHR videoCodecOperations + + + VkStructureType sType + void* pNext + VkBool32 queryResultStatusSupport + + + VkStructureType sType + const void* pNext + uint32_t profileCount + const VkVideoProfileInfoKHR* pProfiles + + + VkStructureType sType + const void* pNext + VkImageUsageFlags imageUsage + + + VkStructureType sType + void* pNext + VkFormat format + VkComponentMapping componentMapping + VkImageCreateFlags imageCreateFlags + VkImageType imageType + VkImageTiling imageTiling + VkImageUsageFlags imageUsageFlags + + + VkStructureType sType + const void* pNext + VkVideoCodecOperationFlagBitsKHR videoCodecOperation + VkVideoChromaSubsamplingFlagsKHR chromaSubsampling + VkVideoComponentBitDepthFlagsKHR lumaBitDepth + VkVideoComponentBitDepthFlagsKHR chromaBitDepth + + + VkStructureType sType + void* pNext + VkVideoCapabilityFlagsKHR flags + VkDeviceSize minBitstreamBufferOffsetAlignment + VkDeviceSize minBitstreamBufferSizeAlignment + VkExtent2D pictureAccessGranularity + VkExtent2D minCodedExtent + VkExtent2D maxCodedExtent + uint32_t maxDpbSlots + uint32_t maxActiveReferencePictures + VkExtensionProperties stdHeaderVersion + + + VkStructureType sType + void* pNext + uint32_t memoryBindIndex + VkMemoryRequirements memoryRequirements + + + VkStructureType sType + const void* pNext + uint32_t memoryBindIndex + VkDeviceMemory memory + VkDeviceSize memoryOffset + VkDeviceSize memorySize + + + VkStructureType sType + const void* pNext + VkOffset2D codedOffsetThe offset to be used for the picture resource, currently only used in field mode + VkExtent2D codedExtentThe extent to be used for the picture resource + uint32_t baseArrayLayerThe first array layer to be accessed for the Decode or Encode Operations + VkImageView imageViewBindingThe ImageView binding of the resource + + + VkStructureType sType + const void* pNext + int32_t slotIndexThe reference slot index + const VkVideoPictureResourceInfoKHR* pPictureResourceThe reference picture resource + + + VkStructureType sType + void* pNext + VkVideoDecodeCapabilityFlagsKHR flags + + + VkStructureType sType + const void* pNext + VkVideoDecodeUsageFlagsKHR videoUsageHints + + + VkStructureType sType + const void* pNext + VkVideoDecodeFlagsKHR flags + VkBuffer srcBuffer + VkDeviceSize srcBufferOffset + VkDeviceSize srcBufferRange + VkVideoPictureResourceInfoKHR dstPictureResource + const VkVideoReferenceSlotInfoKHR* pSetupReferenceSlot + uint32_t referenceSlotCount + const VkVideoReferenceSlotInfoKHR* pReferenceSlots + + Video Decode Codec Standard specific structures + #include "vk_video/vulkan_video_codec_h264std.h" + + + + + + + + + + + + + + + + + + + #include "vk_video/vulkan_video_codec_h264std_decode.h" + + + + + + VkStructureType sType + const void* pNext + StdVideoH264ProfileIdc stdProfileIdc + VkVideoDecodeH264PictureLayoutFlagBitsEXT pictureLayout + + + VkStructureType sType + void* pNext + StdVideoH264LevelIdc maxLevelIdc + VkOffset2D fieldOffsetGranularity + + + + + VkStructureType sType + const void* pNext + uint32_t stdSPSCount + const StdVideoH264SequenceParameterSet* pStdSPSs + uint32_t stdPPSCount + const StdVideoH264PictureParameterSet* pStdPPSsList of Picture Parameters associated with the spsStd, above + + + VkStructureType sType + const void* pNext + uint32_t maxStdSPSCount + uint32_t maxStdPPSCount + const VkVideoDecodeH264SessionParametersAddInfoEXT* pParametersAddInfo + + + VkStructureType sType + const void* pNext + const StdVideoDecodeH264PictureInfo* pStdPictureInfo + uint32_t sliceCount + const uint32_t* pSliceOffsets + + + VkStructureType sType + const void* pNext + const StdVideoDecodeH264ReferenceInfo* pStdReferenceInfo + + #include "vk_video/vulkan_video_codec_h265std.h" + + + + + + + + + + + + + + + + + + + #include "vk_video/vulkan_video_codec_h265std_decode.h" + + + + + + VkStructureType sType + const void* pNext + StdVideoH265ProfileIdc stdProfileIdc + + + VkStructureType sType + void* pNext + StdVideoH265LevelIdc maxLevelIdc + + + VkStructureType sType + const void* pNext + uint32_t stdVPSCount + const StdVideoH265VideoParameterSet* pStdVPSs + uint32_t stdSPSCount + const StdVideoH265SequenceParameterSet* pStdSPSs + uint32_t stdPPSCount + const StdVideoH265PictureParameterSet* pStdPPSsList of Picture Parameters associated with the spsStd, above + + + VkStructureType sType + const void* pNext + uint32_t maxStdVPSCount + uint32_t maxStdSPSCount + uint32_t maxStdPPSCount + const VkVideoDecodeH265SessionParametersAddInfoEXT* pParametersAddInfo + + + VkStructureType sType + const void* pNext + StdVideoDecodeH265PictureInfo* pStdPictureInfo + uint32_t sliceCount + const uint32_t* pSliceOffsets + + + VkStructureType sType + const void* pNext + const StdVideoDecodeH265ReferenceInfo* pStdReferenceInfo + + + VkStructureType sType + const void* pNext + uint32_t queueFamilyIndex + VkVideoSessionCreateFlagsKHR flags + const VkVideoProfileInfoKHR* pVideoProfile + VkFormat pictureFormat + VkExtent2D maxCodedExtent + VkFormat referencePictureFormat + uint32_t maxDpbSlots + uint32_t maxActiveReferencePictures + const VkExtensionProperties* pStdHeaderVersion + + + VkStructureType sType + const void* pNext + VkVideoSessionParametersCreateFlagsKHR flags + VkVideoSessionParametersKHR videoSessionParametersTemplate + VkVideoSessionKHR videoSession + + + VkStructureType sType + const void* pNext + uint32_t updateSequenceCount + + + VkStructureType sType + const void* pNext + VkVideoBeginCodingFlagsKHR flags + VkVideoSessionKHR videoSession + VkVideoSessionParametersKHR videoSessionParameters + uint32_t referenceSlotCount + const VkVideoReferenceSlotInfoKHR* pReferenceSlots + + + VkStructureType sType + const void* pNext + VkVideoEndCodingFlagsKHR flags + + + VkStructureType sType + const void* pNext + VkVideoCodingControlFlagsKHR flags + + + VkStructureType sType + const void* pNext + VkVideoEncodeUsageFlagsKHR videoUsageHints + VkVideoEncodeContentFlagsKHR videoContentHints + VkVideoEncodeTuningModeKHR tuningMode + + + VkStructureType sType + const void* pNext + VkVideoEncodeFlagsKHR flags + uint32_t qualityLevel + VkBuffer dstBitstreamBuffer + VkDeviceSize dstBitstreamBufferOffset + VkDeviceSize dstBitstreamBufferMaxRange + VkVideoPictureResourceInfoKHR srcPictureResource + const VkVideoReferenceSlotInfoKHR* pSetupReferenceSlot + uint32_t referenceSlotCount + const VkVideoReferenceSlotInfoKHR* pReferenceSlots + uint32_t precedingExternallyEncodedBytes + + + VkStructureType sType + const void* pNext + VkVideoEncodeRateControlFlagsKHR flags + VkVideoEncodeRateControlModeFlagBitsKHR rateControlMode + uint8_t layerCount + const VkVideoEncodeRateControlLayerInfoKHR* pLayerConfigs + + + VkStructureType sType + const void* pNext + uint32_t averageBitrate + uint32_t maxBitrate + uint32_t frameRateNumerator + uint32_t frameRateDenominator + uint32_t virtualBufferSizeInMs + uint32_t initialVirtualBufferSizeInMs + + + VkStructureType sType + void* pNext + VkVideoEncodeCapabilityFlagsKHR flags + VkVideoEncodeRateControlModeFlagsKHR rateControlModes + uint8_t rateControlLayerCount + uint8_t qualityLevelCount + VkExtent2D inputImageDataFillAlignment + + + VkStructureType sType + void* pNext + VkVideoEncodeH264CapabilityFlagsEXT flags + VkVideoEncodeH264InputModeFlagsEXT inputModeFlags + VkVideoEncodeH264OutputModeFlagsEXT outputModeFlags + uint8_t maxPPictureL0ReferenceCount + uint8_t maxBPictureL0ReferenceCount + uint8_t maxL1ReferenceCount + VkBool32 motionVectorsOverPicBoundariesFlag + uint32_t maxBytesPerPicDenom + uint32_t maxBitsPerMbDenom + uint32_t log2MaxMvLengthHorizontal + uint32_t log2MaxMvLengthVertical + + #include "vk_video/vulkan_video_codec_h264std_encode.h" + + + + + + + + + + + + VkStructureType sType + const void* pNext + uint32_t stdSPSCount + const StdVideoH264SequenceParameterSet* pStdSPSs + uint32_t stdPPSCount + const StdVideoH264PictureParameterSet* pStdPPSsList of Picture Parameters associated with the spsStd, above + + + VkStructureType sType + const void* pNext + uint32_t maxStdSPSCount + uint32_t maxStdPPSCount + const VkVideoEncodeH264SessionParametersAddInfoEXT* pParametersAddInfo + + + VkStructureType sType + const void* pNext + int8_t slotIndex + const StdVideoEncodeH264ReferenceInfo* pStdReferenceInfo + + + VkStructureType sType + const void* pNext + const VkVideoEncodeH264ReferenceListsInfoEXT* pReferenceFinalLists + uint32_t naluSliceEntryCount + const VkVideoEncodeH264NaluSliceInfoEXT* pNaluSliceEntries + const StdVideoEncodeH264PictureInfo* pCurrentPictureInfo + + + VkStructureType sType + const void* pNext + uint8_t referenceList0EntryCount + const VkVideoEncodeH264DpbSlotInfoEXT* pReferenceList0Entries + uint8_t referenceList1EntryCount + const VkVideoEncodeH264DpbSlotInfoEXT* pReferenceList1Entries + const StdVideoEncodeH264RefMemMgmtCtrlOperations* pMemMgmtCtrlOperations + + + VkStructureType sType + const void* pNext + uint8_t spsId + VkBool32 emitSpsEnable + uint32_t ppsIdEntryCount + const uint8_t* ppsIdEntries + + + VkStructureType sType + const void* pNext + StdVideoH264ProfileIdc stdProfileIdc + + + VkStructureType sType + const void* pNext + uint32_t mbCount + const VkVideoEncodeH264ReferenceListsInfoEXT* pReferenceFinalLists + const StdVideoEncodeH264SliceHeader* pSliceHeaderStd + + + VkStructureType sType + const void* pNext + uint32_t gopFrameCount + uint32_t idrPeriod + uint32_t consecutiveBFrameCount + VkVideoEncodeH264RateControlStructureEXT rateControlStructure + uint8_t temporalLayerCount + + + int32_t qpI + int32_t qpP + int32_t qpB + + + uint32_t frameISize + uint32_t framePSize + uint32_t frameBSize + + + VkStructureType sType + const void* pNext + uint8_t temporalLayerId + VkBool32 useInitialRcQp + VkVideoEncodeH264QpEXT initialRcQp + VkBool32 useMinQp + VkVideoEncodeH264QpEXT minQp + VkBool32 useMaxQp + VkVideoEncodeH264QpEXT maxQp + VkBool32 useMaxFrameSize + VkVideoEncodeH264FrameSizeEXT maxFrameSize + + + VkStructureType sType + void* pNext + VkVideoEncodeH265CapabilityFlagsEXT flags + VkVideoEncodeH265InputModeFlagsEXT inputModeFlags + VkVideoEncodeH265OutputModeFlagsEXT outputModeFlags + VkVideoEncodeH265CtbSizeFlagsEXT ctbSizes + VkVideoEncodeH265TransformBlockSizeFlagsEXT transformBlockSizes + uint8_t maxPPictureL0ReferenceCount + uint8_t maxBPictureL0ReferenceCount + uint8_t maxL1ReferenceCount + uint8_t maxSubLayersCount + uint8_t minLog2MinLumaCodingBlockSizeMinus3 + uint8_t maxLog2MinLumaCodingBlockSizeMinus3 + uint8_t minLog2MinLumaTransformBlockSizeMinus2 + uint8_t maxLog2MinLumaTransformBlockSizeMinus2 + uint8_t minMaxTransformHierarchyDepthInter + uint8_t maxMaxTransformHierarchyDepthInter + uint8_t minMaxTransformHierarchyDepthIntra + uint8_t maxMaxTransformHierarchyDepthIntra + uint8_t maxDiffCuQpDeltaDepth + uint8_t minMaxNumMergeCand + uint8_t maxMaxNumMergeCand + + #include "vk_video/vulkan_video_codec_h265std_encode.h" + + + + + + + + + + VkStructureType sType + const void* pNext + uint32_t stdVPSCount + const StdVideoH265VideoParameterSet* pStdVPSs + uint32_t stdSPSCount + const StdVideoH265SequenceParameterSet* pStdSPSs + uint32_t stdPPSCount + const StdVideoH265PictureParameterSet* pStdPPSsList of Picture Parameters associated with the spsStd, above + + + VkStructureType sType + const void* pNext + uint32_t maxStdVPSCount + uint32_t maxStdSPSCount + uint32_t maxStdPPSCount + const VkVideoEncodeH265SessionParametersAddInfoEXT* pParametersAddInfo + + + VkStructureType sType + const void* pNext + const VkVideoEncodeH265ReferenceListsInfoEXT* pReferenceFinalLists + uint32_t naluSliceSegmentEntryCount + const VkVideoEncodeH265NaluSliceSegmentInfoEXT* pNaluSliceSegmentEntries + const StdVideoEncodeH265PictureInfo* pCurrentPictureInfo + + + VkStructureType sType + const void* pNext + uint8_t vpsId + uint8_t spsId + VkBool32 emitVpsEnable + VkBool32 emitSpsEnable + uint32_t ppsIdEntryCount + const uint8_t* ppsIdEntries + + + VkStructureType sType + const void* pNext + uint32_t ctbCount + const VkVideoEncodeH265ReferenceListsInfoEXT* pReferenceFinalLists + const StdVideoEncodeH265SliceSegmentHeader* pSliceSegmentHeaderStd + + + VkStructureType sType + const void* pNext + uint32_t gopFrameCount + uint32_t idrPeriod + uint32_t consecutiveBFrameCount + VkVideoEncodeH265RateControlStructureEXT rateControlStructure + uint8_t subLayerCount + + + int32_t qpI + int32_t qpP + int32_t qpB + + + uint32_t frameISize + uint32_t framePSize + uint32_t frameBSize + + + VkStructureType sType + const void* pNext + uint8_t temporalId + VkBool32 useInitialRcQp + VkVideoEncodeH265QpEXT initialRcQp + VkBool32 useMinQp + VkVideoEncodeH265QpEXT minQp + VkBool32 useMaxQp + VkVideoEncodeH265QpEXT maxQp + VkBool32 useMaxFrameSize + VkVideoEncodeH265FrameSizeEXT maxFrameSize + + + VkStructureType sType + const void* pNext + StdVideoH265ProfileIdc stdProfileIdc + + + VkStructureType sType + const void* pNext + int8_t slotIndex + const StdVideoEncodeH265ReferenceInfo* pStdReferenceInfo + + + VkStructureType sType + const void* pNext + uint8_t referenceList0EntryCount + const VkVideoEncodeH265DpbSlotInfoEXT* pReferenceList0Entries + uint8_t referenceList1EntryCount + const VkVideoEncodeH265DpbSlotInfoEXT* pReferenceList1Entries + const StdVideoEncodeH265ReferenceModifications* pReferenceModifications + + + VkStructureType sType + void* pNext + VkBool32 inheritedViewportScissor2D + + + VkStructureType sType + const void* pNext + VkBool32 viewportScissor2D + uint32_t viewportDepthCount + const VkViewport* pViewportDepths + + + VkStructureType sType + void* pNext + VkBool32 ycbcr2plane444Formats + + + VkStructureType sType + void* pNext + VkBool32 provokingVertexLast + VkBool32 transformFeedbackPreservesProvokingVertex + + + VkStructureType sType + void* pNext + VkBool32 provokingVertexModePerPipeline + VkBool32 transformFeedbackPreservesTriangleFanProvokingVertex + + + VkStructureType sType + const void* pNext + VkProvokingVertexModeEXT provokingVertexMode + + + VkStructureType sType + const void* pNext + size_t dataSize + const void* pData + + + VkStructureType sType + const void* pNext + VkCuModuleNVX module + const char* pName + + + VkStructureType sType + const void* pNext + VkCuFunctionNVX function + uint32_t gridDimX + uint32_t gridDimY + uint32_t gridDimZ + uint32_t blockDimX + uint32_t blockDimY + uint32_t blockDimZ + uint32_t sharedMemBytes + size_t paramCount + const void* const * pParams + size_t extraCount + const void* const * pExtras + + + VkStructureType sType + void* pNext + VkBool32 descriptorBuffer + VkBool32 descriptorBufferCaptureReplay + VkBool32 descriptorBufferImageLayoutIgnored + VkBool32 descriptorBufferPushDescriptors + + + VkStructureType sType + void* pNext + VkBool32 combinedImageSamplerDescriptorSingleArray + VkBool32 bufferlessPushDescriptors + VkBool32 allowSamplerImageViewPostSubmitCreation + VkDeviceSize descriptorBufferOffsetAlignment + uint32_t maxDescriptorBufferBindings + uint32_t maxResourceDescriptorBufferBindings + uint32_t maxSamplerDescriptorBufferBindings + uint32_t maxEmbeddedImmutableSamplerBindings + uint32_t maxEmbeddedImmutableSamplers + size_t bufferCaptureReplayDescriptorDataSize + size_t imageCaptureReplayDescriptorDataSize + size_t imageViewCaptureReplayDescriptorDataSize + size_t samplerCaptureReplayDescriptorDataSize + size_t accelerationStructureCaptureReplayDescriptorDataSize + size_t samplerDescriptorSize + size_t combinedImageSamplerDescriptorSize + size_t sampledImageDescriptorSize + size_t storageImageDescriptorSize + size_t uniformTexelBufferDescriptorSize + size_t robustUniformTexelBufferDescriptorSize + size_t storageTexelBufferDescriptorSize + size_t robustStorageTexelBufferDescriptorSize + size_t uniformBufferDescriptorSize + size_t robustUniformBufferDescriptorSize + size_t storageBufferDescriptorSize + size_t robustStorageBufferDescriptorSize + size_t inputAttachmentDescriptorSize + size_t accelerationStructureDescriptorSize + VkDeviceSize maxSamplerDescriptorBufferRange + VkDeviceSize maxResourceDescriptorBufferRange + VkDeviceSize samplerDescriptorBufferAddressSpaceSize + VkDeviceSize resourceDescriptorBufferAddressSpaceSize + VkDeviceSize descriptorBufferAddressSpaceSize + + + VkStructureType sType + void* pNext + size_t combinedImageSamplerDensityMapDescriptorSize + + + VkStructureType sType + void* pNext + VkDeviceAddress address + VkDeviceSize range + VkFormat format + + + VkStructureType sType + void* pNext + VkDeviceAddress address + VkBufferUsageFlags usage + + + VkStructureType sType + void* pNext + VkBuffer buffer + + + const VkSampler* pSampler + const VkDescriptorImageInfo* pCombinedImageSampler + const VkDescriptorImageInfo* pInputAttachmentImage + const VkDescriptorImageInfo* pSampledImage + const VkDescriptorImageInfo* pStorageImage + const VkDescriptorAddressInfoEXT* pUniformTexelBuffer + const VkDescriptorAddressInfoEXT* pStorageTexelBuffer + const VkDescriptorAddressInfoEXT* pUniformBuffer + const VkDescriptorAddressInfoEXT* pStorageBuffer + VkDeviceAddress accelerationStructure + + + VkStructureType sType + const void* pNext + VkDescriptorType type + VkDescriptorDataEXT data + + + VkStructureType sType + const void* pNext + VkBuffer buffer + + + VkStructureType sType + const void* pNext + VkImage image + + + VkStructureType sType + const void* pNext + VkImageView imageView + + + VkStructureType sType + const void* pNext + VkSampler sampler + + + VkStructureType sType + const void* pNext + VkAccelerationStructureKHR accelerationStructure + VkAccelerationStructureNV accelerationStructureNV + + + VkStructureType sType + const void* pNext + const void* opaqueCaptureDescriptorData + + + VkStructureType sType + void* pNext + VkBool32 shaderIntegerDotProduct + + + + VkStructureType sType + void* pNext + VkBool32 integerDotProduct8BitUnsignedAccelerated + VkBool32 integerDotProduct8BitSignedAccelerated + VkBool32 integerDotProduct8BitMixedSignednessAccelerated + VkBool32 integerDotProduct4x8BitPackedUnsignedAccelerated + VkBool32 integerDotProduct4x8BitPackedSignedAccelerated + VkBool32 integerDotProduct4x8BitPackedMixedSignednessAccelerated + VkBool32 integerDotProduct16BitUnsignedAccelerated + VkBool32 integerDotProduct16BitSignedAccelerated + VkBool32 integerDotProduct16BitMixedSignednessAccelerated + VkBool32 integerDotProduct32BitUnsignedAccelerated + VkBool32 integerDotProduct32BitSignedAccelerated + VkBool32 integerDotProduct32BitMixedSignednessAccelerated + VkBool32 integerDotProduct64BitUnsignedAccelerated + VkBool32 integerDotProduct64BitSignedAccelerated + VkBool32 integerDotProduct64BitMixedSignednessAccelerated + VkBool32 integerDotProductAccumulatingSaturating8BitUnsignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating8BitSignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated + VkBool32 integerDotProductAccumulatingSaturating16BitUnsignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating16BitSignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated + VkBool32 integerDotProductAccumulatingSaturating32BitUnsignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating32BitSignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated + VkBool32 integerDotProductAccumulatingSaturating64BitUnsignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating64BitSignedAccelerated + VkBool32 integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated + + + + VkStructureType sType + void* pNext + VkBool32 hasPrimary + VkBool32 hasRender + int64_t primaryMajor + int64_t primaryMinor + int64_t renderMajor + int64_t renderMinor + + + VkStructureType sType + void* pNext + VkBool32 fragmentShaderBarycentric + + + VkStructureType sType + void* pNext + VkBool32 triStripVertexOrderIndependentOfProvokingVertex + + + VkStructureType sType + void* pNext + VkBool32 rayTracingMotionBlur + VkBool32 rayTracingMotionBlurPipelineTraceRaysIndirect + + + + VkStructureType sType + const void* pNext + VkDeviceOrHostAddressConstKHR vertexData + + + VkStructureType sType + const void* pNext + uint32_t maxInstances + VkAccelerationStructureMotionInfoFlagsNV flags + + + float sx + float a + float b + float pvx + float sy + float c + float pvy + float sz + float pvz + float qx + float qy + float qz + float qw + float tx + float ty + float tz + + + The bitfields in this structure are non-normative since bitfield ordering is implementation-defined in C. The specification defines the normative layout. + VkSRTDataNV transformT0 + VkSRTDataNV transformT1 + uint32_t instanceCustomIndex:24 + uint32_t mask:8 + uint32_t instanceShaderBindingTableRecordOffset:24 + VkGeometryInstanceFlagsKHR flags:8 + uint64_t accelerationStructureReference + + + The bitfields in this structure are non-normative since bitfield ordering is implementation-defined in C. The specification defines the normative layout. + VkTransformMatrixKHR transformT0 + VkTransformMatrixKHR transformT1 + uint32_t instanceCustomIndex:24 + uint32_t mask:8 + uint32_t instanceShaderBindingTableRecordOffset:24 + VkGeometryInstanceFlagsKHR flags:8 + uint64_t accelerationStructureReference + + + VkAccelerationStructureInstanceKHR staticInstance + VkAccelerationStructureMatrixMotionInstanceNV matrixMotionInstance + VkAccelerationStructureSRTMotionInstanceNV srtMotionInstance + + + VkAccelerationStructureMotionInstanceTypeNV type + VkAccelerationStructureMotionInstanceFlagsNV flags + VkAccelerationStructureMotionInstanceDataNV data + + typedef void* VkRemoteAddressNV; + + VkStructureType sType + const void* pNext + VkDeviceMemory memory + VkExternalMemoryHandleTypeFlagBits handleType + + + VkStructureType sType + const void* pNext + VkBufferCollectionFUCHSIA collection + uint32_t index + + + VkStructureType sType + const void* pNext + VkBufferCollectionFUCHSIA collection + uint32_t index + + + VkStructureType sType + const void* pNext + VkBufferCollectionFUCHSIA collection + uint32_t index + + + VkStructureType sType + const void* pNext + zx_handle_t collectionToken + + + VkStructureType sType + void* pNext + uint32_t memoryTypeBits + uint32_t bufferCount + uint32_t createInfoIndex + uint64_t sysmemPixelFormat + VkFormatFeatureFlags formatFeatures + VkSysmemColorSpaceFUCHSIA sysmemColorSpaceIndex + VkComponentMapping samplerYcbcrConversionComponents + VkSamplerYcbcrModelConversion suggestedYcbcrModel + VkSamplerYcbcrRange suggestedYcbcrRange + VkChromaLocation suggestedXChromaOffset + VkChromaLocation suggestedYChromaOffset + + + VkStructureType sType + const void* pNext + VkBufferCreateInfo createInfo + VkFormatFeatureFlags requiredFormatFeatures + VkBufferCollectionConstraintsInfoFUCHSIA bufferCollectionConstraints + + + VkStructureType sType + const void* pNext + uint32_t colorSpace + + + VkStructureType sType + const void* pNext + VkImageCreateInfo imageCreateInfo + VkFormatFeatureFlags requiredFormatFeatures + VkImageFormatConstraintsFlagsFUCHSIA flags + uint64_t sysmemPixelFormat + uint32_t colorSpaceCount + const VkSysmemColorSpaceFUCHSIA* pColorSpaces + + + VkStructureType sType + const void* pNext + uint32_t formatConstraintsCount + const VkImageFormatConstraintsInfoFUCHSIA* pFormatConstraints + VkBufferCollectionConstraintsInfoFUCHSIA bufferCollectionConstraints + VkImageConstraintsInfoFlagsFUCHSIA flags + + + VkStructureType sType + const void* pNext + uint32_t minBufferCount + uint32_t maxBufferCount + uint32_t minBufferCountForCamping + uint32_t minBufferCountForDedicatedSlack + uint32_t minBufferCountForSharedSlack + + + VkStructureType sType + void* pNext + VkBool32 formatRgba10x6WithoutYCbCrSampler + + + VkStructureType sType + void* pNext + VkFormatFeatureFlags2 linearTilingFeatures + VkFormatFeatureFlags2 optimalTilingFeatures + VkFormatFeatureFlags2 bufferFeatures + + + + VkStructureType sType + void* pNext + uint32_t drmFormatModifierCount + VkDrmFormatModifierProperties2EXT* pDrmFormatModifierProperties + + + uint64_t drmFormatModifier + uint32_t drmFormatModifierPlaneCount + VkFormatFeatureFlags2 drmFormatModifierTilingFeatures + + + VkStructureType sType + void* pNext + VkFormat format + uint64_t externalFormat + VkFormatFeatureFlags2 formatFeatures + VkComponentMapping samplerYcbcrConversionComponents + VkSamplerYcbcrModelConversion suggestedYcbcrModel + VkSamplerYcbcrRange suggestedYcbcrRange + VkChromaLocation suggestedXChromaOffset + VkChromaLocation suggestedYChromaOffset + + + VkStructureType sType + const void* pNext + uint32_t viewMask + uint32_t colorAttachmentCount + const VkFormat* pColorAttachmentFormats + VkFormat depthAttachmentFormat + VkFormat stencilAttachmentFormat + + + + VkStructureType sType + const void* pNext + VkRenderingFlags flags + VkRect2D renderArea + uint32_t layerCount + uint32_t viewMask + uint32_t colorAttachmentCount + const VkRenderingAttachmentInfo* pColorAttachments + const VkRenderingAttachmentInfo* pDepthAttachment + const VkRenderingAttachmentInfo* pStencilAttachment + + + + VkStructureType sType + const void* pNext + VkImageView imageView + VkImageLayout imageLayout + VkResolveModeFlagBits resolveMode + VkImageView resolveImageView + VkImageLayout resolveImageLayout + VkAttachmentLoadOp loadOp + VkAttachmentStoreOp storeOp + VkClearValue clearValue + + + + VkStructureType sType + const void* pNext + VkImageView imageView + VkImageLayout imageLayout + VkExtent2D shadingRateAttachmentTexelSize + + + VkStructureType sType + const void* pNext + VkImageView imageView + VkImageLayout imageLayout + + + VkStructureType sType + void* pNext + VkBool32 dynamicRendering + + + + VkStructureType sType + const void* pNext + VkRenderingFlags flags + uint32_t viewMask + uint32_t colorAttachmentCount + const VkFormat* pColorAttachmentFormats + VkFormat depthAttachmentFormat + VkFormat stencilAttachmentFormat + VkSampleCountFlagBits rasterizationSamples + + + + VkStructureType sType + const void* pNext + uint32_t colorAttachmentCount + const VkSampleCountFlagBits* pColorAttachmentSamples + VkSampleCountFlagBits depthStencilAttachmentSamples + + + + VkStructureType sType + const void* pNext + VkBool32 perViewAttributes + VkBool32 perViewAttributesPositionXOnly + + + VkStructureType sType + void* pNext + VkBool32 minLod + + + VkStructureType sType + const void* pNext + float minLod + + + VkStructureType sType + void* pNext + VkBool32 rasterizationOrderColorAttachmentAccess + VkBool32 rasterizationOrderDepthAttachmentAccess + VkBool32 rasterizationOrderStencilAttachmentAccess + + + + VkStructureType sType + void* pNext + VkBool32 linearColorAttachment + + + VkStructureType sType + void* pNext + VkBool32 graphicsPipelineLibrary + + + VkStructureType sType + void* pNext + VkBool32 graphicsPipelineLibraryFastLinking + VkBool32 graphicsPipelineLibraryIndependentInterpolationDecoration + + + VkStructureType sType + void* pNext + VkGraphicsPipelineLibraryFlagsEXT flags + + + VkStructureType sType + void* pNext + VkBool32 descriptorSetHostMapping + + + VkStructureType sType + const void* pNext + VkDescriptorSetLayout descriptorSetLayout + uint32_t binding + + + VkStructureType sType + void* pNext + size_t descriptorOffset + uint32_t descriptorSize + + + VkStructureType sType + void* pNext + VkBool32 shaderModuleIdentifier + + + VkStructureType sType + void* pNext + uint8_t shaderModuleIdentifierAlgorithmUUID[VK_UUID_SIZE] + + + VkStructureType sType + const void* pNext + uint32_t identifierSize + const uint8_t* pIdentifier + + + VkStructureType sType + void* pNext + uint32_t identifierSize + uint8_t identifier[VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT] + + + VkStructureType sType + const void* pNext + VkImageCompressionFlagsEXT flags + uint32_t compressionControlPlaneCount + VkImageCompressionFixedRateFlagsEXT* pFixedRateFlags + + + VkStructureType sType + void* pNext + VkBool32 imageCompressionControl + + + VkStructureType sType + void* pNext + VkImageCompressionFlagsEXT imageCompressionFlags + VkImageCompressionFixedRateFlagsEXT imageCompressionFixedRateFlags + + + VkStructureType sType + void* pNext + VkBool32 imageCompressionControlSwapchain + + + VkStructureType sType + void* pNext + VkImageSubresource imageSubresource + + + VkStructureType sType + void* pNext + VkSubresourceLayout subresourceLayout + + + VkStructureType sType + const void* pNext + VkBool32 disallowMerging + + + uint32_t postMergeSubpassCount + + + VkStructureType sType + const void* pNext + VkRenderPassCreationFeedbackInfoEXT* pRenderPassFeedback + + + VkSubpassMergeStatusEXT subpassMergeStatus + char description[VK_MAX_DESCRIPTION_SIZE] + uint32_t postMergeIndex + + + VkStructureType sType + const void* pNext + VkRenderPassSubpassFeedbackInfoEXT* pSubpassFeedback + + + VkStructureType sType + void* pNext + VkBool32 subpassMergeFeedback + + + VkStructureType sType + const void* pNext + VkMicromapTypeEXT type + VkBuildMicromapFlagsEXT flags + VkBuildMicromapModeEXT mode + VkMicromapEXT dstMicromap + uint32_t usageCountsCount + const VkMicromapUsageEXT* pUsageCounts + const VkMicromapUsageEXT* const* ppUsageCounts + VkDeviceOrHostAddressConstKHR data + VkDeviceOrHostAddressKHR scratchData + VkDeviceOrHostAddressConstKHR triangleArray + VkDeviceSize triangleArrayStride + + + VkStructureType sType + const void* pNext + VkMicromapCreateFlagsEXT createFlags + VkBuffer buffer + VkDeviceSize offsetSpecified in bytes + VkDeviceSize size + VkMicromapTypeEXT type + VkDeviceAddress deviceAddress + + + VkStructureType sType + const void* pNext + const uint8_t* pVersionData + + + VkStructureType sType + const void* pNext + VkMicromapEXT src + VkMicromapEXT dst + VkCopyMicromapModeEXT mode + + + VkStructureType sType + const void* pNext + VkMicromapEXT src + VkDeviceOrHostAddressKHR dst + VkCopyMicromapModeEXT mode + + + VkStructureType sType + const void* pNext + VkDeviceOrHostAddressConstKHR src + VkMicromapEXT dst + VkCopyMicromapModeEXT mode + + + VkStructureType sType + const void* pNext + VkDeviceSize micromapSize + VkDeviceSize buildScratchSize + VkBool32 discardable + + + uint32_t count + uint32_t subdivisionLevel + uint32_t formatInterpretation depends on parent type + + + uint32_t dataOffsetSpecified in bytes + uint16_t subdivisionLevel + uint16_t format + + + VkStructureType sType + void* pNext + VkBool32 micromap + VkBool32 micromapCaptureReplay + VkBool32 micromapHostCommands + + + VkStructureType sType + void* pNext + uint32_t maxOpacity2StateSubdivisionLevel + uint32_t maxOpacity4StateSubdivisionLevel + + + VkStructureType sType + void* pNext + VkIndexType indexType + VkDeviceOrHostAddressConstKHR indexBuffer + VkDeviceSize indexStride + uint32_t baseTriangle + uint32_t usageCountsCount + const VkMicromapUsageEXT* pUsageCounts + const VkMicromapUsageEXT* const* ppUsageCounts + VkMicromapEXT micromap + + + VkStructureType sType + void* pNext + uint8_t pipelineIdentifier[VK_UUID_SIZE] + + + VkStructureType sType + void* pNext + VkBool32 pipelinePropertiesIdentifier + + + VkStructureType sType + void* pNext + VkBool32 shaderEarlyAndLateFragmentTests + + + VkStructureType sType + const void* pNext + VkExportMetalObjectTypeFlagBitsEXT exportObjectType + + + VkStructureType sType + const void* pNext + + + VkStructureType sType + const void* pNext + MTLDevice_id mtlDevice + + + VkStructureType sType + const void* pNext + VkQueue queue + MTLCommandQueue_id mtlCommandQueue + + + VkStructureType sType + const void* pNext + VkDeviceMemory memory + MTLBuffer_id mtlBuffer + + + VkStructureType sType + const void* pNext + MTLBuffer_id mtlBuffer + + + VkStructureType sType + const void* pNext + VkImage image + VkImageView imageView + VkBufferView bufferView + VkImageAspectFlagBits plane + MTLTexture_id mtlTexture + + + VkStructureType sType + const void* pNext + VkImageAspectFlagBits plane + MTLTexture_id mtlTexture + + + VkStructureType sType + const void* pNext + VkImage image + IOSurfaceRef ioSurface + + + VkStructureType sType + const void* pNext + IOSurfaceRef ioSurface + + + VkStructureType sType + const void* pNext + VkSemaphore semaphore + VkEvent event + MTLSharedEvent_id mtlSharedEvent + + + VkStructureType sType + const void* pNext + MTLSharedEvent_id mtlSharedEvent + + + VkStructureType sType + void* pNext + VkBool32 nonSeamlessCubeMap + + + VkStructureType sType + void* pNext + VkBool32 pipelineRobustness + + + VkStructureType sType + const void* pNext + VkPipelineRobustnessBufferBehaviorEXT storageBuffers + VkPipelineRobustnessBufferBehaviorEXT uniformBuffers + VkPipelineRobustnessBufferBehaviorEXT vertexInputs + VkPipelineRobustnessImageBehaviorEXT images + + + VkStructureType sType + void* pNext + VkPipelineRobustnessBufferBehaviorEXT defaultRobustnessStorageBuffers + VkPipelineRobustnessBufferBehaviorEXT defaultRobustnessUniformBuffers + VkPipelineRobustnessBufferBehaviorEXT defaultRobustnessVertexInputs + VkPipelineRobustnessImageBehaviorEXT defaultRobustnessImages + + + VkStructureType sType + const void* pNext + VkOffset2D filterCenter + VkExtent2D filterSize + uint32_t numPhases + + + VkStructureType sType + void* pNext + VkBool32 textureSampleWeighted + VkBool32 textureBoxFilter + VkBool32 textureBlockMatch + + + VkStructureType sType + void* pNext + uint32_t maxWeightFilterPhases + VkExtent2D maxWeightFilterDimension + VkExtent2D maxBlockMatchRegion + VkExtent2D maxBoxFilterBlockSize + + + VkStructureType sType + void* pNext + VkBool32 tileProperties + + + VkStructureType sType + void* pNext + VkExtent3D tileSize + VkExtent2D apronSize + VkOffset2D origin + + + VkStructureType sType + void* pNext + VkBool32 amigoProfiling + + + VkStructureType sType + const void* pNext + uint64_t firstDrawTimestamp + uint64_t swapBufferTimestamp + + + VkStructureType sType + void* pNext + VkBool32 attachmentFeedbackLoopLayout + + + VkStructureType sType + void* pNext + VkBool32 depthClampZeroOne + + + VkStructureType sType + void* pNext + VkBool32 reportAddressBinding + + + VkStructureType sType + void* pNext + VkDeviceAddressBindingFlagsEXT flags + VkDeviceAddress baseAddress + VkDeviceSize size + VkDeviceAddressBindingTypeEXT bindingType + + + VkStructureType sType + void* pNext + VkBool32 opticalFlow + + + VkStructureType sType + void* pNext + VkOpticalFlowGridSizeFlagsNV supportedOutputGridSizes + VkOpticalFlowGridSizeFlagsNV supportedHintGridSizes + VkBool32 hintSupported + VkBool32 costSupported + VkBool32 bidirectionalFlowSupported + VkBool32 globalFlowSupported + uint32_t minWidth + uint32_t minHeight + uint32_t maxWidth + uint32_t maxHeight + uint32_t maxNumRegionsOfInterest + + + VkStructureType sType + const void* pNext + VkOpticalFlowUsageFlagsNV usage + + + VkStructureType sType + const void* pNext + VkFormat format + + + VkStructureType sType + void* pNext + uint32_t width + uint32_t height + VkFormat imageFormat + VkFormat flowVectorFormat + VkFormat costFormat + VkOpticalFlowGridSizeFlagsNV outputGridSize + VkOpticalFlowGridSizeFlagsNV hintGridSize + VkOpticalFlowPerformanceLevelNV performanceLevel + VkOpticalFlowSessionCreateFlagsNV flags + + NV internal use only + VkStructureType sType + void* pNext + uint32_t id + uint32_t size + const void* pPrivateData + + + VkStructureType sType + void* pNext + VkOpticalFlowExecuteFlagsNV flags + uint32_t regionCount + const VkRect2D* pRegions + + + VkStructureType sType + void* pNext + VkBool32 deviceFault + VkBool32 deviceFaultVendorBinary + + + VkDeviceFaultAddressTypeEXT addressType + VkDeviceAddress reportedAddress + VkDeviceSize addressPrecision + + + char description[VK_MAX_DESCRIPTION_SIZE]Free-form description of the fault + uint64_t vendorFaultCode + uint64_t vendorFaultData + + + VkStructureType sType + void* pNext + uint32_t addressInfoCount + uint32_t vendorInfoCount + VkDeviceSize vendorBinarySizeSpecified in bytes + + + VkStructureType sType + void* pNext + char description[VK_MAX_DESCRIPTION_SIZE]Free-form description of the fault + VkDeviceFaultAddressInfoEXT* pAddressInfos + VkDeviceFaultVendorInfoEXT* pVendorInfos + void* pVendorBinaryData + + + The fields in this structure are non-normative since structure packing is implementation-defined in C. The specification defines the normative layout. + uint32_t headerSize + VkDeviceFaultVendorBinaryHeaderVersionEXT headerVersion + uint32_t vendorID + uint32_t deviceID + uint32_t driverVersion + uint8_t pipelineCacheUUID[VK_UUID_SIZE] + uint32_t applicationNameOffset + uint32_t applicationVersion + uint32_t engineNameOffset + + + VkDeviceAddress srcAddress + VkDeviceAddress dstAddress + VkDeviceSize compressedSizeSpecified in bytes + VkDeviceSize decompressedSizeSpecified in bytes + VkMemoryDecompressionMethodFlagsNV decompressionMethod + + + VkStructureType sType + void* pNext + uint64_t shaderCoreMask + uint32_t shaderCoreCount + uint32_t shaderWarpsPerCore + + + VkStructureType sType + void* pNext + VkBool32 shaderCoreBuiltins + + + VkStructureType sType + void* pNext + VkBool32 rayTracingInvocationReorder + + + VkStructureType sType + void* pNext + VkRayTracingInvocationReorderModeNV rayTracingInvocationReorderReorderingHint + + + + + Vulkan enumerant (token) definitions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unlike OpenGL, most tokens in Vulkan are actual typed enumerants in + their own numeric namespaces. The "name" attribute is the C enum + type name, and is pulled in from a type tag definition above + (slightly clunky, but retains the type / enum distinction). "type" + attributes of "enum" or "bitmask" indicate that these values should + be generated inside an appropriate definition. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + value="4" reserved for VK_KHR_sampler_mirror_clamp_to_edge + enum VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; do not + alias! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Return codes (positive values) + + + + + + + Error codes (negative values) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Flags + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WSI Extensions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NVX_device_generated_commands formerly used these enum values, but that extension has been removed + value 31 / name VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT + value 32 / name VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Vendor IDs are now represented as enums instead of the old + <vendorids> tag, allowing them to be included in the + API headers. + + + + + + + + + + Driver IDs are now represented as enums instead of the old + <driverids> tag, allowing them to be included in the + API headers. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bitpos 17-31 are specified by extensions to the original VkAccessFlagBits enum + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bitpos 17-31 are specified by extensions to the original VkPipelineStageFlagBits enum + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VkResult vkCreateInstance + const VkInstanceCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkInstance* pInstance + + + void vkDestroyInstance + VkInstance instance + const VkAllocationCallbacks* pAllocator + + all sname:VkPhysicalDevice objects enumerated from pname:instance + + + + VkResult vkEnumeratePhysicalDevices + VkInstance instance + uint32_t* pPhysicalDeviceCount + VkPhysicalDevice* pPhysicalDevices + + + PFN_vkVoidFunction vkGetDeviceProcAddr + VkDevice device + const char* pName + + + PFN_vkVoidFunction vkGetInstanceProcAddr + VkInstance instance + const char* pName + + + void vkGetPhysicalDeviceProperties + VkPhysicalDevice physicalDevice + VkPhysicalDeviceProperties* pProperties + + + void vkGetPhysicalDeviceQueueFamilyProperties + VkPhysicalDevice physicalDevice + uint32_t* pQueueFamilyPropertyCount + VkQueueFamilyProperties* pQueueFamilyProperties + + + void vkGetPhysicalDeviceMemoryProperties + VkPhysicalDevice physicalDevice + VkPhysicalDeviceMemoryProperties* pMemoryProperties + + + void vkGetPhysicalDeviceFeatures + VkPhysicalDevice physicalDevice + VkPhysicalDeviceFeatures* pFeatures + + + void vkGetPhysicalDeviceFormatProperties + VkPhysicalDevice physicalDevice + VkFormat format + VkFormatProperties* pFormatProperties + + + VkResult vkGetPhysicalDeviceImageFormatProperties + VkPhysicalDevice physicalDevice + VkFormat format + VkImageType type + VkImageTiling tiling + VkImageUsageFlags usage + VkImageCreateFlags flags + VkImageFormatProperties* pImageFormatProperties + + + VkResult vkCreateDevice + VkPhysicalDevice physicalDevice + const VkDeviceCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkDevice* pDevice + + + void vkDestroyDevice + VkDevice device + const VkAllocationCallbacks* pAllocator + + all sname:VkQueue objects created from pname:device + + + + VkResult vkEnumerateInstanceVersion + uint32_t* pApiVersion + + + VkResult vkEnumerateInstanceLayerProperties + uint32_t* pPropertyCount + VkLayerProperties* pProperties + + + VkResult vkEnumerateInstanceExtensionProperties + const char* pLayerName + uint32_t* pPropertyCount + VkExtensionProperties* pProperties + + + VkResult vkEnumerateDeviceLayerProperties + VkPhysicalDevice physicalDevice + uint32_t* pPropertyCount + VkLayerProperties* pProperties + + + VkResult vkEnumerateDeviceExtensionProperties + VkPhysicalDevice physicalDevice + const char* pLayerName + uint32_t* pPropertyCount + VkExtensionProperties* pProperties + + + void vkGetDeviceQueue + VkDevice device + uint32_t queueFamilyIndex + uint32_t queueIndex + VkQueue* pQueue + + + VkResult vkQueueSubmit + VkQueue queue + uint32_t submitCount + const VkSubmitInfo* pSubmits + VkFence fence + + + VkResult vkQueueWaitIdle + VkQueue queue + + + VkResult vkDeviceWaitIdle + VkDevice device + + all sname:VkQueue objects created from pname:device + + + + VkResult vkAllocateMemory + VkDevice device + const VkMemoryAllocateInfo* pAllocateInfo + const VkAllocationCallbacks* pAllocator + VkDeviceMemory* pMemory + + + void vkFreeMemory + VkDevice device + VkDeviceMemory memory + const VkAllocationCallbacks* pAllocator + + + VkResult vkMapMemory + VkDevice device + VkDeviceMemory memory + VkDeviceSize offset + VkDeviceSize size + VkMemoryMapFlags flags + void** ppData + + + void vkUnmapMemory + VkDevice device + VkDeviceMemory memory + + + VkResult vkFlushMappedMemoryRanges + VkDevice device + uint32_t memoryRangeCount + const VkMappedMemoryRange* pMemoryRanges + + + VkResult vkInvalidateMappedMemoryRanges + VkDevice device + uint32_t memoryRangeCount + const VkMappedMemoryRange* pMemoryRanges + + + void vkGetDeviceMemoryCommitment + VkDevice device + VkDeviceMemory memory + VkDeviceSize* pCommittedMemoryInBytes + + + void vkGetBufferMemoryRequirements + VkDevice device + VkBuffer buffer + VkMemoryRequirements* pMemoryRequirements + + + VkResult vkBindBufferMemory + VkDevice device + VkBuffer buffer + VkDeviceMemory memory + VkDeviceSize memoryOffset + + + void vkGetImageMemoryRequirements + VkDevice device + VkImage image + VkMemoryRequirements* pMemoryRequirements + + + VkResult vkBindImageMemory + VkDevice device + VkImage image + VkDeviceMemory memory + VkDeviceSize memoryOffset + + + void vkGetImageSparseMemoryRequirements + VkDevice device + VkImage image + uint32_t* pSparseMemoryRequirementCount + VkSparseImageMemoryRequirements* pSparseMemoryRequirements + + + void vkGetPhysicalDeviceSparseImageFormatProperties + VkPhysicalDevice physicalDevice + VkFormat format + VkImageType type + VkSampleCountFlagBits samples + VkImageUsageFlags usage + VkImageTiling tiling + uint32_t* pPropertyCount + VkSparseImageFormatProperties* pProperties + + + VkResult vkQueueBindSparse + VkQueue queue + uint32_t bindInfoCount + const VkBindSparseInfo* pBindInfo + VkFence fence + + + VkResult vkCreateFence + VkDevice device + const VkFenceCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkFence* pFence + + + void vkDestroyFence + VkDevice device + VkFence fence + const VkAllocationCallbacks* pAllocator + + + VkResult vkResetFences + VkDevice device + uint32_t fenceCount + const VkFence* pFences + + + VkResult vkGetFenceStatus + VkDevice device + VkFence fence + + + VkResult vkWaitForFences + VkDevice device + uint32_t fenceCount + const VkFence* pFences + VkBool32 waitAll + uint64_t timeout + + + VkResult vkCreateSemaphore + VkDevice device + const VkSemaphoreCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSemaphore* pSemaphore + + + void vkDestroySemaphore + VkDevice device + VkSemaphore semaphore + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateEvent + VkDevice device + const VkEventCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkEvent* pEvent + + + void vkDestroyEvent + VkDevice device + VkEvent event + const VkAllocationCallbacks* pAllocator + + + VkResult vkGetEventStatus + VkDevice device + VkEvent event + + + VkResult vkSetEvent + VkDevice device + VkEvent event + + + VkResult vkResetEvent + VkDevice device + VkEvent event + + + VkResult vkCreateQueryPool + VkDevice device + const VkQueryPoolCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkQueryPool* pQueryPool + + + void vkDestroyQueryPool + VkDevice device + VkQueryPool queryPool + const VkAllocationCallbacks* pAllocator + + + VkResult vkGetQueryPoolResults + VkDevice device + VkQueryPool queryPool + uint32_t firstQuery + uint32_t queryCount + size_t dataSize + void* pData + VkDeviceSize stride + VkQueryResultFlags flags + + + void vkResetQueryPool + VkDevice device + VkQueryPool queryPool + uint32_t firstQuery + uint32_t queryCount + + + + VkResult vkCreateBuffer + VkDevice device + const VkBufferCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkBuffer* pBuffer + + + void vkDestroyBuffer + VkDevice device + VkBuffer buffer + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateBufferView + VkDevice device + const VkBufferViewCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkBufferView* pView + + + void vkDestroyBufferView + VkDevice device + VkBufferView bufferView + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateImage + VkDevice device + const VkImageCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkImage* pImage + + + void vkDestroyImage + VkDevice device + VkImage image + const VkAllocationCallbacks* pAllocator + + + void vkGetImageSubresourceLayout + VkDevice device + VkImage image + const VkImageSubresource* pSubresource + VkSubresourceLayout* pLayout + + + VkResult vkCreateImageView + VkDevice device + const VkImageViewCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkImageView* pView + + + void vkDestroyImageView + VkDevice device + VkImageView imageView + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateShaderModule + VkDevice device + const VkShaderModuleCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkShaderModule* pShaderModule + + + void vkDestroyShaderModule + VkDevice device + VkShaderModule shaderModule + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreatePipelineCache + VkDevice device + const VkPipelineCacheCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkPipelineCache* pPipelineCache + + + void vkDestroyPipelineCache + VkDevice device + VkPipelineCache pipelineCache + const VkAllocationCallbacks* pAllocator + + + VkResult vkGetPipelineCacheData + VkDevice device + VkPipelineCache pipelineCache + size_t* pDataSize + void* pData + + + VkResult vkMergePipelineCaches + VkDevice device + VkPipelineCache dstCache + uint32_t srcCacheCount + const VkPipelineCache* pSrcCaches + + + VkResult vkCreateGraphicsPipelines + VkDevice device + VkPipelineCache pipelineCache + uint32_t createInfoCount + const VkGraphicsPipelineCreateInfo* pCreateInfos + const VkAllocationCallbacks* pAllocator + VkPipeline* pPipelines + + + VkResult vkCreateComputePipelines + VkDevice device + VkPipelineCache pipelineCache + uint32_t createInfoCount + const VkComputePipelineCreateInfo* pCreateInfos + const VkAllocationCallbacks* pAllocator + VkPipeline* pPipelines + + + VkResult vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI + VkDevice device + VkRenderPass renderpass + VkExtent2D* pMaxWorkgroupSize + + + void vkDestroyPipeline + VkDevice device + VkPipeline pipeline + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreatePipelineLayout + VkDevice device + const VkPipelineLayoutCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkPipelineLayout* pPipelineLayout + + + void vkDestroyPipelineLayout + VkDevice device + VkPipelineLayout pipelineLayout + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateSampler + VkDevice device + const VkSamplerCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSampler* pSampler + + + void vkDestroySampler + VkDevice device + VkSampler sampler + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateDescriptorSetLayout + VkDevice device + const VkDescriptorSetLayoutCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkDescriptorSetLayout* pSetLayout + + + void vkDestroyDescriptorSetLayout + VkDevice device + VkDescriptorSetLayout descriptorSetLayout + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateDescriptorPool + VkDevice device + const VkDescriptorPoolCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkDescriptorPool* pDescriptorPool + + + void vkDestroyDescriptorPool + VkDevice device + VkDescriptorPool descriptorPool + const VkAllocationCallbacks* pAllocator + + + VkResult vkResetDescriptorPool + VkDevice device + VkDescriptorPool descriptorPool + VkDescriptorPoolResetFlags flags + + any sname:VkDescriptorSet objects allocated from pname:descriptorPool + + + + VkResult vkAllocateDescriptorSets + VkDevice device + const VkDescriptorSetAllocateInfo* pAllocateInfo + VkDescriptorSet* pDescriptorSets + + + VkResult vkFreeDescriptorSets + VkDevice device + VkDescriptorPool descriptorPool + uint32_t descriptorSetCount + const VkDescriptorSet* pDescriptorSets + + + void vkUpdateDescriptorSets + VkDevice device + uint32_t descriptorWriteCount + const VkWriteDescriptorSet* pDescriptorWrites + uint32_t descriptorCopyCount + const VkCopyDescriptorSet* pDescriptorCopies + + + VkResult vkCreateFramebuffer + VkDevice device + const VkFramebufferCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkFramebuffer* pFramebuffer + + + void vkDestroyFramebuffer + VkDevice device + VkFramebuffer framebuffer + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateRenderPass + VkDevice device + const VkRenderPassCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkRenderPass* pRenderPass + + + void vkDestroyRenderPass + VkDevice device + VkRenderPass renderPass + const VkAllocationCallbacks* pAllocator + + + void vkGetRenderAreaGranularity + VkDevice device + VkRenderPass renderPass + VkExtent2D* pGranularity + + + VkResult vkCreateCommandPool + VkDevice device + const VkCommandPoolCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkCommandPool* pCommandPool + + + void vkDestroyCommandPool + VkDevice device + VkCommandPool commandPool + const VkAllocationCallbacks* pAllocator + + + VkResult vkResetCommandPool + VkDevice device + VkCommandPool commandPool + VkCommandPoolResetFlags flags + + + VkResult vkAllocateCommandBuffers + VkDevice device + const VkCommandBufferAllocateInfo* pAllocateInfo + VkCommandBuffer* pCommandBuffers + + + void vkFreeCommandBuffers + VkDevice device + VkCommandPool commandPool + uint32_t commandBufferCount + const VkCommandBuffer* pCommandBuffers + + + VkResult vkBeginCommandBuffer + VkCommandBuffer commandBuffer + const VkCommandBufferBeginInfo* pBeginInfo + + the sname:VkCommandPool that pname:commandBuffer was allocated from + + + + VkResult vkEndCommandBuffer + VkCommandBuffer commandBuffer + + the sname:VkCommandPool that pname:commandBuffer was allocated from + + + + VkResult vkResetCommandBuffer + VkCommandBuffer commandBuffer + VkCommandBufferResetFlags flags + + the sname:VkCommandPool that pname:commandBuffer was allocated from + + + + void vkCmdBindPipeline + VkCommandBuffer commandBuffer + VkPipelineBindPoint pipelineBindPoint + VkPipeline pipeline + + + void vkCmdSetViewport + VkCommandBuffer commandBuffer + uint32_t firstViewport + uint32_t viewportCount + const VkViewport* pViewports + + + void vkCmdSetScissor + VkCommandBuffer commandBuffer + uint32_t firstScissor + uint32_t scissorCount + const VkRect2D* pScissors + + + void vkCmdSetLineWidth + VkCommandBuffer commandBuffer + float lineWidth + + + void vkCmdSetDepthBias + VkCommandBuffer commandBuffer + float depthBiasConstantFactor + float depthBiasClamp + float depthBiasSlopeFactor + + + void vkCmdSetBlendConstants + VkCommandBuffer commandBuffer + const float blendConstants[4] + + + void vkCmdSetDepthBounds + VkCommandBuffer commandBuffer + float minDepthBounds + float maxDepthBounds + + + void vkCmdSetStencilCompareMask + VkCommandBuffer commandBuffer + VkStencilFaceFlags faceMask + uint32_t compareMask + + + void vkCmdSetStencilWriteMask + VkCommandBuffer commandBuffer + VkStencilFaceFlags faceMask + uint32_t writeMask + + + void vkCmdSetStencilReference + VkCommandBuffer commandBuffer + VkStencilFaceFlags faceMask + uint32_t reference + + + void vkCmdBindDescriptorSets + VkCommandBuffer commandBuffer + VkPipelineBindPoint pipelineBindPoint + VkPipelineLayout layout + uint32_t firstSet + uint32_t descriptorSetCount + const VkDescriptorSet* pDescriptorSets + uint32_t dynamicOffsetCount + const uint32_t* pDynamicOffsets + + + void vkCmdBindIndexBuffer + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + VkIndexType indexType + + + void vkCmdBindVertexBuffers + VkCommandBuffer commandBuffer + uint32_t firstBinding + uint32_t bindingCount + const VkBuffer* pBuffers + const VkDeviceSize* pOffsets + + + void vkCmdDraw + VkCommandBuffer commandBuffer + uint32_t vertexCount + uint32_t instanceCount + uint32_t firstVertex + uint32_t firstInstance + + + void vkCmdDrawIndexed + VkCommandBuffer commandBuffer + uint32_t indexCount + uint32_t instanceCount + uint32_t firstIndex + int32_t vertexOffset + uint32_t firstInstance + + + void vkCmdDrawMultiEXT + VkCommandBuffer commandBuffer + uint32_t drawCount + const VkMultiDrawInfoEXT* pVertexInfo + uint32_t instanceCount + uint32_t firstInstance + uint32_t stride + + + void vkCmdDrawMultiIndexedEXT + VkCommandBuffer commandBuffer + uint32_t drawCount + const VkMultiDrawIndexedInfoEXT* pIndexInfo + uint32_t instanceCount + uint32_t firstInstance + uint32_t stride + const int32_t* pVertexOffset + + + void vkCmdDrawIndirect + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + uint32_t drawCount + uint32_t stride + + + void vkCmdDrawIndexedIndirect + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + uint32_t drawCount + uint32_t stride + + + void vkCmdDispatch + VkCommandBuffer commandBuffer + uint32_t groupCountX + uint32_t groupCountY + uint32_t groupCountZ + + + void vkCmdDispatchIndirect + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + + + void vkCmdSubpassShadingHUAWEI + VkCommandBuffer commandBuffer + + + void vkCmdCopyBuffer + VkCommandBuffer commandBuffer + VkBuffer srcBuffer + VkBuffer dstBuffer + uint32_t regionCount + const VkBufferCopy* pRegions + + + void vkCmdCopyImage + VkCommandBuffer commandBuffer + VkImage srcImage + VkImageLayout srcImageLayout + VkImage dstImage + VkImageLayout dstImageLayout + uint32_t regionCount + const VkImageCopy* pRegions + + + void vkCmdBlitImage + VkCommandBuffer commandBuffer + VkImage srcImage + VkImageLayout srcImageLayout + VkImage dstImage + VkImageLayout dstImageLayout + uint32_t regionCount + const VkImageBlit* pRegions + VkFilter filter + + + void vkCmdCopyBufferToImage + VkCommandBuffer commandBuffer + VkBuffer srcBuffer + VkImage dstImage + VkImageLayout dstImageLayout + uint32_t regionCount + const VkBufferImageCopy* pRegions + + + void vkCmdCopyImageToBuffer + VkCommandBuffer commandBuffer + VkImage srcImage + VkImageLayout srcImageLayout + VkBuffer dstBuffer + uint32_t regionCount + const VkBufferImageCopy* pRegions + + + void vkCmdCopyMemoryIndirectNV + VkCommandBuffer commandBuffer + VkDeviceAddress copyBufferAddress + uint32_t copyCount + uint32_t stride + + + void vkCmdCopyMemoryToImageIndirectNV + VkCommandBuffer commandBuffer + VkDeviceAddress copyBufferAddress + uint32_t copyCount + uint32_t stride + VkImage dstImage + VkImageLayout dstImageLayout + const VkImageSubresourceLayers* pImageSubresources + + + void vkCmdUpdateBuffer + VkCommandBuffer commandBuffer + VkBuffer dstBuffer + VkDeviceSize dstOffset + VkDeviceSize dataSize + const void* pData + + + void vkCmdFillBuffer + VkCommandBuffer commandBuffer + VkBuffer dstBuffer + VkDeviceSize dstOffset + VkDeviceSize size + uint32_t data + + + void vkCmdClearColorImage + VkCommandBuffer commandBuffer + VkImage image + VkImageLayout imageLayout + const VkClearColorValue* pColor + uint32_t rangeCount + const VkImageSubresourceRange* pRanges + + + void vkCmdClearDepthStencilImage + VkCommandBuffer commandBuffer + VkImage image + VkImageLayout imageLayout + const VkClearDepthStencilValue* pDepthStencil + uint32_t rangeCount + const VkImageSubresourceRange* pRanges + + + void vkCmdClearAttachments + VkCommandBuffer commandBuffer + uint32_t attachmentCount + const VkClearAttachment* pAttachments + uint32_t rectCount + const VkClearRect* pRects + + + void vkCmdResolveImage + VkCommandBuffer commandBuffer + VkImage srcImage + VkImageLayout srcImageLayout + VkImage dstImage + VkImageLayout dstImageLayout + uint32_t regionCount + const VkImageResolve* pRegions + + + void vkCmdSetEvent + VkCommandBuffer commandBuffer + VkEvent event + VkPipelineStageFlags stageMask + + + void vkCmdResetEvent + VkCommandBuffer commandBuffer + VkEvent event + VkPipelineStageFlags stageMask + + + void vkCmdWaitEvents + VkCommandBuffer commandBuffer + uint32_t eventCount + const VkEvent* pEvents + VkPipelineStageFlags srcStageMask + VkPipelineStageFlags dstStageMask + uint32_t memoryBarrierCount + const VkMemoryBarrier* pMemoryBarriers + uint32_t bufferMemoryBarrierCount + const VkBufferMemoryBarrier* pBufferMemoryBarriers + uint32_t imageMemoryBarrierCount + const VkImageMemoryBarrier* pImageMemoryBarriers + + + void vkCmdPipelineBarrier + VkCommandBuffer commandBuffer + VkPipelineStageFlags srcStageMask + VkPipelineStageFlags dstStageMask + VkDependencyFlags dependencyFlags + uint32_t memoryBarrierCount + const VkMemoryBarrier* pMemoryBarriers + uint32_t bufferMemoryBarrierCount + const VkBufferMemoryBarrier* pBufferMemoryBarriers + uint32_t imageMemoryBarrierCount + const VkImageMemoryBarrier* pImageMemoryBarriers + + + void vkCmdBeginQuery + VkCommandBuffer commandBuffer + VkQueryPool queryPool + uint32_t query + VkQueryControlFlags flags + + + void vkCmdEndQuery + VkCommandBuffer commandBuffer + VkQueryPool queryPool + uint32_t query + + + void vkCmdBeginConditionalRenderingEXT + VkCommandBuffer commandBuffer + const VkConditionalRenderingBeginInfoEXT* pConditionalRenderingBegin + + + void vkCmdEndConditionalRenderingEXT + VkCommandBuffer commandBuffer + + + void vkCmdResetQueryPool + VkCommandBuffer commandBuffer + VkQueryPool queryPool + uint32_t firstQuery + uint32_t queryCount + + + void vkCmdWriteTimestamp + VkCommandBuffer commandBuffer + VkPipelineStageFlagBits pipelineStage + VkQueryPool queryPool + uint32_t query + + + void vkCmdCopyQueryPoolResults + VkCommandBuffer commandBuffer + VkQueryPool queryPool + uint32_t firstQuery + uint32_t queryCount + VkBuffer dstBuffer + VkDeviceSize dstOffset + VkDeviceSize stride + VkQueryResultFlags flags + + + void vkCmdPushConstants + VkCommandBuffer commandBuffer + VkPipelineLayout layout + VkShaderStageFlags stageFlags + uint32_t offset + uint32_t size + const void* pValues + + + void vkCmdBeginRenderPass + VkCommandBuffer commandBuffer + const VkRenderPassBeginInfo* pRenderPassBegin + VkSubpassContents contents + + + void vkCmdNextSubpass + VkCommandBuffer commandBuffer + VkSubpassContents contents + + + void vkCmdEndRenderPass + VkCommandBuffer commandBuffer + + + void vkCmdExecuteCommands + VkCommandBuffer commandBuffer + uint32_t commandBufferCount + const VkCommandBuffer* pCommandBuffers + + + VkResult vkCreateAndroidSurfaceKHR + VkInstance instance + const VkAndroidSurfaceCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkResult vkGetPhysicalDeviceDisplayPropertiesKHR + VkPhysicalDevice physicalDevice + uint32_t* pPropertyCount + VkDisplayPropertiesKHR* pProperties + + + VkResult vkGetPhysicalDeviceDisplayPlanePropertiesKHR + VkPhysicalDevice physicalDevice + uint32_t* pPropertyCount + VkDisplayPlanePropertiesKHR* pProperties + + + VkResult vkGetDisplayPlaneSupportedDisplaysKHR + VkPhysicalDevice physicalDevice + uint32_t planeIndex + uint32_t* pDisplayCount + VkDisplayKHR* pDisplays + + + VkResult vkGetDisplayModePropertiesKHR + VkPhysicalDevice physicalDevice + VkDisplayKHR display + uint32_t* pPropertyCount + VkDisplayModePropertiesKHR* pProperties + + + VkResult vkCreateDisplayModeKHR + VkPhysicalDevice physicalDevice + VkDisplayKHR display + const VkDisplayModeCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkDisplayModeKHR* pMode + + + VkResult vkGetDisplayPlaneCapabilitiesKHR + VkPhysicalDevice physicalDevice + VkDisplayModeKHR mode + uint32_t planeIndex + VkDisplayPlaneCapabilitiesKHR* pCapabilities + + + VkResult vkCreateDisplayPlaneSurfaceKHR + VkInstance instance + const VkDisplaySurfaceCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkResult vkCreateSharedSwapchainsKHR + VkDevice device + uint32_t swapchainCount + const VkSwapchainCreateInfoKHR* pCreateInfos + const VkAllocationCallbacks* pAllocator + VkSwapchainKHR* pSwapchains + + + void vkDestroySurfaceKHR + VkInstance instance + VkSurfaceKHR surface + const VkAllocationCallbacks* pAllocator + + + VkResult vkGetPhysicalDeviceSurfaceSupportKHR + VkPhysicalDevice physicalDevice + uint32_t queueFamilyIndex + VkSurfaceKHR surface + VkBool32* pSupported + + + VkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR + VkPhysicalDevice physicalDevice + VkSurfaceKHR surface + VkSurfaceCapabilitiesKHR* pSurfaceCapabilities + + + VkResult vkGetPhysicalDeviceSurfaceFormatsKHR + VkPhysicalDevice physicalDevice + VkSurfaceKHR surface + uint32_t* pSurfaceFormatCount + VkSurfaceFormatKHR* pSurfaceFormats + + + VkResult vkGetPhysicalDeviceSurfacePresentModesKHR + VkPhysicalDevice physicalDevice + VkSurfaceKHR surface + uint32_t* pPresentModeCount + VkPresentModeKHR* pPresentModes + + + VkResult vkCreateSwapchainKHR + VkDevice device + const VkSwapchainCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSwapchainKHR* pSwapchain + + + void vkDestroySwapchainKHR + VkDevice device + VkSwapchainKHR swapchain + const VkAllocationCallbacks* pAllocator + + + VkResult vkGetSwapchainImagesKHR + VkDevice device + VkSwapchainKHR swapchain + uint32_t* pSwapchainImageCount + VkImage* pSwapchainImages + + + VkResult vkAcquireNextImageKHR + VkDevice device + VkSwapchainKHR swapchain + uint64_t timeout + VkSemaphore semaphore + VkFence fence + uint32_t* pImageIndex + + + VkResult vkQueuePresentKHR + VkQueue queue + const VkPresentInfoKHR* pPresentInfo + + + VkResult vkCreateViSurfaceNN + VkInstance instance + const VkViSurfaceCreateInfoNN* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkResult vkCreateWaylandSurfaceKHR + VkInstance instance + const VkWaylandSurfaceCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkBool32 vkGetPhysicalDeviceWaylandPresentationSupportKHR + VkPhysicalDevice physicalDevice + uint32_t queueFamilyIndex + struct wl_display* display + + + VkResult vkCreateWin32SurfaceKHR + VkInstance instance + const VkWin32SurfaceCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkBool32 vkGetPhysicalDeviceWin32PresentationSupportKHR + VkPhysicalDevice physicalDevice + uint32_t queueFamilyIndex + + + VkResult vkCreateXlibSurfaceKHR + VkInstance instance + const VkXlibSurfaceCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkBool32 vkGetPhysicalDeviceXlibPresentationSupportKHR + VkPhysicalDevice physicalDevice + uint32_t queueFamilyIndex + Display* dpy + VisualID visualID + + + VkResult vkCreateXcbSurfaceKHR + VkInstance instance + const VkXcbSurfaceCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkBool32 vkGetPhysicalDeviceXcbPresentationSupportKHR + VkPhysicalDevice physicalDevice + uint32_t queueFamilyIndex + xcb_connection_t* connection + xcb_visualid_t visual_id + + + VkResult vkCreateDirectFBSurfaceEXT + VkInstance instance + const VkDirectFBSurfaceCreateInfoEXT* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkBool32 vkGetPhysicalDeviceDirectFBPresentationSupportEXT + VkPhysicalDevice physicalDevice + uint32_t queueFamilyIndex + IDirectFB* dfb + + + VkResult vkCreateImagePipeSurfaceFUCHSIA + VkInstance instance + const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkResult vkCreateStreamDescriptorSurfaceGGP + VkInstance instance + const VkStreamDescriptorSurfaceCreateInfoGGP* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkResult vkCreateScreenSurfaceQNX + VkInstance instance + const VkScreenSurfaceCreateInfoQNX* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkBool32 vkGetPhysicalDeviceScreenPresentationSupportQNX + VkPhysicalDevice physicalDevice + uint32_t queueFamilyIndex + struct _screen_window* window + + + VkResult vkCreateDebugReportCallbackEXT + VkInstance instance + const VkDebugReportCallbackCreateInfoEXT* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkDebugReportCallbackEXT* pCallback + + + void vkDestroyDebugReportCallbackEXT + VkInstance instance + VkDebugReportCallbackEXT callback + const VkAllocationCallbacks* pAllocator + + + void vkDebugReportMessageEXT + VkInstance instance + VkDebugReportFlagsEXT flags + VkDebugReportObjectTypeEXT objectType + uint64_t object + size_t location + int32_t messageCode + const char* pLayerPrefix + const char* pMessage + + + VkResult vkDebugMarkerSetObjectNameEXT + VkDevice device + const VkDebugMarkerObjectNameInfoEXT* pNameInfo + + + VkResult vkDebugMarkerSetObjectTagEXT + VkDevice device + const VkDebugMarkerObjectTagInfoEXT* pTagInfo + + + void vkCmdDebugMarkerBeginEXT + VkCommandBuffer commandBuffer + const VkDebugMarkerMarkerInfoEXT* pMarkerInfo + + + void vkCmdDebugMarkerEndEXT + VkCommandBuffer commandBuffer + + + void vkCmdDebugMarkerInsertEXT + VkCommandBuffer commandBuffer + const VkDebugMarkerMarkerInfoEXT* pMarkerInfo + + + VkResult vkGetPhysicalDeviceExternalImageFormatPropertiesNV + VkPhysicalDevice physicalDevice + VkFormat format + VkImageType type + VkImageTiling tiling + VkImageUsageFlags usage + VkImageCreateFlags flags + VkExternalMemoryHandleTypeFlagsNV externalHandleType + VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties + + + VkResult vkGetMemoryWin32HandleNV + VkDevice device + VkDeviceMemory memory + VkExternalMemoryHandleTypeFlagsNV handleType + HANDLE* pHandle + + + void vkCmdExecuteGeneratedCommandsNV + VkCommandBuffer commandBuffer + VkBool32 isPreprocessed + const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo + + + void vkCmdPreprocessGeneratedCommandsNV + VkCommandBuffer commandBuffer + const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo + + + void vkCmdBindPipelineShaderGroupNV + VkCommandBuffer commandBuffer + VkPipelineBindPoint pipelineBindPoint + VkPipeline pipeline + uint32_t groupIndex + + + void vkGetGeneratedCommandsMemoryRequirementsNV + VkDevice device + const VkGeneratedCommandsMemoryRequirementsInfoNV* pInfo + VkMemoryRequirements2* pMemoryRequirements + + + VkResult vkCreateIndirectCommandsLayoutNV + VkDevice device + const VkIndirectCommandsLayoutCreateInfoNV* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkIndirectCommandsLayoutNV* pIndirectCommandsLayout + + + void vkDestroyIndirectCommandsLayoutNV + VkDevice device + VkIndirectCommandsLayoutNV indirectCommandsLayout + const VkAllocationCallbacks* pAllocator + + + void vkGetPhysicalDeviceFeatures2 + VkPhysicalDevice physicalDevice + VkPhysicalDeviceFeatures2* pFeatures + + + + void vkGetPhysicalDeviceProperties2 + VkPhysicalDevice physicalDevice + VkPhysicalDeviceProperties2* pProperties + + + + void vkGetPhysicalDeviceFormatProperties2 + VkPhysicalDevice physicalDevice + VkFormat format + VkFormatProperties2* pFormatProperties + + + + VkResult vkGetPhysicalDeviceImageFormatProperties2 + VkPhysicalDevice physicalDevice + const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo + VkImageFormatProperties2* pImageFormatProperties + + + + void vkGetPhysicalDeviceQueueFamilyProperties2 + VkPhysicalDevice physicalDevice + uint32_t* pQueueFamilyPropertyCount + VkQueueFamilyProperties2* pQueueFamilyProperties + + + + void vkGetPhysicalDeviceMemoryProperties2 + VkPhysicalDevice physicalDevice + VkPhysicalDeviceMemoryProperties2* pMemoryProperties + + + + void vkGetPhysicalDeviceSparseImageFormatProperties2 + VkPhysicalDevice physicalDevice + const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo + uint32_t* pPropertyCount + VkSparseImageFormatProperties2* pProperties + + + + void vkCmdPushDescriptorSetKHR + VkCommandBuffer commandBuffer + VkPipelineBindPoint pipelineBindPoint + VkPipelineLayout layout + uint32_t set + uint32_t descriptorWriteCount + const VkWriteDescriptorSet* pDescriptorWrites + + + void vkTrimCommandPool + VkDevice device + VkCommandPool commandPool + VkCommandPoolTrimFlags flags + + + + void vkGetPhysicalDeviceExternalBufferProperties + VkPhysicalDevice physicalDevice + const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo + VkExternalBufferProperties* pExternalBufferProperties + + + + VkResult vkGetMemoryWin32HandleKHR + VkDevice device + const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo + HANDLE* pHandle + + + VkResult vkGetMemoryWin32HandlePropertiesKHR + VkDevice device + VkExternalMemoryHandleTypeFlagBits handleType + HANDLE handle + VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties + + + VkResult vkGetMemoryFdKHR + VkDevice device + const VkMemoryGetFdInfoKHR* pGetFdInfo + int* pFd + + + VkResult vkGetMemoryFdPropertiesKHR + VkDevice device + VkExternalMemoryHandleTypeFlagBits handleType + int fd + VkMemoryFdPropertiesKHR* pMemoryFdProperties + + + VkResult vkGetMemoryZirconHandleFUCHSIA + VkDevice device + const VkMemoryGetZirconHandleInfoFUCHSIA* pGetZirconHandleInfo + zx_handle_t* pZirconHandle + + + VkResult vkGetMemoryZirconHandlePropertiesFUCHSIA + VkDevice device + VkExternalMemoryHandleTypeFlagBits handleType + zx_handle_t zirconHandle + VkMemoryZirconHandlePropertiesFUCHSIA* pMemoryZirconHandleProperties + + + VkResult vkGetMemoryRemoteAddressNV + VkDevice device + const VkMemoryGetRemoteAddressInfoNV* pMemoryGetRemoteAddressInfo + VkRemoteAddressNV* pAddress + + + void vkGetPhysicalDeviceExternalSemaphoreProperties + VkPhysicalDevice physicalDevice + const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo + VkExternalSemaphoreProperties* pExternalSemaphoreProperties + + + + VkResult vkGetSemaphoreWin32HandleKHR + VkDevice device + const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo + HANDLE* pHandle + + + VkResult vkImportSemaphoreWin32HandleKHR + VkDevice device + const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo + + + VkResult vkGetSemaphoreFdKHR + VkDevice device + const VkSemaphoreGetFdInfoKHR* pGetFdInfo + int* pFd + + + VkResult vkImportSemaphoreFdKHR + VkDevice device + const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo + + + VkResult vkGetSemaphoreZirconHandleFUCHSIA + VkDevice device + const VkSemaphoreGetZirconHandleInfoFUCHSIA* pGetZirconHandleInfo + zx_handle_t* pZirconHandle + + + VkResult vkImportSemaphoreZirconHandleFUCHSIA + VkDevice device + const VkImportSemaphoreZirconHandleInfoFUCHSIA* pImportSemaphoreZirconHandleInfo + + + void vkGetPhysicalDeviceExternalFenceProperties + VkPhysicalDevice physicalDevice + const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo + VkExternalFenceProperties* pExternalFenceProperties + + + + VkResult vkGetFenceWin32HandleKHR + VkDevice device + const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo + HANDLE* pHandle + + + VkResult vkImportFenceWin32HandleKHR + VkDevice device + const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo + + + VkResult vkGetFenceFdKHR + VkDevice device + const VkFenceGetFdInfoKHR* pGetFdInfo + int* pFd + + + VkResult vkImportFenceFdKHR + VkDevice device + const VkImportFenceFdInfoKHR* pImportFenceFdInfo + + + VkResult vkReleaseDisplayEXT + VkPhysicalDevice physicalDevice + VkDisplayKHR display + + + VkResult vkAcquireXlibDisplayEXT + VkPhysicalDevice physicalDevice + Display* dpy + VkDisplayKHR display + + + VkResult vkGetRandROutputDisplayEXT + VkPhysicalDevice physicalDevice + Display* dpy + RROutput rrOutput + VkDisplayKHR* pDisplay + + + VkResult vkAcquireWinrtDisplayNV + VkPhysicalDevice physicalDevice + VkDisplayKHR display + + + VkResult vkGetWinrtDisplayNV + VkPhysicalDevice physicalDevice + uint32_t deviceRelativeId + VkDisplayKHR* pDisplay + + + VkResult vkDisplayPowerControlEXT + VkDevice device + VkDisplayKHR display + const VkDisplayPowerInfoEXT* pDisplayPowerInfo + + + VkResult vkRegisterDeviceEventEXT + VkDevice device + const VkDeviceEventInfoEXT* pDeviceEventInfo + const VkAllocationCallbacks* pAllocator + VkFence* pFence + + + VkResult vkRegisterDisplayEventEXT + VkDevice device + VkDisplayKHR display + const VkDisplayEventInfoEXT* pDisplayEventInfo + const VkAllocationCallbacks* pAllocator + VkFence* pFence + + + VkResult vkGetSwapchainCounterEXT + VkDevice device + VkSwapchainKHR swapchain + VkSurfaceCounterFlagBitsEXT counter + uint64_t* pCounterValue + + + VkResult vkGetPhysicalDeviceSurfaceCapabilities2EXT + VkPhysicalDevice physicalDevice + VkSurfaceKHR surface + VkSurfaceCapabilities2EXT* pSurfaceCapabilities + + + VkResult vkEnumeratePhysicalDeviceGroups + VkInstance instance + uint32_t* pPhysicalDeviceGroupCount + VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties + + + + void vkGetDeviceGroupPeerMemoryFeatures + VkDevice device + uint32_t heapIndex + uint32_t localDeviceIndex + uint32_t remoteDeviceIndex + VkPeerMemoryFeatureFlags* pPeerMemoryFeatures + + + + VkResult vkBindBufferMemory2 + VkDevice device + uint32_t bindInfoCount + const VkBindBufferMemoryInfo* pBindInfos + + + + VkResult vkBindImageMemory2 + VkDevice device + uint32_t bindInfoCount + const VkBindImageMemoryInfo* pBindInfos + + + + void vkCmdSetDeviceMask + VkCommandBuffer commandBuffer + uint32_t deviceMask + + + + VkResult vkGetDeviceGroupPresentCapabilitiesKHR + VkDevice device + VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities + + + VkResult vkGetDeviceGroupSurfacePresentModesKHR + VkDevice device + VkSurfaceKHR surface + VkDeviceGroupPresentModeFlagsKHR* pModes + + + VkResult vkAcquireNextImage2KHR + VkDevice device + const VkAcquireNextImageInfoKHR* pAcquireInfo + uint32_t* pImageIndex + + + void vkCmdDispatchBase + VkCommandBuffer commandBuffer + uint32_t baseGroupX + uint32_t baseGroupY + uint32_t baseGroupZ + uint32_t groupCountX + uint32_t groupCountY + uint32_t groupCountZ + + + + VkResult vkGetPhysicalDevicePresentRectanglesKHR + VkPhysicalDevice physicalDevice + VkSurfaceKHR surface + uint32_t* pRectCount + VkRect2D* pRects + + + VkResult vkCreateDescriptorUpdateTemplate + VkDevice device + const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate + + + + void vkDestroyDescriptorUpdateTemplate + VkDevice device + VkDescriptorUpdateTemplate descriptorUpdateTemplate + const VkAllocationCallbacks* pAllocator + + + + void vkUpdateDescriptorSetWithTemplate + VkDevice device + VkDescriptorSet descriptorSet + VkDescriptorUpdateTemplate descriptorUpdateTemplate + const void* pData + + + + void vkCmdPushDescriptorSetWithTemplateKHR + VkCommandBuffer commandBuffer + VkDescriptorUpdateTemplate descriptorUpdateTemplate + VkPipelineLayout layout + uint32_t set + const void* pData + + + void vkSetHdrMetadataEXT + VkDevice device + uint32_t swapchainCount + const VkSwapchainKHR* pSwapchains + const VkHdrMetadataEXT* pMetadata + + + VkResult vkGetSwapchainStatusKHR + VkDevice device + VkSwapchainKHR swapchain + + + VkResult vkGetRefreshCycleDurationGOOGLE + VkDevice device + VkSwapchainKHR swapchain + VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties + + + VkResult vkGetPastPresentationTimingGOOGLE + VkDevice device + VkSwapchainKHR swapchain + uint32_t* pPresentationTimingCount + VkPastPresentationTimingGOOGLE* pPresentationTimings + + + VkResult vkCreateIOSSurfaceMVK + VkInstance instance + const VkIOSSurfaceCreateInfoMVK* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkResult vkCreateMacOSSurfaceMVK + VkInstance instance + const VkMacOSSurfaceCreateInfoMVK* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkResult vkCreateMetalSurfaceEXT + VkInstance instance + const VkMetalSurfaceCreateInfoEXT* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + void vkCmdSetViewportWScalingNV + VkCommandBuffer commandBuffer + uint32_t firstViewport + uint32_t viewportCount + const VkViewportWScalingNV* pViewportWScalings + + + void vkCmdSetDiscardRectangleEXT + VkCommandBuffer commandBuffer + uint32_t firstDiscardRectangle + uint32_t discardRectangleCount + const VkRect2D* pDiscardRectangles + + + void vkCmdSetSampleLocationsEXT + VkCommandBuffer commandBuffer + const VkSampleLocationsInfoEXT* pSampleLocationsInfo + + + void vkGetPhysicalDeviceMultisamplePropertiesEXT + VkPhysicalDevice physicalDevice + VkSampleCountFlagBits samples + VkMultisamplePropertiesEXT* pMultisampleProperties + + + VkResult vkGetPhysicalDeviceSurfaceCapabilities2KHR + VkPhysicalDevice physicalDevice + const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo + VkSurfaceCapabilities2KHR* pSurfaceCapabilities + + + VkResult vkGetPhysicalDeviceSurfaceFormats2KHR + VkPhysicalDevice physicalDevice + const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo + uint32_t* pSurfaceFormatCount + VkSurfaceFormat2KHR* pSurfaceFormats + + + VkResult vkGetPhysicalDeviceDisplayProperties2KHR + VkPhysicalDevice physicalDevice + uint32_t* pPropertyCount + VkDisplayProperties2KHR* pProperties + + + VkResult vkGetPhysicalDeviceDisplayPlaneProperties2KHR + VkPhysicalDevice physicalDevice + uint32_t* pPropertyCount + VkDisplayPlaneProperties2KHR* pProperties + + + VkResult vkGetDisplayModeProperties2KHR + VkPhysicalDevice physicalDevice + VkDisplayKHR display + uint32_t* pPropertyCount + VkDisplayModeProperties2KHR* pProperties + + + VkResult vkGetDisplayPlaneCapabilities2KHR + VkPhysicalDevice physicalDevice + const VkDisplayPlaneInfo2KHR* pDisplayPlaneInfo + VkDisplayPlaneCapabilities2KHR* pCapabilities + + + void vkGetBufferMemoryRequirements2 + VkDevice device + const VkBufferMemoryRequirementsInfo2* pInfo + VkMemoryRequirements2* pMemoryRequirements + + + + void vkGetImageMemoryRequirements2 + VkDevice device + const VkImageMemoryRequirementsInfo2* pInfo + VkMemoryRequirements2* pMemoryRequirements + + + + void vkGetImageSparseMemoryRequirements2 + VkDevice device + const VkImageSparseMemoryRequirementsInfo2* pInfo + uint32_t* pSparseMemoryRequirementCount + VkSparseImageMemoryRequirements2* pSparseMemoryRequirements + + + + void vkGetDeviceBufferMemoryRequirements + VkDevice device + const VkDeviceBufferMemoryRequirements* pInfo + VkMemoryRequirements2* pMemoryRequirements + + + + void vkGetDeviceImageMemoryRequirements + VkDevice device + const VkDeviceImageMemoryRequirements* pInfo + VkMemoryRequirements2* pMemoryRequirements + + + + void vkGetDeviceImageSparseMemoryRequirements + VkDevice device + const VkDeviceImageMemoryRequirements* pInfo + uint32_t* pSparseMemoryRequirementCount + VkSparseImageMemoryRequirements2* pSparseMemoryRequirements + + + + VkResult vkCreateSamplerYcbcrConversion + VkDevice device + const VkSamplerYcbcrConversionCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSamplerYcbcrConversion* pYcbcrConversion + + + + void vkDestroySamplerYcbcrConversion + VkDevice device + VkSamplerYcbcrConversion ycbcrConversion + const VkAllocationCallbacks* pAllocator + + + + void vkGetDeviceQueue2 + VkDevice device + const VkDeviceQueueInfo2* pQueueInfo + VkQueue* pQueue + + + VkResult vkCreateValidationCacheEXT + VkDevice device + const VkValidationCacheCreateInfoEXT* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkValidationCacheEXT* pValidationCache + + + void vkDestroyValidationCacheEXT + VkDevice device + VkValidationCacheEXT validationCache + const VkAllocationCallbacks* pAllocator + + + VkResult vkGetValidationCacheDataEXT + VkDevice device + VkValidationCacheEXT validationCache + size_t* pDataSize + void* pData + + + VkResult vkMergeValidationCachesEXT + VkDevice device + VkValidationCacheEXT dstCache + uint32_t srcCacheCount + const VkValidationCacheEXT* pSrcCaches + + + void vkGetDescriptorSetLayoutSupport + VkDevice device + const VkDescriptorSetLayoutCreateInfo* pCreateInfo + VkDescriptorSetLayoutSupport* pSupport + + + + VkResult vkGetSwapchainGrallocUsageANDROID + VkDevice device + VkFormat format + VkImageUsageFlags imageUsage + int* grallocUsage + + + VkResult vkGetSwapchainGrallocUsage2ANDROID + VkDevice device + VkFormat format + VkImageUsageFlags imageUsage + VkSwapchainImageUsageFlagsANDROID swapchainImageUsage + uint64_t* grallocConsumerUsage + uint64_t* grallocProducerUsage + + + VkResult vkAcquireImageANDROID + VkDevice device + VkImage image + int nativeFenceFd + VkSemaphore semaphore + VkFence fence + + + VkResult vkQueueSignalReleaseImageANDROID + VkQueue queue + uint32_t waitSemaphoreCount + const VkSemaphore* pWaitSemaphores + VkImage image + int* pNativeFenceFd + + + VkResult vkGetShaderInfoAMD + VkDevice device + VkPipeline pipeline + VkShaderStageFlagBits shaderStage + VkShaderInfoTypeAMD infoType + size_t* pInfoSize + void* pInfo + + + void vkSetLocalDimmingAMD + VkDevice device + VkSwapchainKHR swapChain + VkBool32 localDimmingEnable + + + VkResult vkGetPhysicalDeviceCalibrateableTimeDomainsEXT + VkPhysicalDevice physicalDevice + uint32_t* pTimeDomainCount + VkTimeDomainEXT* pTimeDomains + + + VkResult vkGetCalibratedTimestampsEXT + VkDevice device + uint32_t timestampCount + const VkCalibratedTimestampInfoEXT* pTimestampInfos + uint64_t* pTimestamps + uint64_t* pMaxDeviation + + + VkResult vkSetDebugUtilsObjectNameEXT + VkDevice device + const VkDebugUtilsObjectNameInfoEXT* pNameInfo + + + VkResult vkSetDebugUtilsObjectTagEXT + VkDevice device + const VkDebugUtilsObjectTagInfoEXT* pTagInfo + + + void vkQueueBeginDebugUtilsLabelEXT + VkQueue queue + const VkDebugUtilsLabelEXT* pLabelInfo + + + void vkQueueEndDebugUtilsLabelEXT + VkQueue queue + + + void vkQueueInsertDebugUtilsLabelEXT + VkQueue queue + const VkDebugUtilsLabelEXT* pLabelInfo + + + void vkCmdBeginDebugUtilsLabelEXT + VkCommandBuffer commandBuffer + const VkDebugUtilsLabelEXT* pLabelInfo + + + void vkCmdEndDebugUtilsLabelEXT + VkCommandBuffer commandBuffer + + + void vkCmdInsertDebugUtilsLabelEXT + VkCommandBuffer commandBuffer + const VkDebugUtilsLabelEXT* pLabelInfo + + + VkResult vkCreateDebugUtilsMessengerEXT + VkInstance instance + const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkDebugUtilsMessengerEXT* pMessenger + + + void vkDestroyDebugUtilsMessengerEXT + VkInstance instance + VkDebugUtilsMessengerEXT messenger + const VkAllocationCallbacks* pAllocator + + + void vkSubmitDebugUtilsMessageEXT + VkInstance instance + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity + VkDebugUtilsMessageTypeFlagsEXT messageTypes + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData + + + VkResult vkGetMemoryHostPointerPropertiesEXT + VkDevice device + VkExternalMemoryHandleTypeFlagBits handleType + const void* pHostPointer + VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties + + + void vkCmdWriteBufferMarkerAMD + VkCommandBuffer commandBuffer + VkPipelineStageFlagBits pipelineStage + VkBuffer dstBuffer + VkDeviceSize dstOffset + uint32_t marker + + + VkResult vkCreateRenderPass2 + VkDevice device + const VkRenderPassCreateInfo2* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkRenderPass* pRenderPass + + + + void vkCmdBeginRenderPass2 + VkCommandBuffer commandBuffer + const VkRenderPassBeginInfo* pRenderPassBegin + const VkSubpassBeginInfo* pSubpassBeginInfo + + + + void vkCmdNextSubpass2 + VkCommandBuffer commandBuffer + const VkSubpassBeginInfo* pSubpassBeginInfo + const VkSubpassEndInfo* pSubpassEndInfo + + + + void vkCmdEndRenderPass2 + VkCommandBuffer commandBuffer + const VkSubpassEndInfo* pSubpassEndInfo + + + + VkResult vkGetSemaphoreCounterValue + VkDevice device + VkSemaphore semaphore + uint64_t* pValue + + + + VkResult vkWaitSemaphores + VkDevice device + const VkSemaphoreWaitInfo* pWaitInfo + uint64_t timeout + + + + VkResult vkSignalSemaphore + VkDevice device + const VkSemaphoreSignalInfo* pSignalInfo + + + + VkResult vkGetAndroidHardwareBufferPropertiesANDROID + VkDevice device + const struct AHardwareBuffer* buffer + VkAndroidHardwareBufferPropertiesANDROID* pProperties + + + VkResult vkGetMemoryAndroidHardwareBufferANDROID + VkDevice device + const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo + struct AHardwareBuffer** pBuffer + + + void vkCmdDrawIndirectCount + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + VkBuffer countBuffer + VkDeviceSize countBufferOffset + uint32_t maxDrawCount + uint32_t stride + + + + + void vkCmdDrawIndexedIndirectCount + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + VkBuffer countBuffer + VkDeviceSize countBufferOffset + uint32_t maxDrawCount + uint32_t stride + + + + + void vkCmdSetCheckpointNV + VkCommandBuffer commandBuffer + const void* pCheckpointMarker + + + void vkGetQueueCheckpointDataNV + VkQueue queue + uint32_t* pCheckpointDataCount + VkCheckpointDataNV* pCheckpointData + + + void vkCmdBindTransformFeedbackBuffersEXT + VkCommandBuffer commandBuffer + uint32_t firstBinding + uint32_t bindingCount + const VkBuffer* pBuffers + const VkDeviceSize* pOffsets + const VkDeviceSize* pSizes + + + void vkCmdBeginTransformFeedbackEXT + VkCommandBuffer commandBuffer + uint32_t firstCounterBuffer + uint32_t counterBufferCount + const VkBuffer* pCounterBuffers + const VkDeviceSize* pCounterBufferOffsets + + + void vkCmdEndTransformFeedbackEXT + VkCommandBuffer commandBuffer + uint32_t firstCounterBuffer + uint32_t counterBufferCount + const VkBuffer* pCounterBuffers + const VkDeviceSize* pCounterBufferOffsets + + + void vkCmdBeginQueryIndexedEXT + VkCommandBuffer commandBuffer + VkQueryPool queryPool + uint32_t query + VkQueryControlFlags flags + uint32_t index + + + void vkCmdEndQueryIndexedEXT + VkCommandBuffer commandBuffer + VkQueryPool queryPool + uint32_t query + uint32_t index + + + void vkCmdDrawIndirectByteCountEXT + VkCommandBuffer commandBuffer + uint32_t instanceCount + uint32_t firstInstance + VkBuffer counterBuffer + VkDeviceSize counterBufferOffset + uint32_t counterOffset + uint32_t vertexStride + + + void vkCmdSetExclusiveScissorNV + VkCommandBuffer commandBuffer + uint32_t firstExclusiveScissor + uint32_t exclusiveScissorCount + const VkRect2D* pExclusiveScissors + + + void vkCmdBindShadingRateImageNV + VkCommandBuffer commandBuffer + VkImageView imageView + VkImageLayout imageLayout + + + void vkCmdSetViewportShadingRatePaletteNV + VkCommandBuffer commandBuffer + uint32_t firstViewport + uint32_t viewportCount + const VkShadingRatePaletteNV* pShadingRatePalettes + + + void vkCmdSetCoarseSampleOrderNV + VkCommandBuffer commandBuffer + VkCoarseSampleOrderTypeNV sampleOrderType + uint32_t customSampleOrderCount + const VkCoarseSampleOrderCustomNV* pCustomSampleOrders + + + void vkCmdDrawMeshTasksNV + VkCommandBuffer commandBuffer + uint32_t taskCount + uint32_t firstTask + + + void vkCmdDrawMeshTasksIndirectNV + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + uint32_t drawCount + uint32_t stride + + + void vkCmdDrawMeshTasksIndirectCountNV + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + VkBuffer countBuffer + VkDeviceSize countBufferOffset + uint32_t maxDrawCount + uint32_t stride + + + void vkCmdDrawMeshTasksEXT + VkCommandBuffer commandBuffer + uint32_t groupCountX + uint32_t groupCountY + uint32_t groupCountZ + + + void vkCmdDrawMeshTasksIndirectEXT + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + uint32_t drawCount + uint32_t stride + + + void vkCmdDrawMeshTasksIndirectCountEXT + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + VkBuffer countBuffer + VkDeviceSize countBufferOffset + uint32_t maxDrawCount + uint32_t stride + + + VkResult vkCompileDeferredNV + VkDevice device + VkPipeline pipeline + uint32_t shader + + + VkResult vkCreateAccelerationStructureNV + VkDevice device + const VkAccelerationStructureCreateInfoNV* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkAccelerationStructureNV* pAccelerationStructure + + + void vkCmdBindInvocationMaskHUAWEI + VkCommandBuffer commandBuffer + VkImageView imageView + VkImageLayout imageLayout + + + void vkDestroyAccelerationStructureKHR + VkDevice device + VkAccelerationStructureKHR accelerationStructure + const VkAllocationCallbacks* pAllocator + + + void vkDestroyAccelerationStructureNV + VkDevice device + VkAccelerationStructureNV accelerationStructure + const VkAllocationCallbacks* pAllocator + + + void vkGetAccelerationStructureMemoryRequirementsNV + VkDevice device + const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo + VkMemoryRequirements2KHR* pMemoryRequirements + + + VkResult vkBindAccelerationStructureMemoryNV + VkDevice device + uint32_t bindInfoCount + const VkBindAccelerationStructureMemoryInfoNV* pBindInfos + + + void vkCmdCopyAccelerationStructureNV + VkCommandBuffer commandBuffer + VkAccelerationStructureNV dst + VkAccelerationStructureNV src + VkCopyAccelerationStructureModeKHR mode + + + void vkCmdCopyAccelerationStructureKHR + VkCommandBuffer commandBuffer + const VkCopyAccelerationStructureInfoKHR* pInfo + + + VkResult vkCopyAccelerationStructureKHR + VkDevice device + VkDeferredOperationKHR deferredOperation + const VkCopyAccelerationStructureInfoKHR* pInfo + + + void vkCmdCopyAccelerationStructureToMemoryKHR + VkCommandBuffer commandBuffer + const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo + + + VkResult vkCopyAccelerationStructureToMemoryKHR + VkDevice device + VkDeferredOperationKHR deferredOperation + const VkCopyAccelerationStructureToMemoryInfoKHR* pInfo + + + void vkCmdCopyMemoryToAccelerationStructureKHR + VkCommandBuffer commandBuffer + const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo + + + VkResult vkCopyMemoryToAccelerationStructureKHR + VkDevice device + VkDeferredOperationKHR deferredOperation + const VkCopyMemoryToAccelerationStructureInfoKHR* pInfo + + + void vkCmdWriteAccelerationStructuresPropertiesKHR + VkCommandBuffer commandBuffer + uint32_t accelerationStructureCount + const VkAccelerationStructureKHR* pAccelerationStructures + VkQueryType queryType + VkQueryPool queryPool + uint32_t firstQuery + + + void vkCmdWriteAccelerationStructuresPropertiesNV + VkCommandBuffer commandBuffer + uint32_t accelerationStructureCount + const VkAccelerationStructureNV* pAccelerationStructures + VkQueryType queryType + VkQueryPool queryPool + uint32_t firstQuery + + + void vkCmdBuildAccelerationStructureNV + VkCommandBuffer commandBuffer + const VkAccelerationStructureInfoNV* pInfo + VkBuffer instanceData + VkDeviceSize instanceOffset + VkBool32 update + VkAccelerationStructureNV dst + VkAccelerationStructureNV src + VkBuffer scratch + VkDeviceSize scratchOffset + + + VkResult vkWriteAccelerationStructuresPropertiesKHR + VkDevice device + uint32_t accelerationStructureCount + const VkAccelerationStructureKHR* pAccelerationStructures + VkQueryType queryType + size_t dataSize + void* pData + size_t stride + + + void vkCmdTraceRaysKHR + VkCommandBuffer commandBuffer + const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable + const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable + const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable + const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable + uint32_t width + uint32_t height + uint32_t depth + + + void vkCmdTraceRaysNV + VkCommandBuffer commandBuffer + VkBuffer raygenShaderBindingTableBuffer + VkDeviceSize raygenShaderBindingOffset + VkBuffer missShaderBindingTableBuffer + VkDeviceSize missShaderBindingOffset + VkDeviceSize missShaderBindingStride + VkBuffer hitShaderBindingTableBuffer + VkDeviceSize hitShaderBindingOffset + VkDeviceSize hitShaderBindingStride + VkBuffer callableShaderBindingTableBuffer + VkDeviceSize callableShaderBindingOffset + VkDeviceSize callableShaderBindingStride + uint32_t width + uint32_t height + uint32_t depth + + + VkResult vkGetRayTracingShaderGroupHandlesKHR + VkDevice device + VkPipeline pipeline + uint32_t firstGroup + uint32_t groupCount + size_t dataSize + void* pData + + + + VkResult vkGetRayTracingCaptureReplayShaderGroupHandlesKHR + VkDevice device + VkPipeline pipeline + uint32_t firstGroup + uint32_t groupCount + size_t dataSize + void* pData + + + VkResult vkGetAccelerationStructureHandleNV + VkDevice device + VkAccelerationStructureNV accelerationStructure + size_t dataSize + void* pData + + + VkResult vkCreateRayTracingPipelinesNV + VkDevice device + VkPipelineCache pipelineCache + uint32_t createInfoCount + const VkRayTracingPipelineCreateInfoNV* pCreateInfos + const VkAllocationCallbacks* pAllocator + VkPipeline* pPipelines + + + VkResult vkCreateRayTracingPipelinesKHR + VkDevice device + VkDeferredOperationKHR deferredOperation + VkPipelineCache pipelineCache + uint32_t createInfoCount + const VkRayTracingPipelineCreateInfoKHR* pCreateInfos + const VkAllocationCallbacks* pAllocator + VkPipeline* pPipelines + + + VkResult vkGetPhysicalDeviceCooperativeMatrixPropertiesNV + VkPhysicalDevice physicalDevice + uint32_t* pPropertyCount + VkCooperativeMatrixPropertiesNV* pProperties + + + void vkCmdTraceRaysIndirectKHR + VkCommandBuffer commandBuffer + const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable + const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable + const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable + const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable + VkDeviceAddress indirectDeviceAddress + + + void vkCmdTraceRaysIndirect2KHR + VkCommandBuffer commandBuffer + VkDeviceAddress indirectDeviceAddress + + + void vkGetDeviceAccelerationStructureCompatibilityKHR + VkDevice device + const VkAccelerationStructureVersionInfoKHR* pVersionInfo + VkAccelerationStructureCompatibilityKHR* pCompatibility + + + VkDeviceSize vkGetRayTracingShaderGroupStackSizeKHR + VkDevice device + VkPipeline pipeline + uint32_t group + VkShaderGroupShaderKHR groupShader + + + void vkCmdSetRayTracingPipelineStackSizeKHR + VkCommandBuffer commandBuffer + uint32_t pipelineStackSize + + + uint32_t vkGetImageViewHandleNVX + VkDevice device + const VkImageViewHandleInfoNVX* pInfo + + + VkResult vkGetImageViewAddressNVX + VkDevice device + VkImageView imageView + VkImageViewAddressPropertiesNVX* pProperties + + + VkResult vkGetPhysicalDeviceSurfacePresentModes2EXT + VkPhysicalDevice physicalDevice + const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo + uint32_t* pPresentModeCount + VkPresentModeKHR* pPresentModes + + + VkResult vkGetDeviceGroupSurfacePresentModes2EXT + VkDevice device + const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo + VkDeviceGroupPresentModeFlagsKHR* pModes + + + VkResult vkAcquireFullScreenExclusiveModeEXT + VkDevice device + VkSwapchainKHR swapchain + + + VkResult vkReleaseFullScreenExclusiveModeEXT + VkDevice device + VkSwapchainKHR swapchain + + + VkResult vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR + VkPhysicalDevice physicalDevice + uint32_t queueFamilyIndex + uint32_t* pCounterCount + VkPerformanceCounterKHR* pCounters + VkPerformanceCounterDescriptionKHR* pCounterDescriptions + + + void vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR + VkPhysicalDevice physicalDevice + const VkQueryPoolPerformanceCreateInfoKHR* pPerformanceQueryCreateInfo + uint32_t* pNumPasses + + + VkResult vkAcquireProfilingLockKHR + VkDevice device + const VkAcquireProfilingLockInfoKHR* pInfo + + + void vkReleaseProfilingLockKHR + VkDevice device + + + VkResult vkGetImageDrmFormatModifierPropertiesEXT + VkDevice device + VkImage image + VkImageDrmFormatModifierPropertiesEXT* pProperties + + + uint64_t vkGetBufferOpaqueCaptureAddress + VkDevice device + const VkBufferDeviceAddressInfo* pInfo + + + + VkDeviceAddress vkGetBufferDeviceAddress + VkDevice device + const VkBufferDeviceAddressInfo* pInfo + + + + + VkResult vkCreateHeadlessSurfaceEXT + VkInstance instance + const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSurfaceKHR* pSurface + + + VkResult vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV + VkPhysicalDevice physicalDevice + uint32_t* pCombinationCount + VkFramebufferMixedSamplesCombinationNV* pCombinations + + + VkResult vkInitializePerformanceApiINTEL + VkDevice device + const VkInitializePerformanceApiInfoINTEL* pInitializeInfo + + + void vkUninitializePerformanceApiINTEL + VkDevice device + + + VkResult vkCmdSetPerformanceMarkerINTEL + VkCommandBuffer commandBuffer + const VkPerformanceMarkerInfoINTEL* pMarkerInfo + + + VkResult vkCmdSetPerformanceStreamMarkerINTEL + VkCommandBuffer commandBuffer + const VkPerformanceStreamMarkerInfoINTEL* pMarkerInfo + + + VkResult vkCmdSetPerformanceOverrideINTEL + VkCommandBuffer commandBuffer + const VkPerformanceOverrideInfoINTEL* pOverrideInfo + + + VkResult vkAcquirePerformanceConfigurationINTEL + VkDevice device + const VkPerformanceConfigurationAcquireInfoINTEL* pAcquireInfo + VkPerformanceConfigurationINTEL* pConfiguration + + + VkResult vkReleasePerformanceConfigurationINTEL + VkDevice device + VkPerformanceConfigurationINTEL configuration + + + VkResult vkQueueSetPerformanceConfigurationINTEL + VkQueue queue + VkPerformanceConfigurationINTEL configuration + + + VkResult vkGetPerformanceParameterINTEL + VkDevice device + VkPerformanceParameterTypeINTEL parameter + VkPerformanceValueINTEL* pValue + + + uint64_t vkGetDeviceMemoryOpaqueCaptureAddress + VkDevice device + const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo + + + + VkResult vkGetPipelineExecutablePropertiesKHR + VkDevice device + const VkPipelineInfoKHR* pPipelineInfo + uint32_t* pExecutableCount + VkPipelineExecutablePropertiesKHR* pProperties + + + VkResult vkGetPipelineExecutableStatisticsKHR + VkDevice device + const VkPipelineExecutableInfoKHR* pExecutableInfo + uint32_t* pStatisticCount + VkPipelineExecutableStatisticKHR* pStatistics + + + VkResult vkGetPipelineExecutableInternalRepresentationsKHR + VkDevice device + const VkPipelineExecutableInfoKHR* pExecutableInfo + uint32_t* pInternalRepresentationCount + VkPipelineExecutableInternalRepresentationKHR* pInternalRepresentations + + + void vkCmdSetLineStippleEXT + VkCommandBuffer commandBuffer + uint32_t lineStippleFactor + uint16_t lineStipplePattern + + + VkResult vkGetPhysicalDeviceToolProperties + VkPhysicalDevice physicalDevice + uint32_t* pToolCount + VkPhysicalDeviceToolProperties* pToolProperties + + + + VkResult vkCreateAccelerationStructureKHR + VkDevice device + const VkAccelerationStructureCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkAccelerationStructureKHR* pAccelerationStructure + + + void vkCmdBuildAccelerationStructuresKHR + VkCommandBuffer commandBuffer + uint32_t infoCount + const VkAccelerationStructureBuildGeometryInfoKHR* pInfos + const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos + + + void vkCmdBuildAccelerationStructuresIndirectKHR + VkCommandBuffer commandBuffer + uint32_t infoCount + const VkAccelerationStructureBuildGeometryInfoKHR* pInfos + const VkDeviceAddress* pIndirectDeviceAddresses + const uint32_t* pIndirectStrides + const uint32_t* const* ppMaxPrimitiveCounts + + + VkResult vkBuildAccelerationStructuresKHR + VkDevice device + VkDeferredOperationKHR deferredOperation + uint32_t infoCount + const VkAccelerationStructureBuildGeometryInfoKHR* pInfos + const VkAccelerationStructureBuildRangeInfoKHR* const* ppBuildRangeInfos + + + VkDeviceAddress vkGetAccelerationStructureDeviceAddressKHR + VkDevice device + const VkAccelerationStructureDeviceAddressInfoKHR* pInfo + + + VkResult vkCreateDeferredOperationKHR + VkDevice device + const VkAllocationCallbacks* pAllocator + VkDeferredOperationKHR* pDeferredOperation + + + void vkDestroyDeferredOperationKHR + VkDevice device + VkDeferredOperationKHR operation + const VkAllocationCallbacks* pAllocator + + + uint32_t vkGetDeferredOperationMaxConcurrencyKHR + VkDevice device + VkDeferredOperationKHR operation + + + VkResult vkGetDeferredOperationResultKHR + VkDevice device + VkDeferredOperationKHR operation + + + VkResult vkDeferredOperationJoinKHR + VkDevice device + VkDeferredOperationKHR operation + + + void vkCmdSetCullMode + VkCommandBuffer commandBuffer + VkCullModeFlags cullMode + + + + void vkCmdSetFrontFace + VkCommandBuffer commandBuffer + VkFrontFace frontFace + + + + void vkCmdSetPrimitiveTopology + VkCommandBuffer commandBuffer + VkPrimitiveTopology primitiveTopology + + + + void vkCmdSetViewportWithCount + VkCommandBuffer commandBuffer + uint32_t viewportCount + const VkViewport* pViewports + + + + void vkCmdSetScissorWithCount + VkCommandBuffer commandBuffer + uint32_t scissorCount + const VkRect2D* pScissors + + + + void vkCmdBindVertexBuffers2 + VkCommandBuffer commandBuffer + uint32_t firstBinding + uint32_t bindingCount + const VkBuffer* pBuffers + const VkDeviceSize* pOffsets + const VkDeviceSize* pSizes + const VkDeviceSize* pStrides + + + + void vkCmdSetDepthTestEnable + VkCommandBuffer commandBuffer + VkBool32 depthTestEnable + + + + void vkCmdSetDepthWriteEnable + VkCommandBuffer commandBuffer + VkBool32 depthWriteEnable + + + + void vkCmdSetDepthCompareOp + VkCommandBuffer commandBuffer + VkCompareOp depthCompareOp + + + + void vkCmdSetDepthBoundsTestEnable + VkCommandBuffer commandBuffer + VkBool32 depthBoundsTestEnable + + + + void vkCmdSetStencilTestEnable + VkCommandBuffer commandBuffer + VkBool32 stencilTestEnable + + + + void vkCmdSetStencilOp + VkCommandBuffer commandBuffer + VkStencilFaceFlags faceMask + VkStencilOp failOp + VkStencilOp passOp + VkStencilOp depthFailOp + VkCompareOp compareOp + + + + void vkCmdSetPatchControlPointsEXT + VkCommandBuffer commandBuffer + uint32_t patchControlPoints + + + void vkCmdSetRasterizerDiscardEnable + VkCommandBuffer commandBuffer + VkBool32 rasterizerDiscardEnable + + + + void vkCmdSetDepthBiasEnable + VkCommandBuffer commandBuffer + VkBool32 depthBiasEnable + + + + void vkCmdSetLogicOpEXT + VkCommandBuffer commandBuffer + VkLogicOp logicOp + + + void vkCmdSetPrimitiveRestartEnable + VkCommandBuffer commandBuffer + VkBool32 primitiveRestartEnable + + + + void vkCmdSetTessellationDomainOriginEXT + VkCommandBuffer commandBuffer + VkTessellationDomainOrigin domainOrigin + + + void vkCmdSetDepthClampEnableEXT + VkCommandBuffer commandBuffer + VkBool32 depthClampEnable + + + void vkCmdSetPolygonModeEXT + VkCommandBuffer commandBuffer + VkPolygonMode polygonMode + + + void vkCmdSetRasterizationSamplesEXT + VkCommandBuffer commandBuffer + VkSampleCountFlagBits rasterizationSamples + + + void vkCmdSetSampleMaskEXT + VkCommandBuffer commandBuffer + VkSampleCountFlagBits samples + const VkSampleMask* pSampleMask + + + void vkCmdSetAlphaToCoverageEnableEXT + VkCommandBuffer commandBuffer + VkBool32 alphaToCoverageEnable + + + void vkCmdSetAlphaToOneEnableEXT + VkCommandBuffer commandBuffer + VkBool32 alphaToOneEnable + + + void vkCmdSetLogicOpEnableEXT + VkCommandBuffer commandBuffer + VkBool32 logicOpEnable + + + void vkCmdSetColorBlendEnableEXT + VkCommandBuffer commandBuffer + uint32_t firstAttachment + uint32_t attachmentCount + const VkBool32* pColorBlendEnables + + + void vkCmdSetColorBlendEquationEXT + VkCommandBuffer commandBuffer + uint32_t firstAttachment + uint32_t attachmentCount + const VkColorBlendEquationEXT* pColorBlendEquations + + + void vkCmdSetColorWriteMaskEXT + VkCommandBuffer commandBuffer + uint32_t firstAttachment + uint32_t attachmentCount + const VkColorComponentFlags* pColorWriteMasks + + + void vkCmdSetRasterizationStreamEXT + VkCommandBuffer commandBuffer + uint32_t rasterizationStream + + + void vkCmdSetConservativeRasterizationModeEXT + VkCommandBuffer commandBuffer + VkConservativeRasterizationModeEXT conservativeRasterizationMode + + + void vkCmdSetExtraPrimitiveOverestimationSizeEXT + VkCommandBuffer commandBuffer + float extraPrimitiveOverestimationSize + + + void vkCmdSetDepthClipEnableEXT + VkCommandBuffer commandBuffer + VkBool32 depthClipEnable + + + void vkCmdSetSampleLocationsEnableEXT + VkCommandBuffer commandBuffer + VkBool32 sampleLocationsEnable + + + void vkCmdSetColorBlendAdvancedEXT + VkCommandBuffer commandBuffer + uint32_t firstAttachment + uint32_t attachmentCount + const VkColorBlendAdvancedEXT* pColorBlendAdvanced + + + void vkCmdSetProvokingVertexModeEXT + VkCommandBuffer commandBuffer + VkProvokingVertexModeEXT provokingVertexMode + + + void vkCmdSetLineRasterizationModeEXT + VkCommandBuffer commandBuffer + VkLineRasterizationModeEXT lineRasterizationMode + + + void vkCmdSetLineStippleEnableEXT + VkCommandBuffer commandBuffer + VkBool32 stippledLineEnable + + + void vkCmdSetDepthClipNegativeOneToOneEXT + VkCommandBuffer commandBuffer + VkBool32 negativeOneToOne + + + void vkCmdSetViewportWScalingEnableNV + VkCommandBuffer commandBuffer + VkBool32 viewportWScalingEnable + + + void vkCmdSetViewportSwizzleNV + VkCommandBuffer commandBuffer + uint32_t firstViewport + uint32_t viewportCount + const VkViewportSwizzleNV* pViewportSwizzles + + + void vkCmdSetCoverageToColorEnableNV + VkCommandBuffer commandBuffer + VkBool32 coverageToColorEnable + + + void vkCmdSetCoverageToColorLocationNV + VkCommandBuffer commandBuffer + uint32_t coverageToColorLocation + + + void vkCmdSetCoverageModulationModeNV + VkCommandBuffer commandBuffer + VkCoverageModulationModeNV coverageModulationMode + + + void vkCmdSetCoverageModulationTableEnableNV + VkCommandBuffer commandBuffer + VkBool32 coverageModulationTableEnable + + + void vkCmdSetCoverageModulationTableNV + VkCommandBuffer commandBuffer + uint32_t coverageModulationTableCount + const float* pCoverageModulationTable + + + void vkCmdSetShadingRateImageEnableNV + VkCommandBuffer commandBuffer + VkBool32 shadingRateImageEnable + + + void vkCmdSetCoverageReductionModeNV + VkCommandBuffer commandBuffer + VkCoverageReductionModeNV coverageReductionMode + + + void vkCmdSetRepresentativeFragmentTestEnableNV + VkCommandBuffer commandBuffer + VkBool32 representativeFragmentTestEnable + + + VkResult vkCreatePrivateDataSlot + VkDevice device + const VkPrivateDataSlotCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkPrivateDataSlot* pPrivateDataSlot + + + + void vkDestroyPrivateDataSlot + VkDevice device + VkPrivateDataSlot privateDataSlot + const VkAllocationCallbacks* pAllocator + + + + VkResult vkSetPrivateData + VkDevice device + VkObjectType objectType + uint64_t objectHandle + VkPrivateDataSlot privateDataSlot + uint64_t data + + + + void vkGetPrivateData + VkDevice device + VkObjectType objectType + uint64_t objectHandle + VkPrivateDataSlot privateDataSlot + uint64_t* pData + + + + void vkCmdCopyBuffer2 + VkCommandBuffer commandBuffer + const VkCopyBufferInfo2* pCopyBufferInfo + + + + void vkCmdCopyImage2 + VkCommandBuffer commandBuffer + const VkCopyImageInfo2* pCopyImageInfo + + + + void vkCmdBlitImage2 + VkCommandBuffer commandBuffer + const VkBlitImageInfo2* pBlitImageInfo + + + + void vkCmdCopyBufferToImage2 + VkCommandBuffer commandBuffer + const VkCopyBufferToImageInfo2* pCopyBufferToImageInfo + + + + void vkCmdCopyImageToBuffer2 + VkCommandBuffer commandBuffer + const VkCopyImageToBufferInfo2* pCopyImageToBufferInfo + + + + void vkCmdResolveImage2 + VkCommandBuffer commandBuffer + const VkResolveImageInfo2* pResolveImageInfo + + + + void vkCmdSetFragmentShadingRateKHR + VkCommandBuffer commandBuffer + const VkExtent2D* pFragmentSize + const VkFragmentShadingRateCombinerOpKHR combinerOps[2] + + + VkResult vkGetPhysicalDeviceFragmentShadingRatesKHR + VkPhysicalDevice physicalDevice + uint32_t* pFragmentShadingRateCount + VkPhysicalDeviceFragmentShadingRateKHR* pFragmentShadingRates + + + void vkCmdSetFragmentShadingRateEnumNV + VkCommandBuffer commandBuffer + VkFragmentShadingRateNV shadingRate + const VkFragmentShadingRateCombinerOpKHR combinerOps[2] + + + void vkGetAccelerationStructureBuildSizesKHR + VkDevice device + VkAccelerationStructureBuildTypeKHR buildType + const VkAccelerationStructureBuildGeometryInfoKHR* pBuildInfo + const uint32_t* pMaxPrimitiveCounts + VkAccelerationStructureBuildSizesInfoKHR* pSizeInfo + + + void vkCmdSetVertexInputEXT + VkCommandBuffer commandBuffer + uint32_t vertexBindingDescriptionCount + const VkVertexInputBindingDescription2EXT* pVertexBindingDescriptions + uint32_t vertexAttributeDescriptionCount + const VkVertexInputAttributeDescription2EXT* pVertexAttributeDescriptions + + + void vkCmdSetColorWriteEnableEXT + VkCommandBuffer commandBuffer + uint32_t attachmentCount + const VkBool32* pColorWriteEnables + + + void vkCmdSetEvent2 + VkCommandBuffer commandBuffer + VkEvent event + const VkDependencyInfo* pDependencyInfo + + + + void vkCmdResetEvent2 + VkCommandBuffer commandBuffer + VkEvent event + VkPipelineStageFlags2 stageMask + + + + void vkCmdWaitEvents2 + VkCommandBuffer commandBuffer + uint32_t eventCount + const VkEvent* pEvents + const VkDependencyInfo* pDependencyInfos + + + + void vkCmdPipelineBarrier2 + VkCommandBuffer commandBuffer + const VkDependencyInfo* pDependencyInfo + + + + VkResult vkQueueSubmit2 + VkQueue queue + uint32_t submitCount + const VkSubmitInfo2* pSubmits + VkFence fence + + + + void vkCmdWriteTimestamp2 + VkCommandBuffer commandBuffer + VkPipelineStageFlags2 stage + VkQueryPool queryPool + uint32_t query + + + + void vkCmdWriteBufferMarker2AMD + VkCommandBuffer commandBuffer + VkPipelineStageFlags2 stage + VkBuffer dstBuffer + VkDeviceSize dstOffset + uint32_t marker + + + void vkGetQueueCheckpointData2NV + VkQueue queue + uint32_t* pCheckpointDataCount + VkCheckpointData2NV* pCheckpointData + + + VkResult vkGetPhysicalDeviceVideoCapabilitiesKHR + VkPhysicalDevice physicalDevice + const VkVideoProfileInfoKHR* pVideoProfile + VkVideoCapabilitiesKHR* pCapabilities + + + VkResult vkGetPhysicalDeviceVideoFormatPropertiesKHR + VkPhysicalDevice physicalDevice + const VkPhysicalDeviceVideoFormatInfoKHR* pVideoFormatInfo + uint32_t* pVideoFormatPropertyCount + VkVideoFormatPropertiesKHR* pVideoFormatProperties + + + VkResult vkCreateVideoSessionKHR + VkDevice device + const VkVideoSessionCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkVideoSessionKHR* pVideoSession + + + void vkDestroyVideoSessionKHR + VkDevice device + VkVideoSessionKHR videoSession + const VkAllocationCallbacks* pAllocator + + + VkResult vkCreateVideoSessionParametersKHR + VkDevice device + const VkVideoSessionParametersCreateInfoKHR* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkVideoSessionParametersKHR* pVideoSessionParameters + + + VkResult vkUpdateVideoSessionParametersKHR + VkDevice device + VkVideoSessionParametersKHR videoSessionParameters + const VkVideoSessionParametersUpdateInfoKHR* pUpdateInfo + + + void vkDestroyVideoSessionParametersKHR + VkDevice device + VkVideoSessionParametersKHR videoSessionParameters + const VkAllocationCallbacks* pAllocator + + + VkResult vkGetVideoSessionMemoryRequirementsKHR + VkDevice device + VkVideoSessionKHR videoSession + uint32_t* pMemoryRequirementsCount + VkVideoSessionMemoryRequirementsKHR* pMemoryRequirements + + + VkResult vkBindVideoSessionMemoryKHR + VkDevice device + VkVideoSessionKHR videoSession + uint32_t bindSessionMemoryInfoCount + const VkBindVideoSessionMemoryInfoKHR* pBindSessionMemoryInfos + + + void vkCmdDecodeVideoKHR + VkCommandBuffer commandBuffer + const VkVideoDecodeInfoKHR* pDecodeInfo + + + void vkCmdBeginVideoCodingKHR + VkCommandBuffer commandBuffer + const VkVideoBeginCodingInfoKHR* pBeginInfo + + + void vkCmdControlVideoCodingKHR + VkCommandBuffer commandBuffer + const VkVideoCodingControlInfoKHR* pCodingControlInfo + + + void vkCmdEndVideoCodingKHR + VkCommandBuffer commandBuffer + const VkVideoEndCodingInfoKHR* pEndCodingInfo + + + void vkCmdEncodeVideoKHR + VkCommandBuffer commandBuffer + const VkVideoEncodeInfoKHR* pEncodeInfo + + + void vkCmdDecompressMemoryNV + VkCommandBuffer commandBuffer + uint32_t decompressRegionCount + const VkDecompressMemoryRegionNV* pDecompressMemoryRegions + + + void vkCmdDecompressMemoryIndirectCountNV + VkCommandBuffer commandBuffer + VkDeviceAddress indirectCommandsAddress + VkDeviceAddress indirectCommandsCountAddress + uint32_t stride + + + VkResult vkCreateCuModuleNVX + VkDevice device + const VkCuModuleCreateInfoNVX* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkCuModuleNVX* pModule + + + VkResult vkCreateCuFunctionNVX + VkDevice device + const VkCuFunctionCreateInfoNVX* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkCuFunctionNVX* pFunction + + + void vkDestroyCuModuleNVX + VkDevice device + VkCuModuleNVX module + const VkAllocationCallbacks* pAllocator + + + void vkDestroyCuFunctionNVX + VkDevice device + VkCuFunctionNVX function + const VkAllocationCallbacks* pAllocator + + + void vkCmdCuLaunchKernelNVX + VkCommandBuffer commandBuffer + const VkCuLaunchInfoNVX* pLaunchInfo + + + void vkGetDescriptorSetLayoutSizeEXT + VkDevice device + VkDescriptorSetLayout layout + VkDeviceSize* pLayoutSizeInBytes + + + void vkGetDescriptorSetLayoutBindingOffsetEXT + VkDevice device + VkDescriptorSetLayout layout + uint32_t binding + VkDeviceSize* pOffset + + + void vkGetDescriptorEXT + VkDevice device + const VkDescriptorGetInfoEXT* pDescriptorInfo + size_t dataSize + void* pDescriptor + + + void vkCmdBindDescriptorBuffersEXT + VkCommandBuffer commandBuffer + uint32_t bufferCount + const VkDescriptorBufferBindingInfoEXT* pBindingInfos + + + void vkCmdSetDescriptorBufferOffsetsEXT + VkCommandBuffer commandBuffer + VkPipelineBindPoint pipelineBindPoint + VkPipelineLayout layout + uint32_t firstSet + uint32_t setCount + const uint32_t* pBufferIndices + const VkDeviceSize* pOffsets + + + void vkCmdBindDescriptorBufferEmbeddedSamplersEXT + VkCommandBuffer commandBuffer + VkPipelineBindPoint pipelineBindPoint + VkPipelineLayout layout + uint32_t set + + + VkResult vkGetBufferOpaqueCaptureDescriptorDataEXT + VkDevice device + const VkBufferCaptureDescriptorDataInfoEXT* pInfo + void* pData + + + VkResult vkGetImageOpaqueCaptureDescriptorDataEXT + VkDevice device + const VkImageCaptureDescriptorDataInfoEXT* pInfo + void* pData + + + VkResult vkGetImageViewOpaqueCaptureDescriptorDataEXT + VkDevice device + const VkImageViewCaptureDescriptorDataInfoEXT* pInfo + void* pData + + + VkResult vkGetSamplerOpaqueCaptureDescriptorDataEXT + VkDevice device + const VkSamplerCaptureDescriptorDataInfoEXT* pInfo + void* pData + + + VkResult vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT + VkDevice device + const VkAccelerationStructureCaptureDescriptorDataInfoEXT* pInfo + void* pData + + + void vkSetDeviceMemoryPriorityEXT + VkDevice device + VkDeviceMemory memory + float priority + + + VkResult vkAcquireDrmDisplayEXT + VkPhysicalDevice physicalDevice + int32_t drmFd + VkDisplayKHR display + + + VkResult vkGetDrmDisplayEXT + VkPhysicalDevice physicalDevice + int32_t drmFd + uint32_t connectorId + VkDisplayKHR* display + + + VkResult vkWaitForPresentKHR + VkDevice device + VkSwapchainKHR swapchain + uint64_t presentId + uint64_t timeout + + + VkResult vkCreateBufferCollectionFUCHSIA + VkDevice device + const VkBufferCollectionCreateInfoFUCHSIA* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkBufferCollectionFUCHSIA* pCollection + + + VkResult vkSetBufferCollectionBufferConstraintsFUCHSIA + VkDevice device + VkBufferCollectionFUCHSIA collection + const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo + + + VkResult vkSetBufferCollectionImageConstraintsFUCHSIA + VkDevice device + VkBufferCollectionFUCHSIA collection + const VkImageConstraintsInfoFUCHSIA* pImageConstraintsInfo + + + void vkDestroyBufferCollectionFUCHSIA + VkDevice device + VkBufferCollectionFUCHSIA collection + const VkAllocationCallbacks* pAllocator + + + VkResult vkGetBufferCollectionPropertiesFUCHSIA + VkDevice device + VkBufferCollectionFUCHSIA collection + VkBufferCollectionPropertiesFUCHSIA* pProperties + + + void vkCmdBeginRendering + VkCommandBuffer commandBuffer + const VkRenderingInfo* pRenderingInfo + + + + void vkCmdEndRendering + VkCommandBuffer commandBuffer + + + + + void vkGetDescriptorSetLayoutHostMappingInfoVALVE + VkDevice device + const VkDescriptorSetBindingReferenceVALVE* pBindingReference + VkDescriptorSetLayoutHostMappingInfoVALVE* pHostMapping + + + void vkGetDescriptorSetHostMappingVALVE + VkDevice device + VkDescriptorSet descriptorSet + void** ppData + + + VkResult vkCreateMicromapEXT + VkDevice device + const VkMicromapCreateInfoEXT* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkMicromapEXT* pMicromap + + + void vkCmdBuildMicromapsEXT + VkCommandBuffer commandBuffer + uint32_t infoCount + const VkMicromapBuildInfoEXT* pInfos + + + VkResult vkBuildMicromapsEXT + VkDevice device + VkDeferredOperationKHR deferredOperation + uint32_t infoCount + const VkMicromapBuildInfoEXT* pInfos + + + void vkDestroyMicromapEXT + VkDevice device + VkMicromapEXT micromap + const VkAllocationCallbacks* pAllocator + + + void vkCmdCopyMicromapEXT + VkCommandBuffer commandBuffer + const VkCopyMicromapInfoEXT* pInfo + + + VkResult vkCopyMicromapEXT + VkDevice device + VkDeferredOperationKHR deferredOperation + const VkCopyMicromapInfoEXT* pInfo + + + void vkCmdCopyMicromapToMemoryEXT + VkCommandBuffer commandBuffer + const VkCopyMicromapToMemoryInfoEXT* pInfo + + + VkResult vkCopyMicromapToMemoryEXT + VkDevice device + VkDeferredOperationKHR deferredOperation + const VkCopyMicromapToMemoryInfoEXT* pInfo + + + void vkCmdCopyMemoryToMicromapEXT + VkCommandBuffer commandBuffer + const VkCopyMemoryToMicromapInfoEXT* pInfo + + + VkResult vkCopyMemoryToMicromapEXT + VkDevice device + VkDeferredOperationKHR deferredOperation + const VkCopyMemoryToMicromapInfoEXT* pInfo + + + void vkCmdWriteMicromapsPropertiesEXT + VkCommandBuffer commandBuffer + uint32_t micromapCount + const VkMicromapEXT* pMicromaps + VkQueryType queryType + VkQueryPool queryPool + uint32_t firstQuery + + + VkResult vkWriteMicromapsPropertiesEXT + VkDevice device + uint32_t micromapCount + const VkMicromapEXT* pMicromaps + VkQueryType queryType + size_t dataSize + void* pData + size_t stride + + + void vkGetDeviceMicromapCompatibilityEXT + VkDevice device + const VkMicromapVersionInfoEXT* pVersionInfo + VkAccelerationStructureCompatibilityKHR* pCompatibility + + + void vkGetMicromapBuildSizesEXT + VkDevice device + VkAccelerationStructureBuildTypeKHR buildType + const VkMicromapBuildInfoEXT* pBuildInfo + VkMicromapBuildSizesInfoEXT* pSizeInfo + + + void vkGetShaderModuleIdentifierEXT + VkDevice device + VkShaderModule shaderModule + VkShaderModuleIdentifierEXT* pIdentifier + + + void vkGetShaderModuleCreateInfoIdentifierEXT + VkDevice device + const VkShaderModuleCreateInfo* pCreateInfo + VkShaderModuleIdentifierEXT* pIdentifier + + + void vkGetImageSubresourceLayout2EXT + VkDevice device + VkImage image + const VkImageSubresource2EXT* pSubresource + VkSubresourceLayout2EXT* pLayout + + + VkResult vkGetPipelinePropertiesEXT + VkDevice device + const VkPipelineInfoEXT* pPipelineInfo + VkBaseOutStructure* pPipelineProperties + + + void vkExportMetalObjectsEXT + VkDevice device + VkExportMetalObjectsInfoEXT* pMetalObjectsInfo + + + VkResult vkGetFramebufferTilePropertiesQCOM + VkDevice device + VkFramebuffer framebuffer + uint32_t* pPropertiesCount + VkTilePropertiesQCOM* pProperties + + + VkResult vkGetDynamicRenderingTilePropertiesQCOM + VkDevice device + const VkRenderingInfo* pRenderingInfo + VkTilePropertiesQCOM* pProperties + + + VkResult vkGetPhysicalDeviceOpticalFlowImageFormatsNV + VkPhysicalDevice physicalDevice + const VkOpticalFlowImageFormatInfoNV* pOpticalFlowImageFormatInfo + uint32_t* pFormatCount + VkOpticalFlowImageFormatPropertiesNV* pImageFormatProperties + + + VkResult vkCreateOpticalFlowSessionNV + VkDevice device + const VkOpticalFlowSessionCreateInfoNV* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkOpticalFlowSessionNV* pSession + + + void vkDestroyOpticalFlowSessionNV + VkDevice device + VkOpticalFlowSessionNV session + const VkAllocationCallbacks* pAllocator + + + VkResult vkBindOpticalFlowSessionImageNV + VkDevice device + VkOpticalFlowSessionNV session + VkOpticalFlowSessionBindingPointNV bindingPoint + VkImageView view + VkImageLayout layout + + + void vkCmdOpticalFlowExecuteNV + VkCommandBuffer commandBuffer + VkOpticalFlowSessionNV session + const VkOpticalFlowExecuteInfoNV* pExecuteInfo + + + VkResult vkGetDeviceFaultInfoEXT + VkDevice device + VkDeviceFaultCountsEXT* pFaultCounts + VkDeviceFaultInfoEXT* pFaultInfo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + offset 1 reserved for the old VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHX enum + offset 2 reserved for the old VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHX enum + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Additional dependent types / tokens extending enumerants, not explicitly mentioned + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Additional dependent types / tokens extending enumerants, not explicitly mentioned + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This duplicates definitions in VK_KHR_device_group below + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VK_ANDROID_native_buffer is used between the Android Vulkan loader and drivers to implement the WSI extensions. It is not exposed to applications and uses types that are not part of Android's stable public API, so it is left disabled to keep it out of the standard Vulkan headers. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This duplicates definitions in other extensions, below + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + enum offset=0 was mistakenly used for the 1.1 core enum + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES + (value=1000094000). Fortunately, no conflict resulted. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This extension requires buffer_device_address functionality. + VK_EXT_buffer_device_address is also acceptable, but since it is deprecated the KHR version is preferred. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + These enums are present only to inform downstream + consumers like KTX2. There is no actual Vulkan extension + corresponding to the enums. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT and + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT + were not promoted to Vulkan 1.3. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VkPhysicalDevice4444FormatsFeaturesEXT and + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT + were not promoted to Vulkan 1.3. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NV internal use only + + + + + + + + + + + + + + + + + + + + + + + + + + NV internal use only + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 82fa1cf334159d5c4261f8f1ff345165e7942ec0 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 12 Dec 2022 05:35:07 +0200 Subject: [PATCH 0002/2777] winevulkan: Remove autogenerated files. Proton's build system creates them anyway. They are getting outdated pretty fast and are confusing at best. --- dlls/vulkan-1/vulkan-1.spec | 251 - dlls/winevulkan/loader_thunks.c | 6230 ----- dlls/winevulkan/loader_thunks.h | 4665 ---- dlls/winevulkan/vulkan_thunks.c | 41346 ------------------------------ dlls/winevulkan/vulkan_thunks.h | 1108 - dlls/winevulkan/winevulkan.json | 7 - dlls/winevulkan/winevulkan.spec | 256 - include/wine/vulkan.h | 12636 --------- include/wine/vulkan_driver.h | 118 - 9 files changed, 66617 deletions(-) delete mode 100644 dlls/vulkan-1/vulkan-1.spec delete mode 100644 dlls/winevulkan/loader_thunks.c delete mode 100644 dlls/winevulkan/loader_thunks.h delete mode 100644 dlls/winevulkan/vulkan_thunks.c delete mode 100644 dlls/winevulkan/vulkan_thunks.h delete mode 100644 dlls/winevulkan/winevulkan.json delete mode 100644 dlls/winevulkan/winevulkan.spec delete mode 100644 include/wine/vulkan.h delete mode 100644 include/wine/vulkan_driver.h diff --git a/dlls/vulkan-1/vulkan-1.spec b/dlls/vulkan-1/vulkan-1.spec deleted file mode 100644 index c73df709e08..00000000000 --- a/dlls/vulkan-1/vulkan-1.spec +++ /dev/null @@ -1,251 +0,0 @@ -# Automatically generated from Vulkan vk.xml; DO NOT EDIT! -# -# This file is generated from Vulkan vk.xml file covered -# by the following copyright and permission notice: -# -# Copyright 2015-2022 The Khronos Group Inc. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# - -@ stdcall vkAcquireNextImage2KHR(ptr ptr ptr) winevulkan.vkAcquireNextImage2KHR -@ stdcall vkAcquireNextImageKHR(ptr int64 int64 int64 int64 ptr) winevulkan.vkAcquireNextImageKHR -@ stdcall vkAllocateCommandBuffers(ptr ptr ptr) winevulkan.vkAllocateCommandBuffers -@ stdcall vkAllocateDescriptorSets(ptr ptr ptr) winevulkan.vkAllocateDescriptorSets -@ stdcall vkAllocateMemory(ptr ptr ptr ptr) winevulkan.vkAllocateMemory -@ stdcall vkBeginCommandBuffer(ptr ptr) winevulkan.vkBeginCommandBuffer -@ stdcall vkBindBufferMemory(ptr int64 int64 int64) winevulkan.vkBindBufferMemory -@ stdcall vkBindBufferMemory2(ptr long ptr) winevulkan.vkBindBufferMemory2 -@ stdcall vkBindImageMemory(ptr int64 int64 int64) winevulkan.vkBindImageMemory -@ stdcall vkBindImageMemory2(ptr long ptr) winevulkan.vkBindImageMemory2 -@ stdcall vkCmdBeginQuery(ptr int64 long long) winevulkan.vkCmdBeginQuery -@ stdcall vkCmdBeginRenderPass(ptr ptr long) winevulkan.vkCmdBeginRenderPass -@ stdcall vkCmdBeginRenderPass2(ptr ptr ptr) winevulkan.vkCmdBeginRenderPass2 -@ stdcall vkCmdBeginRendering(ptr ptr) winevulkan.vkCmdBeginRendering -@ stdcall vkCmdBindDescriptorSets(ptr long int64 long long ptr long ptr) winevulkan.vkCmdBindDescriptorSets -@ stdcall vkCmdBindIndexBuffer(ptr int64 int64 long) winevulkan.vkCmdBindIndexBuffer -@ stdcall vkCmdBindPipeline(ptr long int64) winevulkan.vkCmdBindPipeline -@ stdcall vkCmdBindVertexBuffers(ptr long long ptr ptr) winevulkan.vkCmdBindVertexBuffers -@ stdcall vkCmdBindVertexBuffers2(ptr long long ptr ptr ptr ptr) winevulkan.vkCmdBindVertexBuffers2 -@ stdcall vkCmdBlitImage(ptr int64 long int64 long long ptr long) winevulkan.vkCmdBlitImage -@ stdcall vkCmdBlitImage2(ptr ptr) winevulkan.vkCmdBlitImage2 -@ stdcall vkCmdClearAttachments(ptr long ptr long ptr) winevulkan.vkCmdClearAttachments -@ stdcall vkCmdClearColorImage(ptr int64 long ptr long ptr) winevulkan.vkCmdClearColorImage -@ stdcall vkCmdClearDepthStencilImage(ptr int64 long ptr long ptr) winevulkan.vkCmdClearDepthStencilImage -@ stdcall vkCmdCopyBuffer(ptr int64 int64 long ptr) winevulkan.vkCmdCopyBuffer -@ stdcall vkCmdCopyBuffer2(ptr ptr) winevulkan.vkCmdCopyBuffer2 -@ stdcall vkCmdCopyBufferToImage(ptr int64 int64 long long ptr) winevulkan.vkCmdCopyBufferToImage -@ stdcall vkCmdCopyBufferToImage2(ptr ptr) winevulkan.vkCmdCopyBufferToImage2 -@ stdcall vkCmdCopyImage(ptr int64 long int64 long long ptr) winevulkan.vkCmdCopyImage -@ stdcall vkCmdCopyImage2(ptr ptr) winevulkan.vkCmdCopyImage2 -@ stdcall vkCmdCopyImageToBuffer(ptr int64 long int64 long ptr) winevulkan.vkCmdCopyImageToBuffer -@ stdcall vkCmdCopyImageToBuffer2(ptr ptr) winevulkan.vkCmdCopyImageToBuffer2 -@ stdcall vkCmdCopyQueryPoolResults(ptr int64 long long int64 int64 int64 long) winevulkan.vkCmdCopyQueryPoolResults -@ stdcall vkCmdDispatch(ptr long long long) winevulkan.vkCmdDispatch -@ stdcall vkCmdDispatchBase(ptr long long long long long long) winevulkan.vkCmdDispatchBase -@ stdcall vkCmdDispatchIndirect(ptr int64 int64) winevulkan.vkCmdDispatchIndirect -@ stdcall vkCmdDraw(ptr long long long long) winevulkan.vkCmdDraw -@ stdcall vkCmdDrawIndexed(ptr long long long long long) winevulkan.vkCmdDrawIndexed -@ stdcall vkCmdDrawIndexedIndirect(ptr int64 int64 long long) winevulkan.vkCmdDrawIndexedIndirect -@ stdcall vkCmdDrawIndexedIndirectCount(ptr int64 int64 int64 int64 long long) winevulkan.vkCmdDrawIndexedIndirectCount -@ stdcall vkCmdDrawIndirect(ptr int64 int64 long long) winevulkan.vkCmdDrawIndirect -@ stdcall vkCmdDrawIndirectCount(ptr int64 int64 int64 int64 long long) winevulkan.vkCmdDrawIndirectCount -@ stdcall vkCmdEndQuery(ptr int64 long) winevulkan.vkCmdEndQuery -@ stdcall vkCmdEndRenderPass(ptr) winevulkan.vkCmdEndRenderPass -@ stdcall vkCmdEndRenderPass2(ptr ptr) winevulkan.vkCmdEndRenderPass2 -@ stdcall vkCmdEndRendering(ptr) winevulkan.vkCmdEndRendering -@ stdcall vkCmdExecuteCommands(ptr long ptr) winevulkan.vkCmdExecuteCommands -@ stdcall vkCmdFillBuffer(ptr int64 int64 int64 long) winevulkan.vkCmdFillBuffer -@ stdcall vkCmdNextSubpass(ptr long) winevulkan.vkCmdNextSubpass -@ stdcall vkCmdNextSubpass2(ptr ptr ptr) winevulkan.vkCmdNextSubpass2 -@ stdcall vkCmdPipelineBarrier(ptr long long long long ptr long ptr long ptr) winevulkan.vkCmdPipelineBarrier -@ stdcall vkCmdPipelineBarrier2(ptr ptr) winevulkan.vkCmdPipelineBarrier2 -@ stdcall vkCmdPushConstants(ptr int64 long long long ptr) winevulkan.vkCmdPushConstants -@ stdcall vkCmdResetEvent(ptr int64 long) winevulkan.vkCmdResetEvent -@ stdcall vkCmdResetEvent2(ptr int64 int64) winevulkan.vkCmdResetEvent2 -@ stdcall vkCmdResetQueryPool(ptr int64 long long) winevulkan.vkCmdResetQueryPool -@ stdcall vkCmdResolveImage(ptr int64 long int64 long long ptr) winevulkan.vkCmdResolveImage -@ stdcall vkCmdResolveImage2(ptr ptr) winevulkan.vkCmdResolveImage2 -@ stdcall vkCmdSetBlendConstants(ptr ptr) winevulkan.vkCmdSetBlendConstants -@ stdcall vkCmdSetCullMode(ptr long) winevulkan.vkCmdSetCullMode -@ stdcall vkCmdSetDepthBias(ptr float float float) winevulkan.vkCmdSetDepthBias -@ stdcall vkCmdSetDepthBiasEnable(ptr long) winevulkan.vkCmdSetDepthBiasEnable -@ stdcall vkCmdSetDepthBounds(ptr float float) winevulkan.vkCmdSetDepthBounds -@ stdcall vkCmdSetDepthBoundsTestEnable(ptr long) winevulkan.vkCmdSetDepthBoundsTestEnable -@ stdcall vkCmdSetDepthCompareOp(ptr long) winevulkan.vkCmdSetDepthCompareOp -@ stdcall vkCmdSetDepthTestEnable(ptr long) winevulkan.vkCmdSetDepthTestEnable -@ stdcall vkCmdSetDepthWriteEnable(ptr long) winevulkan.vkCmdSetDepthWriteEnable -@ stdcall vkCmdSetDeviceMask(ptr long) winevulkan.vkCmdSetDeviceMask -@ stdcall vkCmdSetEvent(ptr int64 long) winevulkan.vkCmdSetEvent -@ stdcall vkCmdSetEvent2(ptr int64 ptr) winevulkan.vkCmdSetEvent2 -@ stdcall vkCmdSetFrontFace(ptr long) winevulkan.vkCmdSetFrontFace -@ stdcall vkCmdSetLineWidth(ptr float) winevulkan.vkCmdSetLineWidth -@ stdcall vkCmdSetPrimitiveRestartEnable(ptr long) winevulkan.vkCmdSetPrimitiveRestartEnable -@ stdcall vkCmdSetPrimitiveTopology(ptr long) winevulkan.vkCmdSetPrimitiveTopology -@ stdcall vkCmdSetRasterizerDiscardEnable(ptr long) winevulkan.vkCmdSetRasterizerDiscardEnable -@ stdcall vkCmdSetScissor(ptr long long ptr) winevulkan.vkCmdSetScissor -@ stdcall vkCmdSetScissorWithCount(ptr long ptr) winevulkan.vkCmdSetScissorWithCount -@ stdcall vkCmdSetStencilCompareMask(ptr long long) winevulkan.vkCmdSetStencilCompareMask -@ stdcall vkCmdSetStencilOp(ptr long long long long long) winevulkan.vkCmdSetStencilOp -@ stdcall vkCmdSetStencilReference(ptr long long) winevulkan.vkCmdSetStencilReference -@ stdcall vkCmdSetStencilTestEnable(ptr long) winevulkan.vkCmdSetStencilTestEnable -@ stdcall vkCmdSetStencilWriteMask(ptr long long) winevulkan.vkCmdSetStencilWriteMask -@ stdcall vkCmdSetViewport(ptr long long ptr) winevulkan.vkCmdSetViewport -@ stdcall vkCmdSetViewportWithCount(ptr long ptr) winevulkan.vkCmdSetViewportWithCount -@ stdcall vkCmdUpdateBuffer(ptr int64 int64 int64 ptr) winevulkan.vkCmdUpdateBuffer -@ stdcall vkCmdWaitEvents(ptr long ptr long long long ptr long ptr long ptr) winevulkan.vkCmdWaitEvents -@ stdcall vkCmdWaitEvents2(ptr long ptr ptr) winevulkan.vkCmdWaitEvents2 -@ stdcall vkCmdWriteTimestamp(ptr long int64 long) winevulkan.vkCmdWriteTimestamp -@ stdcall vkCmdWriteTimestamp2(ptr int64 int64 long) winevulkan.vkCmdWriteTimestamp2 -@ stdcall vkCreateBuffer(ptr ptr ptr ptr) winevulkan.vkCreateBuffer -@ stdcall vkCreateBufferView(ptr ptr ptr ptr) winevulkan.vkCreateBufferView -@ stdcall vkCreateCommandPool(ptr ptr ptr ptr) winevulkan.vkCreateCommandPool -@ stdcall vkCreateComputePipelines(ptr int64 long ptr ptr ptr) winevulkan.vkCreateComputePipelines -@ stdcall vkCreateDescriptorPool(ptr ptr ptr ptr) winevulkan.vkCreateDescriptorPool -@ stdcall vkCreateDescriptorSetLayout(ptr ptr ptr ptr) winevulkan.vkCreateDescriptorSetLayout -@ stdcall vkCreateDescriptorUpdateTemplate(ptr ptr ptr ptr) winevulkan.vkCreateDescriptorUpdateTemplate -@ stdcall vkCreateDevice(ptr ptr ptr ptr) winevulkan.vkCreateDevice -@ stub vkCreateDisplayModeKHR -@ stub vkCreateDisplayPlaneSurfaceKHR -@ stdcall vkCreateEvent(ptr ptr ptr ptr) winevulkan.vkCreateEvent -@ stdcall vkCreateFence(ptr ptr ptr ptr) winevulkan.vkCreateFence -@ stdcall vkCreateFramebuffer(ptr ptr ptr ptr) winevulkan.vkCreateFramebuffer -@ stdcall vkCreateGraphicsPipelines(ptr int64 long ptr ptr ptr) winevulkan.vkCreateGraphicsPipelines -@ stdcall vkCreateImage(ptr ptr ptr ptr) winevulkan.vkCreateImage -@ stdcall vkCreateImageView(ptr ptr ptr ptr) winevulkan.vkCreateImageView -@ stdcall vkCreateInstance(ptr ptr ptr) winevulkan.vkCreateInstance -@ stdcall vkCreatePipelineCache(ptr ptr ptr ptr) winevulkan.vkCreatePipelineCache -@ stdcall vkCreatePipelineLayout(ptr ptr ptr ptr) winevulkan.vkCreatePipelineLayout -@ stdcall vkCreatePrivateDataSlot(ptr ptr ptr ptr) winevulkan.vkCreatePrivateDataSlot -@ stdcall vkCreateQueryPool(ptr ptr ptr ptr) winevulkan.vkCreateQueryPool -@ stdcall vkCreateRenderPass(ptr ptr ptr ptr) winevulkan.vkCreateRenderPass -@ stdcall vkCreateRenderPass2(ptr ptr ptr ptr) winevulkan.vkCreateRenderPass2 -@ stdcall vkCreateSampler(ptr ptr ptr ptr) winevulkan.vkCreateSampler -@ stdcall vkCreateSamplerYcbcrConversion(ptr ptr ptr ptr) winevulkan.vkCreateSamplerYcbcrConversion -@ stdcall vkCreateSemaphore(ptr ptr ptr ptr) winevulkan.vkCreateSemaphore -@ stdcall vkCreateShaderModule(ptr ptr ptr ptr) winevulkan.vkCreateShaderModule -@ stub vkCreateSharedSwapchainsKHR -@ stdcall vkCreateSwapchainKHR(ptr ptr ptr ptr) winevulkan.vkCreateSwapchainKHR -@ stdcall vkCreateWin32SurfaceKHR(ptr ptr ptr ptr) winevulkan.vkCreateWin32SurfaceKHR -@ stdcall vkDestroyBuffer(ptr int64 ptr) winevulkan.vkDestroyBuffer -@ stdcall vkDestroyBufferView(ptr int64 ptr) winevulkan.vkDestroyBufferView -@ stdcall vkDestroyCommandPool(ptr int64 ptr) winevulkan.vkDestroyCommandPool -@ stdcall vkDestroyDescriptorPool(ptr int64 ptr) winevulkan.vkDestroyDescriptorPool -@ stdcall vkDestroyDescriptorSetLayout(ptr int64 ptr) winevulkan.vkDestroyDescriptorSetLayout -@ stdcall vkDestroyDescriptorUpdateTemplate(ptr int64 ptr) winevulkan.vkDestroyDescriptorUpdateTemplate -@ stdcall vkDestroyDevice(ptr ptr) winevulkan.vkDestroyDevice -@ stdcall vkDestroyEvent(ptr int64 ptr) winevulkan.vkDestroyEvent -@ stdcall vkDestroyFence(ptr int64 ptr) winevulkan.vkDestroyFence -@ stdcall vkDestroyFramebuffer(ptr int64 ptr) winevulkan.vkDestroyFramebuffer -@ stdcall vkDestroyImage(ptr int64 ptr) winevulkan.vkDestroyImage -@ stdcall vkDestroyImageView(ptr int64 ptr) winevulkan.vkDestroyImageView -@ stdcall vkDestroyInstance(ptr ptr) winevulkan.vkDestroyInstance -@ stdcall vkDestroyPipeline(ptr int64 ptr) winevulkan.vkDestroyPipeline -@ stdcall vkDestroyPipelineCache(ptr int64 ptr) winevulkan.vkDestroyPipelineCache -@ stdcall vkDestroyPipelineLayout(ptr int64 ptr) winevulkan.vkDestroyPipelineLayout -@ stdcall vkDestroyPrivateDataSlot(ptr int64 ptr) winevulkan.vkDestroyPrivateDataSlot -@ stdcall vkDestroyQueryPool(ptr int64 ptr) winevulkan.vkDestroyQueryPool -@ stdcall vkDestroyRenderPass(ptr int64 ptr) winevulkan.vkDestroyRenderPass -@ stdcall vkDestroySampler(ptr int64 ptr) winevulkan.vkDestroySampler -@ stdcall vkDestroySamplerYcbcrConversion(ptr int64 ptr) winevulkan.vkDestroySamplerYcbcrConversion -@ stdcall vkDestroySemaphore(ptr int64 ptr) winevulkan.vkDestroySemaphore -@ stdcall vkDestroyShaderModule(ptr int64 ptr) winevulkan.vkDestroyShaderModule -@ stdcall vkDestroySurfaceKHR(ptr int64 ptr) winevulkan.vkDestroySurfaceKHR -@ stdcall vkDestroySwapchainKHR(ptr int64 ptr) winevulkan.vkDestroySwapchainKHR -@ stdcall vkDeviceWaitIdle(ptr) winevulkan.vkDeviceWaitIdle -@ stdcall vkEndCommandBuffer(ptr) winevulkan.vkEndCommandBuffer -@ stdcall vkEnumerateDeviceExtensionProperties(ptr str ptr ptr) winevulkan.vkEnumerateDeviceExtensionProperties -@ stdcall vkEnumerateDeviceLayerProperties(ptr ptr ptr) winevulkan.vkEnumerateDeviceLayerProperties -@ stdcall vkEnumerateInstanceExtensionProperties(str ptr ptr) winevulkan.vkEnumerateInstanceExtensionProperties -@ stdcall vkEnumerateInstanceLayerProperties(ptr ptr) winevulkan.vkEnumerateInstanceLayerProperties -@ stdcall vkEnumerateInstanceVersion(ptr) winevulkan.vkEnumerateInstanceVersion -@ stdcall vkEnumeratePhysicalDeviceGroups(ptr ptr ptr) winevulkan.vkEnumeratePhysicalDeviceGroups -@ stdcall vkEnumeratePhysicalDevices(ptr ptr ptr) winevulkan.vkEnumeratePhysicalDevices -@ stdcall vkFlushMappedMemoryRanges(ptr long ptr) winevulkan.vkFlushMappedMemoryRanges -@ stdcall vkFreeCommandBuffers(ptr int64 long ptr) winevulkan.vkFreeCommandBuffers -@ stdcall vkFreeDescriptorSets(ptr int64 long ptr) winevulkan.vkFreeDescriptorSets -@ stdcall vkFreeMemory(ptr int64 ptr) winevulkan.vkFreeMemory -@ stdcall vkGetBufferDeviceAddress(ptr ptr) winevulkan.vkGetBufferDeviceAddress -@ stdcall vkGetBufferMemoryRequirements(ptr int64 ptr) winevulkan.vkGetBufferMemoryRequirements -@ stdcall vkGetBufferMemoryRequirements2(ptr ptr ptr) winevulkan.vkGetBufferMemoryRequirements2 -@ stdcall vkGetBufferOpaqueCaptureAddress(ptr ptr) winevulkan.vkGetBufferOpaqueCaptureAddress -@ stdcall vkGetDescriptorSetLayoutSupport(ptr ptr ptr) winevulkan.vkGetDescriptorSetLayoutSupport -@ stdcall vkGetDeviceBufferMemoryRequirements(ptr ptr ptr) winevulkan.vkGetDeviceBufferMemoryRequirements -@ stdcall vkGetDeviceGroupPeerMemoryFeatures(ptr long long long ptr) winevulkan.vkGetDeviceGroupPeerMemoryFeatures -@ stdcall vkGetDeviceGroupPresentCapabilitiesKHR(ptr ptr) winevulkan.vkGetDeviceGroupPresentCapabilitiesKHR -@ stdcall vkGetDeviceGroupSurfacePresentModesKHR(ptr int64 ptr) winevulkan.vkGetDeviceGroupSurfacePresentModesKHR -@ stdcall vkGetDeviceImageMemoryRequirements(ptr ptr ptr) winevulkan.vkGetDeviceImageMemoryRequirements -@ stdcall vkGetDeviceImageSparseMemoryRequirements(ptr ptr ptr ptr) winevulkan.vkGetDeviceImageSparseMemoryRequirements -@ stdcall vkGetDeviceMemoryCommitment(ptr int64 ptr) winevulkan.vkGetDeviceMemoryCommitment -@ stdcall vkGetDeviceMemoryOpaqueCaptureAddress(ptr ptr) winevulkan.vkGetDeviceMemoryOpaqueCaptureAddress -@ stdcall vkGetDeviceProcAddr(ptr str) winevulkan.vkGetDeviceProcAddr -@ stdcall vkGetDeviceQueue(ptr long long ptr) winevulkan.vkGetDeviceQueue -@ stdcall vkGetDeviceQueue2(ptr ptr ptr) winevulkan.vkGetDeviceQueue2 -@ stub vkGetDisplayModePropertiesKHR -@ stub vkGetDisplayPlaneCapabilitiesKHR -@ stub vkGetDisplayPlaneSupportedDisplaysKHR -@ stdcall vkGetEventStatus(ptr int64) winevulkan.vkGetEventStatus -@ stdcall vkGetFenceStatus(ptr int64) winevulkan.vkGetFenceStatus -@ stdcall vkGetImageMemoryRequirements(ptr int64 ptr) winevulkan.vkGetImageMemoryRequirements -@ stdcall vkGetImageMemoryRequirements2(ptr ptr ptr) winevulkan.vkGetImageMemoryRequirements2 -@ stdcall vkGetImageSparseMemoryRequirements(ptr int64 ptr ptr) winevulkan.vkGetImageSparseMemoryRequirements -@ stdcall vkGetImageSparseMemoryRequirements2(ptr ptr ptr ptr) winevulkan.vkGetImageSparseMemoryRequirements2 -@ stdcall vkGetImageSubresourceLayout(ptr int64 ptr ptr) winevulkan.vkGetImageSubresourceLayout -@ stdcall vkGetInstanceProcAddr(ptr str) winevulkan.vkGetInstanceProcAddr -@ stub vkGetPhysicalDeviceDisplayPlanePropertiesKHR -@ stub vkGetPhysicalDeviceDisplayPropertiesKHR -@ stdcall vkGetPhysicalDeviceExternalBufferProperties(ptr ptr ptr) winevulkan.vkGetPhysicalDeviceExternalBufferProperties -@ stdcall vkGetPhysicalDeviceExternalFenceProperties(ptr ptr ptr) winevulkan.vkGetPhysicalDeviceExternalFenceProperties -@ stdcall vkGetPhysicalDeviceExternalSemaphoreProperties(ptr ptr ptr) winevulkan.vkGetPhysicalDeviceExternalSemaphoreProperties -@ stdcall vkGetPhysicalDeviceFeatures(ptr ptr) winevulkan.vkGetPhysicalDeviceFeatures -@ stdcall vkGetPhysicalDeviceFeatures2(ptr ptr) winevulkan.vkGetPhysicalDeviceFeatures2 -@ stdcall vkGetPhysicalDeviceFormatProperties(ptr long ptr) winevulkan.vkGetPhysicalDeviceFormatProperties -@ stdcall vkGetPhysicalDeviceFormatProperties2(ptr long ptr) winevulkan.vkGetPhysicalDeviceFormatProperties2 -@ stdcall vkGetPhysicalDeviceImageFormatProperties(ptr long long long long long ptr) winevulkan.vkGetPhysicalDeviceImageFormatProperties -@ stdcall vkGetPhysicalDeviceImageFormatProperties2(ptr ptr ptr) winevulkan.vkGetPhysicalDeviceImageFormatProperties2 -@ stdcall vkGetPhysicalDeviceMemoryProperties(ptr ptr) winevulkan.vkGetPhysicalDeviceMemoryProperties -@ stdcall vkGetPhysicalDeviceMemoryProperties2(ptr ptr) winevulkan.vkGetPhysicalDeviceMemoryProperties2 -@ stdcall vkGetPhysicalDevicePresentRectanglesKHR(ptr int64 ptr ptr) winevulkan.vkGetPhysicalDevicePresentRectanglesKHR -@ stdcall vkGetPhysicalDeviceProperties(ptr ptr) winevulkan.vkGetPhysicalDeviceProperties -@ stdcall vkGetPhysicalDeviceProperties2(ptr ptr) winevulkan.vkGetPhysicalDeviceProperties2 -@ stdcall vkGetPhysicalDeviceQueueFamilyProperties(ptr ptr ptr) winevulkan.vkGetPhysicalDeviceQueueFamilyProperties -@ stdcall vkGetPhysicalDeviceQueueFamilyProperties2(ptr ptr ptr) winevulkan.vkGetPhysicalDeviceQueueFamilyProperties2 -@ stdcall vkGetPhysicalDeviceSparseImageFormatProperties(ptr long long long long long ptr ptr) winevulkan.vkGetPhysicalDeviceSparseImageFormatProperties -@ stdcall vkGetPhysicalDeviceSparseImageFormatProperties2(ptr ptr ptr ptr) winevulkan.vkGetPhysicalDeviceSparseImageFormatProperties2 -@ stdcall vkGetPhysicalDeviceSurfaceCapabilities2KHR(ptr ptr ptr) winevulkan.vkGetPhysicalDeviceSurfaceCapabilities2KHR -@ stdcall vkGetPhysicalDeviceSurfaceCapabilitiesKHR(ptr int64 ptr) winevulkan.vkGetPhysicalDeviceSurfaceCapabilitiesKHR -@ stdcall vkGetPhysicalDeviceSurfaceFormats2KHR(ptr ptr ptr ptr) winevulkan.vkGetPhysicalDeviceSurfaceFormats2KHR -@ stdcall vkGetPhysicalDeviceSurfaceFormatsKHR(ptr int64 ptr ptr) winevulkan.vkGetPhysicalDeviceSurfaceFormatsKHR -@ stdcall vkGetPhysicalDeviceSurfacePresentModesKHR(ptr int64 ptr ptr) winevulkan.vkGetPhysicalDeviceSurfacePresentModesKHR -@ stdcall vkGetPhysicalDeviceSurfaceSupportKHR(ptr long int64 ptr) winevulkan.vkGetPhysicalDeviceSurfaceSupportKHR -@ stdcall vkGetPhysicalDeviceToolProperties(ptr ptr ptr) winevulkan.vkGetPhysicalDeviceToolProperties -@ stdcall vkGetPhysicalDeviceWin32PresentationSupportKHR(ptr long) winevulkan.vkGetPhysicalDeviceWin32PresentationSupportKHR -@ stdcall vkGetPipelineCacheData(ptr int64 ptr ptr) winevulkan.vkGetPipelineCacheData -@ stdcall vkGetPrivateData(ptr long int64 int64 ptr) winevulkan.vkGetPrivateData -@ stdcall vkGetQueryPoolResults(ptr int64 long long long ptr int64 long) winevulkan.vkGetQueryPoolResults -@ stdcall vkGetRenderAreaGranularity(ptr int64 ptr) winevulkan.vkGetRenderAreaGranularity -@ stdcall vkGetSemaphoreCounterValue(ptr int64 ptr) winevulkan.vkGetSemaphoreCounterValue -@ stdcall vkGetSwapchainImagesKHR(ptr int64 ptr ptr) winevulkan.vkGetSwapchainImagesKHR -@ stdcall vkInvalidateMappedMemoryRanges(ptr long ptr) winevulkan.vkInvalidateMappedMemoryRanges -@ stdcall vkMapMemory(ptr int64 int64 int64 long ptr) winevulkan.vkMapMemory -@ stdcall vkMergePipelineCaches(ptr int64 long ptr) winevulkan.vkMergePipelineCaches -@ stdcall vkQueueBindSparse(ptr long ptr int64) winevulkan.vkQueueBindSparse -@ stdcall vkQueuePresentKHR(ptr ptr) winevulkan.vkQueuePresentKHR -@ stdcall vkQueueSubmit(ptr long ptr int64) winevulkan.vkQueueSubmit -@ stdcall vkQueueSubmit2(ptr long ptr int64) winevulkan.vkQueueSubmit2 -@ stdcall vkQueueWaitIdle(ptr) winevulkan.vkQueueWaitIdle -@ stdcall vkResetCommandBuffer(ptr long) winevulkan.vkResetCommandBuffer -@ stdcall vkResetCommandPool(ptr int64 long) winevulkan.vkResetCommandPool -@ stdcall vkResetDescriptorPool(ptr int64 long) winevulkan.vkResetDescriptorPool -@ stdcall vkResetEvent(ptr int64) winevulkan.vkResetEvent -@ stdcall vkResetFences(ptr long ptr) winevulkan.vkResetFences -@ stdcall vkResetQueryPool(ptr int64 long long) winevulkan.vkResetQueryPool -@ stdcall vkSetEvent(ptr int64) winevulkan.vkSetEvent -@ stdcall vkSetPrivateData(ptr long int64 int64 int64) winevulkan.vkSetPrivateData -@ stdcall vkSignalSemaphore(ptr ptr) winevulkan.vkSignalSemaphore -@ stdcall vkTrimCommandPool(ptr int64 long) winevulkan.vkTrimCommandPool -@ stdcall vkUnmapMemory(ptr int64) winevulkan.vkUnmapMemory -@ stdcall vkUpdateDescriptorSetWithTemplate(ptr int64 int64 ptr) winevulkan.vkUpdateDescriptorSetWithTemplate -@ stdcall vkUpdateDescriptorSets(ptr long ptr long ptr) winevulkan.vkUpdateDescriptorSets -@ stdcall vkWaitForFences(ptr long ptr long int64) winevulkan.vkWaitForFences -@ stdcall vkWaitSemaphores(ptr ptr int64) winevulkan.vkWaitSemaphores diff --git a/dlls/winevulkan/loader_thunks.c b/dlls/winevulkan/loader_thunks.c deleted file mode 100644 index 5ccf1df27e2..00000000000 --- a/dlls/winevulkan/loader_thunks.c +++ /dev/null @@ -1,6230 +0,0 @@ -/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! - * - * This file is generated from Vulkan vk.xml file covered - * by the following copyright and permission notice: - * - * Copyright 2015-2022 The Khronos Group Inc. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "vulkan_loader.h" - -WINE_DEFAULT_DEBUG_CHANNEL(vulkan); - -VkResult WINAPI vkAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR *pAcquireInfo, uint32_t *pImageIndex) -{ - struct vkAcquireNextImage2KHR_params params; - NTSTATUS status; - params.device = device; - params.pAcquireInfo = pAcquireInfo; - params.pImageIndex = pImageIndex; - status = UNIX_CALL(vkAcquireNextImage2KHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) -{ - struct vkAcquireNextImageKHR_params params; - NTSTATUS status; - params.device = device; - params.swapchain = swapchain; - params.timeout = timeout; - params.semaphore = semaphore; - params.fence = fence; - params.pImageIndex = pImageIndex; - status = UNIX_CALL(vkAcquireNextImageKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkAcquirePerformanceConfigurationINTEL(VkDevice device, const VkPerformanceConfigurationAcquireInfoINTEL *pAcquireInfo, VkPerformanceConfigurationINTEL *pConfiguration) -{ - struct vkAcquirePerformanceConfigurationINTEL_params params; - NTSTATUS status; - params.device = device; - params.pAcquireInfo = pAcquireInfo; - params.pConfiguration = pConfiguration; - status = UNIX_CALL(vkAcquirePerformanceConfigurationINTEL, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkAcquireProfilingLockKHR(VkDevice device, const VkAcquireProfilingLockInfoKHR *pInfo) -{ - struct vkAcquireProfilingLockKHR_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - status = UNIX_CALL(vkAcquireProfilingLockKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo, VkDescriptorSet *pDescriptorSets) -{ - struct vkAllocateDescriptorSets_params params; - NTSTATUS status; - params.device = device; - params.pAllocateInfo = pAllocateInfo; - params.pDescriptorSets = pDescriptorSets; - status = UNIX_CALL(vkAllocateDescriptorSets, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo, const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) -{ - struct vkAllocateMemory_params params; - NTSTATUS status; - params.device = device; - params.pAllocateInfo = pAllocateInfo; - params.pAllocator = pAllocator; - params.pMemory = pMemory; - status = UNIX_CALL(vkAllocateMemory, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo) -{ - struct vkBeginCommandBuffer_params params; - NTSTATUS status; - params.commandBuffer = commandBuffer; - params.pBeginInfo = pBeginInfo; - status = UNIX_CALL(vkBeginCommandBuffer, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkBindAccelerationStructureMemoryNV(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNV *pBindInfos) -{ - struct vkBindAccelerationStructureMemoryNV_params params; - NTSTATUS status; - params.device = device; - params.bindInfoCount = bindInfoCount; - params.pBindInfos = pBindInfos; - status = UNIX_CALL(vkBindAccelerationStructureMemoryNV, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset) -{ - struct vkBindBufferMemory_params params; - NTSTATUS status; - params.device = device; - params.buffer = buffer; - params.memory = memory; - params.memoryOffset = memoryOffset; - status = UNIX_CALL(vkBindBufferMemory, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkBindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo *pBindInfos) -{ - struct vkBindBufferMemory2_params params; - NTSTATUS status; - params.device = device; - params.bindInfoCount = bindInfoCount; - params.pBindInfos = pBindInfos; - status = UNIX_CALL(vkBindBufferMemory2, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkBindBufferMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo *pBindInfos) -{ - struct vkBindBufferMemory2KHR_params params; - NTSTATUS status; - params.device = device; - params.bindInfoCount = bindInfoCount; - params.pBindInfos = pBindInfos; - status = UNIX_CALL(vkBindBufferMemory2KHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset) -{ - struct vkBindImageMemory_params params; - NTSTATUS status; - params.device = device; - params.image = image; - params.memory = memory; - params.memoryOffset = memoryOffset; - status = UNIX_CALL(vkBindImageMemory, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo *pBindInfos) -{ - struct vkBindImageMemory2_params params; - NTSTATUS status; - params.device = device; - params.bindInfoCount = bindInfoCount; - params.pBindInfos = pBindInfos; - status = UNIX_CALL(vkBindImageMemory2, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkBindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo *pBindInfos) -{ - struct vkBindImageMemory2KHR_params params; - NTSTATUS status; - params.device = device; - params.bindInfoCount = bindInfoCount; - params.pBindInfos = pBindInfos; - status = UNIX_CALL(vkBindImageMemory2KHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkBindOpticalFlowSessionImageNV(VkDevice device, VkOpticalFlowSessionNV session, VkOpticalFlowSessionBindingPointNV bindingPoint, VkImageView view, VkImageLayout layout) -{ - struct vkBindOpticalFlowSessionImageNV_params params; - NTSTATUS status; - params.device = device; - params.session = session; - params.bindingPoint = bindingPoint; - params.view = view; - params.layout = layout; - status = UNIX_CALL(vkBindOpticalFlowSessionImageNV, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkBuildAccelerationStructuresKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR *pInfos, const VkAccelerationStructureBuildRangeInfoKHR * const*ppBuildRangeInfos) -{ - struct vkBuildAccelerationStructuresKHR_params params; - NTSTATUS status; - params.device = device; - params.deferredOperation = deferredOperation; - params.infoCount = infoCount; - params.pInfos = pInfos; - params.ppBuildRangeInfos = ppBuildRangeInfos; - status = UNIX_CALL(vkBuildAccelerationStructuresKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkBuildMicromapsEXT(VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount, const VkMicromapBuildInfoEXT *pInfos) -{ - struct vkBuildMicromapsEXT_params params; - NTSTATUS status; - params.device = device; - params.deferredOperation = deferredOperation; - params.infoCount = infoCount; - params.pInfos = pInfos; - status = UNIX_CALL(vkBuildMicromapsEXT, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkCmdBeginConditionalRenderingEXT(VkCommandBuffer commandBuffer, const VkConditionalRenderingBeginInfoEXT *pConditionalRenderingBegin) -{ - struct vkCmdBeginConditionalRenderingEXT_params params; - params.commandBuffer = commandBuffer; - params.pConditionalRenderingBegin = pConditionalRenderingBegin; - UNIX_CALL(vkCmdBeginConditionalRenderingEXT, ¶ms); -} - -void WINAPI vkCmdBeginDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT *pLabelInfo) -{ - struct vkCmdBeginDebugUtilsLabelEXT_params params; - params.commandBuffer = commandBuffer; - params.pLabelInfo = pLabelInfo; - UNIX_CALL(vkCmdBeginDebugUtilsLabelEXT, ¶ms); -} - -void WINAPI vkCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags) -{ - struct vkCmdBeginQuery_params params; - params.commandBuffer = commandBuffer; - params.queryPool = queryPool; - params.query = query; - params.flags = flags; - UNIX_CALL(vkCmdBeginQuery, ¶ms); -} - -void WINAPI vkCmdBeginQueryIndexedEXT(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags, uint32_t index) -{ - struct vkCmdBeginQueryIndexedEXT_params params; - params.commandBuffer = commandBuffer; - params.queryPool = queryPool; - params.query = query; - params.flags = flags; - params.index = index; - UNIX_CALL(vkCmdBeginQueryIndexedEXT, ¶ms); -} - -void WINAPI vkCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, VkSubpassContents contents) -{ - struct vkCmdBeginRenderPass_params params; - params.commandBuffer = commandBuffer; - params.pRenderPassBegin = pRenderPassBegin; - params.contents = contents; - UNIX_CALL(vkCmdBeginRenderPass, ¶ms); -} - -void WINAPI vkCmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, const VkSubpassBeginInfo *pSubpassBeginInfo) -{ - struct vkCmdBeginRenderPass2_params params; - params.commandBuffer = commandBuffer; - params.pRenderPassBegin = pRenderPassBegin; - params.pSubpassBeginInfo = pSubpassBeginInfo; - UNIX_CALL(vkCmdBeginRenderPass2, ¶ms); -} - -void WINAPI vkCmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, const VkSubpassBeginInfo *pSubpassBeginInfo) -{ - struct vkCmdBeginRenderPass2KHR_params params; - params.commandBuffer = commandBuffer; - params.pRenderPassBegin = pRenderPassBegin; - params.pSubpassBeginInfo = pSubpassBeginInfo; - UNIX_CALL(vkCmdBeginRenderPass2KHR, ¶ms); -} - -void WINAPI vkCmdBeginRendering(VkCommandBuffer commandBuffer, const VkRenderingInfo *pRenderingInfo) -{ - struct vkCmdBeginRendering_params params; - params.commandBuffer = commandBuffer; - params.pRenderingInfo = pRenderingInfo; - UNIX_CALL(vkCmdBeginRendering, ¶ms); -} - -void WINAPI vkCmdBeginRenderingKHR(VkCommandBuffer commandBuffer, const VkRenderingInfo *pRenderingInfo) -{ - struct vkCmdBeginRenderingKHR_params params; - params.commandBuffer = commandBuffer; - params.pRenderingInfo = pRenderingInfo; - UNIX_CALL(vkCmdBeginRenderingKHR, ¶ms); -} - -void WINAPI vkCmdBeginTransformFeedbackEXT(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer *pCounterBuffers, const VkDeviceSize *pCounterBufferOffsets) -{ - struct vkCmdBeginTransformFeedbackEXT_params params; - params.commandBuffer = commandBuffer; - params.firstCounterBuffer = firstCounterBuffer; - params.counterBufferCount = counterBufferCount; - params.pCounterBuffers = pCounterBuffers; - params.pCounterBufferOffsets = pCounterBufferOffsets; - UNIX_CALL(vkCmdBeginTransformFeedbackEXT, ¶ms); -} - -void WINAPI vkCmdBindDescriptorBufferEmbeddedSamplersEXT(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set) -{ - struct vkCmdBindDescriptorBufferEmbeddedSamplersEXT_params params; - params.commandBuffer = commandBuffer; - params.pipelineBindPoint = pipelineBindPoint; - params.layout = layout; - params.set = set; - UNIX_CALL(vkCmdBindDescriptorBufferEmbeddedSamplersEXT, ¶ms); -} - -void WINAPI vkCmdBindDescriptorBuffersEXT(VkCommandBuffer commandBuffer, uint32_t bufferCount, const VkDescriptorBufferBindingInfoEXT *pBindingInfos) -{ - struct vkCmdBindDescriptorBuffersEXT_params params; - params.commandBuffer = commandBuffer; - params.bufferCount = bufferCount; - params.pBindingInfos = pBindingInfos; - UNIX_CALL(vkCmdBindDescriptorBuffersEXT, ¶ms); -} - -void WINAPI vkCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t *pDynamicOffsets) -{ - struct vkCmdBindDescriptorSets_params params; - params.commandBuffer = commandBuffer; - params.pipelineBindPoint = pipelineBindPoint; - params.layout = layout; - params.firstSet = firstSet; - params.descriptorSetCount = descriptorSetCount; - params.pDescriptorSets = pDescriptorSets; - params.dynamicOffsetCount = dynamicOffsetCount; - params.pDynamicOffsets = pDynamicOffsets; - UNIX_CALL(vkCmdBindDescriptorSets, ¶ms); -} - -void WINAPI vkCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType) -{ - struct vkCmdBindIndexBuffer_params params; - params.commandBuffer = commandBuffer; - params.buffer = buffer; - params.offset = offset; - params.indexType = indexType; - UNIX_CALL(vkCmdBindIndexBuffer, ¶ms); -} - -void WINAPI vkCmdBindInvocationMaskHUAWEI(VkCommandBuffer commandBuffer, VkImageView imageView, VkImageLayout imageLayout) -{ - struct vkCmdBindInvocationMaskHUAWEI_params params; - params.commandBuffer = commandBuffer; - params.imageView = imageView; - params.imageLayout = imageLayout; - UNIX_CALL(vkCmdBindInvocationMaskHUAWEI, ¶ms); -} - -void WINAPI vkCmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline) -{ - struct vkCmdBindPipeline_params params; - params.commandBuffer = commandBuffer; - params.pipelineBindPoint = pipelineBindPoint; - params.pipeline = pipeline; - UNIX_CALL(vkCmdBindPipeline, ¶ms); -} - -void WINAPI vkCmdBindPipelineShaderGroupNV(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline, uint32_t groupIndex) -{ - struct vkCmdBindPipelineShaderGroupNV_params params; - params.commandBuffer = commandBuffer; - params.pipelineBindPoint = pipelineBindPoint; - params.pipeline = pipeline; - params.groupIndex = groupIndex; - UNIX_CALL(vkCmdBindPipelineShaderGroupNV, ¶ms); -} - -void WINAPI vkCmdBindShadingRateImageNV(VkCommandBuffer commandBuffer, VkImageView imageView, VkImageLayout imageLayout) -{ - struct vkCmdBindShadingRateImageNV_params params; - params.commandBuffer = commandBuffer; - params.imageView = imageView; - params.imageLayout = imageLayout; - UNIX_CALL(vkCmdBindShadingRateImageNV, ¶ms); -} - -void WINAPI vkCmdBindTransformFeedbackBuffersEXT(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers, const VkDeviceSize *pOffsets, const VkDeviceSize *pSizes) -{ - struct vkCmdBindTransformFeedbackBuffersEXT_params params; - params.commandBuffer = commandBuffer; - params.firstBinding = firstBinding; - params.bindingCount = bindingCount; - params.pBuffers = pBuffers; - params.pOffsets = pOffsets; - params.pSizes = pSizes; - UNIX_CALL(vkCmdBindTransformFeedbackBuffersEXT, ¶ms); -} - -void WINAPI vkCmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers, const VkDeviceSize *pOffsets) -{ - struct vkCmdBindVertexBuffers_params params; - params.commandBuffer = commandBuffer; - params.firstBinding = firstBinding; - params.bindingCount = bindingCount; - params.pBuffers = pBuffers; - params.pOffsets = pOffsets; - UNIX_CALL(vkCmdBindVertexBuffers, ¶ms); -} - -void WINAPI vkCmdBindVertexBuffers2(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers, const VkDeviceSize *pOffsets, const VkDeviceSize *pSizes, const VkDeviceSize *pStrides) -{ - struct vkCmdBindVertexBuffers2_params params; - params.commandBuffer = commandBuffer; - params.firstBinding = firstBinding; - params.bindingCount = bindingCount; - params.pBuffers = pBuffers; - params.pOffsets = pOffsets; - params.pSizes = pSizes; - params.pStrides = pStrides; - UNIX_CALL(vkCmdBindVertexBuffers2, ¶ms); -} - -void WINAPI vkCmdBindVertexBuffers2EXT(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers, const VkDeviceSize *pOffsets, const VkDeviceSize *pSizes, const VkDeviceSize *pStrides) -{ - struct vkCmdBindVertexBuffers2EXT_params params; - params.commandBuffer = commandBuffer; - params.firstBinding = firstBinding; - params.bindingCount = bindingCount; - params.pBuffers = pBuffers; - params.pOffsets = pOffsets; - params.pSizes = pSizes; - params.pStrides = pStrides; - UNIX_CALL(vkCmdBindVertexBuffers2EXT, ¶ms); -} - -void WINAPI vkCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit *pRegions, VkFilter filter) -{ - struct vkCmdBlitImage_params params; - params.commandBuffer = commandBuffer; - params.srcImage = srcImage; - params.srcImageLayout = srcImageLayout; - params.dstImage = dstImage; - params.dstImageLayout = dstImageLayout; - params.regionCount = regionCount; - params.pRegions = pRegions; - params.filter = filter; - UNIX_CALL(vkCmdBlitImage, ¶ms); -} - -void WINAPI vkCmdBlitImage2(VkCommandBuffer commandBuffer, const VkBlitImageInfo2 *pBlitImageInfo) -{ - struct vkCmdBlitImage2_params params; - params.commandBuffer = commandBuffer; - params.pBlitImageInfo = pBlitImageInfo; - UNIX_CALL(vkCmdBlitImage2, ¶ms); -} - -void WINAPI vkCmdBlitImage2KHR(VkCommandBuffer commandBuffer, const VkBlitImageInfo2 *pBlitImageInfo) -{ - struct vkCmdBlitImage2KHR_params params; - params.commandBuffer = commandBuffer; - params.pBlitImageInfo = pBlitImageInfo; - UNIX_CALL(vkCmdBlitImage2KHR, ¶ms); -} - -void WINAPI vkCmdBuildAccelerationStructureNV(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV *pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkBuffer scratch, VkDeviceSize scratchOffset) -{ - struct vkCmdBuildAccelerationStructureNV_params params; - params.commandBuffer = commandBuffer; - params.pInfo = pInfo; - params.instanceData = instanceData; - params.instanceOffset = instanceOffset; - params.update = update; - params.dst = dst; - params.src = src; - params.scratch = scratch; - params.scratchOffset = scratchOffset; - UNIX_CALL(vkCmdBuildAccelerationStructureNV, ¶ms); -} - -void WINAPI vkCmdBuildAccelerationStructuresIndirectKHR(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR *pInfos, const VkDeviceAddress *pIndirectDeviceAddresses, const uint32_t *pIndirectStrides, const uint32_t * const*ppMaxPrimitiveCounts) -{ - struct vkCmdBuildAccelerationStructuresIndirectKHR_params params; - params.commandBuffer = commandBuffer; - params.infoCount = infoCount; - params.pInfos = pInfos; - params.pIndirectDeviceAddresses = pIndirectDeviceAddresses; - params.pIndirectStrides = pIndirectStrides; - params.ppMaxPrimitiveCounts = ppMaxPrimitiveCounts; - UNIX_CALL(vkCmdBuildAccelerationStructuresIndirectKHR, ¶ms); -} - -void WINAPI vkCmdBuildAccelerationStructuresKHR(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR *pInfos, const VkAccelerationStructureBuildRangeInfoKHR * const*ppBuildRangeInfos) -{ - struct vkCmdBuildAccelerationStructuresKHR_params params; - params.commandBuffer = commandBuffer; - params.infoCount = infoCount; - params.pInfos = pInfos; - params.ppBuildRangeInfos = ppBuildRangeInfos; - UNIX_CALL(vkCmdBuildAccelerationStructuresKHR, ¶ms); -} - -void WINAPI vkCmdBuildMicromapsEXT(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkMicromapBuildInfoEXT *pInfos) -{ - struct vkCmdBuildMicromapsEXT_params params; - params.commandBuffer = commandBuffer; - params.infoCount = infoCount; - params.pInfos = pInfos; - UNIX_CALL(vkCmdBuildMicromapsEXT, ¶ms); -} - -void WINAPI vkCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment *pAttachments, uint32_t rectCount, const VkClearRect *pRects) -{ - struct vkCmdClearAttachments_params params; - params.commandBuffer = commandBuffer; - params.attachmentCount = attachmentCount; - params.pAttachments = pAttachments; - params.rectCount = rectCount; - params.pRects = pRects; - UNIX_CALL(vkCmdClearAttachments, ¶ms); -} - -void WINAPI vkCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue *pColor, uint32_t rangeCount, const VkImageSubresourceRange *pRanges) -{ - struct vkCmdClearColorImage_params params; - params.commandBuffer = commandBuffer; - params.image = image; - params.imageLayout = imageLayout; - params.pColor = pColor; - params.rangeCount = rangeCount; - params.pRanges = pRanges; - UNIX_CALL(vkCmdClearColorImage, ¶ms); -} - -void WINAPI vkCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange *pRanges) -{ - struct vkCmdClearDepthStencilImage_params params; - params.commandBuffer = commandBuffer; - params.image = image; - params.imageLayout = imageLayout; - params.pDepthStencil = pDepthStencil; - params.rangeCount = rangeCount; - params.pRanges = pRanges; - UNIX_CALL(vkCmdClearDepthStencilImage, ¶ms); -} - -void WINAPI vkCmdCopyAccelerationStructureKHR(VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureInfoKHR *pInfo) -{ - struct vkCmdCopyAccelerationStructureKHR_params params; - params.commandBuffer = commandBuffer; - params.pInfo = pInfo; - UNIX_CALL(vkCmdCopyAccelerationStructureKHR, ¶ms); -} - -void WINAPI vkCmdCopyAccelerationStructureNV(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkCopyAccelerationStructureModeKHR mode) -{ - struct vkCmdCopyAccelerationStructureNV_params params; - params.commandBuffer = commandBuffer; - params.dst = dst; - params.src = src; - params.mode = mode; - UNIX_CALL(vkCmdCopyAccelerationStructureNV, ¶ms); -} - -void WINAPI vkCmdCopyAccelerationStructureToMemoryKHR(VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureToMemoryInfoKHR *pInfo) -{ - struct vkCmdCopyAccelerationStructureToMemoryKHR_params params; - params.commandBuffer = commandBuffer; - params.pInfo = pInfo; - UNIX_CALL(vkCmdCopyAccelerationStructureToMemoryKHR, ¶ms); -} - -void WINAPI vkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy *pRegions) -{ - struct vkCmdCopyBuffer_params params; - params.commandBuffer = commandBuffer; - params.srcBuffer = srcBuffer; - params.dstBuffer = dstBuffer; - params.regionCount = regionCount; - params.pRegions = pRegions; - UNIX_CALL(vkCmdCopyBuffer, ¶ms); -} - -void WINAPI vkCmdCopyBuffer2(VkCommandBuffer commandBuffer, const VkCopyBufferInfo2 *pCopyBufferInfo) -{ - struct vkCmdCopyBuffer2_params params; - params.commandBuffer = commandBuffer; - params.pCopyBufferInfo = pCopyBufferInfo; - UNIX_CALL(vkCmdCopyBuffer2, ¶ms); -} - -void WINAPI vkCmdCopyBuffer2KHR(VkCommandBuffer commandBuffer, const VkCopyBufferInfo2 *pCopyBufferInfo) -{ - struct vkCmdCopyBuffer2KHR_params params; - params.commandBuffer = commandBuffer; - params.pCopyBufferInfo = pCopyBufferInfo; - UNIX_CALL(vkCmdCopyBuffer2KHR, ¶ms); -} - -void WINAPI vkCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy *pRegions) -{ - struct vkCmdCopyBufferToImage_params params; - params.commandBuffer = commandBuffer; - params.srcBuffer = srcBuffer; - params.dstImage = dstImage; - params.dstImageLayout = dstImageLayout; - params.regionCount = regionCount; - params.pRegions = pRegions; - UNIX_CALL(vkCmdCopyBufferToImage, ¶ms); -} - -void WINAPI vkCmdCopyBufferToImage2(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2 *pCopyBufferToImageInfo) -{ - struct vkCmdCopyBufferToImage2_params params; - params.commandBuffer = commandBuffer; - params.pCopyBufferToImageInfo = pCopyBufferToImageInfo; - UNIX_CALL(vkCmdCopyBufferToImage2, ¶ms); -} - -void WINAPI vkCmdCopyBufferToImage2KHR(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2 *pCopyBufferToImageInfo) -{ - struct vkCmdCopyBufferToImage2KHR_params params; - params.commandBuffer = commandBuffer; - params.pCopyBufferToImageInfo = pCopyBufferToImageInfo; - UNIX_CALL(vkCmdCopyBufferToImage2KHR, ¶ms); -} - -void WINAPI vkCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy *pRegions) -{ - struct vkCmdCopyImage_params params; - params.commandBuffer = commandBuffer; - params.srcImage = srcImage; - params.srcImageLayout = srcImageLayout; - params.dstImage = dstImage; - params.dstImageLayout = dstImageLayout; - params.regionCount = regionCount; - params.pRegions = pRegions; - UNIX_CALL(vkCmdCopyImage, ¶ms); -} - -void WINAPI vkCmdCopyImage2(VkCommandBuffer commandBuffer, const VkCopyImageInfo2 *pCopyImageInfo) -{ - struct vkCmdCopyImage2_params params; - params.commandBuffer = commandBuffer; - params.pCopyImageInfo = pCopyImageInfo; - UNIX_CALL(vkCmdCopyImage2, ¶ms); -} - -void WINAPI vkCmdCopyImage2KHR(VkCommandBuffer commandBuffer, const VkCopyImageInfo2 *pCopyImageInfo) -{ - struct vkCmdCopyImage2KHR_params params; - params.commandBuffer = commandBuffer; - params.pCopyImageInfo = pCopyImageInfo; - UNIX_CALL(vkCmdCopyImage2KHR, ¶ms); -} - -void WINAPI vkCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) -{ - struct vkCmdCopyImageToBuffer_params params; - params.commandBuffer = commandBuffer; - params.srcImage = srcImage; - params.srcImageLayout = srcImageLayout; - params.dstBuffer = dstBuffer; - params.regionCount = regionCount; - params.pRegions = pRegions; - UNIX_CALL(vkCmdCopyImageToBuffer, ¶ms); -} - -void WINAPI vkCmdCopyImageToBuffer2(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2 *pCopyImageToBufferInfo) -{ - struct vkCmdCopyImageToBuffer2_params params; - params.commandBuffer = commandBuffer; - params.pCopyImageToBufferInfo = pCopyImageToBufferInfo; - UNIX_CALL(vkCmdCopyImageToBuffer2, ¶ms); -} - -void WINAPI vkCmdCopyImageToBuffer2KHR(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2 *pCopyImageToBufferInfo) -{ - struct vkCmdCopyImageToBuffer2KHR_params params; - params.commandBuffer = commandBuffer; - params.pCopyImageToBufferInfo = pCopyImageToBufferInfo; - UNIX_CALL(vkCmdCopyImageToBuffer2KHR, ¶ms); -} - -void WINAPI vkCmdCopyMemoryIndirectNV(VkCommandBuffer commandBuffer, VkDeviceAddress copyBufferAddress, uint32_t copyCount, uint32_t stride) -{ - struct vkCmdCopyMemoryIndirectNV_params params; - params.commandBuffer = commandBuffer; - params.copyBufferAddress = copyBufferAddress; - params.copyCount = copyCount; - params.stride = stride; - UNIX_CALL(vkCmdCopyMemoryIndirectNV, ¶ms); -} - -void WINAPI vkCmdCopyMemoryToAccelerationStructureKHR(VkCommandBuffer commandBuffer, const VkCopyMemoryToAccelerationStructureInfoKHR *pInfo) -{ - struct vkCmdCopyMemoryToAccelerationStructureKHR_params params; - params.commandBuffer = commandBuffer; - params.pInfo = pInfo; - UNIX_CALL(vkCmdCopyMemoryToAccelerationStructureKHR, ¶ms); -} - -void WINAPI vkCmdCopyMemoryToImageIndirectNV(VkCommandBuffer commandBuffer, VkDeviceAddress copyBufferAddress, uint32_t copyCount, uint32_t stride, VkImage dstImage, VkImageLayout dstImageLayout, const VkImageSubresourceLayers *pImageSubresources) -{ - struct vkCmdCopyMemoryToImageIndirectNV_params params; - params.commandBuffer = commandBuffer; - params.copyBufferAddress = copyBufferAddress; - params.copyCount = copyCount; - params.stride = stride; - params.dstImage = dstImage; - params.dstImageLayout = dstImageLayout; - params.pImageSubresources = pImageSubresources; - UNIX_CALL(vkCmdCopyMemoryToImageIndirectNV, ¶ms); -} - -void WINAPI vkCmdCopyMemoryToMicromapEXT(VkCommandBuffer commandBuffer, const VkCopyMemoryToMicromapInfoEXT *pInfo) -{ - struct vkCmdCopyMemoryToMicromapEXT_params params; - params.commandBuffer = commandBuffer; - params.pInfo = pInfo; - UNIX_CALL(vkCmdCopyMemoryToMicromapEXT, ¶ms); -} - -void WINAPI vkCmdCopyMicromapEXT(VkCommandBuffer commandBuffer, const VkCopyMicromapInfoEXT *pInfo) -{ - struct vkCmdCopyMicromapEXT_params params; - params.commandBuffer = commandBuffer; - params.pInfo = pInfo; - UNIX_CALL(vkCmdCopyMicromapEXT, ¶ms); -} - -void WINAPI vkCmdCopyMicromapToMemoryEXT(VkCommandBuffer commandBuffer, const VkCopyMicromapToMemoryInfoEXT *pInfo) -{ - struct vkCmdCopyMicromapToMemoryEXT_params params; - params.commandBuffer = commandBuffer; - params.pInfo = pInfo; - UNIX_CALL(vkCmdCopyMicromapToMemoryEXT, ¶ms); -} - -void WINAPI vkCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags) -{ - struct vkCmdCopyQueryPoolResults_params params; - params.commandBuffer = commandBuffer; - params.queryPool = queryPool; - params.firstQuery = firstQuery; - params.queryCount = queryCount; - params.dstBuffer = dstBuffer; - params.dstOffset = dstOffset; - params.stride = stride; - params.flags = flags; - UNIX_CALL(vkCmdCopyQueryPoolResults, ¶ms); -} - -void WINAPI vkCmdCuLaunchKernelNVX(VkCommandBuffer commandBuffer, const VkCuLaunchInfoNVX *pLaunchInfo) -{ - struct vkCmdCuLaunchKernelNVX_params params; - params.commandBuffer = commandBuffer; - params.pLaunchInfo = pLaunchInfo; - UNIX_CALL(vkCmdCuLaunchKernelNVX, ¶ms); -} - -void WINAPI vkCmdDebugMarkerBeginEXT(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT *pMarkerInfo) -{ - struct vkCmdDebugMarkerBeginEXT_params params; - params.commandBuffer = commandBuffer; - params.pMarkerInfo = pMarkerInfo; - UNIX_CALL(vkCmdDebugMarkerBeginEXT, ¶ms); -} - -void WINAPI vkCmdDebugMarkerEndEXT(VkCommandBuffer commandBuffer) -{ - struct vkCmdDebugMarkerEndEXT_params params; - params.commandBuffer = commandBuffer; - UNIX_CALL(vkCmdDebugMarkerEndEXT, ¶ms); -} - -void WINAPI vkCmdDebugMarkerInsertEXT(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT *pMarkerInfo) -{ - struct vkCmdDebugMarkerInsertEXT_params params; - params.commandBuffer = commandBuffer; - params.pMarkerInfo = pMarkerInfo; - UNIX_CALL(vkCmdDebugMarkerInsertEXT, ¶ms); -} - -void WINAPI vkCmdDecompressMemoryIndirectCountNV(VkCommandBuffer commandBuffer, VkDeviceAddress indirectCommandsAddress, VkDeviceAddress indirectCommandsCountAddress, uint32_t stride) -{ - struct vkCmdDecompressMemoryIndirectCountNV_params params; - params.commandBuffer = commandBuffer; - params.indirectCommandsAddress = indirectCommandsAddress; - params.indirectCommandsCountAddress = indirectCommandsCountAddress; - params.stride = stride; - UNIX_CALL(vkCmdDecompressMemoryIndirectCountNV, ¶ms); -} - -void WINAPI vkCmdDecompressMemoryNV(VkCommandBuffer commandBuffer, uint32_t decompressRegionCount, const VkDecompressMemoryRegionNV *pDecompressMemoryRegions) -{ - struct vkCmdDecompressMemoryNV_params params; - params.commandBuffer = commandBuffer; - params.decompressRegionCount = decompressRegionCount; - params.pDecompressMemoryRegions = pDecompressMemoryRegions; - UNIX_CALL(vkCmdDecompressMemoryNV, ¶ms); -} - -void WINAPI vkCmdDispatch(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) -{ - struct vkCmdDispatch_params params; - params.commandBuffer = commandBuffer; - params.groupCountX = groupCountX; - params.groupCountY = groupCountY; - params.groupCountZ = groupCountZ; - UNIX_CALL(vkCmdDispatch, ¶ms); -} - -void WINAPI vkCmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) -{ - struct vkCmdDispatchBase_params params; - params.commandBuffer = commandBuffer; - params.baseGroupX = baseGroupX; - params.baseGroupY = baseGroupY; - params.baseGroupZ = baseGroupZ; - params.groupCountX = groupCountX; - params.groupCountY = groupCountY; - params.groupCountZ = groupCountZ; - UNIX_CALL(vkCmdDispatchBase, ¶ms); -} - -void WINAPI vkCmdDispatchBaseKHR(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) -{ - struct vkCmdDispatchBaseKHR_params params; - params.commandBuffer = commandBuffer; - params.baseGroupX = baseGroupX; - params.baseGroupY = baseGroupY; - params.baseGroupZ = baseGroupZ; - params.groupCountX = groupCountX; - params.groupCountY = groupCountY; - params.groupCountZ = groupCountZ; - UNIX_CALL(vkCmdDispatchBaseKHR, ¶ms); -} - -void WINAPI vkCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) -{ - struct vkCmdDispatchIndirect_params params; - params.commandBuffer = commandBuffer; - params.buffer = buffer; - params.offset = offset; - UNIX_CALL(vkCmdDispatchIndirect, ¶ms); -} - -void WINAPI vkCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) -{ - struct vkCmdDraw_params params; - params.commandBuffer = commandBuffer; - params.vertexCount = vertexCount; - params.instanceCount = instanceCount; - params.firstVertex = firstVertex; - params.firstInstance = firstInstance; - UNIX_CALL(vkCmdDraw, ¶ms); -} - -void WINAPI vkCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance) -{ - struct vkCmdDrawIndexed_params params; - params.commandBuffer = commandBuffer; - params.indexCount = indexCount; - params.instanceCount = instanceCount; - params.firstIndex = firstIndex; - params.vertexOffset = vertexOffset; - params.firstInstance = firstInstance; - UNIX_CALL(vkCmdDrawIndexed, ¶ms); -} - -void WINAPI vkCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride) -{ - struct vkCmdDrawIndexedIndirect_params params; - params.commandBuffer = commandBuffer; - params.buffer = buffer; - params.offset = offset; - params.drawCount = drawCount; - params.stride = stride; - UNIX_CALL(vkCmdDrawIndexedIndirect, ¶ms); -} - -void WINAPI vkCmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) -{ - struct vkCmdDrawIndexedIndirectCount_params params; - params.commandBuffer = commandBuffer; - params.buffer = buffer; - params.offset = offset; - params.countBuffer = countBuffer; - params.countBufferOffset = countBufferOffset; - params.maxDrawCount = maxDrawCount; - params.stride = stride; - UNIX_CALL(vkCmdDrawIndexedIndirectCount, ¶ms); -} - -void WINAPI vkCmdDrawIndexedIndirectCountAMD(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) -{ - struct vkCmdDrawIndexedIndirectCountAMD_params params; - params.commandBuffer = commandBuffer; - params.buffer = buffer; - params.offset = offset; - params.countBuffer = countBuffer; - params.countBufferOffset = countBufferOffset; - params.maxDrawCount = maxDrawCount; - params.stride = stride; - UNIX_CALL(vkCmdDrawIndexedIndirectCountAMD, ¶ms); -} - -void WINAPI vkCmdDrawIndexedIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) -{ - struct vkCmdDrawIndexedIndirectCountKHR_params params; - params.commandBuffer = commandBuffer; - params.buffer = buffer; - params.offset = offset; - params.countBuffer = countBuffer; - params.countBufferOffset = countBufferOffset; - params.maxDrawCount = maxDrawCount; - params.stride = stride; - UNIX_CALL(vkCmdDrawIndexedIndirectCountKHR, ¶ms); -} - -void WINAPI vkCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride) -{ - struct vkCmdDrawIndirect_params params; - params.commandBuffer = commandBuffer; - params.buffer = buffer; - params.offset = offset; - params.drawCount = drawCount; - params.stride = stride; - UNIX_CALL(vkCmdDrawIndirect, ¶ms); -} - -void WINAPI vkCmdDrawIndirectByteCountEXT(VkCommandBuffer commandBuffer, uint32_t instanceCount, uint32_t firstInstance, VkBuffer counterBuffer, VkDeviceSize counterBufferOffset, uint32_t counterOffset, uint32_t vertexStride) -{ - struct vkCmdDrawIndirectByteCountEXT_params params; - params.commandBuffer = commandBuffer; - params.instanceCount = instanceCount; - params.firstInstance = firstInstance; - params.counterBuffer = counterBuffer; - params.counterBufferOffset = counterBufferOffset; - params.counterOffset = counterOffset; - params.vertexStride = vertexStride; - UNIX_CALL(vkCmdDrawIndirectByteCountEXT, ¶ms); -} - -void WINAPI vkCmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) -{ - struct vkCmdDrawIndirectCount_params params; - params.commandBuffer = commandBuffer; - params.buffer = buffer; - params.offset = offset; - params.countBuffer = countBuffer; - params.countBufferOffset = countBufferOffset; - params.maxDrawCount = maxDrawCount; - params.stride = stride; - UNIX_CALL(vkCmdDrawIndirectCount, ¶ms); -} - -void WINAPI vkCmdDrawIndirectCountAMD(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) -{ - struct vkCmdDrawIndirectCountAMD_params params; - params.commandBuffer = commandBuffer; - params.buffer = buffer; - params.offset = offset; - params.countBuffer = countBuffer; - params.countBufferOffset = countBufferOffset; - params.maxDrawCount = maxDrawCount; - params.stride = stride; - UNIX_CALL(vkCmdDrawIndirectCountAMD, ¶ms); -} - -void WINAPI vkCmdDrawIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) -{ - struct vkCmdDrawIndirectCountKHR_params params; - params.commandBuffer = commandBuffer; - params.buffer = buffer; - params.offset = offset; - params.countBuffer = countBuffer; - params.countBufferOffset = countBufferOffset; - params.maxDrawCount = maxDrawCount; - params.stride = stride; - UNIX_CALL(vkCmdDrawIndirectCountKHR, ¶ms); -} - -void WINAPI vkCmdDrawMeshTasksEXT(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) -{ - struct vkCmdDrawMeshTasksEXT_params params; - params.commandBuffer = commandBuffer; - params.groupCountX = groupCountX; - params.groupCountY = groupCountY; - params.groupCountZ = groupCountZ; - UNIX_CALL(vkCmdDrawMeshTasksEXT, ¶ms); -} - -void WINAPI vkCmdDrawMeshTasksIndirectCountEXT(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) -{ - struct vkCmdDrawMeshTasksIndirectCountEXT_params params; - params.commandBuffer = commandBuffer; - params.buffer = buffer; - params.offset = offset; - params.countBuffer = countBuffer; - params.countBufferOffset = countBufferOffset; - params.maxDrawCount = maxDrawCount; - params.stride = stride; - UNIX_CALL(vkCmdDrawMeshTasksIndirectCountEXT, ¶ms); -} - -void WINAPI vkCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) -{ - struct vkCmdDrawMeshTasksIndirectCountNV_params params; - params.commandBuffer = commandBuffer; - params.buffer = buffer; - params.offset = offset; - params.countBuffer = countBuffer; - params.countBufferOffset = countBufferOffset; - params.maxDrawCount = maxDrawCount; - params.stride = stride; - UNIX_CALL(vkCmdDrawMeshTasksIndirectCountNV, ¶ms); -} - -void WINAPI vkCmdDrawMeshTasksIndirectEXT(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride) -{ - struct vkCmdDrawMeshTasksIndirectEXT_params params; - params.commandBuffer = commandBuffer; - params.buffer = buffer; - params.offset = offset; - params.drawCount = drawCount; - params.stride = stride; - UNIX_CALL(vkCmdDrawMeshTasksIndirectEXT, ¶ms); -} - -void WINAPI vkCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride) -{ - struct vkCmdDrawMeshTasksIndirectNV_params params; - params.commandBuffer = commandBuffer; - params.buffer = buffer; - params.offset = offset; - params.drawCount = drawCount; - params.stride = stride; - UNIX_CALL(vkCmdDrawMeshTasksIndirectNV, ¶ms); -} - -void WINAPI vkCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask) -{ - struct vkCmdDrawMeshTasksNV_params params; - params.commandBuffer = commandBuffer; - params.taskCount = taskCount; - params.firstTask = firstTask; - UNIX_CALL(vkCmdDrawMeshTasksNV, ¶ms); -} - -void WINAPI vkCmdDrawMultiEXT(VkCommandBuffer commandBuffer, uint32_t drawCount, const VkMultiDrawInfoEXT *pVertexInfo, uint32_t instanceCount, uint32_t firstInstance, uint32_t stride) -{ - struct vkCmdDrawMultiEXT_params params; - params.commandBuffer = commandBuffer; - params.drawCount = drawCount; - params.pVertexInfo = pVertexInfo; - params.instanceCount = instanceCount; - params.firstInstance = firstInstance; - params.stride = stride; - UNIX_CALL(vkCmdDrawMultiEXT, ¶ms); -} - -void WINAPI vkCmdDrawMultiIndexedEXT(VkCommandBuffer commandBuffer, uint32_t drawCount, const VkMultiDrawIndexedInfoEXT *pIndexInfo, uint32_t instanceCount, uint32_t firstInstance, uint32_t stride, const int32_t *pVertexOffset) -{ - struct vkCmdDrawMultiIndexedEXT_params params; - params.commandBuffer = commandBuffer; - params.drawCount = drawCount; - params.pIndexInfo = pIndexInfo; - params.instanceCount = instanceCount; - params.firstInstance = firstInstance; - params.stride = stride; - params.pVertexOffset = pVertexOffset; - UNIX_CALL(vkCmdDrawMultiIndexedEXT, ¶ms); -} - -void WINAPI vkCmdEndConditionalRenderingEXT(VkCommandBuffer commandBuffer) -{ - struct vkCmdEndConditionalRenderingEXT_params params; - params.commandBuffer = commandBuffer; - UNIX_CALL(vkCmdEndConditionalRenderingEXT, ¶ms); -} - -void WINAPI vkCmdEndDebugUtilsLabelEXT(VkCommandBuffer commandBuffer) -{ - struct vkCmdEndDebugUtilsLabelEXT_params params; - params.commandBuffer = commandBuffer; - UNIX_CALL(vkCmdEndDebugUtilsLabelEXT, ¶ms); -} - -void WINAPI vkCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query) -{ - struct vkCmdEndQuery_params params; - params.commandBuffer = commandBuffer; - params.queryPool = queryPool; - params.query = query; - UNIX_CALL(vkCmdEndQuery, ¶ms); -} - -void WINAPI vkCmdEndQueryIndexedEXT(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, uint32_t index) -{ - struct vkCmdEndQueryIndexedEXT_params params; - params.commandBuffer = commandBuffer; - params.queryPool = queryPool; - params.query = query; - params.index = index; - UNIX_CALL(vkCmdEndQueryIndexedEXT, ¶ms); -} - -void WINAPI vkCmdEndRenderPass(VkCommandBuffer commandBuffer) -{ - struct vkCmdEndRenderPass_params params; - params.commandBuffer = commandBuffer; - UNIX_CALL(vkCmdEndRenderPass, ¶ms); -} - -void WINAPI vkCmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) -{ - struct vkCmdEndRenderPass2_params params; - params.commandBuffer = commandBuffer; - params.pSubpassEndInfo = pSubpassEndInfo; - UNIX_CALL(vkCmdEndRenderPass2, ¶ms); -} - -void WINAPI vkCmdEndRenderPass2KHR(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo) -{ - struct vkCmdEndRenderPass2KHR_params params; - params.commandBuffer = commandBuffer; - params.pSubpassEndInfo = pSubpassEndInfo; - UNIX_CALL(vkCmdEndRenderPass2KHR, ¶ms); -} - -void WINAPI vkCmdEndRendering(VkCommandBuffer commandBuffer) -{ - struct vkCmdEndRendering_params params; - params.commandBuffer = commandBuffer; - UNIX_CALL(vkCmdEndRendering, ¶ms); -} - -void WINAPI vkCmdEndRenderingKHR(VkCommandBuffer commandBuffer) -{ - struct vkCmdEndRenderingKHR_params params; - params.commandBuffer = commandBuffer; - UNIX_CALL(vkCmdEndRenderingKHR, ¶ms); -} - -void WINAPI vkCmdEndTransformFeedbackEXT(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer *pCounterBuffers, const VkDeviceSize *pCounterBufferOffsets) -{ - struct vkCmdEndTransformFeedbackEXT_params params; - params.commandBuffer = commandBuffer; - params.firstCounterBuffer = firstCounterBuffer; - params.counterBufferCount = counterBufferCount; - params.pCounterBuffers = pCounterBuffers; - params.pCounterBufferOffsets = pCounterBufferOffsets; - UNIX_CALL(vkCmdEndTransformFeedbackEXT, ¶ms); -} - -void WINAPI vkCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers) -{ - struct vkCmdExecuteCommands_params params; - params.commandBuffer = commandBuffer; - params.commandBufferCount = commandBufferCount; - params.pCommandBuffers = pCommandBuffers; - UNIX_CALL(vkCmdExecuteCommands, ¶ms); -} - -void WINAPI vkCmdExecuteGeneratedCommandsNV(VkCommandBuffer commandBuffer, VkBool32 isPreprocessed, const VkGeneratedCommandsInfoNV *pGeneratedCommandsInfo) -{ - struct vkCmdExecuteGeneratedCommandsNV_params params; - params.commandBuffer = commandBuffer; - params.isPreprocessed = isPreprocessed; - params.pGeneratedCommandsInfo = pGeneratedCommandsInfo; - UNIX_CALL(vkCmdExecuteGeneratedCommandsNV, ¶ms); -} - -void WINAPI vkCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data) -{ - struct vkCmdFillBuffer_params params; - params.commandBuffer = commandBuffer; - params.dstBuffer = dstBuffer; - params.dstOffset = dstOffset; - params.size = size; - params.data = data; - UNIX_CALL(vkCmdFillBuffer, ¶ms); -} - -void WINAPI vkCmdInsertDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT *pLabelInfo) -{ - struct vkCmdInsertDebugUtilsLabelEXT_params params; - params.commandBuffer = commandBuffer; - params.pLabelInfo = pLabelInfo; - UNIX_CALL(vkCmdInsertDebugUtilsLabelEXT, ¶ms); -} - -void WINAPI vkCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents) -{ - struct vkCmdNextSubpass_params params; - params.commandBuffer = commandBuffer; - params.contents = contents; - UNIX_CALL(vkCmdNextSubpass, ¶ms); -} - -void WINAPI vkCmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo, const VkSubpassEndInfo *pSubpassEndInfo) -{ - struct vkCmdNextSubpass2_params params; - params.commandBuffer = commandBuffer; - params.pSubpassBeginInfo = pSubpassBeginInfo; - params.pSubpassEndInfo = pSubpassEndInfo; - UNIX_CALL(vkCmdNextSubpass2, ¶ms); -} - -void WINAPI vkCmdNextSubpass2KHR(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo, const VkSubpassEndInfo *pSubpassEndInfo) -{ - struct vkCmdNextSubpass2KHR_params params; - params.commandBuffer = commandBuffer; - params.pSubpassBeginInfo = pSubpassBeginInfo; - params.pSubpassEndInfo = pSubpassEndInfo; - UNIX_CALL(vkCmdNextSubpass2KHR, ¶ms); -} - -void WINAPI vkCmdOpticalFlowExecuteNV(VkCommandBuffer commandBuffer, VkOpticalFlowSessionNV session, const VkOpticalFlowExecuteInfoNV *pExecuteInfo) -{ - struct vkCmdOpticalFlowExecuteNV_params params; - params.commandBuffer = commandBuffer; - params.session = session; - params.pExecuteInfo = pExecuteInfo; - UNIX_CALL(vkCmdOpticalFlowExecuteNV, ¶ms); -} - -void WINAPI vkCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) -{ - struct vkCmdPipelineBarrier_params params; - params.commandBuffer = commandBuffer; - params.srcStageMask = srcStageMask; - params.dstStageMask = dstStageMask; - params.dependencyFlags = dependencyFlags; - params.memoryBarrierCount = memoryBarrierCount; - params.pMemoryBarriers = pMemoryBarriers; - params.bufferMemoryBarrierCount = bufferMemoryBarrierCount; - params.pBufferMemoryBarriers = pBufferMemoryBarriers; - params.imageMemoryBarrierCount = imageMemoryBarrierCount; - params.pImageMemoryBarriers = pImageMemoryBarriers; - UNIX_CALL(vkCmdPipelineBarrier, ¶ms); -} - -void WINAPI vkCmdPipelineBarrier2(VkCommandBuffer commandBuffer, const VkDependencyInfo *pDependencyInfo) -{ - struct vkCmdPipelineBarrier2_params params; - params.commandBuffer = commandBuffer; - params.pDependencyInfo = pDependencyInfo; - UNIX_CALL(vkCmdPipelineBarrier2, ¶ms); -} - -void WINAPI vkCmdPipelineBarrier2KHR(VkCommandBuffer commandBuffer, const VkDependencyInfo *pDependencyInfo) -{ - struct vkCmdPipelineBarrier2KHR_params params; - params.commandBuffer = commandBuffer; - params.pDependencyInfo = pDependencyInfo; - UNIX_CALL(vkCmdPipelineBarrier2KHR, ¶ms); -} - -void WINAPI vkCmdPreprocessGeneratedCommandsNV(VkCommandBuffer commandBuffer, const VkGeneratedCommandsInfoNV *pGeneratedCommandsInfo) -{ - struct vkCmdPreprocessGeneratedCommandsNV_params params; - params.commandBuffer = commandBuffer; - params.pGeneratedCommandsInfo = pGeneratedCommandsInfo; - UNIX_CALL(vkCmdPreprocessGeneratedCommandsNV, ¶ms); -} - -void WINAPI vkCmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void *pValues) -{ - struct vkCmdPushConstants_params params; - params.commandBuffer = commandBuffer; - params.layout = layout; - params.stageFlags = stageFlags; - params.offset = offset; - params.size = size; - params.pValues = pValues; - UNIX_CALL(vkCmdPushConstants, ¶ms); -} - -void WINAPI vkCmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites) -{ - struct vkCmdPushDescriptorSetKHR_params params; - params.commandBuffer = commandBuffer; - params.pipelineBindPoint = pipelineBindPoint; - params.layout = layout; - params.set = set; - params.descriptorWriteCount = descriptorWriteCount; - params.pDescriptorWrites = pDescriptorWrites; - UNIX_CALL(vkCmdPushDescriptorSetKHR, ¶ms); -} - -void WINAPI vkCmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplate descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void *pData) -{ - struct vkCmdPushDescriptorSetWithTemplateKHR_params params; - params.commandBuffer = commandBuffer; - params.descriptorUpdateTemplate = descriptorUpdateTemplate; - params.layout = layout; - params.set = set; - params.pData = pData; - UNIX_CALL(vkCmdPushDescriptorSetWithTemplateKHR, ¶ms); -} - -void WINAPI vkCmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) -{ - struct vkCmdResetEvent_params params; - params.commandBuffer = commandBuffer; - params.event = event; - params.stageMask = stageMask; - UNIX_CALL(vkCmdResetEvent, ¶ms); -} - -void WINAPI vkCmdResetEvent2(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags2 stageMask) -{ - struct vkCmdResetEvent2_params params; - params.commandBuffer = commandBuffer; - params.event = event; - params.stageMask = stageMask; - UNIX_CALL(vkCmdResetEvent2, ¶ms); -} - -void WINAPI vkCmdResetEvent2KHR(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags2 stageMask) -{ - struct vkCmdResetEvent2KHR_params params; - params.commandBuffer = commandBuffer; - params.event = event; - params.stageMask = stageMask; - UNIX_CALL(vkCmdResetEvent2KHR, ¶ms); -} - -void WINAPI vkCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) -{ - struct vkCmdResetQueryPool_params params; - params.commandBuffer = commandBuffer; - params.queryPool = queryPool; - params.firstQuery = firstQuery; - params.queryCount = queryCount; - UNIX_CALL(vkCmdResetQueryPool, ¶ms); -} - -void WINAPI vkCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve *pRegions) -{ - struct vkCmdResolveImage_params params; - params.commandBuffer = commandBuffer; - params.srcImage = srcImage; - params.srcImageLayout = srcImageLayout; - params.dstImage = dstImage; - params.dstImageLayout = dstImageLayout; - params.regionCount = regionCount; - params.pRegions = pRegions; - UNIX_CALL(vkCmdResolveImage, ¶ms); -} - -void WINAPI vkCmdResolveImage2(VkCommandBuffer commandBuffer, const VkResolveImageInfo2 *pResolveImageInfo) -{ - struct vkCmdResolveImage2_params params; - params.commandBuffer = commandBuffer; - params.pResolveImageInfo = pResolveImageInfo; - UNIX_CALL(vkCmdResolveImage2, ¶ms); -} - -void WINAPI vkCmdResolveImage2KHR(VkCommandBuffer commandBuffer, const VkResolveImageInfo2 *pResolveImageInfo) -{ - struct vkCmdResolveImage2KHR_params params; - params.commandBuffer = commandBuffer; - params.pResolveImageInfo = pResolveImageInfo; - UNIX_CALL(vkCmdResolveImage2KHR, ¶ms); -} - -void WINAPI vkCmdSetAlphaToCoverageEnableEXT(VkCommandBuffer commandBuffer, VkBool32 alphaToCoverageEnable) -{ - struct vkCmdSetAlphaToCoverageEnableEXT_params params; - params.commandBuffer = commandBuffer; - params.alphaToCoverageEnable = alphaToCoverageEnable; - UNIX_CALL(vkCmdSetAlphaToCoverageEnableEXT, ¶ms); -} - -void WINAPI vkCmdSetAlphaToOneEnableEXT(VkCommandBuffer commandBuffer, VkBool32 alphaToOneEnable) -{ - struct vkCmdSetAlphaToOneEnableEXT_params params; - params.commandBuffer = commandBuffer; - params.alphaToOneEnable = alphaToOneEnable; - UNIX_CALL(vkCmdSetAlphaToOneEnableEXT, ¶ms); -} - -void WINAPI vkCmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]) -{ - struct vkCmdSetBlendConstants_params params; - params.commandBuffer = commandBuffer; - params.blendConstants = blendConstants; - UNIX_CALL(vkCmdSetBlendConstants, ¶ms); -} - -void WINAPI vkCmdSetCheckpointNV(VkCommandBuffer commandBuffer, const void *pCheckpointMarker) -{ - struct vkCmdSetCheckpointNV_params params; - params.commandBuffer = commandBuffer; - params.pCheckpointMarker = pCheckpointMarker; - UNIX_CALL(vkCmdSetCheckpointNV, ¶ms); -} - -void WINAPI vkCmdSetCoarseSampleOrderNV(VkCommandBuffer commandBuffer, VkCoarseSampleOrderTypeNV sampleOrderType, uint32_t customSampleOrderCount, const VkCoarseSampleOrderCustomNV *pCustomSampleOrders) -{ - struct vkCmdSetCoarseSampleOrderNV_params params; - params.commandBuffer = commandBuffer; - params.sampleOrderType = sampleOrderType; - params.customSampleOrderCount = customSampleOrderCount; - params.pCustomSampleOrders = pCustomSampleOrders; - UNIX_CALL(vkCmdSetCoarseSampleOrderNV, ¶ms); -} - -void WINAPI vkCmdSetColorBlendAdvancedEXT(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorBlendAdvancedEXT *pColorBlendAdvanced) -{ - struct vkCmdSetColorBlendAdvancedEXT_params params; - params.commandBuffer = commandBuffer; - params.firstAttachment = firstAttachment; - params.attachmentCount = attachmentCount; - params.pColorBlendAdvanced = pColorBlendAdvanced; - UNIX_CALL(vkCmdSetColorBlendAdvancedEXT, ¶ms); -} - -void WINAPI vkCmdSetColorBlendEnableEXT(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkBool32 *pColorBlendEnables) -{ - struct vkCmdSetColorBlendEnableEXT_params params; - params.commandBuffer = commandBuffer; - params.firstAttachment = firstAttachment; - params.attachmentCount = attachmentCount; - params.pColorBlendEnables = pColorBlendEnables; - UNIX_CALL(vkCmdSetColorBlendEnableEXT, ¶ms); -} - -void WINAPI vkCmdSetColorBlendEquationEXT(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorBlendEquationEXT *pColorBlendEquations) -{ - struct vkCmdSetColorBlendEquationEXT_params params; - params.commandBuffer = commandBuffer; - params.firstAttachment = firstAttachment; - params.attachmentCount = attachmentCount; - params.pColorBlendEquations = pColorBlendEquations; - UNIX_CALL(vkCmdSetColorBlendEquationEXT, ¶ms); -} - -void WINAPI vkCmdSetColorWriteEnableEXT(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkBool32 *pColorWriteEnables) -{ - struct vkCmdSetColorWriteEnableEXT_params params; - params.commandBuffer = commandBuffer; - params.attachmentCount = attachmentCount; - params.pColorWriteEnables = pColorWriteEnables; - UNIX_CALL(vkCmdSetColorWriteEnableEXT, ¶ms); -} - -void WINAPI vkCmdSetColorWriteMaskEXT(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorComponentFlags *pColorWriteMasks) -{ - struct vkCmdSetColorWriteMaskEXT_params params; - params.commandBuffer = commandBuffer; - params.firstAttachment = firstAttachment; - params.attachmentCount = attachmentCount; - params.pColorWriteMasks = pColorWriteMasks; - UNIX_CALL(vkCmdSetColorWriteMaskEXT, ¶ms); -} - -void WINAPI vkCmdSetConservativeRasterizationModeEXT(VkCommandBuffer commandBuffer, VkConservativeRasterizationModeEXT conservativeRasterizationMode) -{ - struct vkCmdSetConservativeRasterizationModeEXT_params params; - params.commandBuffer = commandBuffer; - params.conservativeRasterizationMode = conservativeRasterizationMode; - UNIX_CALL(vkCmdSetConservativeRasterizationModeEXT, ¶ms); -} - -void WINAPI vkCmdSetCoverageModulationModeNV(VkCommandBuffer commandBuffer, VkCoverageModulationModeNV coverageModulationMode) -{ - struct vkCmdSetCoverageModulationModeNV_params params; - params.commandBuffer = commandBuffer; - params.coverageModulationMode = coverageModulationMode; - UNIX_CALL(vkCmdSetCoverageModulationModeNV, ¶ms); -} - -void WINAPI vkCmdSetCoverageModulationTableEnableNV(VkCommandBuffer commandBuffer, VkBool32 coverageModulationTableEnable) -{ - struct vkCmdSetCoverageModulationTableEnableNV_params params; - params.commandBuffer = commandBuffer; - params.coverageModulationTableEnable = coverageModulationTableEnable; - UNIX_CALL(vkCmdSetCoverageModulationTableEnableNV, ¶ms); -} - -void WINAPI vkCmdSetCoverageModulationTableNV(VkCommandBuffer commandBuffer, uint32_t coverageModulationTableCount, const float *pCoverageModulationTable) -{ - struct vkCmdSetCoverageModulationTableNV_params params; - params.commandBuffer = commandBuffer; - params.coverageModulationTableCount = coverageModulationTableCount; - params.pCoverageModulationTable = pCoverageModulationTable; - UNIX_CALL(vkCmdSetCoverageModulationTableNV, ¶ms); -} - -void WINAPI vkCmdSetCoverageReductionModeNV(VkCommandBuffer commandBuffer, VkCoverageReductionModeNV coverageReductionMode) -{ - struct vkCmdSetCoverageReductionModeNV_params params; - params.commandBuffer = commandBuffer; - params.coverageReductionMode = coverageReductionMode; - UNIX_CALL(vkCmdSetCoverageReductionModeNV, ¶ms); -} - -void WINAPI vkCmdSetCoverageToColorEnableNV(VkCommandBuffer commandBuffer, VkBool32 coverageToColorEnable) -{ - struct vkCmdSetCoverageToColorEnableNV_params params; - params.commandBuffer = commandBuffer; - params.coverageToColorEnable = coverageToColorEnable; - UNIX_CALL(vkCmdSetCoverageToColorEnableNV, ¶ms); -} - -void WINAPI vkCmdSetCoverageToColorLocationNV(VkCommandBuffer commandBuffer, uint32_t coverageToColorLocation) -{ - struct vkCmdSetCoverageToColorLocationNV_params params; - params.commandBuffer = commandBuffer; - params.coverageToColorLocation = coverageToColorLocation; - UNIX_CALL(vkCmdSetCoverageToColorLocationNV, ¶ms); -} - -void WINAPI vkCmdSetCullMode(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode) -{ - struct vkCmdSetCullMode_params params; - params.commandBuffer = commandBuffer; - params.cullMode = cullMode; - UNIX_CALL(vkCmdSetCullMode, ¶ms); -} - -void WINAPI vkCmdSetCullModeEXT(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode) -{ - struct vkCmdSetCullModeEXT_params params; - params.commandBuffer = commandBuffer; - params.cullMode = cullMode; - UNIX_CALL(vkCmdSetCullModeEXT, ¶ms); -} - -void WINAPI vkCmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor) -{ - struct vkCmdSetDepthBias_params params; - params.commandBuffer = commandBuffer; - params.depthBiasConstantFactor = depthBiasConstantFactor; - params.depthBiasClamp = depthBiasClamp; - params.depthBiasSlopeFactor = depthBiasSlopeFactor; - UNIX_CALL(vkCmdSetDepthBias, ¶ms); -} - -void WINAPI vkCmdSetDepthBiasEnable(VkCommandBuffer commandBuffer, VkBool32 depthBiasEnable) -{ - struct vkCmdSetDepthBiasEnable_params params; - params.commandBuffer = commandBuffer; - params.depthBiasEnable = depthBiasEnable; - UNIX_CALL(vkCmdSetDepthBiasEnable, ¶ms); -} - -void WINAPI vkCmdSetDepthBiasEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthBiasEnable) -{ - struct vkCmdSetDepthBiasEnableEXT_params params; - params.commandBuffer = commandBuffer; - params.depthBiasEnable = depthBiasEnable; - UNIX_CALL(vkCmdSetDepthBiasEnableEXT, ¶ms); -} - -void WINAPI vkCmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds) -{ - struct vkCmdSetDepthBounds_params params; - params.commandBuffer = commandBuffer; - params.minDepthBounds = minDepthBounds; - params.maxDepthBounds = maxDepthBounds; - UNIX_CALL(vkCmdSetDepthBounds, ¶ms); -} - -void WINAPI vkCmdSetDepthBoundsTestEnable(VkCommandBuffer commandBuffer, VkBool32 depthBoundsTestEnable) -{ - struct vkCmdSetDepthBoundsTestEnable_params params; - params.commandBuffer = commandBuffer; - params.depthBoundsTestEnable = depthBoundsTestEnable; - UNIX_CALL(vkCmdSetDepthBoundsTestEnable, ¶ms); -} - -void WINAPI vkCmdSetDepthBoundsTestEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthBoundsTestEnable) -{ - struct vkCmdSetDepthBoundsTestEnableEXT_params params; - params.commandBuffer = commandBuffer; - params.depthBoundsTestEnable = depthBoundsTestEnable; - UNIX_CALL(vkCmdSetDepthBoundsTestEnableEXT, ¶ms); -} - -void WINAPI vkCmdSetDepthClampEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthClampEnable) -{ - struct vkCmdSetDepthClampEnableEXT_params params; - params.commandBuffer = commandBuffer; - params.depthClampEnable = depthClampEnable; - UNIX_CALL(vkCmdSetDepthClampEnableEXT, ¶ms); -} - -void WINAPI vkCmdSetDepthClipEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthClipEnable) -{ - struct vkCmdSetDepthClipEnableEXT_params params; - params.commandBuffer = commandBuffer; - params.depthClipEnable = depthClipEnable; - UNIX_CALL(vkCmdSetDepthClipEnableEXT, ¶ms); -} - -void WINAPI vkCmdSetDepthClipNegativeOneToOneEXT(VkCommandBuffer commandBuffer, VkBool32 negativeOneToOne) -{ - struct vkCmdSetDepthClipNegativeOneToOneEXT_params params; - params.commandBuffer = commandBuffer; - params.negativeOneToOne = negativeOneToOne; - UNIX_CALL(vkCmdSetDepthClipNegativeOneToOneEXT, ¶ms); -} - -void WINAPI vkCmdSetDepthCompareOp(VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp) -{ - struct vkCmdSetDepthCompareOp_params params; - params.commandBuffer = commandBuffer; - params.depthCompareOp = depthCompareOp; - UNIX_CALL(vkCmdSetDepthCompareOp, ¶ms); -} - -void WINAPI vkCmdSetDepthCompareOpEXT(VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp) -{ - struct vkCmdSetDepthCompareOpEXT_params params; - params.commandBuffer = commandBuffer; - params.depthCompareOp = depthCompareOp; - UNIX_CALL(vkCmdSetDepthCompareOpEXT, ¶ms); -} - -void WINAPI vkCmdSetDepthTestEnable(VkCommandBuffer commandBuffer, VkBool32 depthTestEnable) -{ - struct vkCmdSetDepthTestEnable_params params; - params.commandBuffer = commandBuffer; - params.depthTestEnable = depthTestEnable; - UNIX_CALL(vkCmdSetDepthTestEnable, ¶ms); -} - -void WINAPI vkCmdSetDepthTestEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthTestEnable) -{ - struct vkCmdSetDepthTestEnableEXT_params params; - params.commandBuffer = commandBuffer; - params.depthTestEnable = depthTestEnable; - UNIX_CALL(vkCmdSetDepthTestEnableEXT, ¶ms); -} - -void WINAPI vkCmdSetDepthWriteEnable(VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable) -{ - struct vkCmdSetDepthWriteEnable_params params; - params.commandBuffer = commandBuffer; - params.depthWriteEnable = depthWriteEnable; - UNIX_CALL(vkCmdSetDepthWriteEnable, ¶ms); -} - -void WINAPI vkCmdSetDepthWriteEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable) -{ - struct vkCmdSetDepthWriteEnableEXT_params params; - params.commandBuffer = commandBuffer; - params.depthWriteEnable = depthWriteEnable; - UNIX_CALL(vkCmdSetDepthWriteEnableEXT, ¶ms); -} - -void WINAPI vkCmdSetDescriptorBufferOffsetsEXT(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount, const uint32_t *pBufferIndices, const VkDeviceSize *pOffsets) -{ - struct vkCmdSetDescriptorBufferOffsetsEXT_params params; - params.commandBuffer = commandBuffer; - params.pipelineBindPoint = pipelineBindPoint; - params.layout = layout; - params.firstSet = firstSet; - params.setCount = setCount; - params.pBufferIndices = pBufferIndices; - params.pOffsets = pOffsets; - UNIX_CALL(vkCmdSetDescriptorBufferOffsetsEXT, ¶ms); -} - -void WINAPI vkCmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) -{ - struct vkCmdSetDeviceMask_params params; - params.commandBuffer = commandBuffer; - params.deviceMask = deviceMask; - UNIX_CALL(vkCmdSetDeviceMask, ¶ms); -} - -void WINAPI vkCmdSetDeviceMaskKHR(VkCommandBuffer commandBuffer, uint32_t deviceMask) -{ - struct vkCmdSetDeviceMaskKHR_params params; - params.commandBuffer = commandBuffer; - params.deviceMask = deviceMask; - UNIX_CALL(vkCmdSetDeviceMaskKHR, ¶ms); -} - -void WINAPI vkCmdSetDiscardRectangleEXT(VkCommandBuffer commandBuffer, uint32_t firstDiscardRectangle, uint32_t discardRectangleCount, const VkRect2D *pDiscardRectangles) -{ - struct vkCmdSetDiscardRectangleEXT_params params; - params.commandBuffer = commandBuffer; - params.firstDiscardRectangle = firstDiscardRectangle; - params.discardRectangleCount = discardRectangleCount; - params.pDiscardRectangles = pDiscardRectangles; - UNIX_CALL(vkCmdSetDiscardRectangleEXT, ¶ms); -} - -void WINAPI vkCmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) -{ - struct vkCmdSetEvent_params params; - params.commandBuffer = commandBuffer; - params.event = event; - params.stageMask = stageMask; - UNIX_CALL(vkCmdSetEvent, ¶ms); -} - -void WINAPI vkCmdSetEvent2(VkCommandBuffer commandBuffer, VkEvent event, const VkDependencyInfo *pDependencyInfo) -{ - struct vkCmdSetEvent2_params params; - params.commandBuffer = commandBuffer; - params.event = event; - params.pDependencyInfo = pDependencyInfo; - UNIX_CALL(vkCmdSetEvent2, ¶ms); -} - -void WINAPI vkCmdSetEvent2KHR(VkCommandBuffer commandBuffer, VkEvent event, const VkDependencyInfo *pDependencyInfo) -{ - struct vkCmdSetEvent2KHR_params params; - params.commandBuffer = commandBuffer; - params.event = event; - params.pDependencyInfo = pDependencyInfo; - UNIX_CALL(vkCmdSetEvent2KHR, ¶ms); -} - -void WINAPI vkCmdSetExclusiveScissorNV(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor, uint32_t exclusiveScissorCount, const VkRect2D *pExclusiveScissors) -{ - struct vkCmdSetExclusiveScissorNV_params params; - params.commandBuffer = commandBuffer; - params.firstExclusiveScissor = firstExclusiveScissor; - params.exclusiveScissorCount = exclusiveScissorCount; - params.pExclusiveScissors = pExclusiveScissors; - UNIX_CALL(vkCmdSetExclusiveScissorNV, ¶ms); -} - -void WINAPI vkCmdSetExtraPrimitiveOverestimationSizeEXT(VkCommandBuffer commandBuffer, float extraPrimitiveOverestimationSize) -{ - struct vkCmdSetExtraPrimitiveOverestimationSizeEXT_params params; - params.commandBuffer = commandBuffer; - params.extraPrimitiveOverestimationSize = extraPrimitiveOverestimationSize; - UNIX_CALL(vkCmdSetExtraPrimitiveOverestimationSizeEXT, ¶ms); -} - -void WINAPI vkCmdSetFragmentShadingRateEnumNV(VkCommandBuffer commandBuffer, VkFragmentShadingRateNV shadingRate, const VkFragmentShadingRateCombinerOpKHR combinerOps[2]) -{ - struct vkCmdSetFragmentShadingRateEnumNV_params params; - params.commandBuffer = commandBuffer; - params.shadingRate = shadingRate; - params.combinerOps = combinerOps; - UNIX_CALL(vkCmdSetFragmentShadingRateEnumNV, ¶ms); -} - -void WINAPI vkCmdSetFragmentShadingRateKHR(VkCommandBuffer commandBuffer, const VkExtent2D *pFragmentSize, const VkFragmentShadingRateCombinerOpKHR combinerOps[2]) -{ - struct vkCmdSetFragmentShadingRateKHR_params params; - params.commandBuffer = commandBuffer; - params.pFragmentSize = pFragmentSize; - params.combinerOps = combinerOps; - UNIX_CALL(vkCmdSetFragmentShadingRateKHR, ¶ms); -} - -void WINAPI vkCmdSetFrontFace(VkCommandBuffer commandBuffer, VkFrontFace frontFace) -{ - struct vkCmdSetFrontFace_params params; - params.commandBuffer = commandBuffer; - params.frontFace = frontFace; - UNIX_CALL(vkCmdSetFrontFace, ¶ms); -} - -void WINAPI vkCmdSetFrontFaceEXT(VkCommandBuffer commandBuffer, VkFrontFace frontFace) -{ - struct vkCmdSetFrontFaceEXT_params params; - params.commandBuffer = commandBuffer; - params.frontFace = frontFace; - UNIX_CALL(vkCmdSetFrontFaceEXT, ¶ms); -} - -void WINAPI vkCmdSetLineRasterizationModeEXT(VkCommandBuffer commandBuffer, VkLineRasterizationModeEXT lineRasterizationMode) -{ - struct vkCmdSetLineRasterizationModeEXT_params params; - params.commandBuffer = commandBuffer; - params.lineRasterizationMode = lineRasterizationMode; - UNIX_CALL(vkCmdSetLineRasterizationModeEXT, ¶ms); -} - -void WINAPI vkCmdSetLineStippleEXT(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, uint16_t lineStipplePattern) -{ - struct vkCmdSetLineStippleEXT_params params; - params.commandBuffer = commandBuffer; - params.lineStippleFactor = lineStippleFactor; - params.lineStipplePattern = lineStipplePattern; - UNIX_CALL(vkCmdSetLineStippleEXT, ¶ms); -} - -void WINAPI vkCmdSetLineStippleEnableEXT(VkCommandBuffer commandBuffer, VkBool32 stippledLineEnable) -{ - struct vkCmdSetLineStippleEnableEXT_params params; - params.commandBuffer = commandBuffer; - params.stippledLineEnable = stippledLineEnable; - UNIX_CALL(vkCmdSetLineStippleEnableEXT, ¶ms); -} - -void WINAPI vkCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth) -{ - struct vkCmdSetLineWidth_params params; - params.commandBuffer = commandBuffer; - params.lineWidth = lineWidth; - UNIX_CALL(vkCmdSetLineWidth, ¶ms); -} - -void WINAPI vkCmdSetLogicOpEXT(VkCommandBuffer commandBuffer, VkLogicOp logicOp) -{ - struct vkCmdSetLogicOpEXT_params params; - params.commandBuffer = commandBuffer; - params.logicOp = logicOp; - UNIX_CALL(vkCmdSetLogicOpEXT, ¶ms); -} - -void WINAPI vkCmdSetLogicOpEnableEXT(VkCommandBuffer commandBuffer, VkBool32 logicOpEnable) -{ - struct vkCmdSetLogicOpEnableEXT_params params; - params.commandBuffer = commandBuffer; - params.logicOpEnable = logicOpEnable; - UNIX_CALL(vkCmdSetLogicOpEnableEXT, ¶ms); -} - -void WINAPI vkCmdSetPatchControlPointsEXT(VkCommandBuffer commandBuffer, uint32_t patchControlPoints) -{ - struct vkCmdSetPatchControlPointsEXT_params params; - params.commandBuffer = commandBuffer; - params.patchControlPoints = patchControlPoints; - UNIX_CALL(vkCmdSetPatchControlPointsEXT, ¶ms); -} - -VkResult WINAPI vkCmdSetPerformanceMarkerINTEL(VkCommandBuffer commandBuffer, const VkPerformanceMarkerInfoINTEL *pMarkerInfo) -{ - struct vkCmdSetPerformanceMarkerINTEL_params params; - NTSTATUS status; - params.commandBuffer = commandBuffer; - params.pMarkerInfo = pMarkerInfo; - status = UNIX_CALL(vkCmdSetPerformanceMarkerINTEL, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCmdSetPerformanceOverrideINTEL(VkCommandBuffer commandBuffer, const VkPerformanceOverrideInfoINTEL *pOverrideInfo) -{ - struct vkCmdSetPerformanceOverrideINTEL_params params; - NTSTATUS status; - params.commandBuffer = commandBuffer; - params.pOverrideInfo = pOverrideInfo; - status = UNIX_CALL(vkCmdSetPerformanceOverrideINTEL, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCmdSetPerformanceStreamMarkerINTEL(VkCommandBuffer commandBuffer, const VkPerformanceStreamMarkerInfoINTEL *pMarkerInfo) -{ - struct vkCmdSetPerformanceStreamMarkerINTEL_params params; - NTSTATUS status; - params.commandBuffer = commandBuffer; - params.pMarkerInfo = pMarkerInfo; - status = UNIX_CALL(vkCmdSetPerformanceStreamMarkerINTEL, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkCmdSetPolygonModeEXT(VkCommandBuffer commandBuffer, VkPolygonMode polygonMode) -{ - struct vkCmdSetPolygonModeEXT_params params; - params.commandBuffer = commandBuffer; - params.polygonMode = polygonMode; - UNIX_CALL(vkCmdSetPolygonModeEXT, ¶ms); -} - -void WINAPI vkCmdSetPrimitiveRestartEnable(VkCommandBuffer commandBuffer, VkBool32 primitiveRestartEnable) -{ - struct vkCmdSetPrimitiveRestartEnable_params params; - params.commandBuffer = commandBuffer; - params.primitiveRestartEnable = primitiveRestartEnable; - UNIX_CALL(vkCmdSetPrimitiveRestartEnable, ¶ms); -} - -void WINAPI vkCmdSetPrimitiveRestartEnableEXT(VkCommandBuffer commandBuffer, VkBool32 primitiveRestartEnable) -{ - struct vkCmdSetPrimitiveRestartEnableEXT_params params; - params.commandBuffer = commandBuffer; - params.primitiveRestartEnable = primitiveRestartEnable; - UNIX_CALL(vkCmdSetPrimitiveRestartEnableEXT, ¶ms); -} - -void WINAPI vkCmdSetPrimitiveTopology(VkCommandBuffer commandBuffer, VkPrimitiveTopology primitiveTopology) -{ - struct vkCmdSetPrimitiveTopology_params params; - params.commandBuffer = commandBuffer; - params.primitiveTopology = primitiveTopology; - UNIX_CALL(vkCmdSetPrimitiveTopology, ¶ms); -} - -void WINAPI vkCmdSetPrimitiveTopologyEXT(VkCommandBuffer commandBuffer, VkPrimitiveTopology primitiveTopology) -{ - struct vkCmdSetPrimitiveTopologyEXT_params params; - params.commandBuffer = commandBuffer; - params.primitiveTopology = primitiveTopology; - UNIX_CALL(vkCmdSetPrimitiveTopologyEXT, ¶ms); -} - -void WINAPI vkCmdSetProvokingVertexModeEXT(VkCommandBuffer commandBuffer, VkProvokingVertexModeEXT provokingVertexMode) -{ - struct vkCmdSetProvokingVertexModeEXT_params params; - params.commandBuffer = commandBuffer; - params.provokingVertexMode = provokingVertexMode; - UNIX_CALL(vkCmdSetProvokingVertexModeEXT, ¶ms); -} - -void WINAPI vkCmdSetRasterizationSamplesEXT(VkCommandBuffer commandBuffer, VkSampleCountFlagBits rasterizationSamples) -{ - struct vkCmdSetRasterizationSamplesEXT_params params; - params.commandBuffer = commandBuffer; - params.rasterizationSamples = rasterizationSamples; - UNIX_CALL(vkCmdSetRasterizationSamplesEXT, ¶ms); -} - -void WINAPI vkCmdSetRasterizationStreamEXT(VkCommandBuffer commandBuffer, uint32_t rasterizationStream) -{ - struct vkCmdSetRasterizationStreamEXT_params params; - params.commandBuffer = commandBuffer; - params.rasterizationStream = rasterizationStream; - UNIX_CALL(vkCmdSetRasterizationStreamEXT, ¶ms); -} - -void WINAPI vkCmdSetRasterizerDiscardEnable(VkCommandBuffer commandBuffer, VkBool32 rasterizerDiscardEnable) -{ - struct vkCmdSetRasterizerDiscardEnable_params params; - params.commandBuffer = commandBuffer; - params.rasterizerDiscardEnable = rasterizerDiscardEnable; - UNIX_CALL(vkCmdSetRasterizerDiscardEnable, ¶ms); -} - -void WINAPI vkCmdSetRasterizerDiscardEnableEXT(VkCommandBuffer commandBuffer, VkBool32 rasterizerDiscardEnable) -{ - struct vkCmdSetRasterizerDiscardEnableEXT_params params; - params.commandBuffer = commandBuffer; - params.rasterizerDiscardEnable = rasterizerDiscardEnable; - UNIX_CALL(vkCmdSetRasterizerDiscardEnableEXT, ¶ms); -} - -void WINAPI vkCmdSetRayTracingPipelineStackSizeKHR(VkCommandBuffer commandBuffer, uint32_t pipelineStackSize) -{ - struct vkCmdSetRayTracingPipelineStackSizeKHR_params params; - params.commandBuffer = commandBuffer; - params.pipelineStackSize = pipelineStackSize; - UNIX_CALL(vkCmdSetRayTracingPipelineStackSizeKHR, ¶ms); -} - -void WINAPI vkCmdSetRepresentativeFragmentTestEnableNV(VkCommandBuffer commandBuffer, VkBool32 representativeFragmentTestEnable) -{ - struct vkCmdSetRepresentativeFragmentTestEnableNV_params params; - params.commandBuffer = commandBuffer; - params.representativeFragmentTestEnable = representativeFragmentTestEnable; - UNIX_CALL(vkCmdSetRepresentativeFragmentTestEnableNV, ¶ms); -} - -void WINAPI vkCmdSetSampleLocationsEXT(VkCommandBuffer commandBuffer, const VkSampleLocationsInfoEXT *pSampleLocationsInfo) -{ - struct vkCmdSetSampleLocationsEXT_params params; - params.commandBuffer = commandBuffer; - params.pSampleLocationsInfo = pSampleLocationsInfo; - UNIX_CALL(vkCmdSetSampleLocationsEXT, ¶ms); -} - -void WINAPI vkCmdSetSampleLocationsEnableEXT(VkCommandBuffer commandBuffer, VkBool32 sampleLocationsEnable) -{ - struct vkCmdSetSampleLocationsEnableEXT_params params; - params.commandBuffer = commandBuffer; - params.sampleLocationsEnable = sampleLocationsEnable; - UNIX_CALL(vkCmdSetSampleLocationsEnableEXT, ¶ms); -} - -void WINAPI vkCmdSetSampleMaskEXT(VkCommandBuffer commandBuffer, VkSampleCountFlagBits samples, const VkSampleMask *pSampleMask) -{ - struct vkCmdSetSampleMaskEXT_params params; - params.commandBuffer = commandBuffer; - params.samples = samples; - params.pSampleMask = pSampleMask; - UNIX_CALL(vkCmdSetSampleMaskEXT, ¶ms); -} - -void WINAPI vkCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D *pScissors) -{ - struct vkCmdSetScissor_params params; - params.commandBuffer = commandBuffer; - params.firstScissor = firstScissor; - params.scissorCount = scissorCount; - params.pScissors = pScissors; - UNIX_CALL(vkCmdSetScissor, ¶ms); -} - -void WINAPI vkCmdSetScissorWithCount(VkCommandBuffer commandBuffer, uint32_t scissorCount, const VkRect2D *pScissors) -{ - struct vkCmdSetScissorWithCount_params params; - params.commandBuffer = commandBuffer; - params.scissorCount = scissorCount; - params.pScissors = pScissors; - UNIX_CALL(vkCmdSetScissorWithCount, ¶ms); -} - -void WINAPI vkCmdSetScissorWithCountEXT(VkCommandBuffer commandBuffer, uint32_t scissorCount, const VkRect2D *pScissors) -{ - struct vkCmdSetScissorWithCountEXT_params params; - params.commandBuffer = commandBuffer; - params.scissorCount = scissorCount; - params.pScissors = pScissors; - UNIX_CALL(vkCmdSetScissorWithCountEXT, ¶ms); -} - -void WINAPI vkCmdSetShadingRateImageEnableNV(VkCommandBuffer commandBuffer, VkBool32 shadingRateImageEnable) -{ - struct vkCmdSetShadingRateImageEnableNV_params params; - params.commandBuffer = commandBuffer; - params.shadingRateImageEnable = shadingRateImageEnable; - UNIX_CALL(vkCmdSetShadingRateImageEnableNV, ¶ms); -} - -void WINAPI vkCmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask) -{ - struct vkCmdSetStencilCompareMask_params params; - params.commandBuffer = commandBuffer; - params.faceMask = faceMask; - params.compareMask = compareMask; - UNIX_CALL(vkCmdSetStencilCompareMask, ¶ms); -} - -void WINAPI vkCmdSetStencilOp(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp) -{ - struct vkCmdSetStencilOp_params params; - params.commandBuffer = commandBuffer; - params.faceMask = faceMask; - params.failOp = failOp; - params.passOp = passOp; - params.depthFailOp = depthFailOp; - params.compareOp = compareOp; - UNIX_CALL(vkCmdSetStencilOp, ¶ms); -} - -void WINAPI vkCmdSetStencilOpEXT(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp) -{ - struct vkCmdSetStencilOpEXT_params params; - params.commandBuffer = commandBuffer; - params.faceMask = faceMask; - params.failOp = failOp; - params.passOp = passOp; - params.depthFailOp = depthFailOp; - params.compareOp = compareOp; - UNIX_CALL(vkCmdSetStencilOpEXT, ¶ms); -} - -void WINAPI vkCmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference) -{ - struct vkCmdSetStencilReference_params params; - params.commandBuffer = commandBuffer; - params.faceMask = faceMask; - params.reference = reference; - UNIX_CALL(vkCmdSetStencilReference, ¶ms); -} - -void WINAPI vkCmdSetStencilTestEnable(VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable) -{ - struct vkCmdSetStencilTestEnable_params params; - params.commandBuffer = commandBuffer; - params.stencilTestEnable = stencilTestEnable; - UNIX_CALL(vkCmdSetStencilTestEnable, ¶ms); -} - -void WINAPI vkCmdSetStencilTestEnableEXT(VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable) -{ - struct vkCmdSetStencilTestEnableEXT_params params; - params.commandBuffer = commandBuffer; - params.stencilTestEnable = stencilTestEnable; - UNIX_CALL(vkCmdSetStencilTestEnableEXT, ¶ms); -} - -void WINAPI vkCmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask) -{ - struct vkCmdSetStencilWriteMask_params params; - params.commandBuffer = commandBuffer; - params.faceMask = faceMask; - params.writeMask = writeMask; - UNIX_CALL(vkCmdSetStencilWriteMask, ¶ms); -} - -void WINAPI vkCmdSetTessellationDomainOriginEXT(VkCommandBuffer commandBuffer, VkTessellationDomainOrigin domainOrigin) -{ - struct vkCmdSetTessellationDomainOriginEXT_params params; - params.commandBuffer = commandBuffer; - params.domainOrigin = domainOrigin; - UNIX_CALL(vkCmdSetTessellationDomainOriginEXT, ¶ms); -} - -void WINAPI vkCmdSetVertexInputEXT(VkCommandBuffer commandBuffer, uint32_t vertexBindingDescriptionCount, const VkVertexInputBindingDescription2EXT *pVertexBindingDescriptions, uint32_t vertexAttributeDescriptionCount, const VkVertexInputAttributeDescription2EXT *pVertexAttributeDescriptions) -{ - struct vkCmdSetVertexInputEXT_params params; - params.commandBuffer = commandBuffer; - params.vertexBindingDescriptionCount = vertexBindingDescriptionCount; - params.pVertexBindingDescriptions = pVertexBindingDescriptions; - params.vertexAttributeDescriptionCount = vertexAttributeDescriptionCount; - params.pVertexAttributeDescriptions = pVertexAttributeDescriptions; - UNIX_CALL(vkCmdSetVertexInputEXT, ¶ms); -} - -void WINAPI vkCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport *pViewports) -{ - struct vkCmdSetViewport_params params; - params.commandBuffer = commandBuffer; - params.firstViewport = firstViewport; - params.viewportCount = viewportCount; - params.pViewports = pViewports; - UNIX_CALL(vkCmdSetViewport, ¶ms); -} - -void WINAPI vkCmdSetViewportShadingRatePaletteNV(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkShadingRatePaletteNV *pShadingRatePalettes) -{ - struct vkCmdSetViewportShadingRatePaletteNV_params params; - params.commandBuffer = commandBuffer; - params.firstViewport = firstViewport; - params.viewportCount = viewportCount; - params.pShadingRatePalettes = pShadingRatePalettes; - UNIX_CALL(vkCmdSetViewportShadingRatePaletteNV, ¶ms); -} - -void WINAPI vkCmdSetViewportSwizzleNV(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportSwizzleNV *pViewportSwizzles) -{ - struct vkCmdSetViewportSwizzleNV_params params; - params.commandBuffer = commandBuffer; - params.firstViewport = firstViewport; - params.viewportCount = viewportCount; - params.pViewportSwizzles = pViewportSwizzles; - UNIX_CALL(vkCmdSetViewportSwizzleNV, ¶ms); -} - -void WINAPI vkCmdSetViewportWScalingEnableNV(VkCommandBuffer commandBuffer, VkBool32 viewportWScalingEnable) -{ - struct vkCmdSetViewportWScalingEnableNV_params params; - params.commandBuffer = commandBuffer; - params.viewportWScalingEnable = viewportWScalingEnable; - UNIX_CALL(vkCmdSetViewportWScalingEnableNV, ¶ms); -} - -void WINAPI vkCmdSetViewportWScalingNV(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportWScalingNV *pViewportWScalings) -{ - struct vkCmdSetViewportWScalingNV_params params; - params.commandBuffer = commandBuffer; - params.firstViewport = firstViewport; - params.viewportCount = viewportCount; - params.pViewportWScalings = pViewportWScalings; - UNIX_CALL(vkCmdSetViewportWScalingNV, ¶ms); -} - -void WINAPI vkCmdSetViewportWithCount(VkCommandBuffer commandBuffer, uint32_t viewportCount, const VkViewport *pViewports) -{ - struct vkCmdSetViewportWithCount_params params; - params.commandBuffer = commandBuffer; - params.viewportCount = viewportCount; - params.pViewports = pViewports; - UNIX_CALL(vkCmdSetViewportWithCount, ¶ms); -} - -void WINAPI vkCmdSetViewportWithCountEXT(VkCommandBuffer commandBuffer, uint32_t viewportCount, const VkViewport *pViewports) -{ - struct vkCmdSetViewportWithCountEXT_params params; - params.commandBuffer = commandBuffer; - params.viewportCount = viewportCount; - params.pViewports = pViewports; - UNIX_CALL(vkCmdSetViewportWithCountEXT, ¶ms); -} - -void WINAPI vkCmdSubpassShadingHUAWEI(VkCommandBuffer commandBuffer) -{ - struct vkCmdSubpassShadingHUAWEI_params params; - params.commandBuffer = commandBuffer; - UNIX_CALL(vkCmdSubpassShadingHUAWEI, ¶ms); -} - -void WINAPI vkCmdTraceRaysIndirect2KHR(VkCommandBuffer commandBuffer, VkDeviceAddress indirectDeviceAddress) -{ - struct vkCmdTraceRaysIndirect2KHR_params params; - params.commandBuffer = commandBuffer; - params.indirectDeviceAddress = indirectDeviceAddress; - UNIX_CALL(vkCmdTraceRaysIndirect2KHR, ¶ms); -} - -void WINAPI vkCmdTraceRaysIndirectKHR(VkCommandBuffer commandBuffer, const VkStridedDeviceAddressRegionKHR *pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR *pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR *pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR *pCallableShaderBindingTable, VkDeviceAddress indirectDeviceAddress) -{ - struct vkCmdTraceRaysIndirectKHR_params params; - params.commandBuffer = commandBuffer; - params.pRaygenShaderBindingTable = pRaygenShaderBindingTable; - params.pMissShaderBindingTable = pMissShaderBindingTable; - params.pHitShaderBindingTable = pHitShaderBindingTable; - params.pCallableShaderBindingTable = pCallableShaderBindingTable; - params.indirectDeviceAddress = indirectDeviceAddress; - UNIX_CALL(vkCmdTraceRaysIndirectKHR, ¶ms); -} - -void WINAPI vkCmdTraceRaysKHR(VkCommandBuffer commandBuffer, const VkStridedDeviceAddressRegionKHR *pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR *pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR *pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR *pCallableShaderBindingTable, uint32_t width, uint32_t height, uint32_t depth) -{ - struct vkCmdTraceRaysKHR_params params; - params.commandBuffer = commandBuffer; - params.pRaygenShaderBindingTable = pRaygenShaderBindingTable; - params.pMissShaderBindingTable = pMissShaderBindingTable; - params.pHitShaderBindingTable = pHitShaderBindingTable; - params.pCallableShaderBindingTable = pCallableShaderBindingTable; - params.width = width; - params.height = height; - params.depth = depth; - UNIX_CALL(vkCmdTraceRaysKHR, ¶ms); -} - -void WINAPI vkCmdTraceRaysNV(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, uint32_t width, uint32_t height, uint32_t depth) -{ - struct vkCmdTraceRaysNV_params params; - params.commandBuffer = commandBuffer; - params.raygenShaderBindingTableBuffer = raygenShaderBindingTableBuffer; - params.raygenShaderBindingOffset = raygenShaderBindingOffset; - params.missShaderBindingTableBuffer = missShaderBindingTableBuffer; - params.missShaderBindingOffset = missShaderBindingOffset; - params.missShaderBindingStride = missShaderBindingStride; - params.hitShaderBindingTableBuffer = hitShaderBindingTableBuffer; - params.hitShaderBindingOffset = hitShaderBindingOffset; - params.hitShaderBindingStride = hitShaderBindingStride; - params.callableShaderBindingTableBuffer = callableShaderBindingTableBuffer; - params.callableShaderBindingOffset = callableShaderBindingOffset; - params.callableShaderBindingStride = callableShaderBindingStride; - params.width = width; - params.height = height; - params.depth = depth; - UNIX_CALL(vkCmdTraceRaysNV, ¶ms); -} - -void WINAPI vkCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void *pData) -{ - struct vkCmdUpdateBuffer_params params; - params.commandBuffer = commandBuffer; - params.dstBuffer = dstBuffer; - params.dstOffset = dstOffset; - params.dataSize = dataSize; - params.pData = pData; - UNIX_CALL(vkCmdUpdateBuffer, ¶ms); -} - -void WINAPI vkCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) -{ - struct vkCmdWaitEvents_params params; - params.commandBuffer = commandBuffer; - params.eventCount = eventCount; - params.pEvents = pEvents; - params.srcStageMask = srcStageMask; - params.dstStageMask = dstStageMask; - params.memoryBarrierCount = memoryBarrierCount; - params.pMemoryBarriers = pMemoryBarriers; - params.bufferMemoryBarrierCount = bufferMemoryBarrierCount; - params.pBufferMemoryBarriers = pBufferMemoryBarriers; - params.imageMemoryBarrierCount = imageMemoryBarrierCount; - params.pImageMemoryBarriers = pImageMemoryBarriers; - UNIX_CALL(vkCmdWaitEvents, ¶ms); -} - -void WINAPI vkCmdWaitEvents2(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents, const VkDependencyInfo *pDependencyInfos) -{ - struct vkCmdWaitEvents2_params params; - params.commandBuffer = commandBuffer; - params.eventCount = eventCount; - params.pEvents = pEvents; - params.pDependencyInfos = pDependencyInfos; - UNIX_CALL(vkCmdWaitEvents2, ¶ms); -} - -void WINAPI vkCmdWaitEvents2KHR(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents, const VkDependencyInfo *pDependencyInfos) -{ - struct vkCmdWaitEvents2KHR_params params; - params.commandBuffer = commandBuffer; - params.eventCount = eventCount; - params.pEvents = pEvents; - params.pDependencyInfos = pDependencyInfos; - UNIX_CALL(vkCmdWaitEvents2KHR, ¶ms); -} - -void WINAPI vkCmdWriteAccelerationStructuresPropertiesKHR(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR *pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery) -{ - struct vkCmdWriteAccelerationStructuresPropertiesKHR_params params; - params.commandBuffer = commandBuffer; - params.accelerationStructureCount = accelerationStructureCount; - params.pAccelerationStructures = pAccelerationStructures; - params.queryType = queryType; - params.queryPool = queryPool; - params.firstQuery = firstQuery; - UNIX_CALL(vkCmdWriteAccelerationStructuresPropertiesKHR, ¶ms); -} - -void WINAPI vkCmdWriteAccelerationStructuresPropertiesNV(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureNV *pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery) -{ - struct vkCmdWriteAccelerationStructuresPropertiesNV_params params; - params.commandBuffer = commandBuffer; - params.accelerationStructureCount = accelerationStructureCount; - params.pAccelerationStructures = pAccelerationStructures; - params.queryType = queryType; - params.queryPool = queryPool; - params.firstQuery = firstQuery; - UNIX_CALL(vkCmdWriteAccelerationStructuresPropertiesNV, ¶ms); -} - -void WINAPI vkCmdWriteBufferMarker2AMD(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker) -{ - struct vkCmdWriteBufferMarker2AMD_params params; - params.commandBuffer = commandBuffer; - params.stage = stage; - params.dstBuffer = dstBuffer; - params.dstOffset = dstOffset; - params.marker = marker; - UNIX_CALL(vkCmdWriteBufferMarker2AMD, ¶ms); -} - -void WINAPI vkCmdWriteBufferMarkerAMD(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker) -{ - struct vkCmdWriteBufferMarkerAMD_params params; - params.commandBuffer = commandBuffer; - params.pipelineStage = pipelineStage; - params.dstBuffer = dstBuffer; - params.dstOffset = dstOffset; - params.marker = marker; - UNIX_CALL(vkCmdWriteBufferMarkerAMD, ¶ms); -} - -void WINAPI vkCmdWriteMicromapsPropertiesEXT(VkCommandBuffer commandBuffer, uint32_t micromapCount, const VkMicromapEXT *pMicromaps, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery) -{ - struct vkCmdWriteMicromapsPropertiesEXT_params params; - params.commandBuffer = commandBuffer; - params.micromapCount = micromapCount; - params.pMicromaps = pMicromaps; - params.queryType = queryType; - params.queryPool = queryPool; - params.firstQuery = firstQuery; - UNIX_CALL(vkCmdWriteMicromapsPropertiesEXT, ¶ms); -} - -void WINAPI vkCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query) -{ - struct vkCmdWriteTimestamp_params params; - params.commandBuffer = commandBuffer; - params.pipelineStage = pipelineStage; - params.queryPool = queryPool; - params.query = query; - UNIX_CALL(vkCmdWriteTimestamp, ¶ms); -} - -void WINAPI vkCmdWriteTimestamp2(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkQueryPool queryPool, uint32_t query) -{ - struct vkCmdWriteTimestamp2_params params; - params.commandBuffer = commandBuffer; - params.stage = stage; - params.queryPool = queryPool; - params.query = query; - UNIX_CALL(vkCmdWriteTimestamp2, ¶ms); -} - -void WINAPI vkCmdWriteTimestamp2KHR(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkQueryPool queryPool, uint32_t query) -{ - struct vkCmdWriteTimestamp2KHR_params params; - params.commandBuffer = commandBuffer; - params.stage = stage; - params.queryPool = queryPool; - params.query = query; - UNIX_CALL(vkCmdWriteTimestamp2KHR, ¶ms); -} - -VkResult WINAPI vkCompileDeferredNV(VkDevice device, VkPipeline pipeline, uint32_t shader) -{ - struct vkCompileDeferredNV_params params; - NTSTATUS status; - params.device = device; - params.pipeline = pipeline; - params.shader = shader; - status = UNIX_CALL(vkCompileDeferredNV, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCopyAccelerationStructureKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyAccelerationStructureInfoKHR *pInfo) -{ - struct vkCopyAccelerationStructureKHR_params params; - NTSTATUS status; - params.device = device; - params.deferredOperation = deferredOperation; - params.pInfo = pInfo; - status = UNIX_CALL(vkCopyAccelerationStructureKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCopyAccelerationStructureToMemoryKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyAccelerationStructureToMemoryInfoKHR *pInfo) -{ - struct vkCopyAccelerationStructureToMemoryKHR_params params; - NTSTATUS status; - params.device = device; - params.deferredOperation = deferredOperation; - params.pInfo = pInfo; - status = UNIX_CALL(vkCopyAccelerationStructureToMemoryKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCopyMemoryToAccelerationStructureKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMemoryToAccelerationStructureInfoKHR *pInfo) -{ - struct vkCopyMemoryToAccelerationStructureKHR_params params; - NTSTATUS status; - params.device = device; - params.deferredOperation = deferredOperation; - params.pInfo = pInfo; - status = UNIX_CALL(vkCopyMemoryToAccelerationStructureKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCopyMemoryToMicromapEXT(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMemoryToMicromapInfoEXT *pInfo) -{ - struct vkCopyMemoryToMicromapEXT_params params; - NTSTATUS status; - params.device = device; - params.deferredOperation = deferredOperation; - params.pInfo = pInfo; - status = UNIX_CALL(vkCopyMemoryToMicromapEXT, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCopyMicromapEXT(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMicromapInfoEXT *pInfo) -{ - struct vkCopyMicromapEXT_params params; - NTSTATUS status; - params.device = device; - params.deferredOperation = deferredOperation; - params.pInfo = pInfo; - status = UNIX_CALL(vkCopyMicromapEXT, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCopyMicromapToMemoryEXT(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMicromapToMemoryInfoEXT *pInfo) -{ - struct vkCopyMicromapToMemoryEXT_params params; - NTSTATUS status; - params.device = device; - params.deferredOperation = deferredOperation; - params.pInfo = pInfo; - status = UNIX_CALL(vkCopyMicromapToMemoryEXT, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateAccelerationStructureKHR(VkDevice device, const VkAccelerationStructureCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkAccelerationStructureKHR *pAccelerationStructure) -{ - struct vkCreateAccelerationStructureKHR_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pAccelerationStructure = pAccelerationStructure; - status = UNIX_CALL(vkCreateAccelerationStructureKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateAccelerationStructureNV(VkDevice device, const VkAccelerationStructureCreateInfoNV *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkAccelerationStructureNV *pAccelerationStructure) -{ - struct vkCreateAccelerationStructureNV_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pAccelerationStructure = pAccelerationStructure; - status = UNIX_CALL(vkCreateAccelerationStructureNV, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) -{ - struct vkCreateBuffer_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pBuffer = pBuffer; - status = UNIX_CALL(vkCreateBuffer, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkBufferView *pView) -{ - struct vkCreateBufferView_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pView = pView; - status = UNIX_CALL(vkCreateBufferView, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) -{ - struct vkCreateComputePipelines_params params; - NTSTATUS status; - params.device = device; - params.pipelineCache = pipelineCache; - params.createInfoCount = createInfoCount; - params.pCreateInfos = pCreateInfos; - params.pAllocator = pAllocator; - params.pPipelines = pPipelines; - status = UNIX_CALL(vkCreateComputePipelines, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateCuFunctionNVX(VkDevice device, const VkCuFunctionCreateInfoNVX *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkCuFunctionNVX *pFunction) -{ - struct vkCreateCuFunctionNVX_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pFunction = pFunction; - status = UNIX_CALL(vkCreateCuFunctionNVX, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateCuModuleNVX(VkDevice device, const VkCuModuleCreateInfoNVX *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkCuModuleNVX *pModule) -{ - struct vkCreateCuModuleNVX_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pModule = pModule; - status = UNIX_CALL(vkCreateCuModuleNVX, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback) -{ - struct vkCreateDebugReportCallbackEXT_params params; - NTSTATUS status; - params.instance = instance; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pCallback = pCallback; - status = UNIX_CALL(vkCreateDebugReportCallbackEXT, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT *pMessenger) -{ - struct vkCreateDebugUtilsMessengerEXT_params params; - NTSTATUS status; - params.instance = instance; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pMessenger = pMessenger; - status = UNIX_CALL(vkCreateDebugUtilsMessengerEXT, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateDeferredOperationKHR(VkDevice device, const VkAllocationCallbacks *pAllocator, VkDeferredOperationKHR *pDeferredOperation) -{ - struct vkCreateDeferredOperationKHR_params params; - NTSTATUS status; - params.device = device; - params.pAllocator = pAllocator; - params.pDeferredOperation = pDeferredOperation; - status = UNIX_CALL(vkCreateDeferredOperationKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool) -{ - struct vkCreateDescriptorPool_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pDescriptorPool = pDescriptorPool; - status = UNIX_CALL(vkCreateDescriptorPool, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout) -{ - struct vkCreateDescriptorSetLayout_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pSetLayout = pSetLayout; - status = UNIX_CALL(vkCreateDescriptorSetLayout, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorUpdateTemplate *pDescriptorUpdateTemplate) -{ - struct vkCreateDescriptorUpdateTemplate_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pDescriptorUpdateTemplate = pDescriptorUpdateTemplate; - status = UNIX_CALL(vkCreateDescriptorUpdateTemplate, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateDescriptorUpdateTemplateKHR(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorUpdateTemplate *pDescriptorUpdateTemplate) -{ - struct vkCreateDescriptorUpdateTemplateKHR_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pDescriptorUpdateTemplate = pDescriptorUpdateTemplate; - status = UNIX_CALL(vkCreateDescriptorUpdateTemplateKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkEvent *pEvent) -{ - struct vkCreateEvent_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pEvent = pEvent; - status = UNIX_CALL(vkCreateEvent, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence) -{ - struct vkCreateFence_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pFence = pFence; - status = UNIX_CALL(vkCreateFence, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer) -{ - struct vkCreateFramebuffer_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pFramebuffer = pFramebuffer; - status = UNIX_CALL(vkCreateFramebuffer, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) -{ - struct vkCreateGraphicsPipelines_params params; - NTSTATUS status; - params.device = device; - params.pipelineCache = pipelineCache; - params.createInfoCount = createInfoCount; - params.pCreateInfos = pCreateInfos; - params.pAllocator = pAllocator; - params.pPipelines = pPipelines; - status = UNIX_CALL(vkCreateGraphicsPipelines, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImage *pImage) -{ - struct vkCreateImage_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pImage = pImage; - status = UNIX_CALL(vkCreateImage, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImageView *pView) -{ - struct vkCreateImageView_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pView = pView; - status = UNIX_CALL(vkCreateImageView, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateIndirectCommandsLayoutNV(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNV *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkIndirectCommandsLayoutNV *pIndirectCommandsLayout) -{ - struct vkCreateIndirectCommandsLayoutNV_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pIndirectCommandsLayout = pIndirectCommandsLayout; - status = UNIX_CALL(vkCreateIndirectCommandsLayoutNV, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateMicromapEXT(VkDevice device, const VkMicromapCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkMicromapEXT *pMicromap) -{ - struct vkCreateMicromapEXT_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pMicromap = pMicromap; - status = UNIX_CALL(vkCreateMicromapEXT, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateOpticalFlowSessionNV(VkDevice device, const VkOpticalFlowSessionCreateInfoNV *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkOpticalFlowSessionNV *pSession) -{ - struct vkCreateOpticalFlowSessionNV_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pSession = pSession; - status = UNIX_CALL(vkCreateOpticalFlowSessionNV, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache) -{ - struct vkCreatePipelineCache_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pPipelineCache = pPipelineCache; - status = UNIX_CALL(vkCreatePipelineCache, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout) -{ - struct vkCreatePipelineLayout_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pPipelineLayout = pPipelineLayout; - status = UNIX_CALL(vkCreatePipelineLayout, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreatePrivateDataSlot(VkDevice device, const VkPrivateDataSlotCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPrivateDataSlot *pPrivateDataSlot) -{ - struct vkCreatePrivateDataSlot_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pPrivateDataSlot = pPrivateDataSlot; - status = UNIX_CALL(vkCreatePrivateDataSlot, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreatePrivateDataSlotEXT(VkDevice device, const VkPrivateDataSlotCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPrivateDataSlot *pPrivateDataSlot) -{ - struct vkCreatePrivateDataSlotEXT_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pPrivateDataSlot = pPrivateDataSlot; - status = UNIX_CALL(vkCreatePrivateDataSlotEXT, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool) -{ - struct vkCreateQueryPool_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pQueryPool = pQueryPool; - status = UNIX_CALL(vkCreateQueryPool, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateRayTracingPipelinesKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoKHR *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) -{ - struct vkCreateRayTracingPipelinesKHR_params params; - NTSTATUS status; - params.device = device; - params.deferredOperation = deferredOperation; - params.pipelineCache = pipelineCache; - params.createInfoCount = createInfoCount; - params.pCreateInfos = pCreateInfos; - params.pAllocator = pAllocator; - params.pPipelines = pPipelines; - status = UNIX_CALL(vkCreateRayTracingPipelinesKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoNV *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines) -{ - struct vkCreateRayTracingPipelinesNV_params params; - NTSTATUS status; - params.device = device; - params.pipelineCache = pipelineCache; - params.createInfoCount = createInfoCount; - params.pCreateInfos = pCreateInfos; - params.pAllocator = pAllocator; - params.pPipelines = pPipelines; - status = UNIX_CALL(vkCreateRayTracingPipelinesNV, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) -{ - struct vkCreateRenderPass_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pRenderPass = pRenderPass; - status = UNIX_CALL(vkCreateRenderPass, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) -{ - struct vkCreateRenderPass2_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pRenderPass = pRenderPass; - status = UNIX_CALL(vkCreateRenderPass2, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) -{ - struct vkCreateRenderPass2KHR_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pRenderPass = pRenderPass; - status = UNIX_CALL(vkCreateRenderPass2KHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSampler *pSampler) -{ - struct vkCreateSampler_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pSampler = pSampler; - status = UNIX_CALL(vkCreateSampler, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSamplerYcbcrConversion *pYcbcrConversion) -{ - struct vkCreateSamplerYcbcrConversion_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pYcbcrConversion = pYcbcrConversion; - status = UNIX_CALL(vkCreateSamplerYcbcrConversion, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateSamplerYcbcrConversionKHR(VkDevice device, const VkSamplerYcbcrConversionCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSamplerYcbcrConversion *pYcbcrConversion) -{ - struct vkCreateSamplerYcbcrConversionKHR_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pYcbcrConversion = pYcbcrConversion; - status = UNIX_CALL(vkCreateSamplerYcbcrConversionKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore) -{ - struct vkCreateSemaphore_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pSemaphore = pSemaphore; - status = UNIX_CALL(vkCreateSemaphore, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule) -{ - struct vkCreateShaderModule_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pShaderModule = pShaderModule; - status = UNIX_CALL(vkCreateShaderModule, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) -{ - struct vkCreateSwapchainKHR_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pSwapchain = pSwapchain; - status = UNIX_CALL(vkCreateSwapchainKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateValidationCacheEXT(VkDevice device, const VkValidationCacheCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkValidationCacheEXT *pValidationCache) -{ - struct vkCreateValidationCacheEXT_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pValidationCache = pValidationCache; - status = UNIX_CALL(vkCreateValidationCacheEXT, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkCreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) -{ - struct vkCreateWin32SurfaceKHR_params params; - NTSTATUS status; - params.instance = instance; - params.pCreateInfo = pCreateInfo; - params.pAllocator = pAllocator; - params.pSurface = pSurface; - status = UNIX_CALL(vkCreateWin32SurfaceKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkDebugMarkerSetObjectNameEXT(VkDevice device, const VkDebugMarkerObjectNameInfoEXT *pNameInfo) -{ - struct vkDebugMarkerSetObjectNameEXT_params params; - NTSTATUS status; - params.device = device; - params.pNameInfo = pNameInfo; - status = UNIX_CALL(vkDebugMarkerSetObjectNameEXT, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkDebugMarkerSetObjectTagEXT(VkDevice device, const VkDebugMarkerObjectTagInfoEXT *pTagInfo) -{ - struct vkDebugMarkerSetObjectTagEXT_params params; - NTSTATUS status; - params.device = device; - params.pTagInfo = pTagInfo; - status = UNIX_CALL(vkDebugMarkerSetObjectTagEXT, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char *pLayerPrefix, const char *pMessage) -{ - struct vkDebugReportMessageEXT_params params; - NTSTATUS status; - params.instance = instance; - params.flags = flags; - params.objectType = objectType; - params.object = object; - params.location = location; - params.messageCode = messageCode; - params.pLayerPrefix = pLayerPrefix; - params.pMessage = pMessage; - status = UNIX_CALL(vkDebugReportMessageEXT, ¶ms); - assert(!status); -} - -VkResult WINAPI vkDeferredOperationJoinKHR(VkDevice device, VkDeferredOperationKHR operation) -{ - struct vkDeferredOperationJoinKHR_params params; - NTSTATUS status; - params.device = device; - params.operation = operation; - status = UNIX_CALL(vkDeferredOperationJoinKHR, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkDestroyAccelerationStructureKHR(VkDevice device, VkAccelerationStructureKHR accelerationStructure, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyAccelerationStructureKHR_params params; - NTSTATUS status; - params.device = device; - params.accelerationStructure = accelerationStructure; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyAccelerationStructureKHR, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyAccelerationStructureNV(VkDevice device, VkAccelerationStructureNV accelerationStructure, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyAccelerationStructureNV_params params; - NTSTATUS status; - params.device = device; - params.accelerationStructure = accelerationStructure; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyAccelerationStructureNV, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyBuffer_params params; - NTSTATUS status; - params.device = device; - params.buffer = buffer; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyBuffer, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyBufferView_params params; - NTSTATUS status; - params.device = device; - params.bufferView = bufferView; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyBufferView, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyCuFunctionNVX(VkDevice device, VkCuFunctionNVX function, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyCuFunctionNVX_params params; - NTSTATUS status; - params.device = device; - params.function = function; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyCuFunctionNVX, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyCuModuleNVX(VkDevice device, VkCuModuleNVX module, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyCuModuleNVX_params params; - NTSTATUS status; - params.device = device; - params.module = module; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyCuModuleNVX, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyDebugReportCallbackEXT_params params; - NTSTATUS status; - params.instance = instance; - params.callback = callback; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyDebugReportCallbackEXT, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyDebugUtilsMessengerEXT_params params; - NTSTATUS status; - params.instance = instance; - params.messenger = messenger; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyDebugUtilsMessengerEXT, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyDeferredOperationKHR(VkDevice device, VkDeferredOperationKHR operation, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyDeferredOperationKHR_params params; - NTSTATUS status; - params.device = device; - params.operation = operation; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyDeferredOperationKHR, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyDescriptorPool_params params; - NTSTATUS status; - params.device = device; - params.descriptorPool = descriptorPool; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyDescriptorPool, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyDescriptorSetLayout_params params; - NTSTATUS status; - params.device = device; - params.descriptorSetLayout = descriptorSetLayout; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyDescriptorSetLayout, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyDescriptorUpdateTemplate_params params; - NTSTATUS status; - params.device = device; - params.descriptorUpdateTemplate = descriptorUpdateTemplate; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyDescriptorUpdateTemplate, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyDescriptorUpdateTemplateKHR(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyDescriptorUpdateTemplateKHR_params params; - NTSTATUS status; - params.device = device; - params.descriptorUpdateTemplate = descriptorUpdateTemplate; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyDescriptorUpdateTemplateKHR, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyEvent_params params; - NTSTATUS status; - params.device = device; - params.event = event; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyEvent, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyFence_params params; - NTSTATUS status; - params.device = device; - params.fence = fence; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyFence, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyFramebuffer_params params; - NTSTATUS status; - params.device = device; - params.framebuffer = framebuffer; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyFramebuffer, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyImage_params params; - NTSTATUS status; - params.device = device; - params.image = image; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyImage, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyImageView_params params; - NTSTATUS status; - params.device = device; - params.imageView = imageView; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyImageView, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyIndirectCommandsLayoutNV(VkDevice device, VkIndirectCommandsLayoutNV indirectCommandsLayout, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyIndirectCommandsLayoutNV_params params; - NTSTATUS status; - params.device = device; - params.indirectCommandsLayout = indirectCommandsLayout; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyIndirectCommandsLayoutNV, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyMicromapEXT(VkDevice device, VkMicromapEXT micromap, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyMicromapEXT_params params; - NTSTATUS status; - params.device = device; - params.micromap = micromap; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyMicromapEXT, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyOpticalFlowSessionNV(VkDevice device, VkOpticalFlowSessionNV session, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyOpticalFlowSessionNV_params params; - NTSTATUS status; - params.device = device; - params.session = session; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyOpticalFlowSessionNV, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyPipeline_params params; - NTSTATUS status; - params.device = device; - params.pipeline = pipeline; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyPipeline, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyPipelineCache_params params; - NTSTATUS status; - params.device = device; - params.pipelineCache = pipelineCache; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyPipelineCache, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyPipelineLayout_params params; - NTSTATUS status; - params.device = device; - params.pipelineLayout = pipelineLayout; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyPipelineLayout, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyPrivateDataSlot(VkDevice device, VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyPrivateDataSlot_params params; - NTSTATUS status; - params.device = device; - params.privateDataSlot = privateDataSlot; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyPrivateDataSlot, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyPrivateDataSlotEXT(VkDevice device, VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyPrivateDataSlotEXT_params params; - NTSTATUS status; - params.device = device; - params.privateDataSlot = privateDataSlot; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyPrivateDataSlotEXT, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyQueryPool_params params; - NTSTATUS status; - params.device = device; - params.queryPool = queryPool; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyQueryPool, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyRenderPass_params params; - NTSTATUS status; - params.device = device; - params.renderPass = renderPass; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyRenderPass, ¶ms); - assert(!status); -} - -void WINAPI vkDestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroySampler_params params; - NTSTATUS status; - params.device = device; - params.sampler = sampler; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroySampler, ¶ms); - assert(!status); -} - -void WINAPI vkDestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroySamplerYcbcrConversion_params params; - NTSTATUS status; - params.device = device; - params.ycbcrConversion = ycbcrConversion; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroySamplerYcbcrConversion, ¶ms); - assert(!status); -} - -void WINAPI vkDestroySamplerYcbcrConversionKHR(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroySamplerYcbcrConversionKHR_params params; - NTSTATUS status; - params.device = device; - params.ycbcrConversion = ycbcrConversion; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroySamplerYcbcrConversionKHR, ¶ms); - assert(!status); -} - -void WINAPI vkDestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroySemaphore_params params; - NTSTATUS status; - params.device = device; - params.semaphore = semaphore; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroySemaphore, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyShaderModule_params params; - NTSTATUS status; - params.device = device; - params.shaderModule = shaderModule; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyShaderModule, ¶ms); - assert(!status); -} - -void WINAPI vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroySurfaceKHR_params params; - NTSTATUS status; - params.instance = instance; - params.surface = surface; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroySurfaceKHR, ¶ms); - assert(!status); -} - -void WINAPI vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroySwapchainKHR_params params; - NTSTATUS status; - params.device = device; - params.swapchain = swapchain; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroySwapchainKHR, ¶ms); - assert(!status); -} - -void WINAPI vkDestroyValidationCacheEXT(VkDevice device, VkValidationCacheEXT validationCache, const VkAllocationCallbacks *pAllocator) -{ - struct vkDestroyValidationCacheEXT_params params; - NTSTATUS status; - params.device = device; - params.validationCache = validationCache; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkDestroyValidationCacheEXT, ¶ms); - assert(!status); -} - -VkResult WINAPI vkDeviceWaitIdle(VkDevice device) -{ - struct vkDeviceWaitIdle_params params; - NTSTATUS status; - params.device = device; - status = UNIX_CALL(vkDeviceWaitIdle, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkEndCommandBuffer(VkCommandBuffer commandBuffer) -{ - struct vkEndCommandBuffer_params params; - NTSTATUS status; - params.commandBuffer = commandBuffer; - status = UNIX_CALL(vkEndCommandBuffer, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName, uint32_t *pPropertyCount, VkExtensionProperties *pProperties) -{ - struct vkEnumerateDeviceExtensionProperties_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pLayerName = pLayerName; - params.pPropertyCount = pPropertyCount; - params.pProperties = pProperties; - status = UNIX_CALL(vkEnumerateDeviceExtensionProperties, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkLayerProperties *pProperties) -{ - struct vkEnumerateDeviceLayerProperties_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pPropertyCount = pPropertyCount; - params.pProperties = pProperties; - status = UNIX_CALL(vkEnumerateDeviceLayerProperties, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkEnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties) -{ - struct vkEnumeratePhysicalDeviceGroups_params params; - NTSTATUS status; - params.instance = instance; - params.pPhysicalDeviceGroupCount = pPhysicalDeviceGroupCount; - params.pPhysicalDeviceGroupProperties = pPhysicalDeviceGroupProperties; - status = UNIX_CALL(vkEnumeratePhysicalDeviceGroups, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkEnumeratePhysicalDeviceGroupsKHR(VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties) -{ - struct vkEnumeratePhysicalDeviceGroupsKHR_params params; - NTSTATUS status; - params.instance = instance; - params.pPhysicalDeviceGroupCount = pPhysicalDeviceGroupCount; - params.pPhysicalDeviceGroupProperties = pPhysicalDeviceGroupProperties; - status = UNIX_CALL(vkEnumeratePhysicalDeviceGroupsKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, uint32_t *pCounterCount, VkPerformanceCounterKHR *pCounters, VkPerformanceCounterDescriptionKHR *pCounterDescriptions) -{ - struct vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.queueFamilyIndex = queueFamilyIndex; - params.pCounterCount = pCounterCount; - params.pCounters = pCounters; - params.pCounterDescriptions = pCounterDescriptions; - status = UNIX_CALL(vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices) -{ - struct vkEnumeratePhysicalDevices_params params; - NTSTATUS status; - params.instance = instance; - params.pPhysicalDeviceCount = pPhysicalDeviceCount; - params.pPhysicalDevices = pPhysicalDevices; - status = UNIX_CALL(vkEnumeratePhysicalDevices, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkFlushMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange *pMemoryRanges) -{ - struct vkFlushMappedMemoryRanges_params params; - NTSTATUS status; - params.device = device; - params.memoryRangeCount = memoryRangeCount; - params.pMemoryRanges = pMemoryRanges; - status = UNIX_CALL(vkFlushMappedMemoryRanges, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets) -{ - struct vkFreeDescriptorSets_params params; - NTSTATUS status; - params.device = device; - params.descriptorPool = descriptorPool; - params.descriptorSetCount = descriptorSetCount; - params.pDescriptorSets = pDescriptorSets; - status = UNIX_CALL(vkFreeDescriptorSets, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkFreeMemory(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks *pAllocator) -{ - struct vkFreeMemory_params params; - NTSTATUS status; - params.device = device; - params.memory = memory; - params.pAllocator = pAllocator; - status = UNIX_CALL(vkFreeMemory, ¶ms); - assert(!status); -} - -void WINAPI vkGetAccelerationStructureBuildSizesKHR(VkDevice device, VkAccelerationStructureBuildTypeKHR buildType, const VkAccelerationStructureBuildGeometryInfoKHR *pBuildInfo, const uint32_t *pMaxPrimitiveCounts, VkAccelerationStructureBuildSizesInfoKHR *pSizeInfo) -{ - struct vkGetAccelerationStructureBuildSizesKHR_params params; - NTSTATUS status; - params.device = device; - params.buildType = buildType; - params.pBuildInfo = pBuildInfo; - params.pMaxPrimitiveCounts = pMaxPrimitiveCounts; - params.pSizeInfo = pSizeInfo; - status = UNIX_CALL(vkGetAccelerationStructureBuildSizesKHR, ¶ms); - assert(!status); -} - -VkDeviceAddress WINAPI vkGetAccelerationStructureDeviceAddressKHR(VkDevice device, const VkAccelerationStructureDeviceAddressInfoKHR *pInfo) -{ - struct vkGetAccelerationStructureDeviceAddressKHR_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - status = UNIX_CALL(vkGetAccelerationStructureDeviceAddressKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetAccelerationStructureHandleNV(VkDevice device, VkAccelerationStructureNV accelerationStructure, size_t dataSize, void *pData) -{ - struct vkGetAccelerationStructureHandleNV_params params; - NTSTATUS status; - params.device = device; - params.accelerationStructure = accelerationStructure; - params.dataSize = dataSize; - params.pData = pData; - status = UNIX_CALL(vkGetAccelerationStructureHandleNV, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkGetAccelerationStructureMemoryRequirementsNV(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNV *pInfo, VkMemoryRequirements2KHR *pMemoryRequirements) -{ - struct vkGetAccelerationStructureMemoryRequirementsNV_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pMemoryRequirements = pMemoryRequirements; - status = UNIX_CALL(vkGetAccelerationStructureMemoryRequirementsNV, ¶ms); - assert(!status); -} - -VkResult WINAPI vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT(VkDevice device, const VkAccelerationStructureCaptureDescriptorDataInfoEXT *pInfo, void *pData) -{ - struct vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pData = pData; - status = UNIX_CALL(vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT, ¶ms); - assert(!status); - return params.result; -} - -VkDeviceAddress WINAPI vkGetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo *pInfo) -{ - struct vkGetBufferDeviceAddress_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - status = UNIX_CALL(vkGetBufferDeviceAddress, ¶ms); - assert(!status); - return params.result; -} - -VkDeviceAddress WINAPI vkGetBufferDeviceAddressEXT(VkDevice device, const VkBufferDeviceAddressInfo *pInfo) -{ - struct vkGetBufferDeviceAddressEXT_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - status = UNIX_CALL(vkGetBufferDeviceAddressEXT, ¶ms); - assert(!status); - return params.result; -} - -VkDeviceAddress WINAPI vkGetBufferDeviceAddressKHR(VkDevice device, const VkBufferDeviceAddressInfo *pInfo) -{ - struct vkGetBufferDeviceAddressKHR_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - status = UNIX_CALL(vkGetBufferDeviceAddressKHR, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements) -{ - struct vkGetBufferMemoryRequirements_params params; - NTSTATUS status; - params.device = device; - params.buffer = buffer; - params.pMemoryRequirements = pMemoryRequirements; - status = UNIX_CALL(vkGetBufferMemoryRequirements, ¶ms); - assert(!status); -} - -void WINAPI vkGetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2 *pInfo, VkMemoryRequirements2 *pMemoryRequirements) -{ - struct vkGetBufferMemoryRequirements2_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pMemoryRequirements = pMemoryRequirements; - status = UNIX_CALL(vkGetBufferMemoryRequirements2, ¶ms); - assert(!status); -} - -void WINAPI vkGetBufferMemoryRequirements2KHR(VkDevice device, const VkBufferMemoryRequirementsInfo2 *pInfo, VkMemoryRequirements2 *pMemoryRequirements) -{ - struct vkGetBufferMemoryRequirements2KHR_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pMemoryRequirements = pMemoryRequirements; - status = UNIX_CALL(vkGetBufferMemoryRequirements2KHR, ¶ms); - assert(!status); -} - -uint64_t WINAPI vkGetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo *pInfo) -{ - struct vkGetBufferOpaqueCaptureAddress_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - status = UNIX_CALL(vkGetBufferOpaqueCaptureAddress, ¶ms); - assert(!status); - return params.result; -} - -uint64_t WINAPI vkGetBufferOpaqueCaptureAddressKHR(VkDevice device, const VkBufferDeviceAddressInfo *pInfo) -{ - struct vkGetBufferOpaqueCaptureAddressKHR_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - status = UNIX_CALL(vkGetBufferOpaqueCaptureAddressKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetBufferOpaqueCaptureDescriptorDataEXT(VkDevice device, const VkBufferCaptureDescriptorDataInfoEXT *pInfo, void *pData) -{ - struct vkGetBufferOpaqueCaptureDescriptorDataEXT_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pData = pData; - status = UNIX_CALL(vkGetBufferOpaqueCaptureDescriptorDataEXT, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetCalibratedTimestampsEXT(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoEXT *pTimestampInfos, uint64_t *pTimestamps, uint64_t *pMaxDeviation) -{ - struct vkGetCalibratedTimestampsEXT_params params; - NTSTATUS status; - params.device = device; - params.timestampCount = timestampCount; - params.pTimestampInfos = pTimestampInfos; - params.pTimestamps = pTimestamps; - params.pMaxDeviation = pMaxDeviation; - status = UNIX_CALL(vkGetCalibratedTimestampsEXT, ¶ms); - assert(!status); - return params.result; -} - -uint32_t WINAPI vkGetDeferredOperationMaxConcurrencyKHR(VkDevice device, VkDeferredOperationKHR operation) -{ - struct vkGetDeferredOperationMaxConcurrencyKHR_params params; - NTSTATUS status; - params.device = device; - params.operation = operation; - status = UNIX_CALL(vkGetDeferredOperationMaxConcurrencyKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetDeferredOperationResultKHR(VkDevice device, VkDeferredOperationKHR operation) -{ - struct vkGetDeferredOperationResultKHR_params params; - NTSTATUS status; - params.device = device; - params.operation = operation; - status = UNIX_CALL(vkGetDeferredOperationResultKHR, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkGetDescriptorEXT(VkDevice device, const VkDescriptorGetInfoEXT *pDescriptorInfo, size_t dataSize, void *pDescriptor) -{ - struct vkGetDescriptorEXT_params params; - params.device = device; - params.pDescriptorInfo = pDescriptorInfo; - params.dataSize = dataSize; - params.pDescriptor = pDescriptor; - UNIX_CALL(vkGetDescriptorEXT, ¶ms); -} - -void WINAPI vkGetDescriptorSetHostMappingVALVE(VkDevice device, VkDescriptorSet descriptorSet, void **ppData) -{ - struct vkGetDescriptorSetHostMappingVALVE_params params; - NTSTATUS status; - params.device = device; - params.descriptorSet = descriptorSet; - params.ppData = ppData; - status = UNIX_CALL(vkGetDescriptorSetHostMappingVALVE, ¶ms); - assert(!status); -} - -void WINAPI vkGetDescriptorSetLayoutBindingOffsetEXT(VkDevice device, VkDescriptorSetLayout layout, uint32_t binding, VkDeviceSize *pOffset) -{ - struct vkGetDescriptorSetLayoutBindingOffsetEXT_params params; - NTSTATUS status; - params.device = device; - params.layout = layout; - params.binding = binding; - params.pOffset = pOffset; - status = UNIX_CALL(vkGetDescriptorSetLayoutBindingOffsetEXT, ¶ms); - assert(!status); -} - -void WINAPI vkGetDescriptorSetLayoutHostMappingInfoVALVE(VkDevice device, const VkDescriptorSetBindingReferenceVALVE *pBindingReference, VkDescriptorSetLayoutHostMappingInfoVALVE *pHostMapping) -{ - struct vkGetDescriptorSetLayoutHostMappingInfoVALVE_params params; - NTSTATUS status; - params.device = device; - params.pBindingReference = pBindingReference; - params.pHostMapping = pHostMapping; - status = UNIX_CALL(vkGetDescriptorSetLayoutHostMappingInfoVALVE, ¶ms); - assert(!status); -} - -void WINAPI vkGetDescriptorSetLayoutSizeEXT(VkDevice device, VkDescriptorSetLayout layout, VkDeviceSize *pLayoutSizeInBytes) -{ - struct vkGetDescriptorSetLayoutSizeEXT_params params; - NTSTATUS status; - params.device = device; - params.layout = layout; - params.pLayoutSizeInBytes = pLayoutSizeInBytes; - status = UNIX_CALL(vkGetDescriptorSetLayoutSizeEXT, ¶ms); - assert(!status); -} - -void WINAPI vkGetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, VkDescriptorSetLayoutSupport *pSupport) -{ - struct vkGetDescriptorSetLayoutSupport_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pSupport = pSupport; - status = UNIX_CALL(vkGetDescriptorSetLayoutSupport, ¶ms); - assert(!status); -} - -void WINAPI vkGetDescriptorSetLayoutSupportKHR(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, VkDescriptorSetLayoutSupport *pSupport) -{ - struct vkGetDescriptorSetLayoutSupportKHR_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pSupport = pSupport; - status = UNIX_CALL(vkGetDescriptorSetLayoutSupportKHR, ¶ms); - assert(!status); -} - -void WINAPI vkGetDeviceAccelerationStructureCompatibilityKHR(VkDevice device, const VkAccelerationStructureVersionInfoKHR *pVersionInfo, VkAccelerationStructureCompatibilityKHR *pCompatibility) -{ - struct vkGetDeviceAccelerationStructureCompatibilityKHR_params params; - NTSTATUS status; - params.device = device; - params.pVersionInfo = pVersionInfo; - params.pCompatibility = pCompatibility; - status = UNIX_CALL(vkGetDeviceAccelerationStructureCompatibilityKHR, ¶ms); - assert(!status); -} - -void WINAPI vkGetDeviceBufferMemoryRequirements(VkDevice device, const VkDeviceBufferMemoryRequirements *pInfo, VkMemoryRequirements2 *pMemoryRequirements) -{ - struct vkGetDeviceBufferMemoryRequirements_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pMemoryRequirements = pMemoryRequirements; - status = UNIX_CALL(vkGetDeviceBufferMemoryRequirements, ¶ms); - assert(!status); -} - -void WINAPI vkGetDeviceBufferMemoryRequirementsKHR(VkDevice device, const VkDeviceBufferMemoryRequirements *pInfo, VkMemoryRequirements2 *pMemoryRequirements) -{ - struct vkGetDeviceBufferMemoryRequirementsKHR_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pMemoryRequirements = pMemoryRequirements; - status = UNIX_CALL(vkGetDeviceBufferMemoryRequirementsKHR, ¶ms); - assert(!status); -} - -VkResult WINAPI vkGetDeviceFaultInfoEXT(VkDevice device, VkDeviceFaultCountsEXT *pFaultCounts, VkDeviceFaultInfoEXT *pFaultInfo) -{ - struct vkGetDeviceFaultInfoEXT_params params; - NTSTATUS status; - params.device = device; - params.pFaultCounts = pFaultCounts; - params.pFaultInfo = pFaultInfo; - status = UNIX_CALL(vkGetDeviceFaultInfoEXT, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkGetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags *pPeerMemoryFeatures) -{ - struct vkGetDeviceGroupPeerMemoryFeatures_params params; - NTSTATUS status; - params.device = device; - params.heapIndex = heapIndex; - params.localDeviceIndex = localDeviceIndex; - params.remoteDeviceIndex = remoteDeviceIndex; - params.pPeerMemoryFeatures = pPeerMemoryFeatures; - status = UNIX_CALL(vkGetDeviceGroupPeerMemoryFeatures, ¶ms); - assert(!status); -} - -void WINAPI vkGetDeviceGroupPeerMemoryFeaturesKHR(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags *pPeerMemoryFeatures) -{ - struct vkGetDeviceGroupPeerMemoryFeaturesKHR_params params; - NTSTATUS status; - params.device = device; - params.heapIndex = heapIndex; - params.localDeviceIndex = localDeviceIndex; - params.remoteDeviceIndex = remoteDeviceIndex; - params.pPeerMemoryFeatures = pPeerMemoryFeatures; - status = UNIX_CALL(vkGetDeviceGroupPeerMemoryFeaturesKHR, ¶ms); - assert(!status); -} - -VkResult WINAPI vkGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR *pDeviceGroupPresentCapabilities) -{ - struct vkGetDeviceGroupPresentCapabilitiesKHR_params params; - NTSTATUS status; - params.device = device; - params.pDeviceGroupPresentCapabilities = pDeviceGroupPresentCapabilities; - status = UNIX_CALL(vkGetDeviceGroupPresentCapabilitiesKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR *pModes) -{ - struct vkGetDeviceGroupSurfacePresentModesKHR_params params; - NTSTATUS status; - params.device = device; - params.surface = surface; - params.pModes = pModes; - status = UNIX_CALL(vkGetDeviceGroupSurfacePresentModesKHR, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkGetDeviceImageMemoryRequirements(VkDevice device, const VkDeviceImageMemoryRequirements *pInfo, VkMemoryRequirements2 *pMemoryRequirements) -{ - struct vkGetDeviceImageMemoryRequirements_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pMemoryRequirements = pMemoryRequirements; - status = UNIX_CALL(vkGetDeviceImageMemoryRequirements, ¶ms); - assert(!status); -} - -void WINAPI vkGetDeviceImageMemoryRequirementsKHR(VkDevice device, const VkDeviceImageMemoryRequirements *pInfo, VkMemoryRequirements2 *pMemoryRequirements) -{ - struct vkGetDeviceImageMemoryRequirementsKHR_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pMemoryRequirements = pMemoryRequirements; - status = UNIX_CALL(vkGetDeviceImageMemoryRequirementsKHR, ¶ms); - assert(!status); -} - -void WINAPI vkGetDeviceImageSparseMemoryRequirements(VkDevice device, const VkDeviceImageMemoryRequirements *pInfo, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements) -{ - struct vkGetDeviceImageSparseMemoryRequirements_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pSparseMemoryRequirementCount = pSparseMemoryRequirementCount; - params.pSparseMemoryRequirements = pSparseMemoryRequirements; - status = UNIX_CALL(vkGetDeviceImageSparseMemoryRequirements, ¶ms); - assert(!status); -} - -void WINAPI vkGetDeviceImageSparseMemoryRequirementsKHR(VkDevice device, const VkDeviceImageMemoryRequirements *pInfo, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements) -{ - struct vkGetDeviceImageSparseMemoryRequirementsKHR_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pSparseMemoryRequirementCount = pSparseMemoryRequirementCount; - params.pSparseMemoryRequirements = pSparseMemoryRequirements; - status = UNIX_CALL(vkGetDeviceImageSparseMemoryRequirementsKHR, ¶ms); - assert(!status); -} - -void WINAPI vkGetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory memory, VkDeviceSize *pCommittedMemoryInBytes) -{ - struct vkGetDeviceMemoryCommitment_params params; - NTSTATUS status; - params.device = device; - params.memory = memory; - params.pCommittedMemoryInBytes = pCommittedMemoryInBytes; - status = UNIX_CALL(vkGetDeviceMemoryCommitment, ¶ms); - assert(!status); -} - -uint64_t WINAPI vkGetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo *pInfo) -{ - struct vkGetDeviceMemoryOpaqueCaptureAddress_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - status = UNIX_CALL(vkGetDeviceMemoryOpaqueCaptureAddress, ¶ms); - assert(!status); - return params.result; -} - -uint64_t WINAPI vkGetDeviceMemoryOpaqueCaptureAddressKHR(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo *pInfo) -{ - struct vkGetDeviceMemoryOpaqueCaptureAddressKHR_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - status = UNIX_CALL(vkGetDeviceMemoryOpaqueCaptureAddressKHR, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkGetDeviceMicromapCompatibilityEXT(VkDevice device, const VkMicromapVersionInfoEXT *pVersionInfo, VkAccelerationStructureCompatibilityKHR *pCompatibility) -{ - struct vkGetDeviceMicromapCompatibilityEXT_params params; - NTSTATUS status; - params.device = device; - params.pVersionInfo = pVersionInfo; - params.pCompatibility = pCompatibility; - status = UNIX_CALL(vkGetDeviceMicromapCompatibilityEXT, ¶ms); - assert(!status); -} - -void WINAPI vkGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) -{ - struct vkGetDeviceQueue_params params; - NTSTATUS status; - params.device = device; - params.queueFamilyIndex = queueFamilyIndex; - params.queueIndex = queueIndex; - params.pQueue = pQueue; - status = UNIX_CALL(vkGetDeviceQueue, ¶ms); - assert(!status); -} - -void WINAPI vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 *pQueueInfo, VkQueue *pQueue) -{ - struct vkGetDeviceQueue2_params params; - NTSTATUS status; - params.device = device; - params.pQueueInfo = pQueueInfo; - params.pQueue = pQueue; - status = UNIX_CALL(vkGetDeviceQueue2, ¶ms); - assert(!status); -} - -VkResult WINAPI vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI(VkDevice device, VkRenderPass renderpass, VkExtent2D *pMaxWorkgroupSize) -{ - struct vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI_params params; - NTSTATUS status; - params.device = device; - params.renderpass = renderpass; - params.pMaxWorkgroupSize = pMaxWorkgroupSize; - status = UNIX_CALL(vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetDynamicRenderingTilePropertiesQCOM(VkDevice device, const VkRenderingInfo *pRenderingInfo, VkTilePropertiesQCOM *pProperties) -{ - struct vkGetDynamicRenderingTilePropertiesQCOM_params params; - NTSTATUS status; - params.device = device; - params.pRenderingInfo = pRenderingInfo; - params.pProperties = pProperties; - status = UNIX_CALL(vkGetDynamicRenderingTilePropertiesQCOM, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetEventStatus(VkDevice device, VkEvent event) -{ - struct vkGetEventStatus_params params; - NTSTATUS status; - params.device = device; - params.event = event; - status = UNIX_CALL(vkGetEventStatus, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetFenceStatus(VkDevice device, VkFence fence) -{ - struct vkGetFenceStatus_params params; - NTSTATUS status; - params.device = device; - params.fence = fence; - status = UNIX_CALL(vkGetFenceStatus, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetFramebufferTilePropertiesQCOM(VkDevice device, VkFramebuffer framebuffer, uint32_t *pPropertiesCount, VkTilePropertiesQCOM *pProperties) -{ - struct vkGetFramebufferTilePropertiesQCOM_params params; - NTSTATUS status; - params.device = device; - params.framebuffer = framebuffer; - params.pPropertiesCount = pPropertiesCount; - params.pProperties = pProperties; - status = UNIX_CALL(vkGetFramebufferTilePropertiesQCOM, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkGetGeneratedCommandsMemoryRequirementsNV(VkDevice device, const VkGeneratedCommandsMemoryRequirementsInfoNV *pInfo, VkMemoryRequirements2 *pMemoryRequirements) -{ - struct vkGetGeneratedCommandsMemoryRequirementsNV_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pMemoryRequirements = pMemoryRequirements; - status = UNIX_CALL(vkGetGeneratedCommandsMemoryRequirementsNV, ¶ms); - assert(!status); -} - -void WINAPI vkGetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements) -{ - struct vkGetImageMemoryRequirements_params params; - NTSTATUS status; - params.device = device; - params.image = image; - params.pMemoryRequirements = pMemoryRequirements; - status = UNIX_CALL(vkGetImageMemoryRequirements, ¶ms); - assert(!status); -} - -void WINAPI vkGetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2 *pInfo, VkMemoryRequirements2 *pMemoryRequirements) -{ - struct vkGetImageMemoryRequirements2_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pMemoryRequirements = pMemoryRequirements; - status = UNIX_CALL(vkGetImageMemoryRequirements2, ¶ms); - assert(!status); -} - -void WINAPI vkGetImageMemoryRequirements2KHR(VkDevice device, const VkImageMemoryRequirementsInfo2 *pInfo, VkMemoryRequirements2 *pMemoryRequirements) -{ - struct vkGetImageMemoryRequirements2KHR_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pMemoryRequirements = pMemoryRequirements; - status = UNIX_CALL(vkGetImageMemoryRequirements2KHR, ¶ms); - assert(!status); -} - -VkResult WINAPI vkGetImageOpaqueCaptureDescriptorDataEXT(VkDevice device, const VkImageCaptureDescriptorDataInfoEXT *pInfo, void *pData) -{ - struct vkGetImageOpaqueCaptureDescriptorDataEXT_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pData = pData; - status = UNIX_CALL(vkGetImageOpaqueCaptureDescriptorDataEXT, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkGetImageSparseMemoryRequirements(VkDevice device, VkImage image, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements *pSparseMemoryRequirements) -{ - struct vkGetImageSparseMemoryRequirements_params params; - NTSTATUS status; - params.device = device; - params.image = image; - params.pSparseMemoryRequirementCount = pSparseMemoryRequirementCount; - params.pSparseMemoryRequirements = pSparseMemoryRequirements; - status = UNIX_CALL(vkGetImageSparseMemoryRequirements, ¶ms); - assert(!status); -} - -void WINAPI vkGetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2 *pInfo, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements) -{ - struct vkGetImageSparseMemoryRequirements2_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pSparseMemoryRequirementCount = pSparseMemoryRequirementCount; - params.pSparseMemoryRequirements = pSparseMemoryRequirements; - status = UNIX_CALL(vkGetImageSparseMemoryRequirements2, ¶ms); - assert(!status); -} - -void WINAPI vkGetImageSparseMemoryRequirements2KHR(VkDevice device, const VkImageSparseMemoryRequirementsInfo2 *pInfo, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements) -{ - struct vkGetImageSparseMemoryRequirements2KHR_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pSparseMemoryRequirementCount = pSparseMemoryRequirementCount; - params.pSparseMemoryRequirements = pSparseMemoryRequirements; - status = UNIX_CALL(vkGetImageSparseMemoryRequirements2KHR, ¶ms); - assert(!status); -} - -void WINAPI vkGetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource, VkSubresourceLayout *pLayout) -{ - struct vkGetImageSubresourceLayout_params params; - NTSTATUS status; - params.device = device; - params.image = image; - params.pSubresource = pSubresource; - params.pLayout = pLayout; - status = UNIX_CALL(vkGetImageSubresourceLayout, ¶ms); - assert(!status); -} - -void WINAPI vkGetImageSubresourceLayout2EXT(VkDevice device, VkImage image, const VkImageSubresource2EXT *pSubresource, VkSubresourceLayout2EXT *pLayout) -{ - struct vkGetImageSubresourceLayout2EXT_params params; - NTSTATUS status; - params.device = device; - params.image = image; - params.pSubresource = pSubresource; - params.pLayout = pLayout; - status = UNIX_CALL(vkGetImageSubresourceLayout2EXT, ¶ms); - assert(!status); -} - -VkResult WINAPI vkGetImageViewAddressNVX(VkDevice device, VkImageView imageView, VkImageViewAddressPropertiesNVX *pProperties) -{ - struct vkGetImageViewAddressNVX_params params; - NTSTATUS status; - params.device = device; - params.imageView = imageView; - params.pProperties = pProperties; - status = UNIX_CALL(vkGetImageViewAddressNVX, ¶ms); - assert(!status); - return params.result; -} - -uint32_t WINAPI vkGetImageViewHandleNVX(VkDevice device, const VkImageViewHandleInfoNVX *pInfo) -{ - struct vkGetImageViewHandleNVX_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - status = UNIX_CALL(vkGetImageViewHandleNVX, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetImageViewOpaqueCaptureDescriptorDataEXT(VkDevice device, const VkImageViewCaptureDescriptorDataInfoEXT *pInfo, void *pData) -{ - struct vkGetImageViewOpaqueCaptureDescriptorDataEXT_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pData = pData; - status = UNIX_CALL(vkGetImageViewOpaqueCaptureDescriptorDataEXT, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetMemoryHostPointerPropertiesEXT(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, const void *pHostPointer, VkMemoryHostPointerPropertiesEXT *pMemoryHostPointerProperties) -{ - struct vkGetMemoryHostPointerPropertiesEXT_params params; - NTSTATUS status; - params.device = device; - params.handleType = handleType; - params.pHostPointer = pHostPointer; - params.pMemoryHostPointerProperties = pMemoryHostPointerProperties; - status = UNIX_CALL(vkGetMemoryHostPointerPropertiesEXT, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkGetMicromapBuildSizesEXT(VkDevice device, VkAccelerationStructureBuildTypeKHR buildType, const VkMicromapBuildInfoEXT *pBuildInfo, VkMicromapBuildSizesInfoEXT *pSizeInfo) -{ - struct vkGetMicromapBuildSizesEXT_params params; - NTSTATUS status; - params.device = device; - params.buildType = buildType; - params.pBuildInfo = pBuildInfo; - params.pSizeInfo = pSizeInfo; - status = UNIX_CALL(vkGetMicromapBuildSizesEXT, ¶ms); - assert(!status); -} - -VkResult WINAPI vkGetPerformanceParameterINTEL(VkDevice device, VkPerformanceParameterTypeINTEL parameter, VkPerformanceValueINTEL *pValue) -{ - struct vkGetPerformanceParameterINTEL_params params; - NTSTATUS status; - params.device = device; - params.parameter = parameter; - params.pValue = pValue; - status = UNIX_CALL(vkGetPerformanceParameterINTEL, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(VkPhysicalDevice physicalDevice, uint32_t *pTimeDomainCount, VkTimeDomainEXT *pTimeDomains) -{ - struct vkGetPhysicalDeviceCalibrateableTimeDomainsEXT_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pTimeDomainCount = pTimeDomainCount; - params.pTimeDomains = pTimeDomains; - status = UNIX_CALL(vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPhysicalDeviceCooperativeMatrixPropertiesNV(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkCooperativeMatrixPropertiesNV *pProperties) -{ - struct vkGetPhysicalDeviceCooperativeMatrixPropertiesNV_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pPropertyCount = pPropertyCount; - params.pProperties = pProperties; - status = UNIX_CALL(vkGetPhysicalDeviceCooperativeMatrixPropertiesNV, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, VkExternalBufferProperties *pExternalBufferProperties) -{ - struct vkGetPhysicalDeviceExternalBufferProperties_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pExternalBufferInfo = pExternalBufferInfo; - params.pExternalBufferProperties = pExternalBufferProperties; - status = UNIX_CALL(vkGetPhysicalDeviceExternalBufferProperties, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, VkExternalBufferProperties *pExternalBufferProperties) -{ - struct vkGetPhysicalDeviceExternalBufferPropertiesKHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pExternalBufferInfo = pExternalBufferInfo; - params.pExternalBufferProperties = pExternalBufferProperties; - status = UNIX_CALL(vkGetPhysicalDeviceExternalBufferPropertiesKHR, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo, VkExternalFenceProperties *pExternalFenceProperties) -{ - struct vkGetPhysicalDeviceExternalFenceProperties_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pExternalFenceInfo = pExternalFenceInfo; - params.pExternalFenceProperties = pExternalFenceProperties; - status = UNIX_CALL(vkGetPhysicalDeviceExternalFenceProperties, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceExternalFencePropertiesKHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo, VkExternalFenceProperties *pExternalFenceProperties) -{ - struct vkGetPhysicalDeviceExternalFencePropertiesKHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pExternalFenceInfo = pExternalFenceInfo; - params.pExternalFenceProperties = pExternalFenceProperties; - status = UNIX_CALL(vkGetPhysicalDeviceExternalFencePropertiesKHR, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo, VkExternalSemaphoreProperties *pExternalSemaphoreProperties) -{ - struct vkGetPhysicalDeviceExternalSemaphoreProperties_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pExternalSemaphoreInfo = pExternalSemaphoreInfo; - params.pExternalSemaphoreProperties = pExternalSemaphoreProperties; - status = UNIX_CALL(vkGetPhysicalDeviceExternalSemaphoreProperties, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo, VkExternalSemaphoreProperties *pExternalSemaphoreProperties) -{ - struct vkGetPhysicalDeviceExternalSemaphorePropertiesKHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pExternalSemaphoreInfo = pExternalSemaphoreInfo; - params.pExternalSemaphoreProperties = pExternalSemaphoreProperties; - status = UNIX_CALL(vkGetPhysicalDeviceExternalSemaphorePropertiesKHR, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures *pFeatures) -{ - struct vkGetPhysicalDeviceFeatures_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pFeatures = pFeatures; - status = UNIX_CALL(vkGetPhysicalDeviceFeatures, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2 *pFeatures) -{ - struct vkGetPhysicalDeviceFeatures2_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pFeatures = pFeatures; - status = UNIX_CALL(vkGetPhysicalDeviceFeatures2, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceFeatures2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2 *pFeatures) -{ - struct vkGetPhysicalDeviceFeatures2KHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pFeatures = pFeatures; - status = UNIX_CALL(vkGetPhysicalDeviceFeatures2KHR, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties *pFormatProperties) -{ - struct vkGetPhysicalDeviceFormatProperties_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.format = format; - params.pFormatProperties = pFormatProperties; - status = UNIX_CALL(vkGetPhysicalDeviceFormatProperties, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2 *pFormatProperties) -{ - struct vkGetPhysicalDeviceFormatProperties2_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.format = format; - params.pFormatProperties = pFormatProperties; - status = UNIX_CALL(vkGetPhysicalDeviceFormatProperties2, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceFormatProperties2KHR(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2 *pFormatProperties) -{ - struct vkGetPhysicalDeviceFormatProperties2KHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.format = format; - params.pFormatProperties = pFormatProperties; - status = UNIX_CALL(vkGetPhysicalDeviceFormatProperties2KHR, ¶ms); - assert(!status); -} - -VkResult WINAPI vkGetPhysicalDeviceFragmentShadingRatesKHR(VkPhysicalDevice physicalDevice, uint32_t *pFragmentShadingRateCount, VkPhysicalDeviceFragmentShadingRateKHR *pFragmentShadingRates) -{ - struct vkGetPhysicalDeviceFragmentShadingRatesKHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pFragmentShadingRateCount = pFragmentShadingRateCount; - params.pFragmentShadingRates = pFragmentShadingRates; - status = UNIX_CALL(vkGetPhysicalDeviceFragmentShadingRatesKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties *pImageFormatProperties) -{ - struct vkGetPhysicalDeviceImageFormatProperties_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.format = format; - params.type = type; - params.tiling = tiling; - params.usage = usage; - params.flags = flags; - params.pImageFormatProperties = pImageFormatProperties; - status = UNIX_CALL(vkGetPhysicalDeviceImageFormatProperties, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties) -{ - struct vkGetPhysicalDeviceImageFormatProperties2_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pImageFormatInfo = pImageFormatInfo; - params.pImageFormatProperties = pImageFormatProperties; - status = UNIX_CALL(vkGetPhysicalDeviceImageFormatProperties2, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties) -{ - struct vkGetPhysicalDeviceImageFormatProperties2KHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pImageFormatInfo = pImageFormatInfo; - params.pImageFormatProperties = pImageFormatProperties; - status = UNIX_CALL(vkGetPhysicalDeviceImageFormatProperties2KHR, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkGetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties *pMemoryProperties) -{ - struct vkGetPhysicalDeviceMemoryProperties_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pMemoryProperties = pMemoryProperties; - status = UNIX_CALL(vkGetPhysicalDeviceMemoryProperties, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2 *pMemoryProperties) -{ - struct vkGetPhysicalDeviceMemoryProperties2_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pMemoryProperties = pMemoryProperties; - status = UNIX_CALL(vkGetPhysicalDeviceMemoryProperties2, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceMemoryProperties2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2 *pMemoryProperties) -{ - struct vkGetPhysicalDeviceMemoryProperties2KHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pMemoryProperties = pMemoryProperties; - status = UNIX_CALL(vkGetPhysicalDeviceMemoryProperties2KHR, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceMultisamplePropertiesEXT(VkPhysicalDevice physicalDevice, VkSampleCountFlagBits samples, VkMultisamplePropertiesEXT *pMultisampleProperties) -{ - struct vkGetPhysicalDeviceMultisamplePropertiesEXT_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.samples = samples; - params.pMultisampleProperties = pMultisampleProperties; - status = UNIX_CALL(vkGetPhysicalDeviceMultisamplePropertiesEXT, ¶ms); - assert(!status); -} - -VkResult WINAPI vkGetPhysicalDeviceOpticalFlowImageFormatsNV(VkPhysicalDevice physicalDevice, const VkOpticalFlowImageFormatInfoNV *pOpticalFlowImageFormatInfo, uint32_t *pFormatCount, VkOpticalFlowImageFormatPropertiesNV *pImageFormatProperties) -{ - struct vkGetPhysicalDeviceOpticalFlowImageFormatsNV_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pOpticalFlowImageFormatInfo = pOpticalFlowImageFormatInfo; - params.pFormatCount = pFormatCount; - params.pImageFormatProperties = pImageFormatProperties; - status = UNIX_CALL(vkGetPhysicalDeviceOpticalFlowImageFormatsNV, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pRectCount, VkRect2D *pRects) -{ - struct vkGetPhysicalDevicePresentRectanglesKHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.surface = surface; - params.pRectCount = pRectCount; - params.pRects = pRects; - status = UNIX_CALL(vkGetPhysicalDevicePresentRectanglesKHR, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties) -{ - struct vkGetPhysicalDeviceProperties_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pProperties = pProperties; - status = UNIX_CALL(vkGetPhysicalDeviceProperties, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR(VkPhysicalDevice physicalDevice, const VkQueryPoolPerformanceCreateInfoKHR *pPerformanceQueryCreateInfo, uint32_t *pNumPasses) -{ - struct vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pPerformanceQueryCreateInfo = pPerformanceQueryCreateInfo; - params.pNumPasses = pNumPasses; - status = UNIX_CALL(vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties *pQueueFamilyProperties) -{ - struct vkGetPhysicalDeviceQueueFamilyProperties_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pQueueFamilyPropertyCount = pQueueFamilyPropertyCount; - params.pQueueFamilyProperties = pQueueFamilyProperties; - status = UNIX_CALL(vkGetPhysicalDeviceQueueFamilyProperties, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2 *pQueueFamilyProperties) -{ - struct vkGetPhysicalDeviceQueueFamilyProperties2_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pQueueFamilyPropertyCount = pQueueFamilyPropertyCount; - params.pQueueFamilyProperties = pQueueFamilyProperties; - status = UNIX_CALL(vkGetPhysicalDeviceQueueFamilyProperties2, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2 *pQueueFamilyProperties) -{ - struct vkGetPhysicalDeviceQueueFamilyProperties2KHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pQueueFamilyPropertyCount = pQueueFamilyPropertyCount; - params.pQueueFamilyProperties = pQueueFamilyProperties; - status = UNIX_CALL(vkGetPhysicalDeviceQueueFamilyProperties2KHR, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t *pPropertyCount, VkSparseImageFormatProperties *pProperties) -{ - struct vkGetPhysicalDeviceSparseImageFormatProperties_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.format = format; - params.type = type; - params.samples = samples; - params.usage = usage; - params.tiling = tiling; - params.pPropertyCount = pPropertyCount; - params.pProperties = pProperties; - status = UNIX_CALL(vkGetPhysicalDeviceSparseImageFormatProperties, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo, uint32_t *pPropertyCount, VkSparseImageFormatProperties2 *pProperties) -{ - struct vkGetPhysicalDeviceSparseImageFormatProperties2_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pFormatInfo = pFormatInfo; - params.pPropertyCount = pPropertyCount; - params.pProperties = pProperties; - status = UNIX_CALL(vkGetPhysicalDeviceSparseImageFormatProperties2, ¶ms); - assert(!status); -} - -void WINAPI vkGetPhysicalDeviceSparseImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo, uint32_t *pPropertyCount, VkSparseImageFormatProperties2 *pProperties) -{ - struct vkGetPhysicalDeviceSparseImageFormatProperties2KHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pFormatInfo = pFormatInfo; - params.pPropertyCount = pPropertyCount; - params.pProperties = pProperties; - status = UNIX_CALL(vkGetPhysicalDeviceSparseImageFormatProperties2KHR, ¶ms); - assert(!status); -} - -VkResult WINAPI vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV(VkPhysicalDevice physicalDevice, uint32_t *pCombinationCount, VkFramebufferMixedSamplesCombinationNV *pCombinations) -{ - struct vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pCombinationCount = pCombinationCount; - params.pCombinations = pCombinations; - status = UNIX_CALL(vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, VkSurfaceCapabilities2KHR *pSurfaceCapabilities) -{ - struct vkGetPhysicalDeviceSurfaceCapabilities2KHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pSurfaceInfo = pSurfaceInfo; - params.pSurfaceCapabilities = pSurfaceCapabilities; - status = UNIX_CALL(vkGetPhysicalDeviceSurfaceCapabilities2KHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) -{ - struct vkGetPhysicalDeviceSurfaceCapabilitiesKHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.surface = surface; - params.pSurfaceCapabilities = pSurfaceCapabilities; - status = UNIX_CALL(vkGetPhysicalDeviceSurfaceCapabilitiesKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, uint32_t *pSurfaceFormatCount, VkSurfaceFormat2KHR *pSurfaceFormats) -{ - struct vkGetPhysicalDeviceSurfaceFormats2KHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pSurfaceInfo = pSurfaceInfo; - params.pSurfaceFormatCount = pSurfaceFormatCount; - params.pSurfaceFormats = pSurfaceFormats; - status = UNIX_CALL(vkGetPhysicalDeviceSurfaceFormats2KHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pSurfaceFormatCount, VkSurfaceFormatKHR *pSurfaceFormats) -{ - struct vkGetPhysicalDeviceSurfaceFormatsKHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.surface = surface; - params.pSurfaceFormatCount = pSurfaceFormatCount; - params.pSurfaceFormats = pSurfaceFormats; - status = UNIX_CALL(vkGetPhysicalDeviceSurfaceFormatsKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes) -{ - struct vkGetPhysicalDeviceSurfacePresentModesKHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.surface = surface; - params.pPresentModeCount = pPresentModeCount; - params.pPresentModes = pPresentModes; - status = UNIX_CALL(vkGetPhysicalDeviceSurfacePresentModesKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32 *pSupported) -{ - struct vkGetPhysicalDeviceSurfaceSupportKHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.queueFamilyIndex = queueFamilyIndex; - params.surface = surface; - params.pSupported = pSupported; - status = UNIX_CALL(vkGetPhysicalDeviceSurfaceSupportKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPhysicalDeviceToolProperties(VkPhysicalDevice physicalDevice, uint32_t *pToolCount, VkPhysicalDeviceToolProperties *pToolProperties) -{ - struct vkGetPhysicalDeviceToolProperties_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pToolCount = pToolCount; - params.pToolProperties = pToolProperties; - status = UNIX_CALL(vkGetPhysicalDeviceToolProperties, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPhysicalDeviceToolPropertiesEXT(VkPhysicalDevice physicalDevice, uint32_t *pToolCount, VkPhysicalDeviceToolProperties *pToolProperties) -{ - struct vkGetPhysicalDeviceToolPropertiesEXT_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.pToolCount = pToolCount; - params.pToolProperties = pToolProperties; - status = UNIX_CALL(vkGetPhysicalDeviceToolPropertiesEXT, ¶ms); - assert(!status); - return params.result; -} - -VkBool32 WINAPI vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex) -{ - struct vkGetPhysicalDeviceWin32PresentationSupportKHR_params params; - NTSTATUS status; - params.physicalDevice = physicalDevice; - params.queueFamilyIndex = queueFamilyIndex; - status = UNIX_CALL(vkGetPhysicalDeviceWin32PresentationSupportKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize, void *pData) -{ - struct vkGetPipelineCacheData_params params; - NTSTATUS status; - params.device = device; - params.pipelineCache = pipelineCache; - params.pDataSize = pDataSize; - params.pData = pData; - status = UNIX_CALL(vkGetPipelineCacheData, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPipelineExecutableInternalRepresentationsKHR(VkDevice device, const VkPipelineExecutableInfoKHR *pExecutableInfo, uint32_t *pInternalRepresentationCount, VkPipelineExecutableInternalRepresentationKHR *pInternalRepresentations) -{ - struct vkGetPipelineExecutableInternalRepresentationsKHR_params params; - NTSTATUS status; - params.device = device; - params.pExecutableInfo = pExecutableInfo; - params.pInternalRepresentationCount = pInternalRepresentationCount; - params.pInternalRepresentations = pInternalRepresentations; - status = UNIX_CALL(vkGetPipelineExecutableInternalRepresentationsKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPipelineExecutablePropertiesKHR(VkDevice device, const VkPipelineInfoKHR *pPipelineInfo, uint32_t *pExecutableCount, VkPipelineExecutablePropertiesKHR *pProperties) -{ - struct vkGetPipelineExecutablePropertiesKHR_params params; - NTSTATUS status; - params.device = device; - params.pPipelineInfo = pPipelineInfo; - params.pExecutableCount = pExecutableCount; - params.pProperties = pProperties; - status = UNIX_CALL(vkGetPipelineExecutablePropertiesKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPipelineExecutableStatisticsKHR(VkDevice device, const VkPipelineExecutableInfoKHR *pExecutableInfo, uint32_t *pStatisticCount, VkPipelineExecutableStatisticKHR *pStatistics) -{ - struct vkGetPipelineExecutableStatisticsKHR_params params; - NTSTATUS status; - params.device = device; - params.pExecutableInfo = pExecutableInfo; - params.pStatisticCount = pStatisticCount; - params.pStatistics = pStatistics; - status = UNIX_CALL(vkGetPipelineExecutableStatisticsKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetPipelinePropertiesEXT(VkDevice device, const VkPipelineInfoEXT *pPipelineInfo, VkBaseOutStructure *pPipelineProperties) -{ - struct vkGetPipelinePropertiesEXT_params params; - NTSTATUS status; - params.device = device; - params.pPipelineInfo = pPipelineInfo; - params.pPipelineProperties = pPipelineProperties; - status = UNIX_CALL(vkGetPipelinePropertiesEXT, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkGetPrivateData(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t *pData) -{ - struct vkGetPrivateData_params params; - NTSTATUS status; - params.device = device; - params.objectType = objectType; - params.objectHandle = objectHandle; - params.privateDataSlot = privateDataSlot; - params.pData = pData; - status = UNIX_CALL(vkGetPrivateData, ¶ms); - assert(!status); -} - -void WINAPI vkGetPrivateDataEXT(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t *pData) -{ - struct vkGetPrivateDataEXT_params params; - NTSTATUS status; - params.device = device; - params.objectType = objectType; - params.objectHandle = objectHandle; - params.privateDataSlot = privateDataSlot; - params.pData = pData; - status = UNIX_CALL(vkGetPrivateDataEXT, ¶ms); - assert(!status); -} - -VkResult WINAPI vkGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void *pData, VkDeviceSize stride, VkQueryResultFlags flags) -{ - struct vkGetQueryPoolResults_params params; - NTSTATUS status; - params.device = device; - params.queryPool = queryPool; - params.firstQuery = firstQuery; - params.queryCount = queryCount; - params.dataSize = dataSize; - params.pData = pData; - params.stride = stride; - params.flags = flags; - status = UNIX_CALL(vkGetQueryPoolResults, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkGetQueueCheckpointData2NV(VkQueue queue, uint32_t *pCheckpointDataCount, VkCheckpointData2NV *pCheckpointData) -{ - struct vkGetQueueCheckpointData2NV_params params; - NTSTATUS status; - params.queue = queue; - params.pCheckpointDataCount = pCheckpointDataCount; - params.pCheckpointData = pCheckpointData; - status = UNIX_CALL(vkGetQueueCheckpointData2NV, ¶ms); - assert(!status); -} - -void WINAPI vkGetQueueCheckpointDataNV(VkQueue queue, uint32_t *pCheckpointDataCount, VkCheckpointDataNV *pCheckpointData) -{ - struct vkGetQueueCheckpointDataNV_params params; - NTSTATUS status; - params.queue = queue; - params.pCheckpointDataCount = pCheckpointDataCount; - params.pCheckpointData = pCheckpointData; - status = UNIX_CALL(vkGetQueueCheckpointDataNV, ¶ms); - assert(!status); -} - -VkResult WINAPI vkGetRayTracingCaptureReplayShaderGroupHandlesKHR(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void *pData) -{ - struct vkGetRayTracingCaptureReplayShaderGroupHandlesKHR_params params; - NTSTATUS status; - params.device = device; - params.pipeline = pipeline; - params.firstGroup = firstGroup; - params.groupCount = groupCount; - params.dataSize = dataSize; - params.pData = pData; - status = UNIX_CALL(vkGetRayTracingCaptureReplayShaderGroupHandlesKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetRayTracingShaderGroupHandlesKHR(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void *pData) -{ - struct vkGetRayTracingShaderGroupHandlesKHR_params params; - NTSTATUS status; - params.device = device; - params.pipeline = pipeline; - params.firstGroup = firstGroup; - params.groupCount = groupCount; - params.dataSize = dataSize; - params.pData = pData; - status = UNIX_CALL(vkGetRayTracingShaderGroupHandlesKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetRayTracingShaderGroupHandlesNV(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void *pData) -{ - struct vkGetRayTracingShaderGroupHandlesNV_params params; - NTSTATUS status; - params.device = device; - params.pipeline = pipeline; - params.firstGroup = firstGroup; - params.groupCount = groupCount; - params.dataSize = dataSize; - params.pData = pData; - status = UNIX_CALL(vkGetRayTracingShaderGroupHandlesNV, ¶ms); - assert(!status); - return params.result; -} - -VkDeviceSize WINAPI vkGetRayTracingShaderGroupStackSizeKHR(VkDevice device, VkPipeline pipeline, uint32_t group, VkShaderGroupShaderKHR groupShader) -{ - struct vkGetRayTracingShaderGroupStackSizeKHR_params params; - NTSTATUS status; - params.device = device; - params.pipeline = pipeline; - params.group = group; - params.groupShader = groupShader; - status = UNIX_CALL(vkGetRayTracingShaderGroupStackSizeKHR, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkGetRenderAreaGranularity(VkDevice device, VkRenderPass renderPass, VkExtent2D *pGranularity) -{ - struct vkGetRenderAreaGranularity_params params; - NTSTATUS status; - params.device = device; - params.renderPass = renderPass; - params.pGranularity = pGranularity; - status = UNIX_CALL(vkGetRenderAreaGranularity, ¶ms); - assert(!status); -} - -VkResult WINAPI vkGetSamplerOpaqueCaptureDescriptorDataEXT(VkDevice device, const VkSamplerCaptureDescriptorDataInfoEXT *pInfo, void *pData) -{ - struct vkGetSamplerOpaqueCaptureDescriptorDataEXT_params params; - NTSTATUS status; - params.device = device; - params.pInfo = pInfo; - params.pData = pData; - status = UNIX_CALL(vkGetSamplerOpaqueCaptureDescriptorDataEXT, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t *pValue) -{ - struct vkGetSemaphoreCounterValue_params params; - NTSTATUS status; - params.device = device; - params.semaphore = semaphore; - params.pValue = pValue; - status = UNIX_CALL(vkGetSemaphoreCounterValue, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetSemaphoreCounterValueKHR(VkDevice device, VkSemaphore semaphore, uint64_t *pValue) -{ - struct vkGetSemaphoreCounterValueKHR_params params; - NTSTATUS status; - params.device = device; - params.semaphore = semaphore; - params.pValue = pValue; - status = UNIX_CALL(vkGetSemaphoreCounterValueKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetShaderInfoAMD(VkDevice device, VkPipeline pipeline, VkShaderStageFlagBits shaderStage, VkShaderInfoTypeAMD infoType, size_t *pInfoSize, void *pInfo) -{ - struct vkGetShaderInfoAMD_params params; - NTSTATUS status; - params.device = device; - params.pipeline = pipeline; - params.shaderStage = shaderStage; - params.infoType = infoType; - params.pInfoSize = pInfoSize; - params.pInfo = pInfo; - status = UNIX_CALL(vkGetShaderInfoAMD, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkGetShaderModuleCreateInfoIdentifierEXT(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo, VkShaderModuleIdentifierEXT *pIdentifier) -{ - struct vkGetShaderModuleCreateInfoIdentifierEXT_params params; - NTSTATUS status; - params.device = device; - params.pCreateInfo = pCreateInfo; - params.pIdentifier = pIdentifier; - status = UNIX_CALL(vkGetShaderModuleCreateInfoIdentifierEXT, ¶ms); - assert(!status); -} - -void WINAPI vkGetShaderModuleIdentifierEXT(VkDevice device, VkShaderModule shaderModule, VkShaderModuleIdentifierEXT *pIdentifier) -{ - struct vkGetShaderModuleIdentifierEXT_params params; - NTSTATUS status; - params.device = device; - params.shaderModule = shaderModule; - params.pIdentifier = pIdentifier; - status = UNIX_CALL(vkGetShaderModuleIdentifierEXT, ¶ms); - assert(!status); -} - -VkResult WINAPI vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) -{ - struct vkGetSwapchainImagesKHR_params params; - NTSTATUS status; - params.device = device; - params.swapchain = swapchain; - params.pSwapchainImageCount = pSwapchainImageCount; - params.pSwapchainImages = pSwapchainImages; - status = UNIX_CALL(vkGetSwapchainImagesKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkGetValidationCacheDataEXT(VkDevice device, VkValidationCacheEXT validationCache, size_t *pDataSize, void *pData) -{ - struct vkGetValidationCacheDataEXT_params params; - NTSTATUS status; - params.device = device; - params.validationCache = validationCache; - params.pDataSize = pDataSize; - params.pData = pData; - status = UNIX_CALL(vkGetValidationCacheDataEXT, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkInitializePerformanceApiINTEL(VkDevice device, const VkInitializePerformanceApiInfoINTEL *pInitializeInfo) -{ - struct vkInitializePerformanceApiINTEL_params params; - NTSTATUS status; - params.device = device; - params.pInitializeInfo = pInitializeInfo; - status = UNIX_CALL(vkInitializePerformanceApiINTEL, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkInvalidateMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange *pMemoryRanges) -{ - struct vkInvalidateMappedMemoryRanges_params params; - NTSTATUS status; - params.device = device; - params.memoryRangeCount = memoryRangeCount; - params.pMemoryRanges = pMemoryRanges; - status = UNIX_CALL(vkInvalidateMappedMemoryRanges, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkMapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void **ppData) -{ - struct vkMapMemory_params params; - NTSTATUS status; - params.device = device; - params.memory = memory; - params.offset = offset; - params.size = size; - params.flags = flags; - params.ppData = ppData; - status = UNIX_CALL(vkMapMemory, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkMergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache *pSrcCaches) -{ - struct vkMergePipelineCaches_params params; - NTSTATUS status; - params.device = device; - params.dstCache = dstCache; - params.srcCacheCount = srcCacheCount; - params.pSrcCaches = pSrcCaches; - status = UNIX_CALL(vkMergePipelineCaches, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkMergeValidationCachesEXT(VkDevice device, VkValidationCacheEXT dstCache, uint32_t srcCacheCount, const VkValidationCacheEXT *pSrcCaches) -{ - struct vkMergeValidationCachesEXT_params params; - NTSTATUS status; - params.device = device; - params.dstCache = dstCache; - params.srcCacheCount = srcCacheCount; - params.pSrcCaches = pSrcCaches; - status = UNIX_CALL(vkMergeValidationCachesEXT, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkQueueBeginDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo) -{ - struct vkQueueBeginDebugUtilsLabelEXT_params params; - NTSTATUS status; - params.queue = queue; - params.pLabelInfo = pLabelInfo; - status = UNIX_CALL(vkQueueBeginDebugUtilsLabelEXT, ¶ms); - assert(!status); -} - -VkResult WINAPI vkQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo, VkFence fence) -{ - struct vkQueueBindSparse_params params; - NTSTATUS status; - params.queue = queue; - params.bindInfoCount = bindInfoCount; - params.pBindInfo = pBindInfo; - params.fence = fence; - status = UNIX_CALL(vkQueueBindSparse, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkQueueEndDebugUtilsLabelEXT(VkQueue queue) -{ - struct vkQueueEndDebugUtilsLabelEXT_params params; - NTSTATUS status; - params.queue = queue; - status = UNIX_CALL(vkQueueEndDebugUtilsLabelEXT, ¶ms); - assert(!status); -} - -void WINAPI vkQueueInsertDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo) -{ - struct vkQueueInsertDebugUtilsLabelEXT_params params; - NTSTATUS status; - params.queue = queue; - params.pLabelInfo = pLabelInfo; - status = UNIX_CALL(vkQueueInsertDebugUtilsLabelEXT, ¶ms); - assert(!status); -} - -VkResult WINAPI vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) -{ - struct vkQueuePresentKHR_params params; - NTSTATUS status; - params.queue = queue; - params.pPresentInfo = pPresentInfo; - status = UNIX_CALL(vkQueuePresentKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkQueueSetPerformanceConfigurationINTEL(VkQueue queue, VkPerformanceConfigurationINTEL configuration) -{ - struct vkQueueSetPerformanceConfigurationINTEL_params params; - NTSTATUS status; - params.queue = queue; - params.configuration = configuration; - status = UNIX_CALL(vkQueueSetPerformanceConfigurationINTEL, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence) -{ - struct vkQueueSubmit_params params; - NTSTATUS status; - params.queue = queue; - params.submitCount = submitCount; - params.pSubmits = pSubmits; - params.fence = fence; - status = UNIX_CALL(vkQueueSubmit, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkQueueSubmit2(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2 *pSubmits, VkFence fence) -{ - struct vkQueueSubmit2_params params; - NTSTATUS status; - params.queue = queue; - params.submitCount = submitCount; - params.pSubmits = pSubmits; - params.fence = fence; - status = UNIX_CALL(vkQueueSubmit2, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkQueueSubmit2KHR(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2 *pSubmits, VkFence fence) -{ - struct vkQueueSubmit2KHR_params params; - NTSTATUS status; - params.queue = queue; - params.submitCount = submitCount; - params.pSubmits = pSubmits; - params.fence = fence; - status = UNIX_CALL(vkQueueSubmit2KHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkQueueWaitIdle(VkQueue queue) -{ - struct vkQueueWaitIdle_params params; - NTSTATUS status; - params.queue = queue; - status = UNIX_CALL(vkQueueWaitIdle, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkReleasePerformanceConfigurationINTEL(VkDevice device, VkPerformanceConfigurationINTEL configuration) -{ - struct vkReleasePerformanceConfigurationINTEL_params params; - NTSTATUS status; - params.device = device; - params.configuration = configuration; - status = UNIX_CALL(vkReleasePerformanceConfigurationINTEL, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkReleaseProfilingLockKHR(VkDevice device) -{ - struct vkReleaseProfilingLockKHR_params params; - NTSTATUS status; - params.device = device; - status = UNIX_CALL(vkReleaseProfilingLockKHR, ¶ms); - assert(!status); -} - -VkResult WINAPI vkReleaseSwapchainImagesEXT(VkDevice device, const VkReleaseSwapchainImagesInfoEXT *pReleaseInfo) -{ - struct vkReleaseSwapchainImagesEXT_params params; - NTSTATUS status; - params.device = device; - params.pReleaseInfo = pReleaseInfo; - status = UNIX_CALL(vkReleaseSwapchainImagesEXT, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) -{ - struct vkResetCommandBuffer_params params; - NTSTATUS status; - params.commandBuffer = commandBuffer; - params.flags = flags; - status = UNIX_CALL(vkResetCommandBuffer, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) -{ - struct vkResetCommandPool_params params; - NTSTATUS status; - params.device = device; - params.commandPool = commandPool; - params.flags = flags; - status = UNIX_CALL(vkResetCommandPool, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags) -{ - struct vkResetDescriptorPool_params params; - NTSTATUS status; - params.device = device; - params.descriptorPool = descriptorPool; - params.flags = flags; - status = UNIX_CALL(vkResetDescriptorPool, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkResetEvent(VkDevice device, VkEvent event) -{ - struct vkResetEvent_params params; - NTSTATUS status; - params.device = device; - params.event = event; - status = UNIX_CALL(vkResetEvent, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences) -{ - struct vkResetFences_params params; - NTSTATUS status; - params.device = device; - params.fenceCount = fenceCount; - params.pFences = pFences; - status = UNIX_CALL(vkResetFences, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) -{ - struct vkResetQueryPool_params params; - NTSTATUS status; - params.device = device; - params.queryPool = queryPool; - params.firstQuery = firstQuery; - params.queryCount = queryCount; - status = UNIX_CALL(vkResetQueryPool, ¶ms); - assert(!status); -} - -void WINAPI vkResetQueryPoolEXT(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) -{ - struct vkResetQueryPoolEXT_params params; - NTSTATUS status; - params.device = device; - params.queryPool = queryPool; - params.firstQuery = firstQuery; - params.queryCount = queryCount; - status = UNIX_CALL(vkResetQueryPoolEXT, ¶ms); - assert(!status); -} - -VkResult WINAPI vkSetDebugUtilsObjectNameEXT(VkDevice device, const VkDebugUtilsObjectNameInfoEXT *pNameInfo) -{ - struct vkSetDebugUtilsObjectNameEXT_params params; - NTSTATUS status; - params.device = device; - params.pNameInfo = pNameInfo; - status = UNIX_CALL(vkSetDebugUtilsObjectNameEXT, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkSetDebugUtilsObjectTagEXT(VkDevice device, const VkDebugUtilsObjectTagInfoEXT *pTagInfo) -{ - struct vkSetDebugUtilsObjectTagEXT_params params; - NTSTATUS status; - params.device = device; - params.pTagInfo = pTagInfo; - status = UNIX_CALL(vkSetDebugUtilsObjectTagEXT, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkSetDeviceMemoryPriorityEXT(VkDevice device, VkDeviceMemory memory, float priority) -{ - struct vkSetDeviceMemoryPriorityEXT_params params; - NTSTATUS status; - params.device = device; - params.memory = memory; - params.priority = priority; - status = UNIX_CALL(vkSetDeviceMemoryPriorityEXT, ¶ms); - assert(!status); -} - -VkResult WINAPI vkSetEvent(VkDevice device, VkEvent event) -{ - struct vkSetEvent_params params; - NTSTATUS status; - params.device = device; - params.event = event; - status = UNIX_CALL(vkSetEvent, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkSetPrivateData(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data) -{ - struct vkSetPrivateData_params params; - NTSTATUS status; - params.device = device; - params.objectType = objectType; - params.objectHandle = objectHandle; - params.privateDataSlot = privateDataSlot; - params.data = data; - status = UNIX_CALL(vkSetPrivateData, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkSetPrivateDataEXT(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data) -{ - struct vkSetPrivateDataEXT_params params; - NTSTATUS status; - params.device = device; - params.objectType = objectType; - params.objectHandle = objectHandle; - params.privateDataSlot = privateDataSlot; - params.data = data; - status = UNIX_CALL(vkSetPrivateDataEXT, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkSignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo *pSignalInfo) -{ - struct vkSignalSemaphore_params params; - NTSTATUS status; - params.device = device; - params.pSignalInfo = pSignalInfo; - status = UNIX_CALL(vkSignalSemaphore, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkSignalSemaphoreKHR(VkDevice device, const VkSemaphoreSignalInfo *pSignalInfo) -{ - struct vkSignalSemaphoreKHR_params params; - NTSTATUS status; - params.device = device; - params.pSignalInfo = pSignalInfo; - status = UNIX_CALL(vkSignalSemaphoreKHR, ¶ms); - assert(!status); - return params.result; -} - -void WINAPI vkSubmitDebugUtilsMessageEXT(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData) -{ - struct vkSubmitDebugUtilsMessageEXT_params params; - NTSTATUS status; - params.instance = instance; - params.messageSeverity = messageSeverity; - params.messageTypes = messageTypes; - params.pCallbackData = pCallbackData; - status = UNIX_CALL(vkSubmitDebugUtilsMessageEXT, ¶ms); - assert(!status); -} - -void WINAPI vkTrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags) -{ - struct vkTrimCommandPool_params params; - NTSTATUS status; - params.device = device; - params.commandPool = commandPool; - params.flags = flags; - status = UNIX_CALL(vkTrimCommandPool, ¶ms); - assert(!status); -} - -void WINAPI vkTrimCommandPoolKHR(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags) -{ - struct vkTrimCommandPoolKHR_params params; - NTSTATUS status; - params.device = device; - params.commandPool = commandPool; - params.flags = flags; - status = UNIX_CALL(vkTrimCommandPoolKHR, ¶ms); - assert(!status); -} - -void WINAPI vkUninitializePerformanceApiINTEL(VkDevice device) -{ - struct vkUninitializePerformanceApiINTEL_params params; - NTSTATUS status; - params.device = device; - status = UNIX_CALL(vkUninitializePerformanceApiINTEL, ¶ms); - assert(!status); -} - -void WINAPI vkUnmapMemory(VkDevice device, VkDeviceMemory memory) -{ - struct vkUnmapMemory_params params; - NTSTATUS status; - params.device = device; - params.memory = memory; - status = UNIX_CALL(vkUnmapMemory, ¶ms); - assert(!status); -} - -void WINAPI vkUpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void *pData) -{ - struct vkUpdateDescriptorSetWithTemplate_params params; - params.device = device; - params.descriptorSet = descriptorSet; - params.descriptorUpdateTemplate = descriptorUpdateTemplate; - params.pData = pData; - UNIX_CALL(vkUpdateDescriptorSetWithTemplate, ¶ms); -} - -void WINAPI vkUpdateDescriptorSetWithTemplateKHR(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void *pData) -{ - struct vkUpdateDescriptorSetWithTemplateKHR_params params; - NTSTATUS status; - params.device = device; - params.descriptorSet = descriptorSet; - params.descriptorUpdateTemplate = descriptorUpdateTemplate; - params.pData = pData; - status = UNIX_CALL(vkUpdateDescriptorSetWithTemplateKHR, ¶ms); - assert(!status); -} - -void WINAPI vkUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies) -{ - struct vkUpdateDescriptorSets_params params; - params.device = device; - params.descriptorWriteCount = descriptorWriteCount; - params.pDescriptorWrites = pDescriptorWrites; - params.descriptorCopyCount = descriptorCopyCount; - params.pDescriptorCopies = pDescriptorCopies; - UNIX_CALL(vkUpdateDescriptorSets, ¶ms); -} - -VkResult WINAPI vkWaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout) -{ - struct vkWaitForFences_params params; - NTSTATUS status; - params.device = device; - params.fenceCount = fenceCount; - params.pFences = pFences; - params.waitAll = waitAll; - params.timeout = timeout; - status = UNIX_CALL(vkWaitForFences, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkWaitForPresentKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t presentId, uint64_t timeout) -{ - struct vkWaitForPresentKHR_params params; - NTSTATUS status; - params.device = device; - params.swapchain = swapchain; - params.presentId = presentId; - params.timeout = timeout; - status = UNIX_CALL(vkWaitForPresentKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkWaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo *pWaitInfo, uint64_t timeout) -{ - struct vkWaitSemaphores_params params; - NTSTATUS status; - params.device = device; - params.pWaitInfo = pWaitInfo; - params.timeout = timeout; - status = UNIX_CALL(vkWaitSemaphores, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkWaitSemaphoresKHR(VkDevice device, const VkSemaphoreWaitInfo *pWaitInfo, uint64_t timeout) -{ - struct vkWaitSemaphoresKHR_params params; - NTSTATUS status; - params.device = device; - params.pWaitInfo = pWaitInfo; - params.timeout = timeout; - status = UNIX_CALL(vkWaitSemaphoresKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkWriteAccelerationStructuresPropertiesKHR(VkDevice device, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR *pAccelerationStructures, VkQueryType queryType, size_t dataSize, void *pData, size_t stride) -{ - struct vkWriteAccelerationStructuresPropertiesKHR_params params; - NTSTATUS status; - params.device = device; - params.accelerationStructureCount = accelerationStructureCount; - params.pAccelerationStructures = pAccelerationStructures; - params.queryType = queryType; - params.dataSize = dataSize; - params.pData = pData; - params.stride = stride; - status = UNIX_CALL(vkWriteAccelerationStructuresPropertiesKHR, ¶ms); - assert(!status); - return params.result; -} - -VkResult WINAPI vkWriteMicromapsPropertiesEXT(VkDevice device, uint32_t micromapCount, const VkMicromapEXT *pMicromaps, VkQueryType queryType, size_t dataSize, void *pData, size_t stride) -{ - struct vkWriteMicromapsPropertiesEXT_params params; - NTSTATUS status; - params.device = device; - params.micromapCount = micromapCount; - params.pMicromaps = pMicromaps; - params.queryType = queryType; - params.dataSize = dataSize; - params.pData = pData; - params.stride = stride; - status = UNIX_CALL(vkWriteMicromapsPropertiesEXT, ¶ms); - assert(!status); - return params.result; -} - -static const struct vulkan_func vk_device_dispatch_table[] = -{ - {"vkAcquireNextImage2KHR", vkAcquireNextImage2KHR}, - {"vkAcquireNextImageKHR", vkAcquireNextImageKHR}, - {"vkAcquirePerformanceConfigurationINTEL", vkAcquirePerformanceConfigurationINTEL}, - {"vkAcquireProfilingLockKHR", vkAcquireProfilingLockKHR}, - {"vkAllocateCommandBuffers", vkAllocateCommandBuffers}, - {"vkAllocateDescriptorSets", vkAllocateDescriptorSets}, - {"vkAllocateMemory", vkAllocateMemory}, - {"vkBeginCommandBuffer", vkBeginCommandBuffer}, - {"vkBindAccelerationStructureMemoryNV", vkBindAccelerationStructureMemoryNV}, - {"vkBindBufferMemory", vkBindBufferMemory}, - {"vkBindBufferMemory2", vkBindBufferMemory2}, - {"vkBindBufferMemory2KHR", vkBindBufferMemory2KHR}, - {"vkBindImageMemory", vkBindImageMemory}, - {"vkBindImageMemory2", vkBindImageMemory2}, - {"vkBindImageMemory2KHR", vkBindImageMemory2KHR}, - {"vkBindOpticalFlowSessionImageNV", vkBindOpticalFlowSessionImageNV}, - {"vkBuildAccelerationStructuresKHR", vkBuildAccelerationStructuresKHR}, - {"vkBuildMicromapsEXT", vkBuildMicromapsEXT}, - {"vkCmdBeginConditionalRenderingEXT", vkCmdBeginConditionalRenderingEXT}, - {"vkCmdBeginDebugUtilsLabelEXT", vkCmdBeginDebugUtilsLabelEXT}, - {"vkCmdBeginQuery", vkCmdBeginQuery}, - {"vkCmdBeginQueryIndexedEXT", vkCmdBeginQueryIndexedEXT}, - {"vkCmdBeginRenderPass", vkCmdBeginRenderPass}, - {"vkCmdBeginRenderPass2", vkCmdBeginRenderPass2}, - {"vkCmdBeginRenderPass2KHR", vkCmdBeginRenderPass2KHR}, - {"vkCmdBeginRendering", vkCmdBeginRendering}, - {"vkCmdBeginRenderingKHR", vkCmdBeginRenderingKHR}, - {"vkCmdBeginTransformFeedbackEXT", vkCmdBeginTransformFeedbackEXT}, - {"vkCmdBindDescriptorBufferEmbeddedSamplersEXT", vkCmdBindDescriptorBufferEmbeddedSamplersEXT}, - {"vkCmdBindDescriptorBuffersEXT", vkCmdBindDescriptorBuffersEXT}, - {"vkCmdBindDescriptorSets", vkCmdBindDescriptorSets}, - {"vkCmdBindIndexBuffer", vkCmdBindIndexBuffer}, - {"vkCmdBindInvocationMaskHUAWEI", vkCmdBindInvocationMaskHUAWEI}, - {"vkCmdBindPipeline", vkCmdBindPipeline}, - {"vkCmdBindPipelineShaderGroupNV", vkCmdBindPipelineShaderGroupNV}, - {"vkCmdBindShadingRateImageNV", vkCmdBindShadingRateImageNV}, - {"vkCmdBindTransformFeedbackBuffersEXT", vkCmdBindTransformFeedbackBuffersEXT}, - {"vkCmdBindVertexBuffers", vkCmdBindVertexBuffers}, - {"vkCmdBindVertexBuffers2", vkCmdBindVertexBuffers2}, - {"vkCmdBindVertexBuffers2EXT", vkCmdBindVertexBuffers2EXT}, - {"vkCmdBlitImage", vkCmdBlitImage}, - {"vkCmdBlitImage2", vkCmdBlitImage2}, - {"vkCmdBlitImage2KHR", vkCmdBlitImage2KHR}, - {"vkCmdBuildAccelerationStructureNV", vkCmdBuildAccelerationStructureNV}, - {"vkCmdBuildAccelerationStructuresIndirectKHR", vkCmdBuildAccelerationStructuresIndirectKHR}, - {"vkCmdBuildAccelerationStructuresKHR", vkCmdBuildAccelerationStructuresKHR}, - {"vkCmdBuildMicromapsEXT", vkCmdBuildMicromapsEXT}, - {"vkCmdClearAttachments", vkCmdClearAttachments}, - {"vkCmdClearColorImage", vkCmdClearColorImage}, - {"vkCmdClearDepthStencilImage", vkCmdClearDepthStencilImage}, - {"vkCmdCopyAccelerationStructureKHR", vkCmdCopyAccelerationStructureKHR}, - {"vkCmdCopyAccelerationStructureNV", vkCmdCopyAccelerationStructureNV}, - {"vkCmdCopyAccelerationStructureToMemoryKHR", vkCmdCopyAccelerationStructureToMemoryKHR}, - {"vkCmdCopyBuffer", vkCmdCopyBuffer}, - {"vkCmdCopyBuffer2", vkCmdCopyBuffer2}, - {"vkCmdCopyBuffer2KHR", vkCmdCopyBuffer2KHR}, - {"vkCmdCopyBufferToImage", vkCmdCopyBufferToImage}, - {"vkCmdCopyBufferToImage2", vkCmdCopyBufferToImage2}, - {"vkCmdCopyBufferToImage2KHR", vkCmdCopyBufferToImage2KHR}, - {"vkCmdCopyImage", vkCmdCopyImage}, - {"vkCmdCopyImage2", vkCmdCopyImage2}, - {"vkCmdCopyImage2KHR", vkCmdCopyImage2KHR}, - {"vkCmdCopyImageToBuffer", vkCmdCopyImageToBuffer}, - {"vkCmdCopyImageToBuffer2", vkCmdCopyImageToBuffer2}, - {"vkCmdCopyImageToBuffer2KHR", vkCmdCopyImageToBuffer2KHR}, - {"vkCmdCopyMemoryIndirectNV", vkCmdCopyMemoryIndirectNV}, - {"vkCmdCopyMemoryToAccelerationStructureKHR", vkCmdCopyMemoryToAccelerationStructureKHR}, - {"vkCmdCopyMemoryToImageIndirectNV", vkCmdCopyMemoryToImageIndirectNV}, - {"vkCmdCopyMemoryToMicromapEXT", vkCmdCopyMemoryToMicromapEXT}, - {"vkCmdCopyMicromapEXT", vkCmdCopyMicromapEXT}, - {"vkCmdCopyMicromapToMemoryEXT", vkCmdCopyMicromapToMemoryEXT}, - {"vkCmdCopyQueryPoolResults", vkCmdCopyQueryPoolResults}, - {"vkCmdCuLaunchKernelNVX", vkCmdCuLaunchKernelNVX}, - {"vkCmdDebugMarkerBeginEXT", vkCmdDebugMarkerBeginEXT}, - {"vkCmdDebugMarkerEndEXT", vkCmdDebugMarkerEndEXT}, - {"vkCmdDebugMarkerInsertEXT", vkCmdDebugMarkerInsertEXT}, - {"vkCmdDecompressMemoryIndirectCountNV", vkCmdDecompressMemoryIndirectCountNV}, - {"vkCmdDecompressMemoryNV", vkCmdDecompressMemoryNV}, - {"vkCmdDispatch", vkCmdDispatch}, - {"vkCmdDispatchBase", vkCmdDispatchBase}, - {"vkCmdDispatchBaseKHR", vkCmdDispatchBaseKHR}, - {"vkCmdDispatchIndirect", vkCmdDispatchIndirect}, - {"vkCmdDraw", vkCmdDraw}, - {"vkCmdDrawIndexed", vkCmdDrawIndexed}, - {"vkCmdDrawIndexedIndirect", vkCmdDrawIndexedIndirect}, - {"vkCmdDrawIndexedIndirectCount", vkCmdDrawIndexedIndirectCount}, - {"vkCmdDrawIndexedIndirectCountAMD", vkCmdDrawIndexedIndirectCountAMD}, - {"vkCmdDrawIndexedIndirectCountKHR", vkCmdDrawIndexedIndirectCountKHR}, - {"vkCmdDrawIndirect", vkCmdDrawIndirect}, - {"vkCmdDrawIndirectByteCountEXT", vkCmdDrawIndirectByteCountEXT}, - {"vkCmdDrawIndirectCount", vkCmdDrawIndirectCount}, - {"vkCmdDrawIndirectCountAMD", vkCmdDrawIndirectCountAMD}, - {"vkCmdDrawIndirectCountKHR", vkCmdDrawIndirectCountKHR}, - {"vkCmdDrawMeshTasksEXT", vkCmdDrawMeshTasksEXT}, - {"vkCmdDrawMeshTasksIndirectCountEXT", vkCmdDrawMeshTasksIndirectCountEXT}, - {"vkCmdDrawMeshTasksIndirectCountNV", vkCmdDrawMeshTasksIndirectCountNV}, - {"vkCmdDrawMeshTasksIndirectEXT", vkCmdDrawMeshTasksIndirectEXT}, - {"vkCmdDrawMeshTasksIndirectNV", vkCmdDrawMeshTasksIndirectNV}, - {"vkCmdDrawMeshTasksNV", vkCmdDrawMeshTasksNV}, - {"vkCmdDrawMultiEXT", vkCmdDrawMultiEXT}, - {"vkCmdDrawMultiIndexedEXT", vkCmdDrawMultiIndexedEXT}, - {"vkCmdEndConditionalRenderingEXT", vkCmdEndConditionalRenderingEXT}, - {"vkCmdEndDebugUtilsLabelEXT", vkCmdEndDebugUtilsLabelEXT}, - {"vkCmdEndQuery", vkCmdEndQuery}, - {"vkCmdEndQueryIndexedEXT", vkCmdEndQueryIndexedEXT}, - {"vkCmdEndRenderPass", vkCmdEndRenderPass}, - {"vkCmdEndRenderPass2", vkCmdEndRenderPass2}, - {"vkCmdEndRenderPass2KHR", vkCmdEndRenderPass2KHR}, - {"vkCmdEndRendering", vkCmdEndRendering}, - {"vkCmdEndRenderingKHR", vkCmdEndRenderingKHR}, - {"vkCmdEndTransformFeedbackEXT", vkCmdEndTransformFeedbackEXT}, - {"vkCmdExecuteCommands", vkCmdExecuteCommands}, - {"vkCmdExecuteGeneratedCommandsNV", vkCmdExecuteGeneratedCommandsNV}, - {"vkCmdFillBuffer", vkCmdFillBuffer}, - {"vkCmdInsertDebugUtilsLabelEXT", vkCmdInsertDebugUtilsLabelEXT}, - {"vkCmdNextSubpass", vkCmdNextSubpass}, - {"vkCmdNextSubpass2", vkCmdNextSubpass2}, - {"vkCmdNextSubpass2KHR", vkCmdNextSubpass2KHR}, - {"vkCmdOpticalFlowExecuteNV", vkCmdOpticalFlowExecuteNV}, - {"vkCmdPipelineBarrier", vkCmdPipelineBarrier}, - {"vkCmdPipelineBarrier2", vkCmdPipelineBarrier2}, - {"vkCmdPipelineBarrier2KHR", vkCmdPipelineBarrier2KHR}, - {"vkCmdPreprocessGeneratedCommandsNV", vkCmdPreprocessGeneratedCommandsNV}, - {"vkCmdPushConstants", vkCmdPushConstants}, - {"vkCmdPushDescriptorSetKHR", vkCmdPushDescriptorSetKHR}, - {"vkCmdPushDescriptorSetWithTemplateKHR", vkCmdPushDescriptorSetWithTemplateKHR}, - {"vkCmdResetEvent", vkCmdResetEvent}, - {"vkCmdResetEvent2", vkCmdResetEvent2}, - {"vkCmdResetEvent2KHR", vkCmdResetEvent2KHR}, - {"vkCmdResetQueryPool", vkCmdResetQueryPool}, - {"vkCmdResolveImage", vkCmdResolveImage}, - {"vkCmdResolveImage2", vkCmdResolveImage2}, - {"vkCmdResolveImage2KHR", vkCmdResolveImage2KHR}, - {"vkCmdSetAlphaToCoverageEnableEXT", vkCmdSetAlphaToCoverageEnableEXT}, - {"vkCmdSetAlphaToOneEnableEXT", vkCmdSetAlphaToOneEnableEXT}, - {"vkCmdSetBlendConstants", vkCmdSetBlendConstants}, - {"vkCmdSetCheckpointNV", vkCmdSetCheckpointNV}, - {"vkCmdSetCoarseSampleOrderNV", vkCmdSetCoarseSampleOrderNV}, - {"vkCmdSetColorBlendAdvancedEXT", vkCmdSetColorBlendAdvancedEXT}, - {"vkCmdSetColorBlendEnableEXT", vkCmdSetColorBlendEnableEXT}, - {"vkCmdSetColorBlendEquationEXT", vkCmdSetColorBlendEquationEXT}, - {"vkCmdSetColorWriteEnableEXT", vkCmdSetColorWriteEnableEXT}, - {"vkCmdSetColorWriteMaskEXT", vkCmdSetColorWriteMaskEXT}, - {"vkCmdSetConservativeRasterizationModeEXT", vkCmdSetConservativeRasterizationModeEXT}, - {"vkCmdSetCoverageModulationModeNV", vkCmdSetCoverageModulationModeNV}, - {"vkCmdSetCoverageModulationTableEnableNV", vkCmdSetCoverageModulationTableEnableNV}, - {"vkCmdSetCoverageModulationTableNV", vkCmdSetCoverageModulationTableNV}, - {"vkCmdSetCoverageReductionModeNV", vkCmdSetCoverageReductionModeNV}, - {"vkCmdSetCoverageToColorEnableNV", vkCmdSetCoverageToColorEnableNV}, - {"vkCmdSetCoverageToColorLocationNV", vkCmdSetCoverageToColorLocationNV}, - {"vkCmdSetCullMode", vkCmdSetCullMode}, - {"vkCmdSetCullModeEXT", vkCmdSetCullModeEXT}, - {"vkCmdSetDepthBias", vkCmdSetDepthBias}, - {"vkCmdSetDepthBiasEnable", vkCmdSetDepthBiasEnable}, - {"vkCmdSetDepthBiasEnableEXT", vkCmdSetDepthBiasEnableEXT}, - {"vkCmdSetDepthBounds", vkCmdSetDepthBounds}, - {"vkCmdSetDepthBoundsTestEnable", vkCmdSetDepthBoundsTestEnable}, - {"vkCmdSetDepthBoundsTestEnableEXT", vkCmdSetDepthBoundsTestEnableEXT}, - {"vkCmdSetDepthClampEnableEXT", vkCmdSetDepthClampEnableEXT}, - {"vkCmdSetDepthClipEnableEXT", vkCmdSetDepthClipEnableEXT}, - {"vkCmdSetDepthClipNegativeOneToOneEXT", vkCmdSetDepthClipNegativeOneToOneEXT}, - {"vkCmdSetDepthCompareOp", vkCmdSetDepthCompareOp}, - {"vkCmdSetDepthCompareOpEXT", vkCmdSetDepthCompareOpEXT}, - {"vkCmdSetDepthTestEnable", vkCmdSetDepthTestEnable}, - {"vkCmdSetDepthTestEnableEXT", vkCmdSetDepthTestEnableEXT}, - {"vkCmdSetDepthWriteEnable", vkCmdSetDepthWriteEnable}, - {"vkCmdSetDepthWriteEnableEXT", vkCmdSetDepthWriteEnableEXT}, - {"vkCmdSetDescriptorBufferOffsetsEXT", vkCmdSetDescriptorBufferOffsetsEXT}, - {"vkCmdSetDeviceMask", vkCmdSetDeviceMask}, - {"vkCmdSetDeviceMaskKHR", vkCmdSetDeviceMaskKHR}, - {"vkCmdSetDiscardRectangleEXT", vkCmdSetDiscardRectangleEXT}, - {"vkCmdSetEvent", vkCmdSetEvent}, - {"vkCmdSetEvent2", vkCmdSetEvent2}, - {"vkCmdSetEvent2KHR", vkCmdSetEvent2KHR}, - {"vkCmdSetExclusiveScissorNV", vkCmdSetExclusiveScissorNV}, - {"vkCmdSetExtraPrimitiveOverestimationSizeEXT", vkCmdSetExtraPrimitiveOverestimationSizeEXT}, - {"vkCmdSetFragmentShadingRateEnumNV", vkCmdSetFragmentShadingRateEnumNV}, - {"vkCmdSetFragmentShadingRateKHR", vkCmdSetFragmentShadingRateKHR}, - {"vkCmdSetFrontFace", vkCmdSetFrontFace}, - {"vkCmdSetFrontFaceEXT", vkCmdSetFrontFaceEXT}, - {"vkCmdSetLineRasterizationModeEXT", vkCmdSetLineRasterizationModeEXT}, - {"vkCmdSetLineStippleEXT", vkCmdSetLineStippleEXT}, - {"vkCmdSetLineStippleEnableEXT", vkCmdSetLineStippleEnableEXT}, - {"vkCmdSetLineWidth", vkCmdSetLineWidth}, - {"vkCmdSetLogicOpEXT", vkCmdSetLogicOpEXT}, - {"vkCmdSetLogicOpEnableEXT", vkCmdSetLogicOpEnableEXT}, - {"vkCmdSetPatchControlPointsEXT", vkCmdSetPatchControlPointsEXT}, - {"vkCmdSetPerformanceMarkerINTEL", vkCmdSetPerformanceMarkerINTEL}, - {"vkCmdSetPerformanceOverrideINTEL", vkCmdSetPerformanceOverrideINTEL}, - {"vkCmdSetPerformanceStreamMarkerINTEL", vkCmdSetPerformanceStreamMarkerINTEL}, - {"vkCmdSetPolygonModeEXT", vkCmdSetPolygonModeEXT}, - {"vkCmdSetPrimitiveRestartEnable", vkCmdSetPrimitiveRestartEnable}, - {"vkCmdSetPrimitiveRestartEnableEXT", vkCmdSetPrimitiveRestartEnableEXT}, - {"vkCmdSetPrimitiveTopology", vkCmdSetPrimitiveTopology}, - {"vkCmdSetPrimitiveTopologyEXT", vkCmdSetPrimitiveTopologyEXT}, - {"vkCmdSetProvokingVertexModeEXT", vkCmdSetProvokingVertexModeEXT}, - {"vkCmdSetRasterizationSamplesEXT", vkCmdSetRasterizationSamplesEXT}, - {"vkCmdSetRasterizationStreamEXT", vkCmdSetRasterizationStreamEXT}, - {"vkCmdSetRasterizerDiscardEnable", vkCmdSetRasterizerDiscardEnable}, - {"vkCmdSetRasterizerDiscardEnableEXT", vkCmdSetRasterizerDiscardEnableEXT}, - {"vkCmdSetRayTracingPipelineStackSizeKHR", vkCmdSetRayTracingPipelineStackSizeKHR}, - {"vkCmdSetRepresentativeFragmentTestEnableNV", vkCmdSetRepresentativeFragmentTestEnableNV}, - {"vkCmdSetSampleLocationsEXT", vkCmdSetSampleLocationsEXT}, - {"vkCmdSetSampleLocationsEnableEXT", vkCmdSetSampleLocationsEnableEXT}, - {"vkCmdSetSampleMaskEXT", vkCmdSetSampleMaskEXT}, - {"vkCmdSetScissor", vkCmdSetScissor}, - {"vkCmdSetScissorWithCount", vkCmdSetScissorWithCount}, - {"vkCmdSetScissorWithCountEXT", vkCmdSetScissorWithCountEXT}, - {"vkCmdSetShadingRateImageEnableNV", vkCmdSetShadingRateImageEnableNV}, - {"vkCmdSetStencilCompareMask", vkCmdSetStencilCompareMask}, - {"vkCmdSetStencilOp", vkCmdSetStencilOp}, - {"vkCmdSetStencilOpEXT", vkCmdSetStencilOpEXT}, - {"vkCmdSetStencilReference", vkCmdSetStencilReference}, - {"vkCmdSetStencilTestEnable", vkCmdSetStencilTestEnable}, - {"vkCmdSetStencilTestEnableEXT", vkCmdSetStencilTestEnableEXT}, - {"vkCmdSetStencilWriteMask", vkCmdSetStencilWriteMask}, - {"vkCmdSetTessellationDomainOriginEXT", vkCmdSetTessellationDomainOriginEXT}, - {"vkCmdSetVertexInputEXT", vkCmdSetVertexInputEXT}, - {"vkCmdSetViewport", vkCmdSetViewport}, - {"vkCmdSetViewportShadingRatePaletteNV", vkCmdSetViewportShadingRatePaletteNV}, - {"vkCmdSetViewportSwizzleNV", vkCmdSetViewportSwizzleNV}, - {"vkCmdSetViewportWScalingEnableNV", vkCmdSetViewportWScalingEnableNV}, - {"vkCmdSetViewportWScalingNV", vkCmdSetViewportWScalingNV}, - {"vkCmdSetViewportWithCount", vkCmdSetViewportWithCount}, - {"vkCmdSetViewportWithCountEXT", vkCmdSetViewportWithCountEXT}, - {"vkCmdSubpassShadingHUAWEI", vkCmdSubpassShadingHUAWEI}, - {"vkCmdTraceRaysIndirect2KHR", vkCmdTraceRaysIndirect2KHR}, - {"vkCmdTraceRaysIndirectKHR", vkCmdTraceRaysIndirectKHR}, - {"vkCmdTraceRaysKHR", vkCmdTraceRaysKHR}, - {"vkCmdTraceRaysNV", vkCmdTraceRaysNV}, - {"vkCmdUpdateBuffer", vkCmdUpdateBuffer}, - {"vkCmdWaitEvents", vkCmdWaitEvents}, - {"vkCmdWaitEvents2", vkCmdWaitEvents2}, - {"vkCmdWaitEvents2KHR", vkCmdWaitEvents2KHR}, - {"vkCmdWriteAccelerationStructuresPropertiesKHR", vkCmdWriteAccelerationStructuresPropertiesKHR}, - {"vkCmdWriteAccelerationStructuresPropertiesNV", vkCmdWriteAccelerationStructuresPropertiesNV}, - {"vkCmdWriteBufferMarker2AMD", vkCmdWriteBufferMarker2AMD}, - {"vkCmdWriteBufferMarkerAMD", vkCmdWriteBufferMarkerAMD}, - {"vkCmdWriteMicromapsPropertiesEXT", vkCmdWriteMicromapsPropertiesEXT}, - {"vkCmdWriteTimestamp", vkCmdWriteTimestamp}, - {"vkCmdWriteTimestamp2", vkCmdWriteTimestamp2}, - {"vkCmdWriteTimestamp2KHR", vkCmdWriteTimestamp2KHR}, - {"vkCompileDeferredNV", vkCompileDeferredNV}, - {"vkCopyAccelerationStructureKHR", vkCopyAccelerationStructureKHR}, - {"vkCopyAccelerationStructureToMemoryKHR", vkCopyAccelerationStructureToMemoryKHR}, - {"vkCopyMemoryToAccelerationStructureKHR", vkCopyMemoryToAccelerationStructureKHR}, - {"vkCopyMemoryToMicromapEXT", vkCopyMemoryToMicromapEXT}, - {"vkCopyMicromapEXT", vkCopyMicromapEXT}, - {"vkCopyMicromapToMemoryEXT", vkCopyMicromapToMemoryEXT}, - {"vkCreateAccelerationStructureKHR", vkCreateAccelerationStructureKHR}, - {"vkCreateAccelerationStructureNV", vkCreateAccelerationStructureNV}, - {"vkCreateBuffer", vkCreateBuffer}, - {"vkCreateBufferView", vkCreateBufferView}, - {"vkCreateCommandPool", vkCreateCommandPool}, - {"vkCreateComputePipelines", vkCreateComputePipelines}, - {"vkCreateCuFunctionNVX", vkCreateCuFunctionNVX}, - {"vkCreateCuModuleNVX", vkCreateCuModuleNVX}, - {"vkCreateDeferredOperationKHR", vkCreateDeferredOperationKHR}, - {"vkCreateDescriptorPool", vkCreateDescriptorPool}, - {"vkCreateDescriptorSetLayout", vkCreateDescriptorSetLayout}, - {"vkCreateDescriptorUpdateTemplate", vkCreateDescriptorUpdateTemplate}, - {"vkCreateDescriptorUpdateTemplateKHR", vkCreateDescriptorUpdateTemplateKHR}, - {"vkCreateEvent", vkCreateEvent}, - {"vkCreateFence", vkCreateFence}, - {"vkCreateFramebuffer", vkCreateFramebuffer}, - {"vkCreateGraphicsPipelines", vkCreateGraphicsPipelines}, - {"vkCreateImage", vkCreateImage}, - {"vkCreateImageView", vkCreateImageView}, - {"vkCreateIndirectCommandsLayoutNV", vkCreateIndirectCommandsLayoutNV}, - {"vkCreateMicromapEXT", vkCreateMicromapEXT}, - {"vkCreateOpticalFlowSessionNV", vkCreateOpticalFlowSessionNV}, - {"vkCreatePipelineCache", vkCreatePipelineCache}, - {"vkCreatePipelineLayout", vkCreatePipelineLayout}, - {"vkCreatePrivateDataSlot", vkCreatePrivateDataSlot}, - {"vkCreatePrivateDataSlotEXT", vkCreatePrivateDataSlotEXT}, - {"vkCreateQueryPool", vkCreateQueryPool}, - {"vkCreateRayTracingPipelinesKHR", vkCreateRayTracingPipelinesKHR}, - {"vkCreateRayTracingPipelinesNV", vkCreateRayTracingPipelinesNV}, - {"vkCreateRenderPass", vkCreateRenderPass}, - {"vkCreateRenderPass2", vkCreateRenderPass2}, - {"vkCreateRenderPass2KHR", vkCreateRenderPass2KHR}, - {"vkCreateSampler", vkCreateSampler}, - {"vkCreateSamplerYcbcrConversion", vkCreateSamplerYcbcrConversion}, - {"vkCreateSamplerYcbcrConversionKHR", vkCreateSamplerYcbcrConversionKHR}, - {"vkCreateSemaphore", vkCreateSemaphore}, - {"vkCreateShaderModule", vkCreateShaderModule}, - {"vkCreateSwapchainKHR", vkCreateSwapchainKHR}, - {"vkCreateValidationCacheEXT", vkCreateValidationCacheEXT}, - {"vkDebugMarkerSetObjectNameEXT", vkDebugMarkerSetObjectNameEXT}, - {"vkDebugMarkerSetObjectTagEXT", vkDebugMarkerSetObjectTagEXT}, - {"vkDeferredOperationJoinKHR", vkDeferredOperationJoinKHR}, - {"vkDestroyAccelerationStructureKHR", vkDestroyAccelerationStructureKHR}, - {"vkDestroyAccelerationStructureNV", vkDestroyAccelerationStructureNV}, - {"vkDestroyBuffer", vkDestroyBuffer}, - {"vkDestroyBufferView", vkDestroyBufferView}, - {"vkDestroyCommandPool", vkDestroyCommandPool}, - {"vkDestroyCuFunctionNVX", vkDestroyCuFunctionNVX}, - {"vkDestroyCuModuleNVX", vkDestroyCuModuleNVX}, - {"vkDestroyDeferredOperationKHR", vkDestroyDeferredOperationKHR}, - {"vkDestroyDescriptorPool", vkDestroyDescriptorPool}, - {"vkDestroyDescriptorSetLayout", vkDestroyDescriptorSetLayout}, - {"vkDestroyDescriptorUpdateTemplate", vkDestroyDescriptorUpdateTemplate}, - {"vkDestroyDescriptorUpdateTemplateKHR", vkDestroyDescriptorUpdateTemplateKHR}, - {"vkDestroyDevice", vkDestroyDevice}, - {"vkDestroyEvent", vkDestroyEvent}, - {"vkDestroyFence", vkDestroyFence}, - {"vkDestroyFramebuffer", vkDestroyFramebuffer}, - {"vkDestroyImage", vkDestroyImage}, - {"vkDestroyImageView", vkDestroyImageView}, - {"vkDestroyIndirectCommandsLayoutNV", vkDestroyIndirectCommandsLayoutNV}, - {"vkDestroyMicromapEXT", vkDestroyMicromapEXT}, - {"vkDestroyOpticalFlowSessionNV", vkDestroyOpticalFlowSessionNV}, - {"vkDestroyPipeline", vkDestroyPipeline}, - {"vkDestroyPipelineCache", vkDestroyPipelineCache}, - {"vkDestroyPipelineLayout", vkDestroyPipelineLayout}, - {"vkDestroyPrivateDataSlot", vkDestroyPrivateDataSlot}, - {"vkDestroyPrivateDataSlotEXT", vkDestroyPrivateDataSlotEXT}, - {"vkDestroyQueryPool", vkDestroyQueryPool}, - {"vkDestroyRenderPass", vkDestroyRenderPass}, - {"vkDestroySampler", vkDestroySampler}, - {"vkDestroySamplerYcbcrConversion", vkDestroySamplerYcbcrConversion}, - {"vkDestroySamplerYcbcrConversionKHR", vkDestroySamplerYcbcrConversionKHR}, - {"vkDestroySemaphore", vkDestroySemaphore}, - {"vkDestroyShaderModule", vkDestroyShaderModule}, - {"vkDestroySwapchainKHR", vkDestroySwapchainKHR}, - {"vkDestroyValidationCacheEXT", vkDestroyValidationCacheEXT}, - {"vkDeviceWaitIdle", vkDeviceWaitIdle}, - {"vkEndCommandBuffer", vkEndCommandBuffer}, - {"vkFlushMappedMemoryRanges", vkFlushMappedMemoryRanges}, - {"vkFreeCommandBuffers", vkFreeCommandBuffers}, - {"vkFreeDescriptorSets", vkFreeDescriptorSets}, - {"vkFreeMemory", vkFreeMemory}, - {"vkGetAccelerationStructureBuildSizesKHR", vkGetAccelerationStructureBuildSizesKHR}, - {"vkGetAccelerationStructureDeviceAddressKHR", vkGetAccelerationStructureDeviceAddressKHR}, - {"vkGetAccelerationStructureHandleNV", vkGetAccelerationStructureHandleNV}, - {"vkGetAccelerationStructureMemoryRequirementsNV", vkGetAccelerationStructureMemoryRequirementsNV}, - {"vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT", vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT}, - {"vkGetBufferDeviceAddress", vkGetBufferDeviceAddress}, - {"vkGetBufferDeviceAddressEXT", vkGetBufferDeviceAddressEXT}, - {"vkGetBufferDeviceAddressKHR", vkGetBufferDeviceAddressKHR}, - {"vkGetBufferMemoryRequirements", vkGetBufferMemoryRequirements}, - {"vkGetBufferMemoryRequirements2", vkGetBufferMemoryRequirements2}, - {"vkGetBufferMemoryRequirements2KHR", vkGetBufferMemoryRequirements2KHR}, - {"vkGetBufferOpaqueCaptureAddress", vkGetBufferOpaqueCaptureAddress}, - {"vkGetBufferOpaqueCaptureAddressKHR", vkGetBufferOpaqueCaptureAddressKHR}, - {"vkGetBufferOpaqueCaptureDescriptorDataEXT", vkGetBufferOpaqueCaptureDescriptorDataEXT}, - {"vkGetCalibratedTimestampsEXT", vkGetCalibratedTimestampsEXT}, - {"vkGetDeferredOperationMaxConcurrencyKHR", vkGetDeferredOperationMaxConcurrencyKHR}, - {"vkGetDeferredOperationResultKHR", vkGetDeferredOperationResultKHR}, - {"vkGetDescriptorEXT", vkGetDescriptorEXT}, - {"vkGetDescriptorSetHostMappingVALVE", vkGetDescriptorSetHostMappingVALVE}, - {"vkGetDescriptorSetLayoutBindingOffsetEXT", vkGetDescriptorSetLayoutBindingOffsetEXT}, - {"vkGetDescriptorSetLayoutHostMappingInfoVALVE", vkGetDescriptorSetLayoutHostMappingInfoVALVE}, - {"vkGetDescriptorSetLayoutSizeEXT", vkGetDescriptorSetLayoutSizeEXT}, - {"vkGetDescriptorSetLayoutSupport", vkGetDescriptorSetLayoutSupport}, - {"vkGetDescriptorSetLayoutSupportKHR", vkGetDescriptorSetLayoutSupportKHR}, - {"vkGetDeviceAccelerationStructureCompatibilityKHR", vkGetDeviceAccelerationStructureCompatibilityKHR}, - {"vkGetDeviceBufferMemoryRequirements", vkGetDeviceBufferMemoryRequirements}, - {"vkGetDeviceBufferMemoryRequirementsKHR", vkGetDeviceBufferMemoryRequirementsKHR}, - {"vkGetDeviceFaultInfoEXT", vkGetDeviceFaultInfoEXT}, - {"vkGetDeviceGroupPeerMemoryFeatures", vkGetDeviceGroupPeerMemoryFeatures}, - {"vkGetDeviceGroupPeerMemoryFeaturesKHR", vkGetDeviceGroupPeerMemoryFeaturesKHR}, - {"vkGetDeviceGroupPresentCapabilitiesKHR", vkGetDeviceGroupPresentCapabilitiesKHR}, - {"vkGetDeviceGroupSurfacePresentModesKHR", vkGetDeviceGroupSurfacePresentModesKHR}, - {"vkGetDeviceImageMemoryRequirements", vkGetDeviceImageMemoryRequirements}, - {"vkGetDeviceImageMemoryRequirementsKHR", vkGetDeviceImageMemoryRequirementsKHR}, - {"vkGetDeviceImageSparseMemoryRequirements", vkGetDeviceImageSparseMemoryRequirements}, - {"vkGetDeviceImageSparseMemoryRequirementsKHR", vkGetDeviceImageSparseMemoryRequirementsKHR}, - {"vkGetDeviceMemoryCommitment", vkGetDeviceMemoryCommitment}, - {"vkGetDeviceMemoryOpaqueCaptureAddress", vkGetDeviceMemoryOpaqueCaptureAddress}, - {"vkGetDeviceMemoryOpaqueCaptureAddressKHR", vkGetDeviceMemoryOpaqueCaptureAddressKHR}, - {"vkGetDeviceMicromapCompatibilityEXT", vkGetDeviceMicromapCompatibilityEXT}, - {"vkGetDeviceProcAddr", vkGetDeviceProcAddr}, - {"vkGetDeviceQueue", vkGetDeviceQueue}, - {"vkGetDeviceQueue2", vkGetDeviceQueue2}, - {"vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI", vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI}, - {"vkGetDynamicRenderingTilePropertiesQCOM", vkGetDynamicRenderingTilePropertiesQCOM}, - {"vkGetEventStatus", vkGetEventStatus}, - {"vkGetFenceStatus", vkGetFenceStatus}, - {"vkGetFramebufferTilePropertiesQCOM", vkGetFramebufferTilePropertiesQCOM}, - {"vkGetGeneratedCommandsMemoryRequirementsNV", vkGetGeneratedCommandsMemoryRequirementsNV}, - {"vkGetImageMemoryRequirements", vkGetImageMemoryRequirements}, - {"vkGetImageMemoryRequirements2", vkGetImageMemoryRequirements2}, - {"vkGetImageMemoryRequirements2KHR", vkGetImageMemoryRequirements2KHR}, - {"vkGetImageOpaqueCaptureDescriptorDataEXT", vkGetImageOpaqueCaptureDescriptorDataEXT}, - {"vkGetImageSparseMemoryRequirements", vkGetImageSparseMemoryRequirements}, - {"vkGetImageSparseMemoryRequirements2", vkGetImageSparseMemoryRequirements2}, - {"vkGetImageSparseMemoryRequirements2KHR", vkGetImageSparseMemoryRequirements2KHR}, - {"vkGetImageSubresourceLayout", vkGetImageSubresourceLayout}, - {"vkGetImageSubresourceLayout2EXT", vkGetImageSubresourceLayout2EXT}, - {"vkGetImageViewAddressNVX", vkGetImageViewAddressNVX}, - {"vkGetImageViewHandleNVX", vkGetImageViewHandleNVX}, - {"vkGetImageViewOpaqueCaptureDescriptorDataEXT", vkGetImageViewOpaqueCaptureDescriptorDataEXT}, - {"vkGetMemoryHostPointerPropertiesEXT", vkGetMemoryHostPointerPropertiesEXT}, - {"vkGetMicromapBuildSizesEXT", vkGetMicromapBuildSizesEXT}, - {"vkGetPerformanceParameterINTEL", vkGetPerformanceParameterINTEL}, - {"vkGetPipelineCacheData", vkGetPipelineCacheData}, - {"vkGetPipelineExecutableInternalRepresentationsKHR", vkGetPipelineExecutableInternalRepresentationsKHR}, - {"vkGetPipelineExecutablePropertiesKHR", vkGetPipelineExecutablePropertiesKHR}, - {"vkGetPipelineExecutableStatisticsKHR", vkGetPipelineExecutableStatisticsKHR}, - {"vkGetPipelinePropertiesEXT", vkGetPipelinePropertiesEXT}, - {"vkGetPrivateData", vkGetPrivateData}, - {"vkGetPrivateDataEXT", vkGetPrivateDataEXT}, - {"vkGetQueryPoolResults", vkGetQueryPoolResults}, - {"vkGetQueueCheckpointData2NV", vkGetQueueCheckpointData2NV}, - {"vkGetQueueCheckpointDataNV", vkGetQueueCheckpointDataNV}, - {"vkGetRayTracingCaptureReplayShaderGroupHandlesKHR", vkGetRayTracingCaptureReplayShaderGroupHandlesKHR}, - {"vkGetRayTracingShaderGroupHandlesKHR", vkGetRayTracingShaderGroupHandlesKHR}, - {"vkGetRayTracingShaderGroupHandlesNV", vkGetRayTracingShaderGroupHandlesNV}, - {"vkGetRayTracingShaderGroupStackSizeKHR", vkGetRayTracingShaderGroupStackSizeKHR}, - {"vkGetRenderAreaGranularity", vkGetRenderAreaGranularity}, - {"vkGetSamplerOpaqueCaptureDescriptorDataEXT", vkGetSamplerOpaqueCaptureDescriptorDataEXT}, - {"vkGetSemaphoreCounterValue", vkGetSemaphoreCounterValue}, - {"vkGetSemaphoreCounterValueKHR", vkGetSemaphoreCounterValueKHR}, - {"vkGetShaderInfoAMD", vkGetShaderInfoAMD}, - {"vkGetShaderModuleCreateInfoIdentifierEXT", vkGetShaderModuleCreateInfoIdentifierEXT}, - {"vkGetShaderModuleIdentifierEXT", vkGetShaderModuleIdentifierEXT}, - {"vkGetSwapchainImagesKHR", vkGetSwapchainImagesKHR}, - {"vkGetValidationCacheDataEXT", vkGetValidationCacheDataEXT}, - {"vkInitializePerformanceApiINTEL", vkInitializePerformanceApiINTEL}, - {"vkInvalidateMappedMemoryRanges", vkInvalidateMappedMemoryRanges}, - {"vkMapMemory", vkMapMemory}, - {"vkMergePipelineCaches", vkMergePipelineCaches}, - {"vkMergeValidationCachesEXT", vkMergeValidationCachesEXT}, - {"vkQueueBeginDebugUtilsLabelEXT", vkQueueBeginDebugUtilsLabelEXT}, - {"vkQueueBindSparse", vkQueueBindSparse}, - {"vkQueueEndDebugUtilsLabelEXT", vkQueueEndDebugUtilsLabelEXT}, - {"vkQueueInsertDebugUtilsLabelEXT", vkQueueInsertDebugUtilsLabelEXT}, - {"vkQueuePresentKHR", vkQueuePresentKHR}, - {"vkQueueSetPerformanceConfigurationINTEL", vkQueueSetPerformanceConfigurationINTEL}, - {"vkQueueSubmit", vkQueueSubmit}, - {"vkQueueSubmit2", vkQueueSubmit2}, - {"vkQueueSubmit2KHR", vkQueueSubmit2KHR}, - {"vkQueueWaitIdle", vkQueueWaitIdle}, - {"vkReleasePerformanceConfigurationINTEL", vkReleasePerformanceConfigurationINTEL}, - {"vkReleaseProfilingLockKHR", vkReleaseProfilingLockKHR}, - {"vkReleaseSwapchainImagesEXT", vkReleaseSwapchainImagesEXT}, - {"vkResetCommandBuffer", vkResetCommandBuffer}, - {"vkResetCommandPool", vkResetCommandPool}, - {"vkResetDescriptorPool", vkResetDescriptorPool}, - {"vkResetEvent", vkResetEvent}, - {"vkResetFences", vkResetFences}, - {"vkResetQueryPool", vkResetQueryPool}, - {"vkResetQueryPoolEXT", vkResetQueryPoolEXT}, - {"vkSetDebugUtilsObjectNameEXT", vkSetDebugUtilsObjectNameEXT}, - {"vkSetDebugUtilsObjectTagEXT", vkSetDebugUtilsObjectTagEXT}, - {"vkSetDeviceMemoryPriorityEXT", vkSetDeviceMemoryPriorityEXT}, - {"vkSetEvent", vkSetEvent}, - {"vkSetPrivateData", vkSetPrivateData}, - {"vkSetPrivateDataEXT", vkSetPrivateDataEXT}, - {"vkSignalSemaphore", vkSignalSemaphore}, - {"vkSignalSemaphoreKHR", vkSignalSemaphoreKHR}, - {"vkTrimCommandPool", vkTrimCommandPool}, - {"vkTrimCommandPoolKHR", vkTrimCommandPoolKHR}, - {"vkUninitializePerformanceApiINTEL", vkUninitializePerformanceApiINTEL}, - {"vkUnmapMemory", vkUnmapMemory}, - {"vkUpdateDescriptorSetWithTemplate", vkUpdateDescriptorSetWithTemplate}, - {"vkUpdateDescriptorSetWithTemplateKHR", vkUpdateDescriptorSetWithTemplateKHR}, - {"vkUpdateDescriptorSets", vkUpdateDescriptorSets}, - {"vkWaitForFences", vkWaitForFences}, - {"vkWaitForPresentKHR", vkWaitForPresentKHR}, - {"vkWaitSemaphores", vkWaitSemaphores}, - {"vkWaitSemaphoresKHR", vkWaitSemaphoresKHR}, - {"vkWriteAccelerationStructuresPropertiesKHR", vkWriteAccelerationStructuresPropertiesKHR}, - {"vkWriteMicromapsPropertiesEXT", vkWriteMicromapsPropertiesEXT}, -}; - -static const struct vulkan_func vk_phys_dev_dispatch_table[] = -{ - {"vkCreateDevice", vkCreateDevice}, - {"vkEnumerateDeviceExtensionProperties", vkEnumerateDeviceExtensionProperties}, - {"vkEnumerateDeviceLayerProperties", vkEnumerateDeviceLayerProperties}, - {"vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR", vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR}, - {"vkGetPhysicalDeviceCalibrateableTimeDomainsEXT", vkGetPhysicalDeviceCalibrateableTimeDomainsEXT}, - {"vkGetPhysicalDeviceCooperativeMatrixPropertiesNV", vkGetPhysicalDeviceCooperativeMatrixPropertiesNV}, - {"vkGetPhysicalDeviceExternalBufferProperties", vkGetPhysicalDeviceExternalBufferProperties}, - {"vkGetPhysicalDeviceExternalBufferPropertiesKHR", vkGetPhysicalDeviceExternalBufferPropertiesKHR}, - {"vkGetPhysicalDeviceExternalFenceProperties", vkGetPhysicalDeviceExternalFenceProperties}, - {"vkGetPhysicalDeviceExternalFencePropertiesKHR", vkGetPhysicalDeviceExternalFencePropertiesKHR}, - {"vkGetPhysicalDeviceExternalSemaphoreProperties", vkGetPhysicalDeviceExternalSemaphoreProperties}, - {"vkGetPhysicalDeviceExternalSemaphorePropertiesKHR", vkGetPhysicalDeviceExternalSemaphorePropertiesKHR}, - {"vkGetPhysicalDeviceFeatures", vkGetPhysicalDeviceFeatures}, - {"vkGetPhysicalDeviceFeatures2", vkGetPhysicalDeviceFeatures2}, - {"vkGetPhysicalDeviceFeatures2KHR", vkGetPhysicalDeviceFeatures2KHR}, - {"vkGetPhysicalDeviceFormatProperties", vkGetPhysicalDeviceFormatProperties}, - {"vkGetPhysicalDeviceFormatProperties2", vkGetPhysicalDeviceFormatProperties2}, - {"vkGetPhysicalDeviceFormatProperties2KHR", vkGetPhysicalDeviceFormatProperties2KHR}, - {"vkGetPhysicalDeviceFragmentShadingRatesKHR", vkGetPhysicalDeviceFragmentShadingRatesKHR}, - {"vkGetPhysicalDeviceImageFormatProperties", vkGetPhysicalDeviceImageFormatProperties}, - {"vkGetPhysicalDeviceImageFormatProperties2", vkGetPhysicalDeviceImageFormatProperties2}, - {"vkGetPhysicalDeviceImageFormatProperties2KHR", vkGetPhysicalDeviceImageFormatProperties2KHR}, - {"vkGetPhysicalDeviceMemoryProperties", vkGetPhysicalDeviceMemoryProperties}, - {"vkGetPhysicalDeviceMemoryProperties2", vkGetPhysicalDeviceMemoryProperties2}, - {"vkGetPhysicalDeviceMemoryProperties2KHR", vkGetPhysicalDeviceMemoryProperties2KHR}, - {"vkGetPhysicalDeviceMultisamplePropertiesEXT", vkGetPhysicalDeviceMultisamplePropertiesEXT}, - {"vkGetPhysicalDeviceOpticalFlowImageFormatsNV", vkGetPhysicalDeviceOpticalFlowImageFormatsNV}, - {"vkGetPhysicalDevicePresentRectanglesKHR", vkGetPhysicalDevicePresentRectanglesKHR}, - {"vkGetPhysicalDeviceProperties", vkGetPhysicalDeviceProperties}, - {"vkGetPhysicalDeviceProperties2", vkGetPhysicalDeviceProperties2}, - {"vkGetPhysicalDeviceProperties2KHR", vkGetPhysicalDeviceProperties2KHR}, - {"vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR", vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR}, - {"vkGetPhysicalDeviceQueueFamilyProperties", vkGetPhysicalDeviceQueueFamilyProperties}, - {"vkGetPhysicalDeviceQueueFamilyProperties2", vkGetPhysicalDeviceQueueFamilyProperties2}, - {"vkGetPhysicalDeviceQueueFamilyProperties2KHR", vkGetPhysicalDeviceQueueFamilyProperties2KHR}, - {"vkGetPhysicalDeviceSparseImageFormatProperties", vkGetPhysicalDeviceSparseImageFormatProperties}, - {"vkGetPhysicalDeviceSparseImageFormatProperties2", vkGetPhysicalDeviceSparseImageFormatProperties2}, - {"vkGetPhysicalDeviceSparseImageFormatProperties2KHR", vkGetPhysicalDeviceSparseImageFormatProperties2KHR}, - {"vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV", vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV}, - {"vkGetPhysicalDeviceSurfaceCapabilities2KHR", vkGetPhysicalDeviceSurfaceCapabilities2KHR}, - {"vkGetPhysicalDeviceSurfaceCapabilitiesKHR", vkGetPhysicalDeviceSurfaceCapabilitiesKHR}, - {"vkGetPhysicalDeviceSurfaceFormats2KHR", vkGetPhysicalDeviceSurfaceFormats2KHR}, - {"vkGetPhysicalDeviceSurfaceFormatsKHR", vkGetPhysicalDeviceSurfaceFormatsKHR}, - {"vkGetPhysicalDeviceSurfacePresentModesKHR", vkGetPhysicalDeviceSurfacePresentModesKHR}, - {"vkGetPhysicalDeviceSurfaceSupportKHR", vkGetPhysicalDeviceSurfaceSupportKHR}, - {"vkGetPhysicalDeviceToolProperties", vkGetPhysicalDeviceToolProperties}, - {"vkGetPhysicalDeviceToolPropertiesEXT", vkGetPhysicalDeviceToolPropertiesEXT}, - {"vkGetPhysicalDeviceWin32PresentationSupportKHR", vkGetPhysicalDeviceWin32PresentationSupportKHR}, -}; - -static const struct vulkan_func vk_instance_dispatch_table[] = -{ - {"vkCreateDebugReportCallbackEXT", vkCreateDebugReportCallbackEXT}, - {"vkCreateDebugUtilsMessengerEXT", vkCreateDebugUtilsMessengerEXT}, - {"vkCreateWin32SurfaceKHR", vkCreateWin32SurfaceKHR}, - {"vkDebugReportMessageEXT", vkDebugReportMessageEXT}, - {"vkDestroyDebugReportCallbackEXT", vkDestroyDebugReportCallbackEXT}, - {"vkDestroyDebugUtilsMessengerEXT", vkDestroyDebugUtilsMessengerEXT}, - {"vkDestroyInstance", vkDestroyInstance}, - {"vkDestroySurfaceKHR", vkDestroySurfaceKHR}, - {"vkEnumeratePhysicalDeviceGroups", vkEnumeratePhysicalDeviceGroups}, - {"vkEnumeratePhysicalDeviceGroupsKHR", vkEnumeratePhysicalDeviceGroupsKHR}, - {"vkEnumeratePhysicalDevices", vkEnumeratePhysicalDevices}, - {"vkSubmitDebugUtilsMessageEXT", vkSubmitDebugUtilsMessageEXT}, -}; - -void *wine_vk_get_device_proc_addr(const char *name) -{ - unsigned int i; - for (i = 0; i < ARRAY_SIZE(vk_device_dispatch_table); i++) - { - if (strcmp(vk_device_dispatch_table[i].name, name) == 0) - { - TRACE("Found name=%s in device table\n", debugstr_a(name)); - return vk_device_dispatch_table[i].func; - } - } - return NULL; -} - -void *wine_vk_get_phys_dev_proc_addr(const char *name) -{ - unsigned int i; - for (i = 0; i < ARRAY_SIZE(vk_phys_dev_dispatch_table); i++) - { - if (strcmp(vk_phys_dev_dispatch_table[i].name, name) == 0) - { - TRACE("Found name=%s in physical device table\n", debugstr_a(name)); - return vk_phys_dev_dispatch_table[i].func; - } - } - return NULL; -} - -void *wine_vk_get_instance_proc_addr(const char *name) -{ - unsigned int i; - for (i = 0; i < ARRAY_SIZE(vk_instance_dispatch_table); i++) - { - if (strcmp(vk_instance_dispatch_table[i].name, name) == 0) - { - TRACE("Found name=%s in instance table\n", debugstr_a(name)); - return vk_instance_dispatch_table[i].func; - } - } - return NULL; -} diff --git a/dlls/winevulkan/loader_thunks.h b/dlls/winevulkan/loader_thunks.h deleted file mode 100644 index b80a0349329..00000000000 --- a/dlls/winevulkan/loader_thunks.h +++ /dev/null @@ -1,4665 +0,0 @@ -/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! - * - * This file is generated from Vulkan vk.xml file covered - * by the following copyright and permission notice: - * - * Copyright 2015-2022 The Khronos Group Inc. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#ifndef __WINE_VULKAN_LOADER_THUNKS_H -#define __WINE_VULKAN_LOADER_THUNKS_H - -enum unix_call -{ - unix_init, - unix_is_available_instance_function, - unix_is_available_device_function, - unix_vkAcquireNextImage2KHR, - unix_vkAcquireNextImageKHR, - unix_vkAcquirePerformanceConfigurationINTEL, - unix_vkAcquireProfilingLockKHR, - unix_vkAllocateCommandBuffers, - unix_vkAllocateDescriptorSets, - unix_vkAllocateMemory, - unix_vkBeginCommandBuffer, - unix_vkBindAccelerationStructureMemoryNV, - unix_vkBindBufferMemory, - unix_vkBindBufferMemory2, - unix_vkBindBufferMemory2KHR, - unix_vkBindImageMemory, - unix_vkBindImageMemory2, - unix_vkBindImageMemory2KHR, - unix_vkBindOpticalFlowSessionImageNV, - unix_vkBuildAccelerationStructuresKHR, - unix_vkBuildMicromapsEXT, - unix_vkCmdBeginConditionalRenderingEXT, - unix_vkCmdBeginDebugUtilsLabelEXT, - unix_vkCmdBeginQuery, - unix_vkCmdBeginQueryIndexedEXT, - unix_vkCmdBeginRenderPass, - unix_vkCmdBeginRenderPass2, - unix_vkCmdBeginRenderPass2KHR, - unix_vkCmdBeginRendering, - unix_vkCmdBeginRenderingKHR, - unix_vkCmdBeginTransformFeedbackEXT, - unix_vkCmdBindDescriptorBufferEmbeddedSamplersEXT, - unix_vkCmdBindDescriptorBuffersEXT, - unix_vkCmdBindDescriptorSets, - unix_vkCmdBindIndexBuffer, - unix_vkCmdBindInvocationMaskHUAWEI, - unix_vkCmdBindPipeline, - unix_vkCmdBindPipelineShaderGroupNV, - unix_vkCmdBindShadingRateImageNV, - unix_vkCmdBindTransformFeedbackBuffersEXT, - unix_vkCmdBindVertexBuffers, - unix_vkCmdBindVertexBuffers2, - unix_vkCmdBindVertexBuffers2EXT, - unix_vkCmdBlitImage, - unix_vkCmdBlitImage2, - unix_vkCmdBlitImage2KHR, - unix_vkCmdBuildAccelerationStructureNV, - unix_vkCmdBuildAccelerationStructuresIndirectKHR, - unix_vkCmdBuildAccelerationStructuresKHR, - unix_vkCmdBuildMicromapsEXT, - unix_vkCmdClearAttachments, - unix_vkCmdClearColorImage, - unix_vkCmdClearDepthStencilImage, - unix_vkCmdCopyAccelerationStructureKHR, - unix_vkCmdCopyAccelerationStructureNV, - unix_vkCmdCopyAccelerationStructureToMemoryKHR, - unix_vkCmdCopyBuffer, - unix_vkCmdCopyBuffer2, - unix_vkCmdCopyBuffer2KHR, - unix_vkCmdCopyBufferToImage, - unix_vkCmdCopyBufferToImage2, - unix_vkCmdCopyBufferToImage2KHR, - unix_vkCmdCopyImage, - unix_vkCmdCopyImage2, - unix_vkCmdCopyImage2KHR, - unix_vkCmdCopyImageToBuffer, - unix_vkCmdCopyImageToBuffer2, - unix_vkCmdCopyImageToBuffer2KHR, - unix_vkCmdCopyMemoryIndirectNV, - unix_vkCmdCopyMemoryToAccelerationStructureKHR, - unix_vkCmdCopyMemoryToImageIndirectNV, - unix_vkCmdCopyMemoryToMicromapEXT, - unix_vkCmdCopyMicromapEXT, - unix_vkCmdCopyMicromapToMemoryEXT, - unix_vkCmdCopyQueryPoolResults, - unix_vkCmdCuLaunchKernelNVX, - unix_vkCmdDebugMarkerBeginEXT, - unix_vkCmdDebugMarkerEndEXT, - unix_vkCmdDebugMarkerInsertEXT, - unix_vkCmdDecompressMemoryIndirectCountNV, - unix_vkCmdDecompressMemoryNV, - unix_vkCmdDispatch, - unix_vkCmdDispatchBase, - unix_vkCmdDispatchBaseKHR, - unix_vkCmdDispatchIndirect, - unix_vkCmdDraw, - unix_vkCmdDrawIndexed, - unix_vkCmdDrawIndexedIndirect, - unix_vkCmdDrawIndexedIndirectCount, - unix_vkCmdDrawIndexedIndirectCountAMD, - unix_vkCmdDrawIndexedIndirectCountKHR, - unix_vkCmdDrawIndirect, - unix_vkCmdDrawIndirectByteCountEXT, - unix_vkCmdDrawIndirectCount, - unix_vkCmdDrawIndirectCountAMD, - unix_vkCmdDrawIndirectCountKHR, - unix_vkCmdDrawMeshTasksEXT, - unix_vkCmdDrawMeshTasksIndirectCountEXT, - unix_vkCmdDrawMeshTasksIndirectCountNV, - unix_vkCmdDrawMeshTasksIndirectEXT, - unix_vkCmdDrawMeshTasksIndirectNV, - unix_vkCmdDrawMeshTasksNV, - unix_vkCmdDrawMultiEXT, - unix_vkCmdDrawMultiIndexedEXT, - unix_vkCmdEndConditionalRenderingEXT, - unix_vkCmdEndDebugUtilsLabelEXT, - unix_vkCmdEndQuery, - unix_vkCmdEndQueryIndexedEXT, - unix_vkCmdEndRenderPass, - unix_vkCmdEndRenderPass2, - unix_vkCmdEndRenderPass2KHR, - unix_vkCmdEndRendering, - unix_vkCmdEndRenderingKHR, - unix_vkCmdEndTransformFeedbackEXT, - unix_vkCmdExecuteCommands, - unix_vkCmdExecuteGeneratedCommandsNV, - unix_vkCmdFillBuffer, - unix_vkCmdInsertDebugUtilsLabelEXT, - unix_vkCmdNextSubpass, - unix_vkCmdNextSubpass2, - unix_vkCmdNextSubpass2KHR, - unix_vkCmdOpticalFlowExecuteNV, - unix_vkCmdPipelineBarrier, - unix_vkCmdPipelineBarrier2, - unix_vkCmdPipelineBarrier2KHR, - unix_vkCmdPreprocessGeneratedCommandsNV, - unix_vkCmdPushConstants, - unix_vkCmdPushDescriptorSetKHR, - unix_vkCmdPushDescriptorSetWithTemplateKHR, - unix_vkCmdResetEvent, - unix_vkCmdResetEvent2, - unix_vkCmdResetEvent2KHR, - unix_vkCmdResetQueryPool, - unix_vkCmdResolveImage, - unix_vkCmdResolveImage2, - unix_vkCmdResolveImage2KHR, - unix_vkCmdSetAlphaToCoverageEnableEXT, - unix_vkCmdSetAlphaToOneEnableEXT, - unix_vkCmdSetBlendConstants, - unix_vkCmdSetCheckpointNV, - unix_vkCmdSetCoarseSampleOrderNV, - unix_vkCmdSetColorBlendAdvancedEXT, - unix_vkCmdSetColorBlendEnableEXT, - unix_vkCmdSetColorBlendEquationEXT, - unix_vkCmdSetColorWriteEnableEXT, - unix_vkCmdSetColorWriteMaskEXT, - unix_vkCmdSetConservativeRasterizationModeEXT, - unix_vkCmdSetCoverageModulationModeNV, - unix_vkCmdSetCoverageModulationTableEnableNV, - unix_vkCmdSetCoverageModulationTableNV, - unix_vkCmdSetCoverageReductionModeNV, - unix_vkCmdSetCoverageToColorEnableNV, - unix_vkCmdSetCoverageToColorLocationNV, - unix_vkCmdSetCullMode, - unix_vkCmdSetCullModeEXT, - unix_vkCmdSetDepthBias, - unix_vkCmdSetDepthBiasEnable, - unix_vkCmdSetDepthBiasEnableEXT, - unix_vkCmdSetDepthBounds, - unix_vkCmdSetDepthBoundsTestEnable, - unix_vkCmdSetDepthBoundsTestEnableEXT, - unix_vkCmdSetDepthClampEnableEXT, - unix_vkCmdSetDepthClipEnableEXT, - unix_vkCmdSetDepthClipNegativeOneToOneEXT, - unix_vkCmdSetDepthCompareOp, - unix_vkCmdSetDepthCompareOpEXT, - unix_vkCmdSetDepthTestEnable, - unix_vkCmdSetDepthTestEnableEXT, - unix_vkCmdSetDepthWriteEnable, - unix_vkCmdSetDepthWriteEnableEXT, - unix_vkCmdSetDescriptorBufferOffsetsEXT, - unix_vkCmdSetDeviceMask, - unix_vkCmdSetDeviceMaskKHR, - unix_vkCmdSetDiscardRectangleEXT, - unix_vkCmdSetEvent, - unix_vkCmdSetEvent2, - unix_vkCmdSetEvent2KHR, - unix_vkCmdSetExclusiveScissorNV, - unix_vkCmdSetExtraPrimitiveOverestimationSizeEXT, - unix_vkCmdSetFragmentShadingRateEnumNV, - unix_vkCmdSetFragmentShadingRateKHR, - unix_vkCmdSetFrontFace, - unix_vkCmdSetFrontFaceEXT, - unix_vkCmdSetLineRasterizationModeEXT, - unix_vkCmdSetLineStippleEXT, - unix_vkCmdSetLineStippleEnableEXT, - unix_vkCmdSetLineWidth, - unix_vkCmdSetLogicOpEXT, - unix_vkCmdSetLogicOpEnableEXT, - unix_vkCmdSetPatchControlPointsEXT, - unix_vkCmdSetPerformanceMarkerINTEL, - unix_vkCmdSetPerformanceOverrideINTEL, - unix_vkCmdSetPerformanceStreamMarkerINTEL, - unix_vkCmdSetPolygonModeEXT, - unix_vkCmdSetPrimitiveRestartEnable, - unix_vkCmdSetPrimitiveRestartEnableEXT, - unix_vkCmdSetPrimitiveTopology, - unix_vkCmdSetPrimitiveTopologyEXT, - unix_vkCmdSetProvokingVertexModeEXT, - unix_vkCmdSetRasterizationSamplesEXT, - unix_vkCmdSetRasterizationStreamEXT, - unix_vkCmdSetRasterizerDiscardEnable, - unix_vkCmdSetRasterizerDiscardEnableEXT, - unix_vkCmdSetRayTracingPipelineStackSizeKHR, - unix_vkCmdSetRepresentativeFragmentTestEnableNV, - unix_vkCmdSetSampleLocationsEXT, - unix_vkCmdSetSampleLocationsEnableEXT, - unix_vkCmdSetSampleMaskEXT, - unix_vkCmdSetScissor, - unix_vkCmdSetScissorWithCount, - unix_vkCmdSetScissorWithCountEXT, - unix_vkCmdSetShadingRateImageEnableNV, - unix_vkCmdSetStencilCompareMask, - unix_vkCmdSetStencilOp, - unix_vkCmdSetStencilOpEXT, - unix_vkCmdSetStencilReference, - unix_vkCmdSetStencilTestEnable, - unix_vkCmdSetStencilTestEnableEXT, - unix_vkCmdSetStencilWriteMask, - unix_vkCmdSetTessellationDomainOriginEXT, - unix_vkCmdSetVertexInputEXT, - unix_vkCmdSetViewport, - unix_vkCmdSetViewportShadingRatePaletteNV, - unix_vkCmdSetViewportSwizzleNV, - unix_vkCmdSetViewportWScalingEnableNV, - unix_vkCmdSetViewportWScalingNV, - unix_vkCmdSetViewportWithCount, - unix_vkCmdSetViewportWithCountEXT, - unix_vkCmdSubpassShadingHUAWEI, - unix_vkCmdTraceRaysIndirect2KHR, - unix_vkCmdTraceRaysIndirectKHR, - unix_vkCmdTraceRaysKHR, - unix_vkCmdTraceRaysNV, - unix_vkCmdUpdateBuffer, - unix_vkCmdWaitEvents, - unix_vkCmdWaitEvents2, - unix_vkCmdWaitEvents2KHR, - unix_vkCmdWriteAccelerationStructuresPropertiesKHR, - unix_vkCmdWriteAccelerationStructuresPropertiesNV, - unix_vkCmdWriteBufferMarker2AMD, - unix_vkCmdWriteBufferMarkerAMD, - unix_vkCmdWriteMicromapsPropertiesEXT, - unix_vkCmdWriteTimestamp, - unix_vkCmdWriteTimestamp2, - unix_vkCmdWriteTimestamp2KHR, - unix_vkCompileDeferredNV, - unix_vkCopyAccelerationStructureKHR, - unix_vkCopyAccelerationStructureToMemoryKHR, - unix_vkCopyMemoryToAccelerationStructureKHR, - unix_vkCopyMemoryToMicromapEXT, - unix_vkCopyMicromapEXT, - unix_vkCopyMicromapToMemoryEXT, - unix_vkCreateAccelerationStructureKHR, - unix_vkCreateAccelerationStructureNV, - unix_vkCreateBuffer, - unix_vkCreateBufferView, - unix_vkCreateCommandPool, - unix_vkCreateComputePipelines, - unix_vkCreateCuFunctionNVX, - unix_vkCreateCuModuleNVX, - unix_vkCreateDebugReportCallbackEXT, - unix_vkCreateDebugUtilsMessengerEXT, - unix_vkCreateDeferredOperationKHR, - unix_vkCreateDescriptorPool, - unix_vkCreateDescriptorSetLayout, - unix_vkCreateDescriptorUpdateTemplate, - unix_vkCreateDescriptorUpdateTemplateKHR, - unix_vkCreateDevice, - unix_vkCreateEvent, - unix_vkCreateFence, - unix_vkCreateFramebuffer, - unix_vkCreateGraphicsPipelines, - unix_vkCreateImage, - unix_vkCreateImageView, - unix_vkCreateIndirectCommandsLayoutNV, - unix_vkCreateInstance, - unix_vkCreateMicromapEXT, - unix_vkCreateOpticalFlowSessionNV, - unix_vkCreatePipelineCache, - unix_vkCreatePipelineLayout, - unix_vkCreatePrivateDataSlot, - unix_vkCreatePrivateDataSlotEXT, - unix_vkCreateQueryPool, - unix_vkCreateRayTracingPipelinesKHR, - unix_vkCreateRayTracingPipelinesNV, - unix_vkCreateRenderPass, - unix_vkCreateRenderPass2, - unix_vkCreateRenderPass2KHR, - unix_vkCreateSampler, - unix_vkCreateSamplerYcbcrConversion, - unix_vkCreateSamplerYcbcrConversionKHR, - unix_vkCreateSemaphore, - unix_vkCreateShaderModule, - unix_vkCreateSwapchainKHR, - unix_vkCreateValidationCacheEXT, - unix_vkCreateWin32SurfaceKHR, - unix_vkDebugMarkerSetObjectNameEXT, - unix_vkDebugMarkerSetObjectTagEXT, - unix_vkDebugReportMessageEXT, - unix_vkDeferredOperationJoinKHR, - unix_vkDestroyAccelerationStructureKHR, - unix_vkDestroyAccelerationStructureNV, - unix_vkDestroyBuffer, - unix_vkDestroyBufferView, - unix_vkDestroyCommandPool, - unix_vkDestroyCuFunctionNVX, - unix_vkDestroyCuModuleNVX, - unix_vkDestroyDebugReportCallbackEXT, - unix_vkDestroyDebugUtilsMessengerEXT, - unix_vkDestroyDeferredOperationKHR, - unix_vkDestroyDescriptorPool, - unix_vkDestroyDescriptorSetLayout, - unix_vkDestroyDescriptorUpdateTemplate, - unix_vkDestroyDescriptorUpdateTemplateKHR, - unix_vkDestroyDevice, - unix_vkDestroyEvent, - unix_vkDestroyFence, - unix_vkDestroyFramebuffer, - unix_vkDestroyImage, - unix_vkDestroyImageView, - unix_vkDestroyIndirectCommandsLayoutNV, - unix_vkDestroyInstance, - unix_vkDestroyMicromapEXT, - unix_vkDestroyOpticalFlowSessionNV, - unix_vkDestroyPipeline, - unix_vkDestroyPipelineCache, - unix_vkDestroyPipelineLayout, - unix_vkDestroyPrivateDataSlot, - unix_vkDestroyPrivateDataSlotEXT, - unix_vkDestroyQueryPool, - unix_vkDestroyRenderPass, - unix_vkDestroySampler, - unix_vkDestroySamplerYcbcrConversion, - unix_vkDestroySamplerYcbcrConversionKHR, - unix_vkDestroySemaphore, - unix_vkDestroyShaderModule, - unix_vkDestroySurfaceKHR, - unix_vkDestroySwapchainKHR, - unix_vkDestroyValidationCacheEXT, - unix_vkDeviceWaitIdle, - unix_vkEndCommandBuffer, - unix_vkEnumerateDeviceExtensionProperties, - unix_vkEnumerateDeviceLayerProperties, - unix_vkEnumerateInstanceExtensionProperties, - unix_vkEnumerateInstanceVersion, - unix_vkEnumeratePhysicalDeviceGroups, - unix_vkEnumeratePhysicalDeviceGroupsKHR, - unix_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR, - unix_vkEnumeratePhysicalDevices, - unix_vkFlushMappedMemoryRanges, - unix_vkFreeCommandBuffers, - unix_vkFreeDescriptorSets, - unix_vkFreeMemory, - unix_vkGetAccelerationStructureBuildSizesKHR, - unix_vkGetAccelerationStructureDeviceAddressKHR, - unix_vkGetAccelerationStructureHandleNV, - unix_vkGetAccelerationStructureMemoryRequirementsNV, - unix_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT, - unix_vkGetBufferDeviceAddress, - unix_vkGetBufferDeviceAddressEXT, - unix_vkGetBufferDeviceAddressKHR, - unix_vkGetBufferMemoryRequirements, - unix_vkGetBufferMemoryRequirements2, - unix_vkGetBufferMemoryRequirements2KHR, - unix_vkGetBufferOpaqueCaptureAddress, - unix_vkGetBufferOpaqueCaptureAddressKHR, - unix_vkGetBufferOpaqueCaptureDescriptorDataEXT, - unix_vkGetCalibratedTimestampsEXT, - unix_vkGetDeferredOperationMaxConcurrencyKHR, - unix_vkGetDeferredOperationResultKHR, - unix_vkGetDescriptorEXT, - unix_vkGetDescriptorSetHostMappingVALVE, - unix_vkGetDescriptorSetLayoutBindingOffsetEXT, - unix_vkGetDescriptorSetLayoutHostMappingInfoVALVE, - unix_vkGetDescriptorSetLayoutSizeEXT, - unix_vkGetDescriptorSetLayoutSupport, - unix_vkGetDescriptorSetLayoutSupportKHR, - unix_vkGetDeviceAccelerationStructureCompatibilityKHR, - unix_vkGetDeviceBufferMemoryRequirements, - unix_vkGetDeviceBufferMemoryRequirementsKHR, - unix_vkGetDeviceFaultInfoEXT, - unix_vkGetDeviceGroupPeerMemoryFeatures, - unix_vkGetDeviceGroupPeerMemoryFeaturesKHR, - unix_vkGetDeviceGroupPresentCapabilitiesKHR, - unix_vkGetDeviceGroupSurfacePresentModesKHR, - unix_vkGetDeviceImageMemoryRequirements, - unix_vkGetDeviceImageMemoryRequirementsKHR, - unix_vkGetDeviceImageSparseMemoryRequirements, - unix_vkGetDeviceImageSparseMemoryRequirementsKHR, - unix_vkGetDeviceMemoryCommitment, - unix_vkGetDeviceMemoryOpaqueCaptureAddress, - unix_vkGetDeviceMemoryOpaqueCaptureAddressKHR, - unix_vkGetDeviceMicromapCompatibilityEXT, - unix_vkGetDeviceQueue, - unix_vkGetDeviceQueue2, - unix_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI, - unix_vkGetDynamicRenderingTilePropertiesQCOM, - unix_vkGetEventStatus, - unix_vkGetFenceStatus, - unix_vkGetFramebufferTilePropertiesQCOM, - unix_vkGetGeneratedCommandsMemoryRequirementsNV, - unix_vkGetImageMemoryRequirements, - unix_vkGetImageMemoryRequirements2, - unix_vkGetImageMemoryRequirements2KHR, - unix_vkGetImageOpaqueCaptureDescriptorDataEXT, - unix_vkGetImageSparseMemoryRequirements, - unix_vkGetImageSparseMemoryRequirements2, - unix_vkGetImageSparseMemoryRequirements2KHR, - unix_vkGetImageSubresourceLayout, - unix_vkGetImageSubresourceLayout2EXT, - unix_vkGetImageViewAddressNVX, - unix_vkGetImageViewHandleNVX, - unix_vkGetImageViewOpaqueCaptureDescriptorDataEXT, - unix_vkGetMemoryHostPointerPropertiesEXT, - unix_vkGetMicromapBuildSizesEXT, - unix_vkGetPerformanceParameterINTEL, - unix_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, - unix_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV, - unix_vkGetPhysicalDeviceExternalBufferProperties, - unix_vkGetPhysicalDeviceExternalBufferPropertiesKHR, - unix_vkGetPhysicalDeviceExternalFenceProperties, - unix_vkGetPhysicalDeviceExternalFencePropertiesKHR, - unix_vkGetPhysicalDeviceExternalSemaphoreProperties, - unix_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR, - unix_vkGetPhysicalDeviceFeatures, - unix_vkGetPhysicalDeviceFeatures2, - unix_vkGetPhysicalDeviceFeatures2KHR, - unix_vkGetPhysicalDeviceFormatProperties, - unix_vkGetPhysicalDeviceFormatProperties2, - unix_vkGetPhysicalDeviceFormatProperties2KHR, - unix_vkGetPhysicalDeviceFragmentShadingRatesKHR, - unix_vkGetPhysicalDeviceImageFormatProperties, - unix_vkGetPhysicalDeviceImageFormatProperties2, - unix_vkGetPhysicalDeviceImageFormatProperties2KHR, - unix_vkGetPhysicalDeviceMemoryProperties, - unix_vkGetPhysicalDeviceMemoryProperties2, - unix_vkGetPhysicalDeviceMemoryProperties2KHR, - unix_vkGetPhysicalDeviceMultisamplePropertiesEXT, - unix_vkGetPhysicalDeviceOpticalFlowImageFormatsNV, - unix_vkGetPhysicalDevicePresentRectanglesKHR, - unix_vkGetPhysicalDeviceProperties, - unix_vkGetPhysicalDeviceProperties2, - unix_vkGetPhysicalDeviceProperties2KHR, - unix_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR, - unix_vkGetPhysicalDeviceQueueFamilyProperties, - unix_vkGetPhysicalDeviceQueueFamilyProperties2, - unix_vkGetPhysicalDeviceQueueFamilyProperties2KHR, - unix_vkGetPhysicalDeviceSparseImageFormatProperties, - unix_vkGetPhysicalDeviceSparseImageFormatProperties2, - unix_vkGetPhysicalDeviceSparseImageFormatProperties2KHR, - unix_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV, - unix_vkGetPhysicalDeviceSurfaceCapabilities2KHR, - unix_vkGetPhysicalDeviceSurfaceCapabilitiesKHR, - unix_vkGetPhysicalDeviceSurfaceFormats2KHR, - unix_vkGetPhysicalDeviceSurfaceFormatsKHR, - unix_vkGetPhysicalDeviceSurfacePresentModesKHR, - unix_vkGetPhysicalDeviceSurfaceSupportKHR, - unix_vkGetPhysicalDeviceToolProperties, - unix_vkGetPhysicalDeviceToolPropertiesEXT, - unix_vkGetPhysicalDeviceWin32PresentationSupportKHR, - unix_vkGetPipelineCacheData, - unix_vkGetPipelineExecutableInternalRepresentationsKHR, - unix_vkGetPipelineExecutablePropertiesKHR, - unix_vkGetPipelineExecutableStatisticsKHR, - unix_vkGetPipelinePropertiesEXT, - unix_vkGetPrivateData, - unix_vkGetPrivateDataEXT, - unix_vkGetQueryPoolResults, - unix_vkGetQueueCheckpointData2NV, - unix_vkGetQueueCheckpointDataNV, - unix_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR, - unix_vkGetRayTracingShaderGroupHandlesKHR, - unix_vkGetRayTracingShaderGroupHandlesNV, - unix_vkGetRayTracingShaderGroupStackSizeKHR, - unix_vkGetRenderAreaGranularity, - unix_vkGetSamplerOpaqueCaptureDescriptorDataEXT, - unix_vkGetSemaphoreCounterValue, - unix_vkGetSemaphoreCounterValueKHR, - unix_vkGetShaderInfoAMD, - unix_vkGetShaderModuleCreateInfoIdentifierEXT, - unix_vkGetShaderModuleIdentifierEXT, - unix_vkGetSwapchainImagesKHR, - unix_vkGetValidationCacheDataEXT, - unix_vkInitializePerformanceApiINTEL, - unix_vkInvalidateMappedMemoryRanges, - unix_vkMapMemory, - unix_vkMergePipelineCaches, - unix_vkMergeValidationCachesEXT, - unix_vkQueueBeginDebugUtilsLabelEXT, - unix_vkQueueBindSparse, - unix_vkQueueEndDebugUtilsLabelEXT, - unix_vkQueueInsertDebugUtilsLabelEXT, - unix_vkQueuePresentKHR, - unix_vkQueueSetPerformanceConfigurationINTEL, - unix_vkQueueSubmit, - unix_vkQueueSubmit2, - unix_vkQueueSubmit2KHR, - unix_vkQueueWaitIdle, - unix_vkReleasePerformanceConfigurationINTEL, - unix_vkReleaseProfilingLockKHR, - unix_vkReleaseSwapchainImagesEXT, - unix_vkResetCommandBuffer, - unix_vkResetCommandPool, - unix_vkResetDescriptorPool, - unix_vkResetEvent, - unix_vkResetFences, - unix_vkResetQueryPool, - unix_vkResetQueryPoolEXT, - unix_vkSetDebugUtilsObjectNameEXT, - unix_vkSetDebugUtilsObjectTagEXT, - unix_vkSetDeviceMemoryPriorityEXT, - unix_vkSetEvent, - unix_vkSetPrivateData, - unix_vkSetPrivateDataEXT, - unix_vkSignalSemaphore, - unix_vkSignalSemaphoreKHR, - unix_vkSubmitDebugUtilsMessageEXT, - unix_vkTrimCommandPool, - unix_vkTrimCommandPoolKHR, - unix_vkUninitializePerformanceApiINTEL, - unix_vkUnmapMemory, - unix_vkUpdateDescriptorSetWithTemplate, - unix_vkUpdateDescriptorSetWithTemplateKHR, - unix_vkUpdateDescriptorSets, - unix_vkWaitForFences, - unix_vkWaitForPresentKHR, - unix_vkWaitSemaphores, - unix_vkWaitSemaphoresKHR, - unix_vkWriteAccelerationStructuresPropertiesKHR, - unix_vkWriteMicromapsPropertiesEXT, - unix_count, -}; - -struct vkAcquireNextImage2KHR_params -{ - VkDevice device; - const VkAcquireNextImageInfoKHR *pAcquireInfo; - uint32_t *pImageIndex; - VkResult result; -}; - -struct vkAcquireNextImageKHR_params -{ - VkDevice device; - VkSwapchainKHR DECLSPEC_ALIGN(8) swapchain; - uint64_t DECLSPEC_ALIGN(8) timeout; - VkSemaphore DECLSPEC_ALIGN(8) semaphore; - VkFence DECLSPEC_ALIGN(8) fence; - uint32_t *pImageIndex; - VkResult result; -}; - -struct vkAcquirePerformanceConfigurationINTEL_params -{ - VkDevice device; - const VkPerformanceConfigurationAcquireInfoINTEL *pAcquireInfo; - VkPerformanceConfigurationINTEL *pConfiguration; - VkResult result; -}; - -struct vkAcquireProfilingLockKHR_params -{ - VkDevice device; - const VkAcquireProfilingLockInfoKHR *pInfo; - VkResult result; -}; - -struct vkAllocateCommandBuffers_params -{ - VkDevice device; - const VkCommandBufferAllocateInfo *pAllocateInfo; - VkCommandBuffer *pCommandBuffers; - VkResult result; -}; - -struct vkAllocateDescriptorSets_params -{ - VkDevice device; - const VkDescriptorSetAllocateInfo *pAllocateInfo; - VkDescriptorSet *pDescriptorSets; - VkResult result; -}; - -struct vkAllocateMemory_params -{ - VkDevice device; - const VkMemoryAllocateInfo *pAllocateInfo; - const VkAllocationCallbacks *pAllocator; - VkDeviceMemory *pMemory; - VkResult result; -}; - -struct vkBeginCommandBuffer_params -{ - VkCommandBuffer commandBuffer; - const VkCommandBufferBeginInfo *pBeginInfo; - VkResult result; -}; - -struct vkBindAccelerationStructureMemoryNV_params -{ - VkDevice device; - uint32_t bindInfoCount; - const VkBindAccelerationStructureMemoryInfoNV *pBindInfos; - VkResult result; -}; - -struct vkBindBufferMemory_params -{ - VkDevice device; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - VkDeviceSize DECLSPEC_ALIGN(8) memoryOffset; - VkResult result; -}; - -struct vkBindBufferMemory2_params -{ - VkDevice device; - uint32_t bindInfoCount; - const VkBindBufferMemoryInfo *pBindInfos; - VkResult result; -}; - -struct vkBindBufferMemory2KHR_params -{ - VkDevice device; - uint32_t bindInfoCount; - const VkBindBufferMemoryInfo *pBindInfos; - VkResult result; -}; - -struct vkBindImageMemory_params -{ - VkDevice device; - VkImage DECLSPEC_ALIGN(8) image; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - VkDeviceSize DECLSPEC_ALIGN(8) memoryOffset; - VkResult result; -}; - -struct vkBindImageMemory2_params -{ - VkDevice device; - uint32_t bindInfoCount; - const VkBindImageMemoryInfo *pBindInfos; - VkResult result; -}; - -struct vkBindImageMemory2KHR_params -{ - VkDevice device; - uint32_t bindInfoCount; - const VkBindImageMemoryInfo *pBindInfos; - VkResult result; -}; - -struct vkBindOpticalFlowSessionImageNV_params -{ - VkDevice device; - VkOpticalFlowSessionNV DECLSPEC_ALIGN(8) session; - VkOpticalFlowSessionBindingPointNV bindingPoint; - VkImageView DECLSPEC_ALIGN(8) view; - VkImageLayout layout; - VkResult result; -}; - -struct vkBuildAccelerationStructuresKHR_params -{ - VkDevice device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - uint32_t infoCount; - const VkAccelerationStructureBuildGeometryInfoKHR *pInfos; - const VkAccelerationStructureBuildRangeInfoKHR * const*ppBuildRangeInfos; - VkResult result; -}; - -struct vkBuildMicromapsEXT_params -{ - VkDevice device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - uint32_t infoCount; - const VkMicromapBuildInfoEXT *pInfos; - VkResult result; -}; - -struct vkCmdBeginConditionalRenderingEXT_params -{ - VkCommandBuffer commandBuffer; - const VkConditionalRenderingBeginInfoEXT *pConditionalRenderingBegin; -}; - -struct vkCmdBeginDebugUtilsLabelEXT_params -{ - VkCommandBuffer commandBuffer; - const VkDebugUtilsLabelEXT *pLabelInfo; -}; - -struct vkCmdBeginQuery_params -{ - VkCommandBuffer commandBuffer; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t query; - VkQueryControlFlags flags; -}; - -struct vkCmdBeginQueryIndexedEXT_params -{ - VkCommandBuffer commandBuffer; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t query; - VkQueryControlFlags flags; - uint32_t index; -}; - -struct vkCmdBeginRenderPass_params -{ - VkCommandBuffer commandBuffer; - const VkRenderPassBeginInfo *pRenderPassBegin; - VkSubpassContents contents; -}; - -struct vkCmdBeginRenderPass2_params -{ - VkCommandBuffer commandBuffer; - const VkRenderPassBeginInfo *pRenderPassBegin; - const VkSubpassBeginInfo *pSubpassBeginInfo; -}; - -struct vkCmdBeginRenderPass2KHR_params -{ - VkCommandBuffer commandBuffer; - const VkRenderPassBeginInfo *pRenderPassBegin; - const VkSubpassBeginInfo *pSubpassBeginInfo; -}; - -struct vkCmdBeginRendering_params -{ - VkCommandBuffer commandBuffer; - const VkRenderingInfo *pRenderingInfo; -}; - -struct vkCmdBeginRenderingKHR_params -{ - VkCommandBuffer commandBuffer; - const VkRenderingInfo *pRenderingInfo; -}; - -struct vkCmdBeginTransformFeedbackEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t firstCounterBuffer; - uint32_t counterBufferCount; - const VkBuffer *pCounterBuffers; - const VkDeviceSize *pCounterBufferOffsets; -}; - -struct vkCmdBindDescriptorBufferEmbeddedSamplersEXT_params -{ - VkCommandBuffer commandBuffer; - VkPipelineBindPoint pipelineBindPoint; - VkPipelineLayout DECLSPEC_ALIGN(8) layout; - uint32_t set; -}; - -struct vkCmdBindDescriptorBuffersEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t bufferCount; - const VkDescriptorBufferBindingInfoEXT *pBindingInfos; -}; - -struct vkCmdBindDescriptorSets_params -{ - VkCommandBuffer commandBuffer; - VkPipelineBindPoint pipelineBindPoint; - VkPipelineLayout DECLSPEC_ALIGN(8) layout; - uint32_t firstSet; - uint32_t descriptorSetCount; - const VkDescriptorSet *pDescriptorSets; - uint32_t dynamicOffsetCount; - const uint32_t *pDynamicOffsets; -}; - -struct vkCmdBindIndexBuffer_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkIndexType indexType; -}; - -struct vkCmdBindInvocationMaskHUAWEI_params -{ - VkCommandBuffer commandBuffer; - VkImageView DECLSPEC_ALIGN(8) imageView; - VkImageLayout imageLayout; -}; - -struct vkCmdBindPipeline_params -{ - VkCommandBuffer commandBuffer; - VkPipelineBindPoint pipelineBindPoint; - VkPipeline DECLSPEC_ALIGN(8) pipeline; -}; - -struct vkCmdBindPipelineShaderGroupNV_params -{ - VkCommandBuffer commandBuffer; - VkPipelineBindPoint pipelineBindPoint; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - uint32_t groupIndex; -}; - -struct vkCmdBindShadingRateImageNV_params -{ - VkCommandBuffer commandBuffer; - VkImageView DECLSPEC_ALIGN(8) imageView; - VkImageLayout imageLayout; -}; - -struct vkCmdBindTransformFeedbackBuffersEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t firstBinding; - uint32_t bindingCount; - const VkBuffer *pBuffers; - const VkDeviceSize *pOffsets; - const VkDeviceSize *pSizes; -}; - -struct vkCmdBindVertexBuffers_params -{ - VkCommandBuffer commandBuffer; - uint32_t firstBinding; - uint32_t bindingCount; - const VkBuffer *pBuffers; - const VkDeviceSize *pOffsets; -}; - -struct vkCmdBindVertexBuffers2_params -{ - VkCommandBuffer commandBuffer; - uint32_t firstBinding; - uint32_t bindingCount; - const VkBuffer *pBuffers; - const VkDeviceSize *pOffsets; - const VkDeviceSize *pSizes; - const VkDeviceSize *pStrides; -}; - -struct vkCmdBindVertexBuffers2EXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t firstBinding; - uint32_t bindingCount; - const VkBuffer *pBuffers; - const VkDeviceSize *pOffsets; - const VkDeviceSize *pSizes; - const VkDeviceSize *pStrides; -}; - -struct vkCmdBlitImage_params -{ - VkCommandBuffer commandBuffer; - VkImage DECLSPEC_ALIGN(8) srcImage; - VkImageLayout srcImageLayout; - VkImage DECLSPEC_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - const VkImageBlit *pRegions; - VkFilter filter; -}; - -struct vkCmdBlitImage2_params -{ - VkCommandBuffer commandBuffer; - const VkBlitImageInfo2 *pBlitImageInfo; -}; - -struct vkCmdBlitImage2KHR_params -{ - VkCommandBuffer commandBuffer; - const VkBlitImageInfo2 *pBlitImageInfo; -}; - -struct vkCmdBuildAccelerationStructureNV_params -{ - VkCommandBuffer commandBuffer; - const VkAccelerationStructureInfoNV *pInfo; - VkBuffer DECLSPEC_ALIGN(8) instanceData; - VkDeviceSize DECLSPEC_ALIGN(8) instanceOffset; - VkBool32 update; - VkAccelerationStructureNV DECLSPEC_ALIGN(8) dst; - VkAccelerationStructureNV DECLSPEC_ALIGN(8) src; - VkBuffer DECLSPEC_ALIGN(8) scratch; - VkDeviceSize DECLSPEC_ALIGN(8) scratchOffset; -}; - -struct vkCmdBuildAccelerationStructuresIndirectKHR_params -{ - VkCommandBuffer commandBuffer; - uint32_t infoCount; - const VkAccelerationStructureBuildGeometryInfoKHR *pInfos; - const VkDeviceAddress *pIndirectDeviceAddresses; - const uint32_t *pIndirectStrides; - const uint32_t * const*ppMaxPrimitiveCounts; -}; - -struct vkCmdBuildAccelerationStructuresKHR_params -{ - VkCommandBuffer commandBuffer; - uint32_t infoCount; - const VkAccelerationStructureBuildGeometryInfoKHR *pInfos; - const VkAccelerationStructureBuildRangeInfoKHR * const*ppBuildRangeInfos; -}; - -struct vkCmdBuildMicromapsEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t infoCount; - const VkMicromapBuildInfoEXT *pInfos; -}; - -struct vkCmdClearAttachments_params -{ - VkCommandBuffer commandBuffer; - uint32_t attachmentCount; - const VkClearAttachment *pAttachments; - uint32_t rectCount; - const VkClearRect *pRects; -}; - -struct vkCmdClearColorImage_params -{ - VkCommandBuffer commandBuffer; - VkImage DECLSPEC_ALIGN(8) image; - VkImageLayout imageLayout; - const VkClearColorValue *pColor; - uint32_t rangeCount; - const VkImageSubresourceRange *pRanges; -}; - -struct vkCmdClearDepthStencilImage_params -{ - VkCommandBuffer commandBuffer; - VkImage DECLSPEC_ALIGN(8) image; - VkImageLayout imageLayout; - const VkClearDepthStencilValue *pDepthStencil; - uint32_t rangeCount; - const VkImageSubresourceRange *pRanges; -}; - -struct vkCmdCopyAccelerationStructureKHR_params -{ - VkCommandBuffer commandBuffer; - const VkCopyAccelerationStructureInfoKHR *pInfo; -}; - -struct vkCmdCopyAccelerationStructureNV_params -{ - VkCommandBuffer commandBuffer; - VkAccelerationStructureNV DECLSPEC_ALIGN(8) dst; - VkAccelerationStructureNV DECLSPEC_ALIGN(8) src; - VkCopyAccelerationStructureModeKHR mode; -}; - -struct vkCmdCopyAccelerationStructureToMemoryKHR_params -{ - VkCommandBuffer commandBuffer; - const VkCopyAccelerationStructureToMemoryInfoKHR *pInfo; -}; - -struct vkCmdCopyBuffer_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) srcBuffer; - VkBuffer DECLSPEC_ALIGN(8) dstBuffer; - uint32_t regionCount; - const VkBufferCopy *pRegions; -}; - -struct vkCmdCopyBuffer2_params -{ - VkCommandBuffer commandBuffer; - const VkCopyBufferInfo2 *pCopyBufferInfo; -}; - -struct vkCmdCopyBuffer2KHR_params -{ - VkCommandBuffer commandBuffer; - const VkCopyBufferInfo2 *pCopyBufferInfo; -}; - -struct vkCmdCopyBufferToImage_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) srcBuffer; - VkImage DECLSPEC_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - const VkBufferImageCopy *pRegions; -}; - -struct vkCmdCopyBufferToImage2_params -{ - VkCommandBuffer commandBuffer; - const VkCopyBufferToImageInfo2 *pCopyBufferToImageInfo; -}; - -struct vkCmdCopyBufferToImage2KHR_params -{ - VkCommandBuffer commandBuffer; - const VkCopyBufferToImageInfo2 *pCopyBufferToImageInfo; -}; - -struct vkCmdCopyImage_params -{ - VkCommandBuffer commandBuffer; - VkImage DECLSPEC_ALIGN(8) srcImage; - VkImageLayout srcImageLayout; - VkImage DECLSPEC_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - const VkImageCopy *pRegions; -}; - -struct vkCmdCopyImage2_params -{ - VkCommandBuffer commandBuffer; - const VkCopyImageInfo2 *pCopyImageInfo; -}; - -struct vkCmdCopyImage2KHR_params -{ - VkCommandBuffer commandBuffer; - const VkCopyImageInfo2 *pCopyImageInfo; -}; - -struct vkCmdCopyImageToBuffer_params -{ - VkCommandBuffer commandBuffer; - VkImage DECLSPEC_ALIGN(8) srcImage; - VkImageLayout srcImageLayout; - VkBuffer DECLSPEC_ALIGN(8) dstBuffer; - uint32_t regionCount; - const VkBufferImageCopy *pRegions; -}; - -struct vkCmdCopyImageToBuffer2_params -{ - VkCommandBuffer commandBuffer; - const VkCopyImageToBufferInfo2 *pCopyImageToBufferInfo; -}; - -struct vkCmdCopyImageToBuffer2KHR_params -{ - VkCommandBuffer commandBuffer; - const VkCopyImageToBufferInfo2 *pCopyImageToBufferInfo; -}; - -struct vkCmdCopyMemoryIndirectNV_params -{ - VkCommandBuffer commandBuffer; - VkDeviceAddress DECLSPEC_ALIGN(8) copyBufferAddress; - uint32_t copyCount; - uint32_t stride; -}; - -struct vkCmdCopyMemoryToAccelerationStructureKHR_params -{ - VkCommandBuffer commandBuffer; - const VkCopyMemoryToAccelerationStructureInfoKHR *pInfo; -}; - -struct vkCmdCopyMemoryToImageIndirectNV_params -{ - VkCommandBuffer commandBuffer; - VkDeviceAddress DECLSPEC_ALIGN(8) copyBufferAddress; - uint32_t copyCount; - uint32_t stride; - VkImage DECLSPEC_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - const VkImageSubresourceLayers *pImageSubresources; -}; - -struct vkCmdCopyMemoryToMicromapEXT_params -{ - VkCommandBuffer commandBuffer; - const VkCopyMemoryToMicromapInfoEXT *pInfo; -}; - -struct vkCmdCopyMicromapEXT_params -{ - VkCommandBuffer commandBuffer; - const VkCopyMicromapInfoEXT *pInfo; -}; - -struct vkCmdCopyMicromapToMemoryEXT_params -{ - VkCommandBuffer commandBuffer; - const VkCopyMicromapToMemoryInfoEXT *pInfo; -}; - -struct vkCmdCopyQueryPoolResults_params -{ - VkCommandBuffer commandBuffer; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t firstQuery; - uint32_t queryCount; - VkBuffer DECLSPEC_ALIGN(8) dstBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) dstOffset; - VkDeviceSize DECLSPEC_ALIGN(8) stride; - VkQueryResultFlags flags; -}; - -struct vkCmdCuLaunchKernelNVX_params -{ - VkCommandBuffer commandBuffer; - const VkCuLaunchInfoNVX *pLaunchInfo; -}; - -struct vkCmdDebugMarkerBeginEXT_params -{ - VkCommandBuffer commandBuffer; - const VkDebugMarkerMarkerInfoEXT *pMarkerInfo; -}; - -struct vkCmdDebugMarkerEndEXT_params -{ - VkCommandBuffer commandBuffer; -}; - -struct vkCmdDebugMarkerInsertEXT_params -{ - VkCommandBuffer commandBuffer; - const VkDebugMarkerMarkerInfoEXT *pMarkerInfo; -}; - -struct vkCmdDecompressMemoryIndirectCountNV_params -{ - VkCommandBuffer commandBuffer; - VkDeviceAddress DECLSPEC_ALIGN(8) indirectCommandsAddress; - VkDeviceAddress DECLSPEC_ALIGN(8) indirectCommandsCountAddress; - uint32_t stride; -}; - -struct vkCmdDecompressMemoryNV_params -{ - VkCommandBuffer commandBuffer; - uint32_t decompressRegionCount; - const VkDecompressMemoryRegionNV *pDecompressMemoryRegions; -}; - -struct vkCmdDispatch_params -{ - VkCommandBuffer commandBuffer; - uint32_t groupCountX; - uint32_t groupCountY; - uint32_t groupCountZ; -}; - -struct vkCmdDispatchBase_params -{ - VkCommandBuffer commandBuffer; - uint32_t baseGroupX; - uint32_t baseGroupY; - uint32_t baseGroupZ; - uint32_t groupCountX; - uint32_t groupCountY; - uint32_t groupCountZ; -}; - -struct vkCmdDispatchBaseKHR_params -{ - VkCommandBuffer commandBuffer; - uint32_t baseGroupX; - uint32_t baseGroupY; - uint32_t baseGroupZ; - uint32_t groupCountX; - uint32_t groupCountY; - uint32_t groupCountZ; -}; - -struct vkCmdDispatchIndirect_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; -}; - -struct vkCmdDraw_params -{ - VkCommandBuffer commandBuffer; - uint32_t vertexCount; - uint32_t instanceCount; - uint32_t firstVertex; - uint32_t firstInstance; -}; - -struct vkCmdDrawIndexed_params -{ - VkCommandBuffer commandBuffer; - uint32_t indexCount; - uint32_t instanceCount; - uint32_t firstIndex; - int32_t vertexOffset; - uint32_t firstInstance; -}; - -struct vkCmdDrawIndexedIndirect_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - uint32_t drawCount; - uint32_t stride; -}; - -struct vkCmdDrawIndexedIndirectCount_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkBuffer DECLSPEC_ALIGN(8) countBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) countBufferOffset; - uint32_t maxDrawCount; - uint32_t stride; -}; - -struct vkCmdDrawIndexedIndirectCountAMD_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkBuffer DECLSPEC_ALIGN(8) countBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) countBufferOffset; - uint32_t maxDrawCount; - uint32_t stride; -}; - -struct vkCmdDrawIndexedIndirectCountKHR_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkBuffer DECLSPEC_ALIGN(8) countBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) countBufferOffset; - uint32_t maxDrawCount; - uint32_t stride; -}; - -struct vkCmdDrawIndirect_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - uint32_t drawCount; - uint32_t stride; -}; - -struct vkCmdDrawIndirectByteCountEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t instanceCount; - uint32_t firstInstance; - VkBuffer DECLSPEC_ALIGN(8) counterBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) counterBufferOffset; - uint32_t counterOffset; - uint32_t vertexStride; -}; - -struct vkCmdDrawIndirectCount_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkBuffer DECLSPEC_ALIGN(8) countBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) countBufferOffset; - uint32_t maxDrawCount; - uint32_t stride; -}; - -struct vkCmdDrawIndirectCountAMD_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkBuffer DECLSPEC_ALIGN(8) countBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) countBufferOffset; - uint32_t maxDrawCount; - uint32_t stride; -}; - -struct vkCmdDrawIndirectCountKHR_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkBuffer DECLSPEC_ALIGN(8) countBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) countBufferOffset; - uint32_t maxDrawCount; - uint32_t stride; -}; - -struct vkCmdDrawMeshTasksEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t groupCountX; - uint32_t groupCountY; - uint32_t groupCountZ; -}; - -struct vkCmdDrawMeshTasksIndirectCountEXT_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkBuffer DECLSPEC_ALIGN(8) countBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) countBufferOffset; - uint32_t maxDrawCount; - uint32_t stride; -}; - -struct vkCmdDrawMeshTasksIndirectCountNV_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkBuffer DECLSPEC_ALIGN(8) countBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) countBufferOffset; - uint32_t maxDrawCount; - uint32_t stride; -}; - -struct vkCmdDrawMeshTasksIndirectEXT_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - uint32_t drawCount; - uint32_t stride; -}; - -struct vkCmdDrawMeshTasksIndirectNV_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - uint32_t drawCount; - uint32_t stride; -}; - -struct vkCmdDrawMeshTasksNV_params -{ - VkCommandBuffer commandBuffer; - uint32_t taskCount; - uint32_t firstTask; -}; - -struct vkCmdDrawMultiEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t drawCount; - const VkMultiDrawInfoEXT *pVertexInfo; - uint32_t instanceCount; - uint32_t firstInstance; - uint32_t stride; -}; - -struct vkCmdDrawMultiIndexedEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t drawCount; - const VkMultiDrawIndexedInfoEXT *pIndexInfo; - uint32_t instanceCount; - uint32_t firstInstance; - uint32_t stride; - const int32_t *pVertexOffset; -}; - -struct vkCmdEndConditionalRenderingEXT_params -{ - VkCommandBuffer commandBuffer; -}; - -struct vkCmdEndDebugUtilsLabelEXT_params -{ - VkCommandBuffer commandBuffer; -}; - -struct vkCmdEndQuery_params -{ - VkCommandBuffer commandBuffer; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t query; -}; - -struct vkCmdEndQueryIndexedEXT_params -{ - VkCommandBuffer commandBuffer; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t query; - uint32_t index; -}; - -struct vkCmdEndRenderPass_params -{ - VkCommandBuffer commandBuffer; -}; - -struct vkCmdEndRenderPass2_params -{ - VkCommandBuffer commandBuffer; - const VkSubpassEndInfo *pSubpassEndInfo; -}; - -struct vkCmdEndRenderPass2KHR_params -{ - VkCommandBuffer commandBuffer; - const VkSubpassEndInfo *pSubpassEndInfo; -}; - -struct vkCmdEndRendering_params -{ - VkCommandBuffer commandBuffer; -}; - -struct vkCmdEndRenderingKHR_params -{ - VkCommandBuffer commandBuffer; -}; - -struct vkCmdEndTransformFeedbackEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t firstCounterBuffer; - uint32_t counterBufferCount; - const VkBuffer *pCounterBuffers; - const VkDeviceSize *pCounterBufferOffsets; -}; - -struct vkCmdExecuteCommands_params -{ - VkCommandBuffer commandBuffer; - uint32_t commandBufferCount; - const VkCommandBuffer *pCommandBuffers; -}; - -struct vkCmdExecuteGeneratedCommandsNV_params -{ - VkCommandBuffer commandBuffer; - VkBool32 isPreprocessed; - const VkGeneratedCommandsInfoNV *pGeneratedCommandsInfo; -}; - -struct vkCmdFillBuffer_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) dstBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) dstOffset; - VkDeviceSize DECLSPEC_ALIGN(8) size; - uint32_t data; -}; - -struct vkCmdInsertDebugUtilsLabelEXT_params -{ - VkCommandBuffer commandBuffer; - const VkDebugUtilsLabelEXT *pLabelInfo; -}; - -struct vkCmdNextSubpass_params -{ - VkCommandBuffer commandBuffer; - VkSubpassContents contents; -}; - -struct vkCmdNextSubpass2_params -{ - VkCommandBuffer commandBuffer; - const VkSubpassBeginInfo *pSubpassBeginInfo; - const VkSubpassEndInfo *pSubpassEndInfo; -}; - -struct vkCmdNextSubpass2KHR_params -{ - VkCommandBuffer commandBuffer; - const VkSubpassBeginInfo *pSubpassBeginInfo; - const VkSubpassEndInfo *pSubpassEndInfo; -}; - -struct vkCmdOpticalFlowExecuteNV_params -{ - VkCommandBuffer commandBuffer; - VkOpticalFlowSessionNV DECLSPEC_ALIGN(8) session; - const VkOpticalFlowExecuteInfoNV *pExecuteInfo; -}; - -struct vkCmdPipelineBarrier_params -{ - VkCommandBuffer commandBuffer; - VkPipelineStageFlags srcStageMask; - VkPipelineStageFlags dstStageMask; - VkDependencyFlags dependencyFlags; - uint32_t memoryBarrierCount; - const VkMemoryBarrier *pMemoryBarriers; - uint32_t bufferMemoryBarrierCount; - const VkBufferMemoryBarrier *pBufferMemoryBarriers; - uint32_t imageMemoryBarrierCount; - const VkImageMemoryBarrier *pImageMemoryBarriers; -}; - -struct vkCmdPipelineBarrier2_params -{ - VkCommandBuffer commandBuffer; - const VkDependencyInfo *pDependencyInfo; -}; - -struct vkCmdPipelineBarrier2KHR_params -{ - VkCommandBuffer commandBuffer; - const VkDependencyInfo *pDependencyInfo; -}; - -struct vkCmdPreprocessGeneratedCommandsNV_params -{ - VkCommandBuffer commandBuffer; - const VkGeneratedCommandsInfoNV *pGeneratedCommandsInfo; -}; - -struct vkCmdPushConstants_params -{ - VkCommandBuffer commandBuffer; - VkPipelineLayout DECLSPEC_ALIGN(8) layout; - VkShaderStageFlags stageFlags; - uint32_t offset; - uint32_t size; - const void *pValues; -}; - -struct vkCmdPushDescriptorSetKHR_params -{ - VkCommandBuffer commandBuffer; - VkPipelineBindPoint pipelineBindPoint; - VkPipelineLayout DECLSPEC_ALIGN(8) layout; - uint32_t set; - uint32_t descriptorWriteCount; - const VkWriteDescriptorSet *pDescriptorWrites; -}; - -struct vkCmdPushDescriptorSetWithTemplateKHR_params -{ - VkCommandBuffer commandBuffer; - VkDescriptorUpdateTemplate DECLSPEC_ALIGN(8) descriptorUpdateTemplate; - VkPipelineLayout DECLSPEC_ALIGN(8) layout; - uint32_t set; - const void *pData; -}; - -struct vkCmdResetEvent_params -{ - VkCommandBuffer commandBuffer; - VkEvent DECLSPEC_ALIGN(8) event; - VkPipelineStageFlags stageMask; -}; - -struct vkCmdResetEvent2_params -{ - VkCommandBuffer commandBuffer; - VkEvent DECLSPEC_ALIGN(8) event; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) stageMask; -}; - -struct vkCmdResetEvent2KHR_params -{ - VkCommandBuffer commandBuffer; - VkEvent DECLSPEC_ALIGN(8) event; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) stageMask; -}; - -struct vkCmdResetQueryPool_params -{ - VkCommandBuffer commandBuffer; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t firstQuery; - uint32_t queryCount; -}; - -struct vkCmdResolveImage_params -{ - VkCommandBuffer commandBuffer; - VkImage DECLSPEC_ALIGN(8) srcImage; - VkImageLayout srcImageLayout; - VkImage DECLSPEC_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - const VkImageResolve *pRegions; -}; - -struct vkCmdResolveImage2_params -{ - VkCommandBuffer commandBuffer; - const VkResolveImageInfo2 *pResolveImageInfo; -}; - -struct vkCmdResolveImage2KHR_params -{ - VkCommandBuffer commandBuffer; - const VkResolveImageInfo2 *pResolveImageInfo; -}; - -struct vkCmdSetAlphaToCoverageEnableEXT_params -{ - VkCommandBuffer commandBuffer; - VkBool32 alphaToCoverageEnable; -}; - -struct vkCmdSetAlphaToOneEnableEXT_params -{ - VkCommandBuffer commandBuffer; - VkBool32 alphaToOneEnable; -}; - -struct vkCmdSetBlendConstants_params -{ - VkCommandBuffer commandBuffer; - const float *blendConstants; -}; - -struct vkCmdSetCheckpointNV_params -{ - VkCommandBuffer commandBuffer; - const void *pCheckpointMarker; -}; - -struct vkCmdSetCoarseSampleOrderNV_params -{ - VkCommandBuffer commandBuffer; - VkCoarseSampleOrderTypeNV sampleOrderType; - uint32_t customSampleOrderCount; - const VkCoarseSampleOrderCustomNV *pCustomSampleOrders; -}; - -struct vkCmdSetColorBlendAdvancedEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t firstAttachment; - uint32_t attachmentCount; - const VkColorBlendAdvancedEXT *pColorBlendAdvanced; -}; - -struct vkCmdSetColorBlendEnableEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t firstAttachment; - uint32_t attachmentCount; - const VkBool32 *pColorBlendEnables; -}; - -struct vkCmdSetColorBlendEquationEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t firstAttachment; - uint32_t attachmentCount; - const VkColorBlendEquationEXT *pColorBlendEquations; -}; - -struct vkCmdSetColorWriteEnableEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t attachmentCount; - const VkBool32 *pColorWriteEnables; -}; - -struct vkCmdSetColorWriteMaskEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t firstAttachment; - uint32_t attachmentCount; - const VkColorComponentFlags *pColorWriteMasks; -}; - -struct vkCmdSetConservativeRasterizationModeEXT_params -{ - VkCommandBuffer commandBuffer; - VkConservativeRasterizationModeEXT conservativeRasterizationMode; -}; - -struct vkCmdSetCoverageModulationModeNV_params -{ - VkCommandBuffer commandBuffer; - VkCoverageModulationModeNV coverageModulationMode; -}; - -struct vkCmdSetCoverageModulationTableEnableNV_params -{ - VkCommandBuffer commandBuffer; - VkBool32 coverageModulationTableEnable; -}; - -struct vkCmdSetCoverageModulationTableNV_params -{ - VkCommandBuffer commandBuffer; - uint32_t coverageModulationTableCount; - const float *pCoverageModulationTable; -}; - -struct vkCmdSetCoverageReductionModeNV_params -{ - VkCommandBuffer commandBuffer; - VkCoverageReductionModeNV coverageReductionMode; -}; - -struct vkCmdSetCoverageToColorEnableNV_params -{ - VkCommandBuffer commandBuffer; - VkBool32 coverageToColorEnable; -}; - -struct vkCmdSetCoverageToColorLocationNV_params -{ - VkCommandBuffer commandBuffer; - uint32_t coverageToColorLocation; -}; - -struct vkCmdSetCullMode_params -{ - VkCommandBuffer commandBuffer; - VkCullModeFlags cullMode; -}; - -struct vkCmdSetCullModeEXT_params -{ - VkCommandBuffer commandBuffer; - VkCullModeFlags cullMode; -}; - -struct vkCmdSetDepthBias_params -{ - VkCommandBuffer commandBuffer; - float depthBiasConstantFactor; - float depthBiasClamp; - float depthBiasSlopeFactor; -}; - -struct vkCmdSetDepthBiasEnable_params -{ - VkCommandBuffer commandBuffer; - VkBool32 depthBiasEnable; -}; - -struct vkCmdSetDepthBiasEnableEXT_params -{ - VkCommandBuffer commandBuffer; - VkBool32 depthBiasEnable; -}; - -struct vkCmdSetDepthBounds_params -{ - VkCommandBuffer commandBuffer; - float minDepthBounds; - float maxDepthBounds; -}; - -struct vkCmdSetDepthBoundsTestEnable_params -{ - VkCommandBuffer commandBuffer; - VkBool32 depthBoundsTestEnable; -}; - -struct vkCmdSetDepthBoundsTestEnableEXT_params -{ - VkCommandBuffer commandBuffer; - VkBool32 depthBoundsTestEnable; -}; - -struct vkCmdSetDepthClampEnableEXT_params -{ - VkCommandBuffer commandBuffer; - VkBool32 depthClampEnable; -}; - -struct vkCmdSetDepthClipEnableEXT_params -{ - VkCommandBuffer commandBuffer; - VkBool32 depthClipEnable; -}; - -struct vkCmdSetDepthClipNegativeOneToOneEXT_params -{ - VkCommandBuffer commandBuffer; - VkBool32 negativeOneToOne; -}; - -struct vkCmdSetDepthCompareOp_params -{ - VkCommandBuffer commandBuffer; - VkCompareOp depthCompareOp; -}; - -struct vkCmdSetDepthCompareOpEXT_params -{ - VkCommandBuffer commandBuffer; - VkCompareOp depthCompareOp; -}; - -struct vkCmdSetDepthTestEnable_params -{ - VkCommandBuffer commandBuffer; - VkBool32 depthTestEnable; -}; - -struct vkCmdSetDepthTestEnableEXT_params -{ - VkCommandBuffer commandBuffer; - VkBool32 depthTestEnable; -}; - -struct vkCmdSetDepthWriteEnable_params -{ - VkCommandBuffer commandBuffer; - VkBool32 depthWriteEnable; -}; - -struct vkCmdSetDepthWriteEnableEXT_params -{ - VkCommandBuffer commandBuffer; - VkBool32 depthWriteEnable; -}; - -struct vkCmdSetDescriptorBufferOffsetsEXT_params -{ - VkCommandBuffer commandBuffer; - VkPipelineBindPoint pipelineBindPoint; - VkPipelineLayout DECLSPEC_ALIGN(8) layout; - uint32_t firstSet; - uint32_t setCount; - const uint32_t *pBufferIndices; - const VkDeviceSize *pOffsets; -}; - -struct vkCmdSetDeviceMask_params -{ - VkCommandBuffer commandBuffer; - uint32_t deviceMask; -}; - -struct vkCmdSetDeviceMaskKHR_params -{ - VkCommandBuffer commandBuffer; - uint32_t deviceMask; -}; - -struct vkCmdSetDiscardRectangleEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t firstDiscardRectangle; - uint32_t discardRectangleCount; - const VkRect2D *pDiscardRectangles; -}; - -struct vkCmdSetEvent_params -{ - VkCommandBuffer commandBuffer; - VkEvent DECLSPEC_ALIGN(8) event; - VkPipelineStageFlags stageMask; -}; - -struct vkCmdSetEvent2_params -{ - VkCommandBuffer commandBuffer; - VkEvent DECLSPEC_ALIGN(8) event; - const VkDependencyInfo *pDependencyInfo; -}; - -struct vkCmdSetEvent2KHR_params -{ - VkCommandBuffer commandBuffer; - VkEvent DECLSPEC_ALIGN(8) event; - const VkDependencyInfo *pDependencyInfo; -}; - -struct vkCmdSetExclusiveScissorNV_params -{ - VkCommandBuffer commandBuffer; - uint32_t firstExclusiveScissor; - uint32_t exclusiveScissorCount; - const VkRect2D *pExclusiveScissors; -}; - -struct vkCmdSetExtraPrimitiveOverestimationSizeEXT_params -{ - VkCommandBuffer commandBuffer; - float extraPrimitiveOverestimationSize; -}; - -struct vkCmdSetFragmentShadingRateEnumNV_params -{ - VkCommandBuffer commandBuffer; - VkFragmentShadingRateNV shadingRate; - const VkFragmentShadingRateCombinerOpKHR *combinerOps; -}; - -struct vkCmdSetFragmentShadingRateKHR_params -{ - VkCommandBuffer commandBuffer; - const VkExtent2D *pFragmentSize; - const VkFragmentShadingRateCombinerOpKHR *combinerOps; -}; - -struct vkCmdSetFrontFace_params -{ - VkCommandBuffer commandBuffer; - VkFrontFace frontFace; -}; - -struct vkCmdSetFrontFaceEXT_params -{ - VkCommandBuffer commandBuffer; - VkFrontFace frontFace; -}; - -struct vkCmdSetLineRasterizationModeEXT_params -{ - VkCommandBuffer commandBuffer; - VkLineRasterizationModeEXT lineRasterizationMode; -}; - -struct vkCmdSetLineStippleEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t lineStippleFactor; - uint16_t lineStipplePattern; -}; - -struct vkCmdSetLineStippleEnableEXT_params -{ - VkCommandBuffer commandBuffer; - VkBool32 stippledLineEnable; -}; - -struct vkCmdSetLineWidth_params -{ - VkCommandBuffer commandBuffer; - float lineWidth; -}; - -struct vkCmdSetLogicOpEXT_params -{ - VkCommandBuffer commandBuffer; - VkLogicOp logicOp; -}; - -struct vkCmdSetLogicOpEnableEXT_params -{ - VkCommandBuffer commandBuffer; - VkBool32 logicOpEnable; -}; - -struct vkCmdSetPatchControlPointsEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t patchControlPoints; -}; - -struct vkCmdSetPerformanceMarkerINTEL_params -{ - VkCommandBuffer commandBuffer; - const VkPerformanceMarkerInfoINTEL *pMarkerInfo; - VkResult result; -}; - -struct vkCmdSetPerformanceOverrideINTEL_params -{ - VkCommandBuffer commandBuffer; - const VkPerformanceOverrideInfoINTEL *pOverrideInfo; - VkResult result; -}; - -struct vkCmdSetPerformanceStreamMarkerINTEL_params -{ - VkCommandBuffer commandBuffer; - const VkPerformanceStreamMarkerInfoINTEL *pMarkerInfo; - VkResult result; -}; - -struct vkCmdSetPolygonModeEXT_params -{ - VkCommandBuffer commandBuffer; - VkPolygonMode polygonMode; -}; - -struct vkCmdSetPrimitiveRestartEnable_params -{ - VkCommandBuffer commandBuffer; - VkBool32 primitiveRestartEnable; -}; - -struct vkCmdSetPrimitiveRestartEnableEXT_params -{ - VkCommandBuffer commandBuffer; - VkBool32 primitiveRestartEnable; -}; - -struct vkCmdSetPrimitiveTopology_params -{ - VkCommandBuffer commandBuffer; - VkPrimitiveTopology primitiveTopology; -}; - -struct vkCmdSetPrimitiveTopologyEXT_params -{ - VkCommandBuffer commandBuffer; - VkPrimitiveTopology primitiveTopology; -}; - -struct vkCmdSetProvokingVertexModeEXT_params -{ - VkCommandBuffer commandBuffer; - VkProvokingVertexModeEXT provokingVertexMode; -}; - -struct vkCmdSetRasterizationSamplesEXT_params -{ - VkCommandBuffer commandBuffer; - VkSampleCountFlagBits rasterizationSamples; -}; - -struct vkCmdSetRasterizationStreamEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t rasterizationStream; -}; - -struct vkCmdSetRasterizerDiscardEnable_params -{ - VkCommandBuffer commandBuffer; - VkBool32 rasterizerDiscardEnable; -}; - -struct vkCmdSetRasterizerDiscardEnableEXT_params -{ - VkCommandBuffer commandBuffer; - VkBool32 rasterizerDiscardEnable; -}; - -struct vkCmdSetRayTracingPipelineStackSizeKHR_params -{ - VkCommandBuffer commandBuffer; - uint32_t pipelineStackSize; -}; - -struct vkCmdSetRepresentativeFragmentTestEnableNV_params -{ - VkCommandBuffer commandBuffer; - VkBool32 representativeFragmentTestEnable; -}; - -struct vkCmdSetSampleLocationsEXT_params -{ - VkCommandBuffer commandBuffer; - const VkSampleLocationsInfoEXT *pSampleLocationsInfo; -}; - -struct vkCmdSetSampleLocationsEnableEXT_params -{ - VkCommandBuffer commandBuffer; - VkBool32 sampleLocationsEnable; -}; - -struct vkCmdSetSampleMaskEXT_params -{ - VkCommandBuffer commandBuffer; - VkSampleCountFlagBits samples; - const VkSampleMask *pSampleMask; -}; - -struct vkCmdSetScissor_params -{ - VkCommandBuffer commandBuffer; - uint32_t firstScissor; - uint32_t scissorCount; - const VkRect2D *pScissors; -}; - -struct vkCmdSetScissorWithCount_params -{ - VkCommandBuffer commandBuffer; - uint32_t scissorCount; - const VkRect2D *pScissors; -}; - -struct vkCmdSetScissorWithCountEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t scissorCount; - const VkRect2D *pScissors; -}; - -struct vkCmdSetShadingRateImageEnableNV_params -{ - VkCommandBuffer commandBuffer; - VkBool32 shadingRateImageEnable; -}; - -struct vkCmdSetStencilCompareMask_params -{ - VkCommandBuffer commandBuffer; - VkStencilFaceFlags faceMask; - uint32_t compareMask; -}; - -struct vkCmdSetStencilOp_params -{ - VkCommandBuffer commandBuffer; - VkStencilFaceFlags faceMask; - VkStencilOp failOp; - VkStencilOp passOp; - VkStencilOp depthFailOp; - VkCompareOp compareOp; -}; - -struct vkCmdSetStencilOpEXT_params -{ - VkCommandBuffer commandBuffer; - VkStencilFaceFlags faceMask; - VkStencilOp failOp; - VkStencilOp passOp; - VkStencilOp depthFailOp; - VkCompareOp compareOp; -}; - -struct vkCmdSetStencilReference_params -{ - VkCommandBuffer commandBuffer; - VkStencilFaceFlags faceMask; - uint32_t reference; -}; - -struct vkCmdSetStencilTestEnable_params -{ - VkCommandBuffer commandBuffer; - VkBool32 stencilTestEnable; -}; - -struct vkCmdSetStencilTestEnableEXT_params -{ - VkCommandBuffer commandBuffer; - VkBool32 stencilTestEnable; -}; - -struct vkCmdSetStencilWriteMask_params -{ - VkCommandBuffer commandBuffer; - VkStencilFaceFlags faceMask; - uint32_t writeMask; -}; - -struct vkCmdSetTessellationDomainOriginEXT_params -{ - VkCommandBuffer commandBuffer; - VkTessellationDomainOrigin domainOrigin; -}; - -struct vkCmdSetVertexInputEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t vertexBindingDescriptionCount; - const VkVertexInputBindingDescription2EXT *pVertexBindingDescriptions; - uint32_t vertexAttributeDescriptionCount; - const VkVertexInputAttributeDescription2EXT *pVertexAttributeDescriptions; -}; - -struct vkCmdSetViewport_params -{ - VkCommandBuffer commandBuffer; - uint32_t firstViewport; - uint32_t viewportCount; - const VkViewport *pViewports; -}; - -struct vkCmdSetViewportShadingRatePaletteNV_params -{ - VkCommandBuffer commandBuffer; - uint32_t firstViewport; - uint32_t viewportCount; - const VkShadingRatePaletteNV *pShadingRatePalettes; -}; - -struct vkCmdSetViewportSwizzleNV_params -{ - VkCommandBuffer commandBuffer; - uint32_t firstViewport; - uint32_t viewportCount; - const VkViewportSwizzleNV *pViewportSwizzles; -}; - -struct vkCmdSetViewportWScalingEnableNV_params -{ - VkCommandBuffer commandBuffer; - VkBool32 viewportWScalingEnable; -}; - -struct vkCmdSetViewportWScalingNV_params -{ - VkCommandBuffer commandBuffer; - uint32_t firstViewport; - uint32_t viewportCount; - const VkViewportWScalingNV *pViewportWScalings; -}; - -struct vkCmdSetViewportWithCount_params -{ - VkCommandBuffer commandBuffer; - uint32_t viewportCount; - const VkViewport *pViewports; -}; - -struct vkCmdSetViewportWithCountEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t viewportCount; - const VkViewport *pViewports; -}; - -struct vkCmdSubpassShadingHUAWEI_params -{ - VkCommandBuffer commandBuffer; -}; - -struct vkCmdTraceRaysIndirect2KHR_params -{ - VkCommandBuffer commandBuffer; - VkDeviceAddress DECLSPEC_ALIGN(8) indirectDeviceAddress; -}; - -struct vkCmdTraceRaysIndirectKHR_params -{ - VkCommandBuffer commandBuffer; - const VkStridedDeviceAddressRegionKHR *pRaygenShaderBindingTable; - const VkStridedDeviceAddressRegionKHR *pMissShaderBindingTable; - const VkStridedDeviceAddressRegionKHR *pHitShaderBindingTable; - const VkStridedDeviceAddressRegionKHR *pCallableShaderBindingTable; - VkDeviceAddress DECLSPEC_ALIGN(8) indirectDeviceAddress; -}; - -struct vkCmdTraceRaysKHR_params -{ - VkCommandBuffer commandBuffer; - const VkStridedDeviceAddressRegionKHR *pRaygenShaderBindingTable; - const VkStridedDeviceAddressRegionKHR *pMissShaderBindingTable; - const VkStridedDeviceAddressRegionKHR *pHitShaderBindingTable; - const VkStridedDeviceAddressRegionKHR *pCallableShaderBindingTable; - uint32_t width; - uint32_t height; - uint32_t depth; -}; - -struct vkCmdTraceRaysNV_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) raygenShaderBindingTableBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) raygenShaderBindingOffset; - VkBuffer DECLSPEC_ALIGN(8) missShaderBindingTableBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) missShaderBindingOffset; - VkDeviceSize DECLSPEC_ALIGN(8) missShaderBindingStride; - VkBuffer DECLSPEC_ALIGN(8) hitShaderBindingTableBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) hitShaderBindingOffset; - VkDeviceSize DECLSPEC_ALIGN(8) hitShaderBindingStride; - VkBuffer DECLSPEC_ALIGN(8) callableShaderBindingTableBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) callableShaderBindingOffset; - VkDeviceSize DECLSPEC_ALIGN(8) callableShaderBindingStride; - uint32_t width; - uint32_t height; - uint32_t depth; -}; - -struct vkCmdUpdateBuffer_params -{ - VkCommandBuffer commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) dstBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) dstOffset; - VkDeviceSize DECLSPEC_ALIGN(8) dataSize; - const void *pData; -}; - -struct vkCmdWaitEvents_params -{ - VkCommandBuffer commandBuffer; - uint32_t eventCount; - const VkEvent *pEvents; - VkPipelineStageFlags srcStageMask; - VkPipelineStageFlags dstStageMask; - uint32_t memoryBarrierCount; - const VkMemoryBarrier *pMemoryBarriers; - uint32_t bufferMemoryBarrierCount; - const VkBufferMemoryBarrier *pBufferMemoryBarriers; - uint32_t imageMemoryBarrierCount; - const VkImageMemoryBarrier *pImageMemoryBarriers; -}; - -struct vkCmdWaitEvents2_params -{ - VkCommandBuffer commandBuffer; - uint32_t eventCount; - const VkEvent *pEvents; - const VkDependencyInfo *pDependencyInfos; -}; - -struct vkCmdWaitEvents2KHR_params -{ - VkCommandBuffer commandBuffer; - uint32_t eventCount; - const VkEvent *pEvents; - const VkDependencyInfo *pDependencyInfos; -}; - -struct vkCmdWriteAccelerationStructuresPropertiesKHR_params -{ - VkCommandBuffer commandBuffer; - uint32_t accelerationStructureCount; - const VkAccelerationStructureKHR *pAccelerationStructures; - VkQueryType queryType; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t firstQuery; -}; - -struct vkCmdWriteAccelerationStructuresPropertiesNV_params -{ - VkCommandBuffer commandBuffer; - uint32_t accelerationStructureCount; - const VkAccelerationStructureNV *pAccelerationStructures; - VkQueryType queryType; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t firstQuery; -}; - -struct vkCmdWriteBufferMarker2AMD_params -{ - VkCommandBuffer commandBuffer; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) stage; - VkBuffer DECLSPEC_ALIGN(8) dstBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) dstOffset; - uint32_t marker; -}; - -struct vkCmdWriteBufferMarkerAMD_params -{ - VkCommandBuffer commandBuffer; - VkPipelineStageFlagBits pipelineStage; - VkBuffer DECLSPEC_ALIGN(8) dstBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) dstOffset; - uint32_t marker; -}; - -struct vkCmdWriteMicromapsPropertiesEXT_params -{ - VkCommandBuffer commandBuffer; - uint32_t micromapCount; - const VkMicromapEXT *pMicromaps; - VkQueryType queryType; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t firstQuery; -}; - -struct vkCmdWriteTimestamp_params -{ - VkCommandBuffer commandBuffer; - VkPipelineStageFlagBits pipelineStage; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t query; -}; - -struct vkCmdWriteTimestamp2_params -{ - VkCommandBuffer commandBuffer; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) stage; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t query; -}; - -struct vkCmdWriteTimestamp2KHR_params -{ - VkCommandBuffer commandBuffer; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) stage; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t query; -}; - -struct vkCompileDeferredNV_params -{ - VkDevice device; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - uint32_t shader; - VkResult result; -}; - -struct vkCopyAccelerationStructureKHR_params -{ - VkDevice device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - const VkCopyAccelerationStructureInfoKHR *pInfo; - VkResult result; -}; - -struct vkCopyAccelerationStructureToMemoryKHR_params -{ - VkDevice device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - const VkCopyAccelerationStructureToMemoryInfoKHR *pInfo; - VkResult result; -}; - -struct vkCopyMemoryToAccelerationStructureKHR_params -{ - VkDevice device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - const VkCopyMemoryToAccelerationStructureInfoKHR *pInfo; - VkResult result; -}; - -struct vkCopyMemoryToMicromapEXT_params -{ - VkDevice device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - const VkCopyMemoryToMicromapInfoEXT *pInfo; - VkResult result; -}; - -struct vkCopyMicromapEXT_params -{ - VkDevice device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - const VkCopyMicromapInfoEXT *pInfo; - VkResult result; -}; - -struct vkCopyMicromapToMemoryEXT_params -{ - VkDevice device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - const VkCopyMicromapToMemoryInfoEXT *pInfo; - VkResult result; -}; - -struct vkCreateAccelerationStructureKHR_params -{ - VkDevice device; - const VkAccelerationStructureCreateInfoKHR *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkAccelerationStructureKHR *pAccelerationStructure; - VkResult result; -}; - -struct vkCreateAccelerationStructureNV_params -{ - VkDevice device; - const VkAccelerationStructureCreateInfoNV *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkAccelerationStructureNV *pAccelerationStructure; - VkResult result; -}; - -struct vkCreateBuffer_params -{ - VkDevice device; - const VkBufferCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkBuffer *pBuffer; - VkResult result; -}; - -struct vkCreateBufferView_params -{ - VkDevice device; - const VkBufferViewCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkBufferView *pView; - VkResult result; -}; - -struct vkCreateCommandPool_params -{ - VkDevice device; - const VkCommandPoolCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkCommandPool *pCommandPool; - void *client_ptr; - VkResult result; -}; - -struct vkCreateComputePipelines_params -{ - VkDevice device; - VkPipelineCache DECLSPEC_ALIGN(8) pipelineCache; - uint32_t createInfoCount; - const VkComputePipelineCreateInfo *pCreateInfos; - const VkAllocationCallbacks *pAllocator; - VkPipeline *pPipelines; - VkResult result; -}; - -struct vkCreateCuFunctionNVX_params -{ - VkDevice device; - const VkCuFunctionCreateInfoNVX *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkCuFunctionNVX *pFunction; - VkResult result; -}; - -struct vkCreateCuModuleNVX_params -{ - VkDevice device; - const VkCuModuleCreateInfoNVX *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkCuModuleNVX *pModule; - VkResult result; -}; - -struct vkCreateDebugReportCallbackEXT_params -{ - VkInstance instance; - const VkDebugReportCallbackCreateInfoEXT *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkDebugReportCallbackEXT *pCallback; - VkResult result; -}; - -struct vkCreateDebugUtilsMessengerEXT_params -{ - VkInstance instance; - const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkDebugUtilsMessengerEXT *pMessenger; - VkResult result; -}; - -struct vkCreateDeferredOperationKHR_params -{ - VkDevice device; - const VkAllocationCallbacks *pAllocator; - VkDeferredOperationKHR *pDeferredOperation; - VkResult result; -}; - -struct vkCreateDescriptorPool_params -{ - VkDevice device; - const VkDescriptorPoolCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkDescriptorPool *pDescriptorPool; - VkResult result; -}; - -struct vkCreateDescriptorSetLayout_params -{ - VkDevice device; - const VkDescriptorSetLayoutCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkDescriptorSetLayout *pSetLayout; - VkResult result; -}; - -struct vkCreateDescriptorUpdateTemplate_params -{ - VkDevice device; - const VkDescriptorUpdateTemplateCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkDescriptorUpdateTemplate *pDescriptorUpdateTemplate; - VkResult result; -}; - -struct vkCreateDescriptorUpdateTemplateKHR_params -{ - VkDevice device; - const VkDescriptorUpdateTemplateCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkDescriptorUpdateTemplate *pDescriptorUpdateTemplate; - VkResult result; -}; - -struct vkCreateDevice_params -{ - VkPhysicalDevice physicalDevice; - const VkDeviceCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkDevice *pDevice; - void *client_ptr; - VkResult result; -}; - -struct vkCreateEvent_params -{ - VkDevice device; - const VkEventCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkEvent *pEvent; - VkResult result; -}; - -struct vkCreateFence_params -{ - VkDevice device; - const VkFenceCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkFence *pFence; - VkResult result; -}; - -struct vkCreateFramebuffer_params -{ - VkDevice device; - const VkFramebufferCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkFramebuffer *pFramebuffer; - VkResult result; -}; - -struct vkCreateGraphicsPipelines_params -{ - VkDevice device; - VkPipelineCache DECLSPEC_ALIGN(8) pipelineCache; - uint32_t createInfoCount; - const VkGraphicsPipelineCreateInfo *pCreateInfos; - const VkAllocationCallbacks *pAllocator; - VkPipeline *pPipelines; - VkResult result; -}; - -struct vkCreateImage_params -{ - VkDevice device; - const VkImageCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkImage *pImage; - VkResult result; -}; - -struct vkCreateImageView_params -{ - VkDevice device; - const VkImageViewCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkImageView *pView; - VkResult result; -}; - -struct vkCreateIndirectCommandsLayoutNV_params -{ - VkDevice device; - const VkIndirectCommandsLayoutCreateInfoNV *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkIndirectCommandsLayoutNV *pIndirectCommandsLayout; - VkResult result; -}; - -struct vkCreateInstance_params -{ - const VkInstanceCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkInstance *pInstance; - void *client_ptr; - VkResult result; -}; - -struct vkCreateMicromapEXT_params -{ - VkDevice device; - const VkMicromapCreateInfoEXT *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkMicromapEXT *pMicromap; - VkResult result; -}; - -struct vkCreateOpticalFlowSessionNV_params -{ - VkDevice device; - const VkOpticalFlowSessionCreateInfoNV *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkOpticalFlowSessionNV *pSession; - VkResult result; -}; - -struct vkCreatePipelineCache_params -{ - VkDevice device; - const VkPipelineCacheCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkPipelineCache *pPipelineCache; - VkResult result; -}; - -struct vkCreatePipelineLayout_params -{ - VkDevice device; - const VkPipelineLayoutCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkPipelineLayout *pPipelineLayout; - VkResult result; -}; - -struct vkCreatePrivateDataSlot_params -{ - VkDevice device; - const VkPrivateDataSlotCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkPrivateDataSlot *pPrivateDataSlot; - VkResult result; -}; - -struct vkCreatePrivateDataSlotEXT_params -{ - VkDevice device; - const VkPrivateDataSlotCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkPrivateDataSlot *pPrivateDataSlot; - VkResult result; -}; - -struct vkCreateQueryPool_params -{ - VkDevice device; - const VkQueryPoolCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkQueryPool *pQueryPool; - VkResult result; -}; - -struct vkCreateRayTracingPipelinesKHR_params -{ - VkDevice device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - VkPipelineCache DECLSPEC_ALIGN(8) pipelineCache; - uint32_t createInfoCount; - const VkRayTracingPipelineCreateInfoKHR *pCreateInfos; - const VkAllocationCallbacks *pAllocator; - VkPipeline *pPipelines; - VkResult result; -}; - -struct vkCreateRayTracingPipelinesNV_params -{ - VkDevice device; - VkPipelineCache DECLSPEC_ALIGN(8) pipelineCache; - uint32_t createInfoCount; - const VkRayTracingPipelineCreateInfoNV *pCreateInfos; - const VkAllocationCallbacks *pAllocator; - VkPipeline *pPipelines; - VkResult result; -}; - -struct vkCreateRenderPass_params -{ - VkDevice device; - const VkRenderPassCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkRenderPass *pRenderPass; - VkResult result; -}; - -struct vkCreateRenderPass2_params -{ - VkDevice device; - const VkRenderPassCreateInfo2 *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkRenderPass *pRenderPass; - VkResult result; -}; - -struct vkCreateRenderPass2KHR_params -{ - VkDevice device; - const VkRenderPassCreateInfo2 *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkRenderPass *pRenderPass; - VkResult result; -}; - -struct vkCreateSampler_params -{ - VkDevice device; - const VkSamplerCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkSampler *pSampler; - VkResult result; -}; - -struct vkCreateSamplerYcbcrConversion_params -{ - VkDevice device; - const VkSamplerYcbcrConversionCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkSamplerYcbcrConversion *pYcbcrConversion; - VkResult result; -}; - -struct vkCreateSamplerYcbcrConversionKHR_params -{ - VkDevice device; - const VkSamplerYcbcrConversionCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkSamplerYcbcrConversion *pYcbcrConversion; - VkResult result; -}; - -struct vkCreateSemaphore_params -{ - VkDevice device; - const VkSemaphoreCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkSemaphore *pSemaphore; - VkResult result; -}; - -struct vkCreateShaderModule_params -{ - VkDevice device; - const VkShaderModuleCreateInfo *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkShaderModule *pShaderModule; - VkResult result; -}; - -struct vkCreateSwapchainKHR_params -{ - VkDevice device; - const VkSwapchainCreateInfoKHR *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkSwapchainKHR *pSwapchain; - VkResult result; -}; - -struct vkCreateValidationCacheEXT_params -{ - VkDevice device; - const VkValidationCacheCreateInfoEXT *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkValidationCacheEXT *pValidationCache; - VkResult result; -}; - -struct vkCreateWin32SurfaceKHR_params -{ - VkInstance instance; - const VkWin32SurfaceCreateInfoKHR *pCreateInfo; - const VkAllocationCallbacks *pAllocator; - VkSurfaceKHR *pSurface; - VkResult result; -}; - -struct vkDebugMarkerSetObjectNameEXT_params -{ - VkDevice device; - const VkDebugMarkerObjectNameInfoEXT *pNameInfo; - VkResult result; -}; - -struct vkDebugMarkerSetObjectTagEXT_params -{ - VkDevice device; - const VkDebugMarkerObjectTagInfoEXT *pTagInfo; - VkResult result; -}; - -struct vkDebugReportMessageEXT_params -{ - VkInstance instance; - VkDebugReportFlagsEXT flags; - VkDebugReportObjectTypeEXT objectType; - uint64_t DECLSPEC_ALIGN(8) object; - size_t location; - int32_t messageCode; - const char *pLayerPrefix; - const char *pMessage; -}; - -struct vkDeferredOperationJoinKHR_params -{ - VkDevice device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) operation; - VkResult result; -}; - -struct vkDestroyAccelerationStructureKHR_params -{ - VkDevice device; - VkAccelerationStructureKHR DECLSPEC_ALIGN(8) accelerationStructure; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyAccelerationStructureNV_params -{ - VkDevice device; - VkAccelerationStructureNV DECLSPEC_ALIGN(8) accelerationStructure; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyBuffer_params -{ - VkDevice device; - VkBuffer DECLSPEC_ALIGN(8) buffer; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyBufferView_params -{ - VkDevice device; - VkBufferView DECLSPEC_ALIGN(8) bufferView; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyCommandPool_params -{ - VkDevice device; - VkCommandPool DECLSPEC_ALIGN(8) commandPool; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyCuFunctionNVX_params -{ - VkDevice device; - VkCuFunctionNVX DECLSPEC_ALIGN(8) function; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyCuModuleNVX_params -{ - VkDevice device; - VkCuModuleNVX DECLSPEC_ALIGN(8) module; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyDebugReportCallbackEXT_params -{ - VkInstance instance; - VkDebugReportCallbackEXT DECLSPEC_ALIGN(8) callback; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyDebugUtilsMessengerEXT_params -{ - VkInstance instance; - VkDebugUtilsMessengerEXT DECLSPEC_ALIGN(8) messenger; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyDeferredOperationKHR_params -{ - VkDevice device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) operation; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyDescriptorPool_params -{ - VkDevice device; - VkDescriptorPool DECLSPEC_ALIGN(8) descriptorPool; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyDescriptorSetLayout_params -{ - VkDevice device; - VkDescriptorSetLayout DECLSPEC_ALIGN(8) descriptorSetLayout; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyDescriptorUpdateTemplate_params -{ - VkDevice device; - VkDescriptorUpdateTemplate DECLSPEC_ALIGN(8) descriptorUpdateTemplate; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyDescriptorUpdateTemplateKHR_params -{ - VkDevice device; - VkDescriptorUpdateTemplate DECLSPEC_ALIGN(8) descriptorUpdateTemplate; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyDevice_params -{ - VkDevice device; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyEvent_params -{ - VkDevice device; - VkEvent DECLSPEC_ALIGN(8) event; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyFence_params -{ - VkDevice device; - VkFence DECLSPEC_ALIGN(8) fence; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyFramebuffer_params -{ - VkDevice device; - VkFramebuffer DECLSPEC_ALIGN(8) framebuffer; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyImage_params -{ - VkDevice device; - VkImage DECLSPEC_ALIGN(8) image; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyImageView_params -{ - VkDevice device; - VkImageView DECLSPEC_ALIGN(8) imageView; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyIndirectCommandsLayoutNV_params -{ - VkDevice device; - VkIndirectCommandsLayoutNV DECLSPEC_ALIGN(8) indirectCommandsLayout; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyInstance_params -{ - VkInstance instance; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyMicromapEXT_params -{ - VkDevice device; - VkMicromapEXT DECLSPEC_ALIGN(8) micromap; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyOpticalFlowSessionNV_params -{ - VkDevice device; - VkOpticalFlowSessionNV DECLSPEC_ALIGN(8) session; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyPipeline_params -{ - VkDevice device; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyPipelineCache_params -{ - VkDevice device; - VkPipelineCache DECLSPEC_ALIGN(8) pipelineCache; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyPipelineLayout_params -{ - VkDevice device; - VkPipelineLayout DECLSPEC_ALIGN(8) pipelineLayout; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyPrivateDataSlot_params -{ - VkDevice device; - VkPrivateDataSlot DECLSPEC_ALIGN(8) privateDataSlot; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyPrivateDataSlotEXT_params -{ - VkDevice device; - VkPrivateDataSlot DECLSPEC_ALIGN(8) privateDataSlot; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyQueryPool_params -{ - VkDevice device; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyRenderPass_params -{ - VkDevice device; - VkRenderPass DECLSPEC_ALIGN(8) renderPass; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroySampler_params -{ - VkDevice device; - VkSampler DECLSPEC_ALIGN(8) sampler; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroySamplerYcbcrConversion_params -{ - VkDevice device; - VkSamplerYcbcrConversion DECLSPEC_ALIGN(8) ycbcrConversion; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroySamplerYcbcrConversionKHR_params -{ - VkDevice device; - VkSamplerYcbcrConversion DECLSPEC_ALIGN(8) ycbcrConversion; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroySemaphore_params -{ - VkDevice device; - VkSemaphore DECLSPEC_ALIGN(8) semaphore; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyShaderModule_params -{ - VkDevice device; - VkShaderModule DECLSPEC_ALIGN(8) shaderModule; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroySurfaceKHR_params -{ - VkInstance instance; - VkSurfaceKHR DECLSPEC_ALIGN(8) surface; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroySwapchainKHR_params -{ - VkDevice device; - VkSwapchainKHR DECLSPEC_ALIGN(8) swapchain; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDestroyValidationCacheEXT_params -{ - VkDevice device; - VkValidationCacheEXT DECLSPEC_ALIGN(8) validationCache; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkDeviceWaitIdle_params -{ - VkDevice device; - VkResult result; -}; - -struct vkEndCommandBuffer_params -{ - VkCommandBuffer commandBuffer; - VkResult result; -}; - -struct vkEnumerateDeviceExtensionProperties_params -{ - VkPhysicalDevice physicalDevice; - const char *pLayerName; - uint32_t *pPropertyCount; - VkExtensionProperties *pProperties; - VkResult result; -}; - -struct vkEnumerateDeviceLayerProperties_params -{ - VkPhysicalDevice physicalDevice; - uint32_t *pPropertyCount; - VkLayerProperties *pProperties; - VkResult result; -}; - -struct vkEnumerateInstanceExtensionProperties_params -{ - const char *pLayerName; - uint32_t *pPropertyCount; - VkExtensionProperties *pProperties; - VkResult result; -}; - -struct vkEnumerateInstanceVersion_params -{ - uint32_t *pApiVersion; - VkResult result; -}; - -struct vkEnumeratePhysicalDeviceGroups_params -{ - VkInstance instance; - uint32_t *pPhysicalDeviceGroupCount; - VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties; - VkResult result; -}; - -struct vkEnumeratePhysicalDeviceGroupsKHR_params -{ - VkInstance instance; - uint32_t *pPhysicalDeviceGroupCount; - VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties; - VkResult result; -}; - -struct vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR_params -{ - VkPhysicalDevice physicalDevice; - uint32_t queueFamilyIndex; - uint32_t *pCounterCount; - VkPerformanceCounterKHR *pCounters; - VkPerformanceCounterDescriptionKHR *pCounterDescriptions; - VkResult result; -}; - -struct vkEnumeratePhysicalDevices_params -{ - VkInstance instance; - uint32_t *pPhysicalDeviceCount; - VkPhysicalDevice *pPhysicalDevices; - VkResult result; -}; - -struct vkFlushMappedMemoryRanges_params -{ - VkDevice device; - uint32_t memoryRangeCount; - const VkMappedMemoryRange *pMemoryRanges; - VkResult result; -}; - -struct vkFreeCommandBuffers_params -{ - VkDevice device; - VkCommandPool DECLSPEC_ALIGN(8) commandPool; - uint32_t commandBufferCount; - const VkCommandBuffer *pCommandBuffers; -}; - -struct vkFreeDescriptorSets_params -{ - VkDevice device; - VkDescriptorPool DECLSPEC_ALIGN(8) descriptorPool; - uint32_t descriptorSetCount; - const VkDescriptorSet *pDescriptorSets; - VkResult result; -}; - -struct vkFreeMemory_params -{ - VkDevice device; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - const VkAllocationCallbacks *pAllocator; -}; - -struct vkGetAccelerationStructureBuildSizesKHR_params -{ - VkDevice device; - VkAccelerationStructureBuildTypeKHR buildType; - const VkAccelerationStructureBuildGeometryInfoKHR *pBuildInfo; - const uint32_t *pMaxPrimitiveCounts; - VkAccelerationStructureBuildSizesInfoKHR *pSizeInfo; -}; - -struct vkGetAccelerationStructureDeviceAddressKHR_params -{ - VkDevice device; - const VkAccelerationStructureDeviceAddressInfoKHR *pInfo; - VkDeviceAddress result; -}; - -struct vkGetAccelerationStructureHandleNV_params -{ - VkDevice device; - VkAccelerationStructureNV DECLSPEC_ALIGN(8) accelerationStructure; - size_t dataSize; - void *pData; - VkResult result; -}; - -struct vkGetAccelerationStructureMemoryRequirementsNV_params -{ - VkDevice device; - const VkAccelerationStructureMemoryRequirementsInfoNV *pInfo; - VkMemoryRequirements2KHR *pMemoryRequirements; -}; - -struct vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT_params -{ - VkDevice device; - const VkAccelerationStructureCaptureDescriptorDataInfoEXT *pInfo; - void *pData; - VkResult result; -}; - -struct vkGetBufferDeviceAddress_params -{ - VkDevice device; - const VkBufferDeviceAddressInfo *pInfo; - VkDeviceAddress result; -}; - -struct vkGetBufferDeviceAddressEXT_params -{ - VkDevice device; - const VkBufferDeviceAddressInfo *pInfo; - VkDeviceAddress result; -}; - -struct vkGetBufferDeviceAddressKHR_params -{ - VkDevice device; - const VkBufferDeviceAddressInfo *pInfo; - VkDeviceAddress result; -}; - -struct vkGetBufferMemoryRequirements_params -{ - VkDevice device; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkMemoryRequirements *pMemoryRequirements; -}; - -struct vkGetBufferMemoryRequirements2_params -{ - VkDevice device; - const VkBufferMemoryRequirementsInfo2 *pInfo; - VkMemoryRequirements2 *pMemoryRequirements; -}; - -struct vkGetBufferMemoryRequirements2KHR_params -{ - VkDevice device; - const VkBufferMemoryRequirementsInfo2 *pInfo; - VkMemoryRequirements2 *pMemoryRequirements; -}; - -struct vkGetBufferOpaqueCaptureAddress_params -{ - VkDevice device; - const VkBufferDeviceAddressInfo *pInfo; - uint64_t result; -}; - -struct vkGetBufferOpaqueCaptureAddressKHR_params -{ - VkDevice device; - const VkBufferDeviceAddressInfo *pInfo; - uint64_t result; -}; - -struct vkGetBufferOpaqueCaptureDescriptorDataEXT_params -{ - VkDevice device; - const VkBufferCaptureDescriptorDataInfoEXT *pInfo; - void *pData; - VkResult result; -}; - -struct vkGetCalibratedTimestampsEXT_params -{ - VkDevice device; - uint32_t timestampCount; - const VkCalibratedTimestampInfoEXT *pTimestampInfos; - uint64_t *pTimestamps; - uint64_t *pMaxDeviation; - VkResult result; -}; - -struct vkGetDeferredOperationMaxConcurrencyKHR_params -{ - VkDevice device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) operation; - uint32_t result; -}; - -struct vkGetDeferredOperationResultKHR_params -{ - VkDevice device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) operation; - VkResult result; -}; - -struct vkGetDescriptorEXT_params -{ - VkDevice device; - const VkDescriptorGetInfoEXT *pDescriptorInfo; - size_t dataSize; - void *pDescriptor; -}; - -struct vkGetDescriptorSetHostMappingVALVE_params -{ - VkDevice device; - VkDescriptorSet DECLSPEC_ALIGN(8) descriptorSet; - void **ppData; -}; - -struct vkGetDescriptorSetLayoutBindingOffsetEXT_params -{ - VkDevice device; - VkDescriptorSetLayout DECLSPEC_ALIGN(8) layout; - uint32_t binding; - VkDeviceSize *pOffset; -}; - -struct vkGetDescriptorSetLayoutHostMappingInfoVALVE_params -{ - VkDevice device; - const VkDescriptorSetBindingReferenceVALVE *pBindingReference; - VkDescriptorSetLayoutHostMappingInfoVALVE *pHostMapping; -}; - -struct vkGetDescriptorSetLayoutSizeEXT_params -{ - VkDevice device; - VkDescriptorSetLayout DECLSPEC_ALIGN(8) layout; - VkDeviceSize *pLayoutSizeInBytes; -}; - -struct vkGetDescriptorSetLayoutSupport_params -{ - VkDevice device; - const VkDescriptorSetLayoutCreateInfo *pCreateInfo; - VkDescriptorSetLayoutSupport *pSupport; -}; - -struct vkGetDescriptorSetLayoutSupportKHR_params -{ - VkDevice device; - const VkDescriptorSetLayoutCreateInfo *pCreateInfo; - VkDescriptorSetLayoutSupport *pSupport; -}; - -struct vkGetDeviceAccelerationStructureCompatibilityKHR_params -{ - VkDevice device; - const VkAccelerationStructureVersionInfoKHR *pVersionInfo; - VkAccelerationStructureCompatibilityKHR *pCompatibility; -}; - -struct vkGetDeviceBufferMemoryRequirements_params -{ - VkDevice device; - const VkDeviceBufferMemoryRequirements *pInfo; - VkMemoryRequirements2 *pMemoryRequirements; -}; - -struct vkGetDeviceBufferMemoryRequirementsKHR_params -{ - VkDevice device; - const VkDeviceBufferMemoryRequirements *pInfo; - VkMemoryRequirements2 *pMemoryRequirements; -}; - -struct vkGetDeviceFaultInfoEXT_params -{ - VkDevice device; - VkDeviceFaultCountsEXT *pFaultCounts; - VkDeviceFaultInfoEXT *pFaultInfo; - VkResult result; -}; - -struct vkGetDeviceGroupPeerMemoryFeatures_params -{ - VkDevice device; - uint32_t heapIndex; - uint32_t localDeviceIndex; - uint32_t remoteDeviceIndex; - VkPeerMemoryFeatureFlags *pPeerMemoryFeatures; -}; - -struct vkGetDeviceGroupPeerMemoryFeaturesKHR_params -{ - VkDevice device; - uint32_t heapIndex; - uint32_t localDeviceIndex; - uint32_t remoteDeviceIndex; - VkPeerMemoryFeatureFlags *pPeerMemoryFeatures; -}; - -struct vkGetDeviceGroupPresentCapabilitiesKHR_params -{ - VkDevice device; - VkDeviceGroupPresentCapabilitiesKHR *pDeviceGroupPresentCapabilities; - VkResult result; -}; - -struct vkGetDeviceGroupSurfacePresentModesKHR_params -{ - VkDevice device; - VkSurfaceKHR DECLSPEC_ALIGN(8) surface; - VkDeviceGroupPresentModeFlagsKHR *pModes; - VkResult result; -}; - -struct vkGetDeviceImageMemoryRequirements_params -{ - VkDevice device; - const VkDeviceImageMemoryRequirements *pInfo; - VkMemoryRequirements2 *pMemoryRequirements; -}; - -struct vkGetDeviceImageMemoryRequirementsKHR_params -{ - VkDevice device; - const VkDeviceImageMemoryRequirements *pInfo; - VkMemoryRequirements2 *pMemoryRequirements; -}; - -struct vkGetDeviceImageSparseMemoryRequirements_params -{ - VkDevice device; - const VkDeviceImageMemoryRequirements *pInfo; - uint32_t *pSparseMemoryRequirementCount; - VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements; -}; - -struct vkGetDeviceImageSparseMemoryRequirementsKHR_params -{ - VkDevice device; - const VkDeviceImageMemoryRequirements *pInfo; - uint32_t *pSparseMemoryRequirementCount; - VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements; -}; - -struct vkGetDeviceMemoryCommitment_params -{ - VkDevice device; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - VkDeviceSize *pCommittedMemoryInBytes; -}; - -struct vkGetDeviceMemoryOpaqueCaptureAddress_params -{ - VkDevice device; - const VkDeviceMemoryOpaqueCaptureAddressInfo *pInfo; - uint64_t result; -}; - -struct vkGetDeviceMemoryOpaqueCaptureAddressKHR_params -{ - VkDevice device; - const VkDeviceMemoryOpaqueCaptureAddressInfo *pInfo; - uint64_t result; -}; - -struct vkGetDeviceMicromapCompatibilityEXT_params -{ - VkDevice device; - const VkMicromapVersionInfoEXT *pVersionInfo; - VkAccelerationStructureCompatibilityKHR *pCompatibility; -}; - -struct vkGetDeviceQueue_params -{ - VkDevice device; - uint32_t queueFamilyIndex; - uint32_t queueIndex; - VkQueue *pQueue; -}; - -struct vkGetDeviceQueue2_params -{ - VkDevice device; - const VkDeviceQueueInfo2 *pQueueInfo; - VkQueue *pQueue; -}; - -struct vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI_params -{ - VkDevice device; - VkRenderPass DECLSPEC_ALIGN(8) renderpass; - VkExtent2D *pMaxWorkgroupSize; - VkResult result; -}; - -struct vkGetDynamicRenderingTilePropertiesQCOM_params -{ - VkDevice device; - const VkRenderingInfo *pRenderingInfo; - VkTilePropertiesQCOM *pProperties; - VkResult result; -}; - -struct vkGetEventStatus_params -{ - VkDevice device; - VkEvent DECLSPEC_ALIGN(8) event; - VkResult result; -}; - -struct vkGetFenceStatus_params -{ - VkDevice device; - VkFence DECLSPEC_ALIGN(8) fence; - VkResult result; -}; - -struct vkGetFramebufferTilePropertiesQCOM_params -{ - VkDevice device; - VkFramebuffer DECLSPEC_ALIGN(8) framebuffer; - uint32_t *pPropertiesCount; - VkTilePropertiesQCOM *pProperties; - VkResult result; -}; - -struct vkGetGeneratedCommandsMemoryRequirementsNV_params -{ - VkDevice device; - const VkGeneratedCommandsMemoryRequirementsInfoNV *pInfo; - VkMemoryRequirements2 *pMemoryRequirements; -}; - -struct vkGetImageMemoryRequirements_params -{ - VkDevice device; - VkImage DECLSPEC_ALIGN(8) image; - VkMemoryRequirements *pMemoryRequirements; -}; - -struct vkGetImageMemoryRequirements2_params -{ - VkDevice device; - const VkImageMemoryRequirementsInfo2 *pInfo; - VkMemoryRequirements2 *pMemoryRequirements; -}; - -struct vkGetImageMemoryRequirements2KHR_params -{ - VkDevice device; - const VkImageMemoryRequirementsInfo2 *pInfo; - VkMemoryRequirements2 *pMemoryRequirements; -}; - -struct vkGetImageOpaqueCaptureDescriptorDataEXT_params -{ - VkDevice device; - const VkImageCaptureDescriptorDataInfoEXT *pInfo; - void *pData; - VkResult result; -}; - -struct vkGetImageSparseMemoryRequirements_params -{ - VkDevice device; - VkImage DECLSPEC_ALIGN(8) image; - uint32_t *pSparseMemoryRequirementCount; - VkSparseImageMemoryRequirements *pSparseMemoryRequirements; -}; - -struct vkGetImageSparseMemoryRequirements2_params -{ - VkDevice device; - const VkImageSparseMemoryRequirementsInfo2 *pInfo; - uint32_t *pSparseMemoryRequirementCount; - VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements; -}; - -struct vkGetImageSparseMemoryRequirements2KHR_params -{ - VkDevice device; - const VkImageSparseMemoryRequirementsInfo2 *pInfo; - uint32_t *pSparseMemoryRequirementCount; - VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements; -}; - -struct vkGetImageSubresourceLayout_params -{ - VkDevice device; - VkImage DECLSPEC_ALIGN(8) image; - const VkImageSubresource *pSubresource; - VkSubresourceLayout *pLayout; -}; - -struct vkGetImageSubresourceLayout2EXT_params -{ - VkDevice device; - VkImage DECLSPEC_ALIGN(8) image; - const VkImageSubresource2EXT *pSubresource; - VkSubresourceLayout2EXT *pLayout; -}; - -struct vkGetImageViewAddressNVX_params -{ - VkDevice device; - VkImageView DECLSPEC_ALIGN(8) imageView; - VkImageViewAddressPropertiesNVX *pProperties; - VkResult result; -}; - -struct vkGetImageViewHandleNVX_params -{ - VkDevice device; - const VkImageViewHandleInfoNVX *pInfo; - uint32_t result; -}; - -struct vkGetImageViewOpaqueCaptureDescriptorDataEXT_params -{ - VkDevice device; - const VkImageViewCaptureDescriptorDataInfoEXT *pInfo; - void *pData; - VkResult result; -}; - -struct vkGetMemoryHostPointerPropertiesEXT_params -{ - VkDevice device; - VkExternalMemoryHandleTypeFlagBits handleType; - const void *pHostPointer; - VkMemoryHostPointerPropertiesEXT *pMemoryHostPointerProperties; - VkResult result; -}; - -struct vkGetMicromapBuildSizesEXT_params -{ - VkDevice device; - VkAccelerationStructureBuildTypeKHR buildType; - const VkMicromapBuildInfoEXT *pBuildInfo; - VkMicromapBuildSizesInfoEXT *pSizeInfo; -}; - -struct vkGetPerformanceParameterINTEL_params -{ - VkDevice device; - VkPerformanceParameterTypeINTEL parameter; - VkPerformanceValueINTEL *pValue; - VkResult result; -}; - -struct vkGetPhysicalDeviceCalibrateableTimeDomainsEXT_params -{ - VkPhysicalDevice physicalDevice; - uint32_t *pTimeDomainCount; - VkTimeDomainEXT *pTimeDomains; - VkResult result; -}; - -struct vkGetPhysicalDeviceCooperativeMatrixPropertiesNV_params -{ - VkPhysicalDevice physicalDevice; - uint32_t *pPropertyCount; - VkCooperativeMatrixPropertiesNV *pProperties; - VkResult result; -}; - -struct vkGetPhysicalDeviceExternalBufferProperties_params -{ - VkPhysicalDevice physicalDevice; - const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo; - VkExternalBufferProperties *pExternalBufferProperties; -}; - -struct vkGetPhysicalDeviceExternalBufferPropertiesKHR_params -{ - VkPhysicalDevice physicalDevice; - const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo; - VkExternalBufferProperties *pExternalBufferProperties; -}; - -struct vkGetPhysicalDeviceExternalFenceProperties_params -{ - VkPhysicalDevice physicalDevice; - const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo; - VkExternalFenceProperties *pExternalFenceProperties; -}; - -struct vkGetPhysicalDeviceExternalFencePropertiesKHR_params -{ - VkPhysicalDevice physicalDevice; - const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo; - VkExternalFenceProperties *pExternalFenceProperties; -}; - -struct vkGetPhysicalDeviceExternalSemaphoreProperties_params -{ - VkPhysicalDevice physicalDevice; - const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo; - VkExternalSemaphoreProperties *pExternalSemaphoreProperties; -}; - -struct vkGetPhysicalDeviceExternalSemaphorePropertiesKHR_params -{ - VkPhysicalDevice physicalDevice; - const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo; - VkExternalSemaphoreProperties *pExternalSemaphoreProperties; -}; - -struct vkGetPhysicalDeviceFeatures_params -{ - VkPhysicalDevice physicalDevice; - VkPhysicalDeviceFeatures *pFeatures; -}; - -struct vkGetPhysicalDeviceFeatures2_params -{ - VkPhysicalDevice physicalDevice; - VkPhysicalDeviceFeatures2 *pFeatures; -}; - -struct vkGetPhysicalDeviceFeatures2KHR_params -{ - VkPhysicalDevice physicalDevice; - VkPhysicalDeviceFeatures2 *pFeatures; -}; - -struct vkGetPhysicalDeviceFormatProperties_params -{ - VkPhysicalDevice physicalDevice; - VkFormat format; - VkFormatProperties *pFormatProperties; -}; - -struct vkGetPhysicalDeviceFormatProperties2_params -{ - VkPhysicalDevice physicalDevice; - VkFormat format; - VkFormatProperties2 *pFormatProperties; -}; - -struct vkGetPhysicalDeviceFormatProperties2KHR_params -{ - VkPhysicalDevice physicalDevice; - VkFormat format; - VkFormatProperties2 *pFormatProperties; -}; - -struct vkGetPhysicalDeviceFragmentShadingRatesKHR_params -{ - VkPhysicalDevice physicalDevice; - uint32_t *pFragmentShadingRateCount; - VkPhysicalDeviceFragmentShadingRateKHR *pFragmentShadingRates; - VkResult result; -}; - -struct vkGetPhysicalDeviceImageFormatProperties_params -{ - VkPhysicalDevice physicalDevice; - VkFormat format; - VkImageType type; - VkImageTiling tiling; - VkImageUsageFlags usage; - VkImageCreateFlags flags; - VkImageFormatProperties *pImageFormatProperties; - VkResult result; -}; - -struct vkGetPhysicalDeviceImageFormatProperties2_params -{ - VkPhysicalDevice physicalDevice; - const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo; - VkImageFormatProperties2 *pImageFormatProperties; - VkResult result; -}; - -struct vkGetPhysicalDeviceImageFormatProperties2KHR_params -{ - VkPhysicalDevice physicalDevice; - const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo; - VkImageFormatProperties2 *pImageFormatProperties; - VkResult result; -}; - -struct vkGetPhysicalDeviceMemoryProperties_params -{ - VkPhysicalDevice physicalDevice; - VkPhysicalDeviceMemoryProperties *pMemoryProperties; -}; - -struct vkGetPhysicalDeviceMemoryProperties2_params -{ - VkPhysicalDevice physicalDevice; - VkPhysicalDeviceMemoryProperties2 *pMemoryProperties; -}; - -struct vkGetPhysicalDeviceMemoryProperties2KHR_params -{ - VkPhysicalDevice physicalDevice; - VkPhysicalDeviceMemoryProperties2 *pMemoryProperties; -}; - -struct vkGetPhysicalDeviceMultisamplePropertiesEXT_params -{ - VkPhysicalDevice physicalDevice; - VkSampleCountFlagBits samples; - VkMultisamplePropertiesEXT *pMultisampleProperties; -}; - -struct vkGetPhysicalDeviceOpticalFlowImageFormatsNV_params -{ - VkPhysicalDevice physicalDevice; - const VkOpticalFlowImageFormatInfoNV *pOpticalFlowImageFormatInfo; - uint32_t *pFormatCount; - VkOpticalFlowImageFormatPropertiesNV *pImageFormatProperties; - VkResult result; -}; - -struct vkGetPhysicalDevicePresentRectanglesKHR_params -{ - VkPhysicalDevice physicalDevice; - VkSurfaceKHR DECLSPEC_ALIGN(8) surface; - uint32_t *pRectCount; - VkRect2D *pRects; - VkResult result; -}; - -struct vkGetPhysicalDeviceProperties_params -{ - VkPhysicalDevice physicalDevice; - VkPhysicalDeviceProperties *pProperties; -}; - -struct vkGetPhysicalDeviceProperties2_params -{ - VkPhysicalDevice physicalDevice; - VkPhysicalDeviceProperties2 *pProperties; -}; - -struct vkGetPhysicalDeviceProperties2KHR_params -{ - VkPhysicalDevice physicalDevice; - VkPhysicalDeviceProperties2 *pProperties; -}; - -struct vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR_params -{ - VkPhysicalDevice physicalDevice; - const VkQueryPoolPerformanceCreateInfoKHR *pPerformanceQueryCreateInfo; - uint32_t *pNumPasses; -}; - -struct vkGetPhysicalDeviceQueueFamilyProperties_params -{ - VkPhysicalDevice physicalDevice; - uint32_t *pQueueFamilyPropertyCount; - VkQueueFamilyProperties *pQueueFamilyProperties; -}; - -struct vkGetPhysicalDeviceQueueFamilyProperties2_params -{ - VkPhysicalDevice physicalDevice; - uint32_t *pQueueFamilyPropertyCount; - VkQueueFamilyProperties2 *pQueueFamilyProperties; -}; - -struct vkGetPhysicalDeviceQueueFamilyProperties2KHR_params -{ - VkPhysicalDevice physicalDevice; - uint32_t *pQueueFamilyPropertyCount; - VkQueueFamilyProperties2 *pQueueFamilyProperties; -}; - -struct vkGetPhysicalDeviceSparseImageFormatProperties_params -{ - VkPhysicalDevice physicalDevice; - VkFormat format; - VkImageType type; - VkSampleCountFlagBits samples; - VkImageUsageFlags usage; - VkImageTiling tiling; - uint32_t *pPropertyCount; - VkSparseImageFormatProperties *pProperties; -}; - -struct vkGetPhysicalDeviceSparseImageFormatProperties2_params -{ - VkPhysicalDevice physicalDevice; - const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo; - uint32_t *pPropertyCount; - VkSparseImageFormatProperties2 *pProperties; -}; - -struct vkGetPhysicalDeviceSparseImageFormatProperties2KHR_params -{ - VkPhysicalDevice physicalDevice; - const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo; - uint32_t *pPropertyCount; - VkSparseImageFormatProperties2 *pProperties; -}; - -struct vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV_params -{ - VkPhysicalDevice physicalDevice; - uint32_t *pCombinationCount; - VkFramebufferMixedSamplesCombinationNV *pCombinations; - VkResult result; -}; - -struct vkGetPhysicalDeviceSurfaceCapabilities2KHR_params -{ - VkPhysicalDevice physicalDevice; - const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo; - VkSurfaceCapabilities2KHR *pSurfaceCapabilities; - VkResult result; -}; - -struct vkGetPhysicalDeviceSurfaceCapabilitiesKHR_params -{ - VkPhysicalDevice physicalDevice; - VkSurfaceKHR DECLSPEC_ALIGN(8) surface; - VkSurfaceCapabilitiesKHR *pSurfaceCapabilities; - VkResult result; -}; - -struct vkGetPhysicalDeviceSurfaceFormats2KHR_params -{ - VkPhysicalDevice physicalDevice; - const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo; - uint32_t *pSurfaceFormatCount; - VkSurfaceFormat2KHR *pSurfaceFormats; - VkResult result; -}; - -struct vkGetPhysicalDeviceSurfaceFormatsKHR_params -{ - VkPhysicalDevice physicalDevice; - VkSurfaceKHR DECLSPEC_ALIGN(8) surface; - uint32_t *pSurfaceFormatCount; - VkSurfaceFormatKHR *pSurfaceFormats; - VkResult result; -}; - -struct vkGetPhysicalDeviceSurfacePresentModesKHR_params -{ - VkPhysicalDevice physicalDevice; - VkSurfaceKHR DECLSPEC_ALIGN(8) surface; - uint32_t *pPresentModeCount; - VkPresentModeKHR *pPresentModes; - VkResult result; -}; - -struct vkGetPhysicalDeviceSurfaceSupportKHR_params -{ - VkPhysicalDevice physicalDevice; - uint32_t queueFamilyIndex; - VkSurfaceKHR DECLSPEC_ALIGN(8) surface; - VkBool32 *pSupported; - VkResult result; -}; - -struct vkGetPhysicalDeviceToolProperties_params -{ - VkPhysicalDevice physicalDevice; - uint32_t *pToolCount; - VkPhysicalDeviceToolProperties *pToolProperties; - VkResult result; -}; - -struct vkGetPhysicalDeviceToolPropertiesEXT_params -{ - VkPhysicalDevice physicalDevice; - uint32_t *pToolCount; - VkPhysicalDeviceToolProperties *pToolProperties; - VkResult result; -}; - -struct vkGetPhysicalDeviceWin32PresentationSupportKHR_params -{ - VkPhysicalDevice physicalDevice; - uint32_t queueFamilyIndex; - VkBool32 result; -}; - -struct vkGetPipelineCacheData_params -{ - VkDevice device; - VkPipelineCache DECLSPEC_ALIGN(8) pipelineCache; - size_t *pDataSize; - void *pData; - VkResult result; -}; - -struct vkGetPipelineExecutableInternalRepresentationsKHR_params -{ - VkDevice device; - const VkPipelineExecutableInfoKHR *pExecutableInfo; - uint32_t *pInternalRepresentationCount; - VkPipelineExecutableInternalRepresentationKHR *pInternalRepresentations; - VkResult result; -}; - -struct vkGetPipelineExecutablePropertiesKHR_params -{ - VkDevice device; - const VkPipelineInfoKHR *pPipelineInfo; - uint32_t *pExecutableCount; - VkPipelineExecutablePropertiesKHR *pProperties; - VkResult result; -}; - -struct vkGetPipelineExecutableStatisticsKHR_params -{ - VkDevice device; - const VkPipelineExecutableInfoKHR *pExecutableInfo; - uint32_t *pStatisticCount; - VkPipelineExecutableStatisticKHR *pStatistics; - VkResult result; -}; - -struct vkGetPipelinePropertiesEXT_params -{ - VkDevice device; - const VkPipelineInfoEXT *pPipelineInfo; - VkBaseOutStructure *pPipelineProperties; - VkResult result; -}; - -struct vkGetPrivateData_params -{ - VkDevice device; - VkObjectType objectType; - uint64_t DECLSPEC_ALIGN(8) objectHandle; - VkPrivateDataSlot DECLSPEC_ALIGN(8) privateDataSlot; - uint64_t *pData; -}; - -struct vkGetPrivateDataEXT_params -{ - VkDevice device; - VkObjectType objectType; - uint64_t DECLSPEC_ALIGN(8) objectHandle; - VkPrivateDataSlot DECLSPEC_ALIGN(8) privateDataSlot; - uint64_t *pData; -}; - -struct vkGetQueryPoolResults_params -{ - VkDevice device; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t firstQuery; - uint32_t queryCount; - size_t dataSize; - void *pData; - VkDeviceSize DECLSPEC_ALIGN(8) stride; - VkQueryResultFlags flags; - VkResult result; -}; - -struct vkGetQueueCheckpointData2NV_params -{ - VkQueue queue; - uint32_t *pCheckpointDataCount; - VkCheckpointData2NV *pCheckpointData; -}; - -struct vkGetQueueCheckpointDataNV_params -{ - VkQueue queue; - uint32_t *pCheckpointDataCount; - VkCheckpointDataNV *pCheckpointData; -}; - -struct vkGetRayTracingCaptureReplayShaderGroupHandlesKHR_params -{ - VkDevice device; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - uint32_t firstGroup; - uint32_t groupCount; - size_t dataSize; - void *pData; - VkResult result; -}; - -struct vkGetRayTracingShaderGroupHandlesKHR_params -{ - VkDevice device; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - uint32_t firstGroup; - uint32_t groupCount; - size_t dataSize; - void *pData; - VkResult result; -}; - -struct vkGetRayTracingShaderGroupHandlesNV_params -{ - VkDevice device; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - uint32_t firstGroup; - uint32_t groupCount; - size_t dataSize; - void *pData; - VkResult result; -}; - -struct vkGetRayTracingShaderGroupStackSizeKHR_params -{ - VkDevice device; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - uint32_t group; - VkShaderGroupShaderKHR groupShader; - VkDeviceSize result; -}; - -struct vkGetRenderAreaGranularity_params -{ - VkDevice device; - VkRenderPass DECLSPEC_ALIGN(8) renderPass; - VkExtent2D *pGranularity; -}; - -struct vkGetSamplerOpaqueCaptureDescriptorDataEXT_params -{ - VkDevice device; - const VkSamplerCaptureDescriptorDataInfoEXT *pInfo; - void *pData; - VkResult result; -}; - -struct vkGetSemaphoreCounterValue_params -{ - VkDevice device; - VkSemaphore DECLSPEC_ALIGN(8) semaphore; - uint64_t *pValue; - VkResult result; -}; - -struct vkGetSemaphoreCounterValueKHR_params -{ - VkDevice device; - VkSemaphore DECLSPEC_ALIGN(8) semaphore; - uint64_t *pValue; - VkResult result; -}; - -struct vkGetShaderInfoAMD_params -{ - VkDevice device; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - VkShaderStageFlagBits shaderStage; - VkShaderInfoTypeAMD infoType; - size_t *pInfoSize; - void *pInfo; - VkResult result; -}; - -struct vkGetShaderModuleCreateInfoIdentifierEXT_params -{ - VkDevice device; - const VkShaderModuleCreateInfo *pCreateInfo; - VkShaderModuleIdentifierEXT *pIdentifier; -}; - -struct vkGetShaderModuleIdentifierEXT_params -{ - VkDevice device; - VkShaderModule DECLSPEC_ALIGN(8) shaderModule; - VkShaderModuleIdentifierEXT *pIdentifier; -}; - -struct vkGetSwapchainImagesKHR_params -{ - VkDevice device; - VkSwapchainKHR DECLSPEC_ALIGN(8) swapchain; - uint32_t *pSwapchainImageCount; - VkImage *pSwapchainImages; - VkResult result; -}; - -struct vkGetValidationCacheDataEXT_params -{ - VkDevice device; - VkValidationCacheEXT DECLSPEC_ALIGN(8) validationCache; - size_t *pDataSize; - void *pData; - VkResult result; -}; - -struct vkInitializePerformanceApiINTEL_params -{ - VkDevice device; - const VkInitializePerformanceApiInfoINTEL *pInitializeInfo; - VkResult result; -}; - -struct vkInvalidateMappedMemoryRanges_params -{ - VkDevice device; - uint32_t memoryRangeCount; - const VkMappedMemoryRange *pMemoryRanges; - VkResult result; -}; - -struct vkMapMemory_params -{ - VkDevice device; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkDeviceSize DECLSPEC_ALIGN(8) size; - VkMemoryMapFlags flags; - void **ppData; - VkResult result; -}; - -struct vkMergePipelineCaches_params -{ - VkDevice device; - VkPipelineCache DECLSPEC_ALIGN(8) dstCache; - uint32_t srcCacheCount; - const VkPipelineCache *pSrcCaches; - VkResult result; -}; - -struct vkMergeValidationCachesEXT_params -{ - VkDevice device; - VkValidationCacheEXT DECLSPEC_ALIGN(8) dstCache; - uint32_t srcCacheCount; - const VkValidationCacheEXT *pSrcCaches; - VkResult result; -}; - -struct vkQueueBeginDebugUtilsLabelEXT_params -{ - VkQueue queue; - const VkDebugUtilsLabelEXT *pLabelInfo; -}; - -struct vkQueueBindSparse_params -{ - VkQueue queue; - uint32_t bindInfoCount; - const VkBindSparseInfo *pBindInfo; - VkFence DECLSPEC_ALIGN(8) fence; - VkResult result; -}; - -struct vkQueueEndDebugUtilsLabelEXT_params -{ - VkQueue queue; -}; - -struct vkQueueInsertDebugUtilsLabelEXT_params -{ - VkQueue queue; - const VkDebugUtilsLabelEXT *pLabelInfo; -}; - -struct vkQueuePresentKHR_params -{ - VkQueue queue; - const VkPresentInfoKHR *pPresentInfo; - VkResult result; -}; - -struct vkQueueSetPerformanceConfigurationINTEL_params -{ - VkQueue queue; - VkPerformanceConfigurationINTEL DECLSPEC_ALIGN(8) configuration; - VkResult result; -}; - -struct vkQueueSubmit_params -{ - VkQueue queue; - uint32_t submitCount; - const VkSubmitInfo *pSubmits; - VkFence DECLSPEC_ALIGN(8) fence; - VkResult result; -}; - -struct vkQueueSubmit2_params -{ - VkQueue queue; - uint32_t submitCount; - const VkSubmitInfo2 *pSubmits; - VkFence DECLSPEC_ALIGN(8) fence; - VkResult result; -}; - -struct vkQueueSubmit2KHR_params -{ - VkQueue queue; - uint32_t submitCount; - const VkSubmitInfo2 *pSubmits; - VkFence DECLSPEC_ALIGN(8) fence; - VkResult result; -}; - -struct vkQueueWaitIdle_params -{ - VkQueue queue; - VkResult result; -}; - -struct vkReleasePerformanceConfigurationINTEL_params -{ - VkDevice device; - VkPerformanceConfigurationINTEL DECLSPEC_ALIGN(8) configuration; - VkResult result; -}; - -struct vkReleaseProfilingLockKHR_params -{ - VkDevice device; -}; - -struct vkReleaseSwapchainImagesEXT_params -{ - VkDevice device; - const VkReleaseSwapchainImagesInfoEXT *pReleaseInfo; - VkResult result; -}; - -struct vkResetCommandBuffer_params -{ - VkCommandBuffer commandBuffer; - VkCommandBufferResetFlags flags; - VkResult result; -}; - -struct vkResetCommandPool_params -{ - VkDevice device; - VkCommandPool DECLSPEC_ALIGN(8) commandPool; - VkCommandPoolResetFlags flags; - VkResult result; -}; - -struct vkResetDescriptorPool_params -{ - VkDevice device; - VkDescriptorPool DECLSPEC_ALIGN(8) descriptorPool; - VkDescriptorPoolResetFlags flags; - VkResult result; -}; - -struct vkResetEvent_params -{ - VkDevice device; - VkEvent DECLSPEC_ALIGN(8) event; - VkResult result; -}; - -struct vkResetFences_params -{ - VkDevice device; - uint32_t fenceCount; - const VkFence *pFences; - VkResult result; -}; - -struct vkResetQueryPool_params -{ - VkDevice device; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t firstQuery; - uint32_t queryCount; -}; - -struct vkResetQueryPoolEXT_params -{ - VkDevice device; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t firstQuery; - uint32_t queryCount; -}; - -struct vkSetDebugUtilsObjectNameEXT_params -{ - VkDevice device; - const VkDebugUtilsObjectNameInfoEXT *pNameInfo; - VkResult result; -}; - -struct vkSetDebugUtilsObjectTagEXT_params -{ - VkDevice device; - const VkDebugUtilsObjectTagInfoEXT *pTagInfo; - VkResult result; -}; - -struct vkSetDeviceMemoryPriorityEXT_params -{ - VkDevice device; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - float priority; -}; - -struct vkSetEvent_params -{ - VkDevice device; - VkEvent DECLSPEC_ALIGN(8) event; - VkResult result; -}; - -struct vkSetPrivateData_params -{ - VkDevice device; - VkObjectType objectType; - uint64_t DECLSPEC_ALIGN(8) objectHandle; - VkPrivateDataSlot DECLSPEC_ALIGN(8) privateDataSlot; - uint64_t DECLSPEC_ALIGN(8) data; - VkResult result; -}; - -struct vkSetPrivateDataEXT_params -{ - VkDevice device; - VkObjectType objectType; - uint64_t DECLSPEC_ALIGN(8) objectHandle; - VkPrivateDataSlot DECLSPEC_ALIGN(8) privateDataSlot; - uint64_t DECLSPEC_ALIGN(8) data; - VkResult result; -}; - -struct vkSignalSemaphore_params -{ - VkDevice device; - const VkSemaphoreSignalInfo *pSignalInfo; - VkResult result; -}; - -struct vkSignalSemaphoreKHR_params -{ - VkDevice device; - const VkSemaphoreSignalInfo *pSignalInfo; - VkResult result; -}; - -struct vkSubmitDebugUtilsMessageEXT_params -{ - VkInstance instance; - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity; - VkDebugUtilsMessageTypeFlagsEXT messageTypes; - const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData; -}; - -struct vkTrimCommandPool_params -{ - VkDevice device; - VkCommandPool DECLSPEC_ALIGN(8) commandPool; - VkCommandPoolTrimFlags flags; -}; - -struct vkTrimCommandPoolKHR_params -{ - VkDevice device; - VkCommandPool DECLSPEC_ALIGN(8) commandPool; - VkCommandPoolTrimFlags flags; -}; - -struct vkUninitializePerformanceApiINTEL_params -{ - VkDevice device; -}; - -struct vkUnmapMemory_params -{ - VkDevice device; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; -}; - -struct vkUpdateDescriptorSetWithTemplate_params -{ - VkDevice device; - VkDescriptorSet DECLSPEC_ALIGN(8) descriptorSet; - VkDescriptorUpdateTemplate DECLSPEC_ALIGN(8) descriptorUpdateTemplate; - const void *pData; -}; - -struct vkUpdateDescriptorSetWithTemplateKHR_params -{ - VkDevice device; - VkDescriptorSet DECLSPEC_ALIGN(8) descriptorSet; - VkDescriptorUpdateTemplate DECLSPEC_ALIGN(8) descriptorUpdateTemplate; - const void *pData; -}; - -struct vkUpdateDescriptorSets_params -{ - VkDevice device; - uint32_t descriptorWriteCount; - const VkWriteDescriptorSet *pDescriptorWrites; - uint32_t descriptorCopyCount; - const VkCopyDescriptorSet *pDescriptorCopies; -}; - -struct vkWaitForFences_params -{ - VkDevice device; - uint32_t fenceCount; - const VkFence *pFences; - VkBool32 waitAll; - uint64_t DECLSPEC_ALIGN(8) timeout; - VkResult result; -}; - -struct vkWaitForPresentKHR_params -{ - VkDevice device; - VkSwapchainKHR DECLSPEC_ALIGN(8) swapchain; - uint64_t DECLSPEC_ALIGN(8) presentId; - uint64_t DECLSPEC_ALIGN(8) timeout; - VkResult result; -}; - -struct vkWaitSemaphores_params -{ - VkDevice device; - const VkSemaphoreWaitInfo *pWaitInfo; - uint64_t DECLSPEC_ALIGN(8) timeout; - VkResult result; -}; - -struct vkWaitSemaphoresKHR_params -{ - VkDevice device; - const VkSemaphoreWaitInfo *pWaitInfo; - uint64_t DECLSPEC_ALIGN(8) timeout; - VkResult result; -}; - -struct vkWriteAccelerationStructuresPropertiesKHR_params -{ - VkDevice device; - uint32_t accelerationStructureCount; - const VkAccelerationStructureKHR *pAccelerationStructures; - VkQueryType queryType; - size_t dataSize; - void *pData; - size_t stride; - VkResult result; -}; - -struct vkWriteMicromapsPropertiesEXT_params -{ - VkDevice device; - uint32_t micromapCount; - const VkMicromapEXT *pMicromaps; - VkQueryType queryType; - size_t dataSize; - void *pData; - size_t stride; - VkResult result; -}; - -#endif /* __WINE_VULKAN_LOADER_THUNKS_H */ diff --git a/dlls/winevulkan/vulkan_thunks.c b/dlls/winevulkan/vulkan_thunks.c deleted file mode 100644 index 8cf554b6fff..00000000000 --- a/dlls/winevulkan/vulkan_thunks.c +++ /dev/null @@ -1,41346 +0,0 @@ -/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! - * - * This file is generated from Vulkan vk.xml file covered - * by the following copyright and permission notice: - * - * Copyright 2015-2022 The Khronos Group Inc. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#if 0 -#pragma makedep unix -#endif - -#include "config.h" - -#include - -#include "vulkan_private.h" - -WINE_DEFAULT_DEBUG_CHANNEL(vulkan); - -typedef struct VkAcquireNextImageInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkSwapchainKHR DECLSPEC_ALIGN(8) swapchain; - uint64_t DECLSPEC_ALIGN(8) timeout; - VkSemaphore DECLSPEC_ALIGN(8) semaphore; - VkFence DECLSPEC_ALIGN(8) fence; - uint32_t deviceMask; -} VkAcquireNextImageInfoKHR32; - -typedef struct VkPerformanceConfigurationAcquireInfoINTEL32 -{ - VkStructureType sType; - PTR32 pNext; - VkPerformanceConfigurationTypeINTEL type; -} VkPerformanceConfigurationAcquireInfoINTEL32; - -typedef struct VkAcquireProfilingLockInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkAcquireProfilingLockFlagsKHR flags; - uint64_t DECLSPEC_ALIGN(8) timeout; -} VkAcquireProfilingLockInfoKHR32; - -typedef struct VkCommandBufferAllocateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkCommandPool DECLSPEC_ALIGN(8) commandPool; - VkCommandBufferLevel level; - uint32_t commandBufferCount; -} VkCommandBufferAllocateInfo32; - -typedef struct VkDescriptorSetVariableDescriptorCountAllocateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t descriptorSetCount; - PTR32 pDescriptorCounts; -} VkDescriptorSetVariableDescriptorCountAllocateInfo32; -typedef VkDescriptorSetVariableDescriptorCountAllocateInfo32 VkDescriptorSetVariableDescriptorCountAllocateInfoEXT32; - -typedef struct VkDescriptorSetAllocateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkDescriptorPool DECLSPEC_ALIGN(8) descriptorPool; - uint32_t descriptorSetCount; - PTR32 pSetLayouts; -} VkDescriptorSetAllocateInfo32; - -typedef struct VkDedicatedAllocationMemoryAllocateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkImage DECLSPEC_ALIGN(8) image; - VkBuffer DECLSPEC_ALIGN(8) buffer; -} VkDedicatedAllocationMemoryAllocateInfoNV32; - -typedef struct VkExportMemoryAllocateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkExternalMemoryHandleTypeFlags handleTypes; -} VkExportMemoryAllocateInfo32; -typedef VkExportMemoryAllocateInfo32 VkExportMemoryAllocateInfoKHR32; - -typedef struct VkImportMemoryWin32HandleInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkExternalMemoryHandleTypeFlagBits handleType; - HANDLE handle; - LPCWSTR name; -} VkImportMemoryWin32HandleInfoKHR32; - -typedef struct VkExportMemoryWin32HandleInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 pAttributes; - DWORD dwAccess; - LPCWSTR name; -} VkExportMemoryWin32HandleInfoKHR32; - -typedef struct VkMemoryAllocateFlagsInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkMemoryAllocateFlags flags; - uint32_t deviceMask; -} VkMemoryAllocateFlagsInfo32; -typedef VkMemoryAllocateFlagsInfo32 VkMemoryAllocateFlagsInfoKHR32; - -typedef struct VkMemoryDedicatedAllocateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkImage DECLSPEC_ALIGN(8) image; - VkBuffer DECLSPEC_ALIGN(8) buffer; -} VkMemoryDedicatedAllocateInfo32; -typedef VkMemoryDedicatedAllocateInfo32 VkMemoryDedicatedAllocateInfoKHR32; - -typedef struct VkImportMemoryHostPointerInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkExternalMemoryHandleTypeFlagBits handleType; - PTR32 pHostPointer; -} VkImportMemoryHostPointerInfoEXT32; - -typedef struct VkMemoryPriorityAllocateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - float priority; -} VkMemoryPriorityAllocateInfoEXT32; - -typedef struct VkMemoryOpaqueCaptureAddressAllocateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint64_t DECLSPEC_ALIGN(8) opaqueCaptureAddress; -} VkMemoryOpaqueCaptureAddressAllocateInfo32; -typedef VkMemoryOpaqueCaptureAddressAllocateInfo32 VkMemoryOpaqueCaptureAddressAllocateInfoKHR32; - -typedef struct VkMemoryAllocateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceSize DECLSPEC_ALIGN(8) allocationSize; - uint32_t memoryTypeIndex; -} VkMemoryAllocateInfo32; - -typedef struct VkCommandBufferInheritanceConditionalRenderingInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 conditionalRenderingEnable; -} VkCommandBufferInheritanceConditionalRenderingInfoEXT32; - -typedef struct VkCommandBufferInheritanceRenderPassTransformInfoQCOM32 -{ - VkStructureType sType; - PTR32 pNext; - VkSurfaceTransformFlagBitsKHR transform; - VkRect2D renderArea; -} VkCommandBufferInheritanceRenderPassTransformInfoQCOM32; - -typedef struct VkCommandBufferInheritanceViewportScissorInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 viewportScissor2D; - uint32_t viewportDepthCount; - PTR32 pViewportDepths; -} VkCommandBufferInheritanceViewportScissorInfoNV32; - -typedef struct VkCommandBufferInheritanceRenderingInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkRenderingFlags flags; - uint32_t viewMask; - uint32_t colorAttachmentCount; - PTR32 pColorAttachmentFormats; - VkFormat depthAttachmentFormat; - VkFormat stencilAttachmentFormat; - VkSampleCountFlagBits rasterizationSamples; -} VkCommandBufferInheritanceRenderingInfo32; -typedef VkCommandBufferInheritanceRenderingInfo32 VkCommandBufferInheritanceRenderingInfoKHR32; - -typedef struct VkAttachmentSampleCountInfoAMD32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t colorAttachmentCount; - PTR32 pColorAttachmentSamples; - VkSampleCountFlagBits depthStencilAttachmentSamples; -} VkAttachmentSampleCountInfoAMD32; -typedef VkAttachmentSampleCountInfoAMD32 VkAttachmentSampleCountInfoNV32; - -typedef struct VkMultiviewPerViewAttributesInfoNVX32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 perViewAttributes; - VkBool32 perViewAttributesPositionXOnly; -} VkMultiviewPerViewAttributesInfoNVX32; - -typedef struct VkCommandBufferInheritanceInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkRenderPass DECLSPEC_ALIGN(8) renderPass; - uint32_t subpass; - VkFramebuffer DECLSPEC_ALIGN(8) framebuffer; - VkBool32 occlusionQueryEnable; - VkQueryControlFlags queryFlags; - VkQueryPipelineStatisticFlags pipelineStatistics; -} VkCommandBufferInheritanceInfo32; - -typedef struct VkDeviceGroupCommandBufferBeginInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t deviceMask; -} VkDeviceGroupCommandBufferBeginInfo32; -typedef VkDeviceGroupCommandBufferBeginInfo32 VkDeviceGroupCommandBufferBeginInfoKHR32; - -typedef struct VkCommandBufferBeginInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkCommandBufferUsageFlags flags; - PTR32 pInheritanceInfo; -} VkCommandBufferBeginInfo32; - -typedef struct VkBindAccelerationStructureMemoryInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkAccelerationStructureNV DECLSPEC_ALIGN(8) accelerationStructure; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - VkDeviceSize DECLSPEC_ALIGN(8) memoryOffset; - uint32_t deviceIndexCount; - PTR32 pDeviceIndices; -} VkBindAccelerationStructureMemoryInfoNV32; - -typedef struct VkBindBufferMemoryDeviceGroupInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t deviceIndexCount; - PTR32 pDeviceIndices; -} VkBindBufferMemoryDeviceGroupInfo32; -typedef VkBindBufferMemoryDeviceGroupInfo32 VkBindBufferMemoryDeviceGroupInfoKHR32; - -typedef struct VkBindBufferMemoryInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - VkDeviceSize DECLSPEC_ALIGN(8) memoryOffset; -} VkBindBufferMemoryInfo32; -typedef VkBindBufferMemoryInfo32 VkBindBufferMemoryInfoKHR32; - -typedef struct VkBindImageMemoryDeviceGroupInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t deviceIndexCount; - PTR32 pDeviceIndices; - uint32_t splitInstanceBindRegionCount; - PTR32 pSplitInstanceBindRegions; -} VkBindImageMemoryDeviceGroupInfo32; -typedef VkBindImageMemoryDeviceGroupInfo32 VkBindImageMemoryDeviceGroupInfoKHR32; - -typedef struct VkBindImageMemorySwapchainInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkSwapchainKHR DECLSPEC_ALIGN(8) swapchain; - uint32_t imageIndex; -} VkBindImageMemorySwapchainInfoKHR32; - -typedef struct VkBindImagePlaneMemoryInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageAspectFlagBits planeAspect; -} VkBindImagePlaneMemoryInfo32; -typedef VkBindImagePlaneMemoryInfo32 VkBindImagePlaneMemoryInfoKHR32; - -typedef struct VkBindImageMemoryInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkImage DECLSPEC_ALIGN(8) image; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - VkDeviceSize DECLSPEC_ALIGN(8) memoryOffset; -} VkBindImageMemoryInfo32; -typedef VkBindImageMemoryInfo32 VkBindImageMemoryInfoKHR32; - -typedef struct VkAccelerationStructureGeometryMotionTrianglesDataNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceOrHostAddressConstKHR DECLSPEC_ALIGN(8) vertexData; -} VkAccelerationStructureGeometryMotionTrianglesDataNV32; - -typedef struct VkAccelerationStructureTrianglesOpacityMicromapEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkIndexType indexType; - VkDeviceOrHostAddressConstKHR DECLSPEC_ALIGN(8) indexBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) indexStride; - uint32_t baseTriangle; - uint32_t usageCountsCount; - PTR32 pUsageCounts; - PTR32 ppUsageCounts; - VkMicromapEXT DECLSPEC_ALIGN(8) micromap; -} VkAccelerationStructureTrianglesOpacityMicromapEXT32; - -typedef struct VkAccelerationStructureGeometryTrianglesDataKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkFormat vertexFormat; - VkDeviceOrHostAddressConstKHR DECLSPEC_ALIGN(8) vertexData; - VkDeviceSize DECLSPEC_ALIGN(8) vertexStride; - uint32_t maxVertex; - VkIndexType indexType; - VkDeviceOrHostAddressConstKHR DECLSPEC_ALIGN(8) indexData; - VkDeviceOrHostAddressConstKHR DECLSPEC_ALIGN(8) transformData; -} VkAccelerationStructureGeometryTrianglesDataKHR32; - -typedef struct VkAccelerationStructureGeometryAabbsDataKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceOrHostAddressConstKHR DECLSPEC_ALIGN(8) data; - VkDeviceSize DECLSPEC_ALIGN(8) stride; -} VkAccelerationStructureGeometryAabbsDataKHR32; - -typedef struct VkAccelerationStructureGeometryInstancesDataKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 arrayOfPointers; - VkDeviceOrHostAddressConstKHR DECLSPEC_ALIGN(8) data; -} VkAccelerationStructureGeometryInstancesDataKHR32; - -typedef union VkAccelerationStructureGeometryDataKHR32 -{ - VkAccelerationStructureGeometryTrianglesDataKHR32 DECLSPEC_ALIGN(8) triangles; - VkAccelerationStructureGeometryAabbsDataKHR32 DECLSPEC_ALIGN(8) aabbs; - VkAccelerationStructureGeometryInstancesDataKHR32 DECLSPEC_ALIGN(8) instances; -} VkAccelerationStructureGeometryDataKHR32; - -typedef struct VkAccelerationStructureGeometryKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkGeometryTypeKHR geometryType; - VkAccelerationStructureGeometryDataKHR32 DECLSPEC_ALIGN(8) geometry; - VkGeometryFlagsKHR flags; -} VkAccelerationStructureGeometryKHR32; - -typedef struct VkAccelerationStructureBuildGeometryInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkAccelerationStructureTypeKHR type; - VkBuildAccelerationStructureFlagsKHR flags; - VkBuildAccelerationStructureModeKHR mode; - VkAccelerationStructureKHR DECLSPEC_ALIGN(8) srcAccelerationStructure; - VkAccelerationStructureKHR DECLSPEC_ALIGN(8) dstAccelerationStructure; - uint32_t geometryCount; - PTR32 pGeometries; - PTR32 ppGeometries; - VkDeviceOrHostAddressKHR DECLSPEC_ALIGN(8) scratchData; -} VkAccelerationStructureBuildGeometryInfoKHR32; - -typedef struct VkMicromapBuildInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkMicromapTypeEXT type; - VkBuildMicromapFlagsEXT flags; - VkBuildMicromapModeEXT mode; - VkMicromapEXT DECLSPEC_ALIGN(8) dstMicromap; - uint32_t usageCountsCount; - PTR32 pUsageCounts; - PTR32 ppUsageCounts; - VkDeviceOrHostAddressConstKHR DECLSPEC_ALIGN(8) data; - VkDeviceOrHostAddressKHR DECLSPEC_ALIGN(8) scratchData; - VkDeviceOrHostAddressConstKHR DECLSPEC_ALIGN(8) triangleArray; - VkDeviceSize DECLSPEC_ALIGN(8) triangleArrayStride; -} VkMicromapBuildInfoEXT32; - -typedef struct VkConditionalRenderingBeginInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkConditionalRenderingFlagsEXT flags; -} VkConditionalRenderingBeginInfoEXT32; - -typedef struct VkDebugUtilsLabelEXT32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 pLabelName; - float color[4]; -} VkDebugUtilsLabelEXT32; - -typedef struct VkSampleLocationsInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkSampleCountFlagBits sampleLocationsPerPixel; - VkExtent2D sampleLocationGridSize; - uint32_t sampleLocationsCount; - PTR32 pSampleLocations; -} VkSampleLocationsInfoEXT32; - -typedef struct VkAttachmentSampleLocationsEXT32 -{ - uint32_t attachmentIndex; - VkSampleLocationsInfoEXT32 sampleLocationsInfo; -} VkAttachmentSampleLocationsEXT32; - -typedef struct VkSubpassSampleLocationsEXT32 -{ - uint32_t subpassIndex; - VkSampleLocationsInfoEXT32 sampleLocationsInfo; -} VkSubpassSampleLocationsEXT32; - -typedef struct VkDeviceGroupRenderPassBeginInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t deviceMask; - uint32_t deviceRenderAreaCount; - PTR32 pDeviceRenderAreas; -} VkDeviceGroupRenderPassBeginInfo32; -typedef VkDeviceGroupRenderPassBeginInfo32 VkDeviceGroupRenderPassBeginInfoKHR32; - -typedef struct VkRenderPassSampleLocationsBeginInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t attachmentInitialSampleLocationsCount; - PTR32 pAttachmentInitialSampleLocations; - uint32_t postSubpassSampleLocationsCount; - PTR32 pPostSubpassSampleLocations; -} VkRenderPassSampleLocationsBeginInfoEXT32; - -typedef struct VkRenderPassAttachmentBeginInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t attachmentCount; - PTR32 pAttachments; -} VkRenderPassAttachmentBeginInfo32; -typedef VkRenderPassAttachmentBeginInfo32 VkRenderPassAttachmentBeginInfoKHR32; - -typedef struct VkRenderPassTransformBeginInfoQCOM32 -{ - VkStructureType sType; - PTR32 pNext; - VkSurfaceTransformFlagBitsKHR transform; -} VkRenderPassTransformBeginInfoQCOM32; - -typedef struct VkRenderPassBeginInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkRenderPass DECLSPEC_ALIGN(8) renderPass; - VkFramebuffer DECLSPEC_ALIGN(8) framebuffer; - VkRect2D renderArea; - uint32_t clearValueCount; - PTR32 pClearValues; -} VkRenderPassBeginInfo32; - -typedef struct VkSubpassBeginInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkSubpassContents contents; -} VkSubpassBeginInfo32; -typedef VkSubpassBeginInfo32 VkSubpassBeginInfoKHR32; - -typedef struct VkRenderingAttachmentInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageView DECLSPEC_ALIGN(8) imageView; - VkImageLayout imageLayout; - VkResolveModeFlagBits resolveMode; - VkImageView DECLSPEC_ALIGN(8) resolveImageView; - VkImageLayout resolveImageLayout; - VkAttachmentLoadOp loadOp; - VkAttachmentStoreOp storeOp; - VkClearValue clearValue; -} VkRenderingAttachmentInfo32; -typedef VkRenderingAttachmentInfo32 VkRenderingAttachmentInfoKHR32; - -typedef struct VkMultisampledRenderToSingleSampledInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 multisampledRenderToSingleSampledEnable; - VkSampleCountFlagBits rasterizationSamples; -} VkMultisampledRenderToSingleSampledInfoEXT32; - -typedef struct VkRenderingFragmentShadingRateAttachmentInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageView DECLSPEC_ALIGN(8) imageView; - VkImageLayout imageLayout; - VkExtent2D shadingRateAttachmentTexelSize; -} VkRenderingFragmentShadingRateAttachmentInfoKHR32; - -typedef struct VkRenderingFragmentDensityMapAttachmentInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageView DECLSPEC_ALIGN(8) imageView; - VkImageLayout imageLayout; -} VkRenderingFragmentDensityMapAttachmentInfoEXT32; - -typedef struct VkRenderingInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkRenderingFlags flags; - VkRect2D renderArea; - uint32_t layerCount; - uint32_t viewMask; - uint32_t colorAttachmentCount; - PTR32 pColorAttachments; - PTR32 pDepthAttachment; - PTR32 pStencilAttachment; -} VkRenderingInfo32; -typedef VkRenderingInfo32 VkRenderingInfoKHR32; - -typedef struct VkDescriptorBufferBindingPushDescriptorBufferHandleEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBuffer DECLSPEC_ALIGN(8) buffer; -} VkDescriptorBufferBindingPushDescriptorBufferHandleEXT32; - -typedef struct VkDescriptorBufferBindingInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceAddress DECLSPEC_ALIGN(8) address; - VkBufferUsageFlags usage; -} VkDescriptorBufferBindingInfoEXT32; - -typedef struct VkCopyCommandTransformInfoQCOM32 -{ - VkStructureType sType; - PTR32 pNext; - VkSurfaceTransformFlagBitsKHR transform; -} VkCopyCommandTransformInfoQCOM32; - -typedef struct VkImageBlit232 -{ - VkStructureType sType; - PTR32 pNext; - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffsets[2]; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffsets[2]; -} VkImageBlit232; -typedef VkImageBlit232 VkImageBlit2KHR32; - -typedef struct VkBlitImageInfo232 -{ - VkStructureType sType; - PTR32 pNext; - VkImage DECLSPEC_ALIGN(8) srcImage; - VkImageLayout srcImageLayout; - VkImage DECLSPEC_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - PTR32 pRegions; - VkFilter filter; -} VkBlitImageInfo232; -typedef VkBlitImageInfo232 VkBlitImageInfo2KHR32; - -typedef struct VkGeometryTrianglesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBuffer DECLSPEC_ALIGN(8) vertexData; - VkDeviceSize DECLSPEC_ALIGN(8) vertexOffset; - uint32_t vertexCount; - VkDeviceSize DECLSPEC_ALIGN(8) vertexStride; - VkFormat vertexFormat; - VkBuffer DECLSPEC_ALIGN(8) indexData; - VkDeviceSize DECLSPEC_ALIGN(8) indexOffset; - uint32_t indexCount; - VkIndexType indexType; - VkBuffer DECLSPEC_ALIGN(8) transformData; - VkDeviceSize DECLSPEC_ALIGN(8) transformOffset; -} VkGeometryTrianglesNV32; - -typedef struct VkGeometryAABBNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBuffer DECLSPEC_ALIGN(8) aabbData; - uint32_t numAABBs; - uint32_t stride; - VkDeviceSize DECLSPEC_ALIGN(8) offset; -} VkGeometryAABBNV32; - -typedef struct VkGeometryDataNV32 -{ - VkGeometryTrianglesNV32 DECLSPEC_ALIGN(8) triangles; - VkGeometryAABBNV32 DECLSPEC_ALIGN(8) aabbs; -} VkGeometryDataNV32; - -typedef struct VkGeometryNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkGeometryTypeKHR geometryType; - VkGeometryDataNV32 DECLSPEC_ALIGN(8) geometry; - VkGeometryFlagsKHR flags; -} VkGeometryNV32; - -typedef struct VkAccelerationStructureInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkAccelerationStructureTypeNV type; - VkBuildAccelerationStructureFlagsNV flags; - uint32_t instanceCount; - uint32_t geometryCount; - PTR32 pGeometries; -} VkAccelerationStructureInfoNV32; - -typedef struct VkCopyAccelerationStructureInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkAccelerationStructureKHR DECLSPEC_ALIGN(8) src; - VkAccelerationStructureKHR DECLSPEC_ALIGN(8) dst; - VkCopyAccelerationStructureModeKHR mode; -} VkCopyAccelerationStructureInfoKHR32; - -typedef struct VkCopyAccelerationStructureToMemoryInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkAccelerationStructureKHR DECLSPEC_ALIGN(8) src; - VkDeviceOrHostAddressKHR DECLSPEC_ALIGN(8) dst; - VkCopyAccelerationStructureModeKHR mode; -} VkCopyAccelerationStructureToMemoryInfoKHR32; - -typedef struct VkBufferCopy32 -{ - VkDeviceSize DECLSPEC_ALIGN(8) srcOffset; - VkDeviceSize DECLSPEC_ALIGN(8) dstOffset; - VkDeviceSize DECLSPEC_ALIGN(8) size; -} VkBufferCopy32; - -typedef struct VkBufferCopy232 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceSize DECLSPEC_ALIGN(8) srcOffset; - VkDeviceSize DECLSPEC_ALIGN(8) dstOffset; - VkDeviceSize DECLSPEC_ALIGN(8) size; -} VkBufferCopy232; -typedef VkBufferCopy232 VkBufferCopy2KHR32; - -typedef struct VkCopyBufferInfo232 -{ - VkStructureType sType; - PTR32 pNext; - VkBuffer DECLSPEC_ALIGN(8) srcBuffer; - VkBuffer DECLSPEC_ALIGN(8) dstBuffer; - uint32_t regionCount; - PTR32 pRegions; -} VkCopyBufferInfo232; -typedef VkCopyBufferInfo232 VkCopyBufferInfo2KHR32; - -typedef struct VkBufferImageCopy32 -{ - VkDeviceSize DECLSPEC_ALIGN(8) bufferOffset; - uint32_t bufferRowLength; - uint32_t bufferImageHeight; - VkImageSubresourceLayers imageSubresource; - VkOffset3D imageOffset; - VkExtent3D imageExtent; -} VkBufferImageCopy32; - -typedef struct VkBufferImageCopy232 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceSize DECLSPEC_ALIGN(8) bufferOffset; - uint32_t bufferRowLength; - uint32_t bufferImageHeight; - VkImageSubresourceLayers imageSubresource; - VkOffset3D imageOffset; - VkExtent3D imageExtent; -} VkBufferImageCopy232; -typedef VkBufferImageCopy232 VkBufferImageCopy2KHR32; - -typedef struct VkCopyBufferToImageInfo232 -{ - VkStructureType sType; - PTR32 pNext; - VkBuffer DECLSPEC_ALIGN(8) srcBuffer; - VkImage DECLSPEC_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - PTR32 pRegions; -} VkCopyBufferToImageInfo232; -typedef VkCopyBufferToImageInfo232 VkCopyBufferToImageInfo2KHR32; - -typedef struct VkImageCopy232 -{ - VkStructureType sType; - PTR32 pNext; - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; -} VkImageCopy232; -typedef VkImageCopy232 VkImageCopy2KHR32; - -typedef struct VkCopyImageInfo232 -{ - VkStructureType sType; - PTR32 pNext; - VkImage DECLSPEC_ALIGN(8) srcImage; - VkImageLayout srcImageLayout; - VkImage DECLSPEC_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - PTR32 pRegions; -} VkCopyImageInfo232; -typedef VkCopyImageInfo232 VkCopyImageInfo2KHR32; - -typedef struct VkCopyImageToBufferInfo232 -{ - VkStructureType sType; - PTR32 pNext; - VkImage DECLSPEC_ALIGN(8) srcImage; - VkImageLayout srcImageLayout; - VkBuffer DECLSPEC_ALIGN(8) dstBuffer; - uint32_t regionCount; - PTR32 pRegions; -} VkCopyImageToBufferInfo232; -typedef VkCopyImageToBufferInfo232 VkCopyImageToBufferInfo2KHR32; - -typedef struct VkCopyMemoryToAccelerationStructureInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceOrHostAddressConstKHR DECLSPEC_ALIGN(8) src; - VkAccelerationStructureKHR DECLSPEC_ALIGN(8) dst; - VkCopyAccelerationStructureModeKHR mode; -} VkCopyMemoryToAccelerationStructureInfoKHR32; - -typedef struct VkCopyMemoryToMicromapInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceOrHostAddressConstKHR DECLSPEC_ALIGN(8) src; - VkMicromapEXT DECLSPEC_ALIGN(8) dst; - VkCopyMicromapModeEXT mode; -} VkCopyMemoryToMicromapInfoEXT32; - -typedef struct VkCopyMicromapInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkMicromapEXT DECLSPEC_ALIGN(8) src; - VkMicromapEXT DECLSPEC_ALIGN(8) dst; - VkCopyMicromapModeEXT mode; -} VkCopyMicromapInfoEXT32; - -typedef struct VkCopyMicromapToMemoryInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkMicromapEXT DECLSPEC_ALIGN(8) src; - VkDeviceOrHostAddressKHR DECLSPEC_ALIGN(8) dst; - VkCopyMicromapModeEXT mode; -} VkCopyMicromapToMemoryInfoEXT32; - -typedef struct VkCuLaunchInfoNVX32 -{ - VkStructureType sType; - PTR32 pNext; - VkCuFunctionNVX DECLSPEC_ALIGN(8) function; - uint32_t gridDimX; - uint32_t gridDimY; - uint32_t gridDimZ; - uint32_t blockDimX; - uint32_t blockDimY; - uint32_t blockDimZ; - uint32_t sharedMemBytes; - PTR32 paramCount; - PTR32 pParams; - PTR32 extraCount; - PTR32 pExtras; -} VkCuLaunchInfoNVX32; - -typedef struct VkDebugMarkerMarkerInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 pMarkerName; - float color[4]; -} VkDebugMarkerMarkerInfoEXT32; - -typedef struct VkDecompressMemoryRegionNV32 -{ - VkDeviceAddress DECLSPEC_ALIGN(8) srcAddress; - VkDeviceAddress DECLSPEC_ALIGN(8) dstAddress; - VkDeviceSize DECLSPEC_ALIGN(8) compressedSize; - VkDeviceSize DECLSPEC_ALIGN(8) decompressedSize; - VkMemoryDecompressionMethodFlagsNV DECLSPEC_ALIGN(8) decompressionMethod; -} VkDecompressMemoryRegionNV32; - -typedef struct VkSubpassFragmentDensityMapOffsetEndInfoQCOM32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t fragmentDensityOffsetCount; - PTR32 pFragmentDensityOffsets; -} VkSubpassFragmentDensityMapOffsetEndInfoQCOM32; - -typedef struct VkSubpassEndInfo32 -{ - VkStructureType sType; - PTR32 pNext; -} VkSubpassEndInfo32; -typedef VkSubpassEndInfo32 VkSubpassEndInfoKHR32; - -typedef struct VkIndirectCommandsStreamNV32 -{ - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; -} VkIndirectCommandsStreamNV32; - -typedef struct VkGeneratedCommandsInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineBindPoint pipelineBindPoint; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - VkIndirectCommandsLayoutNV DECLSPEC_ALIGN(8) indirectCommandsLayout; - uint32_t streamCount; - PTR32 pStreams; - uint32_t sequencesCount; - VkBuffer DECLSPEC_ALIGN(8) preprocessBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) preprocessOffset; - VkDeviceSize DECLSPEC_ALIGN(8) preprocessSize; - VkBuffer DECLSPEC_ALIGN(8) sequencesCountBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) sequencesCountOffset; - VkBuffer DECLSPEC_ALIGN(8) sequencesIndexBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) sequencesIndexOffset; -} VkGeneratedCommandsInfoNV32; - -typedef struct VkOpticalFlowExecuteInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkOpticalFlowExecuteFlagsNV flags; - uint32_t regionCount; - PTR32 pRegions; -} VkOpticalFlowExecuteInfoNV32; - -typedef struct VkMemoryBarrier32 -{ - VkStructureType sType; - PTR32 pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; -} VkMemoryBarrier32; - -typedef struct VkBufferMemoryBarrier32 -{ - VkStructureType sType; - PTR32 pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkDeviceSize DECLSPEC_ALIGN(8) size; -} VkBufferMemoryBarrier32; - -typedef struct VkImageMemoryBarrier32 -{ - VkStructureType sType; - PTR32 pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkImageLayout oldLayout; - VkImageLayout newLayout; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkImage DECLSPEC_ALIGN(8) image; - VkImageSubresourceRange subresourceRange; -} VkImageMemoryBarrier32; - -typedef struct VkMemoryBarrier232 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) srcStageMask; - VkAccessFlags2 DECLSPEC_ALIGN(8) srcAccessMask; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) dstStageMask; - VkAccessFlags2 DECLSPEC_ALIGN(8) dstAccessMask; -} VkMemoryBarrier232; -typedef VkMemoryBarrier232 VkMemoryBarrier2KHR32; - -typedef struct VkBufferMemoryBarrier232 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) srcStageMask; - VkAccessFlags2 DECLSPEC_ALIGN(8) srcAccessMask; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) dstStageMask; - VkAccessFlags2 DECLSPEC_ALIGN(8) dstAccessMask; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkDeviceSize DECLSPEC_ALIGN(8) size; -} VkBufferMemoryBarrier232; -typedef VkBufferMemoryBarrier232 VkBufferMemoryBarrier2KHR32; - -typedef struct VkImageMemoryBarrier232 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) srcStageMask; - VkAccessFlags2 DECLSPEC_ALIGN(8) srcAccessMask; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) dstStageMask; - VkAccessFlags2 DECLSPEC_ALIGN(8) dstAccessMask; - VkImageLayout oldLayout; - VkImageLayout newLayout; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkImage DECLSPEC_ALIGN(8) image; - VkImageSubresourceRange subresourceRange; -} VkImageMemoryBarrier232; -typedef VkImageMemoryBarrier232 VkImageMemoryBarrier2KHR32; - -typedef struct VkDependencyInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkDependencyFlags dependencyFlags; - uint32_t memoryBarrierCount; - PTR32 pMemoryBarriers; - uint32_t bufferMemoryBarrierCount; - PTR32 pBufferMemoryBarriers; - uint32_t imageMemoryBarrierCount; - PTR32 pImageMemoryBarriers; -} VkDependencyInfo32; -typedef VkDependencyInfo32 VkDependencyInfoKHR32; - -typedef struct VkDescriptorImageInfo32 -{ - VkSampler DECLSPEC_ALIGN(8) sampler; - VkImageView DECLSPEC_ALIGN(8) imageView; - VkImageLayout imageLayout; -} VkDescriptorImageInfo32; - -typedef struct VkDescriptorBufferInfo32 -{ - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkDeviceSize DECLSPEC_ALIGN(8) range; -} VkDescriptorBufferInfo32; - -typedef struct VkWriteDescriptorSetInlineUniformBlock32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t dataSize; - PTR32 pData; -} VkWriteDescriptorSetInlineUniformBlock32; -typedef VkWriteDescriptorSetInlineUniformBlock32 VkWriteDescriptorSetInlineUniformBlockEXT32; - -typedef struct VkWriteDescriptorSetAccelerationStructureKHR32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t accelerationStructureCount; - PTR32 pAccelerationStructures; -} VkWriteDescriptorSetAccelerationStructureKHR32; - -typedef struct VkWriteDescriptorSetAccelerationStructureNV32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t accelerationStructureCount; - PTR32 pAccelerationStructures; -} VkWriteDescriptorSetAccelerationStructureNV32; - -typedef struct VkWriteDescriptorSet32 -{ - VkStructureType sType; - PTR32 pNext; - VkDescriptorSet DECLSPEC_ALIGN(8) dstSet; - uint32_t dstBinding; - uint32_t dstArrayElement; - uint32_t descriptorCount; - VkDescriptorType descriptorType; - PTR32 pImageInfo; - PTR32 pBufferInfo; - PTR32 pTexelBufferView; -} VkWriteDescriptorSet32; - -typedef struct VkImageResolve232 -{ - VkStructureType sType; - PTR32 pNext; - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; -} VkImageResolve232; -typedef VkImageResolve232 VkImageResolve2KHR32; - -typedef struct VkResolveImageInfo232 -{ - VkStructureType sType; - PTR32 pNext; - VkImage DECLSPEC_ALIGN(8) srcImage; - VkImageLayout srcImageLayout; - VkImage DECLSPEC_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - PTR32 pRegions; -} VkResolveImageInfo232; -typedef VkResolveImageInfo232 VkResolveImageInfo2KHR32; - -typedef struct VkCoarseSampleOrderCustomNV32 -{ - VkShadingRatePaletteEntryNV shadingRate; - uint32_t sampleCount; - uint32_t sampleLocationCount; - PTR32 pSampleLocations; -} VkCoarseSampleOrderCustomNV32; - -typedef struct VkPerformanceMarkerInfoINTEL32 -{ - VkStructureType sType; - PTR32 pNext; - uint64_t DECLSPEC_ALIGN(8) marker; -} VkPerformanceMarkerInfoINTEL32; - -typedef struct VkPerformanceOverrideInfoINTEL32 -{ - VkStructureType sType; - PTR32 pNext; - VkPerformanceOverrideTypeINTEL type; - VkBool32 enable; - uint64_t DECLSPEC_ALIGN(8) parameter; -} VkPerformanceOverrideInfoINTEL32; - -typedef struct VkPerformanceStreamMarkerInfoINTEL32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t marker; -} VkPerformanceStreamMarkerInfoINTEL32; - -typedef struct VkVertexInputBindingDescription2EXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t binding; - uint32_t stride; - VkVertexInputRate inputRate; - uint32_t divisor; -} VkVertexInputBindingDescription2EXT32; - -typedef struct VkVertexInputAttributeDescription2EXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t location; - uint32_t binding; - VkFormat format; - uint32_t offset; -} VkVertexInputAttributeDescription2EXT32; - -typedef struct VkShadingRatePaletteNV32 -{ - uint32_t shadingRatePaletteEntryCount; - PTR32 pShadingRatePaletteEntries; -} VkShadingRatePaletteNV32; - -typedef struct VkStridedDeviceAddressRegionKHR32 -{ - VkDeviceAddress DECLSPEC_ALIGN(8) deviceAddress; - VkDeviceSize DECLSPEC_ALIGN(8) stride; - VkDeviceSize DECLSPEC_ALIGN(8) size; -} VkStridedDeviceAddressRegionKHR32; - -typedef struct VkOpaqueCaptureDescriptorDataCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 opaqueCaptureDescriptorData; -} VkOpaqueCaptureDescriptorDataCreateInfoEXT32; - -typedef struct VkAccelerationStructureMotionInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxInstances; - VkAccelerationStructureMotionInfoFlagsNV flags; -} VkAccelerationStructureMotionInfoNV32; - -typedef struct VkAccelerationStructureCreateInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkAccelerationStructureCreateFlagsKHR createFlags; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkDeviceSize DECLSPEC_ALIGN(8) size; - VkAccelerationStructureTypeKHR type; - VkDeviceAddress DECLSPEC_ALIGN(8) deviceAddress; -} VkAccelerationStructureCreateInfoKHR32; - -typedef struct VkAccelerationStructureCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceSize DECLSPEC_ALIGN(8) compactedSize; - VkAccelerationStructureInfoNV32 info; -} VkAccelerationStructureCreateInfoNV32; - -typedef struct VkDedicatedAllocationBufferCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 dedicatedAllocation; -} VkDedicatedAllocationBufferCreateInfoNV32; - -typedef struct VkExternalMemoryBufferCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkExternalMemoryHandleTypeFlags handleTypes; -} VkExternalMemoryBufferCreateInfo32; -typedef VkExternalMemoryBufferCreateInfo32 VkExternalMemoryBufferCreateInfoKHR32; - -typedef struct VkBufferOpaqueCaptureAddressCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint64_t DECLSPEC_ALIGN(8) opaqueCaptureAddress; -} VkBufferOpaqueCaptureAddressCreateInfo32; -typedef VkBufferOpaqueCaptureAddressCreateInfo32 VkBufferOpaqueCaptureAddressCreateInfoKHR32; - -typedef struct VkBufferDeviceAddressCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceAddress DECLSPEC_ALIGN(8) deviceAddress; -} VkBufferDeviceAddressCreateInfoEXT32; - -typedef struct VkBufferCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkBufferCreateFlags flags; - VkDeviceSize DECLSPEC_ALIGN(8) size; - VkBufferUsageFlags usage; - VkSharingMode sharingMode; - uint32_t queueFamilyIndexCount; - PTR32 pQueueFamilyIndices; -} VkBufferCreateInfo32; - -typedef struct VkBufferViewCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkBufferViewCreateFlags flags; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkFormat format; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkDeviceSize DECLSPEC_ALIGN(8) range; -} VkBufferViewCreateInfo32; - -typedef struct VkCommandPoolCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkCommandPoolCreateFlags flags; - uint32_t queueFamilyIndex; -} VkCommandPoolCreateInfo32; - -typedef struct VkPipelineCreationFeedback32 -{ - VkPipelineCreationFeedbackFlags flags; - uint64_t DECLSPEC_ALIGN(8) duration; -} VkPipelineCreationFeedback32; -typedef VkPipelineCreationFeedback32 VkPipelineCreationFeedbackEXT32; - -typedef struct VkSpecializationMapEntry32 -{ - uint32_t constantID; - uint32_t offset; - PTR32 size; -} VkSpecializationMapEntry32; - -typedef struct VkSpecializationInfo32 -{ - uint32_t mapEntryCount; - PTR32 pMapEntries; - PTR32 dataSize; - PTR32 pData; -} VkSpecializationInfo32; - -typedef struct VkShaderModuleCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkShaderModuleCreateFlags flags; - PTR32 codeSize; - PTR32 pCode; -} VkShaderModuleCreateInfo32; - -typedef struct VkShaderModuleValidationCacheCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkValidationCacheEXT DECLSPEC_ALIGN(8) validationCache; -} VkShaderModuleValidationCacheCreateInfoEXT32; - -typedef struct VkDebugUtilsObjectNameInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkObjectType objectType; - uint64_t DECLSPEC_ALIGN(8) objectHandle; - PTR32 pObjectName; -} VkDebugUtilsObjectNameInfoEXT32; - -typedef struct VkPipelineShaderStageRequiredSubgroupSizeCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t requiredSubgroupSize; -} VkPipelineShaderStageRequiredSubgroupSizeCreateInfo32; -typedef VkPipelineShaderStageRequiredSubgroupSizeCreateInfo32 VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT32; - -typedef struct VkPipelineShaderStageModuleIdentifierCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t identifierSize; - PTR32 pIdentifier; -} VkPipelineShaderStageModuleIdentifierCreateInfoEXT32; - -typedef struct VkPipelineRobustnessCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineRobustnessBufferBehaviorEXT storageBuffers; - VkPipelineRobustnessBufferBehaviorEXT uniformBuffers; - VkPipelineRobustnessBufferBehaviorEXT vertexInputs; - VkPipelineRobustnessImageBehaviorEXT images; -} VkPipelineRobustnessCreateInfoEXT32; - -typedef struct VkPipelineShaderStageCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineShaderStageCreateFlags flags; - VkShaderStageFlagBits stage; - VkShaderModule DECLSPEC_ALIGN(8) module; - PTR32 pName; - PTR32 pSpecializationInfo; -} VkPipelineShaderStageCreateInfo32; - -typedef struct VkPipelineCreationFeedbackCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 pPipelineCreationFeedback; - uint32_t pipelineStageCreationFeedbackCount; - PTR32 pPipelineStageCreationFeedbacks; -} VkPipelineCreationFeedbackCreateInfo32; -typedef VkPipelineCreationFeedbackCreateInfo32 VkPipelineCreationFeedbackCreateInfoEXT32; - -typedef struct VkSubpassShadingPipelineCreateInfoHUAWEI32 -{ - VkStructureType sType; - PTR32 pNext; - VkRenderPass DECLSPEC_ALIGN(8) renderPass; - uint32_t subpass; -} VkSubpassShadingPipelineCreateInfoHUAWEI32; - -typedef struct VkPipelineCompilerControlCreateInfoAMD32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineCompilerControlFlagsAMD compilerControlFlags; -} VkPipelineCompilerControlCreateInfoAMD32; - -typedef struct VkComputePipelineCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineCreateFlags flags; - VkPipelineShaderStageCreateInfo32 DECLSPEC_ALIGN(8) stage; - VkPipelineLayout DECLSPEC_ALIGN(8) layout; - VkPipeline DECLSPEC_ALIGN(8) basePipelineHandle; - int32_t basePipelineIndex; -} VkComputePipelineCreateInfo32; - -typedef struct VkCuFunctionCreateInfoNVX32 -{ - VkStructureType sType; - PTR32 pNext; - VkCuModuleNVX DECLSPEC_ALIGN(8) module; - PTR32 pName; -} VkCuFunctionCreateInfoNVX32; - -typedef struct VkCuModuleCreateInfoNVX32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 dataSize; - PTR32 pData; -} VkCuModuleCreateInfoNVX32; - -typedef struct VkDebugReportCallbackCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkDebugReportFlagsEXT flags; - PFN_vkDebugReportCallbackEXT pfnCallback; - PTR32 pUserData; -} VkDebugReportCallbackCreateInfoEXT32; - -typedef struct VkDebugUtilsMessengerCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkDebugUtilsMessengerCreateFlagsEXT flags; - VkDebugUtilsMessageSeverityFlagsEXT messageSeverity; - VkDebugUtilsMessageTypeFlagsEXT messageType; - PFN_vkDebugUtilsMessengerCallbackEXT pfnUserCallback; - PTR32 pUserData; -} VkDebugUtilsMessengerCreateInfoEXT32; - -typedef struct VkMutableDescriptorTypeListEXT32 -{ - uint32_t descriptorTypeCount; - PTR32 pDescriptorTypes; -} VkMutableDescriptorTypeListEXT32; -typedef VkMutableDescriptorTypeListEXT32 VkMutableDescriptorTypeListVALVE32; - -typedef struct VkDescriptorPoolInlineUniformBlockCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxInlineUniformBlockBindings; -} VkDescriptorPoolInlineUniformBlockCreateInfo32; -typedef VkDescriptorPoolInlineUniformBlockCreateInfo32 VkDescriptorPoolInlineUniformBlockCreateInfoEXT32; - -typedef struct VkMutableDescriptorTypeCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t mutableDescriptorTypeListCount; - PTR32 pMutableDescriptorTypeLists; -} VkMutableDescriptorTypeCreateInfoEXT32; -typedef VkMutableDescriptorTypeCreateInfoEXT32 VkMutableDescriptorTypeCreateInfoVALVE32; - -typedef struct VkDescriptorPoolCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkDescriptorPoolCreateFlags flags; - uint32_t maxSets; - uint32_t poolSizeCount; - PTR32 pPoolSizes; -} VkDescriptorPoolCreateInfo32; - -typedef struct VkDescriptorSetLayoutBinding32 -{ - uint32_t binding; - VkDescriptorType descriptorType; - uint32_t descriptorCount; - VkShaderStageFlags stageFlags; - PTR32 pImmutableSamplers; -} VkDescriptorSetLayoutBinding32; - -typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t bindingCount; - PTR32 pBindingFlags; -} VkDescriptorSetLayoutBindingFlagsCreateInfo32; -typedef VkDescriptorSetLayoutBindingFlagsCreateInfo32 VkDescriptorSetLayoutBindingFlagsCreateInfoEXT32; - -typedef struct VkDescriptorSetLayoutCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkDescriptorSetLayoutCreateFlags flags; - uint32_t bindingCount; - PTR32 pBindings; -} VkDescriptorSetLayoutCreateInfo32; - -typedef struct VkDescriptorUpdateTemplateEntry32 -{ - uint32_t dstBinding; - uint32_t dstArrayElement; - uint32_t descriptorCount; - VkDescriptorType descriptorType; - PTR32 offset; - PTR32 stride; -} VkDescriptorUpdateTemplateEntry32; -typedef VkDescriptorUpdateTemplateEntry32 VkDescriptorUpdateTemplateEntryKHR32; - -typedef struct VkDescriptorUpdateTemplateCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkDescriptorUpdateTemplateCreateFlags flags; - uint32_t descriptorUpdateEntryCount; - PTR32 pDescriptorUpdateEntries; - VkDescriptorUpdateTemplateType templateType; - VkDescriptorSetLayout DECLSPEC_ALIGN(8) descriptorSetLayout; - VkPipelineBindPoint pipelineBindPoint; - VkPipelineLayout DECLSPEC_ALIGN(8) pipelineLayout; - uint32_t set; -} VkDescriptorUpdateTemplateCreateInfo32; -typedef VkDescriptorUpdateTemplateCreateInfo32 VkDescriptorUpdateTemplateCreateInfoKHR32; - -typedef struct VkDeviceQueueGlobalPriorityCreateInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkQueueGlobalPriorityKHR globalPriority; -} VkDeviceQueueGlobalPriorityCreateInfoKHR32; -typedef VkDeviceQueueGlobalPriorityCreateInfoKHR32 VkDeviceQueueGlobalPriorityCreateInfoEXT32; - -typedef struct VkDeviceQueueCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceQueueCreateFlags flags; - uint32_t queueFamilyIndex; - uint32_t queueCount; - PTR32 pQueuePriorities; -} VkDeviceQueueCreateInfo32; - -typedef struct VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 deviceGeneratedCommands; -} VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV32; - -typedef struct VkDevicePrivateDataCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t privateDataSlotRequestCount; -} VkDevicePrivateDataCreateInfo32; -typedef VkDevicePrivateDataCreateInfo32 VkDevicePrivateDataCreateInfoEXT32; - -typedef struct VkPhysicalDevicePrivateDataFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 privateData; -} VkPhysicalDevicePrivateDataFeatures32; -typedef VkPhysicalDevicePrivateDataFeatures32 VkPhysicalDevicePrivateDataFeaturesEXT32; - -typedef struct VkPhysicalDeviceFeatures232 -{ - VkStructureType sType; - PTR32 pNext; - VkPhysicalDeviceFeatures features; -} VkPhysicalDeviceFeatures232; -typedef VkPhysicalDeviceFeatures232 VkPhysicalDeviceFeatures2KHR32; - -typedef struct VkPhysicalDeviceVariablePointersFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 variablePointersStorageBuffer; - VkBool32 variablePointers; -} VkPhysicalDeviceVariablePointersFeatures32; -typedef VkPhysicalDeviceVariablePointersFeatures32 VkPhysicalDeviceVariablePointersFeaturesKHR32; -typedef VkPhysicalDeviceVariablePointersFeatures32 VkPhysicalDeviceVariablePointerFeaturesKHR32; -typedef VkPhysicalDeviceVariablePointersFeatures32 VkPhysicalDeviceVariablePointerFeatures32; - -typedef struct VkPhysicalDeviceMultiviewFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 multiview; - VkBool32 multiviewGeometryShader; - VkBool32 multiviewTessellationShader; -} VkPhysicalDeviceMultiviewFeatures32; -typedef VkPhysicalDeviceMultiviewFeatures32 VkPhysicalDeviceMultiviewFeaturesKHR32; - -typedef struct VkDeviceGroupDeviceCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t physicalDeviceCount; - PTR32 pPhysicalDevices; -} VkDeviceGroupDeviceCreateInfo32; -typedef VkDeviceGroupDeviceCreateInfo32 VkDeviceGroupDeviceCreateInfoKHR32; - -typedef struct VkPhysicalDevicePresentIdFeaturesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 presentId; -} VkPhysicalDevicePresentIdFeaturesKHR32; - -typedef struct VkPhysicalDevicePresentWaitFeaturesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 presentWait; -} VkPhysicalDevicePresentWaitFeaturesKHR32; - -typedef struct VkPhysicalDevice16BitStorageFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 storageBuffer16BitAccess; - VkBool32 uniformAndStorageBuffer16BitAccess; - VkBool32 storagePushConstant16; - VkBool32 storageInputOutput16; -} VkPhysicalDevice16BitStorageFeatures32; -typedef VkPhysicalDevice16BitStorageFeatures32 VkPhysicalDevice16BitStorageFeaturesKHR32; - -typedef struct VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderSubgroupExtendedTypes; -} VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures32; -typedef VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures32 VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR32; - -typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 samplerYcbcrConversion; -} VkPhysicalDeviceSamplerYcbcrConversionFeatures32; -typedef VkPhysicalDeviceSamplerYcbcrConversionFeatures32 VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR32; - -typedef struct VkPhysicalDeviceProtectedMemoryFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 protectedMemory; -} VkPhysicalDeviceProtectedMemoryFeatures32; - -typedef struct VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 advancedBlendCoherentOperations; -} VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT32; - -typedef struct VkPhysicalDeviceMultiDrawFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 multiDraw; -} VkPhysicalDeviceMultiDrawFeaturesEXT32; - -typedef struct VkPhysicalDeviceInlineUniformBlockFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 inlineUniformBlock; - VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; -} VkPhysicalDeviceInlineUniformBlockFeatures32; -typedef VkPhysicalDeviceInlineUniformBlockFeatures32 VkPhysicalDeviceInlineUniformBlockFeaturesEXT32; - -typedef struct VkPhysicalDeviceMaintenance4Features32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 maintenance4; -} VkPhysicalDeviceMaintenance4Features32; -typedef VkPhysicalDeviceMaintenance4Features32 VkPhysicalDeviceMaintenance4FeaturesKHR32; - -typedef struct VkPhysicalDeviceShaderDrawParametersFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderDrawParameters; -} VkPhysicalDeviceShaderDrawParametersFeatures32; -typedef VkPhysicalDeviceShaderDrawParametersFeatures32 VkPhysicalDeviceShaderDrawParameterFeatures32; - -typedef struct VkPhysicalDeviceShaderFloat16Int8Features32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderFloat16; - VkBool32 shaderInt8; -} VkPhysicalDeviceShaderFloat16Int8Features32; -typedef VkPhysicalDeviceShaderFloat16Int8Features32 VkPhysicalDeviceShaderFloat16Int8FeaturesKHR32; -typedef VkPhysicalDeviceShaderFloat16Int8Features32 VkPhysicalDeviceFloat16Int8FeaturesKHR32; - -typedef struct VkPhysicalDeviceHostQueryResetFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 hostQueryReset; -} VkPhysicalDeviceHostQueryResetFeatures32; -typedef VkPhysicalDeviceHostQueryResetFeatures32 VkPhysicalDeviceHostQueryResetFeaturesEXT32; - -typedef struct VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 globalPriorityQuery; -} VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR32; -typedef VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR32 VkPhysicalDeviceGlobalPriorityQueryFeaturesEXT32; - -typedef struct VkPhysicalDeviceDescriptorIndexingFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderInputAttachmentArrayDynamicIndexing; - VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; - VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; - VkBool32 shaderUniformBufferArrayNonUniformIndexing; - VkBool32 shaderSampledImageArrayNonUniformIndexing; - VkBool32 shaderStorageBufferArrayNonUniformIndexing; - VkBool32 shaderStorageImageArrayNonUniformIndexing; - VkBool32 shaderInputAttachmentArrayNonUniformIndexing; - VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; - VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; - VkBool32 descriptorBindingUniformBufferUpdateAfterBind; - VkBool32 descriptorBindingSampledImageUpdateAfterBind; - VkBool32 descriptorBindingStorageImageUpdateAfterBind; - VkBool32 descriptorBindingStorageBufferUpdateAfterBind; - VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingUpdateUnusedWhilePending; - VkBool32 descriptorBindingPartiallyBound; - VkBool32 descriptorBindingVariableDescriptorCount; - VkBool32 runtimeDescriptorArray; -} VkPhysicalDeviceDescriptorIndexingFeatures32; -typedef VkPhysicalDeviceDescriptorIndexingFeatures32 VkPhysicalDeviceDescriptorIndexingFeaturesEXT32; - -typedef struct VkPhysicalDeviceTimelineSemaphoreFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 timelineSemaphore; -} VkPhysicalDeviceTimelineSemaphoreFeatures32; -typedef VkPhysicalDeviceTimelineSemaphoreFeatures32 VkPhysicalDeviceTimelineSemaphoreFeaturesKHR32; - -typedef struct VkPhysicalDevice8BitStorageFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 storageBuffer8BitAccess; - VkBool32 uniformAndStorageBuffer8BitAccess; - VkBool32 storagePushConstant8; -} VkPhysicalDevice8BitStorageFeatures32; -typedef VkPhysicalDevice8BitStorageFeatures32 VkPhysicalDevice8BitStorageFeaturesKHR32; - -typedef struct VkPhysicalDeviceConditionalRenderingFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 conditionalRendering; - VkBool32 inheritedConditionalRendering; -} VkPhysicalDeviceConditionalRenderingFeaturesEXT32; - -typedef struct VkPhysicalDeviceVulkanMemoryModelFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 vulkanMemoryModel; - VkBool32 vulkanMemoryModelDeviceScope; - VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; -} VkPhysicalDeviceVulkanMemoryModelFeatures32; -typedef VkPhysicalDeviceVulkanMemoryModelFeatures32 VkPhysicalDeviceVulkanMemoryModelFeaturesKHR32; - -typedef struct VkPhysicalDeviceShaderAtomicInt64Features32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderBufferInt64Atomics; - VkBool32 shaderSharedInt64Atomics; -} VkPhysicalDeviceShaderAtomicInt64Features32; -typedef VkPhysicalDeviceShaderAtomicInt64Features32 VkPhysicalDeviceShaderAtomicInt64FeaturesKHR32; - -typedef struct VkPhysicalDeviceShaderAtomicFloatFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderBufferFloat32Atomics; - VkBool32 shaderBufferFloat32AtomicAdd; - VkBool32 shaderBufferFloat64Atomics; - VkBool32 shaderBufferFloat64AtomicAdd; - VkBool32 shaderSharedFloat32Atomics; - VkBool32 shaderSharedFloat32AtomicAdd; - VkBool32 shaderSharedFloat64Atomics; - VkBool32 shaderSharedFloat64AtomicAdd; - VkBool32 shaderImageFloat32Atomics; - VkBool32 shaderImageFloat32AtomicAdd; - VkBool32 sparseImageFloat32Atomics; - VkBool32 sparseImageFloat32AtomicAdd; -} VkPhysicalDeviceShaderAtomicFloatFeaturesEXT32; - -typedef struct VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderBufferFloat16Atomics; - VkBool32 shaderBufferFloat16AtomicAdd; - VkBool32 shaderBufferFloat16AtomicMinMax; - VkBool32 shaderBufferFloat32AtomicMinMax; - VkBool32 shaderBufferFloat64AtomicMinMax; - VkBool32 shaderSharedFloat16Atomics; - VkBool32 shaderSharedFloat16AtomicAdd; - VkBool32 shaderSharedFloat16AtomicMinMax; - VkBool32 shaderSharedFloat32AtomicMinMax; - VkBool32 shaderSharedFloat64AtomicMinMax; - VkBool32 shaderImageFloat32AtomicMinMax; - VkBool32 sparseImageFloat32AtomicMinMax; -} VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT32; - -typedef struct VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 vertexAttributeInstanceRateDivisor; - VkBool32 vertexAttributeInstanceRateZeroDivisor; -} VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT32; - -typedef struct VkPhysicalDeviceASTCDecodeFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 decodeModeSharedExponent; -} VkPhysicalDeviceASTCDecodeFeaturesEXT32; - -typedef struct VkPhysicalDeviceTransformFeedbackFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 transformFeedback; - VkBool32 geometryStreams; -} VkPhysicalDeviceTransformFeedbackFeaturesEXT32; - -typedef struct VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 representativeFragmentTest; -} VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV32; - -typedef struct VkPhysicalDeviceExclusiveScissorFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 exclusiveScissor; -} VkPhysicalDeviceExclusiveScissorFeaturesNV32; - -typedef struct VkPhysicalDeviceCornerSampledImageFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 cornerSampledImage; -} VkPhysicalDeviceCornerSampledImageFeaturesNV32; - -typedef struct VkPhysicalDeviceComputeShaderDerivativesFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 computeDerivativeGroupQuads; - VkBool32 computeDerivativeGroupLinear; -} VkPhysicalDeviceComputeShaderDerivativesFeaturesNV32; - -typedef struct VkPhysicalDeviceShaderImageFootprintFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 imageFootprint; -} VkPhysicalDeviceShaderImageFootprintFeaturesNV32; - -typedef struct VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 dedicatedAllocationImageAliasing; -} VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV32; - -typedef struct VkPhysicalDeviceCopyMemoryIndirectFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 indirectCopy; -} VkPhysicalDeviceCopyMemoryIndirectFeaturesNV32; - -typedef struct VkPhysicalDeviceMemoryDecompressionFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 memoryDecompression; -} VkPhysicalDeviceMemoryDecompressionFeaturesNV32; - -typedef struct VkPhysicalDeviceShadingRateImageFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shadingRateImage; - VkBool32 shadingRateCoarseSampleOrder; -} VkPhysicalDeviceShadingRateImageFeaturesNV32; - -typedef struct VkPhysicalDeviceInvocationMaskFeaturesHUAWEI32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 invocationMask; -} VkPhysicalDeviceInvocationMaskFeaturesHUAWEI32; - -typedef struct VkPhysicalDeviceMeshShaderFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 taskShader; - VkBool32 meshShader; -} VkPhysicalDeviceMeshShaderFeaturesNV32; - -typedef struct VkPhysicalDeviceMeshShaderFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 taskShader; - VkBool32 meshShader; - VkBool32 multiviewMeshShader; - VkBool32 primitiveFragmentShadingRateMeshShader; - VkBool32 meshShaderQueries; -} VkPhysicalDeviceMeshShaderFeaturesEXT32; - -typedef struct VkPhysicalDeviceAccelerationStructureFeaturesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 accelerationStructure; - VkBool32 accelerationStructureCaptureReplay; - VkBool32 accelerationStructureIndirectBuild; - VkBool32 accelerationStructureHostCommands; - VkBool32 descriptorBindingAccelerationStructureUpdateAfterBind; -} VkPhysicalDeviceAccelerationStructureFeaturesKHR32; - -typedef struct VkPhysicalDeviceRayTracingPipelineFeaturesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 rayTracingPipeline; - VkBool32 rayTracingPipelineShaderGroupHandleCaptureReplay; - VkBool32 rayTracingPipelineShaderGroupHandleCaptureReplayMixed; - VkBool32 rayTracingPipelineTraceRaysIndirect; - VkBool32 rayTraversalPrimitiveCulling; -} VkPhysicalDeviceRayTracingPipelineFeaturesKHR32; - -typedef struct VkPhysicalDeviceRayQueryFeaturesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 rayQuery; -} VkPhysicalDeviceRayQueryFeaturesKHR32; - -typedef struct VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 rayTracingMaintenance1; - VkBool32 rayTracingPipelineTraceRaysIndirect2; -} VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR32; - -typedef struct VkDeviceMemoryOverallocationCreateInfoAMD32 -{ - VkStructureType sType; - PTR32 pNext; - VkMemoryOverallocationBehaviorAMD overallocationBehavior; -} VkDeviceMemoryOverallocationCreateInfoAMD32; - -typedef struct VkPhysicalDeviceFragmentDensityMapFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 fragmentDensityMap; - VkBool32 fragmentDensityMapDynamic; - VkBool32 fragmentDensityMapNonSubsampledImages; -} VkPhysicalDeviceFragmentDensityMapFeaturesEXT32; - -typedef struct VkPhysicalDeviceFragmentDensityMap2FeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 fragmentDensityMapDeferred; -} VkPhysicalDeviceFragmentDensityMap2FeaturesEXT32; - -typedef struct VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 fragmentDensityMapOffset; -} VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM32; - -typedef struct VkPhysicalDeviceScalarBlockLayoutFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 scalarBlockLayout; -} VkPhysicalDeviceScalarBlockLayoutFeatures32; -typedef VkPhysicalDeviceScalarBlockLayoutFeatures32 VkPhysicalDeviceScalarBlockLayoutFeaturesEXT32; - -typedef struct VkPhysicalDeviceUniformBufferStandardLayoutFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 uniformBufferStandardLayout; -} VkPhysicalDeviceUniformBufferStandardLayoutFeatures32; -typedef VkPhysicalDeviceUniformBufferStandardLayoutFeatures32 VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR32; - -typedef struct VkPhysicalDeviceDepthClipEnableFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 depthClipEnable; -} VkPhysicalDeviceDepthClipEnableFeaturesEXT32; - -typedef struct VkPhysicalDeviceMemoryPriorityFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 memoryPriority; -} VkPhysicalDeviceMemoryPriorityFeaturesEXT32; - -typedef struct VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 pageableDeviceLocalMemory; -} VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT32; - -typedef struct VkPhysicalDeviceBufferDeviceAddressFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 bufferDeviceAddress; - VkBool32 bufferDeviceAddressCaptureReplay; - VkBool32 bufferDeviceAddressMultiDevice; -} VkPhysicalDeviceBufferDeviceAddressFeatures32; -typedef VkPhysicalDeviceBufferDeviceAddressFeatures32 VkPhysicalDeviceBufferDeviceAddressFeaturesKHR32; - -typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 bufferDeviceAddress; - VkBool32 bufferDeviceAddressCaptureReplay; - VkBool32 bufferDeviceAddressMultiDevice; -} VkPhysicalDeviceBufferDeviceAddressFeaturesEXT32; -typedef VkPhysicalDeviceBufferDeviceAddressFeaturesEXT32 VkPhysicalDeviceBufferAddressFeaturesEXT32; - -typedef struct VkPhysicalDeviceImagelessFramebufferFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 imagelessFramebuffer; -} VkPhysicalDeviceImagelessFramebufferFeatures32; -typedef VkPhysicalDeviceImagelessFramebufferFeatures32 VkPhysicalDeviceImagelessFramebufferFeaturesKHR32; - -typedef struct VkPhysicalDeviceTextureCompressionASTCHDRFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 textureCompressionASTC_HDR; -} VkPhysicalDeviceTextureCompressionASTCHDRFeatures32; -typedef VkPhysicalDeviceTextureCompressionASTCHDRFeatures32 VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT32; - -typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 cooperativeMatrix; - VkBool32 cooperativeMatrixRobustBufferAccess; -} VkPhysicalDeviceCooperativeMatrixFeaturesNV32; - -typedef struct VkPhysicalDeviceYcbcrImageArraysFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 ycbcrImageArrays; -} VkPhysicalDeviceYcbcrImageArraysFeaturesEXT32; - -typedef struct VkPhysicalDevicePresentBarrierFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 presentBarrier; -} VkPhysicalDevicePresentBarrierFeaturesNV32; - -typedef struct VkPhysicalDevicePerformanceQueryFeaturesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 performanceCounterQueryPools; - VkBool32 performanceCounterMultipleQueryPools; -} VkPhysicalDevicePerformanceQueryFeaturesKHR32; - -typedef struct VkPhysicalDeviceCoverageReductionModeFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 coverageReductionMode; -} VkPhysicalDeviceCoverageReductionModeFeaturesNV32; - -typedef struct VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderIntegerFunctions2; -} VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL32; - -typedef struct VkPhysicalDeviceShaderClockFeaturesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderSubgroupClock; - VkBool32 shaderDeviceClock; -} VkPhysicalDeviceShaderClockFeaturesKHR32; - -typedef struct VkPhysicalDeviceIndexTypeUint8FeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 indexTypeUint8; -} VkPhysicalDeviceIndexTypeUint8FeaturesEXT32; - -typedef struct VkPhysicalDeviceShaderSMBuiltinsFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderSMBuiltins; -} VkPhysicalDeviceShaderSMBuiltinsFeaturesNV32; - -typedef struct VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 fragmentShaderSampleInterlock; - VkBool32 fragmentShaderPixelInterlock; - VkBool32 fragmentShaderShadingRateInterlock; -} VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT32; - -typedef struct VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 separateDepthStencilLayouts; -} VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures32; -typedef VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures32 VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR32; - -typedef struct VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 primitiveTopologyListRestart; - VkBool32 primitiveTopologyPatchListRestart; -} VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT32; - -typedef struct VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 pipelineExecutableInfo; -} VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR32; - -typedef struct VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderDemoteToHelperInvocation; -} VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures32; -typedef VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures32 VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT32; - -typedef struct VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 texelBufferAlignment; -} VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT32; - -typedef struct VkPhysicalDeviceSubgroupSizeControlFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 subgroupSizeControl; - VkBool32 computeFullSubgroups; -} VkPhysicalDeviceSubgroupSizeControlFeatures32; -typedef VkPhysicalDeviceSubgroupSizeControlFeatures32 VkPhysicalDeviceSubgroupSizeControlFeaturesEXT32; - -typedef struct VkPhysicalDeviceLineRasterizationFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 rectangularLines; - VkBool32 bresenhamLines; - VkBool32 smoothLines; - VkBool32 stippledRectangularLines; - VkBool32 stippledBresenhamLines; - VkBool32 stippledSmoothLines; -} VkPhysicalDeviceLineRasterizationFeaturesEXT32; - -typedef struct VkPhysicalDevicePipelineCreationCacheControlFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 pipelineCreationCacheControl; -} VkPhysicalDevicePipelineCreationCacheControlFeatures32; -typedef VkPhysicalDevicePipelineCreationCacheControlFeatures32 VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT32; - -typedef struct VkPhysicalDeviceVulkan11Features32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 storageBuffer16BitAccess; - VkBool32 uniformAndStorageBuffer16BitAccess; - VkBool32 storagePushConstant16; - VkBool32 storageInputOutput16; - VkBool32 multiview; - VkBool32 multiviewGeometryShader; - VkBool32 multiviewTessellationShader; - VkBool32 variablePointersStorageBuffer; - VkBool32 variablePointers; - VkBool32 protectedMemory; - VkBool32 samplerYcbcrConversion; - VkBool32 shaderDrawParameters; -} VkPhysicalDeviceVulkan11Features32; - -typedef struct VkPhysicalDeviceVulkan12Features32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 samplerMirrorClampToEdge; - VkBool32 drawIndirectCount; - VkBool32 storageBuffer8BitAccess; - VkBool32 uniformAndStorageBuffer8BitAccess; - VkBool32 storagePushConstant8; - VkBool32 shaderBufferInt64Atomics; - VkBool32 shaderSharedInt64Atomics; - VkBool32 shaderFloat16; - VkBool32 shaderInt8; - VkBool32 descriptorIndexing; - VkBool32 shaderInputAttachmentArrayDynamicIndexing; - VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; - VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; - VkBool32 shaderUniformBufferArrayNonUniformIndexing; - VkBool32 shaderSampledImageArrayNonUniformIndexing; - VkBool32 shaderStorageBufferArrayNonUniformIndexing; - VkBool32 shaderStorageImageArrayNonUniformIndexing; - VkBool32 shaderInputAttachmentArrayNonUniformIndexing; - VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; - VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; - VkBool32 descriptorBindingUniformBufferUpdateAfterBind; - VkBool32 descriptorBindingSampledImageUpdateAfterBind; - VkBool32 descriptorBindingStorageImageUpdateAfterBind; - VkBool32 descriptorBindingStorageBufferUpdateAfterBind; - VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingUpdateUnusedWhilePending; - VkBool32 descriptorBindingPartiallyBound; - VkBool32 descriptorBindingVariableDescriptorCount; - VkBool32 runtimeDescriptorArray; - VkBool32 samplerFilterMinmax; - VkBool32 scalarBlockLayout; - VkBool32 imagelessFramebuffer; - VkBool32 uniformBufferStandardLayout; - VkBool32 shaderSubgroupExtendedTypes; - VkBool32 separateDepthStencilLayouts; - VkBool32 hostQueryReset; - VkBool32 timelineSemaphore; - VkBool32 bufferDeviceAddress; - VkBool32 bufferDeviceAddressCaptureReplay; - VkBool32 bufferDeviceAddressMultiDevice; - VkBool32 vulkanMemoryModel; - VkBool32 vulkanMemoryModelDeviceScope; - VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; - VkBool32 shaderOutputViewportIndex; - VkBool32 shaderOutputLayer; - VkBool32 subgroupBroadcastDynamicId; -} VkPhysicalDeviceVulkan12Features32; - -typedef struct VkPhysicalDeviceVulkan13Features32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 robustImageAccess; - VkBool32 inlineUniformBlock; - VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; - VkBool32 pipelineCreationCacheControl; - VkBool32 privateData; - VkBool32 shaderDemoteToHelperInvocation; - VkBool32 shaderTerminateInvocation; - VkBool32 subgroupSizeControl; - VkBool32 computeFullSubgroups; - VkBool32 synchronization2; - VkBool32 textureCompressionASTC_HDR; - VkBool32 shaderZeroInitializeWorkgroupMemory; - VkBool32 dynamicRendering; - VkBool32 shaderIntegerDotProduct; - VkBool32 maintenance4; -} VkPhysicalDeviceVulkan13Features32; - -typedef struct VkPhysicalDeviceCoherentMemoryFeaturesAMD32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 deviceCoherentMemory; -} VkPhysicalDeviceCoherentMemoryFeaturesAMD32; - -typedef struct VkPhysicalDeviceCustomBorderColorFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 customBorderColors; - VkBool32 customBorderColorWithoutFormat; -} VkPhysicalDeviceCustomBorderColorFeaturesEXT32; - -typedef struct VkPhysicalDeviceBorderColorSwizzleFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 borderColorSwizzle; - VkBool32 borderColorSwizzleFromImage; -} VkPhysicalDeviceBorderColorSwizzleFeaturesEXT32; - -typedef struct VkPhysicalDeviceExtendedDynamicStateFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 extendedDynamicState; -} VkPhysicalDeviceExtendedDynamicStateFeaturesEXT32; - -typedef struct VkPhysicalDeviceExtendedDynamicState2FeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 extendedDynamicState2; - VkBool32 extendedDynamicState2LogicOp; - VkBool32 extendedDynamicState2PatchControlPoints; -} VkPhysicalDeviceExtendedDynamicState2FeaturesEXT32; - -typedef struct VkPhysicalDeviceExtendedDynamicState3FeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 extendedDynamicState3TessellationDomainOrigin; - VkBool32 extendedDynamicState3DepthClampEnable; - VkBool32 extendedDynamicState3PolygonMode; - VkBool32 extendedDynamicState3RasterizationSamples; - VkBool32 extendedDynamicState3SampleMask; - VkBool32 extendedDynamicState3AlphaToCoverageEnable; - VkBool32 extendedDynamicState3AlphaToOneEnable; - VkBool32 extendedDynamicState3LogicOpEnable; - VkBool32 extendedDynamicState3ColorBlendEnable; - VkBool32 extendedDynamicState3ColorBlendEquation; - VkBool32 extendedDynamicState3ColorWriteMask; - VkBool32 extendedDynamicState3RasterizationStream; - VkBool32 extendedDynamicState3ConservativeRasterizationMode; - VkBool32 extendedDynamicState3ExtraPrimitiveOverestimationSize; - VkBool32 extendedDynamicState3DepthClipEnable; - VkBool32 extendedDynamicState3SampleLocationsEnable; - VkBool32 extendedDynamicState3ColorBlendAdvanced; - VkBool32 extendedDynamicState3ProvokingVertexMode; - VkBool32 extendedDynamicState3LineRasterizationMode; - VkBool32 extendedDynamicState3LineStippleEnable; - VkBool32 extendedDynamicState3DepthClipNegativeOneToOne; - VkBool32 extendedDynamicState3ViewportWScalingEnable; - VkBool32 extendedDynamicState3ViewportSwizzle; - VkBool32 extendedDynamicState3CoverageToColorEnable; - VkBool32 extendedDynamicState3CoverageToColorLocation; - VkBool32 extendedDynamicState3CoverageModulationMode; - VkBool32 extendedDynamicState3CoverageModulationTableEnable; - VkBool32 extendedDynamicState3CoverageModulationTable; - VkBool32 extendedDynamicState3CoverageReductionMode; - VkBool32 extendedDynamicState3RepresentativeFragmentTestEnable; - VkBool32 extendedDynamicState3ShadingRateImageEnable; -} VkPhysicalDeviceExtendedDynamicState3FeaturesEXT32; - -typedef struct VkPhysicalDeviceDiagnosticsConfigFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 diagnosticsConfig; -} VkPhysicalDeviceDiagnosticsConfigFeaturesNV32; - -typedef struct VkDeviceDiagnosticsConfigCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceDiagnosticsConfigFlagsNV flags; -} VkDeviceDiagnosticsConfigCreateInfoNV32; - -typedef struct VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderZeroInitializeWorkgroupMemory; -} VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures32; -typedef VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures32 VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR32; - -typedef struct VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderSubgroupUniformControlFlow; -} VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR32; - -typedef struct VkPhysicalDeviceRobustness2FeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 robustBufferAccess2; - VkBool32 robustImageAccess2; - VkBool32 nullDescriptor; -} VkPhysicalDeviceRobustness2FeaturesEXT32; - -typedef struct VkPhysicalDeviceImageRobustnessFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 robustImageAccess; -} VkPhysicalDeviceImageRobustnessFeatures32; -typedef VkPhysicalDeviceImageRobustnessFeatures32 VkPhysicalDeviceImageRobustnessFeaturesEXT32; - -typedef struct VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 workgroupMemoryExplicitLayout; - VkBool32 workgroupMemoryExplicitLayoutScalarBlockLayout; - VkBool32 workgroupMemoryExplicitLayout8BitAccess; - VkBool32 workgroupMemoryExplicitLayout16BitAccess; -} VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR32; - -typedef struct VkPhysicalDevice4444FormatsFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 formatA4R4G4B4; - VkBool32 formatA4B4G4R4; -} VkPhysicalDevice4444FormatsFeaturesEXT32; - -typedef struct VkPhysicalDeviceSubpassShadingFeaturesHUAWEI32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 subpassShading; -} VkPhysicalDeviceSubpassShadingFeaturesHUAWEI32; - -typedef struct VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderImageInt64Atomics; - VkBool32 sparseImageInt64Atomics; -} VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT32; - -typedef struct VkPhysicalDeviceFragmentShadingRateFeaturesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 pipelineFragmentShadingRate; - VkBool32 primitiveFragmentShadingRate; - VkBool32 attachmentFragmentShadingRate; -} VkPhysicalDeviceFragmentShadingRateFeaturesKHR32; - -typedef struct VkPhysicalDeviceShaderTerminateInvocationFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderTerminateInvocation; -} VkPhysicalDeviceShaderTerminateInvocationFeatures32; -typedef VkPhysicalDeviceShaderTerminateInvocationFeatures32 VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR32; - -typedef struct VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 fragmentShadingRateEnums; - VkBool32 supersampleFragmentShadingRates; - VkBool32 noInvocationFragmentShadingRates; -} VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV32; - -typedef struct VkPhysicalDeviceImage2DViewOf3DFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 image2DViewOf3D; - VkBool32 sampler2DViewOf3D; -} VkPhysicalDeviceImage2DViewOf3DFeaturesEXT32; - -typedef struct VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 mutableDescriptorType; -} VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT32; -typedef VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT32 VkPhysicalDeviceMutableDescriptorTypeFeaturesVALVE32; - -typedef struct VkPhysicalDeviceDepthClipControlFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 depthClipControl; -} VkPhysicalDeviceDepthClipControlFeaturesEXT32; - -typedef struct VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 vertexInputDynamicState; -} VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT32; - -typedef struct VkPhysicalDeviceColorWriteEnableFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 colorWriteEnable; -} VkPhysicalDeviceColorWriteEnableFeaturesEXT32; - -typedef struct VkPhysicalDeviceSynchronization2Features32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 synchronization2; -} VkPhysicalDeviceSynchronization2Features32; -typedef VkPhysicalDeviceSynchronization2Features32 VkPhysicalDeviceSynchronization2FeaturesKHR32; - -typedef struct VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 primitivesGeneratedQuery; - VkBool32 primitivesGeneratedQueryWithRasterizerDiscard; - VkBool32 primitivesGeneratedQueryWithNonZeroStreams; -} VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT32; - -typedef struct VkPhysicalDeviceLegacyDitheringFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 legacyDithering; -} VkPhysicalDeviceLegacyDitheringFeaturesEXT32; - -typedef struct VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 multisampledRenderToSingleSampled; -} VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT32; - -typedef struct VkPhysicalDevicePipelineProtectedAccessFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 pipelineProtectedAccess; -} VkPhysicalDevicePipelineProtectedAccessFeaturesEXT32; - -typedef struct VkPhysicalDeviceInheritedViewportScissorFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 inheritedViewportScissor2D; -} VkPhysicalDeviceInheritedViewportScissorFeaturesNV32; - -typedef struct VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 ycbcr2plane444Formats; -} VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT32; - -typedef struct VkPhysicalDeviceProvokingVertexFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 provokingVertexLast; - VkBool32 transformFeedbackPreservesProvokingVertex; -} VkPhysicalDeviceProvokingVertexFeaturesEXT32; - -typedef struct VkPhysicalDeviceDescriptorBufferFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 descriptorBuffer; - VkBool32 descriptorBufferCaptureReplay; - VkBool32 descriptorBufferImageLayoutIgnored; - VkBool32 descriptorBufferPushDescriptors; -} VkPhysicalDeviceDescriptorBufferFeaturesEXT32; - -typedef struct VkPhysicalDeviceShaderIntegerDotProductFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderIntegerDotProduct; -} VkPhysicalDeviceShaderIntegerDotProductFeatures32; -typedef VkPhysicalDeviceShaderIntegerDotProductFeatures32 VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR32; - -typedef struct VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 fragmentShaderBarycentric; -} VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR32; -typedef VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR32 VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV32; - -typedef struct VkPhysicalDeviceRayTracingMotionBlurFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 rayTracingMotionBlur; - VkBool32 rayTracingMotionBlurPipelineTraceRaysIndirect; -} VkPhysicalDeviceRayTracingMotionBlurFeaturesNV32; - -typedef struct VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 formatRgba10x6WithoutYCbCrSampler; -} VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT32; - -typedef struct VkPhysicalDeviceDynamicRenderingFeatures32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 dynamicRendering; -} VkPhysicalDeviceDynamicRenderingFeatures32; -typedef VkPhysicalDeviceDynamicRenderingFeatures32 VkPhysicalDeviceDynamicRenderingFeaturesKHR32; - -typedef struct VkPhysicalDeviceImageViewMinLodFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 minLod; -} VkPhysicalDeviceImageViewMinLodFeaturesEXT32; - -typedef struct VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 rasterizationOrderColorAttachmentAccess; - VkBool32 rasterizationOrderDepthAttachmentAccess; - VkBool32 rasterizationOrderStencilAttachmentAccess; -} VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT32; -typedef VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT32 VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM32; - -typedef struct VkPhysicalDeviceLinearColorAttachmentFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 linearColorAttachment; -} VkPhysicalDeviceLinearColorAttachmentFeaturesNV32; - -typedef struct VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 graphicsPipelineLibrary; -} VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT32; - -typedef struct VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 descriptorSetHostMapping; -} VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE32; - -typedef struct VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderModuleIdentifier; -} VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT32; - -typedef struct VkPhysicalDeviceImageCompressionControlFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 imageCompressionControl; -} VkPhysicalDeviceImageCompressionControlFeaturesEXT32; - -typedef struct VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 imageCompressionControlSwapchain; -} VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT32; - -typedef struct VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 subpassMergeFeedback; -} VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT32; - -typedef struct VkPhysicalDeviceOpacityMicromapFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 micromap; - VkBool32 micromapCaptureReplay; - VkBool32 micromapHostCommands; -} VkPhysicalDeviceOpacityMicromapFeaturesEXT32; - -typedef struct VkPhysicalDevicePipelinePropertiesFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 pipelinePropertiesIdentifier; -} VkPhysicalDevicePipelinePropertiesFeaturesEXT32; - -typedef struct VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderEarlyAndLateFragmentTests; -} VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD32; - -typedef struct VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 nonSeamlessCubeMap; -} VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT32; - -typedef struct VkPhysicalDevicePipelineRobustnessFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 pipelineRobustness; -} VkPhysicalDevicePipelineRobustnessFeaturesEXT32; - -typedef struct VkPhysicalDeviceImageProcessingFeaturesQCOM32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 textureSampleWeighted; - VkBool32 textureBoxFilter; - VkBool32 textureBlockMatch; -} VkPhysicalDeviceImageProcessingFeaturesQCOM32; - -typedef struct VkPhysicalDeviceTilePropertiesFeaturesQCOM32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 tileProperties; -} VkPhysicalDeviceTilePropertiesFeaturesQCOM32; - -typedef struct VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 attachmentFeedbackLoopLayout; -} VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT32; - -typedef struct VkPhysicalDeviceDepthClampZeroOneFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 depthClampZeroOne; -} VkPhysicalDeviceDepthClampZeroOneFeaturesEXT32; - -typedef struct VkPhysicalDeviceAddressBindingReportFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 reportAddressBinding; -} VkPhysicalDeviceAddressBindingReportFeaturesEXT32; - -typedef struct VkPhysicalDeviceOpticalFlowFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 opticalFlow; -} VkPhysicalDeviceOpticalFlowFeaturesNV32; - -typedef struct VkPhysicalDeviceFaultFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 deviceFault; - VkBool32 deviceFaultVendorBinary; -} VkPhysicalDeviceFaultFeaturesEXT32; - -typedef struct VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shaderCoreBuiltins; -} VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM32; - -typedef struct VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 swapchainMaintenance1; -} VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT32; - -typedef struct VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 rayTracingInvocationReorder; -} VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV32; - -typedef struct VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 multiviewPerViewViewports; -} VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM32; - -typedef struct VkDeviceCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceCreateFlags flags; - uint32_t queueCreateInfoCount; - PTR32 pQueueCreateInfos; - uint32_t enabledLayerCount; - PTR32 ppEnabledLayerNames; - uint32_t enabledExtensionCount; - PTR32 ppEnabledExtensionNames; - PTR32 pEnabledFeatures; -} VkDeviceCreateInfo32; - -typedef struct VkEventCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkEventCreateFlags flags; -} VkEventCreateInfo32; - -typedef struct VkExportFenceCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkExternalFenceHandleTypeFlags handleTypes; -} VkExportFenceCreateInfo32; -typedef VkExportFenceCreateInfo32 VkExportFenceCreateInfoKHR32; - -typedef struct VkFenceCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkFenceCreateFlags flags; -} VkFenceCreateInfo32; - -typedef struct VkFramebufferAttachmentImageInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageCreateFlags flags; - VkImageUsageFlags usage; - uint32_t width; - uint32_t height; - uint32_t layerCount; - uint32_t viewFormatCount; - PTR32 pViewFormats; -} VkFramebufferAttachmentImageInfo32; -typedef VkFramebufferAttachmentImageInfo32 VkFramebufferAttachmentImageInfoKHR32; - -typedef struct VkFramebufferAttachmentsCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t attachmentImageInfoCount; - PTR32 pAttachmentImageInfos; -} VkFramebufferAttachmentsCreateInfo32; -typedef VkFramebufferAttachmentsCreateInfo32 VkFramebufferAttachmentsCreateInfoKHR32; - -typedef struct VkFramebufferCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkFramebufferCreateFlags flags; - VkRenderPass DECLSPEC_ALIGN(8) renderPass; - uint32_t attachmentCount; - PTR32 pAttachments; - uint32_t width; - uint32_t height; - uint32_t layers; -} VkFramebufferCreateInfo32; - -typedef struct VkPipelineVertexInputDivisorStateCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t vertexBindingDivisorCount; - PTR32 pVertexBindingDivisors; -} VkPipelineVertexInputDivisorStateCreateInfoEXT32; - -typedef struct VkPipelineVertexInputStateCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineVertexInputStateCreateFlags flags; - uint32_t vertexBindingDescriptionCount; - PTR32 pVertexBindingDescriptions; - uint32_t vertexAttributeDescriptionCount; - PTR32 pVertexAttributeDescriptions; -} VkPipelineVertexInputStateCreateInfo32; - -typedef struct VkPipelineTessellationDomainOriginStateCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkTessellationDomainOrigin domainOrigin; -} VkPipelineTessellationDomainOriginStateCreateInfo32; -typedef VkPipelineTessellationDomainOriginStateCreateInfo32 VkPipelineTessellationDomainOriginStateCreateInfoKHR32; - -typedef struct VkPipelineTessellationStateCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineTessellationStateCreateFlags flags; - uint32_t patchControlPoints; -} VkPipelineTessellationStateCreateInfo32; - -typedef struct VkGraphicsShaderGroupCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t stageCount; - PTR32 pStages; - PTR32 pVertexInputState; - PTR32 pTessellationState; -} VkGraphicsShaderGroupCreateInfoNV32; - -typedef struct VkPipelineInputAssemblyStateCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineInputAssemblyStateCreateFlags flags; - VkPrimitiveTopology topology; - VkBool32 primitiveRestartEnable; -} VkPipelineInputAssemblyStateCreateInfo32; - -typedef struct VkPipelineViewportWScalingStateCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 viewportWScalingEnable; - uint32_t viewportCount; - PTR32 pViewportWScalings; -} VkPipelineViewportWScalingStateCreateInfoNV32; - -typedef struct VkPipelineViewportSwizzleStateCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineViewportSwizzleStateCreateFlagsNV flags; - uint32_t viewportCount; - PTR32 pViewportSwizzles; -} VkPipelineViewportSwizzleStateCreateInfoNV32; - -typedef struct VkPipelineViewportExclusiveScissorStateCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t exclusiveScissorCount; - PTR32 pExclusiveScissors; -} VkPipelineViewportExclusiveScissorStateCreateInfoNV32; - -typedef struct VkPipelineViewportShadingRateImageStateCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 shadingRateImageEnable; - uint32_t viewportCount; - PTR32 pShadingRatePalettes; -} VkPipelineViewportShadingRateImageStateCreateInfoNV32; - -typedef struct VkPipelineViewportCoarseSampleOrderStateCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkCoarseSampleOrderTypeNV sampleOrderType; - uint32_t customSampleOrderCount; - PTR32 pCustomSampleOrders; -} VkPipelineViewportCoarseSampleOrderStateCreateInfoNV32; - -typedef struct VkPipelineViewportDepthClipControlCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 negativeOneToOne; -} VkPipelineViewportDepthClipControlCreateInfoEXT32; - -typedef struct VkPipelineViewportStateCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineViewportStateCreateFlags flags; - uint32_t viewportCount; - PTR32 pViewports; - uint32_t scissorCount; - PTR32 pScissors; -} VkPipelineViewportStateCreateInfo32; - -typedef struct VkPipelineRasterizationStateRasterizationOrderAMD32 -{ - VkStructureType sType; - PTR32 pNext; - VkRasterizationOrderAMD rasterizationOrder; -} VkPipelineRasterizationStateRasterizationOrderAMD32; - -typedef struct VkPipelineRasterizationConservativeStateCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineRasterizationConservativeStateCreateFlagsEXT flags; - VkConservativeRasterizationModeEXT conservativeRasterizationMode; - float extraPrimitiveOverestimationSize; -} VkPipelineRasterizationConservativeStateCreateInfoEXT32; - -typedef struct VkPipelineRasterizationStateStreamCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineRasterizationStateStreamCreateFlagsEXT flags; - uint32_t rasterizationStream; -} VkPipelineRasterizationStateStreamCreateInfoEXT32; - -typedef struct VkPipelineRasterizationDepthClipStateCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineRasterizationDepthClipStateCreateFlagsEXT flags; - VkBool32 depthClipEnable; -} VkPipelineRasterizationDepthClipStateCreateInfoEXT32; - -typedef struct VkPipelineRasterizationLineStateCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkLineRasterizationModeEXT lineRasterizationMode; - VkBool32 stippledLineEnable; - uint32_t lineStippleFactor; - uint16_t lineStipplePattern; -} VkPipelineRasterizationLineStateCreateInfoEXT32; - -typedef struct VkPipelineRasterizationProvokingVertexStateCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkProvokingVertexModeEXT provokingVertexMode; -} VkPipelineRasterizationProvokingVertexStateCreateInfoEXT32; - -typedef struct VkPipelineRasterizationStateCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineRasterizationStateCreateFlags flags; - VkBool32 depthClampEnable; - VkBool32 rasterizerDiscardEnable; - VkPolygonMode polygonMode; - VkCullModeFlags cullMode; - VkFrontFace frontFace; - VkBool32 depthBiasEnable; - float depthBiasConstantFactor; - float depthBiasClamp; - float depthBiasSlopeFactor; - float lineWidth; -} VkPipelineRasterizationStateCreateInfo32; - -typedef struct VkPipelineCoverageToColorStateCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineCoverageToColorStateCreateFlagsNV flags; - VkBool32 coverageToColorEnable; - uint32_t coverageToColorLocation; -} VkPipelineCoverageToColorStateCreateInfoNV32; - -typedef struct VkPipelineSampleLocationsStateCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 sampleLocationsEnable; - VkSampleLocationsInfoEXT32 sampleLocationsInfo; -} VkPipelineSampleLocationsStateCreateInfoEXT32; - -typedef struct VkPipelineCoverageModulationStateCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineCoverageModulationStateCreateFlagsNV flags; - VkCoverageModulationModeNV coverageModulationMode; - VkBool32 coverageModulationTableEnable; - uint32_t coverageModulationTableCount; - PTR32 pCoverageModulationTable; -} VkPipelineCoverageModulationStateCreateInfoNV32; - -typedef struct VkPipelineCoverageReductionStateCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineCoverageReductionStateCreateFlagsNV flags; - VkCoverageReductionModeNV coverageReductionMode; -} VkPipelineCoverageReductionStateCreateInfoNV32; - -typedef struct VkPipelineMultisampleStateCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineMultisampleStateCreateFlags flags; - VkSampleCountFlagBits rasterizationSamples; - VkBool32 sampleShadingEnable; - float minSampleShading; - PTR32 pSampleMask; - VkBool32 alphaToCoverageEnable; - VkBool32 alphaToOneEnable; -} VkPipelineMultisampleStateCreateInfo32; - -typedef struct VkPipelineDepthStencilStateCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineDepthStencilStateCreateFlags flags; - VkBool32 depthTestEnable; - VkBool32 depthWriteEnable; - VkCompareOp depthCompareOp; - VkBool32 depthBoundsTestEnable; - VkBool32 stencilTestEnable; - VkStencilOpState front; - VkStencilOpState back; - float minDepthBounds; - float maxDepthBounds; -} VkPipelineDepthStencilStateCreateInfo32; - -typedef struct VkPipelineColorBlendAdvancedStateCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 srcPremultiplied; - VkBool32 dstPremultiplied; - VkBlendOverlapEXT blendOverlap; -} VkPipelineColorBlendAdvancedStateCreateInfoEXT32; - -typedef struct VkPipelineColorWriteCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t attachmentCount; - PTR32 pColorWriteEnables; -} VkPipelineColorWriteCreateInfoEXT32; - -typedef struct VkPipelineColorBlendStateCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineColorBlendStateCreateFlags flags; - VkBool32 logicOpEnable; - VkLogicOp logicOp; - uint32_t attachmentCount; - PTR32 pAttachments; - float blendConstants[4]; -} VkPipelineColorBlendStateCreateInfo32; - -typedef struct VkPipelineDynamicStateCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineDynamicStateCreateFlags flags; - uint32_t dynamicStateCount; - PTR32 pDynamicStates; -} VkPipelineDynamicStateCreateInfo32; - -typedef struct VkGraphicsPipelineShaderGroupsCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t groupCount; - PTR32 pGroups; - uint32_t pipelineCount; - PTR32 pPipelines; -} VkGraphicsPipelineShaderGroupsCreateInfoNV32; - -typedef struct VkPipelineDiscardRectangleStateCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineDiscardRectangleStateCreateFlagsEXT flags; - VkDiscardRectangleModeEXT discardRectangleMode; - uint32_t discardRectangleCount; - PTR32 pDiscardRectangles; -} VkPipelineDiscardRectangleStateCreateInfoEXT32; - -typedef struct VkPipelineRepresentativeFragmentTestStateCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 representativeFragmentTestEnable; -} VkPipelineRepresentativeFragmentTestStateCreateInfoNV32; - -typedef struct VkPipelineLibraryCreateInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t libraryCount; - PTR32 pLibraries; -} VkPipelineLibraryCreateInfoKHR32; - -typedef struct VkPipelineFragmentShadingRateStateCreateInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkExtent2D fragmentSize; - VkFragmentShadingRateCombinerOpKHR combinerOps[2]; -} VkPipelineFragmentShadingRateStateCreateInfoKHR32; - -typedef struct VkPipelineFragmentShadingRateEnumStateCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkFragmentShadingRateTypeNV shadingRateType; - VkFragmentShadingRateNV shadingRate; - VkFragmentShadingRateCombinerOpKHR combinerOps[2]; -} VkPipelineFragmentShadingRateEnumStateCreateInfoNV32; - -typedef struct VkPipelineRenderingCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t viewMask; - uint32_t colorAttachmentCount; - PTR32 pColorAttachmentFormats; - VkFormat depthAttachmentFormat; - VkFormat stencilAttachmentFormat; -} VkPipelineRenderingCreateInfo32; -typedef VkPipelineRenderingCreateInfo32 VkPipelineRenderingCreateInfoKHR32; - -typedef struct VkGraphicsPipelineLibraryCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkGraphicsPipelineLibraryFlagsEXT flags; -} VkGraphicsPipelineLibraryCreateInfoEXT32; - -typedef struct VkGraphicsPipelineCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineCreateFlags flags; - uint32_t stageCount; - PTR32 pStages; - PTR32 pVertexInputState; - PTR32 pInputAssemblyState; - PTR32 pTessellationState; - PTR32 pViewportState; - PTR32 pRasterizationState; - PTR32 pMultisampleState; - PTR32 pDepthStencilState; - PTR32 pColorBlendState; - PTR32 pDynamicState; - VkPipelineLayout DECLSPEC_ALIGN(8) layout; - VkRenderPass DECLSPEC_ALIGN(8) renderPass; - uint32_t subpass; - VkPipeline DECLSPEC_ALIGN(8) basePipelineHandle; - int32_t basePipelineIndex; -} VkGraphicsPipelineCreateInfo32; - -typedef struct VkDedicatedAllocationImageCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 dedicatedAllocation; -} VkDedicatedAllocationImageCreateInfoNV32; - -typedef struct VkExternalMemoryImageCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkExternalMemoryHandleTypeFlags handleTypes; -} VkExternalMemoryImageCreateInfo32; -typedef VkExternalMemoryImageCreateInfo32 VkExternalMemoryImageCreateInfoKHR32; - -typedef struct VkImageSwapchainCreateInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkSwapchainKHR DECLSPEC_ALIGN(8) swapchain; -} VkImageSwapchainCreateInfoKHR32; - -typedef struct VkImageFormatListCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t viewFormatCount; - PTR32 pViewFormats; -} VkImageFormatListCreateInfo32; -typedef VkImageFormatListCreateInfo32 VkImageFormatListCreateInfoKHR32; - -typedef struct VkImageStencilUsageCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageUsageFlags stencilUsage; -} VkImageStencilUsageCreateInfo32; -typedef VkImageStencilUsageCreateInfo32 VkImageStencilUsageCreateInfoEXT32; - -typedef struct VkImageCompressionControlEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageCompressionFlagsEXT flags; - uint32_t compressionControlPlaneCount; - PTR32 pFixedRateFlags; -} VkImageCompressionControlEXT32; - -typedef struct VkOpticalFlowImageFormatInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkOpticalFlowUsageFlagsNV usage; -} VkOpticalFlowImageFormatInfoNV32; - -typedef struct VkImageCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageCreateFlags flags; - VkImageType imageType; - VkFormat format; - VkExtent3D extent; - uint32_t mipLevels; - uint32_t arrayLayers; - VkSampleCountFlagBits samples; - VkImageTiling tiling; - VkImageUsageFlags usage; - VkSharingMode sharingMode; - uint32_t queueFamilyIndexCount; - PTR32 pQueueFamilyIndices; - VkImageLayout initialLayout; -} VkImageCreateInfo32; - -typedef struct VkImageViewUsageCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageUsageFlags usage; -} VkImageViewUsageCreateInfo32; -typedef VkImageViewUsageCreateInfo32 VkImageViewUsageCreateInfoKHR32; - -typedef struct VkSamplerYcbcrConversionInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkSamplerYcbcrConversion DECLSPEC_ALIGN(8) conversion; -} VkSamplerYcbcrConversionInfo32; -typedef VkSamplerYcbcrConversionInfo32 VkSamplerYcbcrConversionInfoKHR32; - -typedef struct VkImageViewASTCDecodeModeEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkFormat decodeMode; -} VkImageViewASTCDecodeModeEXT32; - -typedef struct VkImageViewMinLodCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - float minLod; -} VkImageViewMinLodCreateInfoEXT32; - -typedef struct VkImageViewSampleWeightCreateInfoQCOM32 -{ - VkStructureType sType; - PTR32 pNext; - VkOffset2D filterCenter; - VkExtent2D filterSize; - uint32_t numPhases; -} VkImageViewSampleWeightCreateInfoQCOM32; - -typedef struct VkImageViewCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageViewCreateFlags flags; - VkImage DECLSPEC_ALIGN(8) image; - VkImageViewType viewType; - VkFormat format; - VkComponentMapping components; - VkImageSubresourceRange subresourceRange; -} VkImageViewCreateInfo32; - -typedef struct VkIndirectCommandsLayoutTokenNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkIndirectCommandsTokenTypeNV tokenType; - uint32_t stream; - uint32_t offset; - uint32_t vertexBindingUnit; - VkBool32 vertexDynamicStride; - VkPipelineLayout DECLSPEC_ALIGN(8) pushconstantPipelineLayout; - VkShaderStageFlags pushconstantShaderStageFlags; - uint32_t pushconstantOffset; - uint32_t pushconstantSize; - VkIndirectStateFlagsNV indirectStateFlags; - uint32_t indexTypeCount; - PTR32 pIndexTypes; - PTR32 pIndexTypeValues; -} VkIndirectCommandsLayoutTokenNV32; - -typedef struct VkIndirectCommandsLayoutCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkIndirectCommandsLayoutUsageFlagsNV flags; - VkPipelineBindPoint pipelineBindPoint; - uint32_t tokenCount; - PTR32 pTokens; - uint32_t streamCount; - PTR32 pStreamStrides; -} VkIndirectCommandsLayoutCreateInfoNV32; - -typedef struct VkApplicationInfo32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 pApplicationName; - uint32_t applicationVersion; - PTR32 pEngineName; - uint32_t engineVersion; - uint32_t apiVersion; -} VkApplicationInfo32; - -typedef struct VkValidationFlagsEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t disabledValidationCheckCount; - PTR32 pDisabledValidationChecks; -} VkValidationFlagsEXT32; - -typedef struct VkValidationFeaturesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t enabledValidationFeatureCount; - PTR32 pEnabledValidationFeatures; - uint32_t disabledValidationFeatureCount; - PTR32 pDisabledValidationFeatures; -} VkValidationFeaturesEXT32; - -typedef struct VkInstanceCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkInstanceCreateFlags flags; - PTR32 pApplicationInfo; - uint32_t enabledLayerCount; - PTR32 ppEnabledLayerNames; - uint32_t enabledExtensionCount; - PTR32 ppEnabledExtensionNames; -} VkInstanceCreateInfo32; - -typedef struct VkMicromapCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkMicromapCreateFlagsEXT createFlags; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkDeviceSize DECLSPEC_ALIGN(8) size; - VkMicromapTypeEXT type; - VkDeviceAddress DECLSPEC_ALIGN(8) deviceAddress; -} VkMicromapCreateInfoEXT32; - -typedef struct VkOpticalFlowSessionCreatePrivateDataInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t id; - uint32_t size; - PTR32 pPrivateData; -} VkOpticalFlowSessionCreatePrivateDataInfoNV32; - -typedef struct VkOpticalFlowSessionCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t width; - uint32_t height; - VkFormat imageFormat; - VkFormat flowVectorFormat; - VkFormat costFormat; - VkOpticalFlowGridSizeFlagsNV outputGridSize; - VkOpticalFlowGridSizeFlagsNV hintGridSize; - VkOpticalFlowPerformanceLevelNV performanceLevel; - VkOpticalFlowSessionCreateFlagsNV flags; -} VkOpticalFlowSessionCreateInfoNV32; - -typedef struct VkPipelineCacheCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineCacheCreateFlags flags; - PTR32 initialDataSize; - PTR32 pInitialData; -} VkPipelineCacheCreateInfo32; - -typedef struct VkPipelineLayoutCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineLayoutCreateFlags flags; - uint32_t setLayoutCount; - PTR32 pSetLayouts; - uint32_t pushConstantRangeCount; - PTR32 pPushConstantRanges; -} VkPipelineLayoutCreateInfo32; - -typedef struct VkPrivateDataSlotCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkPrivateDataSlotCreateFlags flags; -} VkPrivateDataSlotCreateInfo32; -typedef VkPrivateDataSlotCreateInfo32 VkPrivateDataSlotCreateInfoEXT32; - -typedef struct VkQueryPoolPerformanceCreateInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t queueFamilyIndex; - uint32_t counterIndexCount; - PTR32 pCounterIndices; -} VkQueryPoolPerformanceCreateInfoKHR32; - -typedef struct VkQueryPoolPerformanceQueryCreateInfoINTEL32 -{ - VkStructureType sType; - PTR32 pNext; - VkQueryPoolSamplingModeINTEL performanceCountersSampling; -} VkQueryPoolPerformanceQueryCreateInfoINTEL32; -typedef VkQueryPoolPerformanceQueryCreateInfoINTEL32 VkQueryPoolCreateInfoINTEL32; - -typedef struct VkQueryPoolCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkQueryPoolCreateFlags flags; - VkQueryType queryType; - uint32_t queryCount; - VkQueryPipelineStatisticFlags pipelineStatistics; -} VkQueryPoolCreateInfo32; - -typedef struct VkRayTracingShaderGroupCreateInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkRayTracingShaderGroupTypeKHR type; - uint32_t generalShader; - uint32_t closestHitShader; - uint32_t anyHitShader; - uint32_t intersectionShader; - PTR32 pShaderGroupCaptureReplayHandle; -} VkRayTracingShaderGroupCreateInfoKHR32; - -typedef struct VkRayTracingPipelineInterfaceCreateInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxPipelineRayPayloadSize; - uint32_t maxPipelineRayHitAttributeSize; -} VkRayTracingPipelineInterfaceCreateInfoKHR32; - -typedef struct VkRayTracingPipelineCreateInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineCreateFlags flags; - uint32_t stageCount; - PTR32 pStages; - uint32_t groupCount; - PTR32 pGroups; - uint32_t maxPipelineRayRecursionDepth; - PTR32 pLibraryInfo; - PTR32 pLibraryInterface; - PTR32 pDynamicState; - VkPipelineLayout DECLSPEC_ALIGN(8) layout; - VkPipeline DECLSPEC_ALIGN(8) basePipelineHandle; - int32_t basePipelineIndex; -} VkRayTracingPipelineCreateInfoKHR32; - -typedef struct VkRayTracingShaderGroupCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkRayTracingShaderGroupTypeKHR type; - uint32_t generalShader; - uint32_t closestHitShader; - uint32_t anyHitShader; - uint32_t intersectionShader; -} VkRayTracingShaderGroupCreateInfoNV32; - -typedef struct VkRayTracingPipelineCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineCreateFlags flags; - uint32_t stageCount; - PTR32 pStages; - uint32_t groupCount; - PTR32 pGroups; - uint32_t maxRecursionDepth; - VkPipelineLayout DECLSPEC_ALIGN(8) layout; - VkPipeline DECLSPEC_ALIGN(8) basePipelineHandle; - int32_t basePipelineIndex; -} VkRayTracingPipelineCreateInfoNV32; - -typedef struct VkSubpassDescription32 -{ - VkSubpassDescriptionFlags flags; - VkPipelineBindPoint pipelineBindPoint; - uint32_t inputAttachmentCount; - PTR32 pInputAttachments; - uint32_t colorAttachmentCount; - PTR32 pColorAttachments; - PTR32 pResolveAttachments; - PTR32 pDepthStencilAttachment; - uint32_t preserveAttachmentCount; - PTR32 pPreserveAttachments; -} VkSubpassDescription32; - -typedef struct VkRenderPassMultiviewCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t subpassCount; - PTR32 pViewMasks; - uint32_t dependencyCount; - PTR32 pViewOffsets; - uint32_t correlationMaskCount; - PTR32 pCorrelationMasks; -} VkRenderPassMultiviewCreateInfo32; -typedef VkRenderPassMultiviewCreateInfo32 VkRenderPassMultiviewCreateInfoKHR32; - -typedef struct VkRenderPassInputAttachmentAspectCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t aspectReferenceCount; - PTR32 pAspectReferences; -} VkRenderPassInputAttachmentAspectCreateInfo32; -typedef VkRenderPassInputAttachmentAspectCreateInfo32 VkRenderPassInputAttachmentAspectCreateInfoKHR32; - -typedef struct VkRenderPassFragmentDensityMapCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkAttachmentReference fragmentDensityMapAttachment; -} VkRenderPassFragmentDensityMapCreateInfoEXT32; - -typedef struct VkRenderPassCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkRenderPassCreateFlags flags; - uint32_t attachmentCount; - PTR32 pAttachments; - uint32_t subpassCount; - PTR32 pSubpasses; - uint32_t dependencyCount; - PTR32 pDependencies; -} VkRenderPassCreateInfo32; - -typedef struct VkAttachmentDescriptionStencilLayout32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageLayout stencilInitialLayout; - VkImageLayout stencilFinalLayout; -} VkAttachmentDescriptionStencilLayout32; -typedef VkAttachmentDescriptionStencilLayout32 VkAttachmentDescriptionStencilLayoutKHR32; - -typedef struct VkAttachmentDescription232 -{ - VkStructureType sType; - PTR32 pNext; - VkAttachmentDescriptionFlags flags; - VkFormat format; - VkSampleCountFlagBits samples; - VkAttachmentLoadOp loadOp; - VkAttachmentStoreOp storeOp; - VkAttachmentLoadOp stencilLoadOp; - VkAttachmentStoreOp stencilStoreOp; - VkImageLayout initialLayout; - VkImageLayout finalLayout; -} VkAttachmentDescription232; -typedef VkAttachmentDescription232 VkAttachmentDescription2KHR32; - -typedef struct VkAttachmentReferenceStencilLayout32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageLayout stencilLayout; -} VkAttachmentReferenceStencilLayout32; -typedef VkAttachmentReferenceStencilLayout32 VkAttachmentReferenceStencilLayoutKHR32; - -typedef struct VkAttachmentReference232 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t attachment; - VkImageLayout layout; - VkImageAspectFlags aspectMask; -} VkAttachmentReference232; -typedef VkAttachmentReference232 VkAttachmentReference2KHR32; - -typedef struct VkSubpassDescriptionDepthStencilResolve32 -{ - VkStructureType sType; - PTR32 pNext; - VkResolveModeFlagBits depthResolveMode; - VkResolveModeFlagBits stencilResolveMode; - PTR32 pDepthStencilResolveAttachment; -} VkSubpassDescriptionDepthStencilResolve32; -typedef VkSubpassDescriptionDepthStencilResolve32 VkSubpassDescriptionDepthStencilResolveKHR32; - -typedef struct VkFragmentShadingRateAttachmentInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 pFragmentShadingRateAttachment; - VkExtent2D shadingRateAttachmentTexelSize; -} VkFragmentShadingRateAttachmentInfoKHR32; - -typedef struct VkRenderPassCreationControlEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 disallowMerging; -} VkRenderPassCreationControlEXT32; - -typedef struct VkRenderPassSubpassFeedbackCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 pSubpassFeedback; -} VkRenderPassSubpassFeedbackCreateInfoEXT32; - -typedef struct VkSubpassDescription232 -{ - VkStructureType sType; - PTR32 pNext; - VkSubpassDescriptionFlags flags; - VkPipelineBindPoint pipelineBindPoint; - uint32_t viewMask; - uint32_t inputAttachmentCount; - PTR32 pInputAttachments; - uint32_t colorAttachmentCount; - PTR32 pColorAttachments; - PTR32 pResolveAttachments; - PTR32 pDepthStencilAttachment; - uint32_t preserveAttachmentCount; - PTR32 pPreserveAttachments; -} VkSubpassDescription232; -typedef VkSubpassDescription232 VkSubpassDescription2KHR32; - -typedef struct VkSubpassDependency232 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t srcSubpass; - uint32_t dstSubpass; - VkPipelineStageFlags srcStageMask; - VkPipelineStageFlags dstStageMask; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkDependencyFlags dependencyFlags; - int32_t viewOffset; -} VkSubpassDependency232; -typedef VkSubpassDependency232 VkSubpassDependency2KHR32; - -typedef struct VkRenderPassCreationFeedbackCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 pRenderPassFeedback; -} VkRenderPassCreationFeedbackCreateInfoEXT32; - -typedef struct VkRenderPassCreateInfo232 -{ - VkStructureType sType; - PTR32 pNext; - VkRenderPassCreateFlags flags; - uint32_t attachmentCount; - PTR32 pAttachments; - uint32_t subpassCount; - PTR32 pSubpasses; - uint32_t dependencyCount; - PTR32 pDependencies; - uint32_t correlatedViewMaskCount; - PTR32 pCorrelatedViewMasks; -} VkRenderPassCreateInfo232; -typedef VkRenderPassCreateInfo232 VkRenderPassCreateInfo2KHR32; - -typedef struct VkSamplerReductionModeCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkSamplerReductionMode reductionMode; -} VkSamplerReductionModeCreateInfo32; -typedef VkSamplerReductionModeCreateInfo32 VkSamplerReductionModeCreateInfoEXT32; - -typedef struct VkSamplerCustomBorderColorCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkClearColorValue customBorderColor; - VkFormat format; -} VkSamplerCustomBorderColorCreateInfoEXT32; - -typedef struct VkSamplerBorderColorComponentMappingCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkComponentMapping components; - VkBool32 srgb; -} VkSamplerBorderColorComponentMappingCreateInfoEXT32; - -typedef struct VkSamplerCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkSamplerCreateFlags flags; - VkFilter magFilter; - VkFilter minFilter; - VkSamplerMipmapMode mipmapMode; - VkSamplerAddressMode addressModeU; - VkSamplerAddressMode addressModeV; - VkSamplerAddressMode addressModeW; - float mipLodBias; - VkBool32 anisotropyEnable; - float maxAnisotropy; - VkBool32 compareEnable; - VkCompareOp compareOp; - float minLod; - float maxLod; - VkBorderColor borderColor; - VkBool32 unnormalizedCoordinates; -} VkSamplerCreateInfo32; - -typedef struct VkSamplerYcbcrConversionCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkFormat format; - VkSamplerYcbcrModelConversion ycbcrModel; - VkSamplerYcbcrRange ycbcrRange; - VkComponentMapping components; - VkChromaLocation xChromaOffset; - VkChromaLocation yChromaOffset; - VkFilter chromaFilter; - VkBool32 forceExplicitReconstruction; -} VkSamplerYcbcrConversionCreateInfo32; -typedef VkSamplerYcbcrConversionCreateInfo32 VkSamplerYcbcrConversionCreateInfoKHR32; - -typedef struct VkExportSemaphoreCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkExternalSemaphoreHandleTypeFlags handleTypes; -} VkExportSemaphoreCreateInfo32; -typedef VkExportSemaphoreCreateInfo32 VkExportSemaphoreCreateInfoKHR32; - -typedef struct VkSemaphoreTypeCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkSemaphoreType semaphoreType; - uint64_t DECLSPEC_ALIGN(8) initialValue; -} VkSemaphoreTypeCreateInfo32; -typedef VkSemaphoreTypeCreateInfo32 VkSemaphoreTypeCreateInfoKHR32; - -typedef struct VkSemaphoreCreateInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkSemaphoreCreateFlags flags; -} VkSemaphoreCreateInfo32; - -typedef struct VkDeviceGroupSwapchainCreateInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceGroupPresentModeFlagsKHR modes; -} VkDeviceGroupSwapchainCreateInfoKHR32; - -typedef struct VkSwapchainPresentBarrierCreateInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 presentBarrierEnable; -} VkSwapchainPresentBarrierCreateInfoNV32; - -typedef struct VkSwapchainPresentModesCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t presentModeCount; - PTR32 pPresentModes; -} VkSwapchainPresentModesCreateInfoEXT32; - -typedef struct VkSwapchainPresentScalingCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkPresentScalingFlagsEXT scalingBehavior; - VkPresentGravityFlagsEXT presentGravityX; - VkPresentGravityFlagsEXT presentGravityY; -} VkSwapchainPresentScalingCreateInfoEXT32; - -typedef struct VkSwapchainCreateInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkSwapchainCreateFlagsKHR flags; - VkSurfaceKHR DECLSPEC_ALIGN(8) surface; - uint32_t minImageCount; - VkFormat imageFormat; - VkColorSpaceKHR imageColorSpace; - VkExtent2D imageExtent; - uint32_t imageArrayLayers; - VkImageUsageFlags imageUsage; - VkSharingMode imageSharingMode; - uint32_t queueFamilyIndexCount; - PTR32 pQueueFamilyIndices; - VkSurfaceTransformFlagBitsKHR preTransform; - VkCompositeAlphaFlagBitsKHR compositeAlpha; - VkPresentModeKHR presentMode; - VkBool32 clipped; - VkSwapchainKHR DECLSPEC_ALIGN(8) oldSwapchain; -} VkSwapchainCreateInfoKHR32; - -typedef struct VkValidationCacheCreateInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkValidationCacheCreateFlagsEXT flags; - PTR32 initialDataSize; - PTR32 pInitialData; -} VkValidationCacheCreateInfoEXT32; - -typedef struct VkWin32SurfaceCreateInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkWin32SurfaceCreateFlagsKHR flags; - PTR32 hinstance; - PTR32 hwnd; -} VkWin32SurfaceCreateInfoKHR32; - -typedef struct VkDebugMarkerObjectNameInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkDebugReportObjectTypeEXT objectType; - uint64_t DECLSPEC_ALIGN(8) object; - PTR32 pObjectName; -} VkDebugMarkerObjectNameInfoEXT32; - -typedef struct VkDebugMarkerObjectTagInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkDebugReportObjectTypeEXT objectType; - uint64_t DECLSPEC_ALIGN(8) object; - uint64_t DECLSPEC_ALIGN(8) tagName; - PTR32 tagSize; - PTR32 pTag; -} VkDebugMarkerObjectTagInfoEXT32; - -typedef struct VkPhysicalDeviceGroupProperties32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t physicalDeviceCount; - PTR32 physicalDevices[VK_MAX_DEVICE_GROUP_SIZE]; - VkBool32 subsetAllocation; -} VkPhysicalDeviceGroupProperties32; -typedef VkPhysicalDeviceGroupProperties32 VkPhysicalDeviceGroupPropertiesKHR32; - -typedef struct VkPerformanceCounterKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkPerformanceCounterUnitKHR unit; - VkPerformanceCounterScopeKHR scope; - VkPerformanceCounterStorageKHR storage; - uint8_t uuid[VK_UUID_SIZE]; -} VkPerformanceCounterKHR32; - -typedef struct VkPerformanceCounterDescriptionKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkPerformanceCounterDescriptionFlagsKHR flags; - char name[VK_MAX_DESCRIPTION_SIZE]; - char category[VK_MAX_DESCRIPTION_SIZE]; - char description[VK_MAX_DESCRIPTION_SIZE]; -} VkPerformanceCounterDescriptionKHR32; - -typedef struct VkMappedMemoryRange32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkDeviceSize DECLSPEC_ALIGN(8) size; -} VkMappedMemoryRange32; - -typedef struct VkAccelerationStructureBuildSizesInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceSize DECLSPEC_ALIGN(8) accelerationStructureSize; - VkDeviceSize DECLSPEC_ALIGN(8) updateScratchSize; - VkDeviceSize DECLSPEC_ALIGN(8) buildScratchSize; -} VkAccelerationStructureBuildSizesInfoKHR32; - -typedef struct VkAccelerationStructureDeviceAddressInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkAccelerationStructureKHR DECLSPEC_ALIGN(8) accelerationStructure; -} VkAccelerationStructureDeviceAddressInfoKHR32; - -typedef struct VkAccelerationStructureMemoryRequirementsInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkAccelerationStructureMemoryRequirementsTypeNV type; - VkAccelerationStructureNV DECLSPEC_ALIGN(8) accelerationStructure; -} VkAccelerationStructureMemoryRequirementsInfoNV32; - -typedef struct VkMemoryRequirements32 -{ - VkDeviceSize DECLSPEC_ALIGN(8) size; - VkDeviceSize DECLSPEC_ALIGN(8) alignment; - uint32_t memoryTypeBits; -} VkMemoryRequirements32; - - -typedef struct VkAccelerationStructureCaptureDescriptorDataInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkAccelerationStructureKHR DECLSPEC_ALIGN(8) accelerationStructure; - VkAccelerationStructureNV DECLSPEC_ALIGN(8) accelerationStructureNV; -} VkAccelerationStructureCaptureDescriptorDataInfoEXT32; - -typedef struct VkBufferDeviceAddressInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkBuffer DECLSPEC_ALIGN(8) buffer; -} VkBufferDeviceAddressInfo32; -typedef VkBufferDeviceAddressInfo32 VkBufferDeviceAddressInfoKHR32; -typedef VkBufferDeviceAddressInfo32 VkBufferDeviceAddressInfoEXT32; - -typedef struct VkBufferMemoryRequirementsInfo232 -{ - VkStructureType sType; - PTR32 pNext; - VkBuffer DECLSPEC_ALIGN(8) buffer; -} VkBufferMemoryRequirementsInfo232; -typedef VkBufferMemoryRequirementsInfo232 VkBufferMemoryRequirementsInfo2KHR32; - -typedef struct VkMemoryDedicatedRequirements32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 prefersDedicatedAllocation; - VkBool32 requiresDedicatedAllocation; -} VkMemoryDedicatedRequirements32; -typedef VkMemoryDedicatedRequirements32 VkMemoryDedicatedRequirementsKHR32; - -typedef struct VkMemoryRequirements232 -{ - VkStructureType sType; - PTR32 pNext; - VkMemoryRequirements32 DECLSPEC_ALIGN(8) memoryRequirements; -} VkMemoryRequirements232; -typedef VkMemoryRequirements232 VkMemoryRequirements2KHR32; - -typedef struct VkBufferCaptureDescriptorDataInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBuffer DECLSPEC_ALIGN(8) buffer; -} VkBufferCaptureDescriptorDataInfoEXT32; - -typedef struct VkCalibratedTimestampInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkTimeDomainEXT timeDomain; -} VkCalibratedTimestampInfoEXT32; - -typedef struct VkDescriptorAddressInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceAddress DECLSPEC_ALIGN(8) address; - VkDeviceSize DECLSPEC_ALIGN(8) range; - VkFormat format; -} VkDescriptorAddressInfoEXT32; - -typedef union VkDescriptorDataEXT32 -{ - PTR32 pSampler; - PTR32 pCombinedImageSampler; - PTR32 pInputAttachmentImage; - PTR32 pSampledImage; - PTR32 pStorageImage; - PTR32 pUniformTexelBuffer; - PTR32 pStorageTexelBuffer; - PTR32 pUniformBuffer; - PTR32 pStorageBuffer; - VkDeviceAddress DECLSPEC_ALIGN(8) accelerationStructure; -} VkDescriptorDataEXT32; - -typedef struct VkDescriptorGetInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkDescriptorType type; - VkDescriptorDataEXT32 DECLSPEC_ALIGN(8) data; -} VkDescriptorGetInfoEXT32; - -typedef struct VkDescriptorSetBindingReferenceVALVE32 -{ - VkStructureType sType; - PTR32 pNext; - VkDescriptorSetLayout DECLSPEC_ALIGN(8) descriptorSetLayout; - uint32_t binding; -} VkDescriptorSetBindingReferenceVALVE32; - -typedef struct VkDescriptorSetLayoutHostMappingInfoVALVE32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 descriptorOffset; - uint32_t descriptorSize; -} VkDescriptorSetLayoutHostMappingInfoVALVE32; - -typedef struct VkDescriptorSetVariableDescriptorCountLayoutSupport32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxVariableDescriptorCount; -} VkDescriptorSetVariableDescriptorCountLayoutSupport32; -typedef VkDescriptorSetVariableDescriptorCountLayoutSupport32 VkDescriptorSetVariableDescriptorCountLayoutSupportEXT32; - -typedef struct VkDescriptorSetLayoutSupport32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 supported; -} VkDescriptorSetLayoutSupport32; -typedef VkDescriptorSetLayoutSupport32 VkDescriptorSetLayoutSupportKHR32; - -typedef struct VkAccelerationStructureVersionInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 pVersionData; -} VkAccelerationStructureVersionInfoKHR32; - -typedef struct VkDeviceBufferMemoryRequirements32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 pCreateInfo; -} VkDeviceBufferMemoryRequirements32; -typedef VkDeviceBufferMemoryRequirements32 VkDeviceBufferMemoryRequirementsKHR32; - -typedef struct VkDeviceFaultCountsEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t addressInfoCount; - uint32_t vendorInfoCount; - VkDeviceSize DECLSPEC_ALIGN(8) vendorBinarySize; -} VkDeviceFaultCountsEXT32; - -typedef struct VkDeviceFaultAddressInfoEXT32 -{ - VkDeviceFaultAddressTypeEXT addressType; - VkDeviceAddress DECLSPEC_ALIGN(8) reportedAddress; - VkDeviceSize DECLSPEC_ALIGN(8) addressPrecision; -} VkDeviceFaultAddressInfoEXT32; - -typedef struct VkDeviceFaultVendorInfoEXT32 -{ - char description[VK_MAX_DESCRIPTION_SIZE]; - uint64_t DECLSPEC_ALIGN(8) vendorFaultCode; - uint64_t DECLSPEC_ALIGN(8) vendorFaultData; -} VkDeviceFaultVendorInfoEXT32; - -typedef struct VkDeviceFaultInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - char description[VK_MAX_DESCRIPTION_SIZE]; - PTR32 pAddressInfos; - PTR32 pVendorInfos; - PTR32 pVendorBinaryData; -} VkDeviceFaultInfoEXT32; - -typedef struct VkDeviceGroupPresentCapabilitiesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t presentMask[VK_MAX_DEVICE_GROUP_SIZE]; - VkDeviceGroupPresentModeFlagsKHR modes; -} VkDeviceGroupPresentCapabilitiesKHR32; - -typedef struct VkDeviceImageMemoryRequirements32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 pCreateInfo; - VkImageAspectFlagBits planeAspect; -} VkDeviceImageMemoryRequirements32; -typedef VkDeviceImageMemoryRequirements32 VkDeviceImageMemoryRequirementsKHR32; - -typedef struct VkSparseImageMemoryRequirements32 -{ - VkSparseImageFormatProperties formatProperties; - uint32_t imageMipTailFirstLod; - VkDeviceSize DECLSPEC_ALIGN(8) imageMipTailSize; - VkDeviceSize DECLSPEC_ALIGN(8) imageMipTailOffset; - VkDeviceSize DECLSPEC_ALIGN(8) imageMipTailStride; -} VkSparseImageMemoryRequirements32; - -typedef struct VkSparseImageMemoryRequirements232 -{ - VkStructureType sType; - PTR32 pNext; - VkSparseImageMemoryRequirements32 DECLSPEC_ALIGN(8) memoryRequirements; -} VkSparseImageMemoryRequirements232; -typedef VkSparseImageMemoryRequirements232 VkSparseImageMemoryRequirements2KHR32; - -typedef struct VkDeviceMemoryOpaqueCaptureAddressInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; -} VkDeviceMemoryOpaqueCaptureAddressInfo32; -typedef VkDeviceMemoryOpaqueCaptureAddressInfo32 VkDeviceMemoryOpaqueCaptureAddressInfoKHR32; - -typedef struct VkMicromapVersionInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 pVersionData; -} VkMicromapVersionInfoEXT32; - -typedef struct VkDeviceQueueInfo232 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceQueueCreateFlags flags; - uint32_t queueFamilyIndex; - uint32_t queueIndex; -} VkDeviceQueueInfo232; - -typedef struct VkTilePropertiesQCOM32 -{ - VkStructureType sType; - PTR32 pNext; - VkExtent3D tileSize; - VkExtent2D apronSize; - VkOffset2D origin; -} VkTilePropertiesQCOM32; - -typedef struct VkGeneratedCommandsMemoryRequirementsInfoNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineBindPoint pipelineBindPoint; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - VkIndirectCommandsLayoutNV DECLSPEC_ALIGN(8) indirectCommandsLayout; - uint32_t maxSequencesCount; -} VkGeneratedCommandsMemoryRequirementsInfoNV32; - -typedef struct VkImagePlaneMemoryRequirementsInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageAspectFlagBits planeAspect; -} VkImagePlaneMemoryRequirementsInfo32; -typedef VkImagePlaneMemoryRequirementsInfo32 VkImagePlaneMemoryRequirementsInfoKHR32; - -typedef struct VkImageMemoryRequirementsInfo232 -{ - VkStructureType sType; - PTR32 pNext; - VkImage DECLSPEC_ALIGN(8) image; -} VkImageMemoryRequirementsInfo232; -typedef VkImageMemoryRequirementsInfo232 VkImageMemoryRequirementsInfo2KHR32; - -typedef struct VkImageCaptureDescriptorDataInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkImage DECLSPEC_ALIGN(8) image; -} VkImageCaptureDescriptorDataInfoEXT32; - -typedef struct VkImageSparseMemoryRequirementsInfo232 -{ - VkStructureType sType; - PTR32 pNext; - VkImage DECLSPEC_ALIGN(8) image; -} VkImageSparseMemoryRequirementsInfo232; -typedef VkImageSparseMemoryRequirementsInfo232 VkImageSparseMemoryRequirementsInfo2KHR32; - -typedef struct VkSubresourceLayout32 -{ - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkDeviceSize DECLSPEC_ALIGN(8) size; - VkDeviceSize DECLSPEC_ALIGN(8) rowPitch; - VkDeviceSize DECLSPEC_ALIGN(8) arrayPitch; - VkDeviceSize DECLSPEC_ALIGN(8) depthPitch; -} VkSubresourceLayout32; - -typedef struct VkImageSubresource2EXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageSubresource imageSubresource; -} VkImageSubresource2EXT32; - -typedef struct VkImageCompressionPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageCompressionFlagsEXT imageCompressionFlags; - VkImageCompressionFixedRateFlagsEXT imageCompressionFixedRateFlags; -} VkImageCompressionPropertiesEXT32; - -typedef struct VkSubresourceLayout2EXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkSubresourceLayout32 DECLSPEC_ALIGN(8) subresourceLayout; -} VkSubresourceLayout2EXT32; - -typedef struct VkImageViewAddressPropertiesNVX32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceAddress DECLSPEC_ALIGN(8) deviceAddress; - VkDeviceSize DECLSPEC_ALIGN(8) size; -} VkImageViewAddressPropertiesNVX32; - -typedef struct VkImageViewHandleInfoNVX32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageView DECLSPEC_ALIGN(8) imageView; - VkDescriptorType descriptorType; - VkSampler DECLSPEC_ALIGN(8) sampler; -} VkImageViewHandleInfoNVX32; - -typedef struct VkImageViewCaptureDescriptorDataInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageView DECLSPEC_ALIGN(8) imageView; -} VkImageViewCaptureDescriptorDataInfoEXT32; - -typedef struct VkMemoryHostPointerPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t memoryTypeBits; -} VkMemoryHostPointerPropertiesEXT32; - -typedef struct VkMicromapBuildSizesInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceSize DECLSPEC_ALIGN(8) micromapSize; - VkDeviceSize DECLSPEC_ALIGN(8) buildScratchSize; - VkBool32 discardable; -} VkMicromapBuildSizesInfoEXT32; - -typedef union VkPerformanceValueDataINTEL32 -{ - uint32_t value32; - uint64_t DECLSPEC_ALIGN(8) value64; - float valueFloat; - VkBool32 valueBool; - PTR32 valueString; -} VkPerformanceValueDataINTEL32; - -typedef struct VkPerformanceValueINTEL32 -{ - VkPerformanceValueTypeINTEL type; - VkPerformanceValueDataINTEL32 DECLSPEC_ALIGN(8) data; -} VkPerformanceValueINTEL32; - -typedef struct VkCooperativeMatrixPropertiesNV32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t MSize; - uint32_t NSize; - uint32_t KSize; - VkComponentTypeNV AType; - VkComponentTypeNV BType; - VkComponentTypeNV CType; - VkComponentTypeNV DType; - VkScopeNV scope; -} VkCooperativeMatrixPropertiesNV32; - -typedef struct VkPhysicalDeviceExternalBufferInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkBufferCreateFlags flags; - VkBufferUsageFlags usage; - VkExternalMemoryHandleTypeFlagBits handleType; -} VkPhysicalDeviceExternalBufferInfo32; -typedef VkPhysicalDeviceExternalBufferInfo32 VkPhysicalDeviceExternalBufferInfoKHR32; - -typedef struct VkExternalBufferProperties32 -{ - VkStructureType sType; - PTR32 pNext; - VkExternalMemoryProperties externalMemoryProperties; -} VkExternalBufferProperties32; -typedef VkExternalBufferProperties32 VkExternalBufferPropertiesKHR32; - -typedef struct VkPhysicalDeviceExternalFenceInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkExternalFenceHandleTypeFlagBits handleType; -} VkPhysicalDeviceExternalFenceInfo32; -typedef VkPhysicalDeviceExternalFenceInfo32 VkPhysicalDeviceExternalFenceInfoKHR32; - -typedef struct VkExternalFenceProperties32 -{ - VkStructureType sType; - PTR32 pNext; - VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes; - VkExternalFenceHandleTypeFlags compatibleHandleTypes; - VkExternalFenceFeatureFlags externalFenceFeatures; -} VkExternalFenceProperties32; -typedef VkExternalFenceProperties32 VkExternalFencePropertiesKHR32; - -typedef struct VkPhysicalDeviceExternalSemaphoreInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkExternalSemaphoreHandleTypeFlagBits handleType; -} VkPhysicalDeviceExternalSemaphoreInfo32; -typedef VkPhysicalDeviceExternalSemaphoreInfo32 VkPhysicalDeviceExternalSemaphoreInfoKHR32; - -typedef struct VkExternalSemaphoreProperties32 -{ - VkStructureType sType; - PTR32 pNext; - VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes; - VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes; - VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures; -} VkExternalSemaphoreProperties32; -typedef VkExternalSemaphoreProperties32 VkExternalSemaphorePropertiesKHR32; - -typedef struct VkSubpassResolvePerformanceQueryEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 optimal; -} VkSubpassResolvePerformanceQueryEXT32; - -typedef struct VkFormatProperties332 -{ - VkStructureType sType; - PTR32 pNext; - VkFormatFeatureFlags2 DECLSPEC_ALIGN(8) linearTilingFeatures; - VkFormatFeatureFlags2 DECLSPEC_ALIGN(8) optimalTilingFeatures; - VkFormatFeatureFlags2 DECLSPEC_ALIGN(8) bufferFeatures; -} VkFormatProperties332; -typedef VkFormatProperties332 VkFormatProperties3KHR32; - -typedef struct VkFormatProperties232 -{ - VkStructureType sType; - PTR32 pNext; - VkFormatProperties formatProperties; -} VkFormatProperties232; -typedef VkFormatProperties232 VkFormatProperties2KHR32; - -typedef struct VkPhysicalDeviceFragmentShadingRateKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkSampleCountFlags sampleCounts; - VkExtent2D fragmentSize; -} VkPhysicalDeviceFragmentShadingRateKHR32; - -typedef struct VkImageFormatProperties32 -{ - VkExtent3D maxExtent; - uint32_t maxMipLevels; - uint32_t maxArrayLayers; - VkSampleCountFlags sampleCounts; - VkDeviceSize DECLSPEC_ALIGN(8) maxResourceSize; -} VkImageFormatProperties32; - -typedef struct VkPhysicalDeviceExternalImageFormatInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkExternalMemoryHandleTypeFlagBits handleType; -} VkPhysicalDeviceExternalImageFormatInfo32; -typedef VkPhysicalDeviceExternalImageFormatInfo32 VkPhysicalDeviceExternalImageFormatInfoKHR32; - -typedef struct VkPhysicalDeviceImageViewImageFormatInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkImageViewType imageViewType; -} VkPhysicalDeviceImageViewImageFormatInfoEXT32; - -typedef struct VkPhysicalDeviceImageFormatInfo232 -{ - VkStructureType sType; - PTR32 pNext; - VkFormat format; - VkImageType type; - VkImageTiling tiling; - VkImageUsageFlags usage; - VkImageCreateFlags flags; -} VkPhysicalDeviceImageFormatInfo232; -typedef VkPhysicalDeviceImageFormatInfo232 VkPhysicalDeviceImageFormatInfo2KHR32; - -typedef struct VkExternalImageFormatProperties32 -{ - VkStructureType sType; - PTR32 pNext; - VkExternalMemoryProperties externalMemoryProperties; -} VkExternalImageFormatProperties32; -typedef VkExternalImageFormatProperties32 VkExternalImageFormatPropertiesKHR32; - -typedef struct VkSamplerYcbcrConversionImageFormatProperties32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t combinedImageSamplerDescriptorCount; -} VkSamplerYcbcrConversionImageFormatProperties32; -typedef VkSamplerYcbcrConversionImageFormatProperties32 VkSamplerYcbcrConversionImageFormatPropertiesKHR32; - -typedef struct VkTextureLODGatherFormatPropertiesAMD32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 supportsTextureGatherLODBiasAMD; -} VkTextureLODGatherFormatPropertiesAMD32; - -typedef struct VkFilterCubicImageViewImageFormatPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 filterCubic; - VkBool32 filterCubicMinmax; -} VkFilterCubicImageViewImageFormatPropertiesEXT32; - -typedef struct VkImageFormatProperties232 -{ - VkStructureType sType; - PTR32 pNext; - VkImageFormatProperties32 DECLSPEC_ALIGN(8) imageFormatProperties; -} VkImageFormatProperties232; -typedef VkImageFormatProperties232 VkImageFormatProperties2KHR32; - -typedef struct VkMemoryHeap32 -{ - VkDeviceSize DECLSPEC_ALIGN(8) size; - VkMemoryHeapFlags flags; -} VkMemoryHeap32; - -typedef struct VkPhysicalDeviceMemoryProperties32 -{ - uint32_t memoryTypeCount; - VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES]; - uint32_t memoryHeapCount; - VkMemoryHeap32 DECLSPEC_ALIGN(8) memoryHeaps[VK_MAX_MEMORY_HEAPS]; -} VkPhysicalDeviceMemoryProperties32; - -typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceSize DECLSPEC_ALIGN(8) heapBudget[VK_MAX_MEMORY_HEAPS]; - VkDeviceSize DECLSPEC_ALIGN(8) heapUsage[VK_MAX_MEMORY_HEAPS]; -} VkPhysicalDeviceMemoryBudgetPropertiesEXT32; - -typedef struct VkPhysicalDeviceMemoryProperties232 -{ - VkStructureType sType; - PTR32 pNext; - VkPhysicalDeviceMemoryProperties32 DECLSPEC_ALIGN(8) memoryProperties; -} VkPhysicalDeviceMemoryProperties232; -typedef VkPhysicalDeviceMemoryProperties232 VkPhysicalDeviceMemoryProperties2KHR32; - -typedef struct VkMultisamplePropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkExtent2D maxSampleLocationGridSize; -} VkMultisamplePropertiesEXT32; - -typedef struct VkOpticalFlowImageFormatPropertiesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkFormat format; -} VkOpticalFlowImageFormatPropertiesNV32; - -typedef struct VkPhysicalDeviceLimits32 -{ - uint32_t maxImageDimension1D; - uint32_t maxImageDimension2D; - uint32_t maxImageDimension3D; - uint32_t maxImageDimensionCube; - uint32_t maxImageArrayLayers; - uint32_t maxTexelBufferElements; - uint32_t maxUniformBufferRange; - uint32_t maxStorageBufferRange; - uint32_t maxPushConstantsSize; - uint32_t maxMemoryAllocationCount; - uint32_t maxSamplerAllocationCount; - VkDeviceSize DECLSPEC_ALIGN(8) bufferImageGranularity; - VkDeviceSize DECLSPEC_ALIGN(8) sparseAddressSpaceSize; - uint32_t maxBoundDescriptorSets; - uint32_t maxPerStageDescriptorSamplers; - uint32_t maxPerStageDescriptorUniformBuffers; - uint32_t maxPerStageDescriptorStorageBuffers; - uint32_t maxPerStageDescriptorSampledImages; - uint32_t maxPerStageDescriptorStorageImages; - uint32_t maxPerStageDescriptorInputAttachments; - uint32_t maxPerStageResources; - uint32_t maxDescriptorSetSamplers; - uint32_t maxDescriptorSetUniformBuffers; - uint32_t maxDescriptorSetUniformBuffersDynamic; - uint32_t maxDescriptorSetStorageBuffers; - uint32_t maxDescriptorSetStorageBuffersDynamic; - uint32_t maxDescriptorSetSampledImages; - uint32_t maxDescriptorSetStorageImages; - uint32_t maxDescriptorSetInputAttachments; - uint32_t maxVertexInputAttributes; - uint32_t maxVertexInputBindings; - uint32_t maxVertexInputAttributeOffset; - uint32_t maxVertexInputBindingStride; - uint32_t maxVertexOutputComponents; - uint32_t maxTessellationGenerationLevel; - uint32_t maxTessellationPatchSize; - uint32_t maxTessellationControlPerVertexInputComponents; - uint32_t maxTessellationControlPerVertexOutputComponents; - uint32_t maxTessellationControlPerPatchOutputComponents; - uint32_t maxTessellationControlTotalOutputComponents; - uint32_t maxTessellationEvaluationInputComponents; - uint32_t maxTessellationEvaluationOutputComponents; - uint32_t maxGeometryShaderInvocations; - uint32_t maxGeometryInputComponents; - uint32_t maxGeometryOutputComponents; - uint32_t maxGeometryOutputVertices; - uint32_t maxGeometryTotalOutputComponents; - uint32_t maxFragmentInputComponents; - uint32_t maxFragmentOutputAttachments; - uint32_t maxFragmentDualSrcAttachments; - uint32_t maxFragmentCombinedOutputResources; - uint32_t maxComputeSharedMemorySize; - uint32_t maxComputeWorkGroupCount[3]; - uint32_t maxComputeWorkGroupInvocations; - uint32_t maxComputeWorkGroupSize[3]; - uint32_t subPixelPrecisionBits; - uint32_t subTexelPrecisionBits; - uint32_t mipmapPrecisionBits; - uint32_t maxDrawIndexedIndexValue; - uint32_t maxDrawIndirectCount; - float maxSamplerLodBias; - float maxSamplerAnisotropy; - uint32_t maxViewports; - uint32_t maxViewportDimensions[2]; - float viewportBoundsRange[2]; - uint32_t viewportSubPixelBits; - PTR32 minMemoryMapAlignment; - VkDeviceSize DECLSPEC_ALIGN(8) minTexelBufferOffsetAlignment; - VkDeviceSize DECLSPEC_ALIGN(8) minUniformBufferOffsetAlignment; - VkDeviceSize DECLSPEC_ALIGN(8) minStorageBufferOffsetAlignment; - int32_t minTexelOffset; - uint32_t maxTexelOffset; - int32_t minTexelGatherOffset; - uint32_t maxTexelGatherOffset; - float minInterpolationOffset; - float maxInterpolationOffset; - uint32_t subPixelInterpolationOffsetBits; - uint32_t maxFramebufferWidth; - uint32_t maxFramebufferHeight; - uint32_t maxFramebufferLayers; - VkSampleCountFlags framebufferColorSampleCounts; - VkSampleCountFlags framebufferDepthSampleCounts; - VkSampleCountFlags framebufferStencilSampleCounts; - VkSampleCountFlags framebufferNoAttachmentsSampleCounts; - uint32_t maxColorAttachments; - VkSampleCountFlags sampledImageColorSampleCounts; - VkSampleCountFlags sampledImageIntegerSampleCounts; - VkSampleCountFlags sampledImageDepthSampleCounts; - VkSampleCountFlags sampledImageStencilSampleCounts; - VkSampleCountFlags storageImageSampleCounts; - uint32_t maxSampleMaskWords; - VkBool32 timestampComputeAndGraphics; - float timestampPeriod; - uint32_t maxClipDistances; - uint32_t maxCullDistances; - uint32_t maxCombinedClipAndCullDistances; - uint32_t discreteQueuePriorities; - float pointSizeRange[2]; - float lineWidthRange[2]; - float pointSizeGranularity; - float lineWidthGranularity; - VkBool32 strictLines; - VkBool32 standardSampleLocations; - VkDeviceSize DECLSPEC_ALIGN(8) optimalBufferCopyOffsetAlignment; - VkDeviceSize DECLSPEC_ALIGN(8) optimalBufferCopyRowPitchAlignment; - VkDeviceSize DECLSPEC_ALIGN(8) nonCoherentAtomSize; -} VkPhysicalDeviceLimits32; - -typedef struct VkPhysicalDeviceProperties32 -{ - uint32_t apiVersion; - uint32_t driverVersion; - uint32_t vendorID; - uint32_t deviceID; - VkPhysicalDeviceType deviceType; - char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]; - uint8_t pipelineCacheUUID[VK_UUID_SIZE]; - VkPhysicalDeviceLimits32 DECLSPEC_ALIGN(8) limits; - VkPhysicalDeviceSparseProperties sparseProperties; -} VkPhysicalDeviceProperties32; - -typedef struct VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxGraphicsShaderGroupCount; - uint32_t maxIndirectSequenceCount; - uint32_t maxIndirectCommandsTokenCount; - uint32_t maxIndirectCommandsStreamCount; - uint32_t maxIndirectCommandsTokenOffset; - uint32_t maxIndirectCommandsStreamStride; - uint32_t minSequencesCountBufferOffsetAlignment; - uint32_t minSequencesIndexBufferOffsetAlignment; - uint32_t minIndirectCommandsBufferOffsetAlignment; -} VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV32; - -typedef struct VkPhysicalDeviceMultiDrawPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxMultiDrawCount; -} VkPhysicalDeviceMultiDrawPropertiesEXT32; - -typedef struct VkPhysicalDevicePushDescriptorPropertiesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxPushDescriptors; -} VkPhysicalDevicePushDescriptorPropertiesKHR32; - -typedef struct VkPhysicalDeviceDriverProperties32 -{ - VkStructureType sType; - PTR32 pNext; - VkDriverId driverID; - char driverName[VK_MAX_DRIVER_NAME_SIZE]; - char driverInfo[VK_MAX_DRIVER_INFO_SIZE]; - VkConformanceVersion conformanceVersion; -} VkPhysicalDeviceDriverProperties32; -typedef VkPhysicalDeviceDriverProperties32 VkPhysicalDeviceDriverPropertiesKHR32; - -typedef struct VkPhysicalDeviceIDProperties32 -{ - VkStructureType sType; - PTR32 pNext; - uint8_t deviceUUID[VK_UUID_SIZE]; - uint8_t driverUUID[VK_UUID_SIZE]; - uint8_t deviceLUID[VK_LUID_SIZE]; - uint32_t deviceNodeMask; - VkBool32 deviceLUIDValid; -} VkPhysicalDeviceIDProperties32; -typedef VkPhysicalDeviceIDProperties32 VkPhysicalDeviceIDPropertiesKHR32; - -typedef struct VkPhysicalDeviceMultiviewProperties32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxMultiviewViewCount; - uint32_t maxMultiviewInstanceIndex; -} VkPhysicalDeviceMultiviewProperties32; -typedef VkPhysicalDeviceMultiviewProperties32 VkPhysicalDeviceMultiviewPropertiesKHR32; - -typedef struct VkPhysicalDeviceDiscardRectanglePropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxDiscardRectangles; -} VkPhysicalDeviceDiscardRectanglePropertiesEXT32; - -typedef struct VkPhysicalDeviceSubgroupProperties32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t subgroupSize; - VkShaderStageFlags supportedStages; - VkSubgroupFeatureFlags supportedOperations; - VkBool32 quadOperationsInAllStages; -} VkPhysicalDeviceSubgroupProperties32; - -typedef struct VkPhysicalDevicePointClippingProperties32 -{ - VkStructureType sType; - PTR32 pNext; - VkPointClippingBehavior pointClippingBehavior; -} VkPhysicalDevicePointClippingProperties32; -typedef VkPhysicalDevicePointClippingProperties32 VkPhysicalDevicePointClippingPropertiesKHR32; - -typedef struct VkPhysicalDeviceProtectedMemoryProperties32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 protectedNoFault; -} VkPhysicalDeviceProtectedMemoryProperties32; - -typedef struct VkPhysicalDeviceSamplerFilterMinmaxProperties32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 filterMinmaxSingleComponentFormats; - VkBool32 filterMinmaxImageComponentMapping; -} VkPhysicalDeviceSamplerFilterMinmaxProperties32; -typedef VkPhysicalDeviceSamplerFilterMinmaxProperties32 VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT32; - -typedef struct VkPhysicalDeviceSampleLocationsPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkSampleCountFlags sampleLocationSampleCounts; - VkExtent2D maxSampleLocationGridSize; - float sampleLocationCoordinateRange[2]; - uint32_t sampleLocationSubPixelBits; - VkBool32 variableSampleLocations; -} VkPhysicalDeviceSampleLocationsPropertiesEXT32; - -typedef struct VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t advancedBlendMaxColorAttachments; - VkBool32 advancedBlendIndependentBlend; - VkBool32 advancedBlendNonPremultipliedSrcColor; - VkBool32 advancedBlendNonPremultipliedDstColor; - VkBool32 advancedBlendCorrelatedOverlap; - VkBool32 advancedBlendAllOperations; -} VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT32; - -typedef struct VkPhysicalDeviceInlineUniformBlockProperties32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxInlineUniformBlockSize; - uint32_t maxPerStageDescriptorInlineUniformBlocks; - uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; - uint32_t maxDescriptorSetInlineUniformBlocks; - uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; -} VkPhysicalDeviceInlineUniformBlockProperties32; -typedef VkPhysicalDeviceInlineUniformBlockProperties32 VkPhysicalDeviceInlineUniformBlockPropertiesEXT32; - -typedef struct VkPhysicalDeviceMaintenance3Properties32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxPerSetDescriptors; - VkDeviceSize DECLSPEC_ALIGN(8) maxMemoryAllocationSize; -} VkPhysicalDeviceMaintenance3Properties32; -typedef VkPhysicalDeviceMaintenance3Properties32 VkPhysicalDeviceMaintenance3PropertiesKHR32; - -typedef struct VkPhysicalDeviceMaintenance4Properties32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceSize DECLSPEC_ALIGN(8) maxBufferSize; -} VkPhysicalDeviceMaintenance4Properties32; -typedef VkPhysicalDeviceMaintenance4Properties32 VkPhysicalDeviceMaintenance4PropertiesKHR32; - -typedef struct VkPhysicalDeviceFloatControlsProperties32 -{ - VkStructureType sType; - PTR32 pNext; - VkShaderFloatControlsIndependence denormBehaviorIndependence; - VkShaderFloatControlsIndependence roundingModeIndependence; - VkBool32 shaderSignedZeroInfNanPreserveFloat16; - VkBool32 shaderSignedZeroInfNanPreserveFloat32; - VkBool32 shaderSignedZeroInfNanPreserveFloat64; - VkBool32 shaderDenormPreserveFloat16; - VkBool32 shaderDenormPreserveFloat32; - VkBool32 shaderDenormPreserveFloat64; - VkBool32 shaderDenormFlushToZeroFloat16; - VkBool32 shaderDenormFlushToZeroFloat32; - VkBool32 shaderDenormFlushToZeroFloat64; - VkBool32 shaderRoundingModeRTEFloat16; - VkBool32 shaderRoundingModeRTEFloat32; - VkBool32 shaderRoundingModeRTEFloat64; - VkBool32 shaderRoundingModeRTZFloat16; - VkBool32 shaderRoundingModeRTZFloat32; - VkBool32 shaderRoundingModeRTZFloat64; -} VkPhysicalDeviceFloatControlsProperties32; -typedef VkPhysicalDeviceFloatControlsProperties32 VkPhysicalDeviceFloatControlsPropertiesKHR32; - -typedef struct VkPhysicalDeviceExternalMemoryHostPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceSize DECLSPEC_ALIGN(8) minImportedHostPointerAlignment; -} VkPhysicalDeviceExternalMemoryHostPropertiesEXT32; - -typedef struct VkPhysicalDeviceConservativeRasterizationPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - float primitiveOverestimationSize; - float maxExtraPrimitiveOverestimationSize; - float extraPrimitiveOverestimationSizeGranularity; - VkBool32 primitiveUnderestimation; - VkBool32 conservativePointAndLineRasterization; - VkBool32 degenerateTrianglesRasterized; - VkBool32 degenerateLinesRasterized; - VkBool32 fullyCoveredFragmentShaderInputVariable; - VkBool32 conservativeRasterizationPostDepthCoverage; -} VkPhysicalDeviceConservativeRasterizationPropertiesEXT32; - -typedef struct VkPhysicalDeviceShaderCorePropertiesAMD32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t shaderEngineCount; - uint32_t shaderArraysPerEngineCount; - uint32_t computeUnitsPerShaderArray; - uint32_t simdPerComputeUnit; - uint32_t wavefrontsPerSimd; - uint32_t wavefrontSize; - uint32_t sgprsPerSimd; - uint32_t minSgprAllocation; - uint32_t maxSgprAllocation; - uint32_t sgprAllocationGranularity; - uint32_t vgprsPerSimd; - uint32_t minVgprAllocation; - uint32_t maxVgprAllocation; - uint32_t vgprAllocationGranularity; -} VkPhysicalDeviceShaderCorePropertiesAMD32; - -typedef struct VkPhysicalDeviceShaderCoreProperties2AMD32 -{ - VkStructureType sType; - PTR32 pNext; - VkShaderCorePropertiesFlagsAMD shaderCoreFeatures; - uint32_t activeComputeUnitCount; -} VkPhysicalDeviceShaderCoreProperties2AMD32; - -typedef struct VkPhysicalDeviceDescriptorIndexingProperties32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxUpdateAfterBindDescriptorsInAllPools; - VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; - VkBool32 shaderSampledImageArrayNonUniformIndexingNative; - VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; - VkBool32 shaderStorageImageArrayNonUniformIndexingNative; - VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; - VkBool32 robustBufferAccessUpdateAfterBind; - VkBool32 quadDivergentImplicitLod; - uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; - uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; - uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; - uint32_t maxPerStageUpdateAfterBindResources; - uint32_t maxDescriptorSetUpdateAfterBindSamplers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindSampledImages; - uint32_t maxDescriptorSetUpdateAfterBindStorageImages; - uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; -} VkPhysicalDeviceDescriptorIndexingProperties32; -typedef VkPhysicalDeviceDescriptorIndexingProperties32 VkPhysicalDeviceDescriptorIndexingPropertiesEXT32; - -typedef struct VkPhysicalDeviceTimelineSemaphoreProperties32 -{ - VkStructureType sType; - PTR32 pNext; - uint64_t DECLSPEC_ALIGN(8) maxTimelineSemaphoreValueDifference; -} VkPhysicalDeviceTimelineSemaphoreProperties32; -typedef VkPhysicalDeviceTimelineSemaphoreProperties32 VkPhysicalDeviceTimelineSemaphorePropertiesKHR32; - -typedef struct VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxVertexAttribDivisor; -} VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT32; - -typedef struct VkPhysicalDevicePCIBusInfoPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t pciDomain; - uint32_t pciBus; - uint32_t pciDevice; - uint32_t pciFunction; -} VkPhysicalDevicePCIBusInfoPropertiesEXT32; - -typedef struct VkPhysicalDeviceDepthStencilResolveProperties32 -{ - VkStructureType sType; - PTR32 pNext; - VkResolveModeFlags supportedDepthResolveModes; - VkResolveModeFlags supportedStencilResolveModes; - VkBool32 independentResolveNone; - VkBool32 independentResolve; -} VkPhysicalDeviceDepthStencilResolveProperties32; -typedef VkPhysicalDeviceDepthStencilResolveProperties32 VkPhysicalDeviceDepthStencilResolvePropertiesKHR32; - -typedef struct VkPhysicalDeviceTransformFeedbackPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxTransformFeedbackStreams; - uint32_t maxTransformFeedbackBuffers; - VkDeviceSize DECLSPEC_ALIGN(8) maxTransformFeedbackBufferSize; - uint32_t maxTransformFeedbackStreamDataSize; - uint32_t maxTransformFeedbackBufferDataSize; - uint32_t maxTransformFeedbackBufferDataStride; - VkBool32 transformFeedbackQueries; - VkBool32 transformFeedbackStreamsLinesTriangles; - VkBool32 transformFeedbackRasterizationStreamSelect; - VkBool32 transformFeedbackDraw; -} VkPhysicalDeviceTransformFeedbackPropertiesEXT32; - -typedef struct VkPhysicalDeviceCopyMemoryIndirectPropertiesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkQueueFlags supportedQueues; -} VkPhysicalDeviceCopyMemoryIndirectPropertiesNV32; - -typedef struct VkPhysicalDeviceMemoryDecompressionPropertiesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkMemoryDecompressionMethodFlagsNV DECLSPEC_ALIGN(8) decompressionMethods; - uint64_t DECLSPEC_ALIGN(8) maxDecompressionIndirectCount; -} VkPhysicalDeviceMemoryDecompressionPropertiesNV32; - -typedef struct VkPhysicalDeviceShadingRateImagePropertiesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkExtent2D shadingRateTexelSize; - uint32_t shadingRatePaletteSize; - uint32_t shadingRateMaxCoarseSamples; -} VkPhysicalDeviceShadingRateImagePropertiesNV32; - -typedef struct VkPhysicalDeviceMeshShaderPropertiesNV32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxDrawMeshTasksCount; - uint32_t maxTaskWorkGroupInvocations; - uint32_t maxTaskWorkGroupSize[3]; - uint32_t maxTaskTotalMemorySize; - uint32_t maxTaskOutputCount; - uint32_t maxMeshWorkGroupInvocations; - uint32_t maxMeshWorkGroupSize[3]; - uint32_t maxMeshTotalMemorySize; - uint32_t maxMeshOutputVertices; - uint32_t maxMeshOutputPrimitives; - uint32_t maxMeshMultiviewViewCount; - uint32_t meshOutputPerVertexGranularity; - uint32_t meshOutputPerPrimitiveGranularity; -} VkPhysicalDeviceMeshShaderPropertiesNV32; - -typedef struct VkPhysicalDeviceMeshShaderPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxTaskWorkGroupTotalCount; - uint32_t maxTaskWorkGroupCount[3]; - uint32_t maxTaskWorkGroupInvocations; - uint32_t maxTaskWorkGroupSize[3]; - uint32_t maxTaskPayloadSize; - uint32_t maxTaskSharedMemorySize; - uint32_t maxTaskPayloadAndSharedMemorySize; - uint32_t maxMeshWorkGroupTotalCount; - uint32_t maxMeshWorkGroupCount[3]; - uint32_t maxMeshWorkGroupInvocations; - uint32_t maxMeshWorkGroupSize[3]; - uint32_t maxMeshSharedMemorySize; - uint32_t maxMeshPayloadAndSharedMemorySize; - uint32_t maxMeshOutputMemorySize; - uint32_t maxMeshPayloadAndOutputMemorySize; - uint32_t maxMeshOutputComponents; - uint32_t maxMeshOutputVertices; - uint32_t maxMeshOutputPrimitives; - uint32_t maxMeshOutputLayers; - uint32_t maxMeshMultiviewViewCount; - uint32_t meshOutputPerVertexGranularity; - uint32_t meshOutputPerPrimitiveGranularity; - uint32_t maxPreferredTaskWorkGroupInvocations; - uint32_t maxPreferredMeshWorkGroupInvocations; - VkBool32 prefersLocalInvocationVertexOutput; - VkBool32 prefersLocalInvocationPrimitiveOutput; - VkBool32 prefersCompactVertexOutput; - VkBool32 prefersCompactPrimitiveOutput; -} VkPhysicalDeviceMeshShaderPropertiesEXT32; - -typedef struct VkPhysicalDeviceAccelerationStructurePropertiesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - uint64_t DECLSPEC_ALIGN(8) maxGeometryCount; - uint64_t DECLSPEC_ALIGN(8) maxInstanceCount; - uint64_t DECLSPEC_ALIGN(8) maxPrimitiveCount; - uint32_t maxPerStageDescriptorAccelerationStructures; - uint32_t maxPerStageDescriptorUpdateAfterBindAccelerationStructures; - uint32_t maxDescriptorSetAccelerationStructures; - uint32_t maxDescriptorSetUpdateAfterBindAccelerationStructures; - uint32_t minAccelerationStructureScratchOffsetAlignment; -} VkPhysicalDeviceAccelerationStructurePropertiesKHR32; - -typedef struct VkPhysicalDeviceRayTracingPipelinePropertiesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t shaderGroupHandleSize; - uint32_t maxRayRecursionDepth; - uint32_t maxShaderGroupStride; - uint32_t shaderGroupBaseAlignment; - uint32_t shaderGroupHandleCaptureReplaySize; - uint32_t maxRayDispatchInvocationCount; - uint32_t shaderGroupHandleAlignment; - uint32_t maxRayHitAttributeSize; -} VkPhysicalDeviceRayTracingPipelinePropertiesKHR32; - -typedef struct VkPhysicalDeviceRayTracingPropertiesNV32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t shaderGroupHandleSize; - uint32_t maxRecursionDepth; - uint32_t maxShaderGroupStride; - uint32_t shaderGroupBaseAlignment; - uint64_t DECLSPEC_ALIGN(8) maxGeometryCount; - uint64_t DECLSPEC_ALIGN(8) maxInstanceCount; - uint64_t DECLSPEC_ALIGN(8) maxTriangleCount; - uint32_t maxDescriptorSetAccelerationStructures; -} VkPhysicalDeviceRayTracingPropertiesNV32; - -typedef struct VkPhysicalDeviceFragmentDensityMapPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkExtent2D minFragmentDensityTexelSize; - VkExtent2D maxFragmentDensityTexelSize; - VkBool32 fragmentDensityInvocations; -} VkPhysicalDeviceFragmentDensityMapPropertiesEXT32; - -typedef struct VkPhysicalDeviceFragmentDensityMap2PropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 subsampledLoads; - VkBool32 subsampledCoarseReconstructionEarlyAccess; - uint32_t maxSubsampledArrayLayers; - uint32_t maxDescriptorSetSubsampledSamplers; -} VkPhysicalDeviceFragmentDensityMap2PropertiesEXT32; - -typedef struct VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM32 -{ - VkStructureType sType; - PTR32 pNext; - VkExtent2D fragmentDensityOffsetGranularity; -} VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM32; - -typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkShaderStageFlags cooperativeMatrixSupportedStages; -} VkPhysicalDeviceCooperativeMatrixPropertiesNV32; - -typedef struct VkPhysicalDevicePerformanceQueryPropertiesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 allowCommandBufferQueryCopies; -} VkPhysicalDevicePerformanceQueryPropertiesKHR32; - -typedef struct VkPhysicalDeviceShaderSMBuiltinsPropertiesNV32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t shaderSMCount; - uint32_t shaderWarpsPerSM; -} VkPhysicalDeviceShaderSMBuiltinsPropertiesNV32; - -typedef struct VkPhysicalDeviceTexelBufferAlignmentProperties32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceSize DECLSPEC_ALIGN(8) storageTexelBufferOffsetAlignmentBytes; - VkBool32 storageTexelBufferOffsetSingleTexelAlignment; - VkDeviceSize DECLSPEC_ALIGN(8) uniformTexelBufferOffsetAlignmentBytes; - VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; -} VkPhysicalDeviceTexelBufferAlignmentProperties32; -typedef VkPhysicalDeviceTexelBufferAlignmentProperties32 VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT32; - -typedef struct VkPhysicalDeviceSubgroupSizeControlProperties32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t minSubgroupSize; - uint32_t maxSubgroupSize; - uint32_t maxComputeWorkgroupSubgroups; - VkShaderStageFlags requiredSubgroupSizeStages; -} VkPhysicalDeviceSubgroupSizeControlProperties32; -typedef VkPhysicalDeviceSubgroupSizeControlProperties32 VkPhysicalDeviceSubgroupSizeControlPropertiesEXT32; - -typedef struct VkPhysicalDeviceSubpassShadingPropertiesHUAWEI32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxSubpassShadingWorkgroupSizeAspectRatio; -} VkPhysicalDeviceSubpassShadingPropertiesHUAWEI32; - -typedef struct VkPhysicalDeviceLineRasterizationPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t lineSubPixelPrecisionBits; -} VkPhysicalDeviceLineRasterizationPropertiesEXT32; - -typedef struct VkPhysicalDeviceVulkan11Properties32 -{ - VkStructureType sType; - PTR32 pNext; - uint8_t deviceUUID[VK_UUID_SIZE]; - uint8_t driverUUID[VK_UUID_SIZE]; - uint8_t deviceLUID[VK_LUID_SIZE]; - uint32_t deviceNodeMask; - VkBool32 deviceLUIDValid; - uint32_t subgroupSize; - VkShaderStageFlags subgroupSupportedStages; - VkSubgroupFeatureFlags subgroupSupportedOperations; - VkBool32 subgroupQuadOperationsInAllStages; - VkPointClippingBehavior pointClippingBehavior; - uint32_t maxMultiviewViewCount; - uint32_t maxMultiviewInstanceIndex; - VkBool32 protectedNoFault; - uint32_t maxPerSetDescriptors; - VkDeviceSize DECLSPEC_ALIGN(8) maxMemoryAllocationSize; -} VkPhysicalDeviceVulkan11Properties32; - -typedef struct VkPhysicalDeviceVulkan12Properties32 -{ - VkStructureType sType; - PTR32 pNext; - VkDriverId driverID; - char driverName[VK_MAX_DRIVER_NAME_SIZE]; - char driverInfo[VK_MAX_DRIVER_INFO_SIZE]; - VkConformanceVersion conformanceVersion; - VkShaderFloatControlsIndependence denormBehaviorIndependence; - VkShaderFloatControlsIndependence roundingModeIndependence; - VkBool32 shaderSignedZeroInfNanPreserveFloat16; - VkBool32 shaderSignedZeroInfNanPreserveFloat32; - VkBool32 shaderSignedZeroInfNanPreserveFloat64; - VkBool32 shaderDenormPreserveFloat16; - VkBool32 shaderDenormPreserveFloat32; - VkBool32 shaderDenormPreserveFloat64; - VkBool32 shaderDenormFlushToZeroFloat16; - VkBool32 shaderDenormFlushToZeroFloat32; - VkBool32 shaderDenormFlushToZeroFloat64; - VkBool32 shaderRoundingModeRTEFloat16; - VkBool32 shaderRoundingModeRTEFloat32; - VkBool32 shaderRoundingModeRTEFloat64; - VkBool32 shaderRoundingModeRTZFloat16; - VkBool32 shaderRoundingModeRTZFloat32; - VkBool32 shaderRoundingModeRTZFloat64; - uint32_t maxUpdateAfterBindDescriptorsInAllPools; - VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; - VkBool32 shaderSampledImageArrayNonUniformIndexingNative; - VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; - VkBool32 shaderStorageImageArrayNonUniformIndexingNative; - VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; - VkBool32 robustBufferAccessUpdateAfterBind; - VkBool32 quadDivergentImplicitLod; - uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; - uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; - uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; - uint32_t maxPerStageUpdateAfterBindResources; - uint32_t maxDescriptorSetUpdateAfterBindSamplers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindSampledImages; - uint32_t maxDescriptorSetUpdateAfterBindStorageImages; - uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; - VkResolveModeFlags supportedDepthResolveModes; - VkResolveModeFlags supportedStencilResolveModes; - VkBool32 independentResolveNone; - VkBool32 independentResolve; - VkBool32 filterMinmaxSingleComponentFormats; - VkBool32 filterMinmaxImageComponentMapping; - uint64_t DECLSPEC_ALIGN(8) maxTimelineSemaphoreValueDifference; - VkSampleCountFlags framebufferIntegerColorSampleCounts; -} VkPhysicalDeviceVulkan12Properties32; - -typedef struct VkPhysicalDeviceVulkan13Properties32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t minSubgroupSize; - uint32_t maxSubgroupSize; - uint32_t maxComputeWorkgroupSubgroups; - VkShaderStageFlags requiredSubgroupSizeStages; - uint32_t maxInlineUniformBlockSize; - uint32_t maxPerStageDescriptorInlineUniformBlocks; - uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; - uint32_t maxDescriptorSetInlineUniformBlocks; - uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; - uint32_t maxInlineUniformTotalSize; - VkBool32 integerDotProduct8BitUnsignedAccelerated; - VkBool32 integerDotProduct8BitSignedAccelerated; - VkBool32 integerDotProduct8BitMixedSignednessAccelerated; - VkBool32 integerDotProduct4x8BitPackedUnsignedAccelerated; - VkBool32 integerDotProduct4x8BitPackedSignedAccelerated; - VkBool32 integerDotProduct4x8BitPackedMixedSignednessAccelerated; - VkBool32 integerDotProduct16BitUnsignedAccelerated; - VkBool32 integerDotProduct16BitSignedAccelerated; - VkBool32 integerDotProduct16BitMixedSignednessAccelerated; - VkBool32 integerDotProduct32BitUnsignedAccelerated; - VkBool32 integerDotProduct32BitSignedAccelerated; - VkBool32 integerDotProduct32BitMixedSignednessAccelerated; - VkBool32 integerDotProduct64BitUnsignedAccelerated; - VkBool32 integerDotProduct64BitSignedAccelerated; - VkBool32 integerDotProduct64BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating8BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating8BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating16BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating16BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating32BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating32BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating64BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating64BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated; - VkDeviceSize DECLSPEC_ALIGN(8) storageTexelBufferOffsetAlignmentBytes; - VkBool32 storageTexelBufferOffsetSingleTexelAlignment; - VkDeviceSize DECLSPEC_ALIGN(8) uniformTexelBufferOffsetAlignmentBytes; - VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; - VkDeviceSize DECLSPEC_ALIGN(8) maxBufferSize; -} VkPhysicalDeviceVulkan13Properties32; - -typedef struct VkPhysicalDeviceCustomBorderColorPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxCustomBorderColorSamplers; -} VkPhysicalDeviceCustomBorderColorPropertiesEXT32; - -typedef struct VkPhysicalDeviceExtendedDynamicState3PropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 dynamicPrimitiveTopologyUnrestricted; -} VkPhysicalDeviceExtendedDynamicState3PropertiesEXT32; - -typedef struct VkPhysicalDeviceRobustness2PropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceSize DECLSPEC_ALIGN(8) robustStorageBufferAccessSizeAlignment; - VkDeviceSize DECLSPEC_ALIGN(8) robustUniformBufferAccessSizeAlignment; -} VkPhysicalDeviceRobustness2PropertiesEXT32; - -typedef struct VkPhysicalDeviceFragmentShadingRatePropertiesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkExtent2D minFragmentShadingRateAttachmentTexelSize; - VkExtent2D maxFragmentShadingRateAttachmentTexelSize; - uint32_t maxFragmentShadingRateAttachmentTexelSizeAspectRatio; - VkBool32 primitiveFragmentShadingRateWithMultipleViewports; - VkBool32 layeredShadingRateAttachments; - VkBool32 fragmentShadingRateNonTrivialCombinerOps; - VkExtent2D maxFragmentSize; - uint32_t maxFragmentSizeAspectRatio; - uint32_t maxFragmentShadingRateCoverageSamples; - VkSampleCountFlagBits maxFragmentShadingRateRasterizationSamples; - VkBool32 fragmentShadingRateWithShaderDepthStencilWrites; - VkBool32 fragmentShadingRateWithSampleMask; - VkBool32 fragmentShadingRateWithShaderSampleMask; - VkBool32 fragmentShadingRateWithConservativeRasterization; - VkBool32 fragmentShadingRateWithFragmentShaderInterlock; - VkBool32 fragmentShadingRateWithCustomSampleLocations; - VkBool32 fragmentShadingRateStrictMultiplyCombiner; -} VkPhysicalDeviceFragmentShadingRatePropertiesKHR32; - -typedef struct VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkSampleCountFlagBits maxFragmentShadingRateInvocationCount; -} VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV32; - -typedef struct VkPhysicalDeviceProvokingVertexPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 provokingVertexModePerPipeline; - VkBool32 transformFeedbackPreservesTriangleFanProvokingVertex; -} VkPhysicalDeviceProvokingVertexPropertiesEXT32; - -typedef struct VkPhysicalDeviceDescriptorBufferPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 combinedImageSamplerDescriptorSingleArray; - VkBool32 bufferlessPushDescriptors; - VkBool32 allowSamplerImageViewPostSubmitCreation; - VkDeviceSize DECLSPEC_ALIGN(8) descriptorBufferOffsetAlignment; - uint32_t maxDescriptorBufferBindings; - uint32_t maxResourceDescriptorBufferBindings; - uint32_t maxSamplerDescriptorBufferBindings; - uint32_t maxEmbeddedImmutableSamplerBindings; - uint32_t maxEmbeddedImmutableSamplers; - PTR32 bufferCaptureReplayDescriptorDataSize; - PTR32 imageCaptureReplayDescriptorDataSize; - PTR32 imageViewCaptureReplayDescriptorDataSize; - PTR32 samplerCaptureReplayDescriptorDataSize; - PTR32 accelerationStructureCaptureReplayDescriptorDataSize; - PTR32 samplerDescriptorSize; - PTR32 combinedImageSamplerDescriptorSize; - PTR32 sampledImageDescriptorSize; - PTR32 storageImageDescriptorSize; - PTR32 uniformTexelBufferDescriptorSize; - PTR32 robustUniformTexelBufferDescriptorSize; - PTR32 storageTexelBufferDescriptorSize; - PTR32 robustStorageTexelBufferDescriptorSize; - PTR32 uniformBufferDescriptorSize; - PTR32 robustUniformBufferDescriptorSize; - PTR32 storageBufferDescriptorSize; - PTR32 robustStorageBufferDescriptorSize; - PTR32 inputAttachmentDescriptorSize; - PTR32 accelerationStructureDescriptorSize; - VkDeviceSize DECLSPEC_ALIGN(8) maxSamplerDescriptorBufferRange; - VkDeviceSize DECLSPEC_ALIGN(8) maxResourceDescriptorBufferRange; - VkDeviceSize DECLSPEC_ALIGN(8) samplerDescriptorBufferAddressSpaceSize; - VkDeviceSize DECLSPEC_ALIGN(8) resourceDescriptorBufferAddressSpaceSize; - VkDeviceSize DECLSPEC_ALIGN(8) descriptorBufferAddressSpaceSize; -} VkPhysicalDeviceDescriptorBufferPropertiesEXT32; - -typedef struct VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 combinedImageSamplerDensityMapDescriptorSize; -} VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT32; - -typedef struct VkPhysicalDeviceShaderIntegerDotProductProperties32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 integerDotProduct8BitUnsignedAccelerated; - VkBool32 integerDotProduct8BitSignedAccelerated; - VkBool32 integerDotProduct8BitMixedSignednessAccelerated; - VkBool32 integerDotProduct4x8BitPackedUnsignedAccelerated; - VkBool32 integerDotProduct4x8BitPackedSignedAccelerated; - VkBool32 integerDotProduct4x8BitPackedMixedSignednessAccelerated; - VkBool32 integerDotProduct16BitUnsignedAccelerated; - VkBool32 integerDotProduct16BitSignedAccelerated; - VkBool32 integerDotProduct16BitMixedSignednessAccelerated; - VkBool32 integerDotProduct32BitUnsignedAccelerated; - VkBool32 integerDotProduct32BitSignedAccelerated; - VkBool32 integerDotProduct32BitMixedSignednessAccelerated; - VkBool32 integerDotProduct64BitUnsignedAccelerated; - VkBool32 integerDotProduct64BitSignedAccelerated; - VkBool32 integerDotProduct64BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating8BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating8BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating16BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating16BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating32BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating32BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating64BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating64BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated; -} VkPhysicalDeviceShaderIntegerDotProductProperties32; -typedef VkPhysicalDeviceShaderIntegerDotProductProperties32 VkPhysicalDeviceShaderIntegerDotProductPropertiesKHR32; - -typedef struct VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 triStripVertexOrderIndependentOfProvokingVertex; -} VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR32; - -typedef struct VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 graphicsPipelineLibraryFastLinking; - VkBool32 graphicsPipelineLibraryIndependentInterpolationDecoration; -} VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT32; - -typedef struct VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint8_t shaderModuleIdentifierAlgorithmUUID[VK_UUID_SIZE]; -} VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT32; - -typedef struct VkPhysicalDeviceOpacityMicromapPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxOpacity2StateSubdivisionLevel; - uint32_t maxOpacity4StateSubdivisionLevel; -} VkPhysicalDeviceOpacityMicromapPropertiesEXT32; - -typedef struct VkPhysicalDevicePipelineRobustnessPropertiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineRobustnessBufferBehaviorEXT defaultRobustnessStorageBuffers; - VkPipelineRobustnessBufferBehaviorEXT defaultRobustnessUniformBuffers; - VkPipelineRobustnessBufferBehaviorEXT defaultRobustnessVertexInputs; - VkPipelineRobustnessImageBehaviorEXT defaultRobustnessImages; -} VkPhysicalDevicePipelineRobustnessPropertiesEXT32; - -typedef struct VkPhysicalDeviceImageProcessingPropertiesQCOM32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t maxWeightFilterPhases; - VkExtent2D maxWeightFilterDimension; - VkExtent2D maxBlockMatchRegion; - VkExtent2D maxBoxFilterBlockSize; -} VkPhysicalDeviceImageProcessingPropertiesQCOM32; - -typedef struct VkPhysicalDeviceOpticalFlowPropertiesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkOpticalFlowGridSizeFlagsNV supportedOutputGridSizes; - VkOpticalFlowGridSizeFlagsNV supportedHintGridSizes; - VkBool32 hintSupported; - VkBool32 costSupported; - VkBool32 bidirectionalFlowSupported; - VkBool32 globalFlowSupported; - uint32_t minWidth; - uint32_t minHeight; - uint32_t maxWidth; - uint32_t maxHeight; - uint32_t maxNumRegionsOfInterest; -} VkPhysicalDeviceOpticalFlowPropertiesNV32; - -typedef struct VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM32 -{ - VkStructureType sType; - PTR32 pNext; - uint64_t DECLSPEC_ALIGN(8) shaderCoreMask; - uint32_t shaderCoreCount; - uint32_t shaderWarpsPerCore; -} VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM32; - -typedef struct VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkRayTracingInvocationReorderModeNV rayTracingInvocationReorderReorderingHint; -} VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV32; - -typedef struct VkPhysicalDeviceProperties232 -{ - VkStructureType sType; - PTR32 pNext; - VkPhysicalDeviceProperties32 DECLSPEC_ALIGN(8) properties; -} VkPhysicalDeviceProperties232; -typedef VkPhysicalDeviceProperties232 VkPhysicalDeviceProperties2KHR32; - -typedef struct VkQueueFamilyGlobalPriorityPropertiesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t priorityCount; - VkQueueGlobalPriorityKHR priorities[VK_MAX_GLOBAL_PRIORITY_SIZE_KHR]; -} VkQueueFamilyGlobalPriorityPropertiesKHR32; -typedef VkQueueFamilyGlobalPriorityPropertiesKHR32 VkQueueFamilyGlobalPriorityPropertiesEXT32; - -typedef struct VkQueueFamilyCheckpointPropertiesNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineStageFlags checkpointExecutionStageMask; -} VkQueueFamilyCheckpointPropertiesNV32; - -typedef struct VkQueueFamilyCheckpointProperties2NV32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) checkpointExecutionStageMask; -} VkQueueFamilyCheckpointProperties2NV32; - -typedef struct VkQueueFamilyProperties232 -{ - VkStructureType sType; - PTR32 pNext; - VkQueueFamilyProperties queueFamilyProperties; -} VkQueueFamilyProperties232; -typedef VkQueueFamilyProperties232 VkQueueFamilyProperties2KHR32; - -typedef struct VkPhysicalDeviceSparseImageFormatInfo232 -{ - VkStructureType sType; - PTR32 pNext; - VkFormat format; - VkImageType type; - VkSampleCountFlagBits samples; - VkImageUsageFlags usage; - VkImageTiling tiling; -} VkPhysicalDeviceSparseImageFormatInfo232; -typedef VkPhysicalDeviceSparseImageFormatInfo232 VkPhysicalDeviceSparseImageFormatInfo2KHR32; - -typedef struct VkSparseImageFormatProperties232 -{ - VkStructureType sType; - PTR32 pNext; - VkSparseImageFormatProperties properties; -} VkSparseImageFormatProperties232; -typedef VkSparseImageFormatProperties232 VkSparseImageFormatProperties2KHR32; - -typedef struct VkFramebufferMixedSamplesCombinationNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkCoverageReductionModeNV coverageReductionMode; - VkSampleCountFlagBits rasterizationSamples; - VkSampleCountFlags depthStencilSamples; - VkSampleCountFlags colorSamples; -} VkFramebufferMixedSamplesCombinationNV32; - -typedef struct VkSurfacePresentModeEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkPresentModeKHR presentMode; -} VkSurfacePresentModeEXT32; - -typedef struct VkPhysicalDeviceSurfaceInfo2KHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkSurfaceKHR DECLSPEC_ALIGN(8) surface; -} VkPhysicalDeviceSurfaceInfo2KHR32; - -typedef struct VkSurfaceCapabilitiesPresentBarrierNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 presentBarrierSupported; -} VkSurfaceCapabilitiesPresentBarrierNV32; - -typedef struct VkSurfacePresentScalingCapabilitiesEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkPresentScalingFlagsEXT supportedPresentScaling; - VkPresentGravityFlagsEXT supportedPresentGravityX; - VkPresentGravityFlagsEXT supportedPresentGravityY; - VkExtent2D minScaledImageExtent; - VkExtent2D maxScaledImageExtent; -} VkSurfacePresentScalingCapabilitiesEXT32; - -typedef struct VkSurfacePresentModeCompatibilityEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t presentModeCount; - PTR32 pPresentModes; -} VkSurfacePresentModeCompatibilityEXT32; - -typedef struct VkSurfaceCapabilities2KHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkSurfaceCapabilitiesKHR surfaceCapabilities; -} VkSurfaceCapabilities2KHR32; - -typedef struct VkSurfaceFormat2KHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkSurfaceFormatKHR surfaceFormat; -} VkSurfaceFormat2KHR32; - -typedef struct VkPhysicalDeviceToolProperties32 -{ - VkStructureType sType; - PTR32 pNext; - char name[VK_MAX_EXTENSION_NAME_SIZE]; - char version[VK_MAX_EXTENSION_NAME_SIZE]; - VkToolPurposeFlags purposes; - char description[VK_MAX_DESCRIPTION_SIZE]; - char layer[VK_MAX_EXTENSION_NAME_SIZE]; -} VkPhysicalDeviceToolProperties32; -typedef VkPhysicalDeviceToolProperties32 VkPhysicalDeviceToolPropertiesEXT32; - -typedef struct VkPipelineExecutableInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - uint32_t executableIndex; -} VkPipelineExecutableInfoKHR32; - -typedef struct VkPipelineExecutableInternalRepresentationKHR32 -{ - VkStructureType sType; - PTR32 pNext; - char name[VK_MAX_DESCRIPTION_SIZE]; - char description[VK_MAX_DESCRIPTION_SIZE]; - VkBool32 isText; - PTR32 dataSize; - PTR32 pData; -} VkPipelineExecutableInternalRepresentationKHR32; - -typedef struct VkPipelineInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipeline DECLSPEC_ALIGN(8) pipeline; -} VkPipelineInfoKHR32; -typedef VkPipelineInfoKHR32 VkPipelineInfoEXT32; - -typedef struct VkPipelineExecutablePropertiesKHR32 -{ - VkStructureType sType; - PTR32 pNext; - VkShaderStageFlags stages; - char name[VK_MAX_DESCRIPTION_SIZE]; - char description[VK_MAX_DESCRIPTION_SIZE]; - uint32_t subgroupSize; -} VkPipelineExecutablePropertiesKHR32; - -typedef union VkPipelineExecutableStatisticValueKHR32 -{ - VkBool32 b32; - int64_t i64; - uint64_t DECLSPEC_ALIGN(8) u64; - double f64; -} VkPipelineExecutableStatisticValueKHR32; - -typedef struct VkPipelineExecutableStatisticKHR32 -{ - VkStructureType sType; - PTR32 pNext; - char name[VK_MAX_DESCRIPTION_SIZE]; - char description[VK_MAX_DESCRIPTION_SIZE]; - VkPipelineExecutableStatisticFormatKHR format; - VkPipelineExecutableStatisticValueKHR32 DECLSPEC_ALIGN(8) value; -} VkPipelineExecutableStatisticKHR32; - - -typedef struct VkCheckpointData2NV32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) stage; - PTR32 pCheckpointMarker; -} VkCheckpointData2NV32; - -typedef struct VkCheckpointDataNV32 -{ - VkStructureType sType; - PTR32 pNext; - VkPipelineStageFlagBits stage; - PTR32 pCheckpointMarker; -} VkCheckpointDataNV32; - -typedef struct VkSamplerCaptureDescriptorDataInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkSampler DECLSPEC_ALIGN(8) sampler; -} VkSamplerCaptureDescriptorDataInfoEXT32; - -typedef struct VkShaderModuleIdentifierEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t identifierSize; - uint8_t identifier[VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT]; -} VkShaderModuleIdentifierEXT32; - -typedef struct VkInitializePerformanceApiInfoINTEL32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 pUserData; -} VkInitializePerformanceApiInfoINTEL32; - -typedef struct VkSparseMemoryBind32 -{ - VkDeviceSize DECLSPEC_ALIGN(8) resourceOffset; - VkDeviceSize DECLSPEC_ALIGN(8) size; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - VkDeviceSize DECLSPEC_ALIGN(8) memoryOffset; - VkSparseMemoryBindFlags flags; -} VkSparseMemoryBind32; - -typedef struct VkSparseBufferMemoryBindInfo32 -{ - VkBuffer DECLSPEC_ALIGN(8) buffer; - uint32_t bindCount; - PTR32 pBinds; -} VkSparseBufferMemoryBindInfo32; - -typedef struct VkSparseImageOpaqueMemoryBindInfo32 -{ - VkImage DECLSPEC_ALIGN(8) image; - uint32_t bindCount; - PTR32 pBinds; -} VkSparseImageOpaqueMemoryBindInfo32; - -typedef struct VkSparseImageMemoryBind32 -{ - VkImageSubresource subresource; - VkOffset3D offset; - VkExtent3D extent; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - VkDeviceSize DECLSPEC_ALIGN(8) memoryOffset; - VkSparseMemoryBindFlags flags; -} VkSparseImageMemoryBind32; - -typedef struct VkSparseImageMemoryBindInfo32 -{ - VkImage DECLSPEC_ALIGN(8) image; - uint32_t bindCount; - PTR32 pBinds; -} VkSparseImageMemoryBindInfo32; - -typedef struct VkDeviceGroupBindSparseInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t resourceDeviceIndex; - uint32_t memoryDeviceIndex; -} VkDeviceGroupBindSparseInfo32; -typedef VkDeviceGroupBindSparseInfo32 VkDeviceGroupBindSparseInfoKHR32; - -typedef struct VkTimelineSemaphoreSubmitInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t waitSemaphoreValueCount; - PTR32 pWaitSemaphoreValues; - uint32_t signalSemaphoreValueCount; - PTR32 pSignalSemaphoreValues; -} VkTimelineSemaphoreSubmitInfo32; -typedef VkTimelineSemaphoreSubmitInfo32 VkTimelineSemaphoreSubmitInfoKHR32; - -typedef struct VkBindSparseInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t waitSemaphoreCount; - PTR32 pWaitSemaphores; - uint32_t bufferBindCount; - PTR32 pBufferBinds; - uint32_t imageOpaqueBindCount; - PTR32 pImageOpaqueBinds; - uint32_t imageBindCount; - PTR32 pImageBinds; - uint32_t signalSemaphoreCount; - PTR32 pSignalSemaphores; -} VkBindSparseInfo32; - -typedef struct VkPresentRegionKHR32 -{ - uint32_t rectangleCount; - PTR32 pRectangles; -} VkPresentRegionKHR32; - -typedef struct VkPresentRegionsKHR32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t swapchainCount; - PTR32 pRegions; -} VkPresentRegionsKHR32; - -typedef struct VkDeviceGroupPresentInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t swapchainCount; - PTR32 pDeviceMasks; - VkDeviceGroupPresentModeFlagBitsKHR mode; -} VkDeviceGroupPresentInfoKHR32; - -typedef struct VkPresentIdKHR32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t swapchainCount; - PTR32 pPresentIds; -} VkPresentIdKHR32; - -typedef struct VkSwapchainPresentFenceInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t swapchainCount; - PTR32 pFences; -} VkSwapchainPresentFenceInfoEXT32; - -typedef struct VkSwapchainPresentModeInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t swapchainCount; - PTR32 pPresentModes; -} VkSwapchainPresentModeInfoEXT32; - -typedef struct VkPresentInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t waitSemaphoreCount; - PTR32 pWaitSemaphores; - uint32_t swapchainCount; - PTR32 pSwapchains; - PTR32 pImageIndices; - PTR32 pResults; -} VkPresentInfoKHR32; - -typedef struct VkDeviceGroupSubmitInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t waitSemaphoreCount; - PTR32 pWaitSemaphoreDeviceIndices; - uint32_t commandBufferCount; - PTR32 pCommandBufferDeviceMasks; - uint32_t signalSemaphoreCount; - PTR32 pSignalSemaphoreDeviceIndices; -} VkDeviceGroupSubmitInfo32; -typedef VkDeviceGroupSubmitInfo32 VkDeviceGroupSubmitInfoKHR32; - -typedef struct VkProtectedSubmitInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkBool32 protectedSubmit; -} VkProtectedSubmitInfo32; - -typedef struct VkPerformanceQuerySubmitInfoKHR32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t counterPassIndex; -} VkPerformanceQuerySubmitInfoKHR32; - -typedef struct VkSubmitInfo32 -{ - VkStructureType sType; - PTR32 pNext; - uint32_t waitSemaphoreCount; - PTR32 pWaitSemaphores; - PTR32 pWaitDstStageMask; - uint32_t commandBufferCount; - PTR32 pCommandBuffers; - uint32_t signalSemaphoreCount; - PTR32 pSignalSemaphores; -} VkSubmitInfo32; - -typedef struct VkSemaphoreSubmitInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkSemaphore DECLSPEC_ALIGN(8) semaphore; - uint64_t DECLSPEC_ALIGN(8) value; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) stageMask; - uint32_t deviceIndex; -} VkSemaphoreSubmitInfo32; -typedef VkSemaphoreSubmitInfo32 VkSemaphoreSubmitInfoKHR32; - -typedef struct VkCommandBufferSubmitInfo32 -{ - VkStructureType sType; - PTR32 pNext; - PTR32 commandBuffer; - uint32_t deviceMask; -} VkCommandBufferSubmitInfo32; -typedef VkCommandBufferSubmitInfo32 VkCommandBufferSubmitInfoKHR32; - -typedef struct VkSubmitInfo232 -{ - VkStructureType sType; - PTR32 pNext; - VkSubmitFlags flags; - uint32_t waitSemaphoreInfoCount; - PTR32 pWaitSemaphoreInfos; - uint32_t commandBufferInfoCount; - PTR32 pCommandBufferInfos; - uint32_t signalSemaphoreInfoCount; - PTR32 pSignalSemaphoreInfos; -} VkSubmitInfo232; -typedef VkSubmitInfo232 VkSubmitInfo2KHR32; - -typedef struct VkReleaseSwapchainImagesInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkSwapchainKHR DECLSPEC_ALIGN(8) swapchain; - uint32_t imageIndexCount; - PTR32 pImageIndices; -} VkReleaseSwapchainImagesInfoEXT32; - -typedef struct VkDebugUtilsObjectTagInfoEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkObjectType objectType; - uint64_t DECLSPEC_ALIGN(8) objectHandle; - uint64_t DECLSPEC_ALIGN(8) tagName; - PTR32 tagSize; - PTR32 pTag; -} VkDebugUtilsObjectTagInfoEXT32; - -typedef struct VkSemaphoreSignalInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkSemaphore DECLSPEC_ALIGN(8) semaphore; - uint64_t DECLSPEC_ALIGN(8) value; -} VkSemaphoreSignalInfo32; -typedef VkSemaphoreSignalInfo32 VkSemaphoreSignalInfoKHR32; - -typedef struct VkDeviceAddressBindingCallbackDataEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkDeviceAddressBindingFlagsEXT flags; - VkDeviceAddress DECLSPEC_ALIGN(8) baseAddress; - VkDeviceSize DECLSPEC_ALIGN(8) size; - VkDeviceAddressBindingTypeEXT bindingType; -} VkDeviceAddressBindingCallbackDataEXT32; - -typedef struct VkDebugUtilsMessengerCallbackDataEXT32 -{ - VkStructureType sType; - PTR32 pNext; - VkDebugUtilsMessengerCallbackDataFlagsEXT flags; - PTR32 pMessageIdName; - int32_t messageIdNumber; - PTR32 pMessage; - uint32_t queueLabelCount; - PTR32 pQueueLabels; - uint32_t cmdBufLabelCount; - PTR32 pCmdBufLabels; - uint32_t objectCount; - PTR32 pObjects; -} VkDebugUtilsMessengerCallbackDataEXT32; - -typedef struct VkCopyDescriptorSet32 -{ - VkStructureType sType; - PTR32 pNext; - VkDescriptorSet DECLSPEC_ALIGN(8) srcSet; - uint32_t srcBinding; - uint32_t srcArrayElement; - VkDescriptorSet DECLSPEC_ALIGN(8) dstSet; - uint32_t dstBinding; - uint32_t dstArrayElement; - uint32_t descriptorCount; -} VkCopyDescriptorSet32; - -typedef struct VkSemaphoreWaitInfo32 -{ - VkStructureType sType; - PTR32 pNext; - VkSemaphoreWaitFlags flags; - uint32_t semaphoreCount; - PTR32 pSemaphores; - PTR32 pValues; -} VkSemaphoreWaitInfo32; -typedef VkSemaphoreWaitInfo32 VkSemaphoreWaitInfoKHR32; - -static uint64_t wine_vk_unwrap_handle(uint32_t type, uint64_t handle) -{ - switch(type) - { - case VK_OBJECT_TYPE_COMMAND_BUFFER: - return (uint64_t) (uintptr_t) wine_cmd_buffer_from_handle(((VkCommandBuffer) (uintptr_t) handle))->command_buffer; - case VK_OBJECT_TYPE_COMMAND_POOL: - return (uint64_t) wine_cmd_pool_from_handle(handle)->command_pool; - case VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT: - return (uint64_t) wine_debug_report_callback_from_handle(handle)->debug_callback; - case VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT: - return (uint64_t) wine_debug_utils_messenger_from_handle(handle)->debug_messenger; - case VK_OBJECT_TYPE_DEVICE: - return (uint64_t) (uintptr_t) wine_device_from_handle(((VkDevice) (uintptr_t) handle))->device; - case VK_OBJECT_TYPE_DEVICE_MEMORY: - return (uint64_t) wine_device_memory_from_handle(handle)->memory; - case VK_OBJECT_TYPE_INSTANCE: - return (uint64_t) (uintptr_t) wine_instance_from_handle(((VkInstance) (uintptr_t) handle))->instance; - case VK_OBJECT_TYPE_PHYSICAL_DEVICE: - return (uint64_t) (uintptr_t) wine_phys_dev_from_handle(((VkPhysicalDevice) (uintptr_t) handle))->phys_dev; - case VK_OBJECT_TYPE_QUEUE: - return (uint64_t) (uintptr_t) wine_queue_from_handle(((VkQueue) (uintptr_t) handle))->queue; - case VK_OBJECT_TYPE_SURFACE_KHR: - return (uint64_t) wine_surface_from_handle(handle)->surface; - default: - return handle; - } -} - -static inline void convert_VkAcquireNextImageInfoKHR_win32_to_host(const VkAcquireNextImageInfoKHR32 *in, VkAcquireNextImageInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->swapchain = in->swapchain; - out->timeout = in->timeout; - out->semaphore = in->semaphore; - out->fence = in->fence; - out->deviceMask = in->deviceMask; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkPerformanceConfigurationAcquireInfoINTEL_win32_to_host(const VkPerformanceConfigurationAcquireInfoINTEL32 *in, VkPerformanceConfigurationAcquireInfoINTEL *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->type = in->type; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkAcquireProfilingLockInfoKHR_win32_to_host(const VkAcquireProfilingLockInfoKHR32 *in, VkAcquireProfilingLockInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->timeout = in->timeout; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkCommandBufferAllocateInfo_win32_to_unwrapped_host(const VkCommandBufferAllocateInfo32 *in, VkCommandBufferAllocateInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->commandPool = in->commandPool; - out->level = in->level; - out->commandBufferCount = in->commandBufferCount; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline VkCommandBuffer *convert_VkCommandBuffer_array_win32_to_unwrapped_host(struct conversion_context *ctx, const PTR32 *in, uint32_t count) -{ - VkCommandBuffer *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - out[i] = UlongToPtr(in[i]); - } - - return out; -} - -static inline void convert_VkDescriptorSetAllocateInfo_win32_to_host(struct conversion_context *ctx, const VkDescriptorSetAllocateInfo32 *in, VkDescriptorSetAllocateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->descriptorPool = in->descriptorPool; - out->descriptorSetCount = in->descriptorSetCount; - out->pSetLayouts = (const VkDescriptorSetLayout *)UlongToPtr(in->pSetLayouts); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO: - { - VkDescriptorSetVariableDescriptorCountAllocateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDescriptorSetVariableDescriptorCountAllocateInfo32 *in_ext = (const VkDescriptorSetVariableDescriptorCountAllocateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO; - out_ext->pNext = NULL; - out_ext->descriptorSetCount = in_ext->descriptorSetCount; - out_ext->pDescriptorCounts = (const uint32_t *)UlongToPtr(in_ext->pDescriptorCounts); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkMemoryAllocateInfo_win32_to_host(struct conversion_context *ctx, const VkMemoryAllocateInfo32 *in, VkMemoryAllocateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->allocationSize = in->allocationSize; - out->memoryTypeIndex = in->memoryTypeIndex; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV: - { - VkDedicatedAllocationMemoryAllocateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDedicatedAllocationMemoryAllocateInfoNV32 *in_ext = (const VkDedicatedAllocationMemoryAllocateInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->image = in_ext->image; - out_ext->buffer = in_ext->buffer; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO: - { - VkExportMemoryAllocateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkExportMemoryAllocateInfo32 *in_ext = (const VkExportMemoryAllocateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO; - out_ext->pNext = NULL; - out_ext->handleTypes = in_ext->handleTypes; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR: - { - VkImportMemoryWin32HandleInfoKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkImportMemoryWin32HandleInfoKHR32 *in_ext = (const VkImportMemoryWin32HandleInfoKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR; - out_ext->pNext = NULL; - out_ext->handleType = in_ext->handleType; - out_ext->handle = in_ext->handle; - out_ext->name = in_ext->name; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR: - { - VkExportMemoryWin32HandleInfoKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkExportMemoryWin32HandleInfoKHR32 *in_ext = (const VkExportMemoryWin32HandleInfoKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR; - out_ext->pNext = NULL; - out_ext->pAttributes = (const SECURITY_ATTRIBUTES *)UlongToPtr(in_ext->pAttributes); - out_ext->dwAccess = in_ext->dwAccess; - out_ext->name = in_ext->name; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO: - { - VkMemoryAllocateFlagsInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkMemoryAllocateFlagsInfo32 *in_ext = (const VkMemoryAllocateFlagsInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->deviceMask = in_ext->deviceMask; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO: - { - VkMemoryDedicatedAllocateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkMemoryDedicatedAllocateInfo32 *in_ext = (const VkMemoryDedicatedAllocateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO; - out_ext->pNext = NULL; - out_ext->image = in_ext->image; - out_ext->buffer = in_ext->buffer; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT: - { - VkImportMemoryHostPointerInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkImportMemoryHostPointerInfoEXT32 *in_ext = (const VkImportMemoryHostPointerInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT; - out_ext->pNext = NULL; - out_ext->handleType = in_ext->handleType; - out_ext->pHostPointer = (void *)UlongToPtr(in_ext->pHostPointer); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT: - { - VkMemoryPriorityAllocateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkMemoryPriorityAllocateInfoEXT32 *in_ext = (const VkMemoryPriorityAllocateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->priority = in_ext->priority; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO: - { - VkMemoryOpaqueCaptureAddressAllocateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkMemoryOpaqueCaptureAddressAllocateInfo32 *in_ext = (const VkMemoryOpaqueCaptureAddressAllocateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO; - out_ext->pNext = NULL; - out_ext->opaqueCaptureAddress = in_ext->opaqueCaptureAddress; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkCommandBufferInheritanceInfo_win32_to_host(struct conversion_context *ctx, const VkCommandBufferInheritanceInfo32 *in, VkCommandBufferInheritanceInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->renderPass = in->renderPass; - out->subpass = in->subpass; - out->framebuffer = in->framebuffer; - out->occlusionQueryEnable = in->occlusionQueryEnable; - out->queryFlags = in->queryFlags; - out->pipelineStatistics = in->pipelineStatistics; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT: - { - VkCommandBufferInheritanceConditionalRenderingInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkCommandBufferInheritanceConditionalRenderingInfoEXT32 *in_ext = (const VkCommandBufferInheritanceConditionalRenderingInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT; - out_ext->pNext = NULL; - out_ext->conditionalRenderingEnable = in_ext->conditionalRenderingEnable; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDER_PASS_TRANSFORM_INFO_QCOM: - { - VkCommandBufferInheritanceRenderPassTransformInfoQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkCommandBufferInheritanceRenderPassTransformInfoQCOM32 *in_ext = (const VkCommandBufferInheritanceRenderPassTransformInfoQCOM32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDER_PASS_TRANSFORM_INFO_QCOM; - out_ext->pNext = NULL; - out_ext->transform = in_ext->transform; - out_ext->renderArea = in_ext->renderArea; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV: - { - VkCommandBufferInheritanceViewportScissorInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkCommandBufferInheritanceViewportScissorInfoNV32 *in_ext = (const VkCommandBufferInheritanceViewportScissorInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV; - out_ext->pNext = NULL; - out_ext->viewportScissor2D = in_ext->viewportScissor2D; - out_ext->viewportDepthCount = in_ext->viewportDepthCount; - out_ext->pViewportDepths = (const VkViewport *)UlongToPtr(in_ext->pViewportDepths); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO: - { - VkCommandBufferInheritanceRenderingInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkCommandBufferInheritanceRenderingInfo32 *in_ext = (const VkCommandBufferInheritanceRenderingInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->viewMask = in_ext->viewMask; - out_ext->colorAttachmentCount = in_ext->colorAttachmentCount; - out_ext->pColorAttachmentFormats = (const VkFormat *)UlongToPtr(in_ext->pColorAttachmentFormats); - out_ext->depthAttachmentFormat = in_ext->depthAttachmentFormat; - out_ext->stencilAttachmentFormat = in_ext->stencilAttachmentFormat; - out_ext->rasterizationSamples = in_ext->rasterizationSamples; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD: - { - VkAttachmentSampleCountInfoAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkAttachmentSampleCountInfoAMD32 *in_ext = (const VkAttachmentSampleCountInfoAMD32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD; - out_ext->pNext = NULL; - out_ext->colorAttachmentCount = in_ext->colorAttachmentCount; - out_ext->pColorAttachmentSamples = (const VkSampleCountFlagBits *)UlongToPtr(in_ext->pColorAttachmentSamples); - out_ext->depthStencilAttachmentSamples = in_ext->depthStencilAttachmentSamples; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_ATTRIBUTES_INFO_NVX: - { - VkMultiviewPerViewAttributesInfoNVX *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkMultiviewPerViewAttributesInfoNVX32 *in_ext = (const VkMultiviewPerViewAttributesInfoNVX32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_ATTRIBUTES_INFO_NVX; - out_ext->pNext = NULL; - out_ext->perViewAttributes = in_ext->perViewAttributes; - out_ext->perViewAttributesPositionXOnly = in_ext->perViewAttributesPositionXOnly; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkCommandBufferInheritanceInfo *convert_VkCommandBufferInheritanceInfo_array_win32_to_host(struct conversion_context *ctx, const VkCommandBufferInheritanceInfo32 *in, uint32_t count) -{ - VkCommandBufferInheritanceInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkCommandBufferInheritanceInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkCommandBufferBeginInfo_win32_to_host(struct conversion_context *ctx, const VkCommandBufferBeginInfo32 *in, VkCommandBufferBeginInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->pInheritanceInfo = convert_VkCommandBufferInheritanceInfo_array_win32_to_host(ctx, (const VkCommandBufferInheritanceInfo32 *)UlongToPtr(in->pInheritanceInfo), 1); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO: - { - VkDeviceGroupCommandBufferBeginInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDeviceGroupCommandBufferBeginInfo32 *in_ext = (const VkDeviceGroupCommandBufferBeginInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO; - out_ext->pNext = NULL; - out_ext->deviceMask = in_ext->deviceMask; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -#ifdef _WIN64 -static inline void convert_VkBindAccelerationStructureMemoryInfoNV_win64_to_host(const VkBindAccelerationStructureMemoryInfoNV *in, VkBindAccelerationStructureMemoryInfoNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->accelerationStructure = in->accelerationStructure; - out->memory = wine_device_memory_from_handle(in->memory)->memory; - out->memoryOffset = in->memoryOffset; - out->deviceIndexCount = in->deviceIndexCount; - out->pDeviceIndices = in->pDeviceIndices; -} -#endif /* _WIN64 */ - -static inline void convert_VkBindAccelerationStructureMemoryInfoNV_win32_to_host(const VkBindAccelerationStructureMemoryInfoNV32 *in, VkBindAccelerationStructureMemoryInfoNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->accelerationStructure = in->accelerationStructure; - out->memory = wine_device_memory_from_handle(in->memory)->memory; - out->memoryOffset = in->memoryOffset; - out->deviceIndexCount = in->deviceIndexCount; - out->pDeviceIndices = (const uint32_t *)UlongToPtr(in->pDeviceIndices); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -#ifdef _WIN64 -static inline const VkBindAccelerationStructureMemoryInfoNV *convert_VkBindAccelerationStructureMemoryInfoNV_array_win64_to_host(struct conversion_context *ctx, const VkBindAccelerationStructureMemoryInfoNV *in, uint32_t count) -{ - VkBindAccelerationStructureMemoryInfoNV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkBindAccelerationStructureMemoryInfoNV_win64_to_host(&in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkBindAccelerationStructureMemoryInfoNV *convert_VkBindAccelerationStructureMemoryInfoNV_array_win32_to_host(struct conversion_context *ctx, const VkBindAccelerationStructureMemoryInfoNV32 *in, uint32_t count) -{ - VkBindAccelerationStructureMemoryInfoNV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkBindAccelerationStructureMemoryInfoNV_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -#ifdef _WIN64 -static inline void convert_VkBindBufferMemoryInfo_win64_to_host(const VkBindBufferMemoryInfo *in, VkBindBufferMemoryInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->buffer = in->buffer; - out->memory = wine_device_memory_from_handle(in->memory)->memory; - out->memoryOffset = in->memoryOffset; -} -#endif /* _WIN64 */ - -static inline void convert_VkBindBufferMemoryInfo_win32_to_host(struct conversion_context *ctx, const VkBindBufferMemoryInfo32 *in, VkBindBufferMemoryInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->buffer = in->buffer; - out->memory = wine_device_memory_from_handle(in->memory)->memory; - out->memoryOffset = in->memoryOffset; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO: - { - VkBindBufferMemoryDeviceGroupInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkBindBufferMemoryDeviceGroupInfo32 *in_ext = (const VkBindBufferMemoryDeviceGroupInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO; - out_ext->pNext = NULL; - out_ext->deviceIndexCount = in_ext->deviceIndexCount; - out_ext->pDeviceIndices = (const uint32_t *)UlongToPtr(in_ext->pDeviceIndices); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -#ifdef _WIN64 -static inline const VkBindBufferMemoryInfo *convert_VkBindBufferMemoryInfo_array_win64_to_host(struct conversion_context *ctx, const VkBindBufferMemoryInfo *in, uint32_t count) -{ - VkBindBufferMemoryInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkBindBufferMemoryInfo_win64_to_host(&in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkBindBufferMemoryInfo *convert_VkBindBufferMemoryInfo_array_win32_to_host(struct conversion_context *ctx, const VkBindBufferMemoryInfo32 *in, uint32_t count) -{ - VkBindBufferMemoryInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkBindBufferMemoryInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -#ifdef _WIN64 -static inline void convert_VkBindImageMemoryInfo_win64_to_host(const VkBindImageMemoryInfo *in, VkBindImageMemoryInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->image = in->image; - out->memory = wine_device_memory_from_handle(in->memory)->memory; - out->memoryOffset = in->memoryOffset; -} -#endif /* _WIN64 */ - -static inline void convert_VkBindImageMemoryInfo_win32_to_host(struct conversion_context *ctx, const VkBindImageMemoryInfo32 *in, VkBindImageMemoryInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->image = in->image; - out->memory = wine_device_memory_from_handle(in->memory)->memory; - out->memoryOffset = in->memoryOffset; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO: - { - VkBindImageMemoryDeviceGroupInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkBindImageMemoryDeviceGroupInfo32 *in_ext = (const VkBindImageMemoryDeviceGroupInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO; - out_ext->pNext = NULL; - out_ext->deviceIndexCount = in_ext->deviceIndexCount; - out_ext->pDeviceIndices = (const uint32_t *)UlongToPtr(in_ext->pDeviceIndices); - out_ext->splitInstanceBindRegionCount = in_ext->splitInstanceBindRegionCount; - out_ext->pSplitInstanceBindRegions = (const VkRect2D *)UlongToPtr(in_ext->pSplitInstanceBindRegions); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR: - { - VkBindImageMemorySwapchainInfoKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkBindImageMemorySwapchainInfoKHR32 *in_ext = (const VkBindImageMemorySwapchainInfoKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR; - out_ext->pNext = NULL; - out_ext->swapchain = in_ext->swapchain; - out_ext->imageIndex = in_ext->imageIndex; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO: - { - VkBindImagePlaneMemoryInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkBindImagePlaneMemoryInfo32 *in_ext = (const VkBindImagePlaneMemoryInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO; - out_ext->pNext = NULL; - out_ext->planeAspect = in_ext->planeAspect; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -#ifdef _WIN64 -static inline const VkBindImageMemoryInfo *convert_VkBindImageMemoryInfo_array_win64_to_host(struct conversion_context *ctx, const VkBindImageMemoryInfo *in, uint32_t count) -{ - VkBindImageMemoryInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkBindImageMemoryInfo_win64_to_host(&in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkBindImageMemoryInfo *convert_VkBindImageMemoryInfo_array_win32_to_host(struct conversion_context *ctx, const VkBindImageMemoryInfo32 *in, uint32_t count) -{ - VkBindImageMemoryInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkBindImageMemoryInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline const VkMicromapUsageEXT * const*convert_VkMicromapUsageEXT_pointer_array_win32_to_host(struct conversion_context *ctx, const PTR32 *in, uint32_t count) -{ - VkMicromapUsageEXT **out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - out[i] = UlongToPtr(in[i]); - } - - return (void *)out; -} - -static inline void convert_VkAccelerationStructureGeometryTrianglesDataKHR_win32_to_host(struct conversion_context *ctx, const VkAccelerationStructureGeometryTrianglesDataKHR32 *in, VkAccelerationStructureGeometryTrianglesDataKHR *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->vertexFormat = in->vertexFormat; - out->vertexData = in->vertexData; - out->vertexStride = in->vertexStride; - out->maxVertex = in->maxVertex; - out->indexType = in->indexType; - out->indexData = in->indexData; - out->transformData = in->transformData; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_MOTION_TRIANGLES_DATA_NV: - { - VkAccelerationStructureGeometryMotionTrianglesDataNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkAccelerationStructureGeometryMotionTrianglesDataNV32 *in_ext = (const VkAccelerationStructureGeometryMotionTrianglesDataNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_MOTION_TRIANGLES_DATA_NV; - out_ext->pNext = NULL; - out_ext->vertexData = in_ext->vertexData; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_TRIANGLES_OPACITY_MICROMAP_EXT: - { - VkAccelerationStructureTrianglesOpacityMicromapEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkAccelerationStructureTrianglesOpacityMicromapEXT32 *in_ext = (const VkAccelerationStructureTrianglesOpacityMicromapEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_TRIANGLES_OPACITY_MICROMAP_EXT; - out_ext->pNext = NULL; - out_ext->indexType = in_ext->indexType; - out_ext->indexBuffer = in_ext->indexBuffer; - out_ext->indexStride = in_ext->indexStride; - out_ext->baseTriangle = in_ext->baseTriangle; - out_ext->usageCountsCount = in_ext->usageCountsCount; - out_ext->pUsageCounts = (const VkMicromapUsageEXT *)UlongToPtr(in_ext->pUsageCounts); - out_ext->ppUsageCounts = convert_VkMicromapUsageEXT_pointer_array_win32_to_host(ctx, (const PTR32 *)UlongToPtr(in_ext->ppUsageCounts), in_ext->usageCountsCount); - out_ext->micromap = in_ext->micromap; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkAccelerationStructureGeometryAabbsDataKHR_win32_to_host(const VkAccelerationStructureGeometryAabbsDataKHR32 *in, VkAccelerationStructureGeometryAabbsDataKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->data = in->data; - out->stride = in->stride; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkAccelerationStructureGeometryInstancesDataKHR_win32_to_host(const VkAccelerationStructureGeometryInstancesDataKHR32 *in, VkAccelerationStructureGeometryInstancesDataKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->arrayOfPointers = in->arrayOfPointers; - out->data = in->data; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkAccelerationStructureGeometryDataKHR_win32_to_host(struct conversion_context *ctx, const VkAccelerationStructureGeometryDataKHR32 *in, VkAccelerationStructureGeometryDataKHR *out, VkFlags selector) -{ - if (!in) return; - - if (selector == VK_GEOMETRY_TYPE_TRIANGLES_KHR) - convert_VkAccelerationStructureGeometryTrianglesDataKHR_win32_to_host(ctx, &in->triangles, &out->triangles); - if (selector == VK_GEOMETRY_TYPE_AABBS_KHR) - convert_VkAccelerationStructureGeometryAabbsDataKHR_win32_to_host(&in->aabbs, &out->aabbs); - if (selector == VK_GEOMETRY_TYPE_INSTANCES_KHR) - convert_VkAccelerationStructureGeometryInstancesDataKHR_win32_to_host(&in->instances, &out->instances); -} - -static inline void convert_VkAccelerationStructureGeometryKHR_win32_to_host(struct conversion_context *ctx, const VkAccelerationStructureGeometryKHR32 *in, VkAccelerationStructureGeometryKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->geometryType = in->geometryType; - convert_VkAccelerationStructureGeometryDataKHR_win32_to_host(ctx, &in->geometry, &out->geometry, in->geometryType); - out->flags = in->flags; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkAccelerationStructureGeometryKHR *convert_VkAccelerationStructureGeometryKHR_array_win32_to_host(struct conversion_context *ctx, const VkAccelerationStructureGeometryKHR32 *in, uint32_t count) -{ - VkAccelerationStructureGeometryKHR *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkAccelerationStructureGeometryKHR_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline const VkAccelerationStructureGeometryKHR * const*convert_VkAccelerationStructureGeometryKHR_pointer_array_win32_to_host(struct conversion_context *ctx, const PTR32 *in, uint32_t count) -{ - VkAccelerationStructureGeometryKHR **out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - if (in[i]) - { - out[i] = conversion_context_alloc(ctx, sizeof(*out[i])); - convert_VkAccelerationStructureGeometryKHR_win32_to_host(ctx, (VkAccelerationStructureGeometryKHR32 *)UlongToPtr(in[i]), out[i]); - } - else - out[i] = NULL; - } - - return (void *)out; -} - -static inline void convert_VkAccelerationStructureBuildGeometryInfoKHR_win32_to_host(struct conversion_context *ctx, const VkAccelerationStructureBuildGeometryInfoKHR32 *in, VkAccelerationStructureBuildGeometryInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->type = in->type; - out->flags = in->flags; - out->mode = in->mode; - out->srcAccelerationStructure = in->srcAccelerationStructure; - out->dstAccelerationStructure = in->dstAccelerationStructure; - out->geometryCount = in->geometryCount; - out->pGeometries = convert_VkAccelerationStructureGeometryKHR_array_win32_to_host(ctx, (const VkAccelerationStructureGeometryKHR32 *)UlongToPtr(in->pGeometries), in->geometryCount); - out->ppGeometries = convert_VkAccelerationStructureGeometryKHR_pointer_array_win32_to_host(ctx, (const PTR32 *)UlongToPtr(in->ppGeometries), in->geometryCount); - out->scratchData = in->scratchData; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkAccelerationStructureBuildGeometryInfoKHR *convert_VkAccelerationStructureBuildGeometryInfoKHR_array_win32_to_host(struct conversion_context *ctx, const VkAccelerationStructureBuildGeometryInfoKHR32 *in, uint32_t count) -{ - VkAccelerationStructureBuildGeometryInfoKHR *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkAccelerationStructureBuildGeometryInfoKHR_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkMicromapBuildInfoEXT_win32_to_host(struct conversion_context *ctx, const VkMicromapBuildInfoEXT32 *in, VkMicromapBuildInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->type = in->type; - out->flags = in->flags; - out->mode = in->mode; - out->dstMicromap = in->dstMicromap; - out->usageCountsCount = in->usageCountsCount; - out->pUsageCounts = (const VkMicromapUsageEXT *)UlongToPtr(in->pUsageCounts); - out->ppUsageCounts = convert_VkMicromapUsageEXT_pointer_array_win32_to_host(ctx, (const PTR32 *)UlongToPtr(in->ppUsageCounts), in->usageCountsCount); - out->data = in->data; - out->scratchData = in->scratchData; - out->triangleArray = in->triangleArray; - out->triangleArrayStride = in->triangleArrayStride; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkMicromapBuildInfoEXT *convert_VkMicromapBuildInfoEXT_array_win32_to_host(struct conversion_context *ctx, const VkMicromapBuildInfoEXT32 *in, uint32_t count) -{ - VkMicromapBuildInfoEXT *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkMicromapBuildInfoEXT_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkConditionalRenderingBeginInfoEXT_win32_to_host(const VkConditionalRenderingBeginInfoEXT32 *in, VkConditionalRenderingBeginInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->buffer = in->buffer; - out->offset = in->offset; - out->flags = in->flags; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkDebugUtilsLabelEXT_win32_to_host(const VkDebugUtilsLabelEXT32 *in, VkDebugUtilsLabelEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->pLabelName = (const char *)UlongToPtr(in->pLabelName); - memcpy(out->color, in->color, 4 * sizeof(float)); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkSampleLocationsInfoEXT_win32_to_host(const VkSampleLocationsInfoEXT32 *in, VkSampleLocationsInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->sampleLocationsPerPixel = in->sampleLocationsPerPixel; - out->sampleLocationGridSize = in->sampleLocationGridSize; - out->sampleLocationsCount = in->sampleLocationsCount; - out->pSampleLocations = (const VkSampleLocationEXT *)UlongToPtr(in->pSampleLocations); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkAttachmentSampleLocationsEXT_win32_to_host(const VkAttachmentSampleLocationsEXT32 *in, VkAttachmentSampleLocationsEXT *out) -{ - if (!in) return; - - out->attachmentIndex = in->attachmentIndex; - convert_VkSampleLocationsInfoEXT_win32_to_host(&in->sampleLocationsInfo, &out->sampleLocationsInfo); -} - -static inline const VkAttachmentSampleLocationsEXT *convert_VkAttachmentSampleLocationsEXT_array_win32_to_host(struct conversion_context *ctx, const VkAttachmentSampleLocationsEXT32 *in, uint32_t count) -{ - VkAttachmentSampleLocationsEXT *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkAttachmentSampleLocationsEXT_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkSubpassSampleLocationsEXT_win32_to_host(const VkSubpassSampleLocationsEXT32 *in, VkSubpassSampleLocationsEXT *out) -{ - if (!in) return; - - out->subpassIndex = in->subpassIndex; - convert_VkSampleLocationsInfoEXT_win32_to_host(&in->sampleLocationsInfo, &out->sampleLocationsInfo); -} - -static inline const VkSubpassSampleLocationsEXT *convert_VkSubpassSampleLocationsEXT_array_win32_to_host(struct conversion_context *ctx, const VkSubpassSampleLocationsEXT32 *in, uint32_t count) -{ - VkSubpassSampleLocationsEXT *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSubpassSampleLocationsEXT_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkRenderPassBeginInfo_win32_to_host(struct conversion_context *ctx, const VkRenderPassBeginInfo32 *in, VkRenderPassBeginInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->renderPass = in->renderPass; - out->framebuffer = in->framebuffer; - out->renderArea = in->renderArea; - out->clearValueCount = in->clearValueCount; - out->pClearValues = (const VkClearValue *)UlongToPtr(in->pClearValues); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO: - { - VkDeviceGroupRenderPassBeginInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDeviceGroupRenderPassBeginInfo32 *in_ext = (const VkDeviceGroupRenderPassBeginInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO; - out_ext->pNext = NULL; - out_ext->deviceMask = in_ext->deviceMask; - out_ext->deviceRenderAreaCount = in_ext->deviceRenderAreaCount; - out_ext->pDeviceRenderAreas = (const VkRect2D *)UlongToPtr(in_ext->pDeviceRenderAreas); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT: - { - VkRenderPassSampleLocationsBeginInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkRenderPassSampleLocationsBeginInfoEXT32 *in_ext = (const VkRenderPassSampleLocationsBeginInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT; - out_ext->pNext = NULL; - out_ext->attachmentInitialSampleLocationsCount = in_ext->attachmentInitialSampleLocationsCount; - out_ext->pAttachmentInitialSampleLocations = convert_VkAttachmentSampleLocationsEXT_array_win32_to_host(ctx, (const VkAttachmentSampleLocationsEXT32 *)UlongToPtr(in_ext->pAttachmentInitialSampleLocations), in_ext->attachmentInitialSampleLocationsCount); - out_ext->postSubpassSampleLocationsCount = in_ext->postSubpassSampleLocationsCount; - out_ext->pPostSubpassSampleLocations = convert_VkSubpassSampleLocationsEXT_array_win32_to_host(ctx, (const VkSubpassSampleLocationsEXT32 *)UlongToPtr(in_ext->pPostSubpassSampleLocations), in_ext->postSubpassSampleLocationsCount); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO: - { - VkRenderPassAttachmentBeginInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkRenderPassAttachmentBeginInfo32 *in_ext = (const VkRenderPassAttachmentBeginInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO; - out_ext->pNext = NULL; - out_ext->attachmentCount = in_ext->attachmentCount; - out_ext->pAttachments = (const VkImageView *)UlongToPtr(in_ext->pAttachments); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_RENDER_PASS_TRANSFORM_BEGIN_INFO_QCOM: - { - VkRenderPassTransformBeginInfoQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkRenderPassTransformBeginInfoQCOM32 *in_ext = (const VkRenderPassTransformBeginInfoQCOM32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_RENDER_PASS_TRANSFORM_BEGIN_INFO_QCOM; - out_ext->pNext = NULL; - out_ext->transform = in_ext->transform; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkSubpassBeginInfo_win32_to_host(const VkSubpassBeginInfo32 *in, VkSubpassBeginInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->contents = in->contents; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkRenderingAttachmentInfo_win32_to_host(const VkRenderingAttachmentInfo32 *in, VkRenderingAttachmentInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->imageView = in->imageView; - out->imageLayout = in->imageLayout; - out->resolveMode = in->resolveMode; - out->resolveImageView = in->resolveImageView; - out->resolveImageLayout = in->resolveImageLayout; - out->loadOp = in->loadOp; - out->storeOp = in->storeOp; - out->clearValue = in->clearValue; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkRenderingAttachmentInfo *convert_VkRenderingAttachmentInfo_array_win32_to_host(struct conversion_context *ctx, const VkRenderingAttachmentInfo32 *in, uint32_t count) -{ - VkRenderingAttachmentInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkRenderingAttachmentInfo_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkRenderingInfo_win32_to_host(struct conversion_context *ctx, const VkRenderingInfo32 *in, VkRenderingInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->renderArea = in->renderArea; - out->layerCount = in->layerCount; - out->viewMask = in->viewMask; - out->colorAttachmentCount = in->colorAttachmentCount; - out->pColorAttachments = convert_VkRenderingAttachmentInfo_array_win32_to_host(ctx, (const VkRenderingAttachmentInfo32 *)UlongToPtr(in->pColorAttachments), in->colorAttachmentCount); - out->pDepthAttachment = convert_VkRenderingAttachmentInfo_array_win32_to_host(ctx, (const VkRenderingAttachmentInfo32 *)UlongToPtr(in->pDepthAttachment), 1); - out->pStencilAttachment = convert_VkRenderingAttachmentInfo_array_win32_to_host(ctx, (const VkRenderingAttachmentInfo32 *)UlongToPtr(in->pStencilAttachment), 1); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO: - { - VkDeviceGroupRenderPassBeginInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDeviceGroupRenderPassBeginInfo32 *in_ext = (const VkDeviceGroupRenderPassBeginInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO; - out_ext->pNext = NULL; - out_ext->deviceMask = in_ext->deviceMask; - out_ext->deviceRenderAreaCount = in_ext->deviceRenderAreaCount; - out_ext->pDeviceRenderAreas = (const VkRect2D *)UlongToPtr(in_ext->pDeviceRenderAreas); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_EXT: - { - VkMultisampledRenderToSingleSampledInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkMultisampledRenderToSingleSampledInfoEXT32 *in_ext = (const VkMultisampledRenderToSingleSampledInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_EXT; - out_ext->pNext = NULL; - out_ext->multisampledRenderToSingleSampledEnable = in_ext->multisampledRenderToSingleSampledEnable; - out_ext->rasterizationSamples = in_ext->rasterizationSamples; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR: - { - VkRenderingFragmentShadingRateAttachmentInfoKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkRenderingFragmentShadingRateAttachmentInfoKHR32 *in_ext = (const VkRenderingFragmentShadingRateAttachmentInfoKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; - out_ext->pNext = NULL; - out_ext->imageView = in_ext->imageView; - out_ext->imageLayout = in_ext->imageLayout; - out_ext->shadingRateAttachmentTexelSize = in_ext->shadingRateAttachmentTexelSize; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_INFO_EXT: - { - VkRenderingFragmentDensityMapAttachmentInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkRenderingFragmentDensityMapAttachmentInfoEXT32 *in_ext = (const VkRenderingFragmentDensityMapAttachmentInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_INFO_EXT; - out_ext->pNext = NULL; - out_ext->imageView = in_ext->imageView; - out_ext->imageLayout = in_ext->imageLayout; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_ATTRIBUTES_INFO_NVX: - { - VkMultiviewPerViewAttributesInfoNVX *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkMultiviewPerViewAttributesInfoNVX32 *in_ext = (const VkMultiviewPerViewAttributesInfoNVX32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_ATTRIBUTES_INFO_NVX; - out_ext->pNext = NULL; - out_ext->perViewAttributes = in_ext->perViewAttributes; - out_ext->perViewAttributesPositionXOnly = in_ext->perViewAttributesPositionXOnly; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkDescriptorBufferBindingInfoEXT_win32_to_host(struct conversion_context *ctx, const VkDescriptorBufferBindingInfoEXT32 *in, VkDescriptorBufferBindingInfoEXT *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->address = in->address; - out->usage = in->usage; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_PUSH_DESCRIPTOR_BUFFER_HANDLE_EXT: - { - VkDescriptorBufferBindingPushDescriptorBufferHandleEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDescriptorBufferBindingPushDescriptorBufferHandleEXT32 *in_ext = (const VkDescriptorBufferBindingPushDescriptorBufferHandleEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_PUSH_DESCRIPTOR_BUFFER_HANDLE_EXT; - out_ext->pNext = NULL; - out_ext->buffer = in_ext->buffer; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkDescriptorBufferBindingInfoEXT *convert_VkDescriptorBufferBindingInfoEXT_array_win32_to_host(struct conversion_context *ctx, const VkDescriptorBufferBindingInfoEXT32 *in, uint32_t count) -{ - VkDescriptorBufferBindingInfoEXT *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkDescriptorBufferBindingInfoEXT_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkImageBlit2_win32_to_host(struct conversion_context *ctx, const VkImageBlit232 *in, VkImageBlit2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcSubresource = in->srcSubresource; - memcpy(out->srcOffsets, in->srcOffsets, 2 * sizeof(VkOffset3D)); - out->dstSubresource = in->dstSubresource; - memcpy(out->dstOffsets, in->dstOffsets, 2 * sizeof(VkOffset3D)); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_COPY_COMMAND_TRANSFORM_INFO_QCOM: - { - VkCopyCommandTransformInfoQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkCopyCommandTransformInfoQCOM32 *in_ext = (const VkCopyCommandTransformInfoQCOM32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_COPY_COMMAND_TRANSFORM_INFO_QCOM; - out_ext->pNext = NULL; - out_ext->transform = in_ext->transform; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkImageBlit2 *convert_VkImageBlit2_array_win32_to_host(struct conversion_context *ctx, const VkImageBlit232 *in, uint32_t count) -{ - VkImageBlit2 *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkImageBlit2_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkBlitImageInfo2_win32_to_host(struct conversion_context *ctx, const VkBlitImageInfo232 *in, VkBlitImageInfo2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcImage = in->srcImage; - out->srcImageLayout = in->srcImageLayout; - out->dstImage = in->dstImage; - out->dstImageLayout = in->dstImageLayout; - out->regionCount = in->regionCount; - out->pRegions = convert_VkImageBlit2_array_win32_to_host(ctx, (const VkImageBlit232 *)UlongToPtr(in->pRegions), in->regionCount); - out->filter = in->filter; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkGeometryTrianglesNV_win32_to_host(const VkGeometryTrianglesNV32 *in, VkGeometryTrianglesNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->vertexData = in->vertexData; - out->vertexOffset = in->vertexOffset; - out->vertexCount = in->vertexCount; - out->vertexStride = in->vertexStride; - out->vertexFormat = in->vertexFormat; - out->indexData = in->indexData; - out->indexOffset = in->indexOffset; - out->indexCount = in->indexCount; - out->indexType = in->indexType; - out->transformData = in->transformData; - out->transformOffset = in->transformOffset; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkGeometryAABBNV_win32_to_host(const VkGeometryAABBNV32 *in, VkGeometryAABBNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->aabbData = in->aabbData; - out->numAABBs = in->numAABBs; - out->stride = in->stride; - out->offset = in->offset; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkGeometryDataNV_win32_to_host(const VkGeometryDataNV32 *in, VkGeometryDataNV *out) -{ - if (!in) return; - - convert_VkGeometryTrianglesNV_win32_to_host(&in->triangles, &out->triangles); - convert_VkGeometryAABBNV_win32_to_host(&in->aabbs, &out->aabbs); -} - -static inline void convert_VkGeometryNV_win32_to_host(const VkGeometryNV32 *in, VkGeometryNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->geometryType = in->geometryType; - convert_VkGeometryDataNV_win32_to_host(&in->geometry, &out->geometry); - out->flags = in->flags; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkGeometryNV *convert_VkGeometryNV_array_win32_to_host(struct conversion_context *ctx, const VkGeometryNV32 *in, uint32_t count) -{ - VkGeometryNV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkGeometryNV_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkAccelerationStructureInfoNV_win32_to_host(struct conversion_context *ctx, const VkAccelerationStructureInfoNV32 *in, VkAccelerationStructureInfoNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->type = in->type; - out->flags = in->flags; - out->instanceCount = in->instanceCount; - out->geometryCount = in->geometryCount; - out->pGeometries = convert_VkGeometryNV_array_win32_to_host(ctx, (const VkGeometryNV32 *)UlongToPtr(in->pGeometries), in->geometryCount); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkCopyAccelerationStructureInfoKHR_win32_to_host(const VkCopyAccelerationStructureInfoKHR32 *in, VkCopyAccelerationStructureInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->src = in->src; - out->dst = in->dst; - out->mode = in->mode; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkCopyAccelerationStructureToMemoryInfoKHR_win32_to_host(const VkCopyAccelerationStructureToMemoryInfoKHR32 *in, VkCopyAccelerationStructureToMemoryInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->src = in->src; - out->dst = in->dst; - out->mode = in->mode; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkBufferCopy_win32_to_host(const VkBufferCopy32 *in, VkBufferCopy *out) -{ - if (!in) return; - - out->srcOffset = in->srcOffset; - out->dstOffset = in->dstOffset; - out->size = in->size; -} - -static inline const VkBufferCopy *convert_VkBufferCopy_array_win32_to_host(struct conversion_context *ctx, const VkBufferCopy32 *in, uint32_t count) -{ - VkBufferCopy *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkBufferCopy_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkBufferCopy2_win32_to_host(const VkBufferCopy232 *in, VkBufferCopy2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcOffset = in->srcOffset; - out->dstOffset = in->dstOffset; - out->size = in->size; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkBufferCopy2 *convert_VkBufferCopy2_array_win32_to_host(struct conversion_context *ctx, const VkBufferCopy232 *in, uint32_t count) -{ - VkBufferCopy2 *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkBufferCopy2_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkCopyBufferInfo2_win32_to_host(struct conversion_context *ctx, const VkCopyBufferInfo232 *in, VkCopyBufferInfo2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcBuffer = in->srcBuffer; - out->dstBuffer = in->dstBuffer; - out->regionCount = in->regionCount; - out->pRegions = convert_VkBufferCopy2_array_win32_to_host(ctx, (const VkBufferCopy232 *)UlongToPtr(in->pRegions), in->regionCount); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkBufferImageCopy_win32_to_host(const VkBufferImageCopy32 *in, VkBufferImageCopy *out) -{ - if (!in) return; - - out->bufferOffset = in->bufferOffset; - out->bufferRowLength = in->bufferRowLength; - out->bufferImageHeight = in->bufferImageHeight; - out->imageSubresource = in->imageSubresource; - out->imageOffset = in->imageOffset; - out->imageExtent = in->imageExtent; -} - -static inline const VkBufferImageCopy *convert_VkBufferImageCopy_array_win32_to_host(struct conversion_context *ctx, const VkBufferImageCopy32 *in, uint32_t count) -{ - VkBufferImageCopy *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkBufferImageCopy_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkBufferImageCopy2_win32_to_host(struct conversion_context *ctx, const VkBufferImageCopy232 *in, VkBufferImageCopy2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->bufferOffset = in->bufferOffset; - out->bufferRowLength = in->bufferRowLength; - out->bufferImageHeight = in->bufferImageHeight; - out->imageSubresource = in->imageSubresource; - out->imageOffset = in->imageOffset; - out->imageExtent = in->imageExtent; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_COPY_COMMAND_TRANSFORM_INFO_QCOM: - { - VkCopyCommandTransformInfoQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkCopyCommandTransformInfoQCOM32 *in_ext = (const VkCopyCommandTransformInfoQCOM32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_COPY_COMMAND_TRANSFORM_INFO_QCOM; - out_ext->pNext = NULL; - out_ext->transform = in_ext->transform; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkBufferImageCopy2 *convert_VkBufferImageCopy2_array_win32_to_host(struct conversion_context *ctx, const VkBufferImageCopy232 *in, uint32_t count) -{ - VkBufferImageCopy2 *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkBufferImageCopy2_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkCopyBufferToImageInfo2_win32_to_host(struct conversion_context *ctx, const VkCopyBufferToImageInfo232 *in, VkCopyBufferToImageInfo2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcBuffer = in->srcBuffer; - out->dstImage = in->dstImage; - out->dstImageLayout = in->dstImageLayout; - out->regionCount = in->regionCount; - out->pRegions = convert_VkBufferImageCopy2_array_win32_to_host(ctx, (const VkBufferImageCopy232 *)UlongToPtr(in->pRegions), in->regionCount); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkImageCopy2_win32_to_host(const VkImageCopy232 *in, VkImageCopy2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcSubresource = in->srcSubresource; - out->srcOffset = in->srcOffset; - out->dstSubresource = in->dstSubresource; - out->dstOffset = in->dstOffset; - out->extent = in->extent; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkImageCopy2 *convert_VkImageCopy2_array_win32_to_host(struct conversion_context *ctx, const VkImageCopy232 *in, uint32_t count) -{ - VkImageCopy2 *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkImageCopy2_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkCopyImageInfo2_win32_to_host(struct conversion_context *ctx, const VkCopyImageInfo232 *in, VkCopyImageInfo2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcImage = in->srcImage; - out->srcImageLayout = in->srcImageLayout; - out->dstImage = in->dstImage; - out->dstImageLayout = in->dstImageLayout; - out->regionCount = in->regionCount; - out->pRegions = convert_VkImageCopy2_array_win32_to_host(ctx, (const VkImageCopy232 *)UlongToPtr(in->pRegions), in->regionCount); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkCopyImageToBufferInfo2_win32_to_host(struct conversion_context *ctx, const VkCopyImageToBufferInfo232 *in, VkCopyImageToBufferInfo2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcImage = in->srcImage; - out->srcImageLayout = in->srcImageLayout; - out->dstBuffer = in->dstBuffer; - out->regionCount = in->regionCount; - out->pRegions = convert_VkBufferImageCopy2_array_win32_to_host(ctx, (const VkBufferImageCopy232 *)UlongToPtr(in->pRegions), in->regionCount); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkCopyMemoryToAccelerationStructureInfoKHR_win32_to_host(const VkCopyMemoryToAccelerationStructureInfoKHR32 *in, VkCopyMemoryToAccelerationStructureInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->src = in->src; - out->dst = in->dst; - out->mode = in->mode; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkCopyMemoryToMicromapInfoEXT_win32_to_host(const VkCopyMemoryToMicromapInfoEXT32 *in, VkCopyMemoryToMicromapInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->src = in->src; - out->dst = in->dst; - out->mode = in->mode; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkCopyMicromapInfoEXT_win32_to_host(const VkCopyMicromapInfoEXT32 *in, VkCopyMicromapInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->src = in->src; - out->dst = in->dst; - out->mode = in->mode; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkCopyMicromapToMemoryInfoEXT_win32_to_host(const VkCopyMicromapToMemoryInfoEXT32 *in, VkCopyMicromapToMemoryInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->src = in->src; - out->dst = in->dst; - out->mode = in->mode; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkCuLaunchInfoNVX_win32_to_host(const VkCuLaunchInfoNVX32 *in, VkCuLaunchInfoNVX *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->function = in->function; - out->gridDimX = in->gridDimX; - out->gridDimY = in->gridDimY; - out->gridDimZ = in->gridDimZ; - out->blockDimX = in->blockDimX; - out->blockDimY = in->blockDimY; - out->blockDimZ = in->blockDimZ; - out->sharedMemBytes = in->sharedMemBytes; - out->paramCount = in->paramCount; - out->pParams = (const void * const *)UlongToPtr(in->pParams); - out->extraCount = in->extraCount; - out->pExtras = (const void * const *)UlongToPtr(in->pExtras); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkDebugMarkerMarkerInfoEXT_win32_to_host(const VkDebugMarkerMarkerInfoEXT32 *in, VkDebugMarkerMarkerInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->pMarkerName = (const char *)UlongToPtr(in->pMarkerName); - memcpy(out->color, in->color, 4 * sizeof(float)); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkDecompressMemoryRegionNV_win32_to_host(const VkDecompressMemoryRegionNV32 *in, VkDecompressMemoryRegionNV *out) -{ - if (!in) return; - - out->srcAddress = in->srcAddress; - out->dstAddress = in->dstAddress; - out->compressedSize = in->compressedSize; - out->decompressedSize = in->decompressedSize; - out->decompressionMethod = in->decompressionMethod; -} - -static inline const VkDecompressMemoryRegionNV *convert_VkDecompressMemoryRegionNV_array_win32_to_host(struct conversion_context *ctx, const VkDecompressMemoryRegionNV32 *in, uint32_t count) -{ - VkDecompressMemoryRegionNV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkDecompressMemoryRegionNV_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkSubpassEndInfo_win32_to_host(struct conversion_context *ctx, const VkSubpassEndInfo32 *in, VkSubpassEndInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_SUBPASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_QCOM: - { - VkSubpassFragmentDensityMapOffsetEndInfoQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSubpassFragmentDensityMapOffsetEndInfoQCOM32 *in_ext = (const VkSubpassFragmentDensityMapOffsetEndInfoQCOM32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SUBPASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_QCOM; - out_ext->pNext = NULL; - out_ext->fragmentDensityOffsetCount = in_ext->fragmentDensityOffsetCount; - out_ext->pFragmentDensityOffsets = (const VkOffset2D *)UlongToPtr(in_ext->pFragmentDensityOffsets); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -#ifdef _WIN64 -static inline const VkCommandBuffer *convert_VkCommandBuffer_array_win64_to_host(struct conversion_context *ctx, const VkCommandBuffer *in, uint32_t count) -{ - VkCommandBuffer *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - out[i] = wine_cmd_buffer_from_handle(in[i])->command_buffer; - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkCommandBuffer *convert_VkCommandBuffer_array_win32_to_host(struct conversion_context *ctx, const PTR32 *in, uint32_t count) -{ - VkCommandBuffer *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - out[i] = wine_cmd_buffer_from_handle(UlongToPtr(in[i]))->command_buffer; - } - - return out; -} - -static inline void convert_VkIndirectCommandsStreamNV_win32_to_host(const VkIndirectCommandsStreamNV32 *in, VkIndirectCommandsStreamNV *out) -{ - if (!in) return; - - out->buffer = in->buffer; - out->offset = in->offset; -} - -static inline const VkIndirectCommandsStreamNV *convert_VkIndirectCommandsStreamNV_array_win32_to_host(struct conversion_context *ctx, const VkIndirectCommandsStreamNV32 *in, uint32_t count) -{ - VkIndirectCommandsStreamNV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkIndirectCommandsStreamNV_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkGeneratedCommandsInfoNV_win32_to_host(struct conversion_context *ctx, const VkGeneratedCommandsInfoNV32 *in, VkGeneratedCommandsInfoNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->pipelineBindPoint = in->pipelineBindPoint; - out->pipeline = in->pipeline; - out->indirectCommandsLayout = in->indirectCommandsLayout; - out->streamCount = in->streamCount; - out->pStreams = convert_VkIndirectCommandsStreamNV_array_win32_to_host(ctx, (const VkIndirectCommandsStreamNV32 *)UlongToPtr(in->pStreams), in->streamCount); - out->sequencesCount = in->sequencesCount; - out->preprocessBuffer = in->preprocessBuffer; - out->preprocessOffset = in->preprocessOffset; - out->preprocessSize = in->preprocessSize; - out->sequencesCountBuffer = in->sequencesCountBuffer; - out->sequencesCountOffset = in->sequencesCountOffset; - out->sequencesIndexBuffer = in->sequencesIndexBuffer; - out->sequencesIndexOffset = in->sequencesIndexOffset; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkOpticalFlowExecuteInfoNV_win32_to_host(const VkOpticalFlowExecuteInfoNV32 *in, VkOpticalFlowExecuteInfoNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->regionCount = in->regionCount; - out->pRegions = (const VkRect2D *)UlongToPtr(in->pRegions); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkMemoryBarrier_win32_to_host(const VkMemoryBarrier32 *in, VkMemoryBarrier *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcAccessMask = in->srcAccessMask; - out->dstAccessMask = in->dstAccessMask; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkMemoryBarrier *convert_VkMemoryBarrier_array_win32_to_host(struct conversion_context *ctx, const VkMemoryBarrier32 *in, uint32_t count) -{ - VkMemoryBarrier *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkMemoryBarrier_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkBufferMemoryBarrier_win32_to_host(const VkBufferMemoryBarrier32 *in, VkBufferMemoryBarrier *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcAccessMask = in->srcAccessMask; - out->dstAccessMask = in->dstAccessMask; - out->srcQueueFamilyIndex = in->srcQueueFamilyIndex; - out->dstQueueFamilyIndex = in->dstQueueFamilyIndex; - out->buffer = in->buffer; - out->offset = in->offset; - out->size = in->size; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkBufferMemoryBarrier *convert_VkBufferMemoryBarrier_array_win32_to_host(struct conversion_context *ctx, const VkBufferMemoryBarrier32 *in, uint32_t count) -{ - VkBufferMemoryBarrier *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkBufferMemoryBarrier_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkImageMemoryBarrier_win32_to_host(struct conversion_context *ctx, const VkImageMemoryBarrier32 *in, VkImageMemoryBarrier *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcAccessMask = in->srcAccessMask; - out->dstAccessMask = in->dstAccessMask; - out->oldLayout = in->oldLayout; - out->newLayout = in->newLayout; - out->srcQueueFamilyIndex = in->srcQueueFamilyIndex; - out->dstQueueFamilyIndex = in->dstQueueFamilyIndex; - out->image = in->image; - out->subresourceRange = in->subresourceRange; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT: - { - VkSampleLocationsInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSampleLocationsInfoEXT32 *in_ext = (const VkSampleLocationsInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT; - out_ext->pNext = NULL; - out_ext->sampleLocationsPerPixel = in_ext->sampleLocationsPerPixel; - out_ext->sampleLocationGridSize = in_ext->sampleLocationGridSize; - out_ext->sampleLocationsCount = in_ext->sampleLocationsCount; - out_ext->pSampleLocations = (const VkSampleLocationEXT *)UlongToPtr(in_ext->pSampleLocations); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkImageMemoryBarrier *convert_VkImageMemoryBarrier_array_win32_to_host(struct conversion_context *ctx, const VkImageMemoryBarrier32 *in, uint32_t count) -{ - VkImageMemoryBarrier *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkImageMemoryBarrier_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkMemoryBarrier2_win32_to_host(const VkMemoryBarrier232 *in, VkMemoryBarrier2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcStageMask = in->srcStageMask; - out->srcAccessMask = in->srcAccessMask; - out->dstStageMask = in->dstStageMask; - out->dstAccessMask = in->dstAccessMask; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkMemoryBarrier2 *convert_VkMemoryBarrier2_array_win32_to_host(struct conversion_context *ctx, const VkMemoryBarrier232 *in, uint32_t count) -{ - VkMemoryBarrier2 *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkMemoryBarrier2_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkBufferMemoryBarrier2_win32_to_host(const VkBufferMemoryBarrier232 *in, VkBufferMemoryBarrier2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcStageMask = in->srcStageMask; - out->srcAccessMask = in->srcAccessMask; - out->dstStageMask = in->dstStageMask; - out->dstAccessMask = in->dstAccessMask; - out->srcQueueFamilyIndex = in->srcQueueFamilyIndex; - out->dstQueueFamilyIndex = in->dstQueueFamilyIndex; - out->buffer = in->buffer; - out->offset = in->offset; - out->size = in->size; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkBufferMemoryBarrier2 *convert_VkBufferMemoryBarrier2_array_win32_to_host(struct conversion_context *ctx, const VkBufferMemoryBarrier232 *in, uint32_t count) -{ - VkBufferMemoryBarrier2 *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkBufferMemoryBarrier2_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkImageMemoryBarrier2_win32_to_host(struct conversion_context *ctx, const VkImageMemoryBarrier232 *in, VkImageMemoryBarrier2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcStageMask = in->srcStageMask; - out->srcAccessMask = in->srcAccessMask; - out->dstStageMask = in->dstStageMask; - out->dstAccessMask = in->dstAccessMask; - out->oldLayout = in->oldLayout; - out->newLayout = in->newLayout; - out->srcQueueFamilyIndex = in->srcQueueFamilyIndex; - out->dstQueueFamilyIndex = in->dstQueueFamilyIndex; - out->image = in->image; - out->subresourceRange = in->subresourceRange; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT: - { - VkSampleLocationsInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSampleLocationsInfoEXT32 *in_ext = (const VkSampleLocationsInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT; - out_ext->pNext = NULL; - out_ext->sampleLocationsPerPixel = in_ext->sampleLocationsPerPixel; - out_ext->sampleLocationGridSize = in_ext->sampleLocationGridSize; - out_ext->sampleLocationsCount = in_ext->sampleLocationsCount; - out_ext->pSampleLocations = (const VkSampleLocationEXT *)UlongToPtr(in_ext->pSampleLocations); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkImageMemoryBarrier2 *convert_VkImageMemoryBarrier2_array_win32_to_host(struct conversion_context *ctx, const VkImageMemoryBarrier232 *in, uint32_t count) -{ - VkImageMemoryBarrier2 *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkImageMemoryBarrier2_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkDependencyInfo_win32_to_host(struct conversion_context *ctx, const VkDependencyInfo32 *in, VkDependencyInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->dependencyFlags = in->dependencyFlags; - out->memoryBarrierCount = in->memoryBarrierCount; - out->pMemoryBarriers = convert_VkMemoryBarrier2_array_win32_to_host(ctx, (const VkMemoryBarrier232 *)UlongToPtr(in->pMemoryBarriers), in->memoryBarrierCount); - out->bufferMemoryBarrierCount = in->bufferMemoryBarrierCount; - out->pBufferMemoryBarriers = convert_VkBufferMemoryBarrier2_array_win32_to_host(ctx, (const VkBufferMemoryBarrier232 *)UlongToPtr(in->pBufferMemoryBarriers), in->bufferMemoryBarrierCount); - out->imageMemoryBarrierCount = in->imageMemoryBarrierCount; - out->pImageMemoryBarriers = convert_VkImageMemoryBarrier2_array_win32_to_host(ctx, (const VkImageMemoryBarrier232 *)UlongToPtr(in->pImageMemoryBarriers), in->imageMemoryBarrierCount); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkDescriptorImageInfo_win32_to_host(const VkDescriptorImageInfo32 *in, VkDescriptorImageInfo *out) -{ - if (!in) return; - - out->sampler = in->sampler; - out->imageView = in->imageView; - out->imageLayout = in->imageLayout; -} - -static inline const VkDescriptorImageInfo *convert_VkDescriptorImageInfo_array_win32_to_host(struct conversion_context *ctx, const VkDescriptorImageInfo32 *in, uint32_t count) -{ - VkDescriptorImageInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkDescriptorImageInfo_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkDescriptorBufferInfo_win32_to_host(const VkDescriptorBufferInfo32 *in, VkDescriptorBufferInfo *out) -{ - if (!in) return; - - out->buffer = in->buffer; - out->offset = in->offset; - out->range = in->range; -} - -static inline const VkDescriptorBufferInfo *convert_VkDescriptorBufferInfo_array_win32_to_host(struct conversion_context *ctx, const VkDescriptorBufferInfo32 *in, uint32_t count) -{ - VkDescriptorBufferInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkDescriptorBufferInfo_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkWriteDescriptorSet_win32_to_host(struct conversion_context *ctx, const VkWriteDescriptorSet32 *in, VkWriteDescriptorSet *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->dstSet = in->dstSet; - out->dstBinding = in->dstBinding; - out->dstArrayElement = in->dstArrayElement; - out->descriptorCount = in->descriptorCount; - out->descriptorType = in->descriptorType; - out->pImageInfo = convert_VkDescriptorImageInfo_array_win32_to_host(ctx, (const VkDescriptorImageInfo32 *)UlongToPtr(in->pImageInfo), in->descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || in->descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || in->descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || in->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || in->descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT || in->descriptorType == VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM || in->descriptorType == VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM ? in->descriptorCount : 0); - out->pBufferInfo = convert_VkDescriptorBufferInfo_array_win32_to_host(ctx, (const VkDescriptorBufferInfo32 *)UlongToPtr(in->pBufferInfo), in->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || in->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || in->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC || in->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC ? in->descriptorCount : 0); - out->pTexelBufferView = (const VkBufferView *)UlongToPtr(in->pTexelBufferView); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK: - { - VkWriteDescriptorSetInlineUniformBlock *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkWriteDescriptorSetInlineUniformBlock32 *in_ext = (const VkWriteDescriptorSetInlineUniformBlock32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK; - out_ext->pNext = NULL; - out_ext->dataSize = in_ext->dataSize; - out_ext->pData = (const void *)UlongToPtr(in_ext->pData); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR: - { - VkWriteDescriptorSetAccelerationStructureKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkWriteDescriptorSetAccelerationStructureKHR32 *in_ext = (const VkWriteDescriptorSetAccelerationStructureKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; - out_ext->pNext = NULL; - out_ext->accelerationStructureCount = in_ext->accelerationStructureCount; - out_ext->pAccelerationStructures = (const VkAccelerationStructureKHR *)UlongToPtr(in_ext->pAccelerationStructures); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV: - { - VkWriteDescriptorSetAccelerationStructureNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkWriteDescriptorSetAccelerationStructureNV32 *in_ext = (const VkWriteDescriptorSetAccelerationStructureNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV; - out_ext->pNext = NULL; - out_ext->accelerationStructureCount = in_ext->accelerationStructureCount; - out_ext->pAccelerationStructures = (const VkAccelerationStructureNV *)UlongToPtr(in_ext->pAccelerationStructures); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkWriteDescriptorSet *convert_VkWriteDescriptorSet_array_win32_to_host(struct conversion_context *ctx, const VkWriteDescriptorSet32 *in, uint32_t count) -{ - VkWriteDescriptorSet *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkWriteDescriptorSet_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkImageResolve2_win32_to_host(const VkImageResolve232 *in, VkImageResolve2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcSubresource = in->srcSubresource; - out->srcOffset = in->srcOffset; - out->dstSubresource = in->dstSubresource; - out->dstOffset = in->dstOffset; - out->extent = in->extent; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkImageResolve2 *convert_VkImageResolve2_array_win32_to_host(struct conversion_context *ctx, const VkImageResolve232 *in, uint32_t count) -{ - VkImageResolve2 *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkImageResolve2_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkResolveImageInfo2_win32_to_host(struct conversion_context *ctx, const VkResolveImageInfo232 *in, VkResolveImageInfo2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcImage = in->srcImage; - out->srcImageLayout = in->srcImageLayout; - out->dstImage = in->dstImage; - out->dstImageLayout = in->dstImageLayout; - out->regionCount = in->regionCount; - out->pRegions = convert_VkImageResolve2_array_win32_to_host(ctx, (const VkImageResolve232 *)UlongToPtr(in->pRegions), in->regionCount); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkCoarseSampleOrderCustomNV_win32_to_host(const VkCoarseSampleOrderCustomNV32 *in, VkCoarseSampleOrderCustomNV *out) -{ - if (!in) return; - - out->shadingRate = in->shadingRate; - out->sampleCount = in->sampleCount; - out->sampleLocationCount = in->sampleLocationCount; - out->pSampleLocations = (const VkCoarseSampleLocationNV *)UlongToPtr(in->pSampleLocations); -} - -static inline const VkCoarseSampleOrderCustomNV *convert_VkCoarseSampleOrderCustomNV_array_win32_to_host(struct conversion_context *ctx, const VkCoarseSampleOrderCustomNV32 *in, uint32_t count) -{ - VkCoarseSampleOrderCustomNV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkCoarseSampleOrderCustomNV_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPerformanceMarkerInfoINTEL_win32_to_host(const VkPerformanceMarkerInfoINTEL32 *in, VkPerformanceMarkerInfoINTEL *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->marker = in->marker; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkPerformanceOverrideInfoINTEL_win32_to_host(const VkPerformanceOverrideInfoINTEL32 *in, VkPerformanceOverrideInfoINTEL *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->type = in->type; - out->enable = in->enable; - out->parameter = in->parameter; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkPerformanceStreamMarkerInfoINTEL_win32_to_host(const VkPerformanceStreamMarkerInfoINTEL32 *in, VkPerformanceStreamMarkerInfoINTEL *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->marker = in->marker; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkVertexInputBindingDescription2EXT_win32_to_host(const VkVertexInputBindingDescription2EXT32 *in, VkVertexInputBindingDescription2EXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->binding = in->binding; - out->stride = in->stride; - out->inputRate = in->inputRate; - out->divisor = in->divisor; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkVertexInputBindingDescription2EXT *convert_VkVertexInputBindingDescription2EXT_array_win32_to_host(struct conversion_context *ctx, const VkVertexInputBindingDescription2EXT32 *in, uint32_t count) -{ - VkVertexInputBindingDescription2EXT *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkVertexInputBindingDescription2EXT_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkVertexInputAttributeDescription2EXT_win32_to_host(const VkVertexInputAttributeDescription2EXT32 *in, VkVertexInputAttributeDescription2EXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->location = in->location; - out->binding = in->binding; - out->format = in->format; - out->offset = in->offset; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkVertexInputAttributeDescription2EXT *convert_VkVertexInputAttributeDescription2EXT_array_win32_to_host(struct conversion_context *ctx, const VkVertexInputAttributeDescription2EXT32 *in, uint32_t count) -{ - VkVertexInputAttributeDescription2EXT *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkVertexInputAttributeDescription2EXT_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkShadingRatePaletteNV_win32_to_host(const VkShadingRatePaletteNV32 *in, VkShadingRatePaletteNV *out) -{ - if (!in) return; - - out->shadingRatePaletteEntryCount = in->shadingRatePaletteEntryCount; - out->pShadingRatePaletteEntries = (const VkShadingRatePaletteEntryNV *)UlongToPtr(in->pShadingRatePaletteEntries); -} - -static inline const VkShadingRatePaletteNV *convert_VkShadingRatePaletteNV_array_win32_to_host(struct conversion_context *ctx, const VkShadingRatePaletteNV32 *in, uint32_t count) -{ - VkShadingRatePaletteNV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkShadingRatePaletteNV_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkStridedDeviceAddressRegionKHR_win32_to_host(const VkStridedDeviceAddressRegionKHR32 *in, VkStridedDeviceAddressRegionKHR *out) -{ - if (!in) return; - - out->deviceAddress = in->deviceAddress; - out->stride = in->stride; - out->size = in->size; -} - -static inline const VkDependencyInfo *convert_VkDependencyInfo_array_win32_to_host(struct conversion_context *ctx, const VkDependencyInfo32 *in, uint32_t count) -{ - VkDependencyInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkDependencyInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkAccelerationStructureCreateInfoKHR_win32_to_host(struct conversion_context *ctx, const VkAccelerationStructureCreateInfoKHR32 *in, VkAccelerationStructureCreateInfoKHR *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->createFlags = in->createFlags; - out->buffer = in->buffer; - out->offset = in->offset; - out->size = in->size; - out->type = in->type; - out->deviceAddress = in->deviceAddress; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT: - { - VkOpaqueCaptureDescriptorDataCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkOpaqueCaptureDescriptorDataCreateInfoEXT32 *in_ext = (const VkOpaqueCaptureDescriptorDataCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->opaqueCaptureDescriptorData = (const void *)UlongToPtr(in_ext->opaqueCaptureDescriptorData); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MOTION_INFO_NV: - { - VkAccelerationStructureMotionInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkAccelerationStructureMotionInfoNV32 *in_ext = (const VkAccelerationStructureMotionInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MOTION_INFO_NV; - out_ext->pNext = NULL; - out_ext->maxInstances = in_ext->maxInstances; - out_ext->flags = in_ext->flags; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkAccelerationStructureCreateInfoNV_win32_to_host(struct conversion_context *ctx, const VkAccelerationStructureCreateInfoNV32 *in, VkAccelerationStructureCreateInfoNV *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->compactedSize = in->compactedSize; - convert_VkAccelerationStructureInfoNV_win32_to_host(ctx, &in->info, &out->info); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT: - { - VkOpaqueCaptureDescriptorDataCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkOpaqueCaptureDescriptorDataCreateInfoEXT32 *in_ext = (const VkOpaqueCaptureDescriptorDataCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->opaqueCaptureDescriptorData = (const void *)UlongToPtr(in_ext->opaqueCaptureDescriptorData); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkBufferCreateInfo_win32_to_host(struct conversion_context *ctx, const VkBufferCreateInfo32 *in, VkBufferCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->size = in->size; - out->usage = in->usage; - out->sharingMode = in->sharingMode; - out->queueFamilyIndexCount = in->queueFamilyIndexCount; - out->pQueueFamilyIndices = (const uint32_t *)UlongToPtr(in->pQueueFamilyIndices); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV: - { - VkDedicatedAllocationBufferCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDedicatedAllocationBufferCreateInfoNV32 *in_ext = (const VkDedicatedAllocationBufferCreateInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->dedicatedAllocation = in_ext->dedicatedAllocation; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO: - { - VkExternalMemoryBufferCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkExternalMemoryBufferCreateInfo32 *in_ext = (const VkExternalMemoryBufferCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->handleTypes = in_ext->handleTypes; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO: - { - VkBufferOpaqueCaptureAddressCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkBufferOpaqueCaptureAddressCreateInfo32 *in_ext = (const VkBufferOpaqueCaptureAddressCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->opaqueCaptureAddress = in_ext->opaqueCaptureAddress; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT: - { - VkBufferDeviceAddressCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkBufferDeviceAddressCreateInfoEXT32 *in_ext = (const VkBufferDeviceAddressCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->deviceAddress = in_ext->deviceAddress; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT: - { - VkOpaqueCaptureDescriptorDataCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkOpaqueCaptureDescriptorDataCreateInfoEXT32 *in_ext = (const VkOpaqueCaptureDescriptorDataCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->opaqueCaptureDescriptorData = (const void *)UlongToPtr(in_ext->opaqueCaptureDescriptorData); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkBufferViewCreateInfo_win32_to_host(const VkBufferViewCreateInfo32 *in, VkBufferViewCreateInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->buffer = in->buffer; - out->format = in->format; - out->offset = in->offset; - out->range = in->range; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkCommandPoolCreateInfo_win32_to_host(const VkCommandPoolCreateInfo32 *in, VkCommandPoolCreateInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->queueFamilyIndex = in->queueFamilyIndex; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkPipelineCreationFeedback_host_to_win32(const VkPipelineCreationFeedback *in, VkPipelineCreationFeedback32 *out) -{ - if (!in) return; - - out->flags = in->flags; - out->duration = in->duration; -} - -static inline VkPipelineCreationFeedback *convert_VkPipelineCreationFeedback_array_win32_to_host(struct conversion_context *ctx, const VkPipelineCreationFeedback32 *in, uint32_t count) -{ - VkPipelineCreationFeedback *out; - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - - return out; -} - -static inline void convert_VkPipelineCreationFeedback_array_host_to_win32(const VkPipelineCreationFeedback *in, VkPipelineCreationFeedback32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkPipelineCreationFeedback_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkSpecializationMapEntry_win32_to_host(const VkSpecializationMapEntry32 *in, VkSpecializationMapEntry *out) -{ - if (!in) return; - - out->constantID = in->constantID; - out->offset = in->offset; - out->size = in->size; -} - -static inline const VkSpecializationMapEntry *convert_VkSpecializationMapEntry_array_win32_to_host(struct conversion_context *ctx, const VkSpecializationMapEntry32 *in, uint32_t count) -{ - VkSpecializationMapEntry *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSpecializationMapEntry_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkSpecializationInfo_win32_to_host(struct conversion_context *ctx, const VkSpecializationInfo32 *in, VkSpecializationInfo *out) -{ - if (!in) return; - - out->mapEntryCount = in->mapEntryCount; - out->pMapEntries = convert_VkSpecializationMapEntry_array_win32_to_host(ctx, (const VkSpecializationMapEntry32 *)UlongToPtr(in->pMapEntries), in->mapEntryCount); - out->dataSize = in->dataSize; - out->pData = (const void *)UlongToPtr(in->pData); -} - -static inline const VkSpecializationInfo *convert_VkSpecializationInfo_array_win32_to_host(struct conversion_context *ctx, const VkSpecializationInfo32 *in, uint32_t count) -{ - VkSpecializationInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSpecializationInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -#ifdef _WIN64 -static inline void convert_VkPipelineShaderStageCreateInfo_win64_to_host(struct conversion_context *ctx, const VkPipelineShaderStageCreateInfo *in, VkPipelineShaderStageCreateInfo *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->stage = in->stage; - out->module = in->module; - out->pName = in->pName; - out->pSpecializationInfo = in->pSpecializationInfo; - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO: - { - VkShaderModuleCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkShaderModuleCreateInfo *in_ext = (const VkShaderModuleCreateInfo *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->codeSize = in_ext->codeSize; - out_ext->pCode = in_ext->pCode; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT: - { - VkShaderModuleValidationCacheCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkShaderModuleValidationCacheCreateInfoEXT *in_ext = (const VkShaderModuleValidationCacheCreateInfoEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->validationCache = in_ext->validationCache; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT: - { - VkDebugUtilsObjectNameInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDebugUtilsObjectNameInfoEXT *in_ext = (const VkDebugUtilsObjectNameInfoEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; - out_ext->pNext = NULL; - out_ext->objectType = in_ext->objectType; - out_ext->objectHandle = wine_vk_unwrap_handle(in_ext->objectType, in_ext->objectHandle); - out_ext->pObjectName = in_ext->pObjectName; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO: - { - VkPipelineShaderStageRequiredSubgroupSizeCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineShaderStageRequiredSubgroupSizeCreateInfo *in_ext = (const VkPipelineShaderStageRequiredSubgroupSizeCreateInfo *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->requiredSubgroupSize = in_ext->requiredSubgroupSize; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_MODULE_IDENTIFIER_CREATE_INFO_EXT: - { - VkPipelineShaderStageModuleIdentifierCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineShaderStageModuleIdentifierCreateInfoEXT *in_ext = (const VkPipelineShaderStageModuleIdentifierCreateInfoEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_MODULE_IDENTIFIER_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->identifierSize = in_ext->identifierSize; - out_ext->pIdentifier = in_ext->pIdentifier; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT: - { - VkPipelineRobustnessCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineRobustnessCreateInfoEXT *in_ext = (const VkPipelineRobustnessCreateInfoEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->storageBuffers = in_ext->storageBuffers; - out_ext->uniformBuffers = in_ext->uniformBuffers; - out_ext->vertexInputs = in_ext->vertexInputs; - out_ext->images = in_ext->images; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} -#endif /* _WIN64 */ - -static inline void convert_VkPipelineShaderStageCreateInfo_win32_to_host(struct conversion_context *ctx, const VkPipelineShaderStageCreateInfo32 *in, VkPipelineShaderStageCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->stage = in->stage; - out->module = in->module; - out->pName = (const char *)UlongToPtr(in->pName); - out->pSpecializationInfo = convert_VkSpecializationInfo_array_win32_to_host(ctx, (const VkSpecializationInfo32 *)UlongToPtr(in->pSpecializationInfo), 1); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO: - { - VkShaderModuleCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkShaderModuleCreateInfo32 *in_ext = (const VkShaderModuleCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->codeSize = in_ext->codeSize; - out_ext->pCode = (const uint32_t *)UlongToPtr(in_ext->pCode); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT: - { - VkShaderModuleValidationCacheCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkShaderModuleValidationCacheCreateInfoEXT32 *in_ext = (const VkShaderModuleValidationCacheCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->validationCache = in_ext->validationCache; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT: - { - VkDebugUtilsObjectNameInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDebugUtilsObjectNameInfoEXT32 *in_ext = (const VkDebugUtilsObjectNameInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; - out_ext->pNext = NULL; - out_ext->objectType = in_ext->objectType; - out_ext->objectHandle = wine_vk_unwrap_handle(in_ext->objectType, in_ext->objectHandle); - out_ext->pObjectName = (const char *)UlongToPtr(in_ext->pObjectName); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO: - { - VkPipelineShaderStageRequiredSubgroupSizeCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineShaderStageRequiredSubgroupSizeCreateInfo32 *in_ext = (const VkPipelineShaderStageRequiredSubgroupSizeCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->requiredSubgroupSize = in_ext->requiredSubgroupSize; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_MODULE_IDENTIFIER_CREATE_INFO_EXT: - { - VkPipelineShaderStageModuleIdentifierCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineShaderStageModuleIdentifierCreateInfoEXT32 *in_ext = (const VkPipelineShaderStageModuleIdentifierCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_MODULE_IDENTIFIER_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->identifierSize = in_ext->identifierSize; - out_ext->pIdentifier = (const uint8_t *)UlongToPtr(in_ext->pIdentifier); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT: - { - VkPipelineRobustnessCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineRobustnessCreateInfoEXT32 *in_ext = (const VkPipelineRobustnessCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->storageBuffers = in_ext->storageBuffers; - out_ext->uniformBuffers = in_ext->uniformBuffers; - out_ext->vertexInputs = in_ext->vertexInputs; - out_ext->images = in_ext->images; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -#ifdef _WIN64 -static inline void convert_VkComputePipelineCreateInfo_win64_to_host(struct conversion_context *ctx, const VkComputePipelineCreateInfo *in, VkComputePipelineCreateInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->flags = in->flags; - convert_VkPipelineShaderStageCreateInfo_win64_to_host(ctx, &in->stage, &out->stage); - out->layout = in->layout; - out->basePipelineHandle = in->basePipelineHandle; - out->basePipelineIndex = in->basePipelineIndex; -} -#endif /* _WIN64 */ - -static inline void convert_VkComputePipelineCreateInfo_win32_to_host(struct conversion_context *ctx, const VkComputePipelineCreateInfo32 *in, VkComputePipelineCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - convert_VkPipelineShaderStageCreateInfo_win32_to_host(ctx, &in->stage, &out->stage); - out->layout = in->layout; - out->basePipelineHandle = in->basePipelineHandle; - out->basePipelineIndex = in->basePipelineIndex; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO: - { - VkPipelineCreationFeedbackCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineCreationFeedbackCreateInfo32 *in_ext = (const VkPipelineCreationFeedbackCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->pPipelineCreationFeedback = convert_VkPipelineCreationFeedback_array_win32_to_host(ctx, (VkPipelineCreationFeedback32 *)UlongToPtr(in_ext->pPipelineCreationFeedback), 1); - out_ext->pipelineStageCreationFeedbackCount = in_ext->pipelineStageCreationFeedbackCount; - out_ext->pPipelineStageCreationFeedbacks = convert_VkPipelineCreationFeedback_array_win32_to_host(ctx, (VkPipelineCreationFeedback32 *)UlongToPtr(in_ext->pPipelineStageCreationFeedbacks), in_ext->pipelineStageCreationFeedbackCount); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SUBPASS_SHADING_PIPELINE_CREATE_INFO_HUAWEI: - { - VkSubpassShadingPipelineCreateInfoHUAWEI *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSubpassShadingPipelineCreateInfoHUAWEI32 *in_ext = (const VkSubpassShadingPipelineCreateInfoHUAWEI32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SUBPASS_SHADING_PIPELINE_CREATE_INFO_HUAWEI; - out_ext->pNext = NULL; - out_ext->renderPass = in_ext->renderPass; - out_ext->subpass = in_ext->subpass; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD: - { - VkPipelineCompilerControlCreateInfoAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineCompilerControlCreateInfoAMD32 *in_ext = (const VkPipelineCompilerControlCreateInfoAMD32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD; - out_ext->pNext = NULL; - out_ext->compilerControlFlags = in_ext->compilerControlFlags; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT: - { - VkPipelineRobustnessCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineRobustnessCreateInfoEXT32 *in_ext = (const VkPipelineRobustnessCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->storageBuffers = in_ext->storageBuffers; - out_ext->uniformBuffers = in_ext->uniformBuffers; - out_ext->vertexInputs = in_ext->vertexInputs; - out_ext->images = in_ext->images; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkComputePipelineCreateInfo_host_to_win32(const VkComputePipelineCreateInfo *in, const VkComputePipelineCreateInfo32 *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure32 *out_header = (void *)out; - - if (!in) return; - - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO: - { - VkPipelineCreationFeedbackCreateInfo32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO); - const VkPipelineCreationFeedbackCreateInfo *in_ext = (const VkPipelineCreationFeedbackCreateInfo *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO; - convert_VkPipelineCreationFeedback_array_host_to_win32(in_ext->pPipelineCreationFeedback, (VkPipelineCreationFeedback32 *)UlongToPtr(out_ext->pPipelineCreationFeedback), 1); - convert_VkPipelineCreationFeedback_array_host_to_win32(in_ext->pPipelineStageCreationFeedbacks, (VkPipelineCreationFeedback32 *)UlongToPtr(out_ext->pPipelineStageCreationFeedbacks), in_ext->pipelineStageCreationFeedbackCount); - out_header = (void *)out_ext; - break; - } - default: - break; - } - } -} - -#ifdef _WIN64 -static inline const VkComputePipelineCreateInfo *convert_VkComputePipelineCreateInfo_array_win64_to_host(struct conversion_context *ctx, const VkComputePipelineCreateInfo *in, uint32_t count) -{ - VkComputePipelineCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkComputePipelineCreateInfo_win64_to_host(ctx, &in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkComputePipelineCreateInfo *convert_VkComputePipelineCreateInfo_array_win32_to_host(struct conversion_context *ctx, const VkComputePipelineCreateInfo32 *in, uint32_t count) -{ - VkComputePipelineCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkComputePipelineCreateInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkComputePipelineCreateInfo_array_host_to_win32(const VkComputePipelineCreateInfo *in, const VkComputePipelineCreateInfo32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkComputePipelineCreateInfo_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkCuFunctionCreateInfoNVX_win32_to_host(const VkCuFunctionCreateInfoNVX32 *in, VkCuFunctionCreateInfoNVX *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->module = in->module; - out->pName = (const char *)UlongToPtr(in->pName); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkCuModuleCreateInfoNVX_win32_to_host(const VkCuModuleCreateInfoNVX32 *in, VkCuModuleCreateInfoNVX *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->dataSize = in->dataSize; - out->pData = (const void *)UlongToPtr(in->pData); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkDebugReportCallbackCreateInfoEXT_win32_to_host(const VkDebugReportCallbackCreateInfoEXT32 *in, VkDebugReportCallbackCreateInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->pfnCallback = in->pfnCallback; - out->pUserData = (void *)UlongToPtr(in->pUserData); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkDebugUtilsMessengerCreateInfoEXT_win32_to_host(const VkDebugUtilsMessengerCreateInfoEXT32 *in, VkDebugUtilsMessengerCreateInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->messageSeverity = in->messageSeverity; - out->messageType = in->messageType; - out->pfnUserCallback = in->pfnUserCallback; - out->pUserData = (void *)UlongToPtr(in->pUserData); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkMutableDescriptorTypeListEXT_win32_to_host(const VkMutableDescriptorTypeListEXT32 *in, VkMutableDescriptorTypeListEXT *out) -{ - if (!in) return; - - out->descriptorTypeCount = in->descriptorTypeCount; - out->pDescriptorTypes = (const VkDescriptorType *)UlongToPtr(in->pDescriptorTypes); -} - -static inline const VkMutableDescriptorTypeListEXT *convert_VkMutableDescriptorTypeListEXT_array_win32_to_host(struct conversion_context *ctx, const VkMutableDescriptorTypeListEXT32 *in, uint32_t count) -{ - VkMutableDescriptorTypeListEXT *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkMutableDescriptorTypeListEXT_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkDescriptorPoolCreateInfo_win32_to_host(struct conversion_context *ctx, const VkDescriptorPoolCreateInfo32 *in, VkDescriptorPoolCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->maxSets = in->maxSets; - out->poolSizeCount = in->poolSizeCount; - out->pPoolSizes = (const VkDescriptorPoolSize *)UlongToPtr(in->pPoolSizes); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO: - { - VkDescriptorPoolInlineUniformBlockCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDescriptorPoolInlineUniformBlockCreateInfo32 *in_ext = (const VkDescriptorPoolInlineUniformBlockCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->maxInlineUniformBlockBindings = in_ext->maxInlineUniformBlockBindings; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT: - { - VkMutableDescriptorTypeCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkMutableDescriptorTypeCreateInfoEXT32 *in_ext = (const VkMutableDescriptorTypeCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->mutableDescriptorTypeListCount = in_ext->mutableDescriptorTypeListCount; - out_ext->pMutableDescriptorTypeLists = convert_VkMutableDescriptorTypeListEXT_array_win32_to_host(ctx, (const VkMutableDescriptorTypeListEXT32 *)UlongToPtr(in_ext->pMutableDescriptorTypeLists), in_ext->mutableDescriptorTypeListCount); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkDescriptorSetLayoutBinding_win32_to_host(const VkDescriptorSetLayoutBinding32 *in, VkDescriptorSetLayoutBinding *out) -{ - if (!in) return; - - out->binding = in->binding; - out->descriptorType = in->descriptorType; - out->descriptorCount = in->descriptorCount; - out->stageFlags = in->stageFlags; - out->pImmutableSamplers = (const VkSampler *)UlongToPtr(in->pImmutableSamplers); -} - -static inline const VkDescriptorSetLayoutBinding *convert_VkDescriptorSetLayoutBinding_array_win32_to_host(struct conversion_context *ctx, const VkDescriptorSetLayoutBinding32 *in, uint32_t count) -{ - VkDescriptorSetLayoutBinding *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkDescriptorSetLayoutBinding_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkDescriptorSetLayoutCreateInfo_win32_to_host(struct conversion_context *ctx, const VkDescriptorSetLayoutCreateInfo32 *in, VkDescriptorSetLayoutCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->bindingCount = in->bindingCount; - out->pBindings = convert_VkDescriptorSetLayoutBinding_array_win32_to_host(ctx, (const VkDescriptorSetLayoutBinding32 *)UlongToPtr(in->pBindings), in->bindingCount); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO: - { - VkDescriptorSetLayoutBindingFlagsCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDescriptorSetLayoutBindingFlagsCreateInfo32 *in_ext = (const VkDescriptorSetLayoutBindingFlagsCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->bindingCount = in_ext->bindingCount; - out_ext->pBindingFlags = (const VkDescriptorBindingFlags *)UlongToPtr(in_ext->pBindingFlags); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT: - { - VkMutableDescriptorTypeCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkMutableDescriptorTypeCreateInfoEXT32 *in_ext = (const VkMutableDescriptorTypeCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->mutableDescriptorTypeListCount = in_ext->mutableDescriptorTypeListCount; - out_ext->pMutableDescriptorTypeLists = convert_VkMutableDescriptorTypeListEXT_array_win32_to_host(ctx, (const VkMutableDescriptorTypeListEXT32 *)UlongToPtr(in_ext->pMutableDescriptorTypeLists), in_ext->mutableDescriptorTypeListCount); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkDescriptorUpdateTemplateEntry_win32_to_host(const VkDescriptorUpdateTemplateEntry32 *in, VkDescriptorUpdateTemplateEntry *out) -{ - if (!in) return; - - out->dstBinding = in->dstBinding; - out->dstArrayElement = in->dstArrayElement; - out->descriptorCount = in->descriptorCount; - out->descriptorType = in->descriptorType; - out->offset = in->offset; - out->stride = in->stride; -} - -static inline const VkDescriptorUpdateTemplateEntry *convert_VkDescriptorUpdateTemplateEntry_array_win32_to_host(struct conversion_context *ctx, const VkDescriptorUpdateTemplateEntry32 *in, uint32_t count) -{ - VkDescriptorUpdateTemplateEntry *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkDescriptorUpdateTemplateEntry_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkDescriptorUpdateTemplateCreateInfo_win32_to_host(struct conversion_context *ctx, const VkDescriptorUpdateTemplateCreateInfo32 *in, VkDescriptorUpdateTemplateCreateInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->descriptorUpdateEntryCount = in->descriptorUpdateEntryCount; - out->pDescriptorUpdateEntries = convert_VkDescriptorUpdateTemplateEntry_array_win32_to_host(ctx, (const VkDescriptorUpdateTemplateEntry32 *)UlongToPtr(in->pDescriptorUpdateEntries), in->descriptorUpdateEntryCount); - out->templateType = in->templateType; - out->descriptorSetLayout = in->descriptorSetLayout; - out->pipelineBindPoint = in->pipelineBindPoint; - out->pipelineLayout = in->pipelineLayout; - out->set = in->set; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -#ifdef _WIN64 -static inline const VkPhysicalDevice *convert_VkPhysicalDevice_array_win64_to_host(struct conversion_context *ctx, const VkPhysicalDevice *in, uint32_t count) -{ - VkPhysicalDevice *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - out[i] = wine_phys_dev_from_handle(in[i])->phys_dev; - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkPhysicalDevice *convert_VkPhysicalDevice_array_win32_to_host(struct conversion_context *ctx, const PTR32 *in, uint32_t count) -{ - VkPhysicalDevice *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - out[i] = wine_phys_dev_from_handle(UlongToPtr(in[i]))->phys_dev; - } - - return out; -} - -static inline void convert_VkDeviceQueueCreateInfo_win32_to_host(struct conversion_context *ctx, const VkDeviceQueueCreateInfo32 *in, VkDeviceQueueCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->queueFamilyIndex = in->queueFamilyIndex; - out->queueCount = in->queueCount; - out->pQueuePriorities = (const float *)UlongToPtr(in->pQueuePriorities); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR: - { - VkDeviceQueueGlobalPriorityCreateInfoKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDeviceQueueGlobalPriorityCreateInfoKHR32 *in_ext = (const VkDeviceQueueGlobalPriorityCreateInfoKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR; - out_ext->pNext = NULL; - out_ext->globalPriority = in_ext->globalPriority; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkDeviceQueueCreateInfo *convert_VkDeviceQueueCreateInfo_array_win32_to_host(struct conversion_context *ctx, const VkDeviceQueueCreateInfo32 *in, uint32_t count) -{ - VkDeviceQueueCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkDeviceQueueCreateInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline const char * const*convert_char_pointer_array_win32_to_host(struct conversion_context *ctx, const PTR32 *in, uint32_t count) -{ - char **out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - out[i] = UlongToPtr(in[i]); - } - - return (void *)out; -} - -#ifdef _WIN64 -static inline void convert_VkDeviceCreateInfo_win64_to_host(struct conversion_context *ctx, const VkDeviceCreateInfo *in, VkDeviceCreateInfo *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->queueCreateInfoCount = in->queueCreateInfoCount; - out->pQueueCreateInfos = in->pQueueCreateInfos; - out->enabledLayerCount = in->enabledLayerCount; - out->ppEnabledLayerNames = in->ppEnabledLayerNames; - out->enabledExtensionCount = in->enabledExtensionCount; - out->ppEnabledExtensionNames = in->ppEnabledExtensionNames; - out->pEnabledFeatures = in->pEnabledFeatures; - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO: - break; - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV: - { - VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV *in_ext = (const VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->deviceGeneratedCommands = in_ext->deviceGeneratedCommands; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO: - { - VkDevicePrivateDataCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDevicePrivateDataCreateInfo *in_ext = (const VkDevicePrivateDataCreateInfo *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->privateDataSlotRequestCount = in_ext->privateDataSlotRequestCount; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES: - { - VkPhysicalDevicePrivateDataFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePrivateDataFeatures *in_ext = (const VkPhysicalDevicePrivateDataFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES; - out_ext->pNext = NULL; - out_ext->privateData = in_ext->privateData; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: - { - VkPhysicalDeviceFeatures2 *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFeatures2 *in_ext = (const VkPhysicalDeviceFeatures2 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - out_ext->pNext = NULL; - out_ext->features = in_ext->features; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES: - { - VkPhysicalDeviceVariablePointersFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVariablePointersFeatures *in_ext = (const VkPhysicalDeviceVariablePointersFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES; - out_ext->pNext = NULL; - out_ext->variablePointersStorageBuffer = in_ext->variablePointersStorageBuffer; - out_ext->variablePointers = in_ext->variablePointers; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: - { - VkPhysicalDeviceMultiviewFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMultiviewFeatures *in_ext = (const VkPhysicalDeviceMultiviewFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; - out_ext->pNext = NULL; - out_ext->multiview = in_ext->multiview; - out_ext->multiviewGeometryShader = in_ext->multiviewGeometryShader; - out_ext->multiviewTessellationShader = in_ext->multiviewTessellationShader; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO: - { - VkDeviceGroupDeviceCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDeviceGroupDeviceCreateInfo *in_ext = (const VkDeviceGroupDeviceCreateInfo *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->physicalDeviceCount = in_ext->physicalDeviceCount; - out_ext->pPhysicalDevices = convert_VkPhysicalDevice_array_win64_to_host(ctx, in_ext->pPhysicalDevices, in_ext->physicalDeviceCount); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR: - { - VkPhysicalDevicePresentIdFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePresentIdFeaturesKHR *in_ext = (const VkPhysicalDevicePresentIdFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->presentId = in_ext->presentId; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR: - { - VkPhysicalDevicePresentWaitFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePresentWaitFeaturesKHR *in_ext = (const VkPhysicalDevicePresentWaitFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->presentWait = in_ext->presentWait; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: - { - VkPhysicalDevice16BitStorageFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevice16BitStorageFeatures *in_ext = (const VkPhysicalDevice16BitStorageFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES; - out_ext->pNext = NULL; - out_ext->storageBuffer16BitAccess = in_ext->storageBuffer16BitAccess; - out_ext->uniformAndStorageBuffer16BitAccess = in_ext->uniformAndStorageBuffer16BitAccess; - out_ext->storagePushConstant16 = in_ext->storagePushConstant16; - out_ext->storageInputOutput16 = in_ext->storageInputOutput16; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES: - { - VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures *in_ext = (const VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderSubgroupExtendedTypes = in_ext->shaderSubgroupExtendedTypes; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: - { - VkPhysicalDeviceSamplerYcbcrConversionFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSamplerYcbcrConversionFeatures *in_ext = (const VkPhysicalDeviceSamplerYcbcrConversionFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES; - out_ext->pNext = NULL; - out_ext->samplerYcbcrConversion = in_ext->samplerYcbcrConversion; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES: - { - VkPhysicalDeviceProtectedMemoryFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceProtectedMemoryFeatures *in_ext = (const VkPhysicalDeviceProtectedMemoryFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES; - out_ext->pNext = NULL; - out_ext->protectedMemory = in_ext->protectedMemory; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT: - { - VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT *in_ext = (const VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->advancedBlendCoherentOperations = in_ext->advancedBlendCoherentOperations; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT: - { - VkPhysicalDeviceMultiDrawFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMultiDrawFeaturesEXT *in_ext = (const VkPhysicalDeviceMultiDrawFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->multiDraw = in_ext->multiDraw; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES: - { - VkPhysicalDeviceInlineUniformBlockFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceInlineUniformBlockFeatures *in_ext = (const VkPhysicalDeviceInlineUniformBlockFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES; - out_ext->pNext = NULL; - out_ext->inlineUniformBlock = in_ext->inlineUniformBlock; - out_ext->descriptorBindingInlineUniformBlockUpdateAfterBind = in_ext->descriptorBindingInlineUniformBlockUpdateAfterBind; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES: - { - VkPhysicalDeviceMaintenance4Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMaintenance4Features *in_ext = (const VkPhysicalDeviceMaintenance4Features *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES; - out_ext->pNext = NULL; - out_ext->maintenance4 = in_ext->maintenance4; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES: - { - VkPhysicalDeviceShaderDrawParametersFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderDrawParametersFeatures *in_ext = (const VkPhysicalDeviceShaderDrawParametersFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderDrawParameters = in_ext->shaderDrawParameters; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES: - { - VkPhysicalDeviceShaderFloat16Int8Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderFloat16Int8Features *in_ext = (const VkPhysicalDeviceShaderFloat16Int8Features *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderFloat16 = in_ext->shaderFloat16; - out_ext->shaderInt8 = in_ext->shaderInt8; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES: - { - VkPhysicalDeviceHostQueryResetFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceHostQueryResetFeatures *in_ext = (const VkPhysicalDeviceHostQueryResetFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES; - out_ext->pNext = NULL; - out_ext->hostQueryReset = in_ext->hostQueryReset; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR: - { - VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR *in_ext = (const VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->globalPriorityQuery = in_ext->globalPriorityQuery; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES: - { - VkPhysicalDeviceDescriptorIndexingFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDescriptorIndexingFeatures *in_ext = (const VkPhysicalDeviceDescriptorIndexingFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderInputAttachmentArrayDynamicIndexing = in_ext->shaderInputAttachmentArrayDynamicIndexing; - out_ext->shaderUniformTexelBufferArrayDynamicIndexing = in_ext->shaderUniformTexelBufferArrayDynamicIndexing; - out_ext->shaderStorageTexelBufferArrayDynamicIndexing = in_ext->shaderStorageTexelBufferArrayDynamicIndexing; - out_ext->shaderUniformBufferArrayNonUniformIndexing = in_ext->shaderUniformBufferArrayNonUniformIndexing; - out_ext->shaderSampledImageArrayNonUniformIndexing = in_ext->shaderSampledImageArrayNonUniformIndexing; - out_ext->shaderStorageBufferArrayNonUniformIndexing = in_ext->shaderStorageBufferArrayNonUniformIndexing; - out_ext->shaderStorageImageArrayNonUniformIndexing = in_ext->shaderStorageImageArrayNonUniformIndexing; - out_ext->shaderInputAttachmentArrayNonUniformIndexing = in_ext->shaderInputAttachmentArrayNonUniformIndexing; - out_ext->shaderUniformTexelBufferArrayNonUniformIndexing = in_ext->shaderUniformTexelBufferArrayNonUniformIndexing; - out_ext->shaderStorageTexelBufferArrayNonUniformIndexing = in_ext->shaderStorageTexelBufferArrayNonUniformIndexing; - out_ext->descriptorBindingUniformBufferUpdateAfterBind = in_ext->descriptorBindingUniformBufferUpdateAfterBind; - out_ext->descriptorBindingSampledImageUpdateAfterBind = in_ext->descriptorBindingSampledImageUpdateAfterBind; - out_ext->descriptorBindingStorageImageUpdateAfterBind = in_ext->descriptorBindingStorageImageUpdateAfterBind; - out_ext->descriptorBindingStorageBufferUpdateAfterBind = in_ext->descriptorBindingStorageBufferUpdateAfterBind; - out_ext->descriptorBindingUniformTexelBufferUpdateAfterBind = in_ext->descriptorBindingUniformTexelBufferUpdateAfterBind; - out_ext->descriptorBindingStorageTexelBufferUpdateAfterBind = in_ext->descriptorBindingStorageTexelBufferUpdateAfterBind; - out_ext->descriptorBindingUpdateUnusedWhilePending = in_ext->descriptorBindingUpdateUnusedWhilePending; - out_ext->descriptorBindingPartiallyBound = in_ext->descriptorBindingPartiallyBound; - out_ext->descriptorBindingVariableDescriptorCount = in_ext->descriptorBindingVariableDescriptorCount; - out_ext->runtimeDescriptorArray = in_ext->runtimeDescriptorArray; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES: - { - VkPhysicalDeviceTimelineSemaphoreFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceTimelineSemaphoreFeatures *in_ext = (const VkPhysicalDeviceTimelineSemaphoreFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES; - out_ext->pNext = NULL; - out_ext->timelineSemaphore = in_ext->timelineSemaphore; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES: - { - VkPhysicalDevice8BitStorageFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevice8BitStorageFeatures *in_ext = (const VkPhysicalDevice8BitStorageFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES; - out_ext->pNext = NULL; - out_ext->storageBuffer8BitAccess = in_ext->storageBuffer8BitAccess; - out_ext->uniformAndStorageBuffer8BitAccess = in_ext->uniformAndStorageBuffer8BitAccess; - out_ext->storagePushConstant8 = in_ext->storagePushConstant8; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT: - { - VkPhysicalDeviceConditionalRenderingFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceConditionalRenderingFeaturesEXT *in_ext = (const VkPhysicalDeviceConditionalRenderingFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->conditionalRendering = in_ext->conditionalRendering; - out_ext->inheritedConditionalRendering = in_ext->inheritedConditionalRendering; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES: - { - VkPhysicalDeviceVulkanMemoryModelFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVulkanMemoryModelFeatures *in_ext = (const VkPhysicalDeviceVulkanMemoryModelFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES; - out_ext->pNext = NULL; - out_ext->vulkanMemoryModel = in_ext->vulkanMemoryModel; - out_ext->vulkanMemoryModelDeviceScope = in_ext->vulkanMemoryModelDeviceScope; - out_ext->vulkanMemoryModelAvailabilityVisibilityChains = in_ext->vulkanMemoryModelAvailabilityVisibilityChains; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES: - { - VkPhysicalDeviceShaderAtomicInt64Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderAtomicInt64Features *in_ext = (const VkPhysicalDeviceShaderAtomicInt64Features *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderBufferInt64Atomics = in_ext->shaderBufferInt64Atomics; - out_ext->shaderSharedInt64Atomics = in_ext->shaderSharedInt64Atomics; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT: - { - VkPhysicalDeviceShaderAtomicFloatFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderAtomicFloatFeaturesEXT *in_ext = (const VkPhysicalDeviceShaderAtomicFloatFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->shaderBufferFloat32Atomics = in_ext->shaderBufferFloat32Atomics; - out_ext->shaderBufferFloat32AtomicAdd = in_ext->shaderBufferFloat32AtomicAdd; - out_ext->shaderBufferFloat64Atomics = in_ext->shaderBufferFloat64Atomics; - out_ext->shaderBufferFloat64AtomicAdd = in_ext->shaderBufferFloat64AtomicAdd; - out_ext->shaderSharedFloat32Atomics = in_ext->shaderSharedFloat32Atomics; - out_ext->shaderSharedFloat32AtomicAdd = in_ext->shaderSharedFloat32AtomicAdd; - out_ext->shaderSharedFloat64Atomics = in_ext->shaderSharedFloat64Atomics; - out_ext->shaderSharedFloat64AtomicAdd = in_ext->shaderSharedFloat64AtomicAdd; - out_ext->shaderImageFloat32Atomics = in_ext->shaderImageFloat32Atomics; - out_ext->shaderImageFloat32AtomicAdd = in_ext->shaderImageFloat32AtomicAdd; - out_ext->sparseImageFloat32Atomics = in_ext->sparseImageFloat32Atomics; - out_ext->sparseImageFloat32AtomicAdd = in_ext->sparseImageFloat32AtomicAdd; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT: - { - VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT *in_ext = (const VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->shaderBufferFloat16Atomics = in_ext->shaderBufferFloat16Atomics; - out_ext->shaderBufferFloat16AtomicAdd = in_ext->shaderBufferFloat16AtomicAdd; - out_ext->shaderBufferFloat16AtomicMinMax = in_ext->shaderBufferFloat16AtomicMinMax; - out_ext->shaderBufferFloat32AtomicMinMax = in_ext->shaderBufferFloat32AtomicMinMax; - out_ext->shaderBufferFloat64AtomicMinMax = in_ext->shaderBufferFloat64AtomicMinMax; - out_ext->shaderSharedFloat16Atomics = in_ext->shaderSharedFloat16Atomics; - out_ext->shaderSharedFloat16AtomicAdd = in_ext->shaderSharedFloat16AtomicAdd; - out_ext->shaderSharedFloat16AtomicMinMax = in_ext->shaderSharedFloat16AtomicMinMax; - out_ext->shaderSharedFloat32AtomicMinMax = in_ext->shaderSharedFloat32AtomicMinMax; - out_ext->shaderSharedFloat64AtomicMinMax = in_ext->shaderSharedFloat64AtomicMinMax; - out_ext->shaderImageFloat32AtomicMinMax = in_ext->shaderImageFloat32AtomicMinMax; - out_ext->sparseImageFloat32AtomicMinMax = in_ext->sparseImageFloat32AtomicMinMax; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT: - { - VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *in_ext = (const VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->vertexAttributeInstanceRateDivisor = in_ext->vertexAttributeInstanceRateDivisor; - out_ext->vertexAttributeInstanceRateZeroDivisor = in_ext->vertexAttributeInstanceRateZeroDivisor; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT: - { - VkPhysicalDeviceASTCDecodeFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceASTCDecodeFeaturesEXT *in_ext = (const VkPhysicalDeviceASTCDecodeFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->decodeModeSharedExponent = in_ext->decodeModeSharedExponent; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT: - { - VkPhysicalDeviceTransformFeedbackFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceTransformFeedbackFeaturesEXT *in_ext = (const VkPhysicalDeviceTransformFeedbackFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->transformFeedback = in_ext->transformFeedback; - out_ext->geometryStreams = in_ext->geometryStreams; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV: - { - VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV *in_ext = (const VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->representativeFragmentTest = in_ext->representativeFragmentTest; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV: - { - VkPhysicalDeviceExclusiveScissorFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceExclusiveScissorFeaturesNV *in_ext = (const VkPhysicalDeviceExclusiveScissorFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->exclusiveScissor = in_ext->exclusiveScissor; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV: - { - VkPhysicalDeviceCornerSampledImageFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCornerSampledImageFeaturesNV *in_ext = (const VkPhysicalDeviceCornerSampledImageFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->cornerSampledImage = in_ext->cornerSampledImage; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV: - { - VkPhysicalDeviceComputeShaderDerivativesFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceComputeShaderDerivativesFeaturesNV *in_ext = (const VkPhysicalDeviceComputeShaderDerivativesFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->computeDerivativeGroupQuads = in_ext->computeDerivativeGroupQuads; - out_ext->computeDerivativeGroupLinear = in_ext->computeDerivativeGroupLinear; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV: - { - VkPhysicalDeviceShaderImageFootprintFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderImageFootprintFeaturesNV *in_ext = (const VkPhysicalDeviceShaderImageFootprintFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->imageFootprint = in_ext->imageFootprint; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV: - { - VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV *in_ext = (const VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->dedicatedAllocationImageAliasing = in_ext->dedicatedAllocationImageAliasing; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_NV: - { - VkPhysicalDeviceCopyMemoryIndirectFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCopyMemoryIndirectFeaturesNV *in_ext = (const VkPhysicalDeviceCopyMemoryIndirectFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->indirectCopy = in_ext->indirectCopy; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_NV: - { - VkPhysicalDeviceMemoryDecompressionFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMemoryDecompressionFeaturesNV *in_ext = (const VkPhysicalDeviceMemoryDecompressionFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->memoryDecompression = in_ext->memoryDecompression; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV: - { - VkPhysicalDeviceShadingRateImageFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShadingRateImageFeaturesNV *in_ext = (const VkPhysicalDeviceShadingRateImageFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->shadingRateImage = in_ext->shadingRateImage; - out_ext->shadingRateCoarseSampleOrder = in_ext->shadingRateCoarseSampleOrder; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI: - { - VkPhysicalDeviceInvocationMaskFeaturesHUAWEI *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceInvocationMaskFeaturesHUAWEI *in_ext = (const VkPhysicalDeviceInvocationMaskFeaturesHUAWEI *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI; - out_ext->pNext = NULL; - out_ext->invocationMask = in_ext->invocationMask; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV: - { - VkPhysicalDeviceMeshShaderFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMeshShaderFeaturesNV *in_ext = (const VkPhysicalDeviceMeshShaderFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->taskShader = in_ext->taskShader; - out_ext->meshShader = in_ext->meshShader; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT: - { - VkPhysicalDeviceMeshShaderFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMeshShaderFeaturesEXT *in_ext = (const VkPhysicalDeviceMeshShaderFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->taskShader = in_ext->taskShader; - out_ext->meshShader = in_ext->meshShader; - out_ext->multiviewMeshShader = in_ext->multiviewMeshShader; - out_ext->primitiveFragmentShadingRateMeshShader = in_ext->primitiveFragmentShadingRateMeshShader; - out_ext->meshShaderQueries = in_ext->meshShaderQueries; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR: - { - VkPhysicalDeviceAccelerationStructureFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceAccelerationStructureFeaturesKHR *in_ext = (const VkPhysicalDeviceAccelerationStructureFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->accelerationStructure = in_ext->accelerationStructure; - out_ext->accelerationStructureCaptureReplay = in_ext->accelerationStructureCaptureReplay; - out_ext->accelerationStructureIndirectBuild = in_ext->accelerationStructureIndirectBuild; - out_ext->accelerationStructureHostCommands = in_ext->accelerationStructureHostCommands; - out_ext->descriptorBindingAccelerationStructureUpdateAfterBind = in_ext->descriptorBindingAccelerationStructureUpdateAfterBind; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR: - { - VkPhysicalDeviceRayTracingPipelineFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRayTracingPipelineFeaturesKHR *in_ext = (const VkPhysicalDeviceRayTracingPipelineFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->rayTracingPipeline = in_ext->rayTracingPipeline; - out_ext->rayTracingPipelineShaderGroupHandleCaptureReplay = in_ext->rayTracingPipelineShaderGroupHandleCaptureReplay; - out_ext->rayTracingPipelineShaderGroupHandleCaptureReplayMixed = in_ext->rayTracingPipelineShaderGroupHandleCaptureReplayMixed; - out_ext->rayTracingPipelineTraceRaysIndirect = in_ext->rayTracingPipelineTraceRaysIndirect; - out_ext->rayTraversalPrimitiveCulling = in_ext->rayTraversalPrimitiveCulling; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR: - { - VkPhysicalDeviceRayQueryFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRayQueryFeaturesKHR *in_ext = (const VkPhysicalDeviceRayQueryFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->rayQuery = in_ext->rayQuery; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR: - { - VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR *in_ext = (const VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->rayTracingMaintenance1 = in_ext->rayTracingMaintenance1; - out_ext->rayTracingPipelineTraceRaysIndirect2 = in_ext->rayTracingPipelineTraceRaysIndirect2; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD: - { - VkDeviceMemoryOverallocationCreateInfoAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDeviceMemoryOverallocationCreateInfoAMD *in_ext = (const VkDeviceMemoryOverallocationCreateInfoAMD *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD; - out_ext->pNext = NULL; - out_ext->overallocationBehavior = in_ext->overallocationBehavior; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT: - { - VkPhysicalDeviceFragmentDensityMapFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentDensityMapFeaturesEXT *in_ext = (const VkPhysicalDeviceFragmentDensityMapFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->fragmentDensityMap = in_ext->fragmentDensityMap; - out_ext->fragmentDensityMapDynamic = in_ext->fragmentDensityMapDynamic; - out_ext->fragmentDensityMapNonSubsampledImages = in_ext->fragmentDensityMapNonSubsampledImages; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT: - { - VkPhysicalDeviceFragmentDensityMap2FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentDensityMap2FeaturesEXT *in_ext = (const VkPhysicalDeviceFragmentDensityMap2FeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->fragmentDensityMapDeferred = in_ext->fragmentDensityMapDeferred; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM: - { - VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM *in_ext = (const VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM; - out_ext->pNext = NULL; - out_ext->fragmentDensityMapOffset = in_ext->fragmentDensityMapOffset; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES: - { - VkPhysicalDeviceScalarBlockLayoutFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceScalarBlockLayoutFeatures *in_ext = (const VkPhysicalDeviceScalarBlockLayoutFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES; - out_ext->pNext = NULL; - out_ext->scalarBlockLayout = in_ext->scalarBlockLayout; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES: - { - VkPhysicalDeviceUniformBufferStandardLayoutFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceUniformBufferStandardLayoutFeatures *in_ext = (const VkPhysicalDeviceUniformBufferStandardLayoutFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES; - out_ext->pNext = NULL; - out_ext->uniformBufferStandardLayout = in_ext->uniformBufferStandardLayout; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT: - { - VkPhysicalDeviceDepthClipEnableFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDepthClipEnableFeaturesEXT *in_ext = (const VkPhysicalDeviceDepthClipEnableFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->depthClipEnable = in_ext->depthClipEnable; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT: - { - VkPhysicalDeviceMemoryPriorityFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMemoryPriorityFeaturesEXT *in_ext = (const VkPhysicalDeviceMemoryPriorityFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->memoryPriority = in_ext->memoryPriority; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT: - { - VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT *in_ext = (const VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->pageableDeviceLocalMemory = in_ext->pageableDeviceLocalMemory; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES: - { - VkPhysicalDeviceBufferDeviceAddressFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceBufferDeviceAddressFeatures *in_ext = (const VkPhysicalDeviceBufferDeviceAddressFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES; - out_ext->pNext = NULL; - out_ext->bufferDeviceAddress = in_ext->bufferDeviceAddress; - out_ext->bufferDeviceAddressCaptureReplay = in_ext->bufferDeviceAddressCaptureReplay; - out_ext->bufferDeviceAddressMultiDevice = in_ext->bufferDeviceAddressMultiDevice; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT: - { - VkPhysicalDeviceBufferDeviceAddressFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceBufferDeviceAddressFeaturesEXT *in_ext = (const VkPhysicalDeviceBufferDeviceAddressFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->bufferDeviceAddress = in_ext->bufferDeviceAddress; - out_ext->bufferDeviceAddressCaptureReplay = in_ext->bufferDeviceAddressCaptureReplay; - out_ext->bufferDeviceAddressMultiDevice = in_ext->bufferDeviceAddressMultiDevice; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES: - { - VkPhysicalDeviceImagelessFramebufferFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImagelessFramebufferFeatures *in_ext = (const VkPhysicalDeviceImagelessFramebufferFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES; - out_ext->pNext = NULL; - out_ext->imagelessFramebuffer = in_ext->imagelessFramebuffer; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES: - { - VkPhysicalDeviceTextureCompressionASTCHDRFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceTextureCompressionASTCHDRFeatures *in_ext = (const VkPhysicalDeviceTextureCompressionASTCHDRFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES; - out_ext->pNext = NULL; - out_ext->textureCompressionASTC_HDR = in_ext->textureCompressionASTC_HDR; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV: - { - VkPhysicalDeviceCooperativeMatrixFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCooperativeMatrixFeaturesNV *in_ext = (const VkPhysicalDeviceCooperativeMatrixFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->cooperativeMatrix = in_ext->cooperativeMatrix; - out_ext->cooperativeMatrixRobustBufferAccess = in_ext->cooperativeMatrixRobustBufferAccess; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT: - { - VkPhysicalDeviceYcbcrImageArraysFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceYcbcrImageArraysFeaturesEXT *in_ext = (const VkPhysicalDeviceYcbcrImageArraysFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->ycbcrImageArrays = in_ext->ycbcrImageArrays; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_BARRIER_FEATURES_NV: - { - VkPhysicalDevicePresentBarrierFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePresentBarrierFeaturesNV *in_ext = (const VkPhysicalDevicePresentBarrierFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_BARRIER_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->presentBarrier = in_ext->presentBarrier; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR: - { - VkPhysicalDevicePerformanceQueryFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePerformanceQueryFeaturesKHR *in_ext = (const VkPhysicalDevicePerformanceQueryFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->performanceCounterQueryPools = in_ext->performanceCounterQueryPools; - out_ext->performanceCounterMultipleQueryPools = in_ext->performanceCounterMultipleQueryPools; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV: - { - VkPhysicalDeviceCoverageReductionModeFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCoverageReductionModeFeaturesNV *in_ext = (const VkPhysicalDeviceCoverageReductionModeFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->coverageReductionMode = in_ext->coverageReductionMode; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL: - { - VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL *in_ext = (const VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL; - out_ext->pNext = NULL; - out_ext->shaderIntegerFunctions2 = in_ext->shaderIntegerFunctions2; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR: - { - VkPhysicalDeviceShaderClockFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderClockFeaturesKHR *in_ext = (const VkPhysicalDeviceShaderClockFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->shaderSubgroupClock = in_ext->shaderSubgroupClock; - out_ext->shaderDeviceClock = in_ext->shaderDeviceClock; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT: - { - VkPhysicalDeviceIndexTypeUint8FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceIndexTypeUint8FeaturesEXT *in_ext = (const VkPhysicalDeviceIndexTypeUint8FeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->indexTypeUint8 = in_ext->indexTypeUint8; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV: - { - VkPhysicalDeviceShaderSMBuiltinsFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderSMBuiltinsFeaturesNV *in_ext = (const VkPhysicalDeviceShaderSMBuiltinsFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->shaderSMBuiltins = in_ext->shaderSMBuiltins; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: - { - VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT *in_ext = (const VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->fragmentShaderSampleInterlock = in_ext->fragmentShaderSampleInterlock; - out_ext->fragmentShaderPixelInterlock = in_ext->fragmentShaderPixelInterlock; - out_ext->fragmentShaderShadingRateInterlock = in_ext->fragmentShaderShadingRateInterlock; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES: - { - VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures *in_ext = (const VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES; - out_ext->pNext = NULL; - out_ext->separateDepthStencilLayouts = in_ext->separateDepthStencilLayouts; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT: - { - VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *in_ext = (const VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->primitiveTopologyListRestart = in_ext->primitiveTopologyListRestart; - out_ext->primitiveTopologyPatchListRestart = in_ext->primitiveTopologyPatchListRestart; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR: - { - VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR *in_ext = (const VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->pipelineExecutableInfo = in_ext->pipelineExecutableInfo; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES: - { - VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures *in_ext = (const VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderDemoteToHelperInvocation = in_ext->shaderDemoteToHelperInvocation; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT: - { - VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT *in_ext = (const VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->texelBufferAlignment = in_ext->texelBufferAlignment; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES: - { - VkPhysicalDeviceSubgroupSizeControlFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSubgroupSizeControlFeatures *in_ext = (const VkPhysicalDeviceSubgroupSizeControlFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES; - out_ext->pNext = NULL; - out_ext->subgroupSizeControl = in_ext->subgroupSizeControl; - out_ext->computeFullSubgroups = in_ext->computeFullSubgroups; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT: - { - VkPhysicalDeviceLineRasterizationFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceLineRasterizationFeaturesEXT *in_ext = (const VkPhysicalDeviceLineRasterizationFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->rectangularLines = in_ext->rectangularLines; - out_ext->bresenhamLines = in_ext->bresenhamLines; - out_ext->smoothLines = in_ext->smoothLines; - out_ext->stippledRectangularLines = in_ext->stippledRectangularLines; - out_ext->stippledBresenhamLines = in_ext->stippledBresenhamLines; - out_ext->stippledSmoothLines = in_ext->stippledSmoothLines; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES: - { - VkPhysicalDevicePipelineCreationCacheControlFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePipelineCreationCacheControlFeatures *in_ext = (const VkPhysicalDevicePipelineCreationCacheControlFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES; - out_ext->pNext = NULL; - out_ext->pipelineCreationCacheControl = in_ext->pipelineCreationCacheControl; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES: - { - VkPhysicalDeviceVulkan11Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVulkan11Features *in_ext = (const VkPhysicalDeviceVulkan11Features *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; - out_ext->pNext = NULL; - out_ext->storageBuffer16BitAccess = in_ext->storageBuffer16BitAccess; - out_ext->uniformAndStorageBuffer16BitAccess = in_ext->uniformAndStorageBuffer16BitAccess; - out_ext->storagePushConstant16 = in_ext->storagePushConstant16; - out_ext->storageInputOutput16 = in_ext->storageInputOutput16; - out_ext->multiview = in_ext->multiview; - out_ext->multiviewGeometryShader = in_ext->multiviewGeometryShader; - out_ext->multiviewTessellationShader = in_ext->multiviewTessellationShader; - out_ext->variablePointersStorageBuffer = in_ext->variablePointersStorageBuffer; - out_ext->variablePointers = in_ext->variablePointers; - out_ext->protectedMemory = in_ext->protectedMemory; - out_ext->samplerYcbcrConversion = in_ext->samplerYcbcrConversion; - out_ext->shaderDrawParameters = in_ext->shaderDrawParameters; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES: - { - VkPhysicalDeviceVulkan12Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVulkan12Features *in_ext = (const VkPhysicalDeviceVulkan12Features *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; - out_ext->pNext = NULL; - out_ext->samplerMirrorClampToEdge = in_ext->samplerMirrorClampToEdge; - out_ext->drawIndirectCount = in_ext->drawIndirectCount; - out_ext->storageBuffer8BitAccess = in_ext->storageBuffer8BitAccess; - out_ext->uniformAndStorageBuffer8BitAccess = in_ext->uniformAndStorageBuffer8BitAccess; - out_ext->storagePushConstant8 = in_ext->storagePushConstant8; - out_ext->shaderBufferInt64Atomics = in_ext->shaderBufferInt64Atomics; - out_ext->shaderSharedInt64Atomics = in_ext->shaderSharedInt64Atomics; - out_ext->shaderFloat16 = in_ext->shaderFloat16; - out_ext->shaderInt8 = in_ext->shaderInt8; - out_ext->descriptorIndexing = in_ext->descriptorIndexing; - out_ext->shaderInputAttachmentArrayDynamicIndexing = in_ext->shaderInputAttachmentArrayDynamicIndexing; - out_ext->shaderUniformTexelBufferArrayDynamicIndexing = in_ext->shaderUniformTexelBufferArrayDynamicIndexing; - out_ext->shaderStorageTexelBufferArrayDynamicIndexing = in_ext->shaderStorageTexelBufferArrayDynamicIndexing; - out_ext->shaderUniformBufferArrayNonUniformIndexing = in_ext->shaderUniformBufferArrayNonUniformIndexing; - out_ext->shaderSampledImageArrayNonUniformIndexing = in_ext->shaderSampledImageArrayNonUniformIndexing; - out_ext->shaderStorageBufferArrayNonUniformIndexing = in_ext->shaderStorageBufferArrayNonUniformIndexing; - out_ext->shaderStorageImageArrayNonUniformIndexing = in_ext->shaderStorageImageArrayNonUniformIndexing; - out_ext->shaderInputAttachmentArrayNonUniformIndexing = in_ext->shaderInputAttachmentArrayNonUniformIndexing; - out_ext->shaderUniformTexelBufferArrayNonUniformIndexing = in_ext->shaderUniformTexelBufferArrayNonUniformIndexing; - out_ext->shaderStorageTexelBufferArrayNonUniformIndexing = in_ext->shaderStorageTexelBufferArrayNonUniformIndexing; - out_ext->descriptorBindingUniformBufferUpdateAfterBind = in_ext->descriptorBindingUniformBufferUpdateAfterBind; - out_ext->descriptorBindingSampledImageUpdateAfterBind = in_ext->descriptorBindingSampledImageUpdateAfterBind; - out_ext->descriptorBindingStorageImageUpdateAfterBind = in_ext->descriptorBindingStorageImageUpdateAfterBind; - out_ext->descriptorBindingStorageBufferUpdateAfterBind = in_ext->descriptorBindingStorageBufferUpdateAfterBind; - out_ext->descriptorBindingUniformTexelBufferUpdateAfterBind = in_ext->descriptorBindingUniformTexelBufferUpdateAfterBind; - out_ext->descriptorBindingStorageTexelBufferUpdateAfterBind = in_ext->descriptorBindingStorageTexelBufferUpdateAfterBind; - out_ext->descriptorBindingUpdateUnusedWhilePending = in_ext->descriptorBindingUpdateUnusedWhilePending; - out_ext->descriptorBindingPartiallyBound = in_ext->descriptorBindingPartiallyBound; - out_ext->descriptorBindingVariableDescriptorCount = in_ext->descriptorBindingVariableDescriptorCount; - out_ext->runtimeDescriptorArray = in_ext->runtimeDescriptorArray; - out_ext->samplerFilterMinmax = in_ext->samplerFilterMinmax; - out_ext->scalarBlockLayout = in_ext->scalarBlockLayout; - out_ext->imagelessFramebuffer = in_ext->imagelessFramebuffer; - out_ext->uniformBufferStandardLayout = in_ext->uniformBufferStandardLayout; - out_ext->shaderSubgroupExtendedTypes = in_ext->shaderSubgroupExtendedTypes; - out_ext->separateDepthStencilLayouts = in_ext->separateDepthStencilLayouts; - out_ext->hostQueryReset = in_ext->hostQueryReset; - out_ext->timelineSemaphore = in_ext->timelineSemaphore; - out_ext->bufferDeviceAddress = in_ext->bufferDeviceAddress; - out_ext->bufferDeviceAddressCaptureReplay = in_ext->bufferDeviceAddressCaptureReplay; - out_ext->bufferDeviceAddressMultiDevice = in_ext->bufferDeviceAddressMultiDevice; - out_ext->vulkanMemoryModel = in_ext->vulkanMemoryModel; - out_ext->vulkanMemoryModelDeviceScope = in_ext->vulkanMemoryModelDeviceScope; - out_ext->vulkanMemoryModelAvailabilityVisibilityChains = in_ext->vulkanMemoryModelAvailabilityVisibilityChains; - out_ext->shaderOutputViewportIndex = in_ext->shaderOutputViewportIndex; - out_ext->shaderOutputLayer = in_ext->shaderOutputLayer; - out_ext->subgroupBroadcastDynamicId = in_ext->subgroupBroadcastDynamicId; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES: - { - VkPhysicalDeviceVulkan13Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVulkan13Features *in_ext = (const VkPhysicalDeviceVulkan13Features *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; - out_ext->pNext = NULL; - out_ext->robustImageAccess = in_ext->robustImageAccess; - out_ext->inlineUniformBlock = in_ext->inlineUniformBlock; - out_ext->descriptorBindingInlineUniformBlockUpdateAfterBind = in_ext->descriptorBindingInlineUniformBlockUpdateAfterBind; - out_ext->pipelineCreationCacheControl = in_ext->pipelineCreationCacheControl; - out_ext->privateData = in_ext->privateData; - out_ext->shaderDemoteToHelperInvocation = in_ext->shaderDemoteToHelperInvocation; - out_ext->shaderTerminateInvocation = in_ext->shaderTerminateInvocation; - out_ext->subgroupSizeControl = in_ext->subgroupSizeControl; - out_ext->computeFullSubgroups = in_ext->computeFullSubgroups; - out_ext->synchronization2 = in_ext->synchronization2; - out_ext->textureCompressionASTC_HDR = in_ext->textureCompressionASTC_HDR; - out_ext->shaderZeroInitializeWorkgroupMemory = in_ext->shaderZeroInitializeWorkgroupMemory; - out_ext->dynamicRendering = in_ext->dynamicRendering; - out_ext->shaderIntegerDotProduct = in_ext->shaderIntegerDotProduct; - out_ext->maintenance4 = in_ext->maintenance4; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD: - { - VkPhysicalDeviceCoherentMemoryFeaturesAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCoherentMemoryFeaturesAMD *in_ext = (const VkPhysicalDeviceCoherentMemoryFeaturesAMD *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD; - out_ext->pNext = NULL; - out_ext->deviceCoherentMemory = in_ext->deviceCoherentMemory; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT: - { - VkPhysicalDeviceCustomBorderColorFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCustomBorderColorFeaturesEXT *in_ext = (const VkPhysicalDeviceCustomBorderColorFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->customBorderColors = in_ext->customBorderColors; - out_ext->customBorderColorWithoutFormat = in_ext->customBorderColorWithoutFormat; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT: - { - VkPhysicalDeviceBorderColorSwizzleFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceBorderColorSwizzleFeaturesEXT *in_ext = (const VkPhysicalDeviceBorderColorSwizzleFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->borderColorSwizzle = in_ext->borderColorSwizzle; - out_ext->borderColorSwizzleFromImage = in_ext->borderColorSwizzleFromImage; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT: - { - VkPhysicalDeviceExtendedDynamicStateFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceExtendedDynamicStateFeaturesEXT *in_ext = (const VkPhysicalDeviceExtendedDynamicStateFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->extendedDynamicState = in_ext->extendedDynamicState; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT: - { - VkPhysicalDeviceExtendedDynamicState2FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceExtendedDynamicState2FeaturesEXT *in_ext = (const VkPhysicalDeviceExtendedDynamicState2FeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->extendedDynamicState2 = in_ext->extendedDynamicState2; - out_ext->extendedDynamicState2LogicOp = in_ext->extendedDynamicState2LogicOp; - out_ext->extendedDynamicState2PatchControlPoints = in_ext->extendedDynamicState2PatchControlPoints; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT: - { - VkPhysicalDeviceExtendedDynamicState3FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceExtendedDynamicState3FeaturesEXT *in_ext = (const VkPhysicalDeviceExtendedDynamicState3FeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->extendedDynamicState3TessellationDomainOrigin = in_ext->extendedDynamicState3TessellationDomainOrigin; - out_ext->extendedDynamicState3DepthClampEnable = in_ext->extendedDynamicState3DepthClampEnable; - out_ext->extendedDynamicState3PolygonMode = in_ext->extendedDynamicState3PolygonMode; - out_ext->extendedDynamicState3RasterizationSamples = in_ext->extendedDynamicState3RasterizationSamples; - out_ext->extendedDynamicState3SampleMask = in_ext->extendedDynamicState3SampleMask; - out_ext->extendedDynamicState3AlphaToCoverageEnable = in_ext->extendedDynamicState3AlphaToCoverageEnable; - out_ext->extendedDynamicState3AlphaToOneEnable = in_ext->extendedDynamicState3AlphaToOneEnable; - out_ext->extendedDynamicState3LogicOpEnable = in_ext->extendedDynamicState3LogicOpEnable; - out_ext->extendedDynamicState3ColorBlendEnable = in_ext->extendedDynamicState3ColorBlendEnable; - out_ext->extendedDynamicState3ColorBlendEquation = in_ext->extendedDynamicState3ColorBlendEquation; - out_ext->extendedDynamicState3ColorWriteMask = in_ext->extendedDynamicState3ColorWriteMask; - out_ext->extendedDynamicState3RasterizationStream = in_ext->extendedDynamicState3RasterizationStream; - out_ext->extendedDynamicState3ConservativeRasterizationMode = in_ext->extendedDynamicState3ConservativeRasterizationMode; - out_ext->extendedDynamicState3ExtraPrimitiveOverestimationSize = in_ext->extendedDynamicState3ExtraPrimitiveOverestimationSize; - out_ext->extendedDynamicState3DepthClipEnable = in_ext->extendedDynamicState3DepthClipEnable; - out_ext->extendedDynamicState3SampleLocationsEnable = in_ext->extendedDynamicState3SampleLocationsEnable; - out_ext->extendedDynamicState3ColorBlendAdvanced = in_ext->extendedDynamicState3ColorBlendAdvanced; - out_ext->extendedDynamicState3ProvokingVertexMode = in_ext->extendedDynamicState3ProvokingVertexMode; - out_ext->extendedDynamicState3LineRasterizationMode = in_ext->extendedDynamicState3LineRasterizationMode; - out_ext->extendedDynamicState3LineStippleEnable = in_ext->extendedDynamicState3LineStippleEnable; - out_ext->extendedDynamicState3DepthClipNegativeOneToOne = in_ext->extendedDynamicState3DepthClipNegativeOneToOne; - out_ext->extendedDynamicState3ViewportWScalingEnable = in_ext->extendedDynamicState3ViewportWScalingEnable; - out_ext->extendedDynamicState3ViewportSwizzle = in_ext->extendedDynamicState3ViewportSwizzle; - out_ext->extendedDynamicState3CoverageToColorEnable = in_ext->extendedDynamicState3CoverageToColorEnable; - out_ext->extendedDynamicState3CoverageToColorLocation = in_ext->extendedDynamicState3CoverageToColorLocation; - out_ext->extendedDynamicState3CoverageModulationMode = in_ext->extendedDynamicState3CoverageModulationMode; - out_ext->extendedDynamicState3CoverageModulationTableEnable = in_ext->extendedDynamicState3CoverageModulationTableEnable; - out_ext->extendedDynamicState3CoverageModulationTable = in_ext->extendedDynamicState3CoverageModulationTable; - out_ext->extendedDynamicState3CoverageReductionMode = in_ext->extendedDynamicState3CoverageReductionMode; - out_ext->extendedDynamicState3RepresentativeFragmentTestEnable = in_ext->extendedDynamicState3RepresentativeFragmentTestEnable; - out_ext->extendedDynamicState3ShadingRateImageEnable = in_ext->extendedDynamicState3ShadingRateImageEnable; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV: - { - VkPhysicalDeviceDiagnosticsConfigFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDiagnosticsConfigFeaturesNV *in_ext = (const VkPhysicalDeviceDiagnosticsConfigFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->diagnosticsConfig = in_ext->diagnosticsConfig; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV: - { - VkDeviceDiagnosticsConfigCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDeviceDiagnosticsConfigCreateInfoNV *in_ext = (const VkDeviceDiagnosticsConfigCreateInfoNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES: - { - VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures *in_ext = (const VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderZeroInitializeWorkgroupMemory = in_ext->shaderZeroInitializeWorkgroupMemory; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR: - { - VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR *in_ext = (const VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->shaderSubgroupUniformControlFlow = in_ext->shaderSubgroupUniformControlFlow; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT: - { - VkPhysicalDeviceRobustness2FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRobustness2FeaturesEXT *in_ext = (const VkPhysicalDeviceRobustness2FeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->robustBufferAccess2 = in_ext->robustBufferAccess2; - out_ext->robustImageAccess2 = in_ext->robustImageAccess2; - out_ext->nullDescriptor = in_ext->nullDescriptor; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES: - { - VkPhysicalDeviceImageRobustnessFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImageRobustnessFeatures *in_ext = (const VkPhysicalDeviceImageRobustnessFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES; - out_ext->pNext = NULL; - out_ext->robustImageAccess = in_ext->robustImageAccess; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR: - { - VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR *in_ext = (const VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->workgroupMemoryExplicitLayout = in_ext->workgroupMemoryExplicitLayout; - out_ext->workgroupMemoryExplicitLayoutScalarBlockLayout = in_ext->workgroupMemoryExplicitLayoutScalarBlockLayout; - out_ext->workgroupMemoryExplicitLayout8BitAccess = in_ext->workgroupMemoryExplicitLayout8BitAccess; - out_ext->workgroupMemoryExplicitLayout16BitAccess = in_ext->workgroupMemoryExplicitLayout16BitAccess; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT: - { - VkPhysicalDevice4444FormatsFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevice4444FormatsFeaturesEXT *in_ext = (const VkPhysicalDevice4444FormatsFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->formatA4R4G4B4 = in_ext->formatA4R4G4B4; - out_ext->formatA4B4G4R4 = in_ext->formatA4B4G4R4; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI: - { - VkPhysicalDeviceSubpassShadingFeaturesHUAWEI *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSubpassShadingFeaturesHUAWEI *in_ext = (const VkPhysicalDeviceSubpassShadingFeaturesHUAWEI *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI; - out_ext->pNext = NULL; - out_ext->subpassShading = in_ext->subpassShading; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT: - { - VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT *in_ext = (const VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->shaderImageInt64Atomics = in_ext->shaderImageInt64Atomics; - out_ext->sparseImageInt64Atomics = in_ext->sparseImageInt64Atomics; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR: - { - VkPhysicalDeviceFragmentShadingRateFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentShadingRateFeaturesKHR *in_ext = (const VkPhysicalDeviceFragmentShadingRateFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->pipelineFragmentShadingRate = in_ext->pipelineFragmentShadingRate; - out_ext->primitiveFragmentShadingRate = in_ext->primitiveFragmentShadingRate; - out_ext->attachmentFragmentShadingRate = in_ext->attachmentFragmentShadingRate; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES: - { - VkPhysicalDeviceShaderTerminateInvocationFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderTerminateInvocationFeatures *in_ext = (const VkPhysicalDeviceShaderTerminateInvocationFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderTerminateInvocation = in_ext->shaderTerminateInvocation; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV: - { - VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV *in_ext = (const VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->fragmentShadingRateEnums = in_ext->fragmentShadingRateEnums; - out_ext->supersampleFragmentShadingRates = in_ext->supersampleFragmentShadingRates; - out_ext->noInvocationFragmentShadingRates = in_ext->noInvocationFragmentShadingRates; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT: - { - VkPhysicalDeviceImage2DViewOf3DFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImage2DViewOf3DFeaturesEXT *in_ext = (const VkPhysicalDeviceImage2DViewOf3DFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->image2DViewOf3D = in_ext->image2DViewOf3D; - out_ext->sampler2DViewOf3D = in_ext->sampler2DViewOf3D; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT: - { - VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *in_ext = (const VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->mutableDescriptorType = in_ext->mutableDescriptorType; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT: - { - VkPhysicalDeviceDepthClipControlFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDepthClipControlFeaturesEXT *in_ext = (const VkPhysicalDeviceDepthClipControlFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->depthClipControl = in_ext->depthClipControl; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT: - { - VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT *in_ext = (const VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->vertexInputDynamicState = in_ext->vertexInputDynamicState; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: - { - VkPhysicalDeviceColorWriteEnableFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceColorWriteEnableFeaturesEXT *in_ext = (const VkPhysicalDeviceColorWriteEnableFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->colorWriteEnable = in_ext->colorWriteEnable; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES: - { - VkPhysicalDeviceSynchronization2Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSynchronization2Features *in_ext = (const VkPhysicalDeviceSynchronization2Features *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES; - out_ext->pNext = NULL; - out_ext->synchronization2 = in_ext->synchronization2; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT: - { - VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *in_ext = (const VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->primitivesGeneratedQuery = in_ext->primitivesGeneratedQuery; - out_ext->primitivesGeneratedQueryWithRasterizerDiscard = in_ext->primitivesGeneratedQueryWithRasterizerDiscard; - out_ext->primitivesGeneratedQueryWithNonZeroStreams = in_ext->primitivesGeneratedQueryWithNonZeroStreams; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT: - { - VkPhysicalDeviceLegacyDitheringFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceLegacyDitheringFeaturesEXT *in_ext = (const VkPhysicalDeviceLegacyDitheringFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->legacyDithering = in_ext->legacyDithering; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT: - { - VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT *in_ext = (const VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->multisampledRenderToSingleSampled = in_ext->multisampledRenderToSingleSampled; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT: - { - VkPhysicalDevicePipelineProtectedAccessFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePipelineProtectedAccessFeaturesEXT *in_ext = (const VkPhysicalDevicePipelineProtectedAccessFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->pipelineProtectedAccess = in_ext->pipelineProtectedAccess; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV: - { - VkPhysicalDeviceInheritedViewportScissorFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceInheritedViewportScissorFeaturesNV *in_ext = (const VkPhysicalDeviceInheritedViewportScissorFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->inheritedViewportScissor2D = in_ext->inheritedViewportScissor2D; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT: - { - VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT *in_ext = (const VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->ycbcr2plane444Formats = in_ext->ycbcr2plane444Formats; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT: - { - VkPhysicalDeviceProvokingVertexFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceProvokingVertexFeaturesEXT *in_ext = (const VkPhysicalDeviceProvokingVertexFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->provokingVertexLast = in_ext->provokingVertexLast; - out_ext->transformFeedbackPreservesProvokingVertex = in_ext->transformFeedbackPreservesProvokingVertex; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT: - { - VkPhysicalDeviceDescriptorBufferFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDescriptorBufferFeaturesEXT *in_ext = (const VkPhysicalDeviceDescriptorBufferFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->descriptorBuffer = in_ext->descriptorBuffer; - out_ext->descriptorBufferCaptureReplay = in_ext->descriptorBufferCaptureReplay; - out_ext->descriptorBufferImageLayoutIgnored = in_ext->descriptorBufferImageLayoutIgnored; - out_ext->descriptorBufferPushDescriptors = in_ext->descriptorBufferPushDescriptors; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES: - { - VkPhysicalDeviceShaderIntegerDotProductFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderIntegerDotProductFeatures *in_ext = (const VkPhysicalDeviceShaderIntegerDotProductFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderIntegerDotProduct = in_ext->shaderIntegerDotProduct; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR: - { - VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR *in_ext = (const VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->fragmentShaderBarycentric = in_ext->fragmentShaderBarycentric; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV: - { - VkPhysicalDeviceRayTracingMotionBlurFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRayTracingMotionBlurFeaturesNV *in_ext = (const VkPhysicalDeviceRayTracingMotionBlurFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->rayTracingMotionBlur = in_ext->rayTracingMotionBlur; - out_ext->rayTracingMotionBlurPipelineTraceRaysIndirect = in_ext->rayTracingMotionBlurPipelineTraceRaysIndirect; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT: - { - VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT *in_ext = (const VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->formatRgba10x6WithoutYCbCrSampler = in_ext->formatRgba10x6WithoutYCbCrSampler; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES: - { - VkPhysicalDeviceDynamicRenderingFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDynamicRenderingFeatures *in_ext = (const VkPhysicalDeviceDynamicRenderingFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES; - out_ext->pNext = NULL; - out_ext->dynamicRendering = in_ext->dynamicRendering; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT: - { - VkPhysicalDeviceImageViewMinLodFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImageViewMinLodFeaturesEXT *in_ext = (const VkPhysicalDeviceImageViewMinLodFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->minLod = in_ext->minLod; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT: - { - VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT *in_ext = (const VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->rasterizationOrderColorAttachmentAccess = in_ext->rasterizationOrderColorAttachmentAccess; - out_ext->rasterizationOrderDepthAttachmentAccess = in_ext->rasterizationOrderDepthAttachmentAccess; - out_ext->rasterizationOrderStencilAttachmentAccess = in_ext->rasterizationOrderStencilAttachmentAccess; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV: - { - VkPhysicalDeviceLinearColorAttachmentFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceLinearColorAttachmentFeaturesNV *in_ext = (const VkPhysicalDeviceLinearColorAttachmentFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->linearColorAttachment = in_ext->linearColorAttachment; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT: - { - VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT *in_ext = (const VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->graphicsPipelineLibrary = in_ext->graphicsPipelineLibrary; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE: - { - VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE *in_ext = (const VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE; - out_ext->pNext = NULL; - out_ext->descriptorSetHostMapping = in_ext->descriptorSetHostMapping; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT: - { - VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT *in_ext = (const VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->shaderModuleIdentifier = in_ext->shaderModuleIdentifier; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT: - { - VkPhysicalDeviceImageCompressionControlFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImageCompressionControlFeaturesEXT *in_ext = (const VkPhysicalDeviceImageCompressionControlFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->imageCompressionControl = in_ext->imageCompressionControl; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT: - { - VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT *in_ext = (const VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->imageCompressionControlSwapchain = in_ext->imageCompressionControlSwapchain; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT: - { - VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT *in_ext = (const VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->subpassMergeFeedback = in_ext->subpassMergeFeedback; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_EXT: - { - VkPhysicalDeviceOpacityMicromapFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceOpacityMicromapFeaturesEXT *in_ext = (const VkPhysicalDeviceOpacityMicromapFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->micromap = in_ext->micromap; - out_ext->micromapCaptureReplay = in_ext->micromapCaptureReplay; - out_ext->micromapHostCommands = in_ext->micromapHostCommands; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT: - { - VkPhysicalDevicePipelinePropertiesFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePipelinePropertiesFeaturesEXT *in_ext = (const VkPhysicalDevicePipelinePropertiesFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->pipelinePropertiesIdentifier = in_ext->pipelinePropertiesIdentifier; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD: - { - VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD *in_ext = (const VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD; - out_ext->pNext = NULL; - out_ext->shaderEarlyAndLateFragmentTests = in_ext->shaderEarlyAndLateFragmentTests; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT: - { - VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT *in_ext = (const VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->nonSeamlessCubeMap = in_ext->nonSeamlessCubeMap; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT: - { - VkPhysicalDevicePipelineRobustnessFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePipelineRobustnessFeaturesEXT *in_ext = (const VkPhysicalDevicePipelineRobustnessFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->pipelineRobustness = in_ext->pipelineRobustness; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM: - { - VkPhysicalDeviceImageProcessingFeaturesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImageProcessingFeaturesQCOM *in_ext = (const VkPhysicalDeviceImageProcessingFeaturesQCOM *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM; - out_ext->pNext = NULL; - out_ext->textureSampleWeighted = in_ext->textureSampleWeighted; - out_ext->textureBoxFilter = in_ext->textureBoxFilter; - out_ext->textureBlockMatch = in_ext->textureBlockMatch; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM: - { - VkPhysicalDeviceTilePropertiesFeaturesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceTilePropertiesFeaturesQCOM *in_ext = (const VkPhysicalDeviceTilePropertiesFeaturesQCOM *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM; - out_ext->pNext = NULL; - out_ext->tileProperties = in_ext->tileProperties; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT: - { - VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT *in_ext = (const VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->attachmentFeedbackLoopLayout = in_ext->attachmentFeedbackLoopLayout; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT: - { - VkPhysicalDeviceDepthClampZeroOneFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDepthClampZeroOneFeaturesEXT *in_ext = (const VkPhysicalDeviceDepthClampZeroOneFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->depthClampZeroOne = in_ext->depthClampZeroOne; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ADDRESS_BINDING_REPORT_FEATURES_EXT: - { - VkPhysicalDeviceAddressBindingReportFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceAddressBindingReportFeaturesEXT *in_ext = (const VkPhysicalDeviceAddressBindingReportFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ADDRESS_BINDING_REPORT_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->reportAddressBinding = in_ext->reportAddressBinding; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV: - { - VkPhysicalDeviceOpticalFlowFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceOpticalFlowFeaturesNV *in_ext = (const VkPhysicalDeviceOpticalFlowFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->opticalFlow = in_ext->opticalFlow; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT: - { - VkPhysicalDeviceFaultFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFaultFeaturesEXT *in_ext = (const VkPhysicalDeviceFaultFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->deviceFault = in_ext->deviceFault; - out_ext->deviceFaultVendorBinary = in_ext->deviceFaultVendorBinary; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM: - { - VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM *in_ext = (const VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM; - out_ext->pNext = NULL; - out_ext->shaderCoreBuiltins = in_ext->shaderCoreBuiltins; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT: - { - VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT *in_ext = (const VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->swapchainMaintenance1 = in_ext->swapchainMaintenance1; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV: - { - VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV *in_ext = (const VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->rayTracingInvocationReorder = in_ext->rayTracingInvocationReorder; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM: - { - VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM *in_ext = (const VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM; - out_ext->pNext = NULL; - out_ext->multiviewPerViewViewports = in_ext->multiviewPerViewViewports; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} -#endif /* _WIN64 */ - -static inline void convert_VkDeviceCreateInfo_win32_to_host(struct conversion_context *ctx, const VkDeviceCreateInfo32 *in, VkDeviceCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->queueCreateInfoCount = in->queueCreateInfoCount; - out->pQueueCreateInfos = convert_VkDeviceQueueCreateInfo_array_win32_to_host(ctx, (const VkDeviceQueueCreateInfo32 *)UlongToPtr(in->pQueueCreateInfos), in->queueCreateInfoCount); - out->enabledLayerCount = in->enabledLayerCount; - out->ppEnabledLayerNames = convert_char_pointer_array_win32_to_host(ctx, (const PTR32 *)UlongToPtr(in->ppEnabledLayerNames), in->enabledLayerCount); - out->enabledExtensionCount = in->enabledExtensionCount; - out->ppEnabledExtensionNames = convert_char_pointer_array_win32_to_host(ctx, (const PTR32 *)UlongToPtr(in->ppEnabledExtensionNames), in->enabledExtensionCount); - out->pEnabledFeatures = (const VkPhysicalDeviceFeatures *)UlongToPtr(in->pEnabledFeatures); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO: - break; - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV: - { - VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV32 *in_ext = (const VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->deviceGeneratedCommands = in_ext->deviceGeneratedCommands; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO: - { - VkDevicePrivateDataCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDevicePrivateDataCreateInfo32 *in_ext = (const VkDevicePrivateDataCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->privateDataSlotRequestCount = in_ext->privateDataSlotRequestCount; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES: - { - VkPhysicalDevicePrivateDataFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePrivateDataFeatures32 *in_ext = (const VkPhysicalDevicePrivateDataFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES; - out_ext->pNext = NULL; - out_ext->privateData = in_ext->privateData; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: - { - VkPhysicalDeviceFeatures2 *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFeatures232 *in_ext = (const VkPhysicalDeviceFeatures232 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - out_ext->pNext = NULL; - out_ext->features = in_ext->features; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES: - { - VkPhysicalDeviceVariablePointersFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVariablePointersFeatures32 *in_ext = (const VkPhysicalDeviceVariablePointersFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES; - out_ext->pNext = NULL; - out_ext->variablePointersStorageBuffer = in_ext->variablePointersStorageBuffer; - out_ext->variablePointers = in_ext->variablePointers; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: - { - VkPhysicalDeviceMultiviewFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMultiviewFeatures32 *in_ext = (const VkPhysicalDeviceMultiviewFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; - out_ext->pNext = NULL; - out_ext->multiview = in_ext->multiview; - out_ext->multiviewGeometryShader = in_ext->multiviewGeometryShader; - out_ext->multiviewTessellationShader = in_ext->multiviewTessellationShader; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO: - { - VkDeviceGroupDeviceCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDeviceGroupDeviceCreateInfo32 *in_ext = (const VkDeviceGroupDeviceCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->physicalDeviceCount = in_ext->physicalDeviceCount; - out_ext->pPhysicalDevices = convert_VkPhysicalDevice_array_win32_to_host(ctx, (const PTR32 *)UlongToPtr(in_ext->pPhysicalDevices), in_ext->physicalDeviceCount); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR: - { - VkPhysicalDevicePresentIdFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePresentIdFeaturesKHR32 *in_ext = (const VkPhysicalDevicePresentIdFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->presentId = in_ext->presentId; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR: - { - VkPhysicalDevicePresentWaitFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePresentWaitFeaturesKHR32 *in_ext = (const VkPhysicalDevicePresentWaitFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->presentWait = in_ext->presentWait; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: - { - VkPhysicalDevice16BitStorageFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevice16BitStorageFeatures32 *in_ext = (const VkPhysicalDevice16BitStorageFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES; - out_ext->pNext = NULL; - out_ext->storageBuffer16BitAccess = in_ext->storageBuffer16BitAccess; - out_ext->uniformAndStorageBuffer16BitAccess = in_ext->uniformAndStorageBuffer16BitAccess; - out_ext->storagePushConstant16 = in_ext->storagePushConstant16; - out_ext->storageInputOutput16 = in_ext->storageInputOutput16; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES: - { - VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures32 *in_ext = (const VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderSubgroupExtendedTypes = in_ext->shaderSubgroupExtendedTypes; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: - { - VkPhysicalDeviceSamplerYcbcrConversionFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSamplerYcbcrConversionFeatures32 *in_ext = (const VkPhysicalDeviceSamplerYcbcrConversionFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES; - out_ext->pNext = NULL; - out_ext->samplerYcbcrConversion = in_ext->samplerYcbcrConversion; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES: - { - VkPhysicalDeviceProtectedMemoryFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceProtectedMemoryFeatures32 *in_ext = (const VkPhysicalDeviceProtectedMemoryFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES; - out_ext->pNext = NULL; - out_ext->protectedMemory = in_ext->protectedMemory; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT: - { - VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT32 *in_ext = (const VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->advancedBlendCoherentOperations = in_ext->advancedBlendCoherentOperations; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT: - { - VkPhysicalDeviceMultiDrawFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMultiDrawFeaturesEXT32 *in_ext = (const VkPhysicalDeviceMultiDrawFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->multiDraw = in_ext->multiDraw; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES: - { - VkPhysicalDeviceInlineUniformBlockFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceInlineUniformBlockFeatures32 *in_ext = (const VkPhysicalDeviceInlineUniformBlockFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES; - out_ext->pNext = NULL; - out_ext->inlineUniformBlock = in_ext->inlineUniformBlock; - out_ext->descriptorBindingInlineUniformBlockUpdateAfterBind = in_ext->descriptorBindingInlineUniformBlockUpdateAfterBind; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES: - { - VkPhysicalDeviceMaintenance4Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMaintenance4Features32 *in_ext = (const VkPhysicalDeviceMaintenance4Features32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES; - out_ext->pNext = NULL; - out_ext->maintenance4 = in_ext->maintenance4; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES: - { - VkPhysicalDeviceShaderDrawParametersFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderDrawParametersFeatures32 *in_ext = (const VkPhysicalDeviceShaderDrawParametersFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderDrawParameters = in_ext->shaderDrawParameters; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES: - { - VkPhysicalDeviceShaderFloat16Int8Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderFloat16Int8Features32 *in_ext = (const VkPhysicalDeviceShaderFloat16Int8Features32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderFloat16 = in_ext->shaderFloat16; - out_ext->shaderInt8 = in_ext->shaderInt8; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES: - { - VkPhysicalDeviceHostQueryResetFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceHostQueryResetFeatures32 *in_ext = (const VkPhysicalDeviceHostQueryResetFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES; - out_ext->pNext = NULL; - out_ext->hostQueryReset = in_ext->hostQueryReset; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR: - { - VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR32 *in_ext = (const VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->globalPriorityQuery = in_ext->globalPriorityQuery; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES: - { - VkPhysicalDeviceDescriptorIndexingFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDescriptorIndexingFeatures32 *in_ext = (const VkPhysicalDeviceDescriptorIndexingFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderInputAttachmentArrayDynamicIndexing = in_ext->shaderInputAttachmentArrayDynamicIndexing; - out_ext->shaderUniformTexelBufferArrayDynamicIndexing = in_ext->shaderUniformTexelBufferArrayDynamicIndexing; - out_ext->shaderStorageTexelBufferArrayDynamicIndexing = in_ext->shaderStorageTexelBufferArrayDynamicIndexing; - out_ext->shaderUniformBufferArrayNonUniformIndexing = in_ext->shaderUniformBufferArrayNonUniformIndexing; - out_ext->shaderSampledImageArrayNonUniformIndexing = in_ext->shaderSampledImageArrayNonUniformIndexing; - out_ext->shaderStorageBufferArrayNonUniformIndexing = in_ext->shaderStorageBufferArrayNonUniformIndexing; - out_ext->shaderStorageImageArrayNonUniformIndexing = in_ext->shaderStorageImageArrayNonUniformIndexing; - out_ext->shaderInputAttachmentArrayNonUniformIndexing = in_ext->shaderInputAttachmentArrayNonUniformIndexing; - out_ext->shaderUniformTexelBufferArrayNonUniformIndexing = in_ext->shaderUniformTexelBufferArrayNonUniformIndexing; - out_ext->shaderStorageTexelBufferArrayNonUniformIndexing = in_ext->shaderStorageTexelBufferArrayNonUniformIndexing; - out_ext->descriptorBindingUniformBufferUpdateAfterBind = in_ext->descriptorBindingUniformBufferUpdateAfterBind; - out_ext->descriptorBindingSampledImageUpdateAfterBind = in_ext->descriptorBindingSampledImageUpdateAfterBind; - out_ext->descriptorBindingStorageImageUpdateAfterBind = in_ext->descriptorBindingStorageImageUpdateAfterBind; - out_ext->descriptorBindingStorageBufferUpdateAfterBind = in_ext->descriptorBindingStorageBufferUpdateAfterBind; - out_ext->descriptorBindingUniformTexelBufferUpdateAfterBind = in_ext->descriptorBindingUniformTexelBufferUpdateAfterBind; - out_ext->descriptorBindingStorageTexelBufferUpdateAfterBind = in_ext->descriptorBindingStorageTexelBufferUpdateAfterBind; - out_ext->descriptorBindingUpdateUnusedWhilePending = in_ext->descriptorBindingUpdateUnusedWhilePending; - out_ext->descriptorBindingPartiallyBound = in_ext->descriptorBindingPartiallyBound; - out_ext->descriptorBindingVariableDescriptorCount = in_ext->descriptorBindingVariableDescriptorCount; - out_ext->runtimeDescriptorArray = in_ext->runtimeDescriptorArray; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES: - { - VkPhysicalDeviceTimelineSemaphoreFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceTimelineSemaphoreFeatures32 *in_ext = (const VkPhysicalDeviceTimelineSemaphoreFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES; - out_ext->pNext = NULL; - out_ext->timelineSemaphore = in_ext->timelineSemaphore; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES: - { - VkPhysicalDevice8BitStorageFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevice8BitStorageFeatures32 *in_ext = (const VkPhysicalDevice8BitStorageFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES; - out_ext->pNext = NULL; - out_ext->storageBuffer8BitAccess = in_ext->storageBuffer8BitAccess; - out_ext->uniformAndStorageBuffer8BitAccess = in_ext->uniformAndStorageBuffer8BitAccess; - out_ext->storagePushConstant8 = in_ext->storagePushConstant8; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT: - { - VkPhysicalDeviceConditionalRenderingFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceConditionalRenderingFeaturesEXT32 *in_ext = (const VkPhysicalDeviceConditionalRenderingFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->conditionalRendering = in_ext->conditionalRendering; - out_ext->inheritedConditionalRendering = in_ext->inheritedConditionalRendering; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES: - { - VkPhysicalDeviceVulkanMemoryModelFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVulkanMemoryModelFeatures32 *in_ext = (const VkPhysicalDeviceVulkanMemoryModelFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES; - out_ext->pNext = NULL; - out_ext->vulkanMemoryModel = in_ext->vulkanMemoryModel; - out_ext->vulkanMemoryModelDeviceScope = in_ext->vulkanMemoryModelDeviceScope; - out_ext->vulkanMemoryModelAvailabilityVisibilityChains = in_ext->vulkanMemoryModelAvailabilityVisibilityChains; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES: - { - VkPhysicalDeviceShaderAtomicInt64Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderAtomicInt64Features32 *in_ext = (const VkPhysicalDeviceShaderAtomicInt64Features32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderBufferInt64Atomics = in_ext->shaderBufferInt64Atomics; - out_ext->shaderSharedInt64Atomics = in_ext->shaderSharedInt64Atomics; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT: - { - VkPhysicalDeviceShaderAtomicFloatFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderAtomicFloatFeaturesEXT32 *in_ext = (const VkPhysicalDeviceShaderAtomicFloatFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->shaderBufferFloat32Atomics = in_ext->shaderBufferFloat32Atomics; - out_ext->shaderBufferFloat32AtomicAdd = in_ext->shaderBufferFloat32AtomicAdd; - out_ext->shaderBufferFloat64Atomics = in_ext->shaderBufferFloat64Atomics; - out_ext->shaderBufferFloat64AtomicAdd = in_ext->shaderBufferFloat64AtomicAdd; - out_ext->shaderSharedFloat32Atomics = in_ext->shaderSharedFloat32Atomics; - out_ext->shaderSharedFloat32AtomicAdd = in_ext->shaderSharedFloat32AtomicAdd; - out_ext->shaderSharedFloat64Atomics = in_ext->shaderSharedFloat64Atomics; - out_ext->shaderSharedFloat64AtomicAdd = in_ext->shaderSharedFloat64AtomicAdd; - out_ext->shaderImageFloat32Atomics = in_ext->shaderImageFloat32Atomics; - out_ext->shaderImageFloat32AtomicAdd = in_ext->shaderImageFloat32AtomicAdd; - out_ext->sparseImageFloat32Atomics = in_ext->sparseImageFloat32Atomics; - out_ext->sparseImageFloat32AtomicAdd = in_ext->sparseImageFloat32AtomicAdd; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT: - { - VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT32 *in_ext = (const VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->shaderBufferFloat16Atomics = in_ext->shaderBufferFloat16Atomics; - out_ext->shaderBufferFloat16AtomicAdd = in_ext->shaderBufferFloat16AtomicAdd; - out_ext->shaderBufferFloat16AtomicMinMax = in_ext->shaderBufferFloat16AtomicMinMax; - out_ext->shaderBufferFloat32AtomicMinMax = in_ext->shaderBufferFloat32AtomicMinMax; - out_ext->shaderBufferFloat64AtomicMinMax = in_ext->shaderBufferFloat64AtomicMinMax; - out_ext->shaderSharedFloat16Atomics = in_ext->shaderSharedFloat16Atomics; - out_ext->shaderSharedFloat16AtomicAdd = in_ext->shaderSharedFloat16AtomicAdd; - out_ext->shaderSharedFloat16AtomicMinMax = in_ext->shaderSharedFloat16AtomicMinMax; - out_ext->shaderSharedFloat32AtomicMinMax = in_ext->shaderSharedFloat32AtomicMinMax; - out_ext->shaderSharedFloat64AtomicMinMax = in_ext->shaderSharedFloat64AtomicMinMax; - out_ext->shaderImageFloat32AtomicMinMax = in_ext->shaderImageFloat32AtomicMinMax; - out_ext->sparseImageFloat32AtomicMinMax = in_ext->sparseImageFloat32AtomicMinMax; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT: - { - VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT32 *in_ext = (const VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->vertexAttributeInstanceRateDivisor = in_ext->vertexAttributeInstanceRateDivisor; - out_ext->vertexAttributeInstanceRateZeroDivisor = in_ext->vertexAttributeInstanceRateZeroDivisor; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT: - { - VkPhysicalDeviceASTCDecodeFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceASTCDecodeFeaturesEXT32 *in_ext = (const VkPhysicalDeviceASTCDecodeFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->decodeModeSharedExponent = in_ext->decodeModeSharedExponent; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT: - { - VkPhysicalDeviceTransformFeedbackFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceTransformFeedbackFeaturesEXT32 *in_ext = (const VkPhysicalDeviceTransformFeedbackFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->transformFeedback = in_ext->transformFeedback; - out_ext->geometryStreams = in_ext->geometryStreams; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV: - { - VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV32 *in_ext = (const VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->representativeFragmentTest = in_ext->representativeFragmentTest; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV: - { - VkPhysicalDeviceExclusiveScissorFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceExclusiveScissorFeaturesNV32 *in_ext = (const VkPhysicalDeviceExclusiveScissorFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->exclusiveScissor = in_ext->exclusiveScissor; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV: - { - VkPhysicalDeviceCornerSampledImageFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCornerSampledImageFeaturesNV32 *in_ext = (const VkPhysicalDeviceCornerSampledImageFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->cornerSampledImage = in_ext->cornerSampledImage; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV: - { - VkPhysicalDeviceComputeShaderDerivativesFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceComputeShaderDerivativesFeaturesNV32 *in_ext = (const VkPhysicalDeviceComputeShaderDerivativesFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->computeDerivativeGroupQuads = in_ext->computeDerivativeGroupQuads; - out_ext->computeDerivativeGroupLinear = in_ext->computeDerivativeGroupLinear; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV: - { - VkPhysicalDeviceShaderImageFootprintFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderImageFootprintFeaturesNV32 *in_ext = (const VkPhysicalDeviceShaderImageFootprintFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->imageFootprint = in_ext->imageFootprint; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV: - { - VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV32 *in_ext = (const VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->dedicatedAllocationImageAliasing = in_ext->dedicatedAllocationImageAliasing; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_NV: - { - VkPhysicalDeviceCopyMemoryIndirectFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCopyMemoryIndirectFeaturesNV32 *in_ext = (const VkPhysicalDeviceCopyMemoryIndirectFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->indirectCopy = in_ext->indirectCopy; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_NV: - { - VkPhysicalDeviceMemoryDecompressionFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMemoryDecompressionFeaturesNV32 *in_ext = (const VkPhysicalDeviceMemoryDecompressionFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->memoryDecompression = in_ext->memoryDecompression; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV: - { - VkPhysicalDeviceShadingRateImageFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShadingRateImageFeaturesNV32 *in_ext = (const VkPhysicalDeviceShadingRateImageFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->shadingRateImage = in_ext->shadingRateImage; - out_ext->shadingRateCoarseSampleOrder = in_ext->shadingRateCoarseSampleOrder; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI: - { - VkPhysicalDeviceInvocationMaskFeaturesHUAWEI *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceInvocationMaskFeaturesHUAWEI32 *in_ext = (const VkPhysicalDeviceInvocationMaskFeaturesHUAWEI32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI; - out_ext->pNext = NULL; - out_ext->invocationMask = in_ext->invocationMask; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV: - { - VkPhysicalDeviceMeshShaderFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMeshShaderFeaturesNV32 *in_ext = (const VkPhysicalDeviceMeshShaderFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->taskShader = in_ext->taskShader; - out_ext->meshShader = in_ext->meshShader; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT: - { - VkPhysicalDeviceMeshShaderFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMeshShaderFeaturesEXT32 *in_ext = (const VkPhysicalDeviceMeshShaderFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->taskShader = in_ext->taskShader; - out_ext->meshShader = in_ext->meshShader; - out_ext->multiviewMeshShader = in_ext->multiviewMeshShader; - out_ext->primitiveFragmentShadingRateMeshShader = in_ext->primitiveFragmentShadingRateMeshShader; - out_ext->meshShaderQueries = in_ext->meshShaderQueries; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR: - { - VkPhysicalDeviceAccelerationStructureFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceAccelerationStructureFeaturesKHR32 *in_ext = (const VkPhysicalDeviceAccelerationStructureFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->accelerationStructure = in_ext->accelerationStructure; - out_ext->accelerationStructureCaptureReplay = in_ext->accelerationStructureCaptureReplay; - out_ext->accelerationStructureIndirectBuild = in_ext->accelerationStructureIndirectBuild; - out_ext->accelerationStructureHostCommands = in_ext->accelerationStructureHostCommands; - out_ext->descriptorBindingAccelerationStructureUpdateAfterBind = in_ext->descriptorBindingAccelerationStructureUpdateAfterBind; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR: - { - VkPhysicalDeviceRayTracingPipelineFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRayTracingPipelineFeaturesKHR32 *in_ext = (const VkPhysicalDeviceRayTracingPipelineFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->rayTracingPipeline = in_ext->rayTracingPipeline; - out_ext->rayTracingPipelineShaderGroupHandleCaptureReplay = in_ext->rayTracingPipelineShaderGroupHandleCaptureReplay; - out_ext->rayTracingPipelineShaderGroupHandleCaptureReplayMixed = in_ext->rayTracingPipelineShaderGroupHandleCaptureReplayMixed; - out_ext->rayTracingPipelineTraceRaysIndirect = in_ext->rayTracingPipelineTraceRaysIndirect; - out_ext->rayTraversalPrimitiveCulling = in_ext->rayTraversalPrimitiveCulling; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR: - { - VkPhysicalDeviceRayQueryFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRayQueryFeaturesKHR32 *in_ext = (const VkPhysicalDeviceRayQueryFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->rayQuery = in_ext->rayQuery; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR: - { - VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR32 *in_ext = (const VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->rayTracingMaintenance1 = in_ext->rayTracingMaintenance1; - out_ext->rayTracingPipelineTraceRaysIndirect2 = in_ext->rayTracingPipelineTraceRaysIndirect2; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD: - { - VkDeviceMemoryOverallocationCreateInfoAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDeviceMemoryOverallocationCreateInfoAMD32 *in_ext = (const VkDeviceMemoryOverallocationCreateInfoAMD32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD; - out_ext->pNext = NULL; - out_ext->overallocationBehavior = in_ext->overallocationBehavior; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT: - { - VkPhysicalDeviceFragmentDensityMapFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentDensityMapFeaturesEXT32 *in_ext = (const VkPhysicalDeviceFragmentDensityMapFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->fragmentDensityMap = in_ext->fragmentDensityMap; - out_ext->fragmentDensityMapDynamic = in_ext->fragmentDensityMapDynamic; - out_ext->fragmentDensityMapNonSubsampledImages = in_ext->fragmentDensityMapNonSubsampledImages; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT: - { - VkPhysicalDeviceFragmentDensityMap2FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentDensityMap2FeaturesEXT32 *in_ext = (const VkPhysicalDeviceFragmentDensityMap2FeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->fragmentDensityMapDeferred = in_ext->fragmentDensityMapDeferred; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM: - { - VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM32 *in_ext = (const VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM; - out_ext->pNext = NULL; - out_ext->fragmentDensityMapOffset = in_ext->fragmentDensityMapOffset; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES: - { - VkPhysicalDeviceScalarBlockLayoutFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceScalarBlockLayoutFeatures32 *in_ext = (const VkPhysicalDeviceScalarBlockLayoutFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES; - out_ext->pNext = NULL; - out_ext->scalarBlockLayout = in_ext->scalarBlockLayout; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES: - { - VkPhysicalDeviceUniformBufferStandardLayoutFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceUniformBufferStandardLayoutFeatures32 *in_ext = (const VkPhysicalDeviceUniformBufferStandardLayoutFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES; - out_ext->pNext = NULL; - out_ext->uniformBufferStandardLayout = in_ext->uniformBufferStandardLayout; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT: - { - VkPhysicalDeviceDepthClipEnableFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDepthClipEnableFeaturesEXT32 *in_ext = (const VkPhysicalDeviceDepthClipEnableFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->depthClipEnable = in_ext->depthClipEnable; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT: - { - VkPhysicalDeviceMemoryPriorityFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMemoryPriorityFeaturesEXT32 *in_ext = (const VkPhysicalDeviceMemoryPriorityFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->memoryPriority = in_ext->memoryPriority; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT: - { - VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT32 *in_ext = (const VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->pageableDeviceLocalMemory = in_ext->pageableDeviceLocalMemory; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES: - { - VkPhysicalDeviceBufferDeviceAddressFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceBufferDeviceAddressFeatures32 *in_ext = (const VkPhysicalDeviceBufferDeviceAddressFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES; - out_ext->pNext = NULL; - out_ext->bufferDeviceAddress = in_ext->bufferDeviceAddress; - out_ext->bufferDeviceAddressCaptureReplay = in_ext->bufferDeviceAddressCaptureReplay; - out_ext->bufferDeviceAddressMultiDevice = in_ext->bufferDeviceAddressMultiDevice; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT: - { - VkPhysicalDeviceBufferDeviceAddressFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceBufferDeviceAddressFeaturesEXT32 *in_ext = (const VkPhysicalDeviceBufferDeviceAddressFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->bufferDeviceAddress = in_ext->bufferDeviceAddress; - out_ext->bufferDeviceAddressCaptureReplay = in_ext->bufferDeviceAddressCaptureReplay; - out_ext->bufferDeviceAddressMultiDevice = in_ext->bufferDeviceAddressMultiDevice; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES: - { - VkPhysicalDeviceImagelessFramebufferFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImagelessFramebufferFeatures32 *in_ext = (const VkPhysicalDeviceImagelessFramebufferFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES; - out_ext->pNext = NULL; - out_ext->imagelessFramebuffer = in_ext->imagelessFramebuffer; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES: - { - VkPhysicalDeviceTextureCompressionASTCHDRFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceTextureCompressionASTCHDRFeatures32 *in_ext = (const VkPhysicalDeviceTextureCompressionASTCHDRFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES; - out_ext->pNext = NULL; - out_ext->textureCompressionASTC_HDR = in_ext->textureCompressionASTC_HDR; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV: - { - VkPhysicalDeviceCooperativeMatrixFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCooperativeMatrixFeaturesNV32 *in_ext = (const VkPhysicalDeviceCooperativeMatrixFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->cooperativeMatrix = in_ext->cooperativeMatrix; - out_ext->cooperativeMatrixRobustBufferAccess = in_ext->cooperativeMatrixRobustBufferAccess; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT: - { - VkPhysicalDeviceYcbcrImageArraysFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceYcbcrImageArraysFeaturesEXT32 *in_ext = (const VkPhysicalDeviceYcbcrImageArraysFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->ycbcrImageArrays = in_ext->ycbcrImageArrays; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_BARRIER_FEATURES_NV: - { - VkPhysicalDevicePresentBarrierFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePresentBarrierFeaturesNV32 *in_ext = (const VkPhysicalDevicePresentBarrierFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_BARRIER_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->presentBarrier = in_ext->presentBarrier; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR: - { - VkPhysicalDevicePerformanceQueryFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePerformanceQueryFeaturesKHR32 *in_ext = (const VkPhysicalDevicePerformanceQueryFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->performanceCounterQueryPools = in_ext->performanceCounterQueryPools; - out_ext->performanceCounterMultipleQueryPools = in_ext->performanceCounterMultipleQueryPools; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV: - { - VkPhysicalDeviceCoverageReductionModeFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCoverageReductionModeFeaturesNV32 *in_ext = (const VkPhysicalDeviceCoverageReductionModeFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->coverageReductionMode = in_ext->coverageReductionMode; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL: - { - VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL32 *in_ext = (const VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL; - out_ext->pNext = NULL; - out_ext->shaderIntegerFunctions2 = in_ext->shaderIntegerFunctions2; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR: - { - VkPhysicalDeviceShaderClockFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderClockFeaturesKHR32 *in_ext = (const VkPhysicalDeviceShaderClockFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->shaderSubgroupClock = in_ext->shaderSubgroupClock; - out_ext->shaderDeviceClock = in_ext->shaderDeviceClock; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT: - { - VkPhysicalDeviceIndexTypeUint8FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceIndexTypeUint8FeaturesEXT32 *in_ext = (const VkPhysicalDeviceIndexTypeUint8FeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->indexTypeUint8 = in_ext->indexTypeUint8; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV: - { - VkPhysicalDeviceShaderSMBuiltinsFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderSMBuiltinsFeaturesNV32 *in_ext = (const VkPhysicalDeviceShaderSMBuiltinsFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->shaderSMBuiltins = in_ext->shaderSMBuiltins; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: - { - VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT32 *in_ext = (const VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->fragmentShaderSampleInterlock = in_ext->fragmentShaderSampleInterlock; - out_ext->fragmentShaderPixelInterlock = in_ext->fragmentShaderPixelInterlock; - out_ext->fragmentShaderShadingRateInterlock = in_ext->fragmentShaderShadingRateInterlock; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES: - { - VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures32 *in_ext = (const VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES; - out_ext->pNext = NULL; - out_ext->separateDepthStencilLayouts = in_ext->separateDepthStencilLayouts; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT: - { - VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT32 *in_ext = (const VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->primitiveTopologyListRestart = in_ext->primitiveTopologyListRestart; - out_ext->primitiveTopologyPatchListRestart = in_ext->primitiveTopologyPatchListRestart; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR: - { - VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR32 *in_ext = (const VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->pipelineExecutableInfo = in_ext->pipelineExecutableInfo; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES: - { - VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures32 *in_ext = (const VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderDemoteToHelperInvocation = in_ext->shaderDemoteToHelperInvocation; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT: - { - VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT32 *in_ext = (const VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->texelBufferAlignment = in_ext->texelBufferAlignment; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES: - { - VkPhysicalDeviceSubgroupSizeControlFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSubgroupSizeControlFeatures32 *in_ext = (const VkPhysicalDeviceSubgroupSizeControlFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES; - out_ext->pNext = NULL; - out_ext->subgroupSizeControl = in_ext->subgroupSizeControl; - out_ext->computeFullSubgroups = in_ext->computeFullSubgroups; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT: - { - VkPhysicalDeviceLineRasterizationFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceLineRasterizationFeaturesEXT32 *in_ext = (const VkPhysicalDeviceLineRasterizationFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->rectangularLines = in_ext->rectangularLines; - out_ext->bresenhamLines = in_ext->bresenhamLines; - out_ext->smoothLines = in_ext->smoothLines; - out_ext->stippledRectangularLines = in_ext->stippledRectangularLines; - out_ext->stippledBresenhamLines = in_ext->stippledBresenhamLines; - out_ext->stippledSmoothLines = in_ext->stippledSmoothLines; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES: - { - VkPhysicalDevicePipelineCreationCacheControlFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePipelineCreationCacheControlFeatures32 *in_ext = (const VkPhysicalDevicePipelineCreationCacheControlFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES; - out_ext->pNext = NULL; - out_ext->pipelineCreationCacheControl = in_ext->pipelineCreationCacheControl; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES: - { - VkPhysicalDeviceVulkan11Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVulkan11Features32 *in_ext = (const VkPhysicalDeviceVulkan11Features32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; - out_ext->pNext = NULL; - out_ext->storageBuffer16BitAccess = in_ext->storageBuffer16BitAccess; - out_ext->uniformAndStorageBuffer16BitAccess = in_ext->uniformAndStorageBuffer16BitAccess; - out_ext->storagePushConstant16 = in_ext->storagePushConstant16; - out_ext->storageInputOutput16 = in_ext->storageInputOutput16; - out_ext->multiview = in_ext->multiview; - out_ext->multiviewGeometryShader = in_ext->multiviewGeometryShader; - out_ext->multiviewTessellationShader = in_ext->multiviewTessellationShader; - out_ext->variablePointersStorageBuffer = in_ext->variablePointersStorageBuffer; - out_ext->variablePointers = in_ext->variablePointers; - out_ext->protectedMemory = in_ext->protectedMemory; - out_ext->samplerYcbcrConversion = in_ext->samplerYcbcrConversion; - out_ext->shaderDrawParameters = in_ext->shaderDrawParameters; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES: - { - VkPhysicalDeviceVulkan12Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVulkan12Features32 *in_ext = (const VkPhysicalDeviceVulkan12Features32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; - out_ext->pNext = NULL; - out_ext->samplerMirrorClampToEdge = in_ext->samplerMirrorClampToEdge; - out_ext->drawIndirectCount = in_ext->drawIndirectCount; - out_ext->storageBuffer8BitAccess = in_ext->storageBuffer8BitAccess; - out_ext->uniformAndStorageBuffer8BitAccess = in_ext->uniformAndStorageBuffer8BitAccess; - out_ext->storagePushConstant8 = in_ext->storagePushConstant8; - out_ext->shaderBufferInt64Atomics = in_ext->shaderBufferInt64Atomics; - out_ext->shaderSharedInt64Atomics = in_ext->shaderSharedInt64Atomics; - out_ext->shaderFloat16 = in_ext->shaderFloat16; - out_ext->shaderInt8 = in_ext->shaderInt8; - out_ext->descriptorIndexing = in_ext->descriptorIndexing; - out_ext->shaderInputAttachmentArrayDynamicIndexing = in_ext->shaderInputAttachmentArrayDynamicIndexing; - out_ext->shaderUniformTexelBufferArrayDynamicIndexing = in_ext->shaderUniformTexelBufferArrayDynamicIndexing; - out_ext->shaderStorageTexelBufferArrayDynamicIndexing = in_ext->shaderStorageTexelBufferArrayDynamicIndexing; - out_ext->shaderUniformBufferArrayNonUniformIndexing = in_ext->shaderUniformBufferArrayNonUniformIndexing; - out_ext->shaderSampledImageArrayNonUniformIndexing = in_ext->shaderSampledImageArrayNonUniformIndexing; - out_ext->shaderStorageBufferArrayNonUniformIndexing = in_ext->shaderStorageBufferArrayNonUniformIndexing; - out_ext->shaderStorageImageArrayNonUniformIndexing = in_ext->shaderStorageImageArrayNonUniformIndexing; - out_ext->shaderInputAttachmentArrayNonUniformIndexing = in_ext->shaderInputAttachmentArrayNonUniformIndexing; - out_ext->shaderUniformTexelBufferArrayNonUniformIndexing = in_ext->shaderUniformTexelBufferArrayNonUniformIndexing; - out_ext->shaderStorageTexelBufferArrayNonUniformIndexing = in_ext->shaderStorageTexelBufferArrayNonUniformIndexing; - out_ext->descriptorBindingUniformBufferUpdateAfterBind = in_ext->descriptorBindingUniformBufferUpdateAfterBind; - out_ext->descriptorBindingSampledImageUpdateAfterBind = in_ext->descriptorBindingSampledImageUpdateAfterBind; - out_ext->descriptorBindingStorageImageUpdateAfterBind = in_ext->descriptorBindingStorageImageUpdateAfterBind; - out_ext->descriptorBindingStorageBufferUpdateAfterBind = in_ext->descriptorBindingStorageBufferUpdateAfterBind; - out_ext->descriptorBindingUniformTexelBufferUpdateAfterBind = in_ext->descriptorBindingUniformTexelBufferUpdateAfterBind; - out_ext->descriptorBindingStorageTexelBufferUpdateAfterBind = in_ext->descriptorBindingStorageTexelBufferUpdateAfterBind; - out_ext->descriptorBindingUpdateUnusedWhilePending = in_ext->descriptorBindingUpdateUnusedWhilePending; - out_ext->descriptorBindingPartiallyBound = in_ext->descriptorBindingPartiallyBound; - out_ext->descriptorBindingVariableDescriptorCount = in_ext->descriptorBindingVariableDescriptorCount; - out_ext->runtimeDescriptorArray = in_ext->runtimeDescriptorArray; - out_ext->samplerFilterMinmax = in_ext->samplerFilterMinmax; - out_ext->scalarBlockLayout = in_ext->scalarBlockLayout; - out_ext->imagelessFramebuffer = in_ext->imagelessFramebuffer; - out_ext->uniformBufferStandardLayout = in_ext->uniformBufferStandardLayout; - out_ext->shaderSubgroupExtendedTypes = in_ext->shaderSubgroupExtendedTypes; - out_ext->separateDepthStencilLayouts = in_ext->separateDepthStencilLayouts; - out_ext->hostQueryReset = in_ext->hostQueryReset; - out_ext->timelineSemaphore = in_ext->timelineSemaphore; - out_ext->bufferDeviceAddress = in_ext->bufferDeviceAddress; - out_ext->bufferDeviceAddressCaptureReplay = in_ext->bufferDeviceAddressCaptureReplay; - out_ext->bufferDeviceAddressMultiDevice = in_ext->bufferDeviceAddressMultiDevice; - out_ext->vulkanMemoryModel = in_ext->vulkanMemoryModel; - out_ext->vulkanMemoryModelDeviceScope = in_ext->vulkanMemoryModelDeviceScope; - out_ext->vulkanMemoryModelAvailabilityVisibilityChains = in_ext->vulkanMemoryModelAvailabilityVisibilityChains; - out_ext->shaderOutputViewportIndex = in_ext->shaderOutputViewportIndex; - out_ext->shaderOutputLayer = in_ext->shaderOutputLayer; - out_ext->subgroupBroadcastDynamicId = in_ext->subgroupBroadcastDynamicId; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES: - { - VkPhysicalDeviceVulkan13Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVulkan13Features32 *in_ext = (const VkPhysicalDeviceVulkan13Features32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; - out_ext->pNext = NULL; - out_ext->robustImageAccess = in_ext->robustImageAccess; - out_ext->inlineUniformBlock = in_ext->inlineUniformBlock; - out_ext->descriptorBindingInlineUniformBlockUpdateAfterBind = in_ext->descriptorBindingInlineUniformBlockUpdateAfterBind; - out_ext->pipelineCreationCacheControl = in_ext->pipelineCreationCacheControl; - out_ext->privateData = in_ext->privateData; - out_ext->shaderDemoteToHelperInvocation = in_ext->shaderDemoteToHelperInvocation; - out_ext->shaderTerminateInvocation = in_ext->shaderTerminateInvocation; - out_ext->subgroupSizeControl = in_ext->subgroupSizeControl; - out_ext->computeFullSubgroups = in_ext->computeFullSubgroups; - out_ext->synchronization2 = in_ext->synchronization2; - out_ext->textureCompressionASTC_HDR = in_ext->textureCompressionASTC_HDR; - out_ext->shaderZeroInitializeWorkgroupMemory = in_ext->shaderZeroInitializeWorkgroupMemory; - out_ext->dynamicRendering = in_ext->dynamicRendering; - out_ext->shaderIntegerDotProduct = in_ext->shaderIntegerDotProduct; - out_ext->maintenance4 = in_ext->maintenance4; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD: - { - VkPhysicalDeviceCoherentMemoryFeaturesAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCoherentMemoryFeaturesAMD32 *in_ext = (const VkPhysicalDeviceCoherentMemoryFeaturesAMD32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD; - out_ext->pNext = NULL; - out_ext->deviceCoherentMemory = in_ext->deviceCoherentMemory; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT: - { - VkPhysicalDeviceCustomBorderColorFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCustomBorderColorFeaturesEXT32 *in_ext = (const VkPhysicalDeviceCustomBorderColorFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->customBorderColors = in_ext->customBorderColors; - out_ext->customBorderColorWithoutFormat = in_ext->customBorderColorWithoutFormat; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT: - { - VkPhysicalDeviceBorderColorSwizzleFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceBorderColorSwizzleFeaturesEXT32 *in_ext = (const VkPhysicalDeviceBorderColorSwizzleFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->borderColorSwizzle = in_ext->borderColorSwizzle; - out_ext->borderColorSwizzleFromImage = in_ext->borderColorSwizzleFromImage; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT: - { - VkPhysicalDeviceExtendedDynamicStateFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceExtendedDynamicStateFeaturesEXT32 *in_ext = (const VkPhysicalDeviceExtendedDynamicStateFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->extendedDynamicState = in_ext->extendedDynamicState; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT: - { - VkPhysicalDeviceExtendedDynamicState2FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceExtendedDynamicState2FeaturesEXT32 *in_ext = (const VkPhysicalDeviceExtendedDynamicState2FeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->extendedDynamicState2 = in_ext->extendedDynamicState2; - out_ext->extendedDynamicState2LogicOp = in_ext->extendedDynamicState2LogicOp; - out_ext->extendedDynamicState2PatchControlPoints = in_ext->extendedDynamicState2PatchControlPoints; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT: - { - VkPhysicalDeviceExtendedDynamicState3FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceExtendedDynamicState3FeaturesEXT32 *in_ext = (const VkPhysicalDeviceExtendedDynamicState3FeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->extendedDynamicState3TessellationDomainOrigin = in_ext->extendedDynamicState3TessellationDomainOrigin; - out_ext->extendedDynamicState3DepthClampEnable = in_ext->extendedDynamicState3DepthClampEnable; - out_ext->extendedDynamicState3PolygonMode = in_ext->extendedDynamicState3PolygonMode; - out_ext->extendedDynamicState3RasterizationSamples = in_ext->extendedDynamicState3RasterizationSamples; - out_ext->extendedDynamicState3SampleMask = in_ext->extendedDynamicState3SampleMask; - out_ext->extendedDynamicState3AlphaToCoverageEnable = in_ext->extendedDynamicState3AlphaToCoverageEnable; - out_ext->extendedDynamicState3AlphaToOneEnable = in_ext->extendedDynamicState3AlphaToOneEnable; - out_ext->extendedDynamicState3LogicOpEnable = in_ext->extendedDynamicState3LogicOpEnable; - out_ext->extendedDynamicState3ColorBlendEnable = in_ext->extendedDynamicState3ColorBlendEnable; - out_ext->extendedDynamicState3ColorBlendEquation = in_ext->extendedDynamicState3ColorBlendEquation; - out_ext->extendedDynamicState3ColorWriteMask = in_ext->extendedDynamicState3ColorWriteMask; - out_ext->extendedDynamicState3RasterizationStream = in_ext->extendedDynamicState3RasterizationStream; - out_ext->extendedDynamicState3ConservativeRasterizationMode = in_ext->extendedDynamicState3ConservativeRasterizationMode; - out_ext->extendedDynamicState3ExtraPrimitiveOverestimationSize = in_ext->extendedDynamicState3ExtraPrimitiveOverestimationSize; - out_ext->extendedDynamicState3DepthClipEnable = in_ext->extendedDynamicState3DepthClipEnable; - out_ext->extendedDynamicState3SampleLocationsEnable = in_ext->extendedDynamicState3SampleLocationsEnable; - out_ext->extendedDynamicState3ColorBlendAdvanced = in_ext->extendedDynamicState3ColorBlendAdvanced; - out_ext->extendedDynamicState3ProvokingVertexMode = in_ext->extendedDynamicState3ProvokingVertexMode; - out_ext->extendedDynamicState3LineRasterizationMode = in_ext->extendedDynamicState3LineRasterizationMode; - out_ext->extendedDynamicState3LineStippleEnable = in_ext->extendedDynamicState3LineStippleEnable; - out_ext->extendedDynamicState3DepthClipNegativeOneToOne = in_ext->extendedDynamicState3DepthClipNegativeOneToOne; - out_ext->extendedDynamicState3ViewportWScalingEnable = in_ext->extendedDynamicState3ViewportWScalingEnable; - out_ext->extendedDynamicState3ViewportSwizzle = in_ext->extendedDynamicState3ViewportSwizzle; - out_ext->extendedDynamicState3CoverageToColorEnable = in_ext->extendedDynamicState3CoverageToColorEnable; - out_ext->extendedDynamicState3CoverageToColorLocation = in_ext->extendedDynamicState3CoverageToColorLocation; - out_ext->extendedDynamicState3CoverageModulationMode = in_ext->extendedDynamicState3CoverageModulationMode; - out_ext->extendedDynamicState3CoverageModulationTableEnable = in_ext->extendedDynamicState3CoverageModulationTableEnable; - out_ext->extendedDynamicState3CoverageModulationTable = in_ext->extendedDynamicState3CoverageModulationTable; - out_ext->extendedDynamicState3CoverageReductionMode = in_ext->extendedDynamicState3CoverageReductionMode; - out_ext->extendedDynamicState3RepresentativeFragmentTestEnable = in_ext->extendedDynamicState3RepresentativeFragmentTestEnable; - out_ext->extendedDynamicState3ShadingRateImageEnable = in_ext->extendedDynamicState3ShadingRateImageEnable; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV: - { - VkPhysicalDeviceDiagnosticsConfigFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDiagnosticsConfigFeaturesNV32 *in_ext = (const VkPhysicalDeviceDiagnosticsConfigFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->diagnosticsConfig = in_ext->diagnosticsConfig; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV: - { - VkDeviceDiagnosticsConfigCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDeviceDiagnosticsConfigCreateInfoNV32 *in_ext = (const VkDeviceDiagnosticsConfigCreateInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES: - { - VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures32 *in_ext = (const VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderZeroInitializeWorkgroupMemory = in_ext->shaderZeroInitializeWorkgroupMemory; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR: - { - VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR32 *in_ext = (const VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->shaderSubgroupUniformControlFlow = in_ext->shaderSubgroupUniformControlFlow; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT: - { - VkPhysicalDeviceRobustness2FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRobustness2FeaturesEXT32 *in_ext = (const VkPhysicalDeviceRobustness2FeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->robustBufferAccess2 = in_ext->robustBufferAccess2; - out_ext->robustImageAccess2 = in_ext->robustImageAccess2; - out_ext->nullDescriptor = in_ext->nullDescriptor; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES: - { - VkPhysicalDeviceImageRobustnessFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImageRobustnessFeatures32 *in_ext = (const VkPhysicalDeviceImageRobustnessFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES; - out_ext->pNext = NULL; - out_ext->robustImageAccess = in_ext->robustImageAccess; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR: - { - VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR32 *in_ext = (const VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->workgroupMemoryExplicitLayout = in_ext->workgroupMemoryExplicitLayout; - out_ext->workgroupMemoryExplicitLayoutScalarBlockLayout = in_ext->workgroupMemoryExplicitLayoutScalarBlockLayout; - out_ext->workgroupMemoryExplicitLayout8BitAccess = in_ext->workgroupMemoryExplicitLayout8BitAccess; - out_ext->workgroupMemoryExplicitLayout16BitAccess = in_ext->workgroupMemoryExplicitLayout16BitAccess; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT: - { - VkPhysicalDevice4444FormatsFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevice4444FormatsFeaturesEXT32 *in_ext = (const VkPhysicalDevice4444FormatsFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->formatA4R4G4B4 = in_ext->formatA4R4G4B4; - out_ext->formatA4B4G4R4 = in_ext->formatA4B4G4R4; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI: - { - VkPhysicalDeviceSubpassShadingFeaturesHUAWEI *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSubpassShadingFeaturesHUAWEI32 *in_ext = (const VkPhysicalDeviceSubpassShadingFeaturesHUAWEI32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI; - out_ext->pNext = NULL; - out_ext->subpassShading = in_ext->subpassShading; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT: - { - VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT32 *in_ext = (const VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->shaderImageInt64Atomics = in_ext->shaderImageInt64Atomics; - out_ext->sparseImageInt64Atomics = in_ext->sparseImageInt64Atomics; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR: - { - VkPhysicalDeviceFragmentShadingRateFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentShadingRateFeaturesKHR32 *in_ext = (const VkPhysicalDeviceFragmentShadingRateFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->pipelineFragmentShadingRate = in_ext->pipelineFragmentShadingRate; - out_ext->primitiveFragmentShadingRate = in_ext->primitiveFragmentShadingRate; - out_ext->attachmentFragmentShadingRate = in_ext->attachmentFragmentShadingRate; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES: - { - VkPhysicalDeviceShaderTerminateInvocationFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderTerminateInvocationFeatures32 *in_ext = (const VkPhysicalDeviceShaderTerminateInvocationFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderTerminateInvocation = in_ext->shaderTerminateInvocation; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV: - { - VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV32 *in_ext = (const VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->fragmentShadingRateEnums = in_ext->fragmentShadingRateEnums; - out_ext->supersampleFragmentShadingRates = in_ext->supersampleFragmentShadingRates; - out_ext->noInvocationFragmentShadingRates = in_ext->noInvocationFragmentShadingRates; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT: - { - VkPhysicalDeviceImage2DViewOf3DFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImage2DViewOf3DFeaturesEXT32 *in_ext = (const VkPhysicalDeviceImage2DViewOf3DFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->image2DViewOf3D = in_ext->image2DViewOf3D; - out_ext->sampler2DViewOf3D = in_ext->sampler2DViewOf3D; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT: - { - VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT32 *in_ext = (const VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->mutableDescriptorType = in_ext->mutableDescriptorType; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT: - { - VkPhysicalDeviceDepthClipControlFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDepthClipControlFeaturesEXT32 *in_ext = (const VkPhysicalDeviceDepthClipControlFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->depthClipControl = in_ext->depthClipControl; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT: - { - VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT32 *in_ext = (const VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->vertexInputDynamicState = in_ext->vertexInputDynamicState; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: - { - VkPhysicalDeviceColorWriteEnableFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceColorWriteEnableFeaturesEXT32 *in_ext = (const VkPhysicalDeviceColorWriteEnableFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->colorWriteEnable = in_ext->colorWriteEnable; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES: - { - VkPhysicalDeviceSynchronization2Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSynchronization2Features32 *in_ext = (const VkPhysicalDeviceSynchronization2Features32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES; - out_ext->pNext = NULL; - out_ext->synchronization2 = in_ext->synchronization2; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT: - { - VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT32 *in_ext = (const VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->primitivesGeneratedQuery = in_ext->primitivesGeneratedQuery; - out_ext->primitivesGeneratedQueryWithRasterizerDiscard = in_ext->primitivesGeneratedQueryWithRasterizerDiscard; - out_ext->primitivesGeneratedQueryWithNonZeroStreams = in_ext->primitivesGeneratedQueryWithNonZeroStreams; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT: - { - VkPhysicalDeviceLegacyDitheringFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceLegacyDitheringFeaturesEXT32 *in_ext = (const VkPhysicalDeviceLegacyDitheringFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->legacyDithering = in_ext->legacyDithering; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT: - { - VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT32 *in_ext = (const VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->multisampledRenderToSingleSampled = in_ext->multisampledRenderToSingleSampled; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT: - { - VkPhysicalDevicePipelineProtectedAccessFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePipelineProtectedAccessFeaturesEXT32 *in_ext = (const VkPhysicalDevicePipelineProtectedAccessFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->pipelineProtectedAccess = in_ext->pipelineProtectedAccess; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV: - { - VkPhysicalDeviceInheritedViewportScissorFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceInheritedViewportScissorFeaturesNV32 *in_ext = (const VkPhysicalDeviceInheritedViewportScissorFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->inheritedViewportScissor2D = in_ext->inheritedViewportScissor2D; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT: - { - VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT32 *in_ext = (const VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->ycbcr2plane444Formats = in_ext->ycbcr2plane444Formats; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT: - { - VkPhysicalDeviceProvokingVertexFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceProvokingVertexFeaturesEXT32 *in_ext = (const VkPhysicalDeviceProvokingVertexFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->provokingVertexLast = in_ext->provokingVertexLast; - out_ext->transformFeedbackPreservesProvokingVertex = in_ext->transformFeedbackPreservesProvokingVertex; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT: - { - VkPhysicalDeviceDescriptorBufferFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDescriptorBufferFeaturesEXT32 *in_ext = (const VkPhysicalDeviceDescriptorBufferFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->descriptorBuffer = in_ext->descriptorBuffer; - out_ext->descriptorBufferCaptureReplay = in_ext->descriptorBufferCaptureReplay; - out_ext->descriptorBufferImageLayoutIgnored = in_ext->descriptorBufferImageLayoutIgnored; - out_ext->descriptorBufferPushDescriptors = in_ext->descriptorBufferPushDescriptors; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES: - { - VkPhysicalDeviceShaderIntegerDotProductFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderIntegerDotProductFeatures32 *in_ext = (const VkPhysicalDeviceShaderIntegerDotProductFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderIntegerDotProduct = in_ext->shaderIntegerDotProduct; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR: - { - VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR32 *in_ext = (const VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->fragmentShaderBarycentric = in_ext->fragmentShaderBarycentric; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV: - { - VkPhysicalDeviceRayTracingMotionBlurFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRayTracingMotionBlurFeaturesNV32 *in_ext = (const VkPhysicalDeviceRayTracingMotionBlurFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->rayTracingMotionBlur = in_ext->rayTracingMotionBlur; - out_ext->rayTracingMotionBlurPipelineTraceRaysIndirect = in_ext->rayTracingMotionBlurPipelineTraceRaysIndirect; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT: - { - VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT32 *in_ext = (const VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->formatRgba10x6WithoutYCbCrSampler = in_ext->formatRgba10x6WithoutYCbCrSampler; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES: - { - VkPhysicalDeviceDynamicRenderingFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDynamicRenderingFeatures32 *in_ext = (const VkPhysicalDeviceDynamicRenderingFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES; - out_ext->pNext = NULL; - out_ext->dynamicRendering = in_ext->dynamicRendering; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT: - { - VkPhysicalDeviceImageViewMinLodFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImageViewMinLodFeaturesEXT32 *in_ext = (const VkPhysicalDeviceImageViewMinLodFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->minLod = in_ext->minLod; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT: - { - VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT32 *in_ext = (const VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->rasterizationOrderColorAttachmentAccess = in_ext->rasterizationOrderColorAttachmentAccess; - out_ext->rasterizationOrderDepthAttachmentAccess = in_ext->rasterizationOrderDepthAttachmentAccess; - out_ext->rasterizationOrderStencilAttachmentAccess = in_ext->rasterizationOrderStencilAttachmentAccess; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV: - { - VkPhysicalDeviceLinearColorAttachmentFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceLinearColorAttachmentFeaturesNV32 *in_ext = (const VkPhysicalDeviceLinearColorAttachmentFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->linearColorAttachment = in_ext->linearColorAttachment; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT: - { - VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT32 *in_ext = (const VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->graphicsPipelineLibrary = in_ext->graphicsPipelineLibrary; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE: - { - VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE32 *in_ext = (const VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE; - out_ext->pNext = NULL; - out_ext->descriptorSetHostMapping = in_ext->descriptorSetHostMapping; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT: - { - VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT32 *in_ext = (const VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->shaderModuleIdentifier = in_ext->shaderModuleIdentifier; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT: - { - VkPhysicalDeviceImageCompressionControlFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImageCompressionControlFeaturesEXT32 *in_ext = (const VkPhysicalDeviceImageCompressionControlFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->imageCompressionControl = in_ext->imageCompressionControl; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT: - { - VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT32 *in_ext = (const VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->imageCompressionControlSwapchain = in_ext->imageCompressionControlSwapchain; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT: - { - VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT32 *in_ext = (const VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->subpassMergeFeedback = in_ext->subpassMergeFeedback; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_EXT: - { - VkPhysicalDeviceOpacityMicromapFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceOpacityMicromapFeaturesEXT32 *in_ext = (const VkPhysicalDeviceOpacityMicromapFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->micromap = in_ext->micromap; - out_ext->micromapCaptureReplay = in_ext->micromapCaptureReplay; - out_ext->micromapHostCommands = in_ext->micromapHostCommands; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT: - { - VkPhysicalDevicePipelinePropertiesFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePipelinePropertiesFeaturesEXT32 *in_ext = (const VkPhysicalDevicePipelinePropertiesFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->pipelinePropertiesIdentifier = in_ext->pipelinePropertiesIdentifier; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD: - { - VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD32 *in_ext = (const VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD; - out_ext->pNext = NULL; - out_ext->shaderEarlyAndLateFragmentTests = in_ext->shaderEarlyAndLateFragmentTests; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT: - { - VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT32 *in_ext = (const VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->nonSeamlessCubeMap = in_ext->nonSeamlessCubeMap; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT: - { - VkPhysicalDevicePipelineRobustnessFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePipelineRobustnessFeaturesEXT32 *in_ext = (const VkPhysicalDevicePipelineRobustnessFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->pipelineRobustness = in_ext->pipelineRobustness; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM: - { - VkPhysicalDeviceImageProcessingFeaturesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImageProcessingFeaturesQCOM32 *in_ext = (const VkPhysicalDeviceImageProcessingFeaturesQCOM32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM; - out_ext->pNext = NULL; - out_ext->textureSampleWeighted = in_ext->textureSampleWeighted; - out_ext->textureBoxFilter = in_ext->textureBoxFilter; - out_ext->textureBlockMatch = in_ext->textureBlockMatch; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM: - { - VkPhysicalDeviceTilePropertiesFeaturesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceTilePropertiesFeaturesQCOM32 *in_ext = (const VkPhysicalDeviceTilePropertiesFeaturesQCOM32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM; - out_ext->pNext = NULL; - out_ext->tileProperties = in_ext->tileProperties; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT: - { - VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT32 *in_ext = (const VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->attachmentFeedbackLoopLayout = in_ext->attachmentFeedbackLoopLayout; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT: - { - VkPhysicalDeviceDepthClampZeroOneFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDepthClampZeroOneFeaturesEXT32 *in_ext = (const VkPhysicalDeviceDepthClampZeroOneFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->depthClampZeroOne = in_ext->depthClampZeroOne; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ADDRESS_BINDING_REPORT_FEATURES_EXT: - { - VkPhysicalDeviceAddressBindingReportFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceAddressBindingReportFeaturesEXT32 *in_ext = (const VkPhysicalDeviceAddressBindingReportFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ADDRESS_BINDING_REPORT_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->reportAddressBinding = in_ext->reportAddressBinding; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV: - { - VkPhysicalDeviceOpticalFlowFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceOpticalFlowFeaturesNV32 *in_ext = (const VkPhysicalDeviceOpticalFlowFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->opticalFlow = in_ext->opticalFlow; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT: - { - VkPhysicalDeviceFaultFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFaultFeaturesEXT32 *in_ext = (const VkPhysicalDeviceFaultFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->deviceFault = in_ext->deviceFault; - out_ext->deviceFaultVendorBinary = in_ext->deviceFaultVendorBinary; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM: - { - VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM32 *in_ext = (const VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM; - out_ext->pNext = NULL; - out_ext->shaderCoreBuiltins = in_ext->shaderCoreBuiltins; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT: - { - VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT32 *in_ext = (const VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->swapchainMaintenance1 = in_ext->swapchainMaintenance1; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV: - { - VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV32 *in_ext = (const VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->rayTracingInvocationReorder = in_ext->rayTracingInvocationReorder; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM: - { - VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM32 *in_ext = (const VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM; - out_ext->pNext = NULL; - out_ext->multiviewPerViewViewports = in_ext->multiviewPerViewViewports; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkEventCreateInfo_win32_to_host(const VkEventCreateInfo32 *in, VkEventCreateInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkFenceCreateInfo_win32_to_host(struct conversion_context *ctx, const VkFenceCreateInfo32 *in, VkFenceCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO: - { - VkExportFenceCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkExportFenceCreateInfo32 *in_ext = (const VkExportFenceCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->handleTypes = in_ext->handleTypes; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkFramebufferAttachmentImageInfo_win32_to_host(const VkFramebufferAttachmentImageInfo32 *in, VkFramebufferAttachmentImageInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->usage = in->usage; - out->width = in->width; - out->height = in->height; - out->layerCount = in->layerCount; - out->viewFormatCount = in->viewFormatCount; - out->pViewFormats = (const VkFormat *)UlongToPtr(in->pViewFormats); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkFramebufferAttachmentImageInfo *convert_VkFramebufferAttachmentImageInfo_array_win32_to_host(struct conversion_context *ctx, const VkFramebufferAttachmentImageInfo32 *in, uint32_t count) -{ - VkFramebufferAttachmentImageInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkFramebufferAttachmentImageInfo_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkFramebufferCreateInfo_win32_to_host(struct conversion_context *ctx, const VkFramebufferCreateInfo32 *in, VkFramebufferCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->renderPass = in->renderPass; - out->attachmentCount = in->attachmentCount; - out->pAttachments = (const VkImageView *)UlongToPtr(in->pAttachments); - out->width = in->width; - out->height = in->height; - out->layers = in->layers; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO: - { - VkFramebufferAttachmentsCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkFramebufferAttachmentsCreateInfo32 *in_ext = (const VkFramebufferAttachmentsCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->attachmentImageInfoCount = in_ext->attachmentImageInfoCount; - out_ext->pAttachmentImageInfos = convert_VkFramebufferAttachmentImageInfo_array_win32_to_host(ctx, (const VkFramebufferAttachmentImageInfo32 *)UlongToPtr(in_ext->pAttachmentImageInfos), in_ext->attachmentImageInfoCount); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -#ifdef _WIN64 -static inline const VkPipelineShaderStageCreateInfo *convert_VkPipelineShaderStageCreateInfo_array_win64_to_host(struct conversion_context *ctx, const VkPipelineShaderStageCreateInfo *in, uint32_t count) -{ - VkPipelineShaderStageCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPipelineShaderStageCreateInfo_win64_to_host(ctx, &in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkPipelineShaderStageCreateInfo *convert_VkPipelineShaderStageCreateInfo_array_win32_to_host(struct conversion_context *ctx, const VkPipelineShaderStageCreateInfo32 *in, uint32_t count) -{ - VkPipelineShaderStageCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPipelineShaderStageCreateInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPipelineVertexInputStateCreateInfo_win32_to_host(struct conversion_context *ctx, const VkPipelineVertexInputStateCreateInfo32 *in, VkPipelineVertexInputStateCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->vertexBindingDescriptionCount = in->vertexBindingDescriptionCount; - out->pVertexBindingDescriptions = (const VkVertexInputBindingDescription *)UlongToPtr(in->pVertexBindingDescriptions); - out->vertexAttributeDescriptionCount = in->vertexAttributeDescriptionCount; - out->pVertexAttributeDescriptions = (const VkVertexInputAttributeDescription *)UlongToPtr(in->pVertexAttributeDescriptions); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT: - { - VkPipelineVertexInputDivisorStateCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineVertexInputDivisorStateCreateInfoEXT32 *in_ext = (const VkPipelineVertexInputDivisorStateCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->vertexBindingDivisorCount = in_ext->vertexBindingDivisorCount; - out_ext->pVertexBindingDivisors = (const VkVertexInputBindingDivisorDescriptionEXT *)UlongToPtr(in_ext->pVertexBindingDivisors); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkPipelineVertexInputStateCreateInfo *convert_VkPipelineVertexInputStateCreateInfo_array_win32_to_host(struct conversion_context *ctx, const VkPipelineVertexInputStateCreateInfo32 *in, uint32_t count) -{ - VkPipelineVertexInputStateCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPipelineVertexInputStateCreateInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPipelineTessellationStateCreateInfo_win32_to_host(struct conversion_context *ctx, const VkPipelineTessellationStateCreateInfo32 *in, VkPipelineTessellationStateCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->patchControlPoints = in->patchControlPoints; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO: - { - VkPipelineTessellationDomainOriginStateCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineTessellationDomainOriginStateCreateInfo32 *in_ext = (const VkPipelineTessellationDomainOriginStateCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->domainOrigin = in_ext->domainOrigin; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkPipelineTessellationStateCreateInfo *convert_VkPipelineTessellationStateCreateInfo_array_win32_to_host(struct conversion_context *ctx, const VkPipelineTessellationStateCreateInfo32 *in, uint32_t count) -{ - VkPipelineTessellationStateCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPipelineTessellationStateCreateInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -#ifdef _WIN64 -static inline void convert_VkGraphicsShaderGroupCreateInfoNV_win64_to_host(struct conversion_context *ctx, const VkGraphicsShaderGroupCreateInfoNV *in, VkGraphicsShaderGroupCreateInfoNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->stageCount = in->stageCount; - out->pStages = convert_VkPipelineShaderStageCreateInfo_array_win64_to_host(ctx, in->pStages, in->stageCount); - out->pVertexInputState = in->pVertexInputState; - out->pTessellationState = in->pTessellationState; -} -#endif /* _WIN64 */ - -static inline void convert_VkGraphicsShaderGroupCreateInfoNV_win32_to_host(struct conversion_context *ctx, const VkGraphicsShaderGroupCreateInfoNV32 *in, VkGraphicsShaderGroupCreateInfoNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->stageCount = in->stageCount; - out->pStages = convert_VkPipelineShaderStageCreateInfo_array_win32_to_host(ctx, (const VkPipelineShaderStageCreateInfo32 *)UlongToPtr(in->pStages), in->stageCount); - out->pVertexInputState = convert_VkPipelineVertexInputStateCreateInfo_array_win32_to_host(ctx, (const VkPipelineVertexInputStateCreateInfo32 *)UlongToPtr(in->pVertexInputState), 1); - out->pTessellationState = convert_VkPipelineTessellationStateCreateInfo_array_win32_to_host(ctx, (const VkPipelineTessellationStateCreateInfo32 *)UlongToPtr(in->pTessellationState), 1); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -#ifdef _WIN64 -static inline const VkGraphicsShaderGroupCreateInfoNV *convert_VkGraphicsShaderGroupCreateInfoNV_array_win64_to_host(struct conversion_context *ctx, const VkGraphicsShaderGroupCreateInfoNV *in, uint32_t count) -{ - VkGraphicsShaderGroupCreateInfoNV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkGraphicsShaderGroupCreateInfoNV_win64_to_host(ctx, &in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkGraphicsShaderGroupCreateInfoNV *convert_VkGraphicsShaderGroupCreateInfoNV_array_win32_to_host(struct conversion_context *ctx, const VkGraphicsShaderGroupCreateInfoNV32 *in, uint32_t count) -{ - VkGraphicsShaderGroupCreateInfoNV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkGraphicsShaderGroupCreateInfoNV_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPipelineInputAssemblyStateCreateInfo_win32_to_host(const VkPipelineInputAssemblyStateCreateInfo32 *in, VkPipelineInputAssemblyStateCreateInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->topology = in->topology; - out->primitiveRestartEnable = in->primitiveRestartEnable; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkPipelineInputAssemblyStateCreateInfo *convert_VkPipelineInputAssemblyStateCreateInfo_array_win32_to_host(struct conversion_context *ctx, const VkPipelineInputAssemblyStateCreateInfo32 *in, uint32_t count) -{ - VkPipelineInputAssemblyStateCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPipelineInputAssemblyStateCreateInfo_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPipelineViewportStateCreateInfo_win32_to_host(struct conversion_context *ctx, const VkPipelineViewportStateCreateInfo32 *in, VkPipelineViewportStateCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->viewportCount = in->viewportCount; - out->pViewports = (const VkViewport *)UlongToPtr(in->pViewports); - out->scissorCount = in->scissorCount; - out->pScissors = (const VkRect2D *)UlongToPtr(in->pScissors); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV: - { - VkPipelineViewportWScalingStateCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineViewportWScalingStateCreateInfoNV32 *in_ext = (const VkPipelineViewportWScalingStateCreateInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->viewportWScalingEnable = in_ext->viewportWScalingEnable; - out_ext->viewportCount = in_ext->viewportCount; - out_ext->pViewportWScalings = (const VkViewportWScalingNV *)UlongToPtr(in_ext->pViewportWScalings); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV: - { - VkPipelineViewportSwizzleStateCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineViewportSwizzleStateCreateInfoNV32 *in_ext = (const VkPipelineViewportSwizzleStateCreateInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->viewportCount = in_ext->viewportCount; - out_ext->pViewportSwizzles = (const VkViewportSwizzleNV *)UlongToPtr(in_ext->pViewportSwizzles); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV: - { - VkPipelineViewportExclusiveScissorStateCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineViewportExclusiveScissorStateCreateInfoNV32 *in_ext = (const VkPipelineViewportExclusiveScissorStateCreateInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->exclusiveScissorCount = in_ext->exclusiveScissorCount; - out_ext->pExclusiveScissors = (const VkRect2D *)UlongToPtr(in_ext->pExclusiveScissors); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV: - { - VkPipelineViewportShadingRateImageStateCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineViewportShadingRateImageStateCreateInfoNV32 *in_ext = (const VkPipelineViewportShadingRateImageStateCreateInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->shadingRateImageEnable = in_ext->shadingRateImageEnable; - out_ext->viewportCount = in_ext->viewportCount; - out_ext->pShadingRatePalettes = convert_VkShadingRatePaletteNV_array_win32_to_host(ctx, (const VkShadingRatePaletteNV32 *)UlongToPtr(in_ext->pShadingRatePalettes), in_ext->viewportCount); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV: - { - VkPipelineViewportCoarseSampleOrderStateCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineViewportCoarseSampleOrderStateCreateInfoNV32 *in_ext = (const VkPipelineViewportCoarseSampleOrderStateCreateInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->sampleOrderType = in_ext->sampleOrderType; - out_ext->customSampleOrderCount = in_ext->customSampleOrderCount; - out_ext->pCustomSampleOrders = convert_VkCoarseSampleOrderCustomNV_array_win32_to_host(ctx, (const VkCoarseSampleOrderCustomNV32 *)UlongToPtr(in_ext->pCustomSampleOrders), in_ext->customSampleOrderCount); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT: - { - VkPipelineViewportDepthClipControlCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineViewportDepthClipControlCreateInfoEXT32 *in_ext = (const VkPipelineViewportDepthClipControlCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->negativeOneToOne = in_ext->negativeOneToOne; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkPipelineViewportStateCreateInfo *convert_VkPipelineViewportStateCreateInfo_array_win32_to_host(struct conversion_context *ctx, const VkPipelineViewportStateCreateInfo32 *in, uint32_t count) -{ - VkPipelineViewportStateCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPipelineViewportStateCreateInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPipelineRasterizationStateCreateInfo_win32_to_host(struct conversion_context *ctx, const VkPipelineRasterizationStateCreateInfo32 *in, VkPipelineRasterizationStateCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->depthClampEnable = in->depthClampEnable; - out->rasterizerDiscardEnable = in->rasterizerDiscardEnable; - out->polygonMode = in->polygonMode; - out->cullMode = in->cullMode; - out->frontFace = in->frontFace; - out->depthBiasEnable = in->depthBiasEnable; - out->depthBiasConstantFactor = in->depthBiasConstantFactor; - out->depthBiasClamp = in->depthBiasClamp; - out->depthBiasSlopeFactor = in->depthBiasSlopeFactor; - out->lineWidth = in->lineWidth; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD: - { - VkPipelineRasterizationStateRasterizationOrderAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineRasterizationStateRasterizationOrderAMD32 *in_ext = (const VkPipelineRasterizationStateRasterizationOrderAMD32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD; - out_ext->pNext = NULL; - out_ext->rasterizationOrder = in_ext->rasterizationOrder; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT: - { - VkPipelineRasterizationConservativeStateCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineRasterizationConservativeStateCreateInfoEXT32 *in_ext = (const VkPipelineRasterizationConservativeStateCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->conservativeRasterizationMode = in_ext->conservativeRasterizationMode; - out_ext->extraPrimitiveOverestimationSize = in_ext->extraPrimitiveOverestimationSize; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT: - { - VkPipelineRasterizationStateStreamCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineRasterizationStateStreamCreateInfoEXT32 *in_ext = (const VkPipelineRasterizationStateStreamCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->rasterizationStream = in_ext->rasterizationStream; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT: - { - VkPipelineRasterizationDepthClipStateCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineRasterizationDepthClipStateCreateInfoEXT32 *in_ext = (const VkPipelineRasterizationDepthClipStateCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->depthClipEnable = in_ext->depthClipEnable; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT: - { - VkPipelineRasterizationLineStateCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineRasterizationLineStateCreateInfoEXT32 *in_ext = (const VkPipelineRasterizationLineStateCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->lineRasterizationMode = in_ext->lineRasterizationMode; - out_ext->stippledLineEnable = in_ext->stippledLineEnable; - out_ext->lineStippleFactor = in_ext->lineStippleFactor; - out_ext->lineStipplePattern = in_ext->lineStipplePattern; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT: - { - VkPipelineRasterizationProvokingVertexStateCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT32 *in_ext = (const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->provokingVertexMode = in_ext->provokingVertexMode; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkPipelineRasterizationStateCreateInfo *convert_VkPipelineRasterizationStateCreateInfo_array_win32_to_host(struct conversion_context *ctx, const VkPipelineRasterizationStateCreateInfo32 *in, uint32_t count) -{ - VkPipelineRasterizationStateCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPipelineRasterizationStateCreateInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPipelineMultisampleStateCreateInfo_win32_to_host(struct conversion_context *ctx, const VkPipelineMultisampleStateCreateInfo32 *in, VkPipelineMultisampleStateCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->rasterizationSamples = in->rasterizationSamples; - out->sampleShadingEnable = in->sampleShadingEnable; - out->minSampleShading = in->minSampleShading; - out->pSampleMask = (const VkSampleMask *)UlongToPtr(in->pSampleMask); - out->alphaToCoverageEnable = in->alphaToCoverageEnable; - out->alphaToOneEnable = in->alphaToOneEnable; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV: - { - VkPipelineCoverageToColorStateCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineCoverageToColorStateCreateInfoNV32 *in_ext = (const VkPipelineCoverageToColorStateCreateInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->coverageToColorEnable = in_ext->coverageToColorEnable; - out_ext->coverageToColorLocation = in_ext->coverageToColorLocation; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT: - { - VkPipelineSampleLocationsStateCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineSampleLocationsStateCreateInfoEXT32 *in_ext = (const VkPipelineSampleLocationsStateCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->sampleLocationsEnable = in_ext->sampleLocationsEnable; - convert_VkSampleLocationsInfoEXT_win32_to_host(&in_ext->sampleLocationsInfo, &out_ext->sampleLocationsInfo); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV: - { - VkPipelineCoverageModulationStateCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineCoverageModulationStateCreateInfoNV32 *in_ext = (const VkPipelineCoverageModulationStateCreateInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->coverageModulationMode = in_ext->coverageModulationMode; - out_ext->coverageModulationTableEnable = in_ext->coverageModulationTableEnable; - out_ext->coverageModulationTableCount = in_ext->coverageModulationTableCount; - out_ext->pCoverageModulationTable = (const float *)UlongToPtr(in_ext->pCoverageModulationTable); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_REDUCTION_STATE_CREATE_INFO_NV: - { - VkPipelineCoverageReductionStateCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineCoverageReductionStateCreateInfoNV32 *in_ext = (const VkPipelineCoverageReductionStateCreateInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_REDUCTION_STATE_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->coverageReductionMode = in_ext->coverageReductionMode; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkPipelineMultisampleStateCreateInfo *convert_VkPipelineMultisampleStateCreateInfo_array_win32_to_host(struct conversion_context *ctx, const VkPipelineMultisampleStateCreateInfo32 *in, uint32_t count) -{ - VkPipelineMultisampleStateCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPipelineMultisampleStateCreateInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPipelineDepthStencilStateCreateInfo_win32_to_host(const VkPipelineDepthStencilStateCreateInfo32 *in, VkPipelineDepthStencilStateCreateInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->depthTestEnable = in->depthTestEnable; - out->depthWriteEnable = in->depthWriteEnable; - out->depthCompareOp = in->depthCompareOp; - out->depthBoundsTestEnable = in->depthBoundsTestEnable; - out->stencilTestEnable = in->stencilTestEnable; - out->front = in->front; - out->back = in->back; - out->minDepthBounds = in->minDepthBounds; - out->maxDepthBounds = in->maxDepthBounds; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkPipelineDepthStencilStateCreateInfo *convert_VkPipelineDepthStencilStateCreateInfo_array_win32_to_host(struct conversion_context *ctx, const VkPipelineDepthStencilStateCreateInfo32 *in, uint32_t count) -{ - VkPipelineDepthStencilStateCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPipelineDepthStencilStateCreateInfo_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPipelineColorBlendStateCreateInfo_win32_to_host(struct conversion_context *ctx, const VkPipelineColorBlendStateCreateInfo32 *in, VkPipelineColorBlendStateCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->logicOpEnable = in->logicOpEnable; - out->logicOp = in->logicOp; - out->attachmentCount = in->attachmentCount; - out->pAttachments = (const VkPipelineColorBlendAttachmentState *)UlongToPtr(in->pAttachments); - memcpy(out->blendConstants, in->blendConstants, 4 * sizeof(float)); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT: - { - VkPipelineColorBlendAdvancedStateCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineColorBlendAdvancedStateCreateInfoEXT32 *in_ext = (const VkPipelineColorBlendAdvancedStateCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->srcPremultiplied = in_ext->srcPremultiplied; - out_ext->dstPremultiplied = in_ext->dstPremultiplied; - out_ext->blendOverlap = in_ext->blendOverlap; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT: - { - VkPipelineColorWriteCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineColorWriteCreateInfoEXT32 *in_ext = (const VkPipelineColorWriteCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->attachmentCount = in_ext->attachmentCount; - out_ext->pColorWriteEnables = (const VkBool32 *)UlongToPtr(in_ext->pColorWriteEnables); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkPipelineColorBlendStateCreateInfo *convert_VkPipelineColorBlendStateCreateInfo_array_win32_to_host(struct conversion_context *ctx, const VkPipelineColorBlendStateCreateInfo32 *in, uint32_t count) -{ - VkPipelineColorBlendStateCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPipelineColorBlendStateCreateInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPipelineDynamicStateCreateInfo_win32_to_host(const VkPipelineDynamicStateCreateInfo32 *in, VkPipelineDynamicStateCreateInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->dynamicStateCount = in->dynamicStateCount; - out->pDynamicStates = (const VkDynamicState *)UlongToPtr(in->pDynamicStates); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkPipelineDynamicStateCreateInfo *convert_VkPipelineDynamicStateCreateInfo_array_win32_to_host(struct conversion_context *ctx, const VkPipelineDynamicStateCreateInfo32 *in, uint32_t count) -{ - VkPipelineDynamicStateCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPipelineDynamicStateCreateInfo_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -#ifdef _WIN64 -static inline void convert_VkGraphicsPipelineCreateInfo_win64_to_host(struct conversion_context *ctx, const VkGraphicsPipelineCreateInfo *in, VkGraphicsPipelineCreateInfo *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->stageCount = in->stageCount; - out->pStages = convert_VkPipelineShaderStageCreateInfo_array_win64_to_host(ctx, in->pStages, in->stageCount); - out->pVertexInputState = in->pVertexInputState; - out->pInputAssemblyState = in->pInputAssemblyState; - out->pTessellationState = in->pTessellationState; - out->pViewportState = in->pViewportState; - out->pRasterizationState = in->pRasterizationState; - out->pMultisampleState = in->pMultisampleState; - out->pDepthStencilState = in->pDepthStencilState; - out->pColorBlendState = in->pColorBlendState; - out->pDynamicState = in->pDynamicState; - out->layout = in->layout; - out->renderPass = in->renderPass; - out->subpass = in->subpass; - out->basePipelineHandle = in->basePipelineHandle; - out->basePipelineIndex = in->basePipelineIndex; - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV: - { - VkGraphicsPipelineShaderGroupsCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkGraphicsPipelineShaderGroupsCreateInfoNV *in_ext = (const VkGraphicsPipelineShaderGroupsCreateInfoNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->groupCount = in_ext->groupCount; - out_ext->pGroups = convert_VkGraphicsShaderGroupCreateInfoNV_array_win64_to_host(ctx, in_ext->pGroups, in_ext->groupCount); - out_ext->pipelineCount = in_ext->pipelineCount; - out_ext->pPipelines = in_ext->pPipelines; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT: - { - VkPipelineDiscardRectangleStateCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineDiscardRectangleStateCreateInfoEXT *in_ext = (const VkPipelineDiscardRectangleStateCreateInfoEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->discardRectangleMode = in_ext->discardRectangleMode; - out_ext->discardRectangleCount = in_ext->discardRectangleCount; - out_ext->pDiscardRectangles = in_ext->pDiscardRectangles; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV: - { - VkPipelineRepresentativeFragmentTestStateCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineRepresentativeFragmentTestStateCreateInfoNV *in_ext = (const VkPipelineRepresentativeFragmentTestStateCreateInfoNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->representativeFragmentTestEnable = in_ext->representativeFragmentTestEnable; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO: - { - VkPipelineCreationFeedbackCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineCreationFeedbackCreateInfo *in_ext = (const VkPipelineCreationFeedbackCreateInfo *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->pPipelineCreationFeedback = in_ext->pPipelineCreationFeedback; - out_ext->pipelineStageCreationFeedbackCount = in_ext->pipelineStageCreationFeedbackCount; - out_ext->pPipelineStageCreationFeedbacks = in_ext->pPipelineStageCreationFeedbacks; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD: - { - VkPipelineCompilerControlCreateInfoAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineCompilerControlCreateInfoAMD *in_ext = (const VkPipelineCompilerControlCreateInfoAMD *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD; - out_ext->pNext = NULL; - out_ext->compilerControlFlags = in_ext->compilerControlFlags; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR: - { - VkPipelineLibraryCreateInfoKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineLibraryCreateInfoKHR *in_ext = (const VkPipelineLibraryCreateInfoKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR; - out_ext->pNext = NULL; - out_ext->libraryCount = in_ext->libraryCount; - out_ext->pLibraries = in_ext->pLibraries; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR: - { - VkPipelineFragmentShadingRateStateCreateInfoKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineFragmentShadingRateStateCreateInfoKHR *in_ext = (const VkPipelineFragmentShadingRateStateCreateInfoKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR; - out_ext->pNext = NULL; - out_ext->fragmentSize = in_ext->fragmentSize; - memcpy(out_ext->combinerOps, in_ext->combinerOps, 2 * sizeof(VkFragmentShadingRateCombinerOpKHR)); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_ENUM_STATE_CREATE_INFO_NV: - { - VkPipelineFragmentShadingRateEnumStateCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineFragmentShadingRateEnumStateCreateInfoNV *in_ext = (const VkPipelineFragmentShadingRateEnumStateCreateInfoNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_ENUM_STATE_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->shadingRateType = in_ext->shadingRateType; - out_ext->shadingRate = in_ext->shadingRate; - memcpy(out_ext->combinerOps, in_ext->combinerOps, 2 * sizeof(VkFragmentShadingRateCombinerOpKHR)); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO: - { - VkPipelineRenderingCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineRenderingCreateInfo *in_ext = (const VkPipelineRenderingCreateInfo *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->viewMask = in_ext->viewMask; - out_ext->colorAttachmentCount = in_ext->colorAttachmentCount; - out_ext->pColorAttachmentFormats = in_ext->pColorAttachmentFormats; - out_ext->depthAttachmentFormat = in_ext->depthAttachmentFormat; - out_ext->stencilAttachmentFormat = in_ext->stencilAttachmentFormat; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD: - { - VkAttachmentSampleCountInfoAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkAttachmentSampleCountInfoAMD *in_ext = (const VkAttachmentSampleCountInfoAMD *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD; - out_ext->pNext = NULL; - out_ext->colorAttachmentCount = in_ext->colorAttachmentCount; - out_ext->pColorAttachmentSamples = in_ext->pColorAttachmentSamples; - out_ext->depthStencilAttachmentSamples = in_ext->depthStencilAttachmentSamples; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_ATTRIBUTES_INFO_NVX: - { - VkMultiviewPerViewAttributesInfoNVX *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkMultiviewPerViewAttributesInfoNVX *in_ext = (const VkMultiviewPerViewAttributesInfoNVX *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_ATTRIBUTES_INFO_NVX; - out_ext->pNext = NULL; - out_ext->perViewAttributes = in_ext->perViewAttributes; - out_ext->perViewAttributesPositionXOnly = in_ext->perViewAttributesPositionXOnly; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT: - { - VkGraphicsPipelineLibraryCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkGraphicsPipelineLibraryCreateInfoEXT *in_ext = (const VkGraphicsPipelineLibraryCreateInfoEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT: - { - VkPipelineRobustnessCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineRobustnessCreateInfoEXT *in_ext = (const VkPipelineRobustnessCreateInfoEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->storageBuffers = in_ext->storageBuffers; - out_ext->uniformBuffers = in_ext->uniformBuffers; - out_ext->vertexInputs = in_ext->vertexInputs; - out_ext->images = in_ext->images; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} -#endif /* _WIN64 */ - -static inline void convert_VkGraphicsPipelineCreateInfo_win32_to_host(struct conversion_context *ctx, const VkGraphicsPipelineCreateInfo32 *in, VkGraphicsPipelineCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->stageCount = in->stageCount; - out->pStages = convert_VkPipelineShaderStageCreateInfo_array_win32_to_host(ctx, (const VkPipelineShaderStageCreateInfo32 *)UlongToPtr(in->pStages), in->stageCount); - out->pVertexInputState = convert_VkPipelineVertexInputStateCreateInfo_array_win32_to_host(ctx, (const VkPipelineVertexInputStateCreateInfo32 *)UlongToPtr(in->pVertexInputState), 1); - out->pInputAssemblyState = convert_VkPipelineInputAssemblyStateCreateInfo_array_win32_to_host(ctx, (const VkPipelineInputAssemblyStateCreateInfo32 *)UlongToPtr(in->pInputAssemblyState), 1); - out->pTessellationState = convert_VkPipelineTessellationStateCreateInfo_array_win32_to_host(ctx, (const VkPipelineTessellationStateCreateInfo32 *)UlongToPtr(in->pTessellationState), 1); - out->pViewportState = convert_VkPipelineViewportStateCreateInfo_array_win32_to_host(ctx, (const VkPipelineViewportStateCreateInfo32 *)UlongToPtr(in->pViewportState), 1); - out->pRasterizationState = convert_VkPipelineRasterizationStateCreateInfo_array_win32_to_host(ctx, (const VkPipelineRasterizationStateCreateInfo32 *)UlongToPtr(in->pRasterizationState), 1); - out->pMultisampleState = convert_VkPipelineMultisampleStateCreateInfo_array_win32_to_host(ctx, (const VkPipelineMultisampleStateCreateInfo32 *)UlongToPtr(in->pMultisampleState), 1); - out->pDepthStencilState = convert_VkPipelineDepthStencilStateCreateInfo_array_win32_to_host(ctx, (const VkPipelineDepthStencilStateCreateInfo32 *)UlongToPtr(in->pDepthStencilState), 1); - out->pColorBlendState = convert_VkPipelineColorBlendStateCreateInfo_array_win32_to_host(ctx, (const VkPipelineColorBlendStateCreateInfo32 *)UlongToPtr(in->pColorBlendState), 1); - out->pDynamicState = convert_VkPipelineDynamicStateCreateInfo_array_win32_to_host(ctx, (const VkPipelineDynamicStateCreateInfo32 *)UlongToPtr(in->pDynamicState), 1); - out->layout = in->layout; - out->renderPass = in->renderPass; - out->subpass = in->subpass; - out->basePipelineHandle = in->basePipelineHandle; - out->basePipelineIndex = in->basePipelineIndex; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV: - { - VkGraphicsPipelineShaderGroupsCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkGraphicsPipelineShaderGroupsCreateInfoNV32 *in_ext = (const VkGraphicsPipelineShaderGroupsCreateInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->groupCount = in_ext->groupCount; - out_ext->pGroups = convert_VkGraphicsShaderGroupCreateInfoNV_array_win32_to_host(ctx, (const VkGraphicsShaderGroupCreateInfoNV32 *)UlongToPtr(in_ext->pGroups), in_ext->groupCount); - out_ext->pipelineCount = in_ext->pipelineCount; - out_ext->pPipelines = (const VkPipeline *)UlongToPtr(in_ext->pPipelines); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT: - { - VkPipelineDiscardRectangleStateCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineDiscardRectangleStateCreateInfoEXT32 *in_ext = (const VkPipelineDiscardRectangleStateCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->discardRectangleMode = in_ext->discardRectangleMode; - out_ext->discardRectangleCount = in_ext->discardRectangleCount; - out_ext->pDiscardRectangles = (const VkRect2D *)UlongToPtr(in_ext->pDiscardRectangles); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV: - { - VkPipelineRepresentativeFragmentTestStateCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineRepresentativeFragmentTestStateCreateInfoNV32 *in_ext = (const VkPipelineRepresentativeFragmentTestStateCreateInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->representativeFragmentTestEnable = in_ext->representativeFragmentTestEnable; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO: - { - VkPipelineCreationFeedbackCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineCreationFeedbackCreateInfo32 *in_ext = (const VkPipelineCreationFeedbackCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->pPipelineCreationFeedback = convert_VkPipelineCreationFeedback_array_win32_to_host(ctx, (VkPipelineCreationFeedback32 *)UlongToPtr(in_ext->pPipelineCreationFeedback), 1); - out_ext->pipelineStageCreationFeedbackCount = in_ext->pipelineStageCreationFeedbackCount; - out_ext->pPipelineStageCreationFeedbacks = convert_VkPipelineCreationFeedback_array_win32_to_host(ctx, (VkPipelineCreationFeedback32 *)UlongToPtr(in_ext->pPipelineStageCreationFeedbacks), in_ext->pipelineStageCreationFeedbackCount); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD: - { - VkPipelineCompilerControlCreateInfoAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineCompilerControlCreateInfoAMD32 *in_ext = (const VkPipelineCompilerControlCreateInfoAMD32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD; - out_ext->pNext = NULL; - out_ext->compilerControlFlags = in_ext->compilerControlFlags; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR: - { - VkPipelineLibraryCreateInfoKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineLibraryCreateInfoKHR32 *in_ext = (const VkPipelineLibraryCreateInfoKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR; - out_ext->pNext = NULL; - out_ext->libraryCount = in_ext->libraryCount; - out_ext->pLibraries = (const VkPipeline *)UlongToPtr(in_ext->pLibraries); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR: - { - VkPipelineFragmentShadingRateStateCreateInfoKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineFragmentShadingRateStateCreateInfoKHR32 *in_ext = (const VkPipelineFragmentShadingRateStateCreateInfoKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR; - out_ext->pNext = NULL; - out_ext->fragmentSize = in_ext->fragmentSize; - memcpy(out_ext->combinerOps, in_ext->combinerOps, 2 * sizeof(VkFragmentShadingRateCombinerOpKHR)); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_ENUM_STATE_CREATE_INFO_NV: - { - VkPipelineFragmentShadingRateEnumStateCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineFragmentShadingRateEnumStateCreateInfoNV32 *in_ext = (const VkPipelineFragmentShadingRateEnumStateCreateInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_ENUM_STATE_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->shadingRateType = in_ext->shadingRateType; - out_ext->shadingRate = in_ext->shadingRate; - memcpy(out_ext->combinerOps, in_ext->combinerOps, 2 * sizeof(VkFragmentShadingRateCombinerOpKHR)); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO: - { - VkPipelineRenderingCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineRenderingCreateInfo32 *in_ext = (const VkPipelineRenderingCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->viewMask = in_ext->viewMask; - out_ext->colorAttachmentCount = in_ext->colorAttachmentCount; - out_ext->pColorAttachmentFormats = (const VkFormat *)UlongToPtr(in_ext->pColorAttachmentFormats); - out_ext->depthAttachmentFormat = in_ext->depthAttachmentFormat; - out_ext->stencilAttachmentFormat = in_ext->stencilAttachmentFormat; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD: - { - VkAttachmentSampleCountInfoAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkAttachmentSampleCountInfoAMD32 *in_ext = (const VkAttachmentSampleCountInfoAMD32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD; - out_ext->pNext = NULL; - out_ext->colorAttachmentCount = in_ext->colorAttachmentCount; - out_ext->pColorAttachmentSamples = (const VkSampleCountFlagBits *)UlongToPtr(in_ext->pColorAttachmentSamples); - out_ext->depthStencilAttachmentSamples = in_ext->depthStencilAttachmentSamples; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_ATTRIBUTES_INFO_NVX: - { - VkMultiviewPerViewAttributesInfoNVX *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkMultiviewPerViewAttributesInfoNVX32 *in_ext = (const VkMultiviewPerViewAttributesInfoNVX32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_ATTRIBUTES_INFO_NVX; - out_ext->pNext = NULL; - out_ext->perViewAttributes = in_ext->perViewAttributes; - out_ext->perViewAttributesPositionXOnly = in_ext->perViewAttributesPositionXOnly; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT: - { - VkGraphicsPipelineLibraryCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkGraphicsPipelineLibraryCreateInfoEXT32 *in_ext = (const VkGraphicsPipelineLibraryCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT: - { - VkPipelineRobustnessCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineRobustnessCreateInfoEXT32 *in_ext = (const VkPipelineRobustnessCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->storageBuffers = in_ext->storageBuffers; - out_ext->uniformBuffers = in_ext->uniformBuffers; - out_ext->vertexInputs = in_ext->vertexInputs; - out_ext->images = in_ext->images; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkGraphicsPipelineCreateInfo_host_to_win32(const VkGraphicsPipelineCreateInfo *in, const VkGraphicsPipelineCreateInfo32 *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure32 *out_header = (void *)out; - - if (!in) return; - - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO: - { - VkPipelineCreationFeedbackCreateInfo32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO); - const VkPipelineCreationFeedbackCreateInfo *in_ext = (const VkPipelineCreationFeedbackCreateInfo *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO; - convert_VkPipelineCreationFeedback_array_host_to_win32(in_ext->pPipelineCreationFeedback, (VkPipelineCreationFeedback32 *)UlongToPtr(out_ext->pPipelineCreationFeedback), 1); - convert_VkPipelineCreationFeedback_array_host_to_win32(in_ext->pPipelineStageCreationFeedbacks, (VkPipelineCreationFeedback32 *)UlongToPtr(out_ext->pPipelineStageCreationFeedbacks), in_ext->pipelineStageCreationFeedbackCount); - out_header = (void *)out_ext; - break; - } - default: - break; - } - } -} - -#ifdef _WIN64 -static inline const VkGraphicsPipelineCreateInfo *convert_VkGraphicsPipelineCreateInfo_array_win64_to_host(struct conversion_context *ctx, const VkGraphicsPipelineCreateInfo *in, uint32_t count) -{ - VkGraphicsPipelineCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkGraphicsPipelineCreateInfo_win64_to_host(ctx, &in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkGraphicsPipelineCreateInfo *convert_VkGraphicsPipelineCreateInfo_array_win32_to_host(struct conversion_context *ctx, const VkGraphicsPipelineCreateInfo32 *in, uint32_t count) -{ - VkGraphicsPipelineCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkGraphicsPipelineCreateInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkGraphicsPipelineCreateInfo_array_host_to_win32(const VkGraphicsPipelineCreateInfo *in, const VkGraphicsPipelineCreateInfo32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkGraphicsPipelineCreateInfo_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkImageCreateInfo_win32_to_host(struct conversion_context *ctx, const VkImageCreateInfo32 *in, VkImageCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->imageType = in->imageType; - out->format = in->format; - out->extent = in->extent; - out->mipLevels = in->mipLevels; - out->arrayLayers = in->arrayLayers; - out->samples = in->samples; - out->tiling = in->tiling; - out->usage = in->usage; - out->sharingMode = in->sharingMode; - out->queueFamilyIndexCount = in->queueFamilyIndexCount; - out->pQueueFamilyIndices = (const uint32_t *)UlongToPtr(in->pQueueFamilyIndices); - out->initialLayout = in->initialLayout; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV: - { - VkDedicatedAllocationImageCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDedicatedAllocationImageCreateInfoNV32 *in_ext = (const VkDedicatedAllocationImageCreateInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->dedicatedAllocation = in_ext->dedicatedAllocation; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO: - { - VkExternalMemoryImageCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkExternalMemoryImageCreateInfo32 *in_ext = (const VkExternalMemoryImageCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->handleTypes = in_ext->handleTypes; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR: - { - VkImageSwapchainCreateInfoKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkImageSwapchainCreateInfoKHR32 *in_ext = (const VkImageSwapchainCreateInfoKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR; - out_ext->pNext = NULL; - out_ext->swapchain = in_ext->swapchain; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO: - { - VkImageFormatListCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkImageFormatListCreateInfo32 *in_ext = (const VkImageFormatListCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->viewFormatCount = in_ext->viewFormatCount; - out_ext->pViewFormats = (const VkFormat *)UlongToPtr(in_ext->pViewFormats); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO: - { - VkImageStencilUsageCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkImageStencilUsageCreateInfo32 *in_ext = (const VkImageStencilUsageCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->stencilUsage = in_ext->stencilUsage; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT: - { - VkOpaqueCaptureDescriptorDataCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkOpaqueCaptureDescriptorDataCreateInfoEXT32 *in_ext = (const VkOpaqueCaptureDescriptorDataCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->opaqueCaptureDescriptorData = (const void *)UlongToPtr(in_ext->opaqueCaptureDescriptorData); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: - { - VkImageCompressionControlEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkImageCompressionControlEXT32 *in_ext = (const VkImageCompressionControlEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->compressionControlPlaneCount = in_ext->compressionControlPlaneCount; - out_ext->pFixedRateFlags = (VkImageCompressionFixedRateFlagsEXT *)UlongToPtr(in_ext->pFixedRateFlags); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_INFO_NV: - { - VkOpticalFlowImageFormatInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkOpticalFlowImageFormatInfoNV32 *in_ext = (const VkOpticalFlowImageFormatInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_INFO_NV; - out_ext->pNext = NULL; - out_ext->usage = in_ext->usage; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkImageViewCreateInfo_win32_to_host(struct conversion_context *ctx, const VkImageViewCreateInfo32 *in, VkImageViewCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->image = in->image; - out->viewType = in->viewType; - out->format = in->format; - out->components = in->components; - out->subresourceRange = in->subresourceRange; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO: - { - VkImageViewUsageCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkImageViewUsageCreateInfo32 *in_ext = (const VkImageViewUsageCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->usage = in_ext->usage; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO: - { - VkSamplerYcbcrConversionInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSamplerYcbcrConversionInfo32 *in_ext = (const VkSamplerYcbcrConversionInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO; - out_ext->pNext = NULL; - out_ext->conversion = in_ext->conversion; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT: - { - VkImageViewASTCDecodeModeEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkImageViewASTCDecodeModeEXT32 *in_ext = (const VkImageViewASTCDecodeModeEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT; - out_ext->pNext = NULL; - out_ext->decodeMode = in_ext->decodeMode; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT: - { - VkOpaqueCaptureDescriptorDataCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkOpaqueCaptureDescriptorDataCreateInfoEXT32 *in_ext = (const VkOpaqueCaptureDescriptorDataCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->opaqueCaptureDescriptorData = (const void *)UlongToPtr(in_ext->opaqueCaptureDescriptorData); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT: - { - VkImageViewMinLodCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkImageViewMinLodCreateInfoEXT32 *in_ext = (const VkImageViewMinLodCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->minLod = in_ext->minLod; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_IMAGE_VIEW_SAMPLE_WEIGHT_CREATE_INFO_QCOM: - { - VkImageViewSampleWeightCreateInfoQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkImageViewSampleWeightCreateInfoQCOM32 *in_ext = (const VkImageViewSampleWeightCreateInfoQCOM32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_SAMPLE_WEIGHT_CREATE_INFO_QCOM; - out_ext->pNext = NULL; - out_ext->filterCenter = in_ext->filterCenter; - out_ext->filterSize = in_ext->filterSize; - out_ext->numPhases = in_ext->numPhases; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkIndirectCommandsLayoutTokenNV_win32_to_host(const VkIndirectCommandsLayoutTokenNV32 *in, VkIndirectCommandsLayoutTokenNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->tokenType = in->tokenType; - out->stream = in->stream; - out->offset = in->offset; - out->vertexBindingUnit = in->vertexBindingUnit; - out->vertexDynamicStride = in->vertexDynamicStride; - out->pushconstantPipelineLayout = in->pushconstantPipelineLayout; - out->pushconstantShaderStageFlags = in->pushconstantShaderStageFlags; - out->pushconstantOffset = in->pushconstantOffset; - out->pushconstantSize = in->pushconstantSize; - out->indirectStateFlags = in->indirectStateFlags; - out->indexTypeCount = in->indexTypeCount; - out->pIndexTypes = (const VkIndexType *)UlongToPtr(in->pIndexTypes); - out->pIndexTypeValues = (const uint32_t *)UlongToPtr(in->pIndexTypeValues); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkIndirectCommandsLayoutTokenNV *convert_VkIndirectCommandsLayoutTokenNV_array_win32_to_host(struct conversion_context *ctx, const VkIndirectCommandsLayoutTokenNV32 *in, uint32_t count) -{ - VkIndirectCommandsLayoutTokenNV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkIndirectCommandsLayoutTokenNV_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkIndirectCommandsLayoutCreateInfoNV_win32_to_host(struct conversion_context *ctx, const VkIndirectCommandsLayoutCreateInfoNV32 *in, VkIndirectCommandsLayoutCreateInfoNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->pipelineBindPoint = in->pipelineBindPoint; - out->tokenCount = in->tokenCount; - out->pTokens = convert_VkIndirectCommandsLayoutTokenNV_array_win32_to_host(ctx, (const VkIndirectCommandsLayoutTokenNV32 *)UlongToPtr(in->pTokens), in->tokenCount); - out->streamCount = in->streamCount; - out->pStreamStrides = (const uint32_t *)UlongToPtr(in->pStreamStrides); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkApplicationInfo_win32_to_host(const VkApplicationInfo32 *in, VkApplicationInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->pApplicationName = (const char *)UlongToPtr(in->pApplicationName); - out->applicationVersion = in->applicationVersion; - out->pEngineName = (const char *)UlongToPtr(in->pEngineName); - out->engineVersion = in->engineVersion; - out->apiVersion = in->apiVersion; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkApplicationInfo *convert_VkApplicationInfo_array_win32_to_host(struct conversion_context *ctx, const VkApplicationInfo32 *in, uint32_t count) -{ - VkApplicationInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkApplicationInfo_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -#ifdef _WIN64 -static inline void convert_VkInstanceCreateInfo_win64_to_host(struct conversion_context *ctx, const VkInstanceCreateInfo *in, VkInstanceCreateInfo *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->pApplicationInfo = in->pApplicationInfo; - out->enabledLayerCount = in->enabledLayerCount; - out->ppEnabledLayerNames = in->ppEnabledLayerNames; - out->enabledExtensionCount = in->enabledExtensionCount; - out->ppEnabledExtensionNames = in->ppEnabledExtensionNames; - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO: - break; - case VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT: - { - VkDebugReportCallbackCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDebugReportCallbackCreateInfoEXT *in_ext = (const VkDebugReportCallbackCreateInfoEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->pfnCallback = in_ext->pfnCallback; - out_ext->pUserData = in_ext->pUserData; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT: - { - VkValidationFlagsEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkValidationFlagsEXT *in_ext = (const VkValidationFlagsEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT; - out_ext->pNext = NULL; - out_ext->disabledValidationCheckCount = in_ext->disabledValidationCheckCount; - out_ext->pDisabledValidationChecks = in_ext->pDisabledValidationChecks; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT: - { - VkValidationFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkValidationFeaturesEXT *in_ext = (const VkValidationFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->enabledValidationFeatureCount = in_ext->enabledValidationFeatureCount; - out_ext->pEnabledValidationFeatures = in_ext->pEnabledValidationFeatures; - out_ext->disabledValidationFeatureCount = in_ext->disabledValidationFeatureCount; - out_ext->pDisabledValidationFeatures = in_ext->pDisabledValidationFeatures; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT: - { - VkDebugUtilsMessengerCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDebugUtilsMessengerCreateInfoEXT *in_ext = (const VkDebugUtilsMessengerCreateInfoEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->messageSeverity = in_ext->messageSeverity; - out_ext->messageType = in_ext->messageType; - out_ext->pfnUserCallback = in_ext->pfnUserCallback; - out_ext->pUserData = in_ext->pUserData; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} -#endif /* _WIN64 */ - -static inline void convert_VkInstanceCreateInfo_win32_to_host(struct conversion_context *ctx, const VkInstanceCreateInfo32 *in, VkInstanceCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->pApplicationInfo = convert_VkApplicationInfo_array_win32_to_host(ctx, (const VkApplicationInfo32 *)UlongToPtr(in->pApplicationInfo), 1); - out->enabledLayerCount = in->enabledLayerCount; - out->ppEnabledLayerNames = convert_char_pointer_array_win32_to_host(ctx, (const PTR32 *)UlongToPtr(in->ppEnabledLayerNames), in->enabledLayerCount); - out->enabledExtensionCount = in->enabledExtensionCount; - out->ppEnabledExtensionNames = convert_char_pointer_array_win32_to_host(ctx, (const PTR32 *)UlongToPtr(in->ppEnabledExtensionNames), in->enabledExtensionCount); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO: - break; - case VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT: - { - VkDebugReportCallbackCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDebugReportCallbackCreateInfoEXT32 *in_ext = (const VkDebugReportCallbackCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->pfnCallback = in_ext->pfnCallback; - out_ext->pUserData = (void *)UlongToPtr(in_ext->pUserData); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT: - { - VkValidationFlagsEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkValidationFlagsEXT32 *in_ext = (const VkValidationFlagsEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT; - out_ext->pNext = NULL; - out_ext->disabledValidationCheckCount = in_ext->disabledValidationCheckCount; - out_ext->pDisabledValidationChecks = (const VkValidationCheckEXT *)UlongToPtr(in_ext->pDisabledValidationChecks); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT: - { - VkValidationFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkValidationFeaturesEXT32 *in_ext = (const VkValidationFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->enabledValidationFeatureCount = in_ext->enabledValidationFeatureCount; - out_ext->pEnabledValidationFeatures = (const VkValidationFeatureEnableEXT *)UlongToPtr(in_ext->pEnabledValidationFeatures); - out_ext->disabledValidationFeatureCount = in_ext->disabledValidationFeatureCount; - out_ext->pDisabledValidationFeatures = (const VkValidationFeatureDisableEXT *)UlongToPtr(in_ext->pDisabledValidationFeatures); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT: - { - VkDebugUtilsMessengerCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDebugUtilsMessengerCreateInfoEXT32 *in_ext = (const VkDebugUtilsMessengerCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->messageSeverity = in_ext->messageSeverity; - out_ext->messageType = in_ext->messageType; - out_ext->pfnUserCallback = in_ext->pfnUserCallback; - out_ext->pUserData = (void *)UlongToPtr(in_ext->pUserData); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkMicromapCreateInfoEXT_win32_to_host(const VkMicromapCreateInfoEXT32 *in, VkMicromapCreateInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->createFlags = in->createFlags; - out->buffer = in->buffer; - out->offset = in->offset; - out->size = in->size; - out->type = in->type; - out->deviceAddress = in->deviceAddress; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkOpticalFlowSessionCreateInfoNV_win32_to_host(struct conversion_context *ctx, const VkOpticalFlowSessionCreateInfoNV32 *in, VkOpticalFlowSessionCreateInfoNV *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->width = in->width; - out->height = in->height; - out->imageFormat = in->imageFormat; - out->flowVectorFormat = in->flowVectorFormat; - out->costFormat = in->costFormat; - out->outputGridSize = in->outputGridSize; - out->hintGridSize = in->hintGridSize; - out->performanceLevel = in->performanceLevel; - out->flags = in->flags; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_PRIVATE_DATA_INFO_NV: - { - VkOpticalFlowSessionCreatePrivateDataInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkOpticalFlowSessionCreatePrivateDataInfoNV32 *in_ext = (const VkOpticalFlowSessionCreatePrivateDataInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_PRIVATE_DATA_INFO_NV; - out_ext->pNext = NULL; - out_ext->id = in_ext->id; - out_ext->size = in_ext->size; - out_ext->pPrivateData = (const void *)UlongToPtr(in_ext->pPrivateData); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkPipelineCacheCreateInfo_win32_to_host(const VkPipelineCacheCreateInfo32 *in, VkPipelineCacheCreateInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->initialDataSize = in->initialDataSize; - out->pInitialData = (const void *)UlongToPtr(in->pInitialData); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkPipelineLayoutCreateInfo_win32_to_host(const VkPipelineLayoutCreateInfo32 *in, VkPipelineLayoutCreateInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->setLayoutCount = in->setLayoutCount; - out->pSetLayouts = (const VkDescriptorSetLayout *)UlongToPtr(in->pSetLayouts); - out->pushConstantRangeCount = in->pushConstantRangeCount; - out->pPushConstantRanges = (const VkPushConstantRange *)UlongToPtr(in->pPushConstantRanges); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkPrivateDataSlotCreateInfo_win32_to_host(const VkPrivateDataSlotCreateInfo32 *in, VkPrivateDataSlotCreateInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkQueryPoolCreateInfo_win32_to_host(struct conversion_context *ctx, const VkQueryPoolCreateInfo32 *in, VkQueryPoolCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->queryType = in->queryType; - out->queryCount = in->queryCount; - out->pipelineStatistics = in->pipelineStatistics; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_CREATE_INFO_KHR: - { - VkQueryPoolPerformanceCreateInfoKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkQueryPoolPerformanceCreateInfoKHR32 *in_ext = (const VkQueryPoolPerformanceCreateInfoKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_CREATE_INFO_KHR; - out_ext->pNext = NULL; - out_ext->queueFamilyIndex = in_ext->queueFamilyIndex; - out_ext->counterIndexCount = in_ext->counterIndexCount; - out_ext->pCounterIndices = (const uint32_t *)UlongToPtr(in_ext->pCounterIndices); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL: - { - VkQueryPoolPerformanceQueryCreateInfoINTEL *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkQueryPoolPerformanceQueryCreateInfoINTEL32 *in_ext = (const VkQueryPoolPerformanceQueryCreateInfoINTEL32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL; - out_ext->pNext = NULL; - out_ext->performanceCountersSampling = in_ext->performanceCountersSampling; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkRayTracingShaderGroupCreateInfoKHR_win32_to_host(const VkRayTracingShaderGroupCreateInfoKHR32 *in, VkRayTracingShaderGroupCreateInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->type = in->type; - out->generalShader = in->generalShader; - out->closestHitShader = in->closestHitShader; - out->anyHitShader = in->anyHitShader; - out->intersectionShader = in->intersectionShader; - out->pShaderGroupCaptureReplayHandle = (const void *)UlongToPtr(in->pShaderGroupCaptureReplayHandle); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkRayTracingShaderGroupCreateInfoKHR *convert_VkRayTracingShaderGroupCreateInfoKHR_array_win32_to_host(struct conversion_context *ctx, const VkRayTracingShaderGroupCreateInfoKHR32 *in, uint32_t count) -{ - VkRayTracingShaderGroupCreateInfoKHR *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkRayTracingShaderGroupCreateInfoKHR_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPipelineLibraryCreateInfoKHR_win32_to_host(const VkPipelineLibraryCreateInfoKHR32 *in, VkPipelineLibraryCreateInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->libraryCount = in->libraryCount; - out->pLibraries = (const VkPipeline *)UlongToPtr(in->pLibraries); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkPipelineLibraryCreateInfoKHR *convert_VkPipelineLibraryCreateInfoKHR_array_win32_to_host(struct conversion_context *ctx, const VkPipelineLibraryCreateInfoKHR32 *in, uint32_t count) -{ - VkPipelineLibraryCreateInfoKHR *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPipelineLibraryCreateInfoKHR_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkRayTracingPipelineInterfaceCreateInfoKHR_win32_to_host(const VkRayTracingPipelineInterfaceCreateInfoKHR32 *in, VkRayTracingPipelineInterfaceCreateInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->maxPipelineRayPayloadSize = in->maxPipelineRayPayloadSize; - out->maxPipelineRayHitAttributeSize = in->maxPipelineRayHitAttributeSize; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkRayTracingPipelineInterfaceCreateInfoKHR *convert_VkRayTracingPipelineInterfaceCreateInfoKHR_array_win32_to_host(struct conversion_context *ctx, const VkRayTracingPipelineInterfaceCreateInfoKHR32 *in, uint32_t count) -{ - VkRayTracingPipelineInterfaceCreateInfoKHR *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkRayTracingPipelineInterfaceCreateInfoKHR_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -#ifdef _WIN64 -static inline void convert_VkRayTracingPipelineCreateInfoKHR_win64_to_host(struct conversion_context *ctx, const VkRayTracingPipelineCreateInfoKHR *in, VkRayTracingPipelineCreateInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->flags = in->flags; - out->stageCount = in->stageCount; - out->pStages = convert_VkPipelineShaderStageCreateInfo_array_win64_to_host(ctx, in->pStages, in->stageCount); - out->groupCount = in->groupCount; - out->pGroups = in->pGroups; - out->maxPipelineRayRecursionDepth = in->maxPipelineRayRecursionDepth; - out->pLibraryInfo = in->pLibraryInfo; - out->pLibraryInterface = in->pLibraryInterface; - out->pDynamicState = in->pDynamicState; - out->layout = in->layout; - out->basePipelineHandle = in->basePipelineHandle; - out->basePipelineIndex = in->basePipelineIndex; -} -#endif /* _WIN64 */ - -static inline void convert_VkRayTracingPipelineCreateInfoKHR_win32_to_host(struct conversion_context *ctx, const VkRayTracingPipelineCreateInfoKHR32 *in, VkRayTracingPipelineCreateInfoKHR *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->stageCount = in->stageCount; - out->pStages = convert_VkPipelineShaderStageCreateInfo_array_win32_to_host(ctx, (const VkPipelineShaderStageCreateInfo32 *)UlongToPtr(in->pStages), in->stageCount); - out->groupCount = in->groupCount; - out->pGroups = convert_VkRayTracingShaderGroupCreateInfoKHR_array_win32_to_host(ctx, (const VkRayTracingShaderGroupCreateInfoKHR32 *)UlongToPtr(in->pGroups), in->groupCount); - out->maxPipelineRayRecursionDepth = in->maxPipelineRayRecursionDepth; - out->pLibraryInfo = convert_VkPipelineLibraryCreateInfoKHR_array_win32_to_host(ctx, (const VkPipelineLibraryCreateInfoKHR32 *)UlongToPtr(in->pLibraryInfo), 1); - out->pLibraryInterface = convert_VkRayTracingPipelineInterfaceCreateInfoKHR_array_win32_to_host(ctx, (const VkRayTracingPipelineInterfaceCreateInfoKHR32 *)UlongToPtr(in->pLibraryInterface), 1); - out->pDynamicState = convert_VkPipelineDynamicStateCreateInfo_array_win32_to_host(ctx, (const VkPipelineDynamicStateCreateInfo32 *)UlongToPtr(in->pDynamicState), 1); - out->layout = in->layout; - out->basePipelineHandle = in->basePipelineHandle; - out->basePipelineIndex = in->basePipelineIndex; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO: - { - VkPipelineCreationFeedbackCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineCreationFeedbackCreateInfo32 *in_ext = (const VkPipelineCreationFeedbackCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->pPipelineCreationFeedback = convert_VkPipelineCreationFeedback_array_win32_to_host(ctx, (VkPipelineCreationFeedback32 *)UlongToPtr(in_ext->pPipelineCreationFeedback), 1); - out_ext->pipelineStageCreationFeedbackCount = in_ext->pipelineStageCreationFeedbackCount; - out_ext->pPipelineStageCreationFeedbacks = convert_VkPipelineCreationFeedback_array_win32_to_host(ctx, (VkPipelineCreationFeedback32 *)UlongToPtr(in_ext->pPipelineStageCreationFeedbacks), in_ext->pipelineStageCreationFeedbackCount); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT: - { - VkPipelineRobustnessCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineRobustnessCreateInfoEXT32 *in_ext = (const VkPipelineRobustnessCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->storageBuffers = in_ext->storageBuffers; - out_ext->uniformBuffers = in_ext->uniformBuffers; - out_ext->vertexInputs = in_ext->vertexInputs; - out_ext->images = in_ext->images; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkRayTracingPipelineCreateInfoKHR_host_to_win32(const VkRayTracingPipelineCreateInfoKHR *in, const VkRayTracingPipelineCreateInfoKHR32 *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure32 *out_header = (void *)out; - - if (!in) return; - - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO: - { - VkPipelineCreationFeedbackCreateInfo32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO); - const VkPipelineCreationFeedbackCreateInfo *in_ext = (const VkPipelineCreationFeedbackCreateInfo *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO; - convert_VkPipelineCreationFeedback_array_host_to_win32(in_ext->pPipelineCreationFeedback, (VkPipelineCreationFeedback32 *)UlongToPtr(out_ext->pPipelineCreationFeedback), 1); - convert_VkPipelineCreationFeedback_array_host_to_win32(in_ext->pPipelineStageCreationFeedbacks, (VkPipelineCreationFeedback32 *)UlongToPtr(out_ext->pPipelineStageCreationFeedbacks), in_ext->pipelineStageCreationFeedbackCount); - out_header = (void *)out_ext; - break; - } - default: - break; - } - } -} - -#ifdef _WIN64 -static inline const VkRayTracingPipelineCreateInfoKHR *convert_VkRayTracingPipelineCreateInfoKHR_array_win64_to_host(struct conversion_context *ctx, const VkRayTracingPipelineCreateInfoKHR *in, uint32_t count) -{ - VkRayTracingPipelineCreateInfoKHR *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkRayTracingPipelineCreateInfoKHR_win64_to_host(ctx, &in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkRayTracingPipelineCreateInfoKHR *convert_VkRayTracingPipelineCreateInfoKHR_array_win32_to_host(struct conversion_context *ctx, const VkRayTracingPipelineCreateInfoKHR32 *in, uint32_t count) -{ - VkRayTracingPipelineCreateInfoKHR *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkRayTracingPipelineCreateInfoKHR_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkRayTracingPipelineCreateInfoKHR_array_host_to_win32(const VkRayTracingPipelineCreateInfoKHR *in, const VkRayTracingPipelineCreateInfoKHR32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkRayTracingPipelineCreateInfoKHR_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkRayTracingShaderGroupCreateInfoNV_win32_to_host(const VkRayTracingShaderGroupCreateInfoNV32 *in, VkRayTracingShaderGroupCreateInfoNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->type = in->type; - out->generalShader = in->generalShader; - out->closestHitShader = in->closestHitShader; - out->anyHitShader = in->anyHitShader; - out->intersectionShader = in->intersectionShader; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkRayTracingShaderGroupCreateInfoNV *convert_VkRayTracingShaderGroupCreateInfoNV_array_win32_to_host(struct conversion_context *ctx, const VkRayTracingShaderGroupCreateInfoNV32 *in, uint32_t count) -{ - VkRayTracingShaderGroupCreateInfoNV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkRayTracingShaderGroupCreateInfoNV_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -#ifdef _WIN64 -static inline void convert_VkRayTracingPipelineCreateInfoNV_win64_to_host(struct conversion_context *ctx, const VkRayTracingPipelineCreateInfoNV *in, VkRayTracingPipelineCreateInfoNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->flags = in->flags; - out->stageCount = in->stageCount; - out->pStages = convert_VkPipelineShaderStageCreateInfo_array_win64_to_host(ctx, in->pStages, in->stageCount); - out->groupCount = in->groupCount; - out->pGroups = in->pGroups; - out->maxRecursionDepth = in->maxRecursionDepth; - out->layout = in->layout; - out->basePipelineHandle = in->basePipelineHandle; - out->basePipelineIndex = in->basePipelineIndex; -} -#endif /* _WIN64 */ - -static inline void convert_VkRayTracingPipelineCreateInfoNV_win32_to_host(struct conversion_context *ctx, const VkRayTracingPipelineCreateInfoNV32 *in, VkRayTracingPipelineCreateInfoNV *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->stageCount = in->stageCount; - out->pStages = convert_VkPipelineShaderStageCreateInfo_array_win32_to_host(ctx, (const VkPipelineShaderStageCreateInfo32 *)UlongToPtr(in->pStages), in->stageCount); - out->groupCount = in->groupCount; - out->pGroups = convert_VkRayTracingShaderGroupCreateInfoNV_array_win32_to_host(ctx, (const VkRayTracingShaderGroupCreateInfoNV32 *)UlongToPtr(in->pGroups), in->groupCount); - out->maxRecursionDepth = in->maxRecursionDepth; - out->layout = in->layout; - out->basePipelineHandle = in->basePipelineHandle; - out->basePipelineIndex = in->basePipelineIndex; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO: - { - VkPipelineCreationFeedbackCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPipelineCreationFeedbackCreateInfo32 *in_ext = (const VkPipelineCreationFeedbackCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->pPipelineCreationFeedback = convert_VkPipelineCreationFeedback_array_win32_to_host(ctx, (VkPipelineCreationFeedback32 *)UlongToPtr(in_ext->pPipelineCreationFeedback), 1); - out_ext->pipelineStageCreationFeedbackCount = in_ext->pipelineStageCreationFeedbackCount; - out_ext->pPipelineStageCreationFeedbacks = convert_VkPipelineCreationFeedback_array_win32_to_host(ctx, (VkPipelineCreationFeedback32 *)UlongToPtr(in_ext->pPipelineStageCreationFeedbacks), in_ext->pipelineStageCreationFeedbackCount); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkRayTracingPipelineCreateInfoNV_host_to_win32(const VkRayTracingPipelineCreateInfoNV *in, const VkRayTracingPipelineCreateInfoNV32 *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure32 *out_header = (void *)out; - - if (!in) return; - - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO: - { - VkPipelineCreationFeedbackCreateInfo32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO); - const VkPipelineCreationFeedbackCreateInfo *in_ext = (const VkPipelineCreationFeedbackCreateInfo *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO; - convert_VkPipelineCreationFeedback_array_host_to_win32(in_ext->pPipelineCreationFeedback, (VkPipelineCreationFeedback32 *)UlongToPtr(out_ext->pPipelineCreationFeedback), 1); - convert_VkPipelineCreationFeedback_array_host_to_win32(in_ext->pPipelineStageCreationFeedbacks, (VkPipelineCreationFeedback32 *)UlongToPtr(out_ext->pPipelineStageCreationFeedbacks), in_ext->pipelineStageCreationFeedbackCount); - out_header = (void *)out_ext; - break; - } - default: - break; - } - } -} - -#ifdef _WIN64 -static inline const VkRayTracingPipelineCreateInfoNV *convert_VkRayTracingPipelineCreateInfoNV_array_win64_to_host(struct conversion_context *ctx, const VkRayTracingPipelineCreateInfoNV *in, uint32_t count) -{ - VkRayTracingPipelineCreateInfoNV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkRayTracingPipelineCreateInfoNV_win64_to_host(ctx, &in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkRayTracingPipelineCreateInfoNV *convert_VkRayTracingPipelineCreateInfoNV_array_win32_to_host(struct conversion_context *ctx, const VkRayTracingPipelineCreateInfoNV32 *in, uint32_t count) -{ - VkRayTracingPipelineCreateInfoNV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkRayTracingPipelineCreateInfoNV_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkRayTracingPipelineCreateInfoNV_array_host_to_win32(const VkRayTracingPipelineCreateInfoNV *in, const VkRayTracingPipelineCreateInfoNV32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkRayTracingPipelineCreateInfoNV_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkSubpassDescription_win32_to_host(const VkSubpassDescription32 *in, VkSubpassDescription *out) -{ - if (!in) return; - - out->flags = in->flags; - out->pipelineBindPoint = in->pipelineBindPoint; - out->inputAttachmentCount = in->inputAttachmentCount; - out->pInputAttachments = (const VkAttachmentReference *)UlongToPtr(in->pInputAttachments); - out->colorAttachmentCount = in->colorAttachmentCount; - out->pColorAttachments = (const VkAttachmentReference *)UlongToPtr(in->pColorAttachments); - out->pResolveAttachments = (const VkAttachmentReference *)UlongToPtr(in->pResolveAttachments); - out->pDepthStencilAttachment = (const VkAttachmentReference *)UlongToPtr(in->pDepthStencilAttachment); - out->preserveAttachmentCount = in->preserveAttachmentCount; - out->pPreserveAttachments = (const uint32_t *)UlongToPtr(in->pPreserveAttachments); -} - -static inline const VkSubpassDescription *convert_VkSubpassDescription_array_win32_to_host(struct conversion_context *ctx, const VkSubpassDescription32 *in, uint32_t count) -{ - VkSubpassDescription *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSubpassDescription_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkRenderPassCreateInfo_win32_to_host(struct conversion_context *ctx, const VkRenderPassCreateInfo32 *in, VkRenderPassCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->attachmentCount = in->attachmentCount; - out->pAttachments = (const VkAttachmentDescription *)UlongToPtr(in->pAttachments); - out->subpassCount = in->subpassCount; - out->pSubpasses = convert_VkSubpassDescription_array_win32_to_host(ctx, (const VkSubpassDescription32 *)UlongToPtr(in->pSubpasses), in->subpassCount); - out->dependencyCount = in->dependencyCount; - out->pDependencies = (const VkSubpassDependency *)UlongToPtr(in->pDependencies); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO: - { - VkRenderPassMultiviewCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkRenderPassMultiviewCreateInfo32 *in_ext = (const VkRenderPassMultiviewCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->subpassCount = in_ext->subpassCount; - out_ext->pViewMasks = (const uint32_t *)UlongToPtr(in_ext->pViewMasks); - out_ext->dependencyCount = in_ext->dependencyCount; - out_ext->pViewOffsets = (const int32_t *)UlongToPtr(in_ext->pViewOffsets); - out_ext->correlationMaskCount = in_ext->correlationMaskCount; - out_ext->pCorrelationMasks = (const uint32_t *)UlongToPtr(in_ext->pCorrelationMasks); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO: - { - VkRenderPassInputAttachmentAspectCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkRenderPassInputAttachmentAspectCreateInfo32 *in_ext = (const VkRenderPassInputAttachmentAspectCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->aspectReferenceCount = in_ext->aspectReferenceCount; - out_ext->pAspectReferences = (const VkInputAttachmentAspectReference *)UlongToPtr(in_ext->pAspectReferences); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT: - { - VkRenderPassFragmentDensityMapCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkRenderPassFragmentDensityMapCreateInfoEXT32 *in_ext = (const VkRenderPassFragmentDensityMapCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->fragmentDensityMapAttachment = in_ext->fragmentDensityMapAttachment; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkAttachmentDescription2_win32_to_host(struct conversion_context *ctx, const VkAttachmentDescription232 *in, VkAttachmentDescription2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->format = in->format; - out->samples = in->samples; - out->loadOp = in->loadOp; - out->storeOp = in->storeOp; - out->stencilLoadOp = in->stencilLoadOp; - out->stencilStoreOp = in->stencilStoreOp; - out->initialLayout = in->initialLayout; - out->finalLayout = in->finalLayout; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT: - { - VkAttachmentDescriptionStencilLayout *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkAttachmentDescriptionStencilLayout32 *in_ext = (const VkAttachmentDescriptionStencilLayout32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT; - out_ext->pNext = NULL; - out_ext->stencilInitialLayout = in_ext->stencilInitialLayout; - out_ext->stencilFinalLayout = in_ext->stencilFinalLayout; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkAttachmentDescription2 *convert_VkAttachmentDescription2_array_win32_to_host(struct conversion_context *ctx, const VkAttachmentDescription232 *in, uint32_t count) -{ - VkAttachmentDescription2 *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkAttachmentDescription2_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkAttachmentReference2_win32_to_host(struct conversion_context *ctx, const VkAttachmentReference232 *in, VkAttachmentReference2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->attachment = in->attachment; - out->layout = in->layout; - out->aspectMask = in->aspectMask; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT: - { - VkAttachmentReferenceStencilLayout *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkAttachmentReferenceStencilLayout32 *in_ext = (const VkAttachmentReferenceStencilLayout32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT; - out_ext->pNext = NULL; - out_ext->stencilLayout = in_ext->stencilLayout; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkAttachmentReference2 *convert_VkAttachmentReference2_array_win32_to_host(struct conversion_context *ctx, const VkAttachmentReference232 *in, uint32_t count) -{ - VkAttachmentReference2 *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkAttachmentReference2_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkSubpassDescription2_win32_to_host(struct conversion_context *ctx, const VkSubpassDescription232 *in, VkSubpassDescription2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->pipelineBindPoint = in->pipelineBindPoint; - out->viewMask = in->viewMask; - out->inputAttachmentCount = in->inputAttachmentCount; - out->pInputAttachments = convert_VkAttachmentReference2_array_win32_to_host(ctx, (const VkAttachmentReference232 *)UlongToPtr(in->pInputAttachments), in->inputAttachmentCount); - out->colorAttachmentCount = in->colorAttachmentCount; - out->pColorAttachments = convert_VkAttachmentReference2_array_win32_to_host(ctx, (const VkAttachmentReference232 *)UlongToPtr(in->pColorAttachments), in->colorAttachmentCount); - out->pResolveAttachments = convert_VkAttachmentReference2_array_win32_to_host(ctx, (const VkAttachmentReference232 *)UlongToPtr(in->pResolveAttachments), in->colorAttachmentCount); - out->pDepthStencilAttachment = convert_VkAttachmentReference2_array_win32_to_host(ctx, (const VkAttachmentReference232 *)UlongToPtr(in->pDepthStencilAttachment), 1); - out->preserveAttachmentCount = in->preserveAttachmentCount; - out->pPreserveAttachments = (const uint32_t *)UlongToPtr(in->pPreserveAttachments); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE: - { - VkSubpassDescriptionDepthStencilResolve *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSubpassDescriptionDepthStencilResolve32 *in_ext = (const VkSubpassDescriptionDepthStencilResolve32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE; - out_ext->pNext = NULL; - out_ext->depthResolveMode = in_ext->depthResolveMode; - out_ext->stencilResolveMode = in_ext->stencilResolveMode; - out_ext->pDepthStencilResolveAttachment = convert_VkAttachmentReference2_array_win32_to_host(ctx, (const VkAttachmentReference232 *)UlongToPtr(in_ext->pDepthStencilResolveAttachment), 1); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR: - { - VkFragmentShadingRateAttachmentInfoKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkFragmentShadingRateAttachmentInfoKHR32 *in_ext = (const VkFragmentShadingRateAttachmentInfoKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; - out_ext->pNext = NULL; - out_ext->pFragmentShadingRateAttachment = convert_VkAttachmentReference2_array_win32_to_host(ctx, (const VkAttachmentReference232 *)UlongToPtr(in_ext->pFragmentShadingRateAttachment), 1); - out_ext->shadingRateAttachmentTexelSize = in_ext->shadingRateAttachmentTexelSize; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_EXT: - { - VkMultisampledRenderToSingleSampledInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkMultisampledRenderToSingleSampledInfoEXT32 *in_ext = (const VkMultisampledRenderToSingleSampledInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_EXT; - out_ext->pNext = NULL; - out_ext->multisampledRenderToSingleSampledEnable = in_ext->multisampledRenderToSingleSampledEnable; - out_ext->rasterizationSamples = in_ext->rasterizationSamples; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_CONTROL_EXT: - { - VkRenderPassCreationControlEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkRenderPassCreationControlEXT32 *in_ext = (const VkRenderPassCreationControlEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_CONTROL_EXT; - out_ext->pNext = NULL; - out_ext->disallowMerging = in_ext->disallowMerging; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_RENDER_PASS_SUBPASS_FEEDBACK_CREATE_INFO_EXT: - { - VkRenderPassSubpassFeedbackCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkRenderPassSubpassFeedbackCreateInfoEXT32 *in_ext = (const VkRenderPassSubpassFeedbackCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_RENDER_PASS_SUBPASS_FEEDBACK_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->pSubpassFeedback = (VkRenderPassSubpassFeedbackInfoEXT *)UlongToPtr(in_ext->pSubpassFeedback); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkSubpassDescription2 *convert_VkSubpassDescription2_array_win32_to_host(struct conversion_context *ctx, const VkSubpassDescription232 *in, uint32_t count) -{ - VkSubpassDescription2 *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSubpassDescription2_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkSubpassDependency2_win32_to_host(struct conversion_context *ctx, const VkSubpassDependency232 *in, VkSubpassDependency2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcSubpass = in->srcSubpass; - out->dstSubpass = in->dstSubpass; - out->srcStageMask = in->srcStageMask; - out->dstStageMask = in->dstStageMask; - out->srcAccessMask = in->srcAccessMask; - out->dstAccessMask = in->dstAccessMask; - out->dependencyFlags = in->dependencyFlags; - out->viewOffset = in->viewOffset; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_MEMORY_BARRIER_2: - { - VkMemoryBarrier2 *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkMemoryBarrier232 *in_ext = (const VkMemoryBarrier232 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2; - out_ext->pNext = NULL; - out_ext->srcStageMask = in_ext->srcStageMask; - out_ext->srcAccessMask = in_ext->srcAccessMask; - out_ext->dstStageMask = in_ext->dstStageMask; - out_ext->dstAccessMask = in_ext->dstAccessMask; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline const VkSubpassDependency2 *convert_VkSubpassDependency2_array_win32_to_host(struct conversion_context *ctx, const VkSubpassDependency232 *in, uint32_t count) -{ - VkSubpassDependency2 *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSubpassDependency2_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkRenderPassCreateInfo2_win32_to_host(struct conversion_context *ctx, const VkRenderPassCreateInfo232 *in, VkRenderPassCreateInfo2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->attachmentCount = in->attachmentCount; - out->pAttachments = convert_VkAttachmentDescription2_array_win32_to_host(ctx, (const VkAttachmentDescription232 *)UlongToPtr(in->pAttachments), in->attachmentCount); - out->subpassCount = in->subpassCount; - out->pSubpasses = convert_VkSubpassDescription2_array_win32_to_host(ctx, (const VkSubpassDescription232 *)UlongToPtr(in->pSubpasses), in->subpassCount); - out->dependencyCount = in->dependencyCount; - out->pDependencies = convert_VkSubpassDependency2_array_win32_to_host(ctx, (const VkSubpassDependency232 *)UlongToPtr(in->pDependencies), in->dependencyCount); - out->correlatedViewMaskCount = in->correlatedViewMaskCount; - out->pCorrelatedViewMasks = (const uint32_t *)UlongToPtr(in->pCorrelatedViewMasks); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT: - { - VkRenderPassFragmentDensityMapCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkRenderPassFragmentDensityMapCreateInfoEXT32 *in_ext = (const VkRenderPassFragmentDensityMapCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->fragmentDensityMapAttachment = in_ext->fragmentDensityMapAttachment; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_CONTROL_EXT: - { - VkRenderPassCreationControlEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkRenderPassCreationControlEXT32 *in_ext = (const VkRenderPassCreationControlEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_CONTROL_EXT; - out_ext->pNext = NULL; - out_ext->disallowMerging = in_ext->disallowMerging; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_FEEDBACK_CREATE_INFO_EXT: - { - VkRenderPassCreationFeedbackCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkRenderPassCreationFeedbackCreateInfoEXT32 *in_ext = (const VkRenderPassCreationFeedbackCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_FEEDBACK_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->pRenderPassFeedback = (VkRenderPassCreationFeedbackInfoEXT *)UlongToPtr(in_ext->pRenderPassFeedback); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkSamplerCreateInfo_win32_to_host(struct conversion_context *ctx, const VkSamplerCreateInfo32 *in, VkSamplerCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->magFilter = in->magFilter; - out->minFilter = in->minFilter; - out->mipmapMode = in->mipmapMode; - out->addressModeU = in->addressModeU; - out->addressModeV = in->addressModeV; - out->addressModeW = in->addressModeW; - out->mipLodBias = in->mipLodBias; - out->anisotropyEnable = in->anisotropyEnable; - out->maxAnisotropy = in->maxAnisotropy; - out->compareEnable = in->compareEnable; - out->compareOp = in->compareOp; - out->minLod = in->minLod; - out->maxLod = in->maxLod; - out->borderColor = in->borderColor; - out->unnormalizedCoordinates = in->unnormalizedCoordinates; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO: - { - VkSamplerYcbcrConversionInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSamplerYcbcrConversionInfo32 *in_ext = (const VkSamplerYcbcrConversionInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO; - out_ext->pNext = NULL; - out_ext->conversion = in_ext->conversion; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO: - { - VkSamplerReductionModeCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSamplerReductionModeCreateInfo32 *in_ext = (const VkSamplerReductionModeCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->reductionMode = in_ext->reductionMode; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT: - { - VkSamplerCustomBorderColorCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSamplerCustomBorderColorCreateInfoEXT32 *in_ext = (const VkSamplerCustomBorderColorCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->customBorderColor = in_ext->customBorderColor; - out_ext->format = in_ext->format; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT: - { - VkSamplerBorderColorComponentMappingCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSamplerBorderColorComponentMappingCreateInfoEXT32 *in_ext = (const VkSamplerBorderColorComponentMappingCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->components = in_ext->components; - out_ext->srgb = in_ext->srgb; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT: - { - VkOpaqueCaptureDescriptorDataCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkOpaqueCaptureDescriptorDataCreateInfoEXT32 *in_ext = (const VkOpaqueCaptureDescriptorDataCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->opaqueCaptureDescriptorData = (const void *)UlongToPtr(in_ext->opaqueCaptureDescriptorData); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkSamplerYcbcrConversionCreateInfo_win32_to_host(const VkSamplerYcbcrConversionCreateInfo32 *in, VkSamplerYcbcrConversionCreateInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->format = in->format; - out->ycbcrModel = in->ycbcrModel; - out->ycbcrRange = in->ycbcrRange; - out->components = in->components; - out->xChromaOffset = in->xChromaOffset; - out->yChromaOffset = in->yChromaOffset; - out->chromaFilter = in->chromaFilter; - out->forceExplicitReconstruction = in->forceExplicitReconstruction; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkSemaphoreCreateInfo_win32_to_host(struct conversion_context *ctx, const VkSemaphoreCreateInfo32 *in, VkSemaphoreCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO: - { - VkExportSemaphoreCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkExportSemaphoreCreateInfo32 *in_ext = (const VkExportSemaphoreCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->handleTypes = in_ext->handleTypes; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO: - { - VkSemaphoreTypeCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSemaphoreTypeCreateInfo32 *in_ext = (const VkSemaphoreTypeCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->semaphoreType = in_ext->semaphoreType; - out_ext->initialValue = in_ext->initialValue; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkShaderModuleCreateInfo_win32_to_host(struct conversion_context *ctx, const VkShaderModuleCreateInfo32 *in, VkShaderModuleCreateInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->codeSize = in->codeSize; - out->pCode = (const uint32_t *)UlongToPtr(in->pCode); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT: - { - VkShaderModuleValidationCacheCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkShaderModuleValidationCacheCreateInfoEXT32 *in_ext = (const VkShaderModuleValidationCacheCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->validationCache = in_ext->validationCache; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -#ifdef _WIN64 -static inline void convert_VkSwapchainCreateInfoKHR_win64_to_host(const VkSwapchainCreateInfoKHR *in, VkSwapchainCreateInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->flags = in->flags; - out->surface = wine_surface_from_handle(in->surface)->driver_surface; - out->minImageCount = in->minImageCount; - out->imageFormat = in->imageFormat; - out->imageColorSpace = in->imageColorSpace; - out->imageExtent = in->imageExtent; - out->imageArrayLayers = in->imageArrayLayers; - out->imageUsage = in->imageUsage; - out->imageSharingMode = in->imageSharingMode; - out->queueFamilyIndexCount = in->queueFamilyIndexCount; - out->pQueueFamilyIndices = in->pQueueFamilyIndices; - out->preTransform = in->preTransform; - out->compositeAlpha = in->compositeAlpha; - out->presentMode = in->presentMode; - out->clipped = in->clipped; - out->oldSwapchain = in->oldSwapchain; -} -#endif /* _WIN64 */ - -static inline void convert_VkSwapchainCreateInfoKHR_win32_to_host(struct conversion_context *ctx, const VkSwapchainCreateInfoKHR32 *in, VkSwapchainCreateInfoKHR *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->surface = wine_surface_from_handle(in->surface)->driver_surface; - out->minImageCount = in->minImageCount; - out->imageFormat = in->imageFormat; - out->imageColorSpace = in->imageColorSpace; - out->imageExtent = in->imageExtent; - out->imageArrayLayers = in->imageArrayLayers; - out->imageUsage = in->imageUsage; - out->imageSharingMode = in->imageSharingMode; - out->queueFamilyIndexCount = in->queueFamilyIndexCount; - out->pQueueFamilyIndices = (const uint32_t *)UlongToPtr(in->pQueueFamilyIndices); - out->preTransform = in->preTransform; - out->compositeAlpha = in->compositeAlpha; - out->presentMode = in->presentMode; - out->clipped = in->clipped; - out->oldSwapchain = in->oldSwapchain; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR: - { - VkDeviceGroupSwapchainCreateInfoKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDeviceGroupSwapchainCreateInfoKHR32 *in_ext = (const VkDeviceGroupSwapchainCreateInfoKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR; - out_ext->pNext = NULL; - out_ext->modes = in_ext->modes; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO: - { - VkImageFormatListCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkImageFormatListCreateInfo32 *in_ext = (const VkImageFormatListCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->viewFormatCount = in_ext->viewFormatCount; - out_ext->pViewFormats = (const VkFormat *)UlongToPtr(in_ext->pViewFormats); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_BARRIER_CREATE_INFO_NV: - { - VkSwapchainPresentBarrierCreateInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSwapchainPresentBarrierCreateInfoNV32 *in_ext = (const VkSwapchainPresentBarrierCreateInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_BARRIER_CREATE_INFO_NV; - out_ext->pNext = NULL; - out_ext->presentBarrierEnable = in_ext->presentBarrierEnable; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: - { - VkImageCompressionControlEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkImageCompressionControlEXT32 *in_ext = (const VkImageCompressionControlEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->compressionControlPlaneCount = in_ext->compressionControlPlaneCount; - out_ext->pFixedRateFlags = (VkImageCompressionFixedRateFlagsEXT *)UlongToPtr(in_ext->pFixedRateFlags); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_EXT: - { - VkSwapchainPresentModesCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSwapchainPresentModesCreateInfoEXT32 *in_ext = (const VkSwapchainPresentModesCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->presentModeCount = in_ext->presentModeCount; - out_ext->pPresentModes = (const VkPresentModeKHR *)UlongToPtr(in_ext->pPresentModes); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_SCALING_CREATE_INFO_EXT: - { - VkSwapchainPresentScalingCreateInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSwapchainPresentScalingCreateInfoEXT32 *in_ext = (const VkSwapchainPresentScalingCreateInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_SCALING_CREATE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->scalingBehavior = in_ext->scalingBehavior; - out_ext->presentGravityX = in_ext->presentGravityX; - out_ext->presentGravityY = in_ext->presentGravityY; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkValidationCacheCreateInfoEXT_win32_to_host(const VkValidationCacheCreateInfoEXT32 *in, VkValidationCacheCreateInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->initialDataSize = in->initialDataSize; - out->pInitialData = (const void *)UlongToPtr(in->pInitialData); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkWin32SurfaceCreateInfoKHR_win32_to_host(const VkWin32SurfaceCreateInfoKHR32 *in, VkWin32SurfaceCreateInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->hinstance = (HINSTANCE)UlongToPtr(in->hinstance); - out->hwnd = (HWND)UlongToPtr(in->hwnd); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -#ifdef _WIN64 -static inline void convert_VkDebugMarkerObjectNameInfoEXT_win64_to_host(const VkDebugMarkerObjectNameInfoEXT *in, VkDebugMarkerObjectNameInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->objectType = in->objectType; - out->object = wine_vk_unwrap_handle(in->objectType, in->object); - out->pObjectName = in->pObjectName; -} -#endif /* _WIN64 */ - -static inline void convert_VkDebugMarkerObjectNameInfoEXT_win32_to_host(const VkDebugMarkerObjectNameInfoEXT32 *in, VkDebugMarkerObjectNameInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->objectType = in->objectType; - out->object = wine_vk_unwrap_handle(in->objectType, in->object); - out->pObjectName = (const char *)UlongToPtr(in->pObjectName); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -#ifdef _WIN64 -static inline void convert_VkDebugMarkerObjectTagInfoEXT_win64_to_host(const VkDebugMarkerObjectTagInfoEXT *in, VkDebugMarkerObjectTagInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->objectType = in->objectType; - out->object = wine_vk_unwrap_handle(in->objectType, in->object); - out->tagName = in->tagName; - out->tagSize = in->tagSize; - out->pTag = in->pTag; -} -#endif /* _WIN64 */ - -static inline void convert_VkDebugMarkerObjectTagInfoEXT_win32_to_host(const VkDebugMarkerObjectTagInfoEXT32 *in, VkDebugMarkerObjectTagInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->objectType = in->objectType; - out->object = wine_vk_unwrap_handle(in->objectType, in->object); - out->tagName = in->tagName; - out->tagSize = in->tagSize; - out->pTag = (const void *)UlongToPtr(in->pTag); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkPhysicalDevice_array_unwrapped_host_to_win32(const VkPhysicalDevice *in, PTR32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - out[i] = PtrToUlong(in[i]); - } -} - -static inline void convert_VkPhysicalDeviceGroupProperties_win32_to_unwrapped_host(const VkPhysicalDeviceGroupProperties32 *in, VkPhysicalDeviceGroupProperties *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkPhysicalDeviceGroupProperties_unwrapped_host_to_win32(const VkPhysicalDeviceGroupProperties *in, VkPhysicalDeviceGroupProperties32 *out) -{ - if (!in) return; - - out->physicalDeviceCount = in->physicalDeviceCount; - convert_VkPhysicalDevice_array_unwrapped_host_to_win32(in->physicalDevices, out->physicalDevices, VK_MAX_DEVICE_GROUP_SIZE); - out->subsetAllocation = in->subsetAllocation; -} - -static inline VkPhysicalDeviceGroupProperties *convert_VkPhysicalDeviceGroupProperties_array_win32_to_unwrapped_host(struct conversion_context *ctx, const VkPhysicalDeviceGroupProperties32 *in, uint32_t count) -{ - VkPhysicalDeviceGroupProperties *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPhysicalDeviceGroupProperties_win32_to_unwrapped_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPhysicalDeviceGroupProperties_array_unwrapped_host_to_win32(const VkPhysicalDeviceGroupProperties *in, VkPhysicalDeviceGroupProperties32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkPhysicalDeviceGroupProperties_unwrapped_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkPerformanceCounterKHR_win32_to_host(const VkPerformanceCounterKHR32 *in, VkPerformanceCounterKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkPerformanceCounterKHR_host_to_win32(const VkPerformanceCounterKHR *in, VkPerformanceCounterKHR32 *out) -{ - if (!in) return; - - out->unit = in->unit; - out->scope = in->scope; - out->storage = in->storage; - memcpy(out->uuid, in->uuid, VK_UUID_SIZE * sizeof(uint8_t)); -} - -static inline VkPerformanceCounterKHR *convert_VkPerformanceCounterKHR_array_win32_to_host(struct conversion_context *ctx, const VkPerformanceCounterKHR32 *in, uint32_t count) -{ - VkPerformanceCounterKHR *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPerformanceCounterKHR_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPerformanceCounterKHR_array_host_to_win32(const VkPerformanceCounterKHR *in, VkPerformanceCounterKHR32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkPerformanceCounterKHR_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkPerformanceCounterDescriptionKHR_win32_to_host(const VkPerformanceCounterDescriptionKHR32 *in, VkPerformanceCounterDescriptionKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkPerformanceCounterDescriptionKHR_host_to_win32(const VkPerformanceCounterDescriptionKHR *in, VkPerformanceCounterDescriptionKHR32 *out) -{ - if (!in) return; - - out->flags = in->flags; - memcpy(out->name, in->name, VK_MAX_DESCRIPTION_SIZE * sizeof(char)); - memcpy(out->category, in->category, VK_MAX_DESCRIPTION_SIZE * sizeof(char)); - memcpy(out->description, in->description, VK_MAX_DESCRIPTION_SIZE * sizeof(char)); -} - -static inline VkPerformanceCounterDescriptionKHR *convert_VkPerformanceCounterDescriptionKHR_array_win32_to_host(struct conversion_context *ctx, const VkPerformanceCounterDescriptionKHR32 *in, uint32_t count) -{ - VkPerformanceCounterDescriptionKHR *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPerformanceCounterDescriptionKHR_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPerformanceCounterDescriptionKHR_array_host_to_win32(const VkPerformanceCounterDescriptionKHR *in, VkPerformanceCounterDescriptionKHR32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkPerformanceCounterDescriptionKHR_host_to_win32(&in[i], &out[i]); - } -} - -#ifdef _WIN64 -static inline void convert_VkMappedMemoryRange_win64_to_host(const VkMappedMemoryRange *in, VkMappedMemoryRange *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->memory = wine_device_memory_from_handle(in->memory)->memory; - out->offset = in->offset; - out->size = in->size; -} -#endif /* _WIN64 */ - -static inline void convert_VkMappedMemoryRange_win32_to_host(const VkMappedMemoryRange32 *in, VkMappedMemoryRange *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->memory = wine_device_memory_from_handle(in->memory)->memory; - out->offset = in->offset; - out->size = in->size; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -#ifdef _WIN64 -static inline const VkMappedMemoryRange *convert_VkMappedMemoryRange_array_win64_to_host(struct conversion_context *ctx, const VkMappedMemoryRange *in, uint32_t count) -{ - VkMappedMemoryRange *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkMappedMemoryRange_win64_to_host(&in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkMappedMemoryRange *convert_VkMappedMemoryRange_array_win32_to_host(struct conversion_context *ctx, const VkMappedMemoryRange32 *in, uint32_t count) -{ - VkMappedMemoryRange *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkMappedMemoryRange_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkAccelerationStructureBuildSizesInfoKHR_win32_to_host(const VkAccelerationStructureBuildSizesInfoKHR32 *in, VkAccelerationStructureBuildSizesInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->accelerationStructureSize = in->accelerationStructureSize; - out->updateScratchSize = in->updateScratchSize; - out->buildScratchSize = in->buildScratchSize; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkAccelerationStructureBuildSizesInfoKHR_host_to_win32(const VkAccelerationStructureBuildSizesInfoKHR *in, VkAccelerationStructureBuildSizesInfoKHR32 *out) -{ - if (!in) return; - - out->accelerationStructureSize = in->accelerationStructureSize; - out->updateScratchSize = in->updateScratchSize; - out->buildScratchSize = in->buildScratchSize; -} - -static inline void convert_VkAccelerationStructureDeviceAddressInfoKHR_win32_to_host(const VkAccelerationStructureDeviceAddressInfoKHR32 *in, VkAccelerationStructureDeviceAddressInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->accelerationStructure = in->accelerationStructure; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkAccelerationStructureMemoryRequirementsInfoNV_win32_to_host(const VkAccelerationStructureMemoryRequirementsInfoNV32 *in, VkAccelerationStructureMemoryRequirementsInfoNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->type = in->type; - out->accelerationStructure = in->accelerationStructure; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkMemoryRequirements_host_to_win32(const VkMemoryRequirements *in, VkMemoryRequirements32 *out) -{ - if (!in) return; - - out->size = in->size; - out->alignment = in->alignment; - out->memoryTypeBits = in->memoryTypeBits; -} - -static inline void convert_VkMemoryRequirements2KHR_win32_to_host(const VkMemoryRequirements2KHR32 *in, VkMemoryRequirements2KHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkMemoryRequirements2KHR_host_to_win32(const VkMemoryRequirements2KHR *in, VkMemoryRequirements2KHR32 *out) -{ - if (!in) return; - - convert_VkMemoryRequirements_host_to_win32(&in->memoryRequirements, &out->memoryRequirements); -} - -static inline void convert_VkAccelerationStructureCaptureDescriptorDataInfoEXT_win32_to_host(const VkAccelerationStructureCaptureDescriptorDataInfoEXT32 *in, VkAccelerationStructureCaptureDescriptorDataInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->accelerationStructure = in->accelerationStructure; - out->accelerationStructureNV = in->accelerationStructureNV; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkBufferDeviceAddressInfo_win32_to_host(const VkBufferDeviceAddressInfo32 *in, VkBufferDeviceAddressInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->buffer = in->buffer; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkBufferMemoryRequirementsInfo2_win32_to_host(const VkBufferMemoryRequirementsInfo232 *in, VkBufferMemoryRequirementsInfo2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->buffer = in->buffer; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkMemoryRequirements2_win32_to_host(struct conversion_context *ctx, const VkMemoryRequirements232 *in, VkMemoryRequirements2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: - { - VkMemoryDedicatedRequirements *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkMemoryRequirements2_host_to_win32(const VkMemoryRequirements2 *in, VkMemoryRequirements232 *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure32 *out_header = (void *)out; - - if (!in) return; - - convert_VkMemoryRequirements_host_to_win32(&in->memoryRequirements, &out->memoryRequirements); - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: - { - VkMemoryDedicatedRequirements32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS); - const VkMemoryDedicatedRequirements *in_ext = (const VkMemoryDedicatedRequirements *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS; - out_ext->prefersDedicatedAllocation = in_ext->prefersDedicatedAllocation; - out_ext->requiresDedicatedAllocation = in_ext->requiresDedicatedAllocation; - out_header = (void *)out_ext; - break; - } - default: - break; - } - } -} - -static inline void convert_VkBufferCaptureDescriptorDataInfoEXT_win32_to_host(const VkBufferCaptureDescriptorDataInfoEXT32 *in, VkBufferCaptureDescriptorDataInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->buffer = in->buffer; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkCalibratedTimestampInfoEXT_win32_to_host(const VkCalibratedTimestampInfoEXT32 *in, VkCalibratedTimestampInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->timeDomain = in->timeDomain; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkCalibratedTimestampInfoEXT *convert_VkCalibratedTimestampInfoEXT_array_win32_to_host(struct conversion_context *ctx, const VkCalibratedTimestampInfoEXT32 *in, uint32_t count) -{ - VkCalibratedTimestampInfoEXT *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkCalibratedTimestampInfoEXT_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkDescriptorAddressInfoEXT_win32_to_host(const VkDescriptorAddressInfoEXT32 *in, VkDescriptorAddressInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->address = in->address; - out->range = in->range; - out->format = in->format; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkDescriptorAddressInfoEXT *convert_VkDescriptorAddressInfoEXT_array_win32_to_host(struct conversion_context *ctx, const VkDescriptorAddressInfoEXT32 *in, uint32_t count) -{ - VkDescriptorAddressInfoEXT *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkDescriptorAddressInfoEXT_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkDescriptorDataEXT_win32_to_host(struct conversion_context *ctx, const VkDescriptorDataEXT32 *in, VkDescriptorDataEXT *out, VkFlags selector) -{ - if (!in) return; - - if (selector == VK_DESCRIPTOR_TYPE_SAMPLER) - out->pSampler = (const VkSampler *)UlongToPtr(in->pSampler); - if (selector == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) - out->pCombinedImageSampler = convert_VkDescriptorImageInfo_array_win32_to_host(ctx, (const VkDescriptorImageInfo32 *)UlongToPtr(in->pCombinedImageSampler), 1); - if (selector == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) - out->pInputAttachmentImage = convert_VkDescriptorImageInfo_array_win32_to_host(ctx, (const VkDescriptorImageInfo32 *)UlongToPtr(in->pInputAttachmentImage), 1); - if (selector == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) - out->pSampledImage = convert_VkDescriptorImageInfo_array_win32_to_host(ctx, (const VkDescriptorImageInfo32 *)UlongToPtr(in->pSampledImage), 1); - if (selector == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) - out->pStorageImage = convert_VkDescriptorImageInfo_array_win32_to_host(ctx, (const VkDescriptorImageInfo32 *)UlongToPtr(in->pStorageImage), 1); - if (selector == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) - out->pUniformTexelBuffer = convert_VkDescriptorAddressInfoEXT_array_win32_to_host(ctx, (const VkDescriptorAddressInfoEXT32 *)UlongToPtr(in->pUniformTexelBuffer), 1); - if (selector == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) - out->pStorageTexelBuffer = convert_VkDescriptorAddressInfoEXT_array_win32_to_host(ctx, (const VkDescriptorAddressInfoEXT32 *)UlongToPtr(in->pStorageTexelBuffer), 1); - if (selector == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) - out->pUniformBuffer = convert_VkDescriptorAddressInfoEXT_array_win32_to_host(ctx, (const VkDescriptorAddressInfoEXT32 *)UlongToPtr(in->pUniformBuffer), 1); - if (selector == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) - out->pStorageBuffer = convert_VkDescriptorAddressInfoEXT_array_win32_to_host(ctx, (const VkDescriptorAddressInfoEXT32 *)UlongToPtr(in->pStorageBuffer), 1); - if (selector == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR || selector == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV) - out->accelerationStructure = in->accelerationStructure; -} - -static inline void convert_VkDescriptorGetInfoEXT_win32_to_host(struct conversion_context *ctx, const VkDescriptorGetInfoEXT32 *in, VkDescriptorGetInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->type = in->type; - convert_VkDescriptorDataEXT_win32_to_host(ctx, &in->data, &out->data, in->type); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkDescriptorSetBindingReferenceVALVE_win32_to_host(const VkDescriptorSetBindingReferenceVALVE32 *in, VkDescriptorSetBindingReferenceVALVE *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->descriptorSetLayout = in->descriptorSetLayout; - out->binding = in->binding; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkDescriptorSetLayoutHostMappingInfoVALVE_win32_to_host(const VkDescriptorSetLayoutHostMappingInfoVALVE32 *in, VkDescriptorSetLayoutHostMappingInfoVALVE *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->descriptorOffset = in->descriptorOffset; - out->descriptorSize = in->descriptorSize; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkDescriptorSetLayoutHostMappingInfoVALVE_host_to_win32(const VkDescriptorSetLayoutHostMappingInfoVALVE *in, VkDescriptorSetLayoutHostMappingInfoVALVE32 *out) -{ - if (!in) return; - - out->descriptorOffset = in->descriptorOffset; - out->descriptorSize = in->descriptorSize; -} - -static inline void convert_VkDescriptorSetLayoutSupport_win32_to_host(struct conversion_context *ctx, const VkDescriptorSetLayoutSupport32 *in, VkDescriptorSetLayoutSupport *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT: - { - VkDescriptorSetVariableDescriptorCountLayoutSupport *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkDescriptorSetLayoutSupport_host_to_win32(const VkDescriptorSetLayoutSupport *in, VkDescriptorSetLayoutSupport32 *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure32 *out_header = (void *)out; - - if (!in) return; - - out->supported = in->supported; - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT: - { - VkDescriptorSetVariableDescriptorCountLayoutSupport32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT); - const VkDescriptorSetVariableDescriptorCountLayoutSupport *in_ext = (const VkDescriptorSetVariableDescriptorCountLayoutSupport *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT; - out_ext->maxVariableDescriptorCount = in_ext->maxVariableDescriptorCount; - out_header = (void *)out_ext; - break; - } - default: - break; - } - } -} - -static inline void convert_VkAccelerationStructureVersionInfoKHR_win32_to_host(const VkAccelerationStructureVersionInfoKHR32 *in, VkAccelerationStructureVersionInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->pVersionData = (const uint8_t *)UlongToPtr(in->pVersionData); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkBufferCreateInfo *convert_VkBufferCreateInfo_array_win32_to_host(struct conversion_context *ctx, const VkBufferCreateInfo32 *in, uint32_t count) -{ - VkBufferCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkBufferCreateInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkDeviceBufferMemoryRequirements_win32_to_host(struct conversion_context *ctx, const VkDeviceBufferMemoryRequirements32 *in, VkDeviceBufferMemoryRequirements *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->pCreateInfo = convert_VkBufferCreateInfo_array_win32_to_host(ctx, (const VkBufferCreateInfo32 *)UlongToPtr(in->pCreateInfo), 1); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkDeviceFaultCountsEXT_win32_to_host(const VkDeviceFaultCountsEXT32 *in, VkDeviceFaultCountsEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->addressInfoCount = in->addressInfoCount; - out->vendorInfoCount = in->vendorInfoCount; - out->vendorBinarySize = in->vendorBinarySize; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkDeviceFaultCountsEXT_host_to_win32(const VkDeviceFaultCountsEXT *in, VkDeviceFaultCountsEXT32 *out) -{ - if (!in) return; - - out->addressInfoCount = in->addressInfoCount; - out->vendorInfoCount = in->vendorInfoCount; - out->vendorBinarySize = in->vendorBinarySize; -} - -static inline void convert_VkDeviceFaultAddressInfoEXT_win32_to_host(const VkDeviceFaultAddressInfoEXT32 *in, VkDeviceFaultAddressInfoEXT *out) -{ - if (!in) return; - - out->addressType = in->addressType; - out->reportedAddress = in->reportedAddress; - out->addressPrecision = in->addressPrecision; -} - -static inline void convert_VkDeviceFaultAddressInfoEXT_host_to_win32(const VkDeviceFaultAddressInfoEXT *in, VkDeviceFaultAddressInfoEXT32 *out) -{ - if (!in) return; - - out->addressType = in->addressType; - out->reportedAddress = in->reportedAddress; - out->addressPrecision = in->addressPrecision; -} - -static inline VkDeviceFaultAddressInfoEXT *convert_VkDeviceFaultAddressInfoEXT_array_win32_to_host(struct conversion_context *ctx, const VkDeviceFaultAddressInfoEXT32 *in, uint32_t count) -{ - VkDeviceFaultAddressInfoEXT *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkDeviceFaultAddressInfoEXT_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkDeviceFaultAddressInfoEXT_array_host_to_win32(const VkDeviceFaultAddressInfoEXT *in, VkDeviceFaultAddressInfoEXT32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkDeviceFaultAddressInfoEXT_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkDeviceFaultVendorInfoEXT_win32_to_host(const VkDeviceFaultVendorInfoEXT32 *in, VkDeviceFaultVendorInfoEXT *out) -{ - if (!in) return; - - memcpy(out->description, in->description, VK_MAX_DESCRIPTION_SIZE * sizeof(char)); - out->vendorFaultCode = in->vendorFaultCode; - out->vendorFaultData = in->vendorFaultData; -} - -static inline void convert_VkDeviceFaultVendorInfoEXT_host_to_win32(const VkDeviceFaultVendorInfoEXT *in, VkDeviceFaultVendorInfoEXT32 *out) -{ - if (!in) return; - - memcpy(out->description, in->description, VK_MAX_DESCRIPTION_SIZE * sizeof(char)); - out->vendorFaultCode = in->vendorFaultCode; - out->vendorFaultData = in->vendorFaultData; -} - -static inline VkDeviceFaultVendorInfoEXT *convert_VkDeviceFaultVendorInfoEXT_array_win32_to_host(struct conversion_context *ctx, const VkDeviceFaultVendorInfoEXT32 *in, uint32_t count) -{ - VkDeviceFaultVendorInfoEXT *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkDeviceFaultVendorInfoEXT_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkDeviceFaultVendorInfoEXT_array_host_to_win32(const VkDeviceFaultVendorInfoEXT *in, VkDeviceFaultVendorInfoEXT32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkDeviceFaultVendorInfoEXT_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkDeviceFaultInfoEXT_win32_to_host(struct conversion_context *ctx, const VkDeviceFaultInfoEXT32 *in, VkDeviceFaultInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - memcpy(out->description, in->description, VK_MAX_DESCRIPTION_SIZE * sizeof(char)); - out->pAddressInfos = convert_VkDeviceFaultAddressInfoEXT_array_win32_to_host(ctx, (VkDeviceFaultAddressInfoEXT32 *)UlongToPtr(in->pAddressInfos), 1); - out->pVendorInfos = convert_VkDeviceFaultVendorInfoEXT_array_win32_to_host(ctx, (VkDeviceFaultVendorInfoEXT32 *)UlongToPtr(in->pVendorInfos), 1); - out->pVendorBinaryData = (void *)UlongToPtr(in->pVendorBinaryData); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkDeviceFaultInfoEXT_host_to_win32(const VkDeviceFaultInfoEXT *in, VkDeviceFaultInfoEXT32 *out) -{ - if (!in) return; - - memcpy(out->description, in->description, VK_MAX_DESCRIPTION_SIZE * sizeof(char)); - convert_VkDeviceFaultAddressInfoEXT_array_host_to_win32(in->pAddressInfos, (VkDeviceFaultAddressInfoEXT32 *)UlongToPtr(out->pAddressInfos), 1); - convert_VkDeviceFaultVendorInfoEXT_array_host_to_win32(in->pVendorInfos, (VkDeviceFaultVendorInfoEXT32 *)UlongToPtr(out->pVendorInfos), 1); - out->pVendorBinaryData = PtrToUlong(in->pVendorBinaryData); -} - -static inline void convert_VkDeviceGroupPresentCapabilitiesKHR_win32_to_host(const VkDeviceGroupPresentCapabilitiesKHR32 *in, VkDeviceGroupPresentCapabilitiesKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkDeviceGroupPresentCapabilitiesKHR_host_to_win32(const VkDeviceGroupPresentCapabilitiesKHR *in, VkDeviceGroupPresentCapabilitiesKHR32 *out) -{ - if (!in) return; - - memcpy(out->presentMask, in->presentMask, VK_MAX_DEVICE_GROUP_SIZE * sizeof(uint32_t)); - out->modes = in->modes; -} - -static inline const VkImageCreateInfo *convert_VkImageCreateInfo_array_win32_to_host(struct conversion_context *ctx, const VkImageCreateInfo32 *in, uint32_t count) -{ - VkImageCreateInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkImageCreateInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkDeviceImageMemoryRequirements_win32_to_host(struct conversion_context *ctx, const VkDeviceImageMemoryRequirements32 *in, VkDeviceImageMemoryRequirements *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->pCreateInfo = convert_VkImageCreateInfo_array_win32_to_host(ctx, (const VkImageCreateInfo32 *)UlongToPtr(in->pCreateInfo), 1); - out->planeAspect = in->planeAspect; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkSparseImageMemoryRequirements_host_to_win32(const VkSparseImageMemoryRequirements *in, VkSparseImageMemoryRequirements32 *out) -{ - if (!in) return; - - out->formatProperties = in->formatProperties; - out->imageMipTailFirstLod = in->imageMipTailFirstLod; - out->imageMipTailSize = in->imageMipTailSize; - out->imageMipTailOffset = in->imageMipTailOffset; - out->imageMipTailStride = in->imageMipTailStride; -} - -static inline void convert_VkSparseImageMemoryRequirements2_win32_to_host(const VkSparseImageMemoryRequirements232 *in, VkSparseImageMemoryRequirements2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkSparseImageMemoryRequirements2_host_to_win32(const VkSparseImageMemoryRequirements2 *in, VkSparseImageMemoryRequirements232 *out) -{ - if (!in) return; - - convert_VkSparseImageMemoryRequirements_host_to_win32(&in->memoryRequirements, &out->memoryRequirements); -} - -static inline VkSparseImageMemoryRequirements2 *convert_VkSparseImageMemoryRequirements2_array_win32_to_host(struct conversion_context *ctx, const VkSparseImageMemoryRequirements232 *in, uint32_t count) -{ - VkSparseImageMemoryRequirements2 *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSparseImageMemoryRequirements2_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkSparseImageMemoryRequirements2_array_host_to_win32(const VkSparseImageMemoryRequirements2 *in, VkSparseImageMemoryRequirements232 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkSparseImageMemoryRequirements2_host_to_win32(&in[i], &out[i]); - } -} - -#ifdef _WIN64 -static inline void convert_VkDeviceMemoryOpaqueCaptureAddressInfo_win64_to_host(const VkDeviceMemoryOpaqueCaptureAddressInfo *in, VkDeviceMemoryOpaqueCaptureAddressInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->memory = wine_device_memory_from_handle(in->memory)->memory; -} -#endif /* _WIN64 */ - -static inline void convert_VkDeviceMemoryOpaqueCaptureAddressInfo_win32_to_host(const VkDeviceMemoryOpaqueCaptureAddressInfo32 *in, VkDeviceMemoryOpaqueCaptureAddressInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->memory = wine_device_memory_from_handle(in->memory)->memory; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkMicromapVersionInfoEXT_win32_to_host(const VkMicromapVersionInfoEXT32 *in, VkMicromapVersionInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->pVersionData = (const uint8_t *)UlongToPtr(in->pVersionData); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkDeviceQueueInfo2_win32_to_host(const VkDeviceQueueInfo232 *in, VkDeviceQueueInfo2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->queueFamilyIndex = in->queueFamilyIndex; - out->queueIndex = in->queueIndex; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkTilePropertiesQCOM_win32_to_host(const VkTilePropertiesQCOM32 *in, VkTilePropertiesQCOM *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->tileSize = in->tileSize; - out->apronSize = in->apronSize; - out->origin = in->origin; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkTilePropertiesQCOM_host_to_win32(const VkTilePropertiesQCOM *in, VkTilePropertiesQCOM32 *out) -{ - if (!in) return; - - out->tileSize = in->tileSize; - out->apronSize = in->apronSize; - out->origin = in->origin; -} - -static inline VkTilePropertiesQCOM *convert_VkTilePropertiesQCOM_array_win32_to_host(struct conversion_context *ctx, const VkTilePropertiesQCOM32 *in, uint32_t count) -{ - VkTilePropertiesQCOM *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkTilePropertiesQCOM_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkTilePropertiesQCOM_array_host_to_win32(const VkTilePropertiesQCOM *in, VkTilePropertiesQCOM32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkTilePropertiesQCOM_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkGeneratedCommandsMemoryRequirementsInfoNV_win32_to_host(const VkGeneratedCommandsMemoryRequirementsInfoNV32 *in, VkGeneratedCommandsMemoryRequirementsInfoNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->pipelineBindPoint = in->pipelineBindPoint; - out->pipeline = in->pipeline; - out->indirectCommandsLayout = in->indirectCommandsLayout; - out->maxSequencesCount = in->maxSequencesCount; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkImageMemoryRequirementsInfo2_win32_to_host(struct conversion_context *ctx, const VkImageMemoryRequirementsInfo232 *in, VkImageMemoryRequirementsInfo2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->image = in->image; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO: - { - VkImagePlaneMemoryRequirementsInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkImagePlaneMemoryRequirementsInfo32 *in_ext = (const VkImagePlaneMemoryRequirementsInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO; - out_ext->pNext = NULL; - out_ext->planeAspect = in_ext->planeAspect; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkImageCaptureDescriptorDataInfoEXT_win32_to_host(const VkImageCaptureDescriptorDataInfoEXT32 *in, VkImageCaptureDescriptorDataInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->image = in->image; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkSparseImageMemoryRequirements_array_host_to_win32(const VkSparseImageMemoryRequirements *in, VkSparseImageMemoryRequirements32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkSparseImageMemoryRequirements_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkImageSparseMemoryRequirementsInfo2_win32_to_host(const VkImageSparseMemoryRequirementsInfo232 *in, VkImageSparseMemoryRequirementsInfo2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->image = in->image; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkSubresourceLayout_win32_to_host(const VkSubresourceLayout32 *in, VkSubresourceLayout *out) -{ - if (!in) return; - - out->offset = in->offset; - out->size = in->size; - out->rowPitch = in->rowPitch; - out->arrayPitch = in->arrayPitch; - out->depthPitch = in->depthPitch; -} - -static inline void convert_VkSubresourceLayout_host_to_win32(const VkSubresourceLayout *in, VkSubresourceLayout32 *out) -{ - if (!in) return; - - out->offset = in->offset; - out->size = in->size; - out->rowPitch = in->rowPitch; - out->arrayPitch = in->arrayPitch; - out->depthPitch = in->depthPitch; -} - -static inline void convert_VkImageSubresource2EXT_win32_to_host(const VkImageSubresource2EXT32 *in, VkImageSubresource2EXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->imageSubresource = in->imageSubresource; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkSubresourceLayout2EXT_win32_to_host(struct conversion_context *ctx, const VkSubresourceLayout2EXT32 *in, VkSubresourceLayout2EXT *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT: - { - VkImageCompressionPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkSubresourceLayout2EXT_host_to_win32(const VkSubresourceLayout2EXT *in, VkSubresourceLayout2EXT32 *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure32 *out_header = (void *)out; - - if (!in) return; - - convert_VkSubresourceLayout_host_to_win32(&in->subresourceLayout, &out->subresourceLayout); - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT: - { - VkImageCompressionPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT); - const VkImageCompressionPropertiesEXT *in_ext = (const VkImageCompressionPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT; - out_ext->imageCompressionFlags = in_ext->imageCompressionFlags; - out_ext->imageCompressionFixedRateFlags = in_ext->imageCompressionFixedRateFlags; - out_header = (void *)out_ext; - break; - } - default: - break; - } - } -} - -static inline void convert_VkImageViewAddressPropertiesNVX_win32_to_host(const VkImageViewAddressPropertiesNVX32 *in, VkImageViewAddressPropertiesNVX *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkImageViewAddressPropertiesNVX_host_to_win32(const VkImageViewAddressPropertiesNVX *in, VkImageViewAddressPropertiesNVX32 *out) -{ - if (!in) return; - - out->deviceAddress = in->deviceAddress; - out->size = in->size; -} - -static inline void convert_VkImageViewHandleInfoNVX_win32_to_host(const VkImageViewHandleInfoNVX32 *in, VkImageViewHandleInfoNVX *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->imageView = in->imageView; - out->descriptorType = in->descriptorType; - out->sampler = in->sampler; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkImageViewCaptureDescriptorDataInfoEXT_win32_to_host(const VkImageViewCaptureDescriptorDataInfoEXT32 *in, VkImageViewCaptureDescriptorDataInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->imageView = in->imageView; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkMemoryHostPointerPropertiesEXT_win32_to_host(const VkMemoryHostPointerPropertiesEXT32 *in, VkMemoryHostPointerPropertiesEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkMemoryHostPointerPropertiesEXT_host_to_win32(const VkMemoryHostPointerPropertiesEXT *in, VkMemoryHostPointerPropertiesEXT32 *out) -{ - if (!in) return; - - out->memoryTypeBits = in->memoryTypeBits; -} - -static inline void convert_VkMicromapBuildSizesInfoEXT_win32_to_host(const VkMicromapBuildSizesInfoEXT32 *in, VkMicromapBuildSizesInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->micromapSize = in->micromapSize; - out->buildScratchSize = in->buildScratchSize; - out->discardable = in->discardable; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkMicromapBuildSizesInfoEXT_host_to_win32(const VkMicromapBuildSizesInfoEXT *in, VkMicromapBuildSizesInfoEXT32 *out) -{ - if (!in) return; - - out->micromapSize = in->micromapSize; - out->buildScratchSize = in->buildScratchSize; - out->discardable = in->discardable; -} - -static inline void convert_VkPerformanceValueDataINTEL_win32_to_host(const VkPerformanceValueDataINTEL32 *in, VkPerformanceValueDataINTEL *out, VkFlags selector) -{ - if (!in) return; - - if (selector == VK_PERFORMANCE_VALUE_TYPE_UINT32_INTEL) - out->value32 = in->value32; - if (selector == VK_PERFORMANCE_VALUE_TYPE_UINT64_INTEL) - out->value64 = in->value64; - if (selector == VK_PERFORMANCE_VALUE_TYPE_FLOAT_INTEL) - out->valueFloat = in->valueFloat; - if (selector == VK_PERFORMANCE_VALUE_TYPE_BOOL_INTEL) - out->valueBool = in->valueBool; - if (selector == VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL) - out->valueString = (const char *)UlongToPtr(in->valueString); -} - -static inline void convert_VkPerformanceValueDataINTEL_host_to_win32(const VkPerformanceValueDataINTEL *in, VkPerformanceValueDataINTEL32 *out, VkFlags selector) -{ - if (!in) return; - - if (selector == VK_PERFORMANCE_VALUE_TYPE_UINT32_INTEL) - out->value32 = in->value32; - if (selector == VK_PERFORMANCE_VALUE_TYPE_UINT64_INTEL) - out->value64 = in->value64; - if (selector == VK_PERFORMANCE_VALUE_TYPE_FLOAT_INTEL) - out->valueFloat = in->valueFloat; - if (selector == VK_PERFORMANCE_VALUE_TYPE_BOOL_INTEL) - out->valueBool = in->valueBool; -} - -static inline void convert_VkPerformanceValueINTEL_host_to_win32(const VkPerformanceValueINTEL *in, VkPerformanceValueINTEL32 *out) -{ - if (!in) return; - - out->type = in->type; - convert_VkPerformanceValueDataINTEL_host_to_win32(&in->data, &out->data, in->type); -} - -static inline void convert_VkCooperativeMatrixPropertiesNV_win32_to_host(const VkCooperativeMatrixPropertiesNV32 *in, VkCooperativeMatrixPropertiesNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkCooperativeMatrixPropertiesNV_host_to_win32(const VkCooperativeMatrixPropertiesNV *in, VkCooperativeMatrixPropertiesNV32 *out) -{ - if (!in) return; - - out->MSize = in->MSize; - out->NSize = in->NSize; - out->KSize = in->KSize; - out->AType = in->AType; - out->BType = in->BType; - out->CType = in->CType; - out->DType = in->DType; - out->scope = in->scope; -} - -static inline VkCooperativeMatrixPropertiesNV *convert_VkCooperativeMatrixPropertiesNV_array_win32_to_host(struct conversion_context *ctx, const VkCooperativeMatrixPropertiesNV32 *in, uint32_t count) -{ - VkCooperativeMatrixPropertiesNV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkCooperativeMatrixPropertiesNV_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkCooperativeMatrixPropertiesNV_array_host_to_win32(const VkCooperativeMatrixPropertiesNV *in, VkCooperativeMatrixPropertiesNV32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkCooperativeMatrixPropertiesNV_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkPhysicalDeviceExternalBufferInfo_win32_to_host(const VkPhysicalDeviceExternalBufferInfo32 *in, VkPhysicalDeviceExternalBufferInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->usage = in->usage; - out->handleType = in->handleType; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkExternalBufferProperties_win32_to_host(const VkExternalBufferProperties32 *in, VkExternalBufferProperties *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkExternalBufferProperties_host_to_win32(const VkExternalBufferProperties *in, VkExternalBufferProperties32 *out) -{ - if (!in) return; - - out->externalMemoryProperties = in->externalMemoryProperties; -} - -static inline void convert_VkPhysicalDeviceExternalFenceInfo_win32_to_host(const VkPhysicalDeviceExternalFenceInfo32 *in, VkPhysicalDeviceExternalFenceInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->handleType = in->handleType; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkExternalFenceProperties_win32_to_host(const VkExternalFenceProperties32 *in, VkExternalFenceProperties *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkExternalFenceProperties_host_to_win32(const VkExternalFenceProperties *in, VkExternalFenceProperties32 *out) -{ - if (!in) return; - - out->exportFromImportedHandleTypes = in->exportFromImportedHandleTypes; - out->compatibleHandleTypes = in->compatibleHandleTypes; - out->externalFenceFeatures = in->externalFenceFeatures; -} - -static inline void convert_VkPhysicalDeviceExternalSemaphoreInfo_win32_to_host(struct conversion_context *ctx, const VkPhysicalDeviceExternalSemaphoreInfo32 *in, VkPhysicalDeviceExternalSemaphoreInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->handleType = in->handleType; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO: - { - VkSemaphoreTypeCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSemaphoreTypeCreateInfo32 *in_ext = (const VkSemaphoreTypeCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->semaphoreType = in_ext->semaphoreType; - out_ext->initialValue = in_ext->initialValue; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkExternalSemaphoreProperties_win32_to_host(const VkExternalSemaphoreProperties32 *in, VkExternalSemaphoreProperties *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkExternalSemaphoreProperties_host_to_win32(const VkExternalSemaphoreProperties *in, VkExternalSemaphoreProperties32 *out) -{ - if (!in) return; - - out->exportFromImportedHandleTypes = in->exportFromImportedHandleTypes; - out->compatibleHandleTypes = in->compatibleHandleTypes; - out->externalSemaphoreFeatures = in->externalSemaphoreFeatures; -} - -static inline void convert_VkPhysicalDeviceFeatures2_win32_to_host(struct conversion_context *ctx, const VkPhysicalDeviceFeatures232 *in, VkPhysicalDeviceFeatures2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->features = in->features; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV: - { - VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV32 *in_ext = (const VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->deviceGeneratedCommands = in_ext->deviceGeneratedCommands; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES: - { - VkPhysicalDevicePrivateDataFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePrivateDataFeatures32 *in_ext = (const VkPhysicalDevicePrivateDataFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES; - out_ext->pNext = NULL; - out_ext->privateData = in_ext->privateData; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES: - { - VkPhysicalDeviceVariablePointersFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVariablePointersFeatures32 *in_ext = (const VkPhysicalDeviceVariablePointersFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES; - out_ext->pNext = NULL; - out_ext->variablePointersStorageBuffer = in_ext->variablePointersStorageBuffer; - out_ext->variablePointers = in_ext->variablePointers; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: - { - VkPhysicalDeviceMultiviewFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMultiviewFeatures32 *in_ext = (const VkPhysicalDeviceMultiviewFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; - out_ext->pNext = NULL; - out_ext->multiview = in_ext->multiview; - out_ext->multiviewGeometryShader = in_ext->multiviewGeometryShader; - out_ext->multiviewTessellationShader = in_ext->multiviewTessellationShader; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR: - { - VkPhysicalDevicePresentIdFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePresentIdFeaturesKHR32 *in_ext = (const VkPhysicalDevicePresentIdFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->presentId = in_ext->presentId; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR: - { - VkPhysicalDevicePresentWaitFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePresentWaitFeaturesKHR32 *in_ext = (const VkPhysicalDevicePresentWaitFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->presentWait = in_ext->presentWait; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: - { - VkPhysicalDevice16BitStorageFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevice16BitStorageFeatures32 *in_ext = (const VkPhysicalDevice16BitStorageFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES; - out_ext->pNext = NULL; - out_ext->storageBuffer16BitAccess = in_ext->storageBuffer16BitAccess; - out_ext->uniformAndStorageBuffer16BitAccess = in_ext->uniformAndStorageBuffer16BitAccess; - out_ext->storagePushConstant16 = in_ext->storagePushConstant16; - out_ext->storageInputOutput16 = in_ext->storageInputOutput16; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES: - { - VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures32 *in_ext = (const VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderSubgroupExtendedTypes = in_ext->shaderSubgroupExtendedTypes; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: - { - VkPhysicalDeviceSamplerYcbcrConversionFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSamplerYcbcrConversionFeatures32 *in_ext = (const VkPhysicalDeviceSamplerYcbcrConversionFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES; - out_ext->pNext = NULL; - out_ext->samplerYcbcrConversion = in_ext->samplerYcbcrConversion; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES: - { - VkPhysicalDeviceProtectedMemoryFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceProtectedMemoryFeatures32 *in_ext = (const VkPhysicalDeviceProtectedMemoryFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES; - out_ext->pNext = NULL; - out_ext->protectedMemory = in_ext->protectedMemory; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT: - { - VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT32 *in_ext = (const VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->advancedBlendCoherentOperations = in_ext->advancedBlendCoherentOperations; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT: - { - VkPhysicalDeviceMultiDrawFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMultiDrawFeaturesEXT32 *in_ext = (const VkPhysicalDeviceMultiDrawFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->multiDraw = in_ext->multiDraw; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES: - { - VkPhysicalDeviceInlineUniformBlockFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceInlineUniformBlockFeatures32 *in_ext = (const VkPhysicalDeviceInlineUniformBlockFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES; - out_ext->pNext = NULL; - out_ext->inlineUniformBlock = in_ext->inlineUniformBlock; - out_ext->descriptorBindingInlineUniformBlockUpdateAfterBind = in_ext->descriptorBindingInlineUniformBlockUpdateAfterBind; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES: - { - VkPhysicalDeviceMaintenance4Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMaintenance4Features32 *in_ext = (const VkPhysicalDeviceMaintenance4Features32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES; - out_ext->pNext = NULL; - out_ext->maintenance4 = in_ext->maintenance4; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES: - { - VkPhysicalDeviceShaderDrawParametersFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderDrawParametersFeatures32 *in_ext = (const VkPhysicalDeviceShaderDrawParametersFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderDrawParameters = in_ext->shaderDrawParameters; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES: - { - VkPhysicalDeviceShaderFloat16Int8Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderFloat16Int8Features32 *in_ext = (const VkPhysicalDeviceShaderFloat16Int8Features32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderFloat16 = in_ext->shaderFloat16; - out_ext->shaderInt8 = in_ext->shaderInt8; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES: - { - VkPhysicalDeviceHostQueryResetFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceHostQueryResetFeatures32 *in_ext = (const VkPhysicalDeviceHostQueryResetFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES; - out_ext->pNext = NULL; - out_ext->hostQueryReset = in_ext->hostQueryReset; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR: - { - VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR32 *in_ext = (const VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->globalPriorityQuery = in_ext->globalPriorityQuery; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES: - { - VkPhysicalDeviceDescriptorIndexingFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDescriptorIndexingFeatures32 *in_ext = (const VkPhysicalDeviceDescriptorIndexingFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderInputAttachmentArrayDynamicIndexing = in_ext->shaderInputAttachmentArrayDynamicIndexing; - out_ext->shaderUniformTexelBufferArrayDynamicIndexing = in_ext->shaderUniformTexelBufferArrayDynamicIndexing; - out_ext->shaderStorageTexelBufferArrayDynamicIndexing = in_ext->shaderStorageTexelBufferArrayDynamicIndexing; - out_ext->shaderUniformBufferArrayNonUniformIndexing = in_ext->shaderUniformBufferArrayNonUniformIndexing; - out_ext->shaderSampledImageArrayNonUniformIndexing = in_ext->shaderSampledImageArrayNonUniformIndexing; - out_ext->shaderStorageBufferArrayNonUniformIndexing = in_ext->shaderStorageBufferArrayNonUniformIndexing; - out_ext->shaderStorageImageArrayNonUniformIndexing = in_ext->shaderStorageImageArrayNonUniformIndexing; - out_ext->shaderInputAttachmentArrayNonUniformIndexing = in_ext->shaderInputAttachmentArrayNonUniformIndexing; - out_ext->shaderUniformTexelBufferArrayNonUniformIndexing = in_ext->shaderUniformTexelBufferArrayNonUniformIndexing; - out_ext->shaderStorageTexelBufferArrayNonUniformIndexing = in_ext->shaderStorageTexelBufferArrayNonUniformIndexing; - out_ext->descriptorBindingUniformBufferUpdateAfterBind = in_ext->descriptorBindingUniformBufferUpdateAfterBind; - out_ext->descriptorBindingSampledImageUpdateAfterBind = in_ext->descriptorBindingSampledImageUpdateAfterBind; - out_ext->descriptorBindingStorageImageUpdateAfterBind = in_ext->descriptorBindingStorageImageUpdateAfterBind; - out_ext->descriptorBindingStorageBufferUpdateAfterBind = in_ext->descriptorBindingStorageBufferUpdateAfterBind; - out_ext->descriptorBindingUniformTexelBufferUpdateAfterBind = in_ext->descriptorBindingUniformTexelBufferUpdateAfterBind; - out_ext->descriptorBindingStorageTexelBufferUpdateAfterBind = in_ext->descriptorBindingStorageTexelBufferUpdateAfterBind; - out_ext->descriptorBindingUpdateUnusedWhilePending = in_ext->descriptorBindingUpdateUnusedWhilePending; - out_ext->descriptorBindingPartiallyBound = in_ext->descriptorBindingPartiallyBound; - out_ext->descriptorBindingVariableDescriptorCount = in_ext->descriptorBindingVariableDescriptorCount; - out_ext->runtimeDescriptorArray = in_ext->runtimeDescriptorArray; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES: - { - VkPhysicalDeviceTimelineSemaphoreFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceTimelineSemaphoreFeatures32 *in_ext = (const VkPhysicalDeviceTimelineSemaphoreFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES; - out_ext->pNext = NULL; - out_ext->timelineSemaphore = in_ext->timelineSemaphore; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES: - { - VkPhysicalDevice8BitStorageFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevice8BitStorageFeatures32 *in_ext = (const VkPhysicalDevice8BitStorageFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES; - out_ext->pNext = NULL; - out_ext->storageBuffer8BitAccess = in_ext->storageBuffer8BitAccess; - out_ext->uniformAndStorageBuffer8BitAccess = in_ext->uniformAndStorageBuffer8BitAccess; - out_ext->storagePushConstant8 = in_ext->storagePushConstant8; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT: - { - VkPhysicalDeviceConditionalRenderingFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceConditionalRenderingFeaturesEXT32 *in_ext = (const VkPhysicalDeviceConditionalRenderingFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->conditionalRendering = in_ext->conditionalRendering; - out_ext->inheritedConditionalRendering = in_ext->inheritedConditionalRendering; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES: - { - VkPhysicalDeviceVulkanMemoryModelFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVulkanMemoryModelFeatures32 *in_ext = (const VkPhysicalDeviceVulkanMemoryModelFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES; - out_ext->pNext = NULL; - out_ext->vulkanMemoryModel = in_ext->vulkanMemoryModel; - out_ext->vulkanMemoryModelDeviceScope = in_ext->vulkanMemoryModelDeviceScope; - out_ext->vulkanMemoryModelAvailabilityVisibilityChains = in_ext->vulkanMemoryModelAvailabilityVisibilityChains; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES: - { - VkPhysicalDeviceShaderAtomicInt64Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderAtomicInt64Features32 *in_ext = (const VkPhysicalDeviceShaderAtomicInt64Features32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderBufferInt64Atomics = in_ext->shaderBufferInt64Atomics; - out_ext->shaderSharedInt64Atomics = in_ext->shaderSharedInt64Atomics; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT: - { - VkPhysicalDeviceShaderAtomicFloatFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderAtomicFloatFeaturesEXT32 *in_ext = (const VkPhysicalDeviceShaderAtomicFloatFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->shaderBufferFloat32Atomics = in_ext->shaderBufferFloat32Atomics; - out_ext->shaderBufferFloat32AtomicAdd = in_ext->shaderBufferFloat32AtomicAdd; - out_ext->shaderBufferFloat64Atomics = in_ext->shaderBufferFloat64Atomics; - out_ext->shaderBufferFloat64AtomicAdd = in_ext->shaderBufferFloat64AtomicAdd; - out_ext->shaderSharedFloat32Atomics = in_ext->shaderSharedFloat32Atomics; - out_ext->shaderSharedFloat32AtomicAdd = in_ext->shaderSharedFloat32AtomicAdd; - out_ext->shaderSharedFloat64Atomics = in_ext->shaderSharedFloat64Atomics; - out_ext->shaderSharedFloat64AtomicAdd = in_ext->shaderSharedFloat64AtomicAdd; - out_ext->shaderImageFloat32Atomics = in_ext->shaderImageFloat32Atomics; - out_ext->shaderImageFloat32AtomicAdd = in_ext->shaderImageFloat32AtomicAdd; - out_ext->sparseImageFloat32Atomics = in_ext->sparseImageFloat32Atomics; - out_ext->sparseImageFloat32AtomicAdd = in_ext->sparseImageFloat32AtomicAdd; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT: - { - VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT32 *in_ext = (const VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->shaderBufferFloat16Atomics = in_ext->shaderBufferFloat16Atomics; - out_ext->shaderBufferFloat16AtomicAdd = in_ext->shaderBufferFloat16AtomicAdd; - out_ext->shaderBufferFloat16AtomicMinMax = in_ext->shaderBufferFloat16AtomicMinMax; - out_ext->shaderBufferFloat32AtomicMinMax = in_ext->shaderBufferFloat32AtomicMinMax; - out_ext->shaderBufferFloat64AtomicMinMax = in_ext->shaderBufferFloat64AtomicMinMax; - out_ext->shaderSharedFloat16Atomics = in_ext->shaderSharedFloat16Atomics; - out_ext->shaderSharedFloat16AtomicAdd = in_ext->shaderSharedFloat16AtomicAdd; - out_ext->shaderSharedFloat16AtomicMinMax = in_ext->shaderSharedFloat16AtomicMinMax; - out_ext->shaderSharedFloat32AtomicMinMax = in_ext->shaderSharedFloat32AtomicMinMax; - out_ext->shaderSharedFloat64AtomicMinMax = in_ext->shaderSharedFloat64AtomicMinMax; - out_ext->shaderImageFloat32AtomicMinMax = in_ext->shaderImageFloat32AtomicMinMax; - out_ext->sparseImageFloat32AtomicMinMax = in_ext->sparseImageFloat32AtomicMinMax; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT: - { - VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT32 *in_ext = (const VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->vertexAttributeInstanceRateDivisor = in_ext->vertexAttributeInstanceRateDivisor; - out_ext->vertexAttributeInstanceRateZeroDivisor = in_ext->vertexAttributeInstanceRateZeroDivisor; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT: - { - VkPhysicalDeviceASTCDecodeFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceASTCDecodeFeaturesEXT32 *in_ext = (const VkPhysicalDeviceASTCDecodeFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->decodeModeSharedExponent = in_ext->decodeModeSharedExponent; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT: - { - VkPhysicalDeviceTransformFeedbackFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceTransformFeedbackFeaturesEXT32 *in_ext = (const VkPhysicalDeviceTransformFeedbackFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->transformFeedback = in_ext->transformFeedback; - out_ext->geometryStreams = in_ext->geometryStreams; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV: - { - VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV32 *in_ext = (const VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->representativeFragmentTest = in_ext->representativeFragmentTest; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV: - { - VkPhysicalDeviceExclusiveScissorFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceExclusiveScissorFeaturesNV32 *in_ext = (const VkPhysicalDeviceExclusiveScissorFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->exclusiveScissor = in_ext->exclusiveScissor; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV: - { - VkPhysicalDeviceCornerSampledImageFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCornerSampledImageFeaturesNV32 *in_ext = (const VkPhysicalDeviceCornerSampledImageFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->cornerSampledImage = in_ext->cornerSampledImage; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV: - { - VkPhysicalDeviceComputeShaderDerivativesFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceComputeShaderDerivativesFeaturesNV32 *in_ext = (const VkPhysicalDeviceComputeShaderDerivativesFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->computeDerivativeGroupQuads = in_ext->computeDerivativeGroupQuads; - out_ext->computeDerivativeGroupLinear = in_ext->computeDerivativeGroupLinear; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV: - { - VkPhysicalDeviceShaderImageFootprintFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderImageFootprintFeaturesNV32 *in_ext = (const VkPhysicalDeviceShaderImageFootprintFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->imageFootprint = in_ext->imageFootprint; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV: - { - VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV32 *in_ext = (const VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->dedicatedAllocationImageAliasing = in_ext->dedicatedAllocationImageAliasing; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_NV: - { - VkPhysicalDeviceCopyMemoryIndirectFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCopyMemoryIndirectFeaturesNV32 *in_ext = (const VkPhysicalDeviceCopyMemoryIndirectFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->indirectCopy = in_ext->indirectCopy; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_NV: - { - VkPhysicalDeviceMemoryDecompressionFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMemoryDecompressionFeaturesNV32 *in_ext = (const VkPhysicalDeviceMemoryDecompressionFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->memoryDecompression = in_ext->memoryDecompression; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV: - { - VkPhysicalDeviceShadingRateImageFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShadingRateImageFeaturesNV32 *in_ext = (const VkPhysicalDeviceShadingRateImageFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->shadingRateImage = in_ext->shadingRateImage; - out_ext->shadingRateCoarseSampleOrder = in_ext->shadingRateCoarseSampleOrder; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI: - { - VkPhysicalDeviceInvocationMaskFeaturesHUAWEI *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceInvocationMaskFeaturesHUAWEI32 *in_ext = (const VkPhysicalDeviceInvocationMaskFeaturesHUAWEI32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI; - out_ext->pNext = NULL; - out_ext->invocationMask = in_ext->invocationMask; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV: - { - VkPhysicalDeviceMeshShaderFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMeshShaderFeaturesNV32 *in_ext = (const VkPhysicalDeviceMeshShaderFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->taskShader = in_ext->taskShader; - out_ext->meshShader = in_ext->meshShader; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT: - { - VkPhysicalDeviceMeshShaderFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMeshShaderFeaturesEXT32 *in_ext = (const VkPhysicalDeviceMeshShaderFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->taskShader = in_ext->taskShader; - out_ext->meshShader = in_ext->meshShader; - out_ext->multiviewMeshShader = in_ext->multiviewMeshShader; - out_ext->primitiveFragmentShadingRateMeshShader = in_ext->primitiveFragmentShadingRateMeshShader; - out_ext->meshShaderQueries = in_ext->meshShaderQueries; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR: - { - VkPhysicalDeviceAccelerationStructureFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceAccelerationStructureFeaturesKHR32 *in_ext = (const VkPhysicalDeviceAccelerationStructureFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->accelerationStructure = in_ext->accelerationStructure; - out_ext->accelerationStructureCaptureReplay = in_ext->accelerationStructureCaptureReplay; - out_ext->accelerationStructureIndirectBuild = in_ext->accelerationStructureIndirectBuild; - out_ext->accelerationStructureHostCommands = in_ext->accelerationStructureHostCommands; - out_ext->descriptorBindingAccelerationStructureUpdateAfterBind = in_ext->descriptorBindingAccelerationStructureUpdateAfterBind; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR: - { - VkPhysicalDeviceRayTracingPipelineFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRayTracingPipelineFeaturesKHR32 *in_ext = (const VkPhysicalDeviceRayTracingPipelineFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->rayTracingPipeline = in_ext->rayTracingPipeline; - out_ext->rayTracingPipelineShaderGroupHandleCaptureReplay = in_ext->rayTracingPipelineShaderGroupHandleCaptureReplay; - out_ext->rayTracingPipelineShaderGroupHandleCaptureReplayMixed = in_ext->rayTracingPipelineShaderGroupHandleCaptureReplayMixed; - out_ext->rayTracingPipelineTraceRaysIndirect = in_ext->rayTracingPipelineTraceRaysIndirect; - out_ext->rayTraversalPrimitiveCulling = in_ext->rayTraversalPrimitiveCulling; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR: - { - VkPhysicalDeviceRayQueryFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRayQueryFeaturesKHR32 *in_ext = (const VkPhysicalDeviceRayQueryFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->rayQuery = in_ext->rayQuery; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR: - { - VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR32 *in_ext = (const VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->rayTracingMaintenance1 = in_ext->rayTracingMaintenance1; - out_ext->rayTracingPipelineTraceRaysIndirect2 = in_ext->rayTracingPipelineTraceRaysIndirect2; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT: - { - VkPhysicalDeviceFragmentDensityMapFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentDensityMapFeaturesEXT32 *in_ext = (const VkPhysicalDeviceFragmentDensityMapFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->fragmentDensityMap = in_ext->fragmentDensityMap; - out_ext->fragmentDensityMapDynamic = in_ext->fragmentDensityMapDynamic; - out_ext->fragmentDensityMapNonSubsampledImages = in_ext->fragmentDensityMapNonSubsampledImages; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT: - { - VkPhysicalDeviceFragmentDensityMap2FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentDensityMap2FeaturesEXT32 *in_ext = (const VkPhysicalDeviceFragmentDensityMap2FeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->fragmentDensityMapDeferred = in_ext->fragmentDensityMapDeferred; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM: - { - VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM32 *in_ext = (const VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM; - out_ext->pNext = NULL; - out_ext->fragmentDensityMapOffset = in_ext->fragmentDensityMapOffset; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES: - { - VkPhysicalDeviceScalarBlockLayoutFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceScalarBlockLayoutFeatures32 *in_ext = (const VkPhysicalDeviceScalarBlockLayoutFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES; - out_ext->pNext = NULL; - out_ext->scalarBlockLayout = in_ext->scalarBlockLayout; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES: - { - VkPhysicalDeviceUniformBufferStandardLayoutFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceUniformBufferStandardLayoutFeatures32 *in_ext = (const VkPhysicalDeviceUniformBufferStandardLayoutFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES; - out_ext->pNext = NULL; - out_ext->uniformBufferStandardLayout = in_ext->uniformBufferStandardLayout; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT: - { - VkPhysicalDeviceDepthClipEnableFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDepthClipEnableFeaturesEXT32 *in_ext = (const VkPhysicalDeviceDepthClipEnableFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->depthClipEnable = in_ext->depthClipEnable; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT: - { - VkPhysicalDeviceMemoryPriorityFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMemoryPriorityFeaturesEXT32 *in_ext = (const VkPhysicalDeviceMemoryPriorityFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->memoryPriority = in_ext->memoryPriority; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT: - { - VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT32 *in_ext = (const VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->pageableDeviceLocalMemory = in_ext->pageableDeviceLocalMemory; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES: - { - VkPhysicalDeviceBufferDeviceAddressFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceBufferDeviceAddressFeatures32 *in_ext = (const VkPhysicalDeviceBufferDeviceAddressFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES; - out_ext->pNext = NULL; - out_ext->bufferDeviceAddress = in_ext->bufferDeviceAddress; - out_ext->bufferDeviceAddressCaptureReplay = in_ext->bufferDeviceAddressCaptureReplay; - out_ext->bufferDeviceAddressMultiDevice = in_ext->bufferDeviceAddressMultiDevice; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT: - { - VkPhysicalDeviceBufferDeviceAddressFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceBufferDeviceAddressFeaturesEXT32 *in_ext = (const VkPhysicalDeviceBufferDeviceAddressFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->bufferDeviceAddress = in_ext->bufferDeviceAddress; - out_ext->bufferDeviceAddressCaptureReplay = in_ext->bufferDeviceAddressCaptureReplay; - out_ext->bufferDeviceAddressMultiDevice = in_ext->bufferDeviceAddressMultiDevice; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES: - { - VkPhysicalDeviceImagelessFramebufferFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImagelessFramebufferFeatures32 *in_ext = (const VkPhysicalDeviceImagelessFramebufferFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES; - out_ext->pNext = NULL; - out_ext->imagelessFramebuffer = in_ext->imagelessFramebuffer; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES: - { - VkPhysicalDeviceTextureCompressionASTCHDRFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceTextureCompressionASTCHDRFeatures32 *in_ext = (const VkPhysicalDeviceTextureCompressionASTCHDRFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES; - out_ext->pNext = NULL; - out_ext->textureCompressionASTC_HDR = in_ext->textureCompressionASTC_HDR; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV: - { - VkPhysicalDeviceCooperativeMatrixFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCooperativeMatrixFeaturesNV32 *in_ext = (const VkPhysicalDeviceCooperativeMatrixFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->cooperativeMatrix = in_ext->cooperativeMatrix; - out_ext->cooperativeMatrixRobustBufferAccess = in_ext->cooperativeMatrixRobustBufferAccess; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT: - { - VkPhysicalDeviceYcbcrImageArraysFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceYcbcrImageArraysFeaturesEXT32 *in_ext = (const VkPhysicalDeviceYcbcrImageArraysFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->ycbcrImageArrays = in_ext->ycbcrImageArrays; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_BARRIER_FEATURES_NV: - { - VkPhysicalDevicePresentBarrierFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePresentBarrierFeaturesNV32 *in_ext = (const VkPhysicalDevicePresentBarrierFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_BARRIER_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->presentBarrier = in_ext->presentBarrier; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR: - { - VkPhysicalDevicePerformanceQueryFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePerformanceQueryFeaturesKHR32 *in_ext = (const VkPhysicalDevicePerformanceQueryFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->performanceCounterQueryPools = in_ext->performanceCounterQueryPools; - out_ext->performanceCounterMultipleQueryPools = in_ext->performanceCounterMultipleQueryPools; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV: - { - VkPhysicalDeviceCoverageReductionModeFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCoverageReductionModeFeaturesNV32 *in_ext = (const VkPhysicalDeviceCoverageReductionModeFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->coverageReductionMode = in_ext->coverageReductionMode; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL: - { - VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL32 *in_ext = (const VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL; - out_ext->pNext = NULL; - out_ext->shaderIntegerFunctions2 = in_ext->shaderIntegerFunctions2; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR: - { - VkPhysicalDeviceShaderClockFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderClockFeaturesKHR32 *in_ext = (const VkPhysicalDeviceShaderClockFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->shaderSubgroupClock = in_ext->shaderSubgroupClock; - out_ext->shaderDeviceClock = in_ext->shaderDeviceClock; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT: - { - VkPhysicalDeviceIndexTypeUint8FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceIndexTypeUint8FeaturesEXT32 *in_ext = (const VkPhysicalDeviceIndexTypeUint8FeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->indexTypeUint8 = in_ext->indexTypeUint8; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV: - { - VkPhysicalDeviceShaderSMBuiltinsFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderSMBuiltinsFeaturesNV32 *in_ext = (const VkPhysicalDeviceShaderSMBuiltinsFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->shaderSMBuiltins = in_ext->shaderSMBuiltins; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: - { - VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT32 *in_ext = (const VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->fragmentShaderSampleInterlock = in_ext->fragmentShaderSampleInterlock; - out_ext->fragmentShaderPixelInterlock = in_ext->fragmentShaderPixelInterlock; - out_ext->fragmentShaderShadingRateInterlock = in_ext->fragmentShaderShadingRateInterlock; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES: - { - VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures32 *in_ext = (const VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES; - out_ext->pNext = NULL; - out_ext->separateDepthStencilLayouts = in_ext->separateDepthStencilLayouts; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT: - { - VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT32 *in_ext = (const VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->primitiveTopologyListRestart = in_ext->primitiveTopologyListRestart; - out_ext->primitiveTopologyPatchListRestart = in_ext->primitiveTopologyPatchListRestart; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR: - { - VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR32 *in_ext = (const VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->pipelineExecutableInfo = in_ext->pipelineExecutableInfo; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES: - { - VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures32 *in_ext = (const VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderDemoteToHelperInvocation = in_ext->shaderDemoteToHelperInvocation; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT: - { - VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT32 *in_ext = (const VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->texelBufferAlignment = in_ext->texelBufferAlignment; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES: - { - VkPhysicalDeviceSubgroupSizeControlFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSubgroupSizeControlFeatures32 *in_ext = (const VkPhysicalDeviceSubgroupSizeControlFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES; - out_ext->pNext = NULL; - out_ext->subgroupSizeControl = in_ext->subgroupSizeControl; - out_ext->computeFullSubgroups = in_ext->computeFullSubgroups; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT: - { - VkPhysicalDeviceLineRasterizationFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceLineRasterizationFeaturesEXT32 *in_ext = (const VkPhysicalDeviceLineRasterizationFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->rectangularLines = in_ext->rectangularLines; - out_ext->bresenhamLines = in_ext->bresenhamLines; - out_ext->smoothLines = in_ext->smoothLines; - out_ext->stippledRectangularLines = in_ext->stippledRectangularLines; - out_ext->stippledBresenhamLines = in_ext->stippledBresenhamLines; - out_ext->stippledSmoothLines = in_ext->stippledSmoothLines; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES: - { - VkPhysicalDevicePipelineCreationCacheControlFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePipelineCreationCacheControlFeatures32 *in_ext = (const VkPhysicalDevicePipelineCreationCacheControlFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES; - out_ext->pNext = NULL; - out_ext->pipelineCreationCacheControl = in_ext->pipelineCreationCacheControl; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES: - { - VkPhysicalDeviceVulkan11Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVulkan11Features32 *in_ext = (const VkPhysicalDeviceVulkan11Features32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; - out_ext->pNext = NULL; - out_ext->storageBuffer16BitAccess = in_ext->storageBuffer16BitAccess; - out_ext->uniformAndStorageBuffer16BitAccess = in_ext->uniformAndStorageBuffer16BitAccess; - out_ext->storagePushConstant16 = in_ext->storagePushConstant16; - out_ext->storageInputOutput16 = in_ext->storageInputOutput16; - out_ext->multiview = in_ext->multiview; - out_ext->multiviewGeometryShader = in_ext->multiviewGeometryShader; - out_ext->multiviewTessellationShader = in_ext->multiviewTessellationShader; - out_ext->variablePointersStorageBuffer = in_ext->variablePointersStorageBuffer; - out_ext->variablePointers = in_ext->variablePointers; - out_ext->protectedMemory = in_ext->protectedMemory; - out_ext->samplerYcbcrConversion = in_ext->samplerYcbcrConversion; - out_ext->shaderDrawParameters = in_ext->shaderDrawParameters; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES: - { - VkPhysicalDeviceVulkan12Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVulkan12Features32 *in_ext = (const VkPhysicalDeviceVulkan12Features32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; - out_ext->pNext = NULL; - out_ext->samplerMirrorClampToEdge = in_ext->samplerMirrorClampToEdge; - out_ext->drawIndirectCount = in_ext->drawIndirectCount; - out_ext->storageBuffer8BitAccess = in_ext->storageBuffer8BitAccess; - out_ext->uniformAndStorageBuffer8BitAccess = in_ext->uniformAndStorageBuffer8BitAccess; - out_ext->storagePushConstant8 = in_ext->storagePushConstant8; - out_ext->shaderBufferInt64Atomics = in_ext->shaderBufferInt64Atomics; - out_ext->shaderSharedInt64Atomics = in_ext->shaderSharedInt64Atomics; - out_ext->shaderFloat16 = in_ext->shaderFloat16; - out_ext->shaderInt8 = in_ext->shaderInt8; - out_ext->descriptorIndexing = in_ext->descriptorIndexing; - out_ext->shaderInputAttachmentArrayDynamicIndexing = in_ext->shaderInputAttachmentArrayDynamicIndexing; - out_ext->shaderUniformTexelBufferArrayDynamicIndexing = in_ext->shaderUniformTexelBufferArrayDynamicIndexing; - out_ext->shaderStorageTexelBufferArrayDynamicIndexing = in_ext->shaderStorageTexelBufferArrayDynamicIndexing; - out_ext->shaderUniformBufferArrayNonUniformIndexing = in_ext->shaderUniformBufferArrayNonUniformIndexing; - out_ext->shaderSampledImageArrayNonUniformIndexing = in_ext->shaderSampledImageArrayNonUniformIndexing; - out_ext->shaderStorageBufferArrayNonUniformIndexing = in_ext->shaderStorageBufferArrayNonUniformIndexing; - out_ext->shaderStorageImageArrayNonUniformIndexing = in_ext->shaderStorageImageArrayNonUniformIndexing; - out_ext->shaderInputAttachmentArrayNonUniformIndexing = in_ext->shaderInputAttachmentArrayNonUniformIndexing; - out_ext->shaderUniformTexelBufferArrayNonUniformIndexing = in_ext->shaderUniformTexelBufferArrayNonUniformIndexing; - out_ext->shaderStorageTexelBufferArrayNonUniformIndexing = in_ext->shaderStorageTexelBufferArrayNonUniformIndexing; - out_ext->descriptorBindingUniformBufferUpdateAfterBind = in_ext->descriptorBindingUniformBufferUpdateAfterBind; - out_ext->descriptorBindingSampledImageUpdateAfterBind = in_ext->descriptorBindingSampledImageUpdateAfterBind; - out_ext->descriptorBindingStorageImageUpdateAfterBind = in_ext->descriptorBindingStorageImageUpdateAfterBind; - out_ext->descriptorBindingStorageBufferUpdateAfterBind = in_ext->descriptorBindingStorageBufferUpdateAfterBind; - out_ext->descriptorBindingUniformTexelBufferUpdateAfterBind = in_ext->descriptorBindingUniformTexelBufferUpdateAfterBind; - out_ext->descriptorBindingStorageTexelBufferUpdateAfterBind = in_ext->descriptorBindingStorageTexelBufferUpdateAfterBind; - out_ext->descriptorBindingUpdateUnusedWhilePending = in_ext->descriptorBindingUpdateUnusedWhilePending; - out_ext->descriptorBindingPartiallyBound = in_ext->descriptorBindingPartiallyBound; - out_ext->descriptorBindingVariableDescriptorCount = in_ext->descriptorBindingVariableDescriptorCount; - out_ext->runtimeDescriptorArray = in_ext->runtimeDescriptorArray; - out_ext->samplerFilterMinmax = in_ext->samplerFilterMinmax; - out_ext->scalarBlockLayout = in_ext->scalarBlockLayout; - out_ext->imagelessFramebuffer = in_ext->imagelessFramebuffer; - out_ext->uniformBufferStandardLayout = in_ext->uniformBufferStandardLayout; - out_ext->shaderSubgroupExtendedTypes = in_ext->shaderSubgroupExtendedTypes; - out_ext->separateDepthStencilLayouts = in_ext->separateDepthStencilLayouts; - out_ext->hostQueryReset = in_ext->hostQueryReset; - out_ext->timelineSemaphore = in_ext->timelineSemaphore; - out_ext->bufferDeviceAddress = in_ext->bufferDeviceAddress; - out_ext->bufferDeviceAddressCaptureReplay = in_ext->bufferDeviceAddressCaptureReplay; - out_ext->bufferDeviceAddressMultiDevice = in_ext->bufferDeviceAddressMultiDevice; - out_ext->vulkanMemoryModel = in_ext->vulkanMemoryModel; - out_ext->vulkanMemoryModelDeviceScope = in_ext->vulkanMemoryModelDeviceScope; - out_ext->vulkanMemoryModelAvailabilityVisibilityChains = in_ext->vulkanMemoryModelAvailabilityVisibilityChains; - out_ext->shaderOutputViewportIndex = in_ext->shaderOutputViewportIndex; - out_ext->shaderOutputLayer = in_ext->shaderOutputLayer; - out_ext->subgroupBroadcastDynamicId = in_ext->subgroupBroadcastDynamicId; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES: - { - VkPhysicalDeviceVulkan13Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVulkan13Features32 *in_ext = (const VkPhysicalDeviceVulkan13Features32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; - out_ext->pNext = NULL; - out_ext->robustImageAccess = in_ext->robustImageAccess; - out_ext->inlineUniformBlock = in_ext->inlineUniformBlock; - out_ext->descriptorBindingInlineUniformBlockUpdateAfterBind = in_ext->descriptorBindingInlineUniformBlockUpdateAfterBind; - out_ext->pipelineCreationCacheControl = in_ext->pipelineCreationCacheControl; - out_ext->privateData = in_ext->privateData; - out_ext->shaderDemoteToHelperInvocation = in_ext->shaderDemoteToHelperInvocation; - out_ext->shaderTerminateInvocation = in_ext->shaderTerminateInvocation; - out_ext->subgroupSizeControl = in_ext->subgroupSizeControl; - out_ext->computeFullSubgroups = in_ext->computeFullSubgroups; - out_ext->synchronization2 = in_ext->synchronization2; - out_ext->textureCompressionASTC_HDR = in_ext->textureCompressionASTC_HDR; - out_ext->shaderZeroInitializeWorkgroupMemory = in_ext->shaderZeroInitializeWorkgroupMemory; - out_ext->dynamicRendering = in_ext->dynamicRendering; - out_ext->shaderIntegerDotProduct = in_ext->shaderIntegerDotProduct; - out_ext->maintenance4 = in_ext->maintenance4; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD: - { - VkPhysicalDeviceCoherentMemoryFeaturesAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCoherentMemoryFeaturesAMD32 *in_ext = (const VkPhysicalDeviceCoherentMemoryFeaturesAMD32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD; - out_ext->pNext = NULL; - out_ext->deviceCoherentMemory = in_ext->deviceCoherentMemory; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT: - { - VkPhysicalDeviceCustomBorderColorFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceCustomBorderColorFeaturesEXT32 *in_ext = (const VkPhysicalDeviceCustomBorderColorFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->customBorderColors = in_ext->customBorderColors; - out_ext->customBorderColorWithoutFormat = in_ext->customBorderColorWithoutFormat; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT: - { - VkPhysicalDeviceBorderColorSwizzleFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceBorderColorSwizzleFeaturesEXT32 *in_ext = (const VkPhysicalDeviceBorderColorSwizzleFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->borderColorSwizzle = in_ext->borderColorSwizzle; - out_ext->borderColorSwizzleFromImage = in_ext->borderColorSwizzleFromImage; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT: - { - VkPhysicalDeviceExtendedDynamicStateFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceExtendedDynamicStateFeaturesEXT32 *in_ext = (const VkPhysicalDeviceExtendedDynamicStateFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->extendedDynamicState = in_ext->extendedDynamicState; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT: - { - VkPhysicalDeviceExtendedDynamicState2FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceExtendedDynamicState2FeaturesEXT32 *in_ext = (const VkPhysicalDeviceExtendedDynamicState2FeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->extendedDynamicState2 = in_ext->extendedDynamicState2; - out_ext->extendedDynamicState2LogicOp = in_ext->extendedDynamicState2LogicOp; - out_ext->extendedDynamicState2PatchControlPoints = in_ext->extendedDynamicState2PatchControlPoints; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT: - { - VkPhysicalDeviceExtendedDynamicState3FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceExtendedDynamicState3FeaturesEXT32 *in_ext = (const VkPhysicalDeviceExtendedDynamicState3FeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->extendedDynamicState3TessellationDomainOrigin = in_ext->extendedDynamicState3TessellationDomainOrigin; - out_ext->extendedDynamicState3DepthClampEnable = in_ext->extendedDynamicState3DepthClampEnable; - out_ext->extendedDynamicState3PolygonMode = in_ext->extendedDynamicState3PolygonMode; - out_ext->extendedDynamicState3RasterizationSamples = in_ext->extendedDynamicState3RasterizationSamples; - out_ext->extendedDynamicState3SampleMask = in_ext->extendedDynamicState3SampleMask; - out_ext->extendedDynamicState3AlphaToCoverageEnable = in_ext->extendedDynamicState3AlphaToCoverageEnable; - out_ext->extendedDynamicState3AlphaToOneEnable = in_ext->extendedDynamicState3AlphaToOneEnable; - out_ext->extendedDynamicState3LogicOpEnable = in_ext->extendedDynamicState3LogicOpEnable; - out_ext->extendedDynamicState3ColorBlendEnable = in_ext->extendedDynamicState3ColorBlendEnable; - out_ext->extendedDynamicState3ColorBlendEquation = in_ext->extendedDynamicState3ColorBlendEquation; - out_ext->extendedDynamicState3ColorWriteMask = in_ext->extendedDynamicState3ColorWriteMask; - out_ext->extendedDynamicState3RasterizationStream = in_ext->extendedDynamicState3RasterizationStream; - out_ext->extendedDynamicState3ConservativeRasterizationMode = in_ext->extendedDynamicState3ConservativeRasterizationMode; - out_ext->extendedDynamicState3ExtraPrimitiveOverestimationSize = in_ext->extendedDynamicState3ExtraPrimitiveOverestimationSize; - out_ext->extendedDynamicState3DepthClipEnable = in_ext->extendedDynamicState3DepthClipEnable; - out_ext->extendedDynamicState3SampleLocationsEnable = in_ext->extendedDynamicState3SampleLocationsEnable; - out_ext->extendedDynamicState3ColorBlendAdvanced = in_ext->extendedDynamicState3ColorBlendAdvanced; - out_ext->extendedDynamicState3ProvokingVertexMode = in_ext->extendedDynamicState3ProvokingVertexMode; - out_ext->extendedDynamicState3LineRasterizationMode = in_ext->extendedDynamicState3LineRasterizationMode; - out_ext->extendedDynamicState3LineStippleEnable = in_ext->extendedDynamicState3LineStippleEnable; - out_ext->extendedDynamicState3DepthClipNegativeOneToOne = in_ext->extendedDynamicState3DepthClipNegativeOneToOne; - out_ext->extendedDynamicState3ViewportWScalingEnable = in_ext->extendedDynamicState3ViewportWScalingEnable; - out_ext->extendedDynamicState3ViewportSwizzle = in_ext->extendedDynamicState3ViewportSwizzle; - out_ext->extendedDynamicState3CoverageToColorEnable = in_ext->extendedDynamicState3CoverageToColorEnable; - out_ext->extendedDynamicState3CoverageToColorLocation = in_ext->extendedDynamicState3CoverageToColorLocation; - out_ext->extendedDynamicState3CoverageModulationMode = in_ext->extendedDynamicState3CoverageModulationMode; - out_ext->extendedDynamicState3CoverageModulationTableEnable = in_ext->extendedDynamicState3CoverageModulationTableEnable; - out_ext->extendedDynamicState3CoverageModulationTable = in_ext->extendedDynamicState3CoverageModulationTable; - out_ext->extendedDynamicState3CoverageReductionMode = in_ext->extendedDynamicState3CoverageReductionMode; - out_ext->extendedDynamicState3RepresentativeFragmentTestEnable = in_ext->extendedDynamicState3RepresentativeFragmentTestEnable; - out_ext->extendedDynamicState3ShadingRateImageEnable = in_ext->extendedDynamicState3ShadingRateImageEnable; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV: - { - VkPhysicalDeviceDiagnosticsConfigFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDiagnosticsConfigFeaturesNV32 *in_ext = (const VkPhysicalDeviceDiagnosticsConfigFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->diagnosticsConfig = in_ext->diagnosticsConfig; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES: - { - VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures32 *in_ext = (const VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderZeroInitializeWorkgroupMemory = in_ext->shaderZeroInitializeWorkgroupMemory; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR: - { - VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR32 *in_ext = (const VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->shaderSubgroupUniformControlFlow = in_ext->shaderSubgroupUniformControlFlow; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT: - { - VkPhysicalDeviceRobustness2FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRobustness2FeaturesEXT32 *in_ext = (const VkPhysicalDeviceRobustness2FeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->robustBufferAccess2 = in_ext->robustBufferAccess2; - out_ext->robustImageAccess2 = in_ext->robustImageAccess2; - out_ext->nullDescriptor = in_ext->nullDescriptor; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES: - { - VkPhysicalDeviceImageRobustnessFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImageRobustnessFeatures32 *in_ext = (const VkPhysicalDeviceImageRobustnessFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES; - out_ext->pNext = NULL; - out_ext->robustImageAccess = in_ext->robustImageAccess; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR: - { - VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR32 *in_ext = (const VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->workgroupMemoryExplicitLayout = in_ext->workgroupMemoryExplicitLayout; - out_ext->workgroupMemoryExplicitLayoutScalarBlockLayout = in_ext->workgroupMemoryExplicitLayoutScalarBlockLayout; - out_ext->workgroupMemoryExplicitLayout8BitAccess = in_ext->workgroupMemoryExplicitLayout8BitAccess; - out_ext->workgroupMemoryExplicitLayout16BitAccess = in_ext->workgroupMemoryExplicitLayout16BitAccess; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT: - { - VkPhysicalDevice4444FormatsFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevice4444FormatsFeaturesEXT32 *in_ext = (const VkPhysicalDevice4444FormatsFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->formatA4R4G4B4 = in_ext->formatA4R4G4B4; - out_ext->formatA4B4G4R4 = in_ext->formatA4B4G4R4; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI: - { - VkPhysicalDeviceSubpassShadingFeaturesHUAWEI *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSubpassShadingFeaturesHUAWEI32 *in_ext = (const VkPhysicalDeviceSubpassShadingFeaturesHUAWEI32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI; - out_ext->pNext = NULL; - out_ext->subpassShading = in_ext->subpassShading; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT: - { - VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT32 *in_ext = (const VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->shaderImageInt64Atomics = in_ext->shaderImageInt64Atomics; - out_ext->sparseImageInt64Atomics = in_ext->sparseImageInt64Atomics; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR: - { - VkPhysicalDeviceFragmentShadingRateFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentShadingRateFeaturesKHR32 *in_ext = (const VkPhysicalDeviceFragmentShadingRateFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->pipelineFragmentShadingRate = in_ext->pipelineFragmentShadingRate; - out_ext->primitiveFragmentShadingRate = in_ext->primitiveFragmentShadingRate; - out_ext->attachmentFragmentShadingRate = in_ext->attachmentFragmentShadingRate; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES: - { - VkPhysicalDeviceShaderTerminateInvocationFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderTerminateInvocationFeatures32 *in_ext = (const VkPhysicalDeviceShaderTerminateInvocationFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderTerminateInvocation = in_ext->shaderTerminateInvocation; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV: - { - VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV32 *in_ext = (const VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->fragmentShadingRateEnums = in_ext->fragmentShadingRateEnums; - out_ext->supersampleFragmentShadingRates = in_ext->supersampleFragmentShadingRates; - out_ext->noInvocationFragmentShadingRates = in_ext->noInvocationFragmentShadingRates; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT: - { - VkPhysicalDeviceImage2DViewOf3DFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImage2DViewOf3DFeaturesEXT32 *in_ext = (const VkPhysicalDeviceImage2DViewOf3DFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->image2DViewOf3D = in_ext->image2DViewOf3D; - out_ext->sampler2DViewOf3D = in_ext->sampler2DViewOf3D; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT: - { - VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT32 *in_ext = (const VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->mutableDescriptorType = in_ext->mutableDescriptorType; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT: - { - VkPhysicalDeviceDepthClipControlFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDepthClipControlFeaturesEXT32 *in_ext = (const VkPhysicalDeviceDepthClipControlFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->depthClipControl = in_ext->depthClipControl; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT: - { - VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT32 *in_ext = (const VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->vertexInputDynamicState = in_ext->vertexInputDynamicState; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: - { - VkPhysicalDeviceColorWriteEnableFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceColorWriteEnableFeaturesEXT32 *in_ext = (const VkPhysicalDeviceColorWriteEnableFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->colorWriteEnable = in_ext->colorWriteEnable; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES: - { - VkPhysicalDeviceSynchronization2Features *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSynchronization2Features32 *in_ext = (const VkPhysicalDeviceSynchronization2Features32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES; - out_ext->pNext = NULL; - out_ext->synchronization2 = in_ext->synchronization2; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT: - { - VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT32 *in_ext = (const VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->primitivesGeneratedQuery = in_ext->primitivesGeneratedQuery; - out_ext->primitivesGeneratedQueryWithRasterizerDiscard = in_ext->primitivesGeneratedQueryWithRasterizerDiscard; - out_ext->primitivesGeneratedQueryWithNonZeroStreams = in_ext->primitivesGeneratedQueryWithNonZeroStreams; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT: - { - VkPhysicalDeviceLegacyDitheringFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceLegacyDitheringFeaturesEXT32 *in_ext = (const VkPhysicalDeviceLegacyDitheringFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->legacyDithering = in_ext->legacyDithering; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT: - { - VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT32 *in_ext = (const VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->multisampledRenderToSingleSampled = in_ext->multisampledRenderToSingleSampled; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT: - { - VkPhysicalDevicePipelineProtectedAccessFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePipelineProtectedAccessFeaturesEXT32 *in_ext = (const VkPhysicalDevicePipelineProtectedAccessFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->pipelineProtectedAccess = in_ext->pipelineProtectedAccess; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV: - { - VkPhysicalDeviceInheritedViewportScissorFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceInheritedViewportScissorFeaturesNV32 *in_ext = (const VkPhysicalDeviceInheritedViewportScissorFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->inheritedViewportScissor2D = in_ext->inheritedViewportScissor2D; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT: - { - VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT32 *in_ext = (const VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->ycbcr2plane444Formats = in_ext->ycbcr2plane444Formats; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT: - { - VkPhysicalDeviceProvokingVertexFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceProvokingVertexFeaturesEXT32 *in_ext = (const VkPhysicalDeviceProvokingVertexFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->provokingVertexLast = in_ext->provokingVertexLast; - out_ext->transformFeedbackPreservesProvokingVertex = in_ext->transformFeedbackPreservesProvokingVertex; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT: - { - VkPhysicalDeviceDescriptorBufferFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDescriptorBufferFeaturesEXT32 *in_ext = (const VkPhysicalDeviceDescriptorBufferFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->descriptorBuffer = in_ext->descriptorBuffer; - out_ext->descriptorBufferCaptureReplay = in_ext->descriptorBufferCaptureReplay; - out_ext->descriptorBufferImageLayoutIgnored = in_ext->descriptorBufferImageLayoutIgnored; - out_ext->descriptorBufferPushDescriptors = in_ext->descriptorBufferPushDescriptors; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES: - { - VkPhysicalDeviceShaderIntegerDotProductFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderIntegerDotProductFeatures32 *in_ext = (const VkPhysicalDeviceShaderIntegerDotProductFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES; - out_ext->pNext = NULL; - out_ext->shaderIntegerDotProduct = in_ext->shaderIntegerDotProduct; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR: - { - VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR32 *in_ext = (const VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR; - out_ext->pNext = NULL; - out_ext->fragmentShaderBarycentric = in_ext->fragmentShaderBarycentric; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV: - { - VkPhysicalDeviceRayTracingMotionBlurFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRayTracingMotionBlurFeaturesNV32 *in_ext = (const VkPhysicalDeviceRayTracingMotionBlurFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->rayTracingMotionBlur = in_ext->rayTracingMotionBlur; - out_ext->rayTracingMotionBlurPipelineTraceRaysIndirect = in_ext->rayTracingMotionBlurPipelineTraceRaysIndirect; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT: - { - VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT32 *in_ext = (const VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->formatRgba10x6WithoutYCbCrSampler = in_ext->formatRgba10x6WithoutYCbCrSampler; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES: - { - VkPhysicalDeviceDynamicRenderingFeatures *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDynamicRenderingFeatures32 *in_ext = (const VkPhysicalDeviceDynamicRenderingFeatures32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES; - out_ext->pNext = NULL; - out_ext->dynamicRendering = in_ext->dynamicRendering; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT: - { - VkPhysicalDeviceImageViewMinLodFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImageViewMinLodFeaturesEXT32 *in_ext = (const VkPhysicalDeviceImageViewMinLodFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->minLod = in_ext->minLod; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT: - { - VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT32 *in_ext = (const VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->rasterizationOrderColorAttachmentAccess = in_ext->rasterizationOrderColorAttachmentAccess; - out_ext->rasterizationOrderDepthAttachmentAccess = in_ext->rasterizationOrderDepthAttachmentAccess; - out_ext->rasterizationOrderStencilAttachmentAccess = in_ext->rasterizationOrderStencilAttachmentAccess; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV: - { - VkPhysicalDeviceLinearColorAttachmentFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceLinearColorAttachmentFeaturesNV32 *in_ext = (const VkPhysicalDeviceLinearColorAttachmentFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->linearColorAttachment = in_ext->linearColorAttachment; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT: - { - VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT32 *in_ext = (const VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->graphicsPipelineLibrary = in_ext->graphicsPipelineLibrary; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE: - { - VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE32 *in_ext = (const VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE; - out_ext->pNext = NULL; - out_ext->descriptorSetHostMapping = in_ext->descriptorSetHostMapping; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT: - { - VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT32 *in_ext = (const VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->shaderModuleIdentifier = in_ext->shaderModuleIdentifier; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT: - { - VkPhysicalDeviceImageCompressionControlFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImageCompressionControlFeaturesEXT32 *in_ext = (const VkPhysicalDeviceImageCompressionControlFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->imageCompressionControl = in_ext->imageCompressionControl; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT: - { - VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT32 *in_ext = (const VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->imageCompressionControlSwapchain = in_ext->imageCompressionControlSwapchain; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT: - { - VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT32 *in_ext = (const VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->subpassMergeFeedback = in_ext->subpassMergeFeedback; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_EXT: - { - VkPhysicalDeviceOpacityMicromapFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceOpacityMicromapFeaturesEXT32 *in_ext = (const VkPhysicalDeviceOpacityMicromapFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->micromap = in_ext->micromap; - out_ext->micromapCaptureReplay = in_ext->micromapCaptureReplay; - out_ext->micromapHostCommands = in_ext->micromapHostCommands; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT: - { - VkPhysicalDevicePipelinePropertiesFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePipelinePropertiesFeaturesEXT32 *in_ext = (const VkPhysicalDevicePipelinePropertiesFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->pipelinePropertiesIdentifier = in_ext->pipelinePropertiesIdentifier; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD: - { - VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD32 *in_ext = (const VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD; - out_ext->pNext = NULL; - out_ext->shaderEarlyAndLateFragmentTests = in_ext->shaderEarlyAndLateFragmentTests; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT: - { - VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT32 *in_ext = (const VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->nonSeamlessCubeMap = in_ext->nonSeamlessCubeMap; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT: - { - VkPhysicalDevicePipelineRobustnessFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDevicePipelineRobustnessFeaturesEXT32 *in_ext = (const VkPhysicalDevicePipelineRobustnessFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->pipelineRobustness = in_ext->pipelineRobustness; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM: - { - VkPhysicalDeviceImageProcessingFeaturesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImageProcessingFeaturesQCOM32 *in_ext = (const VkPhysicalDeviceImageProcessingFeaturesQCOM32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM; - out_ext->pNext = NULL; - out_ext->textureSampleWeighted = in_ext->textureSampleWeighted; - out_ext->textureBoxFilter = in_ext->textureBoxFilter; - out_ext->textureBlockMatch = in_ext->textureBlockMatch; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM: - { - VkPhysicalDeviceTilePropertiesFeaturesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceTilePropertiesFeaturesQCOM32 *in_ext = (const VkPhysicalDeviceTilePropertiesFeaturesQCOM32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM; - out_ext->pNext = NULL; - out_ext->tileProperties = in_ext->tileProperties; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT: - { - VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT32 *in_ext = (const VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->attachmentFeedbackLoopLayout = in_ext->attachmentFeedbackLoopLayout; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT: - { - VkPhysicalDeviceDepthClampZeroOneFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceDepthClampZeroOneFeaturesEXT32 *in_ext = (const VkPhysicalDeviceDepthClampZeroOneFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->depthClampZeroOne = in_ext->depthClampZeroOne; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ADDRESS_BINDING_REPORT_FEATURES_EXT: - { - VkPhysicalDeviceAddressBindingReportFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceAddressBindingReportFeaturesEXT32 *in_ext = (const VkPhysicalDeviceAddressBindingReportFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ADDRESS_BINDING_REPORT_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->reportAddressBinding = in_ext->reportAddressBinding; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV: - { - VkPhysicalDeviceOpticalFlowFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceOpticalFlowFeaturesNV32 *in_ext = (const VkPhysicalDeviceOpticalFlowFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->opticalFlow = in_ext->opticalFlow; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT: - { - VkPhysicalDeviceFaultFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFaultFeaturesEXT32 *in_ext = (const VkPhysicalDeviceFaultFeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->deviceFault = in_ext->deviceFault; - out_ext->deviceFaultVendorBinary = in_ext->deviceFaultVendorBinary; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM: - { - VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM32 *in_ext = (const VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM; - out_ext->pNext = NULL; - out_ext->shaderCoreBuiltins = in_ext->shaderCoreBuiltins; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT: - { - VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT32 *in_ext = (const VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT; - out_ext->pNext = NULL; - out_ext->swapchainMaintenance1 = in_ext->swapchainMaintenance1; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV: - { - VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV32 *in_ext = (const VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV; - out_ext->pNext = NULL; - out_ext->rayTracingInvocationReorder = in_ext->rayTracingInvocationReorder; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM: - { - VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM32 *in_ext = (const VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM; - out_ext->pNext = NULL; - out_ext->multiviewPerViewViewports = in_ext->multiviewPerViewViewports; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkPhysicalDeviceFeatures2_host_to_win32(const VkPhysicalDeviceFeatures2 *in, VkPhysicalDeviceFeatures232 *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure32 *out_header = (void *)out; - - if (!in) return; - - out->features = in->features; - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV: - { - VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV); - const VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV *in_ext = (const VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV; - out_ext->deviceGeneratedCommands = in_ext->deviceGeneratedCommands; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES: - { - VkPhysicalDevicePrivateDataFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES); - const VkPhysicalDevicePrivateDataFeatures *in_ext = (const VkPhysicalDevicePrivateDataFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES; - out_ext->privateData = in_ext->privateData; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES: - { - VkPhysicalDeviceVariablePointersFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES); - const VkPhysicalDeviceVariablePointersFeatures *in_ext = (const VkPhysicalDeviceVariablePointersFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES; - out_ext->variablePointersStorageBuffer = in_ext->variablePointersStorageBuffer; - out_ext->variablePointers = in_ext->variablePointers; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: - { - VkPhysicalDeviceMultiviewFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES); - const VkPhysicalDeviceMultiviewFeatures *in_ext = (const VkPhysicalDeviceMultiviewFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; - out_ext->multiview = in_ext->multiview; - out_ext->multiviewGeometryShader = in_ext->multiviewGeometryShader; - out_ext->multiviewTessellationShader = in_ext->multiviewTessellationShader; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR: - { - VkPhysicalDevicePresentIdFeaturesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR); - const VkPhysicalDevicePresentIdFeaturesKHR *in_ext = (const VkPhysicalDevicePresentIdFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR; - out_ext->presentId = in_ext->presentId; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR: - { - VkPhysicalDevicePresentWaitFeaturesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR); - const VkPhysicalDevicePresentWaitFeaturesKHR *in_ext = (const VkPhysicalDevicePresentWaitFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR; - out_ext->presentWait = in_ext->presentWait; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: - { - VkPhysicalDevice16BitStorageFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES); - const VkPhysicalDevice16BitStorageFeatures *in_ext = (const VkPhysicalDevice16BitStorageFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES; - out_ext->storageBuffer16BitAccess = in_ext->storageBuffer16BitAccess; - out_ext->uniformAndStorageBuffer16BitAccess = in_ext->uniformAndStorageBuffer16BitAccess; - out_ext->storagePushConstant16 = in_ext->storagePushConstant16; - out_ext->storageInputOutput16 = in_ext->storageInputOutput16; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES: - { - VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES); - const VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures *in_ext = (const VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES; - out_ext->shaderSubgroupExtendedTypes = in_ext->shaderSubgroupExtendedTypes; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: - { - VkPhysicalDeviceSamplerYcbcrConversionFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES); - const VkPhysicalDeviceSamplerYcbcrConversionFeatures *in_ext = (const VkPhysicalDeviceSamplerYcbcrConversionFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES; - out_ext->samplerYcbcrConversion = in_ext->samplerYcbcrConversion; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES: - { - VkPhysicalDeviceProtectedMemoryFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES); - const VkPhysicalDeviceProtectedMemoryFeatures *in_ext = (const VkPhysicalDeviceProtectedMemoryFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES; - out_ext->protectedMemory = in_ext->protectedMemory; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT: - { - VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT); - const VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT *in_ext = (const VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT; - out_ext->advancedBlendCoherentOperations = in_ext->advancedBlendCoherentOperations; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT: - { - VkPhysicalDeviceMultiDrawFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT); - const VkPhysicalDeviceMultiDrawFeaturesEXT *in_ext = (const VkPhysicalDeviceMultiDrawFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT; - out_ext->multiDraw = in_ext->multiDraw; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES: - { - VkPhysicalDeviceInlineUniformBlockFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES); - const VkPhysicalDeviceInlineUniformBlockFeatures *in_ext = (const VkPhysicalDeviceInlineUniformBlockFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES; - out_ext->inlineUniformBlock = in_ext->inlineUniformBlock; - out_ext->descriptorBindingInlineUniformBlockUpdateAfterBind = in_ext->descriptorBindingInlineUniformBlockUpdateAfterBind; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES: - { - VkPhysicalDeviceMaintenance4Features32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES); - const VkPhysicalDeviceMaintenance4Features *in_ext = (const VkPhysicalDeviceMaintenance4Features *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES; - out_ext->maintenance4 = in_ext->maintenance4; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES: - { - VkPhysicalDeviceShaderDrawParametersFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES); - const VkPhysicalDeviceShaderDrawParametersFeatures *in_ext = (const VkPhysicalDeviceShaderDrawParametersFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; - out_ext->shaderDrawParameters = in_ext->shaderDrawParameters; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES: - { - VkPhysicalDeviceShaderFloat16Int8Features32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES); - const VkPhysicalDeviceShaderFloat16Int8Features *in_ext = (const VkPhysicalDeviceShaderFloat16Int8Features *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES; - out_ext->shaderFloat16 = in_ext->shaderFloat16; - out_ext->shaderInt8 = in_ext->shaderInt8; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES: - { - VkPhysicalDeviceHostQueryResetFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES); - const VkPhysicalDeviceHostQueryResetFeatures *in_ext = (const VkPhysicalDeviceHostQueryResetFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES; - out_ext->hostQueryReset = in_ext->hostQueryReset; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR: - { - VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR); - const VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR *in_ext = (const VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR; - out_ext->globalPriorityQuery = in_ext->globalPriorityQuery; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES: - { - VkPhysicalDeviceDescriptorIndexingFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES); - const VkPhysicalDeviceDescriptorIndexingFeatures *in_ext = (const VkPhysicalDeviceDescriptorIndexingFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; - out_ext->shaderInputAttachmentArrayDynamicIndexing = in_ext->shaderInputAttachmentArrayDynamicIndexing; - out_ext->shaderUniformTexelBufferArrayDynamicIndexing = in_ext->shaderUniformTexelBufferArrayDynamicIndexing; - out_ext->shaderStorageTexelBufferArrayDynamicIndexing = in_ext->shaderStorageTexelBufferArrayDynamicIndexing; - out_ext->shaderUniformBufferArrayNonUniformIndexing = in_ext->shaderUniformBufferArrayNonUniformIndexing; - out_ext->shaderSampledImageArrayNonUniformIndexing = in_ext->shaderSampledImageArrayNonUniformIndexing; - out_ext->shaderStorageBufferArrayNonUniformIndexing = in_ext->shaderStorageBufferArrayNonUniformIndexing; - out_ext->shaderStorageImageArrayNonUniformIndexing = in_ext->shaderStorageImageArrayNonUniformIndexing; - out_ext->shaderInputAttachmentArrayNonUniformIndexing = in_ext->shaderInputAttachmentArrayNonUniformIndexing; - out_ext->shaderUniformTexelBufferArrayNonUniformIndexing = in_ext->shaderUniformTexelBufferArrayNonUniformIndexing; - out_ext->shaderStorageTexelBufferArrayNonUniformIndexing = in_ext->shaderStorageTexelBufferArrayNonUniformIndexing; - out_ext->descriptorBindingUniformBufferUpdateAfterBind = in_ext->descriptorBindingUniformBufferUpdateAfterBind; - out_ext->descriptorBindingSampledImageUpdateAfterBind = in_ext->descriptorBindingSampledImageUpdateAfterBind; - out_ext->descriptorBindingStorageImageUpdateAfterBind = in_ext->descriptorBindingStorageImageUpdateAfterBind; - out_ext->descriptorBindingStorageBufferUpdateAfterBind = in_ext->descriptorBindingStorageBufferUpdateAfterBind; - out_ext->descriptorBindingUniformTexelBufferUpdateAfterBind = in_ext->descriptorBindingUniformTexelBufferUpdateAfterBind; - out_ext->descriptorBindingStorageTexelBufferUpdateAfterBind = in_ext->descriptorBindingStorageTexelBufferUpdateAfterBind; - out_ext->descriptorBindingUpdateUnusedWhilePending = in_ext->descriptorBindingUpdateUnusedWhilePending; - out_ext->descriptorBindingPartiallyBound = in_ext->descriptorBindingPartiallyBound; - out_ext->descriptorBindingVariableDescriptorCount = in_ext->descriptorBindingVariableDescriptorCount; - out_ext->runtimeDescriptorArray = in_ext->runtimeDescriptorArray; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES: - { - VkPhysicalDeviceTimelineSemaphoreFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES); - const VkPhysicalDeviceTimelineSemaphoreFeatures *in_ext = (const VkPhysicalDeviceTimelineSemaphoreFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES; - out_ext->timelineSemaphore = in_ext->timelineSemaphore; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES: - { - VkPhysicalDevice8BitStorageFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES); - const VkPhysicalDevice8BitStorageFeatures *in_ext = (const VkPhysicalDevice8BitStorageFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES; - out_ext->storageBuffer8BitAccess = in_ext->storageBuffer8BitAccess; - out_ext->uniformAndStorageBuffer8BitAccess = in_ext->uniformAndStorageBuffer8BitAccess; - out_ext->storagePushConstant8 = in_ext->storagePushConstant8; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT: - { - VkPhysicalDeviceConditionalRenderingFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT); - const VkPhysicalDeviceConditionalRenderingFeaturesEXT *in_ext = (const VkPhysicalDeviceConditionalRenderingFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT; - out_ext->conditionalRendering = in_ext->conditionalRendering; - out_ext->inheritedConditionalRendering = in_ext->inheritedConditionalRendering; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES: - { - VkPhysicalDeviceVulkanMemoryModelFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES); - const VkPhysicalDeviceVulkanMemoryModelFeatures *in_ext = (const VkPhysicalDeviceVulkanMemoryModelFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES; - out_ext->vulkanMemoryModel = in_ext->vulkanMemoryModel; - out_ext->vulkanMemoryModelDeviceScope = in_ext->vulkanMemoryModelDeviceScope; - out_ext->vulkanMemoryModelAvailabilityVisibilityChains = in_ext->vulkanMemoryModelAvailabilityVisibilityChains; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES: - { - VkPhysicalDeviceShaderAtomicInt64Features32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES); - const VkPhysicalDeviceShaderAtomicInt64Features *in_ext = (const VkPhysicalDeviceShaderAtomicInt64Features *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES; - out_ext->shaderBufferInt64Atomics = in_ext->shaderBufferInt64Atomics; - out_ext->shaderSharedInt64Atomics = in_ext->shaderSharedInt64Atomics; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT: - { - VkPhysicalDeviceShaderAtomicFloatFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT); - const VkPhysicalDeviceShaderAtomicFloatFeaturesEXT *in_ext = (const VkPhysicalDeviceShaderAtomicFloatFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT; - out_ext->shaderBufferFloat32Atomics = in_ext->shaderBufferFloat32Atomics; - out_ext->shaderBufferFloat32AtomicAdd = in_ext->shaderBufferFloat32AtomicAdd; - out_ext->shaderBufferFloat64Atomics = in_ext->shaderBufferFloat64Atomics; - out_ext->shaderBufferFloat64AtomicAdd = in_ext->shaderBufferFloat64AtomicAdd; - out_ext->shaderSharedFloat32Atomics = in_ext->shaderSharedFloat32Atomics; - out_ext->shaderSharedFloat32AtomicAdd = in_ext->shaderSharedFloat32AtomicAdd; - out_ext->shaderSharedFloat64Atomics = in_ext->shaderSharedFloat64Atomics; - out_ext->shaderSharedFloat64AtomicAdd = in_ext->shaderSharedFloat64AtomicAdd; - out_ext->shaderImageFloat32Atomics = in_ext->shaderImageFloat32Atomics; - out_ext->shaderImageFloat32AtomicAdd = in_ext->shaderImageFloat32AtomicAdd; - out_ext->sparseImageFloat32Atomics = in_ext->sparseImageFloat32Atomics; - out_ext->sparseImageFloat32AtomicAdd = in_ext->sparseImageFloat32AtomicAdd; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT: - { - VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT); - const VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT *in_ext = (const VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT; - out_ext->shaderBufferFloat16Atomics = in_ext->shaderBufferFloat16Atomics; - out_ext->shaderBufferFloat16AtomicAdd = in_ext->shaderBufferFloat16AtomicAdd; - out_ext->shaderBufferFloat16AtomicMinMax = in_ext->shaderBufferFloat16AtomicMinMax; - out_ext->shaderBufferFloat32AtomicMinMax = in_ext->shaderBufferFloat32AtomicMinMax; - out_ext->shaderBufferFloat64AtomicMinMax = in_ext->shaderBufferFloat64AtomicMinMax; - out_ext->shaderSharedFloat16Atomics = in_ext->shaderSharedFloat16Atomics; - out_ext->shaderSharedFloat16AtomicAdd = in_ext->shaderSharedFloat16AtomicAdd; - out_ext->shaderSharedFloat16AtomicMinMax = in_ext->shaderSharedFloat16AtomicMinMax; - out_ext->shaderSharedFloat32AtomicMinMax = in_ext->shaderSharedFloat32AtomicMinMax; - out_ext->shaderSharedFloat64AtomicMinMax = in_ext->shaderSharedFloat64AtomicMinMax; - out_ext->shaderImageFloat32AtomicMinMax = in_ext->shaderImageFloat32AtomicMinMax; - out_ext->sparseImageFloat32AtomicMinMax = in_ext->sparseImageFloat32AtomicMinMax; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT: - { - VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT); - const VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *in_ext = (const VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT; - out_ext->vertexAttributeInstanceRateDivisor = in_ext->vertexAttributeInstanceRateDivisor; - out_ext->vertexAttributeInstanceRateZeroDivisor = in_ext->vertexAttributeInstanceRateZeroDivisor; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT: - { - VkPhysicalDeviceASTCDecodeFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT); - const VkPhysicalDeviceASTCDecodeFeaturesEXT *in_ext = (const VkPhysicalDeviceASTCDecodeFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT; - out_ext->decodeModeSharedExponent = in_ext->decodeModeSharedExponent; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT: - { - VkPhysicalDeviceTransformFeedbackFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT); - const VkPhysicalDeviceTransformFeedbackFeaturesEXT *in_ext = (const VkPhysicalDeviceTransformFeedbackFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT; - out_ext->transformFeedback = in_ext->transformFeedback; - out_ext->geometryStreams = in_ext->geometryStreams; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV: - { - VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV); - const VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV *in_ext = (const VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV; - out_ext->representativeFragmentTest = in_ext->representativeFragmentTest; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV: - { - VkPhysicalDeviceExclusiveScissorFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV); - const VkPhysicalDeviceExclusiveScissorFeaturesNV *in_ext = (const VkPhysicalDeviceExclusiveScissorFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV; - out_ext->exclusiveScissor = in_ext->exclusiveScissor; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV: - { - VkPhysicalDeviceCornerSampledImageFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV); - const VkPhysicalDeviceCornerSampledImageFeaturesNV *in_ext = (const VkPhysicalDeviceCornerSampledImageFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV; - out_ext->cornerSampledImage = in_ext->cornerSampledImage; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV: - { - VkPhysicalDeviceComputeShaderDerivativesFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV); - const VkPhysicalDeviceComputeShaderDerivativesFeaturesNV *in_ext = (const VkPhysicalDeviceComputeShaderDerivativesFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV; - out_ext->computeDerivativeGroupQuads = in_ext->computeDerivativeGroupQuads; - out_ext->computeDerivativeGroupLinear = in_ext->computeDerivativeGroupLinear; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV: - { - VkPhysicalDeviceShaderImageFootprintFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV); - const VkPhysicalDeviceShaderImageFootprintFeaturesNV *in_ext = (const VkPhysicalDeviceShaderImageFootprintFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV; - out_ext->imageFootprint = in_ext->imageFootprint; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV: - { - VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV); - const VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV *in_ext = (const VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV; - out_ext->dedicatedAllocationImageAliasing = in_ext->dedicatedAllocationImageAliasing; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_NV: - { - VkPhysicalDeviceCopyMemoryIndirectFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_NV); - const VkPhysicalDeviceCopyMemoryIndirectFeaturesNV *in_ext = (const VkPhysicalDeviceCopyMemoryIndirectFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_NV; - out_ext->indirectCopy = in_ext->indirectCopy; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_NV: - { - VkPhysicalDeviceMemoryDecompressionFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_NV); - const VkPhysicalDeviceMemoryDecompressionFeaturesNV *in_ext = (const VkPhysicalDeviceMemoryDecompressionFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_NV; - out_ext->memoryDecompression = in_ext->memoryDecompression; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV: - { - VkPhysicalDeviceShadingRateImageFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV); - const VkPhysicalDeviceShadingRateImageFeaturesNV *in_ext = (const VkPhysicalDeviceShadingRateImageFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV; - out_ext->shadingRateImage = in_ext->shadingRateImage; - out_ext->shadingRateCoarseSampleOrder = in_ext->shadingRateCoarseSampleOrder; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI: - { - VkPhysicalDeviceInvocationMaskFeaturesHUAWEI32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI); - const VkPhysicalDeviceInvocationMaskFeaturesHUAWEI *in_ext = (const VkPhysicalDeviceInvocationMaskFeaturesHUAWEI *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI; - out_ext->invocationMask = in_ext->invocationMask; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV: - { - VkPhysicalDeviceMeshShaderFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV); - const VkPhysicalDeviceMeshShaderFeaturesNV *in_ext = (const VkPhysicalDeviceMeshShaderFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV; - out_ext->taskShader = in_ext->taskShader; - out_ext->meshShader = in_ext->meshShader; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT: - { - VkPhysicalDeviceMeshShaderFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT); - const VkPhysicalDeviceMeshShaderFeaturesEXT *in_ext = (const VkPhysicalDeviceMeshShaderFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; - out_ext->taskShader = in_ext->taskShader; - out_ext->meshShader = in_ext->meshShader; - out_ext->multiviewMeshShader = in_ext->multiviewMeshShader; - out_ext->primitiveFragmentShadingRateMeshShader = in_ext->primitiveFragmentShadingRateMeshShader; - out_ext->meshShaderQueries = in_ext->meshShaderQueries; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR: - { - VkPhysicalDeviceAccelerationStructureFeaturesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR); - const VkPhysicalDeviceAccelerationStructureFeaturesKHR *in_ext = (const VkPhysicalDeviceAccelerationStructureFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; - out_ext->accelerationStructure = in_ext->accelerationStructure; - out_ext->accelerationStructureCaptureReplay = in_ext->accelerationStructureCaptureReplay; - out_ext->accelerationStructureIndirectBuild = in_ext->accelerationStructureIndirectBuild; - out_ext->accelerationStructureHostCommands = in_ext->accelerationStructureHostCommands; - out_ext->descriptorBindingAccelerationStructureUpdateAfterBind = in_ext->descriptorBindingAccelerationStructureUpdateAfterBind; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR: - { - VkPhysicalDeviceRayTracingPipelineFeaturesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR); - const VkPhysicalDeviceRayTracingPipelineFeaturesKHR *in_ext = (const VkPhysicalDeviceRayTracingPipelineFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; - out_ext->rayTracingPipeline = in_ext->rayTracingPipeline; - out_ext->rayTracingPipelineShaderGroupHandleCaptureReplay = in_ext->rayTracingPipelineShaderGroupHandleCaptureReplay; - out_ext->rayTracingPipelineShaderGroupHandleCaptureReplayMixed = in_ext->rayTracingPipelineShaderGroupHandleCaptureReplayMixed; - out_ext->rayTracingPipelineTraceRaysIndirect = in_ext->rayTracingPipelineTraceRaysIndirect; - out_ext->rayTraversalPrimitiveCulling = in_ext->rayTraversalPrimitiveCulling; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR: - { - VkPhysicalDeviceRayQueryFeaturesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR); - const VkPhysicalDeviceRayQueryFeaturesKHR *in_ext = (const VkPhysicalDeviceRayQueryFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR; - out_ext->rayQuery = in_ext->rayQuery; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR: - { - VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR); - const VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR *in_ext = (const VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR; - out_ext->rayTracingMaintenance1 = in_ext->rayTracingMaintenance1; - out_ext->rayTracingPipelineTraceRaysIndirect2 = in_ext->rayTracingPipelineTraceRaysIndirect2; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT: - { - VkPhysicalDeviceFragmentDensityMapFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT); - const VkPhysicalDeviceFragmentDensityMapFeaturesEXT *in_ext = (const VkPhysicalDeviceFragmentDensityMapFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT; - out_ext->fragmentDensityMap = in_ext->fragmentDensityMap; - out_ext->fragmentDensityMapDynamic = in_ext->fragmentDensityMapDynamic; - out_ext->fragmentDensityMapNonSubsampledImages = in_ext->fragmentDensityMapNonSubsampledImages; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT: - { - VkPhysicalDeviceFragmentDensityMap2FeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT); - const VkPhysicalDeviceFragmentDensityMap2FeaturesEXT *in_ext = (const VkPhysicalDeviceFragmentDensityMap2FeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT; - out_ext->fragmentDensityMapDeferred = in_ext->fragmentDensityMapDeferred; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM: - { - VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM); - const VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM *in_ext = (const VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM; - out_ext->fragmentDensityMapOffset = in_ext->fragmentDensityMapOffset; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES: - { - VkPhysicalDeviceScalarBlockLayoutFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES); - const VkPhysicalDeviceScalarBlockLayoutFeatures *in_ext = (const VkPhysicalDeviceScalarBlockLayoutFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES; - out_ext->scalarBlockLayout = in_ext->scalarBlockLayout; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES: - { - VkPhysicalDeviceUniformBufferStandardLayoutFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES); - const VkPhysicalDeviceUniformBufferStandardLayoutFeatures *in_ext = (const VkPhysicalDeviceUniformBufferStandardLayoutFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES; - out_ext->uniformBufferStandardLayout = in_ext->uniformBufferStandardLayout; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT: - { - VkPhysicalDeviceDepthClipEnableFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT); - const VkPhysicalDeviceDepthClipEnableFeaturesEXT *in_ext = (const VkPhysicalDeviceDepthClipEnableFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT; - out_ext->depthClipEnable = in_ext->depthClipEnable; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT: - { - VkPhysicalDeviceMemoryPriorityFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT); - const VkPhysicalDeviceMemoryPriorityFeaturesEXT *in_ext = (const VkPhysicalDeviceMemoryPriorityFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT; - out_ext->memoryPriority = in_ext->memoryPriority; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT: - { - VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT); - const VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT *in_ext = (const VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT; - out_ext->pageableDeviceLocalMemory = in_ext->pageableDeviceLocalMemory; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES: - { - VkPhysicalDeviceBufferDeviceAddressFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES); - const VkPhysicalDeviceBufferDeviceAddressFeatures *in_ext = (const VkPhysicalDeviceBufferDeviceAddressFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES; - out_ext->bufferDeviceAddress = in_ext->bufferDeviceAddress; - out_ext->bufferDeviceAddressCaptureReplay = in_ext->bufferDeviceAddressCaptureReplay; - out_ext->bufferDeviceAddressMultiDevice = in_ext->bufferDeviceAddressMultiDevice; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT: - { - VkPhysicalDeviceBufferDeviceAddressFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT); - const VkPhysicalDeviceBufferDeviceAddressFeaturesEXT *in_ext = (const VkPhysicalDeviceBufferDeviceAddressFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT; - out_ext->bufferDeviceAddress = in_ext->bufferDeviceAddress; - out_ext->bufferDeviceAddressCaptureReplay = in_ext->bufferDeviceAddressCaptureReplay; - out_ext->bufferDeviceAddressMultiDevice = in_ext->bufferDeviceAddressMultiDevice; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES: - { - VkPhysicalDeviceImagelessFramebufferFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES); - const VkPhysicalDeviceImagelessFramebufferFeatures *in_ext = (const VkPhysicalDeviceImagelessFramebufferFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES; - out_ext->imagelessFramebuffer = in_ext->imagelessFramebuffer; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES: - { - VkPhysicalDeviceTextureCompressionASTCHDRFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES); - const VkPhysicalDeviceTextureCompressionASTCHDRFeatures *in_ext = (const VkPhysicalDeviceTextureCompressionASTCHDRFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES; - out_ext->textureCompressionASTC_HDR = in_ext->textureCompressionASTC_HDR; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV: - { - VkPhysicalDeviceCooperativeMatrixFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV); - const VkPhysicalDeviceCooperativeMatrixFeaturesNV *in_ext = (const VkPhysicalDeviceCooperativeMatrixFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV; - out_ext->cooperativeMatrix = in_ext->cooperativeMatrix; - out_ext->cooperativeMatrixRobustBufferAccess = in_ext->cooperativeMatrixRobustBufferAccess; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT: - { - VkPhysicalDeviceYcbcrImageArraysFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT); - const VkPhysicalDeviceYcbcrImageArraysFeaturesEXT *in_ext = (const VkPhysicalDeviceYcbcrImageArraysFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT; - out_ext->ycbcrImageArrays = in_ext->ycbcrImageArrays; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_BARRIER_FEATURES_NV: - { - VkPhysicalDevicePresentBarrierFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_BARRIER_FEATURES_NV); - const VkPhysicalDevicePresentBarrierFeaturesNV *in_ext = (const VkPhysicalDevicePresentBarrierFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_BARRIER_FEATURES_NV; - out_ext->presentBarrier = in_ext->presentBarrier; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR: - { - VkPhysicalDevicePerformanceQueryFeaturesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR); - const VkPhysicalDevicePerformanceQueryFeaturesKHR *in_ext = (const VkPhysicalDevicePerformanceQueryFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR; - out_ext->performanceCounterQueryPools = in_ext->performanceCounterQueryPools; - out_ext->performanceCounterMultipleQueryPools = in_ext->performanceCounterMultipleQueryPools; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV: - { - VkPhysicalDeviceCoverageReductionModeFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV); - const VkPhysicalDeviceCoverageReductionModeFeaturesNV *in_ext = (const VkPhysicalDeviceCoverageReductionModeFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV; - out_ext->coverageReductionMode = in_ext->coverageReductionMode; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL: - { - VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL); - const VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL *in_ext = (const VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL; - out_ext->shaderIntegerFunctions2 = in_ext->shaderIntegerFunctions2; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR: - { - VkPhysicalDeviceShaderClockFeaturesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR); - const VkPhysicalDeviceShaderClockFeaturesKHR *in_ext = (const VkPhysicalDeviceShaderClockFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR; - out_ext->shaderSubgroupClock = in_ext->shaderSubgroupClock; - out_ext->shaderDeviceClock = in_ext->shaderDeviceClock; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT: - { - VkPhysicalDeviceIndexTypeUint8FeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT); - const VkPhysicalDeviceIndexTypeUint8FeaturesEXT *in_ext = (const VkPhysicalDeviceIndexTypeUint8FeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT; - out_ext->indexTypeUint8 = in_ext->indexTypeUint8; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV: - { - VkPhysicalDeviceShaderSMBuiltinsFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV); - const VkPhysicalDeviceShaderSMBuiltinsFeaturesNV *in_ext = (const VkPhysicalDeviceShaderSMBuiltinsFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV; - out_ext->shaderSMBuiltins = in_ext->shaderSMBuiltins; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: - { - VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT); - const VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT *in_ext = (const VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT; - out_ext->fragmentShaderSampleInterlock = in_ext->fragmentShaderSampleInterlock; - out_ext->fragmentShaderPixelInterlock = in_ext->fragmentShaderPixelInterlock; - out_ext->fragmentShaderShadingRateInterlock = in_ext->fragmentShaderShadingRateInterlock; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES: - { - VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES); - const VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures *in_ext = (const VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES; - out_ext->separateDepthStencilLayouts = in_ext->separateDepthStencilLayouts; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT: - { - VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT); - const VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *in_ext = (const VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT; - out_ext->primitiveTopologyListRestart = in_ext->primitiveTopologyListRestart; - out_ext->primitiveTopologyPatchListRestart = in_ext->primitiveTopologyPatchListRestart; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR: - { - VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR); - const VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR *in_ext = (const VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR; - out_ext->pipelineExecutableInfo = in_ext->pipelineExecutableInfo; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES: - { - VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES); - const VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures *in_ext = (const VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES; - out_ext->shaderDemoteToHelperInvocation = in_ext->shaderDemoteToHelperInvocation; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT: - { - VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT); - const VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT *in_ext = (const VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT; - out_ext->texelBufferAlignment = in_ext->texelBufferAlignment; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES: - { - VkPhysicalDeviceSubgroupSizeControlFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES); - const VkPhysicalDeviceSubgroupSizeControlFeatures *in_ext = (const VkPhysicalDeviceSubgroupSizeControlFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES; - out_ext->subgroupSizeControl = in_ext->subgroupSizeControl; - out_ext->computeFullSubgroups = in_ext->computeFullSubgroups; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT: - { - VkPhysicalDeviceLineRasterizationFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT); - const VkPhysicalDeviceLineRasterizationFeaturesEXT *in_ext = (const VkPhysicalDeviceLineRasterizationFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT; - out_ext->rectangularLines = in_ext->rectangularLines; - out_ext->bresenhamLines = in_ext->bresenhamLines; - out_ext->smoothLines = in_ext->smoothLines; - out_ext->stippledRectangularLines = in_ext->stippledRectangularLines; - out_ext->stippledBresenhamLines = in_ext->stippledBresenhamLines; - out_ext->stippledSmoothLines = in_ext->stippledSmoothLines; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES: - { - VkPhysicalDevicePipelineCreationCacheControlFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES); - const VkPhysicalDevicePipelineCreationCacheControlFeatures *in_ext = (const VkPhysicalDevicePipelineCreationCacheControlFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES; - out_ext->pipelineCreationCacheControl = in_ext->pipelineCreationCacheControl; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES: - { - VkPhysicalDeviceVulkan11Features32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES); - const VkPhysicalDeviceVulkan11Features *in_ext = (const VkPhysicalDeviceVulkan11Features *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; - out_ext->storageBuffer16BitAccess = in_ext->storageBuffer16BitAccess; - out_ext->uniformAndStorageBuffer16BitAccess = in_ext->uniformAndStorageBuffer16BitAccess; - out_ext->storagePushConstant16 = in_ext->storagePushConstant16; - out_ext->storageInputOutput16 = in_ext->storageInputOutput16; - out_ext->multiview = in_ext->multiview; - out_ext->multiviewGeometryShader = in_ext->multiviewGeometryShader; - out_ext->multiviewTessellationShader = in_ext->multiviewTessellationShader; - out_ext->variablePointersStorageBuffer = in_ext->variablePointersStorageBuffer; - out_ext->variablePointers = in_ext->variablePointers; - out_ext->protectedMemory = in_ext->protectedMemory; - out_ext->samplerYcbcrConversion = in_ext->samplerYcbcrConversion; - out_ext->shaderDrawParameters = in_ext->shaderDrawParameters; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES: - { - VkPhysicalDeviceVulkan12Features32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES); - const VkPhysicalDeviceVulkan12Features *in_ext = (const VkPhysicalDeviceVulkan12Features *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; - out_ext->samplerMirrorClampToEdge = in_ext->samplerMirrorClampToEdge; - out_ext->drawIndirectCount = in_ext->drawIndirectCount; - out_ext->storageBuffer8BitAccess = in_ext->storageBuffer8BitAccess; - out_ext->uniformAndStorageBuffer8BitAccess = in_ext->uniformAndStorageBuffer8BitAccess; - out_ext->storagePushConstant8 = in_ext->storagePushConstant8; - out_ext->shaderBufferInt64Atomics = in_ext->shaderBufferInt64Atomics; - out_ext->shaderSharedInt64Atomics = in_ext->shaderSharedInt64Atomics; - out_ext->shaderFloat16 = in_ext->shaderFloat16; - out_ext->shaderInt8 = in_ext->shaderInt8; - out_ext->descriptorIndexing = in_ext->descriptorIndexing; - out_ext->shaderInputAttachmentArrayDynamicIndexing = in_ext->shaderInputAttachmentArrayDynamicIndexing; - out_ext->shaderUniformTexelBufferArrayDynamicIndexing = in_ext->shaderUniformTexelBufferArrayDynamicIndexing; - out_ext->shaderStorageTexelBufferArrayDynamicIndexing = in_ext->shaderStorageTexelBufferArrayDynamicIndexing; - out_ext->shaderUniformBufferArrayNonUniformIndexing = in_ext->shaderUniformBufferArrayNonUniformIndexing; - out_ext->shaderSampledImageArrayNonUniformIndexing = in_ext->shaderSampledImageArrayNonUniformIndexing; - out_ext->shaderStorageBufferArrayNonUniformIndexing = in_ext->shaderStorageBufferArrayNonUniformIndexing; - out_ext->shaderStorageImageArrayNonUniformIndexing = in_ext->shaderStorageImageArrayNonUniformIndexing; - out_ext->shaderInputAttachmentArrayNonUniformIndexing = in_ext->shaderInputAttachmentArrayNonUniformIndexing; - out_ext->shaderUniformTexelBufferArrayNonUniformIndexing = in_ext->shaderUniformTexelBufferArrayNonUniformIndexing; - out_ext->shaderStorageTexelBufferArrayNonUniformIndexing = in_ext->shaderStorageTexelBufferArrayNonUniformIndexing; - out_ext->descriptorBindingUniformBufferUpdateAfterBind = in_ext->descriptorBindingUniformBufferUpdateAfterBind; - out_ext->descriptorBindingSampledImageUpdateAfterBind = in_ext->descriptorBindingSampledImageUpdateAfterBind; - out_ext->descriptorBindingStorageImageUpdateAfterBind = in_ext->descriptorBindingStorageImageUpdateAfterBind; - out_ext->descriptorBindingStorageBufferUpdateAfterBind = in_ext->descriptorBindingStorageBufferUpdateAfterBind; - out_ext->descriptorBindingUniformTexelBufferUpdateAfterBind = in_ext->descriptorBindingUniformTexelBufferUpdateAfterBind; - out_ext->descriptorBindingStorageTexelBufferUpdateAfterBind = in_ext->descriptorBindingStorageTexelBufferUpdateAfterBind; - out_ext->descriptorBindingUpdateUnusedWhilePending = in_ext->descriptorBindingUpdateUnusedWhilePending; - out_ext->descriptorBindingPartiallyBound = in_ext->descriptorBindingPartiallyBound; - out_ext->descriptorBindingVariableDescriptorCount = in_ext->descriptorBindingVariableDescriptorCount; - out_ext->runtimeDescriptorArray = in_ext->runtimeDescriptorArray; - out_ext->samplerFilterMinmax = in_ext->samplerFilterMinmax; - out_ext->scalarBlockLayout = in_ext->scalarBlockLayout; - out_ext->imagelessFramebuffer = in_ext->imagelessFramebuffer; - out_ext->uniformBufferStandardLayout = in_ext->uniformBufferStandardLayout; - out_ext->shaderSubgroupExtendedTypes = in_ext->shaderSubgroupExtendedTypes; - out_ext->separateDepthStencilLayouts = in_ext->separateDepthStencilLayouts; - out_ext->hostQueryReset = in_ext->hostQueryReset; - out_ext->timelineSemaphore = in_ext->timelineSemaphore; - out_ext->bufferDeviceAddress = in_ext->bufferDeviceAddress; - out_ext->bufferDeviceAddressCaptureReplay = in_ext->bufferDeviceAddressCaptureReplay; - out_ext->bufferDeviceAddressMultiDevice = in_ext->bufferDeviceAddressMultiDevice; - out_ext->vulkanMemoryModel = in_ext->vulkanMemoryModel; - out_ext->vulkanMemoryModelDeviceScope = in_ext->vulkanMemoryModelDeviceScope; - out_ext->vulkanMemoryModelAvailabilityVisibilityChains = in_ext->vulkanMemoryModelAvailabilityVisibilityChains; - out_ext->shaderOutputViewportIndex = in_ext->shaderOutputViewportIndex; - out_ext->shaderOutputLayer = in_ext->shaderOutputLayer; - out_ext->subgroupBroadcastDynamicId = in_ext->subgroupBroadcastDynamicId; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES: - { - VkPhysicalDeviceVulkan13Features32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES); - const VkPhysicalDeviceVulkan13Features *in_ext = (const VkPhysicalDeviceVulkan13Features *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; - out_ext->robustImageAccess = in_ext->robustImageAccess; - out_ext->inlineUniformBlock = in_ext->inlineUniformBlock; - out_ext->descriptorBindingInlineUniformBlockUpdateAfterBind = in_ext->descriptorBindingInlineUniformBlockUpdateAfterBind; - out_ext->pipelineCreationCacheControl = in_ext->pipelineCreationCacheControl; - out_ext->privateData = in_ext->privateData; - out_ext->shaderDemoteToHelperInvocation = in_ext->shaderDemoteToHelperInvocation; - out_ext->shaderTerminateInvocation = in_ext->shaderTerminateInvocation; - out_ext->subgroupSizeControl = in_ext->subgroupSizeControl; - out_ext->computeFullSubgroups = in_ext->computeFullSubgroups; - out_ext->synchronization2 = in_ext->synchronization2; - out_ext->textureCompressionASTC_HDR = in_ext->textureCompressionASTC_HDR; - out_ext->shaderZeroInitializeWorkgroupMemory = in_ext->shaderZeroInitializeWorkgroupMemory; - out_ext->dynamicRendering = in_ext->dynamicRendering; - out_ext->shaderIntegerDotProduct = in_ext->shaderIntegerDotProduct; - out_ext->maintenance4 = in_ext->maintenance4; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD: - { - VkPhysicalDeviceCoherentMemoryFeaturesAMD32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD); - const VkPhysicalDeviceCoherentMemoryFeaturesAMD *in_ext = (const VkPhysicalDeviceCoherentMemoryFeaturesAMD *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD; - out_ext->deviceCoherentMemory = in_ext->deviceCoherentMemory; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT: - { - VkPhysicalDeviceCustomBorderColorFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT); - const VkPhysicalDeviceCustomBorderColorFeaturesEXT *in_ext = (const VkPhysicalDeviceCustomBorderColorFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT; - out_ext->customBorderColors = in_ext->customBorderColors; - out_ext->customBorderColorWithoutFormat = in_ext->customBorderColorWithoutFormat; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT: - { - VkPhysicalDeviceBorderColorSwizzleFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT); - const VkPhysicalDeviceBorderColorSwizzleFeaturesEXT *in_ext = (const VkPhysicalDeviceBorderColorSwizzleFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT; - out_ext->borderColorSwizzle = in_ext->borderColorSwizzle; - out_ext->borderColorSwizzleFromImage = in_ext->borderColorSwizzleFromImage; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT: - { - VkPhysicalDeviceExtendedDynamicStateFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT); - const VkPhysicalDeviceExtendedDynamicStateFeaturesEXT *in_ext = (const VkPhysicalDeviceExtendedDynamicStateFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; - out_ext->extendedDynamicState = in_ext->extendedDynamicState; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT: - { - VkPhysicalDeviceExtendedDynamicState2FeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT); - const VkPhysicalDeviceExtendedDynamicState2FeaturesEXT *in_ext = (const VkPhysicalDeviceExtendedDynamicState2FeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT; - out_ext->extendedDynamicState2 = in_ext->extendedDynamicState2; - out_ext->extendedDynamicState2LogicOp = in_ext->extendedDynamicState2LogicOp; - out_ext->extendedDynamicState2PatchControlPoints = in_ext->extendedDynamicState2PatchControlPoints; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT: - { - VkPhysicalDeviceExtendedDynamicState3FeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT); - const VkPhysicalDeviceExtendedDynamicState3FeaturesEXT *in_ext = (const VkPhysicalDeviceExtendedDynamicState3FeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT; - out_ext->extendedDynamicState3TessellationDomainOrigin = in_ext->extendedDynamicState3TessellationDomainOrigin; - out_ext->extendedDynamicState3DepthClampEnable = in_ext->extendedDynamicState3DepthClampEnable; - out_ext->extendedDynamicState3PolygonMode = in_ext->extendedDynamicState3PolygonMode; - out_ext->extendedDynamicState3RasterizationSamples = in_ext->extendedDynamicState3RasterizationSamples; - out_ext->extendedDynamicState3SampleMask = in_ext->extendedDynamicState3SampleMask; - out_ext->extendedDynamicState3AlphaToCoverageEnable = in_ext->extendedDynamicState3AlphaToCoverageEnable; - out_ext->extendedDynamicState3AlphaToOneEnable = in_ext->extendedDynamicState3AlphaToOneEnable; - out_ext->extendedDynamicState3LogicOpEnable = in_ext->extendedDynamicState3LogicOpEnable; - out_ext->extendedDynamicState3ColorBlendEnable = in_ext->extendedDynamicState3ColorBlendEnable; - out_ext->extendedDynamicState3ColorBlendEquation = in_ext->extendedDynamicState3ColorBlendEquation; - out_ext->extendedDynamicState3ColorWriteMask = in_ext->extendedDynamicState3ColorWriteMask; - out_ext->extendedDynamicState3RasterizationStream = in_ext->extendedDynamicState3RasterizationStream; - out_ext->extendedDynamicState3ConservativeRasterizationMode = in_ext->extendedDynamicState3ConservativeRasterizationMode; - out_ext->extendedDynamicState3ExtraPrimitiveOverestimationSize = in_ext->extendedDynamicState3ExtraPrimitiveOverestimationSize; - out_ext->extendedDynamicState3DepthClipEnable = in_ext->extendedDynamicState3DepthClipEnable; - out_ext->extendedDynamicState3SampleLocationsEnable = in_ext->extendedDynamicState3SampleLocationsEnable; - out_ext->extendedDynamicState3ColorBlendAdvanced = in_ext->extendedDynamicState3ColorBlendAdvanced; - out_ext->extendedDynamicState3ProvokingVertexMode = in_ext->extendedDynamicState3ProvokingVertexMode; - out_ext->extendedDynamicState3LineRasterizationMode = in_ext->extendedDynamicState3LineRasterizationMode; - out_ext->extendedDynamicState3LineStippleEnable = in_ext->extendedDynamicState3LineStippleEnable; - out_ext->extendedDynamicState3DepthClipNegativeOneToOne = in_ext->extendedDynamicState3DepthClipNegativeOneToOne; - out_ext->extendedDynamicState3ViewportWScalingEnable = in_ext->extendedDynamicState3ViewportWScalingEnable; - out_ext->extendedDynamicState3ViewportSwizzle = in_ext->extendedDynamicState3ViewportSwizzle; - out_ext->extendedDynamicState3CoverageToColorEnable = in_ext->extendedDynamicState3CoverageToColorEnable; - out_ext->extendedDynamicState3CoverageToColorLocation = in_ext->extendedDynamicState3CoverageToColorLocation; - out_ext->extendedDynamicState3CoverageModulationMode = in_ext->extendedDynamicState3CoverageModulationMode; - out_ext->extendedDynamicState3CoverageModulationTableEnable = in_ext->extendedDynamicState3CoverageModulationTableEnable; - out_ext->extendedDynamicState3CoverageModulationTable = in_ext->extendedDynamicState3CoverageModulationTable; - out_ext->extendedDynamicState3CoverageReductionMode = in_ext->extendedDynamicState3CoverageReductionMode; - out_ext->extendedDynamicState3RepresentativeFragmentTestEnable = in_ext->extendedDynamicState3RepresentativeFragmentTestEnable; - out_ext->extendedDynamicState3ShadingRateImageEnable = in_ext->extendedDynamicState3ShadingRateImageEnable; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV: - { - VkPhysicalDeviceDiagnosticsConfigFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV); - const VkPhysicalDeviceDiagnosticsConfigFeaturesNV *in_ext = (const VkPhysicalDeviceDiagnosticsConfigFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV; - out_ext->diagnosticsConfig = in_ext->diagnosticsConfig; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES: - { - VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES); - const VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures *in_ext = (const VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES; - out_ext->shaderZeroInitializeWorkgroupMemory = in_ext->shaderZeroInitializeWorkgroupMemory; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR: - { - VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR); - const VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR *in_ext = (const VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR; - out_ext->shaderSubgroupUniformControlFlow = in_ext->shaderSubgroupUniformControlFlow; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT: - { - VkPhysicalDeviceRobustness2FeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT); - const VkPhysicalDeviceRobustness2FeaturesEXT *in_ext = (const VkPhysicalDeviceRobustness2FeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT; - out_ext->robustBufferAccess2 = in_ext->robustBufferAccess2; - out_ext->robustImageAccess2 = in_ext->robustImageAccess2; - out_ext->nullDescriptor = in_ext->nullDescriptor; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES: - { - VkPhysicalDeviceImageRobustnessFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES); - const VkPhysicalDeviceImageRobustnessFeatures *in_ext = (const VkPhysicalDeviceImageRobustnessFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES; - out_ext->robustImageAccess = in_ext->robustImageAccess; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR: - { - VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR); - const VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR *in_ext = (const VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR; - out_ext->workgroupMemoryExplicitLayout = in_ext->workgroupMemoryExplicitLayout; - out_ext->workgroupMemoryExplicitLayoutScalarBlockLayout = in_ext->workgroupMemoryExplicitLayoutScalarBlockLayout; - out_ext->workgroupMemoryExplicitLayout8BitAccess = in_ext->workgroupMemoryExplicitLayout8BitAccess; - out_ext->workgroupMemoryExplicitLayout16BitAccess = in_ext->workgroupMemoryExplicitLayout16BitAccess; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT: - { - VkPhysicalDevice4444FormatsFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT); - const VkPhysicalDevice4444FormatsFeaturesEXT *in_ext = (const VkPhysicalDevice4444FormatsFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT; - out_ext->formatA4R4G4B4 = in_ext->formatA4R4G4B4; - out_ext->formatA4B4G4R4 = in_ext->formatA4B4G4R4; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI: - { - VkPhysicalDeviceSubpassShadingFeaturesHUAWEI32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI); - const VkPhysicalDeviceSubpassShadingFeaturesHUAWEI *in_ext = (const VkPhysicalDeviceSubpassShadingFeaturesHUAWEI *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI; - out_ext->subpassShading = in_ext->subpassShading; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT: - { - VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT); - const VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT *in_ext = (const VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT; - out_ext->shaderImageInt64Atomics = in_ext->shaderImageInt64Atomics; - out_ext->sparseImageInt64Atomics = in_ext->sparseImageInt64Atomics; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR: - { - VkPhysicalDeviceFragmentShadingRateFeaturesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR); - const VkPhysicalDeviceFragmentShadingRateFeaturesKHR *in_ext = (const VkPhysicalDeviceFragmentShadingRateFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; - out_ext->pipelineFragmentShadingRate = in_ext->pipelineFragmentShadingRate; - out_ext->primitiveFragmentShadingRate = in_ext->primitiveFragmentShadingRate; - out_ext->attachmentFragmentShadingRate = in_ext->attachmentFragmentShadingRate; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES: - { - VkPhysicalDeviceShaderTerminateInvocationFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES); - const VkPhysicalDeviceShaderTerminateInvocationFeatures *in_ext = (const VkPhysicalDeviceShaderTerminateInvocationFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES; - out_ext->shaderTerminateInvocation = in_ext->shaderTerminateInvocation; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV: - { - VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV); - const VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV *in_ext = (const VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV; - out_ext->fragmentShadingRateEnums = in_ext->fragmentShadingRateEnums; - out_ext->supersampleFragmentShadingRates = in_ext->supersampleFragmentShadingRates; - out_ext->noInvocationFragmentShadingRates = in_ext->noInvocationFragmentShadingRates; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT: - { - VkPhysicalDeviceImage2DViewOf3DFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT); - const VkPhysicalDeviceImage2DViewOf3DFeaturesEXT *in_ext = (const VkPhysicalDeviceImage2DViewOf3DFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT; - out_ext->image2DViewOf3D = in_ext->image2DViewOf3D; - out_ext->sampler2DViewOf3D = in_ext->sampler2DViewOf3D; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT: - { - VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT); - const VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *in_ext = (const VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT; - out_ext->mutableDescriptorType = in_ext->mutableDescriptorType; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT: - { - VkPhysicalDeviceDepthClipControlFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT); - const VkPhysicalDeviceDepthClipControlFeaturesEXT *in_ext = (const VkPhysicalDeviceDepthClipControlFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT; - out_ext->depthClipControl = in_ext->depthClipControl; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT: - { - VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT); - const VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT *in_ext = (const VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT; - out_ext->vertexInputDynamicState = in_ext->vertexInputDynamicState; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: - { - VkPhysicalDeviceColorWriteEnableFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT); - const VkPhysicalDeviceColorWriteEnableFeaturesEXT *in_ext = (const VkPhysicalDeviceColorWriteEnableFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT; - out_ext->colorWriteEnable = in_ext->colorWriteEnable; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES: - { - VkPhysicalDeviceSynchronization2Features32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES); - const VkPhysicalDeviceSynchronization2Features *in_ext = (const VkPhysicalDeviceSynchronization2Features *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES; - out_ext->synchronization2 = in_ext->synchronization2; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT: - { - VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT); - const VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *in_ext = (const VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT; - out_ext->primitivesGeneratedQuery = in_ext->primitivesGeneratedQuery; - out_ext->primitivesGeneratedQueryWithRasterizerDiscard = in_ext->primitivesGeneratedQueryWithRasterizerDiscard; - out_ext->primitivesGeneratedQueryWithNonZeroStreams = in_ext->primitivesGeneratedQueryWithNonZeroStreams; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT: - { - VkPhysicalDeviceLegacyDitheringFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT); - const VkPhysicalDeviceLegacyDitheringFeaturesEXT *in_ext = (const VkPhysicalDeviceLegacyDitheringFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT; - out_ext->legacyDithering = in_ext->legacyDithering; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT: - { - VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT); - const VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT *in_ext = (const VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT; - out_ext->multisampledRenderToSingleSampled = in_ext->multisampledRenderToSingleSampled; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT: - { - VkPhysicalDevicePipelineProtectedAccessFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT); - const VkPhysicalDevicePipelineProtectedAccessFeaturesEXT *in_ext = (const VkPhysicalDevicePipelineProtectedAccessFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT; - out_ext->pipelineProtectedAccess = in_ext->pipelineProtectedAccess; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV: - { - VkPhysicalDeviceInheritedViewportScissorFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV); - const VkPhysicalDeviceInheritedViewportScissorFeaturesNV *in_ext = (const VkPhysicalDeviceInheritedViewportScissorFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV; - out_ext->inheritedViewportScissor2D = in_ext->inheritedViewportScissor2D; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT: - { - VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT); - const VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT *in_ext = (const VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT; - out_ext->ycbcr2plane444Formats = in_ext->ycbcr2plane444Formats; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT: - { - VkPhysicalDeviceProvokingVertexFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT); - const VkPhysicalDeviceProvokingVertexFeaturesEXT *in_ext = (const VkPhysicalDeviceProvokingVertexFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT; - out_ext->provokingVertexLast = in_ext->provokingVertexLast; - out_ext->transformFeedbackPreservesProvokingVertex = in_ext->transformFeedbackPreservesProvokingVertex; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT: - { - VkPhysicalDeviceDescriptorBufferFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT); - const VkPhysicalDeviceDescriptorBufferFeaturesEXT *in_ext = (const VkPhysicalDeviceDescriptorBufferFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT; - out_ext->descriptorBuffer = in_ext->descriptorBuffer; - out_ext->descriptorBufferCaptureReplay = in_ext->descriptorBufferCaptureReplay; - out_ext->descriptorBufferImageLayoutIgnored = in_ext->descriptorBufferImageLayoutIgnored; - out_ext->descriptorBufferPushDescriptors = in_ext->descriptorBufferPushDescriptors; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES: - { - VkPhysicalDeviceShaderIntegerDotProductFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES); - const VkPhysicalDeviceShaderIntegerDotProductFeatures *in_ext = (const VkPhysicalDeviceShaderIntegerDotProductFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES; - out_ext->shaderIntegerDotProduct = in_ext->shaderIntegerDotProduct; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR: - { - VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR); - const VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR *in_ext = (const VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR; - out_ext->fragmentShaderBarycentric = in_ext->fragmentShaderBarycentric; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV: - { - VkPhysicalDeviceRayTracingMotionBlurFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV); - const VkPhysicalDeviceRayTracingMotionBlurFeaturesNV *in_ext = (const VkPhysicalDeviceRayTracingMotionBlurFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV; - out_ext->rayTracingMotionBlur = in_ext->rayTracingMotionBlur; - out_ext->rayTracingMotionBlurPipelineTraceRaysIndirect = in_ext->rayTracingMotionBlurPipelineTraceRaysIndirect; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT: - { - VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT); - const VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT *in_ext = (const VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT; - out_ext->formatRgba10x6WithoutYCbCrSampler = in_ext->formatRgba10x6WithoutYCbCrSampler; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES: - { - VkPhysicalDeviceDynamicRenderingFeatures32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES); - const VkPhysicalDeviceDynamicRenderingFeatures *in_ext = (const VkPhysicalDeviceDynamicRenderingFeatures *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES; - out_ext->dynamicRendering = in_ext->dynamicRendering; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT: - { - VkPhysicalDeviceImageViewMinLodFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT); - const VkPhysicalDeviceImageViewMinLodFeaturesEXT *in_ext = (const VkPhysicalDeviceImageViewMinLodFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT; - out_ext->minLod = in_ext->minLod; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT: - { - VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT); - const VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT *in_ext = (const VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT; - out_ext->rasterizationOrderColorAttachmentAccess = in_ext->rasterizationOrderColorAttachmentAccess; - out_ext->rasterizationOrderDepthAttachmentAccess = in_ext->rasterizationOrderDepthAttachmentAccess; - out_ext->rasterizationOrderStencilAttachmentAccess = in_ext->rasterizationOrderStencilAttachmentAccess; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV: - { - VkPhysicalDeviceLinearColorAttachmentFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV); - const VkPhysicalDeviceLinearColorAttachmentFeaturesNV *in_ext = (const VkPhysicalDeviceLinearColorAttachmentFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV; - out_ext->linearColorAttachment = in_ext->linearColorAttachment; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT: - { - VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT); - const VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT *in_ext = (const VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT; - out_ext->graphicsPipelineLibrary = in_ext->graphicsPipelineLibrary; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE: - { - VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE); - const VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE *in_ext = (const VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE; - out_ext->descriptorSetHostMapping = in_ext->descriptorSetHostMapping; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT: - { - VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT); - const VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT *in_ext = (const VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT; - out_ext->shaderModuleIdentifier = in_ext->shaderModuleIdentifier; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT: - { - VkPhysicalDeviceImageCompressionControlFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT); - const VkPhysicalDeviceImageCompressionControlFeaturesEXT *in_ext = (const VkPhysicalDeviceImageCompressionControlFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT; - out_ext->imageCompressionControl = in_ext->imageCompressionControl; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT: - { - VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT); - const VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT *in_ext = (const VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT; - out_ext->imageCompressionControlSwapchain = in_ext->imageCompressionControlSwapchain; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT: - { - VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT); - const VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT *in_ext = (const VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT; - out_ext->subpassMergeFeedback = in_ext->subpassMergeFeedback; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_EXT: - { - VkPhysicalDeviceOpacityMicromapFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_EXT); - const VkPhysicalDeviceOpacityMicromapFeaturesEXT *in_ext = (const VkPhysicalDeviceOpacityMicromapFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_EXT; - out_ext->micromap = in_ext->micromap; - out_ext->micromapCaptureReplay = in_ext->micromapCaptureReplay; - out_ext->micromapHostCommands = in_ext->micromapHostCommands; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT: - { - VkPhysicalDevicePipelinePropertiesFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT); - const VkPhysicalDevicePipelinePropertiesFeaturesEXT *in_ext = (const VkPhysicalDevicePipelinePropertiesFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT; - out_ext->pipelinePropertiesIdentifier = in_ext->pipelinePropertiesIdentifier; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD: - { - VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD); - const VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD *in_ext = (const VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD; - out_ext->shaderEarlyAndLateFragmentTests = in_ext->shaderEarlyAndLateFragmentTests; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT: - { - VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT); - const VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT *in_ext = (const VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT; - out_ext->nonSeamlessCubeMap = in_ext->nonSeamlessCubeMap; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT: - { - VkPhysicalDevicePipelineRobustnessFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT); - const VkPhysicalDevicePipelineRobustnessFeaturesEXT *in_ext = (const VkPhysicalDevicePipelineRobustnessFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT; - out_ext->pipelineRobustness = in_ext->pipelineRobustness; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM: - { - VkPhysicalDeviceImageProcessingFeaturesQCOM32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM); - const VkPhysicalDeviceImageProcessingFeaturesQCOM *in_ext = (const VkPhysicalDeviceImageProcessingFeaturesQCOM *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM; - out_ext->textureSampleWeighted = in_ext->textureSampleWeighted; - out_ext->textureBoxFilter = in_ext->textureBoxFilter; - out_ext->textureBlockMatch = in_ext->textureBlockMatch; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM: - { - VkPhysicalDeviceTilePropertiesFeaturesQCOM32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM); - const VkPhysicalDeviceTilePropertiesFeaturesQCOM *in_ext = (const VkPhysicalDeviceTilePropertiesFeaturesQCOM *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM; - out_ext->tileProperties = in_ext->tileProperties; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT: - { - VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT); - const VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT *in_ext = (const VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT; - out_ext->attachmentFeedbackLoopLayout = in_ext->attachmentFeedbackLoopLayout; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT: - { - VkPhysicalDeviceDepthClampZeroOneFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT); - const VkPhysicalDeviceDepthClampZeroOneFeaturesEXT *in_ext = (const VkPhysicalDeviceDepthClampZeroOneFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT; - out_ext->depthClampZeroOne = in_ext->depthClampZeroOne; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ADDRESS_BINDING_REPORT_FEATURES_EXT: - { - VkPhysicalDeviceAddressBindingReportFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ADDRESS_BINDING_REPORT_FEATURES_EXT); - const VkPhysicalDeviceAddressBindingReportFeaturesEXT *in_ext = (const VkPhysicalDeviceAddressBindingReportFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ADDRESS_BINDING_REPORT_FEATURES_EXT; - out_ext->reportAddressBinding = in_ext->reportAddressBinding; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV: - { - VkPhysicalDeviceOpticalFlowFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV); - const VkPhysicalDeviceOpticalFlowFeaturesNV *in_ext = (const VkPhysicalDeviceOpticalFlowFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV; - out_ext->opticalFlow = in_ext->opticalFlow; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT: - { - VkPhysicalDeviceFaultFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT); - const VkPhysicalDeviceFaultFeaturesEXT *in_ext = (const VkPhysicalDeviceFaultFeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT; - out_ext->deviceFault = in_ext->deviceFault; - out_ext->deviceFaultVendorBinary = in_ext->deviceFaultVendorBinary; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM: - { - VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM); - const VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM *in_ext = (const VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM; - out_ext->shaderCoreBuiltins = in_ext->shaderCoreBuiltins; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT: - { - VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT); - const VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT *in_ext = (const VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT; - out_ext->swapchainMaintenance1 = in_ext->swapchainMaintenance1; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV: - { - VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV); - const VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV *in_ext = (const VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV; - out_ext->rayTracingInvocationReorder = in_ext->rayTracingInvocationReorder; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM: - { - VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM); - const VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM *in_ext = (const VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM; - out_ext->multiviewPerViewViewports = in_ext->multiviewPerViewViewports; - out_header = (void *)out_ext; - break; - } - default: - break; - } - } -} - -static inline void convert_VkFormatProperties2_win32_to_host(struct conversion_context *ctx, const VkFormatProperties232 *in, VkFormatProperties2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_SUBPASS_RESOLVE_PERFORMANCE_QUERY_EXT: - { - VkSubpassResolvePerformanceQueryEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_SUBPASS_RESOLVE_PERFORMANCE_QUERY_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3: - { - VkFormatProperties3 *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkFormatProperties2_host_to_win32(const VkFormatProperties2 *in, VkFormatProperties232 *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure32 *out_header = (void *)out; - - if (!in) return; - - out->formatProperties = in->formatProperties; - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_SUBPASS_RESOLVE_PERFORMANCE_QUERY_EXT: - { - VkSubpassResolvePerformanceQueryEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_SUBPASS_RESOLVE_PERFORMANCE_QUERY_EXT); - const VkSubpassResolvePerformanceQueryEXT *in_ext = (const VkSubpassResolvePerformanceQueryEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SUBPASS_RESOLVE_PERFORMANCE_QUERY_EXT; - out_ext->optimal = in_ext->optimal; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3: - { - VkFormatProperties332 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3); - const VkFormatProperties3 *in_ext = (const VkFormatProperties3 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3; - out_ext->linearTilingFeatures = in_ext->linearTilingFeatures; - out_ext->optimalTilingFeatures = in_ext->optimalTilingFeatures; - out_ext->bufferFeatures = in_ext->bufferFeatures; - out_header = (void *)out_ext; - break; - } - default: - break; - } - } -} - -static inline void convert_VkPhysicalDeviceFragmentShadingRateKHR_win32_to_host(const VkPhysicalDeviceFragmentShadingRateKHR32 *in, VkPhysicalDeviceFragmentShadingRateKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkPhysicalDeviceFragmentShadingRateKHR_host_to_win32(const VkPhysicalDeviceFragmentShadingRateKHR *in, VkPhysicalDeviceFragmentShadingRateKHR32 *out) -{ - if (!in) return; - - out->sampleCounts = in->sampleCounts; - out->fragmentSize = in->fragmentSize; -} - -static inline VkPhysicalDeviceFragmentShadingRateKHR *convert_VkPhysicalDeviceFragmentShadingRateKHR_array_win32_to_host(struct conversion_context *ctx, const VkPhysicalDeviceFragmentShadingRateKHR32 *in, uint32_t count) -{ - VkPhysicalDeviceFragmentShadingRateKHR *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPhysicalDeviceFragmentShadingRateKHR_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPhysicalDeviceFragmentShadingRateKHR_array_host_to_win32(const VkPhysicalDeviceFragmentShadingRateKHR *in, VkPhysicalDeviceFragmentShadingRateKHR32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkPhysicalDeviceFragmentShadingRateKHR_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkImageFormatProperties_host_to_win32(const VkImageFormatProperties *in, VkImageFormatProperties32 *out) -{ - if (!in) return; - - out->maxExtent = in->maxExtent; - out->maxMipLevels = in->maxMipLevels; - out->maxArrayLayers = in->maxArrayLayers; - out->sampleCounts = in->sampleCounts; - out->maxResourceSize = in->maxResourceSize; -} - -static inline void convert_VkPhysicalDeviceImageFormatInfo2_win32_to_host(struct conversion_context *ctx, const VkPhysicalDeviceImageFormatInfo232 *in, VkPhysicalDeviceImageFormatInfo2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->format = in->format; - out->type = in->type; - out->tiling = in->tiling; - out->usage = in->usage; - out->flags = in->flags; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO: - { - VkPhysicalDeviceExternalImageFormatInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceExternalImageFormatInfo32 *in_ext = (const VkPhysicalDeviceExternalImageFormatInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO; - out_ext->pNext = NULL; - out_ext->handleType = in_ext->handleType; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO: - { - VkImageFormatListCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkImageFormatListCreateInfo32 *in_ext = (const VkImageFormatListCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->viewFormatCount = in_ext->viewFormatCount; - out_ext->pViewFormats = (const VkFormat *)UlongToPtr(in_ext->pViewFormats); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO: - { - VkImageStencilUsageCreateInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkImageStencilUsageCreateInfo32 *in_ext = (const VkImageStencilUsageCreateInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO; - out_ext->pNext = NULL; - out_ext->stencilUsage = in_ext->stencilUsage; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT: - { - VkPhysicalDeviceImageViewImageFormatInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceImageViewImageFormatInfoEXT32 *in_ext = (const VkPhysicalDeviceImageViewImageFormatInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT; - out_ext->pNext = NULL; - out_ext->imageViewType = in_ext->imageViewType; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: - { - VkImageCompressionControlEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkImageCompressionControlEXT32 *in_ext = (const VkImageCompressionControlEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->compressionControlPlaneCount = in_ext->compressionControlPlaneCount; - out_ext->pFixedRateFlags = (VkImageCompressionFixedRateFlagsEXT *)UlongToPtr(in_ext->pFixedRateFlags); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_INFO_NV: - { - VkOpticalFlowImageFormatInfoNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkOpticalFlowImageFormatInfoNV32 *in_ext = (const VkOpticalFlowImageFormatInfoNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_INFO_NV; - out_ext->pNext = NULL; - out_ext->usage = in_ext->usage; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkImageFormatProperties2_win32_to_host(struct conversion_context *ctx, const VkImageFormatProperties232 *in, VkImageFormatProperties2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES: - { - VkExternalImageFormatProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES: - { - VkSamplerYcbcrConversionImageFormatProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD: - { - VkTextureLODGatherFormatPropertiesAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT: - { - VkFilterCubicImageViewImageFormatPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT: - { - VkImageCompressionPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkImageFormatProperties2_host_to_win32(const VkImageFormatProperties2 *in, VkImageFormatProperties232 *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure32 *out_header = (void *)out; - - if (!in) return; - - convert_VkImageFormatProperties_host_to_win32(&in->imageFormatProperties, &out->imageFormatProperties); - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES: - { - VkExternalImageFormatProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES); - const VkExternalImageFormatProperties *in_ext = (const VkExternalImageFormatProperties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES; - out_ext->externalMemoryProperties = in_ext->externalMemoryProperties; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES: - { - VkSamplerYcbcrConversionImageFormatProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES); - const VkSamplerYcbcrConversionImageFormatProperties *in_ext = (const VkSamplerYcbcrConversionImageFormatProperties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES; - out_ext->combinedImageSamplerDescriptorCount = in_ext->combinedImageSamplerDescriptorCount; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD: - { - VkTextureLODGatherFormatPropertiesAMD32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD); - const VkTextureLODGatherFormatPropertiesAMD *in_ext = (const VkTextureLODGatherFormatPropertiesAMD *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD; - out_ext->supportsTextureGatherLODBiasAMD = in_ext->supportsTextureGatherLODBiasAMD; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT: - { - VkFilterCubicImageViewImageFormatPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT); - const VkFilterCubicImageViewImageFormatPropertiesEXT *in_ext = (const VkFilterCubicImageViewImageFormatPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT; - out_ext->filterCubic = in_ext->filterCubic; - out_ext->filterCubicMinmax = in_ext->filterCubicMinmax; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT: - { - VkImageCompressionPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT); - const VkImageCompressionPropertiesEXT *in_ext = (const VkImageCompressionPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT; - out_ext->imageCompressionFlags = in_ext->imageCompressionFlags; - out_ext->imageCompressionFixedRateFlags = in_ext->imageCompressionFixedRateFlags; - out_header = (void *)out_ext; - break; - } - default: - break; - } - } -} - -static inline void convert_VkMemoryHeap_host_to_win32(const VkMemoryHeap *in, VkMemoryHeap32 *out) -{ - if (!in) return; - - out->size = in->size; - out->flags = in->flags; -} - -static inline void convert_VkMemoryHeap_array_host_to_win32(const VkMemoryHeap *in, VkMemoryHeap32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkMemoryHeap_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkPhysicalDeviceMemoryProperties_host_to_win32(const VkPhysicalDeviceMemoryProperties *in, VkPhysicalDeviceMemoryProperties32 *out) -{ - if (!in) return; - - out->memoryTypeCount = in->memoryTypeCount; - memcpy(out->memoryTypes, in->memoryTypes, VK_MAX_MEMORY_TYPES * sizeof(VkMemoryType)); - out->memoryHeapCount = in->memoryHeapCount; - convert_VkMemoryHeap_array_host_to_win32(in->memoryHeaps, out->memoryHeaps, VK_MAX_MEMORY_HEAPS); -} - -static inline void convert_VkPhysicalDeviceMemoryProperties2_win32_to_host(struct conversion_context *ctx, const VkPhysicalDeviceMemoryProperties232 *in, VkPhysicalDeviceMemoryProperties2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT: - { - VkPhysicalDeviceMemoryBudgetPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkPhysicalDeviceMemoryProperties2_host_to_win32(const VkPhysicalDeviceMemoryProperties2 *in, VkPhysicalDeviceMemoryProperties232 *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure32 *out_header = (void *)out; - - if (!in) return; - - convert_VkPhysicalDeviceMemoryProperties_host_to_win32(&in->memoryProperties, &out->memoryProperties); - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT: - { - VkPhysicalDeviceMemoryBudgetPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT); - const VkPhysicalDeviceMemoryBudgetPropertiesEXT *in_ext = (const VkPhysicalDeviceMemoryBudgetPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; - memcpy(out_ext->heapBudget, in_ext->heapBudget, VK_MAX_MEMORY_HEAPS * sizeof(VkDeviceSize)); - memcpy(out_ext->heapUsage, in_ext->heapUsage, VK_MAX_MEMORY_HEAPS * sizeof(VkDeviceSize)); - out_header = (void *)out_ext; - break; - } - default: - break; - } - } -} - -static inline void convert_VkMultisamplePropertiesEXT_win32_to_host(const VkMultisamplePropertiesEXT32 *in, VkMultisamplePropertiesEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkMultisamplePropertiesEXT_host_to_win32(const VkMultisamplePropertiesEXT *in, VkMultisamplePropertiesEXT32 *out) -{ - if (!in) return; - - out->maxSampleLocationGridSize = in->maxSampleLocationGridSize; -} - -static inline void convert_VkOpticalFlowImageFormatInfoNV_win32_to_host(const VkOpticalFlowImageFormatInfoNV32 *in, VkOpticalFlowImageFormatInfoNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->usage = in->usage; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkOpticalFlowImageFormatPropertiesNV_win32_to_host(const VkOpticalFlowImageFormatPropertiesNV32 *in, VkOpticalFlowImageFormatPropertiesNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkOpticalFlowImageFormatPropertiesNV_host_to_win32(const VkOpticalFlowImageFormatPropertiesNV *in, VkOpticalFlowImageFormatPropertiesNV32 *out) -{ - if (!in) return; - - out->format = in->format; -} - -static inline VkOpticalFlowImageFormatPropertiesNV *convert_VkOpticalFlowImageFormatPropertiesNV_array_win32_to_host(struct conversion_context *ctx, const VkOpticalFlowImageFormatPropertiesNV32 *in, uint32_t count) -{ - VkOpticalFlowImageFormatPropertiesNV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkOpticalFlowImageFormatPropertiesNV_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkOpticalFlowImageFormatPropertiesNV_array_host_to_win32(const VkOpticalFlowImageFormatPropertiesNV *in, VkOpticalFlowImageFormatPropertiesNV32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkOpticalFlowImageFormatPropertiesNV_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkPhysicalDeviceLimits_host_to_win32(const VkPhysicalDeviceLimits *in, VkPhysicalDeviceLimits32 *out) -{ - if (!in) return; - - out->maxImageDimension1D = in->maxImageDimension1D; - out->maxImageDimension2D = in->maxImageDimension2D; - out->maxImageDimension3D = in->maxImageDimension3D; - out->maxImageDimensionCube = in->maxImageDimensionCube; - out->maxImageArrayLayers = in->maxImageArrayLayers; - out->maxTexelBufferElements = in->maxTexelBufferElements; - out->maxUniformBufferRange = in->maxUniformBufferRange; - out->maxStorageBufferRange = in->maxStorageBufferRange; - out->maxPushConstantsSize = in->maxPushConstantsSize; - out->maxMemoryAllocationCount = in->maxMemoryAllocationCount; - out->maxSamplerAllocationCount = in->maxSamplerAllocationCount; - out->bufferImageGranularity = in->bufferImageGranularity; - out->sparseAddressSpaceSize = in->sparseAddressSpaceSize; - out->maxBoundDescriptorSets = in->maxBoundDescriptorSets; - out->maxPerStageDescriptorSamplers = in->maxPerStageDescriptorSamplers; - out->maxPerStageDescriptorUniformBuffers = in->maxPerStageDescriptorUniformBuffers; - out->maxPerStageDescriptorStorageBuffers = in->maxPerStageDescriptorStorageBuffers; - out->maxPerStageDescriptorSampledImages = in->maxPerStageDescriptorSampledImages; - out->maxPerStageDescriptorStorageImages = in->maxPerStageDescriptorStorageImages; - out->maxPerStageDescriptorInputAttachments = in->maxPerStageDescriptorInputAttachments; - out->maxPerStageResources = in->maxPerStageResources; - out->maxDescriptorSetSamplers = in->maxDescriptorSetSamplers; - out->maxDescriptorSetUniformBuffers = in->maxDescriptorSetUniformBuffers; - out->maxDescriptorSetUniformBuffersDynamic = in->maxDescriptorSetUniformBuffersDynamic; - out->maxDescriptorSetStorageBuffers = in->maxDescriptorSetStorageBuffers; - out->maxDescriptorSetStorageBuffersDynamic = in->maxDescriptorSetStorageBuffersDynamic; - out->maxDescriptorSetSampledImages = in->maxDescriptorSetSampledImages; - out->maxDescriptorSetStorageImages = in->maxDescriptorSetStorageImages; - out->maxDescriptorSetInputAttachments = in->maxDescriptorSetInputAttachments; - out->maxVertexInputAttributes = in->maxVertexInputAttributes; - out->maxVertexInputBindings = in->maxVertexInputBindings; - out->maxVertexInputAttributeOffset = in->maxVertexInputAttributeOffset; - out->maxVertexInputBindingStride = in->maxVertexInputBindingStride; - out->maxVertexOutputComponents = in->maxVertexOutputComponents; - out->maxTessellationGenerationLevel = in->maxTessellationGenerationLevel; - out->maxTessellationPatchSize = in->maxTessellationPatchSize; - out->maxTessellationControlPerVertexInputComponents = in->maxTessellationControlPerVertexInputComponents; - out->maxTessellationControlPerVertexOutputComponents = in->maxTessellationControlPerVertexOutputComponents; - out->maxTessellationControlPerPatchOutputComponents = in->maxTessellationControlPerPatchOutputComponents; - out->maxTessellationControlTotalOutputComponents = in->maxTessellationControlTotalOutputComponents; - out->maxTessellationEvaluationInputComponents = in->maxTessellationEvaluationInputComponents; - out->maxTessellationEvaluationOutputComponents = in->maxTessellationEvaluationOutputComponents; - out->maxGeometryShaderInvocations = in->maxGeometryShaderInvocations; - out->maxGeometryInputComponents = in->maxGeometryInputComponents; - out->maxGeometryOutputComponents = in->maxGeometryOutputComponents; - out->maxGeometryOutputVertices = in->maxGeometryOutputVertices; - out->maxGeometryTotalOutputComponents = in->maxGeometryTotalOutputComponents; - out->maxFragmentInputComponents = in->maxFragmentInputComponents; - out->maxFragmentOutputAttachments = in->maxFragmentOutputAttachments; - out->maxFragmentDualSrcAttachments = in->maxFragmentDualSrcAttachments; - out->maxFragmentCombinedOutputResources = in->maxFragmentCombinedOutputResources; - out->maxComputeSharedMemorySize = in->maxComputeSharedMemorySize; - memcpy(out->maxComputeWorkGroupCount, in->maxComputeWorkGroupCount, 3 * sizeof(uint32_t)); - out->maxComputeWorkGroupInvocations = in->maxComputeWorkGroupInvocations; - memcpy(out->maxComputeWorkGroupSize, in->maxComputeWorkGroupSize, 3 * sizeof(uint32_t)); - out->subPixelPrecisionBits = in->subPixelPrecisionBits; - out->subTexelPrecisionBits = in->subTexelPrecisionBits; - out->mipmapPrecisionBits = in->mipmapPrecisionBits; - out->maxDrawIndexedIndexValue = in->maxDrawIndexedIndexValue; - out->maxDrawIndirectCount = in->maxDrawIndirectCount; - out->maxSamplerLodBias = in->maxSamplerLodBias; - out->maxSamplerAnisotropy = in->maxSamplerAnisotropy; - out->maxViewports = in->maxViewports; - memcpy(out->maxViewportDimensions, in->maxViewportDimensions, 2 * sizeof(uint32_t)); - memcpy(out->viewportBoundsRange, in->viewportBoundsRange, 2 * sizeof(float)); - out->viewportSubPixelBits = in->viewportSubPixelBits; - out->minMemoryMapAlignment = in->minMemoryMapAlignment; - out->minTexelBufferOffsetAlignment = in->minTexelBufferOffsetAlignment; - out->minUniformBufferOffsetAlignment = in->minUniformBufferOffsetAlignment; - out->minStorageBufferOffsetAlignment = in->minStorageBufferOffsetAlignment; - out->minTexelOffset = in->minTexelOffset; - out->maxTexelOffset = in->maxTexelOffset; - out->minTexelGatherOffset = in->minTexelGatherOffset; - out->maxTexelGatherOffset = in->maxTexelGatherOffset; - out->minInterpolationOffset = in->minInterpolationOffset; - out->maxInterpolationOffset = in->maxInterpolationOffset; - out->subPixelInterpolationOffsetBits = in->subPixelInterpolationOffsetBits; - out->maxFramebufferWidth = in->maxFramebufferWidth; - out->maxFramebufferHeight = in->maxFramebufferHeight; - out->maxFramebufferLayers = in->maxFramebufferLayers; - out->framebufferColorSampleCounts = in->framebufferColorSampleCounts; - out->framebufferDepthSampleCounts = in->framebufferDepthSampleCounts; - out->framebufferStencilSampleCounts = in->framebufferStencilSampleCounts; - out->framebufferNoAttachmentsSampleCounts = in->framebufferNoAttachmentsSampleCounts; - out->maxColorAttachments = in->maxColorAttachments; - out->sampledImageColorSampleCounts = in->sampledImageColorSampleCounts; - out->sampledImageIntegerSampleCounts = in->sampledImageIntegerSampleCounts; - out->sampledImageDepthSampleCounts = in->sampledImageDepthSampleCounts; - out->sampledImageStencilSampleCounts = in->sampledImageStencilSampleCounts; - out->storageImageSampleCounts = in->storageImageSampleCounts; - out->maxSampleMaskWords = in->maxSampleMaskWords; - out->timestampComputeAndGraphics = in->timestampComputeAndGraphics; - out->timestampPeriod = in->timestampPeriod; - out->maxClipDistances = in->maxClipDistances; - out->maxCullDistances = in->maxCullDistances; - out->maxCombinedClipAndCullDistances = in->maxCombinedClipAndCullDistances; - out->discreteQueuePriorities = in->discreteQueuePriorities; - memcpy(out->pointSizeRange, in->pointSizeRange, 2 * sizeof(float)); - memcpy(out->lineWidthRange, in->lineWidthRange, 2 * sizeof(float)); - out->pointSizeGranularity = in->pointSizeGranularity; - out->lineWidthGranularity = in->lineWidthGranularity; - out->strictLines = in->strictLines; - out->standardSampleLocations = in->standardSampleLocations; - out->optimalBufferCopyOffsetAlignment = in->optimalBufferCopyOffsetAlignment; - out->optimalBufferCopyRowPitchAlignment = in->optimalBufferCopyRowPitchAlignment; - out->nonCoherentAtomSize = in->nonCoherentAtomSize; -} - -static inline void convert_VkPhysicalDeviceProperties_host_to_win32(const VkPhysicalDeviceProperties *in, VkPhysicalDeviceProperties32 *out) -{ - if (!in) return; - - out->apiVersion = in->apiVersion; - out->driverVersion = in->driverVersion; - out->vendorID = in->vendorID; - out->deviceID = in->deviceID; - out->deviceType = in->deviceType; - memcpy(out->deviceName, in->deviceName, VK_MAX_PHYSICAL_DEVICE_NAME_SIZE * sizeof(char)); - memcpy(out->pipelineCacheUUID, in->pipelineCacheUUID, VK_UUID_SIZE * sizeof(uint8_t)); - convert_VkPhysicalDeviceLimits_host_to_win32(&in->limits, &out->limits); - out->sparseProperties = in->sparseProperties; -} - -static inline void convert_VkPhysicalDeviceProperties2_win32_to_host(struct conversion_context *ctx, const VkPhysicalDeviceProperties232 *in, VkPhysicalDeviceProperties2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV: - { - VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT: - { - VkPhysicalDeviceMultiDrawPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR: - { - VkPhysicalDevicePushDescriptorPropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES: - { - VkPhysicalDeviceDriverProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: - { - VkPhysicalDeviceIDProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES: - { - VkPhysicalDeviceMultiviewProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT: - { - VkPhysicalDeviceDiscardRectanglePropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES: - { - VkPhysicalDeviceSubgroupProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: - { - VkPhysicalDevicePointClippingProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES: - { - VkPhysicalDeviceProtectedMemoryProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES: - { - VkPhysicalDeviceSamplerFilterMinmaxProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT: - { - VkPhysicalDeviceSampleLocationsPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT: - { - VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES: - { - VkPhysicalDeviceInlineUniformBlockProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES: - { - VkPhysicalDeviceMaintenance3Properties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES: - { - VkPhysicalDeviceMaintenance4Properties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES: - { - VkPhysicalDeviceFloatControlsProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT: - { - VkPhysicalDeviceExternalMemoryHostPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT: - { - VkPhysicalDeviceConservativeRasterizationPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD: - { - VkPhysicalDeviceShaderCorePropertiesAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD: - { - VkPhysicalDeviceShaderCoreProperties2AMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES: - { - VkPhysicalDeviceDescriptorIndexingProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES: - { - VkPhysicalDeviceTimelineSemaphoreProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: - { - VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT: - { - VkPhysicalDevicePCIBusInfoPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES: - { - VkPhysicalDeviceDepthStencilResolveProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT: - { - VkPhysicalDeviceTransformFeedbackPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_NV: - { - VkPhysicalDeviceCopyMemoryIndirectPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_NV; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_NV: - { - VkPhysicalDeviceMemoryDecompressionPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_NV; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV: - { - VkPhysicalDeviceShadingRateImagePropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV: - { - VkPhysicalDeviceMeshShaderPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT: - { - VkPhysicalDeviceMeshShaderPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR: - { - VkPhysicalDeviceAccelerationStructurePropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR: - { - VkPhysicalDeviceRayTracingPipelinePropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV: - { - VkPhysicalDeviceRayTracingPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT: - { - VkPhysicalDeviceFragmentDensityMapPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT: - { - VkPhysicalDeviceFragmentDensityMap2PropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_QCOM: - { - VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_QCOM; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV: - { - VkPhysicalDeviceCooperativeMatrixPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR: - { - VkPhysicalDevicePerformanceQueryPropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV: - { - VkPhysicalDeviceShaderSMBuiltinsPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES: - { - VkPhysicalDeviceTexelBufferAlignmentProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES: - { - VkPhysicalDeviceSubgroupSizeControlProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI: - { - VkPhysicalDeviceSubpassShadingPropertiesHUAWEI *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT: - { - VkPhysicalDeviceLineRasterizationPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES: - { - VkPhysicalDeviceVulkan11Properties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES: - { - VkPhysicalDeviceVulkan12Properties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES: - { - VkPhysicalDeviceVulkan13Properties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT: - { - VkPhysicalDeviceCustomBorderColorPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT: - { - VkPhysicalDeviceExtendedDynamicState3PropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceExtendedDynamicState3PropertiesEXT32 *in_ext = (const VkPhysicalDeviceExtendedDynamicState3PropertiesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_ext->dynamicPrimitiveTopologyUnrestricted = in_ext->dynamicPrimitiveTopologyUnrestricted; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT: - { - VkPhysicalDeviceRobustness2PropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR: - { - VkPhysicalDeviceFragmentShadingRatePropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV: - { - VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV32 *in_ext = (const VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV; - out_ext->pNext = NULL; - out_ext->maxFragmentShadingRateInvocationCount = in_ext->maxFragmentShadingRateInvocationCount; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT: - { - VkPhysicalDeviceProvokingVertexPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT: - { - VkPhysicalDeviceDescriptorBufferPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT: - { - VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES: - { - VkPhysicalDeviceShaderIntegerDotProductProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR: - { - VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT: - { - VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT32 *in_ext = (const VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_ext->graphicsPipelineLibraryFastLinking = in_ext->graphicsPipelineLibraryFastLinking; - out_ext->graphicsPipelineLibraryIndependentInterpolationDecoration = in_ext->graphicsPipelineLibraryIndependentInterpolationDecoration; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT: - { - VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_EXT: - { - VkPhysicalDeviceOpacityMicromapPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES_EXT: - { - VkPhysicalDevicePipelineRobustnessPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM: - { - VkPhysicalDeviceImageProcessingPropertiesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV: - { - VkPhysicalDeviceOpticalFlowPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM: - { - VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV: - { - VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDeviceProperties2 *in, VkPhysicalDeviceProperties232 *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure32 *out_header = (void *)out; - - if (!in) return; - - convert_VkPhysicalDeviceProperties_host_to_win32(&in->properties, &out->properties); - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV: - { - VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV); - const VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV *in_ext = (const VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV; - out_ext->maxGraphicsShaderGroupCount = in_ext->maxGraphicsShaderGroupCount; - out_ext->maxIndirectSequenceCount = in_ext->maxIndirectSequenceCount; - out_ext->maxIndirectCommandsTokenCount = in_ext->maxIndirectCommandsTokenCount; - out_ext->maxIndirectCommandsStreamCount = in_ext->maxIndirectCommandsStreamCount; - out_ext->maxIndirectCommandsTokenOffset = in_ext->maxIndirectCommandsTokenOffset; - out_ext->maxIndirectCommandsStreamStride = in_ext->maxIndirectCommandsStreamStride; - out_ext->minSequencesCountBufferOffsetAlignment = in_ext->minSequencesCountBufferOffsetAlignment; - out_ext->minSequencesIndexBufferOffsetAlignment = in_ext->minSequencesIndexBufferOffsetAlignment; - out_ext->minIndirectCommandsBufferOffsetAlignment = in_ext->minIndirectCommandsBufferOffsetAlignment; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT: - { - VkPhysicalDeviceMultiDrawPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT); - const VkPhysicalDeviceMultiDrawPropertiesEXT *in_ext = (const VkPhysicalDeviceMultiDrawPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT; - out_ext->maxMultiDrawCount = in_ext->maxMultiDrawCount; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR: - { - VkPhysicalDevicePushDescriptorPropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR); - const VkPhysicalDevicePushDescriptorPropertiesKHR *in_ext = (const VkPhysicalDevicePushDescriptorPropertiesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR; - out_ext->maxPushDescriptors = in_ext->maxPushDescriptors; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES: - { - VkPhysicalDeviceDriverProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES); - const VkPhysicalDeviceDriverProperties *in_ext = (const VkPhysicalDeviceDriverProperties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; - out_ext->driverID = in_ext->driverID; - memcpy(out_ext->driverName, in_ext->driverName, VK_MAX_DRIVER_NAME_SIZE * sizeof(char)); - memcpy(out_ext->driverInfo, in_ext->driverInfo, VK_MAX_DRIVER_INFO_SIZE * sizeof(char)); - out_ext->conformanceVersion = in_ext->conformanceVersion; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: - { - VkPhysicalDeviceIDProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES); - const VkPhysicalDeviceIDProperties *in_ext = (const VkPhysicalDeviceIDProperties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES; - memcpy(out_ext->deviceUUID, in_ext->deviceUUID, VK_UUID_SIZE * sizeof(uint8_t)); - memcpy(out_ext->driverUUID, in_ext->driverUUID, VK_UUID_SIZE * sizeof(uint8_t)); - memcpy(out_ext->deviceLUID, in_ext->deviceLUID, VK_LUID_SIZE * sizeof(uint8_t)); - out_ext->deviceNodeMask = in_ext->deviceNodeMask; - out_ext->deviceLUIDValid = in_ext->deviceLUIDValid; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES: - { - VkPhysicalDeviceMultiviewProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES); - const VkPhysicalDeviceMultiviewProperties *in_ext = (const VkPhysicalDeviceMultiviewProperties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES; - out_ext->maxMultiviewViewCount = in_ext->maxMultiviewViewCount; - out_ext->maxMultiviewInstanceIndex = in_ext->maxMultiviewInstanceIndex; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT: - { - VkPhysicalDeviceDiscardRectanglePropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT); - const VkPhysicalDeviceDiscardRectanglePropertiesEXT *in_ext = (const VkPhysicalDeviceDiscardRectanglePropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT; - out_ext->maxDiscardRectangles = in_ext->maxDiscardRectangles; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES: - { - VkPhysicalDeviceSubgroupProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES); - const VkPhysicalDeviceSubgroupProperties *in_ext = (const VkPhysicalDeviceSubgroupProperties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES; - out_ext->subgroupSize = in_ext->subgroupSize; - out_ext->supportedStages = in_ext->supportedStages; - out_ext->supportedOperations = in_ext->supportedOperations; - out_ext->quadOperationsInAllStages = in_ext->quadOperationsInAllStages; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: - { - VkPhysicalDevicePointClippingProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES); - const VkPhysicalDevicePointClippingProperties *in_ext = (const VkPhysicalDevicePointClippingProperties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES; - out_ext->pointClippingBehavior = in_ext->pointClippingBehavior; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES: - { - VkPhysicalDeviceProtectedMemoryProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES); - const VkPhysicalDeviceProtectedMemoryProperties *in_ext = (const VkPhysicalDeviceProtectedMemoryProperties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES; - out_ext->protectedNoFault = in_ext->protectedNoFault; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES: - { - VkPhysicalDeviceSamplerFilterMinmaxProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES); - const VkPhysicalDeviceSamplerFilterMinmaxProperties *in_ext = (const VkPhysicalDeviceSamplerFilterMinmaxProperties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES; - out_ext->filterMinmaxSingleComponentFormats = in_ext->filterMinmaxSingleComponentFormats; - out_ext->filterMinmaxImageComponentMapping = in_ext->filterMinmaxImageComponentMapping; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT: - { - VkPhysicalDeviceSampleLocationsPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT); - const VkPhysicalDeviceSampleLocationsPropertiesEXT *in_ext = (const VkPhysicalDeviceSampleLocationsPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT; - out_ext->sampleLocationSampleCounts = in_ext->sampleLocationSampleCounts; - out_ext->maxSampleLocationGridSize = in_ext->maxSampleLocationGridSize; - memcpy(out_ext->sampleLocationCoordinateRange, in_ext->sampleLocationCoordinateRange, 2 * sizeof(float)); - out_ext->sampleLocationSubPixelBits = in_ext->sampleLocationSubPixelBits; - out_ext->variableSampleLocations = in_ext->variableSampleLocations; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT: - { - VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT); - const VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT *in_ext = (const VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT; - out_ext->advancedBlendMaxColorAttachments = in_ext->advancedBlendMaxColorAttachments; - out_ext->advancedBlendIndependentBlend = in_ext->advancedBlendIndependentBlend; - out_ext->advancedBlendNonPremultipliedSrcColor = in_ext->advancedBlendNonPremultipliedSrcColor; - out_ext->advancedBlendNonPremultipliedDstColor = in_ext->advancedBlendNonPremultipliedDstColor; - out_ext->advancedBlendCorrelatedOverlap = in_ext->advancedBlendCorrelatedOverlap; - out_ext->advancedBlendAllOperations = in_ext->advancedBlendAllOperations; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES: - { - VkPhysicalDeviceInlineUniformBlockProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES); - const VkPhysicalDeviceInlineUniformBlockProperties *in_ext = (const VkPhysicalDeviceInlineUniformBlockProperties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES; - out_ext->maxInlineUniformBlockSize = in_ext->maxInlineUniformBlockSize; - out_ext->maxPerStageDescriptorInlineUniformBlocks = in_ext->maxPerStageDescriptorInlineUniformBlocks; - out_ext->maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks = in_ext->maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; - out_ext->maxDescriptorSetInlineUniformBlocks = in_ext->maxDescriptorSetInlineUniformBlocks; - out_ext->maxDescriptorSetUpdateAfterBindInlineUniformBlocks = in_ext->maxDescriptorSetUpdateAfterBindInlineUniformBlocks; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES: - { - VkPhysicalDeviceMaintenance3Properties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES); - const VkPhysicalDeviceMaintenance3Properties *in_ext = (const VkPhysicalDeviceMaintenance3Properties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES; - out_ext->maxPerSetDescriptors = in_ext->maxPerSetDescriptors; - out_ext->maxMemoryAllocationSize = in_ext->maxMemoryAllocationSize; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES: - { - VkPhysicalDeviceMaintenance4Properties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES); - const VkPhysicalDeviceMaintenance4Properties *in_ext = (const VkPhysicalDeviceMaintenance4Properties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES; - out_ext->maxBufferSize = in_ext->maxBufferSize; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES: - { - VkPhysicalDeviceFloatControlsProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES); - const VkPhysicalDeviceFloatControlsProperties *in_ext = (const VkPhysicalDeviceFloatControlsProperties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES; - out_ext->denormBehaviorIndependence = in_ext->denormBehaviorIndependence; - out_ext->roundingModeIndependence = in_ext->roundingModeIndependence; - out_ext->shaderSignedZeroInfNanPreserveFloat16 = in_ext->shaderSignedZeroInfNanPreserveFloat16; - out_ext->shaderSignedZeroInfNanPreserveFloat32 = in_ext->shaderSignedZeroInfNanPreserveFloat32; - out_ext->shaderSignedZeroInfNanPreserveFloat64 = in_ext->shaderSignedZeroInfNanPreserveFloat64; - out_ext->shaderDenormPreserveFloat16 = in_ext->shaderDenormPreserveFloat16; - out_ext->shaderDenormPreserveFloat32 = in_ext->shaderDenormPreserveFloat32; - out_ext->shaderDenormPreserveFloat64 = in_ext->shaderDenormPreserveFloat64; - out_ext->shaderDenormFlushToZeroFloat16 = in_ext->shaderDenormFlushToZeroFloat16; - out_ext->shaderDenormFlushToZeroFloat32 = in_ext->shaderDenormFlushToZeroFloat32; - out_ext->shaderDenormFlushToZeroFloat64 = in_ext->shaderDenormFlushToZeroFloat64; - out_ext->shaderRoundingModeRTEFloat16 = in_ext->shaderRoundingModeRTEFloat16; - out_ext->shaderRoundingModeRTEFloat32 = in_ext->shaderRoundingModeRTEFloat32; - out_ext->shaderRoundingModeRTEFloat64 = in_ext->shaderRoundingModeRTEFloat64; - out_ext->shaderRoundingModeRTZFloat16 = in_ext->shaderRoundingModeRTZFloat16; - out_ext->shaderRoundingModeRTZFloat32 = in_ext->shaderRoundingModeRTZFloat32; - out_ext->shaderRoundingModeRTZFloat64 = in_ext->shaderRoundingModeRTZFloat64; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT: - { - VkPhysicalDeviceExternalMemoryHostPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT); - const VkPhysicalDeviceExternalMemoryHostPropertiesEXT *in_ext = (const VkPhysicalDeviceExternalMemoryHostPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT; - out_ext->minImportedHostPointerAlignment = in_ext->minImportedHostPointerAlignment; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT: - { - VkPhysicalDeviceConservativeRasterizationPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT); - const VkPhysicalDeviceConservativeRasterizationPropertiesEXT *in_ext = (const VkPhysicalDeviceConservativeRasterizationPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT; - out_ext->primitiveOverestimationSize = in_ext->primitiveOverestimationSize; - out_ext->maxExtraPrimitiveOverestimationSize = in_ext->maxExtraPrimitiveOverestimationSize; - out_ext->extraPrimitiveOverestimationSizeGranularity = in_ext->extraPrimitiveOverestimationSizeGranularity; - out_ext->primitiveUnderestimation = in_ext->primitiveUnderestimation; - out_ext->conservativePointAndLineRasterization = in_ext->conservativePointAndLineRasterization; - out_ext->degenerateTrianglesRasterized = in_ext->degenerateTrianglesRasterized; - out_ext->degenerateLinesRasterized = in_ext->degenerateLinesRasterized; - out_ext->fullyCoveredFragmentShaderInputVariable = in_ext->fullyCoveredFragmentShaderInputVariable; - out_ext->conservativeRasterizationPostDepthCoverage = in_ext->conservativeRasterizationPostDepthCoverage; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD: - { - VkPhysicalDeviceShaderCorePropertiesAMD32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD); - const VkPhysicalDeviceShaderCorePropertiesAMD *in_ext = (const VkPhysicalDeviceShaderCorePropertiesAMD *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD; - out_ext->shaderEngineCount = in_ext->shaderEngineCount; - out_ext->shaderArraysPerEngineCount = in_ext->shaderArraysPerEngineCount; - out_ext->computeUnitsPerShaderArray = in_ext->computeUnitsPerShaderArray; - out_ext->simdPerComputeUnit = in_ext->simdPerComputeUnit; - out_ext->wavefrontsPerSimd = in_ext->wavefrontsPerSimd; - out_ext->wavefrontSize = in_ext->wavefrontSize; - out_ext->sgprsPerSimd = in_ext->sgprsPerSimd; - out_ext->minSgprAllocation = in_ext->minSgprAllocation; - out_ext->maxSgprAllocation = in_ext->maxSgprAllocation; - out_ext->sgprAllocationGranularity = in_ext->sgprAllocationGranularity; - out_ext->vgprsPerSimd = in_ext->vgprsPerSimd; - out_ext->minVgprAllocation = in_ext->minVgprAllocation; - out_ext->maxVgprAllocation = in_ext->maxVgprAllocation; - out_ext->vgprAllocationGranularity = in_ext->vgprAllocationGranularity; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD: - { - VkPhysicalDeviceShaderCoreProperties2AMD32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD); - const VkPhysicalDeviceShaderCoreProperties2AMD *in_ext = (const VkPhysicalDeviceShaderCoreProperties2AMD *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD; - out_ext->shaderCoreFeatures = in_ext->shaderCoreFeatures; - out_ext->activeComputeUnitCount = in_ext->activeComputeUnitCount; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES: - { - VkPhysicalDeviceDescriptorIndexingProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES); - const VkPhysicalDeviceDescriptorIndexingProperties *in_ext = (const VkPhysicalDeviceDescriptorIndexingProperties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES; - out_ext->maxUpdateAfterBindDescriptorsInAllPools = in_ext->maxUpdateAfterBindDescriptorsInAllPools; - out_ext->shaderUniformBufferArrayNonUniformIndexingNative = in_ext->shaderUniformBufferArrayNonUniformIndexingNative; - out_ext->shaderSampledImageArrayNonUniformIndexingNative = in_ext->shaderSampledImageArrayNonUniformIndexingNative; - out_ext->shaderStorageBufferArrayNonUniformIndexingNative = in_ext->shaderStorageBufferArrayNonUniformIndexingNative; - out_ext->shaderStorageImageArrayNonUniformIndexingNative = in_ext->shaderStorageImageArrayNonUniformIndexingNative; - out_ext->shaderInputAttachmentArrayNonUniformIndexingNative = in_ext->shaderInputAttachmentArrayNonUniformIndexingNative; - out_ext->robustBufferAccessUpdateAfterBind = in_ext->robustBufferAccessUpdateAfterBind; - out_ext->quadDivergentImplicitLod = in_ext->quadDivergentImplicitLod; - out_ext->maxPerStageDescriptorUpdateAfterBindSamplers = in_ext->maxPerStageDescriptorUpdateAfterBindSamplers; - out_ext->maxPerStageDescriptorUpdateAfterBindUniformBuffers = in_ext->maxPerStageDescriptorUpdateAfterBindUniformBuffers; - out_ext->maxPerStageDescriptorUpdateAfterBindStorageBuffers = in_ext->maxPerStageDescriptorUpdateAfterBindStorageBuffers; - out_ext->maxPerStageDescriptorUpdateAfterBindSampledImages = in_ext->maxPerStageDescriptorUpdateAfterBindSampledImages; - out_ext->maxPerStageDescriptorUpdateAfterBindStorageImages = in_ext->maxPerStageDescriptorUpdateAfterBindStorageImages; - out_ext->maxPerStageDescriptorUpdateAfterBindInputAttachments = in_ext->maxPerStageDescriptorUpdateAfterBindInputAttachments; - out_ext->maxPerStageUpdateAfterBindResources = in_ext->maxPerStageUpdateAfterBindResources; - out_ext->maxDescriptorSetUpdateAfterBindSamplers = in_ext->maxDescriptorSetUpdateAfterBindSamplers; - out_ext->maxDescriptorSetUpdateAfterBindUniformBuffers = in_ext->maxDescriptorSetUpdateAfterBindUniformBuffers; - out_ext->maxDescriptorSetUpdateAfterBindUniformBuffersDynamic = in_ext->maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; - out_ext->maxDescriptorSetUpdateAfterBindStorageBuffers = in_ext->maxDescriptorSetUpdateAfterBindStorageBuffers; - out_ext->maxDescriptorSetUpdateAfterBindStorageBuffersDynamic = in_ext->maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; - out_ext->maxDescriptorSetUpdateAfterBindSampledImages = in_ext->maxDescriptorSetUpdateAfterBindSampledImages; - out_ext->maxDescriptorSetUpdateAfterBindStorageImages = in_ext->maxDescriptorSetUpdateAfterBindStorageImages; - out_ext->maxDescriptorSetUpdateAfterBindInputAttachments = in_ext->maxDescriptorSetUpdateAfterBindInputAttachments; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES: - { - VkPhysicalDeviceTimelineSemaphoreProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES); - const VkPhysicalDeviceTimelineSemaphoreProperties *in_ext = (const VkPhysicalDeviceTimelineSemaphoreProperties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES; - out_ext->maxTimelineSemaphoreValueDifference = in_ext->maxTimelineSemaphoreValueDifference; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: - { - VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT); - const VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *in_ext = (const VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT; - out_ext->maxVertexAttribDivisor = in_ext->maxVertexAttribDivisor; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT: - { - VkPhysicalDevicePCIBusInfoPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT); - const VkPhysicalDevicePCIBusInfoPropertiesEXT *in_ext = (const VkPhysicalDevicePCIBusInfoPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT; - out_ext->pciDomain = in_ext->pciDomain; - out_ext->pciBus = in_ext->pciBus; - out_ext->pciDevice = in_ext->pciDevice; - out_ext->pciFunction = in_ext->pciFunction; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES: - { - VkPhysicalDeviceDepthStencilResolveProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES); - const VkPhysicalDeviceDepthStencilResolveProperties *in_ext = (const VkPhysicalDeviceDepthStencilResolveProperties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES; - out_ext->supportedDepthResolveModes = in_ext->supportedDepthResolveModes; - out_ext->supportedStencilResolveModes = in_ext->supportedStencilResolveModes; - out_ext->independentResolveNone = in_ext->independentResolveNone; - out_ext->independentResolve = in_ext->independentResolve; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT: - { - VkPhysicalDeviceTransformFeedbackPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT); - const VkPhysicalDeviceTransformFeedbackPropertiesEXT *in_ext = (const VkPhysicalDeviceTransformFeedbackPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT; - out_ext->maxTransformFeedbackStreams = in_ext->maxTransformFeedbackStreams; - out_ext->maxTransformFeedbackBuffers = in_ext->maxTransformFeedbackBuffers; - out_ext->maxTransformFeedbackBufferSize = in_ext->maxTransformFeedbackBufferSize; - out_ext->maxTransformFeedbackStreamDataSize = in_ext->maxTransformFeedbackStreamDataSize; - out_ext->maxTransformFeedbackBufferDataSize = in_ext->maxTransformFeedbackBufferDataSize; - out_ext->maxTransformFeedbackBufferDataStride = in_ext->maxTransformFeedbackBufferDataStride; - out_ext->transformFeedbackQueries = in_ext->transformFeedbackQueries; - out_ext->transformFeedbackStreamsLinesTriangles = in_ext->transformFeedbackStreamsLinesTriangles; - out_ext->transformFeedbackRasterizationStreamSelect = in_ext->transformFeedbackRasterizationStreamSelect; - out_ext->transformFeedbackDraw = in_ext->transformFeedbackDraw; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_NV: - { - VkPhysicalDeviceCopyMemoryIndirectPropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_NV); - const VkPhysicalDeviceCopyMemoryIndirectPropertiesNV *in_ext = (const VkPhysicalDeviceCopyMemoryIndirectPropertiesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_NV; - out_ext->supportedQueues = in_ext->supportedQueues; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_NV: - { - VkPhysicalDeviceMemoryDecompressionPropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_NV); - const VkPhysicalDeviceMemoryDecompressionPropertiesNV *in_ext = (const VkPhysicalDeviceMemoryDecompressionPropertiesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_NV; - out_ext->decompressionMethods = in_ext->decompressionMethods; - out_ext->maxDecompressionIndirectCount = in_ext->maxDecompressionIndirectCount; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV: - { - VkPhysicalDeviceShadingRateImagePropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV); - const VkPhysicalDeviceShadingRateImagePropertiesNV *in_ext = (const VkPhysicalDeviceShadingRateImagePropertiesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV; - out_ext->shadingRateTexelSize = in_ext->shadingRateTexelSize; - out_ext->shadingRatePaletteSize = in_ext->shadingRatePaletteSize; - out_ext->shadingRateMaxCoarseSamples = in_ext->shadingRateMaxCoarseSamples; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV: - { - VkPhysicalDeviceMeshShaderPropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV); - const VkPhysicalDeviceMeshShaderPropertiesNV *in_ext = (const VkPhysicalDeviceMeshShaderPropertiesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV; - out_ext->maxDrawMeshTasksCount = in_ext->maxDrawMeshTasksCount; - out_ext->maxTaskWorkGroupInvocations = in_ext->maxTaskWorkGroupInvocations; - memcpy(out_ext->maxTaskWorkGroupSize, in_ext->maxTaskWorkGroupSize, 3 * sizeof(uint32_t)); - out_ext->maxTaskTotalMemorySize = in_ext->maxTaskTotalMemorySize; - out_ext->maxTaskOutputCount = in_ext->maxTaskOutputCount; - out_ext->maxMeshWorkGroupInvocations = in_ext->maxMeshWorkGroupInvocations; - memcpy(out_ext->maxMeshWorkGroupSize, in_ext->maxMeshWorkGroupSize, 3 * sizeof(uint32_t)); - out_ext->maxMeshTotalMemorySize = in_ext->maxMeshTotalMemorySize; - out_ext->maxMeshOutputVertices = in_ext->maxMeshOutputVertices; - out_ext->maxMeshOutputPrimitives = in_ext->maxMeshOutputPrimitives; - out_ext->maxMeshMultiviewViewCount = in_ext->maxMeshMultiviewViewCount; - out_ext->meshOutputPerVertexGranularity = in_ext->meshOutputPerVertexGranularity; - out_ext->meshOutputPerPrimitiveGranularity = in_ext->meshOutputPerPrimitiveGranularity; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT: - { - VkPhysicalDeviceMeshShaderPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT); - const VkPhysicalDeviceMeshShaderPropertiesEXT *in_ext = (const VkPhysicalDeviceMeshShaderPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT; - out_ext->maxTaskWorkGroupTotalCount = in_ext->maxTaskWorkGroupTotalCount; - memcpy(out_ext->maxTaskWorkGroupCount, in_ext->maxTaskWorkGroupCount, 3 * sizeof(uint32_t)); - out_ext->maxTaskWorkGroupInvocations = in_ext->maxTaskWorkGroupInvocations; - memcpy(out_ext->maxTaskWorkGroupSize, in_ext->maxTaskWorkGroupSize, 3 * sizeof(uint32_t)); - out_ext->maxTaskPayloadSize = in_ext->maxTaskPayloadSize; - out_ext->maxTaskSharedMemorySize = in_ext->maxTaskSharedMemorySize; - out_ext->maxTaskPayloadAndSharedMemorySize = in_ext->maxTaskPayloadAndSharedMemorySize; - out_ext->maxMeshWorkGroupTotalCount = in_ext->maxMeshWorkGroupTotalCount; - memcpy(out_ext->maxMeshWorkGroupCount, in_ext->maxMeshWorkGroupCount, 3 * sizeof(uint32_t)); - out_ext->maxMeshWorkGroupInvocations = in_ext->maxMeshWorkGroupInvocations; - memcpy(out_ext->maxMeshWorkGroupSize, in_ext->maxMeshWorkGroupSize, 3 * sizeof(uint32_t)); - out_ext->maxMeshSharedMemorySize = in_ext->maxMeshSharedMemorySize; - out_ext->maxMeshPayloadAndSharedMemorySize = in_ext->maxMeshPayloadAndSharedMemorySize; - out_ext->maxMeshOutputMemorySize = in_ext->maxMeshOutputMemorySize; - out_ext->maxMeshPayloadAndOutputMemorySize = in_ext->maxMeshPayloadAndOutputMemorySize; - out_ext->maxMeshOutputComponents = in_ext->maxMeshOutputComponents; - out_ext->maxMeshOutputVertices = in_ext->maxMeshOutputVertices; - out_ext->maxMeshOutputPrimitives = in_ext->maxMeshOutputPrimitives; - out_ext->maxMeshOutputLayers = in_ext->maxMeshOutputLayers; - out_ext->maxMeshMultiviewViewCount = in_ext->maxMeshMultiviewViewCount; - out_ext->meshOutputPerVertexGranularity = in_ext->meshOutputPerVertexGranularity; - out_ext->meshOutputPerPrimitiveGranularity = in_ext->meshOutputPerPrimitiveGranularity; - out_ext->maxPreferredTaskWorkGroupInvocations = in_ext->maxPreferredTaskWorkGroupInvocations; - out_ext->maxPreferredMeshWorkGroupInvocations = in_ext->maxPreferredMeshWorkGroupInvocations; - out_ext->prefersLocalInvocationVertexOutput = in_ext->prefersLocalInvocationVertexOutput; - out_ext->prefersLocalInvocationPrimitiveOutput = in_ext->prefersLocalInvocationPrimitiveOutput; - out_ext->prefersCompactVertexOutput = in_ext->prefersCompactVertexOutput; - out_ext->prefersCompactPrimitiveOutput = in_ext->prefersCompactPrimitiveOutput; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR: - { - VkPhysicalDeviceAccelerationStructurePropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR); - const VkPhysicalDeviceAccelerationStructurePropertiesKHR *in_ext = (const VkPhysicalDeviceAccelerationStructurePropertiesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR; - out_ext->maxGeometryCount = in_ext->maxGeometryCount; - out_ext->maxInstanceCount = in_ext->maxInstanceCount; - out_ext->maxPrimitiveCount = in_ext->maxPrimitiveCount; - out_ext->maxPerStageDescriptorAccelerationStructures = in_ext->maxPerStageDescriptorAccelerationStructures; - out_ext->maxPerStageDescriptorUpdateAfterBindAccelerationStructures = in_ext->maxPerStageDescriptorUpdateAfterBindAccelerationStructures; - out_ext->maxDescriptorSetAccelerationStructures = in_ext->maxDescriptorSetAccelerationStructures; - out_ext->maxDescriptorSetUpdateAfterBindAccelerationStructures = in_ext->maxDescriptorSetUpdateAfterBindAccelerationStructures; - out_ext->minAccelerationStructureScratchOffsetAlignment = in_ext->minAccelerationStructureScratchOffsetAlignment; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR: - { - VkPhysicalDeviceRayTracingPipelinePropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR); - const VkPhysicalDeviceRayTracingPipelinePropertiesKHR *in_ext = (const VkPhysicalDeviceRayTracingPipelinePropertiesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR; - out_ext->shaderGroupHandleSize = in_ext->shaderGroupHandleSize; - out_ext->maxRayRecursionDepth = in_ext->maxRayRecursionDepth; - out_ext->maxShaderGroupStride = in_ext->maxShaderGroupStride; - out_ext->shaderGroupBaseAlignment = in_ext->shaderGroupBaseAlignment; - out_ext->shaderGroupHandleCaptureReplaySize = in_ext->shaderGroupHandleCaptureReplaySize; - out_ext->maxRayDispatchInvocationCount = in_ext->maxRayDispatchInvocationCount; - out_ext->shaderGroupHandleAlignment = in_ext->shaderGroupHandleAlignment; - out_ext->maxRayHitAttributeSize = in_ext->maxRayHitAttributeSize; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV: - { - VkPhysicalDeviceRayTracingPropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV); - const VkPhysicalDeviceRayTracingPropertiesNV *in_ext = (const VkPhysicalDeviceRayTracingPropertiesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV; - out_ext->shaderGroupHandleSize = in_ext->shaderGroupHandleSize; - out_ext->maxRecursionDepth = in_ext->maxRecursionDepth; - out_ext->maxShaderGroupStride = in_ext->maxShaderGroupStride; - out_ext->shaderGroupBaseAlignment = in_ext->shaderGroupBaseAlignment; - out_ext->maxGeometryCount = in_ext->maxGeometryCount; - out_ext->maxInstanceCount = in_ext->maxInstanceCount; - out_ext->maxTriangleCount = in_ext->maxTriangleCount; - out_ext->maxDescriptorSetAccelerationStructures = in_ext->maxDescriptorSetAccelerationStructures; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT: - { - VkPhysicalDeviceFragmentDensityMapPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT); - const VkPhysicalDeviceFragmentDensityMapPropertiesEXT *in_ext = (const VkPhysicalDeviceFragmentDensityMapPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT; - out_ext->minFragmentDensityTexelSize = in_ext->minFragmentDensityTexelSize; - out_ext->maxFragmentDensityTexelSize = in_ext->maxFragmentDensityTexelSize; - out_ext->fragmentDensityInvocations = in_ext->fragmentDensityInvocations; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT: - { - VkPhysicalDeviceFragmentDensityMap2PropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT); - const VkPhysicalDeviceFragmentDensityMap2PropertiesEXT *in_ext = (const VkPhysicalDeviceFragmentDensityMap2PropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT; - out_ext->subsampledLoads = in_ext->subsampledLoads; - out_ext->subsampledCoarseReconstructionEarlyAccess = in_ext->subsampledCoarseReconstructionEarlyAccess; - out_ext->maxSubsampledArrayLayers = in_ext->maxSubsampledArrayLayers; - out_ext->maxDescriptorSetSubsampledSamplers = in_ext->maxDescriptorSetSubsampledSamplers; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_QCOM: - { - VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_QCOM); - const VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM *in_ext = (const VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_QCOM; - out_ext->fragmentDensityOffsetGranularity = in_ext->fragmentDensityOffsetGranularity; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV: - { - VkPhysicalDeviceCooperativeMatrixPropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV); - const VkPhysicalDeviceCooperativeMatrixPropertiesNV *in_ext = (const VkPhysicalDeviceCooperativeMatrixPropertiesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV; - out_ext->cooperativeMatrixSupportedStages = in_ext->cooperativeMatrixSupportedStages; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR: - { - VkPhysicalDevicePerformanceQueryPropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR); - const VkPhysicalDevicePerformanceQueryPropertiesKHR *in_ext = (const VkPhysicalDevicePerformanceQueryPropertiesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR; - out_ext->allowCommandBufferQueryCopies = in_ext->allowCommandBufferQueryCopies; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV: - { - VkPhysicalDeviceShaderSMBuiltinsPropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV); - const VkPhysicalDeviceShaderSMBuiltinsPropertiesNV *in_ext = (const VkPhysicalDeviceShaderSMBuiltinsPropertiesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV; - out_ext->shaderSMCount = in_ext->shaderSMCount; - out_ext->shaderWarpsPerSM = in_ext->shaderWarpsPerSM; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES: - { - VkPhysicalDeviceTexelBufferAlignmentProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES); - const VkPhysicalDeviceTexelBufferAlignmentProperties *in_ext = (const VkPhysicalDeviceTexelBufferAlignmentProperties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES; - out_ext->storageTexelBufferOffsetAlignmentBytes = in_ext->storageTexelBufferOffsetAlignmentBytes; - out_ext->storageTexelBufferOffsetSingleTexelAlignment = in_ext->storageTexelBufferOffsetSingleTexelAlignment; - out_ext->uniformTexelBufferOffsetAlignmentBytes = in_ext->uniformTexelBufferOffsetAlignmentBytes; - out_ext->uniformTexelBufferOffsetSingleTexelAlignment = in_ext->uniformTexelBufferOffsetSingleTexelAlignment; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES: - { - VkPhysicalDeviceSubgroupSizeControlProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES); - const VkPhysicalDeviceSubgroupSizeControlProperties *in_ext = (const VkPhysicalDeviceSubgroupSizeControlProperties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES; - out_ext->minSubgroupSize = in_ext->minSubgroupSize; - out_ext->maxSubgroupSize = in_ext->maxSubgroupSize; - out_ext->maxComputeWorkgroupSubgroups = in_ext->maxComputeWorkgroupSubgroups; - out_ext->requiredSubgroupSizeStages = in_ext->requiredSubgroupSizeStages; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI: - { - VkPhysicalDeviceSubpassShadingPropertiesHUAWEI32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI); - const VkPhysicalDeviceSubpassShadingPropertiesHUAWEI *in_ext = (const VkPhysicalDeviceSubpassShadingPropertiesHUAWEI *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI; - out_ext->maxSubpassShadingWorkgroupSizeAspectRatio = in_ext->maxSubpassShadingWorkgroupSizeAspectRatio; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT: - { - VkPhysicalDeviceLineRasterizationPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT); - const VkPhysicalDeviceLineRasterizationPropertiesEXT *in_ext = (const VkPhysicalDeviceLineRasterizationPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT; - out_ext->lineSubPixelPrecisionBits = in_ext->lineSubPixelPrecisionBits; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES: - { - VkPhysicalDeviceVulkan11Properties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES); - const VkPhysicalDeviceVulkan11Properties *in_ext = (const VkPhysicalDeviceVulkan11Properties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES; - memcpy(out_ext->deviceUUID, in_ext->deviceUUID, VK_UUID_SIZE * sizeof(uint8_t)); - memcpy(out_ext->driverUUID, in_ext->driverUUID, VK_UUID_SIZE * sizeof(uint8_t)); - memcpy(out_ext->deviceLUID, in_ext->deviceLUID, VK_LUID_SIZE * sizeof(uint8_t)); - out_ext->deviceNodeMask = in_ext->deviceNodeMask; - out_ext->deviceLUIDValid = in_ext->deviceLUIDValid; - out_ext->subgroupSize = in_ext->subgroupSize; - out_ext->subgroupSupportedStages = in_ext->subgroupSupportedStages; - out_ext->subgroupSupportedOperations = in_ext->subgroupSupportedOperations; - out_ext->subgroupQuadOperationsInAllStages = in_ext->subgroupQuadOperationsInAllStages; - out_ext->pointClippingBehavior = in_ext->pointClippingBehavior; - out_ext->maxMultiviewViewCount = in_ext->maxMultiviewViewCount; - out_ext->maxMultiviewInstanceIndex = in_ext->maxMultiviewInstanceIndex; - out_ext->protectedNoFault = in_ext->protectedNoFault; - out_ext->maxPerSetDescriptors = in_ext->maxPerSetDescriptors; - out_ext->maxMemoryAllocationSize = in_ext->maxMemoryAllocationSize; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES: - { - VkPhysicalDeviceVulkan12Properties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES); - const VkPhysicalDeviceVulkan12Properties *in_ext = (const VkPhysicalDeviceVulkan12Properties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES; - out_ext->driverID = in_ext->driverID; - memcpy(out_ext->driverName, in_ext->driverName, VK_MAX_DRIVER_NAME_SIZE * sizeof(char)); - memcpy(out_ext->driverInfo, in_ext->driverInfo, VK_MAX_DRIVER_INFO_SIZE * sizeof(char)); - out_ext->conformanceVersion = in_ext->conformanceVersion; - out_ext->denormBehaviorIndependence = in_ext->denormBehaviorIndependence; - out_ext->roundingModeIndependence = in_ext->roundingModeIndependence; - out_ext->shaderSignedZeroInfNanPreserveFloat16 = in_ext->shaderSignedZeroInfNanPreserveFloat16; - out_ext->shaderSignedZeroInfNanPreserveFloat32 = in_ext->shaderSignedZeroInfNanPreserveFloat32; - out_ext->shaderSignedZeroInfNanPreserveFloat64 = in_ext->shaderSignedZeroInfNanPreserveFloat64; - out_ext->shaderDenormPreserveFloat16 = in_ext->shaderDenormPreserveFloat16; - out_ext->shaderDenormPreserveFloat32 = in_ext->shaderDenormPreserveFloat32; - out_ext->shaderDenormPreserveFloat64 = in_ext->shaderDenormPreserveFloat64; - out_ext->shaderDenormFlushToZeroFloat16 = in_ext->shaderDenormFlushToZeroFloat16; - out_ext->shaderDenormFlushToZeroFloat32 = in_ext->shaderDenormFlushToZeroFloat32; - out_ext->shaderDenormFlushToZeroFloat64 = in_ext->shaderDenormFlushToZeroFloat64; - out_ext->shaderRoundingModeRTEFloat16 = in_ext->shaderRoundingModeRTEFloat16; - out_ext->shaderRoundingModeRTEFloat32 = in_ext->shaderRoundingModeRTEFloat32; - out_ext->shaderRoundingModeRTEFloat64 = in_ext->shaderRoundingModeRTEFloat64; - out_ext->shaderRoundingModeRTZFloat16 = in_ext->shaderRoundingModeRTZFloat16; - out_ext->shaderRoundingModeRTZFloat32 = in_ext->shaderRoundingModeRTZFloat32; - out_ext->shaderRoundingModeRTZFloat64 = in_ext->shaderRoundingModeRTZFloat64; - out_ext->maxUpdateAfterBindDescriptorsInAllPools = in_ext->maxUpdateAfterBindDescriptorsInAllPools; - out_ext->shaderUniformBufferArrayNonUniformIndexingNative = in_ext->shaderUniformBufferArrayNonUniformIndexingNative; - out_ext->shaderSampledImageArrayNonUniformIndexingNative = in_ext->shaderSampledImageArrayNonUniformIndexingNative; - out_ext->shaderStorageBufferArrayNonUniformIndexingNative = in_ext->shaderStorageBufferArrayNonUniformIndexingNative; - out_ext->shaderStorageImageArrayNonUniformIndexingNative = in_ext->shaderStorageImageArrayNonUniformIndexingNative; - out_ext->shaderInputAttachmentArrayNonUniformIndexingNative = in_ext->shaderInputAttachmentArrayNonUniformIndexingNative; - out_ext->robustBufferAccessUpdateAfterBind = in_ext->robustBufferAccessUpdateAfterBind; - out_ext->quadDivergentImplicitLod = in_ext->quadDivergentImplicitLod; - out_ext->maxPerStageDescriptorUpdateAfterBindSamplers = in_ext->maxPerStageDescriptorUpdateAfterBindSamplers; - out_ext->maxPerStageDescriptorUpdateAfterBindUniformBuffers = in_ext->maxPerStageDescriptorUpdateAfterBindUniformBuffers; - out_ext->maxPerStageDescriptorUpdateAfterBindStorageBuffers = in_ext->maxPerStageDescriptorUpdateAfterBindStorageBuffers; - out_ext->maxPerStageDescriptorUpdateAfterBindSampledImages = in_ext->maxPerStageDescriptorUpdateAfterBindSampledImages; - out_ext->maxPerStageDescriptorUpdateAfterBindStorageImages = in_ext->maxPerStageDescriptorUpdateAfterBindStorageImages; - out_ext->maxPerStageDescriptorUpdateAfterBindInputAttachments = in_ext->maxPerStageDescriptorUpdateAfterBindInputAttachments; - out_ext->maxPerStageUpdateAfterBindResources = in_ext->maxPerStageUpdateAfterBindResources; - out_ext->maxDescriptorSetUpdateAfterBindSamplers = in_ext->maxDescriptorSetUpdateAfterBindSamplers; - out_ext->maxDescriptorSetUpdateAfterBindUniformBuffers = in_ext->maxDescriptorSetUpdateAfterBindUniformBuffers; - out_ext->maxDescriptorSetUpdateAfterBindUniformBuffersDynamic = in_ext->maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; - out_ext->maxDescriptorSetUpdateAfterBindStorageBuffers = in_ext->maxDescriptorSetUpdateAfterBindStorageBuffers; - out_ext->maxDescriptorSetUpdateAfterBindStorageBuffersDynamic = in_ext->maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; - out_ext->maxDescriptorSetUpdateAfterBindSampledImages = in_ext->maxDescriptorSetUpdateAfterBindSampledImages; - out_ext->maxDescriptorSetUpdateAfterBindStorageImages = in_ext->maxDescriptorSetUpdateAfterBindStorageImages; - out_ext->maxDescriptorSetUpdateAfterBindInputAttachments = in_ext->maxDescriptorSetUpdateAfterBindInputAttachments; - out_ext->supportedDepthResolveModes = in_ext->supportedDepthResolveModes; - out_ext->supportedStencilResolveModes = in_ext->supportedStencilResolveModes; - out_ext->independentResolveNone = in_ext->independentResolveNone; - out_ext->independentResolve = in_ext->independentResolve; - out_ext->filterMinmaxSingleComponentFormats = in_ext->filterMinmaxSingleComponentFormats; - out_ext->filterMinmaxImageComponentMapping = in_ext->filterMinmaxImageComponentMapping; - out_ext->maxTimelineSemaphoreValueDifference = in_ext->maxTimelineSemaphoreValueDifference; - out_ext->framebufferIntegerColorSampleCounts = in_ext->framebufferIntegerColorSampleCounts; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES: - { - VkPhysicalDeviceVulkan13Properties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES); - const VkPhysicalDeviceVulkan13Properties *in_ext = (const VkPhysicalDeviceVulkan13Properties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES; - out_ext->minSubgroupSize = in_ext->minSubgroupSize; - out_ext->maxSubgroupSize = in_ext->maxSubgroupSize; - out_ext->maxComputeWorkgroupSubgroups = in_ext->maxComputeWorkgroupSubgroups; - out_ext->requiredSubgroupSizeStages = in_ext->requiredSubgroupSizeStages; - out_ext->maxInlineUniformBlockSize = in_ext->maxInlineUniformBlockSize; - out_ext->maxPerStageDescriptorInlineUniformBlocks = in_ext->maxPerStageDescriptorInlineUniformBlocks; - out_ext->maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks = in_ext->maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; - out_ext->maxDescriptorSetInlineUniformBlocks = in_ext->maxDescriptorSetInlineUniformBlocks; - out_ext->maxDescriptorSetUpdateAfterBindInlineUniformBlocks = in_ext->maxDescriptorSetUpdateAfterBindInlineUniformBlocks; - out_ext->maxInlineUniformTotalSize = in_ext->maxInlineUniformTotalSize; - out_ext->integerDotProduct8BitUnsignedAccelerated = in_ext->integerDotProduct8BitUnsignedAccelerated; - out_ext->integerDotProduct8BitSignedAccelerated = in_ext->integerDotProduct8BitSignedAccelerated; - out_ext->integerDotProduct8BitMixedSignednessAccelerated = in_ext->integerDotProduct8BitMixedSignednessAccelerated; - out_ext->integerDotProduct4x8BitPackedUnsignedAccelerated = in_ext->integerDotProduct4x8BitPackedUnsignedAccelerated; - out_ext->integerDotProduct4x8BitPackedSignedAccelerated = in_ext->integerDotProduct4x8BitPackedSignedAccelerated; - out_ext->integerDotProduct4x8BitPackedMixedSignednessAccelerated = in_ext->integerDotProduct4x8BitPackedMixedSignednessAccelerated; - out_ext->integerDotProduct16BitUnsignedAccelerated = in_ext->integerDotProduct16BitUnsignedAccelerated; - out_ext->integerDotProduct16BitSignedAccelerated = in_ext->integerDotProduct16BitSignedAccelerated; - out_ext->integerDotProduct16BitMixedSignednessAccelerated = in_ext->integerDotProduct16BitMixedSignednessAccelerated; - out_ext->integerDotProduct32BitUnsignedAccelerated = in_ext->integerDotProduct32BitUnsignedAccelerated; - out_ext->integerDotProduct32BitSignedAccelerated = in_ext->integerDotProduct32BitSignedAccelerated; - out_ext->integerDotProduct32BitMixedSignednessAccelerated = in_ext->integerDotProduct32BitMixedSignednessAccelerated; - out_ext->integerDotProduct64BitUnsignedAccelerated = in_ext->integerDotProduct64BitUnsignedAccelerated; - out_ext->integerDotProduct64BitSignedAccelerated = in_ext->integerDotProduct64BitSignedAccelerated; - out_ext->integerDotProduct64BitMixedSignednessAccelerated = in_ext->integerDotProduct64BitMixedSignednessAccelerated; - out_ext->integerDotProductAccumulatingSaturating8BitUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating8BitUnsignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating8BitSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating8BitSignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated; - out_ext->integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated; - out_ext->integerDotProductAccumulatingSaturating16BitUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating16BitUnsignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating16BitSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating16BitSignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated; - out_ext->integerDotProductAccumulatingSaturating32BitUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating32BitUnsignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating32BitSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating32BitSignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated; - out_ext->integerDotProductAccumulatingSaturating64BitUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating64BitUnsignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating64BitSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating64BitSignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated; - out_ext->storageTexelBufferOffsetAlignmentBytes = in_ext->storageTexelBufferOffsetAlignmentBytes; - out_ext->storageTexelBufferOffsetSingleTexelAlignment = in_ext->storageTexelBufferOffsetSingleTexelAlignment; - out_ext->uniformTexelBufferOffsetAlignmentBytes = in_ext->uniformTexelBufferOffsetAlignmentBytes; - out_ext->uniformTexelBufferOffsetSingleTexelAlignment = in_ext->uniformTexelBufferOffsetSingleTexelAlignment; - out_ext->maxBufferSize = in_ext->maxBufferSize; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT: - { - VkPhysicalDeviceCustomBorderColorPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT); - const VkPhysicalDeviceCustomBorderColorPropertiesEXT *in_ext = (const VkPhysicalDeviceCustomBorderColorPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT; - out_ext->maxCustomBorderColorSamplers = in_ext->maxCustomBorderColorSamplers; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT: - { - VkPhysicalDeviceExtendedDynamicState3PropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT); - const VkPhysicalDeviceExtendedDynamicState3PropertiesEXT *in_ext = (const VkPhysicalDeviceExtendedDynamicState3PropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT; - out_ext->dynamicPrimitiveTopologyUnrestricted = in_ext->dynamicPrimitiveTopologyUnrestricted; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT: - { - VkPhysicalDeviceRobustness2PropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT); - const VkPhysicalDeviceRobustness2PropertiesEXT *in_ext = (const VkPhysicalDeviceRobustness2PropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT; - out_ext->robustStorageBufferAccessSizeAlignment = in_ext->robustStorageBufferAccessSizeAlignment; - out_ext->robustUniformBufferAccessSizeAlignment = in_ext->robustUniformBufferAccessSizeAlignment; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR: - { - VkPhysicalDeviceFragmentShadingRatePropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR); - const VkPhysicalDeviceFragmentShadingRatePropertiesKHR *in_ext = (const VkPhysicalDeviceFragmentShadingRatePropertiesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR; - out_ext->minFragmentShadingRateAttachmentTexelSize = in_ext->minFragmentShadingRateAttachmentTexelSize; - out_ext->maxFragmentShadingRateAttachmentTexelSize = in_ext->maxFragmentShadingRateAttachmentTexelSize; - out_ext->maxFragmentShadingRateAttachmentTexelSizeAspectRatio = in_ext->maxFragmentShadingRateAttachmentTexelSizeAspectRatio; - out_ext->primitiveFragmentShadingRateWithMultipleViewports = in_ext->primitiveFragmentShadingRateWithMultipleViewports; - out_ext->layeredShadingRateAttachments = in_ext->layeredShadingRateAttachments; - out_ext->fragmentShadingRateNonTrivialCombinerOps = in_ext->fragmentShadingRateNonTrivialCombinerOps; - out_ext->maxFragmentSize = in_ext->maxFragmentSize; - out_ext->maxFragmentSizeAspectRatio = in_ext->maxFragmentSizeAspectRatio; - out_ext->maxFragmentShadingRateCoverageSamples = in_ext->maxFragmentShadingRateCoverageSamples; - out_ext->maxFragmentShadingRateRasterizationSamples = in_ext->maxFragmentShadingRateRasterizationSamples; - out_ext->fragmentShadingRateWithShaderDepthStencilWrites = in_ext->fragmentShadingRateWithShaderDepthStencilWrites; - out_ext->fragmentShadingRateWithSampleMask = in_ext->fragmentShadingRateWithSampleMask; - out_ext->fragmentShadingRateWithShaderSampleMask = in_ext->fragmentShadingRateWithShaderSampleMask; - out_ext->fragmentShadingRateWithConservativeRasterization = in_ext->fragmentShadingRateWithConservativeRasterization; - out_ext->fragmentShadingRateWithFragmentShaderInterlock = in_ext->fragmentShadingRateWithFragmentShaderInterlock; - out_ext->fragmentShadingRateWithCustomSampleLocations = in_ext->fragmentShadingRateWithCustomSampleLocations; - out_ext->fragmentShadingRateStrictMultiplyCombiner = in_ext->fragmentShadingRateStrictMultiplyCombiner; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV: - { - VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV); - const VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV *in_ext = (const VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV; - out_ext->maxFragmentShadingRateInvocationCount = in_ext->maxFragmentShadingRateInvocationCount; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT: - { - VkPhysicalDeviceProvokingVertexPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT); - const VkPhysicalDeviceProvokingVertexPropertiesEXT *in_ext = (const VkPhysicalDeviceProvokingVertexPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT; - out_ext->provokingVertexModePerPipeline = in_ext->provokingVertexModePerPipeline; - out_ext->transformFeedbackPreservesTriangleFanProvokingVertex = in_ext->transformFeedbackPreservesTriangleFanProvokingVertex; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT: - { - VkPhysicalDeviceDescriptorBufferPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT); - const VkPhysicalDeviceDescriptorBufferPropertiesEXT *in_ext = (const VkPhysicalDeviceDescriptorBufferPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT; - out_ext->combinedImageSamplerDescriptorSingleArray = in_ext->combinedImageSamplerDescriptorSingleArray; - out_ext->bufferlessPushDescriptors = in_ext->bufferlessPushDescriptors; - out_ext->allowSamplerImageViewPostSubmitCreation = in_ext->allowSamplerImageViewPostSubmitCreation; - out_ext->descriptorBufferOffsetAlignment = in_ext->descriptorBufferOffsetAlignment; - out_ext->maxDescriptorBufferBindings = in_ext->maxDescriptorBufferBindings; - out_ext->maxResourceDescriptorBufferBindings = in_ext->maxResourceDescriptorBufferBindings; - out_ext->maxSamplerDescriptorBufferBindings = in_ext->maxSamplerDescriptorBufferBindings; - out_ext->maxEmbeddedImmutableSamplerBindings = in_ext->maxEmbeddedImmutableSamplerBindings; - out_ext->maxEmbeddedImmutableSamplers = in_ext->maxEmbeddedImmutableSamplers; - out_ext->bufferCaptureReplayDescriptorDataSize = in_ext->bufferCaptureReplayDescriptorDataSize; - out_ext->imageCaptureReplayDescriptorDataSize = in_ext->imageCaptureReplayDescriptorDataSize; - out_ext->imageViewCaptureReplayDescriptorDataSize = in_ext->imageViewCaptureReplayDescriptorDataSize; - out_ext->samplerCaptureReplayDescriptorDataSize = in_ext->samplerCaptureReplayDescriptorDataSize; - out_ext->accelerationStructureCaptureReplayDescriptorDataSize = in_ext->accelerationStructureCaptureReplayDescriptorDataSize; - out_ext->samplerDescriptorSize = in_ext->samplerDescriptorSize; - out_ext->combinedImageSamplerDescriptorSize = in_ext->combinedImageSamplerDescriptorSize; - out_ext->sampledImageDescriptorSize = in_ext->sampledImageDescriptorSize; - out_ext->storageImageDescriptorSize = in_ext->storageImageDescriptorSize; - out_ext->uniformTexelBufferDescriptorSize = in_ext->uniformTexelBufferDescriptorSize; - out_ext->robustUniformTexelBufferDescriptorSize = in_ext->robustUniformTexelBufferDescriptorSize; - out_ext->storageTexelBufferDescriptorSize = in_ext->storageTexelBufferDescriptorSize; - out_ext->robustStorageTexelBufferDescriptorSize = in_ext->robustStorageTexelBufferDescriptorSize; - out_ext->uniformBufferDescriptorSize = in_ext->uniformBufferDescriptorSize; - out_ext->robustUniformBufferDescriptorSize = in_ext->robustUniformBufferDescriptorSize; - out_ext->storageBufferDescriptorSize = in_ext->storageBufferDescriptorSize; - out_ext->robustStorageBufferDescriptorSize = in_ext->robustStorageBufferDescriptorSize; - out_ext->inputAttachmentDescriptorSize = in_ext->inputAttachmentDescriptorSize; - out_ext->accelerationStructureDescriptorSize = in_ext->accelerationStructureDescriptorSize; - out_ext->maxSamplerDescriptorBufferRange = in_ext->maxSamplerDescriptorBufferRange; - out_ext->maxResourceDescriptorBufferRange = in_ext->maxResourceDescriptorBufferRange; - out_ext->samplerDescriptorBufferAddressSpaceSize = in_ext->samplerDescriptorBufferAddressSpaceSize; - out_ext->resourceDescriptorBufferAddressSpaceSize = in_ext->resourceDescriptorBufferAddressSpaceSize; - out_ext->descriptorBufferAddressSpaceSize = in_ext->descriptorBufferAddressSpaceSize; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT: - { - VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT); - const VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT *in_ext = (const VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT; - out_ext->combinedImageSamplerDensityMapDescriptorSize = in_ext->combinedImageSamplerDensityMapDescriptorSize; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES: - { - VkPhysicalDeviceShaderIntegerDotProductProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES); - const VkPhysicalDeviceShaderIntegerDotProductProperties *in_ext = (const VkPhysicalDeviceShaderIntegerDotProductProperties *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES; - out_ext->integerDotProduct8BitUnsignedAccelerated = in_ext->integerDotProduct8BitUnsignedAccelerated; - out_ext->integerDotProduct8BitSignedAccelerated = in_ext->integerDotProduct8BitSignedAccelerated; - out_ext->integerDotProduct8BitMixedSignednessAccelerated = in_ext->integerDotProduct8BitMixedSignednessAccelerated; - out_ext->integerDotProduct4x8BitPackedUnsignedAccelerated = in_ext->integerDotProduct4x8BitPackedUnsignedAccelerated; - out_ext->integerDotProduct4x8BitPackedSignedAccelerated = in_ext->integerDotProduct4x8BitPackedSignedAccelerated; - out_ext->integerDotProduct4x8BitPackedMixedSignednessAccelerated = in_ext->integerDotProduct4x8BitPackedMixedSignednessAccelerated; - out_ext->integerDotProduct16BitUnsignedAccelerated = in_ext->integerDotProduct16BitUnsignedAccelerated; - out_ext->integerDotProduct16BitSignedAccelerated = in_ext->integerDotProduct16BitSignedAccelerated; - out_ext->integerDotProduct16BitMixedSignednessAccelerated = in_ext->integerDotProduct16BitMixedSignednessAccelerated; - out_ext->integerDotProduct32BitUnsignedAccelerated = in_ext->integerDotProduct32BitUnsignedAccelerated; - out_ext->integerDotProduct32BitSignedAccelerated = in_ext->integerDotProduct32BitSignedAccelerated; - out_ext->integerDotProduct32BitMixedSignednessAccelerated = in_ext->integerDotProduct32BitMixedSignednessAccelerated; - out_ext->integerDotProduct64BitUnsignedAccelerated = in_ext->integerDotProduct64BitUnsignedAccelerated; - out_ext->integerDotProduct64BitSignedAccelerated = in_ext->integerDotProduct64BitSignedAccelerated; - out_ext->integerDotProduct64BitMixedSignednessAccelerated = in_ext->integerDotProduct64BitMixedSignednessAccelerated; - out_ext->integerDotProductAccumulatingSaturating8BitUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating8BitUnsignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating8BitSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating8BitSignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated; - out_ext->integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated; - out_ext->integerDotProductAccumulatingSaturating16BitUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating16BitUnsignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating16BitSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating16BitSignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated; - out_ext->integerDotProductAccumulatingSaturating32BitUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating32BitUnsignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating32BitSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating32BitSignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated; - out_ext->integerDotProductAccumulatingSaturating64BitUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating64BitUnsignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating64BitSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating64BitSignedAccelerated; - out_ext->integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR: - { - VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR); - const VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR *in_ext = (const VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR; - out_ext->triStripVertexOrderIndependentOfProvokingVertex = in_ext->triStripVertexOrderIndependentOfProvokingVertex; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT: - { - VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT); - const VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT *in_ext = (const VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT; - out_ext->graphicsPipelineLibraryFastLinking = in_ext->graphicsPipelineLibraryFastLinking; - out_ext->graphicsPipelineLibraryIndependentInterpolationDecoration = in_ext->graphicsPipelineLibraryIndependentInterpolationDecoration; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT: - { - VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT); - const VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT *in_ext = (const VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT; - memcpy(out_ext->shaderModuleIdentifierAlgorithmUUID, in_ext->shaderModuleIdentifierAlgorithmUUID, VK_UUID_SIZE * sizeof(uint8_t)); - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_EXT: - { - VkPhysicalDeviceOpacityMicromapPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_EXT); - const VkPhysicalDeviceOpacityMicromapPropertiesEXT *in_ext = (const VkPhysicalDeviceOpacityMicromapPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_EXT; - out_ext->maxOpacity2StateSubdivisionLevel = in_ext->maxOpacity2StateSubdivisionLevel; - out_ext->maxOpacity4StateSubdivisionLevel = in_ext->maxOpacity4StateSubdivisionLevel; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES_EXT: - { - VkPhysicalDevicePipelineRobustnessPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES_EXT); - const VkPhysicalDevicePipelineRobustnessPropertiesEXT *in_ext = (const VkPhysicalDevicePipelineRobustnessPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES_EXT; - out_ext->defaultRobustnessStorageBuffers = in_ext->defaultRobustnessStorageBuffers; - out_ext->defaultRobustnessUniformBuffers = in_ext->defaultRobustnessUniformBuffers; - out_ext->defaultRobustnessVertexInputs = in_ext->defaultRobustnessVertexInputs; - out_ext->defaultRobustnessImages = in_ext->defaultRobustnessImages; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM: - { - VkPhysicalDeviceImageProcessingPropertiesQCOM32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM); - const VkPhysicalDeviceImageProcessingPropertiesQCOM *in_ext = (const VkPhysicalDeviceImageProcessingPropertiesQCOM *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM; - out_ext->maxWeightFilterPhases = in_ext->maxWeightFilterPhases; - out_ext->maxWeightFilterDimension = in_ext->maxWeightFilterDimension; - out_ext->maxBlockMatchRegion = in_ext->maxBlockMatchRegion; - out_ext->maxBoxFilterBlockSize = in_ext->maxBoxFilterBlockSize; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV: - { - VkPhysicalDeviceOpticalFlowPropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV); - const VkPhysicalDeviceOpticalFlowPropertiesNV *in_ext = (const VkPhysicalDeviceOpticalFlowPropertiesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV; - out_ext->supportedOutputGridSizes = in_ext->supportedOutputGridSizes; - out_ext->supportedHintGridSizes = in_ext->supportedHintGridSizes; - out_ext->hintSupported = in_ext->hintSupported; - out_ext->costSupported = in_ext->costSupported; - out_ext->bidirectionalFlowSupported = in_ext->bidirectionalFlowSupported; - out_ext->globalFlowSupported = in_ext->globalFlowSupported; - out_ext->minWidth = in_ext->minWidth; - out_ext->minHeight = in_ext->minHeight; - out_ext->maxWidth = in_ext->maxWidth; - out_ext->maxHeight = in_ext->maxHeight; - out_ext->maxNumRegionsOfInterest = in_ext->maxNumRegionsOfInterest; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM: - { - VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM); - const VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM *in_ext = (const VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM; - out_ext->shaderCoreMask = in_ext->shaderCoreMask; - out_ext->shaderCoreCount = in_ext->shaderCoreCount; - out_ext->shaderWarpsPerCore = in_ext->shaderWarpsPerCore; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV: - { - VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV); - const VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV *in_ext = (const VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV; - out_ext->rayTracingInvocationReorderReorderingHint = in_ext->rayTracingInvocationReorderReorderingHint; - out_header = (void *)out_ext; - break; - } - default: - break; - } - } -} - -static inline void convert_VkQueryPoolPerformanceCreateInfoKHR_win32_to_host(const VkQueryPoolPerformanceCreateInfoKHR32 *in, VkQueryPoolPerformanceCreateInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->queueFamilyIndex = in->queueFamilyIndex; - out->counterIndexCount = in->counterIndexCount; - out->pCounterIndices = (const uint32_t *)UlongToPtr(in->pCounterIndices); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkQueueFamilyProperties2_win32_to_host(struct conversion_context *ctx, const VkQueueFamilyProperties232 *in, VkQueueFamilyProperties2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR: - { - VkQueueFamilyGlobalPriorityPropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkQueueFamilyGlobalPriorityPropertiesKHR32 *in_ext = (const VkQueueFamilyGlobalPriorityPropertiesKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR; - out_ext->pNext = NULL; - out_ext->priorityCount = in_ext->priorityCount; - memcpy(out_ext->priorities, in_ext->priorities, VK_MAX_GLOBAL_PRIORITY_SIZE_KHR * sizeof(VkQueueGlobalPriorityKHR)); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV: - { - VkQueueFamilyCheckpointPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV: - { - VkQueueFamilyCheckpointProperties2NV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkQueueFamilyProperties2_host_to_win32(const VkQueueFamilyProperties2 *in, VkQueueFamilyProperties232 *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure32 *out_header = (void *)out; - - if (!in) return; - - out->queueFamilyProperties = in->queueFamilyProperties; - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR: - { - VkQueueFamilyGlobalPriorityPropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR); - const VkQueueFamilyGlobalPriorityPropertiesKHR *in_ext = (const VkQueueFamilyGlobalPriorityPropertiesKHR *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR; - out_ext->priorityCount = in_ext->priorityCount; - memcpy(out_ext->priorities, in_ext->priorities, VK_MAX_GLOBAL_PRIORITY_SIZE_KHR * sizeof(VkQueueGlobalPriorityKHR)); - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV: - { - VkQueueFamilyCheckpointPropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV); - const VkQueueFamilyCheckpointPropertiesNV *in_ext = (const VkQueueFamilyCheckpointPropertiesNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV; - out_ext->checkpointExecutionStageMask = in_ext->checkpointExecutionStageMask; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV: - { - VkQueueFamilyCheckpointProperties2NV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV); - const VkQueueFamilyCheckpointProperties2NV *in_ext = (const VkQueueFamilyCheckpointProperties2NV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV; - out_ext->checkpointExecutionStageMask = in_ext->checkpointExecutionStageMask; - out_header = (void *)out_ext; - break; - } - default: - break; - } - } -} - -static inline VkQueueFamilyProperties2 *convert_VkQueueFamilyProperties2_array_win32_to_host(struct conversion_context *ctx, const VkQueueFamilyProperties232 *in, uint32_t count) -{ - VkQueueFamilyProperties2 *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkQueueFamilyProperties2_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkQueueFamilyProperties2_array_host_to_win32(const VkQueueFamilyProperties2 *in, VkQueueFamilyProperties232 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkQueueFamilyProperties2_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkPhysicalDeviceSparseImageFormatInfo2_win32_to_host(const VkPhysicalDeviceSparseImageFormatInfo232 *in, VkPhysicalDeviceSparseImageFormatInfo2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->format = in->format; - out->type = in->type; - out->samples = in->samples; - out->usage = in->usage; - out->tiling = in->tiling; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkSparseImageFormatProperties2_win32_to_host(const VkSparseImageFormatProperties232 *in, VkSparseImageFormatProperties2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkSparseImageFormatProperties2_host_to_win32(const VkSparseImageFormatProperties2 *in, VkSparseImageFormatProperties232 *out) -{ - if (!in) return; - - out->properties = in->properties; -} - -static inline VkSparseImageFormatProperties2 *convert_VkSparseImageFormatProperties2_array_win32_to_host(struct conversion_context *ctx, const VkSparseImageFormatProperties232 *in, uint32_t count) -{ - VkSparseImageFormatProperties2 *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSparseImageFormatProperties2_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkSparseImageFormatProperties2_array_host_to_win32(const VkSparseImageFormatProperties2 *in, VkSparseImageFormatProperties232 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkSparseImageFormatProperties2_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkFramebufferMixedSamplesCombinationNV_win32_to_host(const VkFramebufferMixedSamplesCombinationNV32 *in, VkFramebufferMixedSamplesCombinationNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkFramebufferMixedSamplesCombinationNV_host_to_win32(const VkFramebufferMixedSamplesCombinationNV *in, VkFramebufferMixedSamplesCombinationNV32 *out) -{ - if (!in) return; - - out->coverageReductionMode = in->coverageReductionMode; - out->rasterizationSamples = in->rasterizationSamples; - out->depthStencilSamples = in->depthStencilSamples; - out->colorSamples = in->colorSamples; -} - -static inline VkFramebufferMixedSamplesCombinationNV *convert_VkFramebufferMixedSamplesCombinationNV_array_win32_to_host(struct conversion_context *ctx, const VkFramebufferMixedSamplesCombinationNV32 *in, uint32_t count) -{ - VkFramebufferMixedSamplesCombinationNV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkFramebufferMixedSamplesCombinationNV_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkFramebufferMixedSamplesCombinationNV_array_host_to_win32(const VkFramebufferMixedSamplesCombinationNV *in, VkFramebufferMixedSamplesCombinationNV32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkFramebufferMixedSamplesCombinationNV_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkPhysicalDeviceSurfaceInfo2KHR_win32_to_unwrapped_host(struct conversion_context *ctx, const VkPhysicalDeviceSurfaceInfo2KHR32 *in, VkPhysicalDeviceSurfaceInfo2KHR *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->surface = in->surface; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT: - { - VkSurfacePresentModeEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSurfacePresentModeEXT32 *in_ext = (const VkSurfacePresentModeEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT; - out_ext->pNext = NULL; - out_ext->presentMode = in_ext->presentMode; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkSurfaceCapabilities2KHR_win32_to_host(struct conversion_context *ctx, const VkSurfaceCapabilities2KHR32 *in, VkSurfaceCapabilities2KHR *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_PRESENT_BARRIER_NV: - { - VkSurfaceCapabilitiesPresentBarrierNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_PRESENT_BARRIER_NV; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT: - { - VkSurfacePresentScalingCapabilitiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSurfacePresentScalingCapabilitiesEXT32 *in_ext = (const VkSurfacePresentScalingCapabilitiesEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT; - out_ext->pNext = NULL; - out_ext->supportedPresentScaling = in_ext->supportedPresentScaling; - out_ext->supportedPresentGravityX = in_ext->supportedPresentGravityX; - out_ext->supportedPresentGravityY = in_ext->supportedPresentGravityY; - out_ext->minScaledImageExtent = in_ext->minScaledImageExtent; - out_ext->maxScaledImageExtent = in_ext->maxScaledImageExtent; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT: - { - VkSurfacePresentModeCompatibilityEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSurfacePresentModeCompatibilityEXT32 *in_ext = (const VkSurfacePresentModeCompatibilityEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT; - out_ext->pNext = NULL; - out_ext->presentModeCount = in_ext->presentModeCount; - out_ext->pPresentModes = (VkPresentModeKHR *)UlongToPtr(in_ext->pPresentModes); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkSurfaceCapabilities2KHR_host_to_win32(const VkSurfaceCapabilities2KHR *in, VkSurfaceCapabilities2KHR32 *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure32 *out_header = (void *)out; - - if (!in) return; - - out->surfaceCapabilities = in->surfaceCapabilities; - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_PRESENT_BARRIER_NV: - { - VkSurfaceCapabilitiesPresentBarrierNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_PRESENT_BARRIER_NV); - const VkSurfaceCapabilitiesPresentBarrierNV *in_ext = (const VkSurfaceCapabilitiesPresentBarrierNV *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_PRESENT_BARRIER_NV; - out_ext->presentBarrierSupported = in_ext->presentBarrierSupported; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT: - { - VkSurfacePresentScalingCapabilitiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT); - const VkSurfacePresentScalingCapabilitiesEXT *in_ext = (const VkSurfacePresentScalingCapabilitiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT; - out_ext->supportedPresentScaling = in_ext->supportedPresentScaling; - out_ext->supportedPresentGravityX = in_ext->supportedPresentGravityX; - out_ext->supportedPresentGravityY = in_ext->supportedPresentGravityY; - out_ext->minScaledImageExtent = in_ext->minScaledImageExtent; - out_ext->maxScaledImageExtent = in_ext->maxScaledImageExtent; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT: - { - VkSurfacePresentModeCompatibilityEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT); - const VkSurfacePresentModeCompatibilityEXT *in_ext = (const VkSurfacePresentModeCompatibilityEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT; - out_ext->presentModeCount = in_ext->presentModeCount; - out_ext->pPresentModes = PtrToUlong(in_ext->pPresentModes); - out_header = (void *)out_ext; - break; - } - default: - break; - } - } -} - -#ifdef _WIN64 -static inline void convert_VkPhysicalDeviceSurfaceInfo2KHR_win64_to_host(const VkPhysicalDeviceSurfaceInfo2KHR *in, VkPhysicalDeviceSurfaceInfo2KHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->surface = in->surface ? wine_surface_from_handle(in->surface)->driver_surface : 0; -} -#endif /* _WIN64 */ - -static inline void convert_VkPhysicalDeviceSurfaceInfo2KHR_win32_to_host(struct conversion_context *ctx, const VkPhysicalDeviceSurfaceInfo2KHR32 *in, VkPhysicalDeviceSurfaceInfo2KHR *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->surface = in->surface ? wine_surface_from_handle(in->surface)->driver_surface : 0; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT: - { - VkSurfacePresentModeEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSurfacePresentModeEXT32 *in_ext = (const VkSurfacePresentModeEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT; - out_ext->pNext = NULL; - out_ext->presentMode = in_ext->presentMode; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkSurfaceFormat2KHR_win32_to_host(struct conversion_context *ctx, const VkSurfaceFormat2KHR32 *in, VkSurfaceFormat2KHR *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT: - { - VkImageCompressionPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT; - out_ext->pNext = NULL; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkSurfaceFormat2KHR_host_to_win32(const VkSurfaceFormat2KHR *in, VkSurfaceFormat2KHR32 *out) -{ - const VkBaseInStructure *in_header; - VkBaseOutStructure32 *out_header = (void *)out; - - if (!in) return; - - out->surfaceFormat = in->surfaceFormat; - - for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT: - { - VkImageCompressionPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT); - const VkImageCompressionPropertiesEXT *in_ext = (const VkImageCompressionPropertiesEXT *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT; - out_ext->imageCompressionFlags = in_ext->imageCompressionFlags; - out_ext->imageCompressionFixedRateFlags = in_ext->imageCompressionFixedRateFlags; - out_header = (void *)out_ext; - break; - } - default: - break; - } - } -} - -static inline VkSurfaceFormat2KHR *convert_VkSurfaceFormat2KHR_array_win32_to_host(struct conversion_context *ctx, const VkSurfaceFormat2KHR32 *in, uint32_t count) -{ - VkSurfaceFormat2KHR *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSurfaceFormat2KHR_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkSurfaceFormat2KHR_array_host_to_win32(const VkSurfaceFormat2KHR *in, VkSurfaceFormat2KHR32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkSurfaceFormat2KHR_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkPhysicalDeviceToolProperties_win32_to_host(const VkPhysicalDeviceToolProperties32 *in, VkPhysicalDeviceToolProperties *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkPhysicalDeviceToolProperties_host_to_win32(const VkPhysicalDeviceToolProperties *in, VkPhysicalDeviceToolProperties32 *out) -{ - if (!in) return; - - memcpy(out->name, in->name, VK_MAX_EXTENSION_NAME_SIZE * sizeof(char)); - memcpy(out->version, in->version, VK_MAX_EXTENSION_NAME_SIZE * sizeof(char)); - out->purposes = in->purposes; - memcpy(out->description, in->description, VK_MAX_DESCRIPTION_SIZE * sizeof(char)); - memcpy(out->layer, in->layer, VK_MAX_EXTENSION_NAME_SIZE * sizeof(char)); -} - -static inline VkPhysicalDeviceToolProperties *convert_VkPhysicalDeviceToolProperties_array_win32_to_host(struct conversion_context *ctx, const VkPhysicalDeviceToolProperties32 *in, uint32_t count) -{ - VkPhysicalDeviceToolProperties *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPhysicalDeviceToolProperties_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPhysicalDeviceToolProperties_array_host_to_win32(const VkPhysicalDeviceToolProperties *in, VkPhysicalDeviceToolProperties32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkPhysicalDeviceToolProperties_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkPipelineExecutableInfoKHR_win32_to_host(const VkPipelineExecutableInfoKHR32 *in, VkPipelineExecutableInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->pipeline = in->pipeline; - out->executableIndex = in->executableIndex; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkPipelineExecutableInternalRepresentationKHR_win32_to_host(const VkPipelineExecutableInternalRepresentationKHR32 *in, VkPipelineExecutableInternalRepresentationKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkPipelineExecutableInternalRepresentationKHR_host_to_win32(const VkPipelineExecutableInternalRepresentationKHR *in, VkPipelineExecutableInternalRepresentationKHR32 *out) -{ - if (!in) return; - - memcpy(out->name, in->name, VK_MAX_DESCRIPTION_SIZE * sizeof(char)); - memcpy(out->description, in->description, VK_MAX_DESCRIPTION_SIZE * sizeof(char)); - out->isText = in->isText; - out->dataSize = in->dataSize; - out->pData = PtrToUlong(in->pData); -} - -static inline VkPipelineExecutableInternalRepresentationKHR *convert_VkPipelineExecutableInternalRepresentationKHR_array_win32_to_host(struct conversion_context *ctx, const VkPipelineExecutableInternalRepresentationKHR32 *in, uint32_t count) -{ - VkPipelineExecutableInternalRepresentationKHR *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPipelineExecutableInternalRepresentationKHR_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPipelineExecutableInternalRepresentationKHR_array_host_to_win32(const VkPipelineExecutableInternalRepresentationKHR *in, VkPipelineExecutableInternalRepresentationKHR32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkPipelineExecutableInternalRepresentationKHR_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkPipelineInfoKHR_win32_to_host(const VkPipelineInfoKHR32 *in, VkPipelineInfoKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->pipeline = in->pipeline; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkPipelineExecutablePropertiesKHR_win32_to_host(const VkPipelineExecutablePropertiesKHR32 *in, VkPipelineExecutablePropertiesKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkPipelineExecutablePropertiesKHR_host_to_win32(const VkPipelineExecutablePropertiesKHR *in, VkPipelineExecutablePropertiesKHR32 *out) -{ - if (!in) return; - - out->stages = in->stages; - memcpy(out->name, in->name, VK_MAX_DESCRIPTION_SIZE * sizeof(char)); - memcpy(out->description, in->description, VK_MAX_DESCRIPTION_SIZE * sizeof(char)); - out->subgroupSize = in->subgroupSize; -} - -static inline VkPipelineExecutablePropertiesKHR *convert_VkPipelineExecutablePropertiesKHR_array_win32_to_host(struct conversion_context *ctx, const VkPipelineExecutablePropertiesKHR32 *in, uint32_t count) -{ - VkPipelineExecutablePropertiesKHR *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPipelineExecutablePropertiesKHR_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPipelineExecutablePropertiesKHR_array_host_to_win32(const VkPipelineExecutablePropertiesKHR *in, VkPipelineExecutablePropertiesKHR32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkPipelineExecutablePropertiesKHR_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkPipelineExecutableStatisticValueKHR_host_to_win32(const VkPipelineExecutableStatisticValueKHR *in, VkPipelineExecutableStatisticValueKHR32 *out, VkFlags selector) -{ - if (!in) return; - - if (selector == VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR) - out->b32 = in->b32; - if (selector == VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR) - out->i64 = in->i64; - if (selector == VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR) - out->u64 = in->u64; - if (selector == VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR) - out->f64 = in->f64; -} - -static inline void convert_VkPipelineExecutableStatisticKHR_win32_to_host(const VkPipelineExecutableStatisticKHR32 *in, VkPipelineExecutableStatisticKHR *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkPipelineExecutableStatisticKHR_host_to_win32(const VkPipelineExecutableStatisticKHR *in, VkPipelineExecutableStatisticKHR32 *out) -{ - if (!in) return; - - memcpy(out->name, in->name, VK_MAX_DESCRIPTION_SIZE * sizeof(char)); - memcpy(out->description, in->description, VK_MAX_DESCRIPTION_SIZE * sizeof(char)); - out->format = in->format; - convert_VkPipelineExecutableStatisticValueKHR_host_to_win32(&in->value, &out->value, in->format); -} - -static inline VkPipelineExecutableStatisticKHR *convert_VkPipelineExecutableStatisticKHR_array_win32_to_host(struct conversion_context *ctx, const VkPipelineExecutableStatisticKHR32 *in, uint32_t count) -{ - VkPipelineExecutableStatisticKHR *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPipelineExecutableStatisticKHR_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPipelineExecutableStatisticKHR_array_host_to_win32(const VkPipelineExecutableStatisticKHR *in, VkPipelineExecutableStatisticKHR32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkPipelineExecutableStatisticKHR_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkPipelineInfoEXT_win32_to_host(const VkPipelineInfoEXT32 *in, VkPipelineInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->pipeline = in->pipeline; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkCheckpointData2NV_win32_to_host(const VkCheckpointData2NV32 *in, VkCheckpointData2NV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkCheckpointData2NV_host_to_win32(const VkCheckpointData2NV *in, VkCheckpointData2NV32 *out) -{ - if (!in) return; - - out->stage = in->stage; - out->pCheckpointMarker = PtrToUlong(in->pCheckpointMarker); -} - -static inline VkCheckpointData2NV *convert_VkCheckpointData2NV_array_win32_to_host(struct conversion_context *ctx, const VkCheckpointData2NV32 *in, uint32_t count) -{ - VkCheckpointData2NV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkCheckpointData2NV_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkCheckpointData2NV_array_host_to_win32(const VkCheckpointData2NV *in, VkCheckpointData2NV32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkCheckpointData2NV_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkCheckpointDataNV_win32_to_host(const VkCheckpointDataNV32 *in, VkCheckpointDataNV *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkCheckpointDataNV_host_to_win32(const VkCheckpointDataNV *in, VkCheckpointDataNV32 *out) -{ - if (!in) return; - - out->stage = in->stage; - out->pCheckpointMarker = PtrToUlong(in->pCheckpointMarker); -} - -static inline VkCheckpointDataNV *convert_VkCheckpointDataNV_array_win32_to_host(struct conversion_context *ctx, const VkCheckpointDataNV32 *in, uint32_t count) -{ - VkCheckpointDataNV *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkCheckpointDataNV_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkCheckpointDataNV_array_host_to_win32(const VkCheckpointDataNV *in, VkCheckpointDataNV32 *out, uint32_t count) -{ - unsigned int i; - - if (!in) return; - - for (i = 0; i < count; i++) - { - convert_VkCheckpointDataNV_host_to_win32(&in[i], &out[i]); - } -} - -static inline void convert_VkSamplerCaptureDescriptorDataInfoEXT_win32_to_host(const VkSamplerCaptureDescriptorDataInfoEXT32 *in, VkSamplerCaptureDescriptorDataInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->sampler = in->sampler; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkShaderModuleIdentifierEXT_win32_to_host(const VkShaderModuleIdentifierEXT32 *in, VkShaderModuleIdentifierEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkShaderModuleIdentifierEXT_host_to_win32(const VkShaderModuleIdentifierEXT *in, VkShaderModuleIdentifierEXT32 *out) -{ - if (!in) return; - - out->identifierSize = in->identifierSize; - memcpy(out->identifier, in->identifier, VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT * sizeof(uint8_t)); -} - -static inline void convert_VkInitializePerformanceApiInfoINTEL_win32_to_host(const VkInitializePerformanceApiInfoINTEL32 *in, VkInitializePerformanceApiInfoINTEL *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->pUserData = (void *)UlongToPtr(in->pUserData); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -#ifdef _WIN64 -static inline void convert_VkSparseMemoryBind_win64_to_host(const VkSparseMemoryBind *in, VkSparseMemoryBind *out) -{ - if (!in) return; - - out->resourceOffset = in->resourceOffset; - out->size = in->size; - out->memory = in->memory ? wine_device_memory_from_handle(in->memory)->memory : 0; - out->memoryOffset = in->memoryOffset; - out->flags = in->flags; -} -#endif /* _WIN64 */ - -static inline void convert_VkSparseMemoryBind_win32_to_host(const VkSparseMemoryBind32 *in, VkSparseMemoryBind *out) -{ - if (!in) return; - - out->resourceOffset = in->resourceOffset; - out->size = in->size; - out->memory = in->memory ? wine_device_memory_from_handle(in->memory)->memory : 0; - out->memoryOffset = in->memoryOffset; - out->flags = in->flags; -} - -#ifdef _WIN64 -static inline const VkSparseMemoryBind *convert_VkSparseMemoryBind_array_win64_to_host(struct conversion_context *ctx, const VkSparseMemoryBind *in, uint32_t count) -{ - VkSparseMemoryBind *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSparseMemoryBind_win64_to_host(&in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkSparseMemoryBind *convert_VkSparseMemoryBind_array_win32_to_host(struct conversion_context *ctx, const VkSparseMemoryBind32 *in, uint32_t count) -{ - VkSparseMemoryBind *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSparseMemoryBind_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -#ifdef _WIN64 -static inline void convert_VkSparseBufferMemoryBindInfo_win64_to_host(struct conversion_context *ctx, const VkSparseBufferMemoryBindInfo *in, VkSparseBufferMemoryBindInfo *out) -{ - if (!in) return; - - out->buffer = in->buffer; - out->bindCount = in->bindCount; - out->pBinds = convert_VkSparseMemoryBind_array_win64_to_host(ctx, in->pBinds, in->bindCount); -} -#endif /* _WIN64 */ - -static inline void convert_VkSparseBufferMemoryBindInfo_win32_to_host(struct conversion_context *ctx, const VkSparseBufferMemoryBindInfo32 *in, VkSparseBufferMemoryBindInfo *out) -{ - if (!in) return; - - out->buffer = in->buffer; - out->bindCount = in->bindCount; - out->pBinds = convert_VkSparseMemoryBind_array_win32_to_host(ctx, (const VkSparseMemoryBind32 *)UlongToPtr(in->pBinds), in->bindCount); -} - -#ifdef _WIN64 -static inline const VkSparseBufferMemoryBindInfo *convert_VkSparseBufferMemoryBindInfo_array_win64_to_host(struct conversion_context *ctx, const VkSparseBufferMemoryBindInfo *in, uint32_t count) -{ - VkSparseBufferMemoryBindInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSparseBufferMemoryBindInfo_win64_to_host(ctx, &in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkSparseBufferMemoryBindInfo *convert_VkSparseBufferMemoryBindInfo_array_win32_to_host(struct conversion_context *ctx, const VkSparseBufferMemoryBindInfo32 *in, uint32_t count) -{ - VkSparseBufferMemoryBindInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSparseBufferMemoryBindInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -#ifdef _WIN64 -static inline void convert_VkSparseImageOpaqueMemoryBindInfo_win64_to_host(struct conversion_context *ctx, const VkSparseImageOpaqueMemoryBindInfo *in, VkSparseImageOpaqueMemoryBindInfo *out) -{ - if (!in) return; - - out->image = in->image; - out->bindCount = in->bindCount; - out->pBinds = convert_VkSparseMemoryBind_array_win64_to_host(ctx, in->pBinds, in->bindCount); -} -#endif /* _WIN64 */ - -static inline void convert_VkSparseImageOpaqueMemoryBindInfo_win32_to_host(struct conversion_context *ctx, const VkSparseImageOpaqueMemoryBindInfo32 *in, VkSparseImageOpaqueMemoryBindInfo *out) -{ - if (!in) return; - - out->image = in->image; - out->bindCount = in->bindCount; - out->pBinds = convert_VkSparseMemoryBind_array_win32_to_host(ctx, (const VkSparseMemoryBind32 *)UlongToPtr(in->pBinds), in->bindCount); -} - -#ifdef _WIN64 -static inline const VkSparseImageOpaqueMemoryBindInfo *convert_VkSparseImageOpaqueMemoryBindInfo_array_win64_to_host(struct conversion_context *ctx, const VkSparseImageOpaqueMemoryBindInfo *in, uint32_t count) -{ - VkSparseImageOpaqueMemoryBindInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSparseImageOpaqueMemoryBindInfo_win64_to_host(ctx, &in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkSparseImageOpaqueMemoryBindInfo *convert_VkSparseImageOpaqueMemoryBindInfo_array_win32_to_host(struct conversion_context *ctx, const VkSparseImageOpaqueMemoryBindInfo32 *in, uint32_t count) -{ - VkSparseImageOpaqueMemoryBindInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSparseImageOpaqueMemoryBindInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -#ifdef _WIN64 -static inline void convert_VkSparseImageMemoryBind_win64_to_host(const VkSparseImageMemoryBind *in, VkSparseImageMemoryBind *out) -{ - if (!in) return; - - out->subresource = in->subresource; - out->offset = in->offset; - out->extent = in->extent; - out->memory = in->memory ? wine_device_memory_from_handle(in->memory)->memory : 0; - out->memoryOffset = in->memoryOffset; - out->flags = in->flags; -} -#endif /* _WIN64 */ - -static inline void convert_VkSparseImageMemoryBind_win32_to_host(const VkSparseImageMemoryBind32 *in, VkSparseImageMemoryBind *out) -{ - if (!in) return; - - out->subresource = in->subresource; - out->offset = in->offset; - out->extent = in->extent; - out->memory = in->memory ? wine_device_memory_from_handle(in->memory)->memory : 0; - out->memoryOffset = in->memoryOffset; - out->flags = in->flags; -} - -#ifdef _WIN64 -static inline const VkSparseImageMemoryBind *convert_VkSparseImageMemoryBind_array_win64_to_host(struct conversion_context *ctx, const VkSparseImageMemoryBind *in, uint32_t count) -{ - VkSparseImageMemoryBind *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSparseImageMemoryBind_win64_to_host(&in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkSparseImageMemoryBind *convert_VkSparseImageMemoryBind_array_win32_to_host(struct conversion_context *ctx, const VkSparseImageMemoryBind32 *in, uint32_t count) -{ - VkSparseImageMemoryBind *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSparseImageMemoryBind_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -#ifdef _WIN64 -static inline void convert_VkSparseImageMemoryBindInfo_win64_to_host(struct conversion_context *ctx, const VkSparseImageMemoryBindInfo *in, VkSparseImageMemoryBindInfo *out) -{ - if (!in) return; - - out->image = in->image; - out->bindCount = in->bindCount; - out->pBinds = convert_VkSparseImageMemoryBind_array_win64_to_host(ctx, in->pBinds, in->bindCount); -} -#endif /* _WIN64 */ - -static inline void convert_VkSparseImageMemoryBindInfo_win32_to_host(struct conversion_context *ctx, const VkSparseImageMemoryBindInfo32 *in, VkSparseImageMemoryBindInfo *out) -{ - if (!in) return; - - out->image = in->image; - out->bindCount = in->bindCount; - out->pBinds = convert_VkSparseImageMemoryBind_array_win32_to_host(ctx, (const VkSparseImageMemoryBind32 *)UlongToPtr(in->pBinds), in->bindCount); -} - -#ifdef _WIN64 -static inline const VkSparseImageMemoryBindInfo *convert_VkSparseImageMemoryBindInfo_array_win64_to_host(struct conversion_context *ctx, const VkSparseImageMemoryBindInfo *in, uint32_t count) -{ - VkSparseImageMemoryBindInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSparseImageMemoryBindInfo_win64_to_host(ctx, &in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkSparseImageMemoryBindInfo *convert_VkSparseImageMemoryBindInfo_array_win32_to_host(struct conversion_context *ctx, const VkSparseImageMemoryBindInfo32 *in, uint32_t count) -{ - VkSparseImageMemoryBindInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSparseImageMemoryBindInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -#ifdef _WIN64 -static inline void convert_VkBindSparseInfo_win64_to_host(struct conversion_context *ctx, const VkBindSparseInfo *in, VkBindSparseInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->waitSemaphoreCount = in->waitSemaphoreCount; - out->pWaitSemaphores = in->pWaitSemaphores; - out->bufferBindCount = in->bufferBindCount; - out->pBufferBinds = convert_VkSparseBufferMemoryBindInfo_array_win64_to_host(ctx, in->pBufferBinds, in->bufferBindCount); - out->imageOpaqueBindCount = in->imageOpaqueBindCount; - out->pImageOpaqueBinds = convert_VkSparseImageOpaqueMemoryBindInfo_array_win64_to_host(ctx, in->pImageOpaqueBinds, in->imageOpaqueBindCount); - out->imageBindCount = in->imageBindCount; - out->pImageBinds = convert_VkSparseImageMemoryBindInfo_array_win64_to_host(ctx, in->pImageBinds, in->imageBindCount); - out->signalSemaphoreCount = in->signalSemaphoreCount; - out->pSignalSemaphores = in->pSignalSemaphores; -} -#endif /* _WIN64 */ - -static inline void convert_VkBindSparseInfo_win32_to_host(struct conversion_context *ctx, const VkBindSparseInfo32 *in, VkBindSparseInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->waitSemaphoreCount = in->waitSemaphoreCount; - out->pWaitSemaphores = (const VkSemaphore *)UlongToPtr(in->pWaitSemaphores); - out->bufferBindCount = in->bufferBindCount; - out->pBufferBinds = convert_VkSparseBufferMemoryBindInfo_array_win32_to_host(ctx, (const VkSparseBufferMemoryBindInfo32 *)UlongToPtr(in->pBufferBinds), in->bufferBindCount); - out->imageOpaqueBindCount = in->imageOpaqueBindCount; - out->pImageOpaqueBinds = convert_VkSparseImageOpaqueMemoryBindInfo_array_win32_to_host(ctx, (const VkSparseImageOpaqueMemoryBindInfo32 *)UlongToPtr(in->pImageOpaqueBinds), in->imageOpaqueBindCount); - out->imageBindCount = in->imageBindCount; - out->pImageBinds = convert_VkSparseImageMemoryBindInfo_array_win32_to_host(ctx, (const VkSparseImageMemoryBindInfo32 *)UlongToPtr(in->pImageBinds), in->imageBindCount); - out->signalSemaphoreCount = in->signalSemaphoreCount; - out->pSignalSemaphores = (const VkSemaphore *)UlongToPtr(in->pSignalSemaphores); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO: - { - VkDeviceGroupBindSparseInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDeviceGroupBindSparseInfo32 *in_ext = (const VkDeviceGroupBindSparseInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO; - out_ext->pNext = NULL; - out_ext->resourceDeviceIndex = in_ext->resourceDeviceIndex; - out_ext->memoryDeviceIndex = in_ext->memoryDeviceIndex; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO: - { - VkTimelineSemaphoreSubmitInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkTimelineSemaphoreSubmitInfo32 *in_ext = (const VkTimelineSemaphoreSubmitInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; - out_ext->pNext = NULL; - out_ext->waitSemaphoreValueCount = in_ext->waitSemaphoreValueCount; - out_ext->pWaitSemaphoreValues = (const uint64_t *)UlongToPtr(in_ext->pWaitSemaphoreValues); - out_ext->signalSemaphoreValueCount = in_ext->signalSemaphoreValueCount; - out_ext->pSignalSemaphoreValues = (const uint64_t *)UlongToPtr(in_ext->pSignalSemaphoreValues); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -#ifdef _WIN64 -static inline const VkBindSparseInfo *convert_VkBindSparseInfo_array_win64_to_host(struct conversion_context *ctx, const VkBindSparseInfo *in, uint32_t count) -{ - VkBindSparseInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkBindSparseInfo_win64_to_host(ctx, &in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkBindSparseInfo *convert_VkBindSparseInfo_array_win32_to_host(struct conversion_context *ctx, const VkBindSparseInfo32 *in, uint32_t count) -{ - VkBindSparseInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkBindSparseInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPresentRegionKHR_win32_to_host(const VkPresentRegionKHR32 *in, VkPresentRegionKHR *out) -{ - if (!in) return; - - out->rectangleCount = in->rectangleCount; - out->pRectangles = (const VkRectLayerKHR *)UlongToPtr(in->pRectangles); -} - -static inline const VkPresentRegionKHR *convert_VkPresentRegionKHR_array_win32_to_host(struct conversion_context *ctx, const VkPresentRegionKHR32 *in, uint32_t count) -{ - VkPresentRegionKHR *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkPresentRegionKHR_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkPresentInfoKHR_win32_to_host(struct conversion_context *ctx, const VkPresentInfoKHR32 *in, VkPresentInfoKHR *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->waitSemaphoreCount = in->waitSemaphoreCount; - out->pWaitSemaphores = (const VkSemaphore *)UlongToPtr(in->pWaitSemaphores); - out->swapchainCount = in->swapchainCount; - out->pSwapchains = (const VkSwapchainKHR *)UlongToPtr(in->pSwapchains); - out->pImageIndices = (const uint32_t *)UlongToPtr(in->pImageIndices); - out->pResults = (VkResult *)UlongToPtr(in->pResults); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR: - { - VkPresentRegionsKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPresentRegionsKHR32 *in_ext = (const VkPresentRegionsKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR; - out_ext->pNext = NULL; - out_ext->swapchainCount = in_ext->swapchainCount; - out_ext->pRegions = convert_VkPresentRegionKHR_array_win32_to_host(ctx, (const VkPresentRegionKHR32 *)UlongToPtr(in_ext->pRegions), in_ext->swapchainCount); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR: - { - VkDeviceGroupPresentInfoKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDeviceGroupPresentInfoKHR32 *in_ext = (const VkDeviceGroupPresentInfoKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR; - out_ext->pNext = NULL; - out_ext->swapchainCount = in_ext->swapchainCount; - out_ext->pDeviceMasks = (const uint32_t *)UlongToPtr(in_ext->pDeviceMasks); - out_ext->mode = in_ext->mode; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PRESENT_ID_KHR: - { - VkPresentIdKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPresentIdKHR32 *in_ext = (const VkPresentIdKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PRESENT_ID_KHR; - out_ext->pNext = NULL; - out_ext->swapchainCount = in_ext->swapchainCount; - out_ext->pPresentIds = (const uint64_t *)UlongToPtr(in_ext->pPresentIds); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT: - { - VkSwapchainPresentFenceInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSwapchainPresentFenceInfoEXT32 *in_ext = (const VkSwapchainPresentFenceInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->swapchainCount = in_ext->swapchainCount; - out_ext->pFences = (const VkFence *)UlongToPtr(in_ext->pFences); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT: - { - VkSwapchainPresentModeInfoEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkSwapchainPresentModeInfoEXT32 *in_ext = (const VkSwapchainPresentModeInfoEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT; - out_ext->pNext = NULL; - out_ext->swapchainCount = in_ext->swapchainCount; - out_ext->pPresentModes = (const VkPresentModeKHR *)UlongToPtr(in_ext->pPresentModes); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -#ifdef _WIN64 -static inline void convert_VkSubmitInfo_win64_to_host(struct conversion_context *ctx, const VkSubmitInfo *in, VkSubmitInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->waitSemaphoreCount = in->waitSemaphoreCount; - out->pWaitSemaphores = in->pWaitSemaphores; - out->pWaitDstStageMask = in->pWaitDstStageMask; - out->commandBufferCount = in->commandBufferCount; - out->pCommandBuffers = convert_VkCommandBuffer_array_win64_to_host(ctx, in->pCommandBuffers, in->commandBufferCount); - out->signalSemaphoreCount = in->signalSemaphoreCount; - out->pSignalSemaphores = in->pSignalSemaphores; -} -#endif /* _WIN64 */ - -static inline void convert_VkSubmitInfo_win32_to_host(struct conversion_context *ctx, const VkSubmitInfo32 *in, VkSubmitInfo *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->waitSemaphoreCount = in->waitSemaphoreCount; - out->pWaitSemaphores = (const VkSemaphore *)UlongToPtr(in->pWaitSemaphores); - out->pWaitDstStageMask = (const VkPipelineStageFlags *)UlongToPtr(in->pWaitDstStageMask); - out->commandBufferCount = in->commandBufferCount; - out->pCommandBuffers = convert_VkCommandBuffer_array_win32_to_host(ctx, (const PTR32 *)UlongToPtr(in->pCommandBuffers), in->commandBufferCount); - out->signalSemaphoreCount = in->signalSemaphoreCount; - out->pSignalSemaphores = (const VkSemaphore *)UlongToPtr(in->pSignalSemaphores); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO: - { - VkDeviceGroupSubmitInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDeviceGroupSubmitInfo32 *in_ext = (const VkDeviceGroupSubmitInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO; - out_ext->pNext = NULL; - out_ext->waitSemaphoreCount = in_ext->waitSemaphoreCount; - out_ext->pWaitSemaphoreDeviceIndices = (const uint32_t *)UlongToPtr(in_ext->pWaitSemaphoreDeviceIndices); - out_ext->commandBufferCount = in_ext->commandBufferCount; - out_ext->pCommandBufferDeviceMasks = (const uint32_t *)UlongToPtr(in_ext->pCommandBufferDeviceMasks); - out_ext->signalSemaphoreCount = in_ext->signalSemaphoreCount; - out_ext->pSignalSemaphoreDeviceIndices = (const uint32_t *)UlongToPtr(in_ext->pSignalSemaphoreDeviceIndices); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO: - { - VkProtectedSubmitInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkProtectedSubmitInfo32 *in_ext = (const VkProtectedSubmitInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO; - out_ext->pNext = NULL; - out_ext->protectedSubmit = in_ext->protectedSubmit; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO: - { - VkTimelineSemaphoreSubmitInfo *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkTimelineSemaphoreSubmitInfo32 *in_ext = (const VkTimelineSemaphoreSubmitInfo32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; - out_ext->pNext = NULL; - out_ext->waitSemaphoreValueCount = in_ext->waitSemaphoreValueCount; - out_ext->pWaitSemaphoreValues = (const uint64_t *)UlongToPtr(in_ext->pWaitSemaphoreValues); - out_ext->signalSemaphoreValueCount = in_ext->signalSemaphoreValueCount; - out_ext->pSignalSemaphoreValues = (const uint64_t *)UlongToPtr(in_ext->pSignalSemaphoreValues); - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - case VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR: - { - VkPerformanceQuerySubmitInfoKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPerformanceQuerySubmitInfoKHR32 *in_ext = (const VkPerformanceQuerySubmitInfoKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR; - out_ext->pNext = NULL; - out_ext->counterPassIndex = in_ext->counterPassIndex; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -#ifdef _WIN64 -static inline const VkSubmitInfo *convert_VkSubmitInfo_array_win64_to_host(struct conversion_context *ctx, const VkSubmitInfo *in, uint32_t count) -{ - VkSubmitInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSubmitInfo_win64_to_host(ctx, &in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkSubmitInfo *convert_VkSubmitInfo_array_win32_to_host(struct conversion_context *ctx, const VkSubmitInfo32 *in, uint32_t count) -{ - VkSubmitInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSubmitInfo_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkSemaphoreSubmitInfo_win32_to_host(const VkSemaphoreSubmitInfo32 *in, VkSemaphoreSubmitInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->semaphore = in->semaphore; - out->value = in->value; - out->stageMask = in->stageMask; - out->deviceIndex = in->deviceIndex; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkSemaphoreSubmitInfo *convert_VkSemaphoreSubmitInfo_array_win32_to_host(struct conversion_context *ctx, const VkSemaphoreSubmitInfo32 *in, uint32_t count) -{ - VkSemaphoreSubmitInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSemaphoreSubmitInfo_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -#ifdef _WIN64 -static inline void convert_VkCommandBufferSubmitInfo_win64_to_host(const VkCommandBufferSubmitInfo *in, VkCommandBufferSubmitInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->commandBuffer = wine_cmd_buffer_from_handle(in->commandBuffer)->command_buffer; - out->deviceMask = in->deviceMask; -} -#endif /* _WIN64 */ - -static inline void convert_VkCommandBufferSubmitInfo_win32_to_host(const VkCommandBufferSubmitInfo32 *in, VkCommandBufferSubmitInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->commandBuffer = wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(in->commandBuffer))->command_buffer; - out->deviceMask = in->deviceMask; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -#ifdef _WIN64 -static inline const VkCommandBufferSubmitInfo *convert_VkCommandBufferSubmitInfo_array_win64_to_host(struct conversion_context *ctx, const VkCommandBufferSubmitInfo *in, uint32_t count) -{ - VkCommandBufferSubmitInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkCommandBufferSubmitInfo_win64_to_host(&in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkCommandBufferSubmitInfo *convert_VkCommandBufferSubmitInfo_array_win32_to_host(struct conversion_context *ctx, const VkCommandBufferSubmitInfo32 *in, uint32_t count) -{ - VkCommandBufferSubmitInfo *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkCommandBufferSubmitInfo_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -#ifdef _WIN64 -static inline void convert_VkSubmitInfo2_win64_to_host(struct conversion_context *ctx, const VkSubmitInfo2 *in, VkSubmitInfo2 *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->flags = in->flags; - out->waitSemaphoreInfoCount = in->waitSemaphoreInfoCount; - out->pWaitSemaphoreInfos = in->pWaitSemaphoreInfos; - out->commandBufferInfoCount = in->commandBufferInfoCount; - out->pCommandBufferInfos = convert_VkCommandBufferSubmitInfo_array_win64_to_host(ctx, in->pCommandBufferInfos, in->commandBufferInfoCount); - out->signalSemaphoreInfoCount = in->signalSemaphoreInfoCount; - out->pSignalSemaphoreInfos = in->pSignalSemaphoreInfos; -} -#endif /* _WIN64 */ - -static inline void convert_VkSubmitInfo2_win32_to_host(struct conversion_context *ctx, const VkSubmitInfo232 *in, VkSubmitInfo2 *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->waitSemaphoreInfoCount = in->waitSemaphoreInfoCount; - out->pWaitSemaphoreInfos = convert_VkSemaphoreSubmitInfo_array_win32_to_host(ctx, (const VkSemaphoreSubmitInfo32 *)UlongToPtr(in->pWaitSemaphoreInfos), in->waitSemaphoreInfoCount); - out->commandBufferInfoCount = in->commandBufferInfoCount; - out->pCommandBufferInfos = convert_VkCommandBufferSubmitInfo_array_win32_to_host(ctx, (const VkCommandBufferSubmitInfo32 *)UlongToPtr(in->pCommandBufferInfos), in->commandBufferInfoCount); - out->signalSemaphoreInfoCount = in->signalSemaphoreInfoCount; - out->pSignalSemaphoreInfos = convert_VkSemaphoreSubmitInfo_array_win32_to_host(ctx, (const VkSemaphoreSubmitInfo32 *)UlongToPtr(in->pSignalSemaphoreInfos), in->signalSemaphoreInfoCount); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR: - { - VkPerformanceQuerySubmitInfoKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkPerformanceQuerySubmitInfoKHR32 *in_ext = (const VkPerformanceQuerySubmitInfoKHR32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR; - out_ext->pNext = NULL; - out_ext->counterPassIndex = in_ext->counterPassIndex; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -#ifdef _WIN64 -static inline const VkSubmitInfo2 *convert_VkSubmitInfo2_array_win64_to_host(struct conversion_context *ctx, const VkSubmitInfo2 *in, uint32_t count) -{ - VkSubmitInfo2 *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSubmitInfo2_win64_to_host(ctx, &in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkSubmitInfo2 *convert_VkSubmitInfo2_array_win32_to_host(struct conversion_context *ctx, const VkSubmitInfo232 *in, uint32_t count) -{ - VkSubmitInfo2 *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkSubmitInfo2_win32_to_host(ctx, &in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkReleaseSwapchainImagesInfoEXT_win32_to_host(const VkReleaseSwapchainImagesInfoEXT32 *in, VkReleaseSwapchainImagesInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->swapchain = in->swapchain; - out->imageIndexCount = in->imageIndexCount; - out->pImageIndices = (const uint32_t *)UlongToPtr(in->pImageIndices); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -#ifdef _WIN64 -static inline void convert_VkDebugUtilsObjectNameInfoEXT_win64_to_host(const VkDebugUtilsObjectNameInfoEXT *in, VkDebugUtilsObjectNameInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->objectType = in->objectType; - out->objectHandle = wine_vk_unwrap_handle(in->objectType, in->objectHandle); - out->pObjectName = in->pObjectName; -} -#endif /* _WIN64 */ - -static inline void convert_VkDebugUtilsObjectNameInfoEXT_win32_to_host(const VkDebugUtilsObjectNameInfoEXT32 *in, VkDebugUtilsObjectNameInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->objectType = in->objectType; - out->objectHandle = wine_vk_unwrap_handle(in->objectType, in->objectHandle); - out->pObjectName = (const char *)UlongToPtr(in->pObjectName); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -#ifdef _WIN64 -static inline void convert_VkDebugUtilsObjectTagInfoEXT_win64_to_host(const VkDebugUtilsObjectTagInfoEXT *in, VkDebugUtilsObjectTagInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->objectType = in->objectType; - out->objectHandle = wine_vk_unwrap_handle(in->objectType, in->objectHandle); - out->tagName = in->tagName; - out->tagSize = in->tagSize; - out->pTag = in->pTag; -} -#endif /* _WIN64 */ - -static inline void convert_VkDebugUtilsObjectTagInfoEXT_win32_to_host(const VkDebugUtilsObjectTagInfoEXT32 *in, VkDebugUtilsObjectTagInfoEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->objectType = in->objectType; - out->objectHandle = wine_vk_unwrap_handle(in->objectType, in->objectHandle); - out->tagName = in->tagName; - out->tagSize = in->tagSize; - out->pTag = (const void *)UlongToPtr(in->pTag); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline void convert_VkSemaphoreSignalInfo_win32_to_host(const VkSemaphoreSignalInfo32 *in, VkSemaphoreSignalInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->semaphore = in->semaphore; - out->value = in->value; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkDebugUtilsLabelEXT *convert_VkDebugUtilsLabelEXT_array_win32_to_host(struct conversion_context *ctx, const VkDebugUtilsLabelEXT32 *in, uint32_t count) -{ - VkDebugUtilsLabelEXT *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkDebugUtilsLabelEXT_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -#ifdef _WIN64 -static inline const VkDebugUtilsObjectNameInfoEXT *convert_VkDebugUtilsObjectNameInfoEXT_array_win64_to_host(struct conversion_context *ctx, const VkDebugUtilsObjectNameInfoEXT *in, uint32_t count) -{ - VkDebugUtilsObjectNameInfoEXT *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkDebugUtilsObjectNameInfoEXT_win64_to_host(&in[i], &out[i]); - } - - return out; -} -#endif /* _WIN64 */ - -static inline const VkDebugUtilsObjectNameInfoEXT *convert_VkDebugUtilsObjectNameInfoEXT_array_win32_to_host(struct conversion_context *ctx, const VkDebugUtilsObjectNameInfoEXT32 *in, uint32_t count) -{ - VkDebugUtilsObjectNameInfoEXT *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkDebugUtilsObjectNameInfoEXT_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -#ifdef _WIN64 -static inline void convert_VkDebugUtilsMessengerCallbackDataEXT_win64_to_host(struct conversion_context *ctx, const VkDebugUtilsMessengerCallbackDataEXT *in, VkDebugUtilsMessengerCallbackDataEXT *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = in->pNext; - out->flags = in->flags; - out->pMessageIdName = in->pMessageIdName; - out->messageIdNumber = in->messageIdNumber; - out->pMessage = in->pMessage; - out->queueLabelCount = in->queueLabelCount; - out->pQueueLabels = in->pQueueLabels; - out->cmdBufLabelCount = in->cmdBufLabelCount; - out->pCmdBufLabels = in->pCmdBufLabels; - out->objectCount = in->objectCount; - out->pObjects = convert_VkDebugUtilsObjectNameInfoEXT_array_win64_to_host(ctx, in->pObjects, in->objectCount); -} -#endif /* _WIN64 */ - -static inline void convert_VkDebugUtilsMessengerCallbackDataEXT_win32_to_host(struct conversion_context *ctx, const VkDebugUtilsMessengerCallbackDataEXT32 *in, VkDebugUtilsMessengerCallbackDataEXT *out) -{ - const VkBaseInStructure32 *in_header; - VkBaseOutStructure *out_header = (void *)out; - - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->pMessageIdName = (const char *)UlongToPtr(in->pMessageIdName); - out->messageIdNumber = in->messageIdNumber; - out->pMessage = (const char *)UlongToPtr(in->pMessage); - out->queueLabelCount = in->queueLabelCount; - out->pQueueLabels = convert_VkDebugUtilsLabelEXT_array_win32_to_host(ctx, (const VkDebugUtilsLabelEXT32 *)UlongToPtr(in->pQueueLabels), in->queueLabelCount); - out->cmdBufLabelCount = in->cmdBufLabelCount; - out->pCmdBufLabels = convert_VkDebugUtilsLabelEXT_array_win32_to_host(ctx, (const VkDebugUtilsLabelEXT32 *)UlongToPtr(in->pCmdBufLabels), in->cmdBufLabelCount); - out->objectCount = in->objectCount; - out->pObjects = convert_VkDebugUtilsObjectNameInfoEXT_array_win32_to_host(ctx, (const VkDebugUtilsObjectNameInfoEXT32 *)UlongToPtr(in->pObjects), in->objectCount); - - for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext)) - { - switch (in_header->sType) - { - case VK_STRUCTURE_TYPE_DEVICE_ADDRESS_BINDING_CALLBACK_DATA_EXT: - { - VkDeviceAddressBindingCallbackDataEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext)); - const VkDeviceAddressBindingCallbackDataEXT32 *in_ext = (const VkDeviceAddressBindingCallbackDataEXT32 *)in_header; - out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_ADDRESS_BINDING_CALLBACK_DATA_EXT; - out_ext->pNext = NULL; - out_ext->flags = in_ext->flags; - out_ext->baseAddress = in_ext->baseAddress; - out_ext->size = in_ext->size; - out_ext->bindingType = in_ext->bindingType; - out_header->pNext = (void *)out_ext; - out_header = (void *)out_ext; - break; - } - default: - FIXME("Unhandled sType %u.", in_header->sType); - break; - } - } -} - -static inline void convert_VkCopyDescriptorSet_win32_to_host(const VkCopyDescriptorSet32 *in, VkCopyDescriptorSet *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->srcSet = in->srcSet; - out->srcBinding = in->srcBinding; - out->srcArrayElement = in->srcArrayElement; - out->dstSet = in->dstSet; - out->dstBinding = in->dstBinding; - out->dstArrayElement = in->dstArrayElement; - out->descriptorCount = in->descriptorCount; - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -static inline const VkCopyDescriptorSet *convert_VkCopyDescriptorSet_array_win32_to_host(struct conversion_context *ctx, const VkCopyDescriptorSet32 *in, uint32_t count) -{ - VkCopyDescriptorSet *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; i++) - { - convert_VkCopyDescriptorSet_win32_to_host(&in[i], &out[i]); - } - - return out; -} - -static inline void convert_VkSemaphoreWaitInfo_win32_to_host(const VkSemaphoreWaitInfo32 *in, VkSemaphoreWaitInfo *out) -{ - if (!in) return; - - out->sType = in->sType; - out->pNext = NULL; - out->flags = in->flags; - out->semaphoreCount = in->semaphoreCount; - out->pSemaphores = (const VkSemaphore *)UlongToPtr(in->pSemaphores); - out->pValues = (const uint64_t *)UlongToPtr(in->pValues); - if (in->pNext) - FIXME("Unexpected pNext\n"); -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkAcquireNextImage2KHR(void *args) -{ - struct vkAcquireNextImage2KHR_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pAcquireInfo, params->pImageIndex); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkAcquireNextImage2KHR(wine_device_from_handle(params->device)->device, params->pAcquireInfo, params->pImageIndex); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkAcquireNextImage2KHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pAcquireInfo; - PTR32 pImageIndex; - VkResult result; - } *params = args; - VkAcquireNextImageInfoKHR pAcquireInfo_host; - - TRACE("%#x, %#x, %#x\n", params->device, params->pAcquireInfo, params->pImageIndex); - - convert_VkAcquireNextImageInfoKHR_win32_to_host((const VkAcquireNextImageInfoKHR32 *)UlongToPtr(params->pAcquireInfo), &pAcquireInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkAcquireNextImage2KHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pAcquireInfo_host, (uint32_t *)UlongToPtr(params->pImageIndex)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkAcquireNextImageKHR(void *args) -{ - struct vkAcquireNextImageKHR_params *params = args; - - TRACE("%p, 0x%s, 0x%s, 0x%s, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->swapchain), wine_dbgstr_longlong(params->timeout), wine_dbgstr_longlong(params->semaphore), wine_dbgstr_longlong(params->fence), params->pImageIndex); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkAcquireNextImageKHR(wine_device_from_handle(params->device)->device, params->swapchain, params->timeout, params->semaphore, params->fence, params->pImageIndex); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkAcquireNextImageKHR(void *args) -{ - struct - { - PTR32 device; - VkSwapchainKHR DECLSPEC_ALIGN(8) swapchain; - uint64_t DECLSPEC_ALIGN(8) timeout; - VkSemaphore DECLSPEC_ALIGN(8) semaphore; - VkFence DECLSPEC_ALIGN(8) fence; - PTR32 pImageIndex; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, 0x%s, 0x%s, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->swapchain), wine_dbgstr_longlong(params->timeout), wine_dbgstr_longlong(params->semaphore), wine_dbgstr_longlong(params->fence), params->pImageIndex); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkAcquireNextImageKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->swapchain, params->timeout, params->semaphore, params->fence, (uint32_t *)UlongToPtr(params->pImageIndex)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkAcquirePerformanceConfigurationINTEL(void *args) -{ - struct vkAcquirePerformanceConfigurationINTEL_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pAcquireInfo, params->pConfiguration); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkAcquirePerformanceConfigurationINTEL(wine_device_from_handle(params->device)->device, params->pAcquireInfo, params->pConfiguration); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkAcquirePerformanceConfigurationINTEL(void *args) -{ - struct - { - PTR32 device; - PTR32 pAcquireInfo; - PTR32 pConfiguration; - VkResult result; - } *params = args; - VkPerformanceConfigurationAcquireInfoINTEL pAcquireInfo_host; - - TRACE("%#x, %#x, %#x\n", params->device, params->pAcquireInfo, params->pConfiguration); - - convert_VkPerformanceConfigurationAcquireInfoINTEL_win32_to_host((const VkPerformanceConfigurationAcquireInfoINTEL32 *)UlongToPtr(params->pAcquireInfo), &pAcquireInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkAcquirePerformanceConfigurationINTEL(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pAcquireInfo_host, (VkPerformanceConfigurationINTEL *)UlongToPtr(params->pConfiguration)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkAcquireProfilingLockKHR(void *args) -{ - struct vkAcquireProfilingLockKHR_params *params = args; - - TRACE("%p, %p\n", params->device, params->pInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkAcquireProfilingLockKHR(wine_device_from_handle(params->device)->device, params->pInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkAcquireProfilingLockKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - VkResult result; - } *params = args; - VkAcquireProfilingLockInfoKHR pInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pInfo); - - convert_VkAcquireProfilingLockInfoKHR_win32_to_host((const VkAcquireProfilingLockInfoKHR32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkAcquireProfilingLockKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkAllocateCommandBuffers(void *args) -{ - struct vkAllocateCommandBuffers_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pAllocateInfo, params->pCommandBuffers); - - params->result = wine_vkAllocateCommandBuffers(params->device, params->pAllocateInfo, params->pCommandBuffers); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkAllocateCommandBuffers(void *args) -{ - struct - { - PTR32 device; - PTR32 pAllocateInfo; - PTR32 pCommandBuffers; - VkResult result; - } *params = args; - VkCommandBufferAllocateInfo pAllocateInfo_host; - VkCommandBuffer *pCommandBuffers_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->device, params->pAllocateInfo, params->pCommandBuffers); - - init_conversion_context(&ctx); - convert_VkCommandBufferAllocateInfo_win32_to_unwrapped_host((const VkCommandBufferAllocateInfo32 *)UlongToPtr(params->pAllocateInfo), &pAllocateInfo_host); - pCommandBuffers_host = convert_VkCommandBuffer_array_win32_to_unwrapped_host(&ctx, (PTR32 *)UlongToPtr(params->pCommandBuffers), ((const VkCommandBufferAllocateInfo32 *)UlongToPtr(params->pAllocateInfo))->commandBufferCount); - params->result = wine_vkAllocateCommandBuffers((VkDevice)UlongToPtr(params->device), &pAllocateInfo_host, pCommandBuffers_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkAllocateDescriptorSets(void *args) -{ - struct vkAllocateDescriptorSets_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pAllocateInfo, params->pDescriptorSets); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkAllocateDescriptorSets(wine_device_from_handle(params->device)->device, params->pAllocateInfo, params->pDescriptorSets); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkAllocateDescriptorSets(void *args) -{ - struct - { - PTR32 device; - PTR32 pAllocateInfo; - PTR32 pDescriptorSets; - VkResult result; - } *params = args; - VkDescriptorSetAllocateInfo pAllocateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->device, params->pAllocateInfo, params->pDescriptorSets); - - init_conversion_context(&ctx); - convert_VkDescriptorSetAllocateInfo_win32_to_host(&ctx, (const VkDescriptorSetAllocateInfo32 *)UlongToPtr(params->pAllocateInfo), &pAllocateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkAllocateDescriptorSets(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pAllocateInfo_host, (VkDescriptorSet *)UlongToPtr(params->pDescriptorSets)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkAllocateMemory(void *args) -{ - struct vkAllocateMemory_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pAllocateInfo, params->pAllocator, params->pMemory); - - params->result = wine_vkAllocateMemory(params->device, params->pAllocateInfo, params->pAllocator, params->pMemory); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkAllocateMemory(void *args) -{ - struct - { - PTR32 device; - PTR32 pAllocateInfo; - PTR32 pAllocator; - PTR32 pMemory; - VkResult result; - } *params = args; - VkMemoryAllocateInfo pAllocateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pAllocateInfo, params->pAllocator, params->pMemory); - - init_conversion_context(&ctx); - convert_VkMemoryAllocateInfo_win32_to_host(&ctx, (const VkMemoryAllocateInfo32 *)UlongToPtr(params->pAllocateInfo), &pAllocateInfo_host); - params->result = wine_vkAllocateMemory((VkDevice)UlongToPtr(params->device), &pAllocateInfo_host, (const VkAllocationCallbacks *)UlongToPtr(params->pAllocator), (VkDeviceMemory *)UlongToPtr(params->pMemory)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkBeginCommandBuffer(void *args) -{ - struct vkBeginCommandBuffer_params *params = args; - - TRACE("%p, %p\n", params->commandBuffer, params->pBeginInfo); - - params->result = wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkBeginCommandBuffer(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pBeginInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkBeginCommandBuffer(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pBeginInfo; - VkResult result; - } *params = args; - VkCommandBufferBeginInfo pBeginInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x\n", params->commandBuffer, params->pBeginInfo); - - init_conversion_context(&ctx); - convert_VkCommandBufferBeginInfo_win32_to_host(&ctx, (const VkCommandBufferBeginInfo32 *)UlongToPtr(params->pBeginInfo), &pBeginInfo_host); - params->result = wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkBeginCommandBuffer(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pBeginInfo_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkBindAccelerationStructureMemoryNV(void *args) -{ - struct vkBindAccelerationStructureMemoryNV_params *params = args; - const VkBindAccelerationStructureMemoryInfoNV *pBindInfos_host; - struct conversion_context ctx; - - TRACE("%p, %u, %p\n", params->device, params->bindInfoCount, params->pBindInfos); - - init_conversion_context(&ctx); - pBindInfos_host = convert_VkBindAccelerationStructureMemoryInfoNV_array_win64_to_host(&ctx, params->pBindInfos, params->bindInfoCount); - params->result = wine_device_from_handle(params->device)->funcs.p_vkBindAccelerationStructureMemoryNV(wine_device_from_handle(params->device)->device, params->bindInfoCount, pBindInfos_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkBindAccelerationStructureMemoryNV(void *args) -{ - struct - { - PTR32 device; - uint32_t bindInfoCount; - PTR32 pBindInfos; - VkResult result; - } *params = args; - const VkBindAccelerationStructureMemoryInfoNV *pBindInfos_host; - struct conversion_context ctx; - - TRACE("%#x, %u, %#x\n", params->device, params->bindInfoCount, params->pBindInfos); - - init_conversion_context(&ctx); - pBindInfos_host = convert_VkBindAccelerationStructureMemoryInfoNV_array_win32_to_host(&ctx, (const VkBindAccelerationStructureMemoryInfoNV32 *)UlongToPtr(params->pBindInfos), params->bindInfoCount); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkBindAccelerationStructureMemoryNV(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->bindInfoCount, pBindInfos_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkBindBufferMemory(void *args) -{ - struct vkBindBufferMemory_params *params = args; - - TRACE("%p, 0x%s, 0x%s, 0x%s\n", params->device, wine_dbgstr_longlong(params->buffer), wine_dbgstr_longlong(params->memory), wine_dbgstr_longlong(params->memoryOffset)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkBindBufferMemory(wine_device_from_handle(params->device)->device, params->buffer, wine_device_memory_from_handle(params->memory)->memory, params->memoryOffset); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkBindBufferMemory(void *args) -{ - struct - { - PTR32 device; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - VkDeviceSize DECLSPEC_ALIGN(8) memoryOffset; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, 0x%s, 0x%s\n", params->device, wine_dbgstr_longlong(params->buffer), wine_dbgstr_longlong(params->memory), wine_dbgstr_longlong(params->memoryOffset)); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkBindBufferMemory(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->buffer, wine_device_memory_from_handle(params->memory)->memory, params->memoryOffset); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkBindBufferMemory2(void *args) -{ - struct vkBindBufferMemory2_params *params = args; - const VkBindBufferMemoryInfo *pBindInfos_host; - struct conversion_context ctx; - - TRACE("%p, %u, %p\n", params->device, params->bindInfoCount, params->pBindInfos); - - init_conversion_context(&ctx); - pBindInfos_host = convert_VkBindBufferMemoryInfo_array_win64_to_host(&ctx, params->pBindInfos, params->bindInfoCount); - params->result = wine_device_from_handle(params->device)->funcs.p_vkBindBufferMemory2(wine_device_from_handle(params->device)->device, params->bindInfoCount, pBindInfos_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkBindBufferMemory2(void *args) -{ - struct - { - PTR32 device; - uint32_t bindInfoCount; - PTR32 pBindInfos; - VkResult result; - } *params = args; - const VkBindBufferMemoryInfo *pBindInfos_host; - struct conversion_context ctx; - - TRACE("%#x, %u, %#x\n", params->device, params->bindInfoCount, params->pBindInfos); - - init_conversion_context(&ctx); - pBindInfos_host = convert_VkBindBufferMemoryInfo_array_win32_to_host(&ctx, (const VkBindBufferMemoryInfo32 *)UlongToPtr(params->pBindInfos), params->bindInfoCount); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkBindBufferMemory2(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->bindInfoCount, pBindInfos_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkBindBufferMemory2KHR(void *args) -{ - struct vkBindBufferMemory2KHR_params *params = args; - const VkBindBufferMemoryInfo *pBindInfos_host; - struct conversion_context ctx; - - TRACE("%p, %u, %p\n", params->device, params->bindInfoCount, params->pBindInfos); - - init_conversion_context(&ctx); - pBindInfos_host = convert_VkBindBufferMemoryInfo_array_win64_to_host(&ctx, params->pBindInfos, params->bindInfoCount); - params->result = wine_device_from_handle(params->device)->funcs.p_vkBindBufferMemory2KHR(wine_device_from_handle(params->device)->device, params->bindInfoCount, pBindInfos_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkBindBufferMemory2KHR(void *args) -{ - struct - { - PTR32 device; - uint32_t bindInfoCount; - PTR32 pBindInfos; - VkResult result; - } *params = args; - const VkBindBufferMemoryInfo *pBindInfos_host; - struct conversion_context ctx; - - TRACE("%#x, %u, %#x\n", params->device, params->bindInfoCount, params->pBindInfos); - - init_conversion_context(&ctx); - pBindInfos_host = convert_VkBindBufferMemoryInfo_array_win32_to_host(&ctx, (const VkBindBufferMemoryInfo32 *)UlongToPtr(params->pBindInfos), params->bindInfoCount); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkBindBufferMemory2KHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->bindInfoCount, pBindInfos_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkBindImageMemory(void *args) -{ - struct vkBindImageMemory_params *params = args; - - TRACE("%p, 0x%s, 0x%s, 0x%s\n", params->device, wine_dbgstr_longlong(params->image), wine_dbgstr_longlong(params->memory), wine_dbgstr_longlong(params->memoryOffset)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkBindImageMemory(wine_device_from_handle(params->device)->device, params->image, wine_device_memory_from_handle(params->memory)->memory, params->memoryOffset); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkBindImageMemory(void *args) -{ - struct - { - PTR32 device; - VkImage DECLSPEC_ALIGN(8) image; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - VkDeviceSize DECLSPEC_ALIGN(8) memoryOffset; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, 0x%s, 0x%s\n", params->device, wine_dbgstr_longlong(params->image), wine_dbgstr_longlong(params->memory), wine_dbgstr_longlong(params->memoryOffset)); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkBindImageMemory(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->image, wine_device_memory_from_handle(params->memory)->memory, params->memoryOffset); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkBindImageMemory2(void *args) -{ - struct vkBindImageMemory2_params *params = args; - const VkBindImageMemoryInfo *pBindInfos_host; - struct conversion_context ctx; - - TRACE("%p, %u, %p\n", params->device, params->bindInfoCount, params->pBindInfos); - - init_conversion_context(&ctx); - pBindInfos_host = convert_VkBindImageMemoryInfo_array_win64_to_host(&ctx, params->pBindInfos, params->bindInfoCount); - params->result = wine_device_from_handle(params->device)->funcs.p_vkBindImageMemory2(wine_device_from_handle(params->device)->device, params->bindInfoCount, pBindInfos_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkBindImageMemory2(void *args) -{ - struct - { - PTR32 device; - uint32_t bindInfoCount; - PTR32 pBindInfos; - VkResult result; - } *params = args; - const VkBindImageMemoryInfo *pBindInfos_host; - struct conversion_context ctx; - - TRACE("%#x, %u, %#x\n", params->device, params->bindInfoCount, params->pBindInfos); - - init_conversion_context(&ctx); - pBindInfos_host = convert_VkBindImageMemoryInfo_array_win32_to_host(&ctx, (const VkBindImageMemoryInfo32 *)UlongToPtr(params->pBindInfos), params->bindInfoCount); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkBindImageMemory2(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->bindInfoCount, pBindInfos_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkBindImageMemory2KHR(void *args) -{ - struct vkBindImageMemory2KHR_params *params = args; - const VkBindImageMemoryInfo *pBindInfos_host; - struct conversion_context ctx; - - TRACE("%p, %u, %p\n", params->device, params->bindInfoCount, params->pBindInfos); - - init_conversion_context(&ctx); - pBindInfos_host = convert_VkBindImageMemoryInfo_array_win64_to_host(&ctx, params->pBindInfos, params->bindInfoCount); - params->result = wine_device_from_handle(params->device)->funcs.p_vkBindImageMemory2KHR(wine_device_from_handle(params->device)->device, params->bindInfoCount, pBindInfos_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkBindImageMemory2KHR(void *args) -{ - struct - { - PTR32 device; - uint32_t bindInfoCount; - PTR32 pBindInfos; - VkResult result; - } *params = args; - const VkBindImageMemoryInfo *pBindInfos_host; - struct conversion_context ctx; - - TRACE("%#x, %u, %#x\n", params->device, params->bindInfoCount, params->pBindInfos); - - init_conversion_context(&ctx); - pBindInfos_host = convert_VkBindImageMemoryInfo_array_win32_to_host(&ctx, (const VkBindImageMemoryInfo32 *)UlongToPtr(params->pBindInfos), params->bindInfoCount); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkBindImageMemory2KHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->bindInfoCount, pBindInfos_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkBindOpticalFlowSessionImageNV(void *args) -{ - struct vkBindOpticalFlowSessionImageNV_params *params = args; - - TRACE("%p, 0x%s, %#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->session), params->bindingPoint, wine_dbgstr_longlong(params->view), params->layout); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkBindOpticalFlowSessionImageNV(wine_device_from_handle(params->device)->device, params->session, params->bindingPoint, params->view, params->layout); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkBindOpticalFlowSessionImageNV(void *args) -{ - struct - { - PTR32 device; - VkOpticalFlowSessionNV DECLSPEC_ALIGN(8) session; - VkOpticalFlowSessionBindingPointNV bindingPoint; - VkImageView DECLSPEC_ALIGN(8) view; - VkImageLayout layout; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->session), params->bindingPoint, wine_dbgstr_longlong(params->view), params->layout); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkBindOpticalFlowSessionImageNV(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->session, params->bindingPoint, params->view, params->layout); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkBuildAccelerationStructuresKHR(void *args) -{ - struct vkBuildAccelerationStructuresKHR_params *params = args; - - TRACE("%p, 0x%s, %u, %p, %p\n", params->device, wine_dbgstr_longlong(params->deferredOperation), params->infoCount, params->pInfos, params->ppBuildRangeInfos); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkBuildAccelerationStructuresKHR(wine_device_from_handle(params->device)->device, params->deferredOperation, params->infoCount, params->pInfos, params->ppBuildRangeInfos); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkBuildAccelerationStructuresKHR(void *args) -{ - struct - { - PTR32 device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - uint32_t infoCount; - PTR32 pInfos; - PTR32 ppBuildRangeInfos; - VkResult result; - } *params = args; - const VkAccelerationStructureBuildGeometryInfoKHR *pInfos_host; - struct conversion_context ctx; - - TRACE("%#x, 0x%s, %u, %#x, %#x\n", params->device, wine_dbgstr_longlong(params->deferredOperation), params->infoCount, params->pInfos, params->ppBuildRangeInfos); - - init_conversion_context(&ctx); - pInfos_host = convert_VkAccelerationStructureBuildGeometryInfoKHR_array_win32_to_host(&ctx, (const VkAccelerationStructureBuildGeometryInfoKHR32 *)UlongToPtr(params->pInfos), params->infoCount); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkBuildAccelerationStructuresKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->deferredOperation, params->infoCount, pInfos_host, (const VkAccelerationStructureBuildRangeInfoKHR * const*)UlongToPtr(params->ppBuildRangeInfos)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkBuildMicromapsEXT(void *args) -{ - struct vkBuildMicromapsEXT_params *params = args; - - TRACE("%p, 0x%s, %u, %p\n", params->device, wine_dbgstr_longlong(params->deferredOperation), params->infoCount, params->pInfos); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkBuildMicromapsEXT(wine_device_from_handle(params->device)->device, params->deferredOperation, params->infoCount, params->pInfos); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkBuildMicromapsEXT(void *args) -{ - struct - { - PTR32 device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - uint32_t infoCount; - PTR32 pInfos; - VkResult result; - } *params = args; - const VkMicromapBuildInfoEXT *pInfos_host; - struct conversion_context ctx; - - TRACE("%#x, 0x%s, %u, %#x\n", params->device, wine_dbgstr_longlong(params->deferredOperation), params->infoCount, params->pInfos); - - init_conversion_context(&ctx); - pInfos_host = convert_VkMicromapBuildInfoEXT_array_win32_to_host(&ctx, (const VkMicromapBuildInfoEXT32 *)UlongToPtr(params->pInfos), params->infoCount); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkBuildMicromapsEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->deferredOperation, params->infoCount, pInfos_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static void thunk64_vkCmdBeginConditionalRenderingEXT(void *args) -{ - struct vkCmdBeginConditionalRenderingEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBeginConditionalRenderingEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pConditionalRenderingBegin); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBeginConditionalRenderingEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pConditionalRenderingBegin; - } *params = args; - VkConditionalRenderingBeginInfoEXT pConditionalRenderingBegin_host; - - convert_VkConditionalRenderingBeginInfoEXT_win32_to_host((const VkConditionalRenderingBeginInfoEXT32 *)UlongToPtr(params->pConditionalRenderingBegin), &pConditionalRenderingBegin_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBeginConditionalRenderingEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pConditionalRenderingBegin_host); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBeginDebugUtilsLabelEXT(void *args) -{ - struct vkCmdBeginDebugUtilsLabelEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBeginDebugUtilsLabelEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pLabelInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBeginDebugUtilsLabelEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pLabelInfo; - } *params = args; - VkDebugUtilsLabelEXT pLabelInfo_host; - - convert_VkDebugUtilsLabelEXT_win32_to_host((const VkDebugUtilsLabelEXT32 *)UlongToPtr(params->pLabelInfo), &pLabelInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBeginDebugUtilsLabelEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pLabelInfo_host); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBeginQuery(void *args) -{ - struct vkCmdBeginQuery_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBeginQuery(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->queryPool, params->query, params->flags); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBeginQuery(void *args) -{ - struct - { - PTR32 commandBuffer; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t query; - VkQueryControlFlags flags; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBeginQuery(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->queryPool, params->query, params->flags); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBeginQueryIndexedEXT(void *args) -{ - struct vkCmdBeginQueryIndexedEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBeginQueryIndexedEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->queryPool, params->query, params->flags, params->index); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBeginQueryIndexedEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t query; - VkQueryControlFlags flags; - uint32_t index; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBeginQueryIndexedEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->queryPool, params->query, params->flags, params->index); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBeginRenderPass(void *args) -{ - struct vkCmdBeginRenderPass_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBeginRenderPass(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pRenderPassBegin, params->contents); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBeginRenderPass(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pRenderPassBegin; - VkSubpassContents contents; - } *params = args; - VkRenderPassBeginInfo pRenderPassBegin_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkRenderPassBeginInfo_win32_to_host(&ctx, (const VkRenderPassBeginInfo32 *)UlongToPtr(params->pRenderPassBegin), &pRenderPassBegin_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBeginRenderPass(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pRenderPassBegin_host, params->contents); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBeginRenderPass2(void *args) -{ - struct vkCmdBeginRenderPass2_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBeginRenderPass2(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pRenderPassBegin, params->pSubpassBeginInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBeginRenderPass2(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pRenderPassBegin; - PTR32 pSubpassBeginInfo; - } *params = args; - VkRenderPassBeginInfo pRenderPassBegin_host; - VkSubpassBeginInfo pSubpassBeginInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkRenderPassBeginInfo_win32_to_host(&ctx, (const VkRenderPassBeginInfo32 *)UlongToPtr(params->pRenderPassBegin), &pRenderPassBegin_host); - convert_VkSubpassBeginInfo_win32_to_host((const VkSubpassBeginInfo32 *)UlongToPtr(params->pSubpassBeginInfo), &pSubpassBeginInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBeginRenderPass2(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pRenderPassBegin_host, &pSubpassBeginInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBeginRenderPass2KHR(void *args) -{ - struct vkCmdBeginRenderPass2KHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBeginRenderPass2KHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pRenderPassBegin, params->pSubpassBeginInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBeginRenderPass2KHR(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pRenderPassBegin; - PTR32 pSubpassBeginInfo; - } *params = args; - VkRenderPassBeginInfo pRenderPassBegin_host; - VkSubpassBeginInfo pSubpassBeginInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkRenderPassBeginInfo_win32_to_host(&ctx, (const VkRenderPassBeginInfo32 *)UlongToPtr(params->pRenderPassBegin), &pRenderPassBegin_host); - convert_VkSubpassBeginInfo_win32_to_host((const VkSubpassBeginInfo32 *)UlongToPtr(params->pSubpassBeginInfo), &pSubpassBeginInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBeginRenderPass2KHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pRenderPassBegin_host, &pSubpassBeginInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBeginRendering(void *args) -{ - struct vkCmdBeginRendering_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBeginRendering(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pRenderingInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBeginRendering(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pRenderingInfo; - } *params = args; - VkRenderingInfo pRenderingInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkRenderingInfo_win32_to_host(&ctx, (const VkRenderingInfo32 *)UlongToPtr(params->pRenderingInfo), &pRenderingInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBeginRendering(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pRenderingInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBeginRenderingKHR(void *args) -{ - struct vkCmdBeginRenderingKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBeginRenderingKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pRenderingInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBeginRenderingKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pRenderingInfo; - } *params = args; - VkRenderingInfo pRenderingInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkRenderingInfo_win32_to_host(&ctx, (const VkRenderingInfo32 *)UlongToPtr(params->pRenderingInfo), &pRenderingInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBeginRenderingKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pRenderingInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBeginTransformFeedbackEXT(void *args) -{ - struct vkCmdBeginTransformFeedbackEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBeginTransformFeedbackEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->firstCounterBuffer, params->counterBufferCount, params->pCounterBuffers, params->pCounterBufferOffsets); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBeginTransformFeedbackEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t firstCounterBuffer; - uint32_t counterBufferCount; - PTR32 pCounterBuffers; - PTR32 pCounterBufferOffsets; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBeginTransformFeedbackEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->firstCounterBuffer, params->counterBufferCount, (const VkBuffer *)UlongToPtr(params->pCounterBuffers), (const VkDeviceSize *)UlongToPtr(params->pCounterBufferOffsets)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBindDescriptorBufferEmbeddedSamplersEXT(void *args) -{ - struct vkCmdBindDescriptorBufferEmbeddedSamplersEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBindDescriptorBufferEmbeddedSamplersEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pipelineBindPoint, params->layout, params->set); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBindDescriptorBufferEmbeddedSamplersEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkPipelineBindPoint pipelineBindPoint; - VkPipelineLayout DECLSPEC_ALIGN(8) layout; - uint32_t set; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBindDescriptorBufferEmbeddedSamplersEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->pipelineBindPoint, params->layout, params->set); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBindDescriptorBuffersEXT(void *args) -{ - struct vkCmdBindDescriptorBuffersEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBindDescriptorBuffersEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->bufferCount, params->pBindingInfos); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBindDescriptorBuffersEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t bufferCount; - PTR32 pBindingInfos; - } *params = args; - const VkDescriptorBufferBindingInfoEXT *pBindingInfos_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pBindingInfos_host = convert_VkDescriptorBufferBindingInfoEXT_array_win32_to_host(&ctx, (const VkDescriptorBufferBindingInfoEXT32 *)UlongToPtr(params->pBindingInfos), params->bufferCount); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBindDescriptorBuffersEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->bufferCount, pBindingInfos_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBindDescriptorSets(void *args) -{ - struct vkCmdBindDescriptorSets_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBindDescriptorSets(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pipelineBindPoint, params->layout, params->firstSet, params->descriptorSetCount, params->pDescriptorSets, params->dynamicOffsetCount, params->pDynamicOffsets); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBindDescriptorSets(void *args) -{ - struct - { - PTR32 commandBuffer; - VkPipelineBindPoint pipelineBindPoint; - VkPipelineLayout DECLSPEC_ALIGN(8) layout; - uint32_t firstSet; - uint32_t descriptorSetCount; - PTR32 pDescriptorSets; - uint32_t dynamicOffsetCount; - PTR32 pDynamicOffsets; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBindDescriptorSets(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->pipelineBindPoint, params->layout, params->firstSet, params->descriptorSetCount, (const VkDescriptorSet *)UlongToPtr(params->pDescriptorSets), params->dynamicOffsetCount, (const uint32_t *)UlongToPtr(params->pDynamicOffsets)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBindIndexBuffer(void *args) -{ - struct vkCmdBindIndexBuffer_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBindIndexBuffer(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->buffer, params->offset, params->indexType); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBindIndexBuffer(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkIndexType indexType; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBindIndexBuffer(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->buffer, params->offset, params->indexType); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBindInvocationMaskHUAWEI(void *args) -{ - struct vkCmdBindInvocationMaskHUAWEI_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBindInvocationMaskHUAWEI(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->imageView, params->imageLayout); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBindInvocationMaskHUAWEI(void *args) -{ - struct - { - PTR32 commandBuffer; - VkImageView DECLSPEC_ALIGN(8) imageView; - VkImageLayout imageLayout; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBindInvocationMaskHUAWEI(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->imageView, params->imageLayout); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBindPipeline(void *args) -{ - struct vkCmdBindPipeline_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBindPipeline(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pipelineBindPoint, params->pipeline); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBindPipeline(void *args) -{ - struct - { - PTR32 commandBuffer; - VkPipelineBindPoint pipelineBindPoint; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBindPipeline(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->pipelineBindPoint, params->pipeline); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBindPipelineShaderGroupNV(void *args) -{ - struct vkCmdBindPipelineShaderGroupNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBindPipelineShaderGroupNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pipelineBindPoint, params->pipeline, params->groupIndex); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBindPipelineShaderGroupNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkPipelineBindPoint pipelineBindPoint; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - uint32_t groupIndex; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBindPipelineShaderGroupNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->pipelineBindPoint, params->pipeline, params->groupIndex); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBindShadingRateImageNV(void *args) -{ - struct vkCmdBindShadingRateImageNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBindShadingRateImageNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->imageView, params->imageLayout); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBindShadingRateImageNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkImageView DECLSPEC_ALIGN(8) imageView; - VkImageLayout imageLayout; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBindShadingRateImageNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->imageView, params->imageLayout); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBindTransformFeedbackBuffersEXT(void *args) -{ - struct vkCmdBindTransformFeedbackBuffersEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBindTransformFeedbackBuffersEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->firstBinding, params->bindingCount, params->pBuffers, params->pOffsets, params->pSizes); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBindTransformFeedbackBuffersEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t firstBinding; - uint32_t bindingCount; - PTR32 pBuffers; - PTR32 pOffsets; - PTR32 pSizes; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBindTransformFeedbackBuffersEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->firstBinding, params->bindingCount, (const VkBuffer *)UlongToPtr(params->pBuffers), (const VkDeviceSize *)UlongToPtr(params->pOffsets), (const VkDeviceSize *)UlongToPtr(params->pSizes)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBindVertexBuffers(void *args) -{ - struct vkCmdBindVertexBuffers_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBindVertexBuffers(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->firstBinding, params->bindingCount, params->pBuffers, params->pOffsets); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBindVertexBuffers(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t firstBinding; - uint32_t bindingCount; - PTR32 pBuffers; - PTR32 pOffsets; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBindVertexBuffers(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->firstBinding, params->bindingCount, (const VkBuffer *)UlongToPtr(params->pBuffers), (const VkDeviceSize *)UlongToPtr(params->pOffsets)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBindVertexBuffers2(void *args) -{ - struct vkCmdBindVertexBuffers2_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBindVertexBuffers2(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->firstBinding, params->bindingCount, params->pBuffers, params->pOffsets, params->pSizes, params->pStrides); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBindVertexBuffers2(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t firstBinding; - uint32_t bindingCount; - PTR32 pBuffers; - PTR32 pOffsets; - PTR32 pSizes; - PTR32 pStrides; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBindVertexBuffers2(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->firstBinding, params->bindingCount, (const VkBuffer *)UlongToPtr(params->pBuffers), (const VkDeviceSize *)UlongToPtr(params->pOffsets), (const VkDeviceSize *)UlongToPtr(params->pSizes), (const VkDeviceSize *)UlongToPtr(params->pStrides)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBindVertexBuffers2EXT(void *args) -{ - struct vkCmdBindVertexBuffers2EXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBindVertexBuffers2EXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->firstBinding, params->bindingCount, params->pBuffers, params->pOffsets, params->pSizes, params->pStrides); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBindVertexBuffers2EXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t firstBinding; - uint32_t bindingCount; - PTR32 pBuffers; - PTR32 pOffsets; - PTR32 pSizes; - PTR32 pStrides; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBindVertexBuffers2EXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->firstBinding, params->bindingCount, (const VkBuffer *)UlongToPtr(params->pBuffers), (const VkDeviceSize *)UlongToPtr(params->pOffsets), (const VkDeviceSize *)UlongToPtr(params->pSizes), (const VkDeviceSize *)UlongToPtr(params->pStrides)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBlitImage(void *args) -{ - struct vkCmdBlitImage_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBlitImage(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->srcImage, params->srcImageLayout, params->dstImage, params->dstImageLayout, params->regionCount, params->pRegions, params->filter); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBlitImage(void *args) -{ - struct - { - PTR32 commandBuffer; - VkImage DECLSPEC_ALIGN(8) srcImage; - VkImageLayout srcImageLayout; - VkImage DECLSPEC_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - PTR32 pRegions; - VkFilter filter; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBlitImage(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->srcImage, params->srcImageLayout, params->dstImage, params->dstImageLayout, params->regionCount, (const VkImageBlit *)UlongToPtr(params->pRegions), params->filter); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBlitImage2(void *args) -{ - struct vkCmdBlitImage2_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBlitImage2(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pBlitImageInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBlitImage2(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pBlitImageInfo; - } *params = args; - VkBlitImageInfo2 pBlitImageInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkBlitImageInfo2_win32_to_host(&ctx, (const VkBlitImageInfo232 *)UlongToPtr(params->pBlitImageInfo), &pBlitImageInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBlitImage2(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pBlitImageInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBlitImage2KHR(void *args) -{ - struct vkCmdBlitImage2KHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBlitImage2KHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pBlitImageInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBlitImage2KHR(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pBlitImageInfo; - } *params = args; - VkBlitImageInfo2 pBlitImageInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkBlitImageInfo2_win32_to_host(&ctx, (const VkBlitImageInfo232 *)UlongToPtr(params->pBlitImageInfo), &pBlitImageInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBlitImage2KHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pBlitImageInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBuildAccelerationStructureNV(void *args) -{ - struct vkCmdBuildAccelerationStructureNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBuildAccelerationStructureNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pInfo, params->instanceData, params->instanceOffset, params->update, params->dst, params->src, params->scratch, params->scratchOffset); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBuildAccelerationStructureNV(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pInfo; - VkBuffer DECLSPEC_ALIGN(8) instanceData; - VkDeviceSize DECLSPEC_ALIGN(8) instanceOffset; - VkBool32 update; - VkAccelerationStructureNV DECLSPEC_ALIGN(8) dst; - VkAccelerationStructureNV DECLSPEC_ALIGN(8) src; - VkBuffer DECLSPEC_ALIGN(8) scratch; - VkDeviceSize DECLSPEC_ALIGN(8) scratchOffset; - } *params = args; - VkAccelerationStructureInfoNV pInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkAccelerationStructureInfoNV_win32_to_host(&ctx, (const VkAccelerationStructureInfoNV32 *)UlongToPtr(params->pInfo), &pInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBuildAccelerationStructureNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pInfo_host, params->instanceData, params->instanceOffset, params->update, params->dst, params->src, params->scratch, params->scratchOffset); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBuildAccelerationStructuresIndirectKHR(void *args) -{ - struct vkCmdBuildAccelerationStructuresIndirectKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBuildAccelerationStructuresIndirectKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->infoCount, params->pInfos, params->pIndirectDeviceAddresses, params->pIndirectStrides, params->ppMaxPrimitiveCounts); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBuildAccelerationStructuresIndirectKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t infoCount; - PTR32 pInfos; - PTR32 pIndirectDeviceAddresses; - PTR32 pIndirectStrides; - PTR32 ppMaxPrimitiveCounts; - } *params = args; - const VkAccelerationStructureBuildGeometryInfoKHR *pInfos_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pInfos_host = convert_VkAccelerationStructureBuildGeometryInfoKHR_array_win32_to_host(&ctx, (const VkAccelerationStructureBuildGeometryInfoKHR32 *)UlongToPtr(params->pInfos), params->infoCount); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBuildAccelerationStructuresIndirectKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->infoCount, pInfos_host, (const VkDeviceAddress *)UlongToPtr(params->pIndirectDeviceAddresses), (const uint32_t *)UlongToPtr(params->pIndirectStrides), (const uint32_t * const*)UlongToPtr(params->ppMaxPrimitiveCounts)); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBuildAccelerationStructuresKHR(void *args) -{ - struct vkCmdBuildAccelerationStructuresKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBuildAccelerationStructuresKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->infoCount, params->pInfos, params->ppBuildRangeInfos); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBuildAccelerationStructuresKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t infoCount; - PTR32 pInfos; - PTR32 ppBuildRangeInfos; - } *params = args; - const VkAccelerationStructureBuildGeometryInfoKHR *pInfos_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pInfos_host = convert_VkAccelerationStructureBuildGeometryInfoKHR_array_win32_to_host(&ctx, (const VkAccelerationStructureBuildGeometryInfoKHR32 *)UlongToPtr(params->pInfos), params->infoCount); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBuildAccelerationStructuresKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->infoCount, pInfos_host, (const VkAccelerationStructureBuildRangeInfoKHR * const*)UlongToPtr(params->ppBuildRangeInfos)); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdBuildMicromapsEXT(void *args) -{ - struct vkCmdBuildMicromapsEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdBuildMicromapsEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->infoCount, params->pInfos); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdBuildMicromapsEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t infoCount; - PTR32 pInfos; - } *params = args; - const VkMicromapBuildInfoEXT *pInfos_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pInfos_host = convert_VkMicromapBuildInfoEXT_array_win32_to_host(&ctx, (const VkMicromapBuildInfoEXT32 *)UlongToPtr(params->pInfos), params->infoCount); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdBuildMicromapsEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->infoCount, pInfos_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdClearAttachments(void *args) -{ - struct vkCmdClearAttachments_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdClearAttachments(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->attachmentCount, params->pAttachments, params->rectCount, params->pRects); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdClearAttachments(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t attachmentCount; - PTR32 pAttachments; - uint32_t rectCount; - PTR32 pRects; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdClearAttachments(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->attachmentCount, (const VkClearAttachment *)UlongToPtr(params->pAttachments), params->rectCount, (const VkClearRect *)UlongToPtr(params->pRects)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdClearColorImage(void *args) -{ - struct vkCmdClearColorImage_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdClearColorImage(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->image, params->imageLayout, params->pColor, params->rangeCount, params->pRanges); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdClearColorImage(void *args) -{ - struct - { - PTR32 commandBuffer; - VkImage DECLSPEC_ALIGN(8) image; - VkImageLayout imageLayout; - PTR32 pColor; - uint32_t rangeCount; - PTR32 pRanges; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdClearColorImage(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->image, params->imageLayout, (const VkClearColorValue *)UlongToPtr(params->pColor), params->rangeCount, (const VkImageSubresourceRange *)UlongToPtr(params->pRanges)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdClearDepthStencilImage(void *args) -{ - struct vkCmdClearDepthStencilImage_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdClearDepthStencilImage(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->image, params->imageLayout, params->pDepthStencil, params->rangeCount, params->pRanges); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdClearDepthStencilImage(void *args) -{ - struct - { - PTR32 commandBuffer; - VkImage DECLSPEC_ALIGN(8) image; - VkImageLayout imageLayout; - PTR32 pDepthStencil; - uint32_t rangeCount; - PTR32 pRanges; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdClearDepthStencilImage(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->image, params->imageLayout, (const VkClearDepthStencilValue *)UlongToPtr(params->pDepthStencil), params->rangeCount, (const VkImageSubresourceRange *)UlongToPtr(params->pRanges)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyAccelerationStructureKHR(void *args) -{ - struct vkCmdCopyAccelerationStructureKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyAccelerationStructureKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyAccelerationStructureKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pInfo; - } *params = args; - VkCopyAccelerationStructureInfoKHR pInfo_host; - - convert_VkCopyAccelerationStructureInfoKHR_win32_to_host((const VkCopyAccelerationStructureInfoKHR32 *)UlongToPtr(params->pInfo), &pInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyAccelerationStructureKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pInfo_host); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyAccelerationStructureNV(void *args) -{ - struct vkCmdCopyAccelerationStructureNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyAccelerationStructureNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->dst, params->src, params->mode); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyAccelerationStructureNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkAccelerationStructureNV DECLSPEC_ALIGN(8) dst; - VkAccelerationStructureNV DECLSPEC_ALIGN(8) src; - VkCopyAccelerationStructureModeKHR mode; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyAccelerationStructureNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->dst, params->src, params->mode); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyAccelerationStructureToMemoryKHR(void *args) -{ - struct vkCmdCopyAccelerationStructureToMemoryKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyAccelerationStructureToMemoryKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyAccelerationStructureToMemoryKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pInfo; - } *params = args; - VkCopyAccelerationStructureToMemoryInfoKHR pInfo_host; - - convert_VkCopyAccelerationStructureToMemoryInfoKHR_win32_to_host((const VkCopyAccelerationStructureToMemoryInfoKHR32 *)UlongToPtr(params->pInfo), &pInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyAccelerationStructureToMemoryKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pInfo_host); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyBuffer(void *args) -{ - struct vkCmdCopyBuffer_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyBuffer(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->srcBuffer, params->dstBuffer, params->regionCount, params->pRegions); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyBuffer(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) srcBuffer; - VkBuffer DECLSPEC_ALIGN(8) dstBuffer; - uint32_t regionCount; - PTR32 pRegions; - } *params = args; - const VkBufferCopy *pRegions_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pRegions_host = convert_VkBufferCopy_array_win32_to_host(&ctx, (const VkBufferCopy32 *)UlongToPtr(params->pRegions), params->regionCount); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyBuffer(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->srcBuffer, params->dstBuffer, params->regionCount, pRegions_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyBuffer2(void *args) -{ - struct vkCmdCopyBuffer2_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyBuffer2(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pCopyBufferInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyBuffer2(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pCopyBufferInfo; - } *params = args; - VkCopyBufferInfo2 pCopyBufferInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkCopyBufferInfo2_win32_to_host(&ctx, (const VkCopyBufferInfo232 *)UlongToPtr(params->pCopyBufferInfo), &pCopyBufferInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyBuffer2(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pCopyBufferInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyBuffer2KHR(void *args) -{ - struct vkCmdCopyBuffer2KHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyBuffer2KHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pCopyBufferInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyBuffer2KHR(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pCopyBufferInfo; - } *params = args; - VkCopyBufferInfo2 pCopyBufferInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkCopyBufferInfo2_win32_to_host(&ctx, (const VkCopyBufferInfo232 *)UlongToPtr(params->pCopyBufferInfo), &pCopyBufferInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyBuffer2KHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pCopyBufferInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyBufferToImage(void *args) -{ - struct vkCmdCopyBufferToImage_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyBufferToImage(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->srcBuffer, params->dstImage, params->dstImageLayout, params->regionCount, params->pRegions); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyBufferToImage(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) srcBuffer; - VkImage DECLSPEC_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - PTR32 pRegions; - } *params = args; - const VkBufferImageCopy *pRegions_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pRegions_host = convert_VkBufferImageCopy_array_win32_to_host(&ctx, (const VkBufferImageCopy32 *)UlongToPtr(params->pRegions), params->regionCount); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyBufferToImage(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->srcBuffer, params->dstImage, params->dstImageLayout, params->regionCount, pRegions_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyBufferToImage2(void *args) -{ - struct vkCmdCopyBufferToImage2_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyBufferToImage2(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pCopyBufferToImageInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyBufferToImage2(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pCopyBufferToImageInfo; - } *params = args; - VkCopyBufferToImageInfo2 pCopyBufferToImageInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkCopyBufferToImageInfo2_win32_to_host(&ctx, (const VkCopyBufferToImageInfo232 *)UlongToPtr(params->pCopyBufferToImageInfo), &pCopyBufferToImageInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyBufferToImage2(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pCopyBufferToImageInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyBufferToImage2KHR(void *args) -{ - struct vkCmdCopyBufferToImage2KHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyBufferToImage2KHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pCopyBufferToImageInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyBufferToImage2KHR(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pCopyBufferToImageInfo; - } *params = args; - VkCopyBufferToImageInfo2 pCopyBufferToImageInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkCopyBufferToImageInfo2_win32_to_host(&ctx, (const VkCopyBufferToImageInfo232 *)UlongToPtr(params->pCopyBufferToImageInfo), &pCopyBufferToImageInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyBufferToImage2KHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pCopyBufferToImageInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyImage(void *args) -{ - struct vkCmdCopyImage_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyImage(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->srcImage, params->srcImageLayout, params->dstImage, params->dstImageLayout, params->regionCount, params->pRegions); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyImage(void *args) -{ - struct - { - PTR32 commandBuffer; - VkImage DECLSPEC_ALIGN(8) srcImage; - VkImageLayout srcImageLayout; - VkImage DECLSPEC_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - PTR32 pRegions; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyImage(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->srcImage, params->srcImageLayout, params->dstImage, params->dstImageLayout, params->regionCount, (const VkImageCopy *)UlongToPtr(params->pRegions)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyImage2(void *args) -{ - struct vkCmdCopyImage2_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyImage2(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pCopyImageInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyImage2(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pCopyImageInfo; - } *params = args; - VkCopyImageInfo2 pCopyImageInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkCopyImageInfo2_win32_to_host(&ctx, (const VkCopyImageInfo232 *)UlongToPtr(params->pCopyImageInfo), &pCopyImageInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyImage2(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pCopyImageInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyImage2KHR(void *args) -{ - struct vkCmdCopyImage2KHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyImage2KHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pCopyImageInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyImage2KHR(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pCopyImageInfo; - } *params = args; - VkCopyImageInfo2 pCopyImageInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkCopyImageInfo2_win32_to_host(&ctx, (const VkCopyImageInfo232 *)UlongToPtr(params->pCopyImageInfo), &pCopyImageInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyImage2KHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pCopyImageInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyImageToBuffer(void *args) -{ - struct vkCmdCopyImageToBuffer_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyImageToBuffer(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->srcImage, params->srcImageLayout, params->dstBuffer, params->regionCount, params->pRegions); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyImageToBuffer(void *args) -{ - struct - { - PTR32 commandBuffer; - VkImage DECLSPEC_ALIGN(8) srcImage; - VkImageLayout srcImageLayout; - VkBuffer DECLSPEC_ALIGN(8) dstBuffer; - uint32_t regionCount; - PTR32 pRegions; - } *params = args; - const VkBufferImageCopy *pRegions_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pRegions_host = convert_VkBufferImageCopy_array_win32_to_host(&ctx, (const VkBufferImageCopy32 *)UlongToPtr(params->pRegions), params->regionCount); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyImageToBuffer(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->srcImage, params->srcImageLayout, params->dstBuffer, params->regionCount, pRegions_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyImageToBuffer2(void *args) -{ - struct vkCmdCopyImageToBuffer2_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyImageToBuffer2(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pCopyImageToBufferInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyImageToBuffer2(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pCopyImageToBufferInfo; - } *params = args; - VkCopyImageToBufferInfo2 pCopyImageToBufferInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkCopyImageToBufferInfo2_win32_to_host(&ctx, (const VkCopyImageToBufferInfo232 *)UlongToPtr(params->pCopyImageToBufferInfo), &pCopyImageToBufferInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyImageToBuffer2(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pCopyImageToBufferInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyImageToBuffer2KHR(void *args) -{ - struct vkCmdCopyImageToBuffer2KHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyImageToBuffer2KHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pCopyImageToBufferInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyImageToBuffer2KHR(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pCopyImageToBufferInfo; - } *params = args; - VkCopyImageToBufferInfo2 pCopyImageToBufferInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkCopyImageToBufferInfo2_win32_to_host(&ctx, (const VkCopyImageToBufferInfo232 *)UlongToPtr(params->pCopyImageToBufferInfo), &pCopyImageToBufferInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyImageToBuffer2KHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pCopyImageToBufferInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyMemoryIndirectNV(void *args) -{ - struct vkCmdCopyMemoryIndirectNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyMemoryIndirectNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->copyBufferAddress, params->copyCount, params->stride); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyMemoryIndirectNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkDeviceAddress DECLSPEC_ALIGN(8) copyBufferAddress; - uint32_t copyCount; - uint32_t stride; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyMemoryIndirectNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->copyBufferAddress, params->copyCount, params->stride); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyMemoryToAccelerationStructureKHR(void *args) -{ - struct vkCmdCopyMemoryToAccelerationStructureKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyMemoryToAccelerationStructureKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyMemoryToAccelerationStructureKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pInfo; - } *params = args; - VkCopyMemoryToAccelerationStructureInfoKHR pInfo_host; - - convert_VkCopyMemoryToAccelerationStructureInfoKHR_win32_to_host((const VkCopyMemoryToAccelerationStructureInfoKHR32 *)UlongToPtr(params->pInfo), &pInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyMemoryToAccelerationStructureKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pInfo_host); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyMemoryToImageIndirectNV(void *args) -{ - struct vkCmdCopyMemoryToImageIndirectNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyMemoryToImageIndirectNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->copyBufferAddress, params->copyCount, params->stride, params->dstImage, params->dstImageLayout, params->pImageSubresources); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyMemoryToImageIndirectNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkDeviceAddress DECLSPEC_ALIGN(8) copyBufferAddress; - uint32_t copyCount; - uint32_t stride; - VkImage DECLSPEC_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - PTR32 pImageSubresources; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyMemoryToImageIndirectNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->copyBufferAddress, params->copyCount, params->stride, params->dstImage, params->dstImageLayout, (const VkImageSubresourceLayers *)UlongToPtr(params->pImageSubresources)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyMemoryToMicromapEXT(void *args) -{ - struct vkCmdCopyMemoryToMicromapEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyMemoryToMicromapEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyMemoryToMicromapEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pInfo; - } *params = args; - VkCopyMemoryToMicromapInfoEXT pInfo_host; - - convert_VkCopyMemoryToMicromapInfoEXT_win32_to_host((const VkCopyMemoryToMicromapInfoEXT32 *)UlongToPtr(params->pInfo), &pInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyMemoryToMicromapEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pInfo_host); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyMicromapEXT(void *args) -{ - struct vkCmdCopyMicromapEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyMicromapEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyMicromapEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pInfo; - } *params = args; - VkCopyMicromapInfoEXT pInfo_host; - - convert_VkCopyMicromapInfoEXT_win32_to_host((const VkCopyMicromapInfoEXT32 *)UlongToPtr(params->pInfo), &pInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyMicromapEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pInfo_host); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyMicromapToMemoryEXT(void *args) -{ - struct vkCmdCopyMicromapToMemoryEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyMicromapToMemoryEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyMicromapToMemoryEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pInfo; - } *params = args; - VkCopyMicromapToMemoryInfoEXT pInfo_host; - - convert_VkCopyMicromapToMemoryInfoEXT_win32_to_host((const VkCopyMicromapToMemoryInfoEXT32 *)UlongToPtr(params->pInfo), &pInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyMicromapToMemoryEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pInfo_host); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCopyQueryPoolResults(void *args) -{ - struct vkCmdCopyQueryPoolResults_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCopyQueryPoolResults(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->queryPool, params->firstQuery, params->queryCount, params->dstBuffer, params->dstOffset, params->stride, params->flags); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCopyQueryPoolResults(void *args) -{ - struct - { - PTR32 commandBuffer; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t firstQuery; - uint32_t queryCount; - VkBuffer DECLSPEC_ALIGN(8) dstBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) dstOffset; - VkDeviceSize DECLSPEC_ALIGN(8) stride; - VkQueryResultFlags flags; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCopyQueryPoolResults(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->queryPool, params->firstQuery, params->queryCount, params->dstBuffer, params->dstOffset, params->stride, params->flags); -} - -#ifdef _WIN64 -static void thunk64_vkCmdCuLaunchKernelNVX(void *args) -{ - struct vkCmdCuLaunchKernelNVX_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdCuLaunchKernelNVX(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pLaunchInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdCuLaunchKernelNVX(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pLaunchInfo; - } *params = args; - VkCuLaunchInfoNVX pLaunchInfo_host; - - convert_VkCuLaunchInfoNVX_win32_to_host((const VkCuLaunchInfoNVX32 *)UlongToPtr(params->pLaunchInfo), &pLaunchInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdCuLaunchKernelNVX(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pLaunchInfo_host); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDebugMarkerBeginEXT(void *args) -{ - struct vkCmdDebugMarkerBeginEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDebugMarkerBeginEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pMarkerInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDebugMarkerBeginEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pMarkerInfo; - } *params = args; - VkDebugMarkerMarkerInfoEXT pMarkerInfo_host; - - convert_VkDebugMarkerMarkerInfoEXT_win32_to_host((const VkDebugMarkerMarkerInfoEXT32 *)UlongToPtr(params->pMarkerInfo), &pMarkerInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDebugMarkerBeginEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pMarkerInfo_host); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDebugMarkerEndEXT(void *args) -{ - struct vkCmdDebugMarkerEndEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDebugMarkerEndEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDebugMarkerEndEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDebugMarkerEndEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDebugMarkerInsertEXT(void *args) -{ - struct vkCmdDebugMarkerInsertEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDebugMarkerInsertEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pMarkerInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDebugMarkerInsertEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pMarkerInfo; - } *params = args; - VkDebugMarkerMarkerInfoEXT pMarkerInfo_host; - - convert_VkDebugMarkerMarkerInfoEXT_win32_to_host((const VkDebugMarkerMarkerInfoEXT32 *)UlongToPtr(params->pMarkerInfo), &pMarkerInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDebugMarkerInsertEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pMarkerInfo_host); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDecompressMemoryIndirectCountNV(void *args) -{ - struct vkCmdDecompressMemoryIndirectCountNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDecompressMemoryIndirectCountNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->indirectCommandsAddress, params->indirectCommandsCountAddress, params->stride); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDecompressMemoryIndirectCountNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkDeviceAddress DECLSPEC_ALIGN(8) indirectCommandsAddress; - VkDeviceAddress DECLSPEC_ALIGN(8) indirectCommandsCountAddress; - uint32_t stride; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDecompressMemoryIndirectCountNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->indirectCommandsAddress, params->indirectCommandsCountAddress, params->stride); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDecompressMemoryNV(void *args) -{ - struct vkCmdDecompressMemoryNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDecompressMemoryNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->decompressRegionCount, params->pDecompressMemoryRegions); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDecompressMemoryNV(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t decompressRegionCount; - PTR32 pDecompressMemoryRegions; - } *params = args; - const VkDecompressMemoryRegionNV *pDecompressMemoryRegions_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pDecompressMemoryRegions_host = convert_VkDecompressMemoryRegionNV_array_win32_to_host(&ctx, (const VkDecompressMemoryRegionNV32 *)UlongToPtr(params->pDecompressMemoryRegions), params->decompressRegionCount); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDecompressMemoryNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->decompressRegionCount, pDecompressMemoryRegions_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDispatch(void *args) -{ - struct vkCmdDispatch_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDispatch(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->groupCountX, params->groupCountY, params->groupCountZ); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDispatch(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t groupCountX; - uint32_t groupCountY; - uint32_t groupCountZ; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDispatch(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->groupCountX, params->groupCountY, params->groupCountZ); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDispatchBase(void *args) -{ - struct vkCmdDispatchBase_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDispatchBase(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->baseGroupX, params->baseGroupY, params->baseGroupZ, params->groupCountX, params->groupCountY, params->groupCountZ); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDispatchBase(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t baseGroupX; - uint32_t baseGroupY; - uint32_t baseGroupZ; - uint32_t groupCountX; - uint32_t groupCountY; - uint32_t groupCountZ; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDispatchBase(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->baseGroupX, params->baseGroupY, params->baseGroupZ, params->groupCountX, params->groupCountY, params->groupCountZ); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDispatchBaseKHR(void *args) -{ - struct vkCmdDispatchBaseKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDispatchBaseKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->baseGroupX, params->baseGroupY, params->baseGroupZ, params->groupCountX, params->groupCountY, params->groupCountZ); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDispatchBaseKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t baseGroupX; - uint32_t baseGroupY; - uint32_t baseGroupZ; - uint32_t groupCountX; - uint32_t groupCountY; - uint32_t groupCountZ; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDispatchBaseKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->baseGroupX, params->baseGroupY, params->baseGroupZ, params->groupCountX, params->groupCountY, params->groupCountZ); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDispatchIndirect(void *args) -{ - struct vkCmdDispatchIndirect_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDispatchIndirect(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->buffer, params->offset); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDispatchIndirect(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDispatchIndirect(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->buffer, params->offset); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDraw(void *args) -{ - struct vkCmdDraw_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDraw(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->vertexCount, params->instanceCount, params->firstVertex, params->firstInstance); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDraw(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t vertexCount; - uint32_t instanceCount; - uint32_t firstVertex; - uint32_t firstInstance; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDraw(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->vertexCount, params->instanceCount, params->firstVertex, params->firstInstance); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawIndexed(void *args) -{ - struct vkCmdDrawIndexed_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawIndexed(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->indexCount, params->instanceCount, params->firstIndex, params->vertexOffset, params->firstInstance); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawIndexed(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t indexCount; - uint32_t instanceCount; - uint32_t firstIndex; - int32_t vertexOffset; - uint32_t firstInstance; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawIndexed(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->indexCount, params->instanceCount, params->firstIndex, params->vertexOffset, params->firstInstance); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawIndexedIndirect(void *args) -{ - struct vkCmdDrawIndexedIndirect_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawIndexedIndirect(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->buffer, params->offset, params->drawCount, params->stride); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawIndexedIndirect(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - uint32_t drawCount; - uint32_t stride; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawIndexedIndirect(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->buffer, params->offset, params->drawCount, params->stride); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawIndexedIndirectCount(void *args) -{ - struct vkCmdDrawIndexedIndirectCount_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawIndexedIndirectCount(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->buffer, params->offset, params->countBuffer, params->countBufferOffset, params->maxDrawCount, params->stride); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawIndexedIndirectCount(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkBuffer DECLSPEC_ALIGN(8) countBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) countBufferOffset; - uint32_t maxDrawCount; - uint32_t stride; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawIndexedIndirectCount(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->buffer, params->offset, params->countBuffer, params->countBufferOffset, params->maxDrawCount, params->stride); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawIndexedIndirectCountAMD(void *args) -{ - struct vkCmdDrawIndexedIndirectCountAMD_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawIndexedIndirectCountAMD(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->buffer, params->offset, params->countBuffer, params->countBufferOffset, params->maxDrawCount, params->stride); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawIndexedIndirectCountAMD(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkBuffer DECLSPEC_ALIGN(8) countBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) countBufferOffset; - uint32_t maxDrawCount; - uint32_t stride; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawIndexedIndirectCountAMD(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->buffer, params->offset, params->countBuffer, params->countBufferOffset, params->maxDrawCount, params->stride); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawIndexedIndirectCountKHR(void *args) -{ - struct vkCmdDrawIndexedIndirectCountKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawIndexedIndirectCountKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->buffer, params->offset, params->countBuffer, params->countBufferOffset, params->maxDrawCount, params->stride); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawIndexedIndirectCountKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkBuffer DECLSPEC_ALIGN(8) countBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) countBufferOffset; - uint32_t maxDrawCount; - uint32_t stride; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawIndexedIndirectCountKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->buffer, params->offset, params->countBuffer, params->countBufferOffset, params->maxDrawCount, params->stride); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawIndirect(void *args) -{ - struct vkCmdDrawIndirect_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawIndirect(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->buffer, params->offset, params->drawCount, params->stride); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawIndirect(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - uint32_t drawCount; - uint32_t stride; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawIndirect(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->buffer, params->offset, params->drawCount, params->stride); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawIndirectByteCountEXT(void *args) -{ - struct vkCmdDrawIndirectByteCountEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawIndirectByteCountEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->instanceCount, params->firstInstance, params->counterBuffer, params->counterBufferOffset, params->counterOffset, params->vertexStride); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawIndirectByteCountEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t instanceCount; - uint32_t firstInstance; - VkBuffer DECLSPEC_ALIGN(8) counterBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) counterBufferOffset; - uint32_t counterOffset; - uint32_t vertexStride; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawIndirectByteCountEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->instanceCount, params->firstInstance, params->counterBuffer, params->counterBufferOffset, params->counterOffset, params->vertexStride); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawIndirectCount(void *args) -{ - struct vkCmdDrawIndirectCount_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawIndirectCount(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->buffer, params->offset, params->countBuffer, params->countBufferOffset, params->maxDrawCount, params->stride); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawIndirectCount(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkBuffer DECLSPEC_ALIGN(8) countBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) countBufferOffset; - uint32_t maxDrawCount; - uint32_t stride; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawIndirectCount(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->buffer, params->offset, params->countBuffer, params->countBufferOffset, params->maxDrawCount, params->stride); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawIndirectCountAMD(void *args) -{ - struct vkCmdDrawIndirectCountAMD_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawIndirectCountAMD(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->buffer, params->offset, params->countBuffer, params->countBufferOffset, params->maxDrawCount, params->stride); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawIndirectCountAMD(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkBuffer DECLSPEC_ALIGN(8) countBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) countBufferOffset; - uint32_t maxDrawCount; - uint32_t stride; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawIndirectCountAMD(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->buffer, params->offset, params->countBuffer, params->countBufferOffset, params->maxDrawCount, params->stride); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawIndirectCountKHR(void *args) -{ - struct vkCmdDrawIndirectCountKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawIndirectCountKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->buffer, params->offset, params->countBuffer, params->countBufferOffset, params->maxDrawCount, params->stride); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawIndirectCountKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkBuffer DECLSPEC_ALIGN(8) countBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) countBufferOffset; - uint32_t maxDrawCount; - uint32_t stride; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawIndirectCountKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->buffer, params->offset, params->countBuffer, params->countBufferOffset, params->maxDrawCount, params->stride); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawMeshTasksEXT(void *args) -{ - struct vkCmdDrawMeshTasksEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawMeshTasksEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->groupCountX, params->groupCountY, params->groupCountZ); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawMeshTasksEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t groupCountX; - uint32_t groupCountY; - uint32_t groupCountZ; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawMeshTasksEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->groupCountX, params->groupCountY, params->groupCountZ); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawMeshTasksIndirectCountEXT(void *args) -{ - struct vkCmdDrawMeshTasksIndirectCountEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawMeshTasksIndirectCountEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->buffer, params->offset, params->countBuffer, params->countBufferOffset, params->maxDrawCount, params->stride); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawMeshTasksIndirectCountEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkBuffer DECLSPEC_ALIGN(8) countBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) countBufferOffset; - uint32_t maxDrawCount; - uint32_t stride; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawMeshTasksIndirectCountEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->buffer, params->offset, params->countBuffer, params->countBufferOffset, params->maxDrawCount, params->stride); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawMeshTasksIndirectCountNV(void *args) -{ - struct vkCmdDrawMeshTasksIndirectCountNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawMeshTasksIndirectCountNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->buffer, params->offset, params->countBuffer, params->countBufferOffset, params->maxDrawCount, params->stride); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawMeshTasksIndirectCountNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkBuffer DECLSPEC_ALIGN(8) countBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) countBufferOffset; - uint32_t maxDrawCount; - uint32_t stride; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawMeshTasksIndirectCountNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->buffer, params->offset, params->countBuffer, params->countBufferOffset, params->maxDrawCount, params->stride); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawMeshTasksIndirectEXT(void *args) -{ - struct vkCmdDrawMeshTasksIndirectEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawMeshTasksIndirectEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->buffer, params->offset, params->drawCount, params->stride); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawMeshTasksIndirectEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - uint32_t drawCount; - uint32_t stride; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawMeshTasksIndirectEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->buffer, params->offset, params->drawCount, params->stride); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawMeshTasksIndirectNV(void *args) -{ - struct vkCmdDrawMeshTasksIndirectNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawMeshTasksIndirectNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->buffer, params->offset, params->drawCount, params->stride); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawMeshTasksIndirectNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) buffer; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - uint32_t drawCount; - uint32_t stride; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawMeshTasksIndirectNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->buffer, params->offset, params->drawCount, params->stride); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawMeshTasksNV(void *args) -{ - struct vkCmdDrawMeshTasksNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawMeshTasksNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->taskCount, params->firstTask); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawMeshTasksNV(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t taskCount; - uint32_t firstTask; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawMeshTasksNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->taskCount, params->firstTask); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawMultiEXT(void *args) -{ - struct vkCmdDrawMultiEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawMultiEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->drawCount, params->pVertexInfo, params->instanceCount, params->firstInstance, params->stride); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawMultiEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t drawCount; - PTR32 pVertexInfo; - uint32_t instanceCount; - uint32_t firstInstance; - uint32_t stride; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawMultiEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->drawCount, (const VkMultiDrawInfoEXT *)UlongToPtr(params->pVertexInfo), params->instanceCount, params->firstInstance, params->stride); -} - -#ifdef _WIN64 -static void thunk64_vkCmdDrawMultiIndexedEXT(void *args) -{ - struct vkCmdDrawMultiIndexedEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdDrawMultiIndexedEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->drawCount, params->pIndexInfo, params->instanceCount, params->firstInstance, params->stride, params->pVertexOffset); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdDrawMultiIndexedEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t drawCount; - PTR32 pIndexInfo; - uint32_t instanceCount; - uint32_t firstInstance; - uint32_t stride; - PTR32 pVertexOffset; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdDrawMultiIndexedEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->drawCount, (const VkMultiDrawIndexedInfoEXT *)UlongToPtr(params->pIndexInfo), params->instanceCount, params->firstInstance, params->stride, (const int32_t *)UlongToPtr(params->pVertexOffset)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdEndConditionalRenderingEXT(void *args) -{ - struct vkCmdEndConditionalRenderingEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdEndConditionalRenderingEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdEndConditionalRenderingEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdEndConditionalRenderingEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer); -} - -#ifdef _WIN64 -static void thunk64_vkCmdEndDebugUtilsLabelEXT(void *args) -{ - struct vkCmdEndDebugUtilsLabelEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdEndDebugUtilsLabelEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdEndDebugUtilsLabelEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdEndDebugUtilsLabelEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer); -} - -#ifdef _WIN64 -static void thunk64_vkCmdEndQuery(void *args) -{ - struct vkCmdEndQuery_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdEndQuery(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->queryPool, params->query); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdEndQuery(void *args) -{ - struct - { - PTR32 commandBuffer; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t query; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdEndQuery(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->queryPool, params->query); -} - -#ifdef _WIN64 -static void thunk64_vkCmdEndQueryIndexedEXT(void *args) -{ - struct vkCmdEndQueryIndexedEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdEndQueryIndexedEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->queryPool, params->query, params->index); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdEndQueryIndexedEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t query; - uint32_t index; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdEndQueryIndexedEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->queryPool, params->query, params->index); -} - -#ifdef _WIN64 -static void thunk64_vkCmdEndRenderPass(void *args) -{ - struct vkCmdEndRenderPass_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdEndRenderPass(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdEndRenderPass(void *args) -{ - struct - { - PTR32 commandBuffer; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdEndRenderPass(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer); -} - -#ifdef _WIN64 -static void thunk64_vkCmdEndRenderPass2(void *args) -{ - struct vkCmdEndRenderPass2_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdEndRenderPass2(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pSubpassEndInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdEndRenderPass2(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pSubpassEndInfo; - } *params = args; - VkSubpassEndInfo pSubpassEndInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkSubpassEndInfo_win32_to_host(&ctx, (const VkSubpassEndInfo32 *)UlongToPtr(params->pSubpassEndInfo), &pSubpassEndInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdEndRenderPass2(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pSubpassEndInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdEndRenderPass2KHR(void *args) -{ - struct vkCmdEndRenderPass2KHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdEndRenderPass2KHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pSubpassEndInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdEndRenderPass2KHR(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pSubpassEndInfo; - } *params = args; - VkSubpassEndInfo pSubpassEndInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkSubpassEndInfo_win32_to_host(&ctx, (const VkSubpassEndInfo32 *)UlongToPtr(params->pSubpassEndInfo), &pSubpassEndInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdEndRenderPass2KHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pSubpassEndInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdEndRendering(void *args) -{ - struct vkCmdEndRendering_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdEndRendering(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdEndRendering(void *args) -{ - struct - { - PTR32 commandBuffer; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdEndRendering(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer); -} - -#ifdef _WIN64 -static void thunk64_vkCmdEndRenderingKHR(void *args) -{ - struct vkCmdEndRenderingKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdEndRenderingKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdEndRenderingKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdEndRenderingKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer); -} - -#ifdef _WIN64 -static void thunk64_vkCmdEndTransformFeedbackEXT(void *args) -{ - struct vkCmdEndTransformFeedbackEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdEndTransformFeedbackEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->firstCounterBuffer, params->counterBufferCount, params->pCounterBuffers, params->pCounterBufferOffsets); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdEndTransformFeedbackEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t firstCounterBuffer; - uint32_t counterBufferCount; - PTR32 pCounterBuffers; - PTR32 pCounterBufferOffsets; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdEndTransformFeedbackEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->firstCounterBuffer, params->counterBufferCount, (const VkBuffer *)UlongToPtr(params->pCounterBuffers), (const VkDeviceSize *)UlongToPtr(params->pCounterBufferOffsets)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdExecuteCommands(void *args) -{ - struct vkCmdExecuteCommands_params *params = args; - const VkCommandBuffer *pCommandBuffers_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pCommandBuffers_host = convert_VkCommandBuffer_array_win64_to_host(&ctx, params->pCommandBuffers, params->commandBufferCount); - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdExecuteCommands(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->commandBufferCount, pCommandBuffers_host); - free_conversion_context(&ctx); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdExecuteCommands(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t commandBufferCount; - PTR32 pCommandBuffers; - } *params = args; - const VkCommandBuffer *pCommandBuffers_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pCommandBuffers_host = convert_VkCommandBuffer_array_win32_to_host(&ctx, (const PTR32 *)UlongToPtr(params->pCommandBuffers), params->commandBufferCount); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdExecuteCommands(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->commandBufferCount, pCommandBuffers_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdExecuteGeneratedCommandsNV(void *args) -{ - struct vkCmdExecuteGeneratedCommandsNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdExecuteGeneratedCommandsNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->isPreprocessed, params->pGeneratedCommandsInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdExecuteGeneratedCommandsNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 isPreprocessed; - PTR32 pGeneratedCommandsInfo; - } *params = args; - VkGeneratedCommandsInfoNV pGeneratedCommandsInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkGeneratedCommandsInfoNV_win32_to_host(&ctx, (const VkGeneratedCommandsInfoNV32 *)UlongToPtr(params->pGeneratedCommandsInfo), &pGeneratedCommandsInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdExecuteGeneratedCommandsNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->isPreprocessed, &pGeneratedCommandsInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdFillBuffer(void *args) -{ - struct vkCmdFillBuffer_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdFillBuffer(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->dstBuffer, params->dstOffset, params->size, params->data); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdFillBuffer(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) dstBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) dstOffset; - VkDeviceSize DECLSPEC_ALIGN(8) size; - uint32_t data; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdFillBuffer(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->dstBuffer, params->dstOffset, params->size, params->data); -} - -#ifdef _WIN64 -static void thunk64_vkCmdInsertDebugUtilsLabelEXT(void *args) -{ - struct vkCmdInsertDebugUtilsLabelEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdInsertDebugUtilsLabelEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pLabelInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdInsertDebugUtilsLabelEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pLabelInfo; - } *params = args; - VkDebugUtilsLabelEXT pLabelInfo_host; - - convert_VkDebugUtilsLabelEXT_win32_to_host((const VkDebugUtilsLabelEXT32 *)UlongToPtr(params->pLabelInfo), &pLabelInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdInsertDebugUtilsLabelEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pLabelInfo_host); -} - -#ifdef _WIN64 -static void thunk64_vkCmdNextSubpass(void *args) -{ - struct vkCmdNextSubpass_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdNextSubpass(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->contents); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdNextSubpass(void *args) -{ - struct - { - PTR32 commandBuffer; - VkSubpassContents contents; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdNextSubpass(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->contents); -} - -#ifdef _WIN64 -static void thunk64_vkCmdNextSubpass2(void *args) -{ - struct vkCmdNextSubpass2_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdNextSubpass2(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pSubpassBeginInfo, params->pSubpassEndInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdNextSubpass2(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pSubpassBeginInfo; - PTR32 pSubpassEndInfo; - } *params = args; - VkSubpassBeginInfo pSubpassBeginInfo_host; - VkSubpassEndInfo pSubpassEndInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkSubpassBeginInfo_win32_to_host((const VkSubpassBeginInfo32 *)UlongToPtr(params->pSubpassBeginInfo), &pSubpassBeginInfo_host); - convert_VkSubpassEndInfo_win32_to_host(&ctx, (const VkSubpassEndInfo32 *)UlongToPtr(params->pSubpassEndInfo), &pSubpassEndInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdNextSubpass2(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pSubpassBeginInfo_host, &pSubpassEndInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdNextSubpass2KHR(void *args) -{ - struct vkCmdNextSubpass2KHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdNextSubpass2KHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pSubpassBeginInfo, params->pSubpassEndInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdNextSubpass2KHR(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pSubpassBeginInfo; - PTR32 pSubpassEndInfo; - } *params = args; - VkSubpassBeginInfo pSubpassBeginInfo_host; - VkSubpassEndInfo pSubpassEndInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkSubpassBeginInfo_win32_to_host((const VkSubpassBeginInfo32 *)UlongToPtr(params->pSubpassBeginInfo), &pSubpassBeginInfo_host); - convert_VkSubpassEndInfo_win32_to_host(&ctx, (const VkSubpassEndInfo32 *)UlongToPtr(params->pSubpassEndInfo), &pSubpassEndInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdNextSubpass2KHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pSubpassBeginInfo_host, &pSubpassEndInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdOpticalFlowExecuteNV(void *args) -{ - struct vkCmdOpticalFlowExecuteNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdOpticalFlowExecuteNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->session, params->pExecuteInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdOpticalFlowExecuteNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkOpticalFlowSessionNV DECLSPEC_ALIGN(8) session; - PTR32 pExecuteInfo; - } *params = args; - VkOpticalFlowExecuteInfoNV pExecuteInfo_host; - - convert_VkOpticalFlowExecuteInfoNV_win32_to_host((const VkOpticalFlowExecuteInfoNV32 *)UlongToPtr(params->pExecuteInfo), &pExecuteInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdOpticalFlowExecuteNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->session, &pExecuteInfo_host); -} - -#ifdef _WIN64 -static void thunk64_vkCmdPipelineBarrier(void *args) -{ - struct vkCmdPipelineBarrier_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdPipelineBarrier(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->srcStageMask, params->dstStageMask, params->dependencyFlags, params->memoryBarrierCount, params->pMemoryBarriers, params->bufferMemoryBarrierCount, params->pBufferMemoryBarriers, params->imageMemoryBarrierCount, params->pImageMemoryBarriers); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdPipelineBarrier(void *args) -{ - struct - { - PTR32 commandBuffer; - VkPipelineStageFlags srcStageMask; - VkPipelineStageFlags dstStageMask; - VkDependencyFlags dependencyFlags; - uint32_t memoryBarrierCount; - PTR32 pMemoryBarriers; - uint32_t bufferMemoryBarrierCount; - PTR32 pBufferMemoryBarriers; - uint32_t imageMemoryBarrierCount; - PTR32 pImageMemoryBarriers; - } *params = args; - const VkMemoryBarrier *pMemoryBarriers_host; - const VkBufferMemoryBarrier *pBufferMemoryBarriers_host; - const VkImageMemoryBarrier *pImageMemoryBarriers_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pMemoryBarriers_host = convert_VkMemoryBarrier_array_win32_to_host(&ctx, (const VkMemoryBarrier32 *)UlongToPtr(params->pMemoryBarriers), params->memoryBarrierCount); - pBufferMemoryBarriers_host = convert_VkBufferMemoryBarrier_array_win32_to_host(&ctx, (const VkBufferMemoryBarrier32 *)UlongToPtr(params->pBufferMemoryBarriers), params->bufferMemoryBarrierCount); - pImageMemoryBarriers_host = convert_VkImageMemoryBarrier_array_win32_to_host(&ctx, (const VkImageMemoryBarrier32 *)UlongToPtr(params->pImageMemoryBarriers), params->imageMemoryBarrierCount); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdPipelineBarrier(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->srcStageMask, params->dstStageMask, params->dependencyFlags, params->memoryBarrierCount, pMemoryBarriers_host, params->bufferMemoryBarrierCount, pBufferMemoryBarriers_host, params->imageMemoryBarrierCount, pImageMemoryBarriers_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdPipelineBarrier2(void *args) -{ - struct vkCmdPipelineBarrier2_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdPipelineBarrier2(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pDependencyInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdPipelineBarrier2(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pDependencyInfo; - } *params = args; - VkDependencyInfo pDependencyInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkDependencyInfo_win32_to_host(&ctx, (const VkDependencyInfo32 *)UlongToPtr(params->pDependencyInfo), &pDependencyInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdPipelineBarrier2(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pDependencyInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdPipelineBarrier2KHR(void *args) -{ - struct vkCmdPipelineBarrier2KHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdPipelineBarrier2KHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pDependencyInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdPipelineBarrier2KHR(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pDependencyInfo; - } *params = args; - VkDependencyInfo pDependencyInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkDependencyInfo_win32_to_host(&ctx, (const VkDependencyInfo32 *)UlongToPtr(params->pDependencyInfo), &pDependencyInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdPipelineBarrier2KHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pDependencyInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdPreprocessGeneratedCommandsNV(void *args) -{ - struct vkCmdPreprocessGeneratedCommandsNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdPreprocessGeneratedCommandsNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pGeneratedCommandsInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdPreprocessGeneratedCommandsNV(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pGeneratedCommandsInfo; - } *params = args; - VkGeneratedCommandsInfoNV pGeneratedCommandsInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkGeneratedCommandsInfoNV_win32_to_host(&ctx, (const VkGeneratedCommandsInfoNV32 *)UlongToPtr(params->pGeneratedCommandsInfo), &pGeneratedCommandsInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdPreprocessGeneratedCommandsNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pGeneratedCommandsInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdPushConstants(void *args) -{ - struct vkCmdPushConstants_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdPushConstants(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->layout, params->stageFlags, params->offset, params->size, params->pValues); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdPushConstants(void *args) -{ - struct - { - PTR32 commandBuffer; - VkPipelineLayout DECLSPEC_ALIGN(8) layout; - VkShaderStageFlags stageFlags; - uint32_t offset; - uint32_t size; - PTR32 pValues; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdPushConstants(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->layout, params->stageFlags, params->offset, params->size, (const void *)UlongToPtr(params->pValues)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdPushDescriptorSetKHR(void *args) -{ - struct vkCmdPushDescriptorSetKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdPushDescriptorSetKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pipelineBindPoint, params->layout, params->set, params->descriptorWriteCount, params->pDescriptorWrites); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdPushDescriptorSetKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - VkPipelineBindPoint pipelineBindPoint; - VkPipelineLayout DECLSPEC_ALIGN(8) layout; - uint32_t set; - uint32_t descriptorWriteCount; - PTR32 pDescriptorWrites; - } *params = args; - const VkWriteDescriptorSet *pDescriptorWrites_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pDescriptorWrites_host = convert_VkWriteDescriptorSet_array_win32_to_host(&ctx, (const VkWriteDescriptorSet32 *)UlongToPtr(params->pDescriptorWrites), params->descriptorWriteCount); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdPushDescriptorSetKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->pipelineBindPoint, params->layout, params->set, params->descriptorWriteCount, pDescriptorWrites_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdPushDescriptorSetWithTemplateKHR(void *args) -{ - struct vkCmdPushDescriptorSetWithTemplateKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdPushDescriptorSetWithTemplateKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->descriptorUpdateTemplate, params->layout, params->set, params->pData); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdPushDescriptorSetWithTemplateKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - VkDescriptorUpdateTemplate DECLSPEC_ALIGN(8) descriptorUpdateTemplate; - VkPipelineLayout DECLSPEC_ALIGN(8) layout; - uint32_t set; - PTR32 pData; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdPushDescriptorSetWithTemplateKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->descriptorUpdateTemplate, params->layout, params->set, (const void *)UlongToPtr(params->pData)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdResetEvent(void *args) -{ - struct vkCmdResetEvent_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdResetEvent(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->event, params->stageMask); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdResetEvent(void *args) -{ - struct - { - PTR32 commandBuffer; - VkEvent DECLSPEC_ALIGN(8) event; - VkPipelineStageFlags stageMask; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdResetEvent(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->event, params->stageMask); -} - -#ifdef _WIN64 -static void thunk64_vkCmdResetEvent2(void *args) -{ - struct vkCmdResetEvent2_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdResetEvent2(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->event, params->stageMask); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdResetEvent2(void *args) -{ - struct - { - PTR32 commandBuffer; - VkEvent DECLSPEC_ALIGN(8) event; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) stageMask; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdResetEvent2(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->event, params->stageMask); -} - -#ifdef _WIN64 -static void thunk64_vkCmdResetEvent2KHR(void *args) -{ - struct vkCmdResetEvent2KHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdResetEvent2KHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->event, params->stageMask); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdResetEvent2KHR(void *args) -{ - struct - { - PTR32 commandBuffer; - VkEvent DECLSPEC_ALIGN(8) event; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) stageMask; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdResetEvent2KHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->event, params->stageMask); -} - -#ifdef _WIN64 -static void thunk64_vkCmdResetQueryPool(void *args) -{ - struct vkCmdResetQueryPool_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdResetQueryPool(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->queryPool, params->firstQuery, params->queryCount); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdResetQueryPool(void *args) -{ - struct - { - PTR32 commandBuffer; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t firstQuery; - uint32_t queryCount; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdResetQueryPool(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->queryPool, params->firstQuery, params->queryCount); -} - -#ifdef _WIN64 -static void thunk64_vkCmdResolveImage(void *args) -{ - struct vkCmdResolveImage_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdResolveImage(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->srcImage, params->srcImageLayout, params->dstImage, params->dstImageLayout, params->regionCount, params->pRegions); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdResolveImage(void *args) -{ - struct - { - PTR32 commandBuffer; - VkImage DECLSPEC_ALIGN(8) srcImage; - VkImageLayout srcImageLayout; - VkImage DECLSPEC_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - PTR32 pRegions; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdResolveImage(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->srcImage, params->srcImageLayout, params->dstImage, params->dstImageLayout, params->regionCount, (const VkImageResolve *)UlongToPtr(params->pRegions)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdResolveImage2(void *args) -{ - struct vkCmdResolveImage2_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdResolveImage2(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pResolveImageInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdResolveImage2(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pResolveImageInfo; - } *params = args; - VkResolveImageInfo2 pResolveImageInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkResolveImageInfo2_win32_to_host(&ctx, (const VkResolveImageInfo232 *)UlongToPtr(params->pResolveImageInfo), &pResolveImageInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdResolveImage2(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pResolveImageInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdResolveImage2KHR(void *args) -{ - struct vkCmdResolveImage2KHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdResolveImage2KHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pResolveImageInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdResolveImage2KHR(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pResolveImageInfo; - } *params = args; - VkResolveImageInfo2 pResolveImageInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkResolveImageInfo2_win32_to_host(&ctx, (const VkResolveImageInfo232 *)UlongToPtr(params->pResolveImageInfo), &pResolveImageInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdResolveImage2KHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pResolveImageInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetAlphaToCoverageEnableEXT(void *args) -{ - struct vkCmdSetAlphaToCoverageEnableEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetAlphaToCoverageEnableEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->alphaToCoverageEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetAlphaToCoverageEnableEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 alphaToCoverageEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetAlphaToCoverageEnableEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->alphaToCoverageEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetAlphaToOneEnableEXT(void *args) -{ - struct vkCmdSetAlphaToOneEnableEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetAlphaToOneEnableEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->alphaToOneEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetAlphaToOneEnableEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 alphaToOneEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetAlphaToOneEnableEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->alphaToOneEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetBlendConstants(void *args) -{ - struct vkCmdSetBlendConstants_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetBlendConstants(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->blendConstants); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetBlendConstants(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 blendConstants; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetBlendConstants(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, (const float *)UlongToPtr(params->blendConstants)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetCheckpointNV(void *args) -{ - struct vkCmdSetCheckpointNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetCheckpointNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pCheckpointMarker); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetCheckpointNV(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pCheckpointMarker; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetCheckpointNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, (const void *)UlongToPtr(params->pCheckpointMarker)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetCoarseSampleOrderNV(void *args) -{ - struct vkCmdSetCoarseSampleOrderNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetCoarseSampleOrderNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->sampleOrderType, params->customSampleOrderCount, params->pCustomSampleOrders); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetCoarseSampleOrderNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkCoarseSampleOrderTypeNV sampleOrderType; - uint32_t customSampleOrderCount; - PTR32 pCustomSampleOrders; - } *params = args; - const VkCoarseSampleOrderCustomNV *pCustomSampleOrders_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pCustomSampleOrders_host = convert_VkCoarseSampleOrderCustomNV_array_win32_to_host(&ctx, (const VkCoarseSampleOrderCustomNV32 *)UlongToPtr(params->pCustomSampleOrders), params->customSampleOrderCount); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetCoarseSampleOrderNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->sampleOrderType, params->customSampleOrderCount, pCustomSampleOrders_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetColorBlendAdvancedEXT(void *args) -{ - struct vkCmdSetColorBlendAdvancedEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetColorBlendAdvancedEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->firstAttachment, params->attachmentCount, params->pColorBlendAdvanced); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetColorBlendAdvancedEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t firstAttachment; - uint32_t attachmentCount; - PTR32 pColorBlendAdvanced; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetColorBlendAdvancedEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->firstAttachment, params->attachmentCount, (const VkColorBlendAdvancedEXT *)UlongToPtr(params->pColorBlendAdvanced)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetColorBlendEnableEXT(void *args) -{ - struct vkCmdSetColorBlendEnableEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetColorBlendEnableEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->firstAttachment, params->attachmentCount, params->pColorBlendEnables); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetColorBlendEnableEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t firstAttachment; - uint32_t attachmentCount; - PTR32 pColorBlendEnables; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetColorBlendEnableEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->firstAttachment, params->attachmentCount, (const VkBool32 *)UlongToPtr(params->pColorBlendEnables)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetColorBlendEquationEXT(void *args) -{ - struct vkCmdSetColorBlendEquationEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetColorBlendEquationEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->firstAttachment, params->attachmentCount, params->pColorBlendEquations); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetColorBlendEquationEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t firstAttachment; - uint32_t attachmentCount; - PTR32 pColorBlendEquations; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetColorBlendEquationEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->firstAttachment, params->attachmentCount, (const VkColorBlendEquationEXT *)UlongToPtr(params->pColorBlendEquations)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetColorWriteEnableEXT(void *args) -{ - struct vkCmdSetColorWriteEnableEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetColorWriteEnableEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->attachmentCount, params->pColorWriteEnables); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetColorWriteEnableEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t attachmentCount; - PTR32 pColorWriteEnables; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetColorWriteEnableEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->attachmentCount, (const VkBool32 *)UlongToPtr(params->pColorWriteEnables)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetColorWriteMaskEXT(void *args) -{ - struct vkCmdSetColorWriteMaskEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetColorWriteMaskEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->firstAttachment, params->attachmentCount, params->pColorWriteMasks); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetColorWriteMaskEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t firstAttachment; - uint32_t attachmentCount; - PTR32 pColorWriteMasks; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetColorWriteMaskEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->firstAttachment, params->attachmentCount, (const VkColorComponentFlags *)UlongToPtr(params->pColorWriteMasks)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetConservativeRasterizationModeEXT(void *args) -{ - struct vkCmdSetConservativeRasterizationModeEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetConservativeRasterizationModeEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->conservativeRasterizationMode); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetConservativeRasterizationModeEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkConservativeRasterizationModeEXT conservativeRasterizationMode; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetConservativeRasterizationModeEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->conservativeRasterizationMode); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetCoverageModulationModeNV(void *args) -{ - struct vkCmdSetCoverageModulationModeNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetCoverageModulationModeNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->coverageModulationMode); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetCoverageModulationModeNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkCoverageModulationModeNV coverageModulationMode; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetCoverageModulationModeNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->coverageModulationMode); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetCoverageModulationTableEnableNV(void *args) -{ - struct vkCmdSetCoverageModulationTableEnableNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetCoverageModulationTableEnableNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->coverageModulationTableEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetCoverageModulationTableEnableNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 coverageModulationTableEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetCoverageModulationTableEnableNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->coverageModulationTableEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetCoverageModulationTableNV(void *args) -{ - struct vkCmdSetCoverageModulationTableNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetCoverageModulationTableNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->coverageModulationTableCount, params->pCoverageModulationTable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetCoverageModulationTableNV(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t coverageModulationTableCount; - PTR32 pCoverageModulationTable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetCoverageModulationTableNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->coverageModulationTableCount, (const float *)UlongToPtr(params->pCoverageModulationTable)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetCoverageReductionModeNV(void *args) -{ - struct vkCmdSetCoverageReductionModeNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetCoverageReductionModeNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->coverageReductionMode); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetCoverageReductionModeNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkCoverageReductionModeNV coverageReductionMode; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetCoverageReductionModeNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->coverageReductionMode); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetCoverageToColorEnableNV(void *args) -{ - struct vkCmdSetCoverageToColorEnableNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetCoverageToColorEnableNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->coverageToColorEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetCoverageToColorEnableNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 coverageToColorEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetCoverageToColorEnableNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->coverageToColorEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetCoverageToColorLocationNV(void *args) -{ - struct vkCmdSetCoverageToColorLocationNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetCoverageToColorLocationNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->coverageToColorLocation); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetCoverageToColorLocationNV(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t coverageToColorLocation; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetCoverageToColorLocationNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->coverageToColorLocation); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetCullMode(void *args) -{ - struct vkCmdSetCullMode_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetCullMode(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->cullMode); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetCullMode(void *args) -{ - struct - { - PTR32 commandBuffer; - VkCullModeFlags cullMode; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetCullMode(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->cullMode); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetCullModeEXT(void *args) -{ - struct vkCmdSetCullModeEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetCullModeEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->cullMode); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetCullModeEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkCullModeFlags cullMode; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetCullModeEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->cullMode); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDepthBias(void *args) -{ - struct vkCmdSetDepthBias_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDepthBias(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->depthBiasConstantFactor, params->depthBiasClamp, params->depthBiasSlopeFactor); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDepthBias(void *args) -{ - struct - { - PTR32 commandBuffer; - float depthBiasConstantFactor; - float depthBiasClamp; - float depthBiasSlopeFactor; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDepthBias(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->depthBiasConstantFactor, params->depthBiasClamp, params->depthBiasSlopeFactor); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDepthBiasEnable(void *args) -{ - struct vkCmdSetDepthBiasEnable_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDepthBiasEnable(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->depthBiasEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDepthBiasEnable(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 depthBiasEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDepthBiasEnable(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->depthBiasEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDepthBiasEnableEXT(void *args) -{ - struct vkCmdSetDepthBiasEnableEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDepthBiasEnableEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->depthBiasEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDepthBiasEnableEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 depthBiasEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDepthBiasEnableEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->depthBiasEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDepthBounds(void *args) -{ - struct vkCmdSetDepthBounds_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDepthBounds(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->minDepthBounds, params->maxDepthBounds); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDepthBounds(void *args) -{ - struct - { - PTR32 commandBuffer; - float minDepthBounds; - float maxDepthBounds; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDepthBounds(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->minDepthBounds, params->maxDepthBounds); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDepthBoundsTestEnable(void *args) -{ - struct vkCmdSetDepthBoundsTestEnable_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDepthBoundsTestEnable(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->depthBoundsTestEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDepthBoundsTestEnable(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 depthBoundsTestEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDepthBoundsTestEnable(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->depthBoundsTestEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDepthBoundsTestEnableEXT(void *args) -{ - struct vkCmdSetDepthBoundsTestEnableEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDepthBoundsTestEnableEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->depthBoundsTestEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDepthBoundsTestEnableEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 depthBoundsTestEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDepthBoundsTestEnableEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->depthBoundsTestEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDepthClampEnableEXT(void *args) -{ - struct vkCmdSetDepthClampEnableEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDepthClampEnableEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->depthClampEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDepthClampEnableEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 depthClampEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDepthClampEnableEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->depthClampEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDepthClipEnableEXT(void *args) -{ - struct vkCmdSetDepthClipEnableEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDepthClipEnableEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->depthClipEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDepthClipEnableEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 depthClipEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDepthClipEnableEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->depthClipEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDepthClipNegativeOneToOneEXT(void *args) -{ - struct vkCmdSetDepthClipNegativeOneToOneEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDepthClipNegativeOneToOneEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->negativeOneToOne); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDepthClipNegativeOneToOneEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 negativeOneToOne; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDepthClipNegativeOneToOneEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->negativeOneToOne); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDepthCompareOp(void *args) -{ - struct vkCmdSetDepthCompareOp_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDepthCompareOp(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->depthCompareOp); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDepthCompareOp(void *args) -{ - struct - { - PTR32 commandBuffer; - VkCompareOp depthCompareOp; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDepthCompareOp(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->depthCompareOp); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDepthCompareOpEXT(void *args) -{ - struct vkCmdSetDepthCompareOpEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDepthCompareOpEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->depthCompareOp); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDepthCompareOpEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkCompareOp depthCompareOp; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDepthCompareOpEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->depthCompareOp); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDepthTestEnable(void *args) -{ - struct vkCmdSetDepthTestEnable_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDepthTestEnable(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->depthTestEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDepthTestEnable(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 depthTestEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDepthTestEnable(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->depthTestEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDepthTestEnableEXT(void *args) -{ - struct vkCmdSetDepthTestEnableEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDepthTestEnableEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->depthTestEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDepthTestEnableEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 depthTestEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDepthTestEnableEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->depthTestEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDepthWriteEnable(void *args) -{ - struct vkCmdSetDepthWriteEnable_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDepthWriteEnable(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->depthWriteEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDepthWriteEnable(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 depthWriteEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDepthWriteEnable(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->depthWriteEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDepthWriteEnableEXT(void *args) -{ - struct vkCmdSetDepthWriteEnableEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDepthWriteEnableEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->depthWriteEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDepthWriteEnableEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 depthWriteEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDepthWriteEnableEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->depthWriteEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDescriptorBufferOffsetsEXT(void *args) -{ - struct vkCmdSetDescriptorBufferOffsetsEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDescriptorBufferOffsetsEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pipelineBindPoint, params->layout, params->firstSet, params->setCount, params->pBufferIndices, params->pOffsets); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDescriptorBufferOffsetsEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkPipelineBindPoint pipelineBindPoint; - VkPipelineLayout DECLSPEC_ALIGN(8) layout; - uint32_t firstSet; - uint32_t setCount; - PTR32 pBufferIndices; - PTR32 pOffsets; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDescriptorBufferOffsetsEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->pipelineBindPoint, params->layout, params->firstSet, params->setCount, (const uint32_t *)UlongToPtr(params->pBufferIndices), (const VkDeviceSize *)UlongToPtr(params->pOffsets)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDeviceMask(void *args) -{ - struct vkCmdSetDeviceMask_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDeviceMask(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->deviceMask); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDeviceMask(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t deviceMask; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDeviceMask(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->deviceMask); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDeviceMaskKHR(void *args) -{ - struct vkCmdSetDeviceMaskKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDeviceMaskKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->deviceMask); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDeviceMaskKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t deviceMask; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDeviceMaskKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->deviceMask); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetDiscardRectangleEXT(void *args) -{ - struct vkCmdSetDiscardRectangleEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetDiscardRectangleEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->firstDiscardRectangle, params->discardRectangleCount, params->pDiscardRectangles); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetDiscardRectangleEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t firstDiscardRectangle; - uint32_t discardRectangleCount; - PTR32 pDiscardRectangles; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetDiscardRectangleEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->firstDiscardRectangle, params->discardRectangleCount, (const VkRect2D *)UlongToPtr(params->pDiscardRectangles)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetEvent(void *args) -{ - struct vkCmdSetEvent_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetEvent(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->event, params->stageMask); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetEvent(void *args) -{ - struct - { - PTR32 commandBuffer; - VkEvent DECLSPEC_ALIGN(8) event; - VkPipelineStageFlags stageMask; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetEvent(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->event, params->stageMask); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetEvent2(void *args) -{ - struct vkCmdSetEvent2_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetEvent2(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->event, params->pDependencyInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetEvent2(void *args) -{ - struct - { - PTR32 commandBuffer; - VkEvent DECLSPEC_ALIGN(8) event; - PTR32 pDependencyInfo; - } *params = args; - VkDependencyInfo pDependencyInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkDependencyInfo_win32_to_host(&ctx, (const VkDependencyInfo32 *)UlongToPtr(params->pDependencyInfo), &pDependencyInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetEvent2(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->event, &pDependencyInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetEvent2KHR(void *args) -{ - struct vkCmdSetEvent2KHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetEvent2KHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->event, params->pDependencyInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetEvent2KHR(void *args) -{ - struct - { - PTR32 commandBuffer; - VkEvent DECLSPEC_ALIGN(8) event; - PTR32 pDependencyInfo; - } *params = args; - VkDependencyInfo pDependencyInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkDependencyInfo_win32_to_host(&ctx, (const VkDependencyInfo32 *)UlongToPtr(params->pDependencyInfo), &pDependencyInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetEvent2KHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->event, &pDependencyInfo_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetExclusiveScissorNV(void *args) -{ - struct vkCmdSetExclusiveScissorNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetExclusiveScissorNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->firstExclusiveScissor, params->exclusiveScissorCount, params->pExclusiveScissors); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetExclusiveScissorNV(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t firstExclusiveScissor; - uint32_t exclusiveScissorCount; - PTR32 pExclusiveScissors; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetExclusiveScissorNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->firstExclusiveScissor, params->exclusiveScissorCount, (const VkRect2D *)UlongToPtr(params->pExclusiveScissors)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetExtraPrimitiveOverestimationSizeEXT(void *args) -{ - struct vkCmdSetExtraPrimitiveOverestimationSizeEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetExtraPrimitiveOverestimationSizeEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->extraPrimitiveOverestimationSize); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetExtraPrimitiveOverestimationSizeEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - float extraPrimitiveOverestimationSize; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetExtraPrimitiveOverestimationSizeEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->extraPrimitiveOverestimationSize); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetFragmentShadingRateEnumNV(void *args) -{ - struct vkCmdSetFragmentShadingRateEnumNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetFragmentShadingRateEnumNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->shadingRate, params->combinerOps); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetFragmentShadingRateEnumNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkFragmentShadingRateNV shadingRate; - PTR32 combinerOps; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetFragmentShadingRateEnumNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->shadingRate, (const VkFragmentShadingRateCombinerOpKHR *)UlongToPtr(params->combinerOps)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetFragmentShadingRateKHR(void *args) -{ - struct vkCmdSetFragmentShadingRateKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetFragmentShadingRateKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pFragmentSize, params->combinerOps); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetFragmentShadingRateKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pFragmentSize; - PTR32 combinerOps; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetFragmentShadingRateKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, (const VkExtent2D *)UlongToPtr(params->pFragmentSize), (const VkFragmentShadingRateCombinerOpKHR *)UlongToPtr(params->combinerOps)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetFrontFace(void *args) -{ - struct vkCmdSetFrontFace_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetFrontFace(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->frontFace); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetFrontFace(void *args) -{ - struct - { - PTR32 commandBuffer; - VkFrontFace frontFace; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetFrontFace(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->frontFace); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetFrontFaceEXT(void *args) -{ - struct vkCmdSetFrontFaceEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetFrontFaceEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->frontFace); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetFrontFaceEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkFrontFace frontFace; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetFrontFaceEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->frontFace); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetLineRasterizationModeEXT(void *args) -{ - struct vkCmdSetLineRasterizationModeEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetLineRasterizationModeEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->lineRasterizationMode); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetLineRasterizationModeEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkLineRasterizationModeEXT lineRasterizationMode; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetLineRasterizationModeEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->lineRasterizationMode); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetLineStippleEXT(void *args) -{ - struct vkCmdSetLineStippleEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetLineStippleEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->lineStippleFactor, params->lineStipplePattern); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetLineStippleEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t lineStippleFactor; - uint16_t lineStipplePattern; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetLineStippleEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->lineStippleFactor, params->lineStipplePattern); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetLineStippleEnableEXT(void *args) -{ - struct vkCmdSetLineStippleEnableEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetLineStippleEnableEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->stippledLineEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetLineStippleEnableEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 stippledLineEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetLineStippleEnableEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->stippledLineEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetLineWidth(void *args) -{ - struct vkCmdSetLineWidth_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetLineWidth(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->lineWidth); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetLineWidth(void *args) -{ - struct - { - PTR32 commandBuffer; - float lineWidth; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetLineWidth(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->lineWidth); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetLogicOpEXT(void *args) -{ - struct vkCmdSetLogicOpEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetLogicOpEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->logicOp); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetLogicOpEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkLogicOp logicOp; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetLogicOpEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->logicOp); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetLogicOpEnableEXT(void *args) -{ - struct vkCmdSetLogicOpEnableEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetLogicOpEnableEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->logicOpEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetLogicOpEnableEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 logicOpEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetLogicOpEnableEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->logicOpEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetPatchControlPointsEXT(void *args) -{ - struct vkCmdSetPatchControlPointsEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetPatchControlPointsEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->patchControlPoints); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetPatchControlPointsEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t patchControlPoints; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetPatchControlPointsEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->patchControlPoints); -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCmdSetPerformanceMarkerINTEL(void *args) -{ - struct vkCmdSetPerformanceMarkerINTEL_params *params = args; - - TRACE("%p, %p\n", params->commandBuffer, params->pMarkerInfo); - - params->result = wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetPerformanceMarkerINTEL(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pMarkerInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCmdSetPerformanceMarkerINTEL(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pMarkerInfo; - VkResult result; - } *params = args; - VkPerformanceMarkerInfoINTEL pMarkerInfo_host; - - TRACE("%#x, %#x\n", params->commandBuffer, params->pMarkerInfo); - - convert_VkPerformanceMarkerInfoINTEL_win32_to_host((const VkPerformanceMarkerInfoINTEL32 *)UlongToPtr(params->pMarkerInfo), &pMarkerInfo_host); - params->result = wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetPerformanceMarkerINTEL(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pMarkerInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCmdSetPerformanceOverrideINTEL(void *args) -{ - struct vkCmdSetPerformanceOverrideINTEL_params *params = args; - - TRACE("%p, %p\n", params->commandBuffer, params->pOverrideInfo); - - params->result = wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetPerformanceOverrideINTEL(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pOverrideInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCmdSetPerformanceOverrideINTEL(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pOverrideInfo; - VkResult result; - } *params = args; - VkPerformanceOverrideInfoINTEL pOverrideInfo_host; - - TRACE("%#x, %#x\n", params->commandBuffer, params->pOverrideInfo); - - convert_VkPerformanceOverrideInfoINTEL_win32_to_host((const VkPerformanceOverrideInfoINTEL32 *)UlongToPtr(params->pOverrideInfo), &pOverrideInfo_host); - params->result = wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetPerformanceOverrideINTEL(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pOverrideInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCmdSetPerformanceStreamMarkerINTEL(void *args) -{ - struct vkCmdSetPerformanceStreamMarkerINTEL_params *params = args; - - TRACE("%p, %p\n", params->commandBuffer, params->pMarkerInfo); - - params->result = wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetPerformanceStreamMarkerINTEL(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pMarkerInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCmdSetPerformanceStreamMarkerINTEL(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pMarkerInfo; - VkResult result; - } *params = args; - VkPerformanceStreamMarkerInfoINTEL pMarkerInfo_host; - - TRACE("%#x, %#x\n", params->commandBuffer, params->pMarkerInfo); - - convert_VkPerformanceStreamMarkerInfoINTEL_win32_to_host((const VkPerformanceStreamMarkerInfoINTEL32 *)UlongToPtr(params->pMarkerInfo), &pMarkerInfo_host); - params->result = wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetPerformanceStreamMarkerINTEL(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pMarkerInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetPolygonModeEXT(void *args) -{ - struct vkCmdSetPolygonModeEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetPolygonModeEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->polygonMode); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetPolygonModeEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkPolygonMode polygonMode; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetPolygonModeEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->polygonMode); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetPrimitiveRestartEnable(void *args) -{ - struct vkCmdSetPrimitiveRestartEnable_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetPrimitiveRestartEnable(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->primitiveRestartEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetPrimitiveRestartEnable(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 primitiveRestartEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetPrimitiveRestartEnable(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->primitiveRestartEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetPrimitiveRestartEnableEXT(void *args) -{ - struct vkCmdSetPrimitiveRestartEnableEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetPrimitiveRestartEnableEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->primitiveRestartEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetPrimitiveRestartEnableEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 primitiveRestartEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetPrimitiveRestartEnableEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->primitiveRestartEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetPrimitiveTopology(void *args) -{ - struct vkCmdSetPrimitiveTopology_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetPrimitiveTopology(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->primitiveTopology); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetPrimitiveTopology(void *args) -{ - struct - { - PTR32 commandBuffer; - VkPrimitiveTopology primitiveTopology; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetPrimitiveTopology(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->primitiveTopology); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetPrimitiveTopologyEXT(void *args) -{ - struct vkCmdSetPrimitiveTopologyEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetPrimitiveTopologyEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->primitiveTopology); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetPrimitiveTopologyEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkPrimitiveTopology primitiveTopology; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetPrimitiveTopologyEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->primitiveTopology); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetProvokingVertexModeEXT(void *args) -{ - struct vkCmdSetProvokingVertexModeEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetProvokingVertexModeEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->provokingVertexMode); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetProvokingVertexModeEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkProvokingVertexModeEXT provokingVertexMode; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetProvokingVertexModeEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->provokingVertexMode); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetRasterizationSamplesEXT(void *args) -{ - struct vkCmdSetRasterizationSamplesEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetRasterizationSamplesEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->rasterizationSamples); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetRasterizationSamplesEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkSampleCountFlagBits rasterizationSamples; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetRasterizationSamplesEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->rasterizationSamples); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetRasterizationStreamEXT(void *args) -{ - struct vkCmdSetRasterizationStreamEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetRasterizationStreamEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->rasterizationStream); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetRasterizationStreamEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t rasterizationStream; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetRasterizationStreamEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->rasterizationStream); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetRasterizerDiscardEnable(void *args) -{ - struct vkCmdSetRasterizerDiscardEnable_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetRasterizerDiscardEnable(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->rasterizerDiscardEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetRasterizerDiscardEnable(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 rasterizerDiscardEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetRasterizerDiscardEnable(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->rasterizerDiscardEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetRasterizerDiscardEnableEXT(void *args) -{ - struct vkCmdSetRasterizerDiscardEnableEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetRasterizerDiscardEnableEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->rasterizerDiscardEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetRasterizerDiscardEnableEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 rasterizerDiscardEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetRasterizerDiscardEnableEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->rasterizerDiscardEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetRayTracingPipelineStackSizeKHR(void *args) -{ - struct vkCmdSetRayTracingPipelineStackSizeKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetRayTracingPipelineStackSizeKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pipelineStackSize); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetRayTracingPipelineStackSizeKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t pipelineStackSize; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetRayTracingPipelineStackSizeKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->pipelineStackSize); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetRepresentativeFragmentTestEnableNV(void *args) -{ - struct vkCmdSetRepresentativeFragmentTestEnableNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetRepresentativeFragmentTestEnableNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->representativeFragmentTestEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetRepresentativeFragmentTestEnableNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 representativeFragmentTestEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetRepresentativeFragmentTestEnableNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->representativeFragmentTestEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetSampleLocationsEXT(void *args) -{ - struct vkCmdSetSampleLocationsEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetSampleLocationsEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pSampleLocationsInfo); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetSampleLocationsEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pSampleLocationsInfo; - } *params = args; - VkSampleLocationsInfoEXT pSampleLocationsInfo_host; - - convert_VkSampleLocationsInfoEXT_win32_to_host((const VkSampleLocationsInfoEXT32 *)UlongToPtr(params->pSampleLocationsInfo), &pSampleLocationsInfo_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetSampleLocationsEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pSampleLocationsInfo_host); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetSampleLocationsEnableEXT(void *args) -{ - struct vkCmdSetSampleLocationsEnableEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetSampleLocationsEnableEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->sampleLocationsEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetSampleLocationsEnableEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 sampleLocationsEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetSampleLocationsEnableEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->sampleLocationsEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetSampleMaskEXT(void *args) -{ - struct vkCmdSetSampleMaskEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetSampleMaskEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->samples, params->pSampleMask); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetSampleMaskEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkSampleCountFlagBits samples; - PTR32 pSampleMask; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetSampleMaskEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->samples, (const VkSampleMask *)UlongToPtr(params->pSampleMask)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetScissor(void *args) -{ - struct vkCmdSetScissor_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetScissor(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->firstScissor, params->scissorCount, params->pScissors); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetScissor(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t firstScissor; - uint32_t scissorCount; - PTR32 pScissors; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetScissor(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->firstScissor, params->scissorCount, (const VkRect2D *)UlongToPtr(params->pScissors)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetScissorWithCount(void *args) -{ - struct vkCmdSetScissorWithCount_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetScissorWithCount(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->scissorCount, params->pScissors); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetScissorWithCount(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t scissorCount; - PTR32 pScissors; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetScissorWithCount(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->scissorCount, (const VkRect2D *)UlongToPtr(params->pScissors)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetScissorWithCountEXT(void *args) -{ - struct vkCmdSetScissorWithCountEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetScissorWithCountEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->scissorCount, params->pScissors); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetScissorWithCountEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t scissorCount; - PTR32 pScissors; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetScissorWithCountEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->scissorCount, (const VkRect2D *)UlongToPtr(params->pScissors)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetShadingRateImageEnableNV(void *args) -{ - struct vkCmdSetShadingRateImageEnableNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetShadingRateImageEnableNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->shadingRateImageEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetShadingRateImageEnableNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 shadingRateImageEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetShadingRateImageEnableNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->shadingRateImageEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetStencilCompareMask(void *args) -{ - struct vkCmdSetStencilCompareMask_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetStencilCompareMask(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->faceMask, params->compareMask); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetStencilCompareMask(void *args) -{ - struct - { - PTR32 commandBuffer; - VkStencilFaceFlags faceMask; - uint32_t compareMask; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetStencilCompareMask(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->faceMask, params->compareMask); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetStencilOp(void *args) -{ - struct vkCmdSetStencilOp_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetStencilOp(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->faceMask, params->failOp, params->passOp, params->depthFailOp, params->compareOp); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetStencilOp(void *args) -{ - struct - { - PTR32 commandBuffer; - VkStencilFaceFlags faceMask; - VkStencilOp failOp; - VkStencilOp passOp; - VkStencilOp depthFailOp; - VkCompareOp compareOp; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetStencilOp(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->faceMask, params->failOp, params->passOp, params->depthFailOp, params->compareOp); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetStencilOpEXT(void *args) -{ - struct vkCmdSetStencilOpEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetStencilOpEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->faceMask, params->failOp, params->passOp, params->depthFailOp, params->compareOp); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetStencilOpEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkStencilFaceFlags faceMask; - VkStencilOp failOp; - VkStencilOp passOp; - VkStencilOp depthFailOp; - VkCompareOp compareOp; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetStencilOpEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->faceMask, params->failOp, params->passOp, params->depthFailOp, params->compareOp); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetStencilReference(void *args) -{ - struct vkCmdSetStencilReference_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetStencilReference(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->faceMask, params->reference); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetStencilReference(void *args) -{ - struct - { - PTR32 commandBuffer; - VkStencilFaceFlags faceMask; - uint32_t reference; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetStencilReference(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->faceMask, params->reference); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetStencilTestEnable(void *args) -{ - struct vkCmdSetStencilTestEnable_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetStencilTestEnable(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->stencilTestEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetStencilTestEnable(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 stencilTestEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetStencilTestEnable(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->stencilTestEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetStencilTestEnableEXT(void *args) -{ - struct vkCmdSetStencilTestEnableEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetStencilTestEnableEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->stencilTestEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetStencilTestEnableEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 stencilTestEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetStencilTestEnableEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->stencilTestEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetStencilWriteMask(void *args) -{ - struct vkCmdSetStencilWriteMask_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetStencilWriteMask(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->faceMask, params->writeMask); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetStencilWriteMask(void *args) -{ - struct - { - PTR32 commandBuffer; - VkStencilFaceFlags faceMask; - uint32_t writeMask; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetStencilWriteMask(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->faceMask, params->writeMask); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetTessellationDomainOriginEXT(void *args) -{ - struct vkCmdSetTessellationDomainOriginEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetTessellationDomainOriginEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->domainOrigin); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetTessellationDomainOriginEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - VkTessellationDomainOrigin domainOrigin; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetTessellationDomainOriginEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->domainOrigin); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetVertexInputEXT(void *args) -{ - struct vkCmdSetVertexInputEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetVertexInputEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->vertexBindingDescriptionCount, params->pVertexBindingDescriptions, params->vertexAttributeDescriptionCount, params->pVertexAttributeDescriptions); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetVertexInputEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t vertexBindingDescriptionCount; - PTR32 pVertexBindingDescriptions; - uint32_t vertexAttributeDescriptionCount; - PTR32 pVertexAttributeDescriptions; - } *params = args; - const VkVertexInputBindingDescription2EXT *pVertexBindingDescriptions_host; - const VkVertexInputAttributeDescription2EXT *pVertexAttributeDescriptions_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pVertexBindingDescriptions_host = convert_VkVertexInputBindingDescription2EXT_array_win32_to_host(&ctx, (const VkVertexInputBindingDescription2EXT32 *)UlongToPtr(params->pVertexBindingDescriptions), params->vertexBindingDescriptionCount); - pVertexAttributeDescriptions_host = convert_VkVertexInputAttributeDescription2EXT_array_win32_to_host(&ctx, (const VkVertexInputAttributeDescription2EXT32 *)UlongToPtr(params->pVertexAttributeDescriptions), params->vertexAttributeDescriptionCount); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetVertexInputEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->vertexBindingDescriptionCount, pVertexBindingDescriptions_host, params->vertexAttributeDescriptionCount, pVertexAttributeDescriptions_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetViewport(void *args) -{ - struct vkCmdSetViewport_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetViewport(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->firstViewport, params->viewportCount, params->pViewports); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetViewport(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t firstViewport; - uint32_t viewportCount; - PTR32 pViewports; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetViewport(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->firstViewport, params->viewportCount, (const VkViewport *)UlongToPtr(params->pViewports)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetViewportShadingRatePaletteNV(void *args) -{ - struct vkCmdSetViewportShadingRatePaletteNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetViewportShadingRatePaletteNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->firstViewport, params->viewportCount, params->pShadingRatePalettes); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetViewportShadingRatePaletteNV(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t firstViewport; - uint32_t viewportCount; - PTR32 pShadingRatePalettes; - } *params = args; - const VkShadingRatePaletteNV *pShadingRatePalettes_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pShadingRatePalettes_host = convert_VkShadingRatePaletteNV_array_win32_to_host(&ctx, (const VkShadingRatePaletteNV32 *)UlongToPtr(params->pShadingRatePalettes), params->viewportCount); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetViewportShadingRatePaletteNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->firstViewport, params->viewportCount, pShadingRatePalettes_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetViewportSwizzleNV(void *args) -{ - struct vkCmdSetViewportSwizzleNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetViewportSwizzleNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->firstViewport, params->viewportCount, params->pViewportSwizzles); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetViewportSwizzleNV(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t firstViewport; - uint32_t viewportCount; - PTR32 pViewportSwizzles; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetViewportSwizzleNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->firstViewport, params->viewportCount, (const VkViewportSwizzleNV *)UlongToPtr(params->pViewportSwizzles)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetViewportWScalingEnableNV(void *args) -{ - struct vkCmdSetViewportWScalingEnableNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetViewportWScalingEnableNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->viewportWScalingEnable); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetViewportWScalingEnableNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBool32 viewportWScalingEnable; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetViewportWScalingEnableNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->viewportWScalingEnable); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetViewportWScalingNV(void *args) -{ - struct vkCmdSetViewportWScalingNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetViewportWScalingNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->firstViewport, params->viewportCount, params->pViewportWScalings); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetViewportWScalingNV(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t firstViewport; - uint32_t viewportCount; - PTR32 pViewportWScalings; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetViewportWScalingNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->firstViewport, params->viewportCount, (const VkViewportWScalingNV *)UlongToPtr(params->pViewportWScalings)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetViewportWithCount(void *args) -{ - struct vkCmdSetViewportWithCount_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetViewportWithCount(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->viewportCount, params->pViewports); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetViewportWithCount(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t viewportCount; - PTR32 pViewports; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetViewportWithCount(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->viewportCount, (const VkViewport *)UlongToPtr(params->pViewports)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSetViewportWithCountEXT(void *args) -{ - struct vkCmdSetViewportWithCountEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSetViewportWithCountEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->viewportCount, params->pViewports); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSetViewportWithCountEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t viewportCount; - PTR32 pViewports; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSetViewportWithCountEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->viewportCount, (const VkViewport *)UlongToPtr(params->pViewports)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdSubpassShadingHUAWEI(void *args) -{ - struct vkCmdSubpassShadingHUAWEI_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdSubpassShadingHUAWEI(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdSubpassShadingHUAWEI(void *args) -{ - struct - { - PTR32 commandBuffer; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdSubpassShadingHUAWEI(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer); -} - -#ifdef _WIN64 -static void thunk64_vkCmdTraceRaysIndirect2KHR(void *args) -{ - struct vkCmdTraceRaysIndirect2KHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdTraceRaysIndirect2KHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->indirectDeviceAddress); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdTraceRaysIndirect2KHR(void *args) -{ - struct - { - PTR32 commandBuffer; - VkDeviceAddress DECLSPEC_ALIGN(8) indirectDeviceAddress; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdTraceRaysIndirect2KHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->indirectDeviceAddress); -} - -#ifdef _WIN64 -static void thunk64_vkCmdTraceRaysIndirectKHR(void *args) -{ - struct vkCmdTraceRaysIndirectKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdTraceRaysIndirectKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pRaygenShaderBindingTable, params->pMissShaderBindingTable, params->pHitShaderBindingTable, params->pCallableShaderBindingTable, params->indirectDeviceAddress); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdTraceRaysIndirectKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pRaygenShaderBindingTable; - PTR32 pMissShaderBindingTable; - PTR32 pHitShaderBindingTable; - PTR32 pCallableShaderBindingTable; - VkDeviceAddress DECLSPEC_ALIGN(8) indirectDeviceAddress; - } *params = args; - VkStridedDeviceAddressRegionKHR pRaygenShaderBindingTable_host; - VkStridedDeviceAddressRegionKHR pMissShaderBindingTable_host; - VkStridedDeviceAddressRegionKHR pHitShaderBindingTable_host; - VkStridedDeviceAddressRegionKHR pCallableShaderBindingTable_host; - - convert_VkStridedDeviceAddressRegionKHR_win32_to_host((const VkStridedDeviceAddressRegionKHR32 *)UlongToPtr(params->pRaygenShaderBindingTable), &pRaygenShaderBindingTable_host); - convert_VkStridedDeviceAddressRegionKHR_win32_to_host((const VkStridedDeviceAddressRegionKHR32 *)UlongToPtr(params->pMissShaderBindingTable), &pMissShaderBindingTable_host); - convert_VkStridedDeviceAddressRegionKHR_win32_to_host((const VkStridedDeviceAddressRegionKHR32 *)UlongToPtr(params->pHitShaderBindingTable), &pHitShaderBindingTable_host); - convert_VkStridedDeviceAddressRegionKHR_win32_to_host((const VkStridedDeviceAddressRegionKHR32 *)UlongToPtr(params->pCallableShaderBindingTable), &pCallableShaderBindingTable_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdTraceRaysIndirectKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pRaygenShaderBindingTable_host, &pMissShaderBindingTable_host, &pHitShaderBindingTable_host, &pCallableShaderBindingTable_host, params->indirectDeviceAddress); -} - -#ifdef _WIN64 -static void thunk64_vkCmdTraceRaysKHR(void *args) -{ - struct vkCmdTraceRaysKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdTraceRaysKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pRaygenShaderBindingTable, params->pMissShaderBindingTable, params->pHitShaderBindingTable, params->pCallableShaderBindingTable, params->width, params->height, params->depth); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdTraceRaysKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - PTR32 pRaygenShaderBindingTable; - PTR32 pMissShaderBindingTable; - PTR32 pHitShaderBindingTable; - PTR32 pCallableShaderBindingTable; - uint32_t width; - uint32_t height; - uint32_t depth; - } *params = args; - VkStridedDeviceAddressRegionKHR pRaygenShaderBindingTable_host; - VkStridedDeviceAddressRegionKHR pMissShaderBindingTable_host; - VkStridedDeviceAddressRegionKHR pHitShaderBindingTable_host; - VkStridedDeviceAddressRegionKHR pCallableShaderBindingTable_host; - - convert_VkStridedDeviceAddressRegionKHR_win32_to_host((const VkStridedDeviceAddressRegionKHR32 *)UlongToPtr(params->pRaygenShaderBindingTable), &pRaygenShaderBindingTable_host); - convert_VkStridedDeviceAddressRegionKHR_win32_to_host((const VkStridedDeviceAddressRegionKHR32 *)UlongToPtr(params->pMissShaderBindingTable), &pMissShaderBindingTable_host); - convert_VkStridedDeviceAddressRegionKHR_win32_to_host((const VkStridedDeviceAddressRegionKHR32 *)UlongToPtr(params->pHitShaderBindingTable), &pHitShaderBindingTable_host); - convert_VkStridedDeviceAddressRegionKHR_win32_to_host((const VkStridedDeviceAddressRegionKHR32 *)UlongToPtr(params->pCallableShaderBindingTable), &pCallableShaderBindingTable_host); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdTraceRaysKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, &pRaygenShaderBindingTable_host, &pMissShaderBindingTable_host, &pHitShaderBindingTable_host, &pCallableShaderBindingTable_host, params->width, params->height, params->depth); -} - -#ifdef _WIN64 -static void thunk64_vkCmdTraceRaysNV(void *args) -{ - struct vkCmdTraceRaysNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdTraceRaysNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->raygenShaderBindingTableBuffer, params->raygenShaderBindingOffset, params->missShaderBindingTableBuffer, params->missShaderBindingOffset, params->missShaderBindingStride, params->hitShaderBindingTableBuffer, params->hitShaderBindingOffset, params->hitShaderBindingStride, params->callableShaderBindingTableBuffer, params->callableShaderBindingOffset, params->callableShaderBindingStride, params->width, params->height, params->depth); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdTraceRaysNV(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) raygenShaderBindingTableBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) raygenShaderBindingOffset; - VkBuffer DECLSPEC_ALIGN(8) missShaderBindingTableBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) missShaderBindingOffset; - VkDeviceSize DECLSPEC_ALIGN(8) missShaderBindingStride; - VkBuffer DECLSPEC_ALIGN(8) hitShaderBindingTableBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) hitShaderBindingOffset; - VkDeviceSize DECLSPEC_ALIGN(8) hitShaderBindingStride; - VkBuffer DECLSPEC_ALIGN(8) callableShaderBindingTableBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) callableShaderBindingOffset; - VkDeviceSize DECLSPEC_ALIGN(8) callableShaderBindingStride; - uint32_t width; - uint32_t height; - uint32_t depth; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdTraceRaysNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->raygenShaderBindingTableBuffer, params->raygenShaderBindingOffset, params->missShaderBindingTableBuffer, params->missShaderBindingOffset, params->missShaderBindingStride, params->hitShaderBindingTableBuffer, params->hitShaderBindingOffset, params->hitShaderBindingStride, params->callableShaderBindingTableBuffer, params->callableShaderBindingOffset, params->callableShaderBindingStride, params->width, params->height, params->depth); -} - -#ifdef _WIN64 -static void thunk64_vkCmdUpdateBuffer(void *args) -{ - struct vkCmdUpdateBuffer_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdUpdateBuffer(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->dstBuffer, params->dstOffset, params->dataSize, params->pData); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdUpdateBuffer(void *args) -{ - struct - { - PTR32 commandBuffer; - VkBuffer DECLSPEC_ALIGN(8) dstBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) dstOffset; - VkDeviceSize DECLSPEC_ALIGN(8) dataSize; - PTR32 pData; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdUpdateBuffer(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->dstBuffer, params->dstOffset, params->dataSize, (const void *)UlongToPtr(params->pData)); -} - -#ifdef _WIN64 -static void thunk64_vkCmdWaitEvents(void *args) -{ - struct vkCmdWaitEvents_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdWaitEvents(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->eventCount, params->pEvents, params->srcStageMask, params->dstStageMask, params->memoryBarrierCount, params->pMemoryBarriers, params->bufferMemoryBarrierCount, params->pBufferMemoryBarriers, params->imageMemoryBarrierCount, params->pImageMemoryBarriers); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdWaitEvents(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t eventCount; - PTR32 pEvents; - VkPipelineStageFlags srcStageMask; - VkPipelineStageFlags dstStageMask; - uint32_t memoryBarrierCount; - PTR32 pMemoryBarriers; - uint32_t bufferMemoryBarrierCount; - PTR32 pBufferMemoryBarriers; - uint32_t imageMemoryBarrierCount; - PTR32 pImageMemoryBarriers; - } *params = args; - const VkMemoryBarrier *pMemoryBarriers_host; - const VkBufferMemoryBarrier *pBufferMemoryBarriers_host; - const VkImageMemoryBarrier *pImageMemoryBarriers_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pMemoryBarriers_host = convert_VkMemoryBarrier_array_win32_to_host(&ctx, (const VkMemoryBarrier32 *)UlongToPtr(params->pMemoryBarriers), params->memoryBarrierCount); - pBufferMemoryBarriers_host = convert_VkBufferMemoryBarrier_array_win32_to_host(&ctx, (const VkBufferMemoryBarrier32 *)UlongToPtr(params->pBufferMemoryBarriers), params->bufferMemoryBarrierCount); - pImageMemoryBarriers_host = convert_VkImageMemoryBarrier_array_win32_to_host(&ctx, (const VkImageMemoryBarrier32 *)UlongToPtr(params->pImageMemoryBarriers), params->imageMemoryBarrierCount); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdWaitEvents(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->eventCount, (const VkEvent *)UlongToPtr(params->pEvents), params->srcStageMask, params->dstStageMask, params->memoryBarrierCount, pMemoryBarriers_host, params->bufferMemoryBarrierCount, pBufferMemoryBarriers_host, params->imageMemoryBarrierCount, pImageMemoryBarriers_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdWaitEvents2(void *args) -{ - struct vkCmdWaitEvents2_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdWaitEvents2(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->eventCount, params->pEvents, params->pDependencyInfos); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdWaitEvents2(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t eventCount; - PTR32 pEvents; - PTR32 pDependencyInfos; - } *params = args; - const VkDependencyInfo *pDependencyInfos_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pDependencyInfos_host = convert_VkDependencyInfo_array_win32_to_host(&ctx, (const VkDependencyInfo32 *)UlongToPtr(params->pDependencyInfos), params->eventCount); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdWaitEvents2(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->eventCount, (const VkEvent *)UlongToPtr(params->pEvents), pDependencyInfos_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdWaitEvents2KHR(void *args) -{ - struct vkCmdWaitEvents2KHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdWaitEvents2KHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->eventCount, params->pEvents, params->pDependencyInfos); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdWaitEvents2KHR(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t eventCount; - PTR32 pEvents; - PTR32 pDependencyInfos; - } *params = args; - const VkDependencyInfo *pDependencyInfos_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pDependencyInfos_host = convert_VkDependencyInfo_array_win32_to_host(&ctx, (const VkDependencyInfo32 *)UlongToPtr(params->pDependencyInfos), params->eventCount); - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdWaitEvents2KHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->eventCount, (const VkEvent *)UlongToPtr(params->pEvents), pDependencyInfos_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static void thunk64_vkCmdWriteAccelerationStructuresPropertiesKHR(void *args) -{ - struct vkCmdWriteAccelerationStructuresPropertiesKHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdWriteAccelerationStructuresPropertiesKHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->accelerationStructureCount, params->pAccelerationStructures, params->queryType, params->queryPool, params->firstQuery); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdWriteAccelerationStructuresPropertiesKHR(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t accelerationStructureCount; - PTR32 pAccelerationStructures; - VkQueryType queryType; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t firstQuery; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdWriteAccelerationStructuresPropertiesKHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->accelerationStructureCount, (const VkAccelerationStructureKHR *)UlongToPtr(params->pAccelerationStructures), params->queryType, params->queryPool, params->firstQuery); -} - -#ifdef _WIN64 -static void thunk64_vkCmdWriteAccelerationStructuresPropertiesNV(void *args) -{ - struct vkCmdWriteAccelerationStructuresPropertiesNV_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdWriteAccelerationStructuresPropertiesNV(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->accelerationStructureCount, params->pAccelerationStructures, params->queryType, params->queryPool, params->firstQuery); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdWriteAccelerationStructuresPropertiesNV(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t accelerationStructureCount; - PTR32 pAccelerationStructures; - VkQueryType queryType; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t firstQuery; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdWriteAccelerationStructuresPropertiesNV(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->accelerationStructureCount, (const VkAccelerationStructureNV *)UlongToPtr(params->pAccelerationStructures), params->queryType, params->queryPool, params->firstQuery); -} - -#ifdef _WIN64 -static void thunk64_vkCmdWriteBufferMarker2AMD(void *args) -{ - struct vkCmdWriteBufferMarker2AMD_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdWriteBufferMarker2AMD(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->stage, params->dstBuffer, params->dstOffset, params->marker); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdWriteBufferMarker2AMD(void *args) -{ - struct - { - PTR32 commandBuffer; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) stage; - VkBuffer DECLSPEC_ALIGN(8) dstBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) dstOffset; - uint32_t marker; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdWriteBufferMarker2AMD(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->stage, params->dstBuffer, params->dstOffset, params->marker); -} - -#ifdef _WIN64 -static void thunk64_vkCmdWriteBufferMarkerAMD(void *args) -{ - struct vkCmdWriteBufferMarkerAMD_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdWriteBufferMarkerAMD(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pipelineStage, params->dstBuffer, params->dstOffset, params->marker); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdWriteBufferMarkerAMD(void *args) -{ - struct - { - PTR32 commandBuffer; - VkPipelineStageFlagBits pipelineStage; - VkBuffer DECLSPEC_ALIGN(8) dstBuffer; - VkDeviceSize DECLSPEC_ALIGN(8) dstOffset; - uint32_t marker; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdWriteBufferMarkerAMD(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->pipelineStage, params->dstBuffer, params->dstOffset, params->marker); -} - -#ifdef _WIN64 -static void thunk64_vkCmdWriteMicromapsPropertiesEXT(void *args) -{ - struct vkCmdWriteMicromapsPropertiesEXT_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdWriteMicromapsPropertiesEXT(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->micromapCount, params->pMicromaps, params->queryType, params->queryPool, params->firstQuery); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdWriteMicromapsPropertiesEXT(void *args) -{ - struct - { - PTR32 commandBuffer; - uint32_t micromapCount; - PTR32 pMicromaps; - VkQueryType queryType; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t firstQuery; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdWriteMicromapsPropertiesEXT(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->micromapCount, (const VkMicromapEXT *)UlongToPtr(params->pMicromaps), params->queryType, params->queryPool, params->firstQuery); -} - -#ifdef _WIN64 -static void thunk64_vkCmdWriteTimestamp(void *args) -{ - struct vkCmdWriteTimestamp_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdWriteTimestamp(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->pipelineStage, params->queryPool, params->query); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdWriteTimestamp(void *args) -{ - struct - { - PTR32 commandBuffer; - VkPipelineStageFlagBits pipelineStage; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t query; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdWriteTimestamp(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->pipelineStage, params->queryPool, params->query); -} - -#ifdef _WIN64 -static void thunk64_vkCmdWriteTimestamp2(void *args) -{ - struct vkCmdWriteTimestamp2_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdWriteTimestamp2(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->stage, params->queryPool, params->query); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdWriteTimestamp2(void *args) -{ - struct - { - PTR32 commandBuffer; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) stage; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t query; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdWriteTimestamp2(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->stage, params->queryPool, params->query); -} - -#ifdef _WIN64 -static void thunk64_vkCmdWriteTimestamp2KHR(void *args) -{ - struct vkCmdWriteTimestamp2KHR_params *params = args; - - wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkCmdWriteTimestamp2KHR(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->stage, params->queryPool, params->query); -} -#endif /* _WIN64 */ - -static void thunk32_vkCmdWriteTimestamp2KHR(void *args) -{ - struct - { - PTR32 commandBuffer; - VkPipelineStageFlags2 DECLSPEC_ALIGN(8) stage; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t query; - } *params = args; - - wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkCmdWriteTimestamp2KHR(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->stage, params->queryPool, params->query); -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCompileDeferredNV(void *args) -{ - struct vkCompileDeferredNV_params *params = args; - - TRACE("%p, 0x%s, %u\n", params->device, wine_dbgstr_longlong(params->pipeline), params->shader); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCompileDeferredNV(wine_device_from_handle(params->device)->device, params->pipeline, params->shader); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCompileDeferredNV(void *args) -{ - struct - { - PTR32 device; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - uint32_t shader; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %u\n", params->device, wine_dbgstr_longlong(params->pipeline), params->shader); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCompileDeferredNV(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->pipeline, params->shader); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCopyAccelerationStructureKHR(void *args) -{ - struct vkCopyAccelerationStructureKHR_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->deferredOperation), params->pInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCopyAccelerationStructureKHR(wine_device_from_handle(params->device)->device, params->deferredOperation, params->pInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCopyAccelerationStructureKHR(void *args) -{ - struct - { - PTR32 device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - PTR32 pInfo; - VkResult result; - } *params = args; - VkCopyAccelerationStructureInfoKHR pInfo_host; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->deferredOperation), params->pInfo); - - convert_VkCopyAccelerationStructureInfoKHR_win32_to_host((const VkCopyAccelerationStructureInfoKHR32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCopyAccelerationStructureKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->deferredOperation, &pInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCopyAccelerationStructureToMemoryKHR(void *args) -{ - struct vkCopyAccelerationStructureToMemoryKHR_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->deferredOperation), params->pInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCopyAccelerationStructureToMemoryKHR(wine_device_from_handle(params->device)->device, params->deferredOperation, params->pInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCopyAccelerationStructureToMemoryKHR(void *args) -{ - struct - { - PTR32 device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - PTR32 pInfo; - VkResult result; - } *params = args; - VkCopyAccelerationStructureToMemoryInfoKHR pInfo_host; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->deferredOperation), params->pInfo); - - convert_VkCopyAccelerationStructureToMemoryInfoKHR_win32_to_host((const VkCopyAccelerationStructureToMemoryInfoKHR32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCopyAccelerationStructureToMemoryKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->deferredOperation, &pInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCopyMemoryToAccelerationStructureKHR(void *args) -{ - struct vkCopyMemoryToAccelerationStructureKHR_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->deferredOperation), params->pInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCopyMemoryToAccelerationStructureKHR(wine_device_from_handle(params->device)->device, params->deferredOperation, params->pInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCopyMemoryToAccelerationStructureKHR(void *args) -{ - struct - { - PTR32 device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - PTR32 pInfo; - VkResult result; - } *params = args; - VkCopyMemoryToAccelerationStructureInfoKHR pInfo_host; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->deferredOperation), params->pInfo); - - convert_VkCopyMemoryToAccelerationStructureInfoKHR_win32_to_host((const VkCopyMemoryToAccelerationStructureInfoKHR32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCopyMemoryToAccelerationStructureKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->deferredOperation, &pInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCopyMemoryToMicromapEXT(void *args) -{ - struct vkCopyMemoryToMicromapEXT_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->deferredOperation), params->pInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCopyMemoryToMicromapEXT(wine_device_from_handle(params->device)->device, params->deferredOperation, params->pInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCopyMemoryToMicromapEXT(void *args) -{ - struct - { - PTR32 device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - PTR32 pInfo; - VkResult result; - } *params = args; - VkCopyMemoryToMicromapInfoEXT pInfo_host; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->deferredOperation), params->pInfo); - - convert_VkCopyMemoryToMicromapInfoEXT_win32_to_host((const VkCopyMemoryToMicromapInfoEXT32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCopyMemoryToMicromapEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->deferredOperation, &pInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCopyMicromapEXT(void *args) -{ - struct vkCopyMicromapEXT_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->deferredOperation), params->pInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCopyMicromapEXT(wine_device_from_handle(params->device)->device, params->deferredOperation, params->pInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCopyMicromapEXT(void *args) -{ - struct - { - PTR32 device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - PTR32 pInfo; - VkResult result; - } *params = args; - VkCopyMicromapInfoEXT pInfo_host; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->deferredOperation), params->pInfo); - - convert_VkCopyMicromapInfoEXT_win32_to_host((const VkCopyMicromapInfoEXT32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCopyMicromapEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->deferredOperation, &pInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCopyMicromapToMemoryEXT(void *args) -{ - struct vkCopyMicromapToMemoryEXT_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->deferredOperation), params->pInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCopyMicromapToMemoryEXT(wine_device_from_handle(params->device)->device, params->deferredOperation, params->pInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCopyMicromapToMemoryEXT(void *args) -{ - struct - { - PTR32 device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - PTR32 pInfo; - VkResult result; - } *params = args; - VkCopyMicromapToMemoryInfoEXT pInfo_host; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->deferredOperation), params->pInfo); - - convert_VkCopyMicromapToMemoryInfoEXT_win32_to_host((const VkCopyMicromapToMemoryInfoEXT32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCopyMicromapToMemoryEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->deferredOperation, &pInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateAccelerationStructureKHR(void *args) -{ - struct vkCreateAccelerationStructureKHR_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pAccelerationStructure); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateAccelerationStructureKHR(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pAccelerationStructure); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateAccelerationStructureKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pAccelerationStructure; - VkResult result; - } *params = args; - VkAccelerationStructureCreateInfoKHR pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pAccelerationStructure); - - init_conversion_context(&ctx); - convert_VkAccelerationStructureCreateInfoKHR_win32_to_host(&ctx, (const VkAccelerationStructureCreateInfoKHR32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateAccelerationStructureKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkAccelerationStructureKHR *)UlongToPtr(params->pAccelerationStructure)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateAccelerationStructureNV(void *args) -{ - struct vkCreateAccelerationStructureNV_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pAccelerationStructure); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateAccelerationStructureNV(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pAccelerationStructure); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateAccelerationStructureNV(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pAccelerationStructure; - VkResult result; - } *params = args; - VkAccelerationStructureCreateInfoNV pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pAccelerationStructure); - - init_conversion_context(&ctx); - convert_VkAccelerationStructureCreateInfoNV_win32_to_host(&ctx, (const VkAccelerationStructureCreateInfoNV32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateAccelerationStructureNV(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkAccelerationStructureNV *)UlongToPtr(params->pAccelerationStructure)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateBuffer(void *args) -{ - struct vkCreateBuffer_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pBuffer); - - params->result = wine_vkCreateBuffer(params->device, params->pCreateInfo, params->pAllocator, params->pBuffer); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateBuffer(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pBuffer; - VkResult result; - } *params = args; - VkBufferCreateInfo pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pBuffer); - - init_conversion_context(&ctx); - convert_VkBufferCreateInfo_win32_to_host(&ctx, (const VkBufferCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_vkCreateBuffer((VkDevice)UlongToPtr(params->device), &pCreateInfo_host, (const VkAllocationCallbacks *)UlongToPtr(params->pAllocator), (VkBuffer *)UlongToPtr(params->pBuffer)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateBufferView(void *args) -{ - struct vkCreateBufferView_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pView); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateBufferView(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pView); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateBufferView(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pView; - VkResult result; - } *params = args; - VkBufferViewCreateInfo pCreateInfo_host; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pView); - - convert_VkBufferViewCreateInfo_win32_to_host((const VkBufferViewCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateBufferView(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkBufferView *)UlongToPtr(params->pView)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateCommandPool(void *args) -{ - struct vkCreateCommandPool_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pCommandPool); - - params->result = wine_vkCreateCommandPool(params->device, params->pCreateInfo, params->pAllocator, params->pCommandPool, params->client_ptr); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateCommandPool(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pCommandPool; - PTR32 client_ptr; - VkResult result; - } *params = args; - VkCommandPoolCreateInfo pCreateInfo_host; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pCommandPool); - - convert_VkCommandPoolCreateInfo_win32_to_host((const VkCommandPoolCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_vkCreateCommandPool((VkDevice)UlongToPtr(params->device), &pCreateInfo_host, (const VkAllocationCallbacks *)UlongToPtr(params->pAllocator), (VkCommandPool *)UlongToPtr(params->pCommandPool), UlongToPtr(params->client_ptr)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateComputePipelines(void *args) -{ - struct vkCreateComputePipelines_params *params = args; - const VkComputePipelineCreateInfo *pCreateInfos_host; - struct conversion_context ctx; - - TRACE("%p, 0x%s, %u, %p, %p, %p\n", params->device, wine_dbgstr_longlong(params->pipelineCache), params->createInfoCount, params->pCreateInfos, params->pAllocator, params->pPipelines); - - init_conversion_context(&ctx); - pCreateInfos_host = convert_VkComputePipelineCreateInfo_array_win64_to_host(&ctx, params->pCreateInfos, params->createInfoCount); - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateComputePipelines(wine_device_from_handle(params->device)->device, params->pipelineCache, params->createInfoCount, pCreateInfos_host, NULL, params->pPipelines); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateComputePipelines(void *args) -{ - struct - { - PTR32 device; - VkPipelineCache DECLSPEC_ALIGN(8) pipelineCache; - uint32_t createInfoCount; - PTR32 pCreateInfos; - PTR32 pAllocator; - PTR32 pPipelines; - VkResult result; - } *params = args; - const VkComputePipelineCreateInfo *pCreateInfos_host; - struct conversion_context ctx; - - TRACE("%#x, 0x%s, %u, %#x, %#x, %#x\n", params->device, wine_dbgstr_longlong(params->pipelineCache), params->createInfoCount, params->pCreateInfos, params->pAllocator, params->pPipelines); - - init_conversion_context(&ctx); - pCreateInfos_host = convert_VkComputePipelineCreateInfo_array_win32_to_host(&ctx, (const VkComputePipelineCreateInfo32 *)UlongToPtr(params->pCreateInfos), params->createInfoCount); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateComputePipelines(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->pipelineCache, params->createInfoCount, pCreateInfos_host, NULL, (VkPipeline *)UlongToPtr(params->pPipelines)); - convert_VkComputePipelineCreateInfo_array_host_to_win32(pCreateInfos_host, (const VkComputePipelineCreateInfo32 *)UlongToPtr(params->pCreateInfos), params->createInfoCount); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateCuFunctionNVX(void *args) -{ - struct vkCreateCuFunctionNVX_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pFunction); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateCuFunctionNVX(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pFunction); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateCuFunctionNVX(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pFunction; - VkResult result; - } *params = args; - VkCuFunctionCreateInfoNVX pCreateInfo_host; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pFunction); - - convert_VkCuFunctionCreateInfoNVX_win32_to_host((const VkCuFunctionCreateInfoNVX32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateCuFunctionNVX(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkCuFunctionNVX *)UlongToPtr(params->pFunction)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateCuModuleNVX(void *args) -{ - struct vkCreateCuModuleNVX_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pModule); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateCuModuleNVX(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pModule); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateCuModuleNVX(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pModule; - VkResult result; - } *params = args; - VkCuModuleCreateInfoNVX pCreateInfo_host; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pModule); - - convert_VkCuModuleCreateInfoNVX_win32_to_host((const VkCuModuleCreateInfoNVX32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateCuModuleNVX(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkCuModuleNVX *)UlongToPtr(params->pModule)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateDebugReportCallbackEXT(void *args) -{ - struct vkCreateDebugReportCallbackEXT_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->instance, params->pCreateInfo, params->pAllocator, params->pCallback); - - params->result = wine_vkCreateDebugReportCallbackEXT(params->instance, params->pCreateInfo, params->pAllocator, params->pCallback); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateDebugReportCallbackEXT(void *args) -{ - struct - { - PTR32 instance; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pCallback; - VkResult result; - } *params = args; - VkDebugReportCallbackCreateInfoEXT pCreateInfo_host; - - TRACE("%#x, %#x, %#x, %#x\n", params->instance, params->pCreateInfo, params->pAllocator, params->pCallback); - - convert_VkDebugReportCallbackCreateInfoEXT_win32_to_host((const VkDebugReportCallbackCreateInfoEXT32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_vkCreateDebugReportCallbackEXT((VkInstance)UlongToPtr(params->instance), &pCreateInfo_host, (const VkAllocationCallbacks *)UlongToPtr(params->pAllocator), (VkDebugReportCallbackEXT *)UlongToPtr(params->pCallback)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateDebugUtilsMessengerEXT(void *args) -{ - struct vkCreateDebugUtilsMessengerEXT_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->instance, params->pCreateInfo, params->pAllocator, params->pMessenger); - - params->result = wine_vkCreateDebugUtilsMessengerEXT(params->instance, params->pCreateInfo, params->pAllocator, params->pMessenger); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateDebugUtilsMessengerEXT(void *args) -{ - struct - { - PTR32 instance; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pMessenger; - VkResult result; - } *params = args; - VkDebugUtilsMessengerCreateInfoEXT pCreateInfo_host; - - TRACE("%#x, %#x, %#x, %#x\n", params->instance, params->pCreateInfo, params->pAllocator, params->pMessenger); - - convert_VkDebugUtilsMessengerCreateInfoEXT_win32_to_host((const VkDebugUtilsMessengerCreateInfoEXT32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_vkCreateDebugUtilsMessengerEXT((VkInstance)UlongToPtr(params->instance), &pCreateInfo_host, (const VkAllocationCallbacks *)UlongToPtr(params->pAllocator), (VkDebugUtilsMessengerEXT *)UlongToPtr(params->pMessenger)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateDeferredOperationKHR(void *args) -{ - struct vkCreateDeferredOperationKHR_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pAllocator, params->pDeferredOperation); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateDeferredOperationKHR(wine_device_from_handle(params->device)->device, NULL, params->pDeferredOperation); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateDeferredOperationKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pAllocator; - PTR32 pDeferredOperation; - VkResult result; - } *params = args; - - TRACE("%#x, %#x, %#x\n", params->device, params->pAllocator, params->pDeferredOperation); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateDeferredOperationKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, NULL, (VkDeferredOperationKHR *)UlongToPtr(params->pDeferredOperation)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateDescriptorPool(void *args) -{ - struct vkCreateDescriptorPool_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pDescriptorPool); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateDescriptorPool(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pDescriptorPool); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateDescriptorPool(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pDescriptorPool; - VkResult result; - } *params = args; - VkDescriptorPoolCreateInfo pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pDescriptorPool); - - init_conversion_context(&ctx); - convert_VkDescriptorPoolCreateInfo_win32_to_host(&ctx, (const VkDescriptorPoolCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateDescriptorPool(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkDescriptorPool *)UlongToPtr(params->pDescriptorPool)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateDescriptorSetLayout(void *args) -{ - struct vkCreateDescriptorSetLayout_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pSetLayout); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateDescriptorSetLayout(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pSetLayout); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateDescriptorSetLayout(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pSetLayout; - VkResult result; - } *params = args; - VkDescriptorSetLayoutCreateInfo pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pSetLayout); - - init_conversion_context(&ctx); - convert_VkDescriptorSetLayoutCreateInfo_win32_to_host(&ctx, (const VkDescriptorSetLayoutCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateDescriptorSetLayout(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkDescriptorSetLayout *)UlongToPtr(params->pSetLayout)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateDescriptorUpdateTemplate(void *args) -{ - struct vkCreateDescriptorUpdateTemplate_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pDescriptorUpdateTemplate); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateDescriptorUpdateTemplate(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pDescriptorUpdateTemplate); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateDescriptorUpdateTemplate(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pDescriptorUpdateTemplate; - VkResult result; - } *params = args; - VkDescriptorUpdateTemplateCreateInfo pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pDescriptorUpdateTemplate); - - init_conversion_context(&ctx); - convert_VkDescriptorUpdateTemplateCreateInfo_win32_to_host(&ctx, (const VkDescriptorUpdateTemplateCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateDescriptorUpdateTemplate(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkDescriptorUpdateTemplate *)UlongToPtr(params->pDescriptorUpdateTemplate)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateDescriptorUpdateTemplateKHR(void *args) -{ - struct vkCreateDescriptorUpdateTemplateKHR_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pDescriptorUpdateTemplate); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateDescriptorUpdateTemplateKHR(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pDescriptorUpdateTemplate); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateDescriptorUpdateTemplateKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pDescriptorUpdateTemplate; - VkResult result; - } *params = args; - VkDescriptorUpdateTemplateCreateInfo pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pDescriptorUpdateTemplate); - - init_conversion_context(&ctx); - convert_VkDescriptorUpdateTemplateCreateInfo_win32_to_host(&ctx, (const VkDescriptorUpdateTemplateCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateDescriptorUpdateTemplateKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkDescriptorUpdateTemplate *)UlongToPtr(params->pDescriptorUpdateTemplate)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateDevice(void *args) -{ - struct vkCreateDevice_params *params = args; - VkDeviceCreateInfo pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%p, %p, %p, %p\n", params->physicalDevice, params->pCreateInfo, params->pAllocator, params->pDevice); - - init_conversion_context(&ctx); - convert_VkDeviceCreateInfo_win64_to_host(&ctx, params->pCreateInfo, &pCreateInfo_host); - params->result = wine_vkCreateDevice(params->physicalDevice, &pCreateInfo_host, params->pAllocator, params->pDevice, params->client_ptr); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateDevice(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pDevice; - PTR32 client_ptr; - VkResult result; - } *params = args; - VkDeviceCreateInfo pCreateInfo_host; - VkDevice pDevice_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->physicalDevice, params->pCreateInfo, params->pAllocator, params->pDevice); - - init_conversion_context(&ctx); - convert_VkDeviceCreateInfo_win32_to_host(&ctx, (const VkDeviceCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - pDevice_host = UlongToPtr(*(PTR32 *)UlongToPtr(params->pDevice)); - params->result = wine_vkCreateDevice((VkPhysicalDevice)UlongToPtr(params->physicalDevice), &pCreateInfo_host, (const VkAllocationCallbacks *)UlongToPtr(params->pAllocator), &pDevice_host, UlongToPtr(params->client_ptr)); - *(PTR32 *)UlongToPtr(params->pDevice) = PtrToUlong(pDevice_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateEvent(void *args) -{ - struct vkCreateEvent_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pEvent); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateEvent(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pEvent); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateEvent(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pEvent; - VkResult result; - } *params = args; - VkEventCreateInfo pCreateInfo_host; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pEvent); - - convert_VkEventCreateInfo_win32_to_host((const VkEventCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateEvent(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkEvent *)UlongToPtr(params->pEvent)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateFence(void *args) -{ - struct vkCreateFence_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pFence); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateFence(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pFence); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateFence(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pFence; - VkResult result; - } *params = args; - VkFenceCreateInfo pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pFence); - - init_conversion_context(&ctx); - convert_VkFenceCreateInfo_win32_to_host(&ctx, (const VkFenceCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateFence(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkFence *)UlongToPtr(params->pFence)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateFramebuffer(void *args) -{ - struct vkCreateFramebuffer_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pFramebuffer); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateFramebuffer(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pFramebuffer); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateFramebuffer(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pFramebuffer; - VkResult result; - } *params = args; - VkFramebufferCreateInfo pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pFramebuffer); - - init_conversion_context(&ctx); - convert_VkFramebufferCreateInfo_win32_to_host(&ctx, (const VkFramebufferCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateFramebuffer(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkFramebuffer *)UlongToPtr(params->pFramebuffer)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateGraphicsPipelines(void *args) -{ - struct vkCreateGraphicsPipelines_params *params = args; - const VkGraphicsPipelineCreateInfo *pCreateInfos_host; - struct conversion_context ctx; - - TRACE("%p, 0x%s, %u, %p, %p, %p\n", params->device, wine_dbgstr_longlong(params->pipelineCache), params->createInfoCount, params->pCreateInfos, params->pAllocator, params->pPipelines); - - init_conversion_context(&ctx); - pCreateInfos_host = convert_VkGraphicsPipelineCreateInfo_array_win64_to_host(&ctx, params->pCreateInfos, params->createInfoCount); - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateGraphicsPipelines(wine_device_from_handle(params->device)->device, params->pipelineCache, params->createInfoCount, pCreateInfos_host, NULL, params->pPipelines); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateGraphicsPipelines(void *args) -{ - struct - { - PTR32 device; - VkPipelineCache DECLSPEC_ALIGN(8) pipelineCache; - uint32_t createInfoCount; - PTR32 pCreateInfos; - PTR32 pAllocator; - PTR32 pPipelines; - VkResult result; - } *params = args; - const VkGraphicsPipelineCreateInfo *pCreateInfos_host; - struct conversion_context ctx; - - TRACE("%#x, 0x%s, %u, %#x, %#x, %#x\n", params->device, wine_dbgstr_longlong(params->pipelineCache), params->createInfoCount, params->pCreateInfos, params->pAllocator, params->pPipelines); - - init_conversion_context(&ctx); - pCreateInfos_host = convert_VkGraphicsPipelineCreateInfo_array_win32_to_host(&ctx, (const VkGraphicsPipelineCreateInfo32 *)UlongToPtr(params->pCreateInfos), params->createInfoCount); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateGraphicsPipelines(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->pipelineCache, params->createInfoCount, pCreateInfos_host, NULL, (VkPipeline *)UlongToPtr(params->pPipelines)); - convert_VkGraphicsPipelineCreateInfo_array_host_to_win32(pCreateInfos_host, (const VkGraphicsPipelineCreateInfo32 *)UlongToPtr(params->pCreateInfos), params->createInfoCount); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateImage(void *args) -{ - struct vkCreateImage_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pImage); - - params->result = wine_vkCreateImage(params->device, params->pCreateInfo, params->pAllocator, params->pImage); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateImage(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pImage; - VkResult result; - } *params = args; - VkImageCreateInfo pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pImage); - - init_conversion_context(&ctx); - convert_VkImageCreateInfo_win32_to_host(&ctx, (const VkImageCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_vkCreateImage((VkDevice)UlongToPtr(params->device), &pCreateInfo_host, (const VkAllocationCallbacks *)UlongToPtr(params->pAllocator), (VkImage *)UlongToPtr(params->pImage)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateImageView(void *args) -{ - struct vkCreateImageView_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pView); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateImageView(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pView); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateImageView(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pView; - VkResult result; - } *params = args; - VkImageViewCreateInfo pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pView); - - init_conversion_context(&ctx); - convert_VkImageViewCreateInfo_win32_to_host(&ctx, (const VkImageViewCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateImageView(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkImageView *)UlongToPtr(params->pView)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateIndirectCommandsLayoutNV(void *args) -{ - struct vkCreateIndirectCommandsLayoutNV_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pIndirectCommandsLayout); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateIndirectCommandsLayoutNV(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pIndirectCommandsLayout); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateIndirectCommandsLayoutNV(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pIndirectCommandsLayout; - VkResult result; - } *params = args; - VkIndirectCommandsLayoutCreateInfoNV pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pIndirectCommandsLayout); - - init_conversion_context(&ctx); - convert_VkIndirectCommandsLayoutCreateInfoNV_win32_to_host(&ctx, (const VkIndirectCommandsLayoutCreateInfoNV32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateIndirectCommandsLayoutNV(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkIndirectCommandsLayoutNV *)UlongToPtr(params->pIndirectCommandsLayout)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateInstance(void *args) -{ - struct vkCreateInstance_params *params = args; - VkInstanceCreateInfo pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%p, %p, %p\n", params->pCreateInfo, params->pAllocator, params->pInstance); - - init_conversion_context(&ctx); - convert_VkInstanceCreateInfo_win64_to_host(&ctx, params->pCreateInfo, &pCreateInfo_host); - params->result = wine_vkCreateInstance(&pCreateInfo_host, params->pAllocator, params->pInstance, params->client_ptr); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateInstance(void *args) -{ - struct - { - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pInstance; - PTR32 client_ptr; - VkResult result; - } *params = args; - VkInstanceCreateInfo pCreateInfo_host; - VkInstance pInstance_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->pCreateInfo, params->pAllocator, params->pInstance); - - init_conversion_context(&ctx); - convert_VkInstanceCreateInfo_win32_to_host(&ctx, (const VkInstanceCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - pInstance_host = UlongToPtr(*(PTR32 *)UlongToPtr(params->pInstance)); - params->result = wine_vkCreateInstance(&pCreateInfo_host, (const VkAllocationCallbacks *)UlongToPtr(params->pAllocator), &pInstance_host, UlongToPtr(params->client_ptr)); - *(PTR32 *)UlongToPtr(params->pInstance) = PtrToUlong(pInstance_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateMicromapEXT(void *args) -{ - struct vkCreateMicromapEXT_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pMicromap); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateMicromapEXT(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pMicromap); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateMicromapEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pMicromap; - VkResult result; - } *params = args; - VkMicromapCreateInfoEXT pCreateInfo_host; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pMicromap); - - convert_VkMicromapCreateInfoEXT_win32_to_host((const VkMicromapCreateInfoEXT32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateMicromapEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkMicromapEXT *)UlongToPtr(params->pMicromap)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateOpticalFlowSessionNV(void *args) -{ - struct vkCreateOpticalFlowSessionNV_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pSession); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateOpticalFlowSessionNV(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pSession); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateOpticalFlowSessionNV(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pSession; - VkResult result; - } *params = args; - VkOpticalFlowSessionCreateInfoNV pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pSession); - - init_conversion_context(&ctx); - convert_VkOpticalFlowSessionCreateInfoNV_win32_to_host(&ctx, (const VkOpticalFlowSessionCreateInfoNV32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateOpticalFlowSessionNV(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkOpticalFlowSessionNV *)UlongToPtr(params->pSession)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreatePipelineCache(void *args) -{ - struct vkCreatePipelineCache_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pPipelineCache); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreatePipelineCache(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pPipelineCache); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreatePipelineCache(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pPipelineCache; - VkResult result; - } *params = args; - VkPipelineCacheCreateInfo pCreateInfo_host; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pPipelineCache); - - convert_VkPipelineCacheCreateInfo_win32_to_host((const VkPipelineCacheCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreatePipelineCache(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkPipelineCache *)UlongToPtr(params->pPipelineCache)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreatePipelineLayout(void *args) -{ - struct vkCreatePipelineLayout_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pPipelineLayout); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreatePipelineLayout(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pPipelineLayout); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreatePipelineLayout(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pPipelineLayout; - VkResult result; - } *params = args; - VkPipelineLayoutCreateInfo pCreateInfo_host; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pPipelineLayout); - - convert_VkPipelineLayoutCreateInfo_win32_to_host((const VkPipelineLayoutCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreatePipelineLayout(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkPipelineLayout *)UlongToPtr(params->pPipelineLayout)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreatePrivateDataSlot(void *args) -{ - struct vkCreatePrivateDataSlot_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pPrivateDataSlot); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreatePrivateDataSlot(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pPrivateDataSlot); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreatePrivateDataSlot(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pPrivateDataSlot; - VkResult result; - } *params = args; - VkPrivateDataSlotCreateInfo pCreateInfo_host; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pPrivateDataSlot); - - convert_VkPrivateDataSlotCreateInfo_win32_to_host((const VkPrivateDataSlotCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreatePrivateDataSlot(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkPrivateDataSlot *)UlongToPtr(params->pPrivateDataSlot)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreatePrivateDataSlotEXT(void *args) -{ - struct vkCreatePrivateDataSlotEXT_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pPrivateDataSlot); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreatePrivateDataSlotEXT(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pPrivateDataSlot); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreatePrivateDataSlotEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pPrivateDataSlot; - VkResult result; - } *params = args; - VkPrivateDataSlotCreateInfo pCreateInfo_host; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pPrivateDataSlot); - - convert_VkPrivateDataSlotCreateInfo_win32_to_host((const VkPrivateDataSlotCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreatePrivateDataSlotEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkPrivateDataSlot *)UlongToPtr(params->pPrivateDataSlot)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateQueryPool(void *args) -{ - struct vkCreateQueryPool_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pQueryPool); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateQueryPool(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pQueryPool); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateQueryPool(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pQueryPool; - VkResult result; - } *params = args; - VkQueryPoolCreateInfo pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pQueryPool); - - init_conversion_context(&ctx); - convert_VkQueryPoolCreateInfo_win32_to_host(&ctx, (const VkQueryPoolCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateQueryPool(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkQueryPool *)UlongToPtr(params->pQueryPool)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateRayTracingPipelinesKHR(void *args) -{ - struct vkCreateRayTracingPipelinesKHR_params *params = args; - const VkRayTracingPipelineCreateInfoKHR *pCreateInfos_host; - struct conversion_context ctx; - - TRACE("%p, 0x%s, 0x%s, %u, %p, %p, %p\n", params->device, wine_dbgstr_longlong(params->deferredOperation), wine_dbgstr_longlong(params->pipelineCache), params->createInfoCount, params->pCreateInfos, params->pAllocator, params->pPipelines); - - init_conversion_context(&ctx); - pCreateInfos_host = convert_VkRayTracingPipelineCreateInfoKHR_array_win64_to_host(&ctx, params->pCreateInfos, params->createInfoCount); - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateRayTracingPipelinesKHR(wine_device_from_handle(params->device)->device, params->deferredOperation, params->pipelineCache, params->createInfoCount, pCreateInfos_host, NULL, params->pPipelines); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateRayTracingPipelinesKHR(void *args) -{ - struct - { - PTR32 device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) deferredOperation; - VkPipelineCache DECLSPEC_ALIGN(8) pipelineCache; - uint32_t createInfoCount; - PTR32 pCreateInfos; - PTR32 pAllocator; - PTR32 pPipelines; - VkResult result; - } *params = args; - const VkRayTracingPipelineCreateInfoKHR *pCreateInfos_host; - struct conversion_context ctx; - - TRACE("%#x, 0x%s, 0x%s, %u, %#x, %#x, %#x\n", params->device, wine_dbgstr_longlong(params->deferredOperation), wine_dbgstr_longlong(params->pipelineCache), params->createInfoCount, params->pCreateInfos, params->pAllocator, params->pPipelines); - - init_conversion_context(&ctx); - pCreateInfos_host = convert_VkRayTracingPipelineCreateInfoKHR_array_win32_to_host(&ctx, (const VkRayTracingPipelineCreateInfoKHR32 *)UlongToPtr(params->pCreateInfos), params->createInfoCount); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateRayTracingPipelinesKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->deferredOperation, params->pipelineCache, params->createInfoCount, pCreateInfos_host, NULL, (VkPipeline *)UlongToPtr(params->pPipelines)); - convert_VkRayTracingPipelineCreateInfoKHR_array_host_to_win32(pCreateInfos_host, (const VkRayTracingPipelineCreateInfoKHR32 *)UlongToPtr(params->pCreateInfos), params->createInfoCount); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateRayTracingPipelinesNV(void *args) -{ - struct vkCreateRayTracingPipelinesNV_params *params = args; - const VkRayTracingPipelineCreateInfoNV *pCreateInfos_host; - struct conversion_context ctx; - - TRACE("%p, 0x%s, %u, %p, %p, %p\n", params->device, wine_dbgstr_longlong(params->pipelineCache), params->createInfoCount, params->pCreateInfos, params->pAllocator, params->pPipelines); - - init_conversion_context(&ctx); - pCreateInfos_host = convert_VkRayTracingPipelineCreateInfoNV_array_win64_to_host(&ctx, params->pCreateInfos, params->createInfoCount); - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateRayTracingPipelinesNV(wine_device_from_handle(params->device)->device, params->pipelineCache, params->createInfoCount, pCreateInfos_host, NULL, params->pPipelines); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateRayTracingPipelinesNV(void *args) -{ - struct - { - PTR32 device; - VkPipelineCache DECLSPEC_ALIGN(8) pipelineCache; - uint32_t createInfoCount; - PTR32 pCreateInfos; - PTR32 pAllocator; - PTR32 pPipelines; - VkResult result; - } *params = args; - const VkRayTracingPipelineCreateInfoNV *pCreateInfos_host; - struct conversion_context ctx; - - TRACE("%#x, 0x%s, %u, %#x, %#x, %#x\n", params->device, wine_dbgstr_longlong(params->pipelineCache), params->createInfoCount, params->pCreateInfos, params->pAllocator, params->pPipelines); - - init_conversion_context(&ctx); - pCreateInfos_host = convert_VkRayTracingPipelineCreateInfoNV_array_win32_to_host(&ctx, (const VkRayTracingPipelineCreateInfoNV32 *)UlongToPtr(params->pCreateInfos), params->createInfoCount); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateRayTracingPipelinesNV(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->pipelineCache, params->createInfoCount, pCreateInfos_host, NULL, (VkPipeline *)UlongToPtr(params->pPipelines)); - convert_VkRayTracingPipelineCreateInfoNV_array_host_to_win32(pCreateInfos_host, (const VkRayTracingPipelineCreateInfoNV32 *)UlongToPtr(params->pCreateInfos), params->createInfoCount); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateRenderPass(void *args) -{ - struct vkCreateRenderPass_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pRenderPass); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateRenderPass(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pRenderPass); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateRenderPass(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pRenderPass; - VkResult result; - } *params = args; - VkRenderPassCreateInfo pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pRenderPass); - - init_conversion_context(&ctx); - convert_VkRenderPassCreateInfo_win32_to_host(&ctx, (const VkRenderPassCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateRenderPass(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkRenderPass *)UlongToPtr(params->pRenderPass)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateRenderPass2(void *args) -{ - struct vkCreateRenderPass2_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pRenderPass); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateRenderPass2(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pRenderPass); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateRenderPass2(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pRenderPass; - VkResult result; - } *params = args; - VkRenderPassCreateInfo2 pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pRenderPass); - - init_conversion_context(&ctx); - convert_VkRenderPassCreateInfo2_win32_to_host(&ctx, (const VkRenderPassCreateInfo232 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateRenderPass2(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkRenderPass *)UlongToPtr(params->pRenderPass)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateRenderPass2KHR(void *args) -{ - struct vkCreateRenderPass2KHR_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pRenderPass); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateRenderPass2KHR(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pRenderPass); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateRenderPass2KHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pRenderPass; - VkResult result; - } *params = args; - VkRenderPassCreateInfo2 pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pRenderPass); - - init_conversion_context(&ctx); - convert_VkRenderPassCreateInfo2_win32_to_host(&ctx, (const VkRenderPassCreateInfo232 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateRenderPass2KHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkRenderPass *)UlongToPtr(params->pRenderPass)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateSampler(void *args) -{ - struct vkCreateSampler_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pSampler); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateSampler(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pSampler); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateSampler(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pSampler; - VkResult result; - } *params = args; - VkSamplerCreateInfo pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pSampler); - - init_conversion_context(&ctx); - convert_VkSamplerCreateInfo_win32_to_host(&ctx, (const VkSamplerCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateSampler(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkSampler *)UlongToPtr(params->pSampler)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateSamplerYcbcrConversion(void *args) -{ - struct vkCreateSamplerYcbcrConversion_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pYcbcrConversion); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateSamplerYcbcrConversion(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pYcbcrConversion); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateSamplerYcbcrConversion(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pYcbcrConversion; - VkResult result; - } *params = args; - VkSamplerYcbcrConversionCreateInfo pCreateInfo_host; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pYcbcrConversion); - - convert_VkSamplerYcbcrConversionCreateInfo_win32_to_host((const VkSamplerYcbcrConversionCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateSamplerYcbcrConversion(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkSamplerYcbcrConversion *)UlongToPtr(params->pYcbcrConversion)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateSamplerYcbcrConversionKHR(void *args) -{ - struct vkCreateSamplerYcbcrConversionKHR_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pYcbcrConversion); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateSamplerYcbcrConversionKHR(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pYcbcrConversion); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateSamplerYcbcrConversionKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pYcbcrConversion; - VkResult result; - } *params = args; - VkSamplerYcbcrConversionCreateInfo pCreateInfo_host; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pYcbcrConversion); - - convert_VkSamplerYcbcrConversionCreateInfo_win32_to_host((const VkSamplerYcbcrConversionCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateSamplerYcbcrConversionKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkSamplerYcbcrConversion *)UlongToPtr(params->pYcbcrConversion)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateSemaphore(void *args) -{ - struct vkCreateSemaphore_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pSemaphore); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateSemaphore(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pSemaphore); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateSemaphore(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pSemaphore; - VkResult result; - } *params = args; - VkSemaphoreCreateInfo pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pSemaphore); - - init_conversion_context(&ctx); - convert_VkSemaphoreCreateInfo_win32_to_host(&ctx, (const VkSemaphoreCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateSemaphore(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkSemaphore *)UlongToPtr(params->pSemaphore)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateShaderModule(void *args) -{ - struct vkCreateShaderModule_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pShaderModule); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateShaderModule(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pShaderModule); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateShaderModule(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pShaderModule; - VkResult result; - } *params = args; - VkShaderModuleCreateInfo pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pShaderModule); - - init_conversion_context(&ctx); - convert_VkShaderModuleCreateInfo_win32_to_host(&ctx, (const VkShaderModuleCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateShaderModule(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkShaderModule *)UlongToPtr(params->pShaderModule)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateSwapchainKHR(void *args) -{ - struct vkCreateSwapchainKHR_params *params = args; - VkSwapchainCreateInfoKHR pCreateInfo_host; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pSwapchain); - - convert_VkSwapchainCreateInfoKHR_win64_to_host(params->pCreateInfo, &pCreateInfo_host); - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateSwapchainKHR(wine_device_from_handle(params->device)->device, &pCreateInfo_host, NULL, params->pSwapchain); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateSwapchainKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pSwapchain; - VkResult result; - } *params = args; - VkSwapchainCreateInfoKHR pCreateInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pSwapchain); - - init_conversion_context(&ctx); - convert_VkSwapchainCreateInfoKHR_win32_to_host(&ctx, (const VkSwapchainCreateInfoKHR32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateSwapchainKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkSwapchainKHR *)UlongToPtr(params->pSwapchain)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateValidationCacheEXT(void *args) -{ - struct vkCreateValidationCacheEXT_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pCreateInfo, params->pAllocator, params->pValidationCache); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkCreateValidationCacheEXT(wine_device_from_handle(params->device)->device, params->pCreateInfo, NULL, params->pValidationCache); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateValidationCacheEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pValidationCache; - VkResult result; - } *params = args; - VkValidationCacheCreateInfoEXT pCreateInfo_host; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pAllocator, params->pValidationCache); - - convert_VkValidationCacheCreateInfoEXT_win32_to_host((const VkValidationCacheCreateInfoEXT32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkCreateValidationCacheEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, NULL, (VkValidationCacheEXT *)UlongToPtr(params->pValidationCache)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkCreateWin32SurfaceKHR(void *args) -{ - struct vkCreateWin32SurfaceKHR_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->instance, params->pCreateInfo, params->pAllocator, params->pSurface); - - params->result = wine_vkCreateWin32SurfaceKHR(params->instance, params->pCreateInfo, params->pAllocator, params->pSurface); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkCreateWin32SurfaceKHR(void *args) -{ - struct - { - PTR32 instance; - PTR32 pCreateInfo; - PTR32 pAllocator; - PTR32 pSurface; - VkResult result; - } *params = args; - VkWin32SurfaceCreateInfoKHR pCreateInfo_host; - - TRACE("%#x, %#x, %#x, %#x\n", params->instance, params->pCreateInfo, params->pAllocator, params->pSurface); - - convert_VkWin32SurfaceCreateInfoKHR_win32_to_host((const VkWin32SurfaceCreateInfoKHR32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - params->result = wine_vkCreateWin32SurfaceKHR((VkInstance)UlongToPtr(params->instance), &pCreateInfo_host, (const VkAllocationCallbacks *)UlongToPtr(params->pAllocator), (VkSurfaceKHR *)UlongToPtr(params->pSurface)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDebugMarkerSetObjectNameEXT(void *args) -{ - struct vkDebugMarkerSetObjectNameEXT_params *params = args; - VkDebugMarkerObjectNameInfoEXT pNameInfo_host; - - TRACE("%p, %p\n", params->device, params->pNameInfo); - - convert_VkDebugMarkerObjectNameInfoEXT_win64_to_host(params->pNameInfo, &pNameInfo_host); - params->result = wine_device_from_handle(params->device)->funcs.p_vkDebugMarkerSetObjectNameEXT(wine_device_from_handle(params->device)->device, &pNameInfo_host); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDebugMarkerSetObjectNameEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pNameInfo; - VkResult result; - } *params = args; - VkDebugMarkerObjectNameInfoEXT pNameInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pNameInfo); - - convert_VkDebugMarkerObjectNameInfoEXT_win32_to_host((const VkDebugMarkerObjectNameInfoEXT32 *)UlongToPtr(params->pNameInfo), &pNameInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDebugMarkerSetObjectNameEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pNameInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDebugMarkerSetObjectTagEXT(void *args) -{ - struct vkDebugMarkerSetObjectTagEXT_params *params = args; - VkDebugMarkerObjectTagInfoEXT pTagInfo_host; - - TRACE("%p, %p\n", params->device, params->pTagInfo); - - convert_VkDebugMarkerObjectTagInfoEXT_win64_to_host(params->pTagInfo, &pTagInfo_host); - params->result = wine_device_from_handle(params->device)->funcs.p_vkDebugMarkerSetObjectTagEXT(wine_device_from_handle(params->device)->device, &pTagInfo_host); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDebugMarkerSetObjectTagEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pTagInfo; - VkResult result; - } *params = args; - VkDebugMarkerObjectTagInfoEXT pTagInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pTagInfo); - - convert_VkDebugMarkerObjectTagInfoEXT_win32_to_host((const VkDebugMarkerObjectTagInfoEXT32 *)UlongToPtr(params->pTagInfo), &pTagInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDebugMarkerSetObjectTagEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pTagInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDebugReportMessageEXT(void *args) -{ - struct vkDebugReportMessageEXT_params *params = args; - - TRACE("%p, %#x, %#x, 0x%s, 0x%s, %d, %p, %p\n", params->instance, params->flags, params->objectType, wine_dbgstr_longlong(params->object), wine_dbgstr_longlong(params->location), params->messageCode, params->pLayerPrefix, params->pMessage); - - wine_instance_from_handle(params->instance)->funcs.p_vkDebugReportMessageEXT(wine_instance_from_handle(params->instance)->instance, params->flags, params->objectType, wine_vk_unwrap_handle(params->objectType, params->object), params->location, params->messageCode, params->pLayerPrefix, params->pMessage); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDebugReportMessageEXT(void *args) -{ - struct - { - PTR32 instance; - VkDebugReportFlagsEXT flags; - VkDebugReportObjectTypeEXT objectType; - uint64_t DECLSPEC_ALIGN(8) object; - PTR32 location; - int32_t messageCode; - PTR32 pLayerPrefix; - PTR32 pMessage; - } *params = args; - - TRACE("%#x, %#x, %#x, 0x%s, 0x%s, %d, %#x, %#x\n", params->instance, params->flags, params->objectType, wine_dbgstr_longlong(params->object), wine_dbgstr_longlong(params->location), params->messageCode, params->pLayerPrefix, params->pMessage); - - wine_instance_from_handle((VkInstance)UlongToPtr(params->instance))->funcs.p_vkDebugReportMessageEXT(wine_instance_from_handle((VkInstance)UlongToPtr(params->instance))->instance, params->flags, params->objectType, wine_vk_unwrap_handle(params->objectType, params->object), params->location, params->messageCode, (const char *)UlongToPtr(params->pLayerPrefix), (const char *)UlongToPtr(params->pMessage)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDeferredOperationJoinKHR(void *args) -{ - struct vkDeferredOperationJoinKHR_params *params = args; - - TRACE("%p, 0x%s\n", params->device, wine_dbgstr_longlong(params->operation)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkDeferredOperationJoinKHR(wine_device_from_handle(params->device)->device, params->operation); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDeferredOperationJoinKHR(void *args) -{ - struct - { - PTR32 device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) operation; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s\n", params->device, wine_dbgstr_longlong(params->operation)); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDeferredOperationJoinKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->operation); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyAccelerationStructureKHR(void *args) -{ - struct vkDestroyAccelerationStructureKHR_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->accelerationStructure), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyAccelerationStructureKHR(wine_device_from_handle(params->device)->device, params->accelerationStructure, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyAccelerationStructureKHR(void *args) -{ - struct - { - PTR32 device; - VkAccelerationStructureKHR DECLSPEC_ALIGN(8) accelerationStructure; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->accelerationStructure), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyAccelerationStructureKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->accelerationStructure, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyAccelerationStructureNV(void *args) -{ - struct vkDestroyAccelerationStructureNV_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->accelerationStructure), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyAccelerationStructureNV(wine_device_from_handle(params->device)->device, params->accelerationStructure, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyAccelerationStructureNV(void *args) -{ - struct - { - PTR32 device; - VkAccelerationStructureNV DECLSPEC_ALIGN(8) accelerationStructure; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->accelerationStructure), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyAccelerationStructureNV(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->accelerationStructure, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyBuffer(void *args) -{ - struct vkDestroyBuffer_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->buffer), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyBuffer(wine_device_from_handle(params->device)->device, params->buffer, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyBuffer(void *args) -{ - struct - { - PTR32 device; - VkBuffer DECLSPEC_ALIGN(8) buffer; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->buffer), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyBuffer(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->buffer, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyBufferView(void *args) -{ - struct vkDestroyBufferView_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->bufferView), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyBufferView(wine_device_from_handle(params->device)->device, params->bufferView, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyBufferView(void *args) -{ - struct - { - PTR32 device; - VkBufferView DECLSPEC_ALIGN(8) bufferView; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->bufferView), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyBufferView(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->bufferView, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyCommandPool(void *args) -{ - struct vkDestroyCommandPool_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->commandPool), params->pAllocator); - - wine_vkDestroyCommandPool(params->device, params->commandPool, params->pAllocator); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyCommandPool(void *args) -{ - struct - { - PTR32 device; - VkCommandPool DECLSPEC_ALIGN(8) commandPool; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->commandPool), params->pAllocator); - - wine_vkDestroyCommandPool((VkDevice)UlongToPtr(params->device), params->commandPool, (const VkAllocationCallbacks *)UlongToPtr(params->pAllocator)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyCuFunctionNVX(void *args) -{ - struct vkDestroyCuFunctionNVX_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->function), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyCuFunctionNVX(wine_device_from_handle(params->device)->device, params->function, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyCuFunctionNVX(void *args) -{ - struct - { - PTR32 device; - VkCuFunctionNVX DECLSPEC_ALIGN(8) function; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->function), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyCuFunctionNVX(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->function, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyCuModuleNVX(void *args) -{ - struct vkDestroyCuModuleNVX_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->module), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyCuModuleNVX(wine_device_from_handle(params->device)->device, params->module, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyCuModuleNVX(void *args) -{ - struct - { - PTR32 device; - VkCuModuleNVX DECLSPEC_ALIGN(8) module; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->module), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyCuModuleNVX(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->module, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyDebugReportCallbackEXT(void *args) -{ - struct vkDestroyDebugReportCallbackEXT_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->instance, wine_dbgstr_longlong(params->callback), params->pAllocator); - - wine_vkDestroyDebugReportCallbackEXT(params->instance, params->callback, params->pAllocator); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyDebugReportCallbackEXT(void *args) -{ - struct - { - PTR32 instance; - VkDebugReportCallbackEXT DECLSPEC_ALIGN(8) callback; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->instance, wine_dbgstr_longlong(params->callback), params->pAllocator); - - wine_vkDestroyDebugReportCallbackEXT((VkInstance)UlongToPtr(params->instance), params->callback, (const VkAllocationCallbacks *)UlongToPtr(params->pAllocator)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyDebugUtilsMessengerEXT(void *args) -{ - struct vkDestroyDebugUtilsMessengerEXT_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->instance, wine_dbgstr_longlong(params->messenger), params->pAllocator); - - wine_vkDestroyDebugUtilsMessengerEXT(params->instance, params->messenger, params->pAllocator); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyDebugUtilsMessengerEXT(void *args) -{ - struct - { - PTR32 instance; - VkDebugUtilsMessengerEXT DECLSPEC_ALIGN(8) messenger; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->instance, wine_dbgstr_longlong(params->messenger), params->pAllocator); - - wine_vkDestroyDebugUtilsMessengerEXT((VkInstance)UlongToPtr(params->instance), params->messenger, (const VkAllocationCallbacks *)UlongToPtr(params->pAllocator)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyDeferredOperationKHR(void *args) -{ - struct vkDestroyDeferredOperationKHR_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->operation), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyDeferredOperationKHR(wine_device_from_handle(params->device)->device, params->operation, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyDeferredOperationKHR(void *args) -{ - struct - { - PTR32 device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) operation; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->operation), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyDeferredOperationKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->operation, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyDescriptorPool(void *args) -{ - struct vkDestroyDescriptorPool_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->descriptorPool), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyDescriptorPool(wine_device_from_handle(params->device)->device, params->descriptorPool, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyDescriptorPool(void *args) -{ - struct - { - PTR32 device; - VkDescriptorPool DECLSPEC_ALIGN(8) descriptorPool; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->descriptorPool), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyDescriptorPool(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->descriptorPool, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyDescriptorSetLayout(void *args) -{ - struct vkDestroyDescriptorSetLayout_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->descriptorSetLayout), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyDescriptorSetLayout(wine_device_from_handle(params->device)->device, params->descriptorSetLayout, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyDescriptorSetLayout(void *args) -{ - struct - { - PTR32 device; - VkDescriptorSetLayout DECLSPEC_ALIGN(8) descriptorSetLayout; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->descriptorSetLayout), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyDescriptorSetLayout(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->descriptorSetLayout, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyDescriptorUpdateTemplate(void *args) -{ - struct vkDestroyDescriptorUpdateTemplate_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->descriptorUpdateTemplate), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyDescriptorUpdateTemplate(wine_device_from_handle(params->device)->device, params->descriptorUpdateTemplate, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyDescriptorUpdateTemplate(void *args) -{ - struct - { - PTR32 device; - VkDescriptorUpdateTemplate DECLSPEC_ALIGN(8) descriptorUpdateTemplate; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->descriptorUpdateTemplate), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyDescriptorUpdateTemplate(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->descriptorUpdateTemplate, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyDescriptorUpdateTemplateKHR(void *args) -{ - struct vkDestroyDescriptorUpdateTemplateKHR_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->descriptorUpdateTemplate), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyDescriptorUpdateTemplateKHR(wine_device_from_handle(params->device)->device, params->descriptorUpdateTemplate, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyDescriptorUpdateTemplateKHR(void *args) -{ - struct - { - PTR32 device; - VkDescriptorUpdateTemplate DECLSPEC_ALIGN(8) descriptorUpdateTemplate; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->descriptorUpdateTemplate), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyDescriptorUpdateTemplateKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->descriptorUpdateTemplate, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyDevice(void *args) -{ - struct vkDestroyDevice_params *params = args; - - TRACE("%p, %p\n", params->device, params->pAllocator); - - if (!params->device) - return STATUS_SUCCESS; - - wine_vkDestroyDevice(params->device, params->pAllocator); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyDevice(void *args) -{ - struct - { - PTR32 device; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, %#x\n", params->device, params->pAllocator); - - if (!params->device) - return STATUS_SUCCESS; - - wine_vkDestroyDevice((VkDevice)UlongToPtr(params->device), (const VkAllocationCallbacks *)UlongToPtr(params->pAllocator)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyEvent(void *args) -{ - struct vkDestroyEvent_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->event), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyEvent(wine_device_from_handle(params->device)->device, params->event, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyEvent(void *args) -{ - struct - { - PTR32 device; - VkEvent DECLSPEC_ALIGN(8) event; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->event), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyEvent(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->event, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyFence(void *args) -{ - struct vkDestroyFence_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->fence), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyFence(wine_device_from_handle(params->device)->device, params->fence, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyFence(void *args) -{ - struct - { - PTR32 device; - VkFence DECLSPEC_ALIGN(8) fence; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->fence), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyFence(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->fence, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyFramebuffer(void *args) -{ - struct vkDestroyFramebuffer_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->framebuffer), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyFramebuffer(wine_device_from_handle(params->device)->device, params->framebuffer, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyFramebuffer(void *args) -{ - struct - { - PTR32 device; - VkFramebuffer DECLSPEC_ALIGN(8) framebuffer; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->framebuffer), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyFramebuffer(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->framebuffer, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyImage(void *args) -{ - struct vkDestroyImage_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->image), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyImage(wine_device_from_handle(params->device)->device, params->image, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyImage(void *args) -{ - struct - { - PTR32 device; - VkImage DECLSPEC_ALIGN(8) image; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->image), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyImage(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->image, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyImageView(void *args) -{ - struct vkDestroyImageView_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->imageView), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyImageView(wine_device_from_handle(params->device)->device, params->imageView, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyImageView(void *args) -{ - struct - { - PTR32 device; - VkImageView DECLSPEC_ALIGN(8) imageView; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->imageView), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyImageView(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->imageView, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyIndirectCommandsLayoutNV(void *args) -{ - struct vkDestroyIndirectCommandsLayoutNV_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->indirectCommandsLayout), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyIndirectCommandsLayoutNV(wine_device_from_handle(params->device)->device, params->indirectCommandsLayout, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyIndirectCommandsLayoutNV(void *args) -{ - struct - { - PTR32 device; - VkIndirectCommandsLayoutNV DECLSPEC_ALIGN(8) indirectCommandsLayout; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->indirectCommandsLayout), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyIndirectCommandsLayoutNV(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->indirectCommandsLayout, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyInstance(void *args) -{ - struct vkDestroyInstance_params *params = args; - - TRACE("%p, %p\n", params->instance, params->pAllocator); - - if (!params->instance) - return STATUS_SUCCESS; - - wine_vkDestroyInstance(params->instance, params->pAllocator); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyInstance(void *args) -{ - struct - { - PTR32 instance; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, %#x\n", params->instance, params->pAllocator); - - if (!params->instance) - return STATUS_SUCCESS; - - wine_vkDestroyInstance((VkInstance)UlongToPtr(params->instance), (const VkAllocationCallbacks *)UlongToPtr(params->pAllocator)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyMicromapEXT(void *args) -{ - struct vkDestroyMicromapEXT_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->micromap), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyMicromapEXT(wine_device_from_handle(params->device)->device, params->micromap, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyMicromapEXT(void *args) -{ - struct - { - PTR32 device; - VkMicromapEXT DECLSPEC_ALIGN(8) micromap; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->micromap), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyMicromapEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->micromap, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyOpticalFlowSessionNV(void *args) -{ - struct vkDestroyOpticalFlowSessionNV_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->session), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyOpticalFlowSessionNV(wine_device_from_handle(params->device)->device, params->session, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyOpticalFlowSessionNV(void *args) -{ - struct - { - PTR32 device; - VkOpticalFlowSessionNV DECLSPEC_ALIGN(8) session; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->session), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyOpticalFlowSessionNV(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->session, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyPipeline(void *args) -{ - struct vkDestroyPipeline_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->pipeline), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyPipeline(wine_device_from_handle(params->device)->device, params->pipeline, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyPipeline(void *args) -{ - struct - { - PTR32 device; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->pipeline), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyPipeline(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->pipeline, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyPipelineCache(void *args) -{ - struct vkDestroyPipelineCache_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->pipelineCache), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyPipelineCache(wine_device_from_handle(params->device)->device, params->pipelineCache, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyPipelineCache(void *args) -{ - struct - { - PTR32 device; - VkPipelineCache DECLSPEC_ALIGN(8) pipelineCache; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->pipelineCache), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyPipelineCache(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->pipelineCache, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyPipelineLayout(void *args) -{ - struct vkDestroyPipelineLayout_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->pipelineLayout), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyPipelineLayout(wine_device_from_handle(params->device)->device, params->pipelineLayout, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyPipelineLayout(void *args) -{ - struct - { - PTR32 device; - VkPipelineLayout DECLSPEC_ALIGN(8) pipelineLayout; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->pipelineLayout), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyPipelineLayout(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->pipelineLayout, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyPrivateDataSlot(void *args) -{ - struct vkDestroyPrivateDataSlot_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->privateDataSlot), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyPrivateDataSlot(wine_device_from_handle(params->device)->device, params->privateDataSlot, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyPrivateDataSlot(void *args) -{ - struct - { - PTR32 device; - VkPrivateDataSlot DECLSPEC_ALIGN(8) privateDataSlot; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->privateDataSlot), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyPrivateDataSlot(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->privateDataSlot, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyPrivateDataSlotEXT(void *args) -{ - struct vkDestroyPrivateDataSlotEXT_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->privateDataSlot), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyPrivateDataSlotEXT(wine_device_from_handle(params->device)->device, params->privateDataSlot, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyPrivateDataSlotEXT(void *args) -{ - struct - { - PTR32 device; - VkPrivateDataSlot DECLSPEC_ALIGN(8) privateDataSlot; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->privateDataSlot), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyPrivateDataSlotEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->privateDataSlot, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyQueryPool(void *args) -{ - struct vkDestroyQueryPool_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->queryPool), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyQueryPool(wine_device_from_handle(params->device)->device, params->queryPool, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyQueryPool(void *args) -{ - struct - { - PTR32 device; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->queryPool), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyQueryPool(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->queryPool, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyRenderPass(void *args) -{ - struct vkDestroyRenderPass_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->renderPass), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyRenderPass(wine_device_from_handle(params->device)->device, params->renderPass, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyRenderPass(void *args) -{ - struct - { - PTR32 device; - VkRenderPass DECLSPEC_ALIGN(8) renderPass; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->renderPass), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyRenderPass(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->renderPass, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroySampler(void *args) -{ - struct vkDestroySampler_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->sampler), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroySampler(wine_device_from_handle(params->device)->device, params->sampler, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroySampler(void *args) -{ - struct - { - PTR32 device; - VkSampler DECLSPEC_ALIGN(8) sampler; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->sampler), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroySampler(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->sampler, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroySamplerYcbcrConversion(void *args) -{ - struct vkDestroySamplerYcbcrConversion_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->ycbcrConversion), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroySamplerYcbcrConversion(wine_device_from_handle(params->device)->device, params->ycbcrConversion, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroySamplerYcbcrConversion(void *args) -{ - struct - { - PTR32 device; - VkSamplerYcbcrConversion DECLSPEC_ALIGN(8) ycbcrConversion; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->ycbcrConversion), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroySamplerYcbcrConversion(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->ycbcrConversion, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroySamplerYcbcrConversionKHR(void *args) -{ - struct vkDestroySamplerYcbcrConversionKHR_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->ycbcrConversion), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroySamplerYcbcrConversionKHR(wine_device_from_handle(params->device)->device, params->ycbcrConversion, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroySamplerYcbcrConversionKHR(void *args) -{ - struct - { - PTR32 device; - VkSamplerYcbcrConversion DECLSPEC_ALIGN(8) ycbcrConversion; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->ycbcrConversion), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroySamplerYcbcrConversionKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->ycbcrConversion, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroySemaphore(void *args) -{ - struct vkDestroySemaphore_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->semaphore), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroySemaphore(wine_device_from_handle(params->device)->device, params->semaphore, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroySemaphore(void *args) -{ - struct - { - PTR32 device; - VkSemaphore DECLSPEC_ALIGN(8) semaphore; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->semaphore), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroySemaphore(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->semaphore, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyShaderModule(void *args) -{ - struct vkDestroyShaderModule_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->shaderModule), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyShaderModule(wine_device_from_handle(params->device)->device, params->shaderModule, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyShaderModule(void *args) -{ - struct - { - PTR32 device; - VkShaderModule DECLSPEC_ALIGN(8) shaderModule; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->shaderModule), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyShaderModule(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->shaderModule, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroySurfaceKHR(void *args) -{ - struct vkDestroySurfaceKHR_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->instance, wine_dbgstr_longlong(params->surface), params->pAllocator); - - wine_vkDestroySurfaceKHR(params->instance, params->surface, params->pAllocator); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroySurfaceKHR(void *args) -{ - struct - { - PTR32 instance; - VkSurfaceKHR DECLSPEC_ALIGN(8) surface; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->instance, wine_dbgstr_longlong(params->surface), params->pAllocator); - - wine_vkDestroySurfaceKHR((VkInstance)UlongToPtr(params->instance), params->surface, (const VkAllocationCallbacks *)UlongToPtr(params->pAllocator)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroySwapchainKHR(void *args) -{ - struct vkDestroySwapchainKHR_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->swapchain), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroySwapchainKHR(wine_device_from_handle(params->device)->device, params->swapchain, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroySwapchainKHR(void *args) -{ - struct - { - PTR32 device; - VkSwapchainKHR DECLSPEC_ALIGN(8) swapchain; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->swapchain), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroySwapchainKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->swapchain, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDestroyValidationCacheEXT(void *args) -{ - struct vkDestroyValidationCacheEXT_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->validationCache), params->pAllocator); - - wine_device_from_handle(params->device)->funcs.p_vkDestroyValidationCacheEXT(wine_device_from_handle(params->device)->device, params->validationCache, NULL); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDestroyValidationCacheEXT(void *args) -{ - struct - { - PTR32 device; - VkValidationCacheEXT DECLSPEC_ALIGN(8) validationCache; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->validationCache), params->pAllocator); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDestroyValidationCacheEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->validationCache, NULL); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkDeviceWaitIdle(void *args) -{ - struct vkDeviceWaitIdle_params *params = args; - - TRACE("%p\n", params->device); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkDeviceWaitIdle(wine_device_from_handle(params->device)->device); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkDeviceWaitIdle(void *args) -{ - struct - { - PTR32 device; - VkResult result; - } *params = args; - - TRACE("%#x\n", params->device); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkDeviceWaitIdle(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkEndCommandBuffer(void *args) -{ - struct vkEndCommandBuffer_params *params = args; - - TRACE("%p\n", params->commandBuffer); - - params->result = wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkEndCommandBuffer(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkEndCommandBuffer(void *args) -{ - struct - { - PTR32 commandBuffer; - VkResult result; - } *params = args; - - TRACE("%#x\n", params->commandBuffer); - - params->result = wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkEndCommandBuffer(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkEnumerateDeviceExtensionProperties(void *args) -{ - struct vkEnumerateDeviceExtensionProperties_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->physicalDevice, params->pLayerName, params->pPropertyCount, params->pProperties); - - params->result = wine_vkEnumerateDeviceExtensionProperties(params->physicalDevice, params->pLayerName, params->pPropertyCount, params->pProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkEnumerateDeviceExtensionProperties(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pLayerName; - PTR32 pPropertyCount; - PTR32 pProperties; - VkResult result; - } *params = args; - - TRACE("%#x, %#x, %#x, %#x\n", params->physicalDevice, params->pLayerName, params->pPropertyCount, params->pProperties); - - params->result = wine_vkEnumerateDeviceExtensionProperties((VkPhysicalDevice)UlongToPtr(params->physicalDevice), (const char *)UlongToPtr(params->pLayerName), (uint32_t *)UlongToPtr(params->pPropertyCount), (VkExtensionProperties *)UlongToPtr(params->pProperties)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkEnumerateDeviceLayerProperties(void *args) -{ - struct vkEnumerateDeviceLayerProperties_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pPropertyCount, params->pProperties); - - params->result = wine_vkEnumerateDeviceLayerProperties(params->physicalDevice, params->pPropertyCount, params->pProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkEnumerateDeviceLayerProperties(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pPropertyCount; - PTR32 pProperties; - VkResult result; - } *params = args; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pPropertyCount, params->pProperties); - - params->result = wine_vkEnumerateDeviceLayerProperties((VkPhysicalDevice)UlongToPtr(params->physicalDevice), (uint32_t *)UlongToPtr(params->pPropertyCount), (VkLayerProperties *)UlongToPtr(params->pProperties)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkEnumerateInstanceExtensionProperties(void *args) -{ - struct vkEnumerateInstanceExtensionProperties_params *params = args; - - TRACE("%p, %p, %p\n", params->pLayerName, params->pPropertyCount, params->pProperties); - - params->result = wine_vkEnumerateInstanceExtensionProperties(params->pLayerName, params->pPropertyCount, params->pProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkEnumerateInstanceExtensionProperties(void *args) -{ - struct - { - PTR32 pLayerName; - PTR32 pPropertyCount; - PTR32 pProperties; - VkResult result; - } *params = args; - - TRACE("%#x, %#x, %#x\n", params->pLayerName, params->pPropertyCount, params->pProperties); - - params->result = wine_vkEnumerateInstanceExtensionProperties((const char *)UlongToPtr(params->pLayerName), (uint32_t *)UlongToPtr(params->pPropertyCount), (VkExtensionProperties *)UlongToPtr(params->pProperties)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkEnumerateInstanceVersion(void *args) -{ - struct vkEnumerateInstanceVersion_params *params = args; - - TRACE("%p\n", params->pApiVersion); - - params->result = wine_vkEnumerateInstanceVersion(params->pApiVersion); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkEnumerateInstanceVersion(void *args) -{ - struct - { - PTR32 pApiVersion; - VkResult result; - } *params = args; - - TRACE("%#x\n", params->pApiVersion); - - params->result = wine_vkEnumerateInstanceVersion((uint32_t *)UlongToPtr(params->pApiVersion)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkEnumeratePhysicalDeviceGroups(void *args) -{ - struct vkEnumeratePhysicalDeviceGroups_params *params = args; - - TRACE("%p, %p, %p\n", params->instance, params->pPhysicalDeviceGroupCount, params->pPhysicalDeviceGroupProperties); - - params->result = wine_vkEnumeratePhysicalDeviceGroups(params->instance, params->pPhysicalDeviceGroupCount, params->pPhysicalDeviceGroupProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkEnumeratePhysicalDeviceGroups(void *args) -{ - struct - { - PTR32 instance; - PTR32 pPhysicalDeviceGroupCount; - PTR32 pPhysicalDeviceGroupProperties; - VkResult result; - } *params = args; - VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->instance, params->pPhysicalDeviceGroupCount, params->pPhysicalDeviceGroupProperties); - - init_conversion_context(&ctx); - pPhysicalDeviceGroupProperties_host = convert_VkPhysicalDeviceGroupProperties_array_win32_to_unwrapped_host(&ctx, (VkPhysicalDeviceGroupProperties32 *)UlongToPtr(params->pPhysicalDeviceGroupProperties), *(uint32_t *)UlongToPtr(params->pPhysicalDeviceGroupCount)); - params->result = wine_vkEnumeratePhysicalDeviceGroups((VkInstance)UlongToPtr(params->instance), (uint32_t *)UlongToPtr(params->pPhysicalDeviceGroupCount), pPhysicalDeviceGroupProperties_host); - convert_VkPhysicalDeviceGroupProperties_array_unwrapped_host_to_win32(pPhysicalDeviceGroupProperties_host, (VkPhysicalDeviceGroupProperties32 *)UlongToPtr(params->pPhysicalDeviceGroupProperties), *(uint32_t *)UlongToPtr(params->pPhysicalDeviceGroupCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkEnumeratePhysicalDeviceGroupsKHR(void *args) -{ - struct vkEnumeratePhysicalDeviceGroupsKHR_params *params = args; - - TRACE("%p, %p, %p\n", params->instance, params->pPhysicalDeviceGroupCount, params->pPhysicalDeviceGroupProperties); - - params->result = wine_vkEnumeratePhysicalDeviceGroupsKHR(params->instance, params->pPhysicalDeviceGroupCount, params->pPhysicalDeviceGroupProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkEnumeratePhysicalDeviceGroupsKHR(void *args) -{ - struct - { - PTR32 instance; - PTR32 pPhysicalDeviceGroupCount; - PTR32 pPhysicalDeviceGroupProperties; - VkResult result; - } *params = args; - VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->instance, params->pPhysicalDeviceGroupCount, params->pPhysicalDeviceGroupProperties); - - init_conversion_context(&ctx); - pPhysicalDeviceGroupProperties_host = convert_VkPhysicalDeviceGroupProperties_array_win32_to_unwrapped_host(&ctx, (VkPhysicalDeviceGroupProperties32 *)UlongToPtr(params->pPhysicalDeviceGroupProperties), *(uint32_t *)UlongToPtr(params->pPhysicalDeviceGroupCount)); - params->result = wine_vkEnumeratePhysicalDeviceGroupsKHR((VkInstance)UlongToPtr(params->instance), (uint32_t *)UlongToPtr(params->pPhysicalDeviceGroupCount), pPhysicalDeviceGroupProperties_host); - convert_VkPhysicalDeviceGroupProperties_array_unwrapped_host_to_win32(pPhysicalDeviceGroupProperties_host, (VkPhysicalDeviceGroupProperties32 *)UlongToPtr(params->pPhysicalDeviceGroupProperties), *(uint32_t *)UlongToPtr(params->pPhysicalDeviceGroupCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR(void *args) -{ - struct vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR_params *params = args; - - TRACE("%p, %u, %p, %p, %p\n", params->physicalDevice, params->queueFamilyIndex, params->pCounterCount, params->pCounters, params->pCounterDescriptions); - - params->result = wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->queueFamilyIndex, params->pCounterCount, params->pCounters, params->pCounterDescriptions); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR(void *args) -{ - struct - { - PTR32 physicalDevice; - uint32_t queueFamilyIndex; - PTR32 pCounterCount; - PTR32 pCounters; - PTR32 pCounterDescriptions; - VkResult result; - } *params = args; - VkPerformanceCounterKHR *pCounters_host; - VkPerformanceCounterDescriptionKHR *pCounterDescriptions_host; - struct conversion_context ctx; - - TRACE("%#x, %u, %#x, %#x, %#x\n", params->physicalDevice, params->queueFamilyIndex, params->pCounterCount, params->pCounters, params->pCounterDescriptions); - - init_conversion_context(&ctx); - pCounters_host = convert_VkPerformanceCounterKHR_array_win32_to_host(&ctx, (VkPerformanceCounterKHR32 *)UlongToPtr(params->pCounters), *(uint32_t *)UlongToPtr(params->pCounterCount)); - pCounterDescriptions_host = convert_VkPerformanceCounterDescriptionKHR_array_win32_to_host(&ctx, (VkPerformanceCounterDescriptionKHR32 *)UlongToPtr(params->pCounterDescriptions), *(uint32_t *)UlongToPtr(params->pCounterCount)); - params->result = wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, params->queueFamilyIndex, (uint32_t *)UlongToPtr(params->pCounterCount), pCounters_host, pCounterDescriptions_host); - convert_VkPerformanceCounterKHR_array_host_to_win32(pCounters_host, (VkPerformanceCounterKHR32 *)UlongToPtr(params->pCounters), *(uint32_t *)UlongToPtr(params->pCounterCount)); - convert_VkPerformanceCounterDescriptionKHR_array_host_to_win32(pCounterDescriptions_host, (VkPerformanceCounterDescriptionKHR32 *)UlongToPtr(params->pCounterDescriptions), *(uint32_t *)UlongToPtr(params->pCounterCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkEnumeratePhysicalDevices(void *args) -{ - struct vkEnumeratePhysicalDevices_params *params = args; - - TRACE("%p, %p, %p\n", params->instance, params->pPhysicalDeviceCount, params->pPhysicalDevices); - - params->result = wine_vkEnumeratePhysicalDevices(params->instance, params->pPhysicalDeviceCount, params->pPhysicalDevices); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkEnumeratePhysicalDevices(void *args) -{ - struct - { - PTR32 instance; - PTR32 pPhysicalDeviceCount; - PTR32 pPhysicalDevices; - VkResult result; - } *params = args; - VkPhysicalDevice *pPhysicalDevices_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->instance, params->pPhysicalDeviceCount, params->pPhysicalDevices); - - init_conversion_context(&ctx); - pPhysicalDevices_host = (params->pPhysicalDevices && *(uint32_t *)UlongToPtr(params->pPhysicalDeviceCount)) ? conversion_context_alloc(&ctx, sizeof(*pPhysicalDevices_host) * *(uint32_t *)UlongToPtr(params->pPhysicalDeviceCount)) : NULL; - params->result = wine_vkEnumeratePhysicalDevices((VkInstance)UlongToPtr(params->instance), (uint32_t *)UlongToPtr(params->pPhysicalDeviceCount), pPhysicalDevices_host); - convert_VkPhysicalDevice_array_unwrapped_host_to_win32(pPhysicalDevices_host, (PTR32 *)UlongToPtr(params->pPhysicalDevices), *(uint32_t *)UlongToPtr(params->pPhysicalDeviceCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkFlushMappedMemoryRanges(void *args) -{ - struct vkFlushMappedMemoryRanges_params *params = args; - const VkMappedMemoryRange *pMemoryRanges_host; - struct conversion_context ctx; - - TRACE("%p, %u, %p\n", params->device, params->memoryRangeCount, params->pMemoryRanges); - - init_conversion_context(&ctx); - pMemoryRanges_host = convert_VkMappedMemoryRange_array_win64_to_host(&ctx, params->pMemoryRanges, params->memoryRangeCount); - params->result = wine_device_from_handle(params->device)->funcs.p_vkFlushMappedMemoryRanges(wine_device_from_handle(params->device)->device, params->memoryRangeCount, pMemoryRanges_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkFlushMappedMemoryRanges(void *args) -{ - struct - { - PTR32 device; - uint32_t memoryRangeCount; - PTR32 pMemoryRanges; - VkResult result; - } *params = args; - const VkMappedMemoryRange *pMemoryRanges_host; - struct conversion_context ctx; - - TRACE("%#x, %u, %#x\n", params->device, params->memoryRangeCount, params->pMemoryRanges); - - init_conversion_context(&ctx); - pMemoryRanges_host = convert_VkMappedMemoryRange_array_win32_to_host(&ctx, (const VkMappedMemoryRange32 *)UlongToPtr(params->pMemoryRanges), params->memoryRangeCount); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkFlushMappedMemoryRanges(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->memoryRangeCount, pMemoryRanges_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkFreeCommandBuffers(void *args) -{ - struct vkFreeCommandBuffers_params *params = args; - - TRACE("%p, 0x%s, %u, %p\n", params->device, wine_dbgstr_longlong(params->commandPool), params->commandBufferCount, params->pCommandBuffers); - - wine_vkFreeCommandBuffers(params->device, params->commandPool, params->commandBufferCount, params->pCommandBuffers); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkFreeCommandBuffers(void *args) -{ - struct - { - PTR32 device; - VkCommandPool DECLSPEC_ALIGN(8) commandPool; - uint32_t commandBufferCount; - PTR32 pCommandBuffers; - } *params = args; - const VkCommandBuffer *pCommandBuffers_host; - struct conversion_context ctx; - - TRACE("%#x, 0x%s, %u, %#x\n", params->device, wine_dbgstr_longlong(params->commandPool), params->commandBufferCount, params->pCommandBuffers); - - init_conversion_context(&ctx); - pCommandBuffers_host = convert_VkCommandBuffer_array_win32_to_unwrapped_host(&ctx, (const PTR32 *)UlongToPtr(params->pCommandBuffers), params->commandBufferCount); - wine_vkFreeCommandBuffers((VkDevice)UlongToPtr(params->device), params->commandPool, params->commandBufferCount, pCommandBuffers_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkFreeDescriptorSets(void *args) -{ - struct vkFreeDescriptorSets_params *params = args; - - TRACE("%p, 0x%s, %u, %p\n", params->device, wine_dbgstr_longlong(params->descriptorPool), params->descriptorSetCount, params->pDescriptorSets); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkFreeDescriptorSets(wine_device_from_handle(params->device)->device, params->descriptorPool, params->descriptorSetCount, params->pDescriptorSets); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkFreeDescriptorSets(void *args) -{ - struct - { - PTR32 device; - VkDescriptorPool DECLSPEC_ALIGN(8) descriptorPool; - uint32_t descriptorSetCount; - PTR32 pDescriptorSets; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %u, %#x\n", params->device, wine_dbgstr_longlong(params->descriptorPool), params->descriptorSetCount, params->pDescriptorSets); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkFreeDescriptorSets(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->descriptorPool, params->descriptorSetCount, (const VkDescriptorSet *)UlongToPtr(params->pDescriptorSets)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkFreeMemory(void *args) -{ - struct vkFreeMemory_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->memory), params->pAllocator); - - wine_vkFreeMemory(params->device, params->memory, params->pAllocator); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkFreeMemory(void *args) -{ - struct - { - PTR32 device; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - PTR32 pAllocator; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->memory), params->pAllocator); - - wine_vkFreeMemory((VkDevice)UlongToPtr(params->device), params->memory, (const VkAllocationCallbacks *)UlongToPtr(params->pAllocator)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetAccelerationStructureBuildSizesKHR(void *args) -{ - struct vkGetAccelerationStructureBuildSizesKHR_params *params = args; - - TRACE("%p, %#x, %p, %p, %p\n", params->device, params->buildType, params->pBuildInfo, params->pMaxPrimitiveCounts, params->pSizeInfo); - - wine_device_from_handle(params->device)->funcs.p_vkGetAccelerationStructureBuildSizesKHR(wine_device_from_handle(params->device)->device, params->buildType, params->pBuildInfo, params->pMaxPrimitiveCounts, params->pSizeInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetAccelerationStructureBuildSizesKHR(void *args) -{ - struct - { - PTR32 device; - VkAccelerationStructureBuildTypeKHR buildType; - PTR32 pBuildInfo; - PTR32 pMaxPrimitiveCounts; - PTR32 pSizeInfo; - } *params = args; - VkAccelerationStructureBuildGeometryInfoKHR pBuildInfo_host; - VkAccelerationStructureBuildSizesInfoKHR pSizeInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x, %#x\n", params->device, params->buildType, params->pBuildInfo, params->pMaxPrimitiveCounts, params->pSizeInfo); - - init_conversion_context(&ctx); - convert_VkAccelerationStructureBuildGeometryInfoKHR_win32_to_host(&ctx, (const VkAccelerationStructureBuildGeometryInfoKHR32 *)UlongToPtr(params->pBuildInfo), &pBuildInfo_host); - convert_VkAccelerationStructureBuildSizesInfoKHR_win32_to_host((VkAccelerationStructureBuildSizesInfoKHR32 *)UlongToPtr(params->pSizeInfo), &pSizeInfo_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetAccelerationStructureBuildSizesKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->buildType, &pBuildInfo_host, (const uint32_t *)UlongToPtr(params->pMaxPrimitiveCounts), &pSizeInfo_host); - convert_VkAccelerationStructureBuildSizesInfoKHR_host_to_win32(&pSizeInfo_host, (VkAccelerationStructureBuildSizesInfoKHR32 *)UlongToPtr(params->pSizeInfo)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetAccelerationStructureDeviceAddressKHR(void *args) -{ - struct vkGetAccelerationStructureDeviceAddressKHR_params *params = args; - - TRACE("%p, %p\n", params->device, params->pInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetAccelerationStructureDeviceAddressKHR(wine_device_from_handle(params->device)->device, params->pInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetAccelerationStructureDeviceAddressKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - VkDeviceAddress result; - } *params = args; - VkAccelerationStructureDeviceAddressInfoKHR pInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pInfo); - - convert_VkAccelerationStructureDeviceAddressInfoKHR_win32_to_host((const VkAccelerationStructureDeviceAddressInfoKHR32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetAccelerationStructureDeviceAddressKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetAccelerationStructureHandleNV(void *args) -{ - struct vkGetAccelerationStructureHandleNV_params *params = args; - - TRACE("%p, 0x%s, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->accelerationStructure), wine_dbgstr_longlong(params->dataSize), params->pData); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetAccelerationStructureHandleNV(wine_device_from_handle(params->device)->device, params->accelerationStructure, params->dataSize, params->pData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetAccelerationStructureHandleNV(void *args) -{ - struct - { - PTR32 device; - VkAccelerationStructureNV DECLSPEC_ALIGN(8) accelerationStructure; - PTR32 dataSize; - PTR32 pData; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->accelerationStructure), wine_dbgstr_longlong(params->dataSize), params->pData); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetAccelerationStructureHandleNV(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->accelerationStructure, params->dataSize, (void *)UlongToPtr(params->pData)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetAccelerationStructureMemoryRequirementsNV(void *args) -{ - struct vkGetAccelerationStructureMemoryRequirementsNV_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pInfo, params->pMemoryRequirements); - - wine_device_from_handle(params->device)->funcs.p_vkGetAccelerationStructureMemoryRequirementsNV(wine_device_from_handle(params->device)->device, params->pInfo, params->pMemoryRequirements); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetAccelerationStructureMemoryRequirementsNV(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pMemoryRequirements; - } *params = args; - VkAccelerationStructureMemoryRequirementsInfoNV pInfo_host; - VkMemoryRequirements2KHR pMemoryRequirements_host; - - TRACE("%#x, %#x, %#x\n", params->device, params->pInfo, params->pMemoryRequirements); - - convert_VkAccelerationStructureMemoryRequirementsInfoNV_win32_to_host((const VkAccelerationStructureMemoryRequirementsInfoNV32 *)UlongToPtr(params->pInfo), &pInfo_host); - convert_VkMemoryRequirements2KHR_win32_to_host((VkMemoryRequirements2KHR32 *)UlongToPtr(params->pMemoryRequirements), &pMemoryRequirements_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetAccelerationStructureMemoryRequirementsNV(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, &pMemoryRequirements_host); - convert_VkMemoryRequirements2KHR_host_to_win32(&pMemoryRequirements_host, (VkMemoryRequirements2KHR32 *)UlongToPtr(params->pMemoryRequirements)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT(void *args) -{ - struct vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pInfo, params->pData); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT(wine_device_from_handle(params->device)->device, params->pInfo, params->pData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pData; - VkResult result; - } *params = args; - VkAccelerationStructureCaptureDescriptorDataInfoEXT pInfo_host; - - TRACE("%#x, %#x, %#x\n", params->device, params->pInfo, params->pData); - - convert_VkAccelerationStructureCaptureDescriptorDataInfoEXT_win32_to_host((const VkAccelerationStructureCaptureDescriptorDataInfoEXT32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, (void *)UlongToPtr(params->pData)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetBufferDeviceAddress(void *args) -{ - struct vkGetBufferDeviceAddress_params *params = args; - - TRACE("%p, %p\n", params->device, params->pInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetBufferDeviceAddress(wine_device_from_handle(params->device)->device, params->pInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetBufferDeviceAddress(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - VkDeviceAddress result; - } *params = args; - VkBufferDeviceAddressInfo pInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pInfo); - - convert_VkBufferDeviceAddressInfo_win32_to_host((const VkBufferDeviceAddressInfo32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetBufferDeviceAddress(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetBufferDeviceAddressEXT(void *args) -{ - struct vkGetBufferDeviceAddressEXT_params *params = args; - - TRACE("%p, %p\n", params->device, params->pInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetBufferDeviceAddressEXT(wine_device_from_handle(params->device)->device, params->pInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetBufferDeviceAddressEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - VkDeviceAddress result; - } *params = args; - VkBufferDeviceAddressInfo pInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pInfo); - - convert_VkBufferDeviceAddressInfo_win32_to_host((const VkBufferDeviceAddressInfo32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetBufferDeviceAddressEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetBufferDeviceAddressKHR(void *args) -{ - struct vkGetBufferDeviceAddressKHR_params *params = args; - - TRACE("%p, %p\n", params->device, params->pInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetBufferDeviceAddressKHR(wine_device_from_handle(params->device)->device, params->pInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetBufferDeviceAddressKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - VkDeviceAddress result; - } *params = args; - VkBufferDeviceAddressInfo pInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pInfo); - - convert_VkBufferDeviceAddressInfo_win32_to_host((const VkBufferDeviceAddressInfo32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetBufferDeviceAddressKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetBufferMemoryRequirements(void *args) -{ - struct vkGetBufferMemoryRequirements_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->buffer), params->pMemoryRequirements); - - wine_device_from_handle(params->device)->funcs.p_vkGetBufferMemoryRequirements(wine_device_from_handle(params->device)->device, params->buffer, params->pMemoryRequirements); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetBufferMemoryRequirements(void *args) -{ - struct - { - PTR32 device; - VkBuffer DECLSPEC_ALIGN(8) buffer; - PTR32 pMemoryRequirements; - } *params = args; - VkMemoryRequirements pMemoryRequirements_host; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->buffer), params->pMemoryRequirements); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetBufferMemoryRequirements(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->buffer, &pMemoryRequirements_host); - convert_VkMemoryRequirements_host_to_win32(&pMemoryRequirements_host, (VkMemoryRequirements32 *)UlongToPtr(params->pMemoryRequirements)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetBufferMemoryRequirements2(void *args) -{ - struct vkGetBufferMemoryRequirements2_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pInfo, params->pMemoryRequirements); - - wine_device_from_handle(params->device)->funcs.p_vkGetBufferMemoryRequirements2(wine_device_from_handle(params->device)->device, params->pInfo, params->pMemoryRequirements); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetBufferMemoryRequirements2(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pMemoryRequirements; - } *params = args; - VkBufferMemoryRequirementsInfo2 pInfo_host; - VkMemoryRequirements2 pMemoryRequirements_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->device, params->pInfo, params->pMemoryRequirements); - - init_conversion_context(&ctx); - convert_VkBufferMemoryRequirementsInfo2_win32_to_host((const VkBufferMemoryRequirementsInfo232 *)UlongToPtr(params->pInfo), &pInfo_host); - convert_VkMemoryRequirements2_win32_to_host(&ctx, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements), &pMemoryRequirements_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetBufferMemoryRequirements2(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, &pMemoryRequirements_host); - convert_VkMemoryRequirements2_host_to_win32(&pMemoryRequirements_host, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetBufferMemoryRequirements2KHR(void *args) -{ - struct vkGetBufferMemoryRequirements2KHR_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pInfo, params->pMemoryRequirements); - - wine_device_from_handle(params->device)->funcs.p_vkGetBufferMemoryRequirements2KHR(wine_device_from_handle(params->device)->device, params->pInfo, params->pMemoryRequirements); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetBufferMemoryRequirements2KHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pMemoryRequirements; - } *params = args; - VkBufferMemoryRequirementsInfo2 pInfo_host; - VkMemoryRequirements2 pMemoryRequirements_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->device, params->pInfo, params->pMemoryRequirements); - - init_conversion_context(&ctx); - convert_VkBufferMemoryRequirementsInfo2_win32_to_host((const VkBufferMemoryRequirementsInfo232 *)UlongToPtr(params->pInfo), &pInfo_host); - convert_VkMemoryRequirements2_win32_to_host(&ctx, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements), &pMemoryRequirements_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetBufferMemoryRequirements2KHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, &pMemoryRequirements_host); - convert_VkMemoryRequirements2_host_to_win32(&pMemoryRequirements_host, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetBufferOpaqueCaptureAddress(void *args) -{ - struct vkGetBufferOpaqueCaptureAddress_params *params = args; - - TRACE("%p, %p\n", params->device, params->pInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetBufferOpaqueCaptureAddress(wine_device_from_handle(params->device)->device, params->pInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetBufferOpaqueCaptureAddress(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - uint64_t result; - } *params = args; - VkBufferDeviceAddressInfo pInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pInfo); - - convert_VkBufferDeviceAddressInfo_win32_to_host((const VkBufferDeviceAddressInfo32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetBufferOpaqueCaptureAddress(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetBufferOpaqueCaptureAddressKHR(void *args) -{ - struct vkGetBufferOpaqueCaptureAddressKHR_params *params = args; - - TRACE("%p, %p\n", params->device, params->pInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetBufferOpaqueCaptureAddressKHR(wine_device_from_handle(params->device)->device, params->pInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetBufferOpaqueCaptureAddressKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - uint64_t result; - } *params = args; - VkBufferDeviceAddressInfo pInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pInfo); - - convert_VkBufferDeviceAddressInfo_win32_to_host((const VkBufferDeviceAddressInfo32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetBufferOpaqueCaptureAddressKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetBufferOpaqueCaptureDescriptorDataEXT(void *args) -{ - struct vkGetBufferOpaqueCaptureDescriptorDataEXT_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pInfo, params->pData); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetBufferOpaqueCaptureDescriptorDataEXT(wine_device_from_handle(params->device)->device, params->pInfo, params->pData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetBufferOpaqueCaptureDescriptorDataEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pData; - VkResult result; - } *params = args; - VkBufferCaptureDescriptorDataInfoEXT pInfo_host; - - TRACE("%#x, %#x, %#x\n", params->device, params->pInfo, params->pData); - - convert_VkBufferCaptureDescriptorDataInfoEXT_win32_to_host((const VkBufferCaptureDescriptorDataInfoEXT32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetBufferOpaqueCaptureDescriptorDataEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, (void *)UlongToPtr(params->pData)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetCalibratedTimestampsEXT(void *args) -{ - struct vkGetCalibratedTimestampsEXT_params *params = args; - - TRACE("%p, %u, %p, %p, %p\n", params->device, params->timestampCount, params->pTimestampInfos, params->pTimestamps, params->pMaxDeviation); - - params->result = wine_vkGetCalibratedTimestampsEXT(params->device, params->timestampCount, params->pTimestampInfos, params->pTimestamps, params->pMaxDeviation); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetCalibratedTimestampsEXT(void *args) -{ - struct - { - PTR32 device; - uint32_t timestampCount; - PTR32 pTimestampInfos; - PTR32 pTimestamps; - PTR32 pMaxDeviation; - VkResult result; - } *params = args; - const VkCalibratedTimestampInfoEXT *pTimestampInfos_host; - struct conversion_context ctx; - - TRACE("%#x, %u, %#x, %#x, %#x\n", params->device, params->timestampCount, params->pTimestampInfos, params->pTimestamps, params->pMaxDeviation); - - init_conversion_context(&ctx); - pTimestampInfos_host = convert_VkCalibratedTimestampInfoEXT_array_win32_to_host(&ctx, (const VkCalibratedTimestampInfoEXT32 *)UlongToPtr(params->pTimestampInfos), params->timestampCount); - params->result = wine_vkGetCalibratedTimestampsEXT((VkDevice)UlongToPtr(params->device), params->timestampCount, pTimestampInfos_host, (uint64_t *)UlongToPtr(params->pTimestamps), (uint64_t *)UlongToPtr(params->pMaxDeviation)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeferredOperationMaxConcurrencyKHR(void *args) -{ - struct vkGetDeferredOperationMaxConcurrencyKHR_params *params = args; - - TRACE("%p, 0x%s\n", params->device, wine_dbgstr_longlong(params->operation)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetDeferredOperationMaxConcurrencyKHR(wine_device_from_handle(params->device)->device, params->operation); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeferredOperationMaxConcurrencyKHR(void *args) -{ - struct - { - PTR32 device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) operation; - uint32_t result; - } *params = args; - - TRACE("%#x, 0x%s\n", params->device, wine_dbgstr_longlong(params->operation)); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeferredOperationMaxConcurrencyKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->operation); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeferredOperationResultKHR(void *args) -{ - struct vkGetDeferredOperationResultKHR_params *params = args; - - TRACE("%p, 0x%s\n", params->device, wine_dbgstr_longlong(params->operation)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetDeferredOperationResultKHR(wine_device_from_handle(params->device)->device, params->operation); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeferredOperationResultKHR(void *args) -{ - struct - { - PTR32 device; - VkDeferredOperationKHR DECLSPEC_ALIGN(8) operation; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s\n", params->device, wine_dbgstr_longlong(params->operation)); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeferredOperationResultKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->operation); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static void thunk64_vkGetDescriptorEXT(void *args) -{ - struct vkGetDescriptorEXT_params *params = args; - - wine_device_from_handle(params->device)->funcs.p_vkGetDescriptorEXT(wine_device_from_handle(params->device)->device, params->pDescriptorInfo, params->dataSize, params->pDescriptor); -} -#endif /* _WIN64 */ - -static void thunk32_vkGetDescriptorEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pDescriptorInfo; - PTR32 dataSize; - PTR32 pDescriptor; - } *params = args; - VkDescriptorGetInfoEXT pDescriptorInfo_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - convert_VkDescriptorGetInfoEXT_win32_to_host(&ctx, (const VkDescriptorGetInfoEXT32 *)UlongToPtr(params->pDescriptorInfo), &pDescriptorInfo_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDescriptorEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pDescriptorInfo_host, params->dataSize, (void *)UlongToPtr(params->pDescriptor)); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDescriptorSetHostMappingVALVE(void *args) -{ - struct vkGetDescriptorSetHostMappingVALVE_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->descriptorSet), params->ppData); - - wine_device_from_handle(params->device)->funcs.p_vkGetDescriptorSetHostMappingVALVE(wine_device_from_handle(params->device)->device, params->descriptorSet, params->ppData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDescriptorSetHostMappingVALVE(void *args) -{ - struct - { - PTR32 device; - VkDescriptorSet DECLSPEC_ALIGN(8) descriptorSet; - PTR32 ppData; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->descriptorSet), params->ppData); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDescriptorSetHostMappingVALVE(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->descriptorSet, (void **)UlongToPtr(params->ppData)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDescriptorSetLayoutBindingOffsetEXT(void *args) -{ - struct vkGetDescriptorSetLayoutBindingOffsetEXT_params *params = args; - - TRACE("%p, 0x%s, %u, %p\n", params->device, wine_dbgstr_longlong(params->layout), params->binding, params->pOffset); - - wine_device_from_handle(params->device)->funcs.p_vkGetDescriptorSetLayoutBindingOffsetEXT(wine_device_from_handle(params->device)->device, params->layout, params->binding, params->pOffset); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDescriptorSetLayoutBindingOffsetEXT(void *args) -{ - struct - { - PTR32 device; - VkDescriptorSetLayout DECLSPEC_ALIGN(8) layout; - uint32_t binding; - PTR32 pOffset; - } *params = args; - - TRACE("%#x, 0x%s, %u, %#x\n", params->device, wine_dbgstr_longlong(params->layout), params->binding, params->pOffset); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDescriptorSetLayoutBindingOffsetEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->layout, params->binding, (VkDeviceSize *)UlongToPtr(params->pOffset)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDescriptorSetLayoutHostMappingInfoVALVE(void *args) -{ - struct vkGetDescriptorSetLayoutHostMappingInfoVALVE_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pBindingReference, params->pHostMapping); - - wine_device_from_handle(params->device)->funcs.p_vkGetDescriptorSetLayoutHostMappingInfoVALVE(wine_device_from_handle(params->device)->device, params->pBindingReference, params->pHostMapping); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDescriptorSetLayoutHostMappingInfoVALVE(void *args) -{ - struct - { - PTR32 device; - PTR32 pBindingReference; - PTR32 pHostMapping; - } *params = args; - VkDescriptorSetBindingReferenceVALVE pBindingReference_host; - VkDescriptorSetLayoutHostMappingInfoVALVE pHostMapping_host; - - TRACE("%#x, %#x, %#x\n", params->device, params->pBindingReference, params->pHostMapping); - - convert_VkDescriptorSetBindingReferenceVALVE_win32_to_host((const VkDescriptorSetBindingReferenceVALVE32 *)UlongToPtr(params->pBindingReference), &pBindingReference_host); - convert_VkDescriptorSetLayoutHostMappingInfoVALVE_win32_to_host((VkDescriptorSetLayoutHostMappingInfoVALVE32 *)UlongToPtr(params->pHostMapping), &pHostMapping_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDescriptorSetLayoutHostMappingInfoVALVE(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pBindingReference_host, &pHostMapping_host); - convert_VkDescriptorSetLayoutHostMappingInfoVALVE_host_to_win32(&pHostMapping_host, (VkDescriptorSetLayoutHostMappingInfoVALVE32 *)UlongToPtr(params->pHostMapping)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDescriptorSetLayoutSizeEXT(void *args) -{ - struct vkGetDescriptorSetLayoutSizeEXT_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->layout), params->pLayoutSizeInBytes); - - wine_device_from_handle(params->device)->funcs.p_vkGetDescriptorSetLayoutSizeEXT(wine_device_from_handle(params->device)->device, params->layout, params->pLayoutSizeInBytes); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDescriptorSetLayoutSizeEXT(void *args) -{ - struct - { - PTR32 device; - VkDescriptorSetLayout DECLSPEC_ALIGN(8) layout; - PTR32 pLayoutSizeInBytes; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->layout), params->pLayoutSizeInBytes); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDescriptorSetLayoutSizeEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->layout, (VkDeviceSize *)UlongToPtr(params->pLayoutSizeInBytes)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDescriptorSetLayoutSupport(void *args) -{ - struct vkGetDescriptorSetLayoutSupport_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pCreateInfo, params->pSupport); - - wine_device_from_handle(params->device)->funcs.p_vkGetDescriptorSetLayoutSupport(wine_device_from_handle(params->device)->device, params->pCreateInfo, params->pSupport); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDescriptorSetLayoutSupport(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pSupport; - } *params = args; - VkDescriptorSetLayoutCreateInfo pCreateInfo_host; - VkDescriptorSetLayoutSupport pSupport_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pSupport); - - init_conversion_context(&ctx); - convert_VkDescriptorSetLayoutCreateInfo_win32_to_host(&ctx, (const VkDescriptorSetLayoutCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - convert_VkDescriptorSetLayoutSupport_win32_to_host(&ctx, (VkDescriptorSetLayoutSupport32 *)UlongToPtr(params->pSupport), &pSupport_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDescriptorSetLayoutSupport(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, &pSupport_host); - convert_VkDescriptorSetLayoutSupport_host_to_win32(&pSupport_host, (VkDescriptorSetLayoutSupport32 *)UlongToPtr(params->pSupport)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDescriptorSetLayoutSupportKHR(void *args) -{ - struct vkGetDescriptorSetLayoutSupportKHR_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pCreateInfo, params->pSupport); - - wine_device_from_handle(params->device)->funcs.p_vkGetDescriptorSetLayoutSupportKHR(wine_device_from_handle(params->device)->device, params->pCreateInfo, params->pSupport); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDescriptorSetLayoutSupportKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pSupport; - } *params = args; - VkDescriptorSetLayoutCreateInfo pCreateInfo_host; - VkDescriptorSetLayoutSupport pSupport_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pSupport); - - init_conversion_context(&ctx); - convert_VkDescriptorSetLayoutCreateInfo_win32_to_host(&ctx, (const VkDescriptorSetLayoutCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - convert_VkDescriptorSetLayoutSupport_win32_to_host(&ctx, (VkDescriptorSetLayoutSupport32 *)UlongToPtr(params->pSupport), &pSupport_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDescriptorSetLayoutSupportKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, &pSupport_host); - convert_VkDescriptorSetLayoutSupport_host_to_win32(&pSupport_host, (VkDescriptorSetLayoutSupport32 *)UlongToPtr(params->pSupport)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceAccelerationStructureCompatibilityKHR(void *args) -{ - struct vkGetDeviceAccelerationStructureCompatibilityKHR_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pVersionInfo, params->pCompatibility); - - wine_device_from_handle(params->device)->funcs.p_vkGetDeviceAccelerationStructureCompatibilityKHR(wine_device_from_handle(params->device)->device, params->pVersionInfo, params->pCompatibility); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceAccelerationStructureCompatibilityKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pVersionInfo; - PTR32 pCompatibility; - } *params = args; - VkAccelerationStructureVersionInfoKHR pVersionInfo_host; - - TRACE("%#x, %#x, %#x\n", params->device, params->pVersionInfo, params->pCompatibility); - - convert_VkAccelerationStructureVersionInfoKHR_win32_to_host((const VkAccelerationStructureVersionInfoKHR32 *)UlongToPtr(params->pVersionInfo), &pVersionInfo_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeviceAccelerationStructureCompatibilityKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pVersionInfo_host, (VkAccelerationStructureCompatibilityKHR *)UlongToPtr(params->pCompatibility)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceBufferMemoryRequirements(void *args) -{ - struct vkGetDeviceBufferMemoryRequirements_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pInfo, params->pMemoryRequirements); - - wine_device_from_handle(params->device)->funcs.p_vkGetDeviceBufferMemoryRequirements(wine_device_from_handle(params->device)->device, params->pInfo, params->pMemoryRequirements); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceBufferMemoryRequirements(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pMemoryRequirements; - } *params = args; - VkDeviceBufferMemoryRequirements pInfo_host; - VkMemoryRequirements2 pMemoryRequirements_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->device, params->pInfo, params->pMemoryRequirements); - - init_conversion_context(&ctx); - convert_VkDeviceBufferMemoryRequirements_win32_to_host(&ctx, (const VkDeviceBufferMemoryRequirements32 *)UlongToPtr(params->pInfo), &pInfo_host); - convert_VkMemoryRequirements2_win32_to_host(&ctx, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements), &pMemoryRequirements_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeviceBufferMemoryRequirements(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, &pMemoryRequirements_host); - convert_VkMemoryRequirements2_host_to_win32(&pMemoryRequirements_host, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceBufferMemoryRequirementsKHR(void *args) -{ - struct vkGetDeviceBufferMemoryRequirementsKHR_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pInfo, params->pMemoryRequirements); - - wine_device_from_handle(params->device)->funcs.p_vkGetDeviceBufferMemoryRequirementsKHR(wine_device_from_handle(params->device)->device, params->pInfo, params->pMemoryRequirements); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceBufferMemoryRequirementsKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pMemoryRequirements; - } *params = args; - VkDeviceBufferMemoryRequirements pInfo_host; - VkMemoryRequirements2 pMemoryRequirements_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->device, params->pInfo, params->pMemoryRequirements); - - init_conversion_context(&ctx); - convert_VkDeviceBufferMemoryRequirements_win32_to_host(&ctx, (const VkDeviceBufferMemoryRequirements32 *)UlongToPtr(params->pInfo), &pInfo_host); - convert_VkMemoryRequirements2_win32_to_host(&ctx, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements), &pMemoryRequirements_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeviceBufferMemoryRequirementsKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, &pMemoryRequirements_host); - convert_VkMemoryRequirements2_host_to_win32(&pMemoryRequirements_host, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceFaultInfoEXT(void *args) -{ - struct vkGetDeviceFaultInfoEXT_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pFaultCounts, params->pFaultInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetDeviceFaultInfoEXT(wine_device_from_handle(params->device)->device, params->pFaultCounts, params->pFaultInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceFaultInfoEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pFaultCounts; - PTR32 pFaultInfo; - VkResult result; - } *params = args; - VkDeviceFaultCountsEXT pFaultCounts_host; - VkDeviceFaultInfoEXT *pFaultInfo_host = NULL; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->device, params->pFaultCounts, params->pFaultInfo); - - init_conversion_context(&ctx); - convert_VkDeviceFaultCountsEXT_win32_to_host((VkDeviceFaultCountsEXT32 *)UlongToPtr(params->pFaultCounts), &pFaultCounts_host); - if (params->pFaultInfo) - { - pFaultInfo_host = conversion_context_alloc(&ctx, sizeof(*pFaultInfo_host)); - convert_VkDeviceFaultInfoEXT_win32_to_host(&ctx, (VkDeviceFaultInfoEXT32 *)UlongToPtr(params->pFaultInfo), pFaultInfo_host); - } - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeviceFaultInfoEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pFaultCounts_host, pFaultInfo_host); - convert_VkDeviceFaultCountsEXT_host_to_win32(&pFaultCounts_host, (VkDeviceFaultCountsEXT32 *)UlongToPtr(params->pFaultCounts)); - convert_VkDeviceFaultInfoEXT_host_to_win32(pFaultInfo_host, (VkDeviceFaultInfoEXT32 *)UlongToPtr(params->pFaultInfo)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceGroupPeerMemoryFeatures(void *args) -{ - struct vkGetDeviceGroupPeerMemoryFeatures_params *params = args; - - TRACE("%p, %u, %u, %u, %p\n", params->device, params->heapIndex, params->localDeviceIndex, params->remoteDeviceIndex, params->pPeerMemoryFeatures); - - wine_device_from_handle(params->device)->funcs.p_vkGetDeviceGroupPeerMemoryFeatures(wine_device_from_handle(params->device)->device, params->heapIndex, params->localDeviceIndex, params->remoteDeviceIndex, params->pPeerMemoryFeatures); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceGroupPeerMemoryFeatures(void *args) -{ - struct - { - PTR32 device; - uint32_t heapIndex; - uint32_t localDeviceIndex; - uint32_t remoteDeviceIndex; - PTR32 pPeerMemoryFeatures; - } *params = args; - - TRACE("%#x, %u, %u, %u, %#x\n", params->device, params->heapIndex, params->localDeviceIndex, params->remoteDeviceIndex, params->pPeerMemoryFeatures); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeviceGroupPeerMemoryFeatures(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->heapIndex, params->localDeviceIndex, params->remoteDeviceIndex, (VkPeerMemoryFeatureFlags *)UlongToPtr(params->pPeerMemoryFeatures)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceGroupPeerMemoryFeaturesKHR(void *args) -{ - struct vkGetDeviceGroupPeerMemoryFeaturesKHR_params *params = args; - - TRACE("%p, %u, %u, %u, %p\n", params->device, params->heapIndex, params->localDeviceIndex, params->remoteDeviceIndex, params->pPeerMemoryFeatures); - - wine_device_from_handle(params->device)->funcs.p_vkGetDeviceGroupPeerMemoryFeaturesKHR(wine_device_from_handle(params->device)->device, params->heapIndex, params->localDeviceIndex, params->remoteDeviceIndex, params->pPeerMemoryFeatures); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceGroupPeerMemoryFeaturesKHR(void *args) -{ - struct - { - PTR32 device; - uint32_t heapIndex; - uint32_t localDeviceIndex; - uint32_t remoteDeviceIndex; - PTR32 pPeerMemoryFeatures; - } *params = args; - - TRACE("%#x, %u, %u, %u, %#x\n", params->device, params->heapIndex, params->localDeviceIndex, params->remoteDeviceIndex, params->pPeerMemoryFeatures); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeviceGroupPeerMemoryFeaturesKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->heapIndex, params->localDeviceIndex, params->remoteDeviceIndex, (VkPeerMemoryFeatureFlags *)UlongToPtr(params->pPeerMemoryFeatures)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceGroupPresentCapabilitiesKHR(void *args) -{ - struct vkGetDeviceGroupPresentCapabilitiesKHR_params *params = args; - - TRACE("%p, %p\n", params->device, params->pDeviceGroupPresentCapabilities); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetDeviceGroupPresentCapabilitiesKHR(wine_device_from_handle(params->device)->device, params->pDeviceGroupPresentCapabilities); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceGroupPresentCapabilitiesKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pDeviceGroupPresentCapabilities; - VkResult result; - } *params = args; - VkDeviceGroupPresentCapabilitiesKHR pDeviceGroupPresentCapabilities_host; - - TRACE("%#x, %#x\n", params->device, params->pDeviceGroupPresentCapabilities); - - convert_VkDeviceGroupPresentCapabilitiesKHR_win32_to_host((VkDeviceGroupPresentCapabilitiesKHR32 *)UlongToPtr(params->pDeviceGroupPresentCapabilities), &pDeviceGroupPresentCapabilities_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeviceGroupPresentCapabilitiesKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pDeviceGroupPresentCapabilities_host); - convert_VkDeviceGroupPresentCapabilitiesKHR_host_to_win32(&pDeviceGroupPresentCapabilities_host, (VkDeviceGroupPresentCapabilitiesKHR32 *)UlongToPtr(params->pDeviceGroupPresentCapabilities)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceGroupSurfacePresentModesKHR(void *args) -{ - struct vkGetDeviceGroupSurfacePresentModesKHR_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->surface), params->pModes); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetDeviceGroupSurfacePresentModesKHR(wine_device_from_handle(params->device)->device, wine_surface_from_handle(params->surface)->driver_surface, params->pModes); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceGroupSurfacePresentModesKHR(void *args) -{ - struct - { - PTR32 device; - VkSurfaceKHR DECLSPEC_ALIGN(8) surface; - PTR32 pModes; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->surface), params->pModes); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeviceGroupSurfacePresentModesKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, wine_surface_from_handle(params->surface)->driver_surface, (VkDeviceGroupPresentModeFlagsKHR *)UlongToPtr(params->pModes)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceImageMemoryRequirements(void *args) -{ - struct vkGetDeviceImageMemoryRequirements_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pInfo, params->pMemoryRequirements); - - wine_device_from_handle(params->device)->funcs.p_vkGetDeviceImageMemoryRequirements(wine_device_from_handle(params->device)->device, params->pInfo, params->pMemoryRequirements); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceImageMemoryRequirements(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pMemoryRequirements; - } *params = args; - VkDeviceImageMemoryRequirements pInfo_host; - VkMemoryRequirements2 pMemoryRequirements_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->device, params->pInfo, params->pMemoryRequirements); - - init_conversion_context(&ctx); - convert_VkDeviceImageMemoryRequirements_win32_to_host(&ctx, (const VkDeviceImageMemoryRequirements32 *)UlongToPtr(params->pInfo), &pInfo_host); - convert_VkMemoryRequirements2_win32_to_host(&ctx, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements), &pMemoryRequirements_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeviceImageMemoryRequirements(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, &pMemoryRequirements_host); - convert_VkMemoryRequirements2_host_to_win32(&pMemoryRequirements_host, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceImageMemoryRequirementsKHR(void *args) -{ - struct vkGetDeviceImageMemoryRequirementsKHR_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pInfo, params->pMemoryRequirements); - - wine_device_from_handle(params->device)->funcs.p_vkGetDeviceImageMemoryRequirementsKHR(wine_device_from_handle(params->device)->device, params->pInfo, params->pMemoryRequirements); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceImageMemoryRequirementsKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pMemoryRequirements; - } *params = args; - VkDeviceImageMemoryRequirements pInfo_host; - VkMemoryRequirements2 pMemoryRequirements_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->device, params->pInfo, params->pMemoryRequirements); - - init_conversion_context(&ctx); - convert_VkDeviceImageMemoryRequirements_win32_to_host(&ctx, (const VkDeviceImageMemoryRequirements32 *)UlongToPtr(params->pInfo), &pInfo_host); - convert_VkMemoryRequirements2_win32_to_host(&ctx, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements), &pMemoryRequirements_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeviceImageMemoryRequirementsKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, &pMemoryRequirements_host); - convert_VkMemoryRequirements2_host_to_win32(&pMemoryRequirements_host, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceImageSparseMemoryRequirements(void *args) -{ - struct vkGetDeviceImageSparseMemoryRequirements_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pInfo, params->pSparseMemoryRequirementCount, params->pSparseMemoryRequirements); - - wine_device_from_handle(params->device)->funcs.p_vkGetDeviceImageSparseMemoryRequirements(wine_device_from_handle(params->device)->device, params->pInfo, params->pSparseMemoryRequirementCount, params->pSparseMemoryRequirements); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceImageSparseMemoryRequirements(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pSparseMemoryRequirementCount; - PTR32 pSparseMemoryRequirements; - } *params = args; - VkDeviceImageMemoryRequirements pInfo_host; - VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pInfo, params->pSparseMemoryRequirementCount, params->pSparseMemoryRequirements); - - init_conversion_context(&ctx); - convert_VkDeviceImageMemoryRequirements_win32_to_host(&ctx, (const VkDeviceImageMemoryRequirements32 *)UlongToPtr(params->pInfo), &pInfo_host); - pSparseMemoryRequirements_host = convert_VkSparseImageMemoryRequirements2_array_win32_to_host(&ctx, (VkSparseImageMemoryRequirements232 *)UlongToPtr(params->pSparseMemoryRequirements), *(uint32_t *)UlongToPtr(params->pSparseMemoryRequirementCount)); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeviceImageSparseMemoryRequirements(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, (uint32_t *)UlongToPtr(params->pSparseMemoryRequirementCount), pSparseMemoryRequirements_host); - convert_VkSparseImageMemoryRequirements2_array_host_to_win32(pSparseMemoryRequirements_host, (VkSparseImageMemoryRequirements232 *)UlongToPtr(params->pSparseMemoryRequirements), *(uint32_t *)UlongToPtr(params->pSparseMemoryRequirementCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceImageSparseMemoryRequirementsKHR(void *args) -{ - struct vkGetDeviceImageSparseMemoryRequirementsKHR_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pInfo, params->pSparseMemoryRequirementCount, params->pSparseMemoryRequirements); - - wine_device_from_handle(params->device)->funcs.p_vkGetDeviceImageSparseMemoryRequirementsKHR(wine_device_from_handle(params->device)->device, params->pInfo, params->pSparseMemoryRequirementCount, params->pSparseMemoryRequirements); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceImageSparseMemoryRequirementsKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pSparseMemoryRequirementCount; - PTR32 pSparseMemoryRequirements; - } *params = args; - VkDeviceImageMemoryRequirements pInfo_host; - VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pInfo, params->pSparseMemoryRequirementCount, params->pSparseMemoryRequirements); - - init_conversion_context(&ctx); - convert_VkDeviceImageMemoryRequirements_win32_to_host(&ctx, (const VkDeviceImageMemoryRequirements32 *)UlongToPtr(params->pInfo), &pInfo_host); - pSparseMemoryRequirements_host = convert_VkSparseImageMemoryRequirements2_array_win32_to_host(&ctx, (VkSparseImageMemoryRequirements232 *)UlongToPtr(params->pSparseMemoryRequirements), *(uint32_t *)UlongToPtr(params->pSparseMemoryRequirementCount)); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeviceImageSparseMemoryRequirementsKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, (uint32_t *)UlongToPtr(params->pSparseMemoryRequirementCount), pSparseMemoryRequirements_host); - convert_VkSparseImageMemoryRequirements2_array_host_to_win32(pSparseMemoryRequirements_host, (VkSparseImageMemoryRequirements232 *)UlongToPtr(params->pSparseMemoryRequirements), *(uint32_t *)UlongToPtr(params->pSparseMemoryRequirementCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceMemoryCommitment(void *args) -{ - struct vkGetDeviceMemoryCommitment_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->memory), params->pCommittedMemoryInBytes); - - wine_device_from_handle(params->device)->funcs.p_vkGetDeviceMemoryCommitment(wine_device_from_handle(params->device)->device, wine_device_memory_from_handle(params->memory)->memory, params->pCommittedMemoryInBytes); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceMemoryCommitment(void *args) -{ - struct - { - PTR32 device; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - PTR32 pCommittedMemoryInBytes; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->memory), params->pCommittedMemoryInBytes); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeviceMemoryCommitment(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, wine_device_memory_from_handle(params->memory)->memory, (VkDeviceSize *)UlongToPtr(params->pCommittedMemoryInBytes)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceMemoryOpaqueCaptureAddress(void *args) -{ - struct vkGetDeviceMemoryOpaqueCaptureAddress_params *params = args; - VkDeviceMemoryOpaqueCaptureAddressInfo pInfo_host; - - TRACE("%p, %p\n", params->device, params->pInfo); - - convert_VkDeviceMemoryOpaqueCaptureAddressInfo_win64_to_host(params->pInfo, &pInfo_host); - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetDeviceMemoryOpaqueCaptureAddress(wine_device_from_handle(params->device)->device, &pInfo_host); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceMemoryOpaqueCaptureAddress(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - uint64_t result; - } *params = args; - VkDeviceMemoryOpaqueCaptureAddressInfo pInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pInfo); - - convert_VkDeviceMemoryOpaqueCaptureAddressInfo_win32_to_host((const VkDeviceMemoryOpaqueCaptureAddressInfo32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeviceMemoryOpaqueCaptureAddress(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceMemoryOpaqueCaptureAddressKHR(void *args) -{ - struct vkGetDeviceMemoryOpaqueCaptureAddressKHR_params *params = args; - VkDeviceMemoryOpaqueCaptureAddressInfo pInfo_host; - - TRACE("%p, %p\n", params->device, params->pInfo); - - convert_VkDeviceMemoryOpaqueCaptureAddressInfo_win64_to_host(params->pInfo, &pInfo_host); - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetDeviceMemoryOpaqueCaptureAddressKHR(wine_device_from_handle(params->device)->device, &pInfo_host); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceMemoryOpaqueCaptureAddressKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - uint64_t result; - } *params = args; - VkDeviceMemoryOpaqueCaptureAddressInfo pInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pInfo); - - convert_VkDeviceMemoryOpaqueCaptureAddressInfo_win32_to_host((const VkDeviceMemoryOpaqueCaptureAddressInfo32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeviceMemoryOpaqueCaptureAddressKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceMicromapCompatibilityEXT(void *args) -{ - struct vkGetDeviceMicromapCompatibilityEXT_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pVersionInfo, params->pCompatibility); - - wine_device_from_handle(params->device)->funcs.p_vkGetDeviceMicromapCompatibilityEXT(wine_device_from_handle(params->device)->device, params->pVersionInfo, params->pCompatibility); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceMicromapCompatibilityEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pVersionInfo; - PTR32 pCompatibility; - } *params = args; - VkMicromapVersionInfoEXT pVersionInfo_host; - - TRACE("%#x, %#x, %#x\n", params->device, params->pVersionInfo, params->pCompatibility); - - convert_VkMicromapVersionInfoEXT_win32_to_host((const VkMicromapVersionInfoEXT32 *)UlongToPtr(params->pVersionInfo), &pVersionInfo_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeviceMicromapCompatibilityEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pVersionInfo_host, (VkAccelerationStructureCompatibilityKHR *)UlongToPtr(params->pCompatibility)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceQueue(void *args) -{ - struct vkGetDeviceQueue_params *params = args; - - TRACE("%p, %u, %u, %p\n", params->device, params->queueFamilyIndex, params->queueIndex, params->pQueue); - - wine_vkGetDeviceQueue(params->device, params->queueFamilyIndex, params->queueIndex, params->pQueue); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceQueue(void *args) -{ - struct - { - PTR32 device; - uint32_t queueFamilyIndex; - uint32_t queueIndex; - PTR32 pQueue; - } *params = args; - VkQueue pQueue_host; - - TRACE("%#x, %u, %u, %#x\n", params->device, params->queueFamilyIndex, params->queueIndex, params->pQueue); - - pQueue_host = UlongToPtr(*(PTR32 *)UlongToPtr(params->pQueue)); - wine_vkGetDeviceQueue((VkDevice)UlongToPtr(params->device), params->queueFamilyIndex, params->queueIndex, &pQueue_host); - *(PTR32 *)UlongToPtr(params->pQueue) = PtrToUlong(pQueue_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceQueue2(void *args) -{ - struct vkGetDeviceQueue2_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pQueueInfo, params->pQueue); - - wine_vkGetDeviceQueue2(params->device, params->pQueueInfo, params->pQueue); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceQueue2(void *args) -{ - struct - { - PTR32 device; - PTR32 pQueueInfo; - PTR32 pQueue; - } *params = args; - VkDeviceQueueInfo2 pQueueInfo_host; - VkQueue pQueue_host; - - TRACE("%#x, %#x, %#x\n", params->device, params->pQueueInfo, params->pQueue); - - convert_VkDeviceQueueInfo2_win32_to_host((const VkDeviceQueueInfo232 *)UlongToPtr(params->pQueueInfo), &pQueueInfo_host); - pQueue_host = UlongToPtr(*(PTR32 *)UlongToPtr(params->pQueue)); - wine_vkGetDeviceQueue2((VkDevice)UlongToPtr(params->device), &pQueueInfo_host, &pQueue_host); - *(PTR32 *)UlongToPtr(params->pQueue) = PtrToUlong(pQueue_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI(void *args) -{ - struct vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->renderpass), params->pMaxWorkgroupSize); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI(wine_device_from_handle(params->device)->device, params->renderpass, params->pMaxWorkgroupSize); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI(void *args) -{ - struct - { - PTR32 device; - VkRenderPass DECLSPEC_ALIGN(8) renderpass; - PTR32 pMaxWorkgroupSize; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->renderpass), params->pMaxWorkgroupSize); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->renderpass, (VkExtent2D *)UlongToPtr(params->pMaxWorkgroupSize)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetDynamicRenderingTilePropertiesQCOM(void *args) -{ - struct vkGetDynamicRenderingTilePropertiesQCOM_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pRenderingInfo, params->pProperties); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetDynamicRenderingTilePropertiesQCOM(wine_device_from_handle(params->device)->device, params->pRenderingInfo, params->pProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetDynamicRenderingTilePropertiesQCOM(void *args) -{ - struct - { - PTR32 device; - PTR32 pRenderingInfo; - PTR32 pProperties; - VkResult result; - } *params = args; - VkRenderingInfo pRenderingInfo_host; - VkTilePropertiesQCOM pProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->device, params->pRenderingInfo, params->pProperties); - - init_conversion_context(&ctx); - convert_VkRenderingInfo_win32_to_host(&ctx, (const VkRenderingInfo32 *)UlongToPtr(params->pRenderingInfo), &pRenderingInfo_host); - convert_VkTilePropertiesQCOM_win32_to_host((VkTilePropertiesQCOM32 *)UlongToPtr(params->pProperties), &pProperties_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetDynamicRenderingTilePropertiesQCOM(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pRenderingInfo_host, &pProperties_host); - convert_VkTilePropertiesQCOM_host_to_win32(&pProperties_host, (VkTilePropertiesQCOM32 *)UlongToPtr(params->pProperties)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetEventStatus(void *args) -{ - struct vkGetEventStatus_params *params = args; - - TRACE("%p, 0x%s\n", params->device, wine_dbgstr_longlong(params->event)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetEventStatus(wine_device_from_handle(params->device)->device, params->event); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetEventStatus(void *args) -{ - struct - { - PTR32 device; - VkEvent DECLSPEC_ALIGN(8) event; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s\n", params->device, wine_dbgstr_longlong(params->event)); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetEventStatus(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->event); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetFenceStatus(void *args) -{ - struct vkGetFenceStatus_params *params = args; - - TRACE("%p, 0x%s\n", params->device, wine_dbgstr_longlong(params->fence)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetFenceStatus(wine_device_from_handle(params->device)->device, params->fence); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetFenceStatus(void *args) -{ - struct - { - PTR32 device; - VkFence DECLSPEC_ALIGN(8) fence; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s\n", params->device, wine_dbgstr_longlong(params->fence)); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetFenceStatus(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->fence); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetFramebufferTilePropertiesQCOM(void *args) -{ - struct vkGetFramebufferTilePropertiesQCOM_params *params = args; - - TRACE("%p, 0x%s, %p, %p\n", params->device, wine_dbgstr_longlong(params->framebuffer), params->pPropertiesCount, params->pProperties); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetFramebufferTilePropertiesQCOM(wine_device_from_handle(params->device)->device, params->framebuffer, params->pPropertiesCount, params->pProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetFramebufferTilePropertiesQCOM(void *args) -{ - struct - { - PTR32 device; - VkFramebuffer DECLSPEC_ALIGN(8) framebuffer; - PTR32 pPropertiesCount; - PTR32 pProperties; - VkResult result; - } *params = args; - VkTilePropertiesQCOM *pProperties_host; - struct conversion_context ctx; - - TRACE("%#x, 0x%s, %#x, %#x\n", params->device, wine_dbgstr_longlong(params->framebuffer), params->pPropertiesCount, params->pProperties); - - init_conversion_context(&ctx); - pProperties_host = convert_VkTilePropertiesQCOM_array_win32_to_host(&ctx, (VkTilePropertiesQCOM32 *)UlongToPtr(params->pProperties), *(uint32_t *)UlongToPtr(params->pPropertiesCount)); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetFramebufferTilePropertiesQCOM(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->framebuffer, (uint32_t *)UlongToPtr(params->pPropertiesCount), pProperties_host); - convert_VkTilePropertiesQCOM_array_host_to_win32(pProperties_host, (VkTilePropertiesQCOM32 *)UlongToPtr(params->pProperties), *(uint32_t *)UlongToPtr(params->pPropertiesCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetGeneratedCommandsMemoryRequirementsNV(void *args) -{ - struct vkGetGeneratedCommandsMemoryRequirementsNV_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pInfo, params->pMemoryRequirements); - - wine_device_from_handle(params->device)->funcs.p_vkGetGeneratedCommandsMemoryRequirementsNV(wine_device_from_handle(params->device)->device, params->pInfo, params->pMemoryRequirements); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetGeneratedCommandsMemoryRequirementsNV(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pMemoryRequirements; - } *params = args; - VkGeneratedCommandsMemoryRequirementsInfoNV pInfo_host; - VkMemoryRequirements2 pMemoryRequirements_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->device, params->pInfo, params->pMemoryRequirements); - - init_conversion_context(&ctx); - convert_VkGeneratedCommandsMemoryRequirementsInfoNV_win32_to_host((const VkGeneratedCommandsMemoryRequirementsInfoNV32 *)UlongToPtr(params->pInfo), &pInfo_host); - convert_VkMemoryRequirements2_win32_to_host(&ctx, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements), &pMemoryRequirements_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetGeneratedCommandsMemoryRequirementsNV(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, &pMemoryRequirements_host); - convert_VkMemoryRequirements2_host_to_win32(&pMemoryRequirements_host, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetImageMemoryRequirements(void *args) -{ - struct vkGetImageMemoryRequirements_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->image), params->pMemoryRequirements); - - wine_device_from_handle(params->device)->funcs.p_vkGetImageMemoryRequirements(wine_device_from_handle(params->device)->device, params->image, params->pMemoryRequirements); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetImageMemoryRequirements(void *args) -{ - struct - { - PTR32 device; - VkImage DECLSPEC_ALIGN(8) image; - PTR32 pMemoryRequirements; - } *params = args; - VkMemoryRequirements pMemoryRequirements_host; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->image), params->pMemoryRequirements); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetImageMemoryRequirements(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->image, &pMemoryRequirements_host); - convert_VkMemoryRequirements_host_to_win32(&pMemoryRequirements_host, (VkMemoryRequirements32 *)UlongToPtr(params->pMemoryRequirements)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetImageMemoryRequirements2(void *args) -{ - struct vkGetImageMemoryRequirements2_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pInfo, params->pMemoryRequirements); - - wine_device_from_handle(params->device)->funcs.p_vkGetImageMemoryRequirements2(wine_device_from_handle(params->device)->device, params->pInfo, params->pMemoryRequirements); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetImageMemoryRequirements2(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pMemoryRequirements; - } *params = args; - VkImageMemoryRequirementsInfo2 pInfo_host; - VkMemoryRequirements2 pMemoryRequirements_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->device, params->pInfo, params->pMemoryRequirements); - - init_conversion_context(&ctx); - convert_VkImageMemoryRequirementsInfo2_win32_to_host(&ctx, (const VkImageMemoryRequirementsInfo232 *)UlongToPtr(params->pInfo), &pInfo_host); - convert_VkMemoryRequirements2_win32_to_host(&ctx, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements), &pMemoryRequirements_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetImageMemoryRequirements2(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, &pMemoryRequirements_host); - convert_VkMemoryRequirements2_host_to_win32(&pMemoryRequirements_host, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetImageMemoryRequirements2KHR(void *args) -{ - struct vkGetImageMemoryRequirements2KHR_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pInfo, params->pMemoryRequirements); - - wine_device_from_handle(params->device)->funcs.p_vkGetImageMemoryRequirements2KHR(wine_device_from_handle(params->device)->device, params->pInfo, params->pMemoryRequirements); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetImageMemoryRequirements2KHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pMemoryRequirements; - } *params = args; - VkImageMemoryRequirementsInfo2 pInfo_host; - VkMemoryRequirements2 pMemoryRequirements_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->device, params->pInfo, params->pMemoryRequirements); - - init_conversion_context(&ctx); - convert_VkImageMemoryRequirementsInfo2_win32_to_host(&ctx, (const VkImageMemoryRequirementsInfo232 *)UlongToPtr(params->pInfo), &pInfo_host); - convert_VkMemoryRequirements2_win32_to_host(&ctx, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements), &pMemoryRequirements_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetImageMemoryRequirements2KHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, &pMemoryRequirements_host); - convert_VkMemoryRequirements2_host_to_win32(&pMemoryRequirements_host, (VkMemoryRequirements232 *)UlongToPtr(params->pMemoryRequirements)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetImageOpaqueCaptureDescriptorDataEXT(void *args) -{ - struct vkGetImageOpaqueCaptureDescriptorDataEXT_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pInfo, params->pData); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetImageOpaqueCaptureDescriptorDataEXT(wine_device_from_handle(params->device)->device, params->pInfo, params->pData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetImageOpaqueCaptureDescriptorDataEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pData; - VkResult result; - } *params = args; - VkImageCaptureDescriptorDataInfoEXT pInfo_host; - - TRACE("%#x, %#x, %#x\n", params->device, params->pInfo, params->pData); - - convert_VkImageCaptureDescriptorDataInfoEXT_win32_to_host((const VkImageCaptureDescriptorDataInfoEXT32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetImageOpaqueCaptureDescriptorDataEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, (void *)UlongToPtr(params->pData)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetImageSparseMemoryRequirements(void *args) -{ - struct vkGetImageSparseMemoryRequirements_params *params = args; - - TRACE("%p, 0x%s, %p, %p\n", params->device, wine_dbgstr_longlong(params->image), params->pSparseMemoryRequirementCount, params->pSparseMemoryRequirements); - - wine_device_from_handle(params->device)->funcs.p_vkGetImageSparseMemoryRequirements(wine_device_from_handle(params->device)->device, params->image, params->pSparseMemoryRequirementCount, params->pSparseMemoryRequirements); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetImageSparseMemoryRequirements(void *args) -{ - struct - { - PTR32 device; - VkImage DECLSPEC_ALIGN(8) image; - PTR32 pSparseMemoryRequirementCount; - PTR32 pSparseMemoryRequirements; - } *params = args; - VkSparseImageMemoryRequirements *pSparseMemoryRequirements_host; - struct conversion_context ctx; - - TRACE("%#x, 0x%s, %#x, %#x\n", params->device, wine_dbgstr_longlong(params->image), params->pSparseMemoryRequirementCount, params->pSparseMemoryRequirements); - - init_conversion_context(&ctx); - pSparseMemoryRequirements_host = (params->pSparseMemoryRequirements && *(uint32_t *)UlongToPtr(params->pSparseMemoryRequirementCount)) ? conversion_context_alloc(&ctx, sizeof(*pSparseMemoryRequirements_host) * *(uint32_t *)UlongToPtr(params->pSparseMemoryRequirementCount)) : NULL; - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetImageSparseMemoryRequirements(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->image, (uint32_t *)UlongToPtr(params->pSparseMemoryRequirementCount), pSparseMemoryRequirements_host); - convert_VkSparseImageMemoryRequirements_array_host_to_win32(pSparseMemoryRequirements_host, (VkSparseImageMemoryRequirements32 *)UlongToPtr(params->pSparseMemoryRequirements), *(uint32_t *)UlongToPtr(params->pSparseMemoryRequirementCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetImageSparseMemoryRequirements2(void *args) -{ - struct vkGetImageSparseMemoryRequirements2_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pInfo, params->pSparseMemoryRequirementCount, params->pSparseMemoryRequirements); - - wine_device_from_handle(params->device)->funcs.p_vkGetImageSparseMemoryRequirements2(wine_device_from_handle(params->device)->device, params->pInfo, params->pSparseMemoryRequirementCount, params->pSparseMemoryRequirements); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetImageSparseMemoryRequirements2(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pSparseMemoryRequirementCount; - PTR32 pSparseMemoryRequirements; - } *params = args; - VkImageSparseMemoryRequirementsInfo2 pInfo_host; - VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pInfo, params->pSparseMemoryRequirementCount, params->pSparseMemoryRequirements); - - init_conversion_context(&ctx); - convert_VkImageSparseMemoryRequirementsInfo2_win32_to_host((const VkImageSparseMemoryRequirementsInfo232 *)UlongToPtr(params->pInfo), &pInfo_host); - pSparseMemoryRequirements_host = convert_VkSparseImageMemoryRequirements2_array_win32_to_host(&ctx, (VkSparseImageMemoryRequirements232 *)UlongToPtr(params->pSparseMemoryRequirements), *(uint32_t *)UlongToPtr(params->pSparseMemoryRequirementCount)); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetImageSparseMemoryRequirements2(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, (uint32_t *)UlongToPtr(params->pSparseMemoryRequirementCount), pSparseMemoryRequirements_host); - convert_VkSparseImageMemoryRequirements2_array_host_to_win32(pSparseMemoryRequirements_host, (VkSparseImageMemoryRequirements232 *)UlongToPtr(params->pSparseMemoryRequirements), *(uint32_t *)UlongToPtr(params->pSparseMemoryRequirementCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetImageSparseMemoryRequirements2KHR(void *args) -{ - struct vkGetImageSparseMemoryRequirements2KHR_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pInfo, params->pSparseMemoryRequirementCount, params->pSparseMemoryRequirements); - - wine_device_from_handle(params->device)->funcs.p_vkGetImageSparseMemoryRequirements2KHR(wine_device_from_handle(params->device)->device, params->pInfo, params->pSparseMemoryRequirementCount, params->pSparseMemoryRequirements); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetImageSparseMemoryRequirements2KHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pSparseMemoryRequirementCount; - PTR32 pSparseMemoryRequirements; - } *params = args; - VkImageSparseMemoryRequirementsInfo2 pInfo_host; - VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pInfo, params->pSparseMemoryRequirementCount, params->pSparseMemoryRequirements); - - init_conversion_context(&ctx); - convert_VkImageSparseMemoryRequirementsInfo2_win32_to_host((const VkImageSparseMemoryRequirementsInfo232 *)UlongToPtr(params->pInfo), &pInfo_host); - pSparseMemoryRequirements_host = convert_VkSparseImageMemoryRequirements2_array_win32_to_host(&ctx, (VkSparseImageMemoryRequirements232 *)UlongToPtr(params->pSparseMemoryRequirements), *(uint32_t *)UlongToPtr(params->pSparseMemoryRequirementCount)); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetImageSparseMemoryRequirements2KHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, (uint32_t *)UlongToPtr(params->pSparseMemoryRequirementCount), pSparseMemoryRequirements_host); - convert_VkSparseImageMemoryRequirements2_array_host_to_win32(pSparseMemoryRequirements_host, (VkSparseImageMemoryRequirements232 *)UlongToPtr(params->pSparseMemoryRequirements), *(uint32_t *)UlongToPtr(params->pSparseMemoryRequirementCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetImageSubresourceLayout(void *args) -{ - struct vkGetImageSubresourceLayout_params *params = args; - - TRACE("%p, 0x%s, %p, %p\n", params->device, wine_dbgstr_longlong(params->image), params->pSubresource, params->pLayout); - - wine_device_from_handle(params->device)->funcs.p_vkGetImageSubresourceLayout(wine_device_from_handle(params->device)->device, params->image, params->pSubresource, params->pLayout); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetImageSubresourceLayout(void *args) -{ - struct - { - PTR32 device; - VkImage DECLSPEC_ALIGN(8) image; - PTR32 pSubresource; - PTR32 pLayout; - } *params = args; - VkSubresourceLayout pLayout_host; - - TRACE("%#x, 0x%s, %#x, %#x\n", params->device, wine_dbgstr_longlong(params->image), params->pSubresource, params->pLayout); - - convert_VkSubresourceLayout_win32_to_host((VkSubresourceLayout32 *)UlongToPtr(params->pLayout), &pLayout_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetImageSubresourceLayout(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->image, (const VkImageSubresource *)UlongToPtr(params->pSubresource), &pLayout_host); - convert_VkSubresourceLayout_host_to_win32(&pLayout_host, (VkSubresourceLayout32 *)UlongToPtr(params->pLayout)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetImageSubresourceLayout2EXT(void *args) -{ - struct vkGetImageSubresourceLayout2EXT_params *params = args; - - TRACE("%p, 0x%s, %p, %p\n", params->device, wine_dbgstr_longlong(params->image), params->pSubresource, params->pLayout); - - wine_device_from_handle(params->device)->funcs.p_vkGetImageSubresourceLayout2EXT(wine_device_from_handle(params->device)->device, params->image, params->pSubresource, params->pLayout); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetImageSubresourceLayout2EXT(void *args) -{ - struct - { - PTR32 device; - VkImage DECLSPEC_ALIGN(8) image; - PTR32 pSubresource; - PTR32 pLayout; - } *params = args; - VkImageSubresource2EXT pSubresource_host; - VkSubresourceLayout2EXT pLayout_host; - struct conversion_context ctx; - - TRACE("%#x, 0x%s, %#x, %#x\n", params->device, wine_dbgstr_longlong(params->image), params->pSubresource, params->pLayout); - - init_conversion_context(&ctx); - convert_VkImageSubresource2EXT_win32_to_host((const VkImageSubresource2EXT32 *)UlongToPtr(params->pSubresource), &pSubresource_host); - convert_VkSubresourceLayout2EXT_win32_to_host(&ctx, (VkSubresourceLayout2EXT32 *)UlongToPtr(params->pLayout), &pLayout_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetImageSubresourceLayout2EXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->image, &pSubresource_host, &pLayout_host); - convert_VkSubresourceLayout2EXT_host_to_win32(&pLayout_host, (VkSubresourceLayout2EXT32 *)UlongToPtr(params->pLayout)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetImageViewAddressNVX(void *args) -{ - struct vkGetImageViewAddressNVX_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->imageView), params->pProperties); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetImageViewAddressNVX(wine_device_from_handle(params->device)->device, params->imageView, params->pProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetImageViewAddressNVX(void *args) -{ - struct - { - PTR32 device; - VkImageView DECLSPEC_ALIGN(8) imageView; - PTR32 pProperties; - VkResult result; - } *params = args; - VkImageViewAddressPropertiesNVX pProperties_host; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->imageView), params->pProperties); - - convert_VkImageViewAddressPropertiesNVX_win32_to_host((VkImageViewAddressPropertiesNVX32 *)UlongToPtr(params->pProperties), &pProperties_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetImageViewAddressNVX(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->imageView, &pProperties_host); - convert_VkImageViewAddressPropertiesNVX_host_to_win32(&pProperties_host, (VkImageViewAddressPropertiesNVX32 *)UlongToPtr(params->pProperties)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetImageViewHandleNVX(void *args) -{ - struct vkGetImageViewHandleNVX_params *params = args; - - TRACE("%p, %p\n", params->device, params->pInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetImageViewHandleNVX(wine_device_from_handle(params->device)->device, params->pInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetImageViewHandleNVX(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - uint32_t result; - } *params = args; - VkImageViewHandleInfoNVX pInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pInfo); - - convert_VkImageViewHandleInfoNVX_win32_to_host((const VkImageViewHandleInfoNVX32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetImageViewHandleNVX(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetImageViewOpaqueCaptureDescriptorDataEXT(void *args) -{ - struct vkGetImageViewOpaqueCaptureDescriptorDataEXT_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pInfo, params->pData); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetImageViewOpaqueCaptureDescriptorDataEXT(wine_device_from_handle(params->device)->device, params->pInfo, params->pData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetImageViewOpaqueCaptureDescriptorDataEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pData; - VkResult result; - } *params = args; - VkImageViewCaptureDescriptorDataInfoEXT pInfo_host; - - TRACE("%#x, %#x, %#x\n", params->device, params->pInfo, params->pData); - - convert_VkImageViewCaptureDescriptorDataInfoEXT_win32_to_host((const VkImageViewCaptureDescriptorDataInfoEXT32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetImageViewOpaqueCaptureDescriptorDataEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, (void *)UlongToPtr(params->pData)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetMemoryHostPointerPropertiesEXT(void *args) -{ - struct vkGetMemoryHostPointerPropertiesEXT_params *params = args; - - TRACE("%p, %#x, %p, %p\n", params->device, params->handleType, params->pHostPointer, params->pMemoryHostPointerProperties); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetMemoryHostPointerPropertiesEXT(wine_device_from_handle(params->device)->device, params->handleType, params->pHostPointer, params->pMemoryHostPointerProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetMemoryHostPointerPropertiesEXT(void *args) -{ - struct - { - PTR32 device; - VkExternalMemoryHandleTypeFlagBits handleType; - PTR32 pHostPointer; - PTR32 pMemoryHostPointerProperties; - VkResult result; - } *params = args; - VkMemoryHostPointerPropertiesEXT pMemoryHostPointerProperties_host; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->handleType, params->pHostPointer, params->pMemoryHostPointerProperties); - - convert_VkMemoryHostPointerPropertiesEXT_win32_to_host((VkMemoryHostPointerPropertiesEXT32 *)UlongToPtr(params->pMemoryHostPointerProperties), &pMemoryHostPointerProperties_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetMemoryHostPointerPropertiesEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->handleType, (const void *)UlongToPtr(params->pHostPointer), &pMemoryHostPointerProperties_host); - convert_VkMemoryHostPointerPropertiesEXT_host_to_win32(&pMemoryHostPointerProperties_host, (VkMemoryHostPointerPropertiesEXT32 *)UlongToPtr(params->pMemoryHostPointerProperties)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetMicromapBuildSizesEXT(void *args) -{ - struct vkGetMicromapBuildSizesEXT_params *params = args; - - TRACE("%p, %#x, %p, %p\n", params->device, params->buildType, params->pBuildInfo, params->pSizeInfo); - - wine_device_from_handle(params->device)->funcs.p_vkGetMicromapBuildSizesEXT(wine_device_from_handle(params->device)->device, params->buildType, params->pBuildInfo, params->pSizeInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetMicromapBuildSizesEXT(void *args) -{ - struct - { - PTR32 device; - VkAccelerationStructureBuildTypeKHR buildType; - PTR32 pBuildInfo; - PTR32 pSizeInfo; - } *params = args; - VkMicromapBuildInfoEXT pBuildInfo_host; - VkMicromapBuildSizesInfoEXT pSizeInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->buildType, params->pBuildInfo, params->pSizeInfo); - - init_conversion_context(&ctx); - convert_VkMicromapBuildInfoEXT_win32_to_host(&ctx, (const VkMicromapBuildInfoEXT32 *)UlongToPtr(params->pBuildInfo), &pBuildInfo_host); - convert_VkMicromapBuildSizesInfoEXT_win32_to_host((VkMicromapBuildSizesInfoEXT32 *)UlongToPtr(params->pSizeInfo), &pSizeInfo_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetMicromapBuildSizesEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->buildType, &pBuildInfo_host, &pSizeInfo_host); - convert_VkMicromapBuildSizesInfoEXT_host_to_win32(&pSizeInfo_host, (VkMicromapBuildSizesInfoEXT32 *)UlongToPtr(params->pSizeInfo)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPerformanceParameterINTEL(void *args) -{ - struct vkGetPerformanceParameterINTEL_params *params = args; - - TRACE("%p, %#x, %p\n", params->device, params->parameter, params->pValue); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetPerformanceParameterINTEL(wine_device_from_handle(params->device)->device, params->parameter, params->pValue); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPerformanceParameterINTEL(void *args) -{ - struct - { - PTR32 device; - VkPerformanceParameterTypeINTEL parameter; - PTR32 pValue; - VkResult result; - } *params = args; - VkPerformanceValueINTEL pValue_host; - - TRACE("%#x, %#x, %#x\n", params->device, params->parameter, params->pValue); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetPerformanceParameterINTEL(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->parameter, &pValue_host); - convert_VkPerformanceValueINTEL_host_to_win32(&pValue_host, (VkPerformanceValueINTEL32 *)UlongToPtr(params->pValue)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(void *args) -{ - struct vkGetPhysicalDeviceCalibrateableTimeDomainsEXT_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pTimeDomainCount, params->pTimeDomains); - - params->result = wine_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(params->physicalDevice, params->pTimeDomainCount, params->pTimeDomains); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pTimeDomainCount; - PTR32 pTimeDomains; - VkResult result; - } *params = args; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pTimeDomainCount, params->pTimeDomains); - - params->result = wine_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT((VkPhysicalDevice)UlongToPtr(params->physicalDevice), (uint32_t *)UlongToPtr(params->pTimeDomainCount), (VkTimeDomainEXT *)UlongToPtr(params->pTimeDomains)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV(void *args) -{ - struct vkGetPhysicalDeviceCooperativeMatrixPropertiesNV_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pPropertyCount, params->pProperties); - - params->result = wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pPropertyCount, params->pProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pPropertyCount; - PTR32 pProperties; - VkResult result; - } *params = args; - VkCooperativeMatrixPropertiesNV *pProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pPropertyCount, params->pProperties); - - init_conversion_context(&ctx); - pProperties_host = convert_VkCooperativeMatrixPropertiesNV_array_win32_to_host(&ctx, (VkCooperativeMatrixPropertiesNV32 *)UlongToPtr(params->pProperties), *(uint32_t *)UlongToPtr(params->pPropertyCount)); - params->result = wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, (uint32_t *)UlongToPtr(params->pPropertyCount), pProperties_host); - convert_VkCooperativeMatrixPropertiesNV_array_host_to_win32(pProperties_host, (VkCooperativeMatrixPropertiesNV32 *)UlongToPtr(params->pProperties), *(uint32_t *)UlongToPtr(params->pPropertyCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceExternalBufferProperties(void *args) -{ - struct vkGetPhysicalDeviceExternalBufferProperties_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pExternalBufferInfo, params->pExternalBufferProperties); - - wine_vkGetPhysicalDeviceExternalBufferProperties(params->physicalDevice, params->pExternalBufferInfo, params->pExternalBufferProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceExternalBufferProperties(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pExternalBufferInfo; - PTR32 pExternalBufferProperties; - } *params = args; - VkPhysicalDeviceExternalBufferInfo pExternalBufferInfo_host; - VkExternalBufferProperties pExternalBufferProperties_host; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pExternalBufferInfo, params->pExternalBufferProperties); - - convert_VkPhysicalDeviceExternalBufferInfo_win32_to_host((const VkPhysicalDeviceExternalBufferInfo32 *)UlongToPtr(params->pExternalBufferInfo), &pExternalBufferInfo_host); - convert_VkExternalBufferProperties_win32_to_host((VkExternalBufferProperties32 *)UlongToPtr(params->pExternalBufferProperties), &pExternalBufferProperties_host); - wine_vkGetPhysicalDeviceExternalBufferProperties((VkPhysicalDevice)UlongToPtr(params->physicalDevice), &pExternalBufferInfo_host, &pExternalBufferProperties_host); - convert_VkExternalBufferProperties_host_to_win32(&pExternalBufferProperties_host, (VkExternalBufferProperties32 *)UlongToPtr(params->pExternalBufferProperties)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceExternalBufferPropertiesKHR(void *args) -{ - struct vkGetPhysicalDeviceExternalBufferPropertiesKHR_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pExternalBufferInfo, params->pExternalBufferProperties); - - wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR(params->physicalDevice, params->pExternalBufferInfo, params->pExternalBufferProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceExternalBufferPropertiesKHR(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pExternalBufferInfo; - PTR32 pExternalBufferProperties; - } *params = args; - VkPhysicalDeviceExternalBufferInfo pExternalBufferInfo_host; - VkExternalBufferProperties pExternalBufferProperties_host; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pExternalBufferInfo, params->pExternalBufferProperties); - - convert_VkPhysicalDeviceExternalBufferInfo_win32_to_host((const VkPhysicalDeviceExternalBufferInfo32 *)UlongToPtr(params->pExternalBufferInfo), &pExternalBufferInfo_host); - convert_VkExternalBufferProperties_win32_to_host((VkExternalBufferProperties32 *)UlongToPtr(params->pExternalBufferProperties), &pExternalBufferProperties_host); - wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR((VkPhysicalDevice)UlongToPtr(params->physicalDevice), &pExternalBufferInfo_host, &pExternalBufferProperties_host); - convert_VkExternalBufferProperties_host_to_win32(&pExternalBufferProperties_host, (VkExternalBufferProperties32 *)UlongToPtr(params->pExternalBufferProperties)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceExternalFenceProperties(void *args) -{ - struct vkGetPhysicalDeviceExternalFenceProperties_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pExternalFenceInfo, params->pExternalFenceProperties); - - wine_vkGetPhysicalDeviceExternalFenceProperties(params->physicalDevice, params->pExternalFenceInfo, params->pExternalFenceProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceExternalFenceProperties(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pExternalFenceInfo; - PTR32 pExternalFenceProperties; - } *params = args; - VkPhysicalDeviceExternalFenceInfo pExternalFenceInfo_host; - VkExternalFenceProperties pExternalFenceProperties_host; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pExternalFenceInfo, params->pExternalFenceProperties); - - convert_VkPhysicalDeviceExternalFenceInfo_win32_to_host((const VkPhysicalDeviceExternalFenceInfo32 *)UlongToPtr(params->pExternalFenceInfo), &pExternalFenceInfo_host); - convert_VkExternalFenceProperties_win32_to_host((VkExternalFenceProperties32 *)UlongToPtr(params->pExternalFenceProperties), &pExternalFenceProperties_host); - wine_vkGetPhysicalDeviceExternalFenceProperties((VkPhysicalDevice)UlongToPtr(params->physicalDevice), &pExternalFenceInfo_host, &pExternalFenceProperties_host); - convert_VkExternalFenceProperties_host_to_win32(&pExternalFenceProperties_host, (VkExternalFenceProperties32 *)UlongToPtr(params->pExternalFenceProperties)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceExternalFencePropertiesKHR(void *args) -{ - struct vkGetPhysicalDeviceExternalFencePropertiesKHR_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pExternalFenceInfo, params->pExternalFenceProperties); - - wine_vkGetPhysicalDeviceExternalFencePropertiesKHR(params->physicalDevice, params->pExternalFenceInfo, params->pExternalFenceProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceExternalFencePropertiesKHR(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pExternalFenceInfo; - PTR32 pExternalFenceProperties; - } *params = args; - VkPhysicalDeviceExternalFenceInfo pExternalFenceInfo_host; - VkExternalFenceProperties pExternalFenceProperties_host; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pExternalFenceInfo, params->pExternalFenceProperties); - - convert_VkPhysicalDeviceExternalFenceInfo_win32_to_host((const VkPhysicalDeviceExternalFenceInfo32 *)UlongToPtr(params->pExternalFenceInfo), &pExternalFenceInfo_host); - convert_VkExternalFenceProperties_win32_to_host((VkExternalFenceProperties32 *)UlongToPtr(params->pExternalFenceProperties), &pExternalFenceProperties_host); - wine_vkGetPhysicalDeviceExternalFencePropertiesKHR((VkPhysicalDevice)UlongToPtr(params->physicalDevice), &pExternalFenceInfo_host, &pExternalFenceProperties_host); - convert_VkExternalFenceProperties_host_to_win32(&pExternalFenceProperties_host, (VkExternalFenceProperties32 *)UlongToPtr(params->pExternalFenceProperties)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceExternalSemaphoreProperties(void *args) -{ - struct vkGetPhysicalDeviceExternalSemaphoreProperties_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pExternalSemaphoreInfo, params->pExternalSemaphoreProperties); - - wine_vkGetPhysicalDeviceExternalSemaphoreProperties(params->physicalDevice, params->pExternalSemaphoreInfo, params->pExternalSemaphoreProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceExternalSemaphoreProperties(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pExternalSemaphoreInfo; - PTR32 pExternalSemaphoreProperties; - } *params = args; - VkPhysicalDeviceExternalSemaphoreInfo pExternalSemaphoreInfo_host; - VkExternalSemaphoreProperties pExternalSemaphoreProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pExternalSemaphoreInfo, params->pExternalSemaphoreProperties); - - init_conversion_context(&ctx); - convert_VkPhysicalDeviceExternalSemaphoreInfo_win32_to_host(&ctx, (const VkPhysicalDeviceExternalSemaphoreInfo32 *)UlongToPtr(params->pExternalSemaphoreInfo), &pExternalSemaphoreInfo_host); - convert_VkExternalSemaphoreProperties_win32_to_host((VkExternalSemaphoreProperties32 *)UlongToPtr(params->pExternalSemaphoreProperties), &pExternalSemaphoreProperties_host); - wine_vkGetPhysicalDeviceExternalSemaphoreProperties((VkPhysicalDevice)UlongToPtr(params->physicalDevice), &pExternalSemaphoreInfo_host, &pExternalSemaphoreProperties_host); - convert_VkExternalSemaphoreProperties_host_to_win32(&pExternalSemaphoreProperties_host, (VkExternalSemaphoreProperties32 *)UlongToPtr(params->pExternalSemaphoreProperties)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(void *args) -{ - struct vkGetPhysicalDeviceExternalSemaphorePropertiesKHR_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pExternalSemaphoreInfo, params->pExternalSemaphoreProperties); - - wine_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(params->physicalDevice, params->pExternalSemaphoreInfo, params->pExternalSemaphoreProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pExternalSemaphoreInfo; - PTR32 pExternalSemaphoreProperties; - } *params = args; - VkPhysicalDeviceExternalSemaphoreInfo pExternalSemaphoreInfo_host; - VkExternalSemaphoreProperties pExternalSemaphoreProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pExternalSemaphoreInfo, params->pExternalSemaphoreProperties); - - init_conversion_context(&ctx); - convert_VkPhysicalDeviceExternalSemaphoreInfo_win32_to_host(&ctx, (const VkPhysicalDeviceExternalSemaphoreInfo32 *)UlongToPtr(params->pExternalSemaphoreInfo), &pExternalSemaphoreInfo_host); - convert_VkExternalSemaphoreProperties_win32_to_host((VkExternalSemaphoreProperties32 *)UlongToPtr(params->pExternalSemaphoreProperties), &pExternalSemaphoreProperties_host); - wine_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR((VkPhysicalDevice)UlongToPtr(params->physicalDevice), &pExternalSemaphoreInfo_host, &pExternalSemaphoreProperties_host); - convert_VkExternalSemaphoreProperties_host_to_win32(&pExternalSemaphoreProperties_host, (VkExternalSemaphoreProperties32 *)UlongToPtr(params->pExternalSemaphoreProperties)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceFeatures(void *args) -{ - struct vkGetPhysicalDeviceFeatures_params *params = args; - - TRACE("%p, %p\n", params->physicalDevice, params->pFeatures); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceFeatures(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pFeatures); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceFeatures(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pFeatures; - } *params = args; - - TRACE("%#x, %#x\n", params->physicalDevice, params->pFeatures); - - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceFeatures(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, (VkPhysicalDeviceFeatures *)UlongToPtr(params->pFeatures)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceFeatures2(void *args) -{ - struct vkGetPhysicalDeviceFeatures2_params *params = args; - - TRACE("%p, %p\n", params->physicalDevice, params->pFeatures); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceFeatures2(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pFeatures); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceFeatures2(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pFeatures; - } *params = args; - VkPhysicalDeviceFeatures2 pFeatures_host; - struct conversion_context ctx; - - TRACE("%#x, %#x\n", params->physicalDevice, params->pFeatures); - - init_conversion_context(&ctx); - convert_VkPhysicalDeviceFeatures2_win32_to_host(&ctx, (VkPhysicalDeviceFeatures232 *)UlongToPtr(params->pFeatures), &pFeatures_host); - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceFeatures2(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, &pFeatures_host); - convert_VkPhysicalDeviceFeatures2_host_to_win32(&pFeatures_host, (VkPhysicalDeviceFeatures232 *)UlongToPtr(params->pFeatures)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceFeatures2KHR(void *args) -{ - struct vkGetPhysicalDeviceFeatures2KHR_params *params = args; - - TRACE("%p, %p\n", params->physicalDevice, params->pFeatures); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceFeatures2KHR(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pFeatures); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceFeatures2KHR(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pFeatures; - } *params = args; - VkPhysicalDeviceFeatures2 pFeatures_host; - struct conversion_context ctx; - - TRACE("%#x, %#x\n", params->physicalDevice, params->pFeatures); - - init_conversion_context(&ctx); - convert_VkPhysicalDeviceFeatures2_win32_to_host(&ctx, (VkPhysicalDeviceFeatures232 *)UlongToPtr(params->pFeatures), &pFeatures_host); - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceFeatures2KHR(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, &pFeatures_host); - convert_VkPhysicalDeviceFeatures2_host_to_win32(&pFeatures_host, (VkPhysicalDeviceFeatures232 *)UlongToPtr(params->pFeatures)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceFormatProperties(void *args) -{ - struct vkGetPhysicalDeviceFormatProperties_params *params = args; - - TRACE("%p, %#x, %p\n", params->physicalDevice, params->format, params->pFormatProperties); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceFormatProperties(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->format, params->pFormatProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceFormatProperties(void *args) -{ - struct - { - PTR32 physicalDevice; - VkFormat format; - PTR32 pFormatProperties; - } *params = args; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->format, params->pFormatProperties); - - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceFormatProperties(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, params->format, (VkFormatProperties *)UlongToPtr(params->pFormatProperties)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceFormatProperties2(void *args) -{ - struct vkGetPhysicalDeviceFormatProperties2_params *params = args; - - TRACE("%p, %#x, %p\n", params->physicalDevice, params->format, params->pFormatProperties); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceFormatProperties2(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->format, params->pFormatProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceFormatProperties2(void *args) -{ - struct - { - PTR32 physicalDevice; - VkFormat format; - PTR32 pFormatProperties; - } *params = args; - VkFormatProperties2 pFormatProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->format, params->pFormatProperties); - - init_conversion_context(&ctx); - convert_VkFormatProperties2_win32_to_host(&ctx, (VkFormatProperties232 *)UlongToPtr(params->pFormatProperties), &pFormatProperties_host); - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceFormatProperties2(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, params->format, &pFormatProperties_host); - convert_VkFormatProperties2_host_to_win32(&pFormatProperties_host, (VkFormatProperties232 *)UlongToPtr(params->pFormatProperties)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceFormatProperties2KHR(void *args) -{ - struct vkGetPhysicalDeviceFormatProperties2KHR_params *params = args; - - TRACE("%p, %#x, %p\n", params->physicalDevice, params->format, params->pFormatProperties); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceFormatProperties2KHR(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->format, params->pFormatProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceFormatProperties2KHR(void *args) -{ - struct - { - PTR32 physicalDevice; - VkFormat format; - PTR32 pFormatProperties; - } *params = args; - VkFormatProperties2 pFormatProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->format, params->pFormatProperties); - - init_conversion_context(&ctx); - convert_VkFormatProperties2_win32_to_host(&ctx, (VkFormatProperties232 *)UlongToPtr(params->pFormatProperties), &pFormatProperties_host); - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceFormatProperties2KHR(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, params->format, &pFormatProperties_host); - convert_VkFormatProperties2_host_to_win32(&pFormatProperties_host, (VkFormatProperties232 *)UlongToPtr(params->pFormatProperties)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceFragmentShadingRatesKHR(void *args) -{ - struct vkGetPhysicalDeviceFragmentShadingRatesKHR_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pFragmentShadingRateCount, params->pFragmentShadingRates); - - params->result = wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceFragmentShadingRatesKHR(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pFragmentShadingRateCount, params->pFragmentShadingRates); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceFragmentShadingRatesKHR(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pFragmentShadingRateCount; - PTR32 pFragmentShadingRates; - VkResult result; - } *params = args; - VkPhysicalDeviceFragmentShadingRateKHR *pFragmentShadingRates_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pFragmentShadingRateCount, params->pFragmentShadingRates); - - init_conversion_context(&ctx); - pFragmentShadingRates_host = convert_VkPhysicalDeviceFragmentShadingRateKHR_array_win32_to_host(&ctx, (VkPhysicalDeviceFragmentShadingRateKHR32 *)UlongToPtr(params->pFragmentShadingRates), *(uint32_t *)UlongToPtr(params->pFragmentShadingRateCount)); - params->result = wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceFragmentShadingRatesKHR(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, (uint32_t *)UlongToPtr(params->pFragmentShadingRateCount), pFragmentShadingRates_host); - convert_VkPhysicalDeviceFragmentShadingRateKHR_array_host_to_win32(pFragmentShadingRates_host, (VkPhysicalDeviceFragmentShadingRateKHR32 *)UlongToPtr(params->pFragmentShadingRates), *(uint32_t *)UlongToPtr(params->pFragmentShadingRateCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceImageFormatProperties(void *args) -{ - struct vkGetPhysicalDeviceImageFormatProperties_params *params = args; - - TRACE("%p, %#x, %#x, %#x, %#x, %#x, %p\n", params->physicalDevice, params->format, params->type, params->tiling, params->usage, params->flags, params->pImageFormatProperties); - - params->result = wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceImageFormatProperties(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->format, params->type, params->tiling, params->usage, params->flags, params->pImageFormatProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceImageFormatProperties(void *args) -{ - struct - { - PTR32 physicalDevice; - VkFormat format; - VkImageType type; - VkImageTiling tiling; - VkImageUsageFlags usage; - VkImageCreateFlags flags; - PTR32 pImageFormatProperties; - VkResult result; - } *params = args; - VkImageFormatProperties pImageFormatProperties_host; - - TRACE("%#x, %#x, %#x, %#x, %#x, %#x, %#x\n", params->physicalDevice, params->format, params->type, params->tiling, params->usage, params->flags, params->pImageFormatProperties); - - params->result = wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceImageFormatProperties(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, params->format, params->type, params->tiling, params->usage, params->flags, &pImageFormatProperties_host); - convert_VkImageFormatProperties_host_to_win32(&pImageFormatProperties_host, (VkImageFormatProperties32 *)UlongToPtr(params->pImageFormatProperties)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceImageFormatProperties2(void *args) -{ - struct vkGetPhysicalDeviceImageFormatProperties2_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pImageFormatInfo, params->pImageFormatProperties); - - params->result = wine_vkGetPhysicalDeviceImageFormatProperties2(params->physicalDevice, params->pImageFormatInfo, params->pImageFormatProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceImageFormatProperties2(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pImageFormatInfo; - PTR32 pImageFormatProperties; - VkResult result; - } *params = args; - VkPhysicalDeviceImageFormatInfo2 pImageFormatInfo_host; - VkImageFormatProperties2 pImageFormatProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pImageFormatInfo, params->pImageFormatProperties); - - init_conversion_context(&ctx); - convert_VkPhysicalDeviceImageFormatInfo2_win32_to_host(&ctx, (const VkPhysicalDeviceImageFormatInfo232 *)UlongToPtr(params->pImageFormatInfo), &pImageFormatInfo_host); - convert_VkImageFormatProperties2_win32_to_host(&ctx, (VkImageFormatProperties232 *)UlongToPtr(params->pImageFormatProperties), &pImageFormatProperties_host); - params->result = wine_vkGetPhysicalDeviceImageFormatProperties2((VkPhysicalDevice)UlongToPtr(params->physicalDevice), &pImageFormatInfo_host, &pImageFormatProperties_host); - convert_VkImageFormatProperties2_host_to_win32(&pImageFormatProperties_host, (VkImageFormatProperties232 *)UlongToPtr(params->pImageFormatProperties)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceImageFormatProperties2KHR(void *args) -{ - struct vkGetPhysicalDeviceImageFormatProperties2KHR_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pImageFormatInfo, params->pImageFormatProperties); - - params->result = wine_vkGetPhysicalDeviceImageFormatProperties2KHR(params->physicalDevice, params->pImageFormatInfo, params->pImageFormatProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceImageFormatProperties2KHR(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pImageFormatInfo; - PTR32 pImageFormatProperties; - VkResult result; - } *params = args; - VkPhysicalDeviceImageFormatInfo2 pImageFormatInfo_host; - VkImageFormatProperties2 pImageFormatProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pImageFormatInfo, params->pImageFormatProperties); - - init_conversion_context(&ctx); - convert_VkPhysicalDeviceImageFormatInfo2_win32_to_host(&ctx, (const VkPhysicalDeviceImageFormatInfo232 *)UlongToPtr(params->pImageFormatInfo), &pImageFormatInfo_host); - convert_VkImageFormatProperties2_win32_to_host(&ctx, (VkImageFormatProperties232 *)UlongToPtr(params->pImageFormatProperties), &pImageFormatProperties_host); - params->result = wine_vkGetPhysicalDeviceImageFormatProperties2KHR((VkPhysicalDevice)UlongToPtr(params->physicalDevice), &pImageFormatInfo_host, &pImageFormatProperties_host); - convert_VkImageFormatProperties2_host_to_win32(&pImageFormatProperties_host, (VkImageFormatProperties232 *)UlongToPtr(params->pImageFormatProperties)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceMemoryProperties(void *args) -{ - struct vkGetPhysicalDeviceMemoryProperties_params *params = args; - - TRACE("%p, %p\n", params->physicalDevice, params->pMemoryProperties); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceMemoryProperties(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pMemoryProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceMemoryProperties(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pMemoryProperties; - } *params = args; - VkPhysicalDeviceMemoryProperties pMemoryProperties_host; - - TRACE("%#x, %#x\n", params->physicalDevice, params->pMemoryProperties); - - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceMemoryProperties(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, &pMemoryProperties_host); - convert_VkPhysicalDeviceMemoryProperties_host_to_win32(&pMemoryProperties_host, (VkPhysicalDeviceMemoryProperties32 *)UlongToPtr(params->pMemoryProperties)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceMemoryProperties2(void *args) -{ - struct vkGetPhysicalDeviceMemoryProperties2_params *params = args; - - TRACE("%p, %p\n", params->physicalDevice, params->pMemoryProperties); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceMemoryProperties2(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pMemoryProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceMemoryProperties2(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pMemoryProperties; - } *params = args; - VkPhysicalDeviceMemoryProperties2 pMemoryProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x\n", params->physicalDevice, params->pMemoryProperties); - - init_conversion_context(&ctx); - convert_VkPhysicalDeviceMemoryProperties2_win32_to_host(&ctx, (VkPhysicalDeviceMemoryProperties232 *)UlongToPtr(params->pMemoryProperties), &pMemoryProperties_host); - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceMemoryProperties2(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, &pMemoryProperties_host); - convert_VkPhysicalDeviceMemoryProperties2_host_to_win32(&pMemoryProperties_host, (VkPhysicalDeviceMemoryProperties232 *)UlongToPtr(params->pMemoryProperties)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceMemoryProperties2KHR(void *args) -{ - struct vkGetPhysicalDeviceMemoryProperties2KHR_params *params = args; - - TRACE("%p, %p\n", params->physicalDevice, params->pMemoryProperties); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceMemoryProperties2KHR(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pMemoryProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceMemoryProperties2KHR(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pMemoryProperties; - } *params = args; - VkPhysicalDeviceMemoryProperties2 pMemoryProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x\n", params->physicalDevice, params->pMemoryProperties); - - init_conversion_context(&ctx); - convert_VkPhysicalDeviceMemoryProperties2_win32_to_host(&ctx, (VkPhysicalDeviceMemoryProperties232 *)UlongToPtr(params->pMemoryProperties), &pMemoryProperties_host); - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceMemoryProperties2KHR(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, &pMemoryProperties_host); - convert_VkPhysicalDeviceMemoryProperties2_host_to_win32(&pMemoryProperties_host, (VkPhysicalDeviceMemoryProperties232 *)UlongToPtr(params->pMemoryProperties)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceMultisamplePropertiesEXT(void *args) -{ - struct vkGetPhysicalDeviceMultisamplePropertiesEXT_params *params = args; - - TRACE("%p, %#x, %p\n", params->physicalDevice, params->samples, params->pMultisampleProperties); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceMultisamplePropertiesEXT(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->samples, params->pMultisampleProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceMultisamplePropertiesEXT(void *args) -{ - struct - { - PTR32 physicalDevice; - VkSampleCountFlagBits samples; - PTR32 pMultisampleProperties; - } *params = args; - VkMultisamplePropertiesEXT pMultisampleProperties_host; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->samples, params->pMultisampleProperties); - - convert_VkMultisamplePropertiesEXT_win32_to_host((VkMultisamplePropertiesEXT32 *)UlongToPtr(params->pMultisampleProperties), &pMultisampleProperties_host); - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceMultisamplePropertiesEXT(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, params->samples, &pMultisampleProperties_host); - convert_VkMultisamplePropertiesEXT_host_to_win32(&pMultisampleProperties_host, (VkMultisamplePropertiesEXT32 *)UlongToPtr(params->pMultisampleProperties)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceOpticalFlowImageFormatsNV(void *args) -{ - struct vkGetPhysicalDeviceOpticalFlowImageFormatsNV_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->physicalDevice, params->pOpticalFlowImageFormatInfo, params->pFormatCount, params->pImageFormatProperties); - - params->result = wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceOpticalFlowImageFormatsNV(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pOpticalFlowImageFormatInfo, params->pFormatCount, params->pImageFormatProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceOpticalFlowImageFormatsNV(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pOpticalFlowImageFormatInfo; - PTR32 pFormatCount; - PTR32 pImageFormatProperties; - VkResult result; - } *params = args; - VkOpticalFlowImageFormatInfoNV pOpticalFlowImageFormatInfo_host; - VkOpticalFlowImageFormatPropertiesNV *pImageFormatProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->physicalDevice, params->pOpticalFlowImageFormatInfo, params->pFormatCount, params->pImageFormatProperties); - - init_conversion_context(&ctx); - convert_VkOpticalFlowImageFormatInfoNV_win32_to_host((const VkOpticalFlowImageFormatInfoNV32 *)UlongToPtr(params->pOpticalFlowImageFormatInfo), &pOpticalFlowImageFormatInfo_host); - pImageFormatProperties_host = convert_VkOpticalFlowImageFormatPropertiesNV_array_win32_to_host(&ctx, (VkOpticalFlowImageFormatPropertiesNV32 *)UlongToPtr(params->pImageFormatProperties), *(uint32_t *)UlongToPtr(params->pFormatCount)); - params->result = wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceOpticalFlowImageFormatsNV(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, &pOpticalFlowImageFormatInfo_host, (uint32_t *)UlongToPtr(params->pFormatCount), pImageFormatProperties_host); - convert_VkOpticalFlowImageFormatPropertiesNV_array_host_to_win32(pImageFormatProperties_host, (VkOpticalFlowImageFormatPropertiesNV32 *)UlongToPtr(params->pImageFormatProperties), *(uint32_t *)UlongToPtr(params->pFormatCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDevicePresentRectanglesKHR(void *args) -{ - struct vkGetPhysicalDevicePresentRectanglesKHR_params *params = args; - - TRACE("%p, 0x%s, %p, %p\n", params->physicalDevice, wine_dbgstr_longlong(params->surface), params->pRectCount, params->pRects); - - params->result = wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDevicePresentRectanglesKHR(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, wine_surface_from_handle(params->surface)->driver_surface, params->pRectCount, params->pRects); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDevicePresentRectanglesKHR(void *args) -{ - struct - { - PTR32 physicalDevice; - VkSurfaceKHR DECLSPEC_ALIGN(8) surface; - PTR32 pRectCount; - PTR32 pRects; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %#x, %#x\n", params->physicalDevice, wine_dbgstr_longlong(params->surface), params->pRectCount, params->pRects); - - params->result = wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDevicePresentRectanglesKHR(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, wine_surface_from_handle(params->surface)->driver_surface, (uint32_t *)UlongToPtr(params->pRectCount), (VkRect2D *)UlongToPtr(params->pRects)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceProperties(void *args) -{ - struct vkGetPhysicalDeviceProperties_params *params = args; - - TRACE("%p, %p\n", params->physicalDevice, params->pProperties); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceProperties(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceProperties(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pProperties; - } *params = args; - VkPhysicalDeviceProperties pProperties_host; - - TRACE("%#x, %#x\n", params->physicalDevice, params->pProperties); - - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceProperties(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, &pProperties_host); - convert_VkPhysicalDeviceProperties_host_to_win32(&pProperties_host, (VkPhysicalDeviceProperties32 *)UlongToPtr(params->pProperties)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceProperties2(void *args) -{ - struct vkGetPhysicalDeviceProperties2_params *params = args; - - TRACE("%p, %p\n", params->physicalDevice, params->pProperties); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceProperties2(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceProperties2(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pProperties; - } *params = args; - VkPhysicalDeviceProperties2 pProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x\n", params->physicalDevice, params->pProperties); - - init_conversion_context(&ctx); - convert_VkPhysicalDeviceProperties2_win32_to_host(&ctx, (VkPhysicalDeviceProperties232 *)UlongToPtr(params->pProperties), &pProperties_host); - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceProperties2(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, &pProperties_host); - convert_VkPhysicalDeviceProperties2_host_to_win32(&pProperties_host, (VkPhysicalDeviceProperties232 *)UlongToPtr(params->pProperties)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceProperties2KHR(void *args) -{ - struct vkGetPhysicalDeviceProperties2KHR_params *params = args; - - TRACE("%p, %p\n", params->physicalDevice, params->pProperties); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceProperties2KHR(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceProperties2KHR(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pProperties; - } *params = args; - VkPhysicalDeviceProperties2 pProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x\n", params->physicalDevice, params->pProperties); - - init_conversion_context(&ctx); - convert_VkPhysicalDeviceProperties2_win32_to_host(&ctx, (VkPhysicalDeviceProperties232 *)UlongToPtr(params->pProperties), &pProperties_host); - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceProperties2KHR(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, &pProperties_host); - convert_VkPhysicalDeviceProperties2_host_to_win32(&pProperties_host, (VkPhysicalDeviceProperties232 *)UlongToPtr(params->pProperties)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR(void *args) -{ - struct vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pPerformanceQueryCreateInfo, params->pNumPasses); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pPerformanceQueryCreateInfo, params->pNumPasses); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pPerformanceQueryCreateInfo; - PTR32 pNumPasses; - } *params = args; - VkQueryPoolPerformanceCreateInfoKHR pPerformanceQueryCreateInfo_host; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pPerformanceQueryCreateInfo, params->pNumPasses); - - convert_VkQueryPoolPerformanceCreateInfoKHR_win32_to_host((const VkQueryPoolPerformanceCreateInfoKHR32 *)UlongToPtr(params->pPerformanceQueryCreateInfo), &pPerformanceQueryCreateInfo_host); - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, &pPerformanceQueryCreateInfo_host, (uint32_t *)UlongToPtr(params->pNumPasses)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceQueueFamilyProperties(void *args) -{ - struct vkGetPhysicalDeviceQueueFamilyProperties_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pQueueFamilyPropertyCount, params->pQueueFamilyProperties); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceQueueFamilyProperties(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pQueueFamilyPropertyCount, params->pQueueFamilyProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceQueueFamilyProperties(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pQueueFamilyPropertyCount; - PTR32 pQueueFamilyProperties; - } *params = args; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pQueueFamilyPropertyCount, params->pQueueFamilyProperties); - - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceQueueFamilyProperties(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, (uint32_t *)UlongToPtr(params->pQueueFamilyPropertyCount), (VkQueueFamilyProperties *)UlongToPtr(params->pQueueFamilyProperties)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceQueueFamilyProperties2(void *args) -{ - struct vkGetPhysicalDeviceQueueFamilyProperties2_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pQueueFamilyPropertyCount, params->pQueueFamilyProperties); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceQueueFamilyProperties2(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pQueueFamilyPropertyCount, params->pQueueFamilyProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceQueueFamilyProperties2(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pQueueFamilyPropertyCount; - PTR32 pQueueFamilyProperties; - } *params = args; - VkQueueFamilyProperties2 *pQueueFamilyProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pQueueFamilyPropertyCount, params->pQueueFamilyProperties); - - init_conversion_context(&ctx); - pQueueFamilyProperties_host = convert_VkQueueFamilyProperties2_array_win32_to_host(&ctx, (VkQueueFamilyProperties232 *)UlongToPtr(params->pQueueFamilyProperties), *(uint32_t *)UlongToPtr(params->pQueueFamilyPropertyCount)); - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceQueueFamilyProperties2(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, (uint32_t *)UlongToPtr(params->pQueueFamilyPropertyCount), pQueueFamilyProperties_host); - convert_VkQueueFamilyProperties2_array_host_to_win32(pQueueFamilyProperties_host, (VkQueueFamilyProperties232 *)UlongToPtr(params->pQueueFamilyProperties), *(uint32_t *)UlongToPtr(params->pQueueFamilyPropertyCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceQueueFamilyProperties2KHR(void *args) -{ - struct vkGetPhysicalDeviceQueueFamilyProperties2KHR_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pQueueFamilyPropertyCount, params->pQueueFamilyProperties); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceQueueFamilyProperties2KHR(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pQueueFamilyPropertyCount, params->pQueueFamilyProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceQueueFamilyProperties2KHR(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pQueueFamilyPropertyCount; - PTR32 pQueueFamilyProperties; - } *params = args; - VkQueueFamilyProperties2 *pQueueFamilyProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pQueueFamilyPropertyCount, params->pQueueFamilyProperties); - - init_conversion_context(&ctx); - pQueueFamilyProperties_host = convert_VkQueueFamilyProperties2_array_win32_to_host(&ctx, (VkQueueFamilyProperties232 *)UlongToPtr(params->pQueueFamilyProperties), *(uint32_t *)UlongToPtr(params->pQueueFamilyPropertyCount)); - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceQueueFamilyProperties2KHR(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, (uint32_t *)UlongToPtr(params->pQueueFamilyPropertyCount), pQueueFamilyProperties_host); - convert_VkQueueFamilyProperties2_array_host_to_win32(pQueueFamilyProperties_host, (VkQueueFamilyProperties232 *)UlongToPtr(params->pQueueFamilyProperties), *(uint32_t *)UlongToPtr(params->pQueueFamilyPropertyCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceSparseImageFormatProperties(void *args) -{ - struct vkGetPhysicalDeviceSparseImageFormatProperties_params *params = args; - - TRACE("%p, %#x, %#x, %#x, %#x, %#x, %p, %p\n", params->physicalDevice, params->format, params->type, params->samples, params->usage, params->tiling, params->pPropertyCount, params->pProperties); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceSparseImageFormatProperties(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->format, params->type, params->samples, params->usage, params->tiling, params->pPropertyCount, params->pProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceSparseImageFormatProperties(void *args) -{ - struct - { - PTR32 physicalDevice; - VkFormat format; - VkImageType type; - VkSampleCountFlagBits samples; - VkImageUsageFlags usage; - VkImageTiling tiling; - PTR32 pPropertyCount; - PTR32 pProperties; - } *params = args; - - TRACE("%#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x\n", params->physicalDevice, params->format, params->type, params->samples, params->usage, params->tiling, params->pPropertyCount, params->pProperties); - - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceSparseImageFormatProperties(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, params->format, params->type, params->samples, params->usage, params->tiling, (uint32_t *)UlongToPtr(params->pPropertyCount), (VkSparseImageFormatProperties *)UlongToPtr(params->pProperties)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceSparseImageFormatProperties2(void *args) -{ - struct vkGetPhysicalDeviceSparseImageFormatProperties2_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->physicalDevice, params->pFormatInfo, params->pPropertyCount, params->pProperties); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceSparseImageFormatProperties2(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pFormatInfo, params->pPropertyCount, params->pProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceSparseImageFormatProperties2(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pFormatInfo; - PTR32 pPropertyCount; - PTR32 pProperties; - } *params = args; - VkPhysicalDeviceSparseImageFormatInfo2 pFormatInfo_host; - VkSparseImageFormatProperties2 *pProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->physicalDevice, params->pFormatInfo, params->pPropertyCount, params->pProperties); - - init_conversion_context(&ctx); - convert_VkPhysicalDeviceSparseImageFormatInfo2_win32_to_host((const VkPhysicalDeviceSparseImageFormatInfo232 *)UlongToPtr(params->pFormatInfo), &pFormatInfo_host); - pProperties_host = convert_VkSparseImageFormatProperties2_array_win32_to_host(&ctx, (VkSparseImageFormatProperties232 *)UlongToPtr(params->pProperties), *(uint32_t *)UlongToPtr(params->pPropertyCount)); - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceSparseImageFormatProperties2(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, &pFormatInfo_host, (uint32_t *)UlongToPtr(params->pPropertyCount), pProperties_host); - convert_VkSparseImageFormatProperties2_array_host_to_win32(pProperties_host, (VkSparseImageFormatProperties232 *)UlongToPtr(params->pProperties), *(uint32_t *)UlongToPtr(params->pPropertyCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceSparseImageFormatProperties2KHR(void *args) -{ - struct vkGetPhysicalDeviceSparseImageFormatProperties2KHR_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->physicalDevice, params->pFormatInfo, params->pPropertyCount, params->pProperties); - - wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceSparseImageFormatProperties2KHR(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pFormatInfo, params->pPropertyCount, params->pProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceSparseImageFormatProperties2KHR(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pFormatInfo; - PTR32 pPropertyCount; - PTR32 pProperties; - } *params = args; - VkPhysicalDeviceSparseImageFormatInfo2 pFormatInfo_host; - VkSparseImageFormatProperties2 *pProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->physicalDevice, params->pFormatInfo, params->pPropertyCount, params->pProperties); - - init_conversion_context(&ctx); - convert_VkPhysicalDeviceSparseImageFormatInfo2_win32_to_host((const VkPhysicalDeviceSparseImageFormatInfo232 *)UlongToPtr(params->pFormatInfo), &pFormatInfo_host); - pProperties_host = convert_VkSparseImageFormatProperties2_array_win32_to_host(&ctx, (VkSparseImageFormatProperties232 *)UlongToPtr(params->pProperties), *(uint32_t *)UlongToPtr(params->pPropertyCount)); - wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceSparseImageFormatProperties2KHR(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, &pFormatInfo_host, (uint32_t *)UlongToPtr(params->pPropertyCount), pProperties_host); - convert_VkSparseImageFormatProperties2_array_host_to_win32(pProperties_host, (VkSparseImageFormatProperties232 *)UlongToPtr(params->pProperties), *(uint32_t *)UlongToPtr(params->pPropertyCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV(void *args) -{ - struct vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pCombinationCount, params->pCombinations); - - params->result = wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pCombinationCount, params->pCombinations); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pCombinationCount; - PTR32 pCombinations; - VkResult result; - } *params = args; - VkFramebufferMixedSamplesCombinationNV *pCombinations_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pCombinationCount, params->pCombinations); - - init_conversion_context(&ctx); - pCombinations_host = convert_VkFramebufferMixedSamplesCombinationNV_array_win32_to_host(&ctx, (VkFramebufferMixedSamplesCombinationNV32 *)UlongToPtr(params->pCombinations), *(uint32_t *)UlongToPtr(params->pCombinationCount)); - params->result = wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, (uint32_t *)UlongToPtr(params->pCombinationCount), pCombinations_host); - convert_VkFramebufferMixedSamplesCombinationNV_array_host_to_win32(pCombinations_host, (VkFramebufferMixedSamplesCombinationNV32 *)UlongToPtr(params->pCombinations), *(uint32_t *)UlongToPtr(params->pCombinationCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceSurfaceCapabilities2KHR(void *args) -{ - struct vkGetPhysicalDeviceSurfaceCapabilities2KHR_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pSurfaceInfo, params->pSurfaceCapabilities); - - params->result = wine_vkGetPhysicalDeviceSurfaceCapabilities2KHR(params->physicalDevice, params->pSurfaceInfo, params->pSurfaceCapabilities); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceSurfaceCapabilities2KHR(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pSurfaceInfo; - PTR32 pSurfaceCapabilities; - VkResult result; - } *params = args; - VkPhysicalDeviceSurfaceInfo2KHR pSurfaceInfo_host; - VkSurfaceCapabilities2KHR pSurfaceCapabilities_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pSurfaceInfo, params->pSurfaceCapabilities); - - init_conversion_context(&ctx); - convert_VkPhysicalDeviceSurfaceInfo2KHR_win32_to_unwrapped_host(&ctx, (const VkPhysicalDeviceSurfaceInfo2KHR32 *)UlongToPtr(params->pSurfaceInfo), &pSurfaceInfo_host); - convert_VkSurfaceCapabilities2KHR_win32_to_host(&ctx, (VkSurfaceCapabilities2KHR32 *)UlongToPtr(params->pSurfaceCapabilities), &pSurfaceCapabilities_host); - params->result = wine_vkGetPhysicalDeviceSurfaceCapabilities2KHR((VkPhysicalDevice)UlongToPtr(params->physicalDevice), &pSurfaceInfo_host, &pSurfaceCapabilities_host); - convert_VkSurfaceCapabilities2KHR_host_to_win32(&pSurfaceCapabilities_host, (VkSurfaceCapabilities2KHR32 *)UlongToPtr(params->pSurfaceCapabilities)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(void *args) -{ - struct vkGetPhysicalDeviceSurfaceCapabilitiesKHR_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->physicalDevice, wine_dbgstr_longlong(params->surface), params->pSurfaceCapabilities); - - params->result = wine_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(params->physicalDevice, params->surface, params->pSurfaceCapabilities); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(void *args) -{ - struct - { - PTR32 physicalDevice; - VkSurfaceKHR DECLSPEC_ALIGN(8) surface; - PTR32 pSurfaceCapabilities; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->physicalDevice, wine_dbgstr_longlong(params->surface), params->pSurfaceCapabilities); - - params->result = wine_vkGetPhysicalDeviceSurfaceCapabilitiesKHR((VkPhysicalDevice)UlongToPtr(params->physicalDevice), params->surface, (VkSurfaceCapabilitiesKHR *)UlongToPtr(params->pSurfaceCapabilities)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceSurfaceFormats2KHR(void *args) -{ - struct vkGetPhysicalDeviceSurfaceFormats2KHR_params *params = args; - VkPhysicalDeviceSurfaceInfo2KHR pSurfaceInfo_host; - - TRACE("%p, %p, %p, %p\n", params->physicalDevice, params->pSurfaceInfo, params->pSurfaceFormatCount, params->pSurfaceFormats); - - convert_VkPhysicalDeviceSurfaceInfo2KHR_win64_to_host(params->pSurfaceInfo, &pSurfaceInfo_host); - params->result = wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceSurfaceFormats2KHR(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, &pSurfaceInfo_host, params->pSurfaceFormatCount, params->pSurfaceFormats); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceSurfaceFormats2KHR(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pSurfaceInfo; - PTR32 pSurfaceFormatCount; - PTR32 pSurfaceFormats; - VkResult result; - } *params = args; - VkPhysicalDeviceSurfaceInfo2KHR pSurfaceInfo_host; - VkSurfaceFormat2KHR *pSurfaceFormats_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->physicalDevice, params->pSurfaceInfo, params->pSurfaceFormatCount, params->pSurfaceFormats); - - init_conversion_context(&ctx); - convert_VkPhysicalDeviceSurfaceInfo2KHR_win32_to_host(&ctx, (const VkPhysicalDeviceSurfaceInfo2KHR32 *)UlongToPtr(params->pSurfaceInfo), &pSurfaceInfo_host); - pSurfaceFormats_host = convert_VkSurfaceFormat2KHR_array_win32_to_host(&ctx, (VkSurfaceFormat2KHR32 *)UlongToPtr(params->pSurfaceFormats), *(uint32_t *)UlongToPtr(params->pSurfaceFormatCount)); - params->result = wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceSurfaceFormats2KHR(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, &pSurfaceInfo_host, (uint32_t *)UlongToPtr(params->pSurfaceFormatCount), pSurfaceFormats_host); - convert_VkSurfaceFormat2KHR_array_host_to_win32(pSurfaceFormats_host, (VkSurfaceFormat2KHR32 *)UlongToPtr(params->pSurfaceFormats), *(uint32_t *)UlongToPtr(params->pSurfaceFormatCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceSurfaceFormatsKHR(void *args) -{ - struct vkGetPhysicalDeviceSurfaceFormatsKHR_params *params = args; - - TRACE("%p, 0x%s, %p, %p\n", params->physicalDevice, wine_dbgstr_longlong(params->surface), params->pSurfaceFormatCount, params->pSurfaceFormats); - - params->result = wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceSurfaceFormatsKHR(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->surface ? wine_surface_from_handle(params->surface)->driver_surface : 0, params->pSurfaceFormatCount, params->pSurfaceFormats); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceSurfaceFormatsKHR(void *args) -{ - struct - { - PTR32 physicalDevice; - VkSurfaceKHR DECLSPEC_ALIGN(8) surface; - PTR32 pSurfaceFormatCount; - PTR32 pSurfaceFormats; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %#x, %#x\n", params->physicalDevice, wine_dbgstr_longlong(params->surface), params->pSurfaceFormatCount, params->pSurfaceFormats); - - params->result = wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceSurfaceFormatsKHR(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, params->surface ? wine_surface_from_handle(params->surface)->driver_surface : 0, (uint32_t *)UlongToPtr(params->pSurfaceFormatCount), (VkSurfaceFormatKHR *)UlongToPtr(params->pSurfaceFormats)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceSurfacePresentModesKHR(void *args) -{ - struct vkGetPhysicalDeviceSurfacePresentModesKHR_params *params = args; - - TRACE("%p, 0x%s, %p, %p\n", params->physicalDevice, wine_dbgstr_longlong(params->surface), params->pPresentModeCount, params->pPresentModes); - - params->result = wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceSurfacePresentModesKHR(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->surface ? wine_surface_from_handle(params->surface)->driver_surface : 0, params->pPresentModeCount, params->pPresentModes); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceSurfacePresentModesKHR(void *args) -{ - struct - { - PTR32 physicalDevice; - VkSurfaceKHR DECLSPEC_ALIGN(8) surface; - PTR32 pPresentModeCount; - PTR32 pPresentModes; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %#x, %#x\n", params->physicalDevice, wine_dbgstr_longlong(params->surface), params->pPresentModeCount, params->pPresentModes); - - params->result = wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceSurfacePresentModesKHR(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, params->surface ? wine_surface_from_handle(params->surface)->driver_surface : 0, (uint32_t *)UlongToPtr(params->pPresentModeCount), (VkPresentModeKHR *)UlongToPtr(params->pPresentModes)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceSurfaceSupportKHR(void *args) -{ - struct vkGetPhysicalDeviceSurfaceSupportKHR_params *params = args; - - TRACE("%p, %u, 0x%s, %p\n", params->physicalDevice, params->queueFamilyIndex, wine_dbgstr_longlong(params->surface), params->pSupported); - - params->result = wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceSurfaceSupportKHR(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->queueFamilyIndex, wine_surface_from_handle(params->surface)->driver_surface, params->pSupported); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceSurfaceSupportKHR(void *args) -{ - struct - { - PTR32 physicalDevice; - uint32_t queueFamilyIndex; - VkSurfaceKHR DECLSPEC_ALIGN(8) surface; - PTR32 pSupported; - VkResult result; - } *params = args; - - TRACE("%#x, %u, 0x%s, %#x\n", params->physicalDevice, params->queueFamilyIndex, wine_dbgstr_longlong(params->surface), params->pSupported); - - params->result = wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceSurfaceSupportKHR(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, params->queueFamilyIndex, wine_surface_from_handle(params->surface)->driver_surface, (VkBool32 *)UlongToPtr(params->pSupported)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceToolProperties(void *args) -{ - struct vkGetPhysicalDeviceToolProperties_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pToolCount, params->pToolProperties); - - params->result = wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceToolProperties(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pToolCount, params->pToolProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceToolProperties(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pToolCount; - PTR32 pToolProperties; - VkResult result; - } *params = args; - VkPhysicalDeviceToolProperties *pToolProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pToolCount, params->pToolProperties); - - init_conversion_context(&ctx); - pToolProperties_host = convert_VkPhysicalDeviceToolProperties_array_win32_to_host(&ctx, (VkPhysicalDeviceToolProperties32 *)UlongToPtr(params->pToolProperties), *(uint32_t *)UlongToPtr(params->pToolCount)); - params->result = wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceToolProperties(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, (uint32_t *)UlongToPtr(params->pToolCount), pToolProperties_host); - convert_VkPhysicalDeviceToolProperties_array_host_to_win32(pToolProperties_host, (VkPhysicalDeviceToolProperties32 *)UlongToPtr(params->pToolProperties), *(uint32_t *)UlongToPtr(params->pToolCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceToolPropertiesEXT(void *args) -{ - struct vkGetPhysicalDeviceToolPropertiesEXT_params *params = args; - - TRACE("%p, %p, %p\n", params->physicalDevice, params->pToolCount, params->pToolProperties); - - params->result = wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceToolPropertiesEXT(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->pToolCount, params->pToolProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceToolPropertiesEXT(void *args) -{ - struct - { - PTR32 physicalDevice; - PTR32 pToolCount; - PTR32 pToolProperties; - VkResult result; - } *params = args; - VkPhysicalDeviceToolProperties *pToolProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->physicalDevice, params->pToolCount, params->pToolProperties); - - init_conversion_context(&ctx); - pToolProperties_host = convert_VkPhysicalDeviceToolProperties_array_win32_to_host(&ctx, (VkPhysicalDeviceToolProperties32 *)UlongToPtr(params->pToolProperties), *(uint32_t *)UlongToPtr(params->pToolCount)); - params->result = wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceToolPropertiesEXT(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, (uint32_t *)UlongToPtr(params->pToolCount), pToolProperties_host); - convert_VkPhysicalDeviceToolProperties_array_host_to_win32(pToolProperties_host, (VkPhysicalDeviceToolProperties32 *)UlongToPtr(params->pToolProperties), *(uint32_t *)UlongToPtr(params->pToolCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPhysicalDeviceWin32PresentationSupportKHR(void *args) -{ - struct vkGetPhysicalDeviceWin32PresentationSupportKHR_params *params = args; - - TRACE("%p, %u\n", params->physicalDevice, params->queueFamilyIndex); - - params->result = wine_phys_dev_from_handle(params->physicalDevice)->instance->funcs.p_vkGetPhysicalDeviceWin32PresentationSupportKHR(wine_phys_dev_from_handle(params->physicalDevice)->phys_dev, params->queueFamilyIndex); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPhysicalDeviceWin32PresentationSupportKHR(void *args) -{ - struct - { - PTR32 physicalDevice; - uint32_t queueFamilyIndex; - VkBool32 result; - } *params = args; - - TRACE("%#x, %u\n", params->physicalDevice, params->queueFamilyIndex); - - params->result = wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->instance->funcs.p_vkGetPhysicalDeviceWin32PresentationSupportKHR(wine_phys_dev_from_handle((VkPhysicalDevice)UlongToPtr(params->physicalDevice))->phys_dev, params->queueFamilyIndex); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPipelineCacheData(void *args) -{ - struct vkGetPipelineCacheData_params *params = args; - - TRACE("%p, 0x%s, %p, %p\n", params->device, wine_dbgstr_longlong(params->pipelineCache), params->pDataSize, params->pData); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetPipelineCacheData(wine_device_from_handle(params->device)->device, params->pipelineCache, params->pDataSize, params->pData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPipelineCacheData(void *args) -{ - struct - { - PTR32 device; - VkPipelineCache DECLSPEC_ALIGN(8) pipelineCache; - PTR32 pDataSize; - PTR32 pData; - VkResult result; - } *params = args; - size_t pDataSize_host; - - TRACE("%#x, 0x%s, %#x, %#x\n", params->device, wine_dbgstr_longlong(params->pipelineCache), params->pDataSize, params->pData); - - pDataSize_host = *(PTR32 *)UlongToPtr(params->pDataSize); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetPipelineCacheData(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->pipelineCache, &pDataSize_host, (void *)UlongToPtr(params->pData)); - *(PTR32 *)UlongToPtr(params->pDataSize) = pDataSize_host; - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPipelineExecutableInternalRepresentationsKHR(void *args) -{ - struct vkGetPipelineExecutableInternalRepresentationsKHR_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pExecutableInfo, params->pInternalRepresentationCount, params->pInternalRepresentations); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetPipelineExecutableInternalRepresentationsKHR(wine_device_from_handle(params->device)->device, params->pExecutableInfo, params->pInternalRepresentationCount, params->pInternalRepresentations); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPipelineExecutableInternalRepresentationsKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pExecutableInfo; - PTR32 pInternalRepresentationCount; - PTR32 pInternalRepresentations; - VkResult result; - } *params = args; - VkPipelineExecutableInfoKHR pExecutableInfo_host; - VkPipelineExecutableInternalRepresentationKHR *pInternalRepresentations_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pExecutableInfo, params->pInternalRepresentationCount, params->pInternalRepresentations); - - init_conversion_context(&ctx); - convert_VkPipelineExecutableInfoKHR_win32_to_host((const VkPipelineExecutableInfoKHR32 *)UlongToPtr(params->pExecutableInfo), &pExecutableInfo_host); - pInternalRepresentations_host = convert_VkPipelineExecutableInternalRepresentationKHR_array_win32_to_host(&ctx, (VkPipelineExecutableInternalRepresentationKHR32 *)UlongToPtr(params->pInternalRepresentations), *(uint32_t *)UlongToPtr(params->pInternalRepresentationCount)); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetPipelineExecutableInternalRepresentationsKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pExecutableInfo_host, (uint32_t *)UlongToPtr(params->pInternalRepresentationCount), pInternalRepresentations_host); - convert_VkPipelineExecutableInternalRepresentationKHR_array_host_to_win32(pInternalRepresentations_host, (VkPipelineExecutableInternalRepresentationKHR32 *)UlongToPtr(params->pInternalRepresentations), *(uint32_t *)UlongToPtr(params->pInternalRepresentationCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPipelineExecutablePropertiesKHR(void *args) -{ - struct vkGetPipelineExecutablePropertiesKHR_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pPipelineInfo, params->pExecutableCount, params->pProperties); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetPipelineExecutablePropertiesKHR(wine_device_from_handle(params->device)->device, params->pPipelineInfo, params->pExecutableCount, params->pProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPipelineExecutablePropertiesKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pPipelineInfo; - PTR32 pExecutableCount; - PTR32 pProperties; - VkResult result; - } *params = args; - VkPipelineInfoKHR pPipelineInfo_host; - VkPipelineExecutablePropertiesKHR *pProperties_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pPipelineInfo, params->pExecutableCount, params->pProperties); - - init_conversion_context(&ctx); - convert_VkPipelineInfoKHR_win32_to_host((const VkPipelineInfoKHR32 *)UlongToPtr(params->pPipelineInfo), &pPipelineInfo_host); - pProperties_host = convert_VkPipelineExecutablePropertiesKHR_array_win32_to_host(&ctx, (VkPipelineExecutablePropertiesKHR32 *)UlongToPtr(params->pProperties), *(uint32_t *)UlongToPtr(params->pExecutableCount)); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetPipelineExecutablePropertiesKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pPipelineInfo_host, (uint32_t *)UlongToPtr(params->pExecutableCount), pProperties_host); - convert_VkPipelineExecutablePropertiesKHR_array_host_to_win32(pProperties_host, (VkPipelineExecutablePropertiesKHR32 *)UlongToPtr(params->pProperties), *(uint32_t *)UlongToPtr(params->pExecutableCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPipelineExecutableStatisticsKHR(void *args) -{ - struct vkGetPipelineExecutableStatisticsKHR_params *params = args; - - TRACE("%p, %p, %p, %p\n", params->device, params->pExecutableInfo, params->pStatisticCount, params->pStatistics); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetPipelineExecutableStatisticsKHR(wine_device_from_handle(params->device)->device, params->pExecutableInfo, params->pStatisticCount, params->pStatistics); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPipelineExecutableStatisticsKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pExecutableInfo; - PTR32 pStatisticCount; - PTR32 pStatistics; - VkResult result; - } *params = args; - VkPipelineExecutableInfoKHR pExecutableInfo_host; - VkPipelineExecutableStatisticKHR *pStatistics_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->device, params->pExecutableInfo, params->pStatisticCount, params->pStatistics); - - init_conversion_context(&ctx); - convert_VkPipelineExecutableInfoKHR_win32_to_host((const VkPipelineExecutableInfoKHR32 *)UlongToPtr(params->pExecutableInfo), &pExecutableInfo_host); - pStatistics_host = convert_VkPipelineExecutableStatisticKHR_array_win32_to_host(&ctx, (VkPipelineExecutableStatisticKHR32 *)UlongToPtr(params->pStatistics), *(uint32_t *)UlongToPtr(params->pStatisticCount)); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetPipelineExecutableStatisticsKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pExecutableInfo_host, (uint32_t *)UlongToPtr(params->pStatisticCount), pStatistics_host); - convert_VkPipelineExecutableStatisticKHR_array_host_to_win32(pStatistics_host, (VkPipelineExecutableStatisticKHR32 *)UlongToPtr(params->pStatistics), *(uint32_t *)UlongToPtr(params->pStatisticCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPipelinePropertiesEXT(void *args) -{ - struct vkGetPipelinePropertiesEXT_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pPipelineInfo, params->pPipelineProperties); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetPipelinePropertiesEXT(wine_device_from_handle(params->device)->device, params->pPipelineInfo, params->pPipelineProperties); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPipelinePropertiesEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pPipelineInfo; - PTR32 pPipelineProperties; - VkResult result; - } *params = args; - VkPipelineInfoEXT pPipelineInfo_host; - - TRACE("%#x, %#x, %#x\n", params->device, params->pPipelineInfo, params->pPipelineProperties); - - convert_VkPipelineInfoEXT_win32_to_host((const VkPipelineInfoEXT32 *)UlongToPtr(params->pPipelineInfo), &pPipelineInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetPipelinePropertiesEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pPipelineInfo_host, (VkBaseOutStructure *)UlongToPtr(params->pPipelineProperties)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPrivateData(void *args) -{ - struct vkGetPrivateData_params *params = args; - - TRACE("%p, %#x, 0x%s, 0x%s, %p\n", params->device, params->objectType, wine_dbgstr_longlong(params->objectHandle), wine_dbgstr_longlong(params->privateDataSlot), params->pData); - - wine_device_from_handle(params->device)->funcs.p_vkGetPrivateData(wine_device_from_handle(params->device)->device, params->objectType, wine_vk_unwrap_handle(params->objectType, params->objectHandle), params->privateDataSlot, params->pData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPrivateData(void *args) -{ - struct - { - PTR32 device; - VkObjectType objectType; - uint64_t DECLSPEC_ALIGN(8) objectHandle; - VkPrivateDataSlot DECLSPEC_ALIGN(8) privateDataSlot; - PTR32 pData; - } *params = args; - - TRACE("%#x, %#x, 0x%s, 0x%s, %#x\n", params->device, params->objectType, wine_dbgstr_longlong(params->objectHandle), wine_dbgstr_longlong(params->privateDataSlot), params->pData); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetPrivateData(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->objectType, wine_vk_unwrap_handle(params->objectType, params->objectHandle), params->privateDataSlot, (uint64_t *)UlongToPtr(params->pData)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetPrivateDataEXT(void *args) -{ - struct vkGetPrivateDataEXT_params *params = args; - - TRACE("%p, %#x, 0x%s, 0x%s, %p\n", params->device, params->objectType, wine_dbgstr_longlong(params->objectHandle), wine_dbgstr_longlong(params->privateDataSlot), params->pData); - - wine_device_from_handle(params->device)->funcs.p_vkGetPrivateDataEXT(wine_device_from_handle(params->device)->device, params->objectType, wine_vk_unwrap_handle(params->objectType, params->objectHandle), params->privateDataSlot, params->pData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetPrivateDataEXT(void *args) -{ - struct - { - PTR32 device; - VkObjectType objectType; - uint64_t DECLSPEC_ALIGN(8) objectHandle; - VkPrivateDataSlot DECLSPEC_ALIGN(8) privateDataSlot; - PTR32 pData; - } *params = args; - - TRACE("%#x, %#x, 0x%s, 0x%s, %#x\n", params->device, params->objectType, wine_dbgstr_longlong(params->objectHandle), wine_dbgstr_longlong(params->privateDataSlot), params->pData); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetPrivateDataEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->objectType, wine_vk_unwrap_handle(params->objectType, params->objectHandle), params->privateDataSlot, (uint64_t *)UlongToPtr(params->pData)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetQueryPoolResults(void *args) -{ - struct vkGetQueryPoolResults_params *params = args; - - TRACE("%p, 0x%s, %u, %u, 0x%s, %p, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->queryPool), params->firstQuery, params->queryCount, wine_dbgstr_longlong(params->dataSize), params->pData, wine_dbgstr_longlong(params->stride), params->flags); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetQueryPoolResults(wine_device_from_handle(params->device)->device, params->queryPool, params->firstQuery, params->queryCount, params->dataSize, params->pData, params->stride, params->flags); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetQueryPoolResults(void *args) -{ - struct - { - PTR32 device; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t firstQuery; - uint32_t queryCount; - PTR32 dataSize; - PTR32 pData; - VkDeviceSize DECLSPEC_ALIGN(8) stride; - VkQueryResultFlags flags; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %u, %u, 0x%s, %#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->queryPool), params->firstQuery, params->queryCount, wine_dbgstr_longlong(params->dataSize), params->pData, wine_dbgstr_longlong(params->stride), params->flags); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetQueryPoolResults(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->queryPool, params->firstQuery, params->queryCount, params->dataSize, (void *)UlongToPtr(params->pData), params->stride, params->flags); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetQueueCheckpointData2NV(void *args) -{ - struct vkGetQueueCheckpointData2NV_params *params = args; - - TRACE("%p, %p, %p\n", params->queue, params->pCheckpointDataCount, params->pCheckpointData); - - wine_queue_from_handle(params->queue)->device->funcs.p_vkGetQueueCheckpointData2NV(wine_queue_from_handle(params->queue)->queue, params->pCheckpointDataCount, params->pCheckpointData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetQueueCheckpointData2NV(void *args) -{ - struct - { - PTR32 queue; - PTR32 pCheckpointDataCount; - PTR32 pCheckpointData; - } *params = args; - VkCheckpointData2NV *pCheckpointData_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->queue, params->pCheckpointDataCount, params->pCheckpointData); - - init_conversion_context(&ctx); - pCheckpointData_host = convert_VkCheckpointData2NV_array_win32_to_host(&ctx, (VkCheckpointData2NV32 *)UlongToPtr(params->pCheckpointData), *(uint32_t *)UlongToPtr(params->pCheckpointDataCount)); - wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->device->funcs.p_vkGetQueueCheckpointData2NV(wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->queue, (uint32_t *)UlongToPtr(params->pCheckpointDataCount), pCheckpointData_host); - convert_VkCheckpointData2NV_array_host_to_win32(pCheckpointData_host, (VkCheckpointData2NV32 *)UlongToPtr(params->pCheckpointData), *(uint32_t *)UlongToPtr(params->pCheckpointDataCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetQueueCheckpointDataNV(void *args) -{ - struct vkGetQueueCheckpointDataNV_params *params = args; - - TRACE("%p, %p, %p\n", params->queue, params->pCheckpointDataCount, params->pCheckpointData); - - wine_queue_from_handle(params->queue)->device->funcs.p_vkGetQueueCheckpointDataNV(wine_queue_from_handle(params->queue)->queue, params->pCheckpointDataCount, params->pCheckpointData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetQueueCheckpointDataNV(void *args) -{ - struct - { - PTR32 queue; - PTR32 pCheckpointDataCount; - PTR32 pCheckpointData; - } *params = args; - VkCheckpointDataNV *pCheckpointData_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->queue, params->pCheckpointDataCount, params->pCheckpointData); - - init_conversion_context(&ctx); - pCheckpointData_host = convert_VkCheckpointDataNV_array_win32_to_host(&ctx, (VkCheckpointDataNV32 *)UlongToPtr(params->pCheckpointData), *(uint32_t *)UlongToPtr(params->pCheckpointDataCount)); - wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->device->funcs.p_vkGetQueueCheckpointDataNV(wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->queue, (uint32_t *)UlongToPtr(params->pCheckpointDataCount), pCheckpointData_host); - convert_VkCheckpointDataNV_array_host_to_win32(pCheckpointData_host, (VkCheckpointDataNV32 *)UlongToPtr(params->pCheckpointData), *(uint32_t *)UlongToPtr(params->pCheckpointDataCount)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR(void *args) -{ - struct vkGetRayTracingCaptureReplayShaderGroupHandlesKHR_params *params = args; - - TRACE("%p, 0x%s, %u, %u, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->pipeline), params->firstGroup, params->groupCount, wine_dbgstr_longlong(params->dataSize), params->pData); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR(wine_device_from_handle(params->device)->device, params->pipeline, params->firstGroup, params->groupCount, params->dataSize, params->pData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR(void *args) -{ - struct - { - PTR32 device; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - uint32_t firstGroup; - uint32_t groupCount; - PTR32 dataSize; - PTR32 pData; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %u, %u, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->pipeline), params->firstGroup, params->groupCount, wine_dbgstr_longlong(params->dataSize), params->pData); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->pipeline, params->firstGroup, params->groupCount, params->dataSize, (void *)UlongToPtr(params->pData)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetRayTracingShaderGroupHandlesKHR(void *args) -{ - struct vkGetRayTracingShaderGroupHandlesKHR_params *params = args; - - TRACE("%p, 0x%s, %u, %u, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->pipeline), params->firstGroup, params->groupCount, wine_dbgstr_longlong(params->dataSize), params->pData); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetRayTracingShaderGroupHandlesKHR(wine_device_from_handle(params->device)->device, params->pipeline, params->firstGroup, params->groupCount, params->dataSize, params->pData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetRayTracingShaderGroupHandlesKHR(void *args) -{ - struct - { - PTR32 device; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - uint32_t firstGroup; - uint32_t groupCount; - PTR32 dataSize; - PTR32 pData; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %u, %u, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->pipeline), params->firstGroup, params->groupCount, wine_dbgstr_longlong(params->dataSize), params->pData); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetRayTracingShaderGroupHandlesKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->pipeline, params->firstGroup, params->groupCount, params->dataSize, (void *)UlongToPtr(params->pData)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetRayTracingShaderGroupHandlesNV(void *args) -{ - struct vkGetRayTracingShaderGroupHandlesNV_params *params = args; - - TRACE("%p, 0x%s, %u, %u, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->pipeline), params->firstGroup, params->groupCount, wine_dbgstr_longlong(params->dataSize), params->pData); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetRayTracingShaderGroupHandlesNV(wine_device_from_handle(params->device)->device, params->pipeline, params->firstGroup, params->groupCount, params->dataSize, params->pData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetRayTracingShaderGroupHandlesNV(void *args) -{ - struct - { - PTR32 device; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - uint32_t firstGroup; - uint32_t groupCount; - PTR32 dataSize; - PTR32 pData; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %u, %u, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->pipeline), params->firstGroup, params->groupCount, wine_dbgstr_longlong(params->dataSize), params->pData); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetRayTracingShaderGroupHandlesNV(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->pipeline, params->firstGroup, params->groupCount, params->dataSize, (void *)UlongToPtr(params->pData)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetRayTracingShaderGroupStackSizeKHR(void *args) -{ - struct vkGetRayTracingShaderGroupStackSizeKHR_params *params = args; - - TRACE("%p, 0x%s, %u, %#x\n", params->device, wine_dbgstr_longlong(params->pipeline), params->group, params->groupShader); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetRayTracingShaderGroupStackSizeKHR(wine_device_from_handle(params->device)->device, params->pipeline, params->group, params->groupShader); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetRayTracingShaderGroupStackSizeKHR(void *args) -{ - struct - { - PTR32 device; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - uint32_t group; - VkShaderGroupShaderKHR groupShader; - VkDeviceSize result; - } *params = args; - - TRACE("%#x, 0x%s, %u, %#x\n", params->device, wine_dbgstr_longlong(params->pipeline), params->group, params->groupShader); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetRayTracingShaderGroupStackSizeKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->pipeline, params->group, params->groupShader); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetRenderAreaGranularity(void *args) -{ - struct vkGetRenderAreaGranularity_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->renderPass), params->pGranularity); - - wine_device_from_handle(params->device)->funcs.p_vkGetRenderAreaGranularity(wine_device_from_handle(params->device)->device, params->renderPass, params->pGranularity); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetRenderAreaGranularity(void *args) -{ - struct - { - PTR32 device; - VkRenderPass DECLSPEC_ALIGN(8) renderPass; - PTR32 pGranularity; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->renderPass), params->pGranularity); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetRenderAreaGranularity(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->renderPass, (VkExtent2D *)UlongToPtr(params->pGranularity)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetSamplerOpaqueCaptureDescriptorDataEXT(void *args) -{ - struct vkGetSamplerOpaqueCaptureDescriptorDataEXT_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pInfo, params->pData); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetSamplerOpaqueCaptureDescriptorDataEXT(wine_device_from_handle(params->device)->device, params->pInfo, params->pData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetSamplerOpaqueCaptureDescriptorDataEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pInfo; - PTR32 pData; - VkResult result; - } *params = args; - VkSamplerCaptureDescriptorDataInfoEXT pInfo_host; - - TRACE("%#x, %#x, %#x\n", params->device, params->pInfo, params->pData); - - convert_VkSamplerCaptureDescriptorDataInfoEXT_win32_to_host((const VkSamplerCaptureDescriptorDataInfoEXT32 *)UlongToPtr(params->pInfo), &pInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetSamplerOpaqueCaptureDescriptorDataEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInfo_host, (void *)UlongToPtr(params->pData)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetSemaphoreCounterValue(void *args) -{ - struct vkGetSemaphoreCounterValue_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->semaphore), params->pValue); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetSemaphoreCounterValue(wine_device_from_handle(params->device)->device, params->semaphore, params->pValue); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetSemaphoreCounterValue(void *args) -{ - struct - { - PTR32 device; - VkSemaphore DECLSPEC_ALIGN(8) semaphore; - PTR32 pValue; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->semaphore), params->pValue); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetSemaphoreCounterValue(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->semaphore, (uint64_t *)UlongToPtr(params->pValue)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetSemaphoreCounterValueKHR(void *args) -{ - struct vkGetSemaphoreCounterValueKHR_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->semaphore), params->pValue); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetSemaphoreCounterValueKHR(wine_device_from_handle(params->device)->device, params->semaphore, params->pValue); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetSemaphoreCounterValueKHR(void *args) -{ - struct - { - PTR32 device; - VkSemaphore DECLSPEC_ALIGN(8) semaphore; - PTR32 pValue; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->semaphore), params->pValue); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetSemaphoreCounterValueKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->semaphore, (uint64_t *)UlongToPtr(params->pValue)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetShaderInfoAMD(void *args) -{ - struct vkGetShaderInfoAMD_params *params = args; - - TRACE("%p, 0x%s, %#x, %#x, %p, %p\n", params->device, wine_dbgstr_longlong(params->pipeline), params->shaderStage, params->infoType, params->pInfoSize, params->pInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetShaderInfoAMD(wine_device_from_handle(params->device)->device, params->pipeline, params->shaderStage, params->infoType, params->pInfoSize, params->pInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetShaderInfoAMD(void *args) -{ - struct - { - PTR32 device; - VkPipeline DECLSPEC_ALIGN(8) pipeline; - VkShaderStageFlagBits shaderStage; - VkShaderInfoTypeAMD infoType; - PTR32 pInfoSize; - PTR32 pInfo; - VkResult result; - } *params = args; - size_t pInfoSize_host; - - TRACE("%#x, 0x%s, %#x, %#x, %#x, %#x\n", params->device, wine_dbgstr_longlong(params->pipeline), params->shaderStage, params->infoType, params->pInfoSize, params->pInfo); - - pInfoSize_host = *(PTR32 *)UlongToPtr(params->pInfoSize); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetShaderInfoAMD(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->pipeline, params->shaderStage, params->infoType, &pInfoSize_host, (void *)UlongToPtr(params->pInfo)); - *(PTR32 *)UlongToPtr(params->pInfoSize) = pInfoSize_host; - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetShaderModuleCreateInfoIdentifierEXT(void *args) -{ - struct vkGetShaderModuleCreateInfoIdentifierEXT_params *params = args; - - TRACE("%p, %p, %p\n", params->device, params->pCreateInfo, params->pIdentifier); - - wine_device_from_handle(params->device)->funcs.p_vkGetShaderModuleCreateInfoIdentifierEXT(wine_device_from_handle(params->device)->device, params->pCreateInfo, params->pIdentifier); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetShaderModuleCreateInfoIdentifierEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pCreateInfo; - PTR32 pIdentifier; - } *params = args; - VkShaderModuleCreateInfo pCreateInfo_host; - VkShaderModuleIdentifierEXT pIdentifier_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x\n", params->device, params->pCreateInfo, params->pIdentifier); - - init_conversion_context(&ctx); - convert_VkShaderModuleCreateInfo_win32_to_host(&ctx, (const VkShaderModuleCreateInfo32 *)UlongToPtr(params->pCreateInfo), &pCreateInfo_host); - convert_VkShaderModuleIdentifierEXT_win32_to_host((VkShaderModuleIdentifierEXT32 *)UlongToPtr(params->pIdentifier), &pIdentifier_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetShaderModuleCreateInfoIdentifierEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pCreateInfo_host, &pIdentifier_host); - convert_VkShaderModuleIdentifierEXT_host_to_win32(&pIdentifier_host, (VkShaderModuleIdentifierEXT32 *)UlongToPtr(params->pIdentifier)); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetShaderModuleIdentifierEXT(void *args) -{ - struct vkGetShaderModuleIdentifierEXT_params *params = args; - - TRACE("%p, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->shaderModule), params->pIdentifier); - - wine_device_from_handle(params->device)->funcs.p_vkGetShaderModuleIdentifierEXT(wine_device_from_handle(params->device)->device, params->shaderModule, params->pIdentifier); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetShaderModuleIdentifierEXT(void *args) -{ - struct - { - PTR32 device; - VkShaderModule DECLSPEC_ALIGN(8) shaderModule; - PTR32 pIdentifier; - } *params = args; - VkShaderModuleIdentifierEXT pIdentifier_host; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->shaderModule), params->pIdentifier); - - convert_VkShaderModuleIdentifierEXT_win32_to_host((VkShaderModuleIdentifierEXT32 *)UlongToPtr(params->pIdentifier), &pIdentifier_host); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetShaderModuleIdentifierEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->shaderModule, &pIdentifier_host); - convert_VkShaderModuleIdentifierEXT_host_to_win32(&pIdentifier_host, (VkShaderModuleIdentifierEXT32 *)UlongToPtr(params->pIdentifier)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetSwapchainImagesKHR(void *args) -{ - struct vkGetSwapchainImagesKHR_params *params = args; - - TRACE("%p, 0x%s, %p, %p\n", params->device, wine_dbgstr_longlong(params->swapchain), params->pSwapchainImageCount, params->pSwapchainImages); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetSwapchainImagesKHR(wine_device_from_handle(params->device)->device, params->swapchain, params->pSwapchainImageCount, params->pSwapchainImages); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetSwapchainImagesKHR(void *args) -{ - struct - { - PTR32 device; - VkSwapchainKHR DECLSPEC_ALIGN(8) swapchain; - PTR32 pSwapchainImageCount; - PTR32 pSwapchainImages; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %#x, %#x\n", params->device, wine_dbgstr_longlong(params->swapchain), params->pSwapchainImageCount, params->pSwapchainImages); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetSwapchainImagesKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->swapchain, (uint32_t *)UlongToPtr(params->pSwapchainImageCount), (VkImage *)UlongToPtr(params->pSwapchainImages)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkGetValidationCacheDataEXT(void *args) -{ - struct vkGetValidationCacheDataEXT_params *params = args; - - TRACE("%p, 0x%s, %p, %p\n", params->device, wine_dbgstr_longlong(params->validationCache), params->pDataSize, params->pData); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkGetValidationCacheDataEXT(wine_device_from_handle(params->device)->device, params->validationCache, params->pDataSize, params->pData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkGetValidationCacheDataEXT(void *args) -{ - struct - { - PTR32 device; - VkValidationCacheEXT DECLSPEC_ALIGN(8) validationCache; - PTR32 pDataSize; - PTR32 pData; - VkResult result; - } *params = args; - size_t pDataSize_host; - - TRACE("%#x, 0x%s, %#x, %#x\n", params->device, wine_dbgstr_longlong(params->validationCache), params->pDataSize, params->pData); - - pDataSize_host = *(PTR32 *)UlongToPtr(params->pDataSize); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkGetValidationCacheDataEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->validationCache, &pDataSize_host, (void *)UlongToPtr(params->pData)); - *(PTR32 *)UlongToPtr(params->pDataSize) = pDataSize_host; - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkInitializePerformanceApiINTEL(void *args) -{ - struct vkInitializePerformanceApiINTEL_params *params = args; - - TRACE("%p, %p\n", params->device, params->pInitializeInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkInitializePerformanceApiINTEL(wine_device_from_handle(params->device)->device, params->pInitializeInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkInitializePerformanceApiINTEL(void *args) -{ - struct - { - PTR32 device; - PTR32 pInitializeInfo; - VkResult result; - } *params = args; - VkInitializePerformanceApiInfoINTEL pInitializeInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pInitializeInfo); - - convert_VkInitializePerformanceApiInfoINTEL_win32_to_host((const VkInitializePerformanceApiInfoINTEL32 *)UlongToPtr(params->pInitializeInfo), &pInitializeInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkInitializePerformanceApiINTEL(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pInitializeInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkInvalidateMappedMemoryRanges(void *args) -{ - struct vkInvalidateMappedMemoryRanges_params *params = args; - const VkMappedMemoryRange *pMemoryRanges_host; - struct conversion_context ctx; - - TRACE("%p, %u, %p\n", params->device, params->memoryRangeCount, params->pMemoryRanges); - - init_conversion_context(&ctx); - pMemoryRanges_host = convert_VkMappedMemoryRange_array_win64_to_host(&ctx, params->pMemoryRanges, params->memoryRangeCount); - params->result = wine_device_from_handle(params->device)->funcs.p_vkInvalidateMappedMemoryRanges(wine_device_from_handle(params->device)->device, params->memoryRangeCount, pMemoryRanges_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkInvalidateMappedMemoryRanges(void *args) -{ - struct - { - PTR32 device; - uint32_t memoryRangeCount; - PTR32 pMemoryRanges; - VkResult result; - } *params = args; - const VkMappedMemoryRange *pMemoryRanges_host; - struct conversion_context ctx; - - TRACE("%#x, %u, %#x\n", params->device, params->memoryRangeCount, params->pMemoryRanges); - - init_conversion_context(&ctx); - pMemoryRanges_host = convert_VkMappedMemoryRange_array_win32_to_host(&ctx, (const VkMappedMemoryRange32 *)UlongToPtr(params->pMemoryRanges), params->memoryRangeCount); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkInvalidateMappedMemoryRanges(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->memoryRangeCount, pMemoryRanges_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkMapMemory(void *args) -{ - struct vkMapMemory_params *params = args; - - TRACE("%p, 0x%s, 0x%s, 0x%s, %#x, %p\n", params->device, wine_dbgstr_longlong(params->memory), wine_dbgstr_longlong(params->offset), wine_dbgstr_longlong(params->size), params->flags, params->ppData); - - params->result = wine_vkMapMemory(params->device, params->memory, params->offset, params->size, params->flags, params->ppData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkMapMemory(void *args) -{ - struct - { - PTR32 device; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - VkDeviceSize DECLSPEC_ALIGN(8) offset; - VkDeviceSize DECLSPEC_ALIGN(8) size; - VkMemoryMapFlags flags; - PTR32 ppData; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, 0x%s, 0x%s, %#x, %#x\n", params->device, wine_dbgstr_longlong(params->memory), wine_dbgstr_longlong(params->offset), wine_dbgstr_longlong(params->size), params->flags, params->ppData); - - params->result = wine_vkMapMemory((VkDevice)UlongToPtr(params->device), params->memory, params->offset, params->size, params->flags, (void **)UlongToPtr(params->ppData)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkMergePipelineCaches(void *args) -{ - struct vkMergePipelineCaches_params *params = args; - - TRACE("%p, 0x%s, %u, %p\n", params->device, wine_dbgstr_longlong(params->dstCache), params->srcCacheCount, params->pSrcCaches); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkMergePipelineCaches(wine_device_from_handle(params->device)->device, params->dstCache, params->srcCacheCount, params->pSrcCaches); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkMergePipelineCaches(void *args) -{ - struct - { - PTR32 device; - VkPipelineCache DECLSPEC_ALIGN(8) dstCache; - uint32_t srcCacheCount; - PTR32 pSrcCaches; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %u, %#x\n", params->device, wine_dbgstr_longlong(params->dstCache), params->srcCacheCount, params->pSrcCaches); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkMergePipelineCaches(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->dstCache, params->srcCacheCount, (const VkPipelineCache *)UlongToPtr(params->pSrcCaches)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkMergeValidationCachesEXT(void *args) -{ - struct vkMergeValidationCachesEXT_params *params = args; - - TRACE("%p, 0x%s, %u, %p\n", params->device, wine_dbgstr_longlong(params->dstCache), params->srcCacheCount, params->pSrcCaches); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkMergeValidationCachesEXT(wine_device_from_handle(params->device)->device, params->dstCache, params->srcCacheCount, params->pSrcCaches); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkMergeValidationCachesEXT(void *args) -{ - struct - { - PTR32 device; - VkValidationCacheEXT DECLSPEC_ALIGN(8) dstCache; - uint32_t srcCacheCount; - PTR32 pSrcCaches; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %u, %#x\n", params->device, wine_dbgstr_longlong(params->dstCache), params->srcCacheCount, params->pSrcCaches); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkMergeValidationCachesEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->dstCache, params->srcCacheCount, (const VkValidationCacheEXT *)UlongToPtr(params->pSrcCaches)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkQueueBeginDebugUtilsLabelEXT(void *args) -{ - struct vkQueueBeginDebugUtilsLabelEXT_params *params = args; - - TRACE("%p, %p\n", params->queue, params->pLabelInfo); - - wine_queue_from_handle(params->queue)->device->funcs.p_vkQueueBeginDebugUtilsLabelEXT(wine_queue_from_handle(params->queue)->queue, params->pLabelInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkQueueBeginDebugUtilsLabelEXT(void *args) -{ - struct - { - PTR32 queue; - PTR32 pLabelInfo; - } *params = args; - VkDebugUtilsLabelEXT pLabelInfo_host; - - TRACE("%#x, %#x\n", params->queue, params->pLabelInfo); - - convert_VkDebugUtilsLabelEXT_win32_to_host((const VkDebugUtilsLabelEXT32 *)UlongToPtr(params->pLabelInfo), &pLabelInfo_host); - wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->device->funcs.p_vkQueueBeginDebugUtilsLabelEXT(wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->queue, &pLabelInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkQueueBindSparse(void *args) -{ - struct vkQueueBindSparse_params *params = args; - const VkBindSparseInfo *pBindInfo_host; - struct conversion_context ctx; - - TRACE("%p, %u, %p, 0x%s\n", params->queue, params->bindInfoCount, params->pBindInfo, wine_dbgstr_longlong(params->fence)); - - init_conversion_context(&ctx); - pBindInfo_host = convert_VkBindSparseInfo_array_win64_to_host(&ctx, params->pBindInfo, params->bindInfoCount); - params->result = wine_queue_from_handle(params->queue)->device->funcs.p_vkQueueBindSparse(wine_queue_from_handle(params->queue)->queue, params->bindInfoCount, pBindInfo_host, params->fence); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkQueueBindSparse(void *args) -{ - struct - { - PTR32 queue; - uint32_t bindInfoCount; - PTR32 pBindInfo; - VkFence DECLSPEC_ALIGN(8) fence; - VkResult result; - } *params = args; - const VkBindSparseInfo *pBindInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %u, %#x, 0x%s\n", params->queue, params->bindInfoCount, params->pBindInfo, wine_dbgstr_longlong(params->fence)); - - init_conversion_context(&ctx); - pBindInfo_host = convert_VkBindSparseInfo_array_win32_to_host(&ctx, (const VkBindSparseInfo32 *)UlongToPtr(params->pBindInfo), params->bindInfoCount); - params->result = wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->device->funcs.p_vkQueueBindSparse(wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->queue, params->bindInfoCount, pBindInfo_host, params->fence); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkQueueEndDebugUtilsLabelEXT(void *args) -{ - struct vkQueueEndDebugUtilsLabelEXT_params *params = args; - - TRACE("%p\n", params->queue); - - wine_queue_from_handle(params->queue)->device->funcs.p_vkQueueEndDebugUtilsLabelEXT(wine_queue_from_handle(params->queue)->queue); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkQueueEndDebugUtilsLabelEXT(void *args) -{ - struct - { - PTR32 queue; - } *params = args; - - TRACE("%#x\n", params->queue); - - wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->device->funcs.p_vkQueueEndDebugUtilsLabelEXT(wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->queue); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkQueueInsertDebugUtilsLabelEXT(void *args) -{ - struct vkQueueInsertDebugUtilsLabelEXT_params *params = args; - - TRACE("%p, %p\n", params->queue, params->pLabelInfo); - - wine_queue_from_handle(params->queue)->device->funcs.p_vkQueueInsertDebugUtilsLabelEXT(wine_queue_from_handle(params->queue)->queue, params->pLabelInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkQueueInsertDebugUtilsLabelEXT(void *args) -{ - struct - { - PTR32 queue; - PTR32 pLabelInfo; - } *params = args; - VkDebugUtilsLabelEXT pLabelInfo_host; - - TRACE("%#x, %#x\n", params->queue, params->pLabelInfo); - - convert_VkDebugUtilsLabelEXT_win32_to_host((const VkDebugUtilsLabelEXT32 *)UlongToPtr(params->pLabelInfo), &pLabelInfo_host); - wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->device->funcs.p_vkQueueInsertDebugUtilsLabelEXT(wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->queue, &pLabelInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkQueuePresentKHR(void *args) -{ - struct vkQueuePresentKHR_params *params = args; - - TRACE("%p, %p\n", params->queue, params->pPresentInfo); - - params->result = wine_queue_from_handle(params->queue)->device->funcs.p_vkQueuePresentKHR(wine_queue_from_handle(params->queue)->queue, params->pPresentInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkQueuePresentKHR(void *args) -{ - struct - { - PTR32 queue; - PTR32 pPresentInfo; - VkResult result; - } *params = args; - VkPresentInfoKHR pPresentInfo_host; - struct conversion_context ctx; - - TRACE("%#x, %#x\n", params->queue, params->pPresentInfo); - - init_conversion_context(&ctx); - convert_VkPresentInfoKHR_win32_to_host(&ctx, (const VkPresentInfoKHR32 *)UlongToPtr(params->pPresentInfo), &pPresentInfo_host); - params->result = wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->device->funcs.p_vkQueuePresentKHR(wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->queue, &pPresentInfo_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkQueueSetPerformanceConfigurationINTEL(void *args) -{ - struct vkQueueSetPerformanceConfigurationINTEL_params *params = args; - - TRACE("%p, 0x%s\n", params->queue, wine_dbgstr_longlong(params->configuration)); - - params->result = wine_queue_from_handle(params->queue)->device->funcs.p_vkQueueSetPerformanceConfigurationINTEL(wine_queue_from_handle(params->queue)->queue, params->configuration); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkQueueSetPerformanceConfigurationINTEL(void *args) -{ - struct - { - PTR32 queue; - VkPerformanceConfigurationINTEL DECLSPEC_ALIGN(8) configuration; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s\n", params->queue, wine_dbgstr_longlong(params->configuration)); - - params->result = wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->device->funcs.p_vkQueueSetPerformanceConfigurationINTEL(wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->queue, params->configuration); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkQueueSubmit(void *args) -{ - struct vkQueueSubmit_params *params = args; - const VkSubmitInfo *pSubmits_host; - struct conversion_context ctx; - - TRACE("%p, %u, %p, 0x%s\n", params->queue, params->submitCount, params->pSubmits, wine_dbgstr_longlong(params->fence)); - - init_conversion_context(&ctx); - pSubmits_host = convert_VkSubmitInfo_array_win64_to_host(&ctx, params->pSubmits, params->submitCount); - params->result = wine_queue_from_handle(params->queue)->device->funcs.p_vkQueueSubmit(wine_queue_from_handle(params->queue)->queue, params->submitCount, pSubmits_host, params->fence); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkQueueSubmit(void *args) -{ - struct - { - PTR32 queue; - uint32_t submitCount; - PTR32 pSubmits; - VkFence DECLSPEC_ALIGN(8) fence; - VkResult result; - } *params = args; - const VkSubmitInfo *pSubmits_host; - struct conversion_context ctx; - - TRACE("%#x, %u, %#x, 0x%s\n", params->queue, params->submitCount, params->pSubmits, wine_dbgstr_longlong(params->fence)); - - init_conversion_context(&ctx); - pSubmits_host = convert_VkSubmitInfo_array_win32_to_host(&ctx, (const VkSubmitInfo32 *)UlongToPtr(params->pSubmits), params->submitCount); - params->result = wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->device->funcs.p_vkQueueSubmit(wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->queue, params->submitCount, pSubmits_host, params->fence); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkQueueSubmit2(void *args) -{ - struct vkQueueSubmit2_params *params = args; - const VkSubmitInfo2 *pSubmits_host; - struct conversion_context ctx; - - TRACE("%p, %u, %p, 0x%s\n", params->queue, params->submitCount, params->pSubmits, wine_dbgstr_longlong(params->fence)); - - init_conversion_context(&ctx); - pSubmits_host = convert_VkSubmitInfo2_array_win64_to_host(&ctx, params->pSubmits, params->submitCount); - params->result = wine_queue_from_handle(params->queue)->device->funcs.p_vkQueueSubmit2(wine_queue_from_handle(params->queue)->queue, params->submitCount, pSubmits_host, params->fence); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkQueueSubmit2(void *args) -{ - struct - { - PTR32 queue; - uint32_t submitCount; - PTR32 pSubmits; - VkFence DECLSPEC_ALIGN(8) fence; - VkResult result; - } *params = args; - const VkSubmitInfo2 *pSubmits_host; - struct conversion_context ctx; - - TRACE("%#x, %u, %#x, 0x%s\n", params->queue, params->submitCount, params->pSubmits, wine_dbgstr_longlong(params->fence)); - - init_conversion_context(&ctx); - pSubmits_host = convert_VkSubmitInfo2_array_win32_to_host(&ctx, (const VkSubmitInfo232 *)UlongToPtr(params->pSubmits), params->submitCount); - params->result = wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->device->funcs.p_vkQueueSubmit2(wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->queue, params->submitCount, pSubmits_host, params->fence); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkQueueSubmit2KHR(void *args) -{ - struct vkQueueSubmit2KHR_params *params = args; - const VkSubmitInfo2 *pSubmits_host; - struct conversion_context ctx; - - TRACE("%p, %u, %p, 0x%s\n", params->queue, params->submitCount, params->pSubmits, wine_dbgstr_longlong(params->fence)); - - init_conversion_context(&ctx); - pSubmits_host = convert_VkSubmitInfo2_array_win64_to_host(&ctx, params->pSubmits, params->submitCount); - params->result = wine_queue_from_handle(params->queue)->device->funcs.p_vkQueueSubmit2KHR(wine_queue_from_handle(params->queue)->queue, params->submitCount, pSubmits_host, params->fence); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkQueueSubmit2KHR(void *args) -{ - struct - { - PTR32 queue; - uint32_t submitCount; - PTR32 pSubmits; - VkFence DECLSPEC_ALIGN(8) fence; - VkResult result; - } *params = args; - const VkSubmitInfo2 *pSubmits_host; - struct conversion_context ctx; - - TRACE("%#x, %u, %#x, 0x%s\n", params->queue, params->submitCount, params->pSubmits, wine_dbgstr_longlong(params->fence)); - - init_conversion_context(&ctx); - pSubmits_host = convert_VkSubmitInfo2_array_win32_to_host(&ctx, (const VkSubmitInfo232 *)UlongToPtr(params->pSubmits), params->submitCount); - params->result = wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->device->funcs.p_vkQueueSubmit2KHR(wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->queue, params->submitCount, pSubmits_host, params->fence); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkQueueWaitIdle(void *args) -{ - struct vkQueueWaitIdle_params *params = args; - - TRACE("%p\n", params->queue); - - params->result = wine_queue_from_handle(params->queue)->device->funcs.p_vkQueueWaitIdle(wine_queue_from_handle(params->queue)->queue); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkQueueWaitIdle(void *args) -{ - struct - { - PTR32 queue; - VkResult result; - } *params = args; - - TRACE("%#x\n", params->queue); - - params->result = wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->device->funcs.p_vkQueueWaitIdle(wine_queue_from_handle((VkQueue)UlongToPtr(params->queue))->queue); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkReleasePerformanceConfigurationINTEL(void *args) -{ - struct vkReleasePerformanceConfigurationINTEL_params *params = args; - - TRACE("%p, 0x%s\n", params->device, wine_dbgstr_longlong(params->configuration)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkReleasePerformanceConfigurationINTEL(wine_device_from_handle(params->device)->device, params->configuration); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkReleasePerformanceConfigurationINTEL(void *args) -{ - struct - { - PTR32 device; - VkPerformanceConfigurationINTEL DECLSPEC_ALIGN(8) configuration; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s\n", params->device, wine_dbgstr_longlong(params->configuration)); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkReleasePerformanceConfigurationINTEL(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->configuration); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkReleaseProfilingLockKHR(void *args) -{ - struct vkReleaseProfilingLockKHR_params *params = args; - - TRACE("%p\n", params->device); - - wine_device_from_handle(params->device)->funcs.p_vkReleaseProfilingLockKHR(wine_device_from_handle(params->device)->device); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkReleaseProfilingLockKHR(void *args) -{ - struct - { - PTR32 device; - } *params = args; - - TRACE("%#x\n", params->device); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkReleaseProfilingLockKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkReleaseSwapchainImagesEXT(void *args) -{ - struct vkReleaseSwapchainImagesEXT_params *params = args; - - TRACE("%p, %p\n", params->device, params->pReleaseInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkReleaseSwapchainImagesEXT(wine_device_from_handle(params->device)->device, params->pReleaseInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkReleaseSwapchainImagesEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pReleaseInfo; - VkResult result; - } *params = args; - VkReleaseSwapchainImagesInfoEXT pReleaseInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pReleaseInfo); - - convert_VkReleaseSwapchainImagesInfoEXT_win32_to_host((const VkReleaseSwapchainImagesInfoEXT32 *)UlongToPtr(params->pReleaseInfo), &pReleaseInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkReleaseSwapchainImagesEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pReleaseInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkResetCommandBuffer(void *args) -{ - struct vkResetCommandBuffer_params *params = args; - - TRACE("%p, %#x\n", params->commandBuffer, params->flags); - - params->result = wine_cmd_buffer_from_handle(params->commandBuffer)->device->funcs.p_vkResetCommandBuffer(wine_cmd_buffer_from_handle(params->commandBuffer)->command_buffer, params->flags); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkResetCommandBuffer(void *args) -{ - struct - { - PTR32 commandBuffer; - VkCommandBufferResetFlags flags; - VkResult result; - } *params = args; - - TRACE("%#x, %#x\n", params->commandBuffer, params->flags); - - params->result = wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->device->funcs.p_vkResetCommandBuffer(wine_cmd_buffer_from_handle((VkCommandBuffer)UlongToPtr(params->commandBuffer))->command_buffer, params->flags); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkResetCommandPool(void *args) -{ - struct vkResetCommandPool_params *params = args; - - TRACE("%p, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->commandPool), params->flags); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkResetCommandPool(wine_device_from_handle(params->device)->device, wine_cmd_pool_from_handle(params->commandPool)->command_pool, params->flags); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkResetCommandPool(void *args) -{ - struct - { - PTR32 device; - VkCommandPool DECLSPEC_ALIGN(8) commandPool; - VkCommandPoolResetFlags flags; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->commandPool), params->flags); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkResetCommandPool(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, wine_cmd_pool_from_handle(params->commandPool)->command_pool, params->flags); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkResetDescriptorPool(void *args) -{ - struct vkResetDescriptorPool_params *params = args; - - TRACE("%p, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->descriptorPool), params->flags); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkResetDescriptorPool(wine_device_from_handle(params->device)->device, params->descriptorPool, params->flags); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkResetDescriptorPool(void *args) -{ - struct - { - PTR32 device; - VkDescriptorPool DECLSPEC_ALIGN(8) descriptorPool; - VkDescriptorPoolResetFlags flags; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->descriptorPool), params->flags); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkResetDescriptorPool(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->descriptorPool, params->flags); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkResetEvent(void *args) -{ - struct vkResetEvent_params *params = args; - - TRACE("%p, 0x%s\n", params->device, wine_dbgstr_longlong(params->event)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkResetEvent(wine_device_from_handle(params->device)->device, params->event); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkResetEvent(void *args) -{ - struct - { - PTR32 device; - VkEvent DECLSPEC_ALIGN(8) event; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s\n", params->device, wine_dbgstr_longlong(params->event)); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkResetEvent(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->event); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkResetFences(void *args) -{ - struct vkResetFences_params *params = args; - - TRACE("%p, %u, %p\n", params->device, params->fenceCount, params->pFences); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkResetFences(wine_device_from_handle(params->device)->device, params->fenceCount, params->pFences); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkResetFences(void *args) -{ - struct - { - PTR32 device; - uint32_t fenceCount; - PTR32 pFences; - VkResult result; - } *params = args; - - TRACE("%#x, %u, %#x\n", params->device, params->fenceCount, params->pFences); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkResetFences(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->fenceCount, (const VkFence *)UlongToPtr(params->pFences)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkResetQueryPool(void *args) -{ - struct vkResetQueryPool_params *params = args; - - TRACE("%p, 0x%s, %u, %u\n", params->device, wine_dbgstr_longlong(params->queryPool), params->firstQuery, params->queryCount); - - wine_device_from_handle(params->device)->funcs.p_vkResetQueryPool(wine_device_from_handle(params->device)->device, params->queryPool, params->firstQuery, params->queryCount); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkResetQueryPool(void *args) -{ - struct - { - PTR32 device; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t firstQuery; - uint32_t queryCount; - } *params = args; - - TRACE("%#x, 0x%s, %u, %u\n", params->device, wine_dbgstr_longlong(params->queryPool), params->firstQuery, params->queryCount); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkResetQueryPool(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->queryPool, params->firstQuery, params->queryCount); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkResetQueryPoolEXT(void *args) -{ - struct vkResetQueryPoolEXT_params *params = args; - - TRACE("%p, 0x%s, %u, %u\n", params->device, wine_dbgstr_longlong(params->queryPool), params->firstQuery, params->queryCount); - - wine_device_from_handle(params->device)->funcs.p_vkResetQueryPoolEXT(wine_device_from_handle(params->device)->device, params->queryPool, params->firstQuery, params->queryCount); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkResetQueryPoolEXT(void *args) -{ - struct - { - PTR32 device; - VkQueryPool DECLSPEC_ALIGN(8) queryPool; - uint32_t firstQuery; - uint32_t queryCount; - } *params = args; - - TRACE("%#x, 0x%s, %u, %u\n", params->device, wine_dbgstr_longlong(params->queryPool), params->firstQuery, params->queryCount); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkResetQueryPoolEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->queryPool, params->firstQuery, params->queryCount); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkSetDebugUtilsObjectNameEXT(void *args) -{ - struct vkSetDebugUtilsObjectNameEXT_params *params = args; - VkDebugUtilsObjectNameInfoEXT pNameInfo_host; - - TRACE("%p, %p\n", params->device, params->pNameInfo); - - convert_VkDebugUtilsObjectNameInfoEXT_win64_to_host(params->pNameInfo, &pNameInfo_host); - params->result = wine_device_from_handle(params->device)->funcs.p_vkSetDebugUtilsObjectNameEXT(wine_device_from_handle(params->device)->device, &pNameInfo_host); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkSetDebugUtilsObjectNameEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pNameInfo; - VkResult result; - } *params = args; - VkDebugUtilsObjectNameInfoEXT pNameInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pNameInfo); - - convert_VkDebugUtilsObjectNameInfoEXT_win32_to_host((const VkDebugUtilsObjectNameInfoEXT32 *)UlongToPtr(params->pNameInfo), &pNameInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkSetDebugUtilsObjectNameEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pNameInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkSetDebugUtilsObjectTagEXT(void *args) -{ - struct vkSetDebugUtilsObjectTagEXT_params *params = args; - VkDebugUtilsObjectTagInfoEXT pTagInfo_host; - - TRACE("%p, %p\n", params->device, params->pTagInfo); - - convert_VkDebugUtilsObjectTagInfoEXT_win64_to_host(params->pTagInfo, &pTagInfo_host); - params->result = wine_device_from_handle(params->device)->funcs.p_vkSetDebugUtilsObjectTagEXT(wine_device_from_handle(params->device)->device, &pTagInfo_host); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkSetDebugUtilsObjectTagEXT(void *args) -{ - struct - { - PTR32 device; - PTR32 pTagInfo; - VkResult result; - } *params = args; - VkDebugUtilsObjectTagInfoEXT pTagInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pTagInfo); - - convert_VkDebugUtilsObjectTagInfoEXT_win32_to_host((const VkDebugUtilsObjectTagInfoEXT32 *)UlongToPtr(params->pTagInfo), &pTagInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkSetDebugUtilsObjectTagEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pTagInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkSetDeviceMemoryPriorityEXT(void *args) -{ - struct vkSetDeviceMemoryPriorityEXT_params *params = args; - - TRACE("%p, 0x%s, %f\n", params->device, wine_dbgstr_longlong(params->memory), params->priority); - - wine_device_from_handle(params->device)->funcs.p_vkSetDeviceMemoryPriorityEXT(wine_device_from_handle(params->device)->device, wine_device_memory_from_handle(params->memory)->memory, params->priority); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkSetDeviceMemoryPriorityEXT(void *args) -{ - struct - { - PTR32 device; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - float priority; - } *params = args; - - TRACE("%#x, 0x%s, %f\n", params->device, wine_dbgstr_longlong(params->memory), params->priority); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkSetDeviceMemoryPriorityEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, wine_device_memory_from_handle(params->memory)->memory, params->priority); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkSetEvent(void *args) -{ - struct vkSetEvent_params *params = args; - - TRACE("%p, 0x%s\n", params->device, wine_dbgstr_longlong(params->event)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkSetEvent(wine_device_from_handle(params->device)->device, params->event); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkSetEvent(void *args) -{ - struct - { - PTR32 device; - VkEvent DECLSPEC_ALIGN(8) event; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s\n", params->device, wine_dbgstr_longlong(params->event)); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkSetEvent(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->event); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkSetPrivateData(void *args) -{ - struct vkSetPrivateData_params *params = args; - - TRACE("%p, %#x, 0x%s, 0x%s, 0x%s\n", params->device, params->objectType, wine_dbgstr_longlong(params->objectHandle), wine_dbgstr_longlong(params->privateDataSlot), wine_dbgstr_longlong(params->data)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkSetPrivateData(wine_device_from_handle(params->device)->device, params->objectType, wine_vk_unwrap_handle(params->objectType, params->objectHandle), params->privateDataSlot, params->data); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkSetPrivateData(void *args) -{ - struct - { - PTR32 device; - VkObjectType objectType; - uint64_t DECLSPEC_ALIGN(8) objectHandle; - VkPrivateDataSlot DECLSPEC_ALIGN(8) privateDataSlot; - uint64_t DECLSPEC_ALIGN(8) data; - VkResult result; - } *params = args; - - TRACE("%#x, %#x, 0x%s, 0x%s, 0x%s\n", params->device, params->objectType, wine_dbgstr_longlong(params->objectHandle), wine_dbgstr_longlong(params->privateDataSlot), wine_dbgstr_longlong(params->data)); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkSetPrivateData(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->objectType, wine_vk_unwrap_handle(params->objectType, params->objectHandle), params->privateDataSlot, params->data); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkSetPrivateDataEXT(void *args) -{ - struct vkSetPrivateDataEXT_params *params = args; - - TRACE("%p, %#x, 0x%s, 0x%s, 0x%s\n", params->device, params->objectType, wine_dbgstr_longlong(params->objectHandle), wine_dbgstr_longlong(params->privateDataSlot), wine_dbgstr_longlong(params->data)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkSetPrivateDataEXT(wine_device_from_handle(params->device)->device, params->objectType, wine_vk_unwrap_handle(params->objectType, params->objectHandle), params->privateDataSlot, params->data); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkSetPrivateDataEXT(void *args) -{ - struct - { - PTR32 device; - VkObjectType objectType; - uint64_t DECLSPEC_ALIGN(8) objectHandle; - VkPrivateDataSlot DECLSPEC_ALIGN(8) privateDataSlot; - uint64_t DECLSPEC_ALIGN(8) data; - VkResult result; - } *params = args; - - TRACE("%#x, %#x, 0x%s, 0x%s, 0x%s\n", params->device, params->objectType, wine_dbgstr_longlong(params->objectHandle), wine_dbgstr_longlong(params->privateDataSlot), wine_dbgstr_longlong(params->data)); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkSetPrivateDataEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->objectType, wine_vk_unwrap_handle(params->objectType, params->objectHandle), params->privateDataSlot, params->data); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkSignalSemaphore(void *args) -{ - struct vkSignalSemaphore_params *params = args; - - TRACE("%p, %p\n", params->device, params->pSignalInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkSignalSemaphore(wine_device_from_handle(params->device)->device, params->pSignalInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkSignalSemaphore(void *args) -{ - struct - { - PTR32 device; - PTR32 pSignalInfo; - VkResult result; - } *params = args; - VkSemaphoreSignalInfo pSignalInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pSignalInfo); - - convert_VkSemaphoreSignalInfo_win32_to_host((const VkSemaphoreSignalInfo32 *)UlongToPtr(params->pSignalInfo), &pSignalInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkSignalSemaphore(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pSignalInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkSignalSemaphoreKHR(void *args) -{ - struct vkSignalSemaphoreKHR_params *params = args; - - TRACE("%p, %p\n", params->device, params->pSignalInfo); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkSignalSemaphoreKHR(wine_device_from_handle(params->device)->device, params->pSignalInfo); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkSignalSemaphoreKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pSignalInfo; - VkResult result; - } *params = args; - VkSemaphoreSignalInfo pSignalInfo_host; - - TRACE("%#x, %#x\n", params->device, params->pSignalInfo); - - convert_VkSemaphoreSignalInfo_win32_to_host((const VkSemaphoreSignalInfo32 *)UlongToPtr(params->pSignalInfo), &pSignalInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkSignalSemaphoreKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pSignalInfo_host); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkSubmitDebugUtilsMessageEXT(void *args) -{ - struct vkSubmitDebugUtilsMessageEXT_params *params = args; - VkDebugUtilsMessengerCallbackDataEXT pCallbackData_host; - struct conversion_context ctx; - - TRACE("%p, %#x, %#x, %p\n", params->instance, params->messageSeverity, params->messageTypes, params->pCallbackData); - - init_conversion_context(&ctx); - convert_VkDebugUtilsMessengerCallbackDataEXT_win64_to_host(&ctx, params->pCallbackData, &pCallbackData_host); - wine_instance_from_handle(params->instance)->funcs.p_vkSubmitDebugUtilsMessageEXT(wine_instance_from_handle(params->instance)->instance, params->messageSeverity, params->messageTypes, &pCallbackData_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkSubmitDebugUtilsMessageEXT(void *args) -{ - struct - { - PTR32 instance; - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity; - VkDebugUtilsMessageTypeFlagsEXT messageTypes; - PTR32 pCallbackData; - } *params = args; - VkDebugUtilsMessengerCallbackDataEXT pCallbackData_host; - struct conversion_context ctx; - - TRACE("%#x, %#x, %#x, %#x\n", params->instance, params->messageSeverity, params->messageTypes, params->pCallbackData); - - init_conversion_context(&ctx); - convert_VkDebugUtilsMessengerCallbackDataEXT_win32_to_host(&ctx, (const VkDebugUtilsMessengerCallbackDataEXT32 *)UlongToPtr(params->pCallbackData), &pCallbackData_host); - wine_instance_from_handle((VkInstance)UlongToPtr(params->instance))->funcs.p_vkSubmitDebugUtilsMessageEXT(wine_instance_from_handle((VkInstance)UlongToPtr(params->instance))->instance, params->messageSeverity, params->messageTypes, &pCallbackData_host); - free_conversion_context(&ctx); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkTrimCommandPool(void *args) -{ - struct vkTrimCommandPool_params *params = args; - - TRACE("%p, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->commandPool), params->flags); - - wine_device_from_handle(params->device)->funcs.p_vkTrimCommandPool(wine_device_from_handle(params->device)->device, wine_cmd_pool_from_handle(params->commandPool)->command_pool, params->flags); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkTrimCommandPool(void *args) -{ - struct - { - PTR32 device; - VkCommandPool DECLSPEC_ALIGN(8) commandPool; - VkCommandPoolTrimFlags flags; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->commandPool), params->flags); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkTrimCommandPool(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, wine_cmd_pool_from_handle(params->commandPool)->command_pool, params->flags); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkTrimCommandPoolKHR(void *args) -{ - struct vkTrimCommandPoolKHR_params *params = args; - - TRACE("%p, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->commandPool), params->flags); - - wine_device_from_handle(params->device)->funcs.p_vkTrimCommandPoolKHR(wine_device_from_handle(params->device)->device, wine_cmd_pool_from_handle(params->commandPool)->command_pool, params->flags); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkTrimCommandPoolKHR(void *args) -{ - struct - { - PTR32 device; - VkCommandPool DECLSPEC_ALIGN(8) commandPool; - VkCommandPoolTrimFlags flags; - } *params = args; - - TRACE("%#x, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->commandPool), params->flags); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkTrimCommandPoolKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, wine_cmd_pool_from_handle(params->commandPool)->command_pool, params->flags); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkUninitializePerformanceApiINTEL(void *args) -{ - struct vkUninitializePerformanceApiINTEL_params *params = args; - - TRACE("%p\n", params->device); - - wine_device_from_handle(params->device)->funcs.p_vkUninitializePerformanceApiINTEL(wine_device_from_handle(params->device)->device); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkUninitializePerformanceApiINTEL(void *args) -{ - struct - { - PTR32 device; - } *params = args; - - TRACE("%#x\n", params->device); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkUninitializePerformanceApiINTEL(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkUnmapMemory(void *args) -{ - struct vkUnmapMemory_params *params = args; - - TRACE("%p, 0x%s\n", params->device, wine_dbgstr_longlong(params->memory)); - - wine_vkUnmapMemory(params->device, params->memory); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkUnmapMemory(void *args) -{ - struct - { - PTR32 device; - VkDeviceMemory DECLSPEC_ALIGN(8) memory; - } *params = args; - - TRACE("%#x, 0x%s\n", params->device, wine_dbgstr_longlong(params->memory)); - - wine_vkUnmapMemory((VkDevice)UlongToPtr(params->device), params->memory); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static void thunk64_vkUpdateDescriptorSetWithTemplate(void *args) -{ - struct vkUpdateDescriptorSetWithTemplate_params *params = args; - - wine_device_from_handle(params->device)->funcs.p_vkUpdateDescriptorSetWithTemplate(wine_device_from_handle(params->device)->device, params->descriptorSet, params->descriptorUpdateTemplate, params->pData); -} -#endif /* _WIN64 */ - -static void thunk32_vkUpdateDescriptorSetWithTemplate(void *args) -{ - struct - { - PTR32 device; - VkDescriptorSet DECLSPEC_ALIGN(8) descriptorSet; - VkDescriptorUpdateTemplate DECLSPEC_ALIGN(8) descriptorUpdateTemplate; - PTR32 pData; - } *params = args; - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkUpdateDescriptorSetWithTemplate(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->descriptorSet, params->descriptorUpdateTemplate, (const void *)UlongToPtr(params->pData)); -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkUpdateDescriptorSetWithTemplateKHR(void *args) -{ - struct vkUpdateDescriptorSetWithTemplateKHR_params *params = args; - - TRACE("%p, 0x%s, 0x%s, %p\n", params->device, wine_dbgstr_longlong(params->descriptorSet), wine_dbgstr_longlong(params->descriptorUpdateTemplate), params->pData); - - wine_device_from_handle(params->device)->funcs.p_vkUpdateDescriptorSetWithTemplateKHR(wine_device_from_handle(params->device)->device, params->descriptorSet, params->descriptorUpdateTemplate, params->pData); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkUpdateDescriptorSetWithTemplateKHR(void *args) -{ - struct - { - PTR32 device; - VkDescriptorSet DECLSPEC_ALIGN(8) descriptorSet; - VkDescriptorUpdateTemplate DECLSPEC_ALIGN(8) descriptorUpdateTemplate; - PTR32 pData; - } *params = args; - - TRACE("%#x, 0x%s, 0x%s, %#x\n", params->device, wine_dbgstr_longlong(params->descriptorSet), wine_dbgstr_longlong(params->descriptorUpdateTemplate), params->pData); - - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkUpdateDescriptorSetWithTemplateKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->descriptorSet, params->descriptorUpdateTemplate, (const void *)UlongToPtr(params->pData)); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static void thunk64_vkUpdateDescriptorSets(void *args) -{ - struct vkUpdateDescriptorSets_params *params = args; - - wine_device_from_handle(params->device)->funcs.p_vkUpdateDescriptorSets(wine_device_from_handle(params->device)->device, params->descriptorWriteCount, params->pDescriptorWrites, params->descriptorCopyCount, params->pDescriptorCopies); -} -#endif /* _WIN64 */ - -static void thunk32_vkUpdateDescriptorSets(void *args) -{ - struct - { - PTR32 device; - uint32_t descriptorWriteCount; - PTR32 pDescriptorWrites; - uint32_t descriptorCopyCount; - PTR32 pDescriptorCopies; - } *params = args; - const VkWriteDescriptorSet *pDescriptorWrites_host; - const VkCopyDescriptorSet *pDescriptorCopies_host; - struct conversion_context ctx; - - init_conversion_context(&ctx); - pDescriptorWrites_host = convert_VkWriteDescriptorSet_array_win32_to_host(&ctx, (const VkWriteDescriptorSet32 *)UlongToPtr(params->pDescriptorWrites), params->descriptorWriteCount); - pDescriptorCopies_host = convert_VkCopyDescriptorSet_array_win32_to_host(&ctx, (const VkCopyDescriptorSet32 *)UlongToPtr(params->pDescriptorCopies), params->descriptorCopyCount); - wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkUpdateDescriptorSets(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->descriptorWriteCount, pDescriptorWrites_host, params->descriptorCopyCount, pDescriptorCopies_host); - free_conversion_context(&ctx); -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkWaitForFences(void *args) -{ - struct vkWaitForFences_params *params = args; - - TRACE("%p, %u, %p, %u, 0x%s\n", params->device, params->fenceCount, params->pFences, params->waitAll, wine_dbgstr_longlong(params->timeout)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkWaitForFences(wine_device_from_handle(params->device)->device, params->fenceCount, params->pFences, params->waitAll, params->timeout); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkWaitForFences(void *args) -{ - struct - { - PTR32 device; - uint32_t fenceCount; - PTR32 pFences; - VkBool32 waitAll; - uint64_t DECLSPEC_ALIGN(8) timeout; - VkResult result; - } *params = args; - - TRACE("%#x, %u, %#x, %u, 0x%s\n", params->device, params->fenceCount, params->pFences, params->waitAll, wine_dbgstr_longlong(params->timeout)); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkWaitForFences(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->fenceCount, (const VkFence *)UlongToPtr(params->pFences), params->waitAll, params->timeout); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkWaitForPresentKHR(void *args) -{ - struct vkWaitForPresentKHR_params *params = args; - - TRACE("%p, 0x%s, 0x%s, 0x%s\n", params->device, wine_dbgstr_longlong(params->swapchain), wine_dbgstr_longlong(params->presentId), wine_dbgstr_longlong(params->timeout)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkWaitForPresentKHR(wine_device_from_handle(params->device)->device, params->swapchain, params->presentId, params->timeout); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkWaitForPresentKHR(void *args) -{ - struct - { - PTR32 device; - VkSwapchainKHR DECLSPEC_ALIGN(8) swapchain; - uint64_t DECLSPEC_ALIGN(8) presentId; - uint64_t DECLSPEC_ALIGN(8) timeout; - VkResult result; - } *params = args; - - TRACE("%#x, 0x%s, 0x%s, 0x%s\n", params->device, wine_dbgstr_longlong(params->swapchain), wine_dbgstr_longlong(params->presentId), wine_dbgstr_longlong(params->timeout)); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkWaitForPresentKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->swapchain, params->presentId, params->timeout); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkWaitSemaphores(void *args) -{ - struct vkWaitSemaphores_params *params = args; - - TRACE("%p, %p, 0x%s\n", params->device, params->pWaitInfo, wine_dbgstr_longlong(params->timeout)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkWaitSemaphores(wine_device_from_handle(params->device)->device, params->pWaitInfo, params->timeout); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkWaitSemaphores(void *args) -{ - struct - { - PTR32 device; - PTR32 pWaitInfo; - uint64_t DECLSPEC_ALIGN(8) timeout; - VkResult result; - } *params = args; - VkSemaphoreWaitInfo pWaitInfo_host; - - TRACE("%#x, %#x, 0x%s\n", params->device, params->pWaitInfo, wine_dbgstr_longlong(params->timeout)); - - convert_VkSemaphoreWaitInfo_win32_to_host((const VkSemaphoreWaitInfo32 *)UlongToPtr(params->pWaitInfo), &pWaitInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkWaitSemaphores(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pWaitInfo_host, params->timeout); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkWaitSemaphoresKHR(void *args) -{ - struct vkWaitSemaphoresKHR_params *params = args; - - TRACE("%p, %p, 0x%s\n", params->device, params->pWaitInfo, wine_dbgstr_longlong(params->timeout)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkWaitSemaphoresKHR(wine_device_from_handle(params->device)->device, params->pWaitInfo, params->timeout); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkWaitSemaphoresKHR(void *args) -{ - struct - { - PTR32 device; - PTR32 pWaitInfo; - uint64_t DECLSPEC_ALIGN(8) timeout; - VkResult result; - } *params = args; - VkSemaphoreWaitInfo pWaitInfo_host; - - TRACE("%#x, %#x, 0x%s\n", params->device, params->pWaitInfo, wine_dbgstr_longlong(params->timeout)); - - convert_VkSemaphoreWaitInfo_win32_to_host((const VkSemaphoreWaitInfo32 *)UlongToPtr(params->pWaitInfo), &pWaitInfo_host); - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkWaitSemaphoresKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, &pWaitInfo_host, params->timeout); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkWriteAccelerationStructuresPropertiesKHR(void *args) -{ - struct vkWriteAccelerationStructuresPropertiesKHR_params *params = args; - - TRACE("%p, %u, %p, %#x, 0x%s, %p, 0x%s\n", params->device, params->accelerationStructureCount, params->pAccelerationStructures, params->queryType, wine_dbgstr_longlong(params->dataSize), params->pData, wine_dbgstr_longlong(params->stride)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkWriteAccelerationStructuresPropertiesKHR(wine_device_from_handle(params->device)->device, params->accelerationStructureCount, params->pAccelerationStructures, params->queryType, params->dataSize, params->pData, params->stride); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkWriteAccelerationStructuresPropertiesKHR(void *args) -{ - struct - { - PTR32 device; - uint32_t accelerationStructureCount; - PTR32 pAccelerationStructures; - VkQueryType queryType; - PTR32 dataSize; - PTR32 pData; - PTR32 stride; - VkResult result; - } *params = args; - - TRACE("%#x, %u, %#x, %#x, 0x%s, %#x, 0x%s\n", params->device, params->accelerationStructureCount, params->pAccelerationStructures, params->queryType, wine_dbgstr_longlong(params->dataSize), params->pData, wine_dbgstr_longlong(params->stride)); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkWriteAccelerationStructuresPropertiesKHR(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->accelerationStructureCount, (const VkAccelerationStructureKHR *)UlongToPtr(params->pAccelerationStructures), params->queryType, params->dataSize, (void *)UlongToPtr(params->pData), params->stride); - return STATUS_SUCCESS; -} - -#ifdef _WIN64 -static NTSTATUS thunk64_vkWriteMicromapsPropertiesEXT(void *args) -{ - struct vkWriteMicromapsPropertiesEXT_params *params = args; - - TRACE("%p, %u, %p, %#x, 0x%s, %p, 0x%s\n", params->device, params->micromapCount, params->pMicromaps, params->queryType, wine_dbgstr_longlong(params->dataSize), params->pData, wine_dbgstr_longlong(params->stride)); - - params->result = wine_device_from_handle(params->device)->funcs.p_vkWriteMicromapsPropertiesEXT(wine_device_from_handle(params->device)->device, params->micromapCount, params->pMicromaps, params->queryType, params->dataSize, params->pData, params->stride); - return STATUS_SUCCESS; -} -#endif /* _WIN64 */ - -static NTSTATUS thunk32_vkWriteMicromapsPropertiesEXT(void *args) -{ - struct - { - PTR32 device; - uint32_t micromapCount; - PTR32 pMicromaps; - VkQueryType queryType; - PTR32 dataSize; - PTR32 pData; - PTR32 stride; - VkResult result; - } *params = args; - - TRACE("%#x, %u, %#x, %#x, 0x%s, %#x, 0x%s\n", params->device, params->micromapCount, params->pMicromaps, params->queryType, wine_dbgstr_longlong(params->dataSize), params->pData, wine_dbgstr_longlong(params->stride)); - - params->result = wine_device_from_handle((VkDevice)UlongToPtr(params->device))->funcs.p_vkWriteMicromapsPropertiesEXT(wine_device_from_handle((VkDevice)UlongToPtr(params->device))->device, params->micromapCount, (const VkMicromapEXT *)UlongToPtr(params->pMicromaps), params->queryType, params->dataSize, (void *)UlongToPtr(params->pData), params->stride); - return STATUS_SUCCESS; -} - -static const char * const vk_device_extensions[] = -{ - "VK_AMD_buffer_marker", - "VK_AMD_device_coherent_memory", - "VK_AMD_draw_indirect_count", - "VK_AMD_gcn_shader", - "VK_AMD_gpu_shader_half_float", - "VK_AMD_gpu_shader_int16", - "VK_AMD_memory_overallocation_behavior", - "VK_AMD_mixed_attachment_samples", - "VK_AMD_negative_viewport_height", - "VK_AMD_pipeline_compiler_control", - "VK_AMD_rasterization_order", - "VK_AMD_shader_ballot", - "VK_AMD_shader_core_properties", - "VK_AMD_shader_core_properties2", - "VK_AMD_shader_early_and_late_fragment_tests", - "VK_AMD_shader_explicit_vertex_parameter", - "VK_AMD_shader_fragment_mask", - "VK_AMD_shader_image_load_store_lod", - "VK_AMD_shader_info", - "VK_AMD_shader_trinary_minmax", - "VK_AMD_texture_gather_bias_lod", - "VK_ARM_rasterization_order_attachment_access", - "VK_ARM_shader_core_builtins", - "VK_EXT_4444_formats", - "VK_EXT_astc_decode_mode", - "VK_EXT_attachment_feedback_loop_layout", - "VK_EXT_blend_operation_advanced", - "VK_EXT_border_color_swizzle", - "VK_EXT_buffer_device_address", - "VK_EXT_calibrated_timestamps", - "VK_EXT_color_write_enable", - "VK_EXT_conditional_rendering", - "VK_EXT_conservative_rasterization", - "VK_EXT_custom_border_color", - "VK_EXT_debug_marker", - "VK_EXT_depth_clamp_zero_one", - "VK_EXT_depth_clip_control", - "VK_EXT_depth_clip_enable", - "VK_EXT_depth_range_unrestricted", - "VK_EXT_descriptor_buffer", - "VK_EXT_descriptor_indexing", - "VK_EXT_device_address_binding_report", - "VK_EXT_device_fault", - "VK_EXT_discard_rectangles", - "VK_EXT_extended_dynamic_state", - "VK_EXT_extended_dynamic_state2", - "VK_EXT_extended_dynamic_state3", - "VK_EXT_external_memory_host", - "VK_EXT_filter_cubic", - "VK_EXT_fragment_density_map", - "VK_EXT_fragment_density_map2", - "VK_EXT_fragment_shader_interlock", - "VK_EXT_global_priority", - "VK_EXT_global_priority_query", - "VK_EXT_graphics_pipeline_library", - "VK_EXT_host_query_reset", - "VK_EXT_image_2d_view_of_3d", - "VK_EXT_image_compression_control", - "VK_EXT_image_compression_control_swapchain", - "VK_EXT_image_robustness", - "VK_EXT_image_view_min_lod", - "VK_EXT_index_type_uint8", - "VK_EXT_inline_uniform_block", - "VK_EXT_legacy_dithering", - "VK_EXT_line_rasterization", - "VK_EXT_load_store_op_none", - "VK_EXT_memory_budget", - "VK_EXT_memory_priority", - "VK_EXT_mesh_shader", - "VK_EXT_multi_draw", - "VK_EXT_multisampled_render_to_single_sampled", - "VK_EXT_mutable_descriptor_type", - "VK_EXT_non_seamless_cube_map", - "VK_EXT_opacity_micromap", - "VK_EXT_pageable_device_local_memory", - "VK_EXT_pci_bus_info", - "VK_EXT_pipeline_creation_cache_control", - "VK_EXT_pipeline_creation_feedback", - "VK_EXT_pipeline_properties", - "VK_EXT_pipeline_protected_access", - "VK_EXT_pipeline_robustness", - "VK_EXT_post_depth_coverage", - "VK_EXT_primitive_topology_list_restart", - "VK_EXT_primitives_generated_query", - "VK_EXT_private_data", - "VK_EXT_provoking_vertex", - "VK_EXT_queue_family_foreign", - "VK_EXT_rasterization_order_attachment_access", - "VK_EXT_rgba10x6_formats", - "VK_EXT_robustness2", - "VK_EXT_sample_locations", - "VK_EXT_sampler_filter_minmax", - "VK_EXT_scalar_block_layout", - "VK_EXT_separate_stencil_usage", - "VK_EXT_shader_atomic_float", - "VK_EXT_shader_atomic_float2", - "VK_EXT_shader_demote_to_helper_invocation", - "VK_EXT_shader_image_atomic_int64", - "VK_EXT_shader_module_identifier", - "VK_EXT_shader_stencil_export", - "VK_EXT_shader_subgroup_ballot", - "VK_EXT_shader_subgroup_vote", - "VK_EXT_shader_viewport_index_layer", - "VK_EXT_subgroup_size_control", - "VK_EXT_subpass_merge_feedback", - "VK_EXT_swapchain_maintenance1", - "VK_EXT_texel_buffer_alignment", - "VK_EXT_texture_compression_astc_hdr", - "VK_EXT_tooling_info", - "VK_EXT_transform_feedback", - "VK_EXT_validation_cache", - "VK_EXT_vertex_attribute_divisor", - "VK_EXT_vertex_input_dynamic_state", - "VK_EXT_ycbcr_2plane_444_formats", - "VK_EXT_ycbcr_image_arrays", - "VK_GOOGLE_decorate_string", - "VK_GOOGLE_hlsl_functionality1", - "VK_GOOGLE_user_type", - "VK_HUAWEI_invocation_mask", - "VK_HUAWEI_subpass_shading", - "VK_IMG_filter_cubic", - "VK_IMG_format_pvrtc", - "VK_INTEL_performance_query", - "VK_INTEL_shader_integer_functions2", - "VK_KHR_16bit_storage", - "VK_KHR_8bit_storage", - "VK_KHR_acceleration_structure", - "VK_KHR_bind_memory2", - "VK_KHR_buffer_device_address", - "VK_KHR_copy_commands2", - "VK_KHR_create_renderpass2", - "VK_KHR_dedicated_allocation", - "VK_KHR_deferred_host_operations", - "VK_KHR_depth_stencil_resolve", - "VK_KHR_descriptor_update_template", - "VK_KHR_device_group", - "VK_KHR_draw_indirect_count", - "VK_KHR_driver_properties", - "VK_KHR_dynamic_rendering", - "VK_KHR_external_fence", - "VK_KHR_external_memory", - "VK_KHR_external_semaphore", - "VK_KHR_format_feature_flags2", - "VK_KHR_fragment_shader_barycentric", - "VK_KHR_fragment_shading_rate", - "VK_KHR_get_memory_requirements2", - "VK_KHR_global_priority", - "VK_KHR_image_format_list", - "VK_KHR_imageless_framebuffer", - "VK_KHR_incremental_present", - "VK_KHR_maintenance1", - "VK_KHR_maintenance2", - "VK_KHR_maintenance3", - "VK_KHR_maintenance4", - "VK_KHR_multiview", - "VK_KHR_performance_query", - "VK_KHR_pipeline_executable_properties", - "VK_KHR_pipeline_library", - "VK_KHR_present_id", - "VK_KHR_present_wait", - "VK_KHR_push_descriptor", - "VK_KHR_ray_query", - "VK_KHR_ray_tracing_maintenance1", - "VK_KHR_ray_tracing_pipeline", - "VK_KHR_relaxed_block_layout", - "VK_KHR_sampler_mirror_clamp_to_edge", - "VK_KHR_sampler_ycbcr_conversion", - "VK_KHR_separate_depth_stencil_layouts", - "VK_KHR_shader_atomic_int64", - "VK_KHR_shader_clock", - "VK_KHR_shader_draw_parameters", - "VK_KHR_shader_float16_int8", - "VK_KHR_shader_float_controls", - "VK_KHR_shader_integer_dot_product", - "VK_KHR_shader_non_semantic_info", - "VK_KHR_shader_subgroup_extended_types", - "VK_KHR_shader_subgroup_uniform_control_flow", - "VK_KHR_shader_terminate_invocation", - "VK_KHR_spirv_1_4", - "VK_KHR_storage_buffer_storage_class", - "VK_KHR_swapchain", - "VK_KHR_swapchain_mutable_format", - "VK_KHR_synchronization2", - "VK_KHR_timeline_semaphore", - "VK_KHR_uniform_buffer_standard_layout", - "VK_KHR_variable_pointers", - "VK_KHR_vulkan_memory_model", - "VK_KHR_workgroup_memory_explicit_layout", - "VK_KHR_zero_initialize_workgroup_memory", - "VK_NVX_binary_import", - "VK_NVX_image_view_handle", - "VK_NV_clip_space_w_scaling", - "VK_NV_compute_shader_derivatives", - "VK_NV_cooperative_matrix", - "VK_NV_copy_memory_indirect", - "VK_NV_corner_sampled_image", - "VK_NV_coverage_reduction_mode", - "VK_NV_dedicated_allocation", - "VK_NV_dedicated_allocation_image_aliasing", - "VK_NV_device_diagnostic_checkpoints", - "VK_NV_device_diagnostics_config", - "VK_NV_device_generated_commands", - "VK_NV_fill_rectangle", - "VK_NV_fragment_coverage_to_color", - "VK_NV_fragment_shader_barycentric", - "VK_NV_fragment_shading_rate_enums", - "VK_NV_framebuffer_mixed_samples", - "VK_NV_geometry_shader_passthrough", - "VK_NV_glsl_shader", - "VK_NV_inherited_viewport_scissor", - "VK_NV_linear_color_attachment", - "VK_NV_memory_decompression", - "VK_NV_mesh_shader", - "VK_NV_optical_flow", - "VK_NV_present_barrier", - "VK_NV_ray_tracing", - "VK_NV_ray_tracing_invocation_reorder", - "VK_NV_ray_tracing_motion_blur", - "VK_NV_representative_fragment_test", - "VK_NV_sample_mask_override_coverage", - "VK_NV_scissor_exclusive", - "VK_NV_shader_image_footprint", - "VK_NV_shader_sm_builtins", - "VK_NV_shader_subgroup_partitioned", - "VK_NV_shading_rate_image", - "VK_NV_viewport_array2", - "VK_NV_viewport_swizzle", - "VK_QCOM_fragment_density_map_offset", - "VK_QCOM_image_processing", - "VK_QCOM_multiview_per_view_viewports", - "VK_QCOM_render_pass_shader_resolve", - "VK_QCOM_render_pass_store_ops", - "VK_QCOM_render_pass_transform", - "VK_QCOM_rotated_copy_commands", - "VK_QCOM_tile_properties", - "VK_VALVE_descriptor_set_host_mapping", - "VK_VALVE_mutable_descriptor_type", -}; - -static const char * const vk_instance_extensions[] = -{ - "VK_EXT_debug_report", - "VK_EXT_debug_utils", - "VK_EXT_surface_maintenance1", - "VK_EXT_swapchain_colorspace", - "VK_EXT_validation_features", - "VK_EXT_validation_flags", - "VK_KHR_device_group_creation", - "VK_KHR_external_fence_capabilities", - "VK_KHR_external_memory_capabilities", - "VK_KHR_external_semaphore_capabilities", - "VK_KHR_get_physical_device_properties2", - "VK_KHR_get_surface_capabilities2", - "VK_KHR_portability_enumeration", - "VK_KHR_surface", - "VK_KHR_win32_surface", -}; - -BOOL wine_vk_device_extension_supported(const char *name) -{ - unsigned int i; - for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++) - { - if (strcmp(vk_device_extensions[i], name) == 0) - return TRUE; - } - return FALSE; -} - -BOOL wine_vk_instance_extension_supported(const char *name) -{ - unsigned int i; - for (i = 0; i < ARRAY_SIZE(vk_instance_extensions); i++) - { - if (strcmp(vk_instance_extensions[i], name) == 0) - return TRUE; - } - return FALSE; -} - -BOOL wine_vk_is_type_wrapped(VkObjectType type) -{ - return FALSE || - type == VK_OBJECT_TYPE_COMMAND_BUFFER || - type == VK_OBJECT_TYPE_COMMAND_POOL || - type == VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT || - type == VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT || - type == VK_OBJECT_TYPE_DEVICE || - type == VK_OBJECT_TYPE_DEVICE_MEMORY || - type == VK_OBJECT_TYPE_INSTANCE || - type == VK_OBJECT_TYPE_PHYSICAL_DEVICE || - type == VK_OBJECT_TYPE_QUEUE || - type == VK_OBJECT_TYPE_SURFACE_KHR; -} - -#ifdef _WIN64 - -const unixlib_entry_t __wine_unix_call_funcs[] = -{ - init_vulkan, - vk_is_available_instance_function, - vk_is_available_device_function, - thunk64_vkAcquireNextImage2KHR, - thunk64_vkAcquireNextImageKHR, - thunk64_vkAcquirePerformanceConfigurationINTEL, - thunk64_vkAcquireProfilingLockKHR, - thunk64_vkAllocateCommandBuffers, - thunk64_vkAllocateDescriptorSets, - thunk64_vkAllocateMemory, - thunk64_vkBeginCommandBuffer, - thunk64_vkBindAccelerationStructureMemoryNV, - thunk64_vkBindBufferMemory, - thunk64_vkBindBufferMemory2, - thunk64_vkBindBufferMemory2KHR, - thunk64_vkBindImageMemory, - thunk64_vkBindImageMemory2, - thunk64_vkBindImageMemory2KHR, - thunk64_vkBindOpticalFlowSessionImageNV, - thunk64_vkBuildAccelerationStructuresKHR, - thunk64_vkBuildMicromapsEXT, - (void *)thunk64_vkCmdBeginConditionalRenderingEXT, - (void *)thunk64_vkCmdBeginDebugUtilsLabelEXT, - (void *)thunk64_vkCmdBeginQuery, - (void *)thunk64_vkCmdBeginQueryIndexedEXT, - (void *)thunk64_vkCmdBeginRenderPass, - (void *)thunk64_vkCmdBeginRenderPass2, - (void *)thunk64_vkCmdBeginRenderPass2KHR, - (void *)thunk64_vkCmdBeginRendering, - (void *)thunk64_vkCmdBeginRenderingKHR, - (void *)thunk64_vkCmdBeginTransformFeedbackEXT, - (void *)thunk64_vkCmdBindDescriptorBufferEmbeddedSamplersEXT, - (void *)thunk64_vkCmdBindDescriptorBuffersEXT, - (void *)thunk64_vkCmdBindDescriptorSets, - (void *)thunk64_vkCmdBindIndexBuffer, - (void *)thunk64_vkCmdBindInvocationMaskHUAWEI, - (void *)thunk64_vkCmdBindPipeline, - (void *)thunk64_vkCmdBindPipelineShaderGroupNV, - (void *)thunk64_vkCmdBindShadingRateImageNV, - (void *)thunk64_vkCmdBindTransformFeedbackBuffersEXT, - (void *)thunk64_vkCmdBindVertexBuffers, - (void *)thunk64_vkCmdBindVertexBuffers2, - (void *)thunk64_vkCmdBindVertexBuffers2EXT, - (void *)thunk64_vkCmdBlitImage, - (void *)thunk64_vkCmdBlitImage2, - (void *)thunk64_vkCmdBlitImage2KHR, - (void *)thunk64_vkCmdBuildAccelerationStructureNV, - (void *)thunk64_vkCmdBuildAccelerationStructuresIndirectKHR, - (void *)thunk64_vkCmdBuildAccelerationStructuresKHR, - (void *)thunk64_vkCmdBuildMicromapsEXT, - (void *)thunk64_vkCmdClearAttachments, - (void *)thunk64_vkCmdClearColorImage, - (void *)thunk64_vkCmdClearDepthStencilImage, - (void *)thunk64_vkCmdCopyAccelerationStructureKHR, - (void *)thunk64_vkCmdCopyAccelerationStructureNV, - (void *)thunk64_vkCmdCopyAccelerationStructureToMemoryKHR, - (void *)thunk64_vkCmdCopyBuffer, - (void *)thunk64_vkCmdCopyBuffer2, - (void *)thunk64_vkCmdCopyBuffer2KHR, - (void *)thunk64_vkCmdCopyBufferToImage, - (void *)thunk64_vkCmdCopyBufferToImage2, - (void *)thunk64_vkCmdCopyBufferToImage2KHR, - (void *)thunk64_vkCmdCopyImage, - (void *)thunk64_vkCmdCopyImage2, - (void *)thunk64_vkCmdCopyImage2KHR, - (void *)thunk64_vkCmdCopyImageToBuffer, - (void *)thunk64_vkCmdCopyImageToBuffer2, - (void *)thunk64_vkCmdCopyImageToBuffer2KHR, - (void *)thunk64_vkCmdCopyMemoryIndirectNV, - (void *)thunk64_vkCmdCopyMemoryToAccelerationStructureKHR, - (void *)thunk64_vkCmdCopyMemoryToImageIndirectNV, - (void *)thunk64_vkCmdCopyMemoryToMicromapEXT, - (void *)thunk64_vkCmdCopyMicromapEXT, - (void *)thunk64_vkCmdCopyMicromapToMemoryEXT, - (void *)thunk64_vkCmdCopyQueryPoolResults, - (void *)thunk64_vkCmdCuLaunchKernelNVX, - (void *)thunk64_vkCmdDebugMarkerBeginEXT, - (void *)thunk64_vkCmdDebugMarkerEndEXT, - (void *)thunk64_vkCmdDebugMarkerInsertEXT, - (void *)thunk64_vkCmdDecompressMemoryIndirectCountNV, - (void *)thunk64_vkCmdDecompressMemoryNV, - (void *)thunk64_vkCmdDispatch, - (void *)thunk64_vkCmdDispatchBase, - (void *)thunk64_vkCmdDispatchBaseKHR, - (void *)thunk64_vkCmdDispatchIndirect, - (void *)thunk64_vkCmdDraw, - (void *)thunk64_vkCmdDrawIndexed, - (void *)thunk64_vkCmdDrawIndexedIndirect, - (void *)thunk64_vkCmdDrawIndexedIndirectCount, - (void *)thunk64_vkCmdDrawIndexedIndirectCountAMD, - (void *)thunk64_vkCmdDrawIndexedIndirectCountKHR, - (void *)thunk64_vkCmdDrawIndirect, - (void *)thunk64_vkCmdDrawIndirectByteCountEXT, - (void *)thunk64_vkCmdDrawIndirectCount, - (void *)thunk64_vkCmdDrawIndirectCountAMD, - (void *)thunk64_vkCmdDrawIndirectCountKHR, - (void *)thunk64_vkCmdDrawMeshTasksEXT, - (void *)thunk64_vkCmdDrawMeshTasksIndirectCountEXT, - (void *)thunk64_vkCmdDrawMeshTasksIndirectCountNV, - (void *)thunk64_vkCmdDrawMeshTasksIndirectEXT, - (void *)thunk64_vkCmdDrawMeshTasksIndirectNV, - (void *)thunk64_vkCmdDrawMeshTasksNV, - (void *)thunk64_vkCmdDrawMultiEXT, - (void *)thunk64_vkCmdDrawMultiIndexedEXT, - (void *)thunk64_vkCmdEndConditionalRenderingEXT, - (void *)thunk64_vkCmdEndDebugUtilsLabelEXT, - (void *)thunk64_vkCmdEndQuery, - (void *)thunk64_vkCmdEndQueryIndexedEXT, - (void *)thunk64_vkCmdEndRenderPass, - (void *)thunk64_vkCmdEndRenderPass2, - (void *)thunk64_vkCmdEndRenderPass2KHR, - (void *)thunk64_vkCmdEndRendering, - (void *)thunk64_vkCmdEndRenderingKHR, - (void *)thunk64_vkCmdEndTransformFeedbackEXT, - (void *)thunk64_vkCmdExecuteCommands, - (void *)thunk64_vkCmdExecuteGeneratedCommandsNV, - (void *)thunk64_vkCmdFillBuffer, - (void *)thunk64_vkCmdInsertDebugUtilsLabelEXT, - (void *)thunk64_vkCmdNextSubpass, - (void *)thunk64_vkCmdNextSubpass2, - (void *)thunk64_vkCmdNextSubpass2KHR, - (void *)thunk64_vkCmdOpticalFlowExecuteNV, - (void *)thunk64_vkCmdPipelineBarrier, - (void *)thunk64_vkCmdPipelineBarrier2, - (void *)thunk64_vkCmdPipelineBarrier2KHR, - (void *)thunk64_vkCmdPreprocessGeneratedCommandsNV, - (void *)thunk64_vkCmdPushConstants, - (void *)thunk64_vkCmdPushDescriptorSetKHR, - (void *)thunk64_vkCmdPushDescriptorSetWithTemplateKHR, - (void *)thunk64_vkCmdResetEvent, - (void *)thunk64_vkCmdResetEvent2, - (void *)thunk64_vkCmdResetEvent2KHR, - (void *)thunk64_vkCmdResetQueryPool, - (void *)thunk64_vkCmdResolveImage, - (void *)thunk64_vkCmdResolveImage2, - (void *)thunk64_vkCmdResolveImage2KHR, - (void *)thunk64_vkCmdSetAlphaToCoverageEnableEXT, - (void *)thunk64_vkCmdSetAlphaToOneEnableEXT, - (void *)thunk64_vkCmdSetBlendConstants, - (void *)thunk64_vkCmdSetCheckpointNV, - (void *)thunk64_vkCmdSetCoarseSampleOrderNV, - (void *)thunk64_vkCmdSetColorBlendAdvancedEXT, - (void *)thunk64_vkCmdSetColorBlendEnableEXT, - (void *)thunk64_vkCmdSetColorBlendEquationEXT, - (void *)thunk64_vkCmdSetColorWriteEnableEXT, - (void *)thunk64_vkCmdSetColorWriteMaskEXT, - (void *)thunk64_vkCmdSetConservativeRasterizationModeEXT, - (void *)thunk64_vkCmdSetCoverageModulationModeNV, - (void *)thunk64_vkCmdSetCoverageModulationTableEnableNV, - (void *)thunk64_vkCmdSetCoverageModulationTableNV, - (void *)thunk64_vkCmdSetCoverageReductionModeNV, - (void *)thunk64_vkCmdSetCoverageToColorEnableNV, - (void *)thunk64_vkCmdSetCoverageToColorLocationNV, - (void *)thunk64_vkCmdSetCullMode, - (void *)thunk64_vkCmdSetCullModeEXT, - (void *)thunk64_vkCmdSetDepthBias, - (void *)thunk64_vkCmdSetDepthBiasEnable, - (void *)thunk64_vkCmdSetDepthBiasEnableEXT, - (void *)thunk64_vkCmdSetDepthBounds, - (void *)thunk64_vkCmdSetDepthBoundsTestEnable, - (void *)thunk64_vkCmdSetDepthBoundsTestEnableEXT, - (void *)thunk64_vkCmdSetDepthClampEnableEXT, - (void *)thunk64_vkCmdSetDepthClipEnableEXT, - (void *)thunk64_vkCmdSetDepthClipNegativeOneToOneEXT, - (void *)thunk64_vkCmdSetDepthCompareOp, - (void *)thunk64_vkCmdSetDepthCompareOpEXT, - (void *)thunk64_vkCmdSetDepthTestEnable, - (void *)thunk64_vkCmdSetDepthTestEnableEXT, - (void *)thunk64_vkCmdSetDepthWriteEnable, - (void *)thunk64_vkCmdSetDepthWriteEnableEXT, - (void *)thunk64_vkCmdSetDescriptorBufferOffsetsEXT, - (void *)thunk64_vkCmdSetDeviceMask, - (void *)thunk64_vkCmdSetDeviceMaskKHR, - (void *)thunk64_vkCmdSetDiscardRectangleEXT, - (void *)thunk64_vkCmdSetEvent, - (void *)thunk64_vkCmdSetEvent2, - (void *)thunk64_vkCmdSetEvent2KHR, - (void *)thunk64_vkCmdSetExclusiveScissorNV, - (void *)thunk64_vkCmdSetExtraPrimitiveOverestimationSizeEXT, - (void *)thunk64_vkCmdSetFragmentShadingRateEnumNV, - (void *)thunk64_vkCmdSetFragmentShadingRateKHR, - (void *)thunk64_vkCmdSetFrontFace, - (void *)thunk64_vkCmdSetFrontFaceEXT, - (void *)thunk64_vkCmdSetLineRasterizationModeEXT, - (void *)thunk64_vkCmdSetLineStippleEXT, - (void *)thunk64_vkCmdSetLineStippleEnableEXT, - (void *)thunk64_vkCmdSetLineWidth, - (void *)thunk64_vkCmdSetLogicOpEXT, - (void *)thunk64_vkCmdSetLogicOpEnableEXT, - (void *)thunk64_vkCmdSetPatchControlPointsEXT, - thunk64_vkCmdSetPerformanceMarkerINTEL, - thunk64_vkCmdSetPerformanceOverrideINTEL, - thunk64_vkCmdSetPerformanceStreamMarkerINTEL, - (void *)thunk64_vkCmdSetPolygonModeEXT, - (void *)thunk64_vkCmdSetPrimitiveRestartEnable, - (void *)thunk64_vkCmdSetPrimitiveRestartEnableEXT, - (void *)thunk64_vkCmdSetPrimitiveTopology, - (void *)thunk64_vkCmdSetPrimitiveTopologyEXT, - (void *)thunk64_vkCmdSetProvokingVertexModeEXT, - (void *)thunk64_vkCmdSetRasterizationSamplesEXT, - (void *)thunk64_vkCmdSetRasterizationStreamEXT, - (void *)thunk64_vkCmdSetRasterizerDiscardEnable, - (void *)thunk64_vkCmdSetRasterizerDiscardEnableEXT, - (void *)thunk64_vkCmdSetRayTracingPipelineStackSizeKHR, - (void *)thunk64_vkCmdSetRepresentativeFragmentTestEnableNV, - (void *)thunk64_vkCmdSetSampleLocationsEXT, - (void *)thunk64_vkCmdSetSampleLocationsEnableEXT, - (void *)thunk64_vkCmdSetSampleMaskEXT, - (void *)thunk64_vkCmdSetScissor, - (void *)thunk64_vkCmdSetScissorWithCount, - (void *)thunk64_vkCmdSetScissorWithCountEXT, - (void *)thunk64_vkCmdSetShadingRateImageEnableNV, - (void *)thunk64_vkCmdSetStencilCompareMask, - (void *)thunk64_vkCmdSetStencilOp, - (void *)thunk64_vkCmdSetStencilOpEXT, - (void *)thunk64_vkCmdSetStencilReference, - (void *)thunk64_vkCmdSetStencilTestEnable, - (void *)thunk64_vkCmdSetStencilTestEnableEXT, - (void *)thunk64_vkCmdSetStencilWriteMask, - (void *)thunk64_vkCmdSetTessellationDomainOriginEXT, - (void *)thunk64_vkCmdSetVertexInputEXT, - (void *)thunk64_vkCmdSetViewport, - (void *)thunk64_vkCmdSetViewportShadingRatePaletteNV, - (void *)thunk64_vkCmdSetViewportSwizzleNV, - (void *)thunk64_vkCmdSetViewportWScalingEnableNV, - (void *)thunk64_vkCmdSetViewportWScalingNV, - (void *)thunk64_vkCmdSetViewportWithCount, - (void *)thunk64_vkCmdSetViewportWithCountEXT, - (void *)thunk64_vkCmdSubpassShadingHUAWEI, - (void *)thunk64_vkCmdTraceRaysIndirect2KHR, - (void *)thunk64_vkCmdTraceRaysIndirectKHR, - (void *)thunk64_vkCmdTraceRaysKHR, - (void *)thunk64_vkCmdTraceRaysNV, - (void *)thunk64_vkCmdUpdateBuffer, - (void *)thunk64_vkCmdWaitEvents, - (void *)thunk64_vkCmdWaitEvents2, - (void *)thunk64_vkCmdWaitEvents2KHR, - (void *)thunk64_vkCmdWriteAccelerationStructuresPropertiesKHR, - (void *)thunk64_vkCmdWriteAccelerationStructuresPropertiesNV, - (void *)thunk64_vkCmdWriteBufferMarker2AMD, - (void *)thunk64_vkCmdWriteBufferMarkerAMD, - (void *)thunk64_vkCmdWriteMicromapsPropertiesEXT, - (void *)thunk64_vkCmdWriteTimestamp, - (void *)thunk64_vkCmdWriteTimestamp2, - (void *)thunk64_vkCmdWriteTimestamp2KHR, - thunk64_vkCompileDeferredNV, - thunk64_vkCopyAccelerationStructureKHR, - thunk64_vkCopyAccelerationStructureToMemoryKHR, - thunk64_vkCopyMemoryToAccelerationStructureKHR, - thunk64_vkCopyMemoryToMicromapEXT, - thunk64_vkCopyMicromapEXT, - thunk64_vkCopyMicromapToMemoryEXT, - thunk64_vkCreateAccelerationStructureKHR, - thunk64_vkCreateAccelerationStructureNV, - thunk64_vkCreateBuffer, - thunk64_vkCreateBufferView, - thunk64_vkCreateCommandPool, - thunk64_vkCreateComputePipelines, - thunk64_vkCreateCuFunctionNVX, - thunk64_vkCreateCuModuleNVX, - thunk64_vkCreateDebugReportCallbackEXT, - thunk64_vkCreateDebugUtilsMessengerEXT, - thunk64_vkCreateDeferredOperationKHR, - thunk64_vkCreateDescriptorPool, - thunk64_vkCreateDescriptorSetLayout, - thunk64_vkCreateDescriptorUpdateTemplate, - thunk64_vkCreateDescriptorUpdateTemplateKHR, - thunk64_vkCreateDevice, - thunk64_vkCreateEvent, - thunk64_vkCreateFence, - thunk64_vkCreateFramebuffer, - thunk64_vkCreateGraphicsPipelines, - thunk64_vkCreateImage, - thunk64_vkCreateImageView, - thunk64_vkCreateIndirectCommandsLayoutNV, - thunk64_vkCreateInstance, - thunk64_vkCreateMicromapEXT, - thunk64_vkCreateOpticalFlowSessionNV, - thunk64_vkCreatePipelineCache, - thunk64_vkCreatePipelineLayout, - thunk64_vkCreatePrivateDataSlot, - thunk64_vkCreatePrivateDataSlotEXT, - thunk64_vkCreateQueryPool, - thunk64_vkCreateRayTracingPipelinesKHR, - thunk64_vkCreateRayTracingPipelinesNV, - thunk64_vkCreateRenderPass, - thunk64_vkCreateRenderPass2, - thunk64_vkCreateRenderPass2KHR, - thunk64_vkCreateSampler, - thunk64_vkCreateSamplerYcbcrConversion, - thunk64_vkCreateSamplerYcbcrConversionKHR, - thunk64_vkCreateSemaphore, - thunk64_vkCreateShaderModule, - thunk64_vkCreateSwapchainKHR, - thunk64_vkCreateValidationCacheEXT, - thunk64_vkCreateWin32SurfaceKHR, - thunk64_vkDebugMarkerSetObjectNameEXT, - thunk64_vkDebugMarkerSetObjectTagEXT, - thunk64_vkDebugReportMessageEXT, - thunk64_vkDeferredOperationJoinKHR, - thunk64_vkDestroyAccelerationStructureKHR, - thunk64_vkDestroyAccelerationStructureNV, - thunk64_vkDestroyBuffer, - thunk64_vkDestroyBufferView, - thunk64_vkDestroyCommandPool, - thunk64_vkDestroyCuFunctionNVX, - thunk64_vkDestroyCuModuleNVX, - thunk64_vkDestroyDebugReportCallbackEXT, - thunk64_vkDestroyDebugUtilsMessengerEXT, - thunk64_vkDestroyDeferredOperationKHR, - thunk64_vkDestroyDescriptorPool, - thunk64_vkDestroyDescriptorSetLayout, - thunk64_vkDestroyDescriptorUpdateTemplate, - thunk64_vkDestroyDescriptorUpdateTemplateKHR, - thunk64_vkDestroyDevice, - thunk64_vkDestroyEvent, - thunk64_vkDestroyFence, - thunk64_vkDestroyFramebuffer, - thunk64_vkDestroyImage, - thunk64_vkDestroyImageView, - thunk64_vkDestroyIndirectCommandsLayoutNV, - thunk64_vkDestroyInstance, - thunk64_vkDestroyMicromapEXT, - thunk64_vkDestroyOpticalFlowSessionNV, - thunk64_vkDestroyPipeline, - thunk64_vkDestroyPipelineCache, - thunk64_vkDestroyPipelineLayout, - thunk64_vkDestroyPrivateDataSlot, - thunk64_vkDestroyPrivateDataSlotEXT, - thunk64_vkDestroyQueryPool, - thunk64_vkDestroyRenderPass, - thunk64_vkDestroySampler, - thunk64_vkDestroySamplerYcbcrConversion, - thunk64_vkDestroySamplerYcbcrConversionKHR, - thunk64_vkDestroySemaphore, - thunk64_vkDestroyShaderModule, - thunk64_vkDestroySurfaceKHR, - thunk64_vkDestroySwapchainKHR, - thunk64_vkDestroyValidationCacheEXT, - thunk64_vkDeviceWaitIdle, - thunk64_vkEndCommandBuffer, - thunk64_vkEnumerateDeviceExtensionProperties, - thunk64_vkEnumerateDeviceLayerProperties, - thunk64_vkEnumerateInstanceExtensionProperties, - thunk64_vkEnumerateInstanceVersion, - thunk64_vkEnumeratePhysicalDeviceGroups, - thunk64_vkEnumeratePhysicalDeviceGroupsKHR, - thunk64_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR, - thunk64_vkEnumeratePhysicalDevices, - thunk64_vkFlushMappedMemoryRanges, - thunk64_vkFreeCommandBuffers, - thunk64_vkFreeDescriptorSets, - thunk64_vkFreeMemory, - thunk64_vkGetAccelerationStructureBuildSizesKHR, - thunk64_vkGetAccelerationStructureDeviceAddressKHR, - thunk64_vkGetAccelerationStructureHandleNV, - thunk64_vkGetAccelerationStructureMemoryRequirementsNV, - thunk64_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT, - thunk64_vkGetBufferDeviceAddress, - thunk64_vkGetBufferDeviceAddressEXT, - thunk64_vkGetBufferDeviceAddressKHR, - thunk64_vkGetBufferMemoryRequirements, - thunk64_vkGetBufferMemoryRequirements2, - thunk64_vkGetBufferMemoryRequirements2KHR, - thunk64_vkGetBufferOpaqueCaptureAddress, - thunk64_vkGetBufferOpaqueCaptureAddressKHR, - thunk64_vkGetBufferOpaqueCaptureDescriptorDataEXT, - thunk64_vkGetCalibratedTimestampsEXT, - thunk64_vkGetDeferredOperationMaxConcurrencyKHR, - thunk64_vkGetDeferredOperationResultKHR, - (void *)thunk64_vkGetDescriptorEXT, - thunk64_vkGetDescriptorSetHostMappingVALVE, - thunk64_vkGetDescriptorSetLayoutBindingOffsetEXT, - thunk64_vkGetDescriptorSetLayoutHostMappingInfoVALVE, - thunk64_vkGetDescriptorSetLayoutSizeEXT, - thunk64_vkGetDescriptorSetLayoutSupport, - thunk64_vkGetDescriptorSetLayoutSupportKHR, - thunk64_vkGetDeviceAccelerationStructureCompatibilityKHR, - thunk64_vkGetDeviceBufferMemoryRequirements, - thunk64_vkGetDeviceBufferMemoryRequirementsKHR, - thunk64_vkGetDeviceFaultInfoEXT, - thunk64_vkGetDeviceGroupPeerMemoryFeatures, - thunk64_vkGetDeviceGroupPeerMemoryFeaturesKHR, - thunk64_vkGetDeviceGroupPresentCapabilitiesKHR, - thunk64_vkGetDeviceGroupSurfacePresentModesKHR, - thunk64_vkGetDeviceImageMemoryRequirements, - thunk64_vkGetDeviceImageMemoryRequirementsKHR, - thunk64_vkGetDeviceImageSparseMemoryRequirements, - thunk64_vkGetDeviceImageSparseMemoryRequirementsKHR, - thunk64_vkGetDeviceMemoryCommitment, - thunk64_vkGetDeviceMemoryOpaqueCaptureAddress, - thunk64_vkGetDeviceMemoryOpaqueCaptureAddressKHR, - thunk64_vkGetDeviceMicromapCompatibilityEXT, - thunk64_vkGetDeviceQueue, - thunk64_vkGetDeviceQueue2, - thunk64_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI, - thunk64_vkGetDynamicRenderingTilePropertiesQCOM, - thunk64_vkGetEventStatus, - thunk64_vkGetFenceStatus, - thunk64_vkGetFramebufferTilePropertiesQCOM, - thunk64_vkGetGeneratedCommandsMemoryRequirementsNV, - thunk64_vkGetImageMemoryRequirements, - thunk64_vkGetImageMemoryRequirements2, - thunk64_vkGetImageMemoryRequirements2KHR, - thunk64_vkGetImageOpaqueCaptureDescriptorDataEXT, - thunk64_vkGetImageSparseMemoryRequirements, - thunk64_vkGetImageSparseMemoryRequirements2, - thunk64_vkGetImageSparseMemoryRequirements2KHR, - thunk64_vkGetImageSubresourceLayout, - thunk64_vkGetImageSubresourceLayout2EXT, - thunk64_vkGetImageViewAddressNVX, - thunk64_vkGetImageViewHandleNVX, - thunk64_vkGetImageViewOpaqueCaptureDescriptorDataEXT, - thunk64_vkGetMemoryHostPointerPropertiesEXT, - thunk64_vkGetMicromapBuildSizesEXT, - thunk64_vkGetPerformanceParameterINTEL, - thunk64_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, - thunk64_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV, - thunk64_vkGetPhysicalDeviceExternalBufferProperties, - thunk64_vkGetPhysicalDeviceExternalBufferPropertiesKHR, - thunk64_vkGetPhysicalDeviceExternalFenceProperties, - thunk64_vkGetPhysicalDeviceExternalFencePropertiesKHR, - thunk64_vkGetPhysicalDeviceExternalSemaphoreProperties, - thunk64_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR, - thunk64_vkGetPhysicalDeviceFeatures, - thunk64_vkGetPhysicalDeviceFeatures2, - thunk64_vkGetPhysicalDeviceFeatures2KHR, - thunk64_vkGetPhysicalDeviceFormatProperties, - thunk64_vkGetPhysicalDeviceFormatProperties2, - thunk64_vkGetPhysicalDeviceFormatProperties2KHR, - thunk64_vkGetPhysicalDeviceFragmentShadingRatesKHR, - thunk64_vkGetPhysicalDeviceImageFormatProperties, - thunk64_vkGetPhysicalDeviceImageFormatProperties2, - thunk64_vkGetPhysicalDeviceImageFormatProperties2KHR, - thunk64_vkGetPhysicalDeviceMemoryProperties, - thunk64_vkGetPhysicalDeviceMemoryProperties2, - thunk64_vkGetPhysicalDeviceMemoryProperties2KHR, - thunk64_vkGetPhysicalDeviceMultisamplePropertiesEXT, - thunk64_vkGetPhysicalDeviceOpticalFlowImageFormatsNV, - thunk64_vkGetPhysicalDevicePresentRectanglesKHR, - thunk64_vkGetPhysicalDeviceProperties, - thunk64_vkGetPhysicalDeviceProperties2, - thunk64_vkGetPhysicalDeviceProperties2KHR, - thunk64_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR, - thunk64_vkGetPhysicalDeviceQueueFamilyProperties, - thunk64_vkGetPhysicalDeviceQueueFamilyProperties2, - thunk64_vkGetPhysicalDeviceQueueFamilyProperties2KHR, - thunk64_vkGetPhysicalDeviceSparseImageFormatProperties, - thunk64_vkGetPhysicalDeviceSparseImageFormatProperties2, - thunk64_vkGetPhysicalDeviceSparseImageFormatProperties2KHR, - thunk64_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV, - thunk64_vkGetPhysicalDeviceSurfaceCapabilities2KHR, - thunk64_vkGetPhysicalDeviceSurfaceCapabilitiesKHR, - thunk64_vkGetPhysicalDeviceSurfaceFormats2KHR, - thunk64_vkGetPhysicalDeviceSurfaceFormatsKHR, - thunk64_vkGetPhysicalDeviceSurfacePresentModesKHR, - thunk64_vkGetPhysicalDeviceSurfaceSupportKHR, - thunk64_vkGetPhysicalDeviceToolProperties, - thunk64_vkGetPhysicalDeviceToolPropertiesEXT, - thunk64_vkGetPhysicalDeviceWin32PresentationSupportKHR, - thunk64_vkGetPipelineCacheData, - thunk64_vkGetPipelineExecutableInternalRepresentationsKHR, - thunk64_vkGetPipelineExecutablePropertiesKHR, - thunk64_vkGetPipelineExecutableStatisticsKHR, - thunk64_vkGetPipelinePropertiesEXT, - thunk64_vkGetPrivateData, - thunk64_vkGetPrivateDataEXT, - thunk64_vkGetQueryPoolResults, - thunk64_vkGetQueueCheckpointData2NV, - thunk64_vkGetQueueCheckpointDataNV, - thunk64_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR, - thunk64_vkGetRayTracingShaderGroupHandlesKHR, - thunk64_vkGetRayTracingShaderGroupHandlesNV, - thunk64_vkGetRayTracingShaderGroupStackSizeKHR, - thunk64_vkGetRenderAreaGranularity, - thunk64_vkGetSamplerOpaqueCaptureDescriptorDataEXT, - thunk64_vkGetSemaphoreCounterValue, - thunk64_vkGetSemaphoreCounterValueKHR, - thunk64_vkGetShaderInfoAMD, - thunk64_vkGetShaderModuleCreateInfoIdentifierEXT, - thunk64_vkGetShaderModuleIdentifierEXT, - thunk64_vkGetSwapchainImagesKHR, - thunk64_vkGetValidationCacheDataEXT, - thunk64_vkInitializePerformanceApiINTEL, - thunk64_vkInvalidateMappedMemoryRanges, - thunk64_vkMapMemory, - thunk64_vkMergePipelineCaches, - thunk64_vkMergeValidationCachesEXT, - thunk64_vkQueueBeginDebugUtilsLabelEXT, - thunk64_vkQueueBindSparse, - thunk64_vkQueueEndDebugUtilsLabelEXT, - thunk64_vkQueueInsertDebugUtilsLabelEXT, - thunk64_vkQueuePresentKHR, - thunk64_vkQueueSetPerformanceConfigurationINTEL, - thunk64_vkQueueSubmit, - thunk64_vkQueueSubmit2, - thunk64_vkQueueSubmit2KHR, - thunk64_vkQueueWaitIdle, - thunk64_vkReleasePerformanceConfigurationINTEL, - thunk64_vkReleaseProfilingLockKHR, - thunk64_vkReleaseSwapchainImagesEXT, - thunk64_vkResetCommandBuffer, - thunk64_vkResetCommandPool, - thunk64_vkResetDescriptorPool, - thunk64_vkResetEvent, - thunk64_vkResetFences, - thunk64_vkResetQueryPool, - thunk64_vkResetQueryPoolEXT, - thunk64_vkSetDebugUtilsObjectNameEXT, - thunk64_vkSetDebugUtilsObjectTagEXT, - thunk64_vkSetDeviceMemoryPriorityEXT, - thunk64_vkSetEvent, - thunk64_vkSetPrivateData, - thunk64_vkSetPrivateDataEXT, - thunk64_vkSignalSemaphore, - thunk64_vkSignalSemaphoreKHR, - thunk64_vkSubmitDebugUtilsMessageEXT, - thunk64_vkTrimCommandPool, - thunk64_vkTrimCommandPoolKHR, - thunk64_vkUninitializePerformanceApiINTEL, - thunk64_vkUnmapMemory, - (void *)thunk64_vkUpdateDescriptorSetWithTemplate, - thunk64_vkUpdateDescriptorSetWithTemplateKHR, - (void *)thunk64_vkUpdateDescriptorSets, - thunk64_vkWaitForFences, - thunk64_vkWaitForPresentKHR, - thunk64_vkWaitSemaphores, - thunk64_vkWaitSemaphoresKHR, - thunk64_vkWriteAccelerationStructuresPropertiesKHR, - thunk64_vkWriteMicromapsPropertiesEXT, -}; -C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == unix_count); - -#endif /* _WIN64 */ - -#ifdef _WIN64 -const unixlib_entry_t __wine_unix_call_wow64_funcs[] = -#else -const unixlib_entry_t __wine_unix_call_funcs[] = -#endif -{ - init_vulkan, - vk_is_available_instance_function32, - vk_is_available_device_function32, - thunk32_vkAcquireNextImage2KHR, - thunk32_vkAcquireNextImageKHR, - thunk32_vkAcquirePerformanceConfigurationINTEL, - thunk32_vkAcquireProfilingLockKHR, - thunk32_vkAllocateCommandBuffers, - thunk32_vkAllocateDescriptorSets, - thunk32_vkAllocateMemory, - thunk32_vkBeginCommandBuffer, - thunk32_vkBindAccelerationStructureMemoryNV, - thunk32_vkBindBufferMemory, - thunk32_vkBindBufferMemory2, - thunk32_vkBindBufferMemory2KHR, - thunk32_vkBindImageMemory, - thunk32_vkBindImageMemory2, - thunk32_vkBindImageMemory2KHR, - thunk32_vkBindOpticalFlowSessionImageNV, - thunk32_vkBuildAccelerationStructuresKHR, - thunk32_vkBuildMicromapsEXT, - (void *)thunk32_vkCmdBeginConditionalRenderingEXT, - (void *)thunk32_vkCmdBeginDebugUtilsLabelEXT, - (void *)thunk32_vkCmdBeginQuery, - (void *)thunk32_vkCmdBeginQueryIndexedEXT, - (void *)thunk32_vkCmdBeginRenderPass, - (void *)thunk32_vkCmdBeginRenderPass2, - (void *)thunk32_vkCmdBeginRenderPass2KHR, - (void *)thunk32_vkCmdBeginRendering, - (void *)thunk32_vkCmdBeginRenderingKHR, - (void *)thunk32_vkCmdBeginTransformFeedbackEXT, - (void *)thunk32_vkCmdBindDescriptorBufferEmbeddedSamplersEXT, - (void *)thunk32_vkCmdBindDescriptorBuffersEXT, - (void *)thunk32_vkCmdBindDescriptorSets, - (void *)thunk32_vkCmdBindIndexBuffer, - (void *)thunk32_vkCmdBindInvocationMaskHUAWEI, - (void *)thunk32_vkCmdBindPipeline, - (void *)thunk32_vkCmdBindPipelineShaderGroupNV, - (void *)thunk32_vkCmdBindShadingRateImageNV, - (void *)thunk32_vkCmdBindTransformFeedbackBuffersEXT, - (void *)thunk32_vkCmdBindVertexBuffers, - (void *)thunk32_vkCmdBindVertexBuffers2, - (void *)thunk32_vkCmdBindVertexBuffers2EXT, - (void *)thunk32_vkCmdBlitImage, - (void *)thunk32_vkCmdBlitImage2, - (void *)thunk32_vkCmdBlitImage2KHR, - (void *)thunk32_vkCmdBuildAccelerationStructureNV, - (void *)thunk32_vkCmdBuildAccelerationStructuresIndirectKHR, - (void *)thunk32_vkCmdBuildAccelerationStructuresKHR, - (void *)thunk32_vkCmdBuildMicromapsEXT, - (void *)thunk32_vkCmdClearAttachments, - (void *)thunk32_vkCmdClearColorImage, - (void *)thunk32_vkCmdClearDepthStencilImage, - (void *)thunk32_vkCmdCopyAccelerationStructureKHR, - (void *)thunk32_vkCmdCopyAccelerationStructureNV, - (void *)thunk32_vkCmdCopyAccelerationStructureToMemoryKHR, - (void *)thunk32_vkCmdCopyBuffer, - (void *)thunk32_vkCmdCopyBuffer2, - (void *)thunk32_vkCmdCopyBuffer2KHR, - (void *)thunk32_vkCmdCopyBufferToImage, - (void *)thunk32_vkCmdCopyBufferToImage2, - (void *)thunk32_vkCmdCopyBufferToImage2KHR, - (void *)thunk32_vkCmdCopyImage, - (void *)thunk32_vkCmdCopyImage2, - (void *)thunk32_vkCmdCopyImage2KHR, - (void *)thunk32_vkCmdCopyImageToBuffer, - (void *)thunk32_vkCmdCopyImageToBuffer2, - (void *)thunk32_vkCmdCopyImageToBuffer2KHR, - (void *)thunk32_vkCmdCopyMemoryIndirectNV, - (void *)thunk32_vkCmdCopyMemoryToAccelerationStructureKHR, - (void *)thunk32_vkCmdCopyMemoryToImageIndirectNV, - (void *)thunk32_vkCmdCopyMemoryToMicromapEXT, - (void *)thunk32_vkCmdCopyMicromapEXT, - (void *)thunk32_vkCmdCopyMicromapToMemoryEXT, - (void *)thunk32_vkCmdCopyQueryPoolResults, - (void *)thunk32_vkCmdCuLaunchKernelNVX, - (void *)thunk32_vkCmdDebugMarkerBeginEXT, - (void *)thunk32_vkCmdDebugMarkerEndEXT, - (void *)thunk32_vkCmdDebugMarkerInsertEXT, - (void *)thunk32_vkCmdDecompressMemoryIndirectCountNV, - (void *)thunk32_vkCmdDecompressMemoryNV, - (void *)thunk32_vkCmdDispatch, - (void *)thunk32_vkCmdDispatchBase, - (void *)thunk32_vkCmdDispatchBaseKHR, - (void *)thunk32_vkCmdDispatchIndirect, - (void *)thunk32_vkCmdDraw, - (void *)thunk32_vkCmdDrawIndexed, - (void *)thunk32_vkCmdDrawIndexedIndirect, - (void *)thunk32_vkCmdDrawIndexedIndirectCount, - (void *)thunk32_vkCmdDrawIndexedIndirectCountAMD, - (void *)thunk32_vkCmdDrawIndexedIndirectCountKHR, - (void *)thunk32_vkCmdDrawIndirect, - (void *)thunk32_vkCmdDrawIndirectByteCountEXT, - (void *)thunk32_vkCmdDrawIndirectCount, - (void *)thunk32_vkCmdDrawIndirectCountAMD, - (void *)thunk32_vkCmdDrawIndirectCountKHR, - (void *)thunk32_vkCmdDrawMeshTasksEXT, - (void *)thunk32_vkCmdDrawMeshTasksIndirectCountEXT, - (void *)thunk32_vkCmdDrawMeshTasksIndirectCountNV, - (void *)thunk32_vkCmdDrawMeshTasksIndirectEXT, - (void *)thunk32_vkCmdDrawMeshTasksIndirectNV, - (void *)thunk32_vkCmdDrawMeshTasksNV, - (void *)thunk32_vkCmdDrawMultiEXT, - (void *)thunk32_vkCmdDrawMultiIndexedEXT, - (void *)thunk32_vkCmdEndConditionalRenderingEXT, - (void *)thunk32_vkCmdEndDebugUtilsLabelEXT, - (void *)thunk32_vkCmdEndQuery, - (void *)thunk32_vkCmdEndQueryIndexedEXT, - (void *)thunk32_vkCmdEndRenderPass, - (void *)thunk32_vkCmdEndRenderPass2, - (void *)thunk32_vkCmdEndRenderPass2KHR, - (void *)thunk32_vkCmdEndRendering, - (void *)thunk32_vkCmdEndRenderingKHR, - (void *)thunk32_vkCmdEndTransformFeedbackEXT, - (void *)thunk32_vkCmdExecuteCommands, - (void *)thunk32_vkCmdExecuteGeneratedCommandsNV, - (void *)thunk32_vkCmdFillBuffer, - (void *)thunk32_vkCmdInsertDebugUtilsLabelEXT, - (void *)thunk32_vkCmdNextSubpass, - (void *)thunk32_vkCmdNextSubpass2, - (void *)thunk32_vkCmdNextSubpass2KHR, - (void *)thunk32_vkCmdOpticalFlowExecuteNV, - (void *)thunk32_vkCmdPipelineBarrier, - (void *)thunk32_vkCmdPipelineBarrier2, - (void *)thunk32_vkCmdPipelineBarrier2KHR, - (void *)thunk32_vkCmdPreprocessGeneratedCommandsNV, - (void *)thunk32_vkCmdPushConstants, - (void *)thunk32_vkCmdPushDescriptorSetKHR, - (void *)thunk32_vkCmdPushDescriptorSetWithTemplateKHR, - (void *)thunk32_vkCmdResetEvent, - (void *)thunk32_vkCmdResetEvent2, - (void *)thunk32_vkCmdResetEvent2KHR, - (void *)thunk32_vkCmdResetQueryPool, - (void *)thunk32_vkCmdResolveImage, - (void *)thunk32_vkCmdResolveImage2, - (void *)thunk32_vkCmdResolveImage2KHR, - (void *)thunk32_vkCmdSetAlphaToCoverageEnableEXT, - (void *)thunk32_vkCmdSetAlphaToOneEnableEXT, - (void *)thunk32_vkCmdSetBlendConstants, - (void *)thunk32_vkCmdSetCheckpointNV, - (void *)thunk32_vkCmdSetCoarseSampleOrderNV, - (void *)thunk32_vkCmdSetColorBlendAdvancedEXT, - (void *)thunk32_vkCmdSetColorBlendEnableEXT, - (void *)thunk32_vkCmdSetColorBlendEquationEXT, - (void *)thunk32_vkCmdSetColorWriteEnableEXT, - (void *)thunk32_vkCmdSetColorWriteMaskEXT, - (void *)thunk32_vkCmdSetConservativeRasterizationModeEXT, - (void *)thunk32_vkCmdSetCoverageModulationModeNV, - (void *)thunk32_vkCmdSetCoverageModulationTableEnableNV, - (void *)thunk32_vkCmdSetCoverageModulationTableNV, - (void *)thunk32_vkCmdSetCoverageReductionModeNV, - (void *)thunk32_vkCmdSetCoverageToColorEnableNV, - (void *)thunk32_vkCmdSetCoverageToColorLocationNV, - (void *)thunk32_vkCmdSetCullMode, - (void *)thunk32_vkCmdSetCullModeEXT, - (void *)thunk32_vkCmdSetDepthBias, - (void *)thunk32_vkCmdSetDepthBiasEnable, - (void *)thunk32_vkCmdSetDepthBiasEnableEXT, - (void *)thunk32_vkCmdSetDepthBounds, - (void *)thunk32_vkCmdSetDepthBoundsTestEnable, - (void *)thunk32_vkCmdSetDepthBoundsTestEnableEXT, - (void *)thunk32_vkCmdSetDepthClampEnableEXT, - (void *)thunk32_vkCmdSetDepthClipEnableEXT, - (void *)thunk32_vkCmdSetDepthClipNegativeOneToOneEXT, - (void *)thunk32_vkCmdSetDepthCompareOp, - (void *)thunk32_vkCmdSetDepthCompareOpEXT, - (void *)thunk32_vkCmdSetDepthTestEnable, - (void *)thunk32_vkCmdSetDepthTestEnableEXT, - (void *)thunk32_vkCmdSetDepthWriteEnable, - (void *)thunk32_vkCmdSetDepthWriteEnableEXT, - (void *)thunk32_vkCmdSetDescriptorBufferOffsetsEXT, - (void *)thunk32_vkCmdSetDeviceMask, - (void *)thunk32_vkCmdSetDeviceMaskKHR, - (void *)thunk32_vkCmdSetDiscardRectangleEXT, - (void *)thunk32_vkCmdSetEvent, - (void *)thunk32_vkCmdSetEvent2, - (void *)thunk32_vkCmdSetEvent2KHR, - (void *)thunk32_vkCmdSetExclusiveScissorNV, - (void *)thunk32_vkCmdSetExtraPrimitiveOverestimationSizeEXT, - (void *)thunk32_vkCmdSetFragmentShadingRateEnumNV, - (void *)thunk32_vkCmdSetFragmentShadingRateKHR, - (void *)thunk32_vkCmdSetFrontFace, - (void *)thunk32_vkCmdSetFrontFaceEXT, - (void *)thunk32_vkCmdSetLineRasterizationModeEXT, - (void *)thunk32_vkCmdSetLineStippleEXT, - (void *)thunk32_vkCmdSetLineStippleEnableEXT, - (void *)thunk32_vkCmdSetLineWidth, - (void *)thunk32_vkCmdSetLogicOpEXT, - (void *)thunk32_vkCmdSetLogicOpEnableEXT, - (void *)thunk32_vkCmdSetPatchControlPointsEXT, - thunk32_vkCmdSetPerformanceMarkerINTEL, - thunk32_vkCmdSetPerformanceOverrideINTEL, - thunk32_vkCmdSetPerformanceStreamMarkerINTEL, - (void *)thunk32_vkCmdSetPolygonModeEXT, - (void *)thunk32_vkCmdSetPrimitiveRestartEnable, - (void *)thunk32_vkCmdSetPrimitiveRestartEnableEXT, - (void *)thunk32_vkCmdSetPrimitiveTopology, - (void *)thunk32_vkCmdSetPrimitiveTopologyEXT, - (void *)thunk32_vkCmdSetProvokingVertexModeEXT, - (void *)thunk32_vkCmdSetRasterizationSamplesEXT, - (void *)thunk32_vkCmdSetRasterizationStreamEXT, - (void *)thunk32_vkCmdSetRasterizerDiscardEnable, - (void *)thunk32_vkCmdSetRasterizerDiscardEnableEXT, - (void *)thunk32_vkCmdSetRayTracingPipelineStackSizeKHR, - (void *)thunk32_vkCmdSetRepresentativeFragmentTestEnableNV, - (void *)thunk32_vkCmdSetSampleLocationsEXT, - (void *)thunk32_vkCmdSetSampleLocationsEnableEXT, - (void *)thunk32_vkCmdSetSampleMaskEXT, - (void *)thunk32_vkCmdSetScissor, - (void *)thunk32_vkCmdSetScissorWithCount, - (void *)thunk32_vkCmdSetScissorWithCountEXT, - (void *)thunk32_vkCmdSetShadingRateImageEnableNV, - (void *)thunk32_vkCmdSetStencilCompareMask, - (void *)thunk32_vkCmdSetStencilOp, - (void *)thunk32_vkCmdSetStencilOpEXT, - (void *)thunk32_vkCmdSetStencilReference, - (void *)thunk32_vkCmdSetStencilTestEnable, - (void *)thunk32_vkCmdSetStencilTestEnableEXT, - (void *)thunk32_vkCmdSetStencilWriteMask, - (void *)thunk32_vkCmdSetTessellationDomainOriginEXT, - (void *)thunk32_vkCmdSetVertexInputEXT, - (void *)thunk32_vkCmdSetViewport, - (void *)thunk32_vkCmdSetViewportShadingRatePaletteNV, - (void *)thunk32_vkCmdSetViewportSwizzleNV, - (void *)thunk32_vkCmdSetViewportWScalingEnableNV, - (void *)thunk32_vkCmdSetViewportWScalingNV, - (void *)thunk32_vkCmdSetViewportWithCount, - (void *)thunk32_vkCmdSetViewportWithCountEXT, - (void *)thunk32_vkCmdSubpassShadingHUAWEI, - (void *)thunk32_vkCmdTraceRaysIndirect2KHR, - (void *)thunk32_vkCmdTraceRaysIndirectKHR, - (void *)thunk32_vkCmdTraceRaysKHR, - (void *)thunk32_vkCmdTraceRaysNV, - (void *)thunk32_vkCmdUpdateBuffer, - (void *)thunk32_vkCmdWaitEvents, - (void *)thunk32_vkCmdWaitEvents2, - (void *)thunk32_vkCmdWaitEvents2KHR, - (void *)thunk32_vkCmdWriteAccelerationStructuresPropertiesKHR, - (void *)thunk32_vkCmdWriteAccelerationStructuresPropertiesNV, - (void *)thunk32_vkCmdWriteBufferMarker2AMD, - (void *)thunk32_vkCmdWriteBufferMarkerAMD, - (void *)thunk32_vkCmdWriteMicromapsPropertiesEXT, - (void *)thunk32_vkCmdWriteTimestamp, - (void *)thunk32_vkCmdWriteTimestamp2, - (void *)thunk32_vkCmdWriteTimestamp2KHR, - thunk32_vkCompileDeferredNV, - thunk32_vkCopyAccelerationStructureKHR, - thunk32_vkCopyAccelerationStructureToMemoryKHR, - thunk32_vkCopyMemoryToAccelerationStructureKHR, - thunk32_vkCopyMemoryToMicromapEXT, - thunk32_vkCopyMicromapEXT, - thunk32_vkCopyMicromapToMemoryEXT, - thunk32_vkCreateAccelerationStructureKHR, - thunk32_vkCreateAccelerationStructureNV, - thunk32_vkCreateBuffer, - thunk32_vkCreateBufferView, - thunk32_vkCreateCommandPool, - thunk32_vkCreateComputePipelines, - thunk32_vkCreateCuFunctionNVX, - thunk32_vkCreateCuModuleNVX, - thunk32_vkCreateDebugReportCallbackEXT, - thunk32_vkCreateDebugUtilsMessengerEXT, - thunk32_vkCreateDeferredOperationKHR, - thunk32_vkCreateDescriptorPool, - thunk32_vkCreateDescriptorSetLayout, - thunk32_vkCreateDescriptorUpdateTemplate, - thunk32_vkCreateDescriptorUpdateTemplateKHR, - thunk32_vkCreateDevice, - thunk32_vkCreateEvent, - thunk32_vkCreateFence, - thunk32_vkCreateFramebuffer, - thunk32_vkCreateGraphicsPipelines, - thunk32_vkCreateImage, - thunk32_vkCreateImageView, - thunk32_vkCreateIndirectCommandsLayoutNV, - thunk32_vkCreateInstance, - thunk32_vkCreateMicromapEXT, - thunk32_vkCreateOpticalFlowSessionNV, - thunk32_vkCreatePipelineCache, - thunk32_vkCreatePipelineLayout, - thunk32_vkCreatePrivateDataSlot, - thunk32_vkCreatePrivateDataSlotEXT, - thunk32_vkCreateQueryPool, - thunk32_vkCreateRayTracingPipelinesKHR, - thunk32_vkCreateRayTracingPipelinesNV, - thunk32_vkCreateRenderPass, - thunk32_vkCreateRenderPass2, - thunk32_vkCreateRenderPass2KHR, - thunk32_vkCreateSampler, - thunk32_vkCreateSamplerYcbcrConversion, - thunk32_vkCreateSamplerYcbcrConversionKHR, - thunk32_vkCreateSemaphore, - thunk32_vkCreateShaderModule, - thunk32_vkCreateSwapchainKHR, - thunk32_vkCreateValidationCacheEXT, - thunk32_vkCreateWin32SurfaceKHR, - thunk32_vkDebugMarkerSetObjectNameEXT, - thunk32_vkDebugMarkerSetObjectTagEXT, - thunk32_vkDebugReportMessageEXT, - thunk32_vkDeferredOperationJoinKHR, - thunk32_vkDestroyAccelerationStructureKHR, - thunk32_vkDestroyAccelerationStructureNV, - thunk32_vkDestroyBuffer, - thunk32_vkDestroyBufferView, - thunk32_vkDestroyCommandPool, - thunk32_vkDestroyCuFunctionNVX, - thunk32_vkDestroyCuModuleNVX, - thunk32_vkDestroyDebugReportCallbackEXT, - thunk32_vkDestroyDebugUtilsMessengerEXT, - thunk32_vkDestroyDeferredOperationKHR, - thunk32_vkDestroyDescriptorPool, - thunk32_vkDestroyDescriptorSetLayout, - thunk32_vkDestroyDescriptorUpdateTemplate, - thunk32_vkDestroyDescriptorUpdateTemplateKHR, - thunk32_vkDestroyDevice, - thunk32_vkDestroyEvent, - thunk32_vkDestroyFence, - thunk32_vkDestroyFramebuffer, - thunk32_vkDestroyImage, - thunk32_vkDestroyImageView, - thunk32_vkDestroyIndirectCommandsLayoutNV, - thunk32_vkDestroyInstance, - thunk32_vkDestroyMicromapEXT, - thunk32_vkDestroyOpticalFlowSessionNV, - thunk32_vkDestroyPipeline, - thunk32_vkDestroyPipelineCache, - thunk32_vkDestroyPipelineLayout, - thunk32_vkDestroyPrivateDataSlot, - thunk32_vkDestroyPrivateDataSlotEXT, - thunk32_vkDestroyQueryPool, - thunk32_vkDestroyRenderPass, - thunk32_vkDestroySampler, - thunk32_vkDestroySamplerYcbcrConversion, - thunk32_vkDestroySamplerYcbcrConversionKHR, - thunk32_vkDestroySemaphore, - thunk32_vkDestroyShaderModule, - thunk32_vkDestroySurfaceKHR, - thunk32_vkDestroySwapchainKHR, - thunk32_vkDestroyValidationCacheEXT, - thunk32_vkDeviceWaitIdle, - thunk32_vkEndCommandBuffer, - thunk32_vkEnumerateDeviceExtensionProperties, - thunk32_vkEnumerateDeviceLayerProperties, - thunk32_vkEnumerateInstanceExtensionProperties, - thunk32_vkEnumerateInstanceVersion, - thunk32_vkEnumeratePhysicalDeviceGroups, - thunk32_vkEnumeratePhysicalDeviceGroupsKHR, - thunk32_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR, - thunk32_vkEnumeratePhysicalDevices, - thunk32_vkFlushMappedMemoryRanges, - thunk32_vkFreeCommandBuffers, - thunk32_vkFreeDescriptorSets, - thunk32_vkFreeMemory, - thunk32_vkGetAccelerationStructureBuildSizesKHR, - thunk32_vkGetAccelerationStructureDeviceAddressKHR, - thunk32_vkGetAccelerationStructureHandleNV, - thunk32_vkGetAccelerationStructureMemoryRequirementsNV, - thunk32_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT, - thunk32_vkGetBufferDeviceAddress, - thunk32_vkGetBufferDeviceAddressEXT, - thunk32_vkGetBufferDeviceAddressKHR, - thunk32_vkGetBufferMemoryRequirements, - thunk32_vkGetBufferMemoryRequirements2, - thunk32_vkGetBufferMemoryRequirements2KHR, - thunk32_vkGetBufferOpaqueCaptureAddress, - thunk32_vkGetBufferOpaqueCaptureAddressKHR, - thunk32_vkGetBufferOpaqueCaptureDescriptorDataEXT, - thunk32_vkGetCalibratedTimestampsEXT, - thunk32_vkGetDeferredOperationMaxConcurrencyKHR, - thunk32_vkGetDeferredOperationResultKHR, - (void *)thunk32_vkGetDescriptorEXT, - thunk32_vkGetDescriptorSetHostMappingVALVE, - thunk32_vkGetDescriptorSetLayoutBindingOffsetEXT, - thunk32_vkGetDescriptorSetLayoutHostMappingInfoVALVE, - thunk32_vkGetDescriptorSetLayoutSizeEXT, - thunk32_vkGetDescriptorSetLayoutSupport, - thunk32_vkGetDescriptorSetLayoutSupportKHR, - thunk32_vkGetDeviceAccelerationStructureCompatibilityKHR, - thunk32_vkGetDeviceBufferMemoryRequirements, - thunk32_vkGetDeviceBufferMemoryRequirementsKHR, - thunk32_vkGetDeviceFaultInfoEXT, - thunk32_vkGetDeviceGroupPeerMemoryFeatures, - thunk32_vkGetDeviceGroupPeerMemoryFeaturesKHR, - thunk32_vkGetDeviceGroupPresentCapabilitiesKHR, - thunk32_vkGetDeviceGroupSurfacePresentModesKHR, - thunk32_vkGetDeviceImageMemoryRequirements, - thunk32_vkGetDeviceImageMemoryRequirementsKHR, - thunk32_vkGetDeviceImageSparseMemoryRequirements, - thunk32_vkGetDeviceImageSparseMemoryRequirementsKHR, - thunk32_vkGetDeviceMemoryCommitment, - thunk32_vkGetDeviceMemoryOpaqueCaptureAddress, - thunk32_vkGetDeviceMemoryOpaqueCaptureAddressKHR, - thunk32_vkGetDeviceMicromapCompatibilityEXT, - thunk32_vkGetDeviceQueue, - thunk32_vkGetDeviceQueue2, - thunk32_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI, - thunk32_vkGetDynamicRenderingTilePropertiesQCOM, - thunk32_vkGetEventStatus, - thunk32_vkGetFenceStatus, - thunk32_vkGetFramebufferTilePropertiesQCOM, - thunk32_vkGetGeneratedCommandsMemoryRequirementsNV, - thunk32_vkGetImageMemoryRequirements, - thunk32_vkGetImageMemoryRequirements2, - thunk32_vkGetImageMemoryRequirements2KHR, - thunk32_vkGetImageOpaqueCaptureDescriptorDataEXT, - thunk32_vkGetImageSparseMemoryRequirements, - thunk32_vkGetImageSparseMemoryRequirements2, - thunk32_vkGetImageSparseMemoryRequirements2KHR, - thunk32_vkGetImageSubresourceLayout, - thunk32_vkGetImageSubresourceLayout2EXT, - thunk32_vkGetImageViewAddressNVX, - thunk32_vkGetImageViewHandleNVX, - thunk32_vkGetImageViewOpaqueCaptureDescriptorDataEXT, - thunk32_vkGetMemoryHostPointerPropertiesEXT, - thunk32_vkGetMicromapBuildSizesEXT, - thunk32_vkGetPerformanceParameterINTEL, - thunk32_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, - thunk32_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV, - thunk32_vkGetPhysicalDeviceExternalBufferProperties, - thunk32_vkGetPhysicalDeviceExternalBufferPropertiesKHR, - thunk32_vkGetPhysicalDeviceExternalFenceProperties, - thunk32_vkGetPhysicalDeviceExternalFencePropertiesKHR, - thunk32_vkGetPhysicalDeviceExternalSemaphoreProperties, - thunk32_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR, - thunk32_vkGetPhysicalDeviceFeatures, - thunk32_vkGetPhysicalDeviceFeatures2, - thunk32_vkGetPhysicalDeviceFeatures2KHR, - thunk32_vkGetPhysicalDeviceFormatProperties, - thunk32_vkGetPhysicalDeviceFormatProperties2, - thunk32_vkGetPhysicalDeviceFormatProperties2KHR, - thunk32_vkGetPhysicalDeviceFragmentShadingRatesKHR, - thunk32_vkGetPhysicalDeviceImageFormatProperties, - thunk32_vkGetPhysicalDeviceImageFormatProperties2, - thunk32_vkGetPhysicalDeviceImageFormatProperties2KHR, - thunk32_vkGetPhysicalDeviceMemoryProperties, - thunk32_vkGetPhysicalDeviceMemoryProperties2, - thunk32_vkGetPhysicalDeviceMemoryProperties2KHR, - thunk32_vkGetPhysicalDeviceMultisamplePropertiesEXT, - thunk32_vkGetPhysicalDeviceOpticalFlowImageFormatsNV, - thunk32_vkGetPhysicalDevicePresentRectanglesKHR, - thunk32_vkGetPhysicalDeviceProperties, - thunk32_vkGetPhysicalDeviceProperties2, - thunk32_vkGetPhysicalDeviceProperties2KHR, - thunk32_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR, - thunk32_vkGetPhysicalDeviceQueueFamilyProperties, - thunk32_vkGetPhysicalDeviceQueueFamilyProperties2, - thunk32_vkGetPhysicalDeviceQueueFamilyProperties2KHR, - thunk32_vkGetPhysicalDeviceSparseImageFormatProperties, - thunk32_vkGetPhysicalDeviceSparseImageFormatProperties2, - thunk32_vkGetPhysicalDeviceSparseImageFormatProperties2KHR, - thunk32_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV, - thunk32_vkGetPhysicalDeviceSurfaceCapabilities2KHR, - thunk32_vkGetPhysicalDeviceSurfaceCapabilitiesKHR, - thunk32_vkGetPhysicalDeviceSurfaceFormats2KHR, - thunk32_vkGetPhysicalDeviceSurfaceFormatsKHR, - thunk32_vkGetPhysicalDeviceSurfacePresentModesKHR, - thunk32_vkGetPhysicalDeviceSurfaceSupportKHR, - thunk32_vkGetPhysicalDeviceToolProperties, - thunk32_vkGetPhysicalDeviceToolPropertiesEXT, - thunk32_vkGetPhysicalDeviceWin32PresentationSupportKHR, - thunk32_vkGetPipelineCacheData, - thunk32_vkGetPipelineExecutableInternalRepresentationsKHR, - thunk32_vkGetPipelineExecutablePropertiesKHR, - thunk32_vkGetPipelineExecutableStatisticsKHR, - thunk32_vkGetPipelinePropertiesEXT, - thunk32_vkGetPrivateData, - thunk32_vkGetPrivateDataEXT, - thunk32_vkGetQueryPoolResults, - thunk32_vkGetQueueCheckpointData2NV, - thunk32_vkGetQueueCheckpointDataNV, - thunk32_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR, - thunk32_vkGetRayTracingShaderGroupHandlesKHR, - thunk32_vkGetRayTracingShaderGroupHandlesNV, - thunk32_vkGetRayTracingShaderGroupStackSizeKHR, - thunk32_vkGetRenderAreaGranularity, - thunk32_vkGetSamplerOpaqueCaptureDescriptorDataEXT, - thunk32_vkGetSemaphoreCounterValue, - thunk32_vkGetSemaphoreCounterValueKHR, - thunk32_vkGetShaderInfoAMD, - thunk32_vkGetShaderModuleCreateInfoIdentifierEXT, - thunk32_vkGetShaderModuleIdentifierEXT, - thunk32_vkGetSwapchainImagesKHR, - thunk32_vkGetValidationCacheDataEXT, - thunk32_vkInitializePerformanceApiINTEL, - thunk32_vkInvalidateMappedMemoryRanges, - thunk32_vkMapMemory, - thunk32_vkMergePipelineCaches, - thunk32_vkMergeValidationCachesEXT, - thunk32_vkQueueBeginDebugUtilsLabelEXT, - thunk32_vkQueueBindSparse, - thunk32_vkQueueEndDebugUtilsLabelEXT, - thunk32_vkQueueInsertDebugUtilsLabelEXT, - thunk32_vkQueuePresentKHR, - thunk32_vkQueueSetPerformanceConfigurationINTEL, - thunk32_vkQueueSubmit, - thunk32_vkQueueSubmit2, - thunk32_vkQueueSubmit2KHR, - thunk32_vkQueueWaitIdle, - thunk32_vkReleasePerformanceConfigurationINTEL, - thunk32_vkReleaseProfilingLockKHR, - thunk32_vkReleaseSwapchainImagesEXT, - thunk32_vkResetCommandBuffer, - thunk32_vkResetCommandPool, - thunk32_vkResetDescriptorPool, - thunk32_vkResetEvent, - thunk32_vkResetFences, - thunk32_vkResetQueryPool, - thunk32_vkResetQueryPoolEXT, - thunk32_vkSetDebugUtilsObjectNameEXT, - thunk32_vkSetDebugUtilsObjectTagEXT, - thunk32_vkSetDeviceMemoryPriorityEXT, - thunk32_vkSetEvent, - thunk32_vkSetPrivateData, - thunk32_vkSetPrivateDataEXT, - thunk32_vkSignalSemaphore, - thunk32_vkSignalSemaphoreKHR, - thunk32_vkSubmitDebugUtilsMessageEXT, - thunk32_vkTrimCommandPool, - thunk32_vkTrimCommandPoolKHR, - thunk32_vkUninitializePerformanceApiINTEL, - thunk32_vkUnmapMemory, - (void *)thunk32_vkUpdateDescriptorSetWithTemplate, - thunk32_vkUpdateDescriptorSetWithTemplateKHR, - (void *)thunk32_vkUpdateDescriptorSets, - thunk32_vkWaitForFences, - thunk32_vkWaitForPresentKHR, - thunk32_vkWaitSemaphores, - thunk32_vkWaitSemaphoresKHR, - thunk32_vkWriteAccelerationStructuresPropertiesKHR, - thunk32_vkWriteMicromapsPropertiesEXT, -}; -C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == unix_count); diff --git a/dlls/winevulkan/vulkan_thunks.h b/dlls/winevulkan/vulkan_thunks.h deleted file mode 100644 index b31cf348e1c..00000000000 --- a/dlls/winevulkan/vulkan_thunks.h +++ /dev/null @@ -1,1108 +0,0 @@ -/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! - * - * This file is generated from Vulkan vk.xml file covered - * by the following copyright and permission notice: - * - * Copyright 2015-2022 The Khronos Group Inc. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#ifndef __WINE_VULKAN_THUNKS_H -#define __WINE_VULKAN_THUNKS_H - -#define WINE_VK_VERSION VK_API_VERSION_1_3 - -/* Functions for which we have custom implementations outside of the thunks. */ -VkResult wine_vkAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo, VkCommandBuffer *pCommandBuffers) DECLSPEC_HIDDEN; -VkResult wine_vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo, const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory) DECLSPEC_HIDDEN; -VkResult wine_vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) DECLSPEC_HIDDEN; -VkResult wine_vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool, void *client_ptr) DECLSPEC_HIDDEN; -VkResult wine_vkCreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback) DECLSPEC_HIDDEN; -VkResult wine_vkCreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT *pMessenger) DECLSPEC_HIDDEN; -VkResult wine_vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDevice *pDevice, void *client_ptr) DECLSPEC_HIDDEN; -VkResult wine_vkCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImage *pImage) DECLSPEC_HIDDEN; -VkResult wine_vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance, void *client_ptr) DECLSPEC_HIDDEN; -VkResult wine_vkCreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface) DECLSPEC_HIDDEN; -void wine_vkDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator) DECLSPEC_HIDDEN; -void wine_vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks *pAllocator) DECLSPEC_HIDDEN; -void wine_vkDestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks *pAllocator) DECLSPEC_HIDDEN; -void wine_vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) DECLSPEC_HIDDEN; -void wine_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) DECLSPEC_HIDDEN; -void wine_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *pAllocator) DECLSPEC_HIDDEN; -VkResult wine_vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName, uint32_t *pPropertyCount, VkExtensionProperties *pProperties) DECLSPEC_HIDDEN; -VkResult wine_vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkLayerProperties *pProperties) DECLSPEC_HIDDEN; -VkResult wine_vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pPropertyCount, VkExtensionProperties *pProperties) DECLSPEC_HIDDEN; -VkResult wine_vkEnumerateInstanceVersion(uint32_t *pApiVersion) DECLSPEC_HIDDEN; -VkResult wine_vkEnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties) DECLSPEC_HIDDEN; -VkResult wine_vkEnumeratePhysicalDeviceGroupsKHR(VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties) DECLSPEC_HIDDEN; -VkResult wine_vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices) DECLSPEC_HIDDEN; -void wine_vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers) DECLSPEC_HIDDEN; -void wine_vkFreeMemory(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks *pAllocator) DECLSPEC_HIDDEN; -VkResult wine_vkGetCalibratedTimestampsEXT(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoEXT *pTimestampInfos, uint64_t *pTimestamps, uint64_t *pMaxDeviation) DECLSPEC_HIDDEN; -void wine_vkGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue) DECLSPEC_HIDDEN; -void wine_vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 *pQueueInfo, VkQueue *pQueue) DECLSPEC_HIDDEN; -VkResult wine_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(VkPhysicalDevice physicalDevice, uint32_t *pTimeDomainCount, VkTimeDomainEXT *pTimeDomains) DECLSPEC_HIDDEN; -void wine_vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, VkExternalBufferProperties *pExternalBufferProperties) DECLSPEC_HIDDEN; -void wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, VkExternalBufferProperties *pExternalBufferProperties) DECLSPEC_HIDDEN; -void wine_vkGetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo, VkExternalFenceProperties *pExternalFenceProperties) DECLSPEC_HIDDEN; -void wine_vkGetPhysicalDeviceExternalFencePropertiesKHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo, VkExternalFenceProperties *pExternalFenceProperties) DECLSPEC_HIDDEN; -void wine_vkGetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo, VkExternalSemaphoreProperties *pExternalSemaphoreProperties) DECLSPEC_HIDDEN; -void wine_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo, VkExternalSemaphoreProperties *pExternalSemaphoreProperties) DECLSPEC_HIDDEN; -VkResult wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties) DECLSPEC_HIDDEN; -VkResult wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties) DECLSPEC_HIDDEN; -VkResult wine_vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, VkSurfaceCapabilities2KHR *pSurfaceCapabilities) DECLSPEC_HIDDEN; -VkResult wine_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) DECLSPEC_HIDDEN; -VkResult wine_vkMapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void **ppData) DECLSPEC_HIDDEN; -void wine_vkUnmapMemory(VkDevice device, VkDeviceMemory memory) DECLSPEC_HIDDEN; - -/* For use by vkDevice and children */ -struct vulkan_device_funcs -{ - VkResult (*p_vkAcquireNextImage2KHR)(VkDevice, const VkAcquireNextImageInfoKHR *, uint32_t *); - VkResult (*p_vkAcquireNextImageKHR)(VkDevice, VkSwapchainKHR, uint64_t, VkSemaphore, VkFence, uint32_t *); - VkResult (*p_vkAcquirePerformanceConfigurationINTEL)(VkDevice, const VkPerformanceConfigurationAcquireInfoINTEL *, VkPerformanceConfigurationINTEL *); - VkResult (*p_vkAcquireProfilingLockKHR)(VkDevice, const VkAcquireProfilingLockInfoKHR *); - VkResult (*p_vkAllocateCommandBuffers)(VkDevice, const VkCommandBufferAllocateInfo *, VkCommandBuffer *); - VkResult (*p_vkAllocateDescriptorSets)(VkDevice, const VkDescriptorSetAllocateInfo *, VkDescriptorSet *); - VkResult (*p_vkAllocateMemory)(VkDevice, const VkMemoryAllocateInfo *, const VkAllocationCallbacks *, VkDeviceMemory *); - VkResult (*p_vkBeginCommandBuffer)(VkCommandBuffer, const VkCommandBufferBeginInfo *); - VkResult (*p_vkBindAccelerationStructureMemoryNV)(VkDevice, uint32_t, const VkBindAccelerationStructureMemoryInfoNV *); - VkResult (*p_vkBindBufferMemory)(VkDevice, VkBuffer, VkDeviceMemory, VkDeviceSize); - VkResult (*p_vkBindBufferMemory2)(VkDevice, uint32_t, const VkBindBufferMemoryInfo *); - VkResult (*p_vkBindBufferMemory2KHR)(VkDevice, uint32_t, const VkBindBufferMemoryInfo *); - VkResult (*p_vkBindImageMemory)(VkDevice, VkImage, VkDeviceMemory, VkDeviceSize); - VkResult (*p_vkBindImageMemory2)(VkDevice, uint32_t, const VkBindImageMemoryInfo *); - VkResult (*p_vkBindImageMemory2KHR)(VkDevice, uint32_t, const VkBindImageMemoryInfo *); - VkResult (*p_vkBindOpticalFlowSessionImageNV)(VkDevice, VkOpticalFlowSessionNV, VkOpticalFlowSessionBindingPointNV, VkImageView, VkImageLayout); - VkResult (*p_vkBuildAccelerationStructuresKHR)(VkDevice, VkDeferredOperationKHR, uint32_t, const VkAccelerationStructureBuildGeometryInfoKHR *, const VkAccelerationStructureBuildRangeInfoKHR * const*); - VkResult (*p_vkBuildMicromapsEXT)(VkDevice, VkDeferredOperationKHR, uint32_t, const VkMicromapBuildInfoEXT *); - void (*p_vkCmdBeginConditionalRenderingEXT)(VkCommandBuffer, const VkConditionalRenderingBeginInfoEXT *); - void (*p_vkCmdBeginDebugUtilsLabelEXT)(VkCommandBuffer, const VkDebugUtilsLabelEXT *); - void (*p_vkCmdBeginQuery)(VkCommandBuffer, VkQueryPool, uint32_t, VkQueryControlFlags); - void (*p_vkCmdBeginQueryIndexedEXT)(VkCommandBuffer, VkQueryPool, uint32_t, VkQueryControlFlags, uint32_t); - void (*p_vkCmdBeginRenderPass)(VkCommandBuffer, const VkRenderPassBeginInfo *, VkSubpassContents); - void (*p_vkCmdBeginRenderPass2)(VkCommandBuffer, const VkRenderPassBeginInfo *, const VkSubpassBeginInfo *); - void (*p_vkCmdBeginRenderPass2KHR)(VkCommandBuffer, const VkRenderPassBeginInfo *, const VkSubpassBeginInfo *); - void (*p_vkCmdBeginRendering)(VkCommandBuffer, const VkRenderingInfo *); - void (*p_vkCmdBeginRenderingKHR)(VkCommandBuffer, const VkRenderingInfo *); - void (*p_vkCmdBeginTransformFeedbackEXT)(VkCommandBuffer, uint32_t, uint32_t, const VkBuffer *, const VkDeviceSize *); - void (*p_vkCmdBindDescriptorBufferEmbeddedSamplersEXT)(VkCommandBuffer, VkPipelineBindPoint, VkPipelineLayout, uint32_t); - void (*p_vkCmdBindDescriptorBuffersEXT)(VkCommandBuffer, uint32_t, const VkDescriptorBufferBindingInfoEXT *); - void (*p_vkCmdBindDescriptorSets)(VkCommandBuffer, VkPipelineBindPoint, VkPipelineLayout, uint32_t, uint32_t, const VkDescriptorSet *, uint32_t, const uint32_t *); - void (*p_vkCmdBindIndexBuffer)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkIndexType); - void (*p_vkCmdBindInvocationMaskHUAWEI)(VkCommandBuffer, VkImageView, VkImageLayout); - void (*p_vkCmdBindPipeline)(VkCommandBuffer, VkPipelineBindPoint, VkPipeline); - void (*p_vkCmdBindPipelineShaderGroupNV)(VkCommandBuffer, VkPipelineBindPoint, VkPipeline, uint32_t); - void (*p_vkCmdBindShadingRateImageNV)(VkCommandBuffer, VkImageView, VkImageLayout); - void (*p_vkCmdBindTransformFeedbackBuffersEXT)(VkCommandBuffer, uint32_t, uint32_t, const VkBuffer *, const VkDeviceSize *, const VkDeviceSize *); - void (*p_vkCmdBindVertexBuffers)(VkCommandBuffer, uint32_t, uint32_t, const VkBuffer *, const VkDeviceSize *); - void (*p_vkCmdBindVertexBuffers2)(VkCommandBuffer, uint32_t, uint32_t, const VkBuffer *, const VkDeviceSize *, const VkDeviceSize *, const VkDeviceSize *); - void (*p_vkCmdBindVertexBuffers2EXT)(VkCommandBuffer, uint32_t, uint32_t, const VkBuffer *, const VkDeviceSize *, const VkDeviceSize *, const VkDeviceSize *); - void (*p_vkCmdBlitImage)(VkCommandBuffer, VkImage, VkImageLayout, VkImage, VkImageLayout, uint32_t, const VkImageBlit *, VkFilter); - void (*p_vkCmdBlitImage2)(VkCommandBuffer, const VkBlitImageInfo2 *); - void (*p_vkCmdBlitImage2KHR)(VkCommandBuffer, const VkBlitImageInfo2 *); - void (*p_vkCmdBuildAccelerationStructureNV)(VkCommandBuffer, const VkAccelerationStructureInfoNV *, VkBuffer, VkDeviceSize, VkBool32, VkAccelerationStructureNV, VkAccelerationStructureNV, VkBuffer, VkDeviceSize); - void (*p_vkCmdBuildAccelerationStructuresIndirectKHR)(VkCommandBuffer, uint32_t, const VkAccelerationStructureBuildGeometryInfoKHR *, const VkDeviceAddress *, const uint32_t *, const uint32_t * const*); - void (*p_vkCmdBuildAccelerationStructuresKHR)(VkCommandBuffer, uint32_t, const VkAccelerationStructureBuildGeometryInfoKHR *, const VkAccelerationStructureBuildRangeInfoKHR * const*); - void (*p_vkCmdBuildMicromapsEXT)(VkCommandBuffer, uint32_t, const VkMicromapBuildInfoEXT *); - void (*p_vkCmdClearAttachments)(VkCommandBuffer, uint32_t, const VkClearAttachment *, uint32_t, const VkClearRect *); - void (*p_vkCmdClearColorImage)(VkCommandBuffer, VkImage, VkImageLayout, const VkClearColorValue *, uint32_t, const VkImageSubresourceRange *); - void (*p_vkCmdClearDepthStencilImage)(VkCommandBuffer, VkImage, VkImageLayout, const VkClearDepthStencilValue *, uint32_t, const VkImageSubresourceRange *); - void (*p_vkCmdCopyAccelerationStructureKHR)(VkCommandBuffer, const VkCopyAccelerationStructureInfoKHR *); - void (*p_vkCmdCopyAccelerationStructureNV)(VkCommandBuffer, VkAccelerationStructureNV, VkAccelerationStructureNV, VkCopyAccelerationStructureModeKHR); - void (*p_vkCmdCopyAccelerationStructureToMemoryKHR)(VkCommandBuffer, const VkCopyAccelerationStructureToMemoryInfoKHR *); - void (*p_vkCmdCopyBuffer)(VkCommandBuffer, VkBuffer, VkBuffer, uint32_t, const VkBufferCopy *); - void (*p_vkCmdCopyBuffer2)(VkCommandBuffer, const VkCopyBufferInfo2 *); - void (*p_vkCmdCopyBuffer2KHR)(VkCommandBuffer, const VkCopyBufferInfo2 *); - void (*p_vkCmdCopyBufferToImage)(VkCommandBuffer, VkBuffer, VkImage, VkImageLayout, uint32_t, const VkBufferImageCopy *); - void (*p_vkCmdCopyBufferToImage2)(VkCommandBuffer, const VkCopyBufferToImageInfo2 *); - void (*p_vkCmdCopyBufferToImage2KHR)(VkCommandBuffer, const VkCopyBufferToImageInfo2 *); - void (*p_vkCmdCopyImage)(VkCommandBuffer, VkImage, VkImageLayout, VkImage, VkImageLayout, uint32_t, const VkImageCopy *); - void (*p_vkCmdCopyImage2)(VkCommandBuffer, const VkCopyImageInfo2 *); - void (*p_vkCmdCopyImage2KHR)(VkCommandBuffer, const VkCopyImageInfo2 *); - void (*p_vkCmdCopyImageToBuffer)(VkCommandBuffer, VkImage, VkImageLayout, VkBuffer, uint32_t, const VkBufferImageCopy *); - void (*p_vkCmdCopyImageToBuffer2)(VkCommandBuffer, const VkCopyImageToBufferInfo2 *); - void (*p_vkCmdCopyImageToBuffer2KHR)(VkCommandBuffer, const VkCopyImageToBufferInfo2 *); - void (*p_vkCmdCopyMemoryIndirectNV)(VkCommandBuffer, VkDeviceAddress, uint32_t, uint32_t); - void (*p_vkCmdCopyMemoryToAccelerationStructureKHR)(VkCommandBuffer, const VkCopyMemoryToAccelerationStructureInfoKHR *); - void (*p_vkCmdCopyMemoryToImageIndirectNV)(VkCommandBuffer, VkDeviceAddress, uint32_t, uint32_t, VkImage, VkImageLayout, const VkImageSubresourceLayers *); - void (*p_vkCmdCopyMemoryToMicromapEXT)(VkCommandBuffer, const VkCopyMemoryToMicromapInfoEXT *); - void (*p_vkCmdCopyMicromapEXT)(VkCommandBuffer, const VkCopyMicromapInfoEXT *); - void (*p_vkCmdCopyMicromapToMemoryEXT)(VkCommandBuffer, const VkCopyMicromapToMemoryInfoEXT *); - void (*p_vkCmdCopyQueryPoolResults)(VkCommandBuffer, VkQueryPool, uint32_t, uint32_t, VkBuffer, VkDeviceSize, VkDeviceSize, VkQueryResultFlags); - void (*p_vkCmdCuLaunchKernelNVX)(VkCommandBuffer, const VkCuLaunchInfoNVX *); - void (*p_vkCmdDebugMarkerBeginEXT)(VkCommandBuffer, const VkDebugMarkerMarkerInfoEXT *); - void (*p_vkCmdDebugMarkerEndEXT)(VkCommandBuffer); - void (*p_vkCmdDebugMarkerInsertEXT)(VkCommandBuffer, const VkDebugMarkerMarkerInfoEXT *); - void (*p_vkCmdDecompressMemoryIndirectCountNV)(VkCommandBuffer, VkDeviceAddress, VkDeviceAddress, uint32_t); - void (*p_vkCmdDecompressMemoryNV)(VkCommandBuffer, uint32_t, const VkDecompressMemoryRegionNV *); - void (*p_vkCmdDispatch)(VkCommandBuffer, uint32_t, uint32_t, uint32_t); - void (*p_vkCmdDispatchBase)(VkCommandBuffer, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); - void (*p_vkCmdDispatchBaseKHR)(VkCommandBuffer, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); - void (*p_vkCmdDispatchIndirect)(VkCommandBuffer, VkBuffer, VkDeviceSize); - void (*p_vkCmdDraw)(VkCommandBuffer, uint32_t, uint32_t, uint32_t, uint32_t); - void (*p_vkCmdDrawIndexed)(VkCommandBuffer, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); - void (*p_vkCmdDrawIndexedIndirect)(VkCommandBuffer, VkBuffer, VkDeviceSize, uint32_t, uint32_t); - void (*p_vkCmdDrawIndexedIndirectCount)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, uint32_t, uint32_t); - void (*p_vkCmdDrawIndexedIndirectCountAMD)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, uint32_t, uint32_t); - void (*p_vkCmdDrawIndexedIndirectCountKHR)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, uint32_t, uint32_t); - void (*p_vkCmdDrawIndirect)(VkCommandBuffer, VkBuffer, VkDeviceSize, uint32_t, uint32_t); - void (*p_vkCmdDrawIndirectByteCountEXT)(VkCommandBuffer, uint32_t, uint32_t, VkBuffer, VkDeviceSize, uint32_t, uint32_t); - void (*p_vkCmdDrawIndirectCount)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, uint32_t, uint32_t); - void (*p_vkCmdDrawIndirectCountAMD)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, uint32_t, uint32_t); - void (*p_vkCmdDrawIndirectCountKHR)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, uint32_t, uint32_t); - void (*p_vkCmdDrawMeshTasksEXT)(VkCommandBuffer, uint32_t, uint32_t, uint32_t); - void (*p_vkCmdDrawMeshTasksIndirectCountEXT)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, uint32_t, uint32_t); - void (*p_vkCmdDrawMeshTasksIndirectCountNV)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, uint32_t, uint32_t); - void (*p_vkCmdDrawMeshTasksIndirectEXT)(VkCommandBuffer, VkBuffer, VkDeviceSize, uint32_t, uint32_t); - void (*p_vkCmdDrawMeshTasksIndirectNV)(VkCommandBuffer, VkBuffer, VkDeviceSize, uint32_t, uint32_t); - void (*p_vkCmdDrawMeshTasksNV)(VkCommandBuffer, uint32_t, uint32_t); - void (*p_vkCmdDrawMultiEXT)(VkCommandBuffer, uint32_t, const VkMultiDrawInfoEXT *, uint32_t, uint32_t, uint32_t); - void (*p_vkCmdDrawMultiIndexedEXT)(VkCommandBuffer, uint32_t, const VkMultiDrawIndexedInfoEXT *, uint32_t, uint32_t, uint32_t, const int32_t *); - void (*p_vkCmdEndConditionalRenderingEXT)(VkCommandBuffer); - void (*p_vkCmdEndDebugUtilsLabelEXT)(VkCommandBuffer); - void (*p_vkCmdEndQuery)(VkCommandBuffer, VkQueryPool, uint32_t); - void (*p_vkCmdEndQueryIndexedEXT)(VkCommandBuffer, VkQueryPool, uint32_t, uint32_t); - void (*p_vkCmdEndRenderPass)(VkCommandBuffer); - void (*p_vkCmdEndRenderPass2)(VkCommandBuffer, const VkSubpassEndInfo *); - void (*p_vkCmdEndRenderPass2KHR)(VkCommandBuffer, const VkSubpassEndInfo *); - void (*p_vkCmdEndRendering)(VkCommandBuffer); - void (*p_vkCmdEndRenderingKHR)(VkCommandBuffer); - void (*p_vkCmdEndTransformFeedbackEXT)(VkCommandBuffer, uint32_t, uint32_t, const VkBuffer *, const VkDeviceSize *); - void (*p_vkCmdExecuteCommands)(VkCommandBuffer, uint32_t, const VkCommandBuffer *); - void (*p_vkCmdExecuteGeneratedCommandsNV)(VkCommandBuffer, VkBool32, const VkGeneratedCommandsInfoNV *); - void (*p_vkCmdFillBuffer)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkDeviceSize, uint32_t); - void (*p_vkCmdInsertDebugUtilsLabelEXT)(VkCommandBuffer, const VkDebugUtilsLabelEXT *); - void (*p_vkCmdNextSubpass)(VkCommandBuffer, VkSubpassContents); - void (*p_vkCmdNextSubpass2)(VkCommandBuffer, const VkSubpassBeginInfo *, const VkSubpassEndInfo *); - void (*p_vkCmdNextSubpass2KHR)(VkCommandBuffer, const VkSubpassBeginInfo *, const VkSubpassEndInfo *); - void (*p_vkCmdOpticalFlowExecuteNV)(VkCommandBuffer, VkOpticalFlowSessionNV, const VkOpticalFlowExecuteInfoNV *); - void (*p_vkCmdPipelineBarrier)(VkCommandBuffer, VkPipelineStageFlags, VkPipelineStageFlags, VkDependencyFlags, uint32_t, const VkMemoryBarrier *, uint32_t, const VkBufferMemoryBarrier *, uint32_t, const VkImageMemoryBarrier *); - void (*p_vkCmdPipelineBarrier2)(VkCommandBuffer, const VkDependencyInfo *); - void (*p_vkCmdPipelineBarrier2KHR)(VkCommandBuffer, const VkDependencyInfo *); - void (*p_vkCmdPreprocessGeneratedCommandsNV)(VkCommandBuffer, const VkGeneratedCommandsInfoNV *); - void (*p_vkCmdPushConstants)(VkCommandBuffer, VkPipelineLayout, VkShaderStageFlags, uint32_t, uint32_t, const void *); - void (*p_vkCmdPushDescriptorSetKHR)(VkCommandBuffer, VkPipelineBindPoint, VkPipelineLayout, uint32_t, uint32_t, const VkWriteDescriptorSet *); - void (*p_vkCmdPushDescriptorSetWithTemplateKHR)(VkCommandBuffer, VkDescriptorUpdateTemplate, VkPipelineLayout, uint32_t, const void *); - void (*p_vkCmdResetEvent)(VkCommandBuffer, VkEvent, VkPipelineStageFlags); - void (*p_vkCmdResetEvent2)(VkCommandBuffer, VkEvent, VkPipelineStageFlags2); - void (*p_vkCmdResetEvent2KHR)(VkCommandBuffer, VkEvent, VkPipelineStageFlags2); - void (*p_vkCmdResetQueryPool)(VkCommandBuffer, VkQueryPool, uint32_t, uint32_t); - void (*p_vkCmdResolveImage)(VkCommandBuffer, VkImage, VkImageLayout, VkImage, VkImageLayout, uint32_t, const VkImageResolve *); - void (*p_vkCmdResolveImage2)(VkCommandBuffer, const VkResolveImageInfo2 *); - void (*p_vkCmdResolveImage2KHR)(VkCommandBuffer, const VkResolveImageInfo2 *); - void (*p_vkCmdSetAlphaToCoverageEnableEXT)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetAlphaToOneEnableEXT)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetBlendConstants)(VkCommandBuffer, const float[4]); - void (*p_vkCmdSetCheckpointNV)(VkCommandBuffer, const void *); - void (*p_vkCmdSetCoarseSampleOrderNV)(VkCommandBuffer, VkCoarseSampleOrderTypeNV, uint32_t, const VkCoarseSampleOrderCustomNV *); - void (*p_vkCmdSetColorBlendAdvancedEXT)(VkCommandBuffer, uint32_t, uint32_t, const VkColorBlendAdvancedEXT *); - void (*p_vkCmdSetColorBlendEnableEXT)(VkCommandBuffer, uint32_t, uint32_t, const VkBool32 *); - void (*p_vkCmdSetColorBlendEquationEXT)(VkCommandBuffer, uint32_t, uint32_t, const VkColorBlendEquationEXT *); - void (*p_vkCmdSetColorWriteEnableEXT)(VkCommandBuffer, uint32_t, const VkBool32 *); - void (*p_vkCmdSetColorWriteMaskEXT)(VkCommandBuffer, uint32_t, uint32_t, const VkColorComponentFlags *); - void (*p_vkCmdSetConservativeRasterizationModeEXT)(VkCommandBuffer, VkConservativeRasterizationModeEXT); - void (*p_vkCmdSetCoverageModulationModeNV)(VkCommandBuffer, VkCoverageModulationModeNV); - void (*p_vkCmdSetCoverageModulationTableEnableNV)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetCoverageModulationTableNV)(VkCommandBuffer, uint32_t, const float *); - void (*p_vkCmdSetCoverageReductionModeNV)(VkCommandBuffer, VkCoverageReductionModeNV); - void (*p_vkCmdSetCoverageToColorEnableNV)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetCoverageToColorLocationNV)(VkCommandBuffer, uint32_t); - void (*p_vkCmdSetCullMode)(VkCommandBuffer, VkCullModeFlags); - void (*p_vkCmdSetCullModeEXT)(VkCommandBuffer, VkCullModeFlags); - void (*p_vkCmdSetDepthBias)(VkCommandBuffer, float, float, float); - void (*p_vkCmdSetDepthBiasEnable)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetDepthBiasEnableEXT)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetDepthBounds)(VkCommandBuffer, float, float); - void (*p_vkCmdSetDepthBoundsTestEnable)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetDepthBoundsTestEnableEXT)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetDepthClampEnableEXT)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetDepthClipEnableEXT)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetDepthClipNegativeOneToOneEXT)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetDepthCompareOp)(VkCommandBuffer, VkCompareOp); - void (*p_vkCmdSetDepthCompareOpEXT)(VkCommandBuffer, VkCompareOp); - void (*p_vkCmdSetDepthTestEnable)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetDepthTestEnableEXT)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetDepthWriteEnable)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetDepthWriteEnableEXT)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetDescriptorBufferOffsetsEXT)(VkCommandBuffer, VkPipelineBindPoint, VkPipelineLayout, uint32_t, uint32_t, const uint32_t *, const VkDeviceSize *); - void (*p_vkCmdSetDeviceMask)(VkCommandBuffer, uint32_t); - void (*p_vkCmdSetDeviceMaskKHR)(VkCommandBuffer, uint32_t); - void (*p_vkCmdSetDiscardRectangleEXT)(VkCommandBuffer, uint32_t, uint32_t, const VkRect2D *); - void (*p_vkCmdSetEvent)(VkCommandBuffer, VkEvent, VkPipelineStageFlags); - void (*p_vkCmdSetEvent2)(VkCommandBuffer, VkEvent, const VkDependencyInfo *); - void (*p_vkCmdSetEvent2KHR)(VkCommandBuffer, VkEvent, const VkDependencyInfo *); - void (*p_vkCmdSetExclusiveScissorNV)(VkCommandBuffer, uint32_t, uint32_t, const VkRect2D *); - void (*p_vkCmdSetExtraPrimitiveOverestimationSizeEXT)(VkCommandBuffer, float); - void (*p_vkCmdSetFragmentShadingRateEnumNV)(VkCommandBuffer, VkFragmentShadingRateNV, const VkFragmentShadingRateCombinerOpKHR[2]); - void (*p_vkCmdSetFragmentShadingRateKHR)(VkCommandBuffer, const VkExtent2D *, const VkFragmentShadingRateCombinerOpKHR[2]); - void (*p_vkCmdSetFrontFace)(VkCommandBuffer, VkFrontFace); - void (*p_vkCmdSetFrontFaceEXT)(VkCommandBuffer, VkFrontFace); - void (*p_vkCmdSetLineRasterizationModeEXT)(VkCommandBuffer, VkLineRasterizationModeEXT); - void (*p_vkCmdSetLineStippleEXT)(VkCommandBuffer, uint32_t, uint16_t); - void (*p_vkCmdSetLineStippleEnableEXT)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetLineWidth)(VkCommandBuffer, float); - void (*p_vkCmdSetLogicOpEXT)(VkCommandBuffer, VkLogicOp); - void (*p_vkCmdSetLogicOpEnableEXT)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetPatchControlPointsEXT)(VkCommandBuffer, uint32_t); - VkResult (*p_vkCmdSetPerformanceMarkerINTEL)(VkCommandBuffer, const VkPerformanceMarkerInfoINTEL *); - VkResult (*p_vkCmdSetPerformanceOverrideINTEL)(VkCommandBuffer, const VkPerformanceOverrideInfoINTEL *); - VkResult (*p_vkCmdSetPerformanceStreamMarkerINTEL)(VkCommandBuffer, const VkPerformanceStreamMarkerInfoINTEL *); - void (*p_vkCmdSetPolygonModeEXT)(VkCommandBuffer, VkPolygonMode); - void (*p_vkCmdSetPrimitiveRestartEnable)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetPrimitiveRestartEnableEXT)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetPrimitiveTopology)(VkCommandBuffer, VkPrimitiveTopology); - void (*p_vkCmdSetPrimitiveTopologyEXT)(VkCommandBuffer, VkPrimitiveTopology); - void (*p_vkCmdSetProvokingVertexModeEXT)(VkCommandBuffer, VkProvokingVertexModeEXT); - void (*p_vkCmdSetRasterizationSamplesEXT)(VkCommandBuffer, VkSampleCountFlagBits); - void (*p_vkCmdSetRasterizationStreamEXT)(VkCommandBuffer, uint32_t); - void (*p_vkCmdSetRasterizerDiscardEnable)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetRasterizerDiscardEnableEXT)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetRayTracingPipelineStackSizeKHR)(VkCommandBuffer, uint32_t); - void (*p_vkCmdSetRepresentativeFragmentTestEnableNV)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetSampleLocationsEXT)(VkCommandBuffer, const VkSampleLocationsInfoEXT *); - void (*p_vkCmdSetSampleLocationsEnableEXT)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetSampleMaskEXT)(VkCommandBuffer, VkSampleCountFlagBits, const VkSampleMask *); - void (*p_vkCmdSetScissor)(VkCommandBuffer, uint32_t, uint32_t, const VkRect2D *); - void (*p_vkCmdSetScissorWithCount)(VkCommandBuffer, uint32_t, const VkRect2D *); - void (*p_vkCmdSetScissorWithCountEXT)(VkCommandBuffer, uint32_t, const VkRect2D *); - void (*p_vkCmdSetShadingRateImageEnableNV)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetStencilCompareMask)(VkCommandBuffer, VkStencilFaceFlags, uint32_t); - void (*p_vkCmdSetStencilOp)(VkCommandBuffer, VkStencilFaceFlags, VkStencilOp, VkStencilOp, VkStencilOp, VkCompareOp); - void (*p_vkCmdSetStencilOpEXT)(VkCommandBuffer, VkStencilFaceFlags, VkStencilOp, VkStencilOp, VkStencilOp, VkCompareOp); - void (*p_vkCmdSetStencilReference)(VkCommandBuffer, VkStencilFaceFlags, uint32_t); - void (*p_vkCmdSetStencilTestEnable)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetStencilTestEnableEXT)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetStencilWriteMask)(VkCommandBuffer, VkStencilFaceFlags, uint32_t); - void (*p_vkCmdSetTessellationDomainOriginEXT)(VkCommandBuffer, VkTessellationDomainOrigin); - void (*p_vkCmdSetVertexInputEXT)(VkCommandBuffer, uint32_t, const VkVertexInputBindingDescription2EXT *, uint32_t, const VkVertexInputAttributeDescription2EXT *); - void (*p_vkCmdSetViewport)(VkCommandBuffer, uint32_t, uint32_t, const VkViewport *); - void (*p_vkCmdSetViewportShadingRatePaletteNV)(VkCommandBuffer, uint32_t, uint32_t, const VkShadingRatePaletteNV *); - void (*p_vkCmdSetViewportSwizzleNV)(VkCommandBuffer, uint32_t, uint32_t, const VkViewportSwizzleNV *); - void (*p_vkCmdSetViewportWScalingEnableNV)(VkCommandBuffer, VkBool32); - void (*p_vkCmdSetViewportWScalingNV)(VkCommandBuffer, uint32_t, uint32_t, const VkViewportWScalingNV *); - void (*p_vkCmdSetViewportWithCount)(VkCommandBuffer, uint32_t, const VkViewport *); - void (*p_vkCmdSetViewportWithCountEXT)(VkCommandBuffer, uint32_t, const VkViewport *); - void (*p_vkCmdSubpassShadingHUAWEI)(VkCommandBuffer); - void (*p_vkCmdTraceRaysIndirect2KHR)(VkCommandBuffer, VkDeviceAddress); - void (*p_vkCmdTraceRaysIndirectKHR)(VkCommandBuffer, const VkStridedDeviceAddressRegionKHR *, const VkStridedDeviceAddressRegionKHR *, const VkStridedDeviceAddressRegionKHR *, const VkStridedDeviceAddressRegionKHR *, VkDeviceAddress); - void (*p_vkCmdTraceRaysKHR)(VkCommandBuffer, const VkStridedDeviceAddressRegionKHR *, const VkStridedDeviceAddressRegionKHR *, const VkStridedDeviceAddressRegionKHR *, const VkStridedDeviceAddressRegionKHR *, uint32_t, uint32_t, uint32_t); - void (*p_vkCmdTraceRaysNV)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, VkDeviceSize, VkBuffer, VkDeviceSize, VkDeviceSize, VkBuffer, VkDeviceSize, VkDeviceSize, uint32_t, uint32_t, uint32_t); - void (*p_vkCmdUpdateBuffer)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkDeviceSize, const void *); - void (*p_vkCmdWaitEvents)(VkCommandBuffer, uint32_t, const VkEvent *, VkPipelineStageFlags, VkPipelineStageFlags, uint32_t, const VkMemoryBarrier *, uint32_t, const VkBufferMemoryBarrier *, uint32_t, const VkImageMemoryBarrier *); - void (*p_vkCmdWaitEvents2)(VkCommandBuffer, uint32_t, const VkEvent *, const VkDependencyInfo *); - void (*p_vkCmdWaitEvents2KHR)(VkCommandBuffer, uint32_t, const VkEvent *, const VkDependencyInfo *); - void (*p_vkCmdWriteAccelerationStructuresPropertiesKHR)(VkCommandBuffer, uint32_t, const VkAccelerationStructureKHR *, VkQueryType, VkQueryPool, uint32_t); - void (*p_vkCmdWriteAccelerationStructuresPropertiesNV)(VkCommandBuffer, uint32_t, const VkAccelerationStructureNV *, VkQueryType, VkQueryPool, uint32_t); - void (*p_vkCmdWriteBufferMarker2AMD)(VkCommandBuffer, VkPipelineStageFlags2, VkBuffer, VkDeviceSize, uint32_t); - void (*p_vkCmdWriteBufferMarkerAMD)(VkCommandBuffer, VkPipelineStageFlagBits, VkBuffer, VkDeviceSize, uint32_t); - void (*p_vkCmdWriteMicromapsPropertiesEXT)(VkCommandBuffer, uint32_t, const VkMicromapEXT *, VkQueryType, VkQueryPool, uint32_t); - void (*p_vkCmdWriteTimestamp)(VkCommandBuffer, VkPipelineStageFlagBits, VkQueryPool, uint32_t); - void (*p_vkCmdWriteTimestamp2)(VkCommandBuffer, VkPipelineStageFlags2, VkQueryPool, uint32_t); - void (*p_vkCmdWriteTimestamp2KHR)(VkCommandBuffer, VkPipelineStageFlags2, VkQueryPool, uint32_t); - VkResult (*p_vkCompileDeferredNV)(VkDevice, VkPipeline, uint32_t); - VkResult (*p_vkCopyAccelerationStructureKHR)(VkDevice, VkDeferredOperationKHR, const VkCopyAccelerationStructureInfoKHR *); - VkResult (*p_vkCopyAccelerationStructureToMemoryKHR)(VkDevice, VkDeferredOperationKHR, const VkCopyAccelerationStructureToMemoryInfoKHR *); - VkResult (*p_vkCopyMemoryToAccelerationStructureKHR)(VkDevice, VkDeferredOperationKHR, const VkCopyMemoryToAccelerationStructureInfoKHR *); - VkResult (*p_vkCopyMemoryToMicromapEXT)(VkDevice, VkDeferredOperationKHR, const VkCopyMemoryToMicromapInfoEXT *); - VkResult (*p_vkCopyMicromapEXT)(VkDevice, VkDeferredOperationKHR, const VkCopyMicromapInfoEXT *); - VkResult (*p_vkCopyMicromapToMemoryEXT)(VkDevice, VkDeferredOperationKHR, const VkCopyMicromapToMemoryInfoEXT *); - VkResult (*p_vkCreateAccelerationStructureKHR)(VkDevice, const VkAccelerationStructureCreateInfoKHR *, const VkAllocationCallbacks *, VkAccelerationStructureKHR *); - VkResult (*p_vkCreateAccelerationStructureNV)(VkDevice, const VkAccelerationStructureCreateInfoNV *, const VkAllocationCallbacks *, VkAccelerationStructureNV *); - VkResult (*p_vkCreateBuffer)(VkDevice, const VkBufferCreateInfo *, const VkAllocationCallbacks *, VkBuffer *); - VkResult (*p_vkCreateBufferView)(VkDevice, const VkBufferViewCreateInfo *, const VkAllocationCallbacks *, VkBufferView *); - VkResult (*p_vkCreateCommandPool)(VkDevice, const VkCommandPoolCreateInfo *, const VkAllocationCallbacks *, VkCommandPool *); - VkResult (*p_vkCreateComputePipelines)(VkDevice, VkPipelineCache, uint32_t, const VkComputePipelineCreateInfo *, const VkAllocationCallbacks *, VkPipeline *); - VkResult (*p_vkCreateCuFunctionNVX)(VkDevice, const VkCuFunctionCreateInfoNVX *, const VkAllocationCallbacks *, VkCuFunctionNVX *); - VkResult (*p_vkCreateCuModuleNVX)(VkDevice, const VkCuModuleCreateInfoNVX *, const VkAllocationCallbacks *, VkCuModuleNVX *); - VkResult (*p_vkCreateDeferredOperationKHR)(VkDevice, const VkAllocationCallbacks *, VkDeferredOperationKHR *); - VkResult (*p_vkCreateDescriptorPool)(VkDevice, const VkDescriptorPoolCreateInfo *, const VkAllocationCallbacks *, VkDescriptorPool *); - VkResult (*p_vkCreateDescriptorSetLayout)(VkDevice, const VkDescriptorSetLayoutCreateInfo *, const VkAllocationCallbacks *, VkDescriptorSetLayout *); - VkResult (*p_vkCreateDescriptorUpdateTemplate)(VkDevice, const VkDescriptorUpdateTemplateCreateInfo *, const VkAllocationCallbacks *, VkDescriptorUpdateTemplate *); - VkResult (*p_vkCreateDescriptorUpdateTemplateKHR)(VkDevice, const VkDescriptorUpdateTemplateCreateInfo *, const VkAllocationCallbacks *, VkDescriptorUpdateTemplate *); - VkResult (*p_vkCreateEvent)(VkDevice, const VkEventCreateInfo *, const VkAllocationCallbacks *, VkEvent *); - VkResult (*p_vkCreateFence)(VkDevice, const VkFenceCreateInfo *, const VkAllocationCallbacks *, VkFence *); - VkResult (*p_vkCreateFramebuffer)(VkDevice, const VkFramebufferCreateInfo *, const VkAllocationCallbacks *, VkFramebuffer *); - VkResult (*p_vkCreateGraphicsPipelines)(VkDevice, VkPipelineCache, uint32_t, const VkGraphicsPipelineCreateInfo *, const VkAllocationCallbacks *, VkPipeline *); - VkResult (*p_vkCreateImage)(VkDevice, const VkImageCreateInfo *, const VkAllocationCallbacks *, VkImage *); - VkResult (*p_vkCreateImageView)(VkDevice, const VkImageViewCreateInfo *, const VkAllocationCallbacks *, VkImageView *); - VkResult (*p_vkCreateIndirectCommandsLayoutNV)(VkDevice, const VkIndirectCommandsLayoutCreateInfoNV *, const VkAllocationCallbacks *, VkIndirectCommandsLayoutNV *); - VkResult (*p_vkCreateMicromapEXT)(VkDevice, const VkMicromapCreateInfoEXT *, const VkAllocationCallbacks *, VkMicromapEXT *); - VkResult (*p_vkCreateOpticalFlowSessionNV)(VkDevice, const VkOpticalFlowSessionCreateInfoNV *, const VkAllocationCallbacks *, VkOpticalFlowSessionNV *); - VkResult (*p_vkCreatePipelineCache)(VkDevice, const VkPipelineCacheCreateInfo *, const VkAllocationCallbacks *, VkPipelineCache *); - VkResult (*p_vkCreatePipelineLayout)(VkDevice, const VkPipelineLayoutCreateInfo *, const VkAllocationCallbacks *, VkPipelineLayout *); - VkResult (*p_vkCreatePrivateDataSlot)(VkDevice, const VkPrivateDataSlotCreateInfo *, const VkAllocationCallbacks *, VkPrivateDataSlot *); - VkResult (*p_vkCreatePrivateDataSlotEXT)(VkDevice, const VkPrivateDataSlotCreateInfo *, const VkAllocationCallbacks *, VkPrivateDataSlot *); - VkResult (*p_vkCreateQueryPool)(VkDevice, const VkQueryPoolCreateInfo *, const VkAllocationCallbacks *, VkQueryPool *); - VkResult (*p_vkCreateRayTracingPipelinesKHR)(VkDevice, VkDeferredOperationKHR, VkPipelineCache, uint32_t, const VkRayTracingPipelineCreateInfoKHR *, const VkAllocationCallbacks *, VkPipeline *); - VkResult (*p_vkCreateRayTracingPipelinesNV)(VkDevice, VkPipelineCache, uint32_t, const VkRayTracingPipelineCreateInfoNV *, const VkAllocationCallbacks *, VkPipeline *); - VkResult (*p_vkCreateRenderPass)(VkDevice, const VkRenderPassCreateInfo *, const VkAllocationCallbacks *, VkRenderPass *); - VkResult (*p_vkCreateRenderPass2)(VkDevice, const VkRenderPassCreateInfo2 *, const VkAllocationCallbacks *, VkRenderPass *); - VkResult (*p_vkCreateRenderPass2KHR)(VkDevice, const VkRenderPassCreateInfo2 *, const VkAllocationCallbacks *, VkRenderPass *); - VkResult (*p_vkCreateSampler)(VkDevice, const VkSamplerCreateInfo *, const VkAllocationCallbacks *, VkSampler *); - VkResult (*p_vkCreateSamplerYcbcrConversion)(VkDevice, const VkSamplerYcbcrConversionCreateInfo *, const VkAllocationCallbacks *, VkSamplerYcbcrConversion *); - VkResult (*p_vkCreateSamplerYcbcrConversionKHR)(VkDevice, const VkSamplerYcbcrConversionCreateInfo *, const VkAllocationCallbacks *, VkSamplerYcbcrConversion *); - VkResult (*p_vkCreateSemaphore)(VkDevice, const VkSemaphoreCreateInfo *, const VkAllocationCallbacks *, VkSemaphore *); - VkResult (*p_vkCreateShaderModule)(VkDevice, const VkShaderModuleCreateInfo *, const VkAllocationCallbacks *, VkShaderModule *); - VkResult (*p_vkCreateSwapchainKHR)(VkDevice, const VkSwapchainCreateInfoKHR *, const VkAllocationCallbacks *, VkSwapchainKHR *); - VkResult (*p_vkCreateValidationCacheEXT)(VkDevice, const VkValidationCacheCreateInfoEXT *, const VkAllocationCallbacks *, VkValidationCacheEXT *); - VkResult (*p_vkDebugMarkerSetObjectNameEXT)(VkDevice, const VkDebugMarkerObjectNameInfoEXT *); - VkResult (*p_vkDebugMarkerSetObjectTagEXT)(VkDevice, const VkDebugMarkerObjectTagInfoEXT *); - VkResult (*p_vkDeferredOperationJoinKHR)(VkDevice, VkDeferredOperationKHR); - void (*p_vkDestroyAccelerationStructureKHR)(VkDevice, VkAccelerationStructureKHR, const VkAllocationCallbacks *); - void (*p_vkDestroyAccelerationStructureNV)(VkDevice, VkAccelerationStructureNV, const VkAllocationCallbacks *); - void (*p_vkDestroyBuffer)(VkDevice, VkBuffer, const VkAllocationCallbacks *); - void (*p_vkDestroyBufferView)(VkDevice, VkBufferView, const VkAllocationCallbacks *); - void (*p_vkDestroyCommandPool)(VkDevice, VkCommandPool, const VkAllocationCallbacks *); - void (*p_vkDestroyCuFunctionNVX)(VkDevice, VkCuFunctionNVX, const VkAllocationCallbacks *); - void (*p_vkDestroyCuModuleNVX)(VkDevice, VkCuModuleNVX, const VkAllocationCallbacks *); - void (*p_vkDestroyDeferredOperationKHR)(VkDevice, VkDeferredOperationKHR, const VkAllocationCallbacks *); - void (*p_vkDestroyDescriptorPool)(VkDevice, VkDescriptorPool, const VkAllocationCallbacks *); - void (*p_vkDestroyDescriptorSetLayout)(VkDevice, VkDescriptorSetLayout, const VkAllocationCallbacks *); - void (*p_vkDestroyDescriptorUpdateTemplate)(VkDevice, VkDescriptorUpdateTemplate, const VkAllocationCallbacks *); - void (*p_vkDestroyDescriptorUpdateTemplateKHR)(VkDevice, VkDescriptorUpdateTemplate, const VkAllocationCallbacks *); - void (*p_vkDestroyDevice)(VkDevice, const VkAllocationCallbacks *); - void (*p_vkDestroyEvent)(VkDevice, VkEvent, const VkAllocationCallbacks *); - void (*p_vkDestroyFence)(VkDevice, VkFence, const VkAllocationCallbacks *); - void (*p_vkDestroyFramebuffer)(VkDevice, VkFramebuffer, const VkAllocationCallbacks *); - void (*p_vkDestroyImage)(VkDevice, VkImage, const VkAllocationCallbacks *); - void (*p_vkDestroyImageView)(VkDevice, VkImageView, const VkAllocationCallbacks *); - void (*p_vkDestroyIndirectCommandsLayoutNV)(VkDevice, VkIndirectCommandsLayoutNV, const VkAllocationCallbacks *); - void (*p_vkDestroyMicromapEXT)(VkDevice, VkMicromapEXT, const VkAllocationCallbacks *); - void (*p_vkDestroyOpticalFlowSessionNV)(VkDevice, VkOpticalFlowSessionNV, const VkAllocationCallbacks *); - void (*p_vkDestroyPipeline)(VkDevice, VkPipeline, const VkAllocationCallbacks *); - void (*p_vkDestroyPipelineCache)(VkDevice, VkPipelineCache, const VkAllocationCallbacks *); - void (*p_vkDestroyPipelineLayout)(VkDevice, VkPipelineLayout, const VkAllocationCallbacks *); - void (*p_vkDestroyPrivateDataSlot)(VkDevice, VkPrivateDataSlot, const VkAllocationCallbacks *); - void (*p_vkDestroyPrivateDataSlotEXT)(VkDevice, VkPrivateDataSlot, const VkAllocationCallbacks *); - void (*p_vkDestroyQueryPool)(VkDevice, VkQueryPool, const VkAllocationCallbacks *); - void (*p_vkDestroyRenderPass)(VkDevice, VkRenderPass, const VkAllocationCallbacks *); - void (*p_vkDestroySampler)(VkDevice, VkSampler, const VkAllocationCallbacks *); - void (*p_vkDestroySamplerYcbcrConversion)(VkDevice, VkSamplerYcbcrConversion, const VkAllocationCallbacks *); - void (*p_vkDestroySamplerYcbcrConversionKHR)(VkDevice, VkSamplerYcbcrConversion, const VkAllocationCallbacks *); - void (*p_vkDestroySemaphore)(VkDevice, VkSemaphore, const VkAllocationCallbacks *); - void (*p_vkDestroyShaderModule)(VkDevice, VkShaderModule, const VkAllocationCallbacks *); - void (*p_vkDestroySwapchainKHR)(VkDevice, VkSwapchainKHR, const VkAllocationCallbacks *); - void (*p_vkDestroyValidationCacheEXT)(VkDevice, VkValidationCacheEXT, const VkAllocationCallbacks *); - VkResult (*p_vkDeviceWaitIdle)(VkDevice); - VkResult (*p_vkEndCommandBuffer)(VkCommandBuffer); - VkResult (*p_vkFlushMappedMemoryRanges)(VkDevice, uint32_t, const VkMappedMemoryRange *); - void (*p_vkFreeCommandBuffers)(VkDevice, VkCommandPool, uint32_t, const VkCommandBuffer *); - VkResult (*p_vkFreeDescriptorSets)(VkDevice, VkDescriptorPool, uint32_t, const VkDescriptorSet *); - void (*p_vkFreeMemory)(VkDevice, VkDeviceMemory, const VkAllocationCallbacks *); - void (*p_vkGetAccelerationStructureBuildSizesKHR)(VkDevice, VkAccelerationStructureBuildTypeKHR, const VkAccelerationStructureBuildGeometryInfoKHR *, const uint32_t *, VkAccelerationStructureBuildSizesInfoKHR *); - VkDeviceAddress (*p_vkGetAccelerationStructureDeviceAddressKHR)(VkDevice, const VkAccelerationStructureDeviceAddressInfoKHR *); - VkResult (*p_vkGetAccelerationStructureHandleNV)(VkDevice, VkAccelerationStructureNV, size_t, void *); - void (*p_vkGetAccelerationStructureMemoryRequirementsNV)(VkDevice, const VkAccelerationStructureMemoryRequirementsInfoNV *, VkMemoryRequirements2KHR *); - VkResult (*p_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT)(VkDevice, const VkAccelerationStructureCaptureDescriptorDataInfoEXT *, void *); - VkDeviceAddress (*p_vkGetBufferDeviceAddress)(VkDevice, const VkBufferDeviceAddressInfo *); - VkDeviceAddress (*p_vkGetBufferDeviceAddressEXT)(VkDevice, const VkBufferDeviceAddressInfo *); - VkDeviceAddress (*p_vkGetBufferDeviceAddressKHR)(VkDevice, const VkBufferDeviceAddressInfo *); - void (*p_vkGetBufferMemoryRequirements)(VkDevice, VkBuffer, VkMemoryRequirements *); - void (*p_vkGetBufferMemoryRequirements2)(VkDevice, const VkBufferMemoryRequirementsInfo2 *, VkMemoryRequirements2 *); - void (*p_vkGetBufferMemoryRequirements2KHR)(VkDevice, const VkBufferMemoryRequirementsInfo2 *, VkMemoryRequirements2 *); - uint64_t (*p_vkGetBufferOpaqueCaptureAddress)(VkDevice, const VkBufferDeviceAddressInfo *); - uint64_t (*p_vkGetBufferOpaqueCaptureAddressKHR)(VkDevice, const VkBufferDeviceAddressInfo *); - VkResult (*p_vkGetBufferOpaqueCaptureDescriptorDataEXT)(VkDevice, const VkBufferCaptureDescriptorDataInfoEXT *, void *); - VkResult (*p_vkGetCalibratedTimestampsEXT)(VkDevice, uint32_t, const VkCalibratedTimestampInfoEXT *, uint64_t *, uint64_t *); - uint32_t (*p_vkGetDeferredOperationMaxConcurrencyKHR)(VkDevice, VkDeferredOperationKHR); - VkResult (*p_vkGetDeferredOperationResultKHR)(VkDevice, VkDeferredOperationKHR); - void (*p_vkGetDescriptorEXT)(VkDevice, const VkDescriptorGetInfoEXT *, size_t, void *); - void (*p_vkGetDescriptorSetHostMappingVALVE)(VkDevice, VkDescriptorSet, void **); - void (*p_vkGetDescriptorSetLayoutBindingOffsetEXT)(VkDevice, VkDescriptorSetLayout, uint32_t, VkDeviceSize *); - void (*p_vkGetDescriptorSetLayoutHostMappingInfoVALVE)(VkDevice, const VkDescriptorSetBindingReferenceVALVE *, VkDescriptorSetLayoutHostMappingInfoVALVE *); - void (*p_vkGetDescriptorSetLayoutSizeEXT)(VkDevice, VkDescriptorSetLayout, VkDeviceSize *); - void (*p_vkGetDescriptorSetLayoutSupport)(VkDevice, const VkDescriptorSetLayoutCreateInfo *, VkDescriptorSetLayoutSupport *); - void (*p_vkGetDescriptorSetLayoutSupportKHR)(VkDevice, const VkDescriptorSetLayoutCreateInfo *, VkDescriptorSetLayoutSupport *); - void (*p_vkGetDeviceAccelerationStructureCompatibilityKHR)(VkDevice, const VkAccelerationStructureVersionInfoKHR *, VkAccelerationStructureCompatibilityKHR *); - void (*p_vkGetDeviceBufferMemoryRequirements)(VkDevice, const VkDeviceBufferMemoryRequirements *, VkMemoryRequirements2 *); - void (*p_vkGetDeviceBufferMemoryRequirementsKHR)(VkDevice, const VkDeviceBufferMemoryRequirements *, VkMemoryRequirements2 *); - VkResult (*p_vkGetDeviceFaultInfoEXT)(VkDevice, VkDeviceFaultCountsEXT *, VkDeviceFaultInfoEXT *); - void (*p_vkGetDeviceGroupPeerMemoryFeatures)(VkDevice, uint32_t, uint32_t, uint32_t, VkPeerMemoryFeatureFlags *); - void (*p_vkGetDeviceGroupPeerMemoryFeaturesKHR)(VkDevice, uint32_t, uint32_t, uint32_t, VkPeerMemoryFeatureFlags *); - VkResult (*p_vkGetDeviceGroupPresentCapabilitiesKHR)(VkDevice, VkDeviceGroupPresentCapabilitiesKHR *); - VkResult (*p_vkGetDeviceGroupSurfacePresentModesKHR)(VkDevice, VkSurfaceKHR, VkDeviceGroupPresentModeFlagsKHR *); - void (*p_vkGetDeviceImageMemoryRequirements)(VkDevice, const VkDeviceImageMemoryRequirements *, VkMemoryRequirements2 *); - void (*p_vkGetDeviceImageMemoryRequirementsKHR)(VkDevice, const VkDeviceImageMemoryRequirements *, VkMemoryRequirements2 *); - void (*p_vkGetDeviceImageSparseMemoryRequirements)(VkDevice, const VkDeviceImageMemoryRequirements *, uint32_t *, VkSparseImageMemoryRequirements2 *); - void (*p_vkGetDeviceImageSparseMemoryRequirementsKHR)(VkDevice, const VkDeviceImageMemoryRequirements *, uint32_t *, VkSparseImageMemoryRequirements2 *); - void (*p_vkGetDeviceMemoryCommitment)(VkDevice, VkDeviceMemory, VkDeviceSize *); - uint64_t (*p_vkGetDeviceMemoryOpaqueCaptureAddress)(VkDevice, const VkDeviceMemoryOpaqueCaptureAddressInfo *); - uint64_t (*p_vkGetDeviceMemoryOpaqueCaptureAddressKHR)(VkDevice, const VkDeviceMemoryOpaqueCaptureAddressInfo *); - void (*p_vkGetDeviceMicromapCompatibilityEXT)(VkDevice, const VkMicromapVersionInfoEXT *, VkAccelerationStructureCompatibilityKHR *); - void (*p_vkGetDeviceQueue)(VkDevice, uint32_t, uint32_t, VkQueue *); - void (*p_vkGetDeviceQueue2)(VkDevice, const VkDeviceQueueInfo2 *, VkQueue *); - VkResult (*p_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI)(VkDevice, VkRenderPass, VkExtent2D *); - VkResult (*p_vkGetDynamicRenderingTilePropertiesQCOM)(VkDevice, const VkRenderingInfo *, VkTilePropertiesQCOM *); - VkResult (*p_vkGetEventStatus)(VkDevice, VkEvent); - VkResult (*p_vkGetFenceStatus)(VkDevice, VkFence); - VkResult (*p_vkGetFramebufferTilePropertiesQCOM)(VkDevice, VkFramebuffer, uint32_t *, VkTilePropertiesQCOM *); - void (*p_vkGetGeneratedCommandsMemoryRequirementsNV)(VkDevice, const VkGeneratedCommandsMemoryRequirementsInfoNV *, VkMemoryRequirements2 *); - void (*p_vkGetImageMemoryRequirements)(VkDevice, VkImage, VkMemoryRequirements *); - void (*p_vkGetImageMemoryRequirements2)(VkDevice, const VkImageMemoryRequirementsInfo2 *, VkMemoryRequirements2 *); - void (*p_vkGetImageMemoryRequirements2KHR)(VkDevice, const VkImageMemoryRequirementsInfo2 *, VkMemoryRequirements2 *); - VkResult (*p_vkGetImageOpaqueCaptureDescriptorDataEXT)(VkDevice, const VkImageCaptureDescriptorDataInfoEXT *, void *); - void (*p_vkGetImageSparseMemoryRequirements)(VkDevice, VkImage, uint32_t *, VkSparseImageMemoryRequirements *); - void (*p_vkGetImageSparseMemoryRequirements2)(VkDevice, const VkImageSparseMemoryRequirementsInfo2 *, uint32_t *, VkSparseImageMemoryRequirements2 *); - void (*p_vkGetImageSparseMemoryRequirements2KHR)(VkDevice, const VkImageSparseMemoryRequirementsInfo2 *, uint32_t *, VkSparseImageMemoryRequirements2 *); - void (*p_vkGetImageSubresourceLayout)(VkDevice, VkImage, const VkImageSubresource *, VkSubresourceLayout *); - void (*p_vkGetImageSubresourceLayout2EXT)(VkDevice, VkImage, const VkImageSubresource2EXT *, VkSubresourceLayout2EXT *); - VkResult (*p_vkGetImageViewAddressNVX)(VkDevice, VkImageView, VkImageViewAddressPropertiesNVX *); - uint32_t (*p_vkGetImageViewHandleNVX)(VkDevice, const VkImageViewHandleInfoNVX *); - VkResult (*p_vkGetImageViewOpaqueCaptureDescriptorDataEXT)(VkDevice, const VkImageViewCaptureDescriptorDataInfoEXT *, void *); - VkResult (*p_vkGetMemoryHostPointerPropertiesEXT)(VkDevice, VkExternalMemoryHandleTypeFlagBits, const void *, VkMemoryHostPointerPropertiesEXT *); - void (*p_vkGetMicromapBuildSizesEXT)(VkDevice, VkAccelerationStructureBuildTypeKHR, const VkMicromapBuildInfoEXT *, VkMicromapBuildSizesInfoEXT *); - VkResult (*p_vkGetPerformanceParameterINTEL)(VkDevice, VkPerformanceParameterTypeINTEL, VkPerformanceValueINTEL *); - VkResult (*p_vkGetPipelineCacheData)(VkDevice, VkPipelineCache, size_t *, void *); - VkResult (*p_vkGetPipelineExecutableInternalRepresentationsKHR)(VkDevice, const VkPipelineExecutableInfoKHR *, uint32_t *, VkPipelineExecutableInternalRepresentationKHR *); - VkResult (*p_vkGetPipelineExecutablePropertiesKHR)(VkDevice, const VkPipelineInfoKHR *, uint32_t *, VkPipelineExecutablePropertiesKHR *); - VkResult (*p_vkGetPipelineExecutableStatisticsKHR)(VkDevice, const VkPipelineExecutableInfoKHR *, uint32_t *, VkPipelineExecutableStatisticKHR *); - VkResult (*p_vkGetPipelinePropertiesEXT)(VkDevice, const VkPipelineInfoEXT *, VkBaseOutStructure *); - void (*p_vkGetPrivateData)(VkDevice, VkObjectType, uint64_t, VkPrivateDataSlot, uint64_t *); - void (*p_vkGetPrivateDataEXT)(VkDevice, VkObjectType, uint64_t, VkPrivateDataSlot, uint64_t *); - VkResult (*p_vkGetQueryPoolResults)(VkDevice, VkQueryPool, uint32_t, uint32_t, size_t, void *, VkDeviceSize, VkQueryResultFlags); - void (*p_vkGetQueueCheckpointData2NV)(VkQueue, uint32_t *, VkCheckpointData2NV *); - void (*p_vkGetQueueCheckpointDataNV)(VkQueue, uint32_t *, VkCheckpointDataNV *); - VkResult (*p_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR)(VkDevice, VkPipeline, uint32_t, uint32_t, size_t, void *); - VkResult (*p_vkGetRayTracingShaderGroupHandlesKHR)(VkDevice, VkPipeline, uint32_t, uint32_t, size_t, void *); - VkResult (*p_vkGetRayTracingShaderGroupHandlesNV)(VkDevice, VkPipeline, uint32_t, uint32_t, size_t, void *); - VkDeviceSize (*p_vkGetRayTracingShaderGroupStackSizeKHR)(VkDevice, VkPipeline, uint32_t, VkShaderGroupShaderKHR); - void (*p_vkGetRenderAreaGranularity)(VkDevice, VkRenderPass, VkExtent2D *); - VkResult (*p_vkGetSamplerOpaqueCaptureDescriptorDataEXT)(VkDevice, const VkSamplerCaptureDescriptorDataInfoEXT *, void *); - VkResult (*p_vkGetSemaphoreCounterValue)(VkDevice, VkSemaphore, uint64_t *); - VkResult (*p_vkGetSemaphoreCounterValueKHR)(VkDevice, VkSemaphore, uint64_t *); - VkResult (*p_vkGetShaderInfoAMD)(VkDevice, VkPipeline, VkShaderStageFlagBits, VkShaderInfoTypeAMD, size_t *, void *); - void (*p_vkGetShaderModuleCreateInfoIdentifierEXT)(VkDevice, const VkShaderModuleCreateInfo *, VkShaderModuleIdentifierEXT *); - void (*p_vkGetShaderModuleIdentifierEXT)(VkDevice, VkShaderModule, VkShaderModuleIdentifierEXT *); - VkResult (*p_vkGetSwapchainImagesKHR)(VkDevice, VkSwapchainKHR, uint32_t *, VkImage *); - VkResult (*p_vkGetValidationCacheDataEXT)(VkDevice, VkValidationCacheEXT, size_t *, void *); - VkResult (*p_vkInitializePerformanceApiINTEL)(VkDevice, const VkInitializePerformanceApiInfoINTEL *); - VkResult (*p_vkInvalidateMappedMemoryRanges)(VkDevice, uint32_t, const VkMappedMemoryRange *); - VkResult (*p_vkMapMemory)(VkDevice, VkDeviceMemory, VkDeviceSize, VkDeviceSize, VkMemoryMapFlags, void **); - VkResult (*p_vkMergePipelineCaches)(VkDevice, VkPipelineCache, uint32_t, const VkPipelineCache *); - VkResult (*p_vkMergeValidationCachesEXT)(VkDevice, VkValidationCacheEXT, uint32_t, const VkValidationCacheEXT *); - void (*p_vkQueueBeginDebugUtilsLabelEXT)(VkQueue, const VkDebugUtilsLabelEXT *); - VkResult (*p_vkQueueBindSparse)(VkQueue, uint32_t, const VkBindSparseInfo *, VkFence); - void (*p_vkQueueEndDebugUtilsLabelEXT)(VkQueue); - void (*p_vkQueueInsertDebugUtilsLabelEXT)(VkQueue, const VkDebugUtilsLabelEXT *); - VkResult (*p_vkQueuePresentKHR)(VkQueue, const VkPresentInfoKHR *); - VkResult (*p_vkQueueSetPerformanceConfigurationINTEL)(VkQueue, VkPerformanceConfigurationINTEL); - VkResult (*p_vkQueueSubmit)(VkQueue, uint32_t, const VkSubmitInfo *, VkFence); - VkResult (*p_vkQueueSubmit2)(VkQueue, uint32_t, const VkSubmitInfo2 *, VkFence); - VkResult (*p_vkQueueSubmit2KHR)(VkQueue, uint32_t, const VkSubmitInfo2 *, VkFence); - VkResult (*p_vkQueueWaitIdle)(VkQueue); - VkResult (*p_vkReleasePerformanceConfigurationINTEL)(VkDevice, VkPerformanceConfigurationINTEL); - void (*p_vkReleaseProfilingLockKHR)(VkDevice); - VkResult (*p_vkReleaseSwapchainImagesEXT)(VkDevice, const VkReleaseSwapchainImagesInfoEXT *); - VkResult (*p_vkResetCommandBuffer)(VkCommandBuffer, VkCommandBufferResetFlags); - VkResult (*p_vkResetCommandPool)(VkDevice, VkCommandPool, VkCommandPoolResetFlags); - VkResult (*p_vkResetDescriptorPool)(VkDevice, VkDescriptorPool, VkDescriptorPoolResetFlags); - VkResult (*p_vkResetEvent)(VkDevice, VkEvent); - VkResult (*p_vkResetFences)(VkDevice, uint32_t, const VkFence *); - void (*p_vkResetQueryPool)(VkDevice, VkQueryPool, uint32_t, uint32_t); - void (*p_vkResetQueryPoolEXT)(VkDevice, VkQueryPool, uint32_t, uint32_t); - VkResult (*p_vkSetDebugUtilsObjectNameEXT)(VkDevice, const VkDebugUtilsObjectNameInfoEXT *); - VkResult (*p_vkSetDebugUtilsObjectTagEXT)(VkDevice, const VkDebugUtilsObjectTagInfoEXT *); - void (*p_vkSetDeviceMemoryPriorityEXT)(VkDevice, VkDeviceMemory, float); - VkResult (*p_vkSetEvent)(VkDevice, VkEvent); - VkResult (*p_vkSetPrivateData)(VkDevice, VkObjectType, uint64_t, VkPrivateDataSlot, uint64_t); - VkResult (*p_vkSetPrivateDataEXT)(VkDevice, VkObjectType, uint64_t, VkPrivateDataSlot, uint64_t); - VkResult (*p_vkSignalSemaphore)(VkDevice, const VkSemaphoreSignalInfo *); - VkResult (*p_vkSignalSemaphoreKHR)(VkDevice, const VkSemaphoreSignalInfo *); - void (*p_vkTrimCommandPool)(VkDevice, VkCommandPool, VkCommandPoolTrimFlags); - void (*p_vkTrimCommandPoolKHR)(VkDevice, VkCommandPool, VkCommandPoolTrimFlags); - void (*p_vkUninitializePerformanceApiINTEL)(VkDevice); - void (*p_vkUnmapMemory)(VkDevice, VkDeviceMemory); - void (*p_vkUpdateDescriptorSetWithTemplate)(VkDevice, VkDescriptorSet, VkDescriptorUpdateTemplate, const void *); - void (*p_vkUpdateDescriptorSetWithTemplateKHR)(VkDevice, VkDescriptorSet, VkDescriptorUpdateTemplate, const void *); - void (*p_vkUpdateDescriptorSets)(VkDevice, uint32_t, const VkWriteDescriptorSet *, uint32_t, const VkCopyDescriptorSet *); - VkResult (*p_vkWaitForFences)(VkDevice, uint32_t, const VkFence *, VkBool32, uint64_t); - VkResult (*p_vkWaitForPresentKHR)(VkDevice, VkSwapchainKHR, uint64_t, uint64_t); - VkResult (*p_vkWaitSemaphores)(VkDevice, const VkSemaphoreWaitInfo *, uint64_t); - VkResult (*p_vkWaitSemaphoresKHR)(VkDevice, const VkSemaphoreWaitInfo *, uint64_t); - VkResult (*p_vkWriteAccelerationStructuresPropertiesKHR)(VkDevice, uint32_t, const VkAccelerationStructureKHR *, VkQueryType, size_t, void *, size_t); - VkResult (*p_vkWriteMicromapsPropertiesEXT)(VkDevice, uint32_t, const VkMicromapEXT *, VkQueryType, size_t, void *, size_t); -}; - -/* For use by vkInstance and children */ -struct vulkan_instance_funcs -{ - VkResult (*p_vkCreateDebugReportCallbackEXT)(VkInstance, const VkDebugReportCallbackCreateInfoEXT *, const VkAllocationCallbacks *, VkDebugReportCallbackEXT *); - VkResult (*p_vkCreateDebugUtilsMessengerEXT)(VkInstance, const VkDebugUtilsMessengerCreateInfoEXT *, const VkAllocationCallbacks *, VkDebugUtilsMessengerEXT *); - VkResult (*p_vkCreateWin32SurfaceKHR)(VkInstance, const VkWin32SurfaceCreateInfoKHR *, const VkAllocationCallbacks *, VkSurfaceKHR *); - void (*p_vkDebugReportMessageEXT)(VkInstance, VkDebugReportFlagsEXT, VkDebugReportObjectTypeEXT, uint64_t, size_t, int32_t, const char *, const char *); - void (*p_vkDestroyDebugReportCallbackEXT)(VkInstance, VkDebugReportCallbackEXT, const VkAllocationCallbacks *); - void (*p_vkDestroyDebugUtilsMessengerEXT)(VkInstance, VkDebugUtilsMessengerEXT, const VkAllocationCallbacks *); - void (*p_vkDestroySurfaceKHR)(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks *); - VkResult (*p_vkEnumeratePhysicalDeviceGroups)(VkInstance, uint32_t *, VkPhysicalDeviceGroupProperties *); - VkResult (*p_vkEnumeratePhysicalDeviceGroupsKHR)(VkInstance, uint32_t *, VkPhysicalDeviceGroupProperties *); - VkResult (*p_vkEnumeratePhysicalDevices)(VkInstance, uint32_t *, VkPhysicalDevice *); - void (*p_vkSubmitDebugUtilsMessageEXT)(VkInstance, VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT *); - VkResult (*p_vkCreateDevice)(VkPhysicalDevice, const VkDeviceCreateInfo *, const VkAllocationCallbacks *, VkDevice *); - VkResult (*p_vkEnumerateDeviceExtensionProperties)(VkPhysicalDevice, const char *, uint32_t *, VkExtensionProperties *); - VkResult (*p_vkEnumerateDeviceLayerProperties)(VkPhysicalDevice, uint32_t *, VkLayerProperties *); - VkResult (*p_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR)(VkPhysicalDevice, uint32_t, uint32_t *, VkPerformanceCounterKHR *, VkPerformanceCounterDescriptionKHR *); - VkResult (*p_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice, uint32_t *, VkTimeDomainEXT *); - VkResult (*p_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice, uint32_t *, VkCooperativeMatrixPropertiesNV *); - void (*p_vkGetPhysicalDeviceFeatures)(VkPhysicalDevice, VkPhysicalDeviceFeatures *); - void (*p_vkGetPhysicalDeviceFeatures2)(VkPhysicalDevice, VkPhysicalDeviceFeatures2 *); - void (*p_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice, VkPhysicalDeviceFeatures2 *); - void (*p_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice, VkFormat, VkFormatProperties *); - void (*p_vkGetPhysicalDeviceFormatProperties2)(VkPhysicalDevice, VkFormat, VkFormatProperties2 *); - void (*p_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice, VkFormat, VkFormatProperties2 *); - VkResult (*p_vkGetPhysicalDeviceFragmentShadingRatesKHR)(VkPhysicalDevice, uint32_t *, VkPhysicalDeviceFragmentShadingRateKHR *); - VkResult (*p_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice, VkFormat, VkImageType, VkImageTiling, VkImageUsageFlags, VkImageCreateFlags, VkImageFormatProperties *); - VkResult (*p_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice, const VkPhysicalDeviceImageFormatInfo2 *, VkImageFormatProperties2 *); - VkResult (*p_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice, const VkPhysicalDeviceImageFormatInfo2 *, VkImageFormatProperties2 *); - void (*p_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice, VkPhysicalDeviceMemoryProperties *); - void (*p_vkGetPhysicalDeviceMemoryProperties2)(VkPhysicalDevice, VkPhysicalDeviceMemoryProperties2 *); - void (*p_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice, VkPhysicalDeviceMemoryProperties2 *); - void (*p_vkGetPhysicalDeviceMultisamplePropertiesEXT)(VkPhysicalDevice, VkSampleCountFlagBits, VkMultisamplePropertiesEXT *); - VkResult (*p_vkGetPhysicalDeviceOpticalFlowImageFormatsNV)(VkPhysicalDevice, const VkOpticalFlowImageFormatInfoNV *, uint32_t *, VkOpticalFlowImageFormatPropertiesNV *); - VkResult (*p_vkGetPhysicalDevicePresentRectanglesKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkRect2D *); - void (*p_vkGetPhysicalDeviceProperties)(VkPhysicalDevice, VkPhysicalDeviceProperties *); - void (*p_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice, VkPhysicalDeviceProperties2 *); - void (*p_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice, VkPhysicalDeviceProperties2 *); - void (*p_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR)(VkPhysicalDevice, const VkQueryPoolPerformanceCreateInfoKHR *, uint32_t *); - void (*p_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice, uint32_t *, VkQueueFamilyProperties *); - void (*p_vkGetPhysicalDeviceQueueFamilyProperties2)(VkPhysicalDevice, uint32_t *, VkQueueFamilyProperties2 *); - void (*p_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice, uint32_t *, VkQueueFamilyProperties2 *); - void (*p_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice, VkFormat, VkImageType, VkSampleCountFlagBits, VkImageUsageFlags, VkImageTiling, uint32_t *, VkSparseImageFormatProperties *); - void (*p_vkGetPhysicalDeviceSparseImageFormatProperties2)(VkPhysicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2 *, uint32_t *, VkSparseImageFormatProperties2 *); - void (*p_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2 *, uint32_t *, VkSparseImageFormatProperties2 *); - VkResult (*p_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV)(VkPhysicalDevice, uint32_t *, VkFramebufferMixedSamplesCombinationNV *); - VkResult (*p_vkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *, VkSurfaceCapabilities2KHR *); - VkResult (*p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice, VkSurfaceKHR, VkSurfaceCapabilitiesKHR *); - VkResult (*p_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *, uint32_t *, VkSurfaceFormat2KHR *); - VkResult (*p_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkSurfaceFormatKHR *); - VkResult (*p_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkPresentModeKHR *); - VkResult (*p_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice, uint32_t, VkSurfaceKHR, VkBool32 *); - VkResult (*p_vkGetPhysicalDeviceToolProperties)(VkPhysicalDevice, uint32_t *, VkPhysicalDeviceToolProperties *); - VkResult (*p_vkGetPhysicalDeviceToolPropertiesEXT)(VkPhysicalDevice, uint32_t *, VkPhysicalDeviceToolProperties *); - VkBool32 (*p_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice, uint32_t); -}; - -#define ALL_VK_DEVICE_FUNCS() \ - USE_VK_FUNC(vkAcquireNextImage2KHR) \ - USE_VK_FUNC(vkAcquireNextImageKHR) \ - USE_VK_FUNC(vkAcquirePerformanceConfigurationINTEL) \ - USE_VK_FUNC(vkAcquireProfilingLockKHR) \ - USE_VK_FUNC(vkAllocateCommandBuffers) \ - USE_VK_FUNC(vkAllocateDescriptorSets) \ - USE_VK_FUNC(vkAllocateMemory) \ - USE_VK_FUNC(vkBeginCommandBuffer) \ - USE_VK_FUNC(vkBindAccelerationStructureMemoryNV) \ - USE_VK_FUNC(vkBindBufferMemory) \ - USE_VK_FUNC(vkBindBufferMemory2) \ - USE_VK_FUNC(vkBindBufferMemory2KHR) \ - USE_VK_FUNC(vkBindImageMemory) \ - USE_VK_FUNC(vkBindImageMemory2) \ - USE_VK_FUNC(vkBindImageMemory2KHR) \ - USE_VK_FUNC(vkBindOpticalFlowSessionImageNV) \ - USE_VK_FUNC(vkBuildAccelerationStructuresKHR) \ - USE_VK_FUNC(vkBuildMicromapsEXT) \ - USE_VK_FUNC(vkCmdBeginConditionalRenderingEXT) \ - USE_VK_FUNC(vkCmdBeginDebugUtilsLabelEXT) \ - USE_VK_FUNC(vkCmdBeginQuery) \ - USE_VK_FUNC(vkCmdBeginQueryIndexedEXT) \ - USE_VK_FUNC(vkCmdBeginRenderPass) \ - USE_VK_FUNC(vkCmdBeginRenderPass2) \ - USE_VK_FUNC(vkCmdBeginRenderPass2KHR) \ - USE_VK_FUNC(vkCmdBeginRendering) \ - USE_VK_FUNC(vkCmdBeginRenderingKHR) \ - USE_VK_FUNC(vkCmdBeginTransformFeedbackEXT) \ - USE_VK_FUNC(vkCmdBindDescriptorBufferEmbeddedSamplersEXT) \ - USE_VK_FUNC(vkCmdBindDescriptorBuffersEXT) \ - USE_VK_FUNC(vkCmdBindDescriptorSets) \ - USE_VK_FUNC(vkCmdBindIndexBuffer) \ - USE_VK_FUNC(vkCmdBindInvocationMaskHUAWEI) \ - USE_VK_FUNC(vkCmdBindPipeline) \ - USE_VK_FUNC(vkCmdBindPipelineShaderGroupNV) \ - USE_VK_FUNC(vkCmdBindShadingRateImageNV) \ - USE_VK_FUNC(vkCmdBindTransformFeedbackBuffersEXT) \ - USE_VK_FUNC(vkCmdBindVertexBuffers) \ - USE_VK_FUNC(vkCmdBindVertexBuffers2) \ - USE_VK_FUNC(vkCmdBindVertexBuffers2EXT) \ - USE_VK_FUNC(vkCmdBlitImage) \ - USE_VK_FUNC(vkCmdBlitImage2) \ - USE_VK_FUNC(vkCmdBlitImage2KHR) \ - USE_VK_FUNC(vkCmdBuildAccelerationStructureNV) \ - USE_VK_FUNC(vkCmdBuildAccelerationStructuresIndirectKHR) \ - USE_VK_FUNC(vkCmdBuildAccelerationStructuresKHR) \ - USE_VK_FUNC(vkCmdBuildMicromapsEXT) \ - USE_VK_FUNC(vkCmdClearAttachments) \ - USE_VK_FUNC(vkCmdClearColorImage) \ - USE_VK_FUNC(vkCmdClearDepthStencilImage) \ - USE_VK_FUNC(vkCmdCopyAccelerationStructureKHR) \ - USE_VK_FUNC(vkCmdCopyAccelerationStructureNV) \ - USE_VK_FUNC(vkCmdCopyAccelerationStructureToMemoryKHR) \ - USE_VK_FUNC(vkCmdCopyBuffer) \ - USE_VK_FUNC(vkCmdCopyBuffer2) \ - USE_VK_FUNC(vkCmdCopyBuffer2KHR) \ - USE_VK_FUNC(vkCmdCopyBufferToImage) \ - USE_VK_FUNC(vkCmdCopyBufferToImage2) \ - USE_VK_FUNC(vkCmdCopyBufferToImage2KHR) \ - USE_VK_FUNC(vkCmdCopyImage) \ - USE_VK_FUNC(vkCmdCopyImage2) \ - USE_VK_FUNC(vkCmdCopyImage2KHR) \ - USE_VK_FUNC(vkCmdCopyImageToBuffer) \ - USE_VK_FUNC(vkCmdCopyImageToBuffer2) \ - USE_VK_FUNC(vkCmdCopyImageToBuffer2KHR) \ - USE_VK_FUNC(vkCmdCopyMemoryIndirectNV) \ - USE_VK_FUNC(vkCmdCopyMemoryToAccelerationStructureKHR) \ - USE_VK_FUNC(vkCmdCopyMemoryToImageIndirectNV) \ - USE_VK_FUNC(vkCmdCopyMemoryToMicromapEXT) \ - USE_VK_FUNC(vkCmdCopyMicromapEXT) \ - USE_VK_FUNC(vkCmdCopyMicromapToMemoryEXT) \ - USE_VK_FUNC(vkCmdCopyQueryPoolResults) \ - USE_VK_FUNC(vkCmdCuLaunchKernelNVX) \ - USE_VK_FUNC(vkCmdDebugMarkerBeginEXT) \ - USE_VK_FUNC(vkCmdDebugMarkerEndEXT) \ - USE_VK_FUNC(vkCmdDebugMarkerInsertEXT) \ - USE_VK_FUNC(vkCmdDecompressMemoryIndirectCountNV) \ - USE_VK_FUNC(vkCmdDecompressMemoryNV) \ - USE_VK_FUNC(vkCmdDispatch) \ - USE_VK_FUNC(vkCmdDispatchBase) \ - USE_VK_FUNC(vkCmdDispatchBaseKHR) \ - USE_VK_FUNC(vkCmdDispatchIndirect) \ - USE_VK_FUNC(vkCmdDraw) \ - USE_VK_FUNC(vkCmdDrawIndexed) \ - USE_VK_FUNC(vkCmdDrawIndexedIndirect) \ - USE_VK_FUNC(vkCmdDrawIndexedIndirectCount) \ - USE_VK_FUNC(vkCmdDrawIndexedIndirectCountAMD) \ - USE_VK_FUNC(vkCmdDrawIndexedIndirectCountKHR) \ - USE_VK_FUNC(vkCmdDrawIndirect) \ - USE_VK_FUNC(vkCmdDrawIndirectByteCountEXT) \ - USE_VK_FUNC(vkCmdDrawIndirectCount) \ - USE_VK_FUNC(vkCmdDrawIndirectCountAMD) \ - USE_VK_FUNC(vkCmdDrawIndirectCountKHR) \ - USE_VK_FUNC(vkCmdDrawMeshTasksEXT) \ - USE_VK_FUNC(vkCmdDrawMeshTasksIndirectCountEXT) \ - USE_VK_FUNC(vkCmdDrawMeshTasksIndirectCountNV) \ - USE_VK_FUNC(vkCmdDrawMeshTasksIndirectEXT) \ - USE_VK_FUNC(vkCmdDrawMeshTasksIndirectNV) \ - USE_VK_FUNC(vkCmdDrawMeshTasksNV) \ - USE_VK_FUNC(vkCmdDrawMultiEXT) \ - USE_VK_FUNC(vkCmdDrawMultiIndexedEXT) \ - USE_VK_FUNC(vkCmdEndConditionalRenderingEXT) \ - USE_VK_FUNC(vkCmdEndDebugUtilsLabelEXT) \ - USE_VK_FUNC(vkCmdEndQuery) \ - USE_VK_FUNC(vkCmdEndQueryIndexedEXT) \ - USE_VK_FUNC(vkCmdEndRenderPass) \ - USE_VK_FUNC(vkCmdEndRenderPass2) \ - USE_VK_FUNC(vkCmdEndRenderPass2KHR) \ - USE_VK_FUNC(vkCmdEndRendering) \ - USE_VK_FUNC(vkCmdEndRenderingKHR) \ - USE_VK_FUNC(vkCmdEndTransformFeedbackEXT) \ - USE_VK_FUNC(vkCmdExecuteCommands) \ - USE_VK_FUNC(vkCmdExecuteGeneratedCommandsNV) \ - USE_VK_FUNC(vkCmdFillBuffer) \ - USE_VK_FUNC(vkCmdInsertDebugUtilsLabelEXT) \ - USE_VK_FUNC(vkCmdNextSubpass) \ - USE_VK_FUNC(vkCmdNextSubpass2) \ - USE_VK_FUNC(vkCmdNextSubpass2KHR) \ - USE_VK_FUNC(vkCmdOpticalFlowExecuteNV) \ - USE_VK_FUNC(vkCmdPipelineBarrier) \ - USE_VK_FUNC(vkCmdPipelineBarrier2) \ - USE_VK_FUNC(vkCmdPipelineBarrier2KHR) \ - USE_VK_FUNC(vkCmdPreprocessGeneratedCommandsNV) \ - USE_VK_FUNC(vkCmdPushConstants) \ - USE_VK_FUNC(vkCmdPushDescriptorSetKHR) \ - USE_VK_FUNC(vkCmdPushDescriptorSetWithTemplateKHR) \ - USE_VK_FUNC(vkCmdResetEvent) \ - USE_VK_FUNC(vkCmdResetEvent2) \ - USE_VK_FUNC(vkCmdResetEvent2KHR) \ - USE_VK_FUNC(vkCmdResetQueryPool) \ - USE_VK_FUNC(vkCmdResolveImage) \ - USE_VK_FUNC(vkCmdResolveImage2) \ - USE_VK_FUNC(vkCmdResolveImage2KHR) \ - USE_VK_FUNC(vkCmdSetAlphaToCoverageEnableEXT) \ - USE_VK_FUNC(vkCmdSetAlphaToOneEnableEXT) \ - USE_VK_FUNC(vkCmdSetBlendConstants) \ - USE_VK_FUNC(vkCmdSetCheckpointNV) \ - USE_VK_FUNC(vkCmdSetCoarseSampleOrderNV) \ - USE_VK_FUNC(vkCmdSetColorBlendAdvancedEXT) \ - USE_VK_FUNC(vkCmdSetColorBlendEnableEXT) \ - USE_VK_FUNC(vkCmdSetColorBlendEquationEXT) \ - USE_VK_FUNC(vkCmdSetColorWriteEnableEXT) \ - USE_VK_FUNC(vkCmdSetColorWriteMaskEXT) \ - USE_VK_FUNC(vkCmdSetConservativeRasterizationModeEXT) \ - USE_VK_FUNC(vkCmdSetCoverageModulationModeNV) \ - USE_VK_FUNC(vkCmdSetCoverageModulationTableEnableNV) \ - USE_VK_FUNC(vkCmdSetCoverageModulationTableNV) \ - USE_VK_FUNC(vkCmdSetCoverageReductionModeNV) \ - USE_VK_FUNC(vkCmdSetCoverageToColorEnableNV) \ - USE_VK_FUNC(vkCmdSetCoverageToColorLocationNV) \ - USE_VK_FUNC(vkCmdSetCullMode) \ - USE_VK_FUNC(vkCmdSetCullModeEXT) \ - USE_VK_FUNC(vkCmdSetDepthBias) \ - USE_VK_FUNC(vkCmdSetDepthBiasEnable) \ - USE_VK_FUNC(vkCmdSetDepthBiasEnableEXT) \ - USE_VK_FUNC(vkCmdSetDepthBounds) \ - USE_VK_FUNC(vkCmdSetDepthBoundsTestEnable) \ - USE_VK_FUNC(vkCmdSetDepthBoundsTestEnableEXT) \ - USE_VK_FUNC(vkCmdSetDepthClampEnableEXT) \ - USE_VK_FUNC(vkCmdSetDepthClipEnableEXT) \ - USE_VK_FUNC(vkCmdSetDepthClipNegativeOneToOneEXT) \ - USE_VK_FUNC(vkCmdSetDepthCompareOp) \ - USE_VK_FUNC(vkCmdSetDepthCompareOpEXT) \ - USE_VK_FUNC(vkCmdSetDepthTestEnable) \ - USE_VK_FUNC(vkCmdSetDepthTestEnableEXT) \ - USE_VK_FUNC(vkCmdSetDepthWriteEnable) \ - USE_VK_FUNC(vkCmdSetDepthWriteEnableEXT) \ - USE_VK_FUNC(vkCmdSetDescriptorBufferOffsetsEXT) \ - USE_VK_FUNC(vkCmdSetDeviceMask) \ - USE_VK_FUNC(vkCmdSetDeviceMaskKHR) \ - USE_VK_FUNC(vkCmdSetDiscardRectangleEXT) \ - USE_VK_FUNC(vkCmdSetEvent) \ - USE_VK_FUNC(vkCmdSetEvent2) \ - USE_VK_FUNC(vkCmdSetEvent2KHR) \ - USE_VK_FUNC(vkCmdSetExclusiveScissorNV) \ - USE_VK_FUNC(vkCmdSetExtraPrimitiveOverestimationSizeEXT) \ - USE_VK_FUNC(vkCmdSetFragmentShadingRateEnumNV) \ - USE_VK_FUNC(vkCmdSetFragmentShadingRateKHR) \ - USE_VK_FUNC(vkCmdSetFrontFace) \ - USE_VK_FUNC(vkCmdSetFrontFaceEXT) \ - USE_VK_FUNC(vkCmdSetLineRasterizationModeEXT) \ - USE_VK_FUNC(vkCmdSetLineStippleEXT) \ - USE_VK_FUNC(vkCmdSetLineStippleEnableEXT) \ - USE_VK_FUNC(vkCmdSetLineWidth) \ - USE_VK_FUNC(vkCmdSetLogicOpEXT) \ - USE_VK_FUNC(vkCmdSetLogicOpEnableEXT) \ - USE_VK_FUNC(vkCmdSetPatchControlPointsEXT) \ - USE_VK_FUNC(vkCmdSetPerformanceMarkerINTEL) \ - USE_VK_FUNC(vkCmdSetPerformanceOverrideINTEL) \ - USE_VK_FUNC(vkCmdSetPerformanceStreamMarkerINTEL) \ - USE_VK_FUNC(vkCmdSetPolygonModeEXT) \ - USE_VK_FUNC(vkCmdSetPrimitiveRestartEnable) \ - USE_VK_FUNC(vkCmdSetPrimitiveRestartEnableEXT) \ - USE_VK_FUNC(vkCmdSetPrimitiveTopology) \ - USE_VK_FUNC(vkCmdSetPrimitiveTopologyEXT) \ - USE_VK_FUNC(vkCmdSetProvokingVertexModeEXT) \ - USE_VK_FUNC(vkCmdSetRasterizationSamplesEXT) \ - USE_VK_FUNC(vkCmdSetRasterizationStreamEXT) \ - USE_VK_FUNC(vkCmdSetRasterizerDiscardEnable) \ - USE_VK_FUNC(vkCmdSetRasterizerDiscardEnableEXT) \ - USE_VK_FUNC(vkCmdSetRayTracingPipelineStackSizeKHR) \ - USE_VK_FUNC(vkCmdSetRepresentativeFragmentTestEnableNV) \ - USE_VK_FUNC(vkCmdSetSampleLocationsEXT) \ - USE_VK_FUNC(vkCmdSetSampleLocationsEnableEXT) \ - USE_VK_FUNC(vkCmdSetSampleMaskEXT) \ - USE_VK_FUNC(vkCmdSetScissor) \ - USE_VK_FUNC(vkCmdSetScissorWithCount) \ - USE_VK_FUNC(vkCmdSetScissorWithCountEXT) \ - USE_VK_FUNC(vkCmdSetShadingRateImageEnableNV) \ - USE_VK_FUNC(vkCmdSetStencilCompareMask) \ - USE_VK_FUNC(vkCmdSetStencilOp) \ - USE_VK_FUNC(vkCmdSetStencilOpEXT) \ - USE_VK_FUNC(vkCmdSetStencilReference) \ - USE_VK_FUNC(vkCmdSetStencilTestEnable) \ - USE_VK_FUNC(vkCmdSetStencilTestEnableEXT) \ - USE_VK_FUNC(vkCmdSetStencilWriteMask) \ - USE_VK_FUNC(vkCmdSetTessellationDomainOriginEXT) \ - USE_VK_FUNC(vkCmdSetVertexInputEXT) \ - USE_VK_FUNC(vkCmdSetViewport) \ - USE_VK_FUNC(vkCmdSetViewportShadingRatePaletteNV) \ - USE_VK_FUNC(vkCmdSetViewportSwizzleNV) \ - USE_VK_FUNC(vkCmdSetViewportWScalingEnableNV) \ - USE_VK_FUNC(vkCmdSetViewportWScalingNV) \ - USE_VK_FUNC(vkCmdSetViewportWithCount) \ - USE_VK_FUNC(vkCmdSetViewportWithCountEXT) \ - USE_VK_FUNC(vkCmdSubpassShadingHUAWEI) \ - USE_VK_FUNC(vkCmdTraceRaysIndirect2KHR) \ - USE_VK_FUNC(vkCmdTraceRaysIndirectKHR) \ - USE_VK_FUNC(vkCmdTraceRaysKHR) \ - USE_VK_FUNC(vkCmdTraceRaysNV) \ - USE_VK_FUNC(vkCmdUpdateBuffer) \ - USE_VK_FUNC(vkCmdWaitEvents) \ - USE_VK_FUNC(vkCmdWaitEvents2) \ - USE_VK_FUNC(vkCmdWaitEvents2KHR) \ - USE_VK_FUNC(vkCmdWriteAccelerationStructuresPropertiesKHR) \ - USE_VK_FUNC(vkCmdWriteAccelerationStructuresPropertiesNV) \ - USE_VK_FUNC(vkCmdWriteBufferMarker2AMD) \ - USE_VK_FUNC(vkCmdWriteBufferMarkerAMD) \ - USE_VK_FUNC(vkCmdWriteMicromapsPropertiesEXT) \ - USE_VK_FUNC(vkCmdWriteTimestamp) \ - USE_VK_FUNC(vkCmdWriteTimestamp2) \ - USE_VK_FUNC(vkCmdWriteTimestamp2KHR) \ - USE_VK_FUNC(vkCompileDeferredNV) \ - USE_VK_FUNC(vkCopyAccelerationStructureKHR) \ - USE_VK_FUNC(vkCopyAccelerationStructureToMemoryKHR) \ - USE_VK_FUNC(vkCopyMemoryToAccelerationStructureKHR) \ - USE_VK_FUNC(vkCopyMemoryToMicromapEXT) \ - USE_VK_FUNC(vkCopyMicromapEXT) \ - USE_VK_FUNC(vkCopyMicromapToMemoryEXT) \ - USE_VK_FUNC(vkCreateAccelerationStructureKHR) \ - USE_VK_FUNC(vkCreateAccelerationStructureNV) \ - USE_VK_FUNC(vkCreateBuffer) \ - USE_VK_FUNC(vkCreateBufferView) \ - USE_VK_FUNC(vkCreateCommandPool) \ - USE_VK_FUNC(vkCreateComputePipelines) \ - USE_VK_FUNC(vkCreateCuFunctionNVX) \ - USE_VK_FUNC(vkCreateCuModuleNVX) \ - USE_VK_FUNC(vkCreateDeferredOperationKHR) \ - USE_VK_FUNC(vkCreateDescriptorPool) \ - USE_VK_FUNC(vkCreateDescriptorSetLayout) \ - USE_VK_FUNC(vkCreateDescriptorUpdateTemplate) \ - USE_VK_FUNC(vkCreateDescriptorUpdateTemplateKHR) \ - USE_VK_FUNC(vkCreateEvent) \ - USE_VK_FUNC(vkCreateFence) \ - USE_VK_FUNC(vkCreateFramebuffer) \ - USE_VK_FUNC(vkCreateGraphicsPipelines) \ - USE_VK_FUNC(vkCreateImage) \ - USE_VK_FUNC(vkCreateImageView) \ - USE_VK_FUNC(vkCreateIndirectCommandsLayoutNV) \ - USE_VK_FUNC(vkCreateMicromapEXT) \ - USE_VK_FUNC(vkCreateOpticalFlowSessionNV) \ - USE_VK_FUNC(vkCreatePipelineCache) \ - USE_VK_FUNC(vkCreatePipelineLayout) \ - USE_VK_FUNC(vkCreatePrivateDataSlot) \ - USE_VK_FUNC(vkCreatePrivateDataSlotEXT) \ - USE_VK_FUNC(vkCreateQueryPool) \ - USE_VK_FUNC(vkCreateRayTracingPipelinesKHR) \ - USE_VK_FUNC(vkCreateRayTracingPipelinesNV) \ - USE_VK_FUNC(vkCreateRenderPass) \ - USE_VK_FUNC(vkCreateRenderPass2) \ - USE_VK_FUNC(vkCreateRenderPass2KHR) \ - USE_VK_FUNC(vkCreateSampler) \ - USE_VK_FUNC(vkCreateSamplerYcbcrConversion) \ - USE_VK_FUNC(vkCreateSamplerYcbcrConversionKHR) \ - USE_VK_FUNC(vkCreateSemaphore) \ - USE_VK_FUNC(vkCreateShaderModule) \ - USE_VK_FUNC(vkCreateSwapchainKHR) \ - USE_VK_FUNC(vkCreateValidationCacheEXT) \ - USE_VK_FUNC(vkDebugMarkerSetObjectNameEXT) \ - USE_VK_FUNC(vkDebugMarkerSetObjectTagEXT) \ - USE_VK_FUNC(vkDeferredOperationJoinKHR) \ - USE_VK_FUNC(vkDestroyAccelerationStructureKHR) \ - USE_VK_FUNC(vkDestroyAccelerationStructureNV) \ - USE_VK_FUNC(vkDestroyBuffer) \ - USE_VK_FUNC(vkDestroyBufferView) \ - USE_VK_FUNC(vkDestroyCommandPool) \ - USE_VK_FUNC(vkDestroyCuFunctionNVX) \ - USE_VK_FUNC(vkDestroyCuModuleNVX) \ - USE_VK_FUNC(vkDestroyDeferredOperationKHR) \ - USE_VK_FUNC(vkDestroyDescriptorPool) \ - USE_VK_FUNC(vkDestroyDescriptorSetLayout) \ - USE_VK_FUNC(vkDestroyDescriptorUpdateTemplate) \ - USE_VK_FUNC(vkDestroyDescriptorUpdateTemplateKHR) \ - USE_VK_FUNC(vkDestroyDevice) \ - USE_VK_FUNC(vkDestroyEvent) \ - USE_VK_FUNC(vkDestroyFence) \ - USE_VK_FUNC(vkDestroyFramebuffer) \ - USE_VK_FUNC(vkDestroyImage) \ - USE_VK_FUNC(vkDestroyImageView) \ - USE_VK_FUNC(vkDestroyIndirectCommandsLayoutNV) \ - USE_VK_FUNC(vkDestroyMicromapEXT) \ - USE_VK_FUNC(vkDestroyOpticalFlowSessionNV) \ - USE_VK_FUNC(vkDestroyPipeline) \ - USE_VK_FUNC(vkDestroyPipelineCache) \ - USE_VK_FUNC(vkDestroyPipelineLayout) \ - USE_VK_FUNC(vkDestroyPrivateDataSlot) \ - USE_VK_FUNC(vkDestroyPrivateDataSlotEXT) \ - USE_VK_FUNC(vkDestroyQueryPool) \ - USE_VK_FUNC(vkDestroyRenderPass) \ - USE_VK_FUNC(vkDestroySampler) \ - USE_VK_FUNC(vkDestroySamplerYcbcrConversion) \ - USE_VK_FUNC(vkDestroySamplerYcbcrConversionKHR) \ - USE_VK_FUNC(vkDestroySemaphore) \ - USE_VK_FUNC(vkDestroyShaderModule) \ - USE_VK_FUNC(vkDestroySwapchainKHR) \ - USE_VK_FUNC(vkDestroyValidationCacheEXT) \ - USE_VK_FUNC(vkDeviceWaitIdle) \ - USE_VK_FUNC(vkEndCommandBuffer) \ - USE_VK_FUNC(vkFlushMappedMemoryRanges) \ - USE_VK_FUNC(vkFreeCommandBuffers) \ - USE_VK_FUNC(vkFreeDescriptorSets) \ - USE_VK_FUNC(vkFreeMemory) \ - USE_VK_FUNC(vkGetAccelerationStructureBuildSizesKHR) \ - USE_VK_FUNC(vkGetAccelerationStructureDeviceAddressKHR) \ - USE_VK_FUNC(vkGetAccelerationStructureHandleNV) \ - USE_VK_FUNC(vkGetAccelerationStructureMemoryRequirementsNV) \ - USE_VK_FUNC(vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT) \ - USE_VK_FUNC(vkGetBufferDeviceAddress) \ - USE_VK_FUNC(vkGetBufferDeviceAddressEXT) \ - USE_VK_FUNC(vkGetBufferDeviceAddressKHR) \ - USE_VK_FUNC(vkGetBufferMemoryRequirements) \ - USE_VK_FUNC(vkGetBufferMemoryRequirements2) \ - USE_VK_FUNC(vkGetBufferMemoryRequirements2KHR) \ - USE_VK_FUNC(vkGetBufferOpaqueCaptureAddress) \ - USE_VK_FUNC(vkGetBufferOpaqueCaptureAddressKHR) \ - USE_VK_FUNC(vkGetBufferOpaqueCaptureDescriptorDataEXT) \ - USE_VK_FUNC(vkGetCalibratedTimestampsEXT) \ - USE_VK_FUNC(vkGetDeferredOperationMaxConcurrencyKHR) \ - USE_VK_FUNC(vkGetDeferredOperationResultKHR) \ - USE_VK_FUNC(vkGetDescriptorEXT) \ - USE_VK_FUNC(vkGetDescriptorSetHostMappingVALVE) \ - USE_VK_FUNC(vkGetDescriptorSetLayoutBindingOffsetEXT) \ - USE_VK_FUNC(vkGetDescriptorSetLayoutHostMappingInfoVALVE) \ - USE_VK_FUNC(vkGetDescriptorSetLayoutSizeEXT) \ - USE_VK_FUNC(vkGetDescriptorSetLayoutSupport) \ - USE_VK_FUNC(vkGetDescriptorSetLayoutSupportKHR) \ - USE_VK_FUNC(vkGetDeviceAccelerationStructureCompatibilityKHR) \ - USE_VK_FUNC(vkGetDeviceBufferMemoryRequirements) \ - USE_VK_FUNC(vkGetDeviceBufferMemoryRequirementsKHR) \ - USE_VK_FUNC(vkGetDeviceFaultInfoEXT) \ - USE_VK_FUNC(vkGetDeviceGroupPeerMemoryFeatures) \ - USE_VK_FUNC(vkGetDeviceGroupPeerMemoryFeaturesKHR) \ - USE_VK_FUNC(vkGetDeviceGroupPresentCapabilitiesKHR) \ - USE_VK_FUNC(vkGetDeviceGroupSurfacePresentModesKHR) \ - USE_VK_FUNC(vkGetDeviceImageMemoryRequirements) \ - USE_VK_FUNC(vkGetDeviceImageMemoryRequirementsKHR) \ - USE_VK_FUNC(vkGetDeviceImageSparseMemoryRequirements) \ - USE_VK_FUNC(vkGetDeviceImageSparseMemoryRequirementsKHR) \ - USE_VK_FUNC(vkGetDeviceMemoryCommitment) \ - USE_VK_FUNC(vkGetDeviceMemoryOpaqueCaptureAddress) \ - USE_VK_FUNC(vkGetDeviceMemoryOpaqueCaptureAddressKHR) \ - USE_VK_FUNC(vkGetDeviceMicromapCompatibilityEXT) \ - USE_VK_FUNC(vkGetDeviceQueue) \ - USE_VK_FUNC(vkGetDeviceQueue2) \ - USE_VK_FUNC(vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI) \ - USE_VK_FUNC(vkGetDynamicRenderingTilePropertiesQCOM) \ - USE_VK_FUNC(vkGetEventStatus) \ - USE_VK_FUNC(vkGetFenceStatus) \ - USE_VK_FUNC(vkGetFramebufferTilePropertiesQCOM) \ - USE_VK_FUNC(vkGetGeneratedCommandsMemoryRequirementsNV) \ - USE_VK_FUNC(vkGetImageMemoryRequirements) \ - USE_VK_FUNC(vkGetImageMemoryRequirements2) \ - USE_VK_FUNC(vkGetImageMemoryRequirements2KHR) \ - USE_VK_FUNC(vkGetImageOpaqueCaptureDescriptorDataEXT) \ - USE_VK_FUNC(vkGetImageSparseMemoryRequirements) \ - USE_VK_FUNC(vkGetImageSparseMemoryRequirements2) \ - USE_VK_FUNC(vkGetImageSparseMemoryRequirements2KHR) \ - USE_VK_FUNC(vkGetImageSubresourceLayout) \ - USE_VK_FUNC(vkGetImageSubresourceLayout2EXT) \ - USE_VK_FUNC(vkGetImageViewAddressNVX) \ - USE_VK_FUNC(vkGetImageViewHandleNVX) \ - USE_VK_FUNC(vkGetImageViewOpaqueCaptureDescriptorDataEXT) \ - USE_VK_FUNC(vkGetMemoryHostPointerPropertiesEXT) \ - USE_VK_FUNC(vkGetMicromapBuildSizesEXT) \ - USE_VK_FUNC(vkGetPerformanceParameterINTEL) \ - USE_VK_FUNC(vkGetPipelineCacheData) \ - USE_VK_FUNC(vkGetPipelineExecutableInternalRepresentationsKHR) \ - USE_VK_FUNC(vkGetPipelineExecutablePropertiesKHR) \ - USE_VK_FUNC(vkGetPipelineExecutableStatisticsKHR) \ - USE_VK_FUNC(vkGetPipelinePropertiesEXT) \ - USE_VK_FUNC(vkGetPrivateData) \ - USE_VK_FUNC(vkGetPrivateDataEXT) \ - USE_VK_FUNC(vkGetQueryPoolResults) \ - USE_VK_FUNC(vkGetQueueCheckpointData2NV) \ - USE_VK_FUNC(vkGetQueueCheckpointDataNV) \ - USE_VK_FUNC(vkGetRayTracingCaptureReplayShaderGroupHandlesKHR) \ - USE_VK_FUNC(vkGetRayTracingShaderGroupHandlesKHR) \ - USE_VK_FUNC(vkGetRayTracingShaderGroupHandlesNV) \ - USE_VK_FUNC(vkGetRayTracingShaderGroupStackSizeKHR) \ - USE_VK_FUNC(vkGetRenderAreaGranularity) \ - USE_VK_FUNC(vkGetSamplerOpaqueCaptureDescriptorDataEXT) \ - USE_VK_FUNC(vkGetSemaphoreCounterValue) \ - USE_VK_FUNC(vkGetSemaphoreCounterValueKHR) \ - USE_VK_FUNC(vkGetShaderInfoAMD) \ - USE_VK_FUNC(vkGetShaderModuleCreateInfoIdentifierEXT) \ - USE_VK_FUNC(vkGetShaderModuleIdentifierEXT) \ - USE_VK_FUNC(vkGetSwapchainImagesKHR) \ - USE_VK_FUNC(vkGetValidationCacheDataEXT) \ - USE_VK_FUNC(vkInitializePerformanceApiINTEL) \ - USE_VK_FUNC(vkInvalidateMappedMemoryRanges) \ - USE_VK_FUNC(vkMapMemory) \ - USE_VK_FUNC(vkMergePipelineCaches) \ - USE_VK_FUNC(vkMergeValidationCachesEXT) \ - USE_VK_FUNC(vkQueueBeginDebugUtilsLabelEXT) \ - USE_VK_FUNC(vkQueueBindSparse) \ - USE_VK_FUNC(vkQueueEndDebugUtilsLabelEXT) \ - USE_VK_FUNC(vkQueueInsertDebugUtilsLabelEXT) \ - USE_VK_FUNC(vkQueuePresentKHR) \ - USE_VK_FUNC(vkQueueSetPerformanceConfigurationINTEL) \ - USE_VK_FUNC(vkQueueSubmit) \ - USE_VK_FUNC(vkQueueSubmit2) \ - USE_VK_FUNC(vkQueueSubmit2KHR) \ - USE_VK_FUNC(vkQueueWaitIdle) \ - USE_VK_FUNC(vkReleasePerformanceConfigurationINTEL) \ - USE_VK_FUNC(vkReleaseProfilingLockKHR) \ - USE_VK_FUNC(vkReleaseSwapchainImagesEXT) \ - USE_VK_FUNC(vkResetCommandBuffer) \ - USE_VK_FUNC(vkResetCommandPool) \ - USE_VK_FUNC(vkResetDescriptorPool) \ - USE_VK_FUNC(vkResetEvent) \ - USE_VK_FUNC(vkResetFences) \ - USE_VK_FUNC(vkResetQueryPool) \ - USE_VK_FUNC(vkResetQueryPoolEXT) \ - USE_VK_FUNC(vkSetDebugUtilsObjectNameEXT) \ - USE_VK_FUNC(vkSetDebugUtilsObjectTagEXT) \ - USE_VK_FUNC(vkSetDeviceMemoryPriorityEXT) \ - USE_VK_FUNC(vkSetEvent) \ - USE_VK_FUNC(vkSetPrivateData) \ - USE_VK_FUNC(vkSetPrivateDataEXT) \ - USE_VK_FUNC(vkSignalSemaphore) \ - USE_VK_FUNC(vkSignalSemaphoreKHR) \ - USE_VK_FUNC(vkTrimCommandPool) \ - USE_VK_FUNC(vkTrimCommandPoolKHR) \ - USE_VK_FUNC(vkUninitializePerformanceApiINTEL) \ - USE_VK_FUNC(vkUnmapMemory) \ - USE_VK_FUNC(vkUpdateDescriptorSetWithTemplate) \ - USE_VK_FUNC(vkUpdateDescriptorSetWithTemplateKHR) \ - USE_VK_FUNC(vkUpdateDescriptorSets) \ - USE_VK_FUNC(vkWaitForFences) \ - USE_VK_FUNC(vkWaitForPresentKHR) \ - USE_VK_FUNC(vkWaitSemaphores) \ - USE_VK_FUNC(vkWaitSemaphoresKHR) \ - USE_VK_FUNC(vkWriteAccelerationStructuresPropertiesKHR) \ - USE_VK_FUNC(vkWriteMicromapsPropertiesEXT) - -#define ALL_VK_INSTANCE_FUNCS() \ - USE_VK_FUNC(vkCreateDebugReportCallbackEXT) \ - USE_VK_FUNC(vkCreateDebugUtilsMessengerEXT) \ - USE_VK_FUNC(vkCreateWin32SurfaceKHR) \ - USE_VK_FUNC(vkDebugReportMessageEXT) \ - USE_VK_FUNC(vkDestroyDebugReportCallbackEXT) \ - USE_VK_FUNC(vkDestroyDebugUtilsMessengerEXT) \ - USE_VK_FUNC(vkDestroySurfaceKHR) \ - USE_VK_FUNC(vkEnumeratePhysicalDeviceGroups) \ - USE_VK_FUNC(vkEnumeratePhysicalDeviceGroupsKHR) \ - USE_VK_FUNC(vkEnumeratePhysicalDevices) \ - USE_VK_FUNC(vkSubmitDebugUtilsMessageEXT) \ - USE_VK_FUNC(vkCreateDevice) \ - USE_VK_FUNC(vkEnumerateDeviceExtensionProperties) \ - USE_VK_FUNC(vkEnumerateDeviceLayerProperties) \ - USE_VK_FUNC(vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR) \ - USE_VK_FUNC(vkGetPhysicalDeviceCalibrateableTimeDomainsEXT) \ - USE_VK_FUNC(vkGetPhysicalDeviceCooperativeMatrixPropertiesNV) \ - USE_VK_FUNC(vkGetPhysicalDeviceFeatures) \ - USE_VK_FUNC(vkGetPhysicalDeviceFeatures2) \ - USE_VK_FUNC(vkGetPhysicalDeviceFeatures2KHR) \ - USE_VK_FUNC(vkGetPhysicalDeviceFormatProperties) \ - USE_VK_FUNC(vkGetPhysicalDeviceFormatProperties2) \ - USE_VK_FUNC(vkGetPhysicalDeviceFormatProperties2KHR) \ - USE_VK_FUNC(vkGetPhysicalDeviceFragmentShadingRatesKHR) \ - USE_VK_FUNC(vkGetPhysicalDeviceImageFormatProperties) \ - USE_VK_FUNC(vkGetPhysicalDeviceImageFormatProperties2) \ - USE_VK_FUNC(vkGetPhysicalDeviceImageFormatProperties2KHR) \ - USE_VK_FUNC(vkGetPhysicalDeviceMemoryProperties) \ - USE_VK_FUNC(vkGetPhysicalDeviceMemoryProperties2) \ - USE_VK_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR) \ - USE_VK_FUNC(vkGetPhysicalDeviceMultisamplePropertiesEXT) \ - USE_VK_FUNC(vkGetPhysicalDeviceOpticalFlowImageFormatsNV) \ - USE_VK_FUNC(vkGetPhysicalDevicePresentRectanglesKHR) \ - USE_VK_FUNC(vkGetPhysicalDeviceProperties) \ - USE_VK_FUNC(vkGetPhysicalDeviceProperties2) \ - USE_VK_FUNC(vkGetPhysicalDeviceProperties2KHR) \ - USE_VK_FUNC(vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR) \ - USE_VK_FUNC(vkGetPhysicalDeviceQueueFamilyProperties) \ - USE_VK_FUNC(vkGetPhysicalDeviceQueueFamilyProperties2) \ - USE_VK_FUNC(vkGetPhysicalDeviceQueueFamilyProperties2KHR) \ - USE_VK_FUNC(vkGetPhysicalDeviceSparseImageFormatProperties) \ - USE_VK_FUNC(vkGetPhysicalDeviceSparseImageFormatProperties2) \ - USE_VK_FUNC(vkGetPhysicalDeviceSparseImageFormatProperties2KHR) \ - USE_VK_FUNC(vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV) \ - USE_VK_FUNC(vkGetPhysicalDeviceSurfaceCapabilities2KHR) \ - USE_VK_FUNC(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \ - USE_VK_FUNC(vkGetPhysicalDeviceSurfaceFormats2KHR) \ - USE_VK_FUNC(vkGetPhysicalDeviceSurfaceFormatsKHR) \ - USE_VK_FUNC(vkGetPhysicalDeviceSurfacePresentModesKHR) \ - USE_VK_FUNC(vkGetPhysicalDeviceSurfaceSupportKHR) \ - USE_VK_FUNC(vkGetPhysicalDeviceToolProperties) \ - USE_VK_FUNC(vkGetPhysicalDeviceToolPropertiesEXT) \ - USE_VK_FUNC(vkGetPhysicalDeviceWin32PresentationSupportKHR) - -#endif /* __WINE_VULKAN_THUNKS_H */ diff --git a/dlls/winevulkan/winevulkan.json b/dlls/winevulkan/winevulkan.json deleted file mode 100644 index d8c8c29fded..00000000000 --- a/dlls/winevulkan/winevulkan.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "file_format_version": "1.0.0", - "ICD": { - "library_path": ".\\winevulkan.dll", - "api_version": "1.3.237" - } -} diff --git a/dlls/winevulkan/winevulkan.spec b/dlls/winevulkan/winevulkan.spec deleted file mode 100644 index dceb3037700..00000000000 --- a/dlls/winevulkan/winevulkan.spec +++ /dev/null @@ -1,256 +0,0 @@ -# Automatically generated from Vulkan vk.xml; DO NOT EDIT! -# -# This file is generated from Vulkan vk.xml file covered -# by the following copyright and permission notice: -# -# Copyright 2015-2022 The Khronos Group Inc. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# - -@ stdcall -private vk_icdGetInstanceProcAddr(ptr str) -@ stdcall -private vk_icdGetPhysicalDeviceProcAddr(ptr str) -@ stdcall -private vk_icdNegotiateLoaderICDInterfaceVersion(ptr) -@ stdcall vkAcquireNextImage2KHR(ptr ptr ptr) -@ stdcall vkAcquireNextImageKHR(ptr int64 int64 int64 int64 ptr) -@ stdcall vkAllocateCommandBuffers(ptr ptr ptr) -@ stdcall vkAllocateDescriptorSets(ptr ptr ptr) -@ stdcall vkAllocateMemory(ptr ptr ptr ptr) -@ stdcall vkBeginCommandBuffer(ptr ptr) -@ stdcall vkBindBufferMemory(ptr int64 int64 int64) -@ stdcall vkBindBufferMemory2(ptr long ptr) -@ stdcall vkBindImageMemory(ptr int64 int64 int64) -@ stdcall vkBindImageMemory2(ptr long ptr) -@ stdcall vkCmdBeginQuery(ptr int64 long long) -@ stdcall vkCmdBeginRenderPass(ptr ptr long) -@ stdcall vkCmdBeginRenderPass2(ptr ptr ptr) -@ stdcall vkCmdBeginRendering(ptr ptr) -@ stdcall vkCmdBindDescriptorSets(ptr long int64 long long ptr long ptr) -@ stdcall vkCmdBindIndexBuffer(ptr int64 int64 long) -@ stdcall vkCmdBindPipeline(ptr long int64) -@ stdcall vkCmdBindVertexBuffers(ptr long long ptr ptr) -@ stdcall vkCmdBindVertexBuffers2(ptr long long ptr ptr ptr ptr) -@ stdcall vkCmdBlitImage(ptr int64 long int64 long long ptr long) -@ stdcall vkCmdBlitImage2(ptr ptr) -@ stdcall vkCmdClearAttachments(ptr long ptr long ptr) -@ stdcall vkCmdClearColorImage(ptr int64 long ptr long ptr) -@ stdcall vkCmdClearDepthStencilImage(ptr int64 long ptr long ptr) -@ stdcall vkCmdCopyBuffer(ptr int64 int64 long ptr) -@ stdcall vkCmdCopyBuffer2(ptr ptr) -@ stdcall vkCmdCopyBufferToImage(ptr int64 int64 long long ptr) -@ stdcall vkCmdCopyBufferToImage2(ptr ptr) -@ stdcall vkCmdCopyImage(ptr int64 long int64 long long ptr) -@ stdcall vkCmdCopyImage2(ptr ptr) -@ stdcall vkCmdCopyImageToBuffer(ptr int64 long int64 long ptr) -@ stdcall vkCmdCopyImageToBuffer2(ptr ptr) -@ stdcall vkCmdCopyQueryPoolResults(ptr int64 long long int64 int64 int64 long) -@ stdcall vkCmdDispatch(ptr long long long) -@ stdcall vkCmdDispatchBase(ptr long long long long long long) -@ stdcall vkCmdDispatchIndirect(ptr int64 int64) -@ stdcall vkCmdDraw(ptr long long long long) -@ stdcall vkCmdDrawIndexed(ptr long long long long long) -@ stdcall vkCmdDrawIndexedIndirect(ptr int64 int64 long long) -@ stdcall vkCmdDrawIndexedIndirectCount(ptr int64 int64 int64 int64 long long) -@ stdcall vkCmdDrawIndirect(ptr int64 int64 long long) -@ stdcall vkCmdDrawIndirectCount(ptr int64 int64 int64 int64 long long) -@ stdcall vkCmdEndQuery(ptr int64 long) -@ stdcall vkCmdEndRenderPass(ptr) -@ stdcall vkCmdEndRenderPass2(ptr ptr) -@ stdcall vkCmdEndRendering(ptr) -@ stdcall vkCmdExecuteCommands(ptr long ptr) -@ stdcall vkCmdFillBuffer(ptr int64 int64 int64 long) -@ stdcall vkCmdNextSubpass(ptr long) -@ stdcall vkCmdNextSubpass2(ptr ptr ptr) -@ stdcall vkCmdPipelineBarrier(ptr long long long long ptr long ptr long ptr) -@ stdcall vkCmdPipelineBarrier2(ptr ptr) -@ stdcall vkCmdPushConstants(ptr int64 long long long ptr) -@ stdcall vkCmdResetEvent(ptr int64 long) -@ stdcall vkCmdResetEvent2(ptr int64 int64) -@ stdcall vkCmdResetQueryPool(ptr int64 long long) -@ stdcall vkCmdResolveImage(ptr int64 long int64 long long ptr) -@ stdcall vkCmdResolveImage2(ptr ptr) -@ stdcall vkCmdSetBlendConstants(ptr ptr) -@ stdcall vkCmdSetCullMode(ptr long) -@ stdcall vkCmdSetDepthBias(ptr float float float) -@ stdcall vkCmdSetDepthBiasEnable(ptr long) -@ stdcall vkCmdSetDepthBounds(ptr float float) -@ stdcall vkCmdSetDepthBoundsTestEnable(ptr long) -@ stdcall vkCmdSetDepthCompareOp(ptr long) -@ stdcall vkCmdSetDepthTestEnable(ptr long) -@ stdcall vkCmdSetDepthWriteEnable(ptr long) -@ stdcall vkCmdSetDeviceMask(ptr long) -@ stdcall vkCmdSetEvent(ptr int64 long) -@ stdcall vkCmdSetEvent2(ptr int64 ptr) -@ stdcall vkCmdSetFrontFace(ptr long) -@ stdcall vkCmdSetLineWidth(ptr float) -@ stdcall vkCmdSetPrimitiveRestartEnable(ptr long) -@ stdcall vkCmdSetPrimitiveTopology(ptr long) -@ stdcall vkCmdSetRasterizerDiscardEnable(ptr long) -@ stdcall vkCmdSetScissor(ptr long long ptr) -@ stdcall vkCmdSetScissorWithCount(ptr long ptr) -@ stdcall vkCmdSetStencilCompareMask(ptr long long) -@ stdcall vkCmdSetStencilOp(ptr long long long long long) -@ stdcall vkCmdSetStencilReference(ptr long long) -@ stdcall vkCmdSetStencilTestEnable(ptr long) -@ stdcall vkCmdSetStencilWriteMask(ptr long long) -@ stdcall vkCmdSetViewport(ptr long long ptr) -@ stdcall vkCmdSetViewportWithCount(ptr long ptr) -@ stdcall vkCmdUpdateBuffer(ptr int64 int64 int64 ptr) -@ stdcall vkCmdWaitEvents(ptr long ptr long long long ptr long ptr long ptr) -@ stdcall vkCmdWaitEvents2(ptr long ptr ptr) -@ stdcall vkCmdWriteTimestamp(ptr long int64 long) -@ stdcall vkCmdWriteTimestamp2(ptr int64 int64 long) -@ stdcall vkCreateBuffer(ptr ptr ptr ptr) -@ stdcall vkCreateBufferView(ptr ptr ptr ptr) -@ stdcall vkCreateCommandPool(ptr ptr ptr ptr) -@ stdcall vkCreateComputePipelines(ptr int64 long ptr ptr ptr) -@ stdcall vkCreateDescriptorPool(ptr ptr ptr ptr) -@ stdcall vkCreateDescriptorSetLayout(ptr ptr ptr ptr) -@ stdcall vkCreateDescriptorUpdateTemplate(ptr ptr ptr ptr) -@ stdcall vkCreateDevice(ptr ptr ptr ptr) -@ stub vkCreateDisplayModeKHR -@ stub vkCreateDisplayPlaneSurfaceKHR -@ stdcall vkCreateEvent(ptr ptr ptr ptr) -@ stdcall vkCreateFence(ptr ptr ptr ptr) -@ stdcall vkCreateFramebuffer(ptr ptr ptr ptr) -@ stdcall vkCreateGraphicsPipelines(ptr int64 long ptr ptr ptr) -@ stdcall vkCreateImage(ptr ptr ptr ptr) -@ stdcall vkCreateImageView(ptr ptr ptr ptr) -@ stdcall vkCreateInstance(ptr ptr ptr) -@ stdcall vkCreatePipelineCache(ptr ptr ptr ptr) -@ stdcall vkCreatePipelineLayout(ptr ptr ptr ptr) -@ stdcall vkCreatePrivateDataSlot(ptr ptr ptr ptr) -@ stdcall vkCreateQueryPool(ptr ptr ptr ptr) -@ stdcall vkCreateRenderPass(ptr ptr ptr ptr) -@ stdcall vkCreateRenderPass2(ptr ptr ptr ptr) -@ stdcall vkCreateSampler(ptr ptr ptr ptr) -@ stdcall vkCreateSamplerYcbcrConversion(ptr ptr ptr ptr) -@ stdcall vkCreateSemaphore(ptr ptr ptr ptr) -@ stdcall vkCreateShaderModule(ptr ptr ptr ptr) -@ stub vkCreateSharedSwapchainsKHR -@ stdcall vkCreateSwapchainKHR(ptr ptr ptr ptr) -@ stdcall vkCreateWin32SurfaceKHR(ptr ptr ptr ptr) -@ stdcall vkDestroyBuffer(ptr int64 ptr) -@ stdcall vkDestroyBufferView(ptr int64 ptr) -@ stdcall vkDestroyCommandPool(ptr int64 ptr) -@ stdcall vkDestroyDescriptorPool(ptr int64 ptr) -@ stdcall vkDestroyDescriptorSetLayout(ptr int64 ptr) -@ stdcall vkDestroyDescriptorUpdateTemplate(ptr int64 ptr) -@ stdcall vkDestroyDevice(ptr ptr) -@ stdcall vkDestroyEvent(ptr int64 ptr) -@ stdcall vkDestroyFence(ptr int64 ptr) -@ stdcall vkDestroyFramebuffer(ptr int64 ptr) -@ stdcall vkDestroyImage(ptr int64 ptr) -@ stdcall vkDestroyImageView(ptr int64 ptr) -@ stdcall vkDestroyInstance(ptr ptr) -@ stdcall vkDestroyPipeline(ptr int64 ptr) -@ stdcall vkDestroyPipelineCache(ptr int64 ptr) -@ stdcall vkDestroyPipelineLayout(ptr int64 ptr) -@ stdcall vkDestroyPrivateDataSlot(ptr int64 ptr) -@ stdcall vkDestroyQueryPool(ptr int64 ptr) -@ stdcall vkDestroyRenderPass(ptr int64 ptr) -@ stdcall vkDestroySampler(ptr int64 ptr) -@ stdcall vkDestroySamplerYcbcrConversion(ptr int64 ptr) -@ stdcall vkDestroySemaphore(ptr int64 ptr) -@ stdcall vkDestroyShaderModule(ptr int64 ptr) -@ stdcall vkDestroySurfaceKHR(ptr int64 ptr) -@ stdcall vkDestroySwapchainKHR(ptr int64 ptr) -@ stdcall vkDeviceWaitIdle(ptr) -@ stdcall vkEndCommandBuffer(ptr) -@ stdcall vkEnumerateDeviceExtensionProperties(ptr str ptr ptr) -@ stdcall vkEnumerateDeviceLayerProperties(ptr ptr ptr) -@ stdcall vkEnumerateInstanceExtensionProperties(str ptr ptr) -@ stdcall vkEnumerateInstanceLayerProperties(ptr ptr) -@ stdcall vkEnumerateInstanceVersion(ptr) -@ stdcall vkEnumeratePhysicalDeviceGroups(ptr ptr ptr) -@ stdcall vkEnumeratePhysicalDevices(ptr ptr ptr) -@ stdcall vkFlushMappedMemoryRanges(ptr long ptr) -@ stdcall vkFreeCommandBuffers(ptr int64 long ptr) -@ stdcall vkFreeDescriptorSets(ptr int64 long ptr) -@ stdcall vkFreeMemory(ptr int64 ptr) -@ stdcall vkGetBufferDeviceAddress(ptr ptr) -@ stdcall vkGetBufferMemoryRequirements(ptr int64 ptr) -@ stdcall vkGetBufferMemoryRequirements2(ptr ptr ptr) -@ stdcall vkGetBufferOpaqueCaptureAddress(ptr ptr) -@ stdcall vkGetDescriptorSetLayoutSupport(ptr ptr ptr) -@ stdcall vkGetDeviceBufferMemoryRequirements(ptr ptr ptr) -@ stdcall vkGetDeviceGroupPeerMemoryFeatures(ptr long long long ptr) -@ stdcall vkGetDeviceGroupPresentCapabilitiesKHR(ptr ptr) -@ stdcall vkGetDeviceGroupSurfacePresentModesKHR(ptr int64 ptr) -@ stdcall vkGetDeviceImageMemoryRequirements(ptr ptr ptr) -@ stdcall vkGetDeviceImageSparseMemoryRequirements(ptr ptr ptr ptr) -@ stdcall vkGetDeviceMemoryCommitment(ptr int64 ptr) -@ stdcall vkGetDeviceMemoryOpaqueCaptureAddress(ptr ptr) -@ stdcall vkGetDeviceProcAddr(ptr str) -@ stdcall vkGetDeviceQueue(ptr long long ptr) -@ stdcall vkGetDeviceQueue2(ptr ptr ptr) -@ stub vkGetDisplayModePropertiesKHR -@ stub vkGetDisplayPlaneCapabilitiesKHR -@ stub vkGetDisplayPlaneSupportedDisplaysKHR -@ stdcall vkGetEventStatus(ptr int64) -@ stdcall vkGetFenceStatus(ptr int64) -@ stdcall vkGetImageMemoryRequirements(ptr int64 ptr) -@ stdcall vkGetImageMemoryRequirements2(ptr ptr ptr) -@ stdcall vkGetImageSparseMemoryRequirements(ptr int64 ptr ptr) -@ stdcall vkGetImageSparseMemoryRequirements2(ptr ptr ptr ptr) -@ stdcall vkGetImageSubresourceLayout(ptr int64 ptr ptr) -@ stdcall vkGetInstanceProcAddr(ptr str) -@ stub vkGetPhysicalDeviceDisplayPlanePropertiesKHR -@ stub vkGetPhysicalDeviceDisplayPropertiesKHR -@ stdcall vkGetPhysicalDeviceExternalBufferProperties(ptr ptr ptr) -@ stdcall vkGetPhysicalDeviceExternalFenceProperties(ptr ptr ptr) -@ stdcall vkGetPhysicalDeviceExternalSemaphoreProperties(ptr ptr ptr) -@ stdcall vkGetPhysicalDeviceFeatures(ptr ptr) -@ stdcall vkGetPhysicalDeviceFeatures2(ptr ptr) -@ stdcall vkGetPhysicalDeviceFormatProperties(ptr long ptr) -@ stdcall vkGetPhysicalDeviceFormatProperties2(ptr long ptr) -@ stdcall vkGetPhysicalDeviceImageFormatProperties(ptr long long long long long ptr) -@ stdcall vkGetPhysicalDeviceImageFormatProperties2(ptr ptr ptr) -@ stdcall vkGetPhysicalDeviceMemoryProperties(ptr ptr) -@ stdcall vkGetPhysicalDeviceMemoryProperties2(ptr ptr) -@ stdcall vkGetPhysicalDevicePresentRectanglesKHR(ptr int64 ptr ptr) -@ stdcall vkGetPhysicalDeviceProperties(ptr ptr) -@ stdcall vkGetPhysicalDeviceProperties2(ptr ptr) -@ stdcall vkGetPhysicalDeviceQueueFamilyProperties(ptr ptr ptr) -@ stdcall vkGetPhysicalDeviceQueueFamilyProperties2(ptr ptr ptr) -@ stdcall vkGetPhysicalDeviceSparseImageFormatProperties(ptr long long long long long ptr ptr) -@ stdcall vkGetPhysicalDeviceSparseImageFormatProperties2(ptr ptr ptr ptr) -@ stdcall vkGetPhysicalDeviceSurfaceCapabilities2KHR(ptr ptr ptr) -@ stdcall vkGetPhysicalDeviceSurfaceCapabilitiesKHR(ptr int64 ptr) -@ stdcall vkGetPhysicalDeviceSurfaceFormats2KHR(ptr ptr ptr ptr) -@ stdcall vkGetPhysicalDeviceSurfaceFormatsKHR(ptr int64 ptr ptr) -@ stdcall vkGetPhysicalDeviceSurfacePresentModesKHR(ptr int64 ptr ptr) -@ stdcall vkGetPhysicalDeviceSurfaceSupportKHR(ptr long int64 ptr) -@ stdcall vkGetPhysicalDeviceToolProperties(ptr ptr ptr) -@ stdcall vkGetPhysicalDeviceWin32PresentationSupportKHR(ptr long) -@ stdcall vkGetPipelineCacheData(ptr int64 ptr ptr) -@ stdcall vkGetPrivateData(ptr long int64 int64 ptr) -@ stdcall vkGetQueryPoolResults(ptr int64 long long long ptr int64 long) -@ stdcall vkGetRenderAreaGranularity(ptr int64 ptr) -@ stdcall vkGetSemaphoreCounterValue(ptr int64 ptr) -@ stdcall vkGetSwapchainImagesKHR(ptr int64 ptr ptr) -@ stdcall vkInvalidateMappedMemoryRanges(ptr long ptr) -@ stdcall vkMapMemory(ptr int64 int64 int64 long ptr) -@ stdcall vkMergePipelineCaches(ptr int64 long ptr) -@ stdcall vkQueueBindSparse(ptr long ptr int64) -@ stdcall vkQueuePresentKHR(ptr ptr) -@ stdcall vkQueueSubmit(ptr long ptr int64) -@ stdcall vkQueueSubmit2(ptr long ptr int64) -@ stdcall vkQueueWaitIdle(ptr) -@ stdcall vkResetCommandBuffer(ptr long) -@ stdcall vkResetCommandPool(ptr int64 long) -@ stdcall vkResetDescriptorPool(ptr int64 long) -@ stdcall vkResetEvent(ptr int64) -@ stdcall vkResetFences(ptr long ptr) -@ stdcall vkResetQueryPool(ptr int64 long long) -@ stdcall vkSetEvent(ptr int64) -@ stdcall vkSetPrivateData(ptr long int64 int64 int64) -@ stdcall vkSignalSemaphore(ptr ptr) -@ stdcall vkTrimCommandPool(ptr int64 long) -@ stdcall vkUnmapMemory(ptr int64) -@ stdcall vkUpdateDescriptorSetWithTemplate(ptr int64 int64 ptr) -@ stdcall vkUpdateDescriptorSets(ptr long ptr long ptr) -@ stdcall vkWaitForFences(ptr long ptr long int64) -@ stdcall vkWaitSemaphores(ptr ptr int64) -@ stdcall -private DllRegisterServer() -@ stdcall -private DllUnregisterServer() diff --git a/include/wine/vulkan.h b/include/wine/vulkan.h deleted file mode 100644 index 77c5cc02ae7..00000000000 --- a/include/wine/vulkan.h +++ /dev/null @@ -1,12636 +0,0 @@ -/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! - * - * This file is generated from Vulkan vk.xml file covered - * by the following copyright and permission notice: - * - * Copyright 2015-2022 The Khronos Group Inc. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#ifndef __WINE_VULKAN_H -#define __WINE_VULKAN_H - -#include -#include - -/* Define WINE_VK_HOST to get 'host' headers. */ -#ifdef WINE_VK_HOST -#define VKAPI_CALL -#define WINE_VK_ALIGN(x) -#endif - -#ifndef VKAPI_CALL -#define VKAPI_CALL __stdcall -#endif - -#ifndef VKAPI_PTR -#define VKAPI_PTR VKAPI_CALL -#endif - -#ifndef WINE_VK_ALIGN -#define WINE_VK_ALIGN DECLSPEC_ALIGN -#endif - -#define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256 -#define VK_UUID_SIZE 16 -#define VK_LUID_SIZE 8 -#define VK_LUID_SIZE_KHR VK_LUID_SIZE -#define VK_MAX_EXTENSION_NAME_SIZE 256 -#define VK_MAX_DESCRIPTION_SIZE 256 -#define VK_MAX_MEMORY_TYPES 32 -#define VK_MAX_MEMORY_HEAPS 16 -#define VK_LOD_CLAMP_NONE 1000.0F -#define VK_REMAINING_MIP_LEVELS (~0U) -#define VK_REMAINING_ARRAY_LAYERS (~0U) -#define VK_WHOLE_SIZE (~0ULL) -#define VK_ATTACHMENT_UNUSED (~0U) -#define VK_TRUE 1 -#define VK_FALSE 0 -#define VK_QUEUE_FAMILY_IGNORED (~0U) -#define VK_QUEUE_FAMILY_EXTERNAL (~1U) -#define VK_QUEUE_FAMILY_EXTERNAL_KHR VK_QUEUE_FAMILY_EXTERNAL -#define VK_QUEUE_FAMILY_FOREIGN_EXT (~2U) -#define VK_SUBPASS_EXTERNAL (~0U) -#define VK_MAX_DEVICE_GROUP_SIZE 32 -#define VK_MAX_DEVICE_GROUP_SIZE_KHR VK_MAX_DEVICE_GROUP_SIZE -#define VK_MAX_DRIVER_NAME_SIZE 256 -#define VK_MAX_DRIVER_NAME_SIZE_KHR VK_MAX_DRIVER_NAME_SIZE -#define VK_MAX_DRIVER_INFO_SIZE 256 -#define VK_MAX_DRIVER_INFO_SIZE_KHR VK_MAX_DRIVER_INFO_SIZE -#define VK_SHADER_UNUSED_KHR (~0U) -#define VK_SHADER_UNUSED_NV VK_SHADER_UNUSED_KHR -#define VK_MAX_GLOBAL_PRIORITY_SIZE_KHR 16 -#define VK_MAX_GLOBAL_PRIORITY_SIZE_EXT VK_MAX_GLOBAL_PRIORITY_SIZE_KHR -#define VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT 32 -#define VK_KHR_SURFACE_SPEC_VERSION 25 -#define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface" -#define VK_KHR_SWAPCHAIN_SPEC_VERSION 70 -#define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain" -#define VK_KHR_WIN32_SURFACE_SPEC_VERSION 6 -#define VK_KHR_WIN32_SURFACE_EXTENSION_NAME "VK_KHR_win32_surface" -#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 10 -#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report" -#define VK_NV_GLSL_SHADER_SPEC_VERSION 1 -#define VK_NV_GLSL_SHADER_EXTENSION_NAME "VK_NV_glsl_shader" -#define VK_EXT_DEPTH_RANGE_UNRESTRICTED_SPEC_VERSION 1 -#define VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME "VK_EXT_depth_range_unrestricted" -#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 3 -#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge" -#define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1 -#define VK_IMG_FILTER_CUBIC_EXTENSION_NAME "VK_IMG_filter_cubic" -#define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1 -#define VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME "VK_AMD_rasterization_order" -#define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1 -#define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME "VK_AMD_shader_trinary_minmax" -#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1 -#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter" -#define VK_EXT_DEBUG_MARKER_SPEC_VERSION 4 -#define VK_EXT_DEBUG_MARKER_EXTENSION_NAME "VK_EXT_debug_marker" -#define VK_AMD_GCN_SHADER_SPEC_VERSION 1 -#define VK_AMD_GCN_SHADER_EXTENSION_NAME "VK_AMD_gcn_shader" -#define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1 -#define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation" -#define VK_EXT_TRANSFORM_FEEDBACK_SPEC_VERSION 1 -#define VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME "VK_EXT_transform_feedback" -#define VK_NVX_BINARY_IMPORT_SPEC_VERSION 1 -#define VK_NVX_BINARY_IMPORT_EXTENSION_NAME "VK_NVX_binary_import" -#define VK_NVX_IMAGE_VIEW_HANDLE_SPEC_VERSION 2 -#define VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME "VK_NVX_image_view_handle" -#define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 2 -#define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count" -#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION 1 -#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME "VK_AMD_negative_viewport_height" -#define VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION 2 -#define VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME "VK_AMD_gpu_shader_half_float" -#define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1 -#define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot" -#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_SPEC_VERSION 1 -#define VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME "VK_AMD_texture_gather_bias_lod" -#define VK_AMD_SHADER_INFO_SPEC_VERSION 1 -#define VK_AMD_SHADER_INFO_EXTENSION_NAME "VK_AMD_shader_info" -#define VK_KHR_DYNAMIC_RENDERING_SPEC_VERSION 1 -#define VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME "VK_KHR_dynamic_rendering" -#define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_SPEC_VERSION 1 -#define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_EXTENSION_NAME "VK_AMD_shader_image_load_store_lod" -#define VK_NV_CORNER_SAMPLED_IMAGE_SPEC_VERSION 2 -#define VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME "VK_NV_corner_sampled_image" -#define VK_KHR_MULTIVIEW_SPEC_VERSION 1 -#define VK_KHR_MULTIVIEW_EXTENSION_NAME "VK_KHR_multiview" -#define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1 -#define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc" -#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 2 -#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2" -#define VK_KHR_DEVICE_GROUP_SPEC_VERSION 4 -#define VK_KHR_DEVICE_GROUP_EXTENSION_NAME "VK_KHR_device_group" -#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 2 -#define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags" -#define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1 -#define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters" -#define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1 -#define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME "VK_EXT_shader_subgroup_ballot" -#define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1 -#define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote" -#define VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_SPEC_VERSION 1 -#define VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME "VK_EXT_texture_compression_astc_hdr" -#define VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION 1 -#define VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME "VK_EXT_astc_decode_mode" -#define VK_EXT_PIPELINE_ROBUSTNESS_SPEC_VERSION 1 -#define VK_EXT_PIPELINE_ROBUSTNESS_EXTENSION_NAME "VK_EXT_pipeline_robustness" -#define VK_KHR_MAINTENANCE1_SPEC_VERSION VK_KHR_MAINTENANCE_1_SPEC_VERSION -#define VK_KHR_MAINTENANCE1_EXTENSION_NAME VK_KHR_MAINTENANCE_1_EXTENSION_NAME -#define VK_KHR_MAINTENANCE_1_SPEC_VERSION 2 -#define VK_KHR_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_maintenance1" -#define VK_KHR_DEVICE_GROUP_CREATION_SPEC_VERSION 1 -#define VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHR_device_group_creation" -#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_memory_capabilities" -#define VK_KHR_EXTERNAL_MEMORY_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME "VK_KHR_external_memory" -#define VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHR_external_memory_win32" -#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_semaphore_capabilities" -#define VK_KHR_EXTERNAL_SEMAPHORE_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_KHR_external_semaphore" -#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2 -#define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor" -#define VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION 2 -#define VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME "VK_EXT_conditional_rendering" -#define VK_KHR_SHADER_FLOAT16_INT8_SPEC_VERSION 1 -#define VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME "VK_KHR_shader_float16_int8" -#define VK_KHR_16BIT_STORAGE_SPEC_VERSION 1 -#define VK_KHR_16BIT_STORAGE_EXTENSION_NAME "VK_KHR_16bit_storage" -#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 2 -#define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present" -#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1 -#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template" -#define VK_NV_CLIP_SPACE_W_SCALING_SPEC_VERSION 1 -#define VK_NV_CLIP_SPACE_W_SCALING_EXTENSION_NAME "VK_NV_clip_space_w_scaling" -#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_SPEC_VERSION 1 -#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME "VK_NV_sample_mask_override_coverage" -#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_SPEC_VERSION 1 -#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME "VK_NV_geometry_shader_passthrough" -#define VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION VK_NV_VIEWPORT_ARRAY_2_SPEC_VERSION -#define VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME VK_NV_VIEWPORT_ARRAY_2_EXTENSION_NAME -#define VK_NV_VIEWPORT_ARRAY_2_SPEC_VERSION 1 -#define VK_NV_VIEWPORT_ARRAY_2_EXTENSION_NAME "VK_NV_viewport_array2" -#define VK_NV_VIEWPORT_SWIZZLE_SPEC_VERSION 1 -#define VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME "VK_NV_viewport_swizzle" -#define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 1 -#define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles" -#define VK_EXT_CONSERVATIVE_RASTERIZATION_SPEC_VERSION 1 -#define VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME "VK_EXT_conservative_rasterization" -#define VK_EXT_DEPTH_CLIP_ENABLE_SPEC_VERSION 1 -#define VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME "VK_EXT_depth_clip_enable" -#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 4 -#define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace" -#define VK_KHR_IMAGELESS_FRAMEBUFFER_SPEC_VERSION 1 -#define VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME "VK_KHR_imageless_framebuffer" -#define VK_KHR_CREATE_RENDERPASS_2_SPEC_VERSION 1 -#define VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME "VK_KHR_create_renderpass2" -#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_fence_capabilities" -#define VK_KHR_EXTERNAL_FENCE_SPEC_VERSION 1 -#define VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME "VK_KHR_external_fence" -#define VK_KHR_PERFORMANCE_QUERY_SPEC_VERSION 1 -#define VK_KHR_PERFORMANCE_QUERY_EXTENSION_NAME "VK_KHR_performance_query" -#define VK_KHR_MAINTENANCE2_SPEC_VERSION VK_KHR_MAINTENANCE_2_SPEC_VERSION -#define VK_KHR_MAINTENANCE2_EXTENSION_NAME VK_KHR_MAINTENANCE_2_EXTENSION_NAME -#define VK_KHR_MAINTENANCE_2_SPEC_VERSION 1 -#define VK_KHR_MAINTENANCE_2_EXTENSION_NAME "VK_KHR_maintenance2" -#define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1 -#define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2" -#define VK_KHR_VARIABLE_POINTERS_SPEC_VERSION 1 -#define VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME "VK_KHR_variable_pointers" -#define VK_EXT_QUEUE_FAMILY_FOREIGN_SPEC_VERSION 1 -#define VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME "VK_EXT_queue_family_foreign" -#define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 3 -#define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_KHR_dedicated_allocation" -#define VK_EXT_DEBUG_UTILS_SPEC_VERSION 2 -#define VK_EXT_DEBUG_UTILS_EXTENSION_NAME "VK_EXT_debug_utils" -#define VK_EXT_SAMPLER_FILTER_MINMAX_SPEC_VERSION 2 -#define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME "VK_EXT_sampler_filter_minmax" -#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_SPEC_VERSION 1 -#define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME "VK_KHR_storage_buffer_storage_class" -#define VK_AMD_GPU_SHADER_INT16_SPEC_VERSION 2 -#define VK_AMD_GPU_SHADER_INT16_EXTENSION_NAME "VK_AMD_gpu_shader_int16" -#define VK_AMD_MIXED_ATTACHMENT_SAMPLES_SPEC_VERSION 1 -#define VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME "VK_AMD_mixed_attachment_samples" -#define VK_AMD_SHADER_FRAGMENT_MASK_SPEC_VERSION 1 -#define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask" -#define VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION 1 -#define VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME "VK_EXT_inline_uniform_block" -#define VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION 1 -#define VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME "VK_EXT_shader_stencil_export" -#define VK_EXT_SAMPLE_LOCATIONS_SPEC_VERSION 1 -#define VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME "VK_EXT_sample_locations" -#define VK_KHR_RELAXED_BLOCK_LAYOUT_SPEC_VERSION 1 -#define VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME "VK_KHR_relaxed_block_layout" -#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_SPEC_VERSION 1 -#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME "VK_KHR_get_memory_requirements2" -#define VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION 1 -#define VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME "VK_KHR_image_format_list" -#define VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION 2 -#define VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME "VK_EXT_blend_operation_advanced" -#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_SPEC_VERSION 1 -#define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_EXTENSION_NAME "VK_NV_fragment_coverage_to_color" -#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_SPEC_VERSION 1 -#define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME "VK_NV_framebuffer_mixed_samples" -#define VK_NV_FILL_RECTANGLE_SPEC_VERSION 1 -#define VK_NV_FILL_RECTANGLE_EXTENSION_NAME "VK_NV_fill_rectangle" -#define VK_NV_SHADER_SM_BUILTINS_SPEC_VERSION 1 -#define VK_NV_SHADER_SM_BUILTINS_EXTENSION_NAME "VK_NV_shader_sm_builtins" -#define VK_EXT_POST_DEPTH_COVERAGE_SPEC_VERSION 1 -#define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage" -#define VK_KHR_SAMPLER_YCBCR_CONVERSION_SPEC_VERSION 14 -#define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME "VK_KHR_sampler_ycbcr_conversion" -#define VK_KHR_BIND_MEMORY_2_SPEC_VERSION 1 -#define VK_KHR_BIND_MEMORY_2_EXTENSION_NAME "VK_KHR_bind_memory2" -#define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1 -#define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache" -#define VK_EXT_DESCRIPTOR_INDEXING_SPEC_VERSION 2 -#define VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME "VK_EXT_descriptor_indexing" -#define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_SPEC_VERSION 1 -#define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME "VK_EXT_shader_viewport_index_layer" -#define VK_NV_SHADING_RATE_IMAGE_SPEC_VERSION 3 -#define VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME "VK_NV_shading_rate_image" -#define VK_NV_RAY_TRACING_SPEC_VERSION 3 -#define VK_NV_RAY_TRACING_EXTENSION_NAME "VK_NV_ray_tracing" -#define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_SPEC_VERSION 2 -#define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_EXTENSION_NAME "VK_NV_representative_fragment_test" -#define VK_KHR_MAINTENANCE3_SPEC_VERSION VK_KHR_MAINTENANCE_3_SPEC_VERSION -#define VK_KHR_MAINTENANCE3_EXTENSION_NAME VK_KHR_MAINTENANCE_3_EXTENSION_NAME -#define VK_KHR_MAINTENANCE_3_SPEC_VERSION 1 -#define VK_KHR_MAINTENANCE_3_EXTENSION_NAME "VK_KHR_maintenance3" -#define VK_KHR_DRAW_INDIRECT_COUNT_SPEC_VERSION 1 -#define VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_KHR_draw_indirect_count" -#define VK_EXT_FILTER_CUBIC_SPEC_VERSION 3 -#define VK_EXT_FILTER_CUBIC_EXTENSION_NAME "VK_EXT_filter_cubic" -#define VK_QCOM_RENDER_PASS_SHADER_RESOLVE_SPEC_VERSION 4 -#define VK_QCOM_RENDER_PASS_SHADER_RESOLVE_EXTENSION_NAME "VK_QCOM_render_pass_shader_resolve" -#define VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION 2 -#define VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME "VK_EXT_global_priority" -#define VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_SPEC_VERSION 1 -#define VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_EXTENSION_NAME "VK_KHR_shader_subgroup_extended_types" -#define VK_KHR_8BIT_STORAGE_SPEC_VERSION 1 -#define VK_KHR_8BIT_STORAGE_EXTENSION_NAME "VK_KHR_8bit_storage" -#define VK_EXT_EXTERNAL_MEMORY_HOST_SPEC_VERSION 1 -#define VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME "VK_EXT_external_memory_host" -#define VK_AMD_BUFFER_MARKER_SPEC_VERSION 1 -#define VK_AMD_BUFFER_MARKER_EXTENSION_NAME "VK_AMD_buffer_marker" -#define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1 -#define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64" -#define VK_KHR_SHADER_CLOCK_SPEC_VERSION 1 -#define VK_KHR_SHADER_CLOCK_EXTENSION_NAME "VK_KHR_shader_clock" -#define VK_AMD_PIPELINE_COMPILER_CONTROL_SPEC_VERSION 1 -#define VK_AMD_PIPELINE_COMPILER_CONTROL_EXTENSION_NAME "VK_AMD_pipeline_compiler_control" -#define VK_EXT_CALIBRATED_TIMESTAMPS_SPEC_VERSION 2 -#define VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME "VK_EXT_calibrated_timestamps" -#define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 2 -#define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties" -#define VK_KHR_GLOBAL_PRIORITY_SPEC_VERSION 1 -#define VK_KHR_GLOBAL_PRIORITY_EXTENSION_NAME "VK_KHR_global_priority" -#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_SPEC_VERSION 1 -#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME "VK_AMD_memory_overallocation_behavior" -#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 3 -#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor" -#define VK_EXT_PIPELINE_CREATION_FEEDBACK_SPEC_VERSION 1 -#define VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME "VK_EXT_pipeline_creation_feedback" -#define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1 -#define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties" -#define VK_KHR_SHADER_FLOAT_CONTROLS_SPEC_VERSION 4 -#define VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME "VK_KHR_shader_float_controls" -#define VK_NV_SHADER_SUBGROUP_PARTITIONED_SPEC_VERSION 1 -#define VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME "VK_NV_shader_subgroup_partitioned" -#define VK_KHR_DEPTH_STENCIL_RESOLVE_SPEC_VERSION 1 -#define VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME "VK_KHR_depth_stencil_resolve" -#define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_SPEC_VERSION 1 -#define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME "VK_KHR_swapchain_mutable_format" -#define VK_NV_COMPUTE_SHADER_DERIVATIVES_SPEC_VERSION 1 -#define VK_NV_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME "VK_NV_compute_shader_derivatives" -#define VK_NV_MESH_SHADER_SPEC_VERSION 1 -#define VK_NV_MESH_SHADER_EXTENSION_NAME "VK_NV_mesh_shader" -#define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1 -#define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_NV_fragment_shader_barycentric" -#define VK_NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION 2 -#define VK_NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME "VK_NV_shader_image_footprint" -#define VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION 1 -#define VK_NV_SCISSOR_EXCLUSIVE_EXTENSION_NAME "VK_NV_scissor_exclusive" -#define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_SPEC_VERSION 2 -#define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME "VK_NV_device_diagnostic_checkpoints" -#define VK_KHR_TIMELINE_SEMAPHORE_SPEC_VERSION 2 -#define VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME "VK_KHR_timeline_semaphore" -#define VK_INTEL_SHADER_INTEGER_FUNCTIONS_2_SPEC_VERSION 1 -#define VK_INTEL_SHADER_INTEGER_FUNCTIONS_2_EXTENSION_NAME "VK_INTEL_shader_integer_functions2" -#define VK_INTEL_PERFORMANCE_QUERY_SPEC_VERSION 2 -#define VK_INTEL_PERFORMANCE_QUERY_EXTENSION_NAME "VK_INTEL_performance_query" -#define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 3 -#define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model" -#define VK_EXT_PCI_BUS_INFO_SPEC_VERSION 2 -#define VK_EXT_PCI_BUS_INFO_EXTENSION_NAME "VK_EXT_pci_bus_info" -#define VK_KHR_SHADER_TERMINATE_INVOCATION_SPEC_VERSION 1 -#define VK_KHR_SHADER_TERMINATE_INVOCATION_EXTENSION_NAME "VK_KHR_shader_terminate_invocation" -#define VK_EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION 2 -#define VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME "VK_EXT_fragment_density_map" -#define VK_EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION 1 -#define VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME "VK_EXT_scalar_block_layout" -#define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION VK_GOOGLE_HLSL_FUNCTIONALITY_1_SPEC_VERSION -#define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME VK_GOOGLE_HLSL_FUNCTIONALITY_1_EXTENSION_NAME -#define VK_GOOGLE_HLSL_FUNCTIONALITY_1_SPEC_VERSION 1 -#define VK_GOOGLE_HLSL_FUNCTIONALITY_1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1" -#define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 1 -#define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string" -#define VK_EXT_SUBGROUP_SIZE_CONTROL_SPEC_VERSION 2 -#define VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME "VK_EXT_subgroup_size_control" -#define VK_KHR_FRAGMENT_SHADING_RATE_SPEC_VERSION 2 -#define VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME "VK_KHR_fragment_shading_rate" -#define VK_AMD_SHADER_CORE_PROPERTIES_2_SPEC_VERSION 1 -#define VK_AMD_SHADER_CORE_PROPERTIES_2_EXTENSION_NAME "VK_AMD_shader_core_properties2" -#define VK_AMD_DEVICE_COHERENT_MEMORY_SPEC_VERSION 1 -#define VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME "VK_AMD_device_coherent_memory" -#define VK_EXT_SHADER_IMAGE_ATOMIC_INT64_SPEC_VERSION 1 -#define VK_EXT_SHADER_IMAGE_ATOMIC_INT64_EXTENSION_NAME "VK_EXT_shader_image_atomic_int64" -#define VK_KHR_SPIRV_1_4_SPEC_VERSION 1 -#define VK_KHR_SPIRV_1_4_EXTENSION_NAME "VK_KHR_spirv_1_4" -#define VK_EXT_MEMORY_BUDGET_SPEC_VERSION 1 -#define VK_EXT_MEMORY_BUDGET_EXTENSION_NAME "VK_EXT_memory_budget" -#define VK_EXT_MEMORY_PRIORITY_SPEC_VERSION 1 -#define VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME "VK_EXT_memory_priority" -#define VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_SPEC_VERSION 1 -#define VK_NV_DEDICATED_ALLOCATION_IMAGE_ALIASING_EXTENSION_NAME "VK_NV_dedicated_allocation_image_aliasing" -#define VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_SPEC_VERSION 1 -#define VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_EXTENSION_NAME "VK_KHR_separate_depth_stencil_layouts" -#define VK_EXT_BUFFER_DEVICE_ADDRESS_SPEC_VERSION 2 -#define VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME "VK_EXT_buffer_device_address" -#define VK_EXT_TOOLING_INFO_SPEC_VERSION 1 -#define VK_EXT_TOOLING_INFO_EXTENSION_NAME "VK_EXT_tooling_info" -#define VK_EXT_SEPARATE_STENCIL_USAGE_SPEC_VERSION 1 -#define VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME "VK_EXT_separate_stencil_usage" -#define VK_EXT_VALIDATION_FEATURES_SPEC_VERSION 5 -#define VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME "VK_EXT_validation_features" -#define VK_KHR_PRESENT_WAIT_SPEC_VERSION 1 -#define VK_KHR_PRESENT_WAIT_EXTENSION_NAME "VK_KHR_present_wait" -#define VK_NV_COOPERATIVE_MATRIX_SPEC_VERSION 1 -#define VK_NV_COOPERATIVE_MATRIX_EXTENSION_NAME "VK_NV_cooperative_matrix" -#define VK_NV_COVERAGE_REDUCTION_MODE_SPEC_VERSION 1 -#define VK_NV_COVERAGE_REDUCTION_MODE_EXTENSION_NAME "VK_NV_coverage_reduction_mode" -#define VK_EXT_FRAGMENT_SHADER_INTERLOCK_SPEC_VERSION 1 -#define VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME "VK_EXT_fragment_shader_interlock" -#define VK_EXT_YCBCR_IMAGE_ARRAYS_SPEC_VERSION 1 -#define VK_EXT_YCBCR_IMAGE_ARRAYS_EXTENSION_NAME "VK_EXT_ycbcr_image_arrays" -#define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_SPEC_VERSION 1 -#define VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME "VK_KHR_uniform_buffer_standard_layout" -#define VK_EXT_PROVOKING_VERTEX_SPEC_VERSION 1 -#define VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME "VK_EXT_provoking_vertex" -#define VK_KHR_BUFFER_DEVICE_ADDRESS_SPEC_VERSION 1 -#define VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME "VK_KHR_buffer_device_address" -#define VK_EXT_LINE_RASTERIZATION_SPEC_VERSION 1 -#define VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME "VK_EXT_line_rasterization" -#define VK_EXT_SHADER_ATOMIC_FLOAT_SPEC_VERSION 1 -#define VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME "VK_EXT_shader_atomic_float" -#define VK_EXT_HOST_QUERY_RESET_SPEC_VERSION 1 -#define VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME "VK_EXT_host_query_reset" -#define VK_EXT_INDEX_TYPE_UINT8_SPEC_VERSION 1 -#define VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME "VK_EXT_index_type_uint8" -#define VK_EXT_EXTENDED_DYNAMIC_STATE_SPEC_VERSION 1 -#define VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME "VK_EXT_extended_dynamic_state" -#define VK_KHR_DEFERRED_HOST_OPERATIONS_SPEC_VERSION 4 -#define VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME "VK_KHR_deferred_host_operations" -#define VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_SPEC_VERSION 1 -#define VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME "VK_KHR_pipeline_executable_properties" -#define VK_EXT_SHADER_ATOMIC_FLOAT_2_SPEC_VERSION 1 -#define VK_EXT_SHADER_ATOMIC_FLOAT_2_EXTENSION_NAME "VK_EXT_shader_atomic_float2" -#define VK_EXT_SURFACE_MAINTENANCE_1_SPEC_VERSION 1 -#define VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME "VK_EXT_surface_maintenance1" -#define VK_EXT_SWAPCHAIN_MAINTENANCE_1_SPEC_VERSION 1 -#define VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME "VK_EXT_swapchain_maintenance1" -#define VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_SPEC_VERSION 1 -#define VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME "VK_EXT_shader_demote_to_helper_invocation" -#define VK_NV_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 3 -#define VK_NV_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NV_device_generated_commands" -#define VK_NV_INHERITED_VIEWPORT_SCISSOR_SPEC_VERSION 1 -#define VK_NV_INHERITED_VIEWPORT_SCISSOR_EXTENSION_NAME "VK_NV_inherited_viewport_scissor" -#define VK_KHR_SHADER_INTEGER_DOT_PRODUCT_SPEC_VERSION 1 -#define VK_KHR_SHADER_INTEGER_DOT_PRODUCT_EXTENSION_NAME "VK_KHR_shader_integer_dot_product" -#define VK_EXT_TEXEL_BUFFER_ALIGNMENT_SPEC_VERSION 1 -#define VK_EXT_TEXEL_BUFFER_ALIGNMENT_EXTENSION_NAME "VK_EXT_texel_buffer_alignment" -#define VK_QCOM_RENDER_PASS_TRANSFORM_SPEC_VERSION 3 -#define VK_QCOM_RENDER_PASS_TRANSFORM_EXTENSION_NAME "VK_QCOM_render_pass_transform" -#define VK_EXT_ROBUSTNESS_2_SPEC_VERSION 1 -#define VK_EXT_ROBUSTNESS_2_EXTENSION_NAME "VK_EXT_robustness2" -#define VK_EXT_CUSTOM_BORDER_COLOR_SPEC_VERSION 12 -#define VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME "VK_EXT_custom_border_color" -#define VK_GOOGLE_USER_TYPE_SPEC_VERSION 1 -#define VK_GOOGLE_USER_TYPE_EXTENSION_NAME "VK_GOOGLE_user_type" -#define VK_KHR_PIPELINE_LIBRARY_SPEC_VERSION 1 -#define VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME "VK_KHR_pipeline_library" -#define VK_NV_PRESENT_BARRIER_SPEC_VERSION 1 -#define VK_NV_PRESENT_BARRIER_EXTENSION_NAME "VK_NV_present_barrier" -#define VK_KHR_SHADER_NON_SEMANTIC_INFO_SPEC_VERSION 1 -#define VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME "VK_KHR_shader_non_semantic_info" -#define VK_KHR_PRESENT_ID_SPEC_VERSION 1 -#define VK_KHR_PRESENT_ID_EXTENSION_NAME "VK_KHR_present_id" -#define VK_EXT_PRIVATE_DATA_SPEC_VERSION 1 -#define VK_EXT_PRIVATE_DATA_EXTENSION_NAME "VK_EXT_private_data" -#define VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_SPEC_VERSION 3 -#define VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME "VK_EXT_pipeline_creation_cache_control" -#define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_SPEC_VERSION 2 -#define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME "VK_NV_device_diagnostics_config" -#define VK_QCOM_RENDER_PASS_STORE_OPS_SPEC_VERSION 2 -#define VK_QCOM_RENDER_PASS_STORE_OPS_EXTENSION_NAME "VK_QCOM_render_pass_store_ops" -#define VK_KHR_SYNCHRONIZATION_2_SPEC_VERSION 1 -#define VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME "VK_KHR_synchronization2" -#define VK_EXT_DESCRIPTOR_BUFFER_SPEC_VERSION 1 -#define VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME "VK_EXT_descriptor_buffer" -#define VK_EXT_GRAPHICS_PIPELINE_LIBRARY_SPEC_VERSION 1 -#define VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME "VK_EXT_graphics_pipeline_library" -#define VK_AMD_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_SPEC_VERSION 1 -#define VK_AMD_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_EXTENSION_NAME "VK_AMD_shader_early_and_late_fragment_tests" -#define VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1 -#define VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_KHR_fragment_shader_barycentric" -#define VK_KHR_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_SPEC_VERSION 1 -#define VK_KHR_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_EXTENSION_NAME "VK_KHR_shader_subgroup_uniform_control_flow" -#define VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_SPEC_VERSION 1 -#define VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_EXTENSION_NAME "VK_KHR_zero_initialize_workgroup_memory" -#define VK_NV_FRAGMENT_SHADING_RATE_ENUMS_SPEC_VERSION 1 -#define VK_NV_FRAGMENT_SHADING_RATE_ENUMS_EXTENSION_NAME "VK_NV_fragment_shading_rate_enums" -#define VK_NV_RAY_TRACING_MOTION_BLUR_SPEC_VERSION 1 -#define VK_NV_RAY_TRACING_MOTION_BLUR_EXTENSION_NAME "VK_NV_ray_tracing_motion_blur" -#define VK_EXT_YCBCR_2PLANE_444_FORMATS_SPEC_VERSION 1 -#define VK_EXT_YCBCR_2PLANE_444_FORMATS_EXTENSION_NAME "VK_EXT_ycbcr_2plane_444_formats" -#define VK_EXT_FRAGMENT_DENSITY_MAP_2_SPEC_VERSION 1 -#define VK_EXT_FRAGMENT_DENSITY_MAP_2_EXTENSION_NAME "VK_EXT_fragment_density_map2" -#define VK_QCOM_ROTATED_COPY_COMMANDS_SPEC_VERSION 1 -#define VK_QCOM_ROTATED_COPY_COMMANDS_EXTENSION_NAME "VK_QCOM_rotated_copy_commands" -#define VK_EXT_IMAGE_ROBUSTNESS_SPEC_VERSION 1 -#define VK_EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME "VK_EXT_image_robustness" -#define VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_SPEC_VERSION 1 -#define VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME "VK_KHR_workgroup_memory_explicit_layout" -#define VK_KHR_COPY_COMMANDS_2_SPEC_VERSION 1 -#define VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME "VK_KHR_copy_commands2" -#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SPEC_VERSION 1 -#define VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME "VK_EXT_image_compression_control" -#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_SPEC_VERSION 2 -#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_EXTENSION_NAME "VK_EXT_attachment_feedback_loop_layout" -#define VK_EXT_4444_FORMATS_SPEC_VERSION 1 -#define VK_EXT_4444_FORMATS_EXTENSION_NAME "VK_EXT_4444_formats" -#define VK_EXT_DEVICE_FAULT_SPEC_VERSION 1 -#define VK_EXT_DEVICE_FAULT_EXTENSION_NAME "VK_EXT_device_fault" -#define VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_SPEC_VERSION 1 -#define VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME "VK_ARM_rasterization_order_attachment_access" -#define VK_EXT_RGBA10X6_FORMATS_SPEC_VERSION 1 -#define VK_EXT_RGBA10X6_FORMATS_EXTENSION_NAME "VK_EXT_rgba10x6_formats" -#define VK_VALVE_MUTABLE_DESCRIPTOR_TYPE_SPEC_VERSION 1 -#define VK_VALVE_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME "VK_VALVE_mutable_descriptor_type" -#define VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_SPEC_VERSION 2 -#define VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME "VK_EXT_vertex_input_dynamic_state" -#define VK_EXT_DEVICE_ADDRESS_BINDING_REPORT_SPEC_VERSION 1 -#define VK_EXT_DEVICE_ADDRESS_BINDING_REPORT_EXTENSION_NAME "VK_EXT_device_address_binding_report" -#define VK_EXT_DEPTH_CLIP_CONTROL_SPEC_VERSION 1 -#define VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME "VK_EXT_depth_clip_control" -#define VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_SPEC_VERSION 1 -#define VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME "VK_EXT_primitive_topology_list_restart" -#define VK_KHR_FORMAT_FEATURE_FLAGS_2_SPEC_VERSION 2 -#define VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME "VK_KHR_format_feature_flags2" -#define VK_HUAWEI_SUBPASS_SHADING_SPEC_VERSION 2 -#define VK_HUAWEI_SUBPASS_SHADING_EXTENSION_NAME "VK_HUAWEI_subpass_shading" -#define VK_HUAWEI_INVOCATION_MASK_SPEC_VERSION 1 -#define VK_HUAWEI_INVOCATION_MASK_EXTENSION_NAME "VK_HUAWEI_invocation_mask" -#define VK_EXT_PIPELINE_PROPERTIES_SPEC_VERSION 1 -#define VK_EXT_PIPELINE_PROPERTIES_EXTENSION_NAME "VK_EXT_pipeline_properties" -#define VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_SPEC_VERSION 1 -#define VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_EXTENSION_NAME "VK_EXT_multisampled_render_to_single_sampled" -#define VK_EXT_EXTENDED_DYNAMIC_STATE_2_SPEC_VERSION 1 -#define VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME "VK_EXT_extended_dynamic_state2" -#define VK_EXT_COLOR_WRITE_ENABLE_SPEC_VERSION 1 -#define VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME "VK_EXT_color_write_enable" -#define VK_EXT_PRIMITIVES_GENERATED_QUERY_SPEC_VERSION 1 -#define VK_EXT_PRIMITIVES_GENERATED_QUERY_EXTENSION_NAME "VK_EXT_primitives_generated_query" -#define VK_KHR_RAY_TRACING_MAINTENANCE_1_SPEC_VERSION 1 -#define VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_ray_tracing_maintenance1" -#define VK_EXT_GLOBAL_PRIORITY_QUERY_SPEC_VERSION 1 -#define VK_EXT_GLOBAL_PRIORITY_QUERY_EXTENSION_NAME "VK_EXT_global_priority_query" -#define VK_EXT_IMAGE_VIEW_MIN_LOD_SPEC_VERSION 1 -#define VK_EXT_IMAGE_VIEW_MIN_LOD_EXTENSION_NAME "VK_EXT_image_view_min_lod" -#define VK_EXT_MULTI_DRAW_SPEC_VERSION 1 -#define VK_EXT_MULTI_DRAW_EXTENSION_NAME "VK_EXT_multi_draw" -#define VK_EXT_IMAGE_2D_VIEW_OF_3D_SPEC_VERSION 1 -#define VK_EXT_IMAGE_2D_VIEW_OF_3D_EXTENSION_NAME "VK_EXT_image_2d_view_of_3d" -#define VK_KHR_PORTABILITY_ENUMERATION_SPEC_VERSION 1 -#define VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME "VK_KHR_portability_enumeration" -#define VK_EXT_OPACITY_MICROMAP_SPEC_VERSION 2 -#define VK_EXT_OPACITY_MICROMAP_EXTENSION_NAME "VK_EXT_opacity_micromap" -#define VK_EXT_LOAD_STORE_OP_NONE_SPEC_VERSION 1 -#define VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME "VK_EXT_load_store_op_none" -#define VK_EXT_BORDER_COLOR_SWIZZLE_SPEC_VERSION 1 -#define VK_EXT_BORDER_COLOR_SWIZZLE_EXTENSION_NAME "VK_EXT_border_color_swizzle" -#define VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_SPEC_VERSION 1 -#define VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_EXTENSION_NAME "VK_EXT_pageable_device_local_memory" -#define VK_KHR_MAINTENANCE_4_SPEC_VERSION 2 -#define VK_KHR_MAINTENANCE_4_EXTENSION_NAME "VK_KHR_maintenance4" -#define VK_VALVE_DESCRIPTOR_SET_HOST_MAPPING_SPEC_VERSION 1 -#define VK_VALVE_DESCRIPTOR_SET_HOST_MAPPING_EXTENSION_NAME "VK_VALVE_descriptor_set_host_mapping" -#define VK_EXT_DEPTH_CLAMP_ZERO_ONE_SPEC_VERSION 1 -#define VK_EXT_DEPTH_CLAMP_ZERO_ONE_EXTENSION_NAME "VK_EXT_depth_clamp_zero_one" -#define VK_EXT_NON_SEAMLESS_CUBE_MAP_SPEC_VERSION 1 -#define VK_EXT_NON_SEAMLESS_CUBE_MAP_EXTENSION_NAME "VK_EXT_non_seamless_cube_map" -#define VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_SPEC_VERSION 1 -#define VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_EXTENSION_NAME "VK_QCOM_fragment_density_map_offset" -#define VK_NV_COPY_MEMORY_INDIRECT_SPEC_VERSION 1 -#define VK_NV_COPY_MEMORY_INDIRECT_EXTENSION_NAME "VK_NV_copy_memory_indirect" -#define VK_NV_MEMORY_DECOMPRESSION_SPEC_VERSION 1 -#define VK_NV_MEMORY_DECOMPRESSION_EXTENSION_NAME "VK_NV_memory_decompression" -#define VK_NV_LINEAR_COLOR_ATTACHMENT_SPEC_VERSION 1 -#define VK_NV_LINEAR_COLOR_ATTACHMENT_EXTENSION_NAME "VK_NV_linear_color_attachment" -#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_SPEC_VERSION 1 -#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_EXTENSION_NAME "VK_EXT_image_compression_control_swapchain" -#define VK_QCOM_IMAGE_PROCESSING_SPEC_VERSION 1 -#define VK_QCOM_IMAGE_PROCESSING_EXTENSION_NAME "VK_QCOM_image_processing" -#define VK_EXT_EXTENDED_DYNAMIC_STATE_3_SPEC_VERSION 2 -#define VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME "VK_EXT_extended_dynamic_state3" -#define VK_EXT_SUBPASS_MERGE_FEEDBACK_SPEC_VERSION 2 -#define VK_EXT_SUBPASS_MERGE_FEEDBACK_EXTENSION_NAME "VK_EXT_subpass_merge_feedback" -#define VK_EXT_SHADER_MODULE_IDENTIFIER_SPEC_VERSION 1 -#define VK_EXT_SHADER_MODULE_IDENTIFIER_EXTENSION_NAME "VK_EXT_shader_module_identifier" -#define VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_SPEC_VERSION 1 -#define VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME "VK_EXT_rasterization_order_attachment_access" -#define VK_NV_OPTICAL_FLOW_SPEC_VERSION 1 -#define VK_NV_OPTICAL_FLOW_EXTENSION_NAME "VK_NV_optical_flow" -#define VK_EXT_LEGACY_DITHERING_SPEC_VERSION 1 -#define VK_EXT_LEGACY_DITHERING_EXTENSION_NAME "VK_EXT_legacy_dithering" -#define VK_EXT_PIPELINE_PROTECTED_ACCESS_SPEC_VERSION 1 -#define VK_EXT_PIPELINE_PROTECTED_ACCESS_EXTENSION_NAME "VK_EXT_pipeline_protected_access" -#define VK_QCOM_TILE_PROPERTIES_SPEC_VERSION 1 -#define VK_QCOM_TILE_PROPERTIES_EXTENSION_NAME "VK_QCOM_tile_properties" -#define VK_QCOM_MULTIVIEW_PER_VIEW_VIEWPORTS_SPEC_VERSION 1 -#define VK_QCOM_MULTIVIEW_PER_VIEW_VIEWPORTS_EXTENSION_NAME "VK_QCOM_multiview_per_view_viewports" -#define VK_NV_RAY_TRACING_INVOCATION_REORDER_SPEC_VERSION 1 -#define VK_NV_RAY_TRACING_INVOCATION_REORDER_EXTENSION_NAME "VK_NV_ray_tracing_invocation_reorder" -#define VK_EXT_MUTABLE_DESCRIPTOR_TYPE_SPEC_VERSION 1 -#define VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME "VK_EXT_mutable_descriptor_type" -#define VK_ARM_SHADER_CORE_BUILTINS_SPEC_VERSION 2 -#define VK_ARM_SHADER_CORE_BUILTINS_EXTENSION_NAME "VK_ARM_shader_core_builtins" -#define VK_KHR_ACCELERATION_STRUCTURE_SPEC_VERSION 13 -#define VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME "VK_KHR_acceleration_structure" -#define VK_KHR_RAY_TRACING_PIPELINE_SPEC_VERSION 1 -#define VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME "VK_KHR_ray_tracing_pipeline" -#define VK_KHR_RAY_QUERY_SPEC_VERSION 1 -#define VK_KHR_RAY_QUERY_EXTENSION_NAME "VK_KHR_ray_query" -#define VK_EXT_MESH_SHADER_SPEC_VERSION 1 -#define VK_EXT_MESH_SHADER_EXTENSION_NAME "VK_EXT_mesh_shader" - -#define VK_MAKE_VERSION(major, minor, patch) \ - ((((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch))) -#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) -#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3FFU) -#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) -#define VK_MAKE_API_VERSION(variant, major, minor, patch) \ - ((((uint32_t)(variant)) << 29) | (((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch))) -#define VK_API_VERSION_VARIANT(version) ((uint32_t)(version) >> 29) -#define VK_API_VERSION_MAJOR(version) (((uint32_t)(version) >> 22) & 0x7FU) -#define VK_API_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3FFU) -#define VK_API_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) -#define VK_API_VERSION_1_0 VK_MAKE_API_VERSION(0, 1, 0, 0) -#define VK_API_VERSION_1_1 VK_MAKE_API_VERSION(0, 1, 1, 0) -#define VK_API_VERSION_1_2 VK_MAKE_API_VERSION(0, 1, 2, 0) -#define VK_API_VERSION_1_3 VK_MAKE_API_VERSION(0, 1, 3, 0) -#define VK_HEADER_VERSION 237 -#define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(0, 1, 3, VK_HEADER_VERSION) -#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; -#define VK_USE_64_BIT_PTR_DEFINES 0 - -#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE - #if (VK_USE_64_BIT_PTR_DEFINES==1) - #if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201103L)) - #define VK_NULL_HANDLE nullptr - #else - #define VK_NULL_HANDLE ((void*)0) - #endif - #else - #define VK_NULL_HANDLE 0ULL - #endif -#endif -#ifndef VK_NULL_HANDLE - #define VK_NULL_HANDLE 0 -#endif - -#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE - #if (VK_USE_64_BIT_PTR_DEFINES==1) - #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; - #else - #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; - #endif -#endif -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureKHR) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNV) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBufferView) -VK_DEFINE_HANDLE(VkCommandBuffer) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCuFunctionNVX) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCuModuleNVX) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugUtilsMessengerEXT) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeferredOperationKHR) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplate) -typedef VkDescriptorUpdateTemplate VkDescriptorUpdateTemplateKHR; -VK_DEFINE_HANDLE(VkDevice) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDeviceMemory) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkEvent) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNV) -VK_DEFINE_HANDLE(VkInstance) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkMicromapEXT) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkOpticalFlowSessionNV) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPerformanceConfigurationINTEL) -VK_DEFINE_HANDLE(VkPhysicalDevice) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipeline) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineCache) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPrivateDataSlot) -typedef VkPrivateDataSlot VkPrivateDataSlotEXT; -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkQueryPool) -VK_DEFINE_HANDLE(VkQueue) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkRenderPass) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSampler) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSamplerYcbcrConversion) -typedef VkSamplerYcbcrConversion VkSamplerYcbcrConversionKHR; -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkValidationCacheEXT) - -struct AHardwareBuffer; -struct ANativeWindow; -struct CAMetalLayer; -struct IOSurfaceRef; -struct MTLBuffer_id; -struct MTLCommandQueue_id; -struct MTLDevice_id; -struct MTLSharedEvent_id; -struct MTLTexture_id; -typedef uint32_t VkBool32; -typedef uint64_t VkDeviceAddress; -typedef uint64_t VkDeviceSize; -typedef uint32_t VkFlags; -typedef uint64_t VkFlags64; -typedef void* VkRemoteAddressNV; -typedef uint32_t VkSampleMask; - -typedef VkFlags VkAccelerationStructureCreateFlagsKHR; -typedef VkFlags VkAccelerationStructureMotionInfoFlagsNV; -typedef VkFlags VkAccelerationStructureMotionInstanceFlagsNV; -typedef VkFlags VkAccessFlags; -typedef VkFlags64 VkAccessFlags2; -typedef VkAccessFlags2 VkAccessFlags2KHR; -typedef VkFlags VkAcquireProfilingLockFlagsKHR; -typedef VkFlags VkAndroidSurfaceCreateFlagsKHR; -typedef VkFlags VkAttachmentDescriptionFlags; -typedef VkFlags VkBufferCreateFlags; -typedef VkFlags VkBufferUsageFlags; -typedef VkFlags VkBufferViewCreateFlags; -typedef VkFlags VkBuildAccelerationStructureFlagsKHR; -typedef VkBuildAccelerationStructureFlagsKHR VkBuildAccelerationStructureFlagsNV; -typedef VkFlags VkBuildMicromapFlagsEXT; -typedef VkFlags VkColorComponentFlags; -typedef VkFlags VkCommandBufferResetFlags; -typedef VkFlags VkCommandBufferUsageFlags; -typedef VkFlags VkCommandPoolCreateFlags; -typedef VkFlags VkCommandPoolResetFlags; -typedef VkFlags VkCommandPoolTrimFlags; -typedef VkCommandPoolTrimFlags VkCommandPoolTrimFlagsKHR; -typedef VkFlags VkCompositeAlphaFlagsKHR; -typedef VkFlags VkConditionalRenderingFlagsEXT; -typedef VkFlags VkCullModeFlags; -typedef VkFlags VkDebugReportFlagsEXT; -typedef VkFlags VkDebugUtilsMessageSeverityFlagsEXT; -typedef VkFlags VkDebugUtilsMessageTypeFlagsEXT; -typedef VkFlags VkDebugUtilsMessengerCallbackDataFlagsEXT; -typedef VkFlags VkDebugUtilsMessengerCreateFlagsEXT; -typedef VkFlags VkDependencyFlags; -typedef VkFlags VkDescriptorBindingFlags; -typedef VkDescriptorBindingFlags VkDescriptorBindingFlagsEXT; -typedef VkFlags VkDescriptorPoolCreateFlags; -typedef VkFlags VkDescriptorPoolResetFlags; -typedef VkFlags VkDescriptorSetLayoutCreateFlags; -typedef VkFlags VkDescriptorUpdateTemplateCreateFlags; -typedef VkDescriptorUpdateTemplateCreateFlags VkDescriptorUpdateTemplateCreateFlagsKHR; -typedef VkFlags VkDeviceAddressBindingFlagsEXT; -typedef VkFlags VkDeviceCreateFlags; -typedef VkFlags VkDeviceDiagnosticsConfigFlagsNV; -typedef VkFlags VkDeviceGroupPresentModeFlagsKHR; -typedef VkFlags VkDeviceMemoryReportFlagsEXT; -typedef VkFlags VkDeviceQueueCreateFlags; -typedef VkFlags VkDirectDriverLoadingFlagsLUNARG; -typedef VkFlags VkDirectFBSurfaceCreateFlagsEXT; -typedef VkFlags VkDisplayModeCreateFlagsKHR; -typedef VkFlags VkDisplayPlaneAlphaFlagsKHR; -typedef VkFlags VkDisplaySurfaceCreateFlagsKHR; -typedef VkFlags VkEventCreateFlags; -typedef VkFlags VkExportMetalObjectTypeFlagsEXT; -typedef VkFlags VkExternalFenceFeatureFlags; -typedef VkExternalFenceFeatureFlags VkExternalFenceFeatureFlagsKHR; -typedef VkFlags VkExternalFenceHandleTypeFlags; -typedef VkExternalFenceHandleTypeFlags VkExternalFenceHandleTypeFlagsKHR; -typedef VkFlags VkExternalMemoryFeatureFlags; -typedef VkExternalMemoryFeatureFlags VkExternalMemoryFeatureFlagsKHR; -typedef VkFlags VkExternalMemoryFeatureFlagsNV; -typedef VkFlags VkExternalMemoryHandleTypeFlags; -typedef VkExternalMemoryHandleTypeFlags VkExternalMemoryHandleTypeFlagsKHR; -typedef VkFlags VkExternalMemoryHandleTypeFlagsNV; -typedef VkFlags VkExternalSemaphoreFeatureFlags; -typedef VkExternalSemaphoreFeatureFlags VkExternalSemaphoreFeatureFlagsKHR; -typedef VkFlags VkExternalSemaphoreHandleTypeFlags; -typedef VkExternalSemaphoreHandleTypeFlags VkExternalSemaphoreHandleTypeFlagsKHR; -typedef VkFlags VkFenceCreateFlags; -typedef VkFlags VkFenceImportFlags; -typedef VkFenceImportFlags VkFenceImportFlagsKHR; -typedef VkFlags VkFormatFeatureFlags; -typedef VkFlags64 VkFormatFeatureFlags2; -typedef VkFormatFeatureFlags2 VkFormatFeatureFlags2KHR; -typedef VkFlags VkFramebufferCreateFlags; -typedef VkFlags VkGeometryFlagsKHR; -typedef VkGeometryFlagsKHR VkGeometryFlagsNV; -typedef VkFlags VkGeometryInstanceFlagsKHR; -typedef VkGeometryInstanceFlagsKHR VkGeometryInstanceFlagsNV; -typedef VkFlags VkGraphicsPipelineLibraryFlagsEXT; -typedef VkFlags VkHeadlessSurfaceCreateFlagsEXT; -typedef VkFlags VkIOSSurfaceCreateFlagsMVK; -typedef VkFlags VkImageAspectFlags; -typedef VkFlags VkImageCompressionFixedRateFlagsEXT; -typedef VkFlags VkImageCompressionFlagsEXT; -typedef VkFlags VkImageConstraintsInfoFlagsFUCHSIA; -typedef VkFlags VkImageCreateFlags; -typedef VkFlags VkImageFormatConstraintsFlagsFUCHSIA; -typedef VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA; -typedef VkFlags VkImageUsageFlags; -typedef VkFlags VkImageViewCreateFlags; -typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNV; -typedef VkFlags VkIndirectStateFlagsNV; -typedef VkFlags VkInstanceCreateFlags; -typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; -typedef VkFlags VkMemoryAllocateFlags; -typedef VkMemoryAllocateFlags VkMemoryAllocateFlagsKHR; -typedef VkFlags64 VkMemoryDecompressionMethodFlagsNV; -typedef VkFlags VkMemoryHeapFlags; -typedef VkFlags VkMemoryMapFlags; -typedef VkFlags VkMemoryPropertyFlags; -typedef VkFlags VkMetalSurfaceCreateFlagsEXT; -typedef VkFlags VkMicromapCreateFlagsEXT; -typedef VkFlags VkOpticalFlowExecuteFlagsNV; -typedef VkFlags VkOpticalFlowGridSizeFlagsNV; -typedef VkFlags VkOpticalFlowSessionCreateFlagsNV; -typedef VkFlags VkOpticalFlowUsageFlagsNV; -typedef VkFlags VkPeerMemoryFeatureFlags; -typedef VkPeerMemoryFeatureFlags VkPeerMemoryFeatureFlagsKHR; -typedef VkFlags VkPerformanceCounterDescriptionFlagsKHR; -typedef VkFlags VkPipelineCacheCreateFlags; -typedef VkFlags VkPipelineColorBlendStateCreateFlags; -typedef VkFlags VkPipelineCompilerControlFlagsAMD; -typedef VkFlags VkPipelineCoverageModulationStateCreateFlagsNV; -typedef VkFlags VkPipelineCoverageReductionStateCreateFlagsNV; -typedef VkFlags VkPipelineCoverageToColorStateCreateFlagsNV; -typedef VkFlags VkPipelineCreateFlags; -typedef VkFlags VkPipelineCreationFeedbackFlags; -typedef VkPipelineCreationFeedbackFlags VkPipelineCreationFeedbackFlagsEXT; -typedef VkFlags VkPipelineDepthStencilStateCreateFlags; -typedef VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT; -typedef VkFlags VkPipelineDynamicStateCreateFlags; -typedef VkFlags VkPipelineInputAssemblyStateCreateFlags; -typedef VkFlags VkPipelineLayoutCreateFlags; -typedef VkFlags VkPipelineMultisampleStateCreateFlags; -typedef VkFlags VkPipelineRasterizationConservativeStateCreateFlagsEXT; -typedef VkFlags VkPipelineRasterizationDepthClipStateCreateFlagsEXT; -typedef VkFlags VkPipelineRasterizationStateCreateFlags; -typedef VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT; -typedef VkFlags VkPipelineShaderStageCreateFlags; -typedef VkFlags VkPipelineStageFlags; -typedef VkFlags64 VkPipelineStageFlags2; -typedef VkPipelineStageFlags2 VkPipelineStageFlags2KHR; -typedef VkFlags VkPipelineTessellationStateCreateFlags; -typedef VkFlags VkPipelineVertexInputStateCreateFlags; -typedef VkFlags VkPipelineViewportStateCreateFlags; -typedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV; -typedef VkFlags VkPresentGravityFlagsEXT; -typedef VkFlags VkPresentScalingFlagsEXT; -typedef VkFlags VkPrivateDataSlotCreateFlags; -typedef VkPrivateDataSlotCreateFlags VkPrivateDataSlotCreateFlagsEXT; -typedef VkFlags VkQueryControlFlags; -typedef VkFlags VkQueryPipelineStatisticFlags; -typedef VkFlags VkQueryPoolCreateFlags; -typedef VkFlags VkQueryResultFlags; -typedef VkFlags VkQueueFlags; -typedef VkFlags VkRenderPassCreateFlags; -typedef VkFlags VkRenderingFlags; -typedef VkRenderingFlags VkRenderingFlagsKHR; -typedef VkFlags VkResolveModeFlags; -typedef VkResolveModeFlags VkResolveModeFlagsKHR; -typedef VkFlags VkSampleCountFlags; -typedef VkFlags VkSamplerCreateFlags; -typedef VkFlags VkScreenSurfaceCreateFlagsQNX; -typedef VkFlags VkSemaphoreCreateFlags; -typedef VkFlags VkSemaphoreImportFlags; -typedef VkSemaphoreImportFlags VkSemaphoreImportFlagsKHR; -typedef VkFlags VkSemaphoreWaitFlags; -typedef VkSemaphoreWaitFlags VkSemaphoreWaitFlagsKHR; -typedef VkFlags VkShaderCorePropertiesFlagsAMD; -typedef VkFlags VkShaderModuleCreateFlags; -typedef VkFlags VkShaderStageFlags; -typedef VkFlags VkSparseImageFormatFlags; -typedef VkFlags VkSparseMemoryBindFlags; -typedef VkFlags VkStencilFaceFlags; -typedef VkFlags VkStreamDescriptorSurfaceCreateFlagsGGP; -typedef VkFlags VkSubgroupFeatureFlags; -typedef VkFlags VkSubmitFlags; -typedef VkSubmitFlags VkSubmitFlagsKHR; -typedef VkFlags VkSubpassDescriptionFlags; -typedef VkFlags VkSurfaceCounterFlagsEXT; -typedef VkFlags VkSurfaceTransformFlagsKHR; -typedef VkFlags VkSwapchainCreateFlagsKHR; -typedef VkFlags VkSwapchainImageUsageFlagsANDROID; -typedef VkFlags VkToolPurposeFlags; -typedef VkToolPurposeFlags VkToolPurposeFlagsEXT; -typedef VkFlags VkValidationCacheCreateFlagsEXT; -typedef VkFlags VkViSurfaceCreateFlagsNN; -typedef VkFlags VkVideoBeginCodingFlagsKHR; -typedef VkFlags VkVideoCapabilityFlagsKHR; -typedef VkFlags VkVideoChromaSubsamplingFlagsKHR; -typedef VkFlags VkVideoCodecOperationFlagsKHR; -typedef VkFlags VkVideoCodingControlFlagsKHR; -typedef VkFlags VkVideoComponentBitDepthFlagsKHR; -typedef VkFlags VkVideoDecodeCapabilityFlagsKHR; -typedef VkFlags VkVideoDecodeFlagsKHR; -typedef VkFlags VkVideoDecodeH264PictureLayoutFlagsEXT; -typedef VkFlags VkVideoDecodeUsageFlagsKHR; -typedef VkFlags VkVideoEncodeCapabilityFlagsKHR; -typedef VkFlags VkVideoEncodeContentFlagsKHR; -typedef VkFlags VkVideoEncodeFlagsKHR; -typedef VkFlags VkVideoEncodeH264CapabilityFlagsEXT; -typedef VkFlags VkVideoEncodeH264InputModeFlagsEXT; -typedef VkFlags VkVideoEncodeH264OutputModeFlagsEXT; -typedef VkFlags VkVideoEncodeH265CapabilityFlagsEXT; -typedef VkFlags VkVideoEncodeH265CtbSizeFlagsEXT; -typedef VkFlags VkVideoEncodeH265InputModeFlagsEXT; -typedef VkFlags VkVideoEncodeH265OutputModeFlagsEXT; -typedef VkFlags VkVideoEncodeH265TransformBlockSizeFlagsEXT; -typedef VkFlags VkVideoEncodeRateControlFlagsKHR; -typedef VkFlags VkVideoEncodeRateControlModeFlagsKHR; -typedef VkFlags VkVideoEncodeUsageFlagsKHR; -typedef VkFlags VkVideoEndCodingFlagsKHR; -typedef VkFlags VkVideoSessionCreateFlagsKHR; -typedef VkFlags VkVideoSessionParametersCreateFlagsKHR; -typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; -typedef VkFlags VkWin32SurfaceCreateFlagsKHR; -typedef VkFlags VkXcbSurfaceCreateFlagsKHR; -typedef VkFlags VkXlibSurfaceCreateFlagsKHR; - -typedef enum VkAccelerationStructureBuildTypeKHR -{ - VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_KHR = 0, - VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR = 1, - VK_ACCELERATION_STRUCTURE_BUILD_TYPE_HOST_OR_DEVICE_KHR = 2, - VK_ACCELERATION_STRUCTURE_BUILD_TYPE_KHR_MAX_ENUM = 0x7fffffff, -} VkAccelerationStructureBuildTypeKHR; - -typedef enum VkAccelerationStructureCompatibilityKHR -{ - VK_ACCELERATION_STRUCTURE_COMPATIBILITY_COMPATIBLE_KHR = 0, - VK_ACCELERATION_STRUCTURE_COMPATIBILITY_INCOMPATIBLE_KHR = 1, - VK_ACCELERATION_STRUCTURE_COMPATIBILITY_KHR_MAX_ENUM = 0x7fffffff, -} VkAccelerationStructureCompatibilityKHR; - -typedef enum VkAccelerationStructureCreateFlagBitsKHR -{ - VK_ACCELERATION_STRUCTURE_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = 0x00000001, - VK_ACCELERATION_STRUCTURE_CREATE_MOTION_BIT_NV = 0x00000004, - VK_ACCELERATION_STRUCTURE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 0x00000008, - VK_ACCELERATION_STRUCTURE_CREATE_FLAG_BITS_KHR_MAX_ENUM = 0x7fffffff, -} VkAccelerationStructureCreateFlagBitsKHR; - -typedef enum VkAccelerationStructureMemoryRequirementsTypeNV -{ - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2, - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_NV_MAX_ENUM = 0x7fffffff, -} VkAccelerationStructureMemoryRequirementsTypeNV; - -typedef enum VkAccelerationStructureMotionInstanceTypeNV -{ - VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_STATIC_NV = 0, - VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MATRIX_MOTION_NV = 1, - VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_SRT_MOTION_NV = 2, - VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_NV_MAX_ENUM = 0x7fffffff, -} VkAccelerationStructureMotionInstanceTypeNV; - -typedef enum VkAccelerationStructureTypeKHR -{ - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR = 0, - VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR = 1, - VK_ACCELERATION_STRUCTURE_TYPE_GENERIC_KHR = 2, - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR, - VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, - VK_ACCELERATION_STRUCTURE_TYPE_KHR_MAX_ENUM = 0x7fffffff, -} VkAccelerationStructureTypeKHR; -typedef VkAccelerationStructureTypeKHR VkAccelerationStructureTypeNV; - -typedef enum VkAccessFlagBits -{ - VK_ACCESS_NONE = 0, - VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001, - VK_ACCESS_INDEX_READ_BIT = 0x00000002, - VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004, - VK_ACCESS_UNIFORM_READ_BIT = 0x00000008, - VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010, - VK_ACCESS_SHADER_READ_BIT = 0x00000020, - VK_ACCESS_SHADER_WRITE_BIT = 0x00000040, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400, - VK_ACCESS_TRANSFER_READ_BIT = 0x00000800, - VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000, - VK_ACCESS_HOST_READ_BIT = 0x00002000, - VK_ACCESS_HOST_WRITE_BIT = 0x00004000, - VK_ACCESS_MEMORY_READ_BIT = 0x00008000, - VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000, - VK_ACCESS_COMMAND_PREPROCESS_READ_BIT_NV = 0x00020000, - VK_ACCESS_COMMAND_PREPROCESS_WRITE_BIT_NV = 0x00040000, - VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000, - VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000, - VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR = 0x00200000, - VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR = 0x00400000, - VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR = 0x00800000, - VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000, - VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000, - VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000, - VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000, - VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR, - VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, - VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, - VK_ACCESS_NONE_KHR = VK_ACCESS_NONE, - VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkAccessFlagBits; - -typedef VkFlags64 VkAccessFlagBits2; - -static const VkAccessFlagBits2 VK_ACCESS_2_NONE = 0ull; -static const VkAccessFlagBits2 VK_ACCESS_2_NONE_KHR = 0ull; -static const VkAccessFlagBits2 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT = 0x00000001ull; -static const VkAccessFlagBits2 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR = 0x00000001ull; -static const VkAccessFlagBits2 VK_ACCESS_2_INDEX_READ_BIT = 0x00000002ull; -static const VkAccessFlagBits2 VK_ACCESS_2_INDEX_READ_BIT_KHR = 0x00000002ull; -static const VkAccessFlagBits2 VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004ull; -static const VkAccessFlagBits2 VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR = 0x00000004ull; -static const VkAccessFlagBits2 VK_ACCESS_2_UNIFORM_READ_BIT = 0x00000008ull; -static const VkAccessFlagBits2 VK_ACCESS_2_UNIFORM_READ_BIT_KHR = 0x00000008ull; -static const VkAccessFlagBits2 VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT = 0x00000010ull; -static const VkAccessFlagBits2 VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT_KHR = 0x00000010ull; -static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_READ_BIT = 0x00000020ull; -static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_READ_BIT_KHR = 0x00000020ull; -static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_WRITE_BIT = 0x00000040ull; -static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_WRITE_BIT_KHR = 0x00000040ull; -static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT = 0x00000080ull; -static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR = 0x00000080ull; -static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100ull; -static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR = 0x00000100ull; -static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200ull; -static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR = 0x00000200ull; -static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400ull; -static const VkAccessFlagBits2 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR = 0x00000400ull; -static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_READ_BIT = 0x00000800ull; -static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_READ_BIT_KHR = 0x00000800ull; -static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_WRITE_BIT = 0x00001000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR = 0x00001000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_HOST_READ_BIT = 0x00002000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_HOST_READ_BIT_KHR = 0x00002000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_HOST_WRITE_BIT = 0x00004000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_HOST_WRITE_BIT_KHR = 0x00004000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_READ_BIT = 0x00008000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_READ_BIT_KHR = 0x00008000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_WRITE_BIT = 0x00010000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_MEMORY_WRITE_BIT_KHR = 0x00010000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_READ_BIT_NV = 0x00020000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_COMMAND_PREPROCESS_WRITE_BIT_NV = 0x00040000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR = 0x00200000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR = 0x00400000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR = 0x00800000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_SAMPLED_READ_BIT = 0x100000000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_SAMPLED_READ_BIT_KHR = 0x100000000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_READ_BIT = 0x200000000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_READ_BIT_KHR = 0x200000000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT = 0x400000000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT_KHR = 0x400000000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_INVOCATION_MASK_READ_BIT_HUAWEI = 0x8000000000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_BINDING_TABLE_READ_BIT_KHR = 0x10000000000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_DESCRIPTOR_BUFFER_READ_BIT_EXT = 0x20000000000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_OPTICAL_FLOW_READ_BIT_NV = 0x40000000000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_OPTICAL_FLOW_WRITE_BIT_NV = 0x80000000000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_MICROMAP_READ_BIT_EXT = 0x100000000000ull; -static const VkAccessFlagBits2 VK_ACCESS_2_MICROMAP_WRITE_BIT_EXT = 0x200000000000ull; -typedef VkAccessFlagBits2 VkAccessFlagBits2KHR; - -typedef enum VkAcquireProfilingLockFlagBitsKHR -{ - VK_ACQUIRE_PROFILING_LOCK_FLAG_BITS_KHR_MAX_ENUM = 0x7fffffff, -} VkAcquireProfilingLockFlagBitsKHR; - -typedef enum VkAttachmentDescriptionFlagBits -{ - VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001, - VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkAttachmentDescriptionFlagBits; - -typedef enum VkAttachmentLoadOp -{ - VK_ATTACHMENT_LOAD_OP_LOAD = 0, - VK_ATTACHMENT_LOAD_OP_CLEAR = 1, - VK_ATTACHMENT_LOAD_OP_DONT_CARE = 2, - VK_ATTACHMENT_LOAD_OP_NONE_EXT = 1000400000, - VK_ATTACHMENT_LOAD_OP_MAX_ENUM = 0x7fffffff, -} VkAttachmentLoadOp; - -typedef enum VkAttachmentStoreOp -{ - VK_ATTACHMENT_STORE_OP_STORE = 0, - VK_ATTACHMENT_STORE_OP_DONT_CARE = 1, - VK_ATTACHMENT_STORE_OP_NONE = 1000301000, - VK_ATTACHMENT_STORE_OP_NONE_KHR = VK_ATTACHMENT_STORE_OP_NONE, - VK_ATTACHMENT_STORE_OP_NONE_QCOM = VK_ATTACHMENT_STORE_OP_NONE, - VK_ATTACHMENT_STORE_OP_NONE_EXT = VK_ATTACHMENT_STORE_OP_NONE, - VK_ATTACHMENT_STORE_OP_MAX_ENUM = 0x7fffffff, -} VkAttachmentStoreOp; - -typedef enum VkBlendFactor -{ - VK_BLEND_FACTOR_ZERO = 0, - VK_BLEND_FACTOR_ONE = 1, - VK_BLEND_FACTOR_SRC_COLOR = 2, - VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3, - VK_BLEND_FACTOR_DST_COLOR = 4, - VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5, - VK_BLEND_FACTOR_SRC_ALPHA = 6, - VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7, - VK_BLEND_FACTOR_DST_ALPHA = 8, - VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9, - VK_BLEND_FACTOR_CONSTANT_COLOR = 10, - VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11, - VK_BLEND_FACTOR_CONSTANT_ALPHA = 12, - VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13, - VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 14, - VK_BLEND_FACTOR_SRC1_COLOR = 15, - VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16, - VK_BLEND_FACTOR_SRC1_ALPHA = 17, - VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18, - VK_BLEND_FACTOR_MAX_ENUM = 0x7fffffff, -} VkBlendFactor; - -typedef enum VkBlendOp -{ - VK_BLEND_OP_ADD = 0, - VK_BLEND_OP_SUBTRACT = 1, - VK_BLEND_OP_REVERSE_SUBTRACT = 2, - VK_BLEND_OP_MIN = 3, - VK_BLEND_OP_MAX = 4, - VK_BLEND_OP_ZERO_EXT = 1000148000, - VK_BLEND_OP_SRC_EXT = 1000148001, - VK_BLEND_OP_DST_EXT = 1000148002, - VK_BLEND_OP_SRC_OVER_EXT = 1000148003, - VK_BLEND_OP_DST_OVER_EXT = 1000148004, - VK_BLEND_OP_SRC_IN_EXT = 1000148005, - VK_BLEND_OP_DST_IN_EXT = 1000148006, - VK_BLEND_OP_SRC_OUT_EXT = 1000148007, - VK_BLEND_OP_DST_OUT_EXT = 1000148008, - VK_BLEND_OP_SRC_ATOP_EXT = 1000148009, - VK_BLEND_OP_DST_ATOP_EXT = 1000148010, - VK_BLEND_OP_XOR_EXT = 1000148011, - VK_BLEND_OP_MULTIPLY_EXT = 1000148012, - VK_BLEND_OP_SCREEN_EXT = 1000148013, - VK_BLEND_OP_OVERLAY_EXT = 1000148014, - VK_BLEND_OP_DARKEN_EXT = 1000148015, - VK_BLEND_OP_LIGHTEN_EXT = 1000148016, - VK_BLEND_OP_COLORDODGE_EXT = 1000148017, - VK_BLEND_OP_COLORBURN_EXT = 1000148018, - VK_BLEND_OP_HARDLIGHT_EXT = 1000148019, - VK_BLEND_OP_SOFTLIGHT_EXT = 1000148020, - VK_BLEND_OP_DIFFERENCE_EXT = 1000148021, - VK_BLEND_OP_EXCLUSION_EXT = 1000148022, - VK_BLEND_OP_INVERT_EXT = 1000148023, - VK_BLEND_OP_INVERT_RGB_EXT = 1000148024, - VK_BLEND_OP_LINEARDODGE_EXT = 1000148025, - VK_BLEND_OP_LINEARBURN_EXT = 1000148026, - VK_BLEND_OP_VIVIDLIGHT_EXT = 1000148027, - VK_BLEND_OP_LINEARLIGHT_EXT = 1000148028, - VK_BLEND_OP_PINLIGHT_EXT = 1000148029, - VK_BLEND_OP_HARDMIX_EXT = 1000148030, - VK_BLEND_OP_HSL_HUE_EXT = 1000148031, - VK_BLEND_OP_HSL_SATURATION_EXT = 1000148032, - VK_BLEND_OP_HSL_COLOR_EXT = 1000148033, - VK_BLEND_OP_HSL_LUMINOSITY_EXT = 1000148034, - VK_BLEND_OP_PLUS_EXT = 1000148035, - VK_BLEND_OP_PLUS_CLAMPED_EXT = 1000148036, - VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT = 1000148037, - VK_BLEND_OP_PLUS_DARKER_EXT = 1000148038, - VK_BLEND_OP_MINUS_EXT = 1000148039, - VK_BLEND_OP_MINUS_CLAMPED_EXT = 1000148040, - VK_BLEND_OP_CONTRAST_EXT = 1000148041, - VK_BLEND_OP_INVERT_OVG_EXT = 1000148042, - VK_BLEND_OP_RED_EXT = 1000148043, - VK_BLEND_OP_GREEN_EXT = 1000148044, - VK_BLEND_OP_BLUE_EXT = 1000148045, - VK_BLEND_OP_MAX_ENUM = 0x7fffffff, -} VkBlendOp; - -typedef enum VkBlendOverlapEXT -{ - VK_BLEND_OVERLAP_UNCORRELATED_EXT = 0, - VK_BLEND_OVERLAP_DISJOINT_EXT = 1, - VK_BLEND_OVERLAP_CONJOINT_EXT = 2, - VK_BLEND_OVERLAP_EXT_MAX_ENUM = 0x7fffffff, -} VkBlendOverlapEXT; - -typedef enum VkBorderColor -{ - VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0, - VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 1, - VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 2, - VK_BORDER_COLOR_INT_OPAQUE_BLACK = 3, - VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 4, - VK_BORDER_COLOR_INT_OPAQUE_WHITE = 5, - VK_BORDER_COLOR_FLOAT_CUSTOM_EXT = 1000287003, - VK_BORDER_COLOR_INT_CUSTOM_EXT = 1000287004, - VK_BORDER_COLOR_MAX_ENUM = 0x7fffffff, -} VkBorderColor; - -typedef enum VkBufferCreateFlagBits -{ - VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001, - VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, - VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, - VK_BUFFER_CREATE_PROTECTED_BIT = 0x00000008, - VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 0x00000010, - VK_BUFFER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 0x00000020, - VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, - VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, - VK_BUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkBufferCreateFlagBits; - -typedef enum VkBufferUsageFlagBits -{ - VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001, - VK_BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002, - VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004, - VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008, - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010, - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040, - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080, - VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100, - VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200, - VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR = 0x00000400, - VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 0x00000800, - VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 0x00001000, - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT = 0x00020000, - VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR = 0x00080000, - VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR = 0x00100000, - VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT = 0x00200000, - VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT = 0x00400000, - VK_BUFFER_USAGE_MICROMAP_BUILD_INPUT_READ_ONLY_BIT_EXT = 0x00800000, - VK_BUFFER_USAGE_MICROMAP_STORAGE_BIT_EXT = 0x01000000, - VK_BUFFER_USAGE_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT = 0x04000000, - VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, - VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkBufferUsageFlagBits; - -typedef enum VkBuildAccelerationStructureFlagBitsKHR -{ - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR = 0x00000001, - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR = 0x00000002, - VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR = 0x00000004, - VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR = 0x00000008, - VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR = 0x00000010, - VK_BUILD_ACCELERATION_STRUCTURE_MOTION_BIT_NV = 0x00000020, - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_UPDATE_EXT = 0x00000040, - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISABLE_OPACITY_MICROMAPS_EXT = 0x00000080, - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_DATA_UPDATE_EXT = 0x00000100, - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR, - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR, - VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR, - VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR, - VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR, - VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_KHR_MAX_ENUM = 0x7fffffff, -} VkBuildAccelerationStructureFlagBitsKHR; -typedef VkBuildAccelerationStructureFlagBitsKHR VkBuildAccelerationStructureFlagBitsNV; - -typedef enum VkBuildAccelerationStructureModeKHR -{ - VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR = 0, - VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR = 1, - VK_BUILD_ACCELERATION_STRUCTURE_MODE_KHR_MAX_ENUM = 0x7fffffff, -} VkBuildAccelerationStructureModeKHR; - -typedef enum VkBuildMicromapFlagBitsEXT -{ - VK_BUILD_MICROMAP_PREFER_FAST_TRACE_BIT_EXT = 0x00000001, - VK_BUILD_MICROMAP_PREFER_FAST_BUILD_BIT_EXT = 0x00000002, - VK_BUILD_MICROMAP_ALLOW_COMPACTION_BIT_EXT = 0x00000004, - VK_BUILD_MICROMAP_FLAG_BITS_EXT_MAX_ENUM = 0x7fffffff, -} VkBuildMicromapFlagBitsEXT; - -typedef enum VkBuildMicromapModeEXT -{ - VK_BUILD_MICROMAP_MODE_BUILD_EXT = 0, - VK_BUILD_MICROMAP_MODE_EXT_MAX_ENUM = 0x7fffffff, -} VkBuildMicromapModeEXT; - -typedef enum VkChromaLocation -{ - VK_CHROMA_LOCATION_COSITED_EVEN = 0, - VK_CHROMA_LOCATION_MIDPOINT = 1, - VK_CHROMA_LOCATION_COSITED_EVEN_KHR = VK_CHROMA_LOCATION_COSITED_EVEN, - VK_CHROMA_LOCATION_MIDPOINT_KHR = VK_CHROMA_LOCATION_MIDPOINT, - VK_CHROMA_LOCATION_MAX_ENUM = 0x7fffffff, -} VkChromaLocation; -typedef VkChromaLocation VkChromaLocationKHR; - -typedef enum VkCoarseSampleOrderTypeNV -{ - VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV = 0, - VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV = 1, - VK_COARSE_SAMPLE_ORDER_TYPE_PIXEL_MAJOR_NV = 2, - VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV = 3, - VK_COARSE_SAMPLE_ORDER_TYPE_NV_MAX_ENUM = 0x7fffffff, -} VkCoarseSampleOrderTypeNV; - -typedef enum VkColorComponentFlagBits -{ - VK_COLOR_COMPONENT_R_BIT = 0x00000001, - VK_COLOR_COMPONENT_G_BIT = 0x00000002, - VK_COLOR_COMPONENT_B_BIT = 0x00000004, - VK_COLOR_COMPONENT_A_BIT = 0x00000008, - VK_COLOR_COMPONENT_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkColorComponentFlagBits; - -typedef enum VkColorSpaceKHR -{ - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0, - VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001, - VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002, - VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT = 1000104003, - VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104004, - VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104005, - VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104006, - VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104007, - VK_COLOR_SPACE_HDR10_ST2084_EXT = 1000104008, - VK_COLOR_SPACE_DOLBYVISION_EXT = 1000104009, - VK_COLOR_SPACE_HDR10_HLG_EXT = 1000104010, - VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011, - VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012, - VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013, - VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014, - VK_COLORSPACE_SRGB_NONLINEAR_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, - VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT, - VK_COLOR_SPACE_KHR_MAX_ENUM = 0x7fffffff, -} VkColorSpaceKHR; - -typedef enum VkCommandBufferLevel -{ - VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0, - VK_COMMAND_BUFFER_LEVEL_SECONDARY = 1, - VK_COMMAND_BUFFER_LEVEL_MAX_ENUM = 0x7fffffff, -} VkCommandBufferLevel; - -typedef enum VkCommandBufferResetFlagBits -{ - VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001, - VK_COMMAND_BUFFER_RESET_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkCommandBufferResetFlagBits; - -typedef enum VkCommandBufferUsageFlagBits -{ - VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001, - VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002, - VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004, - VK_COMMAND_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkCommandBufferUsageFlagBits; - -typedef enum VkCommandPoolCreateFlagBits -{ - VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001, - VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002, - VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 0x00000004, - VK_COMMAND_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkCommandPoolCreateFlagBits; - -typedef enum VkCommandPoolResetFlagBits -{ - VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001, - VK_COMMAND_POOL_RESET_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkCommandPoolResetFlagBits; - -typedef enum VkCompareOp -{ - VK_COMPARE_OP_NEVER = 0, - VK_COMPARE_OP_LESS = 1, - VK_COMPARE_OP_EQUAL = 2, - VK_COMPARE_OP_LESS_OR_EQUAL = 3, - VK_COMPARE_OP_GREATER = 4, - VK_COMPARE_OP_NOT_EQUAL = 5, - VK_COMPARE_OP_GREATER_OR_EQUAL = 6, - VK_COMPARE_OP_ALWAYS = 7, - VK_COMPARE_OP_MAX_ENUM = 0x7fffffff, -} VkCompareOp; - -typedef enum VkComponentSwizzle -{ - VK_COMPONENT_SWIZZLE_IDENTITY = 0, - VK_COMPONENT_SWIZZLE_ZERO = 1, - VK_COMPONENT_SWIZZLE_ONE = 2, - VK_COMPONENT_SWIZZLE_R = 3, - VK_COMPONENT_SWIZZLE_G = 4, - VK_COMPONENT_SWIZZLE_B = 5, - VK_COMPONENT_SWIZZLE_A = 6, - VK_COMPONENT_SWIZZLE_MAX_ENUM = 0x7fffffff, -} VkComponentSwizzle; - -typedef enum VkComponentTypeNV -{ - VK_COMPONENT_TYPE_FLOAT16_NV = 0, - VK_COMPONENT_TYPE_FLOAT32_NV = 1, - VK_COMPONENT_TYPE_FLOAT64_NV = 2, - VK_COMPONENT_TYPE_SINT8_NV = 3, - VK_COMPONENT_TYPE_SINT16_NV = 4, - VK_COMPONENT_TYPE_SINT32_NV = 5, - VK_COMPONENT_TYPE_SINT64_NV = 6, - VK_COMPONENT_TYPE_UINT8_NV = 7, - VK_COMPONENT_TYPE_UINT16_NV = 8, - VK_COMPONENT_TYPE_UINT32_NV = 9, - VK_COMPONENT_TYPE_UINT64_NV = 10, - VK_COMPONENT_TYPE_NV_MAX_ENUM = 0x7fffffff, -} VkComponentTypeNV; - -typedef enum VkCompositeAlphaFlagBitsKHR -{ - VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001, - VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002, - VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 0x00000004, - VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008, - VK_COMPOSITE_ALPHA_FLAG_BITS_KHR_MAX_ENUM = 0x7fffffff, -} VkCompositeAlphaFlagBitsKHR; - -typedef enum VkConditionalRenderingFlagBitsEXT -{ - VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT = 0x00000001, - VK_CONDITIONAL_RENDERING_FLAG_BITS_EXT_MAX_ENUM = 0x7fffffff, -} VkConditionalRenderingFlagBitsEXT; - -typedef enum VkConservativeRasterizationModeEXT -{ - VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT = 0, - VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT = 1, - VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT = 2, - VK_CONSERVATIVE_RASTERIZATION_MODE_EXT_MAX_ENUM = 0x7fffffff, -} VkConservativeRasterizationModeEXT; - -typedef enum VkCopyAccelerationStructureModeKHR -{ - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR = 0, - VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR = 1, - VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR = 2, - VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR = 3, - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR, - VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR, - VK_COPY_ACCELERATION_STRUCTURE_MODE_KHR_MAX_ENUM = 0x7fffffff, -} VkCopyAccelerationStructureModeKHR; -typedef VkCopyAccelerationStructureModeKHR VkCopyAccelerationStructureModeNV; - -typedef enum VkCopyMicromapModeEXT -{ - VK_COPY_MICROMAP_MODE_CLONE_EXT = 0, - VK_COPY_MICROMAP_MODE_SERIALIZE_EXT = 1, - VK_COPY_MICROMAP_MODE_DESERIALIZE_EXT = 2, - VK_COPY_MICROMAP_MODE_COMPACT_EXT = 3, - VK_COPY_MICROMAP_MODE_EXT_MAX_ENUM = 0x7fffffff, -} VkCopyMicromapModeEXT; - -typedef enum VkCoverageModulationModeNV -{ - VK_COVERAGE_MODULATION_MODE_NONE_NV = 0, - VK_COVERAGE_MODULATION_MODE_RGB_NV = 1, - VK_COVERAGE_MODULATION_MODE_ALPHA_NV = 2, - VK_COVERAGE_MODULATION_MODE_RGBA_NV = 3, - VK_COVERAGE_MODULATION_MODE_NV_MAX_ENUM = 0x7fffffff, -} VkCoverageModulationModeNV; - -typedef enum VkCoverageReductionModeNV -{ - VK_COVERAGE_REDUCTION_MODE_MERGE_NV = 0, - VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV = 1, - VK_COVERAGE_REDUCTION_MODE_NV_MAX_ENUM = 0x7fffffff, -} VkCoverageReductionModeNV; - -typedef enum VkCullModeFlagBits -{ - VK_CULL_MODE_NONE = 0, - VK_CULL_MODE_FRONT_BIT = 0x00000001, - VK_CULL_MODE_BACK_BIT = 0x00000002, - VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, - VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkCullModeFlagBits; - -typedef enum VkDebugReportFlagBitsEXT -{ - VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001, - VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002, - VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004, - VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008, - VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010, - VK_DEBUG_REPORT_FLAG_BITS_EXT_MAX_ENUM = 0x7fffffff, -} VkDebugReportFlagBitsEXT; - -typedef enum VkDebugReportObjectTypeEXT -{ - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0, - VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1, - VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2, - VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3, - VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4, - VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6, - VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7, - VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8, - VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9, - VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10, - VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11, - VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12, - VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13, - VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14, - VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15, - VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16, - VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17, - VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18, - VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20, - VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23, - VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24, - VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25, - VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26, - VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27, - VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT = 28, - VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29, - VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30, - VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT = 33, - VK_DEBUG_REPORT_OBJECT_TYPE_CU_MODULE_NVX_EXT = 1000029000, - VK_DEBUG_REPORT_OBJECT_TYPE_CU_FUNCTION_NVX_EXT = 1000029001, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000, - VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR_EXT = 1000150000, - VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000, - VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000, - VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT, - VK_DEBUG_REPORT_OBJECT_TYPE_EXT_MAX_ENUM = 0x7fffffff, -} VkDebugReportObjectTypeEXT; - -typedef enum VkDebugUtilsMessageSeverityFlagBitsEXT -{ - VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 0x00000001, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT = 0x00000010, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT = 0x00000100, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 0x00001000, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_FLAG_BITS_EXT_MAX_ENUM = 0x7fffffff, -} VkDebugUtilsMessageSeverityFlagBitsEXT; - -typedef enum VkDebugUtilsMessageTypeFlagBitsEXT -{ - VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 0x00000001, - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT = 0x00000002, - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 0x00000004, - VK_DEBUG_UTILS_MESSAGE_TYPE_DEVICE_ADDRESS_BINDING_BIT_EXT = 0x00000008, - VK_DEBUG_UTILS_MESSAGE_TYPE_FLAG_BITS_EXT_MAX_ENUM = 0x7fffffff, -} VkDebugUtilsMessageTypeFlagBitsEXT; - -typedef enum VkDependencyFlagBits -{ - VK_DEPENDENCY_BY_REGION_BIT = 0x00000001, - VK_DEPENDENCY_VIEW_LOCAL_BIT = 0x00000002, - VK_DEPENDENCY_DEVICE_GROUP_BIT = 0x00000004, - VK_DEPENDENCY_FEEDBACK_LOOP_BIT_EXT = 0x00000008, - VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR = VK_DEPENDENCY_VIEW_LOCAL_BIT, - VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR = VK_DEPENDENCY_DEVICE_GROUP_BIT, - VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkDependencyFlagBits; - -typedef enum VkDescriptorBindingFlagBits -{ - VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT = 0x00000001, - VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT = 0x00000002, - VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT = 0x00000004, - VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT = 0x00000008, - VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT, - VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT = VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, - VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT, - VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT, - VK_DESCRIPTOR_BINDING_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkDescriptorBindingFlagBits; -typedef VkDescriptorBindingFlagBits VkDescriptorBindingFlagBitsEXT; - -typedef enum VkDescriptorPoolCreateFlagBits -{ - VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001, - VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT = 0x00000002, - VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT = 0x00000004, - VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT, - VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE = VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT, - VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkDescriptorPoolCreateFlagBits; - -typedef enum VkDescriptorSetLayoutCreateFlagBits -{ - VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = 0x00000001, - VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT = 0x00000002, - VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT = 0x00000004, - VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT = 0x00000010, - VK_DESCRIPTOR_SET_LAYOUT_CREATE_EMBEDDED_IMMUTABLE_SAMPLERS_BIT_EXT = 0x00000020, - VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, - VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE = VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT, - VK_DESCRIPTOR_SET_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkDescriptorSetLayoutCreateFlagBits; - -typedef enum VkDescriptorType -{ - VK_DESCRIPTOR_TYPE_SAMPLER = 0, - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1, - VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 2, - VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 3, - VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 4, - VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 5, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 6, - VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 7, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8, - VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9, - VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10, - VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK = 1000138000, - VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR = 1000150000, - VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, - VK_DESCRIPTOR_TYPE_MUTABLE_EXT = 1000351000, - VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM = 1000440000, - VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM = 1000440001, - VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK, - VK_DESCRIPTOR_TYPE_MUTABLE_VALVE = VK_DESCRIPTOR_TYPE_MUTABLE_EXT, - VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7fffffff, -} VkDescriptorType; - -typedef enum VkDescriptorUpdateTemplateType -{ - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET, - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM = 0x7fffffff, -} VkDescriptorUpdateTemplateType; -typedef VkDescriptorUpdateTemplateType VkDescriptorUpdateTemplateTypeKHR; - -typedef enum VkDeviceAddressBindingFlagBitsEXT -{ - VK_DEVICE_ADDRESS_BINDING_INTERNAL_OBJECT_BIT_EXT = 0x00000001, - VK_DEVICE_ADDRESS_BINDING_FLAG_BITS_EXT_MAX_ENUM = 0x7fffffff, -} VkDeviceAddressBindingFlagBitsEXT; - -typedef enum VkDeviceAddressBindingTypeEXT -{ - VK_DEVICE_ADDRESS_BINDING_TYPE_BIND_EXT = 0, - VK_DEVICE_ADDRESS_BINDING_TYPE_UNBIND_EXT = 1, - VK_DEVICE_ADDRESS_BINDING_TYPE_EXT_MAX_ENUM = 0x7fffffff, -} VkDeviceAddressBindingTypeEXT; - -typedef enum VkDeviceDiagnosticsConfigFlagBitsNV -{ - VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV = 0x00000001, - VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV = 0x00000002, - VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV = 0x00000004, - VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_ERROR_REPORTING_BIT_NV = 0x00000008, - VK_DEVICE_DIAGNOSTICS_CONFIG_FLAG_BITS_NV_MAX_ENUM = 0x7fffffff, -} VkDeviceDiagnosticsConfigFlagBitsNV; - -typedef enum VkDeviceFaultAddressTypeEXT -{ - VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT = 0, - VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT = 1, - VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT = 2, - VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT = 3, - VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT = 4, - VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT = 5, - VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT = 6, - VK_DEVICE_FAULT_ADDRESS_TYPE_EXT_MAX_ENUM = 0x7fffffff, -} VkDeviceFaultAddressTypeEXT; - -typedef enum VkDeviceFaultVendorBinaryHeaderVersionEXT -{ - VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_EXT = 1, - VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_EXT_MAX_ENUM = 0x7fffffff, -} VkDeviceFaultVendorBinaryHeaderVersionEXT; - -typedef enum VkDeviceGroupPresentModeFlagBitsKHR -{ - VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR = 0x00000001, - VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR = 0x00000002, - VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR = 0x00000004, - VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 0x00000008, - VK_DEVICE_GROUP_PRESENT_MODE_FLAG_BITS_KHR_MAX_ENUM = 0x7fffffff, -} VkDeviceGroupPresentModeFlagBitsKHR; - -typedef enum VkDeviceQueueCreateFlagBits -{ - VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 0x00000001, - VK_DEVICE_QUEUE_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkDeviceQueueCreateFlagBits; - -typedef enum VkDiscardRectangleModeEXT -{ - VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT = 0, - VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1, - VK_DISCARD_RECTANGLE_MODE_EXT_MAX_ENUM = 0x7fffffff, -} VkDiscardRectangleModeEXT; - -typedef enum VkDriverId -{ - VK_DRIVER_ID_AMD_PROPRIETARY = 1, - VK_DRIVER_ID_AMD_OPEN_SOURCE = 2, - VK_DRIVER_ID_MESA_RADV = 3, - VK_DRIVER_ID_NVIDIA_PROPRIETARY = 4, - VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS = 5, - VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA = 6, - VK_DRIVER_ID_IMAGINATION_PROPRIETARY = 7, - VK_DRIVER_ID_QUALCOMM_PROPRIETARY = 8, - VK_DRIVER_ID_ARM_PROPRIETARY = 9, - VK_DRIVER_ID_GOOGLE_SWIFTSHADER = 10, - VK_DRIVER_ID_GGP_PROPRIETARY = 11, - VK_DRIVER_ID_BROADCOM_PROPRIETARY = 12, - VK_DRIVER_ID_MESA_LLVMPIPE = 13, - VK_DRIVER_ID_MOLTENVK = 14, - VK_DRIVER_ID_COREAVI_PROPRIETARY = 15, - VK_DRIVER_ID_JUICE_PROPRIETARY = 16, - VK_DRIVER_ID_VERISILICON_PROPRIETARY = 17, - VK_DRIVER_ID_MESA_TURNIP = 18, - VK_DRIVER_ID_MESA_V3DV = 19, - VK_DRIVER_ID_MESA_PANVK = 20, - VK_DRIVER_ID_SAMSUNG_PROPRIETARY = 21, - VK_DRIVER_ID_MESA_VENUS = 22, - VK_DRIVER_ID_MESA_DOZEN = 23, - VK_DRIVER_ID_MESA_NVK = 24, - VK_DRIVER_ID_AMD_PROPRIETARY_KHR = VK_DRIVER_ID_AMD_PROPRIETARY, - VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = VK_DRIVER_ID_AMD_OPEN_SOURCE, - VK_DRIVER_ID_MESA_RADV_KHR = VK_DRIVER_ID_MESA_RADV, - VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR = VK_DRIVER_ID_NVIDIA_PROPRIETARY, - VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR = VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS, - VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR = VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA, - VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR = VK_DRIVER_ID_IMAGINATION_PROPRIETARY, - VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR = VK_DRIVER_ID_QUALCOMM_PROPRIETARY, - VK_DRIVER_ID_ARM_PROPRIETARY_KHR = VK_DRIVER_ID_ARM_PROPRIETARY, - VK_DRIVER_ID_GOOGLE_SWIFTSHADER_KHR = VK_DRIVER_ID_GOOGLE_SWIFTSHADER, - VK_DRIVER_ID_GGP_PROPRIETARY_KHR = VK_DRIVER_ID_GGP_PROPRIETARY, - VK_DRIVER_ID_BROADCOM_PROPRIETARY_KHR = VK_DRIVER_ID_BROADCOM_PROPRIETARY, - VK_DRIVER_ID_MAX_ENUM = 0x7fffffff, -} VkDriverId; -typedef VkDriverId VkDriverIdKHR; - -typedef enum VkDynamicState -{ - VK_DYNAMIC_STATE_VIEWPORT = 0, - VK_DYNAMIC_STATE_SCISSOR = 1, - VK_DYNAMIC_STATE_LINE_WIDTH = 2, - VK_DYNAMIC_STATE_DEPTH_BIAS = 3, - VK_DYNAMIC_STATE_BLEND_CONSTANTS = 4, - VK_DYNAMIC_STATE_DEPTH_BOUNDS = 5, - VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6, - VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7, - VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8, - VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV = 1000087000, - VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000, - VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT = 1000143000, - VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV = 1000164004, - VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV = 1000164006, - VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV = 1000205001, - VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR = 1000226000, - VK_DYNAMIC_STATE_LINE_STIPPLE_EXT = 1000259000, - VK_DYNAMIC_STATE_CULL_MODE = 1000267000, - VK_DYNAMIC_STATE_FRONT_FACE = 1000267001, - VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY = 1000267002, - VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT = 1000267003, - VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT = 1000267004, - VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE = 1000267005, - VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE = 1000267006, - VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE = 1000267007, - VK_DYNAMIC_STATE_DEPTH_COMPARE_OP = 1000267008, - VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE = 1000267009, - VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE = 1000267010, - VK_DYNAMIC_STATE_STENCIL_OP = 1000267011, - VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR = 1000347000, - VK_DYNAMIC_STATE_VERTEX_INPUT_EXT = 1000352000, - VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT = 1000377000, - VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE = 1000377001, - VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE = 1000377002, - VK_DYNAMIC_STATE_LOGIC_OP_EXT = 1000377003, - VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE = 1000377004, - VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT = 1000381000, - VK_DYNAMIC_STATE_TESSELLATION_DOMAIN_ORIGIN_EXT = 1000455002, - VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT = 1000455003, - VK_DYNAMIC_STATE_POLYGON_MODE_EXT = 1000455004, - VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT = 1000455005, - VK_DYNAMIC_STATE_SAMPLE_MASK_EXT = 1000455006, - VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT = 1000455007, - VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT = 1000455008, - VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT = 1000455009, - VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT = 1000455010, - VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT = 1000455011, - VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT = 1000455012, - VK_DYNAMIC_STATE_RASTERIZATION_STREAM_EXT = 1000455013, - VK_DYNAMIC_STATE_CONSERVATIVE_RASTERIZATION_MODE_EXT = 1000455014, - VK_DYNAMIC_STATE_EXTRA_PRIMITIVE_OVERESTIMATION_SIZE_EXT = 1000455015, - VK_DYNAMIC_STATE_DEPTH_CLIP_ENABLE_EXT = 1000455016, - VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_ENABLE_EXT = 1000455017, - VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT = 1000455018, - VK_DYNAMIC_STATE_PROVOKING_VERTEX_MODE_EXT = 1000455019, - VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT = 1000455020, - VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT = 1000455021, - VK_DYNAMIC_STATE_DEPTH_CLIP_NEGATIVE_ONE_TO_ONE_EXT = 1000455022, - VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_ENABLE_NV = 1000455023, - VK_DYNAMIC_STATE_VIEWPORT_SWIZZLE_NV = 1000455024, - VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_ENABLE_NV = 1000455025, - VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_LOCATION_NV = 1000455026, - VK_DYNAMIC_STATE_COVERAGE_MODULATION_MODE_NV = 1000455027, - VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_ENABLE_NV = 1000455028, - VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_NV = 1000455029, - VK_DYNAMIC_STATE_SHADING_RATE_IMAGE_ENABLE_NV = 1000455030, - VK_DYNAMIC_STATE_REPRESENTATIVE_FRAGMENT_TEST_ENABLE_NV = 1000455031, - VK_DYNAMIC_STATE_COVERAGE_REDUCTION_MODE_NV = 1000455032, - VK_DYNAMIC_STATE_CULL_MODE_EXT = VK_DYNAMIC_STATE_CULL_MODE, - VK_DYNAMIC_STATE_FRONT_FACE_EXT = VK_DYNAMIC_STATE_FRONT_FACE, - VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT = VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY, - VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT = VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT, - VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT = VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT, - VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT = VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE, - VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE, - VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE, - VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT = VK_DYNAMIC_STATE_DEPTH_COMPARE_OP, - VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE, - VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT = VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE, - VK_DYNAMIC_STATE_STENCIL_OP_EXT = VK_DYNAMIC_STATE_STENCIL_OP, - VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT = VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE, - VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT = VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE, - VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT = VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE, - VK_DYNAMIC_STATE_MAX_ENUM = 0x7fffffff, -} VkDynamicState; - -typedef enum VkEventCreateFlagBits -{ - VK_EVENT_CREATE_DEVICE_ONLY_BIT = 0x00000001, - VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR = VK_EVENT_CREATE_DEVICE_ONLY_BIT, - VK_EVENT_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkEventCreateFlagBits; - -typedef enum VkExternalFenceFeatureFlagBits -{ - VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT = 0x00000001, - VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT = 0x00000002, - VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT, - VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT, - VK_EXTERNAL_FENCE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkExternalFenceFeatureFlagBits; -typedef VkExternalFenceFeatureFlagBits VkExternalFenceFeatureFlagBitsKHR; - -typedef enum VkExternalFenceHandleTypeFlagBits -{ - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, - VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000008, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT, - VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, - VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, - VK_EXTERNAL_FENCE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkExternalFenceHandleTypeFlagBits; -typedef VkExternalFenceHandleTypeFlagBits VkExternalFenceHandleTypeFlagBitsKHR; - -typedef enum VkExternalMemoryFeatureFlagBits -{ - VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT = 0x00000001, - VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT = 0x00000002, - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT = 0x00000004, - VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT, - VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT, - VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT, - VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkExternalMemoryFeatureFlagBits; -typedef VkExternalMemoryFeatureFlagBits VkExternalMemoryFeatureFlagBitsKHR; - -typedef enum VkExternalMemoryHandleTypeFlagBits -{ - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT = 0x00000008, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT = 0x00000010, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT = 0x00000020, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT = 0x00000040, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT = 0x00000080, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT = 0x00000100, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT, - VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkExternalMemoryHandleTypeFlagBits; -typedef VkExternalMemoryHandleTypeFlagBits VkExternalMemoryHandleTypeFlagBitsKHR; - -typedef enum VkExternalSemaphoreFeatureFlagBits -{ - VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT = 0x00000001, - VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT = 0x00000002, - VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT, - VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT, - VK_EXTERNAL_SEMAPHORE_FEATURE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkExternalSemaphoreFeatureFlagBits; -typedef VkExternalSemaphoreFeatureFlagBits VkExternalSemaphoreFeatureFlagBitsKHR; - -typedef enum VkExternalSemaphoreHandleTypeFlagBits -{ - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT = 0x00000008, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000010, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D11_FENCE_BIT = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkExternalSemaphoreHandleTypeFlagBits; -typedef VkExternalSemaphoreHandleTypeFlagBits VkExternalSemaphoreHandleTypeFlagBitsKHR; - -typedef enum VkFenceCreateFlagBits -{ - VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001, - VK_FENCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkFenceCreateFlagBits; - -typedef enum VkFenceImportFlagBits -{ - VK_FENCE_IMPORT_TEMPORARY_BIT = 0x00000001, - VK_FENCE_IMPORT_TEMPORARY_BIT_KHR = VK_FENCE_IMPORT_TEMPORARY_BIT, - VK_FENCE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkFenceImportFlagBits; -typedef VkFenceImportFlagBits VkFenceImportFlagBitsKHR; - -typedef enum VkFilter -{ - VK_FILTER_NEAREST = 0, - VK_FILTER_LINEAR = 1, - VK_FILTER_CUBIC_EXT = 1000015000, - VK_FILTER_CUBIC_IMG = VK_FILTER_CUBIC_EXT, - VK_FILTER_MAX_ENUM = 0x7fffffff, -} VkFilter; - -typedef enum VkFormat -{ - VK_FORMAT_UNDEFINED = 0, - VK_FORMAT_R4G4_UNORM_PACK8 = 1, - VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2, - VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3, - VK_FORMAT_R5G6B5_UNORM_PACK16 = 4, - VK_FORMAT_B5G6R5_UNORM_PACK16 = 5, - VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6, - VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7, - VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8, - VK_FORMAT_R8_UNORM = 9, - VK_FORMAT_R8_SNORM = 10, - VK_FORMAT_R8_USCALED = 11, - VK_FORMAT_R8_SSCALED = 12, - VK_FORMAT_R8_UINT = 13, - VK_FORMAT_R8_SINT = 14, - VK_FORMAT_R8_SRGB = 15, - VK_FORMAT_R8G8_UNORM = 16, - VK_FORMAT_R8G8_SNORM = 17, - VK_FORMAT_R8G8_USCALED = 18, - VK_FORMAT_R8G8_SSCALED = 19, - VK_FORMAT_R8G8_UINT = 20, - VK_FORMAT_R8G8_SINT = 21, - VK_FORMAT_R8G8_SRGB = 22, - VK_FORMAT_R8G8B8_UNORM = 23, - VK_FORMAT_R8G8B8_SNORM = 24, - VK_FORMAT_R8G8B8_USCALED = 25, - VK_FORMAT_R8G8B8_SSCALED = 26, - VK_FORMAT_R8G8B8_UINT = 27, - VK_FORMAT_R8G8B8_SINT = 28, - VK_FORMAT_R8G8B8_SRGB = 29, - VK_FORMAT_B8G8R8_UNORM = 30, - VK_FORMAT_B8G8R8_SNORM = 31, - VK_FORMAT_B8G8R8_USCALED = 32, - VK_FORMAT_B8G8R8_SSCALED = 33, - VK_FORMAT_B8G8R8_UINT = 34, - VK_FORMAT_B8G8R8_SINT = 35, - VK_FORMAT_B8G8R8_SRGB = 36, - VK_FORMAT_R8G8B8A8_UNORM = 37, - VK_FORMAT_R8G8B8A8_SNORM = 38, - VK_FORMAT_R8G8B8A8_USCALED = 39, - VK_FORMAT_R8G8B8A8_SSCALED = 40, - VK_FORMAT_R8G8B8A8_UINT = 41, - VK_FORMAT_R8G8B8A8_SINT = 42, - VK_FORMAT_R8G8B8A8_SRGB = 43, - VK_FORMAT_B8G8R8A8_UNORM = 44, - VK_FORMAT_B8G8R8A8_SNORM = 45, - VK_FORMAT_B8G8R8A8_USCALED = 46, - VK_FORMAT_B8G8R8A8_SSCALED = 47, - VK_FORMAT_B8G8R8A8_UINT = 48, - VK_FORMAT_B8G8R8A8_SINT = 49, - VK_FORMAT_B8G8R8A8_SRGB = 50, - VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51, - VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52, - VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53, - VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54, - VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55, - VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56, - VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57, - VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58, - VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59, - VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60, - VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61, - VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62, - VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63, - VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64, - VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65, - VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66, - VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67, - VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68, - VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69, - VK_FORMAT_R16_UNORM = 70, - VK_FORMAT_R16_SNORM = 71, - VK_FORMAT_R16_USCALED = 72, - VK_FORMAT_R16_SSCALED = 73, - VK_FORMAT_R16_UINT = 74, - VK_FORMAT_R16_SINT = 75, - VK_FORMAT_R16_SFLOAT = 76, - VK_FORMAT_R16G16_UNORM = 77, - VK_FORMAT_R16G16_SNORM = 78, - VK_FORMAT_R16G16_USCALED = 79, - VK_FORMAT_R16G16_SSCALED = 80, - VK_FORMAT_R16G16_UINT = 81, - VK_FORMAT_R16G16_SINT = 82, - VK_FORMAT_R16G16_SFLOAT = 83, - VK_FORMAT_R16G16B16_UNORM = 84, - VK_FORMAT_R16G16B16_SNORM = 85, - VK_FORMAT_R16G16B16_USCALED = 86, - VK_FORMAT_R16G16B16_SSCALED = 87, - VK_FORMAT_R16G16B16_UINT = 88, - VK_FORMAT_R16G16B16_SINT = 89, - VK_FORMAT_R16G16B16_SFLOAT = 90, - VK_FORMAT_R16G16B16A16_UNORM = 91, - VK_FORMAT_R16G16B16A16_SNORM = 92, - VK_FORMAT_R16G16B16A16_USCALED = 93, - VK_FORMAT_R16G16B16A16_SSCALED = 94, - VK_FORMAT_R16G16B16A16_UINT = 95, - VK_FORMAT_R16G16B16A16_SINT = 96, - VK_FORMAT_R16G16B16A16_SFLOAT = 97, - VK_FORMAT_R32_UINT = 98, - VK_FORMAT_R32_SINT = 99, - VK_FORMAT_R32_SFLOAT = 100, - VK_FORMAT_R32G32_UINT = 101, - VK_FORMAT_R32G32_SINT = 102, - VK_FORMAT_R32G32_SFLOAT = 103, - VK_FORMAT_R32G32B32_UINT = 104, - VK_FORMAT_R32G32B32_SINT = 105, - VK_FORMAT_R32G32B32_SFLOAT = 106, - VK_FORMAT_R32G32B32A32_UINT = 107, - VK_FORMAT_R32G32B32A32_SINT = 108, - VK_FORMAT_R32G32B32A32_SFLOAT = 109, - VK_FORMAT_R64_UINT = 110, - VK_FORMAT_R64_SINT = 111, - VK_FORMAT_R64_SFLOAT = 112, - VK_FORMAT_R64G64_UINT = 113, - VK_FORMAT_R64G64_SINT = 114, - VK_FORMAT_R64G64_SFLOAT = 115, - VK_FORMAT_R64G64B64_UINT = 116, - VK_FORMAT_R64G64B64_SINT = 117, - VK_FORMAT_R64G64B64_SFLOAT = 118, - VK_FORMAT_R64G64B64A64_UINT = 119, - VK_FORMAT_R64G64B64A64_SINT = 120, - VK_FORMAT_R64G64B64A64_SFLOAT = 121, - VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122, - VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123, - VK_FORMAT_D16_UNORM = 124, - VK_FORMAT_X8_D24_UNORM_PACK32 = 125, - VK_FORMAT_D32_SFLOAT = 126, - VK_FORMAT_S8_UINT = 127, - VK_FORMAT_D16_UNORM_S8_UINT = 128, - VK_FORMAT_D24_UNORM_S8_UINT = 129, - VK_FORMAT_D32_SFLOAT_S8_UINT = 130, - VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131, - VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132, - VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133, - VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134, - VK_FORMAT_BC2_UNORM_BLOCK = 135, - VK_FORMAT_BC2_SRGB_BLOCK = 136, - VK_FORMAT_BC3_UNORM_BLOCK = 137, - VK_FORMAT_BC3_SRGB_BLOCK = 138, - VK_FORMAT_BC4_UNORM_BLOCK = 139, - VK_FORMAT_BC4_SNORM_BLOCK = 140, - VK_FORMAT_BC5_UNORM_BLOCK = 141, - VK_FORMAT_BC5_SNORM_BLOCK = 142, - VK_FORMAT_BC6H_UFLOAT_BLOCK = 143, - VK_FORMAT_BC6H_SFLOAT_BLOCK = 144, - VK_FORMAT_BC7_UNORM_BLOCK = 145, - VK_FORMAT_BC7_SRGB_BLOCK = 146, - VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147, - VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148, - VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149, - VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150, - VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151, - VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152, - VK_FORMAT_EAC_R11_UNORM_BLOCK = 153, - VK_FORMAT_EAC_R11_SNORM_BLOCK = 154, - VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155, - VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156, - VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157, - VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158, - VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159, - VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160, - VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161, - VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162, - VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163, - VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164, - VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165, - VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166, - VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167, - VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168, - VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169, - VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170, - VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171, - VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172, - VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173, - VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174, - VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175, - VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176, - VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177, - VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178, - VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179, - VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180, - VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181, - VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182, - VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183, - VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184, - VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000, - VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001, - VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002, - VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003, - VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004, - VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005, - VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006, - VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007, - VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK = 1000066000, - VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK = 1000066001, - VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK = 1000066002, - VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK = 1000066003, - VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK = 1000066004, - VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK = 1000066005, - VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK = 1000066006, - VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK = 1000066007, - VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK = 1000066008, - VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK = 1000066009, - VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK = 1000066010, - VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK = 1000066011, - VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK = 1000066012, - VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK = 1000066013, - VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000, - VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001, - VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002, - VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003, - VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004, - VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005, - VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006, - VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007, - VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008, - VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009, - VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010, - VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016, - VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017, - VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018, - VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019, - VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020, - VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026, - VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027, - VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028, - VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029, - VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030, - VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031, - VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032, - VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033, - VK_FORMAT_G8_B8R8_2PLANE_444_UNORM = 1000330000, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 = 1000330001, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 = 1000330002, - VK_FORMAT_G16_B16R16_2PLANE_444_UNORM = 1000330003, - VK_FORMAT_A4R4G4B4_UNORM_PACK16 = 1000340000, - VK_FORMAT_A4B4G4R4_UNORM_PACK16 = 1000340001, - VK_FORMAT_R16G16_S10_5_NV = 1000464000, - VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK, - VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK, - VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK, - VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK, - VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK, - VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK, - VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK, - VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK, - VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK, - VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK, - VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK, - VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK, - VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK, - VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT = VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK, - VK_FORMAT_G8B8G8R8_422_UNORM_KHR = VK_FORMAT_G8B8G8R8_422_UNORM, - VK_FORMAT_B8G8R8G8_422_UNORM_KHR = VK_FORMAT_B8G8R8G8_422_UNORM, - VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM, - VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, - VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM, - VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR = VK_FORMAT_G8_B8R8_2PLANE_422_UNORM, - VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM, - VK_FORMAT_R10X6_UNORM_PACK16_KHR = VK_FORMAT_R10X6_UNORM_PACK16, - VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR = VK_FORMAT_R10X6G10X6_UNORM_2PACK16, - VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR = VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, - VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, - VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR = VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, - VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, - VK_FORMAT_R12X4_UNORM_PACK16_KHR = VK_FORMAT_R12X4_UNORM_PACK16, - VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR = VK_FORMAT_R12X4G12X4_UNORM_2PACK16, - VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR = VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16, - VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, - VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR = VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16, - VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR = VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16, - VK_FORMAT_G16B16G16R16_422_UNORM_KHR = VK_FORMAT_G16B16G16R16_422_UNORM, - VK_FORMAT_B16G16R16G16_422_UNORM_KHR = VK_FORMAT_B16G16R16G16_422_UNORM, - VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM, - VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_420_UNORM, - VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM, - VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = VK_FORMAT_G16_B16R16_2PLANE_422_UNORM, - VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM, - VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT = VK_FORMAT_G8_B8R8_2PLANE_444_UNORM, - VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16, - VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16, - VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT = VK_FORMAT_G16_B16R16_2PLANE_444_UNORM, - VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT = VK_FORMAT_A4R4G4B4_UNORM_PACK16, - VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT = VK_FORMAT_A4B4G4R4_UNORM_PACK16, - VK_FORMAT_MAX_ENUM = 0x7fffffff, -} VkFormat; - -typedef enum VkFormatFeatureFlagBits -{ - VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 0x00000001, - VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 0x00000002, - VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004, - VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008, - VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 0x00000010, - VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020, - VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 0x00000040, - VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 0x00000080, - VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100, - VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200, - VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400, - VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = 0x00002000, - VK_FORMAT_FEATURE_TRANSFER_SRC_BIT = 0x00004000, - VK_FORMAT_FEATURE_TRANSFER_DST_BIT = 0x00008000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT = 0x00010000, - VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT = 0x00020000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 0x00040000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 0x00080000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 0x00100000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000, - VK_FORMAT_FEATURE_DISJOINT_BIT = 0x00400000, - VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 0x00800000, - VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x01000000, - VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR = 0x20000000, - VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x40000000, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT, - VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, - VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_DST_BIT, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT, - VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT, - VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT, - VK_FORMAT_FEATURE_DISJOINT_BIT_KHR = VK_FORMAT_FEATURE_DISJOINT_BIT, - VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT, - VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkFormatFeatureFlagBits; - -typedef VkFlags64 VkFormatFeatureFlagBits2; - -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT = 0x00000001ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT_KHR = 0x00000001ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT = 0x00000002ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT_KHR = 0x00000002ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT_KHR = 0x00000004ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT_KHR = 0x00000008ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT = 0x00000010ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT_KHR = 0x00000010ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT_KHR = 0x00000020ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT = 0x00000040ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT_KHR = 0x00000040ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT = 0x00000080ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT_KHR = 0x00000080ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT_KHR = 0x00000100ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT_KHR = 0x00000200ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_SRC_BIT = 0x00000400ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_SRC_BIT_KHR = 0x00000400ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_DST_BIT = 0x00000800ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLIT_DST_BIT_KHR = 0x00000800ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT_KHR = 0x00001000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_CUBIC_BIT = 0x00002000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = 0x00002000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT = 0x00004000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT_KHR = 0x00004000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT = 0x00008000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT_KHR = 0x00008000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT = 0x00010000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT_KHR = 0x00010000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT = 0x00020000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = 0x00020000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 0x00040000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = 0x00040000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 0x00080000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = 0x00080000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 0x00100000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = 0x00100000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = 0x00200000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DISJOINT_BIT = 0x00400000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_DISJOINT_BIT_KHR = 0x00400000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT = 0x00800000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT_KHR = 0x00800000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x01000000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR = 0x20000000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x40000000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT = 0x80000000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT_KHR = 0x80000000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT = 0x100000000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT_KHR = 0x100000000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT = 0x200000000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT_KHR = 0x200000000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_WEIGHT_IMAGE_BIT_QCOM = 0x400000000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_WEIGHT_SAMPLED_IMAGE_BIT_QCOM = 0x800000000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLOCK_MATCHING_BIT_QCOM = 0x1000000000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BOX_FILTER_SAMPLED_BIT_QCOM = 0x2000000000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_LINEAR_COLOR_ATTACHMENT_BIT_NV = 0x4000000000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_OPTICAL_FLOW_IMAGE_BIT_NV = 0x10000000000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_OPTICAL_FLOW_VECTOR_BIT_NV = 0x20000000000ull; -static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_OPTICAL_FLOW_COST_BIT_NV = 0x40000000000ull; -typedef VkFormatFeatureFlagBits2 VkFormatFeatureFlagBits2KHR; - -typedef enum VkFragmentShadingRateCombinerOpKHR -{ - VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR = 0, - VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR = 1, - VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR = 2, - VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR = 3, - VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR = 4, - VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KHR_MAX_ENUM = 0x7fffffff, -} VkFragmentShadingRateCombinerOpKHR; - -typedef enum VkFragmentShadingRateNV -{ - VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_PIXEL_NV = 0, - VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_1X2_PIXELS_NV = 1, - VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X1_PIXELS_NV = 4, - VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X2_PIXELS_NV = 5, - VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_2X4_PIXELS_NV = 6, - VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X2_PIXELS_NV = 9, - VK_FRAGMENT_SHADING_RATE_1_INVOCATION_PER_4X4_PIXELS_NV = 10, - VK_FRAGMENT_SHADING_RATE_2_INVOCATIONS_PER_PIXEL_NV = 11, - VK_FRAGMENT_SHADING_RATE_4_INVOCATIONS_PER_PIXEL_NV = 12, - VK_FRAGMENT_SHADING_RATE_8_INVOCATIONS_PER_PIXEL_NV = 13, - VK_FRAGMENT_SHADING_RATE_16_INVOCATIONS_PER_PIXEL_NV = 14, - VK_FRAGMENT_SHADING_RATE_NO_INVOCATIONS_NV = 15, - VK_FRAGMENT_SHADING_RATE_NV_MAX_ENUM = 0x7fffffff, -} VkFragmentShadingRateNV; - -typedef enum VkFragmentShadingRateTypeNV -{ - VK_FRAGMENT_SHADING_RATE_TYPE_FRAGMENT_SIZE_NV = 0, - VK_FRAGMENT_SHADING_RATE_TYPE_ENUMS_NV = 1, - VK_FRAGMENT_SHADING_RATE_TYPE_NV_MAX_ENUM = 0x7fffffff, -} VkFragmentShadingRateTypeNV; - -typedef enum VkFramebufferCreateFlagBits -{ - VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT = 0x00000001, - VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT, - VK_FRAMEBUFFER_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkFramebufferCreateFlagBits; - -typedef enum VkFrontFace -{ - VK_FRONT_FACE_COUNTER_CLOCKWISE = 0, - VK_FRONT_FACE_CLOCKWISE = 1, - VK_FRONT_FACE_MAX_ENUM = 0x7fffffff, -} VkFrontFace; - -typedef enum VkGeometryFlagBitsKHR -{ - VK_GEOMETRY_OPAQUE_BIT_KHR = 0x00000001, - VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR = 0x00000002, - VK_GEOMETRY_OPAQUE_BIT_NV = VK_GEOMETRY_OPAQUE_BIT_KHR, - VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR, - VK_GEOMETRY_FLAG_BITS_KHR_MAX_ENUM = 0x7fffffff, -} VkGeometryFlagBitsKHR; -typedef VkGeometryFlagBitsKHR VkGeometryFlagBitsNV; - -typedef enum VkGeometryInstanceFlagBitsKHR -{ - VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR = 0x00000001, - VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR = 0x00000002, - VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR = 0x00000004, - VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR = 0x00000008, - VK_GEOMETRY_INSTANCE_FORCE_OPACITY_MICROMAP_2_STATE_EXT = 0x00000010, - VK_GEOMETRY_INSTANCE_DISABLE_OPACITY_MICROMAPS_EXT = 0x00000020, - VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR = VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR, - VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR, - VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR, - VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR, - VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR, - VK_GEOMETRY_INSTANCE_FLAG_BITS_KHR_MAX_ENUM = 0x7fffffff, -} VkGeometryInstanceFlagBitsKHR; -typedef VkGeometryInstanceFlagBitsKHR VkGeometryInstanceFlagBitsNV; - -typedef enum VkGeometryTypeKHR -{ - VK_GEOMETRY_TYPE_TRIANGLES_KHR = 0, - VK_GEOMETRY_TYPE_AABBS_KHR = 1, - VK_GEOMETRY_TYPE_INSTANCES_KHR = 2, - VK_GEOMETRY_TYPE_TRIANGLES_NV = VK_GEOMETRY_TYPE_TRIANGLES_KHR, - VK_GEOMETRY_TYPE_AABBS_NV = VK_GEOMETRY_TYPE_AABBS_KHR, - VK_GEOMETRY_TYPE_KHR_MAX_ENUM = 0x7fffffff, -} VkGeometryTypeKHR; -typedef VkGeometryTypeKHR VkGeometryTypeNV; - -typedef enum VkGraphicsPipelineLibraryFlagBitsEXT -{ - VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT = 0x00000001, - VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT = 0x00000002, - VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT = 0x00000004, - VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT = 0x00000008, - VK_GRAPHICS_PIPELINE_LIBRARY_FLAG_BITS_EXT_MAX_ENUM = 0x7fffffff, -} VkGraphicsPipelineLibraryFlagBitsEXT; - -typedef enum VkImageAspectFlagBits -{ - VK_IMAGE_ASPECT_NONE = 0, - VK_IMAGE_ASPECT_COLOR_BIT = 0x00000001, - VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002, - VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004, - VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008, - VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010, - VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020, - VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040, - VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = VK_IMAGE_ASPECT_PLANE_0_BIT, - VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = VK_IMAGE_ASPECT_PLANE_1_BIT, - VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = VK_IMAGE_ASPECT_PLANE_2_BIT, - VK_IMAGE_ASPECT_NONE_KHR = VK_IMAGE_ASPECT_NONE, - VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkImageAspectFlagBits; - -typedef enum VkImageCompressionFixedRateFlagBitsEXT -{ - VK_IMAGE_COMPRESSION_FIXED_RATE_NONE_EXT = 0, - VK_IMAGE_COMPRESSION_FIXED_RATE_1BPC_BIT_EXT = 0x00000001, - VK_IMAGE_COMPRESSION_FIXED_RATE_2BPC_BIT_EXT = 0x00000002, - VK_IMAGE_COMPRESSION_FIXED_RATE_3BPC_BIT_EXT = 0x00000004, - VK_IMAGE_COMPRESSION_FIXED_RATE_4BPC_BIT_EXT = 0x00000008, - VK_IMAGE_COMPRESSION_FIXED_RATE_5BPC_BIT_EXT = 0x00000010, - VK_IMAGE_COMPRESSION_FIXED_RATE_6BPC_BIT_EXT = 0x00000020, - VK_IMAGE_COMPRESSION_FIXED_RATE_7BPC_BIT_EXT = 0x00000040, - VK_IMAGE_COMPRESSION_FIXED_RATE_8BPC_BIT_EXT = 0x00000080, - VK_IMAGE_COMPRESSION_FIXED_RATE_9BPC_BIT_EXT = 0x00000100, - VK_IMAGE_COMPRESSION_FIXED_RATE_10BPC_BIT_EXT = 0x00000200, - VK_IMAGE_COMPRESSION_FIXED_RATE_11BPC_BIT_EXT = 0x00000400, - VK_IMAGE_COMPRESSION_FIXED_RATE_12BPC_BIT_EXT = 0x00000800, - VK_IMAGE_COMPRESSION_FIXED_RATE_13BPC_BIT_EXT = 0x00001000, - VK_IMAGE_COMPRESSION_FIXED_RATE_14BPC_BIT_EXT = 0x00002000, - VK_IMAGE_COMPRESSION_FIXED_RATE_15BPC_BIT_EXT = 0x00004000, - VK_IMAGE_COMPRESSION_FIXED_RATE_16BPC_BIT_EXT = 0x00008000, - VK_IMAGE_COMPRESSION_FIXED_RATE_17BPC_BIT_EXT = 0x00010000, - VK_IMAGE_COMPRESSION_FIXED_RATE_18BPC_BIT_EXT = 0x00020000, - VK_IMAGE_COMPRESSION_FIXED_RATE_19BPC_BIT_EXT = 0x00040000, - VK_IMAGE_COMPRESSION_FIXED_RATE_20BPC_BIT_EXT = 0x00080000, - VK_IMAGE_COMPRESSION_FIXED_RATE_21BPC_BIT_EXT = 0x00100000, - VK_IMAGE_COMPRESSION_FIXED_RATE_22BPC_BIT_EXT = 0x00200000, - VK_IMAGE_COMPRESSION_FIXED_RATE_23BPC_BIT_EXT = 0x00400000, - VK_IMAGE_COMPRESSION_FIXED_RATE_24BPC_BIT_EXT = 0x00800000, - VK_IMAGE_COMPRESSION_FIXED_RATE_FLAG_BITS_EXT_MAX_ENUM = 0x7fffffff, -} VkImageCompressionFixedRateFlagBitsEXT; - -typedef enum VkImageCompressionFlagBitsEXT -{ - VK_IMAGE_COMPRESSION_DEFAULT_EXT = 0, - VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT = 0x00000001, - VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT = 0x00000002, - VK_IMAGE_COMPRESSION_DISABLED_EXT = 0x00000004, - VK_IMAGE_COMPRESSION_FLAG_BITS_EXT_MAX_ENUM = 0x7fffffff, -} VkImageCompressionFlagBitsEXT; - -typedef enum VkImageCreateFlagBits -{ - VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 0x00000001, - VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, - VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004, - VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, - VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, - VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT = 0x00000020, - VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT = 0x00000040, - VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT = 0x00000080, - VK_IMAGE_CREATE_EXTENDED_USAGE_BIT = 0x00000100, - VK_IMAGE_CREATE_DISJOINT_BIT = 0x00000200, - VK_IMAGE_CREATE_ALIAS_BIT = 0x00000400, - VK_IMAGE_CREATE_PROTECTED_BIT = 0x00000800, - VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000, - VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV = 0x00002000, - VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT = 0x00004000, - VK_IMAGE_CREATE_FRAGMENT_DENSITY_MAP_OFFSET_BIT_QCOM = 0x00008000, - VK_IMAGE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 0x00010000, - VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT = 0x00020000, - VK_IMAGE_CREATE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT = 0x00040000, - VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT, - VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT, - VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT, - VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR = VK_IMAGE_CREATE_EXTENDED_USAGE_BIT, - VK_IMAGE_CREATE_DISJOINT_BIT_KHR = VK_IMAGE_CREATE_DISJOINT_BIT, - VK_IMAGE_CREATE_ALIAS_BIT_KHR = VK_IMAGE_CREATE_ALIAS_BIT, - VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkImageCreateFlagBits; - -typedef enum VkImageLayout -{ - VK_IMAGE_LAYOUT_UNDEFINED = 0, - VK_IMAGE_LAYOUT_GENERAL = 1, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 2, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 3, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 4, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 5, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 6, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 7, - VK_IMAGE_LAYOUT_PREINITIALIZED = 8, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002, - VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL = 1000117000, - VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = 1000117001, - VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR = 1000164003, - VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT = 1000218000, - VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL = 1000241000, - VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL = 1000241001, - VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL = 1000241002, - VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL = 1000241003, - VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL = 1000314000, - VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL = 1000314001, - VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT = 1000339000, - VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, - VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, - VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, - VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL, - VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL, - VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_MAX_ENUM = 0x7fffffff, -} VkImageLayout; - -typedef enum VkImageTiling -{ - VK_IMAGE_TILING_OPTIMAL = 0, - VK_IMAGE_TILING_LINEAR = 1, - VK_IMAGE_TILING_MAX_ENUM = 0x7fffffff, -} VkImageTiling; - -typedef enum VkImageType -{ - VK_IMAGE_TYPE_1D = 0, - VK_IMAGE_TYPE_2D = 1, - VK_IMAGE_TYPE_3D = 2, - VK_IMAGE_TYPE_MAX_ENUM = 0x7fffffff, -} VkImageType; - -typedef enum VkImageUsageFlagBits -{ - VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001, - VK_IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002, - VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004, - VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020, - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040, - VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080, - VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00000100, - VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x00000200, - VK_IMAGE_USAGE_INVOCATION_MASK_BIT_HUAWEI = 0x00040000, - VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x00080000, - VK_IMAGE_USAGE_SAMPLE_WEIGHT_BIT_QCOM = 0x00100000, - VK_IMAGE_USAGE_SAMPLE_BLOCK_MATCH_BIT_QCOM = 0x00200000, - VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV = VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, - VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkImageUsageFlagBits; - -typedef enum VkImageViewCreateFlagBits -{ - VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT = 0x00000001, - VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DEFERRED_BIT_EXT = 0x00000002, - VK_IMAGE_VIEW_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 0x00000004, - VK_IMAGE_VIEW_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkImageViewCreateFlagBits; - -typedef enum VkImageViewType -{ - VK_IMAGE_VIEW_TYPE_1D = 0, - VK_IMAGE_VIEW_TYPE_2D = 1, - VK_IMAGE_VIEW_TYPE_3D = 2, - VK_IMAGE_VIEW_TYPE_CUBE = 3, - VK_IMAGE_VIEW_TYPE_1D_ARRAY = 4, - VK_IMAGE_VIEW_TYPE_2D_ARRAY = 5, - VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 6, - VK_IMAGE_VIEW_TYPE_MAX_ENUM = 0x7fffffff, -} VkImageViewType; - -typedef enum VkIndexType -{ - VK_INDEX_TYPE_UINT16 = 0, - VK_INDEX_TYPE_UINT32 = 1, - VK_INDEX_TYPE_NONE_KHR = 1000165000, - VK_INDEX_TYPE_UINT8_EXT = 1000265000, - VK_INDEX_TYPE_NONE_NV = VK_INDEX_TYPE_NONE_KHR, - VK_INDEX_TYPE_MAX_ENUM = 0x7fffffff, -} VkIndexType; - -typedef enum VkIndirectCommandsLayoutUsageFlagBitsNV -{ - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_NV = 0x00000001, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NV = 0x00000002, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NV = 0x00000004, - VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_NV_MAX_ENUM = 0x7fffffff, -} VkIndirectCommandsLayoutUsageFlagBitsNV; - -typedef enum VkIndirectCommandsTokenTypeNV -{ - VK_INDIRECT_COMMANDS_TOKEN_TYPE_SHADER_GROUP_NV = 0, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_STATE_FLAGS_NV = 1, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NV = 2, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NV = 3, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NV = 4, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NV = 5, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NV = 6, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_TASKS_NV = 7, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV = 1000328000, - VK_INDIRECT_COMMANDS_TOKEN_TYPE_NV_MAX_ENUM = 0x7fffffff, -} VkIndirectCommandsTokenTypeNV; - -typedef enum VkIndirectStateFlagBitsNV -{ - VK_INDIRECT_STATE_FLAG_FRONTFACE_BIT_NV = 0x00000001, - VK_INDIRECT_STATE_FLAG_BITS_NV_MAX_ENUM = 0x7fffffff, -} VkIndirectStateFlagBitsNV; - -typedef enum VkInstanceCreateFlagBits -{ - VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR = 0x00000001, - VK_INSTANCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkInstanceCreateFlagBits; - -typedef enum VkInternalAllocationType -{ - VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0, - VK_INTERNAL_ALLOCATION_TYPE_MAX_ENUM = 0x7fffffff, -} VkInternalAllocationType; - -typedef enum VkLineRasterizationModeEXT -{ - VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT = 0, - VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT = 1, - VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT = 2, - VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT = 3, - VK_LINE_RASTERIZATION_MODE_EXT_MAX_ENUM = 0x7fffffff, -} VkLineRasterizationModeEXT; - -typedef enum VkLogicOp -{ - VK_LOGIC_OP_CLEAR = 0, - VK_LOGIC_OP_AND = 1, - VK_LOGIC_OP_AND_REVERSE = 2, - VK_LOGIC_OP_COPY = 3, - VK_LOGIC_OP_AND_INVERTED = 4, - VK_LOGIC_OP_NO_OP = 5, - VK_LOGIC_OP_XOR = 6, - VK_LOGIC_OP_OR = 7, - VK_LOGIC_OP_NOR = 8, - VK_LOGIC_OP_EQUIVALENT = 9, - VK_LOGIC_OP_INVERT = 10, - VK_LOGIC_OP_OR_REVERSE = 11, - VK_LOGIC_OP_COPY_INVERTED = 12, - VK_LOGIC_OP_OR_INVERTED = 13, - VK_LOGIC_OP_NAND = 14, - VK_LOGIC_OP_SET = 15, - VK_LOGIC_OP_MAX_ENUM = 0x7fffffff, -} VkLogicOp; - -typedef enum VkMemoryAllocateFlagBits -{ - VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT = 0x00000001, - VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT = 0x00000002, - VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT = 0x00000004, - VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT, - VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, - VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_KHR = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT, - VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkMemoryAllocateFlagBits; -typedef VkMemoryAllocateFlagBits VkMemoryAllocateFlagBitsKHR; - -typedef VkFlags64 VkMemoryDecompressionMethodFlagBitsNV; - -static const VkMemoryDecompressionMethodFlagBitsNV VK_MEMORY_DECOMPRESSION_METHOD_GDEFLATE_1_0_BIT_NV = 0x00000001ull; - -typedef enum VkMemoryHeapFlagBits -{ - VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001, - VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 0x00000002, - VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT, - VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkMemoryHeapFlagBits; - -typedef enum VkMemoryOverallocationBehaviorAMD -{ - VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD = 0, - VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD = 1, - VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2, - VK_MEMORY_OVERALLOCATION_BEHAVIOR_AMD_MAX_ENUM = 0x7fffffff, -} VkMemoryOverallocationBehaviorAMD; - -typedef enum VkMemoryPropertyFlagBits -{ - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002, - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004, - VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008, - VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010, - VK_MEMORY_PROPERTY_PROTECTED_BIT = 0x00000020, - VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD = 0x00000040, - VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD = 0x00000080, - VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkMemoryPropertyFlagBits; - -typedef enum VkMicromapCreateFlagBitsEXT -{ - VK_MICROMAP_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT = 0x00000001, - VK_MICROMAP_CREATE_FLAG_BITS_EXT_MAX_ENUM = 0x7fffffff, -} VkMicromapCreateFlagBitsEXT; - -typedef enum VkMicromapTypeEXT -{ - VK_MICROMAP_TYPE_OPACITY_MICROMAP_EXT = 0, - VK_MICROMAP_TYPE_EXT_MAX_ENUM = 0x7fffffff, -} VkMicromapTypeEXT; - -typedef enum VkObjectType -{ - VK_OBJECT_TYPE_UNKNOWN = 0, - VK_OBJECT_TYPE_INSTANCE = 1, - VK_OBJECT_TYPE_PHYSICAL_DEVICE = 2, - VK_OBJECT_TYPE_DEVICE = 3, - VK_OBJECT_TYPE_QUEUE = 4, - VK_OBJECT_TYPE_SEMAPHORE = 5, - VK_OBJECT_TYPE_COMMAND_BUFFER = 6, - VK_OBJECT_TYPE_FENCE = 7, - VK_OBJECT_TYPE_DEVICE_MEMORY = 8, - VK_OBJECT_TYPE_BUFFER = 9, - VK_OBJECT_TYPE_IMAGE = 10, - VK_OBJECT_TYPE_EVENT = 11, - VK_OBJECT_TYPE_QUERY_POOL = 12, - VK_OBJECT_TYPE_BUFFER_VIEW = 13, - VK_OBJECT_TYPE_IMAGE_VIEW = 14, - VK_OBJECT_TYPE_SHADER_MODULE = 15, - VK_OBJECT_TYPE_PIPELINE_CACHE = 16, - VK_OBJECT_TYPE_PIPELINE_LAYOUT = 17, - VK_OBJECT_TYPE_RENDER_PASS = 18, - VK_OBJECT_TYPE_PIPELINE = 19, - VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT = 20, - VK_OBJECT_TYPE_SAMPLER = 21, - VK_OBJECT_TYPE_DESCRIPTOR_POOL = 22, - VK_OBJECT_TYPE_DESCRIPTOR_SET = 23, - VK_OBJECT_TYPE_FRAMEBUFFER = 24, - VK_OBJECT_TYPE_COMMAND_POOL = 25, - VK_OBJECT_TYPE_SURFACE_KHR = 1000000000, - VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000, - VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000, - VK_OBJECT_TYPE_CU_MODULE_NVX = 1000029000, - VK_OBJECT_TYPE_CU_FUNCTION_NVX = 1000029001, - VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000, - VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000, - VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR = 1000150000, - VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000, - VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000, - VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, - VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL = 1000210000, - VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR = 1000268000, - VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV = 1000277000, - VK_OBJECT_TYPE_PRIVATE_DATA_SLOT = 1000295000, - VK_OBJECT_TYPE_MICROMAP_EXT = 1000396000, - VK_OBJECT_TYPE_OPTICAL_FLOW_SESSION_NV = 1000464000, - VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE, - VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION, - VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT = VK_OBJECT_TYPE_PRIVATE_DATA_SLOT, - VK_OBJECT_TYPE_MAX_ENUM = 0x7fffffff, -} VkObjectType; - -typedef enum VkOpacityMicromapFormatEXT -{ - VK_OPACITY_MICROMAP_FORMAT_2_STATE_EXT = 1, - VK_OPACITY_MICROMAP_FORMAT_4_STATE_EXT = 2, - VK_OPACITY_MICROMAP_FORMAT_EXT_MAX_ENUM = 0x7fffffff, -} VkOpacityMicromapFormatEXT; - -typedef enum VkOpacityMicromapSpecialIndexEXT -{ - VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_OPAQUE_EXT = -4, - VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_TRANSPARENT_EXT = -3, - VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_OPAQUE_EXT = -2, - VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_TRANSPARENT_EXT = -1, - VK_OPACITY_MICROMAP_SPECIAL_INDEX_EXT_MAX_ENUM = 0x7fffffff, -} VkOpacityMicromapSpecialIndexEXT; - -typedef enum VkOpticalFlowExecuteFlagBitsNV -{ - VK_OPTICAL_FLOW_EXECUTE_DISABLE_TEMPORAL_HINTS_BIT_NV = 0x00000001, - VK_OPTICAL_FLOW_EXECUTE_FLAG_BITS_NV_MAX_ENUM = 0x7fffffff, -} VkOpticalFlowExecuteFlagBitsNV; - -typedef enum VkOpticalFlowGridSizeFlagBitsNV -{ - VK_OPTICAL_FLOW_GRID_SIZE_UNKNOWN_NV = 0, - VK_OPTICAL_FLOW_GRID_SIZE_1X1_BIT_NV = 0x00000001, - VK_OPTICAL_FLOW_GRID_SIZE_2X2_BIT_NV = 0x00000002, - VK_OPTICAL_FLOW_GRID_SIZE_4X4_BIT_NV = 0x00000004, - VK_OPTICAL_FLOW_GRID_SIZE_8X8_BIT_NV = 0x00000008, - VK_OPTICAL_FLOW_GRID_SIZE_FLAG_BITS_NV_MAX_ENUM = 0x7fffffff, -} VkOpticalFlowGridSizeFlagBitsNV; - -typedef enum VkOpticalFlowPerformanceLevelNV -{ - VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_UNKNOWN_NV = 0, - VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_SLOW_NV = 1, - VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_MEDIUM_NV = 2, - VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_FAST_NV = 3, - VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_NV_MAX_ENUM = 0x7fffffff, -} VkOpticalFlowPerformanceLevelNV; - -typedef enum VkOpticalFlowSessionBindingPointNV -{ - VK_OPTICAL_FLOW_SESSION_BINDING_POINT_UNKNOWN_NV = 0, - VK_OPTICAL_FLOW_SESSION_BINDING_POINT_INPUT_NV = 1, - VK_OPTICAL_FLOW_SESSION_BINDING_POINT_REFERENCE_NV = 2, - VK_OPTICAL_FLOW_SESSION_BINDING_POINT_HINT_NV = 3, - VK_OPTICAL_FLOW_SESSION_BINDING_POINT_FLOW_VECTOR_NV = 4, - VK_OPTICAL_FLOW_SESSION_BINDING_POINT_BACKWARD_FLOW_VECTOR_NV = 5, - VK_OPTICAL_FLOW_SESSION_BINDING_POINT_COST_NV = 6, - VK_OPTICAL_FLOW_SESSION_BINDING_POINT_BACKWARD_COST_NV = 7, - VK_OPTICAL_FLOW_SESSION_BINDING_POINT_GLOBAL_FLOW_NV = 8, - VK_OPTICAL_FLOW_SESSION_BINDING_POINT_NV_MAX_ENUM = 0x7fffffff, -} VkOpticalFlowSessionBindingPointNV; - -typedef enum VkOpticalFlowSessionCreateFlagBitsNV -{ - VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_HINT_BIT_NV = 0x00000001, - VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_COST_BIT_NV = 0x00000002, - VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_GLOBAL_FLOW_BIT_NV = 0x00000004, - VK_OPTICAL_FLOW_SESSION_CREATE_ALLOW_REGIONS_BIT_NV = 0x00000008, - VK_OPTICAL_FLOW_SESSION_CREATE_BOTH_DIRECTIONS_BIT_NV = 0x00000010, - VK_OPTICAL_FLOW_SESSION_CREATE_FLAG_BITS_NV_MAX_ENUM = 0x7fffffff, -} VkOpticalFlowSessionCreateFlagBitsNV; - -typedef enum VkOpticalFlowUsageFlagBitsNV -{ - VK_OPTICAL_FLOW_USAGE_UNKNOWN_NV = 0, - VK_OPTICAL_FLOW_USAGE_INPUT_BIT_NV = 0x00000001, - VK_OPTICAL_FLOW_USAGE_OUTPUT_BIT_NV = 0x00000002, - VK_OPTICAL_FLOW_USAGE_HINT_BIT_NV = 0x00000004, - VK_OPTICAL_FLOW_USAGE_COST_BIT_NV = 0x00000008, - VK_OPTICAL_FLOW_USAGE_GLOBAL_FLOW_BIT_NV = 0x00000010, - VK_OPTICAL_FLOW_USAGE_FLAG_BITS_NV_MAX_ENUM = 0x7fffffff, -} VkOpticalFlowUsageFlagBitsNV; - -typedef enum VkPeerMemoryFeatureFlagBits -{ - VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 0x00000001, - VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 0x00000002, - VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT = 0x00000004, - VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT = 0x00000008, - VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT, - VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_COPY_DST_BIT, - VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT, - VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR = VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT, - VK_PEER_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkPeerMemoryFeatureFlagBits; -typedef VkPeerMemoryFeatureFlagBits VkPeerMemoryFeatureFlagBitsKHR; - -typedef enum VkPerformanceConfigurationTypeINTEL -{ - VK_PERFORMANCE_CONFIGURATION_TYPE_COMMAND_QUEUE_METRICS_DISCOVERY_ACTIVATED_INTEL = 0, - VK_PERFORMANCE_CONFIGURATION_TYPE_INTEL_MAX_ENUM = 0x7fffffff, -} VkPerformanceConfigurationTypeINTEL; - -typedef enum VkPerformanceCounterDescriptionFlagBitsKHR -{ - VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_BIT_KHR = 0x00000001, - VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_BIT_KHR = 0x00000002, - VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_KHR = VK_PERFORMANCE_COUNTER_DESCRIPTION_PERFORMANCE_IMPACTING_BIT_KHR, - VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_KHR = VK_PERFORMANCE_COUNTER_DESCRIPTION_CONCURRENTLY_IMPACTED_BIT_KHR, - VK_PERFORMANCE_COUNTER_DESCRIPTION_FLAG_BITS_KHR_MAX_ENUM = 0x7fffffff, -} VkPerformanceCounterDescriptionFlagBitsKHR; - -typedef enum VkPerformanceCounterScopeKHR -{ - VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR = 0, - VK_PERFORMANCE_COUNTER_SCOPE_RENDER_PASS_KHR = 1, - VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR = 2, - VK_QUERY_SCOPE_COMMAND_BUFFER_KHR = VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR, - VK_QUERY_SCOPE_RENDER_PASS_KHR = VK_PERFORMANCE_COUNTER_SCOPE_RENDER_PASS_KHR, - VK_QUERY_SCOPE_COMMAND_KHR = VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR, - VK_PERFORMANCE_COUNTER_SCOPE_KHR_MAX_ENUM = 0x7fffffff, -} VkPerformanceCounterScopeKHR; - -typedef enum VkPerformanceCounterStorageKHR -{ - VK_PERFORMANCE_COUNTER_STORAGE_INT32_KHR = 0, - VK_PERFORMANCE_COUNTER_STORAGE_INT64_KHR = 1, - VK_PERFORMANCE_COUNTER_STORAGE_UINT32_KHR = 2, - VK_PERFORMANCE_COUNTER_STORAGE_UINT64_KHR = 3, - VK_PERFORMANCE_COUNTER_STORAGE_FLOAT32_KHR = 4, - VK_PERFORMANCE_COUNTER_STORAGE_FLOAT64_KHR = 5, - VK_PERFORMANCE_COUNTER_STORAGE_KHR_MAX_ENUM = 0x7fffffff, -} VkPerformanceCounterStorageKHR; - -typedef enum VkPerformanceCounterUnitKHR -{ - VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR = 0, - VK_PERFORMANCE_COUNTER_UNIT_PERCENTAGE_KHR = 1, - VK_PERFORMANCE_COUNTER_UNIT_NANOSECONDS_KHR = 2, - VK_PERFORMANCE_COUNTER_UNIT_BYTES_KHR = 3, - VK_PERFORMANCE_COUNTER_UNIT_BYTES_PER_SECOND_KHR = 4, - VK_PERFORMANCE_COUNTER_UNIT_KELVIN_KHR = 5, - VK_PERFORMANCE_COUNTER_UNIT_WATTS_KHR = 6, - VK_PERFORMANCE_COUNTER_UNIT_VOLTS_KHR = 7, - VK_PERFORMANCE_COUNTER_UNIT_AMPS_KHR = 8, - VK_PERFORMANCE_COUNTER_UNIT_HERTZ_KHR = 9, - VK_PERFORMANCE_COUNTER_UNIT_CYCLES_KHR = 10, - VK_PERFORMANCE_COUNTER_UNIT_KHR_MAX_ENUM = 0x7fffffff, -} VkPerformanceCounterUnitKHR; - -typedef enum VkPerformanceOverrideTypeINTEL -{ - VK_PERFORMANCE_OVERRIDE_TYPE_NULL_HARDWARE_INTEL = 0, - VK_PERFORMANCE_OVERRIDE_TYPE_FLUSH_GPU_CACHES_INTEL = 1, - VK_PERFORMANCE_OVERRIDE_TYPE_INTEL_MAX_ENUM = 0x7fffffff, -} VkPerformanceOverrideTypeINTEL; - -typedef enum VkPerformanceParameterTypeINTEL -{ - VK_PERFORMANCE_PARAMETER_TYPE_HW_COUNTERS_SUPPORTED_INTEL = 0, - VK_PERFORMANCE_PARAMETER_TYPE_STREAM_MARKER_VALID_BITS_INTEL = 1, - VK_PERFORMANCE_PARAMETER_TYPE_INTEL_MAX_ENUM = 0x7fffffff, -} VkPerformanceParameterTypeINTEL; - -typedef enum VkPerformanceValueTypeINTEL -{ - VK_PERFORMANCE_VALUE_TYPE_UINT32_INTEL = 0, - VK_PERFORMANCE_VALUE_TYPE_UINT64_INTEL = 1, - VK_PERFORMANCE_VALUE_TYPE_FLOAT_INTEL = 2, - VK_PERFORMANCE_VALUE_TYPE_BOOL_INTEL = 3, - VK_PERFORMANCE_VALUE_TYPE_STRING_INTEL = 4, - VK_PERFORMANCE_VALUE_TYPE_INTEL_MAX_ENUM = 0x7fffffff, -} VkPerformanceValueTypeINTEL; - -typedef enum VkPhysicalDeviceType -{ - VK_PHYSICAL_DEVICE_TYPE_OTHER = 0, - VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1, - VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2, - VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3, - VK_PHYSICAL_DEVICE_TYPE_CPU = 4, - VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM = 0x7fffffff, -} VkPhysicalDeviceType; - -typedef enum VkPipelineBindPoint -{ - VK_PIPELINE_BIND_POINT_GRAPHICS = 0, - VK_PIPELINE_BIND_POINT_COMPUTE = 1, - VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR = 1000165000, - VK_PIPELINE_BIND_POINT_SUBPASS_SHADING_HUAWEI = 1000369003, - VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, - VK_PIPELINE_BIND_POINT_MAX_ENUM = 0x7fffffff, -} VkPipelineBindPoint; - -typedef enum VkPipelineCacheCreateFlagBits -{ - VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 0x00000001, - VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT = VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT, - VK_PIPELINE_CACHE_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkPipelineCacheCreateFlagBits; - -typedef enum VkPipelineCacheHeaderVersion -{ - VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1, - VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7fffffff, -} VkPipelineCacheHeaderVersion; - -typedef enum VkPipelineColorBlendStateCreateFlagBits -{ - VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT = 0x00000001, - VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_ARM = VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT, - VK_PIPELINE_COLOR_BLEND_STATE_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkPipelineColorBlendStateCreateFlagBits; - -typedef enum VkPipelineCompilerControlFlagBitsAMD -{ - VK_PIPELINE_COMPILER_CONTROL_FLAG_BITS_AMD_MAX_ENUM = 0x7fffffff, -} VkPipelineCompilerControlFlagBitsAMD; - -typedef enum VkPipelineCreateFlagBits -{ - VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001, - VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002, - VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, - VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008, - VK_PIPELINE_CREATE_DISPATCH_BASE_BIT = 0x00000010, - VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV = 0x00000020, - VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR = 0x00000040, - VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR = 0x00000080, - VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT = 0x00000100, - VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT = 0x00000200, - VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT = 0x00000400, - VK_PIPELINE_CREATE_LIBRARY_BIT_KHR = 0x00000800, - VK_PIPELINE_CREATE_RAY_TRACING_SKIP_TRIANGLES_BIT_KHR = 0x00001000, - VK_PIPELINE_CREATE_RAY_TRACING_SKIP_AABBS_BIT_KHR = 0x00002000, - VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_ANY_HIT_SHADERS_BIT_KHR = 0x00004000, - VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_CLOSEST_HIT_SHADERS_BIT_KHR = 0x00008000, - VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_MISS_SHADERS_BIT_KHR = 0x00010000, - VK_PIPELINE_CREATE_RAY_TRACING_NO_NULL_INTERSECTION_SHADERS_BIT_KHR = 0x00020000, - VK_PIPELINE_CREATE_INDIRECT_BINDABLE_BIT_NV = 0x00040000, - VK_PIPELINE_CREATE_RAY_TRACING_SHADER_GROUP_HANDLE_CAPTURE_REPLAY_BIT_KHR = 0x00080000, - VK_PIPELINE_CREATE_RAY_TRACING_ALLOW_MOTION_BIT_NV = 0x00100000, - VK_PIPELINE_CREATE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00200000, - VK_PIPELINE_CREATE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = 0x00400000, - VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT = 0x00800000, - VK_PIPELINE_CREATE_RAY_TRACING_OPACITY_MICROMAP_BIT_EXT = 0x01000000, - VK_PIPELINE_CREATE_COLOR_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x02000000, - VK_PIPELINE_CREATE_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x04000000, - VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT_EXT = 0x08000000, - VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT = 0x20000000, - VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT_EXT = 0x40000000, - VK_PIPELINE_CREATE_DISPATCH_BASE = VK_PIPELINE_CREATE_DISPATCH_BASE_BIT, - VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = VK_PIPELINE_CREATE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, - VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = VK_PIPELINE_CREATE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT, - VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT, - VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = VK_PIPELINE_CREATE_DISPATCH_BASE, - VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT = VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT, - VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT = VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT, - VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkPipelineCreateFlagBits; - -typedef enum VkPipelineCreationFeedbackFlagBits -{ - VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT = 0x00000001, - VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT = 0x00000002, - VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT = 0x00000004, - VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT, - VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT, - VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT = VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT, - VK_PIPELINE_CREATION_FEEDBACK_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkPipelineCreationFeedbackFlagBits; -typedef VkPipelineCreationFeedbackFlagBits VkPipelineCreationFeedbackFlagBitsEXT; - -typedef enum VkPipelineDepthStencilStateCreateFlagBits -{ - VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT = 0x00000001, - VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT = 0x00000002, - VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM = VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT, - VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM = VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT, - VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkPipelineDepthStencilStateCreateFlagBits; - -typedef enum VkPipelineExecutableStatisticFormatKHR -{ - VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR = 0, - VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR = 1, - VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR = 2, - VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR = 3, - VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_KHR_MAX_ENUM = 0x7fffffff, -} VkPipelineExecutableStatisticFormatKHR; - -typedef enum VkPipelineLayoutCreateFlagBits -{ - VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT = 0x00000002, - VK_PIPELINE_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkPipelineLayoutCreateFlagBits; - -typedef enum VkPipelineRobustnessBufferBehaviorEXT -{ - VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT_EXT = 0, - VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED_EXT = 1, - VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT = 2, - VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2_EXT = 3, - VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_EXT_MAX_ENUM = 0x7fffffff, -} VkPipelineRobustnessBufferBehaviorEXT; - -typedef enum VkPipelineRobustnessImageBehaviorEXT -{ - VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT_EXT = 0, - VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DISABLED_EXT = 1, - VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_EXT = 2, - VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2_EXT = 3, - VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_EXT_MAX_ENUM = 0x7fffffff, -} VkPipelineRobustnessImageBehaviorEXT; - -typedef enum VkPipelineShaderStageCreateFlagBits -{ - VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT = 0x00000001, - VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT = 0x00000002, - VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT = VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT, - VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT = VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT, - VK_PIPELINE_SHADER_STAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkPipelineShaderStageCreateFlagBits; - -typedef enum VkPipelineStageFlagBits -{ - VK_PIPELINE_STAGE_NONE = 0, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001, - VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002, - VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004, - VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008, - VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010, - VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020, - VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080, - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100, - VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800, - VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000, - VK_PIPELINE_STAGE_HOST_BIT = 0x00004000, - VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, - VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV = 0x00020000, - VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000, - VK_PIPELINE_STAGE_TASK_SHADER_BIT_EXT = 0x00080000, - VK_PIPELINE_STAGE_MESH_SHADER_BIT_EXT = 0x00100000, - VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR = 0x00200000, - VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00400000, - VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000, - VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000, - VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR = 0x02000000, - VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, - VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV = VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, - VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, - VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = VK_PIPELINE_STAGE_TASK_SHADER_BIT_EXT, - VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = VK_PIPELINE_STAGE_MESH_SHADER_BIT_EXT, - VK_PIPELINE_STAGE_NONE_KHR = VK_PIPELINE_STAGE_NONE, - VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkPipelineStageFlagBits; - -typedef VkFlags64 VkPipelineStageFlagBits2; - -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_NONE = 0ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_NONE_KHR = 0ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT = 0x00000001ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR = 0x00000001ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT = 0x00000002ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR = 0x00000002ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT = 0x00000004ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR = 0x00000004ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT = 0x00000008ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR = 0x00000008ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT_KHR = 0x00000010ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT_KHR = 0x00000020ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT = 0x00000040ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT_KHR = 0x00000040ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT = 0x00000080ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR = 0x00000080ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT = 0x00000100ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR = 0x00000100ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT = 0x00000200ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR = 0x00000200ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR = 0x00000400ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT = 0x00000800ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR = 0x00000800ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT = 0x00001000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR = 0x00001000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFER_BIT = 0x00001000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR = 0x00001000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT = 0x00002000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR = 0x00002000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_HOST_BIT = 0x00004000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_HOST_BIT_KHR = 0x00004000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT = 0x00008000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT_KHR = 0x00008000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT = 0x00010000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR = 0x00010000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_NV = 0x00020000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_NV = 0x00080000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_EXT = 0x00080000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_NV = 0x00100000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT = 0x00100000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR = 0x00200000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_NV = 0x00200000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00400000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_SHADING_RATE_IMAGE_BIT_NV = 0x00400000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR = 0x02000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_COPY_BIT_KHR = 0x10000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_OPTICAL_FLOW_BIT_NV = 0x20000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MICROMAP_BUILD_BIT_EXT = 0x40000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COPY_BIT = 0x100000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_COPY_BIT_KHR = 0x100000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RESOLVE_BIT = 0x200000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_RESOLVE_BIT_KHR = 0x200000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BLIT_BIT = 0x400000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_BLIT_BIT_KHR = 0x400000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLEAR_BIT = 0x800000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_CLEAR_BIT_KHR = 0x800000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT = 0x1000000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR = 0x1000000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT = 0x2000000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT_KHR = 0x2000000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT = 0x4000000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR = 0x4000000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI = 0x8000000000ull; -static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INVOCATION_MASK_BIT_HUAWEI = 0x10000000000ull; -typedef VkPipelineStageFlagBits2 VkPipelineStageFlagBits2KHR; - -typedef enum VkPointClippingBehavior -{ - VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0, - VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1, - VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES, - VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY, - VK_POINT_CLIPPING_BEHAVIOR_MAX_ENUM = 0x7fffffff, -} VkPointClippingBehavior; -typedef VkPointClippingBehavior VkPointClippingBehaviorKHR; - -typedef enum VkPolygonMode -{ - VK_POLYGON_MODE_FILL = 0, - VK_POLYGON_MODE_LINE = 1, - VK_POLYGON_MODE_POINT = 2, - VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000, - VK_POLYGON_MODE_MAX_ENUM = 0x7fffffff, -} VkPolygonMode; - -typedef enum VkPresentGravityFlagBitsEXT -{ - VK_PRESENT_GRAVITY_MIN_BIT_EXT = 0x00000001, - VK_PRESENT_GRAVITY_MAX_BIT_EXT = 0x00000002, - VK_PRESENT_GRAVITY_CENTERED_BIT_EXT = 0x00000004, - VK_PRESENT_GRAVITY_FLAG_BITS_EXT_MAX_ENUM = 0x7fffffff, -} VkPresentGravityFlagBitsEXT; - -typedef enum VkPresentModeKHR -{ - VK_PRESENT_MODE_IMMEDIATE_KHR = 0, - VK_PRESENT_MODE_MAILBOX_KHR = 1, - VK_PRESENT_MODE_FIFO_KHR = 2, - VK_PRESENT_MODE_FIFO_RELAXED_KHR = 3, - VK_PRESENT_MODE_KHR_MAX_ENUM = 0x7fffffff, -} VkPresentModeKHR; - -typedef enum VkPresentScalingFlagBitsEXT -{ - VK_PRESENT_SCALING_ONE_TO_ONE_BIT_EXT = 0x00000001, - VK_PRESENT_SCALING_ASPECT_RATIO_STRETCH_BIT_EXT = 0x00000002, - VK_PRESENT_SCALING_STRETCH_BIT_EXT = 0x00000004, - VK_PRESENT_SCALING_FLAG_BITS_EXT_MAX_ENUM = 0x7fffffff, -} VkPresentScalingFlagBitsEXT; - -typedef enum VkPrimitiveTopology -{ - VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0, - VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1, - VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 2, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 3, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 4, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 5, - VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 6, - VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9, - VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10, - VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7fffffff, -} VkPrimitiveTopology; - -typedef enum VkProvokingVertexModeEXT -{ - VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT = 0, - VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT = 1, - VK_PROVOKING_VERTEX_MODE_EXT_MAX_ENUM = 0x7fffffff, -} VkProvokingVertexModeEXT; - -typedef enum VkQueryControlFlagBits -{ - VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001, - VK_QUERY_CONTROL_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkQueryControlFlagBits; - -typedef enum VkQueryPipelineStatisticFlagBits -{ - VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 0x00000001, - VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 0x00000002, - VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 0x00000004, - VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 0x00000008, - VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 0x00000010, - VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 0x00000020, - VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 0x00000040, - VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 0x00000080, - VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100, - VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200, - VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400, - VK_QUERY_PIPELINE_STATISTIC_TASK_SHADER_INVOCATIONS_BIT_EXT = 0x00000800, - VK_QUERY_PIPELINE_STATISTIC_MESH_SHADER_INVOCATIONS_BIT_EXT = 0x00001000, - VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkQueryPipelineStatisticFlagBits; - -typedef enum VkQueryPoolSamplingModeINTEL -{ - VK_QUERY_POOL_SAMPLING_MODE_MANUAL_INTEL = 0, - VK_QUERY_POOL_SAMPLING_MODE_INTEL_MAX_ENUM = 0x7fffffff, -} VkQueryPoolSamplingModeINTEL; - -typedef enum VkQueryResultFlagBits -{ - VK_QUERY_RESULT_64_BIT = 0x00000001, - VK_QUERY_RESULT_WAIT_BIT = 0x00000002, - VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004, - VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008, - VK_QUERY_RESULT_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkQueryResultFlagBits; - -typedef enum VkQueryType -{ - VK_QUERY_TYPE_OCCLUSION = 0, - VK_QUERY_TYPE_PIPELINE_STATISTICS = 1, - VK_QUERY_TYPE_TIMESTAMP = 2, - VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004, - VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR = 1000116000, - VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR = 1000150000, - VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR = 1000150001, - VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000, - VK_QUERY_TYPE_PERFORMANCE_QUERY_INTEL = 1000210000, - VK_QUERY_TYPE_MESH_PRIMITIVES_GENERATED_EXT = 1000328000, - VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT = 1000382000, - VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR = 1000386000, - VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SIZE_KHR = 1000386001, - VK_QUERY_TYPE_MICROMAP_SERIALIZATION_SIZE_EXT = 1000396000, - VK_QUERY_TYPE_MICROMAP_COMPACTED_SIZE_EXT = 1000396001, - VK_QUERY_TYPE_MAX_ENUM = 0x7fffffff, -} VkQueryType; - -typedef enum VkQueueFlagBits -{ - VK_QUEUE_GRAPHICS_BIT = 0x00000001, - VK_QUEUE_COMPUTE_BIT = 0x00000002, - VK_QUEUE_TRANSFER_BIT = 0x00000004, - VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, - VK_QUEUE_PROTECTED_BIT = 0x00000010, - VK_QUEUE_OPTICAL_FLOW_BIT_NV = 0x00000100, - VK_QUEUE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkQueueFlagBits; - -typedef enum VkQueueGlobalPriorityKHR -{ - VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR = 128, - VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR = 256, - VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR = 512, - VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR = 1024, - VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT = VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR, - VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT = VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR, - VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT = VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR, - VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR, - VK_QUEUE_GLOBAL_PRIORITY_KHR_MAX_ENUM = 0x7fffffff, -} VkQueueGlobalPriorityKHR; -typedef VkQueueGlobalPriorityKHR VkQueueGlobalPriorityEXT; - -typedef enum VkRasterizationOrderAMD -{ - VK_RASTERIZATION_ORDER_STRICT_AMD = 0, - VK_RASTERIZATION_ORDER_RELAXED_AMD = 1, - VK_RASTERIZATION_ORDER_AMD_MAX_ENUM = 0x7fffffff, -} VkRasterizationOrderAMD; - -typedef enum VkRayTracingInvocationReorderModeNV -{ - VK_RAY_TRACING_INVOCATION_REORDER_MODE_NONE_NV = 0, - VK_RAY_TRACING_INVOCATION_REORDER_MODE_REORDER_NV = 1, - VK_RAY_TRACING_INVOCATION_REORDER_MODE_NV_MAX_ENUM = 0x7fffffff, -} VkRayTracingInvocationReorderModeNV; - -typedef enum VkRayTracingShaderGroupTypeKHR -{ - VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR = 0, - VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR = 1, - VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR = 2, - VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR, - VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR, - VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR, - VK_RAY_TRACING_SHADER_GROUP_TYPE_KHR_MAX_ENUM = 0x7fffffff, -} VkRayTracingShaderGroupTypeKHR; -typedef VkRayTracingShaderGroupTypeKHR VkRayTracingShaderGroupTypeNV; - -typedef enum VkRenderPassCreateFlagBits -{ - VK_RENDER_PASS_CREATE_TRANSFORM_BIT_QCOM = 0x00000002, - VK_RENDER_PASS_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkRenderPassCreateFlagBits; - -typedef enum VkRenderingFlagBits -{ - VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT = 0x00000001, - VK_RENDERING_SUSPENDING_BIT = 0x00000002, - VK_RENDERING_RESUMING_BIT = 0x00000004, - VK_RENDERING_ENABLE_LEGACY_DITHERING_BIT_EXT = 0x00000008, - VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR = VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT, - VK_RENDERING_SUSPENDING_BIT_KHR = VK_RENDERING_SUSPENDING_BIT, - VK_RENDERING_RESUMING_BIT_KHR = VK_RENDERING_RESUMING_BIT, - VK_RENDERING_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkRenderingFlagBits; -typedef VkRenderingFlagBits VkRenderingFlagBitsKHR; - -typedef enum VkResolveModeFlagBits -{ - VK_RESOLVE_MODE_NONE = 0, - VK_RESOLVE_MODE_SAMPLE_ZERO_BIT = 0x00000001, - VK_RESOLVE_MODE_AVERAGE_BIT = 0x00000002, - VK_RESOLVE_MODE_MIN_BIT = 0x00000004, - VK_RESOLVE_MODE_MAX_BIT = 0x00000008, - VK_RESOLVE_MODE_NONE_KHR = VK_RESOLVE_MODE_NONE, - VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT, - VK_RESOLVE_MODE_AVERAGE_BIT_KHR = VK_RESOLVE_MODE_AVERAGE_BIT, - VK_RESOLVE_MODE_MIN_BIT_KHR = VK_RESOLVE_MODE_MIN_BIT, - VK_RESOLVE_MODE_MAX_BIT_KHR = VK_RESOLVE_MODE_MAX_BIT, - VK_RESOLVE_MODE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkResolveModeFlagBits; -typedef VkResolveModeFlagBits VkResolveModeFlagBitsKHR; - -typedef enum VkResult -{ - VK_ERROR_COMPRESSION_EXHAUSTED_EXT = -1000338000, - VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS = -1000257000, - VK_ERROR_NOT_PERMITTED_KHR = -1000174001, - VK_ERROR_FRAGMENTATION = -1000161000, - VK_ERROR_INVALID_EXTERNAL_HANDLE = -1000072003, - VK_ERROR_OUT_OF_POOL_MEMORY = -1000069000, - VK_ERROR_INVALID_SHADER_NV = -1000012000, - VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, - VK_ERROR_OUT_OF_DATE_KHR = -1000001004, - VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001, - VK_ERROR_SURFACE_LOST_KHR = -1000000000, - VK_ERROR_UNKNOWN = -13, - VK_ERROR_FRAGMENTED_POOL = -12, - VK_ERROR_FORMAT_NOT_SUPPORTED = -11, - VK_ERROR_TOO_MANY_OBJECTS = -10, - VK_ERROR_INCOMPATIBLE_DRIVER = -9, - VK_ERROR_FEATURE_NOT_PRESENT = -8, - VK_ERROR_EXTENSION_NOT_PRESENT = -7, - VK_ERROR_LAYER_NOT_PRESENT = -6, - VK_ERROR_MEMORY_MAP_FAILED = -5, - VK_ERROR_DEVICE_LOST = -4, - VK_ERROR_INITIALIZATION_FAILED = -3, - VK_ERROR_OUT_OF_DEVICE_MEMORY = -2, - VK_ERROR_OUT_OF_HOST_MEMORY = -1, - VK_SUCCESS = 0, - VK_NOT_READY = 1, - VK_TIMEOUT = 2, - VK_EVENT_SET = 3, - VK_EVENT_RESET = 4, - VK_INCOMPLETE = 5, - VK_SUBOPTIMAL_KHR = 1000001003, - VK_THREAD_IDLE_KHR = 1000268000, - VK_THREAD_DONE_KHR = 1000268001, - VK_OPERATION_DEFERRED_KHR = 1000268002, - VK_OPERATION_NOT_DEFERRED_KHR = 1000268003, - VK_PIPELINE_COMPILE_REQUIRED = 1000297000, - VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY, - VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = VK_ERROR_INVALID_EXTERNAL_HANDLE, - VK_ERROR_FRAGMENTATION_EXT = VK_ERROR_FRAGMENTATION, - VK_ERROR_NOT_PERMITTED_EXT = VK_ERROR_NOT_PERMITTED_KHR, - VK_ERROR_INVALID_DEVICE_ADDRESS_EXT = VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, - VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR = VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, - VK_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED, - VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT = VK_PIPELINE_COMPILE_REQUIRED, - VK_RESULT_MAX_ENUM = 0x7fffffff, -} VkResult; - -typedef enum VkSampleCountFlagBits -{ - VK_SAMPLE_COUNT_1_BIT = 0x00000001, - VK_SAMPLE_COUNT_2_BIT = 0x00000002, - VK_SAMPLE_COUNT_4_BIT = 0x00000004, - VK_SAMPLE_COUNT_8_BIT = 0x00000008, - VK_SAMPLE_COUNT_16_BIT = 0x00000010, - VK_SAMPLE_COUNT_32_BIT = 0x00000020, - VK_SAMPLE_COUNT_64_BIT = 0x00000040, - VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkSampleCountFlagBits; - -typedef enum VkSamplerAddressMode -{ - VK_SAMPLER_ADDRESS_MODE_REPEAT = 0, - VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 1, - VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 2, - VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 3, - VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 4, - VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE_KHR = VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE, - VK_SAMPLER_ADDRESS_MODE_MAX_ENUM = 0x7fffffff, -} VkSamplerAddressMode; - -typedef enum VkSamplerCreateFlagBits -{ - VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT = 0x00000001, - VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT = 0x00000002, - VK_SAMPLER_CREATE_NON_SEAMLESS_CUBE_MAP_BIT_EXT = 0x00000004, - VK_SAMPLER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT = 0x00000008, - VK_SAMPLER_CREATE_IMAGE_PROCESSING_BIT_QCOM = 0x00000010, - VK_SAMPLER_CREATE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkSamplerCreateFlagBits; - -typedef enum VkSamplerMipmapMode -{ - VK_SAMPLER_MIPMAP_MODE_NEAREST = 0, - VK_SAMPLER_MIPMAP_MODE_LINEAR = 1, - VK_SAMPLER_MIPMAP_MODE_MAX_ENUM = 0x7fffffff, -} VkSamplerMipmapMode; - -typedef enum VkSamplerReductionMode -{ - VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE = 0, - VK_SAMPLER_REDUCTION_MODE_MIN = 1, - VK_SAMPLER_REDUCTION_MODE_MAX = 2, - VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT = VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE, - VK_SAMPLER_REDUCTION_MODE_MIN_EXT = VK_SAMPLER_REDUCTION_MODE_MIN, - VK_SAMPLER_REDUCTION_MODE_MAX_EXT = VK_SAMPLER_REDUCTION_MODE_MAX, - VK_SAMPLER_REDUCTION_MODE_MAX_ENUM = 0x7fffffff, -} VkSamplerReductionMode; -typedef VkSamplerReductionMode VkSamplerReductionModeEXT; - -typedef enum VkSamplerYcbcrModelConversion -{ - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY = 1, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709 = 2, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 = 3, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 = 4, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020, - VK_SAMPLER_YCBCR_MODEL_CONVERSION_MAX_ENUM = 0x7fffffff, -} VkSamplerYcbcrModelConversion; -typedef VkSamplerYcbcrModelConversion VkSamplerYcbcrModelConversionKHR; - -typedef enum VkSamplerYcbcrRange -{ - VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0, - VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1, - VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_FULL, - VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, - VK_SAMPLER_YCBCR_RANGE_MAX_ENUM = 0x7fffffff, -} VkSamplerYcbcrRange; -typedef VkSamplerYcbcrRange VkSamplerYcbcrRangeKHR; - -typedef enum VkScopeNV -{ - VK_SCOPE_DEVICE_NV = 1, - VK_SCOPE_WORKGROUP_NV = 2, - VK_SCOPE_SUBGROUP_NV = 3, - VK_SCOPE_QUEUE_FAMILY_NV = 5, - VK_SCOPE_NV_MAX_ENUM = 0x7fffffff, -} VkScopeNV; - -typedef enum VkSemaphoreImportFlagBits -{ - VK_SEMAPHORE_IMPORT_TEMPORARY_BIT = 0x00000001, - VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT, - VK_SEMAPHORE_IMPORT_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkSemaphoreImportFlagBits; -typedef VkSemaphoreImportFlagBits VkSemaphoreImportFlagBitsKHR; - -typedef enum VkSemaphoreType -{ - VK_SEMAPHORE_TYPE_BINARY = 0, - VK_SEMAPHORE_TYPE_TIMELINE = 1, - VK_SEMAPHORE_TYPE_BINARY_KHR = VK_SEMAPHORE_TYPE_BINARY, - VK_SEMAPHORE_TYPE_TIMELINE_KHR = VK_SEMAPHORE_TYPE_TIMELINE, - VK_SEMAPHORE_TYPE_MAX_ENUM = 0x7fffffff, -} VkSemaphoreType; -typedef VkSemaphoreType VkSemaphoreTypeKHR; - -typedef enum VkSemaphoreWaitFlagBits -{ - VK_SEMAPHORE_WAIT_ANY_BIT = 0x00000001, - VK_SEMAPHORE_WAIT_ANY_BIT_KHR = VK_SEMAPHORE_WAIT_ANY_BIT, - VK_SEMAPHORE_WAIT_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkSemaphoreWaitFlagBits; -typedef VkSemaphoreWaitFlagBits VkSemaphoreWaitFlagBitsKHR; - -typedef enum VkShaderCorePropertiesFlagBitsAMD -{ - VK_SHADER_CORE_PROPERTIES_FLAG_BITS_AMD_MAX_ENUM = 0x7fffffff, -} VkShaderCorePropertiesFlagBitsAMD; - -typedef enum VkShaderFloatControlsIndependence -{ - VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY = 0, - VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL = 1, - VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE = 2, - VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY, - VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL, - VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE, - VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_MAX_ENUM = 0x7fffffff, -} VkShaderFloatControlsIndependence; -typedef VkShaderFloatControlsIndependence VkShaderFloatControlsIndependenceKHR; - -typedef enum VkShaderGroupShaderKHR -{ - VK_SHADER_GROUP_SHADER_GENERAL_KHR = 0, - VK_SHADER_GROUP_SHADER_CLOSEST_HIT_KHR = 1, - VK_SHADER_GROUP_SHADER_ANY_HIT_KHR = 2, - VK_SHADER_GROUP_SHADER_INTERSECTION_KHR = 3, - VK_SHADER_GROUP_SHADER_KHR_MAX_ENUM = 0x7fffffff, -} VkShaderGroupShaderKHR; - -typedef enum VkShaderInfoTypeAMD -{ - VK_SHADER_INFO_TYPE_STATISTICS_AMD = 0, - VK_SHADER_INFO_TYPE_BINARY_AMD = 1, - VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD = 2, - VK_SHADER_INFO_TYPE_AMD_MAX_ENUM = 0x7fffffff, -} VkShaderInfoTypeAMD; - -typedef enum VkShaderStageFlagBits -{ - VK_SHADER_STAGE_VERTEX_BIT = 0x00000001, - VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002, - VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004, - VK_SHADER_STAGE_GEOMETRY_BIT = 0x00000008, - VK_SHADER_STAGE_FRAGMENT_BIT = 0x00000010, - VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001f, - VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020, - VK_SHADER_STAGE_TASK_BIT_EXT = 0x00000040, - VK_SHADER_STAGE_MESH_BIT_EXT = 0x00000080, - VK_SHADER_STAGE_RAYGEN_BIT_KHR = 0x00000100, - VK_SHADER_STAGE_ANY_HIT_BIT_KHR = 0x00000200, - VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR = 0x00000400, - VK_SHADER_STAGE_MISS_BIT_KHR = 0x00000800, - VK_SHADER_STAGE_INTERSECTION_BIT_KHR = 0x00001000, - VK_SHADER_STAGE_CALLABLE_BIT_KHR = 0x00002000, - VK_SHADER_STAGE_SUBPASS_SHADING_BIT_HUAWEI = 0x00004000, - VK_SHADER_STAGE_RAYGEN_BIT_NV = VK_SHADER_STAGE_RAYGEN_BIT_KHR, - VK_SHADER_STAGE_ANY_HIT_BIT_NV = VK_SHADER_STAGE_ANY_HIT_BIT_KHR, - VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, - VK_SHADER_STAGE_MISS_BIT_NV = VK_SHADER_STAGE_MISS_BIT_KHR, - VK_SHADER_STAGE_INTERSECTION_BIT_NV = VK_SHADER_STAGE_INTERSECTION_BIT_KHR, - VK_SHADER_STAGE_CALLABLE_BIT_NV = VK_SHADER_STAGE_CALLABLE_BIT_KHR, - VK_SHADER_STAGE_TASK_BIT_NV = VK_SHADER_STAGE_TASK_BIT_EXT, - VK_SHADER_STAGE_MESH_BIT_NV = VK_SHADER_STAGE_MESH_BIT_EXT, - VK_SHADER_STAGE_ALL = 0x7fffffff, -} VkShaderStageFlagBits; - -typedef enum VkShadingRatePaletteEntryNV -{ - VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV = 0, - VK_SHADING_RATE_PALETTE_ENTRY_16_INVOCATIONS_PER_PIXEL_NV = 1, - VK_SHADING_RATE_PALETTE_ENTRY_8_INVOCATIONS_PER_PIXEL_NV = 2, - VK_SHADING_RATE_PALETTE_ENTRY_4_INVOCATIONS_PER_PIXEL_NV = 3, - VK_SHADING_RATE_PALETTE_ENTRY_2_INVOCATIONS_PER_PIXEL_NV = 4, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV = 5, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X1_PIXELS_NV = 6, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV = 7, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV = 8, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X2_PIXELS_NV = 9, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X4_PIXELS_NV = 10, - VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV = 11, - VK_SHADING_RATE_PALETTE_ENTRY_NV_MAX_ENUM = 0x7fffffff, -} VkShadingRatePaletteEntryNV; - -typedef enum VkSharingMode -{ - VK_SHARING_MODE_EXCLUSIVE = 0, - VK_SHARING_MODE_CONCURRENT = 1, - VK_SHARING_MODE_MAX_ENUM = 0x7fffffff, -} VkSharingMode; - -typedef enum VkSparseImageFormatFlagBits -{ - VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 0x00000001, - VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 0x00000002, - VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 0x00000004, - VK_SPARSE_IMAGE_FORMAT_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkSparseImageFormatFlagBits; - -typedef enum VkSparseMemoryBindFlagBits -{ - VK_SPARSE_MEMORY_BIND_METADATA_BIT = 0x00000001, - VK_SPARSE_MEMORY_BIND_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkSparseMemoryBindFlagBits; - -typedef enum VkStencilFaceFlagBits -{ - VK_STENCIL_FACE_FRONT_BIT = 0x00000001, - VK_STENCIL_FACE_BACK_BIT = 0x00000002, - VK_STENCIL_FACE_FRONT_AND_BACK = 0x00000003, - VK_STENCIL_FRONT_AND_BACK = VK_STENCIL_FACE_FRONT_AND_BACK, - VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkStencilFaceFlagBits; - -typedef enum VkStencilOp -{ - VK_STENCIL_OP_KEEP = 0, - VK_STENCIL_OP_ZERO = 1, - VK_STENCIL_OP_REPLACE = 2, - VK_STENCIL_OP_INCREMENT_AND_CLAMP = 3, - VK_STENCIL_OP_DECREMENT_AND_CLAMP = 4, - VK_STENCIL_OP_INVERT = 5, - VK_STENCIL_OP_INCREMENT_AND_WRAP = 6, - VK_STENCIL_OP_DECREMENT_AND_WRAP = 7, - VK_STENCIL_OP_MAX_ENUM = 0x7fffffff, -} VkStencilOp; - -typedef enum VkStructureType -{ - VK_STRUCTURE_TYPE_APPLICATION_INFO = 0, - VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1, - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2, - VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3, - VK_STRUCTURE_TYPE_SUBMIT_INFO = 4, - VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 5, - VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE = 6, - VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 7, - VK_STRUCTURE_TYPE_FENCE_CREATE_INFO = 8, - VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO = 9, - VK_STRUCTURE_TYPE_EVENT_CREATE_INFO = 10, - VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO = 11, - VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 12, - VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO = 13, - VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 14, - VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO = 15, - VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO = 16, - VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO = 17, - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO = 18, - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19, - VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20, - VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23, - VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24, - VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25, - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26, - VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27, - VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO = 28, - VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO = 29, - VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO = 30, - VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO = 31, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32, - VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO = 33, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO = 34, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET = 35, - VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET = 36, - VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO = 37, - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO = 38, - VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO = 39, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO = 40, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO = 41, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 42, - VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO = 43, - VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER = 44, - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 45, - VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46, - VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47, - VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES = 49, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES = 50, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES = 51, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES = 52, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES = 53, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES = 54, - VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000, - VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001, - VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, - VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000, - VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000, - VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001, - VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002, - VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000, - VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001, - VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002, - VK_STRUCTURE_TYPE_CU_MODULE_CREATE_INFO_NVX = 1000029000, - VK_STRUCTURE_TYPE_CU_FUNCTION_CREATE_INFO_NVX = 1000029001, - VK_STRUCTURE_TYPE_CU_LAUNCH_INFO_NVX = 1000029002, - VK_STRUCTURE_TYPE_IMAGE_VIEW_HANDLE_INFO_NVX = 1000030000, - VK_STRUCTURE_TYPE_IMAGE_VIEW_ADDRESS_PROPERTIES_NVX = 1000030001, - VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, - VK_STRUCTURE_TYPE_RENDERING_INFO = 1000044000, - VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO = 1000044001, - VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO = 1000044002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES = 1000044003, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO = 1000044004, - VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR = 1000044006, - VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_INFO_EXT = 1000044007, - VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD = 1000044008, - VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_ATTRIBUTES_INFO_NVX = 1000044009, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000, - VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO = 1000053000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES = 1000053001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES = 1000053002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 = 1000059000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 = 1000059001, - VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2 = 1000059002, - VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 = 1000059003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 = 1000059004, - VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 = 1000059005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 = 1000059006, - VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2 = 1000059007, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2 = 1000059008, - VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO = 1000060000, - VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO = 1000060003, - VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO = 1000060004, - VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO = 1000060005, - VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO = 1000060006, - VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007, - VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR = 1000060008, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR = 1000060009, - VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR = 1000060010, - VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR = 1000060011, - VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR = 1000060012, - VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO = 1000060013, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO = 1000060014, - VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES = 1000063000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES = 1000066000, - VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT = 1000067000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT = 1000067001, - VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT = 1000068000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT = 1000068001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES_EXT = 1000068002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES = 1000070000, - VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO = 1000070001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO = 1000071000, - VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES = 1000071001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO = 1000071002, - VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES = 1000071003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES = 1000071004, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO = 1000072000, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO = 1000072001, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO = 1000072002, - VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001, - VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002, - VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR = 1000073003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO = 1000076000, - VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES = 1000076001, - VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO = 1000077000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT = 1000081000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT = 1000081001, - VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT = 1000081002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES = 1000082000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES = 1000083000, - VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000, - VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO = 1000085000, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES = 1000094000, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV = 1000098000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000, - VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT = 1000101000, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT = 1000101001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT = 1000102000, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT = 1000102001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES = 1000108000, - VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO = 1000108001, - VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO = 1000108002, - VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO = 1000108003, - VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2 = 1000109000, - VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2 = 1000109001, - VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2 = 1000109002, - VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2 = 1000109003, - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2 = 1000109004, - VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO = 1000109005, - VK_STRUCTURE_TYPE_SUBPASS_END_INFO = 1000109006, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO = 1000112000, - VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES = 1000112001, - VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO = 1000113000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR = 1000116000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR = 1000116001, - VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_CREATE_INFO_KHR = 1000116002, - VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR = 1000116003, - VK_STRUCTURE_TYPE_ACQUIRE_PROFILING_LOCK_INFO_KHR = 1000116004, - VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_KHR = 1000116005, - VK_STRUCTURE_TYPE_PERFORMANCE_COUNTER_DESCRIPTION_KHR = 1000116006, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES = 1000117000, - VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO = 1000117001, - VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO = 1000117002, - VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO = 1000117003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000, - VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001, - VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES = 1000120000, - VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS = 1000127000, - VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO = 1000127001, - VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT = 1000128000, - VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT = 1000128001, - VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT = 1000128002, - VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT = 1000128003, - VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT = 1000128004, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES = 1000130000, - VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO = 1000130001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES = 1000138000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES = 1000138001, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK = 1000138002, - VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO = 1000138003, - VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT = 1000143000, - VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001, - VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT = 1000143003, - VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT = 1000143004, - VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO = 1000145000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES = 1000145001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES = 1000145002, - VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2 = 1000145003, - VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 = 1000146000, - VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2 = 1000146001, - VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 = 1000146002, - VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 = 1000146003, - VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2 = 1000146004, - VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO = 1000147000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT = 1000148000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001, - VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002, - VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR = 1000150000, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR = 1000150002, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR = 1000150003, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR = 1000150004, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR = 1000150005, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR = 1000150006, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR = 1000150007, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_VERSION_INFO_KHR = 1000150009, - VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR = 1000150010, - VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_TO_MEMORY_INFO_KHR = 1000150011, - VK_STRUCTURE_TYPE_COPY_MEMORY_TO_ACCELERATION_STRUCTURE_INFO_KHR = 1000150012, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR = 1000150013, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR = 1000150014, - VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR = 1000150015, - VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR = 1000150016, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR = 1000150017, - VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_INTERFACE_CREATE_INFO_KHR = 1000150018, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR = 1000150020, - VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV = 1000154000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV = 1000154001, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO = 1000156000, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO = 1000156001, - VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO = 1000156002, - VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO = 1000156003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES = 1000156004, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES = 1000156005, - VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO = 1000157000, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO = 1000157001, - VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000, - VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO = 1000161000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES = 1000161001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES = 1000161002, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO = 1000161003, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT = 1000161004, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV = 1000164000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV = 1000164001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005, - VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV = 1000165000, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000165001, - VK_STRUCTURE_TYPE_GEOMETRY_NV = 1000165003, - VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV = 1000165004, - VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV = 1000165005, - VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009, - VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV = 1000165012, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000, - VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV = 1000166001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT = 1000170000, - VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT = 1000170001, - VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR = 1000174000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES = 1000175000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES = 1000177000, - VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000, - VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES = 1000180000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR = 1000181000, - VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD = 1000183000, - VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000, - VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000, - VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002, - VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO = 1000192000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES = 1000196000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES = 1000197000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES = 1000199000, - VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE = 1000199001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV = 1000201000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV = 1000202000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV = 1000202001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR = 1000203000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV = 1000204000, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV = 1000205000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV = 1000205002, - VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000, - VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES = 1000207000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES = 1000207001, - VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO = 1000207002, - VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO = 1000207003, - VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO = 1000207004, - VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO = 1000207005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL = 1000209000, - VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL = 1000210000, - VK_STRUCTURE_TYPE_INITIALIZE_PERFORMANCE_API_INFO_INTEL = 1000210001, - VK_STRUCTURE_TYPE_PERFORMANCE_MARKER_INFO_INTEL = 1000210002, - VK_STRUCTURE_TYPE_PERFORMANCE_STREAM_MARKER_INFO_INTEL = 1000210003, - VK_STRUCTURE_TYPE_PERFORMANCE_OVERRIDE_INFO_INTEL = 1000210004, - VK_STRUCTURE_TYPE_PERFORMANCE_CONFIGURATION_ACQUIRE_INFO_INTEL = 1000210005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES = 1000211000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT = 1000212000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES = 1000215000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT = 1000218000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT = 1000218001, - VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT = 1000218002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES = 1000221000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES = 1000225000, - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO = 1000225001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES = 1000225002, - VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR = 1000226000, - VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR = 1000226001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR = 1000226002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR = 1000226003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR = 1000226004, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD = 1000227000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD = 1000229000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT = 1000234000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT = 1000237000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT = 1000238000, - VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT = 1000238001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV = 1000240000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES = 1000241000, - VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT = 1000241001, - VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT = 1000241002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT = 1000244000, - VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO = 1000244001, - VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_CREATE_INFO_EXT = 1000244002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES = 1000245000, - VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO = 1000246000, - VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT = 1000247000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR = 1000248000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV = 1000249000, - VK_STRUCTURE_TYPE_COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV = 1000249002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV = 1000250000, - VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_REDUCTION_STATE_CREATE_INFO_NV = 1000250001, - VK_STRUCTURE_TYPE_FRAMEBUFFER_MIXED_SAMPLES_COMBINATION_NV = 1000250002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT = 1000251000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT = 1000252000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES = 1000253000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT = 1000254000, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT = 1000254001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT = 1000254002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES = 1000257000, - VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO = 1000257002, - VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO = 1000257003, - VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO = 1000257004, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT = 1000259000, - VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT = 1000259001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT = 1000259002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT = 1000260000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES = 1000261000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT = 1000265000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT = 1000267000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR = 1000269000, - VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR = 1000269001, - VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR = 1000269002, - VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR = 1000269003, - VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_STATISTIC_KHR = 1000269004, - VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR = 1000269005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT = 1000273000, - VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT = 1000274000, - VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT = 1000274001, - VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT = 1000274002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT = 1000275000, - VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT = 1000275001, - VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_EXT = 1000275002, - VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT = 1000275003, - VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_SCALING_CREATE_INFO_EXT = 1000275004, - VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_EXT = 1000275005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES = 1000276000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV = 1000277000, - VK_STRUCTURE_TYPE_GRAPHICS_SHADER_GROUP_CREATE_INFO_NV = 1000277001, - VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV = 1000277002, - VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_TOKEN_NV = 1000277003, - VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NV = 1000277004, - VK_STRUCTURE_TYPE_GENERATED_COMMANDS_INFO_NV = 1000277005, - VK_STRUCTURE_TYPE_GENERATED_COMMANDS_MEMORY_REQUIREMENTS_INFO_NV = 1000277006, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV = 1000277007, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV = 1000278000, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV = 1000278001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES = 1000280000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES = 1000280001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT = 1000281000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES = 1000281001, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDER_PASS_TRANSFORM_INFO_QCOM = 1000282000, - VK_STRUCTURE_TYPE_RENDER_PASS_TRANSFORM_BEGIN_INFO_QCOM = 1000282001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT = 1000286000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT = 1000286001, - VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT = 1000287000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT = 1000287001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT = 1000287002, - VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR = 1000290000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_BARRIER_FEATURES_NV = 1000292000, - VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_PRESENT_BARRIER_NV = 1000292001, - VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_BARRIER_CREATE_INFO_NV = 1000292002, - VK_STRUCTURE_TYPE_PRESENT_ID_KHR = 1000294000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR = 1000294001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES = 1000295000, - VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO = 1000295001, - VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO = 1000295002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES = 1000297000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV = 1000300000, - VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV = 1000300001, - VK_STRUCTURE_TYPE_MEMORY_BARRIER_2 = 1000314000, - VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 = 1000314001, - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 = 1000314002, - VK_STRUCTURE_TYPE_DEPENDENCY_INFO = 1000314003, - VK_STRUCTURE_TYPE_SUBMIT_INFO_2 = 1000314004, - VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO = 1000314005, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO = 1000314006, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES = 1000314007, - VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV = 1000314008, - VK_STRUCTURE_TYPE_CHECKPOINT_DATA_2_NV = 1000314009, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT = 1000316000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT = 1000316001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT = 1000316002, - VK_STRUCTURE_TYPE_DESCRIPTOR_ADDRESS_INFO_EXT = 1000316003, - VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT = 1000316004, - VK_STRUCTURE_TYPE_BUFFER_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316005, - VK_STRUCTURE_TYPE_IMAGE_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316006, - VK_STRUCTURE_TYPE_IMAGE_VIEW_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316007, - VK_STRUCTURE_TYPE_SAMPLER_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316008, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CAPTURE_DESCRIPTOR_DATA_INFO_EXT = 1000316009, - VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT = 1000316010, - VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT = 1000316011, - VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_PUSH_DESCRIPTOR_BUFFER_HANDLE_EXT = 1000316012, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT = 1000320000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT = 1000320001, - VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT = 1000320002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD = 1000321000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR = 1000322000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR = 1000323000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES = 1000325000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV = 1000326000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV = 1000326001, - VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_ENUM_STATE_CREATE_INFO_NV = 1000326002, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_MOTION_TRIANGLES_DATA_NV = 1000327000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV = 1000327001, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MOTION_INFO_NV = 1000327002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT = 1000328000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT = 1000328001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT = 1000330000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT = 1000332000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT = 1000332001, - VK_STRUCTURE_TYPE_COPY_COMMAND_TRANSFORM_INFO_QCOM = 1000333000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES = 1000335000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR = 1000336000, - VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2 = 1000337000, - VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2 = 1000337001, - VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2 = 1000337002, - VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2 = 1000337003, - VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2 = 1000337004, - VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2 = 1000337005, - VK_STRUCTURE_TYPE_BUFFER_COPY_2 = 1000337006, - VK_STRUCTURE_TYPE_IMAGE_COPY_2 = 1000337007, - VK_STRUCTURE_TYPE_IMAGE_BLIT_2 = 1000337008, - VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2 = 1000337009, - VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2 = 1000337010, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT = 1000338000, - VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT = 1000338001, - VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2_EXT = 1000338002, - VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2_EXT = 1000338003, - VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT = 1000338004, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT = 1000339000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT = 1000340000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT = 1000341000, - VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT = 1000341001, - VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT = 1000341002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT = 1000342000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT = 1000344000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR = 1000347000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR = 1000347001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR = 1000348013, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT = 1000351000, - VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT = 1000351002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT = 1000352000, - VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT = 1000352001, - VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT = 1000352002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ADDRESS_BINDING_REPORT_FEATURES_EXT = 1000354000, - VK_STRUCTURE_TYPE_DEVICE_ADDRESS_BINDING_CALLBACK_DATA_EXT = 1000354001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT = 1000355000, - VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT = 1000355001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT = 1000356000, - VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3 = 1000360000, - VK_STRUCTURE_TYPE_SUBPASS_SHADING_PIPELINE_CREATE_INFO_HUAWEI = 1000369000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI = 1000369001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI = 1000369002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI = 1000370000, - VK_STRUCTURE_TYPE_PIPELINE_PROPERTIES_IDENTIFIER_EXT = 1000372000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT = 1000372001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT = 1000376000, - VK_STRUCTURE_TYPE_SUBPASS_RESOLVE_PERFORMANCE_QUERY_EXT = 1000376001, - VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_EXT = 1000376002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT = 1000377000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT = 1000381000, - VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT = 1000381001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT = 1000382000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR = 1000386000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR = 1000388000, - VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR = 1000388001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT = 1000391000, - VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT = 1000391001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT = 1000392000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT = 1000392001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT = 1000393000, - VK_STRUCTURE_TYPE_MICROMAP_BUILD_INFO_EXT = 1000396000, - VK_STRUCTURE_TYPE_MICROMAP_VERSION_INFO_EXT = 1000396001, - VK_STRUCTURE_TYPE_COPY_MICROMAP_INFO_EXT = 1000396002, - VK_STRUCTURE_TYPE_COPY_MICROMAP_TO_MEMORY_INFO_EXT = 1000396003, - VK_STRUCTURE_TYPE_COPY_MEMORY_TO_MICROMAP_INFO_EXT = 1000396004, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_EXT = 1000396005, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_EXT = 1000396006, - VK_STRUCTURE_TYPE_MICROMAP_CREATE_INFO_EXT = 1000396007, - VK_STRUCTURE_TYPE_MICROMAP_BUILD_SIZES_INFO_EXT = 1000396008, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_TRIANGLES_OPACITY_MICROMAP_EXT = 1000396009, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT = 1000411000, - VK_STRUCTURE_TYPE_SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT = 1000411001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT = 1000412000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES = 1000413000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES = 1000413001, - VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS = 1000413002, - VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS = 1000413003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE = 1000420000, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_BINDING_REFERENCE_VALVE = 1000420001, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_HOST_MAPPING_INFO_VALVE = 1000420002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT = 1000421000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT = 1000422000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM = 1000425000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_QCOM = 1000425001, - VK_STRUCTURE_TYPE_SUBPASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_QCOM = 1000425002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_NV = 1000426000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_NV = 1000426001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_NV = 1000427000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_NV = 1000427001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV = 1000430000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT = 1000437000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM = 1000440000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM = 1000440001, - VK_STRUCTURE_TYPE_IMAGE_VIEW_SAMPLE_WEIGHT_CREATE_INFO_QCOM = 1000440002, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT = 1000455000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT = 1000455001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT = 1000458000, - VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_CONTROL_EXT = 1000458001, - VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_FEEDBACK_CREATE_INFO_EXT = 1000458002, - VK_STRUCTURE_TYPE_RENDER_PASS_SUBPASS_FEEDBACK_CREATE_INFO_EXT = 1000458003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT = 1000462000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT = 1000462001, - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_MODULE_IDENTIFIER_CREATE_INFO_EXT = 1000462002, - VK_STRUCTURE_TYPE_SHADER_MODULE_IDENTIFIER_EXT = 1000462003, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV = 1000464000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV = 1000464001, - VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_INFO_NV = 1000464002, - VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_PROPERTIES_NV = 1000464003, - VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_INFO_NV = 1000464004, - VK_STRUCTURE_TYPE_OPTICAL_FLOW_EXECUTE_INFO_NV = 1000464005, - VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_PRIVATE_DATA_INFO_NV = 1000464010, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT = 1000465000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT = 1000466000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM = 1000484000, - VK_STRUCTURE_TYPE_TILE_PROPERTIES_QCOM = 1000484001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM = 1000488000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV = 1000490000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV = 1000490001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM = 1000497000, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM = 1000497001, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES, - VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, - VK_STRUCTURE_TYPE_RENDERING_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_INFO, - VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, - VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO, - VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_NV = VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD, - VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, - VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, - VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, - VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2, - VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2, - VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO, - VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO, - VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO, - VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO, - VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO, - VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES, - VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, - VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO, - VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO, - VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, - VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, - VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, - VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES, - VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES, - VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO, - VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO, - VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO, - VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, - VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, - VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2, - VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2, - VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2, - VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR = VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO, - VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR = VK_STRUCTURE_TYPE_SUBPASS_END_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, - VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES, - VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES, - VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO, - VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, - VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES_KHR, - VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, - VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES, - VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES, - VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK, - VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO, - VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2, - VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2, - VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR = VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2, - VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, - VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR = VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2, - VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, - VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO, - VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO_KHR = VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES, - VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES, - VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO, - VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES, - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT, - VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES, - VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES, - VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES, - VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, - VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO, - VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, - VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO, - VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO_INTEL = VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES, - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES, - VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT, - VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT_KHR = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT, - VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_EXT = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES, - VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES, - VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, - VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_BUFFER_OPAQUE_CAPTURE_ADDRESS_CREATE_INFO, - VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO_KHR = VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO, - VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO_KHR = VK_STRUCTURE_TYPE_DEVICE_MEMORY_OPAQUE_CAPTURE_ADDRESS_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES, - VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO, - VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES, - VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2, - VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2, - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, - VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, - VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, - VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES, - VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2, - VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2, - VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2, - VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2_KHR = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2, - VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2, - VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2_KHR = VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2, - VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR = VK_STRUCTURE_TYPE_BUFFER_COPY_2, - VK_STRUCTURE_TYPE_IMAGE_COPY_2_KHR = VK_STRUCTURE_TYPE_IMAGE_COPY_2, - VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR = VK_STRUCTURE_TYPE_IMAGE_BLIT_2, - VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR = VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2, - VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2_KHR = VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_VALVE = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT, - VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE = VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT, - VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3_KHR = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3, - VK_STRUCTURE_TYPE_PIPELINE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR, - VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES, - VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS, - VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS_KHR = VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS, - VK_STRUCTURE_TYPE_MAX_ENUM = 0x7fffffff, -} VkStructureType; - -typedef enum VkSubgroupFeatureFlagBits -{ - VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001, - VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002, - VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004, - VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008, - VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010, - VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020, - VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040, - VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080, - VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 0x00000100, - VK_SUBGROUP_FEATURE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkSubgroupFeatureFlagBits; - -typedef enum VkSubmitFlagBits -{ - VK_SUBMIT_PROTECTED_BIT = 0x00000001, - VK_SUBMIT_PROTECTED_BIT_KHR = VK_SUBMIT_PROTECTED_BIT, - VK_SUBMIT_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkSubmitFlagBits; -typedef VkSubmitFlagBits VkSubmitFlagBitsKHR; - -typedef enum VkSubpassContents -{ - VK_SUBPASS_CONTENTS_INLINE = 0, - VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 1, - VK_SUBPASS_CONTENTS_MAX_ENUM = 0x7fffffff, -} VkSubpassContents; - -typedef enum VkSubpassDescriptionFlagBits -{ - VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM = 0x00000004, - VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM = 0x00000008, - VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT = 0x00000010, - VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT = 0x00000020, - VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT = 0x00000040, - VK_SUBPASS_DESCRIPTION_ENABLE_LEGACY_DITHERING_BIT_EXT = 0x00000080, - VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_ARM = VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT, - VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM = VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT, - VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM = VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT, - VK_SUBPASS_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkSubpassDescriptionFlagBits; - -typedef enum VkSubpassMergeStatusEXT -{ - VK_SUBPASS_MERGE_STATUS_MERGED_EXT = 0, - VK_SUBPASS_MERGE_STATUS_DISALLOWED_EXT = 1, - VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SIDE_EFFECTS_EXT = 2, - VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SAMPLES_MISMATCH_EXT = 3, - VK_SUBPASS_MERGE_STATUS_NOT_MERGED_VIEWS_MISMATCH_EXT = 4, - VK_SUBPASS_MERGE_STATUS_NOT_MERGED_ALIASING_EXT = 5, - VK_SUBPASS_MERGE_STATUS_NOT_MERGED_DEPENDENCIES_EXT = 6, - VK_SUBPASS_MERGE_STATUS_NOT_MERGED_INCOMPATIBLE_INPUT_ATTACHMENT_EXT = 7, - VK_SUBPASS_MERGE_STATUS_NOT_MERGED_TOO_MANY_ATTACHMENTS_EXT = 8, - VK_SUBPASS_MERGE_STATUS_NOT_MERGED_INSUFFICIENT_STORAGE_EXT = 9, - VK_SUBPASS_MERGE_STATUS_NOT_MERGED_DEPTH_STENCIL_COUNT_EXT = 10, - VK_SUBPASS_MERGE_STATUS_NOT_MERGED_RESOLVE_ATTACHMENT_REUSE_EXT = 11, - VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SINGLE_SUBPASS_EXT = 12, - VK_SUBPASS_MERGE_STATUS_NOT_MERGED_UNSPECIFIED_EXT = 13, - VK_SUBPASS_MERGE_STATUS_EXT_MAX_ENUM = 0x7fffffff, -} VkSubpassMergeStatusEXT; - -typedef enum VkSurfaceTransformFlagBitsKHR -{ - VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001, - VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002, - VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 0x00000004, - VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 0x00000008, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 0x00000010, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 0x00000020, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040, - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080, - VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100, - VK_SURFACE_TRANSFORM_FLAG_BITS_KHR_MAX_ENUM = 0x7fffffff, -} VkSurfaceTransformFlagBitsKHR; - -typedef enum VkSwapchainCreateFlagBitsKHR -{ - VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = 0x00000001, - VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 0x00000002, - VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR = 0x00000004, - VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_EXT = 0x00000008, - VK_SWAPCHAIN_CREATE_FLAG_BITS_KHR_MAX_ENUM = 0x7fffffff, -} VkSwapchainCreateFlagBitsKHR; - -typedef enum VkSystemAllocationScope -{ - VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0, - VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 1, - VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 2, - VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 3, - VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 4, - VK_SYSTEM_ALLOCATION_SCOPE_MAX_ENUM = 0x7fffffff, -} VkSystemAllocationScope; - -typedef enum VkTessellationDomainOrigin -{ - VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT = 0, - VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1, - VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, - VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR = VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT, - VK_TESSELLATION_DOMAIN_ORIGIN_MAX_ENUM = 0x7fffffff, -} VkTessellationDomainOrigin; -typedef VkTessellationDomainOrigin VkTessellationDomainOriginKHR; - -typedef enum VkTimeDomainEXT -{ - VK_TIME_DOMAIN_DEVICE_EXT = 0, - VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = 1, - VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = 2, - VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = 3, - VK_TIME_DOMAIN_EXT_MAX_ENUM = 0x7fffffff, -} VkTimeDomainEXT; - -typedef enum VkToolPurposeFlagBits -{ - VK_TOOL_PURPOSE_VALIDATION_BIT = 0x00000001, - VK_TOOL_PURPOSE_PROFILING_BIT = 0x00000002, - VK_TOOL_PURPOSE_TRACING_BIT = 0x00000004, - VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT = 0x00000008, - VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT = 0x00000010, - VK_TOOL_PURPOSE_DEBUG_REPORTING_BIT_EXT = 0x00000020, - VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT = 0x00000040, - VK_TOOL_PURPOSE_VALIDATION_BIT_EXT = VK_TOOL_PURPOSE_VALIDATION_BIT, - VK_TOOL_PURPOSE_PROFILING_BIT_EXT = VK_TOOL_PURPOSE_PROFILING_BIT, - VK_TOOL_PURPOSE_TRACING_BIT_EXT = VK_TOOL_PURPOSE_TRACING_BIT, - VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT_EXT = VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT, - VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT_EXT = VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT, - VK_TOOL_PURPOSE_FLAG_BITS_MAX_ENUM = 0x7fffffff, -} VkToolPurposeFlagBits; -typedef VkToolPurposeFlagBits VkToolPurposeFlagBitsEXT; - -typedef enum VkValidationCacheHeaderVersionEXT -{ - VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT = 1, - VK_VALIDATION_CACHE_HEADER_VERSION_EXT_MAX_ENUM = 0x7fffffff, -} VkValidationCacheHeaderVersionEXT; - -typedef enum VkValidationCheckEXT -{ - VK_VALIDATION_CHECK_ALL_EXT = 0, - VK_VALIDATION_CHECK_SHADERS_EXT = 1, - VK_VALIDATION_CHECK_EXT_MAX_ENUM = 0x7fffffff, -} VkValidationCheckEXT; - -typedef enum VkValidationFeatureDisableEXT -{ - VK_VALIDATION_FEATURE_DISABLE_ALL_EXT = 0, - VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT = 1, - VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT = 2, - VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT = 3, - VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT = 4, - VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT = 5, - VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT = 6, - VK_VALIDATION_FEATURE_DISABLE_SHADER_VALIDATION_CACHE_EXT = 7, - VK_VALIDATION_FEATURE_DISABLE_EXT_MAX_ENUM = 0x7fffffff, -} VkValidationFeatureDisableEXT; - -typedef enum VkValidationFeatureEnableEXT -{ - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT = 0, - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT = 1, - VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT = 2, - VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT = 3, - VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT = 4, - VK_VALIDATION_FEATURE_ENABLE_EXT_MAX_ENUM = 0x7fffffff, -} VkValidationFeatureEnableEXT; - -typedef enum VkVendorId -{ - VK_VENDOR_ID_VIV = 0x00010001, - VK_VENDOR_ID_VSI = 0x00010002, - VK_VENDOR_ID_KAZAN = 0x00010003, - VK_VENDOR_ID_CODEPLAY = 0x00010004, - VK_VENDOR_ID_MESA = 0x00010005, - VK_VENDOR_ID_POCL = 0x00010006, - VK_VENDOR_ID_MAX_ENUM = 0x7fffffff, -} VkVendorId; - -typedef enum VkVertexInputRate -{ - VK_VERTEX_INPUT_RATE_VERTEX = 0, - VK_VERTEX_INPUT_RATE_INSTANCE = 1, - VK_VERTEX_INPUT_RATE_MAX_ENUM = 0x7fffffff, -} VkVertexInputRate; - -typedef enum VkViewportCoordinateSwizzleNV -{ - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV = 0, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV = 1, - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV = 2, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV = 3, - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV = 4, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5, - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6, - VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7, - VK_VIEWPORT_COORDINATE_SWIZZLE_NV_MAX_ENUM = 0x7fffffff, -} VkViewportCoordinateSwizzleNV; - -typedef void* (VKAPI_PTR * PFN_vkAllocationFunction)( - void *pUserData, - size_t size, - size_t alignment, - VkSystemAllocationScope allocationScope); -typedef VkBool32 (VKAPI_PTR * PFN_vkDebugReportCallbackEXT)( - VkDebugReportFlagsEXT flags, - VkDebugReportObjectTypeEXT objectType, - uint64_t object, - size_t location, - int32_t messageCode, - const char *pLayerPrefix, - const char *pMessage, - void *pUserData); -typedef struct VkDebugUtilsMessengerCallbackDataEXT VkDebugUtilsMessengerCallbackDataEXT; -typedef VkBool32 (VKAPI_PTR * PFN_vkDebugUtilsMessengerCallbackEXT)( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageTypes, - const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, - void *pUserData); -typedef void (VKAPI_PTR * PFN_vkFreeFunction)( - void *pUserData, - void *pMemory); -typedef void (VKAPI_PTR * PFN_vkInternalAllocationNotification)( - void *pUserData, - size_t size, - VkInternalAllocationType allocationType, - VkSystemAllocationScope allocationScope); -typedef void (VKAPI_PTR * PFN_vkInternalFreeNotification)( - void *pUserData, - size_t size, - VkInternalAllocationType allocationType, - VkSystemAllocationScope allocationScope); -typedef void* (VKAPI_PTR * PFN_vkReallocationFunction)( - void *pUserData, - void *pOriginal, - size_t size, - size_t alignment, - VkSystemAllocationScope allocationScope); -typedef void (VKAPI_PTR * PFN_vkVoidFunction)( -void); - -typedef struct VkAabbPositionsKHR -{ - float minX; - float minY; - float minZ; - float maxX; - float maxY; - float maxZ; -} VkAabbPositionsKHR; -typedef VkAabbPositionsKHR VkAabbPositionsNV; - -typedef struct VkAccelerationStructureBuildRangeInfoKHR -{ - uint32_t primitiveCount; - uint32_t primitiveOffset; - uint32_t firstVertex; - uint32_t transformOffset; -} VkAccelerationStructureBuildRangeInfoKHR; - -typedef struct VkAccelerationStructureBuildSizesInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkDeviceSize WINE_VK_ALIGN(8) accelerationStructureSize; - VkDeviceSize WINE_VK_ALIGN(8) updateScratchSize; - VkDeviceSize WINE_VK_ALIGN(8) buildScratchSize; -} VkAccelerationStructureBuildSizesInfoKHR; - -typedef struct VkAccelerationStructureCaptureDescriptorDataInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkAccelerationStructureKHR WINE_VK_ALIGN(8) accelerationStructure; - VkAccelerationStructureNV WINE_VK_ALIGN(8) accelerationStructureNV; -} VkAccelerationStructureCaptureDescriptorDataInfoEXT; - -typedef struct VkAccelerationStructureCreateInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkAccelerationStructureCreateFlagsKHR createFlags; - VkBuffer WINE_VK_ALIGN(8) buffer; - VkDeviceSize WINE_VK_ALIGN(8) offset; - VkDeviceSize WINE_VK_ALIGN(8) size; - VkAccelerationStructureTypeKHR type; - VkDeviceAddress WINE_VK_ALIGN(8) deviceAddress; -} VkAccelerationStructureCreateInfoKHR; - -typedef struct VkAccelerationStructureDeviceAddressInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkAccelerationStructureKHR WINE_VK_ALIGN(8) accelerationStructure; -} VkAccelerationStructureDeviceAddressInfoKHR; - -typedef struct VkAccelerationStructureMemoryRequirementsInfoNV -{ - VkStructureType sType; - const void *pNext; - VkAccelerationStructureMemoryRequirementsTypeNV type; - VkAccelerationStructureNV WINE_VK_ALIGN(8) accelerationStructure; -} VkAccelerationStructureMemoryRequirementsInfoNV; - -typedef struct VkAccelerationStructureMotionInfoNV -{ - VkStructureType sType; - const void *pNext; - uint32_t maxInstances; - VkAccelerationStructureMotionInfoFlagsNV flags; -} VkAccelerationStructureMotionInfoNV; - -typedef struct VkAccelerationStructureVersionInfoKHR -{ - VkStructureType sType; - const void *pNext; - const uint8_t *pVersionData; -} VkAccelerationStructureVersionInfoKHR; - -typedef struct VkAcquireNextImageInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkSwapchainKHR WINE_VK_ALIGN(8) swapchain; - uint64_t WINE_VK_ALIGN(8) timeout; - VkSemaphore WINE_VK_ALIGN(8) semaphore; - VkFence WINE_VK_ALIGN(8) fence; - uint32_t deviceMask; -} VkAcquireNextImageInfoKHR; - -typedef struct VkAcquireProfilingLockInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkAcquireProfilingLockFlagsKHR flags; - uint64_t WINE_VK_ALIGN(8) timeout; -} VkAcquireProfilingLockInfoKHR; - -typedef struct VkAllocationCallbacks -{ - void *pUserData; - PFN_vkAllocationFunction pfnAllocation; - PFN_vkReallocationFunction pfnReallocation; - PFN_vkFreeFunction pfnFree; - PFN_vkInternalAllocationNotification pfnInternalAllocation; - PFN_vkInternalFreeNotification pfnInternalFree; -} VkAllocationCallbacks; - -typedef struct VkApplicationInfo -{ - VkStructureType sType; - const void *pNext; - const char *pApplicationName; - uint32_t applicationVersion; - const char *pEngineName; - uint32_t engineVersion; - uint32_t apiVersion; -} VkApplicationInfo; - -typedef struct VkAttachmentDescription -{ - VkAttachmentDescriptionFlags flags; - VkFormat format; - VkSampleCountFlagBits samples; - VkAttachmentLoadOp loadOp; - VkAttachmentStoreOp storeOp; - VkAttachmentLoadOp stencilLoadOp; - VkAttachmentStoreOp stencilStoreOp; - VkImageLayout initialLayout; - VkImageLayout finalLayout; -} VkAttachmentDescription; - -typedef struct VkAttachmentDescription2 -{ - VkStructureType sType; - const void *pNext; - VkAttachmentDescriptionFlags flags; - VkFormat format; - VkSampleCountFlagBits samples; - VkAttachmentLoadOp loadOp; - VkAttachmentStoreOp storeOp; - VkAttachmentLoadOp stencilLoadOp; - VkAttachmentStoreOp stencilStoreOp; - VkImageLayout initialLayout; - VkImageLayout finalLayout; -} VkAttachmentDescription2; -typedef VkAttachmentDescription2 VkAttachmentDescription2KHR; - -typedef struct VkAttachmentDescriptionStencilLayout -{ - VkStructureType sType; - void *pNext; - VkImageLayout stencilInitialLayout; - VkImageLayout stencilFinalLayout; -} VkAttachmentDescriptionStencilLayout; -typedef VkAttachmentDescriptionStencilLayout VkAttachmentDescriptionStencilLayoutKHR; - -typedef struct VkAttachmentReference -{ - uint32_t attachment; - VkImageLayout layout; -} VkAttachmentReference; - -typedef struct VkAttachmentReference2 -{ - VkStructureType sType; - const void *pNext; - uint32_t attachment; - VkImageLayout layout; - VkImageAspectFlags aspectMask; -} VkAttachmentReference2; -typedef VkAttachmentReference2 VkAttachmentReference2KHR; - -typedef struct VkAttachmentReferenceStencilLayout -{ - VkStructureType sType; - void *pNext; - VkImageLayout stencilLayout; -} VkAttachmentReferenceStencilLayout; -typedef VkAttachmentReferenceStencilLayout VkAttachmentReferenceStencilLayoutKHR; - -typedef struct VkAttachmentSampleCountInfoAMD -{ - VkStructureType sType; - const void *pNext; - uint32_t colorAttachmentCount; - const VkSampleCountFlagBits *pColorAttachmentSamples; - VkSampleCountFlagBits depthStencilAttachmentSamples; -} VkAttachmentSampleCountInfoAMD; -typedef VkAttachmentSampleCountInfoAMD VkAttachmentSampleCountInfoNV; - -typedef struct VkBaseInStructure -{ - VkStructureType sType; - const struct VkBaseInStructure *pNext; -} VkBaseInStructure; - -typedef struct VkBaseOutStructure -{ - VkStructureType sType; - struct VkBaseOutStructure *pNext; -} VkBaseOutStructure; - -typedef struct VkBindAccelerationStructureMemoryInfoNV -{ - VkStructureType sType; - const void *pNext; - VkAccelerationStructureNV WINE_VK_ALIGN(8) accelerationStructure; - VkDeviceMemory WINE_VK_ALIGN(8) memory; - VkDeviceSize WINE_VK_ALIGN(8) memoryOffset; - uint32_t deviceIndexCount; - const uint32_t *pDeviceIndices; -} VkBindAccelerationStructureMemoryInfoNV; - -typedef struct VkBindBufferMemoryDeviceGroupInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t deviceIndexCount; - const uint32_t *pDeviceIndices; -} VkBindBufferMemoryDeviceGroupInfo; -typedef VkBindBufferMemoryDeviceGroupInfo VkBindBufferMemoryDeviceGroupInfoKHR; - -typedef struct VkBindBufferMemoryInfo -{ - VkStructureType sType; - const void *pNext; - VkBuffer WINE_VK_ALIGN(8) buffer; - VkDeviceMemory WINE_VK_ALIGN(8) memory; - VkDeviceSize WINE_VK_ALIGN(8) memoryOffset; -} VkBindBufferMemoryInfo; -typedef VkBindBufferMemoryInfo VkBindBufferMemoryInfoKHR; - -typedef struct VkBindImageMemoryInfo -{ - VkStructureType sType; - const void *pNext; - VkImage WINE_VK_ALIGN(8) image; - VkDeviceMemory WINE_VK_ALIGN(8) memory; - VkDeviceSize WINE_VK_ALIGN(8) memoryOffset; -} VkBindImageMemoryInfo; -typedef VkBindImageMemoryInfo VkBindImageMemoryInfoKHR; - -typedef struct VkBindImageMemorySwapchainInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkSwapchainKHR WINE_VK_ALIGN(8) swapchain; - uint32_t imageIndex; -} VkBindImageMemorySwapchainInfoKHR; - -typedef struct VkBindImagePlaneMemoryInfo -{ - VkStructureType sType; - const void *pNext; - VkImageAspectFlagBits planeAspect; -} VkBindImagePlaneMemoryInfo; -typedef VkBindImagePlaneMemoryInfo VkBindImagePlaneMemoryInfoKHR; - -typedef struct VkBindIndexBufferIndirectCommandNV -{ - VkDeviceAddress WINE_VK_ALIGN(8) bufferAddress; - uint32_t size; - VkIndexType indexType; -} VkBindIndexBufferIndirectCommandNV; - -typedef struct VkBindShaderGroupIndirectCommandNV -{ - uint32_t groupIndex; -} VkBindShaderGroupIndirectCommandNV; - -typedef struct VkBindVertexBufferIndirectCommandNV -{ - VkDeviceAddress WINE_VK_ALIGN(8) bufferAddress; - uint32_t size; - uint32_t stride; -} VkBindVertexBufferIndirectCommandNV; - -typedef struct VkBufferCaptureDescriptorDataInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkBuffer WINE_VK_ALIGN(8) buffer; -} VkBufferCaptureDescriptorDataInfoEXT; - -typedef struct VkBufferCopy -{ - VkDeviceSize WINE_VK_ALIGN(8) srcOffset; - VkDeviceSize WINE_VK_ALIGN(8) dstOffset; - VkDeviceSize WINE_VK_ALIGN(8) size; -} VkBufferCopy; - -typedef struct VkBufferCopy2 -{ - VkStructureType sType; - const void *pNext; - VkDeviceSize WINE_VK_ALIGN(8) srcOffset; - VkDeviceSize WINE_VK_ALIGN(8) dstOffset; - VkDeviceSize WINE_VK_ALIGN(8) size; -} VkBufferCopy2; -typedef VkBufferCopy2 VkBufferCopy2KHR; - -typedef struct VkBufferCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkBufferCreateFlags flags; - VkDeviceSize WINE_VK_ALIGN(8) size; - VkBufferUsageFlags usage; - VkSharingMode sharingMode; - uint32_t queueFamilyIndexCount; - const uint32_t *pQueueFamilyIndices; -} VkBufferCreateInfo; - -typedef struct VkBufferDeviceAddressCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkDeviceAddress WINE_VK_ALIGN(8) deviceAddress; -} VkBufferDeviceAddressCreateInfoEXT; - -typedef struct VkBufferDeviceAddressInfo -{ - VkStructureType sType; - const void *pNext; - VkBuffer WINE_VK_ALIGN(8) buffer; -} VkBufferDeviceAddressInfo; -typedef VkBufferDeviceAddressInfo VkBufferDeviceAddressInfoKHR; -typedef VkBufferDeviceAddressInfo VkBufferDeviceAddressInfoEXT; - -typedef struct VkBufferMemoryBarrier -{ - VkStructureType sType; - const void *pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkBuffer WINE_VK_ALIGN(8) buffer; - VkDeviceSize WINE_VK_ALIGN(8) offset; - VkDeviceSize WINE_VK_ALIGN(8) size; -} VkBufferMemoryBarrier; - -typedef struct VkBufferMemoryBarrier2 -{ - VkStructureType sType; - const void *pNext; - VkPipelineStageFlags2 WINE_VK_ALIGN(8) srcStageMask; - VkAccessFlags2 WINE_VK_ALIGN(8) srcAccessMask; - VkPipelineStageFlags2 WINE_VK_ALIGN(8) dstStageMask; - VkAccessFlags2 WINE_VK_ALIGN(8) dstAccessMask; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkBuffer WINE_VK_ALIGN(8) buffer; - VkDeviceSize WINE_VK_ALIGN(8) offset; - VkDeviceSize WINE_VK_ALIGN(8) size; -} VkBufferMemoryBarrier2; -typedef VkBufferMemoryBarrier2 VkBufferMemoryBarrier2KHR; - -typedef struct VkBufferMemoryRequirementsInfo2 -{ - VkStructureType sType; - const void *pNext; - VkBuffer WINE_VK_ALIGN(8) buffer; -} VkBufferMemoryRequirementsInfo2; -typedef VkBufferMemoryRequirementsInfo2 VkBufferMemoryRequirementsInfo2KHR; - -typedef struct VkBufferOpaqueCaptureAddressCreateInfo -{ - VkStructureType sType; - const void *pNext; - uint64_t WINE_VK_ALIGN(8) opaqueCaptureAddress; -} VkBufferOpaqueCaptureAddressCreateInfo; -typedef VkBufferOpaqueCaptureAddressCreateInfo VkBufferOpaqueCaptureAddressCreateInfoKHR; - -typedef struct VkBufferViewCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkBufferViewCreateFlags flags; - VkBuffer WINE_VK_ALIGN(8) buffer; - VkFormat format; - VkDeviceSize WINE_VK_ALIGN(8) offset; - VkDeviceSize WINE_VK_ALIGN(8) range; -} VkBufferViewCreateInfo; - -typedef struct VkCalibratedTimestampInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkTimeDomainEXT timeDomain; -} VkCalibratedTimestampInfoEXT; - -typedef struct VkCheckpointData2NV -{ - VkStructureType sType; - void *pNext; - VkPipelineStageFlags2 WINE_VK_ALIGN(8) stage; - void *pCheckpointMarker; -} VkCheckpointData2NV; - -typedef struct VkCheckpointDataNV -{ - VkStructureType sType; - void *pNext; - VkPipelineStageFlagBits stage; - void *pCheckpointMarker; -} VkCheckpointDataNV; - -typedef union VkClearColorValue -{ - float float32[4]; - int32_t int32[4]; - uint32_t uint32[4]; -} VkClearColorValue; - -typedef struct VkClearDepthStencilValue -{ - float depth; - uint32_t stencil; -} VkClearDepthStencilValue; - -typedef union VkClearValue -{ - VkClearColorValue color; - VkClearDepthStencilValue depthStencil; -} VkClearValue; - -typedef struct VkCoarseSampleLocationNV -{ - uint32_t pixelX; - uint32_t pixelY; - uint32_t sample; -} VkCoarseSampleLocationNV; - -typedef struct VkCoarseSampleOrderCustomNV -{ - VkShadingRatePaletteEntryNV shadingRate; - uint32_t sampleCount; - uint32_t sampleLocationCount; - const VkCoarseSampleLocationNV *pSampleLocations; -} VkCoarseSampleOrderCustomNV; - -typedef struct VkColorBlendAdvancedEXT -{ - VkBlendOp advancedBlendOp; - VkBool32 srcPremultiplied; - VkBool32 dstPremultiplied; - VkBlendOverlapEXT blendOverlap; - VkBool32 clampResults; -} VkColorBlendAdvancedEXT; - -typedef struct VkColorBlendEquationEXT -{ - VkBlendFactor srcColorBlendFactor; - VkBlendFactor dstColorBlendFactor; - VkBlendOp colorBlendOp; - VkBlendFactor srcAlphaBlendFactor; - VkBlendFactor dstAlphaBlendFactor; - VkBlendOp alphaBlendOp; -} VkColorBlendEquationEXT; - -typedef struct VkCommandBufferAllocateInfo -{ - VkStructureType sType; - const void *pNext; - VkCommandPool WINE_VK_ALIGN(8) commandPool; - VkCommandBufferLevel level; - uint32_t commandBufferCount; -} VkCommandBufferAllocateInfo; - -typedef struct VkCommandBufferInheritanceConditionalRenderingInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkBool32 conditionalRenderingEnable; -} VkCommandBufferInheritanceConditionalRenderingInfoEXT; - -typedef struct VkCommandBufferInheritanceInfo -{ - VkStructureType sType; - const void *pNext; - VkRenderPass WINE_VK_ALIGN(8) renderPass; - uint32_t subpass; - VkFramebuffer WINE_VK_ALIGN(8) framebuffer; - VkBool32 occlusionQueryEnable; - VkQueryControlFlags queryFlags; - VkQueryPipelineStatisticFlags pipelineStatistics; -} VkCommandBufferInheritanceInfo; - -typedef struct VkCommandBufferInheritanceRenderingInfo -{ - VkStructureType sType; - const void *pNext; - VkRenderingFlags flags; - uint32_t viewMask; - uint32_t colorAttachmentCount; - const VkFormat *pColorAttachmentFormats; - VkFormat depthAttachmentFormat; - VkFormat stencilAttachmentFormat; - VkSampleCountFlagBits rasterizationSamples; -} VkCommandBufferInheritanceRenderingInfo; -typedef VkCommandBufferInheritanceRenderingInfo VkCommandBufferInheritanceRenderingInfoKHR; - -typedef struct VkCommandBufferSubmitInfo -{ - VkStructureType sType; - const void *pNext; - VkCommandBuffer commandBuffer; - uint32_t deviceMask; -} VkCommandBufferSubmitInfo; -typedef VkCommandBufferSubmitInfo VkCommandBufferSubmitInfoKHR; - -typedef struct VkCommandPoolCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkCommandPoolCreateFlags flags; - uint32_t queueFamilyIndex; -} VkCommandPoolCreateInfo; - -typedef struct VkComponentMapping -{ - VkComponentSwizzle r; - VkComponentSwizzle g; - VkComponentSwizzle b; - VkComponentSwizzle a; -} VkComponentMapping; - -typedef struct VkConditionalRenderingBeginInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkBuffer WINE_VK_ALIGN(8) buffer; - VkDeviceSize WINE_VK_ALIGN(8) offset; - VkConditionalRenderingFlagsEXT flags; -} VkConditionalRenderingBeginInfoEXT; - -typedef struct VkConformanceVersion -{ - uint8_t major; - uint8_t minor; - uint8_t subminor; - uint8_t patch; -} VkConformanceVersion; -typedef VkConformanceVersion VkConformanceVersionKHR; - -typedef struct VkCooperativeMatrixPropertiesNV -{ - VkStructureType sType; - void *pNext; - uint32_t MSize; - uint32_t NSize; - uint32_t KSize; - VkComponentTypeNV AType; - VkComponentTypeNV BType; - VkComponentTypeNV CType; - VkComponentTypeNV DType; - VkScopeNV scope; -} VkCooperativeMatrixPropertiesNV; - -typedef struct VkCopyAccelerationStructureInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkAccelerationStructureKHR WINE_VK_ALIGN(8) src; - VkAccelerationStructureKHR WINE_VK_ALIGN(8) dst; - VkCopyAccelerationStructureModeKHR mode; -} VkCopyAccelerationStructureInfoKHR; - -typedef struct VkCopyBufferInfo2 -{ - VkStructureType sType; - const void *pNext; - VkBuffer WINE_VK_ALIGN(8) srcBuffer; - VkBuffer WINE_VK_ALIGN(8) dstBuffer; - uint32_t regionCount; - const VkBufferCopy2 *pRegions; -} VkCopyBufferInfo2; -typedef VkCopyBufferInfo2 VkCopyBufferInfo2KHR; - -typedef struct VkCopyCommandTransformInfoQCOM -{ - VkStructureType sType; - const void *pNext; - VkSurfaceTransformFlagBitsKHR transform; -} VkCopyCommandTransformInfoQCOM; - -typedef struct VkCopyDescriptorSet -{ - VkStructureType sType; - const void *pNext; - VkDescriptorSet WINE_VK_ALIGN(8) srcSet; - uint32_t srcBinding; - uint32_t srcArrayElement; - VkDescriptorSet WINE_VK_ALIGN(8) dstSet; - uint32_t dstBinding; - uint32_t dstArrayElement; - uint32_t descriptorCount; -} VkCopyDescriptorSet; - -typedef struct VkCopyMemoryIndirectCommandNV -{ - VkDeviceAddress WINE_VK_ALIGN(8) srcAddress; - VkDeviceAddress WINE_VK_ALIGN(8) dstAddress; - VkDeviceSize WINE_VK_ALIGN(8) size; -} VkCopyMemoryIndirectCommandNV; - -typedef struct VkCopyMicromapInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkMicromapEXT WINE_VK_ALIGN(8) src; - VkMicromapEXT WINE_VK_ALIGN(8) dst; - VkCopyMicromapModeEXT mode; -} VkCopyMicromapInfoEXT; - -typedef struct VkCuFunctionCreateInfoNVX -{ - VkStructureType sType; - const void *pNext; - VkCuModuleNVX WINE_VK_ALIGN(8) module; - const char *pName; -} VkCuFunctionCreateInfoNVX; - -typedef struct VkCuLaunchInfoNVX -{ - VkStructureType sType; - const void *pNext; - VkCuFunctionNVX WINE_VK_ALIGN(8) function; - uint32_t gridDimX; - uint32_t gridDimY; - uint32_t gridDimZ; - uint32_t blockDimX; - uint32_t blockDimY; - uint32_t blockDimZ; - uint32_t sharedMemBytes; - size_t paramCount; - const void * const *pParams; - size_t extraCount; - const void * const *pExtras; -} VkCuLaunchInfoNVX; - -typedef struct VkCuModuleCreateInfoNVX -{ - VkStructureType sType; - const void *pNext; - size_t dataSize; - const void *pData; -} VkCuModuleCreateInfoNVX; - -typedef struct VkDebugMarkerMarkerInfoEXT -{ - VkStructureType sType; - const void *pNext; - const char *pMarkerName; - float color[4]; -} VkDebugMarkerMarkerInfoEXT; - -typedef struct VkDebugMarkerObjectNameInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkDebugReportObjectTypeEXT objectType; - uint64_t WINE_VK_ALIGN(8) object; - const char *pObjectName; -} VkDebugMarkerObjectNameInfoEXT; - -typedef struct VkDebugMarkerObjectTagInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkDebugReportObjectTypeEXT objectType; - uint64_t WINE_VK_ALIGN(8) object; - uint64_t WINE_VK_ALIGN(8) tagName; - size_t tagSize; - const void *pTag; -} VkDebugMarkerObjectTagInfoEXT; - -typedef struct VkDebugReportCallbackCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkDebugReportFlagsEXT flags; - PFN_vkDebugReportCallbackEXT pfnCallback; - void *pUserData; -} VkDebugReportCallbackCreateInfoEXT; - -typedef struct VkDebugUtilsLabelEXT -{ - VkStructureType sType; - const void *pNext; - const char *pLabelName; - float color[4]; -} VkDebugUtilsLabelEXT; - -typedef struct VkDebugUtilsMessengerCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkDebugUtilsMessengerCreateFlagsEXT flags; - VkDebugUtilsMessageSeverityFlagsEXT messageSeverity; - VkDebugUtilsMessageTypeFlagsEXT messageType; - PFN_vkDebugUtilsMessengerCallbackEXT pfnUserCallback; - void *pUserData; -} VkDebugUtilsMessengerCreateInfoEXT; - -typedef struct VkDebugUtilsObjectNameInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkObjectType objectType; - uint64_t WINE_VK_ALIGN(8) objectHandle; - const char *pObjectName; -} VkDebugUtilsObjectNameInfoEXT; - -typedef struct VkDebugUtilsObjectTagInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkObjectType objectType; - uint64_t WINE_VK_ALIGN(8) objectHandle; - uint64_t WINE_VK_ALIGN(8) tagName; - size_t tagSize; - const void *pTag; -} VkDebugUtilsObjectTagInfoEXT; - -typedef struct VkDecompressMemoryRegionNV -{ - VkDeviceAddress WINE_VK_ALIGN(8) srcAddress; - VkDeviceAddress WINE_VK_ALIGN(8) dstAddress; - VkDeviceSize WINE_VK_ALIGN(8) compressedSize; - VkDeviceSize WINE_VK_ALIGN(8) decompressedSize; - VkMemoryDecompressionMethodFlagsNV WINE_VK_ALIGN(8) decompressionMethod; -} VkDecompressMemoryRegionNV; - -typedef struct VkDedicatedAllocationBufferCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - VkBool32 dedicatedAllocation; -} VkDedicatedAllocationBufferCreateInfoNV; - -typedef struct VkDedicatedAllocationImageCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - VkBool32 dedicatedAllocation; -} VkDedicatedAllocationImageCreateInfoNV; - -typedef struct VkDedicatedAllocationMemoryAllocateInfoNV -{ - VkStructureType sType; - const void *pNext; - VkImage WINE_VK_ALIGN(8) image; - VkBuffer WINE_VK_ALIGN(8) buffer; -} VkDedicatedAllocationMemoryAllocateInfoNV; - -typedef struct VkDescriptorAddressInfoEXT -{ - VkStructureType sType; - void *pNext; - VkDeviceAddress WINE_VK_ALIGN(8) address; - VkDeviceSize WINE_VK_ALIGN(8) range; - VkFormat format; -} VkDescriptorAddressInfoEXT; - -typedef struct VkDescriptorBufferBindingInfoEXT -{ - VkStructureType sType; - void *pNext; - VkDeviceAddress WINE_VK_ALIGN(8) address; - VkBufferUsageFlags usage; -} VkDescriptorBufferBindingInfoEXT; - -typedef struct VkDescriptorBufferBindingPushDescriptorBufferHandleEXT -{ - VkStructureType sType; - void *pNext; - VkBuffer WINE_VK_ALIGN(8) buffer; -} VkDescriptorBufferBindingPushDescriptorBufferHandleEXT; - -typedef struct VkDescriptorBufferInfo -{ - VkBuffer WINE_VK_ALIGN(8) buffer; - VkDeviceSize WINE_VK_ALIGN(8) offset; - VkDeviceSize WINE_VK_ALIGN(8) range; -} VkDescriptorBufferInfo; - -typedef struct VkDescriptorImageInfo -{ - VkSampler WINE_VK_ALIGN(8) sampler; - VkImageView WINE_VK_ALIGN(8) imageView; - VkImageLayout imageLayout; -} VkDescriptorImageInfo; - -typedef struct VkDescriptorPoolInlineUniformBlockCreateInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t maxInlineUniformBlockBindings; -} VkDescriptorPoolInlineUniformBlockCreateInfo; -typedef VkDescriptorPoolInlineUniformBlockCreateInfo VkDescriptorPoolInlineUniformBlockCreateInfoEXT; - -typedef struct VkDescriptorPoolSize -{ - VkDescriptorType type; - uint32_t descriptorCount; -} VkDescriptorPoolSize; - -typedef struct VkDescriptorSetAllocateInfo -{ - VkStructureType sType; - const void *pNext; - VkDescriptorPool WINE_VK_ALIGN(8) descriptorPool; - uint32_t descriptorSetCount; - const VkDescriptorSetLayout *pSetLayouts; -} VkDescriptorSetAllocateInfo; - -typedef struct VkDescriptorSetBindingReferenceVALVE -{ - VkStructureType sType; - const void *pNext; - VkDescriptorSetLayout WINE_VK_ALIGN(8) descriptorSetLayout; - uint32_t binding; -} VkDescriptorSetBindingReferenceVALVE; - -typedef struct VkDescriptorSetLayoutBinding -{ - uint32_t binding; - VkDescriptorType descriptorType; - uint32_t descriptorCount; - VkShaderStageFlags stageFlags; - const VkSampler *pImmutableSamplers; -} VkDescriptorSetLayoutBinding; - -typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t bindingCount; - const VkDescriptorBindingFlags *pBindingFlags; -} VkDescriptorSetLayoutBindingFlagsCreateInfo; -typedef VkDescriptorSetLayoutBindingFlagsCreateInfo VkDescriptorSetLayoutBindingFlagsCreateInfoEXT; - -typedef struct VkDescriptorSetLayoutCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkDescriptorSetLayoutCreateFlags flags; - uint32_t bindingCount; - const VkDescriptorSetLayoutBinding *pBindings; -} VkDescriptorSetLayoutCreateInfo; - -typedef struct VkDescriptorSetLayoutHostMappingInfoVALVE -{ - VkStructureType sType; - void *pNext; - size_t descriptorOffset; - uint32_t descriptorSize; -} VkDescriptorSetLayoutHostMappingInfoVALVE; - -typedef struct VkDescriptorSetLayoutSupport -{ - VkStructureType sType; - void *pNext; - VkBool32 supported; -} VkDescriptorSetLayoutSupport; -typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR; - -typedef struct VkDescriptorSetVariableDescriptorCountAllocateInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t descriptorSetCount; - const uint32_t *pDescriptorCounts; -} VkDescriptorSetVariableDescriptorCountAllocateInfo; -typedef VkDescriptorSetVariableDescriptorCountAllocateInfo VkDescriptorSetVariableDescriptorCountAllocateInfoEXT; - -typedef struct VkDescriptorSetVariableDescriptorCountLayoutSupport -{ - VkStructureType sType; - void *pNext; - uint32_t maxVariableDescriptorCount; -} VkDescriptorSetVariableDescriptorCountLayoutSupport; -typedef VkDescriptorSetVariableDescriptorCountLayoutSupport VkDescriptorSetVariableDescriptorCountLayoutSupportEXT; - -typedef struct VkDescriptorUpdateTemplateEntry -{ - uint32_t dstBinding; - uint32_t dstArrayElement; - uint32_t descriptorCount; - VkDescriptorType descriptorType; - size_t offset; - size_t stride; -} VkDescriptorUpdateTemplateEntry; -typedef VkDescriptorUpdateTemplateEntry VkDescriptorUpdateTemplateEntryKHR; - -typedef struct VkDeviceAddressBindingCallbackDataEXT -{ - VkStructureType sType; - void *pNext; - VkDeviceAddressBindingFlagsEXT flags; - VkDeviceAddress WINE_VK_ALIGN(8) baseAddress; - VkDeviceSize WINE_VK_ALIGN(8) size; - VkDeviceAddressBindingTypeEXT bindingType; -} VkDeviceAddressBindingCallbackDataEXT; - -typedef struct VkDeviceBufferMemoryRequirements -{ - VkStructureType sType; - const void *pNext; - const VkBufferCreateInfo *pCreateInfo; -} VkDeviceBufferMemoryRequirements; -typedef VkDeviceBufferMemoryRequirements VkDeviceBufferMemoryRequirementsKHR; - -typedef struct VkDeviceDiagnosticsConfigCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - VkDeviceDiagnosticsConfigFlagsNV flags; -} VkDeviceDiagnosticsConfigCreateInfoNV; - -typedef struct VkDeviceFaultAddressInfoEXT -{ - VkDeviceFaultAddressTypeEXT addressType; - VkDeviceAddress WINE_VK_ALIGN(8) reportedAddress; - VkDeviceSize WINE_VK_ALIGN(8) addressPrecision; -} VkDeviceFaultAddressInfoEXT; - -typedef struct VkDeviceFaultCountsEXT -{ - VkStructureType sType; - void *pNext; - uint32_t addressInfoCount; - uint32_t vendorInfoCount; - VkDeviceSize WINE_VK_ALIGN(8) vendorBinarySize; -} VkDeviceFaultCountsEXT; - -typedef struct VkDeviceFaultVendorBinaryHeaderVersionOneEXT -{ - uint32_t headerSize; - VkDeviceFaultVendorBinaryHeaderVersionEXT headerVersion; - uint32_t vendorID; - uint32_t deviceID; - uint32_t driverVersion; - uint8_t pipelineCacheUUID[VK_UUID_SIZE]; - uint32_t applicationNameOffset; - uint32_t applicationVersion; - uint32_t engineNameOffset; -} VkDeviceFaultVendorBinaryHeaderVersionOneEXT; - -typedef struct VkDeviceFaultVendorInfoEXT -{ - char description[VK_MAX_DESCRIPTION_SIZE]; - uint64_t WINE_VK_ALIGN(8) vendorFaultCode; - uint64_t WINE_VK_ALIGN(8) vendorFaultData; -} VkDeviceFaultVendorInfoEXT; - -typedef struct VkDeviceGroupBindSparseInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t resourceDeviceIndex; - uint32_t memoryDeviceIndex; -} VkDeviceGroupBindSparseInfo; -typedef VkDeviceGroupBindSparseInfo VkDeviceGroupBindSparseInfoKHR; - -typedef struct VkDeviceGroupCommandBufferBeginInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t deviceMask; -} VkDeviceGroupCommandBufferBeginInfo; -typedef VkDeviceGroupCommandBufferBeginInfo VkDeviceGroupCommandBufferBeginInfoKHR; - -typedef struct VkDeviceGroupDeviceCreateInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t physicalDeviceCount; - const VkPhysicalDevice *pPhysicalDevices; -} VkDeviceGroupDeviceCreateInfo; -typedef VkDeviceGroupDeviceCreateInfo VkDeviceGroupDeviceCreateInfoKHR; - -typedef struct VkDeviceGroupPresentCapabilitiesKHR -{ - VkStructureType sType; - void *pNext; - uint32_t presentMask[VK_MAX_DEVICE_GROUP_SIZE]; - VkDeviceGroupPresentModeFlagsKHR modes; -} VkDeviceGroupPresentCapabilitiesKHR; - -typedef struct VkDeviceGroupPresentInfoKHR -{ - VkStructureType sType; - const void *pNext; - uint32_t swapchainCount; - const uint32_t *pDeviceMasks; - VkDeviceGroupPresentModeFlagBitsKHR mode; -} VkDeviceGroupPresentInfoKHR; - -typedef struct VkDeviceGroupSubmitInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t waitSemaphoreCount; - const uint32_t *pWaitSemaphoreDeviceIndices; - uint32_t commandBufferCount; - const uint32_t *pCommandBufferDeviceMasks; - uint32_t signalSemaphoreCount; - const uint32_t *pSignalSemaphoreDeviceIndices; -} VkDeviceGroupSubmitInfo; -typedef VkDeviceGroupSubmitInfo VkDeviceGroupSubmitInfoKHR; - -typedef struct VkDeviceGroupSwapchainCreateInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkDeviceGroupPresentModeFlagsKHR modes; -} VkDeviceGroupSwapchainCreateInfoKHR; - -typedef struct VkDeviceMemoryOpaqueCaptureAddressInfo -{ - VkStructureType sType; - const void *pNext; - VkDeviceMemory WINE_VK_ALIGN(8) memory; -} VkDeviceMemoryOpaqueCaptureAddressInfo; -typedef VkDeviceMemoryOpaqueCaptureAddressInfo VkDeviceMemoryOpaqueCaptureAddressInfoKHR; - -typedef struct VkDeviceMemoryOverallocationCreateInfoAMD -{ - VkStructureType sType; - const void *pNext; - VkMemoryOverallocationBehaviorAMD overallocationBehavior; -} VkDeviceMemoryOverallocationCreateInfoAMD; - -typedef union VkDeviceOrHostAddressConstKHR -{ - VkDeviceAddress WINE_VK_ALIGN(8) deviceAddress; - const void *hostAddress; -} VkDeviceOrHostAddressConstKHR; - -typedef union VkDeviceOrHostAddressKHR -{ - VkDeviceAddress WINE_VK_ALIGN(8) deviceAddress; - void *hostAddress; -} VkDeviceOrHostAddressKHR; - -typedef struct VkDevicePrivateDataCreateInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t privateDataSlotRequestCount; -} VkDevicePrivateDataCreateInfo; -typedef VkDevicePrivateDataCreateInfo VkDevicePrivateDataCreateInfoEXT; - -typedef struct VkDeviceQueueCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkDeviceQueueCreateFlags flags; - uint32_t queueFamilyIndex; - uint32_t queueCount; - const float *pQueuePriorities; -} VkDeviceQueueCreateInfo; - -typedef struct VkDeviceQueueGlobalPriorityCreateInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkQueueGlobalPriorityKHR globalPriority; -} VkDeviceQueueGlobalPriorityCreateInfoKHR; -typedef VkDeviceQueueGlobalPriorityCreateInfoKHR VkDeviceQueueGlobalPriorityCreateInfoEXT; - -typedef struct VkDeviceQueueInfo2 -{ - VkStructureType sType; - const void *pNext; - VkDeviceQueueCreateFlags flags; - uint32_t queueFamilyIndex; - uint32_t queueIndex; -} VkDeviceQueueInfo2; - -typedef struct VkDispatchIndirectCommand -{ - uint32_t x; - uint32_t y; - uint32_t z; -} VkDispatchIndirectCommand; - -typedef struct VkDrawIndexedIndirectCommand -{ - uint32_t indexCount; - uint32_t instanceCount; - uint32_t firstIndex; - int32_t vertexOffset; - uint32_t firstInstance; -} VkDrawIndexedIndirectCommand; - -typedef struct VkDrawIndirectCommand -{ - uint32_t vertexCount; - uint32_t instanceCount; - uint32_t firstVertex; - uint32_t firstInstance; -} VkDrawIndirectCommand; - -typedef struct VkDrawMeshTasksIndirectCommandEXT -{ - uint32_t groupCountX; - uint32_t groupCountY; - uint32_t groupCountZ; -} VkDrawMeshTasksIndirectCommandEXT; - -typedef struct VkDrawMeshTasksIndirectCommandNV -{ - uint32_t taskCount; - uint32_t firstTask; -} VkDrawMeshTasksIndirectCommandNV; - -typedef struct VkEventCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkEventCreateFlags flags; -} VkEventCreateInfo; - -typedef struct VkExportFenceCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkExternalFenceHandleTypeFlags handleTypes; -} VkExportFenceCreateInfo; -typedef VkExportFenceCreateInfo VkExportFenceCreateInfoKHR; - -typedef struct VkExportMemoryAllocateInfo -{ - VkStructureType sType; - const void *pNext; - VkExternalMemoryHandleTypeFlags handleTypes; -} VkExportMemoryAllocateInfo; -typedef VkExportMemoryAllocateInfo VkExportMemoryAllocateInfoKHR; - -typedef struct VkExportMemoryWin32HandleInfoKHR -{ - VkStructureType sType; - const void *pNext; - const SECURITY_ATTRIBUTES *pAttributes; - DWORD dwAccess; - LPCWSTR name; -} VkExportMemoryWin32HandleInfoKHR; - -typedef struct VkExportSemaphoreCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkExternalSemaphoreHandleTypeFlags handleTypes; -} VkExportSemaphoreCreateInfo; -typedef VkExportSemaphoreCreateInfo VkExportSemaphoreCreateInfoKHR; - -typedef struct VkExtensionProperties -{ - char extensionName[VK_MAX_EXTENSION_NAME_SIZE]; - uint32_t specVersion; -} VkExtensionProperties; - -typedef struct VkExtent2D -{ - uint32_t width; - uint32_t height; -} VkExtent2D; - -typedef struct VkExtent3D -{ - uint32_t width; - uint32_t height; - uint32_t depth; -} VkExtent3D; - -typedef struct VkExternalFenceProperties -{ - VkStructureType sType; - void *pNext; - VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes; - VkExternalFenceHandleTypeFlags compatibleHandleTypes; - VkExternalFenceFeatureFlags externalFenceFeatures; -} VkExternalFenceProperties; -typedef VkExternalFenceProperties VkExternalFencePropertiesKHR; - -typedef struct VkExternalMemoryBufferCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkExternalMemoryHandleTypeFlags handleTypes; -} VkExternalMemoryBufferCreateInfo; -typedef VkExternalMemoryBufferCreateInfo VkExternalMemoryBufferCreateInfoKHR; - -typedef struct VkExternalMemoryImageCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkExternalMemoryHandleTypeFlags handleTypes; -} VkExternalMemoryImageCreateInfo; -typedef VkExternalMemoryImageCreateInfo VkExternalMemoryImageCreateInfoKHR; - -typedef struct VkExternalMemoryProperties -{ - VkExternalMemoryFeatureFlags externalMemoryFeatures; - VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes; - VkExternalMemoryHandleTypeFlags compatibleHandleTypes; -} VkExternalMemoryProperties; -typedef VkExternalMemoryProperties VkExternalMemoryPropertiesKHR; - -typedef struct VkExternalSemaphoreProperties -{ - VkStructureType sType; - void *pNext; - VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes; - VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes; - VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures; -} VkExternalSemaphoreProperties; -typedef VkExternalSemaphoreProperties VkExternalSemaphorePropertiesKHR; - -typedef struct VkFenceCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkFenceCreateFlags flags; -} VkFenceCreateInfo; - -typedef struct VkFilterCubicImageViewImageFormatPropertiesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 filterCubic; - VkBool32 filterCubicMinmax; -} VkFilterCubicImageViewImageFormatPropertiesEXT; - -typedef struct VkFormatProperties -{ - VkFormatFeatureFlags linearTilingFeatures; - VkFormatFeatureFlags optimalTilingFeatures; - VkFormatFeatureFlags bufferFeatures; -} VkFormatProperties; - -typedef struct VkFormatProperties2 -{ - VkStructureType sType; - void *pNext; - VkFormatProperties formatProperties; -} VkFormatProperties2; -typedef VkFormatProperties2 VkFormatProperties2KHR; - -typedef struct VkFormatProperties3 -{ - VkStructureType sType; - void *pNext; - VkFormatFeatureFlags2 WINE_VK_ALIGN(8) linearTilingFeatures; - VkFormatFeatureFlags2 WINE_VK_ALIGN(8) optimalTilingFeatures; - VkFormatFeatureFlags2 WINE_VK_ALIGN(8) bufferFeatures; -} VkFormatProperties3; -typedef VkFormatProperties3 VkFormatProperties3KHR; - -typedef struct VkFragmentShadingRateAttachmentInfoKHR -{ - VkStructureType sType; - const void *pNext; - const VkAttachmentReference2 *pFragmentShadingRateAttachment; - VkExtent2D shadingRateAttachmentTexelSize; -} VkFragmentShadingRateAttachmentInfoKHR; - -typedef struct VkFramebufferAttachmentImageInfo -{ - VkStructureType sType; - const void *pNext; - VkImageCreateFlags flags; - VkImageUsageFlags usage; - uint32_t width; - uint32_t height; - uint32_t layerCount; - uint32_t viewFormatCount; - const VkFormat *pViewFormats; -} VkFramebufferAttachmentImageInfo; -typedef VkFramebufferAttachmentImageInfo VkFramebufferAttachmentImageInfoKHR; - -typedef struct VkFramebufferAttachmentsCreateInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t attachmentImageInfoCount; - const VkFramebufferAttachmentImageInfo *pAttachmentImageInfos; -} VkFramebufferAttachmentsCreateInfo; -typedef VkFramebufferAttachmentsCreateInfo VkFramebufferAttachmentsCreateInfoKHR; - -typedef struct VkFramebufferCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkFramebufferCreateFlags flags; - VkRenderPass WINE_VK_ALIGN(8) renderPass; - uint32_t attachmentCount; - const VkImageView *pAttachments; - uint32_t width; - uint32_t height; - uint32_t layers; -} VkFramebufferCreateInfo; - -typedef struct VkFramebufferMixedSamplesCombinationNV -{ - VkStructureType sType; - void *pNext; - VkCoverageReductionModeNV coverageReductionMode; - VkSampleCountFlagBits rasterizationSamples; - VkSampleCountFlags depthStencilSamples; - VkSampleCountFlags colorSamples; -} VkFramebufferMixedSamplesCombinationNV; - -typedef struct VkGeneratedCommandsMemoryRequirementsInfoNV -{ - VkStructureType sType; - const void *pNext; - VkPipelineBindPoint pipelineBindPoint; - VkPipeline WINE_VK_ALIGN(8) pipeline; - VkIndirectCommandsLayoutNV WINE_VK_ALIGN(8) indirectCommandsLayout; - uint32_t maxSequencesCount; -} VkGeneratedCommandsMemoryRequirementsInfoNV; - -typedef struct VkGeometryAABBNV -{ - VkStructureType sType; - const void *pNext; - VkBuffer WINE_VK_ALIGN(8) aabbData; - uint32_t numAABBs; - uint32_t stride; - VkDeviceSize WINE_VK_ALIGN(8) offset; -} VkGeometryAABBNV; - -typedef struct VkGeometryTrianglesNV -{ - VkStructureType sType; - const void *pNext; - VkBuffer WINE_VK_ALIGN(8) vertexData; - VkDeviceSize WINE_VK_ALIGN(8) vertexOffset; - uint32_t vertexCount; - VkDeviceSize WINE_VK_ALIGN(8) vertexStride; - VkFormat vertexFormat; - VkBuffer WINE_VK_ALIGN(8) indexData; - VkDeviceSize WINE_VK_ALIGN(8) indexOffset; - uint32_t indexCount; - VkIndexType indexType; - VkBuffer WINE_VK_ALIGN(8) transformData; - VkDeviceSize WINE_VK_ALIGN(8) transformOffset; -} VkGeometryTrianglesNV; - -typedef struct VkGraphicsPipelineLibraryCreateInfoEXT -{ - VkStructureType sType; - void *pNext; - VkGraphicsPipelineLibraryFlagsEXT flags; -} VkGraphicsPipelineLibraryCreateInfoEXT; - -typedef struct VkImageCaptureDescriptorDataInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkImage WINE_VK_ALIGN(8) image; -} VkImageCaptureDescriptorDataInfoEXT; - -typedef struct VkImageCompressionControlEXT -{ - VkStructureType sType; - const void *pNext; - VkImageCompressionFlagsEXT flags; - uint32_t compressionControlPlaneCount; - VkImageCompressionFixedRateFlagsEXT *pFixedRateFlags; -} VkImageCompressionControlEXT; - -typedef struct VkImageCompressionPropertiesEXT -{ - VkStructureType sType; - void *pNext; - VkImageCompressionFlagsEXT imageCompressionFlags; - VkImageCompressionFixedRateFlagsEXT imageCompressionFixedRateFlags; -} VkImageCompressionPropertiesEXT; - -typedef struct VkImageCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkImageCreateFlags flags; - VkImageType imageType; - VkFormat format; - VkExtent3D extent; - uint32_t mipLevels; - uint32_t arrayLayers; - VkSampleCountFlagBits samples; - VkImageTiling tiling; - VkImageUsageFlags usage; - VkSharingMode sharingMode; - uint32_t queueFamilyIndexCount; - const uint32_t *pQueueFamilyIndices; - VkImageLayout initialLayout; -} VkImageCreateInfo; - -typedef struct VkImageFormatListCreateInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t viewFormatCount; - const VkFormat *pViewFormats; -} VkImageFormatListCreateInfo; -typedef VkImageFormatListCreateInfo VkImageFormatListCreateInfoKHR; - -typedef struct VkImageFormatProperties -{ - VkExtent3D maxExtent; - uint32_t maxMipLevels; - uint32_t maxArrayLayers; - VkSampleCountFlags sampleCounts; - VkDeviceSize WINE_VK_ALIGN(8) maxResourceSize; -} VkImageFormatProperties; - -typedef struct VkImageFormatProperties2 -{ - VkStructureType sType; - void *pNext; - VkImageFormatProperties WINE_VK_ALIGN(8) imageFormatProperties; -} VkImageFormatProperties2; -typedef VkImageFormatProperties2 VkImageFormatProperties2KHR; - -typedef struct VkImageMemoryRequirementsInfo2 -{ - VkStructureType sType; - const void *pNext; - VkImage WINE_VK_ALIGN(8) image; -} VkImageMemoryRequirementsInfo2; -typedef VkImageMemoryRequirementsInfo2 VkImageMemoryRequirementsInfo2KHR; - -typedef struct VkImagePlaneMemoryRequirementsInfo -{ - VkStructureType sType; - const void *pNext; - VkImageAspectFlagBits planeAspect; -} VkImagePlaneMemoryRequirementsInfo; -typedef VkImagePlaneMemoryRequirementsInfo VkImagePlaneMemoryRequirementsInfoKHR; - -typedef struct VkImageSparseMemoryRequirementsInfo2 -{ - VkStructureType sType; - const void *pNext; - VkImage WINE_VK_ALIGN(8) image; -} VkImageSparseMemoryRequirementsInfo2; -typedef VkImageSparseMemoryRequirementsInfo2 VkImageSparseMemoryRequirementsInfo2KHR; - -typedef struct VkImageStencilUsageCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkImageUsageFlags stencilUsage; -} VkImageStencilUsageCreateInfo; -typedef VkImageStencilUsageCreateInfo VkImageStencilUsageCreateInfoEXT; - -typedef struct VkImageSubresource -{ - VkImageAspectFlags aspectMask; - uint32_t mipLevel; - uint32_t arrayLayer; -} VkImageSubresource; - -typedef struct VkImageSubresource2EXT -{ - VkStructureType sType; - void *pNext; - VkImageSubresource imageSubresource; -} VkImageSubresource2EXT; - -typedef struct VkImageSubresourceLayers -{ - VkImageAspectFlags aspectMask; - uint32_t mipLevel; - uint32_t baseArrayLayer; - uint32_t layerCount; -} VkImageSubresourceLayers; - -typedef struct VkImageSubresourceRange -{ - VkImageAspectFlags aspectMask; - uint32_t baseMipLevel; - uint32_t levelCount; - uint32_t baseArrayLayer; - uint32_t layerCount; -} VkImageSubresourceRange; - -typedef struct VkImageSwapchainCreateInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkSwapchainKHR WINE_VK_ALIGN(8) swapchain; -} VkImageSwapchainCreateInfoKHR; - -typedef struct VkImageViewASTCDecodeModeEXT -{ - VkStructureType sType; - const void *pNext; - VkFormat decodeMode; -} VkImageViewASTCDecodeModeEXT; - -typedef struct VkImageViewAddressPropertiesNVX -{ - VkStructureType sType; - void *pNext; - VkDeviceAddress WINE_VK_ALIGN(8) deviceAddress; - VkDeviceSize WINE_VK_ALIGN(8) size; -} VkImageViewAddressPropertiesNVX; - -typedef struct VkImageViewCaptureDescriptorDataInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkImageView WINE_VK_ALIGN(8) imageView; -} VkImageViewCaptureDescriptorDataInfoEXT; - -typedef struct VkImageViewCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkImageViewCreateFlags flags; - VkImage WINE_VK_ALIGN(8) image; - VkImageViewType viewType; - VkFormat format; - VkComponentMapping components; - VkImageSubresourceRange subresourceRange; -} VkImageViewCreateInfo; - -typedef struct VkImageViewHandleInfoNVX -{ - VkStructureType sType; - const void *pNext; - VkImageView WINE_VK_ALIGN(8) imageView; - VkDescriptorType descriptorType; - VkSampler WINE_VK_ALIGN(8) sampler; -} VkImageViewHandleInfoNVX; - -typedef struct VkImageViewMinLodCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - float minLod; -} VkImageViewMinLodCreateInfoEXT; - -typedef struct VkImageViewUsageCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkImageUsageFlags usage; -} VkImageViewUsageCreateInfo; -typedef VkImageViewUsageCreateInfo VkImageViewUsageCreateInfoKHR; - -typedef struct VkImportMemoryHostPointerInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkExternalMemoryHandleTypeFlagBits handleType; - void *pHostPointer; -} VkImportMemoryHostPointerInfoEXT; - -typedef struct VkImportMemoryWin32HandleInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkExternalMemoryHandleTypeFlagBits handleType; - HANDLE handle; - LPCWSTR name; -} VkImportMemoryWin32HandleInfoKHR; - -typedef struct VkIndirectCommandsLayoutTokenNV -{ - VkStructureType sType; - const void *pNext; - VkIndirectCommandsTokenTypeNV tokenType; - uint32_t stream; - uint32_t offset; - uint32_t vertexBindingUnit; - VkBool32 vertexDynamicStride; - VkPipelineLayout WINE_VK_ALIGN(8) pushconstantPipelineLayout; - VkShaderStageFlags pushconstantShaderStageFlags; - uint32_t pushconstantOffset; - uint32_t pushconstantSize; - VkIndirectStateFlagsNV indirectStateFlags; - uint32_t indexTypeCount; - const VkIndexType *pIndexTypes; - const uint32_t *pIndexTypeValues; -} VkIndirectCommandsLayoutTokenNV; - -typedef struct VkIndirectCommandsStreamNV -{ - VkBuffer WINE_VK_ALIGN(8) buffer; - VkDeviceSize WINE_VK_ALIGN(8) offset; -} VkIndirectCommandsStreamNV; - -typedef struct VkInitializePerformanceApiInfoINTEL -{ - VkStructureType sType; - const void *pNext; - void *pUserData; -} VkInitializePerformanceApiInfoINTEL; - -typedef struct VkInputAttachmentAspectReference -{ - uint32_t subpass; - uint32_t inputAttachmentIndex; - VkImageAspectFlags aspectMask; -} VkInputAttachmentAspectReference; -typedef VkInputAttachmentAspectReference VkInputAttachmentAspectReferenceKHR; - -typedef struct VkInstanceCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkInstanceCreateFlags flags; - const VkApplicationInfo *pApplicationInfo; - uint32_t enabledLayerCount; - const char * const*ppEnabledLayerNames; - uint32_t enabledExtensionCount; - const char * const*ppEnabledExtensionNames; -} VkInstanceCreateInfo; - -typedef struct VkLayerProperties -{ - char layerName[VK_MAX_EXTENSION_NAME_SIZE]; - uint32_t specVersion; - uint32_t implementationVersion; - char description[VK_MAX_DESCRIPTION_SIZE]; -} VkLayerProperties; - -typedef struct VkMappedMemoryRange -{ - VkStructureType sType; - const void *pNext; - VkDeviceMemory WINE_VK_ALIGN(8) memory; - VkDeviceSize WINE_VK_ALIGN(8) offset; - VkDeviceSize WINE_VK_ALIGN(8) size; -} VkMappedMemoryRange; - -typedef struct VkMemoryAllocateFlagsInfo -{ - VkStructureType sType; - const void *pNext; - VkMemoryAllocateFlags flags; - uint32_t deviceMask; -} VkMemoryAllocateFlagsInfo; -typedef VkMemoryAllocateFlagsInfo VkMemoryAllocateFlagsInfoKHR; - -typedef struct VkMemoryAllocateInfo -{ - VkStructureType sType; - const void *pNext; - VkDeviceSize WINE_VK_ALIGN(8) allocationSize; - uint32_t memoryTypeIndex; -} VkMemoryAllocateInfo; - -typedef struct VkMemoryBarrier -{ - VkStructureType sType; - const void *pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; -} VkMemoryBarrier; - -typedef struct VkMemoryBarrier2 -{ - VkStructureType sType; - const void *pNext; - VkPipelineStageFlags2 WINE_VK_ALIGN(8) srcStageMask; - VkAccessFlags2 WINE_VK_ALIGN(8) srcAccessMask; - VkPipelineStageFlags2 WINE_VK_ALIGN(8) dstStageMask; - VkAccessFlags2 WINE_VK_ALIGN(8) dstAccessMask; -} VkMemoryBarrier2; -typedef VkMemoryBarrier2 VkMemoryBarrier2KHR; - -typedef struct VkMemoryDedicatedAllocateInfo -{ - VkStructureType sType; - const void *pNext; - VkImage WINE_VK_ALIGN(8) image; - VkBuffer WINE_VK_ALIGN(8) buffer; -} VkMemoryDedicatedAllocateInfo; -typedef VkMemoryDedicatedAllocateInfo VkMemoryDedicatedAllocateInfoKHR; - -typedef struct VkMemoryDedicatedRequirements -{ - VkStructureType sType; - void *pNext; - VkBool32 prefersDedicatedAllocation; - VkBool32 requiresDedicatedAllocation; -} VkMemoryDedicatedRequirements; -typedef VkMemoryDedicatedRequirements VkMemoryDedicatedRequirementsKHR; - -typedef struct VkMemoryGetWin32HandleInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkDeviceMemory WINE_VK_ALIGN(8) memory; - VkExternalMemoryHandleTypeFlagBits handleType; -} VkMemoryGetWin32HandleInfoKHR; - -typedef struct VkMemoryHeap -{ - VkDeviceSize WINE_VK_ALIGN(8) size; - VkMemoryHeapFlags flags; -} VkMemoryHeap; - -typedef struct VkMemoryHostPointerPropertiesEXT -{ - VkStructureType sType; - void *pNext; - uint32_t memoryTypeBits; -} VkMemoryHostPointerPropertiesEXT; - -typedef struct VkMemoryOpaqueCaptureAddressAllocateInfo -{ - VkStructureType sType; - const void *pNext; - uint64_t WINE_VK_ALIGN(8) opaqueCaptureAddress; -} VkMemoryOpaqueCaptureAddressAllocateInfo; -typedef VkMemoryOpaqueCaptureAddressAllocateInfo VkMemoryOpaqueCaptureAddressAllocateInfoKHR; - -typedef struct VkMemoryPriorityAllocateInfoEXT -{ - VkStructureType sType; - const void *pNext; - float priority; -} VkMemoryPriorityAllocateInfoEXT; - -typedef struct VkMemoryRequirements -{ - VkDeviceSize WINE_VK_ALIGN(8) size; - VkDeviceSize WINE_VK_ALIGN(8) alignment; - uint32_t memoryTypeBits; -} VkMemoryRequirements; - -typedef struct VkMemoryRequirements2 -{ - VkStructureType sType; - void *pNext; - VkMemoryRequirements WINE_VK_ALIGN(8) memoryRequirements; -} VkMemoryRequirements2; -typedef VkMemoryRequirements2 VkMemoryRequirements2KHR; - - -typedef struct VkMemoryType -{ - VkMemoryPropertyFlags propertyFlags; - uint32_t heapIndex; -} VkMemoryType; - -typedef struct VkMemoryWin32HandlePropertiesKHR -{ - VkStructureType sType; - void *pNext; - uint32_t memoryTypeBits; -} VkMemoryWin32HandlePropertiesKHR; - -typedef struct VkMicromapBuildSizesInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkDeviceSize WINE_VK_ALIGN(8) micromapSize; - VkDeviceSize WINE_VK_ALIGN(8) buildScratchSize; - VkBool32 discardable; -} VkMicromapBuildSizesInfoEXT; - -typedef struct VkMicromapCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkMicromapCreateFlagsEXT createFlags; - VkBuffer WINE_VK_ALIGN(8) buffer; - VkDeviceSize WINE_VK_ALIGN(8) offset; - VkDeviceSize WINE_VK_ALIGN(8) size; - VkMicromapTypeEXT type; - VkDeviceAddress WINE_VK_ALIGN(8) deviceAddress; -} VkMicromapCreateInfoEXT; - -typedef struct VkMicromapTriangleEXT -{ - uint32_t dataOffset; - uint16_t subdivisionLevel; - uint16_t format; -} VkMicromapTriangleEXT; - -typedef struct VkMicromapUsageEXT -{ - uint32_t count; - uint32_t subdivisionLevel; - uint32_t format; -} VkMicromapUsageEXT; - -typedef struct VkMicromapVersionInfoEXT -{ - VkStructureType sType; - const void *pNext; - const uint8_t *pVersionData; -} VkMicromapVersionInfoEXT; - -typedef struct VkMultiDrawIndexedInfoEXT -{ - uint32_t firstIndex; - uint32_t indexCount; - int32_t vertexOffset; -} VkMultiDrawIndexedInfoEXT; - -typedef struct VkMultiDrawInfoEXT -{ - uint32_t firstVertex; - uint32_t vertexCount; -} VkMultiDrawInfoEXT; - -typedef struct VkMultisamplePropertiesEXT -{ - VkStructureType sType; - void *pNext; - VkExtent2D maxSampleLocationGridSize; -} VkMultisamplePropertiesEXT; - -typedef struct VkMultisampledRenderToSingleSampledInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkBool32 multisampledRenderToSingleSampledEnable; - VkSampleCountFlagBits rasterizationSamples; -} VkMultisampledRenderToSingleSampledInfoEXT; - -typedef struct VkMultiviewPerViewAttributesInfoNVX -{ - VkStructureType sType; - const void *pNext; - VkBool32 perViewAttributes; - VkBool32 perViewAttributesPositionXOnly; -} VkMultiviewPerViewAttributesInfoNVX; - -typedef struct VkMutableDescriptorTypeListEXT -{ - uint32_t descriptorTypeCount; - const VkDescriptorType *pDescriptorTypes; -} VkMutableDescriptorTypeListEXT; -typedef VkMutableDescriptorTypeListEXT VkMutableDescriptorTypeListVALVE; - -typedef struct VkOffset2D -{ - int32_t x; - int32_t y; -} VkOffset2D; - -typedef struct VkOffset3D -{ - int32_t x; - int32_t y; - int32_t z; -} VkOffset3D; - -typedef struct VkOpaqueCaptureDescriptorDataCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - const void *opaqueCaptureDescriptorData; -} VkOpaqueCaptureDescriptorDataCreateInfoEXT; - -typedef struct VkOpticalFlowImageFormatInfoNV -{ - VkStructureType sType; - const void *pNext; - VkOpticalFlowUsageFlagsNV usage; -} VkOpticalFlowImageFormatInfoNV; - -typedef struct VkOpticalFlowImageFormatPropertiesNV -{ - VkStructureType sType; - const void *pNext; - VkFormat format; -} VkOpticalFlowImageFormatPropertiesNV; - -typedef struct VkOpticalFlowSessionCreateInfoNV -{ - VkStructureType sType; - void *pNext; - uint32_t width; - uint32_t height; - VkFormat imageFormat; - VkFormat flowVectorFormat; - VkFormat costFormat; - VkOpticalFlowGridSizeFlagsNV outputGridSize; - VkOpticalFlowGridSizeFlagsNV hintGridSize; - VkOpticalFlowPerformanceLevelNV performanceLevel; - VkOpticalFlowSessionCreateFlagsNV flags; -} VkOpticalFlowSessionCreateInfoNV; - -typedef struct VkOpticalFlowSessionCreatePrivateDataInfoNV -{ - VkStructureType sType; - void *pNext; - uint32_t id; - uint32_t size; - const void *pPrivateData; -} VkOpticalFlowSessionCreatePrivateDataInfoNV; - -typedef struct VkPerformanceConfigurationAcquireInfoINTEL -{ - VkStructureType sType; - const void *pNext; - VkPerformanceConfigurationTypeINTEL type; -} VkPerformanceConfigurationAcquireInfoINTEL; - -typedef struct VkPerformanceCounterDescriptionKHR -{ - VkStructureType sType; - void *pNext; - VkPerformanceCounterDescriptionFlagsKHR flags; - char name[VK_MAX_DESCRIPTION_SIZE]; - char category[VK_MAX_DESCRIPTION_SIZE]; - char description[VK_MAX_DESCRIPTION_SIZE]; -} VkPerformanceCounterDescriptionKHR; - -typedef struct VkPerformanceCounterKHR -{ - VkStructureType sType; - void *pNext; - VkPerformanceCounterUnitKHR unit; - VkPerformanceCounterScopeKHR scope; - VkPerformanceCounterStorageKHR storage; - uint8_t uuid[VK_UUID_SIZE]; -} VkPerformanceCounterKHR; - -typedef union VkPerformanceCounterResultKHR -{ - int32_t int32; - int64_t int64; - uint32_t uint32; - uint64_t WINE_VK_ALIGN(8) uint64; - float float32; - double float64; -} VkPerformanceCounterResultKHR; - -typedef struct VkPerformanceMarkerInfoINTEL -{ - VkStructureType sType; - const void *pNext; - uint64_t WINE_VK_ALIGN(8) marker; -} VkPerformanceMarkerInfoINTEL; - -typedef struct VkPerformanceOverrideInfoINTEL -{ - VkStructureType sType; - const void *pNext; - VkPerformanceOverrideTypeINTEL type; - VkBool32 enable; - uint64_t WINE_VK_ALIGN(8) parameter; -} VkPerformanceOverrideInfoINTEL; - -typedef struct VkPerformanceQuerySubmitInfoKHR -{ - VkStructureType sType; - const void *pNext; - uint32_t counterPassIndex; -} VkPerformanceQuerySubmitInfoKHR; - -typedef struct VkPerformanceStreamMarkerInfoINTEL -{ - VkStructureType sType; - const void *pNext; - uint32_t marker; -} VkPerformanceStreamMarkerInfoINTEL; - -typedef union VkPerformanceValueDataINTEL -{ - uint32_t value32; - uint64_t WINE_VK_ALIGN(8) value64; - float valueFloat; - VkBool32 valueBool; - const char *valueString; -} VkPerformanceValueDataINTEL; - -typedef struct VkPerformanceValueINTEL -{ - VkPerformanceValueTypeINTEL type; - VkPerformanceValueDataINTEL WINE_VK_ALIGN(8) data; -} VkPerformanceValueINTEL; - -typedef struct VkPhysicalDevice16BitStorageFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 storageBuffer16BitAccess; - VkBool32 uniformAndStorageBuffer16BitAccess; - VkBool32 storagePushConstant16; - VkBool32 storageInputOutput16; -} VkPhysicalDevice16BitStorageFeatures; -typedef VkPhysicalDevice16BitStorageFeatures VkPhysicalDevice16BitStorageFeaturesKHR; - -typedef struct VkPhysicalDevice4444FormatsFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 formatA4R4G4B4; - VkBool32 formatA4B4G4R4; -} VkPhysicalDevice4444FormatsFeaturesEXT; - -typedef struct VkPhysicalDevice8BitStorageFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 storageBuffer8BitAccess; - VkBool32 uniformAndStorageBuffer8BitAccess; - VkBool32 storagePushConstant8; -} VkPhysicalDevice8BitStorageFeatures; -typedef VkPhysicalDevice8BitStorageFeatures VkPhysicalDevice8BitStorageFeaturesKHR; - -typedef struct VkPhysicalDeviceASTCDecodeFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 decodeModeSharedExponent; -} VkPhysicalDeviceASTCDecodeFeaturesEXT; - -typedef struct VkPhysicalDeviceAccelerationStructureFeaturesKHR -{ - VkStructureType sType; - void *pNext; - VkBool32 accelerationStructure; - VkBool32 accelerationStructureCaptureReplay; - VkBool32 accelerationStructureIndirectBuild; - VkBool32 accelerationStructureHostCommands; - VkBool32 descriptorBindingAccelerationStructureUpdateAfterBind; -} VkPhysicalDeviceAccelerationStructureFeaturesKHR; - -typedef struct VkPhysicalDeviceAccelerationStructurePropertiesKHR -{ - VkStructureType sType; - void *pNext; - uint64_t WINE_VK_ALIGN(8) maxGeometryCount; - uint64_t WINE_VK_ALIGN(8) maxInstanceCount; - uint64_t WINE_VK_ALIGN(8) maxPrimitiveCount; - uint32_t maxPerStageDescriptorAccelerationStructures; - uint32_t maxPerStageDescriptorUpdateAfterBindAccelerationStructures; - uint32_t maxDescriptorSetAccelerationStructures; - uint32_t maxDescriptorSetUpdateAfterBindAccelerationStructures; - uint32_t minAccelerationStructureScratchOffsetAlignment; -} VkPhysicalDeviceAccelerationStructurePropertiesKHR; - -typedef struct VkPhysicalDeviceAddressBindingReportFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 reportAddressBinding; -} VkPhysicalDeviceAddressBindingReportFeaturesEXT; - -typedef struct VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 attachmentFeedbackLoopLayout; -} VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT; - -typedef struct VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 advancedBlendCoherentOperations; -} VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT; - -typedef struct VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT -{ - VkStructureType sType; - void *pNext; - uint32_t advancedBlendMaxColorAttachments; - VkBool32 advancedBlendIndependentBlend; - VkBool32 advancedBlendNonPremultipliedSrcColor; - VkBool32 advancedBlendNonPremultipliedDstColor; - VkBool32 advancedBlendCorrelatedOverlap; - VkBool32 advancedBlendAllOperations; -} VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT; - -typedef struct VkPhysicalDeviceBorderColorSwizzleFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 borderColorSwizzle; - VkBool32 borderColorSwizzleFromImage; -} VkPhysicalDeviceBorderColorSwizzleFeaturesEXT; - -typedef struct VkPhysicalDeviceBufferDeviceAddressFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 bufferDeviceAddress; - VkBool32 bufferDeviceAddressCaptureReplay; - VkBool32 bufferDeviceAddressMultiDevice; -} VkPhysicalDeviceBufferDeviceAddressFeatures; -typedef VkPhysicalDeviceBufferDeviceAddressFeatures VkPhysicalDeviceBufferDeviceAddressFeaturesKHR; - -typedef struct VkPhysicalDeviceBufferDeviceAddressFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 bufferDeviceAddress; - VkBool32 bufferDeviceAddressCaptureReplay; - VkBool32 bufferDeviceAddressMultiDevice; -} VkPhysicalDeviceBufferDeviceAddressFeaturesEXT; -typedef VkPhysicalDeviceBufferDeviceAddressFeaturesEXT VkPhysicalDeviceBufferAddressFeaturesEXT; - -typedef struct VkPhysicalDeviceCoherentMemoryFeaturesAMD -{ - VkStructureType sType; - void *pNext; - VkBool32 deviceCoherentMemory; -} VkPhysicalDeviceCoherentMemoryFeaturesAMD; - -typedef struct VkPhysicalDeviceColorWriteEnableFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 colorWriteEnable; -} VkPhysicalDeviceColorWriteEnableFeaturesEXT; - -typedef struct VkPhysicalDeviceComputeShaderDerivativesFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 computeDerivativeGroupQuads; - VkBool32 computeDerivativeGroupLinear; -} VkPhysicalDeviceComputeShaderDerivativesFeaturesNV; - -typedef struct VkPhysicalDeviceConditionalRenderingFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 conditionalRendering; - VkBool32 inheritedConditionalRendering; -} VkPhysicalDeviceConditionalRenderingFeaturesEXT; - -typedef struct VkPhysicalDeviceConservativeRasterizationPropertiesEXT -{ - VkStructureType sType; - void *pNext; - float primitiveOverestimationSize; - float maxExtraPrimitiveOverestimationSize; - float extraPrimitiveOverestimationSizeGranularity; - VkBool32 primitiveUnderestimation; - VkBool32 conservativePointAndLineRasterization; - VkBool32 degenerateTrianglesRasterized; - VkBool32 degenerateLinesRasterized; - VkBool32 fullyCoveredFragmentShaderInputVariable; - VkBool32 conservativeRasterizationPostDepthCoverage; -} VkPhysicalDeviceConservativeRasterizationPropertiesEXT; - -typedef struct VkPhysicalDeviceCooperativeMatrixFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 cooperativeMatrix; - VkBool32 cooperativeMatrixRobustBufferAccess; -} VkPhysicalDeviceCooperativeMatrixFeaturesNV; - -typedef struct VkPhysicalDeviceCooperativeMatrixPropertiesNV -{ - VkStructureType sType; - void *pNext; - VkShaderStageFlags cooperativeMatrixSupportedStages; -} VkPhysicalDeviceCooperativeMatrixPropertiesNV; - -typedef struct VkPhysicalDeviceCopyMemoryIndirectFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 indirectCopy; -} VkPhysicalDeviceCopyMemoryIndirectFeaturesNV; - -typedef struct VkPhysicalDeviceCopyMemoryIndirectPropertiesNV -{ - VkStructureType sType; - void *pNext; - VkQueueFlags supportedQueues; -} VkPhysicalDeviceCopyMemoryIndirectPropertiesNV; - -typedef struct VkPhysicalDeviceCornerSampledImageFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 cornerSampledImage; -} VkPhysicalDeviceCornerSampledImageFeaturesNV; - -typedef struct VkPhysicalDeviceCoverageReductionModeFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 coverageReductionMode; -} VkPhysicalDeviceCoverageReductionModeFeaturesNV; - -typedef struct VkPhysicalDeviceCustomBorderColorFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 customBorderColors; - VkBool32 customBorderColorWithoutFormat; -} VkPhysicalDeviceCustomBorderColorFeaturesEXT; - -typedef struct VkPhysicalDeviceCustomBorderColorPropertiesEXT -{ - VkStructureType sType; - void *pNext; - uint32_t maxCustomBorderColorSamplers; -} VkPhysicalDeviceCustomBorderColorPropertiesEXT; - -typedef struct VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 dedicatedAllocationImageAliasing; -} VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV; - -typedef struct VkPhysicalDeviceDepthClampZeroOneFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 depthClampZeroOne; -} VkPhysicalDeviceDepthClampZeroOneFeaturesEXT; - -typedef struct VkPhysicalDeviceDepthClipControlFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 depthClipControl; -} VkPhysicalDeviceDepthClipControlFeaturesEXT; - -typedef struct VkPhysicalDeviceDepthClipEnableFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 depthClipEnable; -} VkPhysicalDeviceDepthClipEnableFeaturesEXT; - -typedef struct VkPhysicalDeviceDepthStencilResolveProperties -{ - VkStructureType sType; - void *pNext; - VkResolveModeFlags supportedDepthResolveModes; - VkResolveModeFlags supportedStencilResolveModes; - VkBool32 independentResolveNone; - VkBool32 independentResolve; -} VkPhysicalDeviceDepthStencilResolveProperties; -typedef VkPhysicalDeviceDepthStencilResolveProperties VkPhysicalDeviceDepthStencilResolvePropertiesKHR; - -typedef struct VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT -{ - VkStructureType sType; - void *pNext; - size_t combinedImageSamplerDensityMapDescriptorSize; -} VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT; - -typedef struct VkPhysicalDeviceDescriptorBufferFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 descriptorBuffer; - VkBool32 descriptorBufferCaptureReplay; - VkBool32 descriptorBufferImageLayoutIgnored; - VkBool32 descriptorBufferPushDescriptors; -} VkPhysicalDeviceDescriptorBufferFeaturesEXT; - -typedef struct VkPhysicalDeviceDescriptorBufferPropertiesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 combinedImageSamplerDescriptorSingleArray; - VkBool32 bufferlessPushDescriptors; - VkBool32 allowSamplerImageViewPostSubmitCreation; - VkDeviceSize WINE_VK_ALIGN(8) descriptorBufferOffsetAlignment; - uint32_t maxDescriptorBufferBindings; - uint32_t maxResourceDescriptorBufferBindings; - uint32_t maxSamplerDescriptorBufferBindings; - uint32_t maxEmbeddedImmutableSamplerBindings; - uint32_t maxEmbeddedImmutableSamplers; - size_t bufferCaptureReplayDescriptorDataSize; - size_t imageCaptureReplayDescriptorDataSize; - size_t imageViewCaptureReplayDescriptorDataSize; - size_t samplerCaptureReplayDescriptorDataSize; - size_t accelerationStructureCaptureReplayDescriptorDataSize; - size_t samplerDescriptorSize; - size_t combinedImageSamplerDescriptorSize; - size_t sampledImageDescriptorSize; - size_t storageImageDescriptorSize; - size_t uniformTexelBufferDescriptorSize; - size_t robustUniformTexelBufferDescriptorSize; - size_t storageTexelBufferDescriptorSize; - size_t robustStorageTexelBufferDescriptorSize; - size_t uniformBufferDescriptorSize; - size_t robustUniformBufferDescriptorSize; - size_t storageBufferDescriptorSize; - size_t robustStorageBufferDescriptorSize; - size_t inputAttachmentDescriptorSize; - size_t accelerationStructureDescriptorSize; - VkDeviceSize WINE_VK_ALIGN(8) maxSamplerDescriptorBufferRange; - VkDeviceSize WINE_VK_ALIGN(8) maxResourceDescriptorBufferRange; - VkDeviceSize WINE_VK_ALIGN(8) samplerDescriptorBufferAddressSpaceSize; - VkDeviceSize WINE_VK_ALIGN(8) resourceDescriptorBufferAddressSpaceSize; - VkDeviceSize WINE_VK_ALIGN(8) descriptorBufferAddressSpaceSize; -} VkPhysicalDeviceDescriptorBufferPropertiesEXT; - -typedef struct VkPhysicalDeviceDescriptorIndexingFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderInputAttachmentArrayDynamicIndexing; - VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; - VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; - VkBool32 shaderUniformBufferArrayNonUniformIndexing; - VkBool32 shaderSampledImageArrayNonUniformIndexing; - VkBool32 shaderStorageBufferArrayNonUniformIndexing; - VkBool32 shaderStorageImageArrayNonUniformIndexing; - VkBool32 shaderInputAttachmentArrayNonUniformIndexing; - VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; - VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; - VkBool32 descriptorBindingUniformBufferUpdateAfterBind; - VkBool32 descriptorBindingSampledImageUpdateAfterBind; - VkBool32 descriptorBindingStorageImageUpdateAfterBind; - VkBool32 descriptorBindingStorageBufferUpdateAfterBind; - VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingUpdateUnusedWhilePending; - VkBool32 descriptorBindingPartiallyBound; - VkBool32 descriptorBindingVariableDescriptorCount; - VkBool32 runtimeDescriptorArray; -} VkPhysicalDeviceDescriptorIndexingFeatures; -typedef VkPhysicalDeviceDescriptorIndexingFeatures VkPhysicalDeviceDescriptorIndexingFeaturesEXT; - -typedef struct VkPhysicalDeviceDescriptorIndexingProperties -{ - VkStructureType sType; - void *pNext; - uint32_t maxUpdateAfterBindDescriptorsInAllPools; - VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; - VkBool32 shaderSampledImageArrayNonUniformIndexingNative; - VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; - VkBool32 shaderStorageImageArrayNonUniformIndexingNative; - VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; - VkBool32 robustBufferAccessUpdateAfterBind; - VkBool32 quadDivergentImplicitLod; - uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; - uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; - uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; - uint32_t maxPerStageUpdateAfterBindResources; - uint32_t maxDescriptorSetUpdateAfterBindSamplers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindSampledImages; - uint32_t maxDescriptorSetUpdateAfterBindStorageImages; - uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; -} VkPhysicalDeviceDescriptorIndexingProperties; -typedef VkPhysicalDeviceDescriptorIndexingProperties VkPhysicalDeviceDescriptorIndexingPropertiesEXT; - -typedef struct VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE -{ - VkStructureType sType; - void *pNext; - VkBool32 descriptorSetHostMapping; -} VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE; - -typedef struct VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 deviceGeneratedCommands; -} VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV; - -typedef struct VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV -{ - VkStructureType sType; - void *pNext; - uint32_t maxGraphicsShaderGroupCount; - uint32_t maxIndirectSequenceCount; - uint32_t maxIndirectCommandsTokenCount; - uint32_t maxIndirectCommandsStreamCount; - uint32_t maxIndirectCommandsTokenOffset; - uint32_t maxIndirectCommandsStreamStride; - uint32_t minSequencesCountBufferOffsetAlignment; - uint32_t minSequencesIndexBufferOffsetAlignment; - uint32_t minIndirectCommandsBufferOffsetAlignment; -} VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV; - -typedef struct VkPhysicalDeviceDiagnosticsConfigFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 diagnosticsConfig; -} VkPhysicalDeviceDiagnosticsConfigFeaturesNV; - -typedef struct VkPhysicalDeviceDiscardRectanglePropertiesEXT -{ - VkStructureType sType; - void *pNext; - uint32_t maxDiscardRectangles; -} VkPhysicalDeviceDiscardRectanglePropertiesEXT; - -typedef struct VkPhysicalDeviceDriverProperties -{ - VkStructureType sType; - void *pNext; - VkDriverId driverID; - char driverName[VK_MAX_DRIVER_NAME_SIZE]; - char driverInfo[VK_MAX_DRIVER_INFO_SIZE]; - VkConformanceVersion conformanceVersion; -} VkPhysicalDeviceDriverProperties; -typedef VkPhysicalDeviceDriverProperties VkPhysicalDeviceDriverPropertiesKHR; - -typedef struct VkPhysicalDeviceDynamicRenderingFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 dynamicRendering; -} VkPhysicalDeviceDynamicRenderingFeatures; -typedef VkPhysicalDeviceDynamicRenderingFeatures VkPhysicalDeviceDynamicRenderingFeaturesKHR; - -typedef struct VkPhysicalDeviceExclusiveScissorFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 exclusiveScissor; -} VkPhysicalDeviceExclusiveScissorFeaturesNV; - -typedef struct VkPhysicalDeviceExtendedDynamicState2FeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 extendedDynamicState2; - VkBool32 extendedDynamicState2LogicOp; - VkBool32 extendedDynamicState2PatchControlPoints; -} VkPhysicalDeviceExtendedDynamicState2FeaturesEXT; - -typedef struct VkPhysicalDeviceExtendedDynamicState3FeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 extendedDynamicState3TessellationDomainOrigin; - VkBool32 extendedDynamicState3DepthClampEnable; - VkBool32 extendedDynamicState3PolygonMode; - VkBool32 extendedDynamicState3RasterizationSamples; - VkBool32 extendedDynamicState3SampleMask; - VkBool32 extendedDynamicState3AlphaToCoverageEnable; - VkBool32 extendedDynamicState3AlphaToOneEnable; - VkBool32 extendedDynamicState3LogicOpEnable; - VkBool32 extendedDynamicState3ColorBlendEnable; - VkBool32 extendedDynamicState3ColorBlendEquation; - VkBool32 extendedDynamicState3ColorWriteMask; - VkBool32 extendedDynamicState3RasterizationStream; - VkBool32 extendedDynamicState3ConservativeRasterizationMode; - VkBool32 extendedDynamicState3ExtraPrimitiveOverestimationSize; - VkBool32 extendedDynamicState3DepthClipEnable; - VkBool32 extendedDynamicState3SampleLocationsEnable; - VkBool32 extendedDynamicState3ColorBlendAdvanced; - VkBool32 extendedDynamicState3ProvokingVertexMode; - VkBool32 extendedDynamicState3LineRasterizationMode; - VkBool32 extendedDynamicState3LineStippleEnable; - VkBool32 extendedDynamicState3DepthClipNegativeOneToOne; - VkBool32 extendedDynamicState3ViewportWScalingEnable; - VkBool32 extendedDynamicState3ViewportSwizzle; - VkBool32 extendedDynamicState3CoverageToColorEnable; - VkBool32 extendedDynamicState3CoverageToColorLocation; - VkBool32 extendedDynamicState3CoverageModulationMode; - VkBool32 extendedDynamicState3CoverageModulationTableEnable; - VkBool32 extendedDynamicState3CoverageModulationTable; - VkBool32 extendedDynamicState3CoverageReductionMode; - VkBool32 extendedDynamicState3RepresentativeFragmentTestEnable; - VkBool32 extendedDynamicState3ShadingRateImageEnable; -} VkPhysicalDeviceExtendedDynamicState3FeaturesEXT; - -typedef struct VkPhysicalDeviceExtendedDynamicState3PropertiesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 dynamicPrimitiveTopologyUnrestricted; -} VkPhysicalDeviceExtendedDynamicState3PropertiesEXT; - -typedef struct VkPhysicalDeviceExtendedDynamicStateFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 extendedDynamicState; -} VkPhysicalDeviceExtendedDynamicStateFeaturesEXT; - -typedef struct VkPhysicalDeviceExternalBufferInfo -{ - VkStructureType sType; - const void *pNext; - VkBufferCreateFlags flags; - VkBufferUsageFlags usage; - VkExternalMemoryHandleTypeFlagBits handleType; -} VkPhysicalDeviceExternalBufferInfo; -typedef VkPhysicalDeviceExternalBufferInfo VkPhysicalDeviceExternalBufferInfoKHR; - -typedef struct VkPhysicalDeviceExternalFenceInfo -{ - VkStructureType sType; - const void *pNext; - VkExternalFenceHandleTypeFlagBits handleType; -} VkPhysicalDeviceExternalFenceInfo; -typedef VkPhysicalDeviceExternalFenceInfo VkPhysicalDeviceExternalFenceInfoKHR; - -typedef struct VkPhysicalDeviceExternalImageFormatInfo -{ - VkStructureType sType; - const void *pNext; - VkExternalMemoryHandleTypeFlagBits handleType; -} VkPhysicalDeviceExternalImageFormatInfo; -typedef VkPhysicalDeviceExternalImageFormatInfo VkPhysicalDeviceExternalImageFormatInfoKHR; - -typedef struct VkPhysicalDeviceExternalMemoryHostPropertiesEXT -{ - VkStructureType sType; - void *pNext; - VkDeviceSize WINE_VK_ALIGN(8) minImportedHostPointerAlignment; -} VkPhysicalDeviceExternalMemoryHostPropertiesEXT; - -typedef struct VkPhysicalDeviceExternalSemaphoreInfo -{ - VkStructureType sType; - const void *pNext; - VkExternalSemaphoreHandleTypeFlagBits handleType; -} VkPhysicalDeviceExternalSemaphoreInfo; -typedef VkPhysicalDeviceExternalSemaphoreInfo VkPhysicalDeviceExternalSemaphoreInfoKHR; - -typedef struct VkPhysicalDeviceFaultFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 deviceFault; - VkBool32 deviceFaultVendorBinary; -} VkPhysicalDeviceFaultFeaturesEXT; - -typedef struct VkPhysicalDeviceFeatures -{ - VkBool32 robustBufferAccess; - VkBool32 fullDrawIndexUint32; - VkBool32 imageCubeArray; - VkBool32 independentBlend; - VkBool32 geometryShader; - VkBool32 tessellationShader; - VkBool32 sampleRateShading; - VkBool32 dualSrcBlend; - VkBool32 logicOp; - VkBool32 multiDrawIndirect; - VkBool32 drawIndirectFirstInstance; - VkBool32 depthClamp; - VkBool32 depthBiasClamp; - VkBool32 fillModeNonSolid; - VkBool32 depthBounds; - VkBool32 wideLines; - VkBool32 largePoints; - VkBool32 alphaToOne; - VkBool32 multiViewport; - VkBool32 samplerAnisotropy; - VkBool32 textureCompressionETC2; - VkBool32 textureCompressionASTC_LDR; - VkBool32 textureCompressionBC; - VkBool32 occlusionQueryPrecise; - VkBool32 pipelineStatisticsQuery; - VkBool32 vertexPipelineStoresAndAtomics; - VkBool32 fragmentStoresAndAtomics; - VkBool32 shaderTessellationAndGeometryPointSize; - VkBool32 shaderImageGatherExtended; - VkBool32 shaderStorageImageExtendedFormats; - VkBool32 shaderStorageImageMultisample; - VkBool32 shaderStorageImageReadWithoutFormat; - VkBool32 shaderStorageImageWriteWithoutFormat; - VkBool32 shaderUniformBufferArrayDynamicIndexing; - VkBool32 shaderSampledImageArrayDynamicIndexing; - VkBool32 shaderStorageBufferArrayDynamicIndexing; - VkBool32 shaderStorageImageArrayDynamicIndexing; - VkBool32 shaderClipDistance; - VkBool32 shaderCullDistance; - VkBool32 shaderFloat64; - VkBool32 shaderInt64; - VkBool32 shaderInt16; - VkBool32 shaderResourceResidency; - VkBool32 shaderResourceMinLod; - VkBool32 sparseBinding; - VkBool32 sparseResidencyBuffer; - VkBool32 sparseResidencyImage2D; - VkBool32 sparseResidencyImage3D; - VkBool32 sparseResidency2Samples; - VkBool32 sparseResidency4Samples; - VkBool32 sparseResidency8Samples; - VkBool32 sparseResidency16Samples; - VkBool32 sparseResidencyAliased; - VkBool32 variableMultisampleRate; - VkBool32 inheritedQueries; -} VkPhysicalDeviceFeatures; - -typedef struct VkPhysicalDeviceFeatures2 -{ - VkStructureType sType; - void *pNext; - VkPhysicalDeviceFeatures features; -} VkPhysicalDeviceFeatures2; -typedef VkPhysicalDeviceFeatures2 VkPhysicalDeviceFeatures2KHR; - -typedef struct VkPhysicalDeviceFloatControlsProperties -{ - VkStructureType sType; - void *pNext; - VkShaderFloatControlsIndependence denormBehaviorIndependence; - VkShaderFloatControlsIndependence roundingModeIndependence; - VkBool32 shaderSignedZeroInfNanPreserveFloat16; - VkBool32 shaderSignedZeroInfNanPreserveFloat32; - VkBool32 shaderSignedZeroInfNanPreserveFloat64; - VkBool32 shaderDenormPreserveFloat16; - VkBool32 shaderDenormPreserveFloat32; - VkBool32 shaderDenormPreserveFloat64; - VkBool32 shaderDenormFlushToZeroFloat16; - VkBool32 shaderDenormFlushToZeroFloat32; - VkBool32 shaderDenormFlushToZeroFloat64; - VkBool32 shaderRoundingModeRTEFloat16; - VkBool32 shaderRoundingModeRTEFloat32; - VkBool32 shaderRoundingModeRTEFloat64; - VkBool32 shaderRoundingModeRTZFloat16; - VkBool32 shaderRoundingModeRTZFloat32; - VkBool32 shaderRoundingModeRTZFloat64; -} VkPhysicalDeviceFloatControlsProperties; -typedef VkPhysicalDeviceFloatControlsProperties VkPhysicalDeviceFloatControlsPropertiesKHR; - -typedef struct VkPhysicalDeviceFragmentDensityMap2FeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 fragmentDensityMapDeferred; -} VkPhysicalDeviceFragmentDensityMap2FeaturesEXT; - -typedef struct VkPhysicalDeviceFragmentDensityMap2PropertiesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 subsampledLoads; - VkBool32 subsampledCoarseReconstructionEarlyAccess; - uint32_t maxSubsampledArrayLayers; - uint32_t maxDescriptorSetSubsampledSamplers; -} VkPhysicalDeviceFragmentDensityMap2PropertiesEXT; - -typedef struct VkPhysicalDeviceFragmentDensityMapFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 fragmentDensityMap; - VkBool32 fragmentDensityMapDynamic; - VkBool32 fragmentDensityMapNonSubsampledImages; -} VkPhysicalDeviceFragmentDensityMapFeaturesEXT; - -typedef struct VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM -{ - VkStructureType sType; - void *pNext; - VkBool32 fragmentDensityMapOffset; -} VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM; - -typedef struct VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM -{ - VkStructureType sType; - void *pNext; - VkExtent2D fragmentDensityOffsetGranularity; -} VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM; - -typedef struct VkPhysicalDeviceFragmentDensityMapPropertiesEXT -{ - VkStructureType sType; - void *pNext; - VkExtent2D minFragmentDensityTexelSize; - VkExtent2D maxFragmentDensityTexelSize; - VkBool32 fragmentDensityInvocations; -} VkPhysicalDeviceFragmentDensityMapPropertiesEXT; - -typedef struct VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR -{ - VkStructureType sType; - void *pNext; - VkBool32 fragmentShaderBarycentric; -} VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR; -typedef VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV; - -typedef struct VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR -{ - VkStructureType sType; - void *pNext; - VkBool32 triStripVertexOrderIndependentOfProvokingVertex; -} VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR; - -typedef struct VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 fragmentShaderSampleInterlock; - VkBool32 fragmentShaderPixelInterlock; - VkBool32 fragmentShaderShadingRateInterlock; -} VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT; - -typedef struct VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 fragmentShadingRateEnums; - VkBool32 supersampleFragmentShadingRates; - VkBool32 noInvocationFragmentShadingRates; -} VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV; - -typedef struct VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV -{ - VkStructureType sType; - void *pNext; - VkSampleCountFlagBits maxFragmentShadingRateInvocationCount; -} VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV; - -typedef struct VkPhysicalDeviceFragmentShadingRateFeaturesKHR -{ - VkStructureType sType; - void *pNext; - VkBool32 pipelineFragmentShadingRate; - VkBool32 primitiveFragmentShadingRate; - VkBool32 attachmentFragmentShadingRate; -} VkPhysicalDeviceFragmentShadingRateFeaturesKHR; - -typedef struct VkPhysicalDeviceFragmentShadingRateKHR -{ - VkStructureType sType; - void *pNext; - VkSampleCountFlags sampleCounts; - VkExtent2D fragmentSize; -} VkPhysicalDeviceFragmentShadingRateKHR; - -typedef struct VkPhysicalDeviceFragmentShadingRatePropertiesKHR -{ - VkStructureType sType; - void *pNext; - VkExtent2D minFragmentShadingRateAttachmentTexelSize; - VkExtent2D maxFragmentShadingRateAttachmentTexelSize; - uint32_t maxFragmentShadingRateAttachmentTexelSizeAspectRatio; - VkBool32 primitiveFragmentShadingRateWithMultipleViewports; - VkBool32 layeredShadingRateAttachments; - VkBool32 fragmentShadingRateNonTrivialCombinerOps; - VkExtent2D maxFragmentSize; - uint32_t maxFragmentSizeAspectRatio; - uint32_t maxFragmentShadingRateCoverageSamples; - VkSampleCountFlagBits maxFragmentShadingRateRasterizationSamples; - VkBool32 fragmentShadingRateWithShaderDepthStencilWrites; - VkBool32 fragmentShadingRateWithSampleMask; - VkBool32 fragmentShadingRateWithShaderSampleMask; - VkBool32 fragmentShadingRateWithConservativeRasterization; - VkBool32 fragmentShadingRateWithFragmentShaderInterlock; - VkBool32 fragmentShadingRateWithCustomSampleLocations; - VkBool32 fragmentShadingRateStrictMultiplyCombiner; -} VkPhysicalDeviceFragmentShadingRatePropertiesKHR; - -typedef struct VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR -{ - VkStructureType sType; - void *pNext; - VkBool32 globalPriorityQuery; -} VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR; -typedef VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR VkPhysicalDeviceGlobalPriorityQueryFeaturesEXT; - -typedef struct VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 graphicsPipelineLibrary; -} VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT; - -typedef struct VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 graphicsPipelineLibraryFastLinking; - VkBool32 graphicsPipelineLibraryIndependentInterpolationDecoration; -} VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT; - -typedef struct VkPhysicalDeviceGroupProperties -{ - VkStructureType sType; - void *pNext; - uint32_t physicalDeviceCount; - VkPhysicalDevice physicalDevices[VK_MAX_DEVICE_GROUP_SIZE]; - VkBool32 subsetAllocation; -} VkPhysicalDeviceGroupProperties; -typedef VkPhysicalDeviceGroupProperties VkPhysicalDeviceGroupPropertiesKHR; - -typedef struct VkPhysicalDeviceHostQueryResetFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 hostQueryReset; -} VkPhysicalDeviceHostQueryResetFeatures; -typedef VkPhysicalDeviceHostQueryResetFeatures VkPhysicalDeviceHostQueryResetFeaturesEXT; - -typedef struct VkPhysicalDeviceIDProperties -{ - VkStructureType sType; - void *pNext; - uint8_t deviceUUID[VK_UUID_SIZE]; - uint8_t driverUUID[VK_UUID_SIZE]; - uint8_t deviceLUID[VK_LUID_SIZE]; - uint32_t deviceNodeMask; - VkBool32 deviceLUIDValid; -} VkPhysicalDeviceIDProperties; -typedef VkPhysicalDeviceIDProperties VkPhysicalDeviceIDPropertiesKHR; - -typedef struct VkPhysicalDeviceImage2DViewOf3DFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 image2DViewOf3D; - VkBool32 sampler2DViewOf3D; -} VkPhysicalDeviceImage2DViewOf3DFeaturesEXT; - -typedef struct VkPhysicalDeviceImageCompressionControlFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 imageCompressionControl; -} VkPhysicalDeviceImageCompressionControlFeaturesEXT; - -typedef struct VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 imageCompressionControlSwapchain; -} VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT; - -typedef struct VkPhysicalDeviceImageFormatInfo2 -{ - VkStructureType sType; - const void *pNext; - VkFormat format; - VkImageType type; - VkImageTiling tiling; - VkImageUsageFlags usage; - VkImageCreateFlags flags; -} VkPhysicalDeviceImageFormatInfo2; -typedef VkPhysicalDeviceImageFormatInfo2 VkPhysicalDeviceImageFormatInfo2KHR; - -typedef struct VkPhysicalDeviceImageProcessingFeaturesQCOM -{ - VkStructureType sType; - void *pNext; - VkBool32 textureSampleWeighted; - VkBool32 textureBoxFilter; - VkBool32 textureBlockMatch; -} VkPhysicalDeviceImageProcessingFeaturesQCOM; - -typedef struct VkPhysicalDeviceImageProcessingPropertiesQCOM -{ - VkStructureType sType; - void *pNext; - uint32_t maxWeightFilterPhases; - VkExtent2D maxWeightFilterDimension; - VkExtent2D maxBlockMatchRegion; - VkExtent2D maxBoxFilterBlockSize; -} VkPhysicalDeviceImageProcessingPropertiesQCOM; - -typedef struct VkPhysicalDeviceImageRobustnessFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 robustImageAccess; -} VkPhysicalDeviceImageRobustnessFeatures; -typedef VkPhysicalDeviceImageRobustnessFeatures VkPhysicalDeviceImageRobustnessFeaturesEXT; - -typedef struct VkPhysicalDeviceImageViewImageFormatInfoEXT -{ - VkStructureType sType; - void *pNext; - VkImageViewType imageViewType; -} VkPhysicalDeviceImageViewImageFormatInfoEXT; - -typedef struct VkPhysicalDeviceImageViewMinLodFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 minLod; -} VkPhysicalDeviceImageViewMinLodFeaturesEXT; - -typedef struct VkPhysicalDeviceImagelessFramebufferFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 imagelessFramebuffer; -} VkPhysicalDeviceImagelessFramebufferFeatures; -typedef VkPhysicalDeviceImagelessFramebufferFeatures VkPhysicalDeviceImagelessFramebufferFeaturesKHR; - -typedef struct VkPhysicalDeviceIndexTypeUint8FeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 indexTypeUint8; -} VkPhysicalDeviceIndexTypeUint8FeaturesEXT; - -typedef struct VkPhysicalDeviceInheritedViewportScissorFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 inheritedViewportScissor2D; -} VkPhysicalDeviceInheritedViewportScissorFeaturesNV; - -typedef struct VkPhysicalDeviceInlineUniformBlockFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 inlineUniformBlock; - VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; -} VkPhysicalDeviceInlineUniformBlockFeatures; -typedef VkPhysicalDeviceInlineUniformBlockFeatures VkPhysicalDeviceInlineUniformBlockFeaturesEXT; - -typedef struct VkPhysicalDeviceInlineUniformBlockProperties -{ - VkStructureType sType; - void *pNext; - uint32_t maxInlineUniformBlockSize; - uint32_t maxPerStageDescriptorInlineUniformBlocks; - uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; - uint32_t maxDescriptorSetInlineUniformBlocks; - uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; -} VkPhysicalDeviceInlineUniformBlockProperties; -typedef VkPhysicalDeviceInlineUniformBlockProperties VkPhysicalDeviceInlineUniformBlockPropertiesEXT; - -typedef struct VkPhysicalDeviceInvocationMaskFeaturesHUAWEI -{ - VkStructureType sType; - void *pNext; - VkBool32 invocationMask; -} VkPhysicalDeviceInvocationMaskFeaturesHUAWEI; - -typedef struct VkPhysicalDeviceLegacyDitheringFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 legacyDithering; -} VkPhysicalDeviceLegacyDitheringFeaturesEXT; - -typedef struct VkPhysicalDeviceLimits -{ - uint32_t maxImageDimension1D; - uint32_t maxImageDimension2D; - uint32_t maxImageDimension3D; - uint32_t maxImageDimensionCube; - uint32_t maxImageArrayLayers; - uint32_t maxTexelBufferElements; - uint32_t maxUniformBufferRange; - uint32_t maxStorageBufferRange; - uint32_t maxPushConstantsSize; - uint32_t maxMemoryAllocationCount; - uint32_t maxSamplerAllocationCount; - VkDeviceSize WINE_VK_ALIGN(8) bufferImageGranularity; - VkDeviceSize WINE_VK_ALIGN(8) sparseAddressSpaceSize; - uint32_t maxBoundDescriptorSets; - uint32_t maxPerStageDescriptorSamplers; - uint32_t maxPerStageDescriptorUniformBuffers; - uint32_t maxPerStageDescriptorStorageBuffers; - uint32_t maxPerStageDescriptorSampledImages; - uint32_t maxPerStageDescriptorStorageImages; - uint32_t maxPerStageDescriptorInputAttachments; - uint32_t maxPerStageResources; - uint32_t maxDescriptorSetSamplers; - uint32_t maxDescriptorSetUniformBuffers; - uint32_t maxDescriptorSetUniformBuffersDynamic; - uint32_t maxDescriptorSetStorageBuffers; - uint32_t maxDescriptorSetStorageBuffersDynamic; - uint32_t maxDescriptorSetSampledImages; - uint32_t maxDescriptorSetStorageImages; - uint32_t maxDescriptorSetInputAttachments; - uint32_t maxVertexInputAttributes; - uint32_t maxVertexInputBindings; - uint32_t maxVertexInputAttributeOffset; - uint32_t maxVertexInputBindingStride; - uint32_t maxVertexOutputComponents; - uint32_t maxTessellationGenerationLevel; - uint32_t maxTessellationPatchSize; - uint32_t maxTessellationControlPerVertexInputComponents; - uint32_t maxTessellationControlPerVertexOutputComponents; - uint32_t maxTessellationControlPerPatchOutputComponents; - uint32_t maxTessellationControlTotalOutputComponents; - uint32_t maxTessellationEvaluationInputComponents; - uint32_t maxTessellationEvaluationOutputComponents; - uint32_t maxGeometryShaderInvocations; - uint32_t maxGeometryInputComponents; - uint32_t maxGeometryOutputComponents; - uint32_t maxGeometryOutputVertices; - uint32_t maxGeometryTotalOutputComponents; - uint32_t maxFragmentInputComponents; - uint32_t maxFragmentOutputAttachments; - uint32_t maxFragmentDualSrcAttachments; - uint32_t maxFragmentCombinedOutputResources; - uint32_t maxComputeSharedMemorySize; - uint32_t maxComputeWorkGroupCount[3]; - uint32_t maxComputeWorkGroupInvocations; - uint32_t maxComputeWorkGroupSize[3]; - uint32_t subPixelPrecisionBits; - uint32_t subTexelPrecisionBits; - uint32_t mipmapPrecisionBits; - uint32_t maxDrawIndexedIndexValue; - uint32_t maxDrawIndirectCount; - float maxSamplerLodBias; - float maxSamplerAnisotropy; - uint32_t maxViewports; - uint32_t maxViewportDimensions[2]; - float viewportBoundsRange[2]; - uint32_t viewportSubPixelBits; - size_t minMemoryMapAlignment; - VkDeviceSize WINE_VK_ALIGN(8) minTexelBufferOffsetAlignment; - VkDeviceSize WINE_VK_ALIGN(8) minUniformBufferOffsetAlignment; - VkDeviceSize WINE_VK_ALIGN(8) minStorageBufferOffsetAlignment; - int32_t minTexelOffset; - uint32_t maxTexelOffset; - int32_t minTexelGatherOffset; - uint32_t maxTexelGatherOffset; - float minInterpolationOffset; - float maxInterpolationOffset; - uint32_t subPixelInterpolationOffsetBits; - uint32_t maxFramebufferWidth; - uint32_t maxFramebufferHeight; - uint32_t maxFramebufferLayers; - VkSampleCountFlags framebufferColorSampleCounts; - VkSampleCountFlags framebufferDepthSampleCounts; - VkSampleCountFlags framebufferStencilSampleCounts; - VkSampleCountFlags framebufferNoAttachmentsSampleCounts; - uint32_t maxColorAttachments; - VkSampleCountFlags sampledImageColorSampleCounts; - VkSampleCountFlags sampledImageIntegerSampleCounts; - VkSampleCountFlags sampledImageDepthSampleCounts; - VkSampleCountFlags sampledImageStencilSampleCounts; - VkSampleCountFlags storageImageSampleCounts; - uint32_t maxSampleMaskWords; - VkBool32 timestampComputeAndGraphics; - float timestampPeriod; - uint32_t maxClipDistances; - uint32_t maxCullDistances; - uint32_t maxCombinedClipAndCullDistances; - uint32_t discreteQueuePriorities; - float pointSizeRange[2]; - float lineWidthRange[2]; - float pointSizeGranularity; - float lineWidthGranularity; - VkBool32 strictLines; - VkBool32 standardSampleLocations; - VkDeviceSize WINE_VK_ALIGN(8) optimalBufferCopyOffsetAlignment; - VkDeviceSize WINE_VK_ALIGN(8) optimalBufferCopyRowPitchAlignment; - VkDeviceSize WINE_VK_ALIGN(8) nonCoherentAtomSize; -} VkPhysicalDeviceLimits; - -typedef struct VkPhysicalDeviceLineRasterizationFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 rectangularLines; - VkBool32 bresenhamLines; - VkBool32 smoothLines; - VkBool32 stippledRectangularLines; - VkBool32 stippledBresenhamLines; - VkBool32 stippledSmoothLines; -} VkPhysicalDeviceLineRasterizationFeaturesEXT; - -typedef struct VkPhysicalDeviceLineRasterizationPropertiesEXT -{ - VkStructureType sType; - void *pNext; - uint32_t lineSubPixelPrecisionBits; -} VkPhysicalDeviceLineRasterizationPropertiesEXT; - -typedef struct VkPhysicalDeviceLinearColorAttachmentFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 linearColorAttachment; -} VkPhysicalDeviceLinearColorAttachmentFeaturesNV; - -typedef struct VkPhysicalDeviceMaintenance3Properties -{ - VkStructureType sType; - void *pNext; - uint32_t maxPerSetDescriptors; - VkDeviceSize WINE_VK_ALIGN(8) maxMemoryAllocationSize; -} VkPhysicalDeviceMaintenance3Properties; -typedef VkPhysicalDeviceMaintenance3Properties VkPhysicalDeviceMaintenance3PropertiesKHR; - -typedef struct VkPhysicalDeviceMaintenance4Features -{ - VkStructureType sType; - void *pNext; - VkBool32 maintenance4; -} VkPhysicalDeviceMaintenance4Features; -typedef VkPhysicalDeviceMaintenance4Features VkPhysicalDeviceMaintenance4FeaturesKHR; - -typedef struct VkPhysicalDeviceMaintenance4Properties -{ - VkStructureType sType; - void *pNext; - VkDeviceSize WINE_VK_ALIGN(8) maxBufferSize; -} VkPhysicalDeviceMaintenance4Properties; -typedef VkPhysicalDeviceMaintenance4Properties VkPhysicalDeviceMaintenance4PropertiesKHR; - -typedef struct VkPhysicalDeviceMemoryBudgetPropertiesEXT -{ - VkStructureType sType; - void *pNext; - VkDeviceSize WINE_VK_ALIGN(8) heapBudget[VK_MAX_MEMORY_HEAPS]; - VkDeviceSize WINE_VK_ALIGN(8) heapUsage[VK_MAX_MEMORY_HEAPS]; -} VkPhysicalDeviceMemoryBudgetPropertiesEXT; - -typedef struct VkPhysicalDeviceMemoryDecompressionFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 memoryDecompression; -} VkPhysicalDeviceMemoryDecompressionFeaturesNV; - -typedef struct VkPhysicalDeviceMemoryDecompressionPropertiesNV -{ - VkStructureType sType; - void *pNext; - VkMemoryDecompressionMethodFlagsNV WINE_VK_ALIGN(8) decompressionMethods; - uint64_t WINE_VK_ALIGN(8) maxDecompressionIndirectCount; -} VkPhysicalDeviceMemoryDecompressionPropertiesNV; - -typedef struct VkPhysicalDeviceMemoryPriorityFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 memoryPriority; -} VkPhysicalDeviceMemoryPriorityFeaturesEXT; - -typedef struct VkPhysicalDeviceMemoryProperties -{ - uint32_t memoryTypeCount; - VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES]; - uint32_t memoryHeapCount; - VkMemoryHeap WINE_VK_ALIGN(8) memoryHeaps[VK_MAX_MEMORY_HEAPS]; -} VkPhysicalDeviceMemoryProperties; - -typedef struct VkPhysicalDeviceMemoryProperties2 -{ - VkStructureType sType; - void *pNext; - VkPhysicalDeviceMemoryProperties WINE_VK_ALIGN(8) memoryProperties; -} VkPhysicalDeviceMemoryProperties2; -typedef VkPhysicalDeviceMemoryProperties2 VkPhysicalDeviceMemoryProperties2KHR; - -typedef struct VkPhysicalDeviceMeshShaderFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 taskShader; - VkBool32 meshShader; - VkBool32 multiviewMeshShader; - VkBool32 primitiveFragmentShadingRateMeshShader; - VkBool32 meshShaderQueries; -} VkPhysicalDeviceMeshShaderFeaturesEXT; - -typedef struct VkPhysicalDeviceMeshShaderFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 taskShader; - VkBool32 meshShader; -} VkPhysicalDeviceMeshShaderFeaturesNV; - -typedef struct VkPhysicalDeviceMeshShaderPropertiesEXT -{ - VkStructureType sType; - void *pNext; - uint32_t maxTaskWorkGroupTotalCount; - uint32_t maxTaskWorkGroupCount[3]; - uint32_t maxTaskWorkGroupInvocations; - uint32_t maxTaskWorkGroupSize[3]; - uint32_t maxTaskPayloadSize; - uint32_t maxTaskSharedMemorySize; - uint32_t maxTaskPayloadAndSharedMemorySize; - uint32_t maxMeshWorkGroupTotalCount; - uint32_t maxMeshWorkGroupCount[3]; - uint32_t maxMeshWorkGroupInvocations; - uint32_t maxMeshWorkGroupSize[3]; - uint32_t maxMeshSharedMemorySize; - uint32_t maxMeshPayloadAndSharedMemorySize; - uint32_t maxMeshOutputMemorySize; - uint32_t maxMeshPayloadAndOutputMemorySize; - uint32_t maxMeshOutputComponents; - uint32_t maxMeshOutputVertices; - uint32_t maxMeshOutputPrimitives; - uint32_t maxMeshOutputLayers; - uint32_t maxMeshMultiviewViewCount; - uint32_t meshOutputPerVertexGranularity; - uint32_t meshOutputPerPrimitiveGranularity; - uint32_t maxPreferredTaskWorkGroupInvocations; - uint32_t maxPreferredMeshWorkGroupInvocations; - VkBool32 prefersLocalInvocationVertexOutput; - VkBool32 prefersLocalInvocationPrimitiveOutput; - VkBool32 prefersCompactVertexOutput; - VkBool32 prefersCompactPrimitiveOutput; -} VkPhysicalDeviceMeshShaderPropertiesEXT; - -typedef struct VkPhysicalDeviceMeshShaderPropertiesNV -{ - VkStructureType sType; - void *pNext; - uint32_t maxDrawMeshTasksCount; - uint32_t maxTaskWorkGroupInvocations; - uint32_t maxTaskWorkGroupSize[3]; - uint32_t maxTaskTotalMemorySize; - uint32_t maxTaskOutputCount; - uint32_t maxMeshWorkGroupInvocations; - uint32_t maxMeshWorkGroupSize[3]; - uint32_t maxMeshTotalMemorySize; - uint32_t maxMeshOutputVertices; - uint32_t maxMeshOutputPrimitives; - uint32_t maxMeshMultiviewViewCount; - uint32_t meshOutputPerVertexGranularity; - uint32_t meshOutputPerPrimitiveGranularity; -} VkPhysicalDeviceMeshShaderPropertiesNV; - -typedef struct VkPhysicalDeviceMultiDrawFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 multiDraw; -} VkPhysicalDeviceMultiDrawFeaturesEXT; - -typedef struct VkPhysicalDeviceMultiDrawPropertiesEXT -{ - VkStructureType sType; - void *pNext; - uint32_t maxMultiDrawCount; -} VkPhysicalDeviceMultiDrawPropertiesEXT; - -typedef struct VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 multisampledRenderToSingleSampled; -} VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT; - -typedef struct VkPhysicalDeviceMultiviewFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 multiview; - VkBool32 multiviewGeometryShader; - VkBool32 multiviewTessellationShader; -} VkPhysicalDeviceMultiviewFeatures; -typedef VkPhysicalDeviceMultiviewFeatures VkPhysicalDeviceMultiviewFeaturesKHR; - -typedef struct VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM -{ - VkStructureType sType; - void *pNext; - VkBool32 multiviewPerViewViewports; -} VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM; - -typedef struct VkPhysicalDeviceMultiviewProperties -{ - VkStructureType sType; - void *pNext; - uint32_t maxMultiviewViewCount; - uint32_t maxMultiviewInstanceIndex; -} VkPhysicalDeviceMultiviewProperties; -typedef VkPhysicalDeviceMultiviewProperties VkPhysicalDeviceMultiviewPropertiesKHR; - -typedef struct VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 mutableDescriptorType; -} VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT; -typedef VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT VkPhysicalDeviceMutableDescriptorTypeFeaturesVALVE; - -typedef struct VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 nonSeamlessCubeMap; -} VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT; - -typedef struct VkPhysicalDeviceOpacityMicromapFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 micromap; - VkBool32 micromapCaptureReplay; - VkBool32 micromapHostCommands; -} VkPhysicalDeviceOpacityMicromapFeaturesEXT; - -typedef struct VkPhysicalDeviceOpacityMicromapPropertiesEXT -{ - VkStructureType sType; - void *pNext; - uint32_t maxOpacity2StateSubdivisionLevel; - uint32_t maxOpacity4StateSubdivisionLevel; -} VkPhysicalDeviceOpacityMicromapPropertiesEXT; - -typedef struct VkPhysicalDeviceOpticalFlowFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 opticalFlow; -} VkPhysicalDeviceOpticalFlowFeaturesNV; - -typedef struct VkPhysicalDeviceOpticalFlowPropertiesNV -{ - VkStructureType sType; - void *pNext; - VkOpticalFlowGridSizeFlagsNV supportedOutputGridSizes; - VkOpticalFlowGridSizeFlagsNV supportedHintGridSizes; - VkBool32 hintSupported; - VkBool32 costSupported; - VkBool32 bidirectionalFlowSupported; - VkBool32 globalFlowSupported; - uint32_t minWidth; - uint32_t minHeight; - uint32_t maxWidth; - uint32_t maxHeight; - uint32_t maxNumRegionsOfInterest; -} VkPhysicalDeviceOpticalFlowPropertiesNV; - -typedef struct VkPhysicalDevicePCIBusInfoPropertiesEXT -{ - VkStructureType sType; - void *pNext; - uint32_t pciDomain; - uint32_t pciBus; - uint32_t pciDevice; - uint32_t pciFunction; -} VkPhysicalDevicePCIBusInfoPropertiesEXT; - -typedef struct VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 pageableDeviceLocalMemory; -} VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT; - -typedef struct VkPhysicalDevicePerformanceQueryFeaturesKHR -{ - VkStructureType sType; - void *pNext; - VkBool32 performanceCounterQueryPools; - VkBool32 performanceCounterMultipleQueryPools; -} VkPhysicalDevicePerformanceQueryFeaturesKHR; - -typedef struct VkPhysicalDevicePerformanceQueryPropertiesKHR -{ - VkStructureType sType; - void *pNext; - VkBool32 allowCommandBufferQueryCopies; -} VkPhysicalDevicePerformanceQueryPropertiesKHR; - -typedef struct VkPhysicalDevicePipelineCreationCacheControlFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 pipelineCreationCacheControl; -} VkPhysicalDevicePipelineCreationCacheControlFeatures; -typedef VkPhysicalDevicePipelineCreationCacheControlFeatures VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT; - -typedef struct VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR -{ - VkStructureType sType; - void *pNext; - VkBool32 pipelineExecutableInfo; -} VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR; - -typedef struct VkPhysicalDevicePipelinePropertiesFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 pipelinePropertiesIdentifier; -} VkPhysicalDevicePipelinePropertiesFeaturesEXT; - -typedef struct VkPhysicalDevicePipelineProtectedAccessFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 pipelineProtectedAccess; -} VkPhysicalDevicePipelineProtectedAccessFeaturesEXT; - -typedef struct VkPhysicalDevicePipelineRobustnessFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 pipelineRobustness; -} VkPhysicalDevicePipelineRobustnessFeaturesEXT; - -typedef struct VkPhysicalDevicePipelineRobustnessPropertiesEXT -{ - VkStructureType sType; - void *pNext; - VkPipelineRobustnessBufferBehaviorEXT defaultRobustnessStorageBuffers; - VkPipelineRobustnessBufferBehaviorEXT defaultRobustnessUniformBuffers; - VkPipelineRobustnessBufferBehaviorEXT defaultRobustnessVertexInputs; - VkPipelineRobustnessImageBehaviorEXT defaultRobustnessImages; -} VkPhysicalDevicePipelineRobustnessPropertiesEXT; - -typedef struct VkPhysicalDevicePointClippingProperties -{ - VkStructureType sType; - void *pNext; - VkPointClippingBehavior pointClippingBehavior; -} VkPhysicalDevicePointClippingProperties; -typedef VkPhysicalDevicePointClippingProperties VkPhysicalDevicePointClippingPropertiesKHR; - -typedef struct VkPhysicalDevicePresentBarrierFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 presentBarrier; -} VkPhysicalDevicePresentBarrierFeaturesNV; - -typedef struct VkPhysicalDevicePresentIdFeaturesKHR -{ - VkStructureType sType; - void *pNext; - VkBool32 presentId; -} VkPhysicalDevicePresentIdFeaturesKHR; - -typedef struct VkPhysicalDevicePresentWaitFeaturesKHR -{ - VkStructureType sType; - void *pNext; - VkBool32 presentWait; -} VkPhysicalDevicePresentWaitFeaturesKHR; - -typedef struct VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 primitiveTopologyListRestart; - VkBool32 primitiveTopologyPatchListRestart; -} VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT; - -typedef struct VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 primitivesGeneratedQuery; - VkBool32 primitivesGeneratedQueryWithRasterizerDiscard; - VkBool32 primitivesGeneratedQueryWithNonZeroStreams; -} VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT; - -typedef struct VkPhysicalDevicePrivateDataFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 privateData; -} VkPhysicalDevicePrivateDataFeatures; -typedef VkPhysicalDevicePrivateDataFeatures VkPhysicalDevicePrivateDataFeaturesEXT; - -typedef struct VkPhysicalDeviceProtectedMemoryFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 protectedMemory; -} VkPhysicalDeviceProtectedMemoryFeatures; - -typedef struct VkPhysicalDeviceProtectedMemoryProperties -{ - VkStructureType sType; - void *pNext; - VkBool32 protectedNoFault; -} VkPhysicalDeviceProtectedMemoryProperties; - -typedef struct VkPhysicalDeviceProvokingVertexFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 provokingVertexLast; - VkBool32 transformFeedbackPreservesProvokingVertex; -} VkPhysicalDeviceProvokingVertexFeaturesEXT; - -typedef struct VkPhysicalDeviceProvokingVertexPropertiesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 provokingVertexModePerPipeline; - VkBool32 transformFeedbackPreservesTriangleFanProvokingVertex; -} VkPhysicalDeviceProvokingVertexPropertiesEXT; - -typedef struct VkPhysicalDevicePushDescriptorPropertiesKHR -{ - VkStructureType sType; - void *pNext; - uint32_t maxPushDescriptors; -} VkPhysicalDevicePushDescriptorPropertiesKHR; - -typedef struct VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 formatRgba10x6WithoutYCbCrSampler; -} VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT; - -typedef struct VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 rasterizationOrderColorAttachmentAccess; - VkBool32 rasterizationOrderDepthAttachmentAccess; - VkBool32 rasterizationOrderStencilAttachmentAccess; -} VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT; -typedef VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM; - -typedef struct VkPhysicalDeviceRayQueryFeaturesKHR -{ - VkStructureType sType; - void *pNext; - VkBool32 rayQuery; -} VkPhysicalDeviceRayQueryFeaturesKHR; - -typedef struct VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 rayTracingInvocationReorder; -} VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV; - -typedef struct VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV -{ - VkStructureType sType; - void *pNext; - VkRayTracingInvocationReorderModeNV rayTracingInvocationReorderReorderingHint; -} VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV; - -typedef struct VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR -{ - VkStructureType sType; - void *pNext; - VkBool32 rayTracingMaintenance1; - VkBool32 rayTracingPipelineTraceRaysIndirect2; -} VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR; - -typedef struct VkPhysicalDeviceRayTracingMotionBlurFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 rayTracingMotionBlur; - VkBool32 rayTracingMotionBlurPipelineTraceRaysIndirect; -} VkPhysicalDeviceRayTracingMotionBlurFeaturesNV; - -typedef struct VkPhysicalDeviceRayTracingPipelineFeaturesKHR -{ - VkStructureType sType; - void *pNext; - VkBool32 rayTracingPipeline; - VkBool32 rayTracingPipelineShaderGroupHandleCaptureReplay; - VkBool32 rayTracingPipelineShaderGroupHandleCaptureReplayMixed; - VkBool32 rayTracingPipelineTraceRaysIndirect; - VkBool32 rayTraversalPrimitiveCulling; -} VkPhysicalDeviceRayTracingPipelineFeaturesKHR; - -typedef struct VkPhysicalDeviceRayTracingPipelinePropertiesKHR -{ - VkStructureType sType; - void *pNext; - uint32_t shaderGroupHandleSize; - uint32_t maxRayRecursionDepth; - uint32_t maxShaderGroupStride; - uint32_t shaderGroupBaseAlignment; - uint32_t shaderGroupHandleCaptureReplaySize; - uint32_t maxRayDispatchInvocationCount; - uint32_t shaderGroupHandleAlignment; - uint32_t maxRayHitAttributeSize; -} VkPhysicalDeviceRayTracingPipelinePropertiesKHR; - -typedef struct VkPhysicalDeviceRayTracingPropertiesNV -{ - VkStructureType sType; - void *pNext; - uint32_t shaderGroupHandleSize; - uint32_t maxRecursionDepth; - uint32_t maxShaderGroupStride; - uint32_t shaderGroupBaseAlignment; - uint64_t WINE_VK_ALIGN(8) maxGeometryCount; - uint64_t WINE_VK_ALIGN(8) maxInstanceCount; - uint64_t WINE_VK_ALIGN(8) maxTriangleCount; - uint32_t maxDescriptorSetAccelerationStructures; -} VkPhysicalDeviceRayTracingPropertiesNV; - -typedef struct VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 representativeFragmentTest; -} VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV; - -typedef struct VkPhysicalDeviceRobustness2FeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 robustBufferAccess2; - VkBool32 robustImageAccess2; - VkBool32 nullDescriptor; -} VkPhysicalDeviceRobustness2FeaturesEXT; - -typedef struct VkPhysicalDeviceRobustness2PropertiesEXT -{ - VkStructureType sType; - void *pNext; - VkDeviceSize WINE_VK_ALIGN(8) robustStorageBufferAccessSizeAlignment; - VkDeviceSize WINE_VK_ALIGN(8) robustUniformBufferAccessSizeAlignment; -} VkPhysicalDeviceRobustness2PropertiesEXT; - -typedef struct VkPhysicalDeviceSampleLocationsPropertiesEXT -{ - VkStructureType sType; - void *pNext; - VkSampleCountFlags sampleLocationSampleCounts; - VkExtent2D maxSampleLocationGridSize; - float sampleLocationCoordinateRange[2]; - uint32_t sampleLocationSubPixelBits; - VkBool32 variableSampleLocations; -} VkPhysicalDeviceSampleLocationsPropertiesEXT; - -typedef struct VkPhysicalDeviceSamplerFilterMinmaxProperties -{ - VkStructureType sType; - void *pNext; - VkBool32 filterMinmaxSingleComponentFormats; - VkBool32 filterMinmaxImageComponentMapping; -} VkPhysicalDeviceSamplerFilterMinmaxProperties; -typedef VkPhysicalDeviceSamplerFilterMinmaxProperties VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT; - -typedef struct VkPhysicalDeviceSamplerYcbcrConversionFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 samplerYcbcrConversion; -} VkPhysicalDeviceSamplerYcbcrConversionFeatures; -typedef VkPhysicalDeviceSamplerYcbcrConversionFeatures VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR; - -typedef struct VkPhysicalDeviceScalarBlockLayoutFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 scalarBlockLayout; -} VkPhysicalDeviceScalarBlockLayoutFeatures; -typedef VkPhysicalDeviceScalarBlockLayoutFeatures VkPhysicalDeviceScalarBlockLayoutFeaturesEXT; - -typedef struct VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 separateDepthStencilLayouts; -} VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures; -typedef VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR; - -typedef struct VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderBufferFloat16Atomics; - VkBool32 shaderBufferFloat16AtomicAdd; - VkBool32 shaderBufferFloat16AtomicMinMax; - VkBool32 shaderBufferFloat32AtomicMinMax; - VkBool32 shaderBufferFloat64AtomicMinMax; - VkBool32 shaderSharedFloat16Atomics; - VkBool32 shaderSharedFloat16AtomicAdd; - VkBool32 shaderSharedFloat16AtomicMinMax; - VkBool32 shaderSharedFloat32AtomicMinMax; - VkBool32 shaderSharedFloat64AtomicMinMax; - VkBool32 shaderImageFloat32AtomicMinMax; - VkBool32 sparseImageFloat32AtomicMinMax; -} VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT; - -typedef struct VkPhysicalDeviceShaderAtomicFloatFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderBufferFloat32Atomics; - VkBool32 shaderBufferFloat32AtomicAdd; - VkBool32 shaderBufferFloat64Atomics; - VkBool32 shaderBufferFloat64AtomicAdd; - VkBool32 shaderSharedFloat32Atomics; - VkBool32 shaderSharedFloat32AtomicAdd; - VkBool32 shaderSharedFloat64Atomics; - VkBool32 shaderSharedFloat64AtomicAdd; - VkBool32 shaderImageFloat32Atomics; - VkBool32 shaderImageFloat32AtomicAdd; - VkBool32 sparseImageFloat32Atomics; - VkBool32 sparseImageFloat32AtomicAdd; -} VkPhysicalDeviceShaderAtomicFloatFeaturesEXT; - -typedef struct VkPhysicalDeviceShaderAtomicInt64Features -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderBufferInt64Atomics; - VkBool32 shaderSharedInt64Atomics; -} VkPhysicalDeviceShaderAtomicInt64Features; -typedef VkPhysicalDeviceShaderAtomicInt64Features VkPhysicalDeviceShaderAtomicInt64FeaturesKHR; - -typedef struct VkPhysicalDeviceShaderClockFeaturesKHR -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderSubgroupClock; - VkBool32 shaderDeviceClock; -} VkPhysicalDeviceShaderClockFeaturesKHR; - -typedef struct VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderCoreBuiltins; -} VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM; - -typedef struct VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM -{ - VkStructureType sType; - void *pNext; - uint64_t WINE_VK_ALIGN(8) shaderCoreMask; - uint32_t shaderCoreCount; - uint32_t shaderWarpsPerCore; -} VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM; - -typedef struct VkPhysicalDeviceShaderCoreProperties2AMD -{ - VkStructureType sType; - void *pNext; - VkShaderCorePropertiesFlagsAMD shaderCoreFeatures; - uint32_t activeComputeUnitCount; -} VkPhysicalDeviceShaderCoreProperties2AMD; - -typedef struct VkPhysicalDeviceShaderCorePropertiesAMD -{ - VkStructureType sType; - void *pNext; - uint32_t shaderEngineCount; - uint32_t shaderArraysPerEngineCount; - uint32_t computeUnitsPerShaderArray; - uint32_t simdPerComputeUnit; - uint32_t wavefrontsPerSimd; - uint32_t wavefrontSize; - uint32_t sgprsPerSimd; - uint32_t minSgprAllocation; - uint32_t maxSgprAllocation; - uint32_t sgprAllocationGranularity; - uint32_t vgprsPerSimd; - uint32_t minVgprAllocation; - uint32_t maxVgprAllocation; - uint32_t vgprAllocationGranularity; -} VkPhysicalDeviceShaderCorePropertiesAMD; - -typedef struct VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderDemoteToHelperInvocation; -} VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures; -typedef VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT; - - -typedef struct VkPhysicalDeviceShaderDrawParametersFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderDrawParameters; -} VkPhysicalDeviceShaderDrawParametersFeatures; -typedef VkPhysicalDeviceShaderDrawParametersFeatures VkPhysicalDeviceShaderDrawParameterFeatures; - -typedef struct VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderEarlyAndLateFragmentTests; -} VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD; - -typedef struct VkPhysicalDeviceShaderFloat16Int8Features -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderFloat16; - VkBool32 shaderInt8; -} VkPhysicalDeviceShaderFloat16Int8Features; -typedef VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceShaderFloat16Int8FeaturesKHR; -typedef VkPhysicalDeviceShaderFloat16Int8Features VkPhysicalDeviceFloat16Int8FeaturesKHR; - -typedef struct VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderImageInt64Atomics; - VkBool32 sparseImageInt64Atomics; -} VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT; - -typedef struct VkPhysicalDeviceShaderImageFootprintFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 imageFootprint; -} VkPhysicalDeviceShaderImageFootprintFeaturesNV; - -typedef struct VkPhysicalDeviceShaderIntegerDotProductFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderIntegerDotProduct; -} VkPhysicalDeviceShaderIntegerDotProductFeatures; -typedef VkPhysicalDeviceShaderIntegerDotProductFeatures VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR; - -typedef struct VkPhysicalDeviceShaderIntegerDotProductProperties -{ - VkStructureType sType; - void *pNext; - VkBool32 integerDotProduct8BitUnsignedAccelerated; - VkBool32 integerDotProduct8BitSignedAccelerated; - VkBool32 integerDotProduct8BitMixedSignednessAccelerated; - VkBool32 integerDotProduct4x8BitPackedUnsignedAccelerated; - VkBool32 integerDotProduct4x8BitPackedSignedAccelerated; - VkBool32 integerDotProduct4x8BitPackedMixedSignednessAccelerated; - VkBool32 integerDotProduct16BitUnsignedAccelerated; - VkBool32 integerDotProduct16BitSignedAccelerated; - VkBool32 integerDotProduct16BitMixedSignednessAccelerated; - VkBool32 integerDotProduct32BitUnsignedAccelerated; - VkBool32 integerDotProduct32BitSignedAccelerated; - VkBool32 integerDotProduct32BitMixedSignednessAccelerated; - VkBool32 integerDotProduct64BitUnsignedAccelerated; - VkBool32 integerDotProduct64BitSignedAccelerated; - VkBool32 integerDotProduct64BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating8BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating8BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating16BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating16BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating32BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating32BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating64BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating64BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated; -} VkPhysicalDeviceShaderIntegerDotProductProperties; -typedef VkPhysicalDeviceShaderIntegerDotProductProperties VkPhysicalDeviceShaderIntegerDotProductPropertiesKHR; - -typedef struct VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderIntegerFunctions2; -} VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL; - -typedef struct VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderModuleIdentifier; -} VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT; - -typedef struct VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT -{ - VkStructureType sType; - void *pNext; - uint8_t shaderModuleIdentifierAlgorithmUUID[VK_UUID_SIZE]; -} VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT; - -typedef struct VkPhysicalDeviceShaderSMBuiltinsFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderSMBuiltins; -} VkPhysicalDeviceShaderSMBuiltinsFeaturesNV; - -typedef struct VkPhysicalDeviceShaderSMBuiltinsPropertiesNV -{ - VkStructureType sType; - void *pNext; - uint32_t shaderSMCount; - uint32_t shaderWarpsPerSM; -} VkPhysicalDeviceShaderSMBuiltinsPropertiesNV; - -typedef struct VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderSubgroupExtendedTypes; -} VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures; -typedef VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures VkPhysicalDeviceShaderSubgroupExtendedTypesFeaturesKHR; - -typedef struct VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderSubgroupUniformControlFlow; -} VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR; - -typedef struct VkPhysicalDeviceShaderTerminateInvocationFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderTerminateInvocation; -} VkPhysicalDeviceShaderTerminateInvocationFeatures; -typedef VkPhysicalDeviceShaderTerminateInvocationFeatures VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR; - -typedef struct VkPhysicalDeviceShadingRateImageFeaturesNV -{ - VkStructureType sType; - void *pNext; - VkBool32 shadingRateImage; - VkBool32 shadingRateCoarseSampleOrder; -} VkPhysicalDeviceShadingRateImageFeaturesNV; - -typedef struct VkPhysicalDeviceShadingRateImagePropertiesNV -{ - VkStructureType sType; - void *pNext; - VkExtent2D shadingRateTexelSize; - uint32_t shadingRatePaletteSize; - uint32_t shadingRateMaxCoarseSamples; -} VkPhysicalDeviceShadingRateImagePropertiesNV; - -typedef struct VkPhysicalDeviceSparseImageFormatInfo2 -{ - VkStructureType sType; - const void *pNext; - VkFormat format; - VkImageType type; - VkSampleCountFlagBits samples; - VkImageUsageFlags usage; - VkImageTiling tiling; -} VkPhysicalDeviceSparseImageFormatInfo2; -typedef VkPhysicalDeviceSparseImageFormatInfo2 VkPhysicalDeviceSparseImageFormatInfo2KHR; - -typedef struct VkPhysicalDeviceSparseProperties -{ - VkBool32 residencyStandard2DBlockShape; - VkBool32 residencyStandard2DMultisampleBlockShape; - VkBool32 residencyStandard3DBlockShape; - VkBool32 residencyAlignedMipSize; - VkBool32 residencyNonResidentStrict; -} VkPhysicalDeviceSparseProperties; - -typedef struct VkPhysicalDeviceSubgroupProperties -{ - VkStructureType sType; - void *pNext; - uint32_t subgroupSize; - VkShaderStageFlags supportedStages; - VkSubgroupFeatureFlags supportedOperations; - VkBool32 quadOperationsInAllStages; -} VkPhysicalDeviceSubgroupProperties; - -typedef struct VkPhysicalDeviceSubgroupSizeControlFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 subgroupSizeControl; - VkBool32 computeFullSubgroups; -} VkPhysicalDeviceSubgroupSizeControlFeatures; -typedef VkPhysicalDeviceSubgroupSizeControlFeatures VkPhysicalDeviceSubgroupSizeControlFeaturesEXT; - -typedef struct VkPhysicalDeviceSubgroupSizeControlProperties -{ - VkStructureType sType; - void *pNext; - uint32_t minSubgroupSize; - uint32_t maxSubgroupSize; - uint32_t maxComputeWorkgroupSubgroups; - VkShaderStageFlags requiredSubgroupSizeStages; -} VkPhysicalDeviceSubgroupSizeControlProperties; -typedef VkPhysicalDeviceSubgroupSizeControlProperties VkPhysicalDeviceSubgroupSizeControlPropertiesEXT; - -typedef struct VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 subpassMergeFeedback; -} VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT; - -typedef struct VkPhysicalDeviceSubpassShadingFeaturesHUAWEI -{ - VkStructureType sType; - void *pNext; - VkBool32 subpassShading; -} VkPhysicalDeviceSubpassShadingFeaturesHUAWEI; - -typedef struct VkPhysicalDeviceSubpassShadingPropertiesHUAWEI -{ - VkStructureType sType; - void *pNext; - uint32_t maxSubpassShadingWorkgroupSizeAspectRatio; -} VkPhysicalDeviceSubpassShadingPropertiesHUAWEI; - -typedef struct VkPhysicalDeviceSurfaceInfo2KHR -{ - VkStructureType sType; - const void *pNext; - VkSurfaceKHR WINE_VK_ALIGN(8) surface; -} VkPhysicalDeviceSurfaceInfo2KHR; - -typedef struct VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 swapchainMaintenance1; -} VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT; - -typedef struct VkPhysicalDeviceSynchronization2Features -{ - VkStructureType sType; - void *pNext; - VkBool32 synchronization2; -} VkPhysicalDeviceSynchronization2Features; -typedef VkPhysicalDeviceSynchronization2Features VkPhysicalDeviceSynchronization2FeaturesKHR; - -typedef struct VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 texelBufferAlignment; -} VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT; - -typedef struct VkPhysicalDeviceTexelBufferAlignmentProperties -{ - VkStructureType sType; - void *pNext; - VkDeviceSize WINE_VK_ALIGN(8) storageTexelBufferOffsetAlignmentBytes; - VkBool32 storageTexelBufferOffsetSingleTexelAlignment; - VkDeviceSize WINE_VK_ALIGN(8) uniformTexelBufferOffsetAlignmentBytes; - VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; -} VkPhysicalDeviceTexelBufferAlignmentProperties; -typedef VkPhysicalDeviceTexelBufferAlignmentProperties VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT; - -typedef struct VkPhysicalDeviceTextureCompressionASTCHDRFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 textureCompressionASTC_HDR; -} VkPhysicalDeviceTextureCompressionASTCHDRFeatures; -typedef VkPhysicalDeviceTextureCompressionASTCHDRFeatures VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT; - -typedef struct VkPhysicalDeviceTilePropertiesFeaturesQCOM -{ - VkStructureType sType; - void *pNext; - VkBool32 tileProperties; -} VkPhysicalDeviceTilePropertiesFeaturesQCOM; - -typedef struct VkPhysicalDeviceTimelineSemaphoreFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 timelineSemaphore; -} VkPhysicalDeviceTimelineSemaphoreFeatures; -typedef VkPhysicalDeviceTimelineSemaphoreFeatures VkPhysicalDeviceTimelineSemaphoreFeaturesKHR; - -typedef struct VkPhysicalDeviceTimelineSemaphoreProperties -{ - VkStructureType sType; - void *pNext; - uint64_t WINE_VK_ALIGN(8) maxTimelineSemaphoreValueDifference; -} VkPhysicalDeviceTimelineSemaphoreProperties; -typedef VkPhysicalDeviceTimelineSemaphoreProperties VkPhysicalDeviceTimelineSemaphorePropertiesKHR; - -typedef struct VkPhysicalDeviceToolProperties -{ - VkStructureType sType; - void *pNext; - char name[VK_MAX_EXTENSION_NAME_SIZE]; - char version[VK_MAX_EXTENSION_NAME_SIZE]; - VkToolPurposeFlags purposes; - char description[VK_MAX_DESCRIPTION_SIZE]; - char layer[VK_MAX_EXTENSION_NAME_SIZE]; -} VkPhysicalDeviceToolProperties; -typedef VkPhysicalDeviceToolProperties VkPhysicalDeviceToolPropertiesEXT; - -typedef struct VkPhysicalDeviceTransformFeedbackFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 transformFeedback; - VkBool32 geometryStreams; -} VkPhysicalDeviceTransformFeedbackFeaturesEXT; - -typedef struct VkPhysicalDeviceTransformFeedbackPropertiesEXT -{ - VkStructureType sType; - void *pNext; - uint32_t maxTransformFeedbackStreams; - uint32_t maxTransformFeedbackBuffers; - VkDeviceSize WINE_VK_ALIGN(8) maxTransformFeedbackBufferSize; - uint32_t maxTransformFeedbackStreamDataSize; - uint32_t maxTransformFeedbackBufferDataSize; - uint32_t maxTransformFeedbackBufferDataStride; - VkBool32 transformFeedbackQueries; - VkBool32 transformFeedbackStreamsLinesTriangles; - VkBool32 transformFeedbackRasterizationStreamSelect; - VkBool32 transformFeedbackDraw; -} VkPhysicalDeviceTransformFeedbackPropertiesEXT; - -typedef struct VkPhysicalDeviceUniformBufferStandardLayoutFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 uniformBufferStandardLayout; -} VkPhysicalDeviceUniformBufferStandardLayoutFeatures; -typedef VkPhysicalDeviceUniformBufferStandardLayoutFeatures VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR; - - -typedef struct VkPhysicalDeviceVariablePointersFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 variablePointersStorageBuffer; - VkBool32 variablePointers; -} VkPhysicalDeviceVariablePointersFeatures; -typedef VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointersFeaturesKHR; -typedef VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeaturesKHR; -typedef VkPhysicalDeviceVariablePointersFeatures VkPhysicalDeviceVariablePointerFeatures; - -typedef struct VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 vertexAttributeInstanceRateDivisor; - VkBool32 vertexAttributeInstanceRateZeroDivisor; -} VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT; - -typedef struct VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT -{ - VkStructureType sType; - void *pNext; - uint32_t maxVertexAttribDivisor; -} VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT; - -typedef struct VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 vertexInputDynamicState; -} VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT; - -typedef struct VkPhysicalDeviceVulkan11Features -{ - VkStructureType sType; - void *pNext; - VkBool32 storageBuffer16BitAccess; - VkBool32 uniformAndStorageBuffer16BitAccess; - VkBool32 storagePushConstant16; - VkBool32 storageInputOutput16; - VkBool32 multiview; - VkBool32 multiviewGeometryShader; - VkBool32 multiviewTessellationShader; - VkBool32 variablePointersStorageBuffer; - VkBool32 variablePointers; - VkBool32 protectedMemory; - VkBool32 samplerYcbcrConversion; - VkBool32 shaderDrawParameters; -} VkPhysicalDeviceVulkan11Features; - -typedef struct VkPhysicalDeviceVulkan11Properties -{ - VkStructureType sType; - void *pNext; - uint8_t deviceUUID[VK_UUID_SIZE]; - uint8_t driverUUID[VK_UUID_SIZE]; - uint8_t deviceLUID[VK_LUID_SIZE]; - uint32_t deviceNodeMask; - VkBool32 deviceLUIDValid; - uint32_t subgroupSize; - VkShaderStageFlags subgroupSupportedStages; - VkSubgroupFeatureFlags subgroupSupportedOperations; - VkBool32 subgroupQuadOperationsInAllStages; - VkPointClippingBehavior pointClippingBehavior; - uint32_t maxMultiviewViewCount; - uint32_t maxMultiviewInstanceIndex; - VkBool32 protectedNoFault; - uint32_t maxPerSetDescriptors; - VkDeviceSize WINE_VK_ALIGN(8) maxMemoryAllocationSize; -} VkPhysicalDeviceVulkan11Properties; - -typedef struct VkPhysicalDeviceVulkan12Features -{ - VkStructureType sType; - void *pNext; - VkBool32 samplerMirrorClampToEdge; - VkBool32 drawIndirectCount; - VkBool32 storageBuffer8BitAccess; - VkBool32 uniformAndStorageBuffer8BitAccess; - VkBool32 storagePushConstant8; - VkBool32 shaderBufferInt64Atomics; - VkBool32 shaderSharedInt64Atomics; - VkBool32 shaderFloat16; - VkBool32 shaderInt8; - VkBool32 descriptorIndexing; - VkBool32 shaderInputAttachmentArrayDynamicIndexing; - VkBool32 shaderUniformTexelBufferArrayDynamicIndexing; - VkBool32 shaderStorageTexelBufferArrayDynamicIndexing; - VkBool32 shaderUniformBufferArrayNonUniformIndexing; - VkBool32 shaderSampledImageArrayNonUniformIndexing; - VkBool32 shaderStorageBufferArrayNonUniformIndexing; - VkBool32 shaderStorageImageArrayNonUniformIndexing; - VkBool32 shaderInputAttachmentArrayNonUniformIndexing; - VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing; - VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing; - VkBool32 descriptorBindingUniformBufferUpdateAfterBind; - VkBool32 descriptorBindingSampledImageUpdateAfterBind; - VkBool32 descriptorBindingStorageImageUpdateAfterBind; - VkBool32 descriptorBindingStorageBufferUpdateAfterBind; - VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind; - VkBool32 descriptorBindingUpdateUnusedWhilePending; - VkBool32 descriptorBindingPartiallyBound; - VkBool32 descriptorBindingVariableDescriptorCount; - VkBool32 runtimeDescriptorArray; - VkBool32 samplerFilterMinmax; - VkBool32 scalarBlockLayout; - VkBool32 imagelessFramebuffer; - VkBool32 uniformBufferStandardLayout; - VkBool32 shaderSubgroupExtendedTypes; - VkBool32 separateDepthStencilLayouts; - VkBool32 hostQueryReset; - VkBool32 timelineSemaphore; - VkBool32 bufferDeviceAddress; - VkBool32 bufferDeviceAddressCaptureReplay; - VkBool32 bufferDeviceAddressMultiDevice; - VkBool32 vulkanMemoryModel; - VkBool32 vulkanMemoryModelDeviceScope; - VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; - VkBool32 shaderOutputViewportIndex; - VkBool32 shaderOutputLayer; - VkBool32 subgroupBroadcastDynamicId; -} VkPhysicalDeviceVulkan12Features; - -typedef struct VkPhysicalDeviceVulkan12Properties -{ - VkStructureType sType; - void *pNext; - VkDriverId driverID; - char driverName[VK_MAX_DRIVER_NAME_SIZE]; - char driverInfo[VK_MAX_DRIVER_INFO_SIZE]; - VkConformanceVersion conformanceVersion; - VkShaderFloatControlsIndependence denormBehaviorIndependence; - VkShaderFloatControlsIndependence roundingModeIndependence; - VkBool32 shaderSignedZeroInfNanPreserveFloat16; - VkBool32 shaderSignedZeroInfNanPreserveFloat32; - VkBool32 shaderSignedZeroInfNanPreserveFloat64; - VkBool32 shaderDenormPreserveFloat16; - VkBool32 shaderDenormPreserveFloat32; - VkBool32 shaderDenormPreserveFloat64; - VkBool32 shaderDenormFlushToZeroFloat16; - VkBool32 shaderDenormFlushToZeroFloat32; - VkBool32 shaderDenormFlushToZeroFloat64; - VkBool32 shaderRoundingModeRTEFloat16; - VkBool32 shaderRoundingModeRTEFloat32; - VkBool32 shaderRoundingModeRTEFloat64; - VkBool32 shaderRoundingModeRTZFloat16; - VkBool32 shaderRoundingModeRTZFloat32; - VkBool32 shaderRoundingModeRTZFloat64; - uint32_t maxUpdateAfterBindDescriptorsInAllPools; - VkBool32 shaderUniformBufferArrayNonUniformIndexingNative; - VkBool32 shaderSampledImageArrayNonUniformIndexingNative; - VkBool32 shaderStorageBufferArrayNonUniformIndexingNative; - VkBool32 shaderStorageImageArrayNonUniformIndexingNative; - VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative; - VkBool32 robustBufferAccessUpdateAfterBind; - VkBool32 quadDivergentImplicitLod; - uint32_t maxPerStageDescriptorUpdateAfterBindSamplers; - uint32_t maxPerStageDescriptorUpdateAfterBindUniformBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageBuffers; - uint32_t maxPerStageDescriptorUpdateAfterBindSampledImages; - uint32_t maxPerStageDescriptorUpdateAfterBindStorageImages; - uint32_t maxPerStageDescriptorUpdateAfterBindInputAttachments; - uint32_t maxPerStageUpdateAfterBindResources; - uint32_t maxDescriptorSetUpdateAfterBindSamplers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffers; - uint32_t maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffers; - uint32_t maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; - uint32_t maxDescriptorSetUpdateAfterBindSampledImages; - uint32_t maxDescriptorSetUpdateAfterBindStorageImages; - uint32_t maxDescriptorSetUpdateAfterBindInputAttachments; - VkResolveModeFlags supportedDepthResolveModes; - VkResolveModeFlags supportedStencilResolveModes; - VkBool32 independentResolveNone; - VkBool32 independentResolve; - VkBool32 filterMinmaxSingleComponentFormats; - VkBool32 filterMinmaxImageComponentMapping; - uint64_t WINE_VK_ALIGN(8) maxTimelineSemaphoreValueDifference; - VkSampleCountFlags framebufferIntegerColorSampleCounts; -} VkPhysicalDeviceVulkan12Properties; - -typedef struct VkPhysicalDeviceVulkan13Features -{ - VkStructureType sType; - void *pNext; - VkBool32 robustImageAccess; - VkBool32 inlineUniformBlock; - VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind; - VkBool32 pipelineCreationCacheControl; - VkBool32 privateData; - VkBool32 shaderDemoteToHelperInvocation; - VkBool32 shaderTerminateInvocation; - VkBool32 subgroupSizeControl; - VkBool32 computeFullSubgroups; - VkBool32 synchronization2; - VkBool32 textureCompressionASTC_HDR; - VkBool32 shaderZeroInitializeWorkgroupMemory; - VkBool32 dynamicRendering; - VkBool32 shaderIntegerDotProduct; - VkBool32 maintenance4; -} VkPhysicalDeviceVulkan13Features; - -typedef struct VkPhysicalDeviceVulkan13Properties -{ - VkStructureType sType; - void *pNext; - uint32_t minSubgroupSize; - uint32_t maxSubgroupSize; - uint32_t maxComputeWorkgroupSubgroups; - VkShaderStageFlags requiredSubgroupSizeStages; - uint32_t maxInlineUniformBlockSize; - uint32_t maxPerStageDescriptorInlineUniformBlocks; - uint32_t maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks; - uint32_t maxDescriptorSetInlineUniformBlocks; - uint32_t maxDescriptorSetUpdateAfterBindInlineUniformBlocks; - uint32_t maxInlineUniformTotalSize; - VkBool32 integerDotProduct8BitUnsignedAccelerated; - VkBool32 integerDotProduct8BitSignedAccelerated; - VkBool32 integerDotProduct8BitMixedSignednessAccelerated; - VkBool32 integerDotProduct4x8BitPackedUnsignedAccelerated; - VkBool32 integerDotProduct4x8BitPackedSignedAccelerated; - VkBool32 integerDotProduct4x8BitPackedMixedSignednessAccelerated; - VkBool32 integerDotProduct16BitUnsignedAccelerated; - VkBool32 integerDotProduct16BitSignedAccelerated; - VkBool32 integerDotProduct16BitMixedSignednessAccelerated; - VkBool32 integerDotProduct32BitUnsignedAccelerated; - VkBool32 integerDotProduct32BitSignedAccelerated; - VkBool32 integerDotProduct32BitMixedSignednessAccelerated; - VkBool32 integerDotProduct64BitUnsignedAccelerated; - VkBool32 integerDotProduct64BitSignedAccelerated; - VkBool32 integerDotProduct64BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating8BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating8BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating16BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating16BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating32BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating32BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated; - VkBool32 integerDotProductAccumulatingSaturating64BitUnsignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating64BitSignedAccelerated; - VkBool32 integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated; - VkDeviceSize WINE_VK_ALIGN(8) storageTexelBufferOffsetAlignmentBytes; - VkBool32 storageTexelBufferOffsetSingleTexelAlignment; - VkDeviceSize WINE_VK_ALIGN(8) uniformTexelBufferOffsetAlignmentBytes; - VkBool32 uniformTexelBufferOffsetSingleTexelAlignment; - VkDeviceSize WINE_VK_ALIGN(8) maxBufferSize; -} VkPhysicalDeviceVulkan13Properties; - -typedef struct VkPhysicalDeviceVulkanMemoryModelFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 vulkanMemoryModel; - VkBool32 vulkanMemoryModelDeviceScope; - VkBool32 vulkanMemoryModelAvailabilityVisibilityChains; -} VkPhysicalDeviceVulkanMemoryModelFeatures; -typedef VkPhysicalDeviceVulkanMemoryModelFeatures VkPhysicalDeviceVulkanMemoryModelFeaturesKHR; - -typedef struct VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR -{ - VkStructureType sType; - void *pNext; - VkBool32 workgroupMemoryExplicitLayout; - VkBool32 workgroupMemoryExplicitLayoutScalarBlockLayout; - VkBool32 workgroupMemoryExplicitLayout8BitAccess; - VkBool32 workgroupMemoryExplicitLayout16BitAccess; -} VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR; - -typedef struct VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 ycbcr2plane444Formats; -} VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT; - -typedef struct VkPhysicalDeviceYcbcrImageArraysFeaturesEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 ycbcrImageArrays; -} VkPhysicalDeviceYcbcrImageArraysFeaturesEXT; - -typedef struct VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures -{ - VkStructureType sType; - void *pNext; - VkBool32 shaderZeroInitializeWorkgroupMemory; -} VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures; -typedef VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR; - -typedef struct VkPipelineCacheCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkPipelineCacheCreateFlags flags; - size_t initialDataSize; - const void *pInitialData; -} VkPipelineCacheCreateInfo; - -typedef struct VkPipelineCacheHeaderVersionOne -{ - uint32_t headerSize; - VkPipelineCacheHeaderVersion headerVersion; - uint32_t vendorID; - uint32_t deviceID; - uint8_t pipelineCacheUUID[VK_UUID_SIZE]; -} VkPipelineCacheHeaderVersionOne; - -typedef struct VkPipelineColorBlendAdvancedStateCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkBool32 srcPremultiplied; - VkBool32 dstPremultiplied; - VkBlendOverlapEXT blendOverlap; -} VkPipelineColorBlendAdvancedStateCreateInfoEXT; - -typedef struct VkPipelineColorBlendAttachmentState -{ - VkBool32 blendEnable; - VkBlendFactor srcColorBlendFactor; - VkBlendFactor dstColorBlendFactor; - VkBlendOp colorBlendOp; - VkBlendFactor srcAlphaBlendFactor; - VkBlendFactor dstAlphaBlendFactor; - VkBlendOp alphaBlendOp; - VkColorComponentFlags colorWriteMask; -} VkPipelineColorBlendAttachmentState; - -typedef struct VkPipelineColorBlendStateCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkPipelineColorBlendStateCreateFlags flags; - VkBool32 logicOpEnable; - VkLogicOp logicOp; - uint32_t attachmentCount; - const VkPipelineColorBlendAttachmentState *pAttachments; - float blendConstants[4]; -} VkPipelineColorBlendStateCreateInfo; - -typedef struct VkPipelineColorWriteCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - uint32_t attachmentCount; - const VkBool32 *pColorWriteEnables; -} VkPipelineColorWriteCreateInfoEXT; - -typedef struct VkPipelineCompilerControlCreateInfoAMD -{ - VkStructureType sType; - const void *pNext; - VkPipelineCompilerControlFlagsAMD compilerControlFlags; -} VkPipelineCompilerControlCreateInfoAMD; - -typedef struct VkPipelineCoverageModulationStateCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - VkPipelineCoverageModulationStateCreateFlagsNV flags; - VkCoverageModulationModeNV coverageModulationMode; - VkBool32 coverageModulationTableEnable; - uint32_t coverageModulationTableCount; - const float *pCoverageModulationTable; -} VkPipelineCoverageModulationStateCreateInfoNV; - -typedef struct VkPipelineCoverageReductionStateCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - VkPipelineCoverageReductionStateCreateFlagsNV flags; - VkCoverageReductionModeNV coverageReductionMode; -} VkPipelineCoverageReductionStateCreateInfoNV; - -typedef struct VkPipelineCoverageToColorStateCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - VkPipelineCoverageToColorStateCreateFlagsNV flags; - VkBool32 coverageToColorEnable; - uint32_t coverageToColorLocation; -} VkPipelineCoverageToColorStateCreateInfoNV; - -typedef struct VkPipelineCreationFeedback -{ - VkPipelineCreationFeedbackFlags flags; - uint64_t WINE_VK_ALIGN(8) duration; -} VkPipelineCreationFeedback; -typedef VkPipelineCreationFeedback VkPipelineCreationFeedbackEXT; - -typedef struct VkPipelineCreationFeedbackCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkPipelineCreationFeedback *pPipelineCreationFeedback; - uint32_t pipelineStageCreationFeedbackCount; - VkPipelineCreationFeedback *pPipelineStageCreationFeedbacks; -} VkPipelineCreationFeedbackCreateInfo; -typedef VkPipelineCreationFeedbackCreateInfo VkPipelineCreationFeedbackCreateInfoEXT; - -typedef struct VkPipelineDynamicStateCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkPipelineDynamicStateCreateFlags flags; - uint32_t dynamicStateCount; - const VkDynamicState *pDynamicStates; -} VkPipelineDynamicStateCreateInfo; - -typedef struct VkPipelineExecutableInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkPipeline WINE_VK_ALIGN(8) pipeline; - uint32_t executableIndex; -} VkPipelineExecutableInfoKHR; - -typedef struct VkPipelineExecutableInternalRepresentationKHR -{ - VkStructureType sType; - void *pNext; - char name[VK_MAX_DESCRIPTION_SIZE]; - char description[VK_MAX_DESCRIPTION_SIZE]; - VkBool32 isText; - size_t dataSize; - void *pData; -} VkPipelineExecutableInternalRepresentationKHR; - -typedef struct VkPipelineExecutablePropertiesKHR -{ - VkStructureType sType; - void *pNext; - VkShaderStageFlags stages; - char name[VK_MAX_DESCRIPTION_SIZE]; - char description[VK_MAX_DESCRIPTION_SIZE]; - uint32_t subgroupSize; -} VkPipelineExecutablePropertiesKHR; - -typedef union VkPipelineExecutableStatisticValueKHR -{ - VkBool32 b32; - int64_t i64; - uint64_t WINE_VK_ALIGN(8) u64; - double f64; -} VkPipelineExecutableStatisticValueKHR; - -typedef struct VkPipelineFragmentShadingRateEnumStateCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - VkFragmentShadingRateTypeNV shadingRateType; - VkFragmentShadingRateNV shadingRate; - VkFragmentShadingRateCombinerOpKHR combinerOps[2]; -} VkPipelineFragmentShadingRateEnumStateCreateInfoNV; - -typedef struct VkPipelineFragmentShadingRateStateCreateInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkExtent2D fragmentSize; - VkFragmentShadingRateCombinerOpKHR combinerOps[2]; -} VkPipelineFragmentShadingRateStateCreateInfoKHR; - - -typedef struct VkPipelineInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkPipeline WINE_VK_ALIGN(8) pipeline; -} VkPipelineInfoKHR; -typedef VkPipelineInfoKHR VkPipelineInfoEXT; - -typedef struct VkPipelineInputAssemblyStateCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkPipelineInputAssemblyStateCreateFlags flags; - VkPrimitiveTopology topology; - VkBool32 primitiveRestartEnable; -} VkPipelineInputAssemblyStateCreateInfo; - -typedef struct VkPipelineLibraryCreateInfoKHR -{ - VkStructureType sType; - const void *pNext; - uint32_t libraryCount; - const VkPipeline *pLibraries; -} VkPipelineLibraryCreateInfoKHR; - -typedef struct VkPipelineMultisampleStateCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkPipelineMultisampleStateCreateFlags flags; - VkSampleCountFlagBits rasterizationSamples; - VkBool32 sampleShadingEnable; - float minSampleShading; - const VkSampleMask *pSampleMask; - VkBool32 alphaToCoverageEnable; - VkBool32 alphaToOneEnable; -} VkPipelineMultisampleStateCreateInfo; - -typedef struct VkPipelinePropertiesIdentifierEXT -{ - VkStructureType sType; - void *pNext; - uint8_t pipelineIdentifier[VK_UUID_SIZE]; -} VkPipelinePropertiesIdentifierEXT; - -typedef struct VkPipelineRasterizationConservativeStateCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkPipelineRasterizationConservativeStateCreateFlagsEXT flags; - VkConservativeRasterizationModeEXT conservativeRasterizationMode; - float extraPrimitiveOverestimationSize; -} VkPipelineRasterizationConservativeStateCreateInfoEXT; - -typedef struct VkPipelineRasterizationDepthClipStateCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkPipelineRasterizationDepthClipStateCreateFlagsEXT flags; - VkBool32 depthClipEnable; -} VkPipelineRasterizationDepthClipStateCreateInfoEXT; - -typedef struct VkPipelineRasterizationLineStateCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkLineRasterizationModeEXT lineRasterizationMode; - VkBool32 stippledLineEnable; - uint32_t lineStippleFactor; - uint16_t lineStipplePattern; -} VkPipelineRasterizationLineStateCreateInfoEXT; - -typedef struct VkPipelineRasterizationProvokingVertexStateCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkProvokingVertexModeEXT provokingVertexMode; -} VkPipelineRasterizationProvokingVertexStateCreateInfoEXT; - -typedef struct VkPipelineRasterizationStateCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkPipelineRasterizationStateCreateFlags flags; - VkBool32 depthClampEnable; - VkBool32 rasterizerDiscardEnable; - VkPolygonMode polygonMode; - VkCullModeFlags cullMode; - VkFrontFace frontFace; - VkBool32 depthBiasEnable; - float depthBiasConstantFactor; - float depthBiasClamp; - float depthBiasSlopeFactor; - float lineWidth; -} VkPipelineRasterizationStateCreateInfo; - -typedef struct VkPipelineRasterizationStateRasterizationOrderAMD -{ - VkStructureType sType; - const void *pNext; - VkRasterizationOrderAMD rasterizationOrder; -} VkPipelineRasterizationStateRasterizationOrderAMD; - -typedef struct VkPipelineRasterizationStateStreamCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkPipelineRasterizationStateStreamCreateFlagsEXT flags; - uint32_t rasterizationStream; -} VkPipelineRasterizationStateStreamCreateInfoEXT; - -typedef struct VkPipelineRenderingCreateInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t viewMask; - uint32_t colorAttachmentCount; - const VkFormat *pColorAttachmentFormats; - VkFormat depthAttachmentFormat; - VkFormat stencilAttachmentFormat; -} VkPipelineRenderingCreateInfo; -typedef VkPipelineRenderingCreateInfo VkPipelineRenderingCreateInfoKHR; - -typedef struct VkPipelineRepresentativeFragmentTestStateCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - VkBool32 representativeFragmentTestEnable; -} VkPipelineRepresentativeFragmentTestStateCreateInfoNV; - -typedef struct VkPipelineRobustnessCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkPipelineRobustnessBufferBehaviorEXT storageBuffers; - VkPipelineRobustnessBufferBehaviorEXT uniformBuffers; - VkPipelineRobustnessBufferBehaviorEXT vertexInputs; - VkPipelineRobustnessImageBehaviorEXT images; -} VkPipelineRobustnessCreateInfoEXT; - -typedef struct VkPipelineShaderStageModuleIdentifierCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - uint32_t identifierSize; - const uint8_t *pIdentifier; -} VkPipelineShaderStageModuleIdentifierCreateInfoEXT; - -typedef struct VkPipelineShaderStageRequiredSubgroupSizeCreateInfo -{ - VkStructureType sType; - void *pNext; - uint32_t requiredSubgroupSize; -} VkPipelineShaderStageRequiredSubgroupSizeCreateInfo; -typedef VkPipelineShaderStageRequiredSubgroupSizeCreateInfo VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT; - -typedef struct VkPipelineTessellationDomainOriginStateCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkTessellationDomainOrigin domainOrigin; -} VkPipelineTessellationDomainOriginStateCreateInfo; -typedef VkPipelineTessellationDomainOriginStateCreateInfo VkPipelineTessellationDomainOriginStateCreateInfoKHR; - -typedef struct VkPipelineTessellationStateCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkPipelineTessellationStateCreateFlags flags; - uint32_t patchControlPoints; -} VkPipelineTessellationStateCreateInfo; - -typedef struct VkPipelineViewportCoarseSampleOrderStateCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - VkCoarseSampleOrderTypeNV sampleOrderType; - uint32_t customSampleOrderCount; - const VkCoarseSampleOrderCustomNV *pCustomSampleOrders; -} VkPipelineViewportCoarseSampleOrderStateCreateInfoNV; - -typedef struct VkPipelineViewportDepthClipControlCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkBool32 negativeOneToOne; -} VkPipelineViewportDepthClipControlCreateInfoEXT; - -typedef struct VkPresentIdKHR -{ - VkStructureType sType; - const void *pNext; - uint32_t swapchainCount; - const uint64_t *pPresentIds; -} VkPresentIdKHR; - -typedef struct VkPresentInfoKHR -{ - VkStructureType sType; - const void *pNext; - uint32_t waitSemaphoreCount; - const VkSemaphore *pWaitSemaphores; - uint32_t swapchainCount; - const VkSwapchainKHR *pSwapchains; - const uint32_t *pImageIndices; - VkResult *pResults; -} VkPresentInfoKHR; - -typedef struct VkPrivateDataSlotCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkPrivateDataSlotCreateFlags flags; -} VkPrivateDataSlotCreateInfo; -typedef VkPrivateDataSlotCreateInfo VkPrivateDataSlotCreateInfoEXT; - -typedef struct VkProtectedSubmitInfo -{ - VkStructureType sType; - const void *pNext; - VkBool32 protectedSubmit; -} VkProtectedSubmitInfo; - -typedef struct VkPushConstantRange -{ - VkShaderStageFlags stageFlags; - uint32_t offset; - uint32_t size; -} VkPushConstantRange; - -typedef struct VkQueryPoolCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkQueryPoolCreateFlags flags; - VkQueryType queryType; - uint32_t queryCount; - VkQueryPipelineStatisticFlags pipelineStatistics; -} VkQueryPoolCreateInfo; - -typedef struct VkQueryPoolPerformanceCreateInfoKHR -{ - VkStructureType sType; - const void *pNext; - uint32_t queueFamilyIndex; - uint32_t counterIndexCount; - const uint32_t *pCounterIndices; -} VkQueryPoolPerformanceCreateInfoKHR; - -typedef struct VkQueryPoolPerformanceQueryCreateInfoINTEL -{ - VkStructureType sType; - const void *pNext; - VkQueryPoolSamplingModeINTEL performanceCountersSampling; -} VkQueryPoolPerformanceQueryCreateInfoINTEL; -typedef VkQueryPoolPerformanceQueryCreateInfoINTEL VkQueryPoolCreateInfoINTEL; - -typedef struct VkQueueFamilyCheckpointProperties2NV -{ - VkStructureType sType; - void *pNext; - VkPipelineStageFlags2 WINE_VK_ALIGN(8) checkpointExecutionStageMask; -} VkQueueFamilyCheckpointProperties2NV; - -typedef struct VkQueueFamilyCheckpointPropertiesNV -{ - VkStructureType sType; - void *pNext; - VkPipelineStageFlags checkpointExecutionStageMask; -} VkQueueFamilyCheckpointPropertiesNV; - -typedef struct VkQueueFamilyGlobalPriorityPropertiesKHR -{ - VkStructureType sType; - void *pNext; - uint32_t priorityCount; - VkQueueGlobalPriorityKHR priorities[VK_MAX_GLOBAL_PRIORITY_SIZE_KHR]; -} VkQueueFamilyGlobalPriorityPropertiesKHR; -typedef VkQueueFamilyGlobalPriorityPropertiesKHR VkQueueFamilyGlobalPriorityPropertiesEXT; - -typedef struct VkQueueFamilyProperties -{ - VkQueueFlags queueFlags; - uint32_t queueCount; - uint32_t timestampValidBits; - VkExtent3D minImageTransferGranularity; -} VkQueueFamilyProperties; - -typedef struct VkQueueFamilyProperties2 -{ - VkStructureType sType; - void *pNext; - VkQueueFamilyProperties queueFamilyProperties; -} VkQueueFamilyProperties2; -typedef VkQueueFamilyProperties2 VkQueueFamilyProperties2KHR; - -typedef struct VkRayTracingPipelineInterfaceCreateInfoKHR -{ - VkStructureType sType; - const void *pNext; - uint32_t maxPipelineRayPayloadSize; - uint32_t maxPipelineRayHitAttributeSize; -} VkRayTracingPipelineInterfaceCreateInfoKHR; - -typedef struct VkRayTracingShaderGroupCreateInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkRayTracingShaderGroupTypeKHR type; - uint32_t generalShader; - uint32_t closestHitShader; - uint32_t anyHitShader; - uint32_t intersectionShader; - const void *pShaderGroupCaptureReplayHandle; -} VkRayTracingShaderGroupCreateInfoKHR; - -typedef struct VkRayTracingShaderGroupCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - VkRayTracingShaderGroupTypeKHR type; - uint32_t generalShader; - uint32_t closestHitShader; - uint32_t anyHitShader; - uint32_t intersectionShader; -} VkRayTracingShaderGroupCreateInfoNV; - -typedef struct VkRect2D -{ - VkOffset2D offset; - VkExtent2D extent; -} VkRect2D; - -typedef struct VkRectLayerKHR -{ - VkOffset2D offset; - VkExtent2D extent; - uint32_t layer; -} VkRectLayerKHR; - -typedef struct VkReleaseSwapchainImagesInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkSwapchainKHR WINE_VK_ALIGN(8) swapchain; - uint32_t imageIndexCount; - const uint32_t *pImageIndices; -} VkReleaseSwapchainImagesInfoEXT; - -typedef struct VkRenderPassAttachmentBeginInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t attachmentCount; - const VkImageView *pAttachments; -} VkRenderPassAttachmentBeginInfo; -typedef VkRenderPassAttachmentBeginInfo VkRenderPassAttachmentBeginInfoKHR; - -typedef struct VkRenderPassBeginInfo -{ - VkStructureType sType; - const void *pNext; - VkRenderPass WINE_VK_ALIGN(8) renderPass; - VkFramebuffer WINE_VK_ALIGN(8) framebuffer; - VkRect2D renderArea; - uint32_t clearValueCount; - const VkClearValue *pClearValues; -} VkRenderPassBeginInfo; - -typedef struct VkRenderPassCreationControlEXT -{ - VkStructureType sType; - const void *pNext; - VkBool32 disallowMerging; -} VkRenderPassCreationControlEXT; - -typedef struct VkRenderPassCreationFeedbackInfoEXT -{ - uint32_t postMergeSubpassCount; -} VkRenderPassCreationFeedbackInfoEXT; - -typedef struct VkRenderPassFragmentDensityMapCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkAttachmentReference fragmentDensityMapAttachment; -} VkRenderPassFragmentDensityMapCreateInfoEXT; - -typedef struct VkRenderPassInputAttachmentAspectCreateInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t aspectReferenceCount; - const VkInputAttachmentAspectReference *pAspectReferences; -} VkRenderPassInputAttachmentAspectCreateInfo; -typedef VkRenderPassInputAttachmentAspectCreateInfo VkRenderPassInputAttachmentAspectCreateInfoKHR; - -typedef struct VkRenderPassMultiviewCreateInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t subpassCount; - const uint32_t *pViewMasks; - uint32_t dependencyCount; - const int32_t *pViewOffsets; - uint32_t correlationMaskCount; - const uint32_t *pCorrelationMasks; -} VkRenderPassMultiviewCreateInfo; -typedef VkRenderPassMultiviewCreateInfo VkRenderPassMultiviewCreateInfoKHR; - -typedef struct VkRenderPassSubpassFeedbackInfoEXT -{ - VkSubpassMergeStatusEXT subpassMergeStatus; - char description[VK_MAX_DESCRIPTION_SIZE]; - uint32_t postMergeIndex; -} VkRenderPassSubpassFeedbackInfoEXT; - -typedef struct VkRenderPassTransformBeginInfoQCOM -{ - VkStructureType sType; - void *pNext; - VkSurfaceTransformFlagBitsKHR transform; -} VkRenderPassTransformBeginInfoQCOM; - -typedef struct VkRenderingAttachmentInfo -{ - VkStructureType sType; - const void *pNext; - VkImageView WINE_VK_ALIGN(8) imageView; - VkImageLayout imageLayout; - VkResolveModeFlagBits resolveMode; - VkImageView WINE_VK_ALIGN(8) resolveImageView; - VkImageLayout resolveImageLayout; - VkAttachmentLoadOp loadOp; - VkAttachmentStoreOp storeOp; - VkClearValue clearValue; -} VkRenderingAttachmentInfo; -typedef VkRenderingAttachmentInfo VkRenderingAttachmentInfoKHR; - -typedef struct VkRenderingFragmentDensityMapAttachmentInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkImageView WINE_VK_ALIGN(8) imageView; - VkImageLayout imageLayout; -} VkRenderingFragmentDensityMapAttachmentInfoEXT; - -typedef struct VkRenderingFragmentShadingRateAttachmentInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkImageView WINE_VK_ALIGN(8) imageView; - VkImageLayout imageLayout; - VkExtent2D shadingRateAttachmentTexelSize; -} VkRenderingFragmentShadingRateAttachmentInfoKHR; - -typedef struct VkRenderingInfo -{ - VkStructureType sType; - const void *pNext; - VkRenderingFlags flags; - VkRect2D renderArea; - uint32_t layerCount; - uint32_t viewMask; - uint32_t colorAttachmentCount; - const VkRenderingAttachmentInfo *pColorAttachments; - const VkRenderingAttachmentInfo *pDepthAttachment; - const VkRenderingAttachmentInfo *pStencilAttachment; -} VkRenderingInfo; -typedef VkRenderingInfo VkRenderingInfoKHR; - -typedef struct VkSRTDataNV -{ - float sx; - float a; - float b; - float pvx; - float sy; - float c; - float pvy; - float sz; - float pvz; - float qx; - float qy; - float qz; - float qw; - float tx; - float ty; - float tz; -} VkSRTDataNV; - -typedef struct VkSampleLocationEXT -{ - float x; - float y; -} VkSampleLocationEXT; - -typedef struct VkSampleLocationsInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkSampleCountFlagBits sampleLocationsPerPixel; - VkExtent2D sampleLocationGridSize; - uint32_t sampleLocationsCount; - const VkSampleLocationEXT *pSampleLocations; -} VkSampleLocationsInfoEXT; - -typedef struct VkSamplerBorderColorComponentMappingCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkComponentMapping components; - VkBool32 srgb; -} VkSamplerBorderColorComponentMappingCreateInfoEXT; - -typedef struct VkSamplerCaptureDescriptorDataInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkSampler WINE_VK_ALIGN(8) sampler; -} VkSamplerCaptureDescriptorDataInfoEXT; - -typedef struct VkSamplerCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkSamplerCreateFlags flags; - VkFilter magFilter; - VkFilter minFilter; - VkSamplerMipmapMode mipmapMode; - VkSamplerAddressMode addressModeU; - VkSamplerAddressMode addressModeV; - VkSamplerAddressMode addressModeW; - float mipLodBias; - VkBool32 anisotropyEnable; - float maxAnisotropy; - VkBool32 compareEnable; - VkCompareOp compareOp; - float minLod; - float maxLod; - VkBorderColor borderColor; - VkBool32 unnormalizedCoordinates; -} VkSamplerCreateInfo; - -typedef struct VkSamplerCustomBorderColorCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkClearColorValue customBorderColor; - VkFormat format; -} VkSamplerCustomBorderColorCreateInfoEXT; - -typedef struct VkSamplerReductionModeCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkSamplerReductionMode reductionMode; -} VkSamplerReductionModeCreateInfo; -typedef VkSamplerReductionModeCreateInfo VkSamplerReductionModeCreateInfoEXT; - -typedef struct VkSamplerYcbcrConversionCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkFormat format; - VkSamplerYcbcrModelConversion ycbcrModel; - VkSamplerYcbcrRange ycbcrRange; - VkComponentMapping components; - VkChromaLocation xChromaOffset; - VkChromaLocation yChromaOffset; - VkFilter chromaFilter; - VkBool32 forceExplicitReconstruction; -} VkSamplerYcbcrConversionCreateInfo; -typedef VkSamplerYcbcrConversionCreateInfo VkSamplerYcbcrConversionCreateInfoKHR; - -typedef struct VkSamplerYcbcrConversionImageFormatProperties -{ - VkStructureType sType; - void *pNext; - uint32_t combinedImageSamplerDescriptorCount; -} VkSamplerYcbcrConversionImageFormatProperties; -typedef VkSamplerYcbcrConversionImageFormatProperties VkSamplerYcbcrConversionImageFormatPropertiesKHR; - -typedef struct VkSamplerYcbcrConversionInfo -{ - VkStructureType sType; - const void *pNext; - VkSamplerYcbcrConversion WINE_VK_ALIGN(8) conversion; -} VkSamplerYcbcrConversionInfo; -typedef VkSamplerYcbcrConversionInfo VkSamplerYcbcrConversionInfoKHR; - -typedef struct VkSemaphoreCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkSemaphoreCreateFlags flags; -} VkSemaphoreCreateInfo; - -typedef struct VkSemaphoreSignalInfo -{ - VkStructureType sType; - const void *pNext; - VkSemaphore WINE_VK_ALIGN(8) semaphore; - uint64_t WINE_VK_ALIGN(8) value; -} VkSemaphoreSignalInfo; -typedef VkSemaphoreSignalInfo VkSemaphoreSignalInfoKHR; - -typedef struct VkSemaphoreSubmitInfo -{ - VkStructureType sType; - const void *pNext; - VkSemaphore WINE_VK_ALIGN(8) semaphore; - uint64_t WINE_VK_ALIGN(8) value; - VkPipelineStageFlags2 WINE_VK_ALIGN(8) stageMask; - uint32_t deviceIndex; -} VkSemaphoreSubmitInfo; -typedef VkSemaphoreSubmitInfo VkSemaphoreSubmitInfoKHR; - -typedef struct VkSemaphoreTypeCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkSemaphoreType semaphoreType; - uint64_t WINE_VK_ALIGN(8) initialValue; -} VkSemaphoreTypeCreateInfo; -typedef VkSemaphoreTypeCreateInfo VkSemaphoreTypeCreateInfoKHR; - -typedef struct VkSemaphoreWaitInfo -{ - VkStructureType sType; - const void *pNext; - VkSemaphoreWaitFlags flags; - uint32_t semaphoreCount; - const VkSemaphore *pSemaphores; - const uint64_t *pValues; -} VkSemaphoreWaitInfo; -typedef VkSemaphoreWaitInfo VkSemaphoreWaitInfoKHR; - -typedef struct VkSetStateFlagsIndirectCommandNV -{ - uint32_t data; -} VkSetStateFlagsIndirectCommandNV; - -typedef struct VkShaderModuleCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkShaderModuleCreateFlags flags; - size_t codeSize; - const uint32_t *pCode; -} VkShaderModuleCreateInfo; - -typedef struct VkShaderModuleIdentifierEXT -{ - VkStructureType sType; - void *pNext; - uint32_t identifierSize; - uint8_t identifier[VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT]; -} VkShaderModuleIdentifierEXT; - -typedef struct VkShaderModuleValidationCacheCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkValidationCacheEXT WINE_VK_ALIGN(8) validationCache; -} VkShaderModuleValidationCacheCreateInfoEXT; - -typedef struct VkShaderResourceUsageAMD -{ - uint32_t numUsedVgprs; - uint32_t numUsedSgprs; - uint32_t ldsSizePerLocalWorkGroup; - size_t ldsUsageSizeInBytes; - size_t scratchMemUsageInBytes; -} VkShaderResourceUsageAMD; - -typedef struct VkShaderStatisticsInfoAMD -{ - VkShaderStageFlags shaderStageMask; - VkShaderResourceUsageAMD resourceUsage; - uint32_t numPhysicalVgprs; - uint32_t numPhysicalSgprs; - uint32_t numAvailableVgprs; - uint32_t numAvailableSgprs; - uint32_t computeWorkGroupSize[3]; -} VkShaderStatisticsInfoAMD; - -typedef struct VkShadingRatePaletteNV -{ - uint32_t shadingRatePaletteEntryCount; - const VkShadingRatePaletteEntryNV *pShadingRatePaletteEntries; -} VkShadingRatePaletteNV; - -typedef struct VkSparseImageFormatProperties -{ - VkImageAspectFlags aspectMask; - VkExtent3D imageGranularity; - VkSparseImageFormatFlags flags; -} VkSparseImageFormatProperties; - -typedef struct VkSparseImageFormatProperties2 -{ - VkStructureType sType; - void *pNext; - VkSparseImageFormatProperties properties; -} VkSparseImageFormatProperties2; -typedef VkSparseImageFormatProperties2 VkSparseImageFormatProperties2KHR; - -typedef struct VkSparseImageMemoryBind -{ - VkImageSubresource subresource; - VkOffset3D offset; - VkExtent3D extent; - VkDeviceMemory WINE_VK_ALIGN(8) memory; - VkDeviceSize WINE_VK_ALIGN(8) memoryOffset; - VkSparseMemoryBindFlags flags; -} VkSparseImageMemoryBind; - -typedef struct VkSparseImageMemoryBindInfo -{ - VkImage WINE_VK_ALIGN(8) image; - uint32_t bindCount; - const VkSparseImageMemoryBind *pBinds; -} VkSparseImageMemoryBindInfo; - -typedef struct VkSparseImageMemoryRequirements -{ - VkSparseImageFormatProperties formatProperties; - uint32_t imageMipTailFirstLod; - VkDeviceSize WINE_VK_ALIGN(8) imageMipTailSize; - VkDeviceSize WINE_VK_ALIGN(8) imageMipTailOffset; - VkDeviceSize WINE_VK_ALIGN(8) imageMipTailStride; -} VkSparseImageMemoryRequirements; - -typedef struct VkSparseImageMemoryRequirements2 -{ - VkStructureType sType; - void *pNext; - VkSparseImageMemoryRequirements WINE_VK_ALIGN(8) memoryRequirements; -} VkSparseImageMemoryRequirements2; -typedef VkSparseImageMemoryRequirements2 VkSparseImageMemoryRequirements2KHR; - -typedef struct VkSparseMemoryBind -{ - VkDeviceSize WINE_VK_ALIGN(8) resourceOffset; - VkDeviceSize WINE_VK_ALIGN(8) size; - VkDeviceMemory WINE_VK_ALIGN(8) memory; - VkDeviceSize WINE_VK_ALIGN(8) memoryOffset; - VkSparseMemoryBindFlags flags; -} VkSparseMemoryBind; - -typedef struct VkSpecializationMapEntry -{ - uint32_t constantID; - uint32_t offset; - size_t size; -} VkSpecializationMapEntry; - -typedef struct VkStencilOpState -{ - VkStencilOp failOp; - VkStencilOp passOp; - VkStencilOp depthFailOp; - VkCompareOp compareOp; - uint32_t compareMask; - uint32_t writeMask; - uint32_t reference; -} VkStencilOpState; - -typedef struct VkStridedDeviceAddressRegionKHR -{ - VkDeviceAddress WINE_VK_ALIGN(8) deviceAddress; - VkDeviceSize WINE_VK_ALIGN(8) stride; - VkDeviceSize WINE_VK_ALIGN(8) size; -} VkStridedDeviceAddressRegionKHR; - -typedef struct VkSubmitInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t waitSemaphoreCount; - const VkSemaphore *pWaitSemaphores; - const VkPipelineStageFlags *pWaitDstStageMask; - uint32_t commandBufferCount; - const VkCommandBuffer *pCommandBuffers; - uint32_t signalSemaphoreCount; - const VkSemaphore *pSignalSemaphores; -} VkSubmitInfo; - -typedef struct VkSubmitInfo2 -{ - VkStructureType sType; - const void *pNext; - VkSubmitFlags flags; - uint32_t waitSemaphoreInfoCount; - const VkSemaphoreSubmitInfo *pWaitSemaphoreInfos; - uint32_t commandBufferInfoCount; - const VkCommandBufferSubmitInfo *pCommandBufferInfos; - uint32_t signalSemaphoreInfoCount; - const VkSemaphoreSubmitInfo *pSignalSemaphoreInfos; -} VkSubmitInfo2; -typedef VkSubmitInfo2 VkSubmitInfo2KHR; - -typedef struct VkSubpassBeginInfo -{ - VkStructureType sType; - const void *pNext; - VkSubpassContents contents; -} VkSubpassBeginInfo; -typedef VkSubpassBeginInfo VkSubpassBeginInfoKHR; - -typedef struct VkSubpassDependency -{ - uint32_t srcSubpass; - uint32_t dstSubpass; - VkPipelineStageFlags srcStageMask; - VkPipelineStageFlags dstStageMask; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkDependencyFlags dependencyFlags; -} VkSubpassDependency; - -typedef struct VkSubpassDependency2 -{ - VkStructureType sType; - const void *pNext; - uint32_t srcSubpass; - uint32_t dstSubpass; - VkPipelineStageFlags srcStageMask; - VkPipelineStageFlags dstStageMask; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkDependencyFlags dependencyFlags; - int32_t viewOffset; -} VkSubpassDependency2; -typedef VkSubpassDependency2 VkSubpassDependency2KHR; - -typedef struct VkSubpassDescription -{ - VkSubpassDescriptionFlags flags; - VkPipelineBindPoint pipelineBindPoint; - uint32_t inputAttachmentCount; - const VkAttachmentReference *pInputAttachments; - uint32_t colorAttachmentCount; - const VkAttachmentReference *pColorAttachments; - const VkAttachmentReference *pResolveAttachments; - const VkAttachmentReference *pDepthStencilAttachment; - uint32_t preserveAttachmentCount; - const uint32_t *pPreserveAttachments; -} VkSubpassDescription; - -typedef struct VkSubpassDescription2 -{ - VkStructureType sType; - const void *pNext; - VkSubpassDescriptionFlags flags; - VkPipelineBindPoint pipelineBindPoint; - uint32_t viewMask; - uint32_t inputAttachmentCount; - const VkAttachmentReference2 *pInputAttachments; - uint32_t colorAttachmentCount; - const VkAttachmentReference2 *pColorAttachments; - const VkAttachmentReference2 *pResolveAttachments; - const VkAttachmentReference2 *pDepthStencilAttachment; - uint32_t preserveAttachmentCount; - const uint32_t *pPreserveAttachments; -} VkSubpassDescription2; -typedef VkSubpassDescription2 VkSubpassDescription2KHR; - -typedef struct VkSubpassDescriptionDepthStencilResolve -{ - VkStructureType sType; - const void *pNext; - VkResolveModeFlagBits depthResolveMode; - VkResolveModeFlagBits stencilResolveMode; - const VkAttachmentReference2 *pDepthStencilResolveAttachment; -} VkSubpassDescriptionDepthStencilResolve; -typedef VkSubpassDescriptionDepthStencilResolve VkSubpassDescriptionDepthStencilResolveKHR; - -typedef struct VkSubpassEndInfo -{ - VkStructureType sType; - const void *pNext; -} VkSubpassEndInfo; -typedef VkSubpassEndInfo VkSubpassEndInfoKHR; - -typedef struct VkSubpassFragmentDensityMapOffsetEndInfoQCOM -{ - VkStructureType sType; - const void *pNext; - uint32_t fragmentDensityOffsetCount; - const VkOffset2D *pFragmentDensityOffsets; -} VkSubpassFragmentDensityMapOffsetEndInfoQCOM; - -typedef struct VkSubpassResolvePerformanceQueryEXT -{ - VkStructureType sType; - void *pNext; - VkBool32 optimal; -} VkSubpassResolvePerformanceQueryEXT; - -typedef struct VkSubpassSampleLocationsEXT -{ - uint32_t subpassIndex; - VkSampleLocationsInfoEXT sampleLocationsInfo; -} VkSubpassSampleLocationsEXT; - -typedef struct VkSubpassShadingPipelineCreateInfoHUAWEI -{ - VkStructureType sType; - void *pNext; - VkRenderPass WINE_VK_ALIGN(8) renderPass; - uint32_t subpass; -} VkSubpassShadingPipelineCreateInfoHUAWEI; - -typedef struct VkSubresourceLayout -{ - VkDeviceSize WINE_VK_ALIGN(8) offset; - VkDeviceSize WINE_VK_ALIGN(8) size; - VkDeviceSize WINE_VK_ALIGN(8) rowPitch; - VkDeviceSize WINE_VK_ALIGN(8) arrayPitch; - VkDeviceSize WINE_VK_ALIGN(8) depthPitch; -} VkSubresourceLayout; - -typedef struct VkSubresourceLayout2EXT -{ - VkStructureType sType; - void *pNext; - VkSubresourceLayout WINE_VK_ALIGN(8) subresourceLayout; -} VkSubresourceLayout2EXT; - -typedef struct VkSurfaceCapabilitiesKHR -{ - uint32_t minImageCount; - uint32_t maxImageCount; - VkExtent2D currentExtent; - VkExtent2D minImageExtent; - VkExtent2D maxImageExtent; - uint32_t maxImageArrayLayers; - VkSurfaceTransformFlagsKHR supportedTransforms; - VkSurfaceTransformFlagBitsKHR currentTransform; - VkCompositeAlphaFlagsKHR supportedCompositeAlpha; - VkImageUsageFlags supportedUsageFlags; -} VkSurfaceCapabilitiesKHR; - -typedef struct VkSurfaceCapabilitiesPresentBarrierNV -{ - VkStructureType sType; - void *pNext; - VkBool32 presentBarrierSupported; -} VkSurfaceCapabilitiesPresentBarrierNV; - -typedef struct VkSurfaceFormatKHR -{ - VkFormat format; - VkColorSpaceKHR colorSpace; -} VkSurfaceFormatKHR; - -typedef struct VkSurfacePresentModeCompatibilityEXT -{ - VkStructureType sType; - void *pNext; - uint32_t presentModeCount; - VkPresentModeKHR *pPresentModes; -} VkSurfacePresentModeCompatibilityEXT; - -typedef struct VkSurfacePresentModeEXT -{ - VkStructureType sType; - void *pNext; - VkPresentModeKHR presentMode; -} VkSurfacePresentModeEXT; - -typedef struct VkSurfacePresentScalingCapabilitiesEXT -{ - VkStructureType sType; - void *pNext; - VkPresentScalingFlagsEXT supportedPresentScaling; - VkPresentGravityFlagsEXT supportedPresentGravityX; - VkPresentGravityFlagsEXT supportedPresentGravityY; - VkExtent2D minScaledImageExtent; - VkExtent2D maxScaledImageExtent; -} VkSurfacePresentScalingCapabilitiesEXT; - -typedef struct VkSwapchainCreateInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkSwapchainCreateFlagsKHR flags; - VkSurfaceKHR WINE_VK_ALIGN(8) surface; - uint32_t minImageCount; - VkFormat imageFormat; - VkColorSpaceKHR imageColorSpace; - VkExtent2D imageExtent; - uint32_t imageArrayLayers; - VkImageUsageFlags imageUsage; - VkSharingMode imageSharingMode; - uint32_t queueFamilyIndexCount; - const uint32_t *pQueueFamilyIndices; - VkSurfaceTransformFlagBitsKHR preTransform; - VkCompositeAlphaFlagBitsKHR compositeAlpha; - VkPresentModeKHR presentMode; - VkBool32 clipped; - VkSwapchainKHR WINE_VK_ALIGN(8) oldSwapchain; -} VkSwapchainCreateInfoKHR; - -typedef struct VkSwapchainPresentBarrierCreateInfoNV -{ - VkStructureType sType; - void *pNext; - VkBool32 presentBarrierEnable; -} VkSwapchainPresentBarrierCreateInfoNV; - -typedef struct VkSwapchainPresentFenceInfoEXT -{ - VkStructureType sType; - void *pNext; - uint32_t swapchainCount; - const VkFence *pFences; -} VkSwapchainPresentFenceInfoEXT; - -typedef struct VkSwapchainPresentModeInfoEXT -{ - VkStructureType sType; - void *pNext; - uint32_t swapchainCount; - const VkPresentModeKHR *pPresentModes; -} VkSwapchainPresentModeInfoEXT; - -typedef struct VkSwapchainPresentModesCreateInfoEXT -{ - VkStructureType sType; - void *pNext; - uint32_t presentModeCount; - const VkPresentModeKHR *pPresentModes; -} VkSwapchainPresentModesCreateInfoEXT; - -typedef struct VkSwapchainPresentScalingCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkPresentScalingFlagsEXT scalingBehavior; - VkPresentGravityFlagsEXT presentGravityX; - VkPresentGravityFlagsEXT presentGravityY; -} VkSwapchainPresentScalingCreateInfoEXT; - -typedef struct VkTextureLODGatherFormatPropertiesAMD -{ - VkStructureType sType; - void *pNext; - VkBool32 supportsTextureGatherLODBiasAMD; -} VkTextureLODGatherFormatPropertiesAMD; - -typedef struct VkTilePropertiesQCOM -{ - VkStructureType sType; - void *pNext; - VkExtent3D tileSize; - VkExtent2D apronSize; - VkOffset2D origin; -} VkTilePropertiesQCOM; - -typedef struct VkTimelineSemaphoreSubmitInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t waitSemaphoreValueCount; - const uint64_t *pWaitSemaphoreValues; - uint32_t signalSemaphoreValueCount; - const uint64_t *pSignalSemaphoreValues; -} VkTimelineSemaphoreSubmitInfo; -typedef VkTimelineSemaphoreSubmitInfo VkTimelineSemaphoreSubmitInfoKHR; - -typedef struct VkTraceRaysIndirectCommand2KHR -{ - VkDeviceAddress WINE_VK_ALIGN(8) raygenShaderRecordAddress; - VkDeviceSize WINE_VK_ALIGN(8) raygenShaderRecordSize; - VkDeviceAddress WINE_VK_ALIGN(8) missShaderBindingTableAddress; - VkDeviceSize WINE_VK_ALIGN(8) missShaderBindingTableSize; - VkDeviceSize WINE_VK_ALIGN(8) missShaderBindingTableStride; - VkDeviceAddress WINE_VK_ALIGN(8) hitShaderBindingTableAddress; - VkDeviceSize WINE_VK_ALIGN(8) hitShaderBindingTableSize; - VkDeviceSize WINE_VK_ALIGN(8) hitShaderBindingTableStride; - VkDeviceAddress WINE_VK_ALIGN(8) callableShaderBindingTableAddress; - VkDeviceSize WINE_VK_ALIGN(8) callableShaderBindingTableSize; - VkDeviceSize WINE_VK_ALIGN(8) callableShaderBindingTableStride; - uint32_t width; - uint32_t height; - uint32_t depth; -} VkTraceRaysIndirectCommand2KHR; - -typedef struct VkTraceRaysIndirectCommandKHR -{ - uint32_t width; - uint32_t height; - uint32_t depth; -} VkTraceRaysIndirectCommandKHR; - -typedef struct VkTransformMatrixKHR -{ - float matrix[3][4]; -} VkTransformMatrixKHR; -typedef VkTransformMatrixKHR VkTransformMatrixNV; - -typedef struct VkValidationCacheCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkValidationCacheCreateFlagsEXT flags; - size_t initialDataSize; - const void *pInitialData; -} VkValidationCacheCreateInfoEXT; - -typedef struct VkValidationFeaturesEXT -{ - VkStructureType sType; - const void *pNext; - uint32_t enabledValidationFeatureCount; - const VkValidationFeatureEnableEXT *pEnabledValidationFeatures; - uint32_t disabledValidationFeatureCount; - const VkValidationFeatureDisableEXT *pDisabledValidationFeatures; -} VkValidationFeaturesEXT; - -typedef struct VkValidationFlagsEXT -{ - VkStructureType sType; - const void *pNext; - uint32_t disabledValidationCheckCount; - const VkValidationCheckEXT *pDisabledValidationChecks; -} VkValidationFlagsEXT; - -typedef struct VkVertexInputAttributeDescription -{ - uint32_t location; - uint32_t binding; - VkFormat format; - uint32_t offset; -} VkVertexInputAttributeDescription; - -typedef struct VkVertexInputAttributeDescription2EXT -{ - VkStructureType sType; - void *pNext; - uint32_t location; - uint32_t binding; - VkFormat format; - uint32_t offset; -} VkVertexInputAttributeDescription2EXT; - -typedef struct VkVertexInputBindingDescription -{ - uint32_t binding; - uint32_t stride; - VkVertexInputRate inputRate; -} VkVertexInputBindingDescription; - -typedef struct VkVertexInputBindingDescription2EXT -{ - VkStructureType sType; - void *pNext; - uint32_t binding; - uint32_t stride; - VkVertexInputRate inputRate; - uint32_t divisor; -} VkVertexInputBindingDescription2EXT; - -typedef struct VkVertexInputBindingDivisorDescriptionEXT -{ - uint32_t binding; - uint32_t divisor; -} VkVertexInputBindingDivisorDescriptionEXT; - -typedef struct VkViewport -{ - float x; - float y; - float width; - float height; - float minDepth; - float maxDepth; -} VkViewport; - -typedef struct VkViewportSwizzleNV -{ - VkViewportCoordinateSwizzleNV x; - VkViewportCoordinateSwizzleNV y; - VkViewportCoordinateSwizzleNV z; - VkViewportCoordinateSwizzleNV w; -} VkViewportSwizzleNV; - -typedef struct VkViewportWScalingNV -{ - float xcoeff; - float ycoeff; -} VkViewportWScalingNV; - -typedef struct VkWin32SurfaceCreateInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkWin32SurfaceCreateFlagsKHR flags; - HINSTANCE hinstance; - HWND hwnd; -} VkWin32SurfaceCreateInfoKHR; - -typedef struct VkWriteDescriptorSet -{ - VkStructureType sType; - const void *pNext; - VkDescriptorSet WINE_VK_ALIGN(8) dstSet; - uint32_t dstBinding; - uint32_t dstArrayElement; - uint32_t descriptorCount; - VkDescriptorType descriptorType; - const VkDescriptorImageInfo *pImageInfo; - const VkDescriptorBufferInfo *pBufferInfo; - const VkBufferView *pTexelBufferView; -} VkWriteDescriptorSet; - -typedef struct VkWriteDescriptorSetAccelerationStructureKHR -{ - VkStructureType sType; - const void *pNext; - uint32_t accelerationStructureCount; - const VkAccelerationStructureKHR *pAccelerationStructures; -} VkWriteDescriptorSetAccelerationStructureKHR; - -typedef struct VkWriteDescriptorSetAccelerationStructureNV -{ - VkStructureType sType; - const void *pNext; - uint32_t accelerationStructureCount; - const VkAccelerationStructureNV *pAccelerationStructures; -} VkWriteDescriptorSetAccelerationStructureNV; - -typedef struct VkWriteDescriptorSetInlineUniformBlock -{ - VkStructureType sType; - const void *pNext; - uint32_t dataSize; - const void *pData; -} VkWriteDescriptorSetInlineUniformBlock; -typedef VkWriteDescriptorSetInlineUniformBlock VkWriteDescriptorSetInlineUniformBlockEXT; - -typedef struct VkAccelerationStructureGeometryAabbsDataKHR -{ - VkStructureType sType; - const void *pNext; - VkDeviceOrHostAddressConstKHR WINE_VK_ALIGN(8) data; - VkDeviceSize WINE_VK_ALIGN(8) stride; -} VkAccelerationStructureGeometryAabbsDataKHR; - -typedef struct VkAccelerationStructureGeometryInstancesDataKHR -{ - VkStructureType sType; - const void *pNext; - VkBool32 arrayOfPointers; - VkDeviceOrHostAddressConstKHR WINE_VK_ALIGN(8) data; -} VkAccelerationStructureGeometryInstancesDataKHR; - -typedef struct VkAccelerationStructureGeometryMotionTrianglesDataNV -{ - VkStructureType sType; - const void *pNext; - VkDeviceOrHostAddressConstKHR WINE_VK_ALIGN(8) vertexData; -} VkAccelerationStructureGeometryMotionTrianglesDataNV; - -typedef struct VkAccelerationStructureGeometryTrianglesDataKHR -{ - VkStructureType sType; - const void *pNext; - VkFormat vertexFormat; - VkDeviceOrHostAddressConstKHR WINE_VK_ALIGN(8) vertexData; - VkDeviceSize WINE_VK_ALIGN(8) vertexStride; - uint32_t maxVertex; - VkIndexType indexType; - VkDeviceOrHostAddressConstKHR WINE_VK_ALIGN(8) indexData; - VkDeviceOrHostAddressConstKHR WINE_VK_ALIGN(8) transformData; -} VkAccelerationStructureGeometryTrianglesDataKHR; - -typedef struct VkAccelerationStructureInstanceKHR -{ - VkTransformMatrixKHR transform; - uint32_t instanceCustomIndex:24; - uint32_t mask:8; - uint32_t instanceShaderBindingTableRecordOffset:24; - VkGeometryInstanceFlagsKHR flags:8; - uint64_t WINE_VK_ALIGN(8) accelerationStructureReference; -} VkAccelerationStructureInstanceKHR; -typedef VkAccelerationStructureInstanceKHR VkAccelerationStructureInstanceNV; - -typedef struct VkAccelerationStructureMatrixMotionInstanceNV -{ - VkTransformMatrixKHR transformT0; - VkTransformMatrixKHR transformT1; - uint32_t instanceCustomIndex:24; - uint32_t mask:8; - uint32_t instanceShaderBindingTableRecordOffset:24; - VkGeometryInstanceFlagsKHR flags:8; - uint64_t WINE_VK_ALIGN(8) accelerationStructureReference; -} VkAccelerationStructureMatrixMotionInstanceNV; - -typedef struct VkAccelerationStructureSRTMotionInstanceNV -{ - VkSRTDataNV transformT0; - VkSRTDataNV transformT1; - uint32_t instanceCustomIndex:24; - uint32_t mask:8; - uint32_t instanceShaderBindingTableRecordOffset:24; - VkGeometryInstanceFlagsKHR flags:8; - uint64_t WINE_VK_ALIGN(8) accelerationStructureReference; -} VkAccelerationStructureSRTMotionInstanceNV; - -typedef struct VkAccelerationStructureTrianglesOpacityMicromapEXT -{ - VkStructureType sType; - void *pNext; - VkIndexType indexType; - VkDeviceOrHostAddressConstKHR WINE_VK_ALIGN(8) indexBuffer; - VkDeviceSize WINE_VK_ALIGN(8) indexStride; - uint32_t baseTriangle; - uint32_t usageCountsCount; - const VkMicromapUsageEXT *pUsageCounts; - const VkMicromapUsageEXT * const*ppUsageCounts; - VkMicromapEXT WINE_VK_ALIGN(8) micromap; -} VkAccelerationStructureTrianglesOpacityMicromapEXT; - -typedef struct VkAttachmentSampleLocationsEXT -{ - uint32_t attachmentIndex; - VkSampleLocationsInfoEXT sampleLocationsInfo; -} VkAttachmentSampleLocationsEXT; - -typedef struct VkBindImageMemoryDeviceGroupInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t deviceIndexCount; - const uint32_t *pDeviceIndices; - uint32_t splitInstanceBindRegionCount; - const VkRect2D *pSplitInstanceBindRegions; -} VkBindImageMemoryDeviceGroupInfo; -typedef VkBindImageMemoryDeviceGroupInfo VkBindImageMemoryDeviceGroupInfoKHR; - -typedef struct VkBufferImageCopy -{ - VkDeviceSize WINE_VK_ALIGN(8) bufferOffset; - uint32_t bufferRowLength; - uint32_t bufferImageHeight; - VkImageSubresourceLayers imageSubresource; - VkOffset3D imageOffset; - VkExtent3D imageExtent; -} VkBufferImageCopy; - -typedef struct VkBufferImageCopy2 -{ - VkStructureType sType; - const void *pNext; - VkDeviceSize WINE_VK_ALIGN(8) bufferOffset; - uint32_t bufferRowLength; - uint32_t bufferImageHeight; - VkImageSubresourceLayers imageSubresource; - VkOffset3D imageOffset; - VkExtent3D imageExtent; -} VkBufferImageCopy2; -typedef VkBufferImageCopy2 VkBufferImageCopy2KHR; - -typedef struct VkClearAttachment -{ - VkImageAspectFlags aspectMask; - uint32_t colorAttachment; - VkClearValue clearValue; -} VkClearAttachment; - -typedef struct VkClearRect -{ - VkRect2D rect; - uint32_t baseArrayLayer; - uint32_t layerCount; -} VkClearRect; - -typedef struct VkCommandBufferBeginInfo -{ - VkStructureType sType; - const void *pNext; - VkCommandBufferUsageFlags flags; - const VkCommandBufferInheritanceInfo *pInheritanceInfo; -} VkCommandBufferBeginInfo; - -typedef struct VkCommandBufferInheritanceRenderPassTransformInfoQCOM -{ - VkStructureType sType; - void *pNext; - VkSurfaceTransformFlagBitsKHR transform; - VkRect2D renderArea; -} VkCommandBufferInheritanceRenderPassTransformInfoQCOM; - -typedef struct VkCommandBufferInheritanceViewportScissorInfoNV -{ - VkStructureType sType; - const void *pNext; - VkBool32 viewportScissor2D; - uint32_t viewportDepthCount; - const VkViewport *pViewportDepths; -} VkCommandBufferInheritanceViewportScissorInfoNV; - -typedef struct VkCopyAccelerationStructureToMemoryInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkAccelerationStructureKHR WINE_VK_ALIGN(8) src; - VkDeviceOrHostAddressKHR WINE_VK_ALIGN(8) dst; - VkCopyAccelerationStructureModeKHR mode; -} VkCopyAccelerationStructureToMemoryInfoKHR; - -typedef struct VkCopyBufferToImageInfo2 -{ - VkStructureType sType; - const void *pNext; - VkBuffer WINE_VK_ALIGN(8) srcBuffer; - VkImage WINE_VK_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - const VkBufferImageCopy2 *pRegions; -} VkCopyBufferToImageInfo2; -typedef VkCopyBufferToImageInfo2 VkCopyBufferToImageInfo2KHR; - -typedef struct VkCopyImageToBufferInfo2 -{ - VkStructureType sType; - const void *pNext; - VkImage WINE_VK_ALIGN(8) srcImage; - VkImageLayout srcImageLayout; - VkBuffer WINE_VK_ALIGN(8) dstBuffer; - uint32_t regionCount; - const VkBufferImageCopy2 *pRegions; -} VkCopyImageToBufferInfo2; -typedef VkCopyImageToBufferInfo2 VkCopyImageToBufferInfo2KHR; - -typedef struct VkCopyMemoryToAccelerationStructureInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkDeviceOrHostAddressConstKHR WINE_VK_ALIGN(8) src; - VkAccelerationStructureKHR WINE_VK_ALIGN(8) dst; - VkCopyAccelerationStructureModeKHR mode; -} VkCopyMemoryToAccelerationStructureInfoKHR; - -typedef struct VkCopyMemoryToImageIndirectCommandNV -{ - VkDeviceAddress WINE_VK_ALIGN(8) srcAddress; - uint32_t bufferRowLength; - uint32_t bufferImageHeight; - VkImageSubresourceLayers imageSubresource; - VkOffset3D imageOffset; - VkExtent3D imageExtent; -} VkCopyMemoryToImageIndirectCommandNV; - -typedef struct VkCopyMemoryToMicromapInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkDeviceOrHostAddressConstKHR WINE_VK_ALIGN(8) src; - VkMicromapEXT WINE_VK_ALIGN(8) dst; - VkCopyMicromapModeEXT mode; -} VkCopyMemoryToMicromapInfoEXT; - -typedef struct VkCopyMicromapToMemoryInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkMicromapEXT WINE_VK_ALIGN(8) src; - VkDeviceOrHostAddressKHR WINE_VK_ALIGN(8) dst; - VkCopyMicromapModeEXT mode; -} VkCopyMicromapToMemoryInfoEXT; - -typedef struct VkDebugUtilsMessengerCallbackDataEXT -{ - VkStructureType sType; - const void *pNext; - VkDebugUtilsMessengerCallbackDataFlagsEXT flags; - const char *pMessageIdName; - int32_t messageIdNumber; - const char *pMessage; - uint32_t queueLabelCount; - const VkDebugUtilsLabelEXT *pQueueLabels; - uint32_t cmdBufLabelCount; - const VkDebugUtilsLabelEXT *pCmdBufLabels; - uint32_t objectCount; - const VkDebugUtilsObjectNameInfoEXT *pObjects; -} VkDebugUtilsMessengerCallbackDataEXT; - -typedef union VkDescriptorDataEXT -{ - const VkSampler *pSampler; - const VkDescriptorImageInfo *pCombinedImageSampler; - const VkDescriptorImageInfo *pInputAttachmentImage; - const VkDescriptorImageInfo *pSampledImage; - const VkDescriptorImageInfo *pStorageImage; - const VkDescriptorAddressInfoEXT *pUniformTexelBuffer; - const VkDescriptorAddressInfoEXT *pStorageTexelBuffer; - const VkDescriptorAddressInfoEXT *pUniformBuffer; - const VkDescriptorAddressInfoEXT *pStorageBuffer; - VkDeviceAddress WINE_VK_ALIGN(8) accelerationStructure; -} VkDescriptorDataEXT; - -typedef struct VkDescriptorGetInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkDescriptorType type; - VkDescriptorDataEXT WINE_VK_ALIGN(8) data; -} VkDescriptorGetInfoEXT; - -typedef struct VkDescriptorPoolCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkDescriptorPoolCreateFlags flags; - uint32_t maxSets; - uint32_t poolSizeCount; - const VkDescriptorPoolSize *pPoolSizes; -} VkDescriptorPoolCreateInfo; - -typedef struct VkDescriptorUpdateTemplateCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkDescriptorUpdateTemplateCreateFlags flags; - uint32_t descriptorUpdateEntryCount; - const VkDescriptorUpdateTemplateEntry *pDescriptorUpdateEntries; - VkDescriptorUpdateTemplateType templateType; - VkDescriptorSetLayout WINE_VK_ALIGN(8) descriptorSetLayout; - VkPipelineBindPoint pipelineBindPoint; - VkPipelineLayout WINE_VK_ALIGN(8) pipelineLayout; - uint32_t set; -} VkDescriptorUpdateTemplateCreateInfo; -typedef VkDescriptorUpdateTemplateCreateInfo VkDescriptorUpdateTemplateCreateInfoKHR; - -typedef struct VkDeviceCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkDeviceCreateFlags flags; - uint32_t queueCreateInfoCount; - const VkDeviceQueueCreateInfo *pQueueCreateInfos; - uint32_t enabledLayerCount; - const char * const*ppEnabledLayerNames; - uint32_t enabledExtensionCount; - const char * const*ppEnabledExtensionNames; - const VkPhysicalDeviceFeatures *pEnabledFeatures; -} VkDeviceCreateInfo; - -typedef struct VkDeviceFaultInfoEXT -{ - VkStructureType sType; - void *pNext; - char description[VK_MAX_DESCRIPTION_SIZE]; - VkDeviceFaultAddressInfoEXT *pAddressInfos; - VkDeviceFaultVendorInfoEXT *pVendorInfos; - void *pVendorBinaryData; -} VkDeviceFaultInfoEXT; - -typedef struct VkDeviceGroupRenderPassBeginInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t deviceMask; - uint32_t deviceRenderAreaCount; - const VkRect2D *pDeviceRenderAreas; -} VkDeviceGroupRenderPassBeginInfo; -typedef VkDeviceGroupRenderPassBeginInfo VkDeviceGroupRenderPassBeginInfoKHR; - -typedef struct VkDeviceImageMemoryRequirements -{ - VkStructureType sType; - const void *pNext; - const VkImageCreateInfo *pCreateInfo; - VkImageAspectFlagBits planeAspect; -} VkDeviceImageMemoryRequirements; -typedef VkDeviceImageMemoryRequirements VkDeviceImageMemoryRequirementsKHR; - -typedef struct VkExternalBufferProperties -{ - VkStructureType sType; - void *pNext; - VkExternalMemoryProperties externalMemoryProperties; -} VkExternalBufferProperties; -typedef VkExternalBufferProperties VkExternalBufferPropertiesKHR; - -typedef struct VkExternalImageFormatProperties -{ - VkStructureType sType; - void *pNext; - VkExternalMemoryProperties externalMemoryProperties; -} VkExternalImageFormatProperties; -typedef VkExternalImageFormatProperties VkExternalImageFormatPropertiesKHR; - -typedef struct VkGeneratedCommandsInfoNV -{ - VkStructureType sType; - const void *pNext; - VkPipelineBindPoint pipelineBindPoint; - VkPipeline WINE_VK_ALIGN(8) pipeline; - VkIndirectCommandsLayoutNV WINE_VK_ALIGN(8) indirectCommandsLayout; - uint32_t streamCount; - const VkIndirectCommandsStreamNV *pStreams; - uint32_t sequencesCount; - VkBuffer WINE_VK_ALIGN(8) preprocessBuffer; - VkDeviceSize WINE_VK_ALIGN(8) preprocessOffset; - VkDeviceSize WINE_VK_ALIGN(8) preprocessSize; - VkBuffer WINE_VK_ALIGN(8) sequencesCountBuffer; - VkDeviceSize WINE_VK_ALIGN(8) sequencesCountOffset; - VkBuffer WINE_VK_ALIGN(8) sequencesIndexBuffer; - VkDeviceSize WINE_VK_ALIGN(8) sequencesIndexOffset; -} VkGeneratedCommandsInfoNV; - -typedef struct VkGeometryDataNV -{ - VkGeometryTrianglesNV WINE_VK_ALIGN(8) triangles; - VkGeometryAABBNV WINE_VK_ALIGN(8) aabbs; -} VkGeometryDataNV; - -typedef struct VkGeometryNV -{ - VkStructureType sType; - const void *pNext; - VkGeometryTypeKHR geometryType; - VkGeometryDataNV WINE_VK_ALIGN(8) geometry; - VkGeometryFlagsKHR flags; -} VkGeometryNV; - -typedef struct VkImageBlit -{ - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffsets[2]; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffsets[2]; -} VkImageBlit; - -typedef struct VkImageBlit2 -{ - VkStructureType sType; - const void *pNext; - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffsets[2]; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffsets[2]; -} VkImageBlit2; -typedef VkImageBlit2 VkImageBlit2KHR; - -typedef struct VkImageCopy -{ - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; -} VkImageCopy; - -typedef struct VkImageCopy2 -{ - VkStructureType sType; - const void *pNext; - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; -} VkImageCopy2; -typedef VkImageCopy2 VkImageCopy2KHR; - -typedef struct VkImageMemoryBarrier -{ - VkStructureType sType; - const void *pNext; - VkAccessFlags srcAccessMask; - VkAccessFlags dstAccessMask; - VkImageLayout oldLayout; - VkImageLayout newLayout; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkImage WINE_VK_ALIGN(8) image; - VkImageSubresourceRange subresourceRange; -} VkImageMemoryBarrier; - -typedef struct VkImageMemoryBarrier2 -{ - VkStructureType sType; - const void *pNext; - VkPipelineStageFlags2 WINE_VK_ALIGN(8) srcStageMask; - VkAccessFlags2 WINE_VK_ALIGN(8) srcAccessMask; - VkPipelineStageFlags2 WINE_VK_ALIGN(8) dstStageMask; - VkAccessFlags2 WINE_VK_ALIGN(8) dstAccessMask; - VkImageLayout oldLayout; - VkImageLayout newLayout; - uint32_t srcQueueFamilyIndex; - uint32_t dstQueueFamilyIndex; - VkImage WINE_VK_ALIGN(8) image; - VkImageSubresourceRange subresourceRange; -} VkImageMemoryBarrier2; -typedef VkImageMemoryBarrier2 VkImageMemoryBarrier2KHR; - -typedef struct VkImageResolve -{ - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; -} VkImageResolve; - -typedef struct VkImageResolve2 -{ - VkStructureType sType; - const void *pNext; - VkImageSubresourceLayers srcSubresource; - VkOffset3D srcOffset; - VkImageSubresourceLayers dstSubresource; - VkOffset3D dstOffset; - VkExtent3D extent; -} VkImageResolve2; -typedef VkImageResolve2 VkImageResolve2KHR; - -typedef struct VkImageViewSampleWeightCreateInfoQCOM -{ - VkStructureType sType; - const void *pNext; - VkOffset2D filterCenter; - VkExtent2D filterSize; - uint32_t numPhases; -} VkImageViewSampleWeightCreateInfoQCOM; - -typedef struct VkIndirectCommandsLayoutCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - VkIndirectCommandsLayoutUsageFlagsNV flags; - VkPipelineBindPoint pipelineBindPoint; - uint32_t tokenCount; - const VkIndirectCommandsLayoutTokenNV *pTokens; - uint32_t streamCount; - const uint32_t *pStreamStrides; -} VkIndirectCommandsLayoutCreateInfoNV; - -typedef struct VkMicromapBuildInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkMicromapTypeEXT type; - VkBuildMicromapFlagsEXT flags; - VkBuildMicromapModeEXT mode; - VkMicromapEXT WINE_VK_ALIGN(8) dstMicromap; - uint32_t usageCountsCount; - const VkMicromapUsageEXT *pUsageCounts; - const VkMicromapUsageEXT * const*ppUsageCounts; - VkDeviceOrHostAddressConstKHR WINE_VK_ALIGN(8) data; - VkDeviceOrHostAddressKHR WINE_VK_ALIGN(8) scratchData; - VkDeviceOrHostAddressConstKHR WINE_VK_ALIGN(8) triangleArray; - VkDeviceSize WINE_VK_ALIGN(8) triangleArrayStride; -} VkMicromapBuildInfoEXT; - -typedef struct VkMutableDescriptorTypeCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - uint32_t mutableDescriptorTypeListCount; - const VkMutableDescriptorTypeListEXT *pMutableDescriptorTypeLists; -} VkMutableDescriptorTypeCreateInfoEXT; -typedef VkMutableDescriptorTypeCreateInfoEXT VkMutableDescriptorTypeCreateInfoVALVE; - -typedef struct VkOpticalFlowExecuteInfoNV -{ - VkStructureType sType; - void *pNext; - VkOpticalFlowExecuteFlagsNV flags; - uint32_t regionCount; - const VkRect2D *pRegions; -} VkOpticalFlowExecuteInfoNV; - -typedef struct VkPhysicalDeviceProperties -{ - uint32_t apiVersion; - uint32_t driverVersion; - uint32_t vendorID; - uint32_t deviceID; - VkPhysicalDeviceType deviceType; - char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]; - uint8_t pipelineCacheUUID[VK_UUID_SIZE]; - VkPhysicalDeviceLimits WINE_VK_ALIGN(8) limits; - VkPhysicalDeviceSparseProperties sparseProperties; -} VkPhysicalDeviceProperties; - -typedef struct VkPhysicalDeviceProperties2 -{ - VkStructureType sType; - void *pNext; - VkPhysicalDeviceProperties WINE_VK_ALIGN(8) properties; -} VkPhysicalDeviceProperties2; -typedef VkPhysicalDeviceProperties2 VkPhysicalDeviceProperties2KHR; - -typedef struct VkPipelineDepthStencilStateCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkPipelineDepthStencilStateCreateFlags flags; - VkBool32 depthTestEnable; - VkBool32 depthWriteEnable; - VkCompareOp depthCompareOp; - VkBool32 depthBoundsTestEnable; - VkBool32 stencilTestEnable; - VkStencilOpState front; - VkStencilOpState back; - float minDepthBounds; - float maxDepthBounds; -} VkPipelineDepthStencilStateCreateInfo; - -typedef struct VkPipelineDiscardRectangleStateCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkPipelineDiscardRectangleStateCreateFlagsEXT flags; - VkDiscardRectangleModeEXT discardRectangleMode; - uint32_t discardRectangleCount; - const VkRect2D *pDiscardRectangles; -} VkPipelineDiscardRectangleStateCreateInfoEXT; - -typedef struct VkPipelineExecutableStatisticKHR -{ - VkStructureType sType; - void *pNext; - char name[VK_MAX_DESCRIPTION_SIZE]; - char description[VK_MAX_DESCRIPTION_SIZE]; - VkPipelineExecutableStatisticFormatKHR format; - VkPipelineExecutableStatisticValueKHR WINE_VK_ALIGN(8) value; -} VkPipelineExecutableStatisticKHR; - -typedef struct VkPipelineLayoutCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkPipelineLayoutCreateFlags flags; - uint32_t setLayoutCount; - const VkDescriptorSetLayout *pSetLayouts; - uint32_t pushConstantRangeCount; - const VkPushConstantRange *pPushConstantRanges; -} VkPipelineLayoutCreateInfo; - -typedef struct VkPipelineSampleLocationsStateCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkBool32 sampleLocationsEnable; - VkSampleLocationsInfoEXT sampleLocationsInfo; -} VkPipelineSampleLocationsStateCreateInfoEXT; - -typedef struct VkPipelineVertexInputDivisorStateCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - uint32_t vertexBindingDivisorCount; - const VkVertexInputBindingDivisorDescriptionEXT *pVertexBindingDivisors; -} VkPipelineVertexInputDivisorStateCreateInfoEXT; - -typedef struct VkPipelineVertexInputStateCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkPipelineVertexInputStateCreateFlags flags; - uint32_t vertexBindingDescriptionCount; - const VkVertexInputBindingDescription *pVertexBindingDescriptions; - uint32_t vertexAttributeDescriptionCount; - const VkVertexInputAttributeDescription *pVertexAttributeDescriptions; -} VkPipelineVertexInputStateCreateInfo; - -typedef struct VkPipelineViewportExclusiveScissorStateCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - uint32_t exclusiveScissorCount; - const VkRect2D *pExclusiveScissors; -} VkPipelineViewportExclusiveScissorStateCreateInfoNV; - -typedef struct VkPipelineViewportShadingRateImageStateCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - VkBool32 shadingRateImageEnable; - uint32_t viewportCount; - const VkShadingRatePaletteNV *pShadingRatePalettes; -} VkPipelineViewportShadingRateImageStateCreateInfoNV; - -typedef struct VkPipelineViewportStateCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkPipelineViewportStateCreateFlags flags; - uint32_t viewportCount; - const VkViewport *pViewports; - uint32_t scissorCount; - const VkRect2D *pScissors; -} VkPipelineViewportStateCreateInfo; - -typedef struct VkPipelineViewportSwizzleStateCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - VkPipelineViewportSwizzleStateCreateFlagsNV flags; - uint32_t viewportCount; - const VkViewportSwizzleNV *pViewportSwizzles; -} VkPipelineViewportSwizzleStateCreateInfoNV; - -typedef struct VkPipelineViewportWScalingStateCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - VkBool32 viewportWScalingEnable; - uint32_t viewportCount; - const VkViewportWScalingNV *pViewportWScalings; -} VkPipelineViewportWScalingStateCreateInfoNV; - -typedef struct VkPresentRegionKHR -{ - uint32_t rectangleCount; - const VkRectLayerKHR *pRectangles; -} VkPresentRegionKHR; - -typedef struct VkPresentRegionsKHR -{ - VkStructureType sType; - const void *pNext; - uint32_t swapchainCount; - const VkPresentRegionKHR *pRegions; -} VkPresentRegionsKHR; - -typedef struct VkRenderPassCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkRenderPassCreateFlags flags; - uint32_t attachmentCount; - const VkAttachmentDescription *pAttachments; - uint32_t subpassCount; - const VkSubpassDescription *pSubpasses; - uint32_t dependencyCount; - const VkSubpassDependency *pDependencies; -} VkRenderPassCreateInfo; - -typedef struct VkRenderPassCreateInfo2 -{ - VkStructureType sType; - const void *pNext; - VkRenderPassCreateFlags flags; - uint32_t attachmentCount; - const VkAttachmentDescription2 *pAttachments; - uint32_t subpassCount; - const VkSubpassDescription2 *pSubpasses; - uint32_t dependencyCount; - const VkSubpassDependency2 *pDependencies; - uint32_t correlatedViewMaskCount; - const uint32_t *pCorrelatedViewMasks; -} VkRenderPassCreateInfo2; -typedef VkRenderPassCreateInfo2 VkRenderPassCreateInfo2KHR; - -typedef struct VkRenderPassCreationFeedbackCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkRenderPassCreationFeedbackInfoEXT *pRenderPassFeedback; -} VkRenderPassCreationFeedbackCreateInfoEXT; - -typedef struct VkRenderPassSampleLocationsBeginInfoEXT -{ - VkStructureType sType; - const void *pNext; - uint32_t attachmentInitialSampleLocationsCount; - const VkAttachmentSampleLocationsEXT *pAttachmentInitialSampleLocations; - uint32_t postSubpassSampleLocationsCount; - const VkSubpassSampleLocationsEXT *pPostSubpassSampleLocations; -} VkRenderPassSampleLocationsBeginInfoEXT; - -typedef struct VkRenderPassSubpassFeedbackCreateInfoEXT -{ - VkStructureType sType; - const void *pNext; - VkRenderPassSubpassFeedbackInfoEXT *pSubpassFeedback; -} VkRenderPassSubpassFeedbackCreateInfoEXT; - -typedef struct VkResolveImageInfo2 -{ - VkStructureType sType; - const void *pNext; - VkImage WINE_VK_ALIGN(8) srcImage; - VkImageLayout srcImageLayout; - VkImage WINE_VK_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - const VkImageResolve2 *pRegions; -} VkResolveImageInfo2; -typedef VkResolveImageInfo2 VkResolveImageInfo2KHR; - -typedef struct VkSparseBufferMemoryBindInfo -{ - VkBuffer WINE_VK_ALIGN(8) buffer; - uint32_t bindCount; - const VkSparseMemoryBind *pBinds; -} VkSparseBufferMemoryBindInfo; - -typedef struct VkSparseImageOpaqueMemoryBindInfo -{ - VkImage WINE_VK_ALIGN(8) image; - uint32_t bindCount; - const VkSparseMemoryBind *pBinds; -} VkSparseImageOpaqueMemoryBindInfo; - -typedef struct VkSpecializationInfo -{ - uint32_t mapEntryCount; - const VkSpecializationMapEntry *pMapEntries; - size_t dataSize; - const void *pData; -} VkSpecializationInfo; - -typedef struct VkSurfaceCapabilities2KHR -{ - VkStructureType sType; - void *pNext; - VkSurfaceCapabilitiesKHR surfaceCapabilities; -} VkSurfaceCapabilities2KHR; - -typedef struct VkSurfaceFormat2KHR -{ - VkStructureType sType; - void *pNext; - VkSurfaceFormatKHR surfaceFormat; -} VkSurfaceFormat2KHR; - -typedef union VkAccelerationStructureGeometryDataKHR -{ - VkAccelerationStructureGeometryTrianglesDataKHR WINE_VK_ALIGN(8) triangles; - VkAccelerationStructureGeometryAabbsDataKHR WINE_VK_ALIGN(8) aabbs; - VkAccelerationStructureGeometryInstancesDataKHR WINE_VK_ALIGN(8) instances; -} VkAccelerationStructureGeometryDataKHR; - -typedef struct VkAccelerationStructureGeometryKHR -{ - VkStructureType sType; - const void *pNext; - VkGeometryTypeKHR geometryType; - VkAccelerationStructureGeometryDataKHR WINE_VK_ALIGN(8) geometry; - VkGeometryFlagsKHR flags; -} VkAccelerationStructureGeometryKHR; - -typedef struct VkAccelerationStructureInfoNV -{ - VkStructureType sType; - const void *pNext; - VkAccelerationStructureTypeNV type; - VkBuildAccelerationStructureFlagsNV flags; - uint32_t instanceCount; - uint32_t geometryCount; - const VkGeometryNV *pGeometries; -} VkAccelerationStructureInfoNV; - -typedef union VkAccelerationStructureMotionInstanceDataNV -{ - VkAccelerationStructureInstanceKHR WINE_VK_ALIGN(8) staticInstance; - VkAccelerationStructureMatrixMotionInstanceNV WINE_VK_ALIGN(8) matrixMotionInstance; - VkAccelerationStructureSRTMotionInstanceNV WINE_VK_ALIGN(8) srtMotionInstance; -} VkAccelerationStructureMotionInstanceDataNV; - -typedef struct VkAccelerationStructureMotionInstanceNV -{ - VkAccelerationStructureMotionInstanceTypeNV type; - VkAccelerationStructureMotionInstanceFlagsNV flags; - VkAccelerationStructureMotionInstanceDataNV WINE_VK_ALIGN(8) data; -} VkAccelerationStructureMotionInstanceNV; - -typedef struct VkBindSparseInfo -{ - VkStructureType sType; - const void *pNext; - uint32_t waitSemaphoreCount; - const VkSemaphore *pWaitSemaphores; - uint32_t bufferBindCount; - const VkSparseBufferMemoryBindInfo *pBufferBinds; - uint32_t imageOpaqueBindCount; - const VkSparseImageOpaqueMemoryBindInfo *pImageOpaqueBinds; - uint32_t imageBindCount; - const VkSparseImageMemoryBindInfo *pImageBinds; - uint32_t signalSemaphoreCount; - const VkSemaphore *pSignalSemaphores; -} VkBindSparseInfo; - -typedef struct VkBlitImageInfo2 -{ - VkStructureType sType; - const void *pNext; - VkImage WINE_VK_ALIGN(8) srcImage; - VkImageLayout srcImageLayout; - VkImage WINE_VK_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - const VkImageBlit2 *pRegions; - VkFilter filter; -} VkBlitImageInfo2; -typedef VkBlitImageInfo2 VkBlitImageInfo2KHR; - -typedef struct VkCopyImageInfo2 -{ - VkStructureType sType; - const void *pNext; - VkImage WINE_VK_ALIGN(8) srcImage; - VkImageLayout srcImageLayout; - VkImage WINE_VK_ALIGN(8) dstImage; - VkImageLayout dstImageLayout; - uint32_t regionCount; - const VkImageCopy2 *pRegions; -} VkCopyImageInfo2; -typedef VkCopyImageInfo2 VkCopyImageInfo2KHR; - -typedef struct VkDependencyInfo -{ - VkStructureType sType; - const void *pNext; - VkDependencyFlags dependencyFlags; - uint32_t memoryBarrierCount; - const VkMemoryBarrier2 *pMemoryBarriers; - uint32_t bufferMemoryBarrierCount; - const VkBufferMemoryBarrier2 *pBufferMemoryBarriers; - uint32_t imageMemoryBarrierCount; - const VkImageMemoryBarrier2 *pImageMemoryBarriers; -} VkDependencyInfo; -typedef VkDependencyInfo VkDependencyInfoKHR; - -typedef struct VkPipelineShaderStageCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkPipelineShaderStageCreateFlags flags; - VkShaderStageFlagBits stage; - VkShaderModule WINE_VK_ALIGN(8) module; - const char *pName; - const VkSpecializationInfo *pSpecializationInfo; -} VkPipelineShaderStageCreateInfo; - -typedef struct VkRayTracingPipelineCreateInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkPipelineCreateFlags flags; - uint32_t stageCount; - const VkPipelineShaderStageCreateInfo *pStages; - uint32_t groupCount; - const VkRayTracingShaderGroupCreateInfoKHR *pGroups; - uint32_t maxPipelineRayRecursionDepth; - const VkPipelineLibraryCreateInfoKHR *pLibraryInfo; - const VkRayTracingPipelineInterfaceCreateInfoKHR *pLibraryInterface; - const VkPipelineDynamicStateCreateInfo *pDynamicState; - VkPipelineLayout WINE_VK_ALIGN(8) layout; - VkPipeline WINE_VK_ALIGN(8) basePipelineHandle; - int32_t basePipelineIndex; -} VkRayTracingPipelineCreateInfoKHR; - -typedef struct VkRayTracingPipelineCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - VkPipelineCreateFlags flags; - uint32_t stageCount; - const VkPipelineShaderStageCreateInfo *pStages; - uint32_t groupCount; - const VkRayTracingShaderGroupCreateInfoNV *pGroups; - uint32_t maxRecursionDepth; - VkPipelineLayout WINE_VK_ALIGN(8) layout; - VkPipeline WINE_VK_ALIGN(8) basePipelineHandle; - int32_t basePipelineIndex; -} VkRayTracingPipelineCreateInfoNV; - -typedef struct VkAccelerationStructureBuildGeometryInfoKHR -{ - VkStructureType sType; - const void *pNext; - VkAccelerationStructureTypeKHR type; - VkBuildAccelerationStructureFlagsKHR flags; - VkBuildAccelerationStructureModeKHR mode; - VkAccelerationStructureKHR WINE_VK_ALIGN(8) srcAccelerationStructure; - VkAccelerationStructureKHR WINE_VK_ALIGN(8) dstAccelerationStructure; - uint32_t geometryCount; - const VkAccelerationStructureGeometryKHR *pGeometries; - const VkAccelerationStructureGeometryKHR * const*ppGeometries; - VkDeviceOrHostAddressKHR WINE_VK_ALIGN(8) scratchData; -} VkAccelerationStructureBuildGeometryInfoKHR; - -typedef struct VkAccelerationStructureCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - VkDeviceSize WINE_VK_ALIGN(8) compactedSize; - VkAccelerationStructureInfoNV info; -} VkAccelerationStructureCreateInfoNV; - -typedef struct VkComputePipelineCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkPipelineCreateFlags flags; - VkPipelineShaderStageCreateInfo WINE_VK_ALIGN(8) stage; - VkPipelineLayout WINE_VK_ALIGN(8) layout; - VkPipeline WINE_VK_ALIGN(8) basePipelineHandle; - int32_t basePipelineIndex; -} VkComputePipelineCreateInfo; - -typedef struct VkGraphicsPipelineCreateInfo -{ - VkStructureType sType; - const void *pNext; - VkPipelineCreateFlags flags; - uint32_t stageCount; - const VkPipelineShaderStageCreateInfo *pStages; - const VkPipelineVertexInputStateCreateInfo *pVertexInputState; - const VkPipelineInputAssemblyStateCreateInfo *pInputAssemblyState; - const VkPipelineTessellationStateCreateInfo *pTessellationState; - const VkPipelineViewportStateCreateInfo *pViewportState; - const VkPipelineRasterizationStateCreateInfo *pRasterizationState; - const VkPipelineMultisampleStateCreateInfo *pMultisampleState; - const VkPipelineDepthStencilStateCreateInfo *pDepthStencilState; - const VkPipelineColorBlendStateCreateInfo *pColorBlendState; - const VkPipelineDynamicStateCreateInfo *pDynamicState; - VkPipelineLayout WINE_VK_ALIGN(8) layout; - VkRenderPass WINE_VK_ALIGN(8) renderPass; - uint32_t subpass; - VkPipeline WINE_VK_ALIGN(8) basePipelineHandle; - int32_t basePipelineIndex; -} VkGraphicsPipelineCreateInfo; - -typedef struct VkGraphicsShaderGroupCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - uint32_t stageCount; - const VkPipelineShaderStageCreateInfo *pStages; - const VkPipelineVertexInputStateCreateInfo *pVertexInputState; - const VkPipelineTessellationStateCreateInfo *pTessellationState; -} VkGraphicsShaderGroupCreateInfoNV; - -typedef struct VkGraphicsPipelineShaderGroupsCreateInfoNV -{ - VkStructureType sType; - const void *pNext; - uint32_t groupCount; - const VkGraphicsShaderGroupCreateInfoNV *pGroups; - uint32_t pipelineCount; - const VkPipeline *pPipelines; -} VkGraphicsPipelineShaderGroupsCreateInfoNV; - -typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImage2KHR)(VkDevice, const VkAcquireNextImageInfoKHR *, uint32_t *); -typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImageKHR)(VkDevice, VkSwapchainKHR, uint64_t, VkSemaphore, VkFence, uint32_t *); -typedef VkResult (VKAPI_PTR *PFN_vkAcquirePerformanceConfigurationINTEL)(VkDevice, const VkPerformanceConfigurationAcquireInfoINTEL *, VkPerformanceConfigurationINTEL *); -typedef VkResult (VKAPI_PTR *PFN_vkAcquireProfilingLockKHR)(VkDevice, const VkAcquireProfilingLockInfoKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkAllocateCommandBuffers)(VkDevice, const VkCommandBufferAllocateInfo *, VkCommandBuffer *); -typedef VkResult (VKAPI_PTR *PFN_vkAllocateDescriptorSets)(VkDevice, const VkDescriptorSetAllocateInfo *, VkDescriptorSet *); -typedef VkResult (VKAPI_PTR *PFN_vkAllocateMemory)(VkDevice, const VkMemoryAllocateInfo *, const VkAllocationCallbacks *, VkDeviceMemory *); -typedef VkResult (VKAPI_PTR *PFN_vkBeginCommandBuffer)(VkCommandBuffer, const VkCommandBufferBeginInfo *); -typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNV)(VkDevice, uint32_t, const VkBindAccelerationStructureMemoryInfoNV *); -typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory)(VkDevice, VkBuffer, VkDeviceMemory, VkDeviceSize); -typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2)(VkDevice, uint32_t, const VkBindBufferMemoryInfo *); -typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2KHR)(VkDevice, uint32_t, const VkBindBufferMemoryInfo *); -typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory)(VkDevice, VkImage, VkDeviceMemory, VkDeviceSize); -typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2)(VkDevice, uint32_t, const VkBindImageMemoryInfo *); -typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2KHR)(VkDevice, uint32_t, const VkBindImageMemoryInfo *); -typedef VkResult (VKAPI_PTR *PFN_vkBindOpticalFlowSessionImageNV)(VkDevice, VkOpticalFlowSessionNV, VkOpticalFlowSessionBindingPointNV, VkImageView, VkImageLayout); -typedef VkResult (VKAPI_PTR *PFN_vkBuildAccelerationStructuresKHR)(VkDevice, VkDeferredOperationKHR, uint32_t, const VkAccelerationStructureBuildGeometryInfoKHR *, const VkAccelerationStructureBuildRangeInfoKHR * const*); -typedef VkResult (VKAPI_PTR *PFN_vkBuildMicromapsEXT)(VkDevice, VkDeferredOperationKHR, uint32_t, const VkMicromapBuildInfoEXT *); -typedef void (VKAPI_PTR *PFN_vkCmdBeginConditionalRenderingEXT)(VkCommandBuffer, const VkConditionalRenderingBeginInfoEXT *); -typedef void (VKAPI_PTR *PFN_vkCmdBeginDebugUtilsLabelEXT)(VkCommandBuffer, const VkDebugUtilsLabelEXT *); -typedef void (VKAPI_PTR *PFN_vkCmdBeginQuery)(VkCommandBuffer, VkQueryPool, uint32_t, VkQueryControlFlags); -typedef void (VKAPI_PTR *PFN_vkCmdBeginQueryIndexedEXT)(VkCommandBuffer, VkQueryPool, uint32_t, VkQueryControlFlags, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass)(VkCommandBuffer, const VkRenderPassBeginInfo *, VkSubpassContents); -typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass2)(VkCommandBuffer, const VkRenderPassBeginInfo *, const VkSubpassBeginInfo *); -typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderPass2KHR)(VkCommandBuffer, const VkRenderPassBeginInfo *, const VkSubpassBeginInfo *); -typedef void (VKAPI_PTR *PFN_vkCmdBeginRendering)(VkCommandBuffer, const VkRenderingInfo *); -typedef void (VKAPI_PTR *PFN_vkCmdBeginRenderingKHR)(VkCommandBuffer, const VkRenderingInfo *); -typedef void (VKAPI_PTR *PFN_vkCmdBeginTransformFeedbackEXT)(VkCommandBuffer, uint32_t, uint32_t, const VkBuffer *, const VkDeviceSize *); -typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorBufferEmbeddedSamplersEXT)(VkCommandBuffer, VkPipelineBindPoint, VkPipelineLayout, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorBuffersEXT)(VkCommandBuffer, uint32_t, const VkDescriptorBufferBindingInfoEXT *); -typedef void (VKAPI_PTR *PFN_vkCmdBindDescriptorSets)(VkCommandBuffer, VkPipelineBindPoint, VkPipelineLayout, uint32_t, uint32_t, const VkDescriptorSet *, uint32_t, const uint32_t *); -typedef void (VKAPI_PTR *PFN_vkCmdBindIndexBuffer)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkIndexType); -typedef void (VKAPI_PTR *PFN_vkCmdBindInvocationMaskHUAWEI)(VkCommandBuffer, VkImageView, VkImageLayout); -typedef void (VKAPI_PTR *PFN_vkCmdBindPipeline)(VkCommandBuffer, VkPipelineBindPoint, VkPipeline); -typedef void (VKAPI_PTR *PFN_vkCmdBindPipelineShaderGroupNV)(VkCommandBuffer, VkPipelineBindPoint, VkPipeline, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdBindShadingRateImageNV)(VkCommandBuffer, VkImageView, VkImageLayout); -typedef void (VKAPI_PTR *PFN_vkCmdBindTransformFeedbackBuffersEXT)(VkCommandBuffer, uint32_t, uint32_t, const VkBuffer *, const VkDeviceSize *, const VkDeviceSize *); -typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers)(VkCommandBuffer, uint32_t, uint32_t, const VkBuffer *, const VkDeviceSize *); -typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers2)(VkCommandBuffer, uint32_t, uint32_t, const VkBuffer *, const VkDeviceSize *, const VkDeviceSize *, const VkDeviceSize *); -typedef void (VKAPI_PTR *PFN_vkCmdBindVertexBuffers2EXT)(VkCommandBuffer, uint32_t, uint32_t, const VkBuffer *, const VkDeviceSize *, const VkDeviceSize *, const VkDeviceSize *); -typedef void (VKAPI_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer, VkImage, VkImageLayout, VkImage, VkImageLayout, uint32_t, const VkImageBlit *, VkFilter); -typedef void (VKAPI_PTR *PFN_vkCmdBlitImage2)(VkCommandBuffer, const VkBlitImageInfo2 *); -typedef void (VKAPI_PTR *PFN_vkCmdBlitImage2KHR)(VkCommandBuffer, const VkBlitImageInfo2 *); -typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNV)(VkCommandBuffer, const VkAccelerationStructureInfoNV *, VkBuffer, VkDeviceSize, VkBool32, VkAccelerationStructureNV, VkAccelerationStructureNV, VkBuffer, VkDeviceSize); -typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructuresIndirectKHR)(VkCommandBuffer, uint32_t, const VkAccelerationStructureBuildGeometryInfoKHR *, const VkDeviceAddress *, const uint32_t *, const uint32_t * const*); -typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructuresKHR)(VkCommandBuffer, uint32_t, const VkAccelerationStructureBuildGeometryInfoKHR *, const VkAccelerationStructureBuildRangeInfoKHR * const*); -typedef void (VKAPI_PTR *PFN_vkCmdBuildMicromapsEXT)(VkCommandBuffer, uint32_t, const VkMicromapBuildInfoEXT *); -typedef void (VKAPI_PTR *PFN_vkCmdClearAttachments)(VkCommandBuffer, uint32_t, const VkClearAttachment *, uint32_t, const VkClearRect *); -typedef void (VKAPI_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer, VkImage, VkImageLayout, const VkClearColorValue *, uint32_t, const VkImageSubresourceRange *); -typedef void (VKAPI_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer, VkImage, VkImageLayout, const VkClearDepthStencilValue *, uint32_t, const VkImageSubresourceRange *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureKHR)(VkCommandBuffer, const VkCopyAccelerationStructureInfoKHR *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNV)(VkCommandBuffer, VkAccelerationStructureNV, VkAccelerationStructureNV, VkCopyAccelerationStructureModeKHR); -typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureToMemoryKHR)(VkCommandBuffer, const VkCopyAccelerationStructureToMemoryInfoKHR *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer, VkBuffer, VkBuffer, uint32_t, const VkBufferCopy *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer2)(VkCommandBuffer, const VkCopyBufferInfo2 *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer2KHR)(VkCommandBuffer, const VkCopyBufferInfo2 *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer, VkBuffer, VkImage, VkImageLayout, uint32_t, const VkBufferImageCopy *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage2)(VkCommandBuffer, const VkCopyBufferToImageInfo2 *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage2KHR)(VkCommandBuffer, const VkCopyBufferToImageInfo2 *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer, VkImage, VkImageLayout, VkImage, VkImageLayout, uint32_t, const VkImageCopy *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyImage2)(VkCommandBuffer, const VkCopyImageInfo2 *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyImage2KHR)(VkCommandBuffer, const VkCopyImageInfo2 *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer, VkImage, VkImageLayout, VkBuffer, uint32_t, const VkBufferImageCopy *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer2)(VkCommandBuffer, const VkCopyImageToBufferInfo2 *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer2KHR)(VkCommandBuffer, const VkCopyImageToBufferInfo2 *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryIndirectNV)(VkCommandBuffer, VkDeviceAddress, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryToAccelerationStructureKHR)(VkCommandBuffer, const VkCopyMemoryToAccelerationStructureInfoKHR *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryToImageIndirectNV)(VkCommandBuffer, VkDeviceAddress, uint32_t, uint32_t, VkImage, VkImageLayout, const VkImageSubresourceLayers *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyMemoryToMicromapEXT)(VkCommandBuffer, const VkCopyMemoryToMicromapInfoEXT *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyMicromapEXT)(VkCommandBuffer, const VkCopyMicromapInfoEXT *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyMicromapToMemoryEXT)(VkCommandBuffer, const VkCopyMicromapToMemoryInfoEXT *); -typedef void (VKAPI_PTR *PFN_vkCmdCopyQueryPoolResults)(VkCommandBuffer, VkQueryPool, uint32_t, uint32_t, VkBuffer, VkDeviceSize, VkDeviceSize, VkQueryResultFlags); -typedef void (VKAPI_PTR *PFN_vkCmdCuLaunchKernelNVX)(VkCommandBuffer, const VkCuLaunchInfoNVX *); -typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerBeginEXT)(VkCommandBuffer, const VkDebugMarkerMarkerInfoEXT *); -typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerEndEXT)(VkCommandBuffer); -typedef void (VKAPI_PTR *PFN_vkCmdDebugMarkerInsertEXT)(VkCommandBuffer, const VkDebugMarkerMarkerInfoEXT *); -typedef void (VKAPI_PTR *PFN_vkCmdDecompressMemoryIndirectCountNV)(VkCommandBuffer, VkDeviceAddress, VkDeviceAddress, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDecompressMemoryNV)(VkCommandBuffer, uint32_t, const VkDecompressMemoryRegionNV *); -typedef void (VKAPI_PTR *PFN_vkCmdDispatch)(VkCommandBuffer, uint32_t, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDispatchBase)(VkCommandBuffer, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDispatchBaseKHR)(VkCommandBuffer, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer, VkBuffer, VkDeviceSize); -typedef void (VKAPI_PTR *PFN_vkCmdDraw)(VkCommandBuffer, uint32_t, uint32_t, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer, VkBuffer, VkDeviceSize, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCount)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountAMD)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountKHR)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirect)(VkCommandBuffer, VkBuffer, VkDeviceSize, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectByteCountEXT)(VkCommandBuffer, uint32_t, uint32_t, VkBuffer, VkDeviceSize, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCount)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountAMD)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountKHR)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksEXT)(VkCommandBuffer, uint32_t, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectCountEXT)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectCountNV)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectEXT)(VkCommandBuffer, VkBuffer, VkDeviceSize, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectNV)(VkCommandBuffer, VkBuffer, VkDeviceSize, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksNV)(VkCommandBuffer, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawMultiEXT)(VkCommandBuffer, uint32_t, const VkMultiDrawInfoEXT *, uint32_t, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdDrawMultiIndexedEXT)(VkCommandBuffer, uint32_t, const VkMultiDrawIndexedInfoEXT *, uint32_t, uint32_t, uint32_t, const int32_t *); -typedef void (VKAPI_PTR *PFN_vkCmdEndConditionalRenderingEXT)(VkCommandBuffer); -typedef void (VKAPI_PTR *PFN_vkCmdEndDebugUtilsLabelEXT)(VkCommandBuffer); -typedef void (VKAPI_PTR *PFN_vkCmdEndQuery)(VkCommandBuffer, VkQueryPool, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdEndQueryIndexedEXT)(VkCommandBuffer, VkQueryPool, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass)(VkCommandBuffer); -typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass2)(VkCommandBuffer, const VkSubpassEndInfo *); -typedef void (VKAPI_PTR *PFN_vkCmdEndRenderPass2KHR)(VkCommandBuffer, const VkSubpassEndInfo *); -typedef void (VKAPI_PTR *PFN_vkCmdEndRendering)(VkCommandBuffer); -typedef void (VKAPI_PTR *PFN_vkCmdEndRenderingKHR)(VkCommandBuffer); -typedef void (VKAPI_PTR *PFN_vkCmdEndTransformFeedbackEXT)(VkCommandBuffer, uint32_t, uint32_t, const VkBuffer *, const VkDeviceSize *); -typedef void (VKAPI_PTR *PFN_vkCmdExecuteCommands)(VkCommandBuffer, uint32_t, const VkCommandBuffer *); -typedef void (VKAPI_PTR *PFN_vkCmdExecuteGeneratedCommandsNV)(VkCommandBuffer, VkBool32, const VkGeneratedCommandsInfoNV *); -typedef void (VKAPI_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkDeviceSize, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdInsertDebugUtilsLabelEXT)(VkCommandBuffer, const VkDebugUtilsLabelEXT *); -typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass)(VkCommandBuffer, VkSubpassContents); -typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass2)(VkCommandBuffer, const VkSubpassBeginInfo *, const VkSubpassEndInfo *); -typedef void (VKAPI_PTR *PFN_vkCmdNextSubpass2KHR)(VkCommandBuffer, const VkSubpassBeginInfo *, const VkSubpassEndInfo *); -typedef void (VKAPI_PTR *PFN_vkCmdOpticalFlowExecuteNV)(VkCommandBuffer, VkOpticalFlowSessionNV, const VkOpticalFlowExecuteInfoNV *); -typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier)(VkCommandBuffer, VkPipelineStageFlags, VkPipelineStageFlags, VkDependencyFlags, uint32_t, const VkMemoryBarrier *, uint32_t, const VkBufferMemoryBarrier *, uint32_t, const VkImageMemoryBarrier *); -typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier2)(VkCommandBuffer, const VkDependencyInfo *); -typedef void (VKAPI_PTR *PFN_vkCmdPipelineBarrier2KHR)(VkCommandBuffer, const VkDependencyInfo *); -typedef void (VKAPI_PTR *PFN_vkCmdPreprocessGeneratedCommandsNV)(VkCommandBuffer, const VkGeneratedCommandsInfoNV *); -typedef void (VKAPI_PTR *PFN_vkCmdPushConstants)(VkCommandBuffer, VkPipelineLayout, VkShaderStageFlags, uint32_t, uint32_t, const void *); -typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetKHR)(VkCommandBuffer, VkPipelineBindPoint, VkPipelineLayout, uint32_t, uint32_t, const VkWriteDescriptorSet *); -typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplateKHR)(VkCommandBuffer, VkDescriptorUpdateTemplate, VkPipelineLayout, uint32_t, const void *); -typedef void (VKAPI_PTR *PFN_vkCmdResetEvent)(VkCommandBuffer, VkEvent, VkPipelineStageFlags); -typedef void (VKAPI_PTR *PFN_vkCmdResetEvent2)(VkCommandBuffer, VkEvent, VkPipelineStageFlags2); -typedef void (VKAPI_PTR *PFN_vkCmdResetEvent2KHR)(VkCommandBuffer, VkEvent, VkPipelineStageFlags2); -typedef void (VKAPI_PTR *PFN_vkCmdResetQueryPool)(VkCommandBuffer, VkQueryPool, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdResolveImage)(VkCommandBuffer, VkImage, VkImageLayout, VkImage, VkImageLayout, uint32_t, const VkImageResolve *); -typedef void (VKAPI_PTR *PFN_vkCmdResolveImage2)(VkCommandBuffer, const VkResolveImageInfo2 *); -typedef void (VKAPI_PTR *PFN_vkCmdResolveImage2KHR)(VkCommandBuffer, const VkResolveImageInfo2 *); -typedef void (VKAPI_PTR *PFN_vkCmdSetAlphaToCoverageEnableEXT)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetAlphaToOneEnableEXT)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetBlendConstants)(VkCommandBuffer, const float[4]); -typedef void (VKAPI_PTR *PFN_vkCmdSetCheckpointNV)(VkCommandBuffer, const void *); -typedef void (VKAPI_PTR *PFN_vkCmdSetCoarseSampleOrderNV)(VkCommandBuffer, VkCoarseSampleOrderTypeNV, uint32_t, const VkCoarseSampleOrderCustomNV *); -typedef void (VKAPI_PTR *PFN_vkCmdSetColorBlendAdvancedEXT)(VkCommandBuffer, uint32_t, uint32_t, const VkColorBlendAdvancedEXT *); -typedef void (VKAPI_PTR *PFN_vkCmdSetColorBlendEnableEXT)(VkCommandBuffer, uint32_t, uint32_t, const VkBool32 *); -typedef void (VKAPI_PTR *PFN_vkCmdSetColorBlendEquationEXT)(VkCommandBuffer, uint32_t, uint32_t, const VkColorBlendEquationEXT *); -typedef void (VKAPI_PTR *PFN_vkCmdSetColorWriteEnableEXT)(VkCommandBuffer, uint32_t, const VkBool32 *); -typedef void (VKAPI_PTR *PFN_vkCmdSetColorWriteMaskEXT)(VkCommandBuffer, uint32_t, uint32_t, const VkColorComponentFlags *); -typedef void (VKAPI_PTR *PFN_vkCmdSetConservativeRasterizationModeEXT)(VkCommandBuffer, VkConservativeRasterizationModeEXT); -typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageModulationModeNV)(VkCommandBuffer, VkCoverageModulationModeNV); -typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageModulationTableEnableNV)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageModulationTableNV)(VkCommandBuffer, uint32_t, const float *); -typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageReductionModeNV)(VkCommandBuffer, VkCoverageReductionModeNV); -typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageToColorEnableNV)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetCoverageToColorLocationNV)(VkCommandBuffer, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdSetCullMode)(VkCommandBuffer, VkCullModeFlags); -typedef void (VKAPI_PTR *PFN_vkCmdSetCullModeEXT)(VkCommandBuffer, VkCullModeFlags); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBias)(VkCommandBuffer, float, float, float); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBiasEnable)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBiasEnableEXT)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBounds)(VkCommandBuffer, float, float); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBoundsTestEnable)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthBoundsTestEnableEXT)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthClampEnableEXT)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthClipEnableEXT)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthClipNegativeOneToOneEXT)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthCompareOp)(VkCommandBuffer, VkCompareOp); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthCompareOpEXT)(VkCommandBuffer, VkCompareOp); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthTestEnable)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthTestEnableEXT)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthWriteEnable)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetDepthWriteEnableEXT)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetDescriptorBufferOffsetsEXT)(VkCommandBuffer, VkPipelineBindPoint, VkPipelineLayout, uint32_t, uint32_t, const uint32_t *, const VkDeviceSize *); -typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMask)(VkCommandBuffer, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMaskKHR)(VkCommandBuffer, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdSetDiscardRectangleEXT)(VkCommandBuffer, uint32_t, uint32_t, const VkRect2D *); -typedef void (VKAPI_PTR *PFN_vkCmdSetEvent)(VkCommandBuffer, VkEvent, VkPipelineStageFlags); -typedef void (VKAPI_PTR *PFN_vkCmdSetEvent2)(VkCommandBuffer, VkEvent, const VkDependencyInfo *); -typedef void (VKAPI_PTR *PFN_vkCmdSetEvent2KHR)(VkCommandBuffer, VkEvent, const VkDependencyInfo *); -typedef void (VKAPI_PTR *PFN_vkCmdSetExclusiveScissorNV)(VkCommandBuffer, uint32_t, uint32_t, const VkRect2D *); -typedef void (VKAPI_PTR *PFN_vkCmdSetExtraPrimitiveOverestimationSizeEXT)(VkCommandBuffer, float); -typedef void (VKAPI_PTR *PFN_vkCmdSetFragmentShadingRateEnumNV)(VkCommandBuffer, VkFragmentShadingRateNV, const VkFragmentShadingRateCombinerOpKHR[2]); -typedef void (VKAPI_PTR *PFN_vkCmdSetFragmentShadingRateKHR)(VkCommandBuffer, const VkExtent2D *, const VkFragmentShadingRateCombinerOpKHR[2]); -typedef void (VKAPI_PTR *PFN_vkCmdSetFrontFace)(VkCommandBuffer, VkFrontFace); -typedef void (VKAPI_PTR *PFN_vkCmdSetFrontFaceEXT)(VkCommandBuffer, VkFrontFace); -typedef void (VKAPI_PTR *PFN_vkCmdSetLineRasterizationModeEXT)(VkCommandBuffer, VkLineRasterizationModeEXT); -typedef void (VKAPI_PTR *PFN_vkCmdSetLineStippleEXT)(VkCommandBuffer, uint32_t, uint16_t); -typedef void (VKAPI_PTR *PFN_vkCmdSetLineStippleEnableEXT)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetLineWidth)(VkCommandBuffer, float); -typedef void (VKAPI_PTR *PFN_vkCmdSetLogicOpEXT)(VkCommandBuffer, VkLogicOp); -typedef void (VKAPI_PTR *PFN_vkCmdSetLogicOpEnableEXT)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetPatchControlPointsEXT)(VkCommandBuffer, uint32_t); -typedef VkResult (VKAPI_PTR *PFN_vkCmdSetPerformanceMarkerINTEL)(VkCommandBuffer, const VkPerformanceMarkerInfoINTEL *); -typedef VkResult (VKAPI_PTR *PFN_vkCmdSetPerformanceOverrideINTEL)(VkCommandBuffer, const VkPerformanceOverrideInfoINTEL *); -typedef VkResult (VKAPI_PTR *PFN_vkCmdSetPerformanceStreamMarkerINTEL)(VkCommandBuffer, const VkPerformanceStreamMarkerInfoINTEL *); -typedef void (VKAPI_PTR *PFN_vkCmdSetPolygonModeEXT)(VkCommandBuffer, VkPolygonMode); -typedef void (VKAPI_PTR *PFN_vkCmdSetPrimitiveRestartEnable)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetPrimitiveRestartEnableEXT)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetPrimitiveTopology)(VkCommandBuffer, VkPrimitiveTopology); -typedef void (VKAPI_PTR *PFN_vkCmdSetPrimitiveTopologyEXT)(VkCommandBuffer, VkPrimitiveTopology); -typedef void (VKAPI_PTR *PFN_vkCmdSetProvokingVertexModeEXT)(VkCommandBuffer, VkProvokingVertexModeEXT); -typedef void (VKAPI_PTR *PFN_vkCmdSetRasterizationSamplesEXT)(VkCommandBuffer, VkSampleCountFlagBits); -typedef void (VKAPI_PTR *PFN_vkCmdSetRasterizationStreamEXT)(VkCommandBuffer, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdSetRasterizerDiscardEnable)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetRasterizerDiscardEnableEXT)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetRayTracingPipelineStackSizeKHR)(VkCommandBuffer, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdSetRepresentativeFragmentTestEnableNV)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetSampleLocationsEXT)(VkCommandBuffer, const VkSampleLocationsInfoEXT *); -typedef void (VKAPI_PTR *PFN_vkCmdSetSampleLocationsEnableEXT)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetSampleMaskEXT)(VkCommandBuffer, VkSampleCountFlagBits, const VkSampleMask *); -typedef void (VKAPI_PTR *PFN_vkCmdSetScissor)(VkCommandBuffer, uint32_t, uint32_t, const VkRect2D *); -typedef void (VKAPI_PTR *PFN_vkCmdSetScissorWithCount)(VkCommandBuffer, uint32_t, const VkRect2D *); -typedef void (VKAPI_PTR *PFN_vkCmdSetScissorWithCountEXT)(VkCommandBuffer, uint32_t, const VkRect2D *); -typedef void (VKAPI_PTR *PFN_vkCmdSetShadingRateImageEnableNV)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetStencilCompareMask)(VkCommandBuffer, VkStencilFaceFlags, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdSetStencilOp)(VkCommandBuffer, VkStencilFaceFlags, VkStencilOp, VkStencilOp, VkStencilOp, VkCompareOp); -typedef void (VKAPI_PTR *PFN_vkCmdSetStencilOpEXT)(VkCommandBuffer, VkStencilFaceFlags, VkStencilOp, VkStencilOp, VkStencilOp, VkCompareOp); -typedef void (VKAPI_PTR *PFN_vkCmdSetStencilReference)(VkCommandBuffer, VkStencilFaceFlags, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdSetStencilTestEnable)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetStencilTestEnableEXT)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetStencilWriteMask)(VkCommandBuffer, VkStencilFaceFlags, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdSetTessellationDomainOriginEXT)(VkCommandBuffer, VkTessellationDomainOrigin); -typedef void (VKAPI_PTR *PFN_vkCmdSetVertexInputEXT)(VkCommandBuffer, uint32_t, const VkVertexInputBindingDescription2EXT *, uint32_t, const VkVertexInputAttributeDescription2EXT *); -typedef void (VKAPI_PTR *PFN_vkCmdSetViewport)(VkCommandBuffer, uint32_t, uint32_t, const VkViewport *); -typedef void (VKAPI_PTR *PFN_vkCmdSetViewportShadingRatePaletteNV)(VkCommandBuffer, uint32_t, uint32_t, const VkShadingRatePaletteNV *); -typedef void (VKAPI_PTR *PFN_vkCmdSetViewportSwizzleNV)(VkCommandBuffer, uint32_t, uint32_t, const VkViewportSwizzleNV *); -typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWScalingEnableNV)(VkCommandBuffer, VkBool32); -typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWScalingNV)(VkCommandBuffer, uint32_t, uint32_t, const VkViewportWScalingNV *); -typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWithCount)(VkCommandBuffer, uint32_t, const VkViewport *); -typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWithCountEXT)(VkCommandBuffer, uint32_t, const VkViewport *); -typedef void (VKAPI_PTR *PFN_vkCmdSubpassShadingHUAWEI)(VkCommandBuffer); -typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysIndirect2KHR)(VkCommandBuffer, VkDeviceAddress); -typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysIndirectKHR)(VkCommandBuffer, const VkStridedDeviceAddressRegionKHR *, const VkStridedDeviceAddressRegionKHR *, const VkStridedDeviceAddressRegionKHR *, const VkStridedDeviceAddressRegionKHR *, VkDeviceAddress); -typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysKHR)(VkCommandBuffer, const VkStridedDeviceAddressRegionKHR *, const VkStridedDeviceAddressRegionKHR *, const VkStridedDeviceAddressRegionKHR *, const VkStridedDeviceAddressRegionKHR *, uint32_t, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNV)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkBuffer, VkDeviceSize, VkDeviceSize, VkBuffer, VkDeviceSize, VkDeviceSize, VkBuffer, VkDeviceSize, VkDeviceSize, uint32_t, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer, VkBuffer, VkDeviceSize, VkDeviceSize, const void *); -typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents)(VkCommandBuffer, uint32_t, const VkEvent *, VkPipelineStageFlags, VkPipelineStageFlags, uint32_t, const VkMemoryBarrier *, uint32_t, const VkBufferMemoryBarrier *, uint32_t, const VkImageMemoryBarrier *); -typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents2)(VkCommandBuffer, uint32_t, const VkEvent *, const VkDependencyInfo *); -typedef void (VKAPI_PTR *PFN_vkCmdWaitEvents2KHR)(VkCommandBuffer, uint32_t, const VkEvent *, const VkDependencyInfo *); -typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesKHR)(VkCommandBuffer, uint32_t, const VkAccelerationStructureKHR *, VkQueryType, VkQueryPool, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesNV)(VkCommandBuffer, uint32_t, const VkAccelerationStructureNV *, VkQueryType, VkQueryPool, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdWriteBufferMarker2AMD)(VkCommandBuffer, VkPipelineStageFlags2, VkBuffer, VkDeviceSize, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdWriteBufferMarkerAMD)(VkCommandBuffer, VkPipelineStageFlagBits, VkBuffer, VkDeviceSize, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdWriteMicromapsPropertiesEXT)(VkCommandBuffer, uint32_t, const VkMicromapEXT *, VkQueryType, VkQueryPool, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp)(VkCommandBuffer, VkPipelineStageFlagBits, VkQueryPool, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp2)(VkCommandBuffer, VkPipelineStageFlags2, VkQueryPool, uint32_t); -typedef void (VKAPI_PTR *PFN_vkCmdWriteTimestamp2KHR)(VkCommandBuffer, VkPipelineStageFlags2, VkQueryPool, uint32_t); -typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNV)(VkDevice, VkPipeline, uint32_t); -typedef VkResult (VKAPI_PTR *PFN_vkCopyAccelerationStructureKHR)(VkDevice, VkDeferredOperationKHR, const VkCopyAccelerationStructureInfoKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkCopyAccelerationStructureToMemoryKHR)(VkDevice, VkDeferredOperationKHR, const VkCopyAccelerationStructureToMemoryInfoKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkCopyMemoryToAccelerationStructureKHR)(VkDevice, VkDeferredOperationKHR, const VkCopyMemoryToAccelerationStructureInfoKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkCopyMemoryToMicromapEXT)(VkDevice, VkDeferredOperationKHR, const VkCopyMemoryToMicromapInfoEXT *); -typedef VkResult (VKAPI_PTR *PFN_vkCopyMicromapEXT)(VkDevice, VkDeferredOperationKHR, const VkCopyMicromapInfoEXT *); -typedef VkResult (VKAPI_PTR *PFN_vkCopyMicromapToMemoryEXT)(VkDevice, VkDeferredOperationKHR, const VkCopyMicromapToMemoryInfoEXT *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureKHR)(VkDevice, const VkAccelerationStructureCreateInfoKHR *, const VkAllocationCallbacks *, VkAccelerationStructureKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureNV)(VkDevice, const VkAccelerationStructureCreateInfoNV *, const VkAllocationCallbacks *, VkAccelerationStructureNV *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateBuffer)(VkDevice, const VkBufferCreateInfo *, const VkAllocationCallbacks *, VkBuffer *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateBufferView)(VkDevice, const VkBufferViewCreateInfo *, const VkAllocationCallbacks *, VkBufferView *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateCommandPool)(VkDevice, const VkCommandPoolCreateInfo *, const VkAllocationCallbacks *, VkCommandPool *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateComputePipelines)(VkDevice, VkPipelineCache, uint32_t, const VkComputePipelineCreateInfo *, const VkAllocationCallbacks *, VkPipeline *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateCuFunctionNVX)(VkDevice, const VkCuFunctionCreateInfoNVX *, const VkAllocationCallbacks *, VkCuFunctionNVX *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateCuModuleNVX)(VkDevice, const VkCuModuleCreateInfoNVX *, const VkAllocationCallbacks *, VkCuModuleNVX *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugReportCallbackEXT)(VkInstance, const VkDebugReportCallbackCreateInfoEXT *, const VkAllocationCallbacks *, VkDebugReportCallbackEXT *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDebugUtilsMessengerEXT)(VkInstance, const VkDebugUtilsMessengerCreateInfoEXT *, const VkAllocationCallbacks *, VkDebugUtilsMessengerEXT *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDeferredOperationKHR)(VkDevice, const VkAllocationCallbacks *, VkDeferredOperationKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorPool)(VkDevice, const VkDescriptorPoolCreateInfo *, const VkAllocationCallbacks *, VkDescriptorPool *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorSetLayout)(VkDevice, const VkDescriptorSetLayoutCreateInfo *, const VkAllocationCallbacks *, VkDescriptorSetLayout *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplate)(VkDevice, const VkDescriptorUpdateTemplateCreateInfo *, const VkAllocationCallbacks *, VkDescriptorUpdateTemplate *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplateKHR)(VkDevice, const VkDescriptorUpdateTemplateCreateInfo *, const VkAllocationCallbacks *, VkDescriptorUpdateTemplate *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateDevice)(VkPhysicalDevice, const VkDeviceCreateInfo *, const VkAllocationCallbacks *, VkDevice *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateEvent)(VkDevice, const VkEventCreateInfo *, const VkAllocationCallbacks *, VkEvent *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateFence)(VkDevice, const VkFenceCreateInfo *, const VkAllocationCallbacks *, VkFence *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateFramebuffer)(VkDevice, const VkFramebufferCreateInfo *, const VkAllocationCallbacks *, VkFramebuffer *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateGraphicsPipelines)(VkDevice, VkPipelineCache, uint32_t, const VkGraphicsPipelineCreateInfo *, const VkAllocationCallbacks *, VkPipeline *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateImage)(VkDevice, const VkImageCreateInfo *, const VkAllocationCallbacks *, VkImage *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateImageView)(VkDevice, const VkImageViewCreateInfo *, const VkAllocationCallbacks *, VkImageView *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateIndirectCommandsLayoutNV)(VkDevice, const VkIndirectCommandsLayoutCreateInfoNV *, const VkAllocationCallbacks *, VkIndirectCommandsLayoutNV *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateMicromapEXT)(VkDevice, const VkMicromapCreateInfoEXT *, const VkAllocationCallbacks *, VkMicromapEXT *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateOpticalFlowSessionNV)(VkDevice, const VkOpticalFlowSessionCreateInfoNV *, const VkAllocationCallbacks *, VkOpticalFlowSessionNV *); -typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineCache)(VkDevice, const VkPipelineCacheCreateInfo *, const VkAllocationCallbacks *, VkPipelineCache *); -typedef VkResult (VKAPI_PTR *PFN_vkCreatePipelineLayout)(VkDevice, const VkPipelineLayoutCreateInfo *, const VkAllocationCallbacks *, VkPipelineLayout *); -typedef VkResult (VKAPI_PTR *PFN_vkCreatePrivateDataSlot)(VkDevice, const VkPrivateDataSlotCreateInfo *, const VkAllocationCallbacks *, VkPrivateDataSlot *); -typedef VkResult (VKAPI_PTR *PFN_vkCreatePrivateDataSlotEXT)(VkDevice, const VkPrivateDataSlotCreateInfo *, const VkAllocationCallbacks *, VkPrivateDataSlot *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateQueryPool)(VkDevice, const VkQueryPoolCreateInfo *, const VkAllocationCallbacks *, VkQueryPool *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateRayTracingPipelinesKHR)(VkDevice, VkDeferredOperationKHR, VkPipelineCache, uint32_t, const VkRayTracingPipelineCreateInfoKHR *, const VkAllocationCallbacks *, VkPipeline *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateRayTracingPipelinesNV)(VkDevice, VkPipelineCache, uint32_t, const VkRayTracingPipelineCreateInfoNV *, const VkAllocationCallbacks *, VkPipeline *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass)(VkDevice, const VkRenderPassCreateInfo *, const VkAllocationCallbacks *, VkRenderPass *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass2)(VkDevice, const VkRenderPassCreateInfo2 *, const VkAllocationCallbacks *, VkRenderPass *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateRenderPass2KHR)(VkDevice, const VkRenderPassCreateInfo2 *, const VkAllocationCallbacks *, VkRenderPass *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateSampler)(VkDevice, const VkSamplerCreateInfo *, const VkAllocationCallbacks *, VkSampler *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversion)(VkDevice, const VkSamplerYcbcrConversionCreateInfo *, const VkAllocationCallbacks *, VkSamplerYcbcrConversion *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateSamplerYcbcrConversionKHR)(VkDevice, const VkSamplerYcbcrConversionCreateInfo *, const VkAllocationCallbacks *, VkSamplerYcbcrConversion *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateSemaphore)(VkDevice, const VkSemaphoreCreateInfo *, const VkAllocationCallbacks *, VkSemaphore *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateShaderModule)(VkDevice, const VkShaderModuleCreateInfo *, const VkAllocationCallbacks *, VkShaderModule *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateSwapchainKHR)(VkDevice, const VkSwapchainCreateInfoKHR *, const VkAllocationCallbacks *, VkSwapchainKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateValidationCacheEXT)(VkDevice, const VkValidationCacheCreateInfoEXT *, const VkAllocationCallbacks *, VkValidationCacheEXT *); -typedef VkResult (VKAPI_PTR *PFN_vkCreateWin32SurfaceKHR)(VkInstance, const VkWin32SurfaceCreateInfoKHR *, const VkAllocationCallbacks *, VkSurfaceKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectNameEXT)(VkDevice, const VkDebugMarkerObjectNameInfoEXT *); -typedef VkResult (VKAPI_PTR *PFN_vkDebugMarkerSetObjectTagEXT)(VkDevice, const VkDebugMarkerObjectTagInfoEXT *); -typedef void (VKAPI_PTR *PFN_vkDebugReportMessageEXT)(VkInstance, VkDebugReportFlagsEXT, VkDebugReportObjectTypeEXT, uint64_t, size_t, int32_t, const char *, const char *); -typedef VkResult (VKAPI_PTR *PFN_vkDeferredOperationJoinKHR)(VkDevice, VkDeferredOperationKHR); -typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureKHR)(VkDevice, VkAccelerationStructureKHR, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureNV)(VkDevice, VkAccelerationStructureNV, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyBuffer)(VkDevice, VkBuffer, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyBufferView)(VkDevice, VkBufferView, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyCommandPool)(VkDevice, VkCommandPool, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyCuFunctionNVX)(VkDevice, VkCuFunctionNVX, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyCuModuleNVX)(VkDevice, VkCuModuleNVX, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyDebugReportCallbackEXT)(VkInstance, VkDebugReportCallbackEXT, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyDebugUtilsMessengerEXT)(VkInstance, VkDebugUtilsMessengerEXT, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyDeferredOperationKHR)(VkDevice, VkDeferredOperationKHR, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorPool)(VkDevice, VkDescriptorPool, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorSetLayout)(VkDevice, VkDescriptorSetLayout, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplate)(VkDevice, VkDescriptorUpdateTemplate, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplateKHR)(VkDevice, VkDescriptorUpdateTemplate, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyDevice)(VkDevice, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyEvent)(VkDevice, VkEvent, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyFence)(VkDevice, VkFence, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyFramebuffer)(VkDevice, VkFramebuffer, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyImage)(VkDevice, VkImage, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyImageView)(VkDevice, VkImageView, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyIndirectCommandsLayoutNV)(VkDevice, VkIndirectCommandsLayoutNV, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyInstance)(VkInstance, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyMicromapEXT)(VkDevice, VkMicromapEXT, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyOpticalFlowSessionNV)(VkDevice, VkOpticalFlowSessionNV, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyPipeline)(VkDevice, VkPipeline, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyPipelineCache)(VkDevice, VkPipelineCache, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyPipelineLayout)(VkDevice, VkPipelineLayout, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyPrivateDataSlot)(VkDevice, VkPrivateDataSlot, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyPrivateDataSlotEXT)(VkDevice, VkPrivateDataSlot, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyQueryPool)(VkDevice, VkQueryPool, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyRenderPass)(VkDevice, VkRenderPass, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroySampler)(VkDevice, VkSampler, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversion)(VkDevice, VkSamplerYcbcrConversion, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroySamplerYcbcrConversionKHR)(VkDevice, VkSamplerYcbcrConversion, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroySemaphore)(VkDevice, VkSemaphore, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyShaderModule)(VkDevice, VkShaderModule, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroySurfaceKHR)(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroySwapchainKHR)(VkDevice, VkSwapchainKHR, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkDestroyValidationCacheEXT)(VkDevice, VkValidationCacheEXT, const VkAllocationCallbacks *); -typedef VkResult (VKAPI_PTR *PFN_vkDeviceWaitIdle)(VkDevice); -typedef VkResult (VKAPI_PTR *PFN_vkEndCommandBuffer)(VkCommandBuffer); -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceExtensionProperties)(VkPhysicalDevice, const char *, uint32_t *, VkExtensionProperties *); -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateDeviceLayerProperties)(VkPhysicalDevice, uint32_t *, VkLayerProperties *); -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceExtensionProperties)(const char *, uint32_t *, VkExtensionProperties *); -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceLayerProperties)(uint32_t *, VkLayerProperties *); -typedef VkResult (VKAPI_PTR *PFN_vkEnumerateInstanceVersion)(uint32_t *); -typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroups)(VkInstance, uint32_t *, VkPhysicalDeviceGroupProperties *); -typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroupsKHR)(VkInstance, uint32_t *, VkPhysicalDeviceGroupProperties *); -typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR)(VkPhysicalDevice, uint32_t, uint32_t *, VkPerformanceCounterKHR *, VkPerformanceCounterDescriptionKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDevices)(VkInstance, uint32_t *, VkPhysicalDevice *); -typedef VkResult (VKAPI_PTR *PFN_vkFlushMappedMemoryRanges)(VkDevice, uint32_t, const VkMappedMemoryRange *); -typedef void (VKAPI_PTR *PFN_vkFreeCommandBuffers)(VkDevice, VkCommandPool, uint32_t, const VkCommandBuffer *); -typedef VkResult (VKAPI_PTR *PFN_vkFreeDescriptorSets)(VkDevice, VkDescriptorPool, uint32_t, const VkDescriptorSet *); -typedef void (VKAPI_PTR *PFN_vkFreeMemory)(VkDevice, VkDeviceMemory, const VkAllocationCallbacks *); -typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureBuildSizesKHR)(VkDevice, VkAccelerationStructureBuildTypeKHR, const VkAccelerationStructureBuildGeometryInfoKHR *, const uint32_t *, VkAccelerationStructureBuildSizesInfoKHR *); -typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetAccelerationStructureDeviceAddressKHR)(VkDevice, const VkAccelerationStructureDeviceAddressInfoKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNV)(VkDevice, VkAccelerationStructureNV, size_t, void *); -typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNV)(VkDevice, const VkAccelerationStructureMemoryRequirementsInfoNV *, VkMemoryRequirements2KHR *); -typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT)(VkDevice, const VkAccelerationStructureCaptureDescriptorDataInfoEXT *, void *); -typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddress)(VkDevice, const VkBufferDeviceAddressInfo *); -typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddressEXT)(VkDevice, const VkBufferDeviceAddressInfo *); -typedef VkDeviceAddress (VKAPI_PTR *PFN_vkGetBufferDeviceAddressKHR)(VkDevice, const VkBufferDeviceAddressInfo *); -typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements)(VkDevice, VkBuffer, VkMemoryRequirements *); -typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2)(VkDevice, const VkBufferMemoryRequirementsInfo2 *, VkMemoryRequirements2 *); -typedef void (VKAPI_PTR *PFN_vkGetBufferMemoryRequirements2KHR)(VkDevice, const VkBufferMemoryRequirementsInfo2 *, VkMemoryRequirements2 *); -typedef uint64_t (VKAPI_PTR *PFN_vkGetBufferOpaqueCaptureAddress)(VkDevice, const VkBufferDeviceAddressInfo *); -typedef uint64_t (VKAPI_PTR *PFN_vkGetBufferOpaqueCaptureAddressKHR)(VkDevice, const VkBufferDeviceAddressInfo *); -typedef VkResult (VKAPI_PTR *PFN_vkGetBufferOpaqueCaptureDescriptorDataEXT)(VkDevice, const VkBufferCaptureDescriptorDataInfoEXT *, void *); -typedef VkResult (VKAPI_PTR *PFN_vkGetCalibratedTimestampsEXT)(VkDevice, uint32_t, const VkCalibratedTimestampInfoEXT *, uint64_t *, uint64_t *); -typedef uint32_t (VKAPI_PTR *PFN_vkGetDeferredOperationMaxConcurrencyKHR)(VkDevice, VkDeferredOperationKHR); -typedef VkResult (VKAPI_PTR *PFN_vkGetDeferredOperationResultKHR)(VkDevice, VkDeferredOperationKHR); -typedef void (VKAPI_PTR *PFN_vkGetDescriptorEXT)(VkDevice, const VkDescriptorGetInfoEXT *, size_t, void *); -typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetHostMappingVALVE)(VkDevice, VkDescriptorSet, void **); -typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutBindingOffsetEXT)(VkDevice, VkDescriptorSetLayout, uint32_t, VkDeviceSize *); -typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE)(VkDevice, const VkDescriptorSetBindingReferenceVALVE *, VkDescriptorSetLayoutHostMappingInfoVALVE *); -typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSizeEXT)(VkDevice, VkDescriptorSetLayout, VkDeviceSize *); -typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupport)(VkDevice, const VkDescriptorSetLayoutCreateInfo *, VkDescriptorSetLayoutSupport *); -typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutSupportKHR)(VkDevice, const VkDescriptorSetLayoutCreateInfo *, VkDescriptorSetLayoutSupport *); -typedef void (VKAPI_PTR *PFN_vkGetDeviceAccelerationStructureCompatibilityKHR)(VkDevice, const VkAccelerationStructureVersionInfoKHR *, VkAccelerationStructureCompatibilityKHR *); -typedef void (VKAPI_PTR *PFN_vkGetDeviceBufferMemoryRequirements)(VkDevice, const VkDeviceBufferMemoryRequirements *, VkMemoryRequirements2 *); -typedef void (VKAPI_PTR *PFN_vkGetDeviceBufferMemoryRequirementsKHR)(VkDevice, const VkDeviceBufferMemoryRequirements *, VkMemoryRequirements2 *); -typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceFaultInfoEXT)(VkDevice, VkDeviceFaultCountsEXT *, VkDeviceFaultInfoEXT *); -typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeatures)(VkDevice, uint32_t, uint32_t, uint32_t, VkPeerMemoryFeatureFlags *); -typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)(VkDevice, uint32_t, uint32_t, uint32_t, VkPeerMemoryFeatureFlags *); -typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHR)(VkDevice, VkDeviceGroupPresentCapabilitiesKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHR)(VkDevice, VkSurfaceKHR, VkDeviceGroupPresentModeFlagsKHR *); -typedef void (VKAPI_PTR *PFN_vkGetDeviceImageMemoryRequirements)(VkDevice, const VkDeviceImageMemoryRequirements *, VkMemoryRequirements2 *); -typedef void (VKAPI_PTR *PFN_vkGetDeviceImageMemoryRequirementsKHR)(VkDevice, const VkDeviceImageMemoryRequirements *, VkMemoryRequirements2 *); -typedef void (VKAPI_PTR *PFN_vkGetDeviceImageSparseMemoryRequirements)(VkDevice, const VkDeviceImageMemoryRequirements *, uint32_t *, VkSparseImageMemoryRequirements2 *); -typedef void (VKAPI_PTR *PFN_vkGetDeviceImageSparseMemoryRequirementsKHR)(VkDevice, const VkDeviceImageMemoryRequirements *, uint32_t *, VkSparseImageMemoryRequirements2 *); -typedef void (VKAPI_PTR *PFN_vkGetDeviceMemoryCommitment)(VkDevice, VkDeviceMemory, VkDeviceSize *); -typedef uint64_t (VKAPI_PTR *PFN_vkGetDeviceMemoryOpaqueCaptureAddress)(VkDevice, const VkDeviceMemoryOpaqueCaptureAddressInfo *); -typedef uint64_t (VKAPI_PTR *PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)(VkDevice, const VkDeviceMemoryOpaqueCaptureAddressInfo *); -typedef void (VKAPI_PTR *PFN_vkGetDeviceMicromapCompatibilityEXT)(VkDevice, const VkMicromapVersionInfoEXT *, VkAccelerationStructureCompatibilityKHR *); -typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetDeviceProcAddr)(VkDevice, const char *); -typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue)(VkDevice, uint32_t, uint32_t, VkQueue *); -typedef void (VKAPI_PTR *PFN_vkGetDeviceQueue2)(VkDevice, const VkDeviceQueueInfo2 *, VkQueue *); -typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI)(VkDevice, VkRenderPass, VkExtent2D *); -typedef VkResult (VKAPI_PTR *PFN_vkGetDynamicRenderingTilePropertiesQCOM)(VkDevice, const VkRenderingInfo *, VkTilePropertiesQCOM *); -typedef VkResult (VKAPI_PTR *PFN_vkGetEventStatus)(VkDevice, VkEvent); -typedef VkResult (VKAPI_PTR *PFN_vkGetFenceStatus)(VkDevice, VkFence); -typedef VkResult (VKAPI_PTR *PFN_vkGetFramebufferTilePropertiesQCOM)(VkDevice, VkFramebuffer, uint32_t *, VkTilePropertiesQCOM *); -typedef void (VKAPI_PTR *PFN_vkGetGeneratedCommandsMemoryRequirementsNV)(VkDevice, const VkGeneratedCommandsMemoryRequirementsInfoNV *, VkMemoryRequirements2 *); -typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements)(VkDevice, VkImage, VkMemoryRequirements *); -typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2)(VkDevice, const VkImageMemoryRequirementsInfo2 *, VkMemoryRequirements2 *); -typedef void (VKAPI_PTR *PFN_vkGetImageMemoryRequirements2KHR)(VkDevice, const VkImageMemoryRequirementsInfo2 *, VkMemoryRequirements2 *); -typedef VkResult (VKAPI_PTR *PFN_vkGetImageOpaqueCaptureDescriptorDataEXT)(VkDevice, const VkImageCaptureDescriptorDataInfoEXT *, void *); -typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements)(VkDevice, VkImage, uint32_t *, VkSparseImageMemoryRequirements *); -typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2)(VkDevice, const VkImageSparseMemoryRequirementsInfo2 *, uint32_t *, VkSparseImageMemoryRequirements2 *); -typedef void (VKAPI_PTR *PFN_vkGetImageSparseMemoryRequirements2KHR)(VkDevice, const VkImageSparseMemoryRequirementsInfo2 *, uint32_t *, VkSparseImageMemoryRequirements2 *); -typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout)(VkDevice, VkImage, const VkImageSubresource *, VkSubresourceLayout *); -typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout2EXT)(VkDevice, VkImage, const VkImageSubresource2EXT *, VkSubresourceLayout2EXT *); -typedef VkResult (VKAPI_PTR *PFN_vkGetImageViewAddressNVX)(VkDevice, VkImageView, VkImageViewAddressPropertiesNVX *); -typedef uint32_t (VKAPI_PTR *PFN_vkGetImageViewHandleNVX)(VkDevice, const VkImageViewHandleInfoNVX *); -typedef VkResult (VKAPI_PTR *PFN_vkGetImageViewOpaqueCaptureDescriptorDataEXT)(VkDevice, const VkImageViewCaptureDescriptorDataInfoEXT *, void *); -typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddr)(VkInstance, const char *); -typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryHostPointerPropertiesEXT)(VkDevice, VkExternalMemoryHandleTypeFlagBits, const void *, VkMemoryHostPointerPropertiesEXT *); -typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleKHR)(VkDevice, const VkMemoryGetWin32HandleInfoKHR *, HANDLE *); -typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandlePropertiesKHR)(VkDevice, VkExternalMemoryHandleTypeFlagBits, HANDLE, VkMemoryWin32HandlePropertiesKHR *); -typedef void (VKAPI_PTR *PFN_vkGetMicromapBuildSizesEXT)(VkDevice, VkAccelerationStructureBuildTypeKHR, const VkMicromapBuildInfoEXT *, VkMicromapBuildSizesInfoEXT *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPerformanceParameterINTEL)(VkDevice, VkPerformanceParameterTypeINTEL, VkPerformanceValueINTEL *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice, uint32_t *, VkTimeDomainEXT *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV)(VkPhysicalDevice, uint32_t *, VkCooperativeMatrixPropertiesNV *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferProperties)(VkPhysicalDevice, const VkPhysicalDeviceExternalBufferInfo *, VkExternalBufferProperties *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR)(VkPhysicalDevice, const VkPhysicalDeviceExternalBufferInfo *, VkExternalBufferProperties *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFenceProperties)(VkPhysicalDevice, const VkPhysicalDeviceExternalFenceInfo *, VkExternalFenceProperties *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR)(VkPhysicalDevice, const VkPhysicalDeviceExternalFenceInfo *, VkExternalFenceProperties *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphoreProperties)(VkPhysicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo *, VkExternalSemaphoreProperties *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)(VkPhysicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo *, VkExternalSemaphoreProperties *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures)(VkPhysicalDevice, VkPhysicalDeviceFeatures *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2)(VkPhysicalDevice, VkPhysicalDeviceFeatures2 *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice, VkPhysicalDeviceFeatures2 *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice, VkFormat, VkFormatProperties *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2)(VkPhysicalDevice, VkFormat, VkFormatProperties2 *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice, VkFormat, VkFormatProperties2 *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceFragmentShadingRatesKHR)(VkPhysicalDevice, uint32_t *, VkPhysicalDeviceFragmentShadingRateKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice, VkFormat, VkImageType, VkImageTiling, VkImageUsageFlags, VkImageCreateFlags, VkImageFormatProperties *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice, const VkPhysicalDeviceImageFormatInfo2 *, VkImageFormatProperties2 *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice, const VkPhysicalDeviceImageFormatInfo2 *, VkImageFormatProperties2 *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice, VkPhysicalDeviceMemoryProperties *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2)(VkPhysicalDevice, VkPhysicalDeviceMemoryProperties2 *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice, VkPhysicalDeviceMemoryProperties2 *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMultisamplePropertiesEXT)(VkPhysicalDevice, VkSampleCountFlagBits, VkMultisamplePropertiesEXT *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceOpticalFlowImageFormatsNV)(VkPhysicalDevice, const VkOpticalFlowImageFormatInfoNV *, uint32_t *, VkOpticalFlowImageFormatPropertiesNV *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkRect2D *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties)(VkPhysicalDevice, VkPhysicalDeviceProperties *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice, VkPhysicalDeviceProperties2 *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice, VkPhysicalDeviceProperties2 *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR)(VkPhysicalDevice, const VkQueryPoolPerformanceCreateInfoKHR *, uint32_t *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice, uint32_t *, VkQueueFamilyProperties *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2)(VkPhysicalDevice, uint32_t *, VkQueueFamilyProperties2 *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice, uint32_t *, VkQueueFamilyProperties2 *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice, VkFormat, VkImageType, VkSampleCountFlagBits, VkImageUsageFlags, VkImageTiling, uint32_t *, VkSparseImageFormatProperties *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2)(VkPhysicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2 *, uint32_t *, VkSparseImageFormatProperties2 *); -typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2 *, uint32_t *, VkSparseImageFormatProperties2 *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV)(VkPhysicalDevice, uint32_t *, VkFramebufferMixedSamplesCombinationNV *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *, VkSurfaceCapabilities2KHR *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice, VkSurfaceKHR, VkSurfaceCapabilitiesKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *, uint32_t *, VkSurfaceFormat2KHR *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkSurfaceFormatKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkPresentModeKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice, uint32_t, VkSurfaceKHR, VkBool32 *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceToolProperties)(VkPhysicalDevice, uint32_t *, VkPhysicalDeviceToolProperties *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceToolPropertiesEXT)(VkPhysicalDevice, uint32_t *, VkPhysicalDeviceToolProperties *); -typedef VkBool32 (VKAPI_PTR *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice, uint32_t); -typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineCacheData)(VkDevice, VkPipelineCache, size_t *, void *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineExecutableInternalRepresentationsKHR)(VkDevice, const VkPipelineExecutableInfoKHR *, uint32_t *, VkPipelineExecutableInternalRepresentationKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineExecutablePropertiesKHR)(VkDevice, const VkPipelineInfoKHR *, uint32_t *, VkPipelineExecutablePropertiesKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPipelineExecutableStatisticsKHR)(VkDevice, const VkPipelineExecutableInfoKHR *, uint32_t *, VkPipelineExecutableStatisticKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkGetPipelinePropertiesEXT)(VkDevice, const VkPipelineInfoEXT *, VkBaseOutStructure *); -typedef void (VKAPI_PTR *PFN_vkGetPrivateData)(VkDevice, VkObjectType, uint64_t, VkPrivateDataSlot, uint64_t *); -typedef void (VKAPI_PTR *PFN_vkGetPrivateDataEXT)(VkDevice, VkObjectType, uint64_t, VkPrivateDataSlot, uint64_t *); -typedef VkResult (VKAPI_PTR *PFN_vkGetQueryPoolResults)(VkDevice, VkQueryPool, uint32_t, uint32_t, size_t, void *, VkDeviceSize, VkQueryResultFlags); -typedef void (VKAPI_PTR *PFN_vkGetQueueCheckpointData2NV)(VkQueue, uint32_t *, VkCheckpointData2NV *); -typedef void (VKAPI_PTR *PFN_vkGetQueueCheckpointDataNV)(VkQueue, uint32_t *, VkCheckpointDataNV *); -typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR)(VkDevice, VkPipeline, uint32_t, uint32_t, size_t, void *); -typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupHandlesKHR)(VkDevice, VkPipeline, uint32_t, uint32_t, size_t, void *); -typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupHandlesNV)(VkDevice, VkPipeline, uint32_t, uint32_t, size_t, void *); -typedef VkDeviceSize (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupStackSizeKHR)(VkDevice, VkPipeline, uint32_t, VkShaderGroupShaderKHR); -typedef void (VKAPI_PTR *PFN_vkGetRenderAreaGranularity)(VkDevice, VkRenderPass, VkExtent2D *); -typedef VkResult (VKAPI_PTR *PFN_vkGetSamplerOpaqueCaptureDescriptorDataEXT)(VkDevice, const VkSamplerCaptureDescriptorDataInfoEXT *, void *); -typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreCounterValue)(VkDevice, VkSemaphore, uint64_t *); -typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreCounterValueKHR)(VkDevice, VkSemaphore, uint64_t *); -typedef VkResult (VKAPI_PTR *PFN_vkGetShaderInfoAMD)(VkDevice, VkPipeline, VkShaderStageFlagBits, VkShaderInfoTypeAMD, size_t *, void *); -typedef void (VKAPI_PTR *PFN_vkGetShaderModuleCreateInfoIdentifierEXT)(VkDevice, const VkShaderModuleCreateInfo *, VkShaderModuleIdentifierEXT *); -typedef void (VKAPI_PTR *PFN_vkGetShaderModuleIdentifierEXT)(VkDevice, VkShaderModule, VkShaderModuleIdentifierEXT *); -typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice, VkSwapchainKHR, uint32_t *, VkImage *); -typedef VkResult (VKAPI_PTR *PFN_vkGetValidationCacheDataEXT)(VkDevice, VkValidationCacheEXT, size_t *, void *); -typedef VkResult (VKAPI_PTR *PFN_vkInitializePerformanceApiINTEL)(VkDevice, const VkInitializePerformanceApiInfoINTEL *); -typedef VkResult (VKAPI_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice, uint32_t, const VkMappedMemoryRange *); -typedef VkResult (VKAPI_PTR *PFN_vkMapMemory)(VkDevice, VkDeviceMemory, VkDeviceSize, VkDeviceSize, VkMemoryMapFlags, void **); -typedef VkResult (VKAPI_PTR *PFN_vkMergePipelineCaches)(VkDevice, VkPipelineCache, uint32_t, const VkPipelineCache *); -typedef VkResult (VKAPI_PTR *PFN_vkMergeValidationCachesEXT)(VkDevice, VkValidationCacheEXT, uint32_t, const VkValidationCacheEXT *); -typedef void (VKAPI_PTR *PFN_vkQueueBeginDebugUtilsLabelEXT)(VkQueue, const VkDebugUtilsLabelEXT *); -typedef VkResult (VKAPI_PTR *PFN_vkQueueBindSparse)(VkQueue, uint32_t, const VkBindSparseInfo *, VkFence); -typedef void (VKAPI_PTR *PFN_vkQueueEndDebugUtilsLabelEXT)(VkQueue); -typedef void (VKAPI_PTR *PFN_vkQueueInsertDebugUtilsLabelEXT)(VkQueue, const VkDebugUtilsLabelEXT *); -typedef VkResult (VKAPI_PTR *PFN_vkQueuePresentKHR)(VkQueue, const VkPresentInfoKHR *); -typedef VkResult (VKAPI_PTR *PFN_vkQueueSetPerformanceConfigurationINTEL)(VkQueue, VkPerformanceConfigurationINTEL); -typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit)(VkQueue, uint32_t, const VkSubmitInfo *, VkFence); -typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit2)(VkQueue, uint32_t, const VkSubmitInfo2 *, VkFence); -typedef VkResult (VKAPI_PTR *PFN_vkQueueSubmit2KHR)(VkQueue, uint32_t, const VkSubmitInfo2 *, VkFence); -typedef VkResult (VKAPI_PTR *PFN_vkQueueWaitIdle)(VkQueue); -typedef VkResult (VKAPI_PTR *PFN_vkReleasePerformanceConfigurationINTEL)(VkDevice, VkPerformanceConfigurationINTEL); -typedef void (VKAPI_PTR *PFN_vkReleaseProfilingLockKHR)(VkDevice); -typedef VkResult (VKAPI_PTR *PFN_vkReleaseSwapchainImagesEXT)(VkDevice, const VkReleaseSwapchainImagesInfoEXT *); -typedef VkResult (VKAPI_PTR *PFN_vkResetCommandBuffer)(VkCommandBuffer, VkCommandBufferResetFlags); -typedef VkResult (VKAPI_PTR *PFN_vkResetCommandPool)(VkDevice, VkCommandPool, VkCommandPoolResetFlags); -typedef VkResult (VKAPI_PTR *PFN_vkResetDescriptorPool)(VkDevice, VkDescriptorPool, VkDescriptorPoolResetFlags); -typedef VkResult (VKAPI_PTR *PFN_vkResetEvent)(VkDevice, VkEvent); -typedef VkResult (VKAPI_PTR *PFN_vkResetFences)(VkDevice, uint32_t, const VkFence *); -typedef void (VKAPI_PTR *PFN_vkResetQueryPool)(VkDevice, VkQueryPool, uint32_t, uint32_t); -typedef void (VKAPI_PTR *PFN_vkResetQueryPoolEXT)(VkDevice, VkQueryPool, uint32_t, uint32_t); -typedef VkResult (VKAPI_PTR *PFN_vkSetDebugUtilsObjectNameEXT)(VkDevice, const VkDebugUtilsObjectNameInfoEXT *); -typedef VkResult (VKAPI_PTR *PFN_vkSetDebugUtilsObjectTagEXT)(VkDevice, const VkDebugUtilsObjectTagInfoEXT *); -typedef void (VKAPI_PTR *PFN_vkSetDeviceMemoryPriorityEXT)(VkDevice, VkDeviceMemory, float); -typedef VkResult (VKAPI_PTR *PFN_vkSetEvent)(VkDevice, VkEvent); -typedef VkResult (VKAPI_PTR *PFN_vkSetPrivateData)(VkDevice, VkObjectType, uint64_t, VkPrivateDataSlot, uint64_t); -typedef VkResult (VKAPI_PTR *PFN_vkSetPrivateDataEXT)(VkDevice, VkObjectType, uint64_t, VkPrivateDataSlot, uint64_t); -typedef VkResult (VKAPI_PTR *PFN_vkSignalSemaphore)(VkDevice, const VkSemaphoreSignalInfo *); -typedef VkResult (VKAPI_PTR *PFN_vkSignalSemaphoreKHR)(VkDevice, const VkSemaphoreSignalInfo *); -typedef void (VKAPI_PTR *PFN_vkSubmitDebugUtilsMessageEXT)(VkInstance, VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT *); -typedef void (VKAPI_PTR *PFN_vkTrimCommandPool)(VkDevice, VkCommandPool, VkCommandPoolTrimFlags); -typedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice, VkCommandPool, VkCommandPoolTrimFlags); -typedef void (VKAPI_PTR *PFN_vkUninitializePerformanceApiINTEL)(VkDevice); -typedef void (VKAPI_PTR *PFN_vkUnmapMemory)(VkDevice, VkDeviceMemory); -typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplate)(VkDevice, VkDescriptorSet, VkDescriptorUpdateTemplate, const void *); -typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplateKHR)(VkDevice, VkDescriptorSet, VkDescriptorUpdateTemplate, const void *); -typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSets)(VkDevice, uint32_t, const VkWriteDescriptorSet *, uint32_t, const VkCopyDescriptorSet *); -typedef VkResult (VKAPI_PTR *PFN_vkWaitForFences)(VkDevice, uint32_t, const VkFence *, VkBool32, uint64_t); -typedef VkResult (VKAPI_PTR *PFN_vkWaitForPresentKHR)(VkDevice, VkSwapchainKHR, uint64_t, uint64_t); -typedef VkResult (VKAPI_PTR *PFN_vkWaitSemaphores)(VkDevice, const VkSemaphoreWaitInfo *, uint64_t); -typedef VkResult (VKAPI_PTR *PFN_vkWaitSemaphoresKHR)(VkDevice, const VkSemaphoreWaitInfo *, uint64_t); -typedef VkResult (VKAPI_PTR *PFN_vkWriteAccelerationStructuresPropertiesKHR)(VkDevice, uint32_t, const VkAccelerationStructureKHR *, VkQueryType, size_t, void *, size_t); -typedef VkResult (VKAPI_PTR *PFN_vkWriteMicromapsPropertiesEXT)(VkDevice, uint32_t, const VkMicromapEXT *, VkQueryType, size_t, void *, size_t); - -#ifndef VK_NO_PROTOTYPES -VkResult VKAPI_CALL vkAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR *pAcquireInfo, uint32_t *pImageIndex); -VkResult VKAPI_CALL vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex); -VkResult VKAPI_CALL vkAcquirePerformanceConfigurationINTEL(VkDevice device, const VkPerformanceConfigurationAcquireInfoINTEL *pAcquireInfo, VkPerformanceConfigurationINTEL *pConfiguration); -VkResult VKAPI_CALL vkAcquireProfilingLockKHR(VkDevice device, const VkAcquireProfilingLockInfoKHR *pInfo); -VkResult VKAPI_CALL vkAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo, VkCommandBuffer *pCommandBuffers); -VkResult VKAPI_CALL vkAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo, VkDescriptorSet *pDescriptorSets); -VkResult VKAPI_CALL vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo, const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory); -VkResult VKAPI_CALL vkBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo); -VkResult VKAPI_CALL vkBindAccelerationStructureMemoryNV(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNV *pBindInfos); -VkResult VKAPI_CALL vkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset); -VkResult VKAPI_CALL vkBindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo *pBindInfos); -VkResult VKAPI_CALL vkBindBufferMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo *pBindInfos); -VkResult VKAPI_CALL vkBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset); -VkResult VKAPI_CALL vkBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo *pBindInfos); -VkResult VKAPI_CALL vkBindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo *pBindInfos); -VkResult VKAPI_CALL vkBindOpticalFlowSessionImageNV(VkDevice device, VkOpticalFlowSessionNV session, VkOpticalFlowSessionBindingPointNV bindingPoint, VkImageView view, VkImageLayout layout); -VkResult VKAPI_CALL vkBuildAccelerationStructuresKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR *pInfos, const VkAccelerationStructureBuildRangeInfoKHR * const*ppBuildRangeInfos); -VkResult VKAPI_CALL vkBuildMicromapsEXT(VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount, const VkMicromapBuildInfoEXT *pInfos); -void VKAPI_CALL vkCmdBeginConditionalRenderingEXT(VkCommandBuffer commandBuffer, const VkConditionalRenderingBeginInfoEXT *pConditionalRenderingBegin); -void VKAPI_CALL vkCmdBeginDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT *pLabelInfo); -void VKAPI_CALL vkCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags); -void VKAPI_CALL vkCmdBeginQueryIndexedEXT(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags, uint32_t index); -void VKAPI_CALL vkCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, VkSubpassContents contents); -void VKAPI_CALL vkCmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, const VkSubpassBeginInfo *pSubpassBeginInfo); -void VKAPI_CALL vkCmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, const VkSubpassBeginInfo *pSubpassBeginInfo); -void VKAPI_CALL vkCmdBeginRendering(VkCommandBuffer commandBuffer, const VkRenderingInfo *pRenderingInfo); -void VKAPI_CALL vkCmdBeginRenderingKHR(VkCommandBuffer commandBuffer, const VkRenderingInfo *pRenderingInfo); -void VKAPI_CALL vkCmdBeginTransformFeedbackEXT(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer *pCounterBuffers, const VkDeviceSize *pCounterBufferOffsets); -void VKAPI_CALL vkCmdBindDescriptorBufferEmbeddedSamplersEXT(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set); -void VKAPI_CALL vkCmdBindDescriptorBuffersEXT(VkCommandBuffer commandBuffer, uint32_t bufferCount, const VkDescriptorBufferBindingInfoEXT *pBindingInfos); -void VKAPI_CALL vkCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t *pDynamicOffsets); -void VKAPI_CALL vkCmdBindIndexBuffer(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkIndexType indexType); -void VKAPI_CALL vkCmdBindInvocationMaskHUAWEI(VkCommandBuffer commandBuffer, VkImageView imageView, VkImageLayout imageLayout); -void VKAPI_CALL vkCmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline); -void VKAPI_CALL vkCmdBindPipelineShaderGroupNV(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline, uint32_t groupIndex); -void VKAPI_CALL vkCmdBindShadingRateImageNV(VkCommandBuffer commandBuffer, VkImageView imageView, VkImageLayout imageLayout); -void VKAPI_CALL vkCmdBindTransformFeedbackBuffersEXT(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers, const VkDeviceSize *pOffsets, const VkDeviceSize *pSizes); -void VKAPI_CALL vkCmdBindVertexBuffers(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers, const VkDeviceSize *pOffsets); -void VKAPI_CALL vkCmdBindVertexBuffers2(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers, const VkDeviceSize *pOffsets, const VkDeviceSize *pSizes, const VkDeviceSize *pStrides); -void VKAPI_CALL vkCmdBindVertexBuffers2EXT(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer *pBuffers, const VkDeviceSize *pOffsets, const VkDeviceSize *pSizes, const VkDeviceSize *pStrides); -void VKAPI_CALL vkCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit *pRegions, VkFilter filter); -void VKAPI_CALL vkCmdBlitImage2(VkCommandBuffer commandBuffer, const VkBlitImageInfo2 *pBlitImageInfo); -void VKAPI_CALL vkCmdBlitImage2KHR(VkCommandBuffer commandBuffer, const VkBlitImageInfo2 *pBlitImageInfo); -void VKAPI_CALL vkCmdBuildAccelerationStructureNV(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV *pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkBuffer scratch, VkDeviceSize scratchOffset); -void VKAPI_CALL vkCmdBuildAccelerationStructuresIndirectKHR(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR *pInfos, const VkDeviceAddress *pIndirectDeviceAddresses, const uint32_t *pIndirectStrides, const uint32_t * const*ppMaxPrimitiveCounts); -void VKAPI_CALL vkCmdBuildAccelerationStructuresKHR(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR *pInfos, const VkAccelerationStructureBuildRangeInfoKHR * const*ppBuildRangeInfos); -void VKAPI_CALL vkCmdBuildMicromapsEXT(VkCommandBuffer commandBuffer, uint32_t infoCount, const VkMicromapBuildInfoEXT *pInfos); -void VKAPI_CALL vkCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkClearAttachment *pAttachments, uint32_t rectCount, const VkClearRect *pRects); -void VKAPI_CALL vkCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue *pColor, uint32_t rangeCount, const VkImageSubresourceRange *pRanges); -void VKAPI_CALL vkCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange *pRanges); -void VKAPI_CALL vkCmdCopyAccelerationStructureKHR(VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureInfoKHR *pInfo); -void VKAPI_CALL vkCmdCopyAccelerationStructureNV(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkCopyAccelerationStructureModeKHR mode); -void VKAPI_CALL vkCmdCopyAccelerationStructureToMemoryKHR(VkCommandBuffer commandBuffer, const VkCopyAccelerationStructureToMemoryInfoKHR *pInfo); -void VKAPI_CALL vkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy *pRegions); -void VKAPI_CALL vkCmdCopyBuffer2(VkCommandBuffer commandBuffer, const VkCopyBufferInfo2 *pCopyBufferInfo); -void VKAPI_CALL vkCmdCopyBuffer2KHR(VkCommandBuffer commandBuffer, const VkCopyBufferInfo2 *pCopyBufferInfo); -void VKAPI_CALL vkCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy *pRegions); -void VKAPI_CALL vkCmdCopyBufferToImage2(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2 *pCopyBufferToImageInfo); -void VKAPI_CALL vkCmdCopyBufferToImage2KHR(VkCommandBuffer commandBuffer, const VkCopyBufferToImageInfo2 *pCopyBufferToImageInfo); -void VKAPI_CALL vkCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy *pRegions); -void VKAPI_CALL vkCmdCopyImage2(VkCommandBuffer commandBuffer, const VkCopyImageInfo2 *pCopyImageInfo); -void VKAPI_CALL vkCmdCopyImage2KHR(VkCommandBuffer commandBuffer, const VkCopyImageInfo2 *pCopyImageInfo); -void VKAPI_CALL vkCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions); -void VKAPI_CALL vkCmdCopyImageToBuffer2(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2 *pCopyImageToBufferInfo); -void VKAPI_CALL vkCmdCopyImageToBuffer2KHR(VkCommandBuffer commandBuffer, const VkCopyImageToBufferInfo2 *pCopyImageToBufferInfo); -void VKAPI_CALL vkCmdCopyMemoryIndirectNV(VkCommandBuffer commandBuffer, VkDeviceAddress copyBufferAddress, uint32_t copyCount, uint32_t stride); -void VKAPI_CALL vkCmdCopyMemoryToAccelerationStructureKHR(VkCommandBuffer commandBuffer, const VkCopyMemoryToAccelerationStructureInfoKHR *pInfo); -void VKAPI_CALL vkCmdCopyMemoryToImageIndirectNV(VkCommandBuffer commandBuffer, VkDeviceAddress copyBufferAddress, uint32_t copyCount, uint32_t stride, VkImage dstImage, VkImageLayout dstImageLayout, const VkImageSubresourceLayers *pImageSubresources); -void VKAPI_CALL vkCmdCopyMemoryToMicromapEXT(VkCommandBuffer commandBuffer, const VkCopyMemoryToMicromapInfoEXT *pInfo); -void VKAPI_CALL vkCmdCopyMicromapEXT(VkCommandBuffer commandBuffer, const VkCopyMicromapInfoEXT *pInfo); -void VKAPI_CALL vkCmdCopyMicromapToMemoryEXT(VkCommandBuffer commandBuffer, const VkCopyMicromapToMemoryInfoEXT *pInfo); -void VKAPI_CALL vkCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags); -void VKAPI_CALL vkCmdCuLaunchKernelNVX(VkCommandBuffer commandBuffer, const VkCuLaunchInfoNVX *pLaunchInfo); -void VKAPI_CALL vkCmdDebugMarkerBeginEXT(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT *pMarkerInfo); -void VKAPI_CALL vkCmdDebugMarkerEndEXT(VkCommandBuffer commandBuffer); -void VKAPI_CALL vkCmdDebugMarkerInsertEXT(VkCommandBuffer commandBuffer, const VkDebugMarkerMarkerInfoEXT *pMarkerInfo); -void VKAPI_CALL vkCmdDecompressMemoryIndirectCountNV(VkCommandBuffer commandBuffer, VkDeviceAddress indirectCommandsAddress, VkDeviceAddress indirectCommandsCountAddress, uint32_t stride); -void VKAPI_CALL vkCmdDecompressMemoryNV(VkCommandBuffer commandBuffer, uint32_t decompressRegionCount, const VkDecompressMemoryRegionNV *pDecompressMemoryRegions); -void VKAPI_CALL vkCmdDispatch(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); -void VKAPI_CALL vkCmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); -void VKAPI_CALL vkCmdDispatchBaseKHR(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); -void VKAPI_CALL vkCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset); -void VKAPI_CALL vkCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance); -void VKAPI_CALL vkCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance); -void VKAPI_CALL vkCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); -void VKAPI_CALL vkCmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); -void VKAPI_CALL vkCmdDrawIndexedIndirectCountAMD(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); -void VKAPI_CALL vkCmdDrawIndexedIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); -void VKAPI_CALL vkCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); -void VKAPI_CALL vkCmdDrawIndirectByteCountEXT(VkCommandBuffer commandBuffer, uint32_t instanceCount, uint32_t firstInstance, VkBuffer counterBuffer, VkDeviceSize counterBufferOffset, uint32_t counterOffset, uint32_t vertexStride); -void VKAPI_CALL vkCmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); -void VKAPI_CALL vkCmdDrawIndirectCountAMD(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); -void VKAPI_CALL vkCmdDrawIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); -void VKAPI_CALL vkCmdDrawMeshTasksEXT(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ); -void VKAPI_CALL vkCmdDrawMeshTasksIndirectCountEXT(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); -void VKAPI_CALL vkCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride); -void VKAPI_CALL vkCmdDrawMeshTasksIndirectEXT(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); -void VKAPI_CALL vkCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride); -void VKAPI_CALL vkCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask); -void VKAPI_CALL vkCmdDrawMultiEXT(VkCommandBuffer commandBuffer, uint32_t drawCount, const VkMultiDrawInfoEXT *pVertexInfo, uint32_t instanceCount, uint32_t firstInstance, uint32_t stride); -void VKAPI_CALL vkCmdDrawMultiIndexedEXT(VkCommandBuffer commandBuffer, uint32_t drawCount, const VkMultiDrawIndexedInfoEXT *pIndexInfo, uint32_t instanceCount, uint32_t firstInstance, uint32_t stride, const int32_t *pVertexOffset); -void VKAPI_CALL vkCmdEndConditionalRenderingEXT(VkCommandBuffer commandBuffer); -void VKAPI_CALL vkCmdEndDebugUtilsLabelEXT(VkCommandBuffer commandBuffer); -void VKAPI_CALL vkCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query); -void VKAPI_CALL vkCmdEndQueryIndexedEXT(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, uint32_t index); -void VKAPI_CALL vkCmdEndRenderPass(VkCommandBuffer commandBuffer); -void VKAPI_CALL vkCmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo); -void VKAPI_CALL vkCmdEndRenderPass2KHR(VkCommandBuffer commandBuffer, const VkSubpassEndInfo *pSubpassEndInfo); -void VKAPI_CALL vkCmdEndRendering(VkCommandBuffer commandBuffer); -void VKAPI_CALL vkCmdEndRenderingKHR(VkCommandBuffer commandBuffer); -void VKAPI_CALL vkCmdEndTransformFeedbackEXT(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer *pCounterBuffers, const VkDeviceSize *pCounterBufferOffsets); -void VKAPI_CALL vkCmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers); -void VKAPI_CALL vkCmdExecuteGeneratedCommandsNV(VkCommandBuffer commandBuffer, VkBool32 isPreprocessed, const VkGeneratedCommandsInfoNV *pGeneratedCommandsInfo); -void VKAPI_CALL vkCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data); -void VKAPI_CALL vkCmdInsertDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const VkDebugUtilsLabelEXT *pLabelInfo); -void VKAPI_CALL vkCmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents); -void VKAPI_CALL vkCmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo, const VkSubpassEndInfo *pSubpassEndInfo); -void VKAPI_CALL vkCmdNextSubpass2KHR(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo *pSubpassBeginInfo, const VkSubpassEndInfo *pSubpassEndInfo); -void VKAPI_CALL vkCmdOpticalFlowExecuteNV(VkCommandBuffer commandBuffer, VkOpticalFlowSessionNV session, const VkOpticalFlowExecuteInfoNV *pExecuteInfo); -void VKAPI_CALL vkCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkDependencyFlags dependencyFlags, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers); -void VKAPI_CALL vkCmdPipelineBarrier2(VkCommandBuffer commandBuffer, const VkDependencyInfo *pDependencyInfo); -void VKAPI_CALL vkCmdPipelineBarrier2KHR(VkCommandBuffer commandBuffer, const VkDependencyInfo *pDependencyInfo); -void VKAPI_CALL vkCmdPreprocessGeneratedCommandsNV(VkCommandBuffer commandBuffer, const VkGeneratedCommandsInfoNV *pGeneratedCommandsInfo); -void VKAPI_CALL vkCmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, uint32_t size, const void *pValues); -void VKAPI_CALL vkCmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites); -void VKAPI_CALL vkCmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplate descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void *pData); -void VKAPI_CALL vkCmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); -void VKAPI_CALL vkCmdResetEvent2(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags2 stageMask); -void VKAPI_CALL vkCmdResetEvent2KHR(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags2 stageMask); -void VKAPI_CALL vkCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); -void VKAPI_CALL vkCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageResolve *pRegions); -void VKAPI_CALL vkCmdResolveImage2(VkCommandBuffer commandBuffer, const VkResolveImageInfo2 *pResolveImageInfo); -void VKAPI_CALL vkCmdResolveImage2KHR(VkCommandBuffer commandBuffer, const VkResolveImageInfo2 *pResolveImageInfo); -void VKAPI_CALL vkCmdSetAlphaToCoverageEnableEXT(VkCommandBuffer commandBuffer, VkBool32 alphaToCoverageEnable); -void VKAPI_CALL vkCmdSetAlphaToOneEnableEXT(VkCommandBuffer commandBuffer, VkBool32 alphaToOneEnable); -void VKAPI_CALL vkCmdSetBlendConstants(VkCommandBuffer commandBuffer, const float blendConstants[4]); -void VKAPI_CALL vkCmdSetCheckpointNV(VkCommandBuffer commandBuffer, const void *pCheckpointMarker); -void VKAPI_CALL vkCmdSetCoarseSampleOrderNV(VkCommandBuffer commandBuffer, VkCoarseSampleOrderTypeNV sampleOrderType, uint32_t customSampleOrderCount, const VkCoarseSampleOrderCustomNV *pCustomSampleOrders); -void VKAPI_CALL vkCmdSetColorBlendAdvancedEXT(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorBlendAdvancedEXT *pColorBlendAdvanced); -void VKAPI_CALL vkCmdSetColorBlendEnableEXT(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkBool32 *pColorBlendEnables); -void VKAPI_CALL vkCmdSetColorBlendEquationEXT(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorBlendEquationEXT *pColorBlendEquations); -void VKAPI_CALL vkCmdSetColorWriteEnableEXT(VkCommandBuffer commandBuffer, uint32_t attachmentCount, const VkBool32 *pColorWriteEnables); -void VKAPI_CALL vkCmdSetColorWriteMaskEXT(VkCommandBuffer commandBuffer, uint32_t firstAttachment, uint32_t attachmentCount, const VkColorComponentFlags *pColorWriteMasks); -void VKAPI_CALL vkCmdSetConservativeRasterizationModeEXT(VkCommandBuffer commandBuffer, VkConservativeRasterizationModeEXT conservativeRasterizationMode); -void VKAPI_CALL vkCmdSetCoverageModulationModeNV(VkCommandBuffer commandBuffer, VkCoverageModulationModeNV coverageModulationMode); -void VKAPI_CALL vkCmdSetCoverageModulationTableEnableNV(VkCommandBuffer commandBuffer, VkBool32 coverageModulationTableEnable); -void VKAPI_CALL vkCmdSetCoverageModulationTableNV(VkCommandBuffer commandBuffer, uint32_t coverageModulationTableCount, const float *pCoverageModulationTable); -void VKAPI_CALL vkCmdSetCoverageReductionModeNV(VkCommandBuffer commandBuffer, VkCoverageReductionModeNV coverageReductionMode); -void VKAPI_CALL vkCmdSetCoverageToColorEnableNV(VkCommandBuffer commandBuffer, VkBool32 coverageToColorEnable); -void VKAPI_CALL vkCmdSetCoverageToColorLocationNV(VkCommandBuffer commandBuffer, uint32_t coverageToColorLocation); -void VKAPI_CALL vkCmdSetCullMode(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode); -void VKAPI_CALL vkCmdSetCullModeEXT(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode); -void VKAPI_CALL vkCmdSetDepthBias(VkCommandBuffer commandBuffer, float depthBiasConstantFactor, float depthBiasClamp, float depthBiasSlopeFactor); -void VKAPI_CALL vkCmdSetDepthBiasEnable(VkCommandBuffer commandBuffer, VkBool32 depthBiasEnable); -void VKAPI_CALL vkCmdSetDepthBiasEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthBiasEnable); -void VKAPI_CALL vkCmdSetDepthBounds(VkCommandBuffer commandBuffer, float minDepthBounds, float maxDepthBounds); -void VKAPI_CALL vkCmdSetDepthBoundsTestEnable(VkCommandBuffer commandBuffer, VkBool32 depthBoundsTestEnable); -void VKAPI_CALL vkCmdSetDepthBoundsTestEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthBoundsTestEnable); -void VKAPI_CALL vkCmdSetDepthClampEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthClampEnable); -void VKAPI_CALL vkCmdSetDepthClipEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthClipEnable); -void VKAPI_CALL vkCmdSetDepthClipNegativeOneToOneEXT(VkCommandBuffer commandBuffer, VkBool32 negativeOneToOne); -void VKAPI_CALL vkCmdSetDepthCompareOp(VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp); -void VKAPI_CALL vkCmdSetDepthCompareOpEXT(VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp); -void VKAPI_CALL vkCmdSetDepthTestEnable(VkCommandBuffer commandBuffer, VkBool32 depthTestEnable); -void VKAPI_CALL vkCmdSetDepthTestEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthTestEnable); -void VKAPI_CALL vkCmdSetDepthWriteEnable(VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable); -void VKAPI_CALL vkCmdSetDepthWriteEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable); -void VKAPI_CALL vkCmdSetDescriptorBufferOffsetsEXT(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount, const uint32_t *pBufferIndices, const VkDeviceSize *pOffsets); -void VKAPI_CALL vkCmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask); -void VKAPI_CALL vkCmdSetDeviceMaskKHR(VkCommandBuffer commandBuffer, uint32_t deviceMask); -void VKAPI_CALL vkCmdSetDiscardRectangleEXT(VkCommandBuffer commandBuffer, uint32_t firstDiscardRectangle, uint32_t discardRectangleCount, const VkRect2D *pDiscardRectangles); -void VKAPI_CALL vkCmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask); -void VKAPI_CALL vkCmdSetEvent2(VkCommandBuffer commandBuffer, VkEvent event, const VkDependencyInfo *pDependencyInfo); -void VKAPI_CALL vkCmdSetEvent2KHR(VkCommandBuffer commandBuffer, VkEvent event, const VkDependencyInfo *pDependencyInfo); -void VKAPI_CALL vkCmdSetExclusiveScissorNV(VkCommandBuffer commandBuffer, uint32_t firstExclusiveScissor, uint32_t exclusiveScissorCount, const VkRect2D *pExclusiveScissors); -void VKAPI_CALL vkCmdSetExtraPrimitiveOverestimationSizeEXT(VkCommandBuffer commandBuffer, float extraPrimitiveOverestimationSize); -void VKAPI_CALL vkCmdSetFragmentShadingRateEnumNV(VkCommandBuffer commandBuffer, VkFragmentShadingRateNV shadingRate, const VkFragmentShadingRateCombinerOpKHR combinerOps[2]); -void VKAPI_CALL vkCmdSetFragmentShadingRateKHR(VkCommandBuffer commandBuffer, const VkExtent2D *pFragmentSize, const VkFragmentShadingRateCombinerOpKHR combinerOps[2]); -void VKAPI_CALL vkCmdSetFrontFace(VkCommandBuffer commandBuffer, VkFrontFace frontFace); -void VKAPI_CALL vkCmdSetFrontFaceEXT(VkCommandBuffer commandBuffer, VkFrontFace frontFace); -void VKAPI_CALL vkCmdSetLineRasterizationModeEXT(VkCommandBuffer commandBuffer, VkLineRasterizationModeEXT lineRasterizationMode); -void VKAPI_CALL vkCmdSetLineStippleEXT(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor, uint16_t lineStipplePattern); -void VKAPI_CALL vkCmdSetLineStippleEnableEXT(VkCommandBuffer commandBuffer, VkBool32 stippledLineEnable); -void VKAPI_CALL vkCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth); -void VKAPI_CALL vkCmdSetLogicOpEXT(VkCommandBuffer commandBuffer, VkLogicOp logicOp); -void VKAPI_CALL vkCmdSetLogicOpEnableEXT(VkCommandBuffer commandBuffer, VkBool32 logicOpEnable); -void VKAPI_CALL vkCmdSetPatchControlPointsEXT(VkCommandBuffer commandBuffer, uint32_t patchControlPoints); -VkResult VKAPI_CALL vkCmdSetPerformanceMarkerINTEL(VkCommandBuffer commandBuffer, const VkPerformanceMarkerInfoINTEL *pMarkerInfo); -VkResult VKAPI_CALL vkCmdSetPerformanceOverrideINTEL(VkCommandBuffer commandBuffer, const VkPerformanceOverrideInfoINTEL *pOverrideInfo); -VkResult VKAPI_CALL vkCmdSetPerformanceStreamMarkerINTEL(VkCommandBuffer commandBuffer, const VkPerformanceStreamMarkerInfoINTEL *pMarkerInfo); -void VKAPI_CALL vkCmdSetPolygonModeEXT(VkCommandBuffer commandBuffer, VkPolygonMode polygonMode); -void VKAPI_CALL vkCmdSetPrimitiveRestartEnable(VkCommandBuffer commandBuffer, VkBool32 primitiveRestartEnable); -void VKAPI_CALL vkCmdSetPrimitiveRestartEnableEXT(VkCommandBuffer commandBuffer, VkBool32 primitiveRestartEnable); -void VKAPI_CALL vkCmdSetPrimitiveTopology(VkCommandBuffer commandBuffer, VkPrimitiveTopology primitiveTopology); -void VKAPI_CALL vkCmdSetPrimitiveTopologyEXT(VkCommandBuffer commandBuffer, VkPrimitiveTopology primitiveTopology); -void VKAPI_CALL vkCmdSetProvokingVertexModeEXT(VkCommandBuffer commandBuffer, VkProvokingVertexModeEXT provokingVertexMode); -void VKAPI_CALL vkCmdSetRasterizationSamplesEXT(VkCommandBuffer commandBuffer, VkSampleCountFlagBits rasterizationSamples); -void VKAPI_CALL vkCmdSetRasterizationStreamEXT(VkCommandBuffer commandBuffer, uint32_t rasterizationStream); -void VKAPI_CALL vkCmdSetRasterizerDiscardEnable(VkCommandBuffer commandBuffer, VkBool32 rasterizerDiscardEnable); -void VKAPI_CALL vkCmdSetRasterizerDiscardEnableEXT(VkCommandBuffer commandBuffer, VkBool32 rasterizerDiscardEnable); -void VKAPI_CALL vkCmdSetRayTracingPipelineStackSizeKHR(VkCommandBuffer commandBuffer, uint32_t pipelineStackSize); -void VKAPI_CALL vkCmdSetRepresentativeFragmentTestEnableNV(VkCommandBuffer commandBuffer, VkBool32 representativeFragmentTestEnable); -void VKAPI_CALL vkCmdSetSampleLocationsEXT(VkCommandBuffer commandBuffer, const VkSampleLocationsInfoEXT *pSampleLocationsInfo); -void VKAPI_CALL vkCmdSetSampleLocationsEnableEXT(VkCommandBuffer commandBuffer, VkBool32 sampleLocationsEnable); -void VKAPI_CALL vkCmdSetSampleMaskEXT(VkCommandBuffer commandBuffer, VkSampleCountFlagBits samples, const VkSampleMask *pSampleMask); -void VKAPI_CALL vkCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D *pScissors); -void VKAPI_CALL vkCmdSetScissorWithCount(VkCommandBuffer commandBuffer, uint32_t scissorCount, const VkRect2D *pScissors); -void VKAPI_CALL vkCmdSetScissorWithCountEXT(VkCommandBuffer commandBuffer, uint32_t scissorCount, const VkRect2D *pScissors); -void VKAPI_CALL vkCmdSetShadingRateImageEnableNV(VkCommandBuffer commandBuffer, VkBool32 shadingRateImageEnable); -void VKAPI_CALL vkCmdSetStencilCompareMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t compareMask); -void VKAPI_CALL vkCmdSetStencilOp(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp); -void VKAPI_CALL vkCmdSetStencilOpEXT(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, VkStencilOp failOp, VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp); -void VKAPI_CALL vkCmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference); -void VKAPI_CALL vkCmdSetStencilTestEnable(VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable); -void VKAPI_CALL vkCmdSetStencilTestEnableEXT(VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable); -void VKAPI_CALL vkCmdSetStencilWriteMask(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t writeMask); -void VKAPI_CALL vkCmdSetTessellationDomainOriginEXT(VkCommandBuffer commandBuffer, VkTessellationDomainOrigin domainOrigin); -void VKAPI_CALL vkCmdSetVertexInputEXT(VkCommandBuffer commandBuffer, uint32_t vertexBindingDescriptionCount, const VkVertexInputBindingDescription2EXT *pVertexBindingDescriptions, uint32_t vertexAttributeDescriptionCount, const VkVertexInputAttributeDescription2EXT *pVertexAttributeDescriptions); -void VKAPI_CALL vkCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport *pViewports); -void VKAPI_CALL vkCmdSetViewportShadingRatePaletteNV(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkShadingRatePaletteNV *pShadingRatePalettes); -void VKAPI_CALL vkCmdSetViewportSwizzleNV(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportSwizzleNV *pViewportSwizzles); -void VKAPI_CALL vkCmdSetViewportWScalingEnableNV(VkCommandBuffer commandBuffer, VkBool32 viewportWScalingEnable); -void VKAPI_CALL vkCmdSetViewportWScalingNV(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportWScalingNV *pViewportWScalings); -void VKAPI_CALL vkCmdSetViewportWithCount(VkCommandBuffer commandBuffer, uint32_t viewportCount, const VkViewport *pViewports); -void VKAPI_CALL vkCmdSetViewportWithCountEXT(VkCommandBuffer commandBuffer, uint32_t viewportCount, const VkViewport *pViewports); -void VKAPI_CALL vkCmdSubpassShadingHUAWEI(VkCommandBuffer commandBuffer); -void VKAPI_CALL vkCmdTraceRaysIndirect2KHR(VkCommandBuffer commandBuffer, VkDeviceAddress indirectDeviceAddress); -void VKAPI_CALL vkCmdTraceRaysIndirectKHR(VkCommandBuffer commandBuffer, const VkStridedDeviceAddressRegionKHR *pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR *pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR *pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR *pCallableShaderBindingTable, VkDeviceAddress indirectDeviceAddress); -void VKAPI_CALL vkCmdTraceRaysKHR(VkCommandBuffer commandBuffer, const VkStridedDeviceAddressRegionKHR *pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR *pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR *pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR *pCallableShaderBindingTable, uint32_t width, uint32_t height, uint32_t depth); -void VKAPI_CALL vkCmdTraceRaysNV(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, uint32_t width, uint32_t height, uint32_t depth); -void VKAPI_CALL vkCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void *pData); -void VKAPI_CALL vkCmdWaitEvents(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers, uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers, uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers); -void VKAPI_CALL vkCmdWaitEvents2(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents, const VkDependencyInfo *pDependencyInfos); -void VKAPI_CALL vkCmdWaitEvents2KHR(VkCommandBuffer commandBuffer, uint32_t eventCount, const VkEvent *pEvents, const VkDependencyInfo *pDependencyInfos); -void VKAPI_CALL vkCmdWriteAccelerationStructuresPropertiesKHR(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR *pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); -void VKAPI_CALL vkCmdWriteAccelerationStructuresPropertiesNV(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureNV *pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); -void VKAPI_CALL vkCmdWriteBufferMarker2AMD(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker); -void VKAPI_CALL vkCmdWriteBufferMarkerAMD(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkBuffer dstBuffer, VkDeviceSize dstOffset, uint32_t marker); -void VKAPI_CALL vkCmdWriteMicromapsPropertiesEXT(VkCommandBuffer commandBuffer, uint32_t micromapCount, const VkMicromapEXT *pMicromaps, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); -void VKAPI_CALL vkCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t query); -void VKAPI_CALL vkCmdWriteTimestamp2(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkQueryPool queryPool, uint32_t query); -void VKAPI_CALL vkCmdWriteTimestamp2KHR(VkCommandBuffer commandBuffer, VkPipelineStageFlags2 stage, VkQueryPool queryPool, uint32_t query); -VkResult VKAPI_CALL vkCompileDeferredNV(VkDevice device, VkPipeline pipeline, uint32_t shader); -VkResult VKAPI_CALL vkCopyAccelerationStructureKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyAccelerationStructureInfoKHR *pInfo); -VkResult VKAPI_CALL vkCopyAccelerationStructureToMemoryKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyAccelerationStructureToMemoryInfoKHR *pInfo); -VkResult VKAPI_CALL vkCopyMemoryToAccelerationStructureKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMemoryToAccelerationStructureInfoKHR *pInfo); -VkResult VKAPI_CALL vkCopyMemoryToMicromapEXT(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMemoryToMicromapInfoEXT *pInfo); -VkResult VKAPI_CALL vkCopyMicromapEXT(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMicromapInfoEXT *pInfo); -VkResult VKAPI_CALL vkCopyMicromapToMemoryEXT(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMicromapToMemoryInfoEXT *pInfo); -VkResult VKAPI_CALL vkCreateAccelerationStructureKHR(VkDevice device, const VkAccelerationStructureCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkAccelerationStructureKHR *pAccelerationStructure); -VkResult VKAPI_CALL vkCreateAccelerationStructureNV(VkDevice device, const VkAccelerationStructureCreateInfoNV *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkAccelerationStructureNV *pAccelerationStructure); -VkResult VKAPI_CALL vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer); -VkResult VKAPI_CALL vkCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkBufferView *pView); -VkResult VKAPI_CALL vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool); -VkResult VKAPI_CALL vkCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines); -VkResult VKAPI_CALL vkCreateCuFunctionNVX(VkDevice device, const VkCuFunctionCreateInfoNVX *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkCuFunctionNVX *pFunction); -VkResult VKAPI_CALL vkCreateCuModuleNVX(VkDevice device, const VkCuModuleCreateInfoNVX *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkCuModuleNVX *pModule); -VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback); -VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT *pMessenger); -VkResult VKAPI_CALL vkCreateDeferredOperationKHR(VkDevice device, const VkAllocationCallbacks *pAllocator, VkDeferredOperationKHR *pDeferredOperation); -VkResult VKAPI_CALL vkCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool); -VkResult VKAPI_CALL vkCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout); -VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorUpdateTemplate *pDescriptorUpdateTemplate); -VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplateKHR(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorUpdateTemplate *pDescriptorUpdateTemplate); -VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDevice *pDevice); -VkResult VKAPI_CALL vkCreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkEvent *pEvent); -VkResult VKAPI_CALL vkCreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence); -VkResult VKAPI_CALL vkCreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer); -VkResult VKAPI_CALL vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines); -VkResult VKAPI_CALL vkCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImage *pImage); -VkResult VKAPI_CALL vkCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImageView *pView); -VkResult VKAPI_CALL vkCreateIndirectCommandsLayoutNV(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNV *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkIndirectCommandsLayoutNV *pIndirectCommandsLayout); -VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance); -VkResult VKAPI_CALL vkCreateMicromapEXT(VkDevice device, const VkMicromapCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkMicromapEXT *pMicromap); -VkResult VKAPI_CALL vkCreateOpticalFlowSessionNV(VkDevice device, const VkOpticalFlowSessionCreateInfoNV *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkOpticalFlowSessionNV *pSession); -VkResult VKAPI_CALL vkCreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache); -VkResult VKAPI_CALL vkCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout); -VkResult VKAPI_CALL vkCreatePrivateDataSlot(VkDevice device, const VkPrivateDataSlotCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPrivateDataSlot *pPrivateDataSlot); -VkResult VKAPI_CALL vkCreatePrivateDataSlotEXT(VkDevice device, const VkPrivateDataSlotCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPrivateDataSlot *pPrivateDataSlot); -VkResult VKAPI_CALL vkCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool); -VkResult VKAPI_CALL vkCreateRayTracingPipelinesKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoKHR *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines); -VkResult VKAPI_CALL vkCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoNV *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines); -VkResult VKAPI_CALL vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass); -VkResult VKAPI_CALL vkCreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass); -VkResult VKAPI_CALL vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass); -VkResult VKAPI_CALL vkCreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSampler *pSampler); -VkResult VKAPI_CALL vkCreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSamplerYcbcrConversion *pYcbcrConversion); -VkResult VKAPI_CALL vkCreateSamplerYcbcrConversionKHR(VkDevice device, const VkSamplerYcbcrConversionCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSamplerYcbcrConversion *pYcbcrConversion); -VkResult VKAPI_CALL vkCreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore); -VkResult VKAPI_CALL vkCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule); -VkResult VKAPI_CALL vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain); -VkResult VKAPI_CALL vkCreateValidationCacheEXT(VkDevice device, const VkValidationCacheCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkValidationCacheEXT *pValidationCache); -VkResult VKAPI_CALL vkCreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface); -VkResult VKAPI_CALL vkDebugMarkerSetObjectNameEXT(VkDevice device, const VkDebugMarkerObjectNameInfoEXT *pNameInfo); -VkResult VKAPI_CALL vkDebugMarkerSetObjectTagEXT(VkDevice device, const VkDebugMarkerObjectTagInfoEXT *pTagInfo); -void VKAPI_CALL vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char *pLayerPrefix, const char *pMessage); -VkResult VKAPI_CALL vkDeferredOperationJoinKHR(VkDevice device, VkDeferredOperationKHR operation); -void VKAPI_CALL vkDestroyAccelerationStructureKHR(VkDevice device, VkAccelerationStructureKHR accelerationStructure, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyAccelerationStructureNV(VkDevice device, VkAccelerationStructureNV accelerationStructure, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyCuFunctionNVX(VkDevice device, VkCuFunctionNVX function, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyCuModuleNVX(VkDevice device, VkCuModuleNVX module, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyDeferredOperationKHR(VkDevice device, VkDeferredOperationKHR operation, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyDescriptorUpdateTemplateKHR(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyIndirectCommandsLayoutNV(VkDevice device, VkIndirectCommandsLayoutNV indirectCommandsLayout, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyMicromapEXT(VkDevice device, VkMicromapEXT micromap, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyOpticalFlowSessionNV(VkDevice device, VkOpticalFlowSessionNV session, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyPrivateDataSlot(VkDevice device, VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyPrivateDataSlotEXT(VkDevice device, VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroySamplerYcbcrConversionKHR(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkDestroyValidationCacheEXT(VkDevice device, VkValidationCacheEXT validationCache, const VkAllocationCallbacks *pAllocator); -VkResult VKAPI_CALL vkDeviceWaitIdle(VkDevice device); -VkResult VKAPI_CALL vkEndCommandBuffer(VkCommandBuffer commandBuffer); -VkResult VKAPI_CALL vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName, uint32_t *pPropertyCount, VkExtensionProperties *pProperties); -VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkLayerProperties *pProperties); -VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pPropertyCount, VkExtensionProperties *pProperties); -VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t *pPropertyCount, VkLayerProperties *pProperties); -VkResult VKAPI_CALL vkEnumerateInstanceVersion(uint32_t *pApiVersion); -VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties); -VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroupsKHR(VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties); -VkResult VKAPI_CALL vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, uint32_t *pCounterCount, VkPerformanceCounterKHR *pCounters, VkPerformanceCounterDescriptionKHR *pCounterDescriptions); -VkResult VKAPI_CALL vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices); -VkResult VKAPI_CALL vkFlushMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange *pMemoryRanges); -void VKAPI_CALL vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers); -VkResult VKAPI_CALL vkFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets); -void VKAPI_CALL vkFreeMemory(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks *pAllocator); -void VKAPI_CALL vkGetAccelerationStructureBuildSizesKHR(VkDevice device, VkAccelerationStructureBuildTypeKHR buildType, const VkAccelerationStructureBuildGeometryInfoKHR *pBuildInfo, const uint32_t *pMaxPrimitiveCounts, VkAccelerationStructureBuildSizesInfoKHR *pSizeInfo); -VkDeviceAddress VKAPI_CALL vkGetAccelerationStructureDeviceAddressKHR(VkDevice device, const VkAccelerationStructureDeviceAddressInfoKHR *pInfo); -VkResult VKAPI_CALL vkGetAccelerationStructureHandleNV(VkDevice device, VkAccelerationStructureNV accelerationStructure, size_t dataSize, void *pData); -void VKAPI_CALL vkGetAccelerationStructureMemoryRequirementsNV(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNV *pInfo, VkMemoryRequirements2KHR *pMemoryRequirements); -VkResult VKAPI_CALL vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT(VkDevice device, const VkAccelerationStructureCaptureDescriptorDataInfoEXT *pInfo, void *pData); -VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo *pInfo); -VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddressEXT(VkDevice device, const VkBufferDeviceAddressInfo *pInfo); -VkDeviceAddress VKAPI_CALL vkGetBufferDeviceAddressKHR(VkDevice device, const VkBufferDeviceAddressInfo *pInfo); -void VKAPI_CALL vkGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements); -void VKAPI_CALL vkGetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2 *pInfo, VkMemoryRequirements2 *pMemoryRequirements); -void VKAPI_CALL vkGetBufferMemoryRequirements2KHR(VkDevice device, const VkBufferMemoryRequirementsInfo2 *pInfo, VkMemoryRequirements2 *pMemoryRequirements); -uint64_t VKAPI_CALL vkGetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo *pInfo); -uint64_t VKAPI_CALL vkGetBufferOpaqueCaptureAddressKHR(VkDevice device, const VkBufferDeviceAddressInfo *pInfo); -VkResult VKAPI_CALL vkGetBufferOpaqueCaptureDescriptorDataEXT(VkDevice device, const VkBufferCaptureDescriptorDataInfoEXT *pInfo, void *pData); -VkResult VKAPI_CALL vkGetCalibratedTimestampsEXT(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoEXT *pTimestampInfos, uint64_t *pTimestamps, uint64_t *pMaxDeviation); -uint32_t VKAPI_CALL vkGetDeferredOperationMaxConcurrencyKHR(VkDevice device, VkDeferredOperationKHR operation); -VkResult VKAPI_CALL vkGetDeferredOperationResultKHR(VkDevice device, VkDeferredOperationKHR operation); -void VKAPI_CALL vkGetDescriptorEXT(VkDevice device, const VkDescriptorGetInfoEXT *pDescriptorInfo, size_t dataSize, void *pDescriptor); -void VKAPI_CALL vkGetDescriptorSetHostMappingVALVE(VkDevice device, VkDescriptorSet descriptorSet, void **ppData); -void VKAPI_CALL vkGetDescriptorSetLayoutBindingOffsetEXT(VkDevice device, VkDescriptorSetLayout layout, uint32_t binding, VkDeviceSize *pOffset); -void VKAPI_CALL vkGetDescriptorSetLayoutHostMappingInfoVALVE(VkDevice device, const VkDescriptorSetBindingReferenceVALVE *pBindingReference, VkDescriptorSetLayoutHostMappingInfoVALVE *pHostMapping); -void VKAPI_CALL vkGetDescriptorSetLayoutSizeEXT(VkDevice device, VkDescriptorSetLayout layout, VkDeviceSize *pLayoutSizeInBytes); -void VKAPI_CALL vkGetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, VkDescriptorSetLayoutSupport *pSupport); -void VKAPI_CALL vkGetDescriptorSetLayoutSupportKHR(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, VkDescriptorSetLayoutSupport *pSupport); -void VKAPI_CALL vkGetDeviceAccelerationStructureCompatibilityKHR(VkDevice device, const VkAccelerationStructureVersionInfoKHR *pVersionInfo, VkAccelerationStructureCompatibilityKHR *pCompatibility); -void VKAPI_CALL vkGetDeviceBufferMemoryRequirements(VkDevice device, const VkDeviceBufferMemoryRequirements *pInfo, VkMemoryRequirements2 *pMemoryRequirements); -void VKAPI_CALL vkGetDeviceBufferMemoryRequirementsKHR(VkDevice device, const VkDeviceBufferMemoryRequirements *pInfo, VkMemoryRequirements2 *pMemoryRequirements); -VkResult VKAPI_CALL vkGetDeviceFaultInfoEXT(VkDevice device, VkDeviceFaultCountsEXT *pFaultCounts, VkDeviceFaultInfoEXT *pFaultInfo); -void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags *pPeerMemoryFeatures); -void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeaturesKHR(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags *pPeerMemoryFeatures); -VkResult VKAPI_CALL vkGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR *pDeviceGroupPresentCapabilities); -VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR *pModes); -void VKAPI_CALL vkGetDeviceImageMemoryRequirements(VkDevice device, const VkDeviceImageMemoryRequirements *pInfo, VkMemoryRequirements2 *pMemoryRequirements); -void VKAPI_CALL vkGetDeviceImageMemoryRequirementsKHR(VkDevice device, const VkDeviceImageMemoryRequirements *pInfo, VkMemoryRequirements2 *pMemoryRequirements); -void VKAPI_CALL vkGetDeviceImageSparseMemoryRequirements(VkDevice device, const VkDeviceImageMemoryRequirements *pInfo, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements); -void VKAPI_CALL vkGetDeviceImageSparseMemoryRequirementsKHR(VkDevice device, const VkDeviceImageMemoryRequirements *pInfo, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements); -void VKAPI_CALL vkGetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory memory, VkDeviceSize *pCommittedMemoryInBytes); -uint64_t VKAPI_CALL vkGetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo *pInfo); -uint64_t VKAPI_CALL vkGetDeviceMemoryOpaqueCaptureAddressKHR(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo *pInfo); -void VKAPI_CALL vkGetDeviceMicromapCompatibilityEXT(VkDevice device, const VkMicromapVersionInfoEXT *pVersionInfo, VkAccelerationStructureCompatibilityKHR *pCompatibility); -PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char *pName); -void VKAPI_CALL vkGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue); -void VKAPI_CALL vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 *pQueueInfo, VkQueue *pQueue); -VkResult VKAPI_CALL vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI(VkDevice device, VkRenderPass renderpass, VkExtent2D *pMaxWorkgroupSize); -VkResult VKAPI_CALL vkGetDynamicRenderingTilePropertiesQCOM(VkDevice device, const VkRenderingInfo *pRenderingInfo, VkTilePropertiesQCOM *pProperties); -VkResult VKAPI_CALL vkGetEventStatus(VkDevice device, VkEvent event); -VkResult VKAPI_CALL vkGetFenceStatus(VkDevice device, VkFence fence); -VkResult VKAPI_CALL vkGetFramebufferTilePropertiesQCOM(VkDevice device, VkFramebuffer framebuffer, uint32_t *pPropertiesCount, VkTilePropertiesQCOM *pProperties); -void VKAPI_CALL vkGetGeneratedCommandsMemoryRequirementsNV(VkDevice device, const VkGeneratedCommandsMemoryRequirementsInfoNV *pInfo, VkMemoryRequirements2 *pMemoryRequirements); -void VKAPI_CALL vkGetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements); -void VKAPI_CALL vkGetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2 *pInfo, VkMemoryRequirements2 *pMemoryRequirements); -void VKAPI_CALL vkGetImageMemoryRequirements2KHR(VkDevice device, const VkImageMemoryRequirementsInfo2 *pInfo, VkMemoryRequirements2 *pMemoryRequirements); -VkResult VKAPI_CALL vkGetImageOpaqueCaptureDescriptorDataEXT(VkDevice device, const VkImageCaptureDescriptorDataInfoEXT *pInfo, void *pData); -void VKAPI_CALL vkGetImageSparseMemoryRequirements(VkDevice device, VkImage image, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements *pSparseMemoryRequirements); -void VKAPI_CALL vkGetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2 *pInfo, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements); -void VKAPI_CALL vkGetImageSparseMemoryRequirements2KHR(VkDevice device, const VkImageSparseMemoryRequirementsInfo2 *pInfo, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements); -void VKAPI_CALL vkGetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource, VkSubresourceLayout *pLayout); -void VKAPI_CALL vkGetImageSubresourceLayout2EXT(VkDevice device, VkImage image, const VkImageSubresource2EXT *pSubresource, VkSubresourceLayout2EXT *pLayout); -VkResult VKAPI_CALL vkGetImageViewAddressNVX(VkDevice device, VkImageView imageView, VkImageViewAddressPropertiesNVX *pProperties); -uint32_t VKAPI_CALL vkGetImageViewHandleNVX(VkDevice device, const VkImageViewHandleInfoNVX *pInfo); -VkResult VKAPI_CALL vkGetImageViewOpaqueCaptureDescriptorDataEXT(VkDevice device, const VkImageViewCaptureDescriptorDataInfoEXT *pInfo, void *pData); -PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *pName); -VkResult VKAPI_CALL vkGetMemoryHostPointerPropertiesEXT(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, const void *pHostPointer, VkMemoryHostPointerPropertiesEXT *pMemoryHostPointerProperties); -VkResult VKAPI_CALL vkGetMemoryWin32HandleKHR(VkDevice device, const VkMemoryGetWin32HandleInfoKHR *pGetWin32HandleInfo, HANDLE *pHandle); -VkResult VKAPI_CALL vkGetMemoryWin32HandlePropertiesKHR(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, HANDLE handle, VkMemoryWin32HandlePropertiesKHR *pMemoryWin32HandleProperties); -void VKAPI_CALL vkGetMicromapBuildSizesEXT(VkDevice device, VkAccelerationStructureBuildTypeKHR buildType, const VkMicromapBuildInfoEXT *pBuildInfo, VkMicromapBuildSizesInfoEXT *pSizeInfo); -VkResult VKAPI_CALL vkGetPerformanceParameterINTEL(VkDevice device, VkPerformanceParameterTypeINTEL parameter, VkPerformanceValueINTEL *pValue); -VkResult VKAPI_CALL vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(VkPhysicalDevice physicalDevice, uint32_t *pTimeDomainCount, VkTimeDomainEXT *pTimeDomains); -VkResult VKAPI_CALL vkGetPhysicalDeviceCooperativeMatrixPropertiesNV(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkCooperativeMatrixPropertiesNV *pProperties); -void VKAPI_CALL vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, VkExternalBufferProperties *pExternalBufferProperties); -void VKAPI_CALL vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, VkExternalBufferProperties *pExternalBufferProperties); -void VKAPI_CALL vkGetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo, VkExternalFenceProperties *pExternalFenceProperties); -void VKAPI_CALL vkGetPhysicalDeviceExternalFencePropertiesKHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo, VkExternalFenceProperties *pExternalFenceProperties); -void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo, VkExternalSemaphoreProperties *pExternalSemaphoreProperties); -void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo, VkExternalSemaphoreProperties *pExternalSemaphoreProperties); -void VKAPI_CALL vkGetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures *pFeatures); -void VKAPI_CALL vkGetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2 *pFeatures); -void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2 *pFeatures); -void VKAPI_CALL vkGetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties *pFormatProperties); -void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2 *pFormatProperties); -void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2 *pFormatProperties); -VkResult VKAPI_CALL vkGetPhysicalDeviceFragmentShadingRatesKHR(VkPhysicalDevice physicalDevice, uint32_t *pFragmentShadingRateCount, VkPhysicalDeviceFragmentShadingRateKHR *pFragmentShadingRates); -VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties *pImageFormatProperties); -VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties); -VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties); -void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties *pMemoryProperties); -void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2 *pMemoryProperties); -void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2 *pMemoryProperties); -void VKAPI_CALL vkGetPhysicalDeviceMultisamplePropertiesEXT(VkPhysicalDevice physicalDevice, VkSampleCountFlagBits samples, VkMultisamplePropertiesEXT *pMultisampleProperties); -VkResult VKAPI_CALL vkGetPhysicalDeviceOpticalFlowImageFormatsNV(VkPhysicalDevice physicalDevice, const VkOpticalFlowImageFormatInfoNV *pOpticalFlowImageFormatInfo, uint32_t *pFormatCount, VkOpticalFlowImageFormatPropertiesNV *pImageFormatProperties); -VkResult VKAPI_CALL vkGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pRectCount, VkRect2D *pRects); -void VKAPI_CALL vkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties); -void VKAPI_CALL vkGetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2 *pProperties); -void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2 *pProperties); -void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR(VkPhysicalDevice physicalDevice, const VkQueryPoolPerformanceCreateInfoKHR *pPerformanceQueryCreateInfo, uint32_t *pNumPasses); -void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties *pQueueFamilyProperties); -void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2 *pQueueFamilyProperties); -void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2 *pQueueFamilyProperties); -void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t *pPropertyCount, VkSparseImageFormatProperties *pProperties); -void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo, uint32_t *pPropertyCount, VkSparseImageFormatProperties2 *pProperties); -void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo, uint32_t *pPropertyCount, VkSparseImageFormatProperties2 *pProperties); -VkResult VKAPI_CALL vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV(VkPhysicalDevice physicalDevice, uint32_t *pCombinationCount, VkFramebufferMixedSamplesCombinationNV *pCombinations); -VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, VkSurfaceCapabilities2KHR *pSurfaceCapabilities); -VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities); -VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, uint32_t *pSurfaceFormatCount, VkSurfaceFormat2KHR *pSurfaceFormats); -VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pSurfaceFormatCount, VkSurfaceFormatKHR *pSurfaceFormats); -VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes); -VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32 *pSupported); -VkResult VKAPI_CALL vkGetPhysicalDeviceToolProperties(VkPhysicalDevice physicalDevice, uint32_t *pToolCount, VkPhysicalDeviceToolProperties *pToolProperties); -VkResult VKAPI_CALL vkGetPhysicalDeviceToolPropertiesEXT(VkPhysicalDevice physicalDevice, uint32_t *pToolCount, VkPhysicalDeviceToolProperties *pToolProperties); -VkBool32 VKAPI_CALL vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex); -VkResult VKAPI_CALL vkGetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize, void *pData); -VkResult VKAPI_CALL vkGetPipelineExecutableInternalRepresentationsKHR(VkDevice device, const VkPipelineExecutableInfoKHR *pExecutableInfo, uint32_t *pInternalRepresentationCount, VkPipelineExecutableInternalRepresentationKHR *pInternalRepresentations); -VkResult VKAPI_CALL vkGetPipelineExecutablePropertiesKHR(VkDevice device, const VkPipelineInfoKHR *pPipelineInfo, uint32_t *pExecutableCount, VkPipelineExecutablePropertiesKHR *pProperties); -VkResult VKAPI_CALL vkGetPipelineExecutableStatisticsKHR(VkDevice device, const VkPipelineExecutableInfoKHR *pExecutableInfo, uint32_t *pStatisticCount, VkPipelineExecutableStatisticKHR *pStatistics); -VkResult VKAPI_CALL vkGetPipelinePropertiesEXT(VkDevice device, const VkPipelineInfoEXT *pPipelineInfo, VkBaseOutStructure *pPipelineProperties); -void VKAPI_CALL vkGetPrivateData(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t *pData); -void VKAPI_CALL vkGetPrivateDataEXT(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t *pData); -VkResult VKAPI_CALL vkGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void *pData, VkDeviceSize stride, VkQueryResultFlags flags); -void VKAPI_CALL vkGetQueueCheckpointData2NV(VkQueue queue, uint32_t *pCheckpointDataCount, VkCheckpointData2NV *pCheckpointData); -void VKAPI_CALL vkGetQueueCheckpointDataNV(VkQueue queue, uint32_t *pCheckpointDataCount, VkCheckpointDataNV *pCheckpointData); -VkResult VKAPI_CALL vkGetRayTracingCaptureReplayShaderGroupHandlesKHR(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void *pData); -VkResult VKAPI_CALL vkGetRayTracingShaderGroupHandlesKHR(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void *pData); -VkResult VKAPI_CALL vkGetRayTracingShaderGroupHandlesNV(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void *pData); -VkDeviceSize VKAPI_CALL vkGetRayTracingShaderGroupStackSizeKHR(VkDevice device, VkPipeline pipeline, uint32_t group, VkShaderGroupShaderKHR groupShader); -void VKAPI_CALL vkGetRenderAreaGranularity(VkDevice device, VkRenderPass renderPass, VkExtent2D *pGranularity); -VkResult VKAPI_CALL vkGetSamplerOpaqueCaptureDescriptorDataEXT(VkDevice device, const VkSamplerCaptureDescriptorDataInfoEXT *pInfo, void *pData); -VkResult VKAPI_CALL vkGetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t *pValue); -VkResult VKAPI_CALL vkGetSemaphoreCounterValueKHR(VkDevice device, VkSemaphore semaphore, uint64_t *pValue); -VkResult VKAPI_CALL vkGetShaderInfoAMD(VkDevice device, VkPipeline pipeline, VkShaderStageFlagBits shaderStage, VkShaderInfoTypeAMD infoType, size_t *pInfoSize, void *pInfo); -void VKAPI_CALL vkGetShaderModuleCreateInfoIdentifierEXT(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo, VkShaderModuleIdentifierEXT *pIdentifier); -void VKAPI_CALL vkGetShaderModuleIdentifierEXT(VkDevice device, VkShaderModule shaderModule, VkShaderModuleIdentifierEXT *pIdentifier); -VkResult VKAPI_CALL vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages); -VkResult VKAPI_CALL vkGetValidationCacheDataEXT(VkDevice device, VkValidationCacheEXT validationCache, size_t *pDataSize, void *pData); -VkResult VKAPI_CALL vkInitializePerformanceApiINTEL(VkDevice device, const VkInitializePerformanceApiInfoINTEL *pInitializeInfo); -VkResult VKAPI_CALL vkInvalidateMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange *pMemoryRanges); -VkResult VKAPI_CALL vkMapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void **ppData); -VkResult VKAPI_CALL vkMergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache *pSrcCaches); -VkResult VKAPI_CALL vkMergeValidationCachesEXT(VkDevice device, VkValidationCacheEXT dstCache, uint32_t srcCacheCount, const VkValidationCacheEXT *pSrcCaches); -void VKAPI_CALL vkQueueBeginDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo); -VkResult VKAPI_CALL vkQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo, VkFence fence); -void VKAPI_CALL vkQueueEndDebugUtilsLabelEXT(VkQueue queue); -void VKAPI_CALL vkQueueInsertDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo); -VkResult VKAPI_CALL vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo); -VkResult VKAPI_CALL vkQueueSetPerformanceConfigurationINTEL(VkQueue queue, VkPerformanceConfigurationINTEL configuration); -VkResult VKAPI_CALL vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence); -VkResult VKAPI_CALL vkQueueSubmit2(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2 *pSubmits, VkFence fence); -VkResult VKAPI_CALL vkQueueSubmit2KHR(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2 *pSubmits, VkFence fence); -VkResult VKAPI_CALL vkQueueWaitIdle(VkQueue queue); -VkResult VKAPI_CALL vkReleasePerformanceConfigurationINTEL(VkDevice device, VkPerformanceConfigurationINTEL configuration); -void VKAPI_CALL vkReleaseProfilingLockKHR(VkDevice device); -VkResult VKAPI_CALL vkReleaseSwapchainImagesEXT(VkDevice device, const VkReleaseSwapchainImagesInfoEXT *pReleaseInfo); -VkResult VKAPI_CALL vkResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags); -VkResult VKAPI_CALL vkResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags); -VkResult VKAPI_CALL vkResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags); -VkResult VKAPI_CALL vkResetEvent(VkDevice device, VkEvent event); -VkResult VKAPI_CALL vkResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences); -void VKAPI_CALL vkResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); -void VKAPI_CALL vkResetQueryPoolEXT(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount); -VkResult VKAPI_CALL vkSetDebugUtilsObjectNameEXT(VkDevice device, const VkDebugUtilsObjectNameInfoEXT *pNameInfo); -VkResult VKAPI_CALL vkSetDebugUtilsObjectTagEXT(VkDevice device, const VkDebugUtilsObjectTagInfoEXT *pTagInfo); -void VKAPI_CALL vkSetDeviceMemoryPriorityEXT(VkDevice device, VkDeviceMemory memory, float priority); -VkResult VKAPI_CALL vkSetEvent(VkDevice device, VkEvent event); -VkResult VKAPI_CALL vkSetPrivateData(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data); -VkResult VKAPI_CALL vkSetPrivateDataEXT(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data); -VkResult VKAPI_CALL vkSignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo *pSignalInfo); -VkResult VKAPI_CALL vkSignalSemaphoreKHR(VkDevice device, const VkSemaphoreSignalInfo *pSignalInfo); -void VKAPI_CALL vkSubmitDebugUtilsMessageEXT(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData); -void VKAPI_CALL vkTrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); -void VKAPI_CALL vkTrimCommandPoolKHR(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags); -void VKAPI_CALL vkUninitializePerformanceApiINTEL(VkDevice device); -void VKAPI_CALL vkUnmapMemory(VkDevice device, VkDeviceMemory memory); -void VKAPI_CALL vkUpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void *pData); -void VKAPI_CALL vkUpdateDescriptorSetWithTemplateKHR(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void *pData); -void VKAPI_CALL vkUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies); -VkResult VKAPI_CALL vkWaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout); -VkResult VKAPI_CALL vkWaitForPresentKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t presentId, uint64_t timeout); -VkResult VKAPI_CALL vkWaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo *pWaitInfo, uint64_t timeout); -VkResult VKAPI_CALL vkWaitSemaphoresKHR(VkDevice device, const VkSemaphoreWaitInfo *pWaitInfo, uint64_t timeout); -VkResult VKAPI_CALL vkWriteAccelerationStructuresPropertiesKHR(VkDevice device, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR *pAccelerationStructures, VkQueryType queryType, size_t dataSize, void *pData, size_t stride); -VkResult VKAPI_CALL vkWriteMicromapsPropertiesEXT(VkDevice device, uint32_t micromapCount, const VkMicromapEXT *pMicromaps, VkQueryType queryType, size_t dataSize, void *pData, size_t stride); -#endif /* VK_NO_PROTOTYPES */ - -#endif /* __WINE_VULKAN_H */ diff --git a/include/wine/vulkan_driver.h b/include/wine/vulkan_driver.h deleted file mode 100644 index f5269d554fb..00000000000 --- a/include/wine/vulkan_driver.h +++ /dev/null @@ -1,118 +0,0 @@ -/* Automatically generated from Vulkan vk.xml; DO NOT EDIT! - * - * This file is generated from Vulkan vk.xml file covered - * by the following copyright and permission notice: - * - * Copyright 2015-2022 The Khronos Group Inc. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#ifndef __WINE_VULKAN_DRIVER_H -#define __WINE_VULKAN_DRIVER_H - -/* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */ -#define WINE_VULKAN_DRIVER_VERSION 11 - -struct vulkan_funcs -{ - /* Vulkan global functions. These are the only calls at this point a graphics driver - * needs to provide. Other function calls will be provided indirectly by dispatch - * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice. - */ - VkResult (*p_vkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *); - VkResult (*p_vkCreateSwapchainKHR)(VkDevice, const VkSwapchainCreateInfoKHR *, const VkAllocationCallbacks *, VkSwapchainKHR *); - VkResult (*p_vkCreateWin32SurfaceKHR)(VkInstance, const VkWin32SurfaceCreateInfoKHR *, const VkAllocationCallbacks *, VkSurfaceKHR *); - void (*p_vkDestroyInstance)(VkInstance, const VkAllocationCallbacks *); - void (*p_vkDestroySurfaceKHR)(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks *); - void (*p_vkDestroySwapchainKHR)(VkDevice, VkSwapchainKHR, const VkAllocationCallbacks *); - VkResult (*p_vkEnumerateInstanceExtensionProperties)(const char *, uint32_t *, VkExtensionProperties *); - VkResult (*p_vkGetDeviceGroupSurfacePresentModesKHR)(VkDevice, VkSurfaceKHR, VkDeviceGroupPresentModeFlagsKHR *); - void * (*p_vkGetDeviceProcAddr)(VkDevice, const char *); - void * (*p_vkGetInstanceProcAddr)(VkInstance, const char *); - VkResult (*p_vkGetPhysicalDevicePresentRectanglesKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkRect2D *); - VkResult (*p_vkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *, VkSurfaceCapabilities2KHR *); - VkResult (*p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice, VkSurfaceKHR, VkSurfaceCapabilitiesKHR *); - VkResult (*p_vkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *, uint32_t *, VkSurfaceFormat2KHR *); - VkResult (*p_vkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkSurfaceFormatKHR *); - VkResult (*p_vkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkPresentModeKHR *); - VkResult (*p_vkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice, uint32_t, VkSurfaceKHR, VkBool32 *); - VkBool32 (*p_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice, uint32_t); - VkResult (*p_vkGetSwapchainImagesKHR)(VkDevice, VkSwapchainKHR, uint32_t *, VkImage *); - VkResult (*p_vkQueuePresentKHR)(VkQueue, const VkPresentInfoKHR *); - - /* winevulkan specific functions */ - VkSurfaceKHR (*p_wine_get_native_surface)(VkSurfaceKHR); -}; - -extern const struct vulkan_funcs * __wine_get_vulkan_driver(UINT version); - -static inline void *get_vulkan_driver_device_proc_addr( - const struct vulkan_funcs *vulkan_funcs, const char *name) -{ - if (!name || name[0] != 'v' || name[1] != 'k') return NULL; - - name += 2; - - if (!strcmp(name, "CreateSwapchainKHR")) - return vulkan_funcs->p_vkCreateSwapchainKHR; - if (!strcmp(name, "DestroySwapchainKHR")) - return vulkan_funcs->p_vkDestroySwapchainKHR; - if (!strcmp(name, "GetDeviceGroupSurfacePresentModesKHR")) - return vulkan_funcs->p_vkGetDeviceGroupSurfacePresentModesKHR; - if (!strcmp(name, "GetDeviceProcAddr")) - return vulkan_funcs->p_vkGetDeviceProcAddr; - if (!strcmp(name, "GetSwapchainImagesKHR")) - return vulkan_funcs->p_vkGetSwapchainImagesKHR; - if (!strcmp(name, "QueuePresentKHR")) - return vulkan_funcs->p_vkQueuePresentKHR; - - return NULL; -} - -static inline void *get_vulkan_driver_instance_proc_addr( - const struct vulkan_funcs *vulkan_funcs, VkInstance instance, const char *name) -{ - if (!name || name[0] != 'v' || name[1] != 'k') return NULL; - - name += 2; - - if (!strcmp(name, "CreateInstance")) - return vulkan_funcs->p_vkCreateInstance; - if (!strcmp(name, "EnumerateInstanceExtensionProperties")) - return vulkan_funcs->p_vkEnumerateInstanceExtensionProperties; - - if (!instance) return NULL; - - if (!strcmp(name, "CreateWin32SurfaceKHR")) - return vulkan_funcs->p_vkCreateWin32SurfaceKHR; - if (!strcmp(name, "DestroyInstance")) - return vulkan_funcs->p_vkDestroyInstance; - if (!strcmp(name, "DestroySurfaceKHR")) - return vulkan_funcs->p_vkDestroySurfaceKHR; - if (!strcmp(name, "GetInstanceProcAddr")) - return vulkan_funcs->p_vkGetInstanceProcAddr; - if (!strcmp(name, "GetPhysicalDevicePresentRectanglesKHR")) - return vulkan_funcs->p_vkGetPhysicalDevicePresentRectanglesKHR; - if (!strcmp(name, "GetPhysicalDeviceSurfaceCapabilities2KHR")) - return vulkan_funcs->p_vkGetPhysicalDeviceSurfaceCapabilities2KHR; - if (!strcmp(name, "GetPhysicalDeviceSurfaceCapabilitiesKHR")) - return vulkan_funcs->p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR; - if (!strcmp(name, "GetPhysicalDeviceSurfaceFormats2KHR")) - return vulkan_funcs->p_vkGetPhysicalDeviceSurfaceFormats2KHR; - if (!strcmp(name, "GetPhysicalDeviceSurfaceFormatsKHR")) - return vulkan_funcs->p_vkGetPhysicalDeviceSurfaceFormatsKHR; - if (!strcmp(name, "GetPhysicalDeviceSurfacePresentModesKHR")) - return vulkan_funcs->p_vkGetPhysicalDeviceSurfacePresentModesKHR; - if (!strcmp(name, "GetPhysicalDeviceSurfaceSupportKHR")) - return vulkan_funcs->p_vkGetPhysicalDeviceSurfaceSupportKHR; - if (!strcmp(name, "GetPhysicalDeviceWin32PresentationSupportKHR")) - return vulkan_funcs->p_vkGetPhysicalDeviceWin32PresentationSupportKHR; - - name -= 2; - - return get_vulkan_driver_device_proc_addr(vulkan_funcs, name); -} - -#endif /* __WINE_VULKAN_DRIVER_H */ From e813ca5771658b00875924ab88d525322e50d39f Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 12 Dec 2022 05:40:31 +0200 Subject: [PATCH 0003/2777] Remove configure and config.h.in. Those are autogenerated by Proton's build system and get outdated very quickly. --- configure | 23616 ------------------------------------------ include/config.h.in | 863 -- 2 files changed, 24479 deletions(-) delete mode 100755 configure delete mode 100644 include/config.h.in diff --git a/configure b/configure deleted file mode 100755 index bdffe3e28b2..00000000000 --- a/configure +++ /dev/null @@ -1,23616 +0,0 @@ -#! /bin/sh -# Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for Wine 8.0. -# -# Report bugs to . -# -# -# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, -# Inc. -# -# -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -as_nop=: -if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else $as_nop - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - - -# Reset variables that may have inherited troublesome values from -# the environment. - -# IFS needs to be set, to space, tab, and newline, in precisely that order. -# (If _AS_PATH_WALK were called with IFS unset, it would have the -# side effect of setting IFS to empty, thus disabling word splitting.) -# Quoting is to prevent editors from complaining about space-tab. -as_nl=' -' -export as_nl -IFS=" "" $as_nl" - -PS1='$ ' -PS2='> ' -PS4='+ ' - -# Ensure predictable behavior from utilities with locale-dependent output. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# We cannot yet rely on "unset" to work, but we need these variables -# to be unset--not just set to an empty or harmless value--now, to -# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct -# also avoids known problems related to "unset" and subshell syntax -# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). -for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH -do eval test \${$as_var+y} \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done - -# Ensure that fds 0, 1, and 2 are open. -if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi -if (exec 3>&2) ; then :; else exec 2>/dev/null; fi - -# The user is always right. -if ${PATH_SEPARATOR+false} :; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - test -r "$as_dir$0" && as_myself=$as_dir$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - - -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="as_nop=: -if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else \$as_nop - case \`(set -o) 2>/dev/null\` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ) -then : - -else \$as_nop - exitcode=1; echo positional parameters were not saved. -fi -test x\$exitcode = x0 || exit 1 -blah=\$(echo \$(echo blah)) -test x\"\$blah\" = xblah || exit 1 -test -x / || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null -then : - as_have_required=yes -else $as_nop - as_have_required=no -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null -then : - -else $as_nop - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - as_found=: - case $as_dir in #( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null -then : - CONFIG_SHELL=$as_shell as_have_required=yes - if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null -then : - break 2 -fi -fi - done;; - esac - as_found=false -done -IFS=$as_save_IFS -if $as_found -then : - -else $as_nop - if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null -then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi -fi - - - if test "x$CONFIG_SHELL" != x -then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 -fi - - if test x$as_have_required = xno -then : - printf "%s\n" "$0: This script requires a shell more modern than all" - printf "%s\n" "$0: the shells that I found on your system." - if test ${ZSH_VERSION+y} ; then - printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" - printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." - else - printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and -$0: wine-devel@winehq.org about your system, including any -$0: error possibly output before this message. Then install -$0: a modern shell, or manually run the script under such a -$0: shell if you do have one." - fi - exit 1 -fi -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit -# as_fn_nop -# --------- -# Do nothing but, unlike ":", preserve the value of $?. -as_fn_nop () -{ - return $? -} -as_nop=as_fn_nop - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null -then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else $as_nop - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null -then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else $as_nop - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - -# as_fn_nop -# --------- -# Do nothing but, unlike ":", preserve the value of $?. -as_fn_nop () -{ - return $? -} -as_nop=as_fn_nop - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - printf "%s\n" "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - - -# Determine whether it's possible to make 'echo' print without a newline. -# These variables are no longer used directly by Autoconf, but are AC_SUBSTed -# for compatibility with existing Makefiles. -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -# For backward compatibility with old third-party macros, we provide -# the shell variables $as_echo and $as_echo_n. New code should use -# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. -as_echo='printf %s\n' -as_echo_n='printf %s' - - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -test -n "$DJDIR" || exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_files= -ac_config_libobj_dir=. -LIBOBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME='Wine' -PACKAGE_TARNAME='wine' -PACKAGE_VERSION='8.0' -PACKAGE_STRING='Wine 8.0' -PACKAGE_BUGREPORT='wine-devel@winehq.org' -PACKAGE_URL='https://www.winehq.org' - -ac_unique_file="server/atom.c" -# Factoring default headers for most tests. -ac_includes_default="\ -#include -#ifdef HAVE_STDIO_H -# include -#endif -#ifdef HAVE_STDLIB_H -# include -#endif -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_INTTYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif" - -ac_header_c_list= -ac_subst_vars='LTLIBOBJS -LIBOBJS -TAGSFLAGS -RT_LIBS -WINELOADER_PROGRAMS -DELAYLOADFLAG -MSVCRTFLAGS -NETAPI_LIBS -NETAPI_CFLAGS -PROCSTAT_LIBS -GSSAPI_LIBS -GSSAPI_CFLAGS -KRB5_LIBS -KRB5_CFLAGS -FONTCONFIG_LIBS -FONTCONFIG_CFLAGS -CUPS_LIBS -CUPS_CFLAGS -CAPI20_LIBS -CAPI20_CFLAGS -SDL2_LIBS -SDL2_CFLAGS -UNWIND_LIBS -UNWIND_CFLAGS -UDEV_LIBS -UDEV_CFLAGS -OSS4_LIBS -OSS4_CFLAGS -ALSA_LIBS -GSTREAMER_LIBS -GSTREAMER_CFLAGS -PULSE_LIBS -PULSE_CFLAGS -GETTEXTPO_LIBS -FREETYPE_LIBS -FREETYPE_CFLAGS -RESOLV_LIBS -GPHOTO2_PORT_LIBS -GPHOTO2_PORT_CFLAGS -GPHOTO2_LIBS -GPHOTO2_CFLAGS -USB_LIBS -USB_CFLAGS -SANE_LIBS -SANE_CFLAGS -GNUTLS_LIBS -GNUTLS_CFLAGS -DBUS_LIBS -DBUS_CFLAGS -INOTIFY_LIBS -INOTIFY_CFLAGS -PCAP_LIBS -X_EXTRA_LIBS -X_LIBS -X_PRE_LIBS -X_CFLAGS -CPP -XMKMF -PTHREAD_LIBS -ZLIB_PE_LIBS -ZLIB_PE_CFLAGS -XSLT_PE_LIBS -XSLT_PE_CFLAGS -XML2_PE_LIBS -XML2_PE_CFLAGS -VKD3D_PE_LIBS -VKD3D_PE_CFLAGS -TIFF_PE_LIBS -TIFF_PE_CFLAGS -PNG_PE_LIBS -PNG_PE_CFLAGS -MPG123_PE_LIBS -MPG123_PE_CFLAGS -LDAP_PE_LIBS -LDAP_PE_CFLAGS -LCMS2_PE_LIBS -LCMS2_PE_CFLAGS -JXR_PE_LIBS -JXR_PE_CFLAGS -JPEG_PE_LIBS -JPEG_PE_CFLAGS -GSM_PE_LIBS -GSM_PE_CFLAGS -FAUDIO_PE_LIBS -FAUDIO_PE_CFLAGS -MINGW_PKG_CONFIG -PE_ARCHS -LIBWINE_DEPENDS -PRELINK -WINELOADER_DEPENDS -LIBWINE_LDFLAGS -LIBWINE_SHAREDLIB -ac_ct_OBJC -OBJCFLAGS -OBJC -OPENCL_LIBS -COREAUDIO_LIBS -SYSTEMCONFIGURATION_LIBS -SECURITY_LIBS -APPKIT_LIBS -CORESERVICES_LIBS -APPLICATIONSERVICES_LIBS -METAL_LIBS -IOKIT_LIBS -DISKARBITRATION_LIBS -COREFOUNDATION_LIBS -CARBON_LIBS -CONFIGURE_TARGETS -DISABLED_SUBDIRS -SUBDIRS -READELF -OTOOL -LDD -WINEPRELOADER_LDFLAGS -WINELOADER_LDFLAGS -TOP_INSTALL_DEV -TOP_INSTALL_LIB -UNIXLDFLAGS -UNIXDLLFLAGS -EXTRACFLAGS -LDEXECFLAGS -LDDLLFLAGS -DLLFLAGS -OPENGL_LIBS -I386_LIBS -ICOTOOL -CONVERT -RSVG -FONTFORGE -PKG_CONFIG -MSGFMT -LDCONFIG -EGREP -GREP -LN_S -RANLIB -STRIP -ac_ct_AR -AR -BISON -FLEX -SED_CMD -RUNTESTFLAGS -MAKEDEP -toolsdir -x86_64_DISABLED_SUBDIRS -x86_64_DELAYLOADFLAG -x86_64_TARGET -x86_64_DEBUG -x86_64_LDFLAGS -x86_64_EXTRACFLAGS -x86_64_CFLAGS -x86_64_CC -i386_DISABLED_SUBDIRS -i386_DELAYLOADFLAG -i386_TARGET -i386_DEBUG -i386_LDFLAGS -i386_EXTRACFLAGS -i386_CFLAGS -i386_CC -arm_DISABLED_SUBDIRS -arm_DELAYLOADFLAG -arm_TARGET -arm_DEBUG -arm_LDFLAGS -arm_EXTRACFLAGS -arm_CFLAGS -arm_CC -aarch64_DISABLED_SUBDIRS -aarch64_DELAYLOADFLAG -aarch64_TARGET -aarch64_DEBUG -aarch64_LDFLAGS -aarch64_EXTRACFLAGS -aarch64_CFLAGS -aarch64_CC -HOST_ARCH -toolsext -TARGETFLAGS -LD -CPPBIN -ac_ct_CXX -CXXFLAGS -CXX -OBJEXT -EXEEXT -ac_ct_CC -CPPFLAGS -LDFLAGS -CFLAGS -CC -SET_MAKE -srcdir -nlsdir -fontdir -dlldir -host_os -host_vendor -host_cpu -host -build_os -build_vendor -build_cpu -build -system_dllpath -target_alias -host_alias -build_alias -LIBS -ECHO_T -ECHO_N -ECHO_C -DEFS -mandir -localedir -libdir -psdir -pdfdir -dvidir -htmldir -infodir -docdir -oldincludedir -includedir -runstatedir -localstatedir -sharedstatedir -sysconfdir -datadir -datarootdir -libexecdir -sbindir -bindir -program_transform_name -prefix -exec_prefix -PACKAGE_URL -PACKAGE_BUGREPORT -PACKAGE_STRING -PACKAGE_VERSION -PACKAGE_TARNAME -PACKAGE_NAME -PATH_SEPARATOR -SHELL' -ac_subst_files='' -ac_user_opts=' -enable_option_checking -enable_archs -enable_win16 -enable_win64 -enable_tests -enable_build_id -enable_maintainer_mode -enable_silent_rules -enable_werror -with_alsa -with_capi -with_coreaudio -with_cups -with_dbus -with_float_abi -with_fontconfig -with_freetype -with_gettext -with_gettextpo -with_gphoto -with_gnutls -with_gssapi -with_gstreamer -with_inotify -with_krb5 -with_mingw -with_netapi -with_opencl -with_opengl -with_osmesa -with_oss -with_pcap -with_pthread -with_pulse -with_sane -with_sdl -with_udev -with_unwind -with_usb -with_v4l2 -with_vulkan -with_xcomposite -with_xcursor -with_xfixes -with_xinerama -with_xinput -with_xinput2 -with_xrandr -with_xrender -with_xshape -with_xshm -with_xxf86vm -with_system_dllpath -with_wine_tools -with_wine64 -enable_largefile -with_x -enable_acledit -enable_aclui -enable_activeds_tlb -enable_activeds -enable_actxprxy -enable_adsldp -enable_adsldpc -enable_advapi32 -enable_advpack -enable_amsi -enable_amstream -enable_apisetschema -enable_apphelp -enable_appwiz_cpl -enable_atl -enable_atl100 -enable_atl110 -enable_atl80 -enable_atl90 -enable_atlthunk -enable_atmlib -enable_authz -enable_avicap32 -enable_avifil32 -enable_avrt -enable_bcrypt -enable_bluetoothapis -enable_browseui -enable_bthprops_cpl -enable_cabinet -enable_capi2032 -enable_cards -enable_cdosys -enable_cfgmgr32 -enable_clusapi -enable_cng_sys -enable_combase -enable_comcat -enable_comctl32 -enable_comdlg32 -enable_compstui -enable_comsvcs -enable_concrt140 -enable_connect -enable_credui -enable_crtdll -enable_crypt32 -enable_cryptdlg -enable_cryptdll -enable_cryptext -enable_cryptnet -enable_cryptowinrt -enable_cryptsp -enable_cryptui -enable_ctapi32 -enable_ctl3d32 -enable_d2d1 -enable_d3d10 -enable_d3d10_1 -enable_d3d10core -enable_d3d11 -enable_d3d12 -enable_d3d8 -enable_d3d8thk -enable_d3d9 -enable_d3dcompiler_33 -enable_d3dcompiler_34 -enable_d3dcompiler_35 -enable_d3dcompiler_36 -enable_d3dcompiler_37 -enable_d3dcompiler_38 -enable_d3dcompiler_39 -enable_d3dcompiler_40 -enable_d3dcompiler_41 -enable_d3dcompiler_42 -enable_d3dcompiler_43 -enable_d3dcompiler_46 -enable_d3dcompiler_47 -enable_d3dim -enable_d3dim700 -enable_d3drm -enable_d3dx10_33 -enable_d3dx10_34 -enable_d3dx10_35 -enable_d3dx10_36 -enable_d3dx10_37 -enable_d3dx10_38 -enable_d3dx10_39 -enable_d3dx10_40 -enable_d3dx10_41 -enable_d3dx10_42 -enable_d3dx10_43 -enable_d3dx11_42 -enable_d3dx11_43 -enable_d3dx9_24 -enable_d3dx9_25 -enable_d3dx9_26 -enable_d3dx9_27 -enable_d3dx9_28 -enable_d3dx9_29 -enable_d3dx9_30 -enable_d3dx9_31 -enable_d3dx9_32 -enable_d3dx9_33 -enable_d3dx9_34 -enable_d3dx9_35 -enable_d3dx9_36 -enable_d3dx9_37 -enable_d3dx9_38 -enable_d3dx9_39 -enable_d3dx9_40 -enable_d3dx9_41 -enable_d3dx9_42 -enable_d3dx9_43 -enable_d3dxof -enable_davclnt -enable_dbgeng -enable_dbghelp -enable_dciman32 -enable_dcomp -enable_ddraw -enable_ddrawex -enable_devenum -enable_dhcpcsvc -enable_dhcpcsvc6 -enable_dhtmled_ocx -enable_diasymreader -enable_difxapi -enable_dinput -enable_dinput8 -enable_directmanipulation -enable_dispex -enable_dmband -enable_dmcompos -enable_dmime -enable_dmloader -enable_dmscript -enable_dmstyle -enable_dmsynth -enable_dmusic -enable_dmusic32 -enable_dnsapi -enable_dplay -enable_dplayx -enable_dpnaddr -enable_dpnet -enable_dpnhpast -enable_dpnhupnp -enable_dpnlobby -enable_dpvoice -enable_dpwsockx -enable_drmclien -enable_dsdmo -enable_dsound -enable_dsquery -enable_dssenh -enable_dsuiext -enable_dswave -enable_dwmapi -enable_dwrite -enable_dx8vb -enable_dxdiagn -enable_dxgi -enable_dxtrans -enable_dxva2 -enable_esent -enable_evr -enable_explorerframe -enable_faultrep -enable_feclient -enable_fltlib -enable_fltmgr_sys -enable_fntcache -enable_fontsub -enable_fusion -enable_fwpuclnt -enable_gameux -enable_gamingtcui -enable_gdi32 -enable_gdiplus -enable_glu32 -enable_gphoto2_ds -enable_gpkcsp -enable_hal -enable_hhctrl_ocx -enable_hid -enable_hidclass_sys -enable_hidparse_sys -enable_hlink -enable_hnetcfg -enable_http_sys -enable_httpapi -enable_ia2comproxy -enable_iccvid -enable_icmp -enable_ieframe -enable_ieproxy -enable_imaadp32_acm -enable_imagehlp -enable_imm32 -enable_inetcomm -enable_inetcpl_cpl -enable_inetmib1 -enable_infosoft -enable_initpki -enable_inkobj -enable_inseng -enable_iphlpapi -enable_iprop -enable_irprops_cpl -enable_itircl -enable_itss -enable_joy_cpl -enable_jscript -enable_jsproxy -enable_kerberos -enable_kernel32 -enable_kernelbase -enable_ksecdd_sys -enable_ksproxy_ax -enable_ksuser -enable_ktmw32 -enable_l3codeca_acm -enable_light_msstyles -enable_loadperf -enable_localspl -enable_localui -enable_lz32 -enable_mapi32 -enable_mapistub -enable_mciavi32 -enable_mcicda -enable_mciqtz32 -enable_mciseq -enable_mciwave -enable_mf -enable_mf3216 -enable_mferror -enable_mfmediaengine -enable_mfplat -enable_mfplay -enable_mfreadwrite -enable_mfsrcsnk -enable_mgmtapi -enable_midimap -enable_mlang -enable_mmcndmgr -enable_mmdevapi -enable_mountmgr_sys -enable_mp3dmod -enable_mpr -enable_mprapi -enable_msacm32_drv -enable_msacm32 -enable_msado15 -enable_msadp32_acm -enable_msasn1 -enable_mscat32 -enable_mscms -enable_mscoree -enable_mscorwks -enable_msctf -enable_msctfmonitor -enable_msctfp -enable_msdaps -enable_msdasql -enable_msdelta -enable_msdmo -enable_msdrm -enable_msftedit -enable_msg711_acm -enable_msgsm32_acm -enable_mshtml_tlb -enable_mshtml -enable_msi -enable_msident -enable_msimg32 -enable_msimsg -enable_msimtf -enable_msisip -enable_msisys_ocx -enable_msls31 -enable_msnet32 -enable_mspatcha -enable_msports -enable_msrle32 -enable_msscript_ocx -enable_mssign32 -enable_mssip32 -enable_mstask -enable_msv1_0 -enable_msvcirt -enable_msvcm80 -enable_msvcm90 -enable_msvcp100 -enable_msvcp110 -enable_msvcp120 -enable_msvcp120_app -enable_msvcp140 -enable_msvcp140_1 -enable_msvcp140_2 -enable_msvcp140_atomic_wait -enable_msvcp60 -enable_msvcp70 -enable_msvcp71 -enable_msvcp80 -enable_msvcp90 -enable_msvcp_win -enable_msvcr100 -enable_msvcr110 -enable_msvcr120 -enable_msvcr120_app -enable_msvcr70 -enable_msvcr71 -enable_msvcr80 -enable_msvcr90 -enable_msvcrt -enable_msvcrt20 -enable_msvcrt40 -enable_msvcrtd -enable_msvfw32 -enable_msvidc32 -enable_mswsock -enable_msxml -enable_msxml2 -enable_msxml3 -enable_msxml4 -enable_msxml6 -enable_mtxdm -enable_ncrypt -enable_nddeapi -enable_ndis_sys -enable_netapi32 -enable_netcfgx -enable_netio_sys -enable_netprofm -enable_netutils -enable_newdev -enable_ninput -enable_normaliz -enable_npmshtml -enable_npptools -enable_nsi -enable_nsiproxy_sys -enable_ntdll -enable_ntdsapi -enable_ntoskrnl_exe -enable_ntprint -enable_objsel -enable_odbc32 -enable_odbcbcp -enable_odbccp32 -enable_odbccu32 -enable_ole32 -enable_oleacc -enable_oleaut32 -enable_olecli32 -enable_oledb32 -enable_oledlg -enable_olepro32 -enable_olesvr32 -enable_olethk32 -enable_opcservices -enable_opencl -enable_opengl32 -enable_packager -enable_pdh -enable_photometadatahandler -enable_pidgen -enable_powrprof -enable_printui -enable_prntvpt -enable_propsys -enable_psapi -enable_pstorec -enable_pwrshplugin -enable_qasf -enable_qcap -enable_qdvd -enable_qedit -enable_qmgr -enable_qmgrprxy -enable_quartz -enable_query -enable_qwave -enable_rasapi32 -enable_rasdlg -enable_regapi -enable_resutils -enable_riched20 -enable_riched32 -enable_rpcrt4 -enable_rsabase -enable_rsaenh -enable_rstrtmgr -enable_rtutils -enable_rtworkq -enable_samlib -enable_sane_ds -enable_sapi -enable_sas -enable_scarddlg -enable_sccbase -enable_schannel -enable_schedsvc -enable_scrobj -enable_scrrun -enable_scsiport_sys -enable_sechost -enable_secur32 -enable_security -enable_sensapi -enable_serialui -enable_setupapi -enable_sfc -enable_sfc_os -enable_shcore -enable_shdoclc -enable_shdocvw -enable_shell32 -enable_shfolder -enable_shlwapi -enable_slbcsp -enable_slc -enable_snmpapi -enable_softpub -enable_spoolss -enable_sppc -enable_srclient -enable_srvcli -enable_sspicli -enable_stdole2_tlb -enable_stdole32_tlb -enable_sti -enable_strmdll -enable_svrapi -enable_sxs -enable_t2embed -enable_tapi32 -enable_taskschd -enable_tbs -enable_tdh -enable_tdi_sys -enable_threadpoolwinrt -enable_traffic -enable_twain_32 -enable_tzres -enable_ucrtbase -enable_uianimation -enable_uiautomationcore -enable_uiribbon -enable_unicows -enable_updspapi -enable_url -enable_urlmon -enable_usbd_sys -enable_user32 -enable_userenv -enable_usp10 -enable_utildll -enable_uxtheme -enable_vbscript -enable_vcomp -enable_vcomp100 -enable_vcomp110 -enable_vcomp120 -enable_vcomp140 -enable_vcomp90 -enable_vcruntime140 -enable_vcruntime140_1 -enable_vdmdbg -enable_version -enable_vga -enable_virtdisk -enable_vssapi -enable_vulkan_1 -enable_wbemdisp -enable_wbemprox -enable_wdscore -enable_webservices -enable_websocket -enable_wer -enable_wevtapi -enable_wevtsvc -enable_wiaservc -enable_wimgapi -enable_win32u -enable_windows_devices_enumeration -enable_windows_gaming_input -enable_windows_gaming_ui_gamebar -enable_windows_globalization -enable_windows_media_devices -enable_windows_media_speech -enable_windows_media -enable_windows_networking -enable_windowscodecs -enable_windowscodecsext -enable_winealsa_drv -enable_wineandroid_drv -enable_winebus_sys -enable_winecoreaudio_drv -enable_winecrt0 -enable_wined3d -enable_winegstreamer -enable_winehid_sys -enable_winemac_drv -enable_winemapi -enable_wineoss_drv -enable_wineps_drv -enable_winepulse_drv -enable_wineusb_sys -enable_winevulkan -enable_winex11_drv -enable_winexinput_sys -enable_wing32 -enable_winhttp -enable_wininet -enable_winmm -enable_winnls32 -enable_winprint -enable_winscard -enable_winspool_drv -enable_winsta -enable_wintab32 -enable_wintrust -enable_wintypes -enable_winusb -enable_wlanapi -enable_wlanui -enable_wldap32 -enable_wmasf -enable_wmi -enable_wmiutils -enable_wmp -enable_wmphoto -enable_wmvcore -enable_wnaspi32 -enable_wofutil -enable_wow64 -enable_wow64cpu -enable_wow64win -enable_wpc -enable_wpcap -enable_ws2_32 -enable_wsdapi -enable_wshom_ocx -enable_wsnmp32 -enable_wsock32 -enable_wtsapi32 -enable_wuapi -enable_wuaueng -enable_x3daudio1_0 -enable_x3daudio1_1 -enable_x3daudio1_2 -enable_x3daudio1_3 -enable_x3daudio1_4 -enable_x3daudio1_5 -enable_x3daudio1_6 -enable_x3daudio1_7 -enable_xactengine2_0 -enable_xactengine2_4 -enable_xactengine2_7 -enable_xactengine2_9 -enable_xactengine3_0 -enable_xactengine3_1 -enable_xactengine3_2 -enable_xactengine3_3 -enable_xactengine3_4 -enable_xactengine3_5 -enable_xactengine3_6 -enable_xactengine3_7 -enable_xapofx1_1 -enable_xapofx1_2 -enable_xapofx1_3 -enable_xapofx1_4 -enable_xapofx1_5 -enable_xaudio2_0 -enable_xaudio2_1 -enable_xaudio2_2 -enable_xaudio2_3 -enable_xaudio2_4 -enable_xaudio2_5 -enable_xaudio2_6 -enable_xaudio2_7 -enable_xaudio2_8 -enable_xaudio2_9 -enable_xinput1_1 -enable_xinput1_2 -enable_xinput1_3 -enable_xinput1_4 -enable_xinput9_1_0 -enable_xinputuap -enable_xmllite -enable_xolehlp -enable_xpsprint -enable_xpssvcs -enable_fonts -enable_include -enable_adsiid -enable_dmoguids -enable_dxerr8 -enable_dxerr9 -enable_dxguid -enable_faudio -enable_gsm -enable_jpeg -enable_jxr -enable_lcms2 -enable_ldap -enable_mfuuid -enable_mpg123 -enable_png -enable_strmbase -enable_strmiids -enable_tiff -enable_uuid -enable_vkd3d -enable_wbemuuid -enable_wine -enable_wmcodecdspuuid -enable_xml2 -enable_xslt -enable_zlib -enable_loader -enable_nls -enable_po -enable_arp -enable_aspnet_regiis -enable_attrib -enable_cabarc -enable_cacls -enable_certutil -enable_chcp_com -enable_clock -enable_cmd -enable_conhost -enable_control -enable_cscript -enable_dism -enable_dllhost -enable_dplaysvr -enable_dpnsvr -enable_dpvsetup -enable_dxdiag -enable_eject -enable_expand -enable_explorer -enable_extrac32 -enable_fc -enable_find -enable_findstr -enable_fsutil -enable_hh -enable_hostname -enable_icacls -enable_icinfo -enable_iexplore -enable_ipconfig -enable_lodctr -enable_mofcomp -enable_mshta -enable_msidb -enable_msiexec -enable_msinfo32 -enable_net -enable_netsh -enable_netstat -enable_ngen -enable_notepad -enable_oleview -enable_ping -enable_plugplay -enable_powershell -enable_presentationfontcache -enable_progman -enable_reg -enable_regasm -enable_regedit -enable_regini -enable_regsvcs -enable_regsvr32 -enable_robocopy -enable_rpcss -enable_rundll32 -enable_sc -enable_schtasks -enable_sdbinst -enable_secedit -enable_servicemodelreg -enable_services -enable_setx -enable_shutdown -enable_spoolsv -enable_start -enable_subst -enable_svchost -enable_systeminfo -enable_taskkill -enable_tasklist -enable_taskmgr -enable_termsv -enable_uninstaller -enable_unlodctr -enable_view -enable_wevtutil -enable_where -enable_whoami -enable_wineboot -enable_winebrowser -enable_winecfg -enable_wineconsole -enable_winedbg -enable_winedevice -enable_winefile -enable_winemenubuilder -enable_winemine -enable_winemsibuilder -enable_winepath -enable_winetest -enable_winhlp32 -enable_winmgmt -enable_winver -enable_wmic -enable_wmplayer -enable_wordpad -enable_write -enable_wscript -enable_wuauserv -enable_wusa -enable_xcopy -enable_server -enable_tools -enable_sfnt2fon -enable_widl -enable_winebuild -enable_winedump -enable_winegcc -enable_winemaker -enable_wmc -enable_wrc -' - ac_precious_vars='build_alias -host_alias -target_alias -CC -CFLAGS -LDFLAGS -LIBS -CPPFLAGS -CXX -CXXFLAGS -CCC -OBJC -OBJCFLAGS -FAUDIO_PE_CFLAGS -FAUDIO_PE_LIBS -GSM_PE_CFLAGS -GSM_PE_LIBS -JPEG_PE_CFLAGS -JPEG_PE_LIBS -JXR_PE_CFLAGS -JXR_PE_LIBS -LCMS2_PE_CFLAGS -LCMS2_PE_LIBS -LDAP_PE_CFLAGS -LDAP_PE_LIBS -MPG123_PE_CFLAGS -MPG123_PE_LIBS -PNG_PE_CFLAGS -PNG_PE_LIBS -TIFF_PE_CFLAGS -TIFF_PE_LIBS -VKD3D_PE_CFLAGS -VKD3D_PE_LIBS -XML2_PE_CFLAGS -XML2_PE_LIBS -XSLT_PE_CFLAGS -XSLT_PE_LIBS -ZLIB_PE_CFLAGS -ZLIB_PE_LIBS -XMKMF -CPP -INOTIFY_CFLAGS -INOTIFY_LIBS -DBUS_CFLAGS -DBUS_LIBS -GNUTLS_CFLAGS -GNUTLS_LIBS -SANE_CFLAGS -SANE_LIBS -USB_CFLAGS -USB_LIBS -GPHOTO2_CFLAGS -GPHOTO2_LIBS -GPHOTO2_PORT_CFLAGS -GPHOTO2_PORT_LIBS -FREETYPE_CFLAGS -FREETYPE_LIBS -PULSE_CFLAGS -PULSE_LIBS -GSTREAMER_CFLAGS -GSTREAMER_LIBS -UDEV_CFLAGS -UDEV_LIBS -UNWIND_CFLAGS -UNWIND_LIBS -SDL2_CFLAGS -SDL2_LIBS -CAPI20_CFLAGS -CAPI20_LIBS -CUPS_CFLAGS -CUPS_LIBS -FONTCONFIG_CFLAGS -FONTCONFIG_LIBS -KRB5_CFLAGS -KRB5_LIBS -GSSAPI_CFLAGS -GSSAPI_LIBS -NETAPI_CFLAGS -NETAPI_LIBS' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -ac_unrecognized_opts= -ac_unrecognized_sep= -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; - esac - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: \`$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: \`$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: \`$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: \`$ac_useropt'" - ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error $? "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information" - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`echo $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: `$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -\`configure' configures Wine 8.0 to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] - -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/wine] - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF - -X features: - --x-includes=DIR X include files are in DIR - --x-libraries=DIR X library files are in DIR - -System types: - --build=BUILD configure for building on BUILD [guessed] - --host=HOST cross-compile to build programs to run on HOST [BUILD] -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of Wine 8.0:";; - esac - cat <<\_ACEOF - -Optional Features: - --disable-option-checking ignore unrecognized --enable/--with options - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-archs={i386,x86_64,arm,aarch64} - enable multiple architectures for PE compilation - --disable-win16 do not include Win16 support - --enable-win64 build a Win64 emulator on AMD64 (won't run Win32 - binaries) - --disable-tests do not build the regression tests - --enable-build-id include .buildid section in output objects - --enable-maintainer-mode - enable maintainer-specific build rules - --enable-silent-rules use silent build rules (override: "make V=1") - --enable-werror treat compilation warnings as errors - --disable-largefile omit support for large files - -Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --without-alsa do not use the Alsa sound support - --without-capi do not use CAPI (ISDN support) - --without-coreaudio do not use the CoreAudio sound support - --without-cups do not use CUPS - --without-dbus do not use DBus (dynamic device support) - --with-float-abi=abi specify the ABI (soft|softfp|hard) for ARM platforms - --without-fontconfig do not use fontconfig - --without-freetype do not use the FreeType library - --without-gettext do not use gettext - --with-gettextpo use the GetTextPO library to rebuild po files - --without-gphoto do not use gphoto (Digital Camera support) - --without-gnutls do not use GnuTLS (schannel support) - --without-gssapi do not use GSSAPI (Kerberos SSP support) - --without-gstreamer do not use GStreamer (codecs support) - --without-inotify do not use inotify (filesystem change notifications) - --without-krb5 do not use krb5 (Kerberos) - --without-mingw do not use the MinGW cross-compiler - --without-netapi do not use the Samba NetAPI library - --without-opencl do not use OpenCL - --without-opengl do not use OpenGL - --without-osmesa do not use the OSMesa library - --without-oss do not use the OSS sound support - --without-pcap do not use the Packet Capture library - --without-pthread do not use the pthread library - --without-pulse do not use PulseAudio sound support - --without-sane do not use SANE (scanner support) - --without-sdl do not use SDL - --without-udev do not use udev (plug and play support) - --without-unwind do not use the libunwind library (exception - handling) - --without-usb do not use the libusb library - --without-v4l2 do not use v4l2 (video capture) - --without-vulkan do not use Vulkan - --without-xcomposite do not use the Xcomposite extension - --without-xcursor do not use the Xcursor extension - --without-xfixes do not use Xfixes for clipboard change notifications - --without-xinerama do not use Xinerama (legacy multi-monitor support) - --without-xinput do not use the Xinput extension - --without-xinput2 do not use the Xinput 2 extension - --without-xrandr do not use Xrandr (multi-monitor support) - --without-xrender do not use the Xrender extension - --without-xshape do not use the Xshape extension - --without-xshm do not use XShm (shared memory extension) - --without-xxf86vm do not use XFree video mode extension - --with-system-dllpath=PATH - load external PE dependencies from colon-separated - path PATH - --with-wine-tools=DIR use Wine tools from directory DIR - --with-wine64=DIR use the 64-bit Wine in DIR for a Wow64 build - --with-x use the X Window System - -Some influential environment variables: - CC C compiler command - CFLAGS C compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a - nonstandard directory - LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - CXX C++ compiler command - CXXFLAGS C++ compiler flags - OBJC Objective C compiler command - OBJCFLAGS Objective C compiler flags - FAUDIO_PE_CFLAGS - C compiler flags for the PE faudio, overriding the bundled - version - FAUDIO_PE_LIBS - Linker flags for the PE faudio, overriding the bundled version - GSM_PE_CFLAGS - C compiler flags for the PE gsm, overriding the bundled version - GSM_PE_LIBS Linker flags for the PE gsm, overriding the bundled version - JPEG_PE_CFLAGS - C compiler flags for the PE jpeg, overriding the bundled version - JPEG_PE_LIBS - Linker flags for the PE jpeg, overriding the bundled version - JXR_PE_CFLAGS - C compiler flags for the PE jxr, overriding the bundled version - JXR_PE_LIBS Linker flags for the PE jxr, overriding the bundled version - LCMS2_PE_CFLAGS - C compiler flags for the PE lcms2, overriding the bundled - version - LCMS2_PE_LIBS - Linker flags for the PE lcms2, overriding the bundled version - LDAP_PE_CFLAGS - C compiler flags for the PE ldap, overriding the bundled version - LDAP_PE_LIBS - Linker flags for the PE ldap, overriding the bundled version - MPG123_PE_CFLAGS - C compiler flags for the PE mpg123, overriding the bundled - version - MPG123_PE_LIBS - Linker flags for the PE mpg123, overriding the bundled version - PNG_PE_CFLAGS - C compiler flags for the PE png, overriding the bundled version - PNG_PE_LIBS Linker flags for the PE png, overriding the bundled version - TIFF_PE_CFLAGS - C compiler flags for the PE tiff, overriding the bundled version - TIFF_PE_LIBS - Linker flags for the PE tiff, overriding the bundled version - VKD3D_PE_CFLAGS - C compiler flags for the PE vkd3d, overriding the bundled - version - VKD3D_PE_LIBS - Linker flags for the PE vkd3d, overriding the bundled version - XML2_PE_CFLAGS - C compiler flags for the PE xml2, overriding the bundled version - XML2_PE_LIBS - Linker flags for the PE xml2, overriding the bundled version - XSLT_PE_CFLAGS - C compiler flags for the PE xslt, overriding the bundled version - XSLT_PE_LIBS - Linker flags for the PE xslt, overriding the bundled version - ZLIB_PE_CFLAGS - C compiler flags for the PE zlib, overriding the bundled version - ZLIB_PE_LIBS - Linker flags for the PE zlib, overriding the bundled version - XMKMF Path to xmkmf, Makefile generator for X Window System - CPP C preprocessor - INOTIFY_CFLAGS - C compiler flags for libinotify, overriding pkg-config - INOTIFY_LIBS - Linker flags for libinotify, overriding pkg-config - DBUS_CFLAGS C compiler flags for dbus-1, overriding pkg-config - DBUS_LIBS Linker flags for dbus-1, overriding pkg-config - GNUTLS_CFLAGS - C compiler flags for gnutls, overriding pkg-config - GNUTLS_LIBS Linker flags for gnutls, overriding pkg-config - SANE_CFLAGS C compiler flags for sane-backends, overriding pkg-config - SANE_LIBS Linker flags for sane-backends, overriding pkg-config - USB_CFLAGS C compiler flags for libusb-1.0, overriding pkg-config - USB_LIBS Linker flags for libusb-1.0, overriding pkg-config - GPHOTO2_CFLAGS - C compiler flags for libgphoto2, overriding pkg-config - GPHOTO2_LIBS - Linker flags for libgphoto2, overriding pkg-config - GPHOTO2_PORT_CFLAGS - C compiler flags for libgphoto2_port, overriding pkg-config - GPHOTO2_PORT_LIBS - Linker flags for libgphoto2_port, overriding pkg-config - FREETYPE_CFLAGS - C compiler flags for freetype2, overriding pkg-config - FREETYPE_LIBS - Linker flags for freetype2, overriding pkg-config - PULSE_CFLAGS - C compiler flags for libpulse, overriding pkg-config - PULSE_LIBS Linker flags for libpulse, overriding pkg-config - GSTREAMER_CFLAGS - C compiler flags for gstreamer-1.0 gstreamer-video-1.0 - gstreamer-audio-1.0, overriding pkg-config - GSTREAMER_LIBS - Linker flags for gstreamer-1.0 gstreamer-video-1.0 - gstreamer-audio-1.0, overriding pkg-config - UDEV_CFLAGS C compiler flags for libudev, overriding pkg-config - UDEV_LIBS Linker flags for libudev, overriding pkg-config - UNWIND_CFLAGS - C compiler flags for libunwind, overriding pkg-config - UNWIND_LIBS Linker flags for libunwind, overriding pkg-config - SDL2_CFLAGS C compiler flags for sdl2, overriding pkg-config - SDL2_LIBS Linker flags for sdl2, overriding pkg-config - CAPI20_CFLAGS - C compiler flags for capi20, overriding pkg-config - CAPI20_LIBS Linker flags for capi20, overriding pkg-config - CUPS_CFLAGS C compiler flags for cups, overriding pkg-config - CUPS_LIBS Linker flags for cups, overriding pkg-config - FONTCONFIG_CFLAGS - C compiler flags for fontconfig, overriding pkg-config - FONTCONFIG_LIBS - Linker flags for fontconfig, overriding pkg-config - KRB5_CFLAGS C compiler flags for krb5, overriding pkg-config - KRB5_LIBS Linker flags for krb5, overriding pkg-config - GSSAPI_CFLAGS - C compiler flags for krb5-gssapi, overriding pkg-config - GSSAPI_LIBS Linker flags for krb5-gssapi, overriding pkg-config - NETAPI_CFLAGS - C compiler flags for netapi, overriding pkg-config - NETAPI_LIBS Linker flags for netapi, overriding pkg-config - -Use these variables to override the choices made by `configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to . -Wine home page: . -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for configure.gnu first; this name is used for a wrapper for - # Metaconfig's "Configure" on case-insensitive file systems. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -Wine configure 8.0 -generated by GNU Autoconf 2.71 - -Copyright (C) 2021 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## - -# ac_fn_c_try_compile LINENO -# -------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext -then : - ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_compile - -# ac_fn_cxx_try_compile LINENO -# ---------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_cxx_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext -then : - ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_cxx_try_compile - -# ac_fn_c_try_link LINENO -# ----------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - } -then : - ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_link - -# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists and can be compiled using the include files in -# INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$3=yes" -else $as_nop - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -eval ac_res=\$$3 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_compile - -# ac_fn_objc_try_compile LINENO -# ----------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_objc_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest.beam - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_objc_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext -then : - ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_objc_try_compile - -# ac_fn_c_check_func LINENO FUNC VAR -# ---------------------------------- -# Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_c_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. */ - -#include -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main (void) -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$3=yes" -else $as_nop - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -fi -eval ac_res=\$$3 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_func - -# ac_fn_c_try_cpp LINENO -# ---------------------- -# Try to preprocess conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_cpp () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - } -then : - ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_cpp - -# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES -# ---------------------------------------------------- -# Tries to find if the field MEMBER exists in type AGGR, after including -# INCLUDES, setting cache variable VAR accordingly. -ac_fn_c_check_member () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 -printf %s "checking for $2.$3... " >&6; } -if eval test \${$4+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$5 -int -main (void) -{ -static $2 ac_aggr; -if (ac_aggr.$3) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$4=yes" -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$5 -int -main (void) -{ -static $2 ac_aggr; -if (sizeof ac_aggr.$3) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$4=yes" -else $as_nop - eval "$4=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -eval ac_res=\$$4 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_member - -# ac_fn_c_check_type LINENO TYPE VAR INCLUDES -# ------------------------------------------- -# Tests whether TYPE exists after having included INCLUDES, setting cache -# variable VAR accordingly. -ac_fn_c_check_type () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -printf %s "checking for $2... " >&6; } -if eval test \${$3+y} -then : - printf %s "(cached) " >&6 -else $as_nop - eval "$3=no" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main (void) -{ -if (sizeof ($2)) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main (void) -{ -if (sizeof (($2))) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else $as_nop - eval "$3=yes" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -eval ac_res=\$$3 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_type -ac_configure_args_raw= -for ac_arg -do - case $ac_arg in - *\'*) - ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append ac_configure_args_raw " '$ac_arg'" -done - -case $ac_configure_args_raw in - *$as_nl*) - ac_safe_unquote= ;; - *) - ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. - ac_unsafe_a="$ac_unsafe_z#~" - ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" - ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; -esac - -cat >config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by Wine $as_me 8.0, which was -generated by GNU Autoconf 2.71. Invocation command line was - - $ $0$ac_configure_args_raw - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - printf "%s\n" "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. We remove comments because anyway the quotes in there -# would cause problems or look ugly. -# WARNING: Use '\'' to represent an apostrophe within the trap. -# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. -trap 'exit_status=$? - # Sanitize IFS. - IFS=" "" $as_nl" - # Save into config.log some information that might help in debugging. - { - echo - - printf "%s\n" "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - # The following way of writing the cache mishandles newlines in values, -( - for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - (set) 2>&1 | - case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - sed -n \ - "s/'\''/'\''\\\\'\'''\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" - ;; #( - *) - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) - echo - - printf "%s\n" "## ----------------- ## -## Output variables. ## -## ----------------- ##" - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - printf "%s\n" "$ac_var='\''$ac_val'\''" - done | sort - echo - - if test -n "$ac_subst_files"; then - printf "%s\n" "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - printf "%s\n" "$ac_var='\''$ac_val'\''" - done | sort - echo - fi - - if test -s confdefs.h; then - printf "%s\n" "## ----------- ## -## confdefs.h. ## -## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - printf "%s\n" "$as_me: caught signal $ac_signal" - printf "%s\n" "$as_me: exit $exit_status" - } >&5 - rm -f core *.core core.conftest.* && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -printf "%s\n" "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h - -printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h - -printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h - -printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h - -printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h - -printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -if test -n "$CONFIG_SITE"; then - ac_site_files="$CONFIG_SITE" -elif test "x$prefix" != xNONE; then - ac_site_files="$prefix/share/config.site $prefix/etc/config.site" -else - ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" -fi - -for ac_site_file in $ac_site_files -do - case $ac_site_file in #( - */*) : - ;; #( - *) : - ac_site_file=./$ac_site_file ;; -esac - if test -f "$ac_site_file" && test -r "$ac_site_file"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5; } - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special files - # actually), so we avoid doing that. DJGPP emulates it as a regular file. - if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -printf "%s\n" "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -printf "%s\n" "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -# Test code for whether the C compiler supports C89 (global declarations) -ac_c_conftest_c89_globals=' -/* Does the compiler advertise C89 conformance? - Do not test the value of __STDC__, because some compilers set it to 0 - while being otherwise adequately conformant. */ -#if !defined __STDC__ -# error "Compiler does not advertise C89 conformance" -#endif - -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ -struct buf { int x; }; -struct buf * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not \xHH hex character constants. - These do not provoke an error unfortunately, instead are silently treated - as an "x". The following induces an error, until -std is added to get - proper ANSI mode. Curiously \x00 != x always comes out true, for an - array size at least. It is necessary to write \x00 == 0 to get something - that is true only with -std. */ -int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) '\''x'\'' -int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), - int, int);' - -# Test code for whether the C compiler supports C89 (body of main). -ac_c_conftest_c89_main=' -ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); -' - -# Test code for whether the C compiler supports C99 (global declarations) -ac_c_conftest_c99_globals=' -// Does the compiler advertise C99 conformance? -#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L -# error "Compiler does not advertise C99 conformance" -#endif - -#include -extern int puts (const char *); -extern int printf (const char *, ...); -extern int dprintf (int, const char *, ...); -extern void *malloc (size_t); - -// Check varargs macros. These examples are taken from C99 6.10.3.5. -// dprintf is used instead of fprintf to avoid needing to declare -// FILE and stderr. -#define debug(...) dprintf (2, __VA_ARGS__) -#define showlist(...) puts (#__VA_ARGS__) -#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) -static void -test_varargs_macros (void) -{ - int x = 1234; - int y = 5678; - debug ("Flag"); - debug ("X = %d\n", x); - showlist (The first, second, and third items.); - report (x>y, "x is %d but y is %d", x, y); -} - -// Check long long types. -#define BIG64 18446744073709551615ull -#define BIG32 4294967295ul -#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) -#if !BIG_OK - #error "your preprocessor is broken" -#endif -#if BIG_OK -#else - #error "your preprocessor is broken" -#endif -static long long int bignum = -9223372036854775807LL; -static unsigned long long int ubignum = BIG64; - -struct incomplete_array -{ - int datasize; - double data[]; -}; - -struct named_init { - int number; - const wchar_t *name; - double average; -}; - -typedef const char *ccp; - -static inline int -test_restrict (ccp restrict text) -{ - // See if C++-style comments work. - // Iterate through items via the restricted pointer. - // Also check for declarations in for loops. - for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) - continue; - return 0; -} - -// Check varargs and va_copy. -static bool -test_varargs (const char *format, ...) -{ - va_list args; - va_start (args, format); - va_list args_copy; - va_copy (args_copy, args); - - const char *str = ""; - int number = 0; - float fnumber = 0; - - while (*format) - { - switch (*format++) - { - case '\''s'\'': // string - str = va_arg (args_copy, const char *); - break; - case '\''d'\'': // int - number = va_arg (args_copy, int); - break; - case '\''f'\'': // float - fnumber = va_arg (args_copy, double); - break; - default: - break; - } - } - va_end (args_copy); - va_end (args); - - return *str && number && fnumber; -} -' - -# Test code for whether the C compiler supports C99 (body of main). -ac_c_conftest_c99_main=' - // Check bool. - _Bool success = false; - success |= (argc != 0); - - // Check restrict. - if (test_restrict ("String literal") == 0) - success = true; - char *restrict newvar = "Another string"; - - // Check varargs. - success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); - test_varargs_macros (); - - // Check flexible array members. - struct incomplete_array *ia = - malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); - ia->datasize = 10; - for (int i = 0; i < ia->datasize; ++i) - ia->data[i] = i * 1.234; - - // Check named initializers. - struct named_init ni = { - .number = 34, - .name = L"Test wide string", - .average = 543.34343, - }; - - ni.number = 58; - - int dynamic_array[ni.number]; - dynamic_array[0] = argv[0][0]; - dynamic_array[ni.number - 1] = 543; - - // work around unused variable warnings - ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' - || dynamic_array[ni.number - 1] != 543); -' - -# Test code for whether the C compiler supports C11 (global declarations) -ac_c_conftest_c11_globals=' -// Does the compiler advertise C11 conformance? -#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L -# error "Compiler does not advertise C11 conformance" -#endif - -// Check _Alignas. -char _Alignas (double) aligned_as_double; -char _Alignas (0) no_special_alignment; -extern char aligned_as_int; -char _Alignas (0) _Alignas (int) aligned_as_int; - -// Check _Alignof. -enum -{ - int_alignment = _Alignof (int), - int_array_alignment = _Alignof (int[100]), - char_alignment = _Alignof (char) -}; -_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); - -// Check _Noreturn. -int _Noreturn does_not_return (void) { for (;;) continue; } - -// Check _Static_assert. -struct test_static_assert -{ - int x; - _Static_assert (sizeof (int) <= sizeof (long int), - "_Static_assert does not work in struct"); - long int y; -}; - -// Check UTF-8 literals. -#define u8 syntax error! -char const utf8_literal[] = u8"happens to be ASCII" "another string"; - -// Check duplicate typedefs. -typedef long *long_ptr; -typedef long int *long_ptr; -typedef long_ptr long_ptr; - -// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. -struct anonymous -{ - union { - struct { int i; int j; }; - struct { int k; long int l; } w; - }; - int m; -} v1; -' - -# Test code for whether the C compiler supports C11 (body of main). -ac_c_conftest_c11_main=' - _Static_assert ((offsetof (struct anonymous, i) - == offsetof (struct anonymous, w.k)), - "Anonymous union alignment botch"); - v1.i = 2; - v1.w.k = 5; - ok |= v1.i != 5; -' - -# Test code for whether the C compiler supports C11 (complete). -ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} -${ac_c_conftest_c99_globals} -${ac_c_conftest_c11_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - ${ac_c_conftest_c99_main} - ${ac_c_conftest_c11_main} - return ok; -} -" - -# Test code for whether the C compiler supports C99 (complete). -ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} -${ac_c_conftest_c99_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - ${ac_c_conftest_c99_main} - return ok; -} -" - -# Test code for whether the C compiler supports C89 (complete). -ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_c_conftest_c89_main} - return ok; -} -" - -# Test code for whether the C++ compiler supports C++98 (global declarations) -ac_cxx_conftest_cxx98_globals=' -// Does the compiler advertise C++98 conformance? -#if !defined __cplusplus || __cplusplus < 199711L -# error "Compiler does not advertise C++98 conformance" -#endif - -// These inclusions are to reject old compilers that -// lack the unsuffixed header files. -#include -#include - -// and are *not* freestanding headers in C++98. -extern void assert (int); -namespace std { - extern int strcmp (const char *, const char *); -} - -// Namespaces, exceptions, and templates were all added after "C++ 2.0". -using std::exception; -using std::strcmp; - -namespace { - -void test_exception_syntax() -{ - try { - throw "test"; - } catch (const char *s) { - // Extra parentheses suppress a warning when building autoconf itself, - // due to lint rules shared with more typical C programs. - assert (!(strcmp) (s, "test")); - } -} - -template struct test_template -{ - T const val; - explicit test_template(T t) : val(t) {} - template T add(U u) { return static_cast(u) + val; } -}; - -} // anonymous namespace -' - -# Test code for whether the C++ compiler supports C++98 (body of main) -ac_cxx_conftest_cxx98_main=' - assert (argc); - assert (! argv[0]); -{ - test_exception_syntax (); - test_template tt (2.0); - assert (tt.add (4) == 6.0); - assert (true && !false); -} -' - -# Test code for whether the C++ compiler supports C++11 (global declarations) -ac_cxx_conftest_cxx11_globals=' -// Does the compiler advertise C++ 2011 conformance? -#if !defined __cplusplus || __cplusplus < 201103L -# error "Compiler does not advertise C++11 conformance" -#endif - -namespace cxx11test -{ - constexpr int get_val() { return 20; } - - struct testinit - { - int i; - double d; - }; - - class delegate - { - public: - delegate(int n) : n(n) {} - delegate(): delegate(2354) {} - - virtual int getval() { return this->n; }; - protected: - int n; - }; - - class overridden : public delegate - { - public: - overridden(int n): delegate(n) {} - virtual int getval() override final { return this->n * 2; } - }; - - class nocopy - { - public: - nocopy(int i): i(i) {} - nocopy() = default; - nocopy(const nocopy&) = delete; - nocopy & operator=(const nocopy&) = delete; - private: - int i; - }; - - // for testing lambda expressions - template Ret eval(Fn f, Ret v) - { - return f(v); - } - - // for testing variadic templates and trailing return types - template auto sum(V first) -> V - { - return first; - } - template auto sum(V first, Args... rest) -> V - { - return first + sum(rest...); - } -} -' - -# Test code for whether the C++ compiler supports C++11 (body of main) -ac_cxx_conftest_cxx11_main=' -{ - // Test auto and decltype - auto a1 = 6538; - auto a2 = 48573953.4; - auto a3 = "String literal"; - - int total = 0; - for (auto i = a3; *i; ++i) { total += *i; } - - decltype(a2) a4 = 34895.034; -} -{ - // Test constexpr - short sa[cxx11test::get_val()] = { 0 }; -} -{ - // Test initializer lists - cxx11test::testinit il = { 4323, 435234.23544 }; -} -{ - // Test range-based for - int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, - 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; - for (auto &x : array) { x += 23; } -} -{ - // Test lambda expressions - using cxx11test::eval; - assert (eval ([](int x) { return x*2; }, 21) == 42); - double d = 2.0; - assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0); - assert (d == 5.0); - assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0); - assert (d == 5.0); -} -{ - // Test use of variadic templates - using cxx11test::sum; - auto a = sum(1); - auto b = sum(1, 2); - auto c = sum(1.0, 2.0, 3.0); -} -{ - // Test constructor delegation - cxx11test::delegate d1; - cxx11test::delegate d2(); - cxx11test::delegate d3(45); -} -{ - // Test override and final - cxx11test::overridden o1(55464); -} -{ - // Test nullptr - char *c = nullptr; -} -{ - // Test template brackets - test_template<::test_template> v(test_template(12)); -} -{ - // Unicode literals - char const *utf8 = u8"UTF-8 string \u2500"; - char16_t const *utf16 = u"UTF-8 string \u2500"; - char32_t const *utf32 = U"UTF-32 string \u2500"; -} -' - -# Test code for whether the C compiler supports C++11 (complete). -ac_cxx_conftest_cxx11_program="${ac_cxx_conftest_cxx98_globals} -${ac_cxx_conftest_cxx11_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_cxx_conftest_cxx98_main} - ${ac_cxx_conftest_cxx11_main} - return ok; -} -" - -# Test code for whether the C compiler supports C++98 (complete). -ac_cxx_conftest_cxx98_program="${ac_cxx_conftest_cxx98_globals} -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_cxx_conftest_cxx98_main} - return ok; -} -" - -as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" -as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" -as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" -as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" -as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" -as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" -as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" -as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" -as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" - -# Auxiliary files required by this configure script. -ac_aux_files="config.guess config.sub" - -# Locations in which to look for auxiliary files. -ac_aux_dir_candidates="${srcdir}/tools" - -# Search for a directory containing all of the required auxiliary files, -# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. -# If we don't find one directory that contains all the files we need, -# we report the set of missing files from the *first* directory in -# $ac_aux_dir_candidates and give up. -ac_missing_aux_files="" -ac_first_candidate=: -printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in $ac_aux_dir_candidates -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - as_found=: - - printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 - ac_aux_dir_found=yes - ac_install_sh= - for ac_aux in $ac_aux_files - do - # As a special case, if "install-sh" is required, that requirement - # can be satisfied by any of "install-sh", "install.sh", or "shtool", - # and $ac_install_sh is set appropriately for whichever one is found. - if test x"$ac_aux" = x"install-sh" - then - if test -f "${as_dir}install-sh"; then - printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 - ac_install_sh="${as_dir}install-sh -c" - elif test -f "${as_dir}install.sh"; then - printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 - ac_install_sh="${as_dir}install.sh -c" - elif test -f "${as_dir}shtool"; then - printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 - ac_install_sh="${as_dir}shtool install -c" - else - ac_aux_dir_found=no - if $ac_first_candidate; then - ac_missing_aux_files="${ac_missing_aux_files} install-sh" - else - break - fi - fi - else - if test -f "${as_dir}${ac_aux}"; then - printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 - else - ac_aux_dir_found=no - if $ac_first_candidate; then - ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" - else - break - fi - fi - fi - done - if test "$ac_aux_dir_found" = yes; then - ac_aux_dir="$as_dir" - break - fi - ac_first_candidate=false - - as_found=false -done -IFS=$as_save_IFS -if $as_found -then : - -else $as_nop - as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 -fi - - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -if test -f "${ac_aux_dir}config.guess"; then - ac_config_guess="$SHELL ${ac_aux_dir}config.guess" -fi -if test -f "${ac_aux_dir}config.sub"; then - ac_config_sub="$SHELL ${ac_aux_dir}config.sub" -fi -if test -f "$ac_aux_dir/configure"; then - ac_configure="$SHELL ${ac_aux_dir}configure" -fi - -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' - and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -ac_config_headers="$ac_config_headers include/config.h" - - - -libwine_version="1.0" - - -# Check whether --enable-archs was given. -if test ${enable_archs+y} -then : - enableval=$enable_archs; -fi - -# Check whether --enable-win16 was given. -if test ${enable_win16+y} -then : - enableval=$enable_win16; -fi - -# Check whether --enable-win64 was given. -if test ${enable_win64+y} -then : - enableval=$enable_win64; -fi - -# Check whether --enable-tests was given. -if test ${enable_tests+y} -then : - enableval=$enable_tests; -fi - -# Check whether --enable-build-id was given. -if test ${enable_build_id+y} -then : - enableval=$enable_build_id; -fi - -# Check whether --enable-maintainer-mode was given. -if test ${enable_maintainer_mode+y} -then : - enableval=$enable_maintainer_mode; -fi - -# Check whether --enable-silent-rules was given. -if test ${enable_silent_rules+y} -then : - enableval=$enable_silent_rules; -fi - -# Check whether --enable-werror was given. -if test ${enable_werror+y} -then : - enableval=$enable_werror; -fi - - - -# Check whether --with-alsa was given. -if test ${with_alsa+y} -then : - withval=$with_alsa; -fi - - -# Check whether --with-capi was given. -if test ${with_capi+y} -then : - withval=$with_capi; -fi - - -# Check whether --with-coreaudio was given. -if test ${with_coreaudio+y} -then : - withval=$with_coreaudio; -fi - - -# Check whether --with-cups was given. -if test ${with_cups+y} -then : - withval=$with_cups; -fi - - -# Check whether --with-dbus was given. -if test ${with_dbus+y} -then : - withval=$with_dbus; -fi - - -# Check whether --with-float-abi was given. -if test ${with_float_abi+y} -then : - withval=$with_float_abi; -fi - - -# Check whether --with-fontconfig was given. -if test ${with_fontconfig+y} -then : - withval=$with_fontconfig; -fi - - -# Check whether --with-freetype was given. -if test ${with_freetype+y} -then : - withval=$with_freetype; -fi - - -# Check whether --with-gettext was given. -if test ${with_gettext+y} -then : - withval=$with_gettext; -fi - - -# Check whether --with-gettextpo was given. -if test ${with_gettextpo+y} -then : - withval=$with_gettextpo; if test "x$withval" = "xno"; then ac_cv_header_gettext_po_h=no; fi -fi - - -# Check whether --with-gphoto was given. -if test ${with_gphoto+y} -then : - withval=$with_gphoto; -fi - - -# Check whether --with-gnutls was given. -if test ${with_gnutls+y} -then : - withval=$with_gnutls; -fi - - -# Check whether --with-gssapi was given. -if test ${with_gssapi+y} -then : - withval=$with_gssapi; -fi - - -# Check whether --with-gstreamer was given. -if test ${with_gstreamer+y} -then : - withval=$with_gstreamer; -fi - - -# Check whether --with-inotify was given. -if test ${with_inotify+y} -then : - withval=$with_inotify; -fi - - -# Check whether --with-krb5 was given. -if test ${with_krb5+y} -then : - withval=$with_krb5; -fi - - -# Check whether --with-mingw was given. -if test ${with_mingw+y} -then : - withval=$with_mingw; -fi - - -# Check whether --with-netapi was given. -if test ${with_netapi+y} -then : - withval=$with_netapi; -fi - - -# Check whether --with-opencl was given. -if test ${with_opencl+y} -then : - withval=$with_opencl; if test "x$withval" = "xno"; then ac_cv_header_CL_cl_h=no; ac_cv_header_OpenCL_opencl_h=no; fi -fi - - -# Check whether --with-opengl was given. -if test ${with_opengl+y} -then : - withval=$with_opengl; -fi - - -# Check whether --with-osmesa was given. -if test ${with_osmesa+y} -then : - withval=$with_osmesa; -fi - - -# Check whether --with-oss was given. -if test ${with_oss+y} -then : - withval=$with_oss; -fi - - -# Check whether --with-pcap was given. -if test ${with_pcap+y} -then : - withval=$with_pcap; if test "x$withval" = "xno"; then ac_cv_header_pcap_pcap_h=no; fi -fi - - -# Check whether --with-pthread was given. -if test ${with_pthread+y} -then : - withval=$with_pthread; if test "x$withval" = "xno"; then ac_cv_header_pthread_h=no; fi -fi - - -# Check whether --with-pulse was given. -if test ${with_pulse+y} -then : - withval=$with_pulse; -fi - - -# Check whether --with-sane was given. -if test ${with_sane+y} -then : - withval=$with_sane; -fi - - -# Check whether --with-sdl was given. -if test ${with_sdl+y} -then : - withval=$with_sdl; -fi - - -# Check whether --with-udev was given. -if test ${with_udev+y} -then : - withval=$with_udev; -fi - - -# Check whether --with-unwind was given. -if test ${with_unwind+y} -then : - withval=$with_unwind; -fi - - -# Check whether --with-usb was given. -if test ${with_usb+y} -then : - withval=$with_usb; -fi - - -# Check whether --with-v4l2 was given. -if test ${with_v4l2+y} -then : - withval=$with_v4l2; -fi - - -# Check whether --with-vulkan was given. -if test ${with_vulkan+y} -then : - withval=$with_vulkan; -fi - - -# Check whether --with-xcomposite was given. -if test ${with_xcomposite+y} -then : - withval=$with_xcomposite; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xcomposite_h=no; fi -fi - - -# Check whether --with-xcursor was given. -if test ${with_xcursor+y} -then : - withval=$with_xcursor; if test "x$withval" = "xno"; then ac_cv_header_X11_Xcursor_Xcursor_h=no; fi -fi - - -# Check whether --with-xfixes was given. -if test ${with_xfixes+y} -then : - withval=$with_xfixes; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xfixes_h=no; fi -fi - - -# Check whether --with-xinerama was given. -if test ${with_xinerama+y} -then : - withval=$with_xinerama; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xinerama_h=no; fi -fi - - -# Check whether --with-xinput was given. -if test ${with_xinput+y} -then : - withval=$with_xinput; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_XInput_h=no; fi -fi - - -# Check whether --with-xinput2 was given. -if test ${with_xinput2+y} -then : - withval=$with_xinput2; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_XInput2_h=no; fi -fi - - -# Check whether --with-xrandr was given. -if test ${with_xrandr+y} -then : - withval=$with_xrandr; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xrandr_h=no; fi -fi - - -# Check whether --with-xrender was given. -if test ${with_xrender+y} -then : - withval=$with_xrender; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xrender_h=no; fi -fi - - -# Check whether --with-xshape was given. -if test ${with_xshape+y} -then : - withval=$with_xshape; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_shape_h=no; fi -fi - - -# Check whether --with-xshm was given. -if test ${with_xshm+y} -then : - withval=$with_xshm; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_XShm_h=no; fi -fi - - -# Check whether --with-xxf86vm was given. -if test ${with_xxf86vm+y} -then : - withval=$with_xxf86vm; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_xf86vmode_h=no; ac_cv_header_X11_extensions_xf86vmproto_h=no; fi -fi - - - -# Check whether --with-system-dllpath was given. -if test ${with_system_dllpath+y} -then : - withval=$with_system_dllpath; system_dllpath=$withval - -fi - - -# Check whether --with-wine-tools was given. -if test ${with_wine_tools+y} -then : - withval=$with_wine_tools; -fi - - -# Check whether --with-wine64 was given. -if test ${with_wine64+y} -then : - withval=$with_wine64; -fi - - - - - - # Make sure we can run config.sub. -$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -printf %s "checking build system type... " >&6; } -if test ${ac_cv_build+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_build_alias=$build_alias -test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` -test "x$ac_build_alias" = x && - as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -printf "%s\n" "$ac_cv_build" >&6; } -case $ac_cv_build in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; -esac -build=$ac_cv_build -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_build -shift -build_cpu=$1 -build_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -build_os=$* -IFS=$ac_save_IFS -case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -printf %s "checking host system type... " >&6; } -if test ${ac_cv_host+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test "x$host_alias" = x; then - ac_cv_host=$ac_cv_build -else - ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || - as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 -fi - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -printf "%s\n" "$ac_cv_host" >&6; } -case $ac_cv_host in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; -esac -host=$ac_cv_host -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_host -shift -host_cpu=$1 -host_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -host_os=$* -IFS=$ac_save_IFS -case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac - - - -dlldir=\${libdir}/wine - -fontdir=\${datadir}/wine/fonts - -nlsdir=\${datadir}/wine/nls - - - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 -printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } -set x ${MAKE-make} -ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` -if eval test \${ac_cv_prog_make_${ac_make}_set+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat >conftest.make <<\_ACEOF -SHELL = /bin/sh -all: - @echo '@@@%%%=$(MAKE)=@@@%%%' -_ACEOF -# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. -case `${MAKE-make} -f conftest.make 2>/dev/null` in - *@@@%%%=?*=@@@%%%*) - eval ac_cv_prog_make_${ac_make}_set=yes;; - *) - eval ac_cv_prog_make_${ac_make}_set=no;; -esac -rm -f conftest.make -fi -if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } - SET_MAKE= -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - SET_MAKE="MAKE=${MAKE-make}" -fi - - - - - - - - - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf "%s\n" "$ac_ct_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" - fi -fi -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf "%s\n" "$ac_ct_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. -set dummy ${ac_tool_prefix}clang; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}clang" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "clang", so it can be a program name with args. -set dummy clang; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="clang" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf "%s\n" "$ac_ct_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -fi - - -test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5; } - -# Provide some information about the compiler. -printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion -version; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -printf %s "checking whether the C compiler works... " >&6; } -ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` - -# The possible output files: -ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" - -ac_rmfiles= -for ac_file in $ac_files -do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - * ) ac_rmfiles="$ac_rmfiles $ac_file";; - esac -done -rm -f $ac_rmfiles - -if { { ac_try="$ac_link_default" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_link_default") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. -# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' -# in a Makefile. We should not override ac_cv_exeext if it was cached, -# so that the user can short-circuit this test for compilers unknown to -# Autoconf. -for ac_file in $ac_files '' -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; - then :; else - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an `-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. - break;; - * ) - break;; - esac -done -test "$ac_cv_exeext" = no && ac_cv_exeext= - -else $as_nop - ac_file='' -fi -if test -z "$ac_file" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "C compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -printf %s "checking for C compiler default output file name... " >&6; } -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -printf "%s\n" "$ac_file" >&6; } -ac_exeext=$ac_cv_exeext - -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -printf %s "checking for suffix of executables... " >&6; } -if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - break;; - * ) break;; - esac -done -else $as_nop - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest conftest$ac_cv_exeext -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -printf "%s\n" "$ac_cv_exeext" >&6; } - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -FILE *f = fopen ("conftest.out", "w"); - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -ac_clean_files="$ac_clean_files conftest.out" -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -printf %s "checking whether we are cross compiling... " >&6; } -if test "$cross_compiling" != yes; then - { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if { ac_try='./conftest$ac_cv_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5; } - fi - fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -printf "%s\n" "$cross_compiling" >&6; } - -rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out -ac_clean_files=$ac_clean_files_save -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -printf %s "checking for suffix of object files... " >&6; } -if test ${ac_cv_objext+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>&5 - ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -then : - for ac_file in conftest.o conftest.obj conftest.*; do - test -f "$ac_file" || continue; - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -printf "%s\n" "$ac_cv_objext" >&6; } -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 -printf %s "checking whether the compiler supports GNU C... " >&6; } -if test ${ac_cv_c_compiler_gnu+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_compiler_gnu=yes -else $as_nop - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+y} -ac_save_CFLAGS=$CFLAGS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -printf %s "checking whether $CC accepts -g... " >&6; } -if test ${ac_cv_prog_cc_g+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_g=yes -else $as_nop - CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else $as_nop - ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -printf "%s\n" "$ac_cv_prog_cc_g" >&6; } -if test $ac_test_CFLAGS; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -ac_prog_cc_stdc=no -if test x$ac_prog_cc_stdc = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 -printf %s "checking for $CC option to enable C11 features... " >&6; } -if test ${ac_cv_prog_cc_c11+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c11=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c11_program -_ACEOF -for ac_arg in '' -std=gnu11 -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c11=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c11" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC -fi - -if test "x$ac_cv_prog_cc_c11" = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c11" = x -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 -printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } - CC="$CC $ac_cv_prog_cc_c11" -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 - ac_prog_cc_stdc=c11 -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 -printf %s "checking for $CC option to enable C99 features... " >&6; } -if test ${ac_cv_prog_cc_c99+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c99=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c99_program -_ACEOF -for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c99=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c99" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC -fi - -if test "x$ac_cv_prog_cc_c99" = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c99" = x -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 -printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } - CC="$CC $ac_cv_prog_cc_c99" -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 - ac_prog_cc_stdc=c99 -fi -fi -if test x$ac_prog_cc_stdc = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 -printf %s "checking for $CC option to enable C89 features... " >&6; } -if test ${ac_cv_prog_cc_c89+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c89_program -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_prog_cc_c89=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC -fi - -if test "x$ac_cv_prog_cc_c89" = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c89" = x -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } - CC="$CC $ac_cv_prog_cc_c89" -fi - ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 - ac_prog_cc_stdc=c89 -fi -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - - - - - -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -if test -z "$CXX"; then - if test -n "$CCC"; then - CXX=$CCC - else - if test -n "$ac_tool_prefix"; then - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CXX+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$CXX"; then - ac_cv_prog_CXX="$CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CXX=$ac_cv_prog_CXX -if test -n "$CXX"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -printf "%s\n" "$CXX" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$CXX" && break - done -fi -if test -z "$CXX"; then - ac_ct_CXX=$CXX - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CXX+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CXX"; then - ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CXX="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CXX=$ac_cv_prog_ac_ct_CXX -if test -n "$ac_ct_CXX"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 -printf "%s\n" "$ac_ct_CXX" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$ac_ct_CXX" && break -done - - if test "x$ac_ct_CXX" = x; then - CXX="g++" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CXX=$ac_ct_CXX - fi -fi - - fi -fi -# Provide some information about the compiler. -printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C++" >&5 -printf %s "checking whether the compiler supports GNU C++... " >&6; } -if test ${ac_cv_cxx_compiler_gnu+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO" -then : - ac_compiler_gnu=yes -else $as_nop - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -ac_cv_cxx_compiler_gnu=$ac_compiler_gnu - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 -printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; } -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - -if test $ac_compiler_gnu = yes; then - GXX=yes -else - GXX= -fi -ac_test_CXXFLAGS=${CXXFLAGS+y} -ac_save_CXXFLAGS=$CXXFLAGS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 -printf %s "checking whether $CXX accepts -g... " >&6; } -if test ${ac_cv_prog_cxx_g+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_save_cxx_werror_flag=$ac_cxx_werror_flag - ac_cxx_werror_flag=yes - ac_cv_prog_cxx_g=no - CXXFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO" -then : - ac_cv_prog_cxx_g=yes -else $as_nop - CXXFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO" -then : - -else $as_nop - ac_cxx_werror_flag=$ac_save_cxx_werror_flag - CXXFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO" -then : - ac_cv_prog_cxx_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_cxx_werror_flag=$ac_save_cxx_werror_flag -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 -printf "%s\n" "$ac_cv_prog_cxx_g" >&6; } -if test $ac_test_CXXFLAGS; then - CXXFLAGS=$ac_save_CXXFLAGS -elif test $ac_cv_prog_cxx_g = yes; then - if test "$GXX" = yes; then - CXXFLAGS="-g -O2" - else - CXXFLAGS="-g" - fi -else - if test "$GXX" = yes; then - CXXFLAGS="-O2" - else - CXXFLAGS= - fi -fi -ac_prog_cxx_stdcxx=no -if test x$ac_prog_cxx_stdcxx = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 -printf %s "checking for $CXX option to enable C++11 features... " >&6; } -if test ${ac_cv_prog_cxx_11+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cxx_11=no -ac_save_CXX=$CXX -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_cxx_conftest_cxx11_program -_ACEOF -for ac_arg in '' -std=gnu++11 -std=gnu++0x -std=c++11 -std=c++0x -qlanglvl=extended0x -AA -do - CXX="$ac_save_CXX $ac_arg" - if ac_fn_cxx_try_compile "$LINENO" -then : - ac_cv_prog_cxx_cxx11=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cxx_cxx11" != "xno" && break -done -rm -f conftest.$ac_ext -CXX=$ac_save_CXX -fi - -if test "x$ac_cv_prog_cxx_cxx11" = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cxx_cxx11" = x -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 -printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; } - CXX="$CXX $ac_cv_prog_cxx_cxx11" -fi - ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 - ac_prog_cxx_stdcxx=cxx11 -fi -fi -if test x$ac_prog_cxx_stdcxx = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 -printf %s "checking for $CXX option to enable C++98 features... " >&6; } -if test ${ac_cv_prog_cxx_98+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cxx_98=no -ac_save_CXX=$CXX -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_cxx_conftest_cxx98_program -_ACEOF -for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA -do - CXX="$ac_save_CXX $ac_arg" - if ac_fn_cxx_try_compile "$LINENO" -then : - ac_cv_prog_cxx_cxx98=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cxx_cxx98" != "xno" && break -done -rm -f conftest.$ac_ext -CXX=$ac_save_CXX -fi - -if test "x$ac_cv_prog_cxx_cxx98" = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cxx_cxx98" = x -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 -printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; } - CXX="$CXX $ac_cv_prog_cxx_cxx98" -fi - ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 - ac_prog_cxx_stdcxx=cxx98 -fi -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cpp", so it can be a program name with args. -set dummy ${ac_tool_prefix}cpp; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CPPBIN+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$CPPBIN"; then - ac_cv_prog_CPPBIN="$CPPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CPPBIN="${ac_tool_prefix}cpp" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CPPBIN=$ac_cv_prog_CPPBIN -if test -n "$CPPBIN"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPPBIN" >&5 -printf "%s\n" "$CPPBIN" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CPPBIN"; then - ac_ct_CPPBIN=$CPPBIN - # Extract the first word of "cpp", so it can be a program name with args. -set dummy cpp; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_CPPBIN+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CPPBIN"; then - ac_cv_prog_ac_ct_CPPBIN="$ac_ct_CPPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CPPBIN="cpp" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CPPBIN=$ac_cv_prog_ac_ct_CPPBIN -if test -n "$ac_ct_CPPBIN"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CPPBIN" >&5 -printf "%s\n" "$ac_ct_CPPBIN" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_CPPBIN" = x; then - CPPBIN="cpp" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CPPBIN=$ac_ct_CPPBIN - fi -else - CPPBIN="$ac_cv_prog_CPPBIN" -fi - - -printf "%s\n" "#define EXEEXT \"$ac_exeext\"" >>confdefs.h - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args. -set dummy ${ac_tool_prefix}ld; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_LD+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$LD"; then - ac_cv_prog_LD="$LD" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_LD="${ac_tool_prefix}ld" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -LD=$ac_cv_prog_LD -if test -n "$LD"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 -printf "%s\n" "$LD" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_LD"; then - ac_ct_LD=$LD - # Extract the first word of "ld", so it can be a program name with args. -set dummy ld; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_LD+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_LD"; then - ac_cv_prog_ac_ct_LD="$ac_ct_LD" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_LD="ld" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_LD=$ac_cv_prog_ac_ct_LD -if test -n "$ac_ct_LD"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LD" >&5 -printf "%s\n" "$ac_ct_LD" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_LD" = x; then - LD="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - LD=$ac_ct_LD - fi -else - LD="$ac_cv_prog_LD" -fi - - -case $host in - *-darwin*) - with_fontconfig=${with_fontconfig:-no} - ;; - *-mingw32*|*-cygwin*) - enable_win16=${enable_win16:-no} - with_mingw=${with_mingw:-no} - ;; -esac - - -case $host in - x86_64*|amd64*) - if test "x$enable_win64" != "xyes" -a "$cross_compiling" != "yes" -a x"$enable_archs" = x - then - CC="$CC -m32" - CXX="$CXX -m32" - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC works" >&5 -printf %s "checking whether $CC works... " >&6; } -if test ${wine_cv_cc_m32+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - wine_cv_cc_m32=yes -else $as_nop - wine_cv_cc_m32=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_cc_m32" >&5 -printf "%s\n" "$wine_cv_cc_m32" >&6; } - test $wine_cv_cc_m32 != no || as_fn_error $? "Cannot build a 32-bit program, you need to install 32-bit development libraries." "$LINENO" 5 - host_cpu="i386" - notice_platform="32-bit " - TARGETFLAGS="$TARGETFLAGS -m32" - PKG_CONFIG_LIBDIR=${PKG_CONFIG_LIBDIR:-/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib32/pkgconfig:/usr/lib/pkgconfig} - export PKG_CONFIG_LIBDIR - with_unwind=${with_unwind:-no} - else - if test "x${GCC}" = "xyes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports __builtin_ms_va_list" >&5 -printf %s "checking whether $CC supports __builtin_ms_va_list... " >&6; } -if test ${wine_cv_builtin_ms_va_list+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -void func(__builtin_ms_va_list *args); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - wine_cv_builtin_ms_va_list=yes -else $as_nop - wine_cv_builtin_ms_va_list=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_builtin_ms_va_list" >&5 -printf "%s\n" "$wine_cv_builtin_ms_va_list" >&6; } - test $wine_cv_builtin_ms_va_list != no || as_fn_error $? "You need gcc >= 4.4 or clang >= 3.8 to build Wine as 64-bit." "$LINENO" 5 - fi - CC="$CC -m64" - CXX="$CXX -m64" - host_cpu="x86_64" - notice_platform="64-bit " - TARGETFLAGS="$TARGETFLAGS -m64" - fi - ;; - arm*) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports Thumb-2" >&5 -printf %s "checking whether $CC supports Thumb-2... " >&6; } -if test ${wine_cv_thumb2+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -asm(".syntax unified\n\t.thumb\n\tldm r0,{r0-r8}"); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - wine_cv_thumb2=yes -else $as_nop - wine_cv_thumb2=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_thumb2" >&5 -printf "%s\n" "$wine_cv_thumb2" >&6; } - if test x"$wine_cv_thumb2" = xyes - then - CFLAGS="$CFLAGS -mthumb" - TARGETFLAGS="$TARGETFLAGS -mthumb" - else - CFLAGS="$CFLAGS -marm" - TARGETFLAGS="$TARGETFLAGS -marm" - fi - case $with_float_abi in - soft|softfp|hard) - float_abi=$with_float_abi ;; - *) - case $host_os in - *eabihf) - float_abi=hard ;; - *) - float_abi=softfp - saved_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -mfloat-abi=$float_abi" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -mfloat-abi=$float_abi" >&5 -printf %s "checking whether $CC supports -mfloat-abi=$float_abi... " >&6; } -if test ${wine_cv_float_abi+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -asm("vmrs r2,fpscr"); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - wine_cv_float_abi=yes -else $as_nop - wine_cv_float_abi=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_float_abi" >&5 -printf "%s\n" "$wine_cv_float_abi" >&6; } - if test $wine_cv_float_abi = no - then - float_abi=soft - as_fn_append wine_warnings "|Floating point is not supported for this target. The resulting build won't be compatible with Windows ARM binaries." - fi - CFLAGS=$saved_CFLAGS - esac - ;; - esac - CFLAGS="$CFLAGS -mfloat-abi=$float_abi" - TARGETFLAGS="$TARGETFLAGS -mfloat-abi=$float_abi" - ;; - i[3456789]86*) - with_unwind=${with_unwind:-no} - ;; -esac - -enable_win16=${enable_win16:-i386} -enable_win64=${enable_win64:-no} -enable_wow64=${enable_wow64:-aarch64,x86_64} -enable_wow64win=${enable_wow64win:-aarch64,x86_64} -enable_wow64cpu=${enable_wow64cpu:-x86_64} - -enable_winetest=${enable_winetest:-$enable_tests} - -if test "x$enable_win64" = "xyes" -then - test -z "$with_wine64" || as_fn_error $? "--enable-win64 and --with-wine64 are mutually exclusive. ---enable-win64 should be used in the 64-bit build tree, --with-wine64 in the 32-bit Wow64 build tree." "$LINENO" 5 -fi - -case $build_os in - cygwin*|mingw32*) toolsext=".exe" - ;; - *) toolsext="" - ;; -esac - -HOST_ARCH=unknown -case "$host_cpu" in - aarch64*) HOST_ARCH=aarch64 ;; - arm*) HOST_ARCH=arm ;; - i[3456789]86*) HOST_ARCH=i386 ;; - x86_64) HOST_ARCH=x86_64 ;; -esac - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the directory containing the Wine tools" >&5 -printf %s "checking for the directory containing the Wine tools... " >&6; } -if test ${wine_cv_toolsdir+y} -then : - printf %s "(cached) " >&6 -else $as_nop - wine_cv_toolsdir="$with_wine_tools" - if test -z "$with_wine_tools"; then - if test "$cross_compiling" = "yes"; then - as_fn_error $? "you must use the --with-wine-tools option when cross-compiling." "$LINENO" 5 - elif test -n "$with_wine64"; then - wine_cv_toolsdir="$with_wine64" - fi - fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_toolsdir" >&5 -printf "%s\n" "$wine_cv_toolsdir" >&6; } -if test -z "$wine_cv_toolsdir"; then - wine_makedep=tools/makedep$toolsext -elif test -d "$wine_cv_toolsdir/tools/winebuild"; then - wine_makedep=$wine_cv_toolsdir/tools/makedep$toolsext - enable_tools=${enable_tools:-no} - test -f "$wine_makedep" || as_fn_error $? "the Wine tools have not yet been built in $wine_cv_toolsdir" "$LINENO" 5 -else - as_fn_error $? "could not find Wine tools in $wine_cv_toolsdir" "$LINENO" 5 -fi -toolsdir=$wine_cv_toolsdir - -MAKEDEP=$wine_makedep - -RUNTESTFLAGS="-q -P wine" - -SED_CMD="LC_ALL=C sed -e 's,@bindir@,\${bindir},g' -e 's,@dlldir@,\${dlldir},g' -e 's,@PACKAGE_STRING@,$PACKAGE_STRING,g' -e 's,@PACKAGE_VERSION@,$PACKAGE_VERSION,g'" - - -if test -n "$host_alias" -a "$host_alias" != "$build_alias" -then - TARGETFLAGS="-b $host_alias $TARGETFLAGS" -fi - -for ac_prog in flex -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_FLEX+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$FLEX"; then - ac_cv_prog_FLEX="$FLEX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_FLEX="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -FLEX=$ac_cv_prog_FLEX -if test -n "$FLEX"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FLEX" >&5 -printf "%s\n" "$FLEX" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$FLEX" && break -done -test -n "$FLEX" || FLEX="none" - -if test "$FLEX" = "none" -then - as_fn_error $? "no suitable flex found. Please install the 'flex' package." "$LINENO" 5 -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether flex is recent enough" >&5 -printf %s "checking whether flex is recent enough... " >&6; } -if test ${wine_cv_recent_flex+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat >conftest.l </dev/null 2>&5 - then - wine_cv_recent_flex=yes - else - wine_cv_recent_flex=no - fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_recent_flex" >&5 -printf "%s\n" "$wine_cv_recent_flex" >&6; } -test $wine_cv_recent_flex != no || as_fn_error $? "Your flex version is too old. Please install flex version 2.5.33 or newer." "$LINENO" 5 - -for ac_prog in bison -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_BISON+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$BISON"; then - ac_cv_prog_BISON="$BISON" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_BISON="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -BISON=$ac_cv_prog_BISON -if test -n "$BISON"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BISON" >&5 -printf "%s\n" "$BISON" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$BISON" && break -done -test -n "$BISON" || BISON="none" - -if test "$BISON" = "none" -then - as_fn_error $? "no suitable bison found. Please install the 'bison' package." "$LINENO" 5 -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether bison is recent enough" >&5 -printf %s "checking whether bison is recent enough... " >&6; } -if test ${wine_cv_recent_bison+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat >conftest.y </dev/null 2>&5 - then - wine_cv_recent_bison=yes - else - wine_cv_recent_bison=no - fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_recent_bison" >&5 -printf "%s\n" "$wine_cv_recent_bison" >&6; } -test $wine_cv_recent_bison != no || as_fn_error $? "Your bison version is too old. Please install bison version 3.0 or newer." "$LINENO" 5 - -if test -n "$ac_tool_prefix"; then - for ac_prog in ar gar - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_AR+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_AR="$ac_tool_prefix$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -printf "%s\n" "$AR" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$AR" && break - done -fi -if test -z "$AR"; then - ac_ct_AR=$AR - for ac_prog in ar gar -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_AR+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_AR="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_AR=$ac_cv_prog_ac_ct_AR -if test -n "$ac_ct_AR"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -printf "%s\n" "$ac_ct_AR" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$ac_ct_AR" && break -done - - if test "x$ac_ct_AR" = x; then - AR="ar" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - AR=$ac_ct_AR - fi -fi - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_STRIP+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -printf "%s\n" "$STRIP" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_STRIP+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -printf "%s\n" "$ac_ct_STRIP" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP="strip" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. -set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_RANLIB+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$RANLIB"; then - ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -RANLIB=$ac_cv_prog_RANLIB -if test -n "$RANLIB"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -printf "%s\n" "$RANLIB" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_RANLIB"; then - ac_ct_RANLIB=$RANLIB - # Extract the first word of "ranlib", so it can be a program name with args. -set dummy ranlib; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_RANLIB+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_RANLIB"; then - ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_RANLIB="ranlib" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB -if test -n "$ac_ct_RANLIB"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -printf "%s\n" "$ac_ct_RANLIB" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_RANLIB" = x; then - RANLIB=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - RANLIB=$ac_ct_RANLIB - fi -else - RANLIB="$ac_cv_prog_RANLIB" -fi - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 -printf %s "checking whether ln -s works... " >&6; } -LN_S=$as_ln_s -if test "$LN_S" = "ln -s"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 -printf "%s\n" "no, using $LN_S" >&6; } -fi - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -printf %s "checking for grep that handles long lines and -e... " >&6; } -if test ${ac_cv_path_GREP+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in grep ggrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf "%s\n" 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -printf "%s\n" "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -printf %s "checking for egrep... " >&6; } -if test ${ac_cv_path_EGREP+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_prog in egrep - do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - printf %s 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - printf "%s\n" 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -printf "%s\n" "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - -# Extract the first word of "ldconfig", so it can be a program name with args. -set dummy ldconfig; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_LDCONFIG+y} -then : - printf %s "(cached) " >&6 -else $as_nop - case $LDCONFIG in - [\\/]* | ?:[\\/]*) - ac_cv_path_LDCONFIG="$LDCONFIG" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in /sbin /usr/sbin $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_LDCONFIG="$as_dir$ac_word$ac_exec_ext" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_path_LDCONFIG" && ac_cv_path_LDCONFIG="true" - ;; -esac -fi -LDCONFIG=$ac_cv_path_LDCONFIG -if test -n "$LDCONFIG"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LDCONFIG" >&5 -printf "%s\n" "$LDCONFIG" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -for ac_prog in msgfmt -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_MSGFMT+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$MSGFMT"; then - ac_cv_prog_MSGFMT="$MSGFMT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_MSGFMT="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -MSGFMT=$ac_cv_prog_MSGFMT -if test -n "$MSGFMT"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5 -printf "%s\n" "$MSGFMT" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$MSGFMT" && break -done -test -n "$MSGFMT" || MSGFMT="false" - -if test ${ac_tool_prefix+y} -then : - # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. -set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_PKG_CONFIG+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$PKG_CONFIG"; then - ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_PKG_CONFIG="${ac_tool_prefix}pkg-config" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -PKG_CONFIG=$ac_cv_prog_PKG_CONFIG -if test -n "$PKG_CONFIG"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 -printf "%s\n" "$PKG_CONFIG" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if ${ac_cv_prog_PKG_CONFIG:+false} : -then : - if test "x$cross_compiling" = xyes -then : - -else $as_nop - { ac_cv_prog_PKG_CONFIG=; unset ac_cv_prog_PKG_CONFIG;} - # Extract the first word of "pkg-config", so it can be a program name with args. -set dummy pkg-config; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_PKG_CONFIG+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$PKG_CONFIG"; then - ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_PKG_CONFIG="pkg-config" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -PKG_CONFIG=$ac_cv_prog_PKG_CONFIG -if test -n "$PKG_CONFIG"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 -printf "%s\n" "$PKG_CONFIG" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -else $as_nop - PKG_CONFIG=$ac_cv_prog_PKG_CONFIG -fi - -if test "x$enable_maintainer_mode" != "xyes" -then - FONTFORGE="" - RSVG="" - CONVERT="" - ICOTOOL="" -else - test "$srcdir" = . || as_fn_error $? "Maintainer mode cannot work out of tree." "$LINENO" 5 - for ac_prog in fontforge -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_FONTFORGE+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$FONTFORGE"; then - ac_cv_prog_FONTFORGE="$FONTFORGE" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_FONTFORGE="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -FONTFORGE=$ac_cv_prog_FONTFORGE -if test -n "$FONTFORGE"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FONTFORGE" >&5 -printf "%s\n" "$FONTFORGE" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$FONTFORGE" && break -done -test -n "$FONTFORGE" || FONTFORGE="false" - - for ac_prog in rsvg-convert rsvg -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_RSVG+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$RSVG"; then - ac_cv_prog_RSVG="$RSVG" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_RSVG="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -RSVG=$ac_cv_prog_RSVG -if test -n "$RSVG"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RSVG" >&5 -printf "%s\n" "$RSVG" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$RSVG" && break -done -test -n "$RSVG" || RSVG="false" - - for ac_prog in convert -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_CONVERT+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$CONVERT"; then - ac_cv_prog_CONVERT="$CONVERT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_CONVERT="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CONVERT=$ac_cv_prog_CONVERT -if test -n "$CONVERT"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CONVERT" >&5 -printf "%s\n" "$CONVERT" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$CONVERT" && break -done -test -n "$CONVERT" || CONVERT="false" - - for ac_prog in icotool -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ICOTOOL+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ICOTOOL"; then - ac_cv_prog_ICOTOOL="$ICOTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ICOTOOL="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ICOTOOL=$ac_cv_prog_ICOTOOL -if test -n "$ICOTOOL"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ICOTOOL" >&5 -printf "%s\n" "$ICOTOOL" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$ICOTOOL" && break -done -test -n "$ICOTOOL" || ICOTOOL="false" - - test "$FONTFORGE" != "false" || as_fn_error $? "You need fontforge to rebuild fonts in maintainer mode." "$LINENO" 5 - test "$RSVG" != "false" || as_fn_error $? "You need rsvg to rebuild icons in maintainer mode." "$LINENO" 5 - - if test "$CONVERT" = false - then - as_fn_error $? "You need imagemagick to rebuild icons in maintainer mode." "$LINENO" 5 - else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for recent enough imagemagick" >&5 -printf %s "checking for recent enough imagemagick... " >&6; } - convert_version=`convert --version | head -n1` - if test "x$convert_version" != "x" - then - convert_version_major=`expr "$convert_version" : '.* \([0-9]*\)\.[0-9]*'` - convert_version_minor=`expr "$convert_version" : '.* [0-9]*\.\([0-9]*\)'` - if test "$convert_version_major" -eq 6 -a "$convert_version_minor" -lt 6 - then - CONVERT=false - fi - fi - if test "$CONVERT" = false - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no ($convert_version_major.$convert_version_minor)" >&5 -printf "%s\n" "no ($convert_version_major.$convert_version_minor)" >&6; } - as_fn_error $? "You need imagemagick version 6.6 or newer to rebuild icons in maintainer mode." "$LINENO" 5 - else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes ($convert_version_major.$convert_version_minor)" >&5 -printf "%s\n" "yes ($convert_version_major.$convert_version_minor)" >&6; } - fi - fi - - if test "$ICOTOOL" = false - then - as_fn_error $? "You need icotool to rebuild icons in maintainer mode." "$LINENO" 5 - else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for recent enough icotool" >&5 -printf %s "checking for recent enough icotool... " >&6; } - icotool_version=`icotool --version | head -n1` - if test "x$icotool_version" != "x" - then - icotool_version_major=`expr "$icotool_version" : '.* \([0-9]*\)\.[0-9]*'` - icotool_version_minor=`expr "$icotool_version" : '.* [0-9]*\.\([0-9]*\)'` - if test "$icotool_version_major" -eq 0 -a "$icotool_version_minor" -lt 29 - then - ICOTOOL=false - as_fn_append wine_warnings "|icotool version 0.29.0 or newer is needed to rebuild icons." - fi - fi - if test "$ICOTOOL" = false - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no ($icotool_version_major.$icotool_version_minor)" >&5 -printf "%s\n" "no ($icotool_version_major.$icotool_version_minor)" >&6; } - as_fn_error $? "You need icotool version 0.29.0 or newer to rebuild icons in maintainer mode." "$LINENO" 5 - else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes ($icotool_version_major.$icotool_version_minor)" >&5 -printf "%s\n" "yes ($icotool_version_major.$icotool_version_minor)" >&6; } - fi - fi - - with_gettext=yes - with_gettextpo=yes - - enable_werror=yes -fi - -test "x$with_gettext" != xno || MSGFMT=false -if test "$MSGFMT" != "false" -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether msgfmt supports contexts" >&5 -printf %s "checking whether msgfmt supports contexts... " >&6; } -if test ${wine_cv_msgfmt_contexts+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat >conftest.po <&5 - then - wine_cv_msgfmt_contexts=yes - else - wine_cv_msgfmt_contexts=no - fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_msgfmt_contexts" >&5 -printf "%s\n" "$wine_cv_msgfmt_contexts" >&6; } - test $wine_cv_msgfmt_contexts != no || MSGFMT=false -fi -if test "$MSGFMT" = false -then : - case "x$with_gettext" in - x) as_fn_append wine_warnings "|gettext tools not found (or too old), translations won't be built." ;; - xno) ;; - *) as_fn_error $? "gettext tools not found (or too old), translations won't be built. -This is an error since --with-gettext was requested." "$LINENO" 5 ;; -esac -enable_po=${enable_po:-no} -fi - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for i386_set_ldt in -li386" >&5 -printf %s "checking for i386_set_ldt in -li386... " >&6; } -if test ${ac_cv_lib_i386_i386_set_ldt+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-li386 $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char i386_set_ldt (); -int -main (void) -{ -return i386_set_ldt (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_i386_i386_set_ldt=yes -else $as_nop - ac_cv_lib_i386_i386_set_ldt=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_i386_i386_set_ldt" >&5 -printf "%s\n" "$ac_cv_lib_i386_i386_set_ldt" >&6; } -if test "x$ac_cv_lib_i386_i386_set_ldt" = xyes -then : - I386_LIBS="-li386" - -fi - - -OPENGL_LIBS="" - - - -# Check whether --enable-largefile was given. -if test ${enable_largefile+y} -then : - enableval=$enable_largefile; -fi - -if test "$enable_largefile" != no; then - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 -printf %s "checking for special C compiler options needed for large files... " >&6; } -if test ${ac_cv_sys_largefile_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_cv_sys_largefile_CC=no - if test "$GCC" != yes; then - ac_save_CC=$CC - while :; do - # IRIX 6.2 and later do not support large files by default, - # so use the C compiler's -n32 option if that helps. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, - since some C++ compilers masquerading as C compilers - incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) - ? 1 : -1]; -int -main (void) -{ - - ; - return 0; -} -_ACEOF - if ac_fn_c_try_compile "$LINENO" -then : - break -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - CC="$CC -n32" - if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_sys_largefile_CC=' -n32'; break -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - break - done - CC=$ac_save_CC - rm -f conftest.$ac_ext - fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 -printf "%s\n" "$ac_cv_sys_largefile_CC" >&6; } - if test "$ac_cv_sys_largefile_CC" != no; then - CC=$CC$ac_cv_sys_largefile_CC - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 -printf %s "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } -if test ${ac_cv_sys_file_offset_bits+y} -then : - printf %s "(cached) " >&6 -else $as_nop - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, - since some C++ compilers masquerading as C compilers - incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) - ? 1 : -1]; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_sys_file_offset_bits=no; break -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#define _FILE_OFFSET_BITS 64 -#include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, - since some C++ compilers masquerading as C compilers - incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) - ? 1 : -1]; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_sys_file_offset_bits=64; break -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_cv_sys_file_offset_bits=unknown - break -done -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 -printf "%s\n" "$ac_cv_sys_file_offset_bits" >&6; } -case $ac_cv_sys_file_offset_bits in #( - no | unknown) ;; - *) -printf "%s\n" "#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits" >>confdefs.h -;; -esac -rm -rf conftest* - if test $ac_cv_sys_file_offset_bits = unknown; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 -printf %s "checking for _LARGE_FILES value needed for large files... " >&6; } -if test ${ac_cv_sys_large_files+y} -then : - printf %s "(cached) " >&6 -else $as_nop - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, - since some C++ compilers masquerading as C compilers - incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) - ? 1 : -1]; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_sys_large_files=no; break -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#define _LARGE_FILES 1 -#include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, - since some C++ compilers masquerading as C compilers - incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) - ? 1 : -1]; -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_sys_large_files=1; break -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_cv_sys_large_files=unknown - break -done -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 -printf "%s\n" "$ac_cv_sys_large_files" >&6; } -case $ac_cv_sys_large_files in #( - no | unknown) ;; - *) -printf "%s\n" "#define _LARGE_FILES $ac_cv_sys_large_files" >>confdefs.h -;; -esac -rm -rf conftest* - fi -fi - - -ac_header= ac_cache= -for ac_item in $ac_header_c_list -do - if test $ac_cache; then - ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" - if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then - printf "%s\n" "#define $ac_item 1" >> confdefs.h - fi - ac_header= ac_cache= - elif test $ac_header; then - ac_cache=$ac_item - else - ac_header=$ac_item - fi -done - - - - - - - - -if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes -then : - -printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "CL/cl.h" "ac_cv_header_CL_cl_h" "$ac_includes_default" -if test "x$ac_cv_header_CL_cl_h" = xyes -then : - printf "%s\n" "#define HAVE_CL_CL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "EGL/egl.h" "ac_cv_header_EGL_egl_h" "$ac_includes_default" -if test "x$ac_cv_header_EGL_egl_h" = xyes -then : - printf "%s\n" "#define HAVE_EGL_EGL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "OpenCL/opencl.h" "ac_cv_header_OpenCL_opencl_h" "$ac_includes_default" -if test "x$ac_cv_header_OpenCL_opencl_h" = xyes -then : - printf "%s\n" "#define HAVE_OPENCL_OPENCL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "arpa/inet.h" "ac_cv_header_arpa_inet_h" "$ac_includes_default" -if test "x$ac_cv_header_arpa_inet_h" = xyes -then : - printf "%s\n" "#define HAVE_ARPA_INET_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "arpa/nameser.h" "ac_cv_header_arpa_nameser_h" "$ac_includes_default" -if test "x$ac_cv_header_arpa_nameser_h" = xyes -then : - printf "%s\n" "#define HAVE_ARPA_NAMESER_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "asm/types.h" "ac_cv_header_asm_types_h" "$ac_includes_default" -if test "x$ac_cv_header_asm_types_h" = xyes -then : - printf "%s\n" "#define HAVE_ASM_TYPES_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "asm/user.h" "ac_cv_header_asm_user_h" "$ac_includes_default" -if test "x$ac_cv_header_asm_user_h" = xyes -then : - printf "%s\n" "#define HAVE_ASM_USER_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "elf.h" "ac_cv_header_elf_h" "$ac_includes_default" -if test "x$ac_cv_header_elf_h" = xyes -then : - printf "%s\n" "#define HAVE_ELF_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "float.h" "ac_cv_header_float_h" "$ac_includes_default" -if test "x$ac_cv_header_float_h" = xyes -then : - printf "%s\n" "#define HAVE_FLOAT_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "gettext-po.h" "ac_cv_header_gettext_po_h" "$ac_includes_default" -if test "x$ac_cv_header_gettext_po_h" = xyes -then : - printf "%s\n" "#define HAVE_GETTEXT_PO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "libproc.h" "ac_cv_header_libproc_h" "$ac_includes_default" -if test "x$ac_cv_header_libproc_h" = xyes -then : - printf "%s\n" "#define HAVE_LIBPROC_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "link.h" "ac_cv_header_link_h" "$ac_includes_default" -if test "x$ac_cv_header_link_h" = xyes -then : - printf "%s\n" "#define HAVE_LINK_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/cdrom.h" "ac_cv_header_linux_cdrom_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_cdrom_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_CDROM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/filter.h" "ac_cv_header_linux_filter_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_filter_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_FILTER_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/hdreg.h" "ac_cv_header_linux_hdreg_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_hdreg_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_HDREG_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/hidraw.h" "ac_cv_header_linux_hidraw_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_hidraw_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_HIDRAW_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/input.h" "ac_cv_header_linux_input_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_input_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_INPUT_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/ioctl.h" "ac_cv_header_linux_ioctl_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_ioctl_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_IOCTL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/major.h" "ac_cv_header_linux_major_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_major_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_MAJOR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/param.h" "ac_cv_header_linux_param_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_param_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_PARAM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/serial.h" "ac_cv_header_linux_serial_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_serial_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_SERIAL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/types.h" "ac_cv_header_linux_types_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_types_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_TYPES_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/ucdrom.h" "ac_cv_header_linux_ucdrom_h" "$ac_includes_default" -if test "x$ac_cv_header_linux_ucdrom_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_UCDROM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "lwp.h" "ac_cv_header_lwp_h" "$ac_includes_default" -if test "x$ac_cv_header_lwp_h" = xyes -then : - printf "%s\n" "#define HAVE_LWP_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "mach-o/loader.h" "ac_cv_header_mach_o_loader_h" "$ac_includes_default" -if test "x$ac_cv_header_mach_o_loader_h" = xyes -then : - printf "%s\n" "#define HAVE_MACH_O_LOADER_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "mach/mach.h" "ac_cv_header_mach_mach_h" "$ac_includes_default" -if test "x$ac_cv_header_mach_mach_h" = xyes -then : - printf "%s\n" "#define HAVE_MACH_MACH_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "machine/cpu.h" "ac_cv_header_machine_cpu_h" "$ac_includes_default" -if test "x$ac_cv_header_machine_cpu_h" = xyes -then : - printf "%s\n" "#define HAVE_MACHINE_CPU_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "machine/sysarch.h" "ac_cv_header_machine_sysarch_h" "$ac_includes_default" -if test "x$ac_cv_header_machine_sysarch_h" = xyes -then : - printf "%s\n" "#define HAVE_MACHINE_SYSARCH_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "mntent.h" "ac_cv_header_mntent_h" "$ac_includes_default" -if test "x$ac_cv_header_mntent_h" = xyes -then : - printf "%s\n" "#define HAVE_MNTENT_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netdb.h" "ac_cv_header_netdb_h" "$ac_includes_default" -if test "x$ac_cv_header_netdb_h" = xyes -then : - printf "%s\n" "#define HAVE_NETDB_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/in.h" "ac_cv_header_netinet_in_h" "$ac_includes_default" -if test "x$ac_cv_header_netinet_in_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_IN_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/in_systm.h" "ac_cv_header_netinet_in_systm_h" "$ac_includes_default" -if test "x$ac_cv_header_netinet_in_systm_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_IN_SYSTM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/tcp.h" "ac_cv_header_netinet_tcp_h" "$ac_includes_default" -if test "x$ac_cv_header_netinet_tcp_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_TCP_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/tcp_fsm.h" "ac_cv_header_netinet_tcp_fsm_h" "$ac_includes_default" -if test "x$ac_cv_header_netinet_tcp_fsm_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_TCP_FSM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "pcap/pcap.h" "ac_cv_header_pcap_pcap_h" "$ac_includes_default" -if test "x$ac_cv_header_pcap_pcap_h" = xyes -then : - printf "%s\n" "#define HAVE_PCAP_PCAP_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "port.h" "ac_cv_header_port_h" "$ac_includes_default" -if test "x$ac_cv_header_port_h" = xyes -then : - printf "%s\n" "#define HAVE_PORT_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" -if test "x$ac_cv_header_pthread_h" = xyes -then : - printf "%s\n" "#define HAVE_PTHREAD_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "pwd.h" "ac_cv_header_pwd_h" "$ac_includes_default" -if test "x$ac_cv_header_pwd_h" = xyes -then : - printf "%s\n" "#define HAVE_PWD_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sched.h" "ac_cv_header_sched_h" "$ac_includes_default" -if test "x$ac_cv_header_sched_h" = xyes -then : - printf "%s\n" "#define HAVE_SCHED_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "scsi/scsi.h" "ac_cv_header_scsi_scsi_h" "$ac_includes_default" -if test "x$ac_cv_header_scsi_scsi_h" = xyes -then : - printf "%s\n" "#define HAVE_SCSI_SCSI_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "scsi/scsi_ioctl.h" "ac_cv_header_scsi_scsi_ioctl_h" "$ac_includes_default" -if test "x$ac_cv_header_scsi_scsi_ioctl_h" = xyes -then : - printf "%s\n" "#define HAVE_SCSI_SCSI_IOCTL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "scsi/sg.h" "ac_cv_header_scsi_sg_h" "$ac_includes_default" -if test "x$ac_cv_header_scsi_sg_h" = xyes -then : - printf "%s\n" "#define HAVE_SCSI_SG_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default" -if test "x$ac_cv_header_stdint_h" = xyes -then : - printf "%s\n" "#define HAVE_STDINT_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/attr.h" "ac_cv_header_sys_attr_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_attr_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_ATTR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/auxv.h" "ac_cv_header_sys_auxv_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_auxv_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_AUXV_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/cdio.h" "ac_cv_header_sys_cdio_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_cdio_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_CDIO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/epoll.h" "ac_cv_header_sys_epoll_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_epoll_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_EPOLL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/event.h" "ac_cv_header_sys_event_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_event_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_EVENT_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/extattr.h" "ac_cv_header_sys_extattr_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_extattr_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_EXTATTR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/filio.h" "ac_cv_header_sys_filio_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_filio_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_FILIO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/ipc.h" "ac_cv_header_sys_ipc_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_ipc_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_IPC_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/link.h" "ac_cv_header_sys_link_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_link_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_LINK_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/modem.h" "ac_cv_header_sys_modem_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_modem_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_MODEM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/mtio.h" "ac_cv_header_sys_mtio_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_mtio_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_MTIO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_param_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_PARAM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/prctl.h" "ac_cv_header_sys_prctl_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_prctl_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_PRCTL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/ptrace.h" "ac_cv_header_sys_ptrace_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_ptrace_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_PTRACE_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/queue.h" "ac_cv_header_sys_queue_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_queue_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_QUEUE_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/random.h" "ac_cv_header_sys_random_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_random_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_RANDOM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/resource.h" "ac_cv_header_sys_resource_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_resource_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_RESOURCE_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/scsiio.h" "ac_cv_header_sys_scsiio_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_scsiio_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_SCSIIO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/shm.h" "ac_cv_header_sys_shm_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_shm_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_SHM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/signal.h" "ac_cv_header_sys_signal_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_signal_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_SIGNAL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/socketvar.h" "ac_cv_header_sys_socketvar_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_socketvar_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_SOCKETVAR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/sockio.h" "ac_cv_header_sys_sockio_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_sockio_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_SOCKIO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/statvfs.h" "ac_cv_header_sys_statvfs_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_statvfs_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_STATVFS_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/strtio.h" "ac_cv_header_sys_strtio_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_strtio_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_STRTIO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/syscall.h" "ac_cv_header_sys_syscall_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_syscall_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_SYSCALL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/sysinfo.h" "ac_cv_header_sys_sysinfo_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_sysinfo_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_SYSINFO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/times.h" "ac_cv_header_sys_times_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_times_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_TIMES_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/uio.h" "ac_cv_header_sys_uio_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_uio_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_UIO_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/user.h" "ac_cv_header_sys_user_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_user_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_USER_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/utsname.h" "ac_cv_header_sys_utsname_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_utsname_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_UTSNAME_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/vnode.h" "ac_cv_header_sys_vnode_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_vnode_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_VNODE_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/xattr.h" "ac_cv_header_sys_xattr_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_xattr_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_XATTR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "syscall.h" "ac_cv_header_syscall_h" "$ac_includes_default" -if test "x$ac_cv_header_syscall_h" = xyes -then : - printf "%s\n" "#define HAVE_SYSCALL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "utime.h" "ac_cv_header_utime_h" "$ac_includes_default" -if test "x$ac_cv_header_utime_h" = xyes -then : - printf "%s\n" "#define HAVE_UTIME_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "valgrind/memcheck.h" "ac_cv_header_valgrind_memcheck_h" "$ac_includes_default" -if test "x$ac_cv_header_valgrind_memcheck_h" = xyes -then : - printf "%s\n" "#define HAVE_VALGRIND_MEMCHECK_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "valgrind/valgrind.h" "ac_cv_header_valgrind_valgrind_h" "$ac_includes_default" -if test "x$ac_cv_header_valgrind_valgrind_h" = xyes -then : - printf "%s\n" "#define HAVE_VALGRIND_VALGRIND_H 1" >>confdefs.h - -fi - -ac_fn_c_check_header_compile "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_mkdev_h" = xyes -then : - -printf "%s\n" "#define MAJOR_IN_MKDEV 1" >>confdefs.h - -fi - -if test $ac_cv_header_sys_mkdev_h = no; then - ac_fn_c_check_header_compile "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_sysmacros_h" = xyes -then : - -printf "%s\n" "#define MAJOR_IN_SYSMACROS 1" >>confdefs.h - -fi - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether stat file-mode macros are broken" >&5 -printf %s "checking whether stat file-mode macros are broken... " >&6; } -if test ${ac_cv_header_stat_broken+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include - -#if defined S_ISBLK && defined S_IFDIR -extern char c1[S_ISBLK (S_IFDIR) ? -1 : 1]; -#endif - -#if defined S_ISBLK && defined S_IFCHR -extern char c2[S_ISBLK (S_IFCHR) ? -1 : 1]; -#endif - -#if defined S_ISLNK && defined S_IFREG -extern char c3[S_ISLNK (S_IFREG) ? -1 : 1]; -#endif - -#if defined S_ISSOCK && defined S_IFREG -extern char c4[S_ISSOCK (S_IFREG) ? -1 : 1]; -#endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_header_stat_broken=no -else $as_nop - ac_cv_header_stat_broken=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stat_broken" >&5 -printf "%s\n" "$ac_cv_header_stat_broken" >&6; } -if test $ac_cv_header_stat_broken = yes; then - -printf "%s\n" "#define STAT_MACROS_BROKEN 1" >>confdefs.h - -fi - - - -ac_fn_c_check_header_compile "$LINENO" "sys/conf.h" "ac_cv_header_sys_conf_h" "#include - #ifdef HAVE_SYS_PARAM_H - # include - #endif -" -if test "x$ac_cv_header_sys_conf_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_CONF_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/mount.h" "ac_cv_header_sys_mount_h" "#include - #ifdef HAVE_SYS_PARAM_H - # include - #endif -" -if test "x$ac_cv_header_sys_mount_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_MOUNT_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/statfs.h" "ac_cv_header_sys_statfs_h" "#include - #ifdef HAVE_SYS_PARAM_H - # include - #endif -" -if test "x$ac_cv_header_sys_statfs_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_STATFS_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/user.h" "ac_cv_header_sys_user_h" "#include - #ifdef HAVE_SYS_PARAM_H - # include - #endif -" -if test "x$ac_cv_header_sys_user_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_USER_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/vfs.h" "ac_cv_header_sys_vfs_h" "#include - #ifdef HAVE_SYS_PARAM_H - # include - #endif -" -if test "x$ac_cv_header_sys_vfs_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_VFS_H 1" >>confdefs.h - -fi - - -saved_sysctl_h_CFLAGS=$CFLAGS -test "x${GCC}" != xyes || CFLAGS="$CFLAGS -Werror" -ac_fn_c_check_header_compile "$LINENO" "sys/sysctl.h" "ac_cv_header_sys_sysctl_h" "#include - #ifdef HAVE_SYS_PARAM_H - # include - #endif -" -if test "x$ac_cv_header_sys_sysctl_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_SYSCTL_H 1" >>confdefs.h - -fi - -CFLAGS=$saved_sysctl_h_CFLAGS - -ac_fn_c_check_header_compile "$LINENO" "netinet/ip.h" "ac_cv_header_netinet_ip_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_ip_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_IP_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_net_if_h" = xyes -then : - printf "%s\n" "#define HAVE_NET_IF_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "net/if_arp.h" "ac_cv_header_net_if_arp_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_net_if_arp_h" = xyes -then : - printf "%s\n" "#define HAVE_NET_IF_ARP_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "net/if_dl.h" "ac_cv_header_net_if_dl_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_net_if_dl_h" = xyes -then : - printf "%s\n" "#define HAVE_NET_IF_DL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "net/if_types.h" "ac_cv_header_net_if_types_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_net_if_types_h" = xyes -then : - printf "%s\n" "#define HAVE_NET_IF_TYPES_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "net/route.h" "ac_cv_header_net_route_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_net_route_h" = xyes -then : - printf "%s\n" "#define HAVE_NET_ROUTE_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/if_ether.h" "ac_cv_header_netinet_if_ether_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_if_ether_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_IF_ETHER_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/in_pcb.h" "ac_cv_header_netinet_in_pcb_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_in_pcb_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_IN_PCB_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/ip_icmp.h" "ac_cv_header_netinet_ip_icmp_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_ip_icmp_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_IP_ICMP_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/ip_var.h" "ac_cv_header_netinet_ip_var_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_ip_var_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_IP_VAR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/udp.h" "ac_cv_header_netinet_udp_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_udp_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_UDP_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet6/ip6_var.h" "ac_cv_header_netinet6_ip6_var_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_netinet6_ip6_var_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET6_IP6_VAR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netipx/ipx.h" "ac_cv_header_netipx_ipx_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_netipx_ipx_h" = xyes -then : - printf "%s\n" "#define HAVE_NETIPX_IPX_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "sys/un.h" "ac_cv_header_sys_un_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NET_ROUTE_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NET_IF_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif -" -if test "x$ac_cv_header_sys_un_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_UN_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "netinet/udp_var.h" "ac_cv_header_netinet_udp_var_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif - #ifdef HAVE_NETINET_IP_VAR_H - # include - #endif - #ifdef HAVE_NETINET_IP_ICMP_H - # include - #endif - #ifdef HAVE_NETINET_UDP_H - # include - #endif - #ifdef HAVE_NETINET_TCP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_udp_var_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_UDP_VAR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/icmp_var.h" "ac_cv_header_netinet_icmp_var_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif - #ifdef HAVE_NETINET_IP_VAR_H - # include - #endif - #ifdef HAVE_NETINET_IP_ICMP_H - # include - #endif - #ifdef HAVE_NETINET_UDP_H - # include - #endif - #ifdef HAVE_NETINET_TCP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_icmp_var_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_ICMP_VAR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/icmp6.h" "ac_cv_header_netinet_icmp6_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif - #ifdef HAVE_NETINET_IP_VAR_H - # include - #endif - #ifdef HAVE_NETINET_IP_ICMP_H - # include - #endif - #ifdef HAVE_NETINET_UDP_H - # include - #endif - #ifdef HAVE_NETINET_TCP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_icmp6_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_ICMP6_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "netinet/tcp_var.h" "ac_cv_header_netinet_tcp_var_h" "#include - #include - #ifdef HAVE_SYS_SOCKETVAR_H - # include - #endif - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_NETINET_IN_SYSTM_H - # include - #endif - #ifdef HAVE_NETINET_IP_H - # include - #endif - #ifdef HAVE_NETINET_IP_VAR_H - # include - #endif - #ifdef HAVE_NETINET_IP_ICMP_H - # include - #endif - #ifdef HAVE_NETINET_UDP_H - # include - #endif - #ifdef HAVE_NETINET_TCP_H - # include - #endif -" -if test "x$ac_cv_header_netinet_tcp_var_h" = xyes -then : - printf "%s\n" "#define HAVE_NETINET_TCP_VAR_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "linux/ipx.h" "ac_cv_header_linux_ipx_h" "#include - #include - #ifdef HAVE_ASM_TYPES_H - # include - #endif - #ifdef HAVE_LINUX_TYPES_H - # include - #endif -" -if test "x$ac_cv_header_linux_ipx_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_IPX_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/irda.h" "ac_cv_header_linux_irda_h" "#include - #include - #ifdef HAVE_ASM_TYPES_H - # include - #endif - #ifdef HAVE_LINUX_TYPES_H - # include - #endif -" -if test "x$ac_cv_header_linux_irda_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_IRDA_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/rtnetlink.h" "ac_cv_header_linux_rtnetlink_h" "#include - #include - #ifdef HAVE_ASM_TYPES_H - # include - #endif - #ifdef HAVE_LINUX_TYPES_H - # include - #endif -" -if test "x$ac_cv_header_linux_rtnetlink_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_RTNETLINK_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "resolv.h" "ac_cv_header_resolv_h" "#include - #include - #ifdef HAVE_NETINET_IN_H - # include - #endif - #ifdef HAVE_ARPA_NAMESER_H - # include - #endif -" -if test "x$ac_cv_header_resolv_h" = xyes -then : - printf "%s\n" "#define HAVE_RESOLV_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "ifaddrs.h" "ac_cv_header_ifaddrs_h" "#include -" -if test "x$ac_cv_header_ifaddrs_h" = xyes -then : - printf "%s\n" "#define HAVE_IFADDRS_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "sys/ucontext.h" "ac_cv_header_sys_ucontext_h" "#include -" -if test "x$ac_cv_header_sys_ucontext_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_UCONTEXT_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "sys/thr.h" "ac_cv_header_sys_thr_h" "#include -#ifdef HAVE_SYS_UCONTEXT_H -#include -#endif -" -if test "x$ac_cv_header_sys_thr_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_THR_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "pthread_np.h" "ac_cv_header_pthread_np_h" "#ifdef HAVE_PTHREAD_H -#include -#endif -" -if test "x$ac_cv_header_pthread_np_h" = xyes -then : - printf "%s\n" "#define HAVE_PTHREAD_NP_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "linux/videodev2.h" "ac_cv_header_linux_videodev2_h" "#include -#include -#ifdef HAVE_ASM_TYPES_H -#include -#endif -" -if test "x$ac_cv_header_linux_videodev2_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_VIDEODEV2_H 1" >>confdefs.h - -fi - - -ac_fn_c_check_header_compile "$LINENO" "libprocstat.h" "ac_cv_header_libprocstat_h" "#ifdef HAVE_SYS_PARAM_H -#include -#endif -#include -#ifdef HAVE_SYS_QUEUE_H -#include -#endif -" -if test "x$ac_cv_header_libprocstat_h" = xyes -then : - printf "%s\n" "#define HAVE_LIBPROCSTAT_H 1" >>confdefs.h - -fi - - -if test "x$ac_cv_header_sys_xattr_h" = xyes -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether getxattr takes additional arguments" >&5 -printf %s "checking whether getxattr takes additional arguments... " >&6; } -if test ${wine_cv_xattr_extra_args+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -getxattr("", "", "", 0, 0, 0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - wine_cv_xattr_extra_args=yes -else $as_nop - wine_cv_xattr_extra_args=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_xattr_extra_args" >&5 -printf "%s\n" "$wine_cv_xattr_extra_args" >&6; } - test $wine_cv_xattr_extra_args != yes || -printf "%s\n" "#define XATTR_ADDITIONAL_OPTIONS 1" >>confdefs.h - -fi - - -DLLFLAGS="" - -LDDLLFLAGS="" - -LDEXECFLAGS="" - -EXTRACFLAGS="" - -UNIXDLLFLAGS="-fPIC" - -UNIXLDFLAGS="-shared -Wl,-Bsymbolic -Wl,-soname,\$(UNIXLIB)" - -TOP_INSTALL_LIB="" - -TOP_INSTALL_DEV="" - -WINELOADER_LDFLAGS="" - -WINEPRELOADER_LDFLAGS="" - -LIBEXT="so" -# Extract the first word of "ldd", so it can be a program name with args. -set dummy ldd; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_LDD+y} -then : - printf %s "(cached) " >&6 -else $as_nop - case $LDD in - [\\/]* | ?:[\\/]*) - ac_cv_path_LDD="$LDD" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_dummy="/sbin:/usr/sbin:$PATH" -for as_dir in $as_dummy -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_LDD="$as_dir$ac_word$ac_exec_ext" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_path_LDD" && ac_cv_path_LDD="true" - ;; -esac -fi -LDD=$ac_cv_path_LDD -if test -n "$LDD"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LDD" >&5 -printf "%s\n" "$LDD" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OTOOL+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$OTOOL"; then - ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OTOOL="${ac_tool_prefix}otool" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -OTOOL=$ac_cv_prog_OTOOL -if test -n "$OTOOL"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 -printf "%s\n" "$OTOOL" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL"; then - ac_ct_OTOOL=$OTOOL - # Extract the first word of "otool", so it can be a program name with args. -set dummy otool; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OTOOL+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_OTOOL"; then - ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OTOOL="otool" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL -if test -n "$ac_ct_OTOOL"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 -printf "%s\n" "$ac_ct_OTOOL" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_OTOOL" = x; then - OTOOL="otool" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL=$ac_ct_OTOOL - fi -else - OTOOL="$ac_cv_prog_OTOOL" -fi - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}readelf", so it can be a program name with args. -set dummy ${ac_tool_prefix}readelf; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_READELF+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$READELF"; then - ac_cv_prog_READELF="$READELF" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_READELF="${ac_tool_prefix}readelf" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -READELF=$ac_cv_prog_READELF -if test -n "$READELF"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $READELF" >&5 -printf "%s\n" "$READELF" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_READELF"; then - ac_ct_READELF=$READELF - # Extract the first word of "readelf", so it can be a program name with args. -set dummy readelf; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_READELF+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_READELF"; then - ac_cv_prog_ac_ct_READELF="$ac_ct_READELF" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_READELF="readelf" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_READELF=$ac_cv_prog_ac_ct_READELF -if test -n "$ac_ct_READELF"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_READELF" >&5 -printf "%s\n" "$ac_ct_READELF" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - if test "x$ac_ct_READELF" = x; then - READELF="true" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - READELF=$ac_ct_READELF - fi -else - READELF="$ac_cv_prog_READELF" -fi - -wine_rules="all:" -SUBDIRS="" - -DISABLED_SUBDIRS="" - -CONFIGURE_TARGETS="" - - -wine_fn_config_makefile () -{ - as_fn_append SUBDIRS " \\$as_nl $1" - eval enable=\$$2 - case "$enable" in - no) as_fn_append DISABLED_SUBDIRS " $1" ;; - *aarch64*|*arm*|*i386*|*x86_64*) - if test -n "$PE_ARCHS" - then - for i in $PE_ARCHS - do - test $(expr ",$enable," : ".*,$i,") -gt 0 || as_fn_append ${i}_DISABLED_SUBDIRS " $1" - done - else - test $(expr ",$enable," : ".*,$HOST_ARCH,") -gt 0 || as_fn_append DISABLED_SUBDIRS " $1" - fi;; - esac -} - -wine_fn_config_symlink () -{ - ac_links=$@ - as_fn_append wine_rules " -$ac_links: - @./config.status \$@" - for f in $ac_links; do as_fn_append CONFIGURE_TARGETS " $f"; done -} - -libwine_soversion=`expr $libwine_version : '\([0-9]*\)\..*'` - -case $host_os in - cygwin*|mingw32*) - LIBEXT="dll" - EXTRACFLAGS="-D__WINE_PE_BUILD" - case $host_cpu in - *i[3456]86*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,--disable-stdcall-fixup" >&5 -printf %s "checking whether the compiler supports -Wl,--disable-stdcall-fixup... " >&6; } -if test ${ac_cv_cflags__Wl___disable_stdcall_fixup+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,--disable-stdcall-fixup" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl___disable_stdcall_fixup=yes -else $as_nop - ac_cv_cflags__Wl___disable_stdcall_fixup=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl___disable_stdcall_fixup" >&5 -printf "%s\n" "$ac_cv_cflags__Wl___disable_stdcall_fixup" >&6; } -if test "x$ac_cv_cflags__Wl___disable_stdcall_fixup" = xyes -then : - LDDLLFLAGS="-Wl,--disable-stdcall-fixup" -fi ;; - esac - enable_loader=${enable_loader:-no} - enable_server=${enable_server:-no} - with_x=${with_x:-no} - with_pthread=${with_pthread:-no} - ;; - - darwin*|macosx*) - LIBEXT="dylib" - DLLFLAGS="$DLLFLAGS -fPIC" - LDDLLFLAGS="-fPIC" - enable_winemac_drv=${enable_winemac_drv:-yes} - CARBON_LIBS="-framework Carbon" - - COREFOUNDATION_LIBS="-framework CoreFoundation" - - DISKARBITRATION_LIBS="-framework DiskArbitration -framework CoreFoundation" - - IOKIT_LIBS="-framework IOKit -framework CoreFoundation" - - METAL_LIBS="-framework Metal" - - APPLICATIONSERVICES_LIBS="-framework ApplicationServices" - - CORESERVICES_LIBS="-framework CoreServices" - - APPKIT_LIBS="-framework AppKit" - - SECURITY_LIBS="-framework Security -framework CoreFoundation" - - SYSTEMCONFIGURATION_LIBS="-framework SystemConfiguration" - - - WINELOADER_LDFLAGS="-Wl,-pie,-segalign,0x1000,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,loader/wine_info.plist" - - wine_can_build_preloader=yes - WINEPRELOADER_LDFLAGS="-nostartfiles -nodefaultlibs -e _start -ldylib1.o -Wl,-image_base,0x7d400000,-segalign,0x1000,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,loader/wine_info.plist,-segaddr,WINE_4GB_RESERVE,0x100000000" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-no_new_main -e _main" >&5 -printf %s "checking whether the compiler supports -Wl,-no_new_main -e _main... " >&6; } -if test ${ac_cv_cflags__Wl__no_new_main__e__main+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,-no_new_main -e _main" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl__no_new_main__e__main=yes -else $as_nop - ac_cv_cflags__Wl__no_new_main__e__main=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl__no_new_main__e__main" >&5 -printf "%s\n" "$ac_cv_cflags__Wl__no_new_main__e__main" >&6; } -if test "x$ac_cv_cflags__Wl__no_new_main__e__main" = xyes -then : - WINEPRELOADER_LDFLAGS="-Wl,-no_new_main $WINEPRELOADER_LDFLAGS" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-no_new_main -e _main -mmacosx-version-min=10.7 -nostartfiles -nodefaultlibs" >&5 -printf %s "checking whether the compiler supports -Wl,-no_new_main -e _main -mmacosx-version-min=10.7 -nostartfiles -nodefaultlibs... " >&6; } -if test ${ac_cv_cflags__Wl__no_new_main__e__main__mmacosx_version_min_10_7__nostartfiles__nodefaultlibs+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,-no_new_main -e _main -mmacosx-version-min=10.7 -nostartfiles -nodefaultlibs" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl__no_new_main__e__main__mmacosx_version_min_10_7__nostartfiles__nodefaultlibs=yes -else $as_nop - ac_cv_cflags__Wl__no_new_main__e__main__mmacosx_version_min_10_7__nostartfiles__nodefaultlibs=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl__no_new_main__e__main__mmacosx_version_min_10_7__nostartfiles__nodefaultlibs" >&5 -printf "%s\n" "$ac_cv_cflags__Wl__no_new_main__e__main__mmacosx_version_min_10_7__nostartfiles__nodefaultlibs" >&6; } -if test "x$ac_cv_cflags__Wl__no_new_main__e__main__mmacosx_version_min_10_7__nostartfiles__nodefaultlibs" = xyes -then : - WINEPRELOADER_LDFLAGS="-mmacosx-version-min=10.7 $WINEPRELOADER_LDFLAGS" -else $as_nop - wine_can_build_preloader=no -fi -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -mmacosx-version-min=10.7 -nostartfiles -nodefaultlibs" >&5 -printf %s "checking whether the compiler supports -mmacosx-version-min=10.7 -nostartfiles -nodefaultlibs... " >&6; } -if test ${ac_cv_cflags__mmacosx_version_min_10_7__nostartfiles__nodefaultlibs+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -mmacosx-version-min=10.7 -nostartfiles -nodefaultlibs" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__mmacosx_version_min_10_7__nostartfiles__nodefaultlibs=yes -else $as_nop - ac_cv_cflags__mmacosx_version_min_10_7__nostartfiles__nodefaultlibs=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__mmacosx_version_min_10_7__nostartfiles__nodefaultlibs" >&5 -printf "%s\n" "$ac_cv_cflags__mmacosx_version_min_10_7__nostartfiles__nodefaultlibs" >&6; } -if test "x$ac_cv_cflags__mmacosx_version_min_10_7__nostartfiles__nodefaultlibs" = xyes -then : - WINEPRELOADER_LDFLAGS="-mmacosx-version-min=10.7 $WINEPRELOADER_LDFLAGS" -else $as_nop - wine_can_build_preloader=no -fi -fi - if test "$wine_can_build_preloader" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-no_pie" >&5 -printf %s "checking whether the compiler supports -Wl,-no_pie... " >&6; } -if test ${ac_cv_cflags__Wl__no_pie+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,-no_pie" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl__no_pie=yes -else $as_nop - ac_cv_cflags__Wl__no_pie=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl__no_pie" >&5 -printf "%s\n" "$ac_cv_cflags__Wl__no_pie" >&6; } -if test "x$ac_cv_cflags__Wl__no_pie" = xyes -then : - WINEPRELOADER_LDFLAGS="-Wl,-no_pie $WINEPRELOADER_LDFLAGS" -fi - WINELOADER_LDFLAGS="$WINELOADER_LDFLAGS -mmacosx-version-min=10.7" - else - as_fn_append wine_warnings "|can't build Wine preloader; many programs won't work" - fi - - if test "x$with_coreaudio" != "xno"; - then - COREAUDIO_LIBS="-framework CoreFoundation -framework CoreAudio -framework AudioUnit -framework AudioToolbox -framework CoreMIDI" - - enable_winecoreaudio_drv=${enable_winecoreaudio_drv:-yes} - fi - if test "$ac_cv_header_OpenCL_opencl_h" = "yes" - then - OPENCL_LIBS="-framework OpenCL" - - ac_cv_lib_OpenCL_clGetPlatformInfo=yes - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether MTLDevice protocol supports registryID property" >&5 -printf %s "checking whether MTLDevice protocol supports registryID property... " >&6; } - ac_ext=m -ac_cpp='$OBJCPP $CPPFLAGS' -ac_compile='$OBJC -c $OBJCFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$OBJC -o conftest$ac_exeext $OBJCFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_objc_compiler_gnu - - ac_ext=m -ac_cpp='$OBJCPP $CPPFLAGS' -ac_compile='$OBJC -c $OBJCFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$OBJC -o conftest$ac_exeext $OBJCFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_objc_compiler_gnu -if test -n "$ac_tool_prefix"; then - for ac_prog in gcc objcc objc cc CC clang - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_OBJC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$OBJC"; then - ac_cv_prog_OBJC="$OBJC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_OBJC="$ac_tool_prefix$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -OBJC=$ac_cv_prog_OBJC -if test -n "$OBJC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OBJC" >&5 -printf "%s\n" "$OBJC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$OBJC" && break - done -fi -if test -z "$OBJC"; then - ac_ct_OBJC=$OBJC - for ac_prog in gcc objcc objc cc CC clang -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_ac_ct_OBJC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_OBJC"; then - ac_cv_prog_ac_ct_OBJC="$ac_ct_OBJC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OBJC="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_OBJC=$ac_cv_prog_ac_ct_OBJC -if test -n "$ac_ct_OBJC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJC" >&5 -printf "%s\n" "$ac_ct_OBJC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$ac_ct_OBJC" && break -done - - if test "x$ac_ct_OBJC" = x; then - OBJC="gcc" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OBJC=$ac_ct_OBJC - fi -fi - -# Provide some information about the compiler. -printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Objective C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU Objective C" >&5 -printf %s "checking whether the compiler supports GNU Objective C... " >&6; } -if test ${ac_cv_objc_compiler_gnu+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_objc_try_compile "$LINENO" -then : - ac_compiler_gnu=yes -else $as_nop - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -ac_cv_objc_compiler_gnu=$ac_compiler_gnu - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objc_compiler_gnu" >&5 -printf "%s\n" "$ac_cv_objc_compiler_gnu" >&6; } -ac_compiler_gnu=$ac_cv_objc_compiler_gnu - -if test $ac_compiler_gnu = yes; then - GOBJC=yes -else - GOBJC= -fi -ac_test_OBJCFLAGS=${OBJCFLAGS+y} -ac_save_OBJCFLAGS=$OBJCFLAGS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $OBJC accepts -g" >&5 -printf %s "checking whether $OBJC accepts -g... " >&6; } -if test ${ac_cv_prog_objc_g+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_save_objc_werror_flag=$ac_objc_werror_flag - ac_objc_werror_flag=yes - ac_cv_prog_objc_g=no - OBJCFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_objc_try_compile "$LINENO" -then : - ac_cv_prog_objc_g=yes -else $as_nop - OBJCFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_objc_try_compile "$LINENO" -then : - -else $as_nop - ac_objc_werror_flag=$ac_save_objc_werror_flag - OBJCFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_objc_try_compile "$LINENO" -then : - ac_cv_prog_objc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_objc_werror_flag=$ac_save_objc_werror_flag -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_objc_g" >&5 -printf "%s\n" "$ac_cv_prog_objc_g" >&6; } -if test $ac_test_OBJCFLAGS; then - OBJCFLAGS=$ac_save_OBJCFLAGS -elif test $ac_cv_prog_objc_g = yes; then - if test "$GOBJC" = yes; then - OBJCFLAGS="-g -O2" - else - OBJCFLAGS="-g" - fi -else - if test "$GOBJC" = yes; then - OBJCFLAGS="-O2" - else - OBJCFLAGS= - fi -fi -ac_ext=m -ac_cpp='$OBJCPP $CPPFLAGS' -ac_compile='$OBJC -c $OBJCFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$OBJC -o conftest$ac_exeext $OBJCFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_objc_compiler_gnu - - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -id device; device.registryID; - ; - return 0; -} -_ACEOF -if ac_fn_objc_try_compile "$LINENO" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } - -printf "%s\n" "#define HAVE_MTLDEVICE_REGISTRYID 1" >>confdefs.h - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - UNIXLDFLAGS="-dynamiclib -install_name @rpath/\$(UNIXLIB) -Wl,-rpath,@loader_path\/" - LIBWINE_SHAREDLIB="libwine.$libwine_version.dylib" - - LIBWINE_LDFLAGS="-dynamiclib -install_name @rpath/libwine.$libwine_soversion.dylib -Wl,-rpath,@loader_path/ -compatibility_version $libwine_soversion -current_version $libwine_version" - - WINELOADER_DEPENDS="wine_info.plist" - - TOP_INSTALL_LIB="$TOP_INSTALL_LIB libs/wine/libwine.$libwine_version.dylib libs/wine/libwine.$libwine_soversion.dylib" - ;; - - linux-android*) - -printf "%s\n" "#define _GNU_SOURCE 1" >>confdefs.h - - DLLFLAGS="$DLLFLAGS -fPIC" - LDDLLFLAGS="-fPIC" - LDEXECFLAGS="-Wl,-pie" - enable_wineandroid_drv=${enable_wineandroid_drv:-yes} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-z,defs" >&5 -printf %s "checking whether the compiler supports -Wl,-z,defs... " >&6; } -if test ${ac_cv_cflags__Wl__z_defs+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,-z,defs" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl__z_defs=yes -else $as_nop - ac_cv_cflags__Wl__z_defs=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl__z_defs" >&5 -printf "%s\n" "$ac_cv_cflags__Wl__z_defs" >&6; } -if test "x$ac_cv_cflags__Wl__z_defs" = xyes -then : - UNIXLDFLAGS="$UNIXLDFLAGS -Wl,-z,defs" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fPIC -Wl,--export-dynamic" >&5 -printf %s "checking whether the compiler supports -fPIC -Wl,--export-dynamic... " >&6; } -if test ${ac_cv_cflags__fPIC__Wl___export_dynamic+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -fPIC -Wl,--export-dynamic" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__fPIC__Wl___export_dynamic=yes -else $as_nop - ac_cv_cflags__fPIC__Wl___export_dynamic=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fPIC__Wl___export_dynamic" >&5 -printf "%s\n" "$ac_cv_cflags__fPIC__Wl___export_dynamic" >&6; } -if test "x$ac_cv_cflags__fPIC__Wl___export_dynamic" = xyes -then : - WINELOADER_LDFLAGS="-Wl,--export-dynamic" -fi - WINEPRELOADER_LDFLAGS="-static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x7d400000" - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lEGL" >&5 -printf %s "checking for -lEGL... " >&6; } -if test ${ac_cv_lib_soname_EGL+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lEGL $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char eglGetProcAddress (); -int -main (void) -{ -return eglGetProcAddress (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_EGL=`$ac_cv_path_LDD conftest.exe | grep "EGL" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_EGL=`$OTOOL -L conftest$ac_exeext | grep "libEGL\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libEGL\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_EGL=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libEGL\\.$LIBEXT" | sed -e "s/^.*\\[\\(libEGL\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_EGL:+false} : -then : - ac_cv_lib_soname_EGL=`$LDD conftest$ac_exeext | grep "libEGL\\.$LIBEXT" | sed -e "s/^.*\(libEGL\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_EGL= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_EGL:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_EGL" >&5 -printf "%s\n" "$ac_cv_lib_soname_EGL" >&6; } - -printf "%s\n" "#define SONAME_LIBEGL \"$ac_cv_lib_soname_EGL\"" >>confdefs.h - - -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lGLESv2" >&5 -printf %s "checking for -lGLESv2... " >&6; } -if test ${ac_cv_lib_soname_GLESv2+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lGLESv2 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char glFlush (); -int -main (void) -{ -return glFlush (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_GLESv2=`$ac_cv_path_LDD conftest.exe | grep "GLESv2" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_GLESv2=`$OTOOL -L conftest$ac_exeext | grep "libGLESv2\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libGLESv2\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_GLESv2=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libGLESv2\\.$LIBEXT" | sed -e "s/^.*\\[\\(libGLESv2\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_GLESv2:+false} : -then : - ac_cv_lib_soname_GLESv2=`$LDD conftest$ac_exeext | grep "libGLESv2\\.$LIBEXT" | sed -e "s/^.*\(libGLESv2\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_GLESv2= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_GLESv2:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_GLESv2" >&5 -printf "%s\n" "$ac_cv_lib_soname_GLESv2" >&6; } - -printf "%s\n" "#define SONAME_LIBGLESV2 \"$ac_cv_lib_soname_GLESv2\"" >>confdefs.h - - -fi - - if test "x$exec_prefix" = xNONE - then - case $host_cpu in - *i[3456]86*) exec_prefix='${prefix}/x86' ;; - *x86_64*) exec_prefix='${prefix}/x86_64' ;; - *arm*) exec_prefix='${prefix}/armeabi-v7a' ;; - *aarch64*) exec_prefix='${prefix}/arm64-v8a' ;; - esac - fi - ;; - - *) - -printf "%s\n" "#define _GNU_SOURCE 1" >>confdefs.h - - test "$ac_cv_sys_file_offset_bits" = 64 && -printf "%s\n" "#define _TIME_BITS 64" >>confdefs.h - - case $host_cpu in - *i[3456789]86*) - DLLFLAGS="$DLLFLAGS -fno-PIC" - LDDLLFLAGS="-fno-PIC" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fno-PIC -Wl,-z,notext" >&5 -printf %s "checking whether the compiler supports -fno-PIC -Wl,-z,notext... " >&6; } -if test ${ac_cv_cflags__fno_PIC__Wl__z_notext+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -fno-PIC -Wl,-z,notext" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__fno_PIC__Wl__z_notext=yes -else $as_nop - ac_cv_cflags__fno_PIC__Wl__z_notext=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fno_PIC__Wl__z_notext" >&5 -printf "%s\n" "$ac_cv_cflags__fno_PIC__Wl__z_notext" >&6; } -if test "x$ac_cv_cflags__fno_PIC__Wl__z_notext" = xyes -then : - LDDLLFLAGS="$LDDLLFLAGS -Wl,-z,notext" -fi - ;; - *) - DLLFLAGS="$DLLFLAGS -fPIC" - LDDLLFLAGS="-fPIC" ;; - esac - LIBWINE_LDFLAGS="-shared -Wl,-soname,libwine.so.$libwine_soversion" - - echo '{ global: *; };' >conftest.map - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -shared -Wl,--version-script=conftest.map" >&5 -printf %s "checking whether the compiler supports -shared -Wl,--version-script=conftest.map... " >&6; } -if test ${ac_cv_cflags__shared__Wl___version_script_conftest_map+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -shared -Wl,--version-script=conftest.map" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__shared__Wl___version_script_conftest_map=yes -else $as_nop - ac_cv_cflags__shared__Wl___version_script_conftest_map=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__shared__Wl___version_script_conftest_map" >&5 -printf "%s\n" "$ac_cv_cflags__shared__Wl___version_script_conftest_map" >&6; } -if test "x$ac_cv_cflags__shared__Wl___version_script_conftest_map" = xyes -then : - LIBWINE_LDFLAGS="$LIBWINE_LDFLAGS -Wl,--version-script=\$(srcdir)/wine.map" -fi - rm -f conftest.map - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-z,defs" >&5 -printf %s "checking whether the compiler supports -Wl,-z,defs... " >&6; } -if test ${ac_cv_cflags__Wl__z_defs+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,-z,defs" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl__z_defs=yes -else $as_nop - ac_cv_cflags__Wl__z_defs=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl__z_defs" >&5 -printf "%s\n" "$ac_cv_cflags__Wl__z_defs" >&6; } -if test "x$ac_cv_cflags__Wl__z_defs" = xyes -then : - UNIXLDFLAGS="$UNIXLDFLAGS -Wl,-z,defs" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,--export-dynamic" >&5 -printf %s "checking whether the compiler supports -Wl,--export-dynamic... " >&6; } -if test ${ac_cv_cflags__Wl___export_dynamic+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,--export-dynamic" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl___export_dynamic=yes -else $as_nop - ac_cv_cflags__Wl___export_dynamic=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl___export_dynamic" >&5 -printf "%s\n" "$ac_cv_cflags__Wl___export_dynamic" >&6; } -if test "x$ac_cv_cflags__Wl___export_dynamic" = xyes -then : - WINELOADER_LDFLAGS="-Wl,--export-dynamic" -fi - WINEPRELOADER_LDFLAGS="-static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x7d400000" - - case $host_cpu in - *i[3456789]86* | x86_64 | *aarch64* | arm*) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-Ttext-segment=0x7bc00000" >&5 -printf %s "checking whether the compiler supports -Wl,-Ttext-segment=0x7bc00000... " >&6; } -if test ${ac_cv_cflags__Wl__Ttext_segment_0x7bc00000+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,-Ttext-segment=0x7bc00000" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl__Ttext_segment_0x7bc00000=yes -else $as_nop - ac_cv_cflags__Wl__Ttext_segment_0x7bc00000=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl__Ttext_segment_0x7bc00000" >&5 -printf "%s\n" "$ac_cv_cflags__Wl__Ttext_segment_0x7bc00000" >&6; } -if test "x$ac_cv_cflags__Wl__Ttext_segment_0x7bc00000" = xyes -then : - case $host_os in - freebsd* | kfreebsd*-gnu) WINELOADER_LDFLAGS="$WINELOADER_LDFLAGS -Wl,-Ttext-segment=0x60000000" ;; - *) WINELOADER_LDFLAGS="$WINELOADER_LDFLAGS -Wl,-Ttext-segment=0x7d000000" ;; - esac -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,--section-start,.interp=0x7d000400" >&5 -printf %s "checking whether the compiler supports -Wl,--section-start,.interp=0x7d000400... " >&6; } -if test ${ac_cv_cflags__Wl___section_start__interp_0x7d000400+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,--section-start,.interp=0x7d000400" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl___section_start__interp_0x7d000400=yes -else $as_nop - ac_cv_cflags__Wl___section_start__interp_0x7d000400=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl___section_start__interp_0x7d000400" >&5 -printf "%s\n" "$ac_cv_cflags__Wl___section_start__interp_0x7d000400" >&6; } -if test "x$ac_cv_cflags__Wl___section_start__interp_0x7d000400" = xyes -then : - case $host_os in - freebsd* | kfreebsd*-gnu) WINELOADER_LDFLAGS="$WINELOADER_LDFLAGS -Wl,--section-start,.interp=0x60000400" ;; - *) WINELOADER_LDFLAGS="$WINELOADER_LDFLAGS -Wl,--section-start,.interp=0x7d000400" ;; - esac -fi - # Extract the first word of "prelink", so it can be a program name with args. -set dummy prelink; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_path_PRELINK+y} -then : - printf %s "(cached) " >&6 -else $as_nop - case $PRELINK in - [\\/]* | ?:[\\/]*) - ac_cv_path_PRELINK="$PRELINK" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in /sbin /usr/sbin $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_path_PRELINK="$as_dir$ac_word$ac_exec_ext" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - - test -z "$ac_cv_path_PRELINK" && ac_cv_path_PRELINK="false" - ;; -esac -fi -PRELINK=$ac_cv_path_PRELINK -if test -n "$PRELINK"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PRELINK" >&5 -printf "%s\n" "$PRELINK" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - if test "x$PRELINK" = xfalse - then - as_fn_append wine_warnings "|prelink not found and linker does not support relocation, base address of core dlls won't be set correctly." - fi -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-z,max-page-size=0x1000" >&5 -printf %s "checking whether the compiler supports -Wl,-z,max-page-size=0x1000... " >&6; } -if test ${ac_cv_cflags__Wl__z_max_page_size_0x1000+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,-z,max-page-size=0x1000" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl__z_max_page_size_0x1000=yes -else $as_nop - ac_cv_cflags__Wl__z_max_page_size_0x1000=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl__z_max_page_size_0x1000" >&5 -printf "%s\n" "$ac_cv_cflags__Wl__z_max_page_size_0x1000" >&6; } -if test "x$ac_cv_cflags__Wl__z_max_page_size_0x1000" = xyes -then : - WINELOADER_LDFLAGS="$WINELOADER_LDFLAGS -Wl,-z,max-page-size=0x1000" -fi - ;; - esac - LIBWINE_SHAREDLIB="libwine.so.$libwine_version" - - LIBWINE_DEPENDS="wine.map" - - TOP_INSTALL_LIB="$TOP_INSTALL_LIB libs/wine/libwine.so.$libwine_version libs/wine/libwine.so.$libwine_soversion" - ;; -esac - -enable_winecoreaudio_drv=${enable_winecoreaudio_drv:-no} -enable_wineandroid_drv=${enable_wineandroid_drv:-no} -enable_winemac_drv=${enable_winemac_drv:-no} - -PE_ARCHS="" - -cross_archs= -if test ${enable_archs+y} -then : - test "x$with_system_dllpath" = "x" || as_fn_error $? "\"The --with-system-dllpath option is not compatible with --enable-archs\"" "$LINENO" 5 - ac_save_IFS=$IFS - IFS=' ,' - set x $enable_archs - IFS=$ac_save_IFS - shift - for arch - do - case $arch in - i386|x86_64|arm|aarch64) cross_archs="$cross_archs $arch" ;; - *) as_fn_error $? "Unknown cross-compilation architecture '$arch'" "$LINENO" 5 ;; - esac - done -else $as_nop - if test "x$with_mingw" != xno - then - test $HOST_ARCH = unknown || cross_archs=$HOST_ARCH - case "x$with_mingw" in - x|xyes) ;; - *) eval "${cross_archs}_CC=\$with_mingw" ;; - esac - fi -fi - -for wine_arch in $cross_archs -do - if eval \${${wine_arch}_CC:+false} : -then : - case $wine_arch in - aarch64) - for ac_prog in aarch64-w64-mingw32-clang aarch64-w64-mingw32-gcc clang -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_aarch64_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$aarch64_CC"; then - ac_cv_prog_aarch64_CC="$aarch64_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_aarch64_CC="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -aarch64_CC=$ac_cv_prog_aarch64_CC -if test -n "$aarch64_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $aarch64_CC" >&5 -printf "%s\n" "$aarch64_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$aarch64_CC" && break -done -test -n "$aarch64_CC" || aarch64_CC="false" - - ;; - arm) - for ac_prog in armv7-w64-mingw32-clang armv7-w64-mingw32-gcc clang -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_arm_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$arm_CC"; then - ac_cv_prog_arm_CC="$arm_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_arm_CC="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -arm_CC=$ac_cv_prog_arm_CC -if test -n "$arm_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $arm_CC" >&5 -printf "%s\n" "$arm_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$arm_CC" && break -done -test -n "$arm_CC" || arm_CC="false" - - ;; - i386) - ac_prefix_list="i686-w64-mingw32-gcc i586-w64-mingw32-gcc i486-w64-mingw32-gcc i386-w64-mingw32-gcc i686-w64-mingw32-clang i586-w64-mingw32-clang i486-w64-mingw32-clang i386-w64-mingw32-clang " - for ac_prog in $ac_prefix_list clang -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_i386_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$i386_CC"; then - ac_cv_prog_i386_CC="$i386_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_i386_CC="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -i386_CC=$ac_cv_prog_i386_CC -if test -n "$i386_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $i386_CC" >&5 -printf "%s\n" "$i386_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$i386_CC" && break -done -test -n "$i386_CC" || i386_CC="false" - - ;; - x86_64) - ac_prefix_list="x86_64-w64-mingw32-gcc amd64-w64-mingw32-gcc x86_64-w64-mingw32-clang amd64-w64-mingw32-clang " - for ac_prog in $ac_prefix_list clang -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_x86_64_CC+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$x86_64_CC"; then - ac_cv_prog_x86_64_CC="$x86_64_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_x86_64_CC="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -x86_64_CC=$ac_cv_prog_x86_64_CC -if test -n "$x86_64_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $x86_64_CC" >&5 -printf "%s\n" "$x86_64_CC" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$x86_64_CC" && break -done -test -n "$x86_64_CC" || x86_64_CC="false" - - ;; - esac -fi - - if eval test \"x\$"${wine_arch}_CC"\" = x"false" -then : - continue -fi - - saved_CC=$CC - saved_CFLAGS=$CFLAGS - - CFLAGS=${CROSSCFLAGS:-"-g -O2"} - eval CC=\$${wine_arch}_CC - eval ${wine_arch}_CFLAGS=\$CFLAGS - eval ${wine_arch}_LDFLAGS=\$CROSSLDFLAGS - eval "${wine_arch}_EXTRACFLAGS=\"-D__WINE_PE_BUILD -Wall\"" - - target="" - as_wine_cv_crosscc=`printf "%s\n" "ac_cv_${wine_arch}_crosscc" | $as_tr_sh` - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC works" >&5 -printf %s "checking whether $CC works... " >&6; } -if eval test \${$as_wine_cv_crosscc+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$as_wine_cv_crosscc=yes" -else $as_nop - eval "$as_wine_cv_crosscc=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -eval ac_res=\$$as_wine_cv_crosscc - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } - if eval test \"x\$"$as_wine_cv_crosscc"\" = x"yes" -then : - set x $CC - shift - while test $# -ge 1 - do - case "$1" in - *-gcc) target=`expr "$1" : '\(.*\)-gcc'` ;; - *-clang) target=`expr "$1" : '\(.*\)-clang'` ;; - esac - shift - done - - llvm_target=$target - if test -z "$llvm_target" - then - case $wine_arch in - i386) llvm_target=i686-windows ;; - arm) llvm_target=armv7-windows ;; - *) llvm_target=$wine_arch-windows ;; - esac - fi - llvm_extra_cflags="-target $llvm_target -fuse-ld=lld" - case $llvm_target in - *windows) llvm_cflags="-Wl,-subsystem:console -Wl,-WX" ;; - esac - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_$llvm_extra_cflags $llvm_cflags" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports $llvm_extra_cflags $llvm_cflags" >&5 -printf %s "checking whether $CC supports $llvm_extra_cflags $llvm_cflags... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs $llvm_extra_cflags $llvm_cflags" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - target=$llvm_target - eval "${wine_arch}_DELAYLOADFLAG=\"-Wl,-delayload,\"" - as_fn_append ${wine_arch}_EXTRACFLAGS " $llvm_extra_cflags" - CFLAGS="$llvm_extra_cflags $llvm_cflags" -fi } - eval "${wine_arch}_TARGET=\$target" -fi - - - if test -z "$target" - then - CC=$saved_CC - CFLAGS=$saved_CFLAGS - continue - fi - as_fn_append PE_ARCHS " $wine_arch" - - as_wine_cv_crosscc_c99=`printf "%s\n" "ac_cv_${wine_arch}_crosscc_c99" | $as_tr_sh` - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 -printf %s "checking for $CC option to enable C99 features... " >&6; } - if eval test \${$as_wine_cv_crosscc_c99+y} -then : - printf %s "(cached) " >&6 -else $as_nop - eval "$as_wine_cv_crosscc_c99=no" - for arg in '' '-std=gnu99' - do - test -z "$arg" || CC="$CC $arg" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_c_conftest_c99_program -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - eval "$as_wine_cv_crosscc_c99=\$arg" -else $as_nop - eval "$as_wine_cv_crosscc_c99=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - eval CC=\$${wine_arch}_CC - if eval test \"x\$"$as_wine_cv_crosscc_c99"\" = x"no" -then : - -else $as_nop - break -fi - done -fi - - eval res=\$$as_wine_cv_crosscc_c99 - case "x$res" in - x) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } ;; - xno) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } ;; - x*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $res" >&5 -printf "%s\n" "$res" >&6; } - as_fn_append ${wine_arch}_CC " $res" ;; - esac - - - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-fno-strict-aliasing" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -fno-strict-aliasing" >&5 -printf %s "checking whether $CC supports -fno-strict-aliasing... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -fno-strict-aliasing" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -fno-strict-aliasing" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Werror=unknown-warning-option" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Werror=unknown-warning-option" >&5 -printf %s "checking whether $CC supports -Werror=unknown-warning-option... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Werror=unknown-warning-option" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - CFLAGS="$CFLAGS -Werror=unknown-warning-option" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Werror=ignored-optimization-argument" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Werror=ignored-optimization-argument" >&5 -printf %s "checking whether $CC supports -Werror=ignored-optimization-argument... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Werror=ignored-optimization-argument" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - CFLAGS="$CFLAGS -Werror=ignored-optimization-argument" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wdeclaration-after-statement" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wdeclaration-after-statement" >&5 -printf %s "checking whether $CC supports -Wdeclaration-after-statement... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wdeclaration-after-statement" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wdeclaration-after-statement" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wempty-body" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wempty-body" >&5 -printf %s "checking whether $CC supports -Wempty-body... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wempty-body" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wempty-body" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wignored-qualifiers" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wignored-qualifiers" >&5 -printf %s "checking whether $CC supports -Wignored-qualifiers... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wignored-qualifiers" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wignored-qualifiers" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Winit-self" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Winit-self" >&5 -printf %s "checking whether $CC supports -Winit-self... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Winit-self" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Winit-self" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wpacked-not-aligned" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wpacked-not-aligned" >&5 -printf %s "checking whether $CC supports -Wpacked-not-aligned... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wpacked-not-aligned" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wno-packed-not-aligned" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wpragma-pack" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wpragma-pack" >&5 -printf %s "checking whether $CC supports -Wpragma-pack... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wpragma-pack" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wno-pragma-pack" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wshift-overflow=2" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wshift-overflow=2" >&5 -printf %s "checking whether $CC supports -Wshift-overflow=2... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wshift-overflow=2" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wshift-overflow=2" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wstrict-prototypes" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wstrict-prototypes" >&5 -printf %s "checking whether $CC supports -Wstrict-prototypes... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wstrict-prototypes" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wstrict-prototypes" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wtype-limits" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wtype-limits" >&5 -printf %s "checking whether $CC supports -Wtype-limits... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wtype-limits" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wtype-limits" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wunused-but-set-parameter" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wunused-but-set-parameter" >&5 -printf %s "checking whether $CC supports -Wunused-but-set-parameter... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wunused-but-set-parameter" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wunused-but-set-parameter" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wvla" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wvla" >&5 -printf %s "checking whether $CC supports -Wvla... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wvla" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wvla" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wwrite-strings" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wwrite-strings" >&5 -printf %s "checking whether $CC supports -Wwrite-strings... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wwrite-strings" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wwrite-strings" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wpointer-arith" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wpointer-arith" >&5 -printf %s "checking whether $CC supports -Wpointer-arith... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wpointer-arith" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wpointer-arith" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wlogical-op" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wlogical-op" >&5 -printf %s "checking whether $CC supports -Wlogical-op... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wlogical-op" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wlogical-op" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wabsolute-value" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wabsolute-value" >&5 -printf %s "checking whether $CC supports -Wabsolute-value... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wabsolute-value" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wabsolute-value" -fi } - - case $wine_arch in - i386) { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-fno-omit-frame-pointer" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -fno-omit-frame-pointer" >&5 -printf %s "checking whether $CC supports -fno-omit-frame-pointer... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -fno-omit-frame-pointer" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -fno-omit-frame-pointer" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wl,--disable-stdcall-fixup" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wl,--disable-stdcall-fixup" >&5 -printf %s "checking whether $CC supports -Wl,--disable-stdcall-fixup... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wl,--disable-stdcall-fixup" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_LDFLAGS " -Wl,--disable-stdcall-fixup" -fi } ;; - x86_64) { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wformat-overflow" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wformat-overflow" >&5 -printf %s "checking whether $CC supports -Wformat-overflow... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wformat-overflow" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wformat-overflow" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wnonnull" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wnonnull" >&5 -printf %s "checking whether $CC supports -Wnonnull... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wnonnull" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Wnonnull" -fi } - { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-mcx16" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -mcx16" >&5 -printf %s "checking whether $CC supports -mcx16... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -mcx16" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -mcx16" -fi } ;; - esac - - wine_crossdebug=$CROSSDEBUG - if test -z "$wine_crossdebug" - then - for ac_flag in $CFLAGS; do - case $ac_flag in - -gdwarf*) wine_crossdebug=dwarf ;; - -gcodeview) wine_crossdebug=pdb ;; - -g) wine_crossdebug=${wine_crossdebug:-dwarf} ;; - esac - done - fi - - ac_debug_format_seen="" - for ac_flag in $CFLAGS; do - case $ac_flag in - -gdwarf*|-gcodeview) ac_debug_format_seen=$ac_flag ;; - esac - done - if test "x$ac_debug_format_seen" = x - then - case $wine_crossdebug in - *dwarf) { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-gdwarf-4" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -gdwarf-4" >&5 -printf %s "checking whether $CC supports -gdwarf-4... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -gdwarf-4" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -gdwarf-4" -fi } ;; - pdb) { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-gcodeview" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -gcodeview" >&5 -printf %s "checking whether $CC supports -gcodeview... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -gcodeview" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -gcodeview" -fi } ;; - esac - fi - eval "${wine_arch}_DEBUG=\$wine_crossdebug" - - test "x$enable_werror" != xyes || { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Werror" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Werror" >&5 -printf %s "checking whether $CC supports -Werror... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Werror" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_EXTRACFLAGS " -Werror" -fi } - test "x$enable_build_id" != xyes || { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wl,--build-id" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wl,--build-id" >&5 -printf %s "checking whether $CC supports -Wl,--build-id... " >&6; } -if eval test \${$as_ac_var+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -ac_wine_try_cflags_saved_exeext=$ac_exeext -CFLAGS="$CFLAGS -nostdlib -nodefaultlibs -Wl,--build-id" -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int __cdecl mainCRTStartup(void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - eval "$as_ac_var=yes" -else $as_nop - eval "$as_ac_var=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -ac_exeext=$ac_wine_try_cflags_saved_exeext -fi -eval ac_res=\$$as_ac_var - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_var"\" = x"yes" -then : - as_fn_append ${wine_arch}_CFLAGS " -Wl,--build-id" - as_fn_append ${wine_arch}_LDFLAGS " -Wl,--build-id" -fi } - - CC=$saved_CC - CFLAGS=$saved_CFLAGS -done - -if test $HOST_ARCH = aarch64 -a "x$PE_ARCHS" = x -then - as_fn_error $? "PE cross-compilation is required for ARM64, please install clang/llvm-dlltool/lld, or llvm-mingw." "$LINENO" 5 -fi - -if test "x$PE_ARCHS" = "x" -then : - case "x$with_mingw" in - x) as_fn_append wine_notices "|MinGW compiler not found, cross-compiling PE files won't be supported." ;; - xno) ;; - *) as_fn_error $? "MinGW compiler not found, cross-compiling PE files won't be supported. -This is an error since --with-mingw was requested." "$LINENO" 5 ;; -esac - -fi - - -if test "x$with_system_dllpath" != "x" -a -n "$PE_ARCHS" -then - case "$host_cpu" in - i[3456789]86*) - ac_prefix_list="i686-w64-mingw32-pkg-config i586-w64-mingw32-pkg-config i486-w64-mingw32-pkg-config i386-w64-mingw32-pkg-config " ;; - *) - ac_prefix_list="$host_cpu-w64-mingw32-pkg-config" ;; -esac -for ac_prog in $ac_prefix_list -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -printf %s "checking for $ac_word... " >&6; } -if test ${ac_cv_prog_MINGW_PKG_CONFIG+y} -then : - printf %s "(cached) " >&6 -else $as_nop - if test -n "$MINGW_PKG_CONFIG"; then - ac_cv_prog_MINGW_PKG_CONFIG="$MINGW_PKG_CONFIG" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then - ac_cv_prog_MINGW_PKG_CONFIG="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -MINGW_PKG_CONFIG=$ac_cv_prog_MINGW_PKG_CONFIG -if test -n "$MINGW_PKG_CONFIG"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MINGW_PKG_CONFIG" >&5 -printf "%s\n" "$MINGW_PKG_CONFIG" >&6; } -else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -fi - - - test -n "$MINGW_PKG_CONFIG" && break -done -test -n "$MINGW_PKG_CONFIG" || MINGW_PKG_CONFIG="false" - -if ${FAUDIO_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - FAUDIO_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags FAudio 2>/dev/null` -fi -fi -if ${FAUDIO_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - FAUDIO_PE_LIBS=`$MINGW_PKG_CONFIG --libs FAudio 2>/dev/null` -fi -fi -FAUDIO_PE_LIBS=${FAUDIO_PE_LIBS:-"-lFAudio"} -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $FAUDIO_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW FAudio.h" >&5 -printf %s "checking for MinGW FAudio.h... " >&6; } -if test ${ac_cv_mingw_header_FAudio_h+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_FAudio_h=yes -else $as_nop - ac_cv_mingw_header_FAudio_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_FAudio_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_FAudio_h" >&6; } -if test "x$ac_cv_mingw_header_FAudio_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for FAudio_CommitOperationSet in MinGW -lFAudio" >&5 -printf %s "checking for FAudio_CommitOperationSet in MinGW -lFAudio... " >&6; } -if test ${ac_cv_mingw_lib_FAudio+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-lFAudio $FAUDIO_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char FAudio_CommitOperationSet (); -int -main (void) -{ -return FAudio_CommitOperationSet (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_FAudio=yes -else $as_nop - ac_cv_mingw_lib_FAudio=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_FAudio" >&5 -printf "%s\n" "$ac_cv_mingw_lib_FAudio" >&6; } -if test "x$ac_cv_mingw_lib_FAudio" = xyes -then : - : -else $as_nop - FAUDIO_PE_CFLAGS=""; FAUDIO_PE_LIBS="" -fi -else $as_nop - FAUDIO_PE_CFLAGS=""; FAUDIO_PE_LIBS="" -fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$FAUDIO_PE_LIBS" = "x" - then - as_fn_append wine_notices "|FAudio ${notice_platform}MinGW development files not found (or too old); using bundled version." - fi - - if ${JPEG_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - JPEG_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags libjpeg 2>/dev/null` -fi -fi -if ${JPEG_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - JPEG_PE_LIBS=`$MINGW_PKG_CONFIG --libs libjpeg 2>/dev/null` -fi -fi - -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $JPEG_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW jpeglib.h" >&5 -printf %s "checking for MinGW jpeglib.h... " >&6; } -if test ${ac_cv_mingw_header_jpeglib_h+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - #include -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_jpeglib_h=yes -else $as_nop - ac_cv_mingw_header_jpeglib_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_jpeglib_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_jpeglib_h" >&6; } -if test "x$ac_cv_mingw_header_jpeglib_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for jpeg_start_decompress in MinGW -ljpeg" >&5 -printf %s "checking for jpeg_start_decompress in MinGW -ljpeg... " >&6; } -if test ${ac_cv_mingw_lib_jpeg+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-ljpeg $JPEG_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char jpeg_start_decompress (); -int -main (void) -{ -return jpeg_start_decompress (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_jpeg=yes -else $as_nop - ac_cv_mingw_lib_jpeg=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_jpeg" >&5 -printf "%s\n" "$ac_cv_mingw_lib_jpeg" >&6; } -if test "x$ac_cv_mingw_lib_jpeg" = xyes -then : - : -else $as_nop - JPEG_PE_CFLAGS=""; JPEG_PE_LIBS="" -fi -else $as_nop - JPEG_PE_CFLAGS=""; JPEG_PE_LIBS="" -fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$JPEG_PE_LIBS" = "x" - then - as_fn_append wine_notices "|libjpeg ${notice_platform}MinGW development files not found; using bundled version." - fi - - if ${LCMS2_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - LCMS2_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags lcms2 2>/dev/null` -fi -fi -if ${LCMS2_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - LCMS2_PE_LIBS=`$MINGW_PKG_CONFIG --libs lcms2 2>/dev/null` -fi -fi -LCMS2_PE_LIBS=${LCMS2_PE_LIBS:-"-llcms2"} -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $LCMS2_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW lcms2.h" >&5 -printf %s "checking for MinGW lcms2.h... " >&6; } -if test ${ac_cv_mingw_header_lcms2_h+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_lcms2_h=yes -else $as_nop - ac_cv_mingw_header_lcms2_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_lcms2_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_lcms2_h" >&6; } -if test "x$ac_cv_mingw_header_lcms2_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cmsOpenProfileFromFile in MinGW -llcms2" >&5 -printf %s "checking for cmsOpenProfileFromFile in MinGW -llcms2... " >&6; } -if test ${ac_cv_mingw_lib_lcms2+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-llcms2 $LCMS2_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char cmsOpenProfileFromFile (); -int -main (void) -{ -return cmsOpenProfileFromFile (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_lcms2=yes -else $as_nop - ac_cv_mingw_lib_lcms2=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_lcms2" >&5 -printf "%s\n" "$ac_cv_mingw_lib_lcms2" >&6; } -if test "x$ac_cv_mingw_lib_lcms2" = xyes -then : - : -else $as_nop - LCMS2_PE_CFLAGS=""; LCMS2_PE_LIBS="" -fi -else $as_nop - LCMS2_PE_CFLAGS=""; LCMS2_PE_LIBS="" -fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$LCMS2_PE_LIBS" = "x" - then - as_fn_append wine_notices "|liblcms2 ${notice_platform}MinGW development files not found; using bundled version." - fi - - if ${MPG123_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - MPG123_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags libmpg123 2>/dev/null` -fi -fi -if ${MPG123_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - MPG123_PE_LIBS=`$MINGW_PKG_CONFIG --libs libmpg123 2>/dev/null` -fi -fi -MPG123_PE_LIBS=${MPG123_PE_LIBS:-"-lmpg123"} -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $MPG123_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW mpg123.h" >&5 -printf %s "checking for MinGW mpg123.h... " >&6; } -if test ${ac_cv_mingw_header_mpg123_h+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_mpg123_h=yes -else $as_nop - ac_cv_mingw_header_mpg123_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_mpg123_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_mpg123_h" >&6; } -if test "x$ac_cv_mingw_header_mpg123_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mpg123_feed in MinGW -lmpg123" >&5 -printf %s "checking for mpg123_feed in MinGW -lmpg123... " >&6; } -if test ${ac_cv_mingw_lib_mpg123+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-lmpg123 $MPG123_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char mpg123_feed (); -int -main (void) -{ -return mpg123_feed (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_mpg123=yes -else $as_nop - ac_cv_mingw_lib_mpg123=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_mpg123" >&5 -printf "%s\n" "$ac_cv_mingw_lib_mpg123" >&6; } -if test "x$ac_cv_mingw_lib_mpg123" = xyes -then : - : -else $as_nop - MPG123_PE_CFLAGS=""; MPG123_PE_LIBS="" -fi -else $as_nop - MPG123_PE_CFLAGS=""; MPG123_PE_LIBS="" -fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$MPG123_PE_LIBS" = "x" - then - as_fn_append wine_notices "|libmpg123 ${notice_platform}MinGW development files not found (or too old); using bundled version." - fi - - if ${PNG_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - PNG_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags libpng 2>/dev/null` -fi -fi -if ${PNG_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - PNG_PE_LIBS=`$MINGW_PKG_CONFIG --libs libpng 2>/dev/null` -fi -fi - -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $PNG_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW png.h" >&5 -printf %s "checking for MinGW png.h... " >&6; } -if test ${ac_cv_mingw_header_png_h+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_png_h=yes -else $as_nop - ac_cv_mingw_header_png_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_png_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_png_h" >&6; } -if test "x$ac_cv_mingw_header_png_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for png_create_read_struct in MinGW -lpng" >&5 -printf %s "checking for png_create_read_struct in MinGW -lpng... " >&6; } -if test ${ac_cv_mingw_lib_png+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-lpng $PNG_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char png_create_read_struct (); -int -main (void) -{ -return png_create_read_struct (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_png=yes -else $as_nop - ac_cv_mingw_lib_png=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_png" >&5 -printf "%s\n" "$ac_cv_mingw_lib_png" >&6; } -if test "x$ac_cv_mingw_lib_png" = xyes -then : - : -else $as_nop - PNG_PE_CFLAGS=""; PNG_PE_LIBS="" -fi -else $as_nop - PNG_PE_CFLAGS=""; PNG_PE_LIBS="" -fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$PNG_PE_LIBS" = "x" - then - as_fn_append wine_notices "|libpng ${notice_platform}MinGW development files not found; using bundled version." - fi - - if ${TIFF_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - TIFF_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags libtiff-4 2>/dev/null` -fi -fi -if ${TIFF_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - TIFF_PE_LIBS=`$MINGW_PKG_CONFIG --libs libtiff-4 2>/dev/null` -fi -fi - -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $TIFF_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW tiffio.h" >&5 -printf %s "checking for MinGW tiffio.h... " >&6; } -if test ${ac_cv_mingw_header_tiffio_h+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_tiffio_h=yes -else $as_nop - ac_cv_mingw_header_tiffio_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_tiffio_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_tiffio_h" >&6; } -if test "x$ac_cv_mingw_header_tiffio_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for TIFFClientOpen in MinGW -ltiff" >&5 -printf %s "checking for TIFFClientOpen in MinGW -ltiff... " >&6; } -if test ${ac_cv_mingw_lib_tiff+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-ltiff $TIFF_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char TIFFClientOpen (); -int -main (void) -{ -return TIFFClientOpen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_tiff=yes -else $as_nop - ac_cv_mingw_lib_tiff=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_tiff" >&5 -printf "%s\n" "$ac_cv_mingw_lib_tiff" >&6; } -if test "x$ac_cv_mingw_lib_tiff" = xyes -then : - : -else $as_nop - TIFF_PE_CFLAGS=""; TIFF_PE_LIBS="" -fi -else $as_nop - TIFF_PE_CFLAGS=""; TIFF_PE_LIBS="" -fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$TIFF_PE_LIBS" = "x" - then - as_fn_append wine_notices "|libtiff ${notice_platform}MinGW development files not found; using bundled version." - fi - - if ${XML2_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - XML2_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags libxml-2.0 2>/dev/null` -fi -fi -if ${XML2_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - XML2_PE_LIBS=`$MINGW_PKG_CONFIG --libs libxml-2.0 2>/dev/null` -fi -fi -XML2_PE_LIBS=${XML2_PE_LIBS:-"-lxml2"} -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $XML2_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW libxml/parser.h" >&5 -printf %s "checking for MinGW libxml/parser.h... " >&6; } -if test ${ac_cv_mingw_header_libxml_parser_h+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_libxml_parser_h=yes -else $as_nop - ac_cv_mingw_header_libxml_parser_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_libxml_parser_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_libxml_parser_h" >&6; } -if test "x$ac_cv_mingw_header_libxml_parser_h" = xyes -then : - -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW libxml/xmlsave.h" >&5 -printf %s "checking for MinGW libxml/xmlsave.h... " >&6; } -if test ${ac_cv_mingw_header_libxml_xmlsave_h+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_libxml_xmlsave_h=yes -else $as_nop - ac_cv_mingw_header_libxml_xmlsave_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_libxml_xmlsave_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_libxml_xmlsave_h" >&6; } -if test "x$ac_cv_mingw_header_libxml_xmlsave_h" = xyes -then : - -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW libxml/SAX2.h" >&5 -printf %s "checking for MinGW libxml/SAX2.h... " >&6; } -if test ${ac_cv_mingw_header_libxml_SAX2_h+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_libxml_SAX2_h=yes -else $as_nop - ac_cv_mingw_header_libxml_SAX2_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_libxml_SAX2_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_libxml_SAX2_h" >&6; } -if test "x$ac_cv_mingw_header_libxml_SAX2_h" = xyes -then : - -fi - if test "$ac_cv_mingw_header_libxml_parser_h" = "yes" -a "$ac_cv_mingw_header_libxml_xmlsave_h" = "yes" -a "$ac_cv_mingw_header_libxml_SAX2_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for xmlFirstElementChild in MinGW -lxml2" >&5 -printf %s "checking for xmlFirstElementChild in MinGW -lxml2... " >&6; } -if test ${ac_cv_mingw_lib_xml2+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-lxml2 $XML2_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char xmlFirstElementChild (); -int -main (void) -{ -return xmlFirstElementChild (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_xml2=yes -else $as_nop - ac_cv_mingw_lib_xml2=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_xml2" >&5 -printf "%s\n" "$ac_cv_mingw_lib_xml2" >&6; } -if test "x$ac_cv_mingw_lib_xml2" = xyes -then : - : -else $as_nop - XML2_PE_CFLAGS=""; XML2_PE_LIBS="" -fi - else - XML2_PE_CFLAGS="" - XML2_PE_LIBS="" - fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$XML2_PE_LIBS" = "x" - then - as_fn_append wine_notices "|libxml2 ${notice_platform}MinGW development files not found (or too old); using bundled version." - fi - - if ${XSLT_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - XSLT_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags libxslt 2>/dev/null` -fi -fi -if ${XSLT_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - XSLT_PE_LIBS=`$MINGW_PKG_CONFIG --libs libxslt 2>/dev/null` -fi -fi -XSLT_PE_LIBS=${XSLT_PE_LIBS:-"-lxslt"} -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $XSLT_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW libxslt/pattern.h" >&5 -printf %s "checking for MinGW libxslt/pattern.h... " >&6; } -if test ${ac_cv_mingw_header_libxslt_pattern_h+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_libxslt_pattern_h=yes -else $as_nop - ac_cv_mingw_header_libxslt_pattern_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_libxslt_pattern_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_libxslt_pattern_h" >&6; } -if test "x$ac_cv_mingw_header_libxslt_pattern_h" = xyes -then : - -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW libxslt/transform.h" >&5 -printf %s "checking for MinGW libxslt/transform.h... " >&6; } -if test ${ac_cv_mingw_header_libxslt_transform_h+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_libxslt_transform_h=yes -else $as_nop - ac_cv_mingw_header_libxslt_transform_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_libxslt_transform_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_libxslt_transform_h" >&6; } -if test "x$ac_cv_mingw_header_libxslt_transform_h" = xyes -then : - -fi - if test "$ac_cv_mingw_header_libxslt_pattern_h" = "yes" -a "$ac_cv_mingw_header_libxslt_transform_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for xsltCompilePattern in MinGW -lxslt" >&5 -printf %s "checking for xsltCompilePattern in MinGW -lxslt... " >&6; } -if test ${ac_cv_mingw_lib_xslt+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-lxslt $XSLT_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char xsltCompilePattern (); -int -main (void) -{ -return xsltCompilePattern (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_xslt=yes -else $as_nop - ac_cv_mingw_lib_xslt=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_xslt" >&5 -printf "%s\n" "$ac_cv_mingw_lib_xslt" >&6; } -if test "x$ac_cv_mingw_lib_xslt" = xyes -then : - : -else $as_nop - XSLT_PE_CFLAGS=""; XSLT_PE_LIBS="" -fi - else - XSLT_PE_CFLAGS="" - XSLT_PE_LIBS="" - fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$XSLT_PE_LIBS" = "x" - then - as_fn_append wine_notices "|libxslt ${notice_platform}MinGW development files not found; using bundled version." - fi - - if ${VKD3D_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - VKD3D_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags libvkd3d libvkd3d-shader 2>/dev/null` -fi -fi -if ${VKD3D_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - VKD3D_PE_LIBS=`$MINGW_PKG_CONFIG --libs libvkd3d libvkd3d-shader 2>/dev/null` -fi -fi -VKD3D_PE_LIBS=${VKD3D_PE_LIBS:-"-lvkd3d -lvkd3d-shader"} -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $VKD3D_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW vkd3d.h" >&5 -printf %s "checking for MinGW vkd3d.h... " >&6; } -if test ${ac_cv_mingw_header_vkd3d_h+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_vkd3d_h=yes -else $as_nop - ac_cv_mingw_header_vkd3d_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_vkd3d_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_vkd3d_h" >&6; } -if test "x$ac_cv_mingw_header_vkd3d_h" = xyes -then : - -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW vkd3d_shader.h" >&5 -printf %s "checking for MinGW vkd3d_shader.h... " >&6; } -if test ${ac_cv_mingw_header_vkd3d_shader_h+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_vkd3d_shader_h=yes -else $as_nop - ac_cv_mingw_header_vkd3d_shader_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_vkd3d_shader_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_vkd3d_shader_h" >&6; } -if test "x$ac_cv_mingw_header_vkd3d_shader_h" = xyes -then : - -fi - if test "$ac_cv_mingw_header_vkd3d_h" = "yes" -a "$ac_cv_mingw_header_vkd3d_shader_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for vkd3d_set_log_callback in MinGW -lvkd3d" >&5 -printf %s "checking for vkd3d_set_log_callback in MinGW -lvkd3d... " >&6; } -if test ${ac_cv_mingw_lib_vkd3d+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-lvkd3d $VKD3D_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char vkd3d_set_log_callback (); -int -main (void) -{ -return vkd3d_set_log_callback (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_vkd3d=yes -else $as_nop - ac_cv_mingw_lib_vkd3d=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_vkd3d" >&5 -printf "%s\n" "$ac_cv_mingw_lib_vkd3d" >&6; } -if test "x$ac_cv_mingw_lib_vkd3d" = xyes -then : - : -else $as_nop - : -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for vkd3d_shader_compile in MinGW -lvkd3d-shader" >&5 -printf %s "checking for vkd3d_shader_compile in MinGW -lvkd3d-shader... " >&6; } -if test ${ac_cv_mingw_lib_vkd3d_shader+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-lvkd3d-shader $VKD3D_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char vkd3d_shader_compile (); -int -main (void) -{ -return vkd3d_shader_compile (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_vkd3d_shader=yes -else $as_nop - ac_cv_mingw_lib_vkd3d_shader=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_vkd3d_shader" >&5 -printf "%s\n" "$ac_cv_mingw_lib_vkd3d_shader" >&6; } -if test "x$ac_cv_mingw_lib_vkd3d_shader" = xyes -then : - : -else $as_nop - : -fi - if test "$ac_cv_mingw_lib_vkd3d" = "no" -o "$ac_cv_mingw_lib_vkd3d_shader" = "no" - then - VKD3D_PE_CFLAGS="" - VKD3D_PE_LIBS="" - fi - else - VKD3D_PE_CFLAGS="" - VKD3D_PE_LIBS="" - fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$VKD3D_PE_LIBS" = "x" - then - as_fn_append wine_notices "|libvkd3d ${notice_platform}MinGW development files not found (or too old); using bundled version." - fi - - if ${ZLIB_PE_CFLAGS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - ZLIB_PE_CFLAGS=`$MINGW_PKG_CONFIG --cflags zlib 2>/dev/null` -fi -fi -if ${ZLIB_PE_LIBS:+false} : -then : - if test ${MINGW_PKG_CONFIG+y} -then : - ZLIB_PE_LIBS=`$MINGW_PKG_CONFIG --libs zlib 2>/dev/null` -fi -fi -ZLIB_PE_LIBS=${ZLIB_PE_LIBS:-"-lz"} -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $ZLIB_PE_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MinGW zlib.h" >&5 -printf %s "checking for MinGW zlib.h... " >&6; } -if test ${ac_cv_mingw_header_zlib_h+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mingw_header_zlib_h=yes -else $as_nop - ac_cv_mingw_header_zlib_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_header_zlib_h" >&5 -printf "%s\n" "$ac_cv_mingw_header_zlib_h" >&6; } -if test "x$ac_cv_mingw_header_zlib_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inflate in MinGW -lz" >&5 -printf %s "checking for inflate in MinGW -lz... " >&6; } -if test ${ac_cv_mingw_lib_z+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_check_headers_saved_cc=$CC -ac_wine_check_headers_saved_exeext=$ac_exeext -ac_wine_check_headers_saved_libs=$LIBS -eval CC=\$${wine_arch}_CC -ac_exeext=".exe" -LIBS="-lz $ZLIB_PE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char inflate (); -int -main (void) -{ -return inflate (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_mingw_lib_z=yes -else $as_nop - ac_cv_mingw_lib_z=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CC=$ac_wine_check_headers_saved_cc -ac_exeext=$ac_wine_check_headers_saved_exeext -LIBS=$ac_wine_check_headers_saved_libs -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_z" >&5 -printf "%s\n" "$ac_cv_mingw_lib_z" >&6; } -if test "x$ac_cv_mingw_lib_z" = xyes -then : - : -else $as_nop - ZLIB_PE_CFLAGS=""; ZLIB_PE_LIBS="" -fi -else $as_nop - ZLIB_PE_CFLAGS=""; ZLIB_PE_LIBS="" -fi -CPPFLAGS=$ac_save_CPPFLAGS - - if test "x$ZLIB_PE_LIBS" = "x" - then - as_fn_append wine_notices "|zlib ${notice_platform}MinGW development files not found; using bundled version." - fi -fi - -if ${FAUDIO_PE_LIBS:+false} : -then : - FAUDIO_PE_LIBS="faudio mfplat mfreadwrite mfuuid propsys" - if ${FAUDIO_PE_CFLAGS:+false} : -then : - FAUDIO_PE_CFLAGS="-I\$(top_srcdir)/libs/faudio/include" -else $as_nop - enable_faudio=no -fi -else $as_nop - enable_faudio=no -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: faudio cflags: $FAUDIO_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: faudio libs: $FAUDIO_PE_LIBS" >&5 - -if ${GSM_PE_LIBS:+false} : -then : - GSM_PE_LIBS=gsm - if ${GSM_PE_CFLAGS:+false} : -then : - GSM_PE_CFLAGS="-I\$(top_srcdir)/libs/gsm/inc" -else $as_nop - enable_gsm=no -fi -else $as_nop - enable_gsm=no -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: gsm cflags: $GSM_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: gsm libs: $GSM_PE_LIBS" >&5 - -if ${JPEG_PE_LIBS:+false} : -then : - JPEG_PE_LIBS=jpeg - if ${JPEG_PE_CFLAGS:+false} : -then : - JPEG_PE_CFLAGS="-I\$(top_srcdir)/libs/jpeg" -else $as_nop - enable_jpeg=no -fi -else $as_nop - enable_jpeg=no -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: jpeg cflags: $JPEG_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: jpeg libs: $JPEG_PE_LIBS" >&5 - -if ${JXR_PE_LIBS:+false} : -then : - JXR_PE_LIBS=jxr - if ${JXR_PE_CFLAGS:+false} : -then : - JXR_PE_CFLAGS="-I\$(top_srcdir)/libs/jxr/jxrgluelib -I\$(top_srcdir)/libs/jxr/image/sys" -else $as_nop - enable_jxr=no -fi -else $as_nop - enable_jxr=no -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: jxr cflags: $JXR_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: jxr libs: $JXR_PE_LIBS" >&5 - -if ${LCMS2_PE_LIBS:+false} : -then : - LCMS2_PE_LIBS=lcms2 - if ${LCMS2_PE_CFLAGS:+false} : -then : - LCMS2_PE_CFLAGS="-I\$(top_srcdir)/libs/lcms2/include" -else $as_nop - enable_lcms2=no -fi -else $as_nop - enable_lcms2=no -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: lcms2 cflags: $LCMS2_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: lcms2 libs: $LCMS2_PE_LIBS" >&5 - -if ${LDAP_PE_LIBS:+false} : -then : - LDAP_PE_LIBS=ldap - if ${LDAP_PE_CFLAGS:+false} : -then : - LDAP_PE_CFLAGS="-I\$(top_srcdir)/libs/ldap/include" -else $as_nop - enable_ldap=no -fi -else $as_nop - enable_ldap=no -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: ldap cflags: $LDAP_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: ldap libs: $LDAP_PE_LIBS" >&5 - -if ${MPG123_PE_LIBS:+false} : -then : - MPG123_PE_LIBS=mpg123 - if ${MPG123_PE_CFLAGS:+false} : -then : - MPG123_PE_CFLAGS="-I\$(top_srcdir)/libs/mpg123/src/libmpg123" -else $as_nop - enable_mpg123=no -fi -else $as_nop - enable_mpg123=no -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: mpg123 cflags: $MPG123_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: mpg123 libs: $MPG123_PE_LIBS" >&5 - -if ${PNG_PE_LIBS:+false} : -then : - PNG_PE_LIBS="png \$(ZLIB_PE_LIBS)" - if ${PNG_PE_CFLAGS:+false} : -then : - PNG_PE_CFLAGS="-I\$(top_srcdir)/libs/png" -else $as_nop - enable_png=no -fi -else $as_nop - enable_png=no -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: png cflags: $PNG_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: png libs: $PNG_PE_LIBS" >&5 - -if ${TIFF_PE_LIBS:+false} : -then : - TIFF_PE_LIBS="tiff \$(ZLIB_PE_LIBS)" - if ${TIFF_PE_CFLAGS:+false} : -then : - TIFF_PE_CFLAGS="-I\$(top_srcdir)/libs/tiff/libtiff" -else $as_nop - enable_tiff=no -fi -else $as_nop - enable_tiff=no -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: tiff cflags: $TIFF_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: tiff libs: $TIFF_PE_LIBS" >&5 - -if ${VKD3D_PE_LIBS:+false} : -then : - VKD3D_PE_LIBS=vkd3d - if ${VKD3D_PE_CFLAGS:+false} : -then : - VKD3D_PE_CFLAGS="-I\$(top_srcdir)/libs/vkd3d/include" -else $as_nop - enable_vkd3d=no -fi -else $as_nop - enable_vkd3d=no -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: vkd3d cflags: $VKD3D_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: vkd3d libs: $VKD3D_PE_LIBS" >&5 - -if ${XML2_PE_LIBS:+false} : -then : - XML2_PE_LIBS=xml2 - if ${XML2_PE_CFLAGS:+false} : -then : - XML2_PE_CFLAGS="-I\$(top_srcdir)/libs/xml2/include -DLIBXML_STATIC" -else $as_nop - enable_xml2=no -fi -else $as_nop - enable_xml2=no -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: xml2 cflags: $XML2_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: xml2 libs: $XML2_PE_LIBS" >&5 - -if ${XSLT_PE_LIBS:+false} : -then : - XSLT_PE_LIBS=xslt - if ${XSLT_PE_CFLAGS:+false} : -then : - XSLT_PE_CFLAGS="-I\$(top_srcdir)/libs/xslt/libxslt -I\$(top_srcdir)/libs/xslt -DLIBXSLT_STATIC" -else $as_nop - enable_xslt=no -fi -else $as_nop - enable_xslt=no -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: xslt cflags: $XSLT_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: xslt libs: $XSLT_PE_LIBS" >&5 - -if ${ZLIB_PE_LIBS:+false} : -then : - ZLIB_PE_LIBS=z - if ${ZLIB_PE_CFLAGS:+false} : -then : - ZLIB_PE_CFLAGS="-I\$(top_srcdir)/libs/zlib -DFAR= -DZ_SOLO" -else $as_nop - enable_zlib=no -fi -else $as_nop - enable_zlib=no -fi -printf "%s\n" "$as_me:${as_lineno-$LINENO}: zlib cflags: $ZLIB_PE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: zlib libs: $ZLIB_PE_LIBS" >&5 - - - -if test "$ac_cv_header_pthread_h" = "yes" -then - ac_fn_c_check_func "$LINENO" "pthread_create" "ac_cv_func_pthread_create" -if test "x$ac_cv_func_pthread_create" = xyes -then : - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 -printf %s "checking for pthread_create in -lpthread... " >&6; } -if test ${ac_cv_lib_pthread_pthread_create+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lpthread $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char pthread_create (); -int -main (void) -{ -return pthread_create (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_pthread_pthread_create=yes -else $as_nop - ac_cv_lib_pthread_pthread_create=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 -printf "%s\n" "$ac_cv_lib_pthread_pthread_create" >&6; } -if test "x$ac_cv_lib_pthread_pthread_create" = xyes -then : - PTHREAD_LIBS="-lpthread" - -fi - -fi - -fi -if test "x$ac_cv_func_pthread_create" != xyes -a "x$PTHREAD_LIBS" = x -then : - case "x$with_pthread" in - xno) ;; - *) as_fn_error $? "pthread ${notice_platform}development files not found. -Wine cannot support threads without libpthread. -Use the --without-pthread option if you really want this." "$LINENO" 5 ;; -esac - -fi - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -printf %s "checking how to run the C preprocessor... " >&6; } -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then - if test ${ac_cv_prog_CPP+y} -then : - printf %s "(cached) " >&6 -else $as_nop - # Double quotes because $CC needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp - do - ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO" -then : - -else $as_nop - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO" -then : - # Broken: success on invalid input. -continue -else $as_nop - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok -then : - break -fi - - done - ac_cv_prog_CPP=$CPP - -fi - CPP=$ac_cv_prog_CPP -else - ac_cv_prog_CPP=$CPP -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -printf "%s\n" "$CPP" >&6; } -ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO" -then : - -else $as_nop - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO" -then : - # Broken: success on invalid input. -continue -else $as_nop - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok -then : - -else $as_nop - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for X" >&5 -printf %s "checking for X... " >&6; } - - -# Check whether --with-x was given. -if test ${with_x+y} -then : - withval=$with_x; -fi - -# $have_x is `yes', `no', `disabled', or empty when we do not yet know. -if test "x$with_x" = xno; then - # The user explicitly disabled X. - have_x=disabled -else - case $x_includes,$x_libraries in #( - *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #( - *,NONE | NONE,*) if test ${ac_cv_have_x+y} -then : - printf %s "(cached) " >&6 -else $as_nop - # One or both of the vars are not set, and there is no cached value. -ac_x_includes=no -ac_x_libraries=no -# Do we need to do anything special at all? -ac_save_LIBS=$LIBS -LIBS="-lX11 $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -XrmInitialize () - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - # We can compile and link X programs with no special options. - ac_x_includes= - ac_x_libraries= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS="$ac_save_LIBS" -# If that didn't work, only try xmkmf and file system searches -# for native compilation. -if test x"$ac_x_includes" = xno && test "$cross_compiling" = no -then : - rm -f -r conftest.dir -if mkdir conftest.dir; then - cd conftest.dir - cat >Imakefile <<'_ACEOF' -incroot: - @echo incroot='${INCROOT}' -usrlibdir: - @echo usrlibdir='${USRLIBDIR}' -libdir: - @echo libdir='${LIBDIR}' -_ACEOF - if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then - # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. - for ac_var in incroot usrlibdir libdir; do - eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" - done - # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. - for ac_extension in a so sl dylib la dll; do - if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && - test -f "$ac_im_libdir/libX11.$ac_extension"; then - ac_im_usrlibdir=$ac_im_libdir; break - fi - done - # Screen out bogus values from the imake configuration. They are - # bogus both because they are the default anyway, and because - # using them would break gcc on systems where it needs fixed includes. - case $ac_im_incroot in - /usr/include) ac_x_includes= ;; - *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; - esac - case $ac_im_usrlibdir in - /usr/lib | /usr/lib64 | /lib | /lib64) ;; - *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; - esac - fi - cd .. - rm -f -r conftest.dir -fi - - # Standard set of common directories for X headers. -# Check X11 before X11Rn because it is often a symlink to the current release. -ac_x_header_dirs=' -/usr/X11/include -/usr/X11R7/include -/usr/X11R6/include -/usr/X11R5/include -/usr/X11R4/include - -/usr/include/X11 -/usr/include/X11R7 -/usr/include/X11R6 -/usr/include/X11R5 -/usr/include/X11R4 - -/usr/local/X11/include -/usr/local/X11R7/include -/usr/local/X11R6/include -/usr/local/X11R5/include -/usr/local/X11R4/include - -/usr/local/include/X11 -/usr/local/include/X11R7 -/usr/local/include/X11R6 -/usr/local/include/X11R5 -/usr/local/include/X11R4 - -/opt/X11/include - -/usr/X386/include -/usr/x386/include -/usr/XFree86/include/X11 - -/usr/include -/usr/local/include -/usr/unsupported/include -/usr/athena/include -/usr/local/x11r5/include -/usr/lpp/Xamples/include - -/usr/openwin/include -/usr/openwin/share/include' - -if test "$ac_x_includes" = no; then - # Guess where to find include files, by looking for Xlib.h. - # First, try using that file with no special directory specified. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO" -then : - # We can compile using X headers with no special include directory. -ac_x_includes= -else $as_nop - for ac_dir in $ac_x_header_dirs; do - if test -r "$ac_dir/X11/Xlib.h"; then - ac_x_includes=$ac_dir - break - fi -done -fi -rm -f conftest.err conftest.i conftest.$ac_ext -fi # $ac_x_includes = no - -if test "$ac_x_libraries" = no; then - # Check for the libraries. - # See if we find them without any special options. - # Don't add to $LIBS permanently. - ac_save_LIBS=$LIBS - LIBS="-lX11 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -XrmInitialize () - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - LIBS=$ac_save_LIBS -# We can link X programs with no special library path. -ac_x_libraries= -else $as_nop - LIBS=$ac_save_LIBS -for ac_dir in `printf "%s\n" "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` -do - # Don't even attempt the hair of trying to link an X program! - for ac_extension in a so sl dylib la dll; do - if test -r "$ac_dir/libX11.$ac_extension"; then - ac_x_libraries=$ac_dir - break 2 - fi - done -done -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -fi # $ac_x_libraries = no - -fi -# Record the results. -case $ac_x_includes,$ac_x_libraries in #( - no,* | *,no | *\'*) : - # Didn't find X, or a directory has "'" in its name. - ac_cv_have_x="have_x=no" ;; #( - *) : - # Record where we found X for the cache. - ac_cv_have_x="have_x=yes\ - ac_x_includes='$ac_x_includes'\ - ac_x_libraries='$ac_x_libraries'" ;; -esac -fi -;; #( - *) have_x=yes;; - esac - eval "$ac_cv_have_x" -fi # $with_x != no - -if test "$have_x" != yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 -printf "%s\n" "$have_x" >&6; } - no_x=yes -else - # If each of the values was on the command line, it overrides each guess. - test "x$x_includes" = xNONE && x_includes=$ac_x_includes - test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries - # Update the cache value to reflect the command line values. - ac_cv_have_x="have_x=yes\ - ac_x_includes='$x_includes'\ - ac_x_libraries='$x_libraries'" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 -printf "%s\n" "libraries $x_libraries, headers $x_includes" >&6; } -fi - -if test "$no_x" = yes; then - # Not all programs may use this symbol, but it does not hurt to define it. - -printf "%s\n" "#define X_DISPLAY_MISSING 1" >>confdefs.h - - X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= -else - if test -n "$x_includes"; then - X_CFLAGS="$X_CFLAGS -I$x_includes" - fi - - # It would also be nice to do this for all -L options, not just this one. - if test -n "$x_libraries"; then - X_LIBS="$X_LIBS -L$x_libraries" - # For Solaris; some versions of Sun CC require a space after -R and - # others require no space. Words are not sufficient . . . . - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -R must be followed by a space" >&5 -printf %s "checking whether -R must be followed by a space... " >&6; } - ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries" - ac_xsave_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - X_LIBS="$X_LIBS -R$x_libraries" -else $as_nop - LIBS="$ac_xsave_LIBS -R $x_libraries" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } - X_LIBS="$X_LIBS -R $x_libraries" -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: neither works" >&5 -printf "%s\n" "neither works" >&6; } -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - ac_c_werror_flag=$ac_xsave_c_werror_flag - LIBS=$ac_xsave_LIBS - fi - - # Check for system-dependent libraries X programs must link with. - # Do this before checking for the system-independent R6 libraries - # (-lICE), since we may need -lsocket or whatever for X linking. - - if test "$ISC" = yes; then - X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" - else - # Martyn Johnson says this is needed for Ultrix, if the X - # libraries were built with DECnet support. And Karl Berry says - # the Alpha needs dnet_stub (dnet does not exist). - ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char XOpenDisplay (); -int -main (void) -{ -return XOpenDisplay (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5 -printf %s "checking for dnet_ntoa in -ldnet... " >&6; } -if test ${ac_cv_lib_dnet_dnet_ntoa+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldnet $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char dnet_ntoa (); -int -main (void) -{ -return dnet_ntoa (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dnet_dnet_ntoa=yes -else $as_nop - ac_cv_lib_dnet_dnet_ntoa=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5 -printf "%s\n" "$ac_cv_lib_dnet_dnet_ntoa" >&6; } -if test "x$ac_cv_lib_dnet_dnet_ntoa" = xyes -then : - X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" -fi - - if test $ac_cv_lib_dnet_dnet_ntoa = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5 -printf %s "checking for dnet_ntoa in -ldnet_stub... " >&6; } -if test ${ac_cv_lib_dnet_stub_dnet_ntoa+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldnet_stub $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char dnet_ntoa (); -int -main (void) -{ -return dnet_ntoa (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_dnet_stub_dnet_ntoa=yes -else $as_nop - ac_cv_lib_dnet_stub_dnet_ntoa=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5 -printf "%s\n" "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; } -if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = xyes -then : - X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" -fi - - fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS="$ac_xsave_LIBS" - - # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, - # to get the SysV transport functions. - # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4) - # needs -lnsl. - # The nsl library prevents programs from opening the X display - # on Irix 5.2, according to T.E. Dickey. - # The functions gethostbyname, getservbyname, and inet_addr are - # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking. - ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" -if test "x$ac_cv_func_gethostbyname" = xyes -then : - -fi - - if test $ac_cv_func_gethostbyname = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 -printf %s "checking for gethostbyname in -lnsl... " >&6; } -if test ${ac_cv_lib_nsl_gethostbyname+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lnsl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char gethostbyname (); -int -main (void) -{ -return gethostbyname (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_nsl_gethostbyname=yes -else $as_nop - ac_cv_lib_nsl_gethostbyname=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 -printf "%s\n" "$ac_cv_lib_nsl_gethostbyname" >&6; } -if test "x$ac_cv_lib_nsl_gethostbyname" = xyes -then : - X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" -fi - - if test $ac_cv_lib_nsl_gethostbyname = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5 -printf %s "checking for gethostbyname in -lbsd... " >&6; } -if test ${ac_cv_lib_bsd_gethostbyname+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lbsd $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char gethostbyname (); -int -main (void) -{ -return gethostbyname (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_bsd_gethostbyname=yes -else $as_nop - ac_cv_lib_bsd_gethostbyname=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5 -printf "%s\n" "$ac_cv_lib_bsd_gethostbyname" >&6; } -if test "x$ac_cv_lib_bsd_gethostbyname" = xyes -then : - X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" -fi - - fi - fi - - # lieder@skyler.mavd.honeywell.com says without -lsocket, - # socket/setsockopt and other routines are undefined under SCO ODT - # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary - # on later versions), says Simon Leinen: it contains gethostby* - # variants that don't use the name server (or something). -lsocket - # must be given before -lnsl if both are needed. We assume that - # if connect needs -lnsl, so does gethostbyname. - ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" -if test "x$ac_cv_func_connect" = xyes -then : - -fi - - if test $ac_cv_func_connect = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 -printf %s "checking for connect in -lsocket... " >&6; } -if test ${ac_cv_lib_socket_connect+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsocket $X_EXTRA_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char connect (); -int -main (void) -{ -return connect (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_socket_connect=yes -else $as_nop - ac_cv_lib_socket_connect=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5 -printf "%s\n" "$ac_cv_lib_socket_connect" >&6; } -if test "x$ac_cv_lib_socket_connect" = xyes -then : - X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" -fi - - fi - - # Guillermo Gomez says -lposix is necessary on A/UX. - ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove" -if test "x$ac_cv_func_remove" = xyes -then : - -fi - - if test $ac_cv_func_remove = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5 -printf %s "checking for remove in -lposix... " >&6; } -if test ${ac_cv_lib_posix_remove+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lposix $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char remove (); -int -main (void) -{ -return remove (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_posix_remove=yes -else $as_nop - ac_cv_lib_posix_remove=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5 -printf "%s\n" "$ac_cv_lib_posix_remove" >&6; } -if test "x$ac_cv_lib_posix_remove" = xyes -then : - X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" -fi - - fi - - # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. - ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat" -if test "x$ac_cv_func_shmat" = xyes -then : - -fi - - if test $ac_cv_func_shmat = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5 -printf %s "checking for shmat in -lipc... " >&6; } -if test ${ac_cv_lib_ipc_shmat+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lipc $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char shmat (); -int -main (void) -{ -return shmat (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_ipc_shmat=yes -else $as_nop - ac_cv_lib_ipc_shmat=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5 -printf "%s\n" "$ac_cv_lib_ipc_shmat" >&6; } -if test "x$ac_cv_lib_ipc_shmat" = xyes -then : - X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" -fi - - fi - fi - - # Check for libraries that X11R6 Xt/Xaw programs need. - ac_save_LDFLAGS=$LDFLAGS - test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" - # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to - # check for ICE first), but we must link in the order -lSM -lICE or - # we get undefined symbols. So assume we have SM if we have ICE. - # These have to be linked with before -lX11, unlike the other - # libraries we check for below, so use a different variable. - # John Interrante, Karl Berry - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5 -printf %s "checking for IceConnectionNumber in -lICE... " >&6; } -if test ${ac_cv_lib_ICE_IceConnectionNumber+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lICE $X_EXTRA_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char IceConnectionNumber (); -int -main (void) -{ -return IceConnectionNumber (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_ICE_IceConnectionNumber=yes -else $as_nop - ac_cv_lib_ICE_IceConnectionNumber=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5 -printf "%s\n" "$ac_cv_lib_ICE_IceConnectionNumber" >&6; } -if test "x$ac_cv_lib_ICE_IceConnectionNumber" = xyes -then : - X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" -fi - - LDFLAGS=$ac_save_LDFLAGS - -fi - - -if test "$have_x" = "yes" -then - ac_save_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$CPPFLAGS $X_CFLAGS" - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lX11" >&5 -printf %s "checking for -lX11... " >&6; } -if test ${ac_cv_lib_soname_X11+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lX11 $X_LIBS $X_EXTRA_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char XCreateWindow (); -int -main (void) -{ -return XCreateWindow (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_X11=`$ac_cv_path_LDD conftest.exe | grep "X11" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_X11=`$OTOOL -L conftest$ac_exeext | grep "libX11\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libX11\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_X11=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libX11\\.$LIBEXT" | sed -e "s/^.*\\[\\(libX11\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_X11:+false} : -then : - ac_cv_lib_soname_X11=`$LDD conftest$ac_exeext | grep "libX11\\.$LIBEXT" | sed -e "s/^.*\(libX11\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_X11= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_X11:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_X11" >&5 -printf "%s\n" "$ac_cv_lib_soname_X11" >&6; } - -printf "%s\n" "#define SONAME_LIBX11 \"$ac_cv_lib_soname_X11\"" >>confdefs.h - - -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXext" >&5 -printf %s "checking for -lXext... " >&6; } -if test ${ac_cv_lib_soname_Xext+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lXext $X_LIBS -lX11 $X_EXTRA_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char XextCreateExtension (); -int -main (void) -{ -return XextCreateExtension (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xext=`$ac_cv_path_LDD conftest.exe | grep "Xext" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xext=`$OTOOL -L conftest$ac_exeext | grep "libXext\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXext\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xext=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXext\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXext\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xext:+false} : -then : - ac_cv_lib_soname_Xext=`$LDD conftest$ac_exeext | grep "libXext\\.$LIBEXT" | sed -e "s/^.*\(libXext\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_Xext= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_Xext:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xext" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xext" >&6; } - -printf "%s\n" "#define SONAME_LIBXEXT \"$ac_cv_lib_soname_Xext\"" >>confdefs.h - - X_LIBS="$X_LIBS -lXext" -fi - X_LIBS="$X_LIBS -lX11" - - ac_fn_c_check_header_compile "$LINENO" "X11/Xlib.h" "ac_cv_header_X11_Xlib_h" "#ifdef HAVE_X11_XLIB_H -# include -#endif -#ifdef HAVE_X11_XUTIL_H -# include -#endif -" -if test "x$ac_cv_header_X11_Xlib_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_XLIB_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/XKBlib.h" "ac_cv_header_X11_XKBlib_h" "#ifdef HAVE_X11_XLIB_H -# include -#endif -#ifdef HAVE_X11_XUTIL_H -# include -#endif -" -if test "x$ac_cv_header_X11_XKBlib_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_XKBLIB_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/Xutil.h" "ac_cv_header_X11_Xutil_h" "#ifdef HAVE_X11_XLIB_H -# include -#endif -#ifdef HAVE_X11_XUTIL_H -# include -#endif -" -if test "x$ac_cv_header_X11_Xutil_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_XUTIL_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/Xcursor/Xcursor.h" "ac_cv_header_X11_Xcursor_Xcursor_h" "#ifdef HAVE_X11_XLIB_H -# include -#endif -#ifdef HAVE_X11_XUTIL_H -# include -#endif -" -if test "x$ac_cv_header_X11_Xcursor_Xcursor_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_XCURSOR_XCURSOR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/shape.h" "ac_cv_header_X11_extensions_shape_h" "#ifdef HAVE_X11_XLIB_H -# include -#endif -#ifdef HAVE_X11_XUTIL_H -# include -#endif -" -if test "x$ac_cv_header_X11_extensions_shape_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_SHAPE_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/XInput.h" "ac_cv_header_X11_extensions_XInput_h" "#ifdef HAVE_X11_XLIB_H -# include -#endif -#ifdef HAVE_X11_XUTIL_H -# include -#endif -" -if test "x$ac_cv_header_X11_extensions_XInput_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XINPUT_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/XInput2.h" "ac_cv_header_X11_extensions_XInput2_h" "#ifdef HAVE_X11_XLIB_H -# include -#endif -#ifdef HAVE_X11_XUTIL_H -# include -#endif -" -if test "x$ac_cv_header_X11_extensions_XInput2_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XINPUT2_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/XShm.h" "ac_cv_header_X11_extensions_XShm_h" "#ifdef HAVE_X11_XLIB_H -# include -#endif -#ifdef HAVE_X11_XUTIL_H -# include -#endif -" -if test "x$ac_cv_header_X11_extensions_XShm_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XSHM_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/Xcomposite.h" "ac_cv_header_X11_extensions_Xcomposite_h" "#ifdef HAVE_X11_XLIB_H -# include -#endif -#ifdef HAVE_X11_XUTIL_H -# include -#endif -" -if test "x$ac_cv_header_X11_extensions_Xcomposite_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XCOMPOSITE_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/Xfixes.h" "ac_cv_header_X11_extensions_Xfixes_h" "#ifdef HAVE_X11_XLIB_H -# include -#endif -#ifdef HAVE_X11_XUTIL_H -# include -#endif -" -if test "x$ac_cv_header_X11_extensions_Xfixes_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XFIXES_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/Xinerama.h" "ac_cv_header_X11_extensions_Xinerama_h" "#ifdef HAVE_X11_XLIB_H -# include -#endif -#ifdef HAVE_X11_XUTIL_H -# include -#endif -" -if test "x$ac_cv_header_X11_extensions_Xinerama_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XINERAMA_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/Xrandr.h" "ac_cv_header_X11_extensions_Xrandr_h" "#ifdef HAVE_X11_XLIB_H -# include -#endif -#ifdef HAVE_X11_XUTIL_H -# include -#endif -" -if test "x$ac_cv_header_X11_extensions_Xrandr_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XRANDR_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/Xrender.h" "ac_cv_header_X11_extensions_Xrender_h" "#ifdef HAVE_X11_XLIB_H -# include -#endif -#ifdef HAVE_X11_XUTIL_H -# include -#endif -" -if test "x$ac_cv_header_X11_extensions_Xrender_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XRENDER_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/xf86vmode.h" "ac_cv_header_X11_extensions_xf86vmode_h" "#ifdef HAVE_X11_XLIB_H -# include -#endif -#ifdef HAVE_X11_XUTIL_H -# include -#endif -" -if test "x$ac_cv_header_X11_extensions_xf86vmode_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XF86VMODE_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "X11/extensions/xf86vmproto.h" "ac_cv_header_X11_extensions_xf86vmproto_h" "#ifdef HAVE_X11_XLIB_H -# include -#endif -#ifdef HAVE_X11_XUTIL_H -# include -#endif -" -if test "x$ac_cv_header_X11_extensions_xf86vmproto_h" = xyes -then : - printf "%s\n" "#define HAVE_X11_EXTENSIONS_XF86VMPROTO_H 1" >>confdefs.h - -fi - - - if test "$ac_cv_header_X11_XKBlib_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for XkbQueryExtension in -lX11" >&5 -printf %s "checking for XkbQueryExtension in -lX11... " >&6; } -if test ${ac_cv_lib_X11_XkbQueryExtension+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lX11 $X_LIBS $X_EXTRA_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char XkbQueryExtension (); -int -main (void) -{ -return XkbQueryExtension (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_X11_XkbQueryExtension=yes -else $as_nop - ac_cv_lib_X11_XkbQueryExtension=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_X11_XkbQueryExtension" >&5 -printf "%s\n" "$ac_cv_lib_X11_XkbQueryExtension" >&6; } -if test "x$ac_cv_lib_X11_XkbQueryExtension" = xyes -then : - -printf "%s\n" "#define HAVE_XKB 1" >>confdefs.h - -fi - - fi - - if test "$ac_cv_header_X11_Xcursor_Xcursor_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXcursor" >&5 -printf %s "checking for -lXcursor... " >&6; } -if test ${ac_cv_lib_soname_Xcursor+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lXcursor $X_LIBS $X_EXTRA_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char XcursorImageLoadCursor (); -int -main (void) -{ -return XcursorImageLoadCursor (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xcursor=`$ac_cv_path_LDD conftest.exe | grep "Xcursor" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xcursor=`$OTOOL -L conftest$ac_exeext | grep "libXcursor\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXcursor\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xcursor=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXcursor\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXcursor\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xcursor:+false} : -then : - ac_cv_lib_soname_Xcursor=`$LDD conftest$ac_exeext | grep "libXcursor\\.$LIBEXT" | sed -e "s/^.*\(libXcursor\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_Xcursor= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_Xcursor:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xcursor" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xcursor" >&6; } - -printf "%s\n" "#define SONAME_LIBXCURSOR \"$ac_cv_lib_soname_Xcursor\"" >>confdefs.h - - -fi - fi - if test "x$ac_cv_lib_soname_Xcursor" = "x" -then : - case "x$with_xcursor" in - x) as_fn_append wine_notices "|libxcursor ${notice_platform}development files not found, the Xcursor extension won't be supported." ;; - xno) ;; - *) as_fn_error $? "libxcursor ${notice_platform}development files not found, the Xcursor extension won't be supported. -This is an error since --with-xcursor was requested." "$LINENO" 5 ;; -esac - -fi - - if test "$ac_cv_header_X11_extensions_XInput_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXi" >&5 -printf %s "checking for -lXi... " >&6; } -if test ${ac_cv_lib_soname_Xi+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lXi $X_LIBS $X_EXTRA_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char XOpenDevice (); -int -main (void) -{ -return XOpenDevice (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xi=`$ac_cv_path_LDD conftest.exe | grep "Xi" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xi=`$OTOOL -L conftest$ac_exeext | grep "libXi\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXi\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xi=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXi\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXi\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xi:+false} : -then : - ac_cv_lib_soname_Xi=`$LDD conftest$ac_exeext | grep "libXi\\.$LIBEXT" | sed -e "s/^.*\(libXi\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_Xi= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_Xi:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xi" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xi" >&6; } - -printf "%s\n" "#define SONAME_LIBXI \"$ac_cv_lib_soname_Xi\"" >>confdefs.h - - -fi - fi - if test "x$ac_cv_lib_soname_Xi" = "x" -then : - case "x$with_xinput" in - x) as_fn_append wine_notices "|libxi ${notice_platform}development files not found, the Xinput extension won't be supported." ;; - xno) ;; - *) as_fn_error $? "libxi ${notice_platform}development files not found, the Xinput extension won't be supported. -This is an error since --with-xinput was requested." "$LINENO" 5 ;; -esac - -fi - - if test "x$ac_cv_lib_soname_Xi" != x - then - if test "$ac_cv_header_X11_extensions_XInput2_h" != "yes" -then : - case "x$with_xinput2" in - x) as_fn_append wine_notices "|XInput2 headers not found, the XInput 2 extension won't be supported." ;; - xno) ;; - *) as_fn_error $? "XInput2 headers not found, the XInput 2 extension won't be supported. -This is an error since --with-xinput2 was requested." "$LINENO" 5 ;; -esac - -fi - fi - - if test "$ac_cv_header_X11_extensions_XShm_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for XShmQueryExtension in -lXext" >&5 -printf %s "checking for XShmQueryExtension in -lXext... " >&6; } -if test ${ac_cv_lib_Xext_XShmQueryExtension+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lXext $X_LIBS $X_EXTRA_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char XShmQueryExtension (); -int -main (void) -{ -return XShmQueryExtension (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_Xext_XShmQueryExtension=yes -else $as_nop - ac_cv_lib_Xext_XShmQueryExtension=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xext_XShmQueryExtension" >&5 -printf "%s\n" "$ac_cv_lib_Xext_XShmQueryExtension" >&6; } -if test "x$ac_cv_lib_Xext_XShmQueryExtension" = xyes -then : - -printf "%s\n" "#define HAVE_LIBXXSHM 1" >>confdefs.h - -fi - - fi - if test "$ac_cv_lib_Xext_XShmQueryExtension" != "yes" -then : - case "x$with_xshm" in - x) as_fn_append wine_notices "|XShm ${notice_platform}development files not found, X Shared Memory won't be supported." ;; - xno) ;; - *) as_fn_error $? "XShm ${notice_platform}development files not found, X Shared Memory won't be supported. -This is an error since --with-xshm was requested." "$LINENO" 5 ;; -esac - -fi - - if test "$ac_cv_header_X11_extensions_shape_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for XShapeQueryExtension in -lXext" >&5 -printf %s "checking for XShapeQueryExtension in -lXext... " >&6; } -if test ${ac_cv_lib_Xext_XShapeQueryExtension+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lXext $X_LIBS $X_EXTRA_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char XShapeQueryExtension (); -int -main (void) -{ -return XShapeQueryExtension (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_Xext_XShapeQueryExtension=yes -else $as_nop - ac_cv_lib_Xext_XShapeQueryExtension=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xext_XShapeQueryExtension" >&5 -printf "%s\n" "$ac_cv_lib_Xext_XShapeQueryExtension" >&6; } -if test "x$ac_cv_lib_Xext_XShapeQueryExtension" = xyes -then : - -printf "%s\n" "#define HAVE_LIBXSHAPE 1" >>confdefs.h - -fi - - fi - if test "$ac_cv_lib_Xext_XShapeQueryExtension" != "yes" -then : - case "x$with_xshape" in - x) as_fn_append wine_notices "|XShape ${notice_platform}development files not found, XShape won't be supported." ;; - xno) ;; - *) as_fn_error $? "XShape ${notice_platform}development files not found, XShape won't be supported. -This is an error since --with-xshape was requested." "$LINENO" 5 ;; -esac - -fi - - if test "$ac_cv_header_X11_extensions_xf86vmode_h" = "yes" -o "$ac_cv_header_X11_extensions_xf86vmproto_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXxf86vm" >&5 -printf %s "checking for -lXxf86vm... " >&6; } -if test ${ac_cv_lib_soname_Xxf86vm+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lXxf86vm $X_LIBS $X_EXTRA_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char XF86VidModeQueryExtension (); -int -main (void) -{ -return XF86VidModeQueryExtension (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xxf86vm=`$ac_cv_path_LDD conftest.exe | grep "Xxf86vm" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xxf86vm=`$OTOOL -L conftest$ac_exeext | grep "libXxf86vm\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXxf86vm\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xxf86vm=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXxf86vm\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXxf86vm\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xxf86vm:+false} : -then : - ac_cv_lib_soname_Xxf86vm=`$LDD conftest$ac_exeext | grep "libXxf86vm\\.$LIBEXT" | sed -e "s/^.*\(libXxf86vm\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_Xxf86vm= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_Xxf86vm:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xxf86vm" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xxf86vm" >&6; } - -printf "%s\n" "#define SONAME_LIBXXF86VM \"$ac_cv_lib_soname_Xxf86vm\"" >>confdefs.h - - -fi - fi - if test "x$ac_cv_lib_soname_Xxf86vm" = "x" -then : - case "x$with_xxf86vm" in - x) as_fn_append wine_notices "|libXxf86vm ${notice_platform}development files not found, XFree86 Vidmode won't be supported." ;; - xno) ;; - *) as_fn_error $? "libXxf86vm ${notice_platform}development files not found, XFree86 Vidmode won't be supported. -This is an error since --with-xxf86vm was requested." "$LINENO" 5 ;; -esac - -fi - - if test "$ac_cv_header_X11_extensions_Xrender_h" = "yes" -a "x$ac_cv_lib_soname_X11" != "x" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXrender" >&5 -printf %s "checking for -lXrender... " >&6; } -if test ${ac_cv_lib_soname_Xrender+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lXrender $X_LIBS $X_EXTRA_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char XRenderQueryExtension (); -int -main (void) -{ -return XRenderQueryExtension (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xrender=`$ac_cv_path_LDD conftest.exe | grep "Xrender" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xrender=`$OTOOL -L conftest$ac_exeext | grep "libXrender\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXrender\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xrender=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXrender\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXrender\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xrender:+false} : -then : - ac_cv_lib_soname_Xrender=`$LDD conftest$ac_exeext | grep "libXrender\\.$LIBEXT" | sed -e "s/^.*\(libXrender\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_Xrender= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_Xrender:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xrender" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xrender" >&6; } - -printf "%s\n" "#define SONAME_LIBXRENDER \"$ac_cv_lib_soname_Xrender\"" >>confdefs.h - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for XRenderSetPictureTransform in -lXrender" >&5 -printf %s "checking for XRenderSetPictureTransform in -lXrender... " >&6; } -if test ${ac_cv_lib_Xrender_XRenderSetPictureTransform+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lXrender $X_LIBS $X_EXTRA_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char XRenderSetPictureTransform (); -int -main (void) -{ -return XRenderSetPictureTransform (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_Xrender_XRenderSetPictureTransform=yes -else $as_nop - ac_cv_lib_Xrender_XRenderSetPictureTransform=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xrender_XRenderSetPictureTransform" >&5 -printf "%s\n" "$ac_cv_lib_Xrender_XRenderSetPictureTransform" >&6; } -if test "x$ac_cv_lib_Xrender_XRenderSetPictureTransform" = xyes -then : - -printf "%s\n" "#define HAVE_XRENDERSETPICTURETRANSFORM 1" >>confdefs.h - -fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for XRenderCreateLinearGradient in -lXrender" >&5 -printf %s "checking for XRenderCreateLinearGradient in -lXrender... " >&6; } -if test ${ac_cv_lib_Xrender_XRenderCreateLinearGradient+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lXrender $X_LIBS $X_EXTRA_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char XRenderCreateLinearGradient (); -int -main (void) -{ -return XRenderCreateLinearGradient (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_Xrender_XRenderCreateLinearGradient=yes -else $as_nop - ac_cv_lib_Xrender_XRenderCreateLinearGradient=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xrender_XRenderCreateLinearGradient" >&5 -printf "%s\n" "$ac_cv_lib_Xrender_XRenderCreateLinearGradient" >&6; } -if test "x$ac_cv_lib_Xrender_XRenderCreateLinearGradient" = xyes -then : - -printf "%s\n" "#define HAVE_XRENDERCREATELINEARGRADIENT 1" >>confdefs.h - -fi - -fi - - fi - if test "x$ac_cv_lib_soname_Xrender" = "x" -then : - case "x$with_xrender" in - x) as_fn_append wine_warnings "|libxrender ${notice_platform}development files not found, XRender won't be supported." ;; - xno) ;; - *) as_fn_error $? "libxrender ${notice_platform}development files not found, XRender won't be supported. -This is an error since --with-xrender was requested." "$LINENO" 5 ;; -esac - -fi - - if test "$ac_cv_header_X11_extensions_Xrandr_h" = "yes" -a "x$ac_cv_lib_soname_Xrender" != "x" - then - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -int -main (void) -{ -static typeof(XRRSetScreenConfigAndRate) * func; if (func) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXrandr" >&5 -printf %s "checking for -lXrandr... " >&6; } -if test ${ac_cv_lib_soname_Xrandr+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lXrandr $X_LIBS $X_EXTRA_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char XRRQueryExtension (); -int -main (void) -{ -return XRRQueryExtension (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xrandr=`$ac_cv_path_LDD conftest.exe | grep "Xrandr" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xrandr=`$OTOOL -L conftest$ac_exeext | grep "libXrandr\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXrandr\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xrandr=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXrandr\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXrandr\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xrandr:+false} : -then : - ac_cv_lib_soname_Xrandr=`$LDD conftest$ac_exeext | grep "libXrandr\\.$LIBEXT" | sed -e "s/^.*\(libXrandr\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_Xrandr= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_Xrandr:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xrandr" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xrandr" >&6; } - -printf "%s\n" "#define SONAME_LIBXRANDR \"$ac_cv_lib_soname_Xrandr\"" >>confdefs.h - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -int -main (void) -{ -static typeof(XRRGetProviderResources) *f; if (f) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -printf "%s\n" "#define HAVE_XRRGETPROVIDERRESOURCES 1" >>confdefs.h - -else $as_nop - as_fn_append wine_notices "|libxrandr ${notice_platform}development files too old, XRandR display device handler won't be supported." -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - fi - if test "x$ac_cv_lib_soname_Xrandr" = "x" -then : - case "x$with_xrandr" in - x) as_fn_append wine_notices "|libxrandr ${notice_platform}development files not found, XRandr won't be supported." ;; - xno) ;; - *) as_fn_error $? "libxrandr ${notice_platform}development files not found, XRandr won't be supported. -This is an error since --with-xrandr was requested." "$LINENO" 5 ;; -esac - -fi - - if test "$ac_cv_header_X11_extensions_Xfixes_h" = "yes" - then - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -int -main (void) -{ -static typeof(XFixesQueryVersion) * func; if (func) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXfixes" >&5 -printf %s "checking for -lXfixes... " >&6; } -if test ${ac_cv_lib_soname_Xfixes+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lXfixes $X_LIBS $X_EXTRA_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char XFixesQueryVersion (); -int -main (void) -{ -return XFixesQueryVersion (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xfixes=`$ac_cv_path_LDD conftest.exe | grep "Xfixes" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xfixes=`$OTOOL -L conftest$ac_exeext | grep "libXfixes\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXfixes\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xfixes=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXfixes\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXfixes\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xfixes:+false} : -then : - ac_cv_lib_soname_Xfixes=`$LDD conftest$ac_exeext | grep "libXfixes\\.$LIBEXT" | sed -e "s/^.*\(libXfixes\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_Xfixes= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_Xfixes:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xfixes" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xfixes" >&6; } - -printf "%s\n" "#define SONAME_LIBXFIXES \"$ac_cv_lib_soname_Xfixes\"" >>confdefs.h - - -fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - fi - if test "x$ac_cv_lib_soname_Xfixes" = "x" -then : - case "x$with_xfixes" in - x) as_fn_append wine_notices "|libxfixes ${notice_platform}development files not found, Xfixes won't be supported." ;; - xno) ;; - *) as_fn_error $? "libxfixes ${notice_platform}development files not found, Xfixes won't be supported. -This is an error since --with-xfixes was requested." "$LINENO" 5 ;; -esac - -fi - - if test "$ac_cv_header_X11_extensions_Xinerama_h" = "yes" - then - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -int -main (void) -{ -static typeof(XineramaQueryScreens) * func; if (func) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXinerama" >&5 -printf %s "checking for -lXinerama... " >&6; } -if test ${ac_cv_lib_soname_Xinerama+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lXinerama $X_LIBS $X_EXTRA_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char XineramaQueryScreens (); -int -main (void) -{ -return XineramaQueryScreens (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xinerama=`$ac_cv_path_LDD conftest.exe | grep "Xinerama" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xinerama=`$OTOOL -L conftest$ac_exeext | grep "libXinerama\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXinerama\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xinerama=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXinerama\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXinerama\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xinerama:+false} : -then : - ac_cv_lib_soname_Xinerama=`$LDD conftest$ac_exeext | grep "libXinerama\\.$LIBEXT" | sed -e "s/^.*\(libXinerama\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_Xinerama= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_Xinerama:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xinerama" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xinerama" >&6; } - -printf "%s\n" "#define SONAME_LIBXINERAMA \"$ac_cv_lib_soname_Xinerama\"" >>confdefs.h - - -fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - fi - if test "x$ac_cv_lib_soname_Xinerama" = "x" -then : - case "x$with_xinerama" in - x) as_fn_append wine_notices "|libxinerama ${notice_platform}development files not found, multi-monitor setups won't be supported." ;; - xno) ;; - *) as_fn_error $? "libxinerama ${notice_platform}development files not found, multi-monitor setups won't be supported. -This is an error since --with-xinerama was requested." "$LINENO" 5 ;; -esac - -fi - - if test "$ac_cv_header_X11_extensions_Xcomposite_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lXcomposite" >&5 -printf %s "checking for -lXcomposite... " >&6; } -if test ${ac_cv_lib_soname_Xcomposite+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lXcomposite $X_LIBS $X_EXTRA_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char XCompositeRedirectWindow (); -int -main (void) -{ -return XCompositeRedirectWindow (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_Xcomposite=`$ac_cv_path_LDD conftest.exe | grep "Xcomposite" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_Xcomposite=`$OTOOL -L conftest$ac_exeext | grep "libXcomposite\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libXcomposite\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_Xcomposite=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libXcomposite\\.$LIBEXT" | sed -e "s/^.*\\[\\(libXcomposite\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_Xcomposite:+false} : -then : - ac_cv_lib_soname_Xcomposite=`$LDD conftest$ac_exeext | grep "libXcomposite\\.$LIBEXT" | sed -e "s/^.*\(libXcomposite\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_Xcomposite= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_Xcomposite:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_Xcomposite" >&5 -printf "%s\n" "$ac_cv_lib_soname_Xcomposite" >&6; } - -printf "%s\n" "#define SONAME_LIBXCOMPOSITE \"$ac_cv_lib_soname_Xcomposite\"" >>confdefs.h - - -fi - fi - if test "x$ac_cv_lib_soname_Xcomposite" = "x" -then : - case "x$with_xcomposite" in - x) as_fn_append wine_notices "|libxcomposite ${notice_platform}development files not found, Xcomposite won't be supported." ;; - xno) ;; - *) as_fn_error $? "libxcomposite ${notice_platform}development files not found, Xcomposite won't be supported. -This is an error since --with-xcomposite was requested." "$LINENO" 5 ;; -esac - -fi - - ac_fn_c_check_member "$LINENO" "XICCallback" "callback" "ac_cv_member_XICCallback_callback" "#ifdef HAVE_X11_XLIB_H -#include -#endif -" -if test "x$ac_cv_member_XICCallback_callback" = xyes -then : - -printf "%s\n" "#define HAVE_XICCALLBACK_CALLBACK 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "XEvent" "xcookie" "ac_cv_member_XEvent_xcookie" "#ifdef HAVE_X11_XLIB_H -#include -#endif -" -if test "x$ac_cv_member_XEvent_xcookie" = xyes -then : - -printf "%s\n" "#define HAVE_XEVENT_XCOOKIE 1" >>confdefs.h - - -fi - - - - opengl_msg="" - if test "x$with_opengl" != "xno" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lGL" >&5 -printf %s "checking for -lGL... " >&6; } -if test ${ac_cv_lib_soname_GL+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lGL $X_LIBS -lm $X_EXTRA_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char glXCreateContext (); -int -main (void) -{ -return glXCreateContext (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_GL=`$ac_cv_path_LDD conftest.exe | grep "GL" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_GL=`$OTOOL -L conftest$ac_exeext | grep "libGL\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libGL\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_GL=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libGL\\.$LIBEXT" | sed -e "s/^.*\\[\\(libGL\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_GL:+false} : -then : - ac_cv_lib_soname_GL=`$LDD conftest$ac_exeext | grep "libGL\\.$LIBEXT" | sed -e "s/^.*\(libGL\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_GL= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_GL:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lGL" >&5 -printf %s "checking for -lGL... " >&6; } -if test ${ac_cv_lib_soname_GL+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lGL $X_LIBS -lm $X_EXTRA_LIBS -dylib_file /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib:/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char glXCreateContext (); -int -main (void) -{ -return glXCreateContext (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_GL=`$ac_cv_path_LDD conftest.exe | grep "GL" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_GL=`$OTOOL -L conftest$ac_exeext | grep "libGL\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libGL\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_GL=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libGL\\.$LIBEXT" | sed -e "s/^.*\\[\\(libGL\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_GL:+false} : -then : - ac_cv_lib_soname_GL=`$LDD conftest$ac_exeext | grep "libGL\\.$LIBEXT" | sed -e "s/^.*\(libGL\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_GL= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_GL:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - if test -f /usr/X11R6/lib/libGL.a - then - opengl_msg="/usr/X11R6/lib/libGL.a is present on your system. -This probably prevents linking to OpenGL. Try deleting the file and restarting configure." - else - opengl_msg="No OpenGL library found on this system." - fi -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_GL" >&5 -printf "%s\n" "$ac_cv_lib_soname_GL" >&6; } - -printf "%s\n" "#define SONAME_LIBGL \"$ac_cv_lib_soname_GL\"" >>confdefs.h - - OPENGL_LIBS="-Xlinker -dylib_file -Xlinker /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib:/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib -lGL" -fi -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_GL" >&5 -printf "%s\n" "$ac_cv_lib_soname_GL" >&6; } - -printf "%s\n" "#define SONAME_LIBGL \"$ac_cv_lib_soname_GL\"" >>confdefs.h - - OPENGL_LIBS="-lGL" -fi - if test "x$with_osmesa" != "xno" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lOSMesa" >&5 -printf %s "checking for -lOSMesa... " >&6; } -if test ${ac_cv_lib_soname_OSMesa+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lOSMesa $X_LIBS -lm $X_EXTRA_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char OSMesaGetProcAddress (); -int -main (void) -{ -return OSMesaGetProcAddress (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_OSMesa=`$ac_cv_path_LDD conftest.exe | grep "OSMesa" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_OSMesa=`$OTOOL -L conftest$ac_exeext | grep "libOSMesa\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libOSMesa\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_OSMesa=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libOSMesa\\.$LIBEXT" | sed -e "s/^.*\\[\\(libOSMesa\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_OSMesa:+false} : -then : - ac_cv_lib_soname_OSMesa=`$LDD conftest$ac_exeext | grep "libOSMesa\\.$LIBEXT" | sed -e "s/^.*\(libOSMesa\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_OSMesa= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_OSMesa:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_OSMesa" >&5 -printf "%s\n" "$ac_cv_lib_soname_OSMesa" >&6; } - -printf "%s\n" "#define SONAME_LIBOSMESA \"$ac_cv_lib_soname_OSMesa\"" >>confdefs.h - - -fi - if test "x$ac_cv_lib_soname_OSMesa" = "x" -then : - case "x$with_osmesa" in - x) as_fn_append wine_notices "|libOSMesa ${notice_platform}development files not found (or too old), OpenGL rendering in bitmaps won't be supported." ;; - xno) ;; - *) as_fn_error $? "libOSMesa ${notice_platform}development files not found (or too old), OpenGL rendering in bitmaps won't be supported. -This is an error since --with-osmesa was requested." "$LINENO" 5 ;; -esac - -fi - fi - fi - if test -n "$opengl_msg" -then : - case "x$with_opengl" in - x) as_fn_append wine_warnings "|$opengl_msg -OpenGL and Direct3D won't be supported." ;; - xno) ;; - *) as_fn_error $? "$opengl_msg -OpenGL and Direct3D won't be supported. -This is an error since --with-opengl was requested." "$LINENO" 5 ;; -esac - -fi - - CPPFLAGS="$ac_save_CPPFLAGS" -else - X_CFLAGS="" - X_LIBS="" -fi - -if test "$enable_wineandroid_drv$enable_winemac_drv" = "nono" -then - if test "x$X_LIBS" = "x" -then : - case "x$with_x" in - xno) ;; - *) as_fn_error $? "X ${notice_platform}development files not found. Wine will be built -without X support, which probably isn't what you want. You will need -to install ${notice_platform}development packages of Xlib at the very least. -Use the --without-x option if you really want this." "$LINENO" 5 ;; -esac -enable_winex11_drv=${enable_winex11_drv:-no} -fi -else - if test "x$X_LIBS" = "x" -then : - case "x$with_x" in - x) as_fn_append wine_notices "|X ${notice_platform}development files not found, the X11 driver won't be supported." ;; - xno) ;; - *) as_fn_error $? "X ${notice_platform}development files not found, the X11 driver won't be supported. -This is an error since --with-x was requested." "$LINENO" 5 ;; -esac -enable_winex11_drv=${enable_winex11_drv:-no} -fi -fi - -if test "$ac_cv_header_CL_cl_h" = "yes" -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clGetPlatformInfo in -lOpenCL" >&5 -printf %s "checking for clGetPlatformInfo in -lOpenCL... " >&6; } -if test ${ac_cv_lib_OpenCL_clGetPlatformInfo+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lOpenCL $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char clGetPlatformInfo (); -int -main (void) -{ -return clGetPlatformInfo (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_OpenCL_clGetPlatformInfo=yes -else $as_nop - ac_cv_lib_OpenCL_clGetPlatformInfo=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_OpenCL_clGetPlatformInfo" >&5 -printf "%s\n" "$ac_cv_lib_OpenCL_clGetPlatformInfo" >&6; } -if test "x$ac_cv_lib_OpenCL_clGetPlatformInfo" = xyes -then : - OPENCL_LIBS="-lOpenCL" - -fi - -fi -if test "x$ac_cv_lib_OpenCL_clGetPlatformInfo" != xyes -then : - case "x$with_opencl" in - x) as_fn_append wine_notices "|OpenCL ${notice_platform}development files not found, OpenCL won't be supported." ;; - xno) ;; - *) as_fn_error $? "OpenCL ${notice_platform}development files not found, OpenCL won't be supported. -This is an error since --with-opencl was requested." "$LINENO" 5 ;; -esac -enable_opencl=${enable_opencl:-no} -fi - -if test "$ac_cv_header_pcap_pcap_h" = "yes" -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pcap_create in -lpcap" >&5 -printf %s "checking for pcap_create in -lpcap... " >&6; } -if test ${ac_cv_lib_pcap_pcap_create+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lpcap $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char pcap_create (); -int -main (void) -{ -return pcap_create (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_pcap_pcap_create=yes -else $as_nop - ac_cv_lib_pcap_pcap_create=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcap_pcap_create" >&5 -printf "%s\n" "$ac_cv_lib_pcap_pcap_create" >&6; } -if test "x$ac_cv_lib_pcap_pcap_create" = xyes -then : - PCAP_LIBS="-lpcap" - -fi - -fi -if test "x$ac_cv_lib_pcap_pcap_create" != xyes -then : - case "x$with_pcap" in - x) as_fn_append wine_notices "|pcap ${notice_platform}development files not found, wpcap won't be supported." ;; - xno) ;; - *) as_fn_error $? "pcap ${notice_platform}development files not found, wpcap won't be supported. -This is an error since --with-pcap was requested." "$LINENO" 5 ;; -esac -enable_wpcap=${enable_wpcap:-no} -fi - -if test "x$with_inotify" != "xno" -then - rm -f conftest.err -if ${INOTIFY_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - INOTIFY_CFLAGS=`$PKG_CONFIG --cflags libinotify 2>conftest.err` -fi -fi - -if ${INOTIFY_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - INOTIFY_LIBS=`$PKG_CONFIG --libs libinotify 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libinotify cflags: $INOTIFY_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libinotify libs: $INOTIFY_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: libinotify errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $INOTIFY_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "sys/inotify.h" "ac_cv_header_sys_inotify_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_inotify_h" = xyes -then : - printf "%s\n" "#define HAVE_SYS_INOTIFY_H 1" >>confdefs.h - -fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inotify_add_watch in -linotify" >&5 -printf %s "checking for inotify_add_watch in -linotify... " >&6; } -if test ${ac_cv_lib_inotify_inotify_add_watch+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-linotify $INOTIFY_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char inotify_add_watch (); -int -main (void) -{ -return inotify_add_watch (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_inotify_inotify_add_watch=yes -else $as_nop - ac_cv_lib_inotify_inotify_add_watch=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inotify_inotify_add_watch" >&5 -printf "%s\n" "$ac_cv_lib_inotify_inotify_add_watch" >&6; } -if test "x$ac_cv_lib_inotify_inotify_add_watch" = xyes -then : - : -else $as_nop - INOTIFY_LIBS="" -fi - -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "$ac_cv_header_sys_inotify_h" != "yes" -then : - case "x$with_inotify" in - x) as_fn_append wine_notices "|libinotify ${notice_platform}development files not found (or too old), filesystem change notifications won't be supported." ;; - xno) ;; - *) as_fn_error $? "libinotify ${notice_platform}development files not found (or too old), filesystem change notifications won't be supported. -This is an error since --with-inotify was requested." "$LINENO" 5 ;; -esac - -fi - -if test "x$with_dbus" != "xno" -then - rm -f conftest.err -if ${DBUS_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - DBUS_CFLAGS=`$PKG_CONFIG --cflags dbus-1 2>conftest.err` -fi -fi - -if ${DBUS_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - DBUS_LIBS=`$PKG_CONFIG --libs dbus-1 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: dbus-1 cflags: $DBUS_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: dbus-1 libs: $DBUS_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: dbus-1 errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $DBUS_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "dbus/dbus.h" "ac_cv_header_dbus_dbus_h" "$ac_includes_default" -if test "x$ac_cv_header_dbus_dbus_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -ldbus-1" >&5 -printf %s "checking for -ldbus-1... " >&6; } -if test ${ac_cv_lib_soname_dbus_1+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-ldbus-1 $DBUS_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char dbus_connection_close (); -int -main (void) -{ -return dbus_connection_close (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_dbus_1=`$ac_cv_path_LDD conftest.exe | grep "dbus-1" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_dbus_1=`$OTOOL -L conftest$ac_exeext | grep "libdbus-1\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libdbus-1\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_dbus_1=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libdbus-1\\.$LIBEXT" | sed -e "s/^.*\\[\\(libdbus-1\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_dbus_1:+false} : -then : - ac_cv_lib_soname_dbus_1=`$LDD conftest$ac_exeext | grep "libdbus-1\\.$LIBEXT" | sed -e "s/^.*\(libdbus-1\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_dbus_1= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_dbus_1:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - DBUS_CFLAGS="" -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_dbus_1" >&5 -printf "%s\n" "$ac_cv_lib_soname_dbus_1" >&6; } - -printf "%s\n" "#define SONAME_LIBDBUS_1 \"$ac_cv_lib_soname_dbus_1\"" >>confdefs.h - - -fi -else $as_nop - DBUS_CFLAGS="" -fi - -CPPFLAGS=$ac_save_CPPFLAGS - -fi -case $host_os in - darwin*|macosx*) ;; - *) if test "x$ac_cv_lib_soname_dbus_1" = "x" -then : - case "x$with_dbus" in - x) as_fn_append wine_notices "|libdbus ${notice_platform}development files not found, no dynamic device support." ;; - xno) ;; - *) as_fn_error $? "libdbus ${notice_platform}development files not found, no dynamic device support. -This is an error since --with-dbus was requested." "$LINENO" 5 ;; -esac - -fi ;; -esac - -if test "x$with_gnutls" != "xno" -then - rm -f conftest.err -if ${GNUTLS_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GNUTLS_CFLAGS=`$PKG_CONFIG --cflags gnutls 2>conftest.err` -fi -fi - -if ${GNUTLS_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GNUTLS_LIBS=`$PKG_CONFIG --libs gnutls 2>/dev/null` -fi -fi - -GNUTLS_LIBS=${GNUTLS_LIBS:-"-lgnutls"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: gnutls cflags: $GNUTLS_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: gnutls libs: $GNUTLS_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: gnutls errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $GNUTLS_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "gnutls/gnutls.h" "ac_cv_header_gnutls_gnutls_h" "$ac_includes_default" -if test "x$ac_cv_header_gnutls_gnutls_h" = xyes -then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -int -main (void) -{ -static typeof(gnutls_mac_get_key_size) *func; if (func) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lgnutls" >&5 -printf %s "checking for -lgnutls... " >&6; } -if test ${ac_cv_lib_soname_gnutls+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lgnutls $GNUTLS_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char gnutls_global_init (); -int -main (void) -{ -return gnutls_global_init (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_gnutls=`$ac_cv_path_LDD conftest.exe | grep "gnutls" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_gnutls=`$OTOOL -L conftest$ac_exeext | grep "libgnutls\\(-deb0\\)\\{0,1\\}\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libgnutls\\(-deb0\\)\\{0,1\\}\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_gnutls=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libgnutls\\(-deb0\\)\\{0,1\\}\\.$LIBEXT" | sed -e "s/^.*\\[\\(libgnutls\\(-deb0\\)\\{0,1\\}\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_gnutls:+false} : -then : - ac_cv_lib_soname_gnutls=`$LDD conftest$ac_exeext | grep "libgnutls\\(-deb0\\)\\{0,1\\}\\.$LIBEXT" | sed -e "s/^.*\(libgnutls\\(-deb0\\)\\{0,1\\}\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_gnutls= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_gnutls:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - GNUTLS_CFLAGS="" -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_gnutls" >&5 -printf "%s\n" "$ac_cv_lib_soname_gnutls" >&6; } - -printf "%s\n" "#define SONAME_LIBGNUTLS \"$ac_cv_lib_soname_gnutls\"" >>confdefs.h - - -fi - ac_wine_check_funcs_save_LIBS="$LIBS" -LIBS="$LIBS $GNUTLS_LIBS" - - for ac_func in gnutls_cipher_init -do : - ac_fn_c_check_func "$LINENO" "gnutls_cipher_init" "ac_cv_func_gnutls_cipher_init" -if test "x$ac_cv_func_gnutls_cipher_init" = xyes -then : - printf "%s\n" "#define HAVE_GNUTLS_CIPHER_INIT 1" >>confdefs.h - -else $as_nop - as_fn_append wine_notices "|libgnutls ${notice_platform}development files too old, bcrypt encryption won't be supported." -fi - -done -LIBS="$ac_wine_check_funcs_save_LIBS" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -else $as_nop - GNUTLS_CFLAGS="" -fi - -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_soname_gnutls" = "x" -then : - case "x$with_gnutls" in - x) as_fn_append wine_warnings "|libgnutls ${notice_platform}development files not found, no schannel support." ;; - xno) ;; - *) as_fn_error $? "libgnutls ${notice_platform}development files not found, no schannel support. -This is an error since --with-gnutls was requested." "$LINENO" 5 ;; -esac - -fi - -if test "x$with_sane" != "xno" -then - rm -f conftest.err -if ${SANE_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - SANE_CFLAGS=`$PKG_CONFIG --cflags sane-backends 2>conftest.err` -fi -fi -test "$cross_compiling" = yes || SANE_CFLAGS=${SANE_CFLAGS:-`${SANE_CONFIG:-sane-config} --cflags 2>/dev/null`} -if ${SANE_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - SANE_LIBS=`$PKG_CONFIG --libs sane-backends 2>/dev/null` -fi -fi -test "$cross_compiling" = yes || SANE_LIBS=${SANE_LIBS:-`${SANE_CONFIG:-sane-config} --ldflags 2>/dev/null`} - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: sane-backends cflags: $SANE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: sane-backends libs: $SANE_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: sane-backends errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $SANE_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "sane/sane.h" "ac_cv_header_sane_sane_h" "$ac_includes_default" -if test "x$ac_cv_header_sane_sane_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sane_init in -lsane" >&5 -printf %s "checking for sane_init in -lsane... " >&6; } -if test ${ac_cv_lib_sane_sane_init+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsane $SANE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char sane_init (); -int -main (void) -{ -return sane_init (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_sane_sane_init=yes -else $as_nop - ac_cv_lib_sane_sane_init=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sane_sane_init" >&5 -printf "%s\n" "$ac_cv_lib_sane_sane_init" >&6; } -if test "x$ac_cv_lib_sane_sane_init" = xyes -then : - : -fi - -fi - -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "$ac_cv_lib_sane_sane_init" != "yes" -then : - case "x$with_sane" in - x) as_fn_append wine_notices "|libsane ${notice_platform}development files not found, scanners won't be supported." ;; - xno) ;; - *) as_fn_error $? "libsane ${notice_platform}development files not found, scanners won't be supported. -This is an error since --with-sane was requested." "$LINENO" 5 ;; -esac -enable_sane_ds=${enable_sane_ds:-no} -fi - -if test "x$with_usb" != "xno" -then - rm -f conftest.err -if ${USB_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - USB_CFLAGS=`$PKG_CONFIG --cflags libusb-1.0 2>conftest.err` -fi -fi - -if ${USB_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - USB_LIBS=`$PKG_CONFIG --libs libusb-1.0 2>/dev/null` -fi -fi - -USB_LIBS=${USB_LIBS:-"-lusb-1.0"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libusb-1.0 cflags: $USB_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libusb-1.0 libs: $USB_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: libusb-1.0 errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $USB_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "libusb.h" "ac_cv_header_libusb_h" "$ac_includes_default" -if test "x$ac_cv_header_libusb_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libusb_interrupt_event_handler in -lusb-1.0" >&5 -printf %s "checking for libusb_interrupt_event_handler in -lusb-1.0... " >&6; } -if test ${ac_cv_lib_usb_1_0_libusb_interrupt_event_handler+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lusb-1.0 $USB_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char libusb_interrupt_event_handler (); -int -main (void) -{ -return libusb_interrupt_event_handler (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_usb_1_0_libusb_interrupt_event_handler=yes -else $as_nop - ac_cv_lib_usb_1_0_libusb_interrupt_event_handler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_usb_1_0_libusb_interrupt_event_handler" >&5 -printf "%s\n" "$ac_cv_lib_usb_1_0_libusb_interrupt_event_handler" >&6; } -if test "x$ac_cv_lib_usb_1_0_libusb_interrupt_event_handler" = xyes -then : - : -else $as_nop - USB_LIBS="" -fi - -else $as_nop - USB_LIBS="" -fi - -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "$ac_cv_lib_usb_1_0_libusb_interrupt_event_handler" != "yes" -then : - case "x$with_usb" in - x) as_fn_append wine_notices "|libusb-1.0 ${notice_platform}development files not found (or too old), USB devices won't be supported." ;; - xno) ;; - *) as_fn_error $? "libusb-1.0 ${notice_platform}development files not found (or too old), USB devices won't be supported. -This is an error since --with-usb was requested." "$LINENO" 5 ;; -esac -enable_wineusb_sys=${enable_wineusb_sys:-no} -fi - -if test "x$with_v4l2" != "xno" -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lv4l2" >&5 -printf %s "checking for -lv4l2... " >&6; } -if test ${ac_cv_lib_soname_v4l2+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lv4l2 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char v4l2_open (); -int -main (void) -{ -return v4l2_open (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_v4l2=`$ac_cv_path_LDD conftest.exe | grep "v4l2" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_v4l2=`$OTOOL -L conftest$ac_exeext | grep "libv4l2\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libv4l2\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_v4l2=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libv4l2\\.$LIBEXT" | sed -e "s/^.*\\[\\(libv4l2\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_v4l2:+false} : -then : - ac_cv_lib_soname_v4l2=`$LDD conftest$ac_exeext | grep "libv4l2\\.$LIBEXT" | sed -e "s/^.*\(libv4l2\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_v4l2= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_v4l2:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_v4l2" >&5 -printf "%s\n" "$ac_cv_lib_soname_v4l2" >&6; } - -printf "%s\n" "#define SONAME_LIBV4L2 \"$ac_cv_lib_soname_v4l2\"" >>confdefs.h - - -fi -fi -if test "x$ac_cv_lib_soname_v4l2" = "x" -then : - case "x$with_v4l2" in - x) as_fn_append wine_notices "|libv4l2 ${notice_platform}development files not found." ;; - xno) ;; - *) as_fn_error $? "libv4l2 ${notice_platform}development files not found. -This is an error since --with-v4l2 was requested." "$LINENO" 5 ;; -esac - -fi - -if test "x$with_gphoto" != "xno" -then - rm -f conftest.err -if ${GPHOTO2_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GPHOTO2_CFLAGS=`$PKG_CONFIG --cflags libgphoto2 2>conftest.err` -fi -fi -test "$cross_compiling" = yes || GPHOTO2_CFLAGS=${GPHOTO2_CFLAGS:-`${GPHOTO2_CONFIG:-gphoto2-config} --cflags 2>/dev/null`} -if ${GPHOTO2_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GPHOTO2_LIBS=`$PKG_CONFIG --libs libgphoto2 2>/dev/null` -fi -fi -test "$cross_compiling" = yes || GPHOTO2_LIBS=${GPHOTO2_LIBS:-`${GPHOTO2_CONFIG:-gphoto2-config} --libs 2>/dev/null`} -GPHOTO2_LIBS=${GPHOTO2_LIBS:-"-lgphoto2"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libgphoto2 cflags: $GPHOTO2_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libgphoto2 libs: $GPHOTO2_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: libgphoto2 errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $GPHOTO2_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "gphoto2-camera.h" "ac_cv_header_gphoto2_camera_h" "$ac_includes_default" -if test "x$ac_cv_header_gphoto2_camera_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gp_camera_new in -lgphoto2" >&5 -printf %s "checking for gp_camera_new in -lgphoto2... " >&6; } -if test ${ac_cv_lib_gphoto2_gp_camera_new+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lgphoto2 $GPHOTO2_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char gp_camera_new (); -int -main (void) -{ -return gp_camera_new (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_gphoto2_gp_camera_new=yes -else $as_nop - ac_cv_lib_gphoto2_gp_camera_new=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gphoto2_gp_camera_new" >&5 -printf "%s\n" "$ac_cv_lib_gphoto2_gp_camera_new" >&6; } -if test "x$ac_cv_lib_gphoto2_gp_camera_new" = xyes -then : - : -fi - -fi - -CPPFLAGS=$ac_save_CPPFLAGS - - rm -f conftest.err -if ${GPHOTO2_PORT_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GPHOTO2_PORT_CFLAGS=`$PKG_CONFIG --cflags libgphoto2_port 2>conftest.err` -fi -fi -test "$cross_compiling" = yes || GPHOTO2_PORT_CFLAGS=${GPHOTO2_PORT_CFLAGS:-`${GPHOTO2_PORT_CONFIG:-gphoto2-port-config} --cflags 2>/dev/null`} -if ${GPHOTO2_PORT_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GPHOTO2_PORT_LIBS=`$PKG_CONFIG --libs libgphoto2_port 2>/dev/null` -fi -fi -test "$cross_compiling" = yes || GPHOTO2_PORT_LIBS=${GPHOTO2_PORT_LIBS:-`${GPHOTO2_PORT_CONFIG:-gphoto2-port-config} --libs 2>/dev/null`} -GPHOTO2_PORT_LIBS=${GPHOTO2_PORT_LIBS:-"-lgphoto2_port"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libgphoto2_port cflags: $GPHOTO2_PORT_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libgphoto2_port libs: $GPHOTO2_PORT_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: libgphoto2_port errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $GPHOTO2_PORT_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "gphoto2-port.h" "ac_cv_header_gphoto2_port_h" "$ac_includes_default" -if test "x$ac_cv_header_gphoto2_port_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gp_port_info_list_new in -lgphoto2_port" >&5 -printf %s "checking for gp_port_info_list_new in -lgphoto2_port... " >&6; } -if test ${ac_cv_lib_gphoto2_port_gp_port_info_list_new+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lgphoto2_port $GPHOTO2_PORT_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char gp_port_info_list_new (); -int -main (void) -{ -return gp_port_info_list_new (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_gphoto2_port_gp_port_info_list_new=yes -else $as_nop - ac_cv_lib_gphoto2_port_gp_port_info_list_new=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gphoto2_port_gp_port_info_list_new" >&5 -printf "%s\n" "$ac_cv_lib_gphoto2_port_gp_port_info_list_new" >&6; } -if test "x$ac_cv_lib_gphoto2_port_gp_port_info_list_new" = xyes -then : - -printf "%s\n" "#define HAVE_GPHOTO2_PORT 1" >>confdefs.h - -else $as_nop - GPHOTO2_PORT_LIBS=""; GPHOTO2_PORT_CFLAGS="" -fi - -else $as_nop - GPHOTO2_PORT_LIBS=""; GPHOTO2_PORT_CFLAGS="" -fi - -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "$ac_cv_lib_gphoto2_gp_camera_new" != "yes" -then : - case "x$with_gphoto" in - x) as_fn_append wine_notices "|libgphoto2 ${notice_platform}development files not found, digital cameras won't be supported." ;; - xno) ;; - *) as_fn_error $? "libgphoto2 ${notice_platform}development files not found, digital cameras won't be supported. -This is an error since --with-gphoto was requested." "$LINENO" 5 ;; -esac -enable_gphoto2_ds=${enable_gphoto2_ds:-no} -fi -if test "$ac_cv_lib_gphoto2_port_gp_port_info_list_new" != "yes" -then : - case "x$with_gphoto" in - x) as_fn_append wine_notices "|libgphoto2_port ${notice_platform}development files not found, digital cameras won't be auto-detected." ;; - xno) ;; - *) as_fn_error $? "libgphoto2_port ${notice_platform}development files not found, digital cameras won't be auto-detected. -This is an error since --with-gphoto was requested." "$LINENO" 5 ;; -esac - -fi - - -if test "$ac_cv_header_resolv_h" = "yes" -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for resolver library" >&5 -printf %s "checking for resolver library... " >&6; } -if test ${ac_cv_have_resolv+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_save_LIBS="$LIBS" - for lib in '' -lresolv - do - LIBS="$lib $ac_save_LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef HAVE_NETINET_IN_H -#include -#endif -#include -int -main (void) -{ -if (!(_res.options & RES_INIT)) res_init(); res_query("foo",ns_c_in,0,0,0); ns_initparse(0,0,0) - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_have_resolv=${lib:-"none required"} -else $as_nop - ac_cv_have_resolv="not found" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - test "x$ac_cv_have_resolv" = "xnot found" || break - done - LIBS="$ac_save_LIBS" -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_resolv" >&5 -printf "%s\n" "$ac_cv_have_resolv" >&6; } - - case "$ac_cv_have_resolv" in - "not found") ;; - "none required") - -printf "%s\n" "#define HAVE_RESOLV 1" >>confdefs.h - ;; - *) - printf "%s\n" "#define HAVE_RESOLV 1" >>confdefs.h - - RESOLV_LIBS=$ac_cv_have_resolv - ;; - esac - - if test "x$ac_cv_have_resolv" != "xnot found" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for res_getservers" >&5 -printf %s "checking for res_getservers... " >&6; } -if test ${ac_cv_have_res_getservers+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_save_LIBS="$LIBS" - LIBS="$RESOLV_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -res_getservers(NULL, NULL, 0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_have_res_getservers=yes -else $as_nop - ac_cv_have_res_getservers=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS="$ac_save_LIBS" -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_res_getservers" >&5 -printf "%s\n" "$ac_cv_have_res_getservers" >&6; } - if test "$ac_cv_have_res_getservers" = "yes" - then - -printf "%s\n" "#define HAVE_RES_GETSERVERS 1" >>confdefs.h - - fi - fi -fi - -if test "x$with_freetype" != "xno" -then - rm -f conftest.err -if ${FREETYPE_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - FREETYPE_CFLAGS=`$PKG_CONFIG --cflags freetype2 2>conftest.err` -fi -fi -test "$cross_compiling" = yes || FREETYPE_CFLAGS=${FREETYPE_CFLAGS:-`(${FREETYPE_CONFIG:-freetype-config} --cflags || ${FREETYPE2_CONFIG:-freetype2-config} --cflags) 2>/dev/null`} -if ${FREETYPE_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - FREETYPE_LIBS=`$PKG_CONFIG --libs freetype2 2>/dev/null` -fi -fi -test "$cross_compiling" = yes || FREETYPE_LIBS=${FREETYPE_LIBS:-`(${FREETYPE_CONFIG:-freetype-config} --libs || ${FREETYPE2_CONFIG:-freetype2-config} --libs) 2>/dev/null`} -FREETYPE_LIBS=${FREETYPE_LIBS:-"-lfreetype"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: freetype2 cflags: $FREETYPE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: freetype2 libs: $FREETYPE_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: freetype2 errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $FREETYPE_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "ft2build.h" "ac_cv_header_ft2build_h" "$ac_includes_default" -if test "x$ac_cv_header_ft2build_h" = xyes -then : - printf "%s\n" "#define HAVE_FT2BUILD_H 1" >>confdefs.h - -fi - - if test "$ac_cv_header_ft2build_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lfreetype" >&5 -printf %s "checking for -lfreetype... " >&6; } -if test ${ac_cv_lib_soname_freetype+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lfreetype $FREETYPE_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char FT_Init_FreeType (); -int -main (void) -{ -return FT_Init_FreeType (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_freetype=`$ac_cv_path_LDD conftest.exe | grep "freetype" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_freetype=`$OTOOL -L conftest$ac_exeext | grep "libfreetype\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libfreetype\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_freetype=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libfreetype\\.$LIBEXT" | sed -e "s/^.*\\[\\(libfreetype\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_freetype:+false} : -then : - ac_cv_lib_soname_freetype=`$LDD conftest$ac_exeext | grep "libfreetype\\.$LIBEXT" | sed -e "s/^.*\(libfreetype\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_freetype= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_freetype:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - FREETYPE_LIBS="" -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_freetype" >&5 -printf "%s\n" "$ac_cv_lib_soname_freetype" >&6; } - -printf "%s\n" "#define SONAME_LIBFREETYPE \"$ac_cv_lib_soname_freetype\"" >>confdefs.h - - -printf "%s\n" "#define HAVE_FREETYPE 1" >>confdefs.h - - ac_fn_c_check_type "$LINENO" "FT_TrueTypeEngineType" "ac_cv_type_FT_TrueTypeEngineType" "#include -#include FT_MODULE_H -" -if test "x$ac_cv_type_FT_TrueTypeEngineType" = xyes -then : - -printf "%s\n" "#define HAVE_FT_TRUETYPEENGINETYPE 1" >>confdefs.h - - -fi - -fi - else - FREETYPE_CFLAGS="" - FREETYPE_LIBS="" - fi -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_soname_freetype" = x -then : - case "x$with_freetype" in - xno) ;; - *) as_fn_error $? "FreeType ${notice_platform}development files not found. Fonts will not be built. -Use the --without-freetype option if you really want this." "$LINENO" 5 ;; -esac -enable_fonts=${enable_fonts:-no} -fi - -ac_wine_check_funcs_save_LIBS="$LIBS" -LIBS="$LIBS $PTHREAD_LIBS" -ac_fn_c_check_func "$LINENO" "pthread_getthreadid_np" "ac_cv_func_pthread_getthreadid_np" -if test "x$ac_cv_func_pthread_getthreadid_np" = xyes -then : - printf "%s\n" "#define HAVE_PTHREAD_GETTHREADID_NP 1" >>confdefs.h - -fi - -LIBS="$ac_wine_check_funcs_save_LIBS" - -if test "x$enable_tools" != xno -a "x$with_gettextpo" = xyes -then - if test "$ac_cv_header_gettext_po_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for po_message_msgctxt in -lgettextpo" >&5 -printf %s "checking for po_message_msgctxt in -lgettextpo... " >&6; } -if test ${ac_cv_lib_gettextpo_po_message_msgctxt+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lgettextpo $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char po_message_msgctxt (); -int -main (void) -{ -return po_message_msgctxt (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_gettextpo_po_message_msgctxt=yes -else $as_nop - ac_cv_lib_gettextpo_po_message_msgctxt=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gettextpo_po_message_msgctxt" >&5 -printf "%s\n" "$ac_cv_lib_gettextpo_po_message_msgctxt" >&6; } -if test "x$ac_cv_lib_gettextpo_po_message_msgctxt" = xyes -then : - -printf "%s\n" "#define HAVE_LIBGETTEXTPO 1" >>confdefs.h - - GETTEXTPO_LIBS="-lgettextpo" - -fi - - fi - if test "x$GETTEXTPO_LIBS" = "x" -then : - case "x$with_gettextpo" in - x) as_fn_append wine_notices "|GetText ${notice_platform}development files not found (or too old), po files can't be rebuilt." ;; - xno) ;; - *) as_fn_error $? "GetText ${notice_platform}development files not found (or too old), po files can't be rebuilt. -This is an error since --with-gettextpo was requested." "$LINENO" 5 ;; -esac - -fi - if test "$srcdir" != . -then : - case "x$with_gettextpo" in - x) as_fn_append wine_notices "|Rebuilding po files is not supported for out of tree builds." ;; - xno) ;; - *) as_fn_error $? "Rebuilding po files is not supported for out of tree builds. -This is an error since --with-gettextpo was requested." "$LINENO" 5 ;; -esac - -fi -fi - -if test "x$with_pulse" != "xno"; -then - rm -f conftest.err -if ${PULSE_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - PULSE_CFLAGS=`$PKG_CONFIG --cflags libpulse 2>conftest.err` -fi -fi - -if ${PULSE_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - PULSE_LIBS=`$PKG_CONFIG --libs libpulse 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libpulse cflags: $PULSE_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libpulse libs: $PULSE_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: libpulse errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $PULSE_CFLAGS" - for ac_header in pulse/pulseaudio.h -do : - ac_fn_c_check_header_compile "$LINENO" "pulse/pulseaudio.h" "ac_cv_header_pulse_pulseaudio_h" "$ac_includes_default" -if test "x$ac_cv_header_pulse_pulseaudio_h" = xyes -then : - printf "%s\n" "#define HAVE_PULSE_PULSEAUDIO_H 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pa_stream_is_corked in -lpulse" >&5 -printf %s "checking for pa_stream_is_corked in -lpulse... " >&6; } -if test ${ac_cv_lib_pulse_pa_stream_is_corked+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lpulse $PULSE_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char pa_stream_is_corked (); -int -main (void) -{ -return pa_stream_is_corked (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_pulse_pa_stream_is_corked=yes -else $as_nop - ac_cv_lib_pulse_pa_stream_is_corked=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pulse_pa_stream_is_corked" >&5 -printf "%s\n" "$ac_cv_lib_pulse_pa_stream_is_corked" >&6; } -if test "x$ac_cv_lib_pulse_pa_stream_is_corked" = xyes -then : - : -else $as_nop - PULSE_LIBS="" -fi - -else $as_nop - PULSE_LIBS="" -fi - -done -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test -z "$PULSE_LIBS" -then : - case "x$with_pulse" in - x) as_fn_append wine_notices "|libpulse ${notice_platform}development files not found or too old, Pulse won't be supported." ;; - xno) ;; - *) as_fn_error $? "libpulse ${notice_platform}development files not found or too old, Pulse won't be supported. -This is an error since --with-pulse was requested." "$LINENO" 5 ;; -esac -enable_winepulse_drv=${enable_winepulse_drv:-no} -fi - -if test "x$with_gstreamer" != "xno" -then - rm -f conftest.err -if ${GSTREAMER_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GSTREAMER_CFLAGS=`$PKG_CONFIG --cflags gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 2>conftest.err` -fi -fi - -if ${GSTREAMER_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GSTREAMER_LIBS=`$PKG_CONFIG --libs gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 cflags: $GSTREAMER_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 libs: $GSTREAMER_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $GSTREAMER_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "gst/gst.h" "ac_cv_header_gst_gst_h" "$ac_includes_default" -if test "x$ac_cv_header_gst_gst_h" = xyes -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether gint64 defined by gst/gst.h is indeed 64-bit" >&5 -printf %s "checking whether gint64 defined by gst/gst.h is indeed 64-bit... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -static int a[sizeof(gint64) > 4 ? 1 : -1]; if (a[0]) return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gst_pad_new in -lgstreamer-1.0" >&5 -printf %s "checking for gst_pad_new in -lgstreamer-1.0... " >&6; } -if test ${ac_cv_lib_gstreamer_1_0_gst_pad_new+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lgstreamer-1.0 $GSTREAMER_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char gst_pad_new (); -int -main (void) -{ -return gst_pad_new (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_gstreamer_1_0_gst_pad_new=yes -else $as_nop - ac_cv_lib_gstreamer_1_0_gst_pad_new=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gstreamer_1_0_gst_pad_new" >&5 -printf "%s\n" "$ac_cv_lib_gstreamer_1_0_gst_pad_new" >&6; } -if test "x$ac_cv_lib_gstreamer_1_0_gst_pad_new" = xyes -then : - : -fi - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } - ac_glib2_broken=yes - as_fn_append wine_notices "|glib-2.0 pkgconfig configuration is for the wrong architecture, winegstreamer won't be built." -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_glib2_broken" != xyes -a "x$ac_cv_lib_gstreamer_1_0_gst_pad_new" != xyes -then : - case "x$with_gstreamer" in - x) as_fn_append wine_notices "|gstreamer-1.0 base plugins ${notice_platform}development files not found, GStreamer won't be supported." ;; - xno) ;; - *) as_fn_error $? "gstreamer-1.0 base plugins ${notice_platform}development files not found, GStreamer won't be supported. -This is an error since --with-gstreamer was requested." "$LINENO" 5 ;; -esac -enable_winegstreamer=${enable_winegstreamer:-no} -fi - -ALSA_LIBS="" - -if test "x$with_alsa" != "xno" -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for snd_pcm_hw_params_get_access_mask in -lasound" >&5 -printf %s "checking for snd_pcm_hw_params_get_access_mask in -lasound... " >&6; } -if test ${ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lasound $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char snd_pcm_hw_params_get_access_mask (); -int -main (void) -{ -return snd_pcm_hw_params_get_access_mask (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask=yes -else $as_nop - ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask" >&5 -printf "%s\n" "$ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask" >&6; } -if test "x$ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask" = xyes -then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -snd_pcm_hw_params_get_access_mask(NULL, NULL) - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ALSA_LIBS="-lasound" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -test -n "$ALSA_LIBS" || enable_winealsa_drv=${enable_winealsa_drv:-no} - -if test "x$with_oss" != xno -then - ac_save_CPPFLAGS="$CPPFLAGS" - if test -f /etc/oss.conf - then - . /etc/oss.conf - fi - ac_oss_incl="-I${OSSLIBDIR:-/usr/lib/oss}/include" - CPPFLAGS="$CPPFLAGS $ac_oss_incl" - ac_fn_c_check_header_compile "$LINENO" "sys/soundcard.h" "ac_cv_header_sys_soundcard_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_soundcard_h" = xyes -then : - ac_fn_c_check_member "$LINENO" "oss_sysinfo" "numaudioengines" "ac_cv_member_oss_sysinfo_numaudioengines" "#include -" -if test "x$ac_cv_member_oss_sysinfo_numaudioengines" = xyes -then : - -printf "%s\n" "#define HAVE_OSS_SYSINFO_NUMAUDIOENGINES 1" >>confdefs.h - -OSS4_CFLAGS="$ac_oss_incl" - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _oss_ioctl in -lossaudio" >&5 -printf %s "checking for _oss_ioctl in -lossaudio... " >&6; } -if test ${ac_cv_lib_ossaudio__oss_ioctl+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lossaudio $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char _oss_ioctl (); -int -main (void) -{ -return _oss_ioctl (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_ossaudio__oss_ioctl=yes -else $as_nop - ac_cv_lib_ossaudio__oss_ioctl=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ossaudio__oss_ioctl" >&5 -printf "%s\n" "$ac_cv_lib_ossaudio__oss_ioctl" >&6; } -if test "x$ac_cv_lib_ossaudio__oss_ioctl" = xyes -then : - OSS4_LIBS="-lossaudio" - -fi - -fi - -fi - - CPPFLAGS="$ac_save_CPPFLAGS" -fi -if test "x$ac_cv_member_oss_sysinfo_numaudioengines" != xyes -then : - case "x$with_oss" in - x) as_fn_append wine_notices "|OSS sound system found but too old (OSSv4 needed), OSS won't be supported." ;; - xno) ;; - *) as_fn_error $? "OSS sound system found but too old (OSSv4 needed), OSS won't be supported. -This is an error since --with-oss was requested." "$LINENO" 5 ;; -esac -enable_wineoss_drv=${enable_wineoss_drv:-no} -fi - -if test "x$with_udev" != "xno" -then - rm -f conftest.err -if ${UDEV_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - UDEV_CFLAGS=`$PKG_CONFIG --cflags libudev 2>conftest.err` -fi -fi - -if ${UDEV_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - UDEV_LIBS=`$PKG_CONFIG --libs libudev 2>/dev/null` -fi -fi - -UDEV_LIBS=${UDEV_LIBS:-"-ludev"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libudev cflags: $UDEV_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libudev libs: $UDEV_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: libudev errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $UDEV_CFLAGS" - for ac_header in libudev.h -do : - ac_fn_c_check_header_compile "$LINENO" "libudev.h" "ac_cv_header_libudev_h" "$ac_includes_default" -if test "x$ac_cv_header_libudev_h" = xyes -then : - printf "%s\n" "#define HAVE_LIBUDEV_H 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for udev_new in -ludev" >&5 -printf %s "checking for udev_new in -ludev... " >&6; } -if test ${ac_cv_lib_udev_udev_new+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-ludev $UDEV_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char udev_new (); -int -main (void) -{ -return udev_new (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_udev_udev_new=yes -else $as_nop - ac_cv_lib_udev_udev_new=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_udev_udev_new" >&5 -printf "%s\n" "$ac_cv_lib_udev_udev_new" >&6; } -if test "x$ac_cv_lib_udev_udev_new" = xyes -then : - -printf "%s\n" "#define HAVE_UDEV 1" >>confdefs.h - -else $as_nop - UDEV_LIBS="" -fi - -else $as_nop - UDEV_LIBS="" -fi - -done -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$UDEV_LIBS" = "x" -then : - case "x$with_udev" in - x) as_fn_append wine_notices "|libudev ${notice_platform}development files not found, plug and play won't be supported." ;; - xno) ;; - *) as_fn_error $? "libudev ${notice_platform}development files not found, plug and play won't be supported. -This is an error since --with-udev was requested." "$LINENO" 5 ;; -esac - -fi - -if test "x$with_unwind" != xno -then - rm -f conftest.err -if ${UNWIND_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - UNWIND_CFLAGS=`$PKG_CONFIG --cflags libunwind 2>conftest.err` -fi -fi - -if ${UNWIND_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - UNWIND_LIBS=`$PKG_CONFIG --libs libunwind 2>/dev/null` -fi -fi - -UNWIND_LIBS=${UNWIND_LIBS:-"-lunwind"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libunwind cflags: $UNWIND_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: libunwind libs: $UNWIND_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: libunwind errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $UNWIND_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for unw_step" >&5 -printf %s "checking for unw_step... " >&6; } -if test ${wine_cv_have_unw_step+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#define UNW_LOCAL_ONLY -#include -int -main (void) -{ -unw_cursor_t cursor; unw_step( &cursor ); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - wine_cv_have_unw_step="yes" -else $as_nop - wine_cv_have_unw_step="no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_have_unw_step" >&5 -printf "%s\n" "$wine_cv_have_unw_step" >&6; } - if test "$wine_cv_have_unw_step" = no -a -n "$UNWIND_LIBS" - then - save_libs=$LIBS - UNWIND_LIBS="-static-libgcc $UNWIND_LIBS" - LIBS="$UNWIND_LIBS $LIBS" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for unw_step in libunwind" >&5 -printf %s "checking for unw_step in libunwind... " >&6; } -if test ${wine_cv_have_libunwind_unw_step+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#define UNW_LOCAL_ONLY -#include -int -main (void) -{ -unw_cursor_t cursor; unw_step( &cursor ); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - wine_cv_have_libunwind_unw_step="yes" -else $as_nop - wine_cv_have_libunwind_unw_step="no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_have_libunwind_unw_step" >&5 -printf "%s\n" "$wine_cv_have_libunwind_unw_step" >&6; } - LIBS=$save_libs - fi - test "$wine_cv_have_libunwind_unw_step" = yes || UNWIND_LIBS="" - if test "x$wine_cv_have_unw_step$wine_cv_have_libunwind_unw_step" != xnono - then - -printf "%s\n" "#define HAVE_LIBUNWIND 1" >>confdefs.h - - fi -CPPFLAGS=$ac_save_CPPFLAGS - -fi -case $host in - aarch64*|*-darwin*) - if test "x$wine_cv_have_unw_step$wine_cv_have_libunwind_unw_step" = xnono -then : - case "x$with_unwind" in - x) as_fn_append wine_notices "|libunwind ${notice_platform}development files not found, stack unwinding won't work." ;; - xno) ;; - *) as_fn_error $? "libunwind ${notice_platform}development files not found, stack unwinding won't work. -This is an error since --with-unwind was requested." "$LINENO" 5 ;; -esac - -fi ;; -esac - -if test "x$with_sdl" != "xno" -then - rm -f conftest.err -if ${SDL2_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - SDL2_CFLAGS=`$PKG_CONFIG --cflags sdl2 2>conftest.err` -fi -fi - -if ${SDL2_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - SDL2_LIBS=`$PKG_CONFIG --libs sdl2 2>/dev/null` -fi -fi - -SDL2_LIBS=${SDL2_LIBS:-"-lSDL2"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: sdl2 cflags: $SDL2_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: sdl2 libs: $SDL2_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: sdl2 errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $SDL2_CFLAGS" - for ac_header in SDL.h -do : - ac_fn_c_check_header_compile "$LINENO" "SDL.h" "ac_cv_header_SDL_h" "$ac_includes_default" -if test "x$ac_cv_header_SDL_h" = xyes -then : - printf "%s\n" "#define HAVE_SDL_H 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lSDL2" >&5 -printf %s "checking for -lSDL2... " >&6; } -if test ${ac_cv_lib_soname_SDL2+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lSDL2 $SDL2_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char SDL_Init (); -int -main (void) -{ -return SDL_Init (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_SDL2=`$ac_cv_path_LDD conftest.exe | grep "SDL2" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_SDL2=`$OTOOL -L conftest$ac_exeext | grep "libSDL2-2.0*\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libSDL2-2.0*\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_SDL2=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libSDL2-2.0*\\.$LIBEXT" | sed -e "s/^.*\\[\\(libSDL2-2.0*\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_SDL2:+false} : -then : - ac_cv_lib_soname_SDL2=`$LDD conftest$ac_exeext | grep "libSDL2-2.0*\\.$LIBEXT" | sed -e "s/^.*\(libSDL2-2.0*\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_SDL2= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_SDL2:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_SDL2" >&5 -printf "%s\n" "$ac_cv_lib_soname_SDL2" >&6; } - -printf "%s\n" "#define SONAME_LIBSDL2 \"$ac_cv_lib_soname_SDL2\"" >>confdefs.h - - -fi -fi - -done -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_soname_SDL2" = "x" -then : - case "x$with_sdl" in - x) as_fn_append wine_notices "|libSDL2 ${notice_platform}development files not found, SDL2 won't be supported." ;; - xno) ;; - *) as_fn_error $? "libSDL2 ${notice_platform}development files not found, SDL2 won't be supported. -This is an error since --with-sdl was requested." "$LINENO" 5 ;; -esac - -fi - -if test "x$with_capi" != "xno" -then - rm -f conftest.err -if ${CAPI20_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - CAPI20_CFLAGS=`$PKG_CONFIG --cflags capi20 2>conftest.err` -fi -fi - -if ${CAPI20_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - CAPI20_LIBS=`$PKG_CONFIG --libs capi20 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: capi20 cflags: $CAPI20_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: capi20 libs: $CAPI20_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: capi20 errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $CAPI20_CFLAGS" - ac_fn_c_check_header_compile "$LINENO" "capi20.h" "ac_cv_header_capi20_h" "#define __user -" -if test "x$ac_cv_header_capi20_h" = xyes -then : - printf "%s\n" "#define HAVE_CAPI20_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "linux/capi.h" "ac_cv_header_linux_capi_h" "#define __user -" -if test "x$ac_cv_header_linux_capi_h" = xyes -then : - printf "%s\n" "#define HAVE_LINUX_CAPI_H 1" >>confdefs.h - -fi - - if test "$ac_cv_header_capi20_h" = "yes" -a "$ac_cv_header_linux_capi_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for capi20_register in -lcapi20" >&5 -printf %s "checking for capi20_register in -lcapi20... " >&6; } -if test ${ac_cv_lib_capi20_capi20_register+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lcapi20 $CAPI20_LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char capi20_register (); -int -main (void) -{ -return capi20_register (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_capi20_capi20_register=yes -else $as_nop - ac_cv_lib_capi20_capi20_register=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_capi20_capi20_register" >&5 -printf "%s\n" "$ac_cv_lib_capi20_capi20_register" >&6; } -if test "x$ac_cv_lib_capi20_capi20_register" = xyes -then : - : -else $as_nop - CAPI20_LIBS="" -fi - - fi -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_capi20_capi20_register" != xyes -then : - case "x$with_capi" in - x) as_fn_append wine_notices "|libcapi20 ${notice_platform}development files not found, ISDN won't be supported." ;; - xno) ;; - *) as_fn_error $? "libcapi20 ${notice_platform}development files not found, ISDN won't be supported. -This is an error since --with-capi was requested." "$LINENO" 5 ;; -esac -enable_capi2032=${enable_capi2032:-no} -fi - -if test "x$with_cups" != "xno" -then - rm -f conftest.err -if ${CUPS_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - CUPS_CFLAGS=`$PKG_CONFIG --cflags cups 2>conftest.err` -fi -fi -test "$cross_compiling" = yes || CUPS_CFLAGS=${CUPS_CFLAGS:-`${CUPS_CONFIG:-cups-config} --cflags 2>/dev/null`} -if ${CUPS_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - CUPS_LIBS=`$PKG_CONFIG --libs cups 2>/dev/null` -fi -fi -test "$cross_compiling" = yes || CUPS_LIBS=${CUPS_LIBS:-`${CUPS_CONFIG:-cups-config} --libs 2>/dev/null`} -CUPS_LIBS=${CUPS_LIBS:-"-lcups"} -printf "%s\n" "$as_me:${as_lineno-$LINENO}: cups cflags: $CUPS_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: cups libs: $CUPS_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: cups errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $CUPS_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "cups/cups.h" "ac_cv_header_cups_cups_h" "$ac_includes_default" -if test "x$ac_cv_header_cups_cups_h" = xyes -then : - printf "%s\n" "#define HAVE_CUPS_CUPS_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "cups/ppd.h" "ac_cv_header_cups_ppd_h" "$ac_includes_default" -if test "x$ac_cv_header_cups_ppd_h" = xyes -then : - printf "%s\n" "#define HAVE_CUPS_PPD_H 1" >>confdefs.h - -fi - - if test "$ac_cv_header_cups_cups_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lcups" >&5 -printf %s "checking for -lcups... " >&6; } -if test ${ac_cv_lib_soname_cups+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lcups $CUPS_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char cupsGetDefault (); -int -main (void) -{ -return cupsGetDefault (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_cups=`$ac_cv_path_LDD conftest.exe | grep "cups" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_cups=`$OTOOL -L conftest$ac_exeext | grep "libcups\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libcups\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_cups=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libcups\\.$LIBEXT" | sed -e "s/^.*\\[\\(libcups\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_cups:+false} : -then : - ac_cv_lib_soname_cups=`$LDD conftest$ac_exeext | grep "libcups\\.$LIBEXT" | sed -e "s/^.*\(libcups\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_cups= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_cups:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - CUPS_LIBS="" -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_cups" >&5 -printf "%s\n" "$ac_cv_lib_soname_cups" >&6; } - -printf "%s\n" "#define SONAME_LIBCUPS \"$ac_cv_lib_soname_cups\"" >>confdefs.h - - -fi - else - CUPS_CFLAGS="" - CUPS_LIBS="" - fi -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_soname_cups" = "x" -then : - case "x$with_cups" in - x) as_fn_append wine_notices "|libcups ${notice_platform}development files not found, CUPS won't be supported." ;; - xno) ;; - *) as_fn_error $? "libcups ${notice_platform}development files not found, CUPS won't be supported. -This is an error since --with-cups was requested." "$LINENO" 5 ;; -esac - -fi - -if test "x$with_fontconfig" != "xno" -then - rm -f conftest.err -if ${FONTCONFIG_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - FONTCONFIG_CFLAGS=`$PKG_CONFIG --cflags fontconfig 2>conftest.err` -fi -fi -test "$cross_compiling" = yes || FONTCONFIG_CFLAGS=${FONTCONFIG_CFLAGS:-$X_CFLAGS} -if ${FONTCONFIG_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - FONTCONFIG_LIBS=`$PKG_CONFIG --libs fontconfig 2>/dev/null` -fi -fi -test "$cross_compiling" = yes || FONTCONFIG_LIBS=${FONTCONFIG_LIBS:-$X_LIBS} - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: fontconfig cflags: $FONTCONFIG_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: fontconfig libs: $FONTCONFIG_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: fontconfig errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $FONTCONFIG_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "fontconfig/fontconfig.h" "ac_cv_header_fontconfig_fontconfig_h" "$ac_includes_default" -if test "x$ac_cv_header_fontconfig_fontconfig_h" = xyes -then : - printf "%s\n" "#define HAVE_FONTCONFIG_FONTCONFIG_H 1" >>confdefs.h - -fi - - if test "$ac_cv_header_fontconfig_fontconfig_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lfontconfig" >&5 -printf %s "checking for -lfontconfig... " >&6; } -if test ${ac_cv_lib_soname_fontconfig+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lfontconfig $FONTCONFIG_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char FcInit (); -int -main (void) -{ -return FcInit (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_fontconfig=`$ac_cv_path_LDD conftest.exe | grep "fontconfig" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_fontconfig=`$OTOOL -L conftest$ac_exeext | grep "libfontconfig\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libfontconfig\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_fontconfig=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libfontconfig\\.$LIBEXT" | sed -e "s/^.*\\[\\(libfontconfig\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_fontconfig:+false} : -then : - ac_cv_lib_soname_fontconfig=`$LDD conftest$ac_exeext | grep "libfontconfig\\.$LIBEXT" | sed -e "s/^.*\(libfontconfig\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_fontconfig= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_fontconfig:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - FONTCONFIG_CFLAGS="" -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_fontconfig" >&5 -printf "%s\n" "$ac_cv_lib_soname_fontconfig" >&6; } - -printf "%s\n" "#define SONAME_LIBFONTCONFIG \"$ac_cv_lib_soname_fontconfig\"" >>confdefs.h - - -fi - else - FONTCONFIG_CFLAGS="" - fi -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_soname_fontconfig" = "x" -then : - case "x$with_fontconfig" in - x) as_fn_append wine_notices "|fontconfig ${notice_platform}development files not found, fontconfig won't be supported." ;; - xno) ;; - *) as_fn_error $? "fontconfig ${notice_platform}development files not found, fontconfig won't be supported. -This is an error since --with-fontconfig was requested." "$LINENO" 5 ;; -esac - -fi - -if test "x$with_krb5" != "xno" -then - rm -f conftest.err -if ${KRB5_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - KRB5_CFLAGS=`$PKG_CONFIG --cflags krb5 2>conftest.err` -fi -fi -test "$cross_compiling" = yes || KRB5_CFLAGS=${KRB5_CFLAGS:-`${KRB5_CONFIG:-krb5-config} --cflags 2>/dev/null`} -if ${KRB5_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - KRB5_LIBS=`$PKG_CONFIG --libs krb5 2>/dev/null` -fi -fi -test "$cross_compiling" = yes || KRB5_LIBS=${KRB5_LIBS:-`${KRB5_CONFIG:-krb5-config} --libs 2>/dev/null`} - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: krb5 cflags: $KRB5_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: krb5 libs: $KRB5_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: krb5 errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $KRB5_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "krb5/krb5.h" "ac_cv_header_krb5_krb5_h" "$ac_includes_default" -if test "x$ac_cv_header_krb5_krb5_h" = xyes -then : - printf "%s\n" "#define HAVE_KRB5_KRB5_H 1" >>confdefs.h - -fi - - if test "$ac_cv_header_krb5_krb5_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lkrb5" >&5 -printf %s "checking for -lkrb5... " >&6; } -if test ${ac_cv_lib_soname_krb5+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lkrb5 $KRB5_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char krb5_is_config_principal (); -int -main (void) -{ -return krb5_is_config_principal (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_krb5=`$ac_cv_path_LDD conftest.exe | grep "krb5" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_krb5=`$OTOOL -L conftest$ac_exeext | grep "libkrb5\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libkrb5\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_krb5=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libkrb5\\.$LIBEXT" | sed -e "s/^.*\\[\\(libkrb5\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_krb5:+false} : -then : - ac_cv_lib_soname_krb5=`$LDD conftest$ac_exeext | grep "libkrb5\\.$LIBEXT" | sed -e "s/^.*\(libkrb5\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_krb5= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_krb5:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - KRB5_CFLAGS="" -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_krb5" >&5 -printf "%s\n" "$ac_cv_lib_soname_krb5" >&6; } - -printf "%s\n" "#define SONAME_LIBKRB5 \"$ac_cv_lib_soname_krb5\"" >>confdefs.h - - -fi - else - KRB5_CFLAGS="" - fi -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_soname_krb5" = "x" -then : - case "x$with_krb5" in - x) as_fn_append wine_notices "|libkrb5 ${notice_platform}development files not found (or too old), Kerberos won't be supported." ;; - xno) ;; - *) as_fn_error $? "libkrb5 ${notice_platform}development files not found (or too old), Kerberos won't be supported. -This is an error since --with-krb5 was requested." "$LINENO" 5 ;; -esac - -fi -test "x$ac_cv_lib_soname_krb5" != "x" || with_gssapi=${with_gssapi:-no} - -if test "x$with_gssapi" != "xno" -then - rm -f conftest.err -if ${GSSAPI_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GSSAPI_CFLAGS=`$PKG_CONFIG --cflags krb5-gssapi 2>conftest.err` -fi -fi -test "$cross_compiling" = yes || GSSAPI_CFLAGS=${GSSAPI_CFLAGS:-`${KRB5_CONFIG:-krb5-config} --cflags gssapi 2>/dev/null`} -if ${GSSAPI_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - GSSAPI_LIBS=`$PKG_CONFIG --libs krb5-gssapi 2>/dev/null` -fi -fi -test "$cross_compiling" = yes || GSSAPI_LIBS=${GSSAPI_LIBS:-`${KRB5_CONFIG:-krb5-config} --libs gssapi 2>/dev/null`} - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: krb5-gssapi cflags: $GSSAPI_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: krb5-gssapi libs: $GSSAPI_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: krb5-gssapi errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $GSSAPI_CFLAGS" -ac_fn_c_check_header_compile "$LINENO" "gssapi/gssapi.h" "ac_cv_header_gssapi_gssapi_h" "$ac_includes_default" -if test "x$ac_cv_header_gssapi_gssapi_h" = xyes -then : - printf "%s\n" "#define HAVE_GSSAPI_GSSAPI_H 1" >>confdefs.h - -fi -ac_fn_c_check_header_compile "$LINENO" "gssapi/gssapi_ext.h" "ac_cv_header_gssapi_gssapi_ext_h" "$ac_includes_default" -if test "x$ac_cv_header_gssapi_gssapi_ext_h" = xyes -then : - printf "%s\n" "#define HAVE_GSSAPI_GSSAPI_EXT_H 1" >>confdefs.h - -fi - - if test "$ac_cv_header_gssapi_gssapi_h" = "yes" -a "$ac_cv_header_gssapi_gssapi_ext_h" = "yes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lgssapi_krb5" >&5 -printf %s "checking for -lgssapi_krb5... " >&6; } -if test ${ac_cv_lib_soname_gssapi_krb5+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lgssapi_krb5 $GSSAPI_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char gss_init_sec_context (); -int -main (void) -{ -return gss_init_sec_context (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_gssapi_krb5=`$ac_cv_path_LDD conftest.exe | grep "gssapi_krb5" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_gssapi_krb5=`$OTOOL -L conftest$ac_exeext | grep "libgssapi_krb5\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libgssapi_krb5\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_gssapi_krb5=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libgssapi_krb5\\.$LIBEXT" | sed -e "s/^.*\\[\\(libgssapi_krb5\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_gssapi_krb5:+false} : -then : - ac_cv_lib_soname_gssapi_krb5=`$LDD conftest$ac_exeext | grep "libgssapi_krb5\\.$LIBEXT" | sed -e "s/^.*\(libgssapi_krb5\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_gssapi_krb5= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_gssapi_krb5:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - GSSAPI_CFLAGS="" -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_gssapi_krb5" >&5 -printf "%s\n" "$ac_cv_lib_soname_gssapi_krb5" >&6; } - -printf "%s\n" "#define SONAME_LIBGSSAPI_KRB5 \"$ac_cv_lib_soname_gssapi_krb5\"" >>confdefs.h - - -fi - else - GSSAPI_CFLAGS="" - fi -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_soname_gssapi_krb5" = "x" -then : - case "x$with_gssapi" in - x) as_fn_append wine_notices "|libgssapi_krb5 ${notice_platform}development files not found (or too old), no Kerberos SSP support." ;; - xno) ;; - *) as_fn_error $? "libgssapi_krb5 ${notice_platform}development files not found (or too old), no Kerberos SSP support. -This is an error since --with-gssapi was requested." "$LINENO" 5 ;; -esac - -fi - -if test "$ac_cv_header_libprocstat_h" = "yes" -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for procstat_open_sysctl in -lprocstat" >&5 -printf %s "checking for procstat_open_sysctl in -lprocstat... " >&6; } -if test ${ac_cv_lib_procstat_procstat_open_sysctl+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS -LIBS="-lprocstat $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char procstat_open_sysctl (); -int -main (void) -{ -return procstat_open_sysctl (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_lib_procstat_procstat_open_sysctl=yes -else $as_nop - ac_cv_lib_procstat_procstat_open_sysctl=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_procstat_procstat_open_sysctl" >&5 -printf "%s\n" "$ac_cv_lib_procstat_procstat_open_sysctl" >&6; } -if test "x$ac_cv_lib_procstat_procstat_open_sysctl" = xyes -then : - -printf "%s\n" "#define HAVE_LIBPROCSTAT 1" >>confdefs.h - - PROCSTAT_LIBS="-lprocstat" - -fi - -fi - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lodbc" >&5 -printf %s "checking for -lodbc... " >&6; } -if test ${ac_cv_lib_soname_odbc+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lodbc $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char SQLConnect (); -int -main (void) -{ -return SQLConnect (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_odbc=`$ac_cv_path_LDD conftest.exe | grep "odbc" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_odbc=`$OTOOL -L conftest$ac_exeext | grep "libodbc\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libodbc\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_odbc=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libodbc\\.$LIBEXT" | sed -e "s/^.*\\[\\(libodbc\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_odbc:+false} : -then : - ac_cv_lib_soname_odbc=`$LDD conftest$ac_exeext | grep "libodbc\\.$LIBEXT" | sed -e "s/^.*\(libodbc\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_odbc= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_odbc:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - printf "%s\n" "#define SONAME_LIBODBC \"libodbc.$LIBEXT\"" >>confdefs.h - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_odbc" >&5 -printf "%s\n" "$ac_cv_lib_soname_odbc" >&6; } - -printf "%s\n" "#define SONAME_LIBODBC \"$ac_cv_lib_soname_odbc\"" >>confdefs.h - - -fi - -if test "x$with_netapi" != "xno" -then - rm -f conftest.err -if ${NETAPI_CFLAGS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - NETAPI_CFLAGS=`$PKG_CONFIG --cflags netapi 2>conftest.err` -fi -fi - -if ${NETAPI_LIBS:+false} : -then : - if test ${PKG_CONFIG+y} -then : - NETAPI_LIBS=`$PKG_CONFIG --libs netapi 2>/dev/null` -fi -fi - - -printf "%s\n" "$as_me:${as_lineno-$LINENO}: netapi cflags: $NETAPI_CFLAGS" >&5 -printf "%s\n" "$as_me:${as_lineno-$LINENO}: netapi libs: $NETAPI_LIBS" >&5 -if test -s conftest.err; then - printf %s "$as_me:${as_lineno-$LINENO}: netapi errors: " >&5 - cat conftest.err >&5 -fi -rm -f conftest.err -ac_save_CPPFLAGS=$CPPFLAGS -CPPFLAGS="$CPPFLAGS $NETAPI_CFLAGS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lnetapi" >&5 -printf %s "checking for -lnetapi... " >&6; } -if test ${ac_cv_lib_soname_netapi+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lnetapi $NETAPI_LIBS $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char libnetapi_init (); -int -main (void) -{ -return libnetapi_init (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_netapi=`$ac_cv_path_LDD conftest.exe | grep "netapi" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_netapi=`$OTOOL -L conftest$ac_exeext | grep "libnetapi\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libnetapi\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_netapi=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libnetapi\\.$LIBEXT" | sed -e "s/^.*\\[\\(libnetapi\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_netapi:+false} : -then : - ac_cv_lib_soname_netapi=`$LDD conftest$ac_exeext | grep "libnetapi\\.$LIBEXT" | sed -e "s/^.*\(libnetapi\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_netapi= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_netapi:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - printf "%s\n" "#define SONAME_LIBNETAPI \"libnetapi.$LIBEXT\"" >>confdefs.h - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_netapi" >&5 -printf "%s\n" "$ac_cv_lib_soname_netapi" >&6; } - -printf "%s\n" "#define SONAME_LIBNETAPI \"$ac_cv_lib_soname_netapi\"" >>confdefs.h - - -fi -CPPFLAGS=$ac_save_CPPFLAGS - -fi -if test "x$ac_cv_lib_soname_netapi" = "x" -then : - case "x$with_netapi" in - x) as_fn_append wine_notices "|libnetapi not found, Samba NetAPI won't be supported." ;; - xno) ;; - *) as_fn_error $? "libnetapi not found, Samba NetAPI won't be supported. -This is an error since --with-netapi was requested." "$LINENO" 5 ;; -esac -enable_netapi=${enable_netapi:-no} -fi - - -if test "x$enable_winealsa_drv$enable_winecoreaudio_drv$enable_winepulse_drv$enable_wineoss_drv$enable_wineandroid_drv" = xnonononono -a \ - "x$with_alsa$with_coreaudio$with_oss$with_pulse" != xnononono -then - as_fn_append wine_warnings "|No sound system was found. Windows applications will be silent." -fi - -if test "x$with_vulkan" != "xno" -then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lvulkan" >&5 -printf %s "checking for -lvulkan... " >&6; } -if test ${ac_cv_lib_soname_vulkan+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lvulkan $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char vkGetInstanceProcAddr (); -int -main (void) -{ -return vkGetInstanceProcAddr (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_vulkan=`$ac_cv_path_LDD conftest.exe | grep "vulkan" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_vulkan=`$OTOOL -L conftest$ac_exeext | grep "libvulkan\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libvulkan\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_vulkan=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libvulkan\\.$LIBEXT" | sed -e "s/^.*\\[\\(libvulkan\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_vulkan:+false} : -then : - ac_cv_lib_soname_vulkan=`$LDD conftest$ac_exeext | grep "libvulkan\\.$LIBEXT" | sed -e "s/^.*\(libvulkan\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_vulkan= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_vulkan:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_vulkan" >&5 -printf "%s\n" "$ac_cv_lib_soname_vulkan" >&6; } - -printf "%s\n" "#define SONAME_LIBVULKAN \"$ac_cv_lib_soname_vulkan\"" >>confdefs.h - - -fi - if test "x$ac_cv_lib_soname_vulkan" = "x" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -lMoltenVK" >&5 -printf %s "checking for -lMoltenVK... " >&6; } -if test ${ac_cv_lib_soname_MoltenVK+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_check_soname_save_LIBS=$LIBS -LIBS="-lMoltenVK $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char vkGetInstanceProcAddr (); -int -main (void) -{ -return vkGetInstanceProcAddr (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - case "$LIBEXT" in - dll) ac_cv_lib_soname_MoltenVK=`$ac_cv_path_LDD conftest.exe | grep "MoltenVK" | sed -e "s/dll.*/dll/"';2,$d'` ;; - dylib) ac_cv_lib_soname_MoltenVK=`$OTOOL -L conftest$ac_exeext | grep "libMoltenVK\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libMoltenVK\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; - *) ac_cv_lib_soname_MoltenVK=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libMoltenVK\\.$LIBEXT" | sed -e "s/^.*\\[\\(libMoltenVK\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` - if ${ac_cv_lib_soname_MoltenVK:+false} : -then : - ac_cv_lib_soname_MoltenVK=`$LDD conftest$ac_exeext | grep "libMoltenVK\\.$LIBEXT" | sed -e "s/^.*\(libMoltenVK\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -fi ;; - esac -else $as_nop - ac_cv_lib_soname_MoltenVK= -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - LIBS=$ac_check_soname_save_LIBS -fi -if ${ac_cv_lib_soname_MoltenVK:+false} : -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -printf "%s\n" "not found" >&6; } - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_MoltenVK" >&5 -printf "%s\n" "$ac_cv_lib_soname_MoltenVK" >&6; } - -printf "%s\n" "#define SONAME_LIBMOLTENVK \"$ac_cv_lib_soname_MoltenVK\"" >>confdefs.h - - -fi - fi -fi -if test "x$ac_cv_lib_soname_vulkan" = "x" -a "x$ac_cv_lib_soname_MoltenVK" = "x" -then : - case "x$with_vulkan" in - x) as_fn_append wine_notices "|libvulkan and libMoltenVK ${notice_platform}development files not found, Vulkan won't be supported." ;; - xno) ;; - *) as_fn_error $? "libvulkan and libMoltenVK ${notice_platform}development files not found, Vulkan won't be supported. -This is an error since --with-vulkan was requested." "$LINENO" 5 ;; -esac - -fi - - -if test "x${GCC}" = "xyes" -then - EXTRACFLAGS="$EXTRACFLAGS -Wall -pipe" - - saved_CFLAGS=$CFLAGS - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Werror=unknown-warning-option" >&5 -printf %s "checking whether the compiler supports -Werror=unknown-warning-option... " >&6; } -if test ${ac_cv_cflags__Werror_unknown_warning_option+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Werror=unknown-warning-option" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Werror_unknown_warning_option=yes -else $as_nop - ac_cv_cflags__Werror_unknown_warning_option=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Werror_unknown_warning_option" >&5 -printf "%s\n" "$ac_cv_cflags__Werror_unknown_warning_option" >&6; } -if test "x$ac_cv_cflags__Werror_unknown_warning_option" = xyes -then : - CFLAGS="$CFLAGS -Werror=unknown-warning-option" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Werror=unused-command-line-argument" >&5 -printf %s "checking whether the compiler supports -Werror=unused-command-line-argument... " >&6; } -if test ${ac_cv_cflags__Werror_unused_command_line_argument+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Werror=unused-command-line-argument" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Werror_unused_command_line_argument=yes -else $as_nop - ac_cv_cflags__Werror_unused_command_line_argument=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Werror_unused_command_line_argument" >&5 -printf "%s\n" "$ac_cv_cflags__Werror_unused_command_line_argument" >&6; } -if test "x$ac_cv_cflags__Werror_unused_command_line_argument" = xyes -then : - CFLAGS="$CFLAGS -Werror=unused-command-line-argument" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Werror=ignored-optimization-argument" >&5 -printf %s "checking whether the compiler supports -Werror=ignored-optimization-argument... " >&6; } -if test ${ac_cv_cflags__Werror_ignored_optimization_argument+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Werror=ignored-optimization-argument" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Werror_ignored_optimization_argument=yes -else $as_nop - ac_cv_cflags__Werror_ignored_optimization_argument=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Werror_ignored_optimization_argument" >&5 -printf "%s\n" "$ac_cv_cflags__Werror_ignored_optimization_argument" >&6; } -if test "x$ac_cv_cflags__Werror_ignored_optimization_argument" = xyes -then : - CFLAGS="$CFLAGS -Werror=ignored-optimization-argument" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fcf-protection=none" >&5 -printf %s "checking whether the compiler supports -fcf-protection=none... " >&6; } -if test ${ac_cv_cflags__fcf_protection_none+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -fcf-protection=none" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__fcf_protection_none=yes -else $as_nop - ac_cv_cflags__fcf_protection_none=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fcf_protection_none" >&5 -printf "%s\n" "$ac_cv_cflags__fcf_protection_none" >&6; } -if test "x$ac_cv_cflags__fcf_protection_none" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -fcf-protection=none" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fno-stack-protector" >&5 -printf %s "checking whether the compiler supports -fno-stack-protector... " >&6; } -if test ${ac_cv_cflags__fno_stack_protector+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -fno-stack-protector" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__fno_stack_protector=yes -else $as_nop - ac_cv_cflags__fno_stack_protector=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fno_stack_protector" >&5 -printf "%s\n" "$ac_cv_cflags__fno_stack_protector" >&6; } -if test "x$ac_cv_cflags__fno_stack_protector" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -fno-stack-protector" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fno-strict-aliasing" >&5 -printf %s "checking whether the compiler supports -fno-strict-aliasing... " >&6; } -if test ${ac_cv_cflags__fno_strict_aliasing+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -fno-strict-aliasing" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__fno_strict_aliasing=yes -else $as_nop - ac_cv_cflags__fno_strict_aliasing=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fno_strict_aliasing" >&5 -printf "%s\n" "$ac_cv_cflags__fno_strict_aliasing" >&6; } -if test "x$ac_cv_cflags__fno_strict_aliasing" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -fno-strict-aliasing" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wdeclaration-after-statement" >&5 -printf %s "checking whether the compiler supports -Wdeclaration-after-statement... " >&6; } -if test ${ac_cv_cflags__Wdeclaration_after_statement+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wdeclaration-after-statement" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wdeclaration_after_statement=yes -else $as_nop - ac_cv_cflags__Wdeclaration_after_statement=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wdeclaration_after_statement" >&5 -printf "%s\n" "$ac_cv_cflags__Wdeclaration_after_statement" >&6; } -if test "x$ac_cv_cflags__Wdeclaration_after_statement" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wdeclaration-after-statement" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wempty-body" >&5 -printf %s "checking whether the compiler supports -Wempty-body... " >&6; } -if test ${ac_cv_cflags__Wempty_body+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wempty-body" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wempty_body=yes -else $as_nop - ac_cv_cflags__Wempty_body=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wempty_body" >&5 -printf "%s\n" "$ac_cv_cflags__Wempty_body" >&6; } -if test "x$ac_cv_cflags__Wempty_body" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wempty-body" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wignored-qualifiers" >&5 -printf %s "checking whether the compiler supports -Wignored-qualifiers... " >&6; } -if test ${ac_cv_cflags__Wignored_qualifiers+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wignored-qualifiers" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wignored_qualifiers=yes -else $as_nop - ac_cv_cflags__Wignored_qualifiers=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wignored_qualifiers" >&5 -printf "%s\n" "$ac_cv_cflags__Wignored_qualifiers" >&6; } -if test "x$ac_cv_cflags__Wignored_qualifiers" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wignored-qualifiers" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Winit-self" >&5 -printf %s "checking whether the compiler supports -Winit-self... " >&6; } -if test ${ac_cv_cflags__Winit_self+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Winit-self" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Winit_self=yes -else $as_nop - ac_cv_cflags__Winit_self=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Winit_self" >&5 -printf "%s\n" "$ac_cv_cflags__Winit_self" >&6; } -if test "x$ac_cv_cflags__Winit_self" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Winit-self" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wpacked-not-aligned" >&5 -printf %s "checking whether the compiler supports -Wpacked-not-aligned... " >&6; } -if test ${ac_cv_cflags__Wpacked_not_aligned+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wpacked-not-aligned" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wpacked_not_aligned=yes -else $as_nop - ac_cv_cflags__Wpacked_not_aligned=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wpacked_not_aligned" >&5 -printf "%s\n" "$ac_cv_cflags__Wpacked_not_aligned" >&6; } -if test "x$ac_cv_cflags__Wpacked_not_aligned" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wno-packed-not-aligned" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wpragma-pack" >&5 -printf %s "checking whether the compiler supports -Wpragma-pack... " >&6; } -if test ${ac_cv_cflags__Wpragma_pack+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wpragma-pack" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wpragma_pack=yes -else $as_nop - ac_cv_cflags__Wpragma_pack=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wpragma_pack" >&5 -printf "%s\n" "$ac_cv_cflags__Wpragma_pack" >&6; } -if test "x$ac_cv_cflags__Wpragma_pack" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wno-pragma-pack" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wshift-overflow=2" >&5 -printf %s "checking whether the compiler supports -Wshift-overflow=2... " >&6; } -if test ${ac_cv_cflags__Wshift_overflow_2+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wshift-overflow=2" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wshift_overflow_2=yes -else $as_nop - ac_cv_cflags__Wshift_overflow_2=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wshift_overflow_2" >&5 -printf "%s\n" "$ac_cv_cflags__Wshift_overflow_2" >&6; } -if test "x$ac_cv_cflags__Wshift_overflow_2" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wshift-overflow=2" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wstrict-prototypes" >&5 -printf %s "checking whether the compiler supports -Wstrict-prototypes... " >&6; } -if test ${ac_cv_cflags__Wstrict_prototypes+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wstrict-prototypes" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wstrict_prototypes=yes -else $as_nop - ac_cv_cflags__Wstrict_prototypes=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wstrict_prototypes" >&5 -printf "%s\n" "$ac_cv_cflags__Wstrict_prototypes" >&6; } -if test "x$ac_cv_cflags__Wstrict_prototypes" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wstrict-prototypes" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wtype-limits" >&5 -printf %s "checking whether the compiler supports -Wtype-limits... " >&6; } -if test ${ac_cv_cflags__Wtype_limits+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wtype-limits" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wtype_limits=yes -else $as_nop - ac_cv_cflags__Wtype_limits=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wtype_limits" >&5 -printf "%s\n" "$ac_cv_cflags__Wtype_limits" >&6; } -if test "x$ac_cv_cflags__Wtype_limits" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wtype-limits" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wunused-but-set-parameter" >&5 -printf %s "checking whether the compiler supports -Wunused-but-set-parameter... " >&6; } -if test ${ac_cv_cflags__Wunused_but_set_parameter+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wunused-but-set-parameter" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wunused_but_set_parameter=yes -else $as_nop - ac_cv_cflags__Wunused_but_set_parameter=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wunused_but_set_parameter" >&5 -printf "%s\n" "$ac_cv_cflags__Wunused_but_set_parameter" >&6; } -if test "x$ac_cv_cflags__Wunused_but_set_parameter" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wunused-but-set-parameter" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wvla" >&5 -printf %s "checking whether the compiler supports -Wvla... " >&6; } -if test ${ac_cv_cflags__Wvla+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wvla" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wvla=yes -else $as_nop - ac_cv_cflags__Wvla=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wvla" >&5 -printf "%s\n" "$ac_cv_cflags__Wvla" >&6; } -if test "x$ac_cv_cflags__Wvla" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wvla" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wwrite-strings" >&5 -printf %s "checking whether the compiler supports -Wwrite-strings... " >&6; } -if test ${ac_cv_cflags__Wwrite_strings+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wwrite-strings" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wwrite_strings=yes -else $as_nop - ac_cv_cflags__Wwrite_strings=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wwrite_strings" >&5 -printf "%s\n" "$ac_cv_cflags__Wwrite_strings" >&6; } -if test "x$ac_cv_cflags__Wwrite_strings" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wwrite-strings" -fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wpointer-arith" >&5 -printf %s "checking whether the compiler supports -Wpointer-arith... " >&6; } -if test ${ac_cv_cflags__Wpointer_arith+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wpointer-arith" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wpointer_arith=yes -else $as_nop - ac_cv_cflags__Wpointer_arith=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wpointer_arith" >&5 -printf "%s\n" "$ac_cv_cflags__Wpointer_arith" >&6; } -if test "x$ac_cv_cflags__Wpointer_arith" = xyes -then : - saved_string_h_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -Wpointer-arith -Werror" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for broken string.h that generates warnings with -Wpointer-arith" >&5 -printf %s "checking for broken string.h that generates warnings with -Wpointer-arith... " >&6; } -if test ${ac_cv_c_string_h_warnings+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_c_string_h_warnings=no -else $as_nop - ac_cv_c_string_h_warnings=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_string_h_warnings" >&5 -printf "%s\n" "$ac_cv_c_string_h_warnings" >&6; } - test "$ac_cv_c_string_h_warnings" = yes || EXTRACFLAGS="$EXTRACFLAGS -Wpointer-arith" - CFLAGS=$saved_string_h_CFLAGS -fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wlogical-op" >&5 -printf %s "checking whether the compiler supports -Wlogical-op... " >&6; } -if test ${ac_cv_cflags__Wlogical_op+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wlogical-op" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wlogical_op=yes -else $as_nop - ac_cv_cflags__Wlogical_op=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wlogical_op" >&5 -printf "%s\n" "$ac_cv_cflags__Wlogical_op" >&6; } -if test "x$ac_cv_cflags__Wlogical_op" = xyes -then : - saved_string_h_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS -Wlogical-op -Werror" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for broken string.h that generates warnings with -Wlogical-op" >&5 -printf %s "checking for broken string.h that generates warnings with -Wlogical-op... " >&6; } -if test ${ac_cv_c_logicalop_noisy+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -char*f(const char *h,char n) {return strchr(h,n);} -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_c_logicalop_noisy=no -else $as_nop - ac_cv_c_logicalop_noisy=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_logicalop_noisy" >&5 -printf "%s\n" "$ac_cv_c_logicalop_noisy" >&6; } - CFLAGS=$saved_string_h_CFLAGS - test "$ac_cv_c_logicalop_noisy" = yes || EXTRACFLAGS="$EXTRACFLAGS -Wlogical-op" -fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for flags needed for 64-bit compare-and-swap support" >&5 -printf %s "checking for flags needed for 64-bit compare-and-swap support... " >&6; } -if test ${wine_cv_64bit_compare_swap+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 -#error no -#endif -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - wine_cv_64bit_compare_swap="none needed" -else $as_nop - case $host_cpu in - *i[3456]86*) wine_cv_64bit_compare_swap="-march=i586" ;; - *arm*) wine_cv_64bit_compare_swap="-march=armv7-a" ;; - *) wine_cv_64bit_compare_swap="unknown" ;; - esac - if test "x$wine_cv_64bit_compare_swap" != xunknown - then - CFLAGS="$CFLAGS $wine_cv_64bit_compare_swap" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 -#error no -#endif -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - -else $as_nop - wine_cv_64bit_compare_swap="unknown" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CFLAGS=$saved_CFLAGS - fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_64bit_compare_swap" >&5 -printf "%s\n" "$wine_cv_64bit_compare_swap" >&6; } - case "$wine_cv_64bit_compare_swap" in - unknown) as_fn_error $? "gcc doesn't support 64-bit compare-and-swap on this platform" "$LINENO" 5 ;; - "none needed") ;; - *) EXTRACFLAGS="$EXTRACFLAGS $wine_cv_64bit_compare_swap" ;; - esac - - ac_debug_format_seen="" - for ac_flag in $CFLAGS; do - case $ac_flag in - -gdwarf*) ac_debug_format_seen=yes ;; - -g) ac_debug_format_seen=${ac_debug_format_seen:-default} ;; - esac - done - if test "x$ac_debug_format_seen" = xdefault - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -gdwarf-4" >&5 -printf %s "checking whether the compiler supports -gdwarf-4... " >&6; } -if test ${ac_cv_cflags__gdwarf_4+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -gdwarf-4" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__gdwarf_4=yes -else $as_nop - ac_cv_cflags__gdwarf_4=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__gdwarf_4" >&5 -printf "%s\n" "$ac_cv_cflags__gdwarf_4" >&6; } -if test "x$ac_cv_cflags__gdwarf_4" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -gdwarf-4" -fi - fi - - MSVCRTFLAGS="" - - case $host_os in - mingw32*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-delayload,autoconftest.dll" >&5 -printf %s "checking whether the compiler supports -Wl,-delayload,autoconftest.dll... " >&6; } -if test ${ac_cv_cflags__Wl__delayload_autoconftest_dll+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,-delayload,autoconftest.dll" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl__delayload_autoconftest_dll=yes -else $as_nop - ac_cv_cflags__Wl__delayload_autoconftest_dll=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl__delayload_autoconftest_dll" >&5 -printf "%s\n" "$ac_cv_cflags__Wl__delayload_autoconftest_dll" >&6; } -if test "x$ac_cv_cflags__Wl__delayload_autoconftest_dll" = xyes -then : - DELAYLOADFLAG="-Wl,-delayload," - -fi ;; - *) MSVCRTFLAGS="-D_WIN32" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fno-builtin" >&5 -printf %s "checking whether the compiler supports -fno-builtin... " >&6; } -if test ${ac_cv_cflags__fno_builtin+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -fno-builtin" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__fno_builtin=yes -else $as_nop - ac_cv_cflags__fno_builtin=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fno_builtin" >&5 -printf "%s\n" "$ac_cv_cflags__fno_builtin" >&6; } -if test "x$ac_cv_cflags__fno_builtin" = xyes -then : - MSVCRTFLAGS="$MSVCRTFLAGS -fno-builtin" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fshort-wchar" >&5 -printf %s "checking whether the compiler supports -fshort-wchar... " >&6; } -if test ${ac_cv_cflags__fshort_wchar+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -fshort-wchar" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__fshort_wchar=yes -else $as_nop - ac_cv_cflags__fshort_wchar=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fshort_wchar" >&5 -printf "%s\n" "$ac_cv_cflags__fshort_wchar" >&6; } -if test "x$ac_cv_cflags__fshort_wchar" = xyes -then : - MSVCRTFLAGS="$MSVCRTFLAGS -fshort-wchar" -fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wno-format" >&5 -printf %s "checking whether the compiler supports -Wno-format... " >&6; } -if test ${ac_cv_cflags__Wno_format+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wno-format" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wno_format=yes -else $as_nop - ac_cv_cflags__Wno_format=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wno_format" >&5 -printf "%s\n" "$ac_cv_cflags__Wno_format" >&6; } -if test "x$ac_cv_cflags__Wno_format" = xyes -then : - MSVCRTFLAGS="$MSVCRTFLAGS -Wno-format" -fi ;; - esac - - case $host_cpu in - *i[3456789]86*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fno-omit-frame-pointer" >&5 -printf %s "checking whether the compiler supports -fno-omit-frame-pointer... " >&6; } -if test ${ac_cv_cflags__fno_omit_frame_pointer+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -fno-omit-frame-pointer" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__fno_omit_frame_pointer=yes -else $as_nop - ac_cv_cflags__fno_omit_frame_pointer=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__fno_omit_frame_pointer" >&5 -printf "%s\n" "$ac_cv_cflags__fno_omit_frame_pointer" >&6; } -if test "x$ac_cv_cflags__fno_omit_frame_pointer" = xyes -then : - MSVCRTFLAGS="$MSVCRTFLAGS -fno-omit-frame-pointer" -fi ;; - *x86_64*) - case $host_os in - cygwin*|mingw32*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wno-format" >&5 -printf %s "checking whether the compiler supports -Wno-format... " >&6; } -if test ${ac_cv_cflags__Wno_format+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wno-format" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wno_format=yes -else $as_nop - ac_cv_cflags__Wno_format=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wno_format" >&5 -printf "%s\n" "$ac_cv_cflags__Wno_format" >&6; } -if test "x$ac_cv_cflags__Wno_format" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wno-format" -fi ;; - *) if test -z "$PE_ARCHS" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working -mabi=ms" >&5 -printf %s "checking for working -mabi=ms... " >&6; } -if test ${ac_cv_mabi_ms+y} -then : - printf %s "(cached) " >&6 -else $as_nop - CFLAGS="$CFLAGS -mabi=ms" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int a(int b, ...) { __builtin_ms_va_list list; __builtin_ms_va_start(list,b); } -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_mabi_ms=yes -else $as_nop - ac_cv_mabi_ms=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CFLAGS=$saved_CFLAGS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mabi_ms" >&5 -printf "%s\n" "$ac_cv_mabi_ms" >&6; } - test $ac_cv_mabi_ms = yes || as_fn_error $? "The compiler doesn't support -mabi=ms. Use gcc instead of clang, or install mingw-w64." "$LINENO" 5 - fi - MSVCRTFLAGS="$MSVCRTFLAGS -mabi=ms" ;; - esac ;; - arm*) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wincompatible-function-pointer-types" >&5 -printf %s "checking whether the compiler supports -Wincompatible-function-pointer-types... " >&6; } -if test ${ac_cv_cflags__Wincompatible_function_pointer_types+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wincompatible-function-pointer-types" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wincompatible_function_pointer_types=yes -else $as_nop - ac_cv_cflags__Wincompatible_function_pointer_types=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wincompatible_function_pointer_types" >&5 -printf "%s\n" "$ac_cv_cflags__Wincompatible_function_pointer_types" >&6; } -if test "x$ac_cv_cflags__Wincompatible_function_pointer_types" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Wno-error=incompatible-function-pointer-types" -fi ;; - esac - - CFLAGS=$saved_CFLAGS - - if test "x$enable_werror" = "xyes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Werror" >&5 -printf %s "checking whether the compiler supports -Werror... " >&6; } -if test ${ac_cv_cflags__Werror+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Werror" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Werror=yes -else $as_nop - ac_cv_cflags__Werror=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Werror" >&5 -printf "%s\n" "$ac_cv_cflags__Werror" >&6; } -if test "x$ac_cv_cflags__Werror" = xyes -then : - EXTRACFLAGS="$EXTRACFLAGS -Werror" -fi - fi - if test "x$enable_build_id" = "xyes" - then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,--build-id" >&5 -printf %s "checking whether the compiler supports -Wl,--build-id... " >&6; } -if test ${ac_cv_cflags__Wl___build_id+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_wine_try_cflags_saved=$CFLAGS -CFLAGS="$CFLAGS -Wl,--build-id" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int main(int argc, char **argv) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_cflags__Wl___build_id=yes -else $as_nop - ac_cv_cflags__Wl___build_id=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -CFLAGS=$ac_wine_try_cflags_saved -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl___build_id" >&5 -printf "%s\n" "$ac_cv_cflags__Wl___build_id" >&6; } -if test "x$ac_cv_cflags__Wl___build_id" = xyes -then : - CFLAGS="$CFLAGS -Wl,--build-id" - LDFLAGS="$LDFLAGS -Wl,--build-id" -fi - fi -fi - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the need to disable Fortify" >&5 -printf %s "checking for the need to disable Fortify... " >&6; } -if test ${ac_cv_c_fortify_enabled+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -#if (defined(__USE_FORTIFY_LEVEL) && __USE_FORTIFY_LEVEL > 0) || (defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0) -#error Fortify enabled -#endif - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_c_fortify_enabled=no -else $as_nop - ac_cv_c_fortify_enabled=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_fortify_enabled" >&5 -printf "%s\n" "$ac_cv_c_fortify_enabled" >&6; } -if test "$ac_cv_c_fortify_enabled" = yes -then - CFLAGS="$CFLAGS -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0" -fi - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether CFI directives are supported in assembly code" >&5 -printf %s "checking whether CFI directives are supported in assembly code... " >&6; } -if test ${ac_cv_c_cfi_support+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -asm(".text\nac_test:\t.cfi_startproc\n\t.long 0\n\t.cfi_endproc"); -int -main (void) -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_c_cfi_support="yes" -else $as_nop - ac_cv_c_cfi_support="no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_cfi_support" >&5 -printf "%s\n" "$ac_cv_c_cfi_support" >&6; } -if test "$ac_cv_c_cfi_support" = "yes" -then - DLLFLAGS="$DLLFLAGS -fasynchronous-unwind-tables" - LDDLLFLAGS="$LDDLLFLAGS -fasynchronous-unwind-tables" - UNIXDLLFLAGS="$UNIXDLLFLAGS -fasynchronous-unwind-tables" -elif test $HOST_ARCH = x86_64 -then - as_fn_append wine_warnings "|building 64-bit Wine without support for CFI directives; exception handling will not work properly." -fi - - -case "$HOST_ARCH,$PE_ARCHS" in - x86_64,*i386*) wine_binary="wine" ;; - x86_64,*) wine_binary="wine64" ;; - *) wine_binary="wine" ;; -esac -WINELOADER_PROGRAMS="$wine_binary" - - -case $host_os in - linux*) - case $host_cpu in - *i[3456789]86*|x86_64*|*aarch64*|arm*) - test "$wine_binary" = wine || as_fn_append CONFIGURE_TARGETS " loader/wine-preloader" - WINELOADER_PROGRAMS="$WINELOADER_PROGRAMS $wine_binary-preloader" - ;; - esac - ;; - darwin*|macosx*) - if test "$wine_can_build_preloader" = "yes" - then - test "$wine_binary" = wine || as_fn_append CONFIGURE_TARGETS " loader/wine-preloader" - WINELOADER_PROGRAMS="$WINELOADER_PROGRAMS $wine_binary-preloader" - fi - ;; -esac - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 -printf %s "checking for library containing dlopen... " >&6; } -if test ${ac_cv_search_dlopen+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char dlopen (); -int -main (void) -{ -return dlopen (); - ; - return 0; -} -_ACEOF -for ac_lib in '' dl -do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO" -then : - ac_cv_search_dlopen=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext - if test ${ac_cv_search_dlopen+y} -then : - break -fi -done -if test ${ac_cv_search_dlopen+y} -then : - -else $as_nop - ac_cv_search_dlopen=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 -printf "%s\n" "$ac_cv_search_dlopen" >&6; } -ac_res=$ac_cv_search_dlopen -if test "$ac_res" != no -then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing gethostbyname" >&5 -printf %s "checking for library containing gethostbyname... " >&6; } -if test ${ac_cv_search_gethostbyname+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char gethostbyname (); -int -main (void) -{ -return gethostbyname (); - ; - return 0; -} -_ACEOF -for ac_lib in '' nsl -do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO" -then : - ac_cv_search_gethostbyname=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext - if test ${ac_cv_search_gethostbyname+y} -then : - break -fi -done -if test ${ac_cv_search_gethostbyname+y} -then : - -else $as_nop - ac_cv_search_gethostbyname=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostbyname" >&5 -printf "%s\n" "$ac_cv_search_gethostbyname" >&6; } -ac_res=$ac_cv_search_gethostbyname -if test "$ac_res" != no -then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing connect" >&5 -printf %s "checking for library containing connect... " >&6; } -if test ${ac_cv_search_connect+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char connect (); -int -main (void) -{ -return connect (); - ; - return 0; -} -_ACEOF -for ac_lib in '' socket -do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO" -then : - ac_cv_search_connect=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext - if test ${ac_cv_search_connect+y} -then : - break -fi -done -if test ${ac_cv_search_connect+y} -then : - -else $as_nop - ac_cv_search_connect=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_connect" >&5 -printf "%s\n" "$ac_cv_search_connect" >&6; } -ac_res=$ac_cv_search_connect -if test "$ac_res" != no -then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing inet_aton" >&5 -printf %s "checking for library containing inet_aton... " >&6; } -if test ${ac_cv_search_inet_aton+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char inet_aton (); -int -main (void) -{ -return inet_aton (); - ; - return 0; -} -_ACEOF -for ac_lib in '' resolv -do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO" -then : - ac_cv_search_inet_aton=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext - if test ${ac_cv_search_inet_aton+y} -then : - break -fi -done -if test ${ac_cv_search_inet_aton+y} -then : - -else $as_nop - ac_cv_search_inet_aton=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inet_aton" >&5 -printf "%s\n" "$ac_cv_search_inet_aton" >&6; } -ac_res=$ac_cv_search_inet_aton -if test "$ac_res" != no -then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - - -ac_save_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS $BUILTINFLAG" -ac_fn_c_check_func "$LINENO" "dladdr1" "ac_cv_func_dladdr1" -if test "x$ac_cv_func_dladdr1" = xyes -then : - printf "%s\n" "#define HAVE_DLADDR1 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "dlinfo" "ac_cv_func_dlinfo" -if test "x$ac_cv_func_dlinfo" = xyes -then : - printf "%s\n" "#define HAVE_DLINFO 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "epoll_create" "ac_cv_func_epoll_create" -if test "x$ac_cv_func_epoll_create" = xyes -then : - printf "%s\n" "#define HAVE_EPOLL_CREATE 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "fstatfs" "ac_cv_func_fstatfs" -if test "x$ac_cv_func_fstatfs" = xyes -then : - printf "%s\n" "#define HAVE_FSTATFS 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "futimens" "ac_cv_func_futimens" -if test "x$ac_cv_func_futimens" = xyes -then : - printf "%s\n" "#define HAVE_FUTIMENS 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "futimes" "ac_cv_func_futimes" -if test "x$ac_cv_func_futimes" = xyes -then : - printf "%s\n" "#define HAVE_FUTIMES 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "futimesat" "ac_cv_func_futimesat" -if test "x$ac_cv_func_futimesat" = xyes -then : - printf "%s\n" "#define HAVE_FUTIMESAT 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "getaddrinfo" "ac_cv_func_getaddrinfo" -if test "x$ac_cv_func_getaddrinfo" = xyes -then : - printf "%s\n" "#define HAVE_GETADDRINFO 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "getattrlist" "ac_cv_func_getattrlist" -if test "x$ac_cv_func_getattrlist" = xyes -then : - printf "%s\n" "#define HAVE_GETATTRLIST 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "getauxval" "ac_cv_func_getauxval" -if test "x$ac_cv_func_getauxval" = xyes -then : - printf "%s\n" "#define HAVE_GETAUXVAL 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "getifaddrs" "ac_cv_func_getifaddrs" -if test "x$ac_cv_func_getifaddrs" = xyes -then : - printf "%s\n" "#define HAVE_GETIFADDRS 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "getrandom" "ac_cv_func_getrandom" -if test "x$ac_cv_func_getrandom" = xyes -then : - printf "%s\n" "#define HAVE_GETRANDOM 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "kqueue" "ac_cv_func_kqueue" -if test "x$ac_cv_func_kqueue" = xyes -then : - printf "%s\n" "#define HAVE_KQUEUE 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "mach_continuous_time" "ac_cv_func_mach_continuous_time" -if test "x$ac_cv_func_mach_continuous_time" = xyes -then : - printf "%s\n" "#define HAVE_MACH_CONTINUOUS_TIME 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "pipe2" "ac_cv_func_pipe2" -if test "x$ac_cv_func_pipe2" = xyes -then : - printf "%s\n" "#define HAVE_PIPE2 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "port_create" "ac_cv_func_port_create" -if test "x$ac_cv_func_port_create" = xyes -then : - printf "%s\n" "#define HAVE_PORT_CREATE 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "posix_fadvise" "ac_cv_func_posix_fadvise" -if test "x$ac_cv_func_posix_fadvise" = xyes -then : - printf "%s\n" "#define HAVE_POSIX_FADVISE 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "posix_fallocate" "ac_cv_func_posix_fallocate" -if test "x$ac_cv_func_posix_fallocate" = xyes -then : - printf "%s\n" "#define HAVE_POSIX_FALLOCATE 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "prctl" "ac_cv_func_prctl" -if test "x$ac_cv_func_prctl" = xyes -then : - printf "%s\n" "#define HAVE_PRCTL 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "proc_pidinfo" "ac_cv_func_proc_pidinfo" -if test "x$ac_cv_func_proc_pidinfo" = xyes -then : - printf "%s\n" "#define HAVE_PROC_PIDINFO 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "sched_yield" "ac_cv_func_sched_yield" -if test "x$ac_cv_func_sched_yield" = xyes -then : - printf "%s\n" "#define HAVE_SCHED_YIELD 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "setproctitle" "ac_cv_func_setproctitle" -if test "x$ac_cv_func_setproctitle" = xyes -then : - printf "%s\n" "#define HAVE_SETPROCTITLE 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "setprogname" "ac_cv_func_setprogname" -if test "x$ac_cv_func_setprogname" = xyes -then : - printf "%s\n" "#define HAVE_SETPROGNAME 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "sigprocmask" "ac_cv_func_sigprocmask" -if test "x$ac_cv_func_sigprocmask" = xyes -then : - printf "%s\n" "#define HAVE_SIGPROCMASK 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "sysinfo" "ac_cv_func_sysinfo" -if test "x$ac_cv_func_sysinfo" = xyes -then : - printf "%s\n" "#define HAVE_SYSINFO 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "tcdrain" "ac_cv_func_tcdrain" -if test "x$ac_cv_func_tcdrain" = xyes -then : - printf "%s\n" "#define HAVE_TCDRAIN 1" >>confdefs.h - -fi -ac_fn_c_check_func "$LINENO" "thr_kill2" "ac_cv_func_thr_kill2" -if test "x$ac_cv_func_thr_kill2" = xyes -then : - printf "%s\n" "#define HAVE_THR_KILL2 1" >>confdefs.h - -fi - -CFLAGS="$ac_save_CFLAGS" - -case $host_os in - darwin*|macosx*) ;; - *) ac_save_LIBS=$LIBS - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 -printf %s "checking for library containing clock_gettime... " >&6; } -if test ${ac_cv_search_clock_gettime+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char clock_gettime (); -int -main (void) -{ -return clock_gettime (); - ; - return 0; -} -_ACEOF -for ac_lib in '' rt -do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO" -then : - ac_cv_search_clock_gettime=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext - if test ${ac_cv_search_clock_gettime+y} -then : - break -fi -done -if test ${ac_cv_search_clock_gettime+y} -then : - -else $as_nop - ac_cv_search_clock_gettime=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 -printf "%s\n" "$ac_cv_search_clock_gettime" >&6; } -ac_res=$ac_cv_search_clock_gettime -if test "$ac_res" != no -then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -printf "%s\n" "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h - - test "$ac_res" = "none required" || RT_LIBS="$ac_res" - -fi - - LIBS=$ac_save_LIBS - ;; -esac - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sched_setaffinity" >&5 -printf %s "checking for sched_setaffinity... " >&6; } -if test ${wine_cv_have_sched_setaffinity+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -sched_setaffinity(0, 0, 0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - wine_cv_have_sched_setaffinity=yes -else $as_nop - wine_cv_have_sched_setaffinity=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_have_sched_setaffinity" >&5 -printf "%s\n" "$wine_cv_have_sched_setaffinity" >&6; } -if test "$wine_cv_have_sched_setaffinity" = "yes" -then - -printf "%s\n" "#define HAVE_SCHED_SETAFFINITY 1" >>confdefs.h - -fi - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 -printf %s "checking for inline... " >&6; } -if test ${ac_cv_c_inline+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_cv_c_inline=no -for ac_kw in inline __inline__ __inline; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __cplusplus -typedef int foo_t; -static $ac_kw foo_t static_foo (void) {return 0; } -$ac_kw foo_t foo (void) {return 0; } -#endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO" -then : - ac_cv_c_inline=$ac_kw -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - test "$ac_cv_c_inline" != no && break -done - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 -printf "%s\n" "$ac_cv_c_inline" >&6; } - -case $ac_cv_c_inline in - inline | yes) ;; - *) - case $ac_cv_c_inline in - no) ac_val=;; - *) ac_val=$ac_cv_c_inline;; - esac - cat >>confdefs.h <<_ACEOF -#ifndef __cplusplus -#define inline $ac_val -#endif -_ACEOF - ;; -esac - -ac_fn_c_check_type "$LINENO" "sigset_t" "ac_cv_type_sigset_t" "#include -#include -" -if test "x$ac_cv_type_sigset_t" = xyes -then : - -printf "%s\n" "#define HAVE_SIGSET_T 1" >>confdefs.h - - -fi - -ac_fn_c_check_type "$LINENO" "request_sense" "ac_cv_type_request_sense" "#include -" -if test "x$ac_cv_type_request_sense" = xyes -then : - -printf "%s\n" "#define HAVE_REQUEST_SENSE 1" >>confdefs.h - - -fi - - -ac_fn_c_check_type "$LINENO" "struct xinpgen" "ac_cv_type_struct_xinpgen" "#include -#include -#ifdef HAVE_SYS_SOCKETVAR_H -#include -#endif -#ifdef HAVE_NET_ROUTE_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_IN_SYSTM_H -#include -#endif -#ifdef HAVE_NETINET_IP_H -#include -#endif -#ifdef HAVE_NETINET_IN_PCB_H -#include -#endif -" -if test "x$ac_cv_type_struct_xinpgen" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_XINPGEN 1" >>confdefs.h - - -fi - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sigaddset" >&5 -printf %s "checking for sigaddset... " >&6; } -if test ${wine_cv_have_sigaddset+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ -sigset_t set; sigaddset(&set,SIGTERM); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - wine_cv_have_sigaddset=yes -else $as_nop - wine_cv_have_sigaddset=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_have_sigaddset" >&5 -printf "%s\n" "$wine_cv_have_sigaddset" >&6; } -if test "$wine_cv_have_sigaddset" = "yes" -then - -printf "%s\n" "#define HAVE_SIGADDSET 1" >>confdefs.h - -fi - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we can use re-entrant gethostbyname_r Linux style" >&5 -printf %s "checking whether we can use re-entrant gethostbyname_r Linux style... " >&6; } -if test ${wine_cv_linux_gethostbyname_r_6+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main (void) -{ - - char *name=0; - struct hostent he; - struct hostent *result; - char *buf=0; - int bufsize=0; - int errnr; - char *addr=0; - int addrlen=0; - int addrtype=0; - gethostbyname_r(name,&he,buf,bufsize,&result,&errnr); - gethostbyaddr_r(addr, addrlen, addrtype,&he,buf,bufsize,&result,&errnr); - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - wine_cv_linux_gethostbyname_r_6=yes -else $as_nop - wine_cv_linux_gethostbyname_r_6=no - -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_linux_gethostbyname_r_6" >&5 -printf "%s\n" "$wine_cv_linux_gethostbyname_r_6" >&6; } - if test "$wine_cv_linux_gethostbyname_r_6" = "yes" - then - -printf "%s\n" "#define HAVE_LINUX_GETHOSTBYNAME_R_6 1" >>confdefs.h - - fi - -ac_fn_c_check_member "$LINENO" "struct msghdr" "msg_accrights" "ac_cv_member_struct_msghdr_msg_accrights" "#include -#include -#ifdef HAVE_SYS_UN_H -# include -#endif -" -if test "x$ac_cv_member_struct_msghdr_msg_accrights" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct sockaddr_un" "sun_len" "ac_cv_member_struct_sockaddr_un_sun_len" "#include -#include -#ifdef HAVE_SYS_UN_H -# include -#endif -" -if test "x$ac_cv_member_struct_sockaddr_un_sun_len" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_UN_SUN_LEN 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "scsireq_t" "cmd" "ac_cv_member_scsireq_t_cmd" "#include -#ifdef HAVE_SCSI_SG_H -#include -#endif -" -if test "x$ac_cv_member_scsireq_t_cmd" = xyes -then : - -printf "%s\n" "#define HAVE_SCSIREQ_T_CMD 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "sg_io_hdr_t" "interface_id" "ac_cv_member_sg_io_hdr_t_interface_id" "#include -#ifdef HAVE_SCSI_SG_H -#include -#endif -" -if test "x$ac_cv_member_sg_io_hdr_t_interface_id" = xyes -then : - -printf "%s\n" "#define HAVE_SG_IO_HDR_T_INTERFACE_ID 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "siginfo_t" "si_fd" "ac_cv_member_siginfo_t_si_fd" "#include -" -if test "x$ac_cv_member_siginfo_t_si_fd" = xyes -then : - -printf "%s\n" "#define HAVE_SIGINFO_T_SI_FD 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct mtget" "mt_blksiz" "ac_cv_member_struct_mtget_mt_blksiz" "#include -#ifdef HAVE_SYS_MTIO_H -#include -#endif -" -if test "x$ac_cv_member_struct_mtget_mt_blksiz" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_MTGET_MT_BLKSIZ 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct mtget" "mt_gstat" "ac_cv_member_struct_mtget_mt_gstat" "#include -#ifdef HAVE_SYS_MTIO_H -#include -#endif -" -if test "x$ac_cv_member_struct_mtget_mt_gstat" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_MTGET_MT_GSTAT 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct mtget" "mt_blkno" "ac_cv_member_struct_mtget_mt_blkno" "#include -#ifdef HAVE_SYS_MTIO_H -#include -#endif -" -if test "x$ac_cv_member_struct_mtget_mt_blkno" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_MTGET_MT_BLKNO 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim" "ac_cv_member_struct_stat_st_mtim" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_mtim" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_MTIM 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "st_mtimespec" "ac_cv_member_struct_stat_st_mtimespec" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_mtimespec" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_MTIMESPEC 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "st_ctim" "ac_cv_member_struct_stat_st_ctim" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_ctim" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_CTIM 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "st_ctimespec" "ac_cv_member_struct_stat_st_ctimespec" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_ctimespec" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_CTIMESPEC 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "st_atim" "ac_cv_member_struct_stat_st_atim" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_atim" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_ATIM 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "st_atimespec" "ac_cv_member_struct_stat_st_atimespec" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_atimespec" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_ATIMESPEC 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtime" "ac_cv_member_struct_stat_st_birthtime" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_birthtime" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtim" "ac_cv_member_struct_stat_st_birthtim" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_birthtim" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_BIRTHTIM 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtimespec" "ac_cv_member_struct_stat_st_birthtimespec" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_birthtimespec" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "__st_birthtime" "ac_cv_member_struct_stat___st_birthtime" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat___st_birthtime" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT___ST_BIRTHTIME 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct stat" "__st_birthtim" "ac_cv_member_struct_stat___st_birthtim" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat___st_birthtim" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_STAT___ST_BIRTHTIM 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct sockaddr_in6" "sin6_scope_id" "ac_cv_member_struct_sockaddr_in6_sin6_scope_id" "#include -#ifdef HAVE_NETINET_IN_H -#include -#endif -" -if test "x$ac_cv_member_struct_sockaddr_in6_sin6_scope_id" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct __res_state" "_u._ext.nscount6" "ac_cv_member_struct___res_state__u__ext_nscount6" "#ifdef HAVE_RESOLV_H -#include -#endif -" -if test "x$ac_cv_member_struct___res_state__u__ext_nscount6" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct in6_pktinfo" "ipi6_addr" "ac_cv_member_struct_in6_pktinfo_ipi6_addr" "#ifdef HAVE_NETINET_IN_H -#include -#endif -" -if test "x$ac_cv_member_struct_in6_pktinfo_ipi6_addr" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_IN6_PKTINFO_IPI6_ADDR 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct ipstat" "ips_total" "ac_cv_member_struct_ipstat_ips_total" "#include -#ifdef HAVE_SYS_SOCKETVAR_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_IP_VAR_H -#include -#endif -" -if test "x$ac_cv_member_struct_ipstat_ips_total" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_IPSTAT_IPS_TOTAL 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct ip_stats" "ips_total" "ac_cv_member_struct_ip_stats_ips_total" "#ifdef HAVE_NETINET_IP_VAR_H -#include -#endif -" -if test "x$ac_cv_member_struct_ip_stats_ips_total" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_IP_STATS_IPS_TOTAL 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct ip6stat" "ip6s_total" "ac_cv_member_struct_ip6stat_ip6s_total" "#include -#ifdef HAVE_SYS_SOCKETVAR_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET6_IP6_VAR_H -#include -#endif -" -if test "x$ac_cv_member_struct_ip6stat_ip6s_total" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_IP6STAT_IP6S_TOTAL 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct icmpstat" "icps_error" "ac_cv_member_struct_icmpstat_icps_error" "#include -#ifdef HAVE_SYS_SOCKETVAR_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_IP_H -#include -#endif -#ifdef HAVE_NETINET_IP_ICMP_H -#include -#endif -#ifdef HAVE_NETINET_ICMP_VAR_H -#include -#endif -" -if test "x$ac_cv_member_struct_icmpstat_icps_error" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_ICMPSTAT_ICPS_ERROR 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct icmp6stat" "icp6s_error" "ac_cv_member_struct_icmp6stat_icp6s_error" "#include -#ifdef HAVE_SYS_SOCKETVAR_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_ICMP6_H -#include -#endif -" -if test "x$ac_cv_member_struct_icmp6stat_icp6s_error" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_ICMP6STAT_ICP6S_ERROR 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct tcpstat" "tcps_connattempt" "ac_cv_member_struct_tcpstat_tcps_connattempt" "#include -#ifdef HAVE_SYS_SOCKETVAR_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_TCP_H -#include -#endif -#ifdef HAVE_NETINET_TCP_VAR_H -#include -#endif -" -if test "x$ac_cv_member_struct_tcpstat_tcps_connattempt" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct tcp_stats" "tcps_connattempt" "ac_cv_member_struct_tcp_stats_tcps_connattempt" "#ifdef HAVE_NETINET_TCP_VAR_H -#include -#endif -" -if test "x$ac_cv_member_struct_tcp_stats_tcps_connattempt" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct udpstat" "udps_ipackets" "ac_cv_member_struct_udpstat_udps_ipackets" "#include -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NETINET_IP_VAR_H -#include -#endif -#ifdef HAVE_NETINET_UDP_H -#include -#endif -#ifdef HAVE_NETINET_UDP_VAR_H -#include -#endif -" -if test "x$ac_cv_member_struct_udpstat_udps_ipackets" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_UDPSTAT_UDPS_IPACKETS 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct ifreq" "ifr_hwaddr" "ac_cv_member_struct_ifreq_ifr_hwaddr" "#include -#ifdef HAVE_NET_IF_H -# include -#endif -" -if test "x$ac_cv_member_struct_ifreq_ifr_hwaddr" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_IFREQ_IFR_HWADDR 1" >>confdefs.h - - -fi - - -ac_fn_c_check_member "$LINENO" "struct sysinfo" "totalram" "ac_cv_member_struct_sysinfo_totalram" "#ifdef HAVE_SYS_SYSINFO_H -# include -#endif -" -if test "x$ac_cv_member_struct_sysinfo_totalram" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_SYSINFO_TOTALRAM 1" >>confdefs.h - - -fi -ac_fn_c_check_member "$LINENO" "struct sysinfo" "mem_unit" "ac_cv_member_struct_sysinfo_mem_unit" "#ifdef HAVE_SYS_SYSINFO_H -# include -#endif -" -if test "x$ac_cv_member_struct_sysinfo_mem_unit" = xyes -then : - -printf "%s\n" "#define HAVE_STRUCT_SYSINFO_MEM_UNIT 1" >>confdefs.h - - -fi - - -LIBS="$ac_save_LIBS" - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __builtin_popcount" >&5 -printf %s "checking for __builtin_popcount... " >&6; } -if test ${ac_cv_have___builtin_popcount+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -return __builtin_popcount(1) - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_have___builtin_popcount="yes" -else $as_nop - ac_cv_have___builtin_popcount="no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have___builtin_popcount" >&5 -printf "%s\n" "$ac_cv_have___builtin_popcount" >&6; } -if test "$ac_cv_have___builtin_popcount" = "yes" -then - -printf "%s\n" "#define HAVE___BUILTIN_POPCOUNT 1" >>confdefs.h - -fi - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __clear_cache" >&5 -printf %s "checking for __clear_cache... " >&6; } -if test ${ac_cv_have___clear_cache+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main (void) -{ -__clear_cache((void*)0, (void*)0); return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO" -then : - ac_cv_have___clear_cache="yes" -else $as_nop - ac_cv_have___clear_cache="no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have___clear_cache" >&5 -printf "%s\n" "$ac_cv_have___clear_cache" >&6; } -if test "$ac_cv_have___clear_cache" = "yes" -then - -printf "%s\n" "#define HAVE___CLEAR_CACHE 1" >>confdefs.h - -fi - - -case $host_cpu in - *i[3456789]86*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we need to define __i386__" >&5 -printf %s "checking whether we need to define __i386__... " >&6; } -if test ${ac_cv_cpp_def___i386__+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __i386__ -yes -#endif -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 -then : - ac_cv_cpp_def___i386__=yes -else $as_nop - ac_cv_cpp_def___i386__=no -fi -rm -rf conftest* - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cpp_def___i386__" >&5 -printf "%s\n" "$ac_cv_cpp_def___i386__" >&6; } -if test "x$ac_cv_cpp_def___i386__" = xyes -then : - CFLAGS="$CFLAGS -D__i386__" - LINTFLAGS="$LINTFLAGS -D__i386__" -fi ;; - *x86_64*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we need to define __x86_64__" >&5 -printf %s "checking whether we need to define __x86_64__... " >&6; } -if test ${ac_cv_cpp_def___x86_64__+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __x86_64__ -yes -#endif -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 -then : - ac_cv_cpp_def___x86_64__=yes -else $as_nop - ac_cv_cpp_def___x86_64__=no -fi -rm -rf conftest* - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cpp_def___x86_64__" >&5 -printf "%s\n" "$ac_cv_cpp_def___x86_64__" >&6; } -if test "x$ac_cv_cpp_def___x86_64__" = xyes -then : - CFLAGS="$CFLAGS -D__x86_64__" - LINTFLAGS="$LINTFLAGS -D__x86_64__" -fi ;; - *sparc64*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we need to define __sparc64__" >&5 -printf %s "checking whether we need to define __sparc64__... " >&6; } -if test ${ac_cv_cpp_def___sparc64__+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __sparc64__ -yes -#endif -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 -then : - ac_cv_cpp_def___sparc64__=yes -else $as_nop - ac_cv_cpp_def___sparc64__=no -fi -rm -rf conftest* - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cpp_def___sparc64__" >&5 -printf "%s\n" "$ac_cv_cpp_def___sparc64__" >&6; } -if test "x$ac_cv_cpp_def___sparc64__" = xyes -then : - CFLAGS="$CFLAGS -D__sparc64__" - LINTFLAGS="$LINTFLAGS -D__sparc64__" -fi ;; - *sparc*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we need to define __sparc__" >&5 -printf %s "checking whether we need to define __sparc__... " >&6; } -if test ${ac_cv_cpp_def___sparc__+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __sparc__ -yes -#endif -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 -then : - ac_cv_cpp_def___sparc__=yes -else $as_nop - ac_cv_cpp_def___sparc__=no -fi -rm -rf conftest* - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cpp_def___sparc__" >&5 -printf "%s\n" "$ac_cv_cpp_def___sparc__" >&6; } -if test "x$ac_cv_cpp_def___sparc__" = xyes -then : - CFLAGS="$CFLAGS -D__sparc__" - LINTFLAGS="$LINTFLAGS -D__sparc__" -fi ;; - *powerpc64*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we need to define __powerpc64__" >&5 -printf %s "checking whether we need to define __powerpc64__... " >&6; } -if test ${ac_cv_cpp_def___powerpc64__+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __powerpc64__ -yes -#endif -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 -then : - ac_cv_cpp_def___powerpc64__=yes -else $as_nop - ac_cv_cpp_def___powerpc64__=no -fi -rm -rf conftest* - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cpp_def___powerpc64__" >&5 -printf "%s\n" "$ac_cv_cpp_def___powerpc64__" >&6; } -if test "x$ac_cv_cpp_def___powerpc64__" = xyes -then : - CFLAGS="$CFLAGS -D__powerpc64__" - LINTFLAGS="$LINTFLAGS -D__powerpc64__" -fi ;; - *powerpc*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we need to define __powerpc__" >&5 -printf %s "checking whether we need to define __powerpc__... " >&6; } -if test ${ac_cv_cpp_def___powerpc__+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __powerpc__ -yes -#endif -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 -then : - ac_cv_cpp_def___powerpc__=yes -else $as_nop - ac_cv_cpp_def___powerpc__=no -fi -rm -rf conftest* - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cpp_def___powerpc__" >&5 -printf "%s\n" "$ac_cv_cpp_def___powerpc__" >&6; } -if test "x$ac_cv_cpp_def___powerpc__" = xyes -then : - CFLAGS="$CFLAGS -D__powerpc__" - LINTFLAGS="$LINTFLAGS -D__powerpc__" -fi ;; - *aarch64*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we need to define __aarch64__" >&5 -printf %s "checking whether we need to define __aarch64__... " >&6; } -if test ${ac_cv_cpp_def___aarch64__+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __aarch64__ -yes -#endif -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 -then : - ac_cv_cpp_def___aarch64__=yes -else $as_nop - ac_cv_cpp_def___aarch64__=no -fi -rm -rf conftest* - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cpp_def___aarch64__" >&5 -printf "%s\n" "$ac_cv_cpp_def___aarch64__" >&6; } -if test "x$ac_cv_cpp_def___aarch64__" = xyes -then : - CFLAGS="$CFLAGS -D__aarch64__" - LINTFLAGS="$LINTFLAGS -D__aarch64__" -fi ;; - *arm*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we need to define __arm__" >&5 -printf %s "checking whether we need to define __arm__... " >&6; } -if test ${ac_cv_cpp_def___arm__+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __arm__ -yes -#endif -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 -then : - ac_cv_cpp_def___arm__=yes -else $as_nop - ac_cv_cpp_def___arm__=no -fi -rm -rf conftest* - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cpp_def___arm__" >&5 -printf "%s\n" "$ac_cv_cpp_def___arm__" >&6; } -if test "x$ac_cv_cpp_def___arm__" = xyes -then : - CFLAGS="$CFLAGS -D__arm__" - LINTFLAGS="$LINTFLAGS -D__arm__" -fi ;; -esac - -case $host_vendor in - *sun*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we need to define __sun__" >&5 -printf %s "checking whether we need to define __sun__... " >&6; } -if test ${ac_cv_cpp_def___sun__+y} -then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __sun__ -yes -#endif -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 -then : - ac_cv_cpp_def___sun__=yes -else $as_nop - ac_cv_cpp_def___sun__=no -fi -rm -rf conftest* - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cpp_def___sun__" >&5 -printf "%s\n" "$ac_cv_cpp_def___sun__" >&6; } -if test "x$ac_cv_cpp_def___sun__" = xyes -then : - CFLAGS="$CFLAGS -D__sun__" - LINTFLAGS="$LINTFLAGS -D__sun__" -fi ;; -esac - - - - - -ac_config_commands="$ac_config_commands include/stamp-h" - -printf %s "creating Makefile rules..." >&6 - -makedep_flags="" -test "x$enable_silent_rules" = xyes && makedep_flags="$makedep_flags -S" - -wine_srcdir= -test "$srcdir" = . || wine_srcdir="$srcdir/" - -ac_config_links="$ac_config_links wine:tools/winewrapper" -wine_fn_config_symlink wine -if test "$HOST_ARCH" = x86_64 -o -n "$with_wine64"; then -ac_config_links="$ac_config_links wine64:tools/winewrapper" -wine_fn_config_symlink wine64 -fi - -wine_fn_config_makefile dlls/acledit enable_acledit -wine_fn_config_makefile dlls/aclui enable_aclui -wine_fn_config_makefile dlls/activeds.tlb enable_activeds_tlb -wine_fn_config_makefile dlls/activeds enable_activeds -wine_fn_config_makefile dlls/activeds/tests enable_tests -wine_fn_config_makefile dlls/actxprxy enable_actxprxy -wine_fn_config_makefile dlls/adsldp enable_adsldp -wine_fn_config_makefile dlls/adsldp/tests enable_tests -wine_fn_config_makefile dlls/adsldpc enable_adsldpc -wine_fn_config_makefile dlls/advapi32 enable_advapi32 -wine_fn_config_makefile dlls/advapi32/tests enable_tests -wine_fn_config_makefile dlls/advpack enable_advpack -wine_fn_config_makefile dlls/advpack/tests enable_tests -wine_fn_config_makefile dlls/amsi enable_amsi -wine_fn_config_makefile dlls/amstream enable_amstream -wine_fn_config_makefile dlls/amstream/tests enable_tests -wine_fn_config_makefile dlls/apisetschema enable_apisetschema -wine_fn_config_makefile dlls/apphelp enable_apphelp -wine_fn_config_makefile dlls/apphelp/tests enable_tests -wine_fn_config_makefile dlls/appwiz.cpl enable_appwiz_cpl -wine_fn_config_makefile dlls/atl enable_atl -wine_fn_config_makefile dlls/atl/tests enable_tests -wine_fn_config_makefile dlls/atl100 enable_atl100 -wine_fn_config_makefile dlls/atl100/tests enable_tests -wine_fn_config_makefile dlls/atl110 enable_atl110 -wine_fn_config_makefile dlls/atl110/tests enable_tests -wine_fn_config_makefile dlls/atl80 enable_atl80 -wine_fn_config_makefile dlls/atl80/tests enable_tests -wine_fn_config_makefile dlls/atl90 enable_atl90 -wine_fn_config_makefile dlls/atlthunk enable_atlthunk -wine_fn_config_makefile dlls/atlthunk/tests enable_tests -wine_fn_config_makefile dlls/atmlib enable_atmlib -wine_fn_config_makefile dlls/authz enable_authz -wine_fn_config_makefile dlls/avicap32 enable_avicap32 -wine_fn_config_makefile dlls/avifil32 enable_avifil32 -wine_fn_config_makefile dlls/avifil32/tests enable_tests -wine_fn_config_makefile dlls/avifile.dll16 enable_win16 -wine_fn_config_makefile dlls/avrt enable_avrt -wine_fn_config_makefile dlls/bcrypt enable_bcrypt -wine_fn_config_makefile dlls/bcrypt/tests enable_tests -wine_fn_config_makefile dlls/bluetoothapis enable_bluetoothapis -wine_fn_config_makefile dlls/browseui enable_browseui -wine_fn_config_makefile dlls/browseui/tests enable_tests -wine_fn_config_makefile dlls/bthprops.cpl enable_bthprops_cpl -wine_fn_config_makefile dlls/cabinet enable_cabinet -wine_fn_config_makefile dlls/cabinet/tests enable_tests -wine_fn_config_makefile dlls/capi2032 enable_capi2032 -wine_fn_config_makefile dlls/cards enable_cards -wine_fn_config_makefile dlls/cdosys enable_cdosys -wine_fn_config_makefile dlls/cfgmgr32 enable_cfgmgr32 -wine_fn_config_makefile dlls/clusapi enable_clusapi -wine_fn_config_makefile dlls/cng.sys enable_cng_sys -wine_fn_config_makefile dlls/combase enable_combase -wine_fn_config_makefile dlls/combase/tests enable_tests -wine_fn_config_makefile dlls/comcat enable_comcat -wine_fn_config_makefile dlls/comcat/tests enable_tests -wine_fn_config_makefile dlls/comctl32 enable_comctl32 -wine_fn_config_makefile dlls/comctl32/tests enable_tests -wine_fn_config_makefile dlls/comdlg32 enable_comdlg32 -wine_fn_config_makefile dlls/comdlg32/tests enable_tests -wine_fn_config_makefile dlls/comm.drv16 enable_win16 -wine_fn_config_makefile dlls/commdlg.dll16 enable_win16 -wine_fn_config_makefile dlls/compobj.dll16 enable_win16 -wine_fn_config_makefile dlls/compstui enable_compstui -wine_fn_config_makefile dlls/compstui/tests enable_tests -wine_fn_config_makefile dlls/comsvcs enable_comsvcs -wine_fn_config_makefile dlls/comsvcs/tests enable_tests -wine_fn_config_makefile dlls/concrt140 enable_concrt140 -wine_fn_config_makefile dlls/concrt140/tests enable_tests -wine_fn_config_makefile dlls/connect enable_connect -wine_fn_config_makefile dlls/credui enable_credui -wine_fn_config_makefile dlls/credui/tests enable_tests -wine_fn_config_makefile dlls/crtdll enable_crtdll -wine_fn_config_makefile dlls/crypt32 enable_crypt32 -wine_fn_config_makefile dlls/crypt32/tests enable_tests -wine_fn_config_makefile dlls/cryptdlg enable_cryptdlg -wine_fn_config_makefile dlls/cryptdll enable_cryptdll -wine_fn_config_makefile dlls/cryptext enable_cryptext -wine_fn_config_makefile dlls/cryptnet enable_cryptnet -wine_fn_config_makefile dlls/cryptnet/tests enable_tests -wine_fn_config_makefile dlls/cryptowinrt enable_cryptowinrt -wine_fn_config_makefile dlls/cryptsp enable_cryptsp -wine_fn_config_makefile dlls/cryptui enable_cryptui -wine_fn_config_makefile dlls/cryptui/tests enable_tests -wine_fn_config_makefile dlls/ctapi32 enable_ctapi32 -wine_fn_config_makefile dlls/ctl3d.dll16 enable_win16 -wine_fn_config_makefile dlls/ctl3d32 enable_ctl3d32 -wine_fn_config_makefile dlls/ctl3dv2.dll16 enable_win16 -wine_fn_config_makefile dlls/d2d1 enable_d2d1 -wine_fn_config_makefile dlls/d2d1/tests enable_tests -wine_fn_config_makefile dlls/d3d10 enable_d3d10 -wine_fn_config_makefile dlls/d3d10/tests enable_tests -wine_fn_config_makefile dlls/d3d10_1 enable_d3d10_1 -wine_fn_config_makefile dlls/d3d10_1/tests enable_tests -wine_fn_config_makefile dlls/d3d10core enable_d3d10core -wine_fn_config_makefile dlls/d3d10core/tests enable_tests -wine_fn_config_makefile dlls/d3d11 enable_d3d11 -wine_fn_config_makefile dlls/d3d11/tests enable_tests -wine_fn_config_makefile dlls/d3d12 enable_d3d12 -wine_fn_config_makefile dlls/d3d12/tests enable_tests -wine_fn_config_makefile dlls/d3d8 enable_d3d8 -wine_fn_config_makefile dlls/d3d8/tests enable_tests -wine_fn_config_makefile dlls/d3d8thk enable_d3d8thk -wine_fn_config_makefile dlls/d3d9 enable_d3d9 -wine_fn_config_makefile dlls/d3d9/tests enable_tests -wine_fn_config_makefile dlls/d3dcompiler_33 enable_d3dcompiler_33 -wine_fn_config_makefile dlls/d3dcompiler_34 enable_d3dcompiler_34 -wine_fn_config_makefile dlls/d3dcompiler_35 enable_d3dcompiler_35 -wine_fn_config_makefile dlls/d3dcompiler_36 enable_d3dcompiler_36 -wine_fn_config_makefile dlls/d3dcompiler_37 enable_d3dcompiler_37 -wine_fn_config_makefile dlls/d3dcompiler_38 enable_d3dcompiler_38 -wine_fn_config_makefile dlls/d3dcompiler_39 enable_d3dcompiler_39 -wine_fn_config_makefile dlls/d3dcompiler_40 enable_d3dcompiler_40 -wine_fn_config_makefile dlls/d3dcompiler_41 enable_d3dcompiler_41 -wine_fn_config_makefile dlls/d3dcompiler_42 enable_d3dcompiler_42 -wine_fn_config_makefile dlls/d3dcompiler_43 enable_d3dcompiler_43 -wine_fn_config_makefile dlls/d3dcompiler_43/tests enable_tests -wine_fn_config_makefile dlls/d3dcompiler_46 enable_d3dcompiler_46 -wine_fn_config_makefile dlls/d3dcompiler_46/tests enable_tests -wine_fn_config_makefile dlls/d3dcompiler_47 enable_d3dcompiler_47 -wine_fn_config_makefile dlls/d3dcompiler_47/tests enable_tests -wine_fn_config_makefile dlls/d3dim enable_d3dim -wine_fn_config_makefile dlls/d3dim700 enable_d3dim700 -wine_fn_config_makefile dlls/d3drm enable_d3drm -wine_fn_config_makefile dlls/d3drm/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_33 enable_d3dx10_33 -wine_fn_config_makefile dlls/d3dx10_34 enable_d3dx10_34 -wine_fn_config_makefile dlls/d3dx10_34/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_35 enable_d3dx10_35 -wine_fn_config_makefile dlls/d3dx10_35/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_36 enable_d3dx10_36 -wine_fn_config_makefile dlls/d3dx10_36/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_37 enable_d3dx10_37 -wine_fn_config_makefile dlls/d3dx10_37/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_38 enable_d3dx10_38 -wine_fn_config_makefile dlls/d3dx10_38/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_39 enable_d3dx10_39 -wine_fn_config_makefile dlls/d3dx10_39/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_40 enable_d3dx10_40 -wine_fn_config_makefile dlls/d3dx10_40/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_41 enable_d3dx10_41 -wine_fn_config_makefile dlls/d3dx10_41/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_42 enable_d3dx10_42 -wine_fn_config_makefile dlls/d3dx10_42/tests enable_tests -wine_fn_config_makefile dlls/d3dx10_43 enable_d3dx10_43 -wine_fn_config_makefile dlls/d3dx10_43/tests enable_tests -wine_fn_config_makefile dlls/d3dx11_42 enable_d3dx11_42 -wine_fn_config_makefile dlls/d3dx11_42/tests enable_tests -wine_fn_config_makefile dlls/d3dx11_43 enable_d3dx11_43 -wine_fn_config_makefile dlls/d3dx11_43/tests enable_tests -wine_fn_config_makefile dlls/d3dx9_24 enable_d3dx9_24 -wine_fn_config_makefile dlls/d3dx9_25 enable_d3dx9_25 -wine_fn_config_makefile dlls/d3dx9_26 enable_d3dx9_26 -wine_fn_config_makefile dlls/d3dx9_27 enable_d3dx9_27 -wine_fn_config_makefile dlls/d3dx9_28 enable_d3dx9_28 -wine_fn_config_makefile dlls/d3dx9_29 enable_d3dx9_29 -wine_fn_config_makefile dlls/d3dx9_30 enable_d3dx9_30 -wine_fn_config_makefile dlls/d3dx9_31 enable_d3dx9_31 -wine_fn_config_makefile dlls/d3dx9_32 enable_d3dx9_32 -wine_fn_config_makefile dlls/d3dx9_33 enable_d3dx9_33 -wine_fn_config_makefile dlls/d3dx9_34 enable_d3dx9_34 -wine_fn_config_makefile dlls/d3dx9_35 enable_d3dx9_35 -wine_fn_config_makefile dlls/d3dx9_36 enable_d3dx9_36 -wine_fn_config_makefile dlls/d3dx9_36/tests enable_tests -wine_fn_config_makefile dlls/d3dx9_37 enable_d3dx9_37 -wine_fn_config_makefile dlls/d3dx9_38 enable_d3dx9_38 -wine_fn_config_makefile dlls/d3dx9_39 enable_d3dx9_39 -wine_fn_config_makefile dlls/d3dx9_40 enable_d3dx9_40 -wine_fn_config_makefile dlls/d3dx9_41 enable_d3dx9_41 -wine_fn_config_makefile dlls/d3dx9_42 enable_d3dx9_42 -wine_fn_config_makefile dlls/d3dx9_43 enable_d3dx9_43 -wine_fn_config_makefile dlls/d3dxof enable_d3dxof -wine_fn_config_makefile dlls/d3dxof/tests enable_tests -wine_fn_config_makefile dlls/davclnt enable_davclnt -wine_fn_config_makefile dlls/dbgeng enable_dbgeng -wine_fn_config_makefile dlls/dbgeng/tests enable_tests -wine_fn_config_makefile dlls/dbghelp enable_dbghelp -wine_fn_config_makefile dlls/dbghelp/tests enable_tests -wine_fn_config_makefile dlls/dciman32 enable_dciman32 -wine_fn_config_makefile dlls/dcomp enable_dcomp -wine_fn_config_makefile dlls/ddeml.dll16 enable_win16 -wine_fn_config_makefile dlls/ddraw enable_ddraw -wine_fn_config_makefile dlls/ddraw/tests enable_tests -wine_fn_config_makefile dlls/ddrawex enable_ddrawex -wine_fn_config_makefile dlls/ddrawex/tests enable_tests -wine_fn_config_makefile dlls/devenum enable_devenum -wine_fn_config_makefile dlls/devenum/tests enable_tests -wine_fn_config_makefile dlls/dhcpcsvc enable_dhcpcsvc -wine_fn_config_makefile dlls/dhcpcsvc/tests enable_tests -wine_fn_config_makefile dlls/dhcpcsvc6 enable_dhcpcsvc6 -wine_fn_config_makefile dlls/dhtmled.ocx enable_dhtmled_ocx -wine_fn_config_makefile dlls/diasymreader enable_diasymreader -wine_fn_config_makefile dlls/difxapi enable_difxapi -wine_fn_config_makefile dlls/dinput enable_dinput -wine_fn_config_makefile dlls/dinput/tests enable_tests -wine_fn_config_makefile dlls/dinput8 enable_dinput8 -wine_fn_config_makefile dlls/directmanipulation enable_directmanipulation -wine_fn_config_makefile dlls/directmanipulation/tests enable_tests -wine_fn_config_makefile dlls/dispdib.dll16 enable_win16 -wine_fn_config_makefile dlls/dispex enable_dispex -wine_fn_config_makefile dlls/dispex/tests enable_tests -wine_fn_config_makefile dlls/display.drv16 enable_win16 -wine_fn_config_makefile dlls/dmband enable_dmband -wine_fn_config_makefile dlls/dmband/tests enable_tests -wine_fn_config_makefile dlls/dmcompos enable_dmcompos -wine_fn_config_makefile dlls/dmcompos/tests enable_tests -wine_fn_config_makefile dlls/dmime enable_dmime -wine_fn_config_makefile dlls/dmime/tests enable_tests -wine_fn_config_makefile dlls/dmloader enable_dmloader -wine_fn_config_makefile dlls/dmloader/tests enable_tests -wine_fn_config_makefile dlls/dmscript enable_dmscript -wine_fn_config_makefile dlls/dmscript/tests enable_tests -wine_fn_config_makefile dlls/dmstyle enable_dmstyle -wine_fn_config_makefile dlls/dmstyle/tests enable_tests -wine_fn_config_makefile dlls/dmsynth enable_dmsynth -wine_fn_config_makefile dlls/dmsynth/tests enable_tests -wine_fn_config_makefile dlls/dmusic enable_dmusic -wine_fn_config_makefile dlls/dmusic/tests enable_tests -wine_fn_config_makefile dlls/dmusic32 enable_dmusic32 -wine_fn_config_makefile dlls/dnsapi enable_dnsapi -wine_fn_config_makefile dlls/dnsapi/tests enable_tests -wine_fn_config_makefile dlls/dplay enable_dplay -wine_fn_config_makefile dlls/dplayx enable_dplayx -wine_fn_config_makefile dlls/dplayx/tests enable_tests -wine_fn_config_makefile dlls/dpnaddr enable_dpnaddr -wine_fn_config_makefile dlls/dpnet enable_dpnet -wine_fn_config_makefile dlls/dpnet/tests enable_tests -wine_fn_config_makefile dlls/dpnhpast enable_dpnhpast -wine_fn_config_makefile dlls/dpnhupnp enable_dpnhupnp -wine_fn_config_makefile dlls/dpnlobby enable_dpnlobby -wine_fn_config_makefile dlls/dpvoice enable_dpvoice -wine_fn_config_makefile dlls/dpvoice/tests enable_tests -wine_fn_config_makefile dlls/dpwsockx enable_dpwsockx -wine_fn_config_makefile dlls/drmclien enable_drmclien -wine_fn_config_makefile dlls/dsdmo enable_dsdmo -wine_fn_config_makefile dlls/dsdmo/tests enable_tests -wine_fn_config_makefile dlls/dsound enable_dsound -wine_fn_config_makefile dlls/dsound/tests enable_tests -wine_fn_config_makefile dlls/dsquery enable_dsquery -wine_fn_config_makefile dlls/dssenh enable_dssenh -wine_fn_config_makefile dlls/dssenh/tests enable_tests -wine_fn_config_makefile dlls/dsuiext enable_dsuiext -wine_fn_config_makefile dlls/dswave enable_dswave -wine_fn_config_makefile dlls/dswave/tests enable_tests -wine_fn_config_makefile dlls/dwmapi enable_dwmapi -wine_fn_config_makefile dlls/dwmapi/tests enable_tests -wine_fn_config_makefile dlls/dwrite enable_dwrite -wine_fn_config_makefile dlls/dwrite/tests enable_tests -wine_fn_config_makefile dlls/dx8vb enable_dx8vb -wine_fn_config_makefile dlls/dxdiagn enable_dxdiagn -wine_fn_config_makefile dlls/dxdiagn/tests enable_tests -wine_fn_config_makefile dlls/dxgi enable_dxgi -wine_fn_config_makefile dlls/dxgi/tests enable_tests -wine_fn_config_makefile dlls/dxtrans enable_dxtrans -wine_fn_config_makefile dlls/dxva2 enable_dxva2 -wine_fn_config_makefile dlls/dxva2/tests enable_tests -wine_fn_config_makefile dlls/esent enable_esent -wine_fn_config_makefile dlls/evr enable_evr -wine_fn_config_makefile dlls/evr/tests enable_tests -wine_fn_config_makefile dlls/explorerframe enable_explorerframe -wine_fn_config_makefile dlls/explorerframe/tests enable_tests -wine_fn_config_makefile dlls/faultrep enable_faultrep -wine_fn_config_makefile dlls/faultrep/tests enable_tests -wine_fn_config_makefile dlls/feclient enable_feclient -wine_fn_config_makefile dlls/fltlib enable_fltlib -wine_fn_config_makefile dlls/fltmgr.sys enable_fltmgr_sys -wine_fn_config_makefile dlls/fntcache enable_fntcache -wine_fn_config_makefile dlls/fontsub enable_fontsub -wine_fn_config_makefile dlls/fusion enable_fusion -wine_fn_config_makefile dlls/fusion/tests enable_tests -wine_fn_config_makefile dlls/fwpuclnt enable_fwpuclnt -wine_fn_config_makefile dlls/gameux enable_gameux -wine_fn_config_makefile dlls/gameux/tests enable_tests -wine_fn_config_makefile dlls/gamingtcui enable_gamingtcui -wine_fn_config_makefile dlls/gdi.exe16 enable_win16 -wine_fn_config_makefile dlls/gdi32 enable_gdi32 -wine_fn_config_makefile dlls/gdi32/tests enable_tests -wine_fn_config_makefile dlls/gdiplus enable_gdiplus -wine_fn_config_makefile dlls/gdiplus/tests enable_tests -wine_fn_config_makefile dlls/glu32 enable_glu32 -wine_fn_config_makefile dlls/gphoto2.ds enable_gphoto2_ds -wine_fn_config_makefile dlls/gpkcsp enable_gpkcsp -wine_fn_config_makefile dlls/hal enable_hal -wine_fn_config_makefile dlls/hhctrl.ocx enable_hhctrl_ocx -wine_fn_config_makefile dlls/hid enable_hid -wine_fn_config_makefile dlls/hid/tests enable_tests -wine_fn_config_makefile dlls/hidclass.sys enable_hidclass_sys -wine_fn_config_makefile dlls/hidparse.sys enable_hidparse_sys -wine_fn_config_makefile dlls/hlink enable_hlink -wine_fn_config_makefile dlls/hlink/tests enable_tests -wine_fn_config_makefile dlls/hnetcfg enable_hnetcfg -wine_fn_config_makefile dlls/hnetcfg/tests enable_tests -wine_fn_config_makefile dlls/http.sys enable_http_sys -wine_fn_config_makefile dlls/httpapi enable_httpapi -wine_fn_config_makefile dlls/httpapi/tests enable_tests -wine_fn_config_makefile dlls/ia2comproxy enable_ia2comproxy -wine_fn_config_makefile dlls/iccvid enable_iccvid -wine_fn_config_makefile dlls/icmp enable_icmp -wine_fn_config_makefile dlls/ieframe enable_ieframe -wine_fn_config_makefile dlls/ieframe/tests enable_tests -wine_fn_config_makefile dlls/ieproxy enable_ieproxy -wine_fn_config_makefile dlls/ifsmgr.vxd enable_win16 -wine_fn_config_makefile dlls/imaadp32.acm enable_imaadp32_acm -wine_fn_config_makefile dlls/imagehlp enable_imagehlp -wine_fn_config_makefile dlls/imagehlp/tests enable_tests -wine_fn_config_makefile dlls/imm.dll16 enable_win16 -wine_fn_config_makefile dlls/imm32 enable_imm32 -wine_fn_config_makefile dlls/imm32/tests enable_tests -wine_fn_config_makefile dlls/inetcomm enable_inetcomm -wine_fn_config_makefile dlls/inetcomm/tests enable_tests -wine_fn_config_makefile dlls/inetcpl.cpl enable_inetcpl_cpl -wine_fn_config_makefile dlls/inetmib1 enable_inetmib1 -wine_fn_config_makefile dlls/inetmib1/tests enable_tests -wine_fn_config_makefile dlls/infosoft enable_infosoft -wine_fn_config_makefile dlls/infosoft/tests enable_tests -wine_fn_config_makefile dlls/initpki enable_initpki -wine_fn_config_makefile dlls/inkobj enable_inkobj -wine_fn_config_makefile dlls/inseng enable_inseng -wine_fn_config_makefile dlls/iphlpapi enable_iphlpapi -wine_fn_config_makefile dlls/iphlpapi/tests enable_tests -wine_fn_config_makefile dlls/iprop enable_iprop -wine_fn_config_makefile dlls/irprops.cpl enable_irprops_cpl -wine_fn_config_makefile dlls/itircl enable_itircl -wine_fn_config_makefile dlls/itss enable_itss -wine_fn_config_makefile dlls/itss/tests enable_tests -wine_fn_config_makefile dlls/joy.cpl enable_joy_cpl -wine_fn_config_makefile dlls/jscript enable_jscript -wine_fn_config_makefile dlls/jscript/tests enable_tests -wine_fn_config_makefile dlls/jsproxy enable_jsproxy -wine_fn_config_makefile dlls/jsproxy/tests enable_tests -wine_fn_config_makefile dlls/kerberos enable_kerberos -wine_fn_config_makefile dlls/kernel32 enable_kernel32 -wine_fn_config_makefile dlls/kernel32/tests enable_tests -wine_fn_config_makefile dlls/kernelbase enable_kernelbase -wine_fn_config_makefile dlls/kernelbase/tests enable_tests -wine_fn_config_makefile dlls/keyboard.drv16 enable_win16 -wine_fn_config_makefile dlls/krnl386.exe16 enable_win16 -wine_fn_config_makefile dlls/ksecdd.sys enable_ksecdd_sys -wine_fn_config_makefile dlls/ksproxy.ax enable_ksproxy_ax -wine_fn_config_makefile dlls/ksuser enable_ksuser -wine_fn_config_makefile dlls/ktmw32 enable_ktmw32 -wine_fn_config_makefile dlls/l3codeca.acm enable_l3codeca_acm -wine_fn_config_makefile dlls/light.msstyles enable_light_msstyles -wine_fn_config_makefile dlls/loadperf enable_loadperf -wine_fn_config_makefile dlls/localspl enable_localspl -wine_fn_config_makefile dlls/localspl/tests enable_tests -wine_fn_config_makefile dlls/localui enable_localui -wine_fn_config_makefile dlls/localui/tests enable_tests -wine_fn_config_makefile dlls/lz32 enable_lz32 -wine_fn_config_makefile dlls/lz32/tests enable_tests -wine_fn_config_makefile dlls/lzexpand.dll16 enable_win16 -wine_fn_config_makefile dlls/mapi32 enable_mapi32 -wine_fn_config_makefile dlls/mapi32/tests enable_tests -wine_fn_config_makefile dlls/mapistub enable_mapistub -wine_fn_config_makefile dlls/mciavi32 enable_mciavi32 -wine_fn_config_makefile dlls/mcicda enable_mcicda -wine_fn_config_makefile dlls/mciqtz32 enable_mciqtz32 -wine_fn_config_makefile dlls/mciseq enable_mciseq -wine_fn_config_makefile dlls/mciwave enable_mciwave -wine_fn_config_makefile dlls/mf enable_mf -wine_fn_config_makefile dlls/mf/tests enable_tests -wine_fn_config_makefile dlls/mf3216 enable_mf3216 -wine_fn_config_makefile dlls/mferror enable_mferror -wine_fn_config_makefile dlls/mfmediaengine enable_mfmediaengine -wine_fn_config_makefile dlls/mfmediaengine/tests enable_tests -wine_fn_config_makefile dlls/mfplat enable_mfplat -wine_fn_config_makefile dlls/mfplat/tests enable_tests -wine_fn_config_makefile dlls/mfplay enable_mfplay -wine_fn_config_makefile dlls/mfplay/tests enable_tests -wine_fn_config_makefile dlls/mfreadwrite enable_mfreadwrite -wine_fn_config_makefile dlls/mfreadwrite/tests enable_tests -wine_fn_config_makefile dlls/mfsrcsnk enable_mfsrcsnk -wine_fn_config_makefile dlls/mfsrcsnk/tests enable_tests -wine_fn_config_makefile dlls/mgmtapi enable_mgmtapi -wine_fn_config_makefile dlls/midimap enable_midimap -wine_fn_config_makefile dlls/mlang enable_mlang -wine_fn_config_makefile dlls/mlang/tests enable_tests -wine_fn_config_makefile dlls/mmcndmgr enable_mmcndmgr -wine_fn_config_makefile dlls/mmcndmgr/tests enable_tests -wine_fn_config_makefile dlls/mmdevapi enable_mmdevapi -wine_fn_config_makefile dlls/mmdevapi/tests enable_tests -wine_fn_config_makefile dlls/mmdevldr.vxd enable_win16 -wine_fn_config_makefile dlls/mmsystem.dll16 enable_win16 -wine_fn_config_makefile dlls/monodebg.vxd enable_win16 -wine_fn_config_makefile dlls/mountmgr.sys enable_mountmgr_sys -wine_fn_config_makefile dlls/mouse.drv16 enable_win16 -wine_fn_config_makefile dlls/mp3dmod enable_mp3dmod -wine_fn_config_makefile dlls/mp3dmod/tests enable_tests -wine_fn_config_makefile dlls/mpr enable_mpr -wine_fn_config_makefile dlls/mpr/tests enable_tests -wine_fn_config_makefile dlls/mprapi enable_mprapi -wine_fn_config_makefile dlls/msacm.dll16 enable_win16 -wine_fn_config_makefile dlls/msacm32.drv enable_msacm32_drv -wine_fn_config_makefile dlls/msacm32 enable_msacm32 -wine_fn_config_makefile dlls/msacm32/tests enable_tests -wine_fn_config_makefile dlls/msado15 enable_msado15 -wine_fn_config_makefile dlls/msado15/tests enable_tests -wine_fn_config_makefile dlls/msadp32.acm enable_msadp32_acm -wine_fn_config_makefile dlls/msasn1 enable_msasn1 -wine_fn_config_makefile dlls/msasn1/tests enable_tests -wine_fn_config_makefile dlls/mscat32 enable_mscat32 -wine_fn_config_makefile dlls/mscms enable_mscms -wine_fn_config_makefile dlls/mscms/tests enable_tests -wine_fn_config_makefile dlls/mscoree enable_mscoree -wine_fn_config_makefile dlls/mscoree/tests enable_tests -wine_fn_config_makefile dlls/mscorwks enable_mscorwks -wine_fn_config_makefile dlls/msctf enable_msctf -wine_fn_config_makefile dlls/msctf/tests enable_tests -wine_fn_config_makefile dlls/msctfmonitor enable_msctfmonitor -wine_fn_config_makefile dlls/msctfp enable_msctfp -wine_fn_config_makefile dlls/msdaps enable_msdaps -wine_fn_config_makefile dlls/msdasql enable_msdasql -wine_fn_config_makefile dlls/msdasql/tests enable_tests -wine_fn_config_makefile dlls/msdelta enable_msdelta -wine_fn_config_makefile dlls/msdmo enable_msdmo -wine_fn_config_makefile dlls/msdmo/tests enable_tests -wine_fn_config_makefile dlls/msdrm enable_msdrm -wine_fn_config_makefile dlls/msftedit enable_msftedit -wine_fn_config_makefile dlls/msftedit/tests enable_tests -wine_fn_config_makefile dlls/msg711.acm enable_msg711_acm -wine_fn_config_makefile dlls/msgsm32.acm enable_msgsm32_acm -wine_fn_config_makefile dlls/mshtml.tlb enable_mshtml_tlb -wine_fn_config_makefile dlls/mshtml enable_mshtml -wine_fn_config_makefile dlls/mshtml/tests enable_tests -wine_fn_config_makefile dlls/msi enable_msi -wine_fn_config_makefile dlls/msi/tests enable_tests -wine_fn_config_makefile dlls/msident enable_msident -wine_fn_config_makefile dlls/msimg32 enable_msimg32 -wine_fn_config_makefile dlls/msimsg enable_msimsg -wine_fn_config_makefile dlls/msimtf enable_msimtf -wine_fn_config_makefile dlls/msisip enable_msisip -wine_fn_config_makefile dlls/msisys.ocx enable_msisys_ocx -wine_fn_config_makefile dlls/msls31 enable_msls31 -wine_fn_config_makefile dlls/msnet32 enable_msnet32 -wine_fn_config_makefile dlls/mspatcha enable_mspatcha -wine_fn_config_makefile dlls/mspatcha/tests enable_tests -wine_fn_config_makefile dlls/msports enable_msports -wine_fn_config_makefile dlls/msrle32 enable_msrle32 -wine_fn_config_makefile dlls/msrle32/tests enable_tests -wine_fn_config_makefile dlls/msscript.ocx enable_msscript_ocx -wine_fn_config_makefile dlls/msscript.ocx/tests enable_tests -wine_fn_config_makefile dlls/mssign32 enable_mssign32 -wine_fn_config_makefile dlls/mssip32 enable_mssip32 -wine_fn_config_makefile dlls/mstask enable_mstask -wine_fn_config_makefile dlls/mstask/tests enable_tests -wine_fn_config_makefile dlls/msv1_0 enable_msv1_0 -wine_fn_config_makefile dlls/msvcirt enable_msvcirt -wine_fn_config_makefile dlls/msvcirt/tests enable_tests -wine_fn_config_makefile dlls/msvcm80 enable_msvcm80 -wine_fn_config_makefile dlls/msvcm90 enable_msvcm90 -wine_fn_config_makefile dlls/msvcp100 enable_msvcp100 -wine_fn_config_makefile dlls/msvcp100/tests enable_tests -wine_fn_config_makefile dlls/msvcp110 enable_msvcp110 -wine_fn_config_makefile dlls/msvcp110/tests enable_tests -wine_fn_config_makefile dlls/msvcp120 enable_msvcp120 -wine_fn_config_makefile dlls/msvcp120/tests enable_tests -wine_fn_config_makefile dlls/msvcp120_app enable_msvcp120_app -wine_fn_config_makefile dlls/msvcp140 enable_msvcp140 -wine_fn_config_makefile dlls/msvcp140/tests enable_tests -wine_fn_config_makefile dlls/msvcp140_1 enable_msvcp140_1 -wine_fn_config_makefile dlls/msvcp140_1/tests enable_tests -wine_fn_config_makefile dlls/msvcp140_2 enable_msvcp140_2 -wine_fn_config_makefile dlls/msvcp140_atomic_wait enable_msvcp140_atomic_wait -wine_fn_config_makefile dlls/msvcp140_atomic_wait/tests enable_tests -wine_fn_config_makefile dlls/msvcp60 enable_msvcp60 -wine_fn_config_makefile dlls/msvcp60/tests enable_tests -wine_fn_config_makefile dlls/msvcp70 enable_msvcp70 -wine_fn_config_makefile dlls/msvcp71 enable_msvcp71 -wine_fn_config_makefile dlls/msvcp80 enable_msvcp80 -wine_fn_config_makefile dlls/msvcp90 enable_msvcp90 -wine_fn_config_makefile dlls/msvcp90/tests enable_tests -wine_fn_config_makefile dlls/msvcp_win enable_msvcp_win -wine_fn_config_makefile dlls/msvcr100 enable_msvcr100 -wine_fn_config_makefile dlls/msvcr100/tests enable_tests -wine_fn_config_makefile dlls/msvcr110 enable_msvcr110 -wine_fn_config_makefile dlls/msvcr110/tests enable_tests -wine_fn_config_makefile dlls/msvcr120 enable_msvcr120 -wine_fn_config_makefile dlls/msvcr120/tests enable_tests -wine_fn_config_makefile dlls/msvcr120_app enable_msvcr120_app -wine_fn_config_makefile dlls/msvcr70 enable_msvcr70 -wine_fn_config_makefile dlls/msvcr70/tests enable_tests -wine_fn_config_makefile dlls/msvcr71 enable_msvcr71 -wine_fn_config_makefile dlls/msvcr71/tests enable_tests -wine_fn_config_makefile dlls/msvcr80 enable_msvcr80 -wine_fn_config_makefile dlls/msvcr80/tests enable_tests -wine_fn_config_makefile dlls/msvcr90 enable_msvcr90 -wine_fn_config_makefile dlls/msvcr90/tests enable_tests -wine_fn_config_makefile dlls/msvcrt enable_msvcrt -wine_fn_config_makefile dlls/msvcrt/tests enable_tests -wine_fn_config_makefile dlls/msvcrt20 enable_msvcrt20 -wine_fn_config_makefile dlls/msvcrt40 enable_msvcrt40 -wine_fn_config_makefile dlls/msvcrtd enable_msvcrtd -wine_fn_config_makefile dlls/msvcrtd/tests enable_tests -wine_fn_config_makefile dlls/msvfw32 enable_msvfw32 -wine_fn_config_makefile dlls/msvfw32/tests enable_tests -wine_fn_config_makefile dlls/msvidc32 enable_msvidc32 -wine_fn_config_makefile dlls/msvideo.dll16 enable_win16 -wine_fn_config_makefile dlls/mswsock enable_mswsock -wine_fn_config_makefile dlls/msxml enable_msxml -wine_fn_config_makefile dlls/msxml2 enable_msxml2 -wine_fn_config_makefile dlls/msxml3 enable_msxml3 -wine_fn_config_makefile dlls/msxml3/tests enable_tests -wine_fn_config_makefile dlls/msxml4 enable_msxml4 -wine_fn_config_makefile dlls/msxml6 enable_msxml6 -wine_fn_config_makefile dlls/mtxdm enable_mtxdm -wine_fn_config_makefile dlls/ncrypt enable_ncrypt -wine_fn_config_makefile dlls/ncrypt/tests enable_tests -wine_fn_config_makefile dlls/nddeapi enable_nddeapi -wine_fn_config_makefile dlls/ndis.sys enable_ndis_sys -wine_fn_config_makefile dlls/ndis.sys/tests enable_tests -wine_fn_config_makefile dlls/netapi32 enable_netapi32 -wine_fn_config_makefile dlls/netapi32/tests enable_tests -wine_fn_config_makefile dlls/netcfgx enable_netcfgx -wine_fn_config_makefile dlls/netcfgx/tests enable_tests -wine_fn_config_makefile dlls/netio.sys enable_netio_sys -wine_fn_config_makefile dlls/netprofm enable_netprofm -wine_fn_config_makefile dlls/netprofm/tests enable_tests -wine_fn_config_makefile dlls/netutils enable_netutils -wine_fn_config_makefile dlls/newdev enable_newdev -wine_fn_config_makefile dlls/ninput enable_ninput -wine_fn_config_makefile dlls/ninput/tests enable_tests -wine_fn_config_makefile dlls/normaliz enable_normaliz -wine_fn_config_makefile dlls/npmshtml enable_npmshtml -wine_fn_config_makefile dlls/npptools enable_npptools -wine_fn_config_makefile dlls/nsi enable_nsi -wine_fn_config_makefile dlls/nsi/tests enable_tests -wine_fn_config_makefile dlls/nsiproxy.sys enable_nsiproxy_sys -wine_fn_config_makefile dlls/ntdll enable_ntdll -wine_fn_config_makefile dlls/ntdll/tests enable_tests -wine_fn_config_makefile dlls/ntdsapi enable_ntdsapi -wine_fn_config_makefile dlls/ntdsapi/tests enable_tests -wine_fn_config_makefile dlls/ntoskrnl.exe enable_ntoskrnl_exe -wine_fn_config_makefile dlls/ntoskrnl.exe/tests enable_tests -wine_fn_config_makefile dlls/ntprint enable_ntprint -wine_fn_config_makefile dlls/ntprint/tests enable_tests -wine_fn_config_makefile dlls/objsel enable_objsel -wine_fn_config_makefile dlls/odbc32 enable_odbc32 -wine_fn_config_makefile dlls/odbcbcp enable_odbcbcp -wine_fn_config_makefile dlls/odbccp32 enable_odbccp32 -wine_fn_config_makefile dlls/odbccp32/tests enable_tests -wine_fn_config_makefile dlls/odbccu32 enable_odbccu32 -wine_fn_config_makefile dlls/ole2.dll16 enable_win16 -wine_fn_config_makefile dlls/ole2conv.dll16 enable_win16 -wine_fn_config_makefile dlls/ole2disp.dll16 enable_win16 -wine_fn_config_makefile dlls/ole2nls.dll16 enable_win16 -wine_fn_config_makefile dlls/ole2prox.dll16 enable_win16 -wine_fn_config_makefile dlls/ole2thk.dll16 enable_win16 -wine_fn_config_makefile dlls/ole32 enable_ole32 -wine_fn_config_makefile dlls/ole32/tests enable_tests -wine_fn_config_makefile dlls/oleacc enable_oleacc -wine_fn_config_makefile dlls/oleacc/tests enable_tests -wine_fn_config_makefile dlls/oleaut32 enable_oleaut32 -wine_fn_config_makefile dlls/oleaut32/tests enable_tests -wine_fn_config_makefile dlls/olecli.dll16 enable_win16 -wine_fn_config_makefile dlls/olecli32 enable_olecli32 -wine_fn_config_makefile dlls/oledb32 enable_oledb32 -wine_fn_config_makefile dlls/oledb32/tests enable_tests -wine_fn_config_makefile dlls/oledlg enable_oledlg -wine_fn_config_makefile dlls/oledlg/tests enable_tests -wine_fn_config_makefile dlls/olepro32 enable_olepro32 -wine_fn_config_makefile dlls/olesvr.dll16 enable_win16 -wine_fn_config_makefile dlls/olesvr32 enable_olesvr32 -wine_fn_config_makefile dlls/olethk32 enable_olethk32 -wine_fn_config_makefile dlls/opcservices enable_opcservices -wine_fn_config_makefile dlls/opcservices/tests enable_tests -wine_fn_config_makefile dlls/opencl enable_opencl -wine_fn_config_makefile dlls/opengl32 enable_opengl32 -wine_fn_config_makefile dlls/opengl32/tests enable_tests -wine_fn_config_makefile dlls/packager enable_packager -wine_fn_config_makefile dlls/packager/tests enable_tests -wine_fn_config_makefile dlls/pdh enable_pdh -wine_fn_config_makefile dlls/pdh/tests enable_tests -wine_fn_config_makefile dlls/photometadatahandler enable_photometadatahandler -wine_fn_config_makefile dlls/pidgen enable_pidgen -wine_fn_config_makefile dlls/powrprof enable_powrprof -wine_fn_config_makefile dlls/printui enable_printui -wine_fn_config_makefile dlls/prntvpt enable_prntvpt -wine_fn_config_makefile dlls/prntvpt/tests enable_tests -wine_fn_config_makefile dlls/propsys enable_propsys -wine_fn_config_makefile dlls/propsys/tests enable_tests -wine_fn_config_makefile dlls/psapi enable_psapi -wine_fn_config_makefile dlls/psapi/tests enable_tests -wine_fn_config_makefile dlls/pstorec enable_pstorec -wine_fn_config_makefile dlls/pstorec/tests enable_tests -wine_fn_config_makefile dlls/pwrshplugin enable_pwrshplugin -wine_fn_config_makefile dlls/qasf enable_qasf -wine_fn_config_makefile dlls/qasf/tests enable_tests -wine_fn_config_makefile dlls/qcap enable_qcap -wine_fn_config_makefile dlls/qcap/tests enable_tests -wine_fn_config_makefile dlls/qdvd enable_qdvd -wine_fn_config_makefile dlls/qdvd/tests enable_tests -wine_fn_config_makefile dlls/qedit enable_qedit -wine_fn_config_makefile dlls/qedit/tests enable_tests -wine_fn_config_makefile dlls/qmgr enable_qmgr -wine_fn_config_makefile dlls/qmgr/tests enable_tests -wine_fn_config_makefile dlls/qmgrprxy enable_qmgrprxy -wine_fn_config_makefile dlls/quartz enable_quartz -wine_fn_config_makefile dlls/quartz/tests enable_tests -wine_fn_config_makefile dlls/query enable_query -wine_fn_config_makefile dlls/qwave enable_qwave -wine_fn_config_makefile dlls/qwave/tests enable_tests -wine_fn_config_makefile dlls/rasapi16.dll16 enable_win16 -wine_fn_config_makefile dlls/rasapi32 enable_rasapi32 -wine_fn_config_makefile dlls/rasapi32/tests enable_tests -wine_fn_config_makefile dlls/rasdlg enable_rasdlg -wine_fn_config_makefile dlls/regapi enable_regapi -wine_fn_config_makefile dlls/resutils enable_resutils -wine_fn_config_makefile dlls/riched20 enable_riched20 -wine_fn_config_makefile dlls/riched20/tests enable_tests -wine_fn_config_makefile dlls/riched32 enable_riched32 -wine_fn_config_makefile dlls/riched32/tests enable_tests -wine_fn_config_makefile dlls/rpcrt4 enable_rpcrt4 -wine_fn_config_makefile dlls/rpcrt4/tests enable_tests -wine_fn_config_makefile dlls/rsabase enable_rsabase -wine_fn_config_makefile dlls/rsaenh enable_rsaenh -wine_fn_config_makefile dlls/rsaenh/tests enable_tests -wine_fn_config_makefile dlls/rstrtmgr enable_rstrtmgr -wine_fn_config_makefile dlls/rtutils enable_rtutils -wine_fn_config_makefile dlls/rtworkq enable_rtworkq -wine_fn_config_makefile dlls/rtworkq/tests enable_tests -wine_fn_config_makefile dlls/samlib enable_samlib -wine_fn_config_makefile dlls/sane.ds enable_sane_ds -wine_fn_config_makefile dlls/sapi enable_sapi -wine_fn_config_makefile dlls/sapi/tests enable_tests -wine_fn_config_makefile dlls/sas enable_sas -wine_fn_config_makefile dlls/scarddlg enable_scarddlg -wine_fn_config_makefile dlls/sccbase enable_sccbase -wine_fn_config_makefile dlls/schannel enable_schannel -wine_fn_config_makefile dlls/schannel/tests enable_tests -wine_fn_config_makefile dlls/schedsvc enable_schedsvc -wine_fn_config_makefile dlls/schedsvc/tests enable_tests -wine_fn_config_makefile dlls/scrobj enable_scrobj -wine_fn_config_makefile dlls/scrobj/tests enable_tests -wine_fn_config_makefile dlls/scrrun enable_scrrun -wine_fn_config_makefile dlls/scrrun/tests enable_tests -wine_fn_config_makefile dlls/scsiport.sys enable_scsiport_sys -wine_fn_config_makefile dlls/sechost enable_sechost -wine_fn_config_makefile dlls/secur32 enable_secur32 -wine_fn_config_makefile dlls/secur32/tests enable_tests -wine_fn_config_makefile dlls/security enable_security -wine_fn_config_makefile dlls/sensapi enable_sensapi -wine_fn_config_makefile dlls/serialui enable_serialui -wine_fn_config_makefile dlls/serialui/tests enable_tests -wine_fn_config_makefile dlls/setupapi enable_setupapi -wine_fn_config_makefile dlls/setupapi/tests enable_tests -wine_fn_config_makefile dlls/setupx.dll16 enable_win16 -wine_fn_config_makefile dlls/sfc enable_sfc -wine_fn_config_makefile dlls/sfc_os enable_sfc_os -wine_fn_config_makefile dlls/shcore enable_shcore -wine_fn_config_makefile dlls/shcore/tests enable_tests -wine_fn_config_makefile dlls/shdoclc enable_shdoclc -wine_fn_config_makefile dlls/shdocvw enable_shdocvw -wine_fn_config_makefile dlls/shdocvw/tests enable_tests -wine_fn_config_makefile dlls/shell.dll16 enable_win16 -wine_fn_config_makefile dlls/shell32 enable_shell32 -wine_fn_config_makefile dlls/shell32/tests enable_tests -wine_fn_config_makefile dlls/shfolder enable_shfolder -wine_fn_config_makefile dlls/shlwapi enable_shlwapi -wine_fn_config_makefile dlls/shlwapi/tests enable_tests -wine_fn_config_makefile dlls/slbcsp enable_slbcsp -wine_fn_config_makefile dlls/slc enable_slc -wine_fn_config_makefile dlls/slc/tests enable_tests -wine_fn_config_makefile dlls/snmpapi enable_snmpapi -wine_fn_config_makefile dlls/snmpapi/tests enable_tests -wine_fn_config_makefile dlls/softpub enable_softpub -wine_fn_config_makefile dlls/sound.drv16 enable_win16 -wine_fn_config_makefile dlls/spoolss enable_spoolss -wine_fn_config_makefile dlls/spoolss/tests enable_tests -wine_fn_config_makefile dlls/sppc enable_sppc -wine_fn_config_makefile dlls/srclient enable_srclient -wine_fn_config_makefile dlls/srvcli enable_srvcli -wine_fn_config_makefile dlls/sspicli enable_sspicli -wine_fn_config_makefile dlls/stdole2.tlb enable_stdole2_tlb -wine_fn_config_makefile dlls/stdole32.tlb enable_stdole32_tlb -wine_fn_config_makefile dlls/sti enable_sti -wine_fn_config_makefile dlls/sti/tests enable_tests -wine_fn_config_makefile dlls/storage.dll16 enable_win16 -wine_fn_config_makefile dlls/stress.dll16 enable_win16 -wine_fn_config_makefile dlls/strmdll enable_strmdll -wine_fn_config_makefile dlls/svrapi enable_svrapi -wine_fn_config_makefile dlls/sxs enable_sxs -wine_fn_config_makefile dlls/sxs/tests enable_tests -wine_fn_config_makefile dlls/system.drv16 enable_win16 -wine_fn_config_makefile dlls/t2embed enable_t2embed -wine_fn_config_makefile dlls/t2embed/tests enable_tests -wine_fn_config_makefile dlls/tapi32 enable_tapi32 -wine_fn_config_makefile dlls/tapi32/tests enable_tests -wine_fn_config_makefile dlls/taskschd enable_taskschd -wine_fn_config_makefile dlls/taskschd/tests enable_tests -wine_fn_config_makefile dlls/tbs enable_tbs -wine_fn_config_makefile dlls/tdh enable_tdh -wine_fn_config_makefile dlls/tdi.sys enable_tdi_sys -wine_fn_config_makefile dlls/threadpoolwinrt enable_threadpoolwinrt -wine_fn_config_makefile dlls/threadpoolwinrt/tests enable_tests -wine_fn_config_makefile dlls/toolhelp.dll16 enable_win16 -wine_fn_config_makefile dlls/traffic enable_traffic -wine_fn_config_makefile dlls/twain.dll16 enable_win16 -wine_fn_config_makefile dlls/twain_32 enable_twain_32 -wine_fn_config_makefile dlls/twain_32/tests enable_tests -wine_fn_config_makefile dlls/typelib.dll16 enable_win16 -wine_fn_config_makefile dlls/tzres enable_tzres -wine_fn_config_makefile dlls/ucrtbase enable_ucrtbase -wine_fn_config_makefile dlls/ucrtbase/tests enable_tests -wine_fn_config_makefile dlls/uianimation enable_uianimation -wine_fn_config_makefile dlls/uianimation/tests enable_tests -wine_fn_config_makefile dlls/uiautomationcore enable_uiautomationcore -wine_fn_config_makefile dlls/uiautomationcore/tests enable_tests -wine_fn_config_makefile dlls/uiribbon enable_uiribbon -wine_fn_config_makefile dlls/unicows enable_unicows -wine_fn_config_makefile dlls/updspapi enable_updspapi -wine_fn_config_makefile dlls/url enable_url -wine_fn_config_makefile dlls/urlmon enable_urlmon -wine_fn_config_makefile dlls/urlmon/tests enable_tests -wine_fn_config_makefile dlls/usbd.sys enable_usbd_sys -wine_fn_config_makefile dlls/user.exe16 enable_win16 -wine_fn_config_makefile dlls/user32 enable_user32 -wine_fn_config_makefile dlls/user32/tests enable_tests -wine_fn_config_makefile dlls/userenv enable_userenv -wine_fn_config_makefile dlls/userenv/tests enable_tests -wine_fn_config_makefile dlls/usp10 enable_usp10 -wine_fn_config_makefile dlls/usp10/tests enable_tests -wine_fn_config_makefile dlls/utildll enable_utildll -wine_fn_config_makefile dlls/uxtheme enable_uxtheme -wine_fn_config_makefile dlls/uxtheme/tests enable_tests -wine_fn_config_makefile dlls/vbscript enable_vbscript -wine_fn_config_makefile dlls/vbscript/tests enable_tests -wine_fn_config_makefile dlls/vcomp enable_vcomp -wine_fn_config_makefile dlls/vcomp/tests enable_tests -wine_fn_config_makefile dlls/vcomp100 enable_vcomp100 -wine_fn_config_makefile dlls/vcomp110 enable_vcomp110 -wine_fn_config_makefile dlls/vcomp110/tests enable_tests -wine_fn_config_makefile dlls/vcomp120 enable_vcomp120 -wine_fn_config_makefile dlls/vcomp140 enable_vcomp140 -wine_fn_config_makefile dlls/vcomp90 enable_vcomp90 -wine_fn_config_makefile dlls/vcruntime140 enable_vcruntime140 -wine_fn_config_makefile dlls/vcruntime140_1 enable_vcruntime140_1 -wine_fn_config_makefile dlls/vdhcp.vxd enable_win16 -wine_fn_config_makefile dlls/vdmdbg enable_vdmdbg -wine_fn_config_makefile dlls/ver.dll16 enable_win16 -wine_fn_config_makefile dlls/version enable_version -wine_fn_config_makefile dlls/version/tests enable_tests -wine_fn_config_makefile dlls/vga enable_vga -wine_fn_config_makefile dlls/virtdisk enable_virtdisk -wine_fn_config_makefile dlls/virtdisk/tests enable_tests -wine_fn_config_makefile dlls/vmm.vxd enable_win16 -wine_fn_config_makefile dlls/vnbt.vxd enable_win16 -wine_fn_config_makefile dlls/vnetbios.vxd enable_win16 -wine_fn_config_makefile dlls/vssapi enable_vssapi -wine_fn_config_makefile dlls/vtdapi.vxd enable_win16 -wine_fn_config_makefile dlls/vulkan-1 enable_vulkan_1 -wine_fn_config_makefile dlls/vulkan-1/tests enable_tests -wine_fn_config_makefile dlls/vwin32.vxd enable_win16 -wine_fn_config_makefile dlls/w32skrnl enable_win16 -wine_fn_config_makefile dlls/w32sys.dll16 enable_win16 -wine_fn_config_makefile dlls/wbemdisp enable_wbemdisp -wine_fn_config_makefile dlls/wbemdisp/tests enable_tests -wine_fn_config_makefile dlls/wbemprox enable_wbemprox -wine_fn_config_makefile dlls/wbemprox/tests enable_tests -wine_fn_config_makefile dlls/wdscore enable_wdscore -wine_fn_config_makefile dlls/webservices enable_webservices -wine_fn_config_makefile dlls/webservices/tests enable_tests -wine_fn_config_makefile dlls/websocket enable_websocket -wine_fn_config_makefile dlls/wer enable_wer -wine_fn_config_makefile dlls/wer/tests enable_tests -wine_fn_config_makefile dlls/wevtapi enable_wevtapi -wine_fn_config_makefile dlls/wevtapi/tests enable_tests -wine_fn_config_makefile dlls/wevtsvc enable_wevtsvc -wine_fn_config_makefile dlls/wiaservc enable_wiaservc -wine_fn_config_makefile dlls/wiaservc/tests enable_tests -wine_fn_config_makefile dlls/wimgapi enable_wimgapi -wine_fn_config_makefile dlls/win32s16.dll16 enable_win16 -wine_fn_config_makefile dlls/win32u enable_win32u -wine_fn_config_makefile dlls/win32u/tests enable_tests -wine_fn_config_makefile dlls/win87em.dll16 enable_win16 -wine_fn_config_makefile dlls/winaspi.dll16 enable_win16 -wine_fn_config_makefile dlls/windebug.dll16 enable_win16 -wine_fn_config_makefile dlls/windows.devices.enumeration enable_windows_devices_enumeration -wine_fn_config_makefile dlls/windows.devices.enumeration/tests enable_tests -wine_fn_config_makefile dlls/windows.gaming.input enable_windows_gaming_input -wine_fn_config_makefile dlls/windows.gaming.input/tests enable_tests -wine_fn_config_makefile dlls/windows.gaming.ui.gamebar enable_windows_gaming_ui_gamebar -wine_fn_config_makefile dlls/windows.gaming.ui.gamebar/tests enable_tests -wine_fn_config_makefile dlls/windows.globalization enable_windows_globalization -wine_fn_config_makefile dlls/windows.globalization/tests enable_tests -wine_fn_config_makefile dlls/windows.media.devices enable_windows_media_devices -wine_fn_config_makefile dlls/windows.media.devices/tests enable_tests -wine_fn_config_makefile dlls/windows.media.speech enable_windows_media_speech -wine_fn_config_makefile dlls/windows.media.speech/tests enable_tests -wine_fn_config_makefile dlls/windows.media enable_windows_media -wine_fn_config_makefile dlls/windows.media/tests enable_tests -wine_fn_config_makefile dlls/windows.networking enable_windows_networking -wine_fn_config_makefile dlls/windowscodecs enable_windowscodecs -wine_fn_config_makefile dlls/windowscodecs/tests enable_tests -wine_fn_config_makefile dlls/windowscodecsext enable_windowscodecsext -wine_fn_config_makefile dlls/windowscodecsext/tests enable_tests -wine_fn_config_makefile dlls/winealsa.drv enable_winealsa_drv -wine_fn_config_makefile dlls/wineandroid.drv enable_wineandroid_drv -wine_fn_config_makefile dlls/winebus.sys enable_winebus_sys -wine_fn_config_makefile dlls/winecoreaudio.drv enable_winecoreaudio_drv -wine_fn_config_makefile dlls/winecrt0 enable_winecrt0 -wine_fn_config_makefile dlls/wined3d enable_wined3d -wine_fn_config_makefile dlls/winegstreamer enable_winegstreamer -wine_fn_config_makefile dlls/winehid.sys enable_winehid_sys -wine_fn_config_makefile dlls/winemac.drv enable_winemac_drv -wine_fn_config_makefile dlls/winemapi enable_winemapi -wine_fn_config_makefile dlls/wineoss.drv enable_wineoss_drv -wine_fn_config_makefile dlls/wineps.drv enable_wineps_drv -wine_fn_config_makefile dlls/wineps16.drv16 enable_win16 -wine_fn_config_makefile dlls/winepulse.drv enable_winepulse_drv -wine_fn_config_makefile dlls/wineusb.sys enable_wineusb_sys -wine_fn_config_makefile dlls/winevulkan enable_winevulkan -wine_fn_config_makefile dlls/winex11.drv enable_winex11_drv -wine_fn_config_makefile dlls/winexinput.sys enable_winexinput_sys -wine_fn_config_makefile dlls/wing.dll16 enable_win16 -wine_fn_config_makefile dlls/wing32 enable_wing32 -wine_fn_config_makefile dlls/winhttp enable_winhttp -wine_fn_config_makefile dlls/winhttp/tests enable_tests -wine_fn_config_makefile dlls/wininet enable_wininet -wine_fn_config_makefile dlls/wininet/tests enable_tests -wine_fn_config_makefile dlls/winmm enable_winmm -wine_fn_config_makefile dlls/winmm/tests enable_tests -wine_fn_config_makefile dlls/winnls.dll16 enable_win16 -wine_fn_config_makefile dlls/winnls32 enable_winnls32 -wine_fn_config_makefile dlls/winprint enable_winprint -wine_fn_config_makefile dlls/winscard enable_winscard -wine_fn_config_makefile dlls/winsock.dll16 enable_win16 -wine_fn_config_makefile dlls/winspool.drv enable_winspool_drv -wine_fn_config_makefile dlls/winspool.drv/tests enable_tests -wine_fn_config_makefile dlls/winsta enable_winsta -wine_fn_config_makefile dlls/wintab.dll16 enable_win16 -wine_fn_config_makefile dlls/wintab32 enable_wintab32 -wine_fn_config_makefile dlls/wintab32/tests enable_tests -wine_fn_config_makefile dlls/wintrust enable_wintrust -wine_fn_config_makefile dlls/wintrust/tests enable_tests -wine_fn_config_makefile dlls/wintypes enable_wintypes -wine_fn_config_makefile dlls/wintypes/tests enable_tests -wine_fn_config_makefile dlls/winusb enable_winusb -wine_fn_config_makefile dlls/wlanapi enable_wlanapi -wine_fn_config_makefile dlls/wlanapi/tests enable_tests -wine_fn_config_makefile dlls/wlanui enable_wlanui -wine_fn_config_makefile dlls/wldap32 enable_wldap32 -wine_fn_config_makefile dlls/wldap32/tests enable_tests -wine_fn_config_makefile dlls/wmasf enable_wmasf -wine_fn_config_makefile dlls/wmi enable_wmi -wine_fn_config_makefile dlls/wmiutils enable_wmiutils -wine_fn_config_makefile dlls/wmiutils/tests enable_tests -wine_fn_config_makefile dlls/wmp enable_wmp -wine_fn_config_makefile dlls/wmp/tests enable_tests -wine_fn_config_makefile dlls/wmphoto enable_wmphoto -wine_fn_config_makefile dlls/wmvcore enable_wmvcore -wine_fn_config_makefile dlls/wmvcore/tests enable_tests -wine_fn_config_makefile dlls/wnaspi32 enable_wnaspi32 -wine_fn_config_makefile dlls/wofutil enable_wofutil -wine_fn_config_makefile dlls/wow32 enable_win16 -wine_fn_config_makefile dlls/wow64 enable_wow64 -wine_fn_config_makefile dlls/wow64cpu enable_wow64cpu -wine_fn_config_makefile dlls/wow64win enable_wow64win -wine_fn_config_makefile dlls/wpc enable_wpc -wine_fn_config_makefile dlls/wpc/tests enable_tests -wine_fn_config_makefile dlls/wpcap enable_wpcap -wine_fn_config_makefile dlls/ws2_32 enable_ws2_32 -wine_fn_config_makefile dlls/ws2_32/tests enable_tests -wine_fn_config_makefile dlls/wsdapi enable_wsdapi -wine_fn_config_makefile dlls/wsdapi/tests enable_tests -wine_fn_config_makefile dlls/wshom.ocx enable_wshom_ocx -wine_fn_config_makefile dlls/wshom.ocx/tests enable_tests -wine_fn_config_makefile dlls/wsnmp32 enable_wsnmp32 -wine_fn_config_makefile dlls/wsnmp32/tests enable_tests -wine_fn_config_makefile dlls/wsock32 enable_wsock32 -wine_fn_config_makefile dlls/wtsapi32 enable_wtsapi32 -wine_fn_config_makefile dlls/wtsapi32/tests enable_tests -wine_fn_config_makefile dlls/wuapi enable_wuapi -wine_fn_config_makefile dlls/wuaueng enable_wuaueng -wine_fn_config_makefile dlls/x3daudio1_0 enable_x3daudio1_0 -wine_fn_config_makefile dlls/x3daudio1_1 enable_x3daudio1_1 -wine_fn_config_makefile dlls/x3daudio1_2 enable_x3daudio1_2 -wine_fn_config_makefile dlls/x3daudio1_3 enable_x3daudio1_3 -wine_fn_config_makefile dlls/x3daudio1_4 enable_x3daudio1_4 -wine_fn_config_makefile dlls/x3daudio1_5 enable_x3daudio1_5 -wine_fn_config_makefile dlls/x3daudio1_6 enable_x3daudio1_6 -wine_fn_config_makefile dlls/x3daudio1_7 enable_x3daudio1_7 -wine_fn_config_makefile dlls/xactengine2_0 enable_xactengine2_0 -wine_fn_config_makefile dlls/xactengine2_4 enable_xactengine2_4 -wine_fn_config_makefile dlls/xactengine2_7 enable_xactengine2_7 -wine_fn_config_makefile dlls/xactengine2_9 enable_xactengine2_9 -wine_fn_config_makefile dlls/xactengine3_0 enable_xactengine3_0 -wine_fn_config_makefile dlls/xactengine3_1 enable_xactengine3_1 -wine_fn_config_makefile dlls/xactengine3_2 enable_xactengine3_2 -wine_fn_config_makefile dlls/xactengine3_3 enable_xactengine3_3 -wine_fn_config_makefile dlls/xactengine3_4 enable_xactengine3_4 -wine_fn_config_makefile dlls/xactengine3_5 enable_xactengine3_5 -wine_fn_config_makefile dlls/xactengine3_6 enable_xactengine3_6 -wine_fn_config_makefile dlls/xactengine3_7 enable_xactengine3_7 -wine_fn_config_makefile dlls/xactengine3_7/tests enable_tests -wine_fn_config_makefile dlls/xapofx1_1 enable_xapofx1_1 -wine_fn_config_makefile dlls/xapofx1_2 enable_xapofx1_2 -wine_fn_config_makefile dlls/xapofx1_3 enable_xapofx1_3 -wine_fn_config_makefile dlls/xapofx1_4 enable_xapofx1_4 -wine_fn_config_makefile dlls/xapofx1_5 enable_xapofx1_5 -wine_fn_config_makefile dlls/xaudio2_0 enable_xaudio2_0 -wine_fn_config_makefile dlls/xaudio2_1 enable_xaudio2_1 -wine_fn_config_makefile dlls/xaudio2_2 enable_xaudio2_2 -wine_fn_config_makefile dlls/xaudio2_3 enable_xaudio2_3 -wine_fn_config_makefile dlls/xaudio2_4 enable_xaudio2_4 -wine_fn_config_makefile dlls/xaudio2_5 enable_xaudio2_5 -wine_fn_config_makefile dlls/xaudio2_6 enable_xaudio2_6 -wine_fn_config_makefile dlls/xaudio2_7 enable_xaudio2_7 -wine_fn_config_makefile dlls/xaudio2_7/tests enable_tests -wine_fn_config_makefile dlls/xaudio2_8 enable_xaudio2_8 -wine_fn_config_makefile dlls/xaudio2_9 enable_xaudio2_9 -wine_fn_config_makefile dlls/xinput1_1 enable_xinput1_1 -wine_fn_config_makefile dlls/xinput1_2 enable_xinput1_2 -wine_fn_config_makefile dlls/xinput1_3 enable_xinput1_3 -wine_fn_config_makefile dlls/xinput1_3/tests enable_tests -wine_fn_config_makefile dlls/xinput1_4 enable_xinput1_4 -wine_fn_config_makefile dlls/xinput9_1_0 enable_xinput9_1_0 -wine_fn_config_makefile dlls/xinputuap enable_xinputuap -wine_fn_config_makefile dlls/xmllite enable_xmllite -wine_fn_config_makefile dlls/xmllite/tests enable_tests -wine_fn_config_makefile dlls/xolehlp enable_xolehlp -wine_fn_config_makefile dlls/xpsprint enable_xpsprint -wine_fn_config_makefile dlls/xpssvcs enable_xpssvcs -wine_fn_config_makefile fonts enable_fonts -wine_fn_config_makefile include enable_include -wine_fn_config_makefile libs/adsiid enable_adsiid -wine_fn_config_makefile libs/dmoguids enable_dmoguids -wine_fn_config_makefile libs/dxerr8 enable_dxerr8 -wine_fn_config_makefile libs/dxerr9 enable_dxerr9 -wine_fn_config_makefile libs/dxguid enable_dxguid -wine_fn_config_makefile libs/faudio enable_faudio -wine_fn_config_makefile libs/gsm enable_gsm -wine_fn_config_makefile libs/jpeg enable_jpeg -wine_fn_config_makefile libs/jxr enable_jxr -wine_fn_config_makefile libs/lcms2 enable_lcms2 -wine_fn_config_makefile libs/ldap enable_ldap -wine_fn_config_makefile libs/mfuuid enable_mfuuid -wine_fn_config_makefile libs/mpg123 enable_mpg123 -wine_fn_config_makefile libs/png enable_png -wine_fn_config_makefile libs/strmbase enable_strmbase -wine_fn_config_makefile libs/strmiids enable_strmiids -wine_fn_config_makefile libs/tiff enable_tiff -wine_fn_config_makefile libs/uuid enable_uuid -wine_fn_config_makefile libs/vkd3d enable_vkd3d -wine_fn_config_makefile libs/wbemuuid enable_wbemuuid -wine_fn_config_makefile libs/wine enable_wine -wine_fn_config_makefile libs/wmcodecdspuuid enable_wmcodecdspuuid -wine_fn_config_makefile libs/xml2 enable_xml2 -wine_fn_config_makefile libs/xslt enable_xslt -wine_fn_config_makefile libs/zlib enable_zlib -wine_fn_config_makefile loader enable_loader -wine_fn_config_makefile nls enable_nls -wine_fn_config_makefile po enable_po -wine_fn_config_makefile programs/arp enable_arp -wine_fn_config_makefile programs/aspnet_regiis enable_aspnet_regiis -wine_fn_config_makefile programs/attrib enable_attrib -wine_fn_config_makefile programs/cabarc enable_cabarc -wine_fn_config_makefile programs/cacls enable_cacls -wine_fn_config_makefile programs/certutil enable_certutil -wine_fn_config_makefile programs/chcp.com enable_chcp_com -wine_fn_config_makefile programs/clock enable_clock -wine_fn_config_makefile programs/cmd enable_cmd -wine_fn_config_makefile programs/cmd/tests enable_tests -wine_fn_config_makefile programs/conhost enable_conhost -wine_fn_config_makefile programs/conhost/tests enable_tests -wine_fn_config_makefile programs/control enable_control -wine_fn_config_makefile programs/cscript enable_cscript -wine_fn_config_makefile programs/dism enable_dism -wine_fn_config_makefile programs/dllhost enable_dllhost -wine_fn_config_makefile programs/dplaysvr enable_dplaysvr -wine_fn_config_makefile programs/dpnsvr enable_dpnsvr -wine_fn_config_makefile programs/dpvsetup enable_dpvsetup -wine_fn_config_makefile programs/dxdiag enable_dxdiag -wine_fn_config_makefile programs/eject enable_eject -wine_fn_config_makefile programs/expand enable_expand -wine_fn_config_makefile programs/explorer enable_explorer -wine_fn_config_makefile programs/explorer/tests enable_tests -wine_fn_config_makefile programs/extrac32 enable_extrac32 -wine_fn_config_makefile programs/fc enable_fc -wine_fn_config_makefile programs/find enable_find -wine_fn_config_makefile programs/find/tests enable_tests -wine_fn_config_makefile programs/findstr enable_findstr -wine_fn_config_makefile programs/fsutil enable_fsutil -wine_fn_config_makefile programs/fsutil/tests enable_tests -wine_fn_config_makefile programs/hh enable_hh -wine_fn_config_makefile programs/hostname enable_hostname -wine_fn_config_makefile programs/icacls enable_icacls -wine_fn_config_makefile programs/icinfo enable_icinfo -wine_fn_config_makefile programs/iexplore enable_iexplore -wine_fn_config_makefile programs/ipconfig enable_ipconfig -wine_fn_config_makefile programs/lodctr enable_lodctr -wine_fn_config_makefile programs/mofcomp enable_mofcomp -wine_fn_config_makefile programs/mshta enable_mshta -wine_fn_config_makefile programs/msidb enable_msidb -wine_fn_config_makefile programs/msiexec enable_msiexec -wine_fn_config_makefile programs/msinfo32 enable_msinfo32 -wine_fn_config_makefile programs/net enable_net -wine_fn_config_makefile programs/netsh enable_netsh -wine_fn_config_makefile programs/netstat enable_netstat -wine_fn_config_makefile programs/ngen enable_ngen -wine_fn_config_makefile programs/notepad enable_notepad -wine_fn_config_makefile programs/oleview enable_oleview -wine_fn_config_makefile programs/ping enable_ping -wine_fn_config_makefile programs/plugplay enable_plugplay -wine_fn_config_makefile programs/powershell enable_powershell -wine_fn_config_makefile programs/presentationfontcache enable_presentationfontcache -wine_fn_config_makefile programs/progman enable_progman -wine_fn_config_makefile programs/reg enable_reg -wine_fn_config_makefile programs/reg/tests enable_tests -wine_fn_config_makefile programs/regasm enable_regasm -wine_fn_config_makefile programs/regedit enable_regedit -wine_fn_config_makefile programs/regedit/tests enable_tests -wine_fn_config_makefile programs/regini enable_regini -wine_fn_config_makefile programs/regsvcs enable_regsvcs -wine_fn_config_makefile programs/regsvr32 enable_regsvr32 -wine_fn_config_makefile programs/robocopy enable_robocopy -wine_fn_config_makefile programs/rpcss enable_rpcss -wine_fn_config_makefile programs/rundll.exe16 enable_win16 -wine_fn_config_makefile programs/rundll32 enable_rundll32 -wine_fn_config_makefile programs/sc enable_sc -wine_fn_config_makefile programs/sc/tests enable_tests -wine_fn_config_makefile programs/schtasks enable_schtasks -wine_fn_config_makefile programs/schtasks/tests enable_tests -wine_fn_config_makefile programs/sdbinst enable_sdbinst -wine_fn_config_makefile programs/secedit enable_secedit -wine_fn_config_makefile programs/servicemodelreg enable_servicemodelreg -wine_fn_config_makefile programs/services enable_services -wine_fn_config_makefile programs/services/tests enable_tests -wine_fn_config_makefile programs/setx enable_setx -wine_fn_config_makefile programs/shutdown enable_shutdown -wine_fn_config_makefile programs/spoolsv enable_spoolsv -wine_fn_config_makefile programs/start enable_start -wine_fn_config_makefile programs/subst enable_subst -wine_fn_config_makefile programs/svchost enable_svchost -wine_fn_config_makefile programs/systeminfo enable_systeminfo -wine_fn_config_makefile programs/taskkill enable_taskkill -wine_fn_config_makefile programs/tasklist enable_tasklist -wine_fn_config_makefile programs/taskmgr enable_taskmgr -wine_fn_config_makefile programs/termsv enable_termsv -wine_fn_config_makefile programs/uninstaller enable_uninstaller -wine_fn_config_makefile programs/unlodctr enable_unlodctr -wine_fn_config_makefile programs/view enable_view -wine_fn_config_makefile programs/wevtutil enable_wevtutil -wine_fn_config_makefile programs/where enable_where -wine_fn_config_makefile programs/whoami enable_whoami -wine_fn_config_makefile programs/wineboot enable_wineboot -wine_fn_config_makefile programs/winebrowser enable_winebrowser -wine_fn_config_makefile programs/winecfg enable_winecfg -wine_fn_config_makefile programs/wineconsole enable_wineconsole -wine_fn_config_makefile programs/winedbg enable_winedbg -wine_fn_config_makefile programs/winedevice enable_winedevice -wine_fn_config_makefile programs/winefile enable_winefile -wine_fn_config_makefile programs/winemenubuilder enable_winemenubuilder -wine_fn_config_makefile programs/winemine enable_winemine -wine_fn_config_makefile programs/winemsibuilder enable_winemsibuilder -wine_fn_config_makefile programs/winepath enable_winepath -wine_fn_config_makefile programs/winetest enable_winetest -wine_fn_config_makefile programs/winevdm enable_win16 -wine_fn_config_makefile programs/winhelp.exe16 enable_win16 -wine_fn_config_makefile programs/winhlp32 enable_winhlp32 -wine_fn_config_makefile programs/winmgmt enable_winmgmt -wine_fn_config_makefile programs/winoldap.mod16 enable_win16 -wine_fn_config_makefile programs/winver enable_winver -wine_fn_config_makefile programs/wmic enable_wmic -wine_fn_config_makefile programs/wmplayer enable_wmplayer -wine_fn_config_makefile programs/wordpad enable_wordpad -wine_fn_config_makefile programs/write enable_write -wine_fn_config_makefile programs/wscript enable_wscript -wine_fn_config_makefile programs/wscript/tests enable_tests -wine_fn_config_makefile programs/wuauserv enable_wuauserv -wine_fn_config_makefile programs/wusa enable_wusa -wine_fn_config_makefile programs/xcopy enable_xcopy -wine_fn_config_makefile programs/xcopy/tests enable_tests -wine_fn_config_makefile server enable_server -test "x$enable_tools" = xno || wine_fn_config_makefile tools enable_tools -test "x$enable_tools" = xno || wine_fn_config_makefile tools/sfnt2fon enable_sfnt2fon -test "x$enable_tools" = xno || wine_fn_config_makefile tools/widl enable_widl -test "x$enable_tools" = xno || wine_fn_config_makefile tools/winebuild enable_winebuild -test "x$enable_tools" = xno || wine_fn_config_makefile tools/winedump enable_winedump -test "x$enable_tools" = xno || wine_fn_config_makefile tools/winegcc enable_winegcc -test "x$enable_tools" = xno || wine_fn_config_makefile tools/winemaker enable_winemaker -test "x$enable_tools" = xno || wine_fn_config_makefile tools/wmc enable_wmc -test "x$enable_tools" = xno || wine_fn_config_makefile tools/wrc enable_wrc - - -as_fn_append CONFIGURE_TARGETS " TAGS" -as_fn_append CONFIGURE_TARGETS " tags" -as_fn_append CONFIGURE_TARGETS " autom4te.cache" -as_fn_append CONFIGURE_TARGETS " config.log" -as_fn_append CONFIGURE_TARGETS " config.status" -as_fn_append CONFIGURE_TARGETS " include/config.h" -as_fn_append CONFIGURE_TARGETS " include/stamp-h" -test "$wine_binary" = wine || as_fn_append CONFIGURE_TARGETS " loader/wine" - -if test "x$enable_tools" != xno -then - as_fn_append CONFIGURE_TARGETS " tools/makedep$ac_exeext" - ac_config_commands="$ac_config_commands tools/makedep" - -fi - -ac_config_commands="$ac_config_commands Makefile" - - - -SHELL=/bin/sh - - -as_fn_append wine_rules " -all: wine - @echo \"Wine build complete.\" -.INIT: Makefile -.MAKEFILEDEPS: -all: Makefile -Makefile: config.status \$(MAKEDEP) - @./config.status Makefile -depend: \$(MAKEDEP) - \$(MAKEDEP)$makedep_flags" - - -as_fn_append wine_rules " -config.status: ${wine_srcdir}configure - @./config.status --recheck -include/config.h: include/stamp-h -include/stamp-h: ${wine_srcdir}include/config.h.in config.status - @./config.status include/config.h include/stamp-h" - -if test "x$enable_maintainer_mode" = xyes -then - as_fn_append wine_rules " -configure: configure.ac aclocal.m4 - autoconf --warnings=all -include/config.h.in: include/stamp-h.in -include/stamp-h.in: configure.ac aclocal.m4 - autoheader --warnings=all - @echo timestamp > \$@" -fi - -if test "x$enable_tools" != xno -then - as_fn_append wine_rules " -tools/makedep$ac_exeext: ${wine_srcdir}tools/makedep.c include/config.h config.status - @./config.status tools/makedep -Makefile: tools/makedep$ac_exeext" -else - as_fn_append wine_rules " -\$(MAKEDEP): - @echo \"You need to run make in $toolsdir first\" && false" -fi - - -if test -n "$with_wine64" -then - case "$with_wine64" in - /*) reldir="" ;; - *) reldir="../" ;; - esac - rm -f fonts server 2>/dev/null - as_fn_append wine_rules " -all: loader/wine64 loader/wine64-preloader $with_wine64/loader/wine $with_wine64/loader/wine-preloader -loader/wine64 loader/wine64-preloader: - rm -f \$@ && \$(LN_S) $reldir$with_wine64/\$@ \$@ -$with_wine64/loader/wine: - rm -f \$@ && \$(LN_S) $ac_pwd/loader/wine \$@ -$with_wine64/loader/wine-preloader: - rm -f \$@ && \$(LN_S) $ac_pwd/loader/wine-preloader \$@ -clean:: - rm -f loader/wine64 loader/wine64-preloader $with_wine64/loader/wine $with_wine64/loader/wine-preloader" -else - TOP_INSTALL_DEV="$TOP_INSTALL_DEV include" - TOP_INSTALL_LIB="$TOP_INSTALL_LIB \ -fonts \ -loader/wine.inf \ -nls \ -programs/msidb/msidb \ -programs/msiexec/msiexec \ -programs/notepad/notepad \ -programs/regedit/regedit \ -programs/regsvr32/regsvr32 \ -programs/wineboot/wineboot \ -programs/winecfg/winecfg \ -programs/wineconsole/wineconsole \ -programs/winedbg/winedbg \ -programs/winefile/winefile \ -programs/winemine/winemine \ -programs/winepath/winepath \ -server/wineserver" - - case $host_os in - cygwin*|mingw32*|darwin*|macosx*|linux-android*) ;; - *) TOP_INSTALL_LIB="$TOP_INSTALL_LIB loader/wine.desktop" ;; - esac -fi - - -as_fn_append wine_rules " -distclean:: clean - rm -rf autom4te.cache -maintainer-clean:: - rm -f configure include/config.h.in" - - -as_fn_append wine_rules " -dlls/ntdll/unix/version.c: dummy - @version=\`(GIT_DIR=${wine_srcdir}.git git describe HEAD 2>/dev/null || echo \"wine-\$(PACKAGE_VERSION)\") | sed -n -e '\$\$s/\(.*\)/const char wine_build[] = \"\\1\";/p'\` && (echo \$\$version | cmp -s - \$@) || echo \$\$version >\$@ || (rm -f \$@ && exit 1) -programs/winetest/build.rc: dummy - @build=\"STRINGTABLE { 1 \\\"\`GIT_DIR=${wine_srcdir}.git git rev-parse HEAD 2>/dev/null\`\\\" }\" && (echo \$\$build | cmp -s - \$@) || echo \$\$build >\$@ || (rm -f \$@ && exit 1) -programs/winetest/build.nfo: - @-\$(CC) -v 2>\$@ -dlls/wineandroid.drv/wine-debug.apk: dlls/wineandroid.drv/build.gradle ${wine_srcdir}dlls/wineandroid.drv/AndroidManifest.xml ${wine_srcdir}dlls/wineandroid.drv/WineActivity.java ${wine_srcdir}dlls/wineandroid.drv/wine.svg - cd dlls/wineandroid.drv && gradle -q -Psrcdir=$srcdir assembleDebug - mv dlls/wineandroid.drv/build/outputs/apk/wine-debug.apk \$@" - - -TAGSFLAGS="--langmap='c:+.idl.l.rh,make:(Make*.in)'" - -as_fn_append wine_rules " -TAGS etags: - rm -f TAGS - (test -d .git && git ls-files || find -L $srcdir -name '*.[ch]' -print) | xargs etags -a \$(TAGSFLAGS) -tags ctags: - rm -f tags - (test -d .git && git ls-files || find -L $srcdir -name '*.[ch]' -print) | xargs ctags -a \$(TAGSFLAGS) -dummy: -.PHONY: depend dummy install-manpages" - -printf "%s\n" " done" >&6 -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -printf "%s\n" "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -DEFS=-DHAVE_CONFIG_H - -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIBOBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - - -: "${CONFIG_STATUS=./config.status}" -ac_write_fail=0 -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -as_nop=: -if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 -then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else $as_nop - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - - -# Reset variables that may have inherited troublesome values from -# the environment. - -# IFS needs to be set, to space, tab, and newline, in precisely that order. -# (If _AS_PATH_WALK were called with IFS unset, it would have the -# side effect of setting IFS to empty, thus disabling word splitting.) -# Quoting is to prevent editors from complaining about space-tab. -as_nl=' -' -export as_nl -IFS=" "" $as_nl" - -PS1='$ ' -PS2='> ' -PS4='+ ' - -# Ensure predictable behavior from utilities with locale-dependent output. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# We cannot yet rely on "unset" to work, but we need these variables -# to be unset--not just set to an empty or harmless value--now, to -# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct -# also avoids known problems related to "unset" and subshell syntax -# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). -for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH -do eval test \${$as_var+y} \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done - -# Ensure that fds 0, 1, and 2 are open. -if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi -if (exec 3>&2) ; then :; else exec 2>/dev/null; fi - -# The user is always right. -if ${PATH_SEPARATOR+false} :; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - case $as_dir in #((( - '') as_dir=./ ;; - */) ;; - *) as_dir=$as_dir/ ;; - esac - test -r "$as_dir$0" && as_myself=$as_dir$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - printf "%s\n" "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null -then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else $as_nop - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null -then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else $as_nop - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - -# Determine whether it's possible to make 'echo' print without a newline. -# These variables are no longer used directly by Autoconf, but are AC_SUBSTed -# for compatibility with existing Makefiles. -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -# For backward compatibility with old third-party macros, we provide -# the shell variables $as_echo and $as_echo_n. New code should use -# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. -as_echo='printf %s\n' -as_echo_n='printf %s' - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -exec 6>&1 -## ----------------------------------- ## -## Main body of $CONFIG_STATUS script. ## -## ----------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by Wine $as_me 8.0, which was -generated by GNU Autoconf 2.71. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - - -case $ac_config_headers in *" -"*) set x $ac_config_headers; shift; ac_config_headers=$*;; -esac - - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_headers="$ac_config_headers" -config_links="$ac_config_links" -config_commands="$ac_config_commands" - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -\`$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE - -Configuration headers: -$config_headers - -Configuration links: -$config_links - -Configuration commands: -$config_commands - -Report bugs to . -Wine home page: ." - -_ACEOF -ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` -ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config='$ac_cs_config_escaped' -ac_cs_version="\\ -Wine config.status 8.0 -configured by $0, generated by GNU Autoconf 2.71, - with options \\"\$ac_cs_config\\" - -Copyright (C) 2021 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -test -n "\$AWK" || AWK=awk -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=?*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - printf "%s\n" "$ac_cs_version"; exit ;; - --config | --confi | --conf | --con | --co | --c ) - printf "%s\n" "$ac_cs_config"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --header | --heade | --head | --hea ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append CONFIG_HEADERS " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h) - # Conflict between --help and --header - as_fn_error $? "ambiguous option: \`$1' -Try \`$0 --help' for more information.";; - --help | --hel | -h ) - printf "%s\n" "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error $? "unrecognized option: \`$1' -Try \`$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX -## Running $as_me. ## -_ASBOX - printf "%s\n" "$ac_log" -} >&5 - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# -# INIT-COMMANDS -# -wine_fn_output_makedep () -{ - as_dir=tools; as_fn_mkdir_p - $CC -I${wine_srcdir}tools -Iinclude -I${wine_srcdir}include -D__WINESRC__ $EXTRACFLAGS $CPPFLAGS $CFLAGS -o tools/makedep$ac_exeext ${wine_srcdir}tools/makedep.c $LDFLAGS -} -wine_fn_output_makefile () -{ - cat <<\_WINE_EOF >\$tmp/makefile && mv -f \$tmp/makefile \$1 && "$wine_makedep"$makedep_flags && return -# This Makefile understands the following targets: -# -# all (default): build wine -# clean: remove all intermediate files -# distclean: also remove all files created by configure -# test: run tests -# testclean: clean test results to force running all tests again -# install-lib: install libraries needed to run applications -# install-dev: install development environment -# install: install everything -# uninstall: uninstall everything -# ctags: create a tags file for vim and others. -# etags: create a TAGS file for Emacs. - -SHELL = $SHELL -PATH_SEPARATOR = $PATH_SEPARATOR -PACKAGE_NAME = $PACKAGE_NAME -PACKAGE_TARNAME = $PACKAGE_TARNAME -PACKAGE_VERSION = $PACKAGE_VERSION -PACKAGE_STRING = $PACKAGE_STRING -PACKAGE_BUGREPORT = $PACKAGE_BUGREPORT -PACKAGE_URL = $PACKAGE_URL -exec_prefix = $exec_prefix -prefix = $prefix -program_transform_name = $program_transform_name -bindir = $bindir -sbindir = $sbindir -libexecdir = $libexecdir -datarootdir = $datarootdir -datadir = $datadir -sysconfdir = $sysconfdir -sharedstatedir = $sharedstatedir -localstatedir = $localstatedir -runstatedir = $runstatedir -includedir = $includedir -oldincludedir = $oldincludedir -docdir = $docdir -infodir = $infodir -htmldir = $htmldir -dvidir = $dvidir -pdfdir = $pdfdir -psdir = $psdir -libdir = $libdir -localedir = $localedir -mandir = $mandir -DEFS = $DEFS -ECHO_C = $ECHO_C -ECHO_N = $ECHO_N -ECHO_T = $ECHO_T -LIBS = $LIBS -build_alias = $build_alias -host_alias = $host_alias -target_alias = $target_alias -system_dllpath = $system_dllpath -build = $build -build_cpu = $build_cpu -build_vendor = $build_vendor -build_os = $build_os -host = $host -host_cpu = $host_cpu -host_vendor = $host_vendor -host_os = $host_os -dlldir = $dlldir -fontdir = $fontdir -nlsdir = $nlsdir -srcdir = $srcdir -SET_MAKE = $SET_MAKE -CC = $CC -CFLAGS = $CFLAGS -LDFLAGS = $LDFLAGS -CPPFLAGS = $CPPFLAGS -ac_ct_CC = $ac_ct_CC -EXEEXT = $EXEEXT -OBJEXT = $OBJEXT -CXX = $CXX -CXXFLAGS = $CXXFLAGS -ac_ct_CXX = $ac_ct_CXX -CPPBIN = $CPPBIN -LD = $LD -TARGETFLAGS = $TARGETFLAGS -toolsext = $toolsext -HOST_ARCH = $HOST_ARCH -aarch64_CC = $aarch64_CC -aarch64_CFLAGS = $aarch64_CFLAGS -aarch64_EXTRACFLAGS = $aarch64_EXTRACFLAGS -aarch64_LDFLAGS = $aarch64_LDFLAGS -aarch64_DEBUG = $aarch64_DEBUG -aarch64_TARGET = $aarch64_TARGET -aarch64_DELAYLOADFLAG = $aarch64_DELAYLOADFLAG -aarch64_DISABLED_SUBDIRS = $aarch64_DISABLED_SUBDIRS -arm_CC = $arm_CC -arm_CFLAGS = $arm_CFLAGS -arm_EXTRACFLAGS = $arm_EXTRACFLAGS -arm_LDFLAGS = $arm_LDFLAGS -arm_DEBUG = $arm_DEBUG -arm_TARGET = $arm_TARGET -arm_DELAYLOADFLAG = $arm_DELAYLOADFLAG -arm_DISABLED_SUBDIRS = $arm_DISABLED_SUBDIRS -i386_CC = $i386_CC -i386_CFLAGS = $i386_CFLAGS -i386_EXTRACFLAGS = $i386_EXTRACFLAGS -i386_LDFLAGS = $i386_LDFLAGS -i386_DEBUG = $i386_DEBUG -i386_TARGET = $i386_TARGET -i386_DELAYLOADFLAG = $i386_DELAYLOADFLAG -i386_DISABLED_SUBDIRS = $i386_DISABLED_SUBDIRS -x86_64_CC = $x86_64_CC -x86_64_CFLAGS = $x86_64_CFLAGS -x86_64_EXTRACFLAGS = $x86_64_EXTRACFLAGS -x86_64_LDFLAGS = $x86_64_LDFLAGS -x86_64_DEBUG = $x86_64_DEBUG -x86_64_TARGET = $x86_64_TARGET -x86_64_DELAYLOADFLAG = $x86_64_DELAYLOADFLAG -x86_64_DISABLED_SUBDIRS = $x86_64_DISABLED_SUBDIRS -toolsdir = $toolsdir -MAKEDEP = $MAKEDEP -RUNTESTFLAGS = $RUNTESTFLAGS -SED_CMD = $SED_CMD -FLEX = $FLEX -BISON = $BISON -AR = $AR -ac_ct_AR = $ac_ct_AR -STRIP = $STRIP -RANLIB = $RANLIB -LN_S = $LN_S -GREP = $GREP -EGREP = $EGREP -LDCONFIG = $LDCONFIG -MSGFMT = $MSGFMT -PKG_CONFIG = $PKG_CONFIG -FONTFORGE = $FONTFORGE -RSVG = $RSVG -CONVERT = $CONVERT -ICOTOOL = $ICOTOOL -I386_LIBS = $I386_LIBS -OPENGL_LIBS = $OPENGL_LIBS -DLLFLAGS = $DLLFLAGS -LDDLLFLAGS = $LDDLLFLAGS -LDEXECFLAGS = $LDEXECFLAGS -EXTRACFLAGS = $EXTRACFLAGS -UNIXDLLFLAGS = $UNIXDLLFLAGS -UNIXLDFLAGS = $UNIXLDFLAGS -TOP_INSTALL_LIB = $TOP_INSTALL_LIB -TOP_INSTALL_DEV = $TOP_INSTALL_DEV -WINELOADER_LDFLAGS = $WINELOADER_LDFLAGS -WINEPRELOADER_LDFLAGS = $WINEPRELOADER_LDFLAGS -LDD = $LDD -OTOOL = $OTOOL -READELF = $READELF -SUBDIRS = $SUBDIRS -DISABLED_SUBDIRS = $DISABLED_SUBDIRS -CONFIGURE_TARGETS = $CONFIGURE_TARGETS -CARBON_LIBS = $CARBON_LIBS -COREFOUNDATION_LIBS = $COREFOUNDATION_LIBS -DISKARBITRATION_LIBS = $DISKARBITRATION_LIBS -IOKIT_LIBS = $IOKIT_LIBS -METAL_LIBS = $METAL_LIBS -APPLICATIONSERVICES_LIBS = $APPLICATIONSERVICES_LIBS -CORESERVICES_LIBS = $CORESERVICES_LIBS -APPKIT_LIBS = $APPKIT_LIBS -SECURITY_LIBS = $SECURITY_LIBS -SYSTEMCONFIGURATION_LIBS = $SYSTEMCONFIGURATION_LIBS -COREAUDIO_LIBS = $COREAUDIO_LIBS -OPENCL_LIBS = $OPENCL_LIBS -OBJC = $OBJC -OBJCFLAGS = $OBJCFLAGS -ac_ct_OBJC = $ac_ct_OBJC -LIBWINE_SHAREDLIB = $LIBWINE_SHAREDLIB -LIBWINE_LDFLAGS = $LIBWINE_LDFLAGS -WINELOADER_DEPENDS = $WINELOADER_DEPENDS -PRELINK = $PRELINK -LIBWINE_DEPENDS = $LIBWINE_DEPENDS -PE_ARCHS = $PE_ARCHS -MINGW_PKG_CONFIG = $MINGW_PKG_CONFIG -FAUDIO_PE_CFLAGS = $FAUDIO_PE_CFLAGS -FAUDIO_PE_LIBS = $FAUDIO_PE_LIBS -GSM_PE_CFLAGS = $GSM_PE_CFLAGS -GSM_PE_LIBS = $GSM_PE_LIBS -JPEG_PE_CFLAGS = $JPEG_PE_CFLAGS -JPEG_PE_LIBS = $JPEG_PE_LIBS -JXR_PE_CFLAGS = $JXR_PE_CFLAGS -JXR_PE_LIBS = $JXR_PE_LIBS -LCMS2_PE_CFLAGS = $LCMS2_PE_CFLAGS -LCMS2_PE_LIBS = $LCMS2_PE_LIBS -LDAP_PE_CFLAGS = $LDAP_PE_CFLAGS -LDAP_PE_LIBS = $LDAP_PE_LIBS -MPG123_PE_CFLAGS = $MPG123_PE_CFLAGS -MPG123_PE_LIBS = $MPG123_PE_LIBS -PNG_PE_CFLAGS = $PNG_PE_CFLAGS -PNG_PE_LIBS = $PNG_PE_LIBS -TIFF_PE_CFLAGS = $TIFF_PE_CFLAGS -TIFF_PE_LIBS = $TIFF_PE_LIBS -VKD3D_PE_CFLAGS = $VKD3D_PE_CFLAGS -VKD3D_PE_LIBS = $VKD3D_PE_LIBS -XML2_PE_CFLAGS = $XML2_PE_CFLAGS -XML2_PE_LIBS = $XML2_PE_LIBS -XSLT_PE_CFLAGS = $XSLT_PE_CFLAGS -XSLT_PE_LIBS = $XSLT_PE_LIBS -ZLIB_PE_CFLAGS = $ZLIB_PE_CFLAGS -ZLIB_PE_LIBS = $ZLIB_PE_LIBS -PTHREAD_LIBS = $PTHREAD_LIBS -XMKMF = $XMKMF -CPP = $CPP -X_CFLAGS = $X_CFLAGS -X_PRE_LIBS = $X_PRE_LIBS -X_LIBS = $X_LIBS -X_EXTRA_LIBS = $X_EXTRA_LIBS -PCAP_LIBS = $PCAP_LIBS -INOTIFY_CFLAGS = $INOTIFY_CFLAGS -INOTIFY_LIBS = $INOTIFY_LIBS -DBUS_CFLAGS = $DBUS_CFLAGS -DBUS_LIBS = $DBUS_LIBS -GNUTLS_CFLAGS = $GNUTLS_CFLAGS -GNUTLS_LIBS = $GNUTLS_LIBS -SANE_CFLAGS = $SANE_CFLAGS -SANE_LIBS = $SANE_LIBS -USB_CFLAGS = $USB_CFLAGS -USB_LIBS = $USB_LIBS -GPHOTO2_CFLAGS = $GPHOTO2_CFLAGS -GPHOTO2_LIBS = $GPHOTO2_LIBS -GPHOTO2_PORT_CFLAGS = $GPHOTO2_PORT_CFLAGS -GPHOTO2_PORT_LIBS = $GPHOTO2_PORT_LIBS -RESOLV_LIBS = $RESOLV_LIBS -FREETYPE_CFLAGS = $FREETYPE_CFLAGS -FREETYPE_LIBS = $FREETYPE_LIBS -GETTEXTPO_LIBS = $GETTEXTPO_LIBS -PULSE_CFLAGS = $PULSE_CFLAGS -PULSE_LIBS = $PULSE_LIBS -GSTREAMER_CFLAGS = $GSTREAMER_CFLAGS -GSTREAMER_LIBS = $GSTREAMER_LIBS -ALSA_LIBS = $ALSA_LIBS -OSS4_CFLAGS = $OSS4_CFLAGS -OSS4_LIBS = $OSS4_LIBS -UDEV_CFLAGS = $UDEV_CFLAGS -UDEV_LIBS = $UDEV_LIBS -UNWIND_CFLAGS = $UNWIND_CFLAGS -UNWIND_LIBS = $UNWIND_LIBS -SDL2_CFLAGS = $SDL2_CFLAGS -SDL2_LIBS = $SDL2_LIBS -CAPI20_CFLAGS = $CAPI20_CFLAGS -CAPI20_LIBS = $CAPI20_LIBS -CUPS_CFLAGS = $CUPS_CFLAGS -CUPS_LIBS = $CUPS_LIBS -FONTCONFIG_CFLAGS = $FONTCONFIG_CFLAGS -FONTCONFIG_LIBS = $FONTCONFIG_LIBS -KRB5_CFLAGS = $KRB5_CFLAGS -KRB5_LIBS = $KRB5_LIBS -GSSAPI_CFLAGS = $GSSAPI_CFLAGS -GSSAPI_LIBS = $GSSAPI_LIBS -PROCSTAT_LIBS = $PROCSTAT_LIBS -NETAPI_CFLAGS = $NETAPI_CFLAGS -NETAPI_LIBS = $NETAPI_LIBS -MSVCRTFLAGS = $MSVCRTFLAGS -DELAYLOADFLAG = $DELAYLOADFLAG -WINELOADER_PROGRAMS = $WINELOADER_PROGRAMS -RT_LIBS = $RT_LIBS -TAGSFLAGS = $TAGSFLAGS -LIBOBJS = $LIBOBJS -LTLIBOBJS = $LTLIBOBJS -$SET_MAKE -$wine_rules -_WINE_EOF - as_fn_error $? "could not create Makefile" "$LINENO" 5 -} - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "include/config.h") CONFIG_HEADERS="$CONFIG_HEADERS include/config.h" ;; - "include/stamp-h") CONFIG_COMMANDS="$CONFIG_COMMANDS include/stamp-h" ;; - "wine") CONFIG_LINKS="$CONFIG_LINKS wine:tools/winewrapper" ;; - "wine64") CONFIG_LINKS="$CONFIG_LINKS wine64:tools/winewrapper" ;; - "tools/makedep") CONFIG_COMMANDS="$CONFIG_COMMANDS tools/makedep" ;; - "Makefile") CONFIG_COMMANDS="$CONFIG_COMMANDS Makefile" ;; - - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers - test ${CONFIG_LINKS+y} || CONFIG_LINKS=$config_links - test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_HEADERS section. -# No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with `./config.status Makefile'. -if test -n "$CONFIG_HEADERS"; then -cat >"$ac_tmp/defines.awk" <<\_ACAWK || -BEGIN { -_ACEOF - -# Transform confdefs.h into an awk script `defines.awk', embedded as -# here-document in config.status, that substitutes the proper values into -# config.h.in to produce config.h. - -# Create a delimiter string that does not exist in confdefs.h, to ease -# handling of long lines. -ac_delim='%!_!# ' -for ac_last_try in false false :; do - ac_tt=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_tt"; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done - -# For the awk script, D is an array of macro values keyed by name, -# likewise P contains macro parameters if any. Preserve backslash -# newline sequences. - -ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* -sed -n ' -s/.\{148\}/&'"$ac_delim"'/g -t rset -:rset -s/^[ ]*#[ ]*define[ ][ ]*/ / -t def -d -:def -s/\\$// -t bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3"/p -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p -d -:bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3\\\\\\n"\\/p -t cont -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p -t cont -d -:cont -n -s/.\{148\}/&'"$ac_delim"'/g -t clear -:clear -s/\\$// -t bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/"/p -d -:bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p -b cont -' >$CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - for (key in D) D_is_set[key] = 1 - FS = "" -} -/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { - line = \$ 0 - split(line, arg, " ") - if (arg[1] == "#") { - defundef = arg[2] - mac1 = arg[3] - } else { - defundef = substr(arg[1], 2) - mac1 = arg[2] - } - split(mac1, mac2, "(") #) - macro = mac2[1] - prefix = substr(line, 1, index(line, defundef) - 1) - if (D_is_set[macro]) { - # Preserve the white space surrounding the "#". - print prefix "define", macro P[macro] D[macro] - next - } else { - # Replace #undef with comments. This is necessary, for example, - # in the case of _POSIX_SOURCE, which is predefined and required - # on some systems where configure will not decide to define it. - if (defundef == "undef") { - print "/*", prefix defundef, macro, "*/" - next - } - } -} -{ print } -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 -fi # test -n "$CONFIG_HEADERS" - - -eval set X " :H $CONFIG_HEADERS :L $CONFIG_LINKS :C $CONFIG_COMMANDS" -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is `configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -printf "%s\n" "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`printf "%s\n" "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - - :H) - # - # CONFIG_HEADER - # - if test x"$ac_file" != x-; then - { - printf "%s\n" "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" - } >"$ac_tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} - else - rm -f "$ac_file" - mv "$ac_tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - fi - else - printf "%s\n" "/* $configure_input */" >&1 \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 - fi - ;; - :L) - # - # CONFIG_LINK - # - - if test "$ac_source" = "$ac_file" && test "$srcdir" = '.'; then - : - else - # Prefer the file from the source tree if names are identical. - if test "$ac_source" = "$ac_file" || test ! -r "$ac_source"; then - ac_source=$srcdir/$ac_source - fi - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: linking $ac_source to $ac_file" >&5 -printf "%s\n" "$as_me: linking $ac_source to $ac_file" >&6;} - - if test ! -r "$ac_source"; then - as_fn_error $? "$ac_source: file not found" "$LINENO" 5 - fi - rm -f "$ac_file" - - # Try a relative symlink, then a hard link, then a copy. - case $ac_source in - [\\/$]* | ?:[\\/]* ) ac_rel_source=$ac_source ;; - *) ac_rel_source=$ac_top_build_prefix$ac_source ;; - esac - ln -s "$ac_rel_source" "$ac_file" 2>/dev/null || - ln "$ac_source" "$ac_file" 2>/dev/null || - cp -p "$ac_source" "$ac_file" || - as_fn_error $? "cannot link or copy $ac_source to $ac_file" "$LINENO" 5 - fi - ;; - :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 -printf "%s\n" "$as_me: executing $ac_file commands" >&6;} - ;; - esac - - - case $ac_file$ac_mode in - "include/stamp-h":C) echo timestamp > include/stamp-h ;; - "tools/makedep":C) wine_fn_output_makedep || as_fn_exit $? ;; - "Makefile":C) wine_fn_output_makefile Makefile ;; - - esac -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_files=$ac_clean_files_save - -test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - - -if test "$no_create" = "yes" -then - exit 0 -fi - -ac_save_IFS="$IFS" -if test "x$wine_notices" != x; then - echo >&6 - IFS="|" - for msg in $wine_notices; do - IFS="$ac_save_IFS" - if ${msg:+false} : -then : - -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $msg" >&5 -printf "%s\n" "$as_me: $msg" >&6;} -fi - done -fi -IFS="|" -for msg in $wine_warnings; do - IFS="$ac_save_IFS" - if ${msg:+false} : -then : - -else $as_nop - echo >&2 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $msg" >&5 -printf "%s\n" "$as_me: WARNING: $msg" >&2;} -fi -done -IFS="$ac_save_IFS" - -printf "%s\n" " -$as_me: Finished. Do '${ac_make}' to compile Wine. -" >&6 - - diff --git a/include/config.h.in b/include/config.h.in deleted file mode 100644 index 0e43013a8ab..00000000000 --- a/include/config.h.in +++ /dev/null @@ -1,863 +0,0 @@ -/* include/config.h.in. Generated from configure.ac by autoheader. */ - -#ifndef __WINE_CONFIG_H -#define __WINE_CONFIG_H - -/* Define to the file extension for executables. */ -#undef EXEEXT - -/* Define to 1 if you have the header file. */ -#undef HAVE_ARPA_INET_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_ARPA_NAMESER_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_ASM_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_ASM_USER_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_CAPI20_H - -/* Define to 1 if you have the `clock_gettime' function. */ -#undef HAVE_CLOCK_GETTIME - -/* Define to 1 if you have the header file. */ -#undef HAVE_CL_CL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_CUPS_CUPS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_CUPS_PPD_H - -/* Define to 1 if you have the `dladdr1' function. */ -#undef HAVE_DLADDR1 - -/* Define to 1 if you have the `dlinfo' function. */ -#undef HAVE_DLINFO - -/* Define to 1 if you have the header file. */ -#undef HAVE_EGL_EGL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_ELF_H - -/* Define to 1 if you have the `epoll_create' function. */ -#undef HAVE_EPOLL_CREATE - -/* Define to 1 if you have the header file. */ -#undef HAVE_FLOAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_FONTCONFIG_FONTCONFIG_H - -/* Define if FreeType 2 is installed */ -#undef HAVE_FREETYPE - -/* Define to 1 if you have the `fstatfs' function. */ -#undef HAVE_FSTATFS - -/* Define to 1 if you have the header file. */ -#undef HAVE_FT2BUILD_H - -/* Define to 1 if the system has the type `FT_TrueTypeEngineType'. */ -#undef HAVE_FT_TRUETYPEENGINETYPE - -/* Define to 1 if you have the `futimens' function. */ -#undef HAVE_FUTIMENS - -/* Define to 1 if you have the `futimes' function. */ -#undef HAVE_FUTIMES - -/* Define to 1 if you have the `futimesat' function. */ -#undef HAVE_FUTIMESAT - -/* Define to 1 if you have the `getaddrinfo' function. */ -#undef HAVE_GETADDRINFO - -/* Define to 1 if you have the `getattrlist' function. */ -#undef HAVE_GETATTRLIST - -/* Define to 1 if you have the `getauxval' function. */ -#undef HAVE_GETAUXVAL - -/* Define to 1 if you have the `getifaddrs' function. */ -#undef HAVE_GETIFADDRS - -/* Define to 1 if you have the `getrandom' function. */ -#undef HAVE_GETRANDOM - -/* Define to 1 if you have the header file. */ -#undef HAVE_GETTEXT_PO_H - -/* Define to 1 if you have the `gnutls_cipher_init' function. */ -#undef HAVE_GNUTLS_CIPHER_INIT - -/* Define if we have the libgphoto2_port development environment */ -#undef HAVE_GPHOTO2_PORT - -/* Define to 1 if you have the header file. */ -#undef HAVE_GSSAPI_GSSAPI_EXT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_GSSAPI_GSSAPI_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_IFADDRS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the `kqueue' function. */ -#undef HAVE_KQUEUE - -/* Define to 1 if you have the header file. */ -#undef HAVE_KRB5_KRB5_H - -/* Define to 1 if you have the `gettextpo' library (-lgettextpo). */ -#undef HAVE_LIBGETTEXTPO - -/* Define to 1 if you have the `procstat' library (-lprocstat). */ -#undef HAVE_LIBPROCSTAT - -/* Define to 1 if you have the header file. */ -#undef HAVE_LIBPROCSTAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LIBPROC_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LIBUDEV_H - -/* Define to 1 if you have the `unwind' library (-lunwind). */ -#undef HAVE_LIBUNWIND - -/* Define if you have the X Shape extension */ -#undef HAVE_LIBXSHAPE - -/* Define if you have the X Shm extension */ -#undef HAVE_LIBXXSHM - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINK_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_CAPI_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_CDROM_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_FILTER_H - -/* Define if Linux-style gethostbyname_r and gethostbyaddr_r are available */ -#undef HAVE_LINUX_GETHOSTBYNAME_R_6 - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_HDREG_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_HIDRAW_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_INPUT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_IOCTL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_IPX_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_IRDA_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_MAJOR_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_PARAM_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_RTNETLINK_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_SERIAL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_UCDROM_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINUX_VIDEODEV2_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LWP_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_MACHINE_CPU_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_MACHINE_SYSARCH_H - -/* Define to 1 if you have the `mach_continuous_time' function. */ -#undef HAVE_MACH_CONTINUOUS_TIME - -/* Define to 1 if you have the header file. */ -#undef HAVE_MACH_MACH_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_MACH_O_LOADER_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_MNTENT_H - -/* Define if MTLDevice protocol has registryID property. */ -#undef HAVE_MTLDEVICE_REGISTRYID - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETDB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET6_IP6_VAR_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_ICMP6_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_ICMP_VAR_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IF_ETHER_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IN_PCB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IN_SYSTM_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IP_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IP_ICMP_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_IP_VAR_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_TCP_FSM_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_TCP_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_TCP_VAR_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_UDP_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETINET_UDP_VAR_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NETIPX_IPX_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NET_IF_ARP_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NET_IF_DL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NET_IF_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NET_IF_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_NET_ROUTE_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_OPENCL_OPENCL_H - -/* Define to 1 if `numaudioengines' is a member of `oss_sysinfo'. */ -#undef HAVE_OSS_SYSINFO_NUMAUDIOENGINES - -/* Define to 1 if you have the header file. */ -#undef HAVE_PCAP_PCAP_H - -/* Define to 1 if you have the `pipe2' function. */ -#undef HAVE_PIPE2 - -/* Define to 1 if you have the `port_create' function. */ -#undef HAVE_PORT_CREATE - -/* Define to 1 if you have the header file. */ -#undef HAVE_PORT_H - -/* Define to 1 if you have the `posix_fadvise' function. */ -#undef HAVE_POSIX_FADVISE - -/* Define to 1 if you have the `posix_fallocate' function. */ -#undef HAVE_POSIX_FALLOCATE - -/* Define to 1 if you have the `prctl' function. */ -#undef HAVE_PRCTL - -/* Define to 1 if you have the `proc_pidinfo' function. */ -#undef HAVE_PROC_PIDINFO - -/* Define to 1 if you have the `pthread_getthreadid_np' function. */ -#undef HAVE_PTHREAD_GETTHREADID_NP - -/* Define to 1 if you have the header file. */ -#undef HAVE_PTHREAD_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_PTHREAD_NP_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_PULSE_PULSEAUDIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_PWD_H - -/* Define to 1 if the system has the type `request_sense'. */ -#undef HAVE_REQUEST_SENSE - -/* Define if you have the resolver library and header */ -#undef HAVE_RESOLV - -/* Define to 1 if you have the header file. */ -#undef HAVE_RESOLV_H - -/* Define to 1 if you have the `res_getservers' function. */ -#undef HAVE_RES_GETSERVERS - -/* Define to 1 if you have the header file. */ -#undef HAVE_SCHED_H - -/* Define to 1 if you have the `sched_setaffinity' function. */ -#undef HAVE_SCHED_SETAFFINITY - -/* Define to 1 if you have the `sched_yield' function. */ -#undef HAVE_SCHED_YIELD - -/* Define to 1 if `cmd' is a member of `scsireq_t'. */ -#undef HAVE_SCSIREQ_T_CMD - -/* Define to 1 if you have the header file. */ -#undef HAVE_SCSI_SCSI_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SCSI_SCSI_IOCTL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SCSI_SG_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SDL_H - -/* Define to 1 if you have the `setproctitle' function. */ -#undef HAVE_SETPROCTITLE - -/* Define to 1 if you have the `setprogname' function. */ -#undef HAVE_SETPROGNAME - -/* Define to 1 if `interface_id' is a member of `sg_io_hdr_t'. */ -#undef HAVE_SG_IO_HDR_T_INTERFACE_ID - -/* Define if sigaddset is supported */ -#undef HAVE_SIGADDSET - -/* Define to 1 if `si_fd' is a member of `siginfo_t'. */ -#undef HAVE_SIGINFO_T_SI_FD - -/* Define to 1 if you have the `sigprocmask' function. */ -#undef HAVE_SIGPROCMASK - -/* Define to 1 if the system has the type `sigset_t'. */ -#undef HAVE_SIGSET_T - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if `icp6s_error' is a member of `struct icmp6stat'. */ -#undef HAVE_STRUCT_ICMP6STAT_ICP6S_ERROR - -/* Define to 1 if `icps_error' is a member of `struct icmpstat'. */ -#undef HAVE_STRUCT_ICMPSTAT_ICPS_ERROR - -/* Define to 1 if `ifr_hwaddr' is a member of `struct ifreq'. */ -#undef HAVE_STRUCT_IFREQ_IFR_HWADDR - -/* Define to 1 if `ipi6_addr' is a member of `struct in6_pktinfo'. */ -#undef HAVE_STRUCT_IN6_PKTINFO_IPI6_ADDR - -/* Define to 1 if `ip6s_total' is a member of `struct ip6stat'. */ -#undef HAVE_STRUCT_IP6STAT_IP6S_TOTAL - -/* Define to 1 if `ips_total' is a member of `struct ipstat'. */ -#undef HAVE_STRUCT_IPSTAT_IPS_TOTAL - -/* Define to 1 if `ips_total' is a member of `struct ip_stats'. */ -#undef HAVE_STRUCT_IP_STATS_IPS_TOTAL - -/* Define to 1 if `msg_accrights' is a member of `struct msghdr'. */ -#undef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS - -/* Define to 1 if `mt_blkno' is a member of `struct mtget'. */ -#undef HAVE_STRUCT_MTGET_MT_BLKNO - -/* Define to 1 if `mt_blksiz' is a member of `struct mtget'. */ -#undef HAVE_STRUCT_MTGET_MT_BLKSIZ - -/* Define to 1 if `mt_gstat' is a member of `struct mtget'. */ -#undef HAVE_STRUCT_MTGET_MT_GSTAT - -/* Define to 1 if `sin6_scope_id' is a member of `struct sockaddr_in6'. */ -#undef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID - -/* Define to 1 if `sun_len' is a member of `struct sockaddr_un'. */ -#undef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN - -/* Define to 1 if `st_atim' is a member of `struct stat'. */ -#undef HAVE_STRUCT_STAT_ST_ATIM - -/* Define to 1 if `st_atimespec' is a member of `struct stat'. */ -#undef HAVE_STRUCT_STAT_ST_ATIMESPEC - -/* Define to 1 if `st_birthtim' is a member of `struct stat'. */ -#undef HAVE_STRUCT_STAT_ST_BIRTHTIM - -/* Define to 1 if `st_birthtime' is a member of `struct stat'. */ -#undef HAVE_STRUCT_STAT_ST_BIRTHTIME - -/* Define to 1 if `st_birthtimespec' is a member of `struct stat'. */ -#undef HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC - -/* Define to 1 if `st_ctim' is a member of `struct stat'. */ -#undef HAVE_STRUCT_STAT_ST_CTIM - -/* Define to 1 if `st_ctimespec' is a member of `struct stat'. */ -#undef HAVE_STRUCT_STAT_ST_CTIMESPEC - -/* Define to 1 if `st_mtim' is a member of `struct stat'. */ -#undef HAVE_STRUCT_STAT_ST_MTIM - -/* Define to 1 if `st_mtimespec' is a member of `struct stat'. */ -#undef HAVE_STRUCT_STAT_ST_MTIMESPEC - -/* Define to 1 if `__st_birthtim' is a member of `struct stat'. */ -#undef HAVE_STRUCT_STAT___ST_BIRTHTIM - -/* Define to 1 if `__st_birthtime' is a member of `struct stat'. */ -#undef HAVE_STRUCT_STAT___ST_BIRTHTIME - -/* Define to 1 if `mem_unit' is a member of `struct sysinfo'. */ -#undef HAVE_STRUCT_SYSINFO_MEM_UNIT - -/* Define to 1 if `totalram' is a member of `struct sysinfo'. */ -#undef HAVE_STRUCT_SYSINFO_TOTALRAM - -/* Define to 1 if `tcps_connattempt' is a member of `struct tcpstat'. */ -#undef HAVE_STRUCT_TCPSTAT_TCPS_CONNATTEMPT - -/* Define to 1 if `tcps_connattempt' is a member of `struct tcp_stats'. */ -#undef HAVE_STRUCT_TCP_STATS_TCPS_CONNATTEMPT - -/* Define to 1 if `udps_ipackets' is a member of `struct udpstat'. */ -#undef HAVE_STRUCT_UDPSTAT_UDPS_IPACKETS - -/* Define to 1 if the system has the type `struct xinpgen'. */ -#undef HAVE_STRUCT_XINPGEN - -/* Define to 1 if `_u._ext.nscount6' is a member of `struct __res_state'. */ -#undef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6 - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYSCALL_H - -/* Define to 1 if you have the `sysinfo' function. */ -#undef HAVE_SYSINFO - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_ATTR_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_AUXV_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_CDIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_CONF_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_EPOLL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_EVENT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_EXTATTR_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_FILIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_INOTIFY_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_IPC_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_LINK_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_MODEM_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_MOUNT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_MTIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_PARAM_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_PRCTL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_PTRACE_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_QUEUE_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_RANDOM_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_RESOURCE_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SCSIIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SHM_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SIGNAL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SOCKETVAR_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SOCKIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STATFS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STATVFS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STRTIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SYSCALL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SYSCTL_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_SYSINFO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_THR_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TIMES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_UCONTEXT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_UIO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_UN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_USER_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_UTSNAME_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_VFS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_VNODE_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_XATTR_H - -/* Define to 1 if you have the `tcdrain' function. */ -#undef HAVE_TCDRAIN - -/* Define to 1 if you have the `thr_kill2' function. */ -#undef HAVE_THR_KILL2 - -/* Define to 1 if you have the `udev' library (-ludev). */ -#undef HAVE_UDEV - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UTIME_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_VALGRIND_MEMCHECK_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_VALGRIND_VALGRIND_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_X11_EXTENSIONS_SHAPE_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_X11_EXTENSIONS_XCOMPOSITE_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_X11_EXTENSIONS_XF86VMODE_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_X11_EXTENSIONS_XF86VMPROTO_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_X11_EXTENSIONS_XFIXES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_X11_EXTENSIONS_XINERAMA_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_X11_EXTENSIONS_XINPUT2_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_X11_EXTENSIONS_XINPUT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_X11_EXTENSIONS_XRANDR_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_X11_EXTENSIONS_XRENDER_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_X11_EXTENSIONS_XSHM_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_X11_XCURSOR_XCURSOR_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_X11_XKBLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_X11_XLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_X11_XUTIL_H - -/* Define to 1 if `xcookie' is a member of `XEvent'. */ -#undef HAVE_XEVENT_XCOOKIE - -/* Define to 1 if `callback' is a member of `XICCallback'. */ -#undef HAVE_XICCALLBACK_CALLBACK - -/* Define if you have the XKB extension */ -#undef HAVE_XKB - -/* Define if Xrender has the XRenderCreateLinearGradient function */ -#undef HAVE_XRENDERCREATELINEARGRADIENT - -/* Define if Xrender has the XRenderSetPictureTransform function */ -#undef HAVE_XRENDERSETPICTURETRANSFORM - -/* Define if Xrandr has the XRRGetProviderResources function */ -#undef HAVE_XRRGETPROVIDERRESOURCES - -/* Define to 1 if you have the `__builtin_popcount' built-in function. */ -#undef HAVE___BUILTIN_POPCOUNT - -/* Define to 1 if you have the `__clear_cache' (potentially built-in) - function. */ -#undef HAVE___CLEAR_CACHE - -/* Define to 1 if `major', `minor', and `makedev' are declared in . - */ -#undef MAJOR_IN_MKDEV - -/* Define to 1 if `major', `minor', and `makedev' are declared in - . */ -#undef MAJOR_IN_SYSMACROS - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Define to the soname of the libcups library. */ -#undef SONAME_LIBCUPS - -/* Define to the soname of the libdbus-1 library. */ -#undef SONAME_LIBDBUS_1 - -/* Define to the soname of the libEGL library. */ -#undef SONAME_LIBEGL - -/* Define to the soname of the libfontconfig library. */ -#undef SONAME_LIBFONTCONFIG - -/* Define to the soname of the libfreetype library. */ -#undef SONAME_LIBFREETYPE - -/* Define to the soname of the libGL library. */ -#undef SONAME_LIBGL - -/* Define to the soname of the libGLESv2 library. */ -#undef SONAME_LIBGLESV2 - -/* Define to the soname of the libgnutls library. */ -#undef SONAME_LIBGNUTLS - -/* Define to the soname of the libgssapi_krb5 library. */ -#undef SONAME_LIBGSSAPI_KRB5 - -/* Define to the soname of the libkrb5 library. */ -#undef SONAME_LIBKRB5 - -/* Define to the soname of the libMoltenVK library. */ -#undef SONAME_LIBMOLTENVK - -/* Define to the soname of the libnetapi library. */ -#undef SONAME_LIBNETAPI - -/* Define to the soname of the libodbc library. */ -#undef SONAME_LIBODBC - -/* Define to the soname of the libOSMesa library. */ -#undef SONAME_LIBOSMESA - -/* Define to the soname of the libSDL2 library. */ -#undef SONAME_LIBSDL2 - -/* Define to the soname of the libv4l2 library. */ -#undef SONAME_LIBV4L2 - -/* Define to the soname of the libvulkan library. */ -#undef SONAME_LIBVULKAN - -/* Define to the soname of the libX11 library. */ -#undef SONAME_LIBX11 - -/* Define to the soname of the libXcomposite library. */ -#undef SONAME_LIBXCOMPOSITE - -/* Define to the soname of the libXcursor library. */ -#undef SONAME_LIBXCURSOR - -/* Define to the soname of the libXext library. */ -#undef SONAME_LIBXEXT - -/* Define to the soname of the libXfixes library. */ -#undef SONAME_LIBXFIXES - -/* Define to the soname of the libXi library. */ -#undef SONAME_LIBXI - -/* Define to the soname of the libXinerama library. */ -#undef SONAME_LIBXINERAMA - -/* Define to the soname of the libXrandr library. */ -#undef SONAME_LIBXRANDR - -/* Define to the soname of the libXrender library. */ -#undef SONAME_LIBXRENDER - -/* Define to the soname of the libXxf86vm library. */ -#undef SONAME_LIBXXF86VM - -/* Define to 1 if the `S_IS*' macros in do not work properly. */ -#undef STAT_MACROS_BROKEN - -/* Define to 1 if all of the C90 standard headers exist (not just the ones - required in a freestanding environment). This macro is provided for - backward compatibility; new code need not use it. */ -#undef STDC_HEADERS - -/* Define if xattr functions take additional arguments (macOS) */ -#undef XATTR_ADDITIONAL_OPTIONS - -/* Define to 1 if the X Window System is missing or not being used. */ -#undef X_DISPLAY_MISSING - -/* Number of bits in a file offset, on hosts where this is settable. */ -#undef _FILE_OFFSET_BITS - -/* Define to 1 to enable GNU extensions on Linux */ -#undef _GNU_SOURCE - -/* Define for large files, on AIX-style hosts. */ -#undef _LARGE_FILES - -/* Define to 64 to enable 64-bit time_t on Linux */ -#undef _TIME_BITS - -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus -#undef inline -#endif - -#endif /* __WINE_CONFIG_H */ From b24ee49f58b992ddf8fabd135c714f32f25d2dd7 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 12 Dec 2022 05:41:47 +0200 Subject: [PATCH 0004/2777] configure: Check for sys/eventfd.h, ppoll(), and shm_open(). We use ppoll() instead of poll() for the better time granularity. Although perhaps we shouldn't since the server doesn't do this. Wine-Staging: eventfd_synchronization --- configure.ac | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/configure.ac b/configure.ac index 3c30db8fd45..ab38a00d9e0 100644 --- a/configure.ac +++ b/configure.ac @@ -453,6 +453,7 @@ AC_CHECK_HEADERS(\ sys/cdio.h \ sys/epoll.h \ sys/event.h \ + sys/eventfd.h \ sys/extattr.h \ sys/filio.h \ sys/ipc.h \ @@ -2024,6 +2025,7 @@ AC_CHECK_FUNCS(\ port_create \ posix_fadvise \ posix_fallocate \ + ppoll \ prctl \ proc_pidinfo \ sched_yield \ @@ -2047,6 +2049,12 @@ case $host_os in ;; esac +ac_save_LIBS=$LIBS +AC_SEARCH_LIBS(shm_open, rt, + [AC_DEFINE(HAVE_SHM_OPEN, 1, [Define to 1 if you have the `shm_open' function.]) + test "$ac_res" = "none required" || AC_SUBST(RT_LIBS,"$ac_res")]) +LIBS=$ac_save_LIBS + AC_CACHE_CHECK([for sched_setaffinity],wine_cv_have_sched_setaffinity, AC_LINK_IFELSE([AC_LANG_PROGRAM( [[#include ]], [[sched_setaffinity(0, 0, 0);]])],[wine_cv_have_sched_setaffinity=yes],[wine_cv_have_sched_setaffinity=no])) From 74ad334c9995ed6897b37495428ddf445e110904 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Thu, 7 Jun 2018 20:09:59 -0500 Subject: [PATCH 0005/2777] server: Create server objects for eventfd-based synchronization objects. Wine-Staging: eventfd_synchronization --- server/Makefile.in | 1 + server/esync.c | 318 ++++++++++++++++++++++++++++++++++++++++++++ server/esync.h | 24 ++++ server/main.c | 4 + server/protocol.def | 25 +++- 5 files changed, 371 insertions(+), 1 deletion(-) create mode 100644 server/esync.c create mode 100644 server/esync.h diff --git a/server/Makefile.in b/server/Makefile.in index c62edbdb892..97afbf72547 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -11,6 +11,7 @@ C_SRCS = \ debugger.c \ device.c \ directory.c \ + esync.c \ event.c \ fd.c \ file.c \ diff --git a/server/esync.c b/server/esync.c new file mode 100644 index 00000000000..35b4833fd4c --- /dev/null +++ b/server/esync.c @@ -0,0 +1,318 @@ +/* + * eventfd-based synchronization objects + * + * Copyright (C) 2018 Zebediah Figura + * + * 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 + */ + +#include "config.h" + + +#include +#include +#include +#ifdef HAVE_SYS_EVENTFD_H +# include +#endif +#include +#ifdef HAVE_SYS_STAT_H +# include +#endif +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winternl.h" + +#include "handle.h" +#include "request.h" +#include "file.h" + +int do_esync(void) +{ +#ifdef HAVE_SYS_EVENTFD_H + static int do_esync_cached = -1; + + if (do_esync_cached == -1) + do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")); + + return do_esync_cached; +#else + return 0; +#endif +} + +static char shm_name[29]; +static int shm_fd; +static off_t shm_size; +static void **shm_addrs; +static int shm_addrs_size; /* length of the allocated shm_addrs array */ +static long pagesize; + +static void shm_cleanup(void) +{ + close( shm_fd ); + if (shm_unlink( shm_name ) == -1) + perror( "shm_unlink" ); +} + +void esync_init(void) +{ + struct stat st; + + if (fstat( config_dir_fd, &st ) == -1) + fatal_error( "cannot stat config dir\n" ); + + if (st.st_ino != (unsigned long)st.st_ino) + sprintf( shm_name, "/wine-%lx%08lx-esync", (unsigned long)((unsigned long long)st.st_ino >> 32), (unsigned long)st.st_ino ); + else + sprintf( shm_name, "/wine-%lx-esync", (unsigned long)st.st_ino ); + + shm_unlink( shm_name ); + + shm_fd = shm_open( shm_name, O_RDWR | O_CREAT | O_EXCL, 0644 ); + if (shm_fd == -1) + perror( "shm_open" ); + + pagesize = sysconf( _SC_PAGESIZE ); + + shm_addrs = calloc( 128, sizeof(shm_addrs[0]) ); + shm_addrs_size = 128; + + shm_size = pagesize; + if (ftruncate( shm_fd, shm_size ) == -1) + perror( "ftruncate" ); + + fprintf( stderr, "esync: up and running.\n" ); + + atexit( shm_cleanup ); +} + +struct esync +{ + struct object obj; /* object header */ + int fd; /* eventfd file descriptor */ + enum esync_type type; + unsigned int shm_idx; /* index into the shared memory section */ +}; + +static void esync_dump( struct object *obj, int verbose ); +static void esync_destroy( struct object *obj ); + +static const struct object_ops esync_ops = +{ + sizeof(struct esync), /* size */ + &no_type, /* type */ + esync_dump, /* dump */ + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + default_map_access, /* map_access */ + default_get_sd, /* get_sd */ + default_set_sd, /* set_sd */ + default_get_full_name, /* get_full_name */ + no_lookup_name, /* lookup_name */ + directory_link_name, /* link_name */ + default_unlink_name, /* unlink_name */ + no_open_file, /* open_file */ + no_kernel_obj_list, /* get_kernel_obj_list */ + no_close_handle, /* close_handle */ + esync_destroy /* destroy */ +}; + +static void esync_dump( struct object *obj, int verbose ) +{ + struct esync *esync = (struct esync *)obj; + assert( obj->ops == &esync_ops ); + fprintf( stderr, "esync fd=%d\n", esync->fd ); +} + +static void esync_destroy( struct object *obj ) +{ + struct esync *esync = (struct esync *)obj; + close( esync->fd ); +} + +static int type_matches( enum esync_type type1, enum esync_type type2 ) +{ + return (type1 == type2) || + ((type1 == ESYNC_AUTO_EVENT || type1 == ESYNC_MANUAL_EVENT) && + (type2 == ESYNC_AUTO_EVENT || type2 == ESYNC_MANUAL_EVENT)); +} + +static void *get_shm( unsigned int idx ) +{ + int entry = (idx * 8) / pagesize; + int offset = (idx * 8) % pagesize; + + if (entry >= shm_addrs_size) + { + int new_size = max(shm_addrs_size * 2, entry + 1); + + if (!(shm_addrs = realloc( shm_addrs, new_size * sizeof(shm_addrs[0]) ))) + fprintf( stderr, "esync: couldn't expand shm_addrs array to size %d\n", entry + 1 ); + + memset( shm_addrs + shm_addrs_size, 0, (new_size - shm_addrs_size) * sizeof(shm_addrs[0]) ); + + shm_addrs_size = new_size; + } + + if (!shm_addrs[entry]) + { + void *addr = mmap( NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, entry * pagesize ); + if (addr == (void *)-1) + { + fprintf( stderr, "esync: failed to map page %d (offset %#lx): ", entry, entry * pagesize ); + perror( "mmap" ); + } + + if (debug_level) + fprintf( stderr, "esync: Mapping page %d at %p.\n", entry, addr ); + + if (__sync_val_compare_and_swap( &shm_addrs[entry], 0, addr )) + munmap( addr, pagesize ); /* someone beat us to it */ + } + + return (void *)((unsigned long)shm_addrs[entry] + offset); +} + +struct semaphore +{ + int max; + int count; +}; +C_ASSERT(sizeof(struct semaphore) == 8); + +struct esync *create_esync( struct object *root, const struct unicode_str *name, + unsigned int attr, int initval, int max, enum esync_type type, + const struct security_descriptor *sd ) +{ +#ifdef HAVE_SYS_EVENTFD_H + struct esync *esync; + + if ((esync = create_named_object( root, &esync_ops, name, attr, sd ))) + { + if (get_error() != STATUS_OBJECT_NAME_EXISTS) + { + int flags = EFD_CLOEXEC | EFD_NONBLOCK; + + if (type == ESYNC_SEMAPHORE) + flags |= EFD_SEMAPHORE; + + /* initialize it if it didn't already exist */ + esync->fd = eventfd( initval, flags ); + if (esync->fd == -1) + { + perror( "eventfd" ); + file_set_error(); + release_object( esync ); + return NULL; + } + esync->type = type; + + /* Use the fd as index, since that'll be unique across all + * processes, but should hopefully end up also allowing reuse. */ + esync->shm_idx = esync->fd + 1; /* we keep index 0 reserved */ + while (esync->shm_idx * 8 >= shm_size) + { + /* Better expand the shm section. */ + shm_size += pagesize; + if (ftruncate( shm_fd, shm_size ) == -1) + { + fprintf( stderr, "esync: couldn't expand %s to size %ld: ", + shm_name, (long)shm_size ); + perror( "ftruncate" ); + } + } + + /* Initialize the shared memory portion. We want to do this on the + * server side to avoid a potential though unlikely race whereby + * the same object is opened and used between the time it's created + * and the time its shared memory portion is initialized. */ + switch (type) + { + case ESYNC_SEMAPHORE: + { + struct semaphore *semaphore = get_shm( esync->shm_idx ); + semaphore->max = max; + semaphore->count = initval; + break; + } + default: + assert( 0 ); + } + } + else + { + /* validate the type */ + if (!type_matches( type, esync->type )) + { + release_object( &esync->obj ); + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + return NULL; + } + } + } + return esync; +#else + /* FIXME: Provide a fallback implementation using pipe(). */ + set_error( STATUS_NOT_IMPLEMENTED ); + return NULL; +#endif +} + +DECL_HANDLER(create_esync) +{ + struct esync *esync; + struct unicode_str name; + struct object *root; + const struct security_descriptor *sd; + const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root ); + + if (!do_esync()) + { + set_error( STATUS_NOT_IMPLEMENTED ); + return; + } + + if (!req->type) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + if (!objattr) return; + + if ((esync = create_esync( root, &name, objattr->attributes, req->initval, req->max, req->type, sd ))) + { + if (get_error() == STATUS_OBJECT_NAME_EXISTS) + reply->handle = alloc_handle( current->process, esync, req->access, objattr->attributes ); + else + reply->handle = alloc_handle_no_access_check( current->process, esync, + req->access, objattr->attributes ); + + reply->type = esync->type; + reply->shm_idx = esync->shm_idx; + send_client_fd( current->process, esync->fd, reply->handle ); + release_object( esync ); + } + + if (root) release_object( root ); +} diff --git a/server/esync.h b/server/esync.h new file mode 100644 index 00000000000..00f9e638d83 --- /dev/null +++ b/server/esync.h @@ -0,0 +1,24 @@ +/* + * eventfd-based synchronization objects + * + * Copyright (C) 2018 Zebediah Figura + * + * 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 + */ + +#include + +extern int do_esync(void); +void esync_init(void); diff --git a/server/main.c b/server/main.c index 4021d55d52c..acf6f1188ac 100644 --- a/server/main.c +++ b/server/main.c @@ -34,6 +34,7 @@ #include "thread.h" #include "request.h" #include "unicode.h" +#include "esync.h" /* command-line options */ int debug_level = 0; @@ -229,6 +230,9 @@ int main( int argc, char *argv[] ) sock_init(); open_master_socket(); + if (do_esync()) + esync_init(); + if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() ); set_current_time(); init_signals(); diff --git a/server/protocol.def b/server/protocol.def index 8c2fbeb4afe..c74498a3bcd 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3776,7 +3776,6 @@ struct handle_info obj_handle_t handle; /* process handle */ @END - /* Iterate thread list for process */ @REQ(get_next_thread) obj_handle_t process; /* process handle */ @@ -3787,3 +3786,27 @@ struct handle_info @REPLY obj_handle_t handle; /* next thread handle */ @END + +enum esync_type +{ + ESYNC_SEMAPHORE = 1, + ESYNC_AUTO_EVENT, + ESYNC_MANUAL_EVENT, + ESYNC_MUTEX, + ESYNC_AUTO_SERVER, + ESYNC_MANUAL_SERVER, + ESYNC_QUEUE, +}; + +/* Create a new eventfd-based synchronization object */ +@REQ(create_esync) + unsigned int access; /* wanted access rights */ + int initval; /* initial value */ + int type; /* type of esync object */ + int max; /* maximum count on a semaphore */ + VARARG(objattr,object_attributes); /* object attributes */ +@REPLY + obj_handle_t handle; /* handle to the object */ + int type; /* actual type (may be different for events) */ + unsigned int shm_idx; +@END From f811d41ef6be4a1c47085650de532c37ed8a46bb Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 12:09:22 -0500 Subject: [PATCH 0006/2777] ntdll: Create eventfd-based objects for semaphores. Wine-Staging: eventfd_synchronization --- dlls/ntdll/Makefile.in | 1 + dlls/ntdll/unix/esync.c | 271 +++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/esync.h | 35 +++++ dlls/ntdll/unix/loader.c | 2 + dlls/ntdll/unix/server.c | 4 +- dlls/ntdll/unix/sync.c | 4 + server/esync.c | 1 + 7 files changed, 316 insertions(+), 2 deletions(-) create mode 100644 dlls/ntdll/unix/esync.c create mode 100644 dlls/ntdll/unix/esync.h diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index 7aeee3a7316..e704a3f1301 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -47,6 +47,7 @@ C_SRCS = \ unix/cdrom.c \ unix/debug.c \ unix/env.c \ + unix/esync.c \ unix/file.c \ unix/loader.c \ unix/loadorder.c \ diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c new file mode 100644 index 00000000000..dc2228390ec --- /dev/null +++ b/dlls/ntdll/unix/esync.c @@ -0,0 +1,271 @@ +/* + * eventfd-based synchronization objects + * + * Copyright (C) 2018 Zebediah Figura + * + * 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 + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_STAT_H +# include +#endif +#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#define NONAMELESSUNION +#include "windef.h" +#include "winternl.h" +#include "wine/server.h" +#include "wine/debug.h" + +#include "unix_private.h" +#include "esync.h" + +WINE_DEFAULT_DEBUG_CHANNEL(esync); + +int do_esync(void) +{ +#ifdef HAVE_SYS_EVENTFD_H + static int do_esync_cached = -1; + + if (do_esync_cached == -1) + do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")); + + return do_esync_cached; +#else + static int once; + if (!once++) + FIXME("eventfd not supported on this platform.\n"); + return 0; +#endif +} + +struct esync +{ + enum esync_type type; + int fd; + void *shm; +}; + +struct semaphore +{ + int max; + int count; +}; +C_ASSERT(sizeof(struct semaphore) == 8); + +static char shm_name[29]; +static int shm_fd; +static void **shm_addrs; +static int shm_addrs_size; /* length of the allocated shm_addrs array */ +static long pagesize; + +static pthread_mutex_t shm_addrs_mutex = PTHREAD_MUTEX_INITIALIZER; + +static void *get_shm( unsigned int idx ) +{ + int entry = (idx * 8) / pagesize; + int offset = (idx * 8) % pagesize; + void *ret; + + pthread_mutex_lock( &shm_addrs_mutex ); + + if (entry >= shm_addrs_size) + { + int new_size = max(shm_addrs_size * 2, entry + 1); + + if (!(shm_addrs = realloc( shm_addrs, new_size * sizeof(shm_addrs[0]) ))) + ERR("Failed to grow shm_addrs array to size %d.\n", shm_addrs_size); + memset( shm_addrs + shm_addrs_size, 0, (new_size - shm_addrs_size) * sizeof(shm_addrs[0]) ); + shm_addrs_size = new_size; + } + + if (!shm_addrs[entry]) + { + void *addr = mmap( NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, entry * pagesize ); + if (addr == (void *)-1) + ERR("Failed to map page %d (offset %#lx).\n", entry, entry * pagesize); + + TRACE("Mapping page %d at %p.\n", entry, addr); + + if (InterlockedCompareExchangePointer( &shm_addrs[entry], addr, 0 )) + munmap( addr, pagesize ); /* someone beat us to it */ + } + + ret = (void *)((unsigned long)shm_addrs[entry] + offset); + + pthread_mutex_unlock( &shm_addrs_mutex ); + + return ret; +} + +/* We'd like lookup to be fast. To that end, we use a static list indexed by handle. + * This is copied and adapted from the fd cache code. */ + +#define ESYNC_LIST_BLOCK_SIZE (65536 / sizeof(struct esync)) +#define ESYNC_LIST_ENTRIES 256 + +static struct esync *esync_list[ESYNC_LIST_ENTRIES]; +static struct esync esync_list_initial_block[ESYNC_LIST_BLOCK_SIZE]; + +static inline UINT_PTR handle_to_index( HANDLE handle, UINT_PTR *entry ) +{ + UINT_PTR idx = (((UINT_PTR)handle) >> 2) - 1; + *entry = idx / ESYNC_LIST_BLOCK_SIZE; + return idx % ESYNC_LIST_BLOCK_SIZE; +} + +static struct esync *add_to_list( HANDLE handle, enum esync_type type, int fd, void *shm ) +{ + UINT_PTR entry, idx = handle_to_index( handle, &entry ); + + if (entry >= ESYNC_LIST_ENTRIES) + { + FIXME( "too many allocated handles, not caching %p\n", handle ); + return FALSE; + } + + if (!esync_list[entry]) /* do we need to allocate a new block of entries? */ + { + if (!entry) esync_list[0] = esync_list_initial_block; + else + { + void *ptr = anon_mmap_alloc( ESYNC_LIST_BLOCK_SIZE * sizeof(struct esync), + PROT_READ | PROT_WRITE ); + if (ptr == MAP_FAILED) return FALSE; + esync_list[entry] = ptr; + } + } + + if (!InterlockedCompareExchange( (LONG *)&esync_list[entry][idx].type, type, 0 )) + { + esync_list[entry][idx].fd = fd; + esync_list[entry][idx].shm = shm; + } + return &esync_list[entry][idx]; +} + +static NTSTATUS create_esync( enum esync_type type, HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, int initval, int max ) +{ + NTSTATUS ret; + data_size_t len; + struct object_attributes *objattr; + obj_handle_t fd_handle; + unsigned int shm_idx; + sigset_t sigset; + int fd; + + if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; + + /* We have to synchronize on the fd cache CS so that our calls to + * receive_fd don't race with theirs. */ + server_enter_uninterrupted_section( &fd_cache_mutex, &sigset ); + SERVER_START_REQ( create_esync ) + { + req->access = access; + req->initval = initval; + req->type = type; + req->max = max; + wine_server_add_data( req, objattr, len ); + ret = wine_server_call( req ); + if (!ret || ret == STATUS_OBJECT_NAME_EXISTS) + { + *handle = wine_server_ptr_handle( reply->handle ); + type = reply->type; + shm_idx = reply->shm_idx; + fd = receive_fd( &fd_handle ); + assert( wine_server_ptr_handle(fd_handle) == *handle ); + } + } + SERVER_END_REQ; + server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); + + if (!ret || ret == STATUS_OBJECT_NAME_EXISTS) + { + add_to_list( *handle, type, fd, shm_idx ? get_shm( shm_idx ) : 0 ); + TRACE("-> handle %p, fd %d.\n", *handle, fd); + } + + free( objattr ); + return ret; +} + +extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) +{ + TRACE("name %s, initial %d, max %d.\n", + attr ? debugstr_us(attr->ObjectName) : "", (int)initial, (int)max); + + return create_esync( ESYNC_SEMAPHORE, handle, access, attr, initial, max ); +} + +void esync_init(void) +{ + struct stat st; + + if (!do_esync()) + { + /* make sure the server isn't running with WINEESYNC */ + HANDLE handle; + NTSTATUS ret; + + ret = create_esync( 0, &handle, 0, NULL, 0, 0 ); + if (ret != STATUS_NOT_IMPLEMENTED) + { + ERR("Server is running with WINEESYNC but this process is not, please enable WINEESYNC or restart wineserver.\n"); + exit(1); + } + + return; + } + + if (stat( config_dir, &st ) == -1) + ERR("Cannot stat %s\n", config_dir); + + if (st.st_ino != (unsigned long)st.st_ino) + sprintf( shm_name, "/wine-%lx%08lx-esync", (unsigned long)((unsigned long long)st.st_ino >> 32), (unsigned long)st.st_ino ); + else + sprintf( shm_name, "/wine-%lx-esync", (unsigned long)st.st_ino ); + + if ((shm_fd = shm_open( shm_name, O_RDWR, 0644 )) == -1) + { + /* probably the server isn't running with WINEESYNC, tell the user and bail */ + if (errno == ENOENT) + ERR("Failed to open esync shared memory file; make sure no stale wineserver instances are running without WINEESYNC.\n"); + else + ERR("Failed to initialize shared memory: %s\n", strerror( errno )); + exit(1); + } + + pagesize = sysconf( _SC_PAGESIZE ); + + shm_addrs = calloc( 128, sizeof(shm_addrs[0]) ); + shm_addrs_size = 128; +} diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h new file mode 100644 index 00000000000..a50a755149a --- /dev/null +++ b/dlls/ntdll/unix/esync.h @@ -0,0 +1,35 @@ +/* + * eventfd-based synchronization objects + * + * Copyright (C) 2018 Zebediah Figura + * + * 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 + */ + +extern int do_esync(void) DECLSPEC_HIDDEN; +extern void esync_init(void) DECLSPEC_HIDDEN; + +extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN; + + +/* We have to synchronize on the fd cache mutex so that our calls to receive_fd + * don't race with theirs. It looks weird, I know. + * + * If we weren't trying to avoid touching the code I'd rename the mutex to + * "server_fd_mutex" or something similar. */ +extern pthread_mutex_t fd_cache_mutex; + +extern int receive_fd( obj_handle_t *handle ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index a1525cf7f93..a675adea3e3 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -89,6 +89,7 @@ #include "winioctl.h" #include "winternl.h" #include "unix_private.h" +#include "esync.h" #include "wine/list.h" #include "wine/debug.h" @@ -2082,6 +2083,7 @@ static void start_main_thread(void) signal_alloc_thread( teb ); dbg_init(); startup_info_size = server_init_process(); + esync_init(); virtual_map_user_shared_data(); init_cpu_info(); init_files(); diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 75a766078cd..0ac77a054b7 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -106,7 +106,7 @@ sigset_t server_block_set; /* signals to block during server calls */ static int fd_socket = -1; /* socket to exchange file descriptors with the server */ static int initial_cwd = -1; static pid_t server_pid; -static pthread_mutex_t fd_cache_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t fd_cache_mutex = PTHREAD_MUTEX_INITIALIZER; /* atomically exchange a 64-bit value */ static inline LONG64 interlocked_xchg64( LONG64 *dest, LONG64 val ) @@ -838,7 +838,7 @@ void wine_server_send_fd( int fd ) * * Receive a file descriptor passed from the server. */ -static int receive_fd( obj_handle_t *handle ) +int receive_fd( obj_handle_t *handle ) { struct iovec vec; struct msghdr msghdr; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index a0905963562..17d0ddc0d11 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -64,6 +64,7 @@ #include "wine/server.h" #include "wine/debug.h" #include "unix_private.h" +#include "esync.h" WINE_DEFAULT_DEBUG_CHANNEL(sync); @@ -273,6 +274,9 @@ NTSTATUS WINAPI NtCreateSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJ if (max <= 0 || initial < 0 || initial > max) return STATUS_INVALID_PARAMETER; if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; + if (do_esync()) + return esync_create_semaphore( handle, access, attr, initial, max ); + SERVER_START_REQ( create_semaphore ) { req->access = access; diff --git a/server/esync.c b/server/esync.c index 35b4833fd4c..75ef586df30 100644 --- a/server/esync.c +++ b/server/esync.c @@ -41,6 +41,7 @@ #include "handle.h" #include "request.h" #include "file.h" +#include "esync.h" int do_esync(void) { From 72acc1f748bbe1601996e38adefb95118a01eb3f Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 12:16:34 -0500 Subject: [PATCH 0007/2777] ntdll: Implement NtReleaseSemaphore(). Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 43 +++++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/esync.h | 1 + dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 47 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index dc2228390ec..b7038e99f4d 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #ifdef HAVE_SYS_STAT_H @@ -171,6 +172,16 @@ static struct esync *add_to_list( HANDLE handle, enum esync_type type, int fd, v return &esync_list[entry][idx]; } +static struct esync *get_cached_object( HANDLE handle ) +{ + UINT_PTR entry, idx = handle_to_index( handle, &entry ); + + if (entry >= ESYNC_LIST_ENTRIES || !esync_list[entry]) return NULL; + if (!esync_list[entry][idx].type) return NULL; + + return &esync_list[entry][idx]; +} + static NTSTATUS create_esync( enum esync_type type, HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, int initval, int max ) { @@ -226,6 +237,38 @@ extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, return create_esync( ESYNC_SEMAPHORE, handle, access, attr, initial, max ); } +NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) +{ + struct esync *obj; + struct semaphore *semaphore; + uint64_t count64 = count; + ULONG current; + + TRACE("%p, %d, %p.\n", handle, (int)count, prev); + + if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; + semaphore = obj->shm; + + do + { + current = semaphore->count; + + if (count + current > semaphore->max) + return STATUS_SEMAPHORE_LIMIT_EXCEEDED; + } while (InterlockedCompareExchange( (LONG *)&semaphore->count, count + current, current ) != current); + + if (prev) *prev = current; + + /* We don't have to worry about a race between increasing the count and + * write(). The fact that we were able to increase the count means that we + * have permission to actually write that many releases to the semaphore. */ + + if (write( obj->fd, &count64, sizeof(count64) ) == -1) + return errno_to_status( errno ); + + return STATUS_SUCCESS; +} + void esync_init(void) { struct stat st; diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h index a50a755149a..09838e95535 100644 --- a/dlls/ntdll/unix/esync.h +++ b/dlls/ntdll/unix/esync.h @@ -23,6 +23,7 @@ extern void esync_init(void) DECLSPEC_HIDDEN; extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN; +extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) DECLSPEC_HIDDEN; /* We have to synchronize on the fd cache mutex so that our calls to receive_fd diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 17d0ddc0d11..19ed0b9fb48 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -359,6 +359,9 @@ NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, ULONG *previous { unsigned int ret; + if (do_esync()) + return esync_release_semaphore( handle, count, previous ); + SERVER_START_REQ( release_semaphore ) { req->handle = wine_server_obj_handle( handle ); From 745531523314fa8bcd25a5310359f0399f0d20ee Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 12:20:44 -0500 Subject: [PATCH 0008/2777] ntdll: Implement NtClose(). Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 18 ++++++++++++++++++ dlls/ntdll/unix/esync.h | 1 + dlls/ntdll/unix/server.c | 4 ++++ 3 files changed, 23 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index b7038e99f4d..cc0ba2ddc8e 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -182,6 +182,24 @@ static struct esync *get_cached_object( HANDLE handle ) return &esync_list[entry][idx]; } +NTSTATUS esync_close( HANDLE handle ) +{ + UINT_PTR entry, idx = handle_to_index( handle, &entry ); + + TRACE("%p.\n", handle); + + if (entry < ESYNC_LIST_ENTRIES && esync_list[entry]) + { + if (InterlockedExchange((LONG *)&esync_list[entry][idx].type, 0)) + { + close( esync_list[entry][idx].fd ); + return STATUS_SUCCESS; + } + } + + return STATUS_INVALID_HANDLE; +} + static NTSTATUS create_esync( enum esync_type type, HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, int initval, int max ) { diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h index 09838e95535..14e52416764 100644 --- a/dlls/ntdll/unix/esync.h +++ b/dlls/ntdll/unix/esync.h @@ -20,6 +20,7 @@ extern int do_esync(void) DECLSPEC_HIDDEN; extern void esync_init(void) DECLSPEC_HIDDEN; +extern NTSTATUS esync_close( HANDLE handle ) DECLSPEC_HIDDEN; extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 0ac77a054b7..56a110882ed 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -79,6 +79,7 @@ #include "wine/server.h" #include "wine/debug.h" #include "unix_private.h" +#include "esync.h" #include "ddk/wdm.h" WINE_DEFAULT_DEBUG_CHANNEL(server); @@ -1744,6 +1745,9 @@ NTSTATUS WINAPI NtClose( HANDLE handle ) * retrieve it again */ fd = remove_fd_from_cache( handle ); + if (do_esync()) + esync_close( handle ); + SERVER_START_REQ( close_handle ) { req->handle = wine_server_obj_handle( handle ); From eedff980001f098e75b9a38bf67f985d9292931a Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 12:34:42 -0500 Subject: [PATCH 0009/2777] ntdll: Implement NtWaitForMultipleObjects(). Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 168 ++++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/esync.h | 3 + dlls/ntdll/unix/sync.c | 7 ++ 3 files changed, 178 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index cc0ba2ddc8e..e4d123a0147 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -34,6 +34,12 @@ #ifdef HAVE_SYS_STAT_H # include #endif +#ifdef HAVE_POLL_H +#include +#endif +#ifdef HAVE_SYS_POLL_H +# include +#endif #include #include @@ -287,6 +293,168 @@ NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) return STATUS_SUCCESS; } +#define TICKSPERSEC 10000000 +#define TICKSPERMSEC 10000 + +static LONGLONG update_timeout( ULONGLONG end ) +{ + LARGE_INTEGER now; + LONGLONG timeleft; + + NtQuerySystemTime( &now ); + timeleft = end - now.QuadPart; + if (timeleft < 0) timeleft = 0; + return timeleft; +} + +static int do_poll( struct pollfd *fds, nfds_t nfds, ULONGLONG *end ) +{ + if (end) + { + LONGLONG timeleft = update_timeout( *end ); + +#ifdef HAVE_PPOLL + /* We use ppoll() if available since the time granularity is better. */ + struct timespec tmo_p; + tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; + tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; + return ppoll( fds, nfds, &tmo_p, NULL ); +#else + return poll( fds, nfds, timeleft / TICKSPERMSEC ); +#endif + } + else + return poll( fds, nfds, -1 ); +} + +static void update_grabbed_object( struct esync *obj ) +{ + if (obj->type == ESYNC_SEMAPHORE) + { + struct semaphore *semaphore = obj->shm; + /* We don't have to worry about a race between this and read(); the + * fact that we were able to grab it at all means the count is nonzero, + * and if someone else grabbed it then the count must have been >= 2, + * etc. */ + InterlockedExchangeAdd( (LONG *)&semaphore->count, -1 ); + } +} + +/* A value of STATUS_NOT_IMPLEMENTED returned from this function means that we + * need to delegate to server_select(). */ +NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ) +{ + struct esync *objs[MAXIMUM_WAIT_OBJECTS]; + struct pollfd fds[MAXIMUM_WAIT_OBJECTS]; + int has_esync = 0, has_server = 0; + LONGLONG timeleft; + LARGE_INTEGER now; + ULONGLONG end; + int i, ret; + + NtQuerySystemTime( &now ); + if (timeout) + { + if (timeout->QuadPart == TIMEOUT_INFINITE) + timeout = NULL; + else if (timeout->QuadPart >= 0) + end = timeout->QuadPart; + else + end = now.QuadPart - timeout->QuadPart; + } + + for (i = 0; i < count; i++) + { + if ((objs[i] = get_cached_object( handles[i] ))) + has_esync = 1; + else + has_server = 1; + } + + if (has_esync && has_server) + FIXME("Can't wait on esync and server objects at the same time!\n"); + else if (has_server) + return STATUS_NOT_IMPLEMENTED; + + if (TRACE_ON(esync)) + { + TRACE("Waiting for %s of %d handles:", wait_any ? "any" : "all", (int)count); + for (i = 0; i < count; i++) + TRACE(" %p", handles[i]); + + if (!timeout) + TRACE(", timeout = INFINITE.\n"); + else + { + timeleft = update_timeout( end ); + TRACE(", timeout = %ld.%07ld sec.\n", + (long) timeleft / TICKSPERSEC, (long) timeleft % TICKSPERSEC); + } + } + + if (wait_any || count == 1) + { + for (i = 0; i < count; i++) + { + fds[i].fd = objs[i] ? objs[i]->fd : -1; + fds[i].events = POLLIN; + } + + while (1) + { + ret = do_poll( fds, count, timeout ? &end : NULL ); + if (ret > 0) + { + /* Find out which object triggered the wait. */ + for (i = 0; i < count; i++) + { + struct esync *obj = objs[i]; + + if (fds[i].revents & (POLLERR | POLLHUP | POLLNVAL)) + { + ERR("Polling on fd %d returned %#x.\n", fds[i].fd, fds[i].revents); + return STATUS_INVALID_HANDLE; + } + + if (obj) + { + int64_t value; + ssize_t size; + + if ((size = read( fds[i].fd, &value, sizeof(value) )) == sizeof(value)) + { + /* We found our object. */ + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + update_grabbed_object( obj ); + return i; + } + } + } + + /* If we got here, someone else stole (or reset, etc.) whatever + * we were waiting for. So keep waiting. */ + NtQuerySystemTime( &now ); + } + else if (ret == 0) + { + TRACE("Wait timed out.\n"); + return STATUS_TIMEOUT; + } + else + { + ERR("ppoll failed: %s\n", strerror( errno )); + return errno_to_status( errno ); + } + } + } + else + { + FIXME("Wait-all not implemented.\n"); + return STATUS_NOT_IMPLEMENTED; + } +} + void esync_init(void) { struct stat st; diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h index 14e52416764..87516e7597a 100644 --- a/dlls/ntdll/unix/esync.h +++ b/dlls/ntdll/unix/esync.h @@ -26,6 +26,9 @@ extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN; extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) DECLSPEC_HIDDEN; +extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; + /* We have to synchronize on the fd cache mutex so that our calls to receive_fd * don't race with theirs. It looks weird, I know. diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 19ed0b9fb48..22eb1af1d28 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -1428,6 +1428,13 @@ NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles, BO if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1; + if (do_esync()) + { + NTSTATUS ret = esync_wait_objects( count, handles, wait_any, alertable, timeout ); + if (ret != STATUS_NOT_IMPLEMENTED) + return ret; + } + if (alertable) flags |= SELECT_ALERTABLE; select_op.wait.op = wait_any ? SELECT_WAIT : SELECT_WAIT_ALL; for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] ); From 39679f4074712b5296b659f25f2ca6edeac72fde Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 14:40:43 -0500 Subject: [PATCH 0010/2777] ntdll, server: Implement NtCreateEvent(). Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 27 +++++++++++++++++++++++++++ dlls/ntdll/unix/esync.h | 3 +++ dlls/ntdll/unix/sync.c | 4 ++++ server/esync.c | 15 +++++++++++++++ 4 files changed, 49 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index e4d123a0147..b382e74dc02 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -87,6 +87,13 @@ struct semaphore }; C_ASSERT(sizeof(struct semaphore) == 8); +struct event +{ + int signaled; + int locked; +}; +C_ASSERT(sizeof(struct event) == 8); + static char shm_name[29]; static int shm_fd; static void **shm_addrs; @@ -293,6 +300,18 @@ NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) return STATUS_SUCCESS; } +NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, EVENT_TYPE event_type, BOOLEAN initial ) +{ + enum esync_type type = (event_type == SynchronizationEvent ? ESYNC_AUTO_EVENT : ESYNC_MANUAL_EVENT); + + TRACE("name %s, %s-reset, initial %d.\n", + attr ? debugstr_us(attr->ObjectName) : "", + event_type == NotificationEvent ? "manual" : "auto", initial); + + return create_esync( type, handle, access, attr, initial, 0 ); +} + #define TICKSPERSEC 10000000 #define TICKSPERMSEC 10000 @@ -338,6 +357,14 @@ static void update_grabbed_object( struct esync *obj ) * etc. */ InterlockedExchangeAdd( (LONG *)&semaphore->count, -1 ); } + else if (obj->type == ESYNC_AUTO_EVENT) + { + struct event *event = obj->shm; + /* We don't have to worry about a race between this and read(), since + * this is just a hint, and the real state is in the kernel object. + * This might already be 0, but that's okay! */ + event->signaled = 0; + } } /* A value of STATUS_NOT_IMPLEMENTED returned from this function means that we diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h index 87516e7597a..d9c7df967f8 100644 --- a/dlls/ntdll/unix/esync.h +++ b/dlls/ntdll/unix/esync.h @@ -26,6 +26,9 @@ extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN; extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) DECLSPEC_HIDDEN; +extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN; + extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 22eb1af1d28..8b18c3c3d3a 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -388,6 +388,10 @@ NTSTATUS WINAPI NtCreateEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ *handle = 0; if (type != NotificationEvent && type != SynchronizationEvent) return STATUS_INVALID_PARAMETER; + + if (do_esync()) + return esync_create_event( handle, access, attr, type, state ); + if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; SERVER_START_REQ( create_event ) diff --git a/server/esync.c b/server/esync.c index 75ef586df30..6a63c0dd5e9 100644 --- a/server/esync.c +++ b/server/esync.c @@ -201,6 +201,13 @@ struct semaphore }; C_ASSERT(sizeof(struct semaphore) == 8); +struct event +{ + int signaled; + int locked; +}; +C_ASSERT(sizeof(struct event) == 8); + struct esync *create_esync( struct object *root, const struct unicode_str *name, unsigned int attr, int initval, int max, enum esync_type type, const struct security_descriptor *sd ) @@ -256,6 +263,14 @@ struct esync *create_esync( struct object *root, const struct unicode_str *name, semaphore->count = initval; break; } + case ESYNC_AUTO_EVENT: + case ESYNC_MANUAL_EVENT: + { + struct event *event = get_shm( esync->shm_idx ); + event->signaled = initval ? 1 : 0; + event->locked = 0; + break; + } default: assert( 0 ); } From 8b02a7cd114f15d39775851481748fbfce3dfcdf Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 14:46:24 -0500 Subject: [PATCH 0011/2777] ntdll: Implement NtSetEvent(). Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 15 +++++++++++++++ dlls/ntdll/unix/esync.h | 1 + dlls/ntdll/unix/sync.c | 4 ++++ 3 files changed, 20 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index b382e74dc02..89150d25798 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -312,6 +312,21 @@ NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, return create_esync( type, handle, access, attr, initial, 0 ); } +NTSTATUS esync_set_event( HANDLE handle ) +{ + static const uint64_t value = 1; + struct esync *obj; + + TRACE("%p.\n", handle); + + if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; + + if (write( obj->fd, &value, sizeof(value) ) == -1) + ERR("write: %s\n", strerror(errno)); + + return STATUS_SUCCESS; +} + #define TICKSPERSEC 10000000 #define TICKSPERMSEC 10000 diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h index d9c7df967f8..b585af047ee 100644 --- a/dlls/ntdll/unix/esync.h +++ b/dlls/ntdll/unix/esync.h @@ -28,6 +28,7 @@ extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN; +extern NTSTATUS esync_set_event( HANDLE handle ) DECLSPEC_HIDDEN; extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 8b18c3c3d3a..9af6f4aa9a5 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -440,8 +440,12 @@ NTSTATUS WINAPI NtOpenEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_AT */ NTSTATUS WINAPI NtSetEvent( HANDLE handle, LONG *prev_state ) { + /* This comment is a dummy to make sure this patch applies in the right place. */ unsigned int ret; + if (do_esync()) + return esync_set_event( handle ); + SERVER_START_REQ( event_op ) { req->handle = wine_server_obj_handle( handle ); From a4ece1943a3a967d28982f792c516d97b1b1fdb6 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 14:51:21 -0500 Subject: [PATCH 0012/2777] ntdll: Implement NtResetEvent(). Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 15 +++++++++++++++ dlls/ntdll/unix/esync.h | 1 + dlls/ntdll/unix/sync.c | 5 +++++ 3 files changed, 21 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 89150d25798..679b55d1ed2 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -327,6 +327,21 @@ NTSTATUS esync_set_event( HANDLE handle ) return STATUS_SUCCESS; } +NTSTATUS esync_reset_event( HANDLE handle ) +{ + uint64_t value; + struct esync *obj; + + TRACE("%p.\n", handle); + + if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; + + if (read( obj->fd, &value, sizeof(value) ) == -1 && errno != EWOULDBLOCK && errno != EAGAIN) + ERR("read: %s\n", strerror(errno)); + + return STATUS_SUCCESS; +} + #define TICKSPERSEC 10000000 #define TICKSPERMSEC 10000 diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h index b585af047ee..8480a213b2a 100644 --- a/dlls/ntdll/unix/esync.h +++ b/dlls/ntdll/unix/esync.h @@ -28,6 +28,7 @@ extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN; +extern NTSTATUS esync_reset_event( HANDLE handle ) DECLSPEC_HIDDEN; extern NTSTATUS esync_set_event( HANDLE handle ) DECLSPEC_HIDDEN; extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 9af6f4aa9a5..38ab9b80911 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -463,8 +463,13 @@ NTSTATUS WINAPI NtSetEvent( HANDLE handle, LONG *prev_state ) */ NTSTATUS WINAPI NtResetEvent( HANDLE handle, LONG *prev_state ) { + /* This comment is a dummy to make sure this patch applies in the right place. */ unsigned int ret; + if (do_esync()) + return esync_reset_event( handle ); + + SERVER_START_REQ( event_op ) { req->handle = wine_server_obj_handle( handle ); From 3c759eeeae83b2b9deb07046a5d6ff6c4d313d91 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 14:57:42 -0500 Subject: [PATCH 0013/2777] ntdll: Implement waiting on manual-reset events. Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 679b55d1ed2..9e77de5b458 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -34,12 +34,7 @@ #ifdef HAVE_SYS_STAT_H # include #endif -#ifdef HAVE_POLL_H #include -#endif -#ifdef HAVE_SYS_POLL_H -# include -#endif #include #include @@ -479,12 +474,24 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an int64_t value; ssize_t size; - if ((size = read( fds[i].fd, &value, sizeof(value) )) == sizeof(value)) + if (obj->type == ESYNC_MANUAL_EVENT) + { + /* Don't grab the object, just check if it's signaled. */ + if (fds[i].revents & POLLIN) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + return i; + } + } + else { - /* We found our object. */ - TRACE("Woken up by handle %p [%d].\n", handles[i], i); - update_grabbed_object( obj ); - return i; + if ((size = read( fds[i].fd, &value, sizeof(value) )) == sizeof(value)) + { + /* We found our object. */ + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + update_grabbed_object( obj ); + return i; + } } } } From 1904c02e56460573eedd9666034e47d260525f25 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 8 Jun 2018 18:51:40 -0500 Subject: [PATCH 0014/2777] server: Add an object operation to grab the esync file descriptor. Split off to decrease patch size. Wine-Staging: eventfd_synchronization --- server/async.c | 2 ++ server/atom.c | 1 + server/change.c | 1 + server/clipboard.c | 1 + server/completion.c | 1 + server/console.c | 7 +++++++ server/debugger.c | 2 ++ server/device.c | 4 ++++ server/directory.c | 2 ++ server/esync.c | 1 + server/event.c | 2 ++ server/fd.c | 4 ++++ server/file.c | 1 + server/handle.c | 1 + server/hook.c | 1 + server/mailslot.c | 4 ++++ server/mapping.c | 3 +++ server/mutex.c | 1 + server/named_pipe.c | 5 +++++ server/object.h | 2 ++ server/process.c | 3 +++ server/queue.c | 2 ++ server/registry.c | 1 + server/request.c | 1 + server/semaphore.c | 1 + server/serial.c | 1 + server/signal.c | 1 + server/sock.c | 3 +++ server/symlink.c | 1 + server/thread.c | 3 +++ server/timer.c | 1 + server/token.c | 1 + server/window.c | 1 + server/winstation.c | 2 ++ 34 files changed, 68 insertions(+) diff --git a/server/async.c b/server/async.c index 26946b5f5ce..76352ba19ae 100644 --- a/server/async.c +++ b/server/async.c @@ -77,6 +77,7 @@ static const struct object_ops async_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ async_signaled, /* signaled */ + NULL, /* get_esync_fd */ async_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -654,6 +655,7 @@ static const struct object_ops iosb_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/atom.c b/server/atom.c index ff0799f5880..d9824de8eac 100644 --- a/server/atom.c +++ b/server/atom.c @@ -79,6 +79,7 @@ static const struct object_ops atom_table_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/change.c b/server/change.c index 7a806abc017..e080511bb23 100644 --- a/server/change.c +++ b/server/change.c @@ -112,6 +112,7 @@ static const struct object_ops dir_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ dir_get_fd, /* get_fd */ diff --git a/server/clipboard.c b/server/clipboard.c index 8118a467dd8..8b265f2dcea 100644 --- a/server/clipboard.c +++ b/server/clipboard.c @@ -76,6 +76,7 @@ static const struct object_ops clipboard_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/completion.c b/server/completion.c index 6933195e72d..3d4be86a212 100644 --- a/server/completion.c +++ b/server/completion.c @@ -75,6 +75,7 @@ static const struct object_ops completion_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ completion_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/console.c b/server/console.c index 5f3f50d006f..ae5d84f7a06 100644 --- a/server/console.c +++ b/server/console.c @@ -81,6 +81,7 @@ static const struct object_ops console_ops = console_add_queue, /* add_queue */ remove_queue, /* remove_queue */ console_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ console_get_fd, /* get_fd */ @@ -158,6 +159,7 @@ static const struct object_ops console_server_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ console_server_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ console_server_get_fd, /* get_fd */ @@ -227,6 +229,7 @@ static const struct object_ops screen_buffer_ops = screen_buffer_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ screen_buffer_get_fd, /* get_fd */ @@ -276,6 +279,7 @@ static const struct object_ops console_device_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -313,6 +317,7 @@ static const struct object_ops console_input_ops = console_input_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ console_input_get_fd, /* get_fd */ @@ -370,6 +375,7 @@ static const struct object_ops console_output_ops = console_output_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ console_output_get_fd, /* get_fd */ @@ -428,6 +434,7 @@ static const struct object_ops console_connection_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ console_connection_get_fd, /* get_fd */ diff --git a/server/debugger.c b/server/debugger.c index 48adb244b09..d85a2000684 100644 --- a/server/debugger.c +++ b/server/debugger.c @@ -86,6 +86,7 @@ static const struct object_ops debug_event_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ debug_event_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -114,6 +115,7 @@ static const struct object_ops debug_obj_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ debug_obj_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/device.c b/server/device.c index 436dac6bfe9..f730fa81afa 100644 --- a/server/device.c +++ b/server/device.c @@ -66,6 +66,7 @@ static const struct object_ops irp_call_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -106,6 +107,7 @@ static const struct object_ops device_manager_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ device_manager_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -163,6 +165,7 @@ static const struct object_ops device_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -215,6 +218,7 @@ static const struct object_ops device_file_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ device_file_get_fd, /* get_fd */ diff --git a/server/directory.c b/server/directory.c index 23d7eb0a2b7..bc161b9ab7e 100644 --- a/server/directory.c +++ b/server/directory.c @@ -69,6 +69,7 @@ static const struct object_ops object_type_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -119,6 +120,7 @@ static const struct object_ops directory_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/esync.c b/server/esync.c index 6a63c0dd5e9..f95dc5a391f 100644 --- a/server/esync.c +++ b/server/esync.c @@ -122,6 +122,7 @@ static const struct object_ops esync_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/event.c b/server/event.c index f1b79b1b35e..c727bfdd1ba 100644 --- a/server/event.c +++ b/server/event.c @@ -72,6 +72,7 @@ static const struct object_ops event_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ event_signaled, /* signaled */ + NULL, /* get_esync_fd */ event_satisfied, /* satisfied */ event_signal, /* signal */ no_get_fd, /* get_fd */ @@ -119,6 +120,7 @@ static const struct object_ops keyed_event_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ keyed_event_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/fd.c b/server/fd.c index eaebe044f37..bbdb715a641 100644 --- a/server/fd.c +++ b/server/fd.c @@ -206,6 +206,7 @@ static const struct object_ops fd_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -247,6 +248,7 @@ static const struct object_ops device_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -287,6 +289,7 @@ static const struct object_ops inode_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -329,6 +332,7 @@ static const struct object_ops file_lock_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ file_lock_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/file.c b/server/file.c index 76c687833c9..26c62809d33 100644 --- a/server/file.c +++ b/server/file.c @@ -94,6 +94,7 @@ static const struct object_ops file_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ file_get_fd, /* get_fd */ diff --git a/server/handle.c b/server/handle.c index 38ad80da267..53cc1e4eb43 100644 --- a/server/handle.c +++ b/server/handle.c @@ -126,6 +126,7 @@ static const struct object_ops handle_table_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/hook.c b/server/hook.c index 5abdf39ad37..da351d6791f 100644 --- a/server/hook.c +++ b/server/hook.c @@ -80,6 +80,7 @@ static const struct object_ops hook_table_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/mailslot.c b/server/mailslot.c index 2d8697ec9bd..4cf9b73f784 100644 --- a/server/mailslot.c +++ b/server/mailslot.c @@ -74,6 +74,7 @@ static const struct object_ops mailslot_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ mailslot_get_fd, /* get_fd */ @@ -133,6 +134,7 @@ static const struct object_ops mail_writer_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ mail_writer_get_fd, /* get_fd */ @@ -196,6 +198,7 @@ static const struct object_ops mailslot_device_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -226,6 +229,7 @@ static const struct object_ops mailslot_device_file_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ mailslot_device_file_get_fd, /* get_fd */ diff --git a/server/mapping.c b/server/mapping.c index 8d4332d240f..1a8d480cfa9 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -67,6 +67,7 @@ static const struct object_ops ranges_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -103,6 +104,7 @@ static const struct object_ops shared_map_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -176,6 +178,7 @@ static const struct object_ops mapping_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ mapping_get_fd, /* get_fd */ diff --git a/server/mutex.c b/server/mutex.c index af0efe72132..4785a830e92 100644 --- a/server/mutex.c +++ b/server/mutex.c @@ -73,6 +73,7 @@ static const struct object_ops mutex_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ mutex_signaled, /* signaled */ + NULL, /* get_esync_fd */ mutex_satisfied, /* satisfied */ mutex_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/named_pipe.c b/server/named_pipe.c index 3e6cf09d4f2..b8ec17a787a 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -119,6 +119,7 @@ static const struct object_ops named_pipe_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -167,6 +168,7 @@ static const struct object_ops pipe_server_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ pipe_end_get_fd, /* get_fd */ @@ -211,6 +213,7 @@ static const struct object_ops pipe_client_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ pipe_end_get_fd, /* get_fd */ @@ -258,6 +261,7 @@ static const struct object_ops named_pipe_device_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -289,6 +293,7 @@ static const struct object_ops named_pipe_device_file_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ named_pipe_device_file_get_fd, /* get_fd */ diff --git a/server/object.h b/server/object.h index f156f1d2f13..c98e45125a0 100644 --- a/server/object.h +++ b/server/object.h @@ -78,6 +78,8 @@ struct object_ops void (*remove_queue)(struct object *,struct wait_queue_entry *); /* is object signaled? */ int (*signaled)(struct object *,struct wait_queue_entry *); + /* return the esync fd for this object */ + int (*get_esync_fd)(struct object *, enum esync_type *type); /* wait satisfied */ void (*satisfied)(struct object *,struct wait_queue_entry *); /* signal an object */ diff --git a/server/process.c b/server/process.c index 8a1fcd07a7f..89e40a3be49 100644 --- a/server/process.c +++ b/server/process.c @@ -105,6 +105,7 @@ static const struct object_ops process_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ process_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -156,6 +157,7 @@ static const struct object_ops startup_info_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ startup_info_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -217,6 +219,7 @@ static const struct object_ops job_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ job_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/queue.c b/server/queue.c index 07a31b47370..e2d4f8970c0 100644 --- a/server/queue.c +++ b/server/queue.c @@ -172,6 +172,7 @@ static const struct object_ops msg_queue_ops = msg_queue_add_queue, /* add_queue */ msg_queue_remove_queue, /* remove_queue */ msg_queue_signaled, /* signaled */ + NULL, /* get_esync_fd */ msg_queue_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -209,6 +210,7 @@ static const struct object_ops thread_input_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/registry.c b/server/registry.c index 03e5f20cae5..10f9cd0b69f 100644 --- a/server/registry.c +++ b/server/registry.c @@ -180,6 +180,7 @@ static const struct object_ops key_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/request.c b/server/request.c index 7021741c765..ca83fdbd2af 100644 --- a/server/request.c +++ b/server/request.c @@ -90,6 +90,7 @@ static const struct object_ops master_socket_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/semaphore.c b/server/semaphore.c index 53b42a886df..e3889f24601 100644 --- a/server/semaphore.c +++ b/server/semaphore.c @@ -70,6 +70,7 @@ static const struct object_ops semaphore_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ semaphore_signaled, /* signaled */ + NULL, /* get_esync_fd */ semaphore_satisfied, /* satisfied */ semaphore_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/serial.c b/server/serial.c index d665eb7fa35..11e204e4419 100644 --- a/server/serial.c +++ b/server/serial.c @@ -85,6 +85,7 @@ static const struct object_ops serial_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ serial_get_fd, /* get_fd */ diff --git a/server/signal.c b/server/signal.c index 19b76d44c16..55cd6aa037e 100644 --- a/server/signal.c +++ b/server/signal.c @@ -62,6 +62,7 @@ static const struct object_ops handler_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/sock.c b/server/sock.c index a64cb22404e..2b1eda396e5 100644 --- a/server/sock.c +++ b/server/sock.c @@ -445,6 +445,7 @@ static const struct object_ops sock_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ sock_get_fd, /* get_fd */ @@ -3465,6 +3466,7 @@ static const struct object_ops ifchange_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ ifchange_get_fd, /* get_fd */ @@ -3686,6 +3688,7 @@ static const struct object_ops socket_device_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/symlink.c b/server/symlink.c index 27d48e2f994..8cb24b4ff6e 100644 --- a/server/symlink.c +++ b/server/symlink.c @@ -71,6 +71,7 @@ static const struct object_ops symlink_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/thread.c b/server/thread.c index 5f8493dd309..103e0e94e4b 100644 --- a/server/thread.c +++ b/server/thread.c @@ -96,6 +96,7 @@ static const struct object_ops thread_apc_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ thread_apc_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -141,6 +142,7 @@ static const struct object_ops context_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ context_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -190,6 +192,7 @@ static const struct object_ops thread_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ thread_signaled, /* signaled */ + NULL, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/timer.c b/server/timer.c index 96dc9d00ca1..f59902d5607 100644 --- a/server/timer.c +++ b/server/timer.c @@ -76,6 +76,7 @@ static const struct object_ops timer_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ timer_signaled, /* signaled */ + NULL, /* get_esync_fd */ timer_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/token.c b/server/token.c index 99f5e36e279..5289a24e47b 100644 --- a/server/token.c +++ b/server/token.c @@ -143,6 +143,7 @@ static const struct object_ops token_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/window.c b/server/window.c index f713ed224aa..c000f493815 100644 --- a/server/window.c +++ b/server/window.c @@ -107,6 +107,7 @@ static const struct object_ops window_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/winstation.c b/server/winstation.c index 1408e1a9e65..a99c60a28ff 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -75,6 +75,7 @@ static const struct object_ops winstation_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -115,6 +116,7 @@ static const struct object_ops desktop_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ + NULL, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ From 5911fe05cecd8dd27f30be51e71a15569df7f802 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 8 Jun 2018 18:55:49 -0500 Subject: [PATCH 0015/2777] server: Add a request to get the eventfd file descriptor associated with a waitable handle. Wine-Staging: eventfd_synchronization --- server/esync.c | 37 +++++++++++++++++++++++++++++++++++++ server/protocol.def | 8 ++++++++ 2 files changed, 45 insertions(+) diff --git a/server/esync.c b/server/esync.c index f95dc5a391f..85f7f1e060f 100644 --- a/server/esync.c +++ b/server/esync.c @@ -333,3 +333,40 @@ DECL_HANDLER(create_esync) if (root) release_object( root ); } + +/* Retrieve a file descriptor for an esync object which will be signaled by the + * server. The client should only read from (i.e. wait on) this object. */ +DECL_HANDLER(get_esync_fd) +{ + struct object *obj; + enum esync_type type; + int fd; + + if (!(obj = get_handle_obj( current->process, req->handle, SYNCHRONIZE, NULL ))) + return; + + if (obj->ops->get_esync_fd) + { + fd = obj->ops->get_esync_fd( obj, &type ); + reply->type = type; + if (obj->ops == &esync_ops) + { + struct esync *esync = (struct esync *)obj; + reply->shm_idx = esync->shm_idx; + } + else + reply->shm_idx = 0; + send_client_fd( current->process, fd, req->handle ); + } + else + { + if (debug_level) + { + fprintf( stderr, "%04x: esync: can't wait on object: ", current->id ); + obj->ops->dump( obj, 0 ); + } + set_error( STATUS_NOT_IMPLEMENTED ); + } + + release_object( obj ); +} diff --git a/server/protocol.def b/server/protocol.def index c74498a3bcd..abaa9162daa 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3810,3 +3810,11 @@ enum esync_type int type; /* actual type (may be different for events) */ unsigned int shm_idx; @END + +/* Retrieve the esync fd for an object. */ +@REQ(get_esync_fd) + obj_handle_t handle; /* handle to the object */ +@REPLY + int type; + unsigned int shm_idx; +@END From 54a0088a8c7692b38cb5c3fdae2fc701742391c3 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 15:11:12 -0500 Subject: [PATCH 0016/2777] server: Create eventfd file descriptors for process objects. Wine-Staging: eventfd_synchronization --- server/esync.c | 18 ++++++++++++++++++ server/esync.h | 1 + server/process.c | 16 +++++++++++++++- server/process.h | 1 + 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/server/esync.c b/server/esync.c index 85f7f1e060f..44214e5fe02 100644 --- a/server/esync.c +++ b/server/esync.c @@ -295,6 +295,24 @@ struct esync *create_esync( struct object *root, const struct unicode_str *name, #endif } +/* Create a file descriptor for an existing handle. + * Caller must close the handle when it's done; it's not linked to an esync + * server object in any way. */ +int esync_create_fd( int initval, int flags ) +{ +#ifdef HAVE_SYS_EVENTFD_H + int fd; + + fd = eventfd( initval, flags | EFD_CLOEXEC | EFD_NONBLOCK ); + if (fd == -1) + perror( "eventfd" ); + + return fd; +#else + return -1; +#endif +} + DECL_HANDLER(create_esync) { struct esync *esync; diff --git a/server/esync.h b/server/esync.h index 00f9e638d83..8522d8a69ae 100644 --- a/server/esync.h +++ b/server/esync.h @@ -22,3 +22,4 @@ extern int do_esync(void); void esync_init(void); +int esync_create_fd( int initval, int flags ); diff --git a/server/process.c b/server/process.c index 89e40a3be49..8d6ed3f548b 100644 --- a/server/process.c +++ b/server/process.c @@ -63,6 +63,7 @@ #include "request.h" #include "user.h" #include "security.h" +#include "esync.h" /* process object */ @@ -95,6 +96,7 @@ static struct security_descriptor *process_get_sd( struct object *obj ); static void process_poll_event( struct fd *fd, int event ); static struct list *process_get_kernel_obj_list( struct object *obj ); static void process_destroy( struct object *obj ); +static int process_get_esync_fd( struct object *obj, enum esync_type *type ); static void terminate_process( struct process *process, struct thread *skip, int exit_code ); static const struct object_ops process_ops = @@ -105,7 +107,7 @@ static const struct object_ops process_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ process_signaled, /* signaled */ - NULL, /* get_esync_fd */ + process_get_esync_fd, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -686,6 +688,7 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla process->rawinput_mouse = NULL; process->rawinput_kbd = NULL; memset( &process->image_info, 0, sizeof(process->image_info) ); + process->esync_fd = -1; list_init( &process->kernel_object ); list_init( &process->thread_list ); list_init( &process->locks ); @@ -742,6 +745,9 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla if (!token_assign_label( process->token, &high_label_sid )) goto error; + if (do_esync()) + process->esync_fd = esync_create_fd( 0, 0 ); + set_fd_events( process->msg_fd, POLLIN ); /* start listening to events */ return process; @@ -789,6 +795,7 @@ static void process_destroy( struct object *obj ) free( process->rawinput_devices ); free( process->dir_cache ); free( process->image ); + if (do_esync()) close( process->esync_fd ); } /* dump a process on stdout for debugging purposes */ @@ -806,6 +813,13 @@ static int process_signaled( struct object *obj, struct wait_queue_entry *entry return !process->running_threads; } +static int process_get_esync_fd( struct object *obj, enum esync_type *type ) +{ + struct process *process = (struct process *)obj; + *type = ESYNC_MANUAL_SERVER; + return process->esync_fd; +} + static unsigned int process_map_access( struct object *obj, unsigned int access ) { access = default_map_access( obj, access ); diff --git a/server/process.h b/server/process.h index 97e0d455ece..a0a071d8f88 100644 --- a/server/process.h +++ b/server/process.h @@ -85,6 +85,7 @@ struct process const struct rawinput_device *rawinput_kbd; /* rawinput keyboard device, if any */ struct list kernel_object; /* list of kernel object pointers */ pe_image_info_t image_info; /* main exe image info */ + int esync_fd; /* esync file descriptor (signaled on exit) */ }; /* process functions */ From d293dd4043d7b85d451806494ef227f64f2df378 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 15:19:37 -0500 Subject: [PATCH 0017/2777] ntdll, server: Implement waiting on server-bound objects. The code here is sort of self-explanatory, but since I split it up over several patches I'll provide a quick explanation. The basic principle is that we can create an eventfd descriptor for any synchronizable handle, and signal it on the server side whenever a wakeup would be triggered. This means not only that we can wait simultaneously on esync primitives and on other primitives, but that we can do it all in "user-mode", i.e. without having to make a server call. With this patch we break waiting on svcctl.exe. Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 84 ++++++++++++++++++++++++++++++++++++++--- server/esync.c | 16 ++++++++ server/esync.h | 1 + server/thread.c | 4 ++ 4 files changed, 99 insertions(+), 6 deletions(-) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 9e77de5b458..f4eda7f2d04 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -190,6 +190,72 @@ static struct esync *get_cached_object( HANDLE handle ) return &esync_list[entry][idx]; } +/* Gets an object. This is either a proper esync object (i.e. an event, + * semaphore, etc. created using create_esync) or a generic synchronizable + * server-side object which the server will signal (e.g. a process, thread, + * message queue, etc.) */ +static NTSTATUS get_object( HANDLE handle, struct esync **obj ) +{ + NTSTATUS ret = STATUS_SUCCESS; + enum esync_type type = 0; + unsigned int shm_idx = 0; + obj_handle_t fd_handle; + sigset_t sigset; + int fd = -1; + + if ((*obj = get_cached_object( handle ))) return STATUS_SUCCESS; + + if ((INT_PTR)handle < 0) + { + /* We can deal with pseudo-handles, but it's just easier this way */ + return STATUS_NOT_IMPLEMENTED; + } + + if (!handle) + { + /* Shadow of the Tomb Raider really likes passing in NULL handles to + * various functions. Concerning, but let's avoid a server call. */ + return STATUS_INVALID_HANDLE; + } + + /* We need to try grabbing it from the server. */ + server_enter_uninterrupted_section( &fd_cache_mutex, &sigset ); + if (!(*obj = get_cached_object( handle ))) + { + SERVER_START_REQ( get_esync_fd ) + { + req->handle = wine_server_obj_handle( handle ); + if (!(ret = wine_server_call( req ))) + { + type = reply->type; + shm_idx = reply->shm_idx; + fd = receive_fd( &fd_handle ); + assert( wine_server_ptr_handle(fd_handle) == handle ); + } + } + SERVER_END_REQ; + } + server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); + + if (*obj) + { + /* We managed to grab it while in the CS; return it. */ + return STATUS_SUCCESS; + } + + if (ret) + { + WARN("Failed to retrieve fd for handle %p, status %#x.\n", handle, (unsigned int)ret); + *obj = NULL; + return ret; + } + + TRACE("Got fd %d for handle %p.\n", fd, handle); + + *obj = add_to_list( handle, type, fd, shm_idx ? get_shm( shm_idx ) : 0 ); + return ret; +} + NTSTATUS esync_close( HANDLE handle ) { UINT_PTR entry, idx = handle_to_index( handle, &entry ); @@ -269,10 +335,11 @@ NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) struct semaphore *semaphore; uint64_t count64 = count; ULONG current; + NTSTATUS ret; TRACE("%p, %d, %p.\n", handle, (int)count, prev); - if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; + if ((ret = get_object( handle, &obj))) return ret; semaphore = obj->shm; do @@ -311,10 +378,11 @@ NTSTATUS esync_set_event( HANDLE handle ) { static const uint64_t value = 1; struct esync *obj; + NTSTATUS ret; TRACE("%p.\n", handle); - if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; + if ((ret = get_object( handle, &obj))) return ret; if (write( obj->fd, &value, sizeof(value) ) == -1) ERR("write: %s\n", strerror(errno)); @@ -326,10 +394,11 @@ NTSTATUS esync_reset_event( HANDLE handle ) { uint64_t value; struct esync *obj; + NTSTATUS ret; TRACE("%p.\n", handle); - if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; + if ((ret = get_object( handle, &obj))) return ret; if (read( obj->fd, &value, sizeof(value) ) == -1 && errno != EWOULDBLOCK && errno != EAGAIN) ERR("read: %s\n", strerror(errno)); @@ -418,10 +487,13 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an for (i = 0; i < count; i++) { - if ((objs[i] = get_cached_object( handles[i] ))) + ret = get_object( handles[i], &objs[i] ); + if (ret == STATUS_SUCCESS) has_esync = 1; - else + else if (ret == STATUS_NOT_IMPLEMENTED) has_server = 1; + else + return ret; } if (has_esync && has_server) @@ -474,7 +546,7 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an int64_t value; ssize_t size; - if (obj->type == ESYNC_MANUAL_EVENT) + if (obj->type == ESYNC_MANUAL_EVENT || obj->type == ESYNC_MANUAL_SERVER) { /* Don't grab the object, just check if it's signaled. */ if (fds[i].revents & POLLIN) diff --git a/server/esync.c b/server/esync.c index 44214e5fe02..60e98936455 100644 --- a/server/esync.c +++ b/server/esync.c @@ -313,6 +313,22 @@ int esync_create_fd( int initval, int flags ) #endif } +/* Wake up a server-side esync object. */ +void esync_wake_up( struct object *obj ) +{ + static const uint64_t value = 1; + enum esync_type dummy; + int fd; + + if (obj->ops->get_esync_fd) + { + fd = obj->ops->get_esync_fd( obj, &dummy ); + + if (write( fd, &value, sizeof(value) ) == -1) + perror( "esync: write" ); + } +} + DECL_HANDLER(create_esync) { struct esync *esync; diff --git a/server/esync.h b/server/esync.h index 8522d8a69ae..1241e6d9f1a 100644 --- a/server/esync.h +++ b/server/esync.h @@ -23,3 +23,4 @@ extern int do_esync(void); void esync_init(void); int esync_create_fd( int initval, int flags ); +void esync_wake_up( struct object *obj ); diff --git a/server/thread.c b/server/thread.c index 103e0e94e4b..c61067a8ae6 100644 --- a/server/thread.c +++ b/server/thread.c @@ -50,6 +50,7 @@ #include "request.h" #include "user.h" #include "security.h" +#include "esync.h" /* thread queues */ @@ -1065,6 +1066,9 @@ void wake_up( struct object *obj, int max ) struct list *ptr; int ret; + if (do_esync()) + esync_wake_up( obj ); + LIST_FOR_EACH( ptr, &obj->wait_queue ) { struct wait_queue_entry *entry = LIST_ENTRY( ptr, struct wait_queue_entry, entry ); From 6caa578a02aec1d03fabc5a4d0b80a3212f1f26f Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 8 Jun 2018 21:01:24 -0500 Subject: [PATCH 0018/2777] server: Create eventfd file descriptors for event objects. We still need this, since there are some events which the server signals. This lets system processes shut down. Wine-Staging: eventfd_synchronization --- server/esync.c | 8 ++++++++ server/esync.h | 1 + server/event.c | 29 +++++++++++++++++++++++++++-- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/server/esync.c b/server/esync.c index 60e98936455..b37438cbecc 100644 --- a/server/esync.c +++ b/server/esync.c @@ -329,6 +329,14 @@ void esync_wake_up( struct object *obj ) } } +void esync_clear( int fd ) +{ + uint64_t value; + + /* we don't care about the return value */ + read( fd, &value, sizeof(value) ); +} + DECL_HANDLER(create_esync) { struct esync *esync; diff --git a/server/esync.h b/server/esync.h index 1241e6d9f1a..d259b5f604d 100644 --- a/server/esync.h +++ b/server/esync.h @@ -24,3 +24,4 @@ extern int do_esync(void); void esync_init(void); int esync_create_fd( int initval, int flags ); void esync_wake_up( struct object *obj ); +void esync_clear( int fd ); diff --git a/server/event.c b/server/event.c index c727bfdd1ba..f1a88e3d23f 100644 --- a/server/event.c +++ b/server/event.c @@ -35,6 +35,7 @@ #include "thread.h" #include "request.h" #include "security.h" +#include "esync.h" static const WCHAR event_name[] = {'E','v','e','n','t'}; @@ -56,13 +57,16 @@ struct event struct list kernel_object; /* list of kernel object pointers */ int manual_reset; /* is it a manual reset event? */ int signaled; /* event has been signaled */ + int esync_fd; /* esync file descriptor */ }; static void event_dump( struct object *obj, int verbose ); static int event_signaled( struct object *obj, struct wait_queue_entry *entry ); static void event_satisfied( struct object *obj, struct wait_queue_entry *entry ); +static int event_get_esync_fd( struct object *obj, enum esync_type *type ); static int event_signal( struct object *obj, unsigned int access); static struct list *event_get_kernel_obj_list( struct object *obj ); +static void event_destroy( struct object *obj ); static const struct object_ops event_ops = { @@ -72,7 +76,7 @@ static const struct object_ops event_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ event_signaled, /* signaled */ - NULL, /* get_esync_fd */ + event_get_esync_fd, /* get_esync_fd */ event_satisfied, /* satisfied */ event_signal, /* signal */ no_get_fd, /* get_fd */ @@ -86,7 +90,7 @@ static const struct object_ops event_ops = no_open_file, /* open_file */ event_get_kernel_obj_list, /* get_kernel_obj_list */ no_close_handle, /* close_handle */ - no_destroy /* destroy */ + event_destroy /* destroy */ }; @@ -152,6 +156,9 @@ struct event *create_event( struct object *root, const struct unicode_str *name, list_init( &event->kernel_object ); event->manual_reset = manual_reset; event->signaled = initial_state; + + if (do_esync()) + event->esync_fd = esync_create_fd( initial_state, 0 ); } } return event; @@ -180,6 +187,9 @@ void set_event( struct event *event ) void reset_event( struct event *event ) { event->signaled = 0; + + if (do_esync()) + esync_clear( event->esync_fd ); } static void event_dump( struct object *obj, int verbose ) @@ -197,6 +207,13 @@ static int event_signaled( struct object *obj, struct wait_queue_entry *entry ) return event->signaled; } +static int event_get_esync_fd( struct object *obj, enum esync_type *type ) +{ + struct event *event = (struct event *)obj; + *type = event->manual_reset ? ESYNC_MANUAL_SERVER : ESYNC_AUTO_SERVER; + return event->esync_fd; +} + static void event_satisfied( struct object *obj, struct wait_queue_entry *entry ) { struct event *event = (struct event *)obj; @@ -225,6 +242,14 @@ static struct list *event_get_kernel_obj_list( struct object *obj ) return &event->kernel_object; } +static void event_destroy( struct object *obj ) +{ + struct event *event = (struct event *)obj; + + if (do_esync()) + close( event->esync_fd ); +} + struct keyed_event *create_keyed_event( struct object *root, const struct unicode_str *name, unsigned int attr, const struct security_descriptor *sd ) { From d042d25cbe88c8e17a64139e9bec37d34de59184 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 8 Jun 2018 21:43:37 -0500 Subject: [PATCH 0019/2777] server: Allow (re)setting esync events on the server side. Some server calls pass an event handle, most notably asyncs. We need to be able to handle these correctly. Accordingly we pass them along to esync if it turns out the underlying object is actually an esync object. In an ideal world we'd just convert all instances of events on the server side to use esyncs instead. But we want to keep esync perfectly configurable, so this is how we do it. Wine-Staging: eventfd_synchronization --- server/esync.c | 22 +++++++++++++++++++++- server/esync.h | 6 ++++++ server/event.c | 15 +++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/server/esync.c b/server/esync.c index b37438cbecc..669afbc70d7 100644 --- a/server/esync.c +++ b/server/esync.c @@ -114,7 +114,7 @@ struct esync static void esync_dump( struct object *obj, int verbose ); static void esync_destroy( struct object *obj ); -static const struct object_ops esync_ops = +const struct object_ops esync_ops = { sizeof(struct esync), /* size */ &no_type, /* type */ @@ -337,6 +337,26 @@ void esync_clear( int fd ) read( fd, &value, sizeof(value) ); } +/* Server-side event support. */ +void esync_set_event( struct esync *esync ) +{ + static const uint64_t value = 1; + + assert( esync->obj.ops == &esync_ops ); + if (write( esync->fd, &value, sizeof(value) ) == -1) + perror( "esync: write" ); +} + +void esync_reset_event( struct esync *esync ) +{ + static uint64_t value = 1; + + assert( esync->obj.ops == &esync_ops ); + + /* we don't care about the return value */ + read( esync->fd, &value, sizeof(value) ); +} + DECL_HANDLER(create_esync) { struct esync *esync; diff --git a/server/esync.h b/server/esync.h index d259b5f604d..689d8569b73 100644 --- a/server/esync.h +++ b/server/esync.h @@ -25,3 +25,9 @@ void esync_init(void); int esync_create_fd( int initval, int flags ); void esync_wake_up( struct object *obj ); void esync_clear( int fd ); + +struct esync; + +extern const struct object_ops esync_ops; +void esync_set_event( struct esync *esync ); +void esync_reset_event( struct esync *esync ); diff --git a/server/event.c b/server/event.c index f1a88e3d23f..f4ca3e48c6f 100644 --- a/server/event.c +++ b/server/event.c @@ -166,6 +166,10 @@ struct event *create_event( struct object *root, const struct unicode_str *name, struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access ) { + struct object *obj; + if (do_esync() && (obj = get_handle_obj( process, handle, access, &esync_ops))) + return (struct event *)obj; /* even though it's not an event */ + return (struct event *)get_handle_obj( process, handle, access, &event_ops ); } @@ -179,6 +183,12 @@ static void pulse_event( struct event *event ) void set_event( struct event *event ) { + if (do_esync() && event->obj.ops == &esync_ops) + { + esync_set_event( (struct esync *)event ); + return; + } + event->signaled = 1; /* wake up all waiters if manual reset, a single one otherwise */ wake_up( &event->obj, !event->manual_reset ); @@ -186,6 +196,11 @@ void set_event( struct event *event ) void reset_event( struct event *event ) { + if (do_esync() && event->obj.ops == &esync_ops) + { + esync_reset_event( (struct esync *)event ); + return; + } event->signaled = 0; if (do_esync()) From 1506b1548d65ae275c01f5e053438cd98788477c Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 8 Jun 2018 21:58:37 -0500 Subject: [PATCH 0020/2777] ntdll: Try again if poll() returns EINTR. I originally had this return STATUS_USER_APC, but that isn't correct. The server code here is a bit confusing, but only the thread that waits *during* the suspend should receive STATUS_USER_APC (and I imagine that it really should receive STATUS_KERNEL_APC instead). The thread that is suspended should just keep on waiting. Besides, we could be suspended for reasons other than to deliver a system APC. Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index f4eda7f2d04..cba696f4b0a 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -422,22 +422,32 @@ static LONGLONG update_timeout( ULONGLONG end ) static int do_poll( struct pollfd *fds, nfds_t nfds, ULONGLONG *end ) { - if (end) + int ret; + + do { - LONGLONG timeleft = update_timeout( *end ); + if (end) + { + LONGLONG timeleft = update_timeout( *end ); #ifdef HAVE_PPOLL - /* We use ppoll() if available since the time granularity is better. */ - struct timespec tmo_p; - tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; - tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; - return ppoll( fds, nfds, &tmo_p, NULL ); + /* We use ppoll() if available since the time granularity is better. */ + struct timespec tmo_p; + tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; + tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; + ret = ppoll( fds, nfds, &tmo_p, NULL ); #else - return poll( fds, nfds, timeleft / TICKSPERMSEC ); + ret = poll( fds, nfds, timeleft / TICKSPERMSEC ); #endif - } - else - return poll( fds, nfds, -1 ); + } + else + ret = poll( fds, nfds, -1 ); + + /* If we receive EINTR we were probably suspended (SIGUSR1), possibly for a + * system APC. The right thing to do is just try again. */ + } while (ret < 0 && errno == EINTR); + + return ret; } static void update_grabbed_object( struct esync *obj ) From e4cbb11f98a0a1f5f76b990a6f5bc0bc18cd36ee Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 8 Jun 2018 22:04:29 -0500 Subject: [PATCH 0021/2777] server: Create eventfd file descriptors for thread objects. Wine-Staging: eventfd_synchronization --- server/thread.c | 17 ++++++++++++++++- server/thread.h | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/server/thread.c b/server/thread.c index c61067a8ae6..6c9fe2983ec 100644 --- a/server/thread.c +++ b/server/thread.c @@ -180,6 +180,7 @@ struct type_descr thread_type = static void dump_thread( struct object *obj, int verbose ); static int thread_signaled( struct object *obj, struct wait_queue_entry *entry ); +static int thread_get_esync_fd( struct object *obj, enum esync_type *type ); static unsigned int thread_map_access( struct object *obj, unsigned int access ); static void thread_poll_event( struct fd *fd, int event ); static struct list *thread_get_kernel_obj_list( struct object *obj ); @@ -193,7 +194,7 @@ static const struct object_ops thread_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ thread_signaled, /* signaled */ - NULL, /* get_esync_fd */ + thread_get_esync_fd, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -233,6 +234,7 @@ static inline void init_thread_structure( struct thread *thread ) thread->context = NULL; thread->teb = 0; thread->entry_point = 0; + thread->esync_fd = -1; thread->system_regs = 0; thread->queue = NULL; thread->wait = NULL; @@ -380,6 +382,9 @@ struct thread *create_thread( int fd, struct process *process, const struct secu } } + if (do_esync()) + thread->esync_fd = esync_create_fd( 0, 0 ); + set_fd_events( thread->request_fd, POLLIN ); /* start listening to events */ add_process_thread( thread->process, thread ); return thread; @@ -458,6 +463,9 @@ static void destroy_thread( struct object *obj ) release_object( thread->process ); if (thread->id) free_ptid( thread->id ); if (thread->token) release_object( thread->token ); + + if (do_esync()) + close( thread->esync_fd ); } /* dump a thread on stdout for debugging purposes */ @@ -476,6 +484,13 @@ static int thread_signaled( struct object *obj, struct wait_queue_entry *entry ) return (mythread->state == TERMINATED); } +static int thread_get_esync_fd( struct object *obj, enum esync_type *type ) +{ + struct thread *thread = (struct thread *)obj; + *type = ESYNC_MANUAL_SERVER; + return thread->esync_fd; +} + static unsigned int thread_map_access( struct object *obj, unsigned int access ) { access = default_map_access( obj, access ); diff --git a/server/thread.h b/server/thread.h index 8dcf966a90a..d4b16d1aba0 100644 --- a/server/thread.h +++ b/server/thread.h @@ -54,6 +54,7 @@ struct thread struct process *process; thread_id_t id; /* thread id */ struct list mutex_list; /* list of currently owned mutexes */ + int esync_fd; /* esync file descriptor (signalled on exit) */ unsigned int system_regs; /* which system regs have been set */ struct msg_queue *queue; /* message queue */ struct thread_wait *wait; /* current wait condition if sleeping */ From 9aa77765d538b7e1156652e3b8f255f7ffe873fe Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 8 Jun 2018 23:30:17 -0500 Subject: [PATCH 0022/2777] rpcrt4: Avoid closing the server thread handle while it is being waited on. This, or something like this, should go upstream. This is invalid behaviour. Wine-Staging: eventfd_synchronization --- dlls/rpcrt4/rpc_server.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/rpcrt4/rpc_server.c b/dlls/rpcrt4/rpc_server.c index 41431ebca02..77b5d83b3c0 100644 --- a/dlls/rpcrt4/rpc_server.c +++ b/dlls/rpcrt4/rpc_server.c @@ -701,10 +701,6 @@ static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg) } LeaveCriticalSection(&cps->cs); - EnterCriticalSection(&listen_cs); - CloseHandle(cps->server_thread); - cps->server_thread = NULL; - LeaveCriticalSection(&listen_cs); TRACE("done\n"); return 0; } @@ -1570,7 +1566,10 @@ RPC_STATUS WINAPI RpcMgmtWaitServerListen( void ) LIST_FOR_EACH_ENTRY(protseq, &protseqs, RpcServerProtseq, entry) { if ((wait_thread = protseq->server_thread)) + { + protseq->server_thread = NULL; break; + } } LeaveCriticalSection(&server_cs); if (!wait_thread) @@ -1579,6 +1578,7 @@ RPC_STATUS WINAPI RpcMgmtWaitServerListen( void ) TRACE("waiting for thread %lu\n", GetThreadId(wait_thread)); LeaveCriticalSection(&listen_cs); WaitForSingleObject(wait_thread, INFINITE); + CloseHandle(wait_thread); EnterCriticalSection(&listen_cs); } if (listen_done_event == event) From 59e77647903f191e8d1028399bdff5d3e561b1ce Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 16:01:56 -0500 Subject: [PATCH 0023/2777] server: Create eventfd file descriptors for message queues. Wine-Staging: eventfd_synchronization --- server/queue.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/server/queue.c b/server/queue.c index e2d4f8970c0..8a222d0dbed 100644 --- a/server/queue.c +++ b/server/queue.c @@ -41,6 +41,7 @@ #include "process.h" #include "request.h" #include "user.h" +#include "esync.h" #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE #define WM_NCMOUSELAST (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST)) @@ -141,6 +142,7 @@ struct msg_queue struct hook_table *hooks; /* hook table */ timeout_t last_get_msg; /* time of last get message call */ int keystate_lock; /* owns an input keystate lock */ + int esync_fd; /* esync file descriptor (signalled on message) */ }; struct hotkey @@ -157,6 +159,7 @@ static void msg_queue_dump( struct object *obj, int verbose ); static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry ); static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry ); static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entry ); +static int msg_queue_get_esync_fd( struct object *obj, enum esync_type *type ); static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry ); static void msg_queue_destroy( struct object *obj ); static void msg_queue_poll_event( struct fd *fd, int event ); @@ -172,7 +175,7 @@ static const struct object_ops msg_queue_ops = msg_queue_add_queue, /* add_queue */ msg_queue_remove_queue, /* remove_queue */ msg_queue_signaled, /* signaled */ - NULL, /* get_esync_fd */ + msg_queue_get_esync_fd, /* get_esync_fd */ msg_queue_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -311,12 +314,16 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ queue->hooks = NULL; queue->last_get_msg = current_time; queue->keystate_lock = 0; + queue->esync_fd = -1; list_init( &queue->send_result ); list_init( &queue->callback_result ); list_init( &queue->pending_timers ); list_init( &queue->expired_timers ); for (i = 0; i < NB_MSG_KINDS; i++) list_init( &queue->msg_list[i] ); + if (do_esync()) + queue->esync_fd = esync_create_fd( 0, 0 ); + thread->queue = queue; } if (new_input) release_object( new_input ); @@ -531,6 +538,9 @@ static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits if (queue->keystate_lock) unlock_input_keystate( queue->input ); queue->keystate_lock = 0; } + + if (do_esync() && !is_signaled( queue )) + esync_clear( queue->esync_fd ); } /* check whether msg is a keyboard message */ @@ -1035,6 +1045,13 @@ static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entr return ret || is_signaled( queue ); } +static int msg_queue_get_esync_fd( struct object *obj, enum esync_type *type ) +{ + struct msg_queue *queue = (struct msg_queue *)obj; + *type = ESYNC_QUEUE; + return queue->esync_fd; +} + static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry ) { struct msg_queue *queue = (struct msg_queue *)obj; @@ -1079,6 +1096,7 @@ static void msg_queue_destroy( struct object *obj ) release_object( queue->input ); if (queue->hooks) release_object( queue->hooks ); if (queue->fd) release_object( queue->fd ); + if (do_esync()) close( queue->esync_fd ); } static void msg_queue_poll_event( struct fd *fd, int event ) @@ -2448,6 +2466,9 @@ DECL_HANDLER(set_queue_mask) if (req->skip_wait) queue->wake_mask = queue->changed_mask = 0; else wake_up( &queue->obj, 0 ); } + + if (do_esync() && !is_signaled( queue )) + esync_clear( queue->esync_fd ); } } @@ -2461,6 +2482,9 @@ DECL_HANDLER(get_queue_status) reply->wake_bits = queue->wake_bits; reply->changed_bits = queue->changed_bits; queue->changed_bits &= ~req->clear_bits; + + if (do_esync() && !is_signaled( queue )) + esync_clear( queue->esync_fd ); } else reply->wake_bits = reply->changed_bits = 0; } @@ -2698,6 +2722,10 @@ DECL_HANDLER(get_message) queue->wake_mask = req->wake_mask; queue->changed_mask = req->changed_mask; set_error( STATUS_PENDING ); /* FIXME */ + + if (do_esync() && !is_signaled( queue )) + esync_clear( queue->esync_fd ); + } From 3d16004f03dead82e41a23007c77bf1f75b9712e Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 16:11:23 -0500 Subject: [PATCH 0024/2777] server, ntdll: Implement message waits. Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 51 +++++++++++++++++++++++++++++++++++++++-- server/protocol.def | 5 ++++ server/queue.c | 21 +++++++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index cba696f4b0a..2ba0dab5664 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -473,12 +473,13 @@ static void update_grabbed_object( struct esync *obj ) /* A value of STATUS_NOT_IMPLEMENTED returned from this function means that we * need to delegate to server_select(). */ -NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, +static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) { struct esync *objs[MAXIMUM_WAIT_OBJECTS]; struct pollfd fds[MAXIMUM_WAIT_OBJECTS]; int has_esync = 0, has_server = 0; + BOOL msgwait = FALSE; LONGLONG timeleft; LARGE_INTEGER now; ULONGLONG end; @@ -506,6 +507,9 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an return ret; } + if (objs[count - 1] && objs[count - 1]->type == ESYNC_QUEUE) + msgwait = TRUE; + if (has_esync && has_server) FIXME("Can't wait on esync and server objects at the same time!\n"); else if (has_server) @@ -517,6 +521,9 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an for (i = 0; i < count; i++) TRACE(" %p", handles[i]); + if (msgwait) + TRACE(" or driver events"); + if (!timeout) TRACE(", timeout = INFINITE.\n"); else @@ -556,7 +563,9 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an int64_t value; ssize_t size; - if (obj->type == ESYNC_MANUAL_EVENT || obj->type == ESYNC_MANUAL_SERVER) + if (obj->type == ESYNC_MANUAL_EVENT + || obj->type == ESYNC_MANUAL_SERVER + || obj->type == ESYNC_QUEUE) { /* Don't grab the object, just check if it's signaled. */ if (fds[i].revents & POLLIN) @@ -601,6 +610,44 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an } } +/* We need to let the server know when we are doing a message wait, and when we + * are done with one, so that all of the code surrounding hung queues works. + * We also need this for WaitForInputIdle(). */ +static void server_set_msgwait( int in_msgwait ) +{ + SERVER_START_REQ( esync_msgwait ) + { + req->in_msgwait = in_msgwait; + wine_server_call( req ); + } + SERVER_END_REQ; +} + +/* This is a very thin wrapper around the proper implementation above. The + * purpose is to make sure the server knows when we are doing a message wait. + * This is separated into a wrapper function since there are at least a dozen + * exit paths from esync_wait_objects(). */ +NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ) +{ + BOOL msgwait = FALSE; + struct esync *obj; + NTSTATUS ret; + + if (count && !get_object( handles[count - 1], &obj ) && obj->type == ESYNC_QUEUE) + { + msgwait = TRUE; + server_set_msgwait( 1 ); + } + + ret = __esync_wait_objects( count, handles, wait_any, alertable, timeout ); + + if (msgwait) + server_set_msgwait( 0 ); + + return ret; +} + void esync_init(void) { struct stat st; diff --git a/server/protocol.def b/server/protocol.def index abaa9162daa..894b0565aea 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3818,3 +3818,8 @@ enum esync_type int type; unsigned int shm_idx; @END + +/* Notify the server that we are doing a message wait or done with one. */ +@REQ(esync_msgwait) + int in_msgwait; /* are we in a message wait? */ +@END diff --git a/server/queue.c b/server/queue.c index 8a222d0dbed..5c246459f50 100644 --- a/server/queue.c +++ b/server/queue.c @@ -143,6 +143,7 @@ struct msg_queue timeout_t last_get_msg; /* time of last get message call */ int keystate_lock; /* owns an input keystate lock */ int esync_fd; /* esync file descriptor (signalled on message) */ + int esync_in_msgwait; /* our thread is currently waiting on us */ }; struct hotkey @@ -315,6 +316,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ queue->last_get_msg = current_time; queue->keystate_lock = 0; queue->esync_fd = -1; + queue->esync_in_msgwait = 0; list_init( &queue->send_result ); list_init( &queue->callback_result ); list_init( &queue->pending_timers ); @@ -990,6 +992,10 @@ static int is_queue_hung( struct msg_queue *queue ) if (get_wait_queue_thread(entry)->queue == queue) return 0; /* thread is waiting on queue -> not hung */ } + + if (do_esync() && queue->esync_in_msgwait) + return 0; /* thread is waiting on queue in absentia -> not hung */ + return 1; } @@ -3428,3 +3434,18 @@ DECL_HANDLER(update_rawinput_devices) process->rawinput_mouse = find_rawinput_device( process, 1, 2 ); process->rawinput_kbd = find_rawinput_device( process, 1, 6 ); } + +DECL_HANDLER(esync_msgwait) +{ + struct msg_queue *queue = get_current_queue(); + + if (!queue) return; + queue->esync_in_msgwait = req->in_msgwait; + + if (current->process->idle_event && !(queue->wake_mask & QS_SMRESULT)) + set_event( current->process->idle_event ); + + /* and start/stop waiting on the driver */ + if (queue->fd) + set_fd_events( queue->fd, req->in_msgwait ? POLLIN : 0 ); +} From 9017a4f2ed3e9332c2a3ad2db49ac33cbe33701b Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 9 Jun 2018 15:39:37 -0500 Subject: [PATCH 0025/2777] server: Create eventfd descriptors for device manager objects. We don't have to worry about synchronization here because wine_ntoskrnl_main_loop() is only ever called from one thread per winedevice process. This lets drivers like mountmgr finally work, and so winecfg can open the Drives tab. Wine-Staging: eventfd_synchronization --- server/device.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/server/device.c b/server/device.c index f730fa81afa..c45d0102a56 100644 --- a/server/device.c +++ b/server/device.c @@ -38,6 +38,7 @@ #include "handle.h" #include "request.h" #include "process.h" +#include "esync.h" /* IRP object */ @@ -93,10 +94,12 @@ struct device_manager struct list requests; /* list of pending irps across all devices */ struct irp_call *current_call; /* call currently executed on client side */ struct wine_rb_tree kernel_objects; /* map of objects that have client side pointer associated */ + int esync_fd; /* esync file descriptor */ }; static void device_manager_dump( struct object *obj, int verbose ); static int device_manager_signaled( struct object *obj, struct wait_queue_entry *entry ); +static int device_manager_get_esync_fd( struct object *obj, enum esync_type *type ); static void device_manager_destroy( struct object *obj ); static const struct object_ops device_manager_ops = @@ -107,7 +110,7 @@ static const struct object_ops device_manager_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ device_manager_signaled, /* signaled */ - NULL, /* get_esync_fd */ + device_manager_get_esync_fd, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -751,6 +754,9 @@ static void delete_file( struct device_file *file ) /* terminate all pending requests */ LIST_FOR_EACH_ENTRY_SAFE( irp, next, &file->requests, struct irp_call, dev_entry ) { + if (do_esync() && file->device->manager && list_empty( &file->device->manager->requests )) + esync_clear( file->device->manager->esync_fd ); + list_remove( &irp->mgr_entry ); set_irp_result( irp, STATUS_FILE_DELETED, NULL, 0, 0 ); } @@ -786,6 +792,13 @@ static int device_manager_signaled( struct object *obj, struct wait_queue_entry return !list_empty( &manager->requests ); } +static int device_manager_get_esync_fd( struct object *obj, enum esync_type *type ) +{ + struct device_manager *manager = (struct device_manager *)obj; + *type = ESYNC_MANUAL_SERVER; + return manager->esync_fd; +} + static void device_manager_destroy( struct object *obj ) { struct device_manager *manager = (struct device_manager *)obj; @@ -820,6 +833,9 @@ static void device_manager_destroy( struct object *obj ) assert( !irp->file && !irp->async ); release_object( irp ); } + + if (do_esync()) + close( manager->esync_fd ); } static struct device_manager *create_device_manager(void) @@ -832,6 +848,9 @@ static struct device_manager *create_device_manager(void) list_init( &manager->devices ); list_init( &manager->requests ); wine_rb_init( &manager->kernel_objects, compare_kernel_object ); + + if (do_esync()) + manager->esync_fd = esync_create_fd( 0, 0 ); } return manager; } @@ -1021,6 +1040,9 @@ DECL_HANDLER(get_next_device_request) /* we already own the object if it's only on manager queue */ if (irp->file) grab_object( irp ); manager->current_call = irp; + + if (do_esync() && list_empty( &manager->requests )) + esync_clear( manager->esync_fd ); } else close_handle( current->process, reply->next ); } From ad3b4751567a97d367dfeff653b922bcf4aa86a9 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 16:34:56 -0500 Subject: [PATCH 0026/2777] ntdll, server: Implement NtCreateMutant(). Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 16 ++++++++++++++++ dlls/ntdll/unix/esync.h | 3 +++ dlls/ntdll/unix/sync.c | 4 ++++ server/esync.c | 14 ++++++++++++++ 4 files changed, 37 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 2ba0dab5664..fcdd583dea0 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -82,6 +82,13 @@ struct semaphore }; C_ASSERT(sizeof(struct semaphore) == 8); +struct mutex +{ + DWORD tid; + int count; /* recursion count */ +}; +C_ASSERT(sizeof(struct mutex) == 8); + struct event { int signaled; @@ -406,6 +413,15 @@ NTSTATUS esync_reset_event( HANDLE handle ) return STATUS_SUCCESS; } +NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) +{ + TRACE("name %s, initial %d.\n", + attr ? debugstr_us(attr->ObjectName) : "", initial); + + return create_esync( ESYNC_MUTEX, handle, access, attr, initial ? 0 : 1, 0 ); +} + #define TICKSPERSEC 10000000 #define TICKSPERMSEC 10000 diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h index 8480a213b2a..38ebefc9eed 100644 --- a/dlls/ntdll/unix/esync.h +++ b/dlls/ntdll/unix/esync.h @@ -31,6 +31,9 @@ extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, extern NTSTATUS esync_reset_event( HANDLE handle ) DECLSPEC_HIDDEN; extern NTSTATUS esync_set_event( HANDLE handle ) DECLSPEC_HIDDEN; +extern NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) DECLSPEC_HIDDEN; + extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 38ab9b80911..8d21ec9a0ac 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -556,6 +556,10 @@ NTSTATUS WINAPI NtCreateMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT struct object_attributes *objattr; *handle = 0; + + if (do_esync()) + return esync_create_mutex( handle, access, attr, owned ); + if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; SERVER_START_REQ( create_mutex ) diff --git a/server/esync.c b/server/esync.c index 669afbc70d7..3f1c61bc1f0 100644 --- a/server/esync.c +++ b/server/esync.c @@ -202,6 +202,13 @@ struct semaphore }; C_ASSERT(sizeof(struct semaphore) == 8); +struct mutex +{ + DWORD tid; + int count; /* recursion count */ +}; +C_ASSERT(sizeof(struct mutex) == 8); + struct event { int signaled; @@ -272,6 +279,13 @@ struct esync *create_esync( struct object *root, const struct unicode_str *name, event->locked = 0; break; } + case ESYNC_MUTEX: + { + struct mutex *mutex = get_shm( esync->shm_idx ); + mutex->tid = initval ? 0 : current->id; + mutex->count = initval ? 0 : 1; + break; + } default: assert( 0 ); } From 8a19f75a2ef1c4bb76bc6dae95566ddd13f9ddb7 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 16:37:49 -0500 Subject: [PATCH 0027/2777] ntdll: Implement NtReleaseMutant(). Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 34 ++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/esync.h | 1 + dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 38 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index fcdd583dea0..09cfb4c034d 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -422,6 +422,40 @@ NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access, return create_esync( ESYNC_MUTEX, handle, access, attr, initial ? 0 : 1, 0 ); } +NTSTATUS esync_release_mutex( HANDLE *handle, LONG *prev ) +{ + struct esync *obj; + struct mutex *mutex; + static const uint64_t value = 1; + NTSTATUS ret; + + TRACE("%p, %p.\n", handle, prev); + + if ((ret = get_object( handle, &obj ))) return ret; + mutex = obj->shm; + + /* This is thread-safe, because the only thread that can change the tid to + * or from our tid is ours. */ + if (mutex->tid != GetCurrentThreadId()) return STATUS_MUTANT_NOT_OWNED; + + if (prev) *prev = mutex->count; + + mutex->count--; + + if (!mutex->count) + { + /* This is also thread-safe, as long as signaling the file is the last + * thing we do. Other threads don't care about the tid if it isn't + * theirs. */ + mutex->tid = 0; + + if (write( obj->fd, &value, sizeof(value) ) == -1) + return errno_to_status( errno ); + } + + return STATUS_SUCCESS; +} + #define TICKSPERSEC 10000000 #define TICKSPERMSEC 10000 diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h index 38ebefc9eed..e69c46ca462 100644 --- a/dlls/ntdll/unix/esync.h +++ b/dlls/ntdll/unix/esync.h @@ -33,6 +33,7 @@ extern NTSTATUS esync_set_event( HANDLE handle ) DECLSPEC_HIDDEN; extern NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) DECLSPEC_HIDDEN; +extern NTSTATUS esync_release_mutex( HANDLE *handle, LONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 8d21ec9a0ac..1b02f680392 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -609,6 +609,9 @@ NTSTATUS WINAPI NtReleaseMutant( HANDLE handle, LONG *prev_count ) { unsigned int ret; + if (do_esync()) + return esync_release_mutex( handle, prev_count ); + SERVER_START_REQ( release_mutex ) { req->handle = wine_server_obj_handle( handle ); From 695d57edffef25e93eabef0bedffbbe6f3f117b2 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 16:42:13 -0500 Subject: [PATCH 0028/2777] ntdll: Implement waiting on mutexes. Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 09cfb4c034d..7557db26a7f 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -502,7 +502,16 @@ static int do_poll( struct pollfd *fds, nfds_t nfds, ULONGLONG *end ) static void update_grabbed_object( struct esync *obj ) { - if (obj->type == ESYNC_SEMAPHORE) + if (obj->type == ESYNC_MUTEX) + { + struct mutex *mutex = obj->shm; + /* We don't have to worry about a race between this and read(); the + * fact that we grabbed it means the count is now zero, so nobody else + * can (and the only thread that can release it is us). */ + mutex->tid = GetCurrentThreadId(); + mutex->count++; + } + else if (obj->type == ESYNC_SEMAPHORE) { struct semaphore *semaphore = obj->shm; /* We don't have to worry about a race between this and read(); the @@ -588,7 +597,25 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA { for (i = 0; i < count; i++) { - fds[i].fd = objs[i] ? objs[i]->fd : -1; + struct esync *obj = objs[i]; + + if (obj && obj->type == ESYNC_MUTEX) + { + /* If we already own the mutex, return immediately. */ + /* Note: This violates the assumption that the *first* object + * to be signaled will be returned. If that becomes a problem, + * we can always check the state of each object before waiting. */ + struct mutex *mutex = (struct mutex *)obj; + + if (mutex->tid == GetCurrentThreadId()) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + mutex->count++; + return i; + } + } + + fds[i].fd = obj ? obj->fd : -1; fds[i].events = POLLIN; } From b8d0eceff733eb87f33d5e630316f4da60cb7257 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 16:47:38 -0500 Subject: [PATCH 0029/2777] ntdll: Implement wait-all. Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 142 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 129 insertions(+), 13 deletions(-) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 7557db26a7f..893b85fef84 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -542,7 +542,9 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA LONGLONG timeleft; LARGE_INTEGER now; ULONGLONG end; - int i, ret; + int64_t value; + ssize_t size; + int i, j, ret; NtQuerySystemTime( &now ); if (timeout) @@ -637,9 +639,6 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA if (obj) { - int64_t value; - ssize_t size; - if (obj->type == ESYNC_MANUAL_EVENT || obj->type == ESYNC_MANUAL_SERVER || obj->type == ESYNC_QUEUE) @@ -668,22 +667,139 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA * we were waiting for. So keep waiting. */ NtQuerySystemTime( &now ); } - else if (ret == 0) + else + goto err; + } + } + else + { + /* Wait-all is a little trickier to implement correctly. Fortunately, + * it's not as common. + * + * The idea is basically just to wait in sequence on every object in the + * set. Then when we're done, try to grab them all in a tight loop. If + * that fails, release any resources we've grabbed (and yes, we can + * reliably do this—it's just mutexes and semaphores that we have to + * put back, and in both cases we just put back 1), and if any of that + * fails we start over. + * + * What makes this inherently bad is that we might temporarily grab a + * resource incorrectly. Hopefully it'll be quick (and hey, it won't + * block on wineserver) so nobody will notice. Besides, consider: if + * object A becomes signaled but someone grabs it before we can grab it + * and everything else, then they could just as well have grabbed it + * before it became signaled. Similarly if object A was signaled and we + * were blocking on object B, then B becomes available and someone grabs + * A before we can, then they might have grabbed A before B became + * signaled. In either case anyone who tries to wait on A or B will be + * waiting for an instant while we put things back. */ + + while (1) + { +tryagain: + /* First step: try to poll on each object in sequence. */ + fds[0].events = POLLIN; + for (i = 0; i < count; i++) { - TRACE("Wait timed out.\n"); - return STATUS_TIMEOUT; + struct esync *obj = objs[i]; + + fds[0].fd = obj ? obj->fd : -1; + + if (obj && obj->type == ESYNC_MUTEX) + { + /* It might be ours. */ + struct mutex *mutex = obj->shm; + + if (mutex->tid == GetCurrentThreadId()) + continue; + } + + ret = do_poll( fds, 1, timeout ? &end : NULL ); + if (ret <= 0) + goto err; + + if (fds[0].revents & (POLLHUP | POLLERR | POLLNVAL)) + { + ERR("Polling on fd %d returned %#x.\n", fds[0].fd, fds[0].revents); + return STATUS_INVALID_HANDLE; + } } - else + + /* If we got here and we haven't timed out, that means all of the + * handles were signaled. Check to make sure they still are. */ + for (i = 0; i < count; i++) { - ERR("ppoll failed: %s\n", strerror( errno )); - return errno_to_status( errno ); + fds[i].fd = objs[i] ? objs[i]->fd : -1; + fds[i].events = POLLIN; } - } + + /* Poll everything to see if they're still signaled. */ + ret = poll( fds, count, 0 ); + if (ret == count) + { + /* Quick, grab everything. */ + for (i = 0; i < count; i++) + { + struct esync *obj = objs[i]; + + switch (obj->type) + { + case ESYNC_MUTEX: + { + struct mutex *mutex = obj->shm; + if (mutex->tid == GetCurrentThreadId()) + break; + /* otherwise fall through */ + } + case ESYNC_SEMAPHORE: + case ESYNC_AUTO_EVENT: + if ((size = read( fds[i].fd, &value, sizeof(value) )) != sizeof(value)) + { + /* We were too slow. Put everything back. */ + value = 1; + for (j = i; j >= 0; j--) + { + if (write( obj->fd, &value, sizeof(value) ) == -1) + return errno_to_status( errno ); + } + + goto tryagain; /* break out of two loops and a switch */ + } + break; + default: + /* If a manual-reset event changed between there and + * here, it's shouldn't be a problem. */ + break; + } + } + + /* If we got here, we successfully waited on every object. */ + /* Make sure to let ourselves know that we grabbed the mutexes + * and semaphores. */ + for (i = 0; i < count; i++) + update_grabbed_object( objs[i] ); + + TRACE("Wait successful.\n"); + return STATUS_SUCCESS; + } + + /* If we got here, ppoll() returned less than all of our objects. + * So loop back to the beginning and try again. */ + } /* while(1) */ + } /* else (wait-all) */ + +err: + /* We should only get here if poll() failed. */ + + if (ret == 0) + { + TRACE("Wait timed out.\n"); + return STATUS_TIMEOUT; } else { - FIXME("Wait-all not implemented.\n"); - return STATUS_NOT_IMPLEMENTED; + ERR("ppoll failed: %s\n", strerror(errno)); + return errno_to_status( errno ); } } From b72c6451a9039da66bb1f000a0d16d2fe91812f5 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 9 Jun 2018 22:44:57 -0500 Subject: [PATCH 0030/2777] esync: Add a README. Wine-Staging: eventfd_synchronization --- README.esync | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 README.esync diff --git a/README.esync b/README.esync new file mode 100644 index 00000000000..8fcb969011b --- /dev/null +++ b/README.esync @@ -0,0 +1,184 @@ +This is eventfd-based synchronization, or 'esync' for short. Turn it on with +WINEESYNC=1 (note that it checks the presence and not the value); debug it +with +esync. + +The aim is to execute all synchronization operations in "user-space", that is, +without going through wineserver. We do this using Linux's eventfd +facility. The main impetus to using eventfd is so that we can poll multiple +objects at once; in particular we can't do this with futexes, or pthread +semaphores, or the like. The only way I know of to wait on any of multiple +objects is to use select/poll/epoll to wait on multiple fds, and eventfd gives +us those fds in a quite usable way. + +Whenever a semaphore, event, or mutex is created, we have the server, instead +of creating a traditional server-side event/semaphore/mutex, instead create an +'esync' primitive. These live in esync.c and are very slim objects; in fact, +they don't even know what type of primitive they are. The server is involved +at all because we still need a way of creating named objects, passing handles +to another process, etc. + +The server creates an eventfd file descriptor with the requested parameters +and passes it back to ntdll. ntdll creates an object of the appropriate type, +then caches it in a table. This table is copied almost wholesale from the fd +cache code in server.c. + +Specific operations follow quite straightforwardly from eventfd: + +* To release an object, or set an event, we simply write() to it. +* An object is signalled if read() succeeds on it. Notably, we create all + eventfd descriptors with O_NONBLOCK, so that we can atomically check if an + object is signalled and grab it if it is. This also lets us reset events. +* For objects whose state should not be reset upon waiting—e.g. manual-reset + events—we simply check for the POLLIN flag instead of reading. +* Semaphores are handled by the EFD_SEMAPHORE flag. This matches up quite well + (although with some difficulties; see below). +* Mutexes store their owner thread locally. This isn't reliable information if + a different process's thread owns the mutex, but this doesn't matter—a + thread should only care whether it owns the mutex, so it knows whether to + try waiting on it or simply to increase the recursion count. + +The interesting part about esync is that (almost) all waits happen in ntdll, +including those on server-bound objects. The idea here is that on the server +side, for any waitable object, we create an eventfd file descriptor (not an +esync primitive), and then pass it to ntdll if the program tries to wait on +it. These are cached too, so only the first wait will require a round trip to +the server. Then the server signals the file descriptor as appropriate, and +thereby wakes up the client. So far this is implemented for processes, +threads, message queues (difficult; see below), and device managers (necessary +for drivers to work). All of these are necessarily server-bound, so we +wouldn't really gain anything by signalling on the client side instead. Of +course, except possibly for message queues, it's not likely that any program +(cutting-edge D3D game or not) is going to be causing a great wineserver load +by waiting on any of these objects; the motivation was rather to provide a way +to wait on ntdll-bound and server-bound objects at the same time. + +Some cases are still passed to the server, and there's probably no reason not +to keep them that way. Those that I noticed while testing include: async +objects, which are internal to the file APIs and never exposed to userspace, +startup_info objects, which are internal to the loader and signalled when a +process starts, and keyed events, which are exposed through an ntdll API +(although not through kernel32) but can't be mixed with other objects (you +have to use NtWaitForKeyedEvent()). Other cases include: named pipes, debug +events, sockets, and timers. It's unlikely we'll want to optimize debug events +or sockets (or any of the other, rather rare, objects), but it is possible +we'll want to optimize named pipes or timers. + +There were two sort of complications when working out the above. The first one +was events. The trouble is that (1) the server actually creates some events by +itself and (2) the server sometimes manipulates events passed by the +client. Resolving the first case was easy enough, and merely entailed creating +eventfd descriptors for the events the same way as for processes and threads +(note that we don't really lose anything this way; the events include +"LowMemoryCondition" and the event that signals system processes to shut +down). For the second case I basically had to hook the server-side event +functions to redirect to esync versions if the event was actually an esync +primitive. + +The second complication was message queues. The difficulty here is that X11 +signals events by writing into a pipe (at least I think it's a pipe?), and so +as a result wineserver has to poll on that descriptor. In theory we could just +let wineserver do so and then signal us as appropriate, except that wineserver +only polls on the pipe when the thread is waiting for events (otherwise we'd +get e.g. keyboard input while the thread is doing something else, and spin +forever trying to wake up a thread that doesn't care). The obvious solution is +just to poll on that fd ourselves, and that's what I did—it's just that +getting the fd from wineserver was kind of ugly, and the code for waiting was +also kind of ugly basically because we have to wait on both X11's fd and the +"normal" process/thread-style wineserver fd that we use to signal sent +messages. The upshot about the whole thing was that races are basically +impossible, since a thread can only wait on its own queue. + +I had kind of figured that APCs just wouldn't work, but then poll() spat EINTR +at me and I realized that this wasn't necessarily true. It seems that the +server will suspend a thread when trying to deliver a system APC to a thread +that's not waiting, and since the server has no idea that we're waiting it +just suspends us. This of course interrupts poll(), which complains at us, and +it turns out that just returning STATUS_USER_APC in that case is enough to +make rpcrt4 happy. + +There are a couple things that this infrastructure can't handle, although +surprisingly there aren't that many. In particular: +* We can't return the previous count on a semaphore, since we have no way to + query the count on a semaphore through eventfd. Currently the code lies and + returns 1 every time. We can make this work (in a single process, or [if + necessary] in multiple processes through shared memory) by keeping a count + locally. We can't guarantee that it's the exact count at the moment the + semaphore was released, but I guess any program that runs into that race + shouldn't be depending on that fact anyway. +* Similarly, we can't enforce the maximum count on a semaphore, since we have + no way to get the current count and subsequently compare it with the + maximum. +* We can't use NtQueryMutant to get the mutant's owner or count if it lives in + a different process. If necessary we can use shared memory to make this + work, I guess, but see below. +* User APCs don't work. However, it's not impossible to make them work; in + particular I think this could be relatively easily implemented by waiting on + another internal file descriptor when we execute an alertable wait. +* Implementing wait-all, i.e. WaitForMultipleObjects(..., TRUE, ...), is not + exactly possible the way we'd like it to be possible. In theory that + function should wait until it knows all objects are available, then grab + them all at once atomically. The server (like the kernel) can do this + because the server is single-threaded and can't race with itself. We can't + do this in ntdll, though. The approach I've taken I've laid out in great + detail in the relevant patch, but for a quick summary we poll on each object + until it's signaled (but don't grab it), check them all again, and if + they're all signaled we try to grab them all at once in a tight loop, and if + we fail on any of them we reset the count on whatever we shouldn't have + consumed. Such a blip would necessarily be very quick. +* The whole patchset only works on Linux, where eventfd is available. However, + it should be possible to make it work on a Mac, since eventfd is just a + quicker, easier way to use pipes (i.e. instead of writing 1 to the fd you'd + write 1 byte; instead of reading a 64-bit value from the fd you'd read as + many bytes as you can carry, which is admittedly less than 2**64 but + can probably be something reasonable.) It's also possible, although I + haven't yet looked, to use some different kind of synchronization + primitives, but pipes would be easiest to tack onto this framework. +* We might hit the maximum number of open fd's. On my system the soft limit is + 1024 and the hard limit is 1048576. I'm inclined to hope this won't be an + issue, since a hypothetical Linux port of any application might just as well + use the same number of eventfds. +* PulseEvent() can't work the way it's supposed to work. Fortunately it's rare + and deprecated. It's also explicitly mentioned on MSDN that a thread can + miss the notification for a kernel APC, so in a sense we're not necessarily + doing anything wrong. + +There are some things that are perfectly implementable but that I just haven't +done yet: +* NtOpen* (aka Open*). This is just a matter of adding another open_esync + request analogous to those for other server primitives. +* NtQuery*. This can be done to some degree (the difficulties are outlined + above). That said, these APIs aren't exposed through kernel32 in any way, so + I doubt anyone is going to be using them. +* SignalObjectAndWait(). The server combines this into a single operation, but + according to MSDN it doesn't need to be atomic, so we can just signal the + appropriate object and wait, and woe betide anyone who gets in the way of + those two operations. +* Other synchronizable server primitives. It's unlikely we'll need any of + these, except perhaps named pipes (which would honestly be rather difficult) + and (maybe) timers. + +This patchset was inspired by Daniel Santos' "hybrid synchronization" +patchset. My idea was to create a framework whereby even contended waits could +be executed in userspace, eliminating a lot of the complexity that his +synchronization primitives used. I do however owe some significant gratitude +toward him for setting me on the right path. + +I've tried to maximize code separation, both to make any potential rebases +easier and to ensure that esync is only active when configured. All code in +existing source files is guarded with "if (do_esync())", and generally that +condition is followed by "return esync_version_of_this_method(...);", where +the latter lives in esync.c and is declared in esync.h. I've also tried to +make the patchset very clear and readable—to write it as if I were going to +submit it upstream. (Some intermediate patches do break things, which Wine is +generally against, but I think it's for the better in this case.) I have cut +some corners, though; there is some error checking missing, or implicit +assumptions that the program is behaving correctly. + +I've tried to be careful about races. There are a lot of comments whose +purpose are basically to assure me that races are impossible. In most cases we +don't have to worry about races since all of the low-level synchronization is +done by the kernel. + +Anyway, yeah, this is esync. Use it if you like. + +--Zebediah Figura \ No newline at end of file From 7adcbf80514147949355b253b9ef42757377f404 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 16:52:39 -0500 Subject: [PATCH 0031/2777] ntdll: Implement NtSignalAndWaitForSingleObject(). Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 28 ++++++++++++++++++++++++++++ dlls/ntdll/unix/esync.h | 2 ++ dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 33 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 893b85fef84..07b2c853100 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -841,6 +841,34 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an return ret; } +NTSTATUS esync_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable, + const LARGE_INTEGER *timeout ) +{ + struct esync *obj; + NTSTATUS ret; + + if ((ret = get_object( signal, &obj ))) return ret; + + switch (obj->type) + { + case ESYNC_SEMAPHORE: + ret = esync_release_semaphore( signal, 1, NULL ); + break; + case ESYNC_AUTO_EVENT: + case ESYNC_MANUAL_EVENT: + ret = esync_set_event( signal ); + break; + case ESYNC_MUTEX: + ret = esync_release_mutex( signal, NULL ); + break; + default: + return STATUS_OBJECT_TYPE_MISMATCH; + } + if (ret) return ret; + + return esync_wait_objects( 1, &wait, TRUE, alertable, timeout ); +} + void esync_init(void) { struct stat st; diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h index e69c46ca462..bee08ff857f 100644 --- a/dlls/ntdll/unix/esync.h +++ b/dlls/ntdll/unix/esync.h @@ -37,6 +37,8 @@ extern NTSTATUS esync_release_mutex( HANDLE *handle, LONG *prev ) DECLSPEC_HIDDE extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; +extern NTSTATUS esync_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable, + const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; /* We have to synchronize on the fd cache mutex so that our calls to receive_fd diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 1b02f680392..e1594512c8b 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -1480,6 +1480,9 @@ NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE signal, HANDLE wait, select_op_t select_op; UINT flags = SELECT_INTERRUPTIBLE; + if (do_esync()) + return esync_signal_and_wait( signal, wait, alertable, timeout ); + if (!signal) return STATUS_INVALID_HANDLE; if (alertable) flags |= SELECT_ALERTABLE; From 2e0604eb6b49f606ea8de7e9b78fb41aed93ffc4 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 16:56:09 -0500 Subject: [PATCH 0032/2777] ntdll: Implement NtOpenSemaphore(). Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 47 +++++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/esync.h | 2 ++ dlls/ntdll/unix/sync.c | 4 ++++ server/esync.c | 31 +++++++++++++++++++++++++++ server/protocol.def | 12 +++++++++++ 5 files changed, 96 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 07b2c853100..c09e0bb02d7 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -327,6 +327,45 @@ static NTSTATUS create_esync( enum esync_type type, HANDLE *handle, ACCESS_MASK return ret; } +static NTSTATUS open_esync( enum esync_type type, HANDLE *handle, + ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) +{ + NTSTATUS ret; + obj_handle_t fd_handle; + unsigned int shm_idx; + sigset_t sigset; + int fd; + + server_enter_uninterrupted_section( &fd_cache_mutex, &sigset ); + SERVER_START_REQ( open_esync ) + { + req->access = access; + req->attributes = attr->Attributes; + req->rootdir = wine_server_obj_handle( attr->RootDirectory ); + req->type = type; + if (attr->ObjectName) + wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length ); + if (!(ret = wine_server_call( req ))) + { + *handle = wine_server_ptr_handle( reply->handle ); + type = reply->type; + shm_idx = reply->shm_idx; + fd = receive_fd( &fd_handle ); + assert( wine_server_ptr_handle(fd_handle) == *handle ); + } + } + SERVER_END_REQ; + server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); + + if (!ret) + { + add_to_list( *handle, type, fd, shm_idx ? get_shm( shm_idx ) : 0 ); + + TRACE("-> handle %p, fd %d.\n", *handle, fd); + } + return ret; +} + extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) { @@ -336,6 +375,14 @@ extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, return create_esync( ESYNC_SEMAPHORE, handle, access, attr, initial, max ); } +NTSTATUS esync_open_semaphore( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ) +{ + TRACE("name %s.\n", debugstr_us(attr->ObjectName)); + + return open_esync( ESYNC_SEMAPHORE, handle, access, attr ); +} + NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) { struct esync *obj; diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h index bee08ff857f..2738e8b7f87 100644 --- a/dlls/ntdll/unix/esync.h +++ b/dlls/ntdll/unix/esync.h @@ -24,6 +24,8 @@ extern NTSTATUS esync_close( HANDLE handle ) DECLSPEC_HIDDEN; extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN; +extern NTSTATUS esync_open_semaphore( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index e1594512c8b..88d0a472e75 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -301,6 +301,10 @@ NTSTATUS WINAPI NtOpenSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJEC unsigned int ret; *handle = 0; + + if (do_esync()) + return esync_open_semaphore( handle, access, attr ); + if ((ret = validate_open_object_attributes( attr ))) return ret; SERVER_START_REQ( open_semaphore ) diff --git a/server/esync.c b/server/esync.c index 3f1c61bc1f0..eca9b6aa67d 100644 --- a/server/esync.c +++ b/server/esync.c @@ -410,6 +410,37 @@ DECL_HANDLER(create_esync) if (root) release_object( root ); } +DECL_HANDLER(open_esync) +{ + struct unicode_str name = get_req_unicode_str(); + + reply->handle = open_object( current->process, req->rootdir, req->access, + &esync_ops, &name, req->attributes ); + + /* send over the fd */ + if (reply->handle) + { + struct esync *esync; + + if (!(esync = (struct esync *)get_handle_obj( current->process, reply->handle, + 0, &esync_ops ))) + return; + + if (!type_matches( req->type, esync->type )) + { + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + release_object( esync ); + return; + } + + reply->type = esync->type; + reply->shm_idx = esync->shm_idx; + + send_client_fd( current->process, esync->fd, reply->handle ); + release_object( esync ); + } +} + /* Retrieve a file descriptor for an esync object which will be signaled by the * server. The client should only read from (i.e. wait on) this object. */ DECL_HANDLER(get_esync_fd) diff --git a/server/protocol.def b/server/protocol.def index 894b0565aea..c6f1d58aaa5 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3811,6 +3811,18 @@ enum esync_type unsigned int shm_idx; @END +@REQ(open_esync) + unsigned int access; /* wanted access rights */ + unsigned int attributes; /* object attributes */ + obj_handle_t rootdir; /* root directory */ + int type; /* type of esync object (above) */ + VARARG(name,unicode_str); /* object name */ +@REPLY + obj_handle_t handle; /* handle to the event */ + int type; /* type of esync object (above) */ + unsigned int shm_idx; /* this object's index into the shm section */ +@END + /* Retrieve the esync fd for an object. */ @REQ(get_esync_fd) obj_handle_t handle; /* handle to the object */ From eaf49660671777b3afa90e675217c8193fcc2065 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 16:58:19 -0500 Subject: [PATCH 0033/2777] ntdll: Implement NtOpenEvent(). Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 8 ++++++++ dlls/ntdll/unix/esync.h | 2 ++ dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 13 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index c09e0bb02d7..73f27fb1905 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -428,6 +428,14 @@ NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, return create_esync( type, handle, access, attr, initial, 0 ); } +NTSTATUS esync_open_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ) +{ + TRACE("name %s.\n", debugstr_us(attr->ObjectName)); + + return open_esync( ESYNC_AUTO_EVENT, handle, access, attr ); /* doesn't matter which */ +} + NTSTATUS esync_set_event( HANDLE handle ) { static const uint64_t value = 1; diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h index 2738e8b7f87..da1b72d4413 100644 --- a/dlls/ntdll/unix/esync.h +++ b/dlls/ntdll/unix/esync.h @@ -30,6 +30,8 @@ extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN; +extern NTSTATUS esync_open_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; extern NTSTATUS esync_reset_event( HANDLE handle ) DECLSPEC_HIDDEN; extern NTSTATUS esync_set_event( HANDLE handle ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 88d0a472e75..f9df7c4d60f 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -424,6 +424,9 @@ NTSTATUS WINAPI NtOpenEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_AT *handle = 0; if ((ret = validate_open_object_attributes( attr ))) return ret; + if (do_esync()) + return esync_open_event( handle, access, attr ); + SERVER_START_REQ( open_event ) { req->access = access; From 3c48f0c0b9530ec5934388a18057ddb4a1e629b3 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 16:59:35 -0500 Subject: [PATCH 0034/2777] ntdll: Implement NtOpenMutant(). Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 8 ++++++++ dlls/ntdll/unix/esync.h | 2 ++ dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 13 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 73f27fb1905..d533a701782 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -477,6 +477,14 @@ NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access, return create_esync( ESYNC_MUTEX, handle, access, attr, initial ? 0 : 1, 0 ); } +NTSTATUS esync_open_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ) +{ + TRACE("name %s.\n", debugstr_us(attr->ObjectName)); + + return open_esync( ESYNC_MUTEX, handle, access, attr ); +} + NTSTATUS esync_release_mutex( HANDLE *handle, LONG *prev ) { struct esync *obj; diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h index da1b72d4413..cb48e2cd022 100644 --- a/dlls/ntdll/unix/esync.h +++ b/dlls/ntdll/unix/esync.h @@ -37,6 +37,8 @@ extern NTSTATUS esync_set_event( HANDLE handle ) DECLSPEC_HIDDEN; extern NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) DECLSPEC_HIDDEN; +extern NTSTATUS esync_open_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; extern NTSTATUS esync_release_mutex( HANDLE *handle, LONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index f9df7c4d60f..4c896b6cfd4 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -594,6 +594,9 @@ NTSTATUS WINAPI NtOpenMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT_A *handle = 0; if ((ret = validate_open_object_attributes( attr ))) return ret; + if (do_esync()) + return esync_open_mutex( handle, access, attr ); + SERVER_START_REQ( open_mutex ) { req->access = access; From c6d46397054d0921bcb20b27dee7335b0b54d773 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 10 Jun 2018 19:08:18 -0500 Subject: [PATCH 0035/2777] server: Implement esync_map_access(). Wine-Staging: eventfd_synchronization --- server/esync.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/server/esync.c b/server/esync.c index eca9b6aa67d..3a334b3b330 100644 --- a/server/esync.c +++ b/server/esync.c @@ -112,6 +112,7 @@ struct esync }; static void esync_dump( struct object *obj, int verbose ); +static unsigned int esync_map_access( struct object *obj, unsigned int access ); static void esync_destroy( struct object *obj ); const struct object_ops esync_ops = @@ -126,7 +127,7 @@ const struct object_ops esync_ops = NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ - default_map_access, /* map_access */ + esync_map_access, /* map_access */ default_get_sd, /* get_sd */ default_set_sd, /* set_sd */ default_get_full_name, /* get_full_name */ @@ -146,6 +147,16 @@ static void esync_dump( struct object *obj, int verbose ) fprintf( stderr, "esync fd=%d\n", esync->fd ); } +static unsigned int esync_map_access( struct object *obj, unsigned int access ) +{ + /* Sync objects have the same flags. */ + if (access & GENERIC_READ) access |= STANDARD_RIGHTS_READ | EVENT_QUERY_STATE; + if (access & GENERIC_WRITE) access |= STANDARD_RIGHTS_WRITE | EVENT_MODIFY_STATE; + if (access & GENERIC_EXECUTE) access |= STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE; + if (access & GENERIC_ALL) access |= STANDARD_RIGHTS_ALL | EVENT_QUERY_STATE | EVENT_MODIFY_STATE; + return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); +} + static void esync_destroy( struct object *obj ) { struct esync *esync = (struct esync *)obj; From 556ce9889d63632bb5b6acce144847b386fe1994 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 17:03:05 -0500 Subject: [PATCH 0036/2777] server: Implement NtDuplicateObject(). Wine-Staging: eventfd_synchronization --- server/esync.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/server/esync.c b/server/esync.c index 3a334b3b330..c5587bef6cf 100644 --- a/server/esync.c +++ b/server/esync.c @@ -112,6 +112,7 @@ struct esync }; static void esync_dump( struct object *obj, int verbose ); +static int esync_get_esync_fd( struct object *obj, enum esync_type *type ); static unsigned int esync_map_access( struct object *obj, unsigned int access ); static void esync_destroy( struct object *obj ); @@ -123,7 +124,7 @@ const struct object_ops esync_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ - NULL, /* get_esync_fd */ + esync_get_esync_fd, /* get_esync_fd */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -147,6 +148,13 @@ static void esync_dump( struct object *obj, int verbose ) fprintf( stderr, "esync fd=%d\n", esync->fd ); } +static int esync_get_esync_fd( struct object *obj, enum esync_type *type ) +{ + struct esync *esync = (struct esync *)obj; + *type = esync->type; + return esync->fd; +} + static unsigned int esync_map_access( struct object *obj, unsigned int access ) { /* Sync objects have the same flags. */ From 0460902786a41c9cee10ac99597397f96507204e Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 15 Jun 2018 11:01:44 -0500 Subject: [PATCH 0037/2777] server: Create eventfd descriptors for timers. Wine-Staging: eventfd_synchronization --- server/timer.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/server/timer.c b/server/timer.c index f59902d5607..36645a2a8d2 100644 --- a/server/timer.c +++ b/server/timer.c @@ -35,6 +35,7 @@ #include "file.h" #include "handle.h" #include "request.h" +#include "esync.h" static const WCHAR timer_name[] = {'T','i','m','e','r'}; @@ -61,10 +62,12 @@ struct timer struct thread *thread; /* thread that set the APC function */ client_ptr_t callback; /* callback APC function */ client_ptr_t arg; /* callback argument */ + int esync_fd; /* esync file descriptor */ }; static void timer_dump( struct object *obj, int verbose ); static int timer_signaled( struct object *obj, struct wait_queue_entry *entry ); +static int timer_get_esync_fd( struct object *obj, enum esync_type *type ); static void timer_satisfied( struct object *obj, struct wait_queue_entry *entry ); static void timer_destroy( struct object *obj ); @@ -76,7 +79,7 @@ static const struct object_ops timer_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ timer_signaled, /* signaled */ - NULL, /* get_esync_fd */ + timer_get_esync_fd, /* get_esync_fd */ timer_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -111,6 +114,10 @@ static struct timer *create_timer( struct object *root, const struct unicode_str timer->period = 0; timer->timeout = NULL; timer->thread = NULL; + timer->esync_fd = -1; + + if (do_esync()) + timer->esync_fd = esync_create_fd( 0, 0 ); } } return timer; @@ -182,6 +189,9 @@ static int set_timer( struct timer *timer, timeout_t expire, unsigned int period { period = 0; /* period doesn't make any sense for a manual timer */ timer->signaled = 0; + + if (do_esync()) + esync_clear( timer->esync_fd ); } timer->when = (expire <= 0) ? expire - monotonic_time : max( expire, current_time ); timer->period = period; @@ -209,6 +219,13 @@ static int timer_signaled( struct object *obj, struct wait_queue_entry *entry ) return timer->signaled; } +static int timer_get_esync_fd( struct object *obj, enum esync_type *type ) +{ + struct timer *timer = (struct timer *)obj; + *type = timer->manual ? ESYNC_MANUAL_SERVER : ESYNC_AUTO_SERVER; + return timer->esync_fd; +} + static void timer_satisfied( struct object *obj, struct wait_queue_entry *entry ) { struct timer *timer = (struct timer *)obj; @@ -223,6 +240,7 @@ static void timer_destroy( struct object *obj ) if (timer->timeout) remove_timeout_user( timer->timeout ); if (timer->thread) release_object( timer->thread ); + if (do_esync()) close( timer->esync_fd ); } /* create a timer */ From 47d5d364c471e16da115b5f20fbcd71e70204ca5 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 17:17:31 -0500 Subject: [PATCH 0038/2777] ntdll, server: Implement alertable waits. Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 77 +++++++++++++++++++++++++++++++--- dlls/ntdll/unix/unix_private.h | 1 + dlls/ntdll/unix/virtual.c | 1 + server/esync.c | 20 +++++++-- server/esync.h | 1 + server/protocol.def | 4 ++ server/thread.c | 13 ++++++ server/thread.h | 1 + 8 files changed, 109 insertions(+), 9 deletions(-) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index d533a701782..381d4ff7b6c 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -598,17 +598,42 @@ static void update_grabbed_object( struct esync *obj ) static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) { + static const LARGE_INTEGER zero; + struct esync *objs[MAXIMUM_WAIT_OBJECTS]; - struct pollfd fds[MAXIMUM_WAIT_OBJECTS]; + struct pollfd fds[MAXIMUM_WAIT_OBJECTS + 1]; int has_esync = 0, has_server = 0; BOOL msgwait = FALSE; LONGLONG timeleft; LARGE_INTEGER now; + DWORD pollcount; ULONGLONG end; int64_t value; ssize_t size; int i, j, ret; + /* Grab the APC fd if we don't already have it. */ + if (alertable && ntdll_get_thread_data()->esync_apc_fd == -1) + { + obj_handle_t fd_handle; + sigset_t sigset; + int fd = -1; + + server_enter_uninterrupted_section( &fd_cache_mutex, &sigset ); + SERVER_START_REQ( get_esync_apc_fd ) + { + if (!(ret = wine_server_call( req ))) + { + fd = receive_fd( &fd_handle ); + assert( fd_handle == GetCurrentThreadId() ); + } + } + SERVER_END_REQ; + server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); + + ntdll_get_thread_data()->esync_apc_fd = fd; + } + NtQuerySystemTime( &now ); if (timeout) { @@ -647,6 +672,8 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA if (msgwait) TRACE(" or driver events"); + if (alertable) + TRACE(", alertable"); if (!timeout) TRACE(", timeout = INFINITE.\n"); @@ -683,12 +710,27 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA fds[i].fd = obj ? obj->fd : -1; fds[i].events = POLLIN; } + if (alertable) + { + fds[i].fd = ntdll_get_thread_data()->esync_apc_fd; + fds[i].events = POLLIN; + i++; + } + pollcount = i; while (1) { - ret = do_poll( fds, count, timeout ? &end : NULL ); + ret = do_poll( fds, pollcount, timeout ? &end : NULL ); if (ret > 0) { + /* We must check this first! The server may set an event that + * we're waiting on, but we need to return STATUS_USER_APC. */ + if (alertable) + { + if (fds[pollcount - 1].revents & POLLIN) + goto userapc; + } + /* Find out which object triggered the wait. */ for (i = 0; i < count; i++) { @@ -762,6 +804,14 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA tryagain: /* First step: try to poll on each object in sequence. */ fds[0].events = POLLIN; + pollcount = 1; + if (alertable) + { + /* We also need to wait on APCs. */ + fds[1].fd = ntdll_get_thread_data()->esync_apc_fd; + fds[1].events = POLLIN; + pollcount++; + } for (i = 0; i < count; i++) { struct esync *obj = objs[i]; @@ -777,9 +827,11 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA continue; } - ret = do_poll( fds, 1, timeout ? &end : NULL ); + ret = do_poll( fds, pollcount, timeout ? &end : NULL ); if (ret <= 0) goto err; + else if (alertable && (fds[1].revents & POLLIN)) + goto userapc; if (fds[0].revents & (POLLHUP | POLLERR | POLLNVAL)) { @@ -795,10 +847,12 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA fds[i].fd = objs[i] ? objs[i]->fd : -1; fds[i].events = POLLIN; } + /* There's no reason to check for APCs here. */ + pollcount = i; /* Poll everything to see if they're still signaled. */ - ret = poll( fds, count, 0 ); - if (ret == count) + ret = poll( fds, pollcount, 0 ); + if (ret == pollcount) { /* Quick, grab everything. */ for (i = 0; i < count; i++) @@ -864,6 +918,19 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA ERR("ppoll failed: %s\n", strerror(errno)); return errno_to_status( errno ); } + +userapc: + TRACE("Woken up by user APC.\n"); + + /* We have to make a server call anyway to get the APC to execute, so just + * delegate down to server_select(). */ + ret = server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, &zero ); + + /* This can happen if we received a system APC, and the APC fd was woken up + * before we got SIGUSR1. poll() doesn't return EINTR in that case. The + * right thing to do seems to be to return STATUS_USER_APC anyway. */ + if (ret == STATUS_TIMEOUT) ret = STATUS_USER_APC; + return ret; } /* We need to let the server know when we are doing a message wait, and when we diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 8821cd78491..347d1dd6102 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -58,6 +58,7 @@ struct ntdll_thread_data { void *cpu_data[16]; /* reserved for CPU-specific data */ void *kernel_stack; /* stack for thread startup and kernel syscalls */ + int esync_apc_fd; /* fd to wait on for user APCs */ int request_fd; /* fd for sending server requests */ int reply_fd; /* fd for receiving server replies */ int wait_fd[2]; /* fd for sleeping server requests */ diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 0f66429fc9d..121eacc06c7 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -2937,6 +2937,7 @@ static TEB *init_teb( void *ptr, BOOL is_wow ) teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; + thread_data->esync_apc_fd = -1; thread_data->request_fd = -1; thread_data->reply_fd = -1; thread_data->wait_fd[0] = -1; diff --git a/server/esync.c b/server/esync.c index c5587bef6cf..0c365006f0b 100644 --- a/server/esync.c +++ b/server/esync.c @@ -346,19 +346,25 @@ int esync_create_fd( int initval, int flags ) #endif } +/* Wake up a specific fd. */ +void esync_wake_fd( int fd ) +{ + static const uint64_t value = 1; + + if (write( fd, &value, sizeof(value) ) == -1) + perror( "esync: write" ); +} + /* Wake up a server-side esync object. */ void esync_wake_up( struct object *obj ) { - static const uint64_t value = 1; enum esync_type dummy; int fd; if (obj->ops->get_esync_fd) { fd = obj->ops->get_esync_fd( obj, &dummy ); - - if (write( fd, &value, sizeof(value) ) == -1) - perror( "esync: write" ); + esync_wake_fd( fd ); } } @@ -496,3 +502,9 @@ DECL_HANDLER(get_esync_fd) release_object( obj ); } + +/* Return the fd used for waiting on user APCs. */ +DECL_HANDLER(get_esync_apc_fd) +{ + send_client_fd( current->process, current->esync_apc_fd, current->id ); +} diff --git a/server/esync.h b/server/esync.h index 689d8569b73..e1588d205d9 100644 --- a/server/esync.h +++ b/server/esync.h @@ -23,6 +23,7 @@ extern int do_esync(void); void esync_init(void); int esync_create_fd( int initval, int flags ); +void esync_wake_fd( int fd ); void esync_wake_up( struct object *obj ); void esync_clear( int fd ); diff --git a/server/protocol.def b/server/protocol.def index c6f1d58aaa5..c512491a673 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3835,3 +3835,7 @@ enum esync_type @REQ(esync_msgwait) int in_msgwait; /* are we in a message wait? */ @END + +/* Retrieve the fd to wait on for user APCs. */ +@REQ(get_esync_apc_fd) +@END diff --git a/server/thread.c b/server/thread.c index 6c9fe2983ec..c41b42fb478 100644 --- a/server/thread.c +++ b/server/thread.c @@ -235,6 +235,7 @@ static inline void init_thread_structure( struct thread *thread ) thread->teb = 0; thread->entry_point = 0; thread->esync_fd = -1; + thread->esync_apc_fd = -1; thread->system_regs = 0; thread->queue = NULL; thread->wait = NULL; @@ -383,7 +384,10 @@ struct thread *create_thread( int fd, struct process *process, const struct secu } if (do_esync()) + { thread->esync_fd = esync_create_fd( 0, 0 ); + thread->esync_apc_fd = esync_create_fd( 0, 0 ); + } set_fd_events( thread->request_fd, POLLIN ); /* start listening to events */ add_process_thread( thread->process, thread ); @@ -1168,8 +1172,13 @@ static int queue_apc( struct process *process, struct thread *thread, struct thr grab_object( apc ); list_add_tail( queue, &apc->entry ); if (!list_prev( queue, &apc->entry )) /* first one */ + { wake_thread( thread ); + if (do_esync() && queue == &thread->user_apc) + esync_wake_fd( thread->esync_apc_fd ); + } + return 1; } @@ -1215,6 +1224,10 @@ static struct thread_apc *thread_dequeue_apc( struct thread *thread, int system apc = LIST_ENTRY( ptr, struct thread_apc, entry ); list_remove( ptr ); } + + if (do_esync() && list_empty( &thread->system_apc ) && list_empty( &thread->user_apc )) + esync_clear( thread->esync_apc_fd ); + return apc; } diff --git a/server/thread.h b/server/thread.h index d4b16d1aba0..c7b58c3d63b 100644 --- a/server/thread.h +++ b/server/thread.h @@ -55,6 +55,7 @@ struct thread thread_id_t id; /* thread id */ struct list mutex_list; /* list of currently owned mutexes */ int esync_fd; /* esync file descriptor (signalled on exit) */ + int esync_apc_fd; /* esync apc fd (signalled when APCs are present) */ unsigned int system_regs; /* which system regs have been set */ struct msg_queue *queue; /* message queue */ struct thread_wait *wait; /* current wait condition if sleeping */ From bbc0a94f58e15481d4dc835763de777f7e8f3ca9 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 10 Jun 2018 13:53:08 -0500 Subject: [PATCH 0039/2777] esync: Update README. Wine-Staging: eventfd_synchronization --- README.esync | 48 +++++++++++++++++------------------------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/README.esync b/README.esync index 8fcb969011b..627cc3f481e 100644 --- a/README.esync +++ b/README.esync @@ -88,32 +88,23 @@ also kind of ugly basically because we have to wait on both X11's fd and the messages. The upshot about the whole thing was that races are basically impossible, since a thread can only wait on its own queue. -I had kind of figured that APCs just wouldn't work, but then poll() spat EINTR -at me and I realized that this wasn't necessarily true. It seems that the -server will suspend a thread when trying to deliver a system APC to a thread -that's not waiting, and since the server has no idea that we're waiting it -just suspends us. This of course interrupts poll(), which complains at us, and -it turns out that just returning STATUS_USER_APC in that case is enough to -make rpcrt4 happy. +System APCs already work, since the server will forcibly suspend a thread if +it's not already waiting, and so we just need to check for EINTR from +poll(). User APCs and alertable waits are implemented in a similar style to +message queues (well, sort of): whenever someone executes an alertable wait, +we add an additional eventfd to the list, which the server signals when an APC +arrives. If that eventfd gets signaled, we hand it off to the server to take +care of, and return STATUS_USER_APC. + +Originally I kept the volatile state of semaphores and mutexes inside a +variable local to the handle, with the knowledge that this would break if +someone tried to open the handle elsewhere or duplicate it. It did, and so now +this state is stored inside shared memory. This is of the POSIX variety, is +allocated by the server (but never mapped there) and lives under the path +"/wine-esync". There are a couple things that this infrastructure can't handle, although surprisingly there aren't that many. In particular: -* We can't return the previous count on a semaphore, since we have no way to - query the count on a semaphore through eventfd. Currently the code lies and - returns 1 every time. We can make this work (in a single process, or [if - necessary] in multiple processes through shared memory) by keeping a count - locally. We can't guarantee that it's the exact count at the moment the - semaphore was released, but I guess any program that runs into that race - shouldn't be depending on that fact anyway. -* Similarly, we can't enforce the maximum count on a semaphore, since we have - no way to get the current count and subsequently compare it with the - maximum. -* We can't use NtQueryMutant to get the mutant's owner or count if it lives in - a different process. If necessary we can use shared memory to make this - work, I guess, but see below. -* User APCs don't work. However, it's not impossible to make them work; in - particular I think this could be relatively easily implemented by waiting on - another internal file descriptor when we execute an alertable wait. * Implementing wait-all, i.e. WaitForMultipleObjects(..., TRUE, ...), is not exactly possible the way we'd like it to be possible. In theory that function should wait until it knows all objects are available, then grab @@ -144,18 +135,13 @@ surprisingly there aren't that many. In particular: There are some things that are perfectly implementable but that I just haven't done yet: -* NtOpen* (aka Open*). This is just a matter of adding another open_esync - request analogous to those for other server primitives. -* NtQuery*. This can be done to some degree (the difficulties are outlined - above). That said, these APIs aren't exposed through kernel32 in any way, so +* NtQuery*. That said, these APIs aren't exposed through kernel32 in any way, so I doubt anyone is going to be using them. -* SignalObjectAndWait(). The server combines this into a single operation, but - according to MSDN it doesn't need to be atomic, so we can just signal the - appropriate object and wait, and woe betide anyone who gets in the way of - those two operations. * Other synchronizable server primitives. It's unlikely we'll need any of these, except perhaps named pipes (which would honestly be rather difficult) and (maybe) timers. +* Access masks. We'd need to store these inside ntdll, and validate them when + someone tries to execute esync operations. This patchset was inspired by Daniel Santos' "hybrid synchronization" patchset. My idea was to create a framework whereby even contended waits could From 1bfc052892b073e7305f1c269eaa34a0d026360b Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 13 Jun 2018 22:25:40 -0500 Subject: [PATCH 0040/2777] kernel32/tests: Mark some existing tests as failing under esync. Wine-Staging: eventfd_synchronization --- dlls/kernel32/tests/sync.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index 60180194b7a..97bd69368c6 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -268,7 +268,8 @@ static void test_mutex(void) SetLastError(0xdeadbeef); hOpened = OpenMutexA(GENERIC_READ | GENERIC_WRITE, FALSE, "WineTestMutex"); ok(hOpened != NULL, "OpenMutex failed with error %ld\n", GetLastError()); - wait_ret = WaitForSingleObject(hOpened, INFINITE); + wait_ret = WaitForSingleObject(hOpened, 0); +todo_wine_if(getenv("WINEESYNC")) /* XFAIL: validation is not implemented */ ok(wait_ret == WAIT_FAILED, "WaitForSingleObject succeeded\n"); CloseHandle(hOpened); @@ -299,6 +300,7 @@ static void test_mutex(void) SetLastError(0xdeadbeef); ret = ReleaseMutex(hCreated); +todo_wine_if(getenv("WINEESYNC")) /* XFAIL: due to the above */ ok(!ret && (GetLastError() == ERROR_NOT_OWNER), "ReleaseMutex should have failed with ERROR_NOT_OWNER instead of %ld\n", GetLastError()); From 20b9871d2dbc165f076554f9061bb7ce0c925e69 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 13 Jun 2018 22:40:47 -0500 Subject: [PATCH 0041/2777] kernel32/tests: Add some semaphore tests. Wine-Staging: eventfd_synchronization --- dlls/kernel32/tests/sync.c | 98 +++++++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index 97bd69368c6..9b22de5191b 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -627,7 +627,10 @@ static void test_event(void) static void test_semaphore(void) { - HANDLE handle, handle2; + HANDLE handle, handle2, handles[2]; + DWORD ret; + LONG prev; + int i; /* test case sensitivity */ @@ -669,6 +672,99 @@ static void test_semaphore(void) ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %lu\n", GetLastError()); CloseHandle( handle ); + + handle = CreateSemaphoreA( NULL, 0, 5, NULL ); + ok(!!handle, "CreateSemaphore failed: %lu\n", GetLastError()); + + ret = WaitForSingleObject( handle, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + ret = ReleaseSemaphore( handle, 1, &prev ); + ok(ret, "got error %lu\n", GetLastError()); + ok(prev == 0, "got prev %ld\n", prev); + + ret = ReleaseSemaphore( handle, 1, &prev ); + ok(ret, "got error %lu\n", GetLastError()); + ok(prev == 1, "got prev %ld\n", prev); + + ret = ReleaseSemaphore( handle, 5, &prev ); + ok(!ret, "got %ld\n", ret); + ok(GetLastError() == ERROR_TOO_MANY_POSTS, "got error %lu\n", GetLastError()); + ok(prev == 1, "got prev %ld\n", prev); + + ret = ReleaseSemaphore( handle, 2, &prev ); + ok(ret, "got error %lu\n", GetLastError()); + ok(prev == 2, "got prev %ld\n", prev); + + ret = ReleaseSemaphore( handle, 1, &prev ); + ok(ret, "got error %lu\n", GetLastError()); + ok(prev == 4, "got prev %ld\n", prev); + + for (i = 0; i < 5; i++) + { + ret = WaitForSingleObject( handle, 0 ); + ok(ret == 0, "got %lu\n", ret); + } + + ret = WaitForSingleObject( handle, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + handle2 = CreateSemaphoreA( NULL, 3, 5, NULL ); + ok(!!handle2, "CreateSemaphore failed: %lu\n", GetLastError()); + + ret = ReleaseSemaphore( handle2, 1, &prev ); + ok(ret, "got error %lu\n", GetLastError()); + ok(prev == 3, "got prev %ld\n", prev); + + for (i = 0; i < 4; i++) + { + ret = WaitForSingleObject( handle2, 0 ); + ok(ret == 0, "got %lu\n", ret); + } + + ret = WaitForSingleObject( handle2, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + handles[0] = handle; + handles[1] = handle2; + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + ReleaseSemaphore( handle, 1, NULL ); + ReleaseSemaphore( handle2, 1, NULL ); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == 1, "got %lu\n", ret); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + ReleaseSemaphore( handle, 1, NULL ); + ReleaseSemaphore( handle2, 1, NULL ); + + ret = WaitForMultipleObjects( 2, handles, TRUE, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + ReleaseSemaphore( handle, 1, NULL ); + + ret = WaitForMultipleObjects( 2, handles, TRUE, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + ret = WaitForSingleObject( handle, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = CloseHandle( handle ); + ok(ret, "got error %lu\n", ret); + + ret = CloseHandle( handle2 ); + ok(ret, "got error %lu\n", ret); } static void test_waitable_timer(void) From 180fbb32bafa859e7c85e7c2c5845e34d42ff365 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 13 Jun 2018 22:59:37 -0500 Subject: [PATCH 0042/2777] kernel32/tests: Add some event tests. Wine-Staging: eventfd_synchronization --- dlls/kernel32/tests/sync.c | 119 ++++++++++++++++++++++++++++++++++++- 1 file changed, 118 insertions(+), 1 deletion(-) diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index 9b22de5191b..bc85126d9aa 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -514,12 +514,13 @@ static void test_slist(void) static void test_event(void) { - HANDLE handle, handle2; + HANDLE handle, handle2, handles[2]; SECURITY_ATTRIBUTES sa; SECURITY_DESCRIPTOR sd; ACL acl; DWORD ret; BOOL val; + int i; /* no sd */ handle = CreateEventA(NULL, FALSE, FALSE, __FILE__ ": Test Event"); @@ -623,6 +624,122 @@ static void test_event(void) ok( ret, "QueryMemoryResourceNotification failed err %lu\n", GetLastError() ); ok( val == FALSE || val == TRUE, "wrong value %u\n", val ); CloseHandle( handle ); + + handle = CreateEventA( NULL, TRUE, FALSE, NULL ); + ok(!!handle, "got error %lu\n", GetLastError()); + + ret = WaitForSingleObject( handle, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + ret = SetEvent( handle ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = SetEvent( handle ); + ok(ret, "got error %lu\n", GetLastError()); + + for (i = 0; i < 100; i++) + { + ret = WaitForSingleObject( handle, 0 ); + ok(ret == 0, "got %lu\n", ret); + } + + ret = ResetEvent( handle ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = ResetEvent( handle ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = WaitForSingleObject( handle, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + handle2 = CreateEventA( NULL, FALSE, TRUE, NULL ); + ok(!!handle2, "got error %lu\n", GetLastError()); + + ret = WaitForSingleObject( handle2, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = WaitForSingleObject( handle2, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + ret = SetEvent( handle2 ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = SetEvent( handle2 ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = ResetEvent( handle2 ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = ResetEvent( handle2 ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = WaitForSingleObject( handle2, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + handles[0] = handle; + handles[1] = handle2; + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + SetEvent( handle ); + SetEvent( handle2 ); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = WaitForSingleObject( handle2, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ResetEvent( handle ); + SetEvent( handle2 ); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == 1, "got %lu\n", ret); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + SetEvent( handle ); + SetEvent( handle2 ); + + ret = WaitForMultipleObjects( 2, handles, TRUE, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = WaitForMultipleObjects( 2, handles, TRUE, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + SetEvent( handle2 ); + ResetEvent( handle ); + + ret = WaitForMultipleObjects( 2, handles, TRUE, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + ret = WaitForSingleObject( handle2, 0 ); + ok(ret == 0, "got %lu\n", ret); + + handles[0] = handle2; + handles[1] = handle; + SetEvent( handle ); + SetEvent( handle2 ); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == 1, "got %lu\n", ret); + + ret = WaitForMultipleObjects( 2, handles, FALSE, 0 ); + ok(ret == 1, "got %lu\n", ret); + + ret = CloseHandle( handle ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = CloseHandle( handle2 ); + ok(ret, "got error %lu\n", GetLastError()); } static void test_semaphore(void) From 23696450c63e560d1ff09c2e4e725b330924723a Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 13 Jun 2018 23:32:04 -0500 Subject: [PATCH 0043/2777] kernel32/tests: Add some mutex tests. Wine-Staging: eventfd_synchronization --- dlls/kernel32/tests/sync.c | 94 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index bc85126d9aa..491052d5593 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -227,8 +227,23 @@ static void test_temporary_objects(void) ok(GetLastError() == ERROR_FILE_NOT_FOUND, "wrong error %lu\n", GetLastError()); } +static HANDLE mutex, mutex2, mutices[2]; + +static DWORD WINAPI mutex_thread( void *param ) +{ + DWORD expect = (DWORD)(DWORD_PTR)param; + DWORD ret; + + ret = WaitForSingleObject( mutex, 0 ); + ok(ret == expect, "expected %lu, got %lu\n", expect, ret); + + if (!ret) ReleaseMutex( mutex ); + return 0; +} + static void test_mutex(void) { + HANDLE thread; DWORD wait_ret; BOOL ret; HANDLE hCreated; @@ -339,6 +354,85 @@ todo_wine_if(getenv("WINEESYNC")) /* XFAIL: due to the above */ CloseHandle(hOpened); CloseHandle(hCreated); + + mutex = CreateMutexA( NULL, FALSE, NULL ); + ok(!!mutex, "got error %lu\n", GetLastError()); + + ret = ReleaseMutex( mutex ); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_NOT_OWNER, "got error %lu\n", GetLastError()); + + for (i = 0; i < 100; i++) + { + ret = WaitForSingleObject( mutex, 0 ); + ok(ret == 0, "got %u\n", ret); + } + + for (i = 0; i < 100; i++) + { + ret = ReleaseMutex( mutex ); + ok(ret, "got error %lu\n", GetLastError()); + } + + ret = ReleaseMutex( mutex ); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_NOT_OWNER, "got error %lu\n", GetLastError()); + + thread = CreateThread( NULL, 0, mutex_thread, (void *)0, 0, NULL ); + ret = WaitForSingleObject( thread, 2000 ); + ok(ret == 0, "wait failed: %u\n", ret); + + WaitForSingleObject( mutex, 0 ); + + thread = CreateThread( NULL, 0, mutex_thread, (void *)WAIT_TIMEOUT, 0, NULL ); + ret = WaitForSingleObject( thread, 2000 ); + ok(ret == 0, "wait failed: %u\n", ret); + + ret = ReleaseMutex( mutex ); + ok(ret, "got error %lu\n", GetLastError()); + + thread = CreateThread( NULL, 0, mutex_thread, (void *)0, 0, NULL ); + ret = WaitForSingleObject( thread, 2000 ); + ok(ret == 0, "wait failed: %u\n", ret); + + mutex2 = CreateMutexA( NULL, TRUE, NULL ); + ok(!!mutex2, "got error %lu\n", GetLastError()); + + ret = ReleaseMutex( mutex2 ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = ReleaseMutex( mutex2 ); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_NOT_OWNER, "got error %lu\n", GetLastError()); + + mutices[0] = mutex; + mutices[1] = mutex2; + + ret = WaitForMultipleObjects( 2, mutices, FALSE, 0 ); + ok(ret == 0, "got %u\n", ret); + + ret = ReleaseMutex( mutex ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = ReleaseMutex( mutex2 ); + ok(!ret, "got %d\n", ret); + ok(GetLastError() == ERROR_NOT_OWNER, "got error %lu\n", GetLastError()); + + ret = WaitForMultipleObjects( 2, mutices, TRUE, 0 ); + ok(ret == 0, "got %u\n", ret); + + ret = ReleaseMutex( mutex ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = ReleaseMutex( mutex2 ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = CloseHandle( mutex ); + ok(ret, "got error %lu\n", GetLastError()); + + ret = CloseHandle( mutex2 ); + ok(ret, "got error %lu\n", GetLastError()); + } static void test_slist(void) From d41366e2de18a82266e92b0dd7609046e8a56a29 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 13 Jun 2018 23:58:01 -0500 Subject: [PATCH 0044/2777] kernel32/tests: Add some tests for wait timeouts. Wine-Staging: eventfd_synchronization --- dlls/kernel32/tests/sync.c | 68 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index 491052d5593..2794906c6ff 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -57,6 +57,7 @@ static BOOLEAN (WINAPI *pTryAcquireSRWLockShared)(PSRWLOCK); static NTSTATUS (WINAPI *pNtAllocateVirtualMemory)(HANDLE, PVOID *, ULONG_PTR, SIZE_T *, ULONG, ULONG); static NTSTATUS (WINAPI *pNtFreeVirtualMemory)(HANDLE, PVOID *, SIZE_T *, ULONG); +static NTSTATUS (WINAPI *pNtQuerySystemTime)(LARGE_INTEGER *); static NTSTATUS (WINAPI *pNtWaitForSingleObject)(HANDLE, BOOLEAN, const LARGE_INTEGER *); static NTSTATUS (WINAPI *pNtWaitForMultipleObjects)(ULONG,const HANDLE*,BOOLEAN,BOOLEAN,const LARGE_INTEGER*); static PSLIST_ENTRY (__fastcall *pRtlInterlockedPushListSList)(PSLIST_HEADER list, PSLIST_ENTRY first, @@ -1530,11 +1531,15 @@ static HANDLE modify_handle(HANDLE handle, DWORD modify) return ULongToHandle(tmp); } +#define TIMEOUT_INFINITE (((LONGLONG)0x7fffffff) << 32 | 0xffffffff) + static void test_WaitForSingleObject(void) { HANDLE signaled, nonsignaled, invalid; + LARGE_INTEGER ntnow, ntthen; LARGE_INTEGER timeout; NTSTATUS status; + DWORD now, then; DWORD ret; signaled = CreateEventW(NULL, TRUE, TRUE, NULL); @@ -1619,6 +1624,68 @@ static void test_WaitForSingleObject(void) status = pNtWaitForSingleObject(GetCurrentThread(), FALSE, &timeout); ok(status == STATUS_TIMEOUT, "expected STATUS_TIMEOUT, got %08lx\n", status); + ret = WaitForSingleObject( signaled, 0 ); + ok(ret == 0, "got %lu\n", ret); + + ret = WaitForSingleObject( nonsignaled, 0 ); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + + /* test that a timed wait actually does wait */ + now = GetTickCount(); + ret = WaitForSingleObject( nonsignaled, 100 ); + then = GetTickCount(); + ok(ret == WAIT_TIMEOUT, "got %lu\n", ret); + ok(abs((then - now) - 100) < 5, "got %lu ms\n", then - now); + + now = GetTickCount(); + ret = WaitForSingleObject( signaled, 100 ); + then = GetTickCount(); + ok(ret == 0, "got %lu\n", ret); + ok(abs(then - now) < 5, "got %lu ms\n", then - now); + + ret = WaitForSingleObject( signaled, INFINITE ); + ok(ret == 0, "got %lu\n", ret); + + /* test NT timeouts */ + pNtQuerySystemTime( &ntnow ); + timeout.QuadPart = ntnow.QuadPart + 100 * 10000; + status = pNtWaitForSingleObject( nonsignaled, FALSE, &timeout ); + pNtQuerySystemTime( &ntthen ); + ok(status == STATUS_TIMEOUT, "got %#lx\n", status); + ok(abs(((ntthen.QuadPart - ntnow.QuadPart) / 10000) - 100) < 5, "got %s ns\n", + wine_dbgstr_longlong((ntthen.QuadPart - ntnow.QuadPart) * 100)); + + pNtQuerySystemTime( &ntnow ); + timeout.QuadPart = -100 * 10000; + status = pNtWaitForSingleObject( nonsignaled, FALSE, &timeout ); + pNtQuerySystemTime( &ntthen ); + ok(status == STATUS_TIMEOUT, "got %#lx\n", status); + ok(abs(((ntthen.QuadPart - ntnow.QuadPart) / 10000) - 100) < 5, "got %s ns\n", + wine_dbgstr_longlong((ntthen.QuadPart - ntnow.QuadPart) * 100)); + + status = pNtWaitForSingleObject( signaled, FALSE, NULL ); + ok(status == 0, "got %#lx\n", status); + + timeout.QuadPart = TIMEOUT_INFINITE; + status = pNtWaitForSingleObject( signaled, FALSE, &timeout ); + ok(status == 0, "got %#lx\n", status); + + pNtQuerySystemTime( &ntnow ); + timeout.QuadPart = ntnow.QuadPart; + status = pNtWaitForSingleObject( nonsignaled, FALSE, &timeout ); + pNtQuerySystemTime( &ntthen ); + ok(status == STATUS_TIMEOUT, "got %#lx\n", status); + ok(abs((ntthen.QuadPart - ntnow.QuadPart) / 10000) < 5, "got %s ns\n", + wine_dbgstr_longlong((ntthen.QuadPart - ntnow.QuadPart) * 100)); + + pNtQuerySystemTime( &ntnow ); + timeout.QuadPart = ntnow.QuadPart - 100 * 10000; + status = pNtWaitForSingleObject( nonsignaled, FALSE, &timeout ); + pNtQuerySystemTime( &ntthen ); + ok(status == STATUS_TIMEOUT, "got %#lx\n", status); + ok(abs((ntthen.QuadPart - ntnow.QuadPart) / 10000) < 5, "got %s ns\n", + wine_dbgstr_longlong((ntthen.QuadPart - ntnow.QuadPart) * 100)); + CloseHandle(signaled); CloseHandle(nonsignaled); } @@ -3158,6 +3225,7 @@ START_TEST(sync) pTryAcquireSRWLockShared = (void *)GetProcAddress(hdll, "TryAcquireSRWLockShared"); pNtAllocateVirtualMemory = (void *)GetProcAddress(hntdll, "NtAllocateVirtualMemory"); pNtFreeVirtualMemory = (void *)GetProcAddress(hntdll, "NtFreeVirtualMemory"); + pNtQuerySystemTime = (void *)GetProcAddress(hntdll, "NtQuerySystemTime"); pNtWaitForSingleObject = (void *)GetProcAddress(hntdll, "NtWaitForSingleObject"); pNtWaitForMultipleObjects = (void *)GetProcAddress(hntdll, "NtWaitForMultipleObjects"); pRtlInterlockedPushListSList = (void *)GetProcAddress(hntdll, "RtlInterlockedPushListSList"); From 1225b04d2c1ec2b42b445403f245a41f87095ad9 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Tue, 26 Jun 2018 18:44:44 -0500 Subject: [PATCH 0045/2777] kernel32/tests: Zigzag test. The primary function is to check for races. The secondary function is to measure performance. Wine-Staging: eventfd_synchronization --- dlls/kernel32/tests/sync.c | 79 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index 2794906c6ff..2cdabc14cd9 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -3199,6 +3199,84 @@ static void test_QueueUserAPC(void) ok(apc_count == 1, "APC count %u\n", apc_count); } +static int zigzag_state, zigzag_count[2], zigzag_stop; + +static DWORD CALLBACK zigzag_event0(void *arg) +{ + HANDLE *events = arg; + + while (!zigzag_stop) + { + WaitForSingleObject(events[0], INFINITE); + ResetEvent(events[0]); + ok(zigzag_state == 0, "got wrong state %d\n", zigzag_state); + zigzag_state++; + SetEvent(events[1]); + zigzag_count[0]++; + } + trace("thread 0 got done\n"); + return 0; +} + +static DWORD CALLBACK zigzag_event1(void *arg) +{ + HANDLE *events = arg; + + while (!zigzag_stop) + { + WaitForSingleObject(events[1], INFINITE); + ResetEvent(events[1]); + ok(zigzag_state == 1, "got wrong state %d\n", zigzag_state); + zigzag_state--; + SetEvent(events[0]); + zigzag_count[1]++; + } + trace("thread 1 got done\n"); + return 0; +} + +static void test_zigzag_event(void) +{ + /* The basic idea is to test SetEvent/Wait back and forth between two + * threads. Each thread clears their own event, sets some common data, + * signals the other's, then waits on their own. We make sure the common + * data is always in the right state. We also print performance data. */ + + HANDLE threads[2], events[2]; + BOOL ret; + + events[0] = CreateEventA(NULL, FALSE, FALSE, NULL); + events[1] = CreateEventA(NULL, FALSE, FALSE, NULL); + + threads[0] = CreateThread(NULL, 0, zigzag_event0, events, 0, NULL); + threads[1] = CreateThread(NULL, 0, zigzag_event1, events, 0, NULL); + + zigzag_state = 0; + zigzag_count[0] = zigzag_count[1] = 0; + zigzag_stop = 0; + + trace("starting zigzag test (events)\n"); + SetEvent(events[0]); + Sleep(2000); + zigzag_stop = 1; + ret = WaitForMultipleObjects(2, threads, FALSE, INFINITE); + trace("%d\n", ret); + ok(ret == 0 || ret == 1, "wait failed: %u\n", ret); + + ok(zigzag_count[0] == zigzag_count[1] || zigzag_count[0] == zigzag_count[1] + 1, + "count did not match: %d != %d\n", zigzag_count[0], zigzag_count[1]); + + /* signal the other thread to finish, if it didn't already + * (in theory they both would at the same time, but there's a slight race on teardown if we get + * thread 1 SetEvent -> thread 0 ResetEvent -> thread 0 Wait -> thread 1 exits */ + zigzag_state = 1-ret; + SetEvent(events[1-ret]); + ret = WaitForSingleObject(threads[1-ret], 1000); + ok(!ret, "wait failed: %u\n", ret); + + trace("count: %d\n", zigzag_count[0]); +} + START_TEST(sync) { char **argv; @@ -3266,5 +3344,6 @@ START_TEST(sync) test_srwlock_example(); test_alertable_wait(); test_apc_deadlock(); + test_zigzag_event(); test_crit_section(); } From 69bde5fd1d085c3fa97a44901f6eecd01d8779b8 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 17:24:17 -0500 Subject: [PATCH 0046/2777] ntdll: Implement NtQuerySemaphore(). Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 19 +++++++++++++++++++ dlls/ntdll/unix/esync.h | 1 + dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 23 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 381d4ff7b6c..f305db34c1f 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -416,6 +416,25 @@ NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) return STATUS_SUCCESS; } +NTSTATUS esync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len ) +{ + struct esync *obj; + struct semaphore *semaphore; + SEMAPHORE_BASIC_INFORMATION *out = info; + NTSTATUS ret; + + TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); + + if ((ret = get_object( handle, &obj ))) return ret; + semaphore = obj->shm; + + out->CurrentCount = semaphore->count; + out->MaximumCount = semaphore->max; + if (ret_len) *ret_len = sizeof(*out); + + return STATUS_SUCCESS; +} + NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, EVENT_TYPE event_type, BOOLEAN initial ) { diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h index cb48e2cd022..599ed6dbd9b 100644 --- a/dlls/ntdll/unix/esync.h +++ b/dlls/ntdll/unix/esync.h @@ -26,6 +26,7 @@ extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN; extern NTSTATUS esync_open_semaphore( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; +extern NTSTATUS esync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len ) DECLSPEC_HIDDEN; extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 4c896b6cfd4..2130944435d 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -341,6 +341,9 @@ NTSTATUS WINAPI NtQuerySemaphore( HANDLE handle, SEMAPHORE_INFORMATION_CLASS cla if (len != sizeof(SEMAPHORE_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; + if (do_esync()) + return esync_query_semaphore( handle, info, ret_len ); + SERVER_START_REQ( query_semaphore ) { req->handle = wine_server_obj_handle( handle ); From 29d0859a57df96a524dab62b4b3cbf66848c0d8a Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 17:26:56 -0500 Subject: [PATCH 0047/2777] ntdll: Implement NtQueryEvent(). Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 20 ++++++++++++++++++++ dlls/ntdll/unix/esync.h | 1 + dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 24 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index f305db34c1f..3c1723388f8 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -487,6 +487,26 @@ NTSTATUS esync_reset_event( HANDLE handle ) return STATUS_SUCCESS; } +NTSTATUS esync_query_event( HANDLE handle, void *info, ULONG *ret_len ) +{ + struct esync *obj; + EVENT_BASIC_INFORMATION *out = info; + struct pollfd fd; + NTSTATUS ret; + + TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); + + if ((ret = get_object( handle, &obj ))) return ret; + + fd.fd = obj->fd; + fd.events = POLLIN; + out->EventState = poll( &fd, 1, 0 ); + out->EventType = (obj->type == ESYNC_AUTO_EVENT ? SynchronizationEvent : NotificationEvent); + if (ret_len) *ret_len = sizeof(*out); + + return STATUS_SUCCESS; +} + NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) { diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h index 599ed6dbd9b..8ac3924da2d 100644 --- a/dlls/ntdll/unix/esync.h +++ b/dlls/ntdll/unix/esync.h @@ -33,6 +33,7 @@ extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN; extern NTSTATUS esync_open_event( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; +extern NTSTATUS esync_query_event( HANDLE handle, void *info, ULONG *ret_len ) DECLSPEC_HIDDEN; extern NTSTATUS esync_reset_event( HANDLE handle ) DECLSPEC_HIDDEN; extern NTSTATUS esync_set_event( HANDLE handle ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 2130944435d..05657febed1 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -540,6 +540,9 @@ NTSTATUS WINAPI NtQueryEvent( HANDLE handle, EVENT_INFORMATION_CLASS class, if (len != sizeof(EVENT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; + if (do_esync()) + return esync_query_event( handle, info, ret_len ); + SERVER_START_REQ( query_event ) { req->handle = wine_server_obj_handle( handle ); From 10f6094501bcc8156c5149cbe83e76b570b97867 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 17:28:58 -0500 Subject: [PATCH 0048/2777] ntdll: Implement NtQueryMutant(). Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 20 ++++++++++++++++++++ dlls/ntdll/unix/esync.h | 1 + dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 24 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 3c1723388f8..87e142c000f 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -558,6 +558,26 @@ NTSTATUS esync_release_mutex( HANDLE *handle, LONG *prev ) return STATUS_SUCCESS; } +NTSTATUS esync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) +{ + struct esync *obj; + struct mutex *mutex; + MUTANT_BASIC_INFORMATION *out = info; + NTSTATUS ret; + + TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); + + if ((ret = get_object( handle, &obj ))) return ret; + mutex = obj->shm; + + out->CurrentCount = 1 - mutex->count; + out->OwnedByCaller = (mutex->tid == GetCurrentThreadId()); + out->AbandonedState = FALSE; + if (ret_len) *ret_len = sizeof(*out); + + return STATUS_SUCCESS; +} + #define TICKSPERSEC 10000000 #define TICKSPERMSEC 10000 diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h index 8ac3924da2d..18788fa273b 100644 --- a/dlls/ntdll/unix/esync.h +++ b/dlls/ntdll/unix/esync.h @@ -41,6 +41,7 @@ extern NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) DECLSPEC_HIDDEN; extern NTSTATUS esync_open_mutex( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; +extern NTSTATUS esync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) DECLSPEC_HIDDEN; extern NTSTATUS esync_release_mutex( HANDLE *handle, LONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 05657febed1..e8ba76c1e2d 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -658,6 +658,9 @@ NTSTATUS WINAPI NtQueryMutant( HANDLE handle, MUTANT_INFORMATION_CLASS class, if (len != sizeof(MUTANT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; + if (do_esync()) + return esync_query_mutex( handle, info, ret_len ); + SERVER_START_REQ( query_mutex ) { req->handle = wine_server_obj_handle( handle ); From 880a0525b851ff9f1cd91d7ba5bbfd0c892803a8 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 7 Jul 2018 12:57:47 +0200 Subject: [PATCH 0049/2777] server: Create eventfd descriptors for pseudo-fd objects and use them for named pipes. Wine-Staging: eventfd_synchronization --- server/fd.c | 22 ++++++++++++++++++++++ server/file.h | 1 + server/named_pipe.c | 4 ++-- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/server/fd.c b/server/fd.c index bbdb715a641..0ca28ec40aa 100644 --- a/server/fd.c +++ b/server/fd.c @@ -96,6 +96,7 @@ #include "handle.h" #include "process.h" #include "request.h" +#include "esync.h" #include "winternl.h" #include "winioctl.h" @@ -193,6 +194,7 @@ struct fd struct completion *completion; /* completion object attached to this fd */ apc_param_t comp_key; /* completion key to set in completion events */ unsigned int comp_flags; /* completion flags */ + int esync_fd; /* esync file descriptor */ }; static void fd_dump( struct object *obj, int verbose ); @@ -1591,6 +1593,9 @@ static void fd_destroy( struct object *obj ) if (fd->unix_fd != -1) close( fd->unix_fd ); free( fd->unix_name ); } + + if (do_esync()) + close( fd->esync_fd ); } /* check if the desired access is possible without violating */ @@ -1707,6 +1712,7 @@ static struct fd *alloc_fd_object(void) fd->poll_index = -1; fd->completion = NULL; fd->comp_flags = 0; + fd->esync_fd = -1; init_async_queue( &fd->read_q ); init_async_queue( &fd->write_q ); init_async_queue( &fd->wait_q ); @@ -1746,11 +1752,15 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use fd->completion = NULL; fd->comp_flags = 0; fd->no_fd_status = STATUS_BAD_DEVICE_TYPE; + fd->esync_fd = -1; init_async_queue( &fd->read_q ); init_async_queue( &fd->write_q ); init_async_queue( &fd->wait_q ); list_init( &fd->inode_entry ); list_init( &fd->locks ); + + if (do_esync()) + fd->esync_fd = esync_create_fd( 0, 0 ); return fd; } @@ -2147,6 +2157,9 @@ void set_fd_signaled( struct fd *fd, int signaled ) if (fd->comp_flags & FILE_SKIP_SET_EVENT_ON_HANDLE) return; fd->signaled = signaled; if (signaled) wake_up( fd->user, 0 ); + + if (do_esync() && !signaled) + esync_clear( fd->esync_fd ); } /* check if events are pending and if yes return which one(s) */ @@ -2172,6 +2185,15 @@ int default_fd_signaled( struct object *obj, struct wait_queue_entry *entry ) return ret; } +int default_fd_get_esync_fd( struct object *obj, enum esync_type *type ) +{ + struct fd *fd = get_obj_fd( obj ); + int ret = fd->esync_fd; + *type = ESYNC_MANUAL_SERVER; + release_object( fd ); + return ret; +} + int default_fd_get_poll_events( struct fd *fd ) { int events = 0; diff --git a/server/file.h b/server/file.h index 0ffe0e2c8dc..b5b1e2a1077 100644 --- a/server/file.h +++ b/server/file.h @@ -106,6 +106,7 @@ extern char *dup_fd_name( struct fd *root, const char *name ); extern void get_nt_name( struct fd *fd, struct unicode_str *name ); extern int default_fd_signaled( struct object *obj, struct wait_queue_entry *entry ); +extern int default_fd_get_esync_fd( struct object *obj, enum esync_type *type ); extern int default_fd_get_poll_events( struct fd *fd ); extern void default_poll_event( struct fd *fd, int event ); extern void fd_cancel_async( struct fd *fd, struct async *async ); diff --git a/server/named_pipe.c b/server/named_pipe.c index b8ec17a787a..e01b28f725a 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -168,7 +168,7 @@ static const struct object_ops pipe_server_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ - NULL, /* get_esync_fd */ + default_fd_get_esync_fd, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ pipe_end_get_fd, /* get_fd */ @@ -213,7 +213,7 @@ static const struct object_ops pipe_client_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ - NULL, /* get_esync_fd */ + default_fd_get_esync_fd, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ pipe_end_get_fd, /* get_fd */ From a11145d77541647114f1fe6f8b8cf48a1b315cba Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 4 Jul 2018 14:58:33 +0200 Subject: [PATCH 0050/2777] esync: Update README. Wine-Staging: eventfd_synchronization --- README.esync | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/README.esync b/README.esync index 627cc3f481e..30e241755ad 100644 --- a/README.esync +++ b/README.esync @@ -2,6 +2,29 @@ This is eventfd-based synchronization, or 'esync' for short. Turn it on with WINEESYNC=1 (note that it checks the presence and not the value); debug it with +esync. +== BUGS AND LIMITATIONS == + +Please let me know if you find any bugs. If you can, also attach a log with ++seh,+pid,+esync,+server. + +If you get something like "eventfd: Too many open files" and then things start +crashing, you've probably run out of file descriptors. esync creates one +eventfd descriptor for each synchronization object, and some games may use a +large number of these. Linux by default limits a process to 4096 file +descriptors, which probably was reasonable back in the nineties but isn't +really anymore. (Fortunately Debian and derivatives [Ubuntu, Mint] already +have a reasonable limit.) To raise the limit you'll want to edit +/etc/security/limits.conf and add a line like + +* hard nofile 1048576 + +then restart your session. + +Also note that if the wineserver has esync active, all clients also must, and +vice versa. Otherwise things will probably crash quite badly. + +== EXPLANATION == + The aim is to execute all synchronization operations in "user-space", that is, without going through wineserver. We do this using Linux's eventfd facility. The main impetus to using eventfd is so that we can poll multiple @@ -135,8 +158,6 @@ surprisingly there aren't that many. In particular: There are some things that are perfectly implementable but that I just haven't done yet: -* NtQuery*. That said, these APIs aren't exposed through kernel32 in any way, so - I doubt anyone is going to be using them. * Other synchronizable server primitives. It's unlikely we'll need any of these, except perhaps named pipes (which would honestly be rather difficult) and (maybe) timers. From e756819d6f4b7f476875ab1bc90f40bd5cd19ce0 Mon Sep 17 00:00:00 2001 From: Mathieu Comandon Date: Sat, 21 Jul 2018 12:56:50 -0700 Subject: [PATCH 0051/2777] esync: Add note about file limits not being raised when using systemd. Wine-Staging: eventfd_synchronization --- README.esync | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.esync b/README.esync index 30e241755ad..7706f395ebd 100644 --- a/README.esync +++ b/README.esync @@ -20,6 +20,16 @@ have a reasonable limit.) To raise the limit you'll want to edit then restart your session. +On distributions using systemd, the settings in `/etc/security/limits.conf` will +be overridden by systemd's own settings. If you run `ulimit -Hn` and it returns +a lower number than the one you've previously set then you can set + +DefaultLimitNOFILE=100000 + +in both `/etc/systemd/system.conf` and `/etc/systemd/user.conf`. You can then +execute `sudo systemctl daemon-reexec` and restart your session. Check again +with `ulimit -Hn` that the limit is correct. + Also note that if the wineserver has esync active, all clients also must, and vice versa. Otherwise things will probably crash quite badly. @@ -188,4 +198,4 @@ done by the kernel. Anyway, yeah, this is esync. Use it if you like. ---Zebediah Figura \ No newline at end of file +--Zebediah Figura From de53be4f94e34d14f89e123435e9096621bbbeb6 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 17:37:29 -0500 Subject: [PATCH 0052/2777] ntdll: Try to avoid poll() for uncontended objects. Just semaphores and mutexes thus far. We don't have to worry about races because this is just a hint: we still call read() eventually. Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 60 ++++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 87e142c000f..90b81451dbd 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -746,23 +746,63 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA if (wait_any || count == 1) { + /* Try to check objects now, so we can obviate poll() at least. */ for (i = 0; i < count; i++) { struct esync *obj = objs[i]; - if (obj && obj->type == ESYNC_MUTEX) + if (obj) { - /* If we already own the mutex, return immediately. */ - /* Note: This violates the assumption that the *first* object - * to be signaled will be returned. If that becomes a problem, - * we can always check the state of each object before waiting. */ - struct mutex *mutex = (struct mutex *)obj; + switch (obj->type) + { + case ESYNC_MUTEX: + { + struct mutex *mutex = obj->shm; - if (mutex->tid == GetCurrentThreadId()) + if (mutex->tid == GetCurrentThreadId()) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + mutex->count++; + return i; + } + else if (!mutex->count) + { + if ((size = read( obj->fd, &value, sizeof(value) )) == sizeof(value)) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + mutex->tid = GetCurrentThreadId(); + mutex->count++; + return i; + } + } + break; + } + case ESYNC_SEMAPHORE: { - TRACE("Woken up by handle %p [%d].\n", handles[i], i); - mutex->count++; - return i; + struct semaphore *semaphore = obj->shm; + + if (semaphore->count) + { + if ((size = read( obj->fd, &value, sizeof(value) )) == sizeof(value)) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + InterlockedDecrement( (LONG *)&semaphore->count ); + return i; + } + } + break; + } + case ESYNC_AUTO_EVENT: + case ESYNC_MANUAL_EVENT: + /* TODO */ + break; + case ESYNC_AUTO_SERVER: + case ESYNC_MANUAL_SERVER: + case ESYNC_QUEUE: + /* We can't wait on any of these. Fortunately I don't think + * they'll ever be uncontended anyway (at least, they won't be + * performance-critical). */ + break; } } From 833e96e972ca6782736b676947df750a23edc016 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 17:44:26 -0500 Subject: [PATCH 0053/2777] ntdll, server: Try to avoid poll() for signaled events. Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 147 ++++++++++++++++++++++++++++++++++++++-- server/esync.c | 61 +++++++++++++++-- 2 files changed, 197 insertions(+), 11 deletions(-) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 90b81451dbd..e61980463a5 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -455,18 +455,103 @@ NTSTATUS esync_open_event( HANDLE *handle, ACCESS_MASK access, return open_esync( ESYNC_AUTO_EVENT, handle, access, attr ); /* doesn't matter which */ } +static inline void small_pause(void) +{ +#ifdef __i386__ + __asm__ __volatile__( "rep;nop" : : : "memory" ); +#else + __asm__ __volatile__( "" : : : "memory" ); +#endif +} + +/* Manual-reset events are actually racier than other objects in terms of shm + * state. With other objects, races don't matter, because we only treat the shm + * state as a hint that lets us skip poll()—we still have to read(). But with + * manual-reset events we don't, which means that the shm state can be out of + * sync with the actual state. + * + * In general we shouldn't have to worry about races between modifying the + * event and waiting on it. If the state changes while we're waiting, it's + * equally plausible that we caught it before or after the state changed. + * However, we can have races between SetEvent() and ResetEvent(), so that the + * event has inconsistent internal state. + * + * To solve this we have to use the other field to lock the event. Currently + * this is implemented as a spinlock, but I'm not sure if a futex might be + * better. I'm also not sure if it's possible to obviate locking by arranging + * writes and reads in a certain way. + * + * Note that we don't have to worry about locking in esync_wait_objects(). + * There's only two general patterns: + * + * WaitFor() SetEvent() + * ------------------------- + * read() + * signaled = 0 + * signaled = 1 + * write() + * ------------------------- + * read() + * signaled = 1 + * signaled = 0 + * + * ------------------------- + * + * That is, if SetEvent() tries to signal the event before WaitFor() resets its + * signaled state, it won't bother trying to write(), and then the signaled + * state will be reset, so the result is a consistent non-signaled event. + * There's several variations to this pattern but all of them are protected in + * the same way. Note however this is why we have to use interlocked_xchg() + * event inside of the lock. + */ + +/* Removing this spinlock is harder than it looks. esync_wait_objects() can + * deal with inconsistent state well enough, and a race between SetEvent() and + * ResetEvent() gives us license to yield either result as long as we act + * consistently, but that's not enough. Notably, esync_wait_objects() should + * probably act like a fence, so that the second half of esync_set_event() does + * not seep past a subsequent reset. That's one problem, but no guarantee there + * aren't others. */ + NTSTATUS esync_set_event( HANDLE handle ) { static const uint64_t value = 1; struct esync *obj; + struct event *event; NTSTATUS ret; TRACE("%p.\n", handle); - if ((ret = get_object( handle, &obj))) return ret; + if ((ret = get_object( handle, &obj ))) return ret; + event = obj->shm; + + if (obj->type == ESYNC_MANUAL_EVENT) + { + /* Acquire the spinlock. */ + while (InterlockedCompareExchange( (LONG *)&event->locked, 1, 0 )) + small_pause(); + } + + /* For manual-reset events, as long as we're in a lock, we can take the + * optimization of only calling write() if the event wasn't already + * signaled. + * + * For auto-reset events, esync_wait_objects() must grab the kernel object. + * Thus if we got into a race so that the shm state is signaled but the + * eventfd is unsignaled (i.e. reset shm, set shm, set fd, reset fd), we + * *must* signal the fd now, or any waiting threads will never wake up. */ + + if (!InterlockedExchange( (LONG *)&event->signaled, 1 ) || obj->type == ESYNC_AUTO_EVENT) + { + if (write( obj->fd, &value, sizeof(value) ) == -1) + ERR("write: %s\n", strerror(errno)); + } - if (write( obj->fd, &value, sizeof(value) ) == -1) - ERR("write: %s\n", strerror(errno)); + if (obj->type == ESYNC_MANUAL_EVENT) + { + /* Release the spinlock. */ + event->locked = 0; + } return STATUS_SUCCESS; } @@ -475,14 +560,40 @@ NTSTATUS esync_reset_event( HANDLE handle ) { uint64_t value; struct esync *obj; + struct event *event; NTSTATUS ret; TRACE("%p.\n", handle); - if ((ret = get_object( handle, &obj))) return ret; + if ((ret = get_object( handle, &obj ))) return ret; + event = obj->shm; - if (read( obj->fd, &value, sizeof(value) ) == -1 && errno != EWOULDBLOCK && errno != EAGAIN) - ERR("read: %s\n", strerror(errno)); + if (obj->type == ESYNC_MANUAL_EVENT) + { + /* Acquire the spinlock. */ + while (InterlockedCompareExchange( (LONG *)&event->locked, 1, 0 )) + small_pause(); + } + + /* For manual-reset events, as long as we're in a lock, we can take the + * optimization of only calling read() if the event was already signaled. + * + * For auto-reset events, we have no guarantee that the previous "signaled" + * state is actually correct. We need to leave both states unsignaled after + * leaving this function, so we always have to read(). */ + if (InterlockedExchange( (LONG *)&event->signaled, 0 ) || obj->type == ESYNC_AUTO_EVENT) + { + if (read( obj->fd, &value, sizeof(value) ) == -1 && errno != EWOULDBLOCK && errno != EAGAIN) + { + ERR("read: %s\n", strerror(errno)); + } + } + + if (obj->type == ESYNC_MANUAL_EVENT) + { + /* Release the spinlock. */ + event->locked = 0; + } return STATUS_SUCCESS; } @@ -793,9 +904,31 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA break; } case ESYNC_AUTO_EVENT: + { + struct event *event = obj->shm; + + if (event->signaled) + { + if ((size = read( obj->fd, &value, sizeof(value) )) == sizeof(value)) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + event->signaled = 0; + return i; + } + } + break; + } case ESYNC_MANUAL_EVENT: - /* TODO */ + { + struct event *event = obj->shm; + + if (event->signaled) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + return i; + } break; + } case ESYNC_AUTO_SERVER: case ESYNC_MANUAL_SERVER: case ESYNC_QUEUE: diff --git a/server/esync.c b/server/esync.c index 0c365006f0b..20ea97869e9 100644 --- a/server/esync.c +++ b/server/esync.c @@ -376,24 +376,77 @@ void esync_clear( int fd ) read( fd, &value, sizeof(value) ); } +static inline void small_pause(void) +{ +#ifdef __i386__ + __asm__ __volatile__( "rep;nop" : : : "memory" ); +#else + __asm__ __volatile__( "" : : : "memory" ); +#endif +} + /* Server-side event support. */ void esync_set_event( struct esync *esync ) { static const uint64_t value = 1; + struct event *event = get_shm( esync->shm_idx ); assert( esync->obj.ops == &esync_ops ); - if (write( esync->fd, &value, sizeof(value) ) == -1) - perror( "esync: write" ); + assert( event != NULL ); + + if (debug_level) + fprintf( stderr, "esync_set_event() fd=%d\n", esync->fd ); + + if (esync->type == ESYNC_MANUAL_EVENT) + { + /* Acquire the spinlock. */ + while (__sync_val_compare_and_swap( &event->locked, 0, 1 )) + small_pause(); + } + + if (!__atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST )) + { + if (write( esync->fd, &value, sizeof(value) ) == -1) + perror( "esync: write" ); + } + + if (esync->type == ESYNC_MANUAL_EVENT) + { + /* Release the spinlock. */ + event->locked = 0; + } } void esync_reset_event( struct esync *esync ) { static uint64_t value = 1; + struct event *event = get_shm( esync->shm_idx ); assert( esync->obj.ops == &esync_ops ); + assert( event != NULL ); - /* we don't care about the return value */ - read( esync->fd, &value, sizeof(value) ); + if (debug_level) + fprintf( stderr, "esync_reset_event() fd=%d\n", esync->fd ); + + if (esync->type == ESYNC_MANUAL_EVENT) + { + /* Acquire the spinlock. */ + while (__sync_val_compare_and_swap( &event->locked, 0, 1 )) + small_pause(); + } + + /* Only bother signaling the fd if we weren't already signaled. */ + if (__atomic_exchange_n( &event->signaled, 0, __ATOMIC_SEQ_CST )) + { + /* we don't care about the return value */ + read( esync->fd, &value, sizeof(value) ); + } + + if (esync->type == ESYNC_MANUAL_EVENT) + { + /* Release the spinlock. */ + event->locked = 0; + } } DECL_HANDLER(create_esync) From 668f16c7536092219235f5d7038e93026778c441 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 4 Aug 2018 15:18:24 -0500 Subject: [PATCH 0054/2777] esync: Update README. Wine-Staging: eventfd_synchronization --- README.esync | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/README.esync b/README.esync index 7706f395ebd..b64bfefc1a3 100644 --- a/README.esync +++ b/README.esync @@ -5,7 +5,7 @@ with +esync. == BUGS AND LIMITATIONS == Please let me know if you find any bugs. If you can, also attach a log with -+seh,+pid,+esync,+server. ++seh,+pid,+esync,+server,+timestamp. If you get something like "eventfd: Too many open files" and then things start crashing, you've probably run out of file descriptors. esync creates one @@ -20,11 +20,11 @@ have a reasonable limit.) To raise the limit you'll want to edit then restart your session. -On distributions using systemd, the settings in `/etc/security/limits.conf` will -be overridden by systemd's own settings. If you run `ulimit -Hn` and it returns -a lower number than the one you've previously set then you can set +On distributions using systemd, the settings in `/etc/security/limits.conf` +will be overridden by systemd's own settings. If you run `ulimit -Hn` and it +returns a lower number than the one you've previously set, then you can set -DefaultLimitNOFILE=100000 +DefaultLimitNOFILE=1048576 in both `/etc/systemd/system.conf` and `/etc/systemd/user.conf`. You can then execute `sudo systemctl daemon-reexec` and restart your session. Check again @@ -157,10 +157,6 @@ surprisingly there aren't that many. In particular: can probably be something reasonable.) It's also possible, although I haven't yet looked, to use some different kind of synchronization primitives, but pipes would be easiest to tack onto this framework. -* We might hit the maximum number of open fd's. On my system the soft limit is - 1024 and the hard limit is 1048576. I'm inclined to hope this won't be an - issue, since a hypothetical Linux port of any application might just as well - use the same number of eventfds. * PulseEvent() can't work the way it's supposed to work. Fortunately it's rare and deprecated. It's also explicitly mentioned on MSDN that a thread can miss the notification for a kernel APC, so in a sense we're not necessarily From c4c89b3a3809a26c4d350731b36a5f43ffd02800 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 17:56:40 -0500 Subject: [PATCH 0055/2777] ntdll: Implement NtPulseEvent(). Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 25 +++++++++++++++++++++++++ dlls/ntdll/unix/esync.h | 1 + dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 29 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index e61980463a5..a52622de8ec 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -598,6 +598,31 @@ NTSTATUS esync_reset_event( HANDLE handle ) return STATUS_SUCCESS; } +NTSTATUS esync_pulse_event( HANDLE handle ) +{ + uint64_t value = 1; + struct esync *obj; + NTSTATUS ret; + + TRACE("%p.\n", handle); + + if ((ret = get_object( handle, &obj ))) return ret; + + /* This isn't really correct; an application could miss the write. + * Unfortunately we can't really do much better. Fortunately this is rarely + * used (and publicly deprecated). */ + if (write( obj->fd, &value, sizeof(value) ) == -1) + return errno_to_status( errno ); + + /* Try to give other threads a chance to wake up. Hopefully erring on this + * side is the better thing to do... */ + NtYieldExecution(); + + read( obj->fd, &value, sizeof(value) ); + + return STATUS_SUCCESS; +} + NTSTATUS esync_query_event( HANDLE handle, void *info, ULONG *ret_len ) { struct esync *obj; diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h index 18788fa273b..188304f3be7 100644 --- a/dlls/ntdll/unix/esync.h +++ b/dlls/ntdll/unix/esync.h @@ -33,6 +33,7 @@ extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN; extern NTSTATUS esync_open_event( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; +extern NTSTATUS esync_pulse_event( HANDLE handle ) DECLSPEC_HIDDEN; extern NTSTATUS esync_query_event( HANDLE handle, void *info, ULONG *ret_len ) DECLSPEC_HIDDEN; extern NTSTATUS esync_reset_event( HANDLE handle ) DECLSPEC_HIDDEN; extern NTSTATUS esync_set_event( HANDLE handle ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index e8ba76c1e2d..84b217293db 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -509,6 +509,9 @@ NTSTATUS WINAPI NtPulseEvent( HANDLE handle, LONG *prev_state ) { unsigned int ret; + if (do_esync()) + return esync_pulse_event( handle ); + SERVER_START_REQ( event_op ) { req->handle = wine_server_obj_handle( handle ); From 1abb2bfd635f192afa8014e232646b616987c145 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 19 Aug 2018 13:40:05 -0500 Subject: [PATCH 0056/2777] esync: Update README. Wine-Staging: eventfd_synchronization --- README.esync | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.esync b/README.esync index b64bfefc1a3..11d86563a10 100644 --- a/README.esync +++ b/README.esync @@ -1,6 +1,5 @@ This is eventfd-based synchronization, or 'esync' for short. Turn it on with -WINEESYNC=1 (note that it checks the presence and not the value); debug it -with +esync. +WINEESYNC=1; debug it with +esync. == BUGS AND LIMITATIONS == From 0d36933e540c3f9b4949579c388d335992e1b34a Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 24 Apr 2019 23:21:25 -0500 Subject: [PATCH 0057/2777] server: Create esync file descriptors for true file objects and use them for directory change notifications. Wine-Staging: eventfd_synchronization --- server/change.c | 2 +- server/fd.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/server/change.c b/server/change.c index e080511bb23..5e9d94720a5 100644 --- a/server/change.c +++ b/server/change.c @@ -112,7 +112,7 @@ static const struct object_ops dir_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ - NULL, /* get_esync_fd */ + default_fd_get_esync_fd, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ dir_get_fd, /* get_fd */ diff --git a/server/fd.c b/server/fd.c index 0ca28ec40aa..fc3fb83e61b 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1719,6 +1719,9 @@ static struct fd *alloc_fd_object(void) list_init( &fd->inode_entry ); list_init( &fd->locks ); + if (do_esync()) + fd->esync_fd = esync_create_fd( 1, 0 ); + if ((fd->poll_index = add_poll_user( fd )) == -1) { release_object( fd ); From 66dde672084bf2429d80b03fb72947f153cc0355 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 18:01:32 -0500 Subject: [PATCH 0058/2777] ntdll, server: Abandon esync mutexes on thread exit. Wine-Staging: eventfd_synchronization --- dlls/ntdll/unix/esync.c | 31 ++++++++++++++++++++++++++----- server/esync.c | 25 +++++++++++++++++++++++++ server/esync.h | 1 + server/thread.c | 2 ++ 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index a52622de8ec..7871122e5a1 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -708,7 +708,7 @@ NTSTATUS esync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) out->CurrentCount = 1 - mutex->count; out->OwnedByCaller = (mutex->tid == GetCurrentThreadId()); - out->AbandonedState = FALSE; + out->AbandonedState = (mutex->tid == ~0); if (ret_len) *ret_len = sizeof(*out); return STATUS_SUCCESS; @@ -758,14 +758,19 @@ static int do_poll( struct pollfd *fds, nfds_t nfds, ULONGLONG *end ) return ret; } -static void update_grabbed_object( struct esync *obj ) +/* Return TRUE if abandoned. */ +static BOOL update_grabbed_object( struct esync *obj ) { + BOOL ret = FALSE; + if (obj->type == ESYNC_MUTEX) { struct mutex *mutex = obj->shm; /* We don't have to worry about a race between this and read(); the * fact that we grabbed it means the count is now zero, so nobody else * can (and the only thread that can release it is us). */ + if (mutex->tid == ~0) + ret = TRUE; mutex->tid = GetCurrentThreadId(); mutex->count++; } @@ -786,6 +791,8 @@ static void update_grabbed_object( struct esync *obj ) * This might already be 0, but that's okay! */ event->signaled = 0; } + + return ret; } /* A value of STATUS_NOT_IMPLEMENTED returned from this function means that we @@ -905,7 +912,13 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA { if ((size = read( obj->fd, &value, sizeof(value) )) == sizeof(value)) { - TRACE("Woken up by handle %p [%d].\n", handles[i], i); + if (mutex->tid == ~0) + { + TRACE("Woken up by abandoned mutex %p [%d].\n", handles[i], i); + i += STATUS_ABANDONED_WAIT_0; + } + else + TRACE("Woken up by handle %p [%d].\n", handles[i], i); mutex->tid = GetCurrentThreadId(); mutex->count++; return i; @@ -1018,7 +1031,8 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA { /* We found our object. */ TRACE("Woken up by handle %p [%d].\n", handles[i], i); - update_grabbed_object( obj ); + if (update_grabbed_object( obj )) + return STATUS_ABANDONED_WAIT_0 + i; return i; } } @@ -1111,6 +1125,8 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA ret = poll( fds, pollcount, 0 ); if (ret == pollcount) { + BOOL abandoned = FALSE; + /* Quick, grab everything. */ for (i = 0; i < count; i++) { @@ -1151,8 +1167,13 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA /* Make sure to let ourselves know that we grabbed the mutexes * and semaphores. */ for (i = 0; i < count; i++) - update_grabbed_object( objs[i] ); + abandoned |= update_grabbed_object( objs[i] ); + if (abandoned) + { + TRACE("Wait successful, but some object(s) were abandoned.\n"); + return STATUS_ABANDONED; + } TRACE("Wait successful.\n"); return STATUS_SUCCESS; } diff --git a/server/esync.c b/server/esync.c index 20ea97869e9..e193f61b3a7 100644 --- a/server/esync.c +++ b/server/esync.c @@ -103,12 +103,15 @@ void esync_init(void) atexit( shm_cleanup ); } +static struct list mutex_list = LIST_INIT(mutex_list); + struct esync { struct object obj; /* object header */ int fd; /* eventfd file descriptor */ enum esync_type type; unsigned int shm_idx; /* index into the shared memory section */ + struct list mutex_entry; /* entry in the mutex list (if applicable) */ }; static void esync_dump( struct object *obj, int verbose ); @@ -168,6 +171,8 @@ static unsigned int esync_map_access( struct object *obj, unsigned int access ) static void esync_destroy( struct object *obj ) { struct esync *esync = (struct esync *)obj; + if (esync->type == ESYNC_MUTEX) + list_remove( &esync->mutex_entry ); close( esync->fd ); } @@ -303,6 +308,7 @@ struct esync *create_esync( struct object *root, const struct unicode_str *name, struct mutex *mutex = get_shm( esync->shm_idx ); mutex->tid = initval ? 0 : current->id; mutex->count = initval ? 0 : 1; + list_add_tail( &mutex_list, &esync->mutex_entry ); break; } default: @@ -449,6 +455,25 @@ void esync_reset_event( struct esync *esync ) } } +void esync_abandon_mutexes( struct thread *thread ) +{ + struct esync *esync; + + LIST_FOR_EACH_ENTRY( esync, &mutex_list, struct esync, mutex_entry ) + { + struct mutex *mutex = get_shm( esync->shm_idx ); + + if (mutex->tid == thread->id) + { + if (debug_level) + fprintf( stderr, "esync_abandon_mutexes() fd=%d\n", esync->fd ); + mutex->tid = ~0; + mutex->count = 0; + esync_wake_fd( esync->fd ); + } + } +} + DECL_HANDLER(create_esync) { struct esync *esync; diff --git a/server/esync.h b/server/esync.h index e1588d205d9..d39f4efa3ec 100644 --- a/server/esync.h +++ b/server/esync.h @@ -32,3 +32,4 @@ struct esync; extern const struct object_ops esync_ops; void esync_set_event( struct esync *esync ); void esync_reset_event( struct esync *esync ); +void esync_abandon_mutexes( struct thread *thread ); diff --git a/server/thread.c b/server/thread.c index c41b42fb478..165393293de 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1323,6 +1323,8 @@ void kill_thread( struct thread *thread, int violent_death ) } kill_console_processes( thread, 0 ); abandon_mutexes( thread ); + if (do_esync()) + esync_abandon_mutexes( thread ); wake_up( &thread->obj, 0 ); if (violent_death) send_thread_signal( thread, SIGQUIT ); cleanup_thread( thread ); From 5f4f398928e22592f6e5231f693e6a2a31284911 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 17 Oct 2020 19:13:16 -0500 Subject: [PATCH 0059/2777] server: Create esync file descriptors for console servers. Wine-Staging: eventfd_synchronization --- server/console.c | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/server/console.c b/server/console.c index ae5d84f7a06..3f9c0ce356c 100644 --- a/server/console.c +++ b/server/console.c @@ -41,6 +41,7 @@ #include "wincon.h" #include "winternl.h" #include "wine/condrv.h" +#include "esync.h" struct screen_buffer; @@ -131,20 +132,22 @@ struct console_host_ioctl struct console_server { - struct object obj; /* object header */ - struct fd *fd; /* pseudo-fd for ioctls */ - struct console *console; /* attached console */ - struct list queue; /* ioctl queue */ - struct list read_queue; /* blocking read queue */ + struct object obj; /* object header */ + struct fd *fd; /* pseudo-fd for ioctls */ + struct console *console; /* attached console */ + struct list queue; /* ioctl queue */ + struct list read_queue; /* blocking read queue */ unsigned int busy : 1; /* flag if server processing an ioctl */ unsigned int once_input : 1; /* flag if input thread has already been requested */ - int term_fd; /* UNIX terminal fd */ - struct termios termios; /* original termios */ + int term_fd; /* UNIX terminal fd */ + struct termios termios; /* original termios */ + int esync_fd; }; static void console_server_dump( struct object *obj, int verbose ); static void console_server_destroy( struct object *obj ); static int console_server_signaled( struct object *obj, struct wait_queue_entry *entry ); +static int console_server_get_esync_fd( struct object *obj, enum esync_type *type ); static struct fd *console_server_get_fd( struct object *obj ); static struct object *console_server_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attr, struct object *root ); @@ -159,7 +162,7 @@ static const struct object_ops console_server_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ console_server_signaled, /* signaled */ - NULL, /* get_esync_fd */ + console_server_get_esync_fd, /* get_esync_fd */ no_satisfied, /* satisfied */ no_signal, /* signal */ console_server_get_fd, /* get_fd */ @@ -597,6 +600,8 @@ static void disconnect_console_server( struct console_server *server ) list_remove( &call->entry ); console_host_ioctl_terminate( call, STATUS_CANCELLED ); } + if (do_esync()) + esync_clear( server->esync_fd ); while (!list_empty( &server->read_queue )) { struct console_host_ioctl *call = LIST_ENTRY( list_head( &server->read_queue ), struct console_host_ioctl, entry ); @@ -877,6 +882,7 @@ static void console_server_destroy( struct object *obj ) assert( obj->ops == &console_server_ops ); disconnect_console_server( server ); if (server->fd) release_object( server->fd ); + if (do_esync()) close( server->esync_fd ); } static struct object *console_server_lookup_name( struct object *obj, struct unicode_str *name, @@ -918,6 +924,13 @@ static int console_server_signaled( struct object *obj, struct wait_queue_entry return !server->console || !list_empty( &server->queue ); } +static int console_server_get_esync_fd( struct object *obj, enum esync_type *type ) +{ + struct console_server *server = (struct console_server*)obj; + *type = ESYNC_MANUAL_SERVER; + return server->esync_fd; +} + static struct fd *console_server_get_fd( struct object* obj ) { struct console_server *server = (struct console_server*)obj; @@ -949,6 +962,10 @@ static struct object *create_console_server( void ) return NULL; } allow_fd_caching(server->fd); + server->esync_fd = -1; + + if (do_esync()) + server->esync_fd = esync_create_fd( 0, 0 ); return &server->obj; } @@ -1562,6 +1579,8 @@ DECL_HANDLER(get_next_console_request) /* set result of previous ioctl */ ioctl = LIST_ENTRY( list_head( &server->queue ), struct console_host_ioctl, entry ); list_remove( &ioctl->entry ); + if (do_esync() && list_empty( &server->queue )) + esync_clear( server->esync_fd ); } if (ioctl) @@ -1647,6 +1666,8 @@ DECL_HANDLER(get_next_console_request) { set_error( STATUS_PENDING ); } + if (do_esync() && list_empty( &server->queue )) + esync_clear( server->esync_fd ); release_object( server ); } From 9c957f02c0b04d7cc1bc915805ff4e68091f35ac Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Sun, 16 Oct 2016 03:21:42 +0200 Subject: [PATCH 0060/2777] server: Improve STATUS_CANNOT_DELETE checks for directory case. Wine-Staging: server-File_Permissions --- server/fd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/fd.c b/server/fd.c index fc3fb83e61b..91275e0a9d1 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1916,6 +1916,7 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam int root_fd = -1; int rw_mode; char *path; + int created = (flags & O_CREAT); if (((options & FILE_DELETE_ON_CLOSE) && !(access & DELETE)) || ((options & FILE_DIRECTORY_FILE) && (flags & O_TRUNC))) @@ -1954,6 +1955,7 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam file_set_error(); goto error; } + created = 0; } flags &= ~(O_CREAT | O_EXCL | O_TRUNC); } @@ -2036,7 +2038,7 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam } /* can't unlink files if we don't have permission to access */ - if ((options & FILE_DELETE_ON_CLOSE) && !(flags & O_CREAT) && + if ((options & FILE_DELETE_ON_CLOSE) && !created && !(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) { set_error( STATUS_CANNOT_DELETE ); From 62d33cd68b72e3ee2266a5d72c4a9197764fab47 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Fri, 3 Apr 2015 03:58:47 +0200 Subject: [PATCH 0061/2777] server: Allow to open files without any permission bits. (try 2) Changes in v2: * As suggested by Piotr, fix the problem for both files and directories. * Pay attention to requested access attributes - this fixes a couple more todo_wine's. Wine-Staging: server-File_Permissions --- dlls/advapi32/tests/security.c | 32 ++++++++++++-------------------- server/fd.c | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index 8b4a868ee11..686d1aa71de 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -3782,17 +3782,13 @@ static void test_CreateDirectoryA(void) error = pGetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, (PSID *)&owner, NULL, &pDacl, NULL, &pSD); - todo_wine ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %ld\n", error); - if (error == ERROR_SUCCESS) - { - bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); - ok(bret, "GetAclInformation failed\n"); - todo_wine - ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%ld != 0).\n", - acl_size.AceCount); - LocalFree(pSD); - } + bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); + ok(bret, "GetAclInformation failed\n"); + todo_wine + ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%ld != 0).\n", + acl_size.AceCount); + LocalFree(pSD); CloseHandle(hTemp); /* Test inheritance of ACLs in NtCreateFile without security descriptor */ @@ -3861,17 +3857,13 @@ static void test_CreateDirectoryA(void) error = pGetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, (PSID *)&owner, NULL, &pDacl, NULL, &pSD); - todo_wine ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %ld\n", error); - if (error == ERROR_SUCCESS) - { - bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); - ok(bret, "GetAclInformation failed\n"); - todo_wine - ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%ld != 0).\n", - acl_size.AceCount); - LocalFree(pSD); - } + bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); + ok(bret, "GetAclInformation failed\n"); + todo_wine + ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%ld != 0).\n", + acl_size.AceCount); + LocalFree(pSD); CloseHandle(hTemp); done: diff --git a/server/fd.c b/server/fd.c index 91275e0a9d1..4ec27fcdd9c 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1916,6 +1916,7 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam int root_fd = -1; int rw_mode; char *path; + int do_chmod = 0; int created = (flags & O_CREAT); if (((options & FILE_DELETE_ON_CLOSE) && !(access & DELETE)) || @@ -1975,6 +1976,23 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam if ((access & FILE_UNIX_WRITE_ACCESS) || (flags & O_CREAT)) fd->unix_fd = open( name, O_RDONLY | (flags & ~(O_TRUNC | O_CREAT | O_EXCL)), *mode ); } + else if (errno == EACCES) + { + /* try to change permissions temporarily to open a file descriptor */ + if (!(access & (FILE_UNIX_WRITE_ACCESS | FILE_UNIX_READ_ACCESS | DELETE)) && + !stat( name, &st ) && st.st_uid == getuid() && + !chmod( name, st.st_mode | S_IRUSR )) + { + fd->unix_fd = open( name, O_RDONLY | (flags & ~(O_TRUNC | O_CREAT | O_EXCL)), *mode ); + *mode = st.st_mode; + do_chmod = 1; + } + else + { + set_error( STATUS_ACCESS_DENIED ); + goto error; + } + } if (fd->unix_fd == -1) { @@ -1983,6 +2001,8 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam set_error( STATUS_OBJECT_NAME_INVALID ); else file_set_error(); + + if (do_chmod) chmod( name, *mode ); goto error; } } @@ -1998,6 +2018,7 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam closed_fd->unix_fd = fd->unix_fd; closed_fd->unlink = 0; closed_fd->unix_name = fd->unix_name; + if (do_chmod) chmod( name, *mode ); fstat( fd->unix_fd, &st ); *mode = st.st_mode; From 6b67d8b1c05f51548178eff2e40c48b672ed2c4f Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Fri, 3 Apr 2015 03:58:53 +0200 Subject: [PATCH 0062/2777] server: When creating new directories temporarily give read-permissions until they are opened. Wine-Staging: server-File_Permissions --- server/fd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/fd.c b/server/fd.c index 4ec27fcdd9c..414b6411a78 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1949,7 +1949,12 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam /* create the directory if needed */ if ((options & FILE_DIRECTORY_FILE) && (flags & O_CREAT)) { - if (mkdir( name, *mode ) == -1) + if (mkdir( name, *mode | S_IRUSR ) != -1) + { + /* remove S_IRUSR later, after we have opened the directory */ + do_chmod = !(*mode & S_IRUSR); + } + else { if (errno != EEXIST || (flags & O_EXCL)) { From 97bb25af8bf04d38d71464e57fda078b519ba63c Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Fri, 3 Apr 2015 03:58:59 +0200 Subject: [PATCH 0063/2777] advapi32/tests: Add tests for ACL inheritance in CreateDirectoryA. Wine-Staging: server-File_Permissions --- dlls/advapi32/tests/security.c | 70 ++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index 686d1aa71de..949f70f8ae4 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -3866,6 +3866,76 @@ static void test_CreateDirectoryA(void) LocalFree(pSD); CloseHandle(hTemp); + /* Test inheritance of ACLs in CreateDirectory without security descriptor */ + strcpy(tmpfile, tmpdir); + lstrcatA(tmpfile, "/tmpdir"); + bret = CreateDirectoryA(tmpfile, NULL); + ok(bret == TRUE, "CreateDirectoryA failed with error %u\n", GetLastError()); + + error = pGetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + (PSID *)&owner, NULL, &pDacl, NULL, &pSD); + ok(error == ERROR_SUCCESS, "Failed to get permissions on file\n"); + test_inherited_dacl(pDacl, admin_sid, user_sid, + OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERITED_ACE, + 0x1f01ff, TRUE, TRUE, TRUE, __LINE__); + LocalFree(pSD); + bret = RemoveDirectoryA(tmpfile); + ok(bret == TRUE, "RemoveDirectoryA failed with error %u\n", GetLastError()); + + /* Test inheritance of ACLs in CreateDirectory with security descriptor */ + pSD = &sd; + InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION); + pDacl = HeapAlloc(GetProcessHeap(), 0, sizeof(ACL)); + bret = InitializeAcl(pDacl, sizeof(ACL), ACL_REVISION); + ok(bret, "Failed to initialize ACL\n"); + bret = SetSecurityDescriptorDacl(pSD, TRUE, pDacl, FALSE); + ok(bret, "Failed to add ACL to security desciptor\n"); + + strcpy(tmpfile, tmpdir); + lstrcatA(tmpfile, "/tmpdir1"); + + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = pSD; + sa.bInheritHandle = TRUE; + bret = CreateDirectoryA(tmpfile, &sa); + ok(bret == TRUE, "CreateDirectoryA failed with error %u\n", GetLastError()); + HeapFree(GetProcessHeap(), 0, pDacl); + + error = pGetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + (PSID *)&owner, NULL, &pDacl, NULL, &pSD); + ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %d\n", error); + bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); + ok(bret, "GetAclInformation failed\n"); + todo_wine + ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%d != 0).\n", + acl_size.AceCount); + LocalFree(pSD); + + SetLastError(0xdeadbeef); + bret = RemoveDirectoryA(tmpfile); + error = GetLastError(); + ok(bret == FALSE, "RemoveDirectoryA unexpected succeeded\n"); + ok(error == ERROR_ACCESS_DENIED, "expected ERROR_ACCESS_DENIED, got %u\n", error); + + pSD = &sd; + InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION); + pDacl = HeapAlloc(GetProcessHeap(), 0, 100); + bret = InitializeAcl(pDacl, 100, ACL_REVISION); + ok(bret, "Failed to initialize ACL.\n"); + bret = pAddAccessAllowedAceEx(pDacl, ACL_REVISION, 0, GENERIC_ALL, user_sid); + ok(bret, "Failed to add Current User to ACL.\n"); + bret = SetSecurityDescriptorDacl(pSD, TRUE, pDacl, FALSE); + ok(bret, "Failed to add ACL to security desciptor.\n"); + error = pSetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, + NULL, pDacl, NULL); + ok(error == ERROR_SUCCESS, "SetNamedSecurityInfoA failed with error %u\n", error); + HeapFree(GetProcessHeap(), 0, pDacl); + + bret = RemoveDirectoryA(tmpfile); + ok(bret == TRUE, "RemoveDirectoryA failed with error %u\n", GetLastError()); + done: HeapFree(GetProcessHeap(), 0, user); bret = RemoveDirectoryA(tmpdir); From bcfe3c911852abf00022d00b1717a1d8e43b1442 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Fri, 3 Apr 2015 03:59:05 +0200 Subject: [PATCH 0064/2777] advapi32/tests: Add ACL inheritance tests for creating subdirectories with NtCreateFile. Wine-Staging: server-File_Permissions --- dlls/advapi32/tests/security.c | 76 ++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index 949f70f8ae4..c0fea3c5507 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -3936,6 +3936,82 @@ static void test_CreateDirectoryA(void) bret = RemoveDirectoryA(tmpfile); ok(bret == TRUE, "RemoveDirectoryA failed with error %u\n", GetLastError()); + /* Test inheritance of ACLs in NtCreateFile(..., FILE_DIRECTORY_FILE, ...) without security descriptor */ + strcpy(tmpfile, tmpdir); + lstrcatA(tmpfile, "/tmpdir"); + get_nt_pathW(tmpfile, &tmpfileW); + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &tmpfileW; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + status = pNtCreateFile(&hTemp, GENERIC_READ | DELETE, &attr, &io, NULL, FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, FILE_CREATE, FILE_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE, NULL, 0); + ok(!status, "NtCreateFile failed with %08x\n", status); + RtlFreeUnicodeString(&tmpfileW); + + error = pGetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + (PSID *)&owner, NULL, &pDacl, NULL, &pSD); + ok(error == ERROR_SUCCESS, "Failed to get permissions on file\n"); + test_inherited_dacl(pDacl, admin_sid, user_sid, + OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERITED_ACE, + 0x1f01ff, TRUE, TRUE, TRUE, __LINE__); + LocalFree(pSD); + CloseHandle(hTemp); + + /* Test inheritance of ACLs in NtCreateFile(..., FILE_DIRECTORY_FILE, ...) with security descriptor */ + pSD = &sd; + InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION); + pDacl = HeapAlloc(GetProcessHeap(), 0, sizeof(ACL)); + bret = InitializeAcl(pDacl, sizeof(ACL), ACL_REVISION); + ok(bret, "Failed to initialize ACL\n"); + bret = SetSecurityDescriptorDacl(pSD, TRUE, pDacl, FALSE); + ok(bret, "Failed to add ACL to security desciptor\n"); + + strcpy(tmpfile, tmpdir); + lstrcatA(tmpfile, "/tmpdir2"); + get_nt_pathW(tmpfile, &tmpfileW); + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &tmpfileW; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.SecurityDescriptor = pSD; + attr.SecurityQualityOfService = NULL; + + status = pNtCreateFile(&hTemp, GENERIC_READ | DELETE, &attr, &io, NULL, FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, FILE_CREATE, FILE_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE, NULL, 0); + ok(!status, "NtCreateFile failed with %08x\n", status); + RtlFreeUnicodeString(&tmpfileW); + HeapFree(GetProcessHeap(), 0, pDacl); + + error = GetSecurityInfo(hTemp, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + (PSID *)&owner, NULL, &pDacl, NULL, &pSD); + ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %d\n", error); + bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); + ok(bret, "GetAclInformation failed\n"); + todo_wine + ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%d != 0).\n", + acl_size.AceCount); + LocalFree(pSD); + + error = pGetNamedSecurityInfoA(tmpfile, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + (PSID *)&owner, NULL, &pDacl, NULL, &pSD); + ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %d\n", error); + bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); + ok(bret, "GetAclInformation failed\n"); + todo_wine + ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%d != 0).\n", + acl_size.AceCount); + LocalFree(pSD); + CloseHandle(hTemp); + done: HeapFree(GetProcessHeap(), 0, user); bret = RemoveDirectoryA(tmpdir); From 8f5a28f39124cbc53e09f365afb40fb3153adc52 Mon Sep 17 00:00:00 2001 From: Qian Hong Date: Fri, 15 May 2015 15:28:17 +0800 Subject: [PATCH 0065/2777] ntdll/tests: Added tests for open behaviour on readonly files. Wine-Staging: server-File_Permissions --- dlls/ntdll/tests/file.c | 78 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 6186afdfb63..cbbf49ff3cd 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -4338,6 +4338,83 @@ static void test_NtCreateFile(void) RemoveDirectoryW( path ); } +static void test_readonly(void) +{ + static const WCHAR fooW[] = {'f','o','o',0}; + NTSTATUS status; + HANDLE handle; + WCHAR path[MAX_PATH]; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + UNICODE_STRING nameW; + + GetTempPathW(MAX_PATH, path); + GetTempFileNameW(path, fooW, 0, path); + DeleteFileW(path); + pRtlDosPathNameToNtPathName_U(path, &nameW, NULL, NULL); + + attr.Length = sizeof(attr); + attr.RootDirectory = NULL; + attr.ObjectName = &nameW; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + status = pNtCreateFile(&handle, GENERIC_READ, &attr, &io, NULL, FILE_ATTRIBUTE_READONLY, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_CREATE, 0, NULL, 0); + ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, GENERIC_WRITE, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + ok(status == STATUS_ACCESS_DENIED, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, GENERIC_READ, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, FILE_READ_ATTRIBUTES, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, FILE_WRITE_ATTRIBUTES, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + todo_wine ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, DELETE, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, READ_CONTROL, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, WRITE_DAC, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, WRITE_OWNER, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle(handle); + + status = pNtOpenFile(&handle, SYNCHRONIZE, &attr, &io, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); + ok(status == STATUS_SUCCESS, "got %#x\n", status); + CloseHandle( handle ); + + pRtlFreeUnicodeString(&nameW); + SetFileAttributesW(path, FILE_ATTRIBUTE_ARCHIVE); + DeleteFileW(path); +} + static void test_read_write(void) { static const char contents[14] = "1234567890abcd"; @@ -5478,6 +5555,7 @@ START_TEST(file) test_read_write(); test_NtCreateFile(); + test_readonly(); create_file_test(); open_file_test(); delete_file_test(); From 4e12a1656d439044812e70a716e485767886049b Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Wed, 3 Jun 2015 05:43:31 +0200 Subject: [PATCH 0066/2777] server: FILE_WRITE_ATTRIBUTES should succeed for readonly files. Wine-Staging: server-File_Permissions --- dlls/ntdll/tests/file.c | 2 +- server/fd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index cbbf49ff3cd..477be256596 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -4382,7 +4382,7 @@ static void test_readonly(void) status = pNtOpenFile(&handle, FILE_WRITE_ATTRIBUTES, &attr, &io, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, FILE_OPEN_FOR_BACKUP_INTENT); - todo_wine ok(status == STATUS_SUCCESS, "got %#x\n", status); + ok(status == STATUS_SUCCESS, "got %#x\n", status); CloseHandle(handle); status = pNtOpenFile(&handle, DELETE, &attr, &io, diff --git a/server/fd.c b/server/fd.c index 414b6411a78..4d6206f073f 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1984,7 +1984,7 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam else if (errno == EACCES) { /* try to change permissions temporarily to open a file descriptor */ - if (!(access & (FILE_UNIX_WRITE_ACCESS | FILE_UNIX_READ_ACCESS | DELETE)) && + if (!(access & ((FILE_UNIX_WRITE_ACCESS | FILE_UNIX_READ_ACCESS | DELETE) & ~FILE_WRITE_ATTRIBUTES)) && !stat( name, &st ) && st.st_uid == getuid() && !chmod( name, st.st_mode | S_IRUSR )) { From 890c356dda291442ce73c71976e66f75a75e072d Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Thu, 27 Apr 2017 13:25:04 -0500 Subject: [PATCH 0067/2777] HACK: steam: kernelbase: Substitute the current pid for the Steam client pid. --- dlls/kernelbase/process.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 39de15066d4..6ea1d3f53c2 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -1041,6 +1041,21 @@ HANDLE WINAPI DECLSPEC_HOTPATCH OpenProcess( DWORD access, BOOL inherit, DWORD i attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; + /* PROTON HACK: + * On Windows, the Steam client puts its process ID into the registry + * at: + * + * [HKCU\Software\Valve\Steam\ActiveProcess] + * PID=dword:00000008 + * + * Games get that pid from the registry and then query it with + * OpenProcess to ensure Steam is running. Since we aren't running the + * Windows Steam in Wine, instead we hack this magic number into the + * registry and then substitute the game's process itself in its place + * so it can query a valid process. + */ + if (id == 0xfffe) id = GetCurrentProcessId(); + cid.UniqueProcess = ULongToHandle(id); cid.UniqueThread = 0; From 5b5785001537dea33fb3aa93b0e0d0a6e4c9b794 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 13 Jun 2017 12:35:56 -0500 Subject: [PATCH 0068/2777] HACK: steam: ntdll: Append C:/Program Files (x86)/Steam to PATH. --- dlls/ntdll/loader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 61aeb25898b..81aca02ab40 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -85,7 +85,7 @@ const WCHAR windows_dir[] = L"C:\\windows"; const WCHAR system_dir[] = L"C:\\windows\\system32\\"; /* system search path */ -static const WCHAR system_path[] = L"C:\\windows\\system32;C:\\windows\\system;C:\\windows"; +static const WCHAR system_path[] = L"C:\\windows\\system32;C:\\windows\\system;C:\\windows;C:\\Program Files (x86)\\Steam"; static BOOL is_prefix_bootstrap; /* are we bootstrapping the prefix? */ static BOOL imports_fixup_done = FALSE; /* set once the imports have been fixed up, before attaching them */ From 92cccd853a8f66c59de9e9eeb2bb76105c147ad6 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Wed, 27 Dec 2017 13:31:59 -0600 Subject: [PATCH 0069/2777] HACK: steam: wine.inf: Add required Steam registry entries. --- loader/wine.inf.in | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index f1525c4f6dd..fdb0161f75d 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -95,7 +95,8 @@ AddReg=\ Tapi,\ ThemeManager,\ VersionInfo,\ - LicenseInformation + LicenseInformation, \ + SteamClient [DefaultInstall.ntamd64] RegisterDlls=RegisterDllsSection @@ -120,7 +121,8 @@ AddReg=\ Tapi,\ ThemeManager,\ VersionInfo.ntamd64,\ - LicenseInformation + LicenseInformation, \ + SteamClient.ntamd64 [DefaultInstall.ntarm64] RegisterDlls=RegisterDllsSection @@ -160,7 +162,8 @@ AddReg=\ Misc,\ Tapi,\ VersionInfo.ntamd64,\ - LicenseInformation + LicenseInformation, \ + SteamClient.ntamd64 [Wow64Install.ntarm64] WineFakeDlls=FakeDllsWin32 @@ -2672,3 +2675,19 @@ EtcFiles = 12,etc InfFiles = 17 NlsFiles = 11 SortFiles = 10,globalization\sorting + +[SteamClient] +HKCU,Software\Valve\Steam,"SteamPath",,"%16422%\Steam" +HKCU,Software\Valve\Steam,"SteamExe",,"%16422%\Steam\Steam.exe" +HKCU,Software\Valve\Steam\ActiveProcess,"PID",0x10001,0x0000fffe +HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll",,"%16422%\Steam\steamclient.dll" +HKCU,Software\Valve\Steam\ActiveProcess,"SteamPath",,"%16422%\Steam" + +[SteamClient.ntamd64] +HKCU,Software\Valve\Steam,"SteamPath",,"%16422%\Steam" +HKCU,Software\Valve\Steam,"SteamExe",,"%16422%\Steam\Steam.exe" +HKCU,Software\Valve\Steam\ActiveProcess,"PID",0x10001,0x0000fffe +HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll",,"%16426%\Steam\steamclient.dll" +HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll64",,"%16426%\Steam\steamclient64.dll" +HKCU,Software\Valve\Steam\ActiveProcess,"SteamPath",,"%16426%\Steam" +HKLM,Software\Wow6432Node\Valve\Steam,"InstallPath",,"%16422%\Steam" From 53ba023e0a3638123c1ae64a070b45b76fdedece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Nov 2022 11:02:52 +0100 Subject: [PATCH 0070/2777] HACK: steam: ntdll: Setup steamclient trampolines to lsteamclient. This uses exec page faults to jump from native steamclient into our lsteamclient entry points. --- dlls/ntdll/loader.c | 23 +++++++++++ dlls/ntdll/unix/loader.c | 71 +++++++++++++++++++++++++++++++++ dlls/ntdll/unix/signal_i386.c | 7 ++++ dlls/ntdll/unix/signal_x86_64.c | 7 ++++ dlls/ntdll/unix/unix_private.h | 3 ++ dlls/ntdll/unixlib.h | 7 ++++ 6 files changed, 118 insertions(+) diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 81aca02ab40..327979dfe40 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -2107,12 +2107,16 @@ static NTSTATUS build_module( LPCWSTR load_path, const UNICODE_STRING *nt_name, DWORD flags, BOOL system, WINE_MODREF **pwm ) { static const char builtin_signature[] = "Wine builtin DLL"; + static HMODULE lsteamclient = NULL; char *signature = (char *)((IMAGE_DOS_HEADER *)*module + 1); + UNICODE_STRING lsteamclient_us; BOOL is_builtin; IMAGE_NT_HEADERS *nt; WINE_MODREF *wm; NTSTATUS status; SIZE_T map_size; + WCHAR *basename, *tmp; + ULONG basename_len; if (!(nt = RtlImageNtHeader( *module ))) return STATUS_INVALID_IMAGE_FORMAT; @@ -2133,6 +2137,25 @@ static NTSTATUS build_module( LPCWSTR load_path, const UNICODE_STRING *nt_name, set_security_cookie( *module, map_size ); + basename = nt_name->Buffer; + if ((tmp = wcsrchr(basename, '\\'))) basename = tmp + 1; + if ((tmp = wcsrchr(basename, '/'))) basename = tmp + 1; + basename_len = wcslen(basename); + if (basename_len >= 4 && !wcscmp(basename + basename_len - 4, L".dll")) basename_len -= 4; + + if ((!RtlCompareUnicodeStrings(basename, basename_len, L"steamclient", 11, TRUE) || + !RtlCompareUnicodeStrings(basename, basename_len, L"steamclient64", 13, TRUE) || + !RtlCompareUnicodeStrings(basename, basename_len, L"gameoverlayrenderer", 19, TRUE) || + !RtlCompareUnicodeStrings(basename, basename_len, L"gameoverlayrenderer64", 21, TRUE)) && + RtlCreateUnicodeStringFromAsciiz(&lsteamclient_us, "lsteamclient.dll") && + (lsteamclient || LdrLoadDll(load_path, 0, &lsteamclient_us, &lsteamclient) == STATUS_SUCCESS)) + { + struct steamclient_setup_trampolines_params params = {.src_mod = *module, .tgt_mod = lsteamclient}; + NTDLL_UNIX_CALL( steamclient_setup_trampolines, ¶ms ); + wm->ldr.Flags |= LDR_DONT_RESOLVE_REFS; + flags |= DONT_RESOLVE_DLL_REFERENCES; + } + /* fixup imports */ if (!(flags & DONT_RESOLVE_DLL_REFERENCES) && diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index a675adea3e3..cf532b236ad 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2043,6 +2043,76 @@ static ULONG_PTR get_image_address(void) } +static void *steamclient_srcs[128]; +static void *steamclient_tgts[128]; +static int steamclient_count; + +void *steamclient_handle_fault( LPCVOID addr, DWORD err ) +{ + int i; + + if (!(err & EXCEPTION_EXECUTE_FAULT)) return NULL; + + for (i = 0; i < steamclient_count; ++i) + { + if (addr == steamclient_srcs[i]) + return steamclient_tgts[i]; + } + + return NULL; +} + +static NTSTATUS steamclient_setup_trampolines( void *args ) +{ + struct steamclient_setup_trampolines_params *params = args; + HMODULE src_mod = params->src_mod, tgt_mod = params->tgt_mod; + SYSTEM_BASIC_INFORMATION info; + IMAGE_NT_HEADERS *src_nt = (IMAGE_NT_HEADERS *)((UINT_PTR)src_mod + ((IMAGE_DOS_HEADER *)src_mod)->e_lfanew); + IMAGE_NT_HEADERS *tgt_nt = (IMAGE_NT_HEADERS *)((UINT_PTR)tgt_mod + ((IMAGE_DOS_HEADER *)tgt_mod)->e_lfanew); + IMAGE_SECTION_HEADER *src_sec = (IMAGE_SECTION_HEADER *)(src_nt + 1); + const IMAGE_EXPORT_DIRECTORY *src_exp, *tgt_exp; + const DWORD *names; + SIZE_T size; + void *addr, *src_addr, *tgt_addr; + char *name; + UINT_PTR page_mask; + int i; + + virtual_get_system_info( &info, !!NtCurrentTeb()->WowTebOffset ); + page_mask = info.PageSize - 1; + + for (i = 0; i < src_nt->FileHeader.NumberOfSections; ++i) + { + if (memcmp(src_sec[i].Name, ".text", 5)) continue; + addr = (void *)(((UINT_PTR)src_mod + src_sec[i].VirtualAddress) & ~page_mask); + size = (src_sec[i].Misc.VirtualSize + page_mask) & ~page_mask; + mprotect(addr, size, PROT_READ); + } + + src_exp = get_module_data_dir( src_mod, IMAGE_FILE_EXPORT_DIRECTORY, NULL ); + tgt_exp = get_module_data_dir( tgt_mod, IMAGE_FILE_EXPORT_DIRECTORY, NULL ); + names = (const DWORD *)((UINT_PTR)src_mod + src_exp->AddressOfNames); + for (i = 0; i < src_exp->NumberOfNames; ++i) + { + if (!names[i] || !(name = (char *)((UINT_PTR)src_mod + names[i]))) continue; + if (!(src_addr = (void *)find_named_export(src_mod, src_exp, name))) continue; + if (!(tgt_addr = (void *)find_named_export(tgt_mod, tgt_exp, name))) continue; + assert(steamclient_count < ARRAY_SIZE(steamclient_srcs)); + steamclient_srcs[steamclient_count] = src_addr; + steamclient_tgts[steamclient_count] = tgt_addr; + steamclient_count++; + } + + src_addr = (void *)((UINT_PTR)src_mod + src_nt->OptionalHeader.AddressOfEntryPoint); + tgt_addr = (void *)((UINT_PTR)tgt_mod + tgt_nt->OptionalHeader.AddressOfEntryPoint); + assert(steamclient_count < ARRAY_SIZE(steamclient_srcs)); + steamclient_srcs[steamclient_count] = src_addr; + steamclient_tgts[steamclient_count] = tgt_addr; + steamclient_count++; + + return STATUS_SUCCESS; +} + /*********************************************************************** * __wine_unix_call_funcs */ @@ -2051,6 +2121,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = load_so_dll, unwind_builtin_dll, system_time_precise, + steamclient_setup_trampolines, }; diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index d800885748f..aa0f10d5bfa 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1859,6 +1859,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) struct xcontext xcontext; ucontext_t *ucontext = sigcontext; void *stack = setup_exception_record( sigcontext, &rec, &xcontext ); + void *steamclient_addr = NULL; switch (TRAP_sig(ucontext)) { @@ -1893,6 +1894,12 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) } break; case TRAP_x86_PAGEFLT: /* Page fault */ + if ((steamclient_addr = steamclient_handle_fault( siginfo->si_addr, (ERROR_sig(ucontext) >> 1) & 0x09 ))) + { + EIP_sig(ucontext) = (intptr_t)steamclient_addr; + return; + } + rec.NumberParameters = 2; rec.ExceptionInformation[0] = (ERROR_sig(ucontext) >> 1) & 0x09; rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr; diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 94d79b9cdd1..b369988b85c 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1966,6 +1966,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) EXCEPTION_RECORD rec = { 0 }; struct xcontext context; ucontext_t *ucontext = sigcontext; + void *steamclient_addr = NULL; rec.ExceptionAddress = (void *)RIP_sig(ucontext); save_context( &context, sigcontext ); @@ -1997,6 +1998,12 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) } break; case TRAP_x86_PAGEFLT: /* Page fault */ + if ((steamclient_addr = steamclient_handle_fault( siginfo->si_addr, (ERROR_sig(ucontext) >> 1) & 0x09 ))) + { + RIP_sig(ucontext) = (intptr_t)steamclient_addr; + return; + } + rec.NumberParameters = 2; rec.ExceptionInformation[0] = (ERROR_sig(ucontext) >> 1) & 0x09; rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr; diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 347d1dd6102..975ac0b334f 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -197,6 +197,9 @@ extern NTSTATUS system_time_precise( void *args ) DECLSPEC_HIDDEN; extern void *anon_mmap_fixed( void *start, size_t size, int prot, int flags ) DECLSPEC_HIDDEN; extern void *anon_mmap_alloc( size_t size, int prot ) DECLSPEC_HIDDEN; + +extern void *steamclient_handle_fault( LPCVOID addr, DWORD err ) DECLSPEC_HIDDEN; + extern void virtual_init(void) DECLSPEC_HIDDEN; extern ULONG_PTR get_system_affinity_mask(void) DECLSPEC_HIDDEN; extern void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info, BOOL wow64 ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index 0b4c2a984bb..36b0ded3bc9 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -38,11 +38,18 @@ struct unwind_builtin_dll_params CONTEXT *context; }; +struct steamclient_setup_trampolines_params +{ + HMODULE src_mod; + HMODULE tgt_mod; +}; + enum ntdll_unix_funcs { unix_load_so_dll, unix_unwind_builtin_dll, unix_system_time_precise, + unix_steamclient_setup_trampolines, }; extern unixlib_handle_t ntdll_unix_handle; From 92e01e33fe6eb993582ba40e931479d78f4e9d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 5 Aug 2020 10:35:50 +0200 Subject: [PATCH 0071/2777] HACK: steam: ntdll: Patch entry points with jumps. As a preferred alternative to noexec pages which makes debugging painful. The noexec can be enabled with WINESTEAMNOEXEC=1 environmnent variable. --- dlls/ntdll/unix/loader.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index cf532b236ad..3d250b72178 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2062,8 +2062,22 @@ void *steamclient_handle_fault( LPCVOID addr, DWORD err ) return NULL; } +static void steamclient_write_jump(void *src_addr, void *tgt_addr) +{ +#ifdef _WIN64 + static const char mov[] = {0x48, 0xb8}; +#else + static const char mov[] = {0xb8}; +#endif + static const char jmp[] = {0xff, 0xe0}; + memcpy(src_addr, mov, sizeof(mov)); + memcpy((char *)src_addr + sizeof(mov), &tgt_addr, sizeof(tgt_addr)); + memcpy((char *)src_addr + sizeof(mov) + sizeof(tgt_addr), jmp, sizeof(jmp)); +} + static NTSTATUS steamclient_setup_trampolines( void *args ) { + static int noexec_cached = -1; struct steamclient_setup_trampolines_params *params = args; HMODULE src_mod = params->src_mod, tgt_mod = params->tgt_mod; SYSTEM_BASIC_INFORMATION info; @@ -2074,10 +2088,13 @@ static NTSTATUS steamclient_setup_trampolines( void *args ) const DWORD *names; SIZE_T size; void *addr, *src_addr, *tgt_addr; - char *name; + char *name, *wsne; UINT_PTR page_mask; int i; + if (noexec_cached == -1) + noexec_cached = (wsne = getenv("WINESTEAMNOEXEC")) && atoi(wsne); + virtual_get_system_info( &info, !!NtCurrentTeb()->WowTebOffset ); page_mask = info.PageSize - 1; @@ -2086,7 +2103,8 @@ static NTSTATUS steamclient_setup_trampolines( void *args ) if (memcmp(src_sec[i].Name, ".text", 5)) continue; addr = (void *)(((UINT_PTR)src_mod + src_sec[i].VirtualAddress) & ~page_mask); size = (src_sec[i].Misc.VirtualSize + page_mask) & ~page_mask; - mprotect(addr, size, PROT_READ); + if (noexec_cached) mprotect(addr, size, PROT_READ); + else mprotect(addr, size, PROT_READ|PROT_WRITE|PROT_EXEC); } src_exp = get_module_data_dir( src_mod, IMAGE_FILE_EXPORT_DIRECTORY, NULL ); @@ -2100,7 +2118,8 @@ static NTSTATUS steamclient_setup_trampolines( void *args ) assert(steamclient_count < ARRAY_SIZE(steamclient_srcs)); steamclient_srcs[steamclient_count] = src_addr; steamclient_tgts[steamclient_count] = tgt_addr; - steamclient_count++; + if (!noexec_cached) steamclient_write_jump(src_addr, tgt_addr); + else steamclient_count++; } src_addr = (void *)((UINT_PTR)src_mod + src_nt->OptionalHeader.AddressOfEntryPoint); @@ -2108,7 +2127,8 @@ static NTSTATUS steamclient_setup_trampolines( void *args ) assert(steamclient_count < ARRAY_SIZE(steamclient_srcs)); steamclient_srcs[steamclient_count] = src_addr; steamclient_tgts[steamclient_count] = tgt_addr; - steamclient_count++; + if (!noexec_cached) steamclient_write_jump(src_addr, tgt_addr); + else steamclient_count++; return STATUS_SUCCESS; } From a55c9c74a1ddae88ff300fb8b63e9bc7c7b2d266 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 18 May 2020 14:20:30 -0500 Subject: [PATCH 0072/2777] HACK: steam: wine.inf: Associate the steam protocol with steam.exe. For 2K Launcher. CW-Bug-Id: 18912 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index fdb0161f75d..4ed03c90c3e 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -319,6 +319,7 @@ HKCR,ftp\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" HKCR,http\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" HKCR,https\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" HKCR,mailto\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" +HKCR,steam\shell\open\command,,,"""%16426%\Steam\Steam.exe"" -- ""%1""" [ContentIndex] HKLM,System\CurrentControlSet\Control\ContentIndex\Language\Neutral,"WBreakerClass",,"{369647e0-17b0-11ce-9950-00aa004bbb1f}" From 653847dd8d2740ee886648e96a3eb20db6a6cbe7 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Fri, 19 Jan 2018 14:01:07 -0600 Subject: [PATCH 0073/2777] HACK: proton: advapi32: Use steamuser as Wine username. --- dlls/advapi32/advapi.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/dlls/advapi32/advapi.c b/dlls/advapi32/advapi.c index 6b3ffe2ea25..a22e896c88a 100644 --- a/dlls/advapi32/advapi.c +++ b/dlls/advapi32/advapi.c @@ -44,14 +44,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(advapi); */ BOOL WINAPI GetUserNameA( LPSTR name, LPDWORD size ) { - DWORD len = GetEnvironmentVariableA( "WINEUSERNAME", name, *size ); - BOOL ret; - - if (!len) return FALSE; - if ((ret = (len < *size))) len++; - else SetLastError( ERROR_INSUFFICIENT_BUFFER ); - *size = len; - return ret; + static const char steamuserA[] = {'s','t','e','a','m','u','s','e','r',0}; + if(*size < ARRAY_SIZE(steamuserA)){ + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + *size = ARRAY_SIZE(steamuserA); + return FALSE; + } + memcpy(name, steamuserA, sizeof(steamuserA)); + *size = ARRAY_SIZE(steamuserA); + return TRUE; } /****************************************************************************** @@ -59,14 +60,15 @@ BOOL WINAPI GetUserNameA( LPSTR name, LPDWORD size ) */ BOOL WINAPI GetUserNameW( LPWSTR name, LPDWORD size ) { - DWORD len = GetEnvironmentVariableW( L"WINEUSERNAME", name, *size ); - BOOL ret; - - if (!len) return FALSE; - if ((ret = (len < *size))) len++; - else SetLastError( ERROR_INSUFFICIENT_BUFFER ); - *size = len; - return ret; + static const WCHAR steamuserW[] = {'s','t','e','a','m','u','s','e','r',0}; + if(*size < ARRAY_SIZE(steamuserW)){ + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + *size = ARRAY_SIZE(steamuserW); + return FALSE; + } + memcpy(name, steamuserW, sizeof(steamuserW)); + *size = ARRAY_SIZE(steamuserW); + return TRUE; } /****************************************************************************** From f4f4b6245757675dd351ace0db2d11ca31b14049 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Thu, 30 Sep 2021 19:44:00 +0200 Subject: [PATCH 0074/2777] HACK: proton: shell32: Never create links to the user's home dirs. --- dlls/shell32/shellpath.c | 181 --------------------------------------- 1 file changed, 181 deletions(-) diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c index 5dd9f4b6310..6f03a6feb45 100644 --- a/dlls/shell32/shellpath.c +++ b/dlls/shell32/shellpath.c @@ -2639,183 +2639,6 @@ static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest) return hr; } -static char *xdg_config; -static DWORD xdg_config_len; - -static BOOL WINAPI init_xdg_dirs( INIT_ONCE *once, void *param, void **context ) -{ - const WCHAR *var, *fmt = L"\\??\\unix%s/user-dirs.dirs"; - char *p; - WCHAR *name, *ptr; - HANDLE file; - DWORD len; - - if (!(var = _wgetenv( L"XDG_CONFIG_HOME" )) || var[0] != '/') - { - if (!(var = _wgetenv( L"WINEHOMEDIR" ))) return TRUE; - fmt = L"%s/.config/user-dirs.dirs"; - } - len = lstrlenW(var) + lstrlenW(fmt); - name = heap_alloc( len * sizeof(WCHAR) ); - swprintf( name, len, fmt, var ); - name[1] = '\\'; /* change \??\ to \\?\ */ - for (ptr = name; *ptr; ptr++) if (*ptr == '/') *ptr = '\\'; - - file = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); - heap_free( name ); - if (file != INVALID_HANDLE_VALUE) - { - len = GetFileSize( file, NULL ); - if (!(xdg_config = heap_alloc( len + 1 ))) return TRUE; - if (!ReadFile( file, xdg_config, len, &xdg_config_len, NULL )) - { - heap_free( xdg_config ); - xdg_config = NULL; - } - else - { - for (p = xdg_config; p < xdg_config + xdg_config_len; p++) if (*p == '\n') *p = 0; - *p = 0; /* append null to simplify string parsing */ - } - CloseHandle( file ); - } - return TRUE; -} - -static char *get_xdg_path( const char *var ) -{ - static INIT_ONCE once; - char *p, *ret = NULL; - int i; - - InitOnceExecuteOnce( &once, init_xdg_dirs, NULL, NULL ); - if (!xdg_config) return NULL; - - for (p = xdg_config; p < xdg_config + xdg_config_len; p += strlen(p) + 1) - { - while (*p == ' ' || *p == '\t') p++; - if (strncmp( p, var, strlen(var) )) continue; - p += strlen(var); - while (*p == ' ' || *p == '\t') p++; - if (*p != '=') continue; - p++; - while (*p == ' ' || *p == '\t') p++; - if (*p != '"') continue; - p++; - if (*p != '/' && strncmp( p, "$HOME/", 6 )) continue; - - if (!(ret = heap_alloc( strlen(p) + 1 ))) break; - for (i = 0; *p && *p != '"'; i++, p++) - { - if (*p == '\\' && p[1]) p++; - ret[i] = *p; - } - ret[i] = 0; - if (*p != '"') - { - heap_free( ret ); - ret = NULL; - } - break; - } - return ret; -} - -static BOOL link_folder( HANDLE mgr, const UNICODE_STRING *path, const char *link ) -{ - struct mountmgr_shell_folder *ioctl; - DWORD len = sizeof(*ioctl) + path->Length + strlen(link) + 1; - BOOL ret; - - if (!(ioctl = heap_alloc( len ))) return FALSE; - ioctl->create_backup = FALSE; - ioctl->folder_offset = sizeof(*ioctl); - ioctl->folder_size = path->Length; - memcpy( (char *)ioctl + ioctl->folder_offset, path->Buffer, ioctl->folder_size ); - ioctl->symlink_offset = ioctl->folder_offset + ioctl->folder_size; - strcpy( (char *)ioctl + ioctl->symlink_offset, link ); - - ret = DeviceIoControl( mgr, IOCTL_MOUNTMGR_DEFINE_SHELL_FOLDER, ioctl, len, NULL, 0, NULL, NULL ); - heap_free( ioctl ); - return ret; -} - -/****************************************************************************** - * create_link - * - * Sets up a symbolic link for one of the 'My Whatever' shell folders to point - * into the corresponding XDG directory. - */ -static void create_link( const WCHAR *path, const char *xdg_name, const char *default_name ) -{ - UNICODE_STRING nt_name; - char *target = NULL; - HANDLE mgr; - - if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - 0, 0 )) == INVALID_HANDLE_VALUE) - { - FIXME( "failed to connect to mount manager\n" ); - return; - } - - nt_name.Buffer = NULL; - if (!RtlDosPathNameToNtPathName_U( path, &nt_name, NULL, NULL )) goto done; - - if ((target = get_xdg_path( xdg_name ))) - { - if (link_folder( mgr, &nt_name, target )) goto done; - } - if (link_folder( mgr, &nt_name, default_name )) goto done; - - /* fall back to HOME */ - link_folder( mgr, &nt_name, "$HOME" ); - -done: - RtlFreeUnicodeString( &nt_name ); - heap_free( target ); - CloseHandle( mgr ); -} - -/****************************************************************************** - * _SHCreateSymbolicLink [Internal] - * - * Sets up a symbolic link for one of the special shell folders to point into - * the users home directory. - * - * PARAMS - * nFolder [I] CSIDL identifying the folder. - */ -static void _SHCreateSymbolicLink(int nFolder, const WCHAR *path) -{ - DWORD folder = nFolder & CSIDL_FOLDER_MASK; - - switch (folder) { - case CSIDL_PERSONAL: - create_link( path, "XDG_DOCUMENTS_DIR", "$HOME/Documents" ); - break; - case CSIDL_DESKTOPDIRECTORY: - create_link( path, "XDG_DESKTOP_DIR", "$HOME/Desktop" ); - break; - case CSIDL_MYPICTURES: - create_link( path, "XDG_PICTURES_DIR", "$HOME/Pictures" ); - break; - case CSIDL_MYVIDEO: - create_link( path, "XDG_VIDEOS_DIR", "$HOME/Movies" ); - break; - case CSIDL_MYMUSIC: - create_link( path, "XDG_MUSIC_DIR", "$HOME/Music" ); - break; - case CSIDL_DOWNLOADS: - create_link( path, "XDG_DOWNLOAD_DIR", "$HOME/Downloads" ); - break; - case CSIDL_TEMPLATES: - create_link( path, "XDG_TEMPLATES_DIR", "$HOME/Templates" ); - break; - } -} - /****************************************************************************** * SHGetFolderPathW [SHELL32.@] * @@ -3004,10 +2827,6 @@ HRESULT WINAPI SHGetFolderPathAndSubDirW( goto end; } - /* create symbolic links rather than directories for specific - * user shell folders */ - _SHCreateSymbolicLink(folder, szBuildPath); - /* create directory/directories */ ret = SHCreateDirectoryExW(hwndOwner, szBuildPath, NULL); if (ret && ret != ERROR_ALREADY_EXISTS) From 5052cdf73aae9f1002faf8c39a531ca1307afacc Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Mon, 22 Jan 2018 14:35:51 -0600 Subject: [PATCH 0075/2777] HACK: proton: wineboot: Don't show "updating prefix" window. --- programs/wineboot/wineboot.c | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c index 4de20705224..fd232f0199d 100644 --- a/programs/wineboot/wineboot.c +++ b/programs/wineboot/wineboot.c @@ -1298,37 +1298,6 @@ static BOOL start_services_process(void) return TRUE; } -static INT_PTR CALLBACK wait_dlgproc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) -{ - switch (msg) - { - case WM_INITDIALOG: - { - DWORD len; - WCHAR *buffer, text[1024]; - const WCHAR *name = (WCHAR *)lp; - HICON icon = LoadImageW( 0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, 48, 48, LR_SHARED ); - SendDlgItemMessageW( hwnd, IDC_WAITICON, STM_SETICON, (WPARAM)icon, 0 ); - SendDlgItemMessageW( hwnd, IDC_WAITTEXT, WM_GETTEXT, 1024, (LPARAM)text ); - len = lstrlenW(text) + lstrlenW(name) + 1; - buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - swprintf( buffer, len, text, name ); - SendDlgItemMessageW( hwnd, IDC_WAITTEXT, WM_SETTEXT, 0, (LPARAM)buffer ); - HeapFree( GetProcessHeap(), 0, buffer ); - } - break; - } - return 0; -} - -static HWND show_wait_window(void) -{ - HWND hwnd = CreateDialogParamW( GetModuleHandleW(0), MAKEINTRESOURCEW(IDD_WAITDLG), 0, - wait_dlgproc, (LPARAM)prettyprint_configdir() ); - ShowWindow( hwnd, SW_SHOWNORMAL ); - return hwnd; -} - static HANDLE start_rundll32( const WCHAR *inf_path, const WCHAR *install, WORD machine ) { WCHAR app[MAX_PATH + ARRAY_SIZE(L"\\rundll32.exe" )]; @@ -1479,7 +1448,6 @@ static void update_wineprefix( BOOL force ) if ((process = start_rundll32( inf_path, L"PreInstall", IMAGE_FILE_MACHINE_TARGET_HOST ))) { - HWND hwnd = show_wait_window(); for (;;) { MSG msg; @@ -1497,7 +1465,6 @@ static void update_wineprefix( BOOL force ) } else while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); } - DestroyWindow( hwnd ); } install_root_pnp_devices(); update_user_profile(); From ebf3a84cb53d88d1597bb47b09645cdd07f5d5e8 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Wed, 28 Mar 2018 08:52:14 -0500 Subject: [PATCH 0076/2777] HACK: proton: user32: Replace Wine glass with generic window icon. --- dlls/user32/resources/oic_winlogo.ico | Bin 48230 -> 25214 bytes dlls/user32/resources/oic_winlogo.svg | 1296 ++----------------------- 2 files changed, 63 insertions(+), 1233 deletions(-) diff --git a/dlls/user32/resources/oic_winlogo.ico b/dlls/user32/resources/oic_winlogo.ico index ea183d07bf69e7b4cac5298de0e29b90e1e46abb..8cdda91509f8434ce6417d1bd4eb14584173f353 100644 GIT binary patch literal 25214 zcmeHPNsJsx75&vqx%Yi{ce{GEyX|f_%aOxKAb|!XE=XLt%-90v$bbZrTgFVo!HX;} zn$e6A!ys9+9ALl#qk+D`#S)9e*=sMhdtYpK+a0_YSy5e;nbD+ORoPu8zw|3I;{S;M zGcqDG{{Imr5|eVNs}rONIbI@iNhFysljEf#TPUjoLrhBKP)y|Y3Xw#@$aHnaG*{%sb~d)Q45O;YGGj!xS$sG zHB#iwwWgt*ysVR6e|}+JP2Ibv?h&VwsmZ66k%zqQ`iqb`GcyaE*~aO#>s0wHbXxG# zUtV5T4<09p5?2GyzcssA3s*>>+8TZ zwZ6u5U9BZim+LanP)1&N{f*5H_2kKu6h40PSo7%=*XcC!y6bN~eX2fq?Tdksyzcs2 zTU%=4)kGj9ue-i_PH@$~%=~lWWi$S>Nfl<%INnJwf~=eQp25qDfc8?5c8zf_nB#)^ zEO@Shc_ElHf_@h~Q^EWe%y+@K7mOXj^AwDI!I%+ruV8+H2las%LnvPpj7OBu2Q8#vg` zd}DoUYil2{wZ4)0SUg@@x_^IZX*?cdzH{hkWliOwn#!X?oy;c&5A=_Yc8~TS7)&rf z+|t?E*$eD!8D_qzwz;FWs;ai5xweV*Tqa~+D*zaD(0e} z5@_rdAlKU(u*No!>wYrry3=I;Id@lIZ~D)<>)zfdZ+gOvgXhibal|o2FyqR}1|guFA7#&*bji zyLzo<)>l(gQ*!RyIlacZ^2XQo8jEYIrKKe~fBw8|Y;4G_TetMu>M7P%H$Ht|KKbb} zIeq$cYJK(DyFb(Gs2iXDO0InWRlT0#8j9TOD?Ch+gYxEoSK-2?!zXz(?cL2D8 z+WS+>B+o@Z+(qrxeO9OrL~pW!uHRE^g&wwFpIWwgF6v2-RazlNdUI-(=ecMmy|mv7 zrKES1SfPXT@-i!wYkHRzG(FK{g#_!@#;j0FdT+B8dP#5WutFp0MF}euk=~N|rA^PZ zXnLa+G(Fy8g*fZ)-vLOkXzjK@YlWuMB=84^-ev`dUUR?#HJaX7VFmVI!w%D{y&>!O zgIO<(@8UXz&g1U@&3b%1ZJiRNt_?Fzcb4UL6(Peq~@S(Pwubux<%69(i zm7nXF1mh5A&z{w`^YrwzjzQ3V{`a3hl7IZ^sK=3xiXHyipm5OP-@*TuN$Pj_tAavvvWXW3dn_B{s1UUH|C)U!CUPsiC0S=i~5tdD+l_pixk#%&Yib~frdS9|TZ0t&SO z6F~0&9m*53?F5jrD3j1QF){I5#FkZ1)^5LsgVW6LUo)_SmhcJ+`-1pD34*DF0IZu(t zl(O9Nc~*k+A`GM~w|t(v*gg+p&V}SBr7X96_|x@y6^@O3BW3x?=eP(1{p4fco^uWc z&xX$@pGaBm`$ybDQLiwNvfT2qPf@Wv45Tc#e4h1Tc^F7pZuztuZv6gzh5eNIMaUrd z$;X~f6$aYmV~?o{18wqu`NlUC_Oj*`DZ?$FwgAUOSU_1x`$Mn)FI~Fy8;pl7j){

{LmytS97wSaas3Udd{cu-C?Wt3zeu4MSW=QXt ztlwqS_2kKu6Vx5p#5`@(FnmP0kU?Fc^9FSX*0A5%ZWunMT*yfCQ*mB|?x)K39@6xu z`jP%2`8UmTds+J*XR}lxpkM#f#}bB*H5W2=+fSRVKiJRD%CfNhyxGd})1SUu?9nU; z^z$=^>F4J6KO6MZpFYBj|ISJMUyk2@=*5ze|(eQ-!T3B*~Sz6;sh+ip5uZ* zKmF<3&3AkwSMA&46#D;~%>Op+;nXkA!Ll%7EV+>3r$1vSTvrqV`o(#|j5B2$&+^kh z%s5rHu`s_l7t8ovD+Kh@Kg>8?w(&r}I3LUST_^)=KcnX{c$c;6$0Ay$N5}U2x!wE=Y>@vpiO_Al~#p-HvMrvTNMJ@ z^ndreUsdnC{^dQ5)X}X!&bs5XzM;zt;fHH9>TLXn7cN}*3GxLKzozaNFJAny(LYL~ e9(d6naOSJ`ywf-v%;FqXRNv{pNhCX+C;Klcd1NyH literal 48230 zcmeFa2|U)z_c%V!W8bobDA_`kBB@kDddgmiQX!HevLsouJobIdzGPpMJ!B`M2$c$v zC3`Acg)GniJaxOb+wI=_{r-R7`}usnuh)0(J!U&IbI#0}nKNhR{e%z(Q6o`N1U@Co zT!Tc3zvofGvClnkNjn19Bfs&K%qYFki(6i3x z$j|pFa&rkoxrO@1AQndH5qyPB_bi=E$Euf4Rp7n3@IG(Mq#1v(CwUA zL`zkLs3|U@(TOo+a6TDD#l|2HZ%;&y4Mg&n?B{<2AreDWQeKJzLxPZl?I=o2ss{XSgh=gCNm)BuSXxAtHC4#X?IrNnH1 zh(Q9IyAhuNA9_DCg$j#{5WnCEQc|iyhvghlKyV=N)`-rZe}Z<4HK4%27?hfkhU65- zP*6Z3@c0y|AA5)t6+O`W=LJ+zU5T7s@yOG?73gtA$B#cpPoH-nLxX7GJq($d4xov* zZ%|HtE^=_lLA+c6sG;dTs;+&7c=>!$+|3l^?>_=%@1mZ*UX+jwZJ@Kr#55cFFCD^l zX!heA(l_Wr>KeykCf!Br*m}^T$89Ji>;~GtEfn1djY7j?BhYtQ$khBYs;qp7?iLRM zoo>j@(;e!FM=42AchU%YH~k*Dxu&7RxHeR9rw|Ej@&=yr0jCV;J&8yld|JyN)m6Vi zRn>FoLCZsQ{(>P|%lI1gy&ga*>8a>O&=ib!CMvJ0Kg*NL^@!b*_x67!dy%i0O4x@eh z&5(+UH?p=aLAqzNQE*Tps;;YnzIYDx2O@h1n8YX&J@4#AlT+_dUQq!mC@e)y%@2@Y zpg-CwFodcq7Xasfy_5Xa{TEn~53PegZ< z24($C0i}J`nRU@-luy|#Ux>db_B--7_>!Xx&k9?*{k*O=iX|NouY2(~_y|Z&%`7yV z*zP%zbm|uU-=P!PBX-Y$T-}MkW%j$i*xvqKLz($J{@pNU~no$Rr!}-0&!#J!I`4vVTmFyc~YUc!(JaTsKVF z-FNfH{2$_y22V)H)0+l|pozQBuSYgy{ebX8G~=<{#r^wB_#Q$VOtPiP1x`O8{5~rA zQd|3Mk-szv`7s}jfT29*^(KEg3~RNu?No{cnbgxPM>c?_*oFwfj_x zaS3uGp)F(>&TbHJ-&G;F^H7GQB;#M> zw~Q1X*(am(LfFXpUQEo>7*U{tK)k+_MlNFdpZP!H|5^M;{{JriYyW(s z`&&N|z!7=)>I=fC{dP`;!z(!aSMN(0j<>%$XJ=<(IfxU%8P(R-{+joX1&Fhp@p~%1 zw#4{#&N2SbE=HY~_e;(XB{00a{F=lvKc)k|8p5#rn2s1(c-2^-`$oa<{Xab~l@Jr6&A1Y$RLAylv1JBF{)xM_x(7>3;L4|Fo|@~aU$^vAJb;^kH62dDW5e8^B&*W~B< z9sLOKiRgd82l@X}K>c@Yfy_ekmjXXY|5D_q=|Iv?)1j_Eq<@)>nm?u^7MOT|{sUV; z5DT%ukHZd3{`tK7eGmLe?AvFQ>oXV0D? zbMvR@#EHi!Dk=)XJ!o=r5=lwfLfIsgmzRga!;8?FGp)$pz6#QAAq|ai6dhdx_MHIq z>eVZB`m{gt^^Jo(1N7m;2Q)AUcB!;fh?}CjckhCo%>if#MeXgx)4LPGU|djmWCYY3 zjc~YJur1w%wxdyGY&7cX>Oy&7D@8~Fd3Z#kxWoiBH8q7AA2uOI#%E~v?krSPRD>ug z6Hs$=GvJ+v_6E@)Kxvsk9>S?px)kIz)u7lZ3-$aEk(-8kI{`AH&A+d7BVxd zMW9up%&aUF77>o{ZZ0S}xf$Kcxec_$LK~CF!lDaxc6LJDvFQE#_h{d~eUMiIwsLz! zO&yLNK75EIr4FFP)Ksv&g3%jYK%}H6!A={DY;61h-T__)N`?I3@K7{AKMy#z=;qBf z6dD2cZ00EB?B(xp_CkdS~9Qj*c^>?|rNDM9k`T~PiaN&&lSNJt3uGuTQo&(ZMkFv`r#ggjRO zKNJ%a19bHvPd^{@?%g{S7k?9pi4{TK3FP8ZguK0DAzTMG+aMGO5FJgl!CIn6kDj5l zjC539UXJ$et@&anjgIa|pW z1?o1RG76$Z2qU`K!bo8hn;6$Q(_wGU8bO9YNpznzDE(^x%CW?zA zh6};Ynuw;Sr_r4|cYxj|Nc*34nE!?|)VoX;qUmV(^CE`!2gA>7lG$^(Y{ySAI>p?a zJ;$F!Kc}K9|5*)&*CaTl6-_VZJ$3(Sc?`zzp?_@4?iB4m$tG4>uJ*I4e@nC6_*?jA zq3p_^rT&&Cocde%C!w7;bqary{A-e~>t=^vBYzBJ)(Q%$^ZhaXmy}TzCz6sH?xTN# zaBsuDt7FM~t=bO#6rqZmlf!aukn_sewOw0W~cs$K=CYhotH%w zzilM`l05Yv@(ruSRXMm4s-(<=U!>C|{b7gtH~X^!mHwEIp}BB4AY6|0*s%eV)}Lf!A}-i;O;Gu) zah4O4{aLTtO48-P>W?+!x5qnG$^CoI6m9Xj+|2{_C_ zzWA>-U~t6K;BRp_q!ABezgF@RmmHiX0NRd18E_}f$QT3R;4eBHCFLE^d;L)N%Wj0lUP6&EiC=Wteft9;90fX49x5#_ zLq#QbzMLuUH#Ne0hfK(eMxQ=?LgCSIUvze&ju;dcgX-@$!2NtW+&f32V7L#DjZHvJ zO-(2QbVs7joDAoJP|%x+=Z?I>0+a}PC>>q!7ag{$rW$y2fxGJvI4>k1U${TcFDwK- zEEnC*&4KqEaX@1t=vS4XqY-tp|8xJ>1OLH2KrOAnf>r;OKmi_BDHS0N#a|P4uH8X< zg#Fhj1on`9A45oj`S)?Pt-p(J$NcU(mR$4%1rz_T7~*Ujw@Fg{cK3lhO0UGQnPbg2 zgne4;`A%+Gr}-_;C`@`>Rrc_23-j*1o0K_uzhxsNM!D;dyvT3yV>J8eNDlrMM>2wf za$lnhTnJ6mBSiF9oqvO6>91+TyzhaC_YH_RM1A77b@r=1f&Z?h?{|y;H+|xpotB0F z>z0LK`NfJxruwzLZ+rhYpZP1tm|u2WX567K3Czr2cieA23;$Q6B<7c`4fD&6`OW{T zf&5SOlPJ)s2S9vh_r>vj_5SbgPkVs)Sb!+R;sCn*z0)5M^0|81FoJP@7;a8KD&8)F1dKPPdU1}ytZ|8Xfri8i&H&* z+!)G80?9i8sQ+E0)6&vzF)=f};p*u=1v)_=ynTFlr}$1?eM3W2%cGW7u$4Ur+tkbF zFP`^2?dW&~_PAcK1NBA4MvuFCc}x?_Qd3hC$K)?xN&Hj%**Mr|g-1trHa&cp`{>c5 z?83rAFe60=;_-NIOG`^{0|Nsh1lZWvM0tCAr-1#b1Z;e5VEcOyw$%5a4^3RPwaEqg zX#Oc0|Eyj(nqk1+^`W)BJw$H%!^^A*) z%aog&+Z-+!uE6ESwauG1Uk96CHrT#CfPBpp>-w{H{>gL?U#|jqPg)E%KxgPz%gD$` zV=F5w9YsaO6EGi4K(6Lp0FJ4v+n+db!phOn(F^RBNzb1@ZvY$cOwGO8UN;|4qM`EN z;(UC3=sbLVVtoVr-=$_{+-YoT3LPIGcL)2c-~FbhVtXft&t{euOE<#8y1)kiI4CIS zNkC9QhhKnyH`r2VV1CCE>-e`2|6QX%0|$)71(2r{fPR1lu%|EL-Q8C09356bjy_vh zTP>Pen2j2l7#CeMF}5L=`L2rpxS+eQ*C|gQ?^!o5k690IZ>|400{?~}4?k}$FF)TI zcQ4Nw;N|4sp#R5Zd-{4C!@T$eWAM?_&->zk9D#pBke8p2Gu(Bo`1<>;K-lqb(EsDI zz5IRCL&L)ezyks1^IyJd`;Q|Y2=Wf_e-?N1CLt_5oZ#i}L%az4U*q6TkpkxKLV89z z;bwe1!PD1g0dxxT|1Au-`FY{I{e5R)KPChR2NPf~nDOxOIrP7UetRd!atlk#)qsEi zf`^9(0luqPwROA>A3*%)J5OKV1MXg4ixCkw2>}5S1b_cj*S7bp$%PhXe_UP68f326Lf};O!l;6`^ zNQ5f@_5iK`J^;Z0L|$S65@3!O60))$uRvXI{*_|@{iWpY4j+&L?L<&kb|xexRRaC# zgwv;qbgBSo0_Xr30$c{T3UD331;7))7a$Pi=n?D@q3=N!f3rXT)>Z#V2-(qS$1w}q#)23{Yp;Y3&OnmV4FLA`NR#32o{&OX) zTbBX!PXPU|q5pdbXU;r_^{4@$1@fN)bisPrN1&n_gn2zoSigRRz{fXC5ELAQb?PNy z-@Z1`Gjf5~f1Uh5TPFJY&VwM&b6Bh!p`v0K=kF7-Xgl=&k}F?!Aow4*`gK zaO*EXjmsV$<%<_C z6fDuv1;E!7#QiHAfVhVdWj<;Zg9%^4VuKbin1DqLCUAv{%Ci@bzf}ja(*<=Z|EuVS zxwaMPCq8Z@I@0Os+1SCs(YvLk4@>?0ZdYvIZkjC%`IEDXm8uLO&`EeL`38wfDwc*h>D7y2b*;Y^!@z5 za{nUs5cGe0XlN+$t_3YGFKfeF)^xCa2Em(LdwAD*YQu&Nd%^B33!uQq$9D|)&=3+5 z(h?LDJpButl9!j)OG-*ghW`JTpYLJ3lK{>U=?D9_H1LoD?>K$?`ueWI+h!f0UxbZ~ zZTH5F8xO!(90L2fJlM~bh+{$o2rKLB>uW7d^Z z0R2tGHi33{a7IW3aD};G1n;y}uUxqz0C!xRaHqjfyyL)2F$B_ft?u8?pSq!$I4z@aCOJ_Z5KK0Bx(Qt8c(x0U$tl9^hMeVP$1y z80L8s%#$=2qbtzw*P)K+e+TWvHlhEl;hT+VSohoEO?zKfR@Mi2TRsEt{d<9~M*#J| zz$2jb6@0red;9k75AgQCAKr^Sg|bsHepdf3`hm9d(EbYS13tw04DaWOvhtUXh(p9B zmVxrbvzNhN7WfA<;hO*&py3_B5P$R-N>|_}}vX%ioI=AKen`{4;-n>udfupZJ)U zh);ZMOZ0zuock+XzkJWW{9pWD{71Z%U&^iENu-JGtTYk6`t85>SKA5B#QZ<_Q@^Cw zl6=YkLMxG8>1D!~F#Ysb{~I3!aK!wtzK`lrIXdd~#5I6UK^_O^DdLoZ7sSNd9_=fc z7r-OEcu?gaLIpuI%lbq^AGd+LI(*eo6oS80a6p1`nESp=Ab$QxZXh zJY54UFSQD|gBrFk-&NT~ah$ZksCJP1*O5=@8JvkQ-L}a%^~ocnPw{=X zO!khgKG8e?Z!&fs@O$=jyt3UY{?Wp`6<1=Y6Hm`jk#*$Nh6V9ESq-u&!UJ zU}jyXh>r61Iulm5ZfiN+x_62^|A=B4b?rXh(?V%)v5!a7PN0`N?vib&MHc#roCFiL0OWjvWg!`miDtmPnddxA3X7rj>$%LIh1; z;4N2HT-=Saj`Vl#z^$n*!hP5zG_rQab~)N4x2)0ZgUZcYs@TV<*QVbw+k=4%P3xmP zGClFn@$1QWn`wCB4gDQMcYHEWSZLVXxZd$t22&W~*bEAb5hw>-tg^kbxG{O5=S6v* zXnHH}=ST1q#;sXX;*+Y#;Ep55j?tT3zFZY<<&+&(So~z(su1rjVA}J(Y$83jWY1^a z2r;PaP_K2TPUMxg8j3{65WhB(aSGAl!~IREVQX>X+tcEL)sKoc&en}ew%Ik7T&BQ# z-#=%JhZ~R z^Nz5~Va)csOX84Zg3KG8>A^i&Qtep>D>T-0EMjP1c(R3CCV6 zV5)5@x!m)~CScW3iB1s(VoJ>WokGKA+w1{-&Dtj^h%-{XS}@IF!gGUJl<9{lEz@4R zv70&tT5lzJ8pv>0v%+Ru(Y`m1%DAfmljZ%VeB0C2RI&LF?#{LCuMk(+uZT1CY~eu1 zunXjjD;AS4a#jMWr;g|^eR>y*(cb31;E3{KN6IiV?LfxrttazU8WzI#em9>&pE(P; zXMSV~QV^2PoBSM^SM}+oY0A_`TnakPx6qkqO1@O@>&;pIzI@Wj&-;AJ)C}%^ll1Bg6>{!_Q+7vR->NX4roNLw?PSW7 zm5}~!D<%EF>6G{S@J6M!39_V%2b6bzmWpHw zBg=oloh&4@X{#M}T8h`czX}FKMsYDOZjNic=gfy)o!X)19~}2k_mr9+V|>D|-fW{N z)W6kT>p;gxTq-&HHr_BKES4Jf@y?<-UvjJm!=Bi5WApy%m6PhtXXS;Q>)5XAXOWYo zgrEsigqqxH`NAqWmpUO>AxqR&SoikWW+N zZzA2p#<*7p(aM=pvzwPbn8(rCys|z?G3Kxf--^2`fbXQ_(H(lXr}NC3F^=3x&!U7L z7=p;}ep zCkOZpOs`zMD*mdYW9ZR*i@m+QKlIcIA;S#@w>1^J1>B7`C!Yu#=+hoDo z59o*EhL-2r<#MtiNU$U3&`V{4PIP28lzxsS9&4*BnFtDVS52s|(5 z)7PgfxiH|S*-6cFqTiyP&aH_sv+Y18TP?4vmD529B##?^E3B!dqoZ^8ZDEVWL|SBX zQWDRHj~|~5)_d&`6T>z|+wdP)$5&AM(ykzJa^JrF`wK2T-*VN)#^B?d=hL2>!k#>5 zdG~(p6Fb3HTx!0IAVv#E$aS;KuWM)^eL5kYo}QlUFc3h)s@RymI zZ1~Dv;@>$tV!-dPR)lr0Hg((Ht2%PRtcN5yVFYC0f3awsShVm|hPn`Zii@8sCs_^| zfBUv!K+n)n#9hKU{=SfVBB`FGrLM%LXyy0V>6k_4BRC^to#w@D6LV<34zMoNxipsKW!`;npxU<+uQB`G*MWo1e&^M>gqr208p4tRvS?(#m|wHtS7Wp? zE+_pmZF1j!ivgMU(u6tbv&0#sjRy7Zd7${%ITb+-J%wr`x_gHQX@y4eE`COgDtf0G zmfOeC3z9DX8*HZJ`IuTo)S~vrP|L==e27fQ@Py)CK6kdYvi|!5JI)HT(nqIv@7cG{ zexaa=bHBqY>&}3sNH3{2%s>j)iqTF+_A>3j%}i7;^Ysrk&5pDLDGJRqK4E8UKhw%^ zhbW<>@9TujZ1=T6>Hs zE${#ne}P_Kb->dYlHM9~!jcCAd!8vlVr$yfv@km!T%Yx;+d~q^1BZr9d)i{tqg&65 zt%c)tO8-LRp2q6=swoyV_T#*X&%(x1ii?ZyjVNbyj3m$_PyL3CO;64huoYd7wQQTX zM9K*_wsA=4p@P}(1=UrbEF^&H<^-{rlQ9o8I-dh>&q-a9_E?2~R+yR{N@O4Z`hrRF0KnWFrV24hWe zF^jt5tj~6L!L|Ewt7UgY6;M~Hc|wK#$4dd;Q9}~KtbS^eoShlz>AIIL-8#(@pdfUX zV&G!ao9LU=up?0htLrj9$$s}3G>1K^7a3dBK8plCWI8o*HKuBLwnZNkr9z8m8Wi%K z?z4O~Odp@OYwOcIr;l65ZYXVk;_cmCqJr+~v!xop)E6>z@n%X2(kA6cG_KG?h;iEk zf}GL9^trl1;pPiPz1BMO75yu@ZcGywi?Ob$^UAi=Oj0tV4-B}9({Vv;B0LzqslF<) z*w*HV2v!x!gR+!YbRzT4lx`1sc>bDE%%{fg_=8o{SKQJ7+yYq3N0hl8%23Qkx&?p*o3Ttf^qwMQcNgF{|x z$}ZltjuBha5u*KQm))KB}`q;ZVYQB2mo#k>xBnRx^ zGNO&!eWOSo7YI*wS_xjL!w!^hR}gwAu5zJgcag9k3pLq=7=i0E_t#}F6B47jre{np z4?6GW3_AI2IVlQZJ3SfO{Cr6sY))`^T0Yynbyt(6w^f_C$|l~|Gq#m`-q=i*J25J* zO%;4Z0y5^k{=#@*tajK z-eZJ38at;9&{Ksu)UcwFYh=h3J1(_mlhs=5T+u0gJ9jGp^PjXWc@cj~r(F&c4NERhW^DjuY}4CFKl1H_RVS1jeMxa+T7J3qwK} zvx|$vi|^dgSp1M=FuFJgbEaUrSg^Pv(g5SBFIq1OBCg!|QO^`FxA=K*>Xv1ol2CX2 zf$P+PL*wd-t=2kg@M}W^(t0<}u<6d%lF*M^Ib5aY1V)jp_Z}Ws*kalaqw=wts^RkO z-6gHAyaVQLvXA@w&8c{9Jy<8;B+N>~bi+%&{i@EG)F55GVCXJh(Fe)$d6WC-(*<`- zx7fk<&(UekNj&j6RzqW6&lwVb*rz4;2=LvSo-yhK?Y8^Js=mds5WiMS|3# zPN!k+YpZqAi6{o3Zz-bp+h?_FsD|Xg~a+)oyeOmSQGZQ68Mf;?&gj3sqCw z(XJR$w^8RDJv|9fU<7g;p4!lPdV2bTdhEAU6S<>NJ?oi;Kxo!__VE>ZE2{D>wyLbP z_Zaw5`=<{d9vL#?%gJgtyY(wHZg!SoUY>ijmTdX$Md_mYUC#N9^X)vUJrtJ~AxS!1n1SF(h|f<>MA8b00t?>i+Wy9L}O*qpZClCE7&BGrqZzEr*k zH{5=Inc@vIo_oS=v_=G5a(QRoZjm!s_>7}%dRmlBfitM-6!Xl1n!Y{lZn^kl_UXp! z>6xUIPZQRwbVNnoO~AS`Rt9?I&9_`%9Eqfve&j5aHu@@iRN`p3b(%eC8FI~;atC2{I(AjUQ|?+xX7wj<{$cyv0qE)%@(B5{@2 zc5l$F67n?^g%0AbSXeynEi_be4VQ_tQcP2qE9y2~m^**!#Uw`3ftE1EPsNYsaCAj; zwI4grI$vFL|Jida!)}6G6HenA2CMM0q*d2;kgR3$#$@UIPTRTzXBlKkFQP5`s5}(7 zy2u}LzU9-9S|eTf*ius(wUvE{&mqM_7u*|djg6$@@!rws&hV_edvEx|^S6$Wi#2YC z<$f=mvzOJ1W%wBn>~9i#@#w19txq-_UW;dh`2DWXnD#_O82W&sUWTzspsg3QS*E&% zo%P{T>p5x7^i-UV@)TNar$B9smD>=UKTq0^G=o09u5WpCk5wM~+P*2h+{yPH;_rG@ z+08TODwwgVSW$Y(=~|L<;}}g7M9K4JH{rlDT682tI%;5X86>{RGWG0IMebH_Z%;3; zR`f9X?Bu4$%xrf^MM-9=Vye&S!cQ-8FWqL9sXBmRHyE)3wWCP5<;IL{-1T<%$?`S4 zZ%8c6GM76!g9uJppbw6@I7m6~=4EX^@4s>>@bKYsRK&;?AI&)e${>v2+v&mj3)~M* zKCx^HYM^klbP;qYBde9mH((fxvuxXIa66eKn89^vta6)yzoqn|T~XYSZfF0MZjfKH zMz+no0XrH~!z81X1CL0S?3(X)CNv+Z*|2#-7R|{)RqcX zxc0Imtmkn*f;(+xHHT~1sZ-;)^r^ek;H2Q8GGs++@V22D4Z8!I~u*y6hrl-Ut;c|T$T`?!|ivraN%O+K%jasc#vWnXsp5qdC zapCe69$V{BDcewExhcrW9cb_l;(PW4sT@6egvEvj&&5@<=k>5B6TU2^nXoyzZ-d!g z{VRbZSG`O=>g8}9UJ#t)>Zm)&k47YwO41BgG@e-X`Z;xx{9&wXwWg z{9L64Y9|>Vd|p~oImN!Pb$)<`ynh*=u;)Red9O%m`%))q@~66S-TaLSc57|I_G1^D z>iV2+uh$&&_Vzl>+FbV#E|4TE%P^JO%#DqGPP1LD-)PhOM5B`{DNz`|_w_EdX!YjE zF;#M~)zOqLd3kV~l06b2?_+*>t|@RM%XXRklKGYEq_;87e#TtV<4nN}$<0iZeP?}2 zSyrVLgjTrq8PwEj3t70`r&m_>R8^^Y_zY;}0y%aZaN%y-yQ5JsTKNKeVwWACr_Xlr z9H&`#79~HjIuwSK`-p}SYo~Zs-}8BMJ6&Z(kI$b?80M$Z*7!)T=U*qTauN2yj}N&% zt+=_*`)mxvJi;wAOtj2%a9{UeL*7iTTNe1{RS!CyW%xAJf0moKk!@=QFPJlq_kA3k zvZV_{&&Z%9eAw)5@5-B2g7@+qw|+*rk62RF$i~s+!|ax?bvL&qkn_N4Z*J#svVo}- zSbp4GrOL2&nho=FD~<`%Qcv7kUHW!Z_N()g)}7``@;OM7%#C?aP_Uy@TxCzRa-&0b z#<2ARamHc~-`vj$%*mk9m}M3sHiL>c%cgdWM|n@LeLqd2@d=AdyfzUM6#cg$IL%Wbg#H{`1?leI@6d zuUvVmED);DzJ;5YSEZv-r}J{`J7;xoPipK7s;M-oopB=WwrOp=%}Q1t+wh4&T)D4S z*6*KoG_>KaJaBbfl}Fi0nF2Y^QjplO9F!qwbB{OqcwbMqS(IelA(B85WI~EsFx3{+ zWTacME>6*_RSb;qnr5eu;N5&7IOM1)2#AZwgTJFadPH9@4~3 zYy%{>I(uozSC*}GRgMkj)=b|fsi{{EUaq68cJ?<;rbr>w2}))kUaqwx?je-edCEt; z587NiDROVBF?)Ll`TH}w-jl&ehAXo0#?Oz!F*Ms!@DcS0_8FCsVd|-g^7p1#Ro#$v zsA}%!l(v`Z<1K<%%7sNW6}N+PFX^evb6b=x-a zL`rLx(3V$tys_?-Y?5Yr&15;tXw5pBU_ooD?TL4k*($H&ctalG!df~eK1?9peQkLU z6(|fb&!~8CVW*<2W*RpvU0gKEr#~<`KCU$xE~nPRog9O8b0n}E7}DrFI8>_AFJA2V zT8AWgXCBR{jOfT#Wt>^lBT;zTc{(Sz)5+tF~hyZboJyiCFy$u)A#B=ZZD;EeIZlEQcF+kd1-~3hMQqLy9JwB5RT(3 z>b`AqDk4^%kG7xsvA7C)faEoqIi8$LQKjQYA2;1PlGU_)v2NQ~ zFRB{H;5I7puEqBYoC?N8=n0ERw3o$=nKoW=or}wvv^;g#csNK1H6_cQT{OEDWh zI~H@PCk`FUR|xh_O;{c>-EG1j`cNYL5n0WMzIwz9Ey{>2Vf;S0u5r?ME{GF9P9x(n zF=cM8Gqq+9hI|{QM?B!|g6)<)yI*KTMaho}2*k8Le8{>pRN>U|W*A(NSi1dJUbOycR{xizLyW@?` zI1`M_;u&;vIBj){FFDzsQNW3XK8$LK*k(fWVXIz&mas|8g@wh0S9ed247)Jl_gReH zw7JG}jy?ZW4BD#fEN$6#5(7UQDZB4g+(xcrqm7L*MMFbb5PcIRU?b_eKZ2}N>0U{T zhiCXJ{G@hpiv!GSlTFe z>k?rPYUwO4sdij`oJ2!&{P;tlWmt>Vs`7Miv9OHyE&9&Tx7uqMk`*uK*A5w+@C+-s z(9zp}1n3^9s4`+ydpn77tLm!?$n-hcvYRI(DqbdE`9(IfOv!AXt z2L#m@+`iI&SMUbuyjv4(+DyH^D+nE{^6C*9@<_1@w#oVSS7vX_eO~fl_oMUQv+Ld7 zuI{oq3%MqIm^$YH`#Y3*rOEwoqvZK`J5M~bb|eAi8a5hhy!Y-SR}Bx?x9;lHP*GXo z9N-{dX2eX9Jl^QgUGXApA9}%yTj*8x(YI&zkBgDrib(K*PZKUBKGR&&S3qEY)iPJn zu{cuZ($CO4|L!7H?M&NV7squS$>JU6v0nK6(Q}q6Rt0x2tSl__n5t~pU~Fuc6;!Ye zo3jB8(8xSbcGHTRptH`F;1ejYp3 zjalAB(iZ=2j?FlqyEgO5(PHiPgd#QQEbnB;`(Z21i9$IQkYCX}PT#Q?iS+&D( zNtE35iTJ1PPILL3@*Mk~bqgDACa1`F8?b@?u8xjzo83{$Cmf$&(#qh>0SD z)2IwwnQBP%b8Il7JJRRU9C?Q-t+=LKb#~B)@^bdcNGi^1sVy(*HJG+FQ!^YtZvA}K zPl$AI<+NSMq_f;xic$`lt%@u5CzH?foJYz@%uJSleD9w-zwNcHig{fF<|z6 zW?V22T4M)A$wfW+#_*FT9Ba~zp<+Z21n<(%?DIAU)U^760CLNbdi|yr$kEb z;2`!uw}kL`^y~^tU^oNX*vmi!LvZeyORs6oHc~w5Dfgl$@eh}pBE#M=vROPQ#M!+ zdhXeoC8-L8(dq5Mw+b$16w9wWySwU=HS?kg6^SbQib(%D#Z~D;m!D+K+a}2}^wIZU zv`Bbusk%i|v9&c(gIe#l@)dTzs-ZBSvwi#4xDVCd5oWHuAT7;pgrh|G-Ga~Hx}y6D zYa1msQe|>EAh>HW$FuXTm*Tzqo3!!MGuk;=#%aPN3;uro8qs>zY5Bev%pTQdyt@OeQ4 z8-*w)kt8iWn>pPlDPv0o(=$-UlXsG{k@JlO$3;@68V3iGkjp5g)w&Ck)pAe_OK|5I zJWf7M5$CpRk6Y;-e44u6wrz={7xG`6P*tMI%%TcY43|$(mZer(-zVJg!HMqPCYev% zgK3u!*)|=Q3wk{svMGvfy(keG>9gV|2*;z~WJ>G+!O^*$FZ@H% zQ$cITchff_luxj57`~5ew_GDeE8mDZ$>tt%`C&LQy(29yR_$b+*7-8CWO(l_CCVL& zBM}$+wuPMTsEvt{i6MW{tNq!*YG;&w*eqQN&a4g7{*0Vab-nMImlQ}S<9P6L?ir>G z?!lGyeI*$_Q&T;=qlRRn1kyi$7Jb>{H|R#8f1zmP;#Q>_bqPL#o{=I z0Uy%4`e6^a`s|mO3yvjegl8CY>rja2+{rUWV`$89hoB#x;2^uJ$~-(w!MtZA=g#HY z9>pHd{L9R8ay!bLrH@>D-|*zXb-i_dED;I|>@*$1Yn|_z(0R+8N$F4eLXt~Z;jPWl zCa2isvdHxIZlU<}jEQ7h2;T38phV_}rLD@=$xLM^Unb{tyi7x$BSxO*miHNfvQqwI zv=2lTANJGh9It*MifSrlsuR}r-dl%F#5pu!B+nhk51c>6az=|aPMN%{Pd9b`{e8ID zVS80X;Smzzd$I9?U3#)AzLo8WkKRu5ZKu&QEYD6bfxZ>J$9`|pLLFI9@+&27vd|A> z>+-;g*9&qjx#4?dW|!_AqBK%>RXP>lkfI%bv5y4*!9@NnhwFvAXSaH_d6ZIegog2} zQN_&igmUJdQLt|(;}%lF4s@=@PfewEh+e-QB5i@9tEH4bebm2Ox^A)Ft0mW;pv-nD z^nimTSz@R4lfhFcuHf`GMsns$vOrJf`t!UT8I>Yxv-26MZ*IK|oOoYb`$5UXP)z<# zNrdz|_U9C;%wT<2+PQN2#6*Smx?raAuo0(Of6AdnN!m7jd8&>0?fmDExDZb&>72Zv zX1&K|>}nG-T1(q#qEJA|Vxc zZ(Q){$_ktGRm$#qFa2XjU+`V2I#2(e>tNQIenwQ2WjsFn8Hw^v8__@q(t`1H|1Di^ z_9r76$$Z%3eH6=#m#f*dqMuTqP^+4_6ykU^44;NN?Ev=Qcj zTsRqADjd`jBwIaFNneVh;^G<#A6xHaOgZ6n7||lr4Y`*O4bSE8*qJnXdZ_J0qqg#= zvR*k%t(pkk_4W?wJhD$iGZK~e4>oTispsb9M_=S7)83^QPb0d)H0(3Q+rCnIlkL@a z-!91&FOqz;X`ETYaEKIgWs5=XQDt)V?N<-v&2*2pwcVJSI)wqXG))65N>mvGZ^iR# z7z{jAX6vdb)sAv|>NnM%zab8ry}XgJhnlJEy=&{_kb)CM_|BD7HQwtyuRlkh)^uHJ zefLgt4*P75AfybI^0yCChMz{(1(coKBKPTSmfd!V=hsBZGN@^S7K$YI@QIm$c3tLl zByl*lCo}HD&aumLePx-~b26xQz0nG40tFgF(|~x>%_ta0MrRTd#9%~eyam@e6^w2| zhbY!?OYb7vq(&g!Rb9-W>?G}~-+6ydFuG~g9v$H(yZAY&R;qGNDv35vS=7g~06Ic? zy<=C;>3sJ(C5W1|yxsr%l!FdrkPc0=KVIhBjSH4*SHB6NQK z*fEE-KY`zd(=al;qQ<$vfqUQeYK{n zjh;=i)U+eLaIyWsR_^11xYk4Vl+?SDgz?>KAF;dgw2fOc5_OJAoqB)xt}5G%$43jg z7thpoEzgu7{AUwqZ2p_dxh*lshcbN#M^!s`*ls|HxfvU^k>VaZP=C`>YRvUYXlU2R zhS$QH>y!k>de;wzTBXN)!YS;0zN(UwV|1o87w6PYZISA}$?#c1@+e6h=8GOP+c_wC z?vashadX@;yJO2eHQSmUcQi7Xo8?Zv)MLo+Gp;#yUTxgzok`1unuMn%8@qeQ%HPlV z&DKT=e$gztXuOS-be-DvULVz6pFh@pafkhR%M-WF-o3eHmwV!}GjDns^%Kw1$~2CZ z`5b&ow6ez3?GJQ&dLLH^(qH$1bw{|X+V?kH;OK{&A6Cu(s z>)$;m^fr3RnQQH#Lp0S{8nxJ{Z8xN2x#J!PI8WQw8%7@7>F@ippXbKm&Va*`$#SgA z!I2WgQwy)X1g}W(>^&Oi0|~R*O?4^#%cHJS*=bc9J@ud6PFu%I8Nj!w+-d66S+T{{ z*?$KI8`u1Pc#AefCOyo*hIk6ITHT5JP~2@h5`KR%VsSah**}SdV)SG8EH^u^@YyQ+ z6Kfr-`OH%#a8&iaR_%u;8v|JCq#M~jt)a!085~->cI_O~_;D&l^rp7BQ#Y1BnLs_3 zaU!QYxM^t9oY3*R+gIT=no_9sBg`O~LZr1#=ez6#!Qxd16GDg7^587JjL2fJ!R&h8?L_LXTbYn=_nOgrFu{v6r4 zm=mGPJ452z3oqXhB`wvtc++Df&)LzgEAQ+Q;Zi#%4dbY^!P^AZnW?jds#w*{-s2R4 ztutyaA0xF3UA#x1?_@xni;a6k|G(b811hRz+qRo5AW;w%NfISBQ8I{#h#-i8oK+;W zWF$8^XAqE#Bo)b$Ln9zaPD;)>=M3HbtIv7&zyI&}|D89+J@@UwVt4nhs#SYe?TTxz zDI-RQN=5C(f0y(R_-9LjWQx%bZ;9rL$f6$qm|gr*f8!BUZz|Ohe3YEbYiGT^rw%b zk#xRHO=uPNHB{;^N7Q=TW{y}pSpOue0!DlUkZ0x7yINMwXPta*<_(KfUJ0Ii)EmwV z(Mo%SkuEcdgnPAhMn=*L*58T@xlgV-8YZL95f4ghYgOD0iPFYOnps*uc47Dp-8Rcd z=MNvJY=B1a0Y$&ztubP)JPs=R5D7xJO%*IH!?x8 zc!Z_jbdoXkn&DKe ztuy3|WKN@tnc11&#(LF|7q3XSCnYT@U_5xdsi`zANktU&k2EvWO2xcX88Ko>qVU_) z(^tJwgk(Rz<=+2*z86-41hxTx?&#TUmJgFbt9a+GNN$s3U~Px1$AibZBC7XPhVzMf zZ&C4(L?RZs#m?69?TJZ6E6eXwVHCni6n>-W8}}-aH@Q96E5BTLjyvuy^r>ejv*pzN zzEPC}BLvf44t93-E$EK2m~5J|W7=-R@hfPYX8!Ed*r7l(XTcEeFIEe6yfoC=uSM?O zk2?=r>(QpKxPW($a!qCsYgl2s90rNZ6MhwZbNv_n%ITKoD z9FJ?~$=(zc7)^yCTj+x9>rMt9iBU-7YoytudqVkY-hA!fZfOV0MI?>nh?C}9nuZ>Z z)LxI8mgDP}M0#2Z_4O9^`@{lUwOlM)Ork0-voC&SX@o8W1`1qsaKBkyyWNemP|)y* zS)h2pd?AwlL-fym8XwnSX-23KBy8w~)!D@|rD0jF&q{hxA1S6osY zuGgXu4NHzQ1JzSf!W^Kbfn>iOxM}CE^8{2I=IfC$4gK;9ubd2MX$^nx>p^!fSF1(s zc*{SG3E0r*0o2;~4HQ{QSK|3~P2%TZNPhmBYtf#lfC&$Bdh5YLLy^1xPsc|rGv!1! zt&NZcMMa2pD${gF3z8-F*8cz?mbZ*b-Txe6F9bKE_L_&y{h0H1G8$YhR;h!&dqs6%zkml)CFsuA zV0F#;DRl@TS==O4mI2t+#_;mm*jL*b*@&jQGB2+OlXqRAPE@0SUAPd)spS-(4W=vZ zrP#|Egl~s>L3ZXj(p!{xEaLf|N$mS1E*FcUs&AN)H% zv%I27#s+fzi8iE)14k7Ow^5}o-n@UQru#WwL=J@?u4l>f{NgkF^m`izgO9S0gVYSV zF+2Q-;JeaaipU`|Mc^IDy+GghA;#eod{LlN9v*}iTGQ)vS6iRQkpdIAiTe2_l*&1 z(d6}l)2p|s#&}%zS4mr--}GF$UQBpO0*jsyC0Q5lbE$)ieL52n!}fGl6_pF`q$M}o zOdqc{B151yK{x&o=C%K^NB8{r9{M29DB`KXqT>Eo{Wa6#yxgcMB=U>Dk&O5EQ$5K9 zIa4tkI#N6w$Tb2DMighvwyUQ2&p^3Getta9lXXMWk4HXvNSNw=<=gthA(br5a1H@L zB~Tci4J3>KYkp=H6C4OrYa27-!gR-~;wAn`x9^k;J>jayxsj?$SMtU_s>@x0WdisO zsH?pJzcWn=?~K1a=W8F9#O_&V&#_nDj!DclM;5f6Fy7#VinTh=coXV`{+PR`(Ghx! zznG^_4MA-B=97v$?HYd+BfWy_wgHUm>idN@W%UdDl1}~y`-~WYD3uqKhJpdU0GD{s z2(2pjKr_}9o=@Gdt}B7~o8o{BL$T)h54jlec9wpU_(2d$*I19X32!BBaZuP?O0lA) zmVDRL{W?;-`s!_Bod<+T=#@w#J$HeZc)M)N&gdQEI+zUEFRj@Tl5EeuvO%^-NJF3I~g6vW~A-;h4O>j zD27kf)lCZtQ=UVPyDMqZViNnVM2H)aZL+pt&AiKURmA@+6K_ULUisniT zp|ak^zO##crHF|5hlWlhbp@PPV7mj4I2okJq8bgKk;{3^D`v|a39J~5dyXs+nu;ZM z&s`-XYy1M=t5rDoT%cR&+0c*q{TV!n%Z&iPaBd7ikTX#Ngn?4S*=-4OdPqX)05MS& z{!$;sfTUBSYTi{n-(JNd*eoiWS2rM@+#M49h@aPSF`TL4^33Pvz!LuS^wkmo4v=-n zwg8{{F}>Enrg0+zFPkbF!1W)6-L_g)5JRh774#xN3C&-WnpmGygPKdzdE zk@NU%%q~eoW(o?F>dzXwXp=7guX?oMh6m(-w-Tpf{ulBC4);i}pBuCFZDwXMb&l zTIH+`H{<)oeh!B8D*!fHj2a zG?Z(Ay?PPbM@dMFrGA?VHTU^hpNNFc+T9gh9OF4qFdE%bZ%+{2@Dr`V^(_hHGAe~@m7udb?x~Dq$yI^5dKDFBo z=RB<=m5>zKK}SV)-`~EzE6RC!2_3}2Ue?#dsHuN$PK7sZP1fd&G`juOl0-(K^u*juLJ*S2^RhPVE2Fq2c zsYhUfKJoII^fxl1+-5?drldoC6vXxQ#bh^qL}2P$CVC~1U}L5RPiZRMij36>d&=p$ zYOATh_O0ZL7CM5^`%-rVeJ+Vx-a$!uA(IjltMc>m+RP93U#R2Q$j>#LZ%Jwr?IIu- ztyaULYO2PY3#>JJr%H2WUa%8fYbLgoUE3fPf>JHNp$XE0`kSpC?~Q5~a7Alytaf1Mwh8-RC1P4=Jy#M36QvL%wx8c|2wJ4X>t; zccF#)w=mVIJ!ztlFl2^IH9YdW_k+bLXYe<7mVzl!BS0#^&zBWtpZZ&XR^_`b7F@&h z5u>WW7^~4E;T>w6qyxt5E4;1ixD?J<=_onl8$@NC!;rpbV+5}Hp$WIRM&Lu0*+33@E zy@d6c{Z13qn?=hLpHBY)H3;{7ODqJ+{b7LQ*2TrJa3SVy%UEJLGn$|)U}rPuAotBIV6bNwP@gK%8SjypJ&ls$(N z9C_-88b6kY=@ZSJN}0$vMp4mHh9m`;NRf#XHl5q}#=FN?cT>lITZ0(45{HzU^f@-;d5uUQ1l_G$|+4|aSn zRV8BfG~m&?BXV}i*>$-CN9^IQKmUZ2HzW;=xgeC@LYGt4jT|-{^p&8)<+H>boD$~Y z?fbH)?XugJ2lh`AZ~Xc;!@!%&Ny#z!TW7IdL6Smp=ws9M0?*$r<=P*=MY%)bFHI?#MO;l0B z;qaBUHF|^ua3x<9u79kr zzYL*I*eR?u*c+NvlqCUx7*Go$9x$Ls(cFdZ=WGzs$nc2ow(ij4XcbXlh64aR-+%@6 z99~K@jI?FmmX+!fYwSbtfi3{ro%}&lIar0=7g&EXCv*ZVfY#7K@st+N5=rAQdLv#9 zrJt4V-E@(u=LMGh4v^4{tgG35 zPJ)4arn*-gRqk_fE^9M0LdeL#t4fixN^Ty~FEmEMGe`UrN2Xkh@6X-HnUYf(qG~-S z6=AI%tQ;)DA|lKTk-jeauDqQf4LSB$Z+ODe>=k)Aa-m$mVCQuI&``*h$Rq^vxT>-rsck$9>IBvI?mL)O->8u+^XnBU75J*%st_*~ zr!Oj2hImcqcbf=%alPQW5U)k8_vuOaP}?K~8~6!4L}R5f`7j!O46gz(wB+dO0d-ten&B{`~89>UWp-+%k#=g*gd6>zvU3wa1p zeiVyWq(npgSD=cl$jO!TPsPsa0$ywcR2O$4&%3%`4v36nvNVe4)gbsn%Tfa?)7Stw z#Vs}fS9*kdU?(P<+})+@I!*kE4T5)C2AmeT>)-ikqXAaFsqmsN?uzjz^ggGMQaLfQ z)4v*_D{Wbchsr3tp)O_)_T#wZXJ&2UvGR&3}7UVrx?$7GZYc%QB_3l(t)7~$O4}2e)pYaNF7Dbom+TJ9hYtB^J~I{}8>Gv+P9?AR)29hDi2bgvpD6psf?hXXF#D_EID9;a`>n}S~H5yNl1hz&eeg@ZQz&)B;LRfI71ig}Y}FFD;Lp_jmC z@V=0OaP%5A_nw^QyhTE}A%c7R3cJjlJlfby*yzhJq#B9~C|yQhtzZ3dB_1s9^4My{ zi+B^cYL-KoZWAzZT=&2bx6y(uhyeg9J>+?;i$Xa5CxY-^^krfWA<$3bM9I-an^|HA zAvoa8XaQsCD{@z&bFP$yc!Aa;CXmYODQ>hv;RfEb%Q&i{XRS05ynn{ZmEeDN{e5Hslf5hIxEhfy(6t6j%iOkp+lg6Fy{Zg(#cH ziw)G~JP2Lv4;usN0tn=*;&g3O3I3nWqqMYiw_;gIz+IjMoP0WCe~MrCGialnspYJ{ zoOt1NH60wxv@dBr|G>IijJFvTb&Wv$Hjyu@O`L$sv%#b@>$+XVMV6EWkR2*47+YYl zD}^mbN*5-P{BVqw`3`i1D8rKP)x%4PF8LFrBPq&V^AQUa-eg35o<1x1{g11*dXA20 z+zP9guGjYWJ~DO!BdNRngM(Q=bWD~7+v>Hb^zmjcLmuO1@D9COC>!L)?^T0XG~u*s zDh=@C?_9Zbd~NVb5x`Xk`Clz4P6XM&nXQm~EBU~;4u?upxi1Hj6!H7r!%GWb%1o{P z1-@mt*hcm`T{}@Oetg6F}i(Ph857#YmzI3GdQ zF|ISCmt)&*ZFFbiV!IsJc!#ZeKyCFY6Ad$-u~R}bVjz770=InpCe~}_+^V~N9fQTv zhO19lka+4}*A=hO;wwY0dr59zbh(b_VA_cgoZjVaE0#Q$#O0};QeC;#l)Hof!C{IT z52%k*#K7z5)cT z+UDzQTkv*j0yU=TMjcIL4rDiYSXR5wn&f_o42usGJ4%mwsN*V9kWp| zYnR7vZ=-*eDPxk_DkRyE+Eb;(rk+dGx&U9{7YNOb~Z5|VrO z?)mrk_g|cxaF&khb$#o~zEUdGAE!kl6vo~vCT2QwozRRvMF`9&Q7v?0V7oLcKflbu zo{F4uAukWMeMwFdg4;+7$vb6zr=ReM>l&p%E8YIyLuGARXyJPFv;hN=-i zw_t=;pw78tC7QozC!W^1_znAM-vz)KB~=C&l5$IWdR~34uaAX9<(d!JrUbjoyc-b? zeOscX(iGSEp*2ak(A$#!`f!FheVFYVork0yOnSU`H7C*j;|OED?hEaM?!%Q z3S1?wRg!m86{<>S^w8bWLbI^;p29+~tZn7FwNch9GxED!4`+rGB|FKfZ9(d#W&<#3 z3N3Xy>6e&0L>dsOaWR*et8#aB-Vrn71u2sR#9z2VhaHW^MS+PpV3Y|~kVzi~K+pL0 zm*4dG+N4Rmt`g&e68Z2-yUUiIN*>0=X4{jwF5#eW9o|M=0Ecga0WbKAc%|+8!{mEv z$4ebzfA@TDy*GNk3JY`Dcr(ZN8<_1Q$+zbx=@S>9twqm}`WB$sWtl%3x3Al7H=&c#Rq|bddw-gnOQ&$-|=%~O2vKxoyW1|}e291hIM0|EmJ0A^;9 zoKeOKn!&4E@zuHa+;f@nVo9>i)<~PSRgoRc)R?nLROex;Wh|(@(PhuInzy8KU9d2* z<%yY;8%epgs)JR9>rw#N`%>_;h=_U&sI9ouhWSQGfl%X z4r5D$20LX?fNJ~3w2IQ1a@60dDcq{zOHNAaAiaF~kWtFn<|PJ=iUsJ-pHjfrf_9s& zSBx_SWG>}ger~(jp70YAiO^79C1MsHcT(p``ngP!*rCEKEsoz-&YZIoWcUTu?PES( zQBUvnSfLJJV<9bcu@EcBeHOdmpZGJdR{GY&!GVFMvGH*iGqb!B*Tc1!02=ei&CPA# zmJGP-@Am^}T*oWQnN|T1-)g)Sc)f@`Iy}6L z^_Y-_^||n~uP@41<5_y<6@C6#1Lb!4wrq2qQyn!TA_%;8mKu@2eikx=TC``+9k}+b zJdZ-{Sp-4XD|-MM*hZqS74e+B!jE9iIk-<4CSd50h}`xbD%4M|0uB*|zcxD!<5<~IxSQjoR|a)3*egtW zYYU&UQ+@_s@^r zIr1ZBP>kr@d9f~G)#eKLWGN5$4?F~Uym|BHWHyj-%CYU{J9<0%2P|^0^@lspAz*R* z6*F*lKB(n2(dZzR>2osW5~DGI1^?%ZrdOOI0=CQ4VbMy@DxWp%T!bFW?zTMb{eDYG zc?khq(JU-M%{NMG65X8{8Gp6Yo1?+CIc8ZTy$xpl4KII$&{*Qc%i*K<&oMHGV3DM0 zk_MlnWN|4OGbfid?HfyDp_qa1Bc^{nnwP(Nps=gFd0W!h|K9_%>kFEgBqL$>h86XP`QJtU%AuABJPCT_;5ZQJF$ zln#KKMNUhQ6B7OnX9lku4gH*ZB+SJ84OR0r$nx*p`4b%!Bg+acL7&{!6k6&{m-KZV zJu>LyyI(JER!*Y_784B7h%F=rZ4DfMIQ+72Sos*5mCIpT_|n?^K+;AKK=w%d{3hrN zi-lF)m?_n&My*6=lg}#PHvm*h{Gb+jUK<$}9{x~&*yCwZrovlf1<(1Rw@!oA*{~R2 zG6sr7PH+)IfSXlSu(={LJT(RUC3p_@_3cmt5E45JSzIk)tfAw18^Z@^oTW2Tp1GBd zMGu#0fx&336u2xp`JstCpWHq|&C8W6j!OBhO^gBd>=3(8^Q~8n3u{i>1Nsc%%cJ;Oz+x z!tc#u73(S^(rTnKPGf7zj=N5Y&r6LND=mi!3%}ePEn8MUX%Jhce>--SfKdpPgLu=Y_2{>l3b{ij`I{OXY{W*Xxzc=i-M46tc;J!zs%PzzJ ze0t)R{pi;t=UyCn3Rbr`$qeXBAUWe>*~4FhhEDVx16_Qyp;?irjS`Hc$op~@6(>WY z4why*)6D%>C3`IyO*BMN^&1j+g|C3Ko?ygDAmStyI0U-ro^?wGaFa(|`MJ{e^v4ue zmM#OwNEGrlZgkJrI4KK8z`(d>P&8e13wf|(QA@&CH4{!Qeb6@w%7Q-)2^?7*1IR=z z0~Zn7TtXIVrwir9)!o$Zfv4v$XH?j9lSp(?`nc0@dwtSvrfAA@aZ$6fqWo<{n~8p| zIm1oH8`H->)fi9@Wzs93eEIDyw{P1%YOapIV?Vpw}_IeWb!%8Y_Jed<@A#x8sTl+N8XX-#{3C?~#kSSdXE34SRSMQH{ z+d{fOa0j`W2^=3SULM=+c0o{(+tasAm6`Q60M8S9GnEa81pqnCum0uk?C{PG(ao)i z`3J{OzRY%_E6tb{F5T;sjSSgHXx}6WK!jcI_uQtx*d~rx+PCn)lc$EUVad ztU}Le^p#nf+g5c^zhiw3@4!9L1QE>kG%7t2I3U{2kFz_-H#|MVcRSj6hzo;?sV7o{ znK&td*NLIW53!@+M!*~d>{BtwixP z{d+%t^NC)CFT-|p!0hVcyZZIDDCqenkkb(mE*6Fgrj-I8ZZaP2C z&R0m}D^df6$#F9Ug=)P*n3R;1-AZ3(7U=cqPEUIgG7|tp=5KkJAxS|&Kpd5fuaEmI zY1Vic$~hUv&$8p!Sjp!@3spB~ewH!~eDDm8PaReK29P9!WAnV!3fIlC^2uNYlgC1l z5nybDoL z)qZ$t6u$k!T>9>{oV@v2vUuwsL?&V`n&i!HG zaQhx@fVE1&TBSHN!-Sh*-=5umZ)I+7Zed}e46xI80Dvvqn2tbw>0K3xHD|31=rb{A z{>$CV>6qt_L=y@eKh&D_PGOxmosUJTf7$c}Fp1y4<{ZJ2*aao67oOJ%M+LfQdVOoF zq5qZxtAl=9$RhVq;i`d~^Y1TjDQ)l*Whn@tPl$-*Pm|K)?-JHf1{+FyWPK=#_@56DqfyTcrc3ZckAa+$ULmX@}`?YQO75LF#7;5aC(V}WqNVD?9tM0k(7PcVHRL! zNR2_OO`k2FpOGIet5=7pC!U~RWCGNy7M)2VyJsI2=WqjPug<4!da9S*HSQdQ+w+Wf zFWc4UYHz^JABN}ZjM;I&_}W)nQzHS6vGK7n36m17Q5_;GG1#~G`%%9udAz(tDC$~e z8EK+XjJXn27A$K zJ%Q-;Oih7$JBqpj-#1Wo59ksEm@VC_=AwAdLUE5Nsc>E5+!{0gZo0vCur;!U)O5;M zlYace&t>}uf}<1BfB+QA3>zJtTK!g8S@!Jq?_d4>(ZFXM{4E@=$_~JJPr)JhLB%=N zx>$>cmV*VLo`7?Jdq1t-=?~M$S3y2$@#sKiY6>~85WnV25CWb_m{T8L1@kXrum!dR z+&CD&e5t^2Q$|@q2{i7!kIF^)EiEi`a?N$@8jxk`oOL^Eg_DNo35e64rv@*gPCWM> zS_d4_{Bak70p@#zKN{ua@PIk7!ENrQRxW zJ&ascv=_W46s9Fbd&eYLK`>gSB{@v1PCPnDq|IbE*O_IAHnMG;&a}*F=`*2*GPktI z;ZJUUn%o0dn()J zc7<#$&{sc3@z)6pN?rWCM=pJlg-b}L;&S>V`}nv!C_4$g6#R5INAktYC#)Nq+Y%#w zl~?r-&fXUx=GUi(Mn@fOStw=GgTfRsiKf628`xTtmUVYnXy-_GJ}XHu^mHK=8a_e~ z-8WyHft`k`FQnfA{h>?~&dm1uCtjRIRAFJ^$)Yv#!l&F)6WLImvpAt3|9b1tmb;%B5L2GQ8wAK8^ArWYm!+do6vih%aQAP zyg6REzT1{AwIcS|{L-BHuSf1T*kTA{)!cuNno(xp&5X!DU^_*<%ot#StWo>#p|#CY zf0w-KY!%V(Oeg^Fxk0K5tEOemROb4aV2?{}t~p$5;*z0Wnw}`0*{m5gcrZqRu+aSP|DL-9qupzg9-jB2*qF)`l zoG)*>9L7u^Z}Y}kIHhmAVEPQ1766+&t=^_d2d*tI+79C2p${*rFP7~hme(k82-!-{ zxs*I*xiDxkFmMQl2AB^7#?p>h5UFg^+|C+8R3~Cez6!}syc$+y+x0zffP6}7fP#f= zlcuYFuv6b)!V2`2DVe1`BtcPXr-ROSOMK<>igbGZ({m@LUb2*@Z(v|^L24(M;fmL% z77Nx8CAn`9yh;|6b!wTq!%K{8c*Gn`pekL)YiFeO4l!>PKtPFNWD|XGGT0ZS+Ci!P z`k{iUXDRjh{~t~5!5G3UStaYZH#dF(pT=ws_q7~e8aup_FtvLHP7pzufEX`Km{$S^ysoV1&B=SfNnf$cGbrW&$Dy z1p3D(@B!;v`CmV9K@vBC@BqQ`)$;)XHe?Vi7a#W8zw2O>xhwO++Ri4^KR9SCAth-y zJuCAfGbj5zDK%x^C%|t4dkq@~WZ>`S1;n>;uuDuyPdfp8<$H5;bNhf7es^Saba!-g z^ZKTE?_<90?wQ^(9d)M4(?UJ@4Frn z5;6uj)TcqOxd*m%P=FKt@bA=(O)EG&)GIMH`S52)`^wbx^wRjm#C%YAC>rprq9-ON zch=U{P9~?OPCtLmKk*F?^!mH?W77)=3%DH+77`p59n};4K5omy8-a0fd53XFcck$uxewF_b4o<)qf)gGURTLZ?1333$F<1!* zj6#J*MC4o+y zf?;71yL^21Xi7?Fz|R^2_ynp-n#PV9=;l%=u;9jS@;3$-cN}mBPXSKdN$_5bU{qBH z0iSL95s0hzH|T#58XDOM$Vk3%Ifb^~cf0l}SdwZF~!^2)+MNkFH zPYAdP9|LfjCYEE7o15DJa4YHq{b?Z17B=p`svjF4q*V#@KL+V>0RFLLz}@AXl9Hl? z<*)<1d{TfH@&14C3n~LnL=9jlnGV8N{vEpiL%#<|F9hhn1SAmh%0KrF#{Uk=TmM-gXdXHB3EbOP^)ee3J%|B!C*{RbHP*MQ&R zv0<@s{x1F4bin;gf)%-0koF9aG9Vv7nPC0*VR_I#009gC(X&}uSu-H)_}{4;n-)m> zCy+xRF+lHqF#e_dhYnEQ6o5xv5uD?|^&=pE@G}16`rmN|?Z73F?t4%d=E3`hgz?Yt zSehlD~!2__)_dz}IgeEEyR zHzed%cuaI^c5cpa$+xokZizOHe0zl!_M z*T6h3$uBrC;h%s1?|u&q4gL`j65RCP4gY_J18WC#K>x`f^H?ya{Xeh$)o1@m|7)H; zp{s6)L=?g|8RZ)oxqGN8Kw%bR`1$yv1T=^HxnSMkBxL25%& z!-K)Wu{2gzC5sz3?zytD$vQc^I!6VBhUENp{6M4lq(nO`?{8mUpIu2wi9O&FwFwRj zP4f*7F#fCfzM-MasTt`V0|NuaV0+?YQBhG2u%$^zN=xkn^_S_d;$yD|g@$Z|M@EK& z_D&2dp#2R3YXY19ow(RA!C_$*Aipypoox^gD~loF;g - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From b01bf5778b4c6c117730438c006c1eb93faa5630 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Wed, 28 Mar 2018 09:17:30 -0500 Subject: [PATCH 0077/2777] HACK: proton: wine.inf: Don't show crash dialog by default. --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 4ed03c90c3e..8ae9f5bb1bf 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -412,6 +412,7 @@ HKLM,%CurrentVersionNT%\AeDebug,"Debugger",2,"winedbg --auto %ld %ld" HKLM,%CurrentVersionNT%\AeDebug,"Auto",2,"1" HKCU,Software\Wine\Debug,"RelayExclude",2,"ntdll.RtlEnterCriticalSection;ntdll.RtlTryEnterCriticalSection;ntdll.RtlLeaveCriticalSection;kernel32.48;kernel32.49;kernel32.94;kernel32.95;kernel32.96;kernel32.97;kernel32.98;kernel32.TlsGetValue;kernel32.TlsSetValue;kernel32.FlsGetValue;kernel32.FlsSetValue;kernel32.SetLastError" HKCU,Software\Wine\Debug,"RelayFromExclude",2,"winex11.drv;winemac.drv;user32;gdi32;advapi32;kernel32" +HKCU,Software\Wine\WineDbg,"ShowCrashDialog",0x00010003,0x00000000 [DirectX] HKLM,Software\Microsoft\DirectX,"Version",,"4.09.00.0904" From 5e25ae85bf50673ec63a8437a7e77fe13dba97aa Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Wed, 28 Mar 2018 09:21:41 -0500 Subject: [PATCH 0078/2777] HACK: proton: configure: Don't build winemenubuilder. --- configure.ac | 1 - loader/wine.inf.in | 1 - 2 files changed, 2 deletions(-) diff --git a/configure.ac b/configure.ac index ab38a00d9e0..2060a5d6bc6 100644 --- a/configure.ac +++ b/configure.ac @@ -3401,7 +3401,6 @@ WINE_CONFIG_MAKEFILE(programs/wineconsole) WINE_CONFIG_MAKEFILE(programs/winedbg) WINE_CONFIG_MAKEFILE(programs/winedevice) WINE_CONFIG_MAKEFILE(programs/winefile) -WINE_CONFIG_MAKEFILE(programs/winemenubuilder) WINE_CONFIG_MAKEFILE(programs/winemine) WINE_CONFIG_MAKEFILE(programs/winemsibuilder) WINE_CONFIG_MAKEFILE(programs/winepath) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 8ae9f5bb1bf..ff22a68860b 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2449,7 +2449,6 @@ StartType=3 ErrorControl=1 [Services] -HKLM,%CurrentVersion%\RunServices,"winemenubuilder",2,"%11%\winemenubuilder.exe -a -r" HKLM,"System\CurrentControlSet\Services\Eventlog\Application",,16 HKLM,"System\CurrentControlSet\Services\Eventlog\System","Sources",0x10000,"" HKLM,"System\CurrentControlSet\Services\Tcpip\Parameters","DataBasePath",,"%12%\etc" From 9c00697dc257a30bfbe91959674fb20eba180efa Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Thu, 29 Mar 2018 11:09:53 -0500 Subject: [PATCH 0079/2777] HACK: proton: wine.inf: Add native,builtin overrides for msvcrt DLLs. --- loader/wine.inf.in | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index ff22a68860b..19231c95747 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -96,6 +96,7 @@ AddReg=\ ThemeManager,\ VersionInfo,\ LicenseInformation, \ + ProtonOverrides, \ SteamClient [DefaultInstall.ntamd64] @@ -122,6 +123,7 @@ AddReg=\ ThemeManager,\ VersionInfo.ntamd64,\ LicenseInformation, \ + ProtonOverrides, \ SteamClient.ntamd64 [DefaultInstall.ntarm64] @@ -163,6 +165,7 @@ AddReg=\ Tapi,\ VersionInfo.ntamd64,\ LicenseInformation, \ + ProtonOverrides, \ SteamClient.ntamd64 [Wow64Install.ntarm64] @@ -2692,3 +2695,32 @@ HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll",,"%16426%\Steam\steamcl HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll64",,"%16426%\Steam\steamclient64.dll" HKCU,Software\Valve\Steam\ActiveProcess,"SteamPath",,"%16426%\Steam" HKLM,Software\Wow6432Node\Valve\Steam,"InstallPath",,"%16422%\Steam" + +[ProtonOverrides] +;;Likely want *80 and *90 too, but those require removing Wine's manifest files. +HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"msvcp100",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"msvcr100",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"vcomp100",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"atl110",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"msvcp110",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"msvcr110",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"vcomp110",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"atl120",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"msvcp120",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"msvcr120",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"vcomp120",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-conio-l1-1-0",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-heap-l1-1-0",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-locale-l1-1-0",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-math-l1-1-0",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-runtime-l1-1-0",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-stdio-l1-1-0",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-time-l1-1-0",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"atl140",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"concrt140",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"msvcp140",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"msvcr140",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"ucrtbase",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"vcomp140",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"vcruntime140",0x2,"native,builtin" From d60d512f5a4baa52e70624ea9eb25e50be750953 Mon Sep 17 00:00:00 2001 From: Patryk Obara Date: Fri, 26 Apr 2019 20:40:31 +0200 Subject: [PATCH 0080/2777] HACK: proton: winex11: Fill WM_CLASS based on Steam appid. Some desktop environments (Gnome 3, Cinnamon) decide on an application icon in the following order: - If the first string in WM_CLASS property can be correlated to a name or StartupWMClass key in a .desktop entry file, then the associated icon will be used. - If the second string in WM_CLASS property can be correlated to a name or StartupWMClass key in a .desktop entry file, then the associated icon will be used. - If the application has indicated an icon resource through WM_HINTS property, then the associated X window or pixmaps will be used. Upstream Wine usually deals with this by placing a .desktop file with StartupWMClass filled to match first string in WM_CLASS property (which is the name of exe file being run). Wine in Proton does not do it, but still puts "Wine" as second string, therefore desktop environment can't differentiate between Wine in Proton and Wine installed in OS. By replacing "Wine" with "steam_app_" we force DE to fallback to icon indicated by WM_HINTS (ico file embedded in exe file). Steam can override this behaviour by installing properly crafted .desktop entry file. If SteamAppId environment variable is missing, then generic "steam_proton" name is used instead. --- dlls/winex11.drv/window.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 98b0b23e103..5150b552faf 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -864,8 +864,19 @@ static void set_initial_wm_hints( Display *display, Window window ) /* class hints */ if ((class_hints = XAllocClassHint())) { - class_hints->res_name = process_name; - class_hints->res_class = process_name; + static char steam_proton[] = "steam_proton"; + const char *app_id = getenv("SteamAppId"); + char proton_app_class[128]; + + if(app_id && *app_id){ + snprintf(proton_app_class, sizeof(proton_app_class), "steam_app_%s", app_id); + class_hints->res_name = proton_app_class; + class_hints->res_class = proton_app_class; + }else{ + class_hints->res_name = steam_proton; + class_hints->res_class = steam_proton; + } + XSetClassHint( display, window, class_hints ); XFree( class_hints ); } From 87a85d50c502f705eeaf7a9f3f4c9e54c707ae56 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Mon, 6 Aug 2018 08:06:03 -0500 Subject: [PATCH 0081/2777] HACK: proton: server: Set default timeout to 0 The Steam client will be waiting for the wineserver to exit to set up some environment variables, so make it wait as short as possible. --- server/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/main.c b/server/main.c index acf6f1188ac..1390d15bb88 100644 --- a/server/main.c +++ b/server/main.c @@ -39,7 +39,7 @@ /* command-line options */ int debug_level = 0; int foreground = 0; -timeout_t master_socket_timeout = 3 * -TICKS_PER_SEC; /* master socket timeout, default is 3 seconds */ +timeout_t master_socket_timeout = 0; /* master socket timeout, default is 3 seconds */ const char *server_argv0; /* parse-line args */ From 77a7990f8f57a0d321934a698eb0c9b27ee50e19 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Mon, 20 Aug 2018 10:58:09 -0500 Subject: [PATCH 0082/2777] HACK: proton: secur32: Return real Unix username from GetUserNameEx(NameDisplay) --- dlls/secur32/secur32.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/dlls/secur32/secur32.c b/dlls/secur32/secur32.c index d703757bae7..bf94b1a594e 100644 --- a/dlls/secur32/secur32.c +++ b/dlls/secur32/secur32.c @@ -1135,9 +1135,22 @@ BOOLEAN WINAPI GetUserNameExW( return FALSE; } + case NameDisplay: + { + static const WCHAR wineusernameW[] = {'W','I','N','E','U','S','E','R','N','A','M','E',0}; + + DWORD needed = GetEnvironmentVariableW(wineusernameW, NULL, 0); + if (*nSize < needed) { + *nSize = needed; + SetLastError(ERROR_MORE_DATA); + return FALSE; + } + *nSize = GetEnvironmentVariableW(wineusernameW, lpNameBuffer, *nSize); + return TRUE; + } + case NameUnknown: case NameFullyQualifiedDN: - case NameDisplay: case NameUniqueId: case NameCanonical: case NameUserPrincipal: From a3f687c45dff423b27dcda55fe1a7175d435547b Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Mon, 24 Sep 2018 12:37:49 -0500 Subject: [PATCH 0083/2777] HACK: proton: HACK: dbghelp: Disable DWARF parsing Patch by Zeb. Our DWARF parser has been known to crash winedbg in some cases. Since probably no concerned parties are going to be using plain winedbg, just don't bother parsing anything. --- dlls/dbghelp/dwarf.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c index 9ed63463513..a2d57173587 100644 --- a/dlls/dbghelp/dwarf.c +++ b/dlls/dbghelp/dwarf.c @@ -4200,6 +4200,11 @@ BOOL dwarf2_parse(struct module* module, ULONG_PTR load_offset, struct module_format* dwarf2_modfmt; dwarf2_parse_module_context_t module_ctx; +/* Our DWARF parser has been known to crash winedbg in some cases. Since + * probably no concerned parties are going to be using plain winedbg, just don't + * bother parsing anything. */ +return FALSE; + if (!dwarf2_init_section(&eh_frame, fmap, ".eh_frame", NULL, &eh_frame_sect)) /* lld produces .eh_fram to avoid generating a long name */ dwarf2_init_section(&eh_frame, fmap, ".eh_fram", NULL, &eh_frame_sect); From e4944f439d92ad3de94e979384ef3dcdff4f5a92 Mon Sep 17 00:00:00 2001 From: Sven Baars Date: Thu, 5 Dec 2019 13:48:38 +0100 Subject: [PATCH 0084/2777] HACK: proton: ntdll: Return a handle to kernel32 when being asked for mfc42. For some applications mfc42 is loaded, but never actually used. We can add Steam game IDs when we find more of such applications. --- dlls/ntdll/loader.c | 58 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 327979dfe40..674731950be 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -3058,6 +3058,44 @@ static NTSTATUS search_dll_file( LPCWSTR paths, LPCWSTR search, UNICODE_STRING * return status; } + +static WCHAR *strstriW( const WCHAR *str, const WCHAR *sub ) +{ + while (*str) + { + const WCHAR *p1 = str, *p2 = sub; + while (*p1 && *p2 && tolower(*p1) == tolower(*p2)) { p1++; p2++; } + if (!*p2) return (WCHAR *)str; + str++; + } + return NULL; +} + +static WCHAR *get_env( const WCHAR *var ) +{ + UNICODE_STRING name, value; + + RtlInitUnicodeString( &name, var ); + value.Length = 0; + value.MaximumLength = 0; + value.Buffer = NULL; + + if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL) { + + value.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, value.Length + sizeof(WCHAR) ); + value.MaximumLength = value.Length; + + if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_SUCCESS) { + value.Buffer[value.Length / sizeof(WCHAR)] = 0; + return value.Buffer; + } + + RtlFreeHeap( GetProcessHeap(), 0, value.Buffer ); + } + + return NULL; +} + /*********************************************************************** * find_dll_file * @@ -3115,6 +3153,26 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, UNI done: RtlFreeHeap( GetProcessHeap(), 0, fullname ); if (wow64_old_value) RtlWow64EnableFsRedirectionEx( 1, &wow64_old_value ); + + if (status != STATUS_SUCCESS) + { + /* HACK for Proton issue #17 + * + * Some games try to load mfc42.dll, but then proceed to not use it. + * Just return a handle to kernel32 in that case. + */ + WCHAR *sgi = get_env( L"SteamGameId" ); + if (sgi) + { + if (!wcscmp( sgi, L"105450") && + strstriW( libname, L"mfc42" )) + { + WARN_(loaddll)( "Using a fake mfc42 handle\n" ); + status = find_dll_file( load_path, L"kernel32.dll", nt_name, pwm, mapping, image_info, id ); + } + RtlFreeHeap(GetProcessHeap(), 0, sgi); + } + } return status; } From 08290ccabc137d205ceec261706d78b021d14fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Nov 2022 11:08:22 +0100 Subject: [PATCH 0085/2777] HACK: proton: ntdll: Export a function to set a Unix environment variable --- dlls/ntdll/ntdll.spec | 1 + dlls/ntdll/unix/env.c | 10 +++ dlls/ntdll/unix/loader.c | 1 + dlls/ntdll/unix/unix_private.h | 1 + tools/gdbinit.py | 113 +++++++++++++++++++++++++++++++++ 5 files changed, 126 insertions(+) create mode 100644 tools/gdbinit.py diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index b41e29c0ff5..05999131fc5 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -1696,6 +1696,7 @@ @ extern -private __wine_syscall_dispatcher @ extern -private __wine_unix_call_dispatcher @ extern -arch=arm64 __wine_current_teb +@ stdcall -syscall __wine_set_unix_env(ptr ptr) # Debugging @ stdcall -syscall -norelay __wine_dbg_write(ptr long) diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c index 6f1709f4713..3c387ba9027 100644 --- a/dlls/ntdll/unix/env.c +++ b/dlls/ntdll/unix/env.c @@ -2418,3 +2418,13 @@ void WINAPI RtlSetLastWin32Error( DWORD err ) #endif teb->LastErrorValue = err; } + + +/********************************************************************** + * __wine_set_unix_env (ntdll.so) + */ +ULONG WINAPI __wine_set_unix_env( const char *var, const char *val ) +{ + setenv(var, val, 1); + return 0; +} diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 3d250b72178..fac93f815fd 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -357,6 +357,7 @@ static void * const syscalls[] = NtWriteVirtualMemory, NtYieldExecution, __wine_dbg_write, + __wine_set_unix_env, __wine_unix_spawnvp, wine_nt_to_unix_file_name, wine_server_call, diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 975ac0b334f..a723ae3c5b9 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -294,6 +294,7 @@ extern NTSTATUS call_user_apc_dispatcher( CONTEXT *context_ptr, ULONG_PTR arg1, PNTAPCFUNC func, NTSTATUS status ) DECLSPEC_HIDDEN; extern NTSTATUS call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context ) DECLSPEC_HIDDEN; extern void call_raise_user_exception_dispatcher(void) DECLSPEC_HIDDEN; +extern ULONG WINAPI __wine_set_unix_env( const char *var, const char *val ) DECLSPEC_HIDDEN; #define IMAGE_DLLCHARACTERISTICS_PREFER_NATIVE 0x0010 /* Wine extension */ 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() From 89631f2bf0cd5a1dd4a075c50db2fc365442b3c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 18 Dec 2019 13:49:00 +0100 Subject: [PATCH 0086/2777] HACK: proton: ntdll: Strip gameoverlayrenderer.so from LD_PRELOAD before executing explorer.exe. Work around a bug in gameoverlayrenderer which introduces 50ms hangs during XCheckIfEvent after approx 40 minutes of gameplay. The original user32 hack broke Steam overlay in Origin games, and Steam Input consequently. This ntdll implementation should be safer as it'll modify the environment after the new process has started forking. Link: https://github.com/ValveSoftware/Proton/issues/3316 CW-Bug-Id: #18946 --- dlls/ntdll/unix/loader.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index fac93f815fd..c46f109af71 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -729,11 +729,42 @@ NTSTATUS exec_wineloader( char **argv, int socketfd, const pe_image_info_t *pe_i WORD machine = pe_info->machine; ULONGLONG res_start = pe_info->base; ULONGLONG res_end = pe_info->base + pe_info->map_size; + const char *ld_preload = getenv( "LD_PRELOAD" ); char preloader_reserve[64], socket_env[64]; if (pe_info->image_flags & IMAGE_FLAGS_WineFakeDll) res_start = res_end = 0; if (pe_info->image_flags & IMAGE_FLAGS_ComPlusNativeReady) machine = native_machine; + /* HACK: Unset LD_PRELOAD before executing explorer.exe to disable buggy gameoverlayrenderer.so */ + if (ld_preload && argv[2] && !strcmp( argv[2], "C:\\windows\\system32\\explorer.exe" ) && + argv[3] && !strcmp( argv[3], "/desktop" )) + { + static char const gorso[] = "gameoverlayrenderer.so"; + static int gorso_len = sizeof(gorso) - 1; + int len = strlen( ld_preload ); + char *next, *tmp, *env = malloc( sizeof("LD_PRELOAD=") + len ); + + if (!env) return STATUS_NO_MEMORY; + strcpy( env, "LD_PRELOAD=" ); + strcat( env, ld_preload ); + + tmp = env + 11; + do + { + if (!(next = strchr( tmp, ':' ))) next = tmp + strlen( tmp ); + if (next - tmp >= gorso_len && strncmp( next - gorso_len, gorso, gorso_len ) == 0) + { + if (*next) memmove( tmp, next + 1, strlen(next) ); + else *tmp = 0; + next = tmp; + } + else tmp = next + 1; + } + while (*next); + + putenv( env ); + } + signal( SIGPIPE, SIG_DFL ); sprintf( socket_env, "WINESERVERSOCKET=%u", socketfd ); From 3a98b9cc1dc8bdb17b8fb32b509d237c46d5dc35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 16 Oct 2020 23:37:09 +0200 Subject: [PATCH 0087/2777] dotnetfx35.exe: Add stub program. This makes it possible to override native dotnetfx35 installer, which is broken in an unfixable way. Recent Windows versions also bypass its execution somehow. --- configure.ac | 1 + programs/dotnetfx35/Makefile.in | 7 +++++++ programs/dotnetfx35/main.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 programs/dotnetfx35/Makefile.in create mode 100644 programs/dotnetfx35/main.c diff --git a/configure.ac b/configure.ac index 2060a5d6bc6..96e46275b5c 100644 --- a/configure.ac +++ b/configure.ac @@ -3319,6 +3319,7 @@ WINE_CONFIG_MAKEFILE(programs/cscript) WINE_CONFIG_MAKEFILE(programs/dism) WINE_CONFIG_MAKEFILE(programs/dllhost) WINE_CONFIG_MAKEFILE(programs/dplaysvr) +WINE_CONFIG_MAKEFILE(programs/dotnetfx35) WINE_CONFIG_MAKEFILE(programs/dpnsvr) WINE_CONFIG_MAKEFILE(programs/dpvsetup) WINE_CONFIG_MAKEFILE(programs/dxdiag) diff --git a/programs/dotnetfx35/Makefile.in b/programs/dotnetfx35/Makefile.in new file mode 100644 index 00000000000..e50ed37f700 --- /dev/null +++ b/programs/dotnetfx35/Makefile.in @@ -0,0 +1,7 @@ +MODULE = dotnetfx35.exe +IMPORTS = + +EXTRADLLFLAGS = -mwindows -mno-cygwin + +C_SRCS = \ + main.c diff --git a/programs/dotnetfx35/main.c b/programs/dotnetfx35/main.c new file mode 100644 index 00000000000..cd6df5bcf41 --- /dev/null +++ b/programs/dotnetfx35/main.c @@ -0,0 +1,32 @@ +/* + * Fake dotnetfx35.exe installer + * + * Copyright 2020 Rémi Bernon + * + * 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 + */ + +#include +#include + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dotnetfx); + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + FIXME("stub!"); + return 0; +} From 6164e6218e33c6622ea33b6674cc4da52a7ec987 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Thu, 30 Jan 2020 10:16:19 -0600 Subject: [PATCH 0088/2777] winegstreamer: HACK: Use a different gst registry file per architecture --- dlls/winegstreamer/wg_parser.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index d2db1f039e4..2fad026e750 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1669,6 +1669,22 @@ static void init_gstreamer_once(void) int argc = ARRAY_SIZE(args) - 1; char **argv = args; GError *err; + const char *e; + + if ((e = getenv("WINE_GST_REGISTRY_DIR"))) + { + char gst_reg[PATH_MAX]; +#if defined(__x86_64__) + const char *arch = "/registry.x86_64.bin"; +#elif defined(__i386__) + const char *arch = "/registry.i386.bin"; +#else +#error Bad arch +#endif + strcpy(gst_reg, e); + strcat(gst_reg, arch); + setenv("GST_REGISTRY_1_0", gst_reg, 1); + } if (!gst_init_check(&argc, &argv, &err)) { From 8aa14aea1f52dd537129c6793f0d200a30ef27fd Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Tue, 28 Jan 2020 14:30:43 -0600 Subject: [PATCH 0089/2777] winegstreamer: HACK: Try harder to register winegstreamer filters. --- dlls/quartz/filtergraph.c | 17 +++++++++++++++++ dlls/winegstreamer/main.c | 2 ++ 2 files changed, 19 insertions(+) diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c index 437691b5553..13789a9df6a 100644 --- a/dlls/quartz/filtergraph.c +++ b/dlls/quartz/filtergraph.c @@ -5610,11 +5610,28 @@ static const IUnknownVtbl IInner_VTable = FilterGraphInner_Release }; +static BOOL CALLBACK register_winegstreamer_proc(INIT_ONCE *once, void *param, void **ctx) +{ + HMODULE mod = LoadLibraryW(L"winegstreamer.dll"); + if (mod) + { + HRESULT (WINAPI *proc)(void) = (void *)GetProcAddress(mod, "DllRegisterServer"); + proc(); + FreeLibrary(mod); + } + return TRUE; +} + static HRESULT filter_graph_common_create(IUnknown *outer, IUnknown **out, BOOL threaded) { + static INIT_ONCE once = INIT_ONCE_STATIC_INIT; struct filter_graph *object; HRESULT hr; + /* HACK: our build system makes it difficult to load gstreamer on prefix + * creation, so it won't get registered. Do that here instead. */ + InitOnceExecuteOnce(&once, register_winegstreamer_proc, NULL, NULL); + *out = NULL; if (!(object = calloc(1, sizeof(*object)))) diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 2675430019f..a5846e601df 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -838,6 +838,8 @@ HRESULT WINAPI DllRegisterServer(void) TRACE(".\n"); + init_gstreamer(); + if (FAILED(hr = __wine_register_resources())) return hr; From 6a0b1d49179a3766d49f944b9a0902d4e1d4e4fd Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Fri, 18 Dec 2020 14:08:04 -0600 Subject: [PATCH 0090/2777] mfplat: Register winegstreamer interfaces on load See also "winegstreamer: HACK: Try harder to register winegstreamer filters." --- dlls/mfplat/main.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index e1315de125a..126814f0216 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -1584,6 +1584,18 @@ HRESULT WINAPI MFTGetInfo(CLSID clsid, WCHAR **name, MFT_REGISTER_TYPE_INFO **in return hr; } +static BOOL CALLBACK register_winegstreamer_proc(INIT_ONCE *once, void *param, void **ctx) +{ + HMODULE mod = LoadLibraryW(L"winegstreamer.dll"); + if (mod) + { + HRESULT (WINAPI *proc)(void) = (void *)GetProcAddress(mod, "DllRegisterServer"); + proc(); + FreeLibrary(mod); + } + return TRUE; +} + /*********************************************************************** * MFStartup (mfplat.@) */ @@ -1591,9 +1603,12 @@ HRESULT WINAPI MFStartup(ULONG version, DWORD flags) { #define MF_VERSION_XP MAKELONG( MF_API_VERSION, 1 ) #define MF_VERSION_WIN7 MAKELONG( MF_API_VERSION, 2 ) + static INIT_ONCE once = INIT_ONCE_STATIC_INIT; TRACE("%#lx, %#lx.\n", version, flags); + InitOnceExecuteOnce(&once, register_winegstreamer_proc, NULL, NULL); + if (version != MF_VERSION_XP && version != MF_VERSION_WIN7) return MF_E_BAD_STARTUP_VERSION; From 0e71ea8bc4546624994503daca1f8a696fd98a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 6 Jul 2021 14:06:11 +0200 Subject: [PATCH 0091/2777] HACK: quartz: Keep a reference on the IMediaPosition interface. In the same way we do for IMediaSeeking. Both interfaces are actually implemented with a shared refcount and releasing both makes the filter be destroyed. For Tokyo Xanadu eX+ crash on launch. CW-Bug-Id: #18994 --- dlls/quartz/filtergraph.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c index 13789a9df6a..649fb7580f3 100644 --- a/dlls/quartz/filtergraph.c +++ b/dlls/quartz/filtergraph.c @@ -74,6 +74,7 @@ struct filter struct list entry; IBaseFilter *filter; IMediaSeeking *seeking; + IMediaPosition *position; WCHAR *name; BOOL sorting; }; @@ -556,6 +557,7 @@ static BOOL has_output_pins(IBaseFilter *filter) static void update_seeking(struct filter *filter) { + IMediaPosition *position; IMediaSeeking *seeking; if (!filter->seeking) @@ -574,11 +576,19 @@ static void update_seeking(struct filter *filter) IMediaSeeking_Release(seeking); } } + + if (!filter->position) + { + /* Tokyo Xanadu eX+, same as above, same developer, destroys its filter when + * its IMediaPosition interface is released, so cache the interface instead + * of querying for it every time. */ + if (SUCCEEDED(IBaseFilter_QueryInterface(filter->filter, &IID_IMediaPosition, (void **)&position))) + filter->position = position; + } } static BOOL is_renderer(struct filter *filter) { - IMediaPosition *media_position; IAMFilterMiscFlags *flags; BOOL ret = FALSE; @@ -588,16 +598,11 @@ static BOOL is_renderer(struct filter *filter) ret = TRUE; IAMFilterMiscFlags_Release(flags); } - else if (SUCCEEDED(IBaseFilter_QueryInterface(filter->filter, &IID_IMediaPosition, (void **)&media_position))) - { - if (!has_output_pins(filter->filter)) - ret = TRUE; - IMediaPosition_Release(media_position); - } else { update_seeking(filter); - if (filter->seeking && !has_output_pins(filter->filter)) + if ((filter->seeking || filter->position) && + !has_output_pins(filter->filter)) ret = TRUE; } return ret; @@ -668,6 +673,7 @@ static HRESULT WINAPI FilterGraph2_AddFilter(IFilterGraph2 *iface, list_add_head(&graph->filters, &entry->entry); entry->sorting = FALSE; entry->seeking = NULL; + entry->position = NULL; ++graph->version; return duplicate_name ? VFW_S_DUPLICATE_NAME : hr; @@ -735,6 +741,8 @@ static HRESULT WINAPI FilterGraph2_RemoveFilter(IFilterGraph2 *iface, IBaseFilte { IBaseFilter_SetSyncSource(pFilter, NULL); IBaseFilter_Release(pFilter); + if (entry->position) + IMediaPosition_Release(entry->position); if (entry->seeking) IMediaSeeking_Release(entry->seeking); list_remove(&entry->entry); From 3ac813684ef61fd18b2ffd8e0e0024b841a4ea3f Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Thu, 18 Mar 2021 16:54:44 -0400 Subject: [PATCH 0092/2777] mfplat: Stub out MFCreateDXGIDeviceManager, to avoid the d3d path. --- dlls/mfplat/main.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 126814f0216..cd51bc9ca45 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -9225,9 +9225,29 @@ static const IMFDXGIDeviceManagerVtbl dxgi_device_manager_vtbl = HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **manager) { struct dxgi_device_manager *object; + const char *sgi = getenv("SteamGameId"); + const char *do_not_create = getenv("PROTON_DO_NOT_CREATE_DXGI_DEVICE_MANAGER"); TRACE("%p, %p.\n", token, manager); + /* Returning a DXGI device manager triggers a bug and breaks The + * Long Dark and Trailmakers. This should be removed once CW bug + * #19126 is solved. Returning a DXGI device manager also breaks + * Age of Empires Definitive Edition - this gameid should be removed + * once CW bug #19741 is solved. */ + if (sgi && ( + strcmp(sgi, "305620") == 0 || /* The Long Dark */ + strcmp(sgi, "585420") == 0 || /* Trailmakers */ + strcmp(sgi, "684450") == 0 || /* Surviving the Aftermath */ + strcmp(sgi, "1017900") == 0 || /* Age of Empires: Definitive Edition */ + strcmp(sgi, "1331440") == 0 || /* FUSER */ + (do_not_create && do_not_create[0] != '\0') + )) + { + FIXME("stubbing out\n"); + return E_NOTIMPL; + } + if (!token || !manager) return E_POINTER; From 9356400653433d2303a43a0f6e7fa02ddd31ac87 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Thu, 27 May 2021 19:40:45 +0200 Subject: [PATCH 0093/2777] HACK: mfreadwrite: Ignore source reader flushes for The Medium. --- dlls/mfreadwrite/reader.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 5296e77f3c3..01f54e50f29 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -2101,10 +2101,20 @@ static HRESULT source_reader_flush_async(struct source_reader *reader, unsigned static HRESULT WINAPI src_reader_Flush(IMFSourceReader *iface, DWORD index) { struct source_reader *reader = impl_from_IMFSourceReader(iface); + const char *sgi; HRESULT hr; TRACE("%p, %#lx.\n", iface, index); + sgi = getenv("SteamGameId"); + if (sgi && strcmp(sgi, "1293160") == 0) + { + /* In The Medium flushes sometimes lead to the callback + calling objects that have already been destroyed. */ + WARN("ignoring flush\n"); + return S_OK; + } + EnterCriticalSection(&reader->cs); if (reader->async_callback) From 4f3d59529f9c4dc9f06cae344cf796275b85558e Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 19 Mar 2021 17:01:54 -0400 Subject: [PATCH 0094/2777] winegstreamer: Report streams backwards in media source. Signed-off-by: Derek Lesho Wine-Staging: mfplat-streaming-support --- dlls/winegstreamer/media_source.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 542189b28f5..c7abd24c7a7 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1491,12 +1491,13 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ {WG_PARSER_TAG_LANGUAGE, &MF_SD_LANGUAGE}, {WG_PARSER_TAG_NAME, &MF_SD_STREAM_NAME}, }; + IMFStreamDescriptor **descriptor = descriptors + object->stream_count - 1 - i; unsigned int j; WCHAR *strW; DWORD len; char *str; - IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[i]); + IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, descriptor); for (j = 0; j < ARRAY_SIZE(tags); ++j) { @@ -1509,7 +1510,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ } strW = malloc(len * sizeof(*strW)); if (MultiByteToWideChar(CP_UTF8, 0, str, -1, strW, len)) - IMFStreamDescriptor_SetString(descriptors[i], tags[j].mf_attr, strW); + IMFStreamDescriptor_SetString(*descriptor, tags[j].mf_attr, strW); free(strW); free(str); } From bedb7b53764576d95dd01ea99fc6f290edc9ed3a Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 4 Dec 2020 16:17:11 -0500 Subject: [PATCH 0095/2777] winegstreamer: In the default configuration, select one stream of each major type. Wine-Staging: mfplat-streaming-support --- dlls/winegstreamer/media_source.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index c7abd24c7a7..970f770ea71 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1387,6 +1387,7 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source) { + BOOL video_selected = FALSE, audio_selected = FALSE; IMFStreamDescriptor **descriptors = NULL; unsigned int stream_count = UINT_MAX; struct media_source *object; @@ -1519,9 +1520,28 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc))) goto fail; + /* Select one of each major type. */ for (i = 0; i < object->stream_count; i++) { - IMFPresentationDescriptor_SelectStream(object->pres_desc, i); + IMFMediaTypeHandler *handler; + GUID major_type; + BOOL select_stream = FALSE; + + IMFStreamDescriptor_GetMediaTypeHandler(descriptors[i], &handler); + IMFMediaTypeHandler_GetMajorType(handler, &major_type); + if (IsEqualGUID(&major_type, &MFMediaType_Video) && !video_selected) + { + select_stream = TRUE; + video_selected = TRUE; + } + if (IsEqualGUID(&major_type, &MFMediaType_Audio) && !audio_selected) + { + select_stream = TRUE; + audio_selected = TRUE; + } + if (select_stream) + IMFPresentationDescriptor_SelectStream(object->pres_desc, i); + IMFMediaTypeHandler_Release(handler); IMFStreamDescriptor_Release(descriptors[i]); } free(descriptors); From ed1ae37c6eb49d2b84f4a300ef1ff20f10fd4c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 15 Dec 2021 11:51:33 +0100 Subject: [PATCH 0096/2777] winegstreamer: Update offset according to the size of the buffer read. Wine-Staging: mfplat-streaming-support --- dlls/winegstreamer/wg_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 2fad026e750..77ee2d5666b 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1084,7 +1084,7 @@ static void *push_data(void *arg) break; } - parser->next_offset += size; + parser->next_offset += gst_buffer_get_size(buffer); buffer->duration = buffer->pts = -1; if ((ret = gst_pad_push(parser->my_src, buffer)) < 0) From 39e48f1a2ac64d43694a7baa5ae7ebe84b866550 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Wed, 12 Jan 2022 22:48:35 +0300 Subject: [PATCH 0097/2777] winegstreamer: Add MFVideoFormat_ARGB32 output for the source. CW-Bug-Id: #19975 Wine-Staging: mfplat-streaming-support --- 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 970f770ea71..615465b1ab9 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -856,7 +856,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[6]; + IMFMediaType *stream_types[7]; struct wg_format format; DWORD type_count = 0; unsigned int i; @@ -875,6 +875,7 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) &MFVideoFormat_YUY2, &MFVideoFormat_IYUV, &MFVideoFormat_I420, + &MFVideoFormat_ARGB32, }; IMFMediaType *base_type = mf_media_type_from_wg_format(&format); From 9e57406b10188ba4684a1c5a1232bee91544bd53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Jan 2022 13:21:24 +0100 Subject: [PATCH 0098/2777] strmbase: Add stub IPropertyBag interface for strmbase_filter. Required for Final Fantasy XIV intro video. CW-Bug-Id: #19624 --- include/wine/strmbase.h | 1 + libs/strmbase/filter.c | 48 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/include/wine/strmbase.h b/include/wine/strmbase.h index 1b4cc3f7657..c5abca26757 100644 --- a/include/wine/strmbase.h +++ b/include/wine/strmbase.h @@ -120,6 +120,7 @@ void strmbase_sink_cleanup(struct strmbase_sink *pin); struct strmbase_filter { IBaseFilter IBaseFilter_iface; + IPropertyBag IPropertyBag_iface; IUnknown IUnknown_inner; IUnknown *outer_unk; LONG refcount; diff --git a/libs/strmbase/filter.c b/libs/strmbase/filter.c index ee41611a198..f9ab84d5a9d 100644 --- a/libs/strmbase/filter.c +++ b/libs/strmbase/filter.c @@ -226,6 +226,8 @@ static HRESULT WINAPI filter_inner_QueryInterface(IUnknown *iface, REFIID iid, v { *out = &filter->IBaseFilter_iface; } + else if (IsEqualIID(iid, &IID_IPropertyBag)) + *out = &filter->IPropertyBag_iface; else { WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); @@ -509,6 +511,51 @@ static const IBaseFilterVtbl filter_vtbl = filter_QueryVendorInfo, }; +static inline struct strmbase_filter *impl_from_IPropertyBag(IPropertyBag *iface) +{ + return CONTAINING_RECORD(iface, struct strmbase_filter, IPropertyBag_iface); +} + +static HRESULT WINAPI property_bag_QueryInterface(IPropertyBag *iface, REFIID iid, void **out) +{ + struct strmbase_filter *filter = impl_from_IPropertyBag(iface); + return IUnknown_QueryInterface(filter->outer_unk, iid, out); +} + +static ULONG WINAPI property_bag_AddRef(IPropertyBag *iface) +{ + struct strmbase_filter *filter = impl_from_IPropertyBag(iface); + return IUnknown_AddRef(filter->outer_unk); +} + +static ULONG WINAPI property_bag_Release(IPropertyBag *iface) +{ + struct strmbase_filter *filter = impl_from_IPropertyBag(iface); + return IUnknown_Release(filter->outer_unk); +} + +static HRESULT WINAPI property_bag_Read(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value, + IErrorLog *error_log) +{ + FIXME("iface %p, prop_name %s, value %p, error_log %p stub!\n", iface, debugstr_w(prop_name), value, error_log); + return E_NOTIMPL; +} + +static HRESULT WINAPI property_bag_Write(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value) +{ + FIXME("iface %p, prop_name %s, value %p stub!\n", iface, debugstr_w(prop_name), value); + return E_NOTIMPL; +} + +static const IPropertyBagVtbl property_bag_vtbl = +{ + property_bag_QueryInterface, + property_bag_AddRef, + property_bag_Release, + property_bag_Read, + property_bag_Write, +}; + VOID WINAPI BaseFilterImpl_IncrementPinVersion(struct strmbase_filter *filter) { InterlockedIncrement(&filter->pin_version); @@ -520,6 +567,7 @@ void strmbase_filter_init(struct strmbase_filter *filter, IUnknown *outer, memset(filter, 0, sizeof(*filter)); filter->IBaseFilter_iface.lpVtbl = &filter_vtbl; + filter->IPropertyBag_iface.lpVtbl = &property_bag_vtbl; filter->IUnknown_inner.lpVtbl = &filter_inner_vtbl; filter->outer_unk = outer ? outer : &filter->IUnknown_inner; filter->refcount = 1; From 777acdea8b83598ea93c107c2e5382bb2e8020c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Jan 2022 13:24:44 +0100 Subject: [PATCH 0099/2777] strmbase: Return S_OK from strmbase_filter IPropertyBag_Write. Required for Final Fantasy XIV intro video. CW-Bug-Id: #19624 --- libs/strmbase/filter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/strmbase/filter.c b/libs/strmbase/filter.c index f9ab84d5a9d..97157478e20 100644 --- a/libs/strmbase/filter.c +++ b/libs/strmbase/filter.c @@ -544,7 +544,7 @@ static HRESULT WINAPI property_bag_Read(IPropertyBag *iface, const WCHAR *prop_n static HRESULT WINAPI property_bag_Write(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value) { FIXME("iface %p, prop_name %s, value %p stub!\n", iface, debugstr_w(prop_name), value); - return E_NOTIMPL; + return S_OK; } static const IPropertyBagVtbl property_bag_vtbl = From 134707ee2d2113cae1c2e705db8a24498f096b2a Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 4 Feb 2022 16:44:54 -0600 Subject: [PATCH 0100/2777] HACK: winegstreamer: Report BGRx for Persona 4 Golden. --- dlls/winegstreamer/wm_reader.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 18b0e8a90bc..a9abe16aede 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1508,6 +1508,17 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) * Shadowgrounds provides wmv3 video and assumes that the initial * video type will be BGR. */ stream->format.u.video.format = WG_VIDEO_FORMAT_BGR; + { + /* HACK: Persona 4 Golden tries to read compressed samples, and + * then autoplug them via quartz to a filter that only accepts + * BGRx. This is not trivial to implement. Return BGRx from the + * wmvcore reader for now. */ + + const char *id = getenv("SteamGameId"); + + if (id && !strcmp(id, "1113000")) + stream->format.u.video.format = WG_VIDEO_FORMAT_BGRx; + } } wg_parser_stream_enable(stream->wg_stream, &stream->format); } From 962ce0f21907ca00ef43051001268f3aefd66ab3 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Thu, 28 Oct 2021 17:47:48 -0500 Subject: [PATCH 0101/2777] HACK: winegstreamer: Report streams in reverse order for wmvcore. --- dlls/winegstreamer/wm_reader.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index a9abe16aede..00edb637222 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1484,7 +1484,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) { struct wm_stream *stream = &reader->streams[i]; - stream->wg_stream = wg_parser_get_stream(reader->wg_parser, i); + stream->wg_stream = wg_parser_get_stream(reader->wg_parser, reader->stream_count - i - 1); stream->reader = reader; stream->index = i; stream->selection = WMT_ON; @@ -1629,7 +1629,7 @@ static HRESULT wm_reader_read_stream_sample(struct wm_reader *reader, struct wg_ HRESULT hr; BYTE *data; - if (!(stream = wm_reader_get_stream_by_stream_number(reader, buffer->stream + 1))) + if (!(stream = wm_reader_get_stream_by_stream_number(reader, reader->stream_count - buffer->stream))) return E_INVALIDARG; TRACE("Got buffer for '%s' stream %p.\n", get_major_type_string(stream->format.major_type), stream); @@ -1872,7 +1872,7 @@ static HRESULT WINAPI reader_GetNextSample(IWMSyncReader2 *iface, if (!wg_parser_stream_get_buffer(reader->wg_parser, stream ? stream->wg_stream : NULL, &wg_buffer)) hr = NS_E_NO_MORE_SAMPLES; else if (SUCCEEDED(hr = wm_reader_read_stream_sample(reader, &wg_buffer, sample, pts, duration, flags))) - stream_number = wg_buffer.stream + 1; + stream_number = reader->stream_count - wg_buffer.stream; } if (stream && hr == NS_E_NO_MORE_SAMPLES) From 20583d2e22fc9a4fb3b96374fbef65fffde05cce Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Wed, 23 Feb 2022 16:43:04 +0200 Subject: [PATCH 0102/2777] mfplat: Return E_NOTIMPL from MFCreateDXGIDeviceManager for TOHU. Without this the game renders the videos as garbage. CW-Bug-Id: #20194 --- dlls/mfplat/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index cd51bc9ca45..54c8778f44a 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -9241,6 +9241,7 @@ HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **man strcmp(sgi, "684450") == 0 || /* Surviving the Aftermath */ strcmp(sgi, "1017900") == 0 || /* Age of Empires: Definitive Edition */ strcmp(sgi, "1331440") == 0 || /* FUSER */ + strcmp(sgi, "1075200") == 0 || /* TOHU */ (do_not_create && do_not_create[0] != '\0') )) { From 1f337574a6a6bbd09ae80e818c20b80dfaddc91b Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 25 Jan 2022 10:21:28 -0600 Subject: [PATCH 0103/2777] winegstreamer: Add MFVideoFormat_RGB32 output for the source. CW-Bug-Id: #19516 CW-Bug-Id: #19859 --- 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 615465b1ab9..3e10b1a2753 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -856,7 +856,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; @@ -876,6 +876,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 c288b9165e23cef5b811231db34742dcc66980c9 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 25 Jan 2022 10:29:58 -0600 Subject: [PATCH 0104/2777] HACK: mf: Always allow enumerating source types in topology This lets us connect directly to a source format without a color converter. CW-Bug-Id: #19516 CW-Bug-Id: #19859 --- dlls/mf/session.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index b2371763150..9c746c9f5ef 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -1820,6 +1820,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? */); if (SUCCEEDED(hr)) From 02618558214066a230e5497aa6d15ecbba9b3d7f Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Wed, 23 Feb 2022 09:37:14 -0600 Subject: [PATCH 0105/2777] mfplat: Move MFDXGIDeviceManager hack appid list to proton script --- dlls/mfplat/main.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 54c8778f44a..dbeee57967a 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -9225,8 +9225,7 @@ static const IMFDXGIDeviceManagerVtbl dxgi_device_manager_vtbl = HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **manager) { struct dxgi_device_manager *object; - const char *sgi = getenv("SteamGameId"); - const char *do_not_create = getenv("PROTON_DO_NOT_CREATE_DXGI_DEVICE_MANAGER"); + const char *do_not_create = getenv("WINE_DO_NOT_CREATE_DXGI_DEVICE_MANAGER"); TRACE("%p, %p.\n", token, manager); @@ -9235,15 +9234,7 @@ HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **man * #19126 is solved. Returning a DXGI device manager also breaks * Age of Empires Definitive Edition - this gameid should be removed * once CW bug #19741 is solved. */ - if (sgi && ( - strcmp(sgi, "305620") == 0 || /* The Long Dark */ - strcmp(sgi, "585420") == 0 || /* Trailmakers */ - strcmp(sgi, "684450") == 0 || /* Surviving the Aftermath */ - strcmp(sgi, "1017900") == 0 || /* Age of Empires: Definitive Edition */ - strcmp(sgi, "1331440") == 0 || /* FUSER */ - strcmp(sgi, "1075200") == 0 || /* TOHU */ - (do_not_create && do_not_create[0] != '\0') - )) + if (do_not_create && do_not_create[0] != '\0') { FIXME("stubbing out\n"); return E_NOTIMPL; From dc4826239e45bf31882ef9d0953bd34b390381a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 11 Mar 2022 00:26:59 +0100 Subject: [PATCH 0106/2777] quartz: Return the decodebin filter on WMVideo Decoder DMO lookup. King of Fighters XIII requests it by name, and expects it to be present to connect it to a Samplegrabber filter. CW-Bug-Id: #20244 --- dlls/quartz/filtergraph.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c index 649fb7580f3..3e0a34f07ba 100644 --- a/dlls/quartz/filtergraph.c +++ b/dlls/quartz/filtergraph.c @@ -522,6 +522,13 @@ static IBaseFilter *find_filter_by_name(struct filter_graph *graph, const WCHAR { struct filter *filter; + /* King of Fighters XIII requests the WMV decoder filter by name to + * connect it to a Sample Grabber filter, return our custom decoder + * filter instance instead. + */ + if (!wcscmp(name, L"WMVideo Decoder DMO")) + name = L"GStreamer splitter filter"; + LIST_FOR_EACH_ENTRY(filter, &graph->filters, struct filter, entry) { if (!wcscmp(filter->name, name)) From 1bd78bd20964a82b50587694358cbc323317f4c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 11 Mar 2022 00:27:45 +0100 Subject: [PATCH 0107/2777] winegstreamer: Format the decodebin output pins with out%u. King of Fighters XIII requests them by name, to connect them to the Samplegrabber filter. CW-Bug-Id: #20244 --- dlls/winegstreamer/quartz_parser.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 5561b106327..2940832299f 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1298,13 +1298,20 @@ static const struct strmbase_sink_ops sink_ops = static BOOL decodebin_parser_filter_init_gst(struct parser *filter) { struct wg_parser *parser = filter->wg_parser; + const char *sgi = getenv("SteamGameId"); + const WCHAR *format; unsigned int i, stream_count; WCHAR source_name[20]; + /* King of Fighters XIII requests the WMV decoder filter pins by name + * to connect them to a Sample Grabber filter. + */ + format = (sgi && !strcmp(sgi, "222940")) ? L"out%u" : L"Stream %02u"; + stream_count = wg_parser_get_stream_count(parser); for (i = 0; i < stream_count; ++i) { - swprintf(source_name, ARRAY_SIZE(source_name), L"Stream %02u", i); + swprintf(source_name, ARRAY_SIZE(source_name), format, i); if (!create_pin(filter, wg_parser_get_stream(parser, i), source_name)) return FALSE; } From 60599867c9238ad175dab76ca472e96cebaa3bf5 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 29 Mar 2022 00:48:40 +0300 Subject: [PATCH 0108/2777] qcap: HACK: Return failure from PPB_Load() for UNO. CW-Bug-Id: #20390 --- dlls/qcap/audiorecord.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/qcap/audiorecord.c b/dlls/qcap/audiorecord.c index a6f27cf4f26..6559346e161 100644 --- a/dlls/qcap/audiorecord.c +++ b/dlls/qcap/audiorecord.c @@ -115,7 +115,13 @@ static HRESULT WINAPI PPB_Load(IPersistPropertyBag *iface, IPropertyBag *pPropBa hr = IPropertyBag_Read(pPropBag, L"WaveInID", &var, pErrorLog); if (SUCCEEDED(hr)) { + char sgi[64]; FIXME("FIXME: implement opening waveIn device %ld\n", V_I4(&var)); + if (GetEnvironmentVariableA("SteamGameId", sgi, sizeof(sgi)) && !strcmp(sgi, "470220")) + { + FIXME("HACK: returning error.\n"); + return E_FAIL; + } } return hr; From f407e64acae775f3b9df54a8fc61e631259186e3 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Thu, 4 Nov 2021 12:51:31 +0100 Subject: [PATCH 0109/2777] mfreadwrite/reader: Add a passthrough transform. On Windows media sources typically produce compressed data, so the source reader automatically adds a transform to decompress it. On Wine media sources already care about decompressing data, so there is no need for a transform. However, some applications expect it anyway (e.g., to edit transform attributes) and fail if it's not present. Therefore, this patch adds a trivial passthrough transform implementation to please such programs. CW-Bug-Id: #19126 --- dlls/mfreadwrite/reader.c | 487 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 487 insertions(+) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 01f54e50f29..42dd84c2c67 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -242,6 +242,461 @@ static ULONG source_reader_release(struct source_reader *reader) return refcount; } +struct passthrough_transform +{ + IMFTransform IMFTransform_iface; + LONG refcount; + IMFMediaType *type; + IMFAttributes *attributes; + IMFAttributes *input_attributes; + IMFAttributes *output_attributes; + IMFSample *sample; +}; + +static inline struct passthrough_transform *impl_from_IMFTransform(IMFTransform *iface) +{ + return CONTAINING_RECORD(iface, struct passthrough_transform, IMFTransform_iface); +} + +static HRESULT WINAPI passthrough_transform_QueryInterface(IMFTransform *iface, REFIID riid, void **out) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IMFTransform)) + { + *out = &transform->IMFTransform_iface; + } + else + { + FIXME("(%s, %p)\n", debugstr_guid(riid), out); + *out = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI passthrough_transform_AddRef(IMFTransform *iface) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + ULONG refcount = InterlockedIncrement(&transform->refcount); + + TRACE("%p, refcount %lu.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI passthrough_transform_Release(IMFTransform *iface) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + ULONG refcount = InterlockedDecrement(&transform->refcount); + + TRACE("%p, refcount %lu.\n", iface, refcount); + + if (!refcount) + { + if (transform->type) + IMFMediaType_Release(transform->type); + IMFAttributes_Release(transform->attributes); + IMFAttributes_Release(transform->input_attributes); + IMFAttributes_Release(transform->output_attributes); + if (transform->sample) + IMFSample_Release(transform->sample); + } + + return refcount; +} +static HRESULT WINAPI passthrough_transform_GetStreamLimits(IMFTransform *iface, + DWORD *input_minimum, DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) +{ + TRACE("%p, %p, %p, %p, %p.\n", iface, input_minimum, input_maximum, output_minimum, output_maximum); + + *input_minimum = 1; + *input_maximum = 1; + *output_minimum = 1; + *output_maximum = 1; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) +{ + TRACE("%p, %p, %p.\n", iface, inputs, outputs); + + *inputs = 1; + *outputs = 1; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetStreamIDs(IMFTransform *iface, + DWORD input_size, DWORD *inputs, DWORD output_size, DWORD *outputs) +{ + TRACE("%p, %ld, %p, %ld, %p.\n", iface, input_size, inputs, output_size, outputs); + + if (input_size < 1 || output_size < 1) + return MF_E_BUFFERTOOSMALL; + + inputs[0] = 0; + outputs[0] = 0; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) +{ + TRACE("%p, %ld, %p.\n", iface, id, info); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + info->hnsMaxLatency = 0; + info->dwFlags = MFT_INPUT_STREAM_PROCESSES_IN_PLACE; + info->cbSize = 0; + info->cbMaxLookahead = 0; + info->cbAlignment = 0; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) +{ + TRACE("%p, %ld, %p.\n", iface, id, info); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + info->dwFlags = MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; + info->cbSize = 0; + info->cbAlignment = 0; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %p.\n", iface, attributes); + + IMFAttributes_AddRef(transform->attributes); + + *attributes = transform->attributes; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %ld, %p.\n", iface, id, attributes); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + IMFAttributes_AddRef(transform->input_attributes); + + *attributes = transform->input_attributes; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %ld, %p.\n", iface, id, attributes); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + IMFAttributes_AddRef(transform->output_attributes); + + *attributes = transform->output_attributes; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_DeleteInputStream(IMFTransform *iface, DWORD id) +{ + TRACE("%p, %ld.\n", iface, id); + + return E_NOTIMPL; +} + +static HRESULT WINAPI passthrough_transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) +{ + TRACE("%p, %ld, %p.\n", iface, streams, ids); + + return E_NOTIMPL; +} + +static HRESULT WINAPI passthrough_transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) +{ + TRACE("%p, %ld, %ld, %p.\n", iface, id, index, type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI passthrough_transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %ld, %ld, %p.\n", iface, id, index, type); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + if (index != 0) + return MF_E_NO_MORE_TYPES; + + if (!transform->type) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + *type = transform->type; + IMFMediaType_AddRef(*type); + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %ld, %p, %ld.\n", iface, id, type, flags); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + if (!(flags & MFT_SET_TYPE_TEST_ONLY)) + { + if (transform->type) + IMFMediaType_Release(transform->type); + transform->type = type; + IMFMediaType_AddRef(type); + } + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + DWORD cmp_flags; + HRESULT hr; + + TRACE("%p, %ld, %p, %ld.\n", iface, id, type, flags); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + if (!transform->type) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + hr = IMFMediaType_IsEqual(transform->type, type, &cmp_flags); + if (FAILED(hr)) + return hr; + + if (!(cmp_flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA)) + return MF_E_INVALIDMEDIATYPE; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %ld, %p.\n", iface, id, type); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + if (!transform->type) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + *type = transform->type; + IMFMediaType_AddRef(*type); + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %ld, %p.\n", iface, id, type); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + if (!transform->type) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + *type = transform->type; + IMFMediaType_AddRef(*type); + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %ld, %p.\n", iface, id, flags); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + *flags = transform->sample ? 0 : MFT_INPUT_STATUS_ACCEPT_DATA; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %p.\n", iface, flags); + + *flags = transform->sample ? MFT_OUTPUT_STATUS_SAMPLE_READY : 0; + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) +{ + FIXME("%p, %s, %s.\n", iface, wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI passthrough_transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) +{ + FIXME("%p, %ld, %p.\n", iface, id, event); + + return E_NOTIMPL; +} + +static HRESULT WINAPI passthrough_transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) +{ + FIXME("%p, %u, %Iu.\n", iface, message, param); + + return E_NOTIMPL; +} + +static HRESULT WINAPI passthrough_transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + + TRACE("%p, %ld, %p, %ld.\n", iface, id, sample, flags); + + if (id != 0) + return MF_E_INVALIDSTREAMNUMBER; + + if (transform->sample) + return MF_E_NOTACCEPTING; + + transform->sample = sample; + IMFSample_AddRef(sample); + + return S_OK; +} + +static HRESULT WINAPI passthrough_transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, + MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) +{ + struct passthrough_transform *transform = impl_from_IMFTransform(iface); + unsigned int i; + + TRACE("%p, %ld, %ld, %p, %p.\n", iface, flags, count, samples, status); + + if (!transform->sample) + return MF_E_TRANSFORM_NEED_MORE_INPUT; + + if (samples[0].dwStreamID != 0) + return MF_E_INVALIDSTREAMNUMBER; + + samples[0].pSample = transform->sample; + transform->sample = NULL; + + for (i = 1; i < count; ++i) + samples[i].dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE; + + *status = 0; + + return S_OK; +} + +static const IMFTransformVtbl passthrough_transform_vtbl = { + passthrough_transform_QueryInterface, + passthrough_transform_AddRef, + passthrough_transform_Release, + passthrough_transform_GetStreamLimits, + passthrough_transform_GetStreamCount, + passthrough_transform_GetStreamIDs, + passthrough_transform_GetInputStreamInfo, + passthrough_transform_GetOutputStreamInfo, + passthrough_transform_GetAttributes, + passthrough_transform_GetInputStreamAttributes, + passthrough_transform_GetOutputStreamAttributes, + passthrough_transform_DeleteInputStream, + passthrough_transform_AddInputStreams, + passthrough_transform_GetInputAvailableType, + passthrough_transform_GetOutputAvailableType, + passthrough_transform_SetInputType, + passthrough_transform_SetOutputType, + passthrough_transform_GetInputCurrentType, + passthrough_transform_GetOutputCurrentType, + passthrough_transform_GetInputStatus, + passthrough_transform_GetOutputStatus, + passthrough_transform_SetOutputBounds, + passthrough_transform_ProcessEvent, + passthrough_transform_ProcessMessage, + passthrough_transform_ProcessInput, + passthrough_transform_ProcessOutput, +}; + +static HRESULT create_passthrough_transform(IMFTransform **transform) +{ + struct passthrough_transform *obj; + HRESULT hr; + + if (!(obj = calloc(1, sizeof(*obj)))) + return E_OUTOFMEMORY; + + obj->IMFTransform_iface.lpVtbl = &passthrough_transform_vtbl; + obj->refcount = 1; + + hr = MFCreateAttributes(&obj->attributes, 0); + if (SUCCEEDED(hr)) + hr = MFCreateAttributes(&obj->input_attributes, 0); + if (SUCCEEDED(hr)) + hr = MFCreateAttributes(&obj->output_attributes, 0); + + if (SUCCEEDED(hr)) + { + *transform = &obj->IMFTransform_iface; + } + else + { + if (obj->attributes) + IMFAttributes_Release(obj->attributes); + if (obj->input_attributes) + IMFAttributes_Release(obj->input_attributes); + if (obj->output_attributes) + IMFAttributes_Release(obj->output_attributes); + free(obj); + } + + return hr; +} + static HRESULT WINAPI source_reader_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IUnknown)) @@ -1788,6 +2243,36 @@ static HRESULT source_reader_configure_decoder(struct source_reader *reader, DWO return MF_E_TOPO_CODEC_NOT_FOUND; } +static HRESULT source_reader_add_passthrough_transform(struct source_reader *reader, DWORD index, IMFMediaType *type) +{ + IMFTransform *transform; + HRESULT hr; + + if (FAILED(hr = create_passthrough_transform(&transform))) + return hr; + + if (FAILED(hr = IMFTransform_SetInputType(transform, 0, type, 0))) + { + WARN("Failed to set decoder input type, hr %#lx.\n", hr); + IMFTransform_Release(transform); + return hr; + } + + if (FAILED(hr = IMFTransform_SetOutputType(transform, 0, type, 0))) + { + WARN("Failed to set decoder input type, hr %#lx.\n", hr); + IMFTransform_Release(transform); + return hr; + } + + if (reader->streams[index].decoder.transform) + IMFTransform_Release(reader->streams[index].decoder.transform); + reader->streams[index].decoder.transform = transform; + reader->streams[index].decoder.min_buffer_size = 0; + + return S_OK; +} + static HRESULT source_reader_create_decoder_for_stream(struct source_reader *reader, DWORD index, IMFMediaType *output_type) { MFT_REGISTER_TYPE_INFO in_type, out_type; @@ -1876,6 +2361,8 @@ static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReader *iface, DWO hr = source_reader_set_compatible_media_type(reader, index, type); if (hr == S_FALSE) hr = source_reader_create_decoder_for_stream(reader, index, type); + else if (hr == S_OK) + hr = source_reader_add_passthrough_transform(reader, index, reader->streams[index].current); if (SUCCEEDED(hr)) hr = source_reader_setup_sample_allocator(reader, index); From 4a14a1b2d845f0e6f7d0825c59c0c37ba172335e Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 15 Nov 2021 13:06:10 +0100 Subject: [PATCH 0110/2777] mfreadwrite/reader: Setup the sample allocator in ReadSample. Currently the source reader creates a sample allocator as soon as SetCurrentMediaType() is called. However on Windows if the output attribute MF_SA_D3D11_SHARED_WITHOUT_MUTEX is set on the transform after SetCurrentMediaType() is called, but before ReadSample() is called, the sample allocator will generate shareable samples. In order to emulate the same behavior, we defer creating the sample allocator to the first ReadSample() call, so the most updated attributes are picked up. With this and the previous two patches, some video playback bugs are solved for some games (e.g. Trailmakers, Rustler, TOHU and others) when using DXVK (wined3d doesn't currently support shared resources, so there is no way to check with it). CW-Bug-Id: #19126 --- dlls/mfreadwrite/reader.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 42dd84c2c67..aaf46292da4 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -1677,6 +1677,8 @@ static HRESULT source_reader_flush(struct source_reader *reader, unsigned int in return hr; } +static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader, unsigned int index); + static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface); @@ -1706,7 +1708,15 @@ static HRESULT WINAPI source_reader_async_commands_callback_Invoke(IMFAsyncCallb { stream = &reader->streams[stream_index]; - if (!(report_sample = source_reader_get_read_result(reader, stream, command->u.read.flags, &status, + if (!stream->allocator) + { + hr = source_reader_setup_sample_allocator(reader, stream_index); + + if (FAILED(hr)) + WARN("Failed to setup the sample allocator, hr %#lx.\n", hr); + } + + if (SUCCEEDED(hr) && !(report_sample = source_reader_get_read_result(reader, stream, command->u.read.flags, &status, &stream_index, &stream_flags, ×tamp, &sample))) { stream->requests++; @@ -2363,8 +2373,12 @@ static HRESULT WINAPI src_reader_SetCurrentMediaType(IMFSourceReader *iface, DWO hr = source_reader_create_decoder_for_stream(reader, index, type); else if (hr == S_OK) hr = source_reader_add_passthrough_transform(reader, index, reader->streams[index].current); - if (SUCCEEDED(hr)) - hr = source_reader_setup_sample_allocator(reader, index); + + if (reader->streams[index].allocator) + { + IMFVideoSampleAllocatorEx_Release(reader->streams[index].allocator); + reader->streams[index].allocator = NULL; + } LeaveCriticalSection(&reader->cs); @@ -2463,7 +2477,15 @@ static HRESULT source_reader_read_sample(struct source_reader *reader, DWORD ind stream = &reader->streams[stream_index]; - if (!source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags, + if (!stream->allocator) + { + hr = source_reader_setup_sample_allocator(reader, stream_index); + + if (FAILED(hr)) + WARN("Failed to setup the sample allocator, hr %#lx.\n", hr); + } + + if (SUCCEEDED(hr) && !source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags, timestamp, sample)) { while (!source_reader_got_response_for_stream(reader, stream) && stream->state != STREAM_STATE_EOS) From 3b621e598b0c7ce54610c5c81fcb3e9deea67e3b Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 6 Jun 2022 12:28:58 +0200 Subject: [PATCH 0111/2777] mfplat/buffer: Prepare image copying functions for error checking. CW-Bug-Id: #19126 --- dlls/mfplat/buffer.c | 58 +++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index e3d38438b88..b955a0ac8b9 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -32,7 +32,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); #define ALIGN_SIZE(size, alignment) (((size) + (alignment)) & ~((alignment))) -typedef void (*p_copy_image_func)(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines); +typedef HRESULT (*p_copy_image_func)(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines, DWORD dest_size); struct buffer { @@ -75,32 +75,39 @@ struct buffer CRITICAL_SECTION cs; }; -static void copy_image(const struct buffer *buffer, BYTE *dest, LONG dest_stride, const BYTE *src, - LONG src_stride, DWORD width, DWORD lines) +static HRESULT copy_image(const struct buffer *buffer, BYTE *dest, LONG dest_stride, const BYTE *src, + LONG src_stride, DWORD width, DWORD lines, DWORD dest_size) { - MFCopyImage(dest, dest_stride, src, src_stride, width, lines); + HRESULT hr = S_OK; + + hr = MFCopyImage(dest, dest_stride, src, src_stride, width, lines); - if (buffer->_2d.copy_image) + if (SUCCEEDED(hr) && buffer->_2d.copy_image) { dest += dest_stride * lines; src += src_stride * lines; - buffer->_2d.copy_image(dest, dest_stride, src, src_stride, width, lines); + hr = buffer->_2d.copy_image(dest, dest_stride, src, src_stride, width, lines, dest_size); } + + return hr; } -static void copy_image_nv12(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines) +static HRESULT copy_image_nv12(BYTE *dest, LONG dest_stride, const BYTE *src, + LONG src_stride, DWORD width, DWORD lines, DWORD dest_size) { - MFCopyImage(dest, dest_stride, src, src_stride, width, lines / 2); + return MFCopyImage(dest, dest_stride, src, src_stride, width, lines / 2); } -static void copy_image_imc1(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines) +static HRESULT copy_image_imc1(BYTE *dest, LONG dest_stride, const BYTE *src, + LONG src_stride, DWORD width, DWORD lines, DWORD dest_size) { - MFCopyImage(dest, dest_stride, src, src_stride, width / 2, lines); + return MFCopyImage(dest, dest_stride, src, src_stride, width / 2, lines); } -static void copy_image_imc2(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines) +static HRESULT copy_image_imc2(BYTE *dest, LONG dest_stride, const BYTE *src, + LONG src_stride, DWORD width, DWORD lines, DWORD dest_size) { - MFCopyImage(dest, dest_stride / 2, src, src_stride / 2, width / 2, lines); + return MFCopyImage(dest, dest_stride / 2, src, src_stride / 2, width / 2, lines); } static inline struct buffer *impl_from_IMFMediaBuffer(IMFMediaBuffer *iface) @@ -312,8 +319,8 @@ static HRESULT WINAPI memory_1d_2d_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat hr = E_OUTOFMEMORY; if (SUCCEEDED(hr)) - copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, buffer->data, buffer->_2d.pitch, - buffer->_2d.width, buffer->_2d.height); + hr = copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, buffer->data, buffer->_2d.pitch, + buffer->_2d.width, buffer->_2d.height, buffer->_2d.plane_size); } if (SUCCEEDED(hr)) @@ -334,6 +341,7 @@ static HRESULT WINAPI memory_1d_2d_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat static HRESULT WINAPI memory_1d_2d_buffer_Unlock(IMFMediaBuffer *iface) { struct buffer *buffer = impl_from_IMFMediaBuffer(iface); + HRESULT hr = S_OK; TRACE("%p.\n", iface); @@ -341,8 +349,8 @@ static HRESULT WINAPI memory_1d_2d_buffer_Unlock(IMFMediaBuffer *iface) if (buffer->_2d.linear_buffer && !--buffer->_2d.locks) { - copy_image(buffer, buffer->data, buffer->_2d.pitch, buffer->_2d.linear_buffer, buffer->_2d.width, - buffer->_2d.width, buffer->_2d.height); + hr = copy_image(buffer, buffer->data, buffer->_2d.pitch, buffer->_2d.linear_buffer, buffer->_2d.width, + buffer->_2d.width, buffer->_2d.height, buffer->max_length); free(buffer->_2d.linear_buffer); buffer->_2d.linear_buffer = NULL; @@ -350,7 +358,7 @@ static HRESULT WINAPI memory_1d_2d_buffer_Unlock(IMFMediaBuffer *iface) LeaveCriticalSection(&buffer->cs); - return S_OK; + return hr; } static const IMFMediaBufferVtbl memory_1d_2d_buffer_vtbl = @@ -391,8 +399,8 @@ static HRESULT WINAPI d3d9_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &rect, NULL, 0); if (SUCCEEDED(hr)) { - copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, rect.pBits, rect.Pitch, - buffer->_2d.width, buffer->_2d.height); + hr = copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, rect.pBits, rect.Pitch, + buffer->_2d.width, buffer->_2d.height, buffer->_2d.plane_size); IDirect3DSurface9_UnlockRect(buffer->d3d9_surface.surface); } } @@ -430,8 +438,8 @@ static HRESULT WINAPI d3d9_surface_buffer_Unlock(IMFMediaBuffer *iface) if (SUCCEEDED(hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &rect, NULL, 0))) { - copy_image(buffer, rect.pBits, rect.Pitch, buffer->_2d.linear_buffer, buffer->_2d.width, - buffer->_2d.width, buffer->_2d.height); + hr = copy_image(buffer, rect.pBits, rect.Pitch, buffer->_2d.linear_buffer, buffer->_2d.width, + buffer->_2d.width, buffer->_2d.height, buffer->max_length); IDirect3DSurface9_UnlockRect(buffer->d3d9_surface.surface); } @@ -970,8 +978,8 @@ static HRESULT WINAPI dxgi_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat hr = dxgi_surface_buffer_map(buffer); if (SUCCEEDED(hr)) { - copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, buffer->dxgi_surface.map_desc.pData, - buffer->dxgi_surface.map_desc.RowPitch, buffer->_2d.width, buffer->_2d.height); + hr = copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, buffer->dxgi_surface.map_desc.pData, + buffer->dxgi_surface.map_desc.RowPitch, buffer->_2d.width, buffer->_2d.height, buffer->_2d.plane_size); } } } @@ -1004,8 +1012,8 @@ static HRESULT WINAPI dxgi_surface_buffer_Unlock(IMFMediaBuffer *iface) hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED); else if (!--buffer->_2d.locks) { - copy_image(buffer, buffer->dxgi_surface.map_desc.pData, buffer->dxgi_surface.map_desc.RowPitch, - buffer->_2d.linear_buffer, buffer->_2d.width, buffer->_2d.width, buffer->_2d.height); + hr = copy_image(buffer, buffer->dxgi_surface.map_desc.pData, buffer->dxgi_surface.map_desc.RowPitch, + buffer->_2d.linear_buffer, buffer->_2d.width, buffer->_2d.width, buffer->_2d.height, buffer->max_length); dxgi_surface_buffer_unmap(buffer); free(buffer->_2d.linear_buffer); From eefc50a6d3bd6a08db1d4701442493448e6baf9d Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 6 Jun 2022 12:57:34 +0200 Subject: [PATCH 0112/2777] mfplat/buffer: Validate buffer size in image copying functions. CW-Bug-Id: #19126 --- dlls/mfplat/buffer.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index b955a0ac8b9..c617abf7ae0 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -80,6 +80,9 @@ static HRESULT copy_image(const struct buffer *buffer, BYTE *dest, LONG dest_str { HRESULT hr = S_OK; + if (width > abs(dest_stride) || abs(dest_stride) * lines > dest_size) + return E_NOT_SUFFICIENT_BUFFER; + hr = MFCopyImage(dest, dest_stride, src, src_stride, width, lines); if (SUCCEEDED(hr) && buffer->_2d.copy_image) @@ -95,18 +98,27 @@ static HRESULT copy_image(const struct buffer *buffer, BYTE *dest, LONG dest_str static HRESULT copy_image_nv12(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines, DWORD dest_size) { + if (abs(dest_stride) * (lines + lines / 2) > dest_size) + return E_NOT_SUFFICIENT_BUFFER; + return MFCopyImage(dest, dest_stride, src, src_stride, width, lines / 2); } static HRESULT copy_image_imc1(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines, DWORD dest_size) { + if (abs(dest_stride) * (2 * lines) > dest_size) + return E_NOT_SUFFICIENT_BUFFER; + return MFCopyImage(dest, dest_stride, src, src_stride, width / 2, lines); } static HRESULT copy_image_imc2(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines, DWORD dest_size) { + if (abs(dest_stride) * 3 * lines / 2 > dest_size) + return E_NOT_SUFFICIENT_BUFFER; + return MFCopyImage(dest, dest_stride / 2, src, src_stride / 2, width / 2, lines); } From 968ac2bffba1db38b9afd93bb4ef9770d1da21cf Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Tue, 22 Feb 2022 17:40:01 +0100 Subject: [PATCH 0113/2777] mfplat: Implement IMF2DBuffer2::Copy2DTo(). CW-Bug-Id: #19126 --- dlls/mfplat/buffer.c | 49 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index c617abf7ae0..bdec2777c39 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -652,11 +652,52 @@ static HRESULT WINAPI memory_2d_buffer_Lock2DSize(IMF2DBuffer2 *iface, MF2DBuffe return hr; } -static HRESULT WINAPI memory_2d_buffer_Copy2DTo(IMF2DBuffer2 *iface, IMF2DBuffer2 *dest_buffer) +static HRESULT WINAPI memory_2d_buffer_Copy2DTo(IMF2DBuffer2 *iface, IMF2DBuffer2 *dst_buffer) { - FIXME("%p, %p.\n", iface, dest_buffer); + struct buffer *buffer = impl_from_IMF2DBuffer2(iface); + BYTE *src_scanline0, *dst_scanline0, *src_buffer_start, *dst_buffer_start; + DWORD src_length, dst_length; + LONG src_pitch, dst_pitch; + BOOL src_locked = FALSE, dst_locked = FALSE; + HRESULT hr, hr2; - return E_NOTIMPL; + TRACE("%p, %p.\n", iface, dst_buffer); + + hr = IMF2DBuffer2_Lock2DSize(iface, MF2DBuffer_LockFlags_Read, &src_scanline0, + &src_pitch, &src_buffer_start, &src_length); + if (FAILED(hr)) + goto end; + src_locked = TRUE; + + hr = IMF2DBuffer2_Lock2DSize(dst_buffer, MF2DBuffer_LockFlags_Write, &dst_scanline0, + &dst_pitch, &dst_buffer_start, &dst_length); + if (FAILED(hr)) + goto end; + dst_locked = TRUE; + + hr = copy_image(buffer, dst_scanline0, dst_pitch, src_scanline0, src_pitch, + buffer->_2d.width, buffer->_2d.height, dst_length); + +end: + if (src_locked) + { + hr2 = IMF2DBuffer2_Unlock2D(iface); + if (FAILED(hr2)) + WARN("Unlocking source buffer %p failed with hr %#lx.\n", iface, hr2); + if (FAILED(hr2) && SUCCEEDED(hr)) + hr = hr2; + } + + if (dst_locked) + { + hr2 = IMF2DBuffer2_Unlock2D(dst_buffer); + if (FAILED(hr2)) + WARN("Unlocking destination buffer %p failed with hr %#lx.\n", dst_buffer, hr2); + if (FAILED(hr2) && SUCCEEDED(hr)) + hr = hr2; + } + + return hr; } static const IMF2DBuffer2Vtbl memory_2d_buffer_vtbl = @@ -1339,7 +1380,7 @@ static p_copy_image_func get_2d_buffer_copy_func(DWORD fourcc) return copy_image_nv12; if (fourcc == MAKEFOURCC('I','M','C','1') || fourcc == MAKEFOURCC('I','M','C','3')) return copy_image_imc1; - if (fourcc == MAKEFOURCC('I','M','C','2') || fourcc == MAKEFOURCC('I','M','C','4')) + if (fourcc == MAKEFOURCC('I','M','C','2') || fourcc == MAKEFOURCC('I','M','C','4') || fourcc == MAKEFOURCC('Y','V','1', '2')) return copy_image_imc2; return NULL; } From 633b2d504151182410f6837dc16d59c417931587 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 6 Jun 2022 13:37:48 +0200 Subject: [PATCH 0114/2777] mfplat/sample: Use Copy2DTo when copying samples, if available. CW-Bug-Id: #19126 --- dlls/mfplat/sample.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/dlls/mfplat/sample.c b/dlls/mfplat/sample.c index 687ada1a477..a0082660235 100644 --- a/dlls/mfplat/sample.c +++ b/dlls/mfplat/sample.c @@ -791,6 +791,28 @@ static HRESULT WINAPI sample_GetTotalLength(IMFSample *iface, DWORD *total_lengt return S_OK; } +static HRESULT copy_2d_buffer(IMFMediaBuffer *src, IMFMediaBuffer *dst) +{ + IMF2DBuffer2 *src2d = NULL, *dst2d = NULL; + HRESULT hr = S_OK; + + hr = IMFMediaBuffer_QueryInterface(src, &IID_IMF2DBuffer2, (void **)&src2d); + + if (SUCCEEDED(hr)) + hr = IMFMediaBuffer_QueryInterface(dst, &IID_IMF2DBuffer2, (void **)&dst2d); + + if (SUCCEEDED(hr)) + hr = IMF2DBuffer2_Copy2DTo(src2d, dst2d); + + if (src2d) + IMF2DBuffer2_Release(src2d); + + if (dst2d) + IMF2DBuffer2_Release(dst2d); + + return hr; +} + static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buffer) { struct sample *sample = impl_from_IMFSample(iface); @@ -804,6 +826,15 @@ static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buff EnterCriticalSection(&sample->attributes.cs); + if (sample->buffer_count == 1) + { + if (SUCCEEDED(hr = copy_2d_buffer(sample->buffers[0], buffer))) + { + LeaveCriticalSection(&sample->attributes.cs); + return hr; + } + } + total_length = sample_get_total_length(sample); dst_current_length = 0; From 5cfa3a0c0d422b0e809e2fb849681a28570f7dac Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 6 Jun 2022 14:44:58 +0200 Subject: [PATCH 0115/2777] mfplat/buffer: Implement ContiguousCopyFrom(). CW-Bug-Id: #19126 --- dlls/mfplat/buffer.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index bdec2777c39..94f34b236f5 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -627,9 +627,34 @@ static HRESULT WINAPI memory_2d_buffer_ContiguousCopyTo(IMF2DBuffer2 *iface, BYT static HRESULT WINAPI memory_2d_buffer_ContiguousCopyFrom(IMF2DBuffer2 *iface, const BYTE *src_buffer, DWORD src_length) { - FIXME("%p, %p, %lu.\n", iface, src_buffer, src_length); + struct buffer *buffer = impl_from_IMF2DBuffer2(iface); + BYTE *dst_scanline0, *dst_buffer_start; + DWORD dst_length; + HRESULT hr, hr2; + LONG dst_pitch; - return E_NOTIMPL; + TRACE("%p, %p, %lu.\n", iface, src_buffer, src_length); + + if (src_length != buffer->_2d.plane_size) + { + WARN("truncating contiguous copy not implemented\n"); + return E_NOTIMPL; + } + + hr = IMF2DBuffer2_Lock2DSize(iface, MF2DBuffer_LockFlags_Write, &dst_scanline0, &dst_pitch, &dst_buffer_start, &dst_length); + + if (SUCCEEDED(hr)) + { + hr = copy_image(buffer, dst_scanline0, dst_pitch, src_buffer, buffer->_2d.width, buffer->_2d.width, buffer->_2d.height, buffer->max_length); + } + + hr2 = IMF2DBuffer2_Unlock2D(iface); + if (FAILED(hr2)) + WARN("Unlocking destination buffer %p failed with hr %#lx.\n", iface, hr2); + if (FAILED(hr2) && SUCCEEDED(hr)) + hr = hr2; + + return hr; } static HRESULT WINAPI memory_2d_buffer_Lock2DSize(IMF2DBuffer2 *iface, MF2DBuffer_LockFlags flags, BYTE **scanline0, From 557a4e32e45b94210ae449cec4d9fa249a4af0b9 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 6 Jun 2022 14:56:34 +0200 Subject: [PATCH 0116/2777] mfplat/sample: Use contiguous copy. CW-Bug-Id: #19126 --- dlls/mfplat/sample.c | 52 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/dlls/mfplat/sample.c b/dlls/mfplat/sample.c index a0082660235..6a589e4757b 100644 --- a/dlls/mfplat/sample.c +++ b/dlls/mfplat/sample.c @@ -791,24 +791,58 @@ static HRESULT WINAPI sample_GetTotalLength(IMFSample *iface, DWORD *total_lengt return S_OK; } +static HRESULT copy_2d_buffer_from_contiguous(IMFMediaBuffer *src, IMF2DBuffer *dst) +{ + DWORD current_length; + HRESULT hr, hr2; + BYTE *ptr; + + hr = IMFMediaBuffer_Lock(src, &ptr, NULL, ¤t_length); + + if (SUCCEEDED(hr)) + { + hr = IMF2DBuffer_ContiguousCopyFrom(dst, ptr, current_length); + + hr2 = IMFMediaBuffer_Unlock(src); + if (FAILED(hr2)) + WARN("Unlocking source buffer %p failed with hr %#lx.\n", src, hr2); + if (FAILED(hr2) && SUCCEEDED(hr)) + hr = hr2; + } + + return hr; +} + static HRESULT copy_2d_buffer(IMFMediaBuffer *src, IMFMediaBuffer *dst) { - IMF2DBuffer2 *src2d = NULL, *dst2d = NULL; - HRESULT hr = S_OK; + IMF2DBuffer2 *src2d2 = NULL, *dst2d2 = NULL; + IMF2DBuffer *dst2 = NULL; + HRESULT hr; - hr = IMFMediaBuffer_QueryInterface(src, &IID_IMF2DBuffer2, (void **)&src2d); + hr = IMFMediaBuffer_QueryInterface(src, &IID_IMF2DBuffer2, (void **)&src2d2); + + if (SUCCEEDED(hr)) + hr = IMFMediaBuffer_QueryInterface(dst, &IID_IMF2DBuffer2, (void **)&dst2d2); if (SUCCEEDED(hr)) - hr = IMFMediaBuffer_QueryInterface(dst, &IID_IMF2DBuffer2, (void **)&dst2d); + hr = IMF2DBuffer2_Copy2DTo(src2d2, dst2d2); + + if (src2d2) + IMF2DBuffer2_Release(src2d2); + + if (dst2d2) + IMF2DBuffer2_Release(dst2d2); if (SUCCEEDED(hr)) - hr = IMF2DBuffer2_Copy2DTo(src2d, dst2d); + return hr; - if (src2d) - IMF2DBuffer2_Release(src2d); + hr = IMFMediaBuffer_QueryInterface(dst, &IID_IMF2DBuffer, (void **)&dst2); + + if (SUCCEEDED(hr)) + hr = copy_2d_buffer_from_contiguous(src, dst2); - if (dst2d) - IMF2DBuffer2_Release(dst2d); + if (dst2) + IMF2DBuffer_Release(dst2); return hr; } From e074fc4f1b32ccd027811fda9a9e7572ea095942 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 18 Jul 2022 14:14:54 +0200 Subject: [PATCH 0117/2777] mfplat: Remove comment about games requiring MFCreateDXGIDeviceManager() hack. It is not outdated and partially incorrect. CW-Bug-Id: #19126 CW-Bug-Id: #20985 --- dlls/mfplat/main.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index dbeee57967a..96e6b1d5094 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -9229,11 +9229,6 @@ HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **man TRACE("%p, %p.\n", token, manager); - /* Returning a DXGI device manager triggers a bug and breaks The - * Long Dark and Trailmakers. This should be removed once CW bug - * #19126 is solved. Returning a DXGI device manager also breaks - * Age of Empires Definitive Edition - this gameid should be removed - * once CW bug #19741 is solved. */ if (do_not_create && do_not_create[0] != '\0') { FIXME("stubbing out\n"); From afc209549a165c74baa418f1d35fcac045c02f7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 1 Mar 2022 10:25:27 +0100 Subject: [PATCH 0118/2777] winegstreamer: Let src_getrange_cb allocate the buffer in push_data. GStreamer documentation also states that gst_pad_push caller loses its buffer reference, so whatever we were doing looks wrong here. --- dlls/winegstreamer/wg_parser.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 77ee2d5666b..d59d6cf8f87 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1061,12 +1061,6 @@ static void *push_data(void *arg) GST_DEBUG("Starting push thread."); - if (!(buffer = gst_buffer_new_allocate(NULL, 16384, NULL))) - { - GST_ERROR("Failed to allocate memory."); - return NULL; - } - max_size = parser->stop_offset ? parser->stop_offset : parser->file_size; for (;;) @@ -1078,6 +1072,7 @@ static void *push_data(void *arg) break; size = min(16384, max_size - parser->next_offset); + buffer = NULL; if ((ret = src_getrange_cb(parser->my_src, NULL, parser->next_offset, size, &buffer)) < 0) { GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret)); @@ -1094,8 +1089,6 @@ static void *push_data(void *arg) } } - gst_buffer_unref(buffer); - gst_pad_push_event(parser->my_src, gst_event_new_eos()); GST_DEBUG("Stopping push thread."); From e730d10c81c5924b7c4d496f8d89988e09ad1cc0 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Mon, 24 Jan 2022 00:46:03 -0500 Subject: [PATCH 0119/2777] winegstreamer: After failing to create decodebin parser, try protonvideoconv. --- dlls/winegstreamer/wg_parser.c | 70 +++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index d59d6cf8f87..b02b34da56b 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 @@ -93,6 +94,7 @@ struct wg_parser bool sink_connected; bool unlimited_buffering; + bool use_mediaconv; }; struct wg_parser_stream @@ -493,6 +495,34 @@ static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad, return GST_AUTOPLUG_SELECT_TRY; } +static gint find_videoconv_cb(gconstpointer a, gconstpointer b) +{ + const GValue *val_a = a, *val_b = b; + GstElementFactory *factory_a = g_value_get_object(val_a), *factory_b = g_value_get_object(val_b); + const char *name_a = gst_element_factory_get_longname(factory_a), *name_b = gst_element_factory_get_longname(factory_b); + + if (!strcmp(name_a, "Proton video converter")) + return -1; + if (!strcmp(name_b, "Proton video converter")) + return 1; + return 0; +} + +static GValueArray *autoplug_sort_cb(GstElement *bin, GstPad *pad, + GstCaps *caps, GValueArray *factories, gpointer user) +{ + struct wg_parser *parser = user; + GValueArray *ret = g_value_array_copy(factories); + + if (!parser->use_mediaconv) + return NULL; + + GST_DEBUG("parser %p.", parser); + + g_value_array_sort(ret, find_videoconv_cb); + return ret; +} + static void no_more_pads_cb(GstElement *element, gpointer user) { struct wg_parser *parser = user; @@ -1141,9 +1171,12 @@ static gboolean src_activate_mode_cb(GstPad *pad, GstObject *parent, GstPadMode return FALSE; } +static BOOL decodebin_parser_init_gst(struct wg_parser *parser); + static GstBusSyncReply bus_handler_cb(GstBus *bus, GstMessage *msg, gpointer user) { struct wg_parser *parser = user; + const GstStructure *structure; gchar *dbg_info = NULL; GError *err = NULL; @@ -1184,6 +1217,21 @@ static GstBusSyncReply bus_handler_cb(GstBus *bus, GstMessage *msg, gpointer use pthread_cond_signal(&parser->init_cond); break; + case GST_MESSAGE_ELEMENT: + structure = gst_message_get_structure(msg); + if (gst_structure_has_name(structure, "missing-plugin")) + { + pthread_mutex_lock(&parser->mutex); + if (!parser->use_mediaconv && parser->init_gst == decodebin_parser_init_gst) + { + GST_WARNING("Autoplugged element failed to initialise, trying again with protonvideoconvert."); + parser->error = true; + pthread_cond_signal(&parser->init_cond); + } + pthread_mutex_unlock(&parser->mutex); + } + break; + default: break; } @@ -1318,6 +1366,7 @@ static NTSTATUS wg_parser_connect(void *args) GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); const struct wg_parser_connect_params *params = args; struct wg_parser *parser = params->parser; + bool use_mediaconv = false; unsigned int i; int ret; @@ -1349,9 +1398,16 @@ static NTSTATUS wg_parser_connect(void *args) gst_element_set_state(parser->container, GST_STATE_PAUSED); ret = gst_element_get_state(parser->container, NULL, NULL, -1); + if (ret == GST_STATE_CHANGE_FAILURE) { - GST_ERROR("Failed to play stream.\n"); + if (!parser->use_mediaconv && parser->init_gst == decodebin_parser_init_gst) + { + GST_WARNING("Failed to play media, trying again with protonvideoconvert."); + use_mediaconv = true; + } + else + GST_ERROR("Failed to play stream.\n"); goto out; } @@ -1361,6 +1417,8 @@ static NTSTATUS wg_parser_connect(void *args) pthread_cond_wait(&parser->init_cond, &parser->mutex); if (parser->error) { + if (!parser->use_mediaconv && parser->init_gst == decodebin_parser_init_gst) + use_mediaconv = true; pthread_mutex_unlock(&parser->mutex); goto out; } @@ -1477,6 +1535,15 @@ static NTSTATUS wg_parser_connect(void *args) pthread_mutex_unlock(&parser->mutex); pthread_cond_signal(&parser->read_cond); + if (use_mediaconv) + { + HRESULT hr; + parser->use_mediaconv = true; + hr = wg_parser_connect(args); + parser->use_mediaconv = false; + return hr; + } + return E_FAIL; } @@ -1539,6 +1606,7 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) g_signal_connect(element, "pad-added", G_CALLBACK(pad_added_cb), parser); g_signal_connect(element, "pad-removed", G_CALLBACK(pad_removed_cb), parser); g_signal_connect(element, "autoplug-select", G_CALLBACK(autoplug_select_cb), parser); + g_signal_connect(element, "autoplug-sort", G_CALLBACK(autoplug_sort_cb), parser); g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads_cb), parser); parser->their_sink = gst_element_get_static_pad(element, "sink"); From 998a0d09b85c8eb2b77f3710c8f0fa136baf024b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 12 May 2022 22:03:43 +0200 Subject: [PATCH 0120/2777] winegstreamer: Register stub WMVDecMediaObject transform. CW-Bug-Id: #18799 CW-Bug-Id: #18994 CW-Bug-Id: #20182 --- dlls/winegstreamer/mfplat.c | 53 +++++++++++++++++++++++++++++++ dlls/winegstreamer/wg_transform.c | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index a09c67b4f11..0c99f204314 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -39,6 +39,8 @@ DEFINE_GUID(DMOVideoFormat_RGB8,D3DFMT_P8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC,WAVE_FORMAT_RAW_AAC1); DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); +extern GUID MEDIASUBTYPE_VC1S; + struct class_factory { IClassFactory IClassFactory_iface; @@ -804,6 +806,47 @@ static void mf_media_type_to_wg_format_video_h264(IMFMediaType *type, struct wg_ format->u.video_h264.level = level; } +static void mf_media_type_to_wg_format_wmv(IMFMediaType *type, const GUID *subtype, struct wg_format *format) +{ + UINT64 frame_rate, frame_size; + + format->major_type = WG_MAJOR_TYPE_VIDEO_WMV; + format->u.video_wmv.width = 0; + format->u.video_wmv.height = 0; + format->u.video_wmv.fps_n = 1; + format->u.video_wmv.fps_d = 1; + + if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) + { + format->u.video_wmv.width = (UINT32)(frame_size >> 32); + format->u.video_wmv.height = (UINT32)frame_size; + } + + if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) + { + format->u.video_wmv.fps_n = (UINT32)(frame_rate >> 32); + format->u.video_wmv.fps_d = (UINT32)frame_rate; + } + + if (IsEqualGUID(subtype, &MFVideoFormat_WMV1)) + format->u.video_wmv.version = 1; + else if (IsEqualGUID(subtype, &MFVideoFormat_WMV2)) + format->u.video_wmv.version = 2; + else if (IsEqualGUID(subtype, &MFVideoFormat_WMV3) + || IsEqualGUID(subtype, &MEDIASUBTYPE_WMVP) + || IsEqualGUID(subtype, &MEDIASUBTYPE_WVP2) + || IsEqualGUID(subtype, &MEDIASUBTYPE_WMVR) + || IsEqualGUID(subtype, &MEDIASUBTYPE_WMVA) + || IsEqualGUID(subtype, &MFVideoFormat_WVC1) + || IsEqualGUID(subtype, &MEDIASUBTYPE_VC1S)) + format->u.video_wmv.version = 3; + else + { + assert(0); + return; + } +} + void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) { GUID major_type, subtype; @@ -837,6 +880,16 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) { if (IsEqualGUID(&subtype, &MFVideoFormat_H264)) mf_media_type_to_wg_format_video_h264(type, format); + else if (IsEqualGUID(&subtype, &MFVideoFormat_WMV1) + || IsEqualGUID(&subtype, &MFVideoFormat_WMV2) + || IsEqualGUID(&subtype, &MFVideoFormat_WMV3) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMVP) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WVP2) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMVR) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_WMVA) + || IsEqualGUID(&subtype, &MFVideoFormat_WVC1) + || IsEqualGUID(&subtype, &MEDIASUBTYPE_VC1S)) + mf_media_type_to_wg_format_wmv(type, &subtype, format); else mf_media_type_to_wg_format_video(type, &subtype, format); } diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 302a64eb57b..3997ada1724 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -427,6 +427,7 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_CINEPAK: + case WG_MAJOR_TYPE_VIDEO_WMV: if (!(element = transform_find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, raw_caps)) || !transform_append_element(transform, element, &first, &last)) { @@ -439,7 +440,6 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_VIDEO: break; case WG_MAJOR_TYPE_UNKNOWN: - case WG_MAJOR_TYPE_VIDEO_WMV: GST_FIXME("Format %u not implemented!", input_format.major_type); gst_caps_unref(raw_caps); goto out; From 27f2dfc4069bcd2cc874884a2b311fecbfff16ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 Aug 2022 21:27:56 +0200 Subject: [PATCH 0121/2777] winegstreamer: Use append_element helper in wg_parser. CW-Bug-Id: #18799 CW-Bug-Id: #18994 CW-Bug-Id: #20182 CW-Bug-Id: #20905 CW-Bug-Id: #20980 --- dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/wg_parser.c | 47 +++++++++++-------------------- dlls/winegstreamer/wg_transform.c | 18 ++++++------ 3 files changed, 26 insertions(+), 40 deletions(-) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 617204e97c7..09eb42da755 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -27,6 +27,7 @@ extern bool init_gstreamer(void) DECLSPEC_HIDDEN; extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; +extern bool append_element(GstBin *bin, GstElement *element, GstElement **first, GstElement **last) DECLSPEC_HIDDEN; extern void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) DECLSPEC_HIDDEN; extern bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) DECLSPEC_HIDDEN; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index b02b34da56b..b990338ba9c 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -847,6 +847,7 @@ static void free_stream(struct wg_parser_stream *stream) static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) { + GstElement *first = NULL, *last = NULL; struct wg_parser *parser = user; struct wg_parser_stream *stream; const char *name; @@ -866,62 +867,46 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) if (!strcmp(name, "video/x-raw")) { - GstElement *deinterlace, *vconv, *flip, *vconv2; - /* DirectShow can express interlaced video, but downstream filters can't * necessarily consume it. In particular, the video renderer can't. */ - if (!(deinterlace = create_element("deinterlace", "good"))) + if (!(element = create_element("deinterlace", "good")) + || !append_element(GST_BIN(parser->container), element, &first, &last)) goto out; /* decodebin considers many YUV formats to be "raw", but some quartz * filters can't handle those. Also, videoflip can't handle all "raw" * formats either. Add a videoconvert to swap color spaces. */ - if (!(vconv = create_element("videoconvert", "base"))) + if (!(element = create_element("videoconvert", "base")) + || !append_element(GST_BIN(parser->container), element, &first, &last)) goto out; /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */ - if (!(flip = create_element("videoflip", "good"))) + if (!(element = create_element("videoflip", "base")) + || !append_element(GST_BIN(parser->container), element, &first, &last)) goto out; + stream->flip = element; /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert * to do the final conversion. */ - if (!(vconv2 = create_element("videoconvert", "base"))) + if (!(element = create_element("videoconvert", "base")) + || !append_element(GST_BIN(parser->container), element, &first, &last)) goto out; - /* The bin takes ownership of these elements. */ - gst_bin_add(GST_BIN(parser->container), deinterlace); - gst_element_sync_state_with_parent(deinterlace); - gst_bin_add(GST_BIN(parser->container), vconv); - gst_element_sync_state_with_parent(vconv); - gst_bin_add(GST_BIN(parser->container), flip); - gst_element_sync_state_with_parent(flip); - gst_bin_add(GST_BIN(parser->container), vconv2); - gst_element_sync_state_with_parent(vconv2); - - gst_element_link(deinterlace, vconv); - gst_element_link(vconv, flip); - gst_element_link(flip, vconv2); - - stream->post_sink = gst_element_get_static_pad(deinterlace, "sink"); - stream->post_src = gst_element_get_static_pad(vconv2, "src"); - stream->flip = flip; + stream->post_sink = gst_element_get_static_pad(first, "sink"); + stream->post_src = gst_element_get_static_pad(last, "src"); } else if (!strcmp(name, "audio/x-raw")) { - GstElement *convert; - /* Currently our dsound can't handle 64-bit formats or all * surround-sound configurations. Native dsound can't always handle * 64-bit formats either. Add an audioconvert to allow changing bit * depth and channel count. */ - if (!(convert = create_element("audioconvert", "base"))) + if (!(element = create_element("audioconvert", "base")) + || !append_element(GST_BIN(parser->container), element, &first, &last)) goto out; - gst_bin_add(GST_BIN(parser->container), convert); - gst_element_sync_state_with_parent(convert); - - stream->post_sink = gst_element_get_static_pad(convert, "sink"); - stream->post_src = gst_element_get_static_pad(convert, "src"); + stream->post_sink = gst_element_get_static_pad(first, "sink"); + stream->post_src = gst_element_get_static_pad(last, "src"); } if (stream->post_sink) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 3997ada1724..fb498556e41 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -314,14 +314,14 @@ static GstElement *transform_find_element(GstElementFactoryListType type, GstCap return element; } -static bool transform_append_element(struct wg_transform *transform, GstElement *element, - GstElement **first, GstElement **last) +bool append_element(GstBin *bin, GstElement *element, GstElement **first, GstElement **last) { gchar *name = gst_element_get_name(element); bool success = false; - if (!gst_bin_add(GST_BIN(transform->container), element) || - (*last && !gst_element_link(*last, element))) + if (!gst_bin_add(bin, element) + || !gst_element_sync_state_with_parent(element) + || (*last && !gst_element_link(*last, element))) { GST_ERROR("Failed to link %s element.", name); } @@ -420,7 +420,7 @@ NTSTATUS wg_transform_create(void *args) transform->input_max_length = 16; transform->output_plane_align = 15; if (!(element = create_element("h264parse", "base")) - || !transform_append_element(transform, element, &first, &last)) + || !append_element(GST_BIN(transform->container), element, &first, &last)) goto out; /* fallthrough */ case WG_MAJOR_TYPE_AUDIO_MPEG1: @@ -429,7 +429,7 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_WMV: if (!(element = transform_find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, raw_caps)) - || !transform_append_element(transform, element, &first, &last)) + || !append_element(GST_BIN(transform->container), element, &first, &last)) { gst_caps_unref(raw_caps); goto out; @@ -460,16 +460,16 @@ NTSTATUS wg_transform_create(void *args) * non-interleaved format. */ if (!(element = create_element("audioconvert", "base")) - || !transform_append_element(transform, element, &first, &last)) + || !append_element(GST_BIN(transform->container), element, &first, &last)) goto out; if (!(element = create_element("audioresample", "base")) - || !transform_append_element(transform, element, &first, &last)) + || !append_element(GST_BIN(transform->container), element, &first, &last)) goto out; break; case WG_MAJOR_TYPE_VIDEO: if (!(element = create_element("videoconvert", "base")) - || !transform_append_element(transform, element, &first, &last)) + || !append_element(GST_BIN(transform->container), element, &first, &last)) goto out; /* Let GStreamer choose a default number of threads. */ gst_util_set_object_arg(G_OBJECT(element), "n-threads", "0"); From 4d5f5ad064eea30f764e9a24981355660f12d1cc Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Thu, 28 Oct 2021 17:46:32 -0500 Subject: [PATCH 0122/2777] winegstreamer: Use unlimited buffering for the WM reader objects. --- dlls/winegstreamer/wm_reader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 00edb637222..9fda7949f0a 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, false))) + if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, true))) return E_OUTOFMEMORY; reader->wg_parser = wg_parser; From 7521f9bdaf37540d6fd559bb886cf1a8f1adc775 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 11 Feb 2022 16:35:11 -0600 Subject: [PATCH 0123/2777] 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 2940832299f..02510a9fcb1 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1390,7 +1390,7 @@ static HRESULT parser_create(enum wg_parser_type type, struct parser **parser) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (!(object->wg_parser = wg_parser_create(type, false))) + if (!(object->wg_parser = wg_parser_create(type, true))) { free(object); return E_OUTOFMEMORY; From e8f1a705527279f0b51885143484051a800d186a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 15 Jun 2022 19:12:54 +0200 Subject: [PATCH 0124/2777] winegstreamer: Keep default decodebin queue limits for buffers and time. Only make size unlimited, which fixes problems with Persona 4 while keeping the memory usage lower. CW-Bug-Id: #18799 CW-Bug-Id: #18994 CW-Bug-Id: #20182 CW-Bug-Id: #20363 CW-Bug-Id: #20905 CW-Bug-Id: #20980 --- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 5 ++--- dlls/winegstreamer/media_source.c | 8 +------- dlls/winegstreamer/quartz_parser.c | 2 +- dlls/winegstreamer/unixlib.h | 1 - dlls/winegstreamer/wg_parser.c | 11 +---------- dlls/winegstreamer/wm_reader.c | 2 +- 7 files changed, 7 insertions(+), 24 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 3890db543ff..b4ee870b021 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -69,7 +69,7 @@ HRESULT wg_sample_queue_create(struct wg_sample_queue **out); void wg_sample_queue_destroy(struct wg_sample_queue *queue); void wg_sample_queue_flush(struct wg_sample_queue *queue, bool all); -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); void wg_parser_destroy(struct wg_parser *parser); HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index a5846e601df..5f0a37999a2 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -66,17 +66,16 @@ 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) { struct wg_parser_create_params params = { .type = type, - .unlimited_buffering = unlimited_buffering, .err_on = ERR_ON(quartz), .warn_on = WARN_ON(quartz), }; - TRACE("type %#x, unlimited_buffering %d.\n", type, unlimited_buffering); + TRACE("type %#x.\n", type); if (WINE_UNIX_CALL(unix_wg_parser_create, ¶ms)) return NULL; diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 3e10b1a2753..ad67e5bd778 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1434,13 +1434,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue))) goto fail; - /* In Media Foundation, sources may read from any media source stream - * without fear of blocking due to buffering limits on another. Trailmakers, - * a Unity3D Engine game, only reads one sample from the audio stream (and - * 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))) { hr = E_OUTOFMEMORY; goto fail; diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 02510a9fcb1..158ba849fd4 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1390,7 +1390,7 @@ static HRESULT parser_create(enum wg_parser_type type, struct parser **parser) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (!(object->wg_parser = wg_parser_create(type, true))) + if (!(object->wg_parser = wg_parser_create(type))) { free(object); return E_OUTOFMEMORY; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 5424633003e..c6182693bba 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -179,7 +179,6 @@ struct wg_parser_create_params { struct wg_parser *parser; enum wg_parser_type type; - bool unlimited_buffering; bool err_on; bool warn_on; }; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index b990338ba9c..cd7132fb4c4 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -92,8 +92,6 @@ struct wg_parser } read_request; bool sink_connected; - - bool unlimited_buffering; bool use_mediaconv; }; @@ -1581,13 +1579,7 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) gst_bin_add(GST_BIN(parser->container), element); parser->decodebin = element; - if (parser->unlimited_buffering) - { - g_object_set(parser->decodebin, "max-size-buffers", G_MAXUINT, NULL); - g_object_set(parser->decodebin, "max-size-time", G_MAXUINT64, NULL); - g_object_set(parser->decodebin, "max-size-bytes", G_MAXUINT, NULL); - } - + g_object_set(element, "max-size-bytes", G_MAXUINT, NULL); g_signal_connect(element, "pad-added", G_CALLBACK(pad_added_cb), parser); g_signal_connect(element, "pad-removed", G_CALLBACK(pad_removed_cb), parser); g_signal_connect(element, "autoplug-select", G_CALLBACK(autoplug_select_cb), parser); @@ -1776,7 +1768,6 @@ static NTSTATUS wg_parser_create(void *args) pthread_cond_init(&parser->read_cond, NULL); pthread_cond_init(&parser->read_done_cond, NULL); parser->init_gst = init_funcs[params->type]; - parser->unlimited_buffering = params->unlimited_buffering; parser->err_on = params->err_on; parser->warn_on = params->warn_on; GST_DEBUG("Created winegstreamer parser %p.", parser); diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 9fda7949f0a..d4d829195ad 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))) return E_OUTOFMEMORY; reader->wg_parser = wg_parser; From 92d030f3ee5506820a4b369645c1cfad05193b35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 Aug 2022 16:06:34 +0200 Subject: [PATCH 0125/2777] winegstreamer: Use OpenGL video processing pipeline for WMReader. There's many 32-bit games using either the WM reader or the ASF reader filter, and which require conversion from I420 to RGBA. However, ORC fails to create an optimized routine as it doesn't support spilling vector registers and it needs more than what's available in 32-bit x86. The WM reader (and the ASF reader filter) currently reads audio and video samples synchronously, and having a high video decoding latency causes trouble on the audio stream. Using OpenGL to post-process the video, and more specifically for the color conversion makes it generally faster, enough to solve the problem in most cases. CW-Bug-Id: #18799 CW-Bug-Id: #18994 CW-Bug-Id: #20182 CW-Bug-Id: #20363 CW-Bug-Id: #20905 CW-Bug-Id: #20980 --- configure.ac | 2 +- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 5 +- dlls/winegstreamer/media_source.c | 2 +- dlls/winegstreamer/quartz_parser.c | 2 +- dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_parser.c | 74 +++++++++++++++++++++++++++++- dlls/winegstreamer/wm_reader.c | 5 +- 8 files changed, 85 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index 96e46275b5c..89d39b91ae9 100644 --- a/configure.ac +++ b/configure.ac @@ -1571,7 +1571,7 @@ WINE_NOTICE_WITH(pulse, [test -z "$PULSE_LIBS"], dnl **** Check for gstreamer **** if test "x$with_gstreamer" != "xno" then - WINE_PACKAGE_FLAGS(GSTREAMER,[gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0],,,, + WINE_PACKAGE_FLAGS(GSTREAMER,[gstreamer-1.0 gstreamer-gl-1.0 gstreamer-video-1.0 gstreamer-audio-1.0],,,, [AC_CHECK_HEADER([gst/gst.h], [AC_MSG_CHECKING([whether gint64 defined by gst/gst.h is indeed 64-bit]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index b4ee870b021..8b12160345a 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -69,7 +69,7 @@ HRESULT wg_sample_queue_create(struct wg_sample_queue **out); void wg_sample_queue_destroy(struct wg_sample_queue *queue); void wg_sample_queue_flush(struct wg_sample_queue *queue, bool all); -struct wg_parser *wg_parser_create(enum wg_parser_type type); +struct wg_parser *wg_parser_create(enum wg_parser_type type, bool use_opengl); void wg_parser_destroy(struct wg_parser *parser); HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 5f0a37999a2..4a6f59f53b6 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -66,16 +66,17 @@ 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) +struct wg_parser *wg_parser_create(enum wg_parser_type type, bool use_opengl) { struct wg_parser_create_params params = { .type = type, + .use_opengl = use_opengl, .err_on = ERR_ON(quartz), .warn_on = WARN_ON(quartz), }; - TRACE("type %#x.\n", type); + TRACE("type %#x, use_opengl %u.\n", type, use_opengl); if (WINE_UNIX_CALL(unix_wg_parser_create, ¶ms)) return NULL; diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index ad67e5bd778..559db66440d 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1434,7 +1434,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue))) goto fail; - if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN))) + if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, false))) { hr = E_OUTOFMEMORY; goto fail; diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 158ba849fd4..2940832299f 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1390,7 +1390,7 @@ static HRESULT parser_create(enum wg_parser_type type, struct parser **parser) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (!(object->wg_parser = wg_parser_create(type))) + if (!(object->wg_parser = wg_parser_create(type, false))) { free(object); return E_OUTOFMEMORY; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index c6182693bba..7af9abdf820 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -179,6 +179,7 @@ struct wg_parser_create_params { struct wg_parser *parser; enum wg_parser_type type; + bool use_opengl; bool err_on; bool warn_on; }; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index cd7132fb4c4..b87acfb2d6a 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -35,6 +35,8 @@ #include #include +#include + #include "ntstatus.h" #define WIN32_NO_STATUS #include "winternl.h" @@ -59,6 +61,9 @@ GST_DEBUG_CATEGORY(wine); typedef BOOL (*init_gst_cb)(struct wg_parser *parser); +static GstGLDisplay *gl_display; +static GstGLContext *gl_context; + struct wg_parser { init_gst_cb init_gst; @@ -93,6 +98,9 @@ struct wg_parser bool sink_connected; bool use_mediaconv; + bool use_opengl; + + GstContext *context; }; struct wg_parser_stream @@ -863,7 +871,34 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) if (!(stream = create_stream(parser))) goto out; - if (!strcmp(name, "video/x-raw")) + if (!strcmp(name, "video/x-raw") && parser->use_opengl) + { + GstElement *first = NULL, *last = NULL, *element; + + if (!(element = create_element("glupload", "base")) + || !append_element(GST_BIN(parser->container), element, &first, &last)) + goto out; + if (!(element = create_element("glcolorconvert", "base")) + || !append_element(GST_BIN(parser->container), element, &first, &last)) + goto out; + if (!(element = create_element("glvideoflip", "base")) + || !append_element(GST_BIN(parser->container), element, &first, &last)) + goto out; + stream->flip = element; + if (!(element = create_element("gldeinterlace", "base")) + || !append_element(GST_BIN(parser->container), element, &first, &last)) + goto out; + if (!(element = create_element("glcolorconvert", "base")) + || !append_element(GST_BIN(parser->container), element, &first, &last)) + goto out; + if (!(element = create_element("gldownload", "base")) + || !append_element(GST_BIN(parser->container), element, &first, &last)) + goto out; + + stream->post_sink = gst_element_get_static_pad(first, "sink"); + stream->post_src = gst_element_get_static_pad(last, "src"); + } + else if (!strcmp(name, "video/x-raw")) { /* DirectShow can express interlaced video, but downstream filters can't * necessarily consume it. In particular, the video renderer can't. */ @@ -1364,6 +1399,8 @@ static NTSTATUS wg_parser_connect(void *args) parser->container = gst_bin_new(NULL); gst_element_set_bus(parser->container, parser->bus); + if (parser->context) + gst_element_set_context(parser->container, parser->context); parser->my_src = gst_pad_new_from_static_template(&src_template, "quartz-src"); gst_pad_set_getrange_function(parser->my_src, src_getrange_cb); @@ -1735,6 +1772,28 @@ static void init_gstreamer_once(void) GST_INFO("GStreamer library version %s; wine built with %d.%d.%d.", gst_version_string(), GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO); + + if (!(gl_display = gst_gl_display_new())) + GST_ERROR("Failed to create OpenGL display"); + else + { + GError *error = NULL; + gboolean ret; + + GST_OBJECT_LOCK(gl_display); + ret = gst_gl_display_create_context(gl_display, NULL, &gl_context, &error); + GST_OBJECT_UNLOCK(gl_display); + g_clear_error(&error); + + if (ret) + gst_gl_display_add_context(gl_display, gl_context); + else + { + GST_ERROR("Failed to create OpenGL context"); + gst_object_unref(gl_display); + gl_display = NULL; + } + } } bool init_gstreamer(void) @@ -1762,6 +1821,16 @@ static NTSTATUS wg_parser_create(void *args) if (!(parser = calloc(1, sizeof(*parser)))) return E_OUTOFMEMORY; + if ((parser->use_opengl = params->use_opengl && gl_display)) + { + if ((parser->context = gst_context_new(GST_GL_DISPLAY_CONTEXT_TYPE, false))) + gst_context_set_gl_display(parser->context, gl_display); + else + { + GST_ERROR("Failed to create parser context"); + parser->use_opengl = FALSE; + } + } pthread_mutex_init(&parser->mutex, NULL); pthread_cond_init(&parser->init_cond, NULL); @@ -1785,6 +1854,9 @@ static NTSTATUS wg_parser_destroy(void *args) gst_object_unref(parser->bus); } + if (parser->context) + gst_context_unref(parser->context); + pthread_mutex_destroy(&parser->mutex); pthread_cond_destroy(&parser->init_cond); pthread_cond_destroy(&parser->read_cond); diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index d4d829195ad..2971ec8d35c 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1455,7 +1455,10 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) HRESULT hr; WORD i; - if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN))) + /* 32-bit GStreamer ORC cannot efficiently convert I420 to RGBA, use OpenGL converter + * in that case but keep the usual codepath otherwise. + */ + if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, sizeof(void *) == 4))) return E_OUTOFMEMORY; reader->wg_parser = wg_parser; From f7a2a27fa38d67b16dda98f9e5366ea7df91a9f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 16 Jun 2022 16:50:42 +0200 Subject: [PATCH 0126/2777] winegstreamer: Expose BGRA video format from wm_reader. For Deadly Premonition. CW-Bug-Id: #18799 --- dlls/winegstreamer/wm_reader.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 2971ec8d35c..df4b00dd4c3 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1567,6 +1567,7 @@ static const enum wg_video_format video_formats[] = WG_VIDEO_FORMAT_YUY2, WG_VIDEO_FORMAT_UYVY, WG_VIDEO_FORMAT_YVYU, + WG_VIDEO_FORMAT_BGRA, WG_VIDEO_FORMAT_BGRx, WG_VIDEO_FORMAT_BGR, WG_VIDEO_FORMAT_RGB16, From 821204068d11c6de6964315503036c7ccd08e662 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Fri, 24 Jun 2022 19:46:42 +0200 Subject: [PATCH 0127/2777] winegstreamer: create media source from uri Supported by gstreamer's uridecodebin. Link: https://github.com/ValveSoftware/wine/pull/142 CW-Bug-Id: #20485 --- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 3 ++- dlls/winegstreamer/media_source.c | 32 +++++++++++++++++++++---- dlls/winegstreamer/quartz_parser.c | 2 +- dlls/winegstreamer/unixlib.h | 2 ++ dlls/winegstreamer/wg_parser.c | 38 ++++++++++++++++++++++++++++++ dlls/winegstreamer/wm_reader.c | 2 +- 7 files changed, 72 insertions(+), 9 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 8b12160345a..79873088ae3 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -72,7 +72,7 @@ void wg_sample_queue_flush(struct wg_sample_queue *queue, bool all); struct wg_parser *wg_parser_create(enum wg_parser_type type, bool use_opengl); void wg_parser_destroy(struct wg_parser *parser); -HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size); +HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size, const WCHAR *uri); void wg_parser_disconnect(struct wg_parser *parser); bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, uint32_t *size); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 4a6f59f53b6..8f42673b10e 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -93,12 +93,13 @@ void wg_parser_destroy(struct wg_parser *parser) WINE_UNIX_CALL(unix_wg_parser_destroy, parser); } -HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size) +HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size, const WCHAR *uri) { struct wg_parser_connect_params params = { .parser = parser, .file_size = file_size, + .uri = uri, }; TRACE("parser %p, file_size %I64u.\n", parser, file_size); diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 559db66440d..37d38e1fef8 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -859,8 +859,8 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) IMFMediaType *stream_types[8]; struct wg_format format; DWORD type_count = 0; + HRESULT hr = S_OK; unsigned int i; - HRESULT hr; wg_parser_stream_get_preferred_format(stream->wg_stream, &format); @@ -1387,7 +1387,7 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = media_source_Shutdown, }; -static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source) +static HRESULT media_source_constructor(IMFByteStream *bytestream, const WCHAR *uri, struct media_source **out_media_source) { BOOL video_selected = FALSE, audio_selected = FALSE; IMFStreamDescriptor **descriptors = NULL; @@ -1434,7 +1434,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue))) goto fail; - if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, false))) + if (!(parser = wg_parser_create(uri ? WG_PARSER_URIDECODEBIN : WG_PARSER_DECODEBIN, false))) { hr = E_OUTOFMEMORY; goto fail; @@ -1445,7 +1445,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ object->state = SOURCE_OPENING; - if (FAILED(hr = wg_parser_connect(parser, file_size))) + if (FAILED(hr = wg_parser_connect(parser, file_size, uri))) goto fail; stream_count = wg_parser_get_stream_count(parser); @@ -1594,6 +1594,28 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ return hr; } +HRESULT winegstreamer_create_media_source_from_uri(const WCHAR *uri, IUnknown **out_object) +{ + struct media_source *object; + IMFByteStream *bytestream; + IStream *stream; + HRESULT hr; + + if (FAILED(hr = CreateStreamOnHGlobal(0, TRUE, &stream))) + return hr; + + hr = MFCreateMFByteStreamOnStream(stream, &bytestream); + IStream_Release(stream); + if (FAILED(hr)) + return hr; + + if (SUCCEEDED(hr = media_source_constructor(bytestream, uri, &object))) + *out_object = (IUnknown*)&object->IMFMediaSource_iface; + + IMFByteStream_Release(bytestream); + return hr; +} + struct winegstreamer_stream_handler_result { struct list entry; @@ -1934,7 +1956,7 @@ static HRESULT winegstreamer_stream_handler_create_object(struct winegstreamer_s HRESULT hr; struct media_source *new_source; - if (FAILED(hr = media_source_constructor(stream, &new_source))) + if (FAILED(hr = media_source_constructor(stream, NULL, &new_source))) return hr; TRACE("->(%p)\n", new_source); diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 2940832299f..a4dc792f243 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1253,7 +1253,7 @@ static HRESULT parser_sink_connect(struct strmbase_sink *iface, IPin *peer, cons filter->sink_connected = true; filter->read_thread = CreateThread(NULL, 0, read_thread, filter, 0, NULL); - if (FAILED(hr = wg_parser_connect(filter->wg_parser, file_size))) + if (FAILED(hr = wg_parser_connect(filter->wg_parser, file_size, NULL))) goto err; if (!filter->init_gst(filter)) diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 7af9abdf820..d8209a80b08 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -173,6 +173,7 @@ enum wg_parser_type WG_PARSER_AVIDEMUX, WG_PARSER_MPEGAUDIOPARSE, WG_PARSER_WAVPARSE, + WG_PARSER_URIDECODEBIN, }; struct wg_parser_create_params @@ -187,6 +188,7 @@ struct wg_parser_create_params struct wg_parser_connect_params { struct wg_parser *parser; + const WCHAR *uri; UINT64 file_size; }; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index b87acfb2d6a..86a8c4100f1 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -77,6 +77,7 @@ struct wg_parser guint64 file_size, start_offset, next_offset, stop_offset; guint64 next_pull_offset; + gchar *uri; pthread_t push_thread; @@ -1384,12 +1385,22 @@ static NTSTATUS wg_parser_connect(void *args) GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); const struct wg_parser_connect_params *params = args; struct wg_parser *parser = params->parser; + const WCHAR *uri = params->uri; bool use_mediaconv = false; unsigned int i; int ret; parser->file_size = params->file_size; parser->sink_connected = true; + if (uri) + { + parser->uri = malloc(wcslen(uri) * 3 + 1); + ntdll_wcstoumbs(uri, wcslen(uri) + 1, parser->uri, wcslen(uri) * 3 + 1, FALSE); + } + else + { + parser->uri = NULL; + } if (!parser->bus) { @@ -1638,6 +1649,31 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) return TRUE; } +static BOOL uridecodebin_parser_init_gst(struct wg_parser *parser) +{ + GstElement *element; + + if (!(element = create_element("uridecodebin", "base"))) + return FALSE; + + gst_bin_add(GST_BIN(parser->container), element); + parser->decodebin = element; + + g_object_set(parser->decodebin, "uri", parser->uri, NULL); + g_object_set(parser->decodebin, "max-size-bytes", G_MAXUINT, NULL); + g_signal_connect(element, "pad-added", G_CALLBACK(pad_added_cb), parser); + g_signal_connect(element, "pad-removed", G_CALLBACK(pad_removed_cb), parser); + g_signal_connect(element, "autoplug-select", G_CALLBACK(autoplug_select_cb), parser); + g_signal_connect(element, "autoplug-sort", G_CALLBACK(autoplug_sort_cb), parser); + g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads_cb), parser); + + pthread_mutex_lock(&parser->mutex); + parser->no_more_pads = false; + pthread_mutex_unlock(&parser->mutex); + + return TRUE; +} + static BOOL avi_parser_init_gst(struct wg_parser *parser) { GstElement *element; @@ -1811,6 +1847,7 @@ static NTSTATUS wg_parser_create(void *args) [WG_PARSER_AVIDEMUX] = avi_parser_init_gst, [WG_PARSER_MPEGAUDIOPARSE] = mpeg_audio_parser_init_gst, [WG_PARSER_WAVPARSE] = wave_parser_init_gst, + [WG_PARSER_URIDECODEBIN] = uridecodebin_parser_init_gst, }; struct wg_parser_create_params *params = args; @@ -1862,6 +1899,7 @@ static NTSTATUS wg_parser_destroy(void *args) pthread_cond_destroy(&parser->read_cond); pthread_cond_destroy(&parser->read_done_cond); + free(parser->uri); free(parser); return S_OK; } diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index df4b00dd4c3..9e0c82ed07f 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1469,7 +1469,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) goto out_destroy_parser; } - if (FAILED(hr = wg_parser_connect(reader->wg_parser, file_size))) + if (FAILED(hr = wg_parser_connect(reader->wg_parser, file_size, NULL))) { ERR("Failed to connect parser, hr %#lx.\n", hr); goto out_shutdown_thread; From 43109ae880034dd9e8c7053ef8fa596931eea3d8 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Sun, 17 Apr 2022 16:56:50 +0100 Subject: [PATCH 0128/2777] winegstreamer: add http/https/rtsp scheme handler Link: https://github.com/ValveSoftware/wine/pull/142 CW-Bug-Id: #20485 --- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/mfplat.c | 3 + dlls/winegstreamer/scheme_handler.c | 408 +++++++++++++++++++ dlls/winegstreamer/winegstreamer.rgs | 28 ++ dlls/winegstreamer/winegstreamer_classes.idl | 7 + 6 files changed, 449 insertions(+) create mode 100644 dlls/winegstreamer/scheme_handler.c diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 064a8b68343..9bdafe83897 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -16,6 +16,7 @@ C_SRCS = \ quartz_parser.c \ quartz_transform.c \ resampler.c \ + scheme_handler.c \ video_processor.c \ wg_allocator.c \ wg_format.c \ diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 79873088ae3..a7e73955f1f 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -142,9 +142,11 @@ HRESULT wg_transform_read_mf(struct wg_transform *transform, IMFSample *sample, HRESULT wg_transform_read_quartz(struct wg_transform *transform, struct wg_sample *sample); HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj); +HRESULT winegstreamer_create_media_source_from_uri(const WCHAR *uri, IUnknown **out_media_source) DECLSPEC_HIDDEN; HRESULT aac_decoder_create(REFIID riid, void **ret); HRESULT h264_decoder_create(REFIID riid, void **ret); HRESULT video_processor_create(REFIID riid, void **ret); +HRESULT gstreamer_scheme_handler_construct(REFIID riid, void **ret) DECLSPEC_HIDDEN; #endif /* __GST_PRIVATE_INCLUDED__ */ diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 0c99f204314..86e794d0d37 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -119,6 +119,8 @@ static const IClassFactoryVtbl class_factory_vtbl = static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; +static const GUID CLSID_GStreamerSchemePlugin = {0x587eeb6a,0x7336,0x4ebd,{0xa4,0xf2,0x91,0xc9,0x48,0xde,0x62,0x2c}}; + static const struct class_object { const GUID *clsid; @@ -130,6 +132,7 @@ class_objects[] = { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, { &CLSID_MSAACDecMFT, &aac_decoder_create }, { &CLSID_MSH264DecoderMFT, &h264_decoder_create }, + { &CLSID_GStreamerSchemePlugin, &gstreamer_scheme_handler_construct }, }; HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) diff --git a/dlls/winegstreamer/scheme_handler.c b/dlls/winegstreamer/scheme_handler.c new file mode 100644 index 00000000000..1aa36b8b7a5 --- /dev/null +++ b/dlls/winegstreamer/scheme_handler.c @@ -0,0 +1,408 @@ +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "mfidl.h" +#include "mferror.h" +#include "mfapi.h" +#include "gst_private.h" + +#include "wine/debug.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +struct gstreamer_scheme_handler_result +{ + struct list entry; + IMFAsyncResult *result; + IUnknown *object; +}; + +struct gstreamer_scheme_handler +{ + IMFSchemeHandler IMFSchemeHandler_iface; + IMFAsyncCallback IMFAsyncCallback_iface; + LONG refcount; + struct list results; + CRITICAL_SECTION cs; +}; + +static struct gstreamer_scheme_handler *impl_from_IMFSchemeHandler(IMFSchemeHandler *iface) +{ + return CONTAINING_RECORD(iface, struct gstreamer_scheme_handler, IMFSchemeHandler_iface); +} + +static struct gstreamer_scheme_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct gstreamer_scheme_handler, IMFAsyncCallback_iface); +} + +static HRESULT WINAPI gstreamer_scheme_handler_QueryIntace(IMFSchemeHandler *iface, REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFSchemeHandler) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFSchemeHandler_AddRef(iface); + return S_OK; + } + + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI gstreamer_scheme_handler_AddRef(IMFSchemeHandler *iface) +{ + struct gstreamer_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); + ULONG refcount = InterlockedIncrement(&handler->refcount); + + TRACE("%p, refcount %lu.\n", handler, refcount); + + return refcount; +} + +static ULONG WINAPI gstreamer_scheme_handler_Release(IMFSchemeHandler *iface) +{ + struct gstreamer_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); + ULONG refcount = InterlockedDecrement(&handler->refcount); + struct gstreamer_scheme_handler_result *result, *next; + + TRACE("%p, refcount %lu.\n", iface, refcount); + + if (!refcount) + { + LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct gstreamer_scheme_handler_result, entry) + { + list_remove(&result->entry); + IMFAsyncResult_Release(result->result); + if (result->object) + IUnknown_Release(result->object); + free(result); + } + DeleteCriticalSection(&handler->cs); + free(handler); + } + + return refcount; +} + +struct create_object_context +{ + IUnknown IUnknown_iface; + LONG refcount; + + IPropertyStore *props; + WCHAR *url; + DWORD flags; +}; + +static struct create_object_context *impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct create_object_context, IUnknown_iface); +} + +static HRESULT WINAPI create_object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IUnknown_AddRef(iface); + return S_OK; + } + + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI create_object_context_AddRef(IUnknown *iface) +{ + struct create_object_context *context = impl_from_IUnknown(iface); + ULONG refcount = InterlockedIncrement(&context->refcount); + + TRACE("%p, refcount %lu.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI create_object_context_Release(IUnknown *iface) +{ + struct create_object_context *context = impl_from_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&context->refcount); + + TRACE("%p, refcount %lu.\n", iface, refcount); + + if (!refcount) + { + if (context->props) + IPropertyStore_Release(context->props); + free(context->url); + free(context); + } + + return refcount; +} + +static const IUnknownVtbl create_object_context_vtbl = +{ + create_object_context_QueryInterface, + create_object_context_AddRef, + create_object_context_Release, +}; + +static HRESULT WINAPI gstreamer_scheme_handler_BeginCreateObject(IMFSchemeHandler *iface, const WCHAR *url, DWORD flags, + IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state) +{ + struct gstreamer_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); + struct create_object_context *context; + IMFAsyncResult *caller, *item; + HRESULT hr; + + TRACE("%p, %s, %#lx, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state); + + if (cancel_cookie) + *cancel_cookie = NULL; + + if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller))) + return hr; + + if (!(context = malloc(sizeof(*context)))) + { + IMFAsyncResult_Release(caller); + return E_OUTOFMEMORY; + } + + context->IUnknown_iface.lpVtbl = &create_object_context_vtbl; + context->refcount = 1; + context->props = props; + if (context->props) + IPropertyStore_AddRef(context->props); + context->flags = flags; + context->url = wcsdup(url); + if (!context->url) + { + IMFAsyncResult_Release(caller); + IUnknown_Release(&context->IUnknown_iface); + return E_OUTOFMEMORY; + } + + hr = MFCreateAsyncResult(&context->IUnknown_iface, &handler->IMFAsyncCallback_iface, (IUnknown *)caller, &item); + IUnknown_Release(&context->IUnknown_iface); + if (SUCCEEDED(hr)) + { + if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item))) + { + if (cancel_cookie) + { + *cancel_cookie = (IUnknown *)caller; + IUnknown_AddRef(*cancel_cookie); + } + } + + IMFAsyncResult_Release(item); + } + IMFAsyncResult_Release(caller); + + return hr; +} + +static HRESULT WINAPI gstreamer_scheme_handler_EndCreateObject(IMFSchemeHandler *iface, IMFAsyncResult *result, + MF_OBJECT_TYPE *obj_type, IUnknown **object) +{ + struct gstreamer_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); + struct gstreamer_scheme_handler_result *found = NULL, *cur; + HRESULT hr; + + TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object); + + EnterCriticalSection(&handler->cs); + + LIST_FOR_EACH_ENTRY(cur, &handler->results, struct gstreamer_scheme_handler_result, entry) + { + if (result == cur->result) + { + list_remove(&cur->entry); + found = cur; + break; + } + } + + LeaveCriticalSection(&handler->cs); + + if (found) + { + *obj_type = MF_OBJECT_MEDIASOURCE; + *object = found->object; + hr = IMFAsyncResult_GetStatus(found->result); + IMFAsyncResult_Release(found->result); + free(found); + } + else + { + *obj_type = MF_OBJECT_INVALID; + *object = NULL; + hr = MF_E_UNEXPECTED; + } + + return hr; +} + +static HRESULT WINAPI gstreamer_scheme_handler_CancelObjectCreation(IMFSchemeHandler *iface, IUnknown *cancel_cookie) +{ + struct gstreamer_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); + struct gstreamer_scheme_handler_result *found = NULL, *cur; + + TRACE("%p, %p.\n", iface, cancel_cookie); + + EnterCriticalSection(&handler->cs); + + LIST_FOR_EACH_ENTRY(cur, &handler->results, struct gstreamer_scheme_handler_result, entry) + { + if (cancel_cookie == (IUnknown *)cur->result) + { + list_remove(&cur->entry); + found = cur; + break; + } + } + + LeaveCriticalSection(&handler->cs); + + if (found) + { + IMFAsyncResult_Release(found->result); + if (found->object) + IUnknown_Release(found->object); + free(found); + } + + return found ? S_OK : MF_E_UNEXPECTED; +} + +static const IMFSchemeHandlerVtbl gstreamer_scheme_handler_vtbl = +{ + gstreamer_scheme_handler_QueryIntace, + gstreamer_scheme_handler_AddRef, + gstreamer_scheme_handler_Release, + gstreamer_scheme_handler_BeginCreateObject, + gstreamer_scheme_handler_EndCreateObject, + gstreamer_scheme_handler_CancelObjectCreation, +}; + +static HRESULT WINAPI gstreamer_scheme_handler_callback_QueryIntace(IMFAsyncCallback *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFAsyncCallback) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFAsyncCallback_AddRef(iface); + return S_OK; + } + + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI gstreamer_scheme_handler_callback_AddRef(IMFAsyncCallback *iface) +{ + struct gstreamer_scheme_handler *handler = impl_from_IMFAsyncCallback(iface); + return IMFSchemeHandler_AddRef(&handler->IMFSchemeHandler_iface); +} + +static ULONG WINAPI gstreamer_scheme_handler_callback_Release(IMFAsyncCallback *iface) +{ + struct gstreamer_scheme_handler *handler = impl_from_IMFAsyncCallback(iface); + return IMFSchemeHandler_Release(&handler->IMFSchemeHandler_iface); +} + +static HRESULT WINAPI gstreamer_scheme_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI gstreamer_scheme_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + IMFAsyncResult *caller; + struct gstreamer_scheme_handler *handler = impl_from_IMFAsyncCallback(iface); + struct gstreamer_scheme_handler_result *handler_result; + IUnknown *object = NULL, *context_object; + struct create_object_context *context; + HRESULT hr; + + caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result); + + if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object))) + { + WARN("Expected context set for callee result.\n"); + return hr; + } + + context = impl_from_IUnknown(context_object); + + hr = winegstreamer_create_media_source_from_uri(context->url, &object); + + handler_result = malloc(sizeof(*handler_result)); + if (handler_result) + { + handler_result->result = caller; + IMFAsyncResult_AddRef(handler_result->result); + + handler_result->object = object; + + EnterCriticalSection(&handler->cs); + list_add_tail(&handler->results, &handler_result->entry); + LeaveCriticalSection(&handler->cs); + } + else + { + if (object) + IUnknown_Release(object); + hr = E_OUTOFMEMORY; + } + + IMFAsyncResult_SetStatus(caller, hr); + MFInvokeCallback(caller); + + return S_OK; +} + +static const IMFAsyncCallbackVtbl gstreamer_scheme_handler_callback_vtbl = +{ + gstreamer_scheme_handler_callback_QueryIntace, + gstreamer_scheme_handler_callback_AddRef, + gstreamer_scheme_handler_callback_Release, + gstreamer_scheme_handler_callback_GetParameters, + gstreamer_scheme_handler_callback_Invoke, +}; + +HRESULT gstreamer_scheme_handler_construct(REFIID riid, void **obj) +{ + struct gstreamer_scheme_handler *handler; + HRESULT hr; + + TRACE("%s, %p.\n", debugstr_guid(riid), obj); + + if (!(handler = calloc(1, sizeof(*handler)))) + return E_OUTOFMEMORY; + + handler->IMFSchemeHandler_iface.lpVtbl = &gstreamer_scheme_handler_vtbl; + handler->IMFAsyncCallback_iface.lpVtbl = &gstreamer_scheme_handler_callback_vtbl; + handler->refcount = 1; + list_init(&handler->results); + InitializeCriticalSection(&handler->cs); + + hr = IMFSchemeHandler_QueryInterface(&handler->IMFSchemeHandler_iface, riid, obj); + IMFSchemeHandler_Release(&handler->IMFSchemeHandler_iface); + + return hr; +} + diff --git a/dlls/winegstreamer/winegstreamer.rgs b/dlls/winegstreamer/winegstreamer.rgs index 923ba673f8c..c50d3a05747 100644 --- a/dlls/winegstreamer/winegstreamer.rgs +++ b/dlls/winegstreamer/winegstreamer.rgs @@ -12,3 +12,31 @@ HKCR } } } + +HKLM +{ + NoRemove 'Software' + { + NoRemove 'Microsoft' + { + NoRemove 'Windows Media Foundation' + { + NoRemove 'SchemeHandlers' + { + 'http:' + { + val '{587eeb6a-7336-4ebd-a4f2-91c948de622c}' = s 'GStreamer Scheme Handler' + } + 'https:' + { + val '{587eeb6a-7336-4ebd-a4f2-91c948de622c}' = s 'GStreamer Scheme Handler' + } + 'rtsp:' + { + val '{587eeb6a-7336-4ebd-a4f2-91c948de622c}' = s 'GStreamer Scheme Handler' + } + } + } + } + } +} diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index 30a99c9acfb..1b87dcde716 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl @@ -111,3 +111,10 @@ coclass CResamplerMediaObject {} uuid(98230571-0087-4204-b020-3282538e57d3) ] coclass CColorConvertDMO {} + +[ + helpstring("GStreamer scheme handler"), + threading(both), + uuid(587eeb6a-7336-4ebd-a4f2-91c948de622c) +] +coclass GStreamerSchemePlugin { } From 02599e7092741d161f7e717879e1e130abb7f107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Aug 2022 11:26:20 +0200 Subject: [PATCH 0129/2777] winegstreamer: Allow more input buffer to be queued for uncompressed formats. CW-Bug-Id: #18799 CW-Bug-Id: #18994 CW-Bug-Id: #20182 CW-Bug-Id: #20905 --- dlls/winegstreamer/wg_transform.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index fb498556e41..b711934bf63 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -438,6 +438,7 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_AUDIO: case WG_MAJOR_TYPE_VIDEO: + transform->input_max_length = 16; break; case WG_MAJOR_TYPE_UNKNOWN: GST_FIXME("Format %u not implemented!", input_format.major_type); From b1670ae9a5dc54c8932f0ef009e8dc7b48ddc3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 Aug 2022 09:04:46 +0200 Subject: [PATCH 0130/2777] winegstreamer: Implement WMA decoder DMO side. CW-Bug-Id: #18799 CW-Bug-Id: #18994 CW-Bug-Id: #20182 CW-Bug-Id: #20905 --- dlls/winegstreamer/gst_private.h | 5 + dlls/winegstreamer/quartz_parser.c | 88 +++++++++++++- dlls/winegstreamer/wg_sample.c | 111 +++++++++++++++++- dlls/winegstreamer/wma_decoder.c | 182 ++++++++++++++++++++++++++--- 4 files changed, 366 insertions(+), 20 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index a7e73955f1f..ee1736680ad 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -129,14 +129,19 @@ extern HRESULT mfplat_DllRegisterServer(void); IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format); void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format); +HRESULT wg_sample_create_dmo(IMediaBuffer *buffer, struct wg_sample **out); HRESULT wg_sample_create_mf(IMFSample *sample, struct wg_sample **out); HRESULT wg_sample_create_quartz(IMediaSample *sample, struct wg_sample **out); void wg_sample_release(struct wg_sample *wg_sample); +HRESULT wg_transform_push_dmo(struct wg_transform *transform, struct wg_sample *sample, + struct wg_sample_queue *queue, REFERENCE_TIME pts, REFERENCE_TIME duration); HRESULT wg_transform_push_mf(struct wg_transform *transform, IMFSample *sample, struct wg_sample_queue *queue); HRESULT wg_transform_push_quartz(struct wg_transform *transform, struct wg_sample *sample, struct wg_sample_queue *queue); +HRESULT wg_transform_read_dmo(struct wg_transform *transform, struct wg_sample *sample, + DWORD *flags, REFERENCE_TIME *pts, REFERENCE_TIME *duration); HRESULT wg_transform_read_mf(struct wg_transform *transform, IMFSample *sample, DWORD sample_size, struct wg_format *format, DWORD *flags); HRESULT wg_transform_read_quartz(struct wg_transform *transform, struct wg_sample *sample); diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index a4dc792f243..9a6573cd1f0 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -278,6 +278,54 @@ static bool amt_from_wg_format_audio_mpeg1(AM_MEDIA_TYPE *mt, const struct wg_fo return false; } +static bool amt_from_wg_format_wma(AM_MEDIA_TYPE *mt, const struct wg_format *format) +{ + WAVEFORMATEX *wave_format; + + mt->majortype = MEDIATYPE_Audio; + mt->formattype = FORMAT_WaveFormatEx; + + if (!(wave_format = CoTaskMemAlloc(sizeof(*wave_format) + format->u.audio_wma.codec_data_len))) + return false; + memset(wave_format, 0, sizeof(*wave_format)); + memcpy(wave_format + 1, format->u.audio_wma.codec_data, format->u.audio_wma.codec_data_len); + + mt->cbFormat = sizeof(*wave_format); + mt->pbFormat = (BYTE *)wave_format; + + switch (format->u.audio_wma.version) + { + case 1: + mt->subtype = MEDIASUBTYPE_MSAUDIO1; + wave_format->wFormatTag = WAVE_FORMAT_MSAUDIO1; + break; + case 2: + mt->subtype = MEDIASUBTYPE_WMAUDIO2; + wave_format->wFormatTag = WAVE_FORMAT_WMAUDIO2; + break; + case 3: + mt->subtype = MEDIASUBTYPE_WMAUDIO3; + wave_format->wFormatTag = WAVE_FORMAT_WMAUDIO3; + break; + case 4: + mt->subtype = MEDIASUBTYPE_WMAUDIO_LOSSLESS; + wave_format->wFormatTag = WAVE_FORMAT_WMAUDIO_LOSSLESS; + break; + default: + FIXME("unsupported version %u\n", format->u.audio_wma.version); + assert(0); + return false; + } + + wave_format->nChannels = format->u.audio_wma.channels; + wave_format->nSamplesPerSec = format->u.audio_wma.rate; + wave_format->wBitsPerSample = format->u.audio_wma.depth; + wave_format->nBlockAlign = format->u.audio_wma.block_align; + wave_format->nAvgBytesPerSec = format->u.audio_wma.bitrate / 8; + wave_format->cbSize = sizeof(*wave_format) + format->u.audio_wma.codec_data_len - sizeof(WAVEFORMATEX); + return true; +} + #define ALIGN(n, alignment) (((n) + (alignment) - 1) & ~((alignment) - 1)) unsigned int wg_format_get_max_size(const struct wg_format *format) @@ -545,7 +593,6 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool switch (format->major_type) { case WG_MAJOR_TYPE_AUDIO_MPEG4: - case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: FIXME("Format %u not implemented!\n", format->major_type); @@ -559,6 +606,9 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool case WG_MAJOR_TYPE_AUDIO_MPEG1: return amt_from_wg_format_audio_mpeg1(mt, format); + case WG_MAJOR_TYPE_AUDIO_WMA: + return amt_from_wg_format_wma(mt, format); + case WG_MAJOR_TYPE_VIDEO: return amt_from_wg_format_video(mt, format, wm); @@ -683,6 +733,34 @@ static bool amt_to_wg_format_audio_mpeg1_layer3(const AM_MEDIA_TYPE *mt, struct return true; } +static bool amt_to_wg_format_audio_wma(const AM_MEDIA_TYPE *mt, struct wg_format *format, + uint32_t version) +{ + const WAVEFORMATEX *audio_format = (const WAVEFORMATEX *)mt->pbFormat; + + if (!IsEqualGUID(&mt->formattype, &FORMAT_WaveFormatEx)) + { + FIXME("Unknown format type %s.\n", debugstr_guid(&mt->formattype)); + return false; + } + if (mt->cbFormat < sizeof(*audio_format) || !mt->pbFormat) + { + ERR("Unexpected format size %lu.\n", mt->cbFormat); + return false; + } + + format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; + format->u.audio_wma.version = version; + format->u.audio_wma.channels = audio_format->nChannels; + format->u.audio_wma.depth = audio_format->wBitsPerSample; + format->u.audio_wma.block_align = audio_format->nBlockAlign; + format->u.audio_wma.bitrate = audio_format->nAvgBytesPerSec * 8; + format->u.audio_wma.rate = audio_format->nSamplesPerSec; + format->u.audio_wma.codec_data_len = mt->cbFormat - sizeof(*audio_format); + memcpy(format->u.audio_wma.codec_data, audio_format + 1, format->u.audio_wma.codec_data_len); + return true; +} + static bool amt_to_wg_format_video(const AM_MEDIA_TYPE *mt, struct wg_format *format) { static const struct @@ -794,6 +872,14 @@ bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format) return amt_to_wg_format_audio_mpeg1(mt, format); if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MP3)) return amt_to_wg_format_audio_mpeg1_layer3(mt, format); + if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MSAUDIO1)) + return amt_to_wg_format_audio_wma(mt, format, 1); + if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO2)) + return amt_to_wg_format_audio_wma(mt, format, 2); + if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO3)) + return amt_to_wg_format_audio_wma(mt, format, 3); + if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO_LOSSLESS)) + return amt_to_wg_format_audio_wma(mt, format, 4); return amt_to_wg_format_audio(mt, format); } diff --git a/dlls/winegstreamer/wg_sample.c b/dlls/winegstreamer/wg_sample.c index eb4af86c381..e8e3dca72ba 100644 --- a/dlls/winegstreamer/wg_sample.c +++ b/dlls/winegstreamer/wg_sample.c @@ -48,6 +48,10 @@ struct sample union { + struct + { + IMediaBuffer *buffer; + } dmo; struct { IMFSample *sample; @@ -165,6 +169,55 @@ HRESULT wg_sample_create_quartz(IMediaSample *media_sample, struct wg_sample **o return S_OK; } +static const struct wg_sample_ops dmo_sample_ops; + +static inline struct sample *unsafe_dmo_from_wg_sample(struct wg_sample *wg_sample) +{ + struct sample *sample = CONTAINING_RECORD(wg_sample, struct sample, wg_sample); + if (sample->ops != &dmo_sample_ops) return NULL; + return sample; +} + +static void dmo_sample_destroy(struct wg_sample *wg_sample) +{ + struct sample *sample = unsafe_dmo_from_wg_sample(wg_sample); + + TRACE_(quartz)("wg_sample %p.\n", wg_sample); + + IMediaBuffer_Release(sample->u.dmo.buffer); +} + +static const struct wg_sample_ops dmo_sample_ops = +{ + dmo_sample_destroy, +}; + +HRESULT wg_sample_create_dmo(IMediaBuffer *media_buffer, struct wg_sample **out) +{ + DWORD current_length, max_length; + struct sample *sample; + BYTE *buffer; + HRESULT hr; + + if (FAILED(hr = IMediaBuffer_GetBufferAndLength(media_buffer, &buffer, ¤t_length))) + return hr; + if (FAILED(hr = IMediaBuffer_GetMaxLength(media_buffer, &max_length))) + return hr; + + if (!(sample = calloc(1, sizeof(*sample)))) + return E_OUTOFMEMORY; + + IMediaBuffer_AddRef((sample->u.dmo.buffer = media_buffer)); + sample->wg_sample.data = buffer; + sample->wg_sample.size = current_length; + sample->wg_sample.max_size = max_length; + sample->ops = &dmo_sample_ops; + + TRACE_(quartz)("Created wg_sample %p for IMediaBuffer %p.\n", &sample->wg_sample, media_buffer); + *out = &sample->wg_sample; + return S_OK; +} + void wg_sample_release(struct wg_sample *wg_sample) { struct sample *sample = CONTAINING_RECORD(wg_sample, struct sample, wg_sample); @@ -375,7 +428,7 @@ HRESULT wg_transform_read_quartz(struct wg_transform *transform, struct wg_sampl HRESULT hr; BOOL value; - TRACE_(mfplat)("transform %p, wg_sample %p.\n", transform, wg_sample); + TRACE_(quartz)("transform %p, wg_sample %p.\n", transform, wg_sample); if (FAILED(hr = wg_transform_read_data(transform, wg_sample, NULL))) { @@ -408,3 +461,59 @@ HRESULT wg_transform_read_quartz(struct wg_transform *transform, struct wg_sampl return S_OK; } + +HRESULT wg_transform_push_dmo(struct wg_transform *transform, struct wg_sample *wg_sample, + struct wg_sample_queue *queue, REFERENCE_TIME pts, REFERENCE_TIME duration) +{ + HRESULT hr; + + TRACE_(quartz)("transform %p, wg_sample %p, queue %p, pts %I64u, duration %I64u.\n", + transform, wg_sample, queue, pts, duration); + + wg_sample->pts = pts; + wg_sample->flags |= WG_SAMPLE_FLAG_HAS_PTS; + wg_sample->duration = duration; + wg_sample->flags |= WG_SAMPLE_FLAG_HAS_DURATION; + + wg_sample_queue_begin_append(queue, wg_sample); + hr = wg_transform_push_data(transform, wg_sample); + wg_sample_queue_end_append(queue, wg_sample); + + return hr; +} + +HRESULT wg_transform_read_dmo(struct wg_transform *transform, struct wg_sample *wg_sample, + DWORD *flags, REFERENCE_TIME *pts, REFERENCE_TIME *duration) +{ + struct sample *sample = unsafe_dmo_from_wg_sample(wg_sample); + HRESULT hr; + + TRACE_(quartz)("transform %p, wg_sample %p, flags %p, pts %p, duration %p.\n", + transform, wg_sample, flags, pts, duration); + + if (FAILED(hr = wg_transform_read_data(transform, wg_sample, NULL))) + { + if (hr == MF_E_TRANSFORM_STREAM_CHANGE) + FIXME("Unexpected stream format change!\n"); + return hr; + } + + if (FAILED(hr = IMediaBuffer_SetLength(sample->u.dmo.buffer, wg_sample->size))) + return hr; + + *flags = 0; + if (wg_sample->flags & WG_SAMPLE_FLAG_INCOMPLETE) + *flags |= DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE; + if (wg_sample->flags & WG_SAMPLE_FLAG_HAS_PTS) + { + *pts = wg_sample->pts; + *flags = DMO_OUTPUT_DATA_BUFFERF_TIME; + } + if (wg_sample->flags & WG_SAMPLE_FLAG_HAS_DURATION) + { + *duration = wg_sample->duration; + *flags = DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH; + } + + return S_OK; +} diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 4a0d5f2592e..595d2bb0ace 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -24,6 +24,8 @@ #include "mfobjects.h" #include "mftransform.h" #include "wmcodecdsp.h" +#include "mediaerr.h" +#include "dmort.h" #include "wine/debug.h" #include "wine/heap.h" @@ -58,6 +60,7 @@ struct wma_decoder IMFMediaType *output_type; MFT_OUTPUT_STREAM_INFO output_info; + struct wg_format input_format, output_format; struct wg_transform *wg_transform; struct wg_sample_queue *wg_sample_queue; }; @@ -650,29 +653,133 @@ static HRESULT WINAPI media_object_GetOutputStreamInfo(IMediaObject *iface, DWOR static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index, DMO_MEDIA_TYPE *type) { - FIXME("iface %p, index %lu, type_index %lu, type %p stub!\n", iface, index, type_index, type); - return E_NOTIMPL; + struct wma_decoder *impl = impl_from_IMediaObject(iface); + struct wg_format format = impl->input_format; + + FIXME("iface %p, index %lu, type_index %lu, type %p semi-stub!\n", iface, index, type_index, type); + + if (type_index >= 5) + return VFW_E_NO_TYPES; + + format.major_type = WG_MAJOR_TYPE_AUDIO_WMA; + format.u.audio_wma.version = index + 1; + + if (!amt_from_wg_format((AM_MEDIA_TYPE *)type, &format, false)) + return VFW_E_NO_TYPES; + + return S_OK; } static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD index, DWORD type_index, DMO_MEDIA_TYPE *type) { - FIXME("iface %p, index %lu, type_index %lu, type %p stub!\n", iface, index, type_index, type); - return E_NOTIMPL; + static enum wg_audio_format const audio_formats[] = + { + WG_AUDIO_FORMAT_S16LE, + WG_AUDIO_FORMAT_F32LE, + }; + + struct wma_decoder *impl = impl_from_IMediaObject(iface); + struct wg_format format = impl->output_format; + + FIXME("iface %p, index %lu, type_index %lu, type %p semi-stub!\n", iface, index, type_index, type); + + if (type_index >= ARRAY_SIZE(audio_formats)) + return VFW_E_NO_TYPES; + + format.major_type = WG_MAJOR_TYPE_AUDIO; + format.u.audio.format = audio_formats[index]; + if (!format.u.audio.channels) + { + if (impl->input_format.major_type == WG_MAJOR_TYPE_AUDIO_WMA) + format.u.audio.channels = impl->input_format.u.audio_wma.channels; + if (impl->input_format.major_type == WG_MAJOR_TYPE_AUDIO) + format.u.audio.channels = impl->input_format.u.audio.channels; + } + if (!format.u.audio.rate) + { + if (impl->input_format.major_type == WG_MAJOR_TYPE_AUDIO_WMA) + format.u.audio.rate = impl->input_format.u.audio_wma.rate; + if (impl->input_format.major_type == WG_MAJOR_TYPE_AUDIO) + format.u.audio.rate = impl->input_format.u.audio.rate; + } + + if (!amt_from_wg_format((AM_MEDIA_TYPE *)type, &format, false)) + return VFW_E_NO_TYPES; + + return S_OK; } static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index, const DMO_MEDIA_TYPE *type, DWORD flags) { - FIXME("iface %p, index %lu, type %p, flags %#lx stub!\n", iface, index, type, flags); - return E_NOTIMPL; + struct wma_decoder *impl = impl_from_IMediaObject(iface); + struct wg_format wg_format; + + FIXME("iface %p, index %lu, type %p, flags %#lx semi-stub!\n", iface, index, type, flags); + + if (flags & DMO_SET_TYPEF_CLEAR) + { + memset(&impl->input_format, 0, sizeof(impl->input_format)); + return S_OK; + } + + if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) + return VFW_E_INVALIDMEDIATYPE; + + if (wg_format.major_type != WG_MAJOR_TYPE_AUDIO) + return VFW_E_INVALIDMEDIATYPE; + if (!(flags & DMO_SET_TYPEF_TEST_ONLY)) + { + impl->input_format = wg_format; + if (!impl->output_format.major_type) + return S_OK; + + if (impl->wg_transform) + wg_transform_destroy(impl->wg_transform); + impl->wg_transform = NULL; + + if (!(impl->wg_transform = wg_transform_create(&impl->input_format, &impl->output_format))) + return E_FAIL; + } + + return S_OK; } static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD index, const DMO_MEDIA_TYPE *type, DWORD flags) { - FIXME("iface %p, index %lu, type %p, flags %#lx stub!\n", iface, index, type, flags); - return E_NOTIMPL; + struct wma_decoder *impl = impl_from_IMediaObject(iface); + struct wg_format wg_format; + + FIXME("iface %p, index %lu, type %p, flags %#lx semi-stub!\n", iface, index, type, flags); + + if (flags & DMO_SET_TYPEF_CLEAR) + { + memset(&impl->output_format, 0, sizeof(impl->output_format)); + return S_OK; + } + + if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) + return VFW_E_INVALIDMEDIATYPE; + + if (wg_format.major_type != WG_MAJOR_TYPE_AUDIO) + return VFW_E_INVALIDMEDIATYPE; + if (!(flags & DMO_SET_TYPEF_TEST_ONLY)) + { + impl->output_format = wg_format; + if (!impl->input_format.major_type) + return S_OK; + + if (impl->wg_transform) + wg_transform_destroy(impl->wg_transform); + impl->wg_transform = NULL; + + if (!(impl->wg_transform = wg_transform_create(&impl->input_format, &impl->output_format))) + return E_FAIL; + } + + return S_OK; } static HRESULT WINAPI media_object_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) @@ -697,8 +804,14 @@ static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD i static HRESULT WINAPI media_object_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment) { - FIXME("iface %p, index %lu, size %p, alignment %p stub!\n", iface, index, size, alignment); - return E_NOTIMPL; + struct wma_decoder *impl = impl_from_IMediaObject(iface); + + TRACE("iface %p, index %lu, size %p, alignment %p semi-stub!\n", iface, index, size, alignment); + + *size = impl->output_format.u.audio.rate * impl->output_format.u.audio.channels * 16; + *alignment = 1; + + return S_OK; } static HRESULT WINAPI media_object_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency) @@ -715,14 +828,14 @@ static HRESULT WINAPI media_object_SetInputMaxLatency(IMediaObject *iface, DWORD static HRESULT WINAPI media_object_Flush(IMediaObject *iface) { - FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; + TRACE("iface %p.\n", iface); + return S_OK; } static HRESULT WINAPI media_object_Discontinuity(IMediaObject *iface, DWORD index) { - FIXME("iface %p, index %lu stub!\n", iface, index); - return E_NOTIMPL; + FIXME("iface %p, index %lu semi-stub!\n", iface, index); + return S_OK; } static HRESULT WINAPI media_object_AllocateStreamingResources(IMediaObject *iface) @@ -746,16 +859,49 @@ static HRESULT WINAPI media_object_GetInputStatus(IMediaObject *iface, DWORD ind static HRESULT WINAPI media_object_ProcessInput(IMediaObject *iface, DWORD index, IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength) { - FIXME("iface %p, index %lu, buffer %p, flags %#lx, timestamp %s, timelength %s stub!\n", iface, + struct wma_decoder *impl = impl_from_IMediaObject(iface); + struct wg_sample *wg_sample; + HRESULT hr; + + TRACE("iface %p, index %lu, buffer %p, flags %#lx, timestamp %s, timelength %s.\n", iface, index, buffer, flags, wine_dbgstr_longlong(timestamp), wine_dbgstr_longlong(timelength)); - return E_NOTIMPL; + + if (!impl->wg_transform) + return DMO_E_NOTACCEPTING; + + if (FAILED(hr = wg_sample_create_dmo(buffer, &wg_sample))) + return hr; + + return wg_transform_push_dmo(impl->wg_transform, wg_sample, impl->wg_sample_queue, timestamp, timelength); } static HRESULT WINAPI media_object_ProcessOutput(IMediaObject *iface, DWORD flags, DWORD count, DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status) { - FIXME("iface %p, flags %#lx, count %lu, buffers %p, status %p stub!\n", iface, flags, count, buffers, status); - return E_NOTIMPL; + struct wma_decoder *impl = impl_from_IMediaObject(iface); + struct wg_sample *wg_sample; + HRESULT hr; + + TRACE("iface %p, flags %#lx, count %lu, buffers %p, status %p.\n", iface, flags, count, buffers, status); + + if (!impl->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + *status = 0; + buffers[0].dwStatus = 0; + if (!buffers[0].pBuffer) + return DMO_E_NO_MORE_ITEMS; + + if (FAILED(hr = wg_sample_create_dmo(buffers[0].pBuffer, &wg_sample))) + return hr; + + if (SUCCEEDED(hr = wg_transform_read_dmo(impl->wg_transform, wg_sample, + &buffers[0].dwStatus, &buffers[0].rtTimestamp, &buffers[0].rtTimelength))) + wg_sample_queue_flush(impl->wg_sample_queue, false); + + wg_sample_release(wg_sample); + + return hr; } static HRESULT WINAPI media_object_Lock(IMediaObject *iface, LONG lock) From 64448264d248d2b488839732f6f5eb31e046d2df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 20 May 2022 21:48:59 +0200 Subject: [PATCH 0131/2777] qasf: Register ASF Reader filter media type. --- dlls/qasf/qasf.rgs | 15 +++++++++++++++ dlls/qasf/version.rc | 3 +++ 2 files changed, 18 insertions(+) create mode 100644 dlls/qasf/qasf.rgs diff --git a/dlls/qasf/qasf.rgs b/dlls/qasf/qasf.rgs new file mode 100644 index 00000000000..de0d3e425ed --- /dev/null +++ b/dlls/qasf/qasf.rgs @@ -0,0 +1,15 @@ +HKCR +{ + NoRemove 'Media Type' + { + '{e436eb83-524f-11ce-9f53-0020af0ba770}' + { + '{6b6d0801-9ada-11d0-a520-00a0d10129c0}' + { + val '0' = s '0,4,,3026b275' + val '1' = s '0,4,,d129e2d6' + val 'Source Filter' = s '{187463a0-5bb7-11d3-acbe-0080c75e246e}' + } + } + } +} diff --git a/dlls/qasf/version.rc b/dlls/qasf/version.rc index dab46194395..70ec03ad6b1 100644 --- a/dlls/qasf/version.rc +++ b/dlls/qasf/version.rc @@ -24,3 +24,6 @@ #define WINE_PRODUCTVERSION_STR "9.0.0.4503" #include "wine/wine_common_ver.rc" + +/* @makedep: qasf.rgs */ +1 WINE_REGISTRY qasf.rgs From d4d0fd2d65d06e657a91f995f4d35896a6805be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Aug 2022 11:26:09 +0200 Subject: [PATCH 0132/2777] qasf: Keep calling DMO ProcessOutput until error is returned. CW-Bug-Id: #18799 CW-Bug-Id: #18994 CW-Bug-Id: #20182 CW-Bug-Id: #20905 --- dlls/qasf/dmowrapper.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/dlls/qasf/dmowrapper.c b/dlls/qasf/dmowrapper.c index 95e12e860ae..8b484d9b25a 100644 --- a/dlls/qasf/dmowrapper.c +++ b/dlls/qasf/dmowrapper.c @@ -206,7 +206,6 @@ static HRESULT process_output(struct dmo_wrapper *filter, IMediaObject *dmo) { DMO_OUTPUT_DATA_BUFFER *buffers = filter->buffers; DWORD status, i; - BOOL more_data; HRESULT hr; for (i = 0; i < filter->source_count; ++i) @@ -228,8 +227,6 @@ static HRESULT process_output(struct dmo_wrapper *filter, IMediaObject *dmo) do { - more_data = FALSE; - hr = IMediaObject_ProcessOutput(dmo, DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER, filter->source_count, buffers, &status); if (hr != S_OK) @@ -242,9 +239,6 @@ static HRESULT process_output(struct dmo_wrapper *filter, IMediaObject *dmo) if (!buffers[i].pBuffer) continue; - if (buffers[i].dwStatus & DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE) - more_data = TRUE; - if (buffers[i].dwStatus & DMO_OUTPUT_DATA_BUFFERF_TIME) { if (buffers[i].dwStatus & DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH) @@ -270,7 +264,7 @@ static HRESULT process_output(struct dmo_wrapper *filter, IMediaObject *dmo) } } - } while (more_data); + } while (1); out: for (i = 0; i < filter->source_count; ++i) From 5d6d08bc7abd8283527e6b6e47797c12447311a3 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Thu, 14 Apr 2022 16:58:33 -0400 Subject: [PATCH 0133/2777] mfplat: Add MFVideoFormat_ABGR32 format information. Signed-off-by: Derek Lesho --- dlls/mfplat/mediatype.c | 4 ++++ dlls/winegstreamer/mfplat.c | 2 ++ dlls/winegstreamer/quartz_parser.c | 8 ++++++++ dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_format.c | 3 +++ dlls/winegstreamer/wg_parser.c | 1 + 6 files changed, 19 insertions(+) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index c1c8d0048c3..eca397ef067 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -29,6 +29,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32, D3DFMT_A8B8G8R8); DEFINE_MEDIATYPE_GUID(MFVideoFormat_IMC1, MAKEFOURCC('I','M','C','1')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_IMC2, MAKEFOURCC('I','M','C','2')); DEFINE_MEDIATYPE_GUID(MFVideoFormat_IMC3, MAKEFOURCC('I','M','C','3')); @@ -2637,6 +2638,7 @@ static const struct uncompressed_video_format video_formats[] = { &MFVideoFormat_RGB565, 2, 3, 1, 0 }, { &MFVideoFormat_RGB555, 2, 3, 1, 0 }, { &MFVideoFormat_A2R10G10B10, 4, 3, 1, 0 }, + { &MFVideoFormat_ABGR32, 4, 3, 1, 0 }, { &MFVideoFormat_RGB8, 1, 3, 1, 0 }, { &MFVideoFormat_L8, 1, 3, 1, 0 }, { &MFVideoFormat_AYUV, 4, 3, 0, 1 }, @@ -3509,6 +3511,8 @@ DXGI_FORMAT WINAPI MFMapDX9FormatToDXGIFormat(DWORD format) return DXGI_FORMAT_P8; case D3DFMT_A8P8: return DXGI_FORMAT_A8P8; + case D3DFMT_A8B8G8R8: + return DXGI_FORMAT_R8G8B8A8_UNORM; default: return DXGI_FORMAT_UNKNOWN; } diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 86e794d0d37..6facd9d57d2 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -36,6 +36,7 @@ DEFINE_GUID(DMOVideoFormat_RGB24,D3DFMT_R8G8B8,0x524f,0x11ce,0x9f,0x53,0x00,0x20 DEFINE_GUID(DMOVideoFormat_RGB565,D3DFMT_R5G6B5,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); DEFINE_GUID(DMOVideoFormat_RGB555,D3DFMT_X1R5G5B5,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); DEFINE_GUID(DMOVideoFormat_RGB8,D3DFMT_P8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32,D3DFMT_A8B8G8R8); DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC,WAVE_FORMAT_RAW_AAC1); DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); @@ -441,6 +442,7 @@ video_formats[] = {&MFVideoFormat_ARGB32, WG_VIDEO_FORMAT_BGRA}, {&MFVideoFormat_RGB32, WG_VIDEO_FORMAT_BGRx}, {&MFVideoFormat_RGB24, WG_VIDEO_FORMAT_BGR}, + {&MFVideoFormat_ABGR32, WG_VIDEO_FORMAT_RGBA}, {&MFVideoFormat_RGB555, WG_VIDEO_FORMAT_RGB15}, {&MFVideoFormat_RGB565, WG_VIDEO_FORMAT_RGB16}, {&MFVideoFormat_AYUV, WG_VIDEO_FORMAT_AYUV}, diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 9a6573cd1f0..b73f7634b1e 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -29,6 +29,8 @@ #include "dvdmedia.h" #include "mmreg.h" #include "ks.h" +#include "mfapi.h" +#include "d3d9types.h" #include "wmcodecdsp.h" #include "initguid.h" #include "ksmedia.h" @@ -39,6 +41,7 @@ static const GUID MEDIASUBTYPE_CVID = {mmioFOURCC('c','v','i','d'), 0x0000, 0x00 static const GUID MEDIASUBTYPE_VC1S = {mmioFOURCC('V','C','1','S'), 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; static const GUID MEDIASUBTYPE_MP3 = {WAVE_FORMAT_MPEGLAYER3, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; static const GUID MEDIASUBTYPE_WMV_Unknown = {0x7ce12ca9, 0xbfbf, 0x43d9, {0x9d, 0x00, 0x82, 0xb8, 0xed, 0x54, 0x31, 0x6b}}; +extern const GUID MFVideoFormat_ABGR32; struct parser { @@ -340,6 +343,7 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) { case WG_VIDEO_FORMAT_BGRA: case WG_VIDEO_FORMAT_BGRx: + case WG_VIDEO_FORMAT_RGBA: case WG_VIDEO_FORMAT_AYUV: return width * height * 4; @@ -445,6 +449,7 @@ static const GUID *wg_video_format_get_mediasubtype(enum wg_video_format format) case WG_VIDEO_FORMAT_BGRA: return &MEDIASUBTYPE_ARGB32; case WG_VIDEO_FORMAT_BGRx: return &MEDIASUBTYPE_RGB32; case WG_VIDEO_FORMAT_BGR: return &MEDIASUBTYPE_RGB24; + case WG_VIDEO_FORMAT_RGBA: return &MFVideoFormat_ABGR32; case WG_VIDEO_FORMAT_RGB15: return &MEDIASUBTYPE_RGB555; case WG_VIDEO_FORMAT_RGB16: return &MEDIASUBTYPE_RGB565; case WG_VIDEO_FORMAT_AYUV: return &MEDIASUBTYPE_AYUV; @@ -468,6 +473,7 @@ static DWORD wg_video_format_get_compression(enum wg_video_format format) case WG_VIDEO_FORMAT_BGRA: return BI_RGB; case WG_VIDEO_FORMAT_BGRx: return BI_RGB; case WG_VIDEO_FORMAT_BGR: return BI_RGB; + case WG_VIDEO_FORMAT_RGBA: return BI_RGB; case WG_VIDEO_FORMAT_RGB15: return BI_RGB; case WG_VIDEO_FORMAT_RGB16: return BI_BITFIELDS; case WG_VIDEO_FORMAT_AYUV: return mmioFOURCC('A','Y','U','V'); @@ -491,6 +497,7 @@ static WORD wg_video_format_get_depth(enum wg_video_format format) case WG_VIDEO_FORMAT_BGRA: return 32; case WG_VIDEO_FORMAT_BGRx: return 32; case WG_VIDEO_FORMAT_BGR: return 24; + case WG_VIDEO_FORMAT_RGBA: return 32; case WG_VIDEO_FORMAT_RGB15: return 16; case WG_VIDEO_FORMAT_RGB16: return 16; case WG_VIDEO_FORMAT_AYUV: return 32; @@ -773,6 +780,7 @@ static bool amt_to_wg_format_video(const AM_MEDIA_TYPE *mt, struct wg_format *fo {&MEDIASUBTYPE_ARGB32, WG_VIDEO_FORMAT_BGRA}, {&MEDIASUBTYPE_RGB32, WG_VIDEO_FORMAT_BGRx}, {&MEDIASUBTYPE_RGB24, WG_VIDEO_FORMAT_BGR}, + {&MFVideoFormat_ABGR32, WG_VIDEO_FORMAT_RGBA}, {&MEDIASUBTYPE_RGB555, WG_VIDEO_FORMAT_RGB15}, {&MEDIASUBTYPE_RGB565, WG_VIDEO_FORMAT_RGB16}, {&MEDIASUBTYPE_AYUV, WG_VIDEO_FORMAT_AYUV}, diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index d8209a80b08..c2c429882e5 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -98,6 +98,7 @@ struct wg_format WG_VIDEO_FORMAT_BGRA, WG_VIDEO_FORMAT_BGRx, WG_VIDEO_FORMAT_BGR, + WG_VIDEO_FORMAT_RGBA, WG_VIDEO_FORMAT_RGB15, WG_VIDEO_FORMAT_RGB16, diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index a7876977d6c..8fd8dc6592b 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -144,6 +144,8 @@ static enum wg_video_format wg_video_format_from_gst(GstVideoFormat format) return WG_VIDEO_FORMAT_BGRx; case GST_VIDEO_FORMAT_BGR: return WG_VIDEO_FORMAT_BGR; + case GST_VIDEO_FORMAT_RGBA: + return WG_VIDEO_FORMAT_RGBA; case GST_VIDEO_FORMAT_RGB15: return WG_VIDEO_FORMAT_RGB15; case GST_VIDEO_FORMAT_RGB16: @@ -398,6 +400,7 @@ static GstVideoFormat wg_video_format_to_gst(enum wg_video_format format) case WG_VIDEO_FORMAT_BGRA: return GST_VIDEO_FORMAT_BGRA; case WG_VIDEO_FORMAT_BGRx: return GST_VIDEO_FORMAT_BGRx; case WG_VIDEO_FORMAT_BGR: return GST_VIDEO_FORMAT_BGR; + case WG_VIDEO_FORMAT_RGBA: return GST_VIDEO_FORMAT_RGBA; case WG_VIDEO_FORMAT_RGB15: return GST_VIDEO_FORMAT_RGB15; case WG_VIDEO_FORMAT_RGB16: return GST_VIDEO_FORMAT_RGB16; case WG_VIDEO_FORMAT_AYUV: return GST_VIDEO_FORMAT_AYUV; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 86a8c4100f1..e3ec5687679 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -237,6 +237,7 @@ static NTSTATUS wg_parser_stream_enable(void *args) case WG_VIDEO_FORMAT_BGRA: case WG_VIDEO_FORMAT_BGRx: case WG_VIDEO_FORMAT_BGR: + case WG_VIDEO_FORMAT_RGBA: case WG_VIDEO_FORMAT_RGB15: case WG_VIDEO_FORMAT_RGB16: flip = !flip; From 08929931ec120b7370696dca5943b2da64b4cd7e Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Thu, 14 Apr 2022 17:02:03 -0400 Subject: [PATCH 0134/2777] winegstreamer: Add MFVideoFormat_ABGR32 media type to media source video stream descriptor. Signed-off-by: Derek Lesho --- dlls/winegstreamer/media_source.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 37d38e1fef8..d3e129da8c3 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -27,6 +27,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); +extern const GUID MFVideoFormat_ABGR32; + struct media_stream { IMFMediaStream IMFMediaStream_iface; @@ -856,7 +858,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[8]; + IMFMediaType *stream_types[9]; struct wg_format format; DWORD type_count = 0; HRESULT hr = S_OK; @@ -877,6 +879,7 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) &MFVideoFormat_I420, &MFVideoFormat_ARGB32, &MFVideoFormat_RGB32, + &MFVideoFormat_ABGR32, }; IMFMediaType *base_type = mf_media_type_from_wg_format(&format); From ab7bba8affa3f99c71daa70a202b526a91bff806 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 15 Jul 2022 15:12:52 -0400 Subject: [PATCH 0135/2777] winegstreamer: Add MF_MT_VIDEO_NOMINAL_RANGE attribute to base video output type. --- dlls/winegstreamer/media_source.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index d3e129da8c3..3b59534d67e 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -891,6 +891,8 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) goto done; } + IMFMediaType_SetUINT32(base_type, &MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_Normal); + IMFMediaType_GetGUID(base_type, &MF_MT_SUBTYPE, &base_subtype); stream_types[0] = base_type; From 6db597ccd342eeb9d1e389bbeb7c9111dbc7b828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 Aug 2022 10:50:35 +0200 Subject: [PATCH 0136/2777] HACK: winegstreamer: Allow WMA decoder DMO to pass-through buffers. CW-Bug-Id: #18799 CW-Bug-Id: #18994 CW-Bug-Id: #20182 CW-Bug-Id: #20905 --- dlls/winegstreamer/wma_decoder.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 595d2bb0ace..fcfbd00b777 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -727,7 +727,8 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) return VFW_E_INVALIDMEDIATYPE; - if (wg_format.major_type != WG_MAJOR_TYPE_AUDIO) + if (wg_format.major_type != WG_MAJOR_TYPE_AUDIO_WMA + && wg_format.major_type != WG_MAJOR_TYPE_AUDIO) return VFW_E_INVALIDMEDIATYPE; if (!(flags & DMO_SET_TYPEF_TEST_ONLY)) { From 7a5472e6f3e2f7338428c21fdea87eaa467cde4b Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 21 Oct 2020 16:03:21 -0500 Subject: [PATCH 0137/2777] HACK: winegstreamer: Allow videoconvert to parallelize. Not sure if this should be called a hack. It's not the *best* solution to the problem, but it's not a wrong one either. Signed-off-by: Zebediah Figura Wine-Staging: mfplat-streaming-support --- dlls/winegstreamer/wg_parser.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index e3ec5687679..fe4c04f2d78 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -915,6 +915,9 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) || !append_element(GST_BIN(parser->container), element, &first, &last)) goto out; + /* Let GStreamer choose a default number of threads. */ + gst_util_set_object_arg(G_OBJECT(element), "n-threads", "0"); + /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */ if (!(element = create_element("videoflip", "base")) || !append_element(GST_BIN(parser->container), element, &first, &last)) From 94d91c0531c1bb59181e38c62cff37f514ea218f Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 10 Aug 2022 19:11:51 +0200 Subject: [PATCH 0138/2777] HACK: winegstreamer: Use capssetter to ignore non-default YUV color spaces. --- dlls/winegstreamer/wg_parser.c | 43 ++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index fe4c04f2d78..f00bff39a73 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -902,6 +902,49 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) } else if (!strcmp(name, "video/x-raw")) { + /* Hack?: Flatten down the colorimetry to default values, without + * actually modifying the video at all. + * + * We want to do color matrix conversions when converting from YUV to + * RGB or vice versa. We do *not* want to do color matrix conversions + * when converting YUV <-> YUV or RGB <-> RGB, because these are slow + * (it essentially means always using the slow path, never going through + * liborc). However, we have two videoconvert elements, and it's + * basically impossible to know what conversions each is going to do + * until caps are negotiated (without depending on some implementation + * details, and even then it'snot exactly trivial). And setting + * matrix-mode after caps are negotiated has no effect. + * + * Nor can we just retain colorimetry information the way we retain + * other caps values, because videoconvert automatically clears it if + * not doing passthrough. I think that this would only happen if we have + * to do a double conversion, but that is possible. Not likely, but I + * don't want to have to be the one to find out that there's still a + * game broken. + * + * [Note that we'd actually kind of like to retain colorimetry + * information, just in case it does ever become relevant to pass that + * on to the next DirectShow filter. Hence I think the correct solution + * for upstream is to get videoconvert to Not Do That.] + * + * So as a fallback solution, we force an identity transformation of + * the caps to those with a "default" color matrix—i.e. transform the + * caps, but not the data. We do this by *pre*pending a capssetter to + * the front of the chain, and we remove the matrix-mode setting for the + * videoconvert elements. + */ + if (!(element = create_element("capssetter", "good")) + || !append_element(GST_BIN(parser->container), element, &first, &last)) + goto out; + gst_util_set_object_arg(G_OBJECT(element), "join", "true"); + /* Actually, this is invalid, but it causes videoconvert to use default + * colorimetry as a result. Yes, this is depending on undocumented + * implementation details. It's a hack. + * + * Sadly there doesn't seem to be a way to get capssetter to clear + * certain fields while leaving others untouched. */ + gst_util_set_object_arg(G_OBJECT(element), "caps", "video/x-raw,colorimetry=0:0:0:0"); + /* DirectShow can express interlaced video, but downstream filters can't * necessarily consume it. In particular, the video renderer can't. */ if (!(element = create_element("deinterlace", "good")) From 4f83f6d48faad1df1f9ba5208e1c170c4fce68d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 11 Nov 2022 13:59:53 +0100 Subject: [PATCH 0139/2777] HACK: winegstreamer: Support XMAudio2 input format in WMA decoder. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 CW-Bug-Id: #16839 CW-Bug-Id: #18678 CW-Bug-Id: #19362 Wine-Staging: mfplat-streaming-support --- dlls/winegstreamer/mfplat.c | 13 +++++++++++-- dlls/winegstreamer/quartz_parser.c | 19 ++++++++++++++----- dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_format.c | 18 ++++++++++++++---- dlls/winegstreamer/wma_decoder.c | 9 +++++++++ 5 files changed, 49 insertions(+), 11 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 6facd9d57d2..d8c5292e2d4 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -36,8 +36,9 @@ DEFINE_GUID(DMOVideoFormat_RGB24,D3DFMT_R8G8B8,0x524f,0x11ce,0x9f,0x53,0x00,0x20 DEFINE_GUID(DMOVideoFormat_RGB565,D3DFMT_R5G6B5,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); DEFINE_GUID(DMOVideoFormat_RGB555,D3DFMT_X1R5G5B5,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); DEFINE_GUID(DMOVideoFormat_RGB8,D3DFMT_P8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); -DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32,D3DFMT_A8B8G8R8); DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC,WAVE_FORMAT_RAW_AAC1); +DEFINE_MEDIATYPE_GUID(MFAudioFormat_XMAudio2, 0x0166); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32,D3DFMT_A8B8G8R8); DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); extern GUID MEDIASUBTYPE_VC1S; @@ -721,6 +722,7 @@ static void mf_media_type_to_wg_format_audio_wma(IMFMediaType *type, const GUID { UINT32 rate, depth, channels, block_align, bytes_per_second, codec_data_len; BYTE codec_data[64]; + bool is_xma = false; UINT32 version; if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate))) @@ -762,6 +764,11 @@ static void mf_media_type_to_wg_format_audio_wma(IMFMediaType *type, const GUID version = 3; else if (IsEqualGUID(subtype, &MFAudioFormat_WMAudio_Lossless)) version = 4; + else if (IsEqualGUID(subtype, &MFAudioFormat_XMAudio2)) + { + version = 2; + is_xma = true; + } else { assert(0); @@ -777,6 +784,7 @@ static void mf_media_type_to_wg_format_audio_wma(IMFMediaType *type, const GUID format->u.audio_wma.block_align = block_align; format->u.audio_wma.codec_data_len = codec_data_len; memcpy(format->u.audio_wma.codec_data, codec_data, codec_data_len); + format->u.audio_wma.is_xma = is_xma; } static void mf_media_type_to_wg_format_video_h264(IMFMediaType *type, struct wg_format *format) @@ -874,7 +882,8 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) if (IsEqualGUID(&subtype, &MEDIASUBTYPE_MSAUDIO1) || IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV8) || IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV9) || - IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless)) + IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless) || + IsEqualGUID(&subtype, &MFAudioFormat_XMAudio2)) mf_media_type_to_wg_format_audio_wma(type, &subtype, format); else if (IsEqualGUID(&subtype, &MFAudioFormat_AAC)) mf_media_type_to_wg_format_audio_mpeg4(type, format); diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index b73f7634b1e..86e98f5778b 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -41,6 +41,7 @@ static const GUID MEDIASUBTYPE_CVID = {mmioFOURCC('c','v','i','d'), 0x0000, 0x00 static const GUID MEDIASUBTYPE_VC1S = {mmioFOURCC('V','C','1','S'), 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; static const GUID MEDIASUBTYPE_MP3 = {WAVE_FORMAT_MPEGLAYER3, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; static const GUID MEDIASUBTYPE_WMV_Unknown = {0x7ce12ca9, 0xbfbf, 0x43d9, {0x9d, 0x00, 0x82, 0xb8, 0xed, 0x54, 0x31, 0x6b}}; +static const GUID MEDIASUBTYPE_XMAUDIO2 = {0x0166, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; extern const GUID MFVideoFormat_ABGR32; struct parser @@ -305,6 +306,11 @@ static bool amt_from_wg_format_wma(AM_MEDIA_TYPE *mt, const struct wg_format *fo case 2: mt->subtype = MEDIASUBTYPE_WMAUDIO2; wave_format->wFormatTag = WAVE_FORMAT_WMAUDIO2; + if (format->u.audio_wma.is_xma) + { + mt->subtype = MEDIASUBTYPE_XMAUDIO2; + wave_format->wFormatTag = 0x0166; + } break; case 3: mt->subtype = MEDIASUBTYPE_WMAUDIO3; @@ -741,7 +747,7 @@ static bool amt_to_wg_format_audio_mpeg1_layer3(const AM_MEDIA_TYPE *mt, struct } static bool amt_to_wg_format_audio_wma(const AM_MEDIA_TYPE *mt, struct wg_format *format, - uint32_t version) + uint32_t version, bool is_xma) { const WAVEFORMATEX *audio_format = (const WAVEFORMATEX *)mt->pbFormat; @@ -758,6 +764,7 @@ static bool amt_to_wg_format_audio_wma(const AM_MEDIA_TYPE *mt, struct wg_format format->major_type = WG_MAJOR_TYPE_AUDIO_WMA; format->u.audio_wma.version = version; + format->u.audio_wma.is_xma = is_xma; format->u.audio_wma.channels = audio_format->nChannels; format->u.audio_wma.depth = audio_format->wBitsPerSample; format->u.audio_wma.block_align = audio_format->nBlockAlign; @@ -881,13 +888,15 @@ bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format) if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MP3)) return amt_to_wg_format_audio_mpeg1_layer3(mt, format); if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MSAUDIO1)) - return amt_to_wg_format_audio_wma(mt, format, 1); + return amt_to_wg_format_audio_wma(mt, format, 1, false); if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO2)) - return amt_to_wg_format_audio_wma(mt, format, 2); + return amt_to_wg_format_audio_wma(mt, format, 2, false); if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO3)) - return amt_to_wg_format_audio_wma(mt, format, 3); + return amt_to_wg_format_audio_wma(mt, format, 3, false); if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMAUDIO_LOSSLESS)) - return amt_to_wg_format_audio_wma(mt, format, 4); + return amt_to_wg_format_audio_wma(mt, format, 4, false); + if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_XMAUDIO2)) + return amt_to_wg_format_audio_wma(mt, format, 2, true); return amt_to_wg_format_audio(mt, format); } diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index c2c429882e5..328bc7a48fb 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -87,6 +87,7 @@ struct wg_format uint32_t block_align; uint32_t codec_data_len; unsigned char codec_data[64]; + bool is_xma; } audio_wma; struct diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 8fd8dc6592b..18dde324f8c 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -462,10 +462,20 @@ static GstCaps *wg_format_to_caps_audio_wma(const struct wg_format *format) GstBuffer *buffer; GstCaps *caps; - if (!(caps = gst_caps_new_empty_simple("audio/x-wma"))) - return NULL; - if (format->u.audio_wma.version) - gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.audio_wma.version, NULL); + if (format->u.audio_wma.is_xma) + { + if (!(caps = gst_caps_new_empty_simple("audio/x-xma"))) + return NULL; + if (format->u.audio_wma.version) + gst_caps_set_simple(caps, "xmaversion", G_TYPE_INT, format->u.audio_wma.version, NULL); + } + else + { + if (!(caps = gst_caps_new_empty_simple("audio/x-wma"))) + return NULL; + if (format->u.audio_wma.version) + gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.audio_wma.version, NULL); + } if (format->u.audio_wma.bitrate) gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->u.audio_wma.bitrate, NULL); diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index fcfbd00b777..10a41a0c92f 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -33,12 +33,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(wmadec); WINE_DECLARE_DEBUG_CHANNEL(winediag); +extern const GUID MFAudioFormat_XMAudio2; + static const GUID *const wma_decoder_input_types[] = { &MEDIASUBTYPE_MSAUDIO1, &MFAudioFormat_WMAudioV8, &MFAudioFormat_WMAudioV9, &MFAudioFormat_WMAudio_Lossless, + &MFAudioFormat_XMAudio2, }; static const GUID *const wma_decoder_output_types[] = { @@ -663,6 +666,12 @@ static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index format.major_type = WG_MAJOR_TYPE_AUDIO_WMA; format.u.audio_wma.version = index + 1; + format.u.audio_wma.is_xma = 0; + if (index == 4) + { + format.u.audio_wma.version = 2; + format.u.audio_wma.is_xma = 1; + } if (!amt_from_wg_format((AM_MEDIA_TYPE *)type, &format, false)) return VFW_E_NO_TYPES; From 08c868d9c4667b2b334d71d5230cfec8e79cffd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 26 Feb 2022 18:05:48 +0100 Subject: [PATCH 0140/2777] HACK: winegstreamer: Fake H264 timestamps if framerate cannot be trusted. Fixes MK11 video framerate. 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 | 18 +++++++++++++++++- dlls/winegstreamer/wg_transform.c | 9 +++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index ead00e20840..5e58dd4dc83 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -58,6 +58,8 @@ struct h264_decoder IMFMediaType *output_type; MFT_OUTPUT_STREAM_INFO output_info; + UINT64 last_pts; + struct wg_format wg_format; struct wg_transform *wg_transform; struct wg_sample_queue *wg_sample_queue; @@ -73,6 +75,7 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) struct wg_format input_format; struct wg_format output_format; + decoder->last_pts = 0; if (decoder->wg_transform) wg_transform_destroy(decoder->wg_transform); decoder->wg_transform = NULL; @@ -592,9 +595,10 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { struct h264_decoder *decoder = impl_from_IMFTransform(iface); + UINT64 frame_rate, duration; struct wg_format wg_format; UINT32 sample_size; - UINT64 frame_rate; + LONGLONG time; GUID subtype; HRESULT hr; @@ -618,8 +622,20 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample, sample_size, &wg_format, &samples->dwStatus))) + { wg_sample_queue_flush(decoder->wg_sample_queue, false); + if (FAILED(IMFSample_GetSampleTime(samples->pSample, &time)) + || FAILED(IMFSample_GetSampleDuration(samples->pSample, &time))) + { + frame_rate = (UINT64)decoder->wg_format.u.video.fps_n << 32 | decoder->wg_format.u.video.fps_d; + duration = (UINT64)10000000 * (UINT32)frame_rate / (frame_rate >> 32); + IMFSample_SetSampleTime(samples->pSample, decoder->last_pts); + IMFSample_SetSampleDuration(samples->pSample, duration); + decoder->last_pts += duration; + } + } + if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { decoder->wg_format = wg_format; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index b711934bf63..04cb85c629d 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -62,6 +62,7 @@ struct wg_transform GstSample *output_sample; bool output_caps_changed; GstCaps *output_caps; + bool broken_timestamps; }; static bool is_caps_video(GstCaps *caps) @@ -419,9 +420,10 @@ NTSTATUS wg_transform_create(void *args) */ transform->input_max_length = 16; transform->output_plane_align = 15; - if (!(element = create_element("h264parse", "base")) - || !append_element(GST_BIN(transform->container), element, &first, &last)) + if ((element = create_element("h264parse", "base")) + && !append_element(GST_BIN(transform->container), element, &first, &last)) goto out; + transform->broken_timestamps = !element; /* fallthrough */ case WG_MAJOR_TYPE_AUDIO_MPEG1: case WG_MAJOR_TYPE_AUDIO_MPEG4: @@ -928,6 +930,9 @@ NTSTATUS wg_transform_read_data(void *args) transform->output_sample = NULL; } + if (transform->broken_timestamps) + sample->flags &= ~(WG_SAMPLE_FLAG_HAS_PTS|WG_SAMPLE_FLAG_HAS_DURATION); + params->result = S_OK; wg_allocator_release_sample(transform->allocator, sample, discard_data); return STATUS_SUCCESS; From 7e612b8820e3082ea7a92c9500cfe843ec99bae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Feb 2022 21:31:55 +0100 Subject: [PATCH 0141/2777] HACK: winegstreamer: Check if the decoder accepted our caps. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 CW-Bug-Id: #19854 CW-Bug-Id: #20966 --- dlls/winegstreamer/wg_transform.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 04cb85c629d..0e4e6d998b4 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -513,6 +513,10 @@ NTSTATUS wg_transform_create(void *args) || !gst_pad_push_event(transform->my_src, event)) goto out; + /* Check that the caps event have been accepted */ + if (input_format.major_type == WG_MAJOR_TYPE_VIDEO_H264 && !gst_pad_has_current_caps(transform->their_sink)) + goto out; + /* We need to use GST_FORMAT_TIME here because it's the only format * some elements such avdec_wmav2 correctly support. */ gst_segment_init(&transform->segment, GST_FORMAT_TIME); From 15ea7dbd36647d8f3e52abf8938aba02d91704c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 12 May 2022 22:03:43 +0200 Subject: [PATCH 0142/2777] HACK: winegstreamer: Implement WMVDecMediaObject pass-through DMO. CW-Bug-Id: #18799 CW-Bug-Id: #18994 CW-Bug-Id: #20182 --- dlls/winegstreamer/wmv_decoder.c | 195 ++++++++++++++++++++++++------- 1 file changed, 155 insertions(+), 40 deletions(-) diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index 1b03d9aa639..b81639f312a 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -19,10 +19,12 @@ #include "mfapi.h" #include "mferror.h" -#include "mediaerr.h" #include "mfobjects.h" #include "mftransform.h" #include "wmcodecdsp.h" +#include "mediaerr.h" +#include "dmort.h" + #include "initguid.h" #include "wine/debug.h" @@ -46,6 +48,11 @@ static const GUID *const wmv_decoder_input_types[] = &MFVideoFormat_VC1S, }; +static enum wg_video_format const video_formats[] = +{ + WG_VIDEO_FORMAT_BGRx, +}; + struct wmv_decoder { IUnknown IUnknown_inner; @@ -57,6 +64,8 @@ struct wmv_decoder LONG refcount; struct wg_format input_format; + struct wg_format output_format; + DMO_OUTPUT_DATA_BUFFER output; }; static inline struct wmv_decoder *impl_from_IUnknown(IUnknown *iface) @@ -340,13 +349,8 @@ static ULONG WINAPI media_object_Release(IMediaObject *iface) static HRESULT WINAPI media_object_GetStreamCount(IMediaObject *iface, DWORD *input, DWORD *output) { - TRACE("iface %p, input %p, output %p.\n", iface, input, output); - - if (!input || !output) - return E_POINTER; - + FIXME("iface %p, input %p, output %p semi-stub!\n", iface, input, output); *input = *output = 1; - return S_OK; } @@ -365,21 +369,27 @@ static HRESULT WINAPI media_object_GetOutputStreamInfo(IMediaObject *iface, DWOR static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index, DMO_MEDIA_TYPE *type) { - TRACE("iface %p, index %lu, type_index %lu, type %p.\n", iface, index, type_index, type); + struct wmv_decoder *impl = impl_from_IMediaObject(iface); + struct wg_format format = impl->input_format; - if (index > 0) - return DMO_E_INVALIDSTREAMINDEX; - if (type_index >= ARRAY_SIZE(wmv_decoder_input_types)) - return DMO_E_NO_MORE_ITEMS; - if (!type) - return S_OK; + FIXME("iface %p, index %lu, type_index %lu, type %p semi-stub!\n", iface, index, type_index, type); + + if (type_index >= ARRAY_SIZE(video_formats)) + return VFW_E_NO_TYPES; + + format.major_type = WG_MAJOR_TYPE_VIDEO; + format.u.video.format = video_formats[index]; + if (!format.u.video.width) + format.u.video.width = 1920; + if (!format.u.video.height) + format.u.video.height = 1080; + if (!format.u.video.fps_d) + format.u.video.fps_d = 1; + if (!format.u.video.fps_n) + format.u.video.fps_n = 1; - memset(type, 0, sizeof(*type)); - type->majortype = MFMediaType_Video; - type->subtype = *wmv_decoder_input_types[type_index]; - type->bFixedSizeSamples = FALSE; - type->bTemporalCompression = TRUE; - type->lSampleSize = 0; + if (!amt_from_wg_format((AM_MEDIA_TYPE *)type, &format, false)) + return VFW_E_NO_TYPES; return S_OK; } @@ -387,8 +397,29 @@ static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD index, DWORD type_index, DMO_MEDIA_TYPE *type) { - FIXME("iface %p, index %lu, type_index %lu, type %p stub!\n", iface, index, type_index, type); - return E_NOTIMPL; + struct wmv_decoder *impl = impl_from_IMediaObject(iface); + struct wg_format format = impl->output_format; + + FIXME("iface %p, index %lu, type_index %lu, type %p semi-stub!\n", iface, index, type_index, type); + + if (type_index >= ARRAY_SIZE(video_formats)) + return VFW_E_NO_TYPES; + + format.major_type = WG_MAJOR_TYPE_VIDEO; + format.u.video.format = video_formats[index]; + if (!format.u.video.width) + format.u.video.width = 1920; + if (!format.u.video.height) + format.u.video.height = 1080; + if (!format.u.video.fps_d) + format.u.video.fps_d = 1; + if (!format.u.video.fps_n) + format.u.video.fps_n = 1; + + if (!amt_from_wg_format((AM_MEDIA_TYPE *)type, &format, false)) + return VFW_E_NO_TYPES; + + return S_OK; } static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index, @@ -416,15 +447,18 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) return DMO_E_TYPE_NOT_ACCEPTED; - for (i = 0; i < ARRAY_SIZE(wmv_decoder_input_types); ++i) - if (IsEqualGUID(&type->subtype, wmv_decoder_input_types[i])) - break; - if (i == ARRAY_SIZE(wmv_decoder_input_types)) - return DMO_E_TYPE_NOT_ACCEPTED; - if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) return DMO_E_TYPE_NOT_ACCEPTED; + if (wg_format.major_type != WG_MAJOR_TYPE_VIDEO) + { + for (i = 0; i < ARRAY_SIZE(wmv_decoder_input_types); ++i) + if (IsEqualGUID(&type->subtype, wmv_decoder_input_types[i])) + break; + if (i == ARRAY_SIZE(wmv_decoder_input_types)) + return DMO_E_TYPE_NOT_ACCEPTED; + } + if (!(flags & DMO_SET_TYPEF_TEST_ONLY)) decoder->input_format = wg_format; @@ -434,8 +468,33 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD index, const DMO_MEDIA_TYPE *type, DWORD flags) { - FIXME("iface %p, index %lu, type %p, flags %#lx stub!\n", iface, index, type, flags); - return E_NOTIMPL; + struct wmv_decoder *impl = impl_from_IMediaObject(iface); + struct wg_format wg_format; + DWORD i; + + FIXME("iface %p, index %lu, type %p, flags %#lx semi-stub!\n", iface, index, type, flags); + + if (flags & DMO_SET_TYPEF_CLEAR) + { + memset(&impl->output_format, 0, sizeof(impl->output_format)); + return S_OK; + } + + if (!amt_to_wg_format((const AM_MEDIA_TYPE *)type, &wg_format)) + return VFW_E_INVALIDMEDIATYPE; + + if (wg_format.major_type != WG_MAJOR_TYPE_VIDEO) + return VFW_E_INVALIDMEDIATYPE; + for (i = 0; i < ARRAY_SIZE(video_formats); ++i) + if (wg_format.u.video.format == video_formats[i]) + break; + if (i == ARRAY_SIZE(video_formats)) + return VFW_E_INVALIDMEDIATYPE; + + if (!(flags & DMO_SET_TYPEF_TEST_ONLY)) + impl->output_format = wg_format; + + return S_OK; } static HRESULT WINAPI media_object_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) @@ -460,8 +519,25 @@ static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD i static HRESULT WINAPI media_object_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment) { - FIXME("iface %p, index %lu, size %p, alignment %p stub!\n", iface, index, size, alignment); - return E_NOTIMPL; + struct wmv_decoder *impl = impl_from_IMediaObject(iface); + AM_MEDIA_TYPE mt; + + TRACE("iface %p, index %lu, size %p, alignment %p semi-stub!\n", iface, index, size, alignment); + + if (!amt_from_wg_format(&mt, &impl->output_format, false)) + return VFW_E_INVALIDMEDIATYPE; + + if (!IsEqualGUID(&mt.formattype, &FORMAT_VideoInfo)) + *size = mt.lSampleSize; + else + { + VIDEOINFOHEADER *format = (VIDEOINFOHEADER *)mt.pbFormat; + *size = format->bmiHeader.biSizeImage; + } + FreeMediaType(&mt); + + *alignment = 1; + return S_OK; } static HRESULT WINAPI media_object_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency) @@ -478,14 +554,20 @@ static HRESULT WINAPI media_object_SetInputMaxLatency(IMediaObject *iface, DWORD static HRESULT WINAPI media_object_Flush(IMediaObject *iface) { - FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; + struct wmv_decoder *impl = impl_from_IMediaObject(iface); + + TRACE("iface %p.\n", iface); + + if (impl->output.pBuffer) IMediaBuffer_Release(impl->output.pBuffer); + impl->output.pBuffer = NULL; + + return S_OK; } static HRESULT WINAPI media_object_Discontinuity(IMediaObject *iface, DWORD index) { - FIXME("iface %p, index %lu stub!\n", iface, index); - return E_NOTIMPL; + FIXME("iface %p, index %lu semi-stub!\n", iface, index); + return S_OK; } static HRESULT WINAPI media_object_AllocateStreamingResources(IMediaObject *iface) @@ -509,16 +591,49 @@ static HRESULT WINAPI media_object_GetInputStatus(IMediaObject *iface, DWORD ind static HRESULT WINAPI media_object_ProcessInput(IMediaObject *iface, DWORD index, IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength) { - FIXME("iface %p, index %lu, buffer %p, flags %#lx, timestamp %s, timelength %s stub!\n", iface, + struct wmv_decoder *impl = impl_from_IMediaObject(iface); + + TRACE("iface %p, index %lu, buffer %p, flags %#lx, timestamp %s, timelength %s.\n", iface, index, buffer, flags, wine_dbgstr_longlong(timestamp), wine_dbgstr_longlong(timelength)); - return E_NOTIMPL; + + if (impl->output.pBuffer) return DMO_E_NOTACCEPTING; + + IMediaBuffer_AddRef((impl->output.pBuffer = buffer)); + impl->output.dwStatus = flags; + impl->output.rtTimestamp = timestamp; + impl->output.rtTimelength = timelength; + + return S_OK; } static HRESULT WINAPI media_object_ProcessOutput(IMediaObject *iface, DWORD flags, DWORD count, DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status) { - FIXME("iface %p, flags %#lx, count %lu, buffers %p, status %p stub!\n", iface, flags, count, buffers, status); - return E_NOTIMPL; + struct wmv_decoder *impl = impl_from_IMediaObject(iface); + BYTE *src_data, *dst_data; + DWORD src_len, dst_len; + static int once; + + TRACE("iface %p, flags %#lx, count %lu, buffers %p, status %p.\n", iface, flags, count, buffers, status); + + if (!impl->output.pBuffer) return DMO_E_NO_MORE_ITEMS; + + IMediaBuffer_GetBufferAndLength(impl->output.pBuffer, &src_data, &src_len); + IMediaBuffer_GetBufferAndLength(buffers[0].pBuffer, &dst_data, &dst_len); + IMediaBuffer_GetMaxLength(buffers[0].pBuffer, &dst_len); + if (dst_len != src_len && !once++) FIXME("video conversion not implemented!\n"); + memcpy(dst_data, src_data, min(dst_len, src_len)); + IMediaBuffer_SetLength(buffers[0].pBuffer, min(dst_len, src_len)); + + *status = 0; + buffers[0].dwStatus = impl->output.dwStatus; + buffers[0].rtTimestamp = impl->output.rtTimelength; + buffers[0].rtTimelength = impl->output.rtTimelength; + + IMediaBuffer_Release(impl->output.pBuffer); + impl->output.pBuffer = NULL; + + return S_OK; } static HRESULT WINAPI media_object_Lock(IMediaObject *iface, LONG lock) From 9b0ffcb1771734dba67a9877a16a616c3df5265f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 17 Aug 2022 08:58:46 +0200 Subject: [PATCH 0143/2777] HACK: quartz: Reduce the number of committed buffers for P4G. The game requests 30 buffers of 8M for the video and 30 additional buffers for the audio stream. We're already near the 32bit VM limit and fragmentation often makes it fail. 8 buffers should hopefully be enough overall. CW-Bug-Id: #20363 --- dlls/quartz/memallocator.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dlls/quartz/memallocator.c b/dlls/quartz/memallocator.c index 87869b4d6b2..7a171769574 100644 --- a/dlls/quartz/memallocator.c +++ b/dlls/quartz/memallocator.c @@ -162,6 +162,7 @@ static ULONG WINAPI BaseMemAllocator_Release(IMemAllocator * iface) static HRESULT WINAPI BaseMemAllocator_SetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual) { BaseMemAllocator *This = impl_from_IMemAllocator(iface); + const char *sgi; HRESULT hr; TRACE("(%p)->(%p, %p)\n", This, pRequest, pActual); @@ -169,6 +170,10 @@ static HRESULT WINAPI BaseMemAllocator_SetProperties(IMemAllocator * iface, ALLO TRACE("Requested %ld buffers, size %ld, alignment %ld, prefix %ld.\n", pRequest->cBuffers, pRequest->cbBuffer, pRequest->cbAlign, pRequest->cbPrefix); + sgi = getenv("SteamGameId"); + if (sgi && (!strcmp(sgi, "1113000"))) + pRequest->cBuffers = min(8, pRequest->cBuffers); + EnterCriticalSection(This->pCritSect); { if (!list_empty(&This->used_list)) From dc0a9dc1693a82715ecf54685f0e6e31ef155f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 18 Aug 2022 16:38:19 +0200 Subject: [PATCH 0144/2777] HACK: mf: Force initialize downstream media type if it's not. --- dlls/mf/topology_loader.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c index 6b6d39d76d1..def7c28089c 100644 --- a/dlls/mf/topology_loader.c +++ b/dlls/mf/topology_loader.c @@ -347,7 +347,10 @@ static HRESULT get_first_supported_media_type(IMFMediaTypeHandler *handler, IMFM for (i = 0; SUCCEEDED(hr = IMFMediaTypeHandler_GetMediaTypeByIndex(handler, i, &media_type)); i++) { - if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(handler, media_type, NULL))) + /* HACK: Force initialize media type here, this is now something the topology laoder should do + * according to conformance tests but it should hopefully going to solve uninitialized audio + * renderer issues. */ + if (SUCCEEDED(hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, media_type))) { *type = media_type; return hr; From 2cb221bbdcdda274b0d7b3f55694566695477fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 28 Sep 2022 14:09:39 +0200 Subject: [PATCH 0145/2777] HACK: winegstreamer: Don't flip RGB for Media Foundation clients. This reverts commit 388f76eb6b6623f291ba8df1300d0ae6cc16a980. --- 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 ee1736680ad..caa754125b8 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -82,7 +82,7 @@ uint32_t wg_parser_get_stream_count(struct wg_parser *parser); struct wg_parser_stream *wg_parser_get_stream(struct wg_parser *parser, uint32_t index); void wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, struct wg_format *format); -void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format); +void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format, uint32_t flags); void wg_parser_stream_disable(struct wg_parser_stream *stream); bool wg_parser_stream_get_buffer(struct wg_parser *parser, struct wg_parser_stream *stream, diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 8f42673b10e..de3bde867dc 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -186,12 +186,13 @@ void wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, stru WINE_UNIX_CALL(unix_wg_parser_stream_get_preferred_format, ¶ms); } -void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format) +void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format, uint32_t flags) { struct wg_parser_stream_enable_params params = { .stream = stream, .format = format, + .flags = flags, }; TRACE("stream %p, format %p.\n", stream, format); diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 3b59534d67e..da65785b54a 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -360,7 +360,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); + wg_parser_stream_enable(stream->wg_stream, &format, 0); IMFMediaType_Release(current_mt); IMFMediaTypeHandler_Release(mth); diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 86e98f5778b..e683f96be37 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1253,7 +1253,7 @@ static HRESULT parser_init_stream(struct strmbase_filter *iface) { ret = amt_to_wg_format(&source->pin.pin.mt, &format); assert(ret); - wg_parser_stream_enable(source->wg_stream, &format); + wg_parser_stream_enable(source->wg_stream, &format, STREAM_ENABLE_FLAG_FLIP_RGB); } else { diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 328bc7a48fb..968359b7454 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -227,10 +227,13 @@ 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; + uint32_t flags; }; struct wg_parser_stream_get_buffer_params diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index f00bff39a73..e75c804c270 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -230,31 +230,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_RGBA: - 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: - 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_RGBA: + 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: + break; + } + + gst_util_set_object_arg(G_OBJECT(stream->flip), "method", flip ? "vertical-flip" : "none"); + } } gst_pad_push_event(stream->my_sink, gst_event_new_reconfigure()); diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 9e0c82ed07f..615fe5dde2c 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1523,7 +1523,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); + wg_parser_stream_enable(stream->wg_stream, &stream->format, STREAM_ENABLE_FLAG_FLIP_RGB); } /* We probably discarded events because streams weren't enabled yet. @@ -2238,7 +2238,7 @@ static HRESULT WINAPI reader_SetOutputProps(IWMSyncReader2 *iface, DWORD output, } stream->format = format; - wg_parser_stream_enable(stream->wg_stream, &format); + wg_parser_stream_enable(stream->wg_stream, &format, STREAM_ENABLE_FLAG_FLIP_RGB); /* Re-decode any buffers that might have been generated with the old format. * @@ -2380,7 +2380,7 @@ static HRESULT WINAPI reader_SetStreamsSelected(IWMSyncReader2 *iface, 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); + wg_parser_stream_enable(stream->wg_stream, &stream->format, STREAM_ENABLE_FLAG_FLIP_RGB); } } From 6d9c39fefacb505bfb26317f92f3966c38eaa677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 22 Aug 2022 18:49:06 +0200 Subject: [PATCH 0146/2777] winegstreamer: Avoid entering sync reader CS in GetNextSample when aggregated. CW-Bug-Id: #21147 --- dlls/winegstreamer/wm_reader.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 615fe5dde2c..c72a284c897 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1859,7 +1859,8 @@ static HRESULT WINAPI reader_GetNextSample(IWMSyncReader2 *iface, if (!stream_number && !output_number && !ret_stream_number) return E_INVALIDARG; - EnterCriticalSection(&reader->cs); + if (reader->outer == &reader->IUnknown_inner) + EnterCriticalSection(&reader->cs); if (!stream_number) stream = NULL; @@ -1887,7 +1888,8 @@ static HRESULT WINAPI reader_GetNextSample(IWMSyncReader2 *iface, if (ret_stream_number && (hr == S_OK || stream_number)) *ret_stream_number = stream_number; - LeaveCriticalSection(&reader->cs); + if (reader->outer == &reader->IUnknown_inner) + LeaveCriticalSection(&reader->cs); return hr; } From c0b592250faab01f1c085c8d5f969ebdd1898913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 16 Sep 2022 08:05:48 +0200 Subject: [PATCH 0147/2777] wmvcore: Spawn stream read threads for async reader streams. CW-Bug-Id: #21147 --- dlls/wmvcore/async_reader.c | 254 +++++++++++++++++++++++++++++++++--- 1 file changed, 234 insertions(+), 20 deletions(-) diff --git a/dlls/wmvcore/async_reader.c b/dlls/wmvcore/async_reader.c index a51018260b1..933dfd06a7a 100644 --- a/dlls/wmvcore/async_reader.c +++ b/dlls/wmvcore/async_reader.c @@ -59,12 +59,25 @@ struct async_op struct sample { + struct list entry; INSSBuffer *buffer; QWORD pts, duration; DWORD flags, output; WORD stream; }; +struct stream +{ + struct async_reader *reader; + WORD number; + + HANDLE read_thread; + bool read_requested; + CONDITION_VARIABLE read_cv; + struct list read_samples; + HRESULT read_result; +}; + struct async_reader { IWMReader IWMReader_iface; @@ -78,6 +91,7 @@ struct async_reader LONG refcount; IWMSyncReader2 *reader; + IWMProfile3 *profile; CRITICAL_SECTION cs; @@ -93,6 +107,9 @@ struct async_reader CRITICAL_SECTION callback_cs; CONDITION_VARIABLE callback_cv; + DWORD stream_count; + struct stream *streams; + bool running; struct list async_ops; @@ -292,31 +309,180 @@ static void async_reader_deliver_sample(struct async_reader *reader, struct samp TRACE("Callback returned %#lx.\n", hr); + list_remove(&sample->entry); INSSBuffer_Release(sample->buffer); + free(sample); +} + +static void stream_request_read(struct stream *stream) +{ + stream->read_result = E_PENDING; + stream->read_requested = true; + WakeConditionVariable(&stream->read_cv); +} + +static DWORD WINAPI stream_read_thread(void *arg) +{ + struct stream *stream = arg; + struct async_reader *reader = stream->reader; + struct sample *sample; + HRESULT hr; + + TRACE("reader %p, number %u\n", reader, stream->number); + + EnterCriticalSection(&reader->callback_cs); + + while (reader->running) + { + if (!stream->read_requested) + { + SleepConditionVariableCS(&stream->read_cv, &reader->callback_cs, INFINITE); + continue; + } + + if (!(sample = calloc(1, sizeof(*sample)))) + { + WARN("Failed to allocate memory for sample.\n"); + continue; + } + + while (stream->read_requested) + { + stream->read_requested = false; + + if (sample->buffer) + INSSBuffer_Release(sample->buffer); + sample->buffer = NULL; + + LeaveCriticalSection(&reader->callback_cs); + hr = IWMSyncReader2_GetNextSample(reader->reader, stream->number, + &sample->buffer, &sample->pts, &sample->duration, + &sample->flags, &sample->output, &sample->stream); + EnterCriticalSection(&reader->callback_cs); + } + + if (SUCCEEDED(stream->read_result = hr)) + { + TRACE("Got stream %u buffer with pts %I64d.\n", stream->number, sample->pts); + list_add_tail(&stream->read_samples, &sample->entry); + } + else + { + WARN("Failed to get stream %u sample, hr %#lx.\n", stream->number, stream->read_result); + free(sample); + } + + WakeConditionVariable(&reader->callback_cv); + } + + LeaveCriticalSection(&reader->callback_cs); + + TRACE("Reader is stopping; exiting.\n"); + return 0; +} + +static void stream_flush_samples(struct stream *stream) +{ + struct sample *sample, *next; + + LIST_FOR_EACH_ENTRY_SAFE(sample, next, &stream->read_samples, struct sample, entry) + { + list_remove(&sample->entry); + INSSBuffer_Release(sample->buffer); + free(sample); + } +} + +static void stream_close(struct stream *stream) +{ + if (stream->read_thread) + { + WakeConditionVariable(&stream->read_cv); + WaitForSingleObject(stream->read_thread, INFINITE); + CloseHandle(stream->read_thread); + stream->read_thread = NULL; + } + + stream_flush_samples(stream); +} + +static HRESULT stream_open(struct stream *stream, struct async_reader *reader, WORD number) +{ + if (stream->read_thread) + return S_OK; + + stream->number = number; + stream->reader = reader; + list_init(&stream->read_samples); + + if (!(stream->read_thread = CreateThread(NULL, 0, stream_read_thread, stream, 0, NULL))) + return E_OUTOFMEMORY; + + return S_OK; } -static void callback_thread_run(struct async_reader *reader) +static HRESULT async_reader_get_next_sample(struct async_reader *reader, + struct stream **out_stream, struct sample **out_sample) { + struct sample *sample, *first_sample = NULL; + struct stream *stream, *first_stream = NULL; + WMT_STREAM_SELECTION selection; + struct list *entry; + DWORD i; + + for (i = 0; i < reader->stream_count; ++i) + { + stream = reader->streams + i; + + if (FAILED(IWMSyncReader2_GetStreamSelected(reader->reader, i + 1, &selection)) + || selection == WMT_OFF) + continue; + if (!(entry = list_head(&stream->read_samples))) + { + if (stream->read_result == E_PENDING) + return E_PENDING; + continue; + } + + sample = LIST_ENTRY(entry, struct sample, entry); + if (!first_sample || first_sample->pts > sample->pts) + { + first_stream = stream; + first_sample = sample; + } + } + + if (!first_sample) + return NS_E_NO_MORE_SAMPLES; + + TRACE("Found first stream %u with pts %I64d.\n", first_stream->number, first_sample->pts); + *out_sample = first_sample; + *out_stream = first_stream; + return S_OK; +} + +static void async_reader_deliver_samples(struct async_reader *reader) +{ + static const DWORD zero; + IWMReaderCallbackAdvanced *callback_advanced = reader->callback_advanced; IWMReaderCallback *callback = reader->callback; - static const DWORD zero; HRESULT hr = S_OK; + TRACE("reader %p\n", reader); + while (reader->running && list_empty(&reader->async_ops)) { - struct sample sample; + struct sample *sample; + struct stream *stream; - LeaveCriticalSection(&reader->callback_cs); - hr = IWMSyncReader2_GetNextSample(reader->reader, 0, &sample.buffer, &sample.pts, - &sample.duration, &sample.flags, &sample.output, &sample.stream); - EnterCriticalSection(&reader->callback_cs); - if (hr != S_OK) + if (FAILED(hr = async_reader_get_next_sample(reader, &stream, &sample))) break; - if (async_reader_wait_pts(reader, sample.pts)) - async_reader_deliver_sample(reader, &sample); - else - INSSBuffer_Release(sample.buffer); + stream_request_read(stream); + + if (async_reader_wait_pts(reader, sample->pts)) + async_reader_deliver_sample(reader, sample); } if (hr == NS_E_NO_MORE_SAMPLES) @@ -324,6 +490,8 @@ static void callback_thread_run(struct async_reader *reader) BOOL user_clock = reader->user_clock; QWORD user_time = reader->user_time; + TRACE("No more streams samples, sending EOF notifications.\n"); + LeaveCriticalSection(&reader->callback_cs); IWMReaderCallback_OnStatus(callback, WMT_END_OF_STREAMING, S_OK, @@ -341,25 +509,27 @@ static void callback_thread_run(struct async_reader *reader) } EnterCriticalSection(&reader->callback_cs); - - TRACE("Reached end of stream; exiting.\n"); } - else if (hr != S_OK) + else if (hr == E_PENDING) { - ERR("Failed to get sample, hr %#lx.\n", hr); + TRACE("Waiting for more streams samples.\n"); } } static DWORD WINAPI async_reader_callback_thread(void *arg) { - struct async_reader *reader = arg; static const DWORD zero; + + struct async_reader *reader = arg; struct list *entry; HRESULT hr = S_OK; + DWORD i; IWMReaderCallback_OnStatus(reader->callback, WMT_OPENED, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); + TRACE("reader %p\n", reader); + EnterCriticalSection(&reader->callback_cs); while (reader->running) @@ -378,19 +548,28 @@ static DWORD WINAPI async_reader_callback_thread(void *arg) if (SUCCEEDED(hr)) hr = IWMSyncReader2_SetRange(reader->reader, op->u.start.start, op->u.start.duration); if (SUCCEEDED(hr)) + { reader->clock_start = get_current_time(reader); + for (i = 0; i < reader->stream_count; ++i) + { + struct stream *stream = reader->streams + i; + stream_flush_samples(stream); + stream_request_read(stream); + } + } + LeaveCriticalSection(&reader->callback_cs); IWMReaderCallback_OnStatus(reader->callback, WMT_STARTED, hr, WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); EnterCriticalSection(&reader->callback_cs); - - if (SUCCEEDED(hr)) - callback_thread_run(reader); break; } case ASYNC_OP_STOP: + if (SUCCEEDED(hr)) + reader->clock_start = 0; + LeaveCriticalSection(&reader->callback_cs); IWMReaderCallback_OnStatus(reader->callback, WMT_STOPPED, hr, WMT_TYPE_DWORD, (BYTE *)&zero, reader->context); @@ -411,6 +590,9 @@ static DWORD WINAPI async_reader_callback_thread(void *arg) free(op); } + if (reader->clock_start) + async_reader_deliver_samples(reader); + if (reader->running && list_empty(&reader->async_ops)) SleepConditionVariableCS(&reader->callback_cv, &reader->callback_cs, INFINITE); } @@ -424,6 +606,7 @@ static DWORD WINAPI async_reader_callback_thread(void *arg) static void async_reader_close(struct async_reader *reader) { struct async_op *op, *next; + int i; if (reader->callback_thread) { @@ -438,6 +621,15 @@ static void async_reader_close(struct async_reader *reader) free(op); } + for (i = 0; reader->streams && i < reader->stream_count; ++i) + { + struct stream *stream = reader->streams + i; + stream_close(stream); + } + free(reader->streams); + reader->streams = NULL; + reader->stream_count = 0; + if (reader->allocator) IWMReaderAllocatorEx_Release(reader->allocator); reader->allocator = NULL; @@ -455,6 +647,7 @@ static void async_reader_close(struct async_reader *reader) static HRESULT async_reader_open(struct async_reader *reader, IWMReaderCallback *callback, void *context) { HRESULT hr = E_OUTOFMEMORY; + DWORD i; IWMReaderCallback_AddRef((reader->callback = callback)); reader->context = context; @@ -469,7 +662,24 @@ static HRESULT async_reader_open(struct async_reader *reader, IWMReaderCallback reader->callback_advanced = NULL; } + if (FAILED(hr = IWMProfile3_GetStreamCount(reader->profile, &reader->stream_count))) + goto error; + + if (!(reader->streams = calloc(reader->stream_count, sizeof(*reader->streams)))) + { + hr = E_OUTOFMEMORY; + goto error; + } + reader->running = true; + + for (i = 0; i < reader->stream_count; ++i) + { + struct stream *stream = reader->streams + i; + if (FAILED(hr = stream_open(stream, reader, i + 1))) + goto error; + } + if (!(reader->callback_thread = CreateThread(NULL, 0, async_reader_callback_thread, reader, 0, NULL))) goto error; @@ -1921,6 +2131,10 @@ static HRESULT WINAPI async_reader_create(IWMReader **reader) (void **)&object->reader))) goto failed; IWMReader_Release(&object->IWMReader_iface); + if (FAILED(hr = IUnknown_QueryInterface(object->reader_inner, &IID_IWMProfile3, + (void **)&object->profile))) + goto failed; + IWMReader_Release(&object->IWMReader_iface); InitializeCriticalSection(&object->cs); object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": async_reader.cs"); From b7d6396538e57d1ae543d40ff22aa1422743375a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 1 Sep 2022 15:32:14 +0200 Subject: [PATCH 0148/2777] wmvcore: Implement DedicatedDeliveryThread async reader output setting. This restores the todo_wine in the allocator callback as we're now allocating samples in the delivering thread as well. We'll need to create new threads for allocation to match native behavior. CW-Bug-Id: #21147 --- dlls/wmvcore/async_reader.c | 114 ++++++++++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 6 deletions(-) diff --git a/dlls/wmvcore/async_reader.c b/dlls/wmvcore/async_reader.c index 933dfd06a7a..540a73b84a8 100644 --- a/dlls/wmvcore/async_reader.c +++ b/dlls/wmvcore/async_reader.c @@ -76,6 +76,11 @@ struct stream CONDITION_VARIABLE read_cv; struct list read_samples; HRESULT read_result; + + bool dedicated_delivery_thread; + HANDLE deliver_thread; + struct list deliver_samples; + CONDITION_VARIABLE deliver_cv; }; struct async_reader @@ -321,6 +326,48 @@ static void stream_request_read(struct stream *stream) WakeConditionVariable(&stream->read_cv); } +static void stream_request_deliver(struct async_reader *reader, struct sample *sample) +{ + struct stream *stream = reader->streams + sample->output; + + list_remove(&sample->entry); + list_add_tail(&stream->deliver_samples, &sample->entry); + WakeConditionVariable(&stream->deliver_cv); +} + +static DWORD WINAPI stream_deliver_thread(void *arg) +{ + struct stream *stream = arg; + struct async_reader *reader = stream->reader; + struct list *entry; + + TRACE("reader %p, number %u\n", reader, stream->number); + + EnterCriticalSection(&reader->callback_cs); + + while (reader->running) + { + if (list_empty(&stream->deliver_samples)) + { + SleepConditionVariableCS(&stream->deliver_cv, &reader->callback_cs, INFINITE); + continue; + } + + while ((entry = list_head(&stream->deliver_samples))) + { + struct sample *sample = LIST_ENTRY(entry, struct sample, entry); + async_reader_deliver_sample(reader, sample); + } + + WakeConditionVariable(&reader->callback_cv); + } + + LeaveCriticalSection(&reader->callback_cs); + + TRACE("Reader is stopping; exiting.\n"); + return 0; +} + static DWORD WINAPI stream_read_thread(void *arg) { struct stream *stream = arg; @@ -391,6 +438,13 @@ static void stream_flush_samples(struct stream *stream) INSSBuffer_Release(sample->buffer); free(sample); } + + LIST_FOR_EACH_ENTRY_SAFE(sample, next, &stream->deliver_samples, struct sample, entry) + { + list_remove(&sample->entry); + INSSBuffer_Release(sample->buffer); + free(sample); + } } static void stream_close(struct stream *stream) @@ -403,6 +457,14 @@ static void stream_close(struct stream *stream) stream->read_thread = NULL; } + if (stream->deliver_thread) + { + WakeConditionVariable(&stream->deliver_cv); + WaitForSingleObject(stream->deliver_thread, INFINITE); + CloseHandle(stream->deliver_thread); + stream->deliver_thread = NULL; + } + stream_flush_samples(stream); } @@ -414,10 +476,17 @@ static HRESULT stream_open(struct stream *stream, struct async_reader *reader, W stream->number = number; stream->reader = reader; list_init(&stream->read_samples); + list_init(&stream->deliver_samples); if (!(stream->read_thread = CreateThread(NULL, 0, stream_read_thread, stream, 0, NULL))) return E_OUTOFMEMORY; + if (!(stream->deliver_thread = CreateThread(NULL, 0, stream_deliver_thread, stream, 0, NULL))) + { + stream_close(stream); + return E_OUTOFMEMORY; + } + return S_OK; } @@ -427,6 +496,7 @@ static HRESULT async_reader_get_next_sample(struct async_reader *reader, struct sample *sample, *first_sample = NULL; struct stream *stream, *first_stream = NULL; WMT_STREAM_SELECTION selection; + BOOL pending = FALSE; struct list *entry; DWORD i; @@ -434,6 +504,8 @@ static HRESULT async_reader_get_next_sample(struct async_reader *reader, { stream = reader->streams + i; + if (!list_empty(&stream->deliver_samples)) + pending = TRUE; if (FAILED(IWMSyncReader2_GetStreamSelected(reader->reader, i + 1, &selection)) || selection == WMT_OFF) continue; @@ -453,7 +525,7 @@ static HRESULT async_reader_get_next_sample(struct async_reader *reader, } if (!first_sample) - return NS_E_NO_MORE_SAMPLES; + return pending ? E_PENDING : NS_E_NO_MORE_SAMPLES; TRACE("Found first stream %u with pts %I64d.\n", first_stream->number, first_sample->pts); *out_sample = first_sample; @@ -473,8 +545,8 @@ static void async_reader_deliver_samples(struct async_reader *reader) while (reader->running && list_empty(&reader->async_ops)) { - struct sample *sample; struct stream *stream; + struct sample *sample; if (FAILED(hr = async_reader_get_next_sample(reader, &stream, &sample))) break; @@ -482,7 +554,12 @@ static void async_reader_deliver_samples(struct async_reader *reader) stream_request_read(stream); if (async_reader_wait_pts(reader, sample->pts)) - async_reader_deliver_sample(reader, sample); + { + if (!stream->dedicated_delivery_thread) + async_reader_deliver_sample(reader, sample); + else + stream_request_deliver(reader, sample); + } } if (hr == NS_E_NO_MORE_SAMPLES) @@ -1251,9 +1328,34 @@ static HRESULT WINAPI WMReaderAdvanced2_GetOutputSetting(IWMReaderAdvanced6 *ifa static HRESULT WINAPI WMReaderAdvanced2_SetOutputSetting(IWMReaderAdvanced6 *iface, DWORD output_num, const WCHAR *name, WMT_ATTR_DATATYPE type, const BYTE *value, WORD length) { - struct async_reader *This = impl_from_IWMReaderAdvanced6(iface); - FIXME("(%p)->(%lu %s %#x %p %u)\n", This, output_num, debugstr_w(name), type, value, length); - return E_NOTIMPL; + struct async_reader *reader = impl_from_IWMReaderAdvanced6(iface); + struct stream *stream; + HRESULT hr = E_NOTIMPL; + + FIXME("reader %p, output_num %lu, name %s, type %u, value %p, length %u semi-stub!\n", + reader, output_num, debugstr_w(name), type, value, length); + + EnterCriticalSection(&reader->cs); + + if (!reader->streams) + { + LeaveCriticalSection(&reader->cs); + return E_UNEXPECTED; + } + + stream = reader->streams + output_num; + + EnterCriticalSection(&reader->callback_cs); + if (!wcscmp(name, L"DedicatedDeliveryThread")) + { + stream->dedicated_delivery_thread = *(BOOL *)value; + hr = S_OK; + } + LeaveCriticalSection(&reader->callback_cs); + + LeaveCriticalSection(&reader->cs); + + return hr; } static HRESULT WINAPI WMReaderAdvanced2_Preroll(IWMReaderAdvanced6 *iface, QWORD start, QWORD duration, float rate) From 97462962d89ee5a1ac619104bc487e954acc00a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 1 Sep 2022 21:04:06 +0200 Subject: [PATCH 0149/2777] qasf: Query the IWMReaderAdvanced2 reader interface. CW-Bug-Id: #21147 --- dlls/qasf/asfreader.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dlls/qasf/asfreader.c b/dlls/qasf/asfreader.c index 4cf077e9dd3..adbbae671ef 100644 --- a/dlls/qasf/asfreader.c +++ b/dlls/qasf/asfreader.c @@ -438,13 +438,13 @@ static HRESULT asf_reader_init_stream(struct strmbase_filter *iface) struct asf_reader *filter = impl_from_strmbase_filter(iface); WMT_STREAM_SELECTION selections[ARRAY_SIZE(filter->streams)]; WORD stream_numbers[ARRAY_SIZE(filter->streams)]; - IWMReaderAdvanced *reader_advanced; + IWMReaderAdvanced2 *reader_advanced; HRESULT hr = S_OK; int i; TRACE("iface %p\n", iface); - if (FAILED(hr = IWMReader_QueryInterface(filter->reader, &IID_IWMReaderAdvanced, (void **)&reader_advanced))) + if (FAILED(hr = IWMReader_QueryInterface(filter->reader, &IID_IWMReaderAdvanced2, (void **)&reader_advanced))) return hr; for (i = 0; i < filter->stream_count; ++i) @@ -464,7 +464,7 @@ static HRESULT asf_reader_init_stream(struct strmbase_filter *iface) break; } - if (FAILED(hr = IWMReaderAdvanced_SetAllocateForOutput(reader_advanced, i, TRUE))) + if (FAILED(hr = IWMReaderAdvanced2_SetAllocateForOutput(reader_advanced, i, TRUE))) { WARN("Failed to enable allocation for stream %u, hr %#lx\n", i, hr); break; @@ -495,11 +495,11 @@ static HRESULT asf_reader_init_stream(struct strmbase_filter *iface) selections[i] = WMT_ON; } - if (SUCCEEDED(hr) && FAILED(hr = IWMReaderAdvanced_SetStreamsSelected(reader_advanced, + if (SUCCEEDED(hr) && FAILED(hr = IWMReaderAdvanced2_SetStreamsSelected(reader_advanced, filter->stream_count, stream_numbers, selections))) WARN("Failed to set reader %p stream selection, hr %#lx\n", filter->reader, hr); - IWMReaderAdvanced_Release(reader_advanced); + IWMReaderAdvanced2_Release(reader_advanced); if (FAILED(hr)) return hr; From 281aab5ba331ab5bf437d4699951b0e1a465980f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 30 Aug 2022 15:44:15 +0200 Subject: [PATCH 0150/2777] qasf: Set the DedicatedDeliveryThread property according to ReceiveCanBlock. CW-Bug-Id: #21147 --- dlls/qasf/asfreader.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dlls/qasf/asfreader.c b/dlls/qasf/asfreader.c index adbbae671ef..5119af9ffa3 100644 --- a/dlls/qasf/asfreader.c +++ b/dlls/qasf/asfreader.c @@ -440,6 +440,7 @@ static HRESULT asf_reader_init_stream(struct strmbase_filter *iface) WORD stream_numbers[ARRAY_SIZE(filter->streams)]; IWMReaderAdvanced2 *reader_advanced; HRESULT hr = S_OK; + BOOL value; int i; TRACE("iface %p\n", iface); @@ -492,6 +493,14 @@ static HRESULT asf_reader_init_stream(struct strmbase_filter *iface) break; } + value = IMemInputPin_ReceiveCanBlock(stream->source.pMemInputPin) == S_OK; + if (FAILED(hr = IWMReaderAdvanced2_SetOutputSetting(reader_advanced, i, L"DedicatedDeliveryThread", + WMT_TYPE_BOOL, (BYTE *)&value, sizeof(value)))) + { + WARN("Failed to set DedicatedDeliveryThread for stream %u, hr %#lx\n", i, hr); + break; + } + selections[i] = WMT_ON; } From aa82d51cc6f63d87a2ed3b07ce8fb187394ce4de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 1 Sep 2022 21:04:37 +0200 Subject: [PATCH 0151/2777] qasf: Set user provided clock and time to prevent waits in WMReader. CW-Bug-Id: #21147 --- dlls/qasf/asfreader.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/qasf/asfreader.c b/dlls/qasf/asfreader.c index 5119af9ffa3..75e77b9f070 100644 --- a/dlls/qasf/asfreader.c +++ b/dlls/qasf/asfreader.c @@ -508,6 +508,12 @@ static HRESULT asf_reader_init_stream(struct strmbase_filter *iface) filter->stream_count, stream_numbers, selections))) WARN("Failed to set reader %p stream selection, hr %#lx\n", filter->reader, hr); + if (SUCCEEDED(hr) && FAILED(hr = IWMReaderAdvanced2_SetUserProvidedClock(reader_advanced, TRUE))) + WARN("Failed to set user provided clock, hr %#lx\n", hr); + + if (SUCCEEDED(hr) && FAILED(hr = IWMReaderAdvanced2_DeliverTime(reader_advanced, -1))) + WARN("Failed to set user time, hr %#lx\n", hr); + IWMReaderAdvanced2_Release(reader_advanced); if (FAILED(hr)) From 3f7f8def648176346af304c7e264c83e17897b84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 2 Sep 2022 13:23:21 +0200 Subject: [PATCH 0152/2777] qasf: Increase the minimum number of buffers in asf_reader_DecideBufferSize. Required for Sang Froid. CW-Bug-Id: #18799 CW-Bug-Id: #18994 CW-Bug-Id: #20182 CW-Bug-Id: #20905 --- dlls/qasf/asfreader.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dlls/qasf/asfreader.c b/dlls/qasf/asfreader.c index 75e77b9f070..f561e72b29e 100644 --- a/dlls/qasf/asfreader.c +++ b/dlls/qasf/asfreader.c @@ -604,7 +604,11 @@ static HRESULT WINAPI asf_reader_DecideBufferSize(struct strmbase_source *iface, buffer_size = format->nAvgBytesPerSec; } - req_props->cBuffers = max(req_props->cBuffers, 1); + if (IsEqualGUID(&stream->source.pin.mt.majortype, &MEDIATYPE_Audio)) + req_props->cBuffers = max(req_props->cBuffers, 50); + else + req_props->cBuffers = max(req_props->cBuffers, 10); + req_props->cbBuffer = max(req_props->cbBuffer, buffer_size); req_props->cbAlign = max(req_props->cbAlign, 1); return IMemAllocator_SetProperties(allocator, req_props, &ret_props); From 0b66dec6fcbcd0e7854d35caf107040507ada4da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 27 May 2022 10:45:33 +0200 Subject: [PATCH 0153/2777] qasf: Implement ASF Reader SourceSeeking interface. CW-Bug-Id: #18799 CW-Bug-Id: #18994 CW-Bug-Id: #20182 CW-Bug-Id: #20905 --- dlls/qasf/asfreader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/qasf/asfreader.c b/dlls/qasf/asfreader.c index f561e72b29e..625b26d439e 100644 --- a/dlls/qasf/asfreader.c +++ b/dlls/qasf/asfreader.c @@ -487,7 +487,7 @@ static HRESULT asf_reader_init_stream(struct strmbase_filter *iface) break; } - if (FAILED(hr = IPin_NewSegment(stream->source.pin.peer, 0, 0, 1))) + if (FAILED(hr = IPin_NewSegment(stream->source.pin.peer, stream->seek.llCurrent, stream->seek.llStop, stream->seek.dRate))) { WARN("Failed to start stream %u new segment, hr %#lx\n", i, hr); break; From 264e7a1adabcf76399d4875dabaf1772e0d3326a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 Aug 2022 12:50:21 +0200 Subject: [PATCH 0154/2777] HACK: qasf: Only force user provided time to -1 if no quartz clock is set. This satisfies both Sang Froid intro song which expects the audio stream to fast forward decode by not providing any sync source to the filter, and Space Engineers which expects the filter to respect the system clock timing when decoding its videos. This is likely a hack and there's probably something to do with wmvcore sync clock source to make it match quartz clock. CW-Bug-Id: #21139 --- dlls/qasf/asfreader.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dlls/qasf/asfreader.c b/dlls/qasf/asfreader.c index 625b26d439e..a0f9ef0c2ff 100644 --- a/dlls/qasf/asfreader.c +++ b/dlls/qasf/asfreader.c @@ -508,11 +508,13 @@ static HRESULT asf_reader_init_stream(struct strmbase_filter *iface) filter->stream_count, stream_numbers, selections))) WARN("Failed to set reader %p stream selection, hr %#lx\n", filter->reader, hr); - if (SUCCEEDED(hr) && FAILED(hr = IWMReaderAdvanced2_SetUserProvidedClock(reader_advanced, TRUE))) + if (SUCCEEDED(hr) && FAILED(hr = IWMReaderAdvanced2_SetUserProvidedClock(reader_advanced, !filter->filter.clock))) WARN("Failed to set user provided clock, hr %#lx\n", hr); - - if (SUCCEEDED(hr) && FAILED(hr = IWMReaderAdvanced2_DeliverTime(reader_advanced, -1))) - WARN("Failed to set user time, hr %#lx\n", hr); + else if (!filter->filter.clock) + { + if (SUCCEEDED(hr) && FAILED(hr = IWMReaderAdvanced2_DeliverTime(reader_advanced, -1))) + WARN("Failed to set user time, hr %#lx\n", hr); + } IWMReaderAdvanced2_Release(reader_advanced); From 1eb1070a1e673d0e9f07d5bab2124400096c8976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 14 Sep 2022 12:09:33 +0200 Subject: [PATCH 0155/2777] quartz: Rename This to filter in the DirectSound Renderer Filter. CW-Bug-Id: #21147 --- dlls/quartz/dsoundrender.c | 242 ++++++++++++++++++------------------- 1 file changed, 121 insertions(+), 121 deletions(-) diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c index 1abd4bdbcec..2b620ceba3c 100644 --- a/dlls/quartz/dsoundrender.c +++ b/dlls/quartz/dsoundrender.c @@ -88,17 +88,17 @@ static struct dsound_render *impl_from_IAMDirectSound(IAMDirectSound *iface) return CONTAINING_RECORD(iface, struct dsound_render, IAMDirectSound_iface); } -static REFERENCE_TIME time_from_pos(struct dsound_render *This, DWORD pos) +static REFERENCE_TIME time_from_pos(struct dsound_render *filter, DWORD pos) { - WAVEFORMATEX *wfx = (WAVEFORMATEX *)This->sink.pin.mt.pbFormat; + WAVEFORMATEX *wfx = (WAVEFORMATEX *)filter->sink.pin.mt.pbFormat; REFERENCE_TIME ret = 10000000; ret = ret * pos / wfx->nAvgBytesPerSec; return ret; } -static DWORD pos_from_time(struct dsound_render *This, REFERENCE_TIME time) +static DWORD pos_from_time(struct dsound_render *filter, REFERENCE_TIME time) { - WAVEFORMATEX *wfx = (WAVEFORMATEX *)This->sink.pin.mt.pbFormat; + WAVEFORMATEX *wfx = (WAVEFORMATEX *)filter->sink.pin.mt.pbFormat; REFERENCE_TIME ret = time; ret *= wfx->nAvgBytesPerSec; ret /= 10000000; @@ -106,56 +106,56 @@ static DWORD pos_from_time(struct dsound_render *This, REFERENCE_TIME time) return ret; } -static void DSoundRender_UpdatePositions(struct dsound_render *This, DWORD *seqwritepos, DWORD *minwritepos) +static void DSoundRender_UpdatePositions(struct dsound_render *filter, DWORD *seqwritepos, DWORD *minwritepos) { - WAVEFORMATEX *wfx = (WAVEFORMATEX *)This->sink.pin.mt.pbFormat; + WAVEFORMATEX *wfx = (WAVEFORMATEX *)filter->sink.pin.mt.pbFormat; BYTE *buf1, *buf2; DWORD size1, size2, playpos, writepos, old_writepos, old_playpos, adv; - BOOL writepos_set = This->writepos < This->buf_size; + BOOL writepos_set = filter->writepos < filter->buf_size; /* Update position and zero */ - old_writepos = This->writepos; - old_playpos = This->last_playpos; + old_writepos = filter->writepos; + old_playpos = filter->last_playpos; if (old_writepos <= old_playpos) - old_writepos += This->buf_size; + old_writepos += filter->buf_size; - IDirectSoundBuffer_GetCurrentPosition(This->dsbuffer, &playpos, &writepos); + IDirectSoundBuffer_GetCurrentPosition(filter->dsbuffer, &playpos, &writepos); if (old_playpos > playpos) - adv = This->buf_size + playpos - old_playpos; + adv = filter->buf_size + playpos - old_playpos; else adv = playpos - old_playpos; - This->last_playpos = playpos; + filter->last_playpos = playpos; if (adv) { TRACE("Moving from %lu to %lu: clearing %lu bytes.\n", old_playpos, playpos, adv); - IDirectSoundBuffer_Lock(This->dsbuffer, old_playpos, adv, (void**)&buf1, &size1, (void**)&buf2, &size2, 0); + IDirectSoundBuffer_Lock(filter->dsbuffer, old_playpos, adv, (void**)&buf1, &size1, (void**)&buf2, &size2, 0); memset(buf1, wfx->wBitsPerSample == 8 ? 128 : 0, size1); memset(buf2, wfx->wBitsPerSample == 8 ? 128 : 0, size2); - IDirectSoundBuffer_Unlock(This->dsbuffer, buf1, size1, buf2, size2); + IDirectSoundBuffer_Unlock(filter->dsbuffer, buf1, size1, buf2, size2); } *minwritepos = writepos; if (!writepos_set || old_writepos < writepos) { if (writepos_set) { - This->writepos = This->buf_size; + filter->writepos = filter->buf_size; FIXME("Underrun of data occurred!\n"); } *seqwritepos = writepos; } else - *seqwritepos = This->writepos; + *seqwritepos = filter->writepos; } -static HRESULT DSoundRender_GetWritePos(struct dsound_render *This, +static HRESULT DSoundRender_GetWritePos(struct dsound_render *filter, DWORD *ret_writepos, REFERENCE_TIME write_at, DWORD *pfree, DWORD *skip) { DWORD writepos, min_writepos, playpos; REFERENCE_TIME max_lag = 50 * 10000; REFERENCE_TIME cur, writepos_t, delta_t; - DSoundRender_UpdatePositions(This, &writepos, &min_writepos); - playpos = This->last_playpos; - if (This->filter.clock) + DSoundRender_UpdatePositions(filter, &writepos, &min_writepos); + playpos = filter->last_playpos; + if (filter->filter.clock) { - IReferenceClock_GetTime(This->filter.clock, &cur); - cur -= This->stream_start; + IReferenceClock_GetTime(filter->filter.clock, &cur); + cur -= filter->stream_start; } else write_at = -1; @@ -169,9 +169,9 @@ static HRESULT DSoundRender_GetWritePos(struct dsound_render *This, } if (writepos >= playpos) - writepos_t = cur + time_from_pos(This, writepos - playpos); + writepos_t = cur + time_from_pos(filter, writepos - playpos); else - writepos_t = cur + time_from_pos(This, This->buf_size + writepos - playpos); + writepos_t = cur + time_from_pos(filter, filter->buf_size + writepos - playpos); /* write_at: Starting time of sample */ /* cur: current time of play position */ @@ -184,75 +184,75 @@ static HRESULT DSoundRender_GetWritePos(struct dsound_render *This, REFERENCE_TIME past, min_writepos_t; WARN("Delta too big %s/%s, overwriting old data or even skipping\n", debugstr_time(delta_t), debugstr_time(max_lag)); if (min_writepos >= playpos) - min_writepos_t = cur + time_from_pos(This, min_writepos - playpos); + min_writepos_t = cur + time_from_pos(filter, min_writepos - playpos); else - min_writepos_t = cur + time_from_pos(This, This->buf_size - playpos + min_writepos); + min_writepos_t = cur + time_from_pos(filter, filter->buf_size - playpos + min_writepos); past = min_writepos_t - write_at; if (past >= 0) { - DWORD skipbytes = pos_from_time(This, past); + DWORD skipbytes = pos_from_time(filter, past); WARN("Skipping %lu bytes.\n", skipbytes); *skip = skipbytes; *ret_writepos = min_writepos; } else { - DWORD aheadbytes = pos_from_time(This, -past); + DWORD aheadbytes = pos_from_time(filter, -past); WARN("Advancing %lu bytes.\n", aheadbytes); - *ret_writepos = (min_writepos + aheadbytes) % This->buf_size; + *ret_writepos = (min_writepos + aheadbytes) % filter->buf_size; } } else /* delta_t > 0 */ { DWORD aheadbytes; WARN("Delta too big %s/%s, too far ahead\n", debugstr_time(delta_t), debugstr_time(max_lag)); - aheadbytes = pos_from_time(This, delta_t); + aheadbytes = pos_from_time(filter, delta_t); WARN("Advancing %lu bytes.\n", aheadbytes); if (delta_t >= DSoundRenderer_Max_Fill) return S_FALSE; - *ret_writepos = (min_writepos + aheadbytes) % This->buf_size; + *ret_writepos = (min_writepos + aheadbytes) % filter->buf_size; } end: if (playpos >= *ret_writepos) *pfree = playpos - *ret_writepos; else - *pfree = This->buf_size + playpos - *ret_writepos; - if (time_from_pos(This, This->buf_size - *pfree) >= DSoundRenderer_Max_Fill) { - TRACE("Blocked: too full %s / %s\n", debugstr_time(time_from_pos(This, This->buf_size - *pfree)), + *pfree = filter->buf_size + playpos - *ret_writepos; + if (time_from_pos(filter, filter->buf_size - *pfree) >= DSoundRenderer_Max_Fill) { + TRACE("Blocked: too full %s / %s\n", debugstr_time(time_from_pos(filter, filter->buf_size - *pfree)), debugstr_time(DSoundRenderer_Max_Fill)); return S_FALSE; } return S_OK; } -static HRESULT DSoundRender_HandleEndOfStream(struct dsound_render *This) +static HRESULT DSoundRender_HandleEndOfStream(struct dsound_render *filter) { - while (This->filter.state == State_Running) + while (filter->filter.state == State_Running) { DWORD pos1, pos2; - DSoundRender_UpdatePositions(This, &pos1, &pos2); + DSoundRender_UpdatePositions(filter, &pos1, &pos2); if (pos1 == pos2) break; - WaitForSingleObject(This->flush_event, 10); + WaitForSingleObject(filter->flush_event, 10); } return S_OK; } -static HRESULT DSoundRender_SendSampleData(struct dsound_render *This, +static HRESULT DSoundRender_SendSampleData(struct dsound_render *filter, REFERENCE_TIME tStart, REFERENCE_TIME tStop, const BYTE *data, DWORD size) { HRESULT hr; - while (size && This->filter.state != State_Stopped) { + while (size && filter->filter.state != State_Stopped) { DWORD writepos, skip = 0, free, size1, size2, ret; BYTE *buf1, *buf2; - if (This->filter.state == State_Running) - hr = DSoundRender_GetWritePos(This, &writepos, tStart, &free, &skip); + if (filter->filter.state == State_Running) + hr = DSoundRender_GetWritePos(filter, &writepos, tStart, &free, &skip); else hr = S_FALSE; if (hr != S_OK) { - ret = WaitForSingleObject(This->flush_event, 10); - if (This->sink.flushing || This->filter.state == State_Stopped) - return This->filter.state == State_Paused ? S_OK : VFW_E_WRONG_STATE; + ret = WaitForSingleObject(filter->flush_event, 10); + if (filter->sink.flushing || filter->filter.state == State_Stopped) + return filter->filter.state == State_Paused ? S_OK : VFW_E_WRONG_STATE; if (ret != WAIT_TIMEOUT) ERR("WaitForSingleObject() returned %ld.\n", ret); continue; @@ -266,7 +266,7 @@ static HRESULT DSoundRender_SendSampleData(struct dsound_render *This, data += skip; size -= skip; - hr = IDirectSoundBuffer_Lock(This->dsbuffer, writepos, min(free, size), (void**)&buf1, &size1, (void**)&buf2, &size2, 0); + hr = IDirectSoundBuffer_Lock(filter->dsbuffer, writepos, min(free, size), (void**)&buf1, &size1, (void**)&buf2, &size2, 0); if (hr != DS_OK) { ERR("Failed to lock sound buffer, hr %#lx.\n", hr); break; @@ -274,23 +274,23 @@ static HRESULT DSoundRender_SendSampleData(struct dsound_render *This, memcpy(buf1, data, size1); if (size2) memcpy(buf2, data+size1, size2); - IDirectSoundBuffer_Unlock(This->dsbuffer, buf1, size1, buf2, size2); - This->writepos = (writepos + size1 + size2) % This->buf_size; - TRACE("Wrote %lu bytes at %lu, next at %lu - (%lu/%lu)\n", size1+size2, writepos, This->writepos, free, size); + IDirectSoundBuffer_Unlock(filter->dsbuffer, buf1, size1, buf2, size2); + filter->writepos = (writepos + size1 + size2) % filter->buf_size; + TRACE("Wrote %lu bytes at %lu, next at %lu - (%lu/%lu)\n", size1+size2, writepos, filter->writepos, free, size); data += size1 + size2; size -= size1 + size2; } return S_OK; } -static HRESULT DSoundRender_PrepareReceive(struct dsound_render *This, IMediaSample *pSample) +static HRESULT DSoundRender_PrepareReceive(struct dsound_render *filter, IMediaSample *pSample) { HRESULT hr; AM_MEDIA_TYPE *amt; if (IMediaSample_GetMediaType(pSample, &amt) == S_OK) { - AM_MEDIA_TYPE *orig = &This->sink.pin.mt; + AM_MEDIA_TYPE *orig = &filter->sink.pin.mt; WAVEFORMATEX *origfmt = (WAVEFORMATEX *)orig->pbFormat; WAVEFORMATEX *newfmt = (WAVEFORMATEX *)amt->pbFormat; @@ -305,7 +305,7 @@ static HRESULT DSoundRender_PrepareReceive(struct dsound_render *This, IMediaSam { if (origfmt->nSamplesPerSec != newfmt->nSamplesPerSec) { - hr = IDirectSoundBuffer_SetFrequency(This->dsbuffer, + hr = IDirectSoundBuffer_SetFrequency(filter->dsbuffer, newfmt->nSamplesPerSec); if (FAILED(hr)) return VFW_E_TYPE_NOT_ACCEPTED; @@ -320,7 +320,7 @@ static HRESULT DSoundRender_PrepareReceive(struct dsound_render *This, IMediaSam return S_OK; } -static HRESULT DSoundRender_DoRenderSample(struct dsound_render *This, IMediaSample *pSample) +static HRESULT DSoundRender_DoRenderSample(struct dsound_render *filter, IMediaSample *pSample) { LPBYTE pbSrcStream = NULL; LONG cbSrcStream = 0; @@ -347,7 +347,7 @@ static HRESULT DSoundRender_DoRenderSample(struct dsound_render *This, IMediaSam } cbSrcStream = IMediaSample_GetActualDataLength(pSample); - return DSoundRender_SendSampleData(This, tStart, tStop, pbSrcStream, cbSrcStream); + return DSoundRender_SendSampleData(filter, tStart, tStop, pbSrcStream, cbSrcStream); } static HRESULT WINAPI dsound_render_sink_Receive(struct strmbase_sink *iface, IMediaSample *sample) @@ -397,42 +397,42 @@ static HRESULT dsound_render_sink_query_accept(struct strmbase_pin *iface, const static HRESULT dsound_render_sink_connect(struct strmbase_sink *iface, IPin *peer, const AM_MEDIA_TYPE *mt) { - struct dsound_render *This = impl_from_strmbase_pin(&iface->pin); + struct dsound_render *filter = impl_from_strmbase_pin(&iface->pin); const WAVEFORMATEX *format = (WAVEFORMATEX *)mt->pbFormat; HRESULT hr = S_OK; DSBUFFERDESC buf_desc; - This->buf_size = format->nAvgBytesPerSec; + filter->buf_size = format->nAvgBytesPerSec; memset(&buf_desc,0,sizeof(DSBUFFERDESC)); buf_desc.dwSize = sizeof(DSBUFFERDESC); buf_desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2; - buf_desc.dwBufferBytes = This->buf_size; + buf_desc.dwBufferBytes = filter->buf_size; buf_desc.lpwfxFormat = (WAVEFORMATEX *)format; - hr = IDirectSound8_CreateSoundBuffer(This->dsound, &buf_desc, &This->dsbuffer, NULL); - This->writepos = This->buf_size; + hr = IDirectSound8_CreateSoundBuffer(filter->dsound, &buf_desc, &filter->dsbuffer, NULL); + filter->writepos = filter->buf_size; if (FAILED(hr)) ERR("Failed to create sound buffer, hr %#lx.\n", hr); if (SUCCEEDED(hr)) { - hr = IDirectSoundBuffer_SetVolume(This->dsbuffer, This->volume); + hr = IDirectSoundBuffer_SetVolume(filter->dsbuffer, filter->volume); if (FAILED(hr)) - ERR("Failed to set volume to %ld, hr %#lx.\n", This->volume, hr); + ERR("Failed to set volume to %ld, hr %#lx.\n", filter->volume, hr); - hr = IDirectSoundBuffer_SetPan(This->dsbuffer, This->pan); + hr = IDirectSoundBuffer_SetPan(filter->dsbuffer, filter->pan); if (FAILED(hr)) - ERR("Failed to set pan to %ld, hr %#lx.\n", This->pan, hr); + ERR("Failed to set pan to %ld, hr %#lx.\n", filter->pan, hr); hr = S_OK; } if (FAILED(hr) && hr != VFW_E_ALREADY_CONNECTED) { - if (This->dsbuffer) - IDirectSoundBuffer_Release(This->dsbuffer); - This->dsbuffer = NULL; + if (filter->dsbuffer) + IDirectSoundBuffer_Release(filter->dsbuffer); + filter->dsbuffer = NULL; } return hr; @@ -440,13 +440,13 @@ static HRESULT dsound_render_sink_connect(struct strmbase_sink *iface, IPin *pee static void dsound_render_sink_disconnect(struct strmbase_sink *iface) { - struct dsound_render *This = impl_from_strmbase_pin(&iface->pin); + struct dsound_render *filter = impl_from_strmbase_pin(&iface->pin); TRACE("(%p)->()\n", iface); - if (This->dsbuffer) - IDirectSoundBuffer_Release(This->dsbuffer); - This->dsbuffer = NULL; + if (filter->dsbuffer) + IDirectSoundBuffer_Release(filter->dsbuffer); + filter->dsbuffer = NULL; } static HRESULT dsound_render_sink_eos(struct strmbase_sink *iface) @@ -666,27 +666,27 @@ static const struct strmbase_filter_ops filter_ops = static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface, REFIID riid, LPVOID*ppvObj) { - struct dsound_render *This = impl_from_IBasicAudio(iface); + struct dsound_render *filter = impl_from_IBasicAudio(iface); - TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj); + TRACE("(%p/%p)->(%s, %p)\n", filter, iface, debugstr_guid(riid), ppvObj); - return IUnknown_QueryInterface(This->filter.outer_unk, riid, ppvObj); + return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppvObj); } static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) { - struct dsound_render *This = impl_from_IBasicAudio(iface); + struct dsound_render *filter = impl_from_IBasicAudio(iface); - TRACE("(%p/%p)->()\n", This, iface); + TRACE("(%p/%p)->()\n", filter, iface); - return IUnknown_AddRef(This->filter.outer_unk); + return IUnknown_AddRef(filter->filter.outer_unk); } static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) { - struct dsound_render *This = impl_from_IBasicAudio(iface); + struct dsound_render *filter = impl_from_IBasicAudio(iface); - TRACE("(%p/%p)->()\n", This, iface); + TRACE("(%p/%p)->()\n", filter, iface); - return IUnknown_Release(This->filter.outer_unk); + return IUnknown_Release(filter->filter.outer_unk); } HRESULT WINAPI basic_audio_GetTypeInfoCount(IBasicAudio *iface, UINT *count) @@ -739,63 +739,63 @@ static HRESULT WINAPI basic_audio_Invoke(IBasicAudio *iface, DISPID id, REFIID i static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface, LONG lVolume) { - struct dsound_render *This = impl_from_IBasicAudio(iface); + struct dsound_render *filter = impl_from_IBasicAudio(iface); - TRACE("filter %p, volume %ld.\n", This, lVolume); + TRACE("filter %p, volume %ld.\n", filter, lVolume); if (lVolume > DSBVOLUME_MAX || lVolume < DSBVOLUME_MIN) return E_INVALIDARG; - if (This->dsbuffer) { - if (FAILED(IDirectSoundBuffer_SetVolume(This->dsbuffer, lVolume))) + if (filter->dsbuffer) { + if (FAILED(IDirectSoundBuffer_SetVolume(filter->dsbuffer, lVolume))) return E_FAIL; } - This->volume = lVolume; + filter->volume = lVolume; return S_OK; } static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface, LONG *plVolume) { - struct dsound_render *This = impl_from_IBasicAudio(iface); + struct dsound_render *filter = impl_from_IBasicAudio(iface); - TRACE("(%p/%p)->(%p)\n", This, iface, plVolume); + TRACE("(%p/%p)->(%p)\n", filter, iface, plVolume); if (!plVolume) return E_POINTER; - *plVolume = This->volume; + *plVolume = filter->volume; return S_OK; } static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface, LONG lBalance) { - struct dsound_render *This = impl_from_IBasicAudio(iface); + struct dsound_render *filter = impl_from_IBasicAudio(iface); - TRACE("filter %p, balance %ld.\n", This, lBalance); + TRACE("filter %p, balance %ld.\n", filter, lBalance); if (lBalance < DSBPAN_LEFT || lBalance > DSBPAN_RIGHT) return E_INVALIDARG; - if (This->dsbuffer) { - if (FAILED(IDirectSoundBuffer_SetPan(This->dsbuffer, lBalance))) + if (filter->dsbuffer) { + if (FAILED(IDirectSoundBuffer_SetPan(filter->dsbuffer, lBalance))) return E_FAIL; } - This->pan = lBalance; + filter->pan = lBalance; return S_OK; } static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface, LONG *plBalance) { - struct dsound_render *This = impl_from_IBasicAudio(iface); + struct dsound_render *filter = impl_from_IBasicAudio(iface); - TRACE("(%p/%p)->(%p)\n", This, iface, plBalance); + TRACE("(%p/%p)->(%p)\n", filter, iface, plBalance); if (!plBalance) return E_POINTER; - *plBalance = This->pan; + *plBalance = filter->pan; return S_OK; } @@ -819,100 +819,100 @@ static HRESULT WINAPI AMDirectSound_QueryInterface(IAMDirectSound *iface, REFIID riid, LPVOID*ppvObj) { - struct dsound_render *This = impl_from_IAMDirectSound(iface); + struct dsound_render *filter = impl_from_IAMDirectSound(iface); - TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj); + TRACE("(%p/%p)->(%s, %p)\n", filter, iface, debugstr_guid(riid), ppvObj); - return IUnknown_QueryInterface(This->filter.outer_unk, riid, ppvObj); + return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppvObj); } static ULONG WINAPI AMDirectSound_AddRef(IAMDirectSound *iface) { - struct dsound_render *This = impl_from_IAMDirectSound(iface); + struct dsound_render *filter = impl_from_IAMDirectSound(iface); - TRACE("(%p/%p)->()\n", This, iface); + TRACE("(%p/%p)->()\n", filter, iface); - return IUnknown_AddRef(This->filter.outer_unk); + return IUnknown_AddRef(filter->filter.outer_unk); } static ULONG WINAPI AMDirectSound_Release(IAMDirectSound *iface) { - struct dsound_render *This = impl_from_IAMDirectSound(iface); + struct dsound_render *filter = impl_from_IAMDirectSound(iface); - TRACE("(%p/%p)->()\n", This, iface); + TRACE("(%p/%p)->()\n", filter, iface); - return IUnknown_Release(This->filter.outer_unk); + return IUnknown_Release(filter->filter.outer_unk); } /*** IAMDirectSound methods ***/ static HRESULT WINAPI AMDirectSound_GetDirectSoundInterface(IAMDirectSound *iface, IDirectSound **ds) { - struct dsound_render *This = impl_from_IAMDirectSound(iface); + struct dsound_render *filter = impl_from_IAMDirectSound(iface); - FIXME("(%p/%p)->(%p): stub\n", This, iface, ds); + FIXME("(%p/%p)->(%p): stub\n", filter, iface, ds); return E_NOTIMPL; } static HRESULT WINAPI AMDirectSound_GetPrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf) { - struct dsound_render *This = impl_from_IAMDirectSound(iface); + struct dsound_render *filter = impl_from_IAMDirectSound(iface); - FIXME("(%p/%p)->(%p): stub\n", This, iface, buf); + FIXME("(%p/%p)->(%p): stub\n", filter, iface, buf); return E_NOTIMPL; } static HRESULT WINAPI AMDirectSound_GetSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf) { - struct dsound_render *This = impl_from_IAMDirectSound(iface); + struct dsound_render *filter = impl_from_IAMDirectSound(iface); - FIXME("(%p/%p)->(%p): stub\n", This, iface, buf); + FIXME("(%p/%p)->(%p): stub\n", filter, iface, buf); return E_NOTIMPL; } static HRESULT WINAPI AMDirectSound_ReleaseDirectSoundInterface(IAMDirectSound *iface, IDirectSound *ds) { - struct dsound_render *This = impl_from_IAMDirectSound(iface); + struct dsound_render *filter = impl_from_IAMDirectSound(iface); - FIXME("(%p/%p)->(%p): stub\n", This, iface, ds); + FIXME("(%p/%p)->(%p): stub\n", filter, iface, ds); return E_NOTIMPL; } static HRESULT WINAPI AMDirectSound_ReleasePrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf) { - struct dsound_render *This = impl_from_IAMDirectSound(iface); + struct dsound_render *filter = impl_from_IAMDirectSound(iface); - FIXME("(%p/%p)->(%p): stub\n", This, iface, buf); + FIXME("(%p/%p)->(%p): stub\n", filter, iface, buf); return E_NOTIMPL; } static HRESULT WINAPI AMDirectSound_ReleaseSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf) { - struct dsound_render *This = impl_from_IAMDirectSound(iface); + struct dsound_render *filter = impl_from_IAMDirectSound(iface); - FIXME("(%p/%p)->(%p): stub\n", This, iface, buf); + FIXME("(%p/%p)->(%p): stub\n", filter, iface, buf); return E_NOTIMPL; } static HRESULT WINAPI AMDirectSound_SetFocusWindow(IAMDirectSound *iface, HWND hwnd, BOOL bgaudible) { - struct dsound_render *This = impl_from_IAMDirectSound(iface); + struct dsound_render *filter = impl_from_IAMDirectSound(iface); - FIXME("(%p/%p)->(%p,%d): stub\n", This, iface, hwnd, bgaudible); + FIXME("(%p/%p)->(%p,%d): stub\n", filter, iface, hwnd, bgaudible); return E_NOTIMPL; } static HRESULT WINAPI AMDirectSound_GetFocusWindow(IAMDirectSound *iface, HWND *hwnd, BOOL *bgaudible) { - struct dsound_render *This = impl_from_IAMDirectSound(iface); + struct dsound_render *filter = impl_from_IAMDirectSound(iface); - FIXME("(%p/%p)->(%p,%p): stub\n", This, iface, hwnd, bgaudible); + FIXME("(%p/%p)->(%p,%p): stub\n", filter, iface, hwnd, bgaudible); return E_NOTIMPL; } From d7d05c16ed68665f0537c2194984483f8f750c30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 14 Sep 2022 12:16:57 +0200 Subject: [PATCH 0156/2777] quartz: Add missing static qualifier to DirectSound Renderer Filter methods. CW-Bug-Id: #21147 --- dlls/quartz/dsoundrender.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c index 2b620ceba3c..eb804b31178 100644 --- a/dlls/quartz/dsoundrender.c +++ b/dlls/quartz/dsoundrender.c @@ -689,21 +689,21 @@ static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) { return IUnknown_Release(filter->filter.outer_unk); } -HRESULT WINAPI basic_audio_GetTypeInfoCount(IBasicAudio *iface, UINT *count) +static HRESULT WINAPI basic_audio_GetTypeInfoCount(IBasicAudio *iface, UINT *count) { TRACE("iface %p, count %p.\n", iface, count); *count = 1; return S_OK; } -HRESULT WINAPI basic_audio_GetTypeInfo(IBasicAudio *iface, UINT index, +static HRESULT WINAPI basic_audio_GetTypeInfo(IBasicAudio *iface, UINT index, LCID lcid, ITypeInfo **typeinfo) { TRACE("iface %p, index %u, lcid %#lx, typeinfo %p.\n", iface, index, lcid, typeinfo); return strmbase_get_typeinfo(IBasicAudio_tid, typeinfo); } -HRESULT WINAPI basic_audio_GetIDsOfNames(IBasicAudio *iface, REFIID iid, +static HRESULT WINAPI basic_audio_GetIDsOfNames(IBasicAudio *iface, REFIID iid, LPOLESTR *names, UINT count, LCID lcid, DISPID *ids) { ITypeInfo *typeinfo; From bc8041fd9ecb70429520abd7de280e9868ad3b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 14 Sep 2022 12:19:38 +0200 Subject: [PATCH 0157/2777] quartz: Fix brace wrapping in DirectSound Renderer Filter. CW-Bug-Id: #21147 --- dlls/quartz/dsoundrender.c | 90 ++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 37 deletions(-) diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c index eb804b31178..9f1499c90d8 100644 --- a/dlls/quartz/dsoundrender.c +++ b/dlls/quartz/dsoundrender.c @@ -125,7 +125,8 @@ static void DSoundRender_UpdatePositions(struct dsound_render *filter, DWORD *se else adv = playpos - old_playpos; filter->last_playpos = playpos; - if (adv) { + if (adv) + { TRACE("Moving from %lu to %lu: clearing %lu bytes.\n", old_playpos, playpos, adv); IDirectSoundBuffer_Lock(filter->dsbuffer, old_playpos, adv, (void**)&buf1, &size1, (void**)&buf2, &size2, 0); memset(buf1, wfx->wBitsPerSample == 8 ? 128 : 0, size1); @@ -133,13 +134,16 @@ static void DSoundRender_UpdatePositions(struct dsound_render *filter, DWORD *se IDirectSoundBuffer_Unlock(filter->dsbuffer, buf1, size1, buf2, size2); } *minwritepos = writepos; - if (!writepos_set || old_writepos < writepos) { - if (writepos_set) { + if (!writepos_set || old_writepos < writepos) + { + if (writepos_set) + { filter->writepos = filter->buf_size; FIXME("Underrun of data occurred!\n"); } *seqwritepos = writepos; - } else + } + else *seqwritepos = filter->writepos; } @@ -156,14 +160,16 @@ static HRESULT DSoundRender_GetWritePos(struct dsound_render *filter, { IReferenceClock_GetTime(filter->filter.clock, &cur); cur -= filter->stream_start; - } else + } + else write_at = -1; if (writepos == min_writepos) max_lag = 0; *skip = 0; - if (write_at < 0) { + if (write_at < 0) + { *ret_writepos = writepos; goto end; } @@ -177,10 +183,13 @@ static HRESULT DSoundRender_GetWritePos(struct dsound_render *filter, /* cur: current time of play position */ /* writepos_t: current time of our pointer play position */ delta_t = write_at - writepos_t; - if (delta_t >= -max_lag && delta_t <= max_lag) { + if (delta_t >= -max_lag && delta_t <= max_lag) + { TRACE("Continuing from old position\n"); *ret_writepos = writepos; - } else if (delta_t < 0) { + } + else if (delta_t < 0) + { REFERENCE_TIME past, min_writepos_t; WARN("Delta too big %s/%s, overwriting old data or even skipping\n", debugstr_time(delta_t), debugstr_time(max_lag)); if (min_writepos >= playpos) @@ -188,17 +197,22 @@ static HRESULT DSoundRender_GetWritePos(struct dsound_render *filter, else min_writepos_t = cur + time_from_pos(filter, filter->buf_size - playpos + min_writepos); past = min_writepos_t - write_at; - if (past >= 0) { + if (past >= 0) + { DWORD skipbytes = pos_from_time(filter, past); WARN("Skipping %lu bytes.\n", skipbytes); *skip = skipbytes; *ret_writepos = min_writepos; - } else { + } + else + { DWORD aheadbytes = pos_from_time(filter, -past); WARN("Advancing %lu bytes.\n", aheadbytes); *ret_writepos = (min_writepos + aheadbytes) % filter->buf_size; } - } else /* delta_t > 0 */ { + } + else /* delta_t > 0 */ + { DWORD aheadbytes; WARN("Delta too big %s/%s, too far ahead\n", debugstr_time(delta_t), debugstr_time(max_lag)); aheadbytes = pos_from_time(filter, delta_t); @@ -212,7 +226,8 @@ static HRESULT DSoundRender_GetWritePos(struct dsound_render *filter, *pfree = playpos - *ret_writepos; else *pfree = filter->buf_size + playpos - *ret_writepos; - if (time_from_pos(filter, filter->buf_size - *pfree) >= DSoundRenderer_Max_Fill) { + if (time_from_pos(filter, filter->buf_size - *pfree) >= DSoundRenderer_Max_Fill) + { TRACE("Blocked: too full %s / %s\n", debugstr_time(time_from_pos(filter, filter->buf_size - *pfree)), debugstr_time(DSoundRenderer_Max_Fill)); return S_FALSE; @@ -240,7 +255,8 @@ static HRESULT DSoundRender_SendSampleData(struct dsound_render *filter, { HRESULT hr; - while (size && filter->filter.state != State_Stopped) { + while (size && filter->filter.state != State_Stopped) + { DWORD writepos, skip = 0, free, size1, size2, ret; BYTE *buf1, *buf2; @@ -249,7 +265,8 @@ static HRESULT DSoundRender_SendSampleData(struct dsound_render *filter, else hr = S_FALSE; - if (hr != S_OK) { + if (hr != S_OK) + { ret = WaitForSingleObject(filter->flush_event, 10); if (filter->sink.flushing || filter->filter.state == State_Stopped) return filter->filter.state == State_Paused ? S_OK : VFW_E_WRONG_STATE; @@ -267,7 +284,8 @@ static HRESULT DSoundRender_SendSampleData(struct dsound_render *filter, size -= skip; hr = IDirectSoundBuffer_Lock(filter->dsbuffer, writepos, min(free, size), (void**)&buf1, &size1, (void**)&buf2, &size2, 0); - if (hr != DS_OK) { + if (hr != DS_OK) + { ERR("Failed to lock sound buffer, hr %#lx.\n", hr); break; } @@ -335,7 +353,8 @@ static HRESULT DSoundRender_DoRenderSample(struct dsound_render *filter, IMediaS } hr = IMediaSample_GetTime(pSample, &tStart, &tStop); - if (FAILED(hr)) { + if (FAILED(hr)) + { ERR("Failed to get sample time, hr %#lx.\n", hr); tStart = tStop = -1; } @@ -663,9 +682,8 @@ static const struct strmbase_filter_ops filter_ops = }; /*** IUnknown methods ***/ -static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface, - REFIID riid, - LPVOID*ppvObj) { +static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface, REFIID riid, LPVOID*ppvObj) +{ struct dsound_render *filter = impl_from_IBasicAudio(iface); TRACE("(%p/%p)->(%s, %p)\n", filter, iface, debugstr_guid(riid), ppvObj); @@ -673,7 +691,8 @@ static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface, return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppvObj); } -static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) { +static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) +{ struct dsound_render *filter = impl_from_IBasicAudio(iface); TRACE("(%p/%p)->()\n", filter, iface); @@ -681,7 +700,8 @@ static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) { return IUnknown_AddRef(filter->filter.outer_unk); } -static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) { +static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) +{ struct dsound_render *filter = impl_from_IBasicAudio(iface); TRACE("(%p/%p)->()\n", filter, iface); @@ -737,8 +757,8 @@ static HRESULT WINAPI basic_audio_Invoke(IBasicAudio *iface, DISPID id, REFIID i return hr; } -static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface, - LONG lVolume) { +static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface, LONG lVolume) +{ struct dsound_render *filter = impl_from_IBasicAudio(iface); TRACE("filter %p, volume %ld.\n", filter, lVolume); @@ -746,17 +766,15 @@ static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface, if (lVolume > DSBVOLUME_MAX || lVolume < DSBVOLUME_MIN) return E_INVALIDARG; - if (filter->dsbuffer) { - if (FAILED(IDirectSoundBuffer_SetVolume(filter->dsbuffer, lVolume))) - return E_FAIL; - } + if (filter->dsbuffer && FAILED(IDirectSoundBuffer_SetVolume(filter->dsbuffer, lVolume))) + return E_FAIL; filter->volume = lVolume; return S_OK; } -static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface, - LONG *plVolume) { +static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface, LONG *plVolume) +{ struct dsound_render *filter = impl_from_IBasicAudio(iface); TRACE("(%p/%p)->(%p)\n", filter, iface, plVolume); @@ -768,8 +786,8 @@ static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface, return S_OK; } -static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface, - LONG lBalance) { +static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface, LONG lBalance) +{ struct dsound_render *filter = impl_from_IBasicAudio(iface); TRACE("filter %p, balance %ld.\n", filter, lBalance); @@ -777,17 +795,15 @@ static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface, if (lBalance < DSBPAN_LEFT || lBalance > DSBPAN_RIGHT) return E_INVALIDARG; - if (filter->dsbuffer) { - if (FAILED(IDirectSoundBuffer_SetPan(filter->dsbuffer, lBalance))) - return E_FAIL; - } + if (filter->dsbuffer && FAILED(IDirectSoundBuffer_SetPan(filter->dsbuffer, lBalance))) + return E_FAIL; filter->pan = lBalance; return S_OK; } -static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface, - LONG *plBalance) { +static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface, LONG *plBalance) +{ struct dsound_render *filter = impl_from_IBasicAudio(iface); TRACE("(%p/%p)->(%p)\n", filter, iface, plBalance); From 9cc55cfea6871fbe5c981c7ddec313f0245c57cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 14 Sep 2022 12:20:19 +0200 Subject: [PATCH 0158/2777] quartz: Rename DirectSound Renderer Filter methods to be more consistent. CW-Bug-Id: #21147 --- dlls/quartz/dsoundrender.c | 145 ++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 75 deletions(-) diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c index 9f1499c90d8..f27efd16698 100644 --- a/dlls/quartz/dsoundrender.c +++ b/dlls/quartz/dsoundrender.c @@ -681,17 +681,16 @@ static const struct strmbase_filter_ops filter_ops = .filter_wait_state = dsound_render_wait_state, }; -/*** IUnknown methods ***/ -static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface, REFIID riid, LPVOID*ppvObj) +static HRESULT WINAPI basic_audio_QueryInterface(IBasicAudio *iface, REFIID riid, void **out) { struct dsound_render *filter = impl_from_IBasicAudio(iface); - TRACE("(%p/%p)->(%s, %p)\n", filter, iface, debugstr_guid(riid), ppvObj); + TRACE("(%p/%p)->(%s, %p)\n", filter, iface, debugstr_guid(riid), out); - return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppvObj); + return IUnknown_QueryInterface(filter->filter.outer_unk, riid, out); } -static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) +static ULONG WINAPI basic_audio_AddRef(IBasicAudio *iface) { struct dsound_render *filter = impl_from_IBasicAudio(iface); @@ -700,7 +699,7 @@ static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) return IUnknown_AddRef(filter->filter.outer_unk); } -static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) +static ULONG WINAPI basic_audio_Release(IBasicAudio *iface) { struct dsound_render *filter = impl_from_IBasicAudio(iface); @@ -757,92 +756,89 @@ static HRESULT WINAPI basic_audio_Invoke(IBasicAudio *iface, DISPID id, REFIID i return hr; } -static HRESULT WINAPI Basicaudio_put_Volume(IBasicAudio *iface, LONG lVolume) +static HRESULT WINAPI basic_audio_put_Volume(IBasicAudio *iface, LONG volume) { struct dsound_render *filter = impl_from_IBasicAudio(iface); - TRACE("filter %p, volume %ld.\n", filter, lVolume); + TRACE("filter %p, volume %ld.\n", filter, volume); - if (lVolume > DSBVOLUME_MAX || lVolume < DSBVOLUME_MIN) + if (volume > DSBVOLUME_MAX || volume < DSBVOLUME_MIN) return E_INVALIDARG; - if (filter->dsbuffer && FAILED(IDirectSoundBuffer_SetVolume(filter->dsbuffer, lVolume))) + if (filter->dsbuffer && FAILED(IDirectSoundBuffer_SetVolume(filter->dsbuffer, volume))) return E_FAIL; - filter->volume = lVolume; + filter->volume = volume; return S_OK; } -static HRESULT WINAPI Basicaudio_get_Volume(IBasicAudio *iface, LONG *plVolume) +static HRESULT WINAPI basic_audio_get_Volume(IBasicAudio *iface, LONG *volume) { struct dsound_render *filter = impl_from_IBasicAudio(iface); - TRACE("(%p/%p)->(%p)\n", filter, iface, plVolume); + TRACE("(%p/%p)->(%p)\n", filter, iface, volume); - if (!plVolume) + if (!volume) return E_POINTER; - *plVolume = filter->volume; + *volume = filter->volume; return S_OK; } -static HRESULT WINAPI Basicaudio_put_Balance(IBasicAudio *iface, LONG lBalance) +static HRESULT WINAPI basic_audio_put_Balance(IBasicAudio *iface, LONG balance) { struct dsound_render *filter = impl_from_IBasicAudio(iface); - TRACE("filter %p, balance %ld.\n", filter, lBalance); + TRACE("filter %p, balance %ld.\n", filter, balance); - if (lBalance < DSBPAN_LEFT || lBalance > DSBPAN_RIGHT) + if (balance < DSBPAN_LEFT || balance > DSBPAN_RIGHT) return E_INVALIDARG; - if (filter->dsbuffer && FAILED(IDirectSoundBuffer_SetPan(filter->dsbuffer, lBalance))) + if (filter->dsbuffer && FAILED(IDirectSoundBuffer_SetPan(filter->dsbuffer, balance))) return E_FAIL; - filter->pan = lBalance; + filter->pan = balance; return S_OK; } -static HRESULT WINAPI Basicaudio_get_Balance(IBasicAudio *iface, LONG *plBalance) +static HRESULT WINAPI basic_audio_get_Balance(IBasicAudio *iface, LONG *balance) { struct dsound_render *filter = impl_from_IBasicAudio(iface); - TRACE("(%p/%p)->(%p)\n", filter, iface, plBalance); + TRACE("(%p/%p)->(%p)\n", filter, iface, balance); - if (!plBalance) + if (!balance) return E_POINTER; - *plBalance = filter->pan; + *balance = filter->pan; return S_OK; } -static const IBasicAudioVtbl IBasicAudio_Vtbl = +static const IBasicAudioVtbl basic_audio_vtbl = { - Basicaudio_QueryInterface, - Basicaudio_AddRef, - Basicaudio_Release, + basic_audio_QueryInterface, + basic_audio_AddRef, + basic_audio_Release, basic_audio_GetTypeInfoCount, basic_audio_GetTypeInfo, basic_audio_GetIDsOfNames, basic_audio_Invoke, - Basicaudio_put_Volume, - Basicaudio_get_Volume, - Basicaudio_put_Balance, - Basicaudio_get_Balance + basic_audio_put_Volume, + basic_audio_get_Volume, + basic_audio_put_Balance, + basic_audio_get_Balance, }; -/*** IUnknown methods ***/ -static HRESULT WINAPI AMDirectSound_QueryInterface(IAMDirectSound *iface, - REFIID riid, - LPVOID*ppvObj) +static HRESULT WINAPI am_direct_sound_QueryInterface(IAMDirectSound *iface, REFIID riid, void **out) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); - TRACE("(%p/%p)->(%s, %p)\n", filter, iface, debugstr_guid(riid), ppvObj); + TRACE("(%p/%p)->(%s, %p)\n", filter, iface, debugstr_guid(riid), out); - return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppvObj); + return IUnknown_QueryInterface(filter->filter.outer_unk, riid, out); } -static ULONG WINAPI AMDirectSound_AddRef(IAMDirectSound *iface) +static ULONG WINAPI am_direct_sound_AddRef(IAMDirectSound *iface) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); @@ -851,7 +847,7 @@ static ULONG WINAPI AMDirectSound_AddRef(IAMDirectSound *iface) return IUnknown_AddRef(filter->filter.outer_unk); } -static ULONG WINAPI AMDirectSound_Release(IAMDirectSound *iface) +static ULONG WINAPI am_direct_sound_Release(IAMDirectSound *iface) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); @@ -860,8 +856,7 @@ static ULONG WINAPI AMDirectSound_Release(IAMDirectSound *iface) return IUnknown_Release(filter->filter.outer_unk); } -/*** IAMDirectSound methods ***/ -static HRESULT WINAPI AMDirectSound_GetDirectSoundInterface(IAMDirectSound *iface, IDirectSound **ds) +static HRESULT WINAPI am_direct_sound_GetDirectSoundInterface(IAMDirectSound *iface, IDirectSound **ds) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); @@ -870,7 +865,7 @@ static HRESULT WINAPI AMDirectSound_GetDirectSoundInterface(IAMDirectSound *ifac return E_NOTIMPL; } -static HRESULT WINAPI AMDirectSound_GetPrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf) +static HRESULT WINAPI am_direct_sound_GetPrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); @@ -879,7 +874,7 @@ static HRESULT WINAPI AMDirectSound_GetPrimaryBufferInterface(IAMDirectSound *if return E_NOTIMPL; } -static HRESULT WINAPI AMDirectSound_GetSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf) +static HRESULT WINAPI am_direct_sound_GetSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); @@ -888,7 +883,7 @@ static HRESULT WINAPI AMDirectSound_GetSecondaryBufferInterface(IAMDirectSound * return E_NOTIMPL; } -static HRESULT WINAPI AMDirectSound_ReleaseDirectSoundInterface(IAMDirectSound *iface, IDirectSound *ds) +static HRESULT WINAPI am_direct_sound_ReleaseDirectSoundInterface(IAMDirectSound *iface, IDirectSound *ds) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); @@ -897,7 +892,7 @@ static HRESULT WINAPI AMDirectSound_ReleaseDirectSoundInterface(IAMDirectSound * return E_NOTIMPL; } -static HRESULT WINAPI AMDirectSound_ReleasePrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf) +static HRESULT WINAPI am_direct_sound_ReleasePrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); @@ -906,7 +901,7 @@ static HRESULT WINAPI AMDirectSound_ReleasePrimaryBufferInterface(IAMDirectSound return E_NOTIMPL; } -static HRESULT WINAPI AMDirectSound_ReleaseSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf) +static HRESULT WINAPI am_direct_sound_ReleaseSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); @@ -915,7 +910,7 @@ static HRESULT WINAPI AMDirectSound_ReleaseSecondaryBufferInterface(IAMDirectSou return E_NOTIMPL; } -static HRESULT WINAPI AMDirectSound_SetFocusWindow(IAMDirectSound *iface, HWND hwnd, BOOL bgaudible) +static HRESULT WINAPI am_direct_sound_SetFocusWindow(IAMDirectSound *iface, HWND hwnd, BOOL bgaudible) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); @@ -924,7 +919,7 @@ static HRESULT WINAPI AMDirectSound_SetFocusWindow(IAMDirectSound *iface, HWND h return E_NOTIMPL; } -static HRESULT WINAPI AMDirectSound_GetFocusWindow(IAMDirectSound *iface, HWND *hwnd, BOOL *bgaudible) +static HRESULT WINAPI am_direct_sound_GetFocusWindow(IAMDirectSound *iface, HWND *hwnd, BOOL *bgaudible) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); @@ -933,19 +928,19 @@ static HRESULT WINAPI AMDirectSound_GetFocusWindow(IAMDirectSound *iface, HWND * return E_NOTIMPL; } -static const IAMDirectSoundVtbl IAMDirectSound_Vtbl = +static const IAMDirectSoundVtbl am_direct_sound_vtbl = { - AMDirectSound_QueryInterface, - AMDirectSound_AddRef, - AMDirectSound_Release, - AMDirectSound_GetDirectSoundInterface, - AMDirectSound_GetPrimaryBufferInterface, - AMDirectSound_GetSecondaryBufferInterface, - AMDirectSound_ReleaseDirectSoundInterface, - AMDirectSound_ReleasePrimaryBufferInterface, - AMDirectSound_ReleaseSecondaryBufferInterface, - AMDirectSound_SetFocusWindow, - AMDirectSound_GetFocusWindow + am_direct_sound_QueryInterface, + am_direct_sound_AddRef, + am_direct_sound_Release, + am_direct_sound_GetDirectSoundInterface, + am_direct_sound_GetPrimaryBufferInterface, + am_direct_sound_GetSecondaryBufferInterface, + am_direct_sound_ReleaseDirectSoundInterface, + am_direct_sound_ReleasePrimaryBufferInterface, + am_direct_sound_ReleaseSecondaryBufferInterface, + am_direct_sound_SetFocusWindow, + am_direct_sound_GetFocusWindow, }; static struct dsound_render *impl_from_IQualityControl(IQualityControl *iface) @@ -953,26 +948,26 @@ static struct dsound_render *impl_from_IQualityControl(IQualityControl *iface) return CONTAINING_RECORD(iface, struct dsound_render, IQualityControl_iface); } -static HRESULT WINAPI dsound_render_qc_QueryInterface(IQualityControl *iface, +static HRESULT WINAPI quality_control_QueryInterface(IQualityControl *iface, REFIID iid, void **out) { struct dsound_render *filter = impl_from_IQualityControl(iface); return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out); } -static ULONG WINAPI dsound_render_qc_AddRef(IQualityControl *iface) +static ULONG WINAPI quality_control_AddRef(IQualityControl *iface) { struct dsound_render *filter = impl_from_IQualityControl(iface); return IUnknown_AddRef(filter->filter.outer_unk); } -static ULONG WINAPI dsound_render_qc_Release(IQualityControl *iface) +static ULONG WINAPI quality_control_Release(IQualityControl *iface) { struct dsound_render *filter = impl_from_IQualityControl(iface); return IUnknown_Release(filter->filter.outer_unk); } -static HRESULT WINAPI dsound_render_qc_Notify(IQualityControl *iface, +static HRESULT WINAPI quality_control_Notify(IQualityControl *iface, IBaseFilter *sender, Quality q) { struct dsound_render *filter = impl_from_IQualityControl(iface); @@ -983,7 +978,7 @@ static HRESULT WINAPI dsound_render_qc_Notify(IQualityControl *iface, return E_NOTIMPL; } -static HRESULT WINAPI dsound_render_qc_SetSink(IQualityControl *iface, IQualityControl *sink) +static HRESULT WINAPI quality_control_SetSink(IQualityControl *iface, IQualityControl *sink) { struct dsound_render *filter = impl_from_IQualityControl(iface); @@ -992,13 +987,13 @@ static HRESULT WINAPI dsound_render_qc_SetSink(IQualityControl *iface, IQualityC return E_NOTIMPL; } -static const IQualityControlVtbl dsound_render_qc_vtbl = +static const IQualityControlVtbl quality_control_vtbl = { - dsound_render_qc_QueryInterface, - dsound_render_qc_AddRef, - dsound_render_qc_Release, - dsound_render_qc_Notify, - dsound_render_qc_SetSink, + quality_control_QueryInterface, + quality_control_AddRef, + quality_control_Release, + quality_control_Notify, + quality_control_SetSink, }; HRESULT dsound_render_create(IUnknown *outer, IUnknown **out) @@ -1057,9 +1052,9 @@ HRESULT dsound_render_create(IUnknown *outer, IUnknown **out) object->state_event = CreateEventW(NULL, TRUE, TRUE, NULL); object->flush_event = CreateEventW(NULL, TRUE, TRUE, NULL); - object->IBasicAudio_iface.lpVtbl = &IBasicAudio_Vtbl; - object->IAMDirectSound_iface.lpVtbl = &IAMDirectSound_Vtbl; - object->IQualityControl_iface.lpVtbl = &dsound_render_qc_vtbl; + object->IBasicAudio_iface.lpVtbl = &basic_audio_vtbl; + object->IAMDirectSound_iface.lpVtbl = &am_direct_sound_vtbl; + object->IQualityControl_iface.lpVtbl = &quality_control_vtbl; TRACE("Created DirectSound renderer %p.\n", object); *out = &object->filter.IUnknown_inner; From 3dfc6861bf22b8cbbb1250f4fe4ebf9679fea527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 14 Sep 2022 12:14:53 +0200 Subject: [PATCH 0159/2777] quartz: Make DirectSound Renderer Filter traces more consistent. CW-Bug-Id: #21147 --- dlls/quartz/dsoundrender.c | 88 ++++++++++++++------------------------ 1 file changed, 32 insertions(+), 56 deletions(-) diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c index f27efd16698..ad0b19bfea8 100644 --- a/dlls/quartz/dsoundrender.c +++ b/dlls/quartz/dsoundrender.c @@ -375,6 +375,8 @@ static HRESULT WINAPI dsound_render_sink_Receive(struct strmbase_sink *iface, IM REFERENCE_TIME start, stop; HRESULT hr; + TRACE("filter %p, sample %p.\n", filter, sample); + if (filter->eos || filter->sink.flushing) return S_FALSE; @@ -461,7 +463,7 @@ static void dsound_render_sink_disconnect(struct strmbase_sink *iface) { struct dsound_render *filter = impl_from_strmbase_pin(&iface->pin); - TRACE("(%p)->()\n", iface); + TRACE("filter %p\n", filter); if (filter->dsbuffer) IDirectSoundBuffer_Release(filter->dsbuffer); @@ -684,58 +686,58 @@ static const struct strmbase_filter_ops filter_ops = static HRESULT WINAPI basic_audio_QueryInterface(IBasicAudio *iface, REFIID riid, void **out) { struct dsound_render *filter = impl_from_IBasicAudio(iface); - - TRACE("(%p/%p)->(%s, %p)\n", filter, iface, debugstr_guid(riid), out); - return IUnknown_QueryInterface(filter->filter.outer_unk, riid, out); } static ULONG WINAPI basic_audio_AddRef(IBasicAudio *iface) { struct dsound_render *filter = impl_from_IBasicAudio(iface); - - TRACE("(%p/%p)->()\n", filter, iface); - return IUnknown_AddRef(filter->filter.outer_unk); } static ULONG WINAPI basic_audio_Release(IBasicAudio *iface) { struct dsound_render *filter = impl_from_IBasicAudio(iface); - - TRACE("(%p/%p)->()\n", filter, iface); - return IUnknown_Release(filter->filter.outer_unk); } static HRESULT WINAPI basic_audio_GetTypeInfoCount(IBasicAudio *iface, UINT *count) { - TRACE("iface %p, count %p.\n", iface, count); + struct dsound_render *filter = impl_from_IBasicAudio(iface); + + TRACE("filter %p, count %p.\n", filter, count); + *count = 1; + return S_OK; } static HRESULT WINAPI basic_audio_GetTypeInfo(IBasicAudio *iface, UINT index, LCID lcid, ITypeInfo **typeinfo) { - TRACE("iface %p, index %u, lcid %#lx, typeinfo %p.\n", iface, index, lcid, typeinfo); + struct dsound_render *filter = impl_from_IBasicAudio(iface); + + TRACE("filter %p, index %u, lcid %lu, typeinfo %p.\n", filter, index, lcid, typeinfo); + return strmbase_get_typeinfo(IBasicAudio_tid, typeinfo); } static HRESULT WINAPI basic_audio_GetIDsOfNames(IBasicAudio *iface, REFIID iid, LPOLESTR *names, UINT count, LCID lcid, DISPID *ids) { + struct dsound_render *filter = impl_from_IBasicAudio(iface); ITypeInfo *typeinfo; HRESULT hr; - TRACE("iface %p, iid %s, names %p, count %u, lcid %#lx, ids %p.\n", - iface, debugstr_guid(iid), names, count, lcid, ids); + TRACE("filter %p, iid %s, names %p, count %u, lcid %lu, ids %p.\n", + filter, debugstr_guid(iid), names, count, lcid, ids); if (SUCCEEDED(hr = strmbase_get_typeinfo(IBasicAudio_tid, &typeinfo))) { hr = ITypeInfo_GetIDsOfNames(typeinfo, names, count, ids); ITypeInfo_Release(typeinfo); } + return hr; } @@ -745,14 +747,15 @@ static HRESULT WINAPI basic_audio_Invoke(IBasicAudio *iface, DISPID id, REFIID i ITypeInfo *typeinfo; HRESULT hr; - TRACE("iface %p, id %ld, iid %s, lcid %#lx, flags %#x, params %p, result %p, excepinfo %p, error_arg %p.\n", - iface, id, debugstr_guid(iid), lcid, flags, params, result, excepinfo, error_arg); + TRACE("filter %p, id %ld, iid %s, lcid %lu, flags %u, params %p, result %p, excepinfo %p, error_arg %p.\n", + iface, id, debugstr_guid(iid), lcid, flags, params, result, excepinfo, error_arg); if (SUCCEEDED(hr = strmbase_get_typeinfo(IBasicAudio_tid, &typeinfo))) { hr = ITypeInfo_Invoke(typeinfo, iface, id, flags, params, result, excepinfo, error_arg); ITypeInfo_Release(typeinfo); } + return hr; } @@ -776,7 +779,7 @@ static HRESULT WINAPI basic_audio_get_Volume(IBasicAudio *iface, LONG *volume) { struct dsound_render *filter = impl_from_IBasicAudio(iface); - TRACE("(%p/%p)->(%p)\n", filter, iface, volume); + TRACE("filter %p, volume %p.\n", filter, volume); if (!volume) return E_POINTER; @@ -805,7 +808,7 @@ static HRESULT WINAPI basic_audio_get_Balance(IBasicAudio *iface, LONG *balance) { struct dsound_render *filter = impl_from_IBasicAudio(iface); - TRACE("(%p/%p)->(%p)\n", filter, iface, balance); + TRACE("filter %p, balance %p.\n", filter, balance); if (!balance) return E_POINTER; @@ -832,99 +835,74 @@ static const IBasicAudioVtbl basic_audio_vtbl = static HRESULT WINAPI am_direct_sound_QueryInterface(IAMDirectSound *iface, REFIID riid, void **out) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); - - TRACE("(%p/%p)->(%s, %p)\n", filter, iface, debugstr_guid(riid), out); - return IUnknown_QueryInterface(filter->filter.outer_unk, riid, out); } static ULONG WINAPI am_direct_sound_AddRef(IAMDirectSound *iface) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); - - TRACE("(%p/%p)->()\n", filter, iface); - return IUnknown_AddRef(filter->filter.outer_unk); } static ULONG WINAPI am_direct_sound_Release(IAMDirectSound *iface) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); - - TRACE("(%p/%p)->()\n", filter, iface); - return IUnknown_Release(filter->filter.outer_unk); } static HRESULT WINAPI am_direct_sound_GetDirectSoundInterface(IAMDirectSound *iface, IDirectSound **ds) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); - - FIXME("(%p/%p)->(%p): stub\n", filter, iface, ds); - + FIXME("filter %p, ds %p stub!\n", filter, ds); return E_NOTIMPL; } static HRESULT WINAPI am_direct_sound_GetPrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); - - FIXME("(%p/%p)->(%p): stub\n", filter, iface, buf); - + FIXME("filter %p, buf %p stub!\n", filter, buf); return E_NOTIMPL; } static HRESULT WINAPI am_direct_sound_GetSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer **buf) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); - - FIXME("(%p/%p)->(%p): stub\n", filter, iface, buf); - + FIXME("filter %p, buf %p stub!\n", filter, buf); return E_NOTIMPL; } static HRESULT WINAPI am_direct_sound_ReleaseDirectSoundInterface(IAMDirectSound *iface, IDirectSound *ds) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); - - FIXME("(%p/%p)->(%p): stub\n", filter, iface, ds); - + FIXME("filter %p, ds %p stub!\n", filter, ds); return E_NOTIMPL; } static HRESULT WINAPI am_direct_sound_ReleasePrimaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); - - FIXME("(%p/%p)->(%p): stub\n", filter, iface, buf); - + FIXME("filter %p, buf %p stub!\n", filter, buf); return E_NOTIMPL; } static HRESULT WINAPI am_direct_sound_ReleaseSecondaryBufferInterface(IAMDirectSound *iface, IDirectSoundBuffer *buf) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); - - FIXME("(%p/%p)->(%p): stub\n", filter, iface, buf); - + FIXME("filter %p, buf %p stub!\n", filter, buf); return E_NOTIMPL; } static HRESULT WINAPI am_direct_sound_SetFocusWindow(IAMDirectSound *iface, HWND hwnd, BOOL bgaudible) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); - - FIXME("(%p/%p)->(%p,%d): stub\n", filter, iface, hwnd, bgaudible); - + FIXME("filter %p, hwnd %p, bgaudible %d stub!\n", filter, hwnd, bgaudible); return E_NOTIMPL; } static HRESULT WINAPI am_direct_sound_GetFocusWindow(IAMDirectSound *iface, HWND *hwnd, BOOL *bgaudible) { struct dsound_render *filter = impl_from_IAMDirectSound(iface); - - FIXME("(%p/%p)->(%p,%p): stub\n", filter, iface, hwnd, bgaudible); - + FIXME("filter %p, hwnd %p, bgaudible %p stub!\n", filter, hwnd, bgaudible); return E_NOTIMPL; } @@ -971,19 +949,15 @@ static HRESULT WINAPI quality_control_Notify(IQualityControl *iface, IBaseFilter *sender, Quality q) { struct dsound_render *filter = impl_from_IQualityControl(iface); - FIXME("filter %p, sender %p, type %#x, proportion %ld, late %s, timestamp %s, stub!\n", filter, sender, q.Type, q.Proportion, debugstr_time(q.Late), debugstr_time(q.TimeStamp)); - return E_NOTIMPL; } static HRESULT WINAPI quality_control_SetSink(IQualityControl *iface, IQualityControl *sink) { struct dsound_render *filter = impl_from_IQualityControl(iface); - - FIXME("filter %p, sink %p, stub!\n", filter, sink); - + FIXME("filter %p, sink %p stub!\n", filter, sink); return E_NOTIMPL; } @@ -1007,6 +981,8 @@ HRESULT dsound_render_create(IUnknown *outer, IUnknown **out) IDirectSoundBuffer *buffer; HRESULT hr; + TRACE("outer %p, out %p.\n", outer, out); + if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; From 8524c6b8b07582b1438a8fc03d61c8ae6da65b95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 14 Sep 2022 12:23:09 +0200 Subject: [PATCH 0160/2777] quartz: Simplify DirectSound Renderer Filter sample handling. Writing buffers sequentially instead of trying figuring the write position from the pts throught convoluted logic. CW-Bug-Id: #21147 --- dlls/quartz/dsoundrender.c | 408 +++++++++++++++---------------------- 1 file changed, 168 insertions(+), 240 deletions(-) diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c index ad0b19bfea8..fc3c2dbb52b 100644 --- a/dlls/quartz/dsoundrender.c +++ b/dlls/quartz/dsoundrender.c @@ -27,6 +27,7 @@ #include "dshow.h" #include "evcode.h" #include "strmif.h" +#include "initguid.h" #include "dsound.h" #include "amaudio.h" @@ -34,11 +35,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(quartz); -/* NOTE: buffer can still be filled completely, - * but we start waiting until only this amount is buffered - */ -static const REFERENCE_TIME DSoundRenderer_Max_Fill = 150 * 10000; - struct dsound_render { struct strmbase_filter filter; @@ -56,13 +52,15 @@ struct dsound_render /* Signaled when a flush or state change occurs, i.e. anything that needs * to immediately unblock the streaming thread. */ HANDLE flush_event; + HANDLE empty_event; REFERENCE_TIME stream_start; BOOL eos; IDirectSound8 *dsound; - LPDIRECTSOUNDBUFFER dsbuffer; - DWORD buf_size; - DWORD last_playpos, writepos; + IDirectSoundBuffer *dsbuffer; + + DWORD buffer_size; + DWORD write_pos; LONG volume; LONG pan; @@ -88,225 +86,115 @@ static struct dsound_render *impl_from_IAMDirectSound(IAMDirectSound *iface) return CONTAINING_RECORD(iface, struct dsound_render, IAMDirectSound_iface); } -static REFERENCE_TIME time_from_pos(struct dsound_render *filter, DWORD pos) +static HRESULT dsound_render_write_data(struct dsound_render *filter, const void *data, DWORD size) { WAVEFORMATEX *wfx = (WAVEFORMATEX *)filter->sink.pin.mt.pbFormat; - REFERENCE_TIME ret = 10000000; - ret = ret * pos / wfx->nAvgBytesPerSec; - return ret; -} + unsigned char silence = wfx->wBitsPerSample == 8 ? 128 : 0; + DWORD play_pos, write_end, size1, size2; + void *data1, *data2; + HRESULT hr; -static DWORD pos_from_time(struct dsound_render *filter, REFERENCE_TIME time) -{ - WAVEFORMATEX *wfx = (WAVEFORMATEX *)filter->sink.pin.mt.pbFormat; - REFERENCE_TIME ret = time; - ret *= wfx->nAvgBytesPerSec; - ret /= 10000000; - ret -= ret % wfx->nBlockAlign; - return ret; -} + TRACE("filter %p, data %p, size %#lx\n", filter, data, size); -static void DSoundRender_UpdatePositions(struct dsound_render *filter, DWORD *seqwritepos, DWORD *minwritepos) -{ - WAVEFORMATEX *wfx = (WAVEFORMATEX *)filter->sink.pin.mt.pbFormat; - BYTE *buf1, *buf2; - DWORD size1, size2, playpos, writepos, old_writepos, old_playpos, adv; - BOOL writepos_set = filter->writepos < filter->buf_size; - - /* Update position and zero */ - old_writepos = filter->writepos; - old_playpos = filter->last_playpos; - if (old_writepos <= old_playpos) - old_writepos += filter->buf_size; - - IDirectSoundBuffer_GetCurrentPosition(filter->dsbuffer, &playpos, &writepos); - if (old_playpos > playpos) - adv = filter->buf_size + playpos - old_playpos; - else - adv = playpos - old_playpos; - filter->last_playpos = playpos; - if (adv) - { - TRACE("Moving from %lu to %lu: clearing %lu bytes.\n", old_playpos, playpos, adv); - IDirectSoundBuffer_Lock(filter->dsbuffer, old_playpos, adv, (void**)&buf1, &size1, (void**)&buf2, &size2, 0); - memset(buf1, wfx->wBitsPerSample == 8 ? 128 : 0, size1); - memset(buf2, wfx->wBitsPerSample == 8 ? 128 : 0, size2); - IDirectSoundBuffer_Unlock(filter->dsbuffer, buf1, size1, buf2, size2); - } - *minwritepos = writepos; - if (!writepos_set || old_writepos < writepos) - { - if (writepos_set) - { - filter->writepos = filter->buf_size; - FIXME("Underrun of data occurred!\n"); - } - *seqwritepos = writepos; - } + if (!size) + size = filter->buffer_size / 2; else - *seqwritepos = filter->writepos; -} - -static HRESULT DSoundRender_GetWritePos(struct dsound_render *filter, - DWORD *ret_writepos, REFERENCE_TIME write_at, DWORD *pfree, DWORD *skip) -{ - DWORD writepos, min_writepos, playpos; - REFERENCE_TIME max_lag = 50 * 10000; - REFERENCE_TIME cur, writepos_t, delta_t; + size = min(size, filter->buffer_size / 2); - DSoundRender_UpdatePositions(filter, &writepos, &min_writepos); - playpos = filter->last_playpos; - if (filter->filter.clock) - { - IReferenceClock_GetTime(filter->filter.clock, &cur); - cur -= filter->stream_start; - } + if (filter->write_pos == -1) + filter->write_pos = 0; else - write_at = -1; + { + if (FAILED(hr = IDirectSoundBuffer_GetCurrentPosition(filter->dsbuffer, + &play_pos, NULL))) + return hr; - if (writepos == min_writepos) - max_lag = 0; + write_end = (filter->write_pos + size) % filter->buffer_size; + if (write_end - filter->write_pos >= play_pos - filter->write_pos) + return S_FALSE; + } - *skip = 0; - if (write_at < 0) + if (FAILED(hr = IDirectSoundBuffer_Lock(filter->dsbuffer, filter->write_pos, + size, &data1, &size1, &data2, &size2, 0))) { - *ret_writepos = writepos; - goto end; + ERR("Failed to lock buffer %p, hr %#lx\n", filter->dsbuffer, hr); + return hr; } - if (writepos >= playpos) - writepos_t = cur + time_from_pos(filter, writepos - playpos); - else - writepos_t = cur + time_from_pos(filter, filter->buf_size + writepos - playpos); + TRACE("Locked data1 %p, size1 %#lx, data2 %p, size2 %#lx\n", data1, size1, data2, size2); - /* write_at: Starting time of sample */ - /* cur: current time of play position */ - /* writepos_t: current time of our pointer play position */ - delta_t = write_at - writepos_t; - if (delta_t >= -max_lag && delta_t <= max_lag) - { - TRACE("Continuing from old position\n"); - *ret_writepos = writepos; - } - else if (delta_t < 0) - { - REFERENCE_TIME past, min_writepos_t; - WARN("Delta too big %s/%s, overwriting old data or even skipping\n", debugstr_time(delta_t), debugstr_time(max_lag)); - if (min_writepos >= playpos) - min_writepos_t = cur + time_from_pos(filter, min_writepos - playpos); - else - min_writepos_t = cur + time_from_pos(filter, filter->buf_size - playpos + min_writepos); - past = min_writepos_t - write_at; - if (past >= 0) - { - DWORD skipbytes = pos_from_time(filter, past); - WARN("Skipping %lu bytes.\n", skipbytes); - *skip = skipbytes; - *ret_writepos = min_writepos; - } - else - { - DWORD aheadbytes = pos_from_time(filter, -past); - WARN("Advancing %lu bytes.\n", aheadbytes); - *ret_writepos = (min_writepos + aheadbytes) % filter->buf_size; - } - } - else /* delta_t > 0 */ + if (!data) { - DWORD aheadbytes; - WARN("Delta too big %s/%s, too far ahead\n", debugstr_time(delta_t), debugstr_time(max_lag)); - aheadbytes = pos_from_time(filter, delta_t); - WARN("Advancing %lu bytes.\n", aheadbytes); - if (delta_t >= DSoundRenderer_Max_Fill) - return S_FALSE; - *ret_writepos = (min_writepos + aheadbytes) % filter->buf_size; + memset(data1, silence, size1); + memset(data2, silence, size2); } -end: - if (playpos >= *ret_writepos) - *pfree = playpos - *ret_writepos; else - *pfree = filter->buf_size + playpos - *ret_writepos; - if (time_from_pos(filter, filter->buf_size - *pfree) >= DSoundRenderer_Max_Fill) { - TRACE("Blocked: too full %s / %s\n", debugstr_time(time_from_pos(filter, filter->buf_size - *pfree)), - debugstr_time(DSoundRenderer_Max_Fill)); - return S_FALSE; + memcpy(data1, data, size1); + data = (char *)data + size1; + memcpy(data2, data, size2); } - return S_OK; -} -static HRESULT DSoundRender_HandleEndOfStream(struct dsound_render *filter) -{ - while (filter->filter.state == State_Running) + if (FAILED(hr = IDirectSoundBuffer_Unlock(filter->dsbuffer, data1, size1, data2, size2))) { - DWORD pos1, pos2; - DSoundRender_UpdatePositions(filter, &pos1, &pos2); - if (pos1 == pos2) - break; - - WaitForSingleObject(filter->flush_event, 10); + ERR("Failed to unlock buffer %p, hr %#lx\n", filter->dsbuffer, hr); + return hr; } + TRACE("Unlocked data1 %p, size1 %#lx, data2 %p, size2 %#lx\n", data1, size1, data2, size2); + + filter->write_pos += size; + filter->write_pos %= filter->buffer_size; + + TRACE("Written size %#lx, write_pos %#lx\n", size, filter->write_pos); + return S_OK; } -static HRESULT DSoundRender_SendSampleData(struct dsound_render *filter, - REFERENCE_TIME tStart, REFERENCE_TIME tStop, const BYTE *data, DWORD size) +static HRESULT dsound_render_wait_play_end(struct dsound_render *filter) { + DWORD start_pos, play_pos, end_pos = filter->write_pos; HRESULT hr; - while (size && filter->filter.state != State_Stopped) + if (FAILED(hr = IDirectSoundBuffer_GetCurrentPosition(filter->dsbuffer, + &start_pos, NULL))) { - DWORD writepos, skip = 0, free, size1, size2, ret; - BYTE *buf1, *buf2; + ERR("Failed to get buffer positions, hr %#lx\n", hr); + return hr; + } - if (filter->filter.state == State_Running) - hr = DSoundRender_GetWritePos(filter, &writepos, tStart, &free, &skip); - else - hr = S_FALSE; + if (FAILED(hr = dsound_render_write_data(filter, NULL, 0))) + return hr; + + while (filter->filter.state == State_Running) + { + HANDLE handles[] = {filter->empty_event, filter->flush_event}; - if (hr != S_OK) + if (FAILED(hr = IDirectSoundBuffer_GetCurrentPosition(filter->dsbuffer, + &play_pos, NULL))) { - ret = WaitForSingleObject(filter->flush_event, 10); - if (filter->sink.flushing || filter->filter.state == State_Stopped) - return filter->filter.state == State_Paused ? S_OK : VFW_E_WRONG_STATE; - if (ret != WAIT_TIMEOUT) - ERR("WaitForSingleObject() returned %ld.\n", ret); - continue; + ERR("Failed to get buffer positions, hr %#lx\n", hr); + return hr; } - tStart = -1; - - if (skip) - FIXME("Sample dropped %lu of %lu bytes.\n", skip, size); - if (skip >= size) - return S_OK; - data += skip; - size -= skip; - hr = IDirectSoundBuffer_Lock(filter->dsbuffer, writepos, min(free, size), (void**)&buf1, &size1, (void**)&buf2, &size2, 0); - if (hr != DS_OK) - { - ERR("Failed to lock sound buffer, hr %#lx.\n", hr); + if (play_pos - start_pos >= end_pos - start_pos) break; - } - memcpy(buf1, data, size1); - if (size2) - memcpy(buf2, data+size1, size2); - IDirectSoundBuffer_Unlock(filter->dsbuffer, buf1, size1, buf2, size2); - filter->writepos = (writepos + size1 + size2) % filter->buf_size; - TRACE("Wrote %lu bytes at %lu, next at %lu - (%lu/%lu)\n", size1+size2, writepos, filter->writepos, free, size); - data += size1 + size2; - size -= size1 + size2; + + WARN("Waiting for EOS, start_pos %#lx, play_pos %#lx, end_pos %#lx\n", + start_pos, play_pos, end_pos); + + WaitForMultipleObjects(2, handles, FALSE, INFINITE); } + return S_OK; } -static HRESULT DSoundRender_PrepareReceive(struct dsound_render *filter, IMediaSample *pSample) +static HRESULT dsound_render_configure_buffer(struct dsound_render *filter, IMediaSample *sample) { HRESULT hr; AM_MEDIA_TYPE *amt; - if (IMediaSample_GetMediaType(pSample, &amt) == S_OK) + if (IMediaSample_GetMediaType(sample, &amt) == S_OK) { AM_MEDIA_TYPE *orig = &filter->sink.pin.mt; WAVEFORMATEX *origfmt = (WAVEFORMATEX *)orig->pbFormat; @@ -329,51 +217,24 @@ static HRESULT DSoundRender_PrepareReceive(struct dsound_render *filter, IMediaS return VFW_E_TYPE_NOT_ACCEPTED; FreeMediaType(orig); CopyMediaType(orig, amt); - IMediaSample_SetMediaType(pSample, NULL); + IMediaSample_SetMediaType(sample, NULL); } } else return VFW_E_TYPE_NOT_ACCEPTED; } - return S_OK; -} - -static HRESULT DSoundRender_DoRenderSample(struct dsound_render *filter, IMediaSample *pSample) -{ - LPBYTE pbSrcStream = NULL; - LONG cbSrcStream = 0; - REFERENCE_TIME tStart, tStop; - HRESULT hr; - - hr = IMediaSample_GetPointer(pSample, &pbSrcStream); - if (FAILED(hr)) - { - ERR("Failed to get buffer pointer, hr %#lx.\n", hr); - return hr; - } - - hr = IMediaSample_GetTime(pSample, &tStart, &tStop); - if (FAILED(hr)) - { - ERR("Failed to get sample time, hr %#lx.\n", hr); - tStart = tStop = -1; - } - - if (IMediaSample_IsPreroll(pSample) == S_OK) - { - TRACE("Preroll!\n"); - return S_OK; - } - cbSrcStream = IMediaSample_GetActualDataLength(pSample); - return DSoundRender_SendSampleData(filter, tStart, tStop, pbSrcStream, cbSrcStream); + return S_OK; } static HRESULT WINAPI dsound_render_sink_Receive(struct strmbase_sink *iface, IMediaSample *sample) { struct dsound_render *filter = impl_from_strmbase_pin(&iface->pin); - REFERENCE_TIME start, stop; + WAVEFORMATEX *wfx = (WAVEFORMATEX *)filter->sink.pin.mt.pbFormat; + REFERENCE_TIME current = 0, start = 0, stop; HRESULT hr; + BYTE *data; + LONG size; TRACE("filter %p, sample %p.\n", filter, sample); @@ -383,16 +244,62 @@ static HRESULT WINAPI dsound_render_sink_Receive(struct strmbase_sink *iface, IM if (filter->filter.state == State_Stopped) return VFW_E_WRONG_STATE; - if (FAILED(hr = DSoundRender_PrepareReceive(filter, sample))) + if (FAILED(hr = dsound_render_configure_buffer(filter, sample))) return hr; - if (filter->filter.clock && SUCCEEDED(IMediaSample_GetTime(sample, &start, &stop))) - strmbase_passthrough_update_time(&filter->passthrough, start); + if (filter->filter.clock) + { + if (SUCCEEDED(IMediaSample_GetTime(sample, &start, &stop))) + strmbase_passthrough_update_time(&filter->passthrough, start); + + if (filter->stream_start != -1 && SUCCEEDED(IReferenceClock_GetTime(filter->filter.clock, ¤t))) + current -= filter->stream_start; + } if (filter->filter.state == State_Paused) SetEvent(filter->state_event); - return DSoundRender_DoRenderSample(filter, sample); + if (FAILED(hr = IMediaSample_GetPointer(sample, &data))) + { + ERR("Failed to get buffer pointer, hr %#lx.\n", hr); + return hr; + } + + size = IMediaSample_GetActualDataLength(sample); + + if (filter->write_pos == -1 && start > current) + { + /* prepend some silence if the first sample doesn't start at 0 */ + DWORD length = (start - current) * wfx->nAvgBytesPerSec / 10000000; + length -= length % wfx->nBlockAlign; + + if (length != 0 && FAILED(hr = dsound_render_write_data(filter, NULL, length))) + return hr; + } + else if (filter->write_pos == -1 && start < current) + { + /* or skip some data instead if the first sample is late */ + DWORD offset = (current - start) * wfx->nAvgBytesPerSec / 10000000; + offset -= offset % wfx->nBlockAlign; + + data += min(size, offset); + size -= min(size, offset); + } + + while (size && (hr = dsound_render_write_data(filter, data, size)) == S_FALSE) + { + HANDLE handles[] = {filter->empty_event, filter->flush_event}; + + WARN("Could not write %#lx bytes, waiting for buffer to empty.\n", size); + + if (WaitForMultipleObjects(2, handles, FALSE, INFINITE) == WAIT_OBJECT_0 + 1) + { + TRACE("Flush event notified, dropping sample.\n"); + return S_OK; + } + } + + return hr; } static HRESULT dsound_render_sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) @@ -420,22 +327,45 @@ static HRESULT dsound_render_sink_connect(struct strmbase_sink *iface, IPin *pee { struct dsound_render *filter = impl_from_strmbase_pin(&iface->pin); const WAVEFORMATEX *format = (WAVEFORMATEX *)mt->pbFormat; - HRESULT hr = S_OK; + IDirectSoundNotify *notify; DSBUFFERDESC buf_desc; - - filter->buf_size = format->nAvgBytesPerSec; + HRESULT hr = S_OK; memset(&buf_desc,0,sizeof(DSBUFFERDESC)); buf_desc.dwSize = sizeof(DSBUFFERDESC); buf_desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY | DSBCAPS_GLOBALFOCUS | - DSBCAPS_GETCURRENTPOSITION2; - buf_desc.dwBufferBytes = filter->buf_size; + DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY; + buf_desc.dwBufferBytes = format->nAvgBytesPerSec; buf_desc.lpwfxFormat = (WAVEFORMATEX *)format; - hr = IDirectSound8_CreateSoundBuffer(filter->dsound, &buf_desc, &filter->dsbuffer, NULL); - filter->writepos = filter->buf_size; - if (FAILED(hr)) + + filter->buffer_size = format->nAvgBytesPerSec; + filter->write_pos = -1; + + if (FAILED(hr = IDirectSound8_CreateSoundBuffer(filter->dsound, &buf_desc, &filter->dsbuffer, NULL))) ERR("Failed to create sound buffer, hr %#lx.\n", hr); + else if (FAILED(hr = IDirectSoundBuffer_QueryInterface(filter->dsbuffer, &IID_IDirectSoundNotify, + (void **)¬ify))) + ERR("Failed to query IDirectSoundNotify iface, hr %#lx.\n", hr); + else + { + DSBPOSITIONNOTIFY positions[10] = {{.dwOffset = 0, .hEventNotify = filter->empty_event}}; + int i; + + TRACE("Created buffer %p with size %#lx\n", filter->dsbuffer, filter->buffer_size); + + for (i = 1; i < ARRAY_SIZE(positions); ++i) + { + positions[i] = positions[i - 1]; + positions[i].dwOffset += filter->buffer_size / ARRAY_SIZE(positions); + } + + if (FAILED(hr = IDirectSoundNotify_SetNotificationPositions(notify, + ARRAY_SIZE(positions), positions))) + ERR("Failed to set notification positions, hr %#lx\n", hr); + + IDirectSoundNotify_Release(notify); + } if (SUCCEEDED(hr)) { @@ -475,8 +405,6 @@ static HRESULT dsound_render_sink_eos(struct strmbase_sink *iface) struct dsound_render *filter = impl_from_strmbase_pin(&iface->pin); IFilterGraph *graph = filter->filter.graph; IMediaEventSink *event_sink; - void *buffer; - DWORD size; filter->eos = TRUE; @@ -491,11 +419,8 @@ static HRESULT dsound_render_sink_eos(struct strmbase_sink *iface) strmbase_passthrough_eos(&filter->passthrough); SetEvent(filter->state_event); - DSoundRender_HandleEndOfStream(filter); - - IDirectSoundBuffer_Lock(filter->dsbuffer, 0, 0, &buffer, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER); - memset(buffer, 0, size); - IDirectSoundBuffer_Unlock(filter->dsbuffer, buffer, size, NULL, 0); + if (filter->dsbuffer && filter->write_pos != -1) + dsound_render_wait_play_end(filter); return S_OK; } @@ -527,7 +452,7 @@ static HRESULT dsound_render_sink_end_flush(struct strmbase_sink *iface) IDirectSoundBuffer_Lock(filter->dsbuffer, 0, 0, &buffer, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER); memset(buffer, 0, size); IDirectSoundBuffer_Unlock(filter->dsbuffer, buffer, size, NULL, 0); - filter->writepos = filter->buf_size; + filter->write_pos = -1; } LeaveCriticalSection(&filter->filter.stream_cs); @@ -564,6 +489,7 @@ static void dsound_render_destroy(struct strmbase_filter *iface) CloseHandle(filter->state_event); CloseHandle(filter->flush_event); + CloseHandle(filter->empty_event); strmbase_passthrough_cleanup(&filter->passthrough); strmbase_filter_cleanup(&filter->filter); @@ -644,10 +570,10 @@ static HRESULT dsound_render_stop_stream(struct strmbase_filter *iface) struct dsound_render *filter = impl_from_strmbase_filter(iface); if (filter->sink.pin.peer) - { IDirectSoundBuffer_Stop(filter->dsbuffer); - filter->writepos = filter->buf_size; - } + + filter->stream_start = -1; + return S_OK; } @@ -1024,9 +950,11 @@ HRESULT dsound_render_create(IUnknown *outer, IUnknown **out) ISeekingPassThru_Init(&object->passthrough.ISeekingPassThru_iface, TRUE, &object->sink.pin.IPin_iface); strmbase_sink_init(&object->sink, &object->filter, L"Audio Input pin (rendered)", &sink_ops, NULL); + object->stream_start = -1; object->state_event = CreateEventW(NULL, TRUE, TRUE, NULL); object->flush_event = CreateEventW(NULL, TRUE, TRUE, NULL); + object->empty_event = CreateEventW(NULL, FALSE, FALSE, NULL); object->IBasicAudio_iface.lpVtbl = &basic_audio_vtbl; object->IAMDirectSound_iface.lpVtbl = &am_direct_sound_vtbl; From 7857832f0c375bbb2ac4fe57bd8905fa332fdd40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 13 Oct 2022 10:48:51 +0200 Subject: [PATCH 0161/2777] quartz: Handle DirectSound Renderer Filter underruns. CW-Bug-Id: #21192 --- dlls/quartz/dsoundrender.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c index fc3c2dbb52b..e0ca3ac7da4 100644 --- a/dlls/quartz/dsoundrender.c +++ b/dlls/quartz/dsoundrender.c @@ -90,7 +90,7 @@ static HRESULT dsound_render_write_data(struct dsound_render *filter, const void { WAVEFORMATEX *wfx = (WAVEFORMATEX *)filter->sink.pin.mt.pbFormat; unsigned char silence = wfx->wBitsPerSample == 8 ? 128 : 0; - DWORD play_pos, write_end, size1, size2; + DWORD write_end, size1, size2; void *data1, *data2; HRESULT hr; @@ -105,10 +105,19 @@ static HRESULT dsound_render_write_data(struct dsound_render *filter, const void filter->write_pos = 0; else { + DWORD play_pos, write_pos; + if (FAILED(hr = IDirectSoundBuffer_GetCurrentPosition(filter->dsbuffer, - &play_pos, NULL))) + &play_pos, &write_pos))) return hr; + if (filter->write_pos - play_pos <= write_pos - play_pos) + { + WARN("Buffer underrun detected, filter %p, dsound play pos %#lx, write pos %#lx, filter write pos %#lx!\n", + filter, play_pos, write_pos, filter->write_pos); + filter->write_pos = write_pos; + } + write_end = (filter->write_pos + size) % filter->buffer_size; if (write_end - filter->write_pos >= play_pos - filter->write_pos) return S_FALSE; From 0ea9e08ba52b2ae3ff049ba38198baaecab95813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 13 Oct 2022 10:48:51 +0200 Subject: [PATCH 0162/2777] quartz: Add an initial silent 30ms to the DirectSound Renderer Filter. To avoid underruns as much as possible. This is required for Persona 4 Golden intro with non-english audio settings. CW-Bug-Id: #21192 --- dlls/quartz/dsoundrender.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c index e0ca3ac7da4..f5a96233825 100644 --- a/dlls/quartz/dsoundrender.c +++ b/dlls/quartz/dsoundrender.c @@ -276,10 +276,10 @@ static HRESULT WINAPI dsound_render_sink_Receive(struct strmbase_sink *iface, IM size = IMediaSample_GetActualDataLength(sample); - if (filter->write_pos == -1 && start > current) + if (filter->write_pos == -1 && (start + 300000) > current) { - /* prepend some silence if the first sample doesn't start at 0 */ - DWORD length = (start - current) * wfx->nAvgBytesPerSec / 10000000; + /* prepend at least 30ms of silence before the first sample */ + DWORD length = (start + 300000 - current) * wfx->nAvgBytesPerSec / 10000000; length -= length % wfx->nBlockAlign; if (length != 0 && FAILED(hr = dsound_render_write_data(filter, NULL, length))) From dc02621800f586da4654f0e379668766faf1ef62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 17 Oct 2022 09:54:50 +0200 Subject: [PATCH 0163/2777] winegstreamer: Fill channel position if wg_format is missing channel_mask. CW-Bug-Id: #21409 --- dlls/winegstreamer/wg_format.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 18dde324f8c..6bf613a9342 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -328,6 +328,8 @@ static void wg_channel_mask_to_gst(GstAudioChannelPosition *positions, uint32_t else { GST_WARNING("Incomplete channel mask %#x.", orig_mask); + if (!orig_mask) + positions[i] = position_map[bit]; } } } From f7c47daf0ce1b440d9752b91aa54a990e4ffe866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 17 Oct 2022 16:57:14 +0200 Subject: [PATCH 0164/2777] quartz: Handle position wrap-around while waiting for DirectSound rendererer EOS. --- dlls/quartz/dsoundrender.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c index f5a96233825..788c7ad15d0 100644 --- a/dlls/quartz/dsoundrender.c +++ b/dlls/quartz/dsoundrender.c @@ -162,7 +162,7 @@ static HRESULT dsound_render_write_data(struct dsound_render *filter, const void static HRESULT dsound_render_wait_play_end(struct dsound_render *filter) { - DWORD start_pos, play_pos, end_pos = filter->write_pos; + DWORD start_pos, play_pos, written, played = 0; HRESULT hr; if (FAILED(hr = IDirectSoundBuffer_GetCurrentPosition(filter->dsbuffer, @@ -172,6 +172,8 @@ static HRESULT dsound_render_wait_play_end(struct dsound_render *filter) return hr; } + written = filter->write_pos - start_pos + (filter->write_pos < start_pos ? filter->buffer_size : 0); + if (FAILED(hr = dsound_render_write_data(filter, NULL, 0))) return hr; @@ -186,13 +188,15 @@ static HRESULT dsound_render_wait_play_end(struct dsound_render *filter) return hr; } - if (play_pos - start_pos >= end_pos - start_pos) + played += play_pos - start_pos + (play_pos < start_pos ? filter->buffer_size : 0); + if (played >= written) break; - WARN("Waiting for EOS, start_pos %#lx, play_pos %#lx, end_pos %#lx\n", - start_pos, play_pos, end_pos); + WARN("Waiting for EOS, start_pos %#lx, play_pos %#lx, written %#lx, played %#lx\n", + start_pos, play_pos, written, played); WaitForMultipleObjects(2, handles, FALSE, INFINITE); + start_pos = play_pos; } return S_OK; From 2d73c6cecc73bcf37ca8b0d77d79c63d9c10b453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 28 Jun 2022 10:05:39 +0200 Subject: [PATCH 0165/2777] HACK: winegstreamer: Fail to plug elements when parser has an error. CW-Bug-Id: #20819 --- dlls/winegstreamer/wg_parser.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index e75c804c270..d57fac97d10 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -490,9 +490,12 @@ static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad, GstCaps *caps, GstElementFactory *fact, gpointer user) { const char *name = gst_element_factory_get_longname(fact); + struct wg_parser *parser = user; GST_INFO("Using \"%s\".", name); + if (parser->error) + return GST_AUTOPLUG_SELECT_SKIP; if (strstr(name, "Player protection")) { GST_WARNING("Blacklisted a/52 decoder because it only works in Totem."); From 649c169535af045946517a88a0b1fe2784d2c5c1 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Fri, 6 Nov 2020 12:20:16 -0600 Subject: [PATCH 0166/2777] Revert "winex11.drv: Interpret mouse 6/7 as horiz scroll." This reverts commit 893080e4df5a45929320ebb88b8668eea316476c. We have a trade-off here between supporting horizontal scroll, or mapping those actions to the XBUTTON{1,2} messages. Some users were using those buttons in their games, which broke with this change. It seems more likely that the extra button mapping will be useful than horizontal scrolling, so let's revert this commit. --- dlls/winex11.drv/mouse.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index d1ade2eda68..c9da16171d4 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -76,8 +76,8 @@ static const UINT button_down_flags[NB_BUTTONS] = MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_WHEEL, MOUSEEVENTF_WHEEL, - MOUSEEVENTF_HWHEEL, - MOUSEEVENTF_HWHEEL, + MOUSEEVENTF_XDOWN, /* FIXME: horizontal wheel */ + MOUSEEVENTF_XDOWN, MOUSEEVENTF_XDOWN, MOUSEEVENTF_XDOWN }; @@ -89,8 +89,8 @@ static const UINT button_up_flags[NB_BUTTONS] = MOUSEEVENTF_RIGHTUP, 0, 0, - 0, - 0, + MOUSEEVENTF_XUP, + MOUSEEVENTF_XUP, MOUSEEVENTF_XUP, MOUSEEVENTF_XUP }; @@ -102,8 +102,8 @@ static const UINT button_down_data[NB_BUTTONS] = 0, WHEEL_DELTA, -WHEEL_DELTA, - -WHEEL_DELTA, - WHEEL_DELTA, + XBUTTON1, + XBUTTON2, XBUTTON1, XBUTTON2 }; @@ -115,8 +115,8 @@ static const UINT button_up_data[NB_BUTTONS] = 0, 0, 0, - 0, - 0, + XBUTTON1, + XBUTTON2, XBUTTON1, XBUTTON2 }; From 39e04945ae79b2a498f4192dce06786719d07190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 17 Jan 2020 12:45:32 +0100 Subject: [PATCH 0167/2777] winex11.drv: Rename EVENT_x11_time_to_win32_time to x11drv_time_to_ticks. --- dlls/winex11.drv/event.c | 8 ++++---- dlls/winex11.drv/keyboard.c | 2 +- dlls/winex11.drv/mouse.c | 10 +++++----- dlls/winex11.drv/wintab.c | 6 +++--- dlls/winex11.drv/x11drv.h | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 86edf66b820..1b1117df4cb 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -502,12 +502,12 @@ NTSTATUS X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, } /*********************************************************************** - * EVENT_x11_time_to_win32_time + * x11drv_time_to_ticks * * Make our timer and the X timer line up as best we can * Pass 0 to retrieve the current adjustment value (times -1) */ -DWORD EVENT_x11_time_to_win32_time(Time time) +DWORD x11drv_time_to_ticks( Time time ) { static DWORD adjust = 0; DWORD now = NtGetTickCount(); @@ -568,10 +568,10 @@ static void set_input_focus( struct x11drv_win_data *data ) if (!data->whole_window) return; - if (EVENT_x11_time_to_win32_time(0)) + if (x11drv_time_to_ticks(0)) /* ICCCM says don't use CurrentTime, so try to use last message time if possible */ /* FIXME: this is not entirely correct */ - timestamp = NtUserGetThreadInfo()->message_time - EVENT_x11_time_to_win32_time(0); + timestamp = NtUserGetThreadInfo()->message_time - x11drv_time_to_ticks(0); else timestamp = CurrentTime; diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index f1ad4b01669..a17177c7b82 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1327,7 +1327,7 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) DWORD dwFlags; int ascii_chars; XIC xic = X11DRV_get_ic( hwnd ); - DWORD event_time = EVENT_x11_time_to_win32_time(event->time); + DWORD event_time = x11drv_time_to_ticks( event->time ); Status status = 0; TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n", diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index c9da16171d4..881ea5f5441 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1738,7 +1738,7 @@ BOOL X11DRV_ButtonPress( HWND hwnd, XEvent *xev ) input.u.mi.dy = event->y; input.u.mi.mouseData = button_down_data[buttonNum]; input.u.mi.dwFlags = button_down_flags[buttonNum] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; - input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); + input.u.mi.time = x11drv_time_to_ticks( event->time ); input.u.mi.dwExtraInfo = 0; update_user_time( event->time ); @@ -1765,7 +1765,7 @@ BOOL X11DRV_ButtonRelease( HWND hwnd, XEvent *xev ) input.u.mi.dy = event->y; input.u.mi.mouseData = button_up_data[buttonNum]; input.u.mi.dwFlags = button_up_flags[buttonNum] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; - input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); + input.u.mi.time = x11drv_time_to_ticks( event->time ); input.u.mi.dwExtraInfo = 0; map_event_coords( hwnd, event->window, event->root, event->x_root, event->y_root, &input ); @@ -1789,7 +1789,7 @@ BOOL X11DRV_MotionNotify( HWND hwnd, XEvent *xev ) input.u.mi.dy = event->y; input.u.mi.mouseData = 0; input.u.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; - input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); + input.u.mi.time = x11drv_time_to_ticks( event->time ); input.u.mi.dwExtraInfo = 0; if (!hwnd && is_old_motion_event( event->serial )) @@ -1820,7 +1820,7 @@ BOOL X11DRV_EnterNotify( HWND hwnd, XEvent *xev ) input.u.mi.dy = event->y; input.u.mi.mouseData = 0; input.u.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; - input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); + input.u.mi.time = x11drv_time_to_ticks( event->time ); input.u.mi.dwExtraInfo = 0; if (is_old_motion_event( event->serial )) @@ -1941,7 +1941,7 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) input.type = INPUT_MOUSE; input.u.mi.mouseData = 0; input.u.mi.dwFlags = MOUSEEVENTF_MOVE; - input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); + input.u.mi.time = x11drv_time_to_ticks( event->time ); input.u.mi.dwExtraInfo = 0; input.u.mi.dx = 0; input.u.mi.dy = 0; diff --git a/dlls/winex11.drv/wintab.c b/dlls/winex11.drv/wintab.c index 6f1437f14c6..7855175a29b 100644 --- a/dlls/winex11.drv/wintab.c +++ b/dlls/winex11.drv/wintab.c @@ -895,7 +895,7 @@ static BOOL motion_event( HWND hwnd, XEvent *event ) /* Set cursor to inverted if cursor is the eraser */ gMsgPacket.pkStatus = (cursor->TYPE == CSR_TYPE_ERASER ? TPS_INVERT:0); - gMsgPacket.pkTime = EVENT_x11_time_to_win32_time(motion->time); + gMsgPacket.pkTime = x11drv_time_to_ticks(motion->time); gMsgPacket.pkSerialNumber = gSerial++; gMsgPacket.pkCursor = curnum; gMsgPacket.pkX = motion->axis_data[0]; @@ -928,7 +928,7 @@ static BOOL button_event( HWND hwnd, XEvent *event ) /* Set cursor to inverted if cursor is the eraser */ gMsgPacket.pkStatus = (cursor->TYPE == CSR_TYPE_ERASER ? TPS_INVERT:0); set_button_state(curnum, button->deviceid); - gMsgPacket.pkTime = EVENT_x11_time_to_win32_time(button->time); + gMsgPacket.pkTime = x11drv_time_to_ticks(button->time); gMsgPacket.pkSerialNumber = gSerial++; gMsgPacket.pkCursor = curnum; if (button->axes_count > 0) { @@ -978,7 +978,7 @@ static BOOL proximity_event( HWND hwnd, XEvent *event ) /* Set cursor to inverted if cursor is the eraser */ gMsgPacket.pkStatus = (cursor->TYPE == CSR_TYPE_ERASER ? TPS_INVERT:0); gMsgPacket.pkStatus |= (event->type==proximity_out_type)?TPS_PROXIMITY:0; - gMsgPacket.pkTime = EVENT_x11_time_to_win32_time(proximity->time); + gMsgPacket.pkTime = x11drv_time_to_ticks(proximity->time); gMsgPacket.pkSerialNumber = gSerial++; gMsgPacket.pkCursor = curnum; gMsgPacket.pkX = proximity->axis_data[0]; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 4997367ce9a..439c90b8b27 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -578,7 +578,7 @@ extern int xinput2_opcode DECLSPEC_HIDDEN; extern Bool (*pXGetEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) DECLSPEC_HIDDEN; extern void (*pXFreeEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) DECLSPEC_HIDDEN; -extern DWORD EVENT_x11_time_to_win32_time(Time time) DECLSPEC_HIDDEN; +extern DWORD x11drv_time_to_ticks(Time time) DECLSPEC_HIDDEN; /* X11 driver private messages, must be in the range 0x80001000..0x80001fff */ enum x11drv_window_messages From 3cb3a78fa5c6dbf6686096b1337f8f5b87730d65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 17 Jan 2020 16:33:11 +0100 Subject: [PATCH 0168/2777] winex11.drv: Split XInput2 thread initialization. And rename the library and function loader to X11DRV_XInput2_Load. --- dlls/winex11.drv/mouse.c | 42 ++++++++++++++++++++++------------ dlls/winex11.drv/x11drv.h | 1 + dlls/winex11.drv/x11drv_main.c | 4 +++- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 881ea5f5441..aec8998f8e9 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -278,6 +278,30 @@ static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuator } +/*********************************************************************** + * X11DRV_XInput2_Init + */ +void X11DRV_XInput2_Init(void) +{ +#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + struct x11drv_thread_data *data = x11drv_thread_data(); + int major = 2, minor = 0; + + if (xinput2_available && + !pXIQueryVersion( data->display, &major, &minor )) + { + TRACE( "XInput2 %d.%d available\n", major, minor ); + data->xi2_state = xi_disabled; + } + else + { + data->xi2_state = xi_unavailable; + WARN( "XInput 2.0 not available\n" ); + } +#endif +} + + /*********************************************************************** * enable_xinput2 */ @@ -289,19 +313,7 @@ static void enable_xinput2(void) unsigned char mask_bits[XIMaskLen(XI_LASTEVENT)]; int count; - if (!xinput2_available) return; - - if (data->xi2_state == xi_unknown) - { - int major = 2, minor = 0; - if (!pXIQueryVersion( data->display, &major, &minor )) data->xi2_state = xi_disabled; - else - { - data->xi2_state = xi_unavailable; - WARN( "X Input 2 not available\n" ); - } - } - if (data->xi2_state == xi_unavailable) return; + if (data->xi2_state != xi_disabled) return; if (!pXIGetClientPointer( data->display, None, &data->xi2_core_pointer )) return; mask.mask = mask_bits; @@ -1955,9 +1967,9 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) /*********************************************************************** - * X11DRV_XInput2_Init + * X11DRV_XInput2_Load */ -void X11DRV_XInput2_Init(void) +void X11DRV_XInput2_Load(void) { #if defined(SONAME_LIBXI) && defined(HAVE_X11_EXTENSIONS_XINPUT2_H) int event, error; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 439c90b8b27..180fae408cb 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -257,6 +257,7 @@ extern void X11DRV_ThreadDetach(void) DECLSPEC_HIDDEN; /* X11 driver internal functions */ extern void X11DRV_Xcursor_Init(void) DECLSPEC_HIDDEN; +extern void X11DRV_XInput2_Load(void) DECLSPEC_HIDDEN; extern void X11DRV_XInput2_Init(void) DECLSPEC_HIDDEN; extern DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image, diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 797e4f92d38..9828502ed60 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -706,7 +706,7 @@ static NTSTATUS x11drv_init( void *arg ) #ifdef SONAME_LIBXCOMPOSITE X11DRV_XComposite_Init(); #endif - X11DRV_XInput2_Init(); + X11DRV_XInput2_Load(); #ifdef HAVE_XKB if (use_xkb) use_xkb = XkbUseExtension( gdi_display, NULL, NULL ); @@ -801,6 +801,8 @@ struct x11drv_thread_data *x11drv_init_thread_data(void) if (use_xim) X11DRV_SetupXIM(); + X11DRV_XInput2_Init(); + return data; } From 6cb0d4ce14364fac4572fd73e9843a51becd5226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 14 Nov 2021 14:09:48 +0100 Subject: [PATCH 0169/2777] winex11.drv: Advertise XInput2 version 2.1 support. Under XInput2 protocol version < 2.1, RawEvents are not supposed to be sent if a pointer grab is active. However slave device events are still received regardless of this specification and Wine implemented a workaround to receive RawEvents during pointer grabs by listening to these slave device events. Then, as soon as a mouse button is pressed only the grabbing client will receive the raw motion events. By advertising the support of XInput2 version >= 2.1, where RawEvents are sent even during pointer grabs, we ensure to receive the RawMotion events from the desktop window thread, even if a mouse grab is active. It is now also possible to simplify the code by listening to master device events only and get rid of slave device id tracking. --- dlls/winex11.drv/mouse.c | 46 ++++++++------------------------------- dlls/winex11.drv/x11drv.h | 3 --- 2 files changed, 9 insertions(+), 40 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index aec8998f8e9..11ff03ca5a5 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -285,7 +285,7 @@ void X11DRV_XInput2_Init(void) { #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H struct x11drv_thread_data *data = x11drv_thread_data(); - int major = 2, minor = 0; + int major = 2, minor = 1; if (xinput2_available && !pXIQueryVersion( data->display, &major, &minor )) @@ -296,7 +296,7 @@ void X11DRV_XInput2_Init(void) else { data->xi2_state = xi_unavailable; - WARN( "XInput 2.0 not available\n" ); + WARN( "XInput 2.1 not available\n" ); } #endif } @@ -318,7 +318,7 @@ static void enable_xinput2(void) mask.mask = mask_bits; mask.mask_len = sizeof(mask_bits); - mask.deviceid = XIAllDevices; + mask.deviceid = XIAllMasterDevices; memset( mask_bits, 0, sizeof(mask_bits) ); XISetMask( mask_bits, XI_DeviceChanged ); XISetMask( mask_bits, XI_RawMotion ); @@ -330,16 +330,6 @@ static void enable_xinput2(void) update_relative_valuators( pointer_info->classes, pointer_info->num_classes ); pXIFreeDeviceInfo( pointer_info ); - /* This device info list is only used to find the initial current slave if - * no XI_DeviceChanged events happened. If any hierarchy change occurred that - * might be relevant here (eg. user switching mice after (un)plugging), a - * XI_DeviceChanged event will point us to the right slave. So this list is - * safe to be obtained statically at enable_xinput2() time. - */ - if (data->xi2_devices) pXIFreeDeviceInfo( data->xi2_devices ); - data->xi2_devices = pXIQueryDevice( data->display, XIAllDevices, &data->xi2_device_count ); - data->xi2_current_slave = 0; - data->xi2_state = xi_enabled; } @@ -361,17 +351,15 @@ static void disable_xinput2(void) mask.mask = NULL; mask.mask_len = 0; - mask.deviceid = XIAllDevices; + mask.deviceid = XIAllMasterDevices; pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); - pXIFreeDeviceInfo( data->xi2_devices ); + data->x_valuator.number = -1; data->y_valuator.number = -1; data->x_valuator.value = 0; data->y_valuator.value = 0; - data->xi2_devices = NULL; data->xi2_core_pointer = 0; - data->xi2_current_slave = 0; #endif } @@ -648,6 +636,8 @@ static void map_event_coords( HWND hwnd, Window window, Window event_root, int x input->u.mi.dy = pt.y; } + + /*********************************************************************** * send_mouse_input * @@ -1859,7 +1849,6 @@ static BOOL X11DRV_DeviceChanged( XGenericEventCookie *xev ) if (event->reason != XISlaveSwitch) return FALSE; update_relative_valuators( event->classes, event->num_classes ); - data->xi2_current_slave = event->sourceid; return TRUE; } @@ -1875,25 +1864,7 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input ) if (x->number < 0 || y->number < 0) return FALSE; if (!event->valuators.mask_len) return FALSE; if (thread_data->xi2_state != xi_enabled) return FALSE; - - /* If there is no slave currently detected, no previous motion nor device - * change events were received. Look it up now on the device list in this - * case. - */ - if (!thread_data->xi2_current_slave) - { - XIDeviceInfo *devices = thread_data->xi2_devices; - - for (i = 0; i < thread_data->xi2_device_count; i++) - { - if (devices[i].use != XISlavePointer) continue; - if (devices[i].deviceid != event->deviceid) continue; - if (devices[i].attachment != thread_data->xi2_core_pointer) continue; - thread_data->xi2_current_slave = event->deviceid; - break; - } - } - if (event->deviceid != thread_data->xi2_current_slave) return FALSE; + if (event->deviceid != thread_data->xi2_core_pointer) return FALSE; virtual_rect = NtUserGetVirtualScreenRect(); @@ -1936,6 +1907,7 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input ) return TRUE; } + /*********************************************************************** * X11DRV_RawMotion */ diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 180fae408cb..9d71b1fdb13 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -389,12 +389,9 @@ struct x11drv_thread_data DWORD clip_reset; /* time when clipping was last reset */ #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled } xi2_state; /* XInput2 state */ - void *xi2_devices; /* list of XInput2 devices (valid when state is enabled) */ - int xi2_device_count; XIValuatorClassInfo x_valuator; XIValuatorClassInfo y_valuator; int xi2_core_pointer; /* XInput2 core pointer id */ - int xi2_current_slave; /* Current slave driving the Core pointer */ #endif /* HAVE_X11_EXTENSIONS_XINPUT2_H */ }; From b3fe164fa61a6bff44ce7c722e6af9ffb19728c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 14 Nov 2021 14:35:52 +0100 Subject: [PATCH 0170/2777] winex11.drv: Check for XInput2 core pointer on initialization. --- dlls/winex11.drv/mouse.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 11ff03ca5a5..a039eb5db1a 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -287,14 +287,15 @@ void X11DRV_XInput2_Init(void) struct x11drv_thread_data *data = x11drv_thread_data(); int major = 2, minor = 1; - if (xinput2_available && - !pXIQueryVersion( data->display, &major, &minor )) + if (xinput2_available && pXIQueryVersion( data->display, &major, &minor ) == Success && + pXIGetClientPointer( data->display, None, &data->xi2_core_pointer )) { TRACE( "XInput2 %d.%d available\n", major, minor ); data->xi2_state = xi_disabled; } else { + data->xi2_core_pointer = 0; data->xi2_state = xi_unavailable; WARN( "XInput 2.1 not available\n" ); } @@ -314,7 +315,6 @@ static void enable_xinput2(void) int count; if (data->xi2_state != xi_disabled) return; - if (!pXIGetClientPointer( data->display, None, &data->xi2_core_pointer )) return; mask.mask = mask_bits; mask.mask_len = sizeof(mask_bits); @@ -359,7 +359,6 @@ static void disable_xinput2(void) data->y_valuator.number = -1; data->x_valuator.value = 0; data->y_valuator.value = 0; - data->xi2_core_pointer = 0; #endif } From c62fa3a92e2b6bbfbff329b4508d9604116528af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 14 Nov 2021 14:38:45 +0100 Subject: [PATCH 0171/2777] winex11.drv: Reset XInput2 valuators only on DeviceChange events. --- dlls/winex11.drv/mouse.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index a039eb5db1a..13480fce1b2 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -354,11 +354,6 @@ static void disable_xinput2(void) mask.deviceid = XIAllMasterDevices; pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); - - data->x_valuator.number = -1; - data->y_valuator.number = -1; - data->x_valuator.value = 0; - data->y_valuator.value = 0; #endif } From cbe579c5c7a768b30418aa27aec7750028b96b17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 14 Nov 2021 14:39:51 +0100 Subject: [PATCH 0172/2777] winex11.drv: Stop tracking XInput2 enabled state. It should not be very useful anymore and it'll be meaningless later. --- dlls/winex11.drv/mouse.c | 22 ---------------------- dlls/winex11.drv/x11drv.h | 1 - 2 files changed, 23 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 13480fce1b2..ff47e5edda9 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -289,14 +289,10 @@ void X11DRV_XInput2_Init(void) if (xinput2_available && pXIQueryVersion( data->display, &major, &minor ) == Success && pXIGetClientPointer( data->display, None, &data->xi2_core_pointer )) - { TRACE( "XInput2 %d.%d available\n", major, minor ); - data->xi2_state = xi_disabled; - } else { data->xi2_core_pointer = 0; - data->xi2_state = xi_unavailable; WARN( "XInput 2.1 not available\n" ); } #endif @@ -314,8 +310,6 @@ static void enable_xinput2(void) unsigned char mask_bits[XIMaskLen(XI_LASTEVENT)]; int count; - if (data->xi2_state != xi_disabled) return; - mask.mask = mask_bits; mask.mask_len = sizeof(mask_bits); mask.deviceid = XIAllMasterDevices; @@ -329,8 +323,6 @@ static void enable_xinput2(void) pointer_info = pXIQueryDevice( data->display, data->xi2_core_pointer, &count ); update_relative_valuators( pointer_info->classes, pointer_info->num_classes ); pXIFreeDeviceInfo( pointer_info ); - - data->xi2_state = xi_enabled; } #endif @@ -344,11 +336,6 @@ static void disable_xinput2(void) struct x11drv_thread_data *data = x11drv_thread_data(); XIEventMask mask; - if (data->xi2_state != xi_enabled) return; - - TRACE( "disabling\n" ); - data->xi2_state = xi_disabled; - mask.mask = NULL; mask.mask_len = 0; mask.deviceid = XIAllMasterDevices; @@ -401,14 +388,6 @@ static BOOL grab_clipping_window( const RECT *clip ) /* enable XInput2 unless we are already clipping */ if (!data->clip_hwnd) enable_xinput2(); - if (data->xi2_state != xi_enabled) - { - WARN( "XInput2 not supported, refusing to clip to %s\n", wine_dbgstr_rect(clip) ); - NtUserDestroyWindow( msg_hwnd ); - NtUserClipCursor( NULL ); - return TRUE; - } - TRACE( "clipping to %s win %lx\n", wine_dbgstr_rect(clip), clip_window ); if (!data->clip_hwnd) XUnmapWindow( data->display, clip_window ); @@ -1857,7 +1836,6 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input ) if (x->number < 0 || y->number < 0) return FALSE; if (!event->valuators.mask_len) return FALSE; - if (thread_data->xi2_state != xi_enabled) return FALSE; if (event->deviceid != thread_data->xi2_core_pointer) return FALSE; virtual_rect = NtUserGetVirtualScreenRect(); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 9d71b1fdb13..101718a1cbc 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -388,7 +388,6 @@ struct x11drv_thread_data HWND clip_hwnd; /* message window stored in desktop while clipping is active */ DWORD clip_reset; /* time when clipping was last reset */ #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled } xi2_state; /* XInput2 state */ XIValuatorClassInfo x_valuator; XIValuatorClassInfo y_valuator; int xi2_core_pointer; /* XInput2 core pointer id */ From 9ff8a554b4b9e667fda62e388686ef0b672e9f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 19 Dec 2019 22:34:44 +0100 Subject: [PATCH 0173/2777] winex11.drv: Keep track of pointer and device button mappings. We are going to receive raw button events and we will need to apply the correct button mappings ourselves. Original patch by Andrew Eikum . --- dlls/winex11.drv/keyboard.c | 23 ++++++--- dlls/winex11.drv/mouse.c | 93 +++++++++++++++++++++++++++++++--- dlls/winex11.drv/x11drv.h | 1 + dlls/winex11.drv/x11drv_main.c | 1 + 4 files changed, 105 insertions(+), 13 deletions(-) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index a17177c7b82..9aab9681e27 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1880,13 +1880,24 @@ BOOL X11DRV_MappingNotify( HWND dummy, XEvent *event ) { HWND hwnd; - XRefreshKeyboardMapping(&event->xmapping); - X11DRV_InitKeyboard( event->xmapping.display ); + switch (event->xmapping.request) + { + case MappingModifier: + case MappingKeyboard: + XRefreshKeyboardMapping( &event->xmapping ); + X11DRV_InitKeyboard( event->xmapping.display ); + + hwnd = get_focus(); + if (!hwnd) hwnd = get_active_window(); + NtUserPostMessage( hwnd, WM_INPUTLANGCHANGEREQUEST, + 0 /*FIXME*/, (LPARAM)NtUserGetKeyboardLayout(0) ); + break; + + case MappingPointer: + X11DRV_InitMouse( event->xmapping.display ); + break; + } - hwnd = get_focus(); - if (!hwnd) hwnd = get_active_window(); - NtUserPostMessage( hwnd, WM_INPUTLANGCHANGEREQUEST, - 0 /*FIXME*/, (LPARAM)NtUserGetKeyboardLayout(0) ); return TRUE; } diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index ff47e5edda9..e3c421fd8c6 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -30,6 +30,9 @@ #include #include #include +#ifdef HAVE_X11_EXTENSIONS_XINPUT_H +#include +#endif #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H #include #endif @@ -144,6 +147,14 @@ MAKE_FUNCPTR(XISelectEvents); #undef MAKE_FUNCPTR #endif +#ifdef HAVE_X11_EXTENSIONS_XINPUT_H +#define MAKE_FUNCPTR(f) static typeof(f) * p##f +MAKE_FUNCPTR(XOpenDevice); +MAKE_FUNCPTR(XCloseDevice); +MAKE_FUNCPTR(XGetDeviceButtonMapping); +#undef MAKE_FUNCPTR +#endif + /*********************************************************************** * X11DRV_Xcursor_Init * @@ -249,6 +260,66 @@ void sync_window_cursor( Window window ) set_window_cursor( window, cursor ); } +struct mouse_button_mapping +{ + int deviceid; + unsigned int button_count; + unsigned char buttons[256]; +}; + +static struct mouse_button_mapping *pointer_mapping; +static struct mouse_button_mapping *device_mapping; + +static void update_pointer_mapping( Display *display ) +{ + struct mouse_button_mapping *tmp; + + if (!(tmp = malloc( sizeof(*tmp) ))) + { + WARN("Unable to allocate device mapping.\n"); + return; + } + + tmp->button_count = ARRAY_SIZE( tmp->buttons ); + tmp->button_count = XGetPointerMapping( display, tmp->buttons, tmp->button_count ); + + free( InterlockedExchangePointer( (void**)&pointer_mapping, tmp ) ); +} + +static void update_device_mapping( Display *display, int deviceid ) +{ +#ifdef HAVE_X11_EXTENSIONS_XINPUT_H + struct mouse_button_mapping *tmp; + XDevice *device; + + if (!(device = pXOpenDevice( display, deviceid ))) + { + WARN( "Unable to open cursor device %d\n", deviceid ); + return; + } + + if (!(tmp = malloc( sizeof(*tmp) ))) + { + WARN( "Unable to allocate device mapping.\n" ); + pXCloseDevice( display, device ); + return; + } + + tmp->deviceid = deviceid; + tmp->button_count = ARRAY_SIZE( tmp->buttons ); + tmp->button_count = pXGetDeviceButtonMapping( display, device, tmp->buttons, tmp->button_count ); + + free( InterlockedExchangePointer( (void**)&device_mapping, tmp ) ); + + pXCloseDevice( display, device ); +#endif +} + +void X11DRV_InitMouse( Display *display ) +{ + update_pointer_mapping( display ); +} + #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H /*********************************************************************** * update_relative_valuators @@ -1811,17 +1882,18 @@ BOOL X11DRV_EnterNotify( HWND hwnd, XEvent *xev ) #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H /*********************************************************************** - * X11DRV_DeviceChanged + * X11DRV_XIDeviceChangedEvent */ -static BOOL X11DRV_DeviceChanged( XGenericEventCookie *xev ) +static BOOL X11DRV_XIDeviceChangedEvent( XIDeviceChangedEvent *event ) { - XIDeviceChangedEvent *event = xev->data; struct x11drv_thread_data *data = x11drv_thread_data(); if (event->deviceid != data->xi2_core_pointer) return FALSE; if (event->reason != XISlaveSwitch) return FALSE; update_relative_valuators( event->classes, event->num_classes ); + update_device_mapping( event->display, event->sourceid ); + return TRUE; } @@ -1909,13 +1981,12 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) #endif /* HAVE_X11_EXTENSIONS_XINPUT2_H */ - /*********************************************************************** * X11DRV_XInput2_Load */ void X11DRV_XInput2_Load(void) { -#if defined(SONAME_LIBXI) && defined(HAVE_X11_EXTENSIONS_XINPUT2_H) +#if defined(SONAME_LIBXI) int event, error; void *libxi_handle = dlopen( SONAME_LIBXI, RTLD_NOW ); @@ -1931,11 +2002,20 @@ void X11DRV_XInput2_Load(void) return; \ } +#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H LOAD_FUNCPTR(XIGetClientPointer); LOAD_FUNCPTR(XIFreeDeviceInfo); LOAD_FUNCPTR(XIQueryDevice); LOAD_FUNCPTR(XIQueryVersion); LOAD_FUNCPTR(XISelectEvents); +#endif + +#ifdef HAVE_X11_EXTENSIONS_XINPUT_H + LOAD_FUNCPTR(XOpenDevice); + LOAD_FUNCPTR(XCloseDevice); + LOAD_FUNCPTR(XGetDeviceButtonMapping); +#endif + #undef LOAD_FUNCPTR xinput2_available = XQueryExtension( gdi_display, "XInputExtension", &xinput2_opcode, &event, &error ); @@ -1966,8 +2046,7 @@ BOOL X11DRV_GenericEvent( HWND hwnd, XEvent *xev ) switch (event->evtype) { case XI_DeviceChanged: - ret = X11DRV_DeviceChanged( event ); - break; + return X11DRV_XIDeviceChangedEvent( event->data ); case XI_RawMotion: ret = X11DRV_RawMotion( event ); break; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 101718a1cbc..dd2a7cff05b 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -688,6 +688,7 @@ extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN; extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN; extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN; extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN; +extern void X11DRV_InitMouse( Display *display ) DECLSPEC_HIDDEN; extern NTSTATUS X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, const LARGE_INTEGER *timeout, DWORD mask, DWORD flags ) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 9828502ed60..36e0598251a 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -712,6 +712,7 @@ static NTSTATUS x11drv_init( void *arg ) if (use_xkb) use_xkb = XkbUseExtension( gdi_display, NULL, NULL ); #endif X11DRV_InitKeyboard( gdi_display ); + X11DRV_InitMouse( gdi_display ); if (use_xim) use_xim = X11DRV_InitXIM( input_style ); init_user_driver(); From f9c83ce1a7413ddd2c7281d9c4f982ce3bf6ad59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 14 Nov 2021 14:40:55 +0100 Subject: [PATCH 0174/2777] winex11.drv: Support XInput2 events for individual windows. This will allow us to listen to the XInput version of several events, which can bring additional information. --- dlls/winex11.drv/desktop.c | 1 + dlls/winex11.drv/event.c | 16 ++++++ dlls/winex11.drv/mouse.c | 107 +++++++++++++++++++++++++++---------- dlls/winex11.drv/window.c | 3 ++ dlls/winex11.drv/x11drv.h | 1 + 5 files changed, 99 insertions(+), 29 deletions(-) diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c index bb998543ae7..89a703bff7b 100644 --- a/dlls/winex11.drv/desktop.c +++ b/dlls/winex11.drv/desktop.c @@ -394,6 +394,7 @@ NTSTATUS x11drv_create_desktop( void *arg ) 0, 0, params->width, params->height, 0, default_visual.depth, InputOutput, default_visual.visual, CWEventMask | CWCursor | CWColormap, &win_attr ); if (!win) return FALSE; + X11DRV_XInput2_Enable( display, win, win_attr.event_mask ); if (!create_desktop_win_data( win )) return FALSE; X11DRV_init_desktop( win, params->width, params->height ); diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 1b1117df4cb..47af83cbda6 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -237,6 +237,22 @@ static Bool filter_event( Display *display, XEvent *event, char *arg ) return (mask & QS_MOUSEBUTTON) != 0; #ifdef GenericEvent case GenericEvent: +#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + if (event->xcookie.extension == xinput2_opcode) + { + switch (event->xcookie.evtype) + { + case XI_RawButtonPress: + case XI_RawButtonRelease: + return (mask & QS_MOUSEBUTTON) != 0; + case XI_RawMotion: + return (mask & QS_INPUT) != 0; + case XI_DeviceChanged: + return (mask & (QS_INPUT|QS_MOUSEBUTTON)) != 0; + } + } +#endif + return (mask & QS_SENDMESSAGE) != 0; #endif case MotionNotify: case EnterNotify: diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index e3c421fd8c6..f58d0a39d38 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -371,25 +371,42 @@ void X11DRV_XInput2_Init(void) /*********************************************************************** - * enable_xinput2 + * X11DRV_XInput2_Enable */ -static void enable_xinput2(void) +void X11DRV_XInput2_Enable( Display *display, Window window, long event_mask ) { struct x11drv_thread_data *data = x11drv_thread_data(); - XIEventMask mask; - XIDeviceInfo *pointer_info; unsigned char mask_bits[XIMaskLen(XI_LASTEVENT)]; + BOOL raw = (window == None); + XIDeviceInfo *pointer_info; + XIEventMask mask; int count; mask.mask = mask_bits; mask.mask_len = sizeof(mask_bits); mask.deviceid = XIAllMasterDevices; memset( mask_bits, 0, sizeof(mask_bits) ); - XISetMask( mask_bits, XI_DeviceChanged ); - XISetMask( mask_bits, XI_RawMotion ); - XISetMask( mask_bits, XI_ButtonPress ); - pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); + /* FIXME: steam overlay doesn't like if we use XI2 for non-raw events */ + + if (event_mask & PointerMotionMask) + { + XISetMask( mask_bits, XI_DeviceChanged ); + if (raw) XISetMask( mask_bits, XI_RawMotion ); + } + if (event_mask & ButtonPressMask) + { + XISetMask( mask_bits, XI_DeviceChanged ); + if (raw) XISetMask( mask_bits, XI_RawButtonPress ); + } + if (event_mask & ButtonReleaseMask) + { + XISetMask( mask_bits, XI_DeviceChanged ); + if (raw) XISetMask( mask_bits, XI_RawButtonRelease ); + } + + pXISelectEvents( display, raw ? DefaultRootWindow( display ) : window, &mask, 1 ); + if (!raw) XSelectInput( display, window, event_mask ); pointer_info = pXIQueryDevice( data->display, data->xi2_core_pointer, &count ); update_relative_valuators( pointer_info->classes, pointer_info->num_classes ); @@ -398,24 +415,6 @@ static void enable_xinput2(void) #endif -/*********************************************************************** - * disable_xinput2 - */ -static void disable_xinput2(void) -{ -#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - struct x11drv_thread_data *data = x11drv_thread_data(); - XIEventMask mask; - - mask.mask = NULL; - mask.mask_len = 0; - mask.deviceid = XIAllMasterDevices; - - pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 ); -#endif -} - - /*********************************************************************** * grab_clipping_window * @@ -457,7 +456,7 @@ static BOOL grab_clipping_window( const RECT *clip ) } /* enable XInput2 unless we are already clipping */ - if (!data->clip_hwnd) enable_xinput2(); + if (!data->clip_hwnd) X11DRV_XInput2_Enable( data->display, None, PointerMotionMask ); TRACE( "clipping to %s win %lx\n", wine_dbgstr_rect(clip), clip_window ); @@ -479,7 +478,7 @@ static BOOL grab_clipping_window( const RECT *clip ) if (!clipping_cursor) { - disable_xinput2(); + X11DRV_XInput2_Enable( data->display, None, 0 ); NtUserDestroyWindow( msg_hwnd ); return FALSE; } @@ -562,7 +561,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) TRACE( "clip hwnd reset from %p\n", hwnd ); data->clip_hwnd = 0; data->clip_reset = NtGetTickCount(); - disable_xinput2(); + X11DRV_XInput2_Enable( data->display, None, 0 ); NtUserDestroyWindow( hwnd ); } else if (prev_clip_hwnd) @@ -1979,6 +1978,52 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) return TRUE; } +static BOOL X11DRV_XIDeviceEvent( XIDeviceEvent *event ) +{ + DWORD button = event->detail - 1; + INPUT input; + HWND hwnd; + + if (XFindContext( event->display, event->event, winContext, (char **)&hwnd ) != 0) + hwnd = 0; /* not for a registered window */ + if (!hwnd && event->event == root_window) hwnd = NtUserGetDesktopWindow(); + + TRACE( "evtype %u hwnd %p/%lx pos %f,%f detail %u flags %#x serial %lu\n", + event->evtype, hwnd, event->event, event->event_x, event->event_y, event->detail, event->flags, event->serial ); + + if (!hwnd && is_old_motion_event( event->serial )) + { + TRACE( "pos %f,%f old serial %lu, ignoring\n", event->event_x, event->event_y, event->serial ); + return FALSE; + } + + input.u.mi.dx = event->event_x; + input.u.mi.dy = event->event_y; + input.u.mi.mouseData = 0; + input.u.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; + input.u.mi.time = x11drv_time_to_ticks( event->time ); + input.u.mi.dwExtraInfo = 0; + + switch (event->evtype) + { + case XI_ButtonPress: + if (button >= NB_BUTTONS) return FALSE; + update_user_time( event->time ); + input.u.mi.mouseData = button_down_data[button]; + input.u.mi.dwFlags |= button_down_flags[button]; + break; + case XI_ButtonRelease: + if (button >= NB_BUTTONS) return FALSE; + input.u.mi.mouseData = button_up_data[button]; + input.u.mi.dwFlags |= button_up_flags[button]; + break; + } + + map_event_coords( hwnd, event->event, event->root, event->root_x, event->root_y, &input ); + send_mouse_input( hwnd, event->event, event->detail, &input ); + return TRUE; +} + #endif /* HAVE_X11_EXTENSIONS_XINPUT2_H */ /*********************************************************************** @@ -2050,6 +2095,10 @@ BOOL X11DRV_GenericEvent( HWND hwnd, XEvent *xev ) case XI_RawMotion: ret = X11DRV_RawMotion( event ); break; + case XI_Motion: + case XI_ButtonPress: + case XI_ButtonRelease: + return X11DRV_XIDeviceEvent( event->data ); default: TRACE( "Unhandled event %#x\n", event->evtype ); diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 5150b552faf..7e1a1c52341 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -362,6 +362,7 @@ static void sync_window_style( struct x11drv_win_data *data ) int mask = get_window_attributes( data, &attr ); XChangeWindowAttributes( data->display, data->whole_window, mask, &attr ); + X11DRV_XInput2_Enable( data->display, data->whole_window, attr.event_mask ); } } @@ -1658,6 +1659,7 @@ static void create_whole_window( struct x11drv_win_data *data ) data->vis.visual, mask, &attr ); if (!data->whole_window) goto done; + X11DRV_XInput2_Enable( data->display, data->whole_window, attr.event_mask ); set_initial_wm_hints( data->display, data->whole_window ); set_wm_hints( data ); @@ -1973,6 +1975,7 @@ BOOL X11DRV_CreateWindow( HWND hwnd ) data->clip_window = XCreateWindow( data->display, root_window, 0, 0, 1, 1, 0, 0, InputOnly, default_visual.visual, CWOverrideRedirect | CWEventMask, &attr ); + X11DRV_XInput2_Enable( data->display, data->clip_window, attr.event_mask ); XFlush( data->display ); NtUserSetProp( hwnd, clip_window_prop, (HANDLE)data->clip_window ); X11DRV_DisplayDevices_RegisterEventHandlers(); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index dd2a7cff05b..9ec3712c6aa 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -259,6 +259,7 @@ extern void X11DRV_ThreadDetach(void) DECLSPEC_HIDDEN; extern void X11DRV_Xcursor_Init(void) DECLSPEC_HIDDEN; extern void X11DRV_XInput2_Load(void) DECLSPEC_HIDDEN; extern void X11DRV_XInput2_Init(void) DECLSPEC_HIDDEN; +extern void X11DRV_XInput2_Enable( Display *display, Window window, long event_mask ) DECLSPEC_HIDDEN; extern DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image, const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits, From 4fc2c76c610382f5d3716b59baa8c5b10667ed50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 26 Aug 2019 14:37:20 +0200 Subject: [PATCH 0175/2777] server: Add send_hardware_message flags for rawinput translation. --- dlls/win32u/message.c | 2 ++ server/protocol.def | 1 + server/queue.c | 12 ++++++------ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index f439b7da23b..c4adba96740 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2623,6 +2623,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r req->input.mouse.flags = input->mi.dwFlags; req->input.mouse.time = input->mi.time; req->input.mouse.info = input->mi.dwExtraInfo; + req->flags |= SEND_HWMSG_RAWINPUT; break; case INPUT_KEYBOARD: req->input.kbd.vkey = input->ki.wVk; @@ -2630,6 +2631,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r req->input.kbd.flags = input->ki.dwFlags; req->input.kbd.time = input->ki.time; req->input.kbd.info = input->ki.dwExtraInfo; + req->flags |= SEND_HWMSG_RAWINPUT; break; case INPUT_HARDWARE: req->input.hw.msg = input->hi.uMsg; diff --git a/server/protocol.def b/server/protocol.def index c512491a673..880ad794982 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2081,6 +2081,7 @@ enum message_type VARARG(keystate,bytes); /* global state array for all the keys */ @END #define SEND_HWMSG_INJECTED 0x01 +#define SEND_HWMSG_RAWINPUT 0x02 /* Get a message from the current queue */ diff --git a/server/queue.c b/server/queue.c index 5c246459f50..7eeaeb0aa82 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1782,7 +1782,7 @@ static int queue_rawinput_message( struct process* process, void *arg ) /* queue a hardware message for a mouse event */ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, - unsigned int origin, struct msg_queue *sender ) + unsigned int origin, struct msg_queue *sender, unsigned int req_flags ) { const struct rawinput_device *device; struct hardware_msg_data *msg_data; @@ -1837,7 +1837,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons y = desktop->cursor.y; } - if ((foreground = get_foreground_thread( desktop, win ))) + if ((req_flags & SEND_HWMSG_RAWINPUT) && (foreground = get_foreground_thread( desktop, win ))) { memset( &raw_msg, 0, sizeof(raw_msg) ); raw_msg.foreground = foreground; @@ -1896,7 +1896,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons /* queue a hardware message for a keyboard event */ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, - unsigned int origin, struct msg_queue *sender ) + unsigned int origin, struct msg_queue *sender, unsigned int req_flags ) { struct hw_msg_source source = { IMDT_KEYBOARD, origin }; const struct rawinput_device *device; @@ -1974,7 +1974,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c break; } - if ((foreground = get_foreground_thread( desktop, win ))) + if ((req_flags & SEND_HWMSG_RAWINPUT) && (foreground = get_foreground_thread( desktop, win ))) { memset( &raw_msg, 0, sizeof(raw_msg) ); raw_msg.foreground = foreground; @@ -2604,10 +2604,10 @@ DECL_HANDLER(send_hardware_message) switch (req->input.type) { case INPUT_MOUSE: - reply->wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender ); + reply->wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender, req->flags ); break; case INPUT_KEYBOARD: - reply->wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender ); + reply->wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender, req->flags ); break; case INPUT_HARDWARE: queue_custom_hardware_message( desktop, req->win, origin, &req->input ); From e1e6e0546e019089bb26609934bdad90697177c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 24 Mar 2021 23:29:28 +0100 Subject: [PATCH 0176/2777] user32: Set SEND_HWMSG_RAWINPUT flags only when RAWINPUT is set. So we can generate legacy messages only by calling __wine_send_input with NULL rawinput, and generate WM_INPUT messages only by calling __wine_send_input with INPUT_HARDWARE input type and a rawinput. --- dlls/win32u/input.c | 3 ++- dlls/win32u/message.c | 4 ++-- dlls/wineandroid.drv/keyboard.c | 3 ++- dlls/wineandroid.drv/window.c | 5 +++-- dlls/winemac.drv/ime.c | 6 ++++-- dlls/winemac.drv/keyboard.c | 3 ++- dlls/winemac.drv/mouse.c | 3 ++- dlls/winex11.drv/keyboard.c | 3 ++- dlls/winex11.drv/mouse.c | 11 +++++++---- 9 files changed, 26 insertions(+), 15 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index fd16d03f733..3f8b960215b 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -131,6 +131,7 @@ UINT WINAPI NtUserSendInput( UINT count, INPUT *inputs, int size ) { UINT i; NTSTATUS status = STATUS_SUCCESS; + RAWINPUT rawinput; if (size != sizeof(INPUT)) { @@ -160,7 +161,7 @@ UINT WINAPI NtUserSendInput( UINT count, INPUT *inputs, int size ) update_mouse_coords( &input ); /* fallthrough */ case INPUT_KEYBOARD: - status = send_hardware_message( 0, &input, NULL, SEND_HWMSG_INJECTED ); + status = send_hardware_message( 0, &input, &rawinput, SEND_HWMSG_INJECTED ); break; case INPUT_HARDWARE: RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED ); diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index c4adba96740..0299285f589 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2623,7 +2623,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r req->input.mouse.flags = input->mi.dwFlags; req->input.mouse.time = input->mi.time; req->input.mouse.info = input->mi.dwExtraInfo; - req->flags |= SEND_HWMSG_RAWINPUT; + if (rawinput) req->flags |= SEND_HWMSG_RAWINPUT; break; case INPUT_KEYBOARD: req->input.kbd.vkey = input->ki.wVk; @@ -2631,7 +2631,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r req->input.kbd.flags = input->ki.dwFlags; req->input.kbd.time = input->ki.time; req->input.kbd.info = input->ki.dwExtraInfo; - req->flags |= SEND_HWMSG_RAWINPUT; + if (rawinput) req->flags |= SEND_HWMSG_RAWINPUT; break; case INPUT_HARDWARE: req->input.hw.msg = input->hi.uMsg; diff --git a/dlls/wineandroid.drv/keyboard.c b/dlls/wineandroid.drv/keyboard.c index 7c55c481353..9a20daf8809 100644 --- a/dlls/wineandroid.drv/keyboard.c +++ b/dlls/wineandroid.drv/keyboard.c @@ -674,6 +674,7 @@ static BOOL get_async_key_state( BYTE state[256] ) static void send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags ) { + RAWINPUT rawinput; INPUT input; input.type = INPUT_KEYBOARD; @@ -683,7 +684,7 @@ static void send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags ) input.u.ki.time = 0; input.u.ki.dwExtraInfo = 0; - __wine_send_input( hwnd, &input, NULL ); + __wine_send_input( hwnd, &input, &rawinput ); } /*********************************************************************** diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index a339c20ceda..222751abc29 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -424,6 +424,7 @@ static int process_events( DWORD mask ) DPI_AWARENESS_CONTEXT context; struct java_event *event, *next, *previous; unsigned int count = 0; + RAWINPUT rawinput; assert( GetCurrentThreadId() == desktop_tid ); @@ -517,7 +518,7 @@ static int process_events( DWORD mask ) } SERVER_END_REQ; } - __wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input, NULL ); + __wine_send_input( capture ? capture : event->data.motion.hwnd, &event->data.motion.input, &rawinput ); } break; @@ -531,7 +532,7 @@ static int process_events( DWORD mask ) event->data.kbd.input.u.ki.wVk, event->data.kbd.input.u.ki.wVk, event->data.kbd.input.u.ki.wScan ); update_keyboard_lock_state( event->data.kbd.input.u.ki.wVk, event->data.kbd.lock_state ); - __wine_send_input( 0, &event->data.kbd.input, NULL ); + __wine_send_input( 0, &event->data.kbd.input, &rawinput ); break; default: diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index 19a974b3c24..163980dd691 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -37,6 +37,7 @@ #include "macdrv_dll.h" #include "imm.h" #include "ddk/imm.h" +#include "wine/server.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(imm); @@ -1409,6 +1410,7 @@ NTSTATUS WINAPI macdrv_ime_set_text(void *arg, ULONG size) params->cursor_pos, !params->complete); else { + RAWINPUT rawinput; INPUT input; unsigned int i; @@ -1421,10 +1423,10 @@ NTSTATUS WINAPI macdrv_ime_set_text(void *arg, ULONG size) { input.ki.wScan = params->text[i]; input.ki.dwFlags = KEYEVENTF_UNICODE; - __wine_send_input(hwnd, &input, NULL); + __wine_send_input(hwnd, &input, &rawinput); input.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP; - __wine_send_input(hwnd, &input, NULL); + __wine_send_input(hwnd, &input, &rawinput); } } } diff --git a/dlls/winemac.drv/keyboard.c b/dlls/winemac.drv/keyboard.c index 76c038caf02..9e415bd70e3 100644 --- a/dlls/winemac.drv/keyboard.c +++ b/dlls/winemac.drv/keyboard.c @@ -990,6 +990,7 @@ void macdrv_compute_keyboard_layout(struct macdrv_thread_data *thread_data) */ static void macdrv_send_keyboard_input(HWND hwnd, WORD vkey, WORD scan, unsigned int flags, unsigned int time) { + RAWINPUT rawinput; INPUT input; TRACE_(key)("hwnd %p vkey=%04x scan=%04x flags=%04x\n", hwnd, vkey, scan, flags); @@ -1001,7 +1002,7 @@ static void macdrv_send_keyboard_input(HWND hwnd, WORD vkey, WORD scan, unsigned input.ki.time = time; input.ki.dwExtraInfo = 0; - __wine_send_input(hwnd, &input, NULL); + __wine_send_input(hwnd, &input, &rawinput); } diff --git a/dlls/winemac.drv/mouse.c b/dlls/winemac.drv/mouse.c index cb194095d55..74c329488c4 100644 --- a/dlls/winemac.drv/mouse.c +++ b/dlls/winemac.drv/mouse.c @@ -129,6 +129,7 @@ static const CFStringRef cocoa_cursor_names[] = static void send_mouse_input(HWND hwnd, macdrv_window cocoa_window, UINT flags, int x, int y, DWORD mouse_data, BOOL drag, unsigned long time) { + RAWINPUT rawinput; INPUT input; HWND top_level_hwnd; @@ -158,7 +159,7 @@ static void send_mouse_input(HWND hwnd, macdrv_window cocoa_window, UINT flags, input.mi.time = time; input.mi.dwExtraInfo = 0; - __wine_send_input(top_level_hwnd, &input, NULL); + __wine_send_input(top_level_hwnd, &input, &rawinput); } diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 9aab9681e27..12bb2b863cb 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1134,6 +1134,7 @@ static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e) */ static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, UINT flags, UINT time ) { + RAWINPUT rawinput; INPUT input; TRACE_(key)( "hwnd %p vkey=%04x scan=%04x flags=%04x\n", hwnd, vkey, scan, flags ); @@ -1145,7 +1146,7 @@ static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, UINT fl input.u.ki.time = time; input.u.ki.dwExtraInfo = 0; - __wine_send_input( hwnd, &input, NULL ); + __wine_send_input( hwnd, &input, &rawinput ); } diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index f58d0a39d38..d4f8481e15f 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -689,6 +689,7 @@ static void map_event_coords( HWND hwnd, Window window, Window event_root, int x static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPUT *input ) { struct x11drv_win_data *data; + RAWINPUT rawinput; Window win = 0; input->type = INPUT_MOUSE; @@ -706,7 +707,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU sync_window_cursor( window ); last_cursor_change = input->u.mi.time; } - __wine_send_input( hwnd, input, NULL ); + __wine_send_input( hwnd, input, &rawinput ); return; } @@ -747,7 +748,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU SERVER_END_REQ; } - __wine_send_input( hwnd, input, NULL ); + __wine_send_input( hwnd, input, &rawinput ); } #ifdef SONAME_LIBXCURSOR @@ -1730,6 +1731,7 @@ void move_resize_window( HWND hwnd, int dir ) { MSG msg; INPUT input; + RAWINPUT rawinput; int x, y, rootX, rootY; if (!XQueryPointer( display, root_window, &root, &child, &rootX, &rootY, &x, &y, &xstate )) break; @@ -1745,7 +1747,7 @@ void move_resize_window( HWND hwnd, int dir ) input.u.mi.dwFlags = button_up_flags[button - 1] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; input.u.mi.time = NtGetTickCount(); input.u.mi.dwExtraInfo = 0; - __wine_send_input( hwnd, &input, NULL ); + __wine_send_input( hwnd, &input, &rawinput ); } while (NtUserPeekMessage( &msg, 0, 0, 0, PM_REMOVE )) @@ -1957,6 +1959,7 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input ) static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) { XIRawEvent *event = xev->data; + RAWINPUT rawinput; INPUT input; if (broken_rawevents && is_old_motion_event( xev->serial )) @@ -1974,7 +1977,7 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) input.u.mi.dy = 0; if (!map_raw_event_coords( event, &input )) return FALSE; - __wine_send_input( 0, &input, NULL ); + __wine_send_input( 0, &input, &rawinput ); return TRUE; } From 188172b93647877e1acf8c0dacb9584825eaa235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 25 Mar 2021 14:26:35 +0100 Subject: [PATCH 0177/2777] user32: Support sending RIM_TYPEMOUSE through __wine_send_input. --- dlls/win32u/message.c | 6 ++++++ server/queue.c | 3 +++ 2 files changed, 9 insertions(+) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 0299285f589..a43be558ef4 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2643,6 +2643,12 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r req->input.hw.rawinput.type = rawinput->header.dwType; switch (rawinput->header.dwType) { + case RIM_TYPEMOUSE: + req->input.hw.rawinput.mouse.x = rawinput->data.mouse.lLastX; + req->input.hw.rawinput.mouse.y = rawinput->data.mouse.lLastY; + req->input.hw.rawinput.mouse.data = rawinput->data.mouse.ulRawButtons; + req->input.hw.lparam = rawinput->data.mouse.usFlags; + break; case RIM_TYPEHID: req->input.hw.rawinput.hid.device = HandleToUlong( rawinput->header.hDevice ); req->input.hw.rawinput.hid.param = rawinput->header.wParam; diff --git a/server/queue.c b/server/queue.c index 7eeaeb0aa82..833a4b31b4f 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2068,6 +2068,9 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ msg_data->size = sizeof(*msg_data) + report_size; msg_data->rawinput = input->hw.rawinput; + if (input->hw.msg == WM_INPUT && input->hw.rawinput.type == RIM_TYPEMOUSE) + msg_data->flags = input->hw.lparam; + enum_processes( queue_rawinput_message, &raw_msg ); return; } From 4a1beb8ecfe8c2c3870bcdd9ba0c251230c2875c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Oct 2021 11:45:47 +0200 Subject: [PATCH 0178/2777] winex11.drv: Listen to RawMotion and RawButton* events in the desktop thread. We still need to send "normal" input from the clipping window thread to trigger low-level hooks callbacks when clipping cursor. This is for instance used in our dinput implementation. --- dlls/winex11.drv/event.c | 10 +++- dlls/winex11.drv/mouse.c | 97 +++++++++++++++++++++++++++++++--- dlls/winex11.drv/x11drv.h | 1 + dlls/winex11.drv/x11drv_main.c | 2 + 4 files changed, 102 insertions(+), 8 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 47af83cbda6..55074f41e2f 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -329,6 +329,10 @@ static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawE */ static enum event_merge_action merge_events( XEvent *prev, XEvent *next ) { +#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + struct x11drv_thread_data *thread_data = x11drv_thread_data(); +#endif + switch (prev->type) { case ConfigureNotify: @@ -360,19 +364,21 @@ static enum event_merge_action merge_events( XEvent *prev, XEvent *next ) case GenericEvent: if (next->xcookie.extension != xinput2_opcode) break; if (next->xcookie.evtype != XI_RawMotion) break; - if (x11drv_thread_data()->warp_serial) break; + if (thread_data->xi2_rawinput_only) break; + if (thread_data->warp_serial) break; return MERGE_KEEP; } break; case GenericEvent: if (prev->xcookie.extension != xinput2_opcode) break; if (prev->xcookie.evtype != XI_RawMotion) break; + if (thread_data->xi2_rawinput_only) break; switch (next->type) { case GenericEvent: if (next->xcookie.extension != xinput2_opcode) break; if (next->xcookie.evtype != XI_RawMotion) break; - if (x11drv_thread_data()->warp_serial) break; + if (thread_data->warp_serial) break; return merge_raw_motion_events( prev->xcookie.data, next->xcookie.data ); #endif } diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index d4f8481e15f..4c58bd83ccf 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -387,6 +387,11 @@ void X11DRV_XInput2_Enable( Display *display, Window window, long event_mask ) mask.deviceid = XIAllMasterDevices; memset( mask_bits, 0, sizeof(mask_bits) ); + if (NtUserGetWindowThread( NtUserGetDesktopWindow(), NULL ) == GetCurrentThreadId()) + data->xi2_rawinput_only = TRUE; + else + data->xi2_rawinput_only = FALSE; + /* FIXME: steam overlay doesn't like if we use XI2 for non-raw events */ if (event_mask & PointerMotionMask) @@ -689,7 +694,6 @@ static void map_event_coords( HWND hwnd, Window window, Window event_root, int x static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPUT *input ) { struct x11drv_win_data *data; - RAWINPUT rawinput; Window win = 0; input->type = INPUT_MOUSE; @@ -707,7 +711,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU sync_window_cursor( window ); last_cursor_change = input->u.mi.time; } - __wine_send_input( hwnd, input, &rawinput ); + __wine_send_input( hwnd, input, NULL ); return; } @@ -748,7 +752,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU SERVER_END_REQ; } - __wine_send_input( hwnd, input, &rawinput ); + __wine_send_input( hwnd, input, NULL ); } #ifdef SONAME_LIBXCURSOR @@ -1731,7 +1735,6 @@ void move_resize_window( HWND hwnd, int dir ) { MSG msg; INPUT input; - RAWINPUT rawinput; int x, y, rootX, rootY; if (!XQueryPointer( display, root_window, &root, &child, &rootX, &rootY, &x, &y, &xstate )) break; @@ -1747,7 +1750,7 @@ void move_resize_window( HWND hwnd, int dir ) input.u.mi.dwFlags = button_up_flags[button - 1] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; input.u.mi.time = NtGetTickCount(); input.u.mi.dwExtraInfo = 0; - __wine_send_input( hwnd, &input, &rawinput ); + __wine_send_input( hwnd, &input, NULL ); } while (NtUserPeekMessage( &msg, 0, 0, 0, PM_REMOVE )) @@ -1958,6 +1961,7 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input ) */ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) { + struct x11drv_thread_data *thread_data = x11drv_thread_data(); XIRawEvent *event = xev->data; RAWINPUT rawinput; INPUT input; @@ -1977,7 +1981,84 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) input.u.mi.dy = 0; if (!map_raw_event_coords( event, &input )) return FALSE; - __wine_send_input( 0, &input, &rawinput ); + if (!thread_data->xi2_rawinput_only) + __wine_send_input( 0, &input, NULL ); + else + { + rawinput.header.dwType = RIM_TYPEMOUSE; + rawinput.header.dwSize = offsetof(RAWINPUT, data) + sizeof(RAWMOUSE); + rawinput.header.hDevice = ULongToHandle(1); /* WINE_MOUSE_HANDLE */ + rawinput.header.wParam = RIM_INPUT; + rawinput.data.mouse.usFlags = input.u.mi.dwFlags; + rawinput.data.mouse.ulRawButtons = 0; + rawinput.data.mouse.u.usButtonData = 0; + rawinput.data.mouse.u.usButtonFlags = 0; + rawinput.data.mouse.lLastX = input.u.mi.dx; + rawinput.data.mouse.lLastY = input.u.mi.dy; + rawinput.data.mouse.ulExtraInformation = 0; + + input.type = INPUT_HARDWARE; + input.u.hi.uMsg = WM_INPUT; + input.u.hi.wParamH = 0; + input.u.hi.wParamL = 0; + if (rawinput.data.mouse.lLastX || rawinput.data.mouse.lLastY) + __wine_send_input( 0, &input, &rawinput ); + } + + return TRUE; +} + +/*********************************************************************** + * X11DRV_RawButtonEvent + */ +static BOOL X11DRV_RawButtonEvent( XGenericEventCookie *cookie ) +{ + struct x11drv_thread_data *thread_data = x11drv_thread_data(); + XIRawEvent *event = cookie->data; + int button = event->detail - 1; + RAWINPUT rawinput; + INPUT input; + + if (!device_mapping || device_mapping->deviceid != event->sourceid) + update_device_mapping( event->display, event->sourceid ); + + if (button >= 0 && device_mapping) + button = device_mapping->buttons[button] - 1; + + if (button >= 0 && pointer_mapping) + button = pointer_mapping->buttons[button] - 1; + + if (button < 0 || button >= NB_BUTTONS) return FALSE; + if (event->deviceid != thread_data->xi2_core_pointer) return FALSE; + + TRACE( "raw button %u (raw: %u) %s\n", button, event->detail, event->evtype == XI_RawButtonRelease ? "up" : "down" ); + + rawinput.header.dwType = RIM_TYPEMOUSE; + rawinput.header.dwSize = offsetof(RAWINPUT, data) + sizeof(RAWMOUSE); + rawinput.header.hDevice = ULongToHandle(1); /* WINE_MOUSE_HANDLE */ + rawinput.header.wParam = RIM_INPUT; + if (event->evtype == XI_RawButtonRelease) + { + rawinput.data.mouse.usFlags = button_up_flags[button]; + rawinput.data.mouse.ulRawButtons = button_up_data[button]; + } + else + { + rawinput.data.mouse.usFlags = button_down_flags[button]; + rawinput.data.mouse.ulRawButtons = button_down_data[button]; + } + rawinput.data.mouse.u.usButtonData = 0; + rawinput.data.mouse.u.usButtonFlags = 0; + rawinput.data.mouse.lLastX = 0; + rawinput.data.mouse.lLastY = 0; + rawinput.data.mouse.ulExtraInformation = 0; + + input.type = INPUT_HARDWARE; + input.u.hi.uMsg = WM_INPUT; + input.u.hi.wParamH = 0; + input.u.hi.wParamL = 0; + if (rawinput.data.mouse.usFlags || rawinput.data.mouse.ulRawButtons) + __wine_send_input( 0, &input, &rawinput ); return TRUE; } @@ -2098,6 +2179,10 @@ BOOL X11DRV_GenericEvent( HWND hwnd, XEvent *xev ) case XI_RawMotion: ret = X11DRV_RawMotion( event ); break; + case XI_RawButtonPress: + case XI_RawButtonRelease: + ret = X11DRV_RawButtonEvent( event ); + break; case XI_Motion: case XI_ButtonPress: case XI_ButtonRelease: diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 9ec3712c6aa..ef636d109d5 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -392,6 +392,7 @@ struct x11drv_thread_data XIValuatorClassInfo x_valuator; XIValuatorClassInfo y_valuator; int xi2_core_pointer; /* XInput2 core pointer id */ + int xi2_rawinput_only; #endif /* HAVE_X11_EXTENSIONS_XINPUT2_H */ }; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 36e0598251a..937c757dae7 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -803,6 +803,8 @@ struct x11drv_thread_data *x11drv_init_thread_data(void) if (use_xim) X11DRV_SetupXIM(); X11DRV_XInput2_Init(); + if (NtUserGetWindowThread( NtUserGetDesktopWindow(), NULL ) == GetCurrentThreadId()) + X11DRV_XInput2_Enable( data->display, None, PointerMotionMask|ButtonPressMask|ButtonReleaseMask ); return data; } From 6afc0837992a82ed4b095332aab0094b6967d0bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 18 Oct 2019 11:39:19 +0200 Subject: [PATCH 0179/2777] winex11.drv: Pass XEvent instead of XClientMessageEvent to handlers. This is to avoid a dubious cast from XClientMessageEvent to XEvent in next patch. --- dlls/winex11.drv/event.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 55074f41e2f..4d99f939c3f 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -638,8 +638,10 @@ static void set_focus( Display *display, HWND hwnd, Time time ) /********************************************************************** * handle_manager_message */ -static void handle_manager_message( HWND hwnd, XClientMessageEvent *event ) +static void handle_manager_message( HWND hwnd, XEvent *xev ) { + XClientMessageEvent *event = &xev->xclient; + if (hwnd != NtUserGetDesktopWindow()) return; if (systray_atom && event->data.l[1] == systray_atom) @@ -657,8 +659,9 @@ static void handle_manager_message( HWND hwnd, XClientMessageEvent *event ) /********************************************************************** * handle_wm_protocols */ -static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event ) +static void handle_wm_protocols( HWND hwnd, XEvent *xev ) { + XClientMessageEvent *event = &xev->xclient; Atom protocol = (Atom)event->data.l[0]; Time event_time = (Time)event->data.l[1]; @@ -1638,8 +1641,10 @@ static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event ) /********************************************************************** * handle_xembed_protocol */ -static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event ) +static void handle_xembed_protocol( HWND hwnd, XEvent *xev ) { + XClientMessageEvent *event = &xev->xclient; + switch (event->data.l[1]) { case XEMBED_EMBEDDED_NOTIFY: @@ -1694,8 +1699,9 @@ static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event ) /********************************************************************** * handle_dnd_protocol */ -static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event ) +static void handle_dnd_protocol( HWND hwnd, XEvent *xev ) { + XClientMessageEvent *event = &xev->xclient; Window root, child; int root_x, root_y, child_x, child_y; unsigned int u; @@ -1717,8 +1723,9 @@ static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event ) * * Handle an XdndEnter event. */ -static void handle_xdnd_enter_event( HWND hWnd, XClientMessageEvent *event ) +static void handle_xdnd_enter_event( HWND hWnd, XEvent *xev ) { + XClientMessageEvent *event = &xev->xclient; struct format_entry *data; unsigned long count = 0; Atom *xdndtypes; @@ -1821,8 +1828,9 @@ static long drop_effect_to_xdnd_action( UINT effect ) } -static void handle_xdnd_position_event( HWND hwnd, XClientMessageEvent *event ) +static void handle_xdnd_position_event( HWND hwnd, XEvent *xev ) { + XClientMessageEvent *event = &xev->xclient; struct dnd_position_event_params params; XClientMessageEvent e; UINT effect; @@ -1854,8 +1862,9 @@ static void handle_xdnd_position_event( HWND hwnd, XClientMessageEvent *event ) } -static void handle_xdnd_drop_event( HWND hwnd, XClientMessageEvent *event ) +static void handle_xdnd_drop_event( HWND hwnd, XEvent *xev ) { + XClientMessageEvent *event = &xev->xclient; XClientMessageEvent e; DWORD effect; @@ -1875,7 +1884,7 @@ static void handle_xdnd_drop_event( HWND hwnd, XClientMessageEvent *event ) } -static void handle_xdnd_leave_event( HWND hwnd, XClientMessageEvent *event ) +static void handle_xdnd_leave_event( HWND hwnd, XEvent *xev ) { x11drv_client_call( client_dnd_leave_event, 0 ); } @@ -1883,8 +1892,8 @@ static void handle_xdnd_leave_event( HWND hwnd, XClientMessageEvent *event ) struct client_message_handler { - int atom; /* protocol atom */ - void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */ + int atom; /* protocol atom */ + void (*handler)(HWND, XEvent *); /* corresponding handler function */ }; static const struct client_message_handler client_messages[] = @@ -1920,7 +1929,7 @@ static BOOL X11DRV_ClientMessage( HWND hwnd, XEvent *xev ) { if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM]) { - client_messages[i].handler( hwnd, event ); + client_messages[i].handler( hwnd, xev ); return TRUE; } } From 0ff06a59a96d89b1dcb203f340a871f1a0885a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 23 Dec 2019 14:38:44 +0100 Subject: [PATCH 0180/2777] winex11.drv: Pass XEvent instead of Display to set_focus. --- dlls/winex11.drv/event.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 4d99f939c3f..75561f50995 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -611,7 +611,7 @@ static void set_input_focus( struct x11drv_win_data *data ) /********************************************************************** * set_focus */ -static void set_focus( Display *display, HWND hwnd, Time time ) +static void set_focus( XEvent *xev, HWND hwnd, Time time ) { HWND focus; Window win; @@ -630,7 +630,7 @@ static void set_focus( Display *display, HWND hwnd, Time time ) if (win) { TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time ); - XSetInputFocus( display, win, RevertToParent, time ); + XSetInputFocus( xev->xany.display, win, RevertToParent, time ); } } @@ -739,7 +739,7 @@ static void handle_wm_protocols( HWND hwnd, XEvent *xev ) MAKELONG( HTMENU, WM_LBUTTONDOWN ) ); if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) { - set_focus( event->display, hwnd, event_time ); + set_focus( xev, hwnd, event_time ); return; } } @@ -748,7 +748,7 @@ static void handle_wm_protocols( HWND hwnd, XEvent *xev ) hwnd = NtUserGetForegroundWindow(); if (!hwnd) hwnd = last_focus; if (!hwnd) hwnd = NtUserGetDesktopWindow(); - set_focus( event->display, hwnd, event_time ); + set_focus( xev, hwnd, event_time ); return; } /* try to find some other window to give the focus to */ @@ -756,7 +756,7 @@ static void handle_wm_protocols( HWND hwnd, XEvent *xev ) if (hwnd) hwnd = NtUserGetAncestor( hwnd, GA_ROOT ); if (!hwnd) hwnd = get_active_window(); if (!hwnd) hwnd = last_focus; - if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time ); + if (hwnd && can_activate_window(hwnd)) set_focus( xev, hwnd, event_time ); } else if (protocol == x11drv_atom(_NET_WM_PING)) { @@ -836,7 +836,7 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (hwnd) hwnd = NtUserGetAncestor( hwnd, GA_ROOT ); if (!hwnd) hwnd = get_active_window(); if (!hwnd) hwnd = x11drv_thread_data()->last_focus; - if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime ); + if (hwnd && can_activate_window(hwnd)) set_focus( xev, hwnd, CurrentTime ); } else NtUserSetForegroundWindow( hwnd ); return TRUE; From 0fc22ab365fd4c5728d9f51d4d844afb5b85aa6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 7 Oct 2019 12:58:23 +0200 Subject: [PATCH 0181/2777] winex11.drv: Merge FocusIn/FocusOut NotifyGrab/NotifyUngrab cases. The return value was different as well, this makes it consistent. The switch is also going to go away. --- dlls/winex11.drv/event.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 75561f50995..29fcbe23469 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -810,7 +810,7 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) case NotifyGrab: /* these are received when moving undecorated managed windows on mutter */ keyboard_grabbed = TRUE; - return FALSE; + break; case NotifyWhileGrabbed: keyboard_grabbed = TRUE; break; @@ -820,9 +820,12 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) case NotifyUngrab: keyboard_grabbed = FALSE; retry_grab_clipping_window(); - return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ + break; } + /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ + if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; + if ((xic = X11DRV_get_ic( hwnd ))) XSetICFocus( xic ); if (use_take_focus) { @@ -913,7 +916,7 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) case NotifyUngrab: /* these are received when moving undecorated managed windows on mutter */ keyboard_grabbed = FALSE; - return FALSE; + break; case NotifyNormal: keyboard_grabbed = FALSE; break; @@ -928,10 +931,12 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) * FocusIn with NotifyUngrab mode. */ retry_grab_clipping_window(); - - return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ + break; } + /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ + if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; + focus_out( event->display, hwnd ); return TRUE; } From 14ad9a3418d8ac76cc956cd6878a4b393dc48937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 19 Sep 2019 15:42:09 +0200 Subject: [PATCH 0182/2777] winex11.drv: Wait for pointer grab on FocusIn/WM_TAKE_FOCUS events. The FocusIn/WM_TAKE_FOCUS events are received as soon as a window is clicked, but when some modifier key is pressed or when the click is on the window frame, the WM may still be controlling the window size or position. It usually grabs the cursor while doing so - and if not then there's apparently nothing we can do. When using undecorated mode we handle this case "correctly" by going through the corresponding Windows non-client message loop until mouse buttons are released, but when using decorated windows the window decoration is empty from the Wine perspective and any window event is considered as happening in the client area. This leads to some issues when the window is moved or resized, with applications applying clipping rectangles immediately and not updating it on subsequent window move/resize messages. Delaying the WM_ACTIVATE until the WM releases its grab and the window move is complete helps solving this situation. This delay is implemented here by resending the FocusIn/WM_TAKE_FOCUS events to the window until the cursor can be grabbed and then processing them normally. winex11.drv: Fix focus delay issues with desktop clipping. --- dlls/winex11.drv/event.c | 43 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 29fcbe23469..b70bb3ea83e 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -322,6 +322,25 @@ static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawE } #endif +static int try_grab_pointer( Display *display ) +{ + if (!grab_pointer) + return 1; + + /* if we are already clipping the cursor in the current thread, we should not + * call XGrabPointer here or it would change the confine-to window. */ + if (clipping_cursor && x11drv_thread_data()->clip_hwnd) + return 1; + + if (XGrabPointer( display, root_window, False, 0, GrabModeAsync, GrabModeAsync, + None, None, CurrentTime ) != GrabSuccess) + return 0; + + XUngrabPointer( display, CurrentTime ); + XFlush( display ); + return 1; +} + /*********************************************************************** * merge_events * @@ -617,8 +636,16 @@ static void set_focus( XEvent *xev, HWND hwnd, Time time ) Window win; GUITHREADINFO threadinfo; - TRACE( "setting foreground window to %p\n", hwnd ); - NtUserSetForegroundWindow( hwnd ); + if (!try_grab_pointer( xev->xany.display )) + { + XSendEvent( xev->xany.display, xev->xany.window, False, 0, xev ); + return; + } + else + { + TRACE( "setting foreground window to %p\n", hwnd ); + NtUserSetForegroundWindow( hwnd ); + } threadinfo.cbSize = sizeof(threadinfo); NtUserGetGUIThreadInfo( 0, &threadinfo ); @@ -823,6 +850,14 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) break; } + if (!try_grab_pointer( event->display )) + { + /* ask the desktop window to release its grab before trying to get ours */ + send_message( NtUserGetDesktopWindow(), WM_X11DRV_RELEASE_CURSOR, 0, 0 ); + XSendEvent( event->display, event->window, False, 0, xev ); + return FALSE; + } + /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; @@ -840,8 +875,10 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (!hwnd) hwnd = get_active_window(); if (!hwnd) hwnd = x11drv_thread_data()->last_focus; if (hwnd && can_activate_window(hwnd)) set_focus( xev, hwnd, CurrentTime ); + return TRUE; } - else NtUserSetForegroundWindow( hwnd ); + + NtUserSetForegroundWindow( hwnd ); return TRUE; } From bf0570916cb297aebe9a1361bf0c63d4f378dca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 9 Dec 2021 11:53:02 +0100 Subject: [PATCH 0183/2777] winex11.drv: Release pointer grab on focus change. When using WM_TAKE_FOCUS, the foreground window will only receive the FocusOut message after we have called XSetInputFocus. As we are waiting for the cursor to be released, we have to tell it to release its grab so we can try to grab it ourselves. --- dlls/winex11.drv/event.c | 2 ++ dlls/winex11.drv/window.c | 2 ++ dlls/winex11.drv/x11drv.h | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index b70bb3ea83e..982b7b59b80 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -638,6 +638,8 @@ static void set_focus( XEvent *xev, HWND hwnd, Time time ) if (!try_grab_pointer( xev->xany.display )) { + /* ask the foreground window to release its grab before trying to get ours */ + send_message( NtUserGetForegroundWindow(), WM_X11DRV_RELEASE_CURSOR, 0, 0 ); XSendEvent( xev->xany.display, xev->xany.window, False, 0, xev ); return; } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 7e1a1c52341..370d0868eec 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -3110,6 +3110,8 @@ LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) return 0; case WM_X11DRV_ADD_TAB: taskbar_add_tab( hwnd ); + case WM_X11DRV_RELEASE_CURSOR: + ungrab_clipping_window(); return 0; default: FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, (long)wp, lp ); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index ef636d109d5..f3f6f8402f3 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -589,7 +589,8 @@ enum x11drv_window_messages WM_X11DRV_CLIP_CURSOR_NOTIFY, WM_X11DRV_CLIP_CURSOR_REQUEST, WM_X11DRV_DELETE_TAB, - WM_X11DRV_ADD_TAB + WM_X11DRV_ADD_TAB, + WM_X11DRV_RELEASE_CURSOR, }; /* _NET_WM_STATE properties that we keep track of */ From 0227566268174b62cd0a6dbe97fdb25b1a398e17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 7 Oct 2019 13:03:43 +0200 Subject: [PATCH 0184/2777] winex11.drv: Release pointer grab on FocusOut events. When a window receives FocusOut event, whether it is because the WM is grabbing the keyboard or because of an actual input focus change, we should release the pointer grab. We will re-apply it on FocusIn event if it is necessary from Wine's perspective. --- dlls/winex11.drv/event.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 982b7b59b80..18ea14c4807 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -973,6 +973,8 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) break; } + if (hwnd == NtUserGetForegroundWindow()) ungrab_clipping_window(); + /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; From 48294dc6b2b35cac26badd08f07306b416e0aba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 1 Oct 2019 11:21:24 +0200 Subject: [PATCH 0185/2777] winex11.drv: Restore pointer grab on FocusIn events. This reverts commit 92177b0b161e91f1d609615d89d8e3199feea33f. We introduced unnecessary complexity by adding the last_clip_* state, we can instead use the ClipCursor state. This restores the ClipCursor on FocusIn events by sending a WM_X11DRV_CLIP_CURSOR message to the foreground window, which will query the current clipping rect from the server and apply it. winex11.drv: Send WM_X11DRV_CLIP_CURSOR_REQUEST with timeout. CW-Bug-Id: #21027 --- dlls/winex11.drv/event.c | 13 ++++++------- dlls/winex11.drv/mouse.c | 24 ------------------------ dlls/winex11.drv/x11drv.h | 1 - 3 files changed, 6 insertions(+), 32 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 18ea14c4807..beead1d33c3 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -848,7 +848,6 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) break; case NotifyUngrab: keyboard_grabbed = FALSE; - retry_grab_clipping_window(); break; } @@ -860,6 +859,12 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) return FALSE; } + /* ask the foreground window to re-apply the current ClipCursor rect */ + if (!send_message_timeout( NtUserGetForegroundWindow(), WM_X11DRV_CLIP_CURSOR_REQUEST, 0, 0, + SMTO_NOTIMEOUTIFNOTHUNG, 500, NULL ) && + RtlGetLastWin32Error() == ERROR_TIMEOUT) + ERR( "WM_X11DRV_CLIP_CURSOR_REQUEST timed out.\n" ); + /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; @@ -964,12 +969,6 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) break; case NotifyGrab: keyboard_grabbed = TRUE; - - /* This will do nothing due to keyboard_grabbed == TRUE, but it - * will save the current clipping rect so we can restore it on - * FocusIn with NotifyUngrab mode. - */ - retry_grab_clipping_window(); break; } diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 4c58bd83ccf..55a12985db5 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -129,9 +129,6 @@ XContext cursor_context = 0; static HWND cursor_window; static HCURSOR last_cursor; static DWORD last_cursor_change; -static RECT last_clip_rect; -static HWND last_clip_foreground_window; -static BOOL last_clip_refused; static RECT clip_rect; static Cursor create_cursor( HANDLE handle ); @@ -450,15 +447,8 @@ static BOOL grab_clipping_window( const RECT *clip ) if (keyboard_grabbed) { WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) ); - last_clip_refused = TRUE; - last_clip_foreground_window = NtUserGetForegroundWindow(); - last_clip_rect = *clip; return FALSE; } - else - { - last_clip_refused = FALSE; - } /* enable XInput2 unless we are already clipping */ if (!data->clip_hwnd) X11DRV_XInput2_Enable( data->display, None, PointerMotionMask ); @@ -529,20 +519,6 @@ void reset_clipping_window(void) NtUserClipCursor( NULL ); /* make sure the clip rectangle is reset too */ } -/*********************************************************************** - * retry_grab_clipping_window - * - * Restore the current clip rectangle or retry the last one if it has - * been refused because of an active keyboard grab. - */ -void retry_grab_clipping_window(void) -{ - if (clipping_cursor) - NtUserClipCursor( &clip_rect ); - else if (last_clip_refused && NtUserGetForegroundWindow() == last_clip_foreground_window) - NtUserClipCursor( &last_clip_rect ); -} - /*********************************************************************** * clip_cursor_notify * diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index f3f6f8402f3..48f9c8e278c 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -687,7 +687,6 @@ extern LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip extern LRESULT clip_cursor_request( HWND hwnd, BOOL fullscreen, BOOL reset ) DECLSPEC_HIDDEN; extern void ungrab_clipping_window(void) DECLSPEC_HIDDEN; extern void reset_clipping_window(void) DECLSPEC_HIDDEN; -extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN; extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN; extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN; extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN; From d3b5338ca388aa26374fed748ef2c493dd173609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Nov 2022 01:45:14 +0100 Subject: [PATCH 0186/2777] Revert "winex11.drv: Only grab or warp the cursor when keyboard isn't grabbed." This reverts commit 54f8077c41f715cfcf9c2bc016d964b720911326. We are now delaying FocusIn events until cursor grab is released, eventually restoring the last ClipCursor, and we also release our grab on FocusOut events. This keyboard grab tracking isn't needed anymore. --- dlls/winex11.drv/event.c | 37 ------------------------------------- dlls/winex11.drv/mouse.c | 12 ------------ dlls/winex11.drv/x11drv.h | 1 - 3 files changed, 50 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index beead1d33c3..ac8b5c7d06f 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -147,9 +147,6 @@ static const char * event_names[MAX_EVENT_HANDLERS] = "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent" }; -/* is someone else grabbing the keyboard, for example the WM, when manipulating the window */ -BOOL keyboard_grabbed = FALSE; - int xinput2_opcode = 0; /* return the name of an X event */ @@ -834,23 +831,6 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (event->detail == NotifyPointer) return FALSE; if (hwnd == NtUserGetDesktopWindow()) return FALSE; - switch (event->mode) - { - case NotifyGrab: - /* these are received when moving undecorated managed windows on mutter */ - keyboard_grabbed = TRUE; - break; - case NotifyWhileGrabbed: - keyboard_grabbed = TRUE; - break; - case NotifyNormal: - keyboard_grabbed = FALSE; - break; - case NotifyUngrab: - keyboard_grabbed = FALSE; - break; - } - if (!try_grab_pointer( event->display )) { /* ask the desktop window to release its grab before trying to get ours */ @@ -955,23 +935,6 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) } if (!hwnd) return FALSE; - switch (event->mode) - { - case NotifyUngrab: - /* these are received when moving undecorated managed windows on mutter */ - keyboard_grabbed = FALSE; - break; - case NotifyNormal: - keyboard_grabbed = FALSE; - break; - case NotifyWhileGrabbed: - keyboard_grabbed = TRUE; - break; - case NotifyGrab: - keyboard_grabbed = TRUE; - break; - } - if (hwnd == NtUserGetForegroundWindow()) ungrab_clipping_window(); /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 55a12985db5..9e963971a20 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -444,12 +444,6 @@ static BOOL grab_clipping_window( const RECT *clip ) NULL, 0, NULL, 0, FALSE ))) return TRUE; - if (keyboard_grabbed) - { - WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) ); - return FALSE; - } - /* enable XInput2 unless we are already clipping */ if (!data->clip_hwnd) X11DRV_XInput2_Enable( data->display, None, PointerMotionMask ); @@ -1544,12 +1538,6 @@ BOOL X11DRV_SetCursorPos( INT x, INT y ) struct x11drv_thread_data *data = x11drv_init_thread_data(); POINT pos = virtual_screen_to_root( x, y ); - if (keyboard_grabbed) - { - WARN( "refusing to warp to %u, %u\n", (int)pos.x, (int)pos.y ); - return FALSE; - } - if (!clipping_cursor && XGrabPointer( data->display, root_window, False, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 48f9c8e278c..3b42010db64 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -430,7 +430,6 @@ extern Colormap default_colormap DECLSPEC_HIDDEN; extern XPixmapFormatValues **pixmap_formats DECLSPEC_HIDDEN; extern Window root_window DECLSPEC_HIDDEN; extern BOOL clipping_cursor DECLSPEC_HIDDEN; -extern BOOL keyboard_grabbed DECLSPEC_HIDDEN; extern unsigned int screen_bpp DECLSPEC_HIDDEN; extern BOOL use_xkb DECLSPEC_HIDDEN; extern BOOL usexrandr DECLSPEC_HIDDEN; From 7dc685f645fff8a6215006b42deb8fa8a1329a6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 17 Dec 2019 16:58:07 +0100 Subject: [PATCH 0187/2777] Revert "winex11.drv: Only call XWarpPointer if we can get exclusive pointer grab." This reverts commit 74efb3e872aebf57a42d62b52e149ae26f320c9a. We are now only activating windows only once the window manager has released its grab, it should be safer to let them move the pointer around and this should not be needed anymore. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47771 --- dlls/winex11.drv/mouse.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 9e963971a20..27398070ba8 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1538,21 +1538,8 @@ BOOL X11DRV_SetCursorPos( INT x, INT y ) struct x11drv_thread_data *data = x11drv_init_thread_data(); POINT pos = virtual_screen_to_root( x, y ); - if (!clipping_cursor && - XGrabPointer( data->display, root_window, False, - PointerMotionMask | ButtonPressMask | ButtonReleaseMask, - GrabModeAsync, GrabModeAsync, None, None, CurrentTime ) != GrabSuccess) - { - WARN( "refusing to warp pointer to %u, %u without exclusive grab\n", (int)pos.x, (int)pos.y ); - return FALSE; - } - XWarpPointer( data->display, root_window, root_window, 0, 0, 0, 0, pos.x, pos.y ); data->warp_serial = NextRequest( data->display ); - - if (!clipping_cursor) - XUngrabPointer( data->display, CurrentTime ); - XNoOp( data->display ); XFlush( data->display ); /* avoids bad mouse lag in games that do their own mouse warping */ TRACE( "warped to %d,%d serial %lu\n", x, y, data->warp_serial ); From 4866e64ec2877b0b91da8f745ed550127f8fb59e Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 15 Mar 2021 12:01:25 -0500 Subject: [PATCH 0188/2777] winex11.drv: Flush X connection after ungrabbing the pointer. CW-Bug-Id: #18169 --- dlls/winex11.drv/mouse.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 27398070ba8..b62fc2911ca 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -497,7 +497,11 @@ void ungrab_clipping_window(void) TRACE( "no longer clipping\n" ); XUnmapWindow( display, clip_window ); - if (clipping_cursor) XUngrabPointer( display, CurrentTime ); + if (clipping_cursor) + { + XUngrabPointer( display, CurrentTime ); + XFlush( display ); + } clipping_cursor = FALSE; send_notify_message( NtUserGetDesktopWindow(), WM_X11DRV_CLIP_CURSOR_NOTIFY, 0, 0 ); } From 7649db953ed0b1ae06659315a987ecb97befe39f Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 7 Dec 2020 09:31:52 +0100 Subject: [PATCH 0189/2777] winex11.drv: Recognize the keyboard in a locale-independent way. Try to recognize the keyboard comparing keysyms instead of converting them to multibyte strings, which makes the process locale-dependent and therefore more fragile. Unfortunately this means that the layout tables might need to be updated. However, this change is known to fix the recognitions of a few keys in the French layout. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=30984 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45605 CW-Bug-Id: #16793 --- dlls/winex11.drv/keyboard.c | 64 ++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 12bb2b863cb..97a85f59938 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1414,6 +1414,35 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) return TRUE; } +/* From the point of view of this function there are two types of + * keys: those for which the mapping to vkey and scancode depends on + * the keyboard layout (i.e., letters, numbers, punctuation) and those + * for which it doesn't (control keys); since this function is used to + * recognize the keyboard layout and map keysyms to vkeys and + * scancodes, we are only concerned about the first type, and map + * everything in the second type to zero. + */ +static char keysym_to_char( KeySym keysym ) +{ + /* Dead keys */ + if (0xfe50 <= keysym && keysym < 0xfed0) + return KEYBOARD_MapDeadKeysym( keysym ); + + /* Control keys (there is nothing allocated below 0xfc00, but I + take some margin in case something is added in the future) */ + if (0xf000 <= keysym && keysym < 0x10000) + return 0; + + /* XFree86 vendor keys */ + if (0x10000000 <= keysym) + return 0; + + /* "Normal" keys: return last octet, because our tables don't have + more than that; it would be better to extend the tables and + compare the whole keysym, but it's a lot of work... */ + return keysym & 0xff; +} + /********************************************************************** * X11DRV_KEYBOARD_DetectLayout * @@ -1444,24 +1473,7 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) /* get data for keycode from X server */ for (i = 0; i < syms; i++) { if (!(keysym = keycode_to_keysym (display, keyc, i))) continue; - /* Allow both one-byte and two-byte national keysyms */ - if ((keysym < 0x8000) && (keysym != ' ')) - { -#ifdef HAVE_XKB - if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL)) -#endif - { - TRACE("XKB could not translate keysym %04lx\n", keysym); - /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent - * with appropriate ShiftMask and Mode_switch, use XLookupString - * to get character in the local encoding. - */ - ckey[keyc][i] = keysym & 0xFF; - } - } - else { - ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym); - } + ckey[keyc][i] = keysym_to_char(keysym); } } @@ -1672,21 +1684,7 @@ void X11DRV_InitKeyboard( Display *display ) int maxlen=0,maxval=-1,ok; for (i=0; i Date: Mon, 7 Dec 2020 09:49:53 +0100 Subject: [PATCH 0190/2777] winex11.drv: Dump keysyms and translations for all keys. Dump all we can see about the user keyboard, so that their +keyboard logs can be used to fix layout tables. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=30984 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45605 CW-Bug-Id: #16793 --- dlls/winex11.drv/keyboard.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 97a85f59938..db001696a14 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1474,6 +1474,19 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) for (i = 0; i < syms; i++) { if (!(keysym = keycode_to_keysym (display, keyc, i))) continue; ckey[keyc][i] = keysym_to_char(keysym); + if (TRACE_ON(keyboard)) + { + char buf[32]; + WCHAR bufW[32]; + int len, lenW; + KeySym orig_keysym = keysym; + len = XkbTranslateKeySym(display, &keysym, 0, buf, sizeof(buf), NULL); + lenW = ntdll_umbstowcs(buf, len, bufW, ARRAY_SIZE(bufW)); + if (lenW < ARRAY_SIZE(bufW)) + bufW[lenW] = 0; + TRACE("keycode %u, index %d, orig_keysym 0x%04lx, keysym 0x%04lx, buf %s, bufW %s\n", + keyc, i, orig_keysym, keysym, debugstr_a(buf), debugstr_w(bufW)); + } } } From bbebcf48864381fba08b8e27257fb84eef9ce44a Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Mon, 15 Mar 2021 11:31:37 -0500 Subject: [PATCH 0191/2777] HACK: winex11.drv: Add WINE_ALLOW_XIM option. --- dlls/winex11.drv/x11drv_main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 937c757dae7..e646a832d6a 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -671,6 +671,13 @@ static NTSTATUS x11drv_init( void *arg ) dlopen( SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL ); #endif + { + const char *e = getenv("WINE_ALLOW_XIM"); + if(e){ + use_xim = IS_OPTION_TRUE(*e); + } + } + setup_options(); /* Open display */ From 5c50ea52fcd9ea6cfcab048fd8e1799b6f9b6cf3 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 20 Jun 2018 15:07:28 -0500 Subject: [PATCH 0192/2777] HACK: user32: Remove hooks that time out. In accordance with Win7+ behaviour. --- dlls/win32u/hook.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/dlls/win32u/hook.c b/dlls/win32u/hook.c index 4b9f22f7afd..0216811c90c 100644 --- a/dlls/win32u/hook.c +++ b/dlls/win32u/hook.c @@ -198,6 +198,7 @@ static UINT get_ll_hook_timeout(void) static LRESULT call_hook( struct win_hook_params *info, const WCHAR *module ) { DWORD_PTR ret = 0; + LRESULT lres = 0; if (info->tid) { @@ -212,20 +213,26 @@ static LRESULT call_hook( struct win_hook_params *info, const WCHAR *module ) switch(info->id) { case WH_KEYBOARD_LL: - send_internal_message_timeout( info->pid, info->tid, WM_WINE_KEYBOARD_LL_HOOK, - info->wparam, (LPARAM)&h_extra, SMTO_ABORTIFHUNG, - get_ll_hook_timeout(), &ret ); + lres = send_internal_message_timeout( info->pid, info->tid, WM_WINE_KEYBOARD_LL_HOOK, + info->wparam, (LPARAM)&h_extra, SMTO_ABORTIFHUNG, + get_ll_hook_timeout(), &ret ); break; case WH_MOUSE_LL: - send_internal_message_timeout( info->pid, info->tid, WM_WINE_MOUSE_LL_HOOK, - info->wparam, (LPARAM)&h_extra, SMTO_ABORTIFHUNG, - get_ll_hook_timeout(), &ret ); + lres = send_internal_message_timeout( info->pid, info->tid, WM_WINE_MOUSE_LL_HOOK, + info->wparam, (LPARAM)&h_extra, SMTO_ABORTIFHUNG, + get_ll_hook_timeout(), &ret ); break; default: ERR("Unknown hook id %d\n", info->id); assert(0); break; } + + if (!lres && RtlGetLastWin32Error() == ERROR_TIMEOUT) + { + TRACE( "Hook %p timed out; removing it.\n", info->handle ); + NtUserUnhookWindowsHookEx( info->handle ); + } } else if (info->proc) { From 3371d5fd3f3d3763a1f8f6f34416ab267261309a Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Mon, 12 Feb 2018 09:15:07 -0600 Subject: [PATCH 0193/2777] winex11.drv: Log more information about X11 errors. --- dlls/winex11.drv/x11drv_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index e646a832d6a..2d2b0a64d86 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -317,6 +317,9 @@ static int error_handler( Display *display, XErrorEvent *error_evt ) error_evt->serial, error_evt->request_code ); assert( 0 ); } + TRACE("passing on error %d req %d:%d res 0x%lx\n", + error_evt->error_code, error_evt->request_code, + error_evt->minor_code, error_evt->resourceid); old_error_handler( display, error_evt ); return 0; } From 30148cb70e27af538f5b3af22140c748ced6b845 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Wed, 27 Jun 2018 10:06:48 -0500 Subject: [PATCH 0194/2777] HACK: winex11.drv: Let the WM focus our windows by default. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should fix game windows not being in focus when first started and when exiting, which can cause surprising keyboard behavior (e.g. accidentally Alt-F4ing Steam itself, which is in the background). This may break modal dialogs in some WMs (fvwm2?) which do not respect our responses to WM_TAKE_FOCUS. For games that show that issue, we can re-enable UseTakeFocus. From Zeb: """ The basic problem, if I understand it correctly, is that Wine uses the "globally active" focus model by default. This means that the window manager won't focus our windows unless we respond in the affirmative to a WM_TAKE_FOCUS event. Since the GUI thread isn't processing messages, this doesn't happen. Luckily, there is a very easy workaround: create the registry key HKCU\Software\Wine\X11 Driver and set the somewhat inaptly named value "UseTakeFocus" to "N" (i.e. No). This causes Wine to use the "locally active" model instead, which means that the window manager will focus our windows when it sees fit—i.e. when the user clicks on them, or when they are created. """ --- dlls/winex11.drv/x11drv_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 2d2b0a64d86..31e3276e548 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -73,7 +73,7 @@ BOOL usexvidmode = TRUE; BOOL usexrandr = TRUE; BOOL usexcomposite = TRUE; BOOL use_xkb = TRUE; -BOOL use_take_focus = TRUE; +BOOL use_take_focus = FALSE; BOOL use_primary_selection = FALSE; BOOL use_system_cursors = TRUE; BOOL show_systray = TRUE; From fd243eb7252c1e6d4d5272ce9384d6a0e2855e59 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Fri, 26 Feb 2021 08:59:56 -0600 Subject: [PATCH 0195/2777] HACK: winex11.drv: Add WM detection code. --- dlls/winex11.drv/window.c | 93 ++++++++++++++++++++++++++++++++++ dlls/winex11.drv/x11drv.h | 6 +++ dlls/winex11.drv/x11drv_main.c | 4 ++ include/wine/gdi_driver.h | 20 ++++++++ 4 files changed, 123 insertions(+) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 370d0868eec..fb488d238fc 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -113,6 +113,97 @@ static const WCHAR clip_window_prop[] = static pthread_mutex_t win_data_mutex = PTHREAD_MUTEX_INITIALIZER; +static int handle_wm_name_badwindow_error( Display *dpy, XErrorEvent *event, void *arg ) +{ + if (event->error_code == BadWindow) + { + WARN( "BadWindow error when reading WM name from window %lx, ignoring.\n", event->resourceid ); + return 1; + } + + return 0; +} + +static int detect_wm(Display *dpy) +{ + Display *display = dpy ? dpy : thread_init_display(); /* DefaultRootWindow is a macro... */ + Window root = DefaultRootWindow(display), *wm_check; + Atom type; + int format, err; + unsigned long count, remaining; + char *wm_name; + + static int cached = -1; + + if(cached < 0){ + + if (XGetWindowProperty( display, root, x11drv_atom(_NET_SUPPORTING_WM_CHECK), 0, + sizeof(*wm_check)/sizeof(CARD32), False, x11drv_atom(WINDOW), + &type, &format, &count, &remaining, (unsigned char **)&wm_check ) == Success){ + if (type == x11drv_atom(WINDOW)){ + /* The window returned by _NET_SUPPORTING_WM_CHECK might be stale, + so we may get errors when asking for its properties */ + X11DRV_expect_error( display, handle_wm_name_badwindow_error, NULL ); + err = XGetWindowProperty( display, *wm_check, x11drv_atom(_NET_WM_NAME), 0, + 256/sizeof(CARD32), False, x11drv_atom(UTF8_STRING), + &type, &format, &count, &remaining, (unsigned char **)&wm_name); + + if (X11DRV_check_error() || err != Success || type != x11drv_atom(UTF8_STRING)){ + X11DRV_expect_error( display, handle_wm_name_badwindow_error, NULL ); + err = XGetWindowProperty( display, *wm_check, x11drv_atom(WM_NAME), 0, + 256/sizeof(CARD32), False, x11drv_atom(STRING), + &type, &format, &count, &remaining, (unsigned char **)&wm_name); + + if (X11DRV_check_error() || err != Success || type != x11drv_atom(STRING)) + wm_name = NULL; + } + + if(wm_name){ + TRACE("Got WM name %s\n", wm_name); + + if((strcmp(wm_name, "GNOME Shell") == 0) || + (strcmp(wm_name, "Mutter") == 0)) + cached = WINE_WM_X11_MUTTER; + else if(strcmp(wm_name, "steamcompmgr") == 0) + cached = WINE_WM_X11_STEAMCOMPMGR; + else if(strcmp(wm_name, "KWin") == 0) + cached = WINE_WM_X11_KDE; + else + cached = WINE_WM_UNKNOWN; + + XFree(wm_name); + }else{ + TRACE("WM did not set _NET_WM_NAME or WM_NAME\n"); + cached = WINE_WM_UNKNOWN; + } + }else + cached = WINE_WM_UNKNOWN; + + XFree(wm_check); + }else + cached = WINE_WM_UNKNOWN; + + __wine_set_window_manager(cached); + } + + return cached; +} + +BOOL wm_is_mutter(Display *display) +{ + return detect_wm(display) == WINE_WM_X11_MUTTER; +} + +BOOL wm_is_kde(Display *display) +{ + return detect_wm(display) == WINE_WM_X11_KDE; +} + +BOOL wm_is_steamcompmgr(Display *display) +{ + return detect_wm(display) == WINE_WM_X11_STEAMCOMPMGR; +} + /*********************************************************************** * http://standards.freedesktop.org/startup-notification-spec */ @@ -1883,6 +1974,8 @@ BOOL X11DRV_CreateDesktopWindow( HWND hwnd ) { unsigned int width, height; + detect_wm( gdi_display ); + /* retrieve the real size of the desktop */ SERVER_START_REQ( get_window_rectangles ) { diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 3b42010db64..d9e9e42b68f 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -469,6 +469,7 @@ enum x11drv_atoms XATOM_TEXT, XATOM_TIMESTAMP, XATOM_UTF8_STRING, + XATOM_STRING, XATOM_RAW_ASCENT, XATOM_RAW_DESCENT, XATOM_RAW_CAP_HEIGHT, @@ -476,6 +477,7 @@ enum x11drv_atoms XATOM_Rel_Y, XATOM_WM_PROTOCOLS, XATOM_WM_DELETE_WINDOW, + XATOM_WM_NAME, XATOM_WM_STATE, XATOM_WM_TAKE_FOCUS, XATOM_DndProtocol, @@ -486,6 +488,7 @@ enum x11drv_atoms XATOM__NET_STARTUP_INFO_BEGIN, XATOM__NET_STARTUP_INFO, XATOM__NET_SUPPORTED, + XATOM__NET_SUPPORTING_WM_CHECK, XATOM__NET_SYSTEM_TRAY_OPCODE, XATOM__NET_SYSTEM_TRAY_S0, XATOM__NET_SYSTEM_TRAY_VISUAL, @@ -537,6 +540,7 @@ enum x11drv_atoms XATOM_WCF_SYLK, XATOM_WCF_TIFF, XATOM_WCF_WAVE, + XATOM_WINDOW, XATOM_image_bmp, XATOM_image_gif, XATOM_image_jpeg, @@ -665,6 +669,8 @@ extern BOOL update_clipboard( HWND hwnd ) DECLSPEC_HIDDEN; extern void init_win_context(void) DECLSPEC_HIDDEN; extern void *file_list_to_drop_files( const void *data, size_t size, size_t *ret_size ) DECLSPEC_HIDDEN; extern void *uri_list_to_drop_files( const void *data, size_t size, size_t *ret_size ) DECLSPEC_HIDDEN; +extern BOOL wm_is_mutter(Display *) DECLSPEC_HIDDEN; +extern BOOL wm_is_steamcompmgr(Display *) DECLSPEC_HIDDEN; static inline void mirror_rect( const RECT *window_rect, RECT *rect ) { diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 31e3276e548..dff5d329571 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -143,6 +143,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = "TEXT", "TIMESTAMP", "UTF8_STRING", + "STRING", "RAW_ASCENT", "RAW_DESCENT", "RAW_CAP_HEIGHT", @@ -150,6 +151,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = "Rel Y", "WM_PROTOCOLS", "WM_DELETE_WINDOW", + "WM_NAME", "WM_STATE", "WM_TAKE_FOCUS", "DndProtocol", @@ -160,6 +162,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = "_NET_STARTUP_INFO_BEGIN", "_NET_STARTUP_INFO", "_NET_SUPPORTED", + "_NET_SUPPORTING_WM_CHECK", "_NET_SYSTEM_TRAY_OPCODE", "_NET_SYSTEM_TRAY_S0", "_NET_SYSTEM_TRAY_VISUAL", @@ -211,6 +214,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = "WCF_SYLK", "WCF_TIFF", "WCF_WAVE", + "WINDOW", "image/bmp", "image/gif", "image/jpeg", diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 3db3d0d6af3..1b1ebf85f1a 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -341,4 +341,24 @@ extern void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT #endif /* WINE_UNIX_LIB */ +/* HACK: We use some WM specific hacks in user32 and we need the user + * driver to export that information. */ + +#define WINE_WM_UNKNOWN 0 +#define WINE_WM_X11_MUTTER 1 +#define WINE_WM_X11_STEAMCOMPMGR 2 +#define WINE_WM_X11_KDE 3 + +static inline LONG_PTR __wine_get_window_manager(void) +{ + static const WCHAR __wine_window_managerW[] = {'_','_','w','i','n','e','_','w','i','n','d','o','w','_','m','a','n','a','g','e','r',0}; + return (LONG_PTR)NtUserGetProp(NtUserGetDesktopWindow(), __wine_window_managerW); +} + +static inline void __wine_set_window_manager(LONG_PTR window_manager) +{ + static const WCHAR __wine_window_managerW[] = {'_','_','w','i','n','e','_','w','i','n','d','o','w','_','m','a','n','a','g','e','r',0}; + NtUserSetProp(NtUserGetDesktopWindow(), __wine_window_managerW, (HANDLE)window_manager); +} + #endif /* __WINE_WINE_GDI_DRIVER_H */ From f5d1bea3dec1e3d77cb0fc4be28d6523627d3a27 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Thu, 30 Jan 2020 14:44:00 -0600 Subject: [PATCH 0196/2777] HACK: gamescope: user32: On steamcompmgr, don't limit window size to screen size HACK: user32: Don't resize new windows to fit the display. --- dlls/win32u/defwnd.c | 12 ++++++++++-- dlls/win32u/window.c | 14 ++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c index e58d4e5a793..f22e1d7ad15 100644 --- a/dlls/win32u/defwnd.c +++ b/dlls/win32u/defwnd.c @@ -480,8 +480,16 @@ static LONG handle_window_pos_changing( HWND hwnd, WINDOWPOS *winpos ) if ((style & WS_THICKFRAME) || ((style & (WS_POPUP | WS_CHILD)) == 0)) { MINMAXINFO info = get_min_max_info( hwnd ); - winpos->cx = min( winpos->cx, info.ptMaxTrackSize.x ); - winpos->cy = min( winpos->cy, info.ptMaxTrackSize.y ); + + /* HACK: This code changes the window's size to fit the display. However, + * some games (Bayonetta, Dragon's Dogma) will then have the incorrect + * render size. So just let windows be too big to fit the display. */ + if (__wine_get_window_manager() != WINE_WM_X11_STEAMCOMPMGR) + { + winpos->cx = min( winpos->cx, info.ptMaxTrackSize.x ); + winpos->cy = min( winpos->cy, info.ptMaxTrackSize.y ); + } + if (!(style & WS_MINIMIZE)) { winpos->cx = max( winpos->cx, info.ptMinTrackSize.x ); diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index a3ff0647dcd..b8aacbf9cbe 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -5220,8 +5220,18 @@ HWND WINAPI NtUserCreateWindowEx( DWORD ex_style, UNICODE_STRING *class_name, if ((cs.style & WS_THICKFRAME) || !(cs.style & (WS_POPUP | WS_CHILD))) { MINMAXINFO info = get_min_max_info( hwnd ); - cx = max( min( cx, info.ptMaxTrackSize.x ), info.ptMinTrackSize.x ); - cy = max( min( cy, info.ptMaxTrackSize.y ), info.ptMinTrackSize.y ); + + /* HACK: This code changes the window's size to fit the display. However, + * some games (Bayonetta, Dragon's Dogma) will then have the incorrect + * render size. So just let windows be too big to fit the display. */ + if (__wine_get_window_manager() != WINE_WM_X11_STEAMCOMPMGR) + { + cx = min( cx, info.ptMaxTrackSize.x ); + cy = min( cy, info.ptMaxTrackSize.y ); + } + + cx = max( cx, info.ptMinTrackSize.x ); + cy = max( cy, info.ptMinTrackSize.y ); } if (cx < 0) cx = 0; From 54cc024eacfd138509031a17b74d6be47fed4562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 16 Mar 2020 19:52:52 +0100 Subject: [PATCH 0197/2777] HACK: gamescope: user32: Pretend that windows are undecorated with gamescope. The original commit made all window have their client rect always match their window rects. This was to make sure games always use the full available window size, even when windowed, and end up with an optimal rendering area. Some games, such as Bayonetta or Dragon's Dogma: Dark Arisen, ask for an optimal window size, but, when in windowed mode, the client rect is then adjusted to add a title bar and borders. On Windows, the back buffer is always the requested size, but the rendering is then scaled to match the client rect. With Proton and gamescope, we want to avoid this suboptimal scaling, and make sure both front and back buffer are optimally sized, including when in windowed mode. Then, we still need to keep adjustments on WS_POPUP / WS_EX_TOOLWINDOW windows: This styles usually translates into a single pixel border, and is used for splash screens. Several of them do not expect their client rect to be sized as the window rect and it causes a visible 1px white border on the bottom and the right of the window. WS_EX_TOOLWINDOW should be safe enough, as it means the window is not supposed to be displayed in the taskbar or in the alt-tab menu, which is unlikely for an actual game window. WS_POPUP otoh means that only a 1px border is used, which should not make much of a difference with an undecorated window (although it could cause suboptimal client rect sizes, which we wanted to solve in the first place). CW-Bug-Id: #17639 CW-Bug-Id: #20038 --- dlls/user32/nonclient.c | 4 ++++ dlls/win32u/defwnd.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/dlls/user32/nonclient.c b/dlls/user32/nonclient.c index 00c7368c516..0fd1661fe0b 100644 --- a/dlls/user32/nonclient.c +++ b/dlls/user32/nonclient.c @@ -21,6 +21,7 @@ #include "user_private.h" #include "controls.h" #include "wine/debug.h" +#include "wine/gdi_driver.h" WINE_DEFAULT_DEBUG_CHANNEL(nonclient); @@ -31,6 +32,9 @@ static void adjust_window_rect( RECT *rect, DWORD style, BOOL menu, DWORD exStyl { int adjust = 0; + if (__wine_get_window_manager() == WINE_WM_X11_STEAMCOMPMGR && !((style & WS_POPUP) && (exStyle & WS_EX_TOOLWINDOW))) + return; + if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) adjust = 1; /* for the outer frame always present */ else if ((exStyle & WS_EX_DLGMODALFRAME) || (style & (WS_THICKFRAME|WS_DLGFRAME))) diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c index f22e1d7ad15..85cdc61be1c 100644 --- a/dlls/win32u/defwnd.c +++ b/dlls/win32u/defwnd.c @@ -1852,6 +1852,9 @@ static void handle_nc_calc_size( HWND hwnd, WPARAM wparam, RECT *win_rect ) if (!win_rect) return; + if (__wine_get_window_manager() == WINE_WM_X11_STEAMCOMPMGR && !((style & WS_POPUP) && (ex_style & WS_EX_TOOLWINDOW))) + return; + if (!(style & WS_MINIMIZE)) { AdjustWindowRectEx( &rect, style, FALSE, ex_style & ~WS_EX_CLIENTEDGE ); From 9ae9f595155d284a1b5bafb8fdb520efb0dfa593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 May 2021 17:41:43 +0200 Subject: [PATCH 0198/2777] HACK: gamescope: winex11.drv: Disable gamescope hacks for Street Fighter V. CW-Bug-Id: #18903 --- dlls/winex11.drv/window.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index fb488d238fc..3c54df571a7 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -132,6 +132,7 @@ static int detect_wm(Display *dpy) int format, err; unsigned long count, remaining; char *wm_name; + char const *sgi = getenv("SteamGameId"); static int cached = -1; @@ -183,6 +184,11 @@ static int detect_wm(Display *dpy) }else cached = WINE_WM_UNKNOWN; + /* Street Fighter V expects a certain sequence of window resizes + or gets stuck on startup. The AdjustWindowRect / WM_NCCALCSIZE + hacks confuse it completely, so let's disable them */ + if (sgi && !strcmp(sgi, "310950")) cached = WINE_WM_UNKNOWN; + __wine_set_window_manager(cached); } From 9f15bed79804ece6e1904e0685c00645a3aa780f Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 18 Sep 2018 14:48:58 -0500 Subject: [PATCH 0199/2777] winex11.drv: Allow the application to change window size and states during PropertyNotify. On focus loss, fullscreened DDLC changes to a 1x1 pixel window and minimizes. On restore, it un-minimizes and changes back to fullscreen size. However, this restoring happens during the PropertyNotify handler, which means we didn't update size or the NET_WM_STATEs. --- dlls/winex11.drv/window.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 3c54df571a7..d34f9116855 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2809,7 +2809,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, } /* don't change position if we are about to minimize or maximize a managed window */ - if (!event_type && + if ((!event_type || event_type == PropertyNotify) && !(data->managed && (swp_flags & SWP_STATECHANGED) && (new_style & (WS_MINIMIZE|WS_MAXIMIZE)))) sync_window_position( data, swp_flags, &old_window_rect, &old_whole_rect, &old_client_rect ); @@ -2843,7 +2843,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, else { if (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)) set_wm_hints( data ); - if (!event_type) update_net_wm_states( data ); + if (!event_type || event_type == PropertyNotify) update_net_wm_states( data ); } } From e56ad03113d0a67024b6e207af27cc434dc85b1f Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Wed, 17 Oct 2018 19:55:27 +0300 Subject: [PATCH 0200/2777] winex11.drv: Ignore clip_reset when trying to clip the mouse after the desktop has been resized. This fixes the mouse clipping when the desktop is resized multiple times in a row. --- dlls/winex11.drv/mouse.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index b62fc2911ca..2aeb1316426 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -579,9 +579,10 @@ BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) release_win_data( data ); if (!fullscreen) return FALSE; if (!(thread_data = x11drv_thread_data())) return FALSE; - if (NtGetTickCount() - thread_data->clip_reset < 1000) return FALSE; - if (!reset && clipping_cursor && thread_data->clip_hwnd) return FALSE; /* already clipping */ - + if (!reset) { + if (NtGetTickCount() - thread_data->clip_reset < 1000) return FALSE; + if (!reset && clipping_cursor && thread_data->clip_hwnd) return FALSE; /* already clipping */ + } monitor = NtUserMonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST ); if (!monitor) return FALSE; monitor_info.cbSize = sizeof(monitor_info); From dba0a0db9bb647ab8d0d5b894d9e8cc00ea181b5 Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Sat, 20 Oct 2018 18:07:12 +0300 Subject: [PATCH 0201/2777] winex11.drv: Enable fullscreen clipping even if not already clipping. --- dlls/winex11.drv/mouse.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 2aeb1316426..dfb16694a1f 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1601,12 +1601,12 @@ BOOL X11DRV_ClipCursor( LPCRECT clip ) { if (grab_clipping_window( clip )) return TRUE; } - else /* if currently clipping, check if we should switch to fullscreen clipping */ + else /* check if we should switch to fullscreen clipping */ { struct x11drv_thread_data *data = x11drv_thread_data(); - if (data && data->clip_hwnd) + if (data) { - if (EqualRect( clip, &clip_rect ) || clip_fullscreen_window( foreground, TRUE )) + if ((data->clip_hwnd && EqualRect( clip, &clip_rect ) && !EqualRect(&clip_rect, &virtual_rect)) || clip_fullscreen_window( foreground, TRUE )) return TRUE; } } From 839efb2081fffccc2fa64f4baa385e4841007068 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Fri, 11 Jan 2019 11:31:13 -0600 Subject: [PATCH 0202/2777] winex11.drv: Don't show border if WS_CAPTION is unset. Into the Breach wants a borderless window with WS_THICKFRAME. If we leave the BORDER and RESIZEH styles on, then we get a window with a border and a caption on Linux. --- dlls/winex11.drv/window.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index d34f9116855..f86a0a63e56 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -416,7 +416,10 @@ static unsigned long get_mwm_decorations( struct x11drv_win_data *data, if (style & WS_MAXIMIZEBOX) ret |= MWM_DECOR_MAXIMIZE; } if (ex_style & WS_EX_DLGMODALFRAME) ret |= MWM_DECOR_BORDER; - else if (style & WS_THICKFRAME) ret |= MWM_DECOR_BORDER | MWM_DECOR_RESIZEH; + else if (style & WS_THICKFRAME){ + if((style & WS_CAPTION) == WS_CAPTION) + ret |= MWM_DECOR_BORDER | MWM_DECOR_RESIZEH; + } else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) ret |= MWM_DECOR_BORDER; return ret; } From 2b7fd38390fbc54de1a1a88db082bd33339fdd1a Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Fri, 11 Jan 2019 11:34:03 -0600 Subject: [PATCH 0203/2777] winex11.drv: Ignore ConfigureNotify messages if there is a FULLSCREEN WM state pending. Into the Breach goes fullscreen by first maximizing, then setting the window to fullscreen in a separate call. Mutter processes the maximize request _after_ Wine has sent the fullscreen request. As a result, we get a ConfigureNotify for the size of the workspace when we expect the window to be fullscreened. We then notify ITB that it is no longer fullscreen, which begins the process over again, causing an infinite loop. This fixes that by setting a flag if we have a fullscreen request pending and ignoring ConfigureNotify requests if it is set. We unset it when we receive a _NET_WM_STATE PropertyNotify event that contains the FULLSCREEN flag. --- dlls/winex11.drv/event.c | 35 +++++++++++++++++++++++++++++++++++ dlls/winex11.drv/window.c | 9 +++++++++ dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 45 insertions(+) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index ac8b5c7d06f..5484d184d4f 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1146,6 +1146,12 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) event->serial, data->configure_serial ); goto done; } + if (data->pending_fullscreen) + { + TRACE( "win %p/%lx event %d,%d,%dx%d pending_fullscreen is pending, so ignoring\n", hwnd, + data->whole_window, event->x, event->y, event->width, event->height ); + goto done; + } /* Get geometry */ @@ -1380,15 +1386,44 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat } +static void handle__net_wm_state_notify( HWND hwnd, XPropertyEvent *event ) +{ + struct x11drv_win_data *data = get_win_data( hwnd ); + + if (data->pending_fullscreen) + { + read_net_wm_states( event->display, data ); + if (data->net_wm_state & (1 << NET_WM_STATE_FULLSCREEN)) + { + data->pending_fullscreen = FALSE; + TRACE( "PropertyNotify _NET_WM_STATE, now %#x, pending_fullscreen no longer pending.\n", (UINT)data->net_wm_state ); + } + else TRACE( "PropertyNotify _NET_WM_STATE, now %#x, pending_fullscreen still pending.\n", (UINT)data->net_wm_state ); + } + + release_win_data( data ); +} + + /*********************************************************************** * X11DRV_PropertyNotify */ static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *xev ) { XPropertyEvent *event = &xev->xproperty; + char *name; if (!hwnd) return FALSE; + + name = XGetAtomName( event->display, event->atom ); + if (name) + { + TRACE( "win %p PropertyNotify atom: %s, state: 0x%x\n", hwnd, name, event->state ); + XFree( name ); + } + if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event, TRUE ); + else if (event->atom == x11drv_atom( _NET_WM_STATE )) handle__net_wm_state_notify( hwnd, event ); return TRUE; } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index f86a0a63e56..84f7ee2a4df 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1198,6 +1198,12 @@ void update_net_wm_states( struct x11drv_win_data *data ) i, data->hwnd, data->whole_window, (new_state & (1 << i)) != 0, (data->net_wm_state & (1 << i)) != 0 ); + if (i == NET_WM_STATE_FULLSCREEN) + { + data->pending_fullscreen = (new_state & (1 << i)) != 0; + TRACE( "set pending_fullscreen to: %u\n", data->pending_fullscreen ); + } + xev.xclient.data.l[0] = (new_state & (1 << i)) ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; xev.xclient.data.l[1] = X11DRV_Atoms[net_wm_state_atoms[i] - FIRST_XATOM]; xev.xclient.data.l[2] = ((net_wm_state_atoms[i] == XATOM__NET_WM_STATE_MAXIMIZED_VERT) ? @@ -1327,6 +1333,7 @@ static void unmap_window( HWND hwnd ) data->mapped = FALSE; data->net_wm_state = 0; + data->pending_fullscreen = FALSE; } release_win_data( data ); } @@ -1343,6 +1350,7 @@ void make_window_embedded( struct x11drv_win_data *data ) if (!data->managed) XUnmapWindow( data->display, data->whole_window ); else XWithdrawWindow( data->display, data->whole_window, data->vis.screen ); data->net_wm_state = 0; + data->pending_fullscreen = FALSE; } data->embedded = TRUE; data->managed = TRUE; @@ -1827,6 +1835,7 @@ static void destroy_whole_window( struct x11drv_win_data *data, BOOL already_des data->whole_colormap = 0; data->wm_state = WithdrawnState; data->net_wm_state = 0; + data->pending_fullscreen = FALSE; data->mapped = FALSE; if (data->xic) { diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index d9e9e42b68f..7f13b5c186d 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -622,6 +622,7 @@ struct x11drv_win_data RECT whole_rect; /* X window rectangle for the whole window relative to win32 parent window client area */ RECT client_rect; /* client area relative to win32 parent window client area */ XIC xic; /* X input context */ + BOOL pending_fullscreen : 1; /* HACK: pending change to fullscreen state */ BOOL managed : 1; /* is window managed? */ BOOL mapped : 1; /* is window mapped? (in either normal or iconic state) */ BOOL iconic : 1; /* is window in iconic state? */ From 5d75cc698669673ab44e65a3181f93d6a99512af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Jan 2020 21:05:05 +0100 Subject: [PATCH 0204/2777] winex11.drv: Ignore ClipCursor if desktop window is foreground. --- dlls/winex11.drv/mouse.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index dfb16694a1f..f580aa4e62c 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1586,6 +1586,13 @@ BOOL X11DRV_ClipCursor( LPCRECT clip ) HWND foreground = NtUserGetForegroundWindow(); DWORD tid, pid; + if (foreground == NtUserGetDesktopWindow()) + { + WARN( "desktop is foreground, ignoring ClipCursor\n" ); + ungrab_clipping_window(); + return TRUE; + } + /* forward request to the foreground window if it's in a different thread */ tid = NtUserGetWindowThread( foreground, &pid ); if (tid && tid != GetCurrentThreadId() && pid == GetCurrentProcessId()) From a05a8dd5d9f4497d2eaf4c896a17f722fd2e3831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 26 Jun 2019 18:42:37 +0200 Subject: [PATCH 0205/2777] HACK: mutter: winex11.drv: Workaround mutter issue #649. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When decorations are modified too quickly, mutter loses tracks of the reparenting requests and does not gives focus back to the window. Signed-off-by: Rémi Bernon --- dlls/winex11.drv/window.c | 44 ++++++++++++++++++++++++++++++++++++++- dlls/winex11.drv/x11drv.h | 4 ++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 84f7ee2a4df..cb8e16159c7 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -53,7 +53,6 @@ #include "wine/debug.h" #include "wine/server.h" -#include "mwm.h" WINE_DEFAULT_DEBUG_CHANNEL(x11drv); WINE_DECLARE_DEBUG_CHANNEL(systray); @@ -838,13 +837,22 @@ static void set_size_hints( struct x11drv_win_data *data, DWORD style ) XFree( size_hints ); } +static Bool is_unmap_notify( Display *display, XEvent *event, XPointer arg ) +{ + struct x11drv_win_data *data = (struct x11drv_win_data *)arg; + return event->xany.serial >= data->unmapnotify_serial && + event->xany.window == data->whole_window && + event->type == UnmapNotify; +} /*********************************************************************** * set_mwm_hints */ static void set_mwm_hints( struct x11drv_win_data *data, UINT style, UINT ex_style ) { + GUITHREADINFO info = {.cbSize = sizeof(GUITHREADINFO)}; MwmHints mwm_hints; + int enable_mutter_workaround, mapped; if (data->hwnd == NtUserGetDesktopWindow()) { @@ -872,12 +880,46 @@ static void set_mwm_hints( struct x11drv_win_data *data, UINT style, UINT ex_sty TRACE( "%p setting mwm hints to %lx,%lx (style %x exstyle %x)\n", data->hwnd, mwm_hints.decorations, mwm_hints.functions, style, ex_style ); + enable_mutter_workaround = wm_is_mutter(data->display) && NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) && + info.hwndFocus == data->hwnd && !!data->prev_hints.decorations != !!mwm_hints.decorations && + root_window == DefaultRootWindow(data->display); + + /* workaround for mutter gitlab bug #649, we cannot trust the + * data->mapped flag as mapping is asynchronous. + */ + if (enable_mutter_workaround) + { + XWindowAttributes attr; + + mapped = data->mapped; + if (XGetWindowAttributes( data->display, data->whole_window, &attr )) + mapped = (attr.map_state != IsUnmapped); + } + mwm_hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; mwm_hints.input_mode = 0; mwm_hints.status = 0; + data->unmapnotify_serial = NextRequest( data->display ); XChangeProperty( data->display, data->whole_window, x11drv_atom(_MOTIF_WM_HINTS), x11drv_atom(_MOTIF_WM_HINTS), 32, PropModeReplace, (unsigned char*)&mwm_hints, sizeof(mwm_hints)/sizeof(long) ); + + if (enable_mutter_workaround) + { + XEvent event; + + /* workaround for mutter gitlab bug #649, wait for the map notify + * event each time the decorations are modified before modifying + * them again. + */ + if (mapped) + { + TRACE("workaround mutter bug #649, waiting for UnmapNotify\n"); + XPeekIfEvent( data->display, &event, is_unmap_notify, (XPointer)data ); + } + } + + data->prev_hints = mwm_hints; } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 7f13b5c186d..11b6d95f0df 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -68,6 +68,8 @@ typedef int Status; #include "wine/list.h" #include "wine/debug.h" +#include "mwm.h" + #define MAX_DASHLEN 16 #define WINE_XDND_VERSION 5 @@ -635,12 +637,14 @@ struct x11drv_win_data int wm_state; /* current value of the WM_STATE property */ DWORD net_wm_state; /* bit mask of active x11drv_net_wm_state values */ Window embedder; /* window id of embedder */ + unsigned long unmapnotify_serial; /* serial number of last UnmapNotify event */ unsigned long configure_serial; /* serial number of last configure request */ struct window_surface *surface; Pixmap icon_pixmap; Pixmap icon_mask; unsigned long *icon_bits; unsigned int icon_size; + MwmHints prev_hints; }; extern struct x11drv_win_data *get_win_data( HWND hwnd ) DECLSPEC_HIDDEN; From 0063bac7b18e10547de2ca1125f62ebbb98dd16b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 9 Dec 2019 20:28:20 +0100 Subject: [PATCH 0206/2777] HACK: mutter: winex11.drv: Add a bit of delay before restoring mouse grabs on FocusIn. --- dlls/winex11.drv/event.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 5484d184d4f..8615ad6abeb 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -831,6 +831,17 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (event->detail == NotifyPointer) return FALSE; if (hwnd == NtUserGetDesktopWindow()) return FALSE; + /* Focus was just restored but it can be right after super was + * pressed and gnome-shell needs a bit of time to respond and + * toggle the activity view. If we grab the cursor right away + * it will cancel it and super key will do nothing. + */ + if (event->mode == NotifyUngrab && wm_is_mutter(event->display)) + { + LARGE_INTEGER timeout = {.QuadPart = 100 * -10000}; + NtDelayExecution( FALSE, &timeout ); + } + if (!try_grab_pointer( event->display )) { /* ask the desktop window to release its grab before trying to get ours */ From 4bb6fc5eb97e69bd8dec1d1b3a2f847c8cd2c742 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 21 Aug 2018 14:47:33 -0500 Subject: [PATCH 0207/2777] HACK: mutter: winex11.drv: Workaround mutter issue #273. This would cause fullscreen windows to lose keyboard focus. --- dlls/winex11.drv/event.c | 21 +++++++++++++++++++++ dlls/winex11.drv/window.c | 10 ++++++++++ dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 32 insertions(+) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 8615ad6abeb..b4d6bf6eb3e 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -889,9 +889,30 @@ static void focus_out( Display *display , HWND hwnd ) Window focus_win; int revert; XIC xic; + struct x11drv_win_data *data; if (ximInComposeMode) return; + data = get_win_data(hwnd); + if(data){ + LARGE_INTEGER frequency, counter; + ULONGLONG now; + NtQueryPerformanceCounter( &counter, &frequency ); + now = 1000 * counter.QuadPart / frequency.QuadPart; + if(data->take_focus_back > 0 && + now >= data->take_focus_back && + now - data->take_focus_back < 1000){ + data->take_focus_back = 0; + TRACE("workaround mutter bug, taking focus back\n"); + XSetInputFocus( data->display, data->whole_window, RevertToParent, CurrentTime); + release_win_data(data); + /* don't inform win32 client */ + return; + } + data->take_focus_back = 0; + release_win_data(data); + } + x11drv_thread_data()->last_focus = hwnd; if ((xic = X11DRV_get_ic( hwnd ))) XUnsetICFocus( xic ); diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index cb8e16159c7..1996de28c76 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -919,6 +919,16 @@ static void set_mwm_hints( struct x11drv_win_data *data, UINT style, UINT ex_sty } } + if (wm_is_mutter(data->display) && NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) && + info.hwndFocus == data->hwnd && !!data->prev_hints.decorations != !!mwm_hints.decorations) + { + LARGE_INTEGER frequency, counter; + /* workaround for mutter gitlab bug #273 */ + TRACE("workaround mutter bug, setting take_focus_back\n"); + NtQueryPerformanceCounter( &counter, &frequency ); + data->take_focus_back = 1000 * counter.QuadPart / frequency.QuadPart; + } + data->prev_hints = mwm_hints; } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 11b6d95f0df..696bf43faee 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -634,6 +634,7 @@ struct x11drv_win_data BOOL use_alpha : 1; /* does window use an alpha channel? */ BOOL skip_taskbar : 1; /* does window should be deleted from taskbar */ BOOL add_taskbar : 1; /* does window should be added to taskbar regardless of style */ + ULONGLONG take_focus_back; int wm_state; /* current value of the WM_STATE property */ DWORD net_wm_state; /* bit mask of active x11drv_net_wm_state values */ Window embedder; /* window id of embedder */ From d13563ace98ca92542f3b26a0d59e115096f7072 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 25 Sep 2020 12:58:52 +0300 Subject: [PATCH 0208/2777] HACK: mutter: winex11.drv: Avoid setting empty shape for window on mutter. --- dlls/winex11.drv/bitblt.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c index 10388a1cc8f..565454ac545 100644 --- a/dlls/winex11.drv/bitblt.c +++ b/dlls/winex11.drv/bitblt.c @@ -1748,8 +1748,21 @@ static void update_surface_region( struct x11drv_window_surface *surface ) if ((data = X11DRV_GetRegionData( rgn, 0 ))) { - XShapeCombineRectangles( gdi_display, surface->window, ShapeBounding, 0, 0, - (XRectangle *)data->Buffer, data->rdh.nCount, ShapeSet, YXBanded ); + if (!data->rdh.nCount && wm_is_mutter(gdi_display)) + { + XRectangle xrect; + + xrect.x = xrect.y = -1; + xrect.width = 1; + xrect.height = 1; + XShapeCombineRectangles( gdi_display, surface->window, ShapeBounding, 0, 0, + &xrect, 1, ShapeSet, YXBanded ); + } + else + { + XShapeCombineRectangles( gdi_display, surface->window, ShapeBounding, 0, 0, + (XRectangle *)data->Buffer, data->rdh.nCount, ShapeSet, YXBanded ); + } free( data ); } From 26f41550b292ce1784701c08711dbcb488f20482 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Tue, 8 Jun 2021 16:01:54 +0300 Subject: [PATCH 0209/2777] winex11.drv: Send missed KEYUP events on KeymapNotify. Full focus lost / focus gained events on the Windows side are not feasible for X11's FocusIn/FocusOut events generated by keyboard grabs (see XGrabKeyboard()) that are used for example for Atl+Tab handling. Using them would degrade user's experience, especially with our full screen hack, by causing the window to minimize or flash multiple times depending on a game/window manager combo. Because of that the programs may miss on some KEYUP events that happen during the grab, and since there are no focus changes on the Windows side the state doesn't get resynced. This change attempts to improve user experience by syncing any missed key release events that happened while the window haven't had focus on the X11 side. There's no syncing of key presses as those are more problematic because of window manager quirks, e.g. on KDE it may end up syncing the Tab press portion of Alt+Tab. Luckily missing key events for keys that were pressed and not released while the WM had the keyboard grab is not nearly as confusing as stuck keys. For Warhammer: Chaosbane, theHunter: Call of the Wild, Far Cry Primal and many other games that end up with stuck Alt after Alt+Tabbing. CW-Bug-ID: #17046 CW-Bug-ID: #18904 --- dlls/winex11.drv/event.c | 2 ++ dlls/winex11.drv/keyboard.c | 43 +++++++++++++++++++++++++++++++++++-- dlls/winex11.drv/mouse.c | 2 ++ dlls/winex11.drv/x11drv.h | 1 + 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index b4d6bf6eb3e..ad92207d518 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -831,6 +831,8 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (event->detail == NotifyPointer) return FALSE; if (hwnd == NtUserGetDesktopWindow()) return FALSE; + x11drv_thread_data()->keymapnotify_hwnd = hwnd; + /* Focus was just restored but it can be right after super was * pressed and gnome-shell needs a bit of time to respond and * toggle the activity view. If we grab the cursor right away diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index db001696a14..b51546a6340 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1206,11 +1206,19 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) int i, j; BYTE keystate[256]; WORD vkey; + DWORD flags; + KeyCode keycode; + HWND keymapnotify_hwnd; BOOL changed = FALSE; struct { WORD vkey; + WORD scan; WORD pressed; } keys[256]; + struct x11drv_thread_data *thread_data = x11drv_thread_data(); + + keymapnotify_hwnd = thread_data->keymapnotify_hwnd; + thread_data->keymapnotify_hwnd = NULL; if (!get_async_key_state( keystate )) return FALSE; @@ -1225,11 +1233,17 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) { for (j = 0; j < 8; j++) { - vkey = keyc2vkey[(i * 8) + j]; + keycode = (i * 8) + j; + vkey = keyc2vkey[keycode]; /* If multiple keys map to the same vkey, we want to report it as * pressed iff any of them are pressed. */ - if (!keys[vkey & 0xff].vkey) keys[vkey & 0xff].vkey = vkey; + if (!keys[vkey & 0xff].vkey) + { + keys[vkey & 0xff].vkey = vkey; + keys[vkey & 0xff].scan = keyc2scan[keycode] & 0xff; + } + if (event->xkeymap.key_vector[i] & (1<window, event->x, event->y, event->detail ); + x11drv_thread_data()->keymapnotify_hwnd = hwnd; + if (hwnd == x11drv_thread_data()->grab_hwnd) return FALSE; /* simulate a mouse motion event */ diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 696bf43faee..7134d9196f9 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -382,6 +382,7 @@ struct x11drv_thread_data XEvent *current_event; /* event currently being processed */ HWND grab_hwnd; /* window that currently grabs the mouse */ HWND last_focus; /* last window that had focus */ + HWND keymapnotify_hwnd; /* window that should receive modifier release events */ XIM xim; /* input method */ HWND last_xic_hwnd; /* last xic window */ XFontSet font_set; /* international text drawing font set */ From 6b277cd507184a9aa4c1ecc9416f0d0953b82c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 7 Mar 2022 16:53:09 +0100 Subject: [PATCH 0210/2777] winex11.drv: Call SetForegroundWindow instead of SetActiveWindow on restore. So that the window is both active and foreground before we send the SC_RESTORE command. Project Cars 3 expects that as it tries to reacquire DInput devices on SC_RESTORE. CW-Bug-Id: #19011 CW-Bug-Id: #20227 --- dlls/winex11.drv/event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index ad92207d518..14ae51eedbd 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1396,7 +1396,7 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window ); release_win_data( data ); if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE)) - NtUserSetActiveWindow( hwnd ); + NtUserSetForegroundWindow( hwnd ); send_message( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 ); return; } From e69c9b14c276c1af0593af122afc7ac4104f7129 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 6 Aug 2019 13:27:25 -0500 Subject: [PATCH 0211/2777] winebus.sys: Disable UDEV lnxev devices by default. Based on a patch from Simon McVittie . --- dlls/winebus.sys/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index c02f786a11f..31008180a2e 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -746,7 +746,7 @@ static NTSTATUS udev_driver_init(void) bus_options.disable_hidraw = check_bus_option(L"DisableHidraw", 0); if (bus_options.disable_hidraw) TRACE("UDEV hidraw devices disabled in registry\n"); - bus_options.disable_input = check_bus_option(L"DisableInput", 0); + bus_options.disable_input = check_bus_option(L"DisableInput", 1); if (bus_options.disable_input) TRACE("UDEV input devices disabled in registry\n"); bus_options.disable_udevd = check_bus_option(L"DisableUdevd", 0); if (bus_options.disable_udevd) TRACE("UDEV udevd use disabled in registry\n"); From fab3b2c3355c57e5d713a31b7c9b99a370db9e2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 30 Sep 2021 15:07:25 +0200 Subject: [PATCH 0212/2777] HACK: winebus.sys: Prefer devices on UDEV hidraw bus over SDL bus. --- dlls/winebus.sys/main.c | 42 ++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index 31008180a2e..15898a23d79 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -71,6 +71,7 @@ struct device_extension { struct list entry; DEVICE_OBJECT *device; + const WCHAR *bus_name; CRITICAL_SECTION cs; enum device_state state; @@ -283,7 +284,7 @@ static void remove_pending_irps(DEVICE_OBJECT *device) } } -static DEVICE_OBJECT *bus_create_hid_device(struct device_desc *desc, UINT64 unix_device) +static DEVICE_OBJECT *bus_create_hid_device(const WCHAR *bus_name, struct device_desc *desc, UINT64 unix_device) { struct device_extension *ext; DEVICE_OBJECT *device; @@ -306,6 +307,7 @@ static DEVICE_OBJECT *bus_create_hid_device(struct device_desc *desc, UINT64 uni /* fill out device_extension struct */ ext = (struct device_extension *)device->DeviceExtension; + ext->bus_name = bus_name; ext->device = device; ext->desc = *desc; ext->index = get_device_index(desc); @@ -334,6 +336,17 @@ static DEVICE_OBJECT *bus_find_unix_device(UINT64 unix_device) return NULL; } +static DEVICE_OBJECT *bus_find_device_from_vid_pid(const WCHAR *bus_name, struct device_desc *desc) +{ + struct device_extension *ext; + + LIST_FOR_EACH_ENTRY(ext, &device_list, struct device_extension, entry) + if (!wcscmp(ext->bus_name, bus_name) && ext->desc.vid == desc->vid && + ext->desc.pid == desc->pid) return ext->device; + + return NULL; +} + static void bus_unlink_hid_device(DEVICE_OBJECT *device) { struct device_extension *ext = (struct device_extension *)device->DeviceExtension; @@ -520,7 +533,7 @@ static void mouse_device_create(void) struct device_create_params params = {{0}}; if (winebus_call(mouse_create, ¶ms)) return; - mouse_obj = bus_create_hid_device(¶ms.desc, params.device); + mouse_obj = bus_create_hid_device(L"WINEBUS", ¶ms.desc, params.device); IoInvalidateDeviceRelations(bus_pdo, BusRelations); } @@ -529,7 +542,7 @@ static void keyboard_device_create(void) struct device_create_params params = {{0}}; if (winebus_call(keyboard_create, ¶ms)) return; - keyboard_obj = bus_create_hid_device(¶ms.desc, params.device); + keyboard_obj = bus_create_hid_device(L"WINEBUS", ¶ms.desc, params.device); IoInvalidateDeviceRelations(bus_pdo, BusRelations); } @@ -575,7 +588,20 @@ static DWORD CALLBACK bus_main_thread(void *args) IoInvalidateDeviceRelations(bus_pdo, BusRelations); break; case BUS_EVENT_TYPE_DEVICE_CREATED: - device = bus_create_hid_device(&event->device_created.desc, event->device); + RtlEnterCriticalSection(&device_list_cs); + if (!wcscmp(bus.name, L"SDL")) + { + if (bus_find_device_from_vid_pid(L"UDEV", &event->device_created.desc)) device = NULL; + else device = bus_create_hid_device(bus.name, &event->device_created.desc, event->device); + } + else if (!wcscmp(bus.name, L"UDEV")) + { + if ((device = bus_find_device_from_vid_pid(L"SDL", &event->device_created.desc))) + bus_unlink_hid_device(device); + device = bus_create_hid_device(bus.name, &event->device_created.desc, event->device); + } + else device = bus_create_hid_device(bus.name, &event->device_created.desc, event->device); + RtlLeaveCriticalSection(&device_list_cs); if (device) IoInvalidateDeviceRelations(bus_pdo, BusRelations); else { @@ -782,11 +808,9 @@ static NTSTATUS fdo_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp) mouse_device_create(); keyboard_device_create(); - if (!check_bus_option(L"Enable SDL", 1) || sdl_driver_init()) - { - udev_driver_init(); - iohid_driver_init(); - } + udev_driver_init(); + iohid_driver_init(); + sdl_driver_init(); irp->IoStatus.Status = STATUS_SUCCESS; break; From c6446f568315846fd5812b7837df3813ba2efb2c Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 6 Aug 2019 13:37:38 -0500 Subject: [PATCH 0213/2777] winebus.sys: Enable hidraw only for the DS4/DualSense controllers. And SDL for everything else. CW-Bug-Id: #20281 Squashed with: HACK: winebus.sys: Don't use hidraw for XBox controllers. HACK: winebus.sys: Don't use hidraw for Steam controllers. 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/bus_udev.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 34b3305ed88..82dc6321122 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -1372,8 +1372,12 @@ static void udev_add_device(struct udev_device *dev, int fd) memcpy(desc.serialnumber, zeros, sizeof(zeros)); } - if (is_xbox_gamepad(desc.vid, desc.pid)) - desc.is_gamepad = TRUE; + if (!is_dualshock4_gamepad(desc.vid, desc.pid) && !is_dualsense_gamepad(desc.vid, desc.pid)) + { + TRACE("hidraw %s: deferring %s to a different backend\n", debugstr_a(devnode), debugstr_device_desc(&desc)); + close(fd); + return; + } #ifdef HAS_PROPER_INPUT_HEADER else { From 919293e08c2159c1c662adb1aebc4e04d65a22c8 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Thu, 7 Oct 2021 15:29:05 +0200 Subject: [PATCH 0214/2777] HACK: winebus.sys: Ignore blacklisted SDL controllers and joysticks. --- dlls/winebus.sys/bus_sdl.c | 10 +++++++++- dlls/winebus.sys/bus_udev.c | 7 +++++++ dlls/winebus.sys/unix_private.h | 1 + dlls/winebus.sys/unixlib.c | 18 ++++++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index cd6166a91a8..b0b78ba18a4 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -957,7 +957,8 @@ static void sdl_add_device(unsigned int index) id = pSDL_JoystickInstanceID(joystick); - if (pSDL_JoystickGetProductVersion != NULL) { + if (pSDL_JoystickGetProductVersion != NULL) + { desc.vid = pSDL_JoystickGetVendor(joystick); desc.pid = pSDL_JoystickGetProduct(joystick); desc.version = pSDL_JoystickGetProductVersion(joystick); @@ -969,6 +970,13 @@ static void sdl_add_device(unsigned int index) desc.version = 0; } + if (is_sdl_blacklisted(desc.vid, desc.pid)) + { + /* this device is blacklisted */ + TRACE("ignoring %s, in SDL blacklist\n", debugstr_device_desc(&desc)); + return; + } + if (pSDL_JoystickGetSerial && (sdl_serial = pSDL_JoystickGetSerial(joystick))) { ntdll_umbstowcs(sdl_serial, strlen(sdl_serial) + 1, desc.serialnumber, ARRAY_SIZE(desc.serialnumber)); diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 82dc6321122..e4e5cfd1903 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -1378,6 +1378,13 @@ static void udev_add_device(struct udev_device *dev, int fd) close(fd); return; } + if (is_sdl_blacklisted(desc.vid, desc.pid)) + { + /* this device is blacklisted */ + TRACE("hidraw %s: ignoring %s, in SDL blacklist\n", debugstr_a(devnode), debugstr_device_desc(&desc)); + close(fd); + return; + } #ifdef HAS_PROPER_INPUT_HEADER else { diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index 3001c32e89e..b92694b8259 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -266,6 +266,7 @@ extern void hid_device_drop_report(struct unix_device *iface) DECLSPEC_HIDDEN; extern void hid_device_set_effect_state(struct unix_device *iface, BYTE index, BYTE flags) DECLSPEC_HIDDEN; +BOOL is_sdl_blacklisted(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_dualshock4_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_dualsense_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c index 75d33399738..a1e1686a579 100644 --- a/dlls/winebus.sys/unixlib.c +++ b/dlls/winebus.sys/unixlib.c @@ -38,6 +38,24 @@ #include "unix_private.h" +/* logic from SDL2's SDL_ShouldIgnoreGameController */ +BOOL is_sdl_blacklisted(WORD vid, WORD pid) +{ + const char *allow_virtual = getenv("SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD"); + const char *whitelist = getenv("SDL_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT"); + const char *blacklist = getenv("SDL_GAMECONTROLLER_IGNORE_DEVICES"); + char needle[16]; + + if (vid == 0x28de && pid == 0x11ff && allow_virtual && *allow_virtual && + *allow_virtual != '0' && strcasecmp(allow_virtual, "false")) + return FALSE; + + sprintf(needle, "0x%04x/0x%04x", vid, pid); + if (whitelist) return strcasestr(whitelist, needle) == NULL; + if (blacklist) return strcasestr(blacklist, needle) != NULL; + return FALSE; +} + BOOL is_xbox_gamepad(WORD vid, WORD pid) { if (vid != 0x045e) return FALSE; From 317ee51f852c8c68ce384adb8005fc15e58be2c2 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Fri, 30 Aug 2019 10:20:16 -0500 Subject: [PATCH 0215/2777] HACK: winebus.sys: Override Steam virtual controller vid/pid with Xbox. Matches Windows Steam client behavior. --- dlls/winebus.sys/bus_sdl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index b0b78ba18a4..d8bd53d3ad0 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -977,6 +977,13 @@ static void sdl_add_device(unsigned int index) return; } + if (desc.vid == 0x28de && desc.pid == 0x11ff) + { + TRACE("Steam virtual controller, pretending it's an Xbox 360 controller\n"); + desc.vid = 0x045e; + desc.pid = 0x028e; + } + if (pSDL_JoystickGetSerial && (sdl_serial = pSDL_JoystickGetSerial(joystick))) { ntdll_umbstowcs(sdl_serial, strlen(sdl_serial) + 1, desc.serialnumber, ARRAY_SIZE(desc.serialnumber)); From 30f03a6bdc6e288f2ab3ef253e63f30195bed6bd Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Thu, 30 Sep 2021 20:38:04 +0200 Subject: [PATCH 0216/2777] winebus.sys: Ignore some joysticks that SDL reports. SDL has a blacklist, but it isn't complete. Ignore some more devices while we fix upstream. --- dlls/winebus.sys/bus_sdl.c | 7 +++++++ dlls/winebus.sys/unix_private.h | 1 + dlls/winebus.sys/unixlib.c | 6 ++++++ 3 files changed, 14 insertions(+) diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index d8bd53d3ad0..7eca73b0501 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -977,6 +977,13 @@ static void sdl_add_device(unsigned int index) return; } + if (is_wine_blacklisted(desc.vid, desc.pid)) + { + /* this device is blacklisted */ + TRACE("ignoring %s, in Wine blacklist\n", debugstr_device_desc(&desc)); + return; + } + if (desc.vid == 0x28de && desc.pid == 0x11ff) { TRACE("Steam virtual controller, pretending it's an Xbox 360 controller\n"); diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index b92694b8259..865bcdd4aba 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -267,6 +267,7 @@ extern void hid_device_drop_report(struct unix_device *iface) DECLSPEC_HIDDEN; extern void hid_device_set_effect_state(struct unix_device *iface, BYTE index, BYTE flags) DECLSPEC_HIDDEN; BOOL is_sdl_blacklisted(WORD vid, WORD pid) DECLSPEC_HIDDEN; +BOOL is_wine_blacklisted(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_dualshock4_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_dualsense_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c index a1e1686a579..3f93f4943fc 100644 --- a/dlls/winebus.sys/unixlib.c +++ b/dlls/winebus.sys/unixlib.c @@ -38,6 +38,12 @@ #include "unix_private.h" +BOOL is_wine_blacklisted(WORD vid, WORD pid) +{ + if (vid == 0x056a) return TRUE; /* all Wacom devices */ + return FALSE; +} + /* logic from SDL2's SDL_ShouldIgnoreGameController */ BOOL is_sdl_blacklisted(WORD vid, WORD pid) { From 279746836ccd84bf6101fe4123eedfdf0f6c514a Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Tue, 10 Nov 2020 18:32:28 +0000 Subject: [PATCH 0217/2777] winebus.sys: Automatically bypass udevd in Flatpak or pressure-vessel. Flatpak uses unprivileged containers that don't normally map uid 0 into the container, so netlink events won't work there, as described in previous commits. Steam's pressure-vessel container tool behaves similarly. --- dlls/winebus.sys/bus_udev.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index e4e5cfd1903..88cdf9a92b3 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -1776,6 +1776,12 @@ NTSTATUS udev_bus_init(void *args) goto error; } + if (access("/run/pressure-vessel", R_OK) || access("/.flatpak-info", R_OK)) + { + TRACE("Container detected, bypassing udevd by default\n"); + options.disable_udevd = TRUE; + } + #ifdef HAVE_SYS_INOTIFY_H if (options.disable_udevd) monitor_fd = create_inotify(); if (monitor_fd < 0) options.disable_udevd = FALSE; From ddbe72e96d2ece0a3a2ff65d5e34a5ccf02613a8 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Tue, 10 Nov 2020 19:03:47 +0000 Subject: [PATCH 0218/2777] winebus.sys: Guess the type of evdev input devices. Ordinarily, we can get the type of an evdev input device from udev: the input_id builtin sets udev properties of the form ID_INPUT_FOO that we can read. However, in a container there is no guarantee that the libudev in the container will interoperate with the udevd on the host system, so we need to be prepared to do this ourselves from first principles, using a heuristic similar to the one in udev's input_id. We cannot simply copy the heuristic from udev's input_id, because its licensing is incompatible (GPL). Instead, use a vaguely similar heuristic that works from the same inputs and will generally produce similar results. --- dlls/winebus.sys/bus_udev.c | 325 ++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 88cdf9a92b3..16016b09566 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -25,6 +25,7 @@ #include "config.h" #include #include +#include #include #include #include @@ -555,6 +556,302 @@ static struct base_device *find_device_from_syspath(const char *path) #define test_bit(arr,bit) (((BYTE*)(arr))[(bit)>>3]&(1<<((bit)&7))) +/* Minimal compatibility with code taken from steam-runtime-tools */ +typedef int gboolean; +#define g_debug(fmt, ...) TRACE(fmt "\n", ## __VA_ARGS__) +#define G_N_ELEMENTS(arr) (sizeof(arr)/sizeof(arr[0])) + +typedef enum +{ + SRT_INPUT_DEVICE_TYPE_FLAGS_JOYSTICK = (1 << 0), + SRT_INPUT_DEVICE_TYPE_FLAGS_ACCELEROMETER = (1 << 1), + SRT_INPUT_DEVICE_TYPE_FLAGS_KEYBOARD = (1 << 2), + SRT_INPUT_DEVICE_TYPE_FLAGS_HAS_KEYS = (1 << 3), + SRT_INPUT_DEVICE_TYPE_FLAGS_MOUSE = (1 << 4), + SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHPAD = (1 << 5), + SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHSCREEN = (1 << 6), + SRT_INPUT_DEVICE_TYPE_FLAGS_TABLET = (1 << 7), + SRT_INPUT_DEVICE_TYPE_FLAGS_TABLET_PAD = (1 << 8), + SRT_INPUT_DEVICE_TYPE_FLAGS_POINTING_STICK = (1 << 9), + SRT_INPUT_DEVICE_TYPE_FLAGS_SWITCH = (1 << 10), + SRT_INPUT_DEVICE_TYPE_FLAGS_NONE = 0 +} SrtInputDeviceTypeFlags; + +#define BITS_PER_LONG (sizeof (unsigned long) * CHAR_BIT) +#define LONGS_FOR_BITS(x) ((((x)-1)/BITS_PER_LONG)+1) +typedef struct +{ + unsigned long ev[LONGS_FOR_BITS (EV_MAX)]; + unsigned long keys[LONGS_FOR_BITS (KEY_MAX)]; + unsigned long abs[LONGS_FOR_BITS (ABS_MAX)]; + unsigned long rel[LONGS_FOR_BITS (REL_MAX)]; + unsigned long ff[LONGS_FOR_BITS (FF_MAX)]; + unsigned long props[LONGS_FOR_BITS (INPUT_PROP_MAX)]; +} SrtEvdevCapabilities; + +static gboolean +_srt_get_caps_from_evdev (int fd, + unsigned int type, + unsigned long *bitmask, + size_t bitmask_len_longs) +{ + size_t bitmask_len_bytes = bitmask_len_longs * sizeof (*bitmask); + + memset (bitmask, 0, bitmask_len_bytes); + + if (ioctl (fd, EVIOCGBIT (type, bitmask_len_bytes), bitmask) < 0) + return FALSE; + + return TRUE; +} + +static gboolean +_srt_evdev_capabilities_set_from_evdev (SrtEvdevCapabilities *caps, + int fd) +{ + if (_srt_get_caps_from_evdev (fd, 0, caps->ev, G_N_ELEMENTS (caps->ev))) + { + _srt_get_caps_from_evdev (fd, EV_KEY, caps->keys, G_N_ELEMENTS (caps->keys)); + _srt_get_caps_from_evdev (fd, EV_ABS, caps->abs, G_N_ELEMENTS (caps->abs)); + _srt_get_caps_from_evdev (fd, EV_REL, caps->rel, G_N_ELEMENTS (caps->rel)); + _srt_get_caps_from_evdev (fd, EV_FF, caps->ff, G_N_ELEMENTS (caps->ff)); + ioctl (fd, EVIOCGPROP (sizeof (caps->props)), caps->props); + return TRUE; + } + + memset (caps, 0, sizeof (*caps)); + return FALSE; +} + +#define JOYSTICK_ABS_AXES \ + ((1 << ABS_X) | (1 << ABS_Y) \ + | (1 << ABS_RX) | (1 << ABS_RY) \ + | (1 << ABS_THROTTLE) | (1 << ABS_RUDDER) \ + | (1 << ABS_WHEEL) | (1 << ABS_GAS) | (1 << ABS_BRAKE) \ + | (1 << ABS_HAT0X) | (1 << ABS_HAT0Y) \ + | (1 << ABS_HAT1X) | (1 << ABS_HAT1Y) \ + | (1 << ABS_HAT2X) | (1 << ABS_HAT2Y) \ + | (1 << ABS_HAT3X) | (1 << ABS_HAT3Y)) + +static const unsigned int first_mouse_button = BTN_MOUSE; +static const unsigned int last_mouse_button = BTN_JOYSTICK - 1; + +static const unsigned int first_joystick_button = BTN_JOYSTICK; +static const unsigned int last_joystick_button = BTN_GAMEPAD - 1; + +static const unsigned int first_gamepad_button = BTN_GAMEPAD; +static const unsigned int last_gamepad_button = BTN_DIGI - 1; + +static const unsigned int first_dpad_button = BTN_DPAD_UP; +static const unsigned int last_dpad_button = BTN_DPAD_RIGHT; + +static const unsigned int first_extra_joystick_button = BTN_TRIGGER_HAPPY; +static const unsigned int last_extra_joystick_button = BTN_TRIGGER_HAPPY40; + +SrtInputDeviceTypeFlags +_srt_evdev_capabilities_guess_type (const SrtEvdevCapabilities *caps) +{ + SrtInputDeviceTypeFlags flags = SRT_INPUT_DEVICE_TYPE_FLAGS_NONE; + unsigned int i; + gboolean has_joystick_axes = FALSE; + gboolean has_joystick_buttons = FALSE; + + /* Some properties let us be fairly sure about a device */ + if (test_bit (caps->props, INPUT_PROP_ACCELEROMETER)) + { + g_debug ("INPUT_PROP_ACCELEROMETER => is accelerometer"); + flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_ACCELEROMETER; + } + + if (test_bit (caps->props, INPUT_PROP_POINTING_STICK)) + { + g_debug ("INPUT_PROP_POINTING_STICK => is pointing stick"); + flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_POINTING_STICK; + } + + if (test_bit (caps->props, INPUT_PROP_BUTTONPAD) + || test_bit (caps->props, INPUT_PROP_TOPBUTTONPAD)) + { + g_debug ("INPUT_PROP_[TOP]BUTTONPAD => is touchpad"); + flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHPAD; + } + + /* Devices with a stylus or pen are assumed to be graphics tablets */ + if (test_bit (caps->keys, BTN_STYLUS) + || test_bit (caps->keys, BTN_TOOL_PEN)) + { + g_debug ("Stylus or pen => is tablet"); + flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_TABLET; + } + + /* Devices that accept a finger touch are assumed to be touchpads or + * touchscreens. + * + * In Steam we mostly only care about these as a way to + * reject non-joysticks, so we're not very precise here yet. + * + * SDL assumes that TOUCH means a touchscreen and FINGER + * means a touchpad. */ + if (flags == SRT_INPUT_DEVICE_TYPE_FLAGS_NONE + && (test_bit (caps->keys, BTN_TOOL_FINGER) + || test_bit (caps->keys, BTN_TOUCH) + || test_bit (caps->props, INPUT_PROP_SEMI_MT))) + { + g_debug ("Finger or touch or semi-MT => is touchpad or touchscreen"); + + if (test_bit (caps->props, INPUT_PROP_POINTER)) + flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHPAD; + else + flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHSCREEN; + } + + /* Devices with mouse buttons are ... probably mice? */ + if (flags == SRT_INPUT_DEVICE_TYPE_FLAGS_NONE) + { + for (i = first_mouse_button; i <= last_mouse_button; i++) + { + if (test_bit (caps->keys, i)) + { + g_debug ("Mouse button => mouse"); + flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_MOUSE; + } + } + } + + if (flags == SRT_INPUT_DEVICE_TYPE_FLAGS_NONE) + { + for (i = ABS_X; i < ABS_Z; i++) + { + if (!test_bit (caps->abs, i)) + break; + } + + /* If it has 3 axes and no buttons it's probably an accelerometer. */ + if (i == ABS_Z && !test_bit (caps->ev, EV_KEY)) + { + g_debug ("3 left axes and no buttons => accelerometer"); + flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_ACCELEROMETER; + } + + /* Same for RX..RZ (e.g. Wiimote) */ + for (i = ABS_RX; i < ABS_RZ; i++) + { + if (!test_bit (caps->abs, i)) + break; + } + + if (i == ABS_RZ && !test_bit (caps->ev, EV_KEY)) + { + g_debug ("3 right axes and no buttons => accelerometer"); + flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_ACCELEROMETER; + } + } + + /* Bits 1 to 31 are ESC, numbers and Q to D, which SDL and udev both + * consider to be enough to count as a fully-functioned keyboard. */ + if ((caps->keys[0] & 0xfffffffe) == 0xfffffffe) + { + g_debug ("First few keys => keyboard"); + flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_KEYBOARD; + } + + /* If we have *any* keys, consider it to be something a bit + * keyboard-like. Bits 0 to 63 are all keyboard keys. + * Make sure we stop before reaching KEY_UP which is sometimes + * used on game controller mappings, e.g. for the Wiimote. */ + for (i = 0; i < (64 / BITS_PER_LONG); i++) + { + if (caps->keys[i] != 0) + flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_HAS_KEYS; + } + + if (caps->abs[0] & JOYSTICK_ABS_AXES) + has_joystick_axes = TRUE; + + /* Flight stick buttons */ + for (i = first_joystick_button; i <= last_joystick_button; i++) + { + if (test_bit (caps->keys, i)) + has_joystick_buttons = TRUE; + } + + /* Gamepad buttons (Xbox, PS3, etc.) */ + for (i = first_gamepad_button; i <= last_gamepad_button; i++) + { + if (test_bit (caps->keys, i)) + has_joystick_buttons = TRUE; + } + + /* Gamepad digital dpad */ + for (i = first_dpad_button; i <= last_dpad_button; i++) + { + if (test_bit (caps->keys, i)) + has_joystick_buttons = TRUE; + } + + /* Steering wheel gear-change buttons */ + for (i = BTN_GEAR_DOWN; i <= BTN_GEAR_UP; i++) + { + if (test_bit (caps->keys, i)) + has_joystick_buttons = TRUE; + } + + /* Reserved space for extra game-controller buttons, e.g. on Corsair + * gaming keyboards */ + for (i = first_extra_joystick_button; i <= last_extra_joystick_button; i++) + { + if (test_bit (caps->keys, i)) + has_joystick_buttons = TRUE; + } + + if (test_bit (caps->keys, last_mouse_button)) + { + /* Mice with a very large number of buttons can apparently + * overflow into the joystick-button space, but they're still not + * joysticks. */ + has_joystick_buttons = FALSE; + } + + /* TODO: Do we want to consider BTN_0 up to BTN_9 to be joystick buttons? + * libmanette and SDL look for BTN_1, udev does not. + * + * They're used by some game controllers, like BTN_1 and BTN_2 for the + * Wiimote, BTN_1..BTN_9 for the SpaceTec SpaceBall and BTN_0..BTN_3 + * for Playstation dance pads, but they're also used by + * non-game-controllers like Logitech mice. For now we entirely ignore + * these buttons: they are not evidence that it's a joystick, but + * neither are they evidence that it *isn't* a joystick. */ + + /* We consider it to be a joystick if there is some evidence that it is, + * and no evidence that it's something else. + * + * Unlike SDL, we accept devices with only axes and no buttons as a + * possible joystick, unless they have X/Y/Z axes in which case we + * assume they're accelerometers. */ + if ((has_joystick_buttons || has_joystick_axes) + && (flags == SRT_INPUT_DEVICE_TYPE_FLAGS_NONE)) + { + g_debug ("Looks like a joystick"); + flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_JOYSTICK; + } + + /* If we have *any* keys below BTN_MISC, consider it to be something + * a bit keyboard-like, but don't rule out *also* being considered + * to be a joystick (again for e.g. the Wiimote). */ + for (i = 0; i < (BTN_MISC / BITS_PER_LONG); i++) + { + if (caps->keys[i] != 0) + flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_HAS_KEYS; + } + + /* Also non-exclusive: don't rule out a device being a joystick and + * having a switch */ + if (test_bit (caps->ev, EV_SW)) + flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_SWITCH; + + return flags; +} + static const USAGE_AND_PAGE *what_am_I(struct udev_device *dev, int fd) { static const USAGE_AND_PAGE Unknown = {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = 0}; @@ -565,6 +862,7 @@ static const USAGE_AND_PAGE *what_am_I(struct udev_device *dev, int fd) static const USAGE_AND_PAGE Tablet = {.UsagePage = HID_USAGE_PAGE_DIGITIZER, .Usage = HID_USAGE_DIGITIZER_PEN}; static const USAGE_AND_PAGE Touchscreen = {.UsagePage = HID_USAGE_PAGE_DIGITIZER, .Usage = HID_USAGE_DIGITIZER_TOUCH_SCREEN}; static const USAGE_AND_PAGE Touchpad = {.UsagePage = HID_USAGE_PAGE_DIGITIZER, .Usage = HID_USAGE_DIGITIZER_TOUCH_PAD}; + SrtEvdevCapabilities caps; struct udev_device *parent = dev; @@ -589,6 +887,33 @@ static const USAGE_AND_PAGE *what_am_I(struct udev_device *dev, int fd) parent = udev_device_get_parent_with_subsystem_devtype(parent, "input", NULL); } + /* In a container, udev properties might not be available. Fall back to deriving the device + * type from the fd's evdev capabilities. */ + if (_srt_evdev_capabilities_set_from_evdev (&caps, fd)) + { + SrtInputDeviceTypeFlags guessed_type; + + guessed_type = _srt_evdev_capabilities_guess_type (&caps); + + if (guessed_type & (SRT_INPUT_DEVICE_TYPE_FLAGS_MOUSE + | SRT_INPUT_DEVICE_TYPE_FLAGS_POINTING_STICK)) + return &Mouse; + else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_KEYBOARD) + return &Keyboard; + else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_JOYSTICK) + return &Gamepad; + else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_HAS_KEYS) + return &Keypad; + else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHPAD) + return &Touchpad; + else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHSCREEN) + return &Touchscreen; + else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_TABLET) + return &Tablet; + + /* Mapped to Unknown: ACCELEROMETER, TABLET_PAD, SWITCH. */ + } + return &Unknown; } From 78e0cd4456bd15bea2ebc1ed1c4acf381e784c92 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 15 Dec 2020 12:23:31 -0600 Subject: [PATCH 0219/2777] winebus.sys: Enable SDL input logging when hid channel is enabled. --- dlls/winebus.sys/bus_sdl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 7eca73b0501..818fa160be4 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -114,6 +114,7 @@ MAKE_FUNCPTR(SDL_GameControllerAddMapping); MAKE_FUNCPTR(SDL_RegisterEvents); MAKE_FUNCPTR(SDL_PushEvent); MAKE_FUNCPTR(SDL_GetTicks); +MAKE_FUNCPTR(SDL_LogSetPriority); static int (*pSDL_JoystickRumble)(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms); static int (*pSDL_JoystickRumbleTriggers)(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble, Uint32 duration_ms); static Uint16 (*pSDL_JoystickGetProduct)(SDL_Joystick * joystick); @@ -1151,6 +1152,7 @@ NTSTATUS sdl_bus_init(void *args) LOAD_FUNCPTR(SDL_RegisterEvents); LOAD_FUNCPTR(SDL_PushEvent); LOAD_FUNCPTR(SDL_GetTicks); + LOAD_FUNCPTR(SDL_LogSetPriority); #undef LOAD_FUNCPTR pSDL_JoystickRumble = dlsym(sdl_handle, "SDL_JoystickRumble"); pSDL_JoystickRumbleTriggers = dlsym(sdl_handle, "SDL_JoystickRumbleTriggers"); @@ -1172,6 +1174,11 @@ NTSTATUS sdl_bus_init(void *args) goto failed; } + if (TRACE_ON(hid)) + { + pSDL_LogSetPriority(SDL_LOG_CATEGORY_INPUT, SDL_LOG_PRIORITY_VERBOSE); + } + pSDL_JoystickEventState(SDL_ENABLE); pSDL_GameControllerEventState(SDL_ENABLE); From bbb5ddb65c902035c073c0ac0d65f65872696985 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Nov 2022 00:09:20 +0100 Subject: [PATCH 0220/2777] winebus.sys: Add Logitech G920 mapping to the SDL backend. The HID input report format is different between Linux (hid_logitech_hidpp) and Windows when it comes to axis HID usages. To correct that we can use the device through SDL and craft our own HID mapping. --- dlls/winebus.sys/bus_sdl.c | 53 ++++++++++++++++++++++++--------- dlls/winebus.sys/unix_private.h | 1 + dlls/winebus.sys/unixlib.c | 5 ++++ 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 818fa160be4..599c6af228b 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -247,20 +247,41 @@ static BOOL descriptor_add_haptic(struct sdl_device *impl) return TRUE; } +static const USAGE_AND_PAGE g920_absolute_usages[] = +{ + {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_X}, /* wheel */ + {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_Y}, /* accelerator */ + {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_Z}, /* brake */ + {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_RZ}, /* clutch */ +}; + +static const USAGE_AND_PAGE generic_absolute_usages[] = +{ + {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_X}, + {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_Y}, + {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_Z}, + {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_RX}, + {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_RY}, + {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_RZ}, + {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_SLIDER}, + {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_DIAL}, +}; + +static int get_absolute_usages(struct sdl_device *impl, const USAGE_AND_PAGE **absolute_usages) +{ + if (is_logitech_g920(pSDL_JoystickGetVendor(impl->sdl_joystick), pSDL_JoystickGetProduct(impl->sdl_joystick))) + { + *absolute_usages = g920_absolute_usages; + return ARRAY_SIZE(g920_absolute_usages); + } + + *absolute_usages = generic_absolute_usages; + return ARRAY_SIZE(generic_absolute_usages); +} + static NTSTATUS build_joystick_report_descriptor(struct unix_device *iface) { const USAGE_AND_PAGE device_usage = {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_JOYSTICK}; - static const USAGE_AND_PAGE absolute_usages[] = - { - {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_X}, - {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_Y}, - {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_Z}, - {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_RX}, - {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_RY}, - {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_RZ}, - {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_SLIDER}, - {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_DIAL}, - }; static const USAGE_AND_PAGE relative_usages[] = { {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_X}, @@ -273,16 +294,20 @@ static NTSTATUS build_joystick_report_descriptor(struct unix_device *iface) {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_DIAL}, {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_WHEEL}, }; + const USAGE_AND_PAGE *absolute_usages = NULL; struct sdl_device *impl = impl_from_unix_device(iface); int i, button_count, axis_count, ball_count, hat_count; USAGE_AND_PAGE physical_usage; + size_t absolute_usages_count; + + absolute_usages_count = get_absolute_usages(impl, &absolute_usages); axis_count = pSDL_JoystickNumAxes(impl->sdl_joystick); if (options.split_controllers) axis_count = min(6, axis_count - impl->axis_offset); - if (axis_count > ARRAY_SIZE(absolute_usages)) + if (axis_count > absolute_usages_count) { - FIXME("More than %zu absolute axes found, ignoring.\n", ARRAY_SIZE(absolute_usages)); - axis_count = ARRAY_SIZE(absolute_usages); + FIXME("More than %zu absolute axes found, ignoring.\n", absolute_usages_count); + axis_count = absolute_usages_count; } ball_count = pSDL_JoystickNumBalls(impl->sdl_joystick); diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index 865bcdd4aba..895df96261c 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -271,5 +271,6 @@ BOOL is_wine_blacklisted(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_dualshock4_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_dualsense_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; +BOOL is_logitech_g920(WORD vid, WORD pid) DECLSPEC_HIDDEN; #endif /* __WINEBUS_UNIX_PRIVATE_H */ diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c index 3f93f4943fc..ec5fe6ce710 100644 --- a/dlls/winebus.sys/unixlib.c +++ b/dlls/winebus.sys/unixlib.c @@ -100,6 +100,11 @@ BOOL is_dualsense_gamepad(WORD vid, WORD pid) return FALSE; } +BOOL is_logitech_g920(WORD vid, WORD pid) +{ + return vid == 0x046D && pid == 0xC262; +} + struct mouse_device { struct unix_device unix_device; From 5e2026bd16666c70a250c71e57371b65557ecca6 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Wed, 20 Apr 2022 14:09:16 +0300 Subject: [PATCH 0221/2777] winebus.sys: Enable hidraw for Thrustmaster T.Flight Rudder Pedals Link: https://github.com/ValveSoftware/Proton/issues/5749#issuecomment-1102831266 --- dlls/winebus.sys/bus_udev.c | 2 +- dlls/winebus.sys/unix_private.h | 1 + dlls/winebus.sys/unixlib.c | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 16016b09566..767bb11712e 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -1697,7 +1697,7 @@ static void udev_add_device(struct udev_device *dev, int fd) memcpy(desc.serialnumber, zeros, sizeof(zeros)); } - if (!is_dualshock4_gamepad(desc.vid, desc.pid) && !is_dualsense_gamepad(desc.vid, desc.pid)) + if (!is_dualshock4_gamepad(desc.vid, desc.pid) && !is_dualsense_gamepad(desc.vid, desc.pid) && !is_thrustmaster_rudder_pedals(desc.vid, desc.pid)) { TRACE("hidraw %s: deferring %s to a different backend\n", debugstr_a(devnode), debugstr_device_desc(&desc)); close(fd); diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index 895df96261c..49fa5c3b411 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -272,5 +272,6 @@ BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_dualshock4_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_dualsense_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_logitech_g920(WORD vid, WORD pid) DECLSPEC_HIDDEN; +BOOL is_thrustmaster_rudder_pedals(WORD vid, WORD pid) DECLSPEC_HIDDEN; #endif /* __WINEBUS_UNIX_PRIVATE_H */ diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c index ec5fe6ce710..61396767e5d 100644 --- a/dlls/winebus.sys/unixlib.c +++ b/dlls/winebus.sys/unixlib.c @@ -105,6 +105,11 @@ BOOL is_logitech_g920(WORD vid, WORD pid) return vid == 0x046D && pid == 0xC262; } +BOOL is_thrustmaster_rudder_pedals(WORD vid, WORD pid) +{ + return vid == 0x044F && pid == 0xB679; +} + struct mouse_device { struct unix_device unix_device; From b897e7562310161a9d230d84c1f8e0cf01a2a777 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Tue, 26 Jul 2022 11:22:26 +0300 Subject: [PATCH 0222/2777] winebus.sys: Enable hidraw for Thrustmaster HOTAS. CW-Bug-Id: #20694 --- dlls/winebus.sys/bus_udev.c | 2 +- dlls/winebus.sys/unix_private.h | 2 +- dlls/winebus.sys/unixlib.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 767bb11712e..34538ed2a5e 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -1697,7 +1697,7 @@ static void udev_add_device(struct udev_device *dev, int fd) memcpy(desc.serialnumber, zeros, sizeof(zeros)); } - if (!is_dualshock4_gamepad(desc.vid, desc.pid) && !is_dualsense_gamepad(desc.vid, desc.pid) && !is_thrustmaster_rudder_pedals(desc.vid, desc.pid)) + if (!is_dualshock4_gamepad(desc.vid, desc.pid) && !is_dualsense_gamepad(desc.vid, desc.pid) && !is_thrustmaster_hotas(desc.vid, desc.pid)) { TRACE("hidraw %s: deferring %s to a different backend\n", debugstr_a(devnode), debugstr_device_desc(&desc)); close(fd); diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index 49fa5c3b411..a03200361ad 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -272,6 +272,6 @@ BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_dualshock4_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_dualsense_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_logitech_g920(WORD vid, WORD pid) DECLSPEC_HIDDEN; -BOOL is_thrustmaster_rudder_pedals(WORD vid, WORD pid) DECLSPEC_HIDDEN; +BOOL is_thrustmaster_hotas(WORD vid, WORD pid) DECLSPEC_HIDDEN; #endif /* __WINEBUS_UNIX_PRIVATE_H */ diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c index 61396767e5d..5e7ce71779f 100644 --- a/dlls/winebus.sys/unixlib.c +++ b/dlls/winebus.sys/unixlib.c @@ -105,9 +105,9 @@ BOOL is_logitech_g920(WORD vid, WORD pid) return vid == 0x046D && pid == 0xC262; } -BOOL is_thrustmaster_rudder_pedals(WORD vid, WORD pid) +BOOL is_thrustmaster_hotas(WORD vid, WORD pid) { - return vid == 0x044F && pid == 0xB679; + return vid == 0x044F && (pid == 0xB679 || pid == 0xB687 || pid == 0xB10A); } struct mouse_device From bfd5ab691429cd4b3d770f9f5801e0855b0ecca2 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Tue, 18 Jan 2022 14:29:59 +0200 Subject: [PATCH 0223/2777] dinput: Make it possible to add hacks that override names and GUID of axes. --- dlls/dinput/joystick_hid.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 41fd0e24963..dcf76ee159f 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -544,6 +544,8 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, struct hid_collection_node *node, *node_end; WORD version = impl->base.dinput->dwVersion; BOOL ret, seen_axis[6] = {0}; + const GUID *hack_guid; + const WCHAR *hack_name; const WCHAR *tmp; button_ofs += impl->caps.NumberInputValueCaps * sizeof(LONG); @@ -563,6 +565,8 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, value_ofs += (caps->usage_max - caps->usage_min + 1) * sizeof(LONG); else for (j = caps->usage_min; j <= caps->usage_max; ++j) { + hack_name = NULL; + hack_guid = NULL; instance.dwOfs = value_ofs; switch (MAKELONG(j, caps->usage_page)) { @@ -609,12 +613,16 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, } instance.wUsagePage = caps->usage_page; instance.wUsage = j; - instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage ); + if (hack_guid) + instance.guidType = *hack_guid; + else + instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage ); instance.wReportId = caps->report_id; instance.wCollectionNumber = caps->link_collection; instance.dwDimension = caps->units; instance.wExponent = caps->units_exp; - if ((tmp = object_usage_to_string( &instance ))) lstrcpynW( instance.tszName, tmp, MAX_PATH ); + if (hack_name) lstrcpynW( instance.tszName, hack_name, MAX_PATH ); + else if ((tmp = object_usage_to_string( &instance ))) lstrcpynW( instance.tszName, tmp, MAX_PATH ); else swprintf( instance.tszName, MAX_PATH, L"Unknown %u", DIDFT_GETINSTANCE( instance.dwType ) ); check_pid_effect_axis_caps( impl, &instance ); ret = enum_object( impl, filter, flags, callback, caps, &instance, data ); From f4540f35167b3155ea23d01e18dfa4e1f81f9fda Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Tue, 18 Jan 2022 14:30:46 +0200 Subject: [PATCH 0224/2777] dinput: Add mapping for Logitech G920. The wheel has a custom mapping and type override on Windows that do not correspond what dinput would create by itself basing on HID descriptors. --- dlls/dinput/joystick_hid.c | 39 +++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index dcf76ee159f..c680b56aab5 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -47,6 +47,9 @@ #include "wine/debug.h" #include "wine/hid.h" +#define VID_LOGITECH 0x046D +#define PID_LOGITECH_G920 0xC262 + WINE_DEFAULT_DEBUG_CHANNEL(dinput); DEFINE_GUID( GUID_DEVINTERFACE_WINEXINPUT,0x6c53d5fd,0x6480,0x440f,0xb6,0x18,0x47,0x67,0x50,0xc5,0xe1,0xa6 ); @@ -576,7 +579,38 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, case MAKELONG(HID_USAGE_GENERIC_RX, HID_USAGE_PAGE_GENERIC): case MAKELONG(HID_USAGE_GENERIC_RY, HID_USAGE_PAGE_GENERIC): case MAKELONG(HID_USAGE_GENERIC_RZ, HID_USAGE_PAGE_GENERIC): - set_axis_type( &instance, seen_axis, j - HID_USAGE_GENERIC_X, &axis ); + if (impl->attrs.VendorID == VID_LOGITECH && impl->attrs.ProductID == PID_LOGITECH_G920) + { + if (j == HID_USAGE_GENERIC_X) + { + set_axis_type( &instance, seen_axis, 0, &axis ); + hack_guid = &GUID_XAxis; + hack_name = L"Wheel axis"; + } + else if (j == HID_USAGE_GENERIC_Y) + { + set_axis_type( &instance, seen_axis, 2, &axis ); + hack_guid = &GUID_YAxis; + hack_name = L"Accelerator"; + } + else if (j == HID_USAGE_GENERIC_Z) + { + set_axis_type( &instance, seen_axis, 5, &axis ); + hack_guid = &GUID_RzAxis; + hack_name = L"Brake"; + } + else if (j == HID_USAGE_GENERIC_RZ) + { + instance.dwType = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 6 + axis++ ); + hack_guid = &GUID_Slider; + hack_name = L"Clutch"; + } + else WARN("unknown axis usage page %x usage %lx for Logitech G920\n", caps->usage_page, j); + } + else + { + set_axis_type( &instance, seen_axis, j - HID_USAGE_GENERIC_X, &axis ); + } instance.dwFlags = DIDOI_ASPECTPOSITION; break; case MAKELONG(HID_USAGE_SIMULATION_STEERING, HID_USAGE_PAGE_SIMULATION): @@ -1569,6 +1603,9 @@ static HRESULT hid_joystick_device_try_open( const WCHAR *path, HANDLE *device, break; } + if (attrs->VendorID == VID_LOGITECH && attrs->ProductID == PID_LOGITECH_G920) + type = DI8DEVTYPE_DRIVING | (DI8DEVTYPEDRIVING_DUALPEDALS << 8); + instance->dwDevType = device_type_for_version( type, version ) | DIDEVTYPE_HID; TRACE("detected device type %#lx\n", instance->dwDevType); From 263fa318a2047bcefa381300e736ee9b4213517b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 23 Nov 2021 10:54:06 +0100 Subject: [PATCH 0225/2777] HACK: proton: winex11.drv: Track GAMESCOPE_FOCUSED_APP property changes. CW-Bug-Id: #19673 CW-Bug-Id: #19991 --- dlls/winex11.drv/event.c | 32 ++++++++++++++++++++++++++++++++ dlls/winex11.drv/window.c | 3 ++- dlls/winex11.drv/x11drv.h | 1 + dlls/winex11.drv/x11drv_main.c | 3 ++- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 14ae51eedbd..e23ba5df8f7 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1438,6 +1438,36 @@ static void handle__net_wm_state_notify( HWND hwnd, XPropertyEvent *event ) release_win_data( data ); } +static int handle_gamescope_focused_app_error( Display *dpy, XErrorEvent *event, void *arg ) +{ + WARN( "Failed to read GAMESCOPE_FOCUSED_APP property, ignoring.\n" ); + return 1; +} + +static void handle_gamescope_focused_app( XPropertyEvent *event ) +{ + static const char *sgi = NULL; + + unsigned long count, remaining, *property; + int format, app_id, focused_app_id; + Atom type; + + if (!sgi && !(sgi = getenv( "SteamGameId" ))) return; + app_id = atoi( sgi ); + + X11DRV_expect_error( event->display, handle_gamescope_focused_app_error, NULL ); + XGetWindowProperty( event->display, DefaultRootWindow( event->display ), x11drv_atom( GAMESCOPE_FOCUSED_APP ), + 0, ~0UL, False, XA_CARDINAL, &type, &format, &count, &remaining, (unsigned char **)&property ); + if (X11DRV_check_error()) focused_app_id = app_id; + else + { + if (!property) focused_app_id = app_id; + else focused_app_id = *property; + XFree( property ); + } + + TRACE( "Got app id %u, focused app %u\n", app_id, focused_app_id ); +} /*********************************************************************** * X11DRV_PropertyNotify @@ -1447,6 +1477,8 @@ static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *xev ) XPropertyEvent *event = &xev->xproperty; char *name; + if (event->atom == x11drv_atom( GAMESCOPE_FOCUSED_APP )) handle_gamescope_focused_app( event ); + if (!hwnd) return FALSE; name = XGetAtomName( event->display, event->atom ); diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 1996de28c76..2637ba92ddb 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2139,6 +2139,7 @@ BOOL X11DRV_CreateWindow( HWND hwnd ) InputOnly, default_visual.visual, CWOverrideRedirect | CWEventMask, &attr ); X11DRV_XInput2_Enable( data->display, data->clip_window, attr.event_mask ); + XSelectInput( data->display, DefaultRootWindow( data->display ), PropertyChangeMask ); XFlush( data->display ); NtUserSetProp( hwnd, clip_window_prop, (HANDLE)data->clip_window ); X11DRV_DisplayDevices_RegisterEventHandlers(); @@ -2326,7 +2327,7 @@ NTSTATUS x11drv_systray_init( void *arg ) sprintf( systray_buffer, "_NET_SYSTEM_TRAY_S%u", DefaultScreen( display ) ); systray_atom = XInternAtom( display, systray_buffer, False ); } - XSelectInput( display, root_window, StructureNotifyMask ); + XSelectInput( display, root_window, StructureNotifyMask | PropertyChangeMask ); return TRUE; } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 7134d9196f9..df7960231c3 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -553,6 +553,7 @@ enum x11drv_atoms XATOM_text_rtf, XATOM_text_richtext, XATOM_text_uri_list, + XATOM_GAMESCOPE_FOCUSED_APP, NB_XATOMS }; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index dff5d329571..639b1508b80 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -223,7 +223,8 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = "text/plain", "text/rtf", "text/richtext", - "text/uri-list" + "text/uri-list", + "GAMESCOPE_FOCUSED_APP" }; /*********************************************************************** From 9b1bec1422c8904a2d0813b4b09a8c90b63a1a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 17 Dec 2020 18:47:44 +0100 Subject: [PATCH 0226/2777] HACK: proton: winex11.drv: Check Steam overlay presence and drop events when enabled. Squashed with: winex11.drv: Don't allow querying pointer while overlay is active. HACK: gamescope: winex11.drv: Ignore mouse events when Steam Keyboard is opened. Using a global __wine_steamclient_KeyboardActivated event. We need to keep keyboard events though as it's how the OSK will communicate its input. CW-Bug-Id: #19673 winex11.drv: Don't fail GetCursorPos() from X11DRV_GetCursorPos() when Steam overlay is active. CW-Bug-Id: #20732 HACK: gamescope: winex11.drv: Turn OSK input filtering messages to FIXME. --- dlls/winex11.drv/event.c | 30 ++++++++++++++++++++++++++++-- dlls/winex11.drv/mouse.c | 4 ++++ dlls/winex11.drv/x11drv.h | 2 ++ dlls/winex11.drv/x11drv_main.c | 21 +++++++++++++++++++++ 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index e23ba5df8f7..6343e507dd6 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -445,13 +445,23 @@ static BOOL process_events( Display *display, Bool (*filter)(Display*, XEvent*,X { XEvent event, prev_event; int count = 0; - BOOL queued = FALSE; + BOOL queued = FALSE, overlay_enabled = FALSE, steam_keyboard_opened = FALSE; enum event_merge_action action = MERGE_DISCARD; + ULONG_PTR overlay_filter = QS_KEY | QS_MOUSEBUTTON | QS_MOUSEMOVE; + ULONG_PTR keyboard_filter = QS_MOUSEBUTTON | QS_MOUSEMOVE; + LARGE_INTEGER timeout = {0}; + + if (NtWaitForSingleObject(steam_overlay_event, FALSE, &timeout) == WAIT_OBJECT_0) + overlay_enabled = TRUE; + if (NtWaitForSingleObject(steam_keyboard_event, FALSE, &timeout) == WAIT_OBJECT_0) + steam_keyboard_opened = TRUE; prev_event.type = 0; while (XCheckIfEvent( display, &event, filter, (char *)arg )) { count++; + if (overlay_enabled && filter_event( display, &event, (char *)overlay_filter )) continue; + if (steam_keyboard_opened && filter_event( display, &event, (char *)keyboard_filter )) continue; if (XFilterEvent( &event, None )) { /* @@ -1447,9 +1457,11 @@ static int handle_gamescope_focused_app_error( Display *dpy, XErrorEvent *event, static void handle_gamescope_focused_app( XPropertyEvent *event ) { static const char *sgi = NULL; + static BOOL steam_keyboard_opened; unsigned long count, remaining, *property; int format, app_id, focused_app_id; + BOOL keyboard_opened; Atom type; if (!sgi && !(sgi = getenv( "SteamGameId" ))) return; @@ -1466,7 +1478,21 @@ static void handle_gamescope_focused_app( XPropertyEvent *event ) XFree( property ); } - TRACE( "Got app id %u, focused app %u\n", app_id, focused_app_id ); + keyboard_opened = app_id != focused_app_id; + if (steam_keyboard_opened == keyboard_opened) return; + steam_keyboard_opened = keyboard_opened; + + FIXME( "HACK: Got app id %u, focused app %u\n", app_id, focused_app_id ); + if (keyboard_opened) + { + FIXME( "HACK: Steam Keyboard is opened, filtering events.\n" ); + NtSetEvent( steam_keyboard_event, NULL ); + } + else + { + FIXME( "HACK: Steam Keyboard is closed, stopping events filter.\n" ); + NtResetEvent( steam_keyboard_event, NULL ); + } } /*********************************************************************** diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 85336570c6d..5e37a842b5a 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1557,11 +1557,15 @@ BOOL X11DRV_SetCursorPos( INT x, INT y ) BOOL X11DRV_GetCursorPos(LPPOINT pos) { Display *display = thread_init_display(); + LARGE_INTEGER timeout = {0}; Window root, child; int rootX, rootY, winX, winY; unsigned int xstate; BOOL ret; + if (NtWaitForSingleObject(steam_overlay_event, FALSE, &timeout) == WAIT_OBJECT_0) return TRUE; + if (NtWaitForSingleObject(steam_keyboard_event, FALSE, &timeout) == WAIT_OBJECT_0) return TRUE; + ret = XQueryPointer( display, root_window, &root, &child, &rootX, &rootY, &winX, &winY, &xstate ); if (ret) { diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index df7960231c3..6ed45045018 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -455,6 +455,8 @@ extern int xrender_error_base DECLSPEC_HIDDEN; extern char *process_name DECLSPEC_HIDDEN; extern Display *clipboard_display DECLSPEC_HIDDEN; extern WNDPROC client_foreign_window_proc; +extern HANDLE steam_overlay_event DECLSPEC_HIDDEN; +extern HANDLE steam_keyboard_event DECLSPEC_HIDDEN; /* atoms */ diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 639b1508b80..eadde79ed6b 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -91,6 +91,8 @@ int alloc_system_colors = 256; int xrender_error_base = 0; char *process_name = NULL; WNDPROC client_foreign_window_proc = NULL; +HANDLE steam_overlay_event; +HANDLE steam_keyboard_event; static x11drv_error_callback err_callback; /* current callback for error */ static Display *err_callback_display; /* display callback is set for */ @@ -667,6 +669,25 @@ static NTSTATUS x11drv_init( void *arg ) struct init_params *params = arg; Display *display; void *libx11 = dlopen( SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL ); + OBJECT_ATTRIBUTES attr; + WCHAR buffer[MAX_PATH]; + char path[MAX_PATH]; + UNICODE_STRING str; + + RtlInitUnicodeString( &str, buffer ); + InitializeObjectAttributes( &attr, &str, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, 0, NULL ); + + str.Length = sprintf( path, "\\Sessions\\%u\\BaseNamedObjects\\__wine_steamclient_GameOverlayActivated", + (int)NtCurrentTeb()->Peb->SessionId ); + ascii_to_unicode( buffer, path, str.Length + 1 ); + str.Length *= sizeof(WCHAR); + NtCreateEvent( &steam_overlay_event, EVENT_ALL_ACCESS, &attr, NotificationEvent, FALSE ); + + str.Length = sprintf( path, "\\Sessions\\%u\\BaseNamedObjects\\__wine_steamclient_KeyboardActivated", + (int)NtCurrentTeb()->Peb->SessionId ); + ascii_to_unicode( buffer, path, str.Length + 1 ); + str.Length *= sizeof(WCHAR); + NtCreateEvent( &steam_keyboard_event, EVENT_ALL_ACCESS, &attr, NotificationEvent, FALSE ); if (!libx11) { From 84b39d3aef9a63e3bc46f3142786fcd7f7aca849 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 11 Oct 2021 10:48:49 +0200 Subject: [PATCH 0227/2777] HACK: proton: xinput1_3: Check Steam overlay presence and disconnect controllers when enabled. Squashed with: HACK: gamescope: xinput1_3: Ignore gamepad input when Steam Keyboard is opened. --- dlls/xinput1_3/main.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c index 2abf33a8d45..bf0a3c351eb 100644 --- a/dlls/xinput1_3/main.c +++ b/dlls/xinput1_3/main.c @@ -124,6 +124,8 @@ static HANDLE start_event; static HANDLE stop_event; static HANDLE done_event; static HANDLE update_event; +static HANDLE steam_overlay_event; +static HANDLE steam_keyboard_event; static BOOL find_opened_device(const WCHAR *device_path, int *free_slot) { @@ -558,6 +560,8 @@ static void stop_update_thread(void) CloseHandle(stop_event); CloseHandle(done_event); CloseHandle(update_event); + CloseHandle(steam_overlay_event); + CloseHandle(steam_keyboard_event); for (i = 0; i < XUSER_MAX_COUNT; i++) controller_destroy(&controllers[i], FALSE); } @@ -755,6 +759,9 @@ static BOOL WINAPI start_update_thread_once( INIT_ONCE *once, void *param, void { HANDLE thread; + steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated"); + steam_keyboard_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_KeyboardActivated"); + start_event = CreateEventA(NULL, FALSE, FALSE, NULL); if (!start_event) ERR("failed to create start event, error %lu\n", GetLastError()); @@ -851,7 +858,9 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputSetState(DWORD index, XINPUT_VIBRATION *vib if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; if (!controller_lock(&controllers[index])) return ERROR_DEVICE_NOT_CONNECTED; - ret = HID_set_state(&controllers[index], vibration); + if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0) ret = ERROR_SUCCESS; + else if (WaitForSingleObject(steam_keyboard_event, 0) == WAIT_OBJECT_0) ret = ERROR_SUCCESS; + else ret = HID_set_state(&controllers[index], vibration); controller_unlock(&controllers[index]); @@ -869,7 +878,10 @@ static DWORD xinput_get_state(DWORD index, XINPUT_STATE *state) if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; if (!controller_lock(&controllers[index])) return ERROR_DEVICE_NOT_CONNECTED; - *state = controllers[index].state; + if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0) memset(state, 0, sizeof(*state)); + else if (WaitForSingleObject(steam_keyboard_event, 0) == WAIT_OBJECT_0) memset(state, 0, sizeof(*state)); + else *state = controllers[index].state; + controller_unlock(&controllers[index]); return ERROR_SUCCESS; From 5e2c6582eb763f2600af60f6e8eb03a4c11f3f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 9 Jan 2021 20:11:52 +0100 Subject: [PATCH 0228/2777] HACK: proton: dinput: Check Steam overlay presence and clear device state when enabled. CW-Bug-Id: #20083 Squashed with: HACK: gamescope: dinput: Ignore joystick input when Steam Keyboard is opened. --- dlls/dinput/dinput_main.c | 7 +++++++ dlls/dinput/dinput_private.h | 2 ++ dlls/dinput/joystick_hid.c | 20 ++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index d3db22c70b5..8fc593f37e2 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -1431,6 +1431,9 @@ void check_dinput_events(void) MsgWaitForMultipleObjectsEx(0, NULL, 0, QS_ALLINPUT, 0); } +HANDLE steam_overlay_event; +HANDLE steam_keyboard_event; + BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved ) { TRACE( "inst %p, reason %lu, reserved %p.\n", inst, reason, reserved ); @@ -1439,6 +1442,8 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved ) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(inst); + steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated"); + steam_keyboard_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_KeyboardActivated"); DINPUT_instance = inst; register_di_em_win_class(); break; @@ -1446,6 +1451,8 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved ) if (reserved) break; dinput_thread_stop(); unregister_di_em_win_class(); + CloseHandle(steam_overlay_event); + CloseHandle(steam_keyboard_event); break; } return TRUE; diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h index de48c4c5298..3e61d940005 100644 --- a/dlls/dinput/dinput_private.h +++ b/dlls/dinput/dinput_private.h @@ -47,6 +47,8 @@ struct dinput extern const IDirectInput7AVtbl dinput7_a_vtbl DECLSPEC_HIDDEN; extern const IDirectInput8AVtbl dinput8_a_vtbl DECLSPEC_HIDDEN; +extern HANDLE steam_overlay_event DECLSPEC_HIDDEN; +extern HANDLE steam_keyboard_event DECLSPEC_HIDDEN; extern HRESULT mouse_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance, DWORD version ); extern HRESULT mouse_create_device( struct dinput *dinput, const GUID *guid, IDirectInputDevice8W **out ); diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index c680b56aab5..aa20a36e28c 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -1154,6 +1154,7 @@ struct parse_device_state_params { BYTE old_state[DEVICE_STATE_MAX_SIZE]; BYTE buttons[128]; + BOOL reset_state; DWORD time; DWORD seq; }; @@ -1169,6 +1170,9 @@ static BOOL check_device_state_button( struct hid_joystick *impl, struct hid_val value = params->buttons[instance->wUsage - 1]; old_value = params->old_state[instance->dwOfs]; + + if (params->reset_state) value = 0; + impl->base.device_state[instance->dwOfs] = value; if (old_value != value) queue_event( iface, instance->dwType, value, params->time, params->seq ); @@ -1251,6 +1255,16 @@ static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_value if (instance->dwType & DIDFT_AXIS) value = scale_axis_value( logical_value, properties ); else value = scale_value( logical_value, properties ); + if (params->reset_state) + { + if (instance->dwType & DIDFT_POV) value = -1; + else if (instance->dwType & DIDFT_AXIS) + { + if (!properties->range_min) value = properties->range_max / 2; + else value = round( (properties->range_min + properties->range_max) / 2.0 ); + } + } + old_value = *(LONG *)(params->old_state + instance->dwOfs); *(LONG *)(impl->base.device_state + instance->dwOfs) = value; if (old_value != value) @@ -1281,6 +1295,12 @@ static HRESULT hid_joystick_read( IDirectInputDevice8W *iface ) ret = GetOverlappedResult( impl->device, &impl->read_ovl, &count, FALSE ); + if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0 || /* steam overlay is enabled */ + WaitForSingleObject(steam_keyboard_event, 0) == WAIT_OBJECT_0) /* steam keyboard is enabled */ + params.reset_state = TRUE; + else + params.reset_state = FALSE; + EnterCriticalSection( &impl->base.crit ); while (ret) { From 762ca38cf350f01e813ad97459826941a5b77c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 4 Feb 2022 11:34:26 +0100 Subject: [PATCH 0229/2777] HACK: proton: hidclass.sys: Do not send WM_INPUT messages when overlay is open. So that games listening to them, such as ICEY, do not have input bleeding through the overlay. Note that some other games, such as Hades, which are reading the HID devices directly, have the input bleeding through on Windows, so we do the same here. CW-Bug-Id: #20083 --- dlls/hidclass.sys/device.c | 7 ++++++- dlls/hidclass.sys/hid.h | 6 ++++++ dlls/hidclass.sys/pnp.c | 12 ++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index ac201afeddf..2092054d8ca 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -223,6 +223,7 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack const BOOL polled = ext->u.pdo.information.Polled; ULONG size, report_len = polled ? packet->reportBufferLen : desc->InputLength; struct hid_report *last_report, *report; + BOOL steam_overlay_open = FALSE; struct hid_queue *queue; LIST_ENTRY completed, *entry; RAWINPUT *rawinput; @@ -231,7 +232,11 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack TRACE("device %p, packet %p\n", device, packet); - if (IsEqualGUID( ext->class_guid, &GUID_DEVINTERFACE_HID )) + if (WaitForSingleObject(ext->steam_overlay_event, 0) == WAIT_OBJECT_0 || /* steam overlay is open */ + WaitForSingleObject(ext->steam_keyboard_event, 0) == WAIT_OBJECT_0) /* steam keyboard is open */ + steam_overlay_open = TRUE; + + if (IsEqualGUID( ext->class_guid, &GUID_DEVINTERFACE_HID ) && !steam_overlay_open) { size = offsetof( RAWINPUT, data.hid.bRawData[report_len] ); if (!(rawinput = malloc( size ))) ERR( "Failed to allocate rawinput data!\n" ); diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h index b8cec55fb7c..c14f8d7a942 100644 --- a/dlls/hidclass.sys/hid.h +++ b/dlls/hidclass.sys/hid.h @@ -84,6 +84,9 @@ typedef struct _BASE_DEVICE_EXTENSION WCHAR container_id[MAX_GUID_STRING_LEN]; const GUID *class_guid; + HANDLE steam_overlay_event; + HANDLE steam_keyboard_event; + BOOL is_fdo; } BASE_DEVICE_EXTENSION; @@ -115,6 +118,9 @@ typedef struct _minidriver PDRIVER_ADD_DEVICE AddDevice; PDRIVER_DISPATCH PNPDispatch; + + HANDLE steam_overlay_event; + HANDLE steam_keyboard_event; } minidriver; void call_minidriver( ULONG code, DEVICE_OBJECT *device, void *in_buff, ULONG in_size, diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index c0e2a874788..ca367ec3a7c 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -178,6 +178,9 @@ static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *b if (get_device_id(bus_pdo, BusQueryContainerID, ext->container_id)) ext->container_id[0] = 0; + ext->steam_overlay_event = minidriver->steam_overlay_event; + ext->steam_keyboard_event = minidriver->steam_keyboard_event; + is_xinput_class = !wcsncmp(device_id, L"WINEXINPUT\\", 7) && wcsstr(device_id, L"&XI_") != NULL; if (is_xinput_class) ext->class_guid = &GUID_DEVINTERFACE_WINEXINPUT; else ext->class_guid = &GUID_DEVINTERFACE_HID; @@ -242,6 +245,9 @@ static void create_child(minidriver *minidriver, DEVICE_OBJECT *fdo) pdo_ext->u.pdo.information.VersionNumber = attr.VersionNumber; pdo_ext->u.pdo.information.Polled = minidriver->minidriver.DevicesArePolled; + pdo_ext->steam_overlay_event = minidriver->steam_overlay_event; + pdo_ext->steam_keyboard_event = minidriver->steam_keyboard_event; + call_minidriver( IOCTL_HID_GET_DEVICE_DESCRIPTOR, fdo, NULL, 0, &descriptor, sizeof(descriptor), &io ); if (io.Status != STATUS_SUCCESS) { @@ -591,6 +597,9 @@ static void WINAPI driver_unload(DRIVER_OBJECT *driver) if (md->DriverUnload) md->DriverUnload(md->minidriver.DriverObject); list_remove(&md->entry); + + CloseHandle(md->steam_overlay_event); + CloseHandle(md->steam_keyboard_event); free(md); } } @@ -606,6 +615,9 @@ NTSTATUS WINAPI HidRegisterMinidriver(HID_MINIDRIVER_REGISTRATION *registration) if (!(driver = calloc(1, sizeof(*driver)))) return STATUS_NO_MEMORY; + driver->steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated"); + driver->steam_keyboard_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_KeyboardActivated"); + driver->DriverUnload = registration->DriverObject->DriverUnload; registration->DriverObject->DriverUnload = driver_unload; From 020aef14cfd0eebf72449aad4d765a3a1e920c33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 18 May 2022 20:12:41 +0200 Subject: [PATCH 0230/2777] HACK: proton: winex11.drv: Expose GWL_STYLE and GWL_EXSTYLE as X11 properties. As _WINE_HWND_STYLE and _WINE_HWND_EXSTYLE respectively. CW-Bug-Id: #20663 --- dlls/winex11.drv/window.c | 17 +++++++++++++++++ dlls/winex11.drv/x11drv.h | 2 ++ dlls/winex11.drv/x11drv_main.c | 2 ++ 3 files changed, 21 insertions(+) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 2637ba92ddb..79918dc6b9e 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1773,6 +1773,19 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual ) } +void set_hwnd_style_props( Display *display, Window window, HWND hwnd ) +{ + DWORD style = NtUserGetWindowLongW( hwnd, GWL_STYLE ), exstyle = NtUserGetWindowLongW( hwnd, GWL_EXSTYLE ); + + TRACE( "display %p, window %lx, hwnd %p\n", display, window, hwnd ); + + XChangeProperty( display, window, x11drv_atom(_WINE_HWND_STYLE), XA_CARDINAL, 32, + PropModeReplace, (unsigned char *)&style, sizeof(style) / 4 ); + XChangeProperty( display, window, x11drv_atom(_WINE_HWND_EXSTYLE), XA_CARDINAL, 32, + PropModeReplace, (unsigned char *)&exstyle, sizeof(exstyle) / 4 ); +} + + /********************************************************************** * create_whole_window * @@ -1826,6 +1839,8 @@ static void create_whole_window( struct x11drv_win_data *data ) XSaveContext( data->display, data->whole_window, winContext, (char *)data->hwnd ); NtUserSetProp( data->hwnd, whole_window_prop, (HANDLE)data->whole_window ); + set_hwnd_style_props( data->display, data->whole_window, data->hwnd ); + /* set the window text */ if (!NtUserInternalGetWindowText( data->hwnd, text, ARRAY_SIZE( text ))) text[0] = 0; sync_window_text( data->display, data->whole_window, text ); @@ -2848,6 +2863,8 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, return; } + set_hwnd_style_props( data->display, data->whole_window, data->hwnd ); + /* check if we are currently processing an event relevant to this window */ event_type = 0; if (thread_data && diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 6ed45045018..1e7887e2aab 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -522,6 +522,8 @@ enum x11drv_atoms XATOM__GTK_WORKAREAS_D0, XATOM__XEMBED, XATOM__XEMBED_INFO, + XATOM__WINE_HWND_STYLE, + XATOM__WINE_HWND_EXSTYLE, XATOM_XdndAware, XATOM_XdndEnter, XATOM_XdndPosition, diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index eadde79ed6b..b19027e5b26 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -193,6 +193,8 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = "_GTK_WORKAREAS_D0", "_XEMBED", "_XEMBED_INFO", + "_WINE_HWND_STYLE", + "_WINE_HWND_EXSTYLE", "XdndAware", "XdndEnter", "XdndPosition", From d78c8ed306c5da9ce35e488358fd4274cc59f3ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Nov 2022 09:01:34 +0100 Subject: [PATCH 0231/2777] HACK: proton: winebus.sys: Check for Steam Virtual controller indexes. And expose them as the device input number, in the IG_xx / XI_xx suffixes, and as non-zero values. CW-Bug-Id: #20528 --- dlls/winebus.sys/bus_sdl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 599c6af228b..67caf8f0f5f 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -964,7 +964,7 @@ static void sdl_add_device(unsigned int index) SDL_Joystick* joystick; SDL_JoystickID id; SDL_GameController *controller = NULL; - const char *product, *sdl_serial; + const char *product, *sdl_serial, *str; char guid_str[33], buffer[ARRAY_SIZE(desc.product)]; int axis_count, axis_offset; @@ -1017,6 +1017,10 @@ static void sdl_add_device(unsigned int index) desc.pid = 0x028e; } + /* CW-Bug-Id: #20528 Check steam virtual controller indexes to keep them ordered */ + if ((str = pSDL_JoystickName(joystick)) && sscanf(str, "Microsoft X-Box 360 pad %u", &desc.input) == 1) desc.input++; + else desc.input = -1; + if (pSDL_JoystickGetSerial && (sdl_serial = pSDL_JoystickGetSerial(joystick))) { ntdll_umbstowcs(sdl_serial, strlen(sdl_serial) + 1, desc.serialnumber, ARRAY_SIZE(desc.serialnumber)); From d472faa571c4611ccc7a273b57cf053dfdd9ddfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 23 Nov 2022 01:02:13 +0100 Subject: [PATCH 0232/2777] HACK: proton: xinput1_3: Introduce new open_device_at_index helper. CW-Bug-Id: #20528 --- dlls/xinput1_3/main.c | 119 +++++++++++++++++++++++------------------- 1 file changed, 64 insertions(+), 55 deletions(-) diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c index bf0a3c351eb..7c162ac2197 100644 --- a/dlls/xinput1_3/main.c +++ b/dlls/xinput1_3/main.c @@ -127,19 +127,6 @@ static HANDLE update_event; static HANDLE steam_overlay_event; static HANDLE steam_keyboard_event; -static BOOL find_opened_device(const WCHAR *device_path, int *free_slot) -{ - int i; - - *free_slot = XUSER_MAX_COUNT; - for (i = XUSER_MAX_COUNT; i > 0; i--) - { - if (!controllers[i - 1].device) *free_slot = i - 1; - else if (!wcsicmp(device_path, controllers[i - 1].device_path)) return TRUE; - } - return FALSE; -} - static void check_value_caps(struct xinput_controller *controller, USHORT usage, HIDP_VALUE_CAPS *caps) { switch (usage) @@ -341,7 +328,40 @@ static DWORD HID_set_state(struct xinput_controller *controller, XINPUT_VIBRATIO return ERROR_SUCCESS; } -static void controller_destroy(struct xinput_controller *controller, BOOL already_removed); +static void controller_disable(struct xinput_controller *controller) +{ + XINPUT_VIBRATION state = {0}; + + if (!controller->enabled) return; + if (controller->caps.Flags & XINPUT_CAPS_FFB_SUPPORTED) HID_set_state(controller, &state); + controller->enabled = FALSE; + + CancelIoEx(controller->device, &controller->hid.read_ovl); + WaitForSingleObject(controller->hid.read_ovl.hEvent, INFINITE); + SetEvent(update_event); +} + +static void controller_destroy(struct xinput_controller *controller, BOOL already_removed) +{ + EnterCriticalSection(&controller->crit); + + if (controller->device) + { + TRACE("removing device %s from index %Iu\n", debugstr_w(controller->device_path), controller - controllers); + + if (!already_removed) controller_disable(controller); + CloseHandle(controller->device); + controller->device = NULL; + + free(controller->hid.input_report_buf); + free(controller->hid.output_report_buf); + free(controller->hid.feature_report_buf); + HidD_FreePreparsedData(controller->hid.preparsed); + memset(&controller->hid, 0, sizeof(controller->hid)); + } + + LeaveCriticalSection(&controller->crit); +} static void controller_enable(struct xinput_controller *controller) { @@ -361,19 +381,6 @@ static void controller_enable(struct xinput_controller *controller) else SetEvent(update_event); } -static void controller_disable(struct xinput_controller *controller) -{ - XINPUT_VIBRATION state = {0}; - - if (!controller->enabled) return; - if (controller->caps.Flags & XINPUT_CAPS_FFB_SUPPORTED) HID_set_state(controller, &state); - controller->enabled = FALSE; - - CancelIoEx(controller->device, &controller->hid.read_ovl); - WaitForSingleObject(controller->hid.read_ovl.hEvent, INFINITE); - SetEvent(update_event); -} - static BOOL controller_init(struct xinput_controller *controller, PHIDP_PREPARSED_DATA preparsed, HIDP_CAPS *caps, HANDLE device, const WCHAR *device_path) { @@ -457,21 +464,17 @@ static BOOL device_is_overridden(HANDLE device) return disable; } -static BOOL try_add_device(const WCHAR *device_path) +static void open_device_at_index(const WCHAR *device_path, int index) { SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; PHIDP_PREPARSED_DATA preparsed; HIDP_CAPS caps; NTSTATUS status; HANDLE device; - int i; - - if (find_opened_device(device_path, &i)) return TRUE; /* already opened */ - if (i == XUSER_MAX_COUNT) return FALSE; /* no more slots */ device = CreateFileW(device_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL); - if (device == INVALID_HANDLE_VALUE) return TRUE; + if (device == INVALID_HANDLE_VALUE) return; preparsed = NULL; if (!HidD_GetPreparsedData(device, &preparsed)) @@ -485,13 +488,39 @@ static BOOL try_add_device(const WCHAR *device_path) WARN("ignoring HID device, unsupported usage %04x:%04x\n", caps.UsagePage, caps.Usage); else if (device_is_overridden(device)) WARN("ignoring HID device, overridden for dinput\n"); - else if (!controller_init(&controllers[i], preparsed, &caps, device, device_path)) + else if (!controller_init(&controllers[index], preparsed, &caps, device, device_path)) WARN("ignoring HID device, failed to initialize\n"); else - return TRUE; + { + TRACE("opened device %s at index %u\n", debugstr_w(device_path), index); + return; + } CloseHandle(device); HidD_FreePreparsedData(preparsed); +} + +static BOOL find_opened_device(const WCHAR *device_path, int *free_slot) +{ + int i; + + *free_slot = XUSER_MAX_COUNT; + for (i = XUSER_MAX_COUNT; i > 0; i--) + { + if (!controllers[i - 1].device) *free_slot = i - 1; + else if (!wcsicmp(device_path, controllers[i - 1].device_path)) return TRUE; + } + return FALSE; +} + +static BOOL try_add_device(const WCHAR *device_path) +{ + SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; + int i; + + if (find_opened_device(device_path, &i)) return TRUE; /* already opened */ + if (i == XUSER_MAX_COUNT) return FALSE; /* no more slots */ + open_device_at_index(device_path, i); return TRUE; } @@ -529,26 +558,6 @@ static void update_controller_list(void) SetupDiDestroyDeviceInfoList(set); } -static void controller_destroy(struct xinput_controller *controller, BOOL already_removed) -{ - EnterCriticalSection(&controller->crit); - - if (controller->device) - { - if (!already_removed) controller_disable(controller); - CloseHandle(controller->device); - controller->device = NULL; - - free(controller->hid.input_report_buf); - free(controller->hid.output_report_buf); - free(controller->hid.feature_report_buf); - HidD_FreePreparsedData(controller->hid.preparsed); - memset(&controller->hid, 0, sizeof(controller->hid)); - } - - LeaveCriticalSection(&controller->crit); -} - static void stop_update_thread(void) { int i; From 7ad552e281600825a3046005b3ae60c0e1eea49b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 21 Apr 2022 13:17:38 +0200 Subject: [PATCH 0233/2777] HACK: proton: xinput1_3: Insert Steam virtual controllers in their expected slot. CW-Bug-Id: #20528 --- dlls/xinput1_3/main.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c index 7c162ac2197..192d75413fa 100644 --- a/dlls/xinput1_3/main.c +++ b/dlls/xinput1_3/main.c @@ -510,6 +510,17 @@ static BOOL find_opened_device(const WCHAR *device_path, int *free_slot) if (!controllers[i - 1].device) *free_slot = i - 1; else if (!wcsicmp(device_path, controllers[i - 1].device_path)) return TRUE; } + + /* CW-Bug-Id: #20528 Keep steam virtual controller ordered, swap existing controllers out of the slot */ + if ((swscanf(device_path, L"\\\\?\\hid#vid_045e&pid_028e&xi_%02x#", &i) == 1 || + swscanf(device_path, L"\\\\?\\HID#VID_045E&PID_028E&XI_%02X#", &i) == 1) && + i > 0 && i <= XUSER_MAX_COUNT && *free_slot != i - 1) + { + controller_destroy(&controllers[i - 1], TRUE); + if (*free_slot != XUSER_MAX_COUNT) open_device_at_index(controllers[i - 1].device_path, *free_slot); + *free_slot = i - 1; + } + return FALSE; } From e42c09dc198aeaba78ee43a005421d6bb273dd88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 5 Jan 2022 16:14:02 +0100 Subject: [PATCH 0234/2777] user32: Add or remove rawinput devices individually on WM_DEVICECHANGE. CW-Bug-Id: #19841 CW-Bug-Id: #19843 CW-Bug-Id: #19844 --- dlls/win32u/rawinput.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/rawinput.c b/dlls/win32u/rawinput.c index 1ddbca0896a..737facfe05e 100644 --- a/dlls/win32u/rawinput.c +++ b/dlls/win32u/rawinput.c @@ -780,7 +780,24 @@ BOOL process_rawinput_message( MSG *msg, UINT hw_id, const struct hardware_msg_d if (msg->message == WM_INPUT_DEVICE_CHANGE) { pthread_mutex_lock( &rawinput_mutex ); - rawinput_update_device_list(); + if (msg_data->rawinput.type != RIM_TYPEHID || msg_data->rawinput.hid.param != GIDC_REMOVAL) + rawinput_update_device_list(); + else + { + struct device *device; + + LIST_FOR_EACH_ENTRY( device, &devices, struct device, entry ) + { + if (device->handle == UlongToHandle(msg_data->rawinput.hid.device)) + { + list_remove( &device->entry ); + NtClose( device->file ); + free( device->data ); + free( device ); + break; + } + } + } pthread_mutex_unlock( &rawinput_mutex ); } else From 45da677fec76ce82a4d242d4cb90783451003897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Nov 2022 09:05:04 +0100 Subject: [PATCH 0235/2777] windows.gaming.input: Only create Gamepad instances for XInput devices. --- dlls/windows.gaming.input/provider.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dlls/windows.gaming.input/provider.c b/dlls/windows.gaming.input/provider.c index 6908d733a53..d0472727224 100644 --- a/dlls/windows.gaming.input/provider.c +++ b/dlls/windows.gaming.input/provider.c @@ -152,16 +152,18 @@ static HRESULT WINAPI wine_provider_get_Type( IWineGameControllerProvider *iface { struct provider *impl = impl_from_IWineGameControllerProvider( iface ); DIDEVICEINSTANCEW instance = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; + const WCHAR *tmp; HRESULT hr; TRACE( "iface %p, value %p.\n", iface, value ); if (FAILED(hr = IDirectInputDevice8_GetDeviceInfo( impl->dinput_device, &instance ))) return hr; - switch (GET_DIDEVICE_TYPE( instance.dwDevType )) + if ((tmp = wcschr( impl->device_path + 8, '#' )) && !wcsnicmp( tmp - 6, L"&XI_", 4 )) + *value = WineGameControllerType_Gamepad; + else switch (GET_DIDEVICE_TYPE( instance.dwDevType )) { case DI8DEVTYPE_DRIVING: *value = WineGameControllerType_RacingWheel; break; - case DI8DEVTYPE_GAMEPAD: *value = WineGameControllerType_Gamepad; break; default: { DWORD count = 0; From c149aba1448ed3d44f73b30b7e09b334e0387286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 2 Jun 2022 08:45:04 +0200 Subject: [PATCH 0236/2777] winebus.sys: Always return success from PID effect control. Forza Horizon 5 doesn't like unsupported racing wheel force feedback effects. CW-Bug-Id: #20434 --- dlls/winebus.sys/bus_sdl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 67caf8f0f5f..d25dd6362eb 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -617,7 +617,7 @@ static NTSTATUS sdl_device_physical_effect_control(struct unix_device *iface, BY TRACE("iface %p, index %u, control %04x, iterations %u.\n", iface, index, control, iterations); - if (impl->effect_ids[index] < 0) return STATUS_UNSUCCESSFUL; + if (id < 0) return STATUS_SUCCESS; switch (control) { From 230b5c6b238bf3fe28f30ecbdead9a398abbcd9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 2 Jun 2022 00:11:15 +0200 Subject: [PATCH 0237/2777] winebus.sys: Enable all PID effect types for wheel devices. Forza Horizon 5 doesn't like unsupported racing wheel force feedback effects and gives up too soon. On Windows many wheel devices have custom drivers which report support for all types of force feedback effects. CW-Bug-Id: #20434 --- dlls/winebus.sys/bus_sdl.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index d25dd6362eb..960781fb2e4 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -198,7 +198,7 @@ static void set_hat_value(struct unix_device *iface, int index, int value) hid_device_set_hatswitch_y(iface, index, y); } -static BOOL descriptor_add_haptic(struct sdl_device *impl) +static BOOL descriptor_add_haptic(struct sdl_device *impl, BOOL force) { USHORT i, count = 0; USAGE usages[16]; @@ -227,16 +227,16 @@ static BOOL descriptor_add_haptic(struct sdl_device *impl) if ((impl->effect_support & EFFECT_SUPPORT_PHYSICAL)) { /* SDL_HAPTIC_SQUARE doesn't exist */ - if (impl->effect_support & SDL_HAPTIC_SINE) usages[count++] = PID_USAGE_ET_SINE; - if (impl->effect_support & SDL_HAPTIC_TRIANGLE) usages[count++] = PID_USAGE_ET_TRIANGLE; - if (impl->effect_support & SDL_HAPTIC_SAWTOOTHUP) usages[count++] = PID_USAGE_ET_SAWTOOTH_UP; - if (impl->effect_support & SDL_HAPTIC_SAWTOOTHDOWN) usages[count++] = PID_USAGE_ET_SAWTOOTH_DOWN; - if (impl->effect_support & SDL_HAPTIC_SPRING) usages[count++] = PID_USAGE_ET_SPRING; - if (impl->effect_support & SDL_HAPTIC_DAMPER) usages[count++] = PID_USAGE_ET_DAMPER; - if (impl->effect_support & SDL_HAPTIC_INERTIA) usages[count++] = PID_USAGE_ET_INERTIA; - if (impl->effect_support & SDL_HAPTIC_FRICTION) usages[count++] = PID_USAGE_ET_FRICTION; - if (impl->effect_support & SDL_HAPTIC_CONSTANT) usages[count++] = PID_USAGE_ET_CONSTANT_FORCE; - if (impl->effect_support & SDL_HAPTIC_RAMP) usages[count++] = PID_USAGE_ET_RAMP; + if (force || (impl->effect_support & SDL_HAPTIC_SINE)) usages[count++] = PID_USAGE_ET_SINE; + if (force || (impl->effect_support & SDL_HAPTIC_TRIANGLE)) usages[count++] = PID_USAGE_ET_TRIANGLE; + if (force || (impl->effect_support & SDL_HAPTIC_SAWTOOTHUP)) usages[count++] = PID_USAGE_ET_SAWTOOTH_UP; + if (force || (impl->effect_support & SDL_HAPTIC_SAWTOOTHDOWN)) usages[count++] = PID_USAGE_ET_SAWTOOTH_DOWN; + if (force || (impl->effect_support & SDL_HAPTIC_SPRING)) usages[count++] = PID_USAGE_ET_SPRING; + if (force || (impl->effect_support & SDL_HAPTIC_DAMPER)) usages[count++] = PID_USAGE_ET_DAMPER; + if (force || (impl->effect_support & SDL_HAPTIC_INERTIA)) usages[count++] = PID_USAGE_ET_INERTIA; + if (force || (impl->effect_support & SDL_HAPTIC_FRICTION)) usages[count++] = PID_USAGE_ET_FRICTION; + if (force || (impl->effect_support & SDL_HAPTIC_CONSTANT)) usages[count++] = PID_USAGE_ET_CONSTANT_FORCE; + if (force || (impl->effect_support & SDL_HAPTIC_RAMP)) usages[count++] = PID_USAGE_ET_RAMP; if (!hid_device_add_physical(&impl->unix_device, usages, count)) return FALSE; @@ -384,7 +384,7 @@ static NTSTATUS build_joystick_report_descriptor(struct unix_device *iface) if (!hid_device_end_input_report(iface)) return STATUS_NO_MEMORY; - if (!descriptor_add_haptic(impl)) + if (!descriptor_add_haptic(impl, physical_usage.Usage == HID_USAGE_SIMULATION_AUTOMOBILE_SIMULATION_DEVICE)) return STATUS_NO_MEMORY; if (!hid_device_end_report_descriptor(iface)) @@ -438,7 +438,7 @@ static NTSTATUS build_controller_report_descriptor(struct unix_device *iface) if (!hid_device_end_input_report(iface)) return STATUS_NO_MEMORY; - if (!descriptor_add_haptic(impl)) + if (!descriptor_add_haptic(impl, FALSE)) return STATUS_NO_MEMORY; if (!hid_device_end_report_descriptor(iface)) From 8da1014c459c2445529056695a146dd3242b8e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 11 Oct 2021 10:31:14 +0200 Subject: [PATCH 0238/2777] server: Introduce new set_thread_priority helper. --- server/thread.c | 44 +++++++++++++++++++++++++++++++------------- server/thread.h | 1 + 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/server/thread.c b/server/thread.c index 165393293de..07fdbf96586 100644 --- a/server/thread.c +++ b/server/thread.c @@ -632,25 +632,39 @@ affinity_t get_thread_affinity( struct thread *thread ) #define THREAD_PRIORITY_REALTIME_HIGHEST 6 #define THREAD_PRIORITY_REALTIME_LOWEST -7 +int set_thread_priority( struct thread *thread, int priority_class, int priority ) +{ + int max = THREAD_PRIORITY_HIGHEST; + int min = THREAD_PRIORITY_LOWEST; + if (priority_class == PROCESS_PRIOCLASS_REALTIME) + { + max = THREAD_PRIORITY_REALTIME_HIGHEST; + min = THREAD_PRIORITY_REALTIME_LOWEST; + } + if ((priority < min || priority > max) && + priority != THREAD_PRIORITY_IDLE && + priority != THREAD_PRIORITY_TIME_CRITICAL) + { + errno = EINVAL; + return -1; + } + + if (thread->process->priority == priority_class && + thread->priority == priority) + return 0; + thread->priority = priority; + + return 0; +} + /* set all information about a thread */ static void set_thread_info( struct thread *thread, const struct set_thread_info_request *req ) { if (req->mask & SET_THREAD_INFO_PRIORITY) { - int max = THREAD_PRIORITY_HIGHEST; - int min = THREAD_PRIORITY_LOWEST; - if (thread->process->priority == PROCESS_PRIOCLASS_REALTIME) - { - max = THREAD_PRIORITY_REALTIME_HIGHEST; - min = THREAD_PRIORITY_REALTIME_LOWEST; - } - if ((req->priority >= min && req->priority <= max) || - req->priority == THREAD_PRIORITY_IDLE || - req->priority == THREAD_PRIORITY_TIME_CRITICAL) - thread->priority = req->priority; - else - set_error( STATUS_INVALID_PARAMETER ); + if (set_thread_priority( thread, thread->process->priority, req->priority )) + file_set_error(); } if (req->mask & SET_THREAD_INFO_AFFINITY) { @@ -1453,7 +1467,10 @@ DECL_HANDLER(init_first_thread) if (!process->parent_id) process->affinity = current->affinity = get_thread_affinity( current ); else + { + set_thread_priority( current, current->process->priority, current->priority ); set_thread_affinity( current, current->affinity ); + } debug_level = max( debug_level, req->debug_level ); @@ -1484,6 +1501,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 ); set_thread_affinity( current, current->affinity ); reply->suspend = (current->suspend || current->process->suspend || current->context != NULL); diff --git a/server/thread.h b/server/thread.h index c7b58c3d63b..40e3ecc069f 100644 --- a/server/thread.h +++ b/server/thread.h @@ -121,6 +121,7 @@ extern void thread_cancel_apc( struct thread *thread, struct object *owner, enum extern int thread_add_inflight_fd( struct thread *thread, int client, int server ); extern int thread_get_inflight_fd( struct thread *thread, int client ); extern struct token *thread_get_impersonation_token( struct thread *thread ); +extern int set_thread_priority( struct thread *thread, int priority_class, int priority ); extern int set_thread_affinity( struct thread *thread, affinity_t affinity ); extern int suspend_thread( struct thread *thread ); extern int resume_thread( struct thread *thread ); From 54316f9c12cf151e652b7feaadf55eada33b3999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 17 Dec 2020 20:27:10 +0100 Subject: [PATCH 0239/2777] server: Update individual thread priority when process priority changes. --- server/process.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/server/process.c b/server/process.c index 8d6ed3f548b..899d8568a6a 100644 --- a/server/process.c +++ b/server/process.c @@ -1617,6 +1617,22 @@ DECL_HANDLER(get_process_vm_counters) release_object( process ); } +static void set_process_priority( struct process *process, int priority ) +{ + struct thread *thread; + + if (!process->running_threads) + { + set_error( STATUS_PROCESS_IS_TERMINATING ); + return; + } + + LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry ) + set_thread_priority( thread, priority, thread->priority ); + + process->priority = priority; +} + static void set_process_affinity( struct process *process, affinity_t affinity ) { struct thread *thread; @@ -1642,7 +1658,7 @@ DECL_HANDLER(set_process_info) if ((process = get_process_from_handle( req->handle, PROCESS_SET_INFORMATION ))) { - if (req->mask & SET_PROCESS_INFO_PRIORITY) process->priority = req->priority; + if (req->mask & SET_PROCESS_INFO_PRIORITY) set_process_priority( process, req->priority ); if (req->mask & SET_PROCESS_INFO_AFFINITY) set_process_affinity( process, req->affinity ); release_object( process ); } From 770ccc860b5ef8ad5b7b53d63d06cb4f33dc1c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 18 Dec 2020 14:43:00 +0100 Subject: [PATCH 0240/2777] server: Delay set_thread_priority until unix_tid is known. --- server/thread.c | 26 ++++++++++++++++++++++++++ server/thread.h | 1 + 2 files changed, 27 insertions(+) diff --git a/server/thread.c b/server/thread.c index 07fdbf96586..2cb45e2bf76 100644 --- a/server/thread.c +++ b/server/thread.c @@ -250,6 +250,7 @@ static inline void init_thread_structure( struct thread *thread ) thread->state = RUNNING; thread->exit_code = 0; thread->priority = 0; + thread->delay_priority = NULL; thread->suspend = 0; thread->dbg_hidden = 0; thread->desktop_users = 0; @@ -419,6 +420,9 @@ static void cleanup_thread( struct thread *thread ) { int i; + if (thread->delay_priority) remove_timeout_user( thread->delay_priority ); + thread->delay_priority = NULL; + if (thread->context) { thread->context->status = STATUS_ACCESS_DENIED; @@ -632,6 +636,27 @@ affinity_t get_thread_affinity( struct thread *thread ) #define THREAD_PRIORITY_REALTIME_HIGHEST 6 #define THREAD_PRIORITY_REALTIME_LOWEST -7 +static void apply_thread_priority( struct thread *thread, int priority_class, int priority, int delayed ); + +static void delayed_set_thread_priority( void *private ) +{ + struct thread *thread = private; + int priority_class = thread->process->priority, priority = thread->priority; + apply_thread_priority( thread, priority_class, priority, TRUE ); +} + +static void apply_thread_priority( struct thread *thread, int priority_class, int priority, int delayed ) +{ + if (!delayed && thread->delay_priority) remove_timeout_user( thread->delay_priority ); + thread->delay_priority = NULL; + + if (thread->unix_tid == -1) + { + thread->delay_priority = add_timeout_user( -TICKS_PER_SEC, delayed_set_thread_priority, thread ); + return; + } +} + int set_thread_priority( struct thread *thread, int priority_class, int priority ) { int max = THREAD_PRIORITY_HIGHEST; @@ -654,6 +679,7 @@ int set_thread_priority( struct thread *thread, int priority_class, int priority return 0; thread->priority = priority; + apply_thread_priority( thread, priority_class, priority, FALSE ); return 0; } diff --git a/server/thread.h b/server/thread.h index 40e3ecc069f..92cb3e8c31e 100644 --- a/server/thread.h +++ b/server/thread.h @@ -82,6 +82,7 @@ struct thread client_ptr_t entry_point; /* entry point (in client address space) */ affinity_t affinity; /* affinity mask */ int priority; /* priority level */ + struct timeout_user *delay_priority;/* delayed set_thread_priority */ int suspend; /* suspend count */ int dbg_hidden; /* hidden from debugger */ obj_handle_t desktop; /* desktop handle */ From 7aa2679cea3e6edb206da42d23d9d12cb0f1e937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 21 May 2021 21:54:39 +0200 Subject: [PATCH 0241/2777] ntdll: Set RLIMIT_NICE to its hard limit and inform the server. --- dlls/ntdll/unix/loader.c | 3 +++ dlls/ntdll/unix/server.c | 14 ++++++++++++++ server/process.h | 1 + server/protocol.def | 1 + server/thread.c | 7 +++++++ 5 files changed, 26 insertions(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index c46f109af71..7ece87338fc 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2548,6 +2548,9 @@ void __wine_main( int argc, char *argv[], char *envp[] ) #ifdef RLIMIT_AS set_max_limit( RLIMIT_AS ); #endif +#ifdef RLIMIT_NICE + set_max_limit( RLIMIT_NICE ); +#endif virtual_init(); init_environment( argc, argv, envp ); diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 56a110882ed..321b91d20e0 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -53,6 +53,9 @@ # include #endif #include +#ifdef HAVE_SYS_RESOURCE_H +# include +#endif #ifdef HAVE_SYS_SYSCALL_H # include #endif @@ -1455,6 +1458,8 @@ size_t server_init_process(void) struct sigaction sig_act; size_t info_size; DWORD pid, tid; + struct rlimit rlimit; + int nice_limit = 0; server_pid = -1; if (env_socket) @@ -1516,10 +1521,19 @@ size_t server_init_process(void) reply_pipe = init_thread_pipe(); +#ifdef RLIMIT_NICE + if (!getrlimit( RLIMIT_NICE, &rlimit )) + { + if (rlimit.rlim_cur <= 40) nice_limit = 20 - rlimit.rlim_cur; + else if (rlimit.rlim_cur == -1 /* RLIMIT_INFINITY */) nice_limit = -20; + } +#endif + SERVER_START_REQ( init_first_thread ) { req->unix_pid = getpid(); req->unix_tid = get_unix_tid(); + req->nice_limit = nice_limit; req->reply_fd = reply_pipe; req->wait_fd = ntdll_get_thread_data()->wait_fd[1]; req->debug_level = (TRACE_ON(server) != 0); diff --git a/server/process.h b/server/process.h index a0a071d8f88..d073e9e285f 100644 --- a/server/process.h +++ b/server/process.h @@ -50,6 +50,7 @@ struct process timeout_t sigkill_delay; /* delay before final SIGKILL */ unsigned short machine; /* client machine type */ int unix_pid; /* Unix pid for final SIGKILL */ + int nice_limit; /* RLIMIT_NICE of the process */ int exit_code; /* process exit code */ int running_threads; /* number of threads running in this process */ timeout_t start_time; /* absolute time at process start */ diff --git a/server/protocol.def b/server/protocol.def index 880ad794982..42eae1db9f3 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -941,6 +941,7 @@ typedef struct int debug_level; /* new debug level */ int reply_fd; /* fd for reply pipe */ int wait_fd; /* fd for blocking calls pipe */ + char nice_limit; /* RLIMIT_NICE of new thread */ @REPLY process_id_t pid; /* process id of the new thread's process */ thread_id_t tid; /* thread id of the new thread */ diff --git a/server/thread.c b/server/thread.c index 2cb45e2bf76..7efa00312bb 100644 --- a/server/thread.c +++ b/server/thread.c @@ -37,6 +37,12 @@ #define _WITH_CPU_SET_T #include #endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif #include "ntstatus.h" #define WIN32_NO_STATUS @@ -1489,6 +1495,7 @@ DECL_HANDLER(init_first_thread) current->unix_pid = process->unix_pid = req->unix_pid; current->unix_tid = req->unix_tid; + process->nice_limit = req->nice_limit; if (!process->parent_id) process->affinity = current->affinity = get_thread_affinity( current ); From 6ab575fe76edead60814afd2276e4c5309cee4cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 11 Oct 2021 10:33:12 +0200 Subject: [PATCH 0242/2777] server: Use setpriority to update thread niceness when safe. --- configure.ac | 10 ++++++++++ server/main.c | 1 + server/object.h | 4 ++++ server/thread.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+) diff --git a/configure.ac b/configure.ac index 89d39b91ae9..2bf35cc79e5 100644 --- a/configure.ac +++ b/configure.ac @@ -2063,6 +2063,16 @@ then AC_DEFINE(HAVE_SCHED_SETAFFINITY, 1, [Define to 1 if you have the `sched_setaffinity' function.]) fi +AC_CACHE_CHECK([for setpriority],wine_cv_have_setpriority, + AC_LINK_IFELSE([AC_LANG_PROGRAM( +[[#define _GNU_SOURCE +#include +#include ]], [[setpriority(0, 0, 0);]])],[wine_cv_have_setpriority=yes],[wine_cv_have_setpriority=no])) +if test "$wine_cv_have_setpriority" = "yes" +then + AC_DEFINE(HAVE_SETPRIORITY, 1, [Define to 1 if you have the `setpriority' function.]) +fi + dnl **** Check for types **** AC_C_INLINE diff --git a/server/main.c b/server/main.c index 1390d15bb88..7c635677205 100644 --- a/server/main.c +++ b/server/main.c @@ -237,6 +237,7 @@ int main( int argc, char *argv[] ) set_current_time(); init_signals(); init_directories( load_intl_file() ); + init_threading(); init_registry(); main_loop(); return 0; diff --git a/server/object.h b/server/object.h index c98e45125a0..86906942b77 100644 --- a/server/object.h +++ b/server/object.h @@ -279,6 +279,10 @@ extern struct object *get_directory_obj( struct process *process, obj_handle_t h extern int directory_link_name( struct object *obj, struct object_name *name, struct object *parent ); extern void init_directories( struct fd *intl_fd ); +/* thread functions */ + +extern void init_threading(void); + /* symbolic link functions */ extern struct object *create_root_symlink( struct object *root, const struct unicode_str *name, diff --git a/server/thread.c b/server/thread.c index 7efa00312bb..ebd15a38e6f 100644 --- a/server/thread.c +++ b/server/thread.c @@ -229,6 +229,23 @@ static const struct fd_ops thread_fd_ops = }; static struct list thread_list = LIST_INIT(thread_list); +static int nice_limit; + +void init_threading(void) +{ +#ifdef RLIMIT_NICE + struct rlimit rlimit; + if (!getrlimit( RLIMIT_NICE, &rlimit )) + { + rlimit.rlim_cur = rlimit.rlim_max; + setrlimit( RLIMIT_NICE, &rlimit ); + if (rlimit.rlim_max <= 40) nice_limit = 20 - rlimit.rlim_max; + else if (rlimit.rlim_max == -1) nice_limit = -20; + if (nice_limit >= 0) fprintf(stderr, "wine: RLIMIT_NICE is <= 20, unable to use setpriority safely\n"); + } +#endif + if (nice_limit < 0) fprintf(stderr, "wine: Using setpriority to control niceness in the [%d,%d] range\n", nice_limit, -nice_limit ); +} /* initialize the structure for a newly allocated thread */ static inline void init_thread_structure( struct thread *thread ) @@ -639,6 +656,21 @@ affinity_t get_thread_affinity( struct thread *thread ) return mask; } +static int get_base_priority( int priority_class, int priority ) +{ + static const int class_offsets[] = { 4, 8, 13, 24, 6, 10 }; + assert(priority_class <= ARRAY_SIZE(class_offsets)); + if (priority == THREAD_PRIORITY_IDLE) return (priority_class == PROCESS_PRIOCLASS_REALTIME ? 16 : 1); + else if (priority == THREAD_PRIORITY_TIME_CRITICAL) return (priority_class == PROCESS_PRIOCLASS_REALTIME ? 31 : 15); + else return class_offsets[priority_class - 1] + priority; +} + +static int get_unix_niceness( int base_priority, int limit ) +{ + int min = -limit, max = limit, range = max - min; + return min + (base_priority - 1) * range / 14; +} + #define THREAD_PRIORITY_REALTIME_HIGHEST 6 #define THREAD_PRIORITY_REALTIME_LOWEST -7 @@ -653,6 +685,8 @@ static void delayed_set_thread_priority( void *private ) static void apply_thread_priority( struct thread *thread, int priority_class, int priority, int delayed ) { + int niceness, limit = min( nice_limit, thread->process->nice_limit ); + if (!delayed && thread->delay_priority) remove_timeout_user( thread->delay_priority ); thread->delay_priority = NULL; @@ -661,6 +695,21 @@ static void apply_thread_priority( struct thread *thread, int priority_class, in thread->delay_priority = add_timeout_user( -TICKS_PER_SEC, delayed_set_thread_priority, thread ); return; } + + /* FIXME: handle REALTIME class using SCHED_RR if possible, for now map it to HIGH */ + if (priority_class == PROCESS_PRIOCLASS_REALTIME) priority_class = PROCESS_PRIOCLASS_HIGH; + +#ifdef __linux__ +#ifdef HAVE_SETPRIORITY + if (limit < 0) + { + niceness = get_unix_niceness( get_base_priority( priority_class, priority ), limit ); + if (setpriority( PRIO_PROCESS, thread->unix_tid, niceness ) != 0) + fprintf( stderr, "wine: setpriority %d for pid %d failed: %d\n", niceness, thread->unix_tid, errno ); + return; + } +#endif +#endif } int set_thread_priority( struct thread *thread, int priority_class, int priority ) From 5ac10ba7e0c2576e5183241a3916a779bd411f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 18 Dec 2020 13:58:07 +0100 Subject: [PATCH 0243/2777] server: Check wineserver privileges on init with -20 niceness. --- server/thread.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/server/thread.c b/server/thread.c index ebd15a38e6f..70299636d9d 100644 --- a/server/thread.c +++ b/server/thread.c @@ -235,7 +235,13 @@ void init_threading(void) { #ifdef RLIMIT_NICE struct rlimit rlimit; - if (!getrlimit( RLIMIT_NICE, &rlimit )) +#endif +#ifdef HAVE_SETPRIORITY + if (setpriority( PRIO_PROCESS, getpid(), -20 ) == 0) nice_limit = -19; + setpriority( PRIO_PROCESS, getpid(), 0 ); +#endif +#ifdef RLIMIT_NICE + if (!nice_limit && !getrlimit( RLIMIT_NICE, &rlimit )) { rlimit.rlim_cur = rlimit.rlim_max; setrlimit( RLIMIT_NICE, &rlimit ); From 86ae771b8011d3e50aca9d5870d7a074bff72a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 28 Oct 2021 09:11:02 +0200 Subject: [PATCH 0244/2777] server: Clear the MOUSEEVENTF_(ABSOLUTE|VIRTUALDESK) flags. For rawinput messages, as user32 is currently only expecting relative motion. --- server/queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/queue.c b/server/queue.c index 833a4b31b4f..32396ea9f6c 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1849,7 +1849,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons msg_data = &raw_msg.data; msg_data->info = input->mouse.info; msg_data->size = sizeof(*msg_data); - msg_data->flags = flags; + msg_data->flags = flags & ~(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK); msg_data->rawinput.type = RIM_TYPEMOUSE; msg_data->rawinput.mouse.x = x - desktop->cursor.x; msg_data->rawinput.mouse.y = y - desktop->cursor.y; From 8d3c002b14beb50aca80f48e80c96bb2e26458e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Oct 2021 11:26:43 +0200 Subject: [PATCH 0245/2777] user32: Add support for absolute rawinput messages. --- dlls/win32u/rawinput.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/rawinput.c b/dlls/win32u/rawinput.c index 737facfe05e..f27bc092102 100644 --- a/dlls/win32u/rawinput.c +++ b/dlls/win32u/rawinput.c @@ -96,7 +96,9 @@ static bool rawinput_from_hardware_message( RAWINPUT *rawinput, const struct har rawinput->header.hDevice = WINE_MOUSE_HANDLE; rawinput->header.wParam = 0; - rawinput->data.mouse.usFlags = MOUSE_MOVE_RELATIVE; + rawinput->data.mouse.usFlags = msg_data->flags & MOUSEEVENTF_ABSOLUTE ? MOUSE_MOVE_ABSOLUTE : MOUSE_MOVE_RELATIVE; + if (msg_data->flags & MOUSEEVENTF_VIRTUALDESK) rawinput->data.mouse.usFlags |= MOUSE_VIRTUAL_DESKTOP; + rawinput->data.mouse.usButtonFlags = 0; rawinput->data.mouse.usButtonData = 0; for (i = 1; i < ARRAY_SIZE(button_flags); ++i) From 31da9dc9a68b5a1724f293931df85b1912e9fc1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Oct 2021 11:22:04 +0200 Subject: [PATCH 0246/2777] server: Stop enforcing relative rawinput mouse positions. --- server/queue.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/queue.c b/server/queue.c index 32396ea9f6c..ab2e9e4b3e4 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1849,10 +1849,10 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons msg_data = &raw_msg.data; msg_data->info = input->mouse.info; msg_data->size = sizeof(*msg_data); - msg_data->flags = flags & ~(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK); + msg_data->flags = flags; msg_data->rawinput.type = RIM_TYPEMOUSE; - msg_data->rawinput.mouse.x = x - desktop->cursor.x; - msg_data->rawinput.mouse.y = y - desktop->cursor.y; + msg_data->rawinput.mouse.x = (flags & MOUSEEVENTF_MOVE) ? input->mouse.x : 0; + msg_data->rawinput.mouse.y = (flags & MOUSEEVENTF_MOVE) ? input->mouse.y : 0; msg_data->rawinput.mouse.data = input->mouse.data; enum_processes( queue_rawinput_message, &raw_msg ); From 3cb0528d226ff6e2b5d56058fb93e1403dffe5ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 24 Oct 2021 16:27:40 +0200 Subject: [PATCH 0247/2777] winex11.drv: Simplify XInput2 valuator lookup. Valuator names aren't well specified, and although they usually are Rel X/Y or Abs X/Y, there are cases where the X/Y names are something else. Just assume that the first two valuators are the X/Y axes, as it seems to be generally the case. --- dlls/winex11.drv/mouse.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 5e37a842b5a..dad79249f4a 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -321,26 +321,25 @@ void X11DRV_InitMouse( Display *display ) /*********************************************************************** * update_relative_valuators */ -static void update_relative_valuators(XIAnyClassInfo **valuators, int n_valuators) +static void update_relative_valuators( XIAnyClassInfo **classes, int num_classes ) { struct x11drv_thread_data *thread_data = x11drv_thread_data(); - int i; + XIValuatorClassInfo *valuator; thread_data->x_valuator.number = -1; thread_data->y_valuator.number = -1; - for (i = 0; i < n_valuators; i++) + while (num_classes--) { - XIValuatorClassInfo *class = (XIValuatorClassInfo *)valuators[i]; - if (valuators[i]->type != XIValuatorClass) continue; - if (class->label == x11drv_atom( Rel_X ) || - (!class->label && class->number == 0 && class->mode == XIModeRelative)) - thread_data->x_valuator = *class; - else if (class->label == x11drv_atom( Rel_Y ) || - (!class->label && class->number == 1 && class->mode == XIModeRelative)) - thread_data->y_valuator = *class; + valuator = (XIValuatorClassInfo *)classes[num_classes]; + if (classes[num_classes]->type != XIValuatorClass) continue; + if (valuator->number == 0 && valuator->mode == XIModeRelative) thread_data->x_valuator = *valuator; + if (valuator->number == 1 && valuator->mode == XIModeRelative) thread_data->y_valuator = *valuator; } + if (thread_data->x_valuator.number < 0 || thread_data->y_valuator.number < 0) + WARN( "X/Y axis valuators not found, ignoring RawMotion events\n" ); + thread_data->x_valuator.value = 0; thread_data->y_valuator.value = 0; } From 97e212ac9017dadffb4a1b8138ac41e0927cc164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 7 Jan 2022 10:39:14 +0100 Subject: [PATCH 0248/2777] winex11.drv: Add support for absolute RawMotion events. --- dlls/winex11.drv/mouse.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index dad79249f4a..c5fffcd7442 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -333,12 +333,18 @@ static void update_relative_valuators( XIAnyClassInfo **classes, int num_classes { valuator = (XIValuatorClassInfo *)classes[num_classes]; if (classes[num_classes]->type != XIValuatorClass) continue; - if (valuator->number == 0 && valuator->mode == XIModeRelative) thread_data->x_valuator = *valuator; - if (valuator->number == 1 && valuator->mode == XIModeRelative) thread_data->y_valuator = *valuator; + if (valuator->number == 0) thread_data->x_valuator = *valuator; + if (valuator->number == 1) thread_data->y_valuator = *valuator; } if (thread_data->x_valuator.number < 0 || thread_data->y_valuator.number < 0) WARN( "X/Y axis valuators not found, ignoring RawMotion events\n" ); + else if (thread_data->x_valuator.mode != thread_data->y_valuator.mode) + { + WARN( "Relative/Absolute mismatch between X/Y axis, ignoring RawMotion events\n" ); + thread_data->x_valuator.number = -1; + thread_data->y_valuator.number = -1; + } thread_data->x_valuator.value = 0; thread_data->y_valuator.value = 0; @@ -1882,7 +1888,15 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input ) if (!event->valuators.mask_len) return FALSE; if (event->deviceid != thread_data->xi2_core_pointer) return FALSE; - virtual_rect = NtUserGetVirtualScreenRect(); + if (x->mode == XIModeRelative && y->mode == XIModeRelative) + input->u.mi.dwFlags &= ~(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK); + else if (x->mode == XIModeAbsolute && y->mode == XIModeAbsolute) + input->u.mi.dwFlags |= MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK; + else + FIXME( "Unsupported relative/absolute X/Y axis mismatch\n." ); + + if (input->u.mi.dwFlags & MOUSEEVENTF_VIRTUALDESK) SetRect( &virtual_rect, 0, 0, 65535, 65535 ); + else virtual_rect = NtUserGetVirtualScreenRect(); if (x->max <= x->min) x_scale = 1; else x_scale = (virtual_rect.right - virtual_rect.left) / (x->max - x->min); @@ -1895,12 +1909,14 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input ) if (i == x->number) { x_value = *values; - x->value += x_value * x_scale; + if (x->mode == XIModeRelative) x->value += x_value * x_scale; + else x->value = (x_value - x->min) * x_scale; } if (i == y->number) { y_value = *values; - y->value += y_value * y_scale; + if (y->mode == XIModeRelative) y->value += y_value * y_scale; + else y->value = (y_value - y->min) * y_scale; } values++; } @@ -1914,7 +1930,7 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input ) x->value -= input->u.mi.dx; y->value -= input->u.mi.dy; - if (!input->u.mi.dx && !input->u.mi.dy) + if (!(input->u.mi.dwFlags & MOUSEEVENTF_ABSOLUTE) && !input->u.mi.dx && !input->u.mi.dy) { TRACE( "accumulating motion\n" ); return FALSE; From 56d416c496aa2b500a96c2523933e2e8df874a88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Oct 2021 20:57:55 +0200 Subject: [PATCH 0249/2777] user32: Add support for sending and receiving WM_POINTER* messages. CW-Bug-Id: #18214 --- dlls/user32/misc.c | 3 ++- dlls/win32u/message.c | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/dlls/user32/misc.c b/dlls/user32/misc.c index 497d40e9dc6..1087bdbbd21 100644 --- a/dlls/user32/misc.c +++ b/dlls/user32/misc.c @@ -497,7 +497,8 @@ BOOL WINAPI GetPointerType(UINT32 id, POINTER_INPUT_TYPE *type) return FALSE; } - *type = PT_MOUSE; + if (id == 1) *type = PT_MOUSE; + else *type = PT_TOUCH; return TRUE; } diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index a43be558ef4..cf15c774706 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1452,6 +1452,16 @@ static void send_parent_notify( HWND hwnd, WORD event, WORD idChild, POINT pt ) } } + +static BOOL process_pointer_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data ) +{ + msg->lParam = MAKELONG( msg_data->rawinput.mouse.x, msg_data->rawinput.mouse.y ); + msg->wParam = msg_data->rawinput.mouse.data; + msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt ); + return TRUE; +} + + /*********************************************************************** * process_keyboard_message * @@ -1768,6 +1778,9 @@ static BOOL process_hardware_message( MSG *msg, UINT hw_id, const struct hardwar if (msg->message == WM_INPUT || msg->message == WM_INPUT_DEVICE_CHANGE) ret = process_rawinput_message( msg, hw_id, msg_data ); + else if (msg->message == WM_POINTERDOWN || msg->message == WM_POINTERUP || + msg->message == WM_POINTERUPDATE) + ret = process_pointer_message( msg, hw_id, msg_data ); else if (is_keyboard_message( msg->message )) ret = process_keyboard_message( msg, hw_id, hwnd_filter, first, last, remove ); else if (is_mouse_message( msg->message )) @@ -2640,6 +2653,9 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r { case WM_INPUT: case WM_INPUT_DEVICE_CHANGE: + case WM_POINTERDOWN: + case WM_POINTERUP: + case WM_POINTERUPDATE: req->input.hw.rawinput.type = rawinput->header.dwType; switch (rawinput->header.dwType) { From 92adf630fcc9b87477054490859a915d7ccdd7e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Oct 2021 14:47:24 +0200 Subject: [PATCH 0250/2777] user32: Translate WM_POINTER* messages to WM_TOUCH in DefWindowProc. CW-Bug-Id: #18214 --- dlls/user32/input.c | 9 --------- dlls/user32/user32.spec | 2 +- dlls/win32u/defwnd.c | 32 ++++++++++++++++++++++++++++++++ dlls/win32u/input.c | 11 +++++++++++ dlls/win32u/syscall.c | 1 + dlls/win32u/win32u.spec | 2 +- include/ntuser.h | 1 + 7 files changed, 47 insertions(+), 11 deletions(-) diff --git a/dlls/user32/input.c b/dlls/user32/input.c index c5387cf9212..66a66b8f0d3 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -674,15 +674,6 @@ BOOL WINAPI GetTouchInputInfo( HTOUCHINPUT handle, UINT count, TOUCHINPUT *ptr, return FALSE; } -/********************************************************************** - * IsTouchWindow (USER32.@) - */ -BOOL WINAPI IsTouchWindow( HWND hwnd, ULONG *flags ) -{ - FIXME( "hwnd %p, flags %p stub!\n", hwnd, flags ); - return FALSE; -} - /***************************************************************************** * RegisterTouchWindow (USER32.@) */ diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 1628c7ca74a..133cb31a449 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -478,7 +478,7 @@ @ stdcall IsProcessDPIAware() @ stdcall IsRectEmpty(ptr) # @ stub IsServerSideWindow -@ stdcall IsTouchWindow(long ptr) +@ stdcall IsTouchWindow(long ptr) NtUserIsTouchWindow @ stdcall IsValidDpiAwarenessContext(long) @ stdcall IsWinEventHookInstalled(long) @ stdcall IsWindow(long) diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c index 85cdc61be1c..76779974cfb 100644 --- a/dlls/win32u/defwnd.c +++ b/dlls/win32u/defwnd.c @@ -30,6 +30,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); +#define WINE_MOUSE_HANDLE ((HANDLE)1) +#define WINE_KEYBOARD_HANDLE ((HANDLE)2) #define DRAG_FILE 0x454c4946 @@ -2943,6 +2945,36 @@ LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, 0, NtUserSendMessage, ansi ); } break; + + case WM_POINTERDOWN: + case WM_POINTERUP: + case WM_POINTERUPDATE: + { + TOUCHINPUT touchinput; + + if (!NtUserIsTouchWindow( hwnd, NULL )) return 0; + touchinput.x = LOWORD( lparam ) * 100; + touchinput.y = HIWORD( lparam ) * 100; + touchinput.hSource = WINE_MOUSE_HANDLE; + touchinput.dwID = GET_POINTERID_WPARAM( wparam ); + touchinput.dwFlags = TOUCHEVENTF_NOCOALESCE | TOUCHEVENTF_PALM; + if (msg == WM_POINTERDOWN) touchinput.dwFlags |= TOUCHEVENTF_DOWN; + if (msg == WM_POINTERUP) touchinput.dwFlags |= TOUCHEVENTF_UP; + if (msg == WM_POINTERUPDATE) touchinput.dwFlags |= TOUCHEVENTF_MOVE; + if (IS_POINTER_PRIMARY_WPARAM( wparam )) touchinput.dwFlags |= TOUCHEVENTF_PRIMARY; + touchinput.dwMask = 0; + touchinput.dwTime = NtGetTickCount(); + touchinput.dwExtraInfo = 0; + touchinput.cxContact = 0; + touchinput.cyContact = 0; + + send_message( hwnd, WM_TOUCH, MAKELONG( 1, 0 ), (LPARAM)&touchinput ); + break; + } + + case WM_TOUCH: + /* FIXME: CloseTouchInputHandle( (HTOUCHINPUT)lparam ); */ + return 0; } return result; diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 3f8b960215b..22f4000d16c 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2154,6 +2154,17 @@ void toggle_caret( HWND hwnd ) if (ret && !hidden) display_caret( hwnd, &r ); } + +/********************************************************************** + * NtUserIsTouchWindow (win32u.@) + */ +BOOL WINAPI NtUserIsTouchWindow( HWND hwnd, ULONG *flags ) +{ + FIXME( "hwnd %p, flags %p stub!\n", hwnd, flags ); + return FALSE; +} + + HWND get_shell_window(void) { HWND hwnd = 0; diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index 32812a3d881..1735b0c8133 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -221,6 +221,7 @@ static void * const syscalls[] = NtUserInvalidateRect, NtUserInvalidateRgn, NtUserIsClipboardFormatAvailable, + NtUserIsTouchWindow, NtUserKillTimer, NtUserLockWindowUpdate, NtUserLogicalToPerMonitorDPIPhysicalPoint, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index c3ed3c0559a..f800f7408ae 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1056,7 +1056,7 @@ @ stub NtUserIsNonClientDpiScalingEnabled @ stub NtUserIsResizeLayoutSynchronizationEnabled @ stub NtUserIsTopLevelWindow -@ stub NtUserIsTouchWindow +@ stdcall -syscall NtUserIsTouchWindow(long ptr) @ stub NtUserIsWindowBroadcastingDpiToChildren @ stub NtUserIsWindowGDIScaledDpiMessageEnabled @ stdcall -syscall NtUserKillTimer(long long) diff --git a/include/ntuser.h b/include/ntuser.h index 7bbe7037f20..2619f8d6d56 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -791,6 +791,7 @@ INT WINAPI NtUserInternalGetWindowText( HWND hwnd, WCHAR *text, INT count ); BOOL WINAPI NtUserIsClipboardFormatAvailable( UINT format ); BOOL WINAPI NtUserInvalidateRect( HWND hwnd, const RECT *rect, BOOL erase ); BOOL WINAPI NtUserInvalidateRgn( HWND hwnd, HRGN hrgn, BOOL erase ); +BOOL WINAPI NtUserIsTouchWindow( HWND hwnd, ULONG *flags ); BOOL WINAPI NtUserKillTimer( HWND hwnd, UINT_PTR id ); BOOL WINAPI NtUserLockWindowUpdate( HWND hwnd ); BOOL WINAPI NtUserLogicalToPerMonitorDPIPhysicalPoint( HWND hwnd, POINT *pt ); From ab2f626ed6c6fcf5fc0879b5c22fed4f62a2b6e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Oct 2021 20:58:19 +0200 Subject: [PATCH 0251/2777] server: Add support for WM_POINTER* dispatching. CW-Bug-Id: #18214 server: Keep desktop cursor position updated while touch is set. CW-Bug-Id: #19994 --- server/queue.c | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/server/queue.c b/server/queue.c index ab2e9e4b3e4..9b0f90c7bf7 100644 --- a/server/queue.c +++ b/server/queue.c @@ -576,7 +576,9 @@ static inline int filter_contains_hw_range( unsigned int first, unsigned int las static inline int get_hardware_msg_bit( struct message *msg ) { if (msg->msg == WM_INPUT_DEVICE_CHANGE || msg->msg == WM_INPUT) return QS_RAWINPUT; - if (msg->msg == WM_MOUSEMOVE || msg->msg == WM_NCMOUSEMOVE) return QS_MOUSEMOVE; + if (msg->msg == WM_MOUSEMOVE || msg->msg == WM_NCMOUSEMOVE || + msg->msg == WM_POINTERDOWN || msg->msg == WM_POINTERUP || + msg->msg == WM_POINTERUPDATE) return QS_MOUSEMOVE; if (is_keyboard_msg( msg )) return QS_KEY; return QS_MOUSEBUTTON; } @@ -1533,7 +1535,9 @@ static user_handle_t find_hardware_message_window( struct desktop *desktop, stru *thread = NULL; *msg_code = msg->msg; - if (msg->msg == WM_INPUT || msg->msg == WM_INPUT_DEVICE_CHANGE) + if (msg->msg == WM_INPUT || msg->msg == WM_INPUT_DEVICE_CHANGE || + msg->msg == WM_POINTERDOWN || msg->msg == WM_POINTERUP || + msg->msg == WM_POINTERUPDATE) { if (!(win = msg->win) && input) win = input->focus; } @@ -1601,6 +1605,14 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg if (msg->wparam == VK_SHIFT || msg->wparam == VK_LSHIFT || msg->wparam == VK_RSHIFT) msg->lparam &= ~(KF_EXTENDED << 16); } + else if (msg->msg == WM_POINTERDOWN || msg->msg == WM_POINTERUP || msg->msg == WM_POINTERUPDATE) + { + if (IS_POINTER_PRIMARY_WPARAM( msg_data->rawinput.mouse.data )) + { + prepend_cursor_history( msg->x, msg->y, msg->time, msg_data->info ); + if (update_desktop_cursor_pos( desktop, msg->x, msg->y )) always_queue = 1; + } + } else if (msg->msg != WM_INPUT && msg->msg != WM_INPUT_DEVICE_CHANGE) { if (msg->msg == WM_MOUSEMOVE) @@ -2075,14 +2087,28 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ return; } + if (input->hw.msg == WM_POINTERDOWN || input->hw.msg == WM_POINTERUP || + input->hw.msg == WM_POINTERUPDATE) + source.device = IMDT_TOUCH; + if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return; + if (input->hw.msg == WM_POINTERDOWN || input->hw.msg == WM_POINTERUP || + input->hw.msg == WM_POINTERUPDATE) + { + msg_data = msg->data; + msg_data->info = 0; + msg_data->size = sizeof(*msg_data); + msg_data->flags = input->hw.lparam; + msg_data->rawinput = input->hw.rawinput; + } + msg->win = get_user_full_handle( win ); msg->msg = input->hw.msg; msg->wparam = 0; msg->lparam = input->hw.lparam; - msg->x = desktop->cursor.x; - msg->y = desktop->cursor.y; + msg->x = input->hw.rawinput.mouse.x; + msg->y = input->hw.rawinput.mouse.y; queue_hardware_message( desktop, msg, 1 ); } @@ -2215,7 +2241,9 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user data->hw_id = msg->unique_id; set_reply_data( msg->data, msg->data_size ); - if ((msg->msg == WM_INPUT || msg->msg == WM_INPUT_DEVICE_CHANGE) && (flags & PM_REMOVE)) + if ((msg->msg == WM_INPUT || msg->msg == WM_INPUT_DEVICE_CHANGE || + msg->msg == WM_POINTERDOWN || msg->msg == WM_POINTERUP || + msg->msg == WM_POINTERUPDATE) && (flags & PM_REMOVE)) release_hardware_message( current->queue, data->hw_id ); return 1; } From d48690fb3c81dbdde4ed12eb12a0a24f314a7378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Oct 2021 16:11:24 +0200 Subject: [PATCH 0252/2777] winex11.drv: Select XI_RawTouch* input and translate to WM_POINTER*. CW-Bug-Id: #18214 winex11.drv: Only send WM_POINTER messages from the desktop rawinput-only thread. Instead of sending duplicate messages from any thread using XInput2, for instance when cursor is clipped. --- dlls/winex11.drv/event.c | 3 ++ dlls/winex11.drv/mouse.c | 81 ++++++++++++++++++++++++++++++++++++--- dlls/winex11.drv/x11drv.h | 2 + 3 files changed, 81 insertions(+), 5 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 6343e507dd6..ef1d6aa534f 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -243,6 +243,9 @@ static Bool filter_event( Display *display, XEvent *event, char *arg ) case XI_RawButtonRelease: return (mask & QS_MOUSEBUTTON) != 0; case XI_RawMotion: + case XI_RawTouchBegin: + case XI_RawTouchUpdate: + case XI_RawTouchEnd: return (mask & QS_INPUT) != 0; case XI_DeviceChanged: return (mask & (QS_INPUT|QS_MOUSEBUTTON)) != 0; diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index c5fffcd7442..ce5d6f4c3a7 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -358,7 +358,7 @@ void X11DRV_XInput2_Init(void) { #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H struct x11drv_thread_data *data = x11drv_thread_data(); - int major = 2, minor = 1; + int major = 2, minor = 2; if (xinput2_available && pXIQueryVersion( data->display, &major, &minor ) == Success && pXIGetClientPointer( data->display, None, &data->xi2_core_pointer )) @@ -366,7 +366,7 @@ void X11DRV_XInput2_Init(void) else { data->xi2_core_pointer = 0; - WARN( "XInput 2.1 not available\n" ); + WARN( "XInput 2.2 not available\n" ); } #endif } @@ -399,7 +399,13 @@ void X11DRV_XInput2_Enable( Display *display, Window window, long event_mask ) if (event_mask & PointerMotionMask) { XISetMask( mask_bits, XI_DeviceChanged ); - if (raw) XISetMask( mask_bits, XI_RawMotion ); + if (raw) + { + XISetMask( mask_bits, XI_RawMotion ); + XISetMask( mask_bits, XI_RawTouchBegin ); + XISetMask( mask_bits, XI_RawTouchUpdate ); + XISetMask( mask_bits, XI_RawTouchEnd ); + } } if (event_mask & ButtonPressMask) { @@ -1891,7 +1897,7 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input ) if (x->mode == XIModeRelative && y->mode == XIModeRelative) input->u.mi.dwFlags &= ~(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK); else if (x->mode == XIModeAbsolute && y->mode == XIModeAbsolute) - input->u.mi.dwFlags |= MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK; + input->u.mi.dwFlags |= MOUSEEVENTF_ABSOLUTE; else FIXME( "Unsupported relative/absolute X/Y axis mismatch\n." ); @@ -1958,7 +1964,7 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) input.type = INPUT_MOUSE; input.u.mi.mouseData = 0; - input.u.mi.dwFlags = MOUSEEVENTF_MOVE; + input.u.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK; input.u.mi.time = x11drv_time_to_ticks( event->time ); input.u.mi.dwExtraInfo = 0; input.u.mi.dx = 0; @@ -2143,6 +2149,65 @@ void X11DRV_XInput2_Load(void) #endif } +static BOOL X11DRV_RawTouchEvent( XGenericEventCookie *xev ) +{ + struct x11drv_thread_data *thread_data = x11drv_thread_data(); + XIRawEvent *event = xev->data; + RAWINPUT rawinput = + { + .header = + { + .dwType = RIM_TYPEMOUSE, + .dwSize = offsetof(RAWINPUT, data) + sizeof(RAWMOUSE), + .hDevice = ULongToHandle(1), /* WINE_MOUSE_HANDLE */ + .wParam = RIM_INPUT, + }, + }; + INPUT input = + { + .type = INPUT_MOUSE, + }; + int flags = 0; + POINT pos; + + if (!thread_data->xi2_rawinput_only) return FALSE; + if (!map_raw_event_coords( event, &input )) return FALSE; + if (!(input.u.mi.dwFlags & MOUSEEVENTF_ABSOLUTE)) return FALSE; + pos.x = input.u.mi.dx; + pos.y = input.u.mi.dy; + + flags = POINTER_MESSAGE_FLAG_INRANGE | POINTER_MESSAGE_FLAG_INCONTACT; + if (!thread_data->xi2_active_touches) thread_data->xi2_primary_touchid = event->detail; + if (thread_data->xi2_primary_touchid == event->detail) flags |= POINTER_MESSAGE_FLAG_PRIMARY; + + input.type = INPUT_HARDWARE; + switch (event->evtype) + { + case XI_RawTouchBegin: + input.u.hi.uMsg = WM_POINTERDOWN; + flags |= POINTER_MESSAGE_FLAG_NEW; + thread_data->xi2_active_touches++; + TRACE("XI_RawTouchBegin detail %u pos %dx%d, flags %#x\n", event->detail, (int)pos.x, (int)pos.y, flags); + break; + case XI_RawTouchEnd: + input.u.hi.uMsg = WM_POINTERUP; + thread_data->xi2_active_touches--; + TRACE("XI_RawTouchEnd detail %u pos %dx%d, flags %#x\n", event->detail, (int)pos.x, (int)pos.y, flags); + break; + case XI_RawTouchUpdate: + input.u.hi.uMsg = WM_POINTERUPDATE; + TRACE("XI_RawTouchUpdate detail %u pos %dx%d, flags %#x\n", event->detail, (int)pos.x, (int)pos.y, flags); + break; + } + + rawinput.data.mouse.usFlags = 0; + rawinput.data.mouse.ulRawButtons = MAKELONG( event->detail, flags ); + rawinput.data.mouse.lLastX = pos.x; + rawinput.data.mouse.lLastY = pos.y; + + __wine_send_input( 0, &input, &rawinput ); + return TRUE; +} /*********************************************************************** * X11DRV_GenericEvent @@ -2172,6 +2237,12 @@ BOOL X11DRV_GenericEvent( HWND hwnd, XEvent *xev ) case XI_ButtonRelease: return X11DRV_XIDeviceEvent( event->data ); + case XI_RawTouchBegin: + case XI_RawTouchUpdate: + case XI_RawTouchEnd: + ret = X11DRV_RawTouchEvent( event ); + break; + default: TRACE( "Unhandled event %#x\n", event->evtype ); break; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 1e7887e2aab..3e2493a94e3 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -396,6 +396,8 @@ struct x11drv_thread_data XIValuatorClassInfo y_valuator; int xi2_core_pointer; /* XInput2 core pointer id */ int xi2_rawinput_only; + int xi2_active_touches; + int xi2_primary_touchid; #endif /* HAVE_X11_EXTENSIONS_XINPUT2_H */ }; From 98f99c467541496c61e381cb521eac0947a1212e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Nov 2022 08:36:32 +0100 Subject: [PATCH 0253/2777] winex11.drv: Send legacy and rawinput mouse messages on touch input. CW-Bug-Id: #18214 --- dlls/winex11.drv/mouse.c | 16 ++++++++++++++++ server/queue.c | 2 ++ 2 files changed, 18 insertions(+) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index ce5d6f4c3a7..4378b6bd295 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -2205,6 +2205,22 @@ static BOOL X11DRV_RawTouchEvent( XGenericEventCookie *xev ) rawinput.data.mouse.lLastX = pos.x; rawinput.data.mouse.lLastY = pos.y; + __wine_send_input( 0, &input, &rawinput ); + if (!(flags & POINTER_MESSAGE_FLAG_PRIMARY)) return TRUE; + + input.type = INPUT_MOUSE; + input.u.mi.mouseData = 0; + input.u.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; + if (event->evtype == XI_RawTouchBegin) input.u.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN; + if (event->evtype == XI_RawTouchEnd) input.u.mi.dwFlags |= MOUSEEVENTF_LEFTUP; + input.u.mi.time = x11drv_time_to_ticks( event->time ); + input.u.mi.dx = rawinput.data.mouse.lLastX; + input.u.mi.dy = rawinput.data.mouse.lLastY; + input.u.mi.dwExtraInfo = 0xff515700; + + rawinput.data.mouse.usFlags = input.u.mi.dwFlags; + rawinput.data.mouse.ulRawButtons = 0; + __wine_send_input( 0, &input, &rawinput ); return TRUE; } diff --git a/server/queue.c b/server/queue.c index 9b0f90c7bf7..970b8fa7001 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1822,6 +1822,8 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons WM_MOUSEHWHEEL /* 0x1000 = MOUSEEVENTF_HWHEEL */ }; + if ((input->mouse.info & 0xffffff00) == 0xff515700) source.origin = IMDT_TOUCH; + desktop->cursor.last_change = get_tick_count(); flags = input->mouse.flags; time = input->mouse.time; From 8be15106c79fa19dbe0b46696d190aaefbec9fae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Nov 2022 08:45:36 +0100 Subject: [PATCH 0254/2777] user32: Implement semi-stub touch input support. CW-Bug-Id: #18214 --- dlls/user32/input.c | 21 +++++++++------------ dlls/win32u/input.c | 21 +++++++++++++++++++-- dlls/win32u/ntuser_private.h | 1 + dlls/win32u/sysparams.c | 6 ++++++ dlls/win32u/win32u_private.h | 2 ++ include/ntuser.h | 2 ++ 6 files changed, 39 insertions(+), 14 deletions(-) diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 66a66b8f0d3..440737328e5 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -659,9 +659,8 @@ LRESULT WINAPI DefRawInputProc( RAWINPUT **data, INT data_count, UINT header_siz */ BOOL WINAPI CloseTouchInputHandle( HTOUCHINPUT handle ) { - FIXME( "handle %p stub!\n", handle ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + TRACE( "handle %p.\n", handle ); + return TRUE; } /***************************************************************************** @@ -669,9 +668,9 @@ BOOL WINAPI CloseTouchInputHandle( HTOUCHINPUT handle ) */ BOOL WINAPI GetTouchInputInfo( HTOUCHINPUT handle, UINT count, TOUCHINPUT *ptr, int size ) { - FIXME( "handle %p, count %u, ptr %p, size %u stub!\n", handle, count, ptr, size ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + TRACE( "handle %p, count %u, ptr %p, size %u.\n", handle, count, ptr, size ); + *ptr = *(TOUCHINPUT *)handle; + return TRUE; } /***************************************************************************** @@ -679,9 +678,8 @@ BOOL WINAPI GetTouchInputInfo( HTOUCHINPUT handle, UINT count, TOUCHINPUT *ptr, */ BOOL WINAPI RegisterTouchWindow( HWND hwnd, ULONG flags ) { - FIXME( "hwnd %p, flags %#lx stub!\n", hwnd, flags ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + TRACE( "hwnd %p, flags %#lx.\n", hwnd, flags ); + return NtUserCallTwoParam( (ULONG_PTR)hwnd, flags, NtUserCallTwoParam_RegisterTouchWindow ); } /***************************************************************************** @@ -689,9 +687,8 @@ BOOL WINAPI RegisterTouchWindow( HWND hwnd, ULONG flags ) */ BOOL WINAPI UnregisterTouchWindow( HWND hwnd ) { - FIXME( "hwnd %p stub!\n", hwnd ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + TRACE( "hwnd %p.\n", hwnd ); + return NtUserCallOneParam( (ULONG_PTR)hwnd, NtUserCallOneParam_UnregisterTouchWindow ); } /***************************************************************************** diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 22f4000d16c..93a455bd188 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2160,8 +2160,25 @@ void toggle_caret( HWND hwnd ) */ BOOL WINAPI NtUserIsTouchWindow( HWND hwnd, ULONG *flags ) { - FIXME( "hwnd %p, flags %p stub!\n", hwnd, flags ); - return FALSE; + DWORD win_flags = win_set_flags( hwnd, 0, 0 ); + TRACE( "hwnd %p, flags %p.\n", hwnd, flags ); + return (win_flags & WIN_IS_TOUCH) != 0; +} + + +BOOL register_touch_window( HWND hwnd, UINT flags ) +{ + DWORD win_flags = win_set_flags( hwnd, WIN_IS_TOUCH, 0 ); + TRACE( "hwnd %p, flags %#x.\n", hwnd, flags ); + return (win_flags & WIN_IS_TOUCH) == 0; +} + + +BOOL unregister_touch_window( HWND hwnd ) +{ + DWORD win_flags = win_set_flags( hwnd, 0, WIN_IS_TOUCH ); + TRACE( "hwnd %p.\n", hwnd ); + return (win_flags & WIN_IS_TOUCH) != 0; } diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 4e13822c6fb..80733d29e03 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -104,6 +104,7 @@ typedef struct tagWND #define WIN_NEEDS_SHOW_OWNEDPOPUP 0x0020 /* WM_SHOWWINDOW:SC_SHOW must be sent in the next ShowOwnedPopup call */ #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 WND_OTHER_PROCESS ((WND *)1) /* returned by get_win_ptr on unknown window handles */ #define WND_DESKTOP ((WND *)2) /* returned by get_win_ptr on the desktop window */ diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 2269193b7ff..5c16a4d9a91 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -5566,6 +5566,9 @@ ULONG_PTR WINAPI NtUserCallOneParam( ULONG_PTR arg, ULONG code ) process_layout = arg; return TRUE; + case NtUserCallOneParam_UnregisterTouchWindow: + return unregister_touch_window( (HWND)arg ); + /* temporary exports */ case NtUserGetDeskPattern: return get_entry( &entry_DESKPATTERN, 256, (WCHAR *)arg ); @@ -5598,6 +5601,9 @@ ULONG_PTR WINAPI NtUserCallTwoParam( ULONG_PTR arg1, ULONG_PTR arg2, ULONG code case NtUserCallTwoParam_MonitorFromRect: return HandleToUlong( monitor_from_rect( (const RECT *)arg1, arg2, get_thread_dpi() )); + case NtUserCallTwoParam_RegisterTouchWindow: + return register_touch_window( (HWND)arg1, arg2 ); + case NtUserCallTwoParam_SetCaretPos: return set_caret_pos( arg1, arg2 ); diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 96b1b7647fe..37ed4dbfb7f 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -274,6 +274,7 @@ extern DWORD get_input_state(void) DECLSPEC_HIDDEN; extern HWND get_progman_window(void) DECLSPEC_HIDDEN; extern HWND get_shell_window(void) DECLSPEC_HIDDEN; extern HWND get_taskman_window(void) DECLSPEC_HIDDEN; +extern BOOL register_touch_window( HWND hwnd, UINT flags ) DECLSPEC_HIDDEN; extern BOOL WINAPI release_capture(void) DECLSPEC_HIDDEN; extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) DECLSPEC_HIDDEN; extern BOOL set_caret_blink_time( unsigned int time ) DECLSPEC_HIDDEN; @@ -282,6 +283,7 @@ extern BOOL set_foreground_window( HWND hwnd, BOOL mouse ) DECLSPEC_HIDDEN; extern HWND set_progman_window( HWND hwnd ) DECLSPEC_HIDDEN; extern HWND set_taskman_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void toggle_caret( HWND hwnd ) DECLSPEC_HIDDEN; +extern BOOL unregister_touch_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void update_mouse_tracking_info( HWND hwnd ) DECLSPEC_HIDDEN; /* menu.c */ diff --git a/include/ntuser.h b/include/ntuser.h index 2619f8d6d56..c8e719620da 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -991,6 +991,7 @@ enum NtUserCallOneParam_ReplyMessage, NtUserCallOneParam_SetCaretBlinkTime, NtUserCallOneParam_SetProcessDefaultLayout, + NtUserCallOneParam_UnregisterTouchWindow, /* temporary exports */ NtUserGetDeskPattern, }; @@ -1117,6 +1118,7 @@ enum NtUserCallTwoParam_GetMonitorInfo, NtUserCallTwoParam_GetSystemMetricsForDpi, NtUserCallTwoParam_MonitorFromRect, + NtUserCallTwoParam_RegisterTouchWindow, NtUserCallTwoParam_SetCaretPos, NtUserCallTwoParam_SetIconParam, NtUserCallTwoParam_UnhookWindowsHook, From ee7cc66b3c4817c141f97ec5adc98cc40bc733d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 21 May 2021 14:57:46 +0200 Subject: [PATCH 0255/2777] user32: Implement rudimentary EnableMouseInPointer support. CW-Bug-Id: 18943 Squashed with: user32: Send EnableMouseInPointer emulated messages earlier. Emulating these messages should probably be done elsewhere. CW-Bug-Id: #21331 winex11.drv: Send legacy and rawinput mouse messages on touch input. CW-Bug-Id: #18214 user32: Better emulate EnableMouseInPointer messages. This is still not very good, but it better matches what Windows does, and it fixes mouse input with Return to Monkey Island. CW-Bug-Id: #21331 --- dlls/user32/input.c | 11 --------- dlls/user32/user32.spec | 2 +- dlls/win32u/input.c | 13 +++++++++++ dlls/win32u/message.c | 45 ++++++++++++++++++++++++++++++++++++ dlls/win32u/syscall.c | 1 + dlls/win32u/win32u.spec | 2 +- dlls/win32u/win32u_private.h | 1 + include/ntuser.h | 1 + 8 files changed, 63 insertions(+), 13 deletions(-) diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 440737328e5..e81fda9513e 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -495,17 +495,6 @@ BOOL WINAPI UnloadKeyboardLayout( HKL layout ) } -/*********************************************************************** - * EnableMouseInPointer (USER32.@) - */ -BOOL WINAPI EnableMouseInPointer(BOOL enable) -{ - FIXME("(%#x) stub\n", enable); - - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - static DWORD CALLBACK devnotify_window_callback(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header) { SendMessageTimeoutW(handle, WM_DEVICECHANGE, flags, (LPARAM)header, SMTO_ABORTIFHUNG, 2000, NULL); diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 133cb31a449..18c371ac2fe 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -205,7 +205,7 @@ @ stdcall EditWndProc(long long long long) EditWndProcA @ stdcall EmptyClipboard() NtUserEmptyClipboard @ stdcall EnableMenuItem(long long long) NtUserEnableMenuItem -@ stdcall EnableMouseInPointer(long) +@ stdcall EnableMouseInPointer(long) NtUserEnableMouseInPointer @ stdcall EnableNonClientDpiScaling(long) @ stdcall -import EnableScrollBar(long long long) NtUserEnableScrollBar @ stdcall EnableWindow(long long) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 93a455bd188..9531c9336ef 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -52,6 +52,8 @@ static const WCHAR keyboard_layouts_keyW[] = LONG global_key_state_counter = 0; +BOOL enable_mouse_in_pointer = FALSE; + /********************************************************************** * NtUserAttachThreadInput (win32u.@) @@ -2182,6 +2184,17 @@ BOOL unregister_touch_window( HWND hwnd ) } +/********************************************************************** + * NtUserEnableMouseInPointer (win32u.@) + */ +BOOL WINAPI NtUserEnableMouseInPointer( BOOL enable ) +{ + FIXME( "enable %u semi-stub!\n", enable ); + enable_mouse_in_pointer = TRUE; + return TRUE; +} + + HWND get_shell_window(void) { HWND hwnd = 0; diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index cf15c774706..472266adbfe 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1596,6 +1596,51 @@ static BOOL process_mouse_message( MSG *msg, UINT hw_id, ULONG_PTR extra_info, H msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt ); SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( msg->hwnd )); + if ((extra_info & 0xffffff00) != 0xff515700 && enable_mouse_in_pointer) + { + WORD flags = POINTER_MESSAGE_FLAG_PRIMARY; + DWORD message = 0; + + switch (msg->message) + { + case WM_MOUSEMOVE: + message = WM_POINTERUPDATE; + flags |= POINTER_MESSAGE_FLAG_INRANGE; + break; + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_XBUTTONDOWN: + message = WM_POINTERDOWN; + flags |= POINTER_MESSAGE_FLAG_INRANGE|POINTER_MESSAGE_FLAG_INCONTACT; + if (msg->message == WM_LBUTTONDOWN) flags |= POINTER_MESSAGE_FLAG_FIRSTBUTTON; + if (msg->message == WM_RBUTTONDOWN) flags |= POINTER_MESSAGE_FLAG_SECONDBUTTON; + if (msg->message == WM_MBUTTONDOWN) flags |= POINTER_MESSAGE_FLAG_THIRDBUTTON; + if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_LBUTTON) flags |= POINTER_MESSAGE_FLAG_FIRSTBUTTON; + if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_RBUTTON) flags |= POINTER_MESSAGE_FLAG_SECONDBUTTON; + if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_MBUTTON) flags |= POINTER_MESSAGE_FLAG_THIRDBUTTON; + if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_XBUTTON1) flags |= POINTER_MESSAGE_FLAG_FOURTHBUTTON; + if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_XBUTTON2) flags |= POINTER_MESSAGE_FLAG_FIFTHBUTTON; + break; + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case WM_XBUTTONUP: + message = WM_POINTERUP; + break; + case WM_MOUSEWHEEL: + message = WM_POINTERWHEEL; + flags = HIWORD( msg->wParam ); + break; + case WM_MOUSEHWHEEL: + message = WM_POINTERHWHEEL; + flags = HIWORD( msg->wParam ); + break; + } + + if (message) send_message( msg->hwnd, message, MAKELONG( 1, flags ), MAKELONG( msg->pt.x, msg->pt.y ) ); + } + /* FIXME: is this really the right place for this hook? */ event.message = msg->message; event.time = msg->time; diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index 1735b0c8133..6fbbedd628f 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -145,6 +145,7 @@ static void * const syscalls[] = NtUserDrawIconEx, NtUserEmptyClipboard, NtUserEnableMenuItem, + NtUserEnableMouseInPointer, NtUserEnableScrollBar, NtUserEndDeferWindowPosEx, NtUserEndMenu, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index f800f7408ae..def27cc05f2 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -861,7 +861,7 @@ @ stub NtUserEnableChildWindowDpiMessage @ stub NtUserEnableIAMAccess @ stdcall -syscall NtUserEnableMenuItem(long long long) -@ stub NtUserEnableMouseInPointer +@ stdcall -syscall NtUserEnableMouseInPointer(long) @ stub NtUserEnableMouseInPointerForWindow @ stub NtUserEnableMouseInputForCursorSuppression @ stub NtUserEnableNonClientDpiScaling diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 37ed4dbfb7f..8c56e65b986 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -265,6 +265,7 @@ extern void unregister_imm_window( HWND hwnd ) DECLSPEC_HIDDEN; /* input.c */ extern BOOL destroy_caret(void) DECLSPEC_HIDDEN; +extern BOOL enable_mouse_in_pointer DECLSPEC_HIDDEN; extern LONG global_key_state_counter DECLSPEC_HIDDEN; extern HWND get_active_window(void) DECLSPEC_HIDDEN; extern HWND get_capture(void) DECLSPEC_HIDDEN; diff --git a/include/ntuser.h b/include/ntuser.h index c8e719620da..ee97f535534 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -701,6 +701,7 @@ BOOL WINAPI NtUserDrawIconEx( HDC hdc, INT x0, INT y0, HICON icon, INT width, DWORD WINAPI NtUserDrawMenuBarTemp( HWND hwnd, HDC hdc, RECT *rect, HMENU handle, HFONT font ); BOOL WINAPI NtUserEmptyClipboard(void); BOOL WINAPI NtUserEnableMenuItem( HMENU handle, UINT id, UINT flags ); +BOOL WINAPI NtUserEnableMouseInPointer( BOOL enable ); BOOL WINAPI NtUserEnableScrollBar( HWND hwnd, UINT bar, UINT flags ); BOOL WINAPI NtUserEndDeferWindowPosEx( HDWP hdwp, BOOL async ); BOOL WINAPI NtUserEndMenu(void); From c5fe4c9edae989543a4f830b93d00b8dabeb3e04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 Nov 2021 02:30:41 +0100 Subject: [PATCH 0256/2777] server: Continuously send pointer update messages while it's down. CW-Bug-Id: #18214 server: Clear POINTER_MESSAGE_FLAG_NEW from the correct field. CW-Bug-Id: #19994 server: Merge WM_POINTERUPDATE messages together. CW-Bug-Id: #19994 server: Keep desktop cursor position updated while touch is set. CW-Bug-Id: #19994 --- server/queue.c | 116 +++++++++++++++++++++++++++++++++++++++++++- server/user.h | 2 + server/window.c | 1 + server/winstation.c | 2 + 4 files changed, 120 insertions(+), 1 deletion(-) diff --git a/server/queue.c b/server/queue.c index 970b8fa7001..f0dfd0e6dfd 100644 --- a/server/queue.c +++ b/server/queue.c @@ -599,17 +599,48 @@ static inline unsigned int get_unique_id(void) return id; } +static int merge_pointer_update_message( struct thread_input *input, const struct message *msg ) +{ + struct hardware_msg_data *prev_data, *msg_data = msg->data; + struct message *prev; + struct list *ptr; + + for (ptr = list_tail( &input->msg_list ); ptr; ptr = list_prev( &input->msg_list, ptr )) + { + prev = LIST_ENTRY( ptr, struct message, entry ); + if (prev->msg != WM_POINTERUPDATE || !(prev_data = prev->data)) continue; + if (LOWORD(prev_data->rawinput.mouse.data) == LOWORD(msg_data->rawinput.mouse.data)) break; + } + if (!ptr) return 0; + if (prev->result) return 0; + if (prev->win && msg->win && prev->win != msg->win) return 0; + if (prev->type != msg->type) return 0; + /* now we can merge it */ + prev->wparam = msg->wparam; + prev->lparam = msg->lparam; + prev->x = msg->x; + prev->y = msg->y; + prev->time = msg->time; + prev_data->rawinput.mouse.data |= msg_data->rawinput.mouse.data; + prev_data->rawinput.mouse.x = msg_data->rawinput.mouse.x; + prev_data->rawinput.mouse.y = msg_data->rawinput.mouse.y; + list_remove( ptr ); + list_add_tail( &input->msg_list, ptr ); + return 1; +} + /* try to merge a message with the last in the list; return 1 if successful */ static int merge_message( struct thread_input *input, const struct message *msg ) { struct message *prev; struct list *ptr; + if (msg->msg == WM_POINTERUPDATE) return merge_pointer_update_message( input, msg ); if (msg->msg != WM_MOUSEMOVE) return 0; for (ptr = list_tail( &input->msg_list ); ptr; ptr = list_prev( &input->msg_list, ptr )) { prev = LIST_ENTRY( ptr, struct message, entry ); - if (prev->msg != WM_INPUT) break; + if (prev->msg != WM_INPUT && prev->msg != WM_POINTERUPDATE) break; } if (!ptr) return 0; if (prev->result) return 0; @@ -2047,6 +2078,58 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c return wait; } +struct touch +{ + struct list entry; + struct desktop *desktop; + user_handle_t win; + hw_input_t input; + struct timeout_user *timeout; +}; + +static void queue_touch_input_message( void *private ) +{ + struct hw_msg_source source = { IMDT_UNAVAILABLE, IMDT_TOUCH }; + struct touch *touch = private; + struct desktop *desktop = touch->desktop; + const hw_input_t *input = &touch->input; + user_handle_t win = touch->win; + struct hardware_msg_data *msg_data; + struct message *msg; + + if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return; + + msg_data = msg->data; + msg_data->info = 0; + msg_data->size = sizeof(*msg_data); + msg_data->flags = input->hw.lparam; + msg_data->rawinput = input->hw.rawinput; + + msg->win = get_user_full_handle( win ); + msg->msg = input->hw.msg; + msg->wparam = 0; + msg->lparam = input->hw.lparam; + msg->x = input->hw.rawinput.mouse.x; + msg->y = input->hw.rawinput.mouse.y; + + queue_hardware_message( desktop, msg, 1 ); + touch->timeout = add_timeout_user( -160000, queue_touch_input_message, touch ); +} + +static struct touch *find_touch_input( struct desktop *desktop, unsigned int id ) +{ + struct touch *touch; + + LIST_FOR_EACH_ENTRY( touch, &desktop->touches, struct touch, entry ) + if (LOWORD(touch->input.hw.rawinput.mouse.data) == id) return touch; + + touch = mem_alloc( sizeof(struct touch) ); + list_add_tail( &desktop->touches, &touch->entry ); + touch->desktop = desktop; + touch->timeout = NULL; + return touch; +} + /* queue a hardware message for a custom type of event */ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_t win, unsigned int origin, const hw_input_t *input ) @@ -2054,6 +2137,7 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ struct hw_msg_source source = { IMDT_UNAVAILABLE, origin }; struct hardware_msg_data *msg_data; struct rawinput_message raw_msg; + struct touch *touch; struct message *msg; data_size_t report_size = 0; @@ -2103,6 +2187,21 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ msg_data->size = sizeof(*msg_data); msg_data->flags = input->hw.lparam; msg_data->rawinput = input->hw.rawinput; + touch = find_touch_input( desktop, LOWORD(input->hw.rawinput.mouse.data) ); + if (touch->timeout) remove_timeout_user( touch->timeout ); + if (input->hw.msg != WM_POINTERUP) + { + touch->win = win; + touch->input = *input; + touch->input.hw.msg = WM_POINTERUPDATE; + touch->input.hw.rawinput.mouse.data &= ~(POINTER_MESSAGE_FLAG_NEW << 16); + touch->timeout = add_timeout_user( -160000, queue_touch_input_message, touch ); + } + else + { + list_remove( &touch->entry ); + free( touch ); + } } msg->win = get_user_full_handle( win ); @@ -2422,6 +2521,21 @@ void post_win_event( struct thread *thread, unsigned int event, } } +void free_touches( struct desktop *desktop, user_handle_t window ) +{ + struct touch *touch, *next; + + LIST_FOR_EACH_ENTRY_SAFE( touch, next, &desktop->touches, struct touch, entry ) + { + if (!window || touch->win == window) + { + list_remove( &touch->entry ); + if (touch->timeout) remove_timeout_user( touch->timeout ); + free( touch ); + } + } +} + /* free all hotkeys on a desktop, optionally filtering by window */ void free_hotkeys( struct desktop *desktop, user_handle_t window ) { diff --git a/server/user.h b/server/user.h index 280da454d07..4fb021b3036 100644 --- a/server/user.h +++ b/server/user.h @@ -73,6 +73,7 @@ struct desktop struct hook_table *global_hooks; /* table of global hooks on this desktop */ struct list hotkeys; /* list of registered hotkeys */ struct timeout_user *close_timeout; /* timeout before closing the desktop */ + struct list touches; /* list of active touches */ struct thread_input *foreground_input; /* thread input of foreground thread */ unsigned int users; /* processes and threads using this desktop */ struct global_cursor cursor; /* global cursor information */ @@ -120,6 +121,7 @@ extern void post_win_event( struct thread *thread, unsigned int event, const WCHAR *module, data_size_t module_size, user_handle_t handle ); extern void free_hotkeys( struct desktop *desktop, user_handle_t window ); +extern void free_touches( struct desktop *desktop, user_handle_t window ); /* region functions */ diff --git a/server/window.c b/server/window.c index c000f493815..3425e0eeb19 100644 --- a/server/window.c +++ b/server/window.c @@ -2025,6 +2025,7 @@ void free_window_handle( struct window *win ) if (win == progman_window) progman_window = NULL; if (win == taskman_window) taskman_window = NULL; free_hotkeys( win->desktop, win->handle ); + free_touches( win->desktop, win->handle ); cleanup_clipboard_window( win->desktop, win->handle ); destroy_properties( win ); if (is_desktop_window(win)) diff --git a/server/winstation.c b/server/winstation.c index a99c60a28ff..afaf8e67536 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -241,6 +241,7 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned memset( desktop->keystate, 0, sizeof(desktop->keystate) ); list_add_tail( &winstation->desktops, &desktop->entry ); list_init( &desktop->hotkeys ); + list_init( &desktop->touches ); } else clear_error(); } @@ -289,6 +290,7 @@ static void desktop_destroy( struct object *obj ) struct desktop *desktop = (struct desktop *)obj; free_hotkeys( desktop, 0 ); + free_touches( desktop, 0 ); if (desktop->top_window) free_window_handle( desktop->top_window ); if (desktop->msg_window) free_window_handle( desktop->msg_window ); if (desktop->global_hooks) release_object( desktop->global_hooks ); From 4f181643333d9b960dce8f7e4b9d8db910900e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 28 Oct 2021 16:41:17 +0200 Subject: [PATCH 0257/2777] HACK: gamescope: winex11.drv: Use native screen rect for absolute raw event positions. CW-Bug-Id: #18214 --- dlls/winex11.drv/display.c | 3 +++ dlls/winex11.drv/mouse.c | 1 + dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 5 insertions(+) diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c index 34085c49543..a68e5a9671f 100644 --- a/dlls/winex11.drv/display.c +++ b/dlls/winex11.drv/display.c @@ -31,6 +31,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(x11drv); static struct x11drv_display_device_handler host_handler; struct x11drv_display_device_handler desktop_handler; static struct x11drv_settings_handler settings_handler; +RECT native_screen_rect; #define NEXT_DEVMODEW(mode) ((DEVMODEW *)((char *)((mode) + 1) + (mode)->dmDriverExtra)) @@ -623,4 +624,6 @@ void X11DRV_DisplayDevices_Init(BOOL force) if (force) force_display_devices_refresh = TRUE; /* trigger refresh in win32u */ NtUserGetDisplayConfigBufferSizes( QDC_ONLY_ACTIVE_PATHS, &num_path, &num_mode ); + + if (!native_screen_rect.bottom) native_screen_rect = NtUserGetVirtualScreenRect(); } diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 4378b6bd295..14fa5bc56d1 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1902,6 +1902,7 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input ) FIXME( "Unsupported relative/absolute X/Y axis mismatch\n." ); if (input->u.mi.dwFlags & MOUSEEVENTF_VIRTUALDESK) SetRect( &virtual_rect, 0, 0, 65535, 65535 ); + else if (wm_is_steamcompmgr( event->display )) virtual_rect = native_screen_rect; else virtual_rect = NtUserGetVirtualScreenRect(); if (x->max <= x->min) x_scale = 1; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 3e2493a94e3..0435339a9a0 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -730,6 +730,7 @@ extern void init_recursive_mutex( pthread_mutex_t *mutex ) DECLSPEC_HIDDEN; #define DEPTH_COUNT 3 extern const unsigned int *depths DECLSPEC_HIDDEN; +extern RECT native_screen_rect DECLSPEC_HIDDEN; /* Required functions for changing and enumerating display settings */ struct x11drv_settings_handler From 4f0443edd520236812e5cef89c8f5895b06a5b09 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Fri, 23 Jul 2021 13:46:32 -0400 Subject: [PATCH 0258/2777] user32: Raise EVENT_OBJECT_FOCUS WinEvent when window receives focus. Signed-off-by: Connor McAdams CW-Bug-Id: #18351 --- dlls/win32u/input.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 9531c9336ef..d955e89a4ce 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1508,7 +1508,7 @@ HWND get_focus(void) * * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages */ -static HWND set_focus_window( HWND hwnd ) +static HWND set_focus_window( HWND hwnd, BOOL from_active ) { HWND previous = 0, ime_hwnd; BOOL ret; @@ -1525,6 +1525,9 @@ static HWND set_focus_window( HWND hwnd ) if (previous) { + if (!NtUserIsWindow(hwnd) && !from_active) + NtUserNotifyWinEvent( EVENT_OBJECT_FOCUS, previous, OBJID_CLIENT, CHILDID_SELF ); + send_message( previous, WM_KILLFOCUS, (WPARAM)hwnd, 0 ); ime_hwnd = get_default_ime_window( previous ); @@ -1537,6 +1540,8 @@ static HWND set_focus_window( HWND hwnd ) if (is_window(hwnd)) { user_driver->pSetFocus(hwnd); + if (!from_active) + NtUserNotifyWinEvent( EVENT_OBJECT_FOCUS, hwnd, OBJID_CLIENT, CHILDID_SELF ); ime_hwnd = get_default_ime_window( hwnd ); if (ime_hwnd) @@ -1649,7 +1654,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) if (hwnd == info.hwndActive) { if (!info.hwndFocus || !hwnd || NtUserGetAncestor( info.hwndFocus, GA_ROOT ) != hwnd) - set_focus_window( hwnd ); + set_focus_window( hwnd, TRUE ); } } @@ -1741,7 +1746,7 @@ HWND WINAPI NtUserSetFocus( HWND hwnd ) } /* change focus and send messages */ - return set_focus_window( hwnd ); + return set_focus_window( hwnd, FALSE ); } /******************************************************************* From f3764086835efe5e0ff90d21fa44473272d25c8c 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 0259/2777] 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 Wine-Staging: user32-recursive-activation --- dlls/win32u/input.c | 19 +++++++++++++------ dlls/win32u/ntuser_private.h | 1 + 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index d955e89a4ce..ddefaa2f96d 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1562,7 +1562,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 = get_active_window(); - BOOL ret; + BOOL ret = FALSE; DWORD old_thread, new_thread; CBTACTIVATESTRUCT cbt; @@ -1572,6 +1572,9 @@ 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; @@ -1591,9 +1594,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) { @@ -1601,7 +1604,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) if (send_message( hwnd, WM_QUERYNEWPALETTE, 0, 0 )) send_message_timeout( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0, SMTO_ABORTIFHUNG, 2000, FALSE ); - if (!is_window(hwnd)) return FALSE; + if (!(ret = is_window(hwnd))) goto done; } old_thread = previous ? get_window_thread( previous, NULL ) : 0; @@ -1635,7 +1638,9 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) if (is_window(hwnd)) { - send_message( hwnd, WM_NCACTIVATE, hwnd == NtUserGetForegroundWindow(), (LPARAM)previous ); + send_message( hwnd, WM_NCACTIVATE, + (hwnd == NtUserGetForegroundWindow()) && !(win_get_flags(previous) & WIN_IS_ACTIVATING), + (LPARAM)previous ); send_message( hwnd, WM_ACTIVATE, MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, is_iconic(hwnd) ), (LPARAM)previous ); @@ -1658,7 +1663,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/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 80733d29e03..a28e432e3f8 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -105,6 +105,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 */ #define WND_OTHER_PROCESS ((WND *)1) /* returned by get_win_ptr on unknown window handles */ #define WND_DESKTOP ((WND *)2) /* returned by get_win_ptr on the desktop window */ From 2d79650b4eef7ec15f7484e5242fe587d8ad50c5 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 0260/2777] user32: Use PostMessageW in set_foreground_window. Instead of SendNotifyMessageW for WM_WINE_SETACTIVEWINDOW. CW-Bug-Id: #19612 --- dlls/win32u/input.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index ddefaa2f96d..2995dbbee63 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1781,14 +1781,12 @@ BOOL set_foreground_window( HWND hwnd, BOOL mouse ) if (ret && previous != hwnd) { if (send_msg_old) /* old window belongs to other thread */ - NtUserMessageCall( previous, WM_WINE_SETACTIVEWINDOW, 0, 0, - 0, NtUserSendNotifyMessage, FALSE ); + NtUserPostMessage( 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 */ - NtUserMessageCall( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0, - 0, NtUserSendNotifyMessage, FALSE ); + NtUserPostMessage( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 ); else /* new window belongs to us */ ret = set_active_window( hwnd, NULL, mouse, TRUE ); } From 726795aaf20a7bfe806a4197be3bc4d4ef361e84 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 0261/2777] user32: Do not deactivate if thread is foreground. Instead of only checking that the window is foreground. CW-Bug-Id: #19612 --- dlls/win32u/message.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 472266adbfe..47285a6fb90 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1262,7 +1262,8 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR if (is_desktop_window( hwnd )) return 0; return set_window_style( hwnd, wparam, lparam ); case WM_WINE_SETACTIVEWINDOW: - if (!wparam && NtUserGetForegroundWindow() == hwnd) return 0; + if (!wparam && NtUserGetWindowThread( NtUserGetForegroundWindow(), NULL ) == GetCurrentThreadId()) + return 0; return (LRESULT)NtUserSetActiveWindow( (HWND)wparam ); case WM_WINE_KEYBOARD_LL_HOOK: case WM_WINE_MOUSE_LL_HOOK: From aefb397977840cded2a07c360c349c4e4fda8df9 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 0262/2777] 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/win32u/input.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 2995dbbee63..4262437f0e7 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1785,6 +1785,10 @@ 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 == get_active_window()) + send_message( hwnd, WM_NCACTIVATE, TRUE, (LPARAM)hwnd ); + if (send_msg_new) /* new window belongs to other thread */ NtUserPostMessage( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 ); else /* new window belongs to us */ From 9c99cb41f6e530f1b68b3f462c770c19b5fbb237 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 0263/2777] user32: Send WM_*FOCUS messages even if already focused. CW-Bug-Id: #19612 --- dlls/win32u/input.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 4262437f0e7..94e1185e65c 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1508,7 +1508,7 @@ HWND get_focus(void) * * 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_hwnd; BOOL ret; @@ -1522,6 +1522,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) { @@ -1659,7 +1660,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) if (hwnd == info.hwndActive) { if (!info.hwndFocus || !hwnd || NtUserGetAncestor( info.hwndFocus, GA_ROOT ) != hwnd) - set_focus_window( hwnd, TRUE ); + set_focus_window( hwnd, TRUE, FALSE ); } } @@ -1753,7 +1754,7 @@ HWND WINAPI NtUserSetFocus( HWND hwnd ) } /* change focus and send messages */ - return set_focus_window( hwnd, FALSE ); + return set_focus_window( hwnd, FALSE, hwnd != previous ); } /******************************************************************* From b305f197cf00e7d3b8ecca0b01b6595916e651db 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 0264/2777] server: Drop pending internal messages in set_active_window. When changing the active window in the foreground thread. CW-Bug-Id: #19612 --- dlls/win32u/input.c | 1 + server/protocol.def | 1 + server/queue.c | 12 ++++++++++++ 3 files changed, 14 insertions(+) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 94e1185e65c..aad3e2c5383 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1591,6 +1591,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 42eae1db9f3..325c1bdbe6a 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2842,6 +2842,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 f0dfd0e6dfd..32eafa4179f 100644 --- a/server/queue.c +++ b/server/queue.c @@ -3331,7 +3331,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 )) @@ -3340,9 +3344,17 @@ DECL_HANDLER(set_active_window) { reply->previous = queue->input->active; queue->input->active = get_user_full_handle( req->handle ); + + 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 b037678d7a1320d0290b28cce0d605c372f4c7c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 20 Apr 2021 11:08:53 +0200 Subject: [PATCH 0265/2777] HACK: user32: Disable layered windows support for Zombie Army 4. CW-Bug-Id: 18691 --- dlls/win32u/window.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index b8aacbf9cbe..d0272c20d91 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -1203,6 +1203,7 @@ static HWND set_window_owner( HWND hwnd, HWND owner ) /* Helper function for SetWindowLong(). */ LONG_PTR set_window_long( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL ansi ) { + const char *sgi = getenv( "SteamGameId" ); BOOL ok, made_visible = FALSE; LONG_PTR retval = 0; STYLESTRUCT style; @@ -1258,6 +1259,8 @@ LONG_PTR set_window_long( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOO if (win->dwStyle & WS_MINIMIZE) newval |= WS_MINIMIZE; break; case GWL_EXSTYLE: + /* FIXME: Layered windows don't work well right now, disable them */ + if (sgi && !strcmp( sgi, "694280" )) newval &= ~WS_EX_LAYERED; style.styleOld = win->dwExStyle; style.styleNew = newval; release_win_ptr( win ); From f535f99013f72d80542ce255fd97f893c9cf4e32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 20 Apr 2021 19:37:22 +0200 Subject: [PATCH 0266/2777] HACK: user32: Disable layered windows for Strange Brigade. CW-Bug-Id: 18691 --- dlls/win32u/window.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index d0272c20d91..d97e5445597 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -1261,6 +1261,7 @@ LONG_PTR set_window_long( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOO case GWL_EXSTYLE: /* FIXME: Layered windows don't work well right now, disable them */ if (sgi && !strcmp( sgi, "694280" )) newval &= ~WS_EX_LAYERED; + if (sgi && !strcmp( sgi, "312670" )) newval &= ~WS_EX_LAYERED; style.styleOld = win->dwExStyle; style.styleNew = newval; release_win_ptr( win ); From d2cd9bccddfe80d2e95dd39367f0e6100ed69001 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Wed, 28 Apr 2021 14:32:04 -0500 Subject: [PATCH 0267/2777] HACK: user32: Disable layered windows for Evil Genius 2. CW-Bug-Id: 18691 --- dlls/win32u/window.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index d97e5445597..69b6ccc8f9a 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -1262,6 +1262,7 @@ LONG_PTR set_window_long( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOO /* FIXME: Layered windows don't work well right now, disable them */ if (sgi && !strcmp( sgi, "694280" )) newval &= ~WS_EX_LAYERED; if (sgi && !strcmp( sgi, "312670" )) newval &= ~WS_EX_LAYERED; + if (sgi && !strcmp( sgi, "700600" )) newval &= ~WS_EX_LAYERED; style.styleOld = win->dwExStyle; style.styleNew = newval; release_win_ptr( win ); From 78f790b04b4022a7fda38a0b2cef574e0bb0b395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 16 Nov 2021 21:41:28 +0100 Subject: [PATCH 0268/2777] HACK: mscoree: Build a dummy CameraQuakeViewer.dll for Nights of Azure. The game references types from a non-existing DLL, and Mono cannot be taught to handle it easily. This is an ugly hack to make sure the load succeeds. CW-Bug-Id: #19046 --- dlls/mscoree/metahost.c | 62 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/dlls/mscoree/metahost.c b/dlls/mscoree/metahost.c index c72f510c8ac..657d2ba3640 100644 --- a/dlls/mscoree/metahost.c +++ b/dlls/mscoree/metahost.c @@ -1705,6 +1705,44 @@ static MonoAssembly* mono_assembly_try_load(WCHAR *path) return result; } +static BOOL compile_assembly(const char *source, const char *target, char *target_path, DWORD target_path_len) +{ + static const char *csc = "C:\\windows\\Microsoft.NET\\Framework\\v2.0.50727\\csc.exe"; + char cmdline[2 * MAX_PATH + 74], tmp[MAX_PATH], tmpdir[MAX_PATH], source_path[MAX_PATH]; + STARTUPINFOA si = {.cb = sizeof(STARTUPINFOA)}; + PROCESS_INFORMATION pi; + HANDLE file; + DWORD size; + BOOL ret; + LUID id; + + if (!PathFileExistsA(csc)) return FALSE; + if (!AllocateLocallyUniqueId(&id)) return FALSE; + + GetTempPathA(MAX_PATH, tmp); + if (!GetTempFileNameA(tmp, "assembly", id.LowPart, tmpdir)) return FALSE; + if (!CreateDirectoryA(tmpdir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) return FALSE; + + snprintf(source_path, MAX_PATH, "%s\\source.cs", tmpdir); + snprintf(target_path, target_path_len, "%s\\%s", tmpdir, target); + + file = CreateFileA(source_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (file == INVALID_HANDLE_VALUE) return FALSE; + ret = WriteFile(file, source, strlen(source), &size, NULL); + CloseHandle(file); + if (!ret) return FALSE; + + snprintf(cmdline, ARRAY_SIZE(cmdline), "%s /t:library /out:\"%s\" \"%s\"", csc, target_path, source_path); + ret = CreateProcessA(csc, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + if (!ret) return FALSE; + + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + + return PathFileExistsA(target_path); +} + static MonoAssembly* CDECL mono_assembly_preload_hook_fn(MonoAssemblyName *aname, char **assemblies_path, void *user_data) { int dummy; @@ -1784,6 +1822,30 @@ static MonoAssembly* CDECL wine_mono_assembly_preload_hook_fn(MonoAssemblyName * } } + if (!strcmp(assemblyname, "CameraQuakeViewer")) + { + /* HACK for Nights of Azure which references type from a non-existing DLL. + * Native .NET framework normally gets away with it but Mono cannot + * due to some deeply rooted differences. */ + const char* sgi = getenv("SteamGameId"); + if (sgi && !strcmp(sgi, "527280")) + { + char assembly_path[MAX_PATH]; + + FIXME("HACK: Building CameraQuakeViewer.dll\n"); + + if (compile_assembly("namespace CQViewer { class CQMgr {} }", "CameraQuakeViewer.dll", assembly_path, MAX_PATH)) + result = mono_assembly_open(assembly_path, &stat); + else + ERR("HACK: Failed to build CameraQuakeViewer.dll\n"); + + if (result) + goto done; + else + ERR("HACK: Failed to load CameraQuakeViewer.dll\n"); + } + } + /* FIXME: We should search the given paths before the GAC. */ if ((search_flags & ASSEMBLY_SEARCH_GAC) != 0) From 414c9a8df070296b01120e433319489fed84c96c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 16 Jun 2021 17:36:15 +0200 Subject: [PATCH 0269/2777] devenum: Register IEEE float for Direct Sound default device. Fixes some music does not play in Planet Coaster. CW-Bug-Id: #18986 --- dlls/devenum/createdevenum.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/dlls/devenum/createdevenum.c b/dlls/devenum/createdevenum.c index 8d59d6b385d..9569c38bfcd 100644 --- a/dlls/devenum/createdevenum.c +++ b/dlls/devenum/createdevenum.c @@ -477,7 +477,7 @@ static BOOL CALLBACK register_dsound_devices(GUID *guid, const WCHAR *desc, cons static const WCHAR defaultW[] = L"Default DirectSound Device"; IPropertyBag *prop_bag = NULL; REGFILTERPINS2 rgpins = {0}; - REGPINTYPES rgtypes = {0}; + REGPINTYPES rgtypes[2] = {}; REGFILTER2 rgf = {0}; WCHAR clsid[CHARS_IN_GUID]; VARIANT var; @@ -508,10 +508,12 @@ static BOOL CALLBACK register_dsound_devices(GUID *guid, const WCHAR *desc, cons rgf.rgPins2 = &rgpins; rgpins.dwFlags = REG_PINFLAG_B_RENDERER; /* FIXME: native registers many more formats */ - rgpins.nMediaTypes = 1; - rgpins.lpMediaType = &rgtypes; - rgtypes.clsMajorType = &MEDIATYPE_Audio; - rgtypes.clsMinorType = &MEDIASUBTYPE_PCM; + rgpins.nMediaTypes = 2; + rgpins.lpMediaType = rgtypes; + rgtypes[0].clsMajorType = &MEDIATYPE_Audio; + rgtypes[0].clsMinorType = &MEDIASUBTYPE_PCM; + rgtypes[1].clsMajorType = &MEDIATYPE_Audio; + rgtypes[1].clsMinorType = &MEDIASUBTYPE_IEEE_FLOAT; write_filter_data(prop_bag, &rgf); From 5282bcb3a15788cdd6d5a1b1f0bd706d99355da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 2 Nov 2020 13:21:49 +0100 Subject: [PATCH 0270/2777] wine/server: Add traces for client requests. --- dlls/ntdll/unix/thread.c | 2 +- include/wine/server.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index d56962e1721..b2881cc4695 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -1850,7 +1850,7 @@ static void set_native_thread_name( HANDLE handle, const UNICODE_STRING *name ) #ifdef linux unsigned int status; char path[64], nameA[64]; - int unix_pid, unix_tid, len, fd; + int unix_pid = -1, unix_tid = -1, len, fd; SERVER_START_REQ( get_thread_times ) { diff --git a/include/wine/server.h b/include/wine/server.h index 228682dc914..2ab3ce604f1 100644 --- a/include/wine/server.h +++ b/include/wine/server.h @@ -26,6 +26,7 @@ #include #include #include +#include /* client communication functions */ @@ -123,6 +124,8 @@ static inline void *wine_server_get_ptr( client_ptr_t ptr ) #define SERVER_START_REQ(type) \ do { \ + WINE_DECLARE_DEBUG_CHANNEL(client); \ + static const char *const __req_name = #type; \ struct __server_request_info __req; \ struct type##_request * const req = &__req.u.req.type##_request; \ const struct type##_reply * const reply = &__req.u.reply.type##_reply; \ @@ -130,10 +133,12 @@ static inline void *wine_server_get_ptr( client_ptr_t ptr ) __req.u.req.request_header.req = REQ_##type; \ __req.data_count = 0; \ (void)reply; \ + TRACE_(client)("%s start\n", __req_name); \ do #define SERVER_END_REQ \ while(0); \ + TRACE_(client)("%s end\n", __req_name); \ } while(0) From 4e9a5ccb282ed9d2b4d9f01f169e31bdb8397eed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 2 Nov 2020 13:32:07 +0100 Subject: [PATCH 0271/2777] ntdll: Add +microsecs channel for precise timestamps. --- dlls/ntdll/thread.c | 10 +++++++++- dlls/ntdll/unix/debug.c | 10 +++++++++- dlls/winecrt0/debug.c | 12 +++++++++++- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 1bd8f900d22..130213b765f 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -36,6 +36,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(thread); WINE_DECLARE_DEBUG_CHANNEL(relay); WINE_DECLARE_DEBUG_CHANNEL(pid); WINE_DECLARE_DEBUG_CHANNEL(timestamp); +WINE_DECLARE_DEBUG_CHANNEL(microsecs); struct _KUSER_SHARED_DATA *user_shared_data = (void *)0x7ffe0000; @@ -143,7 +144,14 @@ int __cdecl __wine_dbg_header( enum __wine_debug_class cls, struct __wine_debug_ /* only print header if we are at the beginning of the line */ if (info->out_pos) return 0; - if (TRACE_ON(timestamp)) + if (TRACE_ON(microsecs)) + { + LARGE_INTEGER counter, frequency, microsecs; + NtQueryPerformanceCounter(&counter, &frequency); + microsecs.QuadPart = counter.QuadPart * 1000000 / frequency.QuadPart; + pos += sprintf( pos, "%3u.%06u:", (unsigned int)(microsecs.QuadPart / 1000000), (unsigned int)(microsecs.QuadPart % 1000000) ); + } + else if (TRACE_ON(timestamp)) { ULONG ticks = NtGetTickCount(); pos += sprintf( pos, "%3lu.%03lu:", ticks / 1000, ticks % 1000 ); diff --git a/dlls/ntdll/unix/debug.c b/dlls/ntdll/unix/debug.c index aa2d87c304f..9444d154b49 100644 --- a/dlls/ntdll/unix/debug.c +++ b/dlls/ntdll/unix/debug.c @@ -44,6 +44,7 @@ WINE_DECLARE_DEBUG_CHANNEL(pid); WINE_DECLARE_DEBUG_CHANNEL(timestamp); +WINE_DECLARE_DEBUG_CHANNEL(microsecs); WINE_DEFAULT_DEBUG_CHANNEL(ntdll); struct debug_info @@ -297,7 +298,14 @@ int __cdecl __wine_dbg_header( enum __wine_debug_class cls, struct __wine_debug_ if (init_done) { - if (TRACE_ON(timestamp)) + if (TRACE_ON(microsecs)) + { + LARGE_INTEGER counter, frequency, microsecs; + NtQueryPerformanceCounter(&counter, &frequency); + microsecs.QuadPart = counter.QuadPart * 1000000 / frequency.QuadPart; + pos += sprintf( pos, "%3u.%06u:", (unsigned int)(microsecs.QuadPart / 1000000), (unsigned int)(microsecs.QuadPart % 1000000) ); + } + else if (TRACE_ON(timestamp)) { UINT ticks = NtGetTickCount(); pos += sprintf( pos, "%3u.%03u:", ticks / 1000, ticks % 1000 ); diff --git a/dlls/winecrt0/debug.c b/dlls/winecrt0/debug.c index 2ac4505fb85..fe516e088c5 100644 --- a/dlls/winecrt0/debug.c +++ b/dlls/winecrt0/debug.c @@ -30,6 +30,7 @@ WINE_DECLARE_DEBUG_CHANNEL(pid); WINE_DECLARE_DEBUG_CHANNEL(timestamp); +WINE_DECLARE_DEBUG_CHANNEL(microsecs); static const char * (__cdecl *p__wine_dbg_strdup)( const char *str ); static int (__cdecl *p__wine_dbg_output)( const char *str ); @@ -189,7 +190,16 @@ static int __cdecl fallback__wine_dbg_header( enum __wine_debug_class cls, /* skip header if partial line and no other thread came in between */ if (partial_line_tid == GetCurrentThreadId()) return 0; - if (TRACE_ON(timestamp)) + if (TRACE_ON(microsecs)) + { + static LARGE_INTEGER frequency; + LARGE_INTEGER counter, microsecs; + if (!frequency.QuadPart) QueryPerformanceFrequency(&frequency); + QueryPerformanceCounter(&counter); + microsecs.QuadPart = counter.QuadPart * 1000000 / frequency.QuadPart; + pos += sprintf( pos, "%3u.%06u:", (unsigned int)(microsecs.QuadPart / 1000000), (unsigned int)(microsecs.QuadPart % 1000000) ); + } + else if (TRACE_ON(timestamp)) { UINT ticks = GetTickCount(); pos += sprintf( pos, "%3u.%03u:", ticks / 1000, ticks % 1000 ); From 60d1032157dddb09201c84f712a24348d31f9e0c 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 0272/2777] 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.in | 1 + 2 files changed, 2 insertions(+) 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.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 a3c9cb385e8de27d248587fe31aa529dde454514 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Fri, 11 Sep 2020 17:55:59 +1000 Subject: [PATCH 0273/2777] include: Remove interfaces already define in msxml6.idl Signed-off-by: Alistair Leslie-Hughes Wine-Staging: msxml3-FreeThreadedXMLHTTP60 --- dlls/msxml3/factory.c | 1 + dlls/msxml3/tests/saxreader.c | 1 + dlls/msxml3/tests/schema.c | 5 ++ dlls/msxml3/uuid.c | 11 ++++ include/msxml2.idl | 109 ---------------------------------- include/msxml6.idl | 24 ++++---- 6 files changed, 30 insertions(+), 121 deletions(-) diff --git a/dlls/msxml3/factory.c b/dlls/msxml3/factory.c index c2d3cd30c60..243ee379712 100644 --- a/dlls/msxml3/factory.c +++ b/dlls/msxml3/factory.c @@ -31,6 +31,7 @@ #include "ole2.h" #include "msxml.h" #include "msxml2.h" +#include "msxml6.h" #include "xmlparser.h" /* undef the #define in msxml2 so that we can access the v.2 version diff --git a/dlls/msxml3/tests/saxreader.c b/dlls/msxml3/tests/saxreader.c index e123d4eba5a..48cfa8f5593 100644 --- a/dlls/msxml3/tests/saxreader.c +++ b/dlls/msxml3/tests/saxreader.c @@ -29,6 +29,7 @@ #include "windows.h" #include "ole2.h" #include "msxml2.h" +#include "msxml6.h" #include "msxml2did.h" #include "ocidl.h" #include "dispex.h" diff --git a/dlls/msxml3/tests/schema.c b/dlls/msxml3/tests/schema.c index 3d209c0e4a0..99c7d35cc10 100644 --- a/dlls/msxml3/tests/schema.c +++ b/dlls/msxml3/tests/schema.c @@ -32,6 +32,11 @@ #include "dispex.h" #include "cguid.h" +DEFINE_GUID(CLSID_MXXMLWriter60, 0x88d96a0f, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_SAXAttributes60, 0x88d96a0e, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_SAXXMLReader60, 0x88d96a0c, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_XMLSchemaCache60, 0x88d96a07, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); + #include "wine/test.h" #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) diff --git a/dlls/msxml3/uuid.c b/dlls/msxml3/uuid.c index 4abbe5e4763..333d4f3d3c7 100644 --- a/dlls/msxml3/uuid.c +++ b/dlls/msxml3/uuid.c @@ -41,6 +41,17 @@ #include "initguid.h" #include "msxml2.h" +/* Cannot include msxml6 here since we will get a duplicate LIBID_MSXML2 error. */ +DEFINE_GUID(CLSID_FreeThreadedDOMDocument60, 0x88d96a06, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_MXNamespaceManager60, 0x88d96a11, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_MXXMLWriter60, 0x88d96a0f, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_SAXAttributes60, 0x88d96a0e, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_SAXXMLReader60, 0x88d96a0c, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_ServerXMLHTTP60, 0x88d96a0b, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_XMLHTTP60, 0x88d96a0a, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_XMLSchemaCache60, 0x88d96a07, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_XSLTemplate60, 0x88d96a08, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); + /* * Note that because of a #define in msxml2.h, we end up initializing * CLSID_DOMDocument2 to be the v.3 version independent DOMDocument diff --git a/include/msxml2.idl b/include/msxml2.idl index 916e0e8ab3d..1d1ba7a5248 100644 --- a/include/msxml2.idl +++ b/include/msxml2.idl @@ -1612,15 +1612,6 @@ coclass FreeThreadedDOMDocument40 [default, source] dispinterface XMLDOMDocumentEvents; } -[ - uuid(88d96a06-f192-11d4-a65f-0040963251e5), -] -coclass FreeThreadedDOMDocument60 -{ - [default] interface IXMLDOMDocument3; - [default, source] dispinterface XMLDOMDocumentEvents; -} - [ helpstring("Free threaded XML DOM Document"), progid("Msxml2.FreeThreadedDOMDocument"), @@ -1662,14 +1653,6 @@ coclass XMLHTTP40 [default] interface IXMLHTTPRequest; } -[ - uuid(88d96a0a-f192-11d4-a65f-0040963251e5) -] -coclass XMLHTTP60 -{ - [default] interface IXMLHTTPRequest; -} - [ helpstring("XML HTTP"), progid("Msxml2.XMLHTTP"), @@ -1702,14 +1685,6 @@ coclass ServerXMLHTTP40 [default] interface IServerXMLHTTPRequest2; } -[ - uuid(88d96a0b-f192-11d4-a65f-0040963251e5) -] -coclass ServerXMLHTTP60 -{ - [default] interface IServerXMLHTTPRequest2; -} - [ helpstring("Server XML HTTP"), progid("Msxml2.ServerXMLHTTP"), @@ -1750,14 +1725,6 @@ coclass XMLSchemaCache40 [default] interface IXMLDOMSchemaCollection2; } -[ - uuid(88d96a07-f192-11d4-a65f-0040963251e5) -] -coclass XMLSchemaCache60 -{ - [default] interface IXMLDOMSchemaCollection2; -} - [ helpstring("XML Schema Cache"), progid("Msxml2.XMLSchemaCache"), @@ -1798,14 +1765,6 @@ coclass XSLTemplate40 [default] interface IXSLTemplate; } -[ - uuid(88d96a08-f192-11d4-a65f-0040963251e5) -] -coclass XSLTemplate60 -{ - [default] interface IXSLTemplate; -} - [ helpstring("XSL Template"), progid("Msxml2.XSLTemplate"), @@ -3297,15 +3256,6 @@ coclass SAXXMLReader40 interface ISAXXMLReader; } -[ - uuid(88d96a0c-f192-11d4-a65f-0040963251e5) -] -coclass SAXXMLReader60 -{ - [default] interface IVBSAXXMLReader; - interface ISAXXMLReader; -} - [ helpstring("SAX XML Reader"), progid("Msxml2.SAXXMLReader"), @@ -3380,26 +3330,6 @@ coclass MXHTMLWriter40 interface IVBSAXLexicalHandler; } -[ - uuid(88d96a10-f192-11d4-a65f-0040963251e5) -] -coclass MXHTMLWriter60 -{ - [default] interface IMXWriter; - - interface ISAXContentHandler; - interface ISAXDeclHandler; - interface ISAXDTDHandler; - interface ISAXErrorHandler; - interface ISAXLexicalHandler; - - interface IVBSAXContentHandler; - interface IVBSAXDeclHandler; - interface IVBSAXDTDHandler; - interface IVBSAXErrorHandler; - interface IVBSAXLexicalHandler; -} - [ helpstring("MXXMLWriter 3.0"), progid("Msxml2.MXXMLWriter.3.0"), @@ -3444,26 +3374,6 @@ coclass MXXMLWriter40 interface IVBSAXLexicalHandler; } -[ - uuid(88d96a0f-f192-11d4-a65f-0040963251e5) -] -coclass MXXMLWriter60 -{ - [default] interface IMXWriter; - - interface ISAXContentHandler; - interface ISAXDeclHandler; - interface ISAXDTDHandler; - interface ISAXErrorHandler; - interface ISAXLexicalHandler; - - interface IVBSAXContentHandler; - interface IVBSAXDeclHandler; - interface IVBSAXDTDHandler; - interface IVBSAXErrorHandler; - interface IVBSAXLexicalHandler; -} - [ helpstring("MXXMLWriter"), progid("Msxml2.MXXMLWriter"), @@ -3506,15 +3416,6 @@ coclass MXNamespaceManager40 interface IMXNamespaceManager; } -[ - uuid(88d96a11-f192-11d4-a65f-0040963251e5) -] -coclass MXNamespaceManager60 -{ - [default] interface IVBMXNamespaceManager; - interface IMXNamespaceManager; -} - [ helpstring("SAXAttributes 3.0"), progid("Msxml2.SAXAttributes.3.0"), @@ -3539,16 +3440,6 @@ coclass SAXAttributes40 interface ISAXAttributes; } -[ - uuid(88d96a0e-f192-11d4-a65f-0040963251e5) -] -coclass SAXAttributes60 -{ - [default] interface IMXAttributes; - interface IVBSAXAttributes; - interface ISAXAttributes; -} - [ helpstring("SAXAttributes"), progid("Msxml2.SAXAttributes"), diff --git a/include/msxml6.idl b/include/msxml6.idl index 458c43e389d..4672ae80626 100644 --- a/include/msxml6.idl +++ b/include/msxml6.idl @@ -3051,18 +3051,6 @@ coclass DOMDocument60 [default, source] dispinterface XMLDOMDocumentEvents; } -[ - helpstring("Free threaded XML DOM Document 6.0"), - progid("Msxml2.FreeThreadedDOMDocument.6.0"), - threading(both), - uuid(88d96a06-f192-11d4-a65f-0040963251e5), -] -coclass FreeThreadedDOMDocument60 -{ - [default] interface IXMLDOMDocument3; - [default, source] dispinterface XMLDOMDocumentEvents; -} - [ helpstring("SAX XML Reader 6.0"), progid("Msxml2.SAXXMLReader.6.0"), @@ -3168,6 +3156,18 @@ coclass XSLTemplate60 [default] interface IXSLTemplate; } +[ + helpstring("Free threaded XML DOM Document 6.0"), + progid("Msxml2.FreeThreadedDOMDocument.6.0"), + threading(both), + uuid(88d96a06-f192-11d4-a65f-0040963251e5), +] +coclass FreeThreadedDOMDocument60 +{ + [default] interface IXMLDOMDocument3; + [default, source] dispinterface XMLDOMDocumentEvents; +} + [ helpstring("XML HTTP 6.0"), progid("Msxml2.XMLHTTP.6.0"), From 758483d719f42fad51d22f7d609bb521e8acc46c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 8 Sep 2020 18:43:52 +0200 Subject: [PATCH 0274/2777] msxml3: Implement FreeThreadedXMLHTTP60. Update from Gijs Vermeulen Wine-Staging: msxml3-FreeThreadedXMLHTTP60 --- dlls/msxml3/Makefile.in | 2 +- dlls/msxml3/factory.c | 5 + dlls/msxml3/httprequest.c | 496 +++++++++++++++++++++++++++++++++++- dlls/msxml3/msxml_private.h | 1 + dlls/msxml3/tests/httpreq.c | 395 +++++++++++++++++++++++++++- dlls/msxml3/tests/schema.c | 6 + dlls/msxml3/uuid.c | 5 + 7 files changed, 905 insertions(+), 5 deletions(-) diff --git a/dlls/msxml3/Makefile.in b/dlls/msxml3/Makefile.in index 2bf789732da..e2d737599b1 100644 --- a/dlls/msxml3/Makefile.in +++ b/dlls/msxml3/Makefile.in @@ -1,5 +1,5 @@ MODULE = msxml3.dll -IMPORTS = $(XSLT_PE_LIBS) $(XML2_PE_LIBS) uuid urlmon shlwapi oleaut32 ole32 user32 advapi32 +IMPORTS = $(XSLT_PE_LIBS) $(XML2_PE_LIBS) uuid urlmon shlwapi oleaut32 ole32 user32 advapi32 rtworkq EXTRAINCL = $(XSLT_PE_CFLAGS) $(XML2_PE_CFLAGS) C_SRCS = \ diff --git a/dlls/msxml3/factory.c b/dlls/msxml3/factory.c index 243ee379712..323c7b49848 100644 --- a/dlls/msxml3/factory.c +++ b/dlls/msxml3/factory.c @@ -279,6 +279,7 @@ static HRESULT DOMClassFactory_Create(const GUID *clsid, REFIID riid, void **ppv static ClassFactory xmldoccf = { { &ClassFactoryVtbl }, XMLDocument_create }; static ClassFactory httpreqcf = { { &ClassFactoryVtbl }, XMLHTTPRequest_create }; +static ClassFactory httpreqcf2 = { { &ClassFactoryVtbl }, XMLHTTPRequest2_create }; static ClassFactory serverhttp = { { &ClassFactoryVtbl }, ServerXMLHTTP_create }; static ClassFactory xsltemplatecf = { { &ClassFactoryVtbl }, XSLTemplate_create }; static ClassFactory mxnsmanagercf = { {&ClassFactoryVtbl }, MXNamespaceManager_create }; @@ -340,6 +341,10 @@ HRESULT WINAPI DllGetClassObject( REFCLSID rclsid, REFIID riid, void **ppv ) { cf = &httpreqcf.IClassFactory_iface; } + else if( IsEqualCLSID( rclsid, &CLSID_FreeThreadedXMLHTTP60 )) + { + cf = &httpreqcf2.IClassFactory_iface; + } else if( IsEqualCLSID( rclsid, &CLSID_ServerXMLHTTP ) || IsEqualCLSID( rclsid, &CLSID_ServerXMLHTTP30 ) || IsEqualCLSID( rclsid, &CLSID_ServerXMLHTTP40 ) || diff --git a/dlls/msxml3/httprequest.c b/dlls/msxml3/httprequest.c index cc384a380e5..903787f9af0 100644 --- a/dlls/msxml3/httprequest.c +++ b/dlls/msxml3/httprequest.c @@ -38,10 +38,12 @@ #include "shlwapi.h" #include "msxml_dispex.h" +#include "initguid.h" +#include "rtworkq.h" #include "wine/debug.h" -WINE_DEFAULT_DEBUG_CHANNEL(msxml); +WINE_DEFAULT_DEBUG_CHANNEL(xmlhttp); static const WCHAR colspaceW[] = {':',' ',0}; static const WCHAR crlfW[] = {'\r','\n',0}; @@ -2058,6 +2060,468 @@ static const struct IServerXMLHTTPRequestVtbl ServerXMLHTTPRequestVtbl = ServerXMLHTTPRequest_setOption }; +static DWORD xhr2_work_queue; + +struct xml_http_request_2 +{ + httprequest req; + IXMLHTTPRequest3 IXMLHTTPRequest3_iface; + IRtwqAsyncCallback IRtwqAsyncCallback_iface; + IDispatch IDispatch_iface; + + IXMLHTTPRequest2Callback *callback; + IXMLHTTPRequest3Callback *callback3; + ISequentialStream *response_body; + ISequentialStream *request_body; + ULONGLONG request_body_size; +}; + +static inline struct xml_http_request_2 *impl_from_IXMLHTTPRequest3(IXMLHTTPRequest3 *iface) +{ + return CONTAINING_RECORD(iface, struct xml_http_request_2, IXMLHTTPRequest3_iface); +} + +static inline struct xml_http_request_2 *xml_http_request_2_from_IRtwqAsyncCallback(IRtwqAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct xml_http_request_2, IRtwqAsyncCallback_iface); +} + +static inline struct xml_http_request_2 *xml_http_request_2_from_IDispatch(IDispatch *iface) +{ + return CONTAINING_RECORD(iface, struct xml_http_request_2, IDispatch_iface); +} + +static HRESULT WINAPI xml_http_request_2_QueryInterface(IXMLHTTPRequest3 *iface, REFIID riid, void **obj) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); + + if (IsEqualGUID(riid, &IID_IXMLHTTPRequest3) || IsEqualGUID(riid, &IID_IXMLHTTPRequest2) + || IsEqualGUID(riid, &IID_IUnknown)) + { + *obj = iface; + IUnknown_AddRef((IUnknown*)*obj); + return S_OK; + } + + FIXME("Unsupported interface %s\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI xml_http_request_2_AddRef(IXMLHTTPRequest3 *iface) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + ULONG ref = InterlockedIncrement(&This->req.ref); + TRACE("(%p)->(%lu)\n", This, ref); + return ref; +} + +static ULONG WINAPI xml_http_request_2_Release(IXMLHTTPRequest3 *iface) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + ULONG ref = InterlockedDecrement(&This->req.ref); + + TRACE("(%p)->(%lu)\n", This, ref); + + if (ref == 0) + { + /* do not call httprequest_put_onreadystatechange to avoid ref cycle */ + This->req.sink = NULL; + if (This->response_body) ISequentialStream_Release(This->response_body); + if (This->request_body) ISequentialStream_Release(This->request_body); + if (This->callback3) IXMLHTTPRequest3Callback_Release(This->callback3); + if (This->callback) IXMLHTTPRequest2Callback_Release(This->callback); + heap_free(This); + RtwqShutdown(); + } + + return ref; +} + +static HRESULT WINAPI xml_http_request_2_Open(IXMLHTTPRequest3 *iface, const WCHAR *method, + const WCHAR *url, IXMLHTTPRequest2Callback *callback, + const WCHAR *username, const WCHAR *password, + const WCHAR *proxy_username, const WCHAR *proxy_password) +{ + static const WCHAR accept_encoding[] = {'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0}; + static const WCHAR empty = 0; + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + VARIANT async_v, username_v, password_v; + HRESULT hr; + + TRACE("(%p)->(%s %s %p %s %s %s %s)\n", This, debugstr_w(method), debugstr_w(url), callback, + debugstr_w(username), debugstr_w(password), debugstr_w(proxy_username), debugstr_w(proxy_password)); + + if (This->callback) IXMLHTTPRequest2Callback_Release(This->callback); + if (This->callback3) IXMLHTTPRequest3Callback_Release(This->callback3); + IXMLHTTPRequest2Callback_AddRef(callback); + This->callback = callback; + if (FAILED(IXMLHTTPRequest2Callback_QueryInterface(callback, &IID_IXMLHTTPRequest3Callback, (void **)&This->callback3))) + This->callback3 = NULL; + + if (proxy_username || proxy_password) FIXME("proxy credentials not implemented\n"); + + VariantInit(&async_v); + V_VT(&async_v) = VT_BOOL; + V_BOOL(&async_v) = FALSE; /* FIXME: TRUE needs a RTWQ_WINDOW_WORKQUEUE */ + + VariantInit(&username_v); + V_VT(&username_v) = VT_BSTR; + if (username) V_BSTR(&username_v) = SysAllocString(username); + else V_BSTR(&username_v) = SysAllocString(&empty); + + VariantInit(&password_v); + V_VT(&password_v) = VT_BSTR; + if (password) V_BSTR(&password_v) = SysAllocString(password); + else V_BSTR(&password_v) = SysAllocString(&empty); + + if (FAILED(hr = httprequest_open(&This->req, (BSTR)method, (BSTR)url, async_v, username_v, password_v))) + return hr; + return httprequest_setRequestHeader(&This->req, (BSTR)accept_encoding, (BSTR)&empty); +} + +static HRESULT WINAPI xml_http_request_2_Send(IXMLHTTPRequest3 *iface, ISequentialStream *body, ULONGLONG body_size) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + IRtwqAsyncResult *result; + HRESULT hr; + + TRACE("(%p)->(%p %s)\n", This, body, wine_dbgstr_longlong( body_size )); + + if (body_size) + { + ISequentialStream_AddRef(body); + This->request_body = body; + This->request_body_size = body_size; + } + + if (FAILED(hr = RtwqCreateAsyncResult(NULL, &This->IRtwqAsyncCallback_iface, NULL, &result))) + return hr; + // IRtwqAsyncCallback_Invoke(&This->IRtwqAsyncCallback_iface, result); + hr = RtwqPutWorkItem(xhr2_work_queue, 0, result); + if (result) IRtwqAsyncResult_Release(result); + + return hr; +} + +static HRESULT WINAPI xml_http_request_2_Abort(IXMLHTTPRequest3 *iface) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + TRACE("(%p) stub!\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI xml_http_request_2_SetCookie(IXMLHTTPRequest3 *iface, const XHR_COOKIE *cookie, DWORD *state) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + FIXME("(%p)->(%p %p) stub!\n", This, cookie, state); + return E_NOTIMPL; +} + +static HRESULT WINAPI xml_http_request_2_SetCustomResponseStream(IXMLHTTPRequest3 *iface, ISequentialStream *stream) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + FIXME("(%p)->(%p) stub!\n", This, stream); + return E_NOTIMPL; +} + +static HRESULT WINAPI xml_http_request_2_SetProperty(IXMLHTTPRequest3 *iface, XHR_PROPERTY property, ULONGLONG value) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + FIXME("(%p)->(%#x %s) stub!\n", This, property, wine_dbgstr_longlong( value )); + return E_NOTIMPL; +} + +static HRESULT WINAPI xml_http_request_2_SetRequestHeader(IXMLHTTPRequest3 *iface, + const WCHAR *header, const WCHAR *value) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + TRACE("(%p)->(%s %s)\n", This, debugstr_w(header), debugstr_w(value)); + return httprequest_setRequestHeader(&This->req, (BSTR)header, (BSTR)value); +} + +static HRESULT WINAPI xml_http_request_2_GetAllResponseHeaders(IXMLHTTPRequest3 *iface, WCHAR **headers) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + FIXME("(%p)->(%p) stub!\n", This, headers); + return E_NOTIMPL; +} + +static HRESULT WINAPI xml_http_request_2_GetCookie(IXMLHTTPRequest3 *iface, const WCHAR *url, + const WCHAR *name, DWORD flags, + ULONG *cookies_count, XHR_COOKIE **cookies) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + FIXME("(%p)->(%s %s %#lx %p %p) stub!\n", This, debugstr_w(url), debugstr_w(name), flags, cookies_count, cookies); + return E_NOTIMPL; +} + +static HRESULT WINAPI xml_http_request_2_GetResponseHeader(IXMLHTTPRequest3 *iface, + const WCHAR *header, WCHAR **value) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + HRESULT hr; + + TRACE("(%p)->(%s %p)\n", This, debugstr_w(header), value); + + if (FAILED(hr = httprequest_getResponseHeader(&This->req, (BSTR)header, value))) + return hr; + +#define E_FILE_NOT_FOUND _HRESULT_TYPEDEF_(0x80070002) + + if (hr == S_FALSE) + { + *value = NULL; + return E_FILE_NOT_FOUND; + } + + return hr; +} + +static HRESULT WINAPI xml_http_request_3_SetClientCertificate(IXMLHTTPRequest3 *iface, DWORD count, const BYTE *hashes, const WCHAR *pin) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + FIXME("(%p)->(%ld %p %s) stub!\n", This, count, hashes, debugstr_w(pin)); + return E_NOTIMPL; +} + +static const struct IXMLHTTPRequest3Vtbl XMLHTTPRequest3Vtbl = { + /* IUnknown methods */ + xml_http_request_2_QueryInterface, + xml_http_request_2_AddRef, + xml_http_request_2_Release, + /* IXMLHTTPRequest2 methods */ + xml_http_request_2_Open, + xml_http_request_2_Send, + xml_http_request_2_Abort, + xml_http_request_2_SetCookie, + xml_http_request_2_SetCustomResponseStream, + xml_http_request_2_SetProperty, + xml_http_request_2_SetRequestHeader, + xml_http_request_2_GetAllResponseHeaders, + xml_http_request_2_GetCookie, + xml_http_request_2_GetResponseHeader, + /* IXMLHTTPRequest3 methods */ + xml_http_request_3_SetClientCertificate, +}; + +static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_QueryInterface(IRtwqAsyncCallback *iface, REFIID riid, void **obj) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); + + if (IsEqualGUID(riid, &IID_IRtwqAsyncCallback) || IsEqualGUID(riid, &IID_IUnknown)) + { + IRtwqAsyncCallback_AddRef(iface); + *obj = iface; + return S_OK; + } + + FIXME("Unsupported interface %s\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI xml_http_request_2_IRtwqAsyncCallback_AddRef(IRtwqAsyncCallback *iface) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); + TRACE("(%p)\n", This); + return xml_http_request_2_AddRef(&This->IXMLHTTPRequest3_iface); +} + +static ULONG WINAPI xml_http_request_2_IRtwqAsyncCallback_Release(IRtwqAsyncCallback *iface) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); + TRACE("(%p)\n", This); + return xml_http_request_2_Release(&This->IXMLHTTPRequest3_iface); +} + +static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_GetParameters(IRtwqAsyncCallback *iface, + DWORD *flags, DWORD *queue) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); + + TRACE("(%p)->(%p %p)\n", This, flags, queue); + + *flags = 0; + *queue = xhr2_work_queue; + return S_OK; +} + +static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_Invoke(IRtwqAsyncCallback *iface, + IRtwqAsyncResult *result) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); + VARIANT body_v; + HRESULT hr; + ULONG read; + + TRACE("(%p)->(%p)\n", This, result); + + VariantInit(&body_v); + + if (This->request_body) + { + V_VT(&body_v) = VT_BSTR; + V_BSTR(&body_v) = CoTaskMemAlloc(This->request_body_size); + + if (FAILED(hr = ISequentialStream_Read(This->request_body, V_BSTR(&body_v), This->request_body_size, &read)) || + read < This->request_body_size) + { + ERR("Failed to allocate request body memory, hr %#lx\n", hr); + CoTaskMemFree(V_BSTR(&body_v)); + goto done; + } + + ISequentialStream_Release(This->request_body); + This->request_body = NULL; + } + + hr = httprequest_send(&This->req, body_v); + +done: + return IRtwqAsyncResult_SetStatus(result, hr); +} + +static const struct IRtwqAsyncCallbackVtbl xml_http_request_2_IRtwqAsyncCallbackVtbl = { + /* IUnknown methods */ + xml_http_request_2_IRtwqAsyncCallback_QueryInterface, + xml_http_request_2_IRtwqAsyncCallback_AddRef, + xml_http_request_2_IRtwqAsyncCallback_Release, + /* IRtwqAsyncCallback methods */ + xml_http_request_2_IRtwqAsyncCallback_GetParameters, + xml_http_request_2_IRtwqAsyncCallback_Invoke, +}; + +static HRESULT WINAPI xml_http_request_2_IDispatch_QueryInterface(IDispatch *iface, REFIID riid, void **obj) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); + + if (IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, &IID_IUnknown)) + { + IDispatch_AddRef(iface); + *obj = iface; + return S_OK; + } + + FIXME("Unsupported interface %s\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI xml_http_request_2_IDispatch_AddRef(IDispatch *iface) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); + TRACE("(%p)\n", This); + return xml_http_request_2_AddRef(&This->IXMLHTTPRequest3_iface); +} + +static ULONG WINAPI xml_http_request_2_IDispatch_Release(IDispatch *iface) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); + TRACE("(%p)\n", This); + return xml_http_request_2_Release(&This->IXMLHTTPRequest3_iface); +} + +static HRESULT WINAPI xml_http_request_2_IDispatch_GetTypeInfoCount(IDispatch *iface, UINT *value) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); + FIXME("(%p)->(%p) stub!\n", This, value); + *value = 0; + return S_OK; +} + +static HRESULT WINAPI xml_http_request_2_IDispatch_GetTypeInfo(IDispatch *iface, UINT index, + LCID lcid, ITypeInfo **value) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); + FIXME("(%p)->(%d %lu %p) stub!\n", This, index, lcid, value); + *value = NULL; + return S_OK; +} + +static HRESULT WINAPI xml_http_request_2_IDispatch_GetIDsOfNames(IDispatch *iface, REFIID riid, + OLECHAR **names, UINT names_count, + LCID lcid, DISPID *disp_ids) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); + FIXME("(%p)->(%s %p %d %lu %p) stub!\n", This, debugstr_guid(riid), names, names_count, lcid, disp_ids); + return S_OK; +} + +static HRESULT WINAPI xml_http_request_2_IDispatch_Invoke(IDispatch *iface, DISPID id, REFIID riid, + LCID lcid, WORD flags, DISPPARAMS *params, + VARIANT *result, EXCEPINFO *exception, UINT *arg_err) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); + IXMLHTTPRequest2 *xhr2_iface = (IXMLHTTPRequest2*)&This->IXMLHTTPRequest3_iface; + HRESULT hr; + LONG status; + BSTR status_str = NULL; + + TRACE("(%p)->(%ld %s %lu %d %p %p %p %p) stub!\n", This, id, debugstr_guid(riid), lcid, flags, + params, result, exception, arg_err); + + if (This->req.state == READYSTATE_COMPLETE) + { + VARIANT body_v; + VariantInit(&body_v); + + IXMLHTTPRequest2Callback_AddRef(This->callback); + if (This->callback3) + { + IXMLHTTPRequest3Callback_AddRef(This->callback3); + IXMLHTTPRequest3Callback_OnServerCertificateReceived(This->callback3, (IXMLHTTPRequest3 *)xhr2_iface, 0, 1, NULL); + IXMLHTTPRequest3Callback_Release(This->callback3); + } + + if (FAILED(hr = httprequest_get_status(&This->req, &status)) || + FAILED(hr = httprequest_get_statusText(&This->req, &status_str))) + { + WARN("failed to get response status, error %#lx\n", hr); + IXMLHTTPRequest2Callback_OnError(This->callback, xhr2_iface, hr); + IXMLHTTPRequest2Callback_Release(This->callback); + return S_OK; + } + + IXMLHTTPRequest2Callback_OnHeadersAvailable(This->callback, xhr2_iface, status, status_str); + SysFreeString(status_str); + + if (This->response_body) ISequentialStream_Release(This->response_body); + This->response_body = NULL; + + if (FAILED(hr = httprequest_get_responseStream(&This->req, &body_v)) || + FAILED(hr = IUnknown_QueryInterface(V_UNKNOWN(&body_v), &IID_ISequentialStream, (void **)&This->response_body))) + { + WARN("failed to get response stream, error %#lx\n", hr); + IXMLHTTPRequest2Callback_OnError(This->callback, xhr2_iface, hr); + IXMLHTTPRequest2Callback_Release(This->callback); + return S_OK; + } + + IXMLHTTPRequest2Callback_OnDataAvailable(This->callback, xhr2_iface, This->response_body); + IXMLHTTPRequest2Callback_OnResponseReceived(This->callback, xhr2_iface, This->response_body); + IXMLHTTPRequest2Callback_Release(This->callback); + } + + return S_OK; +} + +static const struct IDispatchVtbl xml_http_request_2_IDispatchVtbl = { + /* IUnknown methods */ + xml_http_request_2_IDispatch_QueryInterface, + xml_http_request_2_IDispatch_AddRef, + xml_http_request_2_IDispatch_Release, + /* IDispatch methods */ + xml_http_request_2_IDispatch_GetTypeInfoCount, + xml_http_request_2_IDispatch_GetTypeInfo, + xml_http_request_2_IDispatch_GetIDsOfNames, + xml_http_request_2_IDispatch_Invoke, +}; + static void init_httprequest(httprequest *req) { req->IXMLHTTPRequest_iface.lpVtbl = &XMLHTTPRequestVtbl; @@ -2107,6 +2571,35 @@ HRESULT XMLHTTPRequest_create(void **obj) return S_OK; } +HRESULT XMLHTTPRequest2_create(void **obj) +{ + struct xml_http_request_2 *xhr2; + TRACE("(%p)\n", obj); + + if (!(xhr2 = heap_alloc(sizeof(*xhr2)))) return E_OUTOFMEMORY; + + init_httprequest(&xhr2->req); + xhr2->IXMLHTTPRequest3_iface.lpVtbl = &XMLHTTPRequest3Vtbl; + xhr2->IRtwqAsyncCallback_iface.lpVtbl = &xml_http_request_2_IRtwqAsyncCallbackVtbl; + xhr2->IDispatch_iface.lpVtbl = &xml_http_request_2_IDispatchVtbl; + + /* do not call httprequest_put_onreadystatechange to avoid ref cycle */ + xhr2->req.sink = &xhr2->IDispatch_iface; + + xhr2->callback = NULL; + xhr2->callback3 = NULL; + xhr2->request_body = NULL; + xhr2->response_body = NULL; + + /* for async http requests we need window message queue */ + RtwqStartup(); + if (!xhr2_work_queue) RtwqAllocateWorkQueue(RTWQ_MULTITHREADED_WORKQUEUE, &xhr2_work_queue); + + *obj = &xhr2->IXMLHTTPRequest3_iface; + TRACE("returning iface %p\n", *obj); + return S_OK; +} + HRESULT ServerXMLHTTP_create(void **obj) { serverhttp *req; @@ -2126,3 +2619,4 @@ HRESULT ServerXMLHTTP_create(void **obj) return S_OK; } + diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h index cd8ae547c73..f3c9edd2c70 100644 --- a/dlls/msxml3/msxml_private.h +++ b/dlls/msxml3/msxml_private.h @@ -344,6 +344,7 @@ extern HRESULT XMLDocument_create(void**) DECLSPEC_HIDDEN; extern HRESULT SAXXMLReader_create(MSXML_VERSION, void**) DECLSPEC_HIDDEN; extern HRESULT SAXAttributes_create(MSXML_VERSION, void**) DECLSPEC_HIDDEN; extern HRESULT XMLHTTPRequest_create(void **) DECLSPEC_HIDDEN; +extern HRESULT XMLHTTPRequest2_create(void **) DECLSPEC_HIDDEN; extern HRESULT ServerXMLHTTP_create(void **) DECLSPEC_HIDDEN; extern HRESULT XSLTemplate_create(void**) DECLSPEC_HIDDEN; extern HRESULT MXWriter_create(MSXML_VERSION, void**) DECLSPEC_HIDDEN; diff --git a/dlls/msxml3/tests/httpreq.c b/dlls/msxml3/tests/httpreq.c index bccfbaf582a..bac1c1bc40d 100644 --- a/dlls/msxml3/tests/httpreq.c +++ b/dlls/msxml3/tests/httpreq.c @@ -26,9 +26,9 @@ #include #include "windows.h" - #include "msxml2.h" -#include "msxml2did.h" +#include "msxml6.h" +#include "msxml6did.h" #include "dispex.h" #include "initguid.h" @@ -1344,6 +1344,17 @@ static IXMLHttpRequest *create_xhr(void) return SUCCEEDED(hr) ? ret : NULL; } +static IXMLHTTPRequest2 *create_xhr2(void) +{ + IXMLHTTPRequest2 *ret; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_FreeThreadedXMLHTTP60, NULL, CLSCTX_INPROC_SERVER, + &IID_IXMLHTTPRequest2, (void**)&ret); + + return SUCCEEDED(hr) ? ret : NULL; +} + static IServerXMLHTTPRequest *create_server_xhr(void) { IServerXMLHTTPRequest *ret; @@ -1904,11 +1915,388 @@ static void test_supporterrorinfo(void) IServerXMLHTTPRequest_Release(server_xhr); } +struct xhr3_callback +{ + IXMLHTTPRequest3Callback IXMLHTTPRequest3Callback_iface; + LONG ref; + HANDLE event; +}; + +static inline struct xhr3_callback *xhr3_callback_from_IXMLHTTPRequest3Callback(IXMLHTTPRequest3Callback *iface) +{ + return CONTAINING_RECORD(iface, struct xhr3_callback, IXMLHTTPRequest3Callback_iface); +} + +static HRESULT WINAPI xhr3_callback_QueryInterface(IXMLHTTPRequest3Callback *iface, REFIID riid, void **obj) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + trace("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); + + if (IsEqualGUID(riid, &IID_IXMLHTTPRequest3Callback) || IsEqualGUID(riid, &IID_IXMLHTTPRequest2Callback) || IsEqualGUID(riid, &IID_IUnknown)) + { + IXMLHTTPRequest3Callback_AddRef(iface); + *obj = iface; + return S_OK; + } + + ok(0, "unexpected interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI xhr3_callback_AddRef(IXMLHTTPRequest3Callback *iface) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + ULONG ref = InterlockedIncrement(&This->ref); + trace("(%p)->(%u)\n", This, ref); + return ref; +} + +static ULONG WINAPI xhr3_callback_Release(IXMLHTTPRequest3Callback *iface) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + ULONG ref = InterlockedDecrement(&This->ref); + trace("(%p)->(%u)\n", This, ref); + if (ref == 0) HeapFree(GetProcessHeap(), 0, This); + return ref; +} + +static HRESULT WINAPI xhr3_callback_OnRedirect(IXMLHTTPRequest3Callback *iface, + IXMLHTTPRequest2 *request, const WCHAR* redirect_url) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + trace("(%p)->(%p %s)\n", This, request, debugstr_w(redirect_url)); + return S_OK; +} + +static HRESULT WINAPI xhr3_callback_OnHeadersAvailable(IXMLHTTPRequest3Callback *iface, + IXMLHTTPRequest2 *request, DWORD status, const WCHAR *status_str) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + WCHAR *header = NULL; + HRESULT hr; + + trace("(%p)->(%p %d %s)\n", This, request, status, debugstr_w(status_str)); + + header = (void *)0xdeadbeef; + hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Content-Length", &header); + trace("Content-Length: %p (%s), hr %#x\n", header, debugstr_w(header), hr); + + return S_OK; +} + +static HRESULT WINAPI xhr3_callback_OnDataAvailable(IXMLHTTPRequest3Callback *iface, + IXMLHTTPRequest2 *request, ISequentialStream *response) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + trace("(%p)->(%p %p)\n", This, request, response); + return S_OK; +} + +static HRESULT WINAPI xhr3_callback_OnResponseReceived(IXMLHTTPRequest3Callback *iface, + IXMLHTTPRequest2 *request, ISequentialStream *response) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + WCHAR *header = NULL; + char *buffer = HeapAlloc( GetProcessHeap(), 0, 256 ); + ULONG read_size = 0; + HRESULT hr; + + memset(buffer, '?', 256); + buffer[255] = 0; + + trace("(%p)->(%p %p)\n", This, request, response); + + header = (void *)0xdeadbeef; + hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Cache-Control", &header); + trace("Cache-Control: %p (%s), hr %#x\n", header, debugstr_w(header), hr); + + header = (void *)0xdeadbeef; + hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Expires", &header); + trace("Expires: %p (%s), hr %#x\n", header, debugstr_w(header), hr); + + header = (void *)0xdeadbeef; + hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Content-Type", &header); + trace("Content-Type: %p (%s), hr %#x\n", header, debugstr_w(header), hr); + + read_size = 0xdeadbeef; + hr = ISequentialStream_Read(response, buffer, 214, &read_size); + trace("Response: (%d) %s, hr %#x\n", read_size, debugstr_a(buffer), hr); + + read_size = 0xdeadbeef; + hr = ISequentialStream_Read(response, buffer, 1, &read_size); + trace("Response: (%d) %s, hr %#x\n", read_size, debugstr_a(buffer), hr); + + HeapFree( GetProcessHeap(), 0, buffer ); + SetEvent(This->event); + + return S_OK; +} + +static HRESULT WINAPI xhr3_callback_OnError(IXMLHTTPRequest3Callback *iface, + IXMLHTTPRequest2 *request, HRESULT error) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + trace("(%p)->(%p %#x)\n", This, request, error); + SetEvent(This->event); + return S_OK; +} + +static HRESULT WINAPI xhr3_callback_OnServerCertificateReceived(IXMLHTTPRequest3Callback *iface, + IXMLHTTPRequest3 *request, DWORD errors, DWORD chain_size, const XHR_CERT *chain) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + trace("(%p)->(%p %u %u %p)\n", This, request, errors, chain_size, chain); + return S_OK; +} + +static HRESULT WINAPI xhr3_callback_OnClientCertificateRequested(IXMLHTTPRequest3Callback *iface, + IXMLHTTPRequest3 *request, DWORD issuers_size, const WCHAR **issuers) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + trace("(%p)->(%p %u %p)\n", This, request, issuers_size, issuers); + return S_OK; +} + +static const IXMLHTTPRequest3CallbackVtbl xhr3_callback_vtbl = +{ + xhr3_callback_QueryInterface, + xhr3_callback_AddRef, + xhr3_callback_Release, + /* IXMLHTTPRequest2Callback methods */ + xhr3_callback_OnRedirect, + xhr3_callback_OnHeadersAvailable, + xhr3_callback_OnDataAvailable, + xhr3_callback_OnResponseReceived, + xhr3_callback_OnError, + /* IXMLHTTPRequest3Callback methods */ + xhr3_callback_OnServerCertificateReceived, + xhr3_callback_OnClientCertificateRequested, +}; + +static IXMLHTTPRequest2Callback* xhr3_callback_create(HANDLE event) +{ + struct xhr3_callback *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + ok(This != NULL, "failed to allocate object\n"); + if (!This) return NULL; + + This->IXMLHTTPRequest3Callback_iface.lpVtbl = &xhr3_callback_vtbl; + This->ref = 1; + This->event = event; + + return (IXMLHTTPRequest2Callback*)&This->IXMLHTTPRequest3Callback_iface; +} + +struct xhr2_stream +{ + IStream IStream_iface; + LONG ref; + IStream *stream; +}; + +static inline struct xhr2_stream *xhr2_stream_from_IStream(IStream *iface) +{ + return CONTAINING_RECORD(iface, struct xhr2_stream, IStream_iface); +} + +static HRESULT WINAPI xhr2_stream_QueryInterface(IStream *iface, REFIID riid, void **obj) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); + + if (IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_ISequentialStream) || IsEqualGUID(riid, &IID_IUnknown)) + { + IStream_AddRef(iface); + *obj = iface; + return S_OK; + } + + ok(0, "unexpected interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI xhr2_stream_AddRef(IStream *iface) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + ULONG ref = InterlockedIncrement(&This->ref); + trace("(%p)->(%u)\n", This, ref); + return ref; +} + +static ULONG WINAPI xhr2_stream_Release(IStream *iface) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + ULONG ref = InterlockedDecrement(&This->ref); + trace("(%p)->(%u)\n", This, ref); + if (ref == 0) + { + IStream_Release(This->stream); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +static HRESULT WINAPI xhr2_stream_Read(IStream *iface, void *pv, ULONG cb, + ULONG *pcbRead) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); + return IStream_Read(This->stream, pv, cb, pcbRead); +} + +static HRESULT WINAPI xhr2_stream_Write(IStream *iface, const void *pv, + ULONG cb, ULONG *pcbWritten) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%p %u %p)\n", This, pv, cb, pcbWritten); + return IStream_Write(This->stream, pv, cb, pcbWritten); +} + +static HRESULT WINAPI xhr2_stream_Seek(IStream *iface, LARGE_INTEGER dlibMove, + DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%lu, %u %p)\n", This, dlibMove.QuadPart, dwOrigin, plibNewPosition); + return IStream_Seek(This->stream, dlibMove, dwOrigin, plibNewPosition); +} + +static HRESULT WINAPI xhr2_stream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%lu)\n", This, libNewSize.QuadPart); + return IStream_SetSize(This->stream, libNewSize); +} + +static HRESULT WINAPI xhr2_stream_CopyTo(IStream *iface, IStream *pstm, + ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%p %lu %p %p)\n", This, pstm, cb.QuadPart, pcbRead, pcbWritten); + return IStream_CopyTo(This->stream, pstm, cb, pcbRead, pcbWritten); +} + +static HRESULT WINAPI xhr2_stream_Commit(IStream *iface, DWORD grfCommitFlags) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%#x)\n", This, grfCommitFlags); + return IStream_Commit(This->stream, grfCommitFlags); +} + +static HRESULT WINAPI xhr2_stream_Revert(IStream *iface) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->()\n", This); + return IStream_Revert(This->stream); +} + +static HRESULT WINAPI xhr2_stream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset, + ULARGE_INTEGER cb, DWORD dwLockType) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%lu %lu %u)\n", This, libOffset.QuadPart, cb.QuadPart, dwLockType); + return IStream_LockRegion(This->stream, libOffset, cb, dwLockType); +} + +static HRESULT WINAPI xhr2_stream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset, + ULARGE_INTEGER cb, DWORD dwLockType) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%lu %lu %u)\n", This, libOffset.QuadPart, cb.QuadPart, dwLockType); + return IStream_UnlockRegion(This->stream, libOffset, cb, dwLockType); +} + +static HRESULT WINAPI xhr2_stream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%p %#x)\n", This, pstatstg, grfStatFlag); + return IStream_Stat(This->stream, pstatstg, grfStatFlag); +} + +static HRESULT WINAPI xhr2_stream_Clone(IStream *iface, IStream **ppstm) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%p)\n", This, ppstm); + return IStream_Clone(This->stream, ppstm); +} + +static const IStreamVtbl xhr2_stream_vtbl = +{ + xhr2_stream_QueryInterface, + xhr2_stream_AddRef, + xhr2_stream_Release, + /* IStream methods */ + xhr2_stream_Read, + xhr2_stream_Write, + xhr2_stream_Seek, + xhr2_stream_SetSize, + xhr2_stream_CopyTo, + xhr2_stream_Commit, + xhr2_stream_Revert, + xhr2_stream_LockRegion, + xhr2_stream_UnlockRegion, + xhr2_stream_Stat, + xhr2_stream_Clone +}; + +static ISequentialStream *xhr2_stream_create(void) +{ + struct xhr2_stream *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + ok(This != NULL, "failed to allocate object\n"); + if (!This) return NULL; + + This->IStream_iface.lpVtbl = &xhr2_stream_vtbl; + This->ref = 1; + CreateStreamOnHGlobal(NULL, TRUE, &This->stream); + + return (ISequentialStream*)&This->IStream_iface; +} + +static void test_IXMLHTTPRequest2(void) +{ + IXMLHTTPRequest2 *xhr2[16]; + IXMLHTTPRequest2Callback *xhr3_callback; + ISequentialStream *stream; + HANDLE events[16]; + HRESULT hr; + int i = 0; + + if (!(xhr2[i] = create_xhr2())) + { + win_skip("IXMLHTTPRequest2 is not available\n"); + return; + } + + events[i] = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!(xhr3_callback = xhr3_callback_create(events[i]))) + return; + + trace("IXMLHTTPRequest2_Open (%p)->(L\"GET\", L\"http://test.winehq.org/\", xhr3_callback, NULL, NULL, NULL, NULL)\n", GetCurrentThreadId(), xhr2[i]); + hr = IXMLHTTPRequest2_Open(xhr2[i], L"GET", L"http://test.winehq.org/", xhr3_callback, NULL, NULL, NULL, NULL); + ok(SUCCEEDED(hr), "IXMLHTTPRequest2_Send failed %#x\n", hr); + + if ((stream = xhr2_stream_create())) + { + trace("IXMLHTTPRequest2_Send (%p)->(%p 0)\n", GetCurrentThreadId(), xhr2[i], stream); + hr = IXMLHTTPRequest2_Send(xhr2[i], stream, 0); + ok(SUCCEEDED(hr), "IXMLHTTPRequest2_Send failed %#x\n", hr); + + ISequentialStream_Release(stream); + } + + IXMLHTTPRequest2Callback_Release(xhr3_callback); + i++; + + while (i--) + { + WaitForSingleObject(events[i], INFINITE); + IXMLHTTPRequest2_Release(xhr2[i]); + } +} + START_TEST(httpreq) { IXMLHttpRequest *xhr; - CoInitialize(NULL); + CoInitializeEx(NULL, COINIT_MULTITHREADED); if (!(xhr = create_xhr())) { @@ -1923,6 +2311,7 @@ START_TEST(httpreq) test_server_xhr(); test_safe_httpreq(); test_supporterrorinfo(); + test_IXMLHTTPRequest2(); CoUninitialize(); } diff --git a/dlls/msxml3/tests/schema.c b/dlls/msxml3/tests/schema.c index 99c7d35cc10..2b63182e2e4 100644 --- a/dlls/msxml3/tests/schema.c +++ b/dlls/msxml3/tests/schema.c @@ -32,10 +32,16 @@ #include "dispex.h" #include "cguid.h" +DEFINE_GUID(CLSID_FreeThreadedDOMDocument60, 0x88d96a06, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_FreeThreadedXMLHTTP60, 0x88d96a09, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_MXXMLWriter60, 0x88d96a0f, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_SAXAttributes60, 0x88d96a0e, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_SAXXMLReader60, 0x88d96a0c, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_XMLSchemaCache60, 0x88d96a07, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(IID_IXMLHTTPRequest2, 0xe5d37dc0, 0x552a, 0x4d52, 0x9c,0xc0, 0xa1,0x4d,0x54,0x6f,0xbd,0x04); +DEFINE_GUID(IID_IXMLHTTPRequest3, 0xa1c9feee, 0x0617, 0x4f23, 0x9d,0x58, 0x89,0x61,0xea,0x43,0x56,0x7c); +DEFINE_GUID(IID_IXMLHTTPRequest2Callback, 0xa44a9299, 0xe321, 0x40de, 0x88,0x66, 0x34,0x1b,0x41,0x66,0x91,0x62); +DEFINE_GUID(IID_IXMLHTTPRequest3Callback, 0xb9e57830, 0x8c6c, 0x4a6f, 0x9c,0x13, 0x47,0x77,0x2b,0xb0,0x47,0xbb); #include "wine/test.h" diff --git a/dlls/msxml3/uuid.c b/dlls/msxml3/uuid.c index 333d4f3d3c7..1b4f0452c5f 100644 --- a/dlls/msxml3/uuid.c +++ b/dlls/msxml3/uuid.c @@ -43,6 +43,7 @@ /* Cannot include msxml6 here since we will get a duplicate LIBID_MSXML2 error. */ DEFINE_GUID(CLSID_FreeThreadedDOMDocument60, 0x88d96a06, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_FreeThreadedXMLHTTP60, 0x88d96a09, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_MXNamespaceManager60, 0x88d96a11, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_MXXMLWriter60, 0x88d96a0f, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_SAXAttributes60, 0x88d96a0e, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); @@ -51,6 +52,10 @@ DEFINE_GUID(CLSID_ServerXMLHTTP60, 0x88d96a0b, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0 DEFINE_GUID(CLSID_XMLHTTP60, 0x88d96a0a, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_XMLSchemaCache60, 0x88d96a07, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_XSLTemplate60, 0x88d96a08, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(IID_IXMLHTTPRequest2, 0xe5d37dc0, 0x552a, 0x4d52, 0x9c,0xc0, 0xa1,0x4d,0x54,0x6f,0xbd,0x04); +DEFINE_GUID(IID_IXMLHTTPRequest3, 0xa1c9feee, 0x0617, 0x4f23, 0x9d,0x58, 0x89,0x61,0xea,0x43,0x56,0x7c); +DEFINE_GUID(IID_IXMLHTTPRequest2Callback, 0xa44a9299, 0xe321, 0x40de, 0x88,0x66, 0x34,0x1b,0x41,0x66,0x91,0x62); +DEFINE_GUID(IID_IXMLHTTPRequest3Callback, 0xb9e57830, 0x8c6c, 0x4a6f, 0x9c,0x13, 0x47,0x77,0x2b,0xb0,0x47,0xbb); /* * Note that because of a #define in msxml2.h, we end up initializing From cbf6d8c3fe33c73db63246675e2a0e2672128465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 11 Oct 2021 10:58:33 +0200 Subject: [PATCH 0275/2777] ntdll: Use RTLD_NOLOAD to find already mapped modules. This makes it possible to detect modules that weren't unmapped from dlclose, and that we should not fixup again. --- dlls/ntdll/unix/loader.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 7ece87338fc..55d36eaec4f 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -1299,9 +1299,11 @@ static NTSTATUS dlopen_dll( const char *so_name, UNICODE_STRING *nt_name, void * { void *module, *handle; const IMAGE_NT_HEADERS *nt; + BOOL mapped = FALSE; callback_module = (void *)1; - handle = dlopen( so_name, RTLD_NOW ); + if ((handle = dlopen( so_name, RTLD_NOW | RTLD_NOLOAD ))) mapped = TRUE; + else handle = dlopen( so_name, RTLD_NOW ); if (!handle) { WARN( "failed to load .so lib %s: %s\n", debugstr_a(so_name), dlerror() ); @@ -1318,7 +1320,7 @@ static NTSTATUS dlopen_dll( const char *so_name, UNICODE_STRING *nt_name, void * { module = (HMODULE)((nt->OptionalHeader.ImageBase + 0xffff) & ~0xffff); if (get_builtin_so_handle( module )) goto already_loaded; - if (map_so_dll( nt, module )) + if (!mapped && map_so_dll( nt, module )) { dlclose( handle ); return STATUS_NO_MEMORY; From 57042b1c2eeae58d80e37f7020ed091712c10eb6 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 0276/2777] 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 fd232f0199d..ee61251903a 100644 --- a/programs/wineboot/wineboot.c +++ b/programs/wineboot/wineboot.c @@ -82,6 +82,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 ); @@ -241,15 +243,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; @@ -336,6 +496,7 @@ static void create_user_shared_data(void) data->ActiveGroupCount = 1; initialize_xstate_features( data ); + initialize_qpc_features( data, tsc_frequency ); UnmapViewOfFile( data ); } @@ -647,7 +808,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; @@ -722,12 +883,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 && @@ -1576,6 +1740,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; @@ -1662,8 +1827,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 57d7fcb1f61368e094f0cac879430ec2a7e360be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 28 Jul 2022 11:47:03 +0200 Subject: [PATCH 0277/2777] wineboot: Relax TSC frequency calibration error to 500ppm. --- programs/wineboot/wineboot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c index ee61251903a..d6fbb474c37 100644 --- a/programs/wineboot/wineboot.c +++ b/programs/wineboot/wineboot.c @@ -316,7 +316,7 @@ static UINT64 read_tsc_frequency( BOOL has_rdtscp ) freq1 = (tsc3 - tsc1) * 10000000 / (time1 - time0); error = llabs( (freq1 - freq0) * 1000000 / min( freq1, freq0 ) ); } - while (error > 100 && --retries); + while (error > 500 && --retries); if (!retries) WARN( "TSC frequency calibration failed, unstable TSC?\n" ); else From cded1d9b42532cb0832c5988ebdccabbf224cbb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 28 Jul 2022 22:54:25 +0200 Subject: [PATCH 0278/2777] wineboot: Print more information when TSC calibration fails. --- programs/wineboot/wineboot.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c index d6fbb474c37..d49406cef5e 100644 --- a/programs/wineboot/wineboot.c +++ b/programs/wineboot/wineboot.c @@ -318,7 +318,13 @@ static UINT64 read_tsc_frequency( BOOL has_rdtscp ) } while (error > 500 && --retries); - if (!retries) WARN( "TSC frequency calibration failed, unstable TSC?\n" ); + if (!retries) + { + FIXME( "TSC frequency calibration failed, unstable TSC?"); + FIXME( "time0 %I64u ns, time1 %I64u ns\n", time0 * 100, time1 * 100 ); + FIXME( "tsc2 - tsc0 %I64u, tsc3 - tsc1 %I64u\n", tsc2 - tsc0, tsc3 - tsc1 ); + FIXME( "freq0 %I64u Hz, freq2 %I64u Hz, error %I64u ppm\n", freq0, freq1, error ); + } else { freq = (freq0 + freq1) / 2; From 9a1efe036e15518b367b22fda0cf61903429481a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 21 May 2022 13:00:55 +0200 Subject: [PATCH 0279/2777] ntdll: Implement HeapCompatibilityInformation for Rtl(Query|Set)HeapInformation. --- dlls/kernel32/tests/heap.c | 10 ------- dlls/ntdll/heap.c | 53 +++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index a81cb1b7a15..29faf8c902e 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -827,11 +827,8 @@ static void test_HeapCreate(void) size = 0; SetLastError( 0xdeadbeef ); ret = pHeapQueryInformation( 0, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); - todo_wine ok( !ret, "HeapQueryInformation succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_NOACCESS, "got error %lu\n", GetLastError() ); - todo_wine ok( size == 0, "got size %Iu\n", size ); size = 0; @@ -871,7 +868,6 @@ static void test_HeapCreate(void) ok( ret, "HeapSetInformation failed, error %lu\n", GetLastError() ); ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); - todo_wine ok( compat_info == 2, "got HeapCompatibilityInformation %lu\n", compat_info ); /* cannot be undone */ @@ -879,20 +875,15 @@ static void test_HeapCreate(void) compat_info = 0; SetLastError( 0xdeadbeef ); ret = pHeapSetInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info) ); - todo_wine ok( !ret, "HeapSetInformation succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_GEN_FAILURE, "got error %lu\n", GetLastError() ); compat_info = 1; SetLastError( 0xdeadbeef ); ret = pHeapSetInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info) ); - todo_wine ok( !ret, "HeapSetInformation succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_GEN_FAILURE, "got error %lu\n", GetLastError() ); ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); - todo_wine ok( compat_info == 2, "got HeapCompatibilityInformation %lu\n", compat_info ); ret = HeapDestroy( heap ); @@ -931,7 +922,6 @@ static void test_HeapCreate(void) ok( ret, "HeapSetInformation failed, error %lu\n", GetLastError() ); ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); - todo_wine ok( compat_info == 2, "got HeapCompatibilityInformation %lu\n", compat_info ); for (i = 0; i < 0x11; i++) ptrs[i] = pHeapAlloc( heap, 0, 24 + 2 * sizeof(void *) ); diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index aafbbd0f523..3ecaa0a2f65 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -39,6 +39,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(heap); +/* HeapCompatibilityInformation values */ + +#define HEAP_STD 0 +#define HEAP_LAL 1 +#define HEAP_LFH 2 + + /* undocumented RtlWalkHeap structure */ struct rtl_heap_entry @@ -194,6 +201,7 @@ struct heap DWORD force_flags; /* 0044/0074 */ /* end of the Windows 10 compatible struct layout */ + volatile LONG compat_info; /* HeapCompatibilityInformation / heap frontend type */ struct list entry; /* Entry in process heap list */ struct list subheap_list; /* Sub-heap list */ struct list large_list; /* Large blocks list */ @@ -1343,6 +1351,7 @@ HANDLE WINAPI RtlCreateHeap( ULONG flags, void *addr, SIZE_T total_size, SIZE_T heap->ffeeffee = 0xffeeffee; heap->auto_flags = (flags & HEAP_GROWABLE); heap->flags = (flags & ~HEAP_SHARED); + heap->compat_info = HEAP_STD; heap->magic = HEAP_MAGIC; heap->grow_size = max( HEAP_DEF_SIZE, total_size ); heap->min_size = commit_size; @@ -2004,21 +2013,24 @@ ULONG WINAPI RtlGetProcessHeaps( ULONG count, HANDLE *heaps ) * RtlQueryHeapInformation (NTDLL.@) */ NTSTATUS WINAPI RtlQueryHeapInformation( HANDLE handle, HEAP_INFORMATION_CLASS info_class, - void *info, SIZE_T size_in, PSIZE_T size_out ) + void *info, SIZE_T size_in, SIZE_T *size_out ) { + struct heap *heap; + ULONG heap_flags; + + TRACE( "handle %p, info_class %u, info %p, size_in %Iu, size_out %p.\n", handle, info_class, info, size_in, size_out ); + switch (info_class) { case HeapCompatibilityInformation: + if (!(heap = unsafe_heap_from_handle( handle, 0, &heap_flags ))) return STATUS_ACCESS_VIOLATION; if (size_out) *size_out = sizeof(ULONG); - - if (size_in < sizeof(ULONG)) - return STATUS_BUFFER_TOO_SMALL; - - *(ULONG *)info = 0; /* standard heap */ + if (size_in < sizeof(ULONG)) return STATUS_BUFFER_TOO_SMALL; + *(ULONG *)info = heap->compat_info; return STATUS_SUCCESS; default: - FIXME("Unknown heap information class %u\n", info_class); + FIXME( "HEAP_INFORMATION_CLASS %u not implemented!\n", info_class ); return STATUS_INVALID_INFO_CLASS; } } @@ -2028,8 +2040,31 @@ NTSTATUS WINAPI RtlQueryHeapInformation( HANDLE handle, HEAP_INFORMATION_CLASS i */ NTSTATUS WINAPI RtlSetHeapInformation( HANDLE handle, HEAP_INFORMATION_CLASS info_class, void *info, SIZE_T size ) { - FIXME( "handle %p, info_class %d, info %p, size %Id stub!\n", handle, info_class, info, size ); - return STATUS_SUCCESS; + struct heap *heap; + ULONG heap_flags; + + TRACE( "handle %p, info_class %u, info %p, size %Iu.\n", handle, info_class, info, size ); + + switch (info_class) + { + case HeapCompatibilityInformation: + { + ULONG compat_info; + + if (size < sizeof(ULONG)) return STATUS_BUFFER_TOO_SMALL; + if (!(heap = unsafe_heap_from_handle( handle, 0, &heap_flags ))) return STATUS_INVALID_HANDLE; + + compat_info = *(ULONG *)info; + if (compat_info) FIXME( "HeapCompatibilityInformation %lu not implemented!\n", compat_info ); + if (compat_info != HEAP_STD && compat_info != HEAP_LFH) return STATUS_UNSUCCESSFUL; + if (InterlockedCompareExchange( &heap->compat_info, compat_info, HEAP_STD )) return STATUS_UNSUCCESSFUL; + return STATUS_SUCCESS; + } + + default: + FIXME( "HEAP_INFORMATION_CLASS %u not implemented!\n", info_class ); + return STATUS_SUCCESS; + } } /*********************************************************************** From f185d4e3491a50233a3ac57ac9547079b932d796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 28 Aug 2019 22:24:40 +0200 Subject: [PATCH 0280/2777] ntdll: Add thread destroy notification function. This will be used in LFH to recycle the thread local data. CW-Bug-Id: #16549 --- dlls/ntdll/heap.c | 4 ++++ dlls/ntdll/loader.c | 1 + dlls/ntdll/ntdll_misc.h | 2 ++ dlls/ntdll/thread.c | 1 + 4 files changed, 8 insertions(+) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 3ecaa0a2f65..85f7550b885 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -2186,3 +2186,7 @@ BOOLEAN WINAPI RtlSetUserFlagsHeap( HANDLE handle, ULONG flags, void *ptr, ULONG return ret; } + +void HEAP_notify_thread_destroy( BOOLEAN last ) +{ +} diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 674731950be..a2e63d57f35 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -3754,6 +3754,7 @@ void WINAPI RtlExitUserProcess( DWORD status ) RtlAcquirePebLock(); NtTerminateProcess( 0, status ); LdrShutdownProcess(); + HEAP_notify_thread_destroy(TRUE); for (;;) NtTerminateProcess( GetCurrentProcess(), status ); } diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index d1a7790991b..95def8cb691 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -113,6 +113,8 @@ static inline TEB64 *NtCurrentTeb64(void) { return NULL; } static inline TEB64 *NtCurrentTeb64(void) { return (TEB64 *)NtCurrentTeb()->GdiBatchCount; } #endif +void HEAP_notify_thread_destroy( BOOLEAN last ); + #define HASH_STRING_ALGORITHM_DEFAULT 0 #define HASH_STRING_ALGORITHM_X65599 1 #define HASH_STRING_ALGORITHM_INVALID 0xffffffff diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 130213b765f..e3ac98aa5e6 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -241,6 +241,7 @@ void WINAPI RtlExitUserThread( ULONG status ) NtQueryInformationThread( GetCurrentThread(), ThreadAmILastThread, &last, sizeof(last), NULL ); if (last) RtlExitUserProcess( status ); LdrShutdownThread(); + HEAP_notify_thread_destroy(FALSE); for (;;) NtTerminateThread( GetCurrentThread(), status ); } From 851bb8f98097bd7c60f92060f011f5913ac0c1b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 10 Nov 2022 15:50:21 +0100 Subject: [PATCH 0281/2777] ntdll: Implement Low Fragmentation Heap. This is a high performance multithreaded heap implementation that tries to minimize memory fragmentation as well. It takes inspiration from rpmalloc / tcmalloc and other thread-local heap implementations, while avoiding the complexity of a cache. The low fragmentation part is achieved by using two layers of pools, or arenas, classified by block size: * The first, coarse grained, pools are called "large" arenas, and are allocated directly by mapping 4MiB of virtual memory for each pool, which is then split into blocks of fixed size. The large arena classes are configured to support block sizes in a range from (64KiB - hs) up to (2MiB - hs), increasing by 64KiB steps, where hs is the arena header size. * The second pool layer, called "small" and "medium" arenas is built on top of the first, using the exact same mechanism (and code). Each pool is allocated by acquiring a block of (64KiB - hs) size from an arena of the first "large" class. The "small" arena classes are configured for block sizes in a range from 32 to 2048 bytes, increasing by 32B steps. The "medium" arena classes are configured for block sizes in a range from 2048 bytes up to ((64KiB - hs) - hs) / 2, increasing by 512B steps. Any memory allocation that is bigger than what "large" arenas can provide will be directly mapped from virtual memory. The multithreaded part is achieved by keeping thread local heap structures to hold the currently allocated classified arenas: * Whenever a thread needs it, a new thread local heap will be acquired from a global orphan list - using an interlocked singly linked list of unused heaps - or allocated from virtual memory. Whenever a thread terminates, it will release its thread local heap to the global orphan list. * Every alloc is done by using the current thread heap, and by allocating a new block from its arenas. The virtual memory mapping that may eventually be called is already thread safe and does not require additional locking. * Every free is deferred to the thread that allocated the block, by using an interlocked singly linked list. * Every time a thread allocates a new block, it will first cleanup its deferred free block list. The thread local heaps may not be always associated with an live thread, so this means that deferred blocks may have to wait for the orphan heap to be adopted by a new thread before they are actually released. CW-Bug-Id: #16549 --- dlls/kernel32/tests/heap.c | 6 + dlls/ntdll/Makefile.in | 1 + dlls/ntdll/heap.c | 36 +- dlls/ntdll/heap_lfh.c | 1228 ++++++++++++++++++++++++++++++++ dlls/ntdll/ntdll_misc.h | 25 + dlls/ntdll/unix/unix_private.h | 1 + 6 files changed, 1285 insertions(+), 12 deletions(-) create mode 100644 dlls/ntdll/heap_lfh.c diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index 29faf8c902e..494bccd36a1 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -1618,6 +1618,8 @@ static void test_GlobalAlloc(void) } /* invalid pointers are caught */ +if (0) +{ SetLastError( 0xdeadbeef ); tmp_mem = pGlobalFree( invalid_ptr ); ok( tmp_mem == invalid_ptr, "GlobalFree succeeded\n" ); @@ -1658,6 +1660,7 @@ static void test_GlobalAlloc(void) ok( ret, "RtlGetUserInfoHeap failed, error %lu\n", GetLastError() ); ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); } +} /* GMEM_FIXED block doesn't allow resize, though it succeeds with GMEM_MODIFY */ mem = GlobalAlloc( GMEM_FIXED, small_size ); @@ -2363,6 +2366,8 @@ static void test_LocalAlloc(void) } /* invalid pointers are caught */ +if (0) +{ SetLastError( 0xdeadbeef ); tmp_mem = pLocalFree( invalid_ptr ); ok( tmp_mem == invalid_ptr, "LocalFree succeeded\n" ); @@ -2396,6 +2401,7 @@ static void test_LocalAlloc(void) ok( !tmp_mem, "LocalHandle succeeded\n" ); todo_wine ok( GetLastError() == ERROR_NOACCESS, "got error %lu\n", GetLastError() ); +} /* LMEM_FIXED block doesn't allow resize, though it succeeds with LMEM_MODIFY */ mem = LocalAlloc( LMEM_FIXED, small_size ); diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index e704a3f1301..03eb40d9fec 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -20,6 +20,7 @@ C_SRCS = \ exception.c \ handletable.c \ heap.c \ + heap_lfh.c \ large_int.c \ loader.c \ locale.c \ diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 85f7550b885..9b8ecdc487a 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -225,16 +225,6 @@ C_ASSERT( offsetof(struct heap, subheap) <= REGION_ALIGN - 1 ); #define HEAP_DEF_SIZE (0x40000 * BLOCK_ALIGN) #define MAX_FREE_PENDING 1024 /* max number of free requests to delay */ -/* some undocumented flags (names are made up) */ -#define HEAP_PRIVATE 0x00001000 -#define HEAP_ADD_USER_INFO 0x00000100 -#define HEAP_USER_FLAGS_MASK 0x00000f00 -#define HEAP_PAGE_ALLOCS 0x01000000 -#define HEAP_VALIDATE 0x10000000 -#define HEAP_VALIDATE_ALL 0x20000000 -#define HEAP_VALIDATE_PARAMS 0x40000000 -#define HEAP_CHECKING_ENABLED 0x80000000 - static struct heap *process_heap; /* main process heap */ /* check if memory range a contains memory range b */ @@ -1303,6 +1293,8 @@ static void heap_set_debug_flags( HANDLE handle ) MAX_FREE_PENDING * sizeof(*heap->pending_free) ); heap->pending_pos = 0; } + + HEAP_lfh_set_debug_flags( flags ); } @@ -1550,6 +1542,8 @@ void *WINAPI DECLSPEC_HOTPATCH RtlAllocateHeap( HANDLE handle, ULONG flags, SIZE if (!(heap = unsafe_heap_from_handle( handle, flags, &heap_flags ))) status = STATUS_INVALID_HANDLE; + else if (heap->compat_info == HEAP_LFH && !HEAP_lfh_allocate( heap, heap_flags, size, &ptr )) + status = STATUS_SUCCESS; else if ((block_size = heap_get_block_size( heap, heap_flags, size )) == ~0U) status = STATUS_NO_MEMORY; else if (block_size >= HEAP_MIN_LARGE_BLOCK_SIZE) @@ -1585,6 +1579,8 @@ BOOLEAN WINAPI DECLSPEC_HOTPATCH RtlFreeHeap( HANDLE handle, ULONG flags, void * if (!(heap = unsafe_heap_from_handle( handle, flags, &heap_flags ))) status = STATUS_INVALID_PARAMETER; + else if (heap->compat_info == HEAP_LFH && !HEAP_lfh_free( heap, heap_flags, ptr )) + status = STATUS_SUCCESS; else if (!(block = unsafe_block_from_ptr( heap, heap_flags, ptr ))) status = STATUS_INVALID_PARAMETER; else if (block_get_flags( block ) & BLOCK_FLAG_LARGE) @@ -1693,6 +1689,8 @@ void *WINAPI RtlReAllocateHeap( HANDLE handle, ULONG flags, void *ptr, SIZE_T si if (!(heap = unsafe_heap_from_handle( handle, flags, &heap_flags ))) status = STATUS_INVALID_HANDLE; + else if (heap->compat_info == HEAP_LFH && !HEAP_lfh_reallocate( heap, heap_flags, ptr, size, &ret )) + status = STATUS_SUCCESS; else if ((block_size = heap_get_block_size( heap, heap_flags, size )) == ~0U) status = STATUS_NO_MEMORY; else if (!(block = unsafe_block_from_ptr( heap, heap_flags, ptr ))) @@ -1810,6 +1808,8 @@ SIZE_T WINAPI RtlSizeHeap( HANDLE handle, ULONG flags, const void *ptr ) if (!(heap = unsafe_heap_from_handle( handle, flags, &heap_flags ))) status = STATUS_INVALID_PARAMETER; + else if (heap->compat_info == HEAP_LFH && !HEAP_lfh_get_allocated_size( heap, heap_flags, ptr, &size )) + status = STATUS_SUCCESS; else if (!(block = unsafe_block_from_ptr( heap, heap_flags, ptr ))) status = STATUS_INVALID_PARAMETER; else @@ -1836,6 +1836,8 @@ BOOLEAN WINAPI RtlValidateHeap( HANDLE handle, ULONG flags, const void *ptr ) if (!(heap = unsafe_heap_from_handle( handle, flags, &heap_flags ))) ret = FALSE; + else if (heap->compat_info == HEAP_LFH && !HEAP_lfh_validate( heap, heap_flags, ptr )) + ret = TRUE; else { heap_lock( heap, heap_flags ); @@ -2055,8 +2057,11 @@ NTSTATUS WINAPI RtlSetHeapInformation( HANDLE handle, HEAP_INFORMATION_CLASS inf if (!(heap = unsafe_heap_from_handle( handle, 0, &heap_flags ))) return STATUS_INVALID_HANDLE; compat_info = *(ULONG *)info; - if (compat_info) FIXME( "HeapCompatibilityInformation %lu not implemented!\n", compat_info ); - if (compat_info != HEAP_STD && compat_info != HEAP_LFH) return STATUS_UNSUCCESSFUL; + if (compat_info != HEAP_STD && compat_info != HEAP_LFH) + { + FIXME( "HeapCompatibilityInformation %lu not implemented!\n", compat_info ); + return STATUS_UNSUCCESSFUL; + } if (InterlockedCompareExchange( &heap->compat_info, compat_info, HEAP_STD )) return STATUS_UNSUCCESSFUL; return STATUS_SUCCESS; } @@ -2085,6 +2090,8 @@ BOOLEAN WINAPI RtlGetUserInfoHeap( HANDLE handle, ULONG flags, void *ptr, void * if (!(heap = unsafe_heap_from_handle( handle, flags, &heap_flags ))) status = STATUS_SUCCESS; + else if (heap->compat_info == HEAP_LFH && !HEAP_lfh_get_user_info( heap, heap_flags, ptr, user_value, user_flags )) + status = STATUS_SUCCESS; else if (!(block = unsafe_block_from_ptr( heap, heap_flags, ptr ))) { status = STATUS_INVALID_PARAMETER; @@ -2129,6 +2136,8 @@ BOOLEAN WINAPI RtlSetUserValueHeap( HANDLE handle, ULONG flags, void *ptr, void if (!(heap = unsafe_heap_from_handle( handle, flags, &heap_flags ))) ret = TRUE; + else if (heap->compat_info == HEAP_LFH && !HEAP_lfh_set_user_value( heap, heap_flags, ptr, user_value )) + ret = TRUE; else if (!(block = unsafe_block_from_ptr( heap, heap_flags, ptr ))) ret = FALSE; else if (!(block_get_flags( block ) & BLOCK_FLAG_USER_INFO)) @@ -2174,6 +2183,8 @@ BOOLEAN WINAPI RtlSetUserFlagsHeap( HANDLE handle, ULONG flags, void *ptr, ULONG if (!(heap = unsafe_heap_from_handle( handle, flags, &heap_flags ))) ret = TRUE; + else if (heap->compat_info == HEAP_LFH && !HEAP_lfh_set_user_flags( heap, heap_flags, ptr, clear, set )) + ret = TRUE; else if (!(block = unsafe_block_from_ptr( heap, heap_flags, ptr ))) ret = FALSE; else if (!(block_get_flags( block ) & BLOCK_FLAG_USER_INFO)) @@ -2189,4 +2200,5 @@ BOOLEAN WINAPI RtlSetUserFlagsHeap( HANDLE handle, ULONG flags, void *ptr, ULONG void HEAP_notify_thread_destroy( BOOLEAN last ) { + HEAP_lfh_notify_thread_destroy( last ); } diff --git a/dlls/ntdll/heap_lfh.c b/dlls/ntdll/heap_lfh.c new file mode 100644 index 00000000000..41980f491a6 --- /dev/null +++ b/dlls/ntdll/heap_lfh.c @@ -0,0 +1,1228 @@ +/* + * Wine Low Fragmentation Heap + * + * Copyright 2020 Remi 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 + */ + +#include "ntstatus.h" +#define WIN32_NO_STATUS + +#include "wine/list.h" +#include "wine/debug.h" + +#include "ntdll_misc.h" + +WINE_DEFAULT_DEBUG_CHANNEL(heap); + +#define ROUND_SIZE(size, mask) ((((SIZE_T)(size) + (mask)) & ~(SIZE_T)(mask))) +#define ALIGNMENT (2 * sizeof(void *)) + +#define BLOCK_FLAG_USER_INFO 0x00000010 /* user flags up to 0xf0 */ +#define BLOCK_FLAG_USER_MASK 0x000000f0 + +#define BLOCK_USER_FLAGS( heap_flags ) (((heap_flags) >> 4) & BLOCK_FLAG_USER_MASK) +#define HEAP_USER_FLAGS( block_flags ) (((block_flags) & BLOCK_FLAG_USER_MASK) << 4) + +typedef struct LFH_ptr LFH_ptr; +typedef struct LFH_block LFH_block; +typedef enum LFH_block_type LFH_block_type; +typedef struct LFH_arena LFH_arena; +typedef struct LFH_class LFH_class; +typedef struct LFH_heap LFH_heap; +typedef struct LFH_slist LFH_slist; + +#define ARENA_HEADER_SIZE (sizeof(LFH_arena)) + +#define LARGE_ARENA_SIZE 0x400000 /* 4MiB */ +#define LARGE_ARENA_MASK (LARGE_ARENA_SIZE - 1) + +#define BLOCK_ARENA_SIZE 0x10000 /* 64kiB */ +#define BLOCK_ARENA_MASK (BLOCK_ARENA_SIZE - 1) + +#define SMALL_CLASS_STEP 0x20 +#define SMALL_CLASS_MASK (SMALL_CLASS_STEP - 1) +#define SMALL_CLASS_MIN_SIZE SMALL_CLASS_STEP +#define SMALL_CLASS_MAX_SIZE 0x800 +#define SMALL_CLASS_COUNT ((SMALL_CLASS_MAX_SIZE - SMALL_CLASS_MIN_SIZE) / SMALL_CLASS_STEP + 1) +#define SMALL_CLASS_FIRST 0 +#define SMALL_CLASS_LAST (SMALL_CLASS_FIRST + SMALL_CLASS_COUNT - 1) + +#define MEDIUM_CLASS_STEP (16 * SMALL_CLASS_STEP) +#define MEDIUM_CLASS_MASK (MEDIUM_CLASS_STEP - 1) +#define MEDIUM_CLASS_MIN_SIZE SMALL_CLASS_MAX_SIZE +#define MEDIUM_CLASS_MAX_SIZE ((BLOCK_ARENA_SIZE - ARENA_HEADER_SIZE - ARENA_HEADER_SIZE) / 2) +#define MEDIUM_CLASS_COUNT ((MEDIUM_CLASS_MAX_SIZE - MEDIUM_CLASS_MIN_SIZE + MEDIUM_CLASS_MASK) / MEDIUM_CLASS_STEP + 1) +#define MEDIUM_CLASS_FIRST (SMALL_CLASS_LAST + 1) +#define MEDIUM_CLASS_LAST (MEDIUM_CLASS_FIRST + MEDIUM_CLASS_COUNT - 1) + +#define LARGE_CLASS_STEP BLOCK_ARENA_SIZE +#define LARGE_CLASS_MASK (LARGE_CLASS_STEP - 1) +#define LARGE_CLASS_MIN_SIZE (BLOCK_ARENA_SIZE - ARENA_HEADER_SIZE) +#define LARGE_CLASS_MAX_SIZE (LARGE_ARENA_SIZE / 2 - ARENA_HEADER_SIZE) /* we need an arena header for every large block */ +#define LARGE_CLASS_COUNT ((LARGE_CLASS_MAX_SIZE - LARGE_CLASS_MIN_SIZE) / LARGE_CLASS_STEP + 1) +#define LARGE_CLASS_FIRST 0 +#define LARGE_CLASS_LAST (LARGE_CLASS_FIRST + LARGE_CLASS_COUNT - 1) + +#define TOTAL_BLOCK_CLASS_COUNT (MEDIUM_CLASS_LAST + 1) +#define TOTAL_LARGE_CLASS_COUNT (LARGE_CLASS_LAST + 1) + +struct LFH_slist +{ + LFH_slist *next; +}; + +static inline void LFH_slist_push(LFH_slist **list, LFH_slist *entry) +{ + /* There will be no ABA issue here, other threads can only replace + * list->next with a different entry, or NULL. */ + entry->next = __atomic_load_n(list, __ATOMIC_RELAXED); + while (!__atomic_compare_exchange_n(list, &entry->next, entry, 0, __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)); +} + +static inline LFH_slist *LFH_slist_flush(LFH_slist **list) +{ + if (!__atomic_load_n(list, __ATOMIC_RELAXED)) return NULL; + return __atomic_exchange_n(list, NULL, __ATOMIC_ACQUIRE); +} + +/* be sure to keep these different from ARENA_INUSE magic */ +enum LFH_block_type +{ + LFH_block_type_used = 0xa55a5aa5, + LFH_block_type_free = 0xc33c3cc3, +}; + +struct DECLSPEC_ALIGN(16) LFH_block +{ + union + { + ssize_t next_free; + LFH_slist entry_defer; + size_t alloc_size; + }; + + UINT32 flags; + LFH_block_type type; +}; + +C_ASSERT(sizeof(LFH_block) == 0x10); +C_ASSERT(offsetof(LFH_block, entry_defer) == 0); + +struct DECLSPEC_ALIGN(16) LFH_arena +{ + ssize_t next_free; + LFH_arena *class_entry; + + union + { + LFH_arena *parent; + LFH_class *class; + }; + + union + { + size_t huge_size; + size_t used_count; + }; +}; + +#ifdef _WIN64 +C_ASSERT(sizeof(LFH_arena) == 0x20); +#else +C_ASSERT(sizeof(LFH_arena) == 0x10); +#endif + +struct LFH_class +{ + LFH_arena *next; + size_t size; +}; + +struct LFH_heap +{ + LFH_slist *list_defer; + LFH_arena *cached_large_arena; + + LFH_class block_class[TOTAL_BLOCK_CLASS_COUNT]; + LFH_class large_class[TOTAL_LARGE_CLASS_COUNT]; + + SLIST_ENTRY entry_orphan; +#ifdef _WIN64 + void *pad[0xc2]; +#else + void *pad[0xc3]; +#endif +}; + +C_ASSERT(TOTAL_BLOCK_CLASS_COUNT == 0x7d); +C_ASSERT(TOTAL_LARGE_CLASS_COUNT == 0x20); + +/* arena->class/arena->parent pointer low bits are used to discriminate between the two */ +C_ASSERT(offsetof(LFH_heap, block_class[0]) > 0); +C_ASSERT(offsetof(LFH_heap, large_class[TOTAL_LARGE_CLASS_COUNT]) < BLOCK_ARENA_SIZE); + +/* helpers to retrieve parent arena from a child, or class pointer from a large or block arena */ +static inline LFH_arena *LFH_parent_from_arena(const LFH_arena *arena) +{ + if (!arena->parent) return (LFH_arena *)arena; + if (!((UINT_PTR)(arena)->parent & BLOCK_ARENA_MASK)) return arena->parent; + return (LFH_arena *)arena; +} + +static inline LFH_class *LFH_class_from_arena(const LFH_arena *arena) +{ + const LFH_arena *parent = LFH_parent_from_arena(arena); + if ((UINT_PTR)parent->class & BLOCK_ARENA_MASK) return parent->class; + return NULL; +} + +/* make sure its aligns to power of two so we can mask class pointers in LFH_heap_from_arena */ +#ifdef _WIN64 +C_ASSERT(sizeof(LFH_heap) == 0x1000); +#else +C_ASSERT(sizeof(LFH_heap) == 0x800); +#endif + +/* helper to retrieve the heap from an arena, using its class pointer */ +static inline LFH_heap *LFH_heap_from_arena(const LFH_arena *arena) +{ + LFH_class *class = LFH_class_from_arena(arena); + return (LFH_heap *)((UINT_PTR)class & ~(sizeof(LFH_heap) - 1)); +} + +/* helpers to retrieve block pointers to the containing block or large (maybe child) arena */ +static inline LFH_arena *LFH_large_arena_from_block(const LFH_block *block) +{ + return (LFH_arena *)((UINT_PTR)block & ~BLOCK_ARENA_MASK); +} + +static inline LFH_arena *LFH_block_arena_from_block(const LFH_block *block) +{ + return LFH_large_arena_from_block(block) + 1; +} + +static inline LFH_arena *LFH_arena_from_block(const LFH_block *block) +{ + LFH_arena *block_arena = LFH_block_arena_from_block(block); + if (block_arena == (LFH_arena *)block) return LFH_large_arena_from_block(block); + return block_arena; +} + +/* helpers to translate between data pointer and LFH_block header */ +static inline LFH_block *LFH_block_from_ptr(const LFH_ptr *ptr) +{ + return ((LFH_block *)ptr) - 1; +} + +static inline void *LFH_ptr_from_block(const LFH_block *block) +{ + return (LFH_ptr *)(block + 1); +} + +static inline size_t LFH_block_get_class_size(const LFH_block *block) +{ + const LFH_arena *arena = LFH_arena_from_block(block); + const LFH_class *class = LFH_class_from_arena(arena); + if (class) return class->size; + return arena->huge_size; +} + +static inline size_t LFH_block_get_alloc_size(const LFH_block *block, ULONG flags) +{ + return block->alloc_size; +} + +static inline size_t LFH_get_class_size(ULONG flags, size_t size) +{ + static const ULONG padd_flags = HEAP_VALIDATE | HEAP_VALIDATE_ALL | HEAP_VALIDATE_PARAMS | HEAP_ADD_USER_INFO; + static const ULONG check_flags = HEAP_TAIL_CHECKING_ENABLED | HEAP_FREE_CHECKING_ENABLED | HEAP_CHECKING_ENABLED; + SIZE_T overhead; + + if ((flags & check_flags)) overhead = ALIGNMENT; + else overhead = sizeof(LFH_block); + + if (flags & HEAP_TAIL_CHECKING_ENABLED) overhead += ALIGNMENT; + if (flags & padd_flags) overhead += ALIGNMENT; + + if (size < ALIGNMENT) size = ALIGNMENT; + return ROUND_SIZE( size + overhead, ALIGNMENT - 1 ); +} + +static inline void *LFH_memory_allocate(size_t size) +{ + void *addr = NULL; + SIZE_T alloc_size = size; + + if (NtAllocateVirtualMemory(NtCurrentProcess(), (void **)&addr, 0, &alloc_size, + MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)) + return NULL; + + return addr; +} + +static inline BOOLEAN LFH_memory_deallocate(void *addr, size_t size) +{ + SIZE_T release_size = 0; + + if (NtFreeVirtualMemory(NtCurrentProcess(), &addr, &release_size, MEM_RELEASE)) + return FALSE; + + return TRUE; +} + +static inline LFH_block *LFH_arena_get_block(const LFH_arena *arena, size_t offset) +{ + return (LFH_block *)((UINT_PTR)arena + offset); +} + +static inline void LFH_arena_push_block(LFH_arena *arena, LFH_block *block) +{ + block->flags = 0; + block->type = LFH_block_type_free; + block->next_free = arena->next_free; + arena->next_free = (UINT_PTR)block - (UINT_PTR)arena; + arena->used_count--; +} + +static inline LFH_block *LFH_arena_pop_block(LFH_arena *arena) +{ + if (arena->next_free > 0) + { + LFH_block *block = LFH_arena_get_block(arena, arena->next_free); + arena->next_free = block->next_free; + arena->used_count++; + return block; + } + else + { + LFH_arena *child, *large_arena = LFH_large_arena_from_block((LFH_block *)arena); + LFH_class *class = LFH_class_from_arena(arena); + LFH_block *block = LFH_arena_get_block(arena, -arena->next_free); + ssize_t extra = 0, limit; + + if (arena == large_arena) + { + extra = ARENA_HEADER_SIZE; + limit = LARGE_ARENA_SIZE; + child = LFH_large_arena_from_block(block); + if (arena != child) child->parent = arena; + } + else limit = LFH_class_from_arena(large_arena)->size; + + arena->next_free -= class->size + extra; + if (-arena->next_free > limit - class->size) + arena->next_free = 0; + + arena->used_count++; + return block; + } +} + +static inline int LFH_arena_is_empty(LFH_arena *arena) +{ + return arena->next_free == 0; +} + +static inline int LFH_arena_is_used(LFH_arena *arena) +{ + return arena->used_count > 0; +} + +static inline int LFH_class_is_block(LFH_heap *heap, LFH_class *class) +{ + return class >= heap->block_class && class < (heap->block_class + TOTAL_BLOCK_CLASS_COUNT); +} + +static void LFH_class_initialize(LFH_heap *heap, LFH_class *class, size_t index) +{ + class->next = NULL; + + if (LFH_class_is_block(heap, class)) + { + if (index <= SMALL_CLASS_LAST) + class->size = min(SMALL_CLASS_MIN_SIZE + SMALL_CLASS_STEP * (index - SMALL_CLASS_FIRST), SMALL_CLASS_MAX_SIZE); + else + class->size = min(MEDIUM_CLASS_MIN_SIZE + MEDIUM_CLASS_STEP * (index - MEDIUM_CLASS_FIRST), MEDIUM_CLASS_MAX_SIZE); + } + else + { + class->size = min(LARGE_CLASS_MIN_SIZE + LARGE_CLASS_STEP * (index - LARGE_CLASS_FIRST), LARGE_CLASS_MAX_SIZE); + } +} + +static inline LFH_arena *LFH_class_pop_arena(LFH_class *class) +{ + LFH_arena *arena = class->next; + if (!arena) return NULL; + class->next = arena->class_entry; + return arena; +} + +static inline void LFH_class_remove_arena(LFH_class *class, LFH_arena *arena) +{ + LFH_arena **next = &class->next; + while (*next != arena) next = &(*next)->class_entry; + *next = arena->class_entry; +} + +static inline LFH_arena *LFH_class_peek_arena(LFH_class *class) +{ + return class->next; +} + +static inline void LFH_class_push_arena(LFH_class *class, LFH_arena *arena) +{ + arena->class_entry = class->next; + class->next = arena; +} + +static inline LFH_class *LFH_heap_get_class(LFH_heap *heap, size_t size) +{ + if (size == 0) + return &heap->block_class[0]; + else if (size <= SMALL_CLASS_MAX_SIZE) + return &heap->block_class[SMALL_CLASS_FIRST + (size + SMALL_CLASS_MASK - SMALL_CLASS_MIN_SIZE) / SMALL_CLASS_STEP]; + else if (size <= MEDIUM_CLASS_MAX_SIZE) + return &heap->block_class[MEDIUM_CLASS_FIRST + (size + MEDIUM_CLASS_MASK - MEDIUM_CLASS_MIN_SIZE) / MEDIUM_CLASS_STEP]; + else if (size <= LARGE_CLASS_MAX_SIZE) + return &heap->large_class[LARGE_CLASS_FIRST + (size + LARGE_CLASS_MASK - LARGE_CLASS_MIN_SIZE) / LARGE_CLASS_STEP]; + else + return NULL; +} + +static void LFH_arena_initialize(LFH_heap *heap, LFH_class *class, LFH_arena *arena, size_t huge_size) +{ + arena->class = class; + arena->next_free = -ARENA_HEADER_SIZE; + + if (class == NULL) + arena->huge_size = huge_size; + else + arena->used_count = 0; +} + +static LFH_arena *LFH_acquire_arena(LFH_heap *heap, LFH_class *class); +static BOOLEAN LFH_release_arena(LFH_heap *heap, LFH_arena *arena); + +static inline LFH_block *LFH_allocate_block(LFH_heap *heap, LFH_class *class, LFH_arena *arena); +static inline BOOLEAN LFH_deallocate_block(LFH_heap *heap, LFH_arena *arena, LFH_block *block); + +static inline BOOLEAN LFH_deallocate_deferred_blocks(LFH_heap *heap) +{ + LFH_slist *entry = LFH_slist_flush(&heap->list_defer); + + while (entry) + { + LFH_block *block = LIST_ENTRY(entry, LFH_block, entry_defer); + entry = entry->next; + + if (!LFH_deallocate_block(heap, LFH_arena_from_block(block), block)) + return FALSE; + } + + return TRUE; +} + +static inline void LFH_deallocated_cached_arenas(LFH_heap *heap) +{ + if (!heap->cached_large_arena) return; + LFH_memory_deallocate(heap->cached_large_arena, LARGE_ARENA_SIZE); + heap->cached_large_arena = NULL; +} + +static inline size_t LFH_huge_alloc_size(size_t size) +{ + return (ARENA_HEADER_SIZE + size + BLOCK_ARENA_MASK) & ~BLOCK_ARENA_MASK; +} + +static inline LFH_arena *LFH_allocate_huge_arena(LFH_heap *heap, size_t size) +{ + LFH_arena *arena; + size_t alloc_size = LFH_huge_alloc_size(size); + if (alloc_size < size) return NULL; + + if ((arena = LFH_memory_allocate(alloc_size))) + LFH_arena_initialize(heap, NULL, arena, size); + + return arena; +} + +static inline LFH_arena *LFH_allocate_large_arena(LFH_heap *heap, LFH_class *class) +{ + LFH_arena *arena; + + if ((arena = heap->cached_large_arena) || + (arena = LFH_memory_allocate(LARGE_ARENA_SIZE))) + { + heap->cached_large_arena = NULL; + LFH_arena_initialize(heap, class, arena, 0); + LFH_class_push_arena(class, arena); + } + + return arena; +} + +static inline LFH_arena *LFH_allocate_block_arena(LFH_heap *heap, LFH_class *large_class, LFH_class *block_class) +{ + LFH_arena *large_arena; + LFH_arena *arena = NULL; + + if ((large_arena = LFH_acquire_arena(heap, large_class))) + { + arena = (LFH_arena *)LFH_allocate_block(heap, large_class, large_arena); + LFH_arena_initialize(heap, block_class, arena, 0); + LFH_class_push_arena(block_class, arena); + } + + return arena; +} + +static inline LFH_arena *LFH_acquire_arena(LFH_heap *heap, LFH_class *class) +{ + LFH_arena *arena; + + if (!(arena = LFH_class_peek_arena(class))) + { + if (LFH_class_is_block(heap, class)) + arena = LFH_allocate_block_arena(heap, &heap->large_class[0], class); + else + arena = LFH_allocate_large_arena(heap, class); + } + + return arena; +} + +static inline BOOLEAN LFH_release_arena(LFH_heap *heap, LFH_arena *arena) +{ + LFH_arena *large_arena = LFH_large_arena_from_block((LFH_block *)arena); + if (arena == large_arena && !heap->cached_large_arena) + { + heap->cached_large_arena = arena; + return TRUE; + } + else if (arena == large_arena) + return LFH_memory_deallocate(arena, LARGE_ARENA_SIZE); + else + return LFH_deallocate_block(heap, large_arena, (LFH_block *)arena); +}; + +static inline LFH_block *LFH_allocate_block(LFH_heap *heap, LFH_class *class, LFH_arena *arena) +{ + LFH_block *block = LFH_arena_pop_block(arena); + if (LFH_arena_is_empty(arena)) + LFH_class_pop_arena(class); + return block; +} + +static inline BOOLEAN LFH_deallocate_block(LFH_heap *heap, LFH_arena *arena, LFH_block *block) +{ + LFH_class *class = LFH_class_from_arena(arena); + + arena = LFH_parent_from_arena(arena); + if (LFH_arena_is_empty(arena)) + LFH_class_push_arena(class, arena); + + LFH_arena_push_block(arena, block); + if (LFH_arena_is_used(arena)) + return TRUE; + + LFH_class_remove_arena(class, arena); + return LFH_release_arena(heap, arena); +} + +static void LFH_heap_initialize(LFH_heap *heap) +{ + size_t i; + + for (i = 0; i < TOTAL_LARGE_CLASS_COUNT; ++i) + LFH_class_initialize(heap, &heap->large_class[i], i); + for (i = 0; i < TOTAL_BLOCK_CLASS_COUNT; ++i) + LFH_class_initialize(heap, &heap->block_class[i], i); + + heap->list_defer = NULL; + heap->cached_large_arena = NULL; +} + +static SLIST_HEADER *LFH_orphan_list(void) +{ + static SLIST_HEADER *header; + SLIST_HEADER *ptr, *expected = NULL; + LFH_heap *tmp; + + C_ASSERT(sizeof(LFH_heap) >= sizeof(SLIST_HEADER)); + + if ((ptr = __atomic_load_n(&header, __ATOMIC_RELAXED))) + return ptr; + + if (!(ptr = LFH_memory_allocate(BLOCK_ARENA_SIZE))) + return NULL; + + RtlInitializeSListHead(ptr); + for (tmp = (LFH_heap *)ptr + 1; tmp < (LFH_heap *)ptr + BLOCK_ARENA_SIZE / sizeof(*tmp); tmp++) + { + LFH_heap_initialize(tmp); + RtlInterlockedPushEntrySList(ptr, &tmp->entry_orphan); + } + + if (__atomic_compare_exchange_n(&header, &expected, ptr, 0, __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) + return ptr; + + LFH_memory_deallocate(ptr, BLOCK_ARENA_SIZE); + return expected; +} + +static void LFH_heap_finalize(LFH_heap *heap) +{ + LFH_arena *arena; + + LFH_deallocate_deferred_blocks(heap); + + for (size_t i = 0; i < TOTAL_BLOCK_CLASS_COUNT; ++i) + { + while ((arena = LFH_class_pop_arena(&heap->block_class[i]))) + { + WARN("block arena %p still has used blocks\n", arena); + LFH_release_arena(heap, arena); + } + } + + for (size_t i = 0; i < TOTAL_LARGE_CLASS_COUNT; ++i) + { + while ((arena = LFH_class_pop_arena(&heap->large_class[i]))) + { + WARN("large arena %p still has used blocks\n", arena); + LFH_memory_deallocate(arena, LARGE_ARENA_SIZE); + } + } + + LFH_deallocated_cached_arenas(heap); +} + +static LFH_heap *LFH_heap_allocate(void) +{ + SLIST_HEADER *list_orphan = LFH_orphan_list(); + LFH_heap *heap, *tmp; + + heap = LFH_memory_allocate(BLOCK_ARENA_SIZE); + if (!heap) + return NULL; + + for (tmp = heap + 1; tmp < heap + BLOCK_ARENA_SIZE / sizeof(*tmp); tmp++) + { + LFH_heap_initialize(tmp); + RtlInterlockedPushEntrySList(list_orphan, &tmp->entry_orphan); + } + + LFH_heap_initialize(heap); + return heap; +} + +static LFH_heap *LFH_create_thread_heap(void) +{ + SLIST_ENTRY *entry; + LFH_heap *heap; + + if ((entry = RtlInterlockedPopEntrySList(LFH_orphan_list()))) + heap = LIST_ENTRY(entry, LFH_heap, entry_orphan); + else + heap = LFH_heap_allocate(); + + return (NtCurrentTeb()->Reserved5[2] = heap); +} + +static inline LFH_heap *LFH_thread_heap(BOOL create) +{ + LFH_heap *heap = (LFH_heap *)NtCurrentTeb()->Reserved5[2]; + if (!heap && create) return LFH_create_thread_heap(); + return heap; +} + +static void LFH_dump_arena(LFH_heap *heap, LFH_class *class, LFH_arena *arena) +{ + LFH_arena *large_arena = LFH_large_arena_from_block((LFH_block *)arena); + LFH_arena *block_arena = LFH_block_arena_from_block((LFH_block *)arena); + + if (arena == block_arena) + WARN(" block arena: %p-%p", arena, (void *)((UINT_PTR)large_arena + BLOCK_ARENA_SIZE - 1)); + else if (arena == large_arena) + WARN(" large arena: %p-%p", arena, (void *)((UINT_PTR)large_arena + LARGE_ARENA_SIZE - 1)); + + WARN(" heap: %p class: %p parent: %p free: %Id used: %Id\n", + LFH_heap_from_arena(arena), LFH_class_from_arena(arena), LFH_parent_from_arena(arena), arena->next_free, arena->used_count); +} + +static void LFH_dump_class(LFH_heap *heap, LFH_class *class) +{ + LFH_arena *arena = class->next; + if (!arena) return; + + if (LFH_class_is_block(heap, class)) + WARN(" block class: %p size: %Ix\n", class, class->size); + else + WARN(" large class: %p size: %Ix\n", class, class->size); + + while (arena) + { + LFH_dump_arena(heap, class, arena); + arena = arena->class_entry; + } +} + +static void LFH_dump_heap(LFH_heap *heap) +{ + size_t i; + + WARN("heap: %p\n", heap); + + for (i = 0; i < TOTAL_BLOCK_CLASS_COUNT; ++i) + LFH_dump_class(heap, &heap->block_class[i]); + + for (i = 0; i < TOTAL_LARGE_CLASS_COUNT; ++i) + LFH_dump_class(heap, &heap->large_class[i]); +} + +static BOOLEAN LFH_validate_arena(ULONG flags, const LFH_arena *arena); +static BOOLEAN LFH_validate_heap(ULONG flags, const LFH_heap *heap); + +static inline BOOLEAN LFH_validate_block(ULONG flags, const LFH_block *block) +{ + const LFH_arena *arena = LFH_arena_from_block(block); + const LFH_arena *large_arena = LFH_large_arena_from_block(block); + const LFH_arena *block_arena = LFH_block_arena_from_block(block); + const LFH_arena *arena_arena = LFH_large_arena_from_block((LFH_block *)arena); + const char *err = NULL; + + if (flags & HEAP_VALIDATE) + return LFH_validate_arena(flags, arena); + + if (!arena) + err = "invalid arena"; + else if (arena != arena_arena && arena != (arena_arena + 1)) + err = "invalid arena alignment"; + else if (arena == block_arena) + { + if ((UINT_PTR)block < (UINT_PTR)block_arena + ARENA_HEADER_SIZE) + err = "invalid block alignment"; + if (((UINT_PTR)block & (sizeof(*block) - 1))) + err = "invalid block alignment"; + } + else if (arena != large_arena) + err = "large/huge arena mismatch"; + else if ((UINT_PTR)block != (UINT_PTR)block_arena) + err = "invalid block for large/huge arena"; + + if (err) WARN("%08lx %p: %s\n", flags, block, err); + return err == NULL; +} + +static BOOLEAN LFH_validate_free_block(ULONG flags, const LFH_block *block) +{ + const char *err = NULL; + + if (!LFH_validate_block(flags, block)) + return FALSE; + if (block->type != LFH_block_type_free) + err = "invalid free block type"; + + if (err) WARN("%08lx %p: %s\n", flags, block, err); + return err == NULL; +} + +static BOOLEAN LFH_validate_defer_block(ULONG flags, const LFH_block *block) +{ + const char *err = NULL; + + if (!LFH_validate_block(flags, block)) + return FALSE; + if (block->type != LFH_block_type_free) + err = "invalid defer block type"; + else if (flags & HEAP_FREE_CHECKING_ENABLED) + { + const unsigned int *data = (const unsigned int *)LFH_ptr_from_block(block); + size_t class_size = LFH_block_get_class_size(block); + for (size_t i = 0; i < class_size / 4 - (data - (const unsigned int *)block) && !err; ++i) + if (data[i] != 0xfeeefeee) err = "invalid free filler"; + } + + if (err) WARN("%08lx %p: %s\n", flags, block, err); + return err == NULL; +} + +static inline BOOLEAN LFH_validate_used_block(ULONG flags, const LFH_block *block) +{ + const char *err = NULL; + + if (!LFH_validate_block(flags, block)) + return FALSE; + if (block->type != LFH_block_type_used) + err = "invalid used block type"; + else if (flags & HEAP_TAIL_CHECKING_ENABLED) + { + const unsigned char *data = (const unsigned char *)LFH_ptr_from_block(block); + size_t alloc_size = LFH_block_get_alloc_size(block, flags); + for (size_t i = alloc_size; i < alloc_size + ALIGNMENT && !err; ++i) + if (data[i] != 0xab) err = "invalid tail filler"; + } + + if (err) WARN("%08lx %p: %s\n", flags, block, err); + return err == NULL; +} + +static BOOLEAN LFH_validate_arena_free_blocks(ULONG flags, const LFH_arena *arena) +{ + ssize_t offset = arena->next_free; + while (offset > 0) + { + LFH_block *block = LFH_arena_get_block(arena, offset); + if (!LFH_validate_free_block(flags, block)) + return FALSE; + offset = block->next_free; + } + + return TRUE; +} + +static BOOLEAN LFH_validate_arena(ULONG flags, const LFH_arena *arena) +{ + const char *err = NULL; + const LFH_arena *parent; + const LFH_arena *block_arena = LFH_block_arena_from_block((LFH_block *)arena); + const LFH_arena *large_arena = LFH_large_arena_from_block((LFH_block *)arena); + + if (flags & HEAP_VALIDATE) + return LFH_validate_heap(flags, LFH_heap_from_arena(arena)); + + if (arena != large_arena && arena != block_arena) + err = "invalid arena alignment"; + else if (arena == block_arena) + { + if (!LFH_validate_block(flags, (LFH_block *)arena)) + err = "invalid block arena"; + else if (!LFH_validate_arena_free_blocks(flags, arena)) + err = "invalid block arena free list"; + } + else if (arena == large_arena && !LFH_class_from_arena(arena)) + { + if (arena->huge_size <= LARGE_CLASS_MAX_SIZE) + err = "invalid huge arena size"; + } + else if (arena == large_arena && (parent = LFH_parent_from_arena(arena)) != arena) + { + if (arena > parent || LFH_large_arena_from_block((LFH_block *)parent) != parent) + err = "invalid child arena parent"; + } + else + { + if (!LFH_validate_arena_free_blocks(flags, arena)) + err = "invalid large arena free list"; + } + + if (err) WARN("%08lx %p: %s\n", flags, arena, err); + return err == NULL; +} + +static BOOLEAN LFH_validate_class_arenas(ULONG flags, const LFH_class *class) +{ + LFH_arena *arena = class->next; + while (arena) + { + if (!LFH_validate_arena(flags, arena)) + return FALSE; + + arena = arena->class_entry; + } + + return TRUE; +} + +static BOOLEAN LFH_validate_heap_defer_blocks(ULONG flags, const LFH_heap *heap) +{ + const LFH_slist *entry = heap->list_defer; + + while (entry) + { + const LFH_block *block = LIST_ENTRY(entry, LFH_block, entry_defer); + if (!LFH_validate_defer_block(flags, block)) + return FALSE; + entry = entry->next; + } + + return TRUE; +} + +static BOOLEAN LFH_validate_heap(ULONG flags, const LFH_heap *heap) +{ + const char *err = NULL; + UINT i; + + flags &= ~HEAP_VALIDATE; + + if (heap != LFH_thread_heap(FALSE)) + err = "unable to validate foreign heap"; + else if (!LFH_validate_heap_defer_blocks(flags, heap)) + err = "invalid heap defer blocks"; + else + { + for (i = 0; err == NULL && i < TOTAL_BLOCK_CLASS_COUNT; ++i) + { + if (!LFH_validate_class_arenas(flags, &heap->block_class[i])) + return FALSE; + } + + for (i = 0; err == NULL && i < TOTAL_LARGE_CLASS_COUNT; ++i) + { + if (!LFH_validate_class_arenas(flags, &heap->large_class[i])) + return FALSE; + } + } + + if (err) WARN("%08lx %p: %s\n", flags, heap, err); + return err == NULL; +} + +static inline void LFH_block_initialize(LFH_block *block, ULONG flags, size_t old_size, size_t new_size, size_t class_size) +{ + char *ptr = (char *)LFH_ptr_from_block(block); + + TRACE("block %p, flags %08lx, old_size %Ix, new_size %Ix, class_size %Ix, ptr %p\n", block, flags, old_size, new_size, class_size, ptr); + + if ((flags & HEAP_ZERO_MEMORY) && new_size > old_size) + memset(ptr + old_size, 0, new_size - old_size); + else if ((flags & HEAP_FREE_CHECKING_ENABLED) && new_size > old_size && class_size < BLOCK_ARENA_SIZE) + memset(ptr + old_size, 0x55, new_size - old_size); + + if ((flags & HEAP_TAIL_CHECKING_ENABLED)) + memset(ptr + new_size, 0xab, class_size - new_size - (ptr - (char *)block)); + + block->flags = BLOCK_USER_FLAGS( flags ); + block->type = LFH_block_type_used; + block->alloc_size = new_size; +} + +static FORCEINLINE LFH_ptr *LFH_allocate(ULONG flags, size_t size) +{ + LFH_block *block = NULL; + LFH_class *class; + LFH_arena *arena; + LFH_heap *heap = LFH_thread_heap(TRUE); + size_t class_size = LFH_get_class_size(flags, size); + + if (class_size == ~(size_t)0) + return NULL; + + if (!LFH_deallocate_deferred_blocks(heap)) + return NULL; + + if ((class = LFH_heap_get_class(heap, class_size))) + { + arena = LFH_acquire_arena(heap, class); + if (arena) block = LFH_allocate_block(heap, class, arena); + if (block) LFH_block_initialize(block, flags, 0, size, LFH_block_get_class_size(block)); + } + else + { + arena = LFH_allocate_huge_arena(heap, class_size); + if (arena) block = LFH_arena_get_block(arena, ARENA_HEADER_SIZE); + if (block) LFH_block_initialize(block, flags & ~HEAP_ZERO_MEMORY, 0, size, LFH_block_get_class_size(block)); + } + + LFH_deallocated_cached_arenas(heap); + + if (!block) return NULL; + return LFH_ptr_from_block(block); +} + +static FORCEINLINE BOOLEAN LFH_free(ULONG flags, LFH_ptr *ptr) +{ + LFH_block *block = LFH_block_from_ptr(ptr); + LFH_arena *arena = LFH_arena_from_block(block); + LFH_heap *heap = LFH_heap_from_arena(arena); + + if (!LFH_class_from_arena(arena)) + return LFH_memory_deallocate(arena, LFH_block_get_class_size(block)); + + if (flags & HEAP_FREE_CHECKING_ENABLED) + { + unsigned int *data = (unsigned int *)LFH_ptr_from_block(block); + size_t class_size = LFH_block_get_class_size(block); + for (size_t i = 0; i < class_size / 4 - (data - (const unsigned int *)block); ++i) + data[i] = 0xfeeefeee; + } + + block->flags = 0; + block->type = LFH_block_type_free; + + if (heap == LFH_thread_heap(FALSE) && !(flags & HEAP_FREE_CHECKING_ENABLED)) + LFH_deallocate_block(heap, LFH_arena_from_block(block), block); + else + LFH_slist_push(&heap->list_defer, &block->entry_defer); + + return TRUE; +} + +static FORCEINLINE LFH_ptr *LFH_reallocate(ULONG flags, LFH_ptr *old_ptr, size_t new_size) +{ + LFH_block *block = LFH_block_from_ptr(old_ptr); + LFH_arena *arena = LFH_arena_from_block(block); + LFH_heap *heap = LFH_heap_from_arena(arena); + size_t old_size = LFH_block_get_alloc_size(block, flags); + size_t old_class_size = LFH_block_get_class_size(block); + size_t new_class_size = LFH_get_class_size(flags, new_size); + LFH_class *new_class, *old_class = LFH_class_from_arena(arena); + LFH_ptr *new_ptr = NULL; + + if (new_class_size == ~(size_t)0) + return NULL; + + if (new_class_size <= old_class_size) + goto in_place; + + if ((new_class = LFH_heap_get_class(heap, new_class_size)) && new_class == old_class) + goto in_place; + + old_class_size = LFH_huge_alloc_size(old_class_size); + new_class_size = LFH_huge_alloc_size(new_class_size); + if (!new_class && !old_class && old_class_size == new_class_size) + goto in_place; + + if (flags & HEAP_REALLOC_IN_PLACE_ONLY) + return NULL; + + if (!(new_ptr = LFH_allocate(flags, new_size))) + return NULL; + + memcpy(new_ptr, old_ptr, old_size); + + if (LFH_free(flags, old_ptr)) + return new_ptr; + + LFH_free(flags, new_ptr); + return NULL; + +in_place: + LFH_block_initialize(block, flags, old_size, new_size, old_class_size); + return old_ptr; +} + +static inline size_t LFH_get_allocated_size(ULONG flags, const LFH_ptr *ptr) +{ + const LFH_block *block = LFH_block_from_ptr(ptr); + return LFH_block_get_alloc_size(block, flags); +} + +static inline BOOLEAN LFH_validate(ULONG flags, const LFH_ptr *ptr) +{ + const LFH_block *block = LFH_block_from_ptr(ptr); + const LFH_heap *heap; + + /* clear HEAP_VALIDATE so we only validate block */ + if (ptr) + return LFH_validate_used_block(flags & ~HEAP_VALIDATE, block); + + if (!(heap = LFH_thread_heap(FALSE))) + return TRUE; + + return LFH_validate_heap(flags, heap); +} + +static inline void LFH_get_user_info( ULONG flags, void *ptr, void **user_value, ULONG *user_flags ) +{ + LFH_block *block = LFH_block_from_ptr(ptr); + void **tmp; + + if (!(*user_flags = HEAP_USER_FLAGS( block->flags ))) return; + + tmp = (void **)((char *)block + LFH_block_get_class_size( block ) - ALIGNMENT); + *user_flags = *user_flags & ~HEAP_ADD_USER_INFO; + *user_value = tmp[1]; +} + +static inline void LFH_set_user_value( ULONG flags, void *ptr, void *user_value ) +{ + LFH_block *block = LFH_block_from_ptr(ptr); + void **tmp; + + if (!(block->flags & BLOCK_FLAG_USER_INFO)) return; + + tmp = (void **)((char *)block + LFH_block_get_class_size( block ) - ALIGNMENT); + tmp[1] = user_value; +} + +static inline void LFH_set_user_flags( ULONG flags, void *ptr, ULONG clear, ULONG set ) +{ + LFH_block *block = LFH_block_from_ptr(ptr); + + if (!(block->flags & BLOCK_FLAG_USER_INFO)) return; + + block->flags &= ~BLOCK_USER_FLAGS( clear ); + block->flags |= BLOCK_USER_FLAGS( set ); +} + +static inline BOOLEAN LFH_try_validate_all(ULONG flags) +{ + if (!(flags & HEAP_VALIDATE_ALL)) + return TRUE; + + if (LFH_validate(flags, NULL)) + return TRUE; + + LFH_dump_heap(LFH_thread_heap(FALSE)); + return FALSE; +} + +NTSTATUS HEAP_lfh_allocate(HANDLE heap, ULONG flags, SIZE_T size, void **out) +{ + TRACE("heap %p, flags %08lx, size %Ix, out %p.\n", heap, flags, size, out); + + if (!LFH_try_validate_all(flags)) + return STATUS_INVALID_PARAMETER; + + if (!(*out = LFH_allocate(flags, size))) + return STATUS_NO_MEMORY; + + return STATUS_SUCCESS; +} + +NTSTATUS HEAP_lfh_free(HANDLE heap, ULONG flags, void *ptr) +{ + TRACE("heap %p, flags %08lx, ptr %p.\n", heap, flags, ptr); + + if (!LFH_try_validate_all(flags)) + return STATUS_INVALID_PARAMETER; + + if (!LFH_validate(flags, ptr)) + return STATUS_INVALID_PARAMETER; + + if (!LFH_free(flags, ptr)) + return STATUS_INVALID_PARAMETER; + + return STATUS_SUCCESS; +} + +NTSTATUS HEAP_lfh_reallocate(HANDLE heap, ULONG flags, void *ptr, SIZE_T size, void **out) +{ + TRACE("heap %p, flags %08lx, ptr %p, size %Ix, out %p.\n", heap, flags, ptr, size, out); + + if (!LFH_try_validate_all(flags)) + return STATUS_INVALID_PARAMETER; + + if (!LFH_validate(flags, ptr)) + return STATUS_INVALID_PARAMETER; + + if (!(*out = LFH_reallocate(flags, ptr, size))) + return STATUS_NO_MEMORY; + + return STATUS_SUCCESS; +} + +NTSTATUS HEAP_lfh_get_allocated_size(HANDLE heap, ULONG flags, const void *ptr, SIZE_T* out) +{ + TRACE("heap %p, flags %08lx, ptr %p, out %p.\n", heap, flags, ptr, out); + + if (!LFH_try_validate_all(flags)) + return STATUS_INVALID_PARAMETER; + + if (!LFH_validate(flags, ptr)) + return STATUS_INVALID_PARAMETER; + + *out = LFH_get_allocated_size(flags, ptr); + return STATUS_SUCCESS; +} + +NTSTATUS HEAP_lfh_validate(HANDLE heap, ULONG flags, const void *ptr) +{ + TRACE("heap %p, flags %08lx, ptr %p.\n", heap, flags, ptr); + + if (!LFH_try_validate_all(flags)) + return STATUS_INVALID_PARAMETER; + + if (!LFH_validate(flags, ptr)) + return STATUS_INVALID_PARAMETER; + + return STATUS_SUCCESS; +} + +NTSTATUS HEAP_lfh_get_user_info( HANDLE heap, ULONG flags, void *ptr, void **user_value, ULONG *user_flags ) +{ + TRACE("heap %p, flags %08lx, ptr %p, user_value %p, user_flags %p.\n", heap, flags, ptr, user_value, user_flags); + + if (!LFH_try_validate_all(flags)) + return STATUS_INVALID_PARAMETER; + + if (!LFH_validate(flags, ptr)) + return STATUS_INVALID_PARAMETER; + + LFH_get_user_info(flags, ptr, user_value, user_flags); + return STATUS_SUCCESS; +} + +NTSTATUS HEAP_lfh_set_user_value( HANDLE heap, ULONG flags, void *ptr, void *user_value ) +{ + TRACE("heap %p, flags %08lx, ptr %p, user_value %p.\n", heap, flags, ptr, user_value); + + if (!LFH_try_validate_all(flags)) + return STATUS_INVALID_PARAMETER; + + if (!LFH_validate(flags, ptr)) + return STATUS_INVALID_PARAMETER; + + LFH_set_user_value(flags, ptr, user_value); + return STATUS_SUCCESS; +} + +NTSTATUS HEAP_lfh_set_user_flags( HANDLE heap, ULONG flags, void *ptr, ULONG clear, ULONG set ) +{ + TRACE("heap %p, flags %08lx, ptr %p, clear %08lx, set %08lx.\n", heap, flags, ptr, clear, set); + + if (!LFH_try_validate_all(flags)) + return STATUS_INVALID_PARAMETER; + + if (!LFH_validate(flags, ptr)) + return STATUS_INVALID_PARAMETER; + + LFH_set_user_flags(flags, ptr, clear, set); + return STATUS_SUCCESS; +} + +void HEAP_lfh_notify_thread_destroy(BOOLEAN last) +{ + SLIST_HEADER *list_orphan = LFH_orphan_list(); + SLIST_ENTRY *entry_orphan = NULL; + LFH_heap *heap; + + if (last) + { + while ((entry_orphan || (entry_orphan = RtlInterlockedFlushSList(list_orphan)))) + { + LFH_heap *orphan = LIST_ENTRY(entry_orphan, LFH_heap, entry_orphan); + entry_orphan = entry_orphan->Next; + LFH_heap_finalize(orphan); + } + LFH_memory_deallocate(list_orphan, BLOCK_ARENA_SIZE); + } + else if ((heap = LFH_thread_heap(FALSE)) && LFH_validate_heap(0, heap)) + RtlInterlockedPushEntrySList(list_orphan, &heap->entry_orphan); +} + +void HEAP_lfh_set_debug_flags(ULONG flags) +{ + LFH_heap *heap = LFH_thread_heap(FALSE); + if (!heap) return; + + LFH_deallocate_deferred_blocks(heap); + LFH_deallocated_cached_arenas(heap); +} diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 95def8cb691..d141fac99d4 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -113,7 +113,32 @@ static inline TEB64 *NtCurrentTeb64(void) { return NULL; } static inline TEB64 *NtCurrentTeb64(void) { return (TEB64 *)NtCurrentTeb()->GdiBatchCount; } #endif +#define HEAP_STD 0 +#define HEAP_LAL 1 +#define HEAP_LFH 2 + +/* some undocumented flags (names are made up) */ +#define HEAP_PRIVATE 0x00001000 +#define HEAP_ADD_USER_INFO 0x00000100 +#define HEAP_USER_FLAGS_MASK 0x00000f00 +#define HEAP_PAGE_ALLOCS 0x01000000 +#define HEAP_VALIDATE 0x10000000 +#define HEAP_VALIDATE_ALL 0x20000000 +#define HEAP_VALIDATE_PARAMS 0x40000000 +#define HEAP_CHECKING_ENABLED 0x80000000 + +NTSTATUS HEAP_lfh_allocate( HANDLE std_heap, ULONG flags, SIZE_T size, void **out ); +NTSTATUS HEAP_lfh_free( HANDLE std_heap, ULONG flags, void *ptr ); +NTSTATUS HEAP_lfh_reallocate( HANDLE std_heap, ULONG flags, void *ptr, SIZE_T size, void **out ); +NTSTATUS HEAP_lfh_get_allocated_size( HANDLE std_heap, ULONG flags, const void *ptr, SIZE_T *out ); +NTSTATUS HEAP_lfh_validate( HANDLE std_heap, ULONG flags, const void *ptr ); +NTSTATUS HEAP_lfh_get_user_info( HANDLE std_handle, ULONG flags, void *ptr, void **user_value, ULONG *user_flags ); +NTSTATUS HEAP_lfh_set_user_value( HANDLE std_handle, ULONG flags, void *ptr, void *user_value ); +NTSTATUS HEAP_lfh_set_user_flags( HANDLE std_handle, ULONG flags, void *ptr, ULONG clear, ULONG set ); + void HEAP_notify_thread_destroy( BOOLEAN last ); +void HEAP_lfh_notify_thread_destroy( BOOLEAN last ); +void HEAP_lfh_set_debug_flags( ULONG flags ); #define HASH_STRING_ALGORITHM_DEFAULT 0 #define HASH_STRING_ALGORITHM_X65599 1 diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index a723ae3c5b9..ef74fdc82f1 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -67,6 +67,7 @@ struct ntdll_thread_data PRTL_THREAD_START_ROUTINE start; /* thread entry point */ void *param; /* thread entry point parameter */ void *jmp_buf; /* setjmp buffer for exception handling */ + void *heap; /* thread local heap data */ }; C_ASSERT( sizeof(struct ntdll_thread_data) <= sizeof(((TEB *)0)->GdiTebBatch) ); From c59b6dc0d3e4ec5c9669b2e6503ed2ff1469011a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 6 Mar 2021 00:05:36 +0100 Subject: [PATCH 0282/2777] server: Create a desktop shared mapping. Signed-off-by: Huw Davies 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 server: Reuse shared mapping's mmaped pointer and handle mmap failures. Desktop and its shared mapping can be still alive and may be reused after desktop is unlinked via close_desktop_timeout() but before all references and handles are cleared. On the re-use path the mmap(PROT_WRITE) is called on a write-sealed fd which will fail returning MAP_FAILED. It would then be propagated up and dereferenced causing the server to crash. This fixes the crash + makes sure that we can recreate the desktop successfully if needed. This also correctly unmap the shared memory pointers whenever a mapping is destroyed, fixing memory leaks when many threads are created. Fixes: 653dab05664e ("server: Seal shared memory mappings against future writes.") Fixes: 61521e371ac4 ("HACK: server: Close desktop immediately when last user is removed.") CW-Bug-Id: #20266 CW-Bug-Id: #20297 server: Cleanup message queue on thread exit. When threads are killed they don't get a chance to close their message queue handle which is kept in user_thread_info->server_queue, and the message queues are kept alive on the server side. In this case, msg_queue_destroy and cleanup_results are never called, leaving message results referencing the stale queue in other thread message queues. Later, when the messages from the other threads are cleaned up this causes invalid shared memory access when we try to update the queue bits from the message results. This doesn't cause much trouble upstream because it only leaks queue objects, which are always valid in memory, but it breaks with Proton shared memory patches, and the recent unmap fixes, as the queue bits are now in unmapped memory. This is probably a hack because it should probably instead close the handle on behalf of the dying thread, but this doesn't play well with process handle caches we use for fsync / esync. The handle should be closed on process exit anyway. Fixes: 2f844caa49fd2efa ("server: Reuse shared mapping's mmaped pointer and handle mmap failures.") CW-Bug-Id: #20266 CW-Bug-Id: #20297 --- configure.ac | 1 + server/directory.c | 17 +++++++++++++++ server/file.h | 6 ++++++ server/mapping.c | 52 ++++++++++++++++++++++++++++++++++++++++++++- server/protocol.def | 5 +++++ server/queue.c | 31 +++++++++++++++++---------- server/user.h | 2 ++ server/winstation.c | 23 ++++++++++++++++++++ 8 files changed, 125 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index 2bf35cc79e5..84a1d83979d 100644 --- a/configure.ac +++ b/configure.ac @@ -2021,6 +2021,7 @@ AC_CHECK_FUNCS(\ getrandom \ kqueue \ mach_continuous_time \ + memfd_create \ pipe2 \ port_create \ posix_fadvise \ diff --git a/server/directory.c b/server/directory.c index bc161b9ab7e..98e4e55e4a0 100644 --- a/server/directory.c +++ b/server/directory.c @@ -37,6 +37,7 @@ #include "process.h" #include "file.h" #include "unicode.h" +#include "user.h" #define HASH_SIZE 7 /* default hash size */ @@ -279,6 +280,22 @@ struct object *get_directory_obj( struct process *process, obj_handle_t handle ) return get_handle_obj( process, handle, 0, &directory_ops ); } +struct object *create_desktop_map_directory( struct winstation *winstation ) +{ + static const WCHAR dir_desktop_mapsW[] = {'_','_','w','i','n','e','_','d','e','s','k','t','o','p','_','m','a','p','p','i','n','g','s'}; + static const struct unicode_str dir_desktop_maps_str = {dir_desktop_mapsW, sizeof(dir_desktop_mapsW)}; + struct object *root; + struct directory *mapping_root, *ret; + const struct unicode_str winsta_name = {winstation->obj.name->name, winstation->obj.name->len}; + + root = winstation->obj.name->parent; + mapping_root = create_directory( root, &dir_desktop_maps_str, OBJ_OPENIF, HASH_SIZE, NULL ); + ret = create_directory( &mapping_root->obj, &winsta_name, OBJ_OPENIF, HASH_SIZE, NULL ); + release_object( &mapping_root->obj ); + + return &ret->obj; +} + /* Global initialization */ static void create_session( unsigned int id ) diff --git a/server/file.h b/server/file.h index b5b1e2a1077..f964ff03d8a 100644 --- a/server/file.h +++ b/server/file.h @@ -157,6 +157,10 @@ extern struct timeout_user *add_timeout_user( timeout_t when, timeout_callback f extern void remove_timeout_user( struct timeout_user *user ); extern const char *get_timeout_str( timeout_t timeout ); +/* directory functions */ + +extern struct object *create_desktop_map_directory( struct winstation *winstation ); + /* file functions */ extern struct file *get_file_obj( struct process *process, obj_handle_t handle, @@ -185,6 +189,8 @@ extern struct mapping *create_fd_mapping( struct object *root, const struct unic unsigned int attr, const struct security_descriptor *sd ); extern struct object *create_user_data_mapping( struct object *root, const struct unicode_str *name, unsigned int attr, const struct security_descriptor *sd ); +extern struct object *create_shared_mapping( struct object *root, const struct unicode_str *name, + mem_size_t size, const struct security_descriptor *sd, void **ptr ); /* device functions */ diff --git a/server/mapping.c b/server/mapping.c index 1a8d480cfa9..1468b05e260 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "ntstatus.h" #define WIN32_NO_STATUS @@ -163,6 +164,7 @@ struct mapping pe_image_info_t image; /* image info (for PE image mapping) */ struct ranges *committed; /* list of committed ranges in this mapping */ struct shared_map *shared; /* temp file for shared PE mapping */ + void *shared_ptr; /* mmaped pointer for shared mappings */ }; static void mapping_dump( struct object *obj, int verbose ); @@ -265,6 +267,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] ) { @@ -298,10 +301,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; @@ -334,6 +350,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; } @@ -887,6 +904,7 @@ static struct mapping *create_mapping( struct object *root, const struct unicode mapping->fd = NULL; mapping->shared = NULL; mapping->committed = NULL; + mapping->shared_ptr = MAP_FAILED; if (!(mapping->flags = get_mapping_flags( handle, flags ))) goto error; @@ -1087,6 +1105,7 @@ static void mapping_destroy( struct object *obj ) if (mapping->fd) release_object( mapping->fd ); if (mapping->committed) release_object( mapping->committed ); if (mapping->shared) release_object( mapping->shared ); + if (mapping->shared_ptr != MAP_FAILED) munmap( mapping->shared_ptr, mapping->size ); } static enum server_fd_type mapping_get_fd_type( struct fd *fd ) @@ -1100,8 +1119,12 @@ 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 ) + unsigned int attr, const struct security_descriptor *sd ) { void *ptr; struct mapping *mapping; @@ -1109,6 +1132,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; @@ -1117,6 +1141,32 @@ struct object *create_user_data_mapping( struct object *root, const struct unico return &mapping->obj; } +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; + + if (mapping->shared_ptr == MAP_FAILED) + mapping->shared_ptr = mmap( NULL, mapping->size, PROT_WRITE, MAP_SHARED, + get_unix_fd( mapping->fd ), 0 ); + + if (mapping->shared_ptr == MAP_FAILED) + { + fprintf( stderr, "wine: Failed to map shared memory: %u %m\n", errno ); + release_object( &mapping->obj ); + return NULL; + } + + fcntl( get_unix_fd( mapping->fd ), F_ADD_SEALS, seals ); + *ptr = mapping->shared_ptr; + + return &mapping->obj; +} + /* create a file mapping */ DECL_HANDLER(create_mapping) { diff --git a/server/protocol.def b/server/protocol.def index 325c1bdbe6a..a94b86b9820 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -865,6 +865,11 @@ typedef struct lparam_t info; } cursor_pos_t; +struct desktop_shared_memory +{ + int placeholder; +}; + /****************************************************************/ /* Request declarations */ diff --git a/server/queue.c b/server/queue.c index 32eafa4179f..36ab8fe8673 100644 --- a/server/queue.c +++ b/server/queue.c @@ -130,6 +130,7 @@ struct msg_queue int quit_message; /* is there a pending quit message? */ int exit_code; /* exit code of pending quit message */ int cursor_count; /* per-queue cursor show count */ + int destroyed; /* queue has been cleaned up */ struct list msg_list[NB_MSG_KINDS]; /* lists of messages */ struct list send_result; /* stack of sent messages waiting for result */ struct list callback_result; /* list of callback messages waiting for result */ @@ -308,6 +309,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ queue->hotkey_count = 0; queue->quit_message = 0; queue->cursor_count = 0; + queue->destroyed = 0; queue->recv_result = NULL; queue->next_timer_id = 0x7fff; queue->timeout = NULL; @@ -332,15 +334,6 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ return queue; } -/* free the message queue of a thread at thread exit */ -void free_msg_queue( struct thread *thread ) -{ - remove_thread_hooks( thread ); - if (!thread->queue) return; - release_object( thread->queue ); - thread->queue = NULL; -} - /* synchronize thread input keystate with the desktop */ static void sync_input_keystate( struct thread_input *input ) { @@ -1098,9 +1091,8 @@ static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *en queue->changed_mask = 0; } -static void msg_queue_destroy( struct object *obj ) +static void cleanup_msg_queue( struct msg_queue *queue ) { - struct msg_queue *queue = (struct msg_queue *)obj; struct list *ptr; struct hotkey *hotkey, *hotkey2; int i; @@ -1136,6 +1128,23 @@ static void msg_queue_destroy( struct object *obj ) if (queue->hooks) release_object( queue->hooks ); if (queue->fd) release_object( queue->fd ); if (do_esync()) close( queue->esync_fd ); + queue->destroyed = 1; +} + +static void msg_queue_destroy( struct object *obj ) +{ + struct msg_queue *queue = (struct msg_queue *)obj; + if (!queue->destroyed) cleanup_msg_queue( queue ); +} + +/* free the message queue of a thread at thread exit */ +void free_msg_queue( struct thread *thread ) +{ + remove_thread_hooks( thread ); + if (!thread->queue) return; + cleanup_msg_queue( thread->queue ); + release_object( thread->queue ); + thread->queue = NULL; } static void msg_queue_poll_event( struct fd *fd, int event ) diff --git a/server/user.h b/server/user.h index 4fb021b3036..2f666ef75d1 100644 --- a/server/user.h +++ b/server/user.h @@ -78,6 +78,8 @@ struct desktop unsigned int users; /* processes and threads using this desktop */ struct global_cursor cursor; /* global cursor information */ unsigned char keystate[256]; /* asynchronous key state */ + struct object *shared_mapping; /* desktop shared memory mapping */ + volatile struct desktop_shared_memory *shared; /* desktop shared memory ptr */ }; /* user handles functions */ diff --git a/server/winstation.c b/server/winstation.c index afaf8e67536..f79a56ada6e 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -218,6 +218,22 @@ struct desktop *get_desktop_obj( struct process *process, obj_handle_t handle, u return (struct desktop *)get_handle_obj( process, handle, access, &desktop_ops ); } +static volatile void *init_desktop_mapping( struct desktop *desktop, const struct unicode_str *name ) +{ + struct object *dir = create_desktop_map_directory( desktop->winstation ); + + desktop->shared = NULL; + desktop->shared_mapping = NULL; + + if (!dir) return NULL; + + desktop->shared_mapping = create_shared_mapping( dir, name, sizeof(struct desktop_shared_memory), + NULL, (void **)&desktop->shared ); + release_object( dir ); + if (desktop->shared_mapping) memset( (void *)desktop->shared, 0, sizeof(*desktop->shared) ); + return desktop->shared; +} + /* create a desktop object */ static struct desktop *create_desktop( const struct unicode_str *name, unsigned int attr, unsigned int flags, struct winstation *winstation ) @@ -242,6 +258,11 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned list_add_tail( &winstation->desktops, &desktop->entry ); list_init( &desktop->hotkeys ); list_init( &desktop->touches ); + if (!init_desktop_mapping( desktop, name )) + { + release_object( desktop ); + return NULL; + } } else clear_error(); } @@ -296,6 +317,8 @@ static void desktop_destroy( struct object *obj ) if (desktop->global_hooks) release_object( desktop->global_hooks ); if (desktop->close_timeout) remove_timeout_user( desktop->close_timeout ); list_remove( &desktop->entry ); + if (desktop->shared_mapping) release_object( desktop->shared_mapping ); + desktop->shared_mapping = NULL; release_object( desktop->winstation ); } From 26d723cb97fb15cf6010db935905dc38979d9fcf Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Mon, 29 Jun 2020 11:12:12 +0100 Subject: [PATCH 0283/2777] server: Use the helper to update the cursor last change time. Signed-off-by: Huw Davies --- server/queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/queue.c b/server/queue.c index 36ab8fe8673..64f99231a2c 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1864,7 +1864,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons if ((input->mouse.info & 0xffffff00) == 0xff515700) source.origin = IMDT_TOUCH; - desktop->cursor.last_change = get_tick_count(); + update_desktop_cursor_pos( desktop, desktop->cursor.x, desktop->cursor.y ); /* Update last change time */ flags = input->mouse.flags; time = input->mouse.time; if (!time) time = desktop->cursor.last_change; From 88d74ff71b36072e9cb5a38486e3828fa2c98000 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Mon, 29 Jun 2020 11:30:14 +0100 Subject: [PATCH 0284/2777] server: Move the cursor position and last change time to the shared data. Signed-off-by: Huw Davies --- server/protocol.def | 9 +++++++- server/queue.c | 54 ++++++++++++++++++++++----------------------- server/user.h | 3 --- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/server/protocol.def b/server/protocol.def index a94b86b9820..e4346b41c97 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -865,9 +865,16 @@ typedef struct lparam_t info; } cursor_pos_t; +struct shared_cursor +{ + int x; /* cursor position */ + int y; + unsigned int last_change; /* time of last position change */ +}; + struct desktop_shared_memory { - int placeholder; + struct shared_cursor cursor; /* global cursor information */ }; /****************************************************************/ diff --git a/server/queue.c b/server/queue.c index 64f99231a2c..5834078019a 100644 --- a/server/queue.c +++ b/server/queue.c @@ -413,10 +413,10 @@ static int update_desktop_cursor_pos( struct desktop *desktop, int x, int y ) x = max( min( x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); y = max( min( y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); - updated = (desktop->cursor.x != x || desktop->cursor.y != y); - desktop->cursor.x = x; - desktop->cursor.y = y; - desktop->cursor.last_change = get_tick_count(); + updated = (desktop->shared->cursor.x != x || desktop->shared->cursor.y != y); + desktop->shared->cursor.x = x; + desktop->shared->cursor.y = y; + desktop->shared->cursor.last_change = get_tick_count(); return updated; } @@ -447,8 +447,8 @@ static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsig { struct desktop *desktop = queue->input->desktop; - *x = desktop->cursor.x; - *y = desktop->cursor.y; + *x = desktop->shared->cursor.x; + *y = desktop->shared->cursor.y; *time = get_tick_count(); } @@ -475,9 +475,9 @@ static void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect post_desktop_message( desktop, desktop->cursor.clip_msg, rect != NULL, 0 ); /* warp the mouse to be inside the clip rect */ - x = max( min( desktop->cursor.x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); - y = max( min( desktop->cursor.y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); - if (x != desktop->cursor.x || y != desktop->cursor.y) set_cursor_pos( desktop, x, y ); + x = max( min( desktop->shared->cursor.x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); + y = max( min( desktop->shared->cursor.y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); + if (x != desktop->shared->cursor.x || y != desktop->shared->cursor.y) set_cursor_pos( desktop, x, y ); } /* change the foreground input and reset the cursor clip rect */ @@ -1668,8 +1668,8 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg if (desktop->keystate[VK_XBUTTON1] & 0x80) msg->wparam |= MK_XBUTTON1; if (desktop->keystate[VK_XBUTTON2] & 0x80) msg->wparam |= MK_XBUTTON2; } - msg->x = desktop->cursor.x; - msg->y = desktop->cursor.y; + msg->x = desktop->shared->cursor.x; + msg->y = desktop->shared->cursor.y; if (msg->win && (thread = get_window_thread( msg->win ))) { @@ -1864,10 +1864,10 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons if ((input->mouse.info & 0xffffff00) == 0xff515700) source.origin = IMDT_TOUCH; - update_desktop_cursor_pos( desktop, desktop->cursor.x, desktop->cursor.y ); /* Update last change time */ + update_desktop_cursor_pos( desktop, desktop->shared->cursor.x, desktop->shared->cursor.y ); /* Update last change time */ flags = input->mouse.flags; time = input->mouse.time; - if (!time) time = desktop->cursor.last_change; + if (!time) time = desktop->shared->cursor.last_change; if (flags & MOUSEEVENTF_MOVE) { @@ -1876,19 +1876,19 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons x = input->mouse.x; y = input->mouse.y; if (flags & ~(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE) && - x == desktop->cursor.x && y == desktop->cursor.y) + x == desktop->shared->cursor.x && y == desktop->shared->cursor.y) flags &= ~MOUSEEVENTF_MOVE; } else { - x = desktop->cursor.x + input->mouse.x; - y = desktop->cursor.y + input->mouse.y; + x = desktop->shared->cursor.x + input->mouse.x; + y = desktop->shared->cursor.y + input->mouse.y; } } else { - x = desktop->cursor.x; - y = desktop->cursor.y; + x = desktop->shared->cursor.x; + y = desktop->shared->cursor.y; } if ((req_flags & SEND_HWMSG_RAWINPUT) && (foreground = get_foreground_thread( desktop, win ))) @@ -2754,8 +2754,8 @@ DECL_HANDLER(send_hardware_message) } } - reply->prev_x = desktop->cursor.x; - reply->prev_y = desktop->cursor.y; + reply->prev_x = desktop->shared->cursor.x; + reply->prev_y = desktop->shared->cursor.y; switch (req->input.type) { @@ -2773,8 +2773,8 @@ DECL_HANDLER(send_hardware_message) } if (thread) release_object( thread ); - reply->new_x = desktop->cursor.x; - reply->new_y = desktop->cursor.y; + reply->new_x = desktop->shared->cursor.x; + reply->new_y = desktop->shared->cursor.y; set_reply_data( desktop->keystate, size ); release_object( desktop ); } @@ -3476,8 +3476,8 @@ DECL_HANDLER(set_cursor) reply->prev_handle = input->cursor; reply->prev_count = input->cursor_count; - reply->prev_x = input->desktop->cursor.x; - reply->prev_y = input->desktop->cursor.y; + reply->prev_x = input->desktop->shared->cursor.x; + reply->prev_y = input->desktop->shared->cursor.y; if (req->flags & SET_CURSOR_HANDLE) { @@ -3508,10 +3508,10 @@ DECL_HANDLER(set_cursor) set_clip_rectangle( desktop, (req->flags & SET_CURSOR_NOCLIP) ? NULL : &req->clip, 0 ); } - reply->new_x = input->desktop->cursor.x; - reply->new_y = input->desktop->cursor.y; + reply->new_x = input->desktop->shared->cursor.x; + reply->new_y = input->desktop->shared->cursor.y; reply->new_clip = input->desktop->cursor.clip; - reply->last_change = input->desktop->cursor.last_change; + reply->last_change = input->desktop->shared->cursor.last_change; } /* Get the history of the 64 last cursor positions */ diff --git a/server/user.h b/server/user.h index 2f666ef75d1..bc55d4c347b 100644 --- a/server/user.h +++ b/server/user.h @@ -54,11 +54,8 @@ struct winstation struct global_cursor { - int x; /* cursor position */ - int y; rectangle_t clip; /* cursor clip rectangle */ unsigned int clip_msg; /* message to post for cursor clip changes */ - unsigned int last_change; /* time of last position change */ user_handle_t win; /* window that contains the cursor */ }; From 19c2c07bfd89c8d6245a8ad3455cf2822032ba86 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Mon, 29 Jun 2020 12:57:39 +0100 Subject: [PATCH 0285/2777] server: Add a sequence number to the shared data. The client should check that the lower SEQUENCE_MASK_BITS are zero before reading the data and confirm that the number is unchanged when it's finished. Signed-off-by: Huw Davies --- server/protocol.def | 5 +++++ server/queue.c | 46 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/server/protocol.def b/server/protocol.def index e4346b41c97..baef611e8b4 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -874,9 +874,14 @@ struct shared_cursor struct desktop_shared_memory { + unsigned int seq; /* sequence number - server updating if (seq_no & SEQUENCE_MASK) != 0 */ struct shared_cursor cursor; /* global cursor information */ }; +/* Bits that must be clear for client to read */ +#define SEQUENCE_MASK_BITS 4 +#define SEQUENCE_MASK ((1UL << SEQUENCE_MASK_BITS) - 1) + /****************************************************************/ /* Request declarations */ diff --git a/server/queue.c b/server/queue.c index 5834078019a..dd149187f6a 100644 --- a/server/queue.c +++ b/server/queue.c @@ -407,16 +407,60 @@ static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_sour return msg; } +#if defined(__i386__) || defined(__x86_64__) + +#define SHARED_WRITE_BEGIN( x ) \ + do { \ + volatile unsigned int __seq = *(x); \ + assert( (__seq & SEQUENCE_MASK) != SEQUENCE_MASK ); \ + *(x) = ++__seq; \ + } while(0) + +#define SHARED_WRITE_END( x ) \ + do { \ + volatile unsigned int __seq = *(x); \ + assert( (__seq & SEQUENCE_MASK) != 0 ); \ + if ((__seq & SEQUENCE_MASK) > 1) __seq--; \ + else __seq += SEQUENCE_MASK; \ + *(x) = __seq; \ + } while(0) + +#else + +#define SHARED_WRITE_BEGIN( x ) \ + do { \ + assert( (*(x) & SEQUENCE_MASK) != SEQUENCE_MASK ); \ + if ((__atomic_add_fetch( x, 1, __ATOMIC_RELAXED ) & SEQUENCE_MASK) == 1) \ + __atomic_thread_fence( __ATOMIC_RELEASE ); \ + } while(0) + +#define SHARED_WRITE_END( x ) \ + do { \ + assert( (*(x) & SEQUENCE_MASK) != 0 ); \ + if ((*(x) & SEQUENCE_MASK) > 1) \ + __atomic_sub_fetch( x, 1, __ATOMIC_RELAXED ); \ + else { \ + __atomic_thread_fence( __ATOMIC_RELEASE ); \ + __atomic_add_fetch( x, SEQUENCE_MASK, __ATOMIC_RELAXED ); \ + } \ + } while(0) + +#endif + static int update_desktop_cursor_pos( struct desktop *desktop, int x, int y ) { int updated; + unsigned int time = get_tick_count(); x = max( min( x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); y = max( min( y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); updated = (desktop->shared->cursor.x != x || desktop->shared->cursor.y != y); + + SHARED_WRITE_BEGIN( &desktop->shared->seq ); desktop->shared->cursor.x = x; desktop->shared->cursor.y = y; - desktop->shared->cursor.last_change = get_tick_count(); + desktop->shared->cursor.last_change = time; + SHARED_WRITE_END( &desktop->shared->seq ); return updated; } From 216ed5c183551fbce4b0d424a56aa6a39fd21ea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Nov 2022 21:30:23 +0100 Subject: [PATCH 0286/2777] user32: Use the desktop shared data for GetCursorPos(). Squashed: win32u: Avoid leaking winstation directory handle. CW-Bug-Id: #22016 --- dlls/win32u/input.c | 20 +++++------ dlls/win32u/ntuser_private.h | 25 +++++++++++++ dlls/win32u/sysparams.c | 7 ++++ dlls/win32u/winstation.c | 69 ++++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 11 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index aad3e2c5383..05241ccbf28 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -219,25 +219,23 @@ BOOL WINAPI NtUserSetCursorPos( INT x, INT y ) */ BOOL get_cursor_pos( POINT *pt ) { - BOOL ret; + volatile struct desktop_shared_memory *shared = get_desktop_shared_memory(); DWORD last_change; + BOOL ret = TRUE; UINT dpi; - if (!pt) return FALSE; + if (!pt || !shared) return FALSE; - SERVER_START_REQ( set_cursor ) + SHARED_READ_BEGIN( &shared->seq ) { - if ((ret = !wine_server_call( req ))) - { - pt->x = reply->new_x; - pt->y = reply->new_y; - last_change = reply->last_change; - } + pt->x = shared->cursor.x; + pt->y = shared->cursor.y; + last_change = shared->cursor.last_change; } - SERVER_END_REQ; + SHARED_READ_END( &shared->seq ); /* query new position from graphics driver if we haven't updated recently */ - if (ret && NtGetTickCount() - last_change > 100) ret = user_driver->pGetCursorPos( pt ); + if (NtGetTickCount() - last_change > 100) ret = user_driver->pGetCursorPos( pt ); if (ret && (dpi = get_thread_dpi())) { HMONITOR monitor = monitor_from_point( *pt, MONITOR_DEFAULTTOPRIMARY, 0 ); diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index a28e432e3f8..e2771491372 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -136,6 +136,8 @@ struct user_thread_info UINT kbd_layout_id; /* Current keyboard layout ID */ struct rawinput_thread_data *rawinput; /* RawInput thread local data / buffer */ UINT spy_indent; /* Current spy indent */ + HANDLE desktop_shared_map; /* HANDLE to server's desktop shared memory */ + struct desktop_shared_memory *desktop_shared_memory; /* Ptr to server's desktop shared memory */ }; C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) ); @@ -249,6 +251,9 @@ void *get_user_handle_ptr( HANDLE handle, unsigned int type ) DECLSPEC_HIDDEN; void release_user_handle_ptr( void *ptr ) DECLSPEC_HIDDEN; UINT win_set_flags( HWND hwnd, UINT set_mask, UINT clear_mask ) DECLSPEC_HIDDEN; +/* winstation.c */ +extern volatile struct desktop_shared_memory *get_desktop_shared_memory( void ) DECLSPEC_HIDDEN; + static inline UINT win_get_flags( HWND hwnd ) { return win_set_flags( hwnd, 0, 0 ); @@ -258,4 +263,24 @@ WND *get_win_ptr( HWND hwnd ) DECLSPEC_HIDDEN; BOOL is_child( HWND parent, HWND child ); BOOL is_window( HWND hwnd ) DECLSPEC_HIDDEN; +#if defined(__i386__) || defined(__x86_64__) +#define __SHARED_READ_SEQ( x ) (*(x)) +#define __SHARED_READ_FENCE do {} while(0) +#else +#define __SHARED_READ_SEQ( x ) __atomic_load_n( x, __ATOMIC_RELAXED ) +#define __SHARED_READ_FENCE __atomic_thread_fence( __ATOMIC_ACQUIRE ) +#endif + +#define SHARED_READ_BEGIN( x ) \ + do { \ + unsigned int __seq; \ + do { \ + while ((__seq = __SHARED_READ_SEQ( x )) & SEQUENCE_MASK) NtYieldExecution(); \ + __SHARED_READ_FENCE; + +#define SHARED_READ_END( x ) \ + __SHARED_READ_FENCE; \ + } while (__SHARED_READ_SEQ( x ) != __seq); \ + } while(0) + #endif /* __WINE_NTUSER_PRIVATE_H */ diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 5c16a4d9a91..67bbb03f30d 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -5437,6 +5437,13 @@ static void thread_detach(void) cleanup_imm_thread(); NtClose( thread_info->server_queue ); + if (thread_info->desktop_shared_map) + { + NtClose( thread_info->desktop_shared_map ); + thread_info->desktop_shared_map = NULL; + thread_info->desktop_shared_memory = NULL; + } + exiting_thread_id = 0; } diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 145e12a8e1f..b6d1d1c8013 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -242,6 +242,12 @@ BOOL WINAPI NtUserSetThreadDesktop( HDESK handle ) thread_info->client_info.top_window = 0; thread_info->client_info.msg_window = 0; if (key_state_info) key_state_info->time = 0; + if (thread_info->desktop_shared_map) + { + NtClose( thread_info->desktop_shared_map ); + thread_info->desktop_shared_map = NULL; + thread_info->desktop_shared_memory = NULL; + } } return ret; } @@ -567,6 +573,69 @@ static const WCHAR *get_default_desktop( void *buf, size_t buf_size ) return defaultW; } +static void map_shared_memory_section( const WCHAR *name, SIZE_T size, HANDLE root, HANDLE *handle, void **ptr ) +{ + OBJECT_ATTRIBUTES attr; + UNICODE_STRING section_str; + unsigned int status; + + RtlInitUnicodeString( §ion_str, name ); + InitializeObjectAttributes( &attr, §ion_str, 0, root, NULL ); + status = NtOpenSection( handle, SECTION_ALL_ACCESS, &attr ); + if (status) + { + ERR( "failed to open section %s: %08x\n", debugstr_w(name), status ); + *ptr = NULL; + *handle = NULL; + return; + } + + *ptr = NULL; + status = NtMapViewOfSection( *handle, GetCurrentProcess(), ptr, 0, 0, NULL, + &size, ViewUnmap, 0, PAGE_READONLY ); + if (status) + { + ERR( "failed to map view of section %s: %08x\n", debugstr_w(name), status ); + NtClose( *handle ); + *ptr = NULL; + *handle = NULL; + } +} + +volatile struct desktop_shared_memory *get_desktop_shared_memory( void ) +{ + static const WCHAR dir_desktop_maps[] = + { + '_','_','w','i','n','e','_','d','e','s','k','t','o','p','_','m','a','p','p','i','n','g','s','\\',0 + }; + struct user_thread_info *thread_info = get_user_thread_info(); + HANDLE root, handles[2]; + WCHAR buf[MAX_PATH], *ptr; + DWORD i, needed; + + if (thread_info->desktop_shared_memory) return thread_info->desktop_shared_memory; + + handles[0] = NtUserGetProcessWindowStation(); + handles[1] = NtUserGetThreadDesktop( GetCurrentThreadId() ); + + memcpy( buf, dir_desktop_maps, wcslen(dir_desktop_maps) * sizeof(WCHAR) ); + ptr = buf + wcslen(dir_desktop_maps); + + for (i = 0; i < 2; i++) + { + NtUserGetObjectInformation( handles[i], UOI_NAME, (void *)ptr, sizeof(buf) - (ptr - buf) * sizeof(WCHAR), &needed ); + ptr += needed / sizeof(WCHAR); + if (i == 0) *(ptr - 1) = '\\'; + } + + root = get_winstations_dir_handle(); + map_shared_memory_section( buf, sizeof(struct desktop_shared_memory), root, + &thread_info->desktop_shared_map, (void **)&thread_info->desktop_shared_memory ); + NtClose( root ); + + return thread_info->desktop_shared_memory; +} + /*********************************************************************** * winstation_init * From 2a44dd0e99fb87b86441e43a181251a0f061a59c Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Tue, 30 Jun 2020 13:58:26 +0100 Subject: [PATCH 0287/2777] server: Use the helper to reset the clip rect when the desktop size changes. Signed-off-by: Huw Davies --- server/queue.c | 2 +- server/user.h | 1 + server/window.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/server/queue.c b/server/queue.c index dd149187f6a..66cac8cb179 100644 --- a/server/queue.c +++ b/server/queue.c @@ -497,7 +497,7 @@ static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsig } /* set the cursor clip rectangle */ -static void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int send_clip_msg ) +void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int send_clip_msg ) { rectangle_t top_rect; int x, y; diff --git a/server/user.h b/server/user.h index bc55d4c347b..8a223fb7229 100644 --- a/server/user.h +++ b/server/user.h @@ -121,6 +121,7 @@ extern void post_win_event( struct thread *thread, unsigned int event, user_handle_t handle ); extern void free_hotkeys( struct desktop *desktop, user_handle_t window ); extern void free_touches( struct desktop *desktop, user_handle_t window ); +extern void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int send_clip_msg ); /* region functions */ diff --git a/server/window.c b/server/window.c index 3425e0eeb19..bd427f24906 100644 --- a/server/window.c +++ b/server/window.c @@ -1829,7 +1829,7 @@ static void set_window_pos( struct window *win, struct window *previous, } /* reset cursor clip rectangle when the desktop changes size */ - if (win == win->desktop->top_window) win->desktop->cursor.clip = *window_rect; + if (win == win->desktop->top_window) set_clip_rectangle( win->desktop, NULL, 0 ); /* if the window is not visible, everything is easy */ if (!visible) return; From bba70563e68579c1a61ee2b2b3155c11e0bdaa3c Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Tue, 30 Jun 2020 14:12:52 +0100 Subject: [PATCH 0288/2777] server: Store the cursor clip rect in the shared data. Signed-off-by: Huw Davies --- server/protocol.def | 1 + server/queue.c | 21 ++++++++++++--------- server/user.h | 1 - 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/server/protocol.def b/server/protocol.def index baef611e8b4..94acbb05392 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -870,6 +870,7 @@ struct shared_cursor int x; /* cursor position */ int y; unsigned int last_change; /* time of last position change */ + rectangle_t clip; /* cursor clip rectangle */ }; struct desktop_shared_memory diff --git a/server/queue.c b/server/queue.c index 66cac8cb179..452c19dea39 100644 --- a/server/queue.c +++ b/server/queue.c @@ -452,8 +452,8 @@ static int update_desktop_cursor_pos( struct desktop *desktop, int x, int y ) int updated; unsigned int time = get_tick_count(); - x = max( min( x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); - y = max( min( y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); + x = max( min( x, desktop->shared->cursor.clip.right - 1 ), desktop->shared->cursor.clip.left ); + y = max( min( y, desktop->shared->cursor.clip.bottom - 1 ), desktop->shared->cursor.clip.top ); updated = (desktop->shared->cursor.x != x || desktop->shared->cursor.y != y); SHARED_WRITE_BEGIN( &desktop->shared->seq ); @@ -499,29 +499,32 @@ static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsig /* set the cursor clip rectangle */ void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int send_clip_msg ) { - rectangle_t top_rect; + rectangle_t top_rect, new_rect; int x, y; get_top_window_rectangle( desktop, &top_rect ); if (rect) { - rectangle_t new_rect = *rect; + new_rect = *rect; if (new_rect.left < top_rect.left) new_rect.left = top_rect.left; if (new_rect.right > top_rect.right) new_rect.right = top_rect.right; if (new_rect.top < top_rect.top) new_rect.top = top_rect.top; if (new_rect.bottom > top_rect.bottom) new_rect.bottom = top_rect.bottom; if (new_rect.left > new_rect.right || new_rect.top > new_rect.bottom) new_rect = top_rect; - desktop->cursor.clip = new_rect; } - else desktop->cursor.clip = top_rect; + else new_rect = top_rect; + + SHARED_WRITE_BEGIN( &desktop->shared->seq ); + desktop->shared->cursor.clip = new_rect; if (desktop->cursor.clip_msg && send_clip_msg) post_desktop_message( desktop, desktop->cursor.clip_msg, rect != NULL, 0 ); /* warp the mouse to be inside the clip rect */ - x = max( min( desktop->shared->cursor.x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); - y = max( min( desktop->shared->cursor.y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); + x = max( min( desktop->shared->cursor.x, desktop->shared->cursor.clip.right - 1 ), desktop->shared->cursor.clip.left ); + y = max( min( desktop->shared->cursor.y, desktop->shared->cursor.clip.bottom - 1 ), desktop->shared->cursor.clip.top ); if (x != desktop->shared->cursor.x || y != desktop->shared->cursor.y) set_cursor_pos( desktop, x, y ); + SHARED_WRITE_END( &desktop->shared->seq ); } /* change the foreground input and reset the cursor clip rect */ @@ -3554,7 +3557,7 @@ DECL_HANDLER(set_cursor) reply->new_x = input->desktop->shared->cursor.x; reply->new_y = input->desktop->shared->cursor.y; - reply->new_clip = input->desktop->cursor.clip; + reply->new_clip = input->desktop->shared->cursor.clip; reply->last_change = input->desktop->shared->cursor.last_change; } diff --git a/server/user.h b/server/user.h index 8a223fb7229..430b299a3c3 100644 --- a/server/user.h +++ b/server/user.h @@ -54,7 +54,6 @@ struct winstation struct global_cursor { - rectangle_t clip; /* cursor clip rectangle */ unsigned int clip_msg; /* message to post for cursor clip changes */ user_handle_t win; /* window that contains the cursor */ }; From 2ef817c275ae61935ed36822012686a5d60991d1 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Tue, 30 Jun 2020 14:28:15 +0100 Subject: [PATCH 0289/2777] user32: Use the desktop shared data for GetClipCursor(). Signed-off-by: Huw Davies --- dlls/win32u/cursoricon.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/dlls/win32u/cursoricon.c b/dlls/win32u/cursoricon.c index 5ae886187f2..eb1d07afb6c 100644 --- a/dlls/win32u/cursoricon.c +++ b/dlls/win32u/cursoricon.c @@ -200,30 +200,26 @@ BOOL WINAPI NtUserClipCursor( const RECT *rect ) BOOL get_clip_cursor( RECT *rect ) { + volatile struct desktop_shared_memory *shared = get_desktop_shared_memory(); UINT dpi; - BOOL ret; - if (!rect) return FALSE; + if (!rect || !shared) return FALSE; - SERVER_START_REQ( set_cursor ) + SHARED_READ_BEGIN( &shared->seq ) { - req->flags = 0; - if ((ret = !wine_server_call( req ))) - { - rect->left = reply->new_clip.left; - rect->top = reply->new_clip.top; - rect->right = reply->new_clip.right; - rect->bottom = reply->new_clip.bottom; - } + rect->left = shared->cursor.clip.left; + rect->top = shared->cursor.clip.top; + rect->right = shared->cursor.clip.right; + rect->bottom = shared->cursor.clip.bottom; } - SERVER_END_REQ; + SHARED_READ_END( &shared->seq ); - if (ret && (dpi = get_thread_dpi())) + if ((dpi = get_thread_dpi())) { HMONITOR monitor = monitor_from_rect( rect, MONITOR_DEFAULTTOPRIMARY, 0 ); *rect = map_dpi_rect( *rect, get_monitor_dpi( monitor ), dpi ); } - return ret; + return TRUE; } HICON alloc_cursoricon_handle( BOOL is_icon ) From 0611514213f1ecbbdc4cba637ab912184d91766e Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Tue, 30 Jun 2020 14:41:57 +0100 Subject: [PATCH 0290/2777] server: Get rid of the global cursor structure. Signed-off-by: Huw Davies --- server/queue.c | 10 +++++----- server/user.h | 9 ++------- server/winstation.c | 3 ++- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/server/queue.c b/server/queue.c index 452c19dea39..bdda47c95f7 100644 --- a/server/queue.c +++ b/server/queue.c @@ -517,8 +517,8 @@ void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int s SHARED_WRITE_BEGIN( &desktop->shared->seq ); desktop->shared->cursor.clip = new_rect; - if (desktop->cursor.clip_msg && send_clip_msg) - post_desktop_message( desktop, desktop->cursor.clip_msg, rect != NULL, 0 ); + if (desktop->cursor_clip_msg && send_clip_msg) + post_desktop_message( desktop, desktop->cursor_clip_msg, rect != NULL, 0 ); /* warp the mouse to be inside the clip rect */ x = max( min( desktop->shared->cursor.x, desktop->shared->cursor.clip.right - 1 ), desktop->shared->cursor.clip.left ); @@ -1734,8 +1734,8 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg } input = thread->queue->input; - if (win != desktop->cursor.win) always_queue = 1; - desktop->cursor.win = win; + if (win != desktop->cursor_win) always_queue = 1; + desktop->cursor_win = win; if (!always_queue || merge_message( input, msg )) free_message( msg ); else @@ -3550,7 +3550,7 @@ DECL_HANDLER(set_cursor) /* only the desktop owner can set the message */ if (req->clip_msg && get_top_window_owner(desktop) == current->process) - desktop->cursor.clip_msg = req->clip_msg; + desktop->cursor_clip_msg = req->clip_msg; set_clip_rectangle( desktop, (req->flags & SET_CURSOR_NOCLIP) ? NULL : &req->clip, 0 ); } diff --git a/server/user.h b/server/user.h index 430b299a3c3..fb0da874a6f 100644 --- a/server/user.h +++ b/server/user.h @@ -52,12 +52,6 @@ struct winstation struct namespace *desktop_names; /* namespace for desktops of this winstation */ }; -struct global_cursor -{ - unsigned int clip_msg; /* message to post for cursor clip changes */ - user_handle_t win; /* window that contains the cursor */ -}; - struct desktop { struct object obj; /* object header */ @@ -72,8 +66,9 @@ struct desktop struct list touches; /* list of active touches */ struct thread_input *foreground_input; /* thread input of foreground thread */ unsigned int users; /* processes and threads using this desktop */ - struct global_cursor cursor; /* global cursor information */ unsigned char keystate[256]; /* asynchronous key state */ + unsigned int cursor_clip_msg; /* message to post for cursor clip changes */ + user_handle_t cursor_win; /* window that contains the cursor */ struct object *shared_mapping; /* desktop shared memory mapping */ volatile struct desktop_shared_memory *shared; /* desktop shared memory ptr */ }; diff --git a/server/winstation.c b/server/winstation.c index f79a56ada6e..5c557b536d2 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -253,7 +253,8 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned desktop->close_timeout = NULL; desktop->foreground_input = NULL; desktop->users = 0; - memset( &desktop->cursor, 0, sizeof(desktop->cursor) ); + desktop->cursor_clip_msg = 0; + desktop->cursor_win = 0; memset( desktop->keystate, 0, sizeof(desktop->keystate) ); list_add_tail( &winstation->desktops, &desktop->entry ); list_init( &desktop->hotkeys ); From d8bac9f82e8b9c862de5ec535796e7d554aa7648 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Tue, 30 Jun 2020 15:42:25 +0100 Subject: [PATCH 0291/2777] server: Use a separate variable to determine the message on Alt release. Signed-off-by: Huw Davies --- server/queue.c | 11 +++++------ server/user.h | 1 + server/winstation.c | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/server/queue.c b/server/queue.c index bdda47c95f7..853dc39ab0e 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2041,17 +2041,16 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c if (input->kbd.flags & KEYEVENTF_KEYUP) { /* send WM_SYSKEYUP if Alt still pressed and no other key in between */ - /* we use 0x02 as a flag to track if some other SYSKEYUP was sent already */ - if ((desktop->keystate[VK_MENU] & 0x82) != 0x82) break; + if (!(desktop->keystate[VK_MENU] & 0x80) || !desktop->last_press_alt) break; message_code = WM_SYSKEYUP; - desktop->keystate[VK_MENU] &= ~0x02; + desktop->last_press_alt = 0; } else { /* send WM_SYSKEYDOWN for Alt except with Ctrl */ if (desktop->keystate[VK_CONTROL] & 0x80) break; message_code = WM_SYSKEYDOWN; - desktop->keystate[VK_MENU] |= 0x02; + desktop->last_press_alt = 1; } break; @@ -2061,7 +2060,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c if (!(input->kbd.flags & KEYEVENTF_KEYUP)) break; if (!(desktop->keystate[VK_MENU] & 0x80)) break; message_code = WM_SYSKEYUP; - desktop->keystate[VK_MENU] &= ~0x02; + desktop->last_press_alt = 0; break; default: @@ -2071,7 +2070,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c /* fall through */ case VK_F10: message_code = (input->kbd.flags & KEYEVENTF_KEYUP) ? WM_SYSKEYUP : WM_SYSKEYDOWN; - desktop->keystate[VK_MENU] &= ~0x02; + desktop->last_press_alt = 0; break; } diff --git a/server/user.h b/server/user.h index fb0da874a6f..90b4b0a5f83 100644 --- a/server/user.h +++ b/server/user.h @@ -71,6 +71,7 @@ struct desktop user_handle_t cursor_win; /* window that contains the cursor */ struct object *shared_mapping; /* desktop shared memory mapping */ volatile struct desktop_shared_memory *shared; /* desktop shared memory ptr */ + unsigned int last_press_alt:1; /* last key press was Alt (used to determine msg on Alt release) */ }; /* user handles functions */ diff --git a/server/winstation.c b/server/winstation.c index 5c557b536d2..4ff5e26ba14 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -255,6 +255,7 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned desktop->users = 0; desktop->cursor_clip_msg = 0; desktop->cursor_win = 0; + desktop->last_press_alt = 0; memset( desktop->keystate, 0, sizeof(desktop->keystate) ); list_add_tail( &winstation->desktops, &desktop->entry ); list_init( &desktop->hotkeys ); From a1bb1d689a3b3f4ef9926625889c9853a2daf09d Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Tue, 7 Jul 2020 13:35:21 +0100 Subject: [PATCH 0292/2777] server: Simplify update_input_key_state(). Signed-off-by: Huw Davies --- server/queue.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/server/queue.c b/server/queue.c index 853dc39ab0e..175e5112a18 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1448,7 +1448,7 @@ static struct timer *set_timer( struct msg_queue *queue, unsigned int rate ) } /* change the input key state for a given key */ -static void set_input_key_state( unsigned char *keystate, unsigned char key, int down ) +static void set_input_key_state( unsigned char *keystate, unsigned char key, unsigned char down ) { if (down) { @@ -1462,31 +1462,30 @@ static void set_input_key_state( unsigned char *keystate, unsigned char key, int static void update_input_key_state( struct desktop *desktop, unsigned char *keystate, unsigned int msg, lparam_t wparam ) { - unsigned char key; - int down = 0; + unsigned char key, down = 0, down_val = (keystate == desktop->keystate) ? 0xc0 : 0x80; switch (msg) { case WM_LBUTTONDOWN: - down = (keystate == desktop->keystate) ? 0xc0 : 0x80; + down = down_val; /* fall through */ case WM_LBUTTONUP: set_input_key_state( keystate, VK_LBUTTON, down ); break; case WM_MBUTTONDOWN: - down = (keystate == desktop->keystate) ? 0xc0 : 0x80; + down = down_val; /* fall through */ case WM_MBUTTONUP: set_input_key_state( keystate, VK_MBUTTON, down ); break; case WM_RBUTTONDOWN: - down = (keystate == desktop->keystate) ? 0xc0 : 0x80; + down = down_val; /* fall through */ case WM_RBUTTONUP: set_input_key_state( keystate, VK_RBUTTON, down ); break; case WM_XBUTTONDOWN: - down = (keystate == desktop->keystate) ? 0xc0 : 0x80; + down = down_val; /* fall through */ case WM_XBUTTONUP: if (wparam >> 16 == XBUTTON1) set_input_key_state( keystate, VK_XBUTTON1, down ); @@ -1494,7 +1493,7 @@ static void update_input_key_state( struct desktop *desktop, unsigned char *keys break; case WM_KEYDOWN: case WM_SYSKEYDOWN: - down = (keystate == desktop->keystate) ? 0xc0 : 0x80; + down = down_val; /* fall through */ case WM_KEYUP: case WM_SYSKEYUP: From cbbf59a115ba2f5a21ceb41370f7e48e1ad16eb9 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Wed, 8 Jul 2020 13:39:49 +0100 Subject: [PATCH 0293/2777] server: Use separate functions to update the desktop and input keystates. Signed-off-by: Huw Davies --- server/queue.c | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/server/queue.c b/server/queue.c index 175e5112a18..04bfa094399 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1459,10 +1459,10 @@ static void set_input_key_state( unsigned char *keystate, unsigned char key, uns } /* update the input key state for a keyboard message */ -static void update_input_key_state( struct desktop *desktop, unsigned char *keystate, - unsigned int msg, lparam_t wparam ) +static void update_key_state( unsigned char *keystate, unsigned int msg, + lparam_t wparam, int desktop ) { - unsigned char key, down = 0, down_val = (keystate == desktop->keystate) ? 0xc0 : 0x80; + unsigned char key, down = 0, down_val = desktop ? 0xc0 : 0x80; switch (msg) { @@ -1521,6 +1521,16 @@ static void update_input_key_state( struct desktop *desktop, unsigned char *keys } } +static void update_input_key_state( struct thread_input *input, unsigned int msg, lparam_t wparam ) +{ + update_key_state( input->keystate, msg, wparam, 0 ); +} + +static void update_desktop_key_state( struct desktop *desktop, unsigned int msg, lparam_t wparam ) +{ + update_key_state( desktop->keystate, msg, wparam, 1 ); +} + /* update the desktop key state according to a mouse message flags */ static void update_desktop_mouse_state( struct desktop *desktop, unsigned int flags, int x, int y, lparam_t wparam ) @@ -1528,21 +1538,21 @@ static void update_desktop_mouse_state( struct desktop *desktop, unsigned int fl if (flags & MOUSEEVENTF_MOVE) update_desktop_cursor_pos( desktop, x, y ); if (flags & MOUSEEVENTF_LEFTDOWN) - update_input_key_state( desktop, desktop->keystate, WM_LBUTTONDOWN, wparam ); + update_desktop_key_state( desktop, WM_LBUTTONDOWN, wparam ); if (flags & MOUSEEVENTF_LEFTUP) - update_input_key_state( desktop, desktop->keystate, WM_LBUTTONUP, wparam ); + update_desktop_key_state( desktop, WM_LBUTTONUP, wparam ); if (flags & MOUSEEVENTF_RIGHTDOWN) - update_input_key_state( desktop, desktop->keystate, WM_RBUTTONDOWN, wparam ); + update_desktop_key_state( desktop, WM_RBUTTONDOWN, wparam ); if (flags & MOUSEEVENTF_RIGHTUP) - update_input_key_state( desktop, desktop->keystate, WM_RBUTTONUP, wparam ); + update_desktop_key_state( desktop, WM_RBUTTONUP, wparam ); if (flags & MOUSEEVENTF_MIDDLEDOWN) - update_input_key_state( desktop, desktop->keystate, WM_MBUTTONDOWN, wparam ); + update_desktop_key_state( desktop, WM_MBUTTONDOWN, wparam ); if (flags & MOUSEEVENTF_MIDDLEUP) - update_input_key_state( desktop, desktop->keystate, WM_MBUTTONUP, wparam ); + update_desktop_key_state( desktop, WM_MBUTTONUP, wparam ); if (flags & MOUSEEVENTF_XDOWN) - update_input_key_state( desktop, desktop->keystate, WM_XBUTTONDOWN, wparam ); + update_desktop_key_state( desktop, WM_XBUTTONDOWN, wparam ); if (flags & MOUSEEVENTF_XUP) - update_input_key_state( desktop, desktop->keystate, WM_XBUTTONUP, wparam ); + update_desktop_key_state( desktop, WM_XBUTTONUP, wparam ); } /* release the hardware message currently being processed by the given thread */ @@ -1570,7 +1580,7 @@ static void release_hardware_message( struct msg_queue *queue, unsigned int hw_i } if (clr_bit) clear_queue_bits( queue, clr_bit ); - update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); + update_input_key_state( input, msg->msg, msg->wparam ); list_remove( &msg->entry ); free_message( msg ); } @@ -1680,7 +1690,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg struct hardware_msg_data *msg_data = msg->data; unsigned int msg_code; - update_input_key_state( desktop, desktop->keystate, msg->msg, msg->wparam ); + update_desktop_key_state( desktop, msg->msg, msg->wparam ); last_input_time = get_tick_count(); if (msg->msg != WM_MOUSEMOVE) always_queue = 1; @@ -1727,7 +1737,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg win = find_hardware_message_window( desktop, input, msg, &msg_code, &thread ); if (!win || !thread) { - if (input) update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); + if (input) update_input_key_state( input, msg->msg, msg->wparam ); free_message( msg ); return; } @@ -2097,7 +2107,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c if ((device = current->process->rawinput_kbd) && (device->flags & RIDEV_NOLEGACY)) { - update_input_key_state( desktop, desktop->keystate, message_code, vkey ); + update_desktop_key_state( desktop, message_code, vkey ); return 0; } @@ -2343,7 +2353,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user if (!win || !win_thread) { /* no window at all, remove it */ - update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); + update_input_key_state( input, msg->msg, msg->wparam ); list_remove( &msg->entry ); free_message( msg ); continue; @@ -2359,7 +2369,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user else { /* for another thread input, drop it */ - update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); + update_input_key_state( input, msg->msg, msg->wparam ); list_remove( &msg->entry ); free_message( msg ); } From 8a89275d807817388081c907e3d721734dfeb189 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Wed, 8 Jul 2020 08:26:21 +0100 Subject: [PATCH 0294/2777] server: Move the desktop keystate to shared memory. Signed-off-by: Huw Davies --- server/protocol.def | 1 + server/queue.c | 68 +++++++++++++++++++++++++-------------------- server/winstation.c | 1 - 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/server/protocol.def b/server/protocol.def index 94acbb05392..9fa24ee12c4 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -877,6 +877,7 @@ struct desktop_shared_memory { unsigned int seq; /* sequence number - server updating if (seq_no & SEQUENCE_MASK) != 0 */ struct shared_cursor cursor; /* global cursor information */ + unsigned char keystate[256]; /* asynchronous key state */ }; /* Bits that must be clear for client to read */ diff --git a/server/queue.c b/server/queue.c index 04bfa094399..c37a1059d35 100644 --- a/server/queue.c +++ b/server/queue.c @@ -280,7 +280,8 @@ static struct thread_input *create_thread_input( struct thread *thread ) release_object( input ); return NULL; } - memcpy( input->desktop_keystate, input->desktop->keystate, sizeof(input->desktop_keystate) ); + memcpy( input->desktop_keystate, (void *)input->desktop->shared->keystate, + sizeof(input->desktop_keystate) ); } return input; } @@ -341,8 +342,8 @@ static void sync_input_keystate( struct thread_input *input ) if (!input->desktop || input->keystate_lock) return; for (i = 0; i < sizeof(input->keystate); ++i) { - if (input->desktop_keystate[i] == input->desktop->keystate[i]) continue; - input->keystate[i] = input->desktop_keystate[i] = input->desktop->keystate[i]; + if (input->desktop_keystate[i] == input->desktop->shared->keystate[i]) continue; + input->keystate[i] = input->desktop_keystate[i] = input->desktop->shared->keystate[i]; } } @@ -1448,7 +1449,7 @@ static struct timer *set_timer( struct msg_queue *queue, unsigned int rate ) } /* change the input key state for a given key */ -static void set_input_key_state( unsigned char *keystate, unsigned char key, unsigned char down ) +static void set_input_key_state( volatile unsigned char *keystate, unsigned char key, unsigned char down ) { if (down) { @@ -1459,7 +1460,7 @@ static void set_input_key_state( unsigned char *keystate, unsigned char key, uns } /* update the input key state for a keyboard message */ -static void update_key_state( unsigned char *keystate, unsigned int msg, +static void update_key_state( volatile unsigned char *keystate, unsigned int msg, lparam_t wparam, int desktop ) { unsigned char key, down = 0, down_val = desktop ? 0xc0 : 0x80; @@ -1528,7 +1529,9 @@ static void update_input_key_state( struct thread_input *input, unsigned int msg static void update_desktop_key_state( struct desktop *desktop, unsigned int msg, lparam_t wparam ) { - update_key_state( desktop->keystate, msg, wparam, 1 ); + SHARED_WRITE_BEGIN( &desktop->shared->seq ); + update_key_state( desktop->shared->keystate, msg, wparam, 1 ); + SHARED_WRITE_END( &desktop->shared->seq ); } /* update the desktop key state according to a mouse message flags */ @@ -1592,10 +1595,10 @@ static int queue_hotkey_message( struct desktop *desktop, struct message *msg ) if (msg->msg != WM_KEYDOWN && msg->msg != WM_SYSKEYDOWN) return 0; - if (desktop->keystate[VK_MENU] & 0x80) modifiers |= MOD_ALT; - if (desktop->keystate[VK_CONTROL] & 0x80) modifiers |= MOD_CONTROL; - if (desktop->keystate[VK_SHIFT] & 0x80) modifiers |= MOD_SHIFT; - if ((desktop->keystate[VK_LWIN] & 0x80) || (desktop->keystate[VK_RWIN] & 0x80)) modifiers |= MOD_WIN; + if (desktop->shared->keystate[VK_MENU] & 0x80) modifiers |= MOD_ALT; + if (desktop->shared->keystate[VK_CONTROL] & 0x80) modifiers |= MOD_CONTROL; + if (desktop->shared->keystate[VK_SHIFT] & 0x80) modifiers |= MOD_SHIFT; + if ((desktop->shared->keystate[VK_LWIN] & 0x80) || (desktop->shared->keystate[VK_RWIN] & 0x80)) modifiers |= MOD_WIN; LIST_FOR_EACH_ENTRY( hotkey, &desktop->hotkeys, struct hotkey, entry ) { @@ -1697,7 +1700,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg if (is_keyboard_msg( msg )) { if (queue_hotkey_message( desktop, msg )) return; - if (desktop->keystate[VK_MENU] & 0x80) msg->lparam |= KF_ALTDOWN << 16; + if (desktop->shared->keystate[VK_MENU] & 0x80) msg->lparam |= KF_ALTDOWN << 16; if (msg->wparam == VK_SHIFT || msg->wparam == VK_LSHIFT || msg->wparam == VK_RSHIFT) msg->lparam &= ~(KF_EXTENDED << 16); } @@ -1716,13 +1719,13 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg prepend_cursor_history( msg->x, msg->y, msg->time, msg_data->info ); if (update_desktop_cursor_pos( desktop, msg->x, msg->y )) always_queue = 1; } - if (desktop->keystate[VK_LBUTTON] & 0x80) msg->wparam |= MK_LBUTTON; - if (desktop->keystate[VK_MBUTTON] & 0x80) msg->wparam |= MK_MBUTTON; - if (desktop->keystate[VK_RBUTTON] & 0x80) msg->wparam |= MK_RBUTTON; - if (desktop->keystate[VK_SHIFT] & 0x80) msg->wparam |= MK_SHIFT; - if (desktop->keystate[VK_CONTROL] & 0x80) msg->wparam |= MK_CONTROL; - if (desktop->keystate[VK_XBUTTON1] & 0x80) msg->wparam |= MK_XBUTTON1; - if (desktop->keystate[VK_XBUTTON2] & 0x80) msg->wparam |= MK_XBUTTON2; + if (desktop->shared->keystate[VK_LBUTTON] & 0x80) msg->wparam |= MK_LBUTTON; + if (desktop->shared->keystate[VK_MBUTTON] & 0x80) msg->wparam |= MK_MBUTTON; + if (desktop->shared->keystate[VK_RBUTTON] & 0x80) msg->wparam |= MK_RBUTTON; + if (desktop->shared->keystate[VK_SHIFT] & 0x80) msg->wparam |= MK_SHIFT; + if (desktop->shared->keystate[VK_CONTROL] & 0x80) msg->wparam |= MK_CONTROL; + if (desktop->shared->keystate[VK_XBUTTON1] & 0x80) msg->wparam |= MK_XBUTTON1; + if (desktop->shared->keystate[VK_XBUTTON2] & 0x80) msg->wparam |= MK_XBUTTON2; } msg->x = desktop->shared->cursor.x; msg->y = desktop->shared->cursor.y; @@ -2050,14 +2053,14 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c if (input->kbd.flags & KEYEVENTF_KEYUP) { /* send WM_SYSKEYUP if Alt still pressed and no other key in between */ - if (!(desktop->keystate[VK_MENU] & 0x80) || !desktop->last_press_alt) break; + if (!(desktop->shared->keystate[VK_MENU] & 0x80) || !desktop->last_press_alt) break; message_code = WM_SYSKEYUP; desktop->last_press_alt = 0; } else { /* send WM_SYSKEYDOWN for Alt except with Ctrl */ - if (desktop->keystate[VK_CONTROL] & 0x80) break; + if (desktop->shared->keystate[VK_CONTROL] & 0x80) break; message_code = WM_SYSKEYDOWN; desktop->last_press_alt = 1; } @@ -2067,15 +2070,15 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c case VK_RCONTROL: /* send WM_SYSKEYUP on release if Alt still pressed */ if (!(input->kbd.flags & KEYEVENTF_KEYUP)) break; - if (!(desktop->keystate[VK_MENU] & 0x80)) break; + if (!(desktop->shared->keystate[VK_MENU] & 0x80)) break; message_code = WM_SYSKEYUP; desktop->last_press_alt = 0; break; default: /* send WM_SYSKEY for Alt-anykey and for F10 */ - if (desktop->keystate[VK_CONTROL] & 0x80) break; - if (!(desktop->keystate[VK_MENU] & 0x80)) break; + if (desktop->shared->keystate[VK_CONTROL] & 0x80) break; + if (!(desktop->shared->keystate[VK_MENU] & 0x80)) break; /* fall through */ case VK_F10: message_code = (input->kbd.flags & KEYEVENTF_KEYUP) ? WM_SYSKEYUP : WM_SYSKEYDOWN; @@ -2129,7 +2132,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c if (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED; /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */ if (input->kbd.flags & KEYEVENTF_KEYUP) flags |= KF_REPEAT | KF_UP; - else if (desktop->keystate[vkey] & 0x80) flags |= KF_REPEAT; + else if (desktop->shared->keystate[vkey] & 0x80) flags |= KF_REPEAT; msg->wparam = vkey; msg->lparam |= flags << 16; @@ -2830,7 +2833,7 @@ DECL_HANDLER(send_hardware_message) reply->new_x = desktop->shared->cursor.x; reply->new_y = desktop->shared->cursor.y; - set_reply_data( desktop->keystate, size ); + set_reply_data( (void *)desktop->shared->keystate, size ); release_object( desktop ); } @@ -3315,10 +3318,12 @@ DECL_HANDLER(get_key_state) if (!(desktop = get_thread_desktop( current, 0 ))) return; if (req->key >= 0) { - reply->state = desktop->keystate[req->key & 0xff]; - desktop->keystate[req->key & 0xff] &= ~0x40; + reply->state = desktop->shared->keystate[req->key & 0xff]; + SHARED_WRITE_BEGIN( &desktop->shared->seq ); + desktop->shared->keystate[req->key & 0xff] &= ~0x40; + SHARED_WRITE_END( &desktop->shared->seq ); } - set_reply_data( desktop->keystate, size ); + set_reply_data( (void *)desktop->shared->keystate, size ); release_object( desktop ); } else @@ -3343,10 +3348,13 @@ DECL_HANDLER(set_key_state) data_size_t size = min( 256, get_req_data_size() ); memcpy( queue->input->keystate, get_req_data(), size ); - memcpy( queue->input->desktop_keystate, queue->input->desktop->keystate, 256 ); + memcpy( queue->input->desktop_keystate, (void *)queue->input->desktop->shared->keystate, + sizeof(queue->input->desktop_keystate) ); if (req->async && (desktop = get_thread_desktop( current, 0 ))) { - memcpy( desktop->keystate, get_req_data(), size ); + SHARED_WRITE_BEGIN( &desktop->shared->seq ); + memcpy( (void *)desktop->shared->keystate, get_req_data(), size ); + SHARED_WRITE_END( &desktop->shared->seq ); release_object( desktop ); } } diff --git a/server/winstation.c b/server/winstation.c index 4ff5e26ba14..72073edc14e 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -256,7 +256,6 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned desktop->cursor_clip_msg = 0; desktop->cursor_win = 0; desktop->last_press_alt = 0; - memset( desktop->keystate, 0, sizeof(desktop->keystate) ); list_add_tail( &winstation->desktops, &desktop->entry ); list_init( &desktop->hotkeys ); list_init( &desktop->touches ); From 0c3f0c750a92e63bcd1b3e3c421291657aa14493 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Wed, 8 Jul 2020 15:45:24 +0100 Subject: [PATCH 0295/2777] user32: Use the shared data if possible for GetAsyncKeyState(). Signed-off-by: Huw Davies --- dlls/win32u/hook.c | 2 -- dlls/win32u/input.c | 39 +++++++++--------------------------- dlls/win32u/message.c | 16 ++------------- dlls/win32u/ntuser_private.h | 8 -------- dlls/win32u/sysparams.c | 2 -- dlls/win32u/win32u_private.h | 1 - dlls/win32u/winstation.c | 2 -- 7 files changed, 11 insertions(+), 59 deletions(-) diff --git a/dlls/win32u/hook.c b/dlls/win32u/hook.c index 0216811c90c..a94cc7cf991 100644 --- a/dlls/win32u/hook.c +++ b/dlls/win32u/hook.c @@ -331,8 +331,6 @@ static LRESULT call_hook( struct win_hook_params *info, const WCHAR *module ) if (params != info) free( params ); } - if (info->id == WH_KEYBOARD_LL || info->id == WH_MOUSE_LL) - InterlockedIncrement( &global_key_state_counter ); /* force refreshing the key state cache */ return ret; } diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 05241ccbf28..b79ae675678 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -51,7 +51,6 @@ static const WCHAR keyboard_layouts_keyW[] = }; -LONG global_key_state_counter = 0; BOOL enable_mouse_in_pointer = FALSE; @@ -279,52 +278,32 @@ static void check_for_events( UINT flags ) */ SHORT WINAPI NtUserGetAsyncKeyState( INT key ) { - struct user_key_state_info *key_state_info = get_user_thread_info()->key_state; - INT counter = global_key_state_counter; - BYTE prev_key_state; + volatile struct desktop_shared_memory *shared = get_desktop_shared_memory(); + BYTE state; SHORT ret; - if (key < 0 || key >= 256) return 0; + if (key < 0 || key >= 256 || !shared) return 0; check_for_events( QS_INPUT ); - if (key_state_info && !(key_state_info->state[key] & 0xc0) && - key_state_info->counter == counter && NtGetTickCount() - key_state_info->time < 50) - { - /* use cached value */ - return 0; - } - else if (!key_state_info) + SHARED_READ_BEGIN( &shared->seq ) { - key_state_info = calloc( 1, sizeof(*key_state_info) ); - get_user_thread_info()->key_state = key_state_info; + state = shared->keystate[key]; } + SHARED_READ_END( &shared->seq ); + if (!(state & 0x40)) return (state & 0x80) << 8; + + /* Need to make a server call to reset the last pressed bit */ ret = 0; SERVER_START_REQ( get_key_state ) { req->async = 1; req->key = key; - if (key_state_info) - { - prev_key_state = key_state_info->state[key]; - wine_server_set_reply( req, key_state_info->state, sizeof(key_state_info->state) ); - } if (!wine_server_call( req )) { if (reply->state & 0x40) ret |= 0x0001; if (reply->state & 0x80) ret |= 0x8000; - if (key_state_info) - { - /* force refreshing the key state cache - some multithreaded programs - * (like Adobe Photoshop CS5) expect that changes to the async key state - * are also immediately available in other threads. */ - if (prev_key_state != key_state_info->state[key]) - counter = InterlockedIncrement( &global_key_state_counter ); - - key_state_info->time = NtGetTickCount(); - key_state_info->counter = counter; - } } } SERVER_END_REQ; diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 47285a6fb90..edc398f1b75 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2638,10 +2638,8 @@ LRESULT send_internal_message_timeout( DWORD dest_pid, DWORD dest_tid, */ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput, UINT flags ) { - struct user_key_state_info *key_state_info = get_user_thread_info()->key_state; struct send_message_info info; int prev_x, prev_y, new_x, new_y; - INT counter = global_key_state_counter; USAGE hid_usage_page, hid_usage; NTSTATUS ret; BOOL wait; @@ -2728,8 +2726,6 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r } break; } - if (key_state_info) wine_server_set_reply( req, key_state_info->state, - sizeof(key_state_info->state) ); ret = wine_server_call( req ); wait = reply->wait; prev_x = reply->prev_x; @@ -2739,16 +2735,8 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r } SERVER_END_REQ; - if (!ret) - { - if (key_state_info) - { - key_state_info->time = NtGetTickCount(); - key_state_info->counter = counter; - } - if ((flags & SEND_HWMSG_INJECTED) && (prev_x != new_x || prev_y != new_y)) - user_driver->pSetCursorPos( new_x, new_y ); - } + if (!ret && (flags & SEND_HWMSG_INJECTED) && (prev_x != new_x || prev_y != new_y)) + user_driver->pSetCursorPos( new_x, new_y ); if (wait) { diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index e2771491372..501cc6e8aa4 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -130,7 +130,6 @@ struct user_thread_info HHOOK hook; /* Current hook */ UINT active_hooks; /* Bitmap of active hooks */ struct received_message_info *receive_info; /* Message being currently received */ - struct user_key_state_info *key_state; /* Cache of global key state */ struct imm_thread_data *imm_thread_data; /* IMM thread data */ HKL kbd_layout; /* Current keyboard layout */ UINT kbd_layout_id; /* Current keyboard layout ID */ @@ -147,13 +146,6 @@ static inline struct user_thread_info *get_user_thread_info(void) return CONTAINING_RECORD( NtUserGetThreadInfo(), struct user_thread_info, client_info ); } -struct user_key_state_info -{ - UINT time; /* Time of last key state refresh */ - INT counter; /* Counter to invalidate the key state */ - BYTE state[256]; /* State for each key */ -}; - struct hook_extra_info { HHOOK handle; diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 67bbb03f30d..8bb3ef49ea0 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -5429,8 +5429,6 @@ static void thread_detach(void) user_driver->pThreadDetach(); - free( thread_info->key_state ); - thread_info->key_state = 0; free( thread_info->rawinput ); destroy_thread_windows(); diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 8c56e65b986..87c76e7422c 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -266,7 +266,6 @@ extern void unregister_imm_window( HWND hwnd ) DECLSPEC_HIDDEN; /* input.c */ extern BOOL destroy_caret(void) DECLSPEC_HIDDEN; extern BOOL enable_mouse_in_pointer DECLSPEC_HIDDEN; -extern LONG global_key_state_counter DECLSPEC_HIDDEN; extern HWND get_active_window(void) DECLSPEC_HIDDEN; extern HWND get_capture(void) DECLSPEC_HIDDEN; extern BOOL get_cursor_pos( POINT *pt ) DECLSPEC_HIDDEN; diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index b6d1d1c8013..e123a4d09f5 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -238,10 +238,8 @@ BOOL WINAPI NtUserSetThreadDesktop( HDESK handle ) if (ret) /* reset the desktop windows */ { struct user_thread_info *thread_info = get_user_thread_info(); - struct user_key_state_info *key_state_info = thread_info->key_state; thread_info->client_info.top_window = 0; thread_info->client_info.msg_window = 0; - if (key_state_info) key_state_info->time = 0; if (thread_info->desktop_shared_map) { NtClose( thread_info->desktop_shared_map ); From 2371cdcffd69294bc4dfc992979255b31735c197 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Wed, 8 Jul 2020 16:07:08 +0100 Subject: [PATCH 0296/2777] server: Don't return the desktop keystate from the send_hardware_message request. Signed-off-by: Huw Davies --- server/protocol.def | 1 - server/queue.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/server/protocol.def b/server/protocol.def index 9fa24ee12c4..ef1a9fc1731 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2098,7 +2098,6 @@ enum message_type int prev_y; int new_x; /* new cursor position */ int new_y; - VARARG(keystate,bytes); /* global state array for all the keys */ @END #define SEND_HWMSG_INJECTED 0x01 #define SEND_HWMSG_RAWINPUT 0x02 diff --git a/server/queue.c b/server/queue.c index c37a1059d35..ef8a089ce64 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2797,7 +2797,6 @@ DECL_HANDLER(send_hardware_message) struct desktop *desktop; unsigned int origin = (req->flags & SEND_HWMSG_INJECTED ? IMO_INJECTED : IMO_HARDWARE); struct msg_queue *sender = get_current_queue(); - data_size_t size = min( 256, get_reply_max_size() ); if (!(desktop = get_thread_desktop( current, 0 ))) return; @@ -2833,7 +2832,6 @@ DECL_HANDLER(send_hardware_message) reply->new_x = desktop->shared->cursor.x; reply->new_y = desktop->shared->cursor.y; - set_reply_data( (void *)desktop->shared->keystate, size ); release_object( desktop ); } From 404d68c05d1ea2e1a1fb6b16e0b93a8d55361d74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 23 Nov 2020 17:21:46 +0100 Subject: [PATCH 0297/2777] user32: Refresh active hook list only when needed. Instead of doing it on every get_message request. --- dlls/win32u/hook.c | 29 ++++++++++++++++++++++++----- dlls/win32u/message.c | 4 +++- server/hook.c | 8 +++++++- server/protocol.def | 8 +++++++- server/queue.c | 2 -- server/user.h | 1 - 6 files changed, 41 insertions(+), 11 deletions(-) diff --git a/dlls/win32u/hook.c b/dlls/win32u/hook.c index a94cc7cf991..e6b3531ff05 100644 --- a/dlls/win32u/hook.c +++ b/dlls/win32u/hook.c @@ -60,12 +60,31 @@ static const char *debugstr_hook_id( unsigned int id ) return hook_names[id - WH_MINHOOK]; } -BOOL is_hooked( INT id ) +/*********************************************************************** + * get_active_hooks + * + */ +static UINT get_active_hooks(void) { struct user_thread_info *thread_info = get_user_thread_info(); - if (!thread_info->active_hooks) return TRUE; - return (thread_info->active_hooks & (1 << (id - WH_MINHOOK))) != 0; + if (!thread_info->active_hooks) + { + SERVER_START_REQ( get_active_hooks ) + { + if (!wine_server_call( req )) thread_info->active_hooks = reply->active_hooks; + } + SERVER_END_REQ; + } + + return thread_info->active_hooks; +} + +BOOL is_hooked( INT id ) +{ + UINT active_hooks = get_active_hooks(); + if (!active_hooks) return TRUE; + return (active_hooks & (1 << (id - WH_MINHOOK))) != 0; } /*********************************************************************** @@ -415,7 +434,7 @@ LRESULT call_hooks( INT id, INT code, WPARAM wparam, LPARAM lparam, size_t lpara if (!is_hooked( id )) { - TRACE( "skipping hook %s mask %x\n", hook_names[id-WH_MINHOOK], thread_info->active_hooks ); + TRACE( "skipping hook %s mask %x\n", hook_names[id-WH_MINHOOK], get_active_hooks() ); return 0; } @@ -550,7 +569,7 @@ void WINAPI NtUserNotifyWinEvent( DWORD event, HWND hwnd, LONG object_id, LONG c if (!is_hooked( WH_WINEVENT )) { - TRACE( "skipping hook mask %x\n", thread_info->active_hooks ); + TRACE( "skipping hook mask %x\n", get_active_hooks() ); return; } diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index edc398f1b75..8d4f054e9d8 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1890,12 +1890,14 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, info.msg.pt.x = reply->x; info.msg.pt.y = reply->y; hw_id = 0; - thread_info->active_hooks = reply->active_hooks; } else buffer_size = reply->total; } SERVER_END_REQ; + /* force refreshing hooks */ + thread_info->active_hooks = 0; + if (res) { free( buffer ); diff --git a/server/hook.c b/server/hook.c index da351d6791f..95a588c843b 100644 --- a/server/hook.c +++ b/server/hook.c @@ -356,7 +356,7 @@ static int is_hook_active( struct hook_table *table, int index ) } /* get a bitmap of all active hooks for the current thread */ -unsigned int get_active_hooks(void) +static unsigned int get_active_hooks(void) { struct hook_table *table = get_queue_hooks( current ); struct hook_table *global_hooks = get_global_hooks( current ); @@ -383,6 +383,12 @@ struct thread *get_first_global_hook( int id ) return hook->owner; } +/* get thread active hooks */ +DECL_HANDLER(get_active_hooks) +{ + reply->active_hooks = get_active_hooks(); +} + /* set a window hook */ DECL_HANDLER(set_hook) { diff --git a/server/protocol.def b/server/protocol.def index ef1a9fc1731..7f04afdc4e0 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2121,7 +2121,6 @@ enum message_type int x; /* message x position */ int y; /* message y position */ unsigned int time; /* message time */ - unsigned int active_hooks; /* active hooks bitmap */ data_size_t total; /* total size of extra data */ VARARG(data,message_data); /* message data for sent messages */ @END @@ -2916,6 +2915,13 @@ enum caret_state }; +/* get thread active hooks */ +@REQ(get_active_hooks) +@REPLY + unsigned int active_hooks; /* active hooks bitmap */ +@END + + /* Set a window hook */ @REQ(set_hook) int id; /* id of the hook */ diff --git a/server/queue.c b/server/queue.c index ef8a089ce64..fdf7c4cdf96 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2857,8 +2857,6 @@ DECL_HANDLER(get_message) user_handle_t get_win = get_user_full_handle( req->get_win ); unsigned int filter = req->flags >> 16; - reply->active_hooks = get_active_hooks(); - if (get_win && get_win != 1 && get_win != -1 && !get_user_object( get_win, USER_WINDOW )) { set_win32_error( ERROR_INVALID_WINDOW_HANDLE ); diff --git a/server/user.h b/server/user.h index 90b4b0a5f83..345db9225d4 100644 --- a/server/user.h +++ b/server/user.h @@ -92,7 +92,6 @@ extern void cleanup_clipboard_thread( struct thread *thread ); /* hook functions */ extern void remove_thread_hooks( struct thread *thread ); -extern unsigned int get_active_hooks(void); extern struct thread *get_first_global_hook( int id ); /* queue functions */ From 072e06d46bb9f6329888a6944bbf4e58ee96db3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 21 Nov 2020 00:20:27 +0100 Subject: [PATCH 0298/2777] server: Create a thread queue shared mapping. --- server/directory.c | 15 ++++++++ server/file.h | 1 + server/protocol.def | 6 ++++ server/queue.c | 85 ++++++++++++++++++++++++--------------------- server/thread.c | 32 +++++++++++++++++ server/thread.h | 2 ++ 6 files changed, 101 insertions(+), 40 deletions(-) diff --git a/server/directory.c b/server/directory.c index 98e4e55e4a0..dc3f0cf3cf8 100644 --- a/server/directory.c +++ b/server/directory.c @@ -296,6 +296,21 @@ struct object *create_desktop_map_directory( struct winstation *winstation ) return &ret->obj; } +struct object *create_thread_map_directory( void ) +{ + static const WCHAR dir_kernelW[] = {'K','e','r','n','e','l','O','b','j','e','c','t','s'}; + static const WCHAR dir_thread_mapsW[] = {'_','_','w','i','n','e','_','t','h','r','e','a','d','_','m','a','p','p','i','n','g','s'}; + static const struct unicode_str dir_kernel_str = {dir_kernelW, sizeof(dir_kernelW)}; + static const struct unicode_str dir_thread_maps_str = {dir_thread_mapsW, sizeof(dir_thread_mapsW)}; + struct directory *mapping_root, *ret; + + mapping_root = create_directory( &root_directory->obj, &dir_kernel_str, OBJ_OPENIF, HASH_SIZE, NULL ); + ret = create_directory( &mapping_root->obj, &dir_thread_maps_str, OBJ_OPENIF, HASH_SIZE, NULL ); + release_object( &mapping_root->obj ); + + return &ret->obj; +} + /* Global initialization */ static void create_session( unsigned int id ) diff --git a/server/file.h b/server/file.h index f964ff03d8a..7069a60e492 100644 --- a/server/file.h +++ b/server/file.h @@ -160,6 +160,7 @@ extern const char *get_timeout_str( timeout_t timeout ); /* directory functions */ extern struct object *create_desktop_map_directory( struct winstation *winstation ); +extern struct object *create_thread_map_directory( void ); /* file functions */ diff --git a/server/protocol.def b/server/protocol.def index 7f04afdc4e0..c5f07d3b3f0 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -880,6 +880,12 @@ struct desktop_shared_memory unsigned char keystate[256]; /* asynchronous key state */ }; +struct queue_shared_memory +{ + unsigned int seq; /* sequence number - server updating if (seq_no & SEQUENCE_MASK) != 0 */ + int created; /* queue has been created */ +}; + /* Bits that must be clear for client to read */ #define SEQUENCE_MASK_BITS 4 #define SEQUENCE_MASK ((1UL << SEQUENCE_MASK_BITS) - 1) diff --git a/server/queue.c b/server/queue.c index fdf7c4cdf96..c4e4bfbdb2b 100644 --- a/server/queue.c +++ b/server/queue.c @@ -145,6 +145,7 @@ struct msg_queue int keystate_lock; /* owns an input keystate lock */ int esync_fd; /* esync file descriptor (signalled on message) */ int esync_in_msgwait; /* our thread is currently waiting on us */ + volatile struct queue_shared_memory *shared; /* thread queue shared memory ptr */ }; struct hotkey @@ -238,6 +239,46 @@ static unsigned int last_input_time; static cursor_pos_t cursor_history[64]; static unsigned int cursor_history_latest; +#if defined(__i386__) || defined(__x86_64__) + +#define SHARED_WRITE_BEGIN( x ) \ + do { \ + volatile unsigned int __seq = *(x); \ + assert( (__seq & SEQUENCE_MASK) != SEQUENCE_MASK ); \ + *(x) = ++__seq; \ + } while(0) + +#define SHARED_WRITE_END( x ) \ + do { \ + volatile unsigned int __seq = *(x); \ + assert( (__seq & SEQUENCE_MASK) != 0 ); \ + if ((__seq & SEQUENCE_MASK) > 1) __seq--; \ + else __seq += SEQUENCE_MASK; \ + *(x) = __seq; \ + } while(0) + +#else + +#define SHARED_WRITE_BEGIN( x ) \ + do { \ + assert( (*(x) & SEQUENCE_MASK) != SEQUENCE_MASK ); \ + if ((__atomic_add_fetch( x, 1, __ATOMIC_RELAXED ) & SEQUENCE_MASK) == 1) \ + __atomic_thread_fence( __ATOMIC_RELEASE ); \ + } while(0) + +#define SHARED_WRITE_END( x ) \ + do { \ + assert( (*(x) & SEQUENCE_MASK) != 0 ); \ + if ((*(x) & SEQUENCE_MASK) > 1) \ + __atomic_sub_fetch( x, 1, __ATOMIC_RELAXED ); \ + else { \ + __atomic_thread_fence( __ATOMIC_RELEASE ); \ + __atomic_add_fetch( x, SEQUENCE_MASK, __ATOMIC_RELAXED ); \ + } \ + } while(0) + +#endif + static void queue_hardware_message( struct desktop *desktop, struct message *msg, int always_queue ); static void free_message( struct message *msg ); @@ -320,6 +361,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ queue->keystate_lock = 0; queue->esync_fd = -1; queue->esync_in_msgwait = 0; + queue->shared = thread->queue_shared; list_init( &queue->send_result ); list_init( &queue->callback_result ); list_init( &queue->pending_timers ); @@ -329,6 +371,9 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ if (do_esync()) queue->esync_fd = esync_create_fd( 0, 0 ); + SHARED_WRITE_BEGIN( &queue->shared->seq ); + queue->shared->created = TRUE; + SHARED_WRITE_END( &queue->shared->seq ); thread->queue = queue; } if (new_input) release_object( new_input ); @@ -408,46 +453,6 @@ static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_sour return msg; } -#if defined(__i386__) || defined(__x86_64__) - -#define SHARED_WRITE_BEGIN( x ) \ - do { \ - volatile unsigned int __seq = *(x); \ - assert( (__seq & SEQUENCE_MASK) != SEQUENCE_MASK ); \ - *(x) = ++__seq; \ - } while(0) - -#define SHARED_WRITE_END( x ) \ - do { \ - volatile unsigned int __seq = *(x); \ - assert( (__seq & SEQUENCE_MASK) != 0 ); \ - if ((__seq & SEQUENCE_MASK) > 1) __seq--; \ - else __seq += SEQUENCE_MASK; \ - *(x) = __seq; \ - } while(0) - -#else - -#define SHARED_WRITE_BEGIN( x ) \ - do { \ - assert( (*(x) & SEQUENCE_MASK) != SEQUENCE_MASK ); \ - if ((__atomic_add_fetch( x, 1, __ATOMIC_RELAXED ) & SEQUENCE_MASK) == 1) \ - __atomic_thread_fence( __ATOMIC_RELEASE ); \ - } while(0) - -#define SHARED_WRITE_END( x ) \ - do { \ - assert( (*(x) & SEQUENCE_MASK) != 0 ); \ - if ((*(x) & SEQUENCE_MASK) > 1) \ - __atomic_sub_fetch( x, 1, __ATOMIC_RELAXED ); \ - else { \ - __atomic_thread_fence( __ATOMIC_RELEASE ); \ - __atomic_add_fetch( x, SEQUENCE_MASK, __ATOMIC_RELAXED ); \ - } \ - } while(0) - -#endif - static int update_desktop_cursor_pos( struct desktop *desktop, int x, int y ) { int updated; diff --git a/server/thread.c b/server/thread.c index 70299636d9d..15a3e25825c 100644 --- a/server/thread.c +++ b/server/thread.c @@ -57,6 +57,7 @@ #include "user.h" #include "security.h" #include "esync.h" +#include "unicode.h" /* thread queues */ @@ -286,6 +287,8 @@ static inline void init_thread_structure( struct thread *thread ) thread->token = NULL; thread->desc = NULL; thread->desc_len = 0; + thread->queue_shared_mapping = NULL; + thread->queue_shared = NULL; thread->creation_time = current_time; thread->exit_time = 0; @@ -336,6 +339,28 @@ static struct context *create_thread_context( struct thread *thread ) } +static volatile void *init_queue_mapping( struct thread *thread ) +{ + struct unicode_str name; + struct object *dir = create_thread_map_directory(); + char nameA[MAX_PATH]; + WCHAR *nameW; + + if (!dir) return NULL; + + sprintf( nameA, "%08x-queue", thread->id ); + nameW = ascii_to_unicode_str( nameA, &name ); + + thread->queue_shared_mapping = create_shared_mapping( dir, &name, sizeof(struct queue_shared_memory), + NULL, (void **)&thread->queue_shared ); + release_object( dir ); + if (thread->queue_shared_mapping) memset( (void *)thread->queue_shared, 0, sizeof(*thread->queue_shared) ); + + free( nameW ); + return thread->queue_shared; +} + + /* create a new thread */ struct thread *create_thread( int fd, struct process *process, const struct security_descriptor *sd ) { @@ -402,6 +427,11 @@ struct thread *create_thread( int fd, struct process *process, const struct secu release_object( thread ); return NULL; } + if (!init_queue_mapping( thread )) + { + release_object( thread ); + return NULL; + } if (process->desktop) { @@ -479,6 +509,8 @@ static void cleanup_thread( struct thread *thread ) } } free( thread->desc ); + if (thread->queue_shared_mapping) release_object( thread->queue_shared_mapping ); + thread->queue_shared_mapping = NULL; thread->req_data = NULL; thread->reply_data = NULL; thread->request_fd = NULL; diff --git a/server/thread.h b/server/thread.h index 92cb3e8c31e..0c16042ccdd 100644 --- a/server/thread.h +++ b/server/thread.h @@ -93,6 +93,8 @@ struct thread struct list kernel_object; /* list of kernel object pointers */ data_size_t desc_len; /* thread description length in bytes */ WCHAR *desc; /* thread description string */ + struct object *queue_shared_mapping; /* thread queue shared memory mapping */ + volatile struct queue_shared_memory *queue_shared; /* thread queue shared memory ptr */ }; extern struct thread *current; From 03072b9d7b577d05c9d5e158c7ed74c528449944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 12 Dec 2021 13:15:26 +0100 Subject: [PATCH 0299/2777] user32: Use the thread queue shared data for peek_message. --- dlls/win32u/message.c | 33 +++++++++++++++++++++++++- dlls/win32u/ntuser_private.h | 3 +++ dlls/win32u/sysparams.c | 7 ++++++ dlls/win32u/winstation.c | 16 +++++++++++++ server/protocol.def | 4 ++++ server/queue.c | 45 +++++++++++++++++++++++++++++++++++- 6 files changed, 106 insertions(+), 2 deletions(-) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 8d4f054e9d8..0d4f4965644 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1847,10 +1847,12 @@ static BOOL process_hardware_message( MSG *msg, UINT hw_id, const struct hardwar static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, UINT changed_mask ) { LRESULT result; + volatile struct queue_shared_memory *shared = get_queue_shared_memory(); struct user_thread_info *thread_info = get_user_thread_info(); INPUT_MESSAGE_SOURCE prev_source = thread_info->client_info.msg_source; struct received_message_info info; unsigned int hw_id = 0; /* id of previous hardware message */ + BOOL skip = FALSE; void *buffer; size_t buffer_size = 1024; @@ -1865,10 +1867,39 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, size_t size = 0; const message_data_t *msg_data = buffer; BOOL needs_unpack = FALSE; + UINT wake_mask = changed_mask & (QS_SENDMESSAGE | QS_SMRESULT); + DWORD clear_bits = 0, filter = flags >> 16 ? flags >> 16 : QS_ALLINPUT; + if (filter & QS_POSTMESSAGE) + { + clear_bits |= QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER; + if (first == 0 && last == ~0U) clear_bits |= QS_ALLPOSTMESSAGE; + } + if (filter & QS_INPUT) clear_bits |= QS_INPUT; + if (filter & QS_PAINT) clear_bits |= QS_PAINT; thread_info->client_info.msg_source = prev_source; - SERVER_START_REQ( get_message ) + if (!shared) skip = FALSE; + else SHARED_READ_BEGIN( &shared->seq ) + { + /* not created yet */ + if (!shared->created) skip = FALSE; + /* if the masks need an update */ + else if (shared->wake_mask != wake_mask) skip = FALSE; + else if (shared->changed_mask != changed_mask) skip = FALSE; + /* or if the queue is signaled */ + else if (shared->wake_bits & wake_mask) skip = FALSE; + else if (shared->changed_bits & changed_mask) skip = FALSE; + /* or if the filter matches some bits */ + else if (shared->wake_bits & filter) skip = FALSE; + /* or if we should clear some bits */ + else if (shared->changed_bits & clear_bits) skip = FALSE; + else skip = TRUE; + } + SHARED_READ_END( &shared->seq ); + + if (skip) res = STATUS_PENDING; + else SERVER_START_REQ( get_message ) { req->flags = flags; req->get_win = wine_server_user_handle( hwnd ); diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 501cc6e8aa4..9d33534d2cd 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -137,6 +137,8 @@ struct user_thread_info UINT spy_indent; /* Current spy indent */ HANDLE desktop_shared_map; /* HANDLE to server's desktop shared memory */ struct desktop_shared_memory *desktop_shared_memory; /* Ptr to server's desktop shared memory */ + HANDLE queue_shared_map; /* HANDLE to server's thread queue shared memory */ + struct queue_shared_memory *queue_shared_memory; /* Ptr to server's thread queue shared memory */ }; C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) ); @@ -245,6 +247,7 @@ UINT win_set_flags( HWND hwnd, UINT set_mask, UINT clear_mask ) DECLSPEC_HIDDEN; /* winstation.c */ extern volatile struct desktop_shared_memory *get_desktop_shared_memory( void ) DECLSPEC_HIDDEN; +extern volatile struct queue_shared_memory *get_queue_shared_memory( void ) DECLSPEC_HIDDEN; static inline UINT win_get_flags( HWND hwnd ) { diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 8bb3ef49ea0..293835ba22a 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -5442,6 +5442,13 @@ static void thread_detach(void) thread_info->desktop_shared_memory = NULL; } + if (thread_info->queue_shared_map) + { + NtClose( thread_info->queue_shared_map ); + thread_info->queue_shared_map = NULL; + thread_info->queue_shared_memory = NULL; + } + exiting_thread_id = 0; } diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index e123a4d09f5..f27377524f7 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -634,6 +634,22 @@ volatile struct desktop_shared_memory *get_desktop_shared_memory( void ) return thread_info->desktop_shared_memory; } +volatile struct queue_shared_memory *get_queue_shared_memory( void ) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + UINT tid = GetCurrentThreadId(); + WCHAR bufferW[MAX_PATH]; + char buffer[MAX_PATH]; + + if (thread_info->queue_shared_memory) return thread_info->queue_shared_memory; + + snprintf( buffer, ARRAY_SIZE(buffer), "\\KernelObjects\\__wine_thread_mappings\\%08x-queue", tid ); + asciiz_to_unicode( bufferW, buffer ); + map_shared_memory_section( bufferW, sizeof(struct queue_shared_memory), NULL, + &thread_info->queue_shared_map, (void **)&thread_info->queue_shared_memory ); + return thread_info->queue_shared_memory; +} + /*********************************************************************** * winstation_init * diff --git a/server/protocol.def b/server/protocol.def index c5f07d3b3f0..4ee201a628b 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -884,6 +884,10 @@ struct queue_shared_memory { unsigned int seq; /* sequence number - server updating if (seq_no & SEQUENCE_MASK) != 0 */ int created; /* queue has been created */ + unsigned int wake_bits; + unsigned int changed_bits; + unsigned int wake_mask; + unsigned int changed_mask; }; /* Bits that must be clear for client to read */ diff --git a/server/queue.c b/server/queue.c index c4e4bfbdb2b..3a70e1e3ff7 100644 --- a/server/queue.c +++ b/server/queue.c @@ -573,6 +573,12 @@ static inline void set_queue_bits( struct msg_queue *queue, unsigned int bits ) } queue->wake_bits |= bits; queue->changed_bits |= bits; + + SHARED_WRITE_BEGIN( &queue->shared->seq ); + queue->shared->wake_bits = queue->wake_bits; + queue->shared->changed_bits = queue->changed_bits; + SHARED_WRITE_END( &queue->shared->seq ); + if (is_signaled( queue )) wake_up( &queue->obj, 0 ); } @@ -589,6 +595,11 @@ static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits if (do_esync() && !is_signaled( queue )) esync_clear( queue->esync_fd ); + + SHARED_WRITE_BEGIN( &queue->shared->seq ); + queue->shared->wake_bits = queue->wake_bits; + queue->shared->changed_bits = queue->changed_bits; + SHARED_WRITE_END( &queue->shared->seq ); } /* check whether msg is a keyboard message */ @@ -1142,6 +1153,11 @@ static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *en struct msg_queue *queue = (struct msg_queue *)obj; queue->wake_mask = 0; queue->changed_mask = 0; + + SHARED_WRITE_BEGIN( &queue->shared->seq ); + queue->shared->wake_mask = queue->wake_mask; + queue->shared->changed_mask = queue->changed_mask; + SHARED_WRITE_END( &queue->shared->seq ); } static void cleanup_msg_queue( struct msg_queue *queue ) @@ -2685,10 +2701,23 @@ DECL_HANDLER(set_queue_mask) queue->changed_mask = req->changed_mask; reply->wake_bits = queue->wake_bits; reply->changed_bits = queue->changed_bits; + + SHARED_WRITE_BEGIN( &queue->shared->seq ); + queue->shared->wake_mask = queue->wake_mask; + queue->shared->changed_mask = queue->changed_mask; + SHARED_WRITE_END( &queue->shared->seq ); + if (is_signaled( queue )) { /* if skip wait is set, do what would have been done in the subsequent wait */ - if (req->skip_wait) queue->wake_mask = queue->changed_mask = 0; + if (req->skip_wait) + { + queue->wake_mask = queue->changed_mask = 0; + SHARED_WRITE_BEGIN( &queue->shared->seq ); + queue->shared->wake_mask = queue->wake_mask; + queue->shared->changed_mask = queue->changed_mask; + SHARED_WRITE_END( &queue->shared->seq ); + } else wake_up( &queue->obj, 0 ); } @@ -2710,6 +2739,10 @@ DECL_HANDLER(get_queue_status) if (do_esync() && !is_signaled( queue )) esync_clear( queue->esync_fd ); + + SHARED_WRITE_BEGIN( &queue->shared->seq ); + queue->shared->changed_bits = queue->changed_bits; + SHARED_WRITE_END( &queue->shared->seq ); } else reply->wake_bits = reply->changed_bits = 0; } @@ -2889,6 +2922,10 @@ DECL_HANDLER(get_message) if (filter & QS_INPUT) queue->changed_bits &= ~QS_INPUT; if (filter & QS_PAINT) queue->changed_bits &= ~QS_PAINT; + SHARED_WRITE_BEGIN( &queue->shared->seq ); + queue->shared->changed_bits = queue->changed_bits; + SHARED_WRITE_END( &queue->shared->seq ); + /* then check for posted messages */ if ((filter & QS_POSTMESSAGE) && get_posted_message( queue, get_win, req->get_first, req->get_last, req->flags, reply )) @@ -2942,6 +2979,12 @@ DECL_HANDLER(get_message) if (get_win == -1 && current->process->idle_event) set_event( current->process->idle_event ); queue->wake_mask = req->wake_mask; queue->changed_mask = req->changed_mask; + + SHARED_WRITE_BEGIN( &queue->shared->seq ); + queue->shared->wake_mask = queue->wake_mask; + queue->shared->changed_mask = queue->changed_mask; + SHARED_WRITE_END( &queue->shared->seq ); + set_error( STATUS_PENDING ); /* FIXME */ if (do_esync() && !is_signaled( queue )) From 7df29730c507f8aebaaf96c7ca536dab62656dbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 12 Dec 2021 13:15:45 +0100 Subject: [PATCH 0300/2777] user32: Don't check for driver events so often. Now that PeekMessage may return quickly we don't want to check for driver events on every call. --- dlls/win32u/message.c | 14 ++++++++++---- dlls/win32u/ntuser_private.h | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 0d4f4965644..204081fb014 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2176,7 +2176,8 @@ static HANDLE get_server_queue_handle(void) /* check for driver events if we detect that the app is not properly consuming messages */ static inline void check_for_driver_events( UINT msg ) { - if (get_user_thread_info()->message_count > 200) + struct user_thread_info *thread_info = get_user_thread_info(); + if (thread_info->message_count > 200) { LARGE_INTEGER zero = { .QuadPart = 0 }; flush_window_surfaces( FALSE ); @@ -2185,9 +2186,9 @@ static inline void check_for_driver_events( UINT msg ) else if (msg == WM_TIMER || msg == WM_SYSTIMER) { /* driver events should have priority over timers, so make sure we'll check for them soon */ - get_user_thread_info()->message_count += 100; + thread_info->message_count += 100; } - else get_user_thread_info()->message_count++; + else thread_info->message_count++; } /* helper for kernel32->ntdll timeout format conversion */ @@ -2360,17 +2361,21 @@ BOOL WINAPI NtUserWaitMessage(void) */ BOOL WINAPI NtUserPeekMessage( MSG *msg_out, HWND hwnd, UINT first, UINT last, UINT flags ) { + struct user_thread_info *thread_info = get_user_thread_info(); MSG msg; int ret; user_check_not_lock(); - check_for_driver_events( 0 ); + if (thread_info->last_driver_time != NtGetTickCount()) + check_for_driver_events( 0 ); ret = peek_message( &msg, hwnd, first, last, flags, 0 ); if (ret < 0) return FALSE; if (!ret) { + if (thread_info->last_driver_time == NtGetTickCount()) return FALSE; + thread_info->last_driver_time = NtGetTickCount(); flush_window_surfaces( TRUE ); ret = wait_message( 0, NULL, 0, QS_ALLINPUT, 0 ); /* if we received driver events, check again for a pending message */ @@ -2378,6 +2383,7 @@ BOOL WINAPI NtUserPeekMessage( MSG *msg_out, HWND hwnd, UINT first, UINT last, U } check_for_driver_events( msg.message ); + thread_info->last_driver_time = NtGetTickCount() - 1; /* copy back our internal safe copy of message data to msg_out. * msg_out is a variable from the *program*, so it can't be used diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 9d33534d2cd..de8d2de6d02 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -124,6 +124,7 @@ struct user_thread_info HANDLE server_queue; /* Handle to server-side queue */ DWORD wake_mask; /* Current queue wake mask */ DWORD changed_mask; /* Current queue changed mask */ + DWORD last_driver_time; /* Get/PeekMessage driver event time */ WORD message_count; /* Get/PeekMessage loop counter */ WORD hook_call_depth; /* Number of recursively called hook procs */ WORD hook_unicode; /* Is current hook unicode? */ From 6db2f69cd65b43167dd6497cce5006a14ef22a9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Nov 2020 19:21:42 +0100 Subject: [PATCH 0301/2777] esync: user32: Always call get_message request after waiting. Because with esync and fsync the wait happens on the client-side, so we need to make the request to do the server side effects. --- dlls/win32u/message.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 204081fb014..094b44a6909 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1844,7 +1844,7 @@ static BOOL process_hardware_message( MSG *msg, UINT hw_id, const struct hardwar * available; -1 on error. * All pending sent messages are processed before returning. */ -static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, UINT changed_mask ) +static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, UINT changed_mask, BOOL waited ) { LRESULT result; volatile struct queue_shared_memory *shared = get_queue_shared_memory(); @@ -1879,7 +1879,7 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, thread_info->client_info.msg_source = prev_source; - if (!shared) skip = FALSE; + if (!shared || waited) skip = FALSE; else SHARED_READ_BEGIN( &shared->seq ) { /* not created yet */ @@ -2083,7 +2083,7 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, } else peek_message( msg, info.msg.hwnd, info.msg.message, - info.msg.message, flags | PM_REMOVE, changed_mask ); + info.msg.message, flags | PM_REMOVE, changed_mask, TRUE ); continue; } if (info.msg.message >= WM_DDE_FIRST && info.msg.message <= WM_DDE_LAST) @@ -2146,7 +2146,7 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, static void process_sent_messages(void) { MSG msg; - peek_message( &msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, 0 ); + peek_message( &msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, 0, FALSE ); } /*********************************************************************** @@ -2369,7 +2369,7 @@ BOOL WINAPI NtUserPeekMessage( MSG *msg_out, HWND hwnd, UINT first, UINT last, U if (thread_info->last_driver_time != NtGetTickCount()) check_for_driver_events( 0 ); - ret = peek_message( &msg, hwnd, first, last, flags, 0 ); + ret = peek_message( &msg, hwnd, first, last, flags, 0, FALSE ); if (ret < 0) return FALSE; if (!ret) @@ -2379,7 +2379,7 @@ BOOL WINAPI NtUserPeekMessage( MSG *msg_out, HWND hwnd, UINT first, UINT last, U flush_window_surfaces( TRUE ); ret = wait_message( 0, NULL, 0, QS_ALLINPUT, 0 ); /* if we received driver events, check again for a pending message */ - if (ret == WAIT_TIMEOUT || peek_message( &msg, hwnd, first, last, flags, 0 ) <= 0) return FALSE; + if (ret == WAIT_TIMEOUT || peek_message( &msg, hwnd, first, last, flags, 0, TRUE ) <= 0) return FALSE; } check_for_driver_events( msg.message ); @@ -2421,7 +2421,7 @@ BOOL WINAPI NtUserGetMessage( MSG *msg, HWND hwnd, UINT first, UINT last ) } else mask = QS_ALLINPUT; - while (!(ret = peek_message( msg, hwnd, first, last, PM_REMOVE | (mask << 16), mask ))) + while (!(ret = peek_message( msg, hwnd, first, last, PM_REMOVE | (mask << 16), mask, TRUE ))) { wait_objects( 1, &server_queue, INFINITE, mask & (QS_SENDMESSAGE | QS_SMRESULT), mask, 0 ); } From 8acb3ceabfe5a1b8b9fa94944ad9b5a31bf0fc19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 12 Dec 2021 13:16:00 +0100 Subject: [PATCH 0302/2777] user32: Call get_message request at least once every 3s. So that the thread queue isn't incorrectly flagged as hung. --- dlls/win32u/message.c | 3 ++- dlls/win32u/ntuser_private.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 094b44a6909..df08302ba77 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1879,7 +1879,7 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, thread_info->client_info.msg_source = prev_source; - if (!shared || waited) skip = FALSE; + if (!shared || waited || NtGetTickCount() - thread_info->last_getmsg_time >= 3000) skip = FALSE; else SHARED_READ_BEGIN( &shared->seq ) { /* not created yet */ @@ -1909,6 +1909,7 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, req->wake_mask = changed_mask & (QS_SENDMESSAGE | QS_SMRESULT); req->changed_mask = changed_mask; wine_server_set_reply( req, buffer, buffer_size ); + thread_info->last_getmsg_time = NtGetTickCount(); if (!(res = wine_server_call( req ))) { size = wine_server_reply_size( reply ); diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index de8d2de6d02..297ad98d1c0 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -125,6 +125,7 @@ struct user_thread_info DWORD wake_mask; /* Current queue wake mask */ DWORD changed_mask; /* Current queue changed mask */ DWORD last_driver_time; /* Get/PeekMessage driver event time */ + DWORD last_getmsg_time; /* Get/PeekMessage last request time */ WORD message_count; /* Get/PeekMessage loop counter */ WORD hook_call_depth; /* Number of recursively called hook procs */ WORD hook_unicode; /* Is current hook unicode? */ From 4bd4c35c4847b8f7168276aa594de132f5970b41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 29 Apr 2021 11:36:15 +0200 Subject: [PATCH 0303/2777] user32: Allocate heap in peek_message only when necessary. --- dlls/win32u/message.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index df08302ba77..0694b6db060 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1851,13 +1851,12 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, struct user_thread_info *thread_info = get_user_thread_info(); INPUT_MESSAGE_SOURCE prev_source = thread_info->client_info.msg_source; struct received_message_info info; + unsigned char buffer_init[1024]; unsigned int hw_id = 0; /* id of previous hardware message */ + void *buffer = buffer_init; BOOL skip = FALSE; - void *buffer; size_t buffer_size = 1024; - if (!(buffer = malloc( buffer_size ))) return -1; - if (!first && !last) last = ~0; if (hwnd == HWND_BROADCAST) hwnd = HWND_TOPMOST; @@ -1932,19 +1931,22 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, if (res) { - free( buffer ); if (res == STATUS_PENDING) { thread_info->wake_mask = changed_mask & (QS_SENDMESSAGE | QS_SMRESULT); thread_info->changed_mask = changed_mask; + if (buffer != buffer_init) free( buffer ); return 0; } if (res != STATUS_BUFFER_OVERFLOW) { RtlSetLastWin32Error( RtlNtStatusToDosError(res) ); + if (buffer != buffer_init) free( buffer ); return -1; } - if (!(buffer = malloc( buffer_size ))) return -1; + if (buffer == buffer_init) buffer = malloc( buffer_size ); + else buffer = realloc( buffer, buffer_size ); + if (!buffer) return -1; continue; } @@ -1961,6 +1963,12 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, break; case MSG_NOTIFY: info.flags = ISMEX_NOTIFY; + /* unpack_message may have to reallocate */ + if (buffer == buffer_init) + { + buffer = malloc( buffer_size ); + memcpy( buffer, buffer_init, buffer_size ); + } if (!unpack_message( info.msg.hwnd, info.msg.message, &info.msg.wParam, &info.msg.lParam, &buffer, size )) continue; @@ -2040,6 +2048,12 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, continue; case MSG_OTHER_PROCESS: info.flags = ISMEX_SEND; + /* unpack_message may have to reallocate */ + if (buffer == buffer_init) + { + buffer = malloc( buffer_size ); + memcpy( buffer, buffer_init, buffer_size ); + } if (!unpack_message( info.msg.hwnd, info.msg.message, &info.msg.wParam, &info.msg.lParam, &buffer, size )) { @@ -2063,7 +2077,7 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, thread_info->client_info.message_pos = MAKELONG( info.msg.pt.x, info.msg.pt.y ); thread_info->client_info.message_time = info.msg.time; thread_info->client_info.message_extra = msg_data->hardware.info; - free( buffer ); + if (buffer != buffer_init) free( buffer ); call_hooks( WH_GETMESSAGE, HC_ACTION, flags & PM_REMOVE, (LPARAM)msg, sizeof(*msg) ); return 1; } @@ -2078,7 +2092,7 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, /* if this is a nested call return right away */ if (first == info.msg.message && last == info.msg.message) { - free( buffer ); + if (buffer != buffer_init) free( buffer ); return 0; } } @@ -2117,7 +2131,7 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, thread_info->client_info.message_time = info.msg.time; thread_info->client_info.message_extra = 0; thread_info->client_info.msg_source = msg_source_unavailable; - free( buffer ); + if (buffer != buffer_init) free( buffer ); call_hooks( WH_GETMESSAGE, HC_ACTION, flags & PM_REMOVE, (LPARAM)msg, sizeof(*msg) ); return 1; } From 6895ef6486d7e8b3d0eaf7e26e634d1b7f106b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 29 Apr 2021 20:07:16 +0200 Subject: [PATCH 0304/2777] user32: Yield thread in peek_message when no message was found. --- dlls/win32u/message.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 0694b6db060..b913f97fdc5 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1936,6 +1936,7 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, thread_info->wake_mask = changed_mask & (QS_SENDMESSAGE | QS_SMRESULT); thread_info->changed_mask = changed_mask; if (buffer != buffer_init) free( buffer ); + NtYieldExecution(); return 0; } if (res != STATUS_BUFFER_OVERFLOW) From e639abfacd20ddb713a747837a37546aa095711e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 14 Jan 2021 15:22:05 +0100 Subject: [PATCH 0305/2777] server: Create a thread input shared mapping. --- server/protocol.def | 8 ++++++++ server/queue.c | 21 ++++++++++++++++++++- server/thread.c | 41 ++++++++++++++++++++++++++++++++++++++++- server/thread.h | 2 ++ 4 files changed, 70 insertions(+), 2 deletions(-) diff --git a/server/protocol.def b/server/protocol.def index 4ee201a628b..8ecdf336b7a 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -888,6 +888,14 @@ struct queue_shared_memory unsigned int changed_bits; unsigned int wake_mask; unsigned int changed_mask; + thread_id_t input_tid; +}; + +struct input_shared_memory +{ + unsigned int seq; /* sequence number - server updating if (seq_no & SEQUENCE_MASK) != 0 */ + int created; + thread_id_t tid; }; /* Bits that must be clear for client to read */ diff --git a/server/queue.c b/server/queue.c index 3a70e1e3ff7..f39f8ee93dc 100644 --- a/server/queue.c +++ b/server/queue.c @@ -115,6 +115,8 @@ struct thread_input unsigned char keystate[256]; /* state of each key */ unsigned char desktop_keystate[256]; /* desktop keystate when keystate was synced */ int keystate_lock; /* keystate is locked */ + struct object *shared_mapping; /* thread input shared memory mapping */ + volatile struct input_shared_memory *shared; /* thread input shared memory ptr */ }; struct msg_queue @@ -304,6 +306,8 @@ static struct thread_input *create_thread_input( struct thread *thread ) if ((input = alloc_object( &thread_input_ops ))) { + input->shared_mapping = grab_object( thread->input_shared_mapping ); + input->shared = thread->input_shared; input->focus = 0; input->capture = 0; input->active = 0; @@ -323,6 +327,10 @@ static struct thread_input *create_thread_input( struct thread *thread ) } memcpy( input->desktop_keystate, (void *)input->desktop->shared->keystate, sizeof(input->desktop_keystate) ); + + SHARED_WRITE_BEGIN( &input->shared->seq ); + input->shared->created = TRUE; + SHARED_WRITE_END( &input->shared->seq ); } return input; } @@ -376,7 +384,13 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ SHARED_WRITE_END( &queue->shared->seq ); thread->queue = queue; } - if (new_input) release_object( new_input ); + if (new_input) + { + SHARED_WRITE_BEGIN( &queue->shared->seq ); + queue->shared->input_tid = new_input->shared->tid; + SHARED_WRITE_END( &queue->shared->seq ); + release_object( new_input ); + } return queue; } @@ -424,6 +438,10 @@ static int assign_thread_input( struct thread *thread, struct thread_input *new_ queue->input = (struct thread_input *)grab_object( new_input ); if (queue->keystate_lock) lock_input_keystate( queue->input ); new_input->cursor_count += queue->cursor_count; + + SHARED_WRITE_BEGIN( &queue->shared->seq ); + queue->shared->input_tid = queue->input->shared->tid; + SHARED_WRITE_END( &queue->shared->seq ); return 1; } @@ -1243,6 +1261,7 @@ static void thread_input_destroy( struct object *obj ) if (input->desktop->foreground_input == input) set_foreground_input( input->desktop, NULL ); release_object( input->desktop ); } + release_object( input->shared_mapping ); } /* fix the thread input data when a window is destroyed */ diff --git a/server/thread.c b/server/thread.c index 15a3e25825c..081a3389538 100644 --- a/server/thread.c +++ b/server/thread.c @@ -289,6 +289,8 @@ static inline void init_thread_structure( struct thread *thread ) thread->desc_len = 0; thread->queue_shared_mapping = NULL; thread->queue_shared = NULL; + thread->input_shared_mapping = NULL; + thread->input_shared = NULL; thread->creation_time = current_time; thread->exit_time = 0; @@ -354,13 +356,43 @@ static volatile void *init_queue_mapping( struct thread *thread ) thread->queue_shared_mapping = create_shared_mapping( dir, &name, sizeof(struct queue_shared_memory), NULL, (void **)&thread->queue_shared ); release_object( dir ); - if (thread->queue_shared_mapping) memset( (void *)thread->queue_shared, 0, sizeof(*thread->queue_shared) ); + if (thread->queue_shared_mapping) + { + memset( (void *)thread->queue_shared, 0, sizeof(*thread->queue_shared) ); + thread->queue_shared->input_tid = thread->id; + } free( nameW ); return thread->queue_shared; } +static volatile void *init_input_mapping( struct thread *thread ) +{ + struct unicode_str name; + struct object *dir = create_thread_map_directory(); + char nameA[MAX_PATH]; + WCHAR *nameW; + + if (!dir) return NULL; + + sprintf( nameA, "%08x-input", thread->id ); + nameW = ascii_to_unicode_str( nameA, &name ); + + thread->input_shared_mapping = create_shared_mapping( dir, &name, sizeof(struct input_shared_memory), + NULL, (void **)&thread->input_shared ); + release_object( dir ); + if (thread->input_shared_mapping) + { + memset( (void *)thread->input_shared, 0, sizeof(*thread->input_shared) ); + thread->input_shared->tid = thread->id; + } + + free( nameW ); + return thread->input_shared; +} + + /* create a new thread */ struct thread *create_thread( int fd, struct process *process, const struct security_descriptor *sd ) { @@ -432,6 +464,11 @@ struct thread *create_thread( int fd, struct process *process, const struct secu release_object( thread ); return NULL; } + if (!init_input_mapping( thread )) + { + release_object( thread ); + return NULL; + } if (process->desktop) { @@ -511,6 +548,8 @@ static void cleanup_thread( struct thread *thread ) free( thread->desc ); if (thread->queue_shared_mapping) release_object( thread->queue_shared_mapping ); thread->queue_shared_mapping = NULL; + if (thread->input_shared_mapping) release_object( thread->input_shared_mapping ); + thread->input_shared_mapping = NULL; thread->req_data = NULL; thread->reply_data = NULL; thread->request_fd = NULL; diff --git a/server/thread.h b/server/thread.h index 0c16042ccdd..d09171c31f9 100644 --- a/server/thread.h +++ b/server/thread.h @@ -95,6 +95,8 @@ struct thread WCHAR *desc; /* thread description string */ struct object *queue_shared_mapping; /* thread queue shared memory mapping */ volatile struct queue_shared_memory *queue_shared; /* thread queue shared memory ptr */ + struct object *input_shared_mapping; /* thread input shared memory mapping */ + volatile struct input_shared_memory *input_shared; /* thread input shared memory ptr */ }; extern struct thread *current; From 5005c59f3868692e69aa361335f57fe1070c1d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 18 Jan 2021 17:35:50 +0100 Subject: [PATCH 0306/2777] server: Move active window to input shared memory. --- server/protocol.def | 1 + server/queue.c | 44 ++++++++++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/server/protocol.def b/server/protocol.def index 8ecdf336b7a..b1097fbaa97 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -896,6 +896,7 @@ struct input_shared_memory unsigned int seq; /* sequence number - server updating if (seq_no & SEQUENCE_MASK) != 0 */ int created; thread_id_t tid; + user_handle_t active; /* handle to the active window */ }; /* Bits that must be clear for client to read */ diff --git a/server/queue.c b/server/queue.c index f39f8ee93dc..24e650e5b56 100644 --- a/server/queue.c +++ b/server/queue.c @@ -102,7 +102,6 @@ struct thread_input struct desktop *desktop; /* desktop that this thread input belongs to */ user_handle_t focus; /* focus window */ user_handle_t capture; /* capture window */ - user_handle_t active; /* active window */ user_handle_t menu_owner; /* current menu owner window */ user_handle_t move_size; /* current moving/resizing window */ user_handle_t caret; /* caret window */ @@ -308,13 +307,15 @@ static struct thread_input *create_thread_input( struct thread *thread ) { input->shared_mapping = grab_object( thread->input_shared_mapping ); input->shared = thread->input_shared; + SHARED_WRITE_BEGIN( &input->shared->seq ); input->focus = 0; input->capture = 0; - input->active = 0; + input->shared->active = 0; input->menu_owner = 0; input->move_size = 0; input->cursor = 0; input->cursor_count = 0; + SHARED_WRITE_END( &input->shared->seq ); list_init( &input->msg_list ); set_caret_window( input, 0 ); memset( input->keystate, 0, sizeof(input->keystate) ); @@ -1248,7 +1249,7 @@ static void thread_input_dump( struct object *obj, int verbose ) { struct thread_input *input = (struct thread_input *)obj; fprintf( stderr, "Thread input focus=%08x capture=%08x active=%08x\n", - input->focus, input->capture, input->active ); + input->focus, input->capture, input->shared->active ); } static void thread_input_destroy( struct object *obj ) @@ -1269,12 +1270,14 @@ static inline void thread_input_cleanup_window( struct msg_queue *queue, user_ha { struct thread_input *input = queue->input; + SHARED_WRITE_BEGIN( &input->shared->seq ); if (window == input->focus) input->focus = 0; if (window == input->capture) input->capture = 0; - if (window == input->active) input->active = 0; + if (window == input->shared->active) input->shared->active = 0; if (window == input->menu_owner) input->menu_owner = 0; if (window == input->move_size) input->move_size = 0; if (window == input->caret) set_caret_window( input, 0 ); + SHARED_WRITE_END( &input->shared->seq ); } /* check if the specified window can be set in the input data of a given queue */ @@ -1307,7 +1310,7 @@ int init_thread_queue( struct thread *thread ) int attach_thread_input( struct thread *thread_from, struct thread *thread_to ) { struct desktop *desktop; - struct thread_input *input; + struct thread_input *input, *old_input; int ret; if (!thread_to->queue && !(thread_to->queue = create_msg_queue( thread_to, NULL ))) return 0; @@ -1324,8 +1327,11 @@ int attach_thread_input( struct thread *thread_from, struct thread *thread_to ) if (thread_from->queue) { - if (!input->focus) input->focus = thread_from->queue->input->focus; - if (!input->active) input->active = thread_from->queue->input->active; + SHARED_WRITE_BEGIN( &input->shared->seq ); + old_input = thread_from->queue->input; + if (!input->focus) input->focus = old_input->focus; + if (!input->shared->active) input->shared->active = old_input->shared->active; + SHARED_WRITE_END( &input->shared->seq ); } ret = assign_thread_input( thread_from, input ); @@ -1351,12 +1357,16 @@ void detach_thread_input( struct thread *thread_from ) } release_object( thread ); } - if (old_input->active && (thread = get_window_thread( old_input->active ))) + if (old_input->shared->active && (thread = get_window_thread( old_input->shared->active ))) { if (thread == thread_from) { - input->active = old_input->active; - old_input->active = 0; + SHARED_WRITE_BEGIN( &input->shared->seq ); + input->shared->active = old_input->shared->active; + SHARED_WRITE_END( &input->shared->seq ); + SHARED_WRITE_BEGIN( &old_input->shared->seq ); + old_input->shared->active = 0; + SHARED_WRITE_END( &old_input->shared->seq ); } release_object( thread ); } @@ -1684,7 +1694,7 @@ static user_handle_t find_hardware_message_window( struct desktop *desktop, stru { if (input && !(win = input->focus)) { - win = input->active; + win = input->shared->active; if (*msg_code < WM_SYSKEYDOWN) *msg_code += WM_SYSKEYDOWN - WM_KEYDOWN; } } @@ -3354,7 +3364,7 @@ DECL_HANDLER(get_thread_input) { reply->focus = input->focus; reply->capture = input->capture; - reply->active = input->active; + reply->active = input->shared->active; reply->menu_owner = input->menu_owner; reply->move_size = input->move_size; reply->caret = input->caret; @@ -3364,7 +3374,7 @@ DECL_HANDLER(get_thread_input) } /* foreground window is active window of foreground thread */ - reply->foreground = desktop->foreground_input ? desktop->foreground_input->active : 0; + reply->foreground = desktop->foreground_input ? desktop->foreground_input->shared->active : 0; if (thread) release_object( thread ); release_object( desktop ); } @@ -3431,7 +3441,7 @@ DECL_HANDLER(set_foreground_window) struct msg_queue *queue = get_current_queue(); if (!(desktop = get_thread_desktop( current, 0 ))) return; - reply->previous = desktop->foreground_input ? desktop->foreground_input->active : 0; + reply->previous = desktop->foreground_input ? desktop->foreground_input->shared->active : 0; reply->send_msg_old = (reply->previous && desktop->foreground_input != queue->input); reply->send_msg_new = FALSE; @@ -3477,8 +3487,10 @@ DECL_HANDLER(set_active_window) { if (!req->handle || make_window_active( req->handle )) { - reply->previous = queue->input->active; - queue->input->active = get_user_full_handle( req->handle ); + reply->previous = queue->input->shared->active; + 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) { From 340a88636a5743034fcee3d254589fd13e6efd2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 18 Jan 2021 22:09:12 +0100 Subject: [PATCH 0307/2777] server: Move focus window to input shared memory. --- server/protocol.def | 1 + server/queue.c | 33 +++++++++++++++++++-------------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/server/protocol.def b/server/protocol.def index b1097fbaa97..386fef0b797 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -896,6 +896,7 @@ struct input_shared_memory unsigned int seq; /* sequence number - server updating if (seq_no & SEQUENCE_MASK) != 0 */ int created; thread_id_t tid; + user_handle_t focus; /* handle to the focus window */ user_handle_t active; /* handle to the active window */ }; diff --git a/server/queue.c b/server/queue.c index 24e650e5b56..b0db7ca110a 100644 --- a/server/queue.c +++ b/server/queue.c @@ -100,7 +100,6 @@ struct thread_input { struct object obj; /* object header */ struct desktop *desktop; /* desktop that this thread input belongs to */ - user_handle_t focus; /* focus window */ user_handle_t capture; /* capture window */ user_handle_t menu_owner; /* current menu owner window */ user_handle_t move_size; /* current moving/resizing window */ @@ -308,7 +307,7 @@ static struct thread_input *create_thread_input( struct thread *thread ) input->shared_mapping = grab_object( thread->input_shared_mapping ); input->shared = thread->input_shared; SHARED_WRITE_BEGIN( &input->shared->seq ); - input->focus = 0; + input->shared->focus = 0; input->capture = 0; input->shared->active = 0; input->menu_owner = 0; @@ -1249,7 +1248,7 @@ static void thread_input_dump( struct object *obj, int verbose ) { struct thread_input *input = (struct thread_input *)obj; fprintf( stderr, "Thread input focus=%08x capture=%08x active=%08x\n", - input->focus, input->capture, input->shared->active ); + input->shared->focus, input->capture, input->shared->active ); } static void thread_input_destroy( struct object *obj ) @@ -1271,7 +1270,7 @@ static inline void thread_input_cleanup_window( struct msg_queue *queue, user_ha struct thread_input *input = queue->input; SHARED_WRITE_BEGIN( &input->shared->seq ); - if (window == input->focus) input->focus = 0; + if (window == input->shared->focus) input->shared->focus = 0; if (window == input->capture) input->capture = 0; if (window == input->shared->active) input->shared->active = 0; if (window == input->menu_owner) input->menu_owner = 0; @@ -1329,7 +1328,7 @@ int attach_thread_input( struct thread *thread_from, struct thread *thread_to ) { SHARED_WRITE_BEGIN( &input->shared->seq ); old_input = thread_from->queue->input; - if (!input->focus) input->focus = old_input->focus; + if (!input->shared->focus) input->shared->focus = old_input->shared->focus; if (!input->shared->active) input->shared->active = old_input->shared->active; SHARED_WRITE_END( &input->shared->seq ); } @@ -1348,12 +1347,16 @@ void detach_thread_input( struct thread *thread_from ) if ((input = create_thread_input( thread_from ))) { - if (old_input->focus && (thread = get_window_thread( old_input->focus ))) + if (old_input->shared->focus && (thread = get_window_thread( old_input->shared->focus ))) { if (thread == thread_from) { - input->focus = old_input->focus; - old_input->focus = 0; + SHARED_WRITE_BEGIN( &input->shared->seq ); + input->shared->focus = old_input->shared->focus; + SHARED_WRITE_END( &input->shared->seq ); + SHARED_WRITE_BEGIN( &old_input->shared->seq ); + old_input->shared->focus = 0; + SHARED_WRITE_END( &old_input->shared->seq ); } release_object( thread ); } @@ -1688,11 +1691,11 @@ static user_handle_t find_hardware_message_window( struct desktop *desktop, stru msg->msg == WM_POINTERDOWN || msg->msg == WM_POINTERUP || msg->msg == WM_POINTERUPDATE) { - if (!(win = msg->win) && input) win = input->focus; + if (!(win = msg->win) && input) win = input->shared->focus; } else if (is_keyboard_msg( msg )) { - if (input && !(win = input->focus)) + if (input && !(win = input->shared->focus)) { win = input->shared->active; if (*msg_code < WM_SYSKEYDOWN) *msg_code += WM_SYSKEYDOWN - WM_KEYDOWN; @@ -1860,7 +1863,7 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa static struct thread *get_foreground_thread( struct desktop *desktop, user_handle_t window ) { /* if desktop has no foreground process, assume the receiving window is */ - if (desktop->foreground_input) return get_window_thread( desktop->foreground_input->focus ); + if (desktop->foreground_input) return get_window_thread( desktop->foreground_input->shared->focus ); if (window) return get_window_thread( window ); return NULL; } @@ -3362,7 +3365,7 @@ DECL_HANDLER(get_thread_input) if (input) { - reply->focus = input->focus; + reply->focus = input->shared->focus; reply->capture = input->capture; reply->active = input->shared->active; reply->menu_owner = input->menu_owner; @@ -3467,8 +3470,10 @@ DECL_HANDLER(set_focus_window) reply->previous = 0; if (queue && check_queue_input_window( queue, req->handle )) { - reply->previous = queue->input->focus; - queue->input->focus = get_user_full_handle( req->handle ); + reply->previous = queue->input->shared->focus; + SHARED_WRITE_BEGIN( &queue->input->shared->seq ); + queue->input->shared->focus = get_user_full_handle( req->handle ); + SHARED_WRITE_END( &queue->input->shared->seq ); } } From 3f50e3f12a5102d2951b7975bd5798bce9626bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 18 Jan 2021 17:58:36 +0100 Subject: [PATCH 0308/2777] server: Add foreground TID to desktop shared memory. --- server/protocol.def | 1 + server/queue.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/server/protocol.def b/server/protocol.def index 386fef0b797..2544ddde5a2 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -878,6 +878,7 @@ struct desktop_shared_memory unsigned int seq; /* sequence number - server updating if (seq_no & SEQUENCE_MASK) != 0 */ struct shared_cursor cursor; /* global cursor information */ unsigned char keystate[256]; /* asynchronous key state */ + thread_id_t foreground_tid; /* tid of the foreground thread */ }; struct queue_shared_memory diff --git a/server/queue.c b/server/queue.c index b0db7ca110a..e14d587839a 100644 --- a/server/queue.c +++ b/server/queue.c @@ -557,6 +557,9 @@ static void set_foreground_input( struct desktop *desktop, struct thread_input * if (desktop->foreground_input == input) return; set_clip_rectangle( desktop, NULL, 1 ); desktop->foreground_input = input; + SHARED_WRITE_BEGIN( &desktop->shared->seq ); + desktop->shared->foreground_tid = input ? input->shared->tid : 0; + SHARED_WRITE_END( &desktop->shared->seq ); } /* get the hook table for a given thread */ From 96540c1dadad9bfdf2168b8c4923ae73af04a60a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 18 Jan 2021 22:10:36 +0100 Subject: [PATCH 0309/2777] server: Move capture window to input shared memory. As well as menu owner / menu size window handles. --- server/protocol.def | 3 +++ server/queue.c | 39 +++++++++++++++++++-------------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/server/protocol.def b/server/protocol.def index 2544ddde5a2..4721302afc7 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -898,7 +898,10 @@ struct input_shared_memory int created; thread_id_t tid; user_handle_t focus; /* handle to the focus window */ + user_handle_t capture; /* handle to the capture window */ user_handle_t active; /* handle to the active window */ + user_handle_t menu_owner; /* handle to the menu owner */ + user_handle_t move_size; /* handle to the moving/resizing window */ }; /* Bits that must be clear for client to read */ diff --git a/server/queue.c b/server/queue.c index e14d587839a..fce8da49486 100644 --- a/server/queue.c +++ b/server/queue.c @@ -100,9 +100,6 @@ struct thread_input { struct object obj; /* object header */ struct desktop *desktop; /* desktop that this thread input belongs to */ - user_handle_t capture; /* capture window */ - user_handle_t menu_owner; /* current menu owner window */ - user_handle_t move_size; /* current moving/resizing window */ user_handle_t caret; /* caret window */ rectangle_t caret_rect; /* caret rectangle */ int caret_hide; /* caret hide count */ @@ -308,10 +305,10 @@ static struct thread_input *create_thread_input( struct thread *thread ) input->shared = thread->input_shared; SHARED_WRITE_BEGIN( &input->shared->seq ); input->shared->focus = 0; - input->capture = 0; + input->shared->capture = 0; input->shared->active = 0; - input->menu_owner = 0; - input->move_size = 0; + input->shared->menu_owner = 0; + input->shared->move_size = 0; input->cursor = 0; input->cursor_count = 0; SHARED_WRITE_END( &input->shared->seq ); @@ -1251,7 +1248,7 @@ static void thread_input_dump( struct object *obj, int verbose ) { struct thread_input *input = (struct thread_input *)obj; fprintf( stderr, "Thread input focus=%08x capture=%08x active=%08x\n", - input->shared->focus, input->capture, input->shared->active ); + input->shared->focus, input->shared->capture, input->shared->active ); } static void thread_input_destroy( struct object *obj ) @@ -1274,10 +1271,10 @@ static inline void thread_input_cleanup_window( struct msg_queue *queue, user_ha SHARED_WRITE_BEGIN( &input->shared->seq ); if (window == input->shared->focus) input->shared->focus = 0; - if (window == input->capture) input->capture = 0; + if (window == input->shared->capture) input->shared->capture = 0; if (window == input->shared->active) input->shared->active = 0; - if (window == input->menu_owner) input->menu_owner = 0; - if (window == input->move_size) input->move_size = 0; + if (window == input->shared->menu_owner) input->shared->menu_owner = 0; + if (window == input->shared->move_size) input->shared->move_size = 0; if (window == input->caret) set_caret_window( input, 0 ); SHARED_WRITE_END( &input->shared->seq ); } @@ -1704,7 +1701,7 @@ static user_handle_t find_hardware_message_window( struct desktop *desktop, stru if (*msg_code < WM_SYSKEYDOWN) *msg_code += WM_SYSKEYDOWN - WM_KEYDOWN; } } - else if (!input || !(win = input->capture)) /* mouse message */ + else if (!input || !(win = input->shared->capture)) /* mouse message */ { if (is_window_visible( msg->win ) && !is_window_transparent( msg->win )) win = msg->win; else win = shallow_window_from_point( desktop, msg->x, msg->y ); @@ -3369,10 +3366,10 @@ DECL_HANDLER(get_thread_input) if (input) { reply->focus = input->shared->focus; - reply->capture = input->capture; + reply->capture = input->shared->capture; reply->active = input->shared->active; - reply->menu_owner = input->menu_owner; - reply->move_size = input->move_size; + reply->menu_owner = input->shared->menu_owner; + reply->move_size = input->shared->move_size; reply->caret = input->caret; reply->cursor = input->cursor; reply->show_count = input->cursor_count; @@ -3524,16 +3521,18 @@ DECL_HANDLER(set_capture_window) struct thread_input *input = queue->input; /* if in menu mode, reject all requests to change focus, except if the menu bit is set */ - if (input->menu_owner && !(req->flags & CAPTURE_MENU)) + if (input->shared->menu_owner && !(req->flags & CAPTURE_MENU)) { set_error(STATUS_ACCESS_DENIED); return; } - reply->previous = input->capture; - input->capture = get_user_full_handle( req->handle ); - input->menu_owner = (req->flags & CAPTURE_MENU) ? input->capture : 0; - input->move_size = (req->flags & CAPTURE_MOVESIZE) ? input->capture : 0; - reply->full_handle = input->capture; + reply->previous = input->shared->capture; + SHARED_WRITE_BEGIN( &input->shared->seq ); + input->shared->capture = get_user_full_handle( req->handle ); + input->shared->menu_owner = (req->flags & CAPTURE_MENU) ? input->shared->capture : 0; + input->shared->move_size = (req->flags & CAPTURE_MOVESIZE) ? input->shared->capture : 0; + SHARED_WRITE_END( &input->shared->seq ); + reply->full_handle = input->shared->capture; } } From 7f4a7113048ebd9b02b76b49a4199f785a6bf712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 18 Jan 2021 18:44:03 +0100 Subject: [PATCH 0310/2777] server: Move caret window and rect to input shared memory. --- server/protocol.def | 2 ++ server/queue.c | 48 ++++++++++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/server/protocol.def b/server/protocol.def index 4721302afc7..3449588c71f 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -902,6 +902,8 @@ struct input_shared_memory user_handle_t active; /* handle to the active window */ user_handle_t menu_owner; /* handle to the menu owner */ user_handle_t move_size; /* handle to the moving/resizing window */ + user_handle_t caret; /* handle to the caret window */ + rectangle_t caret_rect; /* caret rectangle */ }; /* Bits that must be clear for client to read */ diff --git a/server/queue.c b/server/queue.c index fce8da49486..87519908013 100644 --- a/server/queue.c +++ b/server/queue.c @@ -100,8 +100,6 @@ struct thread_input { struct object obj; /* object header */ struct desktop *desktop; /* desktop that this thread input belongs to */ - user_handle_t caret; /* caret window */ - rectangle_t caret_rect; /* caret rectangle */ int caret_hide; /* caret hide count */ int caret_state; /* caret on/off state */ user_handle_t cursor; /* current cursor */ @@ -282,16 +280,18 @@ static void free_message( struct message *msg ); /* set the caret window in a given thread input */ static void set_caret_window( struct thread_input *input, user_handle_t win ) { - if (!win || win != input->caret) + SHARED_WRITE_BEGIN( &input->shared->seq ); + if (!win || win != input->shared->caret) { - input->caret_rect.left = 0; - input->caret_rect.top = 0; - input->caret_rect.right = 0; - input->caret_rect.bottom = 0; + input->shared->caret_rect.left = 0; + input->shared->caret_rect.top = 0; + input->shared->caret_rect.right = 0; + input->shared->caret_rect.bottom = 0; } - input->caret = win; + input->shared->caret = win; input->caret_hide = 1; input->caret_state = 0; + SHARED_WRITE_END( &input->shared->seq ); } /* create a thread input object */ @@ -1275,7 +1275,7 @@ static inline void thread_input_cleanup_window( struct msg_queue *queue, user_ha if (window == input->shared->active) input->shared->active = 0; if (window == input->shared->menu_owner) input->shared->menu_owner = 0; if (window == input->shared->move_size) input->shared->move_size = 0; - if (window == input->caret) set_caret_window( input, 0 ); + if (window == input->shared->caret) set_caret_window( input, 0 ); SHARED_WRITE_END( &input->shared->seq ); } @@ -3370,10 +3370,10 @@ DECL_HANDLER(get_thread_input) reply->active = input->shared->active; reply->menu_owner = input->shared->menu_owner; reply->move_size = input->shared->move_size; - reply->caret = input->caret; + reply->caret = input->shared->caret; reply->cursor = input->cursor; reply->show_count = input->cursor_count; - reply->rect = input->caret_rect; + reply->rect = input->shared->caret_rect; } /* foreground window is active window of foreground thread */ @@ -3547,14 +3547,16 @@ DECL_HANDLER(set_caret_window) { struct thread_input *input = queue->input; - reply->previous = input->caret; - reply->old_rect = input->caret_rect; + reply->previous = input->shared->caret; + reply->old_rect = input->shared->caret_rect; reply->old_hide = input->caret_hide; reply->old_state = input->caret_state; + SHARED_WRITE_BEGIN( &input->shared->seq ); set_caret_window( input, get_user_full_handle(req->handle) ); - input->caret_rect.right = input->caret_rect.left + req->width; - input->caret_rect.bottom = input->caret_rect.top + req->height; + input->shared->caret_rect.right = input->shared->caret_rect.left + req->width; + input->shared->caret_rect.bottom = input->shared->caret_rect.top + req->height; + SHARED_WRITE_END( &input->shared->seq ); } } @@ -3567,22 +3569,24 @@ DECL_HANDLER(set_caret_info) if (!queue) return; input = queue->input; - reply->full_handle = input->caret; - reply->old_rect = input->caret_rect; + reply->full_handle = input->shared->caret; + reply->old_rect = input->shared->caret_rect; reply->old_hide = input->caret_hide; reply->old_state = input->caret_state; - if (req->handle && get_user_full_handle(req->handle) != input->caret) + if (req->handle && get_user_full_handle(req->handle) != input->shared->caret) { set_error( STATUS_ACCESS_DENIED ); return; } if (req->flags & SET_CARET_POS) { - input->caret_rect.right += req->x - input->caret_rect.left; - input->caret_rect.bottom += req->y - input->caret_rect.top; - input->caret_rect.left = req->x; - input->caret_rect.top = req->y; + SHARED_WRITE_BEGIN( &input->shared->seq ); + input->shared->caret_rect.right += req->x - input->shared->caret_rect.left; + input->shared->caret_rect.bottom += req->y - input->shared->caret_rect.top; + input->shared->caret_rect.left = req->x; + input->shared->caret_rect.top = req->y; + SHARED_WRITE_END( &input->shared->seq ); } if (req->flags & SET_CARET_HIDE) { From 4057dae15f7e934d68436d5c851519dc8a5c3124 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 18 Jan 2021 19:05:34 +0100 Subject: [PATCH 0311/2777] user32: Use input shared memory for GetGUIThreadInfo. When the current thread is requested. user32: Use input shared memory for GetActiveWindow. user32: Use desktop shared memory for GetForegroundWindow. --- dlls/win32u/message.c | 28 ++++++++++++++++++++ dlls/win32u/ntuser_private.h | 6 +++++ dlls/win32u/sysparams.c | 14 ++++++++++ dlls/win32u/winstation.c | 51 ++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index b913f97fdc5..5829580c000 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1296,6 +1296,7 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR */ BOOL WINAPI NtUserGetGUIThreadInfo( DWORD id, GUITHREADINFO *info ) { + volatile struct input_shared_memory *shared; BOOL ret; if (info->cbSize != sizeof(*info)) @@ -1304,6 +1305,33 @@ BOOL WINAPI NtUserGetGUIThreadInfo( DWORD id, GUITHREADINFO *info ) return FALSE; } + if (id == GetCurrentThreadId()) shared = get_input_shared_memory(); + else if (id == 0) shared = get_foreground_shared_memory(); + else shared = NULL; + + if (shared) + { + SHARED_READ_BEGIN( &shared->seq ) + { + info->flags = 0; + info->hwndActive = wine_server_ptr_handle( shared->active ); + info->hwndFocus = wine_server_ptr_handle( shared->focus ); + info->hwndCapture = wine_server_ptr_handle( shared->capture ); + info->hwndMenuOwner = wine_server_ptr_handle( shared->menu_owner ); + info->hwndMoveSize = wine_server_ptr_handle( shared->move_size ); + info->hwndCaret = wine_server_ptr_handle( shared->caret ); + info->rcCaret.left = shared->caret_rect.left; + info->rcCaret.top = shared->caret_rect.top; + info->rcCaret.right = shared->caret_rect.right; + info->rcCaret.bottom = shared->caret_rect.bottom; + if (shared->menu_owner) info->flags |= GUI_INMENUMODE; + if (shared->move_size) info->flags |= GUI_INMOVESIZE; + if (shared->caret) info->flags |= GUI_CARETBLINKING; + } + SHARED_READ_END( &shared->seq ); + return TRUE; + } + SERVER_START_REQ( get_thread_input ) { req->tid = id; diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 297ad98d1c0..c86b5010383 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -141,6 +141,10 @@ struct user_thread_info struct desktop_shared_memory *desktop_shared_memory; /* Ptr to server's desktop shared memory */ HANDLE queue_shared_map; /* HANDLE to server's thread queue shared memory */ struct queue_shared_memory *queue_shared_memory; /* Ptr to server's thread queue shared memory */ + HANDLE input_shared_map; /* HANDLE to server's thread input shared memory */ + struct input_shared_memory *input_shared_memory; /* Ptr to server's thread input shared memory */ + HANDLE foreground_shared_map; /* HANDLE to server's thread input shared memory */ + struct input_shared_memory *foreground_shared_memory; /* Ptr to server's thread input shared memory */ }; C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) ); @@ -250,6 +254,8 @@ UINT win_set_flags( HWND hwnd, UINT set_mask, UINT clear_mask ) DECLSPEC_HIDDEN; /* winstation.c */ extern volatile struct desktop_shared_memory *get_desktop_shared_memory( void ) DECLSPEC_HIDDEN; extern volatile struct queue_shared_memory *get_queue_shared_memory( void ) DECLSPEC_HIDDEN; +extern volatile struct input_shared_memory *get_input_shared_memory( void ) DECLSPEC_HIDDEN; +extern volatile struct input_shared_memory *get_foreground_shared_memory( void ) DECLSPEC_HIDDEN; static inline UINT win_get_flags( HWND hwnd ) { diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 293835ba22a..94d5f73ce90 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -5449,6 +5449,20 @@ static void thread_detach(void) thread_info->queue_shared_memory = NULL; } + if (thread_info->input_shared_map) + { + NtClose( thread_info->input_shared_map ); + thread_info->input_shared_map = NULL; + thread_info->input_shared_memory = NULL; + } + + if (thread_info->foreground_shared_memory) + { + NtClose( thread_info->foreground_shared_map ); + thread_info->foreground_shared_map = NULL; + thread_info->foreground_shared_memory = NULL; + } + exiting_thread_id = 0; } diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index f27377524f7..a695365b8f1 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -650,6 +650,57 @@ volatile struct queue_shared_memory *get_queue_shared_memory( void ) return thread_info->queue_shared_memory; } +static volatile struct input_shared_memory *get_thread_input_shared_memory( UINT tid, HANDLE *handle, + struct input_shared_memory **ptr ) +{ + WCHAR bufferW[MAX_PATH]; + char buffer[MAX_PATH]; + + if (*ptr && (*ptr)->tid == tid) return *ptr; + if (*ptr) NtClose( *handle ); + + snprintf( buffer, ARRAY_SIZE(buffer), "\\KernelObjects\\__wine_thread_mappings\\%08x-input", tid ); + asciiz_to_unicode( bufferW, buffer ); + map_shared_memory_section( bufferW, sizeof(struct input_shared_memory), NULL, + handle, (void **)ptr ); + return *ptr; +} + +volatile struct input_shared_memory *get_input_shared_memory( void ) +{ + volatile struct queue_shared_memory *queue = get_queue_shared_memory(); + struct user_thread_info *thread_info = get_user_thread_info(); + UINT tid; + + if (!queue) return NULL; + SHARED_READ_BEGIN( &queue->seq ) + { + tid = queue->input_tid; + } + SHARED_READ_END( &queue->seq ); + + return get_thread_input_shared_memory( tid, &thread_info->input_shared_map, + &thread_info->input_shared_memory ); +} + +volatile struct input_shared_memory *get_foreground_shared_memory( void ) +{ + volatile struct desktop_shared_memory *desktop = get_desktop_shared_memory(); + struct user_thread_info *thread_info = get_user_thread_info(); + UINT tid; + + if (!desktop) return NULL; + SHARED_READ_BEGIN( &desktop->seq ) + { + tid = desktop->foreground_tid; + } + SHARED_READ_END( &desktop->seq ); + + if (!tid) return NULL; + return get_thread_input_shared_memory( tid, &thread_info->foreground_shared_map, + &thread_info->foreground_shared_memory ); +} + /*********************************************************************** * winstation_init * From f167c489fe4f8e88b140691f7304925a0c8ab3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 18 Jan 2021 22:11:03 +0100 Subject: [PATCH 0312/2777] server: Add cursor handle and count to desktop shared memory. --- server/protocol.def | 2 ++ server/queue.c | 44 ++++++++++++++++++++++++++------------------ 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/server/protocol.def b/server/protocol.def index 3449588c71f..eb7aac1761a 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -903,7 +903,9 @@ struct input_shared_memory user_handle_t menu_owner; /* handle to the menu owner */ user_handle_t move_size; /* handle to the moving/resizing window */ user_handle_t caret; /* handle to the caret window */ + user_handle_t cursor; /* handle to the cursor */ rectangle_t caret_rect; /* caret rectangle */ + int cursor_count; /* cursor show count */ }; /* Bits that must be clear for client to read */ diff --git a/server/queue.c b/server/queue.c index 87519908013..ec1f0571b44 100644 --- a/server/queue.c +++ b/server/queue.c @@ -102,8 +102,6 @@ struct thread_input struct desktop *desktop; /* desktop that this thread input belongs to */ int caret_hide; /* caret hide count */ int caret_state; /* caret on/off state */ - user_handle_t cursor; /* current cursor */ - int cursor_count; /* cursor show count */ struct list msg_list; /* list of hardware messages */ unsigned char keystate[256]; /* state of each key */ unsigned char desktop_keystate[256]; /* desktop keystate when keystate was synced */ @@ -309,8 +307,8 @@ static struct thread_input *create_thread_input( struct thread *thread ) input->shared->active = 0; input->shared->menu_owner = 0; input->shared->move_size = 0; - input->cursor = 0; - input->cursor_count = 0; + input->shared->cursor = 0; + input->shared->cursor_count = 0; SHARED_WRITE_END( &input->shared->seq ); list_init( &input->msg_list ); set_caret_window( input, 0 ); @@ -428,13 +426,17 @@ static int assign_thread_input( struct thread *thread, struct thread_input *new_ } if (queue->input) { - queue->input->cursor_count -= queue->cursor_count; + SHARED_WRITE_BEGIN( &queue->input->shared->seq ); + queue->input->shared->cursor_count -= queue->cursor_count; + SHARED_WRITE_END( &queue->input->shared->seq ); if (queue->keystate_lock) unlock_input_keystate( queue->input ); release_object( queue->input ); } queue->input = (struct thread_input *)grab_object( new_input ); if (queue->keystate_lock) lock_input_keystate( queue->input ); - new_input->cursor_count += queue->cursor_count; + SHARED_WRITE_BEGIN( &new_input->shared->seq ); + new_input->shared->cursor_count += queue->cursor_count; + SHARED_WRITE_END( &new_input->shared->seq ); SHARED_WRITE_BEGIN( &queue->shared->seq ); queue->shared->input_tid = queue->input->shared->tid; @@ -1209,7 +1211,9 @@ static void cleanup_msg_queue( struct msg_queue *queue ) free( timer ); } if (queue->timeout) remove_timeout_user( queue->timeout ); - queue->input->cursor_count -= queue->cursor_count; + SHARED_WRITE_BEGIN( &queue->input->shared->seq ); + queue->input->shared->cursor_count -= queue->cursor_count; + SHARED_WRITE_END( &queue->input->shared->seq ); if (queue->keystate_lock) unlock_input_keystate( queue->input ); release_object( queue->input ); if (queue->hooks) release_object( queue->hooks ); @@ -3371,8 +3375,8 @@ DECL_HANDLER(get_thread_input) reply->menu_owner = input->shared->menu_owner; reply->move_size = input->shared->move_size; reply->caret = input->shared->caret; - reply->cursor = input->cursor; - reply->show_count = input->cursor_count; + reply->cursor = input->shared->cursor; + reply->show_count = input->shared->cursor_count; reply->rect = input->shared->caret_rect; } @@ -3623,25 +3627,29 @@ DECL_HANDLER(set_cursor) if (!queue) return; input = queue->input; - reply->prev_handle = input->cursor; - reply->prev_count = input->cursor_count; + reply->prev_handle = input->shared->cursor; + reply->prev_count = input->shared->cursor_count; reply->prev_x = input->desktop->shared->cursor.x; reply->prev_y = input->desktop->shared->cursor.y; + if ((req->flags & SET_CURSOR_HANDLE) && req->handle && + !get_user_object( req->handle, USER_CLIENT )) + { + set_win32_error( ERROR_INVALID_CURSOR_HANDLE ); + return; + } + + SHARED_WRITE_BEGIN( &input->shared->seq ); if (req->flags & SET_CURSOR_HANDLE) { - if (req->handle && !get_user_object( req->handle, USER_CLIENT )) - { - set_win32_error( ERROR_INVALID_CURSOR_HANDLE ); - return; - } - input->cursor = req->handle; + input->shared->cursor = req->handle; } if (req->flags & SET_CURSOR_COUNT) { queue->cursor_count += req->show_count; - input->cursor_count += req->show_count; + input->shared->cursor_count += req->show_count; } + SHARED_WRITE_END( &input->shared->seq ); if (req->flags & SET_CURSOR_POS) { set_cursor_pos( input->desktop, req->x, req->y ); From 000b884c7347f0d77e31d798eb08ded7c858bd58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 18 Jan 2021 19:19:51 +0100 Subject: [PATCH 0313/2777] user32: Use input shared memory for GetCursorInfo. --- dlls/win32u/input.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index b79ae675678..cb401ce0f23 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -248,20 +248,19 @@ BOOL get_cursor_pos( POINT *pt ) */ BOOL WINAPI NtUserGetCursorInfo( CURSORINFO *info ) { + volatile struct input_shared_memory *shared = get_foreground_shared_memory(); BOOL ret; if (!info) return FALSE; - SERVER_START_REQ( get_thread_input ) + if (!shared) ret = FALSE; + else SHARED_READ_BEGIN( &shared->seq ) { - req->tid = 0; - if ((ret = !wine_server_call( req ))) - { - info->hCursor = wine_server_ptr_handle( reply->cursor ); - info->flags = reply->show_count >= 0 ? CURSOR_SHOWING : 0; - } + info->hCursor = wine_server_ptr_handle( shared->cursor ); + info->flags = (shared->cursor_count >= 0) ? CURSOR_SHOWING : 0; + ret = TRUE; } - SERVER_END_REQ; + SHARED_READ_END( &shared->seq ); get_cursor_pos( &info->ptScreenPos ); return ret; } @@ -1445,14 +1444,17 @@ BOOL WINAPI release_capture(void) */ HWND WINAPI NtUserGetForegroundWindow(void) { + volatile struct input_shared_memory *shared = get_foreground_shared_memory(); HWND ret = 0; - SERVER_START_REQ( get_thread_input ) + if (!shared) return 0; + + SHARED_READ_BEGIN( &shared->seq ) { - req->tid = 0; - if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->foreground ); + ret = wine_server_ptr_handle( shared->active ); } - SERVER_END_REQ; + SHARED_READ_END( &shared->seq ); + return ret; } From e17c4ece2e40052866855169ceda592b0b4b1cc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 18 Jan 2021 19:21:09 +0100 Subject: [PATCH 0314/2777] server: Remove cursor and show_count from get_thread_input. --- server/protocol.def | 2 -- server/queue.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/server/protocol.def b/server/protocol.def index eb7aac1761a..fdffe4cd9b5 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2840,8 +2840,6 @@ enum coords_relative user_handle_t menu_owner; /* handle to the menu owner */ user_handle_t move_size; /* handle to the moving/resizing window */ user_handle_t caret; /* handle to the caret window */ - user_handle_t cursor; /* handle to the cursor */ - int show_count; /* cursor show count */ rectangle_t rect; /* caret rectangle */ @END diff --git a/server/queue.c b/server/queue.c index ec1f0571b44..bec5b5913fb 100644 --- a/server/queue.c +++ b/server/queue.c @@ -3375,8 +3375,6 @@ DECL_HANDLER(get_thread_input) reply->menu_owner = input->shared->menu_owner; reply->move_size = input->shared->move_size; reply->caret = input->shared->caret; - reply->cursor = input->shared->cursor; - reply->show_count = input->shared->cursor_count; reply->rect = input->shared->caret_rect; } From 6dcc12b6396e6b9df6f14392247da4b2449ed5ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 18 Jan 2021 22:12:08 +0100 Subject: [PATCH 0315/2777] server: Remove foreground window from get_thread_input. --- server/protocol.def | 1 - server/queue.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/server/protocol.def b/server/protocol.def index fdffe4cd9b5..9499bda5ce6 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2836,7 +2836,6 @@ enum coords_relative user_handle_t focus; /* handle to the focus window */ user_handle_t capture; /* handle to the capture window */ user_handle_t active; /* handle to the active window */ - user_handle_t foreground; /* handle to the global foreground window */ user_handle_t menu_owner; /* handle to the menu owner */ user_handle_t move_size; /* handle to the moving/resizing window */ user_handle_t caret; /* handle to the caret window */ diff --git a/server/queue.c b/server/queue.c index bec5b5913fb..d60b99e121d 100644 --- a/server/queue.c +++ b/server/queue.c @@ -3378,8 +3378,6 @@ DECL_HANDLER(get_thread_input) reply->rect = input->shared->caret_rect; } - /* foreground window is active window of foreground thread */ - reply->foreground = desktop->foreground_input ? desktop->foreground_input->shared->active : 0; if (thread) release_object( thread ); release_object( desktop ); } From b2167a0970f1bd231b70daeb1789dc8459a6aaf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 1 Mar 2021 20:19:52 +0100 Subject: [PATCH 0316/2777] HACK: user32: Always pretend that GetAsyncKeyState recent bit is 0. --- dlls/win32u/input.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index cb401ce0f23..c50143e1ef1 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -279,7 +279,6 @@ SHORT WINAPI NtUserGetAsyncKeyState( INT key ) { volatile struct desktop_shared_memory *shared = get_desktop_shared_memory(); BYTE state; - SHORT ret; if (key < 0 || key >= 256 || !shared) return 0; @@ -291,23 +290,7 @@ SHORT WINAPI NtUserGetAsyncKeyState( INT key ) } SHARED_READ_END( &shared->seq ); - if (!(state & 0x40)) return (state & 0x80) << 8; - - /* Need to make a server call to reset the last pressed bit */ - ret = 0; - SERVER_START_REQ( get_key_state ) - { - req->async = 1; - req->key = key; - if (!wine_server_call( req )) - { - if (reply->state & 0x40) ret |= 0x0001; - if (reply->state & 0x80) ret |= 0x8000; - } - } - SERVER_END_REQ; - - return ret; + return (state & 0x80) << 8; } /*********************************************************************** From e6ec1499ee7a9efc30b03ed6136e2e8de787bce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 17 Aug 2021 16:25:35 +0200 Subject: [PATCH 0317/2777] server: Only return full keystate when requested. --- server/queue.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/queue.c b/server/queue.c index d60b99e121d..44ce8e1a969 100644 --- a/server/queue.c +++ b/server/queue.c @@ -3399,7 +3399,7 @@ DECL_HANDLER(get_key_state) desktop->shared->keystate[req->key & 0xff] &= ~0x40; SHARED_WRITE_END( &desktop->shared->seq ); } - set_reply_data( (void *)desktop->shared->keystate, size ); + else set_reply_data( (void *)desktop->shared->keystate, size ); release_object( desktop ); } else @@ -3411,7 +3411,7 @@ DECL_HANDLER(get_key_state) sync_input_keystate( queue->input ); reply->state = keystate[req->key & 0xff]; } - set_reply_data( keystate, size ); + else set_reply_data( keystate, size ); } } From 59a224f7c5ebfded75d47a5b86a55666e8c11ed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 17 Aug 2021 17:14:13 +0200 Subject: [PATCH 0318/2777] server: Expose thread input keystate through shared memory. --- server/protocol.def | 1 + server/queue.c | 26 ++++++++++++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/server/protocol.def b/server/protocol.def index 9499bda5ce6..43399eba5ef 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -906,6 +906,7 @@ struct input_shared_memory user_handle_t cursor; /* handle to the cursor */ rectangle_t caret_rect; /* caret rectangle */ int cursor_count; /* cursor show count */ + unsigned char keystate[256]; /* key state */ }; /* Bits that must be clear for client to read */ diff --git a/server/queue.c b/server/queue.c index 44ce8e1a969..a2ac2239a47 100644 --- a/server/queue.c +++ b/server/queue.c @@ -103,7 +103,6 @@ struct thread_input int caret_hide; /* caret hide count */ int caret_state; /* caret on/off state */ struct list msg_list; /* list of hardware messages */ - unsigned char keystate[256]; /* state of each key */ unsigned char desktop_keystate[256]; /* desktop keystate when keystate was synced */ int keystate_lock; /* keystate is locked */ struct object *shared_mapping; /* thread input shared memory mapping */ @@ -309,10 +308,10 @@ static struct thread_input *create_thread_input( struct thread *thread ) input->shared->move_size = 0; input->shared->cursor = 0; input->shared->cursor_count = 0; + memset( (void *)input->shared->keystate, 0, sizeof(input->shared->keystate) ); SHARED_WRITE_END( &input->shared->seq ); list_init( &input->msg_list ); set_caret_window( input, 0 ); - memset( input->keystate, 0, sizeof(input->keystate) ); input->keystate_lock = 0; if (!(input->desktop = get_thread_desktop( thread, 0 /* FIXME: access rights */ ))) @@ -394,11 +393,13 @@ static void sync_input_keystate( struct thread_input *input ) { int i; if (!input->desktop || input->keystate_lock) return; - for (i = 0; i < sizeof(input->keystate); ++i) + SHARED_WRITE_BEGIN( &input->shared->seq ); + for (i = 0; i < sizeof(input->shared->keystate); ++i) { if (input->desktop_keystate[i] == input->desktop->shared->keystate[i]) continue; - input->keystate[i] = input->desktop_keystate[i] = input->desktop->shared->keystate[i]; + input->shared->keystate[i] = input->desktop_keystate[i] = input->desktop->shared->keystate[i]; } + SHARED_WRITE_END( &input->shared->seq ); } /* locks thread input keystate to prevent synchronization */ @@ -1338,7 +1339,12 @@ int attach_thread_input( struct thread *thread_from, struct thread *thread_to ) } ret = assign_thread_input( thread_from, input ); - if (ret) memset( input->keystate, 0, sizeof(input->keystate) ); + if (ret) + { + SHARED_WRITE_BEGIN( &input->shared->seq ); + memset( (void *)input->shared->keystate, 0, sizeof(input->shared->keystate) ); + SHARED_WRITE_END( &input->shared->seq ); + } release_object( input ); return ret; } @@ -1581,7 +1587,9 @@ static void update_key_state( volatile unsigned char *keystate, unsigned int msg static void update_input_key_state( struct thread_input *input, unsigned int msg, lparam_t wparam ) { - update_key_state( input->keystate, msg, wparam, 0 ); + SHARED_WRITE_BEGIN( &input->shared->seq ); + update_key_state( input->shared->keystate, msg, wparam, 0 ); + SHARED_WRITE_END( &input->shared->seq ); } static void update_desktop_key_state( struct desktop *desktop, unsigned int msg, lparam_t wparam ) @@ -3405,7 +3413,7 @@ DECL_HANDLER(get_key_state) else { struct msg_queue *queue = get_current_queue(); - unsigned char *keystate = queue->input->keystate; + unsigned char *keystate = (void *)queue->input->shared->keystate; if (req->key >= 0) { sync_input_keystate( queue->input ); @@ -3423,7 +3431,9 @@ DECL_HANDLER(set_key_state) struct msg_queue *queue = get_current_queue(); data_size_t size = min( 256, get_req_data_size() ); - memcpy( queue->input->keystate, get_req_data(), size ); + SHARED_WRITE_BEGIN( &queue->input->shared->seq ); + memcpy( (void *)queue->input->shared->keystate, get_req_data(), size ); + SHARED_WRITE_END( &queue->input->shared->seq ); memcpy( queue->input->desktop_keystate, (void *)queue->input->desktop->shared->keystate, sizeof(queue->input->desktop_keystate) ); if (req->async && (desktop = get_thread_desktop( current, 0 ))) From efe595e94f23b0ef4df55d41432568706c82b2e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 12 Dec 2021 13:19:34 +0100 Subject: [PATCH 0319/2777] user32: Use input shared memory in GetKeyboardState. user32: Mask off the unspecified bits in GetKeyboardState() When using shared memory for the keyboard state (as added in d2cbafab08) we no-longer mask off the unused bits, which causes the map to scroll uncontrollably in some situations in the Age of Empires series. This is a regression of bug: https://bugs.winehq.org/show_bug.cgi?id=30814 An analysis of the bug can be found: https://davidgow.net/hacks/aoescroll.html Fixes: d2cbafab08 ("user32: Use input shared memory in GetKeyboardState.") Signed-off-by: David Gow --- dlls/win32u/input.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index c50143e1ef1..fed3990d047 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -417,11 +417,26 @@ SHORT WINAPI NtUserGetKeyState( INT vkey ) */ BOOL WINAPI NtUserGetKeyboardState( BYTE *state ) { - BOOL ret; + volatile struct input_shared_memory *shared = get_input_shared_memory(); + BOOL ret, skip = TRUE; UINT i; TRACE("(%p)\n", state); + if (!shared) skip = FALSE; + else SHARED_READ_BEGIN( &shared->seq ) + { + if (!shared->created) skip = FALSE; /* server needs to create the queue */ + else memcpy( state, (const void *)shared->keystate, 256 ); + } + SHARED_READ_END( &shared->seq ); + + if (skip) + { + for (i = 0; i < 256; i++) state[i] &= 0x81; + return TRUE; + } + memset( state, 0, 256 ); SERVER_START_REQ( get_key_state ) { @@ -431,6 +446,7 @@ BOOL WINAPI NtUserGetKeyboardState( BYTE *state ) for (i = 0; i < 256; i++) state[i] &= 0x81; } SERVER_END_REQ; + return ret; } From d7115ff7bfdef73a510ac651848938e46072abcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 17 Aug 2021 17:22:26 +0200 Subject: [PATCH 0320/2777] server: Expose thread input keystate lock through shared memory. --- server/protocol.def | 1 + server/queue.c | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/server/protocol.def b/server/protocol.def index 43399eba5ef..ffba1f437cf 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -907,6 +907,7 @@ struct input_shared_memory rectangle_t caret_rect; /* caret rectangle */ int cursor_count; /* cursor show count */ unsigned char keystate[256]; /* key state */ + int keystate_lock; /* keystate is locked */ }; /* Bits that must be clear for client to read */ diff --git a/server/queue.c b/server/queue.c index a2ac2239a47..585fe42a29b 100644 --- a/server/queue.c +++ b/server/queue.c @@ -104,7 +104,6 @@ struct thread_input int caret_state; /* caret on/off state */ struct list msg_list; /* list of hardware messages */ unsigned char desktop_keystate[256]; /* desktop keystate when keystate was synced */ - int keystate_lock; /* keystate is locked */ struct object *shared_mapping; /* thread input shared memory mapping */ volatile struct input_shared_memory *shared; /* thread input shared memory ptr */ }; @@ -308,11 +307,11 @@ static struct thread_input *create_thread_input( struct thread *thread ) input->shared->move_size = 0; input->shared->cursor = 0; input->shared->cursor_count = 0; + input->shared->keystate_lock = 0; memset( (void *)input->shared->keystate, 0, sizeof(input->shared->keystate) ); SHARED_WRITE_END( &input->shared->seq ); list_init( &input->msg_list ); set_caret_window( input, 0 ); - input->keystate_lock = 0; if (!(input->desktop = get_thread_desktop( thread, 0 /* FIXME: access rights */ ))) { @@ -392,7 +391,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ static void sync_input_keystate( struct thread_input *input ) { int i; - if (!input->desktop || input->keystate_lock) return; + if (!input->desktop || input->shared->keystate_lock) return; SHARED_WRITE_BEGIN( &input->shared->seq ); for (i = 0; i < sizeof(input->shared->keystate); ++i) { @@ -405,14 +404,18 @@ static void sync_input_keystate( struct thread_input *input ) /* locks thread input keystate to prevent synchronization */ static void lock_input_keystate( struct thread_input *input ) { - input->keystate_lock++; + SHARED_WRITE_BEGIN( &input->shared->seq ); + input->shared->keystate_lock++; + SHARED_WRITE_END( &input->shared->seq ); } /* unlock the thread input keystate and synchronize it again */ static void unlock_input_keystate( struct thread_input *input ) { - input->keystate_lock--; - if (!input->keystate_lock) sync_input_keystate( input ); + SHARED_WRITE_BEGIN( &input->shared->seq ); + input->shared->keystate_lock--; + SHARED_WRITE_END( &input->shared->seq ); + if (!input->shared->keystate_lock) sync_input_keystate( input ); } /* change the thread input data of a given thread */ From 5e9294a00e8752d1610bba1494c8be8a8fdc9ad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 12 Dec 2021 13:20:22 +0100 Subject: [PATCH 0321/2777] user32: Use input shared memory for GetKeyState. --- dlls/win32u/input.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index fed3990d047..4267a590bfc 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -400,9 +400,20 @@ HKL WINAPI NtUserGetKeyboardLayout( DWORD thread_id ) */ SHORT WINAPI NtUserGetKeyState( INT vkey ) { + volatile struct input_shared_memory *shared = get_input_shared_memory(); SHORT retval = 0; + BOOL skip = TRUE; - SERVER_START_REQ( get_key_state ) + if (!shared) skip = FALSE; + else SHARED_READ_BEGIN( &shared->seq ) + { + if (!shared->created) skip = FALSE; /* server needs to create the queue */ + else if (!shared->keystate_lock) skip = FALSE; /* server needs to call sync_input_keystate */ + else retval = (signed char)(shared->keystate[vkey & 0xff] & 0x81); + } + SHARED_READ_END( &shared->seq ); + + if (!skip) SERVER_START_REQ( get_key_state ) { req->key = vkey; if (!wine_server_call( req )) retval = (signed char)(reply->state & 0x81); From 0c3f7dda85a270db17c5363cc7322f43bd48b942 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 14 Jul 2020 15:00:34 +0300 Subject: [PATCH 0322/2777] ntdll: Support x86_64 syscall emulation. Wine-Staging: ntdll-Syscall_Emulation --- configure.ac | 1 + dlls/ntdll/unix/signal_x86_64.c | 185 ++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) diff --git a/configure.ac b/configure.ac index 84a1d83979d..1babf104454 100644 --- a/configure.ac +++ b/configure.ac @@ -425,6 +425,7 @@ AC_CHECK_HEADERS(\ linux/ioctl.h \ linux/major.h \ linux/param.h \ + linux/seccomp.h \ linux/serial.h \ linux/types.h \ linux/ucdrom.h \ diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index b369988b85c..c8f729fc8bd 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -27,6 +27,7 @@ #include "config.h" #include +#include #include #include #include @@ -34,6 +35,8 @@ #include #include #include +#include +#include #include #ifdef HAVE_MACHINE_SYSARCH_H # include @@ -65,6 +68,14 @@ # include #endif +#if defined(HAVE_LINUX_FILTER_H) && defined(HAVE_LINUX_SECCOMP_H) && defined(HAVE_SYS_PRCTL_H) +#define HAVE_SECCOMP 1 +# include +# include +# include +# include +#endif + #define NONAMELESSUNION #define NONAMELESSSTRUCT #include "ntstatus.h" @@ -1820,6 +1831,179 @@ static inline DWORD is_privileged_instr( CONTEXT *context ) return 0; } +#ifdef HAVE_SECCOMP +static void sigsys_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + extern void __wine_syscall_dispatcher_prolog_end(void); + struct syscall_frame *frame = amd64_thread_data()->syscall_frame; + ucontext_t *ctx = sigcontext; + + TRACE_(seh)("SIGSYS, rax %#llx, rip %#llx.\n", ctx->uc_mcontext.gregs[REG_RAX], + ctx->uc_mcontext.gregs[REG_RIP]); + + frame->rip = ctx->uc_mcontext.gregs[REG_RIP] + 0xb; + frame->rcx = ctx->uc_mcontext.gregs[REG_RIP]; + frame->eflags = ctx->uc_mcontext.gregs[REG_EFL]; + frame->restore_flags = 0; + ctx->uc_mcontext.gregs[REG_RCX] = (ULONG_PTR)frame; + ctx->uc_mcontext.gregs[REG_R11] = frame->eflags; + ctx->uc_mcontext.gregs[REG_EFL] &= ~0x100; /* clear single-step flag */ + ctx->uc_mcontext.gregs[REG_RIP] = (ULONG64)__wine_syscall_dispatcher_prolog_end; +} +#endif + +#ifdef HAVE_SECCOMP +static int sc_seccomp(unsigned int operation, unsigned int flags, void *args) +{ +#ifndef __NR_seccomp +# define __NR_seccomp 317 +#endif + return syscall(__NR_seccomp, operation, flags, args); +} +#endif + +static void check_bpf_jit_enable(void) +{ + char enabled; + int fd; + + fd = open("/proc/sys/net/core/bpf_jit_enable", O_RDONLY); + if (fd == -1) + { + WARN_(seh)("Could not open /proc/sys/net/core/bpf_jit_enable.\n"); + return; + } + + if (read(fd, &enabled, sizeof(enabled)) == sizeof(enabled)) + { + TRACE_(seh)("enabled %#x.\n", enabled); + + if (enabled != '1') + ERR_(seh)("BPF JIT is not enabled in the kernel, enable it to reduce syscall emulation overhead.\n"); + } + else + { + WARN_(seh)("Could not read /proc/sys/net/core/bpf_jit_enable.\n"); + } + close(fd); +} + +static void install_bpf(struct sigaction *sig_act) +{ +#ifdef HAVE_SECCOMP +# ifndef SECCOMP_FILTER_FLAG_SPEC_ALLOW +# define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2) +# endif + +# ifndef SECCOMP_SET_MODE_FILTER +# define SECCOMP_SET_MODE_FILTER 1 +# endif + static const BYTE syscall_trap_test[] = + { + 0x48, 0x89, 0xc8, /* mov %rcx, %rax */ + 0x0f, 0x05, /* syscall */ + 0xc3, /* retq */ + }; + static const unsigned int flags = SECCOMP_FILTER_FLAG_SPEC_ALLOW; + +#define NATIVE_SYSCALL_ADDRESS_START 0x700000000000 + + static struct sock_filter filter[] = + { + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, instruction_pointer) + 4), + /* Native libs are loaded at high addresses. */ + BPF_JUMP(BPF_JMP | BPF_JGT | BPF_K, NATIVE_SYSCALL_ADDRESS_START >> 32, 0, 1), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + /* Allow i386. */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, arch)), + BPF_JUMP (BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1, 0), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + /* Allow wine64-preloader */ + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, instruction_pointer)), + BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, 0x7d400000, 1, 0), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), + BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, 0x7d402000, 0, 1), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), + }; + long (WINAPI *test_syscall)(long sc_number); + struct syscall_frame *frame = amd64_thread_data()->syscall_frame; + struct sock_fprog prog; + NTSTATUS status; + + if ((ULONG_PTR)sc_seccomp < NATIVE_SYSCALL_ADDRESS_START + || (ULONG_PTR)syscall < NATIVE_SYSCALL_ADDRESS_START) + { + ERR_(seh)("Native libs are being loaded in low addresses, sc_seccomp %p, syscall %p, not installing seccomp.\n", + sc_seccomp, syscall); + ERR_(seh)("The known reasons are /proc/sys/vm/legacy_va_layout set to 1 or 'ulimit -s' being 'unlimited'.\n"); + return; + } + + sig_act->sa_sigaction = sigsys_handler; + memset(&prog, 0, sizeof(prog)); + + sigaction(SIGSYS, sig_act, NULL); + + frame->syscall_flags = syscall_flags; + frame->syscall_table = KeServiceDescriptorTable; + + test_syscall = mmap((void *)0x600000000000, 0x1000, PROT_EXEC | PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (test_syscall != (void *)0x600000000000) + { + int ret; + + ERR("Could not allocate test syscall, falling back to seccomp presence check, test_syscall %p, errno %d.\n", + test_syscall, errno); + if (test_syscall != MAP_FAILED) munmap(test_syscall, 0x1000); + + if ((ret = prctl(PR_GET_SECCOMP, 0, NULL, 0, 0))) + { + if (ret == 2) + TRACE_(seh)("Seccomp filters already installed.\n"); + else + ERR_(seh)("Seccomp filters cannot be installed, ret %d, error %s.\n", ret, strerror(errno)); + return; + } + } + else + { + memcpy(test_syscall, syscall_trap_test, sizeof(syscall_trap_test)); + status = test_syscall(0xffff); + munmap(test_syscall, 0x1000); + if (status == STATUS_INVALID_PARAMETER) + { + TRACE_(seh)("Seccomp filters already installed.\n"); + return; + } + if (status != -ENOSYS && (status != -1 || errno != ENOSYS)) + { + ERR_(seh)("Unexpected status %#x, errno %d.\n", status, errno); + return; + } + } + + TRACE_(seh)("Installing seccomp filters.\n"); + + prog.len = ARRAY_SIZE(filter); + prog.filter = filter; + + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) + { + ERR_(seh)("prctl(PR_SET_NO_NEW_PRIVS, ...): %s.\n", strerror(errno)); + return; + } + if (sc_seccomp(SECCOMP_SET_MODE_FILTER, flags, &prog)) + { + ERR_(seh)("prctl(PR_SET_SECCOMP, ...): %s.\n", strerror(errno)); + return; + } + check_bpf_jit_enable(); +#else + WARN_(seh)("Built without seccomp.\n"); +#endif +} /*********************************************************************** * handle_interrupt @@ -2489,6 +2673,7 @@ void signal_init_process(void) if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error; if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error; if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error; + install_bpf(&sig_act); return; error: From adc967990c0dd272dbd95635ec3a9f1bdb8a4d22 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 26 Oct 2021 19:07:26 +0300 Subject: [PATCH 0323/2777] ntdll: Don't use Wine frames during exception processing on x64. CW-Bug-ID: #19570 Wine-Staging: ntdll-wine-frames --- dlls/ntdll/signal_x86_64.c | 65 +++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index ac543338893..e7afdf22a0e 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -348,15 +348,32 @@ __ASM_GLOBAL_FUNC( RtlCaptureContext, "fxsave 0x100(%rcx)\n\t" /* context->FltSave */ "ret" ); -static DWORD __cdecl nested_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, +DWORD __cdecl nested_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) { + TRACE( "exception flags %#lx.\n", rec->ExceptionFlags ); + if (!(rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))) - rec->ExceptionFlags |= EH_NESTED_CALL; + return ExceptionNestedException; return ExceptionContinueSearch; } +/*********************************************************************** + * exception_handler_call_wrapper + */ +DWORD exception_handler_call_wrapper( EXCEPTION_RECORD *rec, void *frame, + CONTEXT *context, DISPATCHER_CONTEXT *dispatch ); +__ASM_GLOBAL_FUNC( exception_handler_call_wrapper, + __ASM_SEH(".seh_endprologue\n\t") + "subq $0x28, %rsp\n\t" + __ASM_SEH(".seh_stackalloc 0x28\n\t") + __ASM_SEH(".seh_handler nested_exception_handler, @except\n\t") + "callq *0x30(%r9)\n\t" /* dispatch->LanguageHandler */ + "nop\n\t" + "addq $0x28, %rsp\n\t" + "ret" ); + /********************************************************************** * call_handler * @@ -365,19 +382,19 @@ static DWORD __cdecl nested_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_ */ static DWORD call_handler( EXCEPTION_RECORD *rec, CONTEXT *context, DISPATCHER_CONTEXT *dispatch ) { - EXCEPTION_REGISTRATION_RECORD frame; DWORD res; - frame.Handler = nested_exception_handler; - __wine_push_frame( &frame ); - TRACE_(seh)( "calling handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n", dispatch->LanguageHandler, rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch ); - res = dispatch->LanguageHandler( rec, (void *)dispatch->EstablisherFrame, context, dispatch ); + res = exception_handler_call_wrapper( rec, (void *)dispatch->EstablisherFrame, context, dispatch ); TRACE_(seh)( "handler at %p returned %lu\n", dispatch->LanguageHandler, res ); rec->ExceptionFlags &= EH_NONCONTINUABLE; - __wine_pop_frame( &frame ); + if (res == ExceptionNestedException) + { + rec->ExceptionFlags |= EH_NESTED_CALL; + res = ExceptionContinueSearch; + } return res; } @@ -992,7 +1009,8 @@ PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc, struct unwind_exception_frame { - EXCEPTION_REGISTRATION_RECORD frame; + BYTE dummy[0x28]; + void *rip; DISPATCHER_CONTEXT *dispatch; }; @@ -1001,7 +1019,7 @@ struct unwind_exception_frame * * Handler for exceptions happening while calling an unwind handler. */ -static DWORD __cdecl unwind_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, +DWORD __cdecl unwind_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) { struct unwind_exception_frame *unwind_frame = (struct unwind_exception_frame *)frame; @@ -1021,27 +1039,36 @@ static DWORD __cdecl unwind_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_ return ExceptionCollidedUnwind; } +/*********************************************************************** + * exception_handler_call_wrapper + */ +DWORD unwind_handler_call_wrapper( EXCEPTION_RECORD *rec, void *frame, + CONTEXT *context, DISPATCHER_CONTEXT *dispatch ); +__ASM_GLOBAL_FUNC( unwind_handler_call_wrapper, + __ASM_SEH(".seh_endprologue\n\t") + "movq %r9, 0x8(%rsp)\n\t" + "subq $0x28, %rsp\n\t" + __ASM_SEH(".seh_stackalloc 0x28\n\t") + __ASM_SEH(".seh_handler unwind_exception_handler, @except, @unwind\n\t") + "callq *0x30(%r9)\n\t" /* dispatch->LanguageHandler */ + "nop\n\t" + "addq $0x28, %rsp\n\t" + "ret" ); + /********************************************************************** * call_unwind_handler * * Call a single unwind handler. */ -static DWORD call_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch ) +DWORD call_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch ) { - struct unwind_exception_frame frame; DWORD res; - frame.frame.Handler = unwind_exception_handler; - frame.dispatch = dispatch; - __wine_push_frame( &frame.frame ); - TRACE( "calling handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n", dispatch->LanguageHandler, rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch ); - res = dispatch->LanguageHandler( rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch ); + res = unwind_handler_call_wrapper( rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch ); TRACE( "handler %p returned %lx\n", dispatch->LanguageHandler, res ); - __wine_pop_frame( &frame.frame ); - switch (res) { case ExceptionContinueSearch: From d549eec5a7fe0f6a9e250081f4c00539aba703de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zef=20Kucia?= Date: Mon, 23 Jul 2018 19:53:20 +0200 Subject: [PATCH 0324/2777] amd_ags_x64: Import v5.1.1 amd_ags.h. Imported from https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK. --- dlls/amd_ags_x64/amd_ags.h | 944 +++++++++++++++++++++++++++++++++++++ 1 file changed, 944 insertions(+) create mode 100644 dlls/amd_ags_x64/amd_ags.h diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h new file mode 100644 index 00000000000..9c3e37e52e5 --- /dev/null +++ b/dlls/amd_ags_x64/amd_ags.h @@ -0,0 +1,944 @@ +// +// Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +/// \file +/// \mainpage +/// AGS Library Overview +/// -------------------- +/// This document provides an overview of the AGS (AMD GPU Services) library. The AGS library provides software developers with the ability to query +/// AMD GPU software and hardware state information that is not normally available through standard operating systems or graphic APIs. +/// +/// The latest version of the API is publicly hosted here: https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK/. +/// It is also worth checking http://gpuopen.com/gaming-product/amd-gpu-services-ags-library/ for any updates and articles on AGS. +/// \internal +/// Online documentation is publicly hosted here: http://gpuopen-librariesandsdks.github.io/ags/ +/// \endinternal +/// +/// What's new in AGS 5.1.1 since version 5.0.6 +/// --------------------------------------- +/// AGS 5.1.1 includes the following updates: +/// * An API change for DX11 extensions +/// - It is now mandatory to call agsDriverExtensionsDX11_CreateDevice() when creating a device if the user wants to access any DX11 AMD extensions. +/// - The corresponding agsDriverExtensionsDX11_DestroyDevice() call must be called to release the device and free up the internal resources allocated by the create call. +/// * App registration extension for DX11. +/// * Freesync 2 HDR support. +/// * Wave reduce and wave scan shader extensions. +/// * AMD user markers for DX12. +/// * Eyefinity bug fixes. +/// * MultiDrawIndexedInstancedIndirectCountIndirect parameter bug fix. +/// * Static lib versions of the binary. +/// * VS2017 support for the samples. +/// +/// What's new in AGS 5.x since version 4.x +/// --------------------------------------- +/// Version 5.x is a major overhaul of the library designed to provide a much clearer view of the GPUs in the system and the displays attached to them. +/// It also exposes the ability to query each display for HDR capabilities and put those HDR capable displays into various HDR modes. +/// Some functions such as agsGetGPUMemorySize and agsGetEyefinityConfigInfo have been removed in favor of including this information in the device & display enumeration. +/// Features include: +/// * Full GPU enumeration with adapter string, device id, revision id and vendor id. +/// * Per GPU display enumeration including information on display name, resolution and HDR capabilities. +/// * Optional user supplied memory allocator. +/// * Function to set displays into HDR mode. +/// * A Microsoft WACK compliant version of the library. +/// * DirectX11 shader compiler controls. +/// * DirectX11 multiview extension enabling MultiView and MultiRes rendering. +/// * DirectX11 Crossfire API now supports using the API without needing a driver profile. Can also specify the transfer engine. +/// +/// Using the AGS library +/// --------------------- +/// It is recommended to take a look at the source code for the samples that come with the AGS SDK: +/// * AGSSample +/// * CrossfireSample +/// * EyefinitySample +/// The AGSSample application is the simplest of the three examples and demonstrates the code required to initialize AGS and use it to query the GPU and Eyefinity state. +/// The CrossfireSample application demonstrates the use of the new API to transfer resources on GPUs in Crossfire mode. Lastly, the EyefinitySample application provides a more +/// extensive example of Eyefinity setup than the basic example provided in AGSSample. +/// There are other samples on Github that demonstrate the DirectX shader extensions, such as the Barycentrics11 and Barycentrics12 samples. +/// +/// To add AGS support to an existing project, follow these steps: +/// * Link your project against the correct import library. Choose from either the 32 bit or 64 bit version. +/// * Copy the AGS dll into the same directory as your game executable. +/// * Include the amd_ags.h header file from your source code. +/// * Include the AGS hlsl files if you are using the shader intrinsics. +/// * Declare a pointer to an AGSContext and make this available for all subsequent calls to AGS. +/// * On game initialization, call agsInit() passing in the address of the context. On success, this function will return a valid context pointer. +/// * The agsInit() function should be called before the D3D device is created if the Crossfire mode is specified. +/// +/// Don't forget to cleanup AGS by calling agsDeInit() when the app exits, after the device has been destroyed. + +#ifndef AMD_AGS_H +#define AMD_AGS_H + +#define AMD_AGS_VERSION_MAJOR 5 ///< AGS major version +#define AMD_AGS_VERSION_MINOR 1 ///< AGS minor version +#define AMD_AGS_VERSION_PATCH 1 ///< AGS patch version + +#ifdef __cplusplus +extern "C" { +#endif + + +#define AMD_AGS_API __declspec(dllexport) ///< AGS calling convention + +// Forward declaration of D3D11 types +struct IDXGIAdapter; +enum D3D_DRIVER_TYPE; +enum D3D_FEATURE_LEVEL; +struct DXGI_SWAP_CHAIN_DESC; +struct ID3D11Device; +struct ID3D11DeviceContext; +struct IDXGISwapChain; +struct ID3D11Resource; +struct ID3D11Buffer; +struct ID3D11Texture1D; +struct ID3D11Texture2D; +struct ID3D11Texture3D; +struct D3D11_BUFFER_DESC; +struct D3D11_TEXTURE1D_DESC; +struct D3D11_TEXTURE2D_DESC; +struct D3D11_TEXTURE3D_DESC; +struct D3D11_SUBRESOURCE_DATA; +struct tagRECT; +typedef tagRECT D3D11_RECT; ///< typedef this ourselves so we don't have to drag d3d11.h in + +// Forward declaration of D3D12 types +struct ID3D12Device; +struct ID3D12GraphicsCommandList; + + +/// The return codes +enum AGSReturnCode +{ + AGS_SUCCESS, ///< Successful function call + AGS_FAILURE, ///< Failed to complete call for some unspecified reason + AGS_INVALID_ARGS, ///< Invalid arguments into the function + AGS_OUT_OF_MEMORY, ///< Out of memory when allocating space internally + AGS_ERROR_MISSING_DLL, ///< Returned when a driver dll fails to load - most likely due to not being present in legacy driver installation + AGS_ERROR_LEGACY_DRIVER, ///< Returned if a feature is not present in the installed driver + AGS_EXTENSION_NOT_SUPPORTED, ///< Returned if the driver does not support the requested driver extension + AGS_ADL_FAILURE, ///< Failure in ADL (the AMD Display Library) +}; + +/// The DirectX11 extension support bits +enum AGSDriverExtensionDX11 +{ + AGS_DX11_EXTENSION_QUADLIST = 1 << 0, + AGS_DX11_EXTENSION_SCREENRECTLIST = 1 << 1, + AGS_DX11_EXTENSION_UAV_OVERLAP = 1 << 2, + AGS_DX11_EXTENSION_DEPTH_BOUNDS_TEST = 1 << 3, + AGS_DX11_EXTENSION_MULTIDRAWINDIRECT = 1 << 4, + AGS_DX11_EXTENSION_MULTIDRAWINDIRECT_COUNTINDIRECT = 1 << 5, + AGS_DX11_EXTENSION_CROSSFIRE_API = 1 << 6, + AGS_DX11_EXTENSION_INTRINSIC_READFIRSTLANE = 1 << 7, + AGS_DX11_EXTENSION_INTRINSIC_READLANE = 1 << 8, + AGS_DX11_EXTENSION_INTRINSIC_LANEID = 1 << 9, + AGS_DX11_EXTENSION_INTRINSIC_SWIZZLE = 1 << 10, + AGS_DX11_EXTENSION_INTRINSIC_BALLOT = 1 << 11, + AGS_DX11_EXTENSION_INTRINSIC_MBCOUNT = 1 << 12, + AGS_DX11_EXTENSION_INTRINSIC_COMPARE3 = 1 << 13, + AGS_DX11_EXTENSION_INTRINSIC_BARYCENTRICS = 1 << 14, + AGS_DX11_EXTENSION_INTRINSIC_WAVE_REDUCE = 1 << 15, ///< Supported in Radeon Software Version 17.9.1 onwards. + AGS_DX11_EXTENSION_INTRINSIC_WAVE_SCAN = 1 << 16, ///< Supported in Radeon Software Version 17.9.1 onwards. + AGS_DX11_EXTENSION_CREATE_SHADER_CONTROLS = 1 << 17, + AGS_DX11_EXTENSION_MULTIVIEW = 1 << 18, + AGS_DX11_EXTENSION_APP_REGISTRATION = 1 << 19 ///< Supported in Radeon Software Version 17.9.1 onwards. +}; + +/// The DirectX12 extension support bits +enum AGSDriverExtensionDX12 +{ + AGS_DX12_EXTENSION_INTRINSIC_READFIRSTLANE = 1 << 0, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. + AGS_DX12_EXTENSION_INTRINSIC_READLANE = 1 << 1, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. + AGS_DX12_EXTENSION_INTRINSIC_LANEID = 1 << 2, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. + AGS_DX12_EXTENSION_INTRINSIC_SWIZZLE = 1 << 3, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. + AGS_DX12_EXTENSION_INTRINSIC_BALLOT = 1 << 4, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. + AGS_DX12_EXTENSION_INTRINSIC_MBCOUNT = 1 << 5, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. + AGS_DX12_EXTENSION_INTRINSIC_COMPARE3 = 1 << 6, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. + AGS_DX12_EXTENSION_INTRINSIC_BARYCENTRICS = 1 << 7, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. + AGS_DX12_EXTENSION_INTRINSIC_WAVE_REDUCE = 1 << 8, ///< Supported in Radeon Software Version 17.9.1 onwards. + AGS_DX12_EXTENSION_INTRINSIC_WAVE_SCAN = 1 << 9, ///< Supported in Radeon Software Version 17.9.1 onwards. + AGS_DX12_EXTENSION_USER_MARKERS = 1 << 10 ///< Supported in Radeon Software Version 17.9.1 onwards. +}; + +/// The space id for DirectX12 intrinsic support +const unsigned int AGS_DX12_SHADER_INSTRINSICS_SPACE_ID = 0x7FFF0ADE; // 2147420894 + + +/// Additional topologies supported via extensions +enum AGSPrimitiveTopology +{ + AGS_PRIMITIVE_TOPOLOGY_QUADLIST = 7, + AGS_PRIMITIVE_TOPOLOGY_SCREENRECTLIST = 9 +}; + +/// The different modes to control Crossfire behavior. +enum AGSCrossfireMode +{ + AGS_CROSSFIRE_MODE_DRIVER_AFR = 0, ///< Use the default driver-based AFR rendering + AGS_CROSSFIRE_MODE_EXPLICIT_AFR, ///< Use the AGS Crossfire API functions to perform explicit AFR rendering without requiring a CF driver profile + AGS_CROSSFIRE_MODE_DISABLE ///< Completely disable AFR rendering +}; + + +/// The Crossfire API transfer types +enum AGSAfrTransferType +{ + AGS_AFR_TRANSFER_DEFAULT = 0, ///< Default Crossfire driver resource tracking + AGS_AFR_TRANSFER_DISABLE = 1, ///< Turn off driver resource tracking + AGS_AFR_TRANSFER_1STEP_P2P = 2, ///< App controlled GPU to next GPU transfer + AGS_AFR_TRANSFER_2STEP_NO_BROADCAST = 3, ///< App controlled GPU to next GPU transfer using intermediate system memory + AGS_AFR_TRANSFER_2STEP_WITH_BROADCAST = 4, ///< App controlled GPU to all render GPUs transfer using intermediate system memory +}; + +/// The Crossfire API transfer engines +enum AGSAfrTransferEngine +{ + AGS_AFR_TRANSFERENGINE_DEFAULT = 0, ///< Use default engine for Crossfire API transfers + AGS_AFR_TRANSFERENGINE_3D_ENGINE = 1, ///< Use 3D engine for Crossfire API transfers + AGS_AFR_TRANSFERENGINE_COPY_ENGINE = 2, ///< Use Copy engine for Crossfire API transfers +}; + +/// The display flags describing various properties of the display. +enum AGSDisplayFlags +{ + AGS_DISPLAYFLAG_PRIMARY_DISPLAY = 1 << 0, ///< Whether this display is marked as the primary display. Not set on the WACK version. + AGS_DISPLAYFLAG_HDR10 = 1 << 1, ///< HDR10 is supported on this display + AGS_DISPLAYFLAG_DOLBYVISION = 1 << 2, ///< Dolby Vision is supported on this display + AGS_DISPLAYFLAG_FREESYNC = 1 << 3, ///< Freesync is supported on this display + AGS_DISPLAYFLAG_FREESYNC_2 = 1 << 4, ///< Freesync 2 is supported on this display + AGS_DISPLAYFLAG_EYEFINITY_IN_GROUP = 1 << 5, ///< The display is part of the Eyefinity group + AGS_DISPLAYFLAG_EYEFINITY_PREFERRED_DISPLAY = 1 << 6, ///< The display is the preferred display in the Eyefinity group for displaying the UI + AGS_DISPLAYFLAG_EYEFINITY_IN_PORTRAIT_MODE = 1 << 7, ///< The display is in the Eyefinity group but in portrait mode +}; + +struct AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInit + +/// The rectangle struct used by AGS. +struct AGSRect +{ + int offsetX; ///< Offset on X axis + int offsetY; ///< Offset on Y axis + int width; ///< Width of rectangle + int height; ///< Height of rectangle +}; + +/// The clip rectangle struct used by \ref agsDriverExtensionsDX11_SetClipRects +struct AGSClipRect +{ + /// The inclusion mode for the rect + enum Mode + { + ClipRectIncluded = 0, ///< Include the rect + ClipRectExcluded = 1 ///< Exclude the rect + }; + + Mode mode; ///< Include/exclude rect region + AGSRect rect; ///< The rect to include/exclude +}; + +/// The display info struct used to describe a display enumerated by AGS +struct AGSDisplayInfo +{ + char name[ 256 ]; ///< The name of the display + char displayDeviceName[ 32 ]; ///< The display device name, i.e. DISPLAY_DEVICE::DeviceName + + unsigned int displayFlags; ///< Bitfield of ::AGSDisplayFlags + + int maxResolutionX; ///< The maximum supported resolution of the unrotated display + int maxResolutionY; ///< The maximum supported resolution of the unrotated display + float maxRefreshRate; ///< The maximum supported refresh rate of the display + + AGSRect currentResolution; ///< The current resolution and position in the desktop, ignoring Eyefinity bezel compensation + AGSRect visibleResolution; ///< The visible resolution and position. When Eyefinity bezel compensation is enabled this will + ///< be the sub region in the Eyefinity single large surface (SLS) + float currentRefreshRate; ///< The current refresh rate + + int eyefinityGridCoordX; ///< The X coordinate in the Eyefinity grid. -1 if not in an Eyefinity group + int eyefinityGridCoordY; ///< The Y coordinate in the Eyefinity grid. -1 if not in an Eyefinity group + + double chromaticityRedX; ///< Red display primary X coord + double chromaticityRedY; ///< Red display primary Y coord + + double chromaticityGreenX; ///< Green display primary X coord + double chromaticityGreenY; ///< Green display primary Y coord + + double chromaticityBlueX; ///< Blue display primary X coord + double chromaticityBlueY; ///< Blue display primary Y coord + + double chromaticityWhitePointX; ///< White point X coord + double chromaticityWhitePointY; ///< White point Y coord + + double screenDiffuseReflectance; ///< Percentage expressed between 0 - 1 + double screenSpecularReflectance; ///< Percentage expressed between 0 - 1 + + double minLuminance; ///< The minimum luminance of the display in nits + double maxLuminance; ///< The maximum luminance of the display in nits + double avgLuminance; ///< The average luminance of the display in nits + + int logicalDisplayIndex; ///< The internally used index of this display + int adlAdapterIndex; ///< The internally used ADL adapter index +}; + +/// The device info struct used to describe a physical GPU enumerated by AGS +struct AGSDeviceInfo +{ + /// The architecture version + enum ArchitectureVersion + { + ArchitectureVersion_Unknown, ///< Unknown architecture, potentially from another IHV. Check AGSDeviceInfo::vendorId + ArchitectureVersion_PreGCN, ///< AMD architecture, pre-GCN + ArchitectureVersion_GCN ///< AMD GCN architecture + }; + + ArchitectureVersion architectureVersion; ///< Set to Unknown if not AMD hardware + const char* adapterString; ///< The adapter name string + int vendorId; ///< The vendor id + int deviceId; ///< The device id + int revisionId; ///< The revision id + + int numCUs; ///< Number of GCN compute units. Zero if not GCN + int coreClock; ///< Core clock speed at 100% power in MHz + int memoryClock; ///< Memory clock speed at 100% power in MHz + float teraFlops; ///< Teraflops of GPU. Zero if not GCN. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD + + int isPrimaryDevice; ///< Whether or not this is the primary adapter in the system. Not set on the WACK version. + long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. + + int numDisplays; ///< The number of active displays found to be attached to this adapter. + AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. + + int eyefinityEnabled; ///< Indicates if Eyefinity is active + int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. + int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. + int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. + + int adlAdapterIndex; ///< Internally used index into the ADL list of adapters +}; + +/// \defgroup general General API functions +/// API for initialization, cleanup, HDR display modes and Crossfire GPU count +/// @{ + +typedef void* (__stdcall *AGS_ALLOC_CALLBACK)( int allocationSize ); ///< AGS user defined allocation prototype +typedef void (__stdcall *AGS_FREE_CALLBACK)( void* allocationPtr ); ///< AGS user defined free prototype + + /// The configuration options that can be passed in to \ref agsInit +struct AGSConfiguration +{ + AGS_ALLOC_CALLBACK allocCallback; ///< Optional memory allocation callback. If not supplied, malloc() is used + AGS_FREE_CALLBACK freeCallback; ///< Optional memory freeing callback. If not supplied, free() is used + AGSCrossfireMode crossfireMode; ///< Desired Crossfire mode +}; + +/// The top level GPU information returned from \ref agsInit +struct AGSGPUInfo +{ + int agsVersionMajor; ///< Major field of Major.Minor.Patch AGS version number + int agsVersionMinor; ///< Minor field of Major.Minor.Patch AGS version number + int agsVersionPatch; ///< Patch field of Major.Minor.Patch AGS version number + int isWACKCompliant; ///< 1 if WACK compliant. + + const char* driverVersion; ///< The AMD driver package version + const char* radeonSoftwareVersion; ///< The Radeon Software Version + + int numDevices; ///< Number of GPUs in the system + AGSDeviceInfo* devices; ///< List of GPUs in the system +}; + +/// The struct to specify the display settings to the driver. +struct AGSDisplaySettings +{ + /// The display mode + enum Mode + { + Mode_SDR, ///< SDR mode + Mode_HDR10_PQ, ///< HDR10 PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. + Mode_HDR10_scRGB, ///< HDR10 scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. + Mode_Freesync2_scRGB, ///< Freesync2 scRGB, requiring an FP16 swapchain. Values in the range of 0.0 to 125.0 where 125.0 == AGSDisplayInfo::maxLuminance. + Mode_DolbyVision ///< Dolby Vision, requiring an 8888 UNORM swapchain + }; + + Mode mode; ///< The display mode to set the display into + + double chromaticityRedX; ///< Red display primary X coord + double chromaticityRedY; ///< Red display primary Y coord + + double chromaticityGreenX; ///< Green display primary X coord + double chromaticityGreenY; ///< Green display primary Y coord + + double chromaticityBlueX; ///< Blue display primary X coord + double chromaticityBlueY; ///< Blue display primary Y coord + + double chromaticityWhitePointX; ///< White point X coord + double chromaticityWhitePointY; ///< White point Y coord + + double minLuminance; ///< The minimum scene luminance in nits + double maxLuminance; ///< The maximum scene luminance in nits + + double maxContentLightLevel; ///< The maximum content light level in nits (MaxCLL) + double maxFrameAverageLightLevel; ///< The maximum frame average light level in nits (MaxFALL) +}; + +/// +/// Function used to initialize the AGS library. +/// Must be called prior to any of the subsequent AGS API calls. +/// Must be called prior to ID3D11Device or ID3D12Device creation. +/// \note This function will fail with AGS_ERROR_LEGACY_DRIVER in Catalyst versions before 12.20. +/// \note It is good practice to check the AGS version returned from AGSGPUInfo against the version defined in the header in case a mismatch between the dll and header has occurred. +/// +/// \param [in, out] context Address of a pointer to a context. This function allocates a context on the heap which is then required for all subsequent API calls. +/// \param [in] config Optional pointer to a AGSConfiguration struct to override the default library configuration. +/// \param [out] gpuInfo Optional pointer to a AGSGPUInfo struct which will get filled in for all the GPUs in the system. +/// +AMD_AGS_API AGSReturnCode agsInit( AGSContext** context, const AGSConfiguration* config, AGSGPUInfo* gpuInfo ); + +/// +/// Function used to clean up the AGS library. +/// +/// \param [in] context Pointer to a context. This function will deallocate the context from the heap. +/// +AMD_AGS_API AGSReturnCode agsDeInit( AGSContext* context ); + +/// +/// Function used to query the number of GPUs used for Crossfire acceleration. +/// This may be different from the total number of GPUs present in the system. +/// +/// \param [in] context Pointer to a context. +/// \param [out] numGPUs Number of GPUs used for Crossfire acceleration +/// +AMD_AGS_API AGSReturnCode agsGetCrossfireGPUCount( AGSContext* context, int* numGPUs ); + +/// +/// Function used to set a specific display into HDR mode +/// \note Setting all of the values apart from color space and transfer function to zero will cause the display to use defaults. +/// \note Call this function after each mode change (switch to fullscreen, any change in swapchain etc). +/// \note HDR10 PQ mode requires a 1010102 swapchain. +/// \note HDR10 scRGB mode requires an FP16 swapchain. +/// \note Freesync2 Gamma mode requires a 1010102 swapchain. +/// \note Freesync2 scRGB mode requires an FP16 swapchain. +/// \note Dolby Vision requires a 8888 UNORM swapchain. +/// +/// \param [in] context Pointer to a context. This is generated by \ref agsInit +/// \param [in] deviceIndex The index of the device listed in \ref AGSGPUInfo::devices. +/// \param [in] displayIndex The index of the display listed in \ref AGSDeviceInfo::displays. +/// \param [in] settings Pointer to the display settings to use. +/// +AMD_AGS_API AGSReturnCode agsSetDisplayMode( AGSContext* context, int deviceIndex, int displayIndex, const AGSDisplaySettings* settings ); + +/// @} + +/// \defgroup dx12 DirectX12 Extensions +/// DirectX12 driver extensions +/// @{ + +/// \defgroup dx12init Initialization and Cleanup +/// @{ + +/// +/// Function used to initialize the AMD-specific driver extensions for D3D12. +/// Extensions require support in the driver, therefore it is important to check the extensionsSupported bitfield. +/// +/// When using the HLSL shader extensions please note: +/// * The shader compiler should not use the D3DCOMPILE_SKIP_OPTIMIZATION option, otherwise it will not work. +/// * The intrinsic instructions require a 5.1 shader model. +/// * The Root Signature will need to use an extra resource and sampler. These are not real resources/samplers, they are just used to encode the intrinsic instruction. +/// +/// \param [in] context Pointer to a context. This is generated by \ref agsInit +/// \param [in] device The D3D12 device. +/// \param [out] extensionsSupported Pointer to a bit mask that this function will fill in to indicate which extensions are supported. See ::AGSDriverExtensionDX12 +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_Init( AGSContext* context, ID3D12Device* device, unsigned int* extensionsSupported ); + +/// +/// Function used to cleanup any AMD-specific driver extensions for D3D12 +/// +/// \param [in] context Pointer to a context. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_DeInit( AGSContext* context ); + +/// @} + +/// \defgroup dx12usermarkers User Markers +/// @{ + +/// +/// Function used to push an AMD user marker onto the command list. +/// This is only has an effect if AGS_DX12_EXTENSION_USER_MARKERS is present in the extensionsSupported bitfield of agsDriverExtensionsDX12_Init() +/// Supported in Radeon Software Version 17.9.1 onwards. +/// +/// \param [in] context Pointer to a context. +/// \param [in] commandList Pointer to the command list. +/// \param [in] data The marker string. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_PushMarker( AGSContext* context, ID3D12GraphicsCommandList* commandList, const char* data ); + +/// +/// Function used to pop an AMD user marker on the command list. +/// Supported in Radeon Software Version 17.9.1 onwards. +/// +/// \param [in] context Pointer to a context. +/// \param [in] commandList Pointer to the command list. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_PopMarker( AGSContext* context, ID3D12GraphicsCommandList* commandList ); + +/// +/// Function used to insert an single event AMD user marker onto the command list. +/// Supported in Radeon Software Version 17.9.1 onwards. +/// +/// \param [in] context Pointer to a context. +/// \param [in] commandList Pointer to the command list. +/// \param [in] data The marker string. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_SetMarker( AGSContext* context, ID3D12GraphicsCommandList* commandList, const char* data ); + +/// @} + +/// @} + +/// \defgroup dx11 DirectX11 Extensions +/// DirectX11 driver extensions +/// @{ + +/// \defgroup dx11init Device creation and cleanup +/// It is now mandatory to call agsDriverExtensionsDX11_CreateDevice() when creating a device if the user wants to access any DX11 AMD extensions. +/// The corresponding agsDriverExtensionsDX11_DestroyDevice() call must be called to release the device and free up the internal resources allocated by the create call. +/// @{ + +/// The struct to specify the existing DX11 device creation parameters +struct AGSDX11DeviceCreationParams +{ + IDXGIAdapter* pAdapter; ///< Consult the DX documentation on D3D11CreateDevice for this parameter + D3D_DRIVER_TYPE DriverType; ///< Consult the DX documentation on D3D11CreateDevice for this parameter + HMODULE Software; ///< Consult the DX documentation on D3D11CreateDevice for this parameter + UINT Flags; ///< Consult the DX documentation on D3D11CreateDevice for this parameter + const D3D_FEATURE_LEVEL* pFeatureLevels; ///< Consult the DX documentation on D3D11CreateDevice for this parameter + UINT FeatureLevels; ///< Consult the DX documentation on D3D11CreateDevice for this parameter + UINT SDKVersion; ///< Consult the DX documentation on D3D11CreateDevice for this parameter + const DXGI_SWAP_CHAIN_DESC* pSwapChainDesc; ///< Optional swapchain description. Specify this to invoke D3D11CreateDeviceAndSwapChain instead of D3D11CreateDevice. This must be null on the WACK compliant version +}; + +#define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX11ExtensionParams +#define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version + +/// The struct to specify DX11 additional device creation parameters +struct AGSDX11ExtensionParams +{ + unsigned int uavSlot; ///< The UAV slot reserved for intrinsic support. This must match the slot defined in the HLSL, i.e. #define AmdDxExtShaderIntrinsicsUAVSlot. + /// The default slot is 7, but the caller is free to use an alternative slot. + const WCHAR* pAppName; ///< Application name + UINT appVersion; ///< Application version + const WCHAR* pEngineName; ///< Engine name + UINT engineVersion; ///< Engine version +}; + +/// The struct to hold all the returned parameters from the device creation call +struct AGSDX11ReturnedParams +{ + ID3D11Device* pDevice; ///< The newly created device + D3D_FEATURE_LEVEL FeatureLevel; ///< The feature level supported by the newly created device + ID3D11DeviceContext* pImmediateContext; ///< The newly created immediate device context + IDXGISwapChain* pSwapChain; ///< The newly created swap chain. This is only created if a valid pSwapChainDesc is supplied in AGSDX11DeviceCreationParams. This is not supported on the WACK compliant version + unsigned int extensionsSupported; ///< Bit mask that \ref agsDriverExtensionsDX11_CreateDevice will fill in to indicate which extensions are supported. See AGSDriverExtensionDX11 +}; + +/// +/// Function used to create a D3D11 device with additional AMD-specific initialization parameters. +/// +/// When using the HLSL shader extensions please note: +/// * The shader compiler should not use the D3DCOMPILE_SKIP_OPTIMIZATION option, otherwise it will not work. +/// +/// \param [in] context Pointer to a context. This is generated by \ref agsInit +/// \param [in] creationParams Pointer to the struct to specify the existing DX11 device creation parameters. +/// \param [in] extensionParams Optional pointer to the struct to specify DX11 additional device creation parameters. +/// \param [out] returnedParams Pointer to struct to hold all the returned parameters from the call. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateDevice( AGSContext* context, AGSDX11DeviceCreationParams* creationParams, AGSDX11ExtensionParams* extensionParams, AGSDX11ReturnedParams* returnedParams ); + +/// +/// Function to destroy the D3D11 device. +/// This call will also cleanup any AMD-specific driver extensions for D3D11. +/// +/// \param [in] context Pointer to a context. +/// \param [in] device Pointer to the D3D11 device. +/// \param [out] references Optional pointer to an unsigned int that will be set to the value returned from device->Release(). +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice( AGSContext* context, ID3D11Device* device, unsigned int* references ); + +/// @} + + +/// \defgroup dx11appreg App Registration +/// @{ +/// This extension allows an apllication to voluntarily register itself with the driver, providing a more robust app detection solution and avoid the issue of the driver +/// relying on exe names to match the app to a driver profile. +/// This feature is supported in Radeon Software Version 17.9.2 onwards. +/// Rules: +/// * AppName or EngineName must be set, but both are not required. Engine profiles will be used only if app specific profiles do not exist. +/// * In an engine, the EngineName should be set, so a default profile can be built. If an app modifies the engine, the AppName should be set, to allow a profile for the specific app. +/// * Version number is not mandatory, but heavily suggested. The use of which can prevent the use of profiles for incompatible versions (for instance engine versions that introduce or change features), and can help prevent older profiles from being used (and introducing new bugs) before the profile is tested with new app builds. +/// * If Version numbers are used and a new version is introduced, a new profile will not be enabled until an AMD engineer has been able to update a previous profile, or make a new one. +/// +/// The cases for profile selection are as follows: +/// +/// |Case|Profile Applied| +/// |----|---------------| +/// | App or Engine Version has profile | The profile is used. | +/// | App or Engine Version num < profile version num | The closest profile > the version number is used. | +/// | App or Engine Version num > profile version num | No profile selected/The previous method is used. | +/// | App and Engine Version have profile | The App's profile is used. | +/// | App and Engine Version num < profile version | The closest App profile > the version number is used. | +/// | App and Engine Version, no App profile found | The Engine profile will be used. | +/// | App/Engine name but no Version, has profile | The latest profile is used. | +/// | No name or version, or no profile | The previous app detection method is used. | +/// +/// As shown above, if an App name is given, and a profile is found for that app, that will be prioritized. The Engine name and profile will be used only if no app name is given, or no viable profile is found for the app name. +/// In the case that App nor Engine have a profile, the previous app detection methods will be used. If given a version number that is larger than any profile version number, no profile will be selected. +/// This is specifically to prevent cases where an update to an engine or app will cause catastrophic breaks in the profile, allowing an engineer to test the profile before clearing it for public use with the new engine/app update. +/// +/// @} + +/// \defgroup dx11misc Misc Extensions +/// API for depth bounds test, UAV overlap and prim topologies +/// @{ + +/// +/// Function used to set the primitive topology. If you are using any of the extended topology types, then this function should +/// be called to set ALL topology types. +/// +/// The Quad List extension is a convenient way to submit quads without using an index buffer. Note that this still submits two triangles at the driver level. +/// In order to use this function, AGS must already be initialized and agsDriverExtensionsDX11_Init must have been called successfully. +/// +/// The Screen Rect extension, which is only available on GCN hardware, allows the user to pass in three of the four corners of a rectangle. +/// The hardware then uses the bounding box of the vertices to rasterize the rectangle primitive (i.e. as a rectangle rather than two triangles). +/// \note Note that this will not return valid interpolated values, only valid SV_Position values. +/// \note If either the Quad List or Screen Rect extension are used, then agsDriverExtensionsDX11_IASetPrimitiveTopology should be called in place of the native DirectX11 equivalent all the time. +/// +/// \param [in] context Pointer to a context. +/// \param [in] topology The topology to set on the D3D11 device. This can be either an AGS-defined topology such as AGS_PRIMITIVE_TOPOLOGY_QUAD_LIST +/// or a standard D3D-defined topology such as D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP. +/// NB. the AGS-defined types will require casting to a D3D_PRIMITIVE_TOPOLOGY type. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_IASetPrimitiveTopology( AGSContext* context, enum D3D_PRIMITIVE_TOPOLOGY topology ); + +/// +/// Function used indicate to the driver it can overlap the subsequent batch of back-to-back dispatches. +/// When calling back-to-back draw calls or dispatch calls that write to the same UAV, the AMD DX11 driver will automatically insert a barrier to ensure there are no write after write (WAW) hazards. +/// If the app can guarantee there is no overlap between the writes between these calls, then this extension will remove those barriers allowing the work to run in parallel on the GPU. +/// +/// Usage would be as follows: +/// \code{.cpp} +/// // Disable automatic WAW syncs +/// agsDriverExtensionsDX11_BeginUAVOverlap( m_agsContext ); +/// +/// // Submit back-to-back dispatches that write to the same UAV +/// m_device->Dispatch( ... ); // First half of UAV +/// m_device->Dispatch( ... ); // Second half of UAV +/// +/// // Reenable automatic WAW syncs +/// agsDriverExtensionsDX11_EndUAVOverlap( m_agsContext ); +/// \endcode +/// +/// \param [in] context Pointer to a context. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_BeginUAVOverlap( AGSContext* context ); + +/// +/// Function used indicate to the driver it can no longer overlap the batch of back-to-back dispatches that has been submitted. +/// +/// \param [in] context Pointer to a context. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_EndUAVOverlap( AGSContext* context ); + +/// +/// Function used to set the depth bounds test extension +/// +/// \param [in] context Pointer to a context. +/// \param [in] enabled Whether to enable or disable the depth bounds testing. If disabled, the next two args are ignored. +/// \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( AGSContext* context, bool enabled, float minDepth, float maxDepth ); + +/// @} + +/// \defgroup mdi Multi Draw Indirect (MDI) +/// API for dispatching multiple instanced draw commands. +/// The multi draw indirect extensions allow multiple sets of DrawInstancedIndirect to be submitted in one API call. +/// The draw calls are issued on the GPU's command processor (CP), potentially saving the significant CPU overheads incurred by submitting the equivalent draw calls on the CPU. +/// +/// The extension allows the following code: +/// \code{.cpp} +/// // Submit n batches of DrawIndirect calls +/// for ( int i = 0; i < n; i++ ) +/// DrawIndexedInstancedIndirect( buffer, i * sizeof( cmd ) ); +/// \endcode +/// To be replaced by the following call: +/// \code{.cpp} +/// // Submit all n batches in one call +/// agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect( m_agsContext, n, buffer, 0, sizeof( cmd ) ); +/// \endcode +/// +/// The buffer used for the indirect args must be of the following formats: +/// \code{.cpp} +/// // Buffer layout for agsDriverExtensions_MultiDrawInstancedIndirect +/// struct DrawInstancedIndirectArgs +/// { +/// UINT VertexCountPerInstance; +/// UINT InstanceCount; +/// UINT StartVertexLocation; +/// UINT StartInstanceLocation; +/// }; +/// +/// // Buffer layout for agsDriverExtensions_MultiDrawIndexedInstancedIndirect +/// struct DrawIndexedInstancedIndirectArgs +/// { +/// UINT IndexCountPerInstance; +/// UINT InstanceCount; +/// UINT StartIndexLocation; +/// UINT BaseVertexLocation; +/// UINT StartInstanceLocation; +/// }; +/// \endcode +/// +/// @{ + +/// +/// Function used to submit a batch of draws via MultiDrawIndirect +/// +/// \param [in] context Pointer to a context. +/// \param [in] drawCount The number of draws. +/// \param [in] pBufferForArgs The args buffer. +/// \param [in] alignedByteOffsetForArgs The offset into the args buffer. +/// \param [in] byteStrideForArgs The per element stride of the args buffer. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirect( AGSContext* context, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); + +/// +/// Function used to submit a batch of draws via MultiDrawIndirect +/// +/// \param [in] context Pointer to a context. +/// \param [in] drawCount The number of draws. +/// \param [in] pBufferForArgs The args buffer. +/// \param [in] alignedByteOffsetForArgs The offset into the args buffer. +/// \param [in] byteStrideForArgs The per element stride of the args buffer. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect( AGSContext* context, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); + +/// +/// Function used to submit a batch of draws via MultiDrawIndirect +/// +/// \param [in] context Pointer to a context. +/// \param [in] pBufferForDrawCount The draw count buffer. +/// \param [in] alignedByteOffsetForDrawCount The offset into the draw count buffer. +/// \param [in] pBufferForArgs The args buffer. +/// \param [in] alignedByteOffsetForArgs The offset into the args buffer. +/// \param [in] byteStrideForArgs The per element stride of the args buffer. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect( AGSContext* context, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); + +/// +/// Function used to submit a batch of draws via MultiDrawIndirect +/// +/// \param [in] context Pointer to a context. +/// \param [in] pBufferForDrawCount The draw count buffer. +/// \param [in] alignedByteOffsetForDrawCount The offset into the draw count buffer. +/// \param [in] pBufferForArgs The args buffer. +/// \param [in] alignedByteOffsetForArgs The offset into the args buffer. +/// \param [in] byteStrideForArgs The per element stride of the args buffer. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect( AGSContext* context, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); + +/// @} + +/// \defgroup shadercompiler Shader Compiler Controls +/// API for controlling DirectX11 shader compilation. +/// Check support for this feature using the AGS_DX11_EXTENSION_CREATE_SHADER_CONTROLS bit. +/// Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. +/// @{ + +/// +/// This method can be used to limit the maximum number of threads the driver uses for asynchronous shader compilation. +/// Setting it to 0 will disable asynchronous compilation completely and force the shaders to be compiled "inline" on the threads that call Create*Shader. +/// +/// This method can only be called before any shaders are created and being compiled by the driver. +/// If this method is called after shaders have been created the function will return AGS_FAILURE. +/// This function only sets an upper limit.The driver may create fewer threads than allowed by this function. +/// +/// \param [in] context Pointer to a context. +/// \param [in] numberOfThreads The maximum number of threads to use. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount( AGSContext* context, unsigned int numberOfThreads ); + +/// +/// This method can be used to determine the total number of asynchronous shader compile jobs that are either +/// queued for waiting for compilation or being compiled by the driver’s asynchronous compilation threads. +/// This method can be called at any during the lifetime of the driver. +/// +/// \param [in] context Pointer to a context. +/// \param [out] numberOfJobs Pointer to the number of jobs in flight currently. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NumPendingAsyncCompileJobs( AGSContext* context, unsigned int* numberOfJobs ); + +/// +/// This method can be used to enable or disable the disk based shader cache. +/// Enabling/disabling the disk cache is not supported if is it disabled explicitly via Radeon Settings or by an app profile. +/// Calling this method under these conditions will result in AGS_FAILURE being returned. +/// It is recommended that this method be called before any shaders are created by the application and being compiled by the driver. +/// Doing so at any other time may result in the cache being left in an inconsistent state. +/// +/// \param [in] context Pointer to a context. +/// \param [in] enable Whether to enable the disk cache. 0 to disable, 1 to enable. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDiskShaderCacheEnabled( AGSContext* context, int enable ); + +/// @} + +/// \defgroup multiview Multiview +/// API for multiview broadcasting. +/// Check support for this feature using the AGS_DX11_EXTENSION_MULTIVIEW bit. +/// Supported in Radeon Software Version 16.12.1 (driver version 16.50.2001) onwards. +/// @{ + +/// +/// Function to control draw calls replication to multiple viewports and RT slices. +/// Setting any mask to 0 disables draw replication. +/// +/// \param [in] context Pointer to a context. +/// \param [in] vpMask Viewport control bit mask. +/// \param [in] rtSliceMask RT slice control bit mask. +/// \param [in] vpMaskPerRtSliceEnabled If 0, 16 lower bits of vpMask apply to all RT slices; if 1 each 16 bits of 64-bit mask apply to corresponding 4 RT slices. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetViewBroadcastMasks( AGSContext* context, unsigned long long vpMask, unsigned long long rtSliceMask, int vpMaskPerRtSliceEnabled ); + +/// +/// Function returns max number of supported clip rectangles. +/// +/// \param [in] context Pointer to a context. +/// \param [out] maxRectCount Returned max number of clip rectangles. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_GetMaxClipRects( AGSContext* context, unsigned int* maxRectCount ); + +/// +/// Function sets clip rectangles. +/// +/// \param [in] context Pointer to a context. +/// \param [in] clipRectCount Number of specified clip rectangles. Use 0 to disable clip rectangles. +/// \param [in] clipRects Array of clip rectangles. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetClipRects( AGSContext* context, unsigned int clipRectCount, const AGSClipRect* clipRects ); + +/// @} + +/// \defgroup cfxapi Explicit Crossfire API +/// API for explicit control over Crossfire +/// @{ + +/// +/// Function to create a Direct3D11 resource with the specified AFR transfer type and specified transfer engine. +/// +/// \param [in] context Pointer to a context. +/// \param [in] desc Pointer to the D3D11 resource description. +/// \param [in] initialData Optional pointer to the initializing data for the resource. +/// \param [out] buffer Returned pointer to the resource. +/// \param [in] transferType The transfer behavior. +/// \param [in] transferEngine The transfer engine to use. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateBuffer( AGSContext* context, const D3D11_BUFFER_DESC* desc, const D3D11_SUBRESOURCE_DATA* initialData, ID3D11Buffer** buffer, AGSAfrTransferType transferType, AGSAfrTransferEngine transferEngine ); + +/// +/// Function to create a Direct3D11 resource with the specified AFR transfer type and specified transfer engine. +/// +/// \param [in] context Pointer to a context. +/// \param [in] desc Pointer to the D3D11 resource description. +/// \param [in] initialData Optional pointer to the initializing data for the resource. +/// \param [out] texture1D Returned pointer to the resource. +/// \param [in] transferType The transfer behavior. +/// \param [in] transferEngine The transfer engine to use. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateTexture1D( AGSContext* context, const D3D11_TEXTURE1D_DESC* desc, const D3D11_SUBRESOURCE_DATA* initialData, ID3D11Texture1D** texture1D, AGSAfrTransferType transferType, AGSAfrTransferEngine transferEngine ); + +/// +/// Function to create a Direct3D11 resource with the specified AFR transfer type and specified transfer engine. +/// +/// \param [in] context Pointer to a context. +/// \param [in] desc Pointer to the D3D11 resource description. +/// \param [in] initialData Optional pointer to the initializing data for the resource. +/// \param [out] texture2D Returned pointer to the resource. +/// \param [in] transferType The transfer behavior. +/// \param [in] transferEngine The transfer engine to use. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateTexture2D( AGSContext* context, const D3D11_TEXTURE2D_DESC* desc, const D3D11_SUBRESOURCE_DATA* initialData, ID3D11Texture2D** texture2D, AGSAfrTransferType transferType, AGSAfrTransferEngine transferEngine ); + +/// +/// Function to create a Direct3D11 resource with the specified AFR transfer type and specified transfer engine. +/// +/// \param [in] context Pointer to a context. +/// \param [in] desc Pointer to the D3D11 resource description. +/// \param [in] initialData Optional pointer to the initializing data for the resource. +/// \param [out] texture3D Returned pointer to the resource. +/// \param [in] transferType The transfer behavior. +/// \param [in] transferEngine The transfer engine to use. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateTexture3D( AGSContext* context, const D3D11_TEXTURE3D_DESC* desc, const D3D11_SUBRESOURCE_DATA* initialData, ID3D11Texture3D** texture3D, AGSAfrTransferType transferType, AGSAfrTransferEngine transferEngine ); + +/// +/// Function to notify the driver that we have finished writing to the resource this frame. +/// This will initiate a transfer for AGS_AFR_TRANSFER_1STEP_P2P, +/// AGS_AFR_TRANSFER_2STEP_NO_BROADCAST, and AGS_AFR_TRANSFER_2STEP_WITH_BROADCAST. +/// +/// \param [in] context Pointer to a context. +/// \param [in] resource Pointer to the resource. +/// \param [in] transferRegions An array of transfer regions (can be null to specify the whole area). +/// \param [in] subresourceArray An array of subresource indices (can be null to specify all subresources). +/// \param [in] numSubresources The number of subresources in subresourceArray OR number of transferRegions. Use 0 to specify ALL subresources and one transferRegion (which may be null if specifying the whole area). +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NotifyResourceEndWrites( AGSContext* context, ID3D11Resource* resource, const D3D11_RECT* transferRegions, const unsigned int* subresourceArray, unsigned int numSubresources ); + +/// +/// This will notify the driver that the app will begin read/write access to the resource. +/// +/// \param [in] context Pointer to a context. +/// \param [in] resource Pointer to the resource. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NotifyResourceBeginAllAccess( AGSContext* context, ID3D11Resource* resource ); + +/// +/// This is used for AGS_AFR_TRANSFER_1STEP_P2P to notify when it is safe to initiate a transfer. +/// This call in frame N-(NumGpus-1) allows a 1 step P2P in frame N to start. +/// This should be called after agsDriverExtensionsDX11_NotifyResourceEndWrites. +/// +/// \param [in] context Pointer to a context. +/// \param [in] resource Pointer to the resource. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NotifyResourceEndAllAccess( AGSContext* context, ID3D11Resource* resource ); + +/// @} + +/// @} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // AMD_AGS_H From 3c43346992b4d9b5c1d64802a9de6373d4979a3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zef=20Kucia?= Date: Mon, 23 Jul 2018 19:53:20 +0200 Subject: [PATCH 0325/2777] amd_ags_x64: Make amd_ags.h usable with gcc. --- dlls/amd_ags_x64/amd_ags.h | 110 +++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 59 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h index 9c3e37e52e5..a83a1f88692 100644 --- a/dlls/amd_ags_x64/amd_ags.h +++ b/dlls/amd_ags_x64/amd_ags.h @@ -96,8 +96,7 @@ extern "C" { #endif - -#define AMD_AGS_API __declspec(dllexport) ///< AGS calling convention +#define AMD_AGS_API WINAPI // Forward declaration of D3D11 types struct IDXGIAdapter; @@ -117,8 +116,6 @@ struct D3D11_TEXTURE1D_DESC; struct D3D11_TEXTURE2D_DESC; struct D3D11_TEXTURE3D_DESC; struct D3D11_SUBRESOURCE_DATA; -struct tagRECT; -typedef tagRECT D3D11_RECT; ///< typedef this ourselves so we don't have to drag d3d11.h in // Forward declaration of D3D12 types struct ID3D12Device; @@ -126,7 +123,7 @@ struct ID3D12GraphicsCommandList; /// The return codes -enum AGSReturnCode +typedef enum AGSReturnCode { AGS_SUCCESS, ///< Successful function call AGS_FAILURE, ///< Failed to complete call for some unspecified reason @@ -136,10 +133,10 @@ enum AGSReturnCode AGS_ERROR_LEGACY_DRIVER, ///< Returned if a feature is not present in the installed driver AGS_EXTENSION_NOT_SUPPORTED, ///< Returned if the driver does not support the requested driver extension AGS_ADL_FAILURE, ///< Failure in ADL (the AMD Display Library) -}; +} AGSReturnCode; /// The DirectX11 extension support bits -enum AGSDriverExtensionDX11 +typedef enum AGSDriverExtensionDX11 { AGS_DX11_EXTENSION_QUADLIST = 1 << 0, AGS_DX11_EXTENSION_SCREENRECTLIST = 1 << 1, @@ -161,10 +158,10 @@ enum AGSDriverExtensionDX11 AGS_DX11_EXTENSION_CREATE_SHADER_CONTROLS = 1 << 17, AGS_DX11_EXTENSION_MULTIVIEW = 1 << 18, AGS_DX11_EXTENSION_APP_REGISTRATION = 1 << 19 ///< Supported in Radeon Software Version 17.9.1 onwards. -}; +} AGSDriverExtensionDX11; /// The DirectX12 extension support bits -enum AGSDriverExtensionDX12 +typedef enum AGSDriverExtensionDX12 { AGS_DX12_EXTENSION_INTRINSIC_READFIRSTLANE = 1 << 0, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. AGS_DX12_EXTENSION_INTRINSIC_READLANE = 1 << 1, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. @@ -177,48 +174,48 @@ enum AGSDriverExtensionDX12 AGS_DX12_EXTENSION_INTRINSIC_WAVE_REDUCE = 1 << 8, ///< Supported in Radeon Software Version 17.9.1 onwards. AGS_DX12_EXTENSION_INTRINSIC_WAVE_SCAN = 1 << 9, ///< Supported in Radeon Software Version 17.9.1 onwards. AGS_DX12_EXTENSION_USER_MARKERS = 1 << 10 ///< Supported in Radeon Software Version 17.9.1 onwards. -}; +} AGSDriverExtensionDX12; /// The space id for DirectX12 intrinsic support const unsigned int AGS_DX12_SHADER_INSTRINSICS_SPACE_ID = 0x7FFF0ADE; // 2147420894 /// Additional topologies supported via extensions -enum AGSPrimitiveTopology +typedef enum AGSPrimitiveTopology { AGS_PRIMITIVE_TOPOLOGY_QUADLIST = 7, AGS_PRIMITIVE_TOPOLOGY_SCREENRECTLIST = 9 -}; +} AGSPrimitiveTopology; /// The different modes to control Crossfire behavior. -enum AGSCrossfireMode +typedef enum AGSCrossfireMode { AGS_CROSSFIRE_MODE_DRIVER_AFR = 0, ///< Use the default driver-based AFR rendering AGS_CROSSFIRE_MODE_EXPLICIT_AFR, ///< Use the AGS Crossfire API functions to perform explicit AFR rendering without requiring a CF driver profile AGS_CROSSFIRE_MODE_DISABLE ///< Completely disable AFR rendering -}; +} AGSCrossfireMode; /// The Crossfire API transfer types -enum AGSAfrTransferType +typedef enum AGSAfrTransferType { AGS_AFR_TRANSFER_DEFAULT = 0, ///< Default Crossfire driver resource tracking AGS_AFR_TRANSFER_DISABLE = 1, ///< Turn off driver resource tracking AGS_AFR_TRANSFER_1STEP_P2P = 2, ///< App controlled GPU to next GPU transfer AGS_AFR_TRANSFER_2STEP_NO_BROADCAST = 3, ///< App controlled GPU to next GPU transfer using intermediate system memory AGS_AFR_TRANSFER_2STEP_WITH_BROADCAST = 4, ///< App controlled GPU to all render GPUs transfer using intermediate system memory -}; +} AGSAfrTransferType; /// The Crossfire API transfer engines -enum AGSAfrTransferEngine +typedef enum AGSAfrTransferEngine { AGS_AFR_TRANSFERENGINE_DEFAULT = 0, ///< Use default engine for Crossfire API transfers AGS_AFR_TRANSFERENGINE_3D_ENGINE = 1, ///< Use 3D engine for Crossfire API transfers AGS_AFR_TRANSFERENGINE_COPY_ENGINE = 2, ///< Use Copy engine for Crossfire API transfers -}; +} AGSAfrTransferEngine; /// The display flags describing various properties of the display. -enum AGSDisplayFlags +typedef enum AGSDisplayFlags { AGS_DISPLAYFLAG_PRIMARY_DISPLAY = 1 << 0, ///< Whether this display is marked as the primary display. Not set on the WACK version. AGS_DISPLAYFLAG_HDR10 = 1 << 1, ///< HDR10 is supported on this display @@ -228,35 +225,33 @@ enum AGSDisplayFlags AGS_DISPLAYFLAG_EYEFINITY_IN_GROUP = 1 << 5, ///< The display is part of the Eyefinity group AGS_DISPLAYFLAG_EYEFINITY_PREFERRED_DISPLAY = 1 << 6, ///< The display is the preferred display in the Eyefinity group for displaying the UI AGS_DISPLAYFLAG_EYEFINITY_IN_PORTRAIT_MODE = 1 << 7, ///< The display is in the Eyefinity group but in portrait mode -}; +} AGSDisplayFlags; -struct AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInit +typedef struct AGSContext AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInit /// The rectangle struct used by AGS. -struct AGSRect +typedef struct AGSRect { int offsetX; ///< Offset on X axis int offsetY; ///< Offset on Y axis int width; ///< Width of rectangle int height; ///< Height of rectangle -}; +} AGSRect; /// The clip rectangle struct used by \ref agsDriverExtensionsDX11_SetClipRects -struct AGSClipRect +typedef struct AGSClipRect { /// The inclusion mode for the rect - enum Mode + enum { ClipRectIncluded = 0, ///< Include the rect ClipRectExcluded = 1 ///< Exclude the rect - }; - - Mode mode; ///< Include/exclude rect region + } mode; ; ///< Include/exclude rect region AGSRect rect; ///< The rect to include/exclude -}; +} AGSClipRect; /// The display info struct used to describe a display enumerated by AGS -struct AGSDisplayInfo +typedef struct AGSDisplayInfo { char name[ 256 ]; ///< The name of the display char displayDeviceName[ 32 ]; ///< The display device name, i.e. DISPLAY_DEVICE::DeviceName @@ -296,19 +291,19 @@ struct AGSDisplayInfo int logicalDisplayIndex; ///< The internally used index of this display int adlAdapterIndex; ///< The internally used ADL adapter index -}; +} AGSDisplayInfo; -/// The device info struct used to describe a physical GPU enumerated by AGS -struct AGSDeviceInfo +/// The architecture version +typedef enum ArchitectureVersion { - /// The architecture version - enum ArchitectureVersion - { - ArchitectureVersion_Unknown, ///< Unknown architecture, potentially from another IHV. Check AGSDeviceInfo::vendorId - ArchitectureVersion_PreGCN, ///< AMD architecture, pre-GCN - ArchitectureVersion_GCN ///< AMD GCN architecture - }; + ArchitectureVersion_Unknown, ///< Unknown architecture, potentially from another IHV. Check \ref AGSDeviceInfo::vendorId + ArchitectureVersion_PreGCN, ///< AMD architecture, pre-GCN + ArchitectureVersion_GCN ///< AMD GCN architecture +} ArchitectureVersion; +/// The device info struct used to describe a physical GPU enumerated by AGS +typedef struct AGSDeviceInfo +{ ArchitectureVersion architectureVersion; ///< Set to Unknown if not AMD hardware const char* adapterString; ///< The adapter name string int vendorId; ///< The vendor id @@ -334,7 +329,7 @@ struct AGSDeviceInfo int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. int adlAdapterIndex; ///< Internally used index into the ADL list of adapters -}; +} AGSDeviceInfo; /// \defgroup general General API functions /// API for initialization, cleanup, HDR display modes and Crossfire GPU count @@ -343,16 +338,15 @@ struct AGSDeviceInfo typedef void* (__stdcall *AGS_ALLOC_CALLBACK)( int allocationSize ); ///< AGS user defined allocation prototype typedef void (__stdcall *AGS_FREE_CALLBACK)( void* allocationPtr ); ///< AGS user defined free prototype - /// The configuration options that can be passed in to \ref agsInit -struct AGSConfiguration +/// The configuration options that can be passed in to \ref agsInit +typedef struct AGSConfiguration { AGS_ALLOC_CALLBACK allocCallback; ///< Optional memory allocation callback. If not supplied, malloc() is used AGS_FREE_CALLBACK freeCallback; ///< Optional memory freeing callback. If not supplied, free() is used - AGSCrossfireMode crossfireMode; ///< Desired Crossfire mode -}; +} AGSConfiguration; /// The top level GPU information returned from \ref agsInit -struct AGSGPUInfo +typedef struct AGSGPUInfo { int agsVersionMajor; ///< Major field of Major.Minor.Patch AGS version number int agsVersionMinor; ///< Minor field of Major.Minor.Patch AGS version number @@ -364,22 +358,20 @@ struct AGSGPUInfo int numDevices; ///< Number of GPUs in the system AGSDeviceInfo* devices; ///< List of GPUs in the system -}; +} AGSGPUInfo; /// The struct to specify the display settings to the driver. -struct AGSDisplaySettings +typedef struct AGSDisplaySettings { /// The display mode - enum Mode + enum { Mode_SDR, ///< SDR mode Mode_HDR10_PQ, ///< HDR10 PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. Mode_HDR10_scRGB, ///< HDR10 scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. Mode_Freesync2_scRGB, ///< Freesync2 scRGB, requiring an FP16 swapchain. Values in the range of 0.0 to 125.0 where 125.0 == AGSDisplayInfo::maxLuminance. Mode_DolbyVision ///< Dolby Vision, requiring an 8888 UNORM swapchain - }; - - Mode mode; ///< The display mode to set the display into + } mode; ///< The display mode to set the display into double chromaticityRedX; ///< Red display primary X coord double chromaticityRedY; ///< Red display primary Y coord @@ -398,7 +390,7 @@ struct AGSDisplaySettings double maxContentLightLevel; ///< The maximum content light level in nits (MaxCLL) double maxFrameAverageLightLevel; ///< The maximum frame average light level in nits (MaxFALL) -}; +} AGSDisplaySettings; /// /// Function used to initialize the AGS library. @@ -526,7 +518,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_SetMarker( AGSContext* context /// @{ /// The struct to specify the existing DX11 device creation parameters -struct AGSDX11DeviceCreationParams +typedef struct AGSDX11DeviceCreationParams { IDXGIAdapter* pAdapter; ///< Consult the DX documentation on D3D11CreateDevice for this parameter D3D_DRIVER_TYPE DriverType; ///< Consult the DX documentation on D3D11CreateDevice for this parameter @@ -536,13 +528,13 @@ struct AGSDX11DeviceCreationParams UINT FeatureLevels; ///< Consult the DX documentation on D3D11CreateDevice for this parameter UINT SDKVersion; ///< Consult the DX documentation on D3D11CreateDevice for this parameter const DXGI_SWAP_CHAIN_DESC* pSwapChainDesc; ///< Optional swapchain description. Specify this to invoke D3D11CreateDeviceAndSwapChain instead of D3D11CreateDevice. This must be null on the WACK compliant version -}; +} AGSDX11DeviceCreationParams; #define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX11ExtensionParams #define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version /// The struct to specify DX11 additional device creation parameters -struct AGSDX11ExtensionParams +typedef struct AGSDX11ExtensionParams { unsigned int uavSlot; ///< The UAV slot reserved for intrinsic support. This must match the slot defined in the HLSL, i.e. #define AmdDxExtShaderIntrinsicsUAVSlot. /// The default slot is 7, but the caller is free to use an alternative slot. @@ -550,17 +542,17 @@ struct AGSDX11ExtensionParams UINT appVersion; ///< Application version const WCHAR* pEngineName; ///< Engine name UINT engineVersion; ///< Engine version -}; +} AGSDX11ExtensionParams; /// The struct to hold all the returned parameters from the device creation call -struct AGSDX11ReturnedParams +typedef struct AGSDX11ReturnedParams { ID3D11Device* pDevice; ///< The newly created device D3D_FEATURE_LEVEL FeatureLevel; ///< The feature level supported by the newly created device ID3D11DeviceContext* pImmediateContext; ///< The newly created immediate device context IDXGISwapChain* pSwapChain; ///< The newly created swap chain. This is only created if a valid pSwapChainDesc is supplied in AGSDX11DeviceCreationParams. This is not supported on the WACK compliant version unsigned int extensionsSupported; ///< Bit mask that \ref agsDriverExtensionsDX11_CreateDevice will fill in to indicate which extensions are supported. See AGSDriverExtensionDX11 -}; +} AGSDX11ReturnedParams; /// /// Function used to create a D3D11 device with additional AMD-specific initialization parameters. From f59ea7ee1fbdbd880e4daff15be5bb7b241db1f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zef=20Kucia?= Date: Mon, 23 Jul 2018 19:53:20 +0200 Subject: [PATCH 0326/2777] amd_ags_x64: Add dll. This is needed to avoid Wolfenstein 2 showing a driver warning dialog on AMD hardware. --- configure.ac | 1 + dlls/amd_ags_x64/Makefile.in | 7 + dlls/amd_ags_x64/amd_ags_x64.spec | 29 +++++ dlls/amd_ags_x64/amd_ags_x64_main.c | 193 ++++++++++++++++++++++++++++ 4 files changed, 230 insertions(+) create mode 100644 dlls/amd_ags_x64/Makefile.in create mode 100644 dlls/amd_ags_x64/amd_ags_x64.spec create mode 100644 dlls/amd_ags_x64/amd_ags_x64_main.c diff --git a/configure.ac b/configure.ac index 1babf104454..e308f8a6a7a 100644 --- a/configure.ac +++ b/configure.ac @@ -2376,6 +2376,7 @@ WINE_CONFIG_MAKEFILE(dlls/advapi32/tests) WINE_CONFIG_MAKEFILE(dlls/advpack) WINE_CONFIG_MAKEFILE(dlls/advpack/tests) WINE_CONFIG_MAKEFILE(dlls/amsi) +WINE_CONFIG_MAKEFILE(dlls/amd_ags_x64) WINE_CONFIG_MAKEFILE(dlls/amstream) WINE_CONFIG_MAKEFILE(dlls/amstream/tests) WINE_CONFIG_MAKEFILE(dlls/apisetschema) diff --git a/dlls/amd_ags_x64/Makefile.in b/dlls/amd_ags_x64/Makefile.in new file mode 100644 index 00000000000..803f06babb1 --- /dev/null +++ b/dlls/amd_ags_x64/Makefile.in @@ -0,0 +1,7 @@ +EXTRADEFS = -DWINE_NO_LONG_TYPES +MODULE = amd_ags_x64.dll +IMPORTS = vulkan-1 +IMPORTLIB = amd_ags_x64 + +C_SRCS = \ + amd_ags_x64_main.c diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec new file mode 100644 index 00000000000..b4da6136a64 --- /dev/null +++ b/dlls/amd_ags_x64/amd_ags_x64.spec @@ -0,0 +1,29 @@ +1 stdcall agsDeInit(ptr) +2 stub agsDriverExtensionsDX11_BeginUAVOverlap +3 stub agsDriverExtensionsDX11_CreateBuffer +4 stub agsDriverExtensionsDX11_CreateTexture1D +5 stub agsDriverExtensionsDX11_CreateTexture2D +6 stub agsDriverExtensionsDX11_CreateTexture3D +7 stub agsDriverExtensionsDX11_DeInit +8 stub agsDriverExtensionsDX11_EndUAVOverlap +9 stub agsDriverExtensionsDX11_GetMaxClipRects +10 stub agsDriverExtensionsDX11_IASetPrimitiveTopology +11 stub agsDriverExtensionsDX11_Init +12 stub agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect +13 stub agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect +14 stub agsDriverExtensionsDX11_MultiDrawInstancedIndirect +15 stub agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect +16 stub agsDriverExtensionsDX11_NotifyResourceBeginAllAccess +17 stub agsDriverExtensionsDX11_NotifyResourceEndAllAccess +18 stub agsDriverExtensionsDX11_NotifyResourceEndWrites +19 stub agsDriverExtensionsDX11_NumPendingAsyncCompileJobs +20 stub agsDriverExtensionsDX11_SetClipRects +21 stub agsDriverExtensionsDX11_SetDepthBounds +22 stub agsDriverExtensionsDX11_SetDiskShaderCacheEnabled +23 stub agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount +24 stub agsDriverExtensionsDX11_SetViewBroadcastMasks +25 stub agsDriverExtensionsDX12_DeInit +26 stub agsDriverExtensionsDX12_Init +27 stub agsGetCrossfireGPUCount +28 stdcall agsInit(ptr ptr ptr) +29 stub agsSetDisplayMode diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c new file mode 100644 index 00000000000..382447089bc --- /dev/null +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -0,0 +1,193 @@ +#include "config.h" + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wine/debug.h" +#include "wine/heap.h" + +#include "wine/vulkan.h" + +#include "d3d11.h" +#include "d3d12.h" + +#include "amd_ags.h" + +WINE_DEFAULT_DEBUG_CHANNEL(amd_ags); + +struct AGSContext +{ + unsigned int device_count; + AGSDeviceInfo *devices; + VkPhysicalDeviceProperties *properties; +}; + +static AGSReturnCode vk_get_physical_device_properties(unsigned int *out_count, + VkPhysicalDeviceProperties **out) +{ + VkPhysicalDeviceProperties *properties = NULL; + VkPhysicalDevice *vk_physical_devices = NULL; + VkInstance vk_instance = VK_NULL_HANDLE; + VkInstanceCreateInfo create_info; + AGSReturnCode ret = AGS_SUCCESS; + uint32_t count, i; + VkResult vr; + + *out = NULL; + *out_count = 0; + + memset(&create_info, 0, sizeof(create_info)); + create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + if ((vr = vkCreateInstance(&create_info, NULL, &vk_instance) < 0)) + { + WARN("Failed to create Vulkan instance, vr %d.\n", vr); + goto done; + } + + if ((vr = vkEnumeratePhysicalDevices(vk_instance, &count, NULL)) < 0) + { + WARN("Failed to enumerate devices, vr %d.\n", vr); + goto done; + } + + if (!(vk_physical_devices = heap_calloc(count, sizeof(*vk_physical_devices)))) + { + WARN("Failed to allocate memory.\n"); + ret = AGS_OUT_OF_MEMORY; + goto done; + } + + if ((vr = vkEnumeratePhysicalDevices(vk_instance, &count, vk_physical_devices)) < 0) + { + WARN("Failed to enumerate devices, vr %d.\n", vr); + goto done; + } + + if (!(properties = heap_calloc(count, sizeof(*properties)))) + { + WARN("Failed to allocate memory.\n"); + ret = AGS_OUT_OF_MEMORY; + goto done; + } + + for (i = 0; i < count; ++i) + vkGetPhysicalDeviceProperties(vk_physical_devices[i], &properties[i]); + + *out_count = count; + *out = properties; + +done: + heap_free(vk_physical_devices); + if (vk_instance) + vkDestroyInstance(vk_instance, NULL); + return ret; +} + +static AGSReturnCode init_ags_context(AGSContext *context) +{ + AGSReturnCode ret; + unsigned int i; + + context->device_count = 0; + context->devices = NULL; + context->properties = NULL; + + ret = vk_get_physical_device_properties(&context->device_count, &context->properties); + if (ret != AGS_SUCCESS || !context->device_count) + return ret; + + if (!(context->devices = heap_calloc(context->device_count, sizeof(*context->devices)))) + { + WARN("Failed to allocate memory.\n"); + heap_free(context->properties); + return AGS_OUT_OF_MEMORY; + } + + for (i = 0; i < context->device_count; ++i) + { + const VkPhysicalDeviceProperties *vk_properties = &context->properties[i]; + AGSDeviceInfo *device = &context->devices[i]; + + device->adapterString = vk_properties->deviceName; + device->vendorId = vk_properties->vendorID; + device->deviceId = vk_properties->deviceID; + + if (device->vendorId == 0x1002) + device->architectureVersion = ArchitectureVersion_GCN; + + if (!i) + device->isPrimaryDevice = 1; + } + + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *config, AGSGPUInfo *gpu_info) +{ + struct AGSContext *object; + AGSReturnCode ret; + + TRACE("context %p, config %p, gpu_info %p.\n", context, config, gpu_info); + + if (!context || !gpu_info) + return AGS_INVALID_ARGS; + + if (config) + FIXME("Ignoring config %p.\n", config); + + if (!(object = heap_alloc(sizeof(*object)))) + return AGS_OUT_OF_MEMORY; + + if ((ret = init_ags_context(object)) != AGS_SUCCESS) + { + heap_free(object); + return ret; + } + + memset(gpu_info, 0, sizeof(*gpu_info)); + gpu_info->agsVersionMajor = AMD_AGS_VERSION_MAJOR; + gpu_info->agsVersionMinor = AMD_AGS_VERSION_MINOR; + gpu_info->agsVersionPatch = AMD_AGS_VERSION_PATCH; + gpu_info->driverVersion = "18.10.16-180516a-328911C-RadeonSoftwareAdrenalin"; + gpu_info->radeonSoftwareVersion = "18.5.1"; + gpu_info->numDevices = object->device_count; + gpu_info->devices = object->devices; + + TRACE("Created context %p.\n", object); + + *context = object; + + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDeInit(AGSContext *context) +{ + TRACE("context %p.\n", context); + + if (context) + { + heap_free(context->properties); + heap_free(context->devices); + heap_free(context); + } + + return AGS_SUCCESS; +} + +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) +{ + TRACE("%p, %u, %p.\n", instance, reason, reserved); + + switch (reason) + { + case DLL_WINE_PREATTACH: + return FALSE; /* Prefer native. */ + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(instance); + break; + } + + return TRUE; +} From f7c67c5d83e53ef5d9db0560137fada3bfa8b5aa Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Tue, 1 Oct 2019 09:28:29 +0800 Subject: [PATCH 0327/2777] amd_ags_x64: Add agsGetCrossfireGPUCount stub. Signed-off-by: Zhiyi Zhang --- dlls/amd_ags_x64/amd_ags_x64.spec | 2 +- dlls/amd_ags_x64/amd_ags_x64_main.c | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec index b4da6136a64..a302d2fc657 100644 --- a/dlls/amd_ags_x64/amd_ags_x64.spec +++ b/dlls/amd_ags_x64/amd_ags_x64.spec @@ -24,6 +24,6 @@ 24 stub agsDriverExtensionsDX11_SetViewBroadcastMasks 25 stub agsDriverExtensionsDX12_DeInit 26 stub agsDriverExtensionsDX12_Init -27 stub agsGetCrossfireGPUCount +27 stdcall agsGetCrossfireGPUCount(ptr ptr) 28 stdcall agsInit(ptr ptr ptr) 29 stub agsSetDisplayMode diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 382447089bc..26b39991525 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -176,6 +176,17 @@ AGSReturnCode WINAPI agsDeInit(AGSContext *context) return AGS_SUCCESS; } +AGSReturnCode WINAPI agsGetCrossfireGPUCount(AGSContext *context, int *gpu_count) +{ + TRACE("context %p gpu_count %p stub!\n", context, gpu_count); + + if (!context || !gpu_count) + return AGS_INVALID_ARGS; + + *gpu_count = 1; + return AGS_SUCCESS; +} + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { TRACE("%p, %u, %p.\n", instance, reason, reserved); From 51f8d68563699b50dcd0358e4080d1addb5aa50a Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Thu, 11 Jun 2020 15:39:32 -0700 Subject: [PATCH 0328/2777] amd_ags_x64: Build with msvcrt. Signed-off-by: Brendan Shanks --- dlls/amd_ags_x64/Makefile.in | 2 ++ dlls/amd_ags_x64/amd_ags_x64_main.c | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/dlls/amd_ags_x64/Makefile.in b/dlls/amd_ags_x64/Makefile.in index 803f06babb1..936d95986b6 100644 --- a/dlls/amd_ags_x64/Makefile.in +++ b/dlls/amd_ags_x64/Makefile.in @@ -3,5 +3,7 @@ MODULE = amd_ags_x64.dll IMPORTS = vulkan-1 IMPORTLIB = amd_ags_x64 +EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native + C_SRCS = \ amd_ags_x64_main.c diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 26b39991525..e339d7b7d2b 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -1,5 +1,3 @@ -#include "config.h" - #include #include @@ -193,8 +191,6 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) switch (reason) { - case DLL_WINE_PREATTACH: - return FALSE; /* Prefer native. */ case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(instance); break; From 07a63fe4423172dc43651ef18e835386cbf74cf1 Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Thu, 11 Jun 2020 17:33:56 -0700 Subject: [PATCH 0329/2777] amd_ags_x64: Update to 5.2.0. --- dlls/amd_ags_x64/amd_ags.h | 577 +++++++++++++++++++++++----- dlls/amd_ags_x64/amd_ags_x64_main.c | 60 ++- 2 files changed, 531 insertions(+), 106 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h index a83a1f88692..b647f912aa7 100644 --- a/dlls/amd_ags_x64/amd_ags.h +++ b/dlls/amd_ags_x64/amd_ags.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2018 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -24,7 +24,7 @@ /// \mainpage /// AGS Library Overview /// -------------------- -/// This document provides an overview of the AGS (AMD GPU Services) library. The AGS library provides software developers with the ability to query +/// This document provides an overview of the AGS (AMD GPU Services) library. The AGS library provides software developers with the ability to query /// AMD GPU software and hardware state information that is not normally available through standard operating systems or graphic APIs. /// /// The latest version of the API is publicly hosted here: https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK/. @@ -33,6 +33,15 @@ /// Online documentation is publicly hosted here: http://gpuopen-librariesandsdks.github.io/ags/ /// \endinternal /// +/// What's new in AGS 5.2.0 since version 5.1 +/// --------------------------------------- +/// AGS 5.2 includes the following updates: +/// * DX12 app registration API +/// * DX11 breadcrumb marker API for tracking down GPU hangs:\ref agsDriverExtensionsDX11_WriteBreadcrumb +/// * DX12 extensions now require the creation of the device via \ref agsDriverExtensionsDX12_CreateDevice +/// * agsGetCrossfireGPUCount has been removed in favor of retrieving the value from \ref agsDriverExtensionsDX11_CreateDevice +/// * API change that fixes a reference leak in \ref agsDriverExtensionsDX11_DestroyDevice +/// /// What's new in AGS 5.1.1 since version 5.0.6 /// --------------------------------------- /// AGS 5.1.1 includes the following updates: @@ -50,7 +59,7 @@ /// /// What's new in AGS 5.x since version 4.x /// --------------------------------------- -/// Version 5.x is a major overhaul of the library designed to provide a much clearer view of the GPUs in the system and the displays attached to them. +/// Version 5.x is a major overhaul of the library designed to provide a much clearer view of the GPUs in the system and the displays attached to them. /// It also exposes the ability to query each display for HDR capabilities and put those HDR capable displays into various HDR modes. /// Some functions such as agsGetGPUMemorySize and agsGetEyefinityConfigInfo have been removed in favor of including this information in the device & display enumeration. /// Features include: @@ -69,8 +78,8 @@ /// * AGSSample /// * CrossfireSample /// * EyefinitySample -/// The AGSSample application is the simplest of the three examples and demonstrates the code required to initialize AGS and use it to query the GPU and Eyefinity state. -/// The CrossfireSample application demonstrates the use of the new API to transfer resources on GPUs in Crossfire mode. Lastly, the EyefinitySample application provides a more +/// The AGSSample application is the simplest of the three examples and demonstrates the code required to initialize AGS and use it to query the GPU and Eyefinity state. +/// The CrossfireSample application demonstrates the use of the new API to transfer resources on GPUs in Crossfire mode. Lastly, the EyefinitySample application provides a more /// extensive example of Eyefinity setup than the basic example provided in AGSSample. /// There are other samples on Github that demonstrate the DirectX shader extensions, such as the Barycentrics11 and Barycentrics12 samples. /// @@ -80,17 +89,16 @@ /// * Include the amd_ags.h header file from your source code. /// * Include the AGS hlsl files if you are using the shader intrinsics. /// * Declare a pointer to an AGSContext and make this available for all subsequent calls to AGS. -/// * On game initialization, call agsInit() passing in the address of the context. On success, this function will return a valid context pointer. -/// * The agsInit() function should be called before the D3D device is created if the Crossfire mode is specified. +/// * On game initialization, call \ref agsInit passing in the address of the context. On success, this function will return a valid context pointer. /// -/// Don't forget to cleanup AGS by calling agsDeInit() when the app exits, after the device has been destroyed. +/// Don't forget to cleanup AGS by calling \ref agsDeInit when the app exits, after the device has been destroyed. #ifndef AMD_AGS_H #define AMD_AGS_H #define AMD_AGS_VERSION_MAJOR 5 ///< AGS major version -#define AMD_AGS_VERSION_MINOR 1 ///< AGS minor version -#define AMD_AGS_VERSION_PATCH 1 ///< AGS patch version +#define AMD_AGS_VERSION_MINOR 2 ///< AGS minor version +#define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version #ifdef __cplusplus extern "C" { @@ -138,42 +146,44 @@ typedef enum AGSReturnCode /// The DirectX11 extension support bits typedef enum AGSDriverExtensionDX11 { - AGS_DX11_EXTENSION_QUADLIST = 1 << 0, - AGS_DX11_EXTENSION_SCREENRECTLIST = 1 << 1, - AGS_DX11_EXTENSION_UAV_OVERLAP = 1 << 2, - AGS_DX11_EXTENSION_DEPTH_BOUNDS_TEST = 1 << 3, - AGS_DX11_EXTENSION_MULTIDRAWINDIRECT = 1 << 4, - AGS_DX11_EXTENSION_MULTIDRAWINDIRECT_COUNTINDIRECT = 1 << 5, - AGS_DX11_EXTENSION_CROSSFIRE_API = 1 << 6, - AGS_DX11_EXTENSION_INTRINSIC_READFIRSTLANE = 1 << 7, - AGS_DX11_EXTENSION_INTRINSIC_READLANE = 1 << 8, - AGS_DX11_EXTENSION_INTRINSIC_LANEID = 1 << 9, - AGS_DX11_EXTENSION_INTRINSIC_SWIZZLE = 1 << 10, - AGS_DX11_EXTENSION_INTRINSIC_BALLOT = 1 << 11, - AGS_DX11_EXTENSION_INTRINSIC_MBCOUNT = 1 << 12, - AGS_DX11_EXTENSION_INTRINSIC_COMPARE3 = 1 << 13, - AGS_DX11_EXTENSION_INTRINSIC_BARYCENTRICS = 1 << 14, + AGS_DX11_EXTENSION_QUADLIST = 1 << 0, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_SCREENRECTLIST = 1 << 1, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_UAV_OVERLAP = 1 << 2, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_DEPTH_BOUNDS_TEST = 1 << 3, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_MULTIDRAWINDIRECT = 1 << 4, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_MULTIDRAWINDIRECT_COUNTINDIRECT = 1 << 5, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_CROSSFIRE_API = 1 << 6, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_READFIRSTLANE = 1 << 7, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_READLANE = 1 << 8, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_LANEID = 1 << 9, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_SWIZZLE = 1 << 10, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_BALLOT = 1 << 11, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_MBCOUNT = 1 << 12, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_MED3 = 1 << 13, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_BARYCENTRICS = 1 << 14, ///< Supported in Radeon Software Version 16.9.2 onwards. AGS_DX11_EXTENSION_INTRINSIC_WAVE_REDUCE = 1 << 15, ///< Supported in Radeon Software Version 17.9.1 onwards. AGS_DX11_EXTENSION_INTRINSIC_WAVE_SCAN = 1 << 16, ///< Supported in Radeon Software Version 17.9.1 onwards. - AGS_DX11_EXTENSION_CREATE_SHADER_CONTROLS = 1 << 17, - AGS_DX11_EXTENSION_MULTIVIEW = 1 << 18, - AGS_DX11_EXTENSION_APP_REGISTRATION = 1 << 19 ///< Supported in Radeon Software Version 17.9.1 onwards. + AGS_DX11_EXTENSION_CREATE_SHADER_CONTROLS = 1 << 17, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX11_EXTENSION_MULTIVIEW = 1 << 18, ///< Supported in Radeon Software Version 16.12.1 onwards. + AGS_DX11_EXTENSION_APP_REGISTRATION = 1 << 19, ///< Supported in Radeon Software Version 17.9.1 onwards. + AGS_DX11_EXTENSION_BREADCRUMB_MARKERS = 1 << 20, ///< Supported in Radeon Software Version 17.11.1 onwards. } AGSDriverExtensionDX11; /// The DirectX12 extension support bits typedef enum AGSDriverExtensionDX12 { - AGS_DX12_EXTENSION_INTRINSIC_READFIRSTLANE = 1 << 0, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. - AGS_DX12_EXTENSION_INTRINSIC_READLANE = 1 << 1, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. - AGS_DX12_EXTENSION_INTRINSIC_LANEID = 1 << 2, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. - AGS_DX12_EXTENSION_INTRINSIC_SWIZZLE = 1 << 3, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. - AGS_DX12_EXTENSION_INTRINSIC_BALLOT = 1 << 4, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. - AGS_DX12_EXTENSION_INTRINSIC_MBCOUNT = 1 << 5, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. - AGS_DX12_EXTENSION_INTRINSIC_COMPARE3 = 1 << 6, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. - AGS_DX12_EXTENSION_INTRINSIC_BARYCENTRICS = 1 << 7, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. + AGS_DX12_EXTENSION_INTRINSIC_READFIRSTLANE = 1 << 0, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_READLANE = 1 << 1, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_LANEID = 1 << 2, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_SWIZZLE = 1 << 3, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_BALLOT = 1 << 4, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_MBCOUNT = 1 << 5, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_MED3 = 1 << 6, ///< Supported in Radeon Software Version 16.9.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_BARYCENTRICS = 1 << 7, ///< Supported in Radeon Software Version 16.9.2 onwards. AGS_DX12_EXTENSION_INTRINSIC_WAVE_REDUCE = 1 << 8, ///< Supported in Radeon Software Version 17.9.1 onwards. AGS_DX12_EXTENSION_INTRINSIC_WAVE_SCAN = 1 << 9, ///< Supported in Radeon Software Version 17.9.1 onwards. - AGS_DX12_EXTENSION_USER_MARKERS = 1 << 10 ///< Supported in Radeon Software Version 17.9.1 onwards. + AGS_DX12_EXTENSION_USER_MARKERS = 1 << 10, ///< Supported in Radeon Software Version 17.9.1 onwards. + AGS_DX12_EXTENSION_APP_REGISTRATION = 1 << 11 ///< Supported in Radeon Software Version 17.9.1 onwards. } AGSDriverExtensionDX12; /// The space id for DirectX12 intrinsic support @@ -183,37 +193,10 @@ const unsigned int AGS_DX12_SHADER_INSTRINSICS_SPACE_ID = 0x7FFF0ADE; // 2147420 /// Additional topologies supported via extensions typedef enum AGSPrimitiveTopology { - AGS_PRIMITIVE_TOPOLOGY_QUADLIST = 7, - AGS_PRIMITIVE_TOPOLOGY_SCREENRECTLIST = 9 + AGS_PRIMITIVE_TOPOLOGY_QUADLIST = 7, ///< Quad list + AGS_PRIMITIVE_TOPOLOGY_SCREENRECTLIST = 9 ///< Screen rect list } AGSPrimitiveTopology; -/// The different modes to control Crossfire behavior. -typedef enum AGSCrossfireMode -{ - AGS_CROSSFIRE_MODE_DRIVER_AFR = 0, ///< Use the default driver-based AFR rendering - AGS_CROSSFIRE_MODE_EXPLICIT_AFR, ///< Use the AGS Crossfire API functions to perform explicit AFR rendering without requiring a CF driver profile - AGS_CROSSFIRE_MODE_DISABLE ///< Completely disable AFR rendering -} AGSCrossfireMode; - - -/// The Crossfire API transfer types -typedef enum AGSAfrTransferType -{ - AGS_AFR_TRANSFER_DEFAULT = 0, ///< Default Crossfire driver resource tracking - AGS_AFR_TRANSFER_DISABLE = 1, ///< Turn off driver resource tracking - AGS_AFR_TRANSFER_1STEP_P2P = 2, ///< App controlled GPU to next GPU transfer - AGS_AFR_TRANSFER_2STEP_NO_BROADCAST = 3, ///< App controlled GPU to next GPU transfer using intermediate system memory - AGS_AFR_TRANSFER_2STEP_WITH_BROADCAST = 4, ///< App controlled GPU to all render GPUs transfer using intermediate system memory -} AGSAfrTransferType; - -/// The Crossfire API transfer engines -typedef enum AGSAfrTransferEngine -{ - AGS_AFR_TRANSFERENGINE_DEFAULT = 0, ///< Use default engine for Crossfire API transfers - AGS_AFR_TRANSFERENGINE_3D_ENGINE = 1, ///< Use 3D engine for Crossfire API transfers - AGS_AFR_TRANSFERENGINE_COPY_ENGINE = 2, ///< Use Copy engine for Crossfire API transfers -} AGSAfrTransferEngine; - /// The display flags describing various properties of the display. typedef enum AGSDisplayFlags { @@ -227,6 +210,13 @@ typedef enum AGSDisplayFlags AGS_DISPLAYFLAG_EYEFINITY_IN_PORTRAIT_MODE = 1 << 7, ///< The display is in the Eyefinity group but in portrait mode } AGSDisplayFlags; +/// The display settings flags. +typedef enum AGSDisplaySettingsFlags +{ + AGS_DISPLAYSETTINGSFLAG_DISABLE_LOCAL_DIMMING = 1 << 0, ///< Disables local dimming if possible +} AGSDisplaySettingsFlags; + + typedef struct AGSContext AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInit /// The rectangle struct used by AGS. @@ -302,7 +292,7 @@ typedef enum ArchitectureVersion } ArchitectureVersion; /// The device info struct used to describe a physical GPU enumerated by AGS -typedef struct AGSDeviceInfo +typedef struct AGSDeviceInfo_511 { ArchitectureVersion architectureVersion; ///< Set to Unknown if not AMD hardware const char* adapterString; ///< The adapter name string @@ -329,20 +319,71 @@ typedef struct AGSDeviceInfo int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. int adlAdapterIndex; ///< Internally used index into the ADL list of adapters +} AGSDeviceInfo_511; + +/// The device info struct used to describe a physical GPU enumerated by AGS +typedef struct AGSDeviceInfo_520 +{ + const char* adapterString; ///< The adapter name string + ArchitectureVersion architectureVersion; ///< Set to Unknown if not AMD hardware + int vendorId; ///< The vendor id + int deviceId; ///< The device id + int revisionId; ///< The revision id + + int numCUs; ///< Number of compute units. Zero if not GCN onwards + int numROPs; ///< Number of ROPs + int coreClock; ///< Core clock speed at 100% power in MHz + int memoryClock; ///< Memory clock speed at 100% power in MHz + int memoryBandwidth; ///< Memory bandwidth in MB/s + float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD + + int isPrimaryDevice; ///< Whether or not this is the primary adapter in the system. Not set on the WACK version. + long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. + + int numDisplays; ///< The number of active displays found to be attached to this adapter. + AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. + + int eyefinityEnabled; ///< Indicates if Eyefinity is active + int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. + int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. + int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. + + int adlAdapterIndex; ///< Internally used index into the ADL list of adapters +} AGSDeviceInfo_520; + +typedef union AGSDeviceInfo +{ + AGSDeviceInfo_511 agsDeviceInfo511; + AGSDeviceInfo_520 agsDeviceInfo520; } AGSDeviceInfo; /// \defgroup general General API functions /// API for initialization, cleanup, HDR display modes and Crossfire GPU count /// @{ -typedef void* (__stdcall *AGS_ALLOC_CALLBACK)( int allocationSize ); ///< AGS user defined allocation prototype -typedef void (__stdcall *AGS_FREE_CALLBACK)( void* allocationPtr ); ///< AGS user defined free prototype +typedef void* (__stdcall *AGS_ALLOC_CALLBACK_511)( int allocationSize ); ///< AGS user defined allocation prototype +typedef void* (__stdcall *AGS_ALLOC_CALLBACK)( size_t allocationSize ); ///< AGS user defined allocation prototype +typedef void (__stdcall *AGS_FREE_CALLBACK)( void* allocationPtr ); ///< AGS user defined free prototype /// The configuration options that can be passed in to \ref agsInit -typedef struct AGSConfiguration +typedef struct AGSConfiguration_511 +{ + AGS_ALLOC_CALLBACK_511 allocCallback; ///< Optional memory allocation callback. If not supplied, malloc() is used + AGS_FREE_CALLBACK freeCallback; ///< Optional memory freeing callback. If not supplied, free() is used +} AGSConfiguration_511; + +typedef struct AGSConfiguration_520 { AGS_ALLOC_CALLBACK allocCallback; ///< Optional memory allocation callback. If not supplied, malloc() is used AGS_FREE_CALLBACK freeCallback; ///< Optional memory freeing callback. If not supplied, free() is used +} AGSConfiguration_520; + +typedef union AGSConfiguration +{ + AGSConfiguration_511 agsConfiguration511; + AGSConfiguration_520 agsConfiguration520; } AGSConfiguration; /// The top level GPU information returned from \ref agsInit @@ -369,7 +410,7 @@ typedef struct AGSDisplaySettings Mode_SDR, ///< SDR mode Mode_HDR10_PQ, ///< HDR10 PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. Mode_HDR10_scRGB, ///< HDR10 scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. - Mode_Freesync2_scRGB, ///< Freesync2 scRGB, requiring an FP16 swapchain. Values in the range of 0.0 to 125.0 where 125.0 == AGSDisplayInfo::maxLuminance. + Mode_Freesync2_scRGB, ///< Freesync2 scRGB, requiring an FP16 swapchain. 1.0 == 80 nits. Tonemap your scene to the range of 0.0 to AGSDisplayInfo::maxLuminance. Mode_DolbyVision ///< Dolby Vision, requiring an 8888 UNORM swapchain } mode; ///< The display mode to set the display into @@ -390,13 +431,16 @@ typedef struct AGSDisplaySettings double maxContentLightLevel; ///< The maximum content light level in nits (MaxCLL) double maxFrameAverageLightLevel; ///< The maximum frame average light level in nits (MaxFALL) + + // ADDED IN 5.2.0 + int flags; ///< Bitfield of ::AGSDisplaySettingsFlags } AGSDisplaySettings; /// /// Function used to initialize the AGS library. /// Must be called prior to any of the subsequent AGS API calls. /// Must be called prior to ID3D11Device or ID3D12Device creation. -/// \note This function will fail with AGS_ERROR_LEGACY_DRIVER in Catalyst versions before 12.20. +/// \note This function will fail with \ref AGS_ERROR_LEGACY_DRIVER in Catalyst versions before 12.20. /// \note It is good practice to check the AGS version returned from AGSGPUInfo against the version defined in the header in case a mismatch between the dll and header has occurred. /// /// \param [in, out] context Address of a pointer to a context. This function allocates a context on the heap which is then required for all subsequent API calls. @@ -419,6 +463,7 @@ AMD_AGS_API AGSReturnCode agsDeInit( AGSContext* context ); /// \param [in] context Pointer to a context. /// \param [out] numGPUs Number of GPUs used for Crossfire acceleration /// +/// REMOVED IN 5.2.0 AMD_AGS_API AGSReturnCode agsGetCrossfireGPUCount( AGSContext* context, int* numGPUs ); /// @@ -427,7 +472,6 @@ AMD_AGS_API AGSReturnCode agsGetCrossfireGPUCount( AGSContext* context, int* num /// \note Call this function after each mode change (switch to fullscreen, any change in swapchain etc). /// \note HDR10 PQ mode requires a 1010102 swapchain. /// \note HDR10 scRGB mode requires an FP16 swapchain. -/// \note Freesync2 Gamma mode requires a 1010102 swapchain. /// \note Freesync2 scRGB mode requires an FP16 swapchain. /// \note Dolby Vision requires a 8888 UNORM swapchain. /// @@ -444,9 +488,65 @@ AMD_AGS_API AGSReturnCode agsSetDisplayMode( AGSContext* context, int deviceInde /// DirectX12 driver extensions /// @{ -/// \defgroup dx12init Initialization and Cleanup +/// \defgroup dx12init Device creation and cleanup +/// It is now mandatory to call \ref agsDriverExtensionsDX12_CreateDevice when creating a device if the user wants to access any future DX12 AMD extensions. +/// The corresponding \ref agsDriverExtensionsDX12_DestroyDevice call must be called to release the device and free up the internal resources allocated by the create call. /// @{ +/// The struct to specify the DX12 device creation parameters +typedef struct AGSDX12DeviceCreationParams +{ + IDXGIAdapter* pAdapter; ///< Pointer to the adapter to use when creating the device. This may be null. + IID iid; ///< The interface ID for the type of device to be created. + D3D_FEATURE_LEVEL FeatureLevel; ///< The minimum feature level to create the device with. +} AGSDX12DeviceCreationParams; + +#define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX12ExtensionParams and \ref AGSDX11ExtensionParams +#define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version + +/// The struct to specify DX12 additional device creation parameters +typedef struct AGSDX12ExtensionParams +{ + const WCHAR* pAppName; ///< Application name + const WCHAR* pEngineName; ///< Engine name + unsigned int appVersion; ///< Application version + unsigned int engineVersion; ///< Engine version +} AGSDX12ExtensionParams; + +/// The struct to hold all the returned parameters from the device creation call +typedef struct AGSDX12ReturnedParams +{ + ID3D12Device* pDevice; ///< The newly created device + unsigned int extensionsSupported; ///< Bit mask that \ref agsDriverExtensionsDX12_CreateDevice will fill in to indicate which extensions are supported. See \ref AGSDriverExtensionDX12 +} AGSDX12ReturnedParams; + + +/// +/// Function used to create a D3D12 device with additional AMD-specific initialization parameters. +/// +/// When using the HLSL shader extensions please note: +/// * The shader compiler should not use the D3DCOMPILE_SKIP_OPTIMIZATION (/Od) option, otherwise it will not work. +/// * The shader compiler needs D3DCOMPILE_ENABLE_STRICTNESS (/Ges) enabled. +/// * The intrinsic instructions require a 5.1 shader model. +/// * The Root Signature will need to use an extra resource and sampler. These are not real resources/samplers, they are just used to encode the intrinsic instruction. +/// +/// \param [in] context Pointer to a context. This is generated by \ref agsInit +/// \param [in] creationParams Pointer to the struct to specify the existing DX12 device creation parameters. +/// \param [in] extensionParams Optional pointer to the struct to specify DX12 additional device creation parameters. +/// \param [out] returnedParams Pointer to struct to hold all the returned parameters from the call. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_CreateDevice( AGSContext* context, const AGSDX12DeviceCreationParams* creationParams, const AGSDX12ExtensionParams* extensionParams, AGSDX12ReturnedParams* returnedParams ); + +/// +/// Function to destroy the D3D12 device. +/// This call will also cleanup any AMD-specific driver extensions for D3D12. +/// +/// \param [in] context Pointer to a context. +/// \param [in] device Pointer to the D3D12 device. +/// \param [out] deviceReferences Optional pointer to an unsigned int that will be set to the value returned from device->Release(). +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_DestroyDevice( AGSContext* context, ID3D12Device* device, unsigned int* deviceReferences ); + /// /// Function used to initialize the AMD-specific driver extensions for D3D12. /// Extensions require support in the driver, therefore it is important to check the extensionsSupported bitfield. @@ -460,6 +560,7 @@ AMD_AGS_API AGSReturnCode agsSetDisplayMode( AGSContext* context, int deviceInde /// \param [in] device The D3D12 device. /// \param [out] extensionsSupported Pointer to a bit mask that this function will fill in to indicate which extensions are supported. See ::AGSDriverExtensionDX12 /// +/// REMOVED IN 5.2.0 AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_Init( AGSContext* context, ID3D12Device* device, unsigned int* extensionsSupported ); /// @@ -467,6 +568,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_Init( AGSContext* context, ID3 /// /// \param [in] context Pointer to a context. /// +/// REMOVED IN 5.2.0 AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_DeInit( AGSContext* context ); /// @} @@ -476,7 +578,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_DeInit( AGSContext* context ); /// /// Function used to push an AMD user marker onto the command list. -/// This is only has an effect if AGS_DX12_EXTENSION_USER_MARKERS is present in the extensionsSupported bitfield of agsDriverExtensionsDX12_Init() +/// This is only has an effect if AGS_DX12_EXTENSION_USER_MARKERS is present in the extensionsSupported bitfield of \ref agsDriverExtensionsDX12_CreateDevice /// Supported in Radeon Software Version 17.9.1 onwards. /// /// \param [in] context Pointer to a context. @@ -513,10 +615,18 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_SetMarker( AGSContext* context /// @{ /// \defgroup dx11init Device creation and cleanup -/// It is now mandatory to call agsDriverExtensionsDX11_CreateDevice() when creating a device if the user wants to access any DX11 AMD extensions. -/// The corresponding agsDriverExtensionsDX11_DestroyDevice() call must be called to release the device and free up the internal resources allocated by the create call. +/// It is now mandatory to call \ref agsDriverExtensionsDX11_CreateDevice when creating a device if the user wants to access any DX11 AMD extensions. +/// The corresponding \ref agsDriverExtensionsDX11_DestroyDevice call must be called to release the device and free up the internal resources allocated by the create call. /// @{ +/// The different modes to control Crossfire behavior. +typedef enum AGSCrossfireMode +{ + AGS_CROSSFIRE_MODE_DRIVER_AFR = 0, ///< Use the default driver-based AFR rendering + AGS_CROSSFIRE_MODE_EXPLICIT_AFR, ///< Use the AGS Crossfire API functions to perform explicit AFR rendering without requiring a CF driver profile + AGS_CROSSFIRE_MODE_DISABLE ///< Completely disable AFR rendering +} AGSCrossfireMode; + /// The struct to specify the existing DX11 device creation parameters typedef struct AGSDX11DeviceCreationParams { @@ -530,11 +640,8 @@ typedef struct AGSDX11DeviceCreationParams const DXGI_SWAP_CHAIN_DESC* pSwapChainDesc; ///< Optional swapchain description. Specify this to invoke D3D11CreateDeviceAndSwapChain instead of D3D11CreateDevice. This must be null on the WACK compliant version } AGSDX11DeviceCreationParams; -#define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX11ExtensionParams -#define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version - /// The struct to specify DX11 additional device creation parameters -typedef struct AGSDX11ExtensionParams +typedef struct AGSDX11ExtensionParams_511 { unsigned int uavSlot; ///< The UAV slot reserved for intrinsic support. This must match the slot defined in the HLSL, i.e. #define AmdDxExtShaderIntrinsicsUAVSlot. /// The default slot is 7, but the caller is free to use an alternative slot. @@ -542,30 +649,80 @@ typedef struct AGSDX11ExtensionParams UINT appVersion; ///< Application version const WCHAR* pEngineName; ///< Engine name UINT engineVersion; ///< Engine version +} AGSDX11ExtensionParams_511; + +typedef struct AGSDX11ExtensionParams_520 +{ + const WCHAR* pAppName; ///< Application name + const WCHAR* pEngineName; ///< Engine name + unsigned int appVersion; ///< Application version + unsigned int engineVersion; ///< Engine version + unsigned int numBreadcrumbMarkers; ///< The number of breadcrumb markers to allocate. Each marker is a uint64 (ie 8 bytes). If 0, the system is disabled. + unsigned int uavSlot; ///< The UAV slot reserved for intrinsic support. This must match the slot defined in the HLSL, i.e. "#define AmdDxExtShaderIntrinsicsUAVSlot". + /// The default slot is 7, but the caller is free to use an alternative slot. + /// If 0 is specified, then the default of 7 will be used. + AGSCrossfireMode crossfireMode; ///< Desired Crossfire mode +} AGSDX11ExtensionParams_520; + +typedef union AGSDX11ExtensionParams +{ + AGSDX11ExtensionParams_511 agsDX11ExtensionParams511; + AGSDX11ExtensionParams_520 agsDX11ExtensionParams520; } AGSDX11ExtensionParams; /// The struct to hold all the returned parameters from the device creation call -typedef struct AGSDX11ReturnedParams +typedef struct AGSDX11ReturnedParams_511 { ID3D11Device* pDevice; ///< The newly created device D3D_FEATURE_LEVEL FeatureLevel; ///< The feature level supported by the newly created device ID3D11DeviceContext* pImmediateContext; ///< The newly created immediate device context IDXGISwapChain* pSwapChain; ///< The newly created swap chain. This is only created if a valid pSwapChainDesc is supplied in AGSDX11DeviceCreationParams. This is not supported on the WACK compliant version unsigned int extensionsSupported; ///< Bit mask that \ref agsDriverExtensionsDX11_CreateDevice will fill in to indicate which extensions are supported. See AGSDriverExtensionDX11 +} AGSDX11ReturnedParams_511; + +typedef struct AGSDX11ReturnedParams_520 +{ + ID3D11Device* pDevice; ///< The newly created device + ID3D11DeviceContext* pImmediateContext; ///< The newly created immediate device context + IDXGISwapChain* pSwapChain; ///< The newly created swap chain. This is only created if a valid pSwapChainDesc is supplied in AGSDX11DeviceCreationParams. This is not supported on the WACK compliant version + D3D_FEATURE_LEVEL FeatureLevel; ///< The feature level supported by the newly created device + unsigned int extensionsSupported; ///< Bit mask that \ref agsDriverExtensionsDX11_CreateDevice will fill in to indicate which extensions are supported. See \ref AGSDriverExtensionDX11 + unsigned int crossfireGPUCount; ///< The number of GPUs that are active for this app + void* breadcrumbBuffer; ///< The CPU buffer returned if the initialization of the breadcrumb was successful. +} AGSDX11ReturnedParams_520; + +typedef union AGSDX11ReturnedParams +{ + AGSDX11ReturnedParams_511 agsDX11ReturnedParams511; + AGSDX11ReturnedParams_520 agsDX11ReturnedParams520; } AGSDX11ReturnedParams; /// /// Function used to create a D3D11 device with additional AMD-specific initialization parameters. /// /// When using the HLSL shader extensions please note: -/// * The shader compiler should not use the D3DCOMPILE_SKIP_OPTIMIZATION option, otherwise it will not work. +/// * The shader compiler should not use the D3DCOMPILE_SKIP_OPTIMIZATION (/Od) option, otherwise it will not work. +/// * The shader compiler needs D3DCOMPILE_ENABLE_STRICTNESS (/Ges) enabled. /// /// \param [in] context Pointer to a context. This is generated by \ref agsInit /// \param [in] creationParams Pointer to the struct to specify the existing DX11 device creation parameters. /// \param [in] extensionParams Optional pointer to the struct to specify DX11 additional device creation parameters. /// \param [out] returnedParams Pointer to struct to hold all the returned parameters from the call. /// -AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateDevice( AGSContext* context, AGSDX11DeviceCreationParams* creationParams, AGSDX11ExtensionParams* extensionParams, AGSDX11ReturnedParams* returnedParams ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateDevice( AGSContext* context, const AGSDX11DeviceCreationParams* creationParams, const AGSDX11ExtensionParams* extensionParams, AGSDX11ReturnedParams* returnedParams ); + +/// +/// Function to destroy the D3D11 device and its immediate context. +/// This call will also cleanup any AMD-specific driver extensions for D3D11. +/// +/// \param [in] context Pointer to a context. +/// \param [in] device Pointer to the D3D11 device. +/// \param [out] deviceReferences Optional pointer to an unsigned int that will be set to the value returned from device->Release(). +/// \param [in] immediateContext Pointer to the D3D11 immediate device context. +/// \param [out] immediateContextReferences Optional pointer to an unsigned int that will be set to the value returned from immediateContext->Release(). +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice_520( AGSContext* context, ID3D11Device* device, unsigned int* deviceReferences, ID3D11DeviceContext* immediateContext, unsigned int* immediateContextReferences ); + /// /// Function to destroy the D3D11 device. @@ -575,7 +732,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateDevice( AGSContext* cont /// \param [in] device Pointer to the D3D11 device. /// \param [out] references Optional pointer to an unsigned int that will be set to the value returned from device->Release(). /// -AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice( AGSContext* context, ID3D11Device* device, unsigned int* references ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice_511( AGSContext* context, ID3D11Device* device, unsigned int* references ); /// @} @@ -610,6 +767,211 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice( AGSContext* con /// /// @} +/// \defgroup breadcrumbs Breadcrumb API +/// API for writing top-of-pipe and bottom-of-pipe markers to help track down GPU hangs. +/// +/// The API is available if the \ref AGS_DX11_EXTENSION_BREADCRUMB_MARKERS is present in \ref AGSDX11ReturnedParams::extensionsSupported. +/// +/// To use the API, a non zero value needs to be specificed in \ref AGSDX11ExtensionParams::numBreadcrumbMarkers. This enables the API (if available) and allocates a system memory buffer +/// which is returned to the user in \ref AGSDX11ReturnedParams::breadcrumbBuffer. +/// +/// The user can now write markers before and after draw calls using \ref agsDriverExtensionsDX11_WriteBreadcrumb. +/// +/// \section background Background +/// +/// A top-of-pipe (TOP) command is scheduled for execution as soon as the command processor (CP) reaches the command. +/// A bottom-of-pipe (BOP) command is scheduled for execution once the previous rendering commands (draw and dispatch) finish execution. +/// TOP and BOP commands do not block CP. i.e. the CP schedules the command for execution then proceeds to the next command without waiting. +/// To effectively use TOP and BOP commands, it is important to understand how they interact with rendering commands: +/// +/// When the CP encounters a rendering command it queues it for execution and moves to the next command. The queued rendering commands are issued in order. +/// There can be multiple rendering commands running in parallel. When a rendering command is issued we say it is at the top of the pipe. When a rendering command +/// finishes execution we say it has reached the bottom of the pipe. +/// +/// A BOP command remains in a waiting queue and is executed once prior rendering commands finish. The queue of BOP commands is limited to 64 entries in GCN generation 1, 2, 3, 4 and 5. +/// If the 64 limit is reached the CP will stop queueing BOP commands and also rendering commands. Developers should limit the number of BOP commands that write markers to avoid contention. +/// In general, developers should limit both TOP and BOP commands to avoid stalling the CP. +/// +/// \subsection eg1 Example 1: +/// +/// \code{.cpp} +/// // Start of a command buffer +/// WriteMarker(TopOfPipe, 1) +/// WriteMarker(BottomOfPipe, 2) +/// WriteMarker(BottomOfPipe, 3) +/// DrawX +/// WriteMarker(BottomOfPipe, 4) +/// WriteMarker(BottomOfPipe, 5) +/// WriteMarker(TopOfPipe, 6) +/// // End of command buffer +/// \endcode +/// +/// In the above example, the CP writes markers 1, 2 and 3 without waiting: +/// Marker 1 is TOP so it's independent from other commands +/// There's no wait for marker 2 and 3 because there are no draws preceding the BOP commands +/// Marker 4 is only written once DrawX finishes execution +/// Marker 5 doesn't wait for additional draws so it is written right after marker 4 +/// Marker 6 can be written as soon as the CP reaches the command. For instance, it is very possible that CP writes marker 6 while DrawX +/// is running and therefore marker 6 gets written before markers 4 and 5 +/// +/// \subsection eg2 Example 2: +/// +/// \code{.cpp} +/// WriteMarker(TopOfPipe, 1) +/// DrawX +/// WriteMarker(BottomOfPipe, 2) +/// WriteMarker(TopOfPipe, 3) +/// DrawY +/// WriteMarker(BottomOfPipe, 4) +/// \endcode +/// +/// In this example marker 1 is written before the start of DrawX +/// Marker 2 is written once DrawX finishes execution +/// Similarly marker 3 is written before the start of DrawY +/// Marker 4 is written once DrawY finishes execution +/// In case of a GPU hang, if markers 1 and 3 are written but markers 2 and 4 are missing we can conclude that: +/// The CP has reached both DrawX and DrawY commands since marker 1 and 3 are present +/// The fact that marker 2 and 4 are missing means that either DrawX is hanging while DrawY is at the top of the pipe or both DrawX and DrawY +/// started and both are simultaneously hanging +/// +/// \subsection eg3 Example 3: +/// +/// \code{.cpp} +/// // Start of a command buffer +/// WriteMarker(BottomOfPipe, 1) +/// DrawX +/// WriteMarker(BottomOfPipe, 2) +/// DrawY +/// WriteMarker(BottomOfPipe, 3) +/// DrawZ +/// WriteMarker(BottomOfPipe, 4) +/// // End of command buffer +/// \endcode +/// +/// In this example marker 1 is written before the start of DrawX +/// Marker 2 is written once DrawX finishes +/// Marker 3 is written once DrawY finishes +/// Marker 4 is written once DrawZ finishes +/// If the GPU hangs and only marker 1 is written we can conclude that the hang is happening in either DrawX, DrawY or DrawZ +/// If the GPU hangs and only marker 1 and 2 are written we can conclude that the hang is happening in DrawY or DrawZ +/// If the GPU hangs and only marker 4 is missing we can conclude that the hang is happening in DrawZ +/// +/// \subsection eg4 Example 4: +/// +/// \code{.cpp} +/// Start of a command buffer +/// WriteMarker(TopOfPipe, 1) +/// DrawX +/// WriteMarker(TopOfPipe, 2) +/// DrawY +/// WriteMarker(TopOfPipe, 3) +/// DrawZ +/// // End of command buffer +/// \endcode +/// +/// In this example, in case the GPU hangs and only marker 1 is written we can conclude that the hang is happening in DrawX +/// In case the GPU hangs and only marker 1 and 2 are written we can conclude that the hang is happening in DrawX or DrawY +/// In case the GPU hangs and all 3 markers are written we can conclude that the hang is happening in any of DrawX, DrawY or DrawZ +/// +/// \subsection eg5 Example 5: +/// +/// \code{.cpp} +/// DrawX +/// WriteMarker(TopOfPipe, 1) +/// WriteMarker(BottomOfPipe, 2) +/// DrawY +/// WriteMarker(TopOfPipe, 3) +/// WriteMarker(BottomOfPipe, 4) +/// \endcode +/// +/// Marker 1 is written right after DrawX is queued for execution. +/// Marker 2 is only written once DrawX finishes execution. +/// Marker 3 is written right after DrawY is queued for execution. +/// Marker 4 is only written once DrawY finishes execution +/// If marker 1 is written we would know that the CP has reached the command DrawX (DrawX at the top of the pipe). +/// If marker 2 is written we can say that DrawX has finished execution (DrawX at the bottom of the pipe). +/// In case the GPU hangs and only marker 1 and 3 are written we can conclude that the hang is happening in DrawX or DrawY +/// In case the GPU hangs and only marker 1 is written we can conclude that the hang is happening in DrawX +/// In case the GPU hangs and only marker 4 is missing we can conclude that the hang is happening in DrawY +/// +/// \section data Retrieving GPU Data +/// +/// In the event of a GPU hang, the user can inspect the system memory buffer to determine which draw has caused the hang. +/// For example: +/// \code{.cpp} +/// // Force the work to be flushed to prevent CPU ahead of GPU +/// g_pImmediateContext->Flush(); +/// +/// // Present the information rendered to the back buffer to the front buffer (the screen) +/// HRESULT hr = g_pSwapChain->Present( 0, 0 ); +/// +/// // Read the marker data buffer once detect device lost +/// if ( hr != S_OK ) +/// { +/// for (UINT i = 0; i < g_NumMarkerWritten; i++) +/// { +/// UINT64* pTempData; +/// pTempData = static_cast(pMarkerBuffer); +/// +/// // Write the marker data to file +/// ofs << i << "\r\n"; +/// ofs << std::hex << *(pTempData + i * 2) << "\r\n"; +/// ofs << std::hex << *(pTempData + (i * 2 + 1)) << "\r\n"; +/// +/// WCHAR s1[256]; +/// setlocale(LC_NUMERIC, "en_US.iso88591"); +/// +/// // Output the marker data to console +/// swprintf(s1, 256, L" The Draw count is %d; The Top maker is % 016llX and the Bottom marker is % 016llX \r\n", i, *(pTempData + i * 2), *(pTempData + (i * 2 + 1))); +/// +/// OutputDebugStringW(s1); +/// } +/// } +/// \endcode +/// +/// The console output would resemble something like: +/// \code{.cpp} +/// D3D11: Removing Device. +/// D3D11 ERROR: ID3D11Device::RemoveDevice: Device removal has been triggered for the following reason (DXGI_ERROR_DEVICE_HUNG: The Device took an unreasonable amount of time to execute its commands, or the hardware crashed/hung. As a result, the TDR (Timeout Detection and Recovery) mechanism has been triggered. The current Device Context was executing commands when the hang occurred. The application may want to respawn and fallback to less aggressive use of the display hardware). [ EXECUTION ERROR #378: DEVICE_REMOVAL_PROCESS_AT_FAULT] +/// The Draw count is 0; The Top maker is 00000000DEADCAFE and the Bottom marker is 00000000DEADBEEF +/// The Draw count is 1; The Top maker is 00000000DEADCAFE and the Bottom marker is 00000000DEADBEEF +/// The Draw count is 2; The Top maker is 00000000DEADCAFE and the Bottom marker is 00000000DEADBEEF +/// The Draw count is 3; The Top maker is 00000000DEADCAFE and the Bottom marker is 00000000DEADBEEF +/// The Draw count is 4; The Top maker is 00000000DEADCAFE and the Bottom marker is 00000000DEADBEEF +/// The Draw count is 5; The Top maker is CDCDCDCDCDCDCDCD and the Bottom marker is CDCDCDCDCDCDCDCD +/// The Draw count is 6; The Top maker is CDCDCDCDCDCDCDCD and the Bottom marker is CDCDCDCDCDCDCDCD +/// The Draw count is 7; The Top maker is CDCDCDCDCDCDCDCD and the Bottom marker is CDCDCDCDCDCDCDCD +/// \endcode +/// +/// @{ + +/// The breadcrumb marker struct used by \ref agsDriverExtensionsDX11_WriteBreadcrumb +typedef struct AGSBreadcrumbMarker +{ + unsigned long long markerData; ///< The user data to write. + enum + { + TopOfPipe = 0, ///< Top-of-pipe marker + BottomOfPipe = 1 ///< Bottom-of-pipe marker + } type; ///< Whether this marker is top or bottom of pipe. + unsigned int index; ///< The index of the marker. This should be less than the value specified in \ref AGSDX11ExtensionParams::numBreadcrumbMarkers +} AGSBreadcrumbMarker; + +/// +/// Function to write a breadcrumb marker. +/// +/// This method inserts a write marker operation in the GPU command stream. In the case where the GPU is hanging the write +/// command will never be reached and the marker will never get written to memory. +/// +/// In order to use this function, \ref AGSDX11ExtensionParams::numBreadcrumbMarkers must be set to a non zero value. +/// +/// \param [in] context Pointer to a context. +/// \param [in] marker Pointer to a marker. +/// +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_WriteBreadcrumb( AGSContext* context, const AGSBreadcrumbMarker* marker ); + +/// @} + /// \defgroup dx11misc Misc Extensions /// API for depth bounds test, UAV overlap and prim topologies /// @{ @@ -618,34 +980,37 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice( AGSContext* con /// Function used to set the primitive topology. If you are using any of the extended topology types, then this function should /// be called to set ALL topology types. /// -/// The Quad List extension is a convenient way to submit quads without using an index buffer. Note that this still submits two triangles at the driver level. +/// The Quad List extension is a convenient way to submit quads without using an index buffer. Note that this still submits two triangles at the driver level. /// In order to use this function, AGS must already be initialized and agsDriverExtensionsDX11_Init must have been called successfully. /// -/// The Screen Rect extension, which is only available on GCN hardware, allows the user to pass in three of the four corners of a rectangle. -/// The hardware then uses the bounding box of the vertices to rasterize the rectangle primitive (i.e. as a rectangle rather than two triangles). +/// The Screen Rect extension, which is only available on GCN hardware, allows the user to pass in three of the four corners of a rectangle. +/// The hardware then uses the bounding box of the vertices to rasterize the rectangle primitive (i.e. as a rectangle rather than two triangles). /// \note Note that this will not return valid interpolated values, only valid SV_Position values. /// \note If either the Quad List or Screen Rect extension are used, then agsDriverExtensionsDX11_IASetPrimitiveTopology should be called in place of the native DirectX11 equivalent all the time. /// /// \param [in] context Pointer to a context. -/// \param [in] topology The topology to set on the D3D11 device. This can be either an AGS-defined topology such as AGS_PRIMITIVE_TOPOLOGY_QUAD_LIST +/// \param [in] topology The topology to set on the D3D11 device. This can be either an AGS-defined topology such as AGS_PRIMITIVE_TOPOLOGY_QUADLIST /// or a standard D3D-defined topology such as D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP. /// NB. the AGS-defined types will require casting to a D3D_PRIMITIVE_TOPOLOGY type. /// AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_IASetPrimitiveTopology( AGSContext* context, enum D3D_PRIMITIVE_TOPOLOGY topology ); /// -/// Function used indicate to the driver it can overlap the subsequent batch of back-to-back dispatches. +/// Function used indicate to the driver that it doesn't need to sync the UAVs bound for the subsequent set of back-to-back dispatches. /// When calling back-to-back draw calls or dispatch calls that write to the same UAV, the AMD DX11 driver will automatically insert a barrier to ensure there are no write after write (WAW) hazards. /// If the app can guarantee there is no overlap between the writes between these calls, then this extension will remove those barriers allowing the work to run in parallel on the GPU. /// /// Usage would be as follows: /// \code{.cpp} +/// m_device->Dispatch( ... ); // First call that writes to the UAV +/// /// // Disable automatic WAW syncs /// agsDriverExtensionsDX11_BeginUAVOverlap( m_agsContext ); /// -/// // Submit back-to-back dispatches that write to the same UAV -/// m_device->Dispatch( ... ); // First half of UAV -/// m_device->Dispatch( ... ); // Second half of UAV +/// // Submit other dispatches that write to the same UAV concurrently +/// m_device->Dispatch( ... ); +/// m_device->Dispatch( ... ); +/// m_device->Dispatch( ... ); /// /// // Reenable automatic WAW syncs /// agsDriverExtensionsDX11_EndUAVOverlap( m_agsContext ); @@ -713,6 +1078,8 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds( AGSContext* co /// }; /// \endcode /// +/// Example usage can be seen in AMD's GeometryFX (https://github.com/GPUOpen-Effects/GeometryFX). In particular, in this file: https://github.com/GPUOpen-Effects/GeometryFX/blob/master/amd_geometryfx/src/AMD_GeometryFX_Filtering.cpp +/// /// @{ /// @@ -846,6 +1213,24 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetClipRects( AGSContext* cont /// API for explicit control over Crossfire /// @{ +/// The Crossfire API transfer types +typedef enum AGSAfrTransferType +{ + AGS_AFR_TRANSFER_DEFAULT = 0, ///< Default Crossfire driver resource tracking + AGS_AFR_TRANSFER_DISABLE = 1, ///< Turn off driver resource tracking + AGS_AFR_TRANSFER_1STEP_P2P = 2, ///< App controlled GPU to next GPU transfer + AGS_AFR_TRANSFER_2STEP_NO_BROADCAST = 3, ///< App controlled GPU to next GPU transfer using intermediate system memory + AGS_AFR_TRANSFER_2STEP_WITH_BROADCAST = 4, ///< App controlled GPU to all render GPUs transfer using intermediate system memory +} AGSAfrTransferType; + +/// The Crossfire API transfer engines +typedef enum AGSAfrTransferEngine +{ + AGS_AFR_TRANSFERENGINE_DEFAULT = 0, ///< Use default engine for Crossfire API transfers + AGS_AFR_TRANSFERENGINE_3D_ENGINE = 1, ///< Use 3D engine for Crossfire API transfers + AGS_AFR_TRANSFERENGINE_COPY_ENGINE = 2, ///< Use Copy engine for Crossfire API transfers +} AGSAfrTransferEngine; + /// /// Function to create a Direct3D11 resource with the specified AFR transfer type and specified transfer engine. /// @@ -916,9 +1301,9 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NotifyResourceEndWrites( AGSCo AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NotifyResourceBeginAllAccess( AGSContext* context, ID3D11Resource* resource ); /// -/// This is used for AGS_AFR_TRANSFER_1STEP_P2P to notify when it is safe to initiate a transfer. -/// This call in frame N-(NumGpus-1) allows a 1 step P2P in frame N to start. -/// This should be called after agsDriverExtensionsDX11_NotifyResourceEndWrites. +/// This is used for AGS_AFR_TRANSFER_1STEP_P2P to notify when it is safe to initiate a transfer. +/// This call in frame N-(NumGpus-1) allows a 1 step P2P in frame N to start. +/// This should be called after agsDriverExtensionsDX11_NotifyResourceEndWrites. /// /// \param [in] context Pointer to a context. /// \param [in] resource Pointer to the resource. diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index e339d7b7d2b..5c8bcaf395b 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -15,8 +15,29 @@ WINE_DEFAULT_DEBUG_CHANNEL(amd_ags); +enum amd_ags_version +{ + AMD_AGS_VERSION_5_1_1, + AMD_AGS_VERSION_5_2_0, + + AMD_AGS_VERSION_COUNT +}; + +struct +{ + int major; + int minor; + int patch; +} +static const amd_ags_versions[AMD_AGS_VERSION_COUNT] = +{ + {5, 1, 1}, + {5, 2, 0}, +}; + struct AGSContext { + enum amd_ags_version version; unsigned int device_count; AGSDeviceInfo *devices; VkPhysicalDeviceProperties *properties; @@ -88,6 +109,8 @@ static AGSReturnCode init_ags_context(AGSContext *context) AGSReturnCode ret; unsigned int i; + // TODO: version check + context->version = AMD_AGS_VERSION_5_1_1; context->device_count = 0; context->devices = NULL; context->properties = NULL; @@ -108,15 +131,32 @@ static AGSReturnCode init_ags_context(AGSContext *context) const VkPhysicalDeviceProperties *vk_properties = &context->properties[i]; AGSDeviceInfo *device = &context->devices[i]; - device->adapterString = vk_properties->deviceName; - device->vendorId = vk_properties->vendorID; - device->deviceId = vk_properties->deviceID; + switch (context->version) + { + case AMD_AGS_VERSION_5_1_1: + device->agsDeviceInfo511.adapterString = vk_properties->deviceName; + device->agsDeviceInfo511.vendorId = vk_properties->vendorID; + device->agsDeviceInfo511.deviceId = vk_properties->deviceID; + + if (device->agsDeviceInfo511.vendorId == 0x1002) + device->agsDeviceInfo511.architectureVersion = ArchitectureVersion_GCN; - if (device->vendorId == 0x1002) - device->architectureVersion = ArchitectureVersion_GCN; + if (!i) + device->agsDeviceInfo511.isPrimaryDevice = 1; + break; + case AMD_AGS_VERSION_5_2_0: + default: + device->agsDeviceInfo520.adapterString = vk_properties->deviceName; + device->agsDeviceInfo520.vendorId = vk_properties->vendorID; + device->agsDeviceInfo520.deviceId = vk_properties->deviceID; + + if (device->agsDeviceInfo520.vendorId == 0x1002) + device->agsDeviceInfo520.architectureVersion = ArchitectureVersion_GCN; - if (!i) - device->isPrimaryDevice = 1; + if (!i) + device->agsDeviceInfo520.isPrimaryDevice = 1; + break; + } } return AGS_SUCCESS; @@ -145,9 +185,9 @@ AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *confi } memset(gpu_info, 0, sizeof(*gpu_info)); - gpu_info->agsVersionMajor = AMD_AGS_VERSION_MAJOR; - gpu_info->agsVersionMinor = AMD_AGS_VERSION_MINOR; - gpu_info->agsVersionPatch = AMD_AGS_VERSION_PATCH; + gpu_info->agsVersionMajor = amd_ags_versions[object->version].major; + gpu_info->agsVersionMinor = amd_ags_versions[object->version].minor; + gpu_info->agsVersionPatch = amd_ags_versions[object->version].patch; gpu_info->driverVersion = "18.10.16-180516a-328911C-RadeonSoftwareAdrenalin"; gpu_info->radeonSoftwareVersion = "18.5.1"; gpu_info->numDevices = object->device_count; From 1b1f5a6d588fbf8ec4e7f80e4436d21a57cafc6f Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Wed, 17 Jun 2020 14:32:18 -0700 Subject: [PATCH 0330/2777] amd_ags_x64: Update to 5.2.1. --- dlls/amd_ags_x64/amd_ags.h | 14 ++++++++++---- dlls/amd_ags_x64/amd_ags_x64_main.c | 3 +++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h index b647f912aa7..c39adb53678 100644 --- a/dlls/amd_ags_x64/amd_ags.h +++ b/dlls/amd_ags_x64/amd_ags.h @@ -33,6 +33,12 @@ /// Online documentation is publicly hosted here: http://gpuopen-librariesandsdks.github.io/ags/ /// \endinternal /// +/// What's new in AGS 5.2.1 since version 5.2.0 +/// --------------------------------------- +/// * Fix for crash when using Eyefinity +/// * Fix for DX12 app registration in the UWP version +/// +/// /// What's new in AGS 5.2.0 since version 5.1 /// --------------------------------------- /// AGS 5.2 includes the following updates: @@ -98,7 +104,7 @@ #define AMD_AGS_VERSION_MAJOR 5 ///< AGS major version #define AMD_AGS_VERSION_MINOR 2 ///< AGS minor version -#define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version +#define AMD_AGS_VERSION_PATCH 1 ///< AGS patch version #ifdef __cplusplus extern "C" { @@ -622,7 +628,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_SetMarker( AGSContext* context /// The different modes to control Crossfire behavior. typedef enum AGSCrossfireMode { - AGS_CROSSFIRE_MODE_DRIVER_AFR = 0, ///< Use the default driver-based AFR rendering + AGS_CROSSFIRE_MODE_DRIVER_AFR = 0, ///< Use the default driver-based AFR rendering. If this mode is specified, do NOT use the agsDriverExtensionsDX11_Create*() APIs to create resources AGS_CROSSFIRE_MODE_EXPLICIT_AFR, ///< Use the AGS Crossfire API functions to perform explicit AFR rendering without requiring a CF driver profile AGS_CROSSFIRE_MODE_DISABLE ///< Completely disable AFR rendering } AGSCrossfireMode; @@ -739,7 +745,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice_511( AGSContext* /// \defgroup dx11appreg App Registration /// @{ -/// This extension allows an apllication to voluntarily register itself with the driver, providing a more robust app detection solution and avoid the issue of the driver +/// This extension allows an apllication to voluntarily register itself with the driver, providing a more robust app detection solution and avoid the issue of the driver /// relying on exe names to match the app to a driver profile. /// This feature is supported in Radeon Software Version 17.9.2 onwards. /// Rules: @@ -1151,7 +1157,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount( /// /// This method can be used to determine the total number of asynchronous shader compile jobs that are either -/// queued for waiting for compilation or being compiled by the driver’s asynchronous compilation threads. +/// queued for waiting for compilation or being compiled by the driverÂ’s asynchronous compilation threads. /// This method can be called at any during the lifetime of the driver. /// /// \param [in] context Pointer to a context. diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 5c8bcaf395b..e8b55bf9d42 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -19,6 +19,7 @@ enum amd_ags_version { AMD_AGS_VERSION_5_1_1, AMD_AGS_VERSION_5_2_0, + AMD_AGS_VERSION_5_2_1, AMD_AGS_VERSION_COUNT }; @@ -33,6 +34,7 @@ static const amd_ags_versions[AMD_AGS_VERSION_COUNT] = { {5, 1, 1}, {5, 2, 0}, + {5, 2, 1}, }; struct AGSContext @@ -145,6 +147,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) device->agsDeviceInfo511.isPrimaryDevice = 1; break; case AMD_AGS_VERSION_5_2_0: + case AMD_AGS_VERSION_5_2_1: default: device->agsDeviceInfo520.adapterString = vk_properties->deviceName; device->agsDeviceInfo520.vendorId = vk_properties->vendorID; From 71e3ac7a4f83aa292c6ed13f636fc34496c80b12 Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Wed, 17 Jun 2020 14:44:25 -0700 Subject: [PATCH 0331/2777] amd_ags_x64: Update to 5.3.0. --- dlls/amd_ags_x64/amd_ags.h | 98 +++++++++++++++++++++++------ dlls/amd_ags_x64/amd_ags_x64_main.c | 3 + 2 files changed, 82 insertions(+), 19 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h index c39adb53678..58f7bb84e37 100644 --- a/dlls/amd_ags_x64/amd_ags.h +++ b/dlls/amd_ags_x64/amd_ags.h @@ -33,6 +33,14 @@ /// Online documentation is publicly hosted here: http://gpuopen-librariesandsdks.github.io/ags/ /// \endinternal /// +/// --------------------------------------- +/// What's new in AGS 5.3 since version 5.2 +/// --------------------------------------- +/// AGS 5.3 includes the following updates: +/// * DX11 deferred context support for Multi Draw Indirect and UAV Overlap extensions. +/// * A Radeon Software Version helper to determine whether the installed driver meets your game's minimum driver version requirements. +/// * Freesync2 Gamma 2.2 mode which uses a 1010102 swapchain and can be considered as an alternative to using the 64 bit swapchain required for Freesync2 scRGB. +/// /// What's new in AGS 5.2.1 since version 5.2.0 /// --------------------------------------- /// * Fix for crash when using Eyefinity @@ -103,8 +111,8 @@ #define AMD_AGS_H #define AMD_AGS_VERSION_MAJOR 5 ///< AGS major version -#define AMD_AGS_VERSION_MINOR 2 ///< AGS minor version -#define AMD_AGS_VERSION_PATCH 1 ///< AGS patch version +#define AMD_AGS_VERSION_MINOR 3 ///< AGS minor version +#define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version #ifdef __cplusplus extern "C" { @@ -112,6 +120,9 @@ extern "C" { #define AMD_AGS_API WINAPI +#define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX12ExtensionParams and \ref AGSDX11ExtensionParams and the Radeon Software Version +#define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version + // Forward declaration of D3D11 types struct IDXGIAdapter; enum D3D_DRIVER_TYPE; @@ -147,6 +158,7 @@ typedef enum AGSReturnCode AGS_ERROR_LEGACY_DRIVER, ///< Returned if a feature is not present in the installed driver AGS_EXTENSION_NOT_SUPPORTED, ///< Returned if the driver does not support the requested driver extension AGS_ADL_FAILURE, ///< Failure in ADL (the AMD Display Library) + AGS_DX_FAILURE ///< Failure from DirectX runtime } AGSReturnCode; /// The DirectX11 extension support bits @@ -173,6 +185,9 @@ typedef enum AGSDriverExtensionDX11 AGS_DX11_EXTENSION_MULTIVIEW = 1 << 18, ///< Supported in Radeon Software Version 16.12.1 onwards. AGS_DX11_EXTENSION_APP_REGISTRATION = 1 << 19, ///< Supported in Radeon Software Version 17.9.1 onwards. AGS_DX11_EXTENSION_BREADCRUMB_MARKERS = 1 << 20, ///< Supported in Radeon Software Version 17.11.1 onwards. + AGS_DX11_EXTENSION_MDI_DEFERRED_CONTEXTS = 1 << 21, ///< Supported in Radeon Software Version XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX onwards. + AGS_DX11_EXTENSION_UAV_OVERLAP_DEFERRED_CONTEXTS = 1 << 22, ///< Supported in Radeon Software Version XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX onwards. + AGS_DX11_EXTENSION_DEPTH_BOUNDS_DEFERRED_CONTEXTS = 1 << 23 ///< Supported in Radeon Software Version XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX onwards. } AGSDriverExtensionDX11; /// The DirectX12 extension support bits @@ -417,6 +432,8 @@ typedef struct AGSDisplaySettings Mode_HDR10_PQ, ///< HDR10 PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. Mode_HDR10_scRGB, ///< HDR10 scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. Mode_Freesync2_scRGB, ///< Freesync2 scRGB, requiring an FP16 swapchain. 1.0 == 80 nits. Tonemap your scene to the range of 0.0 to AGSDisplayInfo::maxLuminance. + // Mode_Freesync2_Gamma22 ADDED IN 5.3.0 + Mode_Freesync2_Gamma22, ///< Freesync2 Gamma 2.2, requiring a 1010102 UNORM swapchain. The output needs to be encoded to gamma 2.2. Mode_DolbyVision ///< Dolby Vision, requiring an 8888 UNORM swapchain } mode; ///< The display mode to set the display into @@ -442,6 +459,24 @@ typedef struct AGSDisplaySettings int flags; ///< Bitfield of ::AGSDisplaySettingsFlags } AGSDisplaySettings; +/// The result returned from \ref agsCheckDriverVersion +typedef enum AGSDriverVersionResult +{ + AGS_SOFTWAREVERSIONCHECK_OK, ///< The reported Radeon Software Version is newer or the same as the required version + AGS_SOFTWAREVERSIONCHECK_OLDER, ///< The reported Radeon Software Version is older than the required version + AGS_SOFTWAREVERSIONCHECK_UNDEFINED ///< The check could not determine as result. This could be because it is a private or custom driver or just invalid arguments. +} AGSDriverVersionResult; + +/// +/// Helper function to check the installed software version against the required software version. +/// +/// \param [in] radeonSoftwareVersionReported The Radeon Software Version returned from \ref AGSGPUInfo::radeonSoftwareVersion. +/// \param [in] radeonSoftwareVersionRequired The Radeon Software Version to check against. This is specificed using \ref AGS_MAKE_VERSION. +/// \return The result of the check. +/// +AMD_AGS_API AGSDriverVersionResult agsCheckDriverVersion( const char* radeonSoftwareVersionReported, unsigned int radeonSoftwareVersionRequired ); + + /// /// Function used to initialize the AGS library. /// Must be called prior to any of the subsequent AGS API calls. @@ -494,7 +529,7 @@ AMD_AGS_API AGSReturnCode agsSetDisplayMode( AGSContext* context, int deviceInde /// DirectX12 driver extensions /// @{ -/// \defgroup dx12init Device creation and cleanup +/// \defgroup dx12init Device and device object creation and cleanup /// It is now mandatory to call \ref agsDriverExtensionsDX12_CreateDevice when creating a device if the user wants to access any future DX12 AMD extensions. /// The corresponding \ref agsDriverExtensionsDX12_DestroyDevice call must be called to release the device and free up the internal resources allocated by the create call. /// @{ @@ -507,9 +542,6 @@ typedef struct AGSDX12DeviceCreationParams D3D_FEATURE_LEVEL FeatureLevel; ///< The minimum feature level to create the device with. } AGSDX12DeviceCreationParams; -#define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX12ExtensionParams and \ref AGSDX11ExtensionParams -#define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version - /// The struct to specify DX12 additional device creation parameters typedef struct AGSDX12ExtensionParams { @@ -628,7 +660,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_SetMarker( AGSContext* context /// The different modes to control Crossfire behavior. typedef enum AGSCrossfireMode { - AGS_CROSSFIRE_MODE_DRIVER_AFR = 0, ///< Use the default driver-based AFR rendering. If this mode is specified, do NOT use the agsDriverExtensionsDX11_Create*() APIs to create resources + AGS_CROSSFIRE_MODE_DRIVER_AFR = 0, ///< Use the default driver-based AFR rendering. If this mode is specified, do NOT use the agsDriverExtensionsDX11_Create*() APIs to create resources AGS_CROSSFIRE_MODE_EXPLICIT_AFR, ///< Use the AGS Crossfire API functions to perform explicit AFR rendering without requiring a CF driver profile AGS_CROSSFIRE_MODE_DISABLE ///< Completely disable AFR rendering } AGSCrossfireMode; @@ -978,8 +1010,8 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_WriteBreadcrumb( AGSContext* c /// @} -/// \defgroup dx11misc Misc Extensions -/// API for depth bounds test, UAV overlap and prim topologies +/// \defgroup dx11Topology Extended Topology +/// API for primitive topologies /// @{ /// @@ -1001,6 +1033,12 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_WriteBreadcrumb( AGSContext* c /// AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_IASetPrimitiveTopology( AGSContext* context, enum D3D_PRIMITIVE_TOPOLOGY topology ); +/// @} + +/// \defgroup dx11UAVOverlap UAV Overlap +/// API for enabling overlapping UAV writes +/// @{ + /// /// Function used indicate to the driver that it doesn't need to sync the UAVs bound for the subsequent set of back-to-back dispatches. /// When calling back-to-back draw calls or dispatch calls that write to the same UAV, the AMD DX11 driver will automatically insert a barrier to ensure there are no write after write (WAW) hazards. @@ -1023,25 +1061,39 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_IASetPrimitiveTopology( AGSCon /// \endcode /// /// \param [in] context Pointer to a context. +/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. +/// with the AGS_DX11_EXTENSION_DEFERRED_CONTEXTS bit. /// -AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_BeginUAVOverlap( AGSContext* context ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_BeginUAVOverlap_520( AGSContext* context ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_BeginUAVOverlap( AGSContext* context, ID3D11DeviceContext* dxContext ); /// /// Function used indicate to the driver it can no longer overlap the batch of back-to-back dispatches that has been submitted. /// /// \param [in] context Pointer to a context. +/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. +/// with the AGS_DX11_EXTENSION_DEFERRED_CONTEXTS bit. /// -AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_EndUAVOverlap( AGSContext* context ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_EndUAVOverlap_520( AGSContext* context ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_EndUAVOverlap( AGSContext* context, ID3D11DeviceContext* dxContext ); + +/// @} + +/// \defgroup dx11DepthBoundsTest Depth Bounds Test +/// API for enabling depth bounds testing +/// @{ /// /// Function used to set the depth bounds test extension /// -/// \param [in] context Pointer to a context. +/// \param [in] context Pointer to a context +/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. /// \param [in] enabled Whether to enable or disable the depth bounds testing. If disabled, the next two args are ignored. /// \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( AGSContext* context, bool enabled, float minDepth, float maxDepth ); +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 ); /// @} @@ -1054,12 +1106,12 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds( AGSContext* co /// \code{.cpp} /// // Submit n batches of DrawIndirect calls /// for ( int i = 0; i < n; i++ ) -/// DrawIndexedInstancedIndirect( buffer, i * sizeof( cmd ) ); +/// deviceContext->DrawIndexedInstancedIndirect( buffer, i * sizeof( cmd ) ); /// \endcode /// To be replaced by the following call: /// \code{.cpp} /// // Submit all n batches in one call -/// agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect( m_agsContext, n, buffer, 0, sizeof( cmd ) ); +/// agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect( m_agsContext, deviceContext, n, buffer, 0, sizeof( cmd ) ); /// \endcode /// /// The buffer used for the indirect args must be of the following formats: @@ -1092,47 +1144,55 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds( AGSContext* co /// Function used to submit a batch of draws via MultiDrawIndirect /// /// \param [in] context Pointer to a context. +/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. /// \param [in] drawCount The number of draws. /// \param [in] pBufferForArgs The args buffer. /// \param [in] alignedByteOffsetForArgs The offset into the args buffer. /// \param [in] byteStrideForArgs The per element stride of the args buffer. /// -AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirect( AGSContext* context, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirect_520( AGSContext* context, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirect( AGSContext* context, ID3D11DeviceContext* dxContext, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); /// /// Function used to submit a batch of draws via MultiDrawIndirect /// /// \param [in] context Pointer to a context. +/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. /// \param [in] drawCount The number of draws. /// \param [in] pBufferForArgs The args buffer. /// \param [in] alignedByteOffsetForArgs The offset into the args buffer. /// \param [in] byteStrideForArgs The per element stride of the args buffer. /// -AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect( AGSContext* context, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect_520( AGSContext* context, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect( AGSContext* context, ID3D11DeviceContext* dxContext, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); /// /// Function used to submit a batch of draws via MultiDrawIndirect /// /// \param [in] context Pointer to a context. +/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. /// \param [in] pBufferForDrawCount The draw count buffer. /// \param [in] alignedByteOffsetForDrawCount The offset into the draw count buffer. /// \param [in] pBufferForArgs The args buffer. /// \param [in] alignedByteOffsetForArgs The offset into the args buffer. /// \param [in] byteStrideForArgs The per element stride of the args buffer. /// -AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect( AGSContext* context, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect_520( AGSContext* context, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect( AGSContext* context, ID3D11DeviceContext* dxContext, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); /// /// Function used to submit a batch of draws via MultiDrawIndirect /// /// \param [in] context Pointer to a context. +/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. /// \param [in] pBufferForDrawCount The draw count buffer. /// \param [in] alignedByteOffsetForDrawCount The offset into the draw count buffer. /// \param [in] pBufferForArgs The args buffer. /// \param [in] alignedByteOffsetForArgs The offset into the args buffer. /// \param [in] byteStrideForArgs The per element stride of the args buffer. /// -AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect( AGSContext* context, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect_520( AGSContext* context, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect( AGSContext* context, ID3D11DeviceContext* dxContext, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); /// @} diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index e8b55bf9d42..b3cf309da41 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -20,6 +20,7 @@ enum amd_ags_version AMD_AGS_VERSION_5_1_1, AMD_AGS_VERSION_5_2_0, AMD_AGS_VERSION_5_2_1, + AMD_AGS_VERSION_5_3_0, AMD_AGS_VERSION_COUNT }; @@ -35,6 +36,7 @@ static const amd_ags_versions[AMD_AGS_VERSION_COUNT] = {5, 1, 1}, {5, 2, 0}, {5, 2, 1}, + {5, 3, 0}, }; struct AGSContext @@ -148,6 +150,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) break; case AMD_AGS_VERSION_5_2_0: case AMD_AGS_VERSION_5_2_1: + case AMD_AGS_VERSION_5_3_0: default: device->agsDeviceInfo520.adapterString = vk_properties->deviceName; device->agsDeviceInfo520.vendorId = vk_properties->vendorID; From bb5efa1a7b6d349e5554babf20a5aa4c52944932 Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Wed, 17 Jun 2020 15:03:02 -0700 Subject: [PATCH 0332/2777] amd_ags_x64: Update to 5.4.0. --- dlls/amd_ags_x64/amd_ags.h | 92 ++++++++++++++++++++++++++--- dlls/amd_ags_x64/amd_ags_x64_main.c | 15 ++++- 2 files changed, 99 insertions(+), 8 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h index 58f7bb84e37..c615ba4c203 100644 --- a/dlls/amd_ags_x64/amd_ags.h +++ b/dlls/amd_ags_x64/amd_ags.h @@ -34,6 +34,14 @@ /// \endinternal /// /// --------------------------------------- +/// What's new in AGS 5.4 since version 5.3 +/// --------------------------------------- +/// AGS 5.4 includes the following updates: +/// * A more detailed description of the GPU architecture, now including RDNA GPUs. +/// * Navi 10, Navi 14 and Radeon 7 core and memory speeds returned. +/// * Draw index and Atomic U64 intrinsics for both DX11 and DX12. +/// +/// --------------------------------------- /// What's new in AGS 5.3 since version 5.2 /// --------------------------------------- /// AGS 5.3 includes the following updates: @@ -111,7 +119,7 @@ #define AMD_AGS_H #define AMD_AGS_VERSION_MAJOR 5 ///< AGS major version -#define AMD_AGS_VERSION_MINOR 3 ///< AGS minor version +#define AMD_AGS_VERSION_MINOR 4 ///< AGS minor version #define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version #ifdef __cplusplus @@ -185,9 +193,11 @@ typedef enum AGSDriverExtensionDX11 AGS_DX11_EXTENSION_MULTIVIEW = 1 << 18, ///< Supported in Radeon Software Version 16.12.1 onwards. AGS_DX11_EXTENSION_APP_REGISTRATION = 1 << 19, ///< Supported in Radeon Software Version 17.9.1 onwards. AGS_DX11_EXTENSION_BREADCRUMB_MARKERS = 1 << 20, ///< Supported in Radeon Software Version 17.11.1 onwards. - AGS_DX11_EXTENSION_MDI_DEFERRED_CONTEXTS = 1 << 21, ///< Supported in Radeon Software Version XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX onwards. - AGS_DX11_EXTENSION_UAV_OVERLAP_DEFERRED_CONTEXTS = 1 << 22, ///< Supported in Radeon Software Version XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX onwards. - AGS_DX11_EXTENSION_DEPTH_BOUNDS_DEFERRED_CONTEXTS = 1 << 23 ///< Supported in Radeon Software Version XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX onwards. + AGS_DX11_EXTENSION_MDI_DEFERRED_CONTEXTS = 1 << 21, ///< Supported in Radeon Software Version 18.8.1 onwards. + AGS_DX11_EXTENSION_UAV_OVERLAP_DEFERRED_CONTEXTS = 1 << 22, ///< Supported in Radeon Software Version 18.8.1 onwards. + AGS_DX11_EXTENSION_DEPTH_BOUNDS_DEFERRED_CONTEXTS = 1 << 23, ///< Supported in Radeon Software Version 18.8.1 onwards. + AGS_DX11_EXTENSION_INTRINSIC_DRAW_INDEX = 1 << 24, ///< Supported in Radeon Software Version 19.12.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_ATOMIC_U64 = 1 << 25 ///< Supported in Radeon Software Version 19.12.2 onwards. } AGSDriverExtensionDX11; /// The DirectX12 extension support bits @@ -204,7 +214,10 @@ typedef enum AGSDriverExtensionDX12 AGS_DX12_EXTENSION_INTRINSIC_WAVE_REDUCE = 1 << 8, ///< Supported in Radeon Software Version 17.9.1 onwards. AGS_DX12_EXTENSION_INTRINSIC_WAVE_SCAN = 1 << 9, ///< Supported in Radeon Software Version 17.9.1 onwards. AGS_DX12_EXTENSION_USER_MARKERS = 1 << 10, ///< Supported in Radeon Software Version 17.9.1 onwards. - AGS_DX12_EXTENSION_APP_REGISTRATION = 1 << 11 ///< Supported in Radeon Software Version 17.9.1 onwards. + AGS_DX12_EXTENSION_APP_REGISTRATION = 1 << 11, ///< Supported in Radeon Software Version 17.9.1 onwards. + AGS_DX12_EXTENSION_INTRINSIC_UAV_BIND_SLOT = 1 << 12, ///< Supported in Radeon Software Version 19.5.1 onwards. + AGS_DX12_EXTENSION_INTRINSIC_DRAW_INDEX = 1 << 13, ///< Supported in Radeon Software Version 19.12.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_ATOMIC_U64 = 1 << 14 ///< Supported in Radeon Software Version 19.12.2 onwards. } AGSDriverExtensionDX12; /// The space id for DirectX12 intrinsic support @@ -312,6 +325,19 @@ typedef enum ArchitectureVersion ArchitectureVersion_GCN ///< AMD GCN architecture } ArchitectureVersion; +/// The ASIC family +typedef enum AsicFamily +{ + AsicFamily_Unknown, ///< Unknown architecture, potentially from another IHV. Check \ref AGSDeviceInfo::vendorId + AsicFamily_PreGCN, ///< Pre GCN architecture. + AsicFamily_GCN1, ///< AMD GCN 1 architecture: Oland, Cape Verde, Pitcairn & Tahiti. + AsicFamily_GCN2, ///< AMD GCN 2 architecture: Hawaii & Bonaire. This also includes APUs Kaveri and Carrizo. + AsicFamily_GCN3, ///< AMD GCN 3 architecture: Tonga & Fiji. + AsicFamily_GCN4, ///< AMD GCN 4 architecture: Polaris. + AsicFamily_Vega, ///< AMD Vega architecture, including Raven Ridge (ie AMD Ryzen CPU + AMD Vega GPU). + AsicFamily_RDNA ///< AMD RDNA architecture +} AsicFamily; + /// The device info struct used to describe a physical GPU enumerated by AGS typedef struct AGSDeviceInfo_511 { @@ -374,10 +400,48 @@ typedef struct AGSDeviceInfo_520 int adlAdapterIndex; ///< Internally used index into the ADL list of adapters } AGSDeviceInfo_520; +/// The device info struct used to describe a physical GPU enumerated by AGS +typedef struct AGSDeviceInfo_540 +{ + const char* adapterString; ///< The adapter name string + AsicFamily asicFamily; ///< Set to Unknown if not AMD hardware + int isAPU; ///< Whether or not this is an APU + int vendorId; ///< The vendor id + int deviceId; ///< The device id + int revisionId; ///< The revision id + + int numCUs; ///< Number of compute units. + int numWGPs; ///< Number of RDNA Work Group Processors. Only valid if ASIC is RDNA onwards. + + int numROPs; ///< Number of ROPs + int coreClock; ///< Core clock speed at 100% power in MHz + int memoryClock; ///< Memory clock speed at 100% power in MHz + int memoryBandwidth; ///< Memory bandwidth in MB/s + float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD + + int isPrimaryDevice; ///< Whether or not this is the primary adapter in the system. Not set on the WACK version. + unsigned long long localMemoryInBytes; ///< The size of local memory in bytes. + unsigned long long sharedMemoryInBytes; ///< The size of system memory available to the GPU in bytes. It is important to factor this into your VRAM budget for APUs + ///< as the reported local memory will only be a small fraction of the total memory available to the GPU. + + int numDisplays; ///< The number of active displays found to be attached to this adapter. + AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. + + int eyefinityEnabled; ///< Indicates if Eyefinity is active + int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. + int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. + int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. + + int adlAdapterIndex; ///< Internally used index into the ADL list of adapters +} AGSDeviceInfo_540; + typedef union AGSDeviceInfo { AGSDeviceInfo_511 agsDeviceInfo511; AGSDeviceInfo_520 agsDeviceInfo520; + AGSDeviceInfo_540 agsDeviceInfo540; } AGSDeviceInfo; /// \defgroup general General API functions @@ -549,6 +613,8 @@ typedef struct AGSDX12ExtensionParams const WCHAR* pEngineName; ///< Engine name unsigned int appVersion; ///< Application version unsigned int engineVersion; ///< Engine version + // ADDED IN 5.4.0 + unsigned int uavSlot; ///< The UAV slot reserved for intrinsic support. Refer to the \ref agsDriverExtensionsDX12_CreateDevice documentation for more details. } AGSDX12ExtensionParams; /// The struct to hold all the returned parameters from the device creation call @@ -566,7 +632,19 @@ typedef struct AGSDX12ReturnedParams /// * The shader compiler should not use the D3DCOMPILE_SKIP_OPTIMIZATION (/Od) option, otherwise it will not work. /// * The shader compiler needs D3DCOMPILE_ENABLE_STRICTNESS (/Ges) enabled. /// * The intrinsic instructions require a 5.1 shader model. -/// * The Root Signature will need to use an extra resource and sampler. These are not real resources/samplers, they are just used to encode the intrinsic instruction. +/// * The Root Signature will need to reserve an extra UAV resource slot. This is not a real resource that requires allocating, it is just used to encode the intrinsic instructions. +/// +/// The easiest way to set up the reserved UAV slot is to specify it at u0. The register space id will automatically be assumed to be \ref AGS_DX12_SHADER_INSTRINSICS_SPACE_ID. +/// The HLSL expects this as default and the set up code would look similar to this: +/// \code{.cpp} +/// CD3DX12_DESCRIPTOR_RANGE range[]; +/// ... +/// range[ 0 ].Init( D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0, AGS_DX12_SHADER_INSTRINSICS_SPACE_ID ); // u0 at driver-reserved space id +/// \endcode +/// +/// Newer drivers also support a user-specified slot in which case the register space id is assumed to be 0. It is important that the \ref AGS_DX12_EXTENSION_INTRINSIC_UAV_BIND_SLOT bit is set +/// to ensure the driver can support this. If not, then u0 and \ref AGS_DX12_SHADER_INSTRINSICS_SPACE_ID must be used. +/// If the driver does support this feature and a non zero slot is required, then the HLSL must also define AMD_EXT_SHADER_INTRINSIC_UAV_OVERRIDE as the matching slot value. /// /// \param [in] context Pointer to a context. This is generated by \ref agsInit /// \param [in] creationParams Pointer to the struct to specify the existing DX12 device creation parameters. @@ -616,7 +694,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_DeInit( AGSContext* context ); /// /// Function used to push an AMD user marker onto the command list. -/// This is only has an effect if AGS_DX12_EXTENSION_USER_MARKERS is present in the extensionsSupported bitfield of \ref agsDriverExtensionsDX12_CreateDevice +/// This is only has an effect if \ref AGS_DX12_EXTENSION_USER_MARKERS is present in the extensionsSupported bitfield of \ref agsDriverExtensionsDX12_CreateDevice /// Supported in Radeon Software Version 17.9.1 onwards. /// /// \param [in] context Pointer to a context. diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index b3cf309da41..9b45ec721c2 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -21,6 +21,7 @@ enum amd_ags_version AMD_AGS_VERSION_5_2_0, AMD_AGS_VERSION_5_2_1, AMD_AGS_VERSION_5_3_0, + AMD_AGS_VERSION_5_4_0, AMD_AGS_VERSION_COUNT }; @@ -37,6 +38,7 @@ static const amd_ags_versions[AMD_AGS_VERSION_COUNT] = {5, 2, 0}, {5, 2, 1}, {5, 3, 0}, + {5, 4, 0}, }; struct AGSContext @@ -151,7 +153,6 @@ static AGSReturnCode init_ags_context(AGSContext *context) case AMD_AGS_VERSION_5_2_0: case AMD_AGS_VERSION_5_2_1: case AMD_AGS_VERSION_5_3_0: - default: device->agsDeviceInfo520.adapterString = vk_properties->deviceName; device->agsDeviceInfo520.vendorId = vk_properties->vendorID; device->agsDeviceInfo520.deviceId = vk_properties->deviceID; @@ -162,6 +163,18 @@ static AGSReturnCode init_ags_context(AGSContext *context) if (!i) device->agsDeviceInfo520.isPrimaryDevice = 1; break; + case AMD_AGS_VERSION_5_4_0: + default: + device->agsDeviceInfo540.adapterString = vk_properties->deviceName; + device->agsDeviceInfo540.vendorId = vk_properties->vendorID; + device->agsDeviceInfo540.deviceId = vk_properties->deviceID; + + if (device->agsDeviceInfo540.vendorId == 0x1002) + device->agsDeviceInfo540.asicFamily = AsicFamily_GCN4; + + if (!i) + device->agsDeviceInfo540.isPrimaryDevice = 1; + break; } } From 0a4cc743559d7639133594a0b90ab911fddd18e6 Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Wed, 17 Jun 2020 15:16:44 -0700 Subject: [PATCH 0333/2777] amd_ags_x64: Update to 5.4.1 --- dlls/amd_ags_x64/amd_ags.h | 101 +++++++++++++++++++++++----- dlls/amd_ags_x64/amd_ags_x64_main.c | 15 ++++- 2 files changed, 98 insertions(+), 18 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h index c615ba4c203..30f3735915c 100644 --- a/dlls/amd_ags_x64/amd_ags.h +++ b/dlls/amd_ags_x64/amd_ags.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2018 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2020 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -34,11 +34,21 @@ /// \endinternal /// /// --------------------------------------- +/// What's new in AGS 5.4.1 since version 5.4.0 +/// --------------------------------------- +/// AGS 5.4.1 includes the following updates: +/// * AsicFamily_Count to help with code maintenance. +/// * Visual Studio 2019 support. +/// * x86 support +/// * BaseInstance and BaseVertex intrinsics along with corresponding caps bits. +/// * GetWaveSize intrinsic along with corresponding caps bits. +/// +/// --------------------------------------- /// What's new in AGS 5.4 since version 5.3 /// --------------------------------------- /// AGS 5.4 includes the following updates: /// * A more detailed description of the GPU architecture, now including RDNA GPUs. -/// * Navi 10, Navi 14 and Radeon 7 core and memory speeds returned. +/// * Radeon 7 core and memory speeds returned. /// * Draw index and Atomic U64 intrinsics for both DX11 and DX12. /// /// --------------------------------------- @@ -47,7 +57,7 @@ /// AGS 5.3 includes the following updates: /// * DX11 deferred context support for Multi Draw Indirect and UAV Overlap extensions. /// * A Radeon Software Version helper to determine whether the installed driver meets your game's minimum driver version requirements. -/// * Freesync2 Gamma 2.2 mode which uses a 1010102 swapchain and can be considered as an alternative to using the 64 bit swapchain required for Freesync2 scRGB. +/// * Freesync HDR Gamma 2.2 mode which uses a 1010102 swapchain and can be considered as an alternative to using the 64 bit swapchain required for Freesync HDR scRGB. /// /// What's new in AGS 5.2.1 since version 5.2.0 /// --------------------------------------- @@ -120,16 +130,19 @@ #define AMD_AGS_VERSION_MAJOR 5 ///< AGS major version #define AMD_AGS_VERSION_MINOR 4 ///< AGS minor version -#define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version +#define AMD_AGS_VERSION_PATCH 1 ///< AGS patch version #ifdef __cplusplus extern "C" { #endif +/// \defgroup Defines AGS defines +/// @{ #define AMD_AGS_API WINAPI #define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX12ExtensionParams and \ref AGSDX11ExtensionParams and the Radeon Software Version #define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version +/// @} // Forward declaration of D3D11 types struct IDXGIAdapter; @@ -154,6 +167,8 @@ struct D3D11_SUBRESOURCE_DATA; struct ID3D12Device; struct ID3D12GraphicsCommandList; +/// \defgroup enums General enumerations +/// @{ /// The return codes typedef enum AGSReturnCode @@ -162,8 +177,10 @@ typedef enum AGSReturnCode AGS_FAILURE, ///< Failed to complete call for some unspecified reason AGS_INVALID_ARGS, ///< Invalid arguments into the function AGS_OUT_OF_MEMORY, ///< Out of memory when allocating space internally - AGS_ERROR_MISSING_DLL, ///< Returned when a driver dll fails to load - most likely due to not being present in legacy driver installation - AGS_ERROR_LEGACY_DRIVER, ///< Returned if a feature is not present in the installed driver + AGS_MISSING_D3D_DLL, ///< Returned when a D3D dll fails to load + AGS_LEGACY_DRIVER, ///< Returned if a feature is not present in the installed driver + // AGS_NO_AMD_DRIVER_INSTALLED ADDED IN 5.4.1 + AGS_NO_AMD_DRIVER_INSTALLED, ///< Returned if the AMD GPU driver does not appear to be installed AGS_EXTENSION_NOT_SUPPORTED, ///< Returned if the driver does not support the requested driver extension AGS_ADL_FAILURE, ///< Failure in ADL (the AMD Display Library) AGS_DX_FAILURE ///< Failure from DirectX runtime @@ -197,7 +214,10 @@ typedef enum AGSDriverExtensionDX11 AGS_DX11_EXTENSION_UAV_OVERLAP_DEFERRED_CONTEXTS = 1 << 22, ///< Supported in Radeon Software Version 18.8.1 onwards. AGS_DX11_EXTENSION_DEPTH_BOUNDS_DEFERRED_CONTEXTS = 1 << 23, ///< Supported in Radeon Software Version 18.8.1 onwards. AGS_DX11_EXTENSION_INTRINSIC_DRAW_INDEX = 1 << 24, ///< Supported in Radeon Software Version 19.12.2 onwards. - AGS_DX11_EXTENSION_INTRINSIC_ATOMIC_U64 = 1 << 25 ///< Supported in Radeon Software Version 19.12.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_ATOMIC_U64 = 1 << 25, ///< Supported in Radeon Software Version 19.12.2 onwards. + AGS_DX11_EXTENSION_INTRINSIC_GET_WAVE_SIZE = 1 << 26, ///< Supported in Radeon Software Version 20.2.1 onwards. + AGS_DX11_EXTENSION_INTRINSIC_BASE_VERTEX = 1 << 27, ///< Supported in Radeon Software Version 20.2.1 onwards. + AGS_DX11_EXTENSION_INTRINSIC_BASE_INSTANCE = 1 << 28 ///< Supported in Radeon Software Version 20.2.1 onwards. } AGSDriverExtensionDX11; /// The DirectX12 extension support bits @@ -217,7 +237,10 @@ typedef enum AGSDriverExtensionDX12 AGS_DX12_EXTENSION_APP_REGISTRATION = 1 << 11, ///< Supported in Radeon Software Version 17.9.1 onwards. AGS_DX12_EXTENSION_INTRINSIC_UAV_BIND_SLOT = 1 << 12, ///< Supported in Radeon Software Version 19.5.1 onwards. AGS_DX12_EXTENSION_INTRINSIC_DRAW_INDEX = 1 << 13, ///< Supported in Radeon Software Version 19.12.2 onwards. - AGS_DX12_EXTENSION_INTRINSIC_ATOMIC_U64 = 1 << 14 ///< Supported in Radeon Software Version 19.12.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_ATOMIC_U64 = 1 << 14, ///< Supported in Radeon Software Version 19.12.2 onwards. + AGS_DX12_EXTENSION_INTRINSIC_BASE_VERTEX = 1 << 15, ///< Supported in Radeon Software Version 20.2.1 onwards. + AGS_DX12_EXTENSION_INTRINSIC_BASE_INSTANCE = 1 << 16, ///< Supported in Radeon Software Version 20.2.1 onwards. + AGS_DX12_EXTENSION_INTRINSIC_GET_WAVE_SIZE = 1 << 17 ///< Supported in Radeon Software Version 20.5.1 onwards. } AGSDriverExtensionDX12; /// The space id for DirectX12 intrinsic support @@ -238,7 +261,7 @@ typedef enum AGSDisplayFlags AGS_DISPLAYFLAG_HDR10 = 1 << 1, ///< HDR10 is supported on this display AGS_DISPLAYFLAG_DOLBYVISION = 1 << 2, ///< Dolby Vision is supported on this display AGS_DISPLAYFLAG_FREESYNC = 1 << 3, ///< Freesync is supported on this display - AGS_DISPLAYFLAG_FREESYNC_2 = 1 << 4, ///< Freesync 2 is supported on this display + AGS_DISPLAYFLAG_FREESYNC_HDR = 1 << 4, ///< Freesync HDR is supported on this display AGS_DISPLAYFLAG_EYEFINITY_IN_GROUP = 1 << 5, ///< The display is part of the Eyefinity group AGS_DISPLAYFLAG_EYEFINITY_PREFERRED_DISPLAY = 1 << 6, ///< The display is the preferred display in the Eyefinity group for displaying the UI AGS_DISPLAYFLAG_EYEFINITY_IN_PORTRAIT_MODE = 1 << 7, ///< The display is in the Eyefinity group but in portrait mode @@ -250,6 +273,7 @@ typedef enum AGSDisplaySettingsFlags AGS_DISPLAYSETTINGSFLAG_DISABLE_LOCAL_DIMMING = 1 << 0, ///< Disables local dimming if possible } AGSDisplaySettingsFlags; +/// @} typedef struct AGSContext AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInit @@ -280,7 +304,7 @@ typedef struct AGSDisplayInfo char name[ 256 ]; ///< The name of the display char displayDeviceName[ 32 ]; ///< The display device name, i.e. DISPLAY_DEVICE::DeviceName - unsigned int displayFlags; ///< Bitfield of ::AGSDisplayFlags + unsigned int displayFlags; ///< Bitfield of \ref AGSDisplayFlags int maxResolutionX; ///< The maximum supported resolution of the unrotated display int maxResolutionY; ///< The maximum supported resolution of the unrotated display @@ -335,7 +359,9 @@ typedef enum AsicFamily AsicFamily_GCN3, ///< AMD GCN 3 architecture: Tonga & Fiji. AsicFamily_GCN4, ///< AMD GCN 4 architecture: Polaris. AsicFamily_Vega, ///< AMD Vega architecture, including Raven Ridge (ie AMD Ryzen CPU + AMD Vega GPU). - AsicFamily_RDNA ///< AMD RDNA architecture + AsicFamily_RDNA, ///< AMD RDNA architecture + + AsicFamily_Count ///< Number of enumerated ASIC families } AsicFamily; /// The device info struct used to describe a physical GPU enumerated by AGS @@ -437,11 +463,47 @@ typedef struct AGSDeviceInfo_540 int adlAdapterIndex; ///< Internally used index into the ADL list of adapters } AGSDeviceInfo_540; +/// The device info struct used to describe a physical GPU enumerated by AGS +typedef struct AGSDeviceInfo_541 +{ + const char* adapterString; ///< The adapter name string + AsicFamily asicFamily; ///< Set to Unknown if not AMD hardware + int isAPU; ///< Whether or not this is an APU + int vendorId; ///< The vendor id + int deviceId; ///< The device id + int revisionId; ///< The revision id + + int numCUs; ///< Number of compute units. + int numWGPs; ///< Number of RDNA Work Group Processors. Only valid if ASIC is RDNA onwards. + + int numROPs; ///< Number of ROPs + int coreClock; ///< Core clock speed at 100% power in MHz + int memoryClock; ///< Memory clock speed at 100% power in MHz + int memoryBandwidth; ///< Memory bandwidth in MB/s + float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD + + int isPrimaryDevice; ///< Whether or not this is the primary adapter in the system. Not set on the WACK version. + long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. + + int numDisplays; ///< The number of active displays found to be attached to this adapter. + AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. + + int eyefinityEnabled; ///< Indicates if Eyefinity is active + int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. + int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. + int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. + + int adlAdapterIndex; ///< Internally used index into the ADL list of adapters +} AGSDeviceInfo_541; + typedef union AGSDeviceInfo { AGSDeviceInfo_511 agsDeviceInfo511; AGSDeviceInfo_520 agsDeviceInfo520; AGSDeviceInfo_540 agsDeviceInfo540; + AGSDeviceInfo_541 agsDeviceInfo541; } AGSDeviceInfo; /// \defgroup general General API functions @@ -495,10 +557,12 @@ typedef struct AGSDisplaySettings Mode_SDR, ///< SDR mode Mode_HDR10_PQ, ///< HDR10 PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. Mode_HDR10_scRGB, ///< HDR10 scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. - Mode_Freesync2_scRGB, ///< Freesync2 scRGB, requiring an FP16 swapchain. 1.0 == 80 nits. Tonemap your scene to the range of 0.0 to AGSDisplayInfo::maxLuminance. - // Mode_Freesync2_Gamma22 ADDED IN 5.3.0 - Mode_Freesync2_Gamma22, ///< Freesync2 Gamma 2.2, requiring a 1010102 UNORM swapchain. The output needs to be encoded to gamma 2.2. - Mode_DolbyVision ///< Dolby Vision, requiring an 8888 UNORM swapchain + Mode_FreesyncHDR_scRGB, ///< Freesync HDR scRGB, requiring an FP16 swapchain. A value of 1.0 == 80 nits. + // Mode_FreesyncHDR_Gamma22 ADDED IN 5.3.0 + Mode_FreesyncHDR_Gamma22, ///< Freesync HDR Gamma 2.2, requiring a 1010102 UNORM swapchain. The output needs to be encoded to gamma 2.2. + Mode_DolbyVision, ///< Dolby Vision, requiring an 8888 UNORM swapchain + + Mode_Count ///< Number of enumerated display modes } mode; ///< The display mode to set the display into double chromaticityRedX; ///< Red display primary X coord @@ -545,7 +609,9 @@ AMD_AGS_API AGSDriverVersionResult agsCheckDriverVersion( const char* radeonSoft /// Function used to initialize the AGS library. /// Must be called prior to any of the subsequent AGS API calls. /// Must be called prior to ID3D11Device or ID3D12Device creation. -/// \note This function will fail with \ref AGS_ERROR_LEGACY_DRIVER in Catalyst versions before 12.20. +/// \note The caller of this function should handle the possibility of the call failing in the cases below. One option is to do a vendor id check and only call \ref agsInit if there is an AMD GPU present. +/// \note This function will fail with \ref AGS_NO_AMD_DRIVER_INSTALLED if there is no AMD driver found on the system. +/// \note This function will fail with \ref AGS_LEGACY_DRIVER in Catalyst versions before 12.20. /// \note It is good practice to check the AGS version returned from AGSGPUInfo against the version defined in the header in case a mismatch between the dll and header has occurred. /// /// \param [in, out] context Address of a pointer to a context. This function allocates a context on the heap which is then required for all subsequent API calls. @@ -577,7 +643,8 @@ AMD_AGS_API AGSReturnCode agsGetCrossfireGPUCount( AGSContext* context, int* num /// \note Call this function after each mode change (switch to fullscreen, any change in swapchain etc). /// \note HDR10 PQ mode requires a 1010102 swapchain. /// \note HDR10 scRGB mode requires an FP16 swapchain. -/// \note Freesync2 scRGB mode requires an FP16 swapchain. +/// \note Freesync HDR scRGB mode requires an FP16 swapchain. +/// \note Freesync HDR Gamma 2.2 mode requires a 1010102 swapchain. /// \note Dolby Vision requires a 8888 UNORM swapchain. /// /// \param [in] context Pointer to a context. This is generated by \ref agsInit diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 9b45ec721c2..85b2db0b936 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -22,6 +22,7 @@ enum amd_ags_version AMD_AGS_VERSION_5_2_1, AMD_AGS_VERSION_5_3_0, AMD_AGS_VERSION_5_4_0, + AMD_AGS_VERSION_5_4_1, AMD_AGS_VERSION_COUNT }; @@ -39,6 +40,7 @@ static const amd_ags_versions[AMD_AGS_VERSION_COUNT] = {5, 2, 1}, {5, 3, 0}, {5, 4, 0}, + {5, 4, 1}, }; struct AGSContext @@ -164,7 +166,6 @@ static AGSReturnCode init_ags_context(AGSContext *context) device->agsDeviceInfo520.isPrimaryDevice = 1; break; case AMD_AGS_VERSION_5_4_0: - default: device->agsDeviceInfo540.adapterString = vk_properties->deviceName; device->agsDeviceInfo540.vendorId = vk_properties->vendorID; device->agsDeviceInfo540.deviceId = vk_properties->deviceID; @@ -175,6 +176,18 @@ static AGSReturnCode init_ags_context(AGSContext *context) if (!i) device->agsDeviceInfo540.isPrimaryDevice = 1; break; + case AMD_AGS_VERSION_5_4_1: + default: + device->agsDeviceInfo541.adapterString = vk_properties->deviceName; + device->agsDeviceInfo541.vendorId = vk_properties->vendorID; + device->agsDeviceInfo541.deviceId = vk_properties->deviceID; + + if (device->agsDeviceInfo541.vendorId == 0x1002) + device->agsDeviceInfo541.asicFamily = AsicFamily_GCN4; + + if (!i) + device->agsDeviceInfo541.isPrimaryDevice = 1; + break; } } From 6f69600e758c4597bb64298d50fb9b99d974d4ef Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Wed, 17 Jun 2020 16:33:08 -0700 Subject: [PATCH 0334/2777] amd_ags_x64: Fill in localMemoryInBytes. --- dlls/amd_ags_x64/amd_ags_x64_main.c | 39 ++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 85b2db0b936..d845a0978d8 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -49,12 +49,14 @@ struct AGSContext unsigned int device_count; AGSDeviceInfo *devices; VkPhysicalDeviceProperties *properties; + VkPhysicalDeviceMemoryProperties *memory_properties; }; static AGSReturnCode vk_get_physical_device_properties(unsigned int *out_count, - VkPhysicalDeviceProperties **out) + VkPhysicalDeviceProperties **out, VkPhysicalDeviceMemoryProperties **out_memory) { VkPhysicalDeviceProperties *properties = NULL; + VkPhysicalDeviceMemoryProperties *memory_properties = NULL; VkPhysicalDevice *vk_physical_devices = NULL; VkInstance vk_instance = VK_NULL_HANDLE; VkInstanceCreateInfo create_info; @@ -99,11 +101,23 @@ static AGSReturnCode vk_get_physical_device_properties(unsigned int *out_count, goto done; } + if (!(memory_properties = heap_calloc(count, sizeof(*memory_properties)))) + { + WARN("Failed to allocate memory.\n"); + heap_free(properties); + ret = AGS_OUT_OF_MEMORY; + goto done; + } + for (i = 0; i < count; ++i) vkGetPhysicalDeviceProperties(vk_physical_devices[i], &properties[i]); + for (i = 0; i < count; ++i) + vkGetPhysicalDeviceMemoryProperties(vk_physical_devices[i], &memory_properties[i]); + *out_count = count; *out = properties; + *out_memory = memory_properties; done: heap_free(vk_physical_devices); @@ -115,15 +129,16 @@ static AGSReturnCode vk_get_physical_device_properties(unsigned int *out_count, static AGSReturnCode init_ags_context(AGSContext *context) { AGSReturnCode ret; - unsigned int i; + unsigned int i, j; // TODO: version check context->version = AMD_AGS_VERSION_5_1_1; context->device_count = 0; context->devices = NULL; context->properties = NULL; + context->memory_properties = NULL; - ret = vk_get_physical_device_properties(&context->device_count, &context->properties); + ret = vk_get_physical_device_properties(&context->device_count, &context->properties, &context->memory_properties); if (ret != AGS_SUCCESS || !context->device_count) return ret; @@ -131,13 +146,26 @@ static AGSReturnCode init_ags_context(AGSContext *context) { WARN("Failed to allocate memory.\n"); heap_free(context->properties); + heap_free(context->memory_properties); return AGS_OUT_OF_MEMORY; } for (i = 0; i < context->device_count; ++i) { const VkPhysicalDeviceProperties *vk_properties = &context->properties[i]; + const VkPhysicalDeviceMemoryProperties *vk_memory_properties = &context->memory_properties[i]; AGSDeviceInfo *device = &context->devices[i]; + VkDeviceSize local_memory_size = 0; + + for (j = 0; j < vk_memory_properties->memoryHeapCount; j++) + { + if (vk_memory_properties->memoryHeaps[j].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) + { + local_memory_size = vk_memory_properties->memoryHeaps[j].size; + break; + } + } + TRACE("reporting local memory size 0x%s bytes\n", wine_dbgstr_longlong(local_memory_size)); switch (context->version) { @@ -145,6 +173,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) device->agsDeviceInfo511.adapterString = vk_properties->deviceName; device->agsDeviceInfo511.vendorId = vk_properties->vendorID; device->agsDeviceInfo511.deviceId = vk_properties->deviceID; + device->agsDeviceInfo511.localMemoryInBytes = local_memory_size; if (device->agsDeviceInfo511.vendorId == 0x1002) device->agsDeviceInfo511.architectureVersion = ArchitectureVersion_GCN; @@ -158,6 +187,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) device->agsDeviceInfo520.adapterString = vk_properties->deviceName; device->agsDeviceInfo520.vendorId = vk_properties->vendorID; device->agsDeviceInfo520.deviceId = vk_properties->deviceID; + device->agsDeviceInfo520.localMemoryInBytes = local_memory_size; if (device->agsDeviceInfo520.vendorId == 0x1002) device->agsDeviceInfo520.architectureVersion = ArchitectureVersion_GCN; @@ -169,6 +199,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) device->agsDeviceInfo540.adapterString = vk_properties->deviceName; device->agsDeviceInfo540.vendorId = vk_properties->vendorID; device->agsDeviceInfo540.deviceId = vk_properties->deviceID; + device->agsDeviceInfo540.localMemoryInBytes = local_memory_size; if (device->agsDeviceInfo540.vendorId == 0x1002) device->agsDeviceInfo540.asicFamily = AsicFamily_GCN4; @@ -181,6 +212,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) device->agsDeviceInfo541.adapterString = vk_properties->deviceName; device->agsDeviceInfo541.vendorId = vk_properties->vendorID; device->agsDeviceInfo541.deviceId = vk_properties->deviceID; + device->agsDeviceInfo541.localMemoryInBytes = local_memory_size; if (device->agsDeviceInfo541.vendorId == 0x1002) device->agsDeviceInfo541.asicFamily = AsicFamily_GCN4; @@ -238,6 +270,7 @@ AGSReturnCode WINAPI agsDeInit(AGSContext *context) if (context) { + heap_free(context->memory_properties); heap_free(context->properties); heap_free(context->devices); heap_free(context); From cae10196d2d4aad36c67e3ede13fa96bb86083d5 Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Wed, 17 Jun 2020 16:36:24 -0700 Subject: [PATCH 0335/2777] amd_ags_x64: Update reported driver version to 20.20.2. Needed to silence warnings in Red Dead Redemption 2. --- dlls/amd_ags_x64/amd_ags_x64_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index d845a0978d8..62a1a02c823 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -252,8 +252,8 @@ AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *confi gpu_info->agsVersionMajor = amd_ags_versions[object->version].major; gpu_info->agsVersionMinor = amd_ags_versions[object->version].minor; gpu_info->agsVersionPatch = amd_ags_versions[object->version].patch; - gpu_info->driverVersion = "18.10.16-180516a-328911C-RadeonSoftwareAdrenalin"; - gpu_info->radeonSoftwareVersion = "18.5.1"; + gpu_info->driverVersion = "20.20.2-180516a-328911C-RadeonSoftwareAdrenalin"; + gpu_info->radeonSoftwareVersion = "20.20.2"; gpu_info->numDevices = object->device_count; gpu_info->devices = object->devices; From ba320a28a184488e4db6b991b3e3307b225630a4 Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Thu, 25 Jun 2020 15:54:59 -0700 Subject: [PATCH 0336/2777] amd_ags_x64: Detect library version from DLL included with game. --- dlls/amd_ags_x64/Makefile.in | 2 +- dlls/amd_ags_x64/amd_ags_x64_main.c | 70 ++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/dlls/amd_ags_x64/Makefile.in b/dlls/amd_ags_x64/Makefile.in index 936d95986b6..910cc7d50c5 100644 --- a/dlls/amd_ags_x64/Makefile.in +++ b/dlls/amd_ags_x64/Makefile.in @@ -1,6 +1,6 @@ EXTRADEFS = -DWINE_NO_LONG_TYPES MODULE = amd_ags_x64.dll -IMPORTS = vulkan-1 +IMPORTS = version vulkan-1 IMPORTLIB = amd_ags_x64 EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 62a1a02c823..b2f8149bcd8 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -126,13 +126,79 @@ static AGSReturnCode vk_get_physical_device_properties(unsigned int *out_count, return ret; } +static enum amd_ags_version determine_ags_version(void) +{ + /* AMD AGS is not binary compatible between versions (even minor versions), and the game + * does not request a specific version when calling agsInit(). + * Checking the version of amd_ags_x64.dll shipped with the game is the only way to + * determine what version the game was built against. + * + * An update to AGS 5.4.1 included an amd_ags_x64.dll with no file version info. + * In case of an error, assume it's that version. + */ + enum amd_ags_version ret = AMD_AGS_VERSION_5_4_1; + DWORD infosize; + void *infobuf = NULL; + void *val; + UINT vallen, i; + VS_FIXEDFILEINFO *info; + UINT16 major, minor, patch; + + infosize = GetFileVersionInfoSizeW(L"amd_ags_x64.dll", NULL); + if (!infosize) + { + WARN("Unable to determine desired version of amd_ags_x64.dll.\n"); + goto done; + } + + if (!(infobuf = heap_alloc(infosize))) + { + WARN("Failed to allocate memory.\n"); + goto done; + } + + if (!GetFileVersionInfoW(L"amd_ags_x64.dll", 0, infosize, infobuf)) + { + WARN("Unable to determine desired version of amd_ags_x64.dll.\n"); + goto done; + } + + if (!VerQueryValueW(infobuf, L"\\", &val, &vallen) || (vallen != sizeof(VS_FIXEDFILEINFO))) + { + WARN("Unable to determine desired version of amd_ags_x64.dll.\n"); + goto done; + } + + info = val; + major = info->dwFileVersionMS >> 16; + minor = info->dwFileVersionMS; + patch = info->dwFileVersionLS >> 16; + TRACE("Found amd_ags_x64.dll v%d.%d.%d\n", major, minor, patch); + + for (i = 0; i < ARRAY_SIZE(amd_ags_versions); i++) + { + if ((major == amd_ags_versions[i].major) && + (minor == amd_ags_versions[i].minor) && + (patch == amd_ags_versions[i].patch)) + { + ret = i; + break; + } + } + +done: + heap_free(infobuf); + TRACE("Using AGS v%d.%d.%d interface\n", + amd_ags_versions[ret].major, amd_ags_versions[ret].minor, amd_ags_versions[ret].patch); + return ret; +} + static AGSReturnCode init_ags_context(AGSContext *context) { AGSReturnCode ret; unsigned int i, j; - // TODO: version check - context->version = AMD_AGS_VERSION_5_1_1; + context->version = determine_ags_version(); context->device_count = 0; context->devices = NULL; context->properties = NULL; From 2d54f2fd888fc7235a34c7cbf69c6b98be1086b7 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Wed, 21 Apr 2021 16:16:55 +0300 Subject: [PATCH 0337/2777] setupapi: Don't install built-in amd_ags_x64.dll in system32/syswow64. The DLL ships with the games and having the built-in version in system32/syswow64 has unexpected consequences. If the game is launched from a subdirectory, but the DLL is in current working directory, the built-in takes precedence as CWD has lower search priority than system directories (with the default SafeDllSearchMode). By not installing amd_ags_x64.dll in system32/syswow64 the built-in is still picked up correctly from lib/ when necessary. This fixes Evil Genius 2. CW-Bug-Id: 18804 --- dlls/setupapi/fakedll.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/setupapi/fakedll.c b/dlls/setupapi/fakedll.c index 7f4d7367285..725b28a253e 100644 --- a/dlls/setupapi/fakedll.c +++ b/dlls/setupapi/fakedll.c @@ -981,6 +981,7 @@ static void install_lib_dir( WCHAR *dest, WCHAR *file, const WCHAR *wildcard, if (lstrlenW( data.name ) > max_dll_name_len) continue; if (!wcscmp( data.name, L"." )) continue; if (!wcscmp( data.name, L".." )) continue; + if (!wcscmp( data.name, L"amd_ags_x64.dll" )) continue; lstrcpyW( name, data.name ); if (default_ext) /* inside build dir */ { From a1c7b5d647e62e91a24a6f2946935cc83e757360 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 16 Apr 2021 20:21:29 +0300 Subject: [PATCH 0338/2777] amd_ags_x64: Don't use ordinals in spec file. For Forza Horizon 4. --- dlls/amd_ags_x64/amd_ags_x64.spec | 58 +++++++++++++++---------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec index a302d2fc657..c571dac2184 100644 --- a/dlls/amd_ags_x64/amd_ags_x64.spec +++ b/dlls/amd_ags_x64/amd_ags_x64.spec @@ -1,29 +1,29 @@ -1 stdcall agsDeInit(ptr) -2 stub agsDriverExtensionsDX11_BeginUAVOverlap -3 stub agsDriverExtensionsDX11_CreateBuffer -4 stub agsDriverExtensionsDX11_CreateTexture1D -5 stub agsDriverExtensionsDX11_CreateTexture2D -6 stub agsDriverExtensionsDX11_CreateTexture3D -7 stub agsDriverExtensionsDX11_DeInit -8 stub agsDriverExtensionsDX11_EndUAVOverlap -9 stub agsDriverExtensionsDX11_GetMaxClipRects -10 stub agsDriverExtensionsDX11_IASetPrimitiveTopology -11 stub agsDriverExtensionsDX11_Init -12 stub agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect -13 stub agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect -14 stub agsDriverExtensionsDX11_MultiDrawInstancedIndirect -15 stub agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect -16 stub agsDriverExtensionsDX11_NotifyResourceBeginAllAccess -17 stub agsDriverExtensionsDX11_NotifyResourceEndAllAccess -18 stub agsDriverExtensionsDX11_NotifyResourceEndWrites -19 stub agsDriverExtensionsDX11_NumPendingAsyncCompileJobs -20 stub agsDriverExtensionsDX11_SetClipRects -21 stub agsDriverExtensionsDX11_SetDepthBounds -22 stub agsDriverExtensionsDX11_SetDiskShaderCacheEnabled -23 stub agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount -24 stub agsDriverExtensionsDX11_SetViewBroadcastMasks -25 stub agsDriverExtensionsDX12_DeInit -26 stub agsDriverExtensionsDX12_Init -27 stdcall agsGetCrossfireGPUCount(ptr ptr) -28 stdcall agsInit(ptr ptr ptr) -29 stub agsSetDisplayMode +@ stdcall agsDeInit(ptr) +@ stub agsDriverExtensionsDX11_BeginUAVOverlap +@ stub agsDriverExtensionsDX11_CreateBuffer +@ stub agsDriverExtensionsDX11_CreateTexture1D +@ stub agsDriverExtensionsDX11_CreateTexture2D +@ stub agsDriverExtensionsDX11_CreateTexture3D +@ stub agsDriverExtensionsDX11_DeInit +@ stub agsDriverExtensionsDX11_EndUAVOverlap +@ stub agsDriverExtensionsDX11_GetMaxClipRects +@ stub agsDriverExtensionsDX11_IASetPrimitiveTopology +@ stub agsDriverExtensionsDX11_Init +@ stub agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect +@ stub agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect +@ stub agsDriverExtensionsDX11_MultiDrawInstancedIndirect +@ stub agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect +@ stub agsDriverExtensionsDX11_NotifyResourceBeginAllAccess +@ stub agsDriverExtensionsDX11_NotifyResourceEndAllAccess +@ stub agsDriverExtensionsDX11_NotifyResourceEndWrites +@ stub agsDriverExtensionsDX11_NumPendingAsyncCompileJobs +@ stub agsDriverExtensionsDX11_SetClipRects +@ stub agsDriverExtensionsDX11_SetDepthBounds +@ stub agsDriverExtensionsDX11_SetDiskShaderCacheEnabled +@ stub agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount +@ stub agsDriverExtensionsDX11_SetViewBroadcastMasks +@ stub agsDriverExtensionsDX12_DeInit +@ stub agsDriverExtensionsDX12_Init +@ stdcall agsGetCrossfireGPUCount(ptr ptr) +@ stdcall agsInit(ptr ptr ptr) +@ stub agsSetDisplayMode From 9e3a6c0f07f9eeab0ae5b28545029881bfa4dd96 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 16 Apr 2021 20:07:28 +0300 Subject: [PATCH 0339/2777] amd_ags_x64: Add more stubs to spec file. For Forza Horizon 4. --- dlls/amd_ags_x64/amd_ags_x64.spec | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec index c571dac2184..f483cc6380b 100644 --- a/dlls/amd_ags_x64/amd_ags_x64.spec +++ b/dlls/amd_ags_x64/amd_ags_x64.spec @@ -1,10 +1,15 @@ @ stdcall agsDeInit(ptr) +@ stub agsCheckDriverVersion @ stub agsDriverExtensionsDX11_BeginUAVOverlap @ stub agsDriverExtensionsDX11_CreateBuffer +@ stub agsDriverExtensionsDX11_CreateDevice +@ stub agsDriverExtensionsDX11_CreateFromDevice @ stub agsDriverExtensionsDX11_CreateTexture1D @ stub agsDriverExtensionsDX11_CreateTexture2D @ stub agsDriverExtensionsDX11_CreateTexture3D @ stub agsDriverExtensionsDX11_DeInit +@ stub agsDriverExtensionsDX11_Destroy +@ stub agsDriverExtensionsDX11_DestroyDevice @ stub agsDriverExtensionsDX11_EndUAVOverlap @ stub agsDriverExtensionsDX11_GetMaxClipRects @ stub agsDriverExtensionsDX11_IASetPrimitiveTopology @@ -22,8 +27,16 @@ @ stub agsDriverExtensionsDX11_SetDiskShaderCacheEnabled @ stub agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount @ stub agsDriverExtensionsDX11_SetViewBroadcastMasks +@ stub agsDriverExtensionsDX11_WriteBreadcrumb +@ stub agsDriverExtensionsDX12_CreateDevice +@ stub agsDriverExtensionsDX12_CreateFromDevice @ stub agsDriverExtensionsDX12_DeInit +@ stub agsDriverExtensionsDX12_Destroy +@ stub agsDriverExtensionsDX12_DestroyDevice @ stub agsDriverExtensionsDX12_Init +@ stub agsDriverExtensionsDX12_PopMarker +@ stub agsDriverExtensionsDX12_PushMarker +@ stub agsDriverExtensionsDX12_SetMarker @ stdcall agsGetCrossfireGPUCount(ptr ptr) @ stdcall agsInit(ptr ptr ptr) @ stub agsSetDisplayMode From 3db06d775be0c2cdb30566dea3aa657e5085d4c6 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 16 Apr 2021 20:30:22 +0300 Subject: [PATCH 0340/2777] amd_ags_x64: Add partial stub for agsCheckDriverVersion(). For Forza Horizon 4. --- dlls/amd_ags_x64/amd_ags_x64.spec | 2 +- dlls/amd_ags_x64/amd_ags_x64_main.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec index f483cc6380b..6806b145751 100644 --- a/dlls/amd_ags_x64/amd_ags_x64.spec +++ b/dlls/amd_ags_x64/amd_ags_x64.spec @@ -1,5 +1,5 @@ @ stdcall agsDeInit(ptr) -@ stub agsCheckDriverVersion +@ stdcall agsCheckDriverVersion(ptr long) @ stub agsDriverExtensionsDX11_BeginUAVOverlap @ stub agsDriverExtensionsDX11_CreateBuffer @ stub agsDriverExtensionsDX11_CreateDevice diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index b2f8149bcd8..d4bc099dedb 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -356,6 +356,13 @@ AGSReturnCode WINAPI agsGetCrossfireGPUCount(AGSContext *context, int *gpu_count return AGS_SUCCESS; } +AGSDriverVersionResult WINAPI agsCheckDriverVersion(const char* version_reported, unsigned int version_required) +{ + FIXME("version_reported %s, version_required %d semi-stub.\n", debugstr_a(version_reported), version_required); + + return AGS_SOFTWAREVERSIONCHECK_OK; +} + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { TRACE("%p, %u, %p.\n", instance, reason, reserved); From 91e3589b64c470fd27991bc7ec9ef3c33c31f1f4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 16 Apr 2021 20:35:31 +0300 Subject: [PATCH 0341/2777] amd_ags_x64: Implement agsDriverExtensionsDX12_CreateDevice(). For Forza Horizon 4. --- dlls/amd_ags_x64/amd_ags_x64.spec | 2 +- dlls/amd_ags_x64/amd_ags_x64_main.c | 43 +++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec index 6806b145751..7551a9346d8 100644 --- a/dlls/amd_ags_x64/amd_ags_x64.spec +++ b/dlls/amd_ags_x64/amd_ags_x64.spec @@ -28,7 +28,7 @@ @ stub agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount @ stub agsDriverExtensionsDX11_SetViewBroadcastMasks @ stub agsDriverExtensionsDX11_WriteBreadcrumb -@ stub agsDriverExtensionsDX12_CreateDevice +@ stdcall agsDriverExtensionsDX12_CreateDevice(ptr ptr ptr ptr) @ stub agsDriverExtensionsDX12_CreateFromDevice @ stub agsDriverExtensionsDX12_DeInit @ stub agsDriverExtensionsDX12_Destroy diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index d4bc099dedb..f54b40da609 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -52,6 +52,21 @@ struct AGSContext VkPhysicalDeviceMemoryProperties *memory_properties; }; +static HMODULE hd3d12; +static typeof(D3D12CreateDevice) *pD3D12CreateDevice; + +static BOOL load_d3d12_functions(void) +{ + if (hd3d12) + return TRUE; + + if (!(hd3d12 = LoadLibraryA("d3d12.dll"))) + return FALSE; + + pD3D12CreateDevice = (void *)GetProcAddress(hd3d12, "D3D12CreateDevice"); + return TRUE; +} + static AGSReturnCode vk_get_physical_device_properties(unsigned int *out_count, VkPhysicalDeviceProperties **out, VkPhysicalDeviceMemoryProperties **out_memory) { @@ -356,6 +371,34 @@ AGSReturnCode WINAPI agsGetCrossfireGPUCount(AGSContext *context, int *gpu_count return AGS_SUCCESS; } +AGSReturnCode WINAPI agsDriverExtensionsDX12_CreateDevice(AGSContext *context, + const AGSDX12DeviceCreationParams *creation_params, const AGSDX12ExtensionParams *extension_params, + AGSDX12ReturnedParams *returned_params) +{ + HRESULT hr; + + TRACE("feature level %#x, app %s, engine %s %#x %#x.\n", creation_params->FeatureLevel, debugstr_w(extension_params->pAppName), + debugstr_w(extension_params->pEngineName), extension_params->appVersion, extension_params->engineVersion); + + if (!load_d3d12_functions()) + { + ERR("Could not load d3d12.dll.\n"); + return AGS_MISSING_D3D_DLL; + } + + memset(returned_params, 0, sizeof(*returned_params)); + if (FAILED(hr = pD3D12CreateDevice((IUnknown *)creation_params->pAdapter, creation_params->FeatureLevel, + &creation_params->iid, (void **)&returned_params->pDevice))) + { + ERR("D3D12CreateDevice failed, hr %#x.\n", hr); + return AGS_DX_FAILURE; + } + + TRACE("Created d3d12 device %p.\n", returned_params->pDevice); + + return AGS_SUCCESS; +} + AGSDriverVersionResult WINAPI agsCheckDriverVersion(const char* version_reported, unsigned int version_required) { FIXME("version_reported %s, version_required %d semi-stub.\n", debugstr_a(version_reported), version_required); From 21eff8f859a65c37a51211a50f44fec0fa83da51 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 16 Apr 2021 17:29:31 +0300 Subject: [PATCH 0342/2777] amd_ags_x64: Fix devices array layout. And refactor multiple layout device structure handling on the way to avoid more switches in future patches. For Forza Horizon 4. --- dlls/amd_ags_x64/amd_ags.h | 10 +- dlls/amd_ags_x64/amd_ags_x64_main.c | 152 +++++++++++++++------------- 2 files changed, 83 insertions(+), 79 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h index 30f3735915c..47ed5b91a14 100644 --- a/dlls/amd_ags_x64/amd_ags.h +++ b/dlls/amd_ags_x64/amd_ags.h @@ -498,13 +498,7 @@ typedef struct AGSDeviceInfo_541 int adlAdapterIndex; ///< Internally used index into the ADL list of adapters } AGSDeviceInfo_541; -typedef union AGSDeviceInfo -{ - AGSDeviceInfo_511 agsDeviceInfo511; - AGSDeviceInfo_520 agsDeviceInfo520; - AGSDeviceInfo_540 agsDeviceInfo540; - AGSDeviceInfo_541 agsDeviceInfo541; -} AGSDeviceInfo; +struct AGSDeviceInfo; /// \defgroup general General API functions /// API for initialization, cleanup, HDR display modes and Crossfire GPU count @@ -545,7 +539,7 @@ typedef struct AGSGPUInfo const char* radeonSoftwareVersion; ///< The Radeon Software Version int numDevices; ///< Number of GPUs in the system - AGSDeviceInfo* devices; ///< List of GPUs in the system + struct AGSDeviceInfo* devices; ///< List of GPUs in the system } AGSGPUInfo; /// The struct to specify the display settings to the driver. diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index f54b40da609..1669f08fae7 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -1,5 +1,6 @@ #include #include +#include #include "windef.h" #include "winbase.h" @@ -27,27 +28,74 @@ enum amd_ags_version AMD_AGS_VERSION_COUNT }; -struct +static const struct { int major; int minor; int patch; + unsigned int device_size; } -static const amd_ags_versions[AMD_AGS_VERSION_COUNT] = +amd_ags_info[AMD_AGS_VERSION_COUNT] = { - {5, 1, 1}, - {5, 2, 0}, - {5, 2, 1}, - {5, 3, 0}, - {5, 4, 0}, - {5, 4, 1}, + {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)}, }; +#define DEF_FIELD(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ + offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ + offsetof(AGSDeviceInfo_541, name)}} +#define DEF_FIELD_520_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ + offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), -1, \ + -1}} +#define DEF_FIELD_540_UP(name) {DEVICE_FIELD_##name, {-1, -1, \ + -1, -1, offsetof(AGSDeviceInfo_540, name), \ + offsetof(AGSDeviceInfo_541, name)}} + +#define DEVICE_FIELD_adapterString 0 +#define DEVICE_FIELD_architectureVersion 1 +#define DEVICE_FIELD_asicFamily 2 +#define DEVICE_FIELD_vendorId 3 +#define DEVICE_FIELD_deviceId 4 +#define DEVICE_FIELD_isPrimaryDevice 5 +#define DEVICE_FIELD_localMemoryInBytes 6 + +static const struct +{ + unsigned int field_index; + int offset[AMD_AGS_VERSION_COUNT]; +} +device_struct_fields[] = +{ + DEF_FIELD(adapterString), + DEF_FIELD_520_BELOW(architectureVersion), + DEF_FIELD_540_UP(asicFamily), + DEF_FIELD(vendorId), + DEF_FIELD(deviceId), + DEF_FIELD(isPrimaryDevice), + DEF_FIELD(localMemoryInBytes), +}; + +#undef DEF_FIELD + +#define GET_DEVICE_FIELD_ADDR(device, name, type, version) \ + (device_struct_fields[DEVICE_FIELD_##name].offset[version] == -1 ? NULL \ + : (type *)((BYTE *)device + device_struct_fields[DEVICE_FIELD_##name].offset[version])) + +#define SET_DEVICE_FIELD(device, name, type, version, value) { \ + type *addr; \ + if ((addr = GET_DEVICE_FIELD_ADDR(device, name, type, version))) \ + *addr = value; \ + } + struct AGSContext { enum amd_ags_version version; unsigned int device_count; - AGSDeviceInfo *devices; + struct AGSDeviceInfo *devices; VkPhysicalDeviceProperties *properties; VkPhysicalDeviceMemoryProperties *memory_properties; }; @@ -190,11 +238,11 @@ static enum amd_ags_version determine_ags_version(void) patch = info->dwFileVersionLS >> 16; TRACE("Found amd_ags_x64.dll v%d.%d.%d\n", major, minor, patch); - for (i = 0; i < ARRAY_SIZE(amd_ags_versions); i++) + for (i = 0; i < ARRAY_SIZE(amd_ags_info); i++) { - if ((major == amd_ags_versions[i].major) && - (minor == amd_ags_versions[i].minor) && - (patch == amd_ags_versions[i].patch)) + if ((major == amd_ags_info[i].major) && + (minor == amd_ags_info[i].minor) && + (patch == amd_ags_info[i].patch)) { ret = i; break; @@ -204,7 +252,7 @@ static enum amd_ags_version determine_ags_version(void) done: heap_free(infobuf); TRACE("Using AGS v%d.%d.%d interface\n", - amd_ags_versions[ret].major, amd_ags_versions[ret].minor, amd_ags_versions[ret].patch); + amd_ags_info[ret].major, amd_ags_info[ret].minor, amd_ags_info[ret].patch); return ret; } @@ -212,6 +260,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) { AGSReturnCode ret; unsigned int i, j; + BYTE *device; context->version = determine_ags_version(); context->device_count = 0; @@ -223,7 +272,9 @@ static AGSReturnCode init_ags_context(AGSContext *context) if (ret != AGS_SUCCESS || !context->device_count) return ret; - if (!(context->devices = heap_calloc(context->device_count, sizeof(*context->devices)))) + assert(context->version < AMD_AGS_VERSION_COUNT); + + if (!(context->devices = heap_calloc(context->device_count, amd_ags_info[context->version].device_size))) { WARN("Failed to allocate memory.\n"); heap_free(context->properties); @@ -231,11 +282,11 @@ static AGSReturnCode init_ags_context(AGSContext *context) return AGS_OUT_OF_MEMORY; } + device = (BYTE *)context->devices; for (i = 0; i < context->device_count; ++i) { const VkPhysicalDeviceProperties *vk_properties = &context->properties[i]; const VkPhysicalDeviceMemoryProperties *vk_memory_properties = &context->memory_properties[i]; - AGSDeviceInfo *device = &context->devices[i]; VkDeviceSize local_memory_size = 0; for (j = 0; j < vk_memory_properties->memoryHeapCount; j++) @@ -248,60 +299,19 @@ static AGSReturnCode init_ags_context(AGSContext *context) } TRACE("reporting local memory size 0x%s bytes\n", wine_dbgstr_longlong(local_memory_size)); - switch (context->version) + SET_DEVICE_FIELD(device, adapterString, const char *, context->version, vk_properties->deviceName); + SET_DEVICE_FIELD(device, vendorId, int, context->version, vk_properties->vendorID); + SET_DEVICE_FIELD(device, deviceId, int, context->version, vk_properties->deviceID); + if (vk_properties->vendorID == 0x1002) { - case AMD_AGS_VERSION_5_1_1: - device->agsDeviceInfo511.adapterString = vk_properties->deviceName; - device->agsDeviceInfo511.vendorId = vk_properties->vendorID; - device->agsDeviceInfo511.deviceId = vk_properties->deviceID; - device->agsDeviceInfo511.localMemoryInBytes = local_memory_size; - - if (device->agsDeviceInfo511.vendorId == 0x1002) - device->agsDeviceInfo511.architectureVersion = ArchitectureVersion_GCN; - - if (!i) - device->agsDeviceInfo511.isPrimaryDevice = 1; - break; - case AMD_AGS_VERSION_5_2_0: - case AMD_AGS_VERSION_5_2_1: - case AMD_AGS_VERSION_5_3_0: - device->agsDeviceInfo520.adapterString = vk_properties->deviceName; - device->agsDeviceInfo520.vendorId = vk_properties->vendorID; - device->agsDeviceInfo520.deviceId = vk_properties->deviceID; - device->agsDeviceInfo520.localMemoryInBytes = local_memory_size; - - if (device->agsDeviceInfo520.vendorId == 0x1002) - device->agsDeviceInfo520.architectureVersion = ArchitectureVersion_GCN; - - if (!i) - device->agsDeviceInfo520.isPrimaryDevice = 1; - break; - case AMD_AGS_VERSION_5_4_0: - device->agsDeviceInfo540.adapterString = vk_properties->deviceName; - device->agsDeviceInfo540.vendorId = vk_properties->vendorID; - device->agsDeviceInfo540.deviceId = vk_properties->deviceID; - device->agsDeviceInfo540.localMemoryInBytes = local_memory_size; - - if (device->agsDeviceInfo540.vendorId == 0x1002) - device->agsDeviceInfo540.asicFamily = AsicFamily_GCN4; - - if (!i) - device->agsDeviceInfo540.isPrimaryDevice = 1; - break; - case AMD_AGS_VERSION_5_4_1: - default: - device->agsDeviceInfo541.adapterString = vk_properties->deviceName; - device->agsDeviceInfo541.vendorId = vk_properties->vendorID; - device->agsDeviceInfo541.deviceId = vk_properties->deviceID; - device->agsDeviceInfo541.localMemoryInBytes = local_memory_size; - - if (device->agsDeviceInfo541.vendorId == 0x1002) - device->agsDeviceInfo541.asicFamily = AsicFamily_GCN4; - - if (!i) - device->agsDeviceInfo541.isPrimaryDevice = 1; - break; + SET_DEVICE_FIELD(device, architectureVersion, ArchitectureVersion, context->version, ArchitectureVersion_GCN); + SET_DEVICE_FIELD(device, asicFamily, AsicFamily, context->version, AsicFamily_GCN4); } + SET_DEVICE_FIELD(device, localMemoryInBytes, ULONG64, context->version, local_memory_size); + if (!i) + SET_DEVICE_FIELD(device, isPrimaryDevice, int, context->version, 1); + + device += amd_ags_info[context->version].device_size; } return AGS_SUCCESS; @@ -330,9 +340,9 @@ AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *confi } memset(gpu_info, 0, sizeof(*gpu_info)); - gpu_info->agsVersionMajor = amd_ags_versions[object->version].major; - gpu_info->agsVersionMinor = amd_ags_versions[object->version].minor; - gpu_info->agsVersionPatch = amd_ags_versions[object->version].patch; + gpu_info->agsVersionMajor = amd_ags_info[object->version].major; + gpu_info->agsVersionMinor = amd_ags_info[object->version].minor; + gpu_info->agsVersionPatch = amd_ags_info[object->version].patch; gpu_info->driverVersion = "20.20.2-180516a-328911C-RadeonSoftwareAdrenalin"; gpu_info->radeonSoftwareVersion = "20.20.2"; gpu_info->numDevices = object->device_count; From a8f2451446c6e0a49d447a52b00051b8d1712e1f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 16 Apr 2021 19:33:36 +0300 Subject: [PATCH 0343/2777] amd_ags_x64: Fill display info in AGS context. For Forza Horizon 4. --- dlls/amd_ags_x64/Makefile.in | 2 +- dlls/amd_ags_x64/amd_ags_x64_main.c | 130 +++++++++++++++++++++++++++- 2 files changed, 130 insertions(+), 2 deletions(-) diff --git a/dlls/amd_ags_x64/Makefile.in b/dlls/amd_ags_x64/Makefile.in index 910cc7d50c5..4e3cd326d2f 100644 --- a/dlls/amd_ags_x64/Makefile.in +++ b/dlls/amd_ags_x64/Makefile.in @@ -1,6 +1,6 @@ EXTRADEFS = -DWINE_NO_LONG_TYPES MODULE = amd_ags_x64.dll -IMPORTS = version vulkan-1 +IMPORTS = version vulkan-1 user32 IMPORTLIB = amd_ags_x64 EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 1669f08fae7..0b56fdf477c 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -62,6 +62,8 @@ amd_ags_info[AMD_AGS_VERSION_COUNT] = #define DEVICE_FIELD_deviceId 4 #define DEVICE_FIELD_isPrimaryDevice 5 #define DEVICE_FIELD_localMemoryInBytes 6 +#define DEVICE_FIELD_numDisplays 7 +#define DEVICE_FIELD_displays 8 static const struct { @@ -77,6 +79,8 @@ device_struct_fields[] = DEF_FIELD(deviceId), DEF_FIELD(isPrimaryDevice), DEF_FIELD(localMemoryInBytes), + DEF_FIELD(numDisplays), + DEF_FIELD(displays), }; #undef DEF_FIELD @@ -256,6 +260,116 @@ static enum amd_ags_version determine_ags_version(void) return ret; } +struct monitor_enum_context +{ + const char *adapter_name; + AGSDisplayInfo **ret_displays; + int *ret_display_count; +}; + +static BOOL WINAPI monitor_enum_proc(HMONITOR hmonitor, HDC hdc, RECT *rect, LPARAM context) +{ + struct monitor_enum_context *c = (struct monitor_enum_context *)context; + MONITORINFOEXA monitor_info; + AGSDisplayInfo *new_alloc; + DISPLAY_DEVICEA device; + AGSDisplayInfo *info; + unsigned int i, mode; + DEVMODEA dev_mode; + + + monitor_info.cbSize = sizeof(monitor_info); + GetMonitorInfoA(hmonitor, (MONITORINFO *)&monitor_info); + TRACE("monitor_info.szDevice %s.\n", debugstr_a(monitor_info.szDevice)); + + device.cb = sizeof(device); + i = 0; + while (EnumDisplayDevicesA(NULL, i, &device, 0)) + { + TRACE("device.DeviceName %s, device.DeviceString %s.\n", debugstr_a(device.DeviceName), debugstr_a(device.DeviceString)); + ++i; + if (strcmp(device.DeviceString, c->adapter_name) || strcmp(device.DeviceName, monitor_info.szDevice)) + continue; + + if (*c->ret_display_count) + { + if (!(new_alloc = heap_realloc(*c->ret_displays, sizeof(*new_alloc) * (*c->ret_display_count + 1)))) + { + ERR("No memory."); + return FALSE; + } + *c->ret_displays = new_alloc; + } + else if (!(*c->ret_displays = heap_alloc(sizeof(**c->ret_displays)))) + { + ERR("No memory."); + return FALSE; + } + info = &(*c->ret_displays)[*c->ret_display_count]; + memset(info, 0, sizeof(*info)); + strcpy(info->displayDeviceName, device.DeviceName); + if (EnumDisplayDevicesA(info->displayDeviceName, 0, &device, 0)) + { + strcpy(info->name, device.DeviceString); + } + else + { + ERR("Could not get monitor name for device %s.\n", debugstr_a(info->displayDeviceName)); + strcpy(info->name, "Unknown"); + } + if (monitor_info.dwFlags & MONITORINFOF_PRIMARY) + info->displayFlags |= AGS_DISPLAYFLAG_PRIMARY_DISPLAY; + + mode = 0; + memset(&dev_mode, 0, sizeof(dev_mode)); + dev_mode.dmSize = sizeof(dev_mode); + while (EnumDisplaySettingsExA(monitor_info.szDevice, mode, &dev_mode, EDS_RAWMODE)) + { + ++mode; + if (dev_mode.dmPelsWidth > info->maxResolutionX) + info->maxResolutionX = dev_mode.dmPelsWidth; + if (dev_mode.dmPelsHeight > info->maxResolutionY) + info->maxResolutionY = dev_mode.dmPelsHeight; + if (dev_mode.dmDisplayFrequency > info->maxRefreshRate) + info->maxRefreshRate = dev_mode.dmDisplayFrequency; + memset(&dev_mode, 0, sizeof(dev_mode)); + dev_mode.dmSize = sizeof(dev_mode); + } + + info->currentResolution.offsetX = monitor_info.rcMonitor.left; + info->currentResolution.offsetY = monitor_info.rcMonitor.top; + info->currentResolution.width = monitor_info.rcMonitor.right - monitor_info.rcMonitor.left; + info->currentResolution.height = monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top; + info->visibleResolution = info->currentResolution; + + memset(&dev_mode, 0, sizeof(dev_mode)); + dev_mode.dmSize = sizeof(dev_mode); + + if (EnumDisplaySettingsExA(monitor_info.szDevice, ENUM_CURRENT_SETTINGS, &dev_mode, EDS_RAWMODE)) + info->currentRefreshRate = dev_mode.dmDisplayFrequency; + else + ERR("Could not get current display settings.\n"); + ++*c->ret_display_count; + + TRACE("Added display %s for %s.\n", debugstr_a(monitor_info.szDevice), debugstr_a(c->adapter_name)); + } + + return TRUE; +} + +static void init_device_displays(const char *adapter_name, AGSDisplayInfo **ret_displays, int *ret_display_count) +{ + struct monitor_enum_context context; + + TRACE("adapter_name %s.\n", debugstr_a(adapter_name)); + + context.adapter_name = adapter_name; + context.ret_displays = ret_displays; + context.ret_display_count = ret_display_count; + + EnumDisplayMonitors(NULL, NULL, monitor_enum_proc, (LPARAM)&context); +} + static AGSReturnCode init_ags_context(AGSContext *context) { AGSReturnCode ret; @@ -297,7 +411,8 @@ static AGSReturnCode init_ags_context(AGSContext *context) break; } } - TRACE("reporting local memory size 0x%s bytes\n", wine_dbgstr_longlong(local_memory_size)); + TRACE("device %s, %04x:%04x, reporting local memory size 0x%s bytes\n", debugstr_a(vk_properties->deviceName), + vk_properties->vendorID, vk_properties->deviceID, wine_dbgstr_longlong(local_memory_size)); SET_DEVICE_FIELD(device, adapterString, const char *, context->version, vk_properties->deviceName); SET_DEVICE_FIELD(device, vendorId, int, context->version, vk_properties->vendorID); @@ -311,6 +426,10 @@ static AGSReturnCode init_ags_context(AGSContext *context) if (!i) SET_DEVICE_FIELD(device, isPrimaryDevice, int, context->version, 1); + init_device_displays(vk_properties->deviceName, + GET_DEVICE_FIELD_ADDR(device, displays, AGSDisplayInfo *, context->version), + GET_DEVICE_FIELD_ADDR(device, numDisplays, int, context->version)); + device += amd_ags_info[context->version].device_size; } @@ -357,12 +476,21 @@ AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *confi AGSReturnCode WINAPI agsDeInit(AGSContext *context) { + unsigned int i; + BYTE *device; + TRACE("context %p.\n", context); if (context) { heap_free(context->memory_properties); heap_free(context->properties); + device = (BYTE *)context->devices; + for (i = 0; i < context->device_count; ++i) + { + heap_free(*GET_DEVICE_FIELD_ADDR(device, displays, AGSDisplayInfo *, context->version)); + device += amd_ags_info[context->version].device_size; + } heap_free(context->devices); heap_free(context); } From 3cfcbb41b49b04430736f14ead75b18806c3d611 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 16 Apr 2021 20:03:12 +0300 Subject: [PATCH 0344/2777] amd_ags_x64: Bump driver version. For Forza Horizon 4. --- dlls/amd_ags_x64/amd_ags_x64_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 0b56fdf477c..3a4dafa7a3a 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -462,8 +462,8 @@ AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *confi gpu_info->agsVersionMajor = amd_ags_info[object->version].major; gpu_info->agsVersionMinor = amd_ags_info[object->version].minor; gpu_info->agsVersionPatch = amd_ags_info[object->version].patch; - gpu_info->driverVersion = "20.20.2-180516a-328911C-RadeonSoftwareAdrenalin"; - gpu_info->radeonSoftwareVersion = "20.20.2"; + gpu_info->driverVersion = "20.50.03.05-210326a-365573E-RadeonSoftwareAdrenalin2020"; + gpu_info->radeonSoftwareVersion = "21.3.2"; gpu_info->numDevices = object->device_count; gpu_info->devices = object->devices; From 9392cbcb656f151fba2d65b343f6ac4205576cb2 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 8 May 2021 04:39:30 +0100 Subject: [PATCH 0345/2777] amd_ags_x64: Implement agsDriverExtensionsDX12_DestroyDevice Signed-off-by: Joshua Ashton --- dlls/amd_ags_x64/amd_ags_x64.spec | 2 +- dlls/amd_ags_x64/amd_ags_x64_main.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec index 7551a9346d8..ae825462f28 100644 --- a/dlls/amd_ags_x64/amd_ags_x64.spec +++ b/dlls/amd_ags_x64/amd_ags_x64.spec @@ -32,7 +32,7 @@ @ stub agsDriverExtensionsDX12_CreateFromDevice @ stub agsDriverExtensionsDX12_DeInit @ stub agsDriverExtensionsDX12_Destroy -@ stub agsDriverExtensionsDX12_DestroyDevice +@ stdcall agsDriverExtensionsDX12_DestroyDevice(ptr ptr ptr) @ stub agsDriverExtensionsDX12_Init @ stub agsDriverExtensionsDX12_PopMarker @ stub agsDriverExtensionsDX12_PushMarker diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 3a4dafa7a3a..81942e4041e 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -9,6 +9,7 @@ #include "wine/vulkan.h" +#define COBJMACROS #include "d3d11.h" #include "d3d12.h" @@ -537,6 +538,20 @@ AGSReturnCode WINAPI agsDriverExtensionsDX12_CreateDevice(AGSContext *context, return AGS_SUCCESS; } +AGSReturnCode WINAPI agsDriverExtensionsDX12_DestroyDevice(AGSContext* context, ID3D12Device* device, unsigned int* device_refs) +{ + ULONG ref_count; + + if (!device) + return AGS_SUCCESS; + + ref_count = ID3D12Device_Release(device); + if (device_refs) + *device_refs = (unsigned int)ref_count; + + return AGS_SUCCESS; +} + AGSDriverVersionResult WINAPI agsCheckDriverVersion(const char* version_reported, unsigned int version_required) { FIXME("version_reported %s, version_required %d semi-stub.\n", debugstr_a(version_reported), version_required); From b556ee5bf66bf61a7728bef0f8cf55d4e62d534f Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 8 May 2021 04:41:40 +0100 Subject: [PATCH 0346/2777] amd_ags_x64: Implement AGS 5.4.2 Signed-off-by: Joshua Ashton --- dlls/amd_ags_x64/amd_ags.h | 46 ++++++++++++++++++++++++++++- dlls/amd_ags_x64/amd_ags_x64_main.c | 8 +++-- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h index 47ed5b91a14..0656e3fbbb3 100644 --- a/dlls/amd_ags_x64/amd_ags.h +++ b/dlls/amd_ags_x64/amd_ags.h @@ -34,6 +34,13 @@ /// \endinternal /// /// --------------------------------------- +/// What's new in AGS 5.4.2 since version 5.4.1 +/// --------------------------------------- +/// AGS 5.4.2 includes the following updates: +/// * sharedMemoryInBytes has been reinstated. +/// * Clock speed returned for APUs. +/// +/// --------------------------------------- /// What's new in AGS 5.4.1 since version 5.4.0 /// --------------------------------------- /// AGS 5.4.1 includes the following updates: @@ -130,7 +137,7 @@ #define AMD_AGS_VERSION_MAJOR 5 ///< AGS major version #define AMD_AGS_VERSION_MINOR 4 ///< AGS minor version -#define AMD_AGS_VERSION_PATCH 1 ///< AGS patch version +#define AMD_AGS_VERSION_PATCH 2 ///< AGS patch version #ifdef __cplusplus extern "C" { @@ -498,6 +505,43 @@ typedef struct AGSDeviceInfo_541 int adlAdapterIndex; ///< Internally used index into the ADL list of adapters } AGSDeviceInfo_541; +/// The device info struct used to describe a physical GPU enumerated by AGS +typedef struct AGSDeviceInfo_542 +{ + const char* adapterString; ///< The adapter name string + AsicFamily asicFamily; ///< Set to Unknown if not AMD hardware + int isAPU; ///< Whether or not this is an APU + int vendorId; ///< The vendor id + int deviceId; ///< The device id + int revisionId; ///< The revision id + + int numCUs; ///< Number of compute units. + int numWGPs; ///< Number of RDNA Work Group Processors. Only valid if ASIC is RDNA onwards. + + int numROPs; ///< Number of ROPs + int coreClock; ///< Core clock speed at 100% power in MHz + int memoryClock; ///< Memory clock speed at 100% power in MHz + int memoryBandwidth; ///< Memory bandwidth in MB/s + float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD + + int isPrimaryDevice; ///< Whether or not this is the primary adapter in the system. Not set on the WACK version. + unsigned long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. + unsigned long long sharedMemoryInBytes; ///< The size of system memory available to the GPU in bytes. It is important to factor this into your VRAM budget for APUs + ///< as the reported local memory will only be a small fraction of the total memory available to the GPU. + + int numDisplays; ///< The number of active displays found to be attached to this adapter. + AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. + + int eyefinityEnabled; ///< Indicates if Eyefinity is active + int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. + int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. + int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. + + int adlAdapterIndex; ///< Internally used index into the ADL list of adapters +} AGSDeviceInfo_542; + struct AGSDeviceInfo; /// \defgroup general General API functions diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 81942e4041e..750401a845e 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -25,6 +25,7 @@ enum amd_ags_version AMD_AGS_VERSION_5_3_0, AMD_AGS_VERSION_5_4_0, AMD_AGS_VERSION_5_4_1, + AMD_AGS_VERSION_5_4_2, AMD_AGS_VERSION_COUNT }; @@ -44,17 +45,18 @@ amd_ags_info[AMD_AGS_VERSION_COUNT] = {5, 3, 0, sizeof(AGSDeviceInfo_520)}, {5, 4, 0, sizeof(AGSDeviceInfo_540)}, {5, 4, 1, sizeof(AGSDeviceInfo_541)}, + {5, 4, 2, sizeof(AGSDeviceInfo_542)}, }; #define DEF_FIELD(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ - offsetof(AGSDeviceInfo_541, name)}} + offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name)}} #define DEF_FIELD_520_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), -1, \ - -1}} + -1, -1}} #define DEF_FIELD_540_UP(name) {DEVICE_FIELD_##name, {-1, -1, \ -1, -1, offsetof(AGSDeviceInfo_540, name), \ - offsetof(AGSDeviceInfo_541, name)}} + offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name)}} #define DEVICE_FIELD_adapterString 0 #define DEVICE_FIELD_architectureVersion 1 From a8c74d6daf9e28629a6f865afadfe9f08455279c Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 8 May 2021 05:14:39 +0100 Subject: [PATCH 0347/2777] amd_ags_x64: Implement AGS 6.0.0 Signed-off-by: Joshua Ashton --- dlls/amd_ags_x64/amd_ags.h | 409 +++++++++++++++++++++++----- dlls/amd_ags_x64/amd_ags_x64.spec | 3 + dlls/amd_ags_x64/amd_ags_x64_main.c | 137 ++++++++-- 3 files changed, 468 insertions(+), 81 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h index 0656e3fbbb3..af9c48c1dd5 100644 --- a/dlls/amd_ags_x64/amd_ags.h +++ b/dlls/amd_ags_x64/amd_ags.h @@ -34,6 +34,20 @@ /// \endinternal /// /// --------------------------------------- +/// What's new in AGS 6.0 since version 5.4.2 +/// --------------------------------------- +/// AGS 6.0 includes the following updates: +/// * DX12 ray tracing hit token for RDNA2 hardware. +/// * Shader intrinsic that exposes ReadLaneAt in DX12. +/// * Shader intrinsics that expose explicit float conversions in DX12. +/// * Refactored and revised API to minimize user error. +/// * Added agsGetVersionNumber. +/// * Detection for external GPUs. +/// * Detection of RDNA2 architecture. +/// * Grouped the more established intrinsics together into per year support. +/// * Function pointer typedefs for the API +/// +/// --------------------------------------- /// What's new in AGS 5.4.2 since version 5.4.1 /// --------------------------------------- /// AGS 5.4.2 includes the following updates: @@ -128,16 +142,16 @@ /// * Include the amd_ags.h header file from your source code. /// * Include the AGS hlsl files if you are using the shader intrinsics. /// * Declare a pointer to an AGSContext and make this available for all subsequent calls to AGS. -/// * On game initialization, call \ref agsInit passing in the address of the context. On success, this function will return a valid context pointer. +/// * On game initialization, call \ref agsInitialize passing in the address of the context. On success, this function will return a valid context pointer. /// -/// Don't forget to cleanup AGS by calling \ref agsDeInit when the app exits, after the device has been destroyed. +/// Don't forget to cleanup AGS by calling \ref agsDeInitialize when the app exits, after the device has been destroyed. #ifndef AMD_AGS_H #define AMD_AGS_H -#define AMD_AGS_VERSION_MAJOR 5 ///< AGS major version -#define AMD_AGS_VERSION_MINOR 4 ///< AGS minor version -#define AMD_AGS_VERSION_PATCH 2 ///< AGS patch version +#define AMD_AGS_VERSION_MAJOR 6 ///< AGS major version +#define AMD_AGS_VERSION_MINOR 0 ///< AGS minor version +#define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version #ifdef __cplusplus extern "C" { @@ -151,14 +165,17 @@ extern "C" { #define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version /// @} -// Forward declaration of D3D11 types +// Forward declaration of D3D and DXGI types struct IDXGIAdapter; +struct IDXGISwapChain; +struct DXGI_SWAP_CHAIN_DESC; enum D3D_DRIVER_TYPE; enum D3D_FEATURE_LEVEL; -struct DXGI_SWAP_CHAIN_DESC; + enum D3D_PRIMITIVE_TOPOLOGY; + +// Forward declaration of D3D11 types struct ID3D11Device; struct ID3D11DeviceContext; -struct IDXGISwapChain; struct ID3D11Resource; struct ID3D11Buffer; struct ID3D11Texture1D; @@ -253,14 +270,6 @@ typedef enum AGSDriverExtensionDX12 /// The space id for DirectX12 intrinsic support const unsigned int AGS_DX12_SHADER_INSTRINSICS_SPACE_ID = 0x7FFF0ADE; // 2147420894 - -/// Additional topologies supported via extensions -typedef enum AGSPrimitiveTopology -{ - AGS_PRIMITIVE_TOPOLOGY_QUADLIST = 7, ///< Quad list - AGS_PRIMITIVE_TOPOLOGY_SCREENRECTLIST = 9 ///< Screen rect list -} AGSPrimitiveTopology; - /// The display flags describing various properties of the display. typedef enum AGSDisplayFlags { @@ -282,7 +291,7 @@ typedef enum AGSDisplaySettingsFlags /// @} -typedef struct AGSContext AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInit +typedef struct AGSContext AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInitialize /// The rectangle struct used by AGS. typedef struct AGSRect @@ -293,25 +302,64 @@ typedef struct AGSRect int height; ///< Height of rectangle } AGSRect; -/// The clip rectangle struct used by \ref agsDriverExtensionsDX11_SetClipRects -typedef struct AGSClipRect +/// The display info struct used to describe a display enumerated by AGS +typedef struct AGSDisplayInfo_511 { - /// The inclusion mode for the rect - enum - { - ClipRectIncluded = 0, ///< Include the rect - ClipRectExcluded = 1 ///< Exclude the rect - } mode; ; ///< Include/exclude rect region - AGSRect rect; ///< The rect to include/exclude -} AGSClipRect; + char name[ 256 ]; ///< The name of the display + char displayDeviceName[ 32 ]; ///< The display device name, i.e. DISPLAY_DEVICE::DeviceName + + unsigned int displayFlags; ///< Bitfield of \ref AGSDisplayFlags + + int maxResolutionX; ///< The maximum supported resolution of the unrotated display + int maxResolutionY; ///< The maximum supported resolution of the unrotated display + float maxRefreshRate; ///< The maximum supported refresh rate of the display + + AGSRect currentResolution; ///< The current resolution and position in the desktop, ignoring Eyefinity bezel compensation + AGSRect visibleResolution; ///< The visible resolution and position. When Eyefinity bezel compensation is enabled this will + ///< be the sub region in the Eyefinity single large surface (SLS) + float currentRefreshRate; ///< The current refresh rate + + int eyefinityGridCoordX; ///< The X coordinate in the Eyefinity grid. -1 if not in an Eyefinity group + int eyefinityGridCoordY; ///< The Y coordinate in the Eyefinity grid. -1 if not in an Eyefinity group + + double chromaticityRedX; ///< Red display primary X coord + double chromaticityRedY; ///< Red display primary Y coord + + double chromaticityGreenX; ///< Green display primary X coord + double chromaticityGreenY; ///< Green display primary Y coord + + double chromaticityBlueX; ///< Blue display primary X coord + double chromaticityBlueY; ///< Blue display primary Y coord + + double chromaticityWhitePointX; ///< White point X coord + double chromaticityWhitePointY; ///< White point Y coord + + double screenDiffuseReflectance; ///< Percentage expressed between 0 - 1 + double screenSpecularReflectance; ///< Percentage expressed between 0 - 1 + + double minLuminance; ///< The minimum luminance of the display in nits + double maxLuminance; ///< The maximum luminance of the display in nits + double avgLuminance; ///< The average luminance of the display in nits + + int logicalDisplayIndex; ///< The internally used index of this display + int adlAdapterIndex; ///< The internally used ADL adapter index +} AGSDisplayInfo_511; /// The display info struct used to describe a display enumerated by AGS -typedef struct AGSDisplayInfo +typedef struct AGSDisplayInfo_600 { char name[ 256 ]; ///< The name of the display char displayDeviceName[ 32 ]; ///< The display device name, i.e. DISPLAY_DEVICE::DeviceName - unsigned int displayFlags; ///< Bitfield of \ref AGSDisplayFlags + unsigned int isPrimaryDisplay : 1; ///< Whether this display is marked as the primary display + unsigned int HDR10 : 1; ///< HDR10 is supported on this display + unsigned int dolbyVision : 1; ///< Dolby Vision is supported on this display + unsigned int freesync : 1; ///< Freesync is supported on this display + unsigned int freesyncHDR : 1; ///< Freesync HDR is supported on this display + unsigned int eyefinityInGroup : 1; ///< The display is part of the Eyefinity group + unsigned int eyefinityPreferredDisplay : 1; ///< The display is the preferred display in the Eyefinity group for displaying the UI + unsigned int eyefinityInPortraitMode : 1; ///< The display is in the Eyefinity group but in portrait mode + unsigned int reservedPadding : 24; ///< Reserved for future use int maxResolutionX; ///< The maximum supported resolution of the unrotated display int maxResolutionY; ///< The maximum supported resolution of the unrotated display @@ -346,7 +394,8 @@ typedef struct AGSDisplayInfo int logicalDisplayIndex; ///< The internally used index of this display int adlAdapterIndex; ///< The internally used ADL adapter index -} AGSDisplayInfo; + int reserved; ///< reserved field +} AGSDisplayInfo_600; /// The architecture version typedef enum ArchitectureVersion @@ -367,6 +416,7 @@ typedef enum AsicFamily AsicFamily_GCN4, ///< AMD GCN 4 architecture: Polaris. AsicFamily_Vega, ///< AMD Vega architecture, including Raven Ridge (ie AMD Ryzen CPU + AMD Vega GPU). AsicFamily_RDNA, ///< AMD RDNA architecture + AsicFamily_RDNA2, ///< AMD RDNA2 architecture AsicFamily_Count ///< Number of enumerated ASIC families } AsicFamily; @@ -389,7 +439,7 @@ typedef struct AGSDeviceInfo_511 long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. int numDisplays; ///< The number of active displays found to be attached to this adapter. - AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. + AGSDisplayInfo_511* displays; ///< List of displays allocated by AGS to be numDisplays in length. int eyefinityEnabled; ///< Indicates if Eyefinity is active int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. @@ -421,7 +471,7 @@ typedef struct AGSDeviceInfo_520 long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. int numDisplays; ///< The number of active displays found to be attached to this adapter. - AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. + AGSDisplayInfo_511* displays; ///< List of displays allocated by AGS to be numDisplays in length. int eyefinityEnabled; ///< Indicates if Eyefinity is active int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. @@ -458,7 +508,7 @@ typedef struct AGSDeviceInfo_540 ///< as the reported local memory will only be a small fraction of the total memory available to the GPU. int numDisplays; ///< The number of active displays found to be attached to this adapter. - AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. + AGSDisplayInfo_511* displays; ///< List of displays allocated by AGS to be numDisplays in length. int eyefinityEnabled; ///< Indicates if Eyefinity is active int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. @@ -493,7 +543,7 @@ typedef struct AGSDeviceInfo_541 long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. int numDisplays; ///< The number of active displays found to be attached to this adapter. - AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. + AGSDisplayInfo_511* displays; ///< List of displays allocated by AGS to be numDisplays in length. int eyefinityEnabled; ///< Indicates if Eyefinity is active int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. @@ -530,7 +580,7 @@ typedef struct AGSDeviceInfo_542 ///< as the reported local memory will only be a small fraction of the total memory available to the GPU. int numDisplays; ///< The number of active displays found to be attached to this adapter. - AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. + AGSDisplayInfo_511* displays; ///< List of displays allocated by AGS to be numDisplays in length. int eyefinityEnabled; ///< Indicates if Eyefinity is active int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. @@ -542,6 +592,47 @@ typedef struct AGSDeviceInfo_542 int adlAdapterIndex; ///< Internally used index into the ADL list of adapters } AGSDeviceInfo_542; +/// The device info struct used to describe a physical GPU enumerated by AGS +typedef struct AGSDeviceInfo_600 +{ + const char* adapterString; ///< The adapter name string + AsicFamily asicFamily; ///< Set to Unknown if not AMD hardware + unsigned int isAPU : 1; ///< Whether this device is an APU + unsigned int isPrimaryDevice : 1; ///< Whether this device is marked as the primary device + unsigned int isExternal :1; ///< Whether this device is a detachable, external device + unsigned int reservedPadding : 29; ///< Reserved for future use + + int vendorId; ///< The vendor id + int deviceId; ///< The device id + int revisionId; ///< The revision id + + int numCUs; ///< Number of compute units + int numWGPs; ///< Number of RDNA Work Group Processors. Only valid if ASIC is RDNA onwards. + + int numROPs; ///< Number of ROPs + int coreClock; ///< Core clock speed at 100% power in MHz + int memoryClock; ///< Memory clock speed at 100% power in MHz + int memoryBandwidth; ///< Memory bandwidth in MB/s + float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD + + unsigned long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. + unsigned long long sharedMemoryInBytes; ///< The size of system memory available to the GPU in bytes. It is important to factor this into your VRAM budget for APUs + ///< as the reported local memory will only be a small fraction of the total memory available to the GPU. + + int numDisplays; ///< The number of active displays found to be attached to this adapter. + AGSDisplayInfo_600* displays; ///< List of displays allocated by AGS to be numDisplays in length. + + int eyefinityEnabled; ///< Indicates if Eyefinity is active + int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. + int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. + int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. + int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. + + int adlAdapterIndex; ///< Internally used index into the ADL list of adapters + int reserved; ///< reserved field +} AGSDeviceInfo_600; + struct AGSDeviceInfo; /// \defgroup general General API functions @@ -552,7 +643,7 @@ typedef void* (__stdcall *AGS_ALLOC_CALLBACK_511)( int allocationSize ); ///< typedef void* (__stdcall *AGS_ALLOC_CALLBACK)( size_t allocationSize ); ///< AGS user defined allocation prototype typedef void (__stdcall *AGS_FREE_CALLBACK)( void* allocationPtr ); ///< AGS user defined free prototype -/// The configuration options that can be passed in to \ref agsInit +/// The configuration options that can be passed in to \ref agsInititalize typedef struct AGSConfiguration_511 { AGS_ALLOC_CALLBACK_511 allocCallback; ///< Optional memory allocation callback. If not supplied, malloc() is used @@ -571,8 +662,8 @@ typedef union AGSConfiguration AGSConfiguration_520 agsConfiguration520; } AGSConfiguration; -/// The top level GPU information returned from \ref agsInit -typedef struct AGSGPUInfo +/// The top level GPU information returned from \ref agsInitialize +typedef struct AGSGPUInfo_511 { int agsVersionMajor; ///< Major field of Major.Minor.Patch AGS version number int agsVersionMinor; ///< Minor field of Major.Minor.Patch AGS version number @@ -584,24 +675,35 @@ typedef struct AGSGPUInfo int numDevices; ///< Number of GPUs in the system struct AGSDeviceInfo* devices; ///< List of GPUs in the system -} AGSGPUInfo; +} AGSGPUInfo_511; -/// The struct to specify the display settings to the driver. -typedef struct AGSDisplaySettings +/// The top level GPU information returned from \ref agsInit +typedef struct AGSGPUInfo_600 { - /// The display mode - enum - { - Mode_SDR, ///< SDR mode - Mode_HDR10_PQ, ///< HDR10 PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. - Mode_HDR10_scRGB, ///< HDR10 scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. - Mode_FreesyncHDR_scRGB, ///< Freesync HDR scRGB, requiring an FP16 swapchain. A value of 1.0 == 80 nits. - // Mode_FreesyncHDR_Gamma22 ADDED IN 5.3.0 - Mode_FreesyncHDR_Gamma22, ///< Freesync HDR Gamma 2.2, requiring a 1010102 UNORM swapchain. The output needs to be encoded to gamma 2.2. - Mode_DolbyVision, ///< Dolby Vision, requiring an 8888 UNORM swapchain + const char* driverVersion; ///< The AMD driver package version + const char* radeonSoftwareVersion; ///< The Radeon Software Version + + int numDevices; ///< Number of GPUs in the system + struct AGSDeviceInfo* devices; ///< List of GPUs in the system +} AGSGPUInfo_600; - Mode_Count ///< Number of enumerated display modes - } mode; ///< The display mode to set the display into +/// The display mode +typedef enum AGSDisplaySettings_Mode +{ + Mode_SDR, ///< SDR mode + Mode_HDR10_PQ, ///< HDR10 PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. + Mode_HDR10_scRGB, ///< HDR10 scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. + Mode_FreesyncHDR_scRGB, ///< Freesync HDR scRGB, requiring an FP16 swapchain. A value of 1.0 == 80 nits. + Mode_FreesyncHDR_Gamma22, ///< Freesync HDR Gamma 2.2, requiring a 1010102 UNORM swapchain. The output needs to be encoded to gamma 2.2. + Mode_DolbyVision, ///< Dolby Vision, requiring an 8888 UNORM swapchain + + Mode_Count ///< Number of enumerated display modes +} AGSDisplaySettings_Mode; + +/// The struct to specify the display settings to the driver. +typedef struct AGSDisplaySettings_511 +{ + AGSDisplaySettings_Mode mode; ///< The display mode to set the display into double chromaticityRedX; ///< Red display primary X coord double chromaticityRedY; ///< Red display primary Y coord @@ -623,6 +725,39 @@ typedef struct AGSDisplaySettings // ADDED IN 5.2.0 int flags; ///< Bitfield of ::AGSDisplaySettingsFlags +} AGSDisplaySettings_511; + +/// The struct to specify the display settings to the driver. +typedef struct AGSDisplaySettings_600 +{ + AGSDisplaySettings_Mode mode; ///< The display mode to set the display into + + double chromaticityRedX; ///< Red display primary X coord + double chromaticityRedY; ///< Red display primary Y coord + + double chromaticityGreenX; ///< Green display primary X coord + double chromaticityGreenY; ///< Green display primary Y coord + + double chromaticityBlueX; ///< Blue display primary X coord + double chromaticityBlueY; ///< Blue display primary Y coord + + double chromaticityWhitePointX; ///< White point X coord + double chromaticityWhitePointY; ///< White point Y coord + + double minLuminance; ///< The minimum scene luminance in nits + double maxLuminance; ///< The maximum scene luminance in nits + + double maxContentLightLevel; ///< The maximum content light level in nits (MaxCLL) + double maxFrameAverageLightLevel; ///< The maximum frame average light level in nits (MaxFALL) + + unsigned int disableLocalDimming : 1; ///< Disables local dimming if possible + unsigned int reservedPadding : 31; ///< Reserved +} AGSDisplaySettings_600; + +typedef union AGSDisplaySettings +{ + AGSDisplaySettings_511 agsDisplaySettings511; + AGSDisplaySettings_600 agsDisplaySettings600; } AGSDisplaySettings; /// The result returned from \ref agsCheckDriverVersion @@ -642,6 +777,12 @@ typedef enum AGSDriverVersionResult /// AMD_AGS_API AGSDriverVersionResult agsCheckDriverVersion( const char* radeonSoftwareVersionReported, unsigned int radeonSoftwareVersionRequired ); +/// +/// Function to return the AGS version number. +/// +/// \return The version number made using AGS_MAKE_VERSION( AMD_AGS_VERSION_MAJOR, AMD_AGS_VERSION_MINOR, AMD_AGS_VERSION_PATCH ). +/// +AMD_AGS_API int agsGetVersionNumber( void ); /// /// Function used to initialize the AGS library. @@ -656,7 +797,23 @@ AMD_AGS_API AGSDriverVersionResult agsCheckDriverVersion( const char* radeonSoft /// \param [in] config Optional pointer to a AGSConfiguration struct to override the default library configuration. /// \param [out] gpuInfo Optional pointer to a AGSGPUInfo struct which will get filled in for all the GPUs in the system. /// -AMD_AGS_API AGSReturnCode agsInit( AGSContext** context, const AGSConfiguration* config, AGSGPUInfo* gpuInfo ); +AMD_AGS_API AGSReturnCode agsInit( AGSContext** context, const AGSConfiguration* config, AGSGPUInfo_511* gpuInfo ); + +/// +/// Function used to initialize the AGS library. +/// agsVersion must be specified as AGS_MAKE_VERSION( AMD_AGS_VERSION_MAJOR, AMD_AGS_VERSION_MINOR, AMD_AGS_VERSION_PATCH ) or the call will return \ref AGS_INVALID_ARGS. +/// Must be called prior to any of the subsequent AGS API calls. +/// Must be called prior to ID3D11Device or ID3D12Device creation. +/// \note The caller of this function should handle the possibility of the call failing in the cases below. One option is to do a vendor id check and only call \ref agsInitialize if there is an AMD GPU present. +/// \note This function will fail with \ref AGS_NO_AMD_DRIVER_INSTALLED if there is no AMD driver found on the system. +/// \note This function will fail with \ref AGS_LEGACY_DRIVER in Catalyst versions before 12.20. +/// +/// \param [in] agsVersion The API version specified using the \ref AGS_MAKE_VERSION macro. If this does not match the version in the binary this initialization call will fail. +/// \param [in] config Optional pointer to a AGSConfiguration struct to override the default library configuration. +/// \param [out] context Address of a pointer to a context. This function allocates a context on the heap which is then required for all subsequent API calls. +/// \param [out] gpuInfo Optional pointer to a AGSGPUInfo struct which will get filled in for all the GPUs in the system. +/// +AMD_AGS_API AGSReturnCode agsInitialize( int agsVersion, const AGSConfiguration* config, AGSContext** context, AGSGPUInfo_600* gpuInfo ); /// /// Function used to clean up the AGS library. @@ -665,6 +822,13 @@ AMD_AGS_API AGSReturnCode agsInit( AGSContext** context, const AGSConfiguration* /// AMD_AGS_API AGSReturnCode agsDeInit( AGSContext* context ); +/// +/// Function used to clean up the AGS library. +/// +/// \param [in] context Pointer to a context. This function will deallocate the context from the heap. +/// +AMD_AGS_API AGSReturnCode agsDeInitialize( AGSContext* context ); + /// /// Function used to query the number of GPUs used for Crossfire acceleration. /// This may be different from the total number of GPUs present in the system. @@ -685,7 +849,7 @@ AMD_AGS_API AGSReturnCode agsGetCrossfireGPUCount( AGSContext* context, int* num /// \note Freesync HDR Gamma 2.2 mode requires a 1010102 swapchain. /// \note Dolby Vision requires a 8888 UNORM swapchain. /// -/// \param [in] context Pointer to a context. This is generated by \ref agsInit +/// \param [in] context Pointer to a context. This is generated by \ref agsInitialize /// \param [in] deviceIndex The index of the device listed in \ref AGSGPUInfo::devices. /// \param [in] displayIndex The index of the display listed in \ref AGSDeviceInfo::displays. /// \param [in] settings Pointer to the display settings to use. @@ -726,6 +890,29 @@ typedef struct AGSDX12ExtensionParams typedef struct AGSDX12ReturnedParams { ID3D12Device* pDevice; ///< The newly created device + /* + This was changed to a struct in 6.0.0+ but it's still the size of an unsigned int. + Ignoring this change for now. + + typedef struct ExtensionsSupported /// Extensions for DX12 + { + unsigned int intrinsics16 : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. ReadFirstLane, ReadLane, LaneID, Swizzle, Ballot, MBCount, Med3, Barycentrics + unsigned int intrinsics17 : 1; ///< Supported in Radeon Software Version 17.9.1 onwards. WaveReduce, WaveScan + unsigned int userMarkers : 1; ///< Supported in Radeon Software Version 17.9.1 onwards. + unsigned int appRegistration : 1; ///< Supported in Radeon Software Version 17.9.1 onwards. + unsigned int UAVBindSlot : 1; ///< Supported in Radeon Software Version 19.5.1 onwards. + unsigned int intrinsics19 : 1; ///< Supported in Radeon Software Version 19.12.2 onwards. DrawIndex, AtomicU64 + unsigned int baseVertex : 1; ///< Supported in Radeon Software Version 20.2.1 onwards. + unsigned int baseInstance : 1; ///< Supported in Radeon Software Version 20.2.1 onwards. + unsigned int getWaveSize : 1; ///< Supported in Radeon Software Version 20.5.1 onwards. + unsigned int floatConversion : 1; ///< Supported in Radeon Software Version 20.5.1 onwards. + unsigned int readLaneAt : 1; ///< Supported in Radeon Software Version 20.11.1 onwards. + unsigned int rayHitToken : 1; ///< Supported in Radeon Software Version 20.11.1 onwards. + unsigned int padding : 20; ///< Reserved + } ExtensionsSupported; + ExtensionsSupported extensionsSupported; ///< List of supported extensions + */ + unsigned int extensionsSupported; ///< Bit mask that \ref agsDriverExtensionsDX12_CreateDevice will fill in to indicate which extensions are supported. See \ref AGSDriverExtensionDX12 } AGSDX12ReturnedParams; @@ -747,11 +934,11 @@ typedef struct AGSDX12ReturnedParams /// range[ 0 ].Init( D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0, AGS_DX12_SHADER_INSTRINSICS_SPACE_ID ); // u0 at driver-reserved space id /// \endcode /// -/// Newer drivers also support a user-specified slot in which case the register space id is assumed to be 0. It is important that the \ref AGS_DX12_EXTENSION_INTRINSIC_UAV_BIND_SLOT bit is set +/// Newer drivers also support a user-specified slot in which case the register space id is assumed to be 0. It is important that the \ref AGSDX12ReturnedParams::ExtensionsSupported::UAVBindSlot bit is set. /// to ensure the driver can support this. If not, then u0 and \ref AGS_DX12_SHADER_INSTRINSICS_SPACE_ID must be used. /// If the driver does support this feature and a non zero slot is required, then the HLSL must also define AMD_EXT_SHADER_INTRINSIC_UAV_OVERRIDE as the matching slot value. /// -/// \param [in] context Pointer to a context. This is generated by \ref agsInit +/// \param [in] context Pointer to a context. This is generated by \ref agsInitialize /// \param [in] creationParams Pointer to the struct to specify the existing DX12 device creation parameters. /// \param [in] extensionParams Optional pointer to the struct to specify DX12 additional device creation parameters. /// \param [out] returnedParams Pointer to struct to hold all the returned parameters from the call. @@ -777,7 +964,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_DestroyDevice( AGSContext* con /// * The intrinsic instructions require a 5.1 shader model. /// * The Root Signature will need to use an extra resource and sampler. These are not real resources/samplers, they are just used to encode the intrinsic instruction. /// -/// \param [in] context Pointer to a context. This is generated by \ref agsInit +/// \param [in] context Pointer to a context. This is generated by \ref agsInitialize /// \param [in] device The D3D12 device. /// \param [out] extensionsSupported Pointer to a bit mask that this function will fill in to indicate which extensions are supported. See ::AGSDriverExtensionDX12 /// @@ -799,7 +986,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_DeInit( AGSContext* context ); /// /// Function used to push an AMD user marker onto the command list. -/// This is only has an effect if \ref AGS_DX12_EXTENSION_USER_MARKERS is present in the extensionsSupported bitfield of \ref agsDriverExtensionsDX12_CreateDevice +/// This is only has an effect if \ref AGSDX12ReturnedParams::ExtensionsSupported::userMarkers is present. /// Supported in Radeon Software Version 17.9.1 onwards. /// /// \param [in] context Pointer to a context. @@ -912,10 +1099,47 @@ typedef struct AGSDX11ReturnedParams_520 void* breadcrumbBuffer; ///< The CPU buffer returned if the initialization of the breadcrumb was successful. } AGSDX11ReturnedParams_520; +typedef struct AGSDX11ExtensionsSupported_600 /// Extensions for DX11 +{ + unsigned int quadList : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. + unsigned int screenRectList : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. + unsigned int uavOverlap : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. + unsigned int depthBoundsTest : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. + unsigned int multiDrawIndirect : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. + unsigned int multiDrawIndirectCountIndirect : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. + unsigned int crossfireAPI : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. + unsigned int createShaderControls : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. + unsigned int intrinsics16 : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. ReadFirstLane, ReadLane, LaneID, Swizzle, Ballot, MBCount, Med3, Barycentrics + unsigned int multiView : 1; ///< Supported in Radeon Software Version 16.12.1 onwards. + unsigned int intrinsics17 : 1; ///< Supported in Radeon Software Version 17.9.1 onwards. WaveReduce, WaveScan + unsigned int appRegistration : 1; ///< Supported in Radeon Software Version 17.9.1 onwards. + unsigned int breadcrumbMarkers : 1; ///< Supported in Radeon Software Version 17.11.1 onwards. + unsigned int MDIDeferredContexts : 1; ///< Supported in Radeon Software Version 18.8.1 onwards. + unsigned int UAVOverlapDeferredContexts : 1; ///< Supported in Radeon Software Version 18.8.1 onwards. + unsigned int depthBoundsDeferredContexts : 1; ///< Supported in Radeon Software Version 18.8.1 onwards. + unsigned int intrinsics19 : 1; ///< Supported in Radeon Software Version 19.12.2 onwards. DrawIndex, AtomicU64 + unsigned int getWaveSize : 1; ///< Supported in Radeon Software Version 20.2.1 onwards. + unsigned int baseVertex : 1; ///< Supported in Radeon Software Version 20.2.1 onwards. + unsigned int baseInstance : 1; ///< Supported in Radeon Software Version 20.2.1 onwards. + unsigned int padding : 12; ///< Reserved +} AGSDX11ExtensionsSupported_600; + +typedef struct AGSDX11ReturnedParams_600 +{ + ID3D11Device* pDevice; ///< The newly created device + ID3D11DeviceContext* pImmediateContext; ///< The newly created immediate device context + IDXGISwapChain* pSwapChain; ///< The newly created swap chain. This is only created if a valid pSwapChainDesc is supplied in AGSDX11DeviceCreationParams. + D3D_FEATURE_LEVEL featureLevel; ///< The feature level supported by the newly created device + AGSDX11ExtensionsSupported_600 extensionsSupported; ///< List of supported extensions + unsigned int crossfireGPUCount; ///< The number of GPUs that are active for this app + void* breadcrumbBuffer; ///< The CPU buffer returned if the initialization of the breadcrumb was successful +} AGSDX11ReturnedParams_600; + typedef union AGSDX11ReturnedParams { AGSDX11ReturnedParams_511 agsDX11ReturnedParams511; AGSDX11ReturnedParams_520 agsDX11ReturnedParams520; + AGSDX11ReturnedParams_600 agsDX11ReturnedParams600; } AGSDX11ReturnedParams; /// @@ -925,7 +1149,7 @@ typedef union AGSDX11ReturnedParams /// * The shader compiler should not use the D3DCOMPILE_SKIP_OPTIMIZATION (/Od) option, otherwise it will not work. /// * The shader compiler needs D3DCOMPILE_ENABLE_STRICTNESS (/Ges) enabled. /// -/// \param [in] context Pointer to a context. This is generated by \ref agsInit +/// \param [in] context Pointer to a context. This is generated by \ref agsInititalize /// \param [in] creationParams Pointer to the struct to specify the existing DX11 device creation parameters. /// \param [in] extensionParams Optional pointer to the struct to specify DX11 additional device creation parameters. /// \param [out] returnedParams Pointer to struct to hold all the returned parameters from the call. @@ -991,7 +1215,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice_511( AGSContext* /// \defgroup breadcrumbs Breadcrumb API /// API for writing top-of-pipe and bottom-of-pipe markers to help track down GPU hangs. /// -/// The API is available if the \ref AGS_DX11_EXTENSION_BREADCRUMB_MARKERS is present in \ref AGSDX11ReturnedParams::extensionsSupported. +/// The API is available if the \ref AGSDX11ReturnedParams::ExtensionsSupported::breadcrumbMarkers is present. /// /// To use the API, a non zero value needs to be specificed in \ref AGSDX11ExtensionParams::numBreadcrumbMarkers. This enables the API (if available) and allocates a system memory buffer /// which is returned to the user in \ref AGSDX11ReturnedParams::breadcrumbBuffer. @@ -1197,6 +1421,13 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_WriteBreadcrumb( AGSContext* c /// API for primitive topologies /// @{ +/// Additional topologies supported via extensions +typedef enum AGSPrimitiveTopology +{ + AGS_PRIMITIVE_TOPOLOGY_QUADLIST = 7, ///< Quad list + AGS_PRIMITIVE_TOPOLOGY_SCREENRECTLIST = 9 ///< Screen rect list +} AGSPrimitiveTopology; + /// /// Function used to set the primitive topology. If you are using any of the extended topology types, then this function should /// be called to set ALL topology types. @@ -1447,6 +1678,22 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetViewBroadcastMasks( AGSCont /// AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_GetMaxClipRects( AGSContext* context, unsigned int* maxRectCount ); +/// The inclusion mode for the rect +typedef enum AGSClipRect_Mode +{ + ClipRectIncluded = 0, ///< Include the rect + ClipRectExcluded = 1 ///< Exclude the rect +} AGSClipRect_Mode; + +/// The clip rectangle struct used by \ref agsDriverExtensionsDX11_SetClipRects +typedef struct AGSClipRect +{ + AGSClipRect_Mode mode; ///< Include/exclude rect region + AGSRect rect; ///< The rect to include/exclude +} AGSClipRect; + + + /// /// Function sets clip rectangles. /// @@ -1563,6 +1810,46 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NotifyResourceEndAllAccess( AG /// @} +/// \defgroup typedefs Function pointer typedefs +/// List of function pointer typedefs for the API +/// @{ + +typedef AMD_AGS_API AGSDriverVersionResult (*AGS_CHECKDRIVERVERSION)( const char*, unsigned int ); ///< \ref agsCheckDriverVersion +typedef AMD_AGS_API int (*AGS_GETVERSIONNUMBER)( void ); ///< \ref agsGetVersionNumber +typedef AMD_AGS_API AGSReturnCode (*AGS_INITIALIZE)( int, const AGSConfiguration*, AGSContext**, AGSGPUInfo_600* ); ///< \ref agsInitialize +typedef AMD_AGS_API AGSReturnCode (*AGS_DEINITIALIZE)( AGSContext* ); ///< \ref agsDeInitialize +typedef AMD_AGS_API AGSReturnCode (*AGS_SETDISPLAYMODE)( AGSContext*, int, int, const AGSDisplaySettings* ); ///< \ref agsSetDisplayMode +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX12_CREATEDEVICE)( AGSContext*, const AGSDX12DeviceCreationParams*, const AGSDX12ExtensionParams*, AGSDX12ReturnedParams* ); ///< \ref agsDriverExtensionsDX12_CreateDevice +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX12_DESTROYDEVICE)( AGSContext*, ID3D12Device*, unsigned int* ); ///< \ref agsDriverExtensionsDX12_DestroyDevice +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX12_PUSHMARKER)( AGSContext*, ID3D12GraphicsCommandList*, const char* ); ///< \ref agsDriverExtensionsDX12_PushMarker +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX12_POPMARKER)( AGSContext*, ID3D12GraphicsCommandList* ); ///< \ref agsDriverExtensionsDX12_PopMarker +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX12_SETMARKER)( AGSContext*, ID3D12GraphicsCommandList*, const char* ); ///< \ref agsDriverExtensionsDX12_SetMarker +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_CREATEDEVICE)( AGSContext*, const AGSDX11DeviceCreationParams*, const AGSDX11ExtensionParams*, AGSDX11ReturnedParams* ); ///< \ref agsDriverExtensionsDX11_CreateDevice +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_DESTROYDEVICE)( AGSContext*, ID3D11Device*, unsigned int*, ID3D11DeviceContext*, unsigned int* ); ///< \ref agsDriverExtensionsDX11_DestroyDevice +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_WRITEBREADCRUMB)( AGSContext*, const AGSBreadcrumbMarker* ); ///< \ref agsDriverExtensionsDX11_WriteBreadcrumb +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_IASETPRIMITIVETOPOLOGY)( AGSContext*, enum D3D_PRIMITIVE_TOPOLOGY ); ///< \ref agsDriverExtensionsDX11_IASetPrimitiveTopology +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_BEGINUAVOVERLAP)( AGSContext*, ID3D11DeviceContext* ); ///< \ref agsDriverExtensionsDX11_BeginUAVOverlap +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_ENDUAVOVERLAP)( AGSContext*, ID3D11DeviceContext* ); ///< \ref agsDriverExtensionsDX11_EndUAVOverlap +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_SETDEPTHBOUNDS)( AGSContext*, ID3D11DeviceContext*, bool, float, float ); ///< \ref agsDriverExtensionsDX11_SetDepthBounds +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_MULTIDRAWINSTANCEDINDIRECT)( AGSContext*, ID3D11DeviceContext*, unsigned int, ID3D11Buffer*, unsigned int, unsigned int ); ///< \ref agsDriverExtensionsDX11_MultiDrawInstancedIndirect +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_MULTIDRAWINDEXEDINSTANCEDINDIRECT)( AGSContext*, ID3D11DeviceContext*, unsigned int, ID3D11Buffer*, unsigned int, unsigned int ); ///< \ref agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_MULTIDRAWINSTANCEDINDIRECTCOUNTINDIRECT)( AGSContext*, ID3D11DeviceContext*, ID3D11Buffer*, unsigned int, ID3D11Buffer*, unsigned int, unsigned int ); ///< \ref agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_MULTIDRAWINDEXEDINSTANCEDINDIRECTCOUNTINDIRECT)( AGSContext*, ID3D11DeviceContext*, ID3D11Buffer*, unsigned int, ID3D11Buffer*, unsigned int, unsigned int ); ///< \ref agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_SETMAXASYNCCOMPILETHREADCOUNT)( AGSContext*, unsigned int ); ///< \ref agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_NUMPENDINGASYNCOMPILEJOBS)( AGSContext*, unsigned int* ); ///< \ref agsDriverExtensionsDX11_NumPendingAsyncCompileJobs +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_SETDISKSHADERCACHEENABLED)( AGSContext*, int ); ///< \ref agsDriverExtensionsDX11_SetDiskShaderCacheEnabled +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_SETVIEWBROADCASTMASKS)( AGSContext*, unsigned long long, unsigned long long, int ); ///< \ref agsDriverExtensionsDX11_SetViewBroadcastMasks +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_GETMAXCLIPRECTS)( AGSContext*, unsigned int* ); ///< \ref agsDriverExtensionsDX11_GetMaxClipRects +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_SETCLIPRECTS)( AGSContext*, unsigned int, const AGSClipRect* ); ///< \ref agsDriverExtensionsDX11_SetClipRects +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_CREATEBUFFER)( AGSContext*, const D3D11_BUFFER_DESC*, const D3D11_SUBRESOURCE_DATA*, ID3D11Buffer**, AGSAfrTransferType, AGSAfrTransferEngine ); ///< \ref agsDriverExtensionsDX11_CreateBuffer +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_CREATETEXTURE1D)( AGSContext*, const D3D11_TEXTURE1D_DESC*, const D3D11_SUBRESOURCE_DATA*, ID3D11Texture1D**, AGSAfrTransferType, AGSAfrTransferEngine ); ///< \ref agsDriverExtensionsDX11_CreateTexture1D +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_CREATETEXTURE2D)( AGSContext*, const D3D11_TEXTURE2D_DESC*, const D3D11_SUBRESOURCE_DATA*, ID3D11Texture2D**, AGSAfrTransferType, AGSAfrTransferEngine ); ///< \ref agsDriverExtensionsDX11_CreateTexture2D +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_CREATETEXTURE3D)( AGSContext*, const D3D11_TEXTURE3D_DESC*, const D3D11_SUBRESOURCE_DATA*, ID3D11Texture3D**, AGSAfrTransferType, AGSAfrTransferEngine ); ///< \ref agsDriverExtensionsDX11_CreateTexture3D +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_NOTIFYRESOURCEENDWRITES)( AGSContext*, ID3D11Resource*, const D3D11_RECT*, const unsigned int*, unsigned int ); ///< \ref agsDriverExtensionsDX11_NotifyResourceEndWrites +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_NOTIFYRESOURCEBEGINALLACCESS)( AGSContext*, ID3D11Resource* ); ///< \ref agsDriverExtensionsDX11_NotifyResourceBeginAllAccess +typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_NOTIFYRESOURCEENDALLACCESS)( AGSContext*, ID3D11Resource* ); ///< \ref agsDriverExtensionsDX11_NotifyResourceEndAllAccess +/// @} + #ifdef __cplusplus } // extern "C" #endif diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec index ae825462f28..562c4103343 100644 --- a/dlls/amd_ags_x64/amd_ags_x64.spec +++ b/dlls/amd_ags_x64/amd_ags_x64.spec @@ -1,4 +1,5 @@ @ stdcall agsDeInit(ptr) +@ stdcall agsDeInitialize(ptr) @ stdcall agsCheckDriverVersion(ptr long) @ stub agsDriverExtensionsDX11_BeginUAVOverlap @ stub agsDriverExtensionsDX11_CreateBuffer @@ -38,5 +39,7 @@ @ stub agsDriverExtensionsDX12_PushMarker @ stub agsDriverExtensionsDX12_SetMarker @ stdcall agsGetCrossfireGPUCount(ptr ptr) +@ stdcall agsGetVersionNumber() @ stdcall agsInit(ptr ptr ptr) +@ stdcall agsInitialize(long ptr ptr ptr) @ stub agsSetDisplayMode diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 750401a845e..88ce02f9e1b 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -26,6 +26,7 @@ enum amd_ags_version AMD_AGS_VERSION_5_4_0, AMD_AGS_VERSION_5_4_1, AMD_AGS_VERSION_5_4_2, + AMD_AGS_VERSION_6_0_0, AMD_AGS_VERSION_COUNT }; @@ -46,17 +47,21 @@ amd_ags_info[AMD_AGS_VERSION_COUNT] = {5, 4, 0, sizeof(AGSDeviceInfo_540)}, {5, 4, 1, sizeof(AGSDeviceInfo_541)}, {5, 4, 2, sizeof(AGSDeviceInfo_542)}, + {6, 0, 0, sizeof(AGSDeviceInfo_600)}, }; #define DEF_FIELD(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ - offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name)}} + offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name)}} #define DEF_FIELD_520_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), -1, \ - -1, -1}} + -1, -1, -1}} #define DEF_FIELD_540_UP(name) {DEVICE_FIELD_##name, {-1, -1, \ -1, -1, offsetof(AGSDeviceInfo_540, name), \ - offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name)}} + offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name)}} +#define DEF_FIELD_600_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ + offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ + offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), -1}} #define DEVICE_FIELD_adapterString 0 #define DEVICE_FIELD_architectureVersion 1 @@ -80,7 +85,7 @@ device_struct_fields[] = DEF_FIELD_540_UP(asicFamily), DEF_FIELD(vendorId), DEF_FIELD(deviceId), - DEF_FIELD(isPrimaryDevice), + DEF_FIELD_600_BELOW(isPrimaryDevice), DEF_FIELD(localMemoryInBytes), DEF_FIELD(numDisplays), DEF_FIELD(displays), @@ -263,20 +268,20 @@ static enum amd_ags_version determine_ags_version(void) return ret; } -struct monitor_enum_context +struct monitor_enum_context_600 { const char *adapter_name; - AGSDisplayInfo **ret_displays; + AGSDisplayInfo_600 **ret_displays; int *ret_display_count; }; -static BOOL WINAPI monitor_enum_proc(HMONITOR hmonitor, HDC hdc, RECT *rect, LPARAM context) +static BOOL WINAPI monitor_enum_proc_600(HMONITOR hmonitor, HDC hdc, RECT *rect, LPARAM context) { - struct monitor_enum_context *c = (struct monitor_enum_context *)context; + struct monitor_enum_context_600 *c = (struct monitor_enum_context_600 *)context; MONITORINFOEXA monitor_info; - AGSDisplayInfo *new_alloc; + AGSDisplayInfo_600 *new_alloc; DISPLAY_DEVICEA device; - AGSDisplayInfo *info; + AGSDisplayInfo_600 *info; unsigned int i, mode; DEVMODEA dev_mode; @@ -321,7 +326,7 @@ static BOOL WINAPI monitor_enum_proc(HMONITOR hmonitor, HDC hdc, RECT *rect, LPA strcpy(info->name, "Unknown"); } if (monitor_info.dwFlags & MONITORINFOF_PRIMARY) - info->displayFlags |= AGS_DISPLAYFLAG_PRIMARY_DISPLAY; + info->isPrimaryDisplay = 1; mode = 0; memset(&dev_mode, 0, sizeof(dev_mode)); @@ -360,9 +365,9 @@ static BOOL WINAPI monitor_enum_proc(HMONITOR hmonitor, HDC hdc, RECT *rect, LPA return TRUE; } -static void init_device_displays(const char *adapter_name, AGSDisplayInfo **ret_displays, int *ret_display_count) +static void init_device_displays_600(const char *adapter_name, AGSDisplayInfo_600 **ret_displays, int *ret_display_count) { - struct monitor_enum_context context; + struct monitor_enum_context_600 context; TRACE("adapter_name %s.\n", debugstr_a(adapter_name)); @@ -370,9 +375,32 @@ static void init_device_displays(const char *adapter_name, AGSDisplayInfo **ret_ context.ret_displays = ret_displays; context.ret_display_count = ret_display_count; - EnumDisplayMonitors(NULL, NULL, monitor_enum_proc, (LPARAM)&context); + EnumDisplayMonitors(NULL, NULL, monitor_enum_proc_600, (LPARAM)&context); +} + +static void init_device_displays_511(const char *adapter_name, AGSDisplayInfo_511 **ret_displays, int *ret_display_count) +{ + AGSDisplayInfo_600 *displays = NULL; + int display_count = 0; + int i; + *ret_displays = NULL; + *ret_display_count = 0; + + init_device_displays_600(adapter_name, &displays, &display_count); + + if ((*ret_displays = heap_alloc(sizeof(**ret_displays) * display_count))) + { + for (i = 0; i < display_count; i++) + { + memcpy(&(*ret_displays)[i], &displays[i], sizeof(AGSDisplayInfo_511)); + } + *ret_display_count = display_count; + } + + heap_free(displays); } + static AGSReturnCode init_ags_context(AGSContext *context) { AGSReturnCode ret; @@ -427,11 +455,31 @@ static AGSReturnCode init_ags_context(AGSContext *context) } SET_DEVICE_FIELD(device, localMemoryInBytes, ULONG64, context->version, local_memory_size); if (!i) - SET_DEVICE_FIELD(device, isPrimaryDevice, int, context->version, 1); + { + if (context->version >= AMD_AGS_VERSION_6_0_0) + { + // This is a bitfield now... Nice... + struct AGSDeviceInfo_600 *device_600 = (struct AGSDeviceInfo_600 *)device; + device_600->isPrimaryDevice = 1; + } + else + { + SET_DEVICE_FIELD(device, isPrimaryDevice, int, context->version, 1); + } + } - init_device_displays(vk_properties->deviceName, - GET_DEVICE_FIELD_ADDR(device, displays, AGSDisplayInfo *, context->version), - GET_DEVICE_FIELD_ADDR(device, numDisplays, int, context->version)); + if (context->version >= AMD_AGS_VERSION_6_0_0) + { + init_device_displays_600(vk_properties->deviceName, + GET_DEVICE_FIELD_ADDR(device, displays, AGSDisplayInfo_600 *, context->version), + GET_DEVICE_FIELD_ADDR(device, numDisplays, int, context->version)); + } + else + { + init_device_displays_511(vk_properties->deviceName, + GET_DEVICE_FIELD_ADDR(device, displays, AGSDisplayInfo_511 *, context->version), + GET_DEVICE_FIELD_ADDR(device, numDisplays, int, context->version)); + } device += amd_ags_info[context->version].device_size; } @@ -439,7 +487,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) return AGS_SUCCESS; } -AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *config, AGSGPUInfo *gpu_info) +AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *config, AGSGPUInfo_511 *gpu_info) { struct AGSContext *object; AGSReturnCode ret; @@ -477,7 +525,47 @@ AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *confi return AGS_SUCCESS; } +AGSReturnCode WINAPI agsInitialize(int ags_version, const AGSConfiguration *config, AGSContext **context, AGSGPUInfo_600 *gpu_info) +{ + struct AGSContext *object; + AGSReturnCode ret; + + TRACE("ags_verison %d, context %p, config %p, gpu_info %p.\n", ags_version, context, config, gpu_info); + + if (!context || !gpu_info) + return AGS_INVALID_ARGS; + + if (config) + FIXME("Ignoring config %p.\n", config); + + if (!(object = heap_alloc(sizeof(*object)))) + return AGS_OUT_OF_MEMORY; + + if ((ret = init_ags_context(object)) != AGS_SUCCESS) + { + heap_free(object); + return ret; + } + + memset(gpu_info, 0, sizeof(*gpu_info)); + gpu_info->driverVersion = "20.50.03.05-210326a-365573E-RadeonSoftwareAdrenalin2020"; + gpu_info->radeonSoftwareVersion = "21.3.2"; + gpu_info->numDevices = object->device_count; + gpu_info->devices = object->devices; + + TRACE("Created context %p.\n", object); + + *context = object; + + return AGS_SUCCESS; +} + AGSReturnCode WINAPI agsDeInit(AGSContext *context) +{ + return agsDeInitialize(context); +} + +AGSReturnCode WINAPI agsDeInitialize(AGSContext *context) { unsigned int i; BYTE *device; @@ -491,7 +579,7 @@ AGSReturnCode WINAPI agsDeInit(AGSContext *context) device = (BYTE *)context->devices; for (i = 0; i < context->device_count; ++i) { - heap_free(*GET_DEVICE_FIELD_ADDR(device, displays, AGSDisplayInfo *, context->version)); + heap_free(*GET_DEVICE_FIELD_ADDR(device, displays, void *, context->version)); device += amd_ags_info[context->version].device_size; } heap_free(context->devices); @@ -561,6 +649,15 @@ AGSDriverVersionResult WINAPI agsCheckDriverVersion(const char* version_reported return AGS_SOFTWAREVERSIONCHECK_OK; } +int WINAPI agsGetVersionNumber(void) +{ + enum amd_ags_version version = determine_ags_version(); + + TRACE("version %d.\n", version); + + return AGS_MAKE_VERSION(amd_ags_info[version].major, amd_ags_info[version].minor, amd_ags_info[version].patch); +} + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { TRACE("%p, %u, %p.\n", instance, reason, reserved); From 453bd3f235f6ebf821f982c6af608c2de2d91870 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 8 May 2021 05:20:08 +0100 Subject: [PATCH 0348/2777] amd_ags_x64: Implement AGS 6.0.1 Signed-off-by: Joshua Ashton --- dlls/amd_ags_x64/amd_ags.h | 8 ++++---- dlls/amd_ags_x64/amd_ags_x64_main.c | 13 +++++++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h index af9c48c1dd5..20fef455f00 100644 --- a/dlls/amd_ags_x64/amd_ags.h +++ b/dlls/amd_ags_x64/amd_ags.h @@ -151,7 +151,7 @@ #define AMD_AGS_VERSION_MAJOR 6 ///< AGS major version #define AMD_AGS_VERSION_MINOR 0 ///< AGS minor version -#define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version +#define AMD_AGS_VERSION_PATCH 1 ///< AGS patch version #ifdef __cplusplus extern "C" { @@ -906,8 +906,8 @@ typedef struct AGSDX12ReturnedParams unsigned int baseInstance : 1; ///< Supported in Radeon Software Version 20.2.1 onwards. unsigned int getWaveSize : 1; ///< Supported in Radeon Software Version 20.5.1 onwards. unsigned int floatConversion : 1; ///< Supported in Radeon Software Version 20.5.1 onwards. - unsigned int readLaneAt : 1; ///< Supported in Radeon Software Version 20.11.1 onwards. - unsigned int rayHitToken : 1; ///< Supported in Radeon Software Version 20.11.1 onwards. + unsigned int readLaneAt : 1; ///< Supported in Radeon Software Version 20.11.2 onwards. + unsigned int rayHitToken : 1; ///< Supported in Radeon Software Version 20.11.2 onwards. unsigned int padding : 20; ///< Reserved } ExtensionsSupported; ExtensionsSupported extensionsSupported; ///< List of supported extensions @@ -1631,7 +1631,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount( /// /// This method can be used to determine the total number of asynchronous shader compile jobs that are either -/// queued for waiting for compilation or being compiled by the driverÂ’s asynchronous compilation threads. +/// queued for waiting for compilation or being compiled by the driverÂ’'s asynchronous compilation threads. /// This method can be called at any during the lifetime of the driver. /// /// \param [in] context Pointer to a context. diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 88ce02f9e1b..b1910def3cd 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -27,6 +27,7 @@ enum amd_ags_version AMD_AGS_VERSION_5_4_1, AMD_AGS_VERSION_5_4_2, AMD_AGS_VERSION_6_0_0, + AMD_AGS_VERSION_6_0_1, AMD_AGS_VERSION_COUNT }; @@ -48,20 +49,24 @@ amd_ags_info[AMD_AGS_VERSION_COUNT] = {5, 4, 1, sizeof(AGSDeviceInfo_541)}, {5, 4, 2, sizeof(AGSDeviceInfo_542)}, {6, 0, 0, sizeof(AGSDeviceInfo_600)}, + {6, 0, 1, sizeof(AGSDeviceInfo_600)}, }; #define DEF_FIELD(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ - offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name)}} + offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name), \ + offsetof(AGSDeviceInfo_600, name)}} #define DEF_FIELD_520_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), -1, \ - -1, -1, -1}} + -1, -1, -1, -1}} #define DEF_FIELD_540_UP(name) {DEVICE_FIELD_##name, {-1, -1, \ -1, -1, offsetof(AGSDeviceInfo_540, name), \ - offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name)}} + offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name), \ + offsetof(AGSDeviceInfo_600, name)}} #define DEF_FIELD_600_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ - offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), -1}} + offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), -1, \ + -1}} #define DEVICE_FIELD_adapterString 0 #define DEVICE_FIELD_architectureVersion 1 From dad6f6cb09dce34c2ab2a137351299887ea8b95e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 6 Oct 2021 22:56:07 +0300 Subject: [PATCH 0349/2777] amd_ags_x64: Add agsDriverExtensionsDX11_Init() semi-stub. --- dlls/amd_ags_x64/amd_ags_x64.spec | 2 +- dlls/amd_ags_x64/amd_ags_x64_main.c | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec index 562c4103343..ebb026da35e 100644 --- a/dlls/amd_ags_x64/amd_ags_x64.spec +++ b/dlls/amd_ags_x64/amd_ags_x64.spec @@ -14,7 +14,7 @@ @ stub agsDriverExtensionsDX11_EndUAVOverlap @ stub agsDriverExtensionsDX11_GetMaxClipRects @ stub agsDriverExtensionsDX11_IASetPrimitiveTopology -@ stub agsDriverExtensionsDX11_Init +@ stdcall agsDriverExtensionsDX11_Init(ptr ptr long ptr) @ stub agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect @ stub agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect @ stub agsDriverExtensionsDX11_MultiDrawInstancedIndirect diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index b1910def3cd..5b6d852b9e7 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -663,6 +663,14 @@ int WINAPI agsGetVersionNumber(void) return AGS_MAKE_VERSION(amd_ags_info[version].major, amd_ags_info[version].minor, amd_ags_info[version].patch); } +AGSReturnCode WINAPI agsDriverExtensionsDX11_Init( AGSContext* context, ID3D11Device* device, unsigned int uavSlot, unsigned int* extensionsSupported ) +{ + FIXME("context %p, device %p, uavSlot %u, extensionsSupported %p stub.\n", context, device, uavSlot, extensionsSupported); + + *extensionsSupported = 0; + return AGS_SUCCESS; +} + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { TRACE("%p, %u, %p.\n", instance, reason, reserved); From c49e2716eaa547f7421bae3390f4fb00b2f48132 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 10 Nov 2021 22:11:59 +0300 Subject: [PATCH 0350/2777] amd_ags_x64: Bump driver version to 21.10.2. For FH5. --- dlls/amd_ags_x64/amd_ags_x64_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 5b6d852b9e7..24b16021acf 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -518,8 +518,8 @@ AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *confi gpu_info->agsVersionMajor = amd_ags_info[object->version].major; gpu_info->agsVersionMinor = amd_ags_info[object->version].minor; gpu_info->agsVersionPatch = amd_ags_info[object->version].patch; - gpu_info->driverVersion = "20.50.03.05-210326a-365573E-RadeonSoftwareAdrenalin2020"; - gpu_info->radeonSoftwareVersion = "21.3.2"; + gpu_info->driverVersion = "21.30.25.05-211005a-372402E-RadeonSoftware"; + gpu_info->radeonSoftwareVersion = "21.10.2"; gpu_info->numDevices = object->device_count; gpu_info->devices = object->devices; @@ -553,8 +553,8 @@ AGSReturnCode WINAPI agsInitialize(int ags_version, const AGSConfiguration *conf } memset(gpu_info, 0, sizeof(*gpu_info)); - gpu_info->driverVersion = "20.50.03.05-210326a-365573E-RadeonSoftwareAdrenalin2020"; - gpu_info->radeonSoftwareVersion = "21.3.2"; + gpu_info->driverVersion = "21.30.25.05-211005a-372402E-RadeonSoftware"; + gpu_info->radeonSoftwareVersion = "21.10.2"; gpu_info->numDevices = object->device_count; gpu_info->devices = object->devices; From 87ffd81fc543bf2401327e05c1cc49a99fa4ac27 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Feb 2022 16:36:37 +0300 Subject: [PATCH 0351/2777] 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 a1a20021edf86bbd5e4c65876f68f277b625bb95 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Feb 2022 17:07:53 +0300 Subject: [PATCH 0352/2777] 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 775d1096cb41fc5d13ea44218fbcef928724d652 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Feb 2022 17:42:41 +0300 Subject: [PATCH 0353/2777] 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 c0678b0686a67cf4f7838b1402ff5b6ab2f258db Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Thu, 30 Sep 2021 20:00:00 +0200 Subject: [PATCH 0354/2777] wine.inf: Set amd_ags_x64 to built-in for Wolfenstein 2. --- loader/wine.inf.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 19231c95747..5ef2a175943 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2724,3 +2724,5 @@ HKCU,Software\Wine\DllOverrides,"msvcr140",0x2,"native,builtin" HKCU,Software\Wine\DllOverrides,"ucrtbase",0x2,"native,builtin" HKCU,Software\Wine\DllOverrides,"vcomp140",0x2,"native,builtin" HKCU,Software\Wine\DllOverrides,"vcruntime140",0x2,"native,builtin" +;;App-specific overrides for amd_ags_x64.dll. +HKCU,Software\Wine\AppDefaults\NewColossus_x64vk.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" From 853228db37faf83a007bb0bf84292c12d92edecf Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Fri, 31 Jul 2020 15:33:57 -0700 Subject: [PATCH 0355/2777] wine.inf: Set amd_ags_x64 to built-in for Red Dead Redemption 2. --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 5ef2a175943..925a71c69dd 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2726,3 +2726,4 @@ HKCU,Software\Wine\DllOverrides,"vcomp140",0x2,"native,builtin" HKCU,Software\Wine\DllOverrides,"vcruntime140",0x2,"native,builtin" ;;App-specific overrides for amd_ags_x64.dll. HKCU,Software\Wine\AppDefaults\NewColossus_x64vk.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" +HKCU,Software\Wine\AppDefaults\RDR2.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" From e904f263c52a695ef315a2309969e9033ff810d7 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 21 Apr 2021 18:40:25 +0300 Subject: [PATCH 0356/2777] wine.inf: Set amd_ags_x64 to built-in for Forza Horizon 4. For Forza Horizon 4. --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 925a71c69dd..2d5eb6a1962 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2727,3 +2727,4 @@ HKCU,Software\Wine\DllOverrides,"vcruntime140",0x2,"native,builtin" ;;App-specific overrides for amd_ags_x64.dll. HKCU,Software\Wine\AppDefaults\NewColossus_x64vk.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" HKCU,Software\Wine\AppDefaults\RDR2.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" +HKCU,Software\Wine\AppDefaults\ForzaHorizon4.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" From 4fe502372c331e37976df4562f615fa3567f40ec Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Sat, 11 Dec 2021 19:00:26 +0100 Subject: [PATCH 0357/2777] wine.inf: Set amd_ags_x64 to built-in for DeathLoop. CW-Bug-Id: #19427 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 2d5eb6a1962..630f4276911 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2728,3 +2728,4 @@ HKCU,Software\Wine\DllOverrides,"vcruntime140",0x2,"native,builtin" HKCU,Software\Wine\AppDefaults\NewColossus_x64vk.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" HKCU,Software\Wine\AppDefaults\RDR2.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" HKCU,Software\Wine\AppDefaults\ForzaHorizon4.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" +HKCU,Software\Wine\AppDefaults\Deathloop.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" From 450c34ef52ad13401fb62986a3d1b29e0a4a539f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 10 Nov 2021 20:34:24 +0300 Subject: [PATCH 0358/2777] wine.inf: Set amd_ags_x64 to built-in for FH5. CW-Bug-Id: #19618 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 630f4276911..84c03f9503d 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2729,3 +2729,4 @@ HKCU,Software\Wine\AppDefaults\NewColossus_x64vk.exe\DllOverrides,"amd_ags_x64", HKCU,Software\Wine\AppDefaults\RDR2.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" HKCU,Software\Wine\AppDefaults\ForzaHorizon4.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" HKCU,Software\Wine\AppDefaults\Deathloop.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" +HKCU,Software\Wine\AppDefaults\ForzaHorizon5.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" From d35477eb551b03d6589396e655062fca371ce88c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 19 Apr 2022 00:24:13 +0300 Subject: [PATCH 0359/2777] wine.inf: Set amd_ags_x64 to built-in for MHR. CW-Bug-Id: #20448 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 84c03f9503d..701aafbd5ff 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2730,3 +2730,4 @@ HKCU,Software\Wine\AppDefaults\RDR2.exe\DllOverrides,"amd_ags_x64",0x2,"builtin, HKCU,Software\Wine\AppDefaults\ForzaHorizon4.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" HKCU,Software\Wine\AppDefaults\Deathloop.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" HKCU,Software\Wine\AppDefaults\ForzaHorizon5.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" +HKCU,Software\Wine\AppDefaults\MonsterHunterRise.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" From 8065f76fbacefcb3c33ba14e97c4b3469ad4a49b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 21 Apr 2022 19:03:33 +0300 Subject: [PATCH 0360/2777] wine.inf: Set amd_ags_x64 to built-in for Serious Sam 4. CW-Bug-Id: #20527 --- loader/wine.inf.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 701aafbd5ff..6dc31196cdf 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2731,3 +2731,5 @@ HKCU,Software\Wine\AppDefaults\ForzaHorizon4.exe\DllOverrides,"amd_ags_x64",0x2, HKCU,Software\Wine\AppDefaults\Deathloop.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" HKCU,Software\Wine\AppDefaults\ForzaHorizon5.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\MonsterHunterRise.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" +HKCU,Software\Wine\AppDefaults\Sam4.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" +HKCU,Software\Wine\AppDefaults\Sam4_Unrestricted.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" From 37a865d3e3f2860bda984ab89ba298fd55bef7a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 10 Jul 2020 10:09:21 +0200 Subject: [PATCH 0361/2777] atiadlxx: Add stub DLL, disabled by default. This is required by several Call of Duty games when using AMD GPU. --- configure.ac | 1 + dlls/atiadlxx/Makefile.in | 6 + dlls/atiadlxx/atiadlxx.spec | 1138 +++++++++++++++++++++++++++++++++ dlls/atiadlxx/atiadlxx_main.c | 91 +++ loader/wine.inf.in | 1 + 5 files changed, 1237 insertions(+) create mode 100644 dlls/atiadlxx/Makefile.in create mode 100644 dlls/atiadlxx/atiadlxx.spec create mode 100644 dlls/atiadlxx/atiadlxx_main.c diff --git a/configure.ac b/configure.ac index e308f8a6a7a..35d951c7e2f 100644 --- a/configure.ac +++ b/configure.ac @@ -2383,6 +2383,7 @@ WINE_CONFIG_MAKEFILE(dlls/apisetschema) WINE_CONFIG_MAKEFILE(dlls/apphelp) WINE_CONFIG_MAKEFILE(dlls/apphelp/tests) WINE_CONFIG_MAKEFILE(dlls/appwiz.cpl) +WINE_CONFIG_MAKEFILE(dlls/atiadlxx) WINE_CONFIG_MAKEFILE(dlls/atl) WINE_CONFIG_MAKEFILE(dlls/atl/tests) WINE_CONFIG_MAKEFILE(dlls/atl100) diff --git a/dlls/atiadlxx/Makefile.in b/dlls/atiadlxx/Makefile.in new file mode 100644 index 00000000000..de1b4c5bc74 --- /dev/null +++ b/dlls/atiadlxx/Makefile.in @@ -0,0 +1,6 @@ +EXTRADEFS = -DWINE_NO_LONG_TYPES +MODULE = atiadlxx.dll +EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native + +C_SRCS = \ + atiadlxx_main.c diff --git a/dlls/atiadlxx/atiadlxx.spec b/dlls/atiadlxx/atiadlxx.spec new file mode 100644 index 00000000000..e2a1f46a838 --- /dev/null +++ b/dlls/atiadlxx/atiadlxx.spec @@ -0,0 +1,1138 @@ +@ stub ADL2_ADC_CurrentProfileFromDrv_Get +@ stub ADL2_ADC_Display_AdapterDeviceProfileEx_Get +@ stub ADL2_ADC_DrvDataToProfile_Copy +@ stub ADL2_ADC_FindClosestMode_Get +@ stub ADL2_ADC_IsDevModeEqual_Get +@ stub ADL2_ADC_Profile_Apply +@ stub ADL2_APO_AudioDelayAdjustmentInfo_Get +@ stub ADL2_APO_AudioDelay_Restore +@ stub ADL2_APO_AudioDelay_Set +@ stub ADL2_AdapterLimitation_Caps +@ stub ADL2_AdapterX2_Caps +@ stub ADL2_Adapter_AMDAndNonAMDDIsplayClone_Get +@ stub ADL2_Adapter_ASICFamilyType_Get +@ stub ADL2_Adapter_ASICInfo_Get +@ stub ADL2_Adapter_Accessibility_Get +@ stub ADL2_Adapter_AceDefaults_Restore +@ stub ADL2_Adapter_Active_Get +@ stub ADL2_Adapter_Active_Set +@ stub ADL2_Adapter_Active_SetPrefer +@ stub ADL2_Adapter_AdapterInfoX2_Get +@ stub ADL2_Adapter_AdapterInfoX3_Get +@ stub ADL2_Adapter_AdapterInfoX4_Get +@ stub ADL2_Adapter_AdapterInfo_Get +@ stub ADL2_Adapter_AdapterList_Disable +@ stub ADL2_Adapter_AdapterLocationPath_Get +@ stub ADL2_Adapter_Aspects_Get +@ stub ADL2_Adapter_AudioChannelSplitConfiguration_Get +@ stub ADL2_Adapter_AudioChannelSplit_Disable +@ stub ADL2_Adapter_AudioChannelSplit_Enable +@ stub ADL2_Adapter_BigSw_Info_Get +@ stub ADL2_Adapter_BlackAndWhiteLevelSupport_Get +@ stub ADL2_Adapter_BlackAndWhiteLevel_Get +@ stub ADL2_Adapter_BlackAndWhiteLevel_Set +@ stub ADL2_Adapter_BoardLayout_Get +@ stub ADL2_Adapter_Caps +@ stub ADL2_Adapter_ChipSetInfo_Get +@ stub ADL2_Adapter_CloneTypes_Get +@ stub ADL2_Adapter_ConfigMemory_Cap +@ stub ADL2_Adapter_ConfigMemory_Get +@ stub ADL2_Adapter_ConfigureState_Get +@ stub ADL2_Adapter_ConnectionData_Get +@ stub ADL2_Adapter_ConnectionData_Remove +@ stub ADL2_Adapter_ConnectionData_Set +@ stub ADL2_Adapter_ConnectionState_Get +@ stub ADL2_Adapter_CrossDisplayPlatformInfo_Get +@ stub ADL2_Adapter_CrossGPUClone_Disable +@ stub ADL2_Adapter_CrossdisplayAdapterRole_Caps +@ stub ADL2_Adapter_CrossdisplayInfoX2_Set +@ stub ADL2_Adapter_CrossdisplayInfo_Get +@ stub ADL2_Adapter_CrossdisplayInfo_Set +@ stub ADL2_Adapter_CrossfireX2_Get +@ stub ADL2_Adapter_Crossfire_Caps +@ stub ADL2_Adapter_Crossfire_Get +@ stub ADL2_Adapter_Crossfire_Set +@ stub ADL2_Adapter_DefaultAudioChannelTable_Load +@ stub ADL2_Adapter_Desktop_Caps +@ stub ADL2_Adapter_Desktop_SupportedSLSGridTypes_Get +@ stub ADL2_Adapter_DeviceID_Get +@ stub ADL2_Adapter_DisplayAudioEndpoint_Enable +@ stub ADL2_Adapter_DisplayAudioEndpoint_Mute +@ stub ADL2_Adapter_DisplayAudioInfo_Get +@ stub ADL2_Adapter_DisplayGTCCaps_Get +@ stub ADL2_Adapter_Display_Caps +@ stub ADL2_Adapter_DriverSettings_Get +@ stub ADL2_Adapter_DriverSettings_Set +@ stub ADL2_Adapter_ECC_ErrorInjection_Set +@ stub ADL2_Adapter_ECC_ErrorRecords_Get +@ stub ADL2_Adapter_EDC_ErrorInjection_Set +@ stub ADL2_Adapter_EDC_ErrorRecords_Get +@ stub ADL2_Adapter_EDIDManagement_Caps +@ stub ADL2_Adapter_EmulationMode_Set +@ stub ADL2_Adapter_ExtInfo_Get +@ stub ADL2_Adapter_Feature_Caps +@ stub ADL2_Adapter_FrameMetrics_Caps +@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Disable +@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Enable +@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Get +@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Start +@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Stop +@ stub ADL2_Adapter_FrameMetrics_Get +@ stub ADL2_Adapter_FrameMetrics_Start +@ stub ADL2_Adapter_FrameMetrics_Stop +@ stub ADL2_Adapter_Gamma_Get +@ stub ADL2_Adapter_Gamma_Set +@ stub ADL2_Adapter_Graphic_Core_Info_Get +@ stub ADL2_Adapter_HBC_Caps +@ stub ADL2_Adapter_HBM_ECC_UC_Check +@ stub ADL2_Adapter_Headless_Get +@ stub ADL2_Adapter_ID_Get +@ stub ADL2_Adapter_IsGamingDriver_Info_Get +@ stub ADL2_Adapter_LocalDisplayConfig_Get +@ stub ADL2_Adapter_LocalDisplayConfig_Set +@ stub ADL2_Adapter_LocalDisplayState_Get +@ stub ADL2_Adapter_MVPU_Set +@ stub ADL2_Adapter_MaxCursorSize_Get +@ stub ADL2_Adapter_MemoryInfo2_Get +@ stub ADL2_Adapter_MemoryInfo_Get +@ stub ADL2_Adapter_MirabilisSupport_Get +@ stub ADL2_Adapter_ModeSwitch +@ stub ADL2_Adapter_ModeTimingOverride_Caps +@ stub ADL2_Adapter_Modes_ReEnumerate +@ stub ADL2_Adapter_NumberOfActivatableSources_Get +@ stdcall ADL2_Adapter_NumberOfAdapters_Get(ptr ptr) +@ stub ADL2_Adapter_ObservedClockInfo_Get +@ stub ADL2_Adapter_PMLog_Start +@ stub ADL2_Adapter_PMLog_Stop +@ stub ADL2_Adapter_PMLog_Support_Get +@ stub ADL2_Adapter_PreFlipPostProcessing_Disable +@ stub ADL2_Adapter_PreFlipPostProcessing_Enable +@ stub ADL2_Adapter_PreFlipPostProcessing_Get_Status +@ stub ADL2_Adapter_PreFlipPostProcessing_Select_LUT_Algorithm +@ stub ADL2_Adapter_PreFlipPostProcessing_Select_LUT_Buffer +@ stub ADL2_Adapter_PreFlipPostProcessing_Unselect_LUT_Buffer +@ stub ADL2_Adapter_Primary_Get +@ stub ADL2_Adapter_Primary_Set +@ stub ADL2_Adapter_RAS_ErrorInjection_Set +@ stub ADL2_Adapter_RegValueInt_Get +@ stub ADL2_Adapter_RegValueInt_Set +@ stub ADL2_Adapter_RegValueString_Get +@ stub ADL2_Adapter_RegValueString_Set +@ stub ADL2_Adapter_SWInfo_Get +@ stub ADL2_Adapter_Speed_Caps +@ stub ADL2_Adapter_Speed_Get +@ stub ADL2_Adapter_Speed_Set +@ stub ADL2_Adapter_SupportedConnections_Get +@ stub ADL2_Adapter_TRNG_Get +@ stub ADL2_Adapter_Tear_Free_Cap +@ stub ADL2_Adapter_VRAMUsage_Get +@ stub ADL2_Adapter_VariBrightEnable_Set +@ stub ADL2_Adapter_VariBrightLevel_Get +@ stub ADL2_Adapter_VariBrightLevel_Set +@ stub ADL2_Adapter_VariBright_Caps +@ stub ADL2_Adapter_VerndorID_Int_get +@ stub ADL2_Adapter_VideoBiosInfo_Get +@ stub ADL2_Adapter_VideoTheaterModeInfo_Get +@ stub ADL2_Adapter_VideoTheaterModeInfo_Set +@ stub ADL2_Adapter_XConnectSupport_Get +@ stub ADL2_ApplicationProfilesX2_AppInterceptionList_Set +@ stub ADL2_ApplicationProfilesX2_AppStartStopInfo_Get +@ stub ADL2_ApplicationProfiles_AppInterceptionList_Set +@ stub ADL2_ApplicationProfiles_AppInterception_Set +@ stub ADL2_ApplicationProfiles_AppStartStopInfo_Get +@ stub ADL2_ApplicationProfiles_AppStartStop_Resume +@ stub ADL2_ApplicationProfiles_Applications_Get +@ stub ADL2_ApplicationProfiles_ConvertToCompact +@ stub ADL2_ApplicationProfiles_DriverAreaPrivacy_Get +@ stub ADL2_ApplicationProfiles_GetCustomization +@ stub ADL2_ApplicationProfiles_HitListsX2_Get +@ stub ADL2_ApplicationProfiles_HitListsX3_Get +@ stub ADL2_ApplicationProfiles_HitLists_Get +@ stub ADL2_ApplicationProfiles_ProfileApplicationX2_Assign +@ stub ADL2_ApplicationProfiles_ProfileApplication_Assign +@ stub ADL2_ApplicationProfiles_ProfileOfAnApplicationX2_Search +@ stub ADL2_ApplicationProfiles_ProfileOfAnApplication_InMemorySearch +@ stub ADL2_ApplicationProfiles_ProfileOfAnApplication_Search +@ stub ADL2_ApplicationProfiles_Profile_Create +@ stub ADL2_ApplicationProfiles_Profile_Exist +@ stub ADL2_ApplicationProfiles_Profile_Remove +@ stub ADL2_ApplicationProfiles_PropertyType_Get +@ stub ADL2_ApplicationProfiles_Release_Get +@ stub ADL2_ApplicationProfiles_RemoveApplication +@ stub ADL2_ApplicationProfiles_StatusInfo_Get +@ stub ADL2_ApplicationProfiles_System_Reload +@ stub ADL2_ApplicationProfiles_User_Load +@ stub ADL2_ApplicationProfiles_User_Unload +@ stub ADL2_Audio_CurrentSampleRate_Get +@ stub ADL2_AutoTuningResult_Get +@ stub ADL2_BOOST_Settings_Get +@ stub ADL2_BOOST_Settings_Set +@ stub ADL2_Blockchain_BlockchainMode_Caps +@ stub ADL2_Blockchain_BlockchainMode_Get +@ stub ADL2_Blockchain_BlockchainMode_Set +@ stub ADL2_Blockchain_Hashrate_Set +@ stub ADL2_CDS_UnsafeMode_Set +@ stub ADL2_CHILL_SettingsX2_Get +@ stub ADL2_CHILL_SettingsX2_Set +@ stub ADL2_CV_DongleSettings_Get +@ stub ADL2_CV_DongleSettings_Reset +@ stub ADL2_CV_DongleSettings_Set +@ stub ADL2_Chill_Caps_Get +@ stub ADL2_Chill_Settings_Get +@ stub ADL2_Chill_Settings_Notify +@ stub ADL2_Chill_Settings_Set +@ stub ADL2_CustomFan_Caps +@ stub ADL2_CustomFan_Get +@ stub ADL2_CustomFan_Set +@ stub ADL2_DELAG_Settings_Get +@ stub ADL2_DELAG_Settings_Set +@ stub ADL2_DFP_AllowOnlyCETimings_Get +@ stub ADL2_DFP_AllowOnlyCETimings_Set +@ stub ADL2_DFP_BaseAudioSupport_Get +@ stub ADL2_DFP_GPUScalingEnable_Get +@ stub ADL2_DFP_GPUScalingEnable_Set +@ stub ADL2_DFP_HDMISupport_Get +@ stub ADL2_DFP_MVPUAnalogSupport_Get +@ stub ADL2_DFP_PixelFormat_Caps +@ stub ADL2_DFP_PixelFormat_Get +@ stub ADL2_DFP_PixelFormat_Set +@ stub ADL2_DVRSupport_Get +@ stub ADL2_Desktop_DOPP_Enable +@ stub ADL2_Desktop_DOPP_EnableX2 +@ stub ADL2_Desktop_Detach +@ stub ADL2_Desktop_Device_Create +@ stub ADL2_Desktop_Device_Destroy +@ stub ADL2_Desktop_ExclusiveModeX2_Get +@ stub ADL2_Desktop_HardwareCursor_SetBitmap +@ stub ADL2_Desktop_HardwareCursor_SetPosition +@ stub ADL2_Desktop_HardwareCursor_Toggle +@ stub ADL2_Desktop_PFPAComplete_Set +@ stub ADL2_Desktop_PFPAState_Get +@ stub ADL2_Desktop_PrimaryInfo_Get +@ stub ADL2_Desktop_TextureState_Get +@ stub ADL2_Desktop_Texture_Enable +@ stub ADL2_Device_PMLog_Device_Create +@ stub ADL2_Device_PMLog_Device_Destroy +@ stub ADL2_DisplayScaling_Set +@ stub ADL2_Display_AdapterID_Get +@ stub ADL2_Display_AdjustCaps_Get +@ stub ADL2_Display_AdjustmentCoherent_Get +@ stub ADL2_Display_AdjustmentCoherent_Set +@ stub ADL2_Display_AudioMappingInfo_Get +@ stub ADL2_Display_AvivoColor_Get +@ stub ADL2_Display_AvivoCurrentColor_Set +@ stub ADL2_Display_AvivoDefaultColor_Set +@ stub ADL2_Display_BackLight_Get +@ stub ADL2_Display_BackLight_Set +@ stub ADL2_Display_BezelOffsetSteppingSize_Get +@ stub ADL2_Display_BezelOffset_Set +@ stub ADL2_Display_BezelSupported_Validate +@ stub ADL2_Display_Capabilities_Get +@ stub ADL2_Display_ColorCaps_Get +@ stub ADL2_Display_ColorDepth_Get +@ stub ADL2_Display_ColorDepth_Set +@ stub ADL2_Display_ColorTemperatureSourceDefault_Get +@ stub ADL2_Display_ColorTemperatureSource_Get +@ stub ADL2_Display_ColorTemperatureSource_Set +@ stub ADL2_Display_Color_Get +@ stub ADL2_Display_Color_Set +@ stub ADL2_Display_ConnectedDisplays_Get +@ stub ADL2_Display_ContainerID_Get +@ stub ADL2_Display_ControllerOverlayAdjustmentCaps_Get +@ stub ADL2_Display_ControllerOverlayAdjustmentData_Get +@ stub ADL2_Display_ControllerOverlayAdjustmentData_Set +@ stub ADL2_Display_CustomizedModeListNum_Get +@ stub ADL2_Display_CustomizedModeList_Get +@ stub ADL2_Display_CustomizedMode_Add +@ stub ADL2_Display_CustomizedMode_Delete +@ stub ADL2_Display_CustomizedMode_Validate +@ stub ADL2_Display_DCE_Get +@ stub ADL2_Display_DCE_Set +@ stub ADL2_Display_DDCBlockAccess_Get +@ stub ADL2_Display_DDCInfo2_Get +@ stub ADL2_Display_DDCInfo_Get +@ stub ADL2_Display_Deflicker_Get +@ stub ADL2_Display_Deflicker_Set +@ stub ADL2_Display_DeviceConfig_Get +@ stub ADL2_Display_DisplayContent_Cap +@ stub ADL2_Display_DisplayContent_Get +@ stub ADL2_Display_DisplayContent_Set +@ stub ADL2_Display_DisplayInfo_Get +@ stub ADL2_Display_DisplayMapConfigX2_Set +@ stub ADL2_Display_DisplayMapConfig_Get +@ stub ADL2_Display_DisplayMapConfig_PossibleAddAndRemove +@ stub ADL2_Display_DisplayMapConfig_Set +@ stub ADL2_Display_DisplayMapConfig_Validate +@ stub ADL2_Display_DitherState_Get +@ stub ADL2_Display_DitherState_Set +@ stub ADL2_Display_Downscaling_Caps +@ stub ADL2_Display_DpMstAuxMsg_Get +@ stub ADL2_Display_DpMstInfo_Get +@ stub ADL2_Display_DummyVirtual_Destroy +@ stub ADL2_Display_DummyVirtual_Get +@ stub ADL2_Display_EdidData_Get +@ stub ADL2_Display_EdidData_Set +@ stub ADL2_Display_EnumDisplays_Get +@ stub ADL2_Display_FilterSVideo_Get +@ stub ADL2_Display_FilterSVideo_Set +@ stub ADL2_Display_ForcibleDisplay_Get +@ stub ADL2_Display_ForcibleDisplay_Set +@ stub ADL2_Display_FormatsOverride_Get +@ stub ADL2_Display_FormatsOverride_Set +@ stub ADL2_Display_FreeSyncState_Get +@ stub ADL2_Display_FreeSyncState_Set +@ stub ADL2_Display_FreeSync_Cap +@ stub ADL2_Display_GamutMapping_Get +@ stub ADL2_Display_GamutMapping_Reset +@ stub ADL2_Display_GamutMapping_Set +@ stub ADL2_Display_Gamut_Caps +@ stub ADL2_Display_Gamut_Get +@ stub ADL2_Display_Gamut_Set +@ stub ADL2_Display_HDCP_Get +@ stub ADL2_Display_HDCP_Set +@ stub ADL2_Display_HDRState_Get +@ stub ADL2_Display_HDRState_Set +@ stub ADL2_Display_ImageExpansion_Get +@ stub ADL2_Display_ImageExpansion_Set +@ stub ADL2_Display_InfoPacket_Get +@ stub ADL2_Display_InfoPacket_Set +@ stub ADL2_Display_IsVirtual_Get +@ stub ADL2_Display_LCDRefreshRateCapability_Get +@ stub ADL2_Display_LCDRefreshRateOptions_Get +@ stub ADL2_Display_LCDRefreshRateOptions_Set +@ stub ADL2_Display_LCDRefreshRate_Get +@ stub ADL2_Display_LCDRefreshRate_Set +@ stub ADL2_Display_Limits_Get +@ stub ADL2_Display_MVPUCaps_Get +@ stub ADL2_Display_MVPUStatus_Get +@ stub ADL2_Display_ModeTimingOverrideInfo_Get +@ stub ADL2_Display_ModeTimingOverrideListX2_Get +@ stub ADL2_Display_ModeTimingOverrideListX3_Get +@ stub ADL2_Display_ModeTimingOverrideList_Get +@ stub ADL2_Display_ModeTimingOverrideX2_Get +@ stub ADL2_Display_ModeTimingOverrideX2_Set +@ stub ADL2_Display_ModeTimingOverrideX3_Get +@ stub ADL2_Display_ModeTimingOverride_Delete +@ stub ADL2_Display_ModeTimingOverride_Get +@ stub ADL2_Display_ModeTimingOverride_Set +@ stub ADL2_Display_Modes_Get +@ stub ADL2_Display_Modes_Set +@ stub ADL2_Display_Modes_X2_Get +@ stub ADL2_Display_MonitorPowerState_Set +@ stub ADL2_Display_NativeAUXChannel_Access +@ stub ADL2_Display_NeedWorkaroundFor5Clone_Get +@ stub ADL2_Display_NumberOfDisplays_Get +@ stub ADL2_Display_ODClockConfig_Set +@ stub ADL2_Display_ODClockInfo_Get +@ stub ADL2_Display_Overlap_NotifyAdjustment +@ stub ADL2_Display_Overlap_Set +@ stub ADL2_Display_Overscan_Get +@ stub ADL2_Display_Overscan_Set +@ stub ADL2_Display_PixelFormatDefault_Get +@ stub ADL2_Display_PixelFormat_Get +@ stub ADL2_Display_PixelFormat_Set +@ stub ADL2_Display_Position_Get +@ stub ADL2_Display_Position_Set +@ stub ADL2_Display_PossibleMapping_Get +@ stub ADL2_Display_PossibleMode_Get +@ stub ADL2_Display_PowerXpressActiveGPU_Get +@ stub ADL2_Display_PowerXpressActiveGPU_Set +@ stub ADL2_Display_PowerXpressActvieGPUR2_Get +@ stub ADL2_Display_PowerXpressVersion_Get +@ stub ADL2_Display_PowerXpress_AutoSwitchConfig_Get +@ stub ADL2_Display_PowerXpress_AutoSwitchConfig_Set +@ stub ADL2_Display_PreferredMode_Get +@ stub ADL2_Display_PreservedAspectRatio_Get +@ stub ADL2_Display_PreservedAspectRatio_Set +@ stub ADL2_Display_Property_Get +@ stub ADL2_Display_Property_Set +@ stub ADL2_Display_RcDisplayAdjustment +@ stub ADL2_Display_ReGammaCoefficients_Get +@ stub ADL2_Display_ReGammaCoefficients_Set +@ stub ADL2_Display_ReducedBlanking_Get +@ stub ADL2_Display_ReducedBlanking_Set +@ stub ADL2_Display_RegammaR1_Get +@ stub ADL2_Display_RegammaR1_Set +@ stub ADL2_Display_Regamma_Get +@ stub ADL2_Display_Regamma_Set +@ stub ADL2_Display_SLSBuilder_CommonMode_Get +@ stub ADL2_Display_SLSBuilder_Create +@ stub ADL2_Display_SLSBuilder_DisplaysCanBeNextCandidateInSLS_Get +@ stub ADL2_Display_SLSBuilder_DisplaysCanBeNextCandidateToEnabled_Get +@ stub ADL2_Display_SLSBuilder_Get +@ stub ADL2_Display_SLSBuilder_IsActive_Notify +@ stub ADL2_Display_SLSBuilder_MaxSLSLayoutSize_Get +@ stub ADL2_Display_SLSBuilder_TimeOut_Get +@ stub ADL2_Display_SLSBuilder_Update +@ stub ADL2_Display_SLSGrid_Caps +@ stub ADL2_Display_SLSMapConfigX2_Delete +@ stub ADL2_Display_SLSMapConfigX2_Get +@ stub ADL2_Display_SLSMapConfig_Create +@ stub ADL2_Display_SLSMapConfig_Delete +@ stub ADL2_Display_SLSMapConfig_Get +@ stub ADL2_Display_SLSMapConfig_ImageCropType_Set +@ stub ADL2_Display_SLSMapConfig_Rearrange +@ stub ADL2_Display_SLSMapConfig_SetState +@ stub ADL2_Display_SLSMapConfig_SupportedImageCropType_Get +@ stub ADL2_Display_SLSMapConfig_Valid +@ stub ADL2_Display_SLSMapIndexList_Get +@ stub ADL2_Display_SLSMapIndex_Get +@ stub ADL2_Display_SLSMiddleMode_Get +@ stub ADL2_Display_SLSMiddleMode_Set +@ stub ADL2_Display_SLSRecords_Get +@ stub ADL2_Display_Sharpness_Caps +@ stub ADL2_Display_Sharpness_Get +@ stub ADL2_Display_Sharpness_Info_Get +@ stub ADL2_Display_Sharpness_Set +@ stub ADL2_Display_Size_Get +@ stub ADL2_Display_Size_Set +@ stub ADL2_Display_SourceContentAttribute_Get +@ stub ADL2_Display_SourceContentAttribute_Set +@ stub ADL2_Display_SplitDisplay_Caps +@ stub ADL2_Display_SplitDisplay_Get +@ stub ADL2_Display_SplitDisplay_RestoreDesktopConfiguration +@ stub ADL2_Display_SplitDisplay_Set +@ stub ADL2_Display_SupportedColorDepth_Get +@ stub ADL2_Display_SupportedPixelFormat_Get +@ stub ADL2_Display_SwitchingCapability_Get +@ stub ADL2_Display_TVCaps_Get +@ stub ADL2_Display_TargetTimingX2_Get +@ stub ADL2_Display_TargetTiming_Get +@ stub ADL2_Display_UnderScan_Auto_Get +@ stub ADL2_Display_UnderScan_Auto_Set +@ stub ADL2_Display_UnderscanState_Get +@ stub ADL2_Display_UnderscanState_Set +@ stub ADL2_Display_UnderscanSupport_Get +@ stub ADL2_Display_Underscan_Get +@ stub ADL2_Display_Underscan_Set +@ stub ADL2_Display_Vector_Get +@ stub ADL2_Display_ViewPort_Cap +@ stub ADL2_Display_ViewPort_Get +@ stub ADL2_Display_ViewPort_Set +@ stub ADL2_Display_VirtualType_Get +@ stub ADL2_Display_WriteAndReadI2C +@ stub ADL2_Display_WriteAndReadI2CLargePayload +@ stub ADL2_Display_WriteAndReadI2CRev_Get +@ stub ADL2_ElmCompatibilityMode_Caps +@ stub ADL2_ElmCompatibilityMode_Status_Get +@ stub ADL2_ElmCompatibilityMode_Status_Set +@ stub ADL2_ExclusiveModeGet +@ stub ADL2_FPS_Caps +@ stub ADL2_FPS_Settings_Get +@ stub ADL2_FPS_Settings_Reset +@ stub ADL2_FPS_Settings_Set +@ stub ADL2_Feature_Settings_Get +@ stub ADL2_Feature_Settings_Set +@ stub ADL2_Flush_Driver_Data +@ stub ADL2_GPUVMPageSize_Info_Get +@ stub ADL2_GPUVMPageSize_Info_Set +@ stub ADL2_GPUVerInfo_Get +@ stub ADL2_GcnAsicInfo_Get +@ stub ADL2_Graphics_IsDetachableGraphicsPlatform_Get +@ stub ADL2_Graphics_IsGfx9AndAbove +@ stub ADL2_Graphics_MantleVersion_Get +@ stub ADL2_Graphics_Platform_Get +@ stdcall ADL2_Graphics_VersionsX2_Get(ptr ptr) +@ stub ADL2_Graphics_Versions_Get +@ stub ADL2_Graphics_VulkanVersion_Get +@ stub ADL2_HybridGraphicsGPU_Set +@ stub ADL2_MGPUSLS_Status_Set +@ stub ADL2_MMD_FeatureList_Get +@ stub ADL2_MMD_FeatureValuesX2_Get +@ stub ADL2_MMD_FeatureValuesX2_Set +@ stub ADL2_MMD_FeatureValues_Get +@ stub ADL2_MMD_FeatureValues_Set +@ stub ADL2_MMD_FeaturesX2_Caps +@ stub ADL2_MMD_Features_Caps +@ stub ADL2_MMD_VideoAdjustInfo_Get +@ stub ADL2_MMD_VideoAdjustInfo_Set +@ stub ADL2_MMD_VideoColor_Caps +@ stub ADL2_MMD_VideoColor_Get +@ stub ADL2_MMD_VideoColor_Set +@ stub ADL2_MMD_Video_Caps +@ stub ADL2_Main_ControlX2_Create +@ stdcall ADL2_Main_Control_Create(ptr long ptr) +@ stub ADL2_Main_Control_Destroy +@ stub ADL2_Main_Control_GetProcAddress +@ stub ADL2_Main_Control_IsFunctionValid +@ stub ADL2_Main_Control_Refresh +@ stub ADL2_Main_LogDebug_Set +@ stub ADL2_Main_LogError_Set +@ stub ADL2_New_QueryPMLogData_Get +@ stub ADL2_Overdrive5_CurrentActivity_Get +@ stub ADL2_Overdrive5_FanSpeedInfo_Get +@ stub ADL2_Overdrive5_FanSpeedToDefault_Set +@ stub ADL2_Overdrive5_FanSpeed_Get +@ stub ADL2_Overdrive5_FanSpeed_Set +@ stub ADL2_Overdrive5_ODParameters_Get +@ stub ADL2_Overdrive5_ODPerformanceLevels_Get +@ stub ADL2_Overdrive5_ODPerformanceLevels_Set +@ stub ADL2_Overdrive5_PowerControlAbsValue_Caps +@ stub ADL2_Overdrive5_PowerControlAbsValue_Get +@ stub ADL2_Overdrive5_PowerControlAbsValue_Set +@ stub ADL2_Overdrive5_PowerControlInfo_Get +@ stub ADL2_Overdrive5_PowerControl_Caps +@ stub ADL2_Overdrive5_PowerControl_Get +@ stub ADL2_Overdrive5_PowerControl_Set +@ stub ADL2_Overdrive5_Temperature_Get +@ stub ADL2_Overdrive5_ThermalDevices_Enum +@ stub ADL2_Overdrive6_AdvancedFan_Caps +@ stub ADL2_Overdrive6_CapabilitiesEx_Get +@ stub ADL2_Overdrive6_Capabilities_Get +@ stub ADL2_Overdrive6_ControlI2C +@ stub ADL2_Overdrive6_CurrentPower_Get +@ stub ADL2_Overdrive6_CurrentStatus_Get +@ stub ADL2_Overdrive6_FanPWMLimitData_Get +@ stub ADL2_Overdrive6_FanPWMLimitData_Set +@ stub ADL2_Overdrive6_FanPWMLimitRangeInfo_Get +@ stub ADL2_Overdrive6_FanSpeed_Get +@ stub ADL2_Overdrive6_FanSpeed_Reset +@ stub ADL2_Overdrive6_FanSpeed_Set +@ stub ADL2_Overdrive6_FuzzyController_Caps +@ stub ADL2_Overdrive6_MaxClockAdjust_Get +@ stub ADL2_Overdrive6_PowerControlInfo_Get +@ stub ADL2_Overdrive6_PowerControlInfo_Get_X2 +@ stub ADL2_Overdrive6_PowerControl_Caps +@ stub ADL2_Overdrive6_PowerControl_Get +@ stub ADL2_Overdrive6_PowerControl_Set +@ stub ADL2_Overdrive6_StateEx_Get +@ stub ADL2_Overdrive6_StateEx_Set +@ stub ADL2_Overdrive6_StateInfo_Get +@ stub ADL2_Overdrive6_State_Reset +@ stub ADL2_Overdrive6_State_Set +@ stub ADL2_Overdrive6_TargetTemperatureData_Get +@ stub ADL2_Overdrive6_TargetTemperatureData_Set +@ stub ADL2_Overdrive6_TargetTemperatureRangeInfo_Get +@ stub ADL2_Overdrive6_TemperatureEx_Get +@ stub ADL2_Overdrive6_Temperature_Get +@ stub ADL2_Overdrive6_ThermalController_Caps +@ stub ADL2_Overdrive6_ThermalLimitUnlock_Get +@ stub ADL2_Overdrive6_ThermalLimitUnlock_Set +@ stub ADL2_Overdrive6_VoltageControlInfo_Get +@ stub ADL2_Overdrive6_VoltageControl_Get +@ stub ADL2_Overdrive6_VoltageControl_Set +@ stub ADL2_Overdrive8_Current_SettingX2_Get +@ stub ADL2_Overdrive8_Current_SettingX3_Get +@ stub ADL2_Overdrive8_Current_Setting_Get +@ stub ADL2_Overdrive8_Init_SettingX2_Get +@ stub ADL2_Overdrive8_Init_Setting_Get +@ stub ADL2_Overdrive8_PMLogSenorRange_Caps +@ stub ADL2_Overdrive8_PMLogSenorType_Support_Get +@ stub ADL2_Overdrive8_PMLog_ShareMemory_Read +@ stub ADL2_Overdrive8_PMLog_ShareMemory_Start +@ stub ADL2_Overdrive8_PMLog_ShareMemory_Stop +@ stub ADL2_Overdrive8_PMLog_ShareMemory_Support +@ stub ADL2_Overdrive8_Setting_Set +@ stub ADL2_OverdriveN_AutoWattman_Caps +@ stub ADL2_OverdriveN_AutoWattman_Get +@ stub ADL2_OverdriveN_AutoWattman_Set +@ stub ADL2_OverdriveN_CapabilitiesX2_Get +@ stub ADL2_OverdriveN_Capabilities_Get +@ stub ADL2_OverdriveN_CountOfEvents_Get +@ stub ADL2_OverdriveN_FanControl_Get +@ stub ADL2_OverdriveN_FanControl_Set +@ stub ADL2_OverdriveN_MemoryClocksX2_Get +@ stub ADL2_OverdriveN_MemoryClocksX2_Set +@ stub ADL2_OverdriveN_MemoryClocks_Get +@ stub ADL2_OverdriveN_MemoryClocks_Set +@ stub ADL2_OverdriveN_MemoryTimingLevel_Get +@ stub ADL2_OverdriveN_MemoryTimingLevel_Set +@ stub ADL2_OverdriveN_PerformanceStatus_Get +@ stub ADL2_OverdriveN_PowerLimit_Get +@ stub ADL2_OverdriveN_PowerLimit_Set +@ stub ADL2_OverdriveN_SCLKAutoOverClock_Get +@ stub ADL2_OverdriveN_SCLKAutoOverClock_Set +@ stub ADL2_OverdriveN_SettingsExt_Get +@ stub ADL2_OverdriveN_SettingsExt_Set +@ stub ADL2_OverdriveN_SystemClocksX2_Get +@ stub ADL2_OverdriveN_SystemClocksX2_Set +@ stub ADL2_OverdriveN_SystemClocks_Get +@ stub ADL2_OverdriveN_SystemClocks_Set +@ stub ADL2_OverdriveN_Temperature_Get +@ stub ADL2_OverdriveN_Test_Set +@ stub ADL2_OverdriveN_ThrottleNotification_Get +@ stub ADL2_OverdriveN_ZeroRPMFan_Get +@ stub ADL2_OverdriveN_ZeroRPMFan_Set +@ stub ADL2_Overdrive_Caps +@ stub ADL2_PPLogSettings_Get +@ stub ADL2_PPLogSettings_Set +@ stub ADL2_PPW_Caps +@ stub ADL2_PPW_Status_Get +@ stub ADL2_PPW_Status_Set +@ stub ADL2_PageMigration_Settings_Get +@ stub ADL2_PageMigration_Settings_Set +@ stub ADL2_PerGPU_GDEvent_Register +@ stub ADL2_PerGPU_GDEvent_UnRegister +@ stub ADL2_PerfTuning_Status_Get +@ stub ADL2_PerfTuning_Status_Set +@ stub ADL2_PerformanceTuning_Caps +@ stub ADL2_PowerStates_Get +@ stub ADL2_PowerXpress_AncillaryDevices_Get +@ stub ADL2_PowerXpress_Config_Caps +@ stub ADL2_PowerXpress_Configuration_Get +@ stub ADL2_PowerXpress_ExtendedBatteryMode_Caps +@ stub ADL2_PowerXpress_ExtendedBatteryMode_Get +@ stub ADL2_PowerXpress_ExtendedBatteryMode_Set +@ stub ADL2_PowerXpress_LongIdleDetect_Get +@ stub ADL2_PowerXpress_LongIdleDetect_Set +@ stub ADL2_PowerXpress_PowerControlMode_Get +@ stub ADL2_PowerXpress_PowerControlMode_Set +@ stub ADL2_PowerXpress_Scheme_Get +@ stub ADL2_PowerXpress_Scheme_Set +@ stub ADL2_RIS_Settings_Get +@ stub ADL2_RIS_Settings_Set +@ stub ADL2_RegisterEvent +@ stub ADL2_RegisterEventX2 +@ stub ADL2_Remap +@ stub ADL2_RemoteDisplay_Destroy +@ stub ADL2_RemoteDisplay_Display_Acquire +@ stub ADL2_RemoteDisplay_Display_Release +@ stub ADL2_RemoteDisplay_Display_Release_All +@ stub ADL2_RemoteDisplay_Hdcp20_Create +@ stub ADL2_RemoteDisplay_Hdcp20_Destroy +@ stub ADL2_RemoteDisplay_Hdcp20_Notify +@ stub ADL2_RemoteDisplay_Hdcp20_Process +@ stub ADL2_RemoteDisplay_IEPort_Set +@ stub ADL2_RemoteDisplay_Initialize +@ stub ADL2_RemoteDisplay_Nofitiation_Register +@ stub ADL2_RemoteDisplay_Notification_UnRegister +@ stub ADL2_RemoteDisplay_Support_Caps +@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_InUse_Get +@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_Info_Get +@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_RadioState_Get +@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_WPSSetting_Change +@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_WPSSetting_Get +@ stub ADL2_RemoteDisplay_WFDDeviceInfo_Get +@ stub ADL2_RemoteDisplay_WFDDeviceName_Change +@ stub ADL2_RemoteDisplay_WFDDevice_StatusInfo_Get +@ stub ADL2_RemoteDisplay_WFDDiscover_Start +@ stub ADL2_RemoteDisplay_WFDDiscover_Stop +@ stub ADL2_RemoteDisplay_WFDLink_Connect +@ stub ADL2_RemoteDisplay_WFDLink_Creation_Accept +@ stub ADL2_RemoteDisplay_WFDLink_Disconnect +@ stub ADL2_RemoteDisplay_WFDLink_WPS_Process +@ stub ADL2_RemoteDisplay_WFDWDSPSettings_Set +@ stub ADL2_RemoteDisplay_WirelessDisplayEnableDisable_Commit +@ stub ADL2_RemotePlay_ControlFlags_Set +@ stub ADL2_ScreenPoint_AudioMappingInfo_Get +@ stub ADL2_Send +@ stub ADL2_SendX2 +@ stub ADL2_Stereo3D_2DPackedFormat_Set +@ stub ADL2_Stereo3D_3DCursorOffset_Get +@ stub ADL2_Stereo3D_3DCursorOffset_Set +@ stub ADL2_Stereo3D_CurrentFormat_Get +@ stub ADL2_Stereo3D_Info_Get +@ stub ADL2_Stereo3D_Modes_Get +@ stub ADL2_SwitchableGraphics_Applications_Get +@ stub ADL2_TV_Standard_Get +@ stub ADL2_TV_Standard_Set +@ stub ADL2_TurboSyncSupport_Get +@ stub ADL2_UnRegisterEvent +@ stub ADL2_UnRegisterEventX2 +@ stub ADL2_User_Settings_Notify +@ stub ADL2_WS_Overdrive_Caps +@ stub ADL2_Win_IsHybridAI +@ stub ADL2_Workstation_8BitGrayscale_Get +@ stub ADL2_Workstation_8BitGrayscale_Set +@ stub ADL2_Workstation_AdapterNumOfGLSyncConnectors_Get +@ stub ADL2_Workstation_Caps +@ stub ADL2_Workstation_DeepBitDepthX2_Get +@ stub ADL2_Workstation_DeepBitDepthX2_Set +@ stub ADL2_Workstation_DeepBitDepth_Get +@ stub ADL2_Workstation_DeepBitDepth_Set +@ stub ADL2_Workstation_DisplayGLSyncMode_Get +@ stub ADL2_Workstation_DisplayGLSyncMode_Set +@ stub ADL2_Workstation_DisplayGenlockCapable_Get +@ stub ADL2_Workstation_ECCData_Get +@ stub ADL2_Workstation_ECCX2_Get +@ stub ADL2_Workstation_ECC_Caps +@ stub ADL2_Workstation_ECC_Get +@ stub ADL2_Workstation_ECC_Set +@ stub ADL2_Workstation_GLSyncCounters_Get +@ stub ADL2_Workstation_GLSyncGenlockConfiguration_Get +@ stub ADL2_Workstation_GLSyncGenlockConfiguration_Set +@ stub ADL2_Workstation_GLSyncModuleDetect_Get +@ stub ADL2_Workstation_GLSyncModuleInfo_Get +@ stub ADL2_Workstation_GLSyncPortState_Get +@ stub ADL2_Workstation_GLSyncPortState_Set +@ stub ADL2_Workstation_GLSyncSupportedTopology_Get +@ stub ADL2_Workstation_GlobalEDIDPersistence_Get +@ stub ADL2_Workstation_GlobalEDIDPersistence_Set +@ stub ADL2_Workstation_LoadBalancing_Caps +@ stub ADL2_Workstation_LoadBalancing_Get +@ stub ADL2_Workstation_LoadBalancing_Set +@ stub ADL2_Workstation_RAS_ErrorCounts_Get +@ stub ADL2_Workstation_RAS_ErrorCounts_Reset +@ stub ADL2_Workstation_SDISegmentList_Get +@ stub ADL2_Workstation_SDI_Caps +@ stub ADL2_Workstation_SDI_Get +@ stub ADL2_Workstation_SDI_Set +@ stub ADL2_Workstation_Stereo_Get +@ stub ADL2_Workstation_Stereo_Set +@ stub ADL2_Workstation_UnsupportedDisplayModes_Enable +@ stub ADL_ADC_CurrentProfileFromDrv_Get +@ stub ADL_ADC_Display_AdapterDeviceProfileEx_Get +@ stub ADL_ADC_DrvDataToProfile_Copy +@ stub ADL_ADC_FindClosestMode_Get +@ stub ADL_ADC_IsDevModeEqual_Get +@ stub ADL_ADC_Profile_Apply +@ stub ADL_APO_AudioDelayAdjustmentInfo_Get +@ stub ADL_APO_AudioDelay_Restore +@ stub ADL_APO_AudioDelay_Set +@ stub ADL_AdapterLimitation_Caps +@ stub ADL_AdapterX2_Caps +@ stub ADL_Adapter_ASICFamilyType_Get +@ stub ADL_Adapter_ASICInfo_Get +@ stub ADL_Adapter_Accessibility_Get +@ stub ADL_Adapter_Active_Get +@ stub ADL_Adapter_Active_Set +@ stub ADL_Adapter_Active_SetPrefer +@ stub ADL_Adapter_AdapterInfoX2_Get +@ stub ADL_Adapter_AdapterInfo_Get +@ stub ADL_Adapter_AdapterList_Disable +@ stub ADL_Adapter_Aspects_Get +@ stub ADL_Adapter_AudioChannelSplitConfiguration_Get +@ stub ADL_Adapter_AudioChannelSplit_Disable +@ stub ADL_Adapter_AudioChannelSplit_Enable +@ stub ADL_Adapter_BigSw_Info_Get +@ stub ADL_Adapter_BlackAndWhiteLevelSupport_Get +@ stub ADL_Adapter_BlackAndWhiteLevel_Get +@ stub ADL_Adapter_BlackAndWhiteLevel_Set +@ stub ADL_Adapter_BoardLayout_Get +@ stub ADL_Adapter_Caps +@ stub ADL_Adapter_ChipSetInfo_Get +@ stub ADL_Adapter_ConfigMemory_Cap +@ stub ADL_Adapter_ConfigMemory_Get +@ stub ADL_Adapter_ConfigureState_Get +@ stub ADL_Adapter_ConnectionData_Get +@ stub ADL_Adapter_ConnectionData_Remove +@ stub ADL_Adapter_ConnectionData_Set +@ stub ADL_Adapter_ConnectionState_Get +@ stub ADL_Adapter_CrossDisplayPlatformInfo_Get +@ stub ADL_Adapter_CrossdisplayAdapterRole_Caps +@ stub ADL_Adapter_CrossdisplayInfoX2_Set +@ stub ADL_Adapter_CrossdisplayInfo_Get +@ stub ADL_Adapter_CrossdisplayInfo_Set +@ stub ADL_Adapter_CrossfireX2_Get +@ stub ADL_Adapter_Crossfire_Caps +@ stub ADL_Adapter_Crossfire_Get +@ stub ADL_Adapter_Crossfire_Set +@ stub ADL_Adapter_DefaultAudioChannelTable_Load +@ stub ADL_Adapter_DisplayAudioEndpoint_Enable +@ stub ADL_Adapter_DisplayAudioEndpoint_Mute +@ stub ADL_Adapter_DisplayAudioInfo_Get +@ stub ADL_Adapter_DisplayGTCCaps_Get +@ stub ADL_Adapter_Display_Caps +@ stub ADL_Adapter_DriverSettings_Get +@ stub ADL_Adapter_DriverSettings_Set +@ stub ADL_Adapter_EDIDManagement_Caps +@ stub ADL_Adapter_EmulationMode_Set +@ stub ADL_Adapter_ExtInfo_Get +@ stub ADL_Adapter_Gamma_Get +@ stub ADL_Adapter_Gamma_Set +@ stub ADL_Adapter_ID_Get +@ stub ADL_Adapter_LocalDisplayConfig_Get +@ stub ADL_Adapter_LocalDisplayConfig_Set +@ stub ADL_Adapter_LocalDisplayState_Get +@ stub ADL_Adapter_MaxCursorSize_Get +@ stub ADL_Adapter_MemoryInfo2_Get +@ stub ADL_Adapter_MemoryInfo_Get +@ stub ADL_Adapter_MirabilisSupport_Get +@ stub ADL_Adapter_ModeSwitch +@ stub ADL_Adapter_ModeTimingOverride_Caps +@ stub ADL_Adapter_Modes_ReEnumerate +@ stub ADL_Adapter_NumberOfActivatableSources_Get +@ stub ADL_Adapter_NumberOfAdapters_Get +@ stub ADL_Adapter_ObservedClockInfo_Get +@ stub ADL_Adapter_ObservedGameClockInfo_Get +@ stub ADL_Adapter_Primary_Get +@ stub ADL_Adapter_Primary_Set +@ stub ADL_Adapter_RegValueInt_Get +@ stub ADL_Adapter_RegValueInt_Set +@ stub ADL_Adapter_RegValueString_Get +@ stub ADL_Adapter_RegValueString_Set +@ stub ADL_Adapter_SWInfo_Get +@ stub ADL_Adapter_Speed_Caps +@ stub ADL_Adapter_Speed_Get +@ stub ADL_Adapter_Speed_Set +@ stub ADL_Adapter_SupportedConnections_Get +@ stub ADL_Adapter_Tear_Free_Cap +@ stub ADL_Adapter_VariBrightEnable_Set +@ stub ADL_Adapter_VariBrightLevel_Get +@ stub ADL_Adapter_VariBrightLevel_Set +@ stub ADL_Adapter_VariBright_Caps +@ stub ADL_Adapter_VideoBiosInfo_Get +@ stub ADL_Adapter_VideoTheaterModeInfo_Get +@ stub ADL_Adapter_VideoTheaterModeInfo_Set +@ stub ADL_ApplicationProfiles_Applications_Get +@ stub ADL_ApplicationProfiles_ConvertToCompact +@ stub ADL_ApplicationProfiles_DriverAreaPrivacy_Get +@ stub ADL_ApplicationProfiles_GetCustomization +@ stub ADL_ApplicationProfiles_HitListsX2_Get +@ stub ADL_ApplicationProfiles_HitLists_Get +@ stub ADL_ApplicationProfiles_ProfileApplicationX2_Assign +@ stub ADL_ApplicationProfiles_ProfileApplication_Assign +@ stub ADL_ApplicationProfiles_ProfileOfAnApplicationX2_Search +@ stub ADL_ApplicationProfiles_ProfileOfAnApplication_InMemorySearch +@ stub ADL_ApplicationProfiles_ProfileOfAnApplication_Search +@ stub ADL_ApplicationProfiles_Profile_Create +@ stub ADL_ApplicationProfiles_Profile_Exist +@ stub ADL_ApplicationProfiles_Profile_Remove +@ stub ADL_ApplicationProfiles_PropertyType_Get +@ stub ADL_ApplicationProfiles_Release_Get +@ stub ADL_ApplicationProfiles_RemoveApplication +@ stub ADL_ApplicationProfiles_StatusInfo_Get +@ stub ADL_ApplicationProfiles_System_Reload +@ stub ADL_ApplicationProfiles_User_Load +@ stub ADL_ApplicationProfiles_User_Unload +@ stub ADL_Audio_CurrentSampleRate_Get +@ stub ADL_CDS_UnsafeMode_Set +@ stub ADL_CV_DongleSettings_Get +@ stub ADL_CV_DongleSettings_Reset +@ stub ADL_CV_DongleSettings_Set +@ stub ADL_DFP_AllowOnlyCETimings_Get +@ stub ADL_DFP_AllowOnlyCETimings_Set +@ stub ADL_DFP_BaseAudioSupport_Get +@ stub ADL_DFP_GPUScalingEnable_Get +@ stub ADL_DFP_GPUScalingEnable_Set +@ stub ADL_DFP_HDMISupport_Get +@ stub ADL_DFP_MVPUAnalogSupport_Get +@ stub ADL_DFP_PixelFormat_Caps +@ stub ADL_DFP_PixelFormat_Get +@ stub ADL_DFP_PixelFormat_Set +@ stub ADL_DisplayScaling_Set +@ stub ADL_Display_AdapterID_Get +@ stub ADL_Display_AdjustCaps_Get +@ stub ADL_Display_AdjustmentCoherent_Get +@ stub ADL_Display_AdjustmentCoherent_Set +@ stub ADL_Display_AudioMappingInfo_Get +@ stub ADL_Display_AvivoColor_Get +@ stub ADL_Display_AvivoCurrentColor_Set +@ stub ADL_Display_AvivoDefaultColor_Set +@ stub ADL_Display_BackLight_Get +@ stub ADL_Display_BackLight_Set +@ stub ADL_Display_BezelOffsetSteppingSize_Get +@ stub ADL_Display_BezelOffset_Set +@ stub ADL_Display_BezelSupported_Validate +@ stub ADL_Display_Capabilities_Get +@ stub ADL_Display_ColorCaps_Get +@ stub ADL_Display_ColorDepth_Get +@ stub ADL_Display_ColorDepth_Set +@ stub ADL_Display_ColorTemperatureSource_Get +@ stub ADL_Display_ColorTemperatureSource_Set +@ stub ADL_Display_Color_Get +@ stub ADL_Display_Color_Set +@ stub ADL_Display_ConnectedDisplays_Get +@ stub ADL_Display_ContainerID_Get +@ stub ADL_Display_ControllerOverlayAdjustmentCaps_Get +@ stub ADL_Display_ControllerOverlayAdjustmentData_Get +@ stub ADL_Display_ControllerOverlayAdjustmentData_Set +@ stub ADL_Display_CurrentPixelClock_Get +@ stub ADL_Display_CustomizedModeListNum_Get +@ stub ADL_Display_CustomizedModeList_Get +@ stub ADL_Display_CustomizedMode_Add +@ stub ADL_Display_CustomizedMode_Delete +@ stub ADL_Display_CustomizedMode_Validate +@ stub ADL_Display_DCE_Get +@ stub ADL_Display_DCE_Set +@ stub ADL_Display_DDCBlockAccess_Get +@ stub ADL_Display_DDCInfo2_Get +@ stub ADL_Display_DDCInfo_Get +@ stub ADL_Display_Deflicker_Get +@ stub ADL_Display_Deflicker_Set +@ stub ADL_Display_DeviceConfig_Get +@ stub ADL_Display_DisplayContent_Cap +@ stub ADL_Display_DisplayContent_Get +@ stub ADL_Display_DisplayContent_Set +@ stub ADL_Display_DisplayInfo_Get +@ stub ADL_Display_DisplayMapConfig_Get +@ stub ADL_Display_DisplayMapConfig_PossibleAddAndRemove +@ stub ADL_Display_DisplayMapConfig_Set +@ stub ADL_Display_DisplayMapConfig_Validate +@ stub ADL_Display_DitherState_Get +@ stub ADL_Display_DitherState_Set +@ stub ADL_Display_Downscaling_Caps +@ stub ADL_Display_DpMstInfo_Get +@ stub ADL_Display_EdidData_Get +@ stub ADL_Display_EdidData_Set +@ stub ADL_Display_EnumDisplays_Get +@ stub ADL_Display_FilterSVideo_Get +@ stub ADL_Display_FilterSVideo_Set +@ stub ADL_Display_ForcibleDisplay_Get +@ stub ADL_Display_ForcibleDisplay_Set +@ stub ADL_Display_FormatsOverride_Get +@ stub ADL_Display_FormatsOverride_Set +@ stub ADL_Display_FreeSyncState_Get +@ stub ADL_Display_FreeSyncState_Set +@ stub ADL_Display_FreeSync_Cap +@ stub ADL_Display_GamutMapping_Get +@ stub ADL_Display_GamutMapping_Reset +@ stub ADL_Display_GamutMapping_Set +@ stub ADL_Display_Gamut_Caps +@ stub ADL_Display_Gamut_Get +@ stub ADL_Display_Gamut_Set +@ stub ADL_Display_ImageExpansion_Get +@ stub ADL_Display_ImageExpansion_Set +@ stub ADL_Display_InfoPacket_Get +@ stub ADL_Display_InfoPacket_Set +@ stub ADL_Display_LCDRefreshRateCapability_Get +@ stub ADL_Display_LCDRefreshRateOptions_Get +@ stub ADL_Display_LCDRefreshRateOptions_Set +@ stub ADL_Display_LCDRefreshRate_Get +@ stub ADL_Display_LCDRefreshRate_Set +@ stub ADL_Display_Limits_Get +@ stub ADL_Display_MVPUCaps_Get +@ stub ADL_Display_MVPUStatus_Get +@ stub ADL_Display_ModeTimingOverrideInfo_Get +@ stub ADL_Display_ModeTimingOverrideListX2_Get +@ stub ADL_Display_ModeTimingOverrideList_Get +@ stub ADL_Display_ModeTimingOverrideX2_Get +@ stub ADL_Display_ModeTimingOverride_Delete +@ stub ADL_Display_ModeTimingOverride_Get +@ stub ADL_Display_ModeTimingOverride_Set +@ stub ADL_Display_Modes_Get +@ stub ADL_Display_Modes_Set +@ stub ADL_Display_MonitorPowerState_Set +@ stub ADL_Display_NativeAUXChannel_Access +@ stub ADL_Display_NeedWorkaroundFor5Clone_Get +@ stub ADL_Display_NumberOfDisplays_Get +@ stub ADL_Display_ODClockConfig_Set +@ stub ADL_Display_ODClockInfo_Get +@ stub ADL_Display_Overlap_Set +@ stub ADL_Display_Overscan_Get +@ stub ADL_Display_Overscan_Set +@ stub ADL_Display_PixelClockAllowableRange_Set +@ stub ADL_Display_PixelClockCaps_Get +@ stub ADL_Display_PixelFormat_Get +@ stub ADL_Display_PixelFormat_Set +@ stub ADL_Display_Position_Get +@ stub ADL_Display_Position_Set +@ stub ADL_Display_PossibleMapping_Get +@ stub ADL_Display_PossibleMode_Get +@ stub ADL_Display_PowerXpressActiveGPU_Get +@ stub ADL_Display_PowerXpressActiveGPU_Set +@ stub ADL_Display_PowerXpressActvieGPUR2_Get +@ stub ADL_Display_PowerXpressVersion_Get +@ stub ADL_Display_PowerXpress_AutoSwitchConfig_Get +@ stub ADL_Display_PowerXpress_AutoSwitchConfig_Set +@ stub ADL_Display_PreservedAspectRatio_Get +@ stub ADL_Display_PreservedAspectRatio_Set +@ stub ADL_Display_Property_Get +@ stub ADL_Display_Property_Set +@ stub ADL_Display_RcDisplayAdjustment +@ stub ADL_Display_ReGammaCoefficients_Get +@ stub ADL_Display_ReGammaCoefficients_Set +@ stub ADL_Display_ReducedBlanking_Get +@ stub ADL_Display_ReducedBlanking_Set +@ stub ADL_Display_RegammaR1_Get +@ stub ADL_Display_RegammaR1_Set +@ stub ADL_Display_Regamma_Get +@ stub ADL_Display_Regamma_Set +@ stub ADL_Display_SLSGrid_Caps +@ stub ADL_Display_SLSMapConfigX2_Get +@ stub ADL_Display_SLSMapConfig_Create +@ stub ADL_Display_SLSMapConfig_Delete +@ stub ADL_Display_SLSMapConfig_Get +@ stub ADL_Display_SLSMapConfig_Rearrange +@ stub ADL_Display_SLSMapConfig_SetState +@ stub ADL_Display_SLSMapIndexList_Get +@ stub ADL_Display_SLSMapIndex_Get +@ stub ADL_Display_SLSMiddleMode_Get +@ stub ADL_Display_SLSMiddleMode_Set +@ stub ADL_Display_SLSRecords_Get +@ stub ADL_Display_Sharpness_Caps +@ stub ADL_Display_Sharpness_Get +@ stub ADL_Display_Sharpness_Info_Get +@ stub ADL_Display_Sharpness_Set +@ stub ADL_Display_Size_Get +@ stub ADL_Display_Size_Set +@ stub ADL_Display_SourceContentAttribute_Get +@ stub ADL_Display_SourceContentAttribute_Set +@ stub ADL_Display_SplitDisplay_Caps +@ stub ADL_Display_SplitDisplay_Get +@ stub ADL_Display_SplitDisplay_RestoreDesktopConfiguration +@ stub ADL_Display_SplitDisplay_Set +@ stub ADL_Display_SupportedColorDepth_Get +@ stub ADL_Display_SupportedPixelFormat_Get +@ stub ADL_Display_SwitchingCapability_Get +@ stub ADL_Display_TVCaps_Get +@ stub ADL_Display_TargetTiming_Get +@ stub ADL_Display_UnderScan_Auto_Get +@ stub ADL_Display_UnderScan_Auto_Set +@ stub ADL_Display_Underscan_Get +@ stub ADL_Display_Underscan_Set +@ stub ADL_Display_Vector_Get +@ stub ADL_Display_ViewPort_Cap +@ stub ADL_Display_ViewPort_Get +@ stub ADL_Display_ViewPort_Set +@ stub ADL_Display_WriteAndReadI2C +@ stub ADL_Display_WriteAndReadI2CLargePayload +@ stub ADL_Display_WriteAndReadI2CRev_Get +@ stub ADL_Flush_Driver_Data +@ stub ADL_Graphics_Platform_Get +@ stdcall ADL_Graphics_Versions_Get(ptr) +@ stub ADL_MMD_FeatureList_Get +@ stub ADL_MMD_FeatureValuesX2_Get +@ stub ADL_MMD_FeatureValuesX2_Set +@ stub ADL_MMD_FeatureValues_Get +@ stub ADL_MMD_FeatureValues_Set +@ stub ADL_MMD_FeaturesX2_Caps +@ stub ADL_MMD_Features_Caps +@ stub ADL_MMD_VideoAdjustInfo_Get +@ stub ADL_MMD_VideoAdjustInfo_Set +@ stub ADL_MMD_VideoColor_Caps +@ stub ADL_MMD_VideoColor_Get +@ stub ADL_MMD_VideoColor_Set +@ stub ADL_MMD_Video_Caps +@ stub ADL_Main_ControlX2_Create +@ stdcall ADL_Main_Control_Create(ptr long) +@ stdcall ADL_Main_Control_Destroy() +@ stub ADL_Main_Control_GetProcAddress +@ stub ADL_Main_Control_IsFunctionValid +@ stub ADL_Main_Control_Refresh +@ stub ADL_Main_LogDebug_Set +@ stub ADL_Main_LogError_Set +@ stub ADL_Overdrive5_CurrentActivity_Get +@ stub ADL_Overdrive5_FanSpeedInfo_Get +@ stub ADL_Overdrive5_FanSpeedToDefault_Set +@ stub ADL_Overdrive5_FanSpeed_Get +@ stub ADL_Overdrive5_FanSpeed_Set +@ stub ADL_Overdrive5_ODParameters_Get +@ stub ADL_Overdrive5_ODPerformanceLevels_Get +@ stub ADL_Overdrive5_ODPerformanceLevels_Set +@ stub ADL_Overdrive5_PowerControlAbsValue_Caps +@ stub ADL_Overdrive5_PowerControlAbsValue_Get +@ stub ADL_Overdrive5_PowerControlAbsValue_Set +@ stub ADL_Overdrive5_PowerControlInfo_Get +@ stub ADL_Overdrive5_PowerControl_Caps +@ stub ADL_Overdrive5_PowerControl_Get +@ stub ADL_Overdrive5_PowerControl_Set +@ stub ADL_Overdrive5_Temperature_Get +@ stub ADL_Overdrive5_ThermalDevices_Enum +@ stub ADL_Overdrive6_AdvancedFan_Caps +@ stub ADL_Overdrive6_CapabilitiesEx_Get +@ stub ADL_Overdrive6_Capabilities_Get +@ stub ADL_Overdrive6_CurrentStatus_Get +@ stub ADL_Overdrive6_FanPWMLimitData_Get +@ stub ADL_Overdrive6_FanPWMLimitData_Set +@ stub ADL_Overdrive6_FanPWMLimitRangeInfo_Get +@ stub ADL_Overdrive6_FanSpeed_Get +@ stub ADL_Overdrive6_FanSpeed_Reset +@ stub ADL_Overdrive6_FanSpeed_Set +@ stub ADL_Overdrive6_FuzzyController_Caps +@ stub ADL_Overdrive6_MaxClockAdjust_Get +@ stub ADL_Overdrive6_PowerControlInfo_Get +@ stub ADL_Overdrive6_PowerControl_Caps +@ stub ADL_Overdrive6_PowerControl_Get +@ stub ADL_Overdrive6_PowerControl_Set +@ stub ADL_Overdrive6_StateEx_Get +@ stub ADL_Overdrive6_StateEx_Set +@ stub ADL_Overdrive6_StateInfo_Get +@ stub ADL_Overdrive6_State_Reset +@ stub ADL_Overdrive6_State_Set +@ stub ADL_Overdrive6_TargetTemperatureData_Get +@ stub ADL_Overdrive6_TargetTemperatureData_Set +@ stub ADL_Overdrive6_TargetTemperatureRangeInfo_Get +@ stub ADL_Overdrive6_Temperature_Get +@ stub ADL_Overdrive6_ThermalController_Caps +@ stub ADL_Overdrive6_ThermalLimitUnlock_Get +@ stub ADL_Overdrive6_ThermalLimitUnlock_Set +@ stub ADL_Overdrive6_VoltageControlInfo_Get +@ stub ADL_Overdrive6_VoltageControl_Get +@ stub ADL_Overdrive6_VoltageControl_Set +@ stub ADL_Overdrive_Caps +@ stub ADL_PowerXpress_AncillaryDevices_Get +@ stub ADL_PowerXpress_Config_Caps +@ stub ADL_PowerXpress_ExtendedBatteryMode_Caps +@ stub ADL_PowerXpress_ExtendedBatteryMode_Get +@ stub ADL_PowerXpress_ExtendedBatteryMode_Set +@ stub ADL_PowerXpress_LongIdleDetect_Get +@ stub ADL_PowerXpress_LongIdleDetect_Set +@ stub ADL_PowerXpress_PowerControlMode_Get +@ stub ADL_PowerXpress_PowerControlMode_Set +@ stub ADL_PowerXpress_Scheme_Get +@ stub ADL_PowerXpress_Scheme_Set +@ stub ADL_Remap +@ stub ADL_RemoteDisplay_Destroy +@ stub ADL_RemoteDisplay_Display_Acquire +@ stub ADL_RemoteDisplay_Display_Release +@ stub ADL_RemoteDisplay_Display_Release_All +@ stub ADL_RemoteDisplay_Hdcp20_Create +@ stub ADL_RemoteDisplay_Hdcp20_Destroy +@ stub ADL_RemoteDisplay_Hdcp20_Notify +@ stub ADL_RemoteDisplay_Hdcp20_Process +@ stub ADL_RemoteDisplay_IEPort_Set +@ stub ADL_RemoteDisplay_Initialize +@ stub ADL_RemoteDisplay_Nofitiation_Register +@ stub ADL_RemoteDisplay_Notification_UnRegister +@ stub ADL_RemoteDisplay_Support_Caps +@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_InUse_Get +@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_Info_Get +@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_RadioState_Get +@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_WPSSetting_Change +@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_WPSSetting_Get +@ stub ADL_RemoteDisplay_WFDDeviceInfo_Get +@ stub ADL_RemoteDisplay_WFDDeviceName_Change +@ stub ADL_RemoteDisplay_WFDDevice_StatusInfo_Get +@ stub ADL_RemoteDisplay_WFDDiscover_Start +@ stub ADL_RemoteDisplay_WFDDiscover_Stop +@ stub ADL_RemoteDisplay_WFDLink_Connect +@ stub ADL_RemoteDisplay_WFDLink_Creation_Accept +@ stub ADL_RemoteDisplay_WFDLink_Disconnect +@ stub ADL_RemoteDisplay_WFDLink_WPS_Process +@ stub ADL_RemoteDisplay_WFDWDSPSettings_Set +@ stub ADL_RemoteDisplay_WirelessDisplayEnableDisable_Commit +@ stub ADL_ScreenPoint_AudioMappingInfo_Get +@ stub ADL_Stereo3D_2DPackedFormat_Set +@ stub ADL_Stereo3D_3DCursorOffset_Get +@ stub ADL_Stereo3D_3DCursorOffset_Set +@ stub ADL_Stereo3D_CurrentFormat_Get +@ stub ADL_Stereo3D_Info_Get +@ stub ADL_Stereo3D_Modes_Get +@ stub ADL_TV_Standard_Get +@ stub ADL_TV_Standard_Set +@ stub ADL_Win_IsHybridAI +@ stub ADL_Workstation_8BitGrayscale_Get +@ stub ADL_Workstation_8BitGrayscale_Set +@ stub ADL_Workstation_AdapterNumOfGLSyncConnectors_Get +@ stub ADL_Workstation_Caps +@ stub ADL_Workstation_DeepBitDepthX2_Get +@ stub ADL_Workstation_DeepBitDepthX2_Set +@ stub ADL_Workstation_DeepBitDepth_Get +@ stub ADL_Workstation_DeepBitDepth_Set +@ stub ADL_Workstation_DisplayGLSyncMode_Get +@ stub ADL_Workstation_DisplayGLSyncMode_Set +@ stub ADL_Workstation_DisplayGenlockCapable_Get +@ stub ADL_Workstation_ECCData_Get +@ stub ADL_Workstation_ECCX2_Get +@ stub ADL_Workstation_ECC_Caps +@ stub ADL_Workstation_ECC_Get +@ stub ADL_Workstation_ECC_Set +@ stub ADL_Workstation_GLSyncCounters_Get +@ stub ADL_Workstation_GLSyncGenlockConfiguration_Get +@ stub ADL_Workstation_GLSyncGenlockConfiguration_Set +@ stub ADL_Workstation_GLSyncModuleDetect_Get +@ stub ADL_Workstation_GLSyncModuleInfo_Get +@ stub ADL_Workstation_GLSyncPortState_Get +@ stub ADL_Workstation_GLSyncPortState_Set +@ stub ADL_Workstation_GLSyncSupportedTopology_Get +@ stub ADL_Workstation_GlobalEDIDPersistence_Get +@ stub ADL_Workstation_GlobalEDIDPersistence_Set +@ stub ADL_Workstation_LoadBalancing_Caps +@ stub ADL_Workstation_LoadBalancing_Get +@ stub ADL_Workstation_LoadBalancing_Set +@ stub ADL_Workstation_RAS_Get_Error_Counts +@ stub ADL_Workstation_RAS_Get_Features +@ stub ADL_Workstation_RAS_Reset_Error_Counts +@ stub ADL_Workstation_RAS_Set_Features +@ stub ADL_Workstation_SDISegmentList_Get +@ stub ADL_Workstation_SDI_Caps +@ stub ADL_Workstation_SDI_Get +@ stub ADL_Workstation_SDI_Set +@ stub ADL_Workstation_Stereo_Get +@ stub ADL_Workstation_Stereo_Set +@ stub ADL_Workstation_UnsupportedDisplayModes_Enable +@ stub AmdPowerXpressRequestHighPerformance +@ stub Desktop_Detach +@ stub Send +@ stub SendX2 diff --git a/dlls/atiadlxx/atiadlxx_main.c b/dlls/atiadlxx/atiadlxx_main.c new file mode 100644 index 00000000000..0b037bb1946 --- /dev/null +++ b/dlls/atiadlxx/atiadlxx_main.c @@ -0,0 +1,91 @@ +#include + +#include "windef.h" +#include "winbase.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(atiadlxx); + +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) +{ + TRACE("(%p, %u, %p)\n", instance, reason, reserved); + + switch (reason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(instance); + break; + } + + return TRUE; +} + +typedef void *(CALLBACK *ADL_MAIN_MALLOC_CALLBACK)(int); +typedef void *ADL_CONTEXT_HANDLE; + +typedef struct ADLVersionsInfo +{ + char strDriverVer[256]; + char strCatalystVersion[256]; + char strCatalystWebLink[256]; +} ADLVersionsInfo, *LPADLVersionsInfo; + +typedef struct ADLVersionsInfoX2 +{ + char strDriverVer[256]; + char strCatalystVersion[256]; + char strCrimsonVersion[256]; + char strCatalystWebLink[256]; +} ADLVersionsInfoX2, *LPADLVersionsInfoX2; + +static const ADLVersionsInfo version = { + "16.11.2", + "16.11.2", + "", +}; + +static const ADLVersionsInfoX2 version2 = { + "16.11.2", + "16.11.2", + "16.11.2", + "", +}; + +int WINAPI ADL2_Main_Control_Create(ADL_MAIN_MALLOC_CALLBACK cb, int arg, ADL_CONTEXT_HANDLE *ptr) +{ + FIXME("cb %p, arg %d, ptr %p stub!\n", cb, arg, ptr); + return 0; +} + +int WINAPI ADL_Main_Control_Create(ADL_MAIN_MALLOC_CALLBACK cb, int arg) +{ + FIXME("cb %p, arg %d stub!\n", cb, arg); + return 0; +} + +int WINAPI ADL_Main_Control_Destroy(void) +{ + FIXME("stub!\n"); + return 0; +} + +int WINAPI ADL2_Adapter_NumberOfAdapters_Get(ADL_CONTEXT_HANDLE *ptr, int *count) +{ + FIXME("ptr %p, count %p stub!\n", ptr, count); + *count = 0; + return 0; +} + +int WINAPI ADL2_Graphics_VersionsX2_Get(ADL_CONTEXT_HANDLE *ptr, ADLVersionsInfoX2 *ver) +{ + FIXME("ptr %p, ver %p stub!\n", ptr, ver); + memcpy(ver, &version2, sizeof(version2)); + return 0; +} + +int WINAPI ADL_Graphics_Versions_Get(ADLVersionsInfo *ver) +{ + FIXME("ver %p stub!\n", ver); + memcpy(ver, &version, sizeof(version)); + return 0; +} diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 6dc31196cdf..1a01a9f63b5 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2724,6 +2724,7 @@ HKCU,Software\Wine\DllOverrides,"msvcr140",0x2,"native,builtin" HKCU,Software\Wine\DllOverrides,"ucrtbase",0x2,"native,builtin" HKCU,Software\Wine\DllOverrides,"vcomp140",0x2,"native,builtin" HKCU,Software\Wine\DllOverrides,"vcruntime140",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"atiadlxx",,"disabled" ;;App-specific overrides for amd_ags_x64.dll. HKCU,Software\Wine\AppDefaults\NewColossus_x64vk.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" HKCU,Software\Wine\AppDefaults\RDR2.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" From 8932fd6a1e46da7a64a151a5559224f507481635 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 12 Oct 2020 17:46:27 +0300 Subject: [PATCH 0362/2777] atiadlxx: Stub GPU/display enumeration and clock/memory info. Shadow of War uses atiadlxx to query the following GPU information: * current memory frequency * current core frequency * memory size * memory bandwidth Those are used to apprise the GPU and recommend user settings. Most of them can be fetched via AMD's powerplay sysfs entries / wined3d helpers. The only value that is not exposed is the memory bandwith so we set it to the value my RX580 reports on Windows. Because of that on high end system the game may recommend lower settings than it would with the real value, and the other way around on low end systems. We also report some "sane default" in case we can't find the powerplay entries - this may be the case with nvapi hack enabled when we report any NVIDIA card as RX480. ADL2 stubs used by Call of Duty games are untouched and still report 0 GPUs. --- dlls/atiadlxx/Makefile.in | 2 + dlls/atiadlxx/atiadlxx.spec | 18 +- dlls/atiadlxx/atiadlxx_main.c | 369 ++++++++++++++++++++++++++++++++-- 3 files changed, 367 insertions(+), 22 deletions(-) diff --git a/dlls/atiadlxx/Makefile.in b/dlls/atiadlxx/Makefile.in index de1b4c5bc74..859d2db12da 100644 --- a/dlls/atiadlxx/Makefile.in +++ b/dlls/atiadlxx/Makefile.in @@ -1,5 +1,7 @@ EXTRADEFS = -DWINE_NO_LONG_TYPES MODULE = atiadlxx.dll +IMPORTS = wined3d + EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native C_SRCS = \ diff --git a/dlls/atiadlxx/atiadlxx.spec b/dlls/atiadlxx/atiadlxx.spec index e2a1f46a838..e2fb060ae8d 100644 --- a/dlls/atiadlxx/atiadlxx.spec +++ b/dlls/atiadlxx/atiadlxx.spec @@ -681,14 +681,14 @@ @ stub ADL_APO_AudioDelay_Set @ stub ADL_AdapterLimitation_Caps @ stub ADL_AdapterX2_Caps -@ stub ADL_Adapter_ASICFamilyType_Get +@ stdcall ADL_Adapter_ASICFamilyType_Get(long ptr ptr) @ stub ADL_Adapter_ASICInfo_Get @ stub ADL_Adapter_Accessibility_Get @ stub ADL_Adapter_Active_Get @ stub ADL_Adapter_Active_Set @ stub ADL_Adapter_Active_SetPrefer @ stub ADL_Adapter_AdapterInfoX2_Get -@ stub ADL_Adapter_AdapterInfo_Get +@ stdcall ADL_Adapter_AdapterInfo_Get(ptr long) @ stub ADL_Adapter_AdapterList_Disable @ stub ADL_Adapter_Aspects_Get @ stub ADL_Adapter_AudioChannelSplitConfiguration_Get @@ -714,8 +714,8 @@ @ stub ADL_Adapter_CrossdisplayInfo_Get @ stub ADL_Adapter_CrossdisplayInfo_Set @ stub ADL_Adapter_CrossfireX2_Get -@ stub ADL_Adapter_Crossfire_Caps -@ stub ADL_Adapter_Crossfire_Get +@ stdcall ADL_Adapter_Crossfire_Caps(long ptr ptr ptr) +@ stdcall ADL_Adapter_Crossfire_Get(long ptr ptr) @ stub ADL_Adapter_Crossfire_Set @ stub ADL_Adapter_DefaultAudioChannelTable_Load @ stub ADL_Adapter_DisplayAudioEndpoint_Enable @@ -736,14 +736,14 @@ @ stub ADL_Adapter_LocalDisplayState_Get @ stub ADL_Adapter_MaxCursorSize_Get @ stub ADL_Adapter_MemoryInfo2_Get -@ stub ADL_Adapter_MemoryInfo_Get +@ stdcall ADL_Adapter_MemoryInfo_Get(long ptr) @ stub ADL_Adapter_MirabilisSupport_Get @ stub ADL_Adapter_ModeSwitch @ stub ADL_Adapter_ModeTimingOverride_Caps @ stub ADL_Adapter_Modes_ReEnumerate @ stub ADL_Adapter_NumberOfActivatableSources_Get -@ stub ADL_Adapter_NumberOfAdapters_Get -@ stub ADL_Adapter_ObservedClockInfo_Get +@ stdcall ADL_Adapter_NumberOfAdapters_Get(ptr) +@ stdcall ADL_Adapter_ObservedClockInfo_Get(long ptr ptr) @ stub ADL_Adapter_ObservedGameClockInfo_Get @ stub ADL_Adapter_Primary_Get @ stub ADL_Adapter_Primary_Set @@ -844,7 +844,7 @@ @ stub ADL_Display_DisplayContent_Cap @ stub ADL_Display_DisplayContent_Get @ stub ADL_Display_DisplayContent_Set -@ stub ADL_Display_DisplayInfo_Get +@ stdcall ADL_Display_DisplayInfo_Get(long long ptr long) @ stub ADL_Display_DisplayMapConfig_Get @ stub ADL_Display_DisplayMapConfig_PossibleAddAndRemove @ stub ADL_Display_DisplayMapConfig_Set @@ -969,7 +969,7 @@ @ stub ADL_Display_WriteAndReadI2CLargePayload @ stub ADL_Display_WriteAndReadI2CRev_Get @ stub ADL_Flush_Driver_Data -@ stub ADL_Graphics_Platform_Get +@ stdcall ADL_Graphics_Platform_Get(ptr) @ stdcall ADL_Graphics_Versions_Get(ptr) @ stub ADL_MMD_FeatureList_Get @ stub ADL_MMD_FeatureValuesX2_Get diff --git a/dlls/atiadlxx/atiadlxx_main.c b/dlls/atiadlxx/atiadlxx_main.c index 0b037bb1946..b1e7551ac82 100644 --- a/dlls/atiadlxx/atiadlxx_main.c +++ b/dlls/atiadlxx/atiadlxx_main.c @@ -1,8 +1,43 @@ +/* Headers: https://github.com/GPUOpen-LibrariesAndSDKs/display-library */ + #include +#include +#include +#define COBJMACROS #include "windef.h" #include "winbase.h" +#include "winuser.h" +#include "objbase.h" #include "wine/debug.h" +#include "wine/wined3d.h" + +#define MAX_GPUS 64 +#define VENDOR_AMD 0x1002 + +#define ADL_OK 0 +#define ADL_ERR -1 +#define ADL_ERR_INVALID_PARAM -3 +#define ADL_ERR_INVALID_ADL_IDX -5 +#define ADL_ERR_NOT_SUPPORTED -8 +#define ADL_ERR_NULL_POINTER -9 + +#define ADL_DISPLAY_DISPLAYINFO_DISPLAYCONNECTED 0x00000001 +#define ADL_DISPLAY_DISPLAYINFO_DISPLAYMAPPED 0x00000002 +#define ADL_DISPLAY_DISPLAYINFO_MASK 0x31fff + +#define ADL_ASIC_DISCRETE (1 << 0) +#define ADL_ASIC_MASK 0xAF + +enum ADLPlatForm +{ + GRAPHICS_PLATFORM_DESKTOP = 0, + GRAPHICS_PLATFORM_MOBILE = 1 +}; +#define GRAPHICS_PLATFORM_UNKNOWN -1 + + +static struct wined3d *wined3d; WINE_DEFAULT_DEBUG_CHANNEL(atiadlxx); @@ -23,21 +58,83 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) typedef void *(CALLBACK *ADL_MAIN_MALLOC_CALLBACK)(int); typedef void *ADL_CONTEXT_HANDLE; +ADL_MAIN_MALLOC_CALLBACK adl_malloc; +#define ADL_MAX_PATH 256 + typedef struct ADLVersionsInfo { - char strDriverVer[256]; - char strCatalystVersion[256]; - char strCatalystWebLink[256]; + char strDriverVer[ADL_MAX_PATH]; + char strCatalystVersion[ADL_MAX_PATH]; + char strCatalystWebLink[ADL_MAX_PATH]; } ADLVersionsInfo, *LPADLVersionsInfo; typedef struct ADLVersionsInfoX2 { - char strDriverVer[256]; - char strCatalystVersion[256]; - char strCrimsonVersion[256]; - char strCatalystWebLink[256]; + char strDriverVer[ADL_MAX_PATH]; + char strCatalystVersion[ADL_MAX_PATH]; + char strCrimsonVersion[ADL_MAX_PATH]; + char strCatalystWebLink[ADL_MAX_PATH]; } ADLVersionsInfoX2, *LPADLVersionsInfoX2; +typedef struct ADLAdapterInfo { + int iSize; + int iAdapterIndex; + char strUDID[ADL_MAX_PATH]; + int iBusNumber; + int iDeviceNumber; + int iFunctionNumber; + int iVendorID; + char strAdapterName[ADL_MAX_PATH]; + char strDisplayName[ADL_MAX_PATH]; + int iPresent; + int iExist; + char strDriverPath[ADL_MAX_PATH]; + char strDriverPathExt[ADL_MAX_PATH]; + char strPNPString[ADL_MAX_PATH]; + int iOSDisplayIndex; +} ADLAdapterInfo, *LPADLAdapterInfo; + +typedef struct ADLDisplayID +{ + int iDisplayLogicalIndex; + int iDisplayPhysicalIndex; + int iDisplayLogicalAdapterIndex; + int iDisplayPhysicalAdapterIndex; +} ADLDisplayID, *LPADLDisplayID; + +typedef struct ADLDisplayInfo +{ + ADLDisplayID displayID; + int iDisplayControllerIndex; + char strDisplayName[ADL_MAX_PATH]; + char strDisplayManufacturerName[ADL_MAX_PATH]; + int iDisplayType; + int iDisplayOutputType; + int iDisplayConnector; + int iDisplayInfoMask; + int iDisplayInfoValue; +} ADLDisplayInfo, *LPADLDisplayInfo; + +typedef struct ADLCrossfireComb +{ + int iNumLinkAdapter; + int iAdaptLink[3]; +} ADLCrossfireComb; + +typedef struct ADLCrossfireInfo +{ + int iErrorCode; + int iState; + int iSupported; +} ADLCrossfireInfo; + +typedef struct ADLMemoryInfo +{ + long long iMemorySize; + char strMemoryType[ADL_MAX_PATH]; + long long iMemoryBandwidth; +} ADLMemoryInfo, *LPADLMemoryInfo; + static const ADLVersionsInfo version = { "16.11.2", "16.11.2", @@ -54,38 +151,284 @@ static const ADLVersionsInfoX2 version2 = { int WINAPI ADL2_Main_Control_Create(ADL_MAIN_MALLOC_CALLBACK cb, int arg, ADL_CONTEXT_HANDLE *ptr) { FIXME("cb %p, arg %d, ptr %p stub!\n", cb, arg, ptr); - return 0; + return ADL_OK; } int WINAPI ADL_Main_Control_Create(ADL_MAIN_MALLOC_CALLBACK cb, int arg) { FIXME("cb %p, arg %d stub!\n", cb, arg); - return 0; + adl_malloc = cb; + + if ((wined3d = wined3d_create(0))) + return ADL_OK; + else + return ADL_ERR; } int WINAPI ADL_Main_Control_Destroy(void) { FIXME("stub!\n"); - return 0; + + if (wined3d != NULL) + wined3d_decref(wined3d); + + return ADL_OK; } int WINAPI ADL2_Adapter_NumberOfAdapters_Get(ADL_CONTEXT_HANDLE *ptr, int *count) { FIXME("ptr %p, count %p stub!\n", ptr, count); + *count = 0; - return 0; + + return ADL_OK; } int WINAPI ADL2_Graphics_VersionsX2_Get(ADL_CONTEXT_HANDLE *ptr, ADLVersionsInfoX2 *ver) { FIXME("ptr %p, ver %p stub!\n", ptr, ver); memcpy(ver, &version2, sizeof(version2)); - return 0; + return ADL_OK; } int WINAPI ADL_Graphics_Versions_Get(ADLVersionsInfo *ver) { FIXME("ver %p stub!\n", ver); memcpy(ver, &version, sizeof(version)); - return 0; + return ADL_OK; +} + +int WINAPI ADL_Adapter_NumberOfAdapters_Get(int *count) +{ + FIXME("count %p stub!\n", count); + *count = wined3d_get_adapter_count(wined3d); + TRACE("*count = %d\n", *count); + return ADL_OK; +} + +static BOOL get_adapter_identifier(int index, struct wined3d_adapter_identifier *identifier) +{ + struct wined3d_adapter *adapter; + HRESULT hr; + + adapter = wined3d_get_adapter(wined3d, index); + if (adapter == NULL) + return FALSE; + + memset(identifier, 0, sizeof(*identifier)); + hr = wined3d_adapter_get_identifier(adapter, 0, identifier); + + if (!SUCCEEDED(hr)) + return FALSE; + + return TRUE; +} + +/* yep, seriously */ +static int convert_vendor_id(int id) +{ + char str[16]; + snprintf(str, ARRAY_SIZE(str), "%x", id); + return atoi(str); +} + +int WINAPI ADL_Adapter_AdapterInfo_Get(ADLAdapterInfo *adapters, int input_size) +{ + int count, i; + struct wined3d_adapter_identifier identifier; + + FIXME("adapters %p, input_size %d, stub!\n", adapters, input_size); + + count = wined3d_get_adapter_count(wined3d); + + if (!adapters) return ADL_ERR_INVALID_PARAM; + if (input_size != count * sizeof(ADLAdapterInfo)) return ADL_ERR_INVALID_PARAM; + + memset(adapters, 0, input_size); + + for (i = 0; i < count; i++) + { + adapters[i].iSize = sizeof(ADLAdapterInfo); + adapters[i].iAdapterIndex = i; + + if (!get_adapter_identifier(i, &identifier)) + return ADL_ERR; + + adapters[i].iVendorID = convert_vendor_id(identifier.vendor_id); + } + + return ADL_OK; +} + +int WINAPI ADL_Display_DisplayInfo_Get(int adapter_index, int *num_displays, ADLDisplayInfo **info, int force_detect) +{ + struct wined3d_adapter *adapter; + struct wined3d_output *output; + int i; + + FIXME("adapter %d, num_displays %p, info %p stub!\n", adapter_index, num_displays, info); + + if (info == NULL || num_displays == NULL) return ADL_ERR_NULL_POINTER; + + adapter = wined3d_get_adapter(wined3d, adapter_index); + if (adapter == NULL) return ADL_ERR_INVALID_PARAM; + + *num_displays = wined3d_adapter_get_output_count(adapter); + + if (*num_displays == 0) + return ADL_OK; + + *info = adl_malloc(*num_displays * sizeof(**info)); + memset(*info, 0, *num_displays * sizeof(**info)); + + for (i = 0; i < *num_displays; i++) + { + output = wined3d_adapter_get_output(adapter, i); + if (output == NULL) + return ADL_ERR; + + (*info)[i].displayID.iDisplayLogicalIndex = i; + (*info)[i].iDisplayInfoValue = ADL_DISPLAY_DISPLAYINFO_DISPLAYCONNECTED | ADL_DISPLAY_DISPLAYINFO_DISPLAYMAPPED; + (*info)[i].iDisplayInfoMask = (*info)[i].iDisplayInfoValue; + } + + return ADL_OK; +} + +int WINAPI ADL_Adapter_Crossfire_Caps(int adapter_index, int *preffered, int *num_comb, ADLCrossfireComb** comb) +{ + FIXME("adapter %d, preffered %p, num_comb %p, comb %p stub!\n", adapter_index, preffered, num_comb, comb); + return ADL_ERR; +} + +int WINAPI ADL_Adapter_Crossfire_Get(int adapter_index, ADLCrossfireComb *comb, ADLCrossfireInfo *info) +{ + FIXME("adapter %d, comb %p, info %p, stub!\n", adapter_index, comb, info); + return ADL_ERR; +} + +int WINAPI ADL_Adapter_ASICFamilyType_Get(int adapter_index, int *asic_type, int *valids) +{ + struct wined3d_adapter_identifier identifier; + + FIXME("adapter %d, asic_type %p, valids %p, stub!\n", adapter_index, asic_type, valids); + + if (asic_type == NULL || valids == NULL) + return ADL_ERR_NULL_POINTER; + + if (!get_adapter_identifier(adapter_index, &identifier)) + return ADL_ERR_INVALID_ADL_IDX; + + if (identifier.vendor_id != VENDOR_AMD) + return ADL_ERR_NOT_SUPPORTED; + + *asic_type = ADL_ASIC_DISCRETE; + *valids = ADL_ASIC_MASK; + + return ADL_OK; +} + +static int get_max_clock(const char *clock, int default_value) +{ + char path[MAX_PATH], line[256]; + FILE *file; + int drm_card, value = 0; + + for (drm_card = 0; drm_card < MAX_GPUS; drm_card++) + { + sprintf(path, "/sys/class/drm/card%d/device/pp_dpm_%s", drm_card, clock); + file = fopen(path, "r"); + + if (file == NULL) + continue; + + while (fgets(line, sizeof(line), file) != NULL) + { + char *number; + + number = strchr(line, ' '); + if (number == NULL) + { + WARN("pp_dpm_%s file has unexpected format\n", clock); + break; + } + + number++; + value = max(strtol(number, NULL, 0), value); + } + } + + if (value != 0) + return value; + + return default_value; +} + +/* documented in the "Linux Specific APIs" section, present and used on Windows */ +/* the name and documentation suggests that this returns current freqs, but it's actually max */ +int WINAPI ADL_Adapter_ObservedClockInfo_Get(int adapter_index, int *core_clock, int *memory_clock) +{ + struct wined3d_adapter_identifier identifier; + + FIXME("adapter %d, core_clock %p, memory_clock %p, stub!\n", adapter_index, core_clock, memory_clock); + + if (core_clock == NULL || memory_clock == NULL) return ADL_ERR; + if (!get_adapter_identifier(adapter_index, &identifier)) return ADL_ERR; + if (identifier.vendor_id != VENDOR_AMD) return ADL_ERR_INVALID_ADL_IDX; + + /* default values based on RX580 */ + *core_clock = get_max_clock("sclk", 1350); + *memory_clock = get_max_clock("mclk", 2000); + + TRACE("*core_clock: %i, *memory_clock %i\n", *core_clock, *memory_clock); + + return ADL_OK; +} + +/* documented in the "Linux Specific APIs" section, present and used on Windows */ +int WINAPI ADL_Adapter_MemoryInfo_Get(int adapter_index, ADLMemoryInfo *mem_info) +{ + struct wined3d_adapter_identifier identifier; + + FIXME("adapter %d, mem_info %p stub!\n", adapter_index, mem_info); + + if (mem_info == NULL) return ADL_ERR_NULL_POINTER; + if (!get_adapter_identifier(adapter_index, &identifier)) return ADL_ERR_INVALID_ADL_IDX; + if (identifier.vendor_id != VENDOR_AMD) return ADL_ERR; + + mem_info->iMemorySize = identifier.video_memory; + mem_info->iMemoryBandwidth = 256000; /* not exposed on Linux, probably needs a lookup table */ + + TRACE("iMemoryBandwidth %s, iMemorySize %s\n", + wine_dbgstr_longlong(mem_info->iMemoryBandwidth), + wine_dbgstr_longlong(mem_info->iMemorySize)); + return ADL_OK; +} + +int WINAPI ADL_Graphics_Platform_Get(int *platform) +{ + struct wined3d_adapter_identifier identifier; + int count, i; + + FIXME("platform %p, stub!\n", platform); + + *platform = GRAPHICS_PLATFORM_UNKNOWN; + + count = wined3d_get_adapter_count(wined3d); + + for (i = 0; i < count; i ++) + { + if (!get_adapter_identifier(i, &identifier)) + continue; + + if (identifier.vendor_id == VENDOR_AMD) + *platform = GRAPHICS_PLATFORM_DESKTOP; + } + + /* NOTE: The real value can be obtained by doing: + * 1. ioctl(DRM_AMDGPU_INFO) with AMDGPU_INFO_DEV_INFO - dev_info.ids_flags & AMDGPU_IDS_FLAGS_FUSION + * 2. VkPhysicalDeviceType() if we ever switch to wined3d vk adapter implementation + */ + + return ADL_OK; } From 60926bc0200366aceded4a88338d172f4af1414a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 3 Nov 2020 16:26:52 +0100 Subject: [PATCH 0363/2777] atiadlxx: Update fake driver version to 20.10.1. --- dlls/atiadlxx/atiadlxx_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dlls/atiadlxx/atiadlxx_main.c b/dlls/atiadlxx/atiadlxx_main.c index b1e7551ac82..f85c7f8ba62 100644 --- a/dlls/atiadlxx/atiadlxx_main.c +++ b/dlls/atiadlxx/atiadlxx_main.c @@ -136,15 +136,15 @@ typedef struct ADLMemoryInfo } ADLMemoryInfo, *LPADLMemoryInfo; static const ADLVersionsInfo version = { - "16.11.2", - "16.11.2", + "20.10.1", + "20.10.1", "", }; static const ADLVersionsInfoX2 version2 = { - "16.11.2", - "16.11.2", - "16.11.2", + "20.10.1", + "20.10.1", + "20.10.1", "", }; From 692e81558de9fdc317d7e84dd9dfb9087aa8d08a Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Mon, 15 Nov 2021 11:33:45 -0600 Subject: [PATCH 0364/2777] atiadlxx: Update fake driver version to 21.20.01 Age of Empires IV wants this. CW-Bug-ID: #19602 --- dlls/atiadlxx/atiadlxx_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dlls/atiadlxx/atiadlxx_main.c b/dlls/atiadlxx/atiadlxx_main.c index f85c7f8ba62..65c6d6ca988 100644 --- a/dlls/atiadlxx/atiadlxx_main.c +++ b/dlls/atiadlxx/atiadlxx_main.c @@ -136,15 +136,15 @@ typedef struct ADLMemoryInfo } ADLMemoryInfo, *LPADLMemoryInfo; static const ADLVersionsInfo version = { - "20.10.1", - "20.10.1", + "21.20.01", + "21.20.01", "", }; static const ADLVersionsInfoX2 version2 = { - "20.10.1", - "20.10.1", - "20.10.1", + "21.20.01", + "21.20.01", + "21.20.01", "", }; From 7396bd2d19941814577ff71a268c89670480ff96 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 25 Nov 2021 21:26:01 +0300 Subject: [PATCH 0365/2777] atiadlxx: Add stub for ADL_Display_DisplayMapConfig_Get(). CW-Bug-Id: #19687 --- dlls/atiadlxx/atiadlxx.spec | 2 +- dlls/atiadlxx/atiadlxx_main.c | 46 +++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/dlls/atiadlxx/atiadlxx.spec b/dlls/atiadlxx/atiadlxx.spec index e2fb060ae8d..1e447f38ded 100644 --- a/dlls/atiadlxx/atiadlxx.spec +++ b/dlls/atiadlxx/atiadlxx.spec @@ -845,7 +845,7 @@ @ stub ADL_Display_DisplayContent_Get @ stub ADL_Display_DisplayContent_Set @ stdcall ADL_Display_DisplayInfo_Get(long long ptr long) -@ stub ADL_Display_DisplayMapConfig_Get +@ stdcall ADL_Display_DisplayMapConfig_Get(long ptr ptr ptr ptr long) @ stub ADL_Display_DisplayMapConfig_PossibleAddAndRemove @ stub ADL_Display_DisplayMapConfig_Set @ stub ADL_Display_DisplayMapConfig_Validate diff --git a/dlls/atiadlxx/atiadlxx_main.c b/dlls/atiadlxx/atiadlxx_main.c index 65c6d6ca988..2f9b1102c37 100644 --- a/dlls/atiadlxx/atiadlxx_main.c +++ b/dlls/atiadlxx/atiadlxx_main.c @@ -135,6 +135,40 @@ typedef struct ADLMemoryInfo long long iMemoryBandwidth; } ADLMemoryInfo, *LPADLMemoryInfo; +typedef struct ADLDisplayTarget +{ + ADLDisplayID displayID; + int iDisplayMapIndex; + int iDisplayTargetMask; + int iDisplayTargetValue; +} ADLDisplayTarget, *LPADLDisplayTarget; + +typedef struct ADLMode +{ + int iAdapterIndex; + ADLDisplayID displayID; + int iXPos; + int iYPos; + int iXRes; + int iYRes; + int iColourDepth; + float fRefreshRate; + int iOrientation; + int iModeFlag; + int iModeMask; + int iModeValue; +} ADLMode, *LPADLMode; + +typedef struct ADLDisplayMap +{ + int iDisplayMapIndex; + ADLMode displayMode; + int iNumDisplayTarget; + int iFirstDisplayTargetArrayIndex; + int iDisplayMapMask; + int iDisplayMapValue; +} ADLDisplayMap, *LPADLDisplayMap; + static const ADLVersionsInfo version = { "21.20.01", "21.20.01", @@ -432,3 +466,15 @@ int WINAPI ADL_Graphics_Platform_Get(int *platform) return ADL_OK; } + + +int WINAPI ADL_Display_DisplayMapConfig_Get(int adapter_index, int *display_map_count, ADLDisplayMap **display_maps, + int *display_target_count, ADLDisplayTarget **display_targets, int options) +{ + FIXME("adapter_index %d, display_map_count %p, display_maps %p, " + "display_target_count %p, display_targets %p, options %d stub.\n", + adapter_index, display_map_count, display_maps, display_target_count, + display_targets, options); + + return ADL_ERR; +} From 080b1d436f6afb6da51d2b412d29048d33a34fc5 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Wed, 29 Dec 2021 18:00:39 +0200 Subject: [PATCH 0366/2777] atiadlxx: Query the information from dxgi instead of wined3d. so it works with DXVK's DXGI vendor/product mangling. --- dlls/atiadlxx/Makefile.in | 2 +- dlls/atiadlxx/atiadlxx_main.c | 101 +++++++++++++++++++--------------- 2 files changed, 58 insertions(+), 45 deletions(-) diff --git a/dlls/atiadlxx/Makefile.in b/dlls/atiadlxx/Makefile.in index 859d2db12da..fd9b8abf626 100644 --- a/dlls/atiadlxx/Makefile.in +++ b/dlls/atiadlxx/Makefile.in @@ -1,6 +1,6 @@ EXTRADEFS = -DWINE_NO_LONG_TYPES MODULE = atiadlxx.dll -IMPORTS = wined3d +IMPORTS = dxgi EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native diff --git a/dlls/atiadlxx/atiadlxx_main.c b/dlls/atiadlxx/atiadlxx_main.c index 2f9b1102c37..6ef2edd356c 100644 --- a/dlls/atiadlxx/atiadlxx_main.c +++ b/dlls/atiadlxx/atiadlxx_main.c @@ -9,8 +9,10 @@ #include "winbase.h" #include "winuser.h" #include "objbase.h" +#include "initguid.h" #include "wine/debug.h" -#include "wine/wined3d.h" + +#include "dxgi.h" #define MAX_GPUS 64 #define VENDOR_AMD 0x1002 @@ -37,7 +39,7 @@ enum ADLPlatForm #define GRAPHICS_PLATFORM_UNKNOWN -1 -static struct wined3d *wined3d; +static IDXGIFactory *dxgi_factory; WINE_DEFAULT_DEBUG_CHANNEL(atiadlxx); @@ -193,7 +195,8 @@ int WINAPI ADL_Main_Control_Create(ADL_MAIN_MALLOC_CALLBACK cb, int arg) FIXME("cb %p, arg %d stub!\n", cb, arg); adl_malloc = cb; - if ((wined3d = wined3d_create(0))) + + if (SUCCEEDED(CreateDXGIFactory(&IID_IDXGIFactory, (void**) &dxgi_factory))) return ADL_OK; else return ADL_ERR; @@ -203,8 +206,8 @@ int WINAPI ADL_Main_Control_Destroy(void) { FIXME("stub!\n"); - if (wined3d != NULL) - wined3d_decref(wined3d); + if (dxgi_factory != NULL) + IUnknown_Release(dxgi_factory); return ADL_OK; } @@ -234,28 +237,34 @@ int WINAPI ADL_Graphics_Versions_Get(ADLVersionsInfo *ver) int WINAPI ADL_Adapter_NumberOfAdapters_Get(int *count) { + IDXGIAdapter *adapter; + FIXME("count %p stub!\n", count); - *count = wined3d_get_adapter_count(wined3d); + + *count = 0; + while (SUCCEEDED(IDXGIFactory_EnumAdapters(dxgi_factory, *count, &adapter))) + { + (*count)++; + IUnknown_Release(adapter); + } + TRACE("*count = %d\n", *count); return ADL_OK; } -static BOOL get_adapter_identifier(int index, struct wined3d_adapter_identifier *identifier) +static int get_adapter_desc(int adapter_index, DXGI_ADAPTER_DESC *desc) { - struct wined3d_adapter *adapter; + IDXGIAdapter *adapter; HRESULT hr; - adapter = wined3d_get_adapter(wined3d, index); - if (adapter == NULL) - return FALSE; + if (FAILED(IDXGIFactory_EnumAdapters(dxgi_factory, adapter_index, &adapter))) + return ADL_ERR; - memset(identifier, 0, sizeof(*identifier)); - hr = wined3d_adapter_get_identifier(adapter, 0, identifier); + hr = IDXGIAdapter_GetDesc(adapter, desc); - if (!SUCCEEDED(hr)) - return FALSE; + IUnknown_Release(adapter); - return TRUE; + return SUCCEEDED(hr) ? ADL_OK : ADL_ERR; } /* yep, seriously */ @@ -269,11 +278,11 @@ static int convert_vendor_id(int id) int WINAPI ADL_Adapter_AdapterInfo_Get(ADLAdapterInfo *adapters, int input_size) { int count, i; - struct wined3d_adapter_identifier identifier; + DXGI_ADAPTER_DESC adapter_desc; FIXME("adapters %p, input_size %d, stub!\n", adapters, input_size); - count = wined3d_get_adapter_count(wined3d); + ADL_Adapter_NumberOfAdapters_Get(&count); if (!adapters) return ADL_ERR_INVALID_PARAM; if (input_size != count * sizeof(ADLAdapterInfo)) return ADL_ERR_INVALID_PARAM; @@ -285,10 +294,10 @@ int WINAPI ADL_Adapter_AdapterInfo_Get(ADLAdapterInfo *adapters, int input_size) adapters[i].iSize = sizeof(ADLAdapterInfo); adapters[i].iAdapterIndex = i; - if (!get_adapter_identifier(i, &identifier)) + if (get_adapter_desc(i, &adapter_desc) != ADL_OK) return ADL_ERR; - adapters[i].iVendorID = convert_vendor_id(identifier.vendor_id); + adapters[i].iVendorID = convert_vendor_id(adapter_desc.VendorId); } return ADL_OK; @@ -296,18 +305,26 @@ int WINAPI ADL_Adapter_AdapterInfo_Get(ADLAdapterInfo *adapters, int input_size) int WINAPI ADL_Display_DisplayInfo_Get(int adapter_index, int *num_displays, ADLDisplayInfo **info, int force_detect) { - struct wined3d_adapter *adapter; - struct wined3d_output *output; + IDXGIAdapter *adapter; + IDXGIOutput *output; int i; FIXME("adapter %d, num_displays %p, info %p stub!\n", adapter_index, num_displays, info); if (info == NULL || num_displays == NULL) return ADL_ERR_NULL_POINTER; - adapter = wined3d_get_adapter(wined3d, adapter_index); - if (adapter == NULL) return ADL_ERR_INVALID_PARAM; + if (FAILED(IDXGIFactory_EnumAdapters(dxgi_factory, adapter_index, &adapter))) + return ADL_ERR_INVALID_PARAM; + + *num_displays = 0; + + while (SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, *num_displays, &output))) + { + (*num_displays)++; + IUnknown_Release(output); + } - *num_displays = wined3d_adapter_get_output_count(adapter); + IUnknown_Release(adapter); if (*num_displays == 0) return ADL_OK; @@ -317,10 +334,6 @@ int WINAPI ADL_Display_DisplayInfo_Get(int adapter_index, int *num_displays, ADL for (i = 0; i < *num_displays; i++) { - output = wined3d_adapter_get_output(adapter, i); - if (output == NULL) - return ADL_ERR; - (*info)[i].displayID.iDisplayLogicalIndex = i; (*info)[i].iDisplayInfoValue = ADL_DISPLAY_DISPLAYINFO_DISPLAYCONNECTED | ADL_DISPLAY_DISPLAYINFO_DISPLAYMAPPED; (*info)[i].iDisplayInfoMask = (*info)[i].iDisplayInfoValue; @@ -343,17 +356,17 @@ int WINAPI ADL_Adapter_Crossfire_Get(int adapter_index, ADLCrossfireComb *comb, int WINAPI ADL_Adapter_ASICFamilyType_Get(int adapter_index, int *asic_type, int *valids) { - struct wined3d_adapter_identifier identifier; + DXGI_ADAPTER_DESC adapter_desc; FIXME("adapter %d, asic_type %p, valids %p, stub!\n", adapter_index, asic_type, valids); if (asic_type == NULL || valids == NULL) return ADL_ERR_NULL_POINTER; - if (!get_adapter_identifier(adapter_index, &identifier)) + if (get_adapter_desc(adapter_index, &adapter_desc) != ADL_OK) return ADL_ERR_INVALID_ADL_IDX; - if (identifier.vendor_id != VENDOR_AMD) + if (adapter_desc.VendorId != VENDOR_AMD) return ADL_ERR_NOT_SUPPORTED; *asic_type = ADL_ASIC_DISCRETE; @@ -402,13 +415,13 @@ static int get_max_clock(const char *clock, int default_value) /* the name and documentation suggests that this returns current freqs, but it's actually max */ int WINAPI ADL_Adapter_ObservedClockInfo_Get(int adapter_index, int *core_clock, int *memory_clock) { - struct wined3d_adapter_identifier identifier; + DXGI_ADAPTER_DESC adapter_desc; FIXME("adapter %d, core_clock %p, memory_clock %p, stub!\n", adapter_index, core_clock, memory_clock); if (core_clock == NULL || memory_clock == NULL) return ADL_ERR; - if (!get_adapter_identifier(adapter_index, &identifier)) return ADL_ERR; - if (identifier.vendor_id != VENDOR_AMD) return ADL_ERR_INVALID_ADL_IDX; + if (get_adapter_desc(adapter_index, &adapter_desc) != ADL_OK) return ADL_ERR; + if (adapter_desc.VendorId != VENDOR_AMD) return ADL_ERR_INVALID_ADL_IDX; /* default values based on RX580 */ *core_clock = get_max_clock("sclk", 1350); @@ -422,15 +435,15 @@ int WINAPI ADL_Adapter_ObservedClockInfo_Get(int adapter_index, int *core_clock, /* documented in the "Linux Specific APIs" section, present and used on Windows */ int WINAPI ADL_Adapter_MemoryInfo_Get(int adapter_index, ADLMemoryInfo *mem_info) { - struct wined3d_adapter_identifier identifier; + DXGI_ADAPTER_DESC adapter_desc; FIXME("adapter %d, mem_info %p stub!\n", adapter_index, mem_info); if (mem_info == NULL) return ADL_ERR_NULL_POINTER; - if (!get_adapter_identifier(adapter_index, &identifier)) return ADL_ERR_INVALID_ADL_IDX; - if (identifier.vendor_id != VENDOR_AMD) return ADL_ERR; + if (get_adapter_desc(adapter_index, &adapter_desc) != ADL_OK) return ADL_ERR_INVALID_ADL_IDX; + if (adapter_desc.VendorId != VENDOR_AMD) return ADL_ERR; - mem_info->iMemorySize = identifier.video_memory; + mem_info->iMemorySize = adapter_desc.DedicatedVideoMemory; mem_info->iMemoryBandwidth = 256000; /* not exposed on Linux, probably needs a lookup table */ TRACE("iMemoryBandwidth %s, iMemorySize %s\n", @@ -441,27 +454,27 @@ int WINAPI ADL_Adapter_MemoryInfo_Get(int adapter_index, ADLMemoryInfo *mem_info int WINAPI ADL_Graphics_Platform_Get(int *platform) { - struct wined3d_adapter_identifier identifier; + DXGI_ADAPTER_DESC adapter_desc; int count, i; FIXME("platform %p, stub!\n", platform); *platform = GRAPHICS_PLATFORM_UNKNOWN; - count = wined3d_get_adapter_count(wined3d); + ADL_Adapter_NumberOfAdapters_Get(&count); for (i = 0; i < count; i ++) { - if (!get_adapter_identifier(i, &identifier)) + if (get_adapter_desc(i, &adapter_desc) != ADL_OK) continue; - if (identifier.vendor_id == VENDOR_AMD) + if (adapter_desc.VendorId == VENDOR_AMD) *platform = GRAPHICS_PLATFORM_DESKTOP; } /* NOTE: The real value can be obtained by doing: * 1. ioctl(DRM_AMDGPU_INFO) with AMDGPU_INFO_DEV_INFO - dev_info.ids_flags & AMDGPU_IDS_FLAGS_FUSION - * 2. VkPhysicalDeviceType() if we ever switch to wined3d vk adapter implementation + * 2. VkPhysicalDeviceType() if we ever want to use Vulkan directly */ return ADL_OK; From 8e692ad69757246032659795d9e66429c68dc28a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 11 Oct 2022 20:48:10 -0500 Subject: [PATCH 0367/2777] atiadlxx: Bump driver version. CW-Bug-Id: #21397 --- dlls/atiadlxx/atiadlxx_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dlls/atiadlxx/atiadlxx_main.c b/dlls/atiadlxx/atiadlxx_main.c index 6ef2edd356c..21dfbe71096 100644 --- a/dlls/atiadlxx/atiadlxx_main.c +++ b/dlls/atiadlxx/atiadlxx_main.c @@ -172,16 +172,16 @@ typedef struct ADLDisplayMap } ADLDisplayMap, *LPADLDisplayMap; static const ADLVersionsInfo version = { - "21.20.01", - "21.20.01", + "22.20.19.16-221003a-384125E-AMD-Software-Adrenalin-Edition", "", + "http://support.amd.com/drivers/xml/driver_09_us.xml", }; static const ADLVersionsInfoX2 version2 = { - "21.20.01", - "21.20.01", - "21.20.01", + "22.20.19.16-221003a-384125E-AMD-Software-Adrenalin-Edition", "", + "22.10.1", + "http://support.amd.com/drivers/xml/driver_09_us.xml", }; int WINAPI ADL2_Main_Control_Create(ADL_MAIN_MALLOC_CALLBACK cb, int arg, ADL_CONTEXT_HANDLE *ptr) From f23e587311dcf2db7c461d16f2be056e9e410ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 30 Sep 2021 20:01:10 +0200 Subject: [PATCH 0368/2777] wine.inf: Enable builtin atiadlxx for Call of Duty games. The games call several functions from this DLL to check driver version, which we stub to some acceptable value to avoid warnings. --- loader/wine.inf.in | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 1a01a9f63b5..7d857b33970 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2734,3 +2734,10 @@ HKCU,Software\Wine\AppDefaults\ForzaHorizon5.exe\DllOverrides,"amd_ags_x64",0x2, HKCU,Software\Wine\AppDefaults\MonsterHunterRise.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\Sam4.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\Sam4_Unrestricted.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" +;;App-specific overrides for atiadlxx.dll. +HKCU,Software\Wine\AppDefaults\s2_sp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" +HKCU,Software\Wine\AppDefaults\s2_mp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" +HKCU,Software\Wine\AppDefaults\h1_sp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" +HKCU,Software\Wine\AppDefaults\h1_mp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" +HKCU,Software\Wine\AppDefaults\iw7_ship.exe\DllOverrides,"atiadlxx",,"builtin" +HKCU,Software\Wine\AppDefaults\BlackOps3.exe\DllOverrides,"atiadlxx",,"builtin" From 0d22cdea23f57bf7ebd3086efccdc85cf77fb589 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Tue, 13 Oct 2020 18:20:39 +0300 Subject: [PATCH 0369/2777] wine.inf: Enable atiadlxx and disable ags for Shadow of War. With the recent stubs game is able to use our atiadlxx without crashing. This helps with getting the resolution list populated with AMD GPUs. AGS has to be force disabled - the dll ships with the game and uses a bunch of more complex ADL2 calls that remain unimplemented. The game works fine if the DLL is not found. --- loader/wine.inf.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 7d857b33970..459763c6529 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2734,6 +2734,7 @@ HKCU,Software\Wine\AppDefaults\ForzaHorizon5.exe\DllOverrides,"amd_ags_x64",0x2, HKCU,Software\Wine\AppDefaults\MonsterHunterRise.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\Sam4.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\Sam4_Unrestricted.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" +HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"amd_ags_x64",,"disabled" ;;App-specific overrides for atiadlxx.dll. HKCU,Software\Wine\AppDefaults\s2_sp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\s2_mp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" @@ -2741,3 +2742,4 @@ HKCU,Software\Wine\AppDefaults\h1_sp64_ship.exe\DllOverrides,"atiadlxx",,"builti HKCU,Software\Wine\AppDefaults\h1_mp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\iw7_ship.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\BlackOps3.exe\DllOverrides,"atiadlxx",,"builtin" +HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"atiadlxx",,"builtin" From af25c976dd900d92b2bbf9b4b2b533c166c60074 Mon Sep 17 00:00:00 2001 From: Anna Lasky Date: Fri, 5 Feb 2021 08:31:07 -0600 Subject: [PATCH 0370/2777] wine.inf: Use built-in atiadlxx for Need For Speed. --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 459763c6529..14b9b833410 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2742,4 +2742,5 @@ HKCU,Software\Wine\AppDefaults\h1_sp64_ship.exe\DllOverrides,"atiadlxx",,"builti HKCU,Software\Wine\AppDefaults\h1_mp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\iw7_ship.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\BlackOps3.exe\DllOverrides,"atiadlxx",,"builtin" +HKCU,Software\Wine\AppDefaults\NFS16.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"atiadlxx",,"builtin" From 6815337e26ca40483662a60b52eba420d0b0823e Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Mon, 15 Mar 2021 13:24:34 -0500 Subject: [PATCH 0371/2777] wine.inf: Use built-in atiadlxx for DIRT5. --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 14b9b833410..ff7f4d817aa 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2744,3 +2744,4 @@ HKCU,Software\Wine\AppDefaults\iw7_ship.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\BlackOps3.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\NFS16.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"atiadlxx",,"builtin" +HKCU,Software\Wine\AppDefaults\DIRT5.exe\DllOverrides,"atiadlxx",,"builtin" From 19b10fb0a4906d4b8f505210ea8ff54c0df2fb85 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 27 Oct 2021 17:25:25 +0300 Subject: [PATCH 0372/2777] wine.inf: Use built-in atiadlxx for GotG. CW-Bug-ID: #19579 Avoids the warning about too old drivers on start. --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index ff7f4d817aa..cc66c321e47 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2745,3 +2745,4 @@ HKCU,Software\Wine\AppDefaults\BlackOps3.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\NFS16.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\DIRT5.exe\DllOverrides,"atiadlxx",,"builtin" +HKCU,Software\Wine\AppDefaults\gotg.exe\DllOverrides,"atiadlxx",,"builtin" From 629c69b16aa05b3d55bce43cb497677ebab8503d Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Sun, 12 Dec 2021 14:07:16 +0100 Subject: [PATCH 0373/2777] wine.inf: Use built-in atiadlxx for Age of Empires IV. CW-Bug-ID: #19602 Avoids the warning about too old drivers on start. --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index cc66c321e47..dce78c9018f 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2746,3 +2746,4 @@ HKCU,Software\Wine\AppDefaults\NFS16.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\DIRT5.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\gotg.exe\DllOverrides,"atiadlxx",,"builtin" +HKCU,Software\Wine\AppDefaults\RelicCardinal.exe\DllOverrides,"atiadlxx",,"builtin" From 7017cb5121f8b306316602ad37f9f751c6175860 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 25 Nov 2021 21:33:24 +0300 Subject: [PATCH 0374/2777] wine.inf: Use built-in atiadlxx for Marvel's Avengers. CW-Bug-Id: #19687 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index dce78c9018f..04cbe7a7907 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2747,3 +2747,4 @@ HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"atiadlxx",,"builtin HKCU,Software\Wine\AppDefaults\DIRT5.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\gotg.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\RelicCardinal.exe\DllOverrides,"atiadlxx",,"builtin" +HKCU,Software\Wine\AppDefaults\Avengers.exe\DllOverrides,"atiadlxx",,"builtin" From b616e2cd58e1c827cd9ea3636f7fd5b89629a3b5 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Feb 2022 18:26:36 +0300 Subject: [PATCH 0375/2777] 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 04cbe7a7907..e72a2167586 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2748,3 +2748,4 @@ HKCU,Software\Wine\AppDefaults\DIRT5.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\gotg.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\RelicCardinal.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\Avengers.exe\DllOverrides,"atiadlxx",,"builtin" +HKCU,Software\Wine\AppDefaults\starwarssquadrons.exe\DllOverrides,"atiadlxx",,"builtin" From 6c9a213041a2c60cc062146118b0f62ae045368b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 29 Jun 2022 11:12:42 -0500 Subject: [PATCH 0376/2777] wine.inf: Use built-in atiadlxx for Plants vs Zombies Garden Warfare 2. CW-Bug-Id: #20818 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index e72a2167586..c72249f6b9f 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2749,3 +2749,4 @@ HKCU,Software\Wine\AppDefaults\gotg.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\RelicCardinal.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\Avengers.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\starwarssquadrons.exe\DllOverrides,"atiadlxx",,"builtin" +HKCU,Software\Wine\AppDefaults\GW2.Main_Win64_Retail.exe\DllOverrides,"atiadlxx",,"builtin" From 84406ef0f012b569eb5cd4d727dc36f03fab183b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 11 Oct 2022 20:51:30 -0500 Subject: [PATCH 0377/2777] wine.inf: Use built-in atiadlxx for Spider-Man Remastered. CW-Bug-Id: #21397 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index c72249f6b9f..879c1b4ebad 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2750,3 +2750,4 @@ HKCU,Software\Wine\AppDefaults\RelicCardinal.exe\DllOverrides,"atiadlxx",,"built HKCU,Software\Wine\AppDefaults\Avengers.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\starwarssquadrons.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\GW2.Main_Win64_Retail.exe\DllOverrides,"atiadlxx",,"builtin" +HKCU,Software\Wine\AppDefaults\Spider-Man.exe\DllOverrides,"atiadlxx",,"builtin" From d46d8bf49cd442d0219a31a5eeab42008095c825 Mon Sep 17 00:00:00 2001 From: Liam Middlebrook Date: Mon, 11 Oct 2021 11:16:49 +0200 Subject: [PATCH 0378/2777] loader: Set default regkey for NVIDIA NGX FullPath Sets the default location for the NVIDIA NGX SDK search-path to be C:\Windows\System32\ This is required for supporting NVIDIA DLSS within Proton. Reviewed-by: Adam Moss --- loader/wine.inf.in | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 879c1b4ebad..93e4562642e 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -96,6 +96,7 @@ AddReg=\ ThemeManager,\ VersionInfo,\ LicenseInformation, \ + NVIDIANGX, \ ProtonOverrides, \ SteamClient @@ -123,6 +124,7 @@ AddReg=\ ThemeManager,\ VersionInfo.ntamd64,\ LicenseInformation, \ + NVIDIANGX, \ ProtonOverrides, \ SteamClient.ntamd64 @@ -165,6 +167,7 @@ AddReg=\ Tapi,\ VersionInfo.ntamd64,\ LicenseInformation, \ + NVIDIANGX, \ ProtonOverrides, \ SteamClient.ntamd64 @@ -2696,6 +2699,9 @@ HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll64",,"%16426%\Steam\steam HKCU,Software\Valve\Steam\ActiveProcess,"SteamPath",,"%16426%\Steam" HKLM,Software\Wow6432Node\Valve\Steam,"InstallPath",,"%16422%\Steam" +[NVIDIANGX] +HKLM,Software\NVIDIA Corporation\Global\NGXCore,"FullPath",,"C:\Windows\System32" + [ProtonOverrides] ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" From 395a60cae345adf0a25c61c9377b2757cead3d62 Mon Sep 17 00:00:00 2001 From: Liam Middlebrook Date: Wed, 8 Sep 2021 11:30:28 -0700 Subject: [PATCH 0379/2777] nvcuda: Add stub DLL This is needed for DLSS versions 2.1.38 through 2.1.40 to work within Proton, as they contain a link-time dependency on nvcuda.dll. In the case of what is needed by DLSS, no ordinals need to be exported for nvcuda.dll to successfully load. Signed-off-by: Liam Middlebrook Link: https://github.com/ValveSoftware/wine/pull/119 --- configure.ac | 1 + dlls/nvcuda/Makefile.in | 1 + dlls/nvcuda/nvcuda.spec | 0 3 files changed, 2 insertions(+) create mode 100644 dlls/nvcuda/Makefile.in create mode 100644 dlls/nvcuda/nvcuda.spec diff --git a/configure.ac b/configure.ac index 35d951c7e2f..4a56c63b888 100644 --- a/configure.ac +++ b/configure.ac @@ -2899,6 +2899,7 @@ WINE_CONFIG_MAKEFILE(dlls/ntoskrnl.exe) WINE_CONFIG_MAKEFILE(dlls/ntoskrnl.exe/tests) WINE_CONFIG_MAKEFILE(dlls/ntprint) WINE_CONFIG_MAKEFILE(dlls/ntprint/tests) +WINE_CONFIG_MAKEFILE(dlls/nvcuda) WINE_CONFIG_MAKEFILE(dlls/objsel) WINE_CONFIG_MAKEFILE(dlls/odbc32) WINE_CONFIG_MAKEFILE(dlls/odbcbcp) diff --git a/dlls/nvcuda/Makefile.in b/dlls/nvcuda/Makefile.in new file mode 100644 index 00000000000..6890c798d63 --- /dev/null +++ b/dlls/nvcuda/Makefile.in @@ -0,0 +1 @@ +MODULE = nvcuda.dll diff --git a/dlls/nvcuda/nvcuda.spec b/dlls/nvcuda/nvcuda.spec new file mode 100644 index 00000000000..e69de29bb2d From dab34389605d89acae6df0737786b8afa335230c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 11 Oct 2021 11:17:19 +0200 Subject: [PATCH 0380/2777] wine.inf: Disable nvcuda.dll by default. The nvcuda.dll stub presence may cause regressions when the games successfully load and try to use it (like Divinity The Original Sin 2). The library is enabled in proton script together with nvapi.dll. Link: https://github.com/ValveSoftware/wine/pull/119 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 93e4562642e..8587f8888cb 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2731,6 +2731,7 @@ HKCU,Software\Wine\DllOverrides,"ucrtbase",0x2,"native,builtin" HKCU,Software\Wine\DllOverrides,"vcomp140",0x2,"native,builtin" HKCU,Software\Wine\DllOverrides,"vcruntime140",0x2,"native,builtin" HKCU,Software\Wine\DllOverrides,"atiadlxx",,"disabled" +HKCU,Software\Wine\DllOverrides,"nvcuda",0x2,"disabled" ;;App-specific overrides for amd_ags_x64.dll. HKCU,Software\Wine\AppDefaults\NewColossus_x64vk.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" HKCU,Software\Wine\AppDefaults\RDR2.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" From b9f13c5efd15621354e4ebd02c5164a24d5b6047 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 16 Sep 2021 15:27:51 +1000 Subject: [PATCH 0381/2777] sapi: ISpObjectToken CreateInstance support ISpAudio CW-Bug-Id: #20616 --- dlls/sapi/token.c | 279 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 278 insertions(+), 1 deletion(-) diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index 385555a4cef..4e44ba8a354 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -1166,13 +1166,290 @@ static HRESULT WINAPI token_GetCategory( ISpObjectToken *iface, return E_NOTIMPL; } +struct speech_audio +{ + ISpAudio ISpAudio_iface; + LONG ref; +}; + +static inline struct speech_audio *impl_from_ISpAudio(ISpAudio *iface) +{ + return CONTAINING_RECORD(iface, struct speech_audio, ISpAudio_iface); +} + +static HRESULT WINAPI spaudio_QueryInterface(ISpAudio *iface, REFIID iid, void **obj) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + + TRACE("(%p, %s %p).\n", audio, debugstr_guid(iid), obj); + + if (IsEqualIID(iid, &IID_IUnknown) || + IsEqualIID(iid, &IID_ISequentialStream) || + IsEqualIID(iid, &IID_IStream) || + IsEqualIID(iid, &IID_ISpStreamFormat) || + IsEqualIID(iid, &IID_ISpAudio)) + *obj = &audio->ISpAudio_iface; + else + { + *obj = NULL; + FIXME("interface %s not implemented.\n", debugstr_guid(iid)); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*obj); + return S_OK; +} + +static ULONG WINAPI spaudio_AddRef(ISpAudio *iface) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + ULONG ref = InterlockedIncrement(&audio->ref); + + TRACE("(%p): ref=%lu.\n", audio, ref); + + return ref; +} + +static ULONG WINAPI spaudio_Release(ISpAudio *iface) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + ULONG ref = InterlockedDecrement(&audio->ref); + + TRACE("(%p): ref=%lu.\n", audio, ref); + + if (!ref) + { + heap_free(audio); + } + + return ref; +} + +static HRESULT WINAPI spaudio_Read(ISpAudio *iface,void *pv, ULONG cb, ULONG *pcbRead) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + + FIXME("%p, %p, %ld %p\n", audio, pv, cb, pcbRead); + + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_Write(ISpAudio *iface, const void *pv, ULONG cb, ULONG *pcbWritten) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + + FIXME("%p, %p, %ld %p\n", audio, pv, cb, pcbWritten); + + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_Seek(ISpAudio *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("%p, %s, %ld, %p\n", audio, wine_dbgstr_longlong(dlibMove.QuadPart), dwOrigin, plibNewPosition); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_SetSize(ISpAudio *iface, ULARGE_INTEGER libNewSize) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("(%p, %s)\n", audio, wine_dbgstr_longlong(libNewSize.QuadPart)); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_CopyTo(ISpAudio *iface,IStream *pstm, ULARGE_INTEGER cb, + ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("(%p, %p, %s, %p, %p)\n", audio, pstm, wine_dbgstr_longlong(cb.QuadPart), pcbRead, pcbWritten); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_Commit(ISpAudio *iface,DWORD grfCommitFlags) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("(%p, %#lx)\n", audio, grfCommitFlags); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_Revert(ISpAudio *iface) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("(%p)\n", audio); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_LockRegion(ISpAudio *iface, ULARGE_INTEGER offset, ULARGE_INTEGER cb, DWORD dwLockType) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("(%p, %s, %s, %ld)\n", audio, wine_dbgstr_longlong(offset.QuadPart), + wine_dbgstr_longlong(cb.QuadPart), dwLockType); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_UnlockRegion(ISpAudio *iface,ULARGE_INTEGER offset, ULARGE_INTEGER cb, DWORD dwLockType) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("(%p, %s, %s, %ld)\n", audio, wine_dbgstr_longlong(offset.QuadPart), + wine_dbgstr_longlong(cb.QuadPart), dwLockType); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_Stat(ISpAudio *iface, STATSTG *stg, DWORD flag) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("%p, %p, %ld\n", audio, stg, flag); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_Clone(ISpAudio *iface, IStream **ppstm) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("%p, %p\n", audio, ppstm); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_GetFormat(ISpAudio *iface, GUID *format, WAVEFORMATEX **wave) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("%p, %p, %p\n", audio, format, wave); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_SetState(ISpAudio *iface, SPAUDIOSTATE state, ULONGLONG reserved) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("%p, %d, %s\n", audio, state, wine_dbgstr_longlong(reserved)); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_SetFormat(ISpAudio *iface, REFGUID guid, const WAVEFORMATEX *wave) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("%p, %s, %p\n", audio, debugstr_guid(guid), wave); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_GetStatus(ISpAudio *iface, SPAUDIOSTATUS *status) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("%p, %p\n", audio, status); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_SetBufferInfo(ISpAudio *iface,const SPAUDIOBUFFERINFO *buffer) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("%p, %p\n", audio, buffer); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_GetBufferInfo(ISpAudio *iface, SPAUDIOBUFFERINFO *buffer) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("%p, %p\n", audio, buffer); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_GetDefaultFormat(ISpAudio *iface, GUID *guid, WAVEFORMATEX **wave) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("%p, %p, %p\n", audio, guid, wave); + return E_NOTIMPL; +} + +static HANDLE WINAPI spaudio_EventHandle(ISpAudio *iface) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("%p\n", audio); + return NULL; +} + +static HRESULT WINAPI spaudio_GetVolumeLevel(ISpAudio *iface, ULONG *level) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("%p, %p\n", audio, level); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_SetVolumeLevel(ISpAudio *iface, ULONG level) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("%p, %ld\n", audio, level); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_GetBufferNotifySize(ISpAudio *iface, ULONG *size) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("%p, %p\n", audio, size); + return E_NOTIMPL; +} + +static HRESULT WINAPI spaudio_SetBufferNotifySize(ISpAudio *iface, ULONG size) +{ + struct speech_audio *audio = impl_from_ISpAudio(iface); + FIXME("%p, %ld\n", audio, size); + return E_NOTIMPL; +} + +const struct ISpAudioVtbl spaudio_vtbl = +{ + spaudio_QueryInterface, + spaudio_AddRef, + spaudio_Release, + spaudio_Read, + spaudio_Write, + spaudio_Seek, + spaudio_SetSize, + spaudio_CopyTo, + spaudio_Commit, + spaudio_Revert, + spaudio_LockRegion, + spaudio_UnlockRegion, + spaudio_Stat, + spaudio_Clone, + spaudio_GetFormat, + spaudio_SetState, + spaudio_SetFormat, + spaudio_GetStatus, + spaudio_SetBufferInfo, + spaudio_GetBufferInfo, + spaudio_GetDefaultFormat, + spaudio_EventHandle, + spaudio_GetVolumeLevel, + spaudio_SetVolumeLevel, + spaudio_GetBufferNotifySize, + spaudio_SetBufferNotifySize +}; + +static HRESULT speech_audio_create(void **obj) +{ + struct speech_audio *This = heap_alloc(sizeof(*This)); + + if (!This) + return E_OUTOFMEMORY; + This->ISpAudio_iface.lpVtbl = &spaudio_vtbl; + This->ref = 1; + + *obj = &This->ISpAudio_iface; + return S_OK; +} + static HRESULT WINAPI token_CreateInstance( ISpObjectToken *iface, IUnknown *outer, DWORD class_context, REFIID riid, void **object ) { - FIXME( "stub\n" ); + struct object_token *This = impl_from_ISpObjectToken( iface ); + + FIXME( "(%p)->(%p 0x%08lx %s, %p): semi-stub\n", This, outer, class_context, debugstr_guid( riid ), object); + + if (IsEqualIID(riid, &IID_ISpAudio)) + { + return speech_audio_create(object); + } return E_NOTIMPL; } From 206fbd59f1898771e9ada84e81119a6f21f7da5f Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Mon, 23 Sep 2019 13:29:16 -0500 Subject: [PATCH 0382/2777] dxdiag: Dump to stdout if no filename is given --- programs/dxdiag/main.c | 8 +++++++- programs/dxdiag/output.c | 10 +++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/programs/dxdiag/main.c b/programs/dxdiag/main.c index f57eec99292..3f41a27e2f2 100644 --- a/programs/dxdiag/main.c +++ b/programs/dxdiag/main.c @@ -72,7 +72,13 @@ static BOOL process_file_name(const WCHAR *cmdline, enum output_type output_type endptr = cmdline + lstrlenW(cmdline); len = endptr - cmdline; - if (len == 0 || len >= filename_len) + if (len == 0) + { + *filename = 0; + return TRUE; + } + + if (len >= filename_len) return FALSE; memcpy(filename, cmdline, len * sizeof(WCHAR)); diff --git a/programs/dxdiag/output.c b/programs/dxdiag/output.c index a8eb733ba4b..63d091395b0 100644 --- a/programs/dxdiag/output.c +++ b/programs/dxdiag/output.c @@ -149,8 +149,12 @@ static BOOL output_text_information(struct dxdiag_information *dxdiag_info, cons fill_system_text_output_table(dxdiag_info, output_table[0].fields); - hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (filename && *filename) + hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + else + hFile = GetStdHandle(STD_OUTPUT_HANDLE); + if (hFile == INVALID_HANDLE_VALUE) { WINE_ERR("File creation failed, last error %lu\n", GetLastError()); @@ -207,7 +211,7 @@ static HRESULT save_xml_document(IXMLDOMDocument *xmldoc, const WCHAR *filename) VARIANT destVar; HRESULT hr; - if (!bstr) + if (!bstr || !filename || !*filename) return E_OUTOFMEMORY; V_VT(&destVar) = VT_BSTR; From a96bb9998ca00bf5e5115fc50b9058ae8fa944d9 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Fri, 30 Mar 2018 10:40:43 -0500 Subject: [PATCH 0383/2777] HACK: winedbg: When crash dialog is not shown, dump crash info to stderr Use the real unix stderr via __wine_dbg_output(). CW-Bug-Id: #21872 --- programs/winedbg/debugger.h | 1 + programs/winedbg/tgt_active.c | 3 +++ programs/winedbg/winedbg.c | 7 +++++++ 3 files changed, 11 insertions(+) diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index c4c0402ef5f..6368248cd08 100644 --- a/programs/winedbg/debugger.h +++ b/programs/winedbg/debugger.h @@ -304,6 +304,7 @@ extern DWORD dbg_curr_tid; extern dbg_ctx_t dbg_context; extern BOOL dbg_interactiveP; extern HANDLE dbg_houtput; +extern BOOL dbg_use_wine_dbg_output; struct dbg_internal_var { diff --git a/programs/winedbg/tgt_active.c b/programs/winedbg/tgt_active.c index 9e130038f22..3c9b465e702 100644 --- a/programs/winedbg/tgt_active.c +++ b/programs/winedbg/tgt_active.c @@ -978,6 +978,9 @@ enum dbg_start dbg_active_auto(int argc, char* argv[]) if (event) thread = display_crash_details( event ); if (thread) dbg_houtput = output = create_temp_file(); break; + case TRUE: + dbg_use_wine_dbg_output = TRUE; + break; } input = parser_generate_command_file("echo Modules:", "info share", diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index 84ec7802396..f0f02438934 100644 --- a/programs/winedbg/winedbg.c +++ b/programs/winedbg/winedbg.c @@ -82,6 +82,7 @@ DWORD dbg_curr_pid = 0; dbg_ctx_t dbg_context; BOOL dbg_interactiveP = FALSE; HANDLE dbg_houtput = 0; +BOOL dbg_use_wine_dbg_output = FALSE; static struct list dbg_process_list = LIST_INIT(dbg_process_list); @@ -94,6 +95,12 @@ static void dbg_outputA(const char* buffer, int len) DWORD w, i; + if (dbg_use_wine_dbg_output) + { + __wine_dbg_output(buffer); + return; + } + while (len > 0) { unsigned int count = min( len, sizeof(line_buff) - line_pos ); From 9b9fd5eb1006cc3f2e12667a7cf45c7a6affa94d Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 18 May 2021 13:34:47 -0500 Subject: [PATCH 0384/2777] HACK: proton: winedbg: Support dumping crash logs to a directory CW-Bug-Id: #18944 --- programs/winedbg/debugger.h | 1 + programs/winedbg/tgt_active.c | 45 +++++++++++++++++++++++++++++++++++ programs/winedbg/winedbg.c | 9 +++---- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index 6368248cd08..4d2b946162b 100644 --- a/programs/winedbg/debugger.h +++ b/programs/winedbg/debugger.h @@ -304,6 +304,7 @@ extern DWORD dbg_curr_tid; extern dbg_ctx_t dbg_context; extern BOOL dbg_interactiveP; extern HANDLE dbg_houtput; +extern HANDLE dbg_crash_report_file; extern BOOL dbg_use_wine_dbg_output; struct dbg_internal_var diff --git a/programs/winedbg/tgt_active.c b/programs/winedbg/tgt_active.c index 3c9b465e702..5d660ab81dd 100644 --- a/programs/winedbg/tgt_active.c +++ b/programs/winedbg/tgt_active.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "debugger.h" #include "psapi.h" @@ -797,6 +799,48 @@ static HANDLE create_temp_file(void) NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0 ); } +static HANDLE create_crash_report_file(void) +{ + const char *dir = getenv("WINE_CRASH_REPORT_DIR"); + const char *sgi; + char timestr[32]; + char name[MAX_PATH], *c; + time_t t; + struct tm lt; + + if(!dir || dir[0] == 0) + return INVALID_HANDLE_VALUE; + + strcpy(name, dir); + + for(c = name + 1; *c; ++c){ + if(*c == '/'){ + *c = 0; + CreateDirectoryA(name, NULL); + *c = '/'; + } + } + CreateDirectoryA(name, NULL); + + sgi = getenv("SteamGameId"); + + t = time(NULL); + lt = *localtime(&t); + strftime(timestr, ARRAY_SIZE(timestr), "%Y-%m-%d_%H:%M:%S", <); + + /* /path/to/crash/reports/2021-05-18_13:21:15_appid-976310_crash.log */ + snprintf(name, ARRAY_SIZE(name), + "%s%s/%s_appid-%s_crash.log", + dir[0] == '/' ? "Z:/" : "", + dir, + timestr, + sgi ? sgi : "0" + ); + + return CreateFileA( name, GENERIC_WRITE, FILE_SHARE_READ, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 ); +} + static const struct { int type; @@ -980,6 +1024,7 @@ enum dbg_start dbg_active_auto(int argc, char* argv[]) break; case TRUE: dbg_use_wine_dbg_output = TRUE; + dbg_crash_report_file = create_crash_report_file(); break; } diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index f0f02438934..b2a1706117a 100644 --- a/programs/winedbg/winedbg.c +++ b/programs/winedbg/winedbg.c @@ -82,6 +82,7 @@ DWORD dbg_curr_pid = 0; dbg_ctx_t dbg_context; BOOL dbg_interactiveP = FALSE; HANDLE dbg_houtput = 0; +HANDLE dbg_crash_report_file = INVALID_HANDLE_VALUE; BOOL dbg_use_wine_dbg_output = FALSE; static struct list dbg_process_list = LIST_INIT(dbg_process_list); @@ -96,10 +97,7 @@ static void dbg_outputA(const char* buffer, int len) DWORD w, i; if (dbg_use_wine_dbg_output) - { __wine_dbg_output(buffer); - return; - } while (len > 0) { @@ -114,7 +112,10 @@ static void dbg_outputA(const char* buffer, int len) if (len > 0) i = line_pos; /* buffer is full, flush anyway */ else break; } - WriteFile(dbg_houtput, line_buff, i, &w, NULL); + if (!dbg_use_wine_dbg_output) + WriteFile(dbg_houtput, line_buff, i, &w, NULL); + if (dbg_crash_report_file != INVALID_HANDLE_VALUE) + WriteFile(dbg_crash_report_file, line_buff, i, &w, NULL); memmove( line_buff, line_buff + i, line_pos - i ); line_pos -= i; } From 749c2c23f107f21000d6d69a9708a1f7151afe4c Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Thu, 23 Jan 2020 09:14:56 -0600 Subject: [PATCH 0385/2777] wine.inf: Set default Windows version to win10. wine.inf: Bump CurrentBuild(Number) to 17763 (Win10 1809). --- dlls/ntdll/version.c | 2 +- loader/wine.inf.in | 28 ++++++++++++++-------------- programs/winecfg/appdefaults.c | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/dlls/ntdll/version.c b/dlls/ntdll/version.c index 02544173096..410a091d6f6 100644 --- a/dlls/ntdll/version.c +++ b/dlls/ntdll/version.c @@ -467,7 +467,7 @@ void version_init(void) NtQuerySystemInformation( SystemWineVersionInformation, wine_version, sizeof(wine_version), NULL ); - current_version = &VersionData[WIN7]; + current_version = &VersionData[WIN10]; RtlOpenCurrentUser( KEY_ALL_ACCESS, &root ); attr.Length = sizeof(attr); diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 8587f8888cb..bbe93c60242 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2463,12 +2463,12 @@ HKLM,"System\CurrentControlSet\Services\Winsock\Parameters",,16 HKLM,"System\CurrentControlSet\Services\Winsock2\Parameters\Protocol_Catalog9\Catalog_Entries",,16 [VersionInfo] -HKLM,%CurrentVersionNT%,"CurrentVersion",2,"6.1" -HKLM,%CurrentVersionNT%,"CurrentMajorVersionNumber",0x10001,6 -HKLM,%CurrentVersionNT%,"CurrentMinorVersionNumber",0x10001,1 -HKLM,%CurrentVersionNT%,"CSDVersion",2,"Service Pack 1" -HKLM,%CurrentVersionNT%,"CurrentBuild",2,"7601" -HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"7601" +HKLM,%CurrentVersionNT%,"CurrentVersion",2,"10.0" +HKLM,%CurrentVersionNT%,"CurrentMajorVersionNumber",0x10001,10 +HKLM,%CurrentVersionNT%,"CurrentMinorVersionNumber",0x10001,0 +HKLM,%CurrentVersionNT%,"CSDVersion",2,"" +HKLM,%CurrentVersionNT%,"CurrentBuild",2,"17763" +HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"17763" HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ @@ -2477,16 +2477,16 @@ HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 -HKLM,%CurrentVersionNT%,"ProductName",2,"Microsoft Windows 7" +HKLM,%CurrentVersionNT%,"ProductName",2,"Microsoft Windows 10" HKLM,%Control%\ProductOptions,"ProductType",2,"WinNT" -HKLM,%Control%\Windows,"CSDVersion",0x10003,0x100 +HKLM,%Control%\Windows,"CSDVersion",0x10003,0x0 HKLM,%Control%\Session Manager\Environment,"OS",2,"Windows_NT" [VersionInfo.ntamd64] -HKLM,%CurrentVersionNT%,"CurrentVersion",2,"6.1" -HKLM,%CurrentVersionNT%,"CSDVersion",2,"Service Pack 1" -HKLM,%CurrentVersionNT%,"CurrentBuild",2,"7601" -HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"7601" +HKLM,%CurrentVersionNT%,"CurrentVersion",2,"10.0" +HKLM,%CurrentVersionNT%,"CSDVersion",2,"" +HKLM,%CurrentVersionNT%,"CurrentBuild",2,"17763" +HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"17763" HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ @@ -2495,9 +2495,9 @@ HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 -HKLM,%CurrentVersionNT%,"ProductName",2,"Microsoft Windows 7" +HKLM,%CurrentVersionNT%,"ProductName",2,"Microsoft Windows 10" HKLM,%Control%\ProductOptions,"ProductType",2,"WinNT" -HKLM,%Control%\Windows,"CSDVersion",0x10003,0x100 +HKLM,%Control%\Windows,"CSDVersion",0x10003,0x0 HKLM,%Control%\Session Manager\Environment,"OS",2,"Windows_NT" [Wow64] diff --git a/programs/winecfg/appdefaults.c b/programs/winecfg/appdefaults.c index 9e43eeb51c8..1d9a2eedb02 100644 --- a/programs/winecfg/appdefaults.c +++ b/programs/winecfg/appdefaults.c @@ -73,7 +73,7 @@ static const struct win_version win_versions[] = #endif }; -#define DEFAULT_WIN_VERSION L"win7" +#define DEFAULT_WIN_VERSION L"win10" static const WCHAR szKey9x[] = L"Software\\Microsoft\\Windows\\CurrentVersion"; static const WCHAR szKeyNT[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion"; From a161620b084892d6c99b61ff1c9aadd2118d81d0 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Wed, 15 Jul 2020 14:57:28 -0500 Subject: [PATCH 0386/2777] wineboot: On prefix upgrade, update win10 build number Some games (Death Stranding) require later build numbers than we had shipped earlier. So fix it up on existing prefixes. --- programs/wineboot/wineboot.c | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c index d49406cef5e..8cd230afea8 100644 --- a/programs/wineboot/wineboot.c +++ b/programs/wineboot/wineboot.c @@ -1585,6 +1585,43 @@ static void update_user_profile(void) LocalFree(sid); } +static void update_win_version(void) +{ + static const WCHAR win10_buildW[] = L"17763"; + + HKEY cv_h; + DWORD type, sz; + WCHAR current_version[256]; + + if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion", + 0, KEY_ALL_ACCESS, &cv_h) == ERROR_SUCCESS){ + /* get the current windows version */ + sz = sizeof(current_version); + if(RegQueryValueExW(cv_h, L"CurrentVersion", NULL, &type, (BYTE *)current_version, &sz) == ERROR_SUCCESS && + type == REG_SZ){ + if(!wcscmp(current_version, L"10.0")){ + RegSetValueExW(cv_h, L"CurrentBuild", 0, REG_SZ, (const BYTE *)win10_buildW, sizeof(win10_buildW)); + RegSetValueExW(cv_h, L"CurrentBuildNumber", 0, REG_SZ, (const BYTE *)win10_buildW, sizeof(win10_buildW)); + } + } + RegCloseKey(cv_h); + } + + if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion", + 0, KEY_ALL_ACCESS, &cv_h) == ERROR_SUCCESS){ + /* get the current windows version */ + sz = sizeof(current_version); + if(RegQueryValueExW(cv_h, L"CurrentVersion", NULL, &type, (BYTE *)current_version, &sz) == ERROR_SUCCESS && + type == REG_SZ){ + if(!wcscmp(current_version, L"10.0")){ + RegSetValueExW(cv_h, L"CurrentBuild", 0, REG_SZ, (const BYTE *)win10_buildW, sizeof(win10_buildW)); + RegSetValueExW(cv_h, L"CurrentBuildNumber", 0, REG_SZ, (const BYTE *)win10_buildW, sizeof(win10_buildW)); + } + } + RegCloseKey(cv_h); + } +} + /* execute rundll32 on the wine.inf file if necessary */ static void update_wineprefix( BOOL force ) { @@ -1638,6 +1675,7 @@ static void update_wineprefix( BOOL force ) } install_root_pnp_devices(); update_user_profile(); + update_win_version(); WINE_MESSAGE( "wine: configuration in %s has been updated.\n", debugstr_w(prettyprint_configdir()) ); } From 4f2fa10f876fbfb9eaf52898c34b76a121204980 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 29 Oct 2019 09:16:37 -0500 Subject: [PATCH 0387/2777] setupapi: Support DICGF_PRESENT when looking for devices CW-Bug-Id: #17243 --- dlls/setupapi/devinst.c | 83 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index ef7b4dccf0d..fa7b91e3884 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -104,6 +104,7 @@ static const WCHAR Linked[] = {'L','i','n','k','e','d',0}; static const WCHAR dotInterfaces[] = {'.','I','n','t','e','r','f','a','c','e','s',0}; static const WCHAR AddInterface[] = {'A','d','d','I','n','t','e','r','f','a','c','e',0}; static const WCHAR backslashW[] = {'\\',0}; +static const WCHAR hashW[] = {'#',0}; static const WCHAR emptyW[] = {0}; #define SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES 128 @@ -319,7 +320,6 @@ static WCHAR *get_iface_key_path(struct device_iface *iface) static WCHAR *get_refstr_key_path(struct device_iface *iface) { - static const WCHAR hashW[] = {'#',0}; static const WCHAR slashW[] = {'\\',0}; WCHAR *path, *ptr; size_t len = lstrlenW(DeviceClasses) + 1 + 38 + 1 + lstrlenW(iface->symlink) + 1 + 1; @@ -2425,6 +2425,80 @@ static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet, } } + +/* iterate over all interfaces supported by this device instance. if any of + * them are "linked", return TRUE */ +static BOOL is_device_instance_linked(HKEY interfacesKey, const WCHAR *deviceInstance) +{ + LONG l; + DWORD class_idx = 0, device_idx, len, type; + HKEY class_key, device_key, link_key; + WCHAR class_keyname[40], device_keyname[MAX_DEVICE_ID_LEN]; + WCHAR interface_devinstance[MAX_DEVICE_ID_LEN]; + + while (1) + { + len = ARRAY_SIZE(class_keyname); + l = RegEnumKeyExW(interfacesKey, class_idx++, class_keyname, &len, NULL, NULL, NULL, NULL); + if (l) + break; + + l = RegOpenKeyExW(interfacesKey, class_keyname, 0, KEY_READ, &class_key); + if (l) + continue; + + device_idx = 0; + while (1) + { + len = ARRAY_SIZE(device_keyname); + l = RegEnumKeyExW(class_key, device_idx++, device_keyname, &len, NULL, NULL, NULL, NULL); + if (l) + break; + + l = RegOpenKeyExW(class_key, device_keyname, 0, KEY_READ, &device_key); + if (l) + continue; + + len = ARRAY_SIZE(interface_devinstance); + l = RegQueryValueExW(device_key, DeviceInstance, NULL, &type, (BYTE *)interface_devinstance, &len); + if (l || type != REG_SZ) + { + RegCloseKey(device_key); + continue; + } + + if (lstrcmpiW(interface_devinstance, deviceInstance)) + { + /* not our device instance */ + RegCloseKey(device_key); + continue; + } + + l = RegOpenKeyExW(device_key, hashW, 0, KEY_READ, &link_key); + if (l) + { + RegCloseKey(device_key); + continue; + } + + if (is_linked(link_key)) + { + RegCloseKey(link_key); + RegCloseKey(device_key); + RegCloseKey(class_key); + return TRUE; + } + + RegCloseKey(link_key); + RegCloseKey(device_key); + } + + RegCloseKey(class_key); + } + + return FALSE; +} + static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set, LPCWSTR enumerator, LPCWSTR deviceName, HKEY deviceKey, const GUID *class, DWORD flags) @@ -2433,6 +2507,7 @@ static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set, DWORD i, len; WCHAR deviceInstance[MAX_PATH]; LONG l = ERROR_SUCCESS; + HKEY interfacesKey = SetupDiOpenClassRegKeyExW(NULL, KEY_READ, DIOCR_INTERFACE, NULL, NULL); TRACE("%s %s\n", debugstr_w(enumerator), debugstr_w(deviceName)); @@ -2469,7 +2544,9 @@ static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set, {'%','s','\\','%','s','\\','%','s',0}; if (swprintf(id, ARRAY_SIZE(id), fmt, enumerator, - deviceName, deviceInstance) != -1) + deviceName, deviceInstance) != -1 && + (!(flags & DIGCF_PRESENT) || + is_device_instance_linked(interfacesKey, id))) { create_device(set, &deviceClass, id, FALSE); } @@ -2482,6 +2559,8 @@ static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set, l = ERROR_SUCCESS; } } + + RegCloseKey(interfacesKey); } static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet, From 58d83919fff758672dfd476aa336f3dfb0c42498 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 29 Mar 2021 21:54:30 +0300 Subject: [PATCH 0388/2777] dxgi: Use proxy IDXGISwapChain interface when importing that from d3d implementation. For Origin overlay. Required for Origin overlay to work (which expects IDXGISwapChain implementation methods to reside in dxgi.dll), also useful for debugging. CW-Bug-Id: #18769 CW-Bug-Id: #18950 --- dlls/dxgi/factory.c | 519 +++++++++++++++++++++++++++++++++++++++++- dlls/dxgi/swapchain.c | 6 +- 2 files changed, 517 insertions(+), 8 deletions(-) diff --git a/dlls/dxgi/factory.c b/dlls/dxgi/factory.c index 8de882b388d..fe0d8c061e8 100644 --- a/dlls/dxgi/factory.c +++ b/dlls/dxgi/factory.c @@ -26,7 +26,7 @@ static inline struct dxgi_factory *impl_from_IWineDXGIFactory(IWineDXGIFactory * return CONTAINING_RECORD(iface, struct dxgi_factory, IWineDXGIFactory_iface); } -static HRESULT STDMETHODCALLTYPE dxgi_factory_QueryInterface(IWineDXGIFactory *iface, REFIID iid, void **out) +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH dxgi_factory_QueryInterface(IWineDXGIFactory *iface, REFIID iid, void **out) { struct dxgi_factory *factory = impl_from_IWineDXGIFactory(iface); @@ -55,7 +55,7 @@ static HRESULT STDMETHODCALLTYPE dxgi_factory_QueryInterface(IWineDXGIFactory *i return E_NOINTERFACE; } -static ULONG STDMETHODCALLTYPE dxgi_factory_AddRef(IWineDXGIFactory *iface) +static ULONG STDMETHODCALLTYPE DECLSPEC_HOTPATCH dxgi_factory_AddRef(IWineDXGIFactory *iface) { struct dxgi_factory *factory = impl_from_IWineDXGIFactory(iface); ULONG refcount = InterlockedIncrement(&factory->refcount); @@ -65,7 +65,7 @@ static ULONG STDMETHODCALLTYPE dxgi_factory_AddRef(IWineDXGIFactory *iface) return refcount; } -static ULONG STDMETHODCALLTYPE dxgi_factory_Release(IWineDXGIFactory *iface) +static ULONG STDMETHODCALLTYPE DECLSPEC_HOTPATCH dxgi_factory_Release(IWineDXGIFactory *iface) { struct dxgi_factory *factory = impl_from_IWineDXGIFactory(iface); ULONG refcount = InterlockedDecrement(&factory->refcount); @@ -267,7 +267,502 @@ static BOOL STDMETHODCALLTYPE dxgi_factory_IsWindowedStereoEnabled(IWineDXGIFact return FALSE; } -static HRESULT STDMETHODCALLTYPE dxgi_factory_CreateSwapChainForHwnd(IWineDXGIFactory *iface, +struct proxy_swapchain +{ + IDXGISwapChain4 IDXGISwapChain4_iface; + IDXGISwapChain4 *swapchain; +}; + +static inline struct proxy_swapchain *proxy_swapchain_from_IDXGISwapChain4(IDXGISwapChain4 *iface) +{ + return CONTAINING_RECORD(iface, struct proxy_swapchain, IDXGISwapChain4_iface); +} + +/* IUnknown methods */ + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_QueryInterface(IDXGISwapChain4 *iface, REFIID riid, void **object) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + HRESULT hr; + IUnknown *unk; + + TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object); + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDXGIObject) + || IsEqualGUID(riid, &IID_IDXGIDeviceSubObject) + || IsEqualGUID(riid, &IID_IDXGISwapChain) + || IsEqualGUID(riid, &IID_IDXGISwapChain1) + || IsEqualGUID(riid, &IID_IDXGISwapChain2) + || IsEqualGUID(riid, &IID_IDXGISwapChain3) + || IsEqualGUID(riid, &IID_IDXGISwapChain4)) + { + hr = IDXGISwapChain4_QueryInterface(swapchain->swapchain, riid, (void **)&unk); + if(SUCCEEDED(hr)) + /* return proxy */ + *object = iface; + else + *object = NULL; + + return hr; + } + + WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid)); + + *object = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_AddRef(IDXGISwapChain4 *iface) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE("swapchain %p.\n", swapchain); + + return IDXGISwapChain4_AddRef(swapchain->swapchain); +} + +static ULONG STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_Release(IDXGISwapChain4 *iface) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + ULONG refcount = IDXGISwapChain4_Release(swapchain->swapchain); + + TRACE("%p decreasing refcount to %lu.\n", swapchain, refcount); + + if (!refcount) + heap_free(swapchain); + + return refcount; +} + +/* IDXGIObject methods */ + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetPrivateData(IDXGISwapChain4 *iface, + REFGUID guid, UINT data_size, const void *data) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data); + + return IDXGISwapChain4_SetPrivateData(swapchain->swapchain, guid, data_size, data); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetPrivateDataInterface(IDXGISwapChain4 *iface, + REFGUID guid, const IUnknown *object) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE("iface %p, guid %s, object %p.\n", iface, debugstr_guid(guid), object); + + return IDXGISwapChain4_SetPrivateDataInterface(swapchain->swapchain, guid, object); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetPrivateData(IDXGISwapChain4 *iface, + REFGUID guid, UINT *data_size, void *data) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data); + + return IDXGISwapChain4_GetPrivateData(swapchain->swapchain, guid, data_size, data); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetParent(IDXGISwapChain4 *iface, REFIID riid, void **parent) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE("iface %p, riid %s, parent %p.\n", iface, debugstr_guid(riid), parent); + + return IDXGISwapChain4_GetParent(swapchain->swapchain, riid, parent); +} + +/* IDXGIDeviceSubObject methods */ + +static HRESULT STDMETHODCALLTYPE proxy_swapchain_GetDevice(IDXGISwapChain4 *iface, REFIID riid, void **device) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE("iface %p, riid %s, device %p.\n", iface, debugstr_guid(riid), device); + + return IDXGISwapChain4_GetDevice(swapchain->swapchain, riid, device); +} + +/* IDXGISwapChain methods */ + +HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_Present(IDXGISwapChain4 *iface, UINT sync_interval, UINT flags) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE("iface %p, sync_interval %u, flags %#x.\n", iface, sync_interval, flags); + + return IDXGISwapChain4_Present(swapchain->swapchain, sync_interval, flags); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetBuffer(IDXGISwapChain4 *iface, + UINT buffer_idx, REFIID riid, void **surface) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetBuffer(swapchain->swapchain, buffer_idx, riid, surface); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetFullscreenState(IDXGISwapChain4 *iface, + BOOL fullscreen, IDXGIOutput *target) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_SetFullscreenState(swapchain->swapchain, fullscreen, target); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetFullscreenState(IDXGISwapChain4 *iface, + BOOL *fullscreen, IDXGIOutput **target) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetFullscreenState(swapchain->swapchain, fullscreen, target); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetDesc(IDXGISwapChain4 *iface, DXGI_SWAP_CHAIN_DESC *desc) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetDesc(swapchain->swapchain, desc); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_ResizeBuffers(IDXGISwapChain4 *iface, + UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format, UINT flags) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_ResizeBuffers(swapchain->swapchain, buffer_count, width, height, format, flags); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_ResizeTarget(IDXGISwapChain4 *iface, + const DXGI_MODE_DESC *target_mode_desc) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_ResizeTarget(swapchain->swapchain, target_mode_desc); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetContainingOutput(IDXGISwapChain4 *iface, IDXGIOutput **output) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetContainingOutput(swapchain->swapchain, output); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetFrameStatistics(IDXGISwapChain4 *iface, + DXGI_FRAME_STATISTICS *stats) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetFrameStatistics(swapchain->swapchain, stats); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetLastPresentCount(IDXGISwapChain4 *iface, + UINT *last_present_count) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetLastPresentCount(swapchain->swapchain, last_present_count); +} + +/* IDXGISwapChain1 methods */ + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetDesc1(IDXGISwapChain4 *iface, DXGI_SWAP_CHAIN_DESC1 *desc) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetDesc1(swapchain->swapchain, desc); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetFullscreenDesc(IDXGISwapChain4 *iface, + DXGI_SWAP_CHAIN_FULLSCREEN_DESC *desc) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetFullscreenDesc(swapchain->swapchain, desc); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetHwnd(IDXGISwapChain4 *iface, HWND *hwnd) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetHwnd(swapchain->swapchain, hwnd); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetCoreWindow(IDXGISwapChain4 *iface, + REFIID iid, void **core_window) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetCoreWindow(swapchain->swapchain, iid, core_window); +} + +HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_Present1(IDXGISwapChain4 *iface, + UINT sync_interval, UINT flags, const DXGI_PRESENT_PARAMETERS *present_parameters) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_Present1(swapchain->swapchain, sync_interval, flags, present_parameters); +} + +static BOOL STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_IsTemporaryMonoSupported(IDXGISwapChain4 *iface) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_IsTemporaryMonoSupported(swapchain->swapchain); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetRestrictToOutput(IDXGISwapChain4 *iface, IDXGIOutput **output) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetRestrictToOutput(swapchain->swapchain, output); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetBackgroundColor(IDXGISwapChain4 *iface, const DXGI_RGBA *color) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_SetBackgroundColor(swapchain->swapchain, color); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetBackgroundColor(IDXGISwapChain4 *iface, DXGI_RGBA *color) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetBackgroundColor(swapchain->swapchain, color); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetRotation(IDXGISwapChain4 *iface, DXGI_MODE_ROTATION rotation) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_SetRotation(swapchain->swapchain, rotation); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetRotation(IDXGISwapChain4 *iface, DXGI_MODE_ROTATION *rotation) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetRotation(swapchain->swapchain, rotation); +} + +/* IDXGISwapChain2 methods */ + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetSourceSize(IDXGISwapChain4 *iface, UINT width, UINT height) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_SetSourceSize(swapchain->swapchain, width, height); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetSourceSize(IDXGISwapChain4 *iface, UINT *width, UINT *height) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetSourceSize(swapchain->swapchain, width, height); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetMaximumFrameLatency(IDXGISwapChain4 *iface, UINT max_latency) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_SetMaximumFrameLatency(swapchain->swapchain, max_latency); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetMaximumFrameLatency(IDXGISwapChain4 *iface, UINT *max_latency) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetMaximumFrameLatency(swapchain->swapchain, max_latency); +} + +static HANDLE STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetFrameLatencyWaitableObject(IDXGISwapChain4 *iface) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetFrameLatencyWaitableObject(swapchain->swapchain); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetMatrixTransform(IDXGISwapChain4 *iface, + const DXGI_MATRIX_3X2_F *matrix) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_SetMatrixTransform(swapchain->swapchain, matrix); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetMatrixTransform(IDXGISwapChain4 *iface, + DXGI_MATRIX_3X2_F *matrix) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetMatrixTransform(swapchain->swapchain, matrix); +} + +/* IDXGISwapChain3 methods */ + +static UINT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetCurrentBackBufferIndex(IDXGISwapChain4 *iface) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_GetCurrentBackBufferIndex(swapchain->swapchain); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_CheckColorSpaceSupport(IDXGISwapChain4 *iface, + DXGI_COLOR_SPACE_TYPE colour_space, UINT *colour_space_support) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_CheckColorSpaceSupport(swapchain->swapchain, colour_space, colour_space_support); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetColorSpace1(IDXGISwapChain4 *iface, + DXGI_COLOR_SPACE_TYPE colour_space) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_SetColorSpace1(swapchain->swapchain, colour_space); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_ResizeBuffers1(IDXGISwapChain4 *iface, + UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format, UINT flags, + const UINT *node_mask, IUnknown * const *present_queue) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_ResizeBuffers1(swapchain->swapchain, buffer_count, width, height, format, flags, node_mask, present_queue); +} + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetHDRMetaData(IDXGISwapChain4 *iface, + DXGI_HDR_METADATA_TYPE type, UINT size, void *metadata) +{ + struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); + + TRACE(".\n"); + + return IDXGISwapChain4_SetHDRMetaData(swapchain->swapchain, type, size, metadata); +} + +static const struct IDXGISwapChain4Vtbl proxy_swapchain_vtbl = +{ + /* IUnknown methods */ + proxy_swapchain_QueryInterface, + proxy_swapchain_AddRef, + proxy_swapchain_Release, + /* IDXGIObject methods */ + proxy_swapchain_SetPrivateData, + proxy_swapchain_SetPrivateDataInterface, + proxy_swapchain_GetPrivateData, + proxy_swapchain_GetParent, + /* IDXGIDeviceSubObject methods */ + proxy_swapchain_GetDevice, + /* IDXGISwapChain methods */ + proxy_swapchain_Present, + proxy_swapchain_GetBuffer, + proxy_swapchain_SetFullscreenState, + proxy_swapchain_GetFullscreenState, + proxy_swapchain_GetDesc, + proxy_swapchain_ResizeBuffers, + proxy_swapchain_ResizeTarget, + proxy_swapchain_GetContainingOutput, + proxy_swapchain_GetFrameStatistics, + proxy_swapchain_GetLastPresentCount, + /* IDXGISwapChain1 methods */ + proxy_swapchain_GetDesc1, + proxy_swapchain_GetFullscreenDesc, + proxy_swapchain_GetHwnd, + proxy_swapchain_GetCoreWindow, + proxy_swapchain_Present1, + proxy_swapchain_IsTemporaryMonoSupported, + proxy_swapchain_GetRestrictToOutput, + proxy_swapchain_SetBackgroundColor, + proxy_swapchain_GetBackgroundColor, + proxy_swapchain_SetRotation, + proxy_swapchain_GetRotation, + /* IDXGISwapChain2 methods */ + proxy_swapchain_SetSourceSize, + proxy_swapchain_GetSourceSize, + proxy_swapchain_SetMaximumFrameLatency, + proxy_swapchain_GetMaximumFrameLatency, + proxy_swapchain_GetFrameLatencyWaitableObject, + proxy_swapchain_SetMatrixTransform, + proxy_swapchain_GetMatrixTransform, + /* IDXGISwapChain3 methods */ + proxy_swapchain_GetCurrentBackBufferIndex, + proxy_swapchain_CheckColorSpaceSupport, + proxy_swapchain_SetColorSpace1, + proxy_swapchain_ResizeBuffers1, + /* IDXGISwapChain4 methods */ + proxy_swapchain_SetHDRMetaData, +}; + +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH dxgi_factory_CreateSwapChainForHwnd(IWineDXGIFactory *iface, IUnknown *device, HWND window, const DXGI_SWAP_CHAIN_DESC1 *desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc, IDXGIOutput *output, IDXGISwapChain1 **swapchain) @@ -299,9 +794,23 @@ static HRESULT STDMETHODCALLTYPE dxgi_factory_CreateSwapChainForHwnd(IWineDXGIFa if (SUCCEEDED(IUnknown_QueryInterface(device, &IID_IWineDXGISwapChainFactory, (void **)&swapchain_factory))) { + IDXGISwapChain4 *swapchain_impl; hr = IWineDXGISwapChainFactory_create_swapchain(swapchain_factory, - (IDXGIFactory *)iface, window, desc, fullscreen_desc, output, swapchain); + (IDXGIFactory *)iface, window, desc, fullscreen_desc, output, (IDXGISwapChain1 **)&swapchain_impl); IWineDXGISwapChainFactory_Release(swapchain_factory); + if (SUCCEEDED(hr)) + { + struct proxy_swapchain *obj; + + obj = heap_alloc_zero(sizeof(*obj)); + obj->IDXGISwapChain4_iface.lpVtbl = &proxy_swapchain_vtbl; + obj->swapchain = swapchain_impl; + *swapchain = (IDXGISwapChain1 *)&obj->IDXGISwapChain4_iface; + } + else + { + *swapchain = NULL; + } return hr; } diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c index 9677142e0af..8ca67b5fdd5 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -221,7 +221,7 @@ static ULONG STDMETHODCALLTYPE d3d11_swapchain_AddRef(IDXGISwapChain1 *iface) return refcount; } -static ULONG STDMETHODCALLTYPE d3d11_swapchain_Release(IDXGISwapChain1 *iface) +static ULONG STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d11_swapchain_Release(IDXGISwapChain1 *iface) { struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface); ULONG refcount = InterlockedDecrement(&swapchain->refcount); @@ -314,7 +314,7 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetDevice(IDXGISwapChain1 *ifac /* IDXGISwapChain1 methods */ -static HRESULT d3d11_swapchain_present(struct d3d11_swapchain *swapchain, +static HRESULT DECLSPEC_HOTPATCH d3d11_swapchain_present(struct d3d11_swapchain *swapchain, unsigned int sync_interval, unsigned int flags) { HRESULT hr; @@ -694,7 +694,7 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetCoreWindow(IDXGISwapChain1 * return DXGI_ERROR_INVALID_CALL; } -static HRESULT STDMETHODCALLTYPE d3d11_swapchain_Present1(IDXGISwapChain1 *iface, +static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d11_swapchain_Present1(IDXGISwapChain1 *iface, UINT sync_interval, UINT flags, const DXGI_PRESENT_PARAMETERS *present_parameters) { struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface); From e85672c6e6b42d187c53b5822c4611eda733442d Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Thu, 22 Jul 2021 16:11:18 -0500 Subject: [PATCH 0389/2777] HACK: shell32: Update knownfolder paths in the registry Guilty Gear Strive requires that the path be in the new format. Since we haven't yet found a game that has a problem with the new format, let's just use that in all cases. For Steam cloud sync failures. CW-Bug-Id: #18905 --- dlls/shell32/shellpath.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c index 6f03a6feb45..0b43a6a64c8 100644 --- a/dlls/shell32/shellpath.c +++ b/dlls/shell32/shellpath.c @@ -2881,6 +2881,8 @@ static HRESULT _SHRegisterFolders(HKEY hRootKey, HANDLE hToken, LPCWSTR szUserShellFolderPath, LPCWSTR szShellFolderPath, const UINT folders[], UINT foldersLen) { + static const WCHAR WineVistaPathsW[] = {'_','_','W','i','n','e','V','i','s','t','a','P','a','t','h','s',0}; + const WCHAR *szValueName; WCHAR buffer[40]; UINT i; @@ -2889,6 +2891,7 @@ static HRESULT _SHRegisterFolders(HKEY hRootKey, HANDLE hToken, HKEY hUserKey = NULL, hKey = NULL; DWORD dwType, dwPathLen; LONG ret; + DWORD already_vista_paths = 0; TRACE("%p,%p,%s,%p,%u\n", hRootKey, hToken, debugstr_w(szUserShellFolderPath), folders, foldersLen); @@ -2902,6 +2905,12 @@ static HRESULT _SHRegisterFolders(HKEY hRootKey, HANDLE hToken, if (ret) hr = HRESULT_FROM_WIN32(ret); } + + /* check if the registry has already been updated to the vista+ style paths */ + dwPathLen = sizeof(already_vista_paths); + RegQueryValueExW(hUserKey, WineVistaPathsW, NULL, &dwType, + (LPBYTE)&already_vista_paths, &dwPathLen); + for (i = 0; SUCCEEDED(hr) && i < foldersLen; i++) { dwPathLen = MAX_PATH * sizeof(WCHAR); @@ -2914,9 +2923,10 @@ static HRESULT _SHRegisterFolders(HKEY hRootKey, HANDLE hToken, szValueName = &buffer[0]; } - if (RegQueryValueExW(hUserKey, szValueName, NULL, - &dwType, (LPBYTE)path, &dwPathLen) || (dwType != REG_SZ && - dwType != REG_EXPAND_SZ)) + if (!already_vista_paths || + RegQueryValueExW(hUserKey, szValueName, NULL, &dwType, + (LPBYTE)path, &dwPathLen) || + (dwType != REG_SZ && dwType != REG_EXPAND_SZ)) { *path = '\0'; if (CSIDL_Data[folders[i]].type == CSIDL_Type_User) @@ -2957,6 +2967,11 @@ static HRESULT _SHRegisterFolders(HKEY hRootKey, HANDLE hToken, hToken, SHGFP_TYPE_DEFAULT, path); } } + + already_vista_paths = 1; + RegSetValueExW(hUserKey, WineVistaPathsW, 0, REG_DWORD, + (LPBYTE)&already_vista_paths, sizeof(already_vista_paths)); + if (hUserKey) RegCloseKey(hUserKey); if (hKey) From 1dd3a7136580c0cf01c049ea18fe8a8b627c058f Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Thu, 3 Feb 2022 11:35:13 -0600 Subject: [PATCH 0390/2777] HACK: shell32: Preserve duplicated Documents/Stuff directories --- dlls/shell32/shellpath.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c index 0b43a6a64c8..36083e575d2 100644 --- a/dlls/shell32/shellpath.c +++ b/dlls/shell32/shellpath.c @@ -3112,6 +3112,23 @@ static HRESULT create_extra_folders(void) hr = SHGetFolderPathAndSubDirW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_DEFAULT, L"Microsoft\\Windows\\Themes", path); } + + + /* Proton HACK: In older Proton versions, duplicate Stuff directories were + * created at both %PROFILE%\Music and %PROFILE\Documents\Music. Due to + * some bugs when downgrading to those older Proton versions, create those + * missing Documents directories here, too. */ + SHGetFolderPathAndSubDirW(0, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, + SHGFP_TYPE_DEFAULT, L"Downloads", path); + SHGetFolderPathAndSubDirW(0, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, + SHGFP_TYPE_DEFAULT, L"Music", path); + SHGetFolderPathAndSubDirW(0, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, + SHGFP_TYPE_DEFAULT, L"Pictures", path); + SHGetFolderPathAndSubDirW(0, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, + SHGFP_TYPE_DEFAULT, L"Templates", path); + SHGetFolderPathAndSubDirW(0, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, + SHGFP_TYPE_DEFAULT, L"Videos", path); + return hr; } From 533b90626c60904121ce57e39b68e2492a332b8c Mon Sep 17 00:00:00 2001 From: Esme Povirk Date: Thu, 22 Apr 2021 14:35:40 -0500 Subject: [PATCH 0391/2777] HACK: mscoree: For M&B2:Bannerlord, redirect ManagedStarter loads to Bannerlord.exe For M&B2:Bannerlord. CW-Bug-Id: #18843 --- dlls/mscoree/metahost.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/dlls/mscoree/metahost.c b/dlls/mscoree/metahost.c index 657d2ba3640..e6ab767c22c 100644 --- a/dlls/mscoree/metahost.c +++ b/dlls/mscoree/metahost.c @@ -1822,6 +1822,30 @@ static MonoAssembly* CDECL wine_mono_assembly_preload_hook_fn(MonoAssemblyName * } } + if (!strcmp(assemblyname, "ManagedStarter")) + { + /* HACK for Mount & Blade II: Bannerlord + * + * The launcher executable uses an AssemblyResolve event handler + * to redirect loads of the "ManagedStarter" assembly to + * Bannerlord.exe. Due to Mono issue #11319, the runtime attempts + * to load ManagedStarter before executing the static constructor + * that adds this event handler. We work around this by doing the + * same thing in our own assembly load hook. */ + const char* sgi = getenv("SteamGameId"); + if (sgi && !strcmp(sgi, "261550")) + { + FIXME("hack, using Bannerlord.exe\n"); + + result = mono_assembly_open("Bannerlord.exe", &stat); + + if (result) + goto done; + else + ERR("Bannerlord.exe failed to load\n"); + } + } + if (!strcmp(assemblyname, "CameraQuakeViewer")) { /* HACK for Nights of Azure which references type from a non-existing DLL. From 4fa0021ed8712b71eaf76f371cce02400115453f Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 7 Jun 2022 13:02:38 -0500 Subject: [PATCH 0392/2777] HACK: mscoree: Add hack for missing UnrealEdCSharp assembly for Karmaflow CW-Bug-Id: #20672 --- dlls/mscoree/metahost.c | 60 +++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/dlls/mscoree/metahost.c b/dlls/mscoree/metahost.c index e6ab767c22c..d35064e9af3 100644 --- a/dlls/mscoree/metahost.c +++ b/dlls/mscoree/metahost.c @@ -1766,6 +1766,8 @@ static MonoAssembly* CDECL wine_mono_assembly_preload_hook_fn(MonoAssemblyName * static const WCHAR dotdllW[] = {'.','d','l','l',0}; static const WCHAR dotexeW[] = {'.','e','x','e',0}; + const char *sgi = getenv("SteamGameId"); + stringname = mono_stringify_assembly_name(aname); assemblyname = mono_assembly_name_get_name(aname); culture = mono_assembly_name_get_culture(aname); @@ -1832,7 +1834,6 @@ static MonoAssembly* CDECL wine_mono_assembly_preload_hook_fn(MonoAssemblyName * * to load ManagedStarter before executing the static constructor * that adds this event handler. We work around this by doing the * same thing in our own assembly load hook. */ - const char* sgi = getenv("SteamGameId"); if (sgi && !strcmp(sgi, "261550")) { FIXME("hack, using Bannerlord.exe\n"); @@ -1846,27 +1847,52 @@ static MonoAssembly* CDECL wine_mono_assembly_preload_hook_fn(MonoAssemblyName * } } - if (!strcmp(assemblyname, "CameraQuakeViewer")) + /* HACK for games which reference a type from a non-existing DLL. + * Native .NET framework normally gets away with it but Mono cannot + * due to some deeply rooted differences. */ + if (sgi) { - /* HACK for Nights of Azure which references type from a non-existing DLL. - * Native .NET framework normally gets away with it but Mono cannot - * due to some deeply rooted differences. */ - const char* sgi = getenv("SteamGameId"); - if (sgi && !strcmp(sgi, "527280")) + size_t i; + + static const struct { + const char *assembly_name; + const char *module_name; + const char *appid; + const char *source; + } assembly_hacks[] = { + { + "CameraQuakeViewer", + "CameraQuakeViewer.dll", + "527280", /* Nights of Azure */ + "namespace CQViewer { class CQMgr {} }" + }, + { + "UnrealEdCSharp", + "UnrealEdCSharp.dll", + "317940", /* Karmaflow */ + "namespace ContentBrowser { class IContentBrowserBackendInterface {} class Package {} } " + }, + }; + + for (i = 0; i < ARRAY_SIZE(assembly_hacks); ++i) { - char assembly_path[MAX_PATH]; + if (!strcmp(assemblyname, assembly_hacks[i].assembly_name) && + !strcmp(sgi, assembly_hacks[i].appid)) + { + char assembly_path[MAX_PATH]; - FIXME("HACK: Building CameraQuakeViewer.dll\n"); + FIXME("HACK: Building %s\n", assembly_hacks[i].module_name); - if (compile_assembly("namespace CQViewer { class CQMgr {} }", "CameraQuakeViewer.dll", assembly_path, MAX_PATH)) - result = mono_assembly_open(assembly_path, &stat); - else - ERR("HACK: Failed to build CameraQuakeViewer.dll\n"); + if (compile_assembly(assembly_hacks[i].source, assembly_hacks[i].module_name, assembly_path, MAX_PATH)) + result = mono_assembly_open(assembly_path, &stat); + else + ERR("HACK: Failed to build %s\n", assembly_hacks[i].assembly_name); - if (result) - goto done; - else - ERR("HACK: Failed to load CameraQuakeViewer.dll\n"); + if (result) + goto done; + + ERR("HACK: Failed to load %s\n", assembly_hacks[i].assembly_name); + } } } From 14e9c847b8a1fedcbc56bd6f76492bd7b6ff27f2 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Tue, 17 May 2022 09:38:08 +0300 Subject: [PATCH 0393/2777] getminidump: Add a small tool to create minidumps. Signed-off-by: Nikolay Sivov --- configure.ac | 1 + programs/getminidump/Makefile.in | 7 ++++ programs/getminidump/main.c | 60 ++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 programs/getminidump/Makefile.in create mode 100644 programs/getminidump/main.c diff --git a/configure.ac b/configure.ac index 4a56c63b888..ac1508c86c5 100644 --- a/configure.ac +++ b/configure.ac @@ -3349,6 +3349,7 @@ WINE_CONFIG_MAKEFILE(programs/find/tests) WINE_CONFIG_MAKEFILE(programs/findstr) WINE_CONFIG_MAKEFILE(programs/fsutil) WINE_CONFIG_MAKEFILE(programs/fsutil/tests) +WINE_CONFIG_MAKEFILE(programs/getminidump) WINE_CONFIG_MAKEFILE(programs/hh) WINE_CONFIG_MAKEFILE(programs/hostname) WINE_CONFIG_MAKEFILE(programs/icacls) diff --git a/programs/getminidump/Makefile.in b/programs/getminidump/Makefile.in new file mode 100644 index 00000000000..c61d9e23cd1 --- /dev/null +++ b/programs/getminidump/Makefile.in @@ -0,0 +1,7 @@ +MODULE = getminidump.exe +IMPORTS = shcore dbghelp + +EXTRADLLFLAGS = -mwindows -municode + +C_SRCS = \ + main.c diff --git a/programs/getminidump/main.c b/programs/getminidump/main.c new file mode 100644 index 00000000000..3cc5010797a --- /dev/null +++ b/programs/getminidump/main.c @@ -0,0 +1,60 @@ +/* + * Copyright 2022 Nikolay Sivov 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 + */ + +#include +#include + +#include +#include +#include + +int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, WCHAR *cmdline, int nCmdShow) +{ + HANDLE process, dumpfile; + WCHAR **argv, *ptr; + DWORD pid; + int argc; + BOOL ret; + + argv = CommandLineToArgvW(cmdline, &argc); + if (argc < 1) return 1; + + ptr = argv[0]; + if (ptr[0] == '0' && towlower(ptr[1]) == 'x') + pid = wcstoul(ptr, NULL, 16); + else + pid = wcstoul(ptr, NULL, 10); + + process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); + if (!process) + return 2; + + dumpfile = CreateFileW(L"minidump.dmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (dumpfile == INVALID_HANDLE_VALUE) + { + CloseHandle(process); + return 3; + } + + ret = MiniDumpWriteDump(process, pid, dumpfile, MiniDumpNormal | MiniDumpWithFullMemory, NULL, NULL, NULL); + + CloseHandle(dumpfile); + CloseHandle(process); + + return ret ? 0 : 4; +} From 45e3205dbde4f832fe5da324d9f66ce76b93f1a6 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 15 Jan 2019 10:10:47 -0600 Subject: [PATCH 0394/2777] HACK: ntdll: Don't pass SDL_AUDIODRIVER from Linux environment. --- dlls/ntdll/unix/env.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c index 3c387ba9027..145b99aafdc 100644 --- a/dlls/ntdll/unix/env.c +++ b/dlls/ntdll/unix/env.c @@ -343,6 +343,7 @@ static BOOL is_special_env_var( const char *var ) STARTS_WITH( var, "TEMP=" ) || STARTS_WITH( var, "TMP=" ) || STARTS_WITH( var, "QT_" ) || + STARTS_WITH( var, "SDL_AUDIODRIVER=" ) || STARTS_WITH( var, "VK_" )); } From 4955ce872e5e114bfda47e3fd682460901d3fe18 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 7 Apr 2020 11:05:47 -0500 Subject: [PATCH 0395/2777] winepulse: Add stub IAudioClockAdjustment implementation CW-Bug-Id: #17818 --- dlls/winepulse.drv/mmdevdrv.c | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c index 5de9a941099..73eb1c137c8 100644 --- a/dlls/winepulse.drv/mmdevdrv.c +++ b/dlls/winepulse.drv/mmdevdrv.c @@ -136,6 +136,7 @@ struct ACImpl { IAudioCaptureClient IAudioCaptureClient_iface; IAudioClock IAudioClock_iface; IAudioClock2 IAudioClock2_iface; + IAudioClockAdjustment IAudioClockAdjustment_iface; IAudioStreamVolume IAudioStreamVolume_iface; IUnknown *marshal; IMMDevice *parent; @@ -163,6 +164,7 @@ static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl; static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl; static const IAudioClockVtbl AudioClock_Vtbl; static const IAudioClock2Vtbl AudioClock2_Vtbl; +static const IAudioClockAdjustmentVtbl AudioClockAdjustment_Vtbl; static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl; static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client); @@ -207,6 +209,11 @@ static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface) return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface); } +static inline ACImpl *impl_from_IAudioClockAdjustment(IAudioClockAdjustment *iface) +{ + return CONTAINING_RECORD(iface, ACImpl, IAudioClockAdjustment_iface); +} + static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface) { return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface); @@ -600,6 +607,7 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl; This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl; This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl; + This->IAudioClockAdjustment_iface.lpVtbl = &AudioClockAdjustment_Vtbl; This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl; This->dataflow = dataflow; This->parent = dev; @@ -634,6 +642,8 @@ static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface, IsEqualIID(riid, &IID_IAudioClient2) || IsEqualIID(riid, &IID_IAudioClient3)) *ppv = iface; + else if (IsEqualIID(riid, &IID_IAudioClockAdjustment)) + *ppv = &This->IAudioClockAdjustment_iface; if (*ppv) { IUnknown_AddRef((IUnknown*)*ppv); return S_OK; @@ -1761,6 +1771,43 @@ static const IAudioClock2Vtbl AudioClock2_Vtbl = AudioClock2_GetDevicePosition }; +static HRESULT WINAPI AudioClockAdjustment_QueryInterface(IAudioClockAdjustment *iface, + REFIID riid, void **ppv) +{ + ACImpl *This = impl_from_IAudioClockAdjustment(iface); + return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv); +} + +static ULONG WINAPI AudioClockAdjustment_AddRef(IAudioClockAdjustment *iface) +{ + ACImpl *This = impl_from_IAudioClockAdjustment(iface); + return IAudioClient_AddRef((IAudioClient *)&This->IAudioClient3_iface); +} + +static ULONG WINAPI AudioClockAdjustment_Release(IAudioClockAdjustment *iface) +{ + ACImpl *This = impl_from_IAudioClockAdjustment(iface); + return IAudioClient_Release((IAudioClient *)&This->IAudioClient3_iface); +} + +static HRESULT WINAPI AudioClockAdjustment_SetSampleRate(IAudioClockAdjustment *iface, + float new_rate) +{ + ACImpl *This = impl_from_IAudioClockAdjustment(iface); + + TRACE("(%p)->(%f)\n", This, new_rate); + + return E_NOTIMPL; +} + +static const IAudioClockAdjustmentVtbl AudioClockAdjustment_Vtbl = +{ + AudioClockAdjustment_QueryInterface, + AudioClockAdjustment_AddRef, + AudioClockAdjustment_Release, + AudioClockAdjustment_SetSampleRate +}; + static HRESULT WINAPI AudioStreamVolume_QueryInterface( IAudioStreamVolume *iface, REFIID riid, void **ppv) { From 2770eb071b7bb3e9fc19e8cd53d70ce6907d77a9 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Fri, 1 Oct 2021 12:47:58 +0200 Subject: [PATCH 0396/2777] winepulse: Implement IAudioClockAdjustment::SetSampleRate CW-Bug-Id: #17818 --- dlls/mmdevapi/unixlib.h | 8 ++++++ dlls/winealsa.drv/alsa.c | 2 ++ dlls/winecoreaudio.drv/coreaudio.c | 2 ++ dlls/wineoss.drv/oss.c | 2 ++ dlls/winepulse.drv/mmdevdrv.c | 9 +++++-- dlls/winepulse.drv/pulse.c | 41 +++++++++++++++++++++++++++++- 6 files changed, 61 insertions(+), 3 deletions(-) diff --git a/dlls/mmdevapi/unixlib.h b/dlls/mmdevapi/unixlib.h index ea0d2f9c4b9..afea9d6def6 100644 --- a/dlls/mmdevapi/unixlib.h +++ b/dlls/mmdevapi/unixlib.h @@ -217,6 +217,13 @@ struct set_event_handle_params HRESULT result; }; +struct set_sample_rate_params +{ + stream_handle stream; + float new_rate; + HRESULT result; +}; + struct test_connect_params { const char *name; @@ -324,6 +331,7 @@ enum unix_funcs get_position, set_volumes, set_event_handle, + set_sample_rate, test_connect, is_started, get_prop_value, diff --git a/dlls/winealsa.drv/alsa.c b/dlls/winealsa.drv/alsa.c index ffa39f5e484..b54656d2fb9 100644 --- a/dlls/winealsa.drv/alsa.c +++ b/dlls/winealsa.drv/alsa.c @@ -2457,6 +2457,7 @@ unixlib_entry_t __wine_unix_call_funcs[] = alsa_set_volumes, alsa_set_event_handle, NULL, + NULL, alsa_is_started, alsa_get_prop_value, NULL, @@ -2878,6 +2879,7 @@ unixlib_entry_t __wine_unix_call_wow64_funcs[] = alsa_wow64_set_volumes, alsa_wow64_set_event_handle, NULL, + NULL, alsa_is_started, alsa_wow64_get_prop_value, NULL, diff --git a/dlls/winecoreaudio.drv/coreaudio.c b/dlls/winecoreaudio.drv/coreaudio.c index b48a0c751fd..a7b4ee154ee 100644 --- a/dlls/winecoreaudio.drv/coreaudio.c +++ b/dlls/winecoreaudio.drv/coreaudio.c @@ -1673,6 +1673,7 @@ unixlib_entry_t __wine_unix_call_funcs[] = unix_set_volumes, NULL, NULL, + NULL, unix_is_started, NULL, unix_midi_init, @@ -2017,6 +2018,7 @@ unixlib_entry_t __wine_unix_call_wow64_funcs[] = unix_wow64_set_volumes, NULL, NULL, + NULL, unix_is_started, NULL, unix_wow64_midi_init, diff --git a/dlls/wineoss.drv/oss.c b/dlls/wineoss.drv/oss.c index 4bc8bc20666..d072f367b57 100644 --- a/dlls/wineoss.drv/oss.c +++ b/dlls/wineoss.drv/oss.c @@ -1637,6 +1637,7 @@ unixlib_entry_t __wine_unix_call_funcs[] = oss_get_position, oss_set_volumes, oss_set_event_handle, + NULL, oss_test_connect, oss_is_started, NULL, @@ -2041,6 +2042,7 @@ unixlib_entry_t __wine_unix_call_wow64_funcs[] = oss_wow64_get_position, oss_wow64_set_volumes, oss_wow64_set_event_handle, + NULL, oss_wow64_test_connect, oss_is_started, NULL, diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c index 73eb1c137c8..18d554d0032 100644 --- a/dlls/winepulse.drv/mmdevdrv.c +++ b/dlls/winepulse.drv/mmdevdrv.c @@ -1794,10 +1794,15 @@ static HRESULT WINAPI AudioClockAdjustment_SetSampleRate(IAudioClockAdjustment * float new_rate) { ACImpl *This = impl_from_IAudioClockAdjustment(iface); + struct set_sample_rate_params params; - TRACE("(%p)->(%f)\n", This, new_rate); + if (!This->pulse_stream) + return AUDCLNT_E_NOT_INITIALIZED; - return E_NOTIMPL; + params.stream = This->pulse_stream; + params.new_rate = new_rate; + pulse_call(set_sample_rate, ¶ms); + return params.result; } static const IAudioClockAdjustmentVtbl AudioClockAdjustment_Vtbl = diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c index 41d988e692b..9c8f4117c10 100644 --- a/dlls/winepulse.drv/pulse.c +++ b/dlls/winepulse.drv/pulse.c @@ -699,7 +699,7 @@ static void pulse_probe_settings(int render, const char *pulse_name, WAVEFORMATE ret = -1; else if (render) ret = pa_stream_connect_playback(stream, pulse_name, &attr, - PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS, NULL, NULL); + PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS|PA_STREAM_VARIABLE_RATE, NULL, NULL); else ret = pa_stream_connect_record(stream, pulse_name, &attr, PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS); if (ret >= 0) { @@ -1041,6 +1041,8 @@ static HRESULT pulse_stream_connect(struct pulse_stream *stream, const char *pul else pulse_name = NULL; /* use default */ + if (stream->dataflow == eRender) flags |= PA_STREAM_VARIABLE_RATE; + if (stream->dataflow == eRender) ret = pa_stream_connect_playback(stream->stream, pulse_name, &attr, flags, NULL, NULL); else @@ -2260,6 +2262,41 @@ static NTSTATUS pulse_set_event_handle(void *args) return STATUS_SUCCESS; } +static NTSTATUS pulse_set_sample_rate(void *args) +{ + struct set_sample_rate_params *params = args; + struct pulse_stream *stream = handle_get_stream(params->stream); + HRESULT hr = S_OK; + pa_operation *o; + int success; + + pulse_lock(); + if (!pulse_stream_valid(stream)) + hr = AUDCLNT_E_DEVICE_INVALIDATED; + else + { + if (!(o = pa_stream_update_sample_rate(stream->stream, params->new_rate, pulse_op_cb, &success))) + success = 0; + else + { + while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) + pthread_cond_wait(&pulse_cond, &pulse_mutex); + pa_operation_unref(o); + } + + if (!success) hr = E_FAIL; + else + { + stream->ss.rate = params->new_rate; + stream->period_bytes = pa_frame_size(&stream->ss) * muldiv(stream->mmdev_period_usec, stream->ss.rate, 1000000); + } + } + pulse_unlock(); + + params->result = hr; + return STATUS_SUCCESS; +} + static NTSTATUS pulse_is_started(void *args) { struct is_started_params *params = args; @@ -2385,6 +2422,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = pulse_get_position, pulse_set_volumes, pulse_set_event_handle, + pulse_set_sample_rate, pulse_test_connect, pulse_is_started, pulse_get_prop_value, @@ -2832,6 +2870,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = pulse_wow64_get_position, pulse_wow64_set_volumes, pulse_wow64_set_event_handle, + NULL, pulse_wow64_test_connect, pulse_is_started, pulse_wow64_get_prop_value, From 464a79989b5250a1aa9e6a6e54aa0a334cd523ff Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Mon, 10 Dec 2018 12:48:41 -0600 Subject: [PATCH 0397/2777] winepulse: Set PulseAudio application name property in the environment. So PA doesn't present all Wine applications as "wine-preloader", and allows PA to store per-application settings. --- dlls/winepulse.drv/pulse.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c index 9c8f4117c10..a16f0a2f1e1 100644 --- a/dlls/winepulse.drv/pulse.c +++ b/dlls/winepulse.drv/pulse.c @@ -371,6 +371,7 @@ static HRESULT pulse_connect(const char *name) pa_context_unref(pulse_ctx); pulse_ctx = pa_context_new(pa_mainloop_get_api(pulse_ml), name); + setenv("PULSE_PROP_application.name", name, 1); if (!pulse_ctx) { ERR("Failed to create context\n"); return E_FAIL; From 75d82b3985fec4152b3852155f68ca1e87994753 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Thu, 19 Dec 2019 09:12:17 -0600 Subject: [PATCH 0398/2777] winex11.drv: Remove nvidia hack workaround This breaks things for users who legitimately have only one resolution. --- dlls/winex11.drv/xrandr.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c index dbd8a721074..1c106c4f985 100644 --- a/dlls/winex11.drv/xrandr.c +++ b/dlls/winex11.drv/xrandr.c @@ -32,9 +32,6 @@ #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(xrandr); -#ifdef HAVE_XRRGETPROVIDERRESOURCES -WINE_DECLARE_DEBUG_CHANNEL(winediag); -#endif #ifdef SONAME_LIBXRANDR @@ -369,7 +366,6 @@ static BOOL is_broken_driver(void) XRRScreenResources *screen_resources; XRROutputInfo *output_info; XRRModeInfo *first_mode; - INT major, event, error; INT output_idx, i, j; BOOL only_one_mode; @@ -420,15 +416,6 @@ static BOOL is_broken_driver(void) if (!only_one_mode) continue; - - /* Check if it is NVIDIA proprietary driver */ - if (XQueryExtension( gdi_display, "NV-CONTROL", &major, &event, &error )) - { - ERR_(winediag)("Broken NVIDIA RandR detected, falling back to RandR 1.0. " - "Please consider using the Nouveau driver instead.\n"); - pXRRFreeScreenResources( screen_resources ); - return TRUE; - } } pXRRFreeScreenResources( screen_resources ); return FALSE; From a414510dae63c4cef878edb7fe7f4a081e598517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20P=C3=A1ral?= Date: Wed, 10 Oct 2018 19:17:00 +0200 Subject: [PATCH 0399/2777] readme: only adjust hard limit in systemd (#20) Instead of increasing both soft and hard fileno limit in systemd instructions, increase just the hard limit. Soft limit needs to stay at 1024 for compatibility with programs using select() instead of newer poll()/epoll(), otherwise such programs might fail. --- README.esync | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.esync b/README.esync index 11d86563a10..6520f2da564 100644 --- a/README.esync +++ b/README.esync @@ -23,7 +23,7 @@ On distributions using systemd, the settings in `/etc/security/limits.conf` will be overridden by systemd's own settings. If you run `ulimit -Hn` and it returns a lower number than the one you've previously set, then you can set -DefaultLimitNOFILE=1048576 +DefaultLimitNOFILE=1024:1048576 in both `/etc/systemd/system.conf` and `/etc/systemd/user.conf`. You can then execute `sudo systemctl daemon-reexec` and restart your session. Check again From 65144565727e61de63e14bf7df774bbd9b6d618c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 12 Mar 2021 23:58:39 +0300 Subject: [PATCH 0400/2777] esync: Fix restoring the objects state on wait all objects retry. For Forza Horizon 4. --- dlls/ntdll/unix/esync.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 7871122e5a1..742d10439db 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -1147,10 +1147,22 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA { /* We were too slow. Put everything back. */ value = 1; - for (j = i; j >= 0; j--) + for (j = i - 1; j >= 0; j--) { - if (write( obj->fd, &value, sizeof(value) ) == -1) + struct esync *obj = objs[j]; + + if (obj->type == ESYNC_MUTEX) + { + struct mutex *mutex = obj->shm; + + if (mutex->tid == GetCurrentThreadId()) + continue; + } + if (write( fds[j].fd, &value, sizeof(value) ) == -1) + { + ERR("write failed.\n"); return errno_to_status( errno ); + } } goto tryagain; /* break out of two loops and a switch */ From 8a4b2fd10861e740d9cbb9c0110326dba6bfc45e Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 15:17:29 -0500 Subject: [PATCH 0401/2777] server: Create server objects for futex-based synchronization objects. --- server/Makefile.in | 1 + server/fsync.c | 286 ++++++++++++++++++++++++++++++++++++++++++++ server/fsync.h | 22 ++++ server/main.c | 4 + server/protocol.def | 11 ++ 5 files changed, 324 insertions(+) create mode 100644 server/fsync.c create mode 100644 server/fsync.h diff --git a/server/Makefile.in b/server/Makefile.in index 97afbf72547..c364b2b62aa 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -15,6 +15,7 @@ C_SRCS = \ event.c \ fd.c \ file.c \ + fsync.c \ handle.c \ hook.c \ mach.c \ diff --git a/server/fsync.c b/server/fsync.c new file mode 100644 index 00000000000..ce538f1a49c --- /dev/null +++ b/server/fsync.c @@ -0,0 +1,286 @@ +/* + * futex-based synchronization objects + * + * Copyright (C) 2018 Zebediah Figura + * + * 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 + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef HAVE_SYS_SYSCALL_H +# include +#endif +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winternl.h" + +#include "handle.h" +#include "request.h" +#include "fsync.h" + +#include "pshpack4.h" +struct futex_wait_block +{ + int *addr; +#if __SIZEOF_POINTER__ == 4 + int pad; +#endif + int val; +}; +#include "poppack.h" + +static inline int futex_wait_multiple( const struct futex_wait_block *futexes, + int count, const struct timespec *timeout ) +{ + return syscall( __NR_futex, futexes, 13, count, timeout, 0, 0 ); +} + +int do_fsync(void) +{ +#ifdef __linux__ + static int do_fsync_cached = -1; + + if (do_fsync_cached == -1) + { + static const struct timespec zero; + futex_wait_multiple( NULL, 0, &zero ); + do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; + } + + return do_fsync_cached; +#else + return 0; +#endif +} + +static char shm_name[29]; +static int shm_fd; +static off_t shm_size; +static void **shm_addrs; +static int shm_addrs_size; /* length of the allocated shm_addrs array */ +static long pagesize; + +static void shm_cleanup(void) +{ + close( shm_fd ); + if (shm_unlink( shm_name ) == -1) + perror( "shm_unlink" ); +} + +void fsync_init(void) +{ + struct stat st; + + if (fstat( config_dir_fd, &st ) == -1) + fatal_error( "cannot stat config dir\n" ); + + if (st.st_ino != (unsigned long)st.st_ino) + sprintf( shm_name, "/wine-%lx%08lx-fsync", (unsigned long)((unsigned long long)st.st_ino >> 32), (unsigned long)st.st_ino ); + else + sprintf( shm_name, "/wine-%lx-fsync", (unsigned long)st.st_ino ); + + if (!shm_unlink( shm_name )) + fprintf( stderr, "fsync: warning: a previous shm file %s was not properly removed\n", shm_name ); + + shm_fd = shm_open( shm_name, O_RDWR | O_CREAT | O_EXCL, 0644 ); + if (shm_fd == -1) + perror( "shm_open" ); + + pagesize = sysconf( _SC_PAGESIZE ); + + shm_addrs = calloc( 128, sizeof(shm_addrs[0]) ); + shm_addrs_size = 128; + + shm_size = pagesize; + if (ftruncate( shm_fd, shm_size ) == -1) + perror( "ftruncate" ); + + atexit( shm_cleanup ); +} + +struct fsync +{ + struct object obj; + unsigned int shm_idx; +}; + +static void fsync_dump( struct object *obj, int verbose ); +static void fsync_destroy( struct object *obj ); + +static const struct object_ops fsync_ops = +{ + sizeof(struct fsync), /* size */ + &no_type, /* type */ + fsync_dump, /* dump */ + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + default_map_access, /* map_access */ + default_get_sd, /* get_sd */ + default_set_sd, /* set_sd */ + default_get_full_name, /* get_full_name */ + no_lookup_name, /* lookup_name */ + directory_link_name, /* link_name */ + default_unlink_name, /* unlink_name */ + no_open_file, /* open_file */ + no_kernel_obj_list, /* get_kernel_obj_list */ + no_close_handle, /* close_handle */ + fsync_destroy /* destroy */ +}; + +static void fsync_dump( struct object *obj, int verbose ) +{ + struct fsync *fsync = (struct fsync *)obj; + assert( obj->ops == &fsync_ops ); + fprintf( stderr, "fsync idx=%d\n", fsync->shm_idx ); +} + +static void fsync_destroy( struct object *obj ) +{ +} + +static void *get_shm( unsigned int idx ) +{ + int entry = (idx * 8) / pagesize; + int offset = (idx * 8) % pagesize; + + if (entry >= shm_addrs_size) + { + int new_size = max(shm_addrs_size * 2, entry + 1); + + if (!(shm_addrs = realloc( shm_addrs, new_size * sizeof(shm_addrs[0]) ))) + fprintf( stderr, "fsync: couldn't expand shm_addrs array to size %d\n", entry + 1 ); + + memset( shm_addrs + shm_addrs_size, 0, (new_size - shm_addrs_size) * sizeof(shm_addrs[0]) ); + + shm_addrs_size = new_size; + } + + if (!shm_addrs[entry]) + { + void *addr = mmap( NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, entry * pagesize ); + if (addr == (void *)-1) + { + fprintf( stderr, "fsync: failed to map page %d (offset %#lx): ", entry, entry * pagesize ); + perror( "mmap" ); + } + + if (debug_level) + fprintf( stderr, "fsync: Mapping page %d at %p.\n", entry, addr ); + + if (__sync_val_compare_and_swap( &shm_addrs[entry], 0, addr )) + munmap( addr, pagesize ); /* someone beat us to it */ + } + + return (void *)((unsigned long)shm_addrs[entry] + offset); +} + +/* FIXME: This is rather inefficient... */ +static unsigned int shm_idx_counter = 1; + +struct fsync *create_fsync( struct object *root, const struct unicode_str *name, + unsigned int attr, int low, int high, + const struct security_descriptor *sd ) +{ +#ifdef __linux__ + struct fsync *fsync; + + if ((fsync = create_named_object( root, &fsync_ops, name, attr, sd ))) + { + if (get_error() != STATUS_OBJECT_NAME_EXISTS) + { + int *shm; + + /* initialize it if it didn't already exist */ + + fsync->shm_idx = shm_idx_counter++; + while (fsync->shm_idx * 8 >= shm_size) + { + /* Better expand the shm section. */ + shm_size += pagesize; + if (ftruncate( shm_fd, shm_size ) == -1) + { + fprintf( stderr, "fsync: couldn't expand %s to size %ld: ", + shm_name, shm_size ); + perror( "ftruncate" ); + } + } + + /* Initialize the shared memory portion. We want to do this on the + * server side to avoid a potential though unlikely race whereby + * the same object is opened and used between the time it's created + * and the time its shared memory portion is initialized. */ + + shm = get_shm( fsync->shm_idx ); + assert(shm); + shm[0] = low; + shm[1] = high; + } + } + + return fsync; +#else + set_error( STATUS_NOT_IMPLEMENTED ); + return NULL; +#endif +} + +DECL_HANDLER(create_fsync) +{ + struct fsync *fsync; + struct unicode_str name; + struct object *root; + const struct security_descriptor *sd; + const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root ); + + if (!do_fsync()) + { + set_error( STATUS_NOT_IMPLEMENTED ); + return; + } + + if (!objattr) return; + + if ((fsync = create_fsync( root, &name, objattr->attributes, req->low, + req->high, sd ))) + { + if (get_error() == STATUS_OBJECT_NAME_EXISTS) + reply->handle = alloc_handle( current->process, fsync, req->access, objattr->attributes ); + else + reply->handle = alloc_handle_no_access_check( current->process, fsync, + req->access, objattr->attributes ); + + reply->shm_idx = fsync->shm_idx; + release_object( fsync ); + } + + if (root) release_object( root ); +} diff --git a/server/fsync.h b/server/fsync.h new file mode 100644 index 00000000000..0b7e46cdaf3 --- /dev/null +++ b/server/fsync.h @@ -0,0 +1,22 @@ +/* + * futex-based synchronization objects + * + * Copyright (C) 2018 Zebediah Figura + * + * 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 + */ + +extern int do_fsync(void); +extern void fsync_init(void); diff --git a/server/main.c b/server/main.c index 7c635677205..db195201419 100644 --- a/server/main.c +++ b/server/main.c @@ -35,6 +35,7 @@ #include "request.h" #include "unicode.h" #include "esync.h" +#include "fsync.h" /* command-line options */ int debug_level = 0; @@ -230,6 +231,9 @@ int main( int argc, char *argv[] ) sock_init(); open_master_socket(); + if (do_fsync()) + fsync_init(); + if (do_esync()) esync_init(); diff --git a/server/protocol.def b/server/protocol.def index ffba1f437cf..fbf1ccc239d 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3893,3 +3893,14 @@ enum esync_type /* Retrieve the fd to wait on for user APCs. */ @REQ(get_esync_apc_fd) @END + +/* Create a new futex-based synchronization object */ +@REQ(create_fsync) + unsigned int access; /* wanted access rights */ + int low; /* initial value of low word */ + int high; /* initial value of high word */ + VARARG(objattr,object_attributes); /* object attributes */ +@REPLY + obj_handle_t handle; /* handle to the object */ + unsigned int shm_idx; /* this object's index into the shm section */ +@END From 76f2a226b889e3ce6a13282afa103b7cc4ecadc5 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 19:14:24 -0500 Subject: [PATCH 0402/2777] ntdll: Create futex-based objects for semaphores. --- dlls/ntdll/Makefile.in | 1 + dlls/ntdll/unix/fsync.c | 288 +++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/fsync.h | 25 ++++ dlls/ntdll/unix/loader.c | 2 + dlls/ntdll/unix/sync.c | 4 + 5 files changed, 320 insertions(+) create mode 100644 dlls/ntdll/unix/fsync.c create mode 100644 dlls/ntdll/unix/fsync.h diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index 03eb40d9fec..17f16adff1e 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -50,6 +50,7 @@ C_SRCS = \ unix/env.c \ unix/esync.c \ unix/file.c \ + unix/fsync.c \ unix/loader.c \ unix/loadorder.c \ unix/process.c \ diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c new file mode 100644 index 00000000000..24bd7f3ce34 --- /dev/null +++ b/dlls/ntdll/unix/fsync.c @@ -0,0 +1,288 @@ +/* + * futex-based synchronization objects + * + * Copyright (C) 2018 Zebediah Figura + * + * 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 + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef HAVE_SYS_SYSCALL_H +# include +#endif +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#define NONAMELESSUNION +#include "windef.h" +#include "winternl.h" +#include "wine/debug.h" +#include "wine/server.h" + +#include "unix_private.h" +#include "fsync.h" + +WINE_DEFAULT_DEBUG_CHANNEL(fsync); + +#include "pshpack4.h" +struct futex_wait_block +{ + int *addr; +#if __SIZEOF_POINTER__ == 4 + int pad; +#endif + int val; +}; +#include "poppack.h" + +static inline int futex_wait_multiple( const struct futex_wait_block *futexes, + int count, const struct timespec *timeout ) +{ + return syscall( __NR_futex, futexes, 13, count, timeout, 0, 0 ); +} + +int do_fsync(void) +{ +#ifdef __linux__ + static int do_fsync_cached = -1; + + if (do_fsync_cached == -1) + { + static const struct timespec zero; + futex_wait_multiple( NULL, 0, &zero ); + do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; + } + + return do_fsync_cached; +#else + static int once; + if (!once++) + FIXME("futexes not supported on this platform.\n"); + return 0; +#endif +} + +enum fsync_type +{ + FSYNC_SEMAPHORE = 1, +}; + +struct fsync +{ + enum fsync_type type; + void *shm; /* pointer to shm section */ +}; + +struct semaphore +{ + int count; + int max; +}; +C_ASSERT(sizeof(struct semaphore) == 8); + + +static char shm_name[29]; +static int shm_fd; +static void **shm_addrs; +static int shm_addrs_size; /* length of the allocated shm_addrs array */ +static long pagesize; + +static void *get_shm( unsigned int idx ) +{ + int entry = (idx * 8) / pagesize; + int offset = (idx * 8) % pagesize; + + if (entry >= shm_addrs_size) + { + int new_size = max(shm_addrs_size * 2, entry + 1); + + if (!(shm_addrs = realloc( shm_addrs, new_size * sizeof(shm_addrs[0]) ))) + ERR("Failed to grow shm_addrs array to size %d.\n", shm_addrs_size); + memset( shm_addrs + shm_addrs_size, 0, (new_size - shm_addrs_size) * sizeof(shm_addrs[0]) ); + shm_addrs_size = new_size; + } + + if (!shm_addrs[entry]) + { + void *addr = mmap( NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, entry * pagesize ); + if (addr == (void *)-1) + ERR("Failed to map page %d (offset %#lx).\n", entry, entry * pagesize); + + TRACE("Mapping page %d at %p.\n", entry, addr); + + if (__sync_val_compare_and_swap( &shm_addrs[entry], 0, addr )) + munmap( addr, pagesize ); /* someone beat us to it */ + } + + return (void *)((unsigned long)shm_addrs[entry] + offset); +} + +/* We'd like lookup to be fast. To that end, we use a static list indexed by handle. + * This is copied and adapted from the fd cache code. */ + +#define FSYNC_LIST_BLOCK_SIZE (65536 / sizeof(struct fsync)) +#define FSYNC_LIST_ENTRIES 256 + +static struct fsync *fsync_list[FSYNC_LIST_ENTRIES]; +static struct fsync fsync_list_initial_block[FSYNC_LIST_BLOCK_SIZE]; + +static inline UINT_PTR handle_to_index( HANDLE handle, UINT_PTR *entry ) +{ + UINT_PTR idx = (((UINT_PTR)handle) >> 2) - 1; + *entry = idx / FSYNC_LIST_BLOCK_SIZE; + return idx % FSYNC_LIST_BLOCK_SIZE; +} + +static struct fsync *add_to_list( HANDLE handle, enum fsync_type type, void *shm ) +{ + UINT_PTR entry, idx = handle_to_index( handle, &entry ); + + if (entry >= FSYNC_LIST_ENTRIES) + { + FIXME( "too many allocated handles, not caching %p\n", handle ); + return FALSE; + } + + if (!fsync_list[entry]) /* do we need to allocate a new block of entries? */ + { + if (!entry) fsync_list[0] = fsync_list_initial_block; + else + { + void *ptr = anon_mmap_alloc( FSYNC_LIST_BLOCK_SIZE * sizeof(struct fsync), + PROT_READ | PROT_WRITE ); + if (ptr == MAP_FAILED) return FALSE; + fsync_list[entry] = ptr; + } + } + + if (!__sync_val_compare_and_swap((int *)&fsync_list[entry][idx].type, 0, type )) + fsync_list[entry][idx].shm = shm; + + return &fsync_list[entry][idx]; +} + +static struct fsync *get_cached_object( HANDLE handle ) +{ + UINT_PTR entry, idx = handle_to_index( handle, &entry ); + + if (entry >= FSYNC_LIST_ENTRIES || !fsync_list[entry]) return NULL; + if (!fsync_list[entry][idx].type) return NULL; + + return &fsync_list[entry][idx]; +} + +static NTSTATUS create_fsync( enum fsync_type type, HANDLE *handle, + ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, int low, int high ) +{ + NTSTATUS ret; + data_size_t len; + struct object_attributes *objattr; + unsigned int shm_idx; + + if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; + + SERVER_START_REQ( create_fsync ) + { + req->access = access; + req->low = low; + req->high = high; + wine_server_add_data( req, objattr, len ); + ret = wine_server_call( req ); + if (!ret || ret == STATUS_OBJECT_NAME_EXISTS) + { + *handle = wine_server_ptr_handle( reply->handle ); + shm_idx = reply->shm_idx; + } + } + SERVER_END_REQ; + + if (!ret || ret == STATUS_OBJECT_NAME_EXISTS) + { + add_to_list( *handle, type, get_shm( shm_idx )); + TRACE("-> handle %p, shm index %d.\n", *handle, shm_idx); + } + + free( objattr ); + return ret; +} + +void fsync_init(void) +{ + struct stat st; + + if (!do_fsync()) + { + /* make sure the server isn't running with WINEFSYNC */ + HANDLE handle; + NTSTATUS ret; + + ret = create_fsync( 0, &handle, 0, NULL, 0, 0 ); + if (ret != STATUS_NOT_IMPLEMENTED) + { + ERR("Server is running with WINEFSYNC but this process is not, please enable WINEFSYNC or restart wineserver.\n"); + exit(1); + } + + return; + } + + if (stat( config_dir, &st ) == -1) + ERR("Cannot stat %s\n", config_dir); + + if (st.st_ino != (unsigned long)st.st_ino) + sprintf( shm_name, "/wine-%lx%08lx-fsync", (unsigned long)((unsigned long long)st.st_ino >> 32), (unsigned long)st.st_ino ); + else + sprintf( shm_name, "/wine-%lx-fsync", (unsigned long)st.st_ino ); + + if ((shm_fd = shm_open( shm_name, O_RDWR, 0644 )) == -1) + { + /* probably the server isn't running with WINEFSYNC, tell the user and bail */ + if (errno == ENOENT) + ERR("Failed to open fsync shared memory file; make sure no stale wineserver instances are running without WINEFSYNC.\n"); + else + ERR("Failed to initialize shared memory: %s\n", strerror( errno )); + exit(1); + } + + pagesize = sysconf( _SC_PAGESIZE ); + + shm_addrs = calloc( 128, sizeof(shm_addrs[0]) ); + shm_addrs_size = 128; +} + +NTSTATUS fsync_create_semaphore( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max ) +{ + TRACE("name %s, initial %d, max %d.\n", + attr ? debugstr_us(attr->ObjectName) : "", (int)initial, (int)max); + + return create_fsync( FSYNC_SEMAPHORE, handle, access, attr, initial, max ); +} diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h new file mode 100644 index 00000000000..0e7828f3fed --- /dev/null +++ b/dlls/ntdll/unix/fsync.h @@ -0,0 +1,25 @@ +/* + * futex-based synchronization objects + * + * Copyright (C) 2018 Zebediah Figura + * + * 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 + */ + +extern int do_fsync(void) DECLSPEC_HIDDEN; +extern void fsync_init(void) DECLSPEC_HIDDEN; + +extern NTSTATUS fsync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 55d36eaec4f..c218774be3d 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -90,6 +90,7 @@ #include "winternl.h" #include "unix_private.h" #include "esync.h" +#include "fsync.h" #include "wine/list.h" #include "wine/debug.h" @@ -2208,6 +2209,7 @@ static void start_main_thread(void) signal_alloc_thread( teb ); dbg_init(); startup_info_size = server_init_process(); + fsync_init(); esync_init(); virtual_map_user_shared_data(); init_cpu_info(); diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 84b217293db..18b365fbce4 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -65,6 +65,7 @@ #include "wine/debug.h" #include "unix_private.h" #include "esync.h" +#include "fsync.h" WINE_DEFAULT_DEBUG_CHANNEL(sync); @@ -274,6 +275,9 @@ NTSTATUS WINAPI NtCreateSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJ if (max <= 0 || initial < 0 || initial > max) return STATUS_INVALID_PARAMETER; if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; + if (do_fsync()) + return fsync_create_semaphore( handle, access, attr, initial, max ); + if (do_esync()) return esync_create_semaphore( handle, access, attr, initial, max ); From 18de6cf5c0aae8f23fe21ab08be25c17527db4a1 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 19:21:55 -0500 Subject: [PATCH 0403/2777] ntdll: Implement NtReleaseSemaphore(). --- dlls/ntdll/unix/fsync.c | 31 +++++++++++++++++++++++++++++++ dlls/ntdll/unix/fsync.h | 1 + dlls/ntdll/unix/sync.c | 3 +++ server/esync.c | 1 + 4 files changed, 36 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 24bd7f3ce34..d7f09f2da05 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -69,6 +69,11 @@ static inline int futex_wait_multiple( const struct futex_wait_block *futexes, return syscall( __NR_futex, futexes, 13, count, timeout, 0, 0 ); } +static inline int futex_wake( int *addr, int val ) +{ + return syscall( __NR_futex, addr, 1, val, NULL, 0, 0 ); +} + int do_fsync(void) { #ifdef __linux__ @@ -286,3 +291,29 @@ NTSTATUS fsync_create_semaphore( HANDLE *handle, ACCESS_MASK access, return create_fsync( FSYNC_SEMAPHORE, handle, access, attr, initial, max ); } + +NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) +{ + struct fsync *obj; + struct semaphore *semaphore; + ULONG current; + + TRACE("%p, %d, %p.\n", handle, (int)count, prev); + + if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; + semaphore = obj->shm; + + do + { + current = semaphore->count; + if (count + current > semaphore->max) + return STATUS_SEMAPHORE_LIMIT_EXCEEDED; + } while (__sync_val_compare_and_swap( &semaphore->count, current, count + current ) != current); + + if (prev) *prev = current; + + if (!current) + futex_wake( &semaphore->count, count ); + + return STATUS_SUCCESS; +} diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h index 0e7828f3fed..5a1e202749e 100644 --- a/dlls/ntdll/unix/fsync.h +++ b/dlls/ntdll/unix/fsync.h @@ -23,3 +23,4 @@ extern void fsync_init(void) DECLSPEC_HIDDEN; extern NTSTATUS fsync_create_semaphore(HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN; +extern NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 18b365fbce4..784473b5c56 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -370,6 +370,9 @@ NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, ULONG *previous { unsigned int ret; + if (do_fsync()) + return fsync_release_semaphore( handle, count, previous ); + if (do_esync()) return esync_release_semaphore( handle, count, previous ); diff --git a/server/esync.c b/server/esync.c index e193f61b3a7..fc8120f9449 100644 --- a/server/esync.c +++ b/server/esync.c @@ -23,6 +23,7 @@ #include #include +#include #include #ifdef HAVE_SYS_EVENTFD_H # include From 8722a2c69282b6e6eb0ccf7fa4c89c551c56e17d Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 15:50:37 -0500 Subject: [PATCH 0404/2777] ntdll: Close fsync objects. --- dlls/ntdll/unix/fsync.c | 15 +++++++++++++++ dlls/ntdll/unix/fsync.h | 1 + dlls/ntdll/unix/server.c | 4 ++++ 3 files changed, 20 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index d7f09f2da05..7a8a204972c 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -204,6 +204,21 @@ static struct fsync *get_cached_object( HANDLE handle ) return &fsync_list[entry][idx]; } +NTSTATUS fsync_close( HANDLE handle ) +{ + UINT_PTR entry, idx = handle_to_index( handle, &entry ); + + TRACE("%p.\n", handle); + + if (entry < FSYNC_LIST_ENTRIES && fsync_list[entry]) + { + if (__atomic_exchange_n( &fsync_list[entry][idx].type, 0, __ATOMIC_SEQ_CST )) + return STATUS_SUCCESS; + } + + return STATUS_INVALID_HANDLE; +} + static NTSTATUS create_fsync( enum fsync_type type, HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, int low, int high ) { diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h index 5a1e202749e..fc730e5124f 100644 --- a/dlls/ntdll/unix/fsync.h +++ b/dlls/ntdll/unix/fsync.h @@ -20,6 +20,7 @@ extern int do_fsync(void) DECLSPEC_HIDDEN; extern void fsync_init(void) DECLSPEC_HIDDEN; +extern NTSTATUS fsync_close( HANDLE handle ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_create_semaphore(HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 321b91d20e0..4ed6d8496b0 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -83,6 +83,7 @@ #include "wine/debug.h" #include "unix_private.h" #include "esync.h" +#include "fsync.h" #include "ddk/wdm.h" WINE_DEFAULT_DEBUG_CHANNEL(server); @@ -1759,6 +1760,9 @@ NTSTATUS WINAPI NtClose( HANDLE handle ) * retrieve it again */ fd = remove_fd_from_cache( handle ); + if (do_fsync()) + fsync_close( handle ); + if (do_esync()) esync_close( handle ); From 71f017c740d02f66d5f95a60ac4a19dcf9c28497 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 16:25:59 -0500 Subject: [PATCH 0405/2777] ntdll: Implement waiting on fsync objects. --- dlls/ntdll/unix/fsync.c | 145 ++++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/fsync.h | 3 + dlls/ntdll/unix/sync.c | 7 ++ 3 files changed, 155 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 7a8a204972c..da043b1291b 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -332,3 +332,148 @@ NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) return STATUS_SUCCESS; } + +static LONGLONG update_timeout( ULONGLONG end ) +{ + LARGE_INTEGER now; + LONGLONG timeleft; + + NtQuerySystemTime( &now ); + timeleft = end - now.QuadPart; + if (timeleft < 0) timeleft = 0; + return timeleft; +} + +NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, + BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) +{ + struct futex_wait_block futexes[MAXIMUM_WAIT_OBJECTS]; + struct fsync *objs[MAXIMUM_WAIT_OBJECTS]; + int has_fsync = 0, has_server = 0; + int dummy_futex = 0; + LONGLONG timeleft; + LARGE_INTEGER now; + ULONGLONG end; + int i, ret; + + NtQuerySystemTime( &now ); + if (timeout) + { + if (timeout->QuadPart == TIMEOUT_INFINITE) + timeout = NULL; + else if (timeout->QuadPart > 0) + end = timeout->QuadPart; + else + end = now.QuadPart - timeout->QuadPart; + } + + for (i = 0; i < count; i++) + { + if ((objs[i] = get_cached_object( handles[i] ))) + has_fsync = 1; + else + has_server = 1; + } + + if (has_fsync && has_server) + FIXME("Can't wait on fsync and server objects at the same time!\n"); + else if (has_server) + return STATUS_NOT_IMPLEMENTED; + + if (TRACE_ON(fsync)) + { + TRACE("Waiting for %s of %d handles:", wait_any ? "any" : "all", (int)count); + for (i = 0; i < count; i++) + TRACE(" %p", handles[i]); + + if (!timeout) + TRACE(", timeout = INFINITE.\n"); + else + { + timeleft = update_timeout( end ); + TRACE(", timeout = %ld.%07ld sec.\n", + (long) (timeleft / TICKSPERSEC), (long) (timeleft % TICKSPERSEC)); + } + } + + if (wait_any || count == 1) + { + while (1) + { + /* Try to grab anything. */ + + for (i = 0; i < count; i++) + { + struct fsync *obj = objs[i]; + + if (obj) + { + switch (obj->type) + { + case FSYNC_SEMAPHORE: + { + struct semaphore *semaphore = obj->shm; + int current; + + do + { + if (!(current = semaphore->count)) break; + } while (__sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) != current); + + if (current) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + return i; + } + + futexes[i].addr = &semaphore->count; + futexes[i].val = current; + break; + } + default: + assert(0); + } + } + else + { + /* Avoid breaking things entirely. */ + futexes[i].addr = &dummy_futex; + futexes[i].val = dummy_futex; + } + +#if __SIZEOF_POINTER__ == 4 + futexes[i].pad = 0; +#endif + } + + /* Looks like everything is contended, so wait. */ + + if (timeout) + { + LONGLONG timeleft = update_timeout( end ); + struct timespec tmo_p; + tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; + tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; + + ret = futex_wait_multiple( futexes, count, &tmo_p ); + } + else + ret = futex_wait_multiple( futexes, count, NULL ); + + /* FUTEX_WAIT_MULTIPLE can succeed or return -EINTR, -EAGAIN, + * -EFAULT/-EACCES, -ETIMEDOUT. In the first three cases we need to + * try again, bad address is already handled by the fact that we + * tried to read from it, so only break out on a timeout. */ + if (ret == -1 && errno == ETIMEDOUT) + { + TRACE("Wait timed out.\n"); + return STATUS_TIMEOUT; + } + } /* while (1) */ + } + else + { + FIXME("Wait-all not implemented.\n"); + return STATUS_NOT_IMPLEMENTED; + } +} diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h index fc730e5124f..f43fac2f943 100644 --- a/dlls/ntdll/unix/fsync.h +++ b/dlls/ntdll/unix/fsync.h @@ -25,3 +25,6 @@ extern NTSTATUS fsync_close( HANDLE handle ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_create_semaphore(HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN; extern NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) DECLSPEC_HIDDEN; + +extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 784473b5c56..6ad4ab8d1e7 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -1477,6 +1477,13 @@ NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles, BO if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1; + if (do_fsync()) + { + NTSTATUS ret = fsync_wait_objects( count, handles, wait_any, alertable, timeout ); + if (ret != STATUS_NOT_IMPLEMENTED) + return ret; + } + if (do_esync()) { NTSTATUS ret = esync_wait_objects( count, handles, wait_any, alertable, timeout ); From 9733a8a6198fba0b844ec9822095e5ba2e379116 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 16:31:54 -0500 Subject: [PATCH 0406/2777] ntdll: Create fsync objects for events. --- dlls/ntdll/unix/fsync.c | 20 ++++++++++++++++++++ dlls/ntdll/unix/fsync.h | 2 ++ dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 25 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index da043b1291b..ab50b65dfbe 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -98,6 +98,8 @@ int do_fsync(void) enum fsync_type { FSYNC_SEMAPHORE = 1, + FSYNC_AUTO_EVENT, + FSYNC_MANUAL_EVENT, }; struct fsync @@ -113,6 +115,12 @@ struct semaphore }; C_ASSERT(sizeof(struct semaphore) == 8); +struct event +{ + int signaled; + int unused; +}; +C_ASSERT(sizeof(struct event) == 8); static char shm_name[29]; static int shm_fd; @@ -333,6 +341,18 @@ NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) return STATUS_SUCCESS; } +NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, EVENT_TYPE event_type, BOOLEAN initial ) +{ + enum fsync_type type = (event_type == SynchronizationEvent ? FSYNC_AUTO_EVENT : FSYNC_MANUAL_EVENT); + + TRACE("name %s, %s-reset, initial %d.\n", + attr ? debugstr_us(attr->ObjectName) : "", + event_type == NotificationEvent ? "manual" : "auto", initial); + + return create_fsync( type, handle, access, attr, initial, 0xdeadbeef ); +} + static LONGLONG update_timeout( ULONGLONG end ) { LARGE_INTEGER now; diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h index f43fac2f943..eb00a62384e 100644 --- a/dlls/ntdll/unix/fsync.h +++ b/dlls/ntdll/unix/fsync.h @@ -25,6 +25,8 @@ extern NTSTATUS fsync_close( HANDLE handle ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_create_semaphore(HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN; extern NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) DECLSPEC_HIDDEN; +extern NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 6ad4ab8d1e7..5462570c68e 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -403,6 +403,9 @@ NTSTATUS WINAPI NtCreateEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ *handle = 0; if (type != NotificationEvent && type != SynchronizationEvent) return STATUS_INVALID_PARAMETER; + if (do_fsync()) + return fsync_create_event( handle, access, attr, type, state ); + if (do_esync()) return esync_create_event( handle, access, attr, type, state ); From d0a38ed602cfdd31f03459f3efa0dda90b394c45 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 16:36:16 -0500 Subject: [PATCH 0407/2777] ntdll: Implement NtSetEvent(). --- dlls/ntdll/unix/fsync.c | 20 ++++++++++++++++++++ dlls/ntdll/unix/fsync.h | 1 + dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 24 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index ab50b65dfbe..f1c47a8473a 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -353,6 +354,25 @@ NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, return create_fsync( type, handle, access, attr, initial, 0xdeadbeef ); } +NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) +{ + struct event *event; + struct fsync *obj; + LONG current; + + TRACE("%p.\n", handle); + + if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; + event = obj->shm; + + if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))) + futex_wake( &event->signaled, obj->type == FSYNC_AUTO_EVENT ? 1 : INT_MAX ); + + if (prev) *prev = current; + + return STATUS_SUCCESS; +} + static LONGLONG update_timeout( ULONGLONG end ) { LARGE_INTEGER now; diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h index eb00a62384e..77d1815ef9c 100644 --- a/dlls/ntdll/unix/fsync.h +++ b/dlls/ntdll/unix/fsync.h @@ -27,6 +27,7 @@ extern NTSTATUS fsync_create_semaphore(HANDLE *handle, ACCESS_MASK access, extern NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN; +extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 5462570c68e..c1dc282c7fa 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -463,6 +463,9 @@ NTSTATUS WINAPI NtSetEvent( HANDLE handle, LONG *prev_state ) /* This comment is a dummy to make sure this patch applies in the right place. */ unsigned int ret; + if (do_fsync()) + return fsync_set_event( handle, prev_state ); + if (do_esync()) return esync_set_event( handle ); From adc1df4c259366c570e9538fe9313632fe334d38 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 16:39:38 -0500 Subject: [PATCH 0408/2777] ntdll: Implement NtResetEvent(). --- dlls/ntdll/unix/fsync.c | 18 ++++++++++++++++++ dlls/ntdll/unix/fsync.h | 1 + dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 22 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index f1c47a8473a..35028aba0fd 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -373,6 +373,24 @@ NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) return STATUS_SUCCESS; } +NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) +{ + struct event *event; + struct fsync *obj; + LONG current; + + TRACE("%p.\n", handle); + + if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; + event = obj->shm; + + current = __atomic_exchange_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); + + if (prev) *prev = current; + + return STATUS_SUCCESS; +} + static LONGLONG update_timeout( ULONGLONG end ) { LARGE_INTEGER now; diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h index 77d1815ef9c..76addff0e4d 100644 --- a/dlls/ntdll/unix/fsync.h +++ b/dlls/ntdll/unix/fsync.h @@ -28,6 +28,7 @@ extern NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev extern NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; +extern NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index c1dc282c7fa..578568ee105 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -489,6 +489,9 @@ NTSTATUS WINAPI NtResetEvent( HANDLE handle, LONG *prev_state ) /* This comment is a dummy to make sure this patch applies in the right place. */ unsigned int ret; + if (do_fsync()) + return fsync_reset_event( handle, prev_state ); + if (do_esync()) return esync_reset_event( handle ); From 97eb924e28ecb1e3fe64aa9a86e40c5e830f2065 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 16:45:43 -0500 Subject: [PATCH 0409/2777] ntdll: Implement waiting on events. --- dlls/ntdll/unix/fsync.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 35028aba0fd..1f9597ca1b2 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -488,6 +488,34 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, futexes[i].val = current; break; } + case FSYNC_AUTO_EVENT: + { + struct event *event = obj->shm; + + if (__sync_val_compare_and_swap( &event->signaled, 1, 0 )) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + return i; + } + + futexes[i].addr = &event->signaled; + futexes[i].val = 0; + break; + } + case FSYNC_MANUAL_EVENT: + { + struct event *event = obj->shm; + + if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + return i; + } + + futexes[i].addr = &event->signaled; + futexes[i].val = 0; + break; + } default: assert(0); } From 18bc240c7773ee3ae2fe5fd8947aacc4f2d0ce6f Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 16:52:01 -0500 Subject: [PATCH 0410/2777] server: Add an object operation to grab the fsync shm index. --- server/async.c | 2 ++ server/atom.c | 1 + server/change.c | 1 + server/clipboard.c | 1 + server/completion.c | 1 + server/console.c | 7 +++++++ server/debugger.c | 2 ++ server/device.c | 4 ++++ server/directory.c | 2 ++ server/esync.c | 1 + server/event.c | 2 ++ server/fd.c | 4 ++++ server/file.c | 1 + server/fsync.c | 1 + server/handle.c | 1 + server/hook.c | 1 + server/mailslot.c | 4 ++++ server/mapping.c | 3 +++ server/mutex.c | 1 + server/named_pipe.c | 5 +++++ server/object.h | 2 ++ server/process.c | 3 +++ server/queue.c | 2 ++ server/registry.c | 1 + server/request.c | 1 + server/semaphore.c | 1 + server/serial.c | 1 + server/signal.c | 1 + server/sock.c | 3 +++ server/symlink.c | 1 + server/thread.c | 3 +++ server/timer.c | 1 + server/token.c | 1 + server/window.c | 1 + server/winstation.c | 2 ++ 35 files changed, 69 insertions(+) diff --git a/server/async.c b/server/async.c index 76352ba19ae..e246650ff3f 100644 --- a/server/async.c +++ b/server/async.c @@ -78,6 +78,7 @@ static const struct object_ops async_ops = remove_queue, /* remove_queue */ async_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ async_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -656,6 +657,7 @@ static const struct object_ops iosb_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/atom.c b/server/atom.c index d9824de8eac..6b95a546597 100644 --- a/server/atom.c +++ b/server/atom.c @@ -80,6 +80,7 @@ static const struct object_ops atom_table_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/change.c b/server/change.c index 5e9d94720a5..72b4232cd41 100644 --- a/server/change.c +++ b/server/change.c @@ -113,6 +113,7 @@ static const struct object_ops dir_ops = remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ default_fd_get_esync_fd, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ dir_get_fd, /* get_fd */ diff --git a/server/clipboard.c b/server/clipboard.c index 8b265f2dcea..f24924eafa5 100644 --- a/server/clipboard.c +++ b/server/clipboard.c @@ -77,6 +77,7 @@ static const struct object_ops clipboard_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/completion.c b/server/completion.c index 3d4be86a212..33266c596da 100644 --- a/server/completion.c +++ b/server/completion.c @@ -76,6 +76,7 @@ static const struct object_ops completion_ops = remove_queue, /* remove_queue */ completion_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/console.c b/server/console.c index 3f9c0ce356c..8279ad468e1 100644 --- a/server/console.c +++ b/server/console.c @@ -83,6 +83,7 @@ static const struct object_ops console_ops = remove_queue, /* remove_queue */ console_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ console_get_fd, /* get_fd */ @@ -163,6 +164,7 @@ static const struct object_ops console_server_ops = remove_queue, /* remove_queue */ console_server_signaled, /* signaled */ console_server_get_esync_fd, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ console_server_get_fd, /* get_fd */ @@ -233,6 +235,7 @@ static const struct object_ops screen_buffer_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ screen_buffer_get_fd, /* get_fd */ @@ -283,6 +286,7 @@ static const struct object_ops console_device_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -321,6 +325,7 @@ static const struct object_ops console_input_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ console_input_get_fd, /* get_fd */ @@ -379,6 +384,7 @@ static const struct object_ops console_output_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ console_output_get_fd, /* get_fd */ @@ -438,6 +444,7 @@ static const struct object_ops console_connection_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ console_connection_get_fd, /* get_fd */ diff --git a/server/debugger.c b/server/debugger.c index d85a2000684..b0cd35604d2 100644 --- a/server/debugger.c +++ b/server/debugger.c @@ -87,6 +87,7 @@ static const struct object_ops debug_event_ops = remove_queue, /* remove_queue */ debug_event_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -116,6 +117,7 @@ static const struct object_ops debug_obj_ops = remove_queue, /* remove_queue */ debug_obj_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/device.c b/server/device.c index c45d0102a56..8613cee58af 100644 --- a/server/device.c +++ b/server/device.c @@ -69,6 +69,7 @@ static const struct object_ops irp_call_ops = NULL, /* signaled */ NULL, /* get_esync_fd */ NULL, /* satisfied */ + NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ default_map_access, /* map_access */ @@ -111,6 +112,7 @@ static const struct object_ops device_manager_ops = remove_queue, /* remove_queue */ device_manager_signaled, /* signaled */ device_manager_get_esync_fd, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -169,6 +171,7 @@ static const struct object_ops device_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -222,6 +225,7 @@ static const struct object_ops device_file_ops = remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ device_file_get_fd, /* get_fd */ diff --git a/server/directory.c b/server/directory.c index dc3f0cf3cf8..878941cddbf 100644 --- a/server/directory.c +++ b/server/directory.c @@ -71,6 +71,7 @@ static const struct object_ops object_type_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -122,6 +123,7 @@ static const struct object_ops directory_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/esync.c b/server/esync.c index fc8120f9449..064bdd61b25 100644 --- a/server/esync.c +++ b/server/esync.c @@ -129,6 +129,7 @@ const struct object_ops esync_ops = NULL, /* remove_queue */ NULL, /* signaled */ esync_get_esync_fd, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/event.c b/server/event.c index f4ca3e48c6f..f5a25c02293 100644 --- a/server/event.c +++ b/server/event.c @@ -77,6 +77,7 @@ static const struct object_ops event_ops = remove_queue, /* remove_queue */ event_signaled, /* signaled */ event_get_esync_fd, /* get_esync_fd */ + NULL, /* get_fsync_idx */ event_satisfied, /* satisfied */ event_signal, /* signal */ no_get_fd, /* get_fd */ @@ -125,6 +126,7 @@ static const struct object_ops keyed_event_ops = remove_queue, /* remove_queue */ keyed_event_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/fd.c b/server/fd.c index 4d6206f073f..66f9bc01e34 100644 --- a/server/fd.c +++ b/server/fd.c @@ -209,6 +209,7 @@ static const struct object_ops fd_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -251,6 +252,7 @@ static const struct object_ops device_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -292,6 +294,7 @@ static const struct object_ops inode_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -335,6 +338,7 @@ static const struct object_ops file_lock_ops = remove_queue, /* remove_queue */ file_lock_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/file.c b/server/file.c index 26c62809d33..5be9578ce48 100644 --- a/server/file.c +++ b/server/file.c @@ -95,6 +95,7 @@ static const struct object_ops file_ops = remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ file_get_fd, /* get_fd */ diff --git a/server/fsync.c b/server/fsync.c index ce538f1a49c..fc098ccea93 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -140,6 +140,7 @@ static const struct object_ops fsync_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/handle.c b/server/handle.c index 53cc1e4eb43..71b23093f62 100644 --- a/server/handle.c +++ b/server/handle.c @@ -127,6 +127,7 @@ static const struct object_ops handle_table_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/hook.c b/server/hook.c index 95a588c843b..3a89a883c3c 100644 --- a/server/hook.c +++ b/server/hook.c @@ -81,6 +81,7 @@ static const struct object_ops hook_table_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/mailslot.c b/server/mailslot.c index 4cf9b73f784..41fb020aaf0 100644 --- a/server/mailslot.c +++ b/server/mailslot.c @@ -75,6 +75,7 @@ static const struct object_ops mailslot_ops = remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ mailslot_get_fd, /* get_fd */ @@ -135,6 +136,7 @@ static const struct object_ops mail_writer_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ mail_writer_get_fd, /* get_fd */ @@ -199,6 +201,7 @@ static const struct object_ops mailslot_device_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -230,6 +233,7 @@ static const struct object_ops mailslot_device_file_ops = remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ mailslot_device_file_get_fd, /* get_fd */ diff --git a/server/mapping.c b/server/mapping.c index 1468b05e260..4c90673a5c5 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -69,6 +69,7 @@ static const struct object_ops ranges_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -106,6 +107,7 @@ static const struct object_ops shared_map_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -181,6 +183,7 @@ static const struct object_ops mapping_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ mapping_get_fd, /* get_fd */ diff --git a/server/mutex.c b/server/mutex.c index 4785a830e92..2503d12057f 100644 --- a/server/mutex.c +++ b/server/mutex.c @@ -74,6 +74,7 @@ static const struct object_ops mutex_ops = remove_queue, /* remove_queue */ mutex_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ mutex_satisfied, /* satisfied */ mutex_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/named_pipe.c b/server/named_pipe.c index e01b28f725a..b6169062781 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -120,6 +120,7 @@ static const struct object_ops named_pipe_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -169,6 +170,7 @@ static const struct object_ops pipe_server_ops = remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ default_fd_get_esync_fd, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ pipe_end_get_fd, /* get_fd */ @@ -214,6 +216,7 @@ static const struct object_ops pipe_client_ops = remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ default_fd_get_esync_fd, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ pipe_end_get_fd, /* get_fd */ @@ -262,6 +265,7 @@ static const struct object_ops named_pipe_device_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -294,6 +298,7 @@ static const struct object_ops named_pipe_device_file_ops = remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ named_pipe_device_file_get_fd, /* get_fd */ diff --git a/server/object.h b/server/object.h index 86906942b77..b188ebe784a 100644 --- a/server/object.h +++ b/server/object.h @@ -80,6 +80,8 @@ struct object_ops int (*signaled)(struct object *,struct wait_queue_entry *); /* return the esync fd for this object */ int (*get_esync_fd)(struct object *, enum esync_type *type); + /* return the fsync shm idx for this object */ + unsigned int (*get_fsync_idx)(struct object *); /* wait satisfied */ void (*satisfied)(struct object *,struct wait_queue_entry *); /* signal an object */ diff --git a/server/process.c b/server/process.c index 899d8568a6a..b50d5cd05da 100644 --- a/server/process.c +++ b/server/process.c @@ -108,6 +108,7 @@ static const struct object_ops process_ops = remove_queue, /* remove_queue */ process_signaled, /* signaled */ process_get_esync_fd, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -160,6 +161,7 @@ static const struct object_ops startup_info_ops = remove_queue, /* remove_queue */ startup_info_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -222,6 +224,7 @@ static const struct object_ops job_ops = remove_queue, /* remove_queue */ job_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/queue.c b/server/queue.c index 585fe42a29b..8221357e73e 100644 --- a/server/queue.c +++ b/server/queue.c @@ -170,6 +170,7 @@ static const struct object_ops msg_queue_ops = msg_queue_remove_queue, /* remove_queue */ msg_queue_signaled, /* signaled */ msg_queue_get_esync_fd, /* get_esync_fd */ + NULL, /* get_fsync_idx */ msg_queue_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -208,6 +209,7 @@ static const struct object_ops thread_input_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/registry.c b/server/registry.c index 10f9cd0b69f..b7761802f46 100644 --- a/server/registry.c +++ b/server/registry.c @@ -181,6 +181,7 @@ static const struct object_ops key_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/request.c b/server/request.c index ca83fdbd2af..343e1a92e0e 100644 --- a/server/request.c +++ b/server/request.c @@ -91,6 +91,7 @@ static const struct object_ops master_socket_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/semaphore.c b/server/semaphore.c index e3889f24601..d354892c224 100644 --- a/server/semaphore.c +++ b/server/semaphore.c @@ -71,6 +71,7 @@ static const struct object_ops semaphore_ops = remove_queue, /* remove_queue */ semaphore_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ semaphore_satisfied, /* satisfied */ semaphore_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/serial.c b/server/serial.c index 11e204e4419..1915d00a977 100644 --- a/server/serial.c +++ b/server/serial.c @@ -86,6 +86,7 @@ static const struct object_ops serial_ops = remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ serial_get_fd, /* get_fd */ diff --git a/server/signal.c b/server/signal.c index 55cd6aa037e..802b7f936b9 100644 --- a/server/signal.c +++ b/server/signal.c @@ -63,6 +63,7 @@ static const struct object_ops handler_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/sock.c b/server/sock.c index 2b1eda396e5..851723a9d03 100644 --- a/server/sock.c +++ b/server/sock.c @@ -446,6 +446,7 @@ static const struct object_ops sock_ops = remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ sock_get_fd, /* get_fd */ @@ -3467,6 +3468,7 @@ static const struct object_ops ifchange_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ ifchange_get_fd, /* get_fd */ @@ -3689,6 +3691,7 @@ static const struct object_ops socket_device_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/symlink.c b/server/symlink.c index 8cb24b4ff6e..cd954effa91 100644 --- a/server/symlink.c +++ b/server/symlink.c @@ -72,6 +72,7 @@ static const struct object_ops symlink_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/thread.c b/server/thread.c index 081a3389538..c3f7b8013f1 100644 --- a/server/thread.c +++ b/server/thread.c @@ -105,6 +105,7 @@ static const struct object_ops thread_apc_ops = remove_queue, /* remove_queue */ thread_apc_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -151,6 +152,7 @@ static const struct object_ops context_ops = remove_queue, /* remove_queue */ context_signaled, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -202,6 +204,7 @@ static const struct object_ops thread_ops = remove_queue, /* remove_queue */ thread_signaled, /* signaled */ thread_get_esync_fd, /* get_esync_fd */ + NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/timer.c b/server/timer.c index 36645a2a8d2..9ec9604aa0e 100644 --- a/server/timer.c +++ b/server/timer.c @@ -80,6 +80,7 @@ static const struct object_ops timer_ops = remove_queue, /* remove_queue */ timer_signaled, /* signaled */ timer_get_esync_fd, /* get_esync_fd */ + NULL, /* get_fsync_idx */ timer_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/token.c b/server/token.c index 5289a24e47b..f9ee2b61398 100644 --- a/server/token.c +++ b/server/token.c @@ -144,6 +144,7 @@ static const struct object_ops token_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/window.c b/server/window.c index bd427f24906..26eb52badc3 100644 --- a/server/window.c +++ b/server/window.c @@ -108,6 +108,7 @@ static const struct object_ops window_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/winstation.c b/server/winstation.c index 72073edc14e..2f009d5ea15 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -76,6 +76,7 @@ static const struct object_ops winstation_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -117,6 +118,7 @@ static const struct object_ops desktop_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ From 450bd4f091ef65611110caa515c8b2757baf9c4d Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 16:57:08 -0500 Subject: [PATCH 0411/2777] server: Add a request to get the shm index associated with a waitable handle. --- dlls/ntdll/unix/fsync.c | 7 ------- server/fsync.c | 28 ++++++++++++++++++++++++++++ server/object.h | 2 +- server/protocol.def | 16 ++++++++++++++++ 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 1f9597ca1b2..208a0539ca1 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -96,13 +96,6 @@ int do_fsync(void) #endif } -enum fsync_type -{ - FSYNC_SEMAPHORE = 1, - FSYNC_AUTO_EVENT, - FSYNC_MANUAL_EVENT, -}; - struct fsync { enum fsync_type type; diff --git a/server/fsync.c b/server/fsync.c index fc098ccea93..8403343fdd8 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -285,3 +285,31 @@ DECL_HANDLER(create_fsync) if (root) release_object( root ); } + + +/* Retrieve the index of a shm section which will be signaled by the server. */ +DECL_HANDLER(get_fsync_idx) +{ + struct object *obj; + enum fsync_type type; + + if (!(obj = get_handle_obj( current->process, req->handle, SYNCHRONIZE, NULL ))) + return; + + if (obj->ops->get_fsync_idx) + { + reply->shm_idx = obj->ops->get_fsync_idx( obj, &type ); + reply->type = type; + } + else + { + if (debug_level) + { + fprintf( stderr, "%04x: fsync: can't wait on object: ", current->id ); + obj->ops->dump( obj, 0 ); + } + set_error( STATUS_NOT_IMPLEMENTED ); + } + + release_object( obj ); +} diff --git a/server/object.h b/server/object.h index b188ebe784a..8bf236abb58 100644 --- a/server/object.h +++ b/server/object.h @@ -81,7 +81,7 @@ struct object_ops /* return the esync fd for this object */ int (*get_esync_fd)(struct object *, enum esync_type *type); /* return the fsync shm idx for this object */ - unsigned int (*get_fsync_idx)(struct object *); + unsigned int (*get_fsync_idx)(struct object *, enum fsync_type *type); /* wait satisfied */ void (*satisfied)(struct object *,struct wait_queue_entry *); /* signal an object */ diff --git a/server/protocol.def b/server/protocol.def index fbf1ccc239d..6af6bbf57b4 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3894,6 +3894,14 @@ enum esync_type @REQ(get_esync_apc_fd) @END +enum fsync_type +{ + FSYNC_SEMAPHORE = 1, + FSYNC_AUTO_EVENT, + FSYNC_MANUAL_EVENT, + FSYNC_MANUAL_SERVER, +}; + /* Create a new futex-based synchronization object */ @REQ(create_fsync) unsigned int access; /* wanted access rights */ @@ -3904,3 +3912,11 @@ enum esync_type obj_handle_t handle; /* handle to the object */ unsigned int shm_idx; /* this object's index into the shm section */ @END + +/* Retrieve the shm index for an object. */ +@REQ(get_fsync_idx) + obj_handle_t handle; /* handle to the object */ +@REPLY + int type; + unsigned int shm_idx; +@END From c2f07b33274f6600255368d17da9d182eba33c32 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 17:20:36 -0500 Subject: [PATCH 0412/2777] server: Create futex sections for process objects. --- server/fsync.c | 49 +++++++++++++++++++++++++++++------------------- server/fsync.h | 1 + server/process.c | 15 ++++++++++++++- server/process.h | 1 + 4 files changed, 46 insertions(+), 20 deletions(-) diff --git a/server/fsync.c b/server/fsync.c index 8403343fdd8..ae4dc7d7318 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -207,6 +207,35 @@ static void *get_shm( unsigned int idx ) /* FIXME: This is rather inefficient... */ static unsigned int shm_idx_counter = 1; +unsigned int fsync_alloc_shm( int low, int high ) +{ +#ifdef __linux__ + int shm_idx = shm_idx_counter++; + int *shm; + + while (shm_idx * 8 >= shm_size) + { + /* Better expand the shm section. */ + shm_size += pagesize; + if (ftruncate( shm_fd, shm_size ) == -1) + { + fprintf( stderr, "fsync: couldn't expand %s to size %jd: ", + shm_name, shm_size ); + perror( "ftruncate" ); + } + } + + shm = get_shm( shm_idx ); + assert(shm); + shm[0] = low; + shm[1] = high; + + return shm_idx; +#else + return 0; +#endif +} + struct fsync *create_fsync( struct object *root, const struct unicode_str *name, unsigned int attr, int low, int high, const struct security_descriptor *sd ) @@ -218,32 +247,14 @@ struct fsync *create_fsync( struct object *root, const struct unicode_str *name, { if (get_error() != STATUS_OBJECT_NAME_EXISTS) { - int *shm; - /* initialize it if it didn't already exist */ - fsync->shm_idx = shm_idx_counter++; - while (fsync->shm_idx * 8 >= shm_size) - { - /* Better expand the shm section. */ - shm_size += pagesize; - if (ftruncate( shm_fd, shm_size ) == -1) - { - fprintf( stderr, "fsync: couldn't expand %s to size %ld: ", - shm_name, shm_size ); - perror( "ftruncate" ); - } - } - /* Initialize the shared memory portion. We want to do this on the * server side to avoid a potential though unlikely race whereby * the same object is opened and used between the time it's created * and the time its shared memory portion is initialized. */ - shm = get_shm( fsync->shm_idx ); - assert(shm); - shm[0] = low; - shm[1] = high; + fsync->shm_idx = fsync_alloc_shm( low, high ); } } diff --git a/server/fsync.h b/server/fsync.h index 0b7e46cdaf3..bbd104f3e16 100644 --- a/server/fsync.h +++ b/server/fsync.h @@ -20,3 +20,4 @@ extern int do_fsync(void); extern void fsync_init(void); +extern unsigned int fsync_alloc_shm( int low, int high ); diff --git a/server/process.c b/server/process.c index b50d5cd05da..130ab0148e1 100644 --- a/server/process.c +++ b/server/process.c @@ -64,6 +64,7 @@ #include "user.h" #include "security.h" #include "esync.h" +#include "fsync.h" /* process object */ @@ -97,6 +98,7 @@ static void process_poll_event( struct fd *fd, int event ); static struct list *process_get_kernel_obj_list( struct object *obj ); static void process_destroy( struct object *obj ); static int process_get_esync_fd( struct object *obj, enum esync_type *type ); +static unsigned int process_get_fsync_idx( struct object *obj, enum fsync_type *type ); static void terminate_process( struct process *process, struct thread *skip, int exit_code ); static const struct object_ops process_ops = @@ -108,7 +110,7 @@ static const struct object_ops process_ops = remove_queue, /* remove_queue */ process_signaled, /* signaled */ process_get_esync_fd, /* get_esync_fd */ - NULL, /* get_fsync_idx */ + process_get_fsync_idx, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -692,6 +694,7 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla process->rawinput_kbd = NULL; memset( &process->image_info, 0, sizeof(process->image_info) ); process->esync_fd = -1; + process->fsync_idx = 0; list_init( &process->kernel_object ); list_init( &process->thread_list ); list_init( &process->locks ); @@ -748,6 +751,9 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla if (!token_assign_label( process->token, &high_label_sid )) goto error; + if (do_fsync()) + process->fsync_idx = fsync_alloc_shm( 0, 0 ); + if (do_esync()) process->esync_fd = esync_create_fd( 0, 0 ); @@ -823,6 +829,13 @@ static int process_get_esync_fd( struct object *obj, enum esync_type *type ) return process->esync_fd; } +static unsigned int process_get_fsync_idx( struct object *obj, enum fsync_type *type ) +{ + struct process *process = (struct process *)obj; + *type = FSYNC_MANUAL_SERVER; + return process->fsync_idx; +} + static unsigned int process_map_access( struct object *obj, unsigned int access ) { access = default_map_access( obj, access ); diff --git a/server/process.h b/server/process.h index d073e9e285f..b3b19859a71 100644 --- a/server/process.h +++ b/server/process.h @@ -87,6 +87,7 @@ struct process struct list kernel_object; /* list of kernel object pointers */ pe_image_info_t image_info; /* main exe image info */ int esync_fd; /* esync file descriptor (signaled on exit) */ + unsigned int fsync_idx; }; /* process functions */ From 61da35c93d35aa56d84d4d3fcf5d64d0998cfe69 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 17:30:47 -0500 Subject: [PATCH 0413/2777] ntdll, server: Implement waiting on server-bound objects. --- dlls/ntdll/unix/fsync.c | 51 +++++++++++++++++++++++++++++++++++++++-- server/fsync.c | 27 ++++++++++++++++++++++ server/fsync.h | 2 ++ server/thread.c | 4 ++++ 4 files changed, 82 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 208a0539ca1..6460c0da376 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -206,6 +206,49 @@ static struct fsync *get_cached_object( HANDLE handle ) return &fsync_list[entry][idx]; } +/* Gets an object. This is either a proper fsync object (i.e. an event, + * semaphore, etc. created using create_fsync) or a generic synchronizable + * server-side object which the server will signal (e.g. a process, thread, + * message queue, etc.) */ +static NTSTATUS get_object( HANDLE handle, struct fsync **obj ) +{ + NTSTATUS ret = STATUS_SUCCESS; + unsigned int shm_idx = 0; + enum fsync_type type; + + if ((*obj = get_cached_object( handle ))) return STATUS_SUCCESS; + + if ((INT_PTR)handle < 0) + { + /* We can deal with pseudo-handles, but it's just easier this way */ + return STATUS_NOT_IMPLEMENTED; + } + + /* We need to try grabbing it from the server. */ + SERVER_START_REQ( get_fsync_idx ) + { + req->handle = wine_server_obj_handle( handle ); + if (!(ret = wine_server_call( req ))) + { + shm_idx = reply->shm_idx; + type = reply->type; + } + } + SERVER_END_REQ; + + if (ret) + { + WARN("Failed to retrieve shm index for handle %p, status %#x.\n", handle, (unsigned int)ret); + *obj = NULL; + return ret; + } + + TRACE("Got shm index %d for handle %p.\n", shm_idx, handle); + + *obj = add_to_list( handle, type, get_shm( shm_idx ) ); + return ret; +} + NTSTATUS fsync_close( HANDLE handle ) { UINT_PTR entry, idx = handle_to_index( handle, &entry ); @@ -420,10 +463,13 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, for (i = 0; i < count; i++) { - if ((objs[i] = get_cached_object( handles[i] ))) + ret = get_object( handles[i], &objs[i] ); + if (ret == STATUS_SUCCESS) has_fsync = 1; - else + else if (ret == STATUS_NOT_IMPLEMENTED) has_server = 1; + else + return ret; } if (has_fsync && has_server) @@ -496,6 +542,7 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, break; } case FSYNC_MANUAL_EVENT: + case FSYNC_MANUAL_SERVER: { struct event *event = obj->shm; diff --git a/server/fsync.c b/server/fsync.c index ae4dc7d7318..da30d94f1f7 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -265,6 +266,32 @@ struct fsync *create_fsync( struct object *root, const struct unicode_str *name, #endif } +static inline int futex_wake( int *addr, int val ) +{ + return syscall( __NR_futex, addr, 1, val, NULL, 0, 0 ); +} + +/* shm layout for events or event-like objects. */ +struct fsync_event +{ + int signaled; + int unused; +}; + +void fsync_wake_up( struct object *obj ) +{ + struct fsync_event *event; + enum fsync_type type; + + if (obj->ops->get_fsync_idx) + { + event = get_shm( obj->ops->get_fsync_idx( obj, &type ) ); + + if (!__atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST )) + futex_wake( &event->signaled, INT_MAX ); + } +} + DECL_HANDLER(create_fsync) { struct fsync *fsync; diff --git a/server/fsync.h b/server/fsync.h index bbd104f3e16..2ff98cb64cb 100644 --- a/server/fsync.h +++ b/server/fsync.h @@ -21,3 +21,5 @@ extern int do_fsync(void); extern void fsync_init(void); extern unsigned int fsync_alloc_shm( int low, int high ); +extern void fsync_wake_up( struct object *obj ); +extern void fsync_clear( struct object *obj ); diff --git a/server/thread.c b/server/thread.c index c3f7b8013f1..564567294bc 100644 --- a/server/thread.c +++ b/server/thread.c @@ -58,6 +58,7 @@ #include "security.h" #include "esync.h" #include "unicode.h" +#include "fsync.h" /* thread queues */ @@ -1260,6 +1261,9 @@ void wake_up( struct object *obj, int max ) struct list *ptr; int ret; + if (do_fsync()) + fsync_wake_up( obj ); + if (do_esync()) esync_wake_up( obj ); From d33d978eae6cd3f7b02a1bbfba8ec075a3dc72b5 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 17:37:55 -0500 Subject: [PATCH 0414/2777] server: Create futexes for event objects. --- server/event.c | 21 ++++++++++++++++++++- server/fsync.c | 13 +++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/server/event.c b/server/event.c index f5a25c02293..9acd7fa263c 100644 --- a/server/event.c +++ b/server/event.c @@ -36,6 +36,7 @@ #include "request.h" #include "security.h" #include "esync.h" +#include "fsync.h" static const WCHAR event_name[] = {'E','v','e','n','t'}; @@ -58,12 +59,14 @@ struct event int manual_reset; /* is it a manual reset event? */ int signaled; /* event has been signaled */ int esync_fd; /* esync file descriptor */ + unsigned int fsync_idx; }; static void event_dump( struct object *obj, int verbose ); static int event_signaled( struct object *obj, struct wait_queue_entry *entry ); static void event_satisfied( struct object *obj, struct wait_queue_entry *entry ); static int event_get_esync_fd( struct object *obj, enum esync_type *type ); +static unsigned int event_get_fsync_idx( struct object *obj, enum fsync_type *type ); static int event_signal( struct object *obj, unsigned int access); static struct list *event_get_kernel_obj_list( struct object *obj ); static void event_destroy( struct object *obj ); @@ -77,7 +80,7 @@ static const struct object_ops event_ops = remove_queue, /* remove_queue */ event_signaled, /* signaled */ event_get_esync_fd, /* get_esync_fd */ - NULL, /* get_fsync_idx */ + event_get_fsync_idx, /* get_fsync_idx */ event_satisfied, /* satisfied */ event_signal, /* signal */ no_get_fd, /* get_fd */ @@ -159,6 +162,9 @@ struct event *create_event( struct object *root, const struct unicode_str *name, event->manual_reset = manual_reset; event->signaled = initial_state; + if (do_fsync()) + event->fsync_idx = fsync_alloc_shm( initial_state, 0 ); + if (do_esync()) event->esync_fd = esync_create_fd( initial_state, 0 ); } @@ -181,6 +187,9 @@ static void pulse_event( struct event *event ) /* wake up all waiters if manual reset, a single one otherwise */ wake_up( &event->obj, !event->manual_reset ); event->signaled = 0; + + if (do_fsync()) + fsync_clear( &event->obj ); } void set_event( struct event *event ) @@ -205,6 +214,9 @@ void reset_event( struct event *event ) } event->signaled = 0; + if (do_fsync()) + fsync_clear( &event->obj ); + if (do_esync()) esync_clear( event->esync_fd ); } @@ -231,6 +243,13 @@ static int event_get_esync_fd( struct object *obj, enum esync_type *type ) return event->esync_fd; } +static unsigned int event_get_fsync_idx( struct object *obj, enum fsync_type *type ) +{ + struct event *event = (struct event *)obj; + *type = FSYNC_MANUAL_SERVER; + return event->fsync_idx; +} + static void event_satisfied( struct object *obj, struct wait_queue_entry *entry ) { struct event *event = (struct event *)obj; diff --git a/server/fsync.c b/server/fsync.c index da30d94f1f7..07c0367d02c 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -292,6 +292,19 @@ void fsync_wake_up( struct object *obj ) } } +void fsync_clear( struct object *obj ) +{ + struct fsync_event *event; + enum fsync_type type; + + if (obj->ops->get_fsync_idx) + { + event = get_shm( obj->ops->get_fsync_idx( obj, &type ) ); + + __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); + } +} + DECL_HANDLER(create_fsync) { struct fsync *fsync; From 1f025a031ae5d2226e1f3cbdc035cee9961e5d07 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 17:44:18 -0500 Subject: [PATCH 0415/2777] server: Allow (re)setting fsync events on the server side. --- server/event.c | 16 ++++++++++++++++ server/fsync.c | 19 ++++++++++++++++++- server/fsync.h | 6 ++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/server/event.c b/server/event.c index 9acd7fa263c..aa1b0a4002a 100644 --- a/server/event.c +++ b/server/event.c @@ -175,6 +175,10 @@ struct event *create_event( struct object *root, const struct unicode_str *name, struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access ) { struct object *obj; + + if (do_fsync() && (obj = get_handle_obj( process, handle, access, &fsync_ops))) + return (struct event *)obj; /* even though it's not an event */ + if (do_esync() && (obj = get_handle_obj( process, handle, access, &esync_ops))) return (struct event *)obj; /* even though it's not an event */ @@ -194,6 +198,12 @@ static void pulse_event( struct event *event ) void set_event( struct event *event ) { + if (do_fsync() && event->obj.ops == &fsync_ops) + { + fsync_set_event( (struct fsync *)event ); + return; + } + if (do_esync() && event->obj.ops == &esync_ops) { esync_set_event( (struct esync *)event ); @@ -207,6 +217,12 @@ void set_event( struct event *event ) void reset_event( struct event *event ) { + if (do_fsync() && event->obj.ops == &fsync_ops) + { + fsync_reset_event( (struct fsync *)event ); + return; + } + if (do_esync() && event->obj.ops == &esync_ops) { esync_reset_event( (struct esync *)event ); diff --git a/server/fsync.c b/server/fsync.c index 07c0367d02c..1d6a49fb517 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -132,7 +132,7 @@ struct fsync static void fsync_dump( struct object *obj, int verbose ); static void fsync_destroy( struct object *obj ); -static const struct object_ops fsync_ops = +const struct object_ops fsync_ops = { sizeof(struct fsync), /* size */ &no_type, /* type */ @@ -305,6 +305,23 @@ void fsync_clear( struct object *obj ) } } +void fsync_set_event( struct fsync *fsync ) +{ + struct fsync_event *event = get_shm( fsync->shm_idx ); + assert( fsync->obj.ops == &fsync_ops ); + + if (!__atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST )) + futex_wake( &event->signaled, INT_MAX ); +} + +void fsync_reset_event( struct fsync *fsync ) +{ + struct fsync_event *event = get_shm( fsync->shm_idx ); + assert( fsync->obj.ops == &fsync_ops ); + + __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); +} + DECL_HANDLER(create_fsync) { struct fsync *fsync; diff --git a/server/fsync.h b/server/fsync.h index 2ff98cb64cb..087d482717b 100644 --- a/server/fsync.h +++ b/server/fsync.h @@ -23,3 +23,9 @@ extern void fsync_init(void); extern unsigned int fsync_alloc_shm( int low, int high ); extern void fsync_wake_up( struct object *obj ); extern void fsync_clear( struct object *obj ); + +struct fsync; + +extern const struct object_ops fsync_ops; +extern void fsync_set_event( struct fsync *fsync ); +extern void fsync_reset_event( struct fsync *fsync ); From a30e3e3a7cb8a1afc51d0b9510567214d06d6240 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 17:47:50 -0500 Subject: [PATCH 0416/2777] server: Create futexes for thread objects. --- server/thread.c | 14 +++++++++++++- server/thread.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/server/thread.c b/server/thread.c index 564567294bc..615198ebe67 100644 --- a/server/thread.c +++ b/server/thread.c @@ -191,6 +191,7 @@ struct type_descr thread_type = static void dump_thread( struct object *obj, int verbose ); static int thread_signaled( struct object *obj, struct wait_queue_entry *entry ); static int thread_get_esync_fd( struct object *obj, enum esync_type *type ); +static unsigned int thread_get_fsync_idx( struct object *obj, enum fsync_type *type ); static unsigned int thread_map_access( struct object *obj, unsigned int access ); static void thread_poll_event( struct fd *fd, int event ); static struct list *thread_get_kernel_obj_list( struct object *obj ); @@ -205,7 +206,7 @@ static const struct object_ops thread_ops = remove_queue, /* remove_queue */ thread_signaled, /* signaled */ thread_get_esync_fd, /* get_esync_fd */ - NULL, /* get_fsync_idx */ + thread_get_fsync_idx, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -270,6 +271,7 @@ static inline void init_thread_structure( struct thread *thread ) thread->entry_point = 0; thread->esync_fd = -1; thread->esync_apc_fd = -1; + thread->fsync_idx = 0; thread->system_regs = 0; thread->queue = NULL; thread->wait = NULL; @@ -484,6 +486,9 @@ struct thread *create_thread( int fd, struct process *process, const struct secu } } + if (do_fsync()) + thread->fsync_idx = fsync_alloc_shm( 0, 0 ); + if (do_esync()) { thread->esync_fd = esync_create_fd( 0, 0 ); @@ -603,6 +608,13 @@ static int thread_get_esync_fd( struct object *obj, enum esync_type *type ) return thread->esync_fd; } +static unsigned int thread_get_fsync_idx( struct object *obj, enum fsync_type *type ) +{ + struct thread *thread = (struct thread *)obj; + *type = FSYNC_MANUAL_SERVER; + return thread->fsync_idx; +} + static unsigned int thread_map_access( struct object *obj, unsigned int access ) { access = default_map_access( obj, access ); diff --git a/server/thread.h b/server/thread.h index d09171c31f9..f9b145fa6b9 100644 --- a/server/thread.h +++ b/server/thread.h @@ -56,6 +56,7 @@ struct thread struct list mutex_list; /* list of currently owned mutexes */ int esync_fd; /* esync file descriptor (signalled on exit) */ int esync_apc_fd; /* esync apc fd (signalled when APCs are present) */ + unsigned int fsync_idx; unsigned int system_regs; /* which system regs have been set */ struct msg_queue *queue; /* message queue */ struct thread_wait *wait; /* current wait condition if sleeping */ From d4d2162529a88f8fb30987402da5f200115b8325 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 17:53:59 -0500 Subject: [PATCH 0417/2777] server: Create futexes for message queues. --- server/protocol.def | 1 + server/queue.c | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/server/protocol.def b/server/protocol.def index 6af6bbf57b4..59fd1364ccf 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3900,6 +3900,7 @@ enum fsync_type FSYNC_AUTO_EVENT, FSYNC_MANUAL_EVENT, FSYNC_MANUAL_SERVER, + FSYNC_QUEUE, }; /* Create a new futex-based synchronization object */ diff --git a/server/queue.c b/server/queue.c index 8221357e73e..7b0d2197f8f 100644 --- a/server/queue.c +++ b/server/queue.c @@ -42,6 +42,7 @@ #include "request.h" #include "user.h" #include "esync.h" +#include "fsync.h" #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE #define WM_NCMOUSELAST (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST)) @@ -136,6 +137,7 @@ struct msg_queue int keystate_lock; /* owns an input keystate lock */ int esync_fd; /* esync file descriptor (signalled on message) */ int esync_in_msgwait; /* our thread is currently waiting on us */ + unsigned int fsync_idx; volatile struct queue_shared_memory *shared; /* thread queue shared memory ptr */ }; @@ -154,6 +156,7 @@ static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *ent static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry ); static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entry ); static int msg_queue_get_esync_fd( struct object *obj, enum esync_type *type ); +static unsigned int msg_queue_get_fsync_idx( struct object *obj, enum fsync_type *type ); static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry ); static void msg_queue_destroy( struct object *obj ); static void msg_queue_poll_event( struct fd *fd, int event ); @@ -170,7 +173,7 @@ static const struct object_ops msg_queue_ops = msg_queue_remove_queue, /* remove_queue */ msg_queue_signaled, /* signaled */ msg_queue_get_esync_fd, /* get_esync_fd */ - NULL, /* get_fsync_idx */ + msg_queue_get_fsync_idx, /* get_fsync_idx */ msg_queue_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -364,6 +367,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ queue->keystate_lock = 0; queue->esync_fd = -1; queue->esync_in_msgwait = 0; + queue->fsync_idx = 0; queue->shared = thread->queue_shared; list_init( &queue->send_result ); list_init( &queue->callback_result ); @@ -371,6 +375,9 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ list_init( &queue->expired_timers ); for (i = 0; i < NB_MSG_KINDS; i++) list_init( &queue->msg_list[i] ); + if (do_fsync()) + queue->fsync_idx = fsync_alloc_shm( 0, 0 ); + if (do_esync()) queue->esync_fd = esync_create_fd( 0, 0 ); @@ -619,6 +626,9 @@ static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits queue->keystate_lock = 0; } + if (do_fsync() && !is_signaled( queue )) + fsync_clear( &queue->obj ); + if (do_esync() && !is_signaled( queue )) esync_clear( queue->esync_fd ); @@ -1174,6 +1184,13 @@ static int msg_queue_get_esync_fd( struct object *obj, enum esync_type *type ) return queue->esync_fd; } +static unsigned int msg_queue_get_fsync_idx( struct object *obj, enum fsync_type *type ) +{ + struct msg_queue *queue = (struct msg_queue *)obj; + *type = FSYNC_QUEUE; + return queue->fsync_idx; +} + static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry ) { struct msg_queue *queue = (struct msg_queue *)obj; @@ -2770,6 +2787,9 @@ DECL_HANDLER(set_queue_mask) else wake_up( &queue->obj, 0 ); } + if (do_fsync() && !is_signaled( queue )) + fsync_clear( &queue->obj ); + if (do_esync() && !is_signaled( queue )) esync_clear( queue->esync_fd ); } @@ -2786,6 +2806,9 @@ DECL_HANDLER(get_queue_status) reply->changed_bits = queue->changed_bits; queue->changed_bits &= ~req->clear_bits; + if (do_fsync() && !is_signaled( queue )) + fsync_clear( &queue->obj ); + if (do_esync() && !is_signaled( queue )) esync_clear( queue->esync_fd ); @@ -3036,6 +3059,9 @@ DECL_HANDLER(get_message) set_error( STATUS_PENDING ); /* FIXME */ + if (do_fsync() && !is_signaled( queue )) + fsync_clear( &queue->obj ); + if (do_esync() && !is_signaled( queue )) esync_clear( queue->esync_fd ); From e91fcad82d14ba5dbf36b028e793ae26b8623ed8 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 19:24:15 -0500 Subject: [PATCH 0418/2777] server, ntdll: Implement message waits. The approach of giving the queue fd to ntdll to wait on doesn't work here. Fortunately, the way esync has ended up lends itself very easily to a rather clean approach: let the server do it the normal way. --- dlls/ntdll/unix/fsync.c | 52 ++++++++++++++++++++++++++++++++++++++++- server/protocol.def | 4 ++++ server/queue.c | 20 ++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 6460c0da376..c8f449d1ba7 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -438,12 +438,13 @@ static LONGLONG update_timeout( ULONGLONG end ) return timeleft; } -NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, +static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) { struct futex_wait_block futexes[MAXIMUM_WAIT_OBJECTS]; struct fsync *objs[MAXIMUM_WAIT_OBJECTS]; int has_fsync = 0, has_server = 0; + BOOL msgwait = FALSE; int dummy_futex = 0; LONGLONG timeleft; LARGE_INTEGER now; @@ -472,6 +473,9 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, return ret; } + if (objs[count - 1] && objs[count - 1]->type == FSYNC_QUEUE) + msgwait = TRUE; + if (has_fsync && has_server) FIXME("Can't wait on fsync and server objects at the same time!\n"); else if (has_server) @@ -483,6 +487,9 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, for (i = 0; i < count; i++) TRACE(" %p", handles[i]); + if (msgwait) + TRACE(" or driver events"); + if (!timeout) TRACE(", timeout = INFINITE.\n"); else @@ -543,6 +550,7 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, } case FSYNC_MANUAL_EVENT: case FSYNC_MANUAL_SERVER: + case FSYNC_QUEUE: { struct event *event = obj->shm; @@ -603,3 +611,45 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, return STATUS_NOT_IMPLEMENTED; } } + +/* Like esync, we need to let the server know when we are doing a message wait, + * and when we are done with one, so that all of the code surrounding hung + * queues works, and we also need this for WaitForInputIdle(). + * + * Unlike esync, we can't wait on the queue fd itself locally. Instead we let + * the server do that for us, the way it normally does. This could actually + * work for esync too, and that might be better. */ +static void server_set_msgwait( int in_msgwait ) +{ + SERVER_START_REQ( fsync_msgwait ) + { + req->in_msgwait = in_msgwait; + wine_server_call( req ); + } + SERVER_END_REQ; +} + +/* This is a very thin wrapper around the proper implementation above. The + * purpose is to make sure the server knows when we are doing a message wait. + * This is separated into a wrapper function since there are at least a dozen + * exit paths from fsync_wait_objects(). */ +NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ) +{ + BOOL msgwait = FALSE; + struct fsync *obj; + NTSTATUS ret; + + if (!get_object( handles[count - 1], &obj ) && obj->type == FSYNC_QUEUE) + { + msgwait = TRUE; + server_set_msgwait( 1 ); + } + + ret = __fsync_wait_objects( count, handles, wait_any, alertable, timeout ); + + if (msgwait) + server_set_msgwait( 0 ); + + return ret; +} diff --git a/server/protocol.def b/server/protocol.def index 59fd1364ccf..c0d8568c6a8 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3921,3 +3921,7 @@ enum fsync_type int type; unsigned int shm_idx; @END + +@REQ(fsync_msgwait) + int in_msgwait; /* are we in a message wait? */ +@END diff --git a/server/queue.c b/server/queue.c index 7b0d2197f8f..8d59f62f379 100644 --- a/server/queue.c +++ b/server/queue.c @@ -138,6 +138,7 @@ struct msg_queue int esync_fd; /* esync file descriptor (signalled on message) */ int esync_in_msgwait; /* our thread is currently waiting on us */ unsigned int fsync_idx; + int fsync_in_msgwait; /* our thread is currently waiting on us */ volatile struct queue_shared_memory *shared; /* thread queue shared memory ptr */ }; @@ -368,6 +369,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ queue->esync_fd = -1; queue->esync_in_msgwait = 0; queue->fsync_idx = 0; + queue->fsync_in_msgwait = 0; queue->shared = thread->queue_shared; list_init( &queue->send_result ); list_init( &queue->callback_result ); @@ -1119,6 +1121,9 @@ static int is_queue_hung( struct msg_queue *queue ) return 0; /* thread is waiting on queue -> not hung */ } + if (do_fsync() && queue->fsync_in_msgwait) + return 0; /* thread is waiting on queue in absentia -> not hung */ + if (do_esync() && queue->esync_in_msgwait) return 0; /* thread is waiting on queue in absentia -> not hung */ @@ -3811,3 +3816,18 @@ DECL_HANDLER(esync_msgwait) if (queue->fd) set_fd_events( queue->fd, req->in_msgwait ? POLLIN : 0 ); } + +DECL_HANDLER(fsync_msgwait) +{ + struct msg_queue *queue = get_current_queue(); + + if (!queue) return; + queue->fsync_in_msgwait = req->in_msgwait; + + if (current->process->idle_event && !(queue->wake_mask & QS_SMRESULT)) + set_event( current->process->idle_event ); + + /* and start/stop waiting on the driver */ + if (queue->fd) + set_fd_events( queue->fd, req->in_msgwait ? POLLIN : 0 ); +} From 24f633828e0cfa559667d5bcde7fe49402987288 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 19:29:56 -0500 Subject: [PATCH 0419/2777] server: Create futexes for device manager objects. --- server/device.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/server/device.c b/server/device.c index 8613cee58af..90e0a0c1fee 100644 --- a/server/device.c +++ b/server/device.c @@ -39,6 +39,7 @@ #include "request.h" #include "process.h" #include "esync.h" +#include "fsync.h" /* IRP object */ @@ -96,11 +97,13 @@ struct device_manager struct irp_call *current_call; /* call currently executed on client side */ struct wine_rb_tree kernel_objects; /* map of objects that have client side pointer associated */ int esync_fd; /* esync file descriptor */ + unsigned int fsync_idx; }; static void device_manager_dump( struct object *obj, int verbose ); static int device_manager_signaled( struct object *obj, struct wait_queue_entry *entry ); static int device_manager_get_esync_fd( struct object *obj, enum esync_type *type ); +static unsigned int device_manager_get_fsync_idx( struct object *obj, enum fsync_type *type ); static void device_manager_destroy( struct object *obj ); static const struct object_ops device_manager_ops = @@ -112,7 +115,7 @@ static const struct object_ops device_manager_ops = remove_queue, /* remove_queue */ device_manager_signaled, /* signaled */ device_manager_get_esync_fd, /* get_esync_fd */ - NULL, /* get_fsync_idx */ + device_manager_get_fsync_idx, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -758,6 +761,9 @@ static void delete_file( struct device_file *file ) /* terminate all pending requests */ LIST_FOR_EACH_ENTRY_SAFE( irp, next, &file->requests, struct irp_call, dev_entry ) { + if (do_fsync() && file->device->manager && list_empty( &file->device->manager->requests )) + fsync_clear( &file->device->manager->obj ); + if (do_esync() && file->device->manager && list_empty( &file->device->manager->requests )) esync_clear( file->device->manager->esync_fd ); @@ -803,6 +809,13 @@ static int device_manager_get_esync_fd( struct object *obj, enum esync_type *typ return manager->esync_fd; } +static unsigned int device_manager_get_fsync_idx( struct object *obj, enum fsync_type *type ) +{ + struct device_manager *manager = (struct device_manager *)obj; + *type = FSYNC_MANUAL_SERVER; + return manager->fsync_idx; +} + static void device_manager_destroy( struct object *obj ) { struct device_manager *manager = (struct device_manager *)obj; @@ -853,6 +866,9 @@ static struct device_manager *create_device_manager(void) list_init( &manager->requests ); wine_rb_init( &manager->kernel_objects, compare_kernel_object ); + if (do_fsync()) + manager->fsync_idx = fsync_alloc_shm( 0, 0 ); + if (do_esync()) manager->esync_fd = esync_create_fd( 0, 0 ); } @@ -1045,6 +1061,9 @@ DECL_HANDLER(get_next_device_request) if (irp->file) grab_object( irp ); manager->current_call = irp; + if (do_fsync() && list_empty( &manager->requests )) + fsync_clear( &manager->obj ); + if (do_esync() && list_empty( &manager->requests )) esync_clear( manager->esync_fd ); } From 734fca42ad78316329458a722192803dd6257925 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 19:36:23 -0500 Subject: [PATCH 0420/2777] ntdll: Implement NtCreateMutant(). --- dlls/ntdll/unix/fsync.c | 17 +++++++++++++++++ dlls/ntdll/unix/fsync.h | 2 ++ dlls/ntdll/unix/sync.c | 3 +++ server/protocol.def | 1 + 4 files changed, 23 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index c8f449d1ba7..fdd6791e24f 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -116,6 +116,13 @@ struct event }; C_ASSERT(sizeof(struct event) == 8); +struct mutex +{ + int tid; + int count; /* recursion count */ +}; +C_ASSERT(sizeof(struct mutex) == 8); + static char shm_name[29]; static int shm_fd; static void **shm_addrs; @@ -427,6 +434,16 @@ NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) return STATUS_SUCCESS; } +NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) +{ + TRACE("name %s, initial %d.\n", + attr ? debugstr_us(attr->ObjectName) : "", initial); + + return create_fsync( FSYNC_MUTEX, handle, access, attr, + initial ? GetCurrentThreadId() : 0, initial ? 1 : 0 ); +} + static LONGLONG update_timeout( ULONGLONG end ) { LARGE_INTEGER now; diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h index 76addff0e4d..834c44e4180 100644 --- a/dlls/ntdll/unix/fsync.h +++ b/dlls/ntdll/unix/fsync.h @@ -29,6 +29,8 @@ extern NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; +extern NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 578568ee105..18e44b2aad5 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -589,6 +589,9 @@ NTSTATUS WINAPI NtCreateMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT *handle = 0; + if (do_fsync()) + return fsync_create_mutex( handle, access, attr, owned ); + if (do_esync()) return esync_create_mutex( handle, access, attr, owned ); diff --git a/server/protocol.def b/server/protocol.def index c0d8568c6a8..8b1681597f1 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3899,6 +3899,7 @@ enum fsync_type FSYNC_SEMAPHORE = 1, FSYNC_AUTO_EVENT, FSYNC_MANUAL_EVENT, + FSYNC_MUTEX, FSYNC_MANUAL_SERVER, FSYNC_QUEUE, }; From cebbba695f864728fc00e70cfc5070535b957778 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 19:42:17 -0500 Subject: [PATCH 0421/2777] ntdll: Implement NtReleaseMutant(). --- dlls/ntdll/unix/fsync.c | 23 +++++++++++++++++++++++ dlls/ntdll/unix/fsync.h | 1 + dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 27 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index fdd6791e24f..45f17c313be 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -444,6 +444,29 @@ NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, initial ? GetCurrentThreadId() : 0, initial ? 1 : 0 ); } +NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) +{ + struct mutex *mutex; + struct fsync *obj; + + TRACE("%p, %p.\n", handle, prev); + + if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; + mutex = obj->shm; + + if (mutex->tid != GetCurrentThreadId()) return STATUS_MUTANT_NOT_OWNED; + + if (prev) *prev = mutex->count; + + if (!--mutex->count) + { + __atomic_store_n( &mutex->tid, 0, __ATOMIC_SEQ_CST ); + futex_wake( &mutex->tid, 1 ); + } + + return STATUS_SUCCESS; +} + static LONGLONG update_timeout( ULONGLONG end ) { LARGE_INTEGER now; diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h index 834c44e4180..4da1626e12b 100644 --- a/dlls/ntdll/unix/fsync.h +++ b/dlls/ntdll/unix/fsync.h @@ -31,6 +31,7 @@ extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) DECLSPEC_HIDDEN; +extern NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 18e44b2aad5..4513ad15f29 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -647,6 +647,9 @@ NTSTATUS WINAPI NtReleaseMutant( HANDLE handle, LONG *prev_count ) { unsigned int ret; + if (do_fsync()) + return fsync_release_mutex( handle, prev_count ); + if (do_esync()) return esync_release_mutex( handle, prev_count ); From 0db4af4de9edf23dc7d13be3fe03f901e5a6b0f1 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 19:46:17 -0500 Subject: [PATCH 0422/2777] ntdll: Implement waiting on mutexes. --- dlls/ntdll/unix/fsync.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 45f17c313be..8ac60ed73b0 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -574,6 +574,28 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, futexes[i].val = current; break; } + case FSYNC_MUTEX: + { + struct mutex *mutex = obj->shm; + + if (mutex->tid == GetCurrentThreadId()) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + mutex->count++; + return i; + } + + if (!__sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() )) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + mutex->count = 1; + return i; + } + + futexes[i].addr = &mutex->tid; + futexes[i].val = mutex->tid; + break; + } case FSYNC_AUTO_EVENT: { struct event *event = obj->shm; From a6fcccbae32db1ab9c40b545f4b52666da5730c8 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 1 Sep 2018 20:35:44 -0500 Subject: [PATCH 0423/2777] ntdll: Implement wait-all. --- dlls/ntdll/unix/fsync.c | 204 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 201 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 8ac60ed73b0..5e75c5a69f9 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -75,6 +75,11 @@ static inline int futex_wake( int *addr, int val ) return syscall( __NR_futex, addr, 1, val, NULL, 0, 0 ); } +static inline int futex_wait( int *addr, int val, struct timespec *timeout ) +{ + return syscall( __NR_futex, addr, 0, val, timeout, 0, 0 ); +} + int do_fsync(void) { #ifdef __linux__ @@ -478,6 +483,29 @@ static LONGLONG update_timeout( ULONGLONG end ) return timeleft; } +static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end ) +{ + int ret; + + if (end) + { + LONGLONG timeleft = update_timeout( *end ); + struct timespec tmo_p; + tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; + tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; + ret = futex_wait( addr, val, &tmo_p ); + } + else + ret = futex_wait( addr, val, NULL ); + + if (!ret) + return 0; + else if (ret < 0 && errno == ETIMEDOUT) + return STATUS_TIMEOUT; + else + return STATUS_PENDING; +} + static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) { @@ -669,9 +697,179 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, } else { - FIXME("Wait-all not implemented.\n"); - return STATUS_NOT_IMPLEMENTED; - } + /* Wait-all is a little trickier to implement correctly. Fortunately, + * it's not as common. + * + * The idea is basically just to wait in sequence on every object in the + * set. Then when we're done, try to grab them all in a tight loop. If + * that fails, release any resources we've grabbed (and yes, we can + * reliably do this—it's just mutexes and semaphores that we have to + * put back, and in both cases we just put back 1), and if any of that + * fails we start over. + * + * What makes this inherently bad is that we might temporarily grab a + * resource incorrectly. Hopefully it'll be quick (and hey, it won't + * block on wineserver) so nobody will notice. Besides, consider: if + * object A becomes signaled but someone grabs it before we can grab it + * and everything else, then they could just as well have grabbed it + * before it became signaled. Similarly if object A was signaled and we + * were blocking on object B, then B becomes available and someone grabs + * A before we can, then they might have grabbed A before B became + * signaled. In either case anyone who tries to wait on A or B will be + * waiting for an instant while we put things back. */ + + NTSTATUS status = STATUS_SUCCESS; + int current; + + while (1) + { +tryagain: + /* First step: try to wait on each object in sequence. */ + + for (i = 0; i < count; i++) + { + struct fsync *obj = objs[i]; + + if (obj && obj->type == FSYNC_MUTEX) + { + struct mutex *mutex = obj->shm; + + if (mutex->tid == GetCurrentThreadId()) + continue; + + while ((current = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ))) + { + status = do_single_wait( &mutex->tid, current, timeout ? &end : NULL ); + if (status != STATUS_PENDING) + break; + } + } + else if (obj) + { + /* this works for semaphores too */ + struct event *event = obj->shm; + + while (!__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) + { + status = do_single_wait( &event->signaled, 0, timeout ? &end : NULL ); + if (status != STATUS_PENDING) + break; + } + } + + if (status == STATUS_TIMEOUT) + { + TRACE("Wait timed out.\n"); + return status; + } + } + + /* If we got here and we haven't timed out, that means all of the + * handles were signaled. Check to make sure they still are. */ + for (i = 0; i < count; i++) + { + struct fsync *obj = objs[i]; + + if (obj && obj->type == FSYNC_MUTEX) + { + struct mutex *mutex = obj->shm; + + if (mutex->tid == GetCurrentThreadId()) + continue; /* ok */ + + if (__atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST )) + goto tryagain; + } + else if (obj) + { + struct event *event = obj->shm; + + if (!__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) + goto tryagain; + } + } + + /* Yep, still signaled. Now quick, grab everything. */ + for (i = 0; i < count; i++) + { + struct fsync *obj = objs[i]; + switch (obj->type) + { + case FSYNC_MUTEX: + { + struct mutex *mutex = obj->shm; + if (mutex->tid == GetCurrentThreadId()) + break; + if (__sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() )) + goto tooslow; + break; + } + case FSYNC_SEMAPHORE: + { + struct semaphore *semaphore = obj->shm; + if (__sync_fetch_and_sub( &semaphore->count, 1 ) <= 0) + goto tooslow; + break; + } + case FSYNC_AUTO_EVENT: + { + struct event *event = obj->shm; + if (!__sync_val_compare_and_swap( &event->signaled, 1, 0 )) + goto tooslow; + break; + } + default: + /* If a manual-reset event changed between there and + * here, it's shouldn't be a problem. */ + break; + } + } + + /* If we got here, we successfully waited on every object. + * Make sure to let ourselves know that we grabbed the mutexes. */ + for (i = 0; i < count; i++) + { + if (objs[i] && objs[i]->type == FSYNC_MUTEX) + { + struct mutex *mutex = objs[i]->shm; + mutex->count++; + } + } + + TRACE("Wait successful.\n"); + return STATUS_SUCCESS; + +tooslow: + for (--i; i >= 0; i--) + { + struct fsync *obj = objs[i]; + switch (obj->type) + { + case FSYNC_MUTEX: + { + struct mutex *mutex = obj->shm; + __atomic_store_n( &mutex->tid, 0, __ATOMIC_SEQ_CST ); + break; + } + case FSYNC_SEMAPHORE: + { + struct semaphore *semaphore = obj->shm; + __sync_fetch_and_add( &semaphore->count, 1 ); + break; + } + case FSYNC_AUTO_EVENT: + { + struct event *event = obj->shm; + __atomic_store_n( &event->signaled, 1, __ATOMIC_SEQ_CST ); + break; + } + default: + /* doesn't need to be put back */ + break; + } + } + } /* while (1) */ + } /* else (wait-all) */ } /* Like esync, we need to let the server know when we are doing a message wait, From 54dd0f9a3f79d4210a1acfe612cb0dff23c5a4f3 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 2 Sep 2018 11:41:07 -0500 Subject: [PATCH 0424/2777] ntdll: Implement NtSignalAndWaitForSingleObject(). --- dlls/ntdll/unix/fsync.c | 28 ++++++++++++++++++++++++++++ dlls/ntdll/unix/fsync.h | 2 ++ dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 33 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 5e75c5a69f9..37cb6a4dab0 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -913,3 +913,31 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an return ret; } + +NTSTATUS fsync_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable, + const LARGE_INTEGER *timeout ) +{ + struct fsync *obj = get_cached_object( signal ); + NTSTATUS ret; + + if (!obj) return STATUS_INVALID_HANDLE; + + switch (obj->type) + { + case FSYNC_SEMAPHORE: + ret = fsync_release_semaphore( signal, 1, NULL ); + break; + case FSYNC_AUTO_EVENT: + case FSYNC_MANUAL_EVENT: + ret = fsync_set_event( signal, NULL ); + break; + case FSYNC_MUTEX: + ret = fsync_release_mutex( signal, NULL ); + break; + default: + return STATUS_OBJECT_TYPE_MISMATCH; + } + if (ret) return ret; + + return fsync_wait_objects( 1, &wait, TRUE, alertable, timeout ); +} diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h index 4da1626e12b..bbfeb9e5579 100644 --- a/dlls/ntdll/unix/fsync.h +++ b/dlls/ntdll/unix/fsync.h @@ -35,3 +35,5 @@ extern NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; +extern NTSTATUS fsync_signal_and_wait( HANDLE signal, HANDLE wait, + BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 4513ad15f29..1878adb2cf1 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -1531,6 +1531,9 @@ NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE signal, HANDLE wait, select_op_t select_op; UINT flags = SELECT_INTERRUPTIBLE; + if (do_fsync()) + return fsync_signal_and_wait( signal, wait, alertable, timeout ); + if (do_esync()) return esync_signal_and_wait( signal, wait, alertable, timeout ); From f13d1046eb223a1ae65043ab4ca9b5d3e922e3b6 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 2 Sep 2018 11:48:26 -0500 Subject: [PATCH 0425/2777] server, ntdll: Also store the fsync type in the server. --- dlls/ntdll/unix/fsync.c | 2 ++ server/fsync.c | 26 +++++++++++++++++++++++--- server/protocol.def | 2 ++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 37cb6a4dab0..afeba5b793c 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -291,12 +291,14 @@ static NTSTATUS create_fsync( enum fsync_type type, HANDLE *handle, req->access = access; req->low = low; req->high = high; + req->type = type; wine_server_add_data( req, objattr, len ); ret = wine_server_call( req ); if (!ret || ret == STATUS_OBJECT_NAME_EXISTS) { *handle = wine_server_ptr_handle( reply->handle ); shm_idx = reply->shm_idx; + type = reply->type; } } SERVER_END_REQ; diff --git a/server/fsync.c b/server/fsync.c index 1d6a49fb517..d32d5f9c689 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -127,6 +127,7 @@ struct fsync { struct object obj; unsigned int shm_idx; + enum fsync_type type; }; static void fsync_dump( struct object *obj, int verbose ); @@ -237,9 +238,16 @@ unsigned int fsync_alloc_shm( int low, int high ) #endif } +static int type_matches( enum fsync_type type1, enum fsync_type type2 ) +{ + return (type1 == type2) || + ((type1 == FSYNC_AUTO_EVENT || type1 == FSYNC_MANUAL_EVENT) && + (type2 == FSYNC_AUTO_EVENT || type2 == FSYNC_MANUAL_EVENT)); +} + struct fsync *create_fsync( struct object *root, const struct unicode_str *name, - unsigned int attr, int low, int high, - const struct security_descriptor *sd ) + unsigned int attr, int low, int high, enum fsync_type type, + const struct security_descriptor *sd ) { #ifdef __linux__ struct fsync *fsync; @@ -256,6 +264,17 @@ struct fsync *create_fsync( struct object *root, const struct unicode_str *name, * and the time its shared memory portion is initialized. */ fsync->shm_idx = fsync_alloc_shm( low, high ); + fsync->type = type; + } + else + { + /* validate the type */ + if (!type_matches( type, fsync->type )) + { + release_object( &fsync->obj ); + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + return NULL; + } } } @@ -339,7 +358,7 @@ DECL_HANDLER(create_fsync) if (!objattr) return; if ((fsync = create_fsync( root, &name, objattr->attributes, req->low, - req->high, sd ))) + req->high, req->type, sd ))) { if (get_error() == STATUS_OBJECT_NAME_EXISTS) reply->handle = alloc_handle( current->process, fsync, req->access, objattr->attributes ); @@ -348,6 +367,7 @@ DECL_HANDLER(create_fsync) req->access, objattr->attributes ); reply->shm_idx = fsync->shm_idx; + reply->type = fsync->type; release_object( fsync ); } diff --git a/server/protocol.def b/server/protocol.def index 8b1681597f1..85891ef7ef9 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3909,9 +3909,11 @@ enum fsync_type unsigned int access; /* wanted access rights */ int low; /* initial value of low word */ int high; /* initial value of high word */ + int type; /* type of fsync object */ VARARG(objattr,object_attributes); /* object attributes */ @REPLY obj_handle_t handle; /* handle to the object */ + int type; /* type of fsync object */ unsigned int shm_idx; /* this object's index into the shm section */ @END From 8dd8790b06ce6d93b65bda684681ec39feb00d8f Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 2 Sep 2018 12:02:39 -0500 Subject: [PATCH 0426/2777] ntdll, server: Implement NtOpenSemaphore(). --- dlls/ntdll/unix/fsync.c | 40 ++++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/fsync.h | 2 ++ dlls/ntdll/unix/sync.c | 3 +++ server/fsync.c | 27 +++++++++++++++++++++++++++ server/protocol.def | 13 +++++++++++++ 5 files changed, 85 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index afeba5b793c..3dc20e18ddc 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -313,6 +313,38 @@ static NTSTATUS create_fsync( enum fsync_type type, HANDLE *handle, return ret; } +static NTSTATUS open_fsync( enum fsync_type type, HANDLE *handle, + ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) +{ + NTSTATUS ret; + unsigned int shm_idx; + + SERVER_START_REQ( open_fsync ) + { + req->access = access; + req->attributes = attr->Attributes; + req->rootdir = wine_server_obj_handle( attr->RootDirectory ); + req->type = type; + if (attr->ObjectName) + wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length ); + if (!(ret = wine_server_call( req ))) + { + *handle = wine_server_ptr_handle( reply->handle ); + type = reply->type; + shm_idx = reply->shm_idx; + } + } + SERVER_END_REQ; + + if (!ret) + { + add_to_list( *handle, type, get_shm( shm_idx ) ); + + TRACE("-> handle %p, shm index %u.\n", *handle, shm_idx); + } + return ret; +} + void fsync_init(void) { struct stat st; @@ -366,6 +398,14 @@ NTSTATUS fsync_create_semaphore( HANDLE *handle, ACCESS_MASK access, return create_fsync( FSYNC_SEMAPHORE, handle, access, attr, initial, max ); } +NTSTATUS fsync_open_semaphore( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ) +{ + TRACE("name %s.\n", debugstr_us(attr->ObjectName)); + + return open_fsync( FSYNC_SEMAPHORE, handle, access, attr ); +} + NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) { struct fsync *obj; diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h index bbfeb9e5579..2b4f26d51a3 100644 --- a/dlls/ntdll/unix/fsync.h +++ b/dlls/ntdll/unix/fsync.h @@ -25,6 +25,8 @@ extern NTSTATUS fsync_close( HANDLE handle ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_create_semaphore(HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN; extern NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) DECLSPEC_HIDDEN; +extern NTSTATUS fsync_open_semaphore( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 1878adb2cf1..deac0df28fa 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -306,6 +306,9 @@ NTSTATUS WINAPI NtOpenSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJEC *handle = 0; + if (do_fsync()) + return fsync_open_semaphore( handle, access, attr ); + if (do_esync()) return esync_open_semaphore( handle, access, attr ); diff --git a/server/fsync.c b/server/fsync.c index d32d5f9c689..3fbc1734735 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -374,6 +374,33 @@ DECL_HANDLER(create_fsync) if (root) release_object( root ); } +DECL_HANDLER(open_fsync) +{ + struct unicode_str name = get_req_unicode_str(); + + reply->handle = open_object( current->process, req->rootdir, req->access, + &fsync_ops, &name, req->attributes ); + + if (reply->handle) + { + struct fsync *fsync; + + if (!(fsync = (struct fsync *)get_handle_obj( current->process, reply->handle, + 0, &fsync_ops ))) + return; + + if (!type_matches( req->type, fsync->type )) + { + set_error( STATUS_OBJECT_TYPE_MISMATCH ); + release_object( fsync ); + return; + } + + reply->type = fsync->type; + reply->shm_idx = fsync->shm_idx; + release_object( fsync ); + } +} /* Retrieve the index of a shm section which will be signaled by the server. */ DECL_HANDLER(get_fsync_idx) diff --git a/server/protocol.def b/server/protocol.def index 85891ef7ef9..00dc3e7f0e6 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3917,6 +3917,19 @@ enum fsync_type unsigned int shm_idx; /* this object's index into the shm section */ @END +/* Open an fsync object */ +@REQ(open_fsync) + unsigned int access; /* wanted access rights */ + unsigned int attributes; /* object attributes */ + obj_handle_t rootdir; /* root directory */ + int type; /* type of fsync object */ + VARARG(name,unicode_str); /* object name */ +@REPLY + obj_handle_t handle; /* handle to the event */ + int type; /* type of fsync object */ + unsigned int shm_idx; /* this object's index into the shm section */ +@END + /* Retrieve the shm index for an object. */ @REQ(get_fsync_idx) obj_handle_t handle; /* handle to the object */ From 6c34389e49a0880d48216f742fee4fd8322e3f5d Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 2 Sep 2018 12:05:37 -0500 Subject: [PATCH 0427/2777] ntdll: Implement NtOpenEvent(). --- dlls/ntdll/unix/fsync.c | 8 ++++++++ dlls/ntdll/unix/fsync.h | 2 ++ dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 13 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 3dc20e18ddc..6015e5087c3 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -444,6 +444,14 @@ NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, return create_fsync( type, handle, access, attr, initial, 0xdeadbeef ); } +NTSTATUS fsync_open_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ) +{ + TRACE("name %s.\n", debugstr_us(attr->ObjectName)); + + return open_fsync( FSYNC_AUTO_EVENT, handle, access, attr ); +} + NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) { struct event *event; diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h index 2b4f26d51a3..71229e3fde3 100644 --- a/dlls/ntdll/unix/fsync.h +++ b/dlls/ntdll/unix/fsync.h @@ -29,6 +29,8 @@ extern NTSTATUS fsync_open_semaphore( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN; +extern NTSTATUS fsync_open_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index deac0df28fa..022add521b6 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -440,6 +440,9 @@ NTSTATUS WINAPI NtOpenEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_AT *handle = 0; if ((ret = validate_open_object_attributes( attr ))) return ret; + if (do_fsync()) + return fsync_open_event( handle, access, attr ); + if (do_esync()) return esync_open_event( handle, access, attr ); From 025bd856ec766cfc175dcac29486c49db0954d16 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 2 Sep 2018 12:06:40 -0500 Subject: [PATCH 0428/2777] ntdll: Implement NtOpenMutant(). --- dlls/ntdll/unix/fsync.c | 8 ++++++++ dlls/ntdll/unix/fsync.h | 2 ++ dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 13 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 6015e5087c3..4ea41113c32 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -499,6 +499,14 @@ NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, initial ? GetCurrentThreadId() : 0, initial ? 1 : 0 ); } +NTSTATUS fsync_open_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ) +{ + TRACE("name %s.\n", debugstr_us(attr->ObjectName)); + + return open_fsync( FSYNC_MUTEX, handle, access, attr ); +} + NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) { struct mutex *mutex; diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h index 71229e3fde3..5c72693bbf4 100644 --- a/dlls/ntdll/unix/fsync.h +++ b/dlls/ntdll/unix/fsync.h @@ -35,6 +35,8 @@ extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) DECLSPEC_HIDDEN; +extern NTSTATUS fsync_open_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 022add521b6..7299804327d 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -628,6 +628,9 @@ NTSTATUS WINAPI NtOpenMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT_A *handle = 0; if ((ret = validate_open_object_attributes( attr ))) return ret; + if (do_fsync()) + return fsync_open_mutex( handle, access, attr ); + if (do_esync()) return esync_open_mutex( handle, access, attr ); From d769959fb3b852c26d75ee96e0bc4c6a9b5f0bd2 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 2 Sep 2018 12:07:48 -0500 Subject: [PATCH 0429/2777] server: Implement fsync_map_access(). --- server/fsync.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/server/fsync.c b/server/fsync.c index 3fbc1734735..1df3aff91b6 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -131,6 +131,7 @@ struct fsync }; static void fsync_dump( struct object *obj, int verbose ); +static unsigned int fsync_map_access( struct object *obj, unsigned int access ); static void fsync_destroy( struct object *obj ); const struct object_ops fsync_ops = @@ -146,7 +147,7 @@ const struct object_ops fsync_ops = NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ - default_map_access, /* map_access */ + fsync_map_access, /* map_access */ default_get_sd, /* get_sd */ default_set_sd, /* set_sd */ default_get_full_name, /* get_full_name */ @@ -166,6 +167,16 @@ static void fsync_dump( struct object *obj, int verbose ) fprintf( stderr, "fsync idx=%d\n", fsync->shm_idx ); } +static unsigned int fsync_map_access( struct object *obj, unsigned int access ) +{ + /* Sync objects have the same flags. */ + if (access & GENERIC_READ) access |= STANDARD_RIGHTS_READ | EVENT_QUERY_STATE; + if (access & GENERIC_WRITE) access |= STANDARD_RIGHTS_WRITE | EVENT_MODIFY_STATE; + if (access & GENERIC_EXECUTE) access |= STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE; + if (access & GENERIC_ALL) access |= STANDARD_RIGHTS_ALL | EVENT_QUERY_STATE | EVENT_MODIFY_STATE; + return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); +} + static void fsync_destroy( struct object *obj ) { } From 8537cc0c166951072a4e475b23a90add8f13cd4f Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 2 Sep 2018 12:12:10 -0500 Subject: [PATCH 0430/2777] ntdll, server: Implement handle duplication. --- dlls/ntdll/unix/fsync.c | 16 ++++++++++------ server/fsync.c | 10 +++++++++- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 4ea41113c32..c779b57489f 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -411,10 +411,11 @@ NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) struct fsync *obj; struct semaphore *semaphore; ULONG current; + NTSTATUS ret; TRACE("%p, %d, %p.\n", handle, (int)count, prev); - if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; + if ((ret = get_object( handle, &obj ))) return ret; semaphore = obj->shm; do @@ -457,10 +458,11 @@ NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) struct event *event; struct fsync *obj; LONG current; + NTSTATUS ret; TRACE("%p.\n", handle); - if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; + if ((ret = get_object( handle, &obj ))) return ret; event = obj->shm; if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))) @@ -476,10 +478,11 @@ NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) struct event *event; struct fsync *obj; LONG current; + NTSTATUS ret; TRACE("%p.\n", handle); - if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; + if ((ret = get_object( handle, &obj ))) return ret; event = obj->shm; current = __atomic_exchange_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); @@ -511,10 +514,11 @@ NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) { struct mutex *mutex; struct fsync *obj; + NTSTATUS ret; TRACE("%p, %p.\n", handle, prev); - if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; + if ((ret = get_object( handle, &obj ))) return ret; mutex = obj->shm; if (mutex->tid != GetCurrentThreadId()) return STATUS_MUTANT_NOT_OWNED; @@ -975,10 +979,10 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an NTSTATUS fsync_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable, const LARGE_INTEGER *timeout ) { - struct fsync *obj = get_cached_object( signal ); + struct fsync *obj; NTSTATUS ret; - if (!obj) return STATUS_INVALID_HANDLE; + if ((ret = get_object( signal, &obj ))) return ret; switch (obj->type) { diff --git a/server/fsync.c b/server/fsync.c index 1df3aff91b6..73d1873759b 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -131,6 +131,7 @@ struct fsync }; static void fsync_dump( struct object *obj, int verbose ); +static unsigned int fsync_get_fsync_idx( struct object *obj, enum fsync_type *type ); static unsigned int fsync_map_access( struct object *obj, unsigned int access ); static void fsync_destroy( struct object *obj ); @@ -143,7 +144,7 @@ const struct object_ops fsync_ops = NULL, /* remove_queue */ NULL, /* signaled */ NULL, /* get_esync_fd */ - NULL, /* get_fsync_idx */ + fsync_get_fsync_idx, /* get_fsync_idx */ NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -167,6 +168,13 @@ static void fsync_dump( struct object *obj, int verbose ) fprintf( stderr, "fsync idx=%d\n", fsync->shm_idx ); } +static unsigned int fsync_get_fsync_idx( struct object *obj, enum fsync_type *type) +{ + struct fsync *fsync = (struct fsync *)obj; + *type = fsync->type; + return fsync->shm_idx; +} + static unsigned int fsync_map_access( struct object *obj, unsigned int access ) { /* Sync objects have the same flags. */ From 6bca54ef9ce57f7fc0d439013461c3321ff10626 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 2 Sep 2018 13:19:09 -0500 Subject: [PATCH 0431/2777] ntdll, server: Implement alertable waits. --- dlls/ntdll/unix/fsync.c | 107 +++++++++++++++++++++++++++++---- dlls/ntdll/unix/unix_private.h | 1 + dlls/ntdll/unix/virtual.c | 1 + server/fsync.c | 33 ++++++---- server/fsync.h | 2 + server/protocol.def | 5 ++ server/thread.c | 10 +++ server/thread.h | 1 + 8 files changed, 135 insertions(+), 25 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index c779b57489f..0f434610f66 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -545,20 +545,53 @@ static LONGLONG update_timeout( ULONGLONG end ) return timeleft; } -static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end ) +static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN alertable ) { int ret; - if (end) + if (alertable) { - LONGLONG timeleft = update_timeout( *end ); - struct timespec tmo_p; - tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; - tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; - ret = futex_wait( addr, val, &tmo_p ); + struct event *apc_event = get_shm( ntdll_get_thread_data()->fsync_apc_idx ); + struct futex_wait_block futexes[2]; + + if (__atomic_load_n( &apc_event->signaled, __ATOMIC_SEQ_CST )) + return STATUS_USER_APC; + + futexes[0].addr = addr; + futexes[0].val = val; + futexes[1].addr = &apc_event->signaled; + futexes[1].val = 0; +#if __SIZEOF_POINTER__ == 4 + futexes[0].pad = futexes[1].pad = 0; +#endif + + if (end) + { + LONGLONG timeleft = update_timeout( *end ); + struct timespec tmo_p; + tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; + tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; + ret = futex_wait_multiple( futexes, 2, &tmo_p ); + } + else + ret = futex_wait_multiple( futexes, 2, NULL ); + + if (__atomic_load_n( &apc_event->signaled, __ATOMIC_SEQ_CST )) + return STATUS_USER_APC; } else - ret = futex_wait( addr, val, NULL ); + { + if (end) + { + LONGLONG timeleft = update_timeout( *end ); + struct timespec tmo_p; + tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; + tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; + ret = futex_wait( addr, val, &tmo_p ); + } + else + ret = futex_wait( addr, val, NULL ); + } if (!ret) return 0; @@ -571,16 +604,30 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end ) static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) { - struct futex_wait_block futexes[MAXIMUM_WAIT_OBJECTS]; + static const LARGE_INTEGER zero = {0}; + + struct futex_wait_block futexes[MAXIMUM_WAIT_OBJECTS + 1]; struct fsync *objs[MAXIMUM_WAIT_OBJECTS]; int has_fsync = 0, has_server = 0; BOOL msgwait = FALSE; int dummy_futex = 0; LONGLONG timeleft; LARGE_INTEGER now; + DWORD waitcount; ULONGLONG end; int i, ret; + /* Grab the APC futex if we don't already have it. */ + if (alertable && !ntdll_get_thread_data()->fsync_apc_idx) + { + SERVER_START_REQ( get_fsync_apc_idx ) + { + if (!(ret = wine_server_call( req ))) + ntdll_get_thread_data()->fsync_apc_idx = reply->shm_idx; + } + SERVER_END_REQ; + } + NtQuerySystemTime( &now ); if (timeout) { @@ -619,6 +666,8 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, if (msgwait) TRACE(" or driver events"); + if (alertable) + TRACE(", alertable"); if (!timeout) TRACE(", timeout = INFINITE.\n"); @@ -732,6 +781,21 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, #endif } + if (alertable) + { + struct event *event = get_shm( ntdll_get_thread_data()->fsync_apc_idx ); + if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) + goto userapc; + + futexes[i].addr = &event->signaled; + futexes[i].val = 0; +#if __SIZEOF_POINTER__ == 4 + futexes[i].pad = 0; +#endif + i++; + } + waitcount = i; + /* Looks like everything is contended, so wait. */ if (timeout) @@ -741,10 +805,10 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; - ret = futex_wait_multiple( futexes, count, &tmo_p ); + ret = futex_wait_multiple( futexes, waitcount, &tmo_p ); } else - ret = futex_wait_multiple( futexes, count, NULL ); + ret = futex_wait_multiple( futexes, waitcount, NULL ); /* FUTEX_WAIT_MULTIPLE can succeed or return -EINTR, -EAGAIN, * -EFAULT/-EACCES, -ETIMEDOUT. In the first three cases we need to @@ -801,7 +865,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, while ((current = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ))) { - status = do_single_wait( &mutex->tid, current, timeout ? &end : NULL ); + status = do_single_wait( &mutex->tid, current, timeout ? &end : NULL, alertable ); if (status != STATUS_PENDING) break; } @@ -813,7 +877,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, while (!__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) { - status = do_single_wait( &event->signaled, 0, timeout ? &end : NULL ); + status = do_single_wait( &event->signaled, 0, timeout ? &end : NULL, alertable ); if (status != STATUS_PENDING) break; } @@ -824,6 +888,8 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, TRACE("Wait timed out.\n"); return status; } + else if (status == STATUS_USER_APC) + goto userapc; } /* If we got here and we haven't timed out, that means all of the @@ -932,6 +998,21 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, } } /* while (1) */ } /* else (wait-all) */ + + assert(0); /* shouldn't reach here... */ + +userapc: + TRACE("Woken up by user APC.\n"); + + /* We have to make a server call anyway to get the APC to execute, so just + * delegate down to server_wait(). */ + ret = server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, &zero ); + + /* This can happen if we received a system APC, and the APC fd was woken up + * before we got SIGUSR1. poll() doesn't return EINTR in that case. The + * right thing to do seems to be to return STATUS_USER_APC anyway. */ + if (ret == STATUS_TIMEOUT) ret = STATUS_USER_APC; + return ret; } /* Like esync, we need to let the server know when we are doing a message wait, diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index ef74fdc82f1..620a849afb3 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -59,6 +59,7 @@ struct ntdll_thread_data void *cpu_data[16]; /* reserved for CPU-specific data */ void *kernel_stack; /* stack for thread startup and kernel syscalls */ int esync_apc_fd; /* fd to wait on for user APCs */ + unsigned int fsync_apc_idx; int request_fd; /* fd for sending server requests */ int reply_fd; /* fd for receiving server replies */ int wait_fd[2]; /* fd for sleeping server requests */ diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 121eacc06c7..544c4c27aa8 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -2938,6 +2938,7 @@ static TEB *init_teb( void *ptr, BOOL is_wow ) teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; thread_data->esync_apc_fd = -1; + thread_data->fsync_apc_idx = 0; thread_data->request_fd = -1; thread_data->reply_fd = -1; thread_data->wait_fd[0] = -1; diff --git a/server/fsync.c b/server/fsync.c index 73d1873759b..10d8eb74bc3 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -316,31 +316,35 @@ struct fsync_event int unused; }; +void fsync_wake_futex( unsigned int shm_idx ) +{ + struct fsync_event *event = get_shm( shm_idx ); + + if (!__atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST )) + futex_wake( &event->signaled, INT_MAX ); +} + void fsync_wake_up( struct object *obj ) { - struct fsync_event *event; enum fsync_type type; if (obj->ops->get_fsync_idx) - { - event = get_shm( obj->ops->get_fsync_idx( obj, &type ) ); + fsync_wake_futex( obj->ops->get_fsync_idx( obj, &type ) ); +} - if (!__atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST )) - futex_wake( &event->signaled, INT_MAX ); - } +void fsync_clear_futex( unsigned int shm_idx ) +{ + struct fsync_event *event = get_shm( shm_idx ); + + __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); } void fsync_clear( struct object *obj ) { - struct fsync_event *event; enum fsync_type type; if (obj->ops->get_fsync_idx) - { - event = get_shm( obj->ops->get_fsync_idx( obj, &type ) ); - - __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); - } + fsync_clear_futex( obj->ops->get_fsync_idx( obj, &type ) ); } void fsync_set_event( struct fsync *fsync ) @@ -447,3 +451,8 @@ DECL_HANDLER(get_fsync_idx) release_object( obj ); } + +DECL_HANDLER(get_fsync_apc_idx) +{ + reply->shm_idx = current->fsync_apc_idx; +} diff --git a/server/fsync.h b/server/fsync.h index 087d482717b..f6f1a48b31e 100644 --- a/server/fsync.h +++ b/server/fsync.h @@ -21,6 +21,8 @@ extern int do_fsync(void); extern void fsync_init(void); extern unsigned int fsync_alloc_shm( int low, int high ); +extern void fsync_wake_futex( unsigned int shm_idx ); +extern void fsync_clear_futex( unsigned int shm_idx ); extern void fsync_wake_up( struct object *obj ); extern void fsync_clear( struct object *obj ); diff --git a/server/protocol.def b/server/protocol.def index 00dc3e7f0e6..7e31038dc2c 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3941,3 +3941,8 @@ enum fsync_type @REQ(fsync_msgwait) int in_msgwait; /* are we in a message wait? */ @END + +@REQ(get_fsync_apc_idx) +@REPLY + unsigned int shm_idx; +@END diff --git a/server/thread.c b/server/thread.c index 615198ebe67..000a3d0e4ae 100644 --- a/server/thread.c +++ b/server/thread.c @@ -487,7 +487,10 @@ struct thread *create_thread( int fd, struct process *process, const struct secu } if (do_fsync()) + { thread->fsync_idx = fsync_alloc_shm( 0, 0 ); + thread->fsync_apc_idx = fsync_alloc_shm( 0, 0 ); + } if (do_esync()) { @@ -666,6 +669,7 @@ static struct thread_apc *create_apc( struct object *owner, const apc_call_t *ca apc->result.type = APC_NONE; if (owner) grab_object( owner ); } + return apc; } @@ -1366,6 +1370,9 @@ static int queue_apc( struct process *process, struct thread *thread, struct thr { wake_thread( thread ); + if (do_fsync() && queue == &thread->user_apc) + fsync_wake_futex( thread->fsync_apc_idx ); + if (do_esync() && queue == &thread->user_apc) esync_wake_fd( thread->esync_apc_fd ); } @@ -1416,6 +1423,9 @@ static struct thread_apc *thread_dequeue_apc( struct thread *thread, int system list_remove( ptr ); } + if (do_fsync() && list_empty( &thread->system_apc ) && list_empty( &thread->user_apc )) + fsync_clear_futex( thread->fsync_apc_idx ); + if (do_esync() && list_empty( &thread->system_apc ) && list_empty( &thread->user_apc )) esync_clear( thread->esync_apc_fd ); diff --git a/server/thread.h b/server/thread.h index f9b145fa6b9..023afba9e4d 100644 --- a/server/thread.h +++ b/server/thread.h @@ -57,6 +57,7 @@ struct thread int esync_fd; /* esync file descriptor (signalled on exit) */ int esync_apc_fd; /* esync apc fd (signalled when APCs are present) */ unsigned int fsync_idx; + unsigned int fsync_apc_idx; unsigned int system_regs; /* which system regs have been set */ struct msg_queue *queue; /* message queue */ struct thread_wait *wait; /* current wait condition if sleeping */ From 7192590edc9cd5b4d43dc952ac5b5762031b298d Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 3 Mar 2019 10:45:10 -0600 Subject: [PATCH 0432/2777] ntdll: Wake all threads in futex_wake(). Because wait-all exists, this unfortunately seems necessary. --- dlls/ntdll/unix/fsync.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 0f434610f66..489a52ddbf7 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -427,8 +427,7 @@ NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) if (prev) *prev = current; - if (!current) - futex_wake( &semaphore->count, count ); + futex_wake( &semaphore->count, INT_MAX ); return STATUS_SUCCESS; } @@ -466,7 +465,7 @@ NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) event = obj->shm; if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))) - futex_wake( &event->signaled, obj->type == FSYNC_AUTO_EVENT ? 1 : INT_MAX ); + futex_wake( &event->signaled, INT_MAX ); if (prev) *prev = current; @@ -528,7 +527,7 @@ NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) if (!--mutex->count) { __atomic_store_n( &mutex->tid, 0, __ATOMIC_SEQ_CST ); - futex_wake( &mutex->tid, 1 ); + futex_wake( &mutex->tid, INT_MAX ); } return STATUS_SUCCESS; From 74156474866e2780416f9e0c5fbc4a41334255d9 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 3 Mar 2019 11:02:28 -0600 Subject: [PATCH 0433/2777] server: Create futex sections for timer objects. --- dlls/ntdll/unix/fsync.c | 3 +++ server/protocol.def | 1 + server/timer.c | 18 +++++++++++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 489a52ddbf7..877a9531caf 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -735,6 +735,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, break; } case FSYNC_AUTO_EVENT: + case FSYNC_AUTO_SERVER: { struct event *event = obj->shm; @@ -939,6 +940,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, break; } case FSYNC_AUTO_EVENT: + case FSYNC_AUTO_SERVER: { struct event *event = obj->shm; if (!__sync_val_compare_and_swap( &event->signaled, 1, 0 )) @@ -985,6 +987,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, break; } case FSYNC_AUTO_EVENT: + case FSYNC_AUTO_SERVER: { struct event *event = obj->shm; __atomic_store_n( &event->signaled, 1, __ATOMIC_SEQ_CST ); diff --git a/server/protocol.def b/server/protocol.def index 7e31038dc2c..a7cd4b8c7d4 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3900,6 +3900,7 @@ enum fsync_type FSYNC_AUTO_EVENT, FSYNC_MANUAL_EVENT, FSYNC_MUTEX, + FSYNC_AUTO_SERVER, FSYNC_MANUAL_SERVER, FSYNC_QUEUE, }; diff --git a/server/timer.c b/server/timer.c index 9ec9604aa0e..afc12ff03ad 100644 --- a/server/timer.c +++ b/server/timer.c @@ -36,6 +36,7 @@ #include "handle.h" #include "request.h" #include "esync.h" +#include "fsync.h" static const WCHAR timer_name[] = {'T','i','m','e','r'}; @@ -63,11 +64,13 @@ struct timer client_ptr_t callback; /* callback APC function */ client_ptr_t arg; /* callback argument */ int esync_fd; /* esync file descriptor */ + unsigned int fsync_idx; /* fsync shm index */ }; static void timer_dump( struct object *obj, int verbose ); static int timer_signaled( struct object *obj, struct wait_queue_entry *entry ); static int timer_get_esync_fd( struct object *obj, enum esync_type *type ); +static unsigned int timer_get_fsync_idx( struct object *obj, enum fsync_type *type ); static void timer_satisfied( struct object *obj, struct wait_queue_entry *entry ); static void timer_destroy( struct object *obj ); @@ -80,7 +83,7 @@ static const struct object_ops timer_ops = remove_queue, /* remove_queue */ timer_signaled, /* signaled */ timer_get_esync_fd, /* get_esync_fd */ - NULL, /* get_fsync_idx */ + timer_get_fsync_idx, /* get_fsync_idx */ timer_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -117,6 +120,9 @@ static struct timer *create_timer( struct object *root, const struct unicode_str timer->thread = NULL; timer->esync_fd = -1; + if (do_fsync()) + timer->fsync_idx = fsync_alloc_shm( 0, 0 ); + if (do_esync()) timer->esync_fd = esync_create_fd( 0, 0 ); } @@ -191,6 +197,9 @@ static int set_timer( struct timer *timer, timeout_t expire, unsigned int period period = 0; /* period doesn't make any sense for a manual timer */ timer->signaled = 0; + if (do_fsync()) + fsync_clear( &timer->obj ); + if (do_esync()) esync_clear( timer->esync_fd ); } @@ -227,6 +236,13 @@ static int timer_get_esync_fd( struct object *obj, enum esync_type *type ) return timer->esync_fd; } +static unsigned int timer_get_fsync_idx( struct object *obj, enum fsync_type *type ) +{ + struct timer *timer = (struct timer *)obj; + *type = timer->manual ? FSYNC_MANUAL_SERVER : FSYNC_AUTO_SERVER; + return timer->fsync_idx; +} + static void timer_satisfied( struct object *obj, struct wait_queue_entry *entry ) { struct timer *timer = (struct timer *)obj; From b918a7361e25026ce8266aeff800a52cf5509ceb Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 3 Mar 2019 11:07:55 -0600 Subject: [PATCH 0434/2777] server: Create futex sections for console input events objects. --- server/console.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/server/console.c b/server/console.c index 8279ad468e1..c229268f834 100644 --- a/server/console.c +++ b/server/console.c @@ -42,6 +42,7 @@ #include "winternl.h" #include "wine/condrv.h" #include "esync.h" +#include "fsync.h" struct screen_buffer; @@ -143,12 +144,14 @@ struct console_server int term_fd; /* UNIX terminal fd */ struct termios termios; /* original termios */ int esync_fd; + unsigned int fsync_idx; }; static void console_server_dump( struct object *obj, int verbose ); static void console_server_destroy( struct object *obj ); static int console_server_signaled( struct object *obj, struct wait_queue_entry *entry ); static int console_server_get_esync_fd( struct object *obj, enum esync_type *type ); +static unsigned int console_server_get_fsync_idx( struct object *obj, enum fsync_type *type ); static struct fd *console_server_get_fd( struct object *obj ); static struct object *console_server_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attr, struct object *root ); @@ -164,7 +167,7 @@ static const struct object_ops console_server_ops = remove_queue, /* remove_queue */ console_server_signaled, /* signaled */ console_server_get_esync_fd, /* get_esync_fd */ - NULL, /* get_fsync_idx */ + console_server_get_fsync_idx, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ console_server_get_fd, /* get_fd */ @@ -607,6 +610,8 @@ static void disconnect_console_server( struct console_server *server ) list_remove( &call->entry ); console_host_ioctl_terminate( call, STATUS_CANCELLED ); } + if (do_fsync()) + fsync_clear( &server->obj ); if (do_esync()) esync_clear( server->esync_fd ); while (!list_empty( &server->read_queue )) @@ -938,6 +943,13 @@ static int console_server_get_esync_fd( struct object *obj, enum esync_type *typ return server->esync_fd; } +static unsigned int console_server_get_fsync_idx( struct object *obj, enum fsync_type *type ) +{ + struct console_server *server = (struct console_server*)obj; + *type = FSYNC_MANUAL_SERVER; + return server->fsync_idx; +} + static struct fd *console_server_get_fd( struct object* obj ) { struct console_server *server = (struct console_server*)obj; @@ -970,6 +982,10 @@ static struct object *create_console_server( void ) } allow_fd_caching(server->fd); server->esync_fd = -1; + server->fsync_idx = 0; + + if (do_fsync()) + server->fsync_idx = fsync_alloc_shm( 0, 0 ); if (do_esync()) server->esync_fd = esync_create_fd( 0, 0 ); @@ -1586,6 +1602,8 @@ DECL_HANDLER(get_next_console_request) /* set result of previous ioctl */ ioctl = LIST_ENTRY( list_head( &server->queue ), struct console_host_ioctl, entry ); list_remove( &ioctl->entry ); + if (do_fsync() && list_empty( &server->queue )) + fsync_clear( &server->obj ); if (do_esync() && list_empty( &server->queue )) esync_clear( server->esync_fd ); } @@ -1673,6 +1691,8 @@ DECL_HANDLER(get_next_console_request) { set_error( STATUS_PENDING ); } + if (do_fsync() && list_empty( &server->queue )) + fsync_clear( &server->obj ); if (do_esync() && list_empty( &server->queue )) esync_clear( server->esync_fd ); From 6415b4ad427e836437f07063a17d30b5e678f8d2 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 3 Mar 2019 11:23:23 -0600 Subject: [PATCH 0435/2777] ntdll: Implement NtQuerySemaphore(). --- dlls/ntdll/unix/fsync.c | 19 +++++++++++++++++++ dlls/ntdll/unix/fsync.h | 1 + dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 23 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 877a9531caf..ca73b48fd74 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -432,6 +432,25 @@ NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) return STATUS_SUCCESS; } +NTSTATUS fsync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len ) +{ + struct fsync *obj; + struct semaphore *semaphore; + SEMAPHORE_BASIC_INFORMATION *out = info; + NTSTATUS ret; + + TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); + + if ((ret = get_object( handle, &obj ))) return ret; + semaphore = obj->shm; + + out->CurrentCount = semaphore->count; + out->MaximumCount = semaphore->max; + if (ret_len) *ret_len = sizeof(*out); + + return STATUS_SUCCESS; +} + NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, EVENT_TYPE event_type, BOOLEAN initial ) { diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h index 5c72693bbf4..e0b4edac153 100644 --- a/dlls/ntdll/unix/fsync.h +++ b/dlls/ntdll/unix/fsync.h @@ -27,6 +27,7 @@ extern NTSTATUS fsync_create_semaphore(HANDLE *handle, ACCESS_MASK access, extern NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_open_semaphore( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; +extern NTSTATUS fsync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_open_event( HANDLE *handle, ACCESS_MASK access, diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 7299804327d..c50cb217c94 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -348,6 +348,9 @@ NTSTATUS WINAPI NtQuerySemaphore( HANDLE handle, SEMAPHORE_INFORMATION_CLASS cla if (len != sizeof(SEMAPHORE_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; + if (do_fsync()) + return fsync_query_semaphore( handle, info, ret_len ); + if (do_esync()) return esync_query_semaphore( handle, info, ret_len ); From 0d508cfb9f70367b6d3d6ba197aed51714fe65f4 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 20:11:08 -0500 Subject: [PATCH 0436/2777] ntdll: Implement NtQueryEvent(). --- dlls/ntdll/unix/fsync.c | 19 +++++++++++++++++++ dlls/ntdll/unix/fsync.h | 1 + dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 23 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index ca73b48fd74..84d400871c1 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -510,6 +510,25 @@ NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) return STATUS_SUCCESS; } +NTSTATUS fsync_query_event( HANDLE handle, void *info, ULONG *ret_len ) +{ + struct event *event; + struct fsync *obj; + EVENT_BASIC_INFORMATION *out = info; + NTSTATUS ret; + + TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); + + if ((ret = get_object( handle, &obj ))) return ret; + event = obj->shm; + + out->EventState = event->signaled; + out->EventType = (obj->type == FSYNC_AUTO_EVENT ? SynchronizationEvent : NotificationEvent); + if (ret_len) *ret_len = sizeof(*out); + + return STATUS_SUCCESS; +} + NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) { diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h index e0b4edac153..12eda935638 100644 --- a/dlls/ntdll/unix/fsync.h +++ b/dlls/ntdll/unix/fsync.h @@ -34,6 +34,7 @@ extern NTSTATUS fsync_open_event( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; +extern NTSTATUS fsync_query_event( HANDLE handle, void *info, ULONG *ret_len ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_open_mutex( HANDLE *handle, ACCESS_MASK access, diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index c50cb217c94..2f41400242a 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -568,6 +568,9 @@ NTSTATUS WINAPI NtQueryEvent( HANDLE handle, EVENT_INFORMATION_CLASS class, if (len != sizeof(EVENT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; + if (do_fsync()) + return fsync_query_event( handle, info, ret_len ); + if (do_esync()) return esync_query_event( handle, info, ret_len ); From 5829818d444fbd318e7e541ea3a7f5e10e0f52ae Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 3 Mar 2019 11:29:55 -0600 Subject: [PATCH 0437/2777] ntdll: Implement NtQueryMutant(). --- dlls/ntdll/unix/fsync.c | 20 ++++++++++++++++++++ dlls/ntdll/unix/fsync.h | 1 + dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 24 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 84d400871c1..dd3748f62b0 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -571,6 +571,26 @@ NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) return STATUS_SUCCESS; } +NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) +{ + struct fsync *obj; + struct mutex *mutex; + MUTANT_BASIC_INFORMATION *out = info; + NTSTATUS ret; + + TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); + + if ((ret = get_object( handle, &obj ))) return ret; + mutex = obj->shm; + + out->CurrentCount = 1 - mutex->count; + out->OwnedByCaller = (mutex->tid == GetCurrentThreadId()); + out->AbandonedState = FALSE; + if (ret_len) *ret_len = sizeof(*out); + + return STATUS_SUCCESS; +} + static LONGLONG update_timeout( ULONGLONG end ) { LARGE_INTEGER now; diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h index 12eda935638..38a6c8f0f70 100644 --- a/dlls/ntdll/unix/fsync.h +++ b/dlls/ntdll/unix/fsync.h @@ -40,6 +40,7 @@ extern NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, extern NTSTATUS fsync_open_mutex( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; +extern NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 2f41400242a..434cf9e1a76 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -698,6 +698,9 @@ NTSTATUS WINAPI NtQueryMutant( HANDLE handle, MUTANT_INFORMATION_CLASS class, if (len != sizeof(MUTANT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; + if (do_fsync()) + return fsync_query_mutex( handle, info, ret_len ); + if (do_esync()) return esync_query_mutex( handle, info, ret_len ); From 724609dba8f6feed91c0b2b481de4ae6d5aac050 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 3 Mar 2019 11:35:22 -0600 Subject: [PATCH 0438/2777] server: Create futex sections for pseudo-fd objects and use them for named pipes. --- server/fd.c | 18 ++++++++++++++++++ server/file.h | 1 + server/named_pipe.c | 4 ++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/server/fd.c b/server/fd.c index 66f9bc01e34..7ade1601e4d 100644 --- a/server/fd.c +++ b/server/fd.c @@ -97,6 +97,7 @@ #include "process.h" #include "request.h" #include "esync.h" +#include "fsync.h" #include "winternl.h" #include "winioctl.h" @@ -195,6 +196,7 @@ struct fd apc_param_t comp_key; /* completion key to set in completion events */ unsigned int comp_flags; /* completion flags */ int esync_fd; /* esync file descriptor */ + unsigned int fsync_idx; /* fsync shm index */ }; static void fd_dump( struct object *obj, int verbose ); @@ -1766,8 +1768,12 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use list_init( &fd->inode_entry ); list_init( &fd->locks ); + if (do_fsync()) + fd->fsync_idx = fsync_alloc_shm( 0, 0 ); + if (do_esync()) fd->esync_fd = esync_create_fd( 0, 0 ); + return fd; } @@ -2193,6 +2199,9 @@ void set_fd_signaled( struct fd *fd, int signaled ) fd->signaled = signaled; if (signaled) wake_up( fd->user, 0 ); + if (do_fsync() && !signaled) + fsync_clear( &fd->obj ); + if (do_esync() && !signaled) esync_clear( fd->esync_fd ); } @@ -2229,6 +2238,15 @@ int default_fd_get_esync_fd( struct object *obj, enum esync_type *type ) return ret; } +unsigned int default_fd_get_fsync_idx( struct object *obj, enum fsync_type *type ) +{ + struct fd *fd = get_obj_fd( obj ); + unsigned int ret = fd->fsync_idx; + *type = FSYNC_MANUAL_SERVER; + release_object( fd ); + return ret; +} + int default_fd_get_poll_events( struct fd *fd ) { int events = 0; diff --git a/server/file.h b/server/file.h index 7069a60e492..ffcbe102156 100644 --- a/server/file.h +++ b/server/file.h @@ -107,6 +107,7 @@ extern void get_nt_name( struct fd *fd, struct unicode_str *name ); extern int default_fd_signaled( struct object *obj, struct wait_queue_entry *entry ); extern int default_fd_get_esync_fd( struct object *obj, enum esync_type *type ); +extern unsigned int default_fd_get_fsync_idx( struct object *obj, enum fsync_type *type ); extern int default_fd_get_poll_events( struct fd *fd ); extern void default_poll_event( struct fd *fd, int event ); extern void fd_cancel_async( struct fd *fd, struct async *async ); diff --git a/server/named_pipe.c b/server/named_pipe.c index b6169062781..6679f4cc3a0 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -170,7 +170,7 @@ static const struct object_ops pipe_server_ops = remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ default_fd_get_esync_fd, /* get_esync_fd */ - NULL, /* get_fsync_idx */ + default_fd_get_fsync_idx, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ pipe_end_get_fd, /* get_fd */ @@ -216,7 +216,7 @@ static const struct object_ops pipe_client_ops = remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ default_fd_get_esync_fd, /* get_esync_fd */ - NULL, /* get_fsync_idx */ + default_fd_get_fsync_idx, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ pipe_end_get_fd, /* get_fd */ From 43732137b8f7260364ae8b578156274014192535 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sun, 3 Mar 2019 11:44:00 -0600 Subject: [PATCH 0439/2777] server: Create futex sections for true file objects and use them for directory change notifications. --- server/change.c | 2 +- server/fd.c | 3 +++ server/fsync.c | 13 ++++++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/server/change.c b/server/change.c index 72b4232cd41..df79e5c8524 100644 --- a/server/change.c +++ b/server/change.c @@ -113,7 +113,7 @@ static const struct object_ops dir_ops = remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ default_fd_get_esync_fd, /* get_esync_fd */ - NULL, /* get_fsync_idx */ + default_fd_get_fsync_idx, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ dir_get_fd, /* get_fd */ diff --git a/server/fd.c b/server/fd.c index 7ade1601e4d..b3e4d591383 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1728,6 +1728,9 @@ static struct fd *alloc_fd_object(void) if (do_esync()) fd->esync_fd = esync_create_fd( 1, 0 ); + if (do_fsync()) + fd->fsync_idx = fsync_alloc_shm( 1, 0 ); + if ((fd->poll_index = add_poll_user( fd )) == -1) { release_object( fd ); diff --git a/server/fsync.c b/server/fsync.c index 10d8eb74bc3..6a67d22d14e 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -85,6 +85,8 @@ static void **shm_addrs; static int shm_addrs_size; /* length of the allocated shm_addrs array */ static long pagesize; +static int is_fsync_initialized; + static void shm_cleanup(void) { close( shm_fd ); @@ -120,6 +122,8 @@ void fsync_init(void) if (ftruncate( shm_fd, shm_size ) == -1) perror( "ftruncate" ); + is_fsync_initialized = 1; + atexit( shm_cleanup ); } @@ -231,9 +235,16 @@ static unsigned int shm_idx_counter = 1; unsigned int fsync_alloc_shm( int low, int high ) { #ifdef __linux__ - int shm_idx = shm_idx_counter++; + int shm_idx; int *shm; + /* this is arguably a bit of a hack, but we need some way to prevent + * allocating shm for the master socket */ + if (!is_fsync_initialized) + return 0; + + shm_idx = shm_idx_counter++; + while (shm_idx * 8 >= shm_size) { /* Better expand the shm section. */ From 4058cc4c08b2696e1f2e48b6c506f362e8e89404 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Tue, 4 Jun 2019 12:29:31 -0500 Subject: [PATCH 0440/2777] ntdll: Skip zero-length waits. An optimization that avoids a syscall. --- dlls/ntdll/unix/fsync.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index dd3748f62b0..253439b7dfb 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -856,7 +856,14 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, /* Looks like everything is contended, so wait. */ - if (timeout) + if (timeout && !timeout->QuadPart) + { + /* Unlike esync, we already know that we've timed out, so we + * can avoid a syscall. */ + TRACE("Wait timed out.\n"); + return STATUS_TIMEOUT; + } + else if (timeout) { LONGLONG timeleft = update_timeout( end ); struct timespec tmo_p; From 472e62576a4d6d46e5cdd4cfa26dcb6eea38afbd Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Thu, 13 Jun 2019 12:58:27 -0500 Subject: [PATCH 0441/2777] server: Add a diagnostic message for fsync. --- server/fsync.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/fsync.c b/server/fsync.c index 6a67d22d14e..d4dbd66d22a 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -124,6 +124,8 @@ void fsync_init(void) is_fsync_initialized = 1; + fprintf( stderr, "fsync: up and running.\n" ); + atexit( shm_cleanup ); } From b2fdf126c4f2ceee1ab77d63043cb162a4a1ce71 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Thu, 13 Jun 2019 12:59:53 -0500 Subject: [PATCH 0442/2777] ntdll, server: Make extra sure that esync is never used if fsync is used. --- dlls/ntdll/unix/esync.c | 3 ++- server/esync.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 742d10439db..1c1d85bd78e 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -48,6 +48,7 @@ #include "unix_private.h" #include "esync.h" +#include "fsync.h" WINE_DEFAULT_DEBUG_CHANNEL(esync); @@ -57,7 +58,7 @@ int do_esync(void) static int do_esync_cached = -1; if (do_esync_cached == -1) - do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")); + do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")) && !do_fsync(); return do_esync_cached; #else diff --git a/server/esync.c b/server/esync.c index 064bdd61b25..a5164435ed6 100644 --- a/server/esync.c +++ b/server/esync.c @@ -43,6 +43,7 @@ #include "request.h" #include "file.h" #include "esync.h" +#include "fsync.h" int do_esync(void) { @@ -50,7 +51,7 @@ int do_esync(void) static int do_esync_cached = -1; if (do_esync_cached == -1) - do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")); + do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")) && !do_fsync(); return do_esync_cached; #else From 3246665749011e76d82d7601de1e6a5f7e640792 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 17 Jul 2019 15:29:04 -0500 Subject: [PATCH 0443/2777] ntdll, server: Switch to testing ABI. --- dlls/ntdll/unix/fsync.c | 6 +++++- server/fsync.c | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 253439b7dfb..8022498ee14 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -61,13 +61,14 @@ struct futex_wait_block int pad; #endif int val; + int bitset; }; #include "poppack.h" static inline int futex_wait_multiple( const struct futex_wait_block *futexes, int count, const struct timespec *timeout ) { - return syscall( __NR_futex, futexes, 13, count, timeout, 0, 0 ); + return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); } static inline int futex_wake( int *addr, int val ) @@ -621,6 +622,7 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN aler #if __SIZEOF_POINTER__ == 4 futexes[0].pad = futexes[1].pad = 0; #endif + futexes[0].bitset = futexes[1].bitset = ~0; if (end) { @@ -837,6 +839,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, #if __SIZEOF_POINTER__ == 4 futexes[i].pad = 0; #endif + futexes[i].bitset = ~0; } if (alertable) @@ -850,6 +853,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, #if __SIZEOF_POINTER__ == 4 futexes[i].pad = 0; #endif + futexes[i].bitset = ~0; i++; } waitcount = i; diff --git a/server/fsync.c b/server/fsync.c index d4dbd66d22a..2cb804517dc 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -57,7 +57,7 @@ struct futex_wait_block static inline int futex_wait_multiple( const struct futex_wait_block *futexes, int count, const struct timespec *timeout ) { - return syscall( __NR_futex, futexes, 13, count, timeout, 0, 0 ); + return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); } int do_fsync(void) From c2c7c54a3c399a61a79cad93399c783f2486e6de Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Tue, 23 Jul 2019 17:22:44 -0500 Subject: [PATCH 0444/2777] ntdll: Check the APC futex first. --- dlls/ntdll/unix/fsync.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 8022498ee14..2eb86cab5e3 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -744,6 +744,16 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, { /* Try to grab anything. */ + if (alertable) + { + /* We must check this first! The server may set an event that + * we're waiting on, but we need to return STATUS_USER_APC. */ + struct event *event = get_shm( ntdll_get_thread_data()->fsync_apc_idx ); + TRACE("...%d\n", __atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )); + if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) + goto userapc; + } + for (i = 0; i < count; i++) { struct fsync *obj = objs[i]; @@ -845,9 +855,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, if (alertable) { struct event *event = get_shm( ntdll_get_thread_data()->fsync_apc_idx ); - if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) - goto userapc; - + /* We already checked if it was signaled; don't bother doing it again. */ futexes[i].addr = &event->signaled; futexes[i].val = 0; #if __SIZEOF_POINTER__ == 4 From 4a3d492c7992a624ea132bb955aa82e876885159 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 24 Jul 2019 14:44:15 -0500 Subject: [PATCH 0445/2777] server: Fix an invalid use of fsync_clear(). The fd object has no get_fsync_idx callback, so this would do nothing. --- server/fd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/fd.c b/server/fd.c index b3e4d591383..f2db3a5e0ee 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2203,7 +2203,7 @@ void set_fd_signaled( struct fd *fd, int signaled ) if (signaled) wake_up( fd->user, 0 ); if (do_fsync() && !signaled) - fsync_clear( &fd->obj ); + fsync_clear( fd->user ); if (do_esync() && !signaled) esync_clear( fd->esync_fd ); From 4a68556b1b15bb162bb06ec8f6261de297eaf040 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 24 Jul 2019 14:45:24 -0500 Subject: [PATCH 0446/2777] server: Be a little more careful about futex operations. --- server/fd.c | 2 ++ server/fsync.c | 24 ++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/server/fd.c b/server/fd.c index f2db3a5e0ee..908bf70fca9 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1719,6 +1719,7 @@ static struct fd *alloc_fd_object(void) fd->completion = NULL; fd->comp_flags = 0; fd->esync_fd = -1; + fd->fsync_idx = 0; init_async_queue( &fd->read_q ); init_async_queue( &fd->write_q ); init_async_queue( &fd->wait_q ); @@ -1765,6 +1766,7 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use fd->comp_flags = 0; fd->no_fd_status = STATUS_BAD_DEVICE_TYPE; fd->esync_fd = -1; + fd->fsync_idx = 0; init_async_queue( &fd->read_q ); init_async_queue( &fd->write_q ); init_async_queue( &fd->wait_q ); diff --git a/server/fsync.c b/server/fsync.c index 2cb804517dc..ca57d7f9cb8 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -331,8 +331,15 @@ struct fsync_event void fsync_wake_futex( unsigned int shm_idx ) { - struct fsync_event *event = get_shm( shm_idx ); + struct fsync_event *event; + if (debug_level) + fprintf( stderr, "fsync_wake_futex: index %u\n", shm_idx ); + + if (!shm_idx) + return; + + event = get_shm( shm_idx ); if (!__atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST )) futex_wake( &event->signaled, INT_MAX ); } @@ -341,14 +348,24 @@ void fsync_wake_up( struct object *obj ) { enum fsync_type type; + if (debug_level) + fprintf( stderr, "fsync_wake_up: object %p\n", obj ); + if (obj->ops->get_fsync_idx) fsync_wake_futex( obj->ops->get_fsync_idx( obj, &type ) ); } void fsync_clear_futex( unsigned int shm_idx ) { - struct fsync_event *event = get_shm( shm_idx ); + struct fsync_event *event; + if (debug_level) + fprintf( stderr, "fsync_clear_futex: index %u\n", shm_idx ); + + if (!shm_idx) + return; + + event = get_shm( shm_idx ); __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); } @@ -356,6 +373,9 @@ void fsync_clear( struct object *obj ) { enum fsync_type type; + if (debug_level) + fprintf( stderr, "fsync_clear: object %p\n", obj ); + if (obj->ops->get_fsync_idx) fsync_clear_futex( obj->ops->get_fsync_idx( obj, &type ) ); } From ae32972fc0d90b96d04384d9b9f221f7cfbaf7c2 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 24 Jul 2019 15:02:01 -0500 Subject: [PATCH 0447/2777] ntdll: Catch closed handles more gracefully. --- dlls/ntdll/unix/fsync.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 2eb86cab5e3..e4a69d1dd6e 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -760,6 +760,13 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, if (obj) { + if (!obj->type) /* gcc complains if we put this in the switch */ + { + /* Someone probably closed an object while waiting on it. */ + WARN("Handle %p has type 0; was it closed?\n", handles[i]); + return STATUS_INVALID_HANDLE; + } + switch (obj->type) { case FSYNC_SEMAPHORE: @@ -836,6 +843,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, break; } default: + ERR("Invalid type %#x for handle %p.\n", obj->type, handles[i]); assert(0); } } From 2a6d763e9f6faf739d9959e1e24075651202a8aa Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 24 Jul 2019 15:04:08 -0500 Subject: [PATCH 0448/2777] ntdll: Implement fsync_pulse_event(). --- dlls/ntdll/unix/fsync.c | 29 +++++++++++++++++++++++++++++ dlls/ntdll/unix/fsync.h | 1 + dlls/ntdll/unix/sync.c | 3 +++ 3 files changed, 33 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index e4a69d1dd6e..ec12fbd0d2b 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -511,6 +511,35 @@ NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) return STATUS_SUCCESS; } +NTSTATUS fsync_pulse_event( HANDLE handle, LONG *prev ) +{ + struct event *event; + struct fsync *obj; + LONG current; + NTSTATUS ret; + + TRACE("%p.\n", handle); + + if ((ret = get_object( handle, &obj ))) return ret; + event = obj->shm; + + /* This isn't really correct; an application could miss the write. + * Unfortunately we can't really do much better. Fortunately this is rarely + * used (and publicly deprecated). */ + if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))) + futex_wake( &event->signaled, INT_MAX ); + + /* Try to give other threads a chance to wake up. Hopefully erring on this + * side is the better thing to do... */ + NtYieldExecution(); + + __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); + + if (prev) *prev = current; + + return STATUS_SUCCESS; +} + NTSTATUS fsync_query_event( HANDLE handle, void *info, ULONG *ret_len ) { struct event *event; diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h index 38a6c8f0f70..b3604548554 100644 --- a/dlls/ntdll/unix/fsync.h +++ b/dlls/ntdll/unix/fsync.h @@ -34,6 +34,7 @@ extern NTSTATUS fsync_open_event( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; +extern NTSTATUS fsync_pulse_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_query_event( HANDLE handle, void *info, ULONG *ret_len ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 434cf9e1a76..4c80b34fa33 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -534,6 +534,9 @@ NTSTATUS WINAPI NtPulseEvent( HANDLE handle, LONG *prev_state ) { unsigned int ret; + if (do_fsync()) + return fsync_pulse_event( handle, prev_state ); + if (do_esync()) return esync_pulse_event( handle ); From 8374093850da569fc920fb8e06e380162d3cef5a Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 31 Jul 2019 12:18:37 -0500 Subject: [PATCH 0449/2777] server: Print a message when using server-side synchronization. --- server/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/main.c b/server/main.c index db195201419..4de74ebe7ac 100644 --- a/server/main.c +++ b/server/main.c @@ -237,6 +237,9 @@ int main( int argc, char *argv[] ) if (do_esync()) esync_init(); + if (!do_fsync() && !do_esync()) + fprintf( stderr, "wineserver: using server-side synchronization.\n" ); + if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() ); set_current_time(); init_signals(); From 4574f08f167b4bd50b5dc20c4e5a5919f182e704 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 7 Aug 2019 17:07:15 -0500 Subject: [PATCH 0450/2777] ntdll: Store the fsync APC futex in the thread data directly. Essentially so we can take get_shm() out of any critical paths. --- dlls/ntdll/unix/fsync.c | 26 +++++++++++++++----------- dlls/ntdll/unix/unix_private.h | 2 +- dlls/ntdll/unix/virtual.c | 2 +- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index ec12fbd0d2b..d88dc09e80a 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -638,15 +638,15 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN aler if (alertable) { - struct event *apc_event = get_shm( ntdll_get_thread_data()->fsync_apc_idx ); + int *apc_futex = ntdll_get_thread_data()->fsync_apc_futex; struct futex_wait_block futexes[2]; - if (__atomic_load_n( &apc_event->signaled, __ATOMIC_SEQ_CST )) + if (__atomic_load_n( apc_futex, __ATOMIC_SEQ_CST )) return STATUS_USER_APC; futexes[0].addr = addr; futexes[0].val = val; - futexes[1].addr = &apc_event->signaled; + futexes[1].addr = apc_futex; futexes[1].val = 0; #if __SIZEOF_POINTER__ == 4 futexes[0].pad = futexes[1].pad = 0; @@ -664,7 +664,7 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN aler else ret = futex_wait_multiple( futexes, 2, NULL ); - if (__atomic_load_n( &apc_event->signaled, __ATOMIC_SEQ_CST )) + if (__atomic_load_n( apc_futex, __ATOMIC_SEQ_CST )) return STATUS_USER_APC; } else @@ -706,14 +706,21 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, int i, ret; /* Grab the APC futex if we don't already have it. */ - if (alertable && !ntdll_get_thread_data()->fsync_apc_idx) + if (alertable && !ntdll_get_thread_data()->fsync_apc_futex) { + unsigned int idx = 0; SERVER_START_REQ( get_fsync_apc_idx ) { if (!(ret = wine_server_call( req ))) - ntdll_get_thread_data()->fsync_apc_idx = reply->shm_idx; + idx = reply->shm_idx; } SERVER_END_REQ; + + if (idx) + { + struct event *apc_event = get_shm( idx ); + ntdll_get_thread_data()->fsync_apc_futex = &apc_event->signaled; + } } NtQuerySystemTime( &now ); @@ -777,9 +784,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, { /* We must check this first! The server may set an event that * we're waiting on, but we need to return STATUS_USER_APC. */ - struct event *event = get_shm( ntdll_get_thread_data()->fsync_apc_idx ); - TRACE("...%d\n", __atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )); - if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) + if (__atomic_load_n( ntdll_get_thread_data()->fsync_apc_futex, __ATOMIC_SEQ_CST )) goto userapc; } @@ -891,9 +896,8 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, if (alertable) { - struct event *event = get_shm( ntdll_get_thread_data()->fsync_apc_idx ); /* We already checked if it was signaled; don't bother doing it again. */ - futexes[i].addr = &event->signaled; + futexes[i].addr = ntdll_get_thread_data()->fsync_apc_futex; futexes[i].val = 0; #if __SIZEOF_POINTER__ == 4 futexes[i].pad = 0; diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 620a849afb3..8476f09b8c7 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -59,7 +59,7 @@ struct ntdll_thread_data void *cpu_data[16]; /* reserved for CPU-specific data */ void *kernel_stack; /* stack for thread startup and kernel syscalls */ int esync_apc_fd; /* fd to wait on for user APCs */ - unsigned int fsync_apc_idx; + int *fsync_apc_futex; int request_fd; /* fd for sending server requests */ int reply_fd; /* fd for receiving server replies */ int wait_fd[2]; /* fd for sleeping server requests */ diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 544c4c27aa8..d1bcd405b66 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -2938,7 +2938,7 @@ static TEB *init_teb( void *ptr, BOOL is_wow ) teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; thread_data->esync_apc_fd = -1; - thread_data->fsync_apc_idx = 0; + thread_data->fsync_apc_futex = NULL; thread_data->request_fd = -1; thread_data->reply_fd = -1; thread_data->wait_fd[0] = -1; From eada8e31b37668b7e2cf3d7909b63a617418fc70 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 7 Aug 2019 17:14:59 -0500 Subject: [PATCH 0451/2777] ntdll/fsync: Lock accessing the shm_addrs array. --- dlls/ntdll/unix/fsync.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index d88dc09e80a..6e077418814 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -135,10 +135,15 @@ static void **shm_addrs; static int shm_addrs_size; /* length of the allocated shm_addrs array */ static long pagesize; +static pthread_mutex_t shm_addrs_mutex = PTHREAD_MUTEX_INITIALIZER; + static void *get_shm( unsigned int idx ) { int entry = (idx * 8) / pagesize; int offset = (idx * 8) % pagesize; + void *ret; + + pthread_mutex_lock( &shm_addrs_mutex ); if (entry >= shm_addrs_size) { @@ -162,7 +167,11 @@ static void *get_shm( unsigned int idx ) munmap( addr, pagesize ); /* someone beat us to it */ } - return (void *)((unsigned long)shm_addrs[entry] + offset); + ret = (void *)((unsigned long)shm_addrs[entry] + offset); + + pthread_mutex_unlock( &shm_addrs_mutex ); + + return ret; } /* We'd like lookup to be fast. To that end, we use a static list indexed by handle. From f8bf44793690df13241ce64147d8d51e09afa348 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Thu, 8 Aug 2019 17:12:46 -0500 Subject: [PATCH 0452/2777] ntdll/fsync: Fix a race condition when waiting on a mutex. --- dlls/ntdll/unix/fsync.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 6e077418814..4235cef430b 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -835,6 +835,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, case FSYNC_MUTEX: { struct mutex *mutex = obj->shm; + int tid; if (mutex->tid == GetCurrentThreadId()) { @@ -843,7 +844,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, return i; } - if (!__sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() )) + if (!(tid = __sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() ))) { TRACE("Woken up by handle %p [%d].\n", handles[i], i); mutex->count = 1; @@ -851,7 +852,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, } futexes[i].addr = &mutex->tid; - futexes[i].val = mutex->tid; + futexes[i].val = tid; break; } case FSYNC_AUTO_EVENT: From 13122432f0fdecb4b0c766d5e2efa530235909c9 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 19 Aug 2019 18:25:42 -0500 Subject: [PATCH 0453/2777] ntdll/fsync: Introduce a configurable spin count. --- dlls/ntdll/unix/fsync.c | 68 +++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 4235cef430b..f71e7a58e5c 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -65,6 +65,15 @@ struct futex_wait_block }; #include "poppack.h" +static inline void small_pause(void) +{ +#if defined(__i386__) || defined(__x86_64__) + __asm__ __volatile__( "rep;nop" : : : "memory" ); +#else + __asm__ __volatile__( "" : : : "memory" ); +#endif +} + static inline int futex_wait_multiple( const struct futex_wait_block *futexes, int count, const struct timespec *timeout ) { @@ -81,6 +90,8 @@ static inline int futex_wait( int *addr, int val, struct timespec *timeout ) return syscall( __NR_futex, addr, 0, val, timeout, 0, 0 ); } +static unsigned int spincount; + int do_fsync(void) { #ifdef __linux__ @@ -91,6 +102,8 @@ int do_fsync(void) static const struct timespec zero; futex_wait_multiple( NULL, 0, &zero ); do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; + if (getenv("WINEFSYNC_SPINCOUNT")) + spincount = atoi(getenv("WINEFSYNC_SPINCOUNT")); } return do_fsync_cached; @@ -708,6 +721,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, int has_fsync = 0, has_server = 0; BOOL msgwait = FALSE; int dummy_futex = 0; + unsigned int spin; LONGLONG timeleft; LARGE_INTEGER now; DWORD waitcount; @@ -817,19 +831,23 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, struct semaphore *semaphore = obj->shm; int current; - do - { - if (!(current = semaphore->count)) break; - } while (__sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) != current); - - if (current) + /* It would be a little clearer (and less error-prone) + * to use a dedicated interlocked_dec_if_nonzero() + * helper, but nesting loops like that is probably not + * great for performance... */ + for (spin = 0; spin <= spincount || current; ++spin) { - TRACE("Woken up by handle %p [%d].\n", handles[i], i); - return i; + if ((current = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST )) + && __sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) == current) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + return i; + } + small_pause(); } futexes[i].addr = &semaphore->count; - futexes[i].val = current; + futexes[i].val = 0; break; } case FSYNC_MUTEX: @@ -844,11 +862,15 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, return i; } - if (!(tid = __sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() ))) + for (spin = 0; spin <= spincount; ++spin) { - TRACE("Woken up by handle %p [%d].\n", handles[i], i); - mutex->count = 1; - return i; + if (!(tid = __sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() ))) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + mutex->count = 1; + return i; + } + small_pause(); } futexes[i].addr = &mutex->tid; @@ -860,10 +882,14 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, { struct event *event = obj->shm; - if (__sync_val_compare_and_swap( &event->signaled, 1, 0 )) + for (spin = 0; spin <= spincount; ++spin) { - TRACE("Woken up by handle %p [%d].\n", handles[i], i); - return i; + if (__sync_val_compare_and_swap( &event->signaled, 1, 0 )) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + return i; + } + small_pause(); } futexes[i].addr = &event->signaled; @@ -876,10 +902,14 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, { struct event *event = obj->shm; - if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) + for (spin = 0; spin <= spincount; ++spin) { - TRACE("Woken up by handle %p [%d].\n", handles[i], i); - return i; + if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + return i; + } + small_pause(); } futexes[i].addr = &event->signaled; From 4a78bb913994dddacb0ecd6eff988b156e8e3174 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 17 Feb 2020 11:57:40 -0600 Subject: [PATCH 0454/2777] ntdll, server: Abandon fsync mutexes on thread exit. --- dlls/ntdll/unix/fsync.c | 35 ++++++++++++++++++++++++++++------- server/fsync.c | 33 +++++++++++++++++++++++++++++++++ server/fsync.h | 1 + server/thread.c | 2 ++ 4 files changed, 64 insertions(+), 7 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index f71e7a58e5c..2c7d4f909ee 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -637,7 +637,7 @@ NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) out->CurrentCount = 1 - mutex->count; out->OwnedByCaller = (mutex->tid == GetCurrentThreadId()); - out->AbandonedState = FALSE; + out->AbandonedState = (mutex->tid == ~0); if (ret_len) *ret_len = sizeof(*out); return STATUS_SUCCESS; @@ -870,6 +870,12 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, mutex->count = 1; return i; } + else if (tid == ~0 && (tid = __sync_val_compare_and_swap( &mutex->tid, ~0, GetCurrentThreadId() )) == ~0) + { + TRACE("Woken up by abandoned mutex %p [%d].\n", handles[i], i); + mutex->count = 1; + return STATUS_ABANDONED_WAIT_0 + i; + } small_pause(); } @@ -1007,7 +1013,11 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, while (1) { + BOOL abandoned; + tryagain: + abandoned = FALSE; + /* First step: try to wait on each object in sequence. */ for (i = 0; i < count; i++) @@ -1059,11 +1069,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, if (obj && obj->type == FSYNC_MUTEX) { struct mutex *mutex = obj->shm; + int tid = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ); - if (mutex->tid == GetCurrentThreadId()) - continue; /* ok */ - - if (__atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST )) + if (tid && tid != ~0 && tid != GetCurrentThreadId()) goto tryagain; } else if (obj) @@ -1084,10 +1092,15 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, case FSYNC_MUTEX: { struct mutex *mutex = obj->shm; - if (mutex->tid == GetCurrentThreadId()) + int tid = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ); + if (tid == GetCurrentThreadId()) break; - if (__sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() )) + if (tid && tid != ~0) + goto tooslow; + if (__sync_val_compare_and_swap( &mutex->tid, tid, GetCurrentThreadId() ) != tid) goto tooslow; + if (tid == ~0) + abandoned = TRUE; break; } case FSYNC_SEMAPHORE: @@ -1123,6 +1136,11 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, } } + if (abandoned) + { + TRACE("Wait successful, but some object(s) were abandoned.\n"); + return STATUS_ABANDONED; + } TRACE("Wait successful.\n"); return STATUS_SUCCESS; @@ -1135,6 +1153,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, case FSYNC_MUTEX: { struct mutex *mutex = obj->shm; + /* HACK: This won't do the right thing with abandoned + * mutexes, but fixing it is probably more trouble than + * it's worth. */ __atomic_store_n( &mutex->tid, 0, __ATOMIC_SEQ_CST ); break; } diff --git a/server/fsync.c b/server/fsync.c index ca57d7f9cb8..3ad59f4735f 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -129,11 +129,14 @@ void fsync_init(void) atexit( shm_cleanup ); } +static struct list mutex_list = LIST_INIT(mutex_list); + struct fsync { struct object obj; unsigned int shm_idx; enum fsync_type type; + struct list mutex_entry; }; static void fsync_dump( struct object *obj, int verbose ); @@ -193,6 +196,9 @@ static unsigned int fsync_map_access( struct object *obj, unsigned int access ) static void fsync_destroy( struct object *obj ) { + struct fsync *fsync = (struct fsync *)obj; + if (fsync->type == FSYNC_MUTEX) + list_remove( &fsync->mutex_entry ); } static void *get_shm( unsigned int idx ) @@ -297,6 +303,8 @@ struct fsync *create_fsync( struct object *root, const struct unicode_str *name, fsync->shm_idx = fsync_alloc_shm( low, high ); fsync->type = type; + if (type == FSYNC_MUTEX) + list_add_tail( &mutex_list, &fsync->mutex_entry ); } else { @@ -397,6 +405,31 @@ void fsync_reset_event( struct fsync *fsync ) __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); } +struct mutex +{ + int tid; + int count; /* recursion count */ +}; + +void fsync_abandon_mutexes( struct thread *thread ) +{ + struct fsync *fsync; + + LIST_FOR_EACH_ENTRY( fsync, &mutex_list, struct fsync, mutex_entry ) + { + struct mutex *mutex = get_shm( fsync->shm_idx ); + + if (mutex->tid == thread->id) + { + if (debug_level) + fprintf( stderr, "fsync_abandon_mutexes() idx=%d\n", fsync->shm_idx ); + mutex->tid = ~0; + mutex->count = 0; + futex_wake( &mutex->tid, INT_MAX ); + } + } +} + DECL_HANDLER(create_fsync) { struct fsync *fsync; diff --git a/server/fsync.h b/server/fsync.h index f6f1a48b31e..a91939b7f0a 100644 --- a/server/fsync.h +++ b/server/fsync.h @@ -31,3 +31,4 @@ struct fsync; extern const struct object_ops fsync_ops; extern void fsync_set_event( struct fsync *fsync ); extern void fsync_reset_event( struct fsync *fsync ); +extern void fsync_abandon_mutexes( struct thread *thread ); diff --git a/server/thread.c b/server/thread.c index 000a3d0e4ae..5bb509c2a08 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1524,6 +1524,8 @@ void kill_thread( struct thread *thread, int violent_death ) } kill_console_processes( thread, 0 ); abandon_mutexes( thread ); + if (do_fsync()) + fsync_abandon_mutexes( thread ); if (do_esync()) esync_abandon_mutexes( thread ); wake_up( &thread->obj, 0 ); From 1fec4055097f1a9757547c314bffb60198fb7440 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 18 Mar 2020 20:03:42 -0500 Subject: [PATCH 0455/2777] ntdll: Default the spin count to 100. --- dlls/ntdll/unix/fsync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 2c7d4f909ee..0323d53c4a0 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -90,7 +90,7 @@ static inline int futex_wait( int *addr, int val, struct timespec *timeout ) return syscall( __NR_futex, addr, 0, val, timeout, 0, 0 ); } -static unsigned int spincount; +static unsigned int spincount = 100; int do_fsync(void) { From a614b60317b2104f7250d42cba6c2e7538535df9 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 13 Mar 2020 15:52:15 -0500 Subject: [PATCH 0456/2777] ntdll: Implement an esync/fsync path for alertable NtDelayExecution(). --- dlls/ntdll/unix/esync.c | 4 ++-- dlls/ntdll/unix/fsync.c | 6 +++--- dlls/ntdll/unix/sync.c | 19 ++++++++++++++++++- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 1c1d85bd78e..19519e84668 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -859,7 +859,7 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA return ret; } - if (objs[count - 1] && objs[count - 1]->type == ESYNC_QUEUE) + if (count && objs[count - 1] && objs[count - 1]->type == ESYNC_QUEUE) msgwait = TRUE; if (has_esync && has_server) @@ -888,7 +888,7 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA } } - if (wait_any || count == 1) + if (wait_any || count <= 1) { /* Try to check objects now, so we can obviate poll() at least. */ for (i = 0; i < count; i++) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 0323d53c4a0..3a4095169e9 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -768,7 +768,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, return ret; } - if (objs[count - 1] && objs[count - 1]->type == FSYNC_QUEUE) + if (count && objs[count - 1] && objs[count - 1]->type == FSYNC_QUEUE) msgwait = TRUE; if (has_fsync && has_server) @@ -797,7 +797,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, } } - if (wait_any || count == 1) + if (wait_any || count <= 1) { while (1) { @@ -1224,7 +1224,7 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an struct fsync *obj; NTSTATUS ret; - if (!get_object( handles[count - 1], &obj ) && obj->type == FSYNC_QUEUE) + if (count && !get_object( handles[count - 1], &obj ) && obj->type == FSYNC_QUEUE) { msgwait = TRUE; server_set_msgwait( 1 ); diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 4c80b34fa33..4cea4d07789 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -1588,7 +1588,24 @@ NTSTATUS WINAPI NtYieldExecution(void) NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout ) { /* if alertable, we need to query the server */ - if (alertable) return server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout ); + if (alertable) + { + if (do_fsync()) + { + NTSTATUS ret = fsync_wait_objects( 0, NULL, TRUE, TRUE, timeout ); + if (ret != STATUS_NOT_IMPLEMENTED) + return ret; + } + + if (do_esync()) + { + NTSTATUS ret = esync_wait_objects( 0, NULL, TRUE, TRUE, timeout ); + if (ret != STATUS_NOT_IMPLEMENTED) + return ret; + } + + return server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout ); + } if (!timeout || timeout->QuadPart == TIMEOUT_INFINITE) /* sleep forever */ { From a16c92036d269d7be763098022274805a0c4ca2d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 25 Jun 2021 23:17:43 +0300 Subject: [PATCH 0457/2777] esync, fsync: Use usleep(0) instead of NtYieldExecution() in esync_pulse_event(). For Mafia III: Definitive Edition when FPS limit is set. CW-Bug-Id: #19024 --- dlls/ntdll/unix/esync.c | 2 +- dlls/ntdll/unix/fsync.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 19519e84668..1632211def8 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -617,7 +617,7 @@ NTSTATUS esync_pulse_event( HANDLE handle ) /* Try to give other threads a chance to wake up. Hopefully erring on this * side is the better thing to do... */ - NtYieldExecution(); + usleep(0); read( obj->fd, &value, sizeof(value) ); diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 3a4095169e9..3efa2bb34ff 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -553,7 +553,7 @@ NTSTATUS fsync_pulse_event( HANDLE handle, LONG *prev ) /* Try to give other threads a chance to wake up. Hopefully erring on this * side is the better thing to do... */ - NtYieldExecution(); + usleep(0); __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); From a14a7e5499d888985114bdd49834208919c1b157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= Date: Fri, 27 Nov 2020 14:05:14 -0300 Subject: [PATCH 0458/2777] ntdll: Call waitv just when nr_futexes > 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit futex_waitv() needs to do an extra copy from userspace compared to futex(), so use the latter when we are waiting in a single futex. Signed-off-by: André Almeida Link: https://github.com/ValveSoftware/wine/pull/128 --- dlls/ntdll/unix/fsync.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 3efa2bb34ff..6c3ec581fd0 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -969,10 +969,18 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; - ret = futex_wait_multiple( futexes, waitcount, &tmo_p ); + if (waitcount == 1) + ret = futex_wait( futexes[0].addr, futexes[0].val, &tmo_p ); + else + ret = futex_wait_multiple( futexes, waitcount, &tmo_p ); } else - ret = futex_wait_multiple( futexes, waitcount, NULL ); + { + if (waitcount == 1) + ret = futex_wait( futexes[0].addr, futexes[0].val, NULL ); + else + ret = futex_wait_multiple( futexes, waitcount, NULL ); + } /* FUTEX_WAIT_MULTIPLE can succeed or return -EINTR, -EAGAIN, * -EFAULT/-EACCES, -ETIMEDOUT. In the first three cases we need to From 52485b8c367df38c33d73ff9ac688c0cf08371e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= Date: Wed, 20 Oct 2021 10:35:58 -0300 Subject: [PATCH 0459/2777] ntdll/fsync: Encapsulate timeout conversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify the wait path by dealing with the timeout conversion inside of futex_wait. Signed-off-by: André Almeida Link: https://github.com/ValveSoftware/wine/pull/128 --- dlls/ntdll/unix/fsync.c | 94 ++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 52 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 6c3ec581fd0..8f81581e292 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -74,10 +74,32 @@ static inline void small_pause(void) #endif } +static LONGLONG update_timeout( ULONGLONG end ) +{ + LARGE_INTEGER now; + LONGLONG timeleft; + + NtQuerySystemTime( &now ); + timeleft = end - now.QuadPart; + if (timeleft < 0) timeleft = 0; + return timeleft; +} + static inline int futex_wait_multiple( const struct futex_wait_block *futexes, - int count, const struct timespec *timeout ) + int count, const ULONGLONG *end ) { - return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); + if (end) + { + LONGLONG timeleft = update_timeout( *end ); + struct timespec timeout; + timeout.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; + timeout.tv_nsec = (timeleft % TICKSPERSEC) * 100; + return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); + } + else + { + return syscall( __NR_futex, futexes, 31, count, NULL, 0, 0 ); + } } static inline int futex_wake( int *addr, int val ) @@ -85,9 +107,20 @@ static inline int futex_wake( int *addr, int val ) return syscall( __NR_futex, addr, 1, val, NULL, 0, 0 ); } -static inline int futex_wait( int *addr, int val, struct timespec *timeout ) +static inline int futex_wait( int *addr, int val, const ULONGLONG *end ) { - return syscall( __NR_futex, addr, 0, val, timeout, 0, 0 ); + if (end) + { + LONGLONG timeleft = update_timeout( *end ); + struct timespec timeout; + timeout.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; + timeout.tv_nsec = (timeleft % TICKSPERSEC) * 100; + return syscall( __NR_futex, addr, 0, val, &timeout, 0, 0 ); + } + else + { + return syscall( __NR_futex, addr, 0, val, NULL, 0, 0 ); + } } static unsigned int spincount = 100; @@ -643,17 +676,6 @@ NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) return STATUS_SUCCESS; } -static LONGLONG update_timeout( ULONGLONG end ) -{ - LARGE_INTEGER now; - LONGLONG timeleft; - - NtQuerySystemTime( &now ); - timeleft = end - now.QuadPart; - if (timeleft < 0) timeleft = 0; - return timeleft; -} - static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN alertable ) { int ret; @@ -675,32 +697,14 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN aler #endif futexes[0].bitset = futexes[1].bitset = ~0; - if (end) - { - LONGLONG timeleft = update_timeout( *end ); - struct timespec tmo_p; - tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; - tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; - ret = futex_wait_multiple( futexes, 2, &tmo_p ); - } - else - ret = futex_wait_multiple( futexes, 2, NULL ); + ret = futex_wait_multiple( futexes, 2, end ); if (__atomic_load_n( apc_futex, __ATOMIC_SEQ_CST )) return STATUS_USER_APC; } else { - if (end) - { - LONGLONG timeleft = update_timeout( *end ); - struct timespec tmo_p; - tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; - tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; - ret = futex_wait( addr, val, &tmo_p ); - } - else - ret = futex_wait( addr, val, NULL ); + ret = futex_wait( addr, val, end ); } if (!ret) @@ -962,25 +966,11 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, TRACE("Wait timed out.\n"); return STATUS_TIMEOUT; } - else if (timeout) - { - LONGLONG timeleft = update_timeout( end ); - struct timespec tmo_p; - tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; - tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; - if (waitcount == 1) - ret = futex_wait( futexes[0].addr, futexes[0].val, &tmo_p ); - else - ret = futex_wait_multiple( futexes, waitcount, &tmo_p ); - } + if (waitcount == 1) + ret = futex_wait( futexes[0].addr, futexes[0].val, timeout ? &end : NULL ); else - { - if (waitcount == 1) - ret = futex_wait( futexes[0].addr, futexes[0].val, NULL ); - else - ret = futex_wait_multiple( futexes, waitcount, NULL ); - } + ret = futex_wait_multiple( futexes, waitcount, timeout ? &end : NULL ); /* FUTEX_WAIT_MULTIPLE can succeed or return -EINTR, -EAGAIN, * -EFAULT/-EACCES, -ETIMEDOUT. In the first three cases we need to From 95e938e7575f4583db92e59d8f1c7a5af5ad06b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= Date: Thu, 21 Oct 2021 13:36:14 -0300 Subject: [PATCH 0460/2777] ntdll/fsync: Support futex_waitv() API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since an interface for wait on multiple futexes was merged, we no longer need to support different interfaces. Drop out FUTEX_WAIT_MULTIPLE (opcode 31) in favor of the futex_waitv() interface accepted by upstream Linux. Signed-off-by: André Almeida Link: https://github.com/ValveSoftware/wine/pull/128 --- dlls/ntdll/unix/fsync.c | 101 ++++++++++++++++++++-------------------- server/fsync.c | 19 ++------ 2 files changed, 55 insertions(+), 65 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 8f81581e292..be0f435599e 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -39,6 +39,7 @@ # include #endif #include +#include #include "ntstatus.h" #define WIN32_NO_STATUS @@ -54,16 +55,30 @@ WINE_DEFAULT_DEBUG_CHANNEL(fsync); #include "pshpack4.h" -struct futex_wait_block -{ - int *addr; -#if __SIZEOF_POINTER__ == 4 - int pad; +#include "poppack.h" + +/* futex_waitv interface */ + +#ifndef __NR_futex_waitv + +# define __NR_futex_waitv 449 +# define FUTEX_32 2 +struct futex_waitv { + uint64_t val; + uint64_t uaddr; + uint32_t flags; + uint32_t __reserved; +}; + #endif - int val; - int bitset; + +#define u64_to_ptr(x) (void *)(uintptr_t)(x) + +struct timespec64 +{ + long long tv_sec; + long long tv_nsec; }; -#include "poppack.h" static inline void small_pause(void) { @@ -85,20 +100,29 @@ static LONGLONG update_timeout( ULONGLONG end ) return timeleft; } -static inline int futex_wait_multiple( const struct futex_wait_block *futexes, +static inline void futex_vector_set( struct futex_waitv *waitv, int *addr, int val ) +{ + waitv->uaddr = (uintptr_t) addr; + waitv->val = val; + waitv->flags = FUTEX_32; + waitv->__reserved = 0; +} + +static inline int futex_wait_multiple( const struct futex_waitv *futexes, int count, const ULONGLONG *end ) { if (end) { - LONGLONG timeleft = update_timeout( *end ); - struct timespec timeout; - timeout.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; - timeout.tv_nsec = (timeleft % TICKSPERSEC) * 100; - return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); + struct timespec64 timeout; + ULONGLONG tmp = *end - SECS_1601_TO_1970 * TICKSPERSEC; + timeout.tv_sec = tmp / (ULONGLONG)TICKSPERSEC; + timeout.tv_nsec = (tmp % TICKSPERSEC) * 100; + + return syscall( __NR_futex_waitv, futexes, count, 0, &timeout, CLOCK_REALTIME ); } else { - return syscall( __NR_futex, futexes, 31, count, NULL, 0, 0 ); + return syscall( __NR_futex_waitv, futexes, count, 0, NULL, 0 ); } } @@ -132,8 +156,7 @@ int do_fsync(void) if (do_fsync_cached == -1) { - static const struct timespec zero; - futex_wait_multiple( NULL, 0, &zero ); + syscall( __NR_futex_waitv, NULL, 0, 0, NULL, 0 ); do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; if (getenv("WINEFSYNC_SPINCOUNT")) spincount = atoi(getenv("WINEFSYNC_SPINCOUNT")); @@ -683,19 +706,13 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN aler if (alertable) { int *apc_futex = ntdll_get_thread_data()->fsync_apc_futex; - struct futex_wait_block futexes[2]; + struct futex_waitv futexes[2]; if (__atomic_load_n( apc_futex, __ATOMIC_SEQ_CST )) return STATUS_USER_APC; - futexes[0].addr = addr; - futexes[0].val = val; - futexes[1].addr = apc_futex; - futexes[1].val = 0; -#if __SIZEOF_POINTER__ == 4 - futexes[0].pad = futexes[1].pad = 0; -#endif - futexes[0].bitset = futexes[1].bitset = ~0; + futex_vector_set( &futexes[0], addr, val ); + futex_vector_set( &futexes[1], apc_futex, 0 ); ret = futex_wait_multiple( futexes, 2, end ); @@ -720,7 +737,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, { static const LARGE_INTEGER zero = {0}; - struct futex_wait_block futexes[MAXIMUM_WAIT_OBJECTS + 1]; + struct futex_waitv futexes[MAXIMUM_WAIT_OBJECTS + 1]; struct fsync *objs[MAXIMUM_WAIT_OBJECTS]; int has_fsync = 0, has_server = 0; BOOL msgwait = FALSE; @@ -850,8 +867,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, small_pause(); } - futexes[i].addr = &semaphore->count; - futexes[i].val = 0; + futex_vector_set( &futexes[i], &semaphore->count, 0 ); break; } case FSYNC_MUTEX: @@ -883,8 +899,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, small_pause(); } - futexes[i].addr = &mutex->tid; - futexes[i].val = tid; + futex_vector_set( &futexes[i], &mutex->tid, tid ); break; } case FSYNC_AUTO_EVENT: @@ -902,8 +917,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, small_pause(); } - futexes[i].addr = &event->signaled; - futexes[i].val = 0; + futex_vector_set( &futexes[i], &event->signaled, 0 ); break; } case FSYNC_MANUAL_EVENT: @@ -922,8 +936,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, small_pause(); } - futexes[i].addr = &event->signaled; - futexes[i].val = 0; + futex_vector_set( &futexes[i], &event->signaled, 0 ); break; } default: @@ -934,26 +947,14 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, else { /* Avoid breaking things entirely. */ - futexes[i].addr = &dummy_futex; - futexes[i].val = dummy_futex; + futex_vector_set( &futexes[i], &dummy_futex, dummy_futex ); } - -#if __SIZEOF_POINTER__ == 4 - futexes[i].pad = 0; -#endif - futexes[i].bitset = ~0; } if (alertable) { /* We already checked if it was signaled; don't bother doing it again. */ - futexes[i].addr = ntdll_get_thread_data()->fsync_apc_futex; - futexes[i].val = 0; -#if __SIZEOF_POINTER__ == 4 - futexes[i].pad = 0; -#endif - futexes[i].bitset = ~0; - i++; + futex_vector_set( &futexes[i++], ntdll_get_thread_data()->fsync_apc_futex, 0 ); } waitcount = i; @@ -968,7 +969,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, } if (waitcount == 1) - ret = futex_wait( futexes[0].addr, futexes[0].val, timeout ? &end : NULL ); + ret = futex_wait( u64_to_ptr(futexes[0].uaddr), futexes[0].val, timeout ? &end : NULL ); else ret = futex_wait_multiple( futexes, waitcount, timeout ? &end : NULL ); diff --git a/server/fsync.c b/server/fsync.c index 3ad59f4735f..593070ad62e 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -44,21 +44,11 @@ #include "fsync.h" #include "pshpack4.h" -struct futex_wait_block -{ - int *addr; -#if __SIZEOF_POINTER__ == 4 - int pad; -#endif - int val; -}; #include "poppack.h" -static inline int futex_wait_multiple( const struct futex_wait_block *futexes, - int count, const struct timespec *timeout ) -{ - return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); -} +#ifndef __NR_futex_waitv +#define __NR_futex_waitv 449 +#endif int do_fsync(void) { @@ -67,8 +57,7 @@ int do_fsync(void) if (do_fsync_cached == -1) { - static const struct timespec zero; - futex_wait_multiple( NULL, 0, &zero ); + syscall( __NR_futex_waitv, 0, 0, 0, 0, 0); do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; } From 84cc62d824332556281e00b6bd3bb179fc7a14fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= Date: Thu, 21 Oct 2021 20:33:58 -0300 Subject: [PATCH 0461/2777] ntdll/fsync: Use absolute timeouts for futex_wait MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the FUTEX_WAIT_BITSET operation instead of FUTEX_WAIT, that allow us to use absolute timeouts rather than relative ones that requires an extra syscall to update the timeout. Signed-off-by: André Almeida Link: https://github.com/ValveSoftware/wine/pull/128 --- dlls/ntdll/unix/fsync.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index be0f435599e..868d4c5a667 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -57,6 +57,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(fsync); #include "pshpack4.h" #include "poppack.h" +#define FUTEX_WAIT_BITSET 9 +#define FUTEX_CLOCK_REALTIME 256 +#define FUTEX_BITSET_MATCH_ANY 0xffffffff + /* futex_waitv interface */ #ifndef __NR_futex_waitv @@ -135,11 +139,13 @@ static inline int futex_wait( int *addr, int val, const ULONGLONG *end ) { if (end) { - LONGLONG timeleft = update_timeout( *end ); struct timespec timeout; - timeout.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; - timeout.tv_nsec = (timeleft % TICKSPERSEC) * 100; - return syscall( __NR_futex, addr, 0, val, &timeout, 0, 0 ); + ULONGLONG tmp = *end - SECS_1601_TO_1970 * TICKSPERSEC; + timeout.tv_sec = tmp / (ULONGLONG)TICKSPERSEC; + timeout.tv_nsec = (tmp % TICKSPERSEC) * 100; + + return syscall( __NR_futex, addr, FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, + val, &timeout, 0, FUTEX_BITSET_MATCH_ANY ); } else { From f870b35dae10b18d77999c2e6d6bb50446b945d2 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 1 Apr 2021 20:19:35 +0300 Subject: [PATCH 0462/2777] esync, fsync: Yield execution before alertable wait for AC Odyssey. CW-Bug-ID: #18881 --- dlls/ntdll/unix/esync.c | 11 +++++++++++ dlls/ntdll/unix/fsync.c | 9 +++++++++ dlls/ntdll/unix/loader.c | 13 +++++++++++++ dlls/ntdll/unix/unix_private.h | 2 ++ 4 files changed, 35 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 1632211def8..5e1237b8ad5 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -948,6 +948,8 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA if (event->signaled) { + if (ac_odyssey && alertable) + usleep( 0 ); if ((size = read( obj->fd, &value, sizeof(value) )) == sizeof(value)) { TRACE("Woken up by handle %p [%d].\n", handles[i], i); @@ -963,6 +965,12 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA if (event->signaled) { + if (ac_odyssey && alertable) + { + usleep( 0 ); + if (!event->signaled) + break; + } TRACE("Woken up by handle %p [%d].\n", handles[i], i); return i; } @@ -991,6 +999,9 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA while (1) { + if (ac_odyssey && alertable) + usleep( 0 ); + ret = do_poll( fds, pollcount, timeout ? &end : NULL ); if (ret > 0) { diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 868d4c5a667..2513f19deb3 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -917,6 +917,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, { if (__sync_val_compare_and_swap( &event->signaled, 1, 0 )) { + if (ac_odyssey && alertable) + usleep( 0 ); + TRACE("Woken up by handle %p [%d].\n", handles[i], i); return i; } @@ -936,6 +939,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, { if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) { + if (ac_odyssey && alertable) + usleep( 0 ); + TRACE("Woken up by handle %p [%d].\n", handles[i], i); return i; } @@ -966,6 +972,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, /* Looks like everything is contended, so wait. */ + if (ac_odyssey && alertable) + usleep( 0 ); + if (timeout && !timeout->QuadPart) { /* Unlike esync, we already know that we've timed out, so we diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index c218774be3d..8fecb129fe6 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2179,6 +2179,18 @@ const unixlib_entry_t __wine_unix_call_funcs[] = steamclient_setup_trampolines, }; +BOOL ac_odyssey; + +static void hacks_init(void) +{ + static const char ac_odyssey_exe[] = "ACOdyssey.exe"; + + if (main_argc > 1 && strstr(main_argv[1], ac_odyssey_exe)) + { + ERR("HACK: AC Odyssey sync tweak on.\n"); + ac_odyssey = TRUE; + } +} #ifdef _WIN64 @@ -2209,6 +2221,7 @@ static void start_main_thread(void) signal_alloc_thread( teb ); dbg_init(); startup_info_size = server_init_process(); + hacks_init(); fsync_init(); esync_init(); virtual_map_user_shared_data(); diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 8476f09b8c7..7d75b6020fb 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -149,6 +149,8 @@ extern BOOL is_wow64 DECLSPEC_HIDDEN; extern struct ldt_copy __wine_ldt_copy DECLSPEC_HIDDEN; #endif +extern BOOL ac_odyssey DECLSPEC_HIDDEN; + extern void init_environment( int argc, char *argv[], char *envp[] ) DECLSPEC_HIDDEN; extern void init_startup_info(void) DECLSPEC_HIDDEN; extern void *create_startup_info( const UNICODE_STRING *nt_image, const RTL_USER_PROCESS_PARAMETERS *params, From dead24aad062daab54317829cdcfd8633d976a9b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 6 Apr 2021 19:43:48 +0300 Subject: [PATCH 0463/2777] ntdll: Simulate async file read and IO cancellation to workaround AC:Odyssey out of order dialogues bug. CW-Bug-ID: #18881 --- dlls/ntdll/unix/file.c | 237 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 957d9f3b801..5fbc40cb0bb 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -5326,6 +5326,230 @@ static unsigned int set_pending_write( HANDLE device ) return status; } +static pthread_mutex_t async_file_read_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t async_file_read_cond = PTHREAD_COND_INITIALIZER; + +struct async_file_read_job +{ + HANDLE handle; + int unix_handle; + int needs_close; + HANDLE event; + IO_STATUS_BLOCK *io; + void *buffer; + ULONG length; + LARGE_INTEGER offset; + DWORD thread_id; + LONG cancelled; + struct list queue_entry; + struct async_file_read_job *next; +}; + + +static struct list async_file_read_queue = LIST_INIT( async_file_read_queue ); +static struct async_file_read_job *async_file_read_running, *async_file_read_free; + +static void async_file_complete_io( struct async_file_read_job *job, NTSTATUS status, ULONG total ) +{ + job->io->u.Status = status; + job->io->Information = total; + + if (job->event) NtSetEvent( job->event, NULL ); +} + +static void *async_file_read_thread(void *dummy) +{ + struct async_file_read_job *job, *ptr; + ULONG buffer_length = 0; + void *buffer = NULL; + struct list *entry; + NTSTATUS status; + ULONG total; + int result; + + pthread_mutex_lock( &async_file_read_mutex ); + while (1) + { + while (!(entry = list_head( &async_file_read_queue ))) + { + pthread_cond_wait( &async_file_read_cond, &async_file_read_mutex ); + continue; + } + + job = LIST_ENTRY( entry, struct async_file_read_job, queue_entry ); + list_remove( entry ); + + total = 0; + + if ( job->cancelled ) + { + pthread_mutex_unlock( &async_file_read_mutex ); + status = STATUS_CANCELLED; + goto done; + } + + job->next = async_file_read_running; + async_file_read_running = job; + pthread_mutex_unlock( &async_file_read_mutex ); + + if (!buffer_length) + { + buffer = malloc(job->length); + buffer_length = job->length; + } + else if (buffer_length < job->length) + { + buffer = realloc(buffer, job->length); + buffer_length = job->length; + } + + while ((result = pread( job->unix_handle, buffer, job->length, job->offset.QuadPart )) == -1) + { + if (errno != EINTR) + { + status = errno_to_status( errno ); + goto done; + } + if (job->cancelled) + break; + } + + total = result; + status = (total || !job->length) ? STATUS_SUCCESS : STATUS_END_OF_FILE; +done: + if (job->needs_close) close( job->unix_handle ); + + if (!InterlockedCompareExchange(&job->cancelled, 1, 0)) + { + if (status == STATUS_SUCCESS) + memcpy( job->buffer, buffer, total ); + + async_file_complete_io( job, status, total ); + } + + pthread_mutex_lock( &async_file_read_mutex ); + + if (status != STATUS_CANCELLED) + { + ptr = async_file_read_running; + if (job == ptr) + { + async_file_read_running = job->next; + } + else + { + while (ptr && ptr->next != job) + ptr = ptr->next; + + assert( ptr ); + ptr->next = job->next; + } + } + + job->next = async_file_read_free; + async_file_read_free = job; + } + + return NULL; +} + +static pthread_once_t async_file_read_once = PTHREAD_ONCE_INIT; + +static void async_file_read_init(void) +{ + pthread_t async_file_read_thread_id; + pthread_attr_t pthread_attr; + + ERR("HACK: AC Odyssey async read workaround.\n"); + + pthread_attr_init( &pthread_attr ); + pthread_attr_setscope( &pthread_attr, PTHREAD_SCOPE_SYSTEM ); + pthread_attr_setdetachstate( &pthread_attr, PTHREAD_CREATE_DETACHED ); + + pthread_create( &async_file_read_thread_id, &pthread_attr, (void * (*)(void *))async_file_read_thread, NULL); + pthread_attr_destroy( &pthread_attr ); +} + +static NTSTATUS queue_async_file_read( HANDLE handle, int unix_handle, int needs_close, HANDLE event, + IO_STATUS_BLOCK *io, void *buffer, ULONG length, LARGE_INTEGER *offset ) +{ + struct async_file_read_job *job; + + pthread_once( &async_file_read_once, async_file_read_init ); + + NtResetEvent( event, NULL ); + + pthread_mutex_lock( &async_file_read_mutex ); + + if (async_file_read_free) + { + job = async_file_read_free; + async_file_read_free = async_file_read_free->next; + } + else + { + if (!(job = malloc( sizeof(*job) ))) + { + pthread_mutex_unlock( &async_file_read_mutex ); + return STATUS_NO_MEMORY; + } + } + + job->handle = handle; + job->unix_handle = unix_handle; + job->needs_close = needs_close; + job->event = event; + job->io = io; + job->buffer = buffer; + job->length = length; + job->offset = *offset; + job->thread_id = GetCurrentThreadId(); + job->cancelled = 0; + + list_add_tail( &async_file_read_queue, &job->queue_entry ); + + pthread_cond_signal( &async_file_read_cond ); + pthread_mutex_unlock( &async_file_read_mutex ); + + return STATUS_PENDING; +} + +static NTSTATUS cancel_async_file_read( HANDLE handle, IO_STATUS_BLOCK *io ) +{ + DWORD thread_id = GetCurrentThreadId(); + struct async_file_read_job *job; + unsigned int count = 0; + + TRACE( "handle %p, io %p.\n", handle, io ); + + pthread_mutex_lock( &async_file_read_mutex ); + job = async_file_read_running; + while (job) + { + if (((io && job->io == io) + || (!io && job->handle == handle && job->thread_id == thread_id)) + && !InterlockedCompareExchange(&job->cancelled, 1, 0)) + { + async_file_complete_io( job, STATUS_CANCELLED, 0 ); + ++count; + } + job = job->next; + } + + LIST_FOR_EACH_ENTRY( job, &async_file_read_queue, struct async_file_read_job, queue_entry ) + { + if (((io && job->io == io) + || (!io && job->handle == handle && job->thread_id == thread_id)) + && !InterlockedCompareExchange(&job->cancelled, 1, 0)) + { + async_file_complete_io( job, STATUS_CANCELLED, 0 ); + ++count; + } + } + + pthread_mutex_unlock( &async_file_read_mutex ); + return count ? STATUS_SUCCESS : STATUS_NOT_FOUND; +} /****************************************************************************** * NtReadFile (NTDLL.@) @@ -5367,6 +5591,13 @@ NTSTATUS WINAPI NtReadFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, vo goto done; } + if (ac_odyssey && async_read && length && event && !apc) + { + status = queue_async_file_read( handle, unix_handle, needs_close, event, io, buffer, length, offset ); + needs_close = 0; + goto err; + } + if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION) { /* async I/O doesn't make sense on regular files */ @@ -6176,6 +6407,9 @@ NTSTATUS WINAPI NtCancelIoFile( HANDLE handle, IO_STATUS_BLOCK *io_status ) TRACE( "%p %p\n", handle, io_status ); + if (ac_odyssey && !cancel_async_file_read( handle, NULL )) + return (io_status->u.Status = STATUS_SUCCESS); + SERVER_START_REQ( cancel_async ) { req->handle = wine_server_obj_handle( handle ); @@ -6201,6 +6435,9 @@ NTSTATUS WINAPI NtCancelIoFileEx( HANDLE handle, IO_STATUS_BLOCK *io, IO_STATUS_ TRACE( "%p %p %p\n", handle, io, io_status ); + if (ac_odyssey && !cancel_async_file_read( handle, io )) + return (io_status->u.Status = STATUS_SUCCESS); + SERVER_START_REQ( cancel_async ) { req->handle = wine_server_obj_handle( handle ); From 108f79ba5e84c8f292e205142db20d137f9c73c3 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 3 Nov 2021 18:07:13 +0300 Subject: [PATCH 0464/2777] ntdll: HACK: Enable WINESTEAMNOEXEC for Mafia II. CW-Bug-Id: #19605 --- dlls/ntdll/unix/loader.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 8fecb129fe6..0d112aaa457 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2184,12 +2184,18 @@ BOOL ac_odyssey; static void hacks_init(void) { static const char ac_odyssey_exe[] = "ACOdyssey.exe"; + const char *sgi; if (main_argc > 1 && strstr(main_argv[1], ac_odyssey_exe)) { ERR("HACK: AC Odyssey sync tweak on.\n"); ac_odyssey = TRUE; + return; } + + sgi = getenv("SteamGameId"); + if (sgi && !strcmp(sgi, "50130")) + setenv("WINESTEAMNOEXEC", "1", 0); } #ifdef _WIN64 From ba6c583a2cf30158925eb62f8eedd9dd80d5c295 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 15 Feb 2022 17:20:40 +0300 Subject: [PATCH 0465/2777] 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 | 17 ++++++++++++++++- dlls/ntdll/unix/loader.c | 15 ++++++++++++--- dlls/ntdll/unix/unix_private.h | 1 + 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 2513f19deb3..9498ccc8e2d 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -112,6 +112,15 @@ static inline void futex_vector_set( struct futex_waitv *waitv, int *addr, int v waitv->__reserved = 0; } +static void simulate_sched_quantum(void) +{ + if (!fsync_simulate_sched_quantum) return; + /* 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, int count, const ULONGLONG *end ) { @@ -745,8 +754,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; @@ -868,6 +877,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(); @@ -885,6 +895,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; } @@ -894,6 +905,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) @@ -921,6 +933,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(); @@ -943,6 +956,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(); @@ -997,6 +1011,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 0d112aaa457..9464d0b745c 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2180,11 +2180,13 @@ const unixlib_entry_t __wine_unix_call_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)) { @@ -2192,9 +2194,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 7d75b6020fb..a8a7442f314 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -150,6 +150,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 ec1032c0ccc135d88a67bc3824c78ca3b7de5d95 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 2 Feb 2022 17:02:44 -0500 Subject: [PATCH 0466/2777] 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 5e1237b8ad5..40cf4a07056 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 61502497571388b29d422529ea3c105bf9f27a6c Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Mon, 14 Feb 2022 12:51:27 -0500 Subject: [PATCH 0467/2777] fsync: Type-check HANDLE in fsync_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 9498ccc8e2d..7ceee10661f 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -577,6 +577,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 05bf66511c1ec7f7cdd41c84086bcd7afd9866c8 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 18 Feb 2022 12:56:58 +0300 Subject: [PATCH 0468/2777] fsync: Fix semaphore grab attempt on wait all path. CW-Bug-Id: #20189 --- dlls/ntdll/unix/fsync.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 7ceee10661f..6ae1ada401b 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -1138,7 +1138,10 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, case FSYNC_SEMAPHORE: { struct semaphore *semaphore = obj->shm; - if (__sync_fetch_and_sub( &semaphore->count, 1 ) <= 0) + int current; + + if (!(current = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST )) + || __sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) != current) goto tooslow; break; } From 676acba6116ee54649a94be9b2c258497d68c17f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 18 Feb 2022 12:58:53 +0300 Subject: [PATCH 0469/2777] fsync: Always check for NULL object on wait all path. CW-Bug-Id: #20189 --- dlls/ntdll/unix/fsync.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 6ae1ada401b..83fd79166a0 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -1119,6 +1119,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, for (i = 0; i < count; i++) { struct fsync *obj = objs[i]; + if (!obj) continue; switch (obj->type) { case FSYNC_MUTEX: @@ -1183,6 +1184,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, for (--i; i >= 0; i--) { struct fsync *obj = objs[i]; + if (!obj) continue; switch (obj->type) { case FSYNC_MUTEX: From e0de4eb78434bcda556e3fa0fd6fccd31a009885 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 18 Feb 2022 13:04:01 +0300 Subject: [PATCH 0470/2777] fsync: Get rid of spin before futex wait. CW-Bug-Id: #20189 --- dlls/ntdll/unix/fsync.c | 99 +++++++++++++---------------------------- 1 file changed, 31 insertions(+), 68 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 83fd79166a0..1ddd77d22e7 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -84,15 +84,6 @@ struct timespec64 long long tv_nsec; }; -static inline void small_pause(void) -{ -#if defined(__i386__) || defined(__x86_64__) - __asm__ __volatile__( "rep;nop" : : : "memory" ); -#else - __asm__ __volatile__( "" : : : "memory" ); -#endif -} - static LONGLONG update_timeout( ULONGLONG end ) { LARGE_INTEGER now; @@ -154,7 +145,7 @@ static inline int futex_wait( int *addr, int val, const ULONGLONG *end ) timeout.tv_nsec = (tmp % TICKSPERSEC) * 100; return syscall( __NR_futex, addr, FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, - val, &timeout, 0, FUTEX_BITSET_MATCH_ANY ); + val, &timeout, 0, FUTEX_BITSET_MATCH_ANY ); } else { @@ -162,8 +153,6 @@ static inline int futex_wait( int *addr, int val, const ULONGLONG *end ) } } -static unsigned int spincount = 100; - int do_fsync(void) { #ifdef __linux__ @@ -173,8 +162,6 @@ int do_fsync(void) { syscall( __NR_futex_waitv, NULL, 0, 0, NULL, 0 ); do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; - if (getenv("WINEFSYNC_SPINCOUNT")) - spincount = atoi(getenv("WINEFSYNC_SPINCOUNT")); } return do_fsync_cached; @@ -760,7 +747,6 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, BOOL msgwait = FALSE, waited = FALSE; int has_fsync = 0, has_server = 0; int dummy_futex = 0; - unsigned int spin; LONGLONG timeleft; LARGE_INTEGER now; DWORD waitcount; @@ -870,22 +856,13 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, struct semaphore *semaphore = obj->shm; int current; - /* It would be a little clearer (and less error-prone) - * to use a dedicated interlocked_dec_if_nonzero() - * helper, but nesting loops like that is probably not - * great for performance... */ - for (spin = 0; spin <= spincount || current; ++spin) + if ((current = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST )) + && __sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) == current) { - if ((current = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST )) - && __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(); + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + if (waited) simulate_sched_quantum(); + return i; } - futex_vector_set( &futexes[i], &semaphore->count, 0 ); break; } @@ -902,22 +879,18 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, return i; } - for (spin = 0; spin <= spincount; ++spin) + if (!(tid = __sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() ))) { - if (!(tid = __sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() ))) - { - 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) - { - TRACE("Woken up by abandoned mutex %p [%d].\n", handles[i], i); - mutex->count = 1; - return STATUS_ABANDONED_WAIT_0 + i; - } - small_pause(); + 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) + { + TRACE("Woken up by abandoned mutex %p [%d].\n", handles[i], i); + mutex->count = 1; + return STATUS_ABANDONED_WAIT_0 + i; } futex_vector_set( &futexes[i], &mutex->tid, tid ); @@ -928,20 +901,15 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, { struct event *event = obj->shm; - for (spin = 0; spin <= spincount; ++spin) + if (__sync_val_compare_and_swap( &event->signaled, 1, 0 )) { - if (__sync_val_compare_and_swap( &event->signaled, 1, 0 )) - { - if (ac_odyssey && alertable) - usleep( 0 ); - - TRACE("Woken up by handle %p [%d].\n", handles[i], i); - if (waited) simulate_sched_quantum(); - return i; - } - small_pause(); - } + if (ac_odyssey && alertable) + usleep( 0 ); + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + if (waited) simulate_sched_quantum(); + return i; + } futex_vector_set( &futexes[i], &event->signaled, 0 ); break; } @@ -951,20 +919,15 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, { struct event *event = obj->shm; - for (spin = 0; spin <= spincount; ++spin) + if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) { - if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) - { - if (ac_odyssey && alertable) - usleep( 0 ); - - TRACE("Woken up by handle %p [%d].\n", handles[i], i); - if (waited) simulate_sched_quantum(); - return i; - } - small_pause(); - } + if (ac_odyssey && alertable) + usleep( 0 ); + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + if (waited) simulate_sched_quantum(); + return i; + } futex_vector_set( &futexes[i], &event->signaled, 0 ); break; } From 0bac3594ffa1f8380e410663c40e6ee2d4ee4c62 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 18 Feb 2022 12:46:59 +0300 Subject: [PATCH 0471/2777] fsync: Always use futex_waitv for wait. CW-Bug-Id: #20189 --- dlls/ntdll/unix/fsync.c | 34 +++++----------------------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 1ddd77d22e7..d12e2d5a989 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -57,10 +57,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(fsync); #include "pshpack4.h" #include "poppack.h" -#define FUTEX_WAIT_BITSET 9 -#define FUTEX_CLOCK_REALTIME 256 -#define FUTEX_BITSET_MATCH_ANY 0xffffffff - /* futex_waitv interface */ #ifndef __NR_futex_waitv @@ -135,24 +131,6 @@ static inline int futex_wake( int *addr, int val ) return syscall( __NR_futex, addr, 1, val, NULL, 0, 0 ); } -static inline int futex_wait( int *addr, int val, const ULONGLONG *end ) -{ - if (end) - { - struct timespec timeout; - ULONGLONG tmp = *end - SECS_1601_TO_1970 * TICKSPERSEC; - timeout.tv_sec = tmp / (ULONGLONG)TICKSPERSEC; - timeout.tv_nsec = (tmp % TICKSPERSEC) * 100; - - return syscall( __NR_futex, addr, FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, - val, &timeout, 0, FUTEX_BITSET_MATCH_ANY ); - } - else - { - return syscall( __NR_futex, addr, 0, val, NULL, 0, 0 ); - } -} - int do_fsync(void) { #ifdef __linux__ @@ -706,17 +684,18 @@ NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN alertable ) { + struct futex_waitv futexes[2]; int ret; + futex_vector_set( &futexes[0], addr, val ); + if (alertable) { int *apc_futex = ntdll_get_thread_data()->fsync_apc_futex; - struct futex_waitv futexes[2]; if (__atomic_load_n( apc_futex, __ATOMIC_SEQ_CST )) return STATUS_USER_APC; - futex_vector_set( &futexes[0], addr, val ); futex_vector_set( &futexes[1], apc_futex, 0 ); ret = futex_wait_multiple( futexes, 2, end ); @@ -726,7 +705,7 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN aler } else { - ret = futex_wait( addr, val, end ); + ret = futex_wait_multiple( futexes, 1, end ); } if (!ret) @@ -963,10 +942,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, return STATUS_TIMEOUT; } - if (waitcount == 1) - ret = futex_wait( u64_to_ptr(futexes[0].uaddr), futexes[0].val, timeout ? &end : NULL ); - else - ret = futex_wait_multiple( futexes, waitcount, timeout ? &end : NULL ); + ret = futex_wait_multiple( futexes, waitcount, timeout ? &end : NULL ); /* FUTEX_WAIT_MULTIPLE can succeed or return -EINTR, -EAGAIN, * -EFAULT/-EACCES, -ETIMEDOUT. In the first three cases we need to From 5c205cf6dfa53c849ed65462de248d4c3bbccfd7 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 21 Feb 2022 12:32:49 -0600 Subject: [PATCH 0472/2777] ntdll: Include linux/futex.h in fsync.c. --- configure.ac | 1 + dlls/ntdll/unix/fsync.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/configure.ac b/configure.ac index ac1508c86c5..84006a06a45 100644 --- a/configure.ac +++ b/configure.ac @@ -419,6 +419,7 @@ AC_CHECK_HEADERS(\ link.h \ linux/cdrom.h \ linux/filter.h \ + linux/futex.h \ linux/hdreg.h \ linux/hidraw.h \ linux/input.h \ diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index d12e2d5a989..cee5a8a08f1 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -38,6 +38,9 @@ #ifdef HAVE_SYS_SYSCALL_H # include #endif +#ifdef HAVE_LINUX_FUTEX_H +# include +#endif #include #include From a3afaf18e4944ea6488867041890cb9165cd18bc Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 27 Apr 2022 15:52:53 -0500 Subject: [PATCH 0473/2777] fsync: Reuse shared mem indices. CW-Bug-Id: #20560 --- server/console.c | 1 + server/device.c | 2 ++ server/event.c | 2 ++ server/fd.c | 1 + server/fsync.c | 66 +++++++++++++++++++++++++++++++++++++++++++++--- server/fsync.h | 1 + server/process.c | 1 + server/queue.c | 1 + server/thread.c | 7 +++++ server/timer.c | 2 ++ 10 files changed, 81 insertions(+), 3 deletions(-) diff --git a/server/console.c b/server/console.c index c229268f834..00c09d1cc01 100644 --- a/server/console.c +++ b/server/console.c @@ -895,6 +895,7 @@ static void console_server_destroy( struct object *obj ) disconnect_console_server( server ); if (server->fd) release_object( server->fd ); if (do_esync()) close( server->esync_fd ); + if (server->fsync_idx) fsync_free_shm_idx( server->fsync_idx ); } static struct object *console_server_lookup_name( struct object *obj, struct unicode_str *name, diff --git a/server/device.c b/server/device.c index 90e0a0c1fee..7e9911efb6a 100644 --- a/server/device.c +++ b/server/device.c @@ -853,6 +853,7 @@ static void device_manager_destroy( struct object *obj ) if (do_esync()) close( manager->esync_fd ); + if (manager->fsync_idx) fsync_free_shm_idx( manager->fsync_idx ); } static struct device_manager *create_device_manager(void) @@ -865,6 +866,7 @@ static struct device_manager *create_device_manager(void) list_init( &manager->devices ); list_init( &manager->requests ); wine_rb_init( &manager->kernel_objects, compare_kernel_object ); + manager->fsync_idx = 0; if (do_fsync()) manager->fsync_idx = fsync_alloc_shm( 0, 0 ); diff --git a/server/event.c b/server/event.c index aa1b0a4002a..b93a9960ad2 100644 --- a/server/event.c +++ b/server/event.c @@ -161,6 +161,7 @@ struct event *create_event( struct object *root, const struct unicode_str *name, list_init( &event->kernel_object ); event->manual_reset = manual_reset; event->signaled = initial_state; + event->fsync_idx = 0; if (do_fsync()) event->fsync_idx = fsync_alloc_shm( initial_state, 0 ); @@ -300,6 +301,7 @@ static void event_destroy( struct object *obj ) if (do_esync()) close( event->esync_fd ); + if (event->fsync_idx) fsync_free_shm_idx( event->fsync_idx ); } struct keyed_event *create_keyed_event( struct object *root, const struct unicode_str *name, diff --git a/server/fd.c b/server/fd.c index 908bf70fca9..d6ae8d08a1c 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1602,6 +1602,7 @@ static void fd_destroy( struct object *obj ) if (do_esync()) close( fd->esync_fd ); + if (fd->fsync_idx) fsync_free_shm_idx( fd->fsync_idx ); } /* check if the desired access is possible without violating */ diff --git a/server/fsync.c b/server/fsync.c index 593070ad62e..3c1e709d7e3 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef HAVE_SYS_STAT_H # include #endif @@ -76,6 +77,12 @@ static long pagesize; static int is_fsync_initialized; +static uint64_t *shm_idx_free_map; +static uint32_t shm_idx_free_map_size; /* uint64_t word count */ +static uint32_t shm_idx_free_search_start_hint; + +#define BITS_IN_FREE_MAP_WORD (8 * sizeof(*shm_idx_free_map)) + static void shm_cleanup(void) { close( shm_fd ); @@ -115,6 +122,11 @@ void fsync_init(void) fprintf( stderr, "fsync: up and running.\n" ); + shm_idx_free_map_size = 256; + shm_idx_free_map = malloc( shm_idx_free_map_size * sizeof(*shm_idx_free_map) ); + memset( shm_idx_free_map, 0xff, shm_idx_free_map_size * sizeof(*shm_idx_free_map) ); + shm_idx_free_map[0] &= ~(uint64_t)1; /* Avoid allocating shm_index 0. */ + atexit( shm_cleanup ); } @@ -188,6 +200,7 @@ static void fsync_destroy( struct object *obj ) struct fsync *fsync = (struct fsync *)obj; if (fsync->type == FSYNC_MUTEX) list_remove( &fsync->mutex_entry ); + fsync_free_shm_idx( fsync->shm_idx ); } static void *get_shm( unsigned int idx ) @@ -226,12 +239,22 @@ static void *get_shm( unsigned int idx ) return (void *)((unsigned long)shm_addrs[entry] + offset); } -/* FIXME: This is rather inefficient... */ -static unsigned int shm_idx_counter = 1; +static int alloc_shm_idx_from_word( unsigned int word_index ) +{ + int ret; + + if (!shm_idx_free_map[word_index]) return 0; + + ret = __builtin_ctzll( shm_idx_free_map[word_index] ); + shm_idx_free_map[word_index] &= ~((uint64_t)1 << ret); + shm_idx_free_search_start_hint = shm_idx_free_map[word_index] ? word_index : word_index + 1; + return word_index * BITS_IN_FREE_MAP_WORD + ret; +} unsigned int fsync_alloc_shm( int low, int high ) { #ifdef __linux__ + unsigned int i; int shm_idx; int *shm; @@ -240,7 +263,29 @@ unsigned int fsync_alloc_shm( int low, int high ) if (!is_fsync_initialized) return 0; - shm_idx = shm_idx_counter++; + /* shm_idx_free_search_start_hint is always at the first word with a free index or before that. */ + for (i = shm_idx_free_search_start_hint; i < shm_idx_free_map_size; ++i) + if ((shm_idx = alloc_shm_idx_from_word( i ))) break; + + if (!shm_idx) + { + uint32_t old_size, new_size; + uint64_t *new_alloc; + + old_size = shm_idx_free_map_size; + new_size = old_size + 256; + new_alloc = realloc( shm_idx_free_map, new_size * sizeof(*new_alloc) ); + if (!new_alloc) + { + fprintf( stderr, "fsync: couldn't expand shm_idx_free_map to size %zd.", + new_size * sizeof(*new_alloc) ); + return 0; + } + memset( new_alloc + old_size, 0xff, (new_size - old_size) * sizeof(*new_alloc) ); + shm_idx_free_map = new_alloc; + shm_idx_free_map_size = new_size; + shm_idx = alloc_shm_idx_from_word( old_size ); + } while (shm_idx * 8 >= shm_size) { @@ -265,6 +310,21 @@ unsigned int fsync_alloc_shm( int low, int high ) #endif } +void fsync_free_shm_idx( int shm_idx ) +{ + unsigned int idx; + uint64_t mask; + + assert( shm_idx ); + assert( shm_idx < shm_idx_free_map_size * BITS_IN_FREE_MAP_WORD ); + idx = shm_idx / BITS_IN_FREE_MAP_WORD; + mask = (uint64_t)1 << (shm_idx % BITS_IN_FREE_MAP_WORD); + assert( !(shm_idx_free_map[idx] & mask) ); + shm_idx_free_map[idx] |= mask; + if (idx < shm_idx_free_search_start_hint) + shm_idx_free_search_start_hint = idx; +} + static int type_matches( enum fsync_type type1, enum fsync_type type2 ) { return (type1 == type2) || diff --git a/server/fsync.h b/server/fsync.h index a91939b7f0a..ee1a729e77e 100644 --- a/server/fsync.h +++ b/server/fsync.h @@ -21,6 +21,7 @@ extern int do_fsync(void); extern void fsync_init(void); extern unsigned int fsync_alloc_shm( int low, int high ); +extern void fsync_free_shm_idx( int shm_idx ); extern void fsync_wake_futex( unsigned int shm_idx ); extern void fsync_clear_futex( unsigned int shm_idx ); extern void fsync_wake_up( struct object *obj ); diff --git a/server/process.c b/server/process.c index 130ab0148e1..0b6121ec389 100644 --- a/server/process.c +++ b/server/process.c @@ -805,6 +805,7 @@ static void process_destroy( struct object *obj ) free( process->dir_cache ); free( process->image ); if (do_esync()) close( process->esync_fd ); + if (process->fsync_idx) fsync_free_shm_idx( process->fsync_idx ); } /* dump a process on stdout for debugging purposes */ diff --git a/server/queue.c b/server/queue.c index 8d59f62f379..72abbc080d0 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1254,6 +1254,7 @@ static void msg_queue_destroy( struct object *obj ) { struct msg_queue *queue = (struct msg_queue *)obj; if (!queue->destroyed) cleanup_msg_queue( queue ); + if (queue->fsync_idx) fsync_free_shm_idx( queue->fsync_idx ); } /* free the message queue of a thread at thread exit */ diff --git a/server/thread.c b/server/thread.c index 5bb509c2a08..b95b4097ef3 100644 --- a/server/thread.c +++ b/server/thread.c @@ -486,6 +486,8 @@ struct thread *create_thread( int fd, struct process *process, const struct secu } } + thread->fsync_idx = 0; + if (do_fsync()) { thread->fsync_idx = fsync_alloc_shm( 0, 0 ); @@ -586,6 +588,11 @@ static void destroy_thread( struct object *obj ) if (do_esync()) close( thread->esync_fd ); + if (thread->fsync_idx) + { + fsync_free_shm_idx( thread->fsync_idx ); + fsync_free_shm_idx( thread->fsync_apc_idx ); + } } /* dump a thread on stdout for debugging purposes */ diff --git a/server/timer.c b/server/timer.c index afc12ff03ad..884ace9376f 100644 --- a/server/timer.c +++ b/server/timer.c @@ -119,6 +119,7 @@ static struct timer *create_timer( struct object *root, const struct unicode_str timer->timeout = NULL; timer->thread = NULL; timer->esync_fd = -1; + timer->fsync_idx = 0; if (do_fsync()) timer->fsync_idx = fsync_alloc_shm( 0, 0 ); @@ -258,6 +259,7 @@ static void timer_destroy( struct object *obj ) if (timer->timeout) remove_timeout_user( timer->timeout ); if (timer->thread) release_object( timer->thread ); if (do_esync()) close( timer->esync_fd ); + if (timer->fsync_idx) fsync_free_shm_idx( timer->fsync_idx ); } /* create a timer */ From 39979963d68cd595a8800ceef72b92dd29663358 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 29 Apr 2022 16:57:13 -0500 Subject: [PATCH 0474/2777] fsync: Use CLOCK_MONOTONIC for relative timeouts. CW-Bug-Id: #20548 Test shows that relative wait timeouts on Windows do not include the time spent is suspend. Using CLOCK_MONOTONIC on Linux is a closer approximation for that. --- dlls/ntdll/unix/fsync.c | 88 +++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 34 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index cee5a8a08f1..b45a21748a9 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -83,13 +83,50 @@ struct timespec64 long long tv_nsec; }; -static LONGLONG update_timeout( ULONGLONG end ) +static LONGLONG nt_time_from_ts( struct timespec *ts ) { - LARGE_INTEGER now; + return ticks_from_time_t( ts->tv_sec ) + (ts->tv_nsec + 50) / 100; +} + +static void get_wait_end_time( const LARGE_INTEGER **timeout, struct timespec64 *end, clockid_t *clock_id ) +{ + ULONGLONG nt_end; + + if (!*timeout) return; + if ((*timeout)->QuadPart == TIMEOUT_INFINITE) + { + *timeout = NULL; + return; + } + + if ((*timeout)->QuadPart > 0) + { + nt_end = (*timeout)->QuadPart; + *clock_id = CLOCK_REALTIME; + } + else + { + struct timespec ts; + + clock_gettime( CLOCK_MONOTONIC, &ts ); + nt_end = nt_time_from_ts( &ts ) - (*timeout)->QuadPart; + *clock_id = CLOCK_MONOTONIC; + } + + nt_end -= SECS_1601_TO_1970 * TICKSPERSEC; + end->tv_sec = nt_end / (ULONGLONG)TICKSPERSEC; + end->tv_nsec = (nt_end % TICKSPERSEC) * 100; +} + +static LONGLONG update_timeout( const struct timespec64 *end, clockid_t clock_id ) +{ + struct timespec end_ts, ts; LONGLONG timeleft; - NtQuerySystemTime( &now ); - timeleft = end - now.QuadPart; + clock_gettime( clock_id, &ts ); + end_ts.tv_sec = end->tv_sec; + end_ts.tv_nsec = end->tv_nsec; + timeleft = nt_time_from_ts( &end_ts ) - nt_time_from_ts( &ts ); if (timeleft < 0) timeleft = 0; return timeleft; } @@ -112,21 +149,12 @@ static void simulate_sched_quantum(void) } static inline int futex_wait_multiple( const struct futex_waitv *futexes, - int count, const ULONGLONG *end ) + int count, const struct timespec64 *end, clockid_t clock_id ) { if (end) - { - struct timespec64 timeout; - ULONGLONG tmp = *end - SECS_1601_TO_1970 * TICKSPERSEC; - timeout.tv_sec = tmp / (ULONGLONG)TICKSPERSEC; - timeout.tv_nsec = (tmp % TICKSPERSEC) * 100; - - return syscall( __NR_futex_waitv, futexes, count, 0, &timeout, CLOCK_REALTIME ); - } + return syscall( __NR_futex_waitv, futexes, count, 0, end, clock_id ); else - { return syscall( __NR_futex_waitv, futexes, count, 0, NULL, 0 ); - } } static inline int futex_wake( int *addr, int val ) @@ -685,7 +713,8 @@ NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) return STATUS_SUCCESS; } -static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN alertable ) +static NTSTATUS do_single_wait( int *addr, int val, const struct timespec64 *end, clockid_t clock_id, + BOOLEAN alertable ) { struct futex_waitv futexes[2]; int ret; @@ -701,14 +730,14 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN aler futex_vector_set( &futexes[1], apc_futex, 0 ); - ret = futex_wait_multiple( futexes, 2, end ); + ret = futex_wait_multiple( futexes, 2, end, clock_id ); if (__atomic_load_n( apc_futex, __ATOMIC_SEQ_CST )) return STATUS_USER_APC; } else { - ret = futex_wait_multiple( futexes, 1, end ); + ret = futex_wait_multiple( futexes, 1, end, clock_id ); } if (!ret) @@ -728,11 +757,11 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, struct fsync *objs[MAXIMUM_WAIT_OBJECTS]; BOOL msgwait = FALSE, waited = FALSE; int has_fsync = 0, has_server = 0; + clockid_t clock_id = 0; + struct timespec64 end; int dummy_futex = 0; LONGLONG timeleft; - LARGE_INTEGER now; DWORD waitcount; - ULONGLONG end; int i, ret; /* Grab the APC futex if we don't already have it. */ @@ -753,16 +782,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, } } - NtQuerySystemTime( &now ); - if (timeout) - { - if (timeout->QuadPart == TIMEOUT_INFINITE) - timeout = NULL; - else if (timeout->QuadPart > 0) - end = timeout->QuadPart; - else - end = now.QuadPart - timeout->QuadPart; - } + get_wait_end_time( &timeout, &end, &clock_id ); for (i = 0; i < count; i++) { @@ -798,7 +818,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, TRACE(", timeout = INFINITE.\n"); else { - timeleft = update_timeout( end ); + timeleft = update_timeout( &end, clock_id ); TRACE(", timeout = %ld.%07ld sec.\n", (long) (timeleft / TICKSPERSEC), (long) (timeleft % TICKSPERSEC)); } @@ -945,7 +965,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, return STATUS_TIMEOUT; } - ret = futex_wait_multiple( futexes, waitcount, timeout ? &end : NULL ); + ret = futex_wait_multiple( futexes, waitcount, timeout ? &end : NULL, clock_id ); /* FUTEX_WAIT_MULTIPLE can succeed or return -EINTR, -EAGAIN, * -EFAULT/-EACCES, -ETIMEDOUT. In the first three cases we need to @@ -1007,7 +1027,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, while ((current = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ))) { - status = do_single_wait( &mutex->tid, current, timeout ? &end : NULL, alertable ); + status = do_single_wait( &mutex->tid, current, timeout ? &end : NULL, clock_id, alertable ); if (status != STATUS_PENDING) break; } @@ -1019,7 +1039,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, while (!__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) { - status = do_single_wait( &event->signaled, 0, timeout ? &end : NULL, alertable ); + status = do_single_wait( &event->signaled, 0, timeout ? &end : NULL, clock_id, alertable ); if (status != STATUS_PENDING) break; } From 03cbe10d2928c59e6cc8d938e173acba612684cd Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 4 Jul 2022 10:27:12 -0500 Subject: [PATCH 0475/2777] fsync: Return a copy of the object instead of cache pointer from get_object(). CW-Bug-Id: #20826 --- dlls/ntdll/unix/fsync.c | 123 +++++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 58 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index b45a21748a9..0f9ebc76463 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -270,14 +270,14 @@ static inline UINT_PTR handle_to_index( HANDLE handle, UINT_PTR *entry ) return idx % FSYNC_LIST_BLOCK_SIZE; } -static struct fsync *add_to_list( HANDLE handle, enum fsync_type type, void *shm ) +static void add_to_list( HANDLE handle, enum fsync_type type, void *shm ) { UINT_PTR entry, idx = handle_to_index( handle, &entry ); if (entry >= FSYNC_LIST_ENTRIES) { FIXME( "too many allocated handles, not caching %p\n", handle ); - return FALSE; + return; } if (!fsync_list[entry]) /* do we need to allocate a new block of entries? */ @@ -287,38 +287,37 @@ static struct fsync *add_to_list( HANDLE handle, enum fsync_type type, void *shm { void *ptr = anon_mmap_alloc( FSYNC_LIST_BLOCK_SIZE * sizeof(struct fsync), PROT_READ | PROT_WRITE ); - if (ptr == MAP_FAILED) return FALSE; + if (ptr == MAP_FAILED) return; fsync_list[entry] = ptr; } } if (!__sync_val_compare_and_swap((int *)&fsync_list[entry][idx].type, 0, type )) fsync_list[entry][idx].shm = shm; - - return &fsync_list[entry][idx]; } -static struct fsync *get_cached_object( HANDLE handle ) +static BOOL get_cached_object( HANDLE handle, struct fsync *obj ) { UINT_PTR entry, idx = handle_to_index( handle, &entry ); - if (entry >= FSYNC_LIST_ENTRIES || !fsync_list[entry]) return NULL; - if (!fsync_list[entry][idx].type) return NULL; + if (entry >= FSYNC_LIST_ENTRIES || !fsync_list[entry]) return FALSE; + if (!fsync_list[entry][idx].type) return FALSE; - return &fsync_list[entry][idx]; + *obj = fsync_list[entry][idx]; + return TRUE; } /* Gets an object. This is either a proper fsync object (i.e. an event, * semaphore, etc. created using create_fsync) or a generic synchronizable * server-side object which the server will signal (e.g. a process, thread, * message queue, etc.) */ -static NTSTATUS get_object( HANDLE handle, struct fsync **obj ) +static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) { NTSTATUS ret = STATUS_SUCCESS; unsigned int shm_idx = 0; enum fsync_type type; - if ((*obj = get_cached_object( handle ))) return STATUS_SUCCESS; + if (get_cached_object( handle, obj )) return STATUS_SUCCESS; if ((INT_PTR)handle < 0) { @@ -341,13 +340,14 @@ static NTSTATUS get_object( HANDLE handle, struct fsync **obj ) if (ret) { WARN("Failed to retrieve shm index for handle %p, status %#x.\n", handle, (unsigned int)ret); - *obj = NULL; return ret; } TRACE("Got shm index %d for handle %p.\n", shm_idx, handle); - *obj = add_to_list( handle, type, get_shm( shm_idx ) ); + obj->type = type; + obj->shm = get_shm( shm_idx ); + add_to_list( handle, type, obj->shm ); return ret; } @@ -498,7 +498,7 @@ NTSTATUS fsync_open_semaphore( HANDLE *handle, ACCESS_MASK access, NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) { - struct fsync *obj; + struct fsync obj; struct semaphore *semaphore; ULONG current; NTSTATUS ret; @@ -506,7 +506,7 @@ NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) TRACE("%p, %d, %p.\n", handle, (int)count, prev); if ((ret = get_object( handle, &obj ))) return ret; - semaphore = obj->shm; + semaphore = obj.shm; do { @@ -524,7 +524,7 @@ NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) NTSTATUS fsync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len ) { - struct fsync *obj; + struct fsync obj; struct semaphore *semaphore; SEMAPHORE_BASIC_INFORMATION *out = info; NTSTATUS ret; @@ -532,7 +532,7 @@ NTSTATUS fsync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len ) TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); if ((ret = get_object( handle, &obj ))) return ret; - semaphore = obj->shm; + semaphore = obj.shm; out->CurrentCount = semaphore->count; out->MaximumCount = semaphore->max; @@ -564,16 +564,16 @@ NTSTATUS fsync_open_event( HANDLE *handle, ACCESS_MASK access, NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) { struct event *event; - struct fsync *obj; + struct fsync obj; LONG current; NTSTATUS ret; TRACE("%p.\n", handle); if ((ret = get_object( handle, &obj ))) return ret; - event = obj->shm; + event = obj.shm; - if (obj->type != FSYNC_MANUAL_EVENT && obj->type != FSYNC_AUTO_EVENT) + 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 ))) @@ -587,14 +587,14 @@ NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) { struct event *event; - struct fsync *obj; + struct fsync obj; LONG current; NTSTATUS ret; TRACE("%p.\n", handle); if ((ret = get_object( handle, &obj ))) return ret; - event = obj->shm; + event = obj.shm; current = __atomic_exchange_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); @@ -606,14 +606,14 @@ NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) NTSTATUS fsync_pulse_event( HANDLE handle, LONG *prev ) { struct event *event; - struct fsync *obj; + struct fsync obj; LONG current; NTSTATUS ret; TRACE("%p.\n", handle); if ((ret = get_object( handle, &obj ))) return ret; - event = obj->shm; + event = obj.shm; /* This isn't really correct; an application could miss the write. * Unfortunately we can't really do much better. Fortunately this is rarely @@ -635,17 +635,17 @@ NTSTATUS fsync_pulse_event( HANDLE handle, LONG *prev ) NTSTATUS fsync_query_event( HANDLE handle, void *info, ULONG *ret_len ) { struct event *event; - struct fsync *obj; + struct fsync obj; EVENT_BASIC_INFORMATION *out = info; NTSTATUS ret; TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); if ((ret = get_object( handle, &obj ))) return ret; - event = obj->shm; + event = obj.shm; out->EventState = event->signaled; - out->EventType = (obj->type == FSYNC_AUTO_EVENT ? SynchronizationEvent : NotificationEvent); + out->EventType = (obj.type == FSYNC_AUTO_EVENT ? SynchronizationEvent : NotificationEvent); if (ret_len) *ret_len = sizeof(*out); return STATUS_SUCCESS; @@ -672,13 +672,13 @@ NTSTATUS fsync_open_mutex( HANDLE *handle, ACCESS_MASK access, NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) { struct mutex *mutex; - struct fsync *obj; + struct fsync obj; NTSTATUS ret; TRACE("%p, %p.\n", handle, prev); if ((ret = get_object( handle, &obj ))) return ret; - mutex = obj->shm; + mutex = obj.shm; if (mutex->tid != GetCurrentThreadId()) return STATUS_MUTANT_NOT_OWNED; @@ -695,7 +695,7 @@ NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) { - struct fsync *obj; + struct fsync obj; struct mutex *mutex; MUTANT_BASIC_INFORMATION *out = info; NTSTATUS ret; @@ -703,7 +703,7 @@ NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); if ((ret = get_object( handle, &obj ))) return ret; - mutex = obj->shm; + mutex = obj.shm; out->CurrentCount = 1 - mutex->count; out->OwnedByCaller = (mutex->tid == GetCurrentThreadId()); @@ -754,7 +754,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, static const LARGE_INTEGER zero = {0}; struct futex_waitv futexes[MAXIMUM_WAIT_OBJECTS + 1]; - struct fsync *objs[MAXIMUM_WAIT_OBJECTS]; + struct fsync objs[MAXIMUM_WAIT_OBJECTS]; BOOL msgwait = FALSE, waited = FALSE; int has_fsync = 0, has_server = 0; clockid_t clock_id = 0; @@ -788,14 +788,28 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, { ret = get_object( handles[i], &objs[i] ); if (ret == STATUS_SUCCESS) + { + if (!objs[i].type) + { + /* Someone probably closed an object while waiting on it. */ + WARN("Handle %p has type 0; was it closed?\n", handles[i]); + return STATUS_INVALID_HANDLE; + } has_fsync = 1; + } else if (ret == STATUS_NOT_IMPLEMENTED) + { + objs[i].type = 0; + objs[i].shm = NULL; has_server = 1; + } else + { return ret; + } } - if (count && objs[count - 1] && objs[count - 1]->type == FSYNC_QUEUE) + if (count && objs[count - 1].type == FSYNC_QUEUE) msgwait = TRUE; if (has_fsync && has_server) @@ -840,17 +854,10 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, for (i = 0; i < count; i++) { - struct fsync *obj = objs[i]; + struct fsync *obj = &objs[i]; - if (obj) + if (obj->type) { - if (!obj->type) /* gcc complains if we put this in the switch */ - { - /* Someone probably closed an object while waiting on it. */ - WARN("Handle %p has type 0; was it closed?\n", handles[i]); - return STATUS_INVALID_HANDLE; - } - switch (obj->type) { case FSYNC_SEMAPHORE: @@ -1016,9 +1023,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, for (i = 0; i < count; i++) { - struct fsync *obj = objs[i]; + struct fsync *obj = &objs[i]; - if (obj && obj->type == FSYNC_MUTEX) + if (obj->type == FSYNC_MUTEX) { struct mutex *mutex = obj->shm; @@ -1032,7 +1039,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, break; } } - else if (obj) + else if (obj->type) { /* this works for semaphores too */ struct event *event = obj->shm; @@ -1058,9 +1065,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, * handles were signaled. Check to make sure they still are. */ for (i = 0; i < count; i++) { - struct fsync *obj = objs[i]; + struct fsync *obj = &objs[i]; - if (obj && obj->type == FSYNC_MUTEX) + if (obj->type == FSYNC_MUTEX) { struct mutex *mutex = obj->shm; int tid = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ); @@ -1068,7 +1075,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, if (tid && tid != ~0 && tid != GetCurrentThreadId()) goto tryagain; } - else if (obj) + else if (obj->type) { struct event *event = obj->shm; @@ -1080,8 +1087,8 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, /* Yep, still signaled. Now quick, grab everything. */ for (i = 0; i < count; i++) { - struct fsync *obj = objs[i]; - if (!obj) continue; + struct fsync *obj = &objs[i]; + if (!obj->type) continue; switch (obj->type) { case FSYNC_MUTEX: @@ -1127,9 +1134,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, * Make sure to let ourselves know that we grabbed the mutexes. */ for (i = 0; i < count; i++) { - if (objs[i] && objs[i]->type == FSYNC_MUTEX) + if (objs[i].type == FSYNC_MUTEX) { - struct mutex *mutex = objs[i]->shm; + struct mutex *mutex = objs[i].shm; mutex->count++; } } @@ -1145,8 +1152,8 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, tooslow: for (--i; i >= 0; i--) { - struct fsync *obj = objs[i]; - if (!obj) continue; + struct fsync *obj = &objs[i]; + if (!obj->type) continue; switch (obj->type) { case FSYNC_MUTEX: @@ -1220,10 +1227,10 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an BOOLEAN alertable, const LARGE_INTEGER *timeout ) { BOOL msgwait = FALSE; - struct fsync *obj; + struct fsync obj; NTSTATUS ret; - if (count && !get_object( handles[count - 1], &obj ) && obj->type == FSYNC_QUEUE) + if (count && !get_object( handles[count - 1], &obj ) && obj.type == FSYNC_QUEUE) { msgwait = TRUE; server_set_msgwait( 1 ); @@ -1240,12 +1247,12 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an NTSTATUS fsync_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable, const LARGE_INTEGER *timeout ) { - struct fsync *obj; + struct fsync obj; NTSTATUS ret; if ((ret = get_object( signal, &obj ))) return ret; - switch (obj->type) + switch (obj.type) { case FSYNC_SEMAPHORE: ret = fsync_release_semaphore( signal, 1, NULL ); From 88c4c09e2c80d06de36c9bb164bb7c7e7c221486 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 4 Jul 2022 11:40:08 -0500 Subject: [PATCH 0476/2777] fsync: Synchronize access to object cache. CW-Bug-Id: #20826 --- dlls/ntdll/unix/fsync.c | 57 +++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 0f9ebc76463..8db9500da75 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -262,6 +262,7 @@ static void *get_shm( unsigned int idx ) static struct fsync *fsync_list[FSYNC_LIST_ENTRIES]; static struct fsync fsync_list_initial_block[FSYNC_LIST_BLOCK_SIZE]; +static int cache_locked; static inline UINT_PTR handle_to_index( HANDLE handle, UINT_PTR *entry ) { @@ -270,6 +271,26 @@ static inline UINT_PTR handle_to_index( HANDLE handle, UINT_PTR *entry ) return idx % FSYNC_LIST_BLOCK_SIZE; } +static void small_pause(void) +{ +#ifdef __i386__ + __asm__ __volatile__( "rep;nop" : : : "memory" ); +#else + __asm__ __volatile__( "" : : : "memory" ); +#endif +} + +static void lock_obj_cache(void) +{ + while (__sync_val_compare_and_swap( &cache_locked, 0, 1 )) + small_pause(); +} + +static void unlock_obj_cache(void) +{ + __atomic_store_n( &cache_locked, 0, __ATOMIC_SEQ_CST ); +} + static void add_to_list( HANDLE handle, enum fsync_type type, void *shm ) { UINT_PTR entry, idx = handle_to_index( handle, &entry ); @@ -288,23 +309,29 @@ static void add_to_list( HANDLE handle, enum fsync_type type, void *shm ) void *ptr = anon_mmap_alloc( FSYNC_LIST_BLOCK_SIZE * sizeof(struct fsync), PROT_READ | PROT_WRITE ); if (ptr == MAP_FAILED) return; - fsync_list[entry] = ptr; + if (__sync_val_compare_and_swap( &fsync_list[entry], NULL, ptr )) + munmap( ptr, FSYNC_LIST_BLOCK_SIZE * sizeof(struct fsync) ); } } - if (!__sync_val_compare_and_swap((int *)&fsync_list[entry][idx].type, 0, type )) - fsync_list[entry][idx].shm = shm; + lock_obj_cache(); + fsync_list[entry][idx].type = type; + fsync_list[entry][idx].shm = shm; + unlock_obj_cache(); } static BOOL get_cached_object( HANDLE handle, struct fsync *obj ) { + BOOL ret = TRUE; UINT_PTR entry, idx = handle_to_index( handle, &entry ); if (entry >= FSYNC_LIST_ENTRIES || !fsync_list[entry]) return FALSE; - if (!fsync_list[entry][idx].type) return FALSE; - *obj = fsync_list[entry][idx]; - return TRUE; + lock_obj_cache(); + if (!fsync_list[entry][idx].type) ret = FALSE; + else *obj = fsync_list[entry][idx]; + unlock_obj_cache(); + return ret; } /* Gets an object. This is either a proper fsync object (i.e. an event, @@ -359,7 +386,16 @@ NTSTATUS fsync_close( HANDLE handle ) if (entry < FSYNC_LIST_ENTRIES && fsync_list[entry]) { - if (__atomic_exchange_n( &fsync_list[entry][idx].type, 0, __ATOMIC_SEQ_CST )) + enum fsync_type type; + + lock_obj_cache(); + if ((type = fsync_list[entry][idx].type)) + { + fsync_list[entry][idx].type = 0; + fsync_list[entry][idx].shm = NULL; + } + unlock_obj_cache(); + if (type) return STATUS_SUCCESS; } @@ -789,12 +825,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, ret = get_object( handles[i], &objs[i] ); if (ret == STATUS_SUCCESS) { - if (!objs[i].type) - { - /* Someone probably closed an object while waiting on it. */ - WARN("Handle %p has type 0; was it closed?\n", handles[i]); - return STATUS_INVALID_HANDLE; - } + assert( objs[i].type ); has_fsync = 1; } else if (ret == STATUS_NOT_IMPLEMENTED) From d755055088e79938fd1065a7614b857d0403c856 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 1 Aug 2022 10:50:13 -0500 Subject: [PATCH 0477/2777] fsync: Use atomic cache stores and load instead of locking cache. CW-Bug-Id: #21050 (replaces "fsync: Synchronize access to object cache.") --- dlls/ntdll/unix/fsync.c | 91 +++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 49 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 8db9500da75..c7df9c77da1 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -260,9 +260,16 @@ static void *get_shm( unsigned int idx ) #define FSYNC_LIST_BLOCK_SIZE (65536 / sizeof(struct fsync)) #define FSYNC_LIST_ENTRIES 256 -static struct fsync *fsync_list[FSYNC_LIST_ENTRIES]; -static struct fsync fsync_list_initial_block[FSYNC_LIST_BLOCK_SIZE]; -static int cache_locked; +struct fsync_cache +{ + enum fsync_type type; + unsigned int shm_idx; +}; + +C_ASSERT(sizeof(struct fsync_cache) == sizeof(uint64_t)); + +static struct fsync_cache *fsync_list[FSYNC_LIST_ENTRIES]; +static struct fsync_cache fsync_list_initial_block[FSYNC_LIST_BLOCK_SIZE]; static inline UINT_PTR handle_to_index( HANDLE handle, UINT_PTR *entry ) { @@ -271,29 +278,10 @@ static inline UINT_PTR handle_to_index( HANDLE handle, UINT_PTR *entry ) return idx % FSYNC_LIST_BLOCK_SIZE; } -static void small_pause(void) -{ -#ifdef __i386__ - __asm__ __volatile__( "rep;nop" : : : "memory" ); -#else - __asm__ __volatile__( "" : : : "memory" ); -#endif -} - -static void lock_obj_cache(void) -{ - while (__sync_val_compare_and_swap( &cache_locked, 0, 1 )) - small_pause(); -} - -static void unlock_obj_cache(void) -{ - __atomic_store_n( &cache_locked, 0, __ATOMIC_SEQ_CST ); -} - -static void add_to_list( HANDLE handle, enum fsync_type type, void *shm ) +static void add_to_list( HANDLE handle, enum fsync_type type, unsigned int shm_idx ) { UINT_PTR entry, idx = handle_to_index( handle, &entry ); + struct fsync_cache cache; if (entry >= FSYNC_LIST_ENTRIES) { @@ -306,32 +294,41 @@ static void add_to_list( HANDLE handle, enum fsync_type type, void *shm ) if (!entry) fsync_list[0] = fsync_list_initial_block; else { - void *ptr = anon_mmap_alloc( FSYNC_LIST_BLOCK_SIZE * sizeof(struct fsync), + void *ptr = anon_mmap_alloc( FSYNC_LIST_BLOCK_SIZE * sizeof(*fsync_list[entry]), PROT_READ | PROT_WRITE ); if (ptr == MAP_FAILED) return; if (__sync_val_compare_and_swap( &fsync_list[entry], NULL, ptr )) - munmap( ptr, FSYNC_LIST_BLOCK_SIZE * sizeof(struct fsync) ); + munmap( ptr, FSYNC_LIST_BLOCK_SIZE * sizeof(*fsync_list[entry]) ); } } - lock_obj_cache(); - fsync_list[entry][idx].type = type; - fsync_list[entry][idx].shm = shm; - unlock_obj_cache(); + cache.type = type; + cache.shm_idx = shm_idx; + __atomic_store_n( (uint64_t *)&fsync_list[entry][idx], *(uint64_t *)&cache, __ATOMIC_SEQ_CST ); } static BOOL get_cached_object( HANDLE handle, struct fsync *obj ) { - BOOL ret = TRUE; UINT_PTR entry, idx = handle_to_index( handle, &entry ); + struct fsync_cache cache; if (entry >= FSYNC_LIST_ENTRIES || !fsync_list[entry]) return FALSE; - lock_obj_cache(); - if (!fsync_list[entry][idx].type) ret = FALSE; - else *obj = fsync_list[entry][idx]; - unlock_obj_cache(); - return ret; +again: + *(uint64_t *)&cache = __atomic_load_n( (uint64_t *)&fsync_list[entry][idx], __ATOMIC_SEQ_CST ); + + if (!cache.type || !cache.shm_idx) return FALSE; + + obj->type = cache.type; + obj->shm = get_shm( cache.shm_idx ); + if (*(uint64_t *)&cache != __atomic_load_n( (uint64_t *)&fsync_list[entry][idx], __ATOMIC_SEQ_CST )) + { + /* This check does not strictly guarantee that we avoid the potential race but is supposed to greatly + * reduce the probability of that. */ + FIXME( "Cache changed while getting object.\n" ); + goto again; + } + return TRUE; } /* Gets an object. This is either a proper fsync object (i.e. an event, @@ -374,7 +371,7 @@ static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) obj->type = type; obj->shm = get_shm( shm_idx ); - add_to_list( handle, type, obj->shm ); + add_to_list( handle, type, shm_idx ); return ret; } @@ -386,17 +383,13 @@ NTSTATUS fsync_close( HANDLE handle ) if (entry < FSYNC_LIST_ENTRIES && fsync_list[entry]) { - enum fsync_type type; + struct fsync_cache cache; - lock_obj_cache(); - if ((type = fsync_list[entry][idx].type)) - { - fsync_list[entry][idx].type = 0; - fsync_list[entry][idx].shm = NULL; - } - unlock_obj_cache(); - if (type) - return STATUS_SUCCESS; + cache.type = 0; + cache.shm_idx = 0; + *(uint64_t *)&cache = __atomic_exchange_n( (uint64_t *)&fsync_list[entry][idx], + *(uint64_t *)&cache, __ATOMIC_SEQ_CST ); + if (cache.type) return STATUS_SUCCESS; } return STATUS_INVALID_HANDLE; @@ -431,7 +424,7 @@ static NTSTATUS create_fsync( enum fsync_type type, HANDLE *handle, if (!ret || ret == STATUS_OBJECT_NAME_EXISTS) { - add_to_list( *handle, type, get_shm( shm_idx )); + add_to_list( *handle, type, shm_idx ); TRACE("-> handle %p, shm index %d.\n", *handle, shm_idx); } @@ -464,7 +457,7 @@ static NTSTATUS open_fsync( enum fsync_type type, HANDLE *handle, if (!ret) { - add_to_list( *handle, type, get_shm( shm_idx ) ); + add_to_list( *handle, type, shm_idx ); TRACE("-> handle %p, shm index %u.\n", *handle, shm_idx); } From 95b0434cacb8df6a61811c5b7063e2e4e03edf62 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 4 Jul 2022 15:11:23 -0500 Subject: [PATCH 0478/2777] fsync: Implement reference counting for sync objects shared memory. CW-Bug-Id: #20826 --- dlls/ntdll/unix/fsync.c | 150 ++++++++++++++++++++++++++++++++++++---- server/fsync.c | 64 ++++++++++++++++- server/fsync.h | 1 + server/process.c | 6 +- server/protocol.def | 5 ++ 5 files changed, 210 insertions(+), 16 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index c7df9c77da1..1b57ae8511f 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -192,22 +192,28 @@ struct semaphore { int count; int max; + int ref; + int last_pid; }; -C_ASSERT(sizeof(struct semaphore) == 8); +C_ASSERT(sizeof(struct semaphore) == 16); struct event { int signaled; int unused; + int ref; + int last_pid; }; -C_ASSERT(sizeof(struct event) == 8); +C_ASSERT(sizeof(struct event) == 16); struct mutex { int tid; int count; /* recursion count */ + int ref; + int last_pid; }; -C_ASSERT(sizeof(struct mutex) == 8); +C_ASSERT(sizeof(struct mutex) == 16); static char shm_name[29]; static int shm_fd; @@ -219,8 +225,8 @@ static pthread_mutex_t shm_addrs_mutex = PTHREAD_MUTEX_INITIALIZER; static void *get_shm( unsigned int idx ) { - int entry = (idx * 8) / pagesize; - int offset = (idx * 8) % pagesize; + int entry = (idx * 16) / pagesize; + int offset = (idx * 16) % pagesize; void *ret; pthread_mutex_lock( &shm_addrs_mutex ); @@ -307,6 +313,59 @@ static void add_to_list( HANDLE handle, enum fsync_type type, unsigned int shm_i __atomic_store_n( (uint64_t *)&fsync_list[entry][idx], *(uint64_t *)&cache, __ATOMIC_SEQ_CST ); } +static void grab_object( struct fsync *obj ) +{ + int *shm = obj->shm; + + __atomic_add_fetch( &shm[2], 1, __ATOMIC_SEQ_CST ); +} + +static unsigned int shm_index_from_shm( char *shm ) +{ + unsigned int count = shm_addrs_size; + unsigned int i, idx_offset; + + for (i = 0; i < count; ++i) + { + if (shm >= (char *)shm_addrs[i] && shm < (char *)shm_addrs[i] + pagesize) + { + idx_offset = (shm - (char *)shm_addrs[i]) / 16; + return i * (pagesize / 16) + idx_offset; + } + } + + ERR( "Index for shm %p not found.\n", shm ); + return ~0u; +} + +static void put_object( struct fsync *obj ) +{ + int *shm = obj->shm; + + if (__atomic_load_n( &shm[2], __ATOMIC_SEQ_CST ) == 1) + { + /* We are holding the last reference, it should be released on server so shm idx get freed. */ + SERVER_START_REQ( fsync_free_shm_idx ) + { + req->shm_idx = shm_index_from_shm( obj->shm ); + wine_server_call( req ); + } + SERVER_END_REQ; + } + else + { + __atomic_sub_fetch( &shm[2], 1, __ATOMIC_SEQ_CST ); + } +} + +static void put_object_from_wait( struct fsync *obj ) +{ + int *shm = obj->shm; + + __sync_val_compare_and_swap( &shm[3], GetCurrentProcessId(), 0 ); + put_object( obj ); +} + static BOOL get_cached_object( HANDLE handle, struct fsync *obj ) { UINT_PTR entry, idx = handle_to_index( handle, &entry ); @@ -321,10 +380,13 @@ static BOOL get_cached_object( HANDLE handle, struct fsync *obj ) obj->type = cache.type; obj->shm = get_shm( cache.shm_idx ); - if (*(uint64_t *)&cache != __atomic_load_n( (uint64_t *)&fsync_list[entry][idx], __ATOMIC_SEQ_CST )) + grab_object( obj ); + if (((int *)obj->shm)[2] < 2 || + *(uint64_t *)&cache != __atomic_load_n( (uint64_t *)&fsync_list[entry][idx], __ATOMIC_SEQ_CST )) { /* This check does not strictly guarantee that we avoid the potential race but is supposed to greatly * reduce the probability of that. */ + put_object( obj ); FIXME( "Cache changed while getting object.\n" ); goto again; } @@ -372,9 +434,24 @@ static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) obj->type = type; obj->shm = get_shm( shm_idx ); add_to_list( handle, type, shm_idx ); + /* get_fsync_idx server request increments shared mem refcount, so not grabbing object here. */ return ret; } +static NTSTATUS get_object_for_wait( HANDLE handle, struct fsync *obj ) +{ + NTSTATUS ret; + int *shm; + + if ((ret = get_object( handle, obj ))) return ret; + + shm = obj->shm; + /* Give wineserver a chance to cleanup shm index if the process + * is killed while we are waiting on the object. */ + __atomic_store_n( &shm[3], GetCurrentProcessId(), __ATOMIC_SEQ_CST ); + return STATUS_SUCCESS; +} + NTSTATUS fsync_close( HANDLE handle ) { UINT_PTR entry, idx = handle_to_index( handle, &entry ); @@ -541,13 +618,17 @@ NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) { current = semaphore->count; if (count + current > semaphore->max) + { + put_object( &obj ); return STATUS_SEMAPHORE_LIMIT_EXCEEDED; + } } while (__sync_val_compare_and_swap( &semaphore->count, current, count + current ) != current); if (prev) *prev = current; futex_wake( &semaphore->count, INT_MAX ); + put_object( &obj ); return STATUS_SUCCESS; } @@ -567,6 +648,7 @@ NTSTATUS fsync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len ) out->MaximumCount = semaphore->max; if (ret_len) *ret_len = sizeof(*out); + put_object( &obj ); return STATUS_SUCCESS; } @@ -603,13 +685,17 @@ NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) event = obj.shm; if (obj.type != FSYNC_MANUAL_EVENT && obj.type != FSYNC_AUTO_EVENT) + { + put_object( &obj ); return STATUS_OBJECT_TYPE_MISMATCH; + } if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))) futex_wake( &event->signaled, INT_MAX ); if (prev) *prev = current; + put_object( &obj ); return STATUS_SUCCESS; } @@ -629,6 +715,7 @@ NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) if (prev) *prev = current; + put_object( &obj ); return STATUS_SUCCESS; } @@ -658,6 +745,7 @@ NTSTATUS fsync_pulse_event( HANDLE handle, LONG *prev ) if (prev) *prev = current; + put_object( &obj ); return STATUS_SUCCESS; } @@ -677,6 +765,7 @@ NTSTATUS fsync_query_event( HANDLE handle, void *info, ULONG *ret_len ) out->EventType = (obj.type == FSYNC_AUTO_EVENT ? SynchronizationEvent : NotificationEvent); if (ret_len) *ret_len = sizeof(*out); + put_object( &obj ); return STATUS_SUCCESS; } @@ -709,7 +798,11 @@ NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) if ((ret = get_object( handle, &obj ))) return ret; mutex = obj.shm; - if (mutex->tid != GetCurrentThreadId()) return STATUS_MUTANT_NOT_OWNED; + if (mutex->tid != GetCurrentThreadId()) + { + put_object( &obj ); + return STATUS_MUTANT_NOT_OWNED; + } if (prev) *prev = mutex->count; @@ -719,6 +812,7 @@ NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) futex_wake( &mutex->tid, INT_MAX ); } + put_object( &obj ); return STATUS_SUCCESS; } @@ -739,6 +833,7 @@ NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) out->AbandonedState = (mutex->tid == ~0); if (ret_len) *ret_len = sizeof(*out); + put_object( &obj ); return STATUS_SUCCESS; } @@ -777,6 +872,14 @@ static NTSTATUS do_single_wait( int *addr, int val, const struct timespec64 *end return STATUS_PENDING; } +static void put_objects( struct fsync *objs, unsigned int count ) +{ + unsigned int i; + + for (i = 0; i < count; ++i) + if (objs[i].type) put_object_from_wait( &objs[i] ); +} + static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) { @@ -815,7 +918,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, for (i = 0; i < count; i++) { - ret = get_object( handles[i], &objs[i] ); + ret = get_object_for_wait( handles[i], &objs[i] ); if (ret == STATUS_SUCCESS) { assert( objs[i].type ); @@ -829,6 +932,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, } else { + put_objects( objs, i ); return ret; } } @@ -839,7 +943,10 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, if (has_fsync && has_server) FIXME("Can't wait on fsync and server objects at the same time!\n"); else if (has_server) + { + put_objects( objs, count ); return STATUS_NOT_IMPLEMENTED; + } if (TRACE_ON(fsync)) { @@ -894,6 +1001,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, { TRACE("Woken up by handle %p [%d].\n", handles[i], i); if (waited) simulate_sched_quantum(); + put_objects( objs, count ); return i; } futex_vector_set( &futexes[i], &semaphore->count, 0 ); @@ -909,6 +1017,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(); + put_objects( objs, count ); return i; } @@ -917,12 +1026,14 @@ 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(); + put_objects( objs, count ); return i; } else if (tid == ~0 && (tid = __sync_val_compare_and_swap( &mutex->tid, ~0, GetCurrentThreadId() )) == ~0) { TRACE("Woken up by abandoned mutex %p [%d].\n", handles[i], i); mutex->count = 1; + put_objects( objs, count ); return STATUS_ABANDONED_WAIT_0 + i; } @@ -941,6 +1052,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, TRACE("Woken up by handle %p [%d].\n", handles[i], i); if (waited) simulate_sched_quantum(); + put_objects( objs, count ); return i; } futex_vector_set( &futexes[i], &event->signaled, 0 ); @@ -959,6 +1071,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, TRACE("Woken up by handle %p [%d].\n", handles[i], i); if (waited) simulate_sched_quantum(); + put_objects( objs, count ); return i; } futex_vector_set( &futexes[i], &event->signaled, 0 ); @@ -993,6 +1106,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, /* Unlike esync, we already know that we've timed out, so we * can avoid a syscall. */ TRACE("Wait timed out.\n"); + put_objects( objs, count ); return STATUS_TIMEOUT; } @@ -1005,6 +1119,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, if (ret == -1 && errno == ETIMEDOUT) { TRACE("Wait timed out.\n"); + put_objects( objs, count ); return STATUS_TIMEOUT; } else waited = TRUE; @@ -1079,6 +1194,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, if (status == STATUS_TIMEOUT) { TRACE("Wait timed out.\n"); + put_objects( objs, count ); return status; } else if (status == STATUS_USER_APC) @@ -1168,9 +1284,11 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, if (abandoned) { TRACE("Wait successful, but some object(s) were abandoned.\n"); + put_objects( objs, count ); return STATUS_ABANDONED; } TRACE("Wait successful.\n"); + put_objects( objs, count ); return STATUS_SUCCESS; tooslow: @@ -1215,6 +1333,8 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, userapc: TRACE("Woken up by user APC.\n"); + put_objects( objs, count ); + /* We have to make a server call anyway to get the APC to execute, so just * delegate down to server_wait(). */ ret = server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, &zero ); @@ -1254,10 +1374,14 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an struct fsync obj; NTSTATUS ret; - if (count && !get_object( handles[count - 1], &obj ) && obj.type == FSYNC_QUEUE) + if (count && !get_object( handles[count - 1], &obj )) { - msgwait = TRUE; - server_set_msgwait( 1 ); + if (obj.type == FSYNC_QUEUE) + { + msgwait = TRUE; + server_set_msgwait( 1 ); + } + put_object( &obj ); } ret = __fsync_wait_objects( count, handles, wait_any, alertable, timeout ); @@ -1289,8 +1413,10 @@ NTSTATUS fsync_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable, ret = fsync_release_mutex( signal, NULL ); break; default: - return STATUS_OBJECT_TYPE_MISMATCH; + ret = STATUS_OBJECT_TYPE_MISMATCH; + break; } + put_object( &obj ); if (ret) return ret; return fsync_wait_objects( 1, &wait, TRUE, alertable, timeout ); diff --git a/server/fsync.c b/server/fsync.c index 3c1e709d7e3..0e3862389da 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -205,8 +205,8 @@ static void fsync_destroy( struct object *obj ) static void *get_shm( unsigned int idx ) { - int entry = (idx * 8) / pagesize; - int offset = (idx * 8) % pagesize; + int entry = (idx * 16) / pagesize; + int offset = (idx * 16) % pagesize; if (entry >= shm_addrs_size) { @@ -287,7 +287,7 @@ unsigned int fsync_alloc_shm( int low, int high ) shm_idx = alloc_shm_idx_from_word( old_size ); } - while (shm_idx * 8 >= shm_size) + while (shm_idx * 16 >= shm_size) { /* Better expand the shm section. */ shm_size += pagesize; @@ -303,6 +303,8 @@ unsigned int fsync_alloc_shm( int low, int high ) assert(shm); shm[0] = low; shm[1] = high; + shm[2] = 1; /* Reference count. */ + shm[3] = 0; /* Last reference process id. */ return shm_idx; #else @@ -314,9 +316,24 @@ void fsync_free_shm_idx( int shm_idx ) { unsigned int idx; uint64_t mask; + int *shm; assert( shm_idx ); assert( shm_idx < shm_idx_free_map_size * BITS_IN_FREE_MAP_WORD ); + + shm = get_shm( shm_idx ); + if (shm[2] <= 0) + { + fprintf( stderr, "wineserver: fsync err: shm refcount is %d.\n", shm[2] ); + return; + } + + if (__atomic_sub_fetch( &shm[2], 1, __ATOMIC_SEQ_CST )) + { + /* Sync object is still referenced in a process. */ + return; + } + idx = shm_idx / BITS_IN_FREE_MAP_WORD; mask = (uint64_t)1 << (shm_idx % BITS_IN_FREE_MAP_WORD); assert( !(shm_idx_free_map[idx] & mask) ); @@ -325,6 +342,31 @@ void fsync_free_shm_idx( int shm_idx ) shm_idx_free_search_start_hint = idx; } +/* Try to cleanup the shared mem indices locked by the wait on the killed processes. + * This is not fully reliable but should avoid leaking the majority of indices on + * process kill. */ +void fsync_cleanup_process_shm_indices( process_id_t id ) +{ + uint64_t free_word; + unsigned int i, j; + void *shmbase; + int *shm; + + for (i = 0; i < shm_idx_free_map_size; ++i) + { + free_word = shm_idx_free_map[i]; + if (free_word == ~(uint64_t)0) continue; + shmbase = get_shm( i * BITS_IN_FREE_MAP_WORD ); + for (j = !i; j < BITS_IN_FREE_MAP_WORD; ++j) + { + shm = (int *)((char *)shmbase + j * 16); + if (!(free_word & ((uint64_t)1 << j)) && shm[3] == id + && __atomic_load_n( &shm[2], __ATOMIC_SEQ_CST ) == 1) + fsync_free_shm_idx( i * BITS_IN_FREE_MAP_WORD + j ); + } + } +} + static int type_matches( enum fsync_type type1, enum fsync_type type2 ) { return (type1 == type2) || @@ -384,6 +426,8 @@ struct fsync_event { int signaled; int unused; + int ref; + int last_pid; }; void fsync_wake_futex( unsigned int shm_idx ) @@ -551,8 +595,12 @@ DECL_HANDLER(get_fsync_idx) if (obj->ops->get_fsync_idx) { + int *shm; + reply->shm_idx = obj->ops->get_fsync_idx( obj, &type ); reply->type = type; + shm = get_shm( reply->shm_idx ); + __atomic_add_fetch( &shm[2], 1, __ATOMIC_SEQ_CST ); } else { @@ -571,3 +619,13 @@ DECL_HANDLER(get_fsync_apc_idx) { reply->shm_idx = current->fsync_apc_idx; } + +DECL_HANDLER(fsync_free_shm_idx) +{ + if (!req->shm_idx || req->shm_idx >= shm_idx_free_map_size * BITS_IN_FREE_MAP_WORD) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + fsync_free_shm_idx( req->shm_idx ); +} diff --git a/server/fsync.h b/server/fsync.h index ee1a729e77e..d4bd889a7f8 100644 --- a/server/fsync.h +++ b/server/fsync.h @@ -33,3 +33,4 @@ extern const struct object_ops fsync_ops; extern void fsync_set_event( struct fsync *fsync ); extern void fsync_reset_event( struct fsync *fsync ); extern void fsync_abandon_mutexes( struct thread *thread ); +extern void fsync_cleanup_process_shm_indices( process_id_t id ); diff --git a/server/process.c b/server/process.c index 0b6121ec389..32486b155a4 100644 --- a/server/process.c +++ b/server/process.c @@ -805,7 +805,11 @@ static void process_destroy( struct object *obj ) free( process->dir_cache ); free( process->image ); if (do_esync()) close( process->esync_fd ); - if (process->fsync_idx) fsync_free_shm_idx( process->fsync_idx ); + if (process->fsync_idx) + { + fsync_cleanup_process_shm_indices( process->id ); + fsync_free_shm_idx( process->fsync_idx ); + } } /* dump a process on stdout for debugging purposes */ diff --git a/server/protocol.def b/server/protocol.def index a7cd4b8c7d4..845dffdf495 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3947,3 +3947,8 @@ enum fsync_type @REPLY unsigned int shm_idx; @END + +@REQ(fsync_free_shm_idx) + unsigned int shm_idx; +@REPLY +@END From 19a33384214b6b020a11047ad8d515a5c3838375 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 1 Aug 2022 10:53:28 -0500 Subject: [PATCH 0479/2777] fsync: Increase shm page size. CW-Bug-Id: #21050 --- dlls/ntdll/unix/fsync.c | 19 +++++++++---------- server/fsync.c | 19 +++++++++---------- server/protocol.def | 2 ++ 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 1b57ae8511f..8c294d9f45d 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -219,14 +219,13 @@ static char shm_name[29]; static int shm_fd; static void **shm_addrs; static int shm_addrs_size; /* length of the allocated shm_addrs array */ -static long pagesize; static pthread_mutex_t shm_addrs_mutex = PTHREAD_MUTEX_INITIALIZER; static void *get_shm( unsigned int idx ) { - int entry = (idx * 16) / pagesize; - int offset = (idx * 16) % pagesize; + int entry = (idx * 16) / FSYNC_SHM_PAGE_SIZE; + int offset = (idx * 16) % FSYNC_SHM_PAGE_SIZE; void *ret; pthread_mutex_lock( &shm_addrs_mutex ); @@ -243,14 +242,16 @@ static void *get_shm( unsigned int idx ) if (!shm_addrs[entry]) { - void *addr = mmap( NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, entry * pagesize ); + void *addr = mmap( NULL, FSYNC_SHM_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, + (off_t)entry * FSYNC_SHM_PAGE_SIZE ); if (addr == (void *)-1) - ERR("Failed to map page %d (offset %#lx).\n", entry, entry * pagesize); + ERR("Failed to map page %d (offset %s).\n", entry, + wine_dbgstr_longlong((off_t)entry * FSYNC_SHM_PAGE_SIZE)); TRACE("Mapping page %d at %p.\n", entry, addr); if (__sync_val_compare_and_swap( &shm_addrs[entry], 0, addr )) - munmap( addr, pagesize ); /* someone beat us to it */ + munmap( addr, FSYNC_SHM_PAGE_SIZE ); /* someone beat us to it */ } ret = (void *)((unsigned long)shm_addrs[entry] + offset); @@ -327,10 +328,10 @@ static unsigned int shm_index_from_shm( char *shm ) for (i = 0; i < count; ++i) { - if (shm >= (char *)shm_addrs[i] && shm < (char *)shm_addrs[i] + pagesize) + if (shm >= (char *)shm_addrs[i] && shm < (char *)shm_addrs[i] + FSYNC_SHM_PAGE_SIZE) { idx_offset = (shm - (char *)shm_addrs[i]) / 16; - return i * (pagesize / 16) + idx_offset; + return i * (FSYNC_SHM_PAGE_SIZE / 16) + idx_offset; } } @@ -579,8 +580,6 @@ void fsync_init(void) exit(1); } - pagesize = sysconf( _SC_PAGESIZE ); - shm_addrs = calloc( 128, sizeof(shm_addrs[0]) ); shm_addrs_size = 128; } diff --git a/server/fsync.c b/server/fsync.c index 0e3862389da..dc50aa0a1f3 100644 --- a/server/fsync.c +++ b/server/fsync.c @@ -73,7 +73,6 @@ static int shm_fd; static off_t shm_size; static void **shm_addrs; static int shm_addrs_size; /* length of the allocated shm_addrs array */ -static long pagesize; static int is_fsync_initialized; @@ -109,12 +108,10 @@ void fsync_init(void) if (shm_fd == -1) perror( "shm_open" ); - pagesize = sysconf( _SC_PAGESIZE ); - shm_addrs = calloc( 128, sizeof(shm_addrs[0]) ); shm_addrs_size = 128; - shm_size = pagesize; + shm_size = FSYNC_SHM_PAGE_SIZE; if (ftruncate( shm_fd, shm_size ) == -1) perror( "ftruncate" ); @@ -205,8 +202,8 @@ static void fsync_destroy( struct object *obj ) static void *get_shm( unsigned int idx ) { - int entry = (idx * 16) / pagesize; - int offset = (idx * 16) % pagesize; + int entry = (idx * 16) / FSYNC_SHM_PAGE_SIZE; + int offset = (idx * 16) % FSYNC_SHM_PAGE_SIZE; if (entry >= shm_addrs_size) { @@ -222,10 +219,12 @@ static void *get_shm( unsigned int idx ) if (!shm_addrs[entry]) { - void *addr = mmap( NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, entry * pagesize ); + void *addr = mmap( NULL, FSYNC_SHM_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, + (off_t)entry * FSYNC_SHM_PAGE_SIZE ); if (addr == (void *)-1) { - fprintf( stderr, "fsync: failed to map page %d (offset %#lx): ", entry, entry * pagesize ); + fprintf( stderr, "fsync: failed to map page %d (offset %#zx): ", + entry, (size_t)entry * FSYNC_SHM_PAGE_SIZE ); perror( "mmap" ); } @@ -233,7 +232,7 @@ static void *get_shm( unsigned int idx ) fprintf( stderr, "fsync: Mapping page %d at %p.\n", entry, addr ); if (__sync_val_compare_and_swap( &shm_addrs[entry], 0, addr )) - munmap( addr, pagesize ); /* someone beat us to it */ + munmap( addr, FSYNC_SHM_PAGE_SIZE ); /* someone beat us to it */ } return (void *)((unsigned long)shm_addrs[entry] + offset); @@ -290,7 +289,7 @@ unsigned int fsync_alloc_shm( int low, int high ) while (shm_idx * 16 >= shm_size) { /* Better expand the shm section. */ - shm_size += pagesize; + shm_size += FSYNC_SHM_PAGE_SIZE; if (ftruncate( shm_fd, shm_size ) == -1) { fprintf( stderr, "fsync: couldn't expand %s to size %jd: ", diff --git a/server/protocol.def b/server/protocol.def index 845dffdf495..f744c274544 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3894,6 +3894,8 @@ enum esync_type @REQ(get_esync_apc_fd) @END +#define FSYNC_SHM_PAGE_SIZE 0x10000 + enum fsync_type { FSYNC_SEMAPHORE = 1, From 79db61e013a1e294a09f923bd1a7c53179da0d3f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 1 Aug 2022 11:01:51 -0500 Subject: [PATCH 0480/2777] fsync: Use static shm_addrs array and get rid of locking in get_shm(). CW-Bug-Id: #21050 --- dlls/ntdll/unix/fsync.c | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 8c294d9f45d..fab1be35adc 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -217,27 +217,18 @@ C_ASSERT(sizeof(struct mutex) == 16); static char shm_name[29]; static int shm_fd; -static void **shm_addrs; -static int shm_addrs_size; /* length of the allocated shm_addrs array */ - -static pthread_mutex_t shm_addrs_mutex = PTHREAD_MUTEX_INITIALIZER; +static volatile void *shm_addrs[8192]; static void *get_shm( unsigned int idx ) { int entry = (idx * 16) / FSYNC_SHM_PAGE_SIZE; int offset = (idx * 16) % FSYNC_SHM_PAGE_SIZE; - void *ret; - - pthread_mutex_lock( &shm_addrs_mutex ); - if (entry >= shm_addrs_size) + if (entry >= ARRAY_SIZE(shm_addrs)) { - int new_size = max(shm_addrs_size * 2, entry + 1); - - if (!(shm_addrs = realloc( shm_addrs, new_size * sizeof(shm_addrs[0]) ))) - ERR("Failed to grow shm_addrs array to size %d.\n", shm_addrs_size); - memset( shm_addrs + shm_addrs_size, 0, (new_size - shm_addrs_size) * sizeof(shm_addrs[0]) ); - shm_addrs_size = new_size; + ERR( "idx %u exceeds maximum of %u.\n", idx, + (unsigned int)ARRAY_SIZE(shm_addrs) * (FSYNC_SHM_PAGE_SIZE / 16) ); + return NULL; } if (!shm_addrs[entry]) @@ -254,11 +245,7 @@ static void *get_shm( unsigned int idx ) munmap( addr, FSYNC_SHM_PAGE_SIZE ); /* someone beat us to it */ } - ret = (void *)((unsigned long)shm_addrs[entry] + offset); - - pthread_mutex_unlock( &shm_addrs_mutex ); - - return ret; + return (char *)shm_addrs[entry] + offset; } /* We'd like lookup to be fast. To that end, we use a static list indexed by handle. @@ -323,10 +310,9 @@ static void grab_object( struct fsync *obj ) static unsigned int shm_index_from_shm( char *shm ) { - unsigned int count = shm_addrs_size; unsigned int i, idx_offset; - for (i = 0; i < count; ++i) + for (i = 0; i < ARRAY_SIZE(shm_addrs); ++i) { if (shm >= (char *)shm_addrs[i] && shm < (char *)shm_addrs[i] + FSYNC_SHM_PAGE_SIZE) { @@ -579,9 +565,6 @@ void fsync_init(void) ERR("Failed to initialize shared memory: %s\n", strerror( errno )); exit(1); } - - shm_addrs = calloc( 128, sizeof(shm_addrs[0]) ); - shm_addrs_size = 128; } NTSTATUS fsync_create_semaphore( HANDLE *handle, ACCESS_MASK access, From 22d64ab56594e80df25545c2245abdd117162647 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 16 Aug 2022 12:34:09 -0500 Subject: [PATCH 0481/2777] esync, fsync: Support waiting on file handles. CW-Bug-Id: #21132 --- server/file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/file.c b/server/file.c index 5be9578ce48..500ffcac153 100644 --- a/server/file.c +++ b/server/file.c @@ -94,8 +94,8 @@ static const struct object_ops file_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ - NULL, /* get_esync_fd */ - NULL, /* get_fsync_idx */ + default_fd_get_esync_fd, /* get_esync_fd */ + default_fd_get_fsync_idx, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ file_get_fd, /* get_fd */ From 01f91fe78ad2ae25edca62c4a431e6a3064fa37e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 13 Jul 2020 10:21:49 -0500 Subject: [PATCH 0482/2777] ntdll: Handle NULL object name buffer in nt_to_unix_file_name_attr(). CW-Bug-Id: #17864 --- dlls/ntdll/tests/file.c | 22 +++++++++++++++++++++- dlls/ntdll/unix/file.c | 5 ++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 477be256596..6433e8548c1 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -145,16 +145,36 @@ static void create_file_test(void) static const WCHAR pathInvalidDosW[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\',0}; static const char testdata[] = "Hello World"; FILE_NETWORK_OPEN_INFORMATION info; + UNICODE_STRING nameW, null_string; NTSTATUS status; HANDLE dir, file; WCHAR path[MAX_PATH]; OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK io; - UNICODE_STRING nameW; LARGE_INTEGER offset; char buf[32]; DWORD ret; + attr.Length = sizeof(attr); + attr.RootDirectory = NULL; + attr.ObjectName = &null_string; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + null_string.Buffer = NULL; + null_string.Length = 256; + + /* try various open modes and options on directories */ + status = pNtCreateFile( &dir, GENERIC_READ|GENERIC_WRITE, &attr, &io, NULL, 0, + FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE, NULL, 0 ); + ok( status == STATUS_ACCESS_VIOLATION, "Got unexpected status %#x.\n", status ); + + null_string.Length = 0; + status = pNtCreateFile( &dir, GENERIC_READ|GENERIC_WRITE, &attr, &io, NULL, 0, + FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, FILE_DIRECTORY_FILE, NULL, 0 ); + ok( status == STATUS_OBJECT_PATH_SYNTAX_BAD, "Got unexpected status %#x.\n", status ); + GetCurrentDirectoryW( MAX_PATH, path ); pRtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL ); attr.Length = sizeof(attr); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 5fbc40cb0bb..5f617418a4c 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -3476,7 +3476,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char name = nameW->Buffer; name_len = nameW->Length / sizeof(WCHAR); - if (!name_len || name[0] != '\\') return STATUS_OBJECT_PATH_SYNTAX_BAD; + if (!name || !name_len || name[0] != '\\') return STATUS_OBJECT_PATH_SYNTAX_BAD; if (!(pos = get_dos_prefix_len( nameW ))) return STATUS_BAD_DEVICE_TYPE; /* no DOS prefix, assume NT native name */ @@ -3587,6 +3587,9 @@ NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, U int name_len, unix_len; NTSTATUS status; + if (!attr->ObjectName->Buffer && attr->ObjectName->Length) + return STATUS_ACCESS_VIOLATION; + if (!attr->RootDirectory) /* without root dir fall back to normal lookup */ return nt_to_unix_file_name_no_root( attr->ObjectName, name_ret, disposition ); From 8d768eff35f6c6f20cd543a6a26c87569fc3abaf Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 26 Jun 2020 15:26:53 +0300 Subject: [PATCH 0483/2777] Avoid undefined result in ntdll_wcstoumbs() in case of error. CW-Bug-Id: #17864 Undefined result is due to RtlUnicodeToUTF8N() not setting output length on error which is a correct behaviour according to existing tests. 'Planet Zoo' is affected which passes NULL object name buffer to NtCreateFile(). Signed-off-by: Paul Gofman --- dlls/ntdll/unix/env.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c index 145b99aafdc..931da192916 100644 --- a/dlls/ntdll/unix/env.c +++ b/dlls/ntdll/unix/env.c @@ -399,7 +399,7 @@ DWORD ntdll_umbstowcs( const char *src, DWORD srclen, WCHAR *dst, DWORD dstlen ) */ int ntdll_wcstoumbs( const WCHAR *src, DWORD srclen, char *dst, DWORD dstlen, BOOL strict ) { - unsigned int i, reslen; + unsigned int i, reslen = 0; if (unix_cp.CodePage != CP_UTF8) { From 6028ac34560f5d2a8f7e36ed519cfcfe64a39896 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Sat, 22 May 2021 01:23:33 +0300 Subject: [PATCH 0484/2777] server: Update system regs from set_thread_context handler only. CW-Bug-Id: #18957 --- server/thread.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/server/thread.c b/server/thread.c index b95b4097ef3..2c9a18be1f3 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1936,8 +1936,6 @@ DECL_HANDLER(select) if (ctx->regs[CTX_NATIVE].flags || ctx->regs[CTX_WOW].flags) { data_size_t size = (ctx->regs[CTX_WOW].flags ? 2 : 1) * sizeof(context_t); - unsigned int flags = system_flags & ctx->regs[CTX_NATIVE].flags; - if (flags) set_thread_context( current, &ctx->regs[CTX_NATIVE], flags ); set_reply_data( ctx->regs, min( size, get_reply_max_size() )); } release_object( ctx ); @@ -2177,7 +2175,7 @@ DECL_HANDLER(set_thread_context) unsigned int native_flags = always_native_flags & context->flags; if (thread != current) stop_thread( thread ); - else if (flags) set_thread_context( thread, context, flags ); + if (system_flags) set_thread_context( thread, context, system_flags ); if (thread->context && !get_error()) { if (ctx_count == 2) From 1b6452bdec0379c1931db71b1d56673c23bc3dbf Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 24 May 2021 14:37:35 +0300 Subject: [PATCH 0485/2777] ntdll: Update cached debug registers in call_init_thunk(). CW-Bug-Id: #18957 --- dlls/ntdll/unix/signal_i386.c | 14 +++++++++++++- dlls/ntdll/unix/signal_x86_64.c | 14 +++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index aa0f10d5bfa..6290d2002b4 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -2456,7 +2456,19 @@ void DECLSPEC_HIDDEN call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, B ((XSAVE_FORMAT *)context.ExtendedRegisters)->MxCsr = 0x1f80; if ((ctx = get_cpu_area( IMAGE_FILE_MACHINE_I386 ))) *ctx = context; - if (suspend) wait_suspend( &context ); + if (suspend) + { + wait_suspend( &context ); + if (context.ContextFlags & CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386) + { + x86_thread_data()->dr0 = context.Dr0; + x86_thread_data()->dr1 = context.Dr1; + x86_thread_data()->dr2 = context.Dr2; + x86_thread_data()->dr3 = context.Dr3; + x86_thread_data()->dr6 = context.Dr6; + x86_thread_data()->dr7 = context.Dr7; + } + } ctx = (CONTEXT *)((ULONG_PTR)context.Esp & ~3) - 1; *ctx = context; diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index c8f729fc8bd..2aa22992b5e 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2745,7 +2745,19 @@ void DECLSPEC_HIDDEN call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, B *(XSAVE_FORMAT *)wow_context->ExtendedRegisters = context.u.FltSave; } - if (suspend) wait_suspend( &context ); + if (suspend) + { + wait_suspend( &context ); + if (context.ContextFlags & CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64) + { + amd64_thread_data()->dr0 = context.Dr0; + amd64_thread_data()->dr1 = context.Dr1; + amd64_thread_data()->dr2 = context.Dr2; + amd64_thread_data()->dr3 = context.Dr3; + amd64_thread_data()->dr6 = context.Dr6; + amd64_thread_data()->dr7 = context.Dr7; + } + } ctx = (CONTEXT *)((ULONG_PTR)context.Rsp & ~15) - 1; *ctx = context; From bf7b84224cf1095c03aa1ab33dea12ffc3e4921b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Sat, 22 May 2021 03:08:55 +0300 Subject: [PATCH 0486/2777] ntdll: Use cached debug registers in NtGetContextThread() if hw debug breakpoints are disabled. CW-Bug-Id: #18957 --- dlls/ntdll/unix/signal_i386.c | 37 ++++++++++++++++++++++++--------- dlls/ntdll/unix/signal_x86_64.c | 37 ++++++++++++++++++++++++--------- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 6290d2002b4..3b1d5b13dd1 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1004,10 +1004,15 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) struct syscall_frame *frame = x86_thread_data()->syscall_frame; DWORD needed_flags = context->ContextFlags & ~CONTEXT_i386; BOOL self = (handle == GetCurrentThread()); + BOOL use_cached_debug_regs = FALSE; NTSTATUS ret; - /* debug registers require a server call */ - if (needed_flags & CONTEXT_DEBUG_REGISTERS) self = FALSE; + if (self && needed_flags & CONTEXT_DEBUG_REGISTERS) + { + /* debug registers require a server call if hw breakpoints are enabled */ + if (x86_thread_data()->dr7 & 0xff) self = FALSE; + else use_cached_debug_regs = TRUE; + } if (!self) { @@ -1115,15 +1120,27 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) xstate->YmmContext = frame->xstate.YmmContext; } } - /* update the cached version of the debug registers */ - if (needed_flags & CONTEXT_DEBUG_REGISTERS) + if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)) { - x86_thread_data()->dr0 = context->Dr0; - x86_thread_data()->dr1 = context->Dr1; - x86_thread_data()->dr2 = context->Dr2; - x86_thread_data()->dr3 = context->Dr3; - x86_thread_data()->dr6 = context->Dr6; - x86_thread_data()->dr7 = context->Dr7; + if (use_cached_debug_regs) + { + context->Dr0 = x86_thread_data()->dr0; + context->Dr1 = x86_thread_data()->dr1; + context->Dr2 = x86_thread_data()->dr2; + context->Dr3 = x86_thread_data()->dr3; + context->Dr6 = x86_thread_data()->dr6; + context->Dr7 = x86_thread_data()->dr7; + } + else + { + /* update the cached version of the debug registers */ + x86_thread_data()->dr0 = context->Dr0; + x86_thread_data()->dr1 = context->Dr1; + x86_thread_data()->dr2 = context->Dr2; + x86_thread_data()->dr3 = context->Dr3; + x86_thread_data()->dr6 = context->Dr6; + x86_thread_data()->dr7 = context->Dr7; + } } } diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 2aa22992b5e..b1425066db4 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1088,10 +1088,15 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) { struct syscall_frame *frame = amd64_thread_data()->syscall_frame; DWORD needed_flags = context->ContextFlags & ~CONTEXT_AMD64; + BOOL use_cached_debug_regs = FALSE; BOOL self = (handle == GetCurrentThread()); - /* debug registers require a server call */ - if (needed_flags & CONTEXT_DEBUG_REGISTERS) self = FALSE; + if (self && needed_flags & CONTEXT_DEBUG_REGISTERS) + { + /* debug registers require a server call if hw breakpoints are enabled */ + if (amd64_thread_data()->dr7 & 0xff) self = FALSE; + else use_cached_debug_regs = TRUE; + } if (!self) { @@ -1190,15 +1195,27 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) memcpy( &xstate->YmmContext, &frame->xstate.YmmContext, sizeof(xstate->YmmContext) ); } } - /* update the cached version of the debug registers */ - if (needed_flags & CONTEXT_DEBUG_REGISTERS) + if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64)) { - amd64_thread_data()->dr0 = context->Dr0; - amd64_thread_data()->dr1 = context->Dr1; - amd64_thread_data()->dr2 = context->Dr2; - amd64_thread_data()->dr3 = context->Dr3; - amd64_thread_data()->dr6 = context->Dr6; - amd64_thread_data()->dr7 = context->Dr7; + if (use_cached_debug_regs) + { + context->Dr0 = amd64_thread_data()->dr0; + context->Dr1 = amd64_thread_data()->dr1; + context->Dr2 = amd64_thread_data()->dr2; + context->Dr3 = amd64_thread_data()->dr3; + context->Dr6 = amd64_thread_data()->dr6; + context->Dr7 = amd64_thread_data()->dr7; + } + else + { + /* update the cached version of the debug registers */ + amd64_thread_data()->dr0 = context->Dr0; + amd64_thread_data()->dr1 = context->Dr1; + amd64_thread_data()->dr2 = context->Dr2; + amd64_thread_data()->dr3 = context->Dr3; + amd64_thread_data()->dr6 = context->Dr6; + amd64_thread_data()->dr7 = context->Dr7; + } } return STATUS_SUCCESS; } From 506a5ca8b268e1108fa19d86ce2893f1acbb3e1b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 21 May 2021 15:10:07 +0300 Subject: [PATCH 0487/2777] ntdll: Read process memory on the client side in NtReadVirtualMemory(). CW-Bug-Id: 18957 --- dlls/ntdll/unix/server.c | 2 +- dlls/ntdll/unix/virtual.c | 46 +++++++++++++++++++++++++++++++++++++++ server/process.c | 2 ++ server/protocol.def | 1 + 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 4ed6d8496b0..a11e61a416a 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -1511,7 +1511,7 @@ size_t server_init_process(void) (version > SERVER_PROTOCOL_VERSION) ? "wine" : "wineserver" ); #if defined(__linux__) && defined(HAVE_PRCTL) /* work around Ubuntu's ptrace breakage */ - if (server_pid != -1) prctl( 0x59616d61 /* PR_SET_PTRACER */, server_pid ); + if (server_pid != -1) prctl( 0x59616d61 /* PR_SET_PTRACER */, PR_SET_PTRACER_ANY ); #endif /* ignore SIGPIPE so that we get an EPIPE error instead */ diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index d1bcd405b66..b3a845379f0 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -64,6 +64,8 @@ # include #endif +#include + #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" @@ -5013,7 +5015,50 @@ NTSTATUS WINAPI NtReadVirtualMemory( HANDLE process, const void *addr, void *buf SIZE_T size, SIZE_T *bytes_read ) { unsigned int status; +#ifdef linux + struct iovec local, remote; + int unix_pid; + ssize_t ret; + + SERVER_START_REQ( read_process_memory ) + { + req->handle = wine_server_obj_handle( process ); + status = wine_server_call( req ); + unix_pid = reply->unix_pid; + } + SERVER_END_REQ; + + if (status) + { + WARN( "Could not get unix_pid for process %p, status %#x.\n", process, status ); + size = 0; + goto done; + } + + local.iov_base = buffer; + local.iov_len = size; + remote.iov_base = (void *)addr; + remote.iov_len = size; + + if ((ret = process_vm_readv( unix_pid, &local, 1, &remote, 1, 0 )) != size) + { + WARN( "Error reading memory from process %p, addr %p, size %p, buffer %p, ret %p, errno %d.\n", + process, addr, (void *)size, buffer, (void *)ret, errno ); + + if (ret == -1) + { + status = errno == ESRCH ? STATUS_PARTIAL_COPY : errno_to_status( errno ); + size = 0; + } + else + { + status = STATUS_PARTIAL_COPY; + size = ret; + } + } +done: +#else if (virtual_check_buffer_for_write( buffer, size )) { SERVER_START_REQ( read_process_memory ) @@ -5030,6 +5075,7 @@ NTSTATUS WINAPI NtReadVirtualMemory( HANDLE process, const void *addr, void *buf status = STATUS_ACCESS_VIOLATION; size = 0; } +#endif if (bytes_read) *bytes_read = size; return status; } diff --git a/server/process.c b/server/process.c index 32486b155a4..a12f16a4337 100644 --- a/server/process.c +++ b/server/process.c @@ -1693,6 +1693,8 @@ DECL_HANDLER(read_process_memory) if (!(process = get_process_from_handle( req->handle, PROCESS_VM_READ ))) return; + reply->unix_pid = process->unix_pid; + if (len) { char *buffer = mem_alloc( len ); diff --git a/server/protocol.def b/server/protocol.def index f744c274544..e08351b2133 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1784,6 +1784,7 @@ struct process_info obj_handle_t handle; /* process handle */ client_ptr_t addr; /* addr to read from */ @REPLY + int unix_pid; /* Unix pid of new process */ VARARG(data,bytes); /* result data */ @END From 902da2e98df30b42a0b9610747f3d446a6d10da1 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 8 May 2020 14:32:09 +0300 Subject: [PATCH 0488/2777] ntdll: Use kernel soft dirty flags for write watches support. Requires kernel patches to have effect. --- dlls/kernel32/tests/virtual.c | 54 ++++++++++++- dlls/ntdll/unix/virtual.c | 141 +++++++++++++++++++++++++++++++--- 2 files changed, 180 insertions(+), 15 deletions(-) diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c index c54fb16ba15..445f519f409 100644 --- a/dlls/kernel32/tests/virtual.c +++ b/dlls/kernel32/tests/virtual.c @@ -2127,15 +2127,61 @@ static void test_write_watch(void) ok( count == 1, "wrong count %Iu\n", count ); ok( results[0] == base + 5*pagesize, "wrong result %p\n", results[0] ); + ret = pResetWriteWatch( base, size ); + ok( !ret, "pResetWriteWatch failed %u\n", GetLastError() ); + + ret = VirtualProtect( base, 6*pagesize, PAGE_READWRITE, &old_prot ); + ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + ok( old_prot == PAGE_NOACCESS, "wrong old prot %x\n", old_prot ); + + base[3*pagesize + 200] = 3; + base[5*pagesize + 200] = 3; + ret = VirtualFree( base, size, MEM_DECOMMIT ); ok( ret, "VirtualFree failed %lu\n", GetLastError() ); count = 64; ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %lu\n", GetLastError() ); - ok( count == 1 || broken(count == 0), /* win98 */ - "wrong count %Iu\n", count ); - if (count) ok( results[0] == base + 5*pagesize, "wrong result %p\n", results[0] ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( !count, "wrong count %lu\n", count ); + + base = VirtualAlloc( base, size, MEM_COMMIT, PAGE_READWRITE ); + ok(!!base, "VirtualAlloc failed.\n"); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( !count, "wrong count %lu\n", count ); + + base[3*pagesize + 200] = 3; + ret = VirtualProtect( base, 6*pagesize, PAGE_READWRITE, &old_prot ); + ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); + ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot ); + + base[5*pagesize + 200] = 3; + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + ok( count == 2, "wrong count %lu\n", count ); + ok( results[0] == base + 3*pagesize && results[1] == base + 5*pagesize, "wrong result %p\n", results[0] ); + + ret = VirtualFree( base, size, MEM_DECOMMIT ); + ok( ret, "VirtualFree failed %u\n", GetLastError() ); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + todo_wine ok( count == 1, "wrong count %lu\n", count ); + ok( results[0] == base + 3*pagesize, "wrong result %p\n", results[0] ); + + base = VirtualAlloc( base, size, MEM_COMMIT, PAGE_READWRITE ); + ok(!!base, "VirtualAlloc failed.\n"); + + count = 64; + ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); + ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); + todo_wine ok( count == 1, "wrong count %lu\n", count ); + ok( results[0] == base + 3*pagesize, "wrong result %p\n", results[0] ); VirtualFree( base, 0, MEM_RELEASE ); } diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index b3a845379f0..236b4ccb4d1 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -202,6 +202,13 @@ static BYTE **pages_vprot; static BYTE *pages_vprot; #endif +static BOOL use_kernel_writewatch; +static int pagemap_fd, pagemap_reset_fd, clear_refs_fd; +#define PAGE_FLAGS_BUFFER_LENGTH 1024 +#define PM_SOFT_DIRTY_PAGE (1ull << 57) + +static void reset_write_watches( void *base, SIZE_T size ); + static struct file_view *view_block_start, *view_block_end, *next_free_view; static const size_t view_block_size = 0x100000; static void *preload_reserve_start; @@ -1065,7 +1072,7 @@ static int get_unix_prot( BYTE vprot ) if (vprot & VPROT_WRITE) prot |= PROT_WRITE | PROT_READ; if (vprot & VPROT_WRITECOPY) prot |= PROT_WRITE | PROT_READ; if (vprot & VPROT_EXEC) prot |= PROT_EXEC | PROT_READ; - if (vprot & VPROT_WRITEWATCH) prot &= ~PROT_WRITE; + if (vprot & VPROT_WRITEWATCH && !use_kernel_writewatch) prot &= ~PROT_WRITE; } if (!prot) prot = PROT_NONE; return prot; @@ -1607,6 +1614,10 @@ static NTSTATUS create_view( struct file_view **view_ret, void *base, size_t siz TRACE( "forcing exec permission on %p-%p\n", base, (char *)base + size - 1 ); mprotect( base, size, unix_prot | PROT_EXEC ); } + + if (vprot & VPROT_WRITEWATCH && use_kernel_writewatch) + reset_write_watches( view->base, view->size ); + return STATUS_SUCCESS; } @@ -1726,7 +1737,7 @@ static BOOL set_vprot( struct file_view *view, void *base, size_t size, BYTE vpr { int unix_prot = get_unix_prot(vprot); - if (view->protect & VPROT_WRITEWATCH) + if (!use_kernel_writewatch && view->protect & VPROT_WRITEWATCH) { /* each page may need different protections depending on write watch flag */ set_page_vprot_bits( base, size, vprot & ~VPROT_WRITEWATCH, ~vprot & ~VPROT_WRITEWATCH ); @@ -1785,8 +1796,24 @@ static void update_write_watches( void *base, size_t size, size_t accessed_size */ static void reset_write_watches( void *base, SIZE_T size ) { - set_page_vprot_bits( base, size, VPROT_WRITEWATCH, 0 ); - mprotect_range( base, size, 0, 0 ); + if (use_kernel_writewatch) + { + char buffer[17]; + ssize_t ret; + + memset(buffer, 0, sizeof(buffer)); + buffer[0] = '6'; + *(void **)&buffer[1] = base; + *(void **)&buffer[1 + 8] = (char *)base + size; + + if ((ret = write(clear_refs_fd, buffer, sizeof(buffer))) != sizeof(buffer)) + ERR("Could not clear soft dirty bits, ret %zd, error %s.\n", ret, strerror(errno)); + } + else + { + set_page_vprot_bits( base, size, VPROT_WRITEWATCH, 0 ); + mprotect_range( base, size, 0, 0 ); + } } @@ -2677,12 +2704,31 @@ void virtual_init(void) size_t size; int i; pthread_mutexattr_t attr; + const char *env_var; pthread_mutexattr_init( &attr ); pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ); pthread_mutex_init( &virtual_mutex, &attr ); pthread_mutexattr_destroy( &attr ); + if (!((env_var = getenv("WINE_DISABLE_KERNEL_WRITEWATCH")) && atoi(env_var)) + && (pagemap_reset_fd = open("/proc/self/pagemap_reset", O_RDONLY)) != -1) + { + use_kernel_writewatch = TRUE; + if ((pagemap_fd = open("/proc/self/pagemap", O_RDONLY)) == -1) + { + ERR("Could not open pagemap file, error %s.\n", strerror(errno)); + exit(-1); + } + if ((clear_refs_fd = open("/proc/self/clear_refs", O_WRONLY)) == -1) + { + ERR("Could not open clear_refs file, error %s.\n", strerror(errno)); + exit(-1); + } + if (ERR_ON(virtual)) + MESSAGE("wine: using kernel write watches (experimental).\n"); + } + if (preload_info && *preload_info) for (i = 0; (*preload_info)[i].size; i++) mmap_add_reserved_area( (*preload_info)[i].addr, (*preload_info)[i].size ); @@ -3305,7 +3351,7 @@ NTSTATUS virtual_handle_fault( void *addr, DWORD err, void *stack ) } else ret = grow_thread_stack( page, &stack_info ); } - else if (err & EXCEPTION_WRITE_FAULT) + else if (!use_kernel_writewatch && err & EXCEPTION_WRITE_FAULT) { if (vprot & VPROT_WRITEWATCH) { @@ -3389,11 +3435,11 @@ static NTSTATUS check_write_access( void *base, size_t size, BOOL *has_write_wat for (i = 0; i < size; i += page_size) { BYTE vprot = get_page_vprot( addr + i ); - if (vprot & VPROT_WRITEWATCH) *has_write_watch = TRUE; + if (!use_kernel_writewatch && vprot & VPROT_WRITEWATCH) *has_write_watch = TRUE; if (!(get_unix_prot( vprot & ~VPROT_WRITEWATCH ) & PROT_WRITE)) return STATUS_INVALID_USER_BUFFER; } - if (*has_write_watch) + if (!use_kernel_writewatch && *has_write_watch) mprotect_range( addr, size, 0, VPROT_WRITEWATCH ); /* temporarily enable write access */ return STATUS_SUCCESS; } @@ -4963,17 +5009,90 @@ NTSTATUS WINAPI NtGetWriteWatch( HANDLE process, ULONG flags, PVOID base, SIZE_T char *addr = base; char *end = addr + size; - while (pos < *count && addr < end) + if (use_kernel_writewatch) + { + static UINT64 buffer[PAGE_FLAGS_BUFFER_LENGTH]; + unsigned int i, length; + ssize_t read_length; + + if (flags & WRITE_WATCH_FLAG_RESET) + { + if (is_win64) + { + addresses[0] = end; + if ((read_length = pread(pagemap_reset_fd, addresses, *count * sizeof(*addresses), + ((ULONG_PTR)addr >> page_shift) * sizeof(*addresses))) == -1) + { + ERR("Error reading page flags, read_length %zd, error %s.\n", read_length, strerror(errno)); + status = STATUS_INVALID_ADDRESS; + goto done; + } + *count = read_length / sizeof(*addresses); + *granularity = page_size; + goto done; + } + + while (pos < *count && addr < end) + { + length = min(PAGE_FLAGS_BUFFER_LENGTH, *count - pos); + + buffer[0] = (ULONG_PTR)end; + if ((read_length = pread(pagemap_reset_fd, buffer, length * sizeof(*buffer), + ((ULONG_PTR)addr >> page_shift) * sizeof(*buffer))) == -1) + { + ERR("Error reading page flags, read_length %zd, error %s.\n", read_length, strerror(errno)); + status = STATUS_INVALID_ADDRESS; + goto done; + } + read_length /= sizeof(*buffer); + for (i = 0; i < read_length; ++i) + { + assert(pos < *count); + addresses[pos++] = (void *)(ULONG_PTR)buffer[i]; + } + if (read_length < length) + break; + addr = (char *)(ULONG_PTR)buffer[read_length - 1] + page_size; + } + } + else + { + while (pos < *count && addr < end) + { + length = min(PAGE_FLAGS_BUFFER_LENGTH, (end - addr) >> page_shift); + + if ((read_length = pread(pagemap_fd, buffer, length * sizeof(*buffer), + ((ULONG_PTR)addr >> page_shift) * sizeof(*buffer))) != length * sizeof(*buffer)) + { + ERR("Error reading page flags, read_length %zd, error %s.\n", read_length, strerror(errno)); + status = STATUS_INVALID_ADDRESS; + goto done; + } + for (i = 0; i < length && pos < *count; ++i) + { + if (buffer[i] & PM_SOFT_DIRTY_PAGE) + addresses[pos++] = addr; + + addr += page_size; + } + } + } + } + else { - if (!(get_page_vprot( addr ) & VPROT_WRITEWATCH)) addresses[pos++] = addr; - addr += page_size; + while (pos < *count && addr < end) + { + if (!(get_page_vprot( addr ) & VPROT_WRITEWATCH)) addresses[pos++] = addr; + addr += page_size; + } + if (flags & WRITE_WATCH_FLAG_RESET) reset_write_watches( base, addr - (char *)base ); } - if (flags & WRITE_WATCH_FLAG_RESET) reset_write_watches( base, addr - (char *)base ); *count = pos; *granularity = page_size; } else status = STATUS_INVALID_PARAMETER; +done: server_leave_uninterrupted_section( &virtual_mutex, &sigset ); return status; } From c118bc27889603fd238af93609588c10c188e7cc Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 13 May 2020 13:55:55 +0300 Subject: [PATCH 0489/2777] ntdll: Add WINE_DISABLE_WRITE_WATCH env var to disable write watch support. Massively improves performance for corert games (Streets of Rage 4). Could be fixed properly with Linux kernel changes. --- dlls/ntdll/unix/virtual.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 236b4ccb4d1..904aa20764e 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -3808,6 +3808,22 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ SIZE_T size = *size_ptr; NTSTATUS status = STATUS_SUCCESS; + if (type & MEM_WRITE_WATCH) + { + static int disable = -1; + + if (disable == -1) + { + const char *env_var; + + if ((disable = (env_var = getenv("WINE_DISABLE_WRITE_WATCH")) && atoi(env_var))) + FIXME("Disabling write watch support.\n"); + } + + if (disable) + return STATUS_NOT_SUPPORTED; + } + /* Round parameters to a page boundary */ if (is_beyond_limit( 0, size, working_set_limit )) return STATUS_WORKING_SET_LIMIT_RANGE; From da269370c90ba39298cae1cc68f520b4c10c6a6a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 2 Nov 2020 23:03:20 +0300 Subject: [PATCH 0490/2777] ntdll: Implement CPU topology override. --- dlls/ntdll/unix/server.c | 3 + dlls/ntdll/unix/system.c | 172 +++++++++++++++++++++++++++++---- dlls/ntdll/unix/thread.c | 15 ++- dlls/ntdll/unix/unix_private.h | 1 + server/process.c | 30 ++++++ server/process.h | 2 + server/protocol.def | 7 ++ server/thread.c | 30 +++++- server/trace.c | 19 ++++ 9 files changed, 257 insertions(+), 22 deletions(-) diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index a11e61a416a..3df115ccea6 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -1590,6 +1590,7 @@ size_t server_init_process(void) */ void server_init_process_done(void) { + struct cpu_topology_override *cpu_override = get_cpu_topology_override(); void *entry, *teb; unsigned int status; int suspend; @@ -1616,6 +1617,8 @@ void server_init_process_done(void) /* Signal the parent process to continue */ SERVER_START_REQ( init_process_done ) { + if (cpu_override) + wine_server_add_data( req, cpu_override, sizeof(*cpu_override) ); req->teb = wine_server_client_ptr( teb ); req->peb = NtCurrentTeb64() ? NtCurrentTeb64()->Peb : wine_server_client_ptr( peb ); #ifdef __i386__ diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index b9762fd278f..79d2a7bab9b 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -236,6 +237,13 @@ static unsigned int logical_proc_info_ex_size, logical_proc_info_ex_alloc_size; static pthread_mutex_t timezone_mutex = PTHREAD_MUTEX_INITIALIZER; +static struct +{ + struct cpu_topology_override mapping; + BOOL smt; +} +cpu_override; + /******************************************************************************* * Architecture specific feature detection for CPUs * @@ -541,6 +549,91 @@ static void get_cpuinfo( SYSTEM_CPU_INFORMATION *info ) #endif /* End architecture specific feature detection for CPUs */ +static void fill_cpu_override(unsigned int host_cpu_count) +{ + const char *env_override = getenv("WINE_CPU_TOPOLOGY"); + unsigned int i; + char *s; + + if (!env_override) + return; + + cpu_override.mapping.cpu_count = strtol(env_override, &s, 10); + if (s == env_override) + goto error; + + if (!cpu_override.mapping.cpu_count || cpu_override.mapping.cpu_count > MAXIMUM_PROCESSORS) + { + ERR("Invalid logical CPU count %u, limit %u.\n", cpu_override.mapping.cpu_count, MAXIMUM_PROCESSORS); + goto error; + } + + if (tolower(*s) == 's') + { + cpu_override.mapping.cpu_count *= 2; + if (cpu_override.mapping.cpu_count > MAXIMUM_PROCESSORS) + { + ERR("Logical CPU count exceeds limit %u.\n", MAXIMUM_PROCESSORS); + goto error; + } + cpu_override.smt = TRUE; + ++s; + } + if (*s != ':') + goto error; + ++s; + for (i = 0; i < cpu_override.mapping.cpu_count; ++i) + { + char *next; + + if (i) + { + if (*s != ',') + { + if (!*s) + ERR("Incomplete host CPU mapping string, %u CPUs mapping required.\n", + cpu_override.mapping.cpu_count); + goto error; + } + ++s; + } + + cpu_override.mapping.host_cpu_id[i] = strtol(s, &next, 10); + if (next == s) + goto error; + if (cpu_override.mapping.host_cpu_id[i] >= host_cpu_count) + { + ERR("Invalid host CPU index %u (host_cpu_count %u).\n", + cpu_override.mapping.host_cpu_id[i], host_cpu_count); + goto error; + } + s = next; + } + if (*s) + goto error; + + if (ERR_ON(ntdll)) + { + MESSAGE("wine: overriding CPU configuration, %u logical CPUs, host CPUs ", cpu_override.mapping.cpu_count); + for (i = 0; i < cpu_override.mapping.cpu_count; ++i) + { + if (i) + MESSAGE(","); + MESSAGE("%u", cpu_override.mapping.host_cpu_id[i]); + } + MESSAGE(".\n"); + } + return; +error: + cpu_override.mapping.cpu_count = 0; + ERR("Invalid WINE_CPU_TOPOLOGY string %s (%s).\n", debugstr_a(env_override), debugstr_a(s)); +} + +struct cpu_topology_override *get_cpu_topology_override(void) +{ + return cpu_override.mapping.cpu_count ? &cpu_override.mapping : NULL; +} + static BOOL grow_logical_proc_buf(void) { SYSTEM_LOGICAL_PROCESSOR_INFORMATION *new_data; @@ -830,11 +923,13 @@ static NTSTATUS create_logical_proc_info(void) static const char core_info[] = "/sys/devices/system/cpu/cpu%u/topology/%s"; static const char cache_info[] = "/sys/devices/system/cpu/cpu%u/cache/index%u/%s"; static const char numa_info[] = "/sys/devices/system/node/node%u/cpumap"; - + const char *env_fake_logical_cores = getenv("WINE_LOGICAL_CPUS_AS_CORES"); + BOOL fake_logical_cpus_as_cores = env_fake_logical_cores && atoi(env_fake_logical_cores); FILE *fcpu_list, *fnuma_list, *f; unsigned int beg, end, i, j, r, num_cpus = 0, max_cpus = 0; char op, name[MAX_PATH]; ULONG_PTR all_cpus_mask = 0; + unsigned int cpu_id; /* On systems with a large number of CPU cores (32 or 64 depending on 32-bit or 64-bit), * we have issues parsing processor information: @@ -859,6 +954,12 @@ static NTSTATUS create_logical_proc_info(void) if (op == '-') fscanf(fcpu_list, "%u%c ", &end, &op); else end = beg; + if (cpu_override.mapping.cpu_count) + { + beg = 0; + end = cpu_override.mapping.cpu_count - 1; + } + for(i = beg; i <= end; i++) { unsigned int phys_core = 0; @@ -870,7 +971,7 @@ static NTSTATUS create_logical_proc_info(void) continue; } - sprintf(name, core_info, i, "physical_package_id"); + sprintf(name, core_info, cpu_override.mapping.cpu_count ? cpu_override.mapping.host_cpu_id[i] : i, "physical_package_id"); f = fopen(name, "r"); if (f) { @@ -897,19 +998,32 @@ static NTSTATUS create_logical_proc_info(void) /* Mask of logical threads sharing same physical core in kernel core numbering. */ sprintf(name, core_info, i, "thread_siblings"); - if(!sysfs_parse_bitmap(name, &thread_mask)) thread_mask = 1<NumberOfProcessors = num; + + fill_cpu_override(num); + + peb->NumberOfProcessors = cpu_override.mapping.cpu_count + ? cpu_override.mapping.cpu_count : num; get_cpuinfo( &cpu_info ); TRACE( "<- CPU arch %d, level %d, rev %d, features 0x%x\n", (int)cpu_info.ProcessorArchitecture, (int)cpu_info.ProcessorLevel, diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index b2881cc4695..edeb355c7cb 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -2427,7 +2427,20 @@ ULONG WINAPI NtGetCurrentProcessorNumber(void) #if defined(__linux__) && defined(__NR_getcpu) int res = syscall(__NR_getcpu, &processor, NULL, NULL); - if (res != -1) return processor; + if (res != -1) + { + struct cpu_topology_override *override = get_cpu_topology_override(); + unsigned int i; + + if (!override) + return processor; + + for (i = 0; i < override->cpu_count; ++i) + if (override->host_cpu_id[i] == processor) + return i; + + WARN("Thread is running on processor which is not in the defined override.\n"); + } #endif if (peb->NumberOfProcessors > 1) diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index a8a7442f314..2740fe10128 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -292,6 +292,7 @@ extern void init_files(void) DECLSPEC_HIDDEN; extern void init_cpu_info(void) DECLSPEC_HIDDEN; extern void add_completion( HANDLE handle, ULONG_PTR value, NTSTATUS status, ULONG info, BOOL async ) DECLSPEC_HIDDEN; extern void set_async_direct_result( HANDLE *async_handle, NTSTATUS status, ULONG_PTR information, BOOL mark_pending ) DECLSPEC_HIDDEN; +extern struct cpu_topology_override *get_cpu_topology_override(void) DECLSPEC_HIDDEN; extern void dbg_init(void) DECLSPEC_HIDDEN; diff --git a/server/process.c b/server/process.c index a12f16a4337..fa9eab47214 100644 --- a/server/process.c +++ b/server/process.c @@ -100,6 +100,7 @@ static void process_destroy( struct object *obj ); static int process_get_esync_fd( struct object *obj, enum esync_type *type ); static unsigned int process_get_fsync_idx( struct object *obj, enum fsync_type *type ); static void terminate_process( struct process *process, struct thread *skip, int exit_code ); +static void set_process_affinity( struct process *process, affinity_t affinity ); static const struct object_ops process_ops = { @@ -695,6 +696,7 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla memset( &process->image_info, 0, sizeof(process->image_info) ); process->esync_fd = -1; process->fsync_idx = 0; + process->cpu_override.cpu_count = 0; list_init( &process->kernel_object ); list_init( &process->thread_list ); list_init( &process->locks ); @@ -1449,6 +1451,26 @@ DECL_HANDLER(init_process_done) struct memory_view *view; client_ptr_t base; 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)) { @@ -1478,6 +1500,14 @@ DECL_HANDLER(init_process_done) if (process->debug_obj) set_process_debug_flag( process, 1 ); reply->entry = current->entry_point; 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 b3b19859a71..7d7a1f3bfcf 100644 --- a/server/process.h +++ b/server/process.h @@ -88,6 +88,8 @@ struct process pe_image_info_t image_info; /* main exe image info */ 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/protocol.def b/server/protocol.def index e08351b2133..572aa593f96 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -865,6 +865,12 @@ 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; /* cursor position */ @@ -979,6 +985,7 @@ struct input_shared_memory client_ptr_t ldt_copy; /* address of LDT copy (in process address space) */ @REPLY client_ptr_t entry; /* process entry point */ + VARARG(cpu_override,cpu_topology_override); /* Overridden CPUs to host CPUs mapping. */ int suspend; /* is process suspended? */ @END diff --git a/server/thread.c b/server/thread.c index 2c9a18be1f3..416746e389d 100644 --- a/server/thread.c +++ b/server/thread.c @@ -733,8 +733,19 @@ int set_thread_affinity( struct thread *thread, affinity_t affinity ) CPU_ZERO( &set ); for (i = 0, mask = 1; mask; i++, mask <<= 1) - if (affinity & mask) CPU_SET( i, &set ); - + if (affinity & mask) + { + if (thread->process->cpu_override.cpu_count) + { + if (i >= thread->process->cpu_override.cpu_count) + break; + CPU_SET( thread->process->cpu_override.host_cpu_id[i], &set ); + } + else + { + CPU_SET( i, &set ); + } + } ret = sched_setaffinity( thread->unix_tid, sizeof(set), &set ); } #endif @@ -752,8 +763,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; diff --git a/server/trace.c b/server/trace.c index a0076d5449b..b749c54a900 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1356,6 +1356,24 @@ static void dump_varargs_handle_infos( const char *prefix, data_size_t size ) fputc( '}', stderr ); } +static void dump_varargs_cpu_topology_override( const char *prefix, data_size_t size ) +{ + const struct cpu_topology_override *cpu_topology = cur_data; + unsigned int i; + + if (size < sizeof(*cpu_topology)) + return; + + fprintf( stderr,"%s{", prefix ); + for (i = 0; i < cpu_topology->cpu_count; ++i) + { + if (i) fputc( ',', stderr ); + fprintf( stderr, "%u", cpu_topology->host_cpu_id[i] ); + } + fputc( '}', stderr ); + remove_data( size ); +} + typedef void (*dump_func)( const void *req ); /* Everything below this line is generated automatically by tools/make_requests */ @@ -1434,6 +1452,7 @@ static void dump_init_process_done_request( const struct init_process_done_reque static void dump_init_process_done_reply( const struct init_process_done_reply *req ) { dump_uint64( " entry=", &req->entry ); + dump_varargs_cpu_topology_override( ", cpu_override=", cur_size ); fprintf( stderr, ", suspend=%d", req->suspend ); } From dd54eca3c430981a38cb33058ced7e1826de4e23 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 7 Dec 2021 11:16:40 +0300 Subject: [PATCH 0491/2777] server: Split waitable object off completion port. CW-Bug-Id: #19621 --- server/completion.c | 120 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 96 insertions(+), 24 deletions(-) diff --git a/server/completion.c b/server/completion.c index 33266c596da..915a083e642 100644 --- a/server/completion.c +++ b/server/completion.c @@ -56,15 +56,52 @@ struct type_descr completion_type = }, }; -struct completion +struct completion_wait { struct object obj; struct list queue; unsigned int depth; }; +struct completion +{ + struct object obj; + struct completion_wait *wait; +}; + +static void completion_wait_dump( struct object*, int ); +static int completion_wait_signaled( struct object *obj, struct wait_queue_entry *entry ); +static void completion_wait_destroy( struct object * ); + +static const struct object_ops completion_wait_ops = +{ + sizeof(struct completion_wait), /* size */ + &no_type, /* type */ + completion_wait_dump, /* dump */ + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + completion_wait_signaled, /* signaled */ + NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + default_map_access, /* map_access */ + default_get_sd, /* get_sd */ + default_set_sd, /* set_sd */ + no_get_full_name, /* get_full_name */ + no_lookup_name, /* lookup_name */ + no_link_name, /* link_name */ + NULL, /* unlink_name */ + no_open_file, /* open_file */ + no_kernel_obj_list, /* get_kernel_obj_list */ + no_close_handle, /* close_handle */ + completion_wait_destroy /* destroy */ +}; + static void completion_dump( struct object*, int ); -static int completion_signaled( struct object *obj, struct wait_queue_entry *entry ); +static int completion_add_queue( struct object *obj, struct wait_queue_entry *entry ); +static void completion_remove_queue( struct object *obj, struct wait_queue_entry *entry ); static void completion_destroy( struct object * ); static const struct object_ops completion_ops = @@ -72,9 +109,9 @@ static const struct object_ops completion_ops = sizeof(struct completion), /* size */ &completion_type, /* type */ completion_dump, /* dump */ - add_queue, /* add_queue */ - remove_queue, /* remove_queue */ - completion_signaled, /* signaled */ + completion_add_queue, /* add_queue */ + completion_remove_queue, /* remove_queue */ + NULL, /* signaled */ NULL, /* get_esync_fd */ NULL, /* get_fsync_idx */ no_satisfied, /* satisfied */ @@ -102,30 +139,63 @@ struct comp_msg unsigned int status; }; -static void completion_destroy( struct object *obj) +static void completion_wait_destroy( struct object *obj) { - struct completion *completion = (struct completion *) obj; + struct completion_wait *wait = (struct completion_wait *)obj; struct comp_msg *tmp, *next; - LIST_FOR_EACH_ENTRY_SAFE( tmp, next, &completion->queue, struct comp_msg, queue_entry ) + LIST_FOR_EACH_ENTRY_SAFE( tmp, next, &wait->queue, struct comp_msg, queue_entry ) { free( tmp ); } } +static void completion_wait_dump( struct object *obj, int verbose ) +{ + struct completion_wait *wait = (struct completion_wait *)obj; + + assert( obj->ops == &completion_wait_ops ); + fprintf( stderr, "Completion depth=%u\n", wait->depth ); +} + +static int completion_wait_signaled( struct object *obj, struct wait_queue_entry *entry ) +{ + struct completion_wait *wait = (struct completion_wait *)obj; + + assert( obj->ops == &completion_wait_ops ); + return !list_empty( &wait->queue ); +} + static void completion_dump( struct object *obj, int verbose ) { - struct completion *completion = (struct completion *) obj; + struct completion *completion = (struct completion *)obj; + + assert( obj->ops == &completion_ops ); + completion->wait->obj.ops->dump( &completion->wait->obj, verbose ); +} + +static int completion_add_queue( struct object *obj, struct wait_queue_entry *entry ) +{ + struct completion *completion = (struct completion *)obj; + + assert( obj->ops == &completion_ops ); + return completion->wait->obj.ops->add_queue( &completion->wait->obj, entry ); +} + +static void completion_remove_queue( struct object *obj, struct wait_queue_entry *entry ) +{ + struct completion *completion = (struct completion *)obj; assert( obj->ops == &completion_ops ); - fprintf( stderr, "Completion depth=%u\n", completion->depth ); + completion->wait->obj.ops->remove_queue( &completion->wait->obj, entry ); } -static int completion_signaled( struct object *obj, struct wait_queue_entry *entry ) +static void completion_destroy( struct object *obj ) { struct completion *completion = (struct completion *)obj; - return !list_empty( &completion->queue ); + assert( obj->ops == &completion_ops ); + release_object( &completion->wait->obj ); } static struct completion *create_completion( struct object *root, const struct unicode_str *name, @@ -134,15 +204,17 @@ static struct completion *create_completion( struct object *root, const struct u { struct completion *completion; - if ((completion = create_named_object( root, &completion_ops, name, attr, sd ))) + if (!(completion = create_named_object( root, &completion_ops, name, attr, sd ))) return NULL; + if (get_error() == STATUS_OBJECT_NAME_EXISTS) return completion; + if (!(completion->wait = alloc_object( &completion_wait_ops ))) { - if (get_error() != STATUS_OBJECT_NAME_EXISTS) - { - list_init( &completion->queue ); - completion->depth = 0; - } + release_object( completion ); + set_error( STATUS_NO_MEMORY ); + return NULL; } + list_init( &completion->wait->queue ); + completion->wait->depth = 0; return completion; } @@ -164,9 +236,9 @@ void add_completion( struct completion *completion, apc_param_t ckey, apc_param_ msg->status = status; msg->information = information; - list_add_tail( &completion->queue, &msg->queue_entry ); - completion->depth++; - wake_up( &completion->obj, 1 ); + list_add_tail( &completion->wait->queue, &msg->queue_entry ); + completion->wait->depth++; + wake_up( &completion->wait->obj, 1 ); } /* create a completion */ @@ -220,13 +292,13 @@ DECL_HANDLER(remove_completion) if (!completion) return; - entry = list_head( &completion->queue ); + entry = list_head( &completion->wait->queue ); if (!entry) set_error( STATUS_PENDING ); else { list_remove( entry ); - completion->depth--; + completion->wait->depth--; msg = LIST_ENTRY( entry, struct comp_msg, queue_entry ); reply->ckey = msg->ckey; reply->cvalue = msg->cvalue; @@ -245,7 +317,7 @@ DECL_HANDLER(query_completion) if (!completion) return; - reply->depth = completion->depth; + reply->depth = completion->wait->depth; release_object( completion ); } From 41c824c5c8c48b4486c59276d66b0bcc3a056751 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 7 Dec 2021 12:27:17 +0300 Subject: [PATCH 0492/2777] server: Abandon wait when completion port is closed. CW-Bug-Id: #19621 Based on patches by Alexey Prokhin. --- dlls/ntdll/tests/sync.c | 65 +++++++++++++++++++++++++++++++++++++++++ server/completion.c | 25 ++++++++++++---- 2 files changed, 85 insertions(+), 5 deletions(-) diff --git a/dlls/ntdll/tests/sync.c b/dlls/ntdll/tests/sync.c index f356d3ec38f..95229f2513d 100644 --- a/dlls/ntdll/tests/sync.c +++ b/dlls/ntdll/tests/sync.c @@ -837,6 +837,70 @@ static void test_tid_alert( char **argv ) CloseHandle( pi.hThread ); } +static HANDLE test_close_io_completion_port_ready, test_close_io_completion_test_ready; +static HANDLE test_close_io_completion_port; + +static DWORD WINAPI test_close_io_completion_thread(void *param) +{ + FILE_IO_COMPLETION_INFORMATION info; + IO_STATUS_BLOCK iosb; + ULONG_PTR key, value; + NTSTATUS status; + ULONG count; + DWORD ret; + + ret = WaitForSingleObject( test_close_io_completion_port_ready, INFINITE ); + ok( ret == WAIT_OBJECT_0, "Got unexpected ret %#x.\n", ret ); + SetEvent( test_close_io_completion_test_ready ); + status = NtRemoveIoCompletion( test_close_io_completion_port, &key, &value, &iosb, NULL ); + if (status == STATUS_INVALID_HANDLE) + skip( "Handle closed before wait started.\n" ); + else + ok( status == STATUS_ABANDONED_WAIT_0, "Got unexpected status %#x.\n", status ); + + ret = WaitForSingleObject( test_close_io_completion_port_ready, INFINITE ); + ok( ret == WAIT_OBJECT_0, "Got unexpected ret %#x.\n", ret ); + SetEvent( test_close_io_completion_test_ready ); + count = 0xdeadbeef; + status = NtRemoveIoCompletionEx( test_close_io_completion_port, &info, 1, &count, NULL, FALSE ); + ok( count == 1, "Got unexpected count %u.\n", count ); + if (status == STATUS_INVALID_HANDLE) + skip( "Handle closed before wait started.\n" ); + else + ok( status == STATUS_ABANDONED_WAIT_0, "Got unexpected status %#x.\n", status ); + + return 0; +} + +static void test_close_io_completion(void) +{ + NTSTATUS status; + unsigned int i; + HANDLE thread; + DWORD ret; + + test_close_io_completion_port_ready = CreateEventA(NULL, FALSE, FALSE, NULL); + test_close_io_completion_test_ready = CreateEventA(NULL, FALSE, FALSE, NULL); + + thread = CreateThread( NULL, 0, test_close_io_completion_thread, NULL, 0, NULL ); + ok( !!thread, "Failed to create thread, error %u.\n", GetLastError() ); + + for (i = 0; i < 2; ++i) + { + status = NtCreateIoCompletion( &test_close_io_completion_port, IO_COMPLETION_ALL_ACCESS, NULL, 0 ); + ok( !status, "Got unexpected status %#x.\n", status ); + ret = SignalObjectAndWait( test_close_io_completion_port_ready, test_close_io_completion_test_ready, + INFINITE, FALSE ); + ok( ret == WAIT_OBJECT_0, "Got unexpected ret %#x.\n", ret ); + Sleep(10); + status = pNtClose( test_close_io_completion_port ); + ok( !status, "Got unexpected status %#x.\n", status ); + } + + WaitForSingleObject( thread, INFINITE ); + CloseHandle( thread ); +} + START_TEST(sync) { HMODULE module = GetModuleHandleA("ntdll.dll"); @@ -884,4 +948,5 @@ START_TEST(sync) test_keyed_events(); test_resource(); test_tid_alert( argv ); + test_close_io_completion(); } diff --git a/server/completion.c b/server/completion.c index 915a083e642..1d70897db83 100644 --- a/server/completion.c +++ b/server/completion.c @@ -56,11 +56,14 @@ struct type_descr completion_type = }, }; +struct completion; + struct completion_wait { - struct object obj; - struct list queue; - unsigned int depth; + struct object obj; + struct completion *completion; + struct list queue; + unsigned int depth; }; struct completion @@ -71,6 +74,7 @@ struct completion static void completion_wait_dump( struct object*, int ); static int completion_wait_signaled( struct object *obj, struct wait_queue_entry *entry ); +static void completion_wait_satisfied( struct object *obj, struct wait_queue_entry *entry ); static void completion_wait_destroy( struct object * ); static const struct object_ops completion_wait_ops = @@ -83,7 +87,7 @@ static const struct object_ops completion_wait_ops = completion_wait_signaled, /* signaled */ NULL, /* get_esync_fd */ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ + completion_wait_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ default_map_access, /* map_access */ @@ -163,7 +167,15 @@ static int completion_wait_signaled( struct object *obj, struct wait_queue_entry struct completion_wait *wait = (struct completion_wait *)obj; assert( obj->ops == &completion_wait_ops ); - return !list_empty( &wait->queue ); + return !wait->completion || !list_empty( &wait->queue ); +} + +static void completion_wait_satisfied( struct object *obj, struct wait_queue_entry *entry ) +{ + struct completion_wait *wait = (struct completion_wait *)obj; + + assert( obj->ops == &completion_wait_ops ); + if (!wait->completion) make_wait_abandoned( entry ); } static void completion_dump( struct object *obj, int verbose ) @@ -195,6 +207,8 @@ static void completion_destroy( struct object *obj ) struct completion *completion = (struct completion *)obj; assert( obj->ops == &completion_ops ); + completion->wait->completion = NULL; + wake_up( &completion->wait->obj, 0 ); release_object( &completion->wait->obj ); } @@ -213,6 +227,7 @@ static struct completion *create_completion( struct object *root, const struct u return NULL; } + completion->wait->completion = completion; list_init( &completion->wait->queue ); completion->wait->depth = 0; return completion; From 6f4f6944a64d581e1a253faf97b5618ae898990f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 7 Dec 2021 13:33:01 +0300 Subject: [PATCH 0493/2777] server: Ensure completion port wait object exists after successful wait. CW-Bug-Id: #19621 Based on the problem analysis by Andrew Eikum. --- dlls/ntdll/unix/sync.c | 6 ++++++ server/completion.c | 36 ++++++++++++++++++++++++++++++------ server/protocol.def | 1 + server/thread.c | 2 ++ server/thread.h | 1 + 5 files changed, 40 insertions(+), 6 deletions(-) diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 4cea4d07789..8aef63c95c4 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -1963,6 +1963,7 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR * IO_STATUS_BLOCK *io, LARGE_INTEGER *timeout ) { unsigned int status; + int waited = 0; TRACE( "(%p, %p, %p, %p, %p)\n", handle, key, value, io, timeout ); @@ -1971,6 +1972,7 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR * SERVER_START_REQ( remove_completion ) { req->handle = wine_server_obj_handle( handle ); + req->waited = waited; if (!(status = wine_server_call( req ))) { *key = reply->ckey; @@ -1983,6 +1985,7 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR * if (status != STATUS_PENDING) return status; status = NtWaitForSingleObject( handle, FALSE, timeout ); if (status != WAIT_OBJECT_0) return status; + waited = 1; } } @@ -1994,6 +1997,7 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM ULONG *written, LARGE_INTEGER *timeout, BOOLEAN alertable ) { unsigned int status; + int waited = 0; ULONG i = 0; TRACE( "%p %p %u %p %p %u\n", handle, info, (int)count, written, timeout, alertable ); @@ -2005,6 +2009,7 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM SERVER_START_REQ( remove_completion ) { req->handle = wine_server_obj_handle( handle ); + req->waited = waited; if (!(status = wine_server_call( req ))) { info[i].CompletionKey = reply->ckey; @@ -2024,6 +2029,7 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM } status = NtWaitForSingleObject( handle, alertable, timeout ); if (status != WAIT_OBJECT_0) break; + waited = 1; } *written = i ? i : 1; return status; diff --git a/server/completion.c b/server/completion.c index 1d70897db83..cbafe811796 100644 --- a/server/completion.c +++ b/server/completion.c @@ -173,9 +173,16 @@ static int completion_wait_signaled( struct object *obj, struct wait_queue_entry static void completion_wait_satisfied( struct object *obj, struct wait_queue_entry *entry ) { struct completion_wait *wait = (struct completion_wait *)obj; + struct thread *thread; assert( obj->ops == &completion_wait_ops ); - if (!wait->completion) make_wait_abandoned( entry ); + if (wait->completion) + { + thread = get_wait_queue_thread( entry ); + if (thread->locked_completion) release_object( thread->locked_completion ); + thread->locked_completion = grab_object( obj ); + } + else make_wait_abandoned( entry ); } static void completion_dump( struct object *obj, int verbose ) @@ -301,19 +308,36 @@ DECL_HANDLER(add_completion) /* get completion from completion port */ DECL_HANDLER(remove_completion) { - struct completion* completion = get_completion_obj( current->process, req->handle, IO_COMPLETION_MODIFY_STATE ); + struct completion* completion; + struct completion_wait *wait; struct list *entry; struct comp_msg *msg; - if (!completion) return; + if (req->waited && (wait = (struct completion_wait *)current->locked_completion)) + current->locked_completion = NULL; + else + { + if (current->locked_completion) + { + release_object( current->locked_completion ); + current->locked_completion = NULL; + } + completion = get_completion_obj( current->process, req->handle, IO_COMPLETION_MODIFY_STATE ); + if (!completion) return; + + wait = (struct completion_wait *)grab_object( completion->wait ); + release_object( completion ); + } - entry = list_head( &completion->wait->queue ); + assert( wait->obj.ops == &completion_wait_ops ); + + entry = list_head( &wait->queue ); if (!entry) set_error( STATUS_PENDING ); else { list_remove( entry ); - completion->wait->depth--; + wait->depth--; msg = LIST_ENTRY( entry, struct comp_msg, queue_entry ); reply->ckey = msg->ckey; reply->cvalue = msg->cvalue; @@ -322,7 +346,7 @@ DECL_HANDLER(remove_completion) free( msg ); } - release_object( completion ); + release_object( wait ); } /* get queue depth for completion port */ diff --git a/server/protocol.def b/server/protocol.def index 572aa593f96..3a2101b08df 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3615,6 +3615,7 @@ struct handle_info /* get completion from completion port queue */ @REQ(remove_completion) obj_handle_t handle; /* port handle */ + int waited; /* port was just successfully waited on */ @REPLY apc_param_t ckey; /* completion key */ apc_param_t cvalue; /* completion value */ diff --git a/server/thread.c b/server/thread.c index 416746e389d..c82225fb050 100644 --- a/server/thread.c +++ b/server/thread.c @@ -300,6 +300,7 @@ static inline void init_thread_structure( struct thread *thread ) thread->creation_time = current_time; thread->exit_time = 0; + thread->locked_completion = NULL; list_init( &thread->mutex_list ); list_init( &thread->system_apc ); @@ -585,6 +586,7 @@ static void destroy_thread( struct object *obj ) release_object( thread->process ); if (thread->id) free_ptid( thread->id ); if (thread->token) release_object( thread->token ); + if (thread->locked_completion) release_object( thread->locked_completion ); if (do_esync()) close( thread->esync_fd ); diff --git a/server/thread.h b/server/thread.h index 023afba9e4d..067fea940cf 100644 --- a/server/thread.h +++ b/server/thread.h @@ -95,6 +95,7 @@ struct thread struct list kernel_object; /* list of kernel object pointers */ data_size_t desc_len; /* thread description length in bytes */ WCHAR *desc; /* thread description string */ + struct object *locked_completion; /* completion port wait object successfully waited by the thread */ struct object *queue_shared_mapping; /* thread queue shared memory mapping */ volatile struct queue_shared_memory *queue_shared; /* thread queue shared memory ptr */ struct object *input_shared_mapping; /* thread input shared memory mapping */ From 14773572ec784c4bc3d6a12e5e31887837268762 Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Thu, 23 Apr 2020 12:29:55 +0300 Subject: [PATCH 0494/2777] kernelbase: Set the proper error code in GetQueuedCompletionStatus{Ex} when the handle is closed. Planet Zoo relies on it being ERROR_ABANDONED_WAIT_0. --- dlls/kernelbase/sync.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/kernelbase/sync.c b/dlls/kernelbase/sync.c index 60b33af99c3..4c366f859c6 100644 --- a/dlls/kernelbase/sync.c +++ b/dlls/kernelbase/sync.c @@ -1093,6 +1093,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetQueuedCompletionStatus( HANDLE port, LPDWORD co } if (status == STATUS_TIMEOUT) SetLastError( WAIT_TIMEOUT ); + else if (status == ERROR_WAIT_NO_CHILDREN) SetLastError( ERROR_ABANDONED_WAIT_0 ); else SetLastError( RtlNtStatusToDosError(status) ); return FALSE; } @@ -1114,6 +1115,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetQueuedCompletionStatusEx( HANDLE port, OVERLAPP if (ret == STATUS_SUCCESS) return TRUE; else if (ret == STATUS_TIMEOUT) SetLastError( WAIT_TIMEOUT ); else if (ret == STATUS_USER_APC) SetLastError( WAIT_IO_COMPLETION ); + else if (ret == ERROR_WAIT_NO_CHILDREN) SetLastError( ERROR_ABANDONED_WAIT_0 ); else SetLastError( RtlNtStatusToDosError(ret) ); return FALSE; } From 314f78c713cb3499f19ebe086f1b7e2d992e6b7d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 25 Mar 2021 17:53:37 +0300 Subject: [PATCH 0495/2777] wine.inf: Create package repository for VCLibs.140. For Forza Horizon 4. --- loader/wine.inf.in | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index bbe93c60242..6ee10ca6db4 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -89,6 +89,7 @@ AddReg=\ MCI,\ Misc,\ OLE,\ + Packages,\ Printing,\ Services, \ SessionMgr,\ @@ -117,6 +118,7 @@ AddReg=\ MCI,\ Misc,\ OLE,\ + Packages.ntamd64,\ Printing,\ Services, \ SessionMgr,\ @@ -145,6 +147,7 @@ AddReg=\ MCI,\ Misc,\ OLE,\ + Packages.ntarm64,\ Printing,\ Services, \ SessionMgr,\ @@ -164,6 +167,7 @@ AddReg=\ DirectX,\ MCI,\ Misc,\ + Packages.wow64,\ Tapi,\ VersionInfo.ntamd64,\ LicenseInformation, \ @@ -257,6 +261,7 @@ CurrentVersion="Software\Microsoft\Windows\CurrentVersion" CurrentVersionNT="Software\Microsoft\Windows NT\CurrentVersion" FontSubStr="Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes" Control="System\CurrentControlSet\Control" +Packages="Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\PackageRepository\Packages" [Classes] HKCR,.chm,,2,"chm.file" @@ -610,6 +615,18 @@ HKCU,Software\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserCho HKLM,"Software\Microsoft\OLE","EnableDCOM",,"Y" HKLM,"Software\Microsoft\OLE","EnableRemoteConnect",,"N" +[Packages] +HKLM,"%Packages%\Microsoft.VCLibs.140.00_14.0.29231.0_x86__8wekyb3d8bbwe","Path",0x00020002,"%SystemRoot%\system32" + +[Packages.ntamd64] +HKLM,"%Packages%\Microsoft.VCLibs.140.00_14.0.29231.0_x64__8wekyb3d8bbwe","Path",0x00020002,"%SystemRoot%\system32" + +[Packages.wow64] +HKLM,"%Packages%\Microsoft.VCLibs.140.00_14.0.29231.0_x86__8wekyb3d8bbwe","Path",0x00020002,"%SystemRoot%\syswow64" + +[Packages.arm64] +HKLM,"%Packages%\Microsoft.VCLibs.140.00_14.0.29231.0_arm64__8wekyb3d8bbwe","Path",0x00020002,"%SystemRoot%\system32" + [Printing] HKLM,%Control%\Print\Monitors\Local Port,"Driver",2,"localspl.dll" HKLM,%Control%\Print\Printers,"DefaultSpoolDirectory",2,"%11%\spool\printers" From 4f20827500da2d90b6b18163f18d6ff9487fe294 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 15 Mar 2021 21:59:00 +0300 Subject: [PATCH 0496/2777] kernel32: Implement GetPackagesByPackageFamily(). For Forza Horizon 4. --- dlls/kernel32/kernel32.spec | 1 + dlls/kernel32/tests/version.c | 132 ++++++++++++++++++++++++++++++++ dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/version.c | 115 ++++++++++++++++++++++++++++ include/appmodel.h | 2 + 5 files changed, 251 insertions(+), 1 deletion(-) diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 8068e45e5e5..9f928274b0c 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -768,6 +768,7 @@ @ stdcall -import GetOverlappedResultEx(long ptr ptr long long) @ stdcall -import GetUserDefaultGeoName(ptr long) @ stdcall -import GetUserPreferredUILanguages(long ptr ptr ptr) +@ stdcall -import GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) @ stdcall GetPackageFamilyName(long ptr ptr) kernelbase.GetPackageFamilyName @ stdcall GetPackageFullName(long ptr ptr) kernelbase.GetPackageFullName @ stdcall -import GetPhysicallyInstalledSystemMemory(ptr) diff --git a/dlls/kernel32/tests/version.c b/dlls/kernel32/tests/version.c index 1c280d2b2eb..27c8ea04b76 100644 --- a/dlls/kernel32/tests/version.c +++ b/dlls/kernel32/tests/version.c @@ -23,6 +23,7 @@ #include "winternl.h" #include "appmodel.h" +static LONG (WINAPI * pGetPackagesByPackageFamily)(const WCHAR *, UINT32 *, WCHAR **, UINT32 *, WCHAR *); static BOOL (WINAPI * pGetProductInfo)(DWORD, DWORD, DWORD, DWORD, DWORD *); static UINT (WINAPI * pGetSystemFirmwareTable)(DWORD, DWORD, void *, DWORD); static LONG (WINAPI * pPackageIdFromFullName)(const WCHAR *, UINT32, UINT32 *, BYTE *); @@ -43,6 +44,7 @@ static void init_function_pointers(void) hmod = GetModuleHandleA("kernel32.dll"); + GET_PROC(GetPackagesByPackageFamily); GET_PROC(GetProductInfo); GET_PROC(GetSystemFirmwareTable); GET_PROC(PackageIdFromFullName); @@ -1075,6 +1077,135 @@ static void test_pe_os_version(void) } } + +static void test_package_info(void) +{ + static const WCHAR package_family_msvc140[] = L"Microsoft.VCLibs.140.00_8wekyb3d8bbwe"; + UINT32 count, length, curr_length, size; + WCHAR *full_names[32]; + BYTE id_buffer[512]; + WCHAR buffer[2048]; + BOOL arch_found; + SYSTEM_INFO si; + unsigned int i; + PACKAGE_ID *id; + DWORD arch; + LONG ret; + + if (!pGetPackagesByPackageFamily) + { + win_skip("GetPackagesByPackageFamily not available.\n"); + return; + } + + GetSystemInfo(&si); + arch = si.wProcessorArchitecture; + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(L"Unknown_8wekyb3d8bbwe", &count, NULL, &length, NULL); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + ok(!length, "Got unexpected length %u.\n", length); + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(L"Unknown_iekyb3d8bbwe", &count, NULL, &length, NULL); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + ok(!length, "Got unexpected length %u.\n", length); + + count = 0xdeadbeef; + length = 0xdeadbeef; + ret = pGetPackagesByPackageFamily(L"Unknown", &count, NULL, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(count == 0xdeadbeef, "Got unexpected count %u.\n", count); + ok(length == 0xdeadbeef, "Got unexpected length %u.\n", length); + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(L"Unknown", &count, NULL, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + ok(!length, "Got unexpected length %u.\n", length); + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(L"Unknown_8wekyb3d8bbwe_b", &count, NULL, &length, NULL); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + ok(!length, "Got unexpected length %u.\n", length); + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(L"Unknown_", &count, NULL, &length, NULL); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + ok(!length, "Got unexpected length %u.\n", length); + + length = 0; + ret = pGetPackagesByPackageFamily(package_family_msvc140, NULL, NULL, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(!length, "Got unexpected length %u.\n", length); + + count = 0; + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(!count, "Got unexpected count %u.\n", count); + + count = ARRAY_SIZE(full_names); + length = ARRAY_SIZE(buffer); + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(count == ARRAY_SIZE(full_names), "Got unexpected count %u.\n", count); + ok(length == ARRAY_SIZE(buffer), "Got unexpected length %u.\n", length); + + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, full_names, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(count == ARRAY_SIZE(full_names), "Got unexpected count %u.\n", count); + ok(length == ARRAY_SIZE(buffer), "Got unexpected length %u.\n", length); + + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, &length, buffer); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + ok(count == ARRAY_SIZE(full_names), "Got unexpected count %u.\n", count); + ok(length == ARRAY_SIZE(buffer), "Got unexpected length %u.\n", length); + + count = 0; + length = 0; + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, &length, NULL); + if (!ret && !count && !length) + { + win_skip("Package VCLibs.140.00 is not installed.\n"); + return; + } + + ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %u.\n", ret); + ok(count >= 1, "Got unexpected count %u.\n", count); + ok(length > 1, "Got unexpected length %u.\n", length); + + ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, full_names, &length, buffer); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(count >= 1, "Got unexpected count %u.\n", count); + ok(length > 1, "Got unexpected length %u.\n", length); + + id = (PACKAGE_ID *)id_buffer; + curr_length = 0; + arch_found = FALSE; + for (i = 0; i < count; ++i) + { + curr_length += lstrlenW(full_names[i]) + 1; + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(full_names[i], 0, &size, id_buffer); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + + if (id->processorArchitecture == arch) + arch_found = TRUE; + } + ok(curr_length == length, "Got unexpected length %u.\n", length); + ok(arch_found, "Did not find package for current arch.\n"); +} + START_TEST(version) { char **argv; @@ -1102,4 +1233,5 @@ START_TEST(version) test_pe_os_version(); test_GetSystemFirmwareTable(); test_PackageIdFromFullName(); + test_package_info(); } diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index 95d4b64d76e..33139abc0d9 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -643,7 +643,7 @@ # @ stub GetPackageStatusForUser # @ stub GetPackageTargetPlatformProperty # @ stub GetPackageVolumeSisPath -# @ stub GetPackagesByPackageFamily +@ stdcall GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) @ stdcall GetPerformanceInfo(ptr long) @ stdcall GetPhysicallyInstalledSystemMemory(ptr) # @ stub GetPreviousFgPolicyRefreshInfoInternal diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c index 4d5a8a4de93..7eb7781738c 100644 --- a/dlls/kernelbase/version.c +++ b/dlls/kernelbase/version.c @@ -39,10 +39,12 @@ #include "winnls.h" #include "winternl.h" #include "winerror.h" +#include "winreg.h" #include "appmodel.h" #include "kernelbase.h" #include "wine/debug.h" +#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(ver); @@ -161,6 +163,8 @@ static const struct } }; +static const WCHAR packages_key_name[] = L"Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows" + L"\\CurrentVersion\\AppModel\\PackageRepository\\Packages"; /****************************************************************************** * init_current_version @@ -1718,3 +1722,114 @@ LONG WINAPI PackageIdFromFullName(const WCHAR *full_name, UINT32 flags, UINT32 * return ERROR_SUCCESS; } + + +/*********************************************************************** + * GetPackagesByPackageFamily (kernelbase.@) + */ +LONG WINAPI GetPackagesByPackageFamily(const WCHAR *family_name, UINT32 *count, WCHAR **full_names, + UINT32 *buffer_length, WCHAR *buffer) +{ + UINT32 curr_count, curr_length, package_id_buf_size, size; + unsigned int i, name_len, publisher_id_len; + DWORD subkey_count, max_key_len, length; + const WCHAR *publisher_id; + WCHAR *package_name; + BOOL short_buffer; + PACKAGE_ID *id; + HKEY key; + + TRACE("family_name %s, count %p, full_names %p, buffer_length %p, buffer %p.\n", + debugstr_w(family_name), count, full_names, buffer_length, buffer); + + if (!buffer_length || !count || !family_name) + return ERROR_INVALID_PARAMETER; + + if ((*buffer_length || *count) && (!full_names || !buffer)) + return ERROR_INVALID_PARAMETER; + + if (!(publisher_id = wcschr(family_name, L'_'))) + return ERROR_INVALID_PARAMETER; + + name_len = publisher_id - family_name; + ++publisher_id; + publisher_id_len = lstrlenW(publisher_id); + + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, packages_key_name, 0, KEY_READ, &key)) + { + ERR("Key open failed.\n"); + *count = 0; + *buffer_length = 0; + return ERROR_SUCCESS; + } + if (RegQueryInfoKeyW(key, NULL, NULL, NULL, &subkey_count, &max_key_len, NULL, NULL, NULL, NULL, NULL, NULL)) + { + ERR("Query key info failed.\n"); + RegCloseKey(key); + *count = 0; + *buffer_length = 0; + return ERROR_SUCCESS; + } + + if (!(package_name = heap_alloc((max_key_len + 1) * sizeof(*package_name)))) + { + ERR("No memory.\n"); + RegCloseKey(key); + return ERROR_OUTOFMEMORY; + } + + package_id_buf_size = sizeof(*id) + (max_key_len + 1) * sizeof(WCHAR); + if (!(id = heap_alloc(package_id_buf_size))) + { + ERR("No memory.\n"); + heap_free(package_name); + RegCloseKey(key); + return ERROR_OUTOFMEMORY; + } + + curr_count = curr_length = 0; + for (i = 0; i < subkey_count; ++i) + { + length = max_key_len + 1; + if (RegEnumKeyExW(key, i, package_name, &length, NULL, NULL, NULL, NULL)) + { + ERR("Error enumerating key %u.\n", i); + continue; + } + + size = package_id_buf_size; + if (PackageIdFromFullName(package_name, 0, &size, (BYTE *)id)) + { + ERR("Error getting package id from full name.\n"); + continue; + } + + if (lstrlenW(id->name) != name_len) + continue; + if (wcsnicmp(family_name, id->name, name_len)) + continue; + + if (lstrlenW(id->publisherId) != publisher_id_len) + continue; + if (wcsnicmp(publisher_id, id->publisherId, publisher_id_len)) + continue; + if (curr_length + length < *buffer_length) + { + memcpy(buffer + curr_length, package_name, (length + 1) * sizeof(*package_name)); + if (curr_count < *count) + full_names[curr_count] = buffer + curr_length; + } + curr_length += length + 1; + ++curr_count; + } + + heap_free(id); + heap_free(package_name); + RegCloseKey(key); + + short_buffer = curr_length > *buffer_length || curr_count > *count; + *count = curr_count; + *buffer_length = curr_length; + + return short_buffer ? ERROR_INSUFFICIENT_BUFFER : ERROR_SUCCESS; +} diff --git a/include/appmodel.h b/include/appmodel.h index 8c219e8080a..1e7eb88a43b 100644 --- a/include/appmodel.h +++ b/include/appmodel.h @@ -89,6 +89,8 @@ LONG WINAPI AppPolicyGetProcessTerminationMethod(HANDLE token, AppPolicyProcessT LONG WINAPI AppPolicyGetShowDeveloperDiagnostic(HANDLE token, AppPolicyShowDeveloperDiagnostic *policy); LONG WINAPI AppPolicyGetThreadInitializationType(HANDLE token, AppPolicyThreadInitializationType *policy); LONG WINAPI AppPolicyGetWindowingModel(HANDLE processToken, AppPolicyWindowingModel *policy); +LONG WINAPI GetPackagesByPackageFamily(const WCHAR *family_name, UINT32 *count, WCHAR **full_names, + UINT32 *buffer_length, WCHAR *buffer); LONG WINAPI PackageIdFromFullName(const WCHAR *full_name, UINT32 flags, UINT32 *buffer_length, BYTE *buffer); #if defined(__cplusplus) From 64fe880c7ae0e56576bd296c9d2b8c51064d1feb Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 26 Mar 2021 01:10:08 +0300 Subject: [PATCH 0497/2777] kernel32: Implement PackageFullNameFromId(). For Forza Horizon 4. --- dlls/kernel32/kernel32.spec | 1 + dlls/kernel32/tests/version.c | 22 ++++++++++++++++- dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/version.c | 43 +++++++++++++++++++++++++++++++++ include/appmodel.h | 1 + 5 files changed, 67 insertions(+), 2 deletions(-) diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 9f928274b0c..3164ca83a2c 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -1157,6 +1157,7 @@ @ stdcall -import PeekConsoleInputW(ptr ptr long ptr) @ stdcall -import PeekNamedPipe(long ptr long ptr ptr ptr) @ stdcall -import PostQueuedCompletionStatus(long long ptr ptr) +@ stdcall -import PackageFullNameFromId(ptr ptr ptr) @ stdcall -import PackageIdFromFullName(wstr long ptr ptr) @ stdcall PowerClearRequest(long long) @ stdcall PowerCreateRequest(ptr) diff --git a/dlls/kernel32/tests/version.c b/dlls/kernel32/tests/version.c index 27c8ea04b76..799ad475fb9 100644 --- a/dlls/kernel32/tests/version.c +++ b/dlls/kernel32/tests/version.c @@ -26,6 +26,7 @@ static LONG (WINAPI * pGetPackagesByPackageFamily)(const WCHAR *, UINT32 *, WCHAR **, UINT32 *, WCHAR *); static BOOL (WINAPI * pGetProductInfo)(DWORD, DWORD, DWORD, DWORD, DWORD *); static UINT (WINAPI * pGetSystemFirmwareTable)(DWORD, DWORD, void *, DWORD); +static LONG (WINAPI * pPackageFullNameFromId)(const PACKAGE_ID *, UINT32 *, WCHAR *); static LONG (WINAPI * pPackageIdFromFullName)(const WCHAR *, UINT32, UINT32 *, BYTE *); static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, void *, ULONG, ULONG *); static NTSTATUS (WINAPI * pRtlGetVersion)(RTL_OSVERSIONINFOEXW *); @@ -47,6 +48,7 @@ static void init_function_pointers(void) GET_PROC(GetPackagesByPackageFamily); GET_PROC(GetProductInfo); GET_PROC(GetSystemFirmwareTable); + GET_PROC(PackageFullNameFromId); GET_PROC(PackageIdFromFullName); hmod = GetModuleHandleA("ntdll.dll"); @@ -803,9 +805,11 @@ static void test_PackageIdFromFullName(void) { 0, PROCESSOR_ARCHITECTURE_INTEL, {{.Major = 1, .Minor = 2, .Build = 3, .Revision = 4}}, - (WCHAR *)L"TestPackage", NULL, + (WCHAR *)L"TestPackage", (WCHAR *)L"TestResource", (WCHAR *)L"TestResourceId", (WCHAR *)L"0abcdefghjkme" }; + static const WCHAR test_package_fullname[] = + L"TestPackage_1.2.3.4_x86_TestResourceId_0abcdefghjkme"; UINT32 size, expected_size; PACKAGE_ID test_id; WCHAR fullname[512]; @@ -918,6 +922,22 @@ static void test_PackageIdFromFullName(void) size = sizeof(id_buffer); ret = pPackageIdFromFullName(L"TestPackage_1.2.3.4_X86_0abcdefghjkme", 0, &size, id_buffer); ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + + ret = pPackageFullNameFromId(&test_package_id, NULL, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + size = sizeof(fullname); + ret = pPackageFullNameFromId(&test_package_id, &size, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + size = 0; + ret = pPackageFullNameFromId(&test_package_id, &size, NULL); + ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %u.\n", ret); + ok(size == lstrlenW(test_package_fullname) + 1, "Got unexpected size %u.\n", size); + + ret = pPackageFullNameFromId(&test_package_id, &size, fullname); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(!lstrcmpW(fullname, test_package_fullname), "Got unexpected fullname %s.\n", debugstr_w(fullname)); } #define TEST_VERSION_WIN7 1 diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index 33139abc0d9..b39b4dd5732 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -1043,7 +1043,7 @@ # @ stub PackageFamilyNameFromFullName # @ stub PackageFamilyNameFromId # @ stub PackageFamilyNameFromProductId -# @ stub PackageFullNameFromId +@ stdcall PackageFullNameFromId(ptr ptr ptr) # @ stub PackageFullNameFromProductId @ stdcall PackageIdFromFullName(wstr long ptr ptr) # @ stub PackageIdFromProductId diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c index 7eb7781738c..ac3aa4b9bd2 100644 --- a/dlls/kernelbase/version.c +++ b/dlls/kernelbase/version.c @@ -1634,6 +1634,16 @@ static UINT32 processor_arch_from_string(const WCHAR *str, unsigned int len) return ~0u; } +const WCHAR *string_from_processor_arch(UINT32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(arch_names); ++i) + if (code == arch_names[i].code) + return arch_names[i].name; + return NULL; +} + /*********************************************************************** * PackageIdFromFullName (kernelbase.@) */ @@ -1724,6 +1734,39 @@ LONG WINAPI PackageIdFromFullName(const WCHAR *full_name, UINT32 flags, UINT32 * } +/*********************************************************************** + * PackageFullNameFromId (kernelbase.@) + */ +LONG WINAPI PackageFullNameFromId(const PACKAGE_ID *package_id, UINT32 *length, WCHAR *full_name) +{ + WCHAR ver_str[5 * 4 + 3 + 1]; + const WCHAR *arch_str; + UINT32 have_length; + + TRACE("package_id %p, length %p, full_name %p.\n", package_id, length, full_name); + + if (!package_id || !length) + return ERROR_INVALID_PARAMETER; + if (!full_name && *length) + return ERROR_INVALID_PARAMETER; + if (!package_id->name || !package_id->resourceId || !package_id->publisherId + || !(arch_str = string_from_processor_arch(package_id->processorArchitecture))) + return ERROR_INVALID_PARAMETER; + + swprintf(ver_str, ARRAY_SIZE(ver_str), L"%u.%u.%u.%u", package_id->version.u.s.Major, + package_id->version.u.s.Minor, package_id->version.u.s.Build, package_id->version.u.s.Revision); + have_length = *length; + *length = lstrlenW(package_id->name) + 1 + lstrlenW(ver_str) + 1 + lstrlenW(arch_str) + 1 + + lstrlenW(package_id->resourceId) + 1 + lstrlenW(package_id->publisherId) + 1; + + if (have_length < *length) + return ERROR_INSUFFICIENT_BUFFER; + + swprintf(full_name, *length, L"%s_%s_%s_%s_%s", package_id->name, ver_str, arch_str, package_id->resourceId, package_id->publisherId); + return ERROR_SUCCESS; +} + + /*********************************************************************** * GetPackagesByPackageFamily (kernelbase.@) */ diff --git a/include/appmodel.h b/include/appmodel.h index 1e7eb88a43b..c3a42567a42 100644 --- a/include/appmodel.h +++ b/include/appmodel.h @@ -91,6 +91,7 @@ LONG WINAPI AppPolicyGetThreadInitializationType(HANDLE token, AppPolicyThreadIn LONG WINAPI AppPolicyGetWindowingModel(HANDLE processToken, AppPolicyWindowingModel *policy); LONG WINAPI GetPackagesByPackageFamily(const WCHAR *family_name, UINT32 *count, WCHAR **full_names, UINT32 *buffer_length, WCHAR *buffer); +LONG WINAPI PackageFullNameFromId(const PACKAGE_ID *package_id, UINT32 *length, WCHAR *full_name); LONG WINAPI PackageIdFromFullName(const WCHAR *full_name, UINT32 flags, UINT32 *buffer_length, BYTE *buffer); #if defined(__cplusplus) From eac6e91d7cf5c4a065fe6d21fd7539277150c68f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 15 Mar 2021 22:05:19 +0300 Subject: [PATCH 0498/2777] kernel32: Implement GetPackagePath(). For Forza Horizon 4. --- dlls/kernel32/kernel32.spec | 1 + dlls/kernel32/tests/version.c | 64 +++++++++++++++++++++++-- dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/version.c | 82 +++++++++++++++++++++++++++++++++ include/appmodel.h | 1 + 5 files changed, 144 insertions(+), 6 deletions(-) diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 3164ca83a2c..1a4976c2638 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -771,6 +771,7 @@ @ stdcall -import GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) @ stdcall GetPackageFamilyName(long ptr ptr) kernelbase.GetPackageFamilyName @ stdcall GetPackageFullName(long ptr ptr) kernelbase.GetPackageFullName +@ stdcall -import GetPackagePath(ptr long ptr ptr) @ stdcall -import GetPhysicallyInstalledSystemMemory(ptr) @ stdcall -import GetPriorityClass(long) @ stdcall GetPrivateProfileIntA(str str long str) diff --git a/dlls/kernel32/tests/version.c b/dlls/kernel32/tests/version.c index 799ad475fb9..1db7053ea3b 100644 --- a/dlls/kernel32/tests/version.c +++ b/dlls/kernel32/tests/version.c @@ -23,6 +23,7 @@ #include "winternl.h" #include "appmodel.h" +static LONG (WINAPI * pGetPackagePath)(const PACKAGE_ID *, const UINT32, UINT32 *, WCHAR *); static LONG (WINAPI * pGetPackagesByPackageFamily)(const WCHAR *, UINT32 *, WCHAR **, UINT32 *, WCHAR *); static BOOL (WINAPI * pGetProductInfo)(DWORD, DWORD, DWORD, DWORD, DWORD *); static UINT (WINAPI * pGetSystemFirmwareTable)(DWORD, DWORD, void *, DWORD); @@ -45,6 +46,7 @@ static void init_function_pointers(void) hmod = GetModuleHandleA("kernel32.dll"); + GET_PROC(GetPackagePath); GET_PROC(GetPackagesByPackageFamily); GET_PROC(GetProductInfo); GET_PROC(GetSystemFirmwareTable); @@ -1101,15 +1103,15 @@ static void test_pe_os_version(void) static void test_package_info(void) { static const WCHAR package_family_msvc140[] = L"Microsoft.VCLibs.140.00_8wekyb3d8bbwe"; - UINT32 count, length, curr_length, size; + UINT32 count, length, curr_length, size, path_length, total_length; + WCHAR buffer[2048], path[MAX_PATH]; + PACKAGE_ID *id, saved_id; WCHAR *full_names[32]; BYTE id_buffer[512]; - WCHAR buffer[2048]; + DWORD arch, attrib; BOOL arch_found; SYSTEM_INFO si; unsigned int i; - PACKAGE_ID *id; - DWORD arch; LONG ret; if (!pGetPackagesByPackageFamily) @@ -1190,6 +1192,10 @@ static void test_package_info(void) ok(count == ARRAY_SIZE(full_names), "Got unexpected count %u.\n", count); ok(length == ARRAY_SIZE(buffer), "Got unexpected length %u.\n", length); + length = 0; + ret = pGetPackagePath(NULL, 0, &length, NULL); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + count = 0; length = 0; ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, &length, NULL); @@ -1208,6 +1214,7 @@ static void test_package_info(void) ok(count >= 1, "Got unexpected count %u.\n", count); ok(length > 1, "Got unexpected length %u.\n", length); + total_length = length; id = (PACKAGE_ID *)id_buffer; curr_length = 0; arch_found = FALSE; @@ -1221,9 +1228,56 @@ static void test_package_info(void) if (id->processorArchitecture == arch) arch_found = TRUE; + + path_length = 0; + ret = pGetPackagePath(id, 0, &path_length, NULL); + ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %u.\n", ret); + ok(path_length > 1, "Got unexpected path_length %u.\n", path_length); + + length = path_length; + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + ok(length == path_length, "Got unexpected length %u.\n", length); + attrib = GetFileAttributesW(path); + ok(attrib != INVALID_FILE_ATTRIBUTES && attrib & FILE_ATTRIBUTE_DIRECTORY, + "Got unexpected attrib %#x, GetLastError() %u.\n", attrib, GetLastError()); } - ok(curr_length == length, "Got unexpected length %u.\n", length); + ok(curr_length == total_length, "Got unexpected length %u.\n", length); ok(arch_found, "Did not find package for current arch.\n"); + + size = sizeof(id_buffer); + ret = pPackageIdFromFullName(full_names[0], 0, &size, id_buffer); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + saved_id = *id; + + id->publisherId = NULL; + length = ARRAY_SIZE(path); + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + *id = saved_id; + id->name = NULL; + length = ARRAY_SIZE(path); + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + *id = saved_id; + id->publisher = NULL; + length = ARRAY_SIZE(path); + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); + + *id = saved_id; + id->processorArchitecture = ~0u; + length = ARRAY_SIZE(path); + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); + + *id = saved_id; + id->name[0] = L'X'; + length = ARRAY_SIZE(path); + ret = pGetPackagePath(id, 0, &length, path); + ok(ret == ERROR_NOT_FOUND, "Got unexpected ret %u.\n", ret); } START_TEST(version) diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index b39b4dd5732..e77cdf1543e 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -630,7 +630,7 @@ # @ stub GetPackageInfo # @ stub GetPackageInstallTime # @ stub GetPackageOSMaxVersionTested -# @ stub GetPackagePath +@ stdcall GetPackagePath(ptr long ptr ptr) # @ stub GetPackagePathByFullName # @ stub GetPackagePathOnVolume # @ stub GetPackageProperty diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c index ac3aa4b9bd2..0a7cdcf6fa0 100644 --- a/dlls/kernelbase/version.c +++ b/dlls/kernelbase/version.c @@ -1876,3 +1876,85 @@ LONG WINAPI GetPackagesByPackageFamily(const WCHAR *family_name, UINT32 *count, return short_buffer ? ERROR_INSUFFICIENT_BUFFER : ERROR_SUCCESS; } + + +/*********************************************************************** + * GetPackagePath (kernelbase.@) + */ +LONG WINAPI GetPackagePath(const PACKAGE_ID *package_id, const UINT32 reserved, UINT32 *length, WCHAR *path) +{ + WCHAR *key_name = NULL, *expanded_path = NULL; + UINT32 required_length, have_length; + unsigned int offset; + HKEY key = NULL; + DWORD size; + LONG ret; + + TRACE("package_id %p, reserved %u, length %p, path %p.\n", package_id, reserved, length, path); + + if (!length) + return ERROR_INVALID_PARAMETER; + if (!path && *length) + return ERROR_INVALID_PARAMETER; + + required_length = 0; + if ((ret = PackageFullNameFromId(package_id, &required_length, NULL)) != ERROR_INSUFFICIENT_BUFFER) + return ret; + + offset = lstrlenW(packages_key_name) + 1; + if (!(key_name = heap_alloc((offset + required_length) * sizeof(WCHAR)))) + { + ERR("No memory."); + return ERROR_OUTOFMEMORY; + } + + if ((ret = PackageFullNameFromId(package_id, &required_length, key_name + offset))) + goto done; + + memcpy(key_name, packages_key_name, (offset - 1) * sizeof(WCHAR)); + key_name[offset - 1] = L'\\'; + + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, key_name, 0, KEY_READ, &key)) + { + WARN("Key %s not found.\n", debugstr_w(key_name)); + ret = ERROR_NOT_FOUND; + goto done; + } + if (RegGetValueW(key, NULL, L"Path", RRF_RT_REG_SZ, NULL, NULL, &size)) + { + WARN("Path value not found in %s.\n", debugstr_w(key_name)); + ret = ERROR_NOT_FOUND; + goto done; + } + if (!(expanded_path = heap_alloc(size))) + { + ERR("No memory."); + ret = ERROR_OUTOFMEMORY; + goto done; + } + if (RegGetValueW(key, NULL, L"Path", RRF_RT_REG_SZ, NULL, expanded_path, &size)) + { + WARN("Could not get Path value from %s.\n", debugstr_w(key_name)); + ret = ERROR_NOT_FOUND; + goto done; + } + + have_length = *length; + *length = lstrlenW(expanded_path) + 1; + if (have_length >= *length) + { + memcpy(path, expanded_path, *length * sizeof(*path)); + ret = ERROR_SUCCESS; + } + else + { + ret = ERROR_INSUFFICIENT_BUFFER; + } + +done: + if (key) + RegCloseKey(key); + heap_free(expanded_path); + heap_free(key_name); + return ret; +} diff --git a/include/appmodel.h b/include/appmodel.h index c3a42567a42..cab001f60c7 100644 --- a/include/appmodel.h +++ b/include/appmodel.h @@ -89,6 +89,7 @@ LONG WINAPI AppPolicyGetProcessTerminationMethod(HANDLE token, AppPolicyProcessT LONG WINAPI AppPolicyGetShowDeveloperDiagnostic(HANDLE token, AppPolicyShowDeveloperDiagnostic *policy); LONG WINAPI AppPolicyGetThreadInitializationType(HANDLE token, AppPolicyThreadInitializationType *policy); LONG WINAPI AppPolicyGetWindowingModel(HANDLE processToken, AppPolicyWindowingModel *policy); +LONG WINAPI GetPackagePath(const PACKAGE_ID *package_id, const UINT32 reserved, UINT32 *length, WCHAR *path); LONG WINAPI GetPackagesByPackageFamily(const WCHAR *family_name, UINT32 *count, WCHAR **full_names, UINT32 *buffer_length, WCHAR *buffer); LONG WINAPI PackageFullNameFromId(const PACKAGE_ID *package_id, UINT32 *length, WCHAR *full_name); From 6aff435957706a2ff2286f8bb0ba00bea8c2f0a2 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 27 Sep 2022 11:30:06 -0500 Subject: [PATCH 0499/2777] kernelbase: HACK: Do not expose version info for builtin DLLs for VC redists. So VC Runtime 2013 redist actually installs the libraries. CW-Bug-Id: #21343 --- dlls/kernelbase/version.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c index 0a7cdcf6fa0..874798ff17d 100644 --- a/dlls/kernelbase/version.c +++ b/dlls/kernelbase/version.c @@ -782,6 +782,27 @@ DWORD WINAPI GetFileVersionInfoSizeExW( DWORD flags, LPCWSTR filename, LPDWORD r if ((hModule = LoadLibraryExW( filename, 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE ))) { HRSRC hRsrc = NULL; + + static const char builtin_signature[] = "Wine builtin DLL"; + HMODULE mod = (HMODULE)((ULONG_PTR)hModule & ~(ULONG_PTR)3); + char *signature = (char *)((IMAGE_DOS_HEADER *)mod + 1); + WCHAR exe_name[MAX_PATH]; + IMAGE_NT_HEADERS *nt; + DWORD exe_name_len; + + if ((exe_name_len = GetModuleFileNameW( NULL, exe_name, ARRAY_SIZE(exe_name) )) + && exe_name_len >= 16 + && (!memcmp( exe_name + exe_name_len - 16, L"vcredist_x64.exe", 16 * sizeof(*exe_name) ) + || !memcmp( exe_name + exe_name_len - 16, L"vcredist_x86.exe", 16 * sizeof(*exe_name) )) + && (nt = RtlImageNtHeader( mod )) && (char *)nt - signature >= sizeof(builtin_signature) + && !memcmp( signature, builtin_signature, sizeof(builtin_signature) )) + { + ERR("HACK: not exposing version info.\n"); + FreeLibrary( hModule ); + SetLastError( ERROR_RESOURCE_NAME_NOT_FOUND ); + return 0; + } + if (!(flags & FILE_VER_GET_LOCALISED)) { LANGID english = MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT ); From 820cfbc8c7b6dfa941396a68c857a519d3150f18 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 30 Jul 2021 21:01:13 +0300 Subject: [PATCH 0500/2777] kernelbase: HACK: Force CEF software rendering for UplayWebCore. Work around Uplay crash. (To be revisited once builtin d3dcompiler is added). --- dlls/kernelbase/process.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 6ea1d3f53c2..5498604a135 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -34,6 +34,7 @@ #include "kernelbase.h" #include "wine/debug.h" #include "wine/condrv.h" +#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(process); @@ -529,7 +530,31 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR } else { - if (!(tidy_cmdline = get_file_name( cmd_line, name, ARRAY_SIZE(name) ))) return FALSE; + static const WCHAR *opt = L" --use-gl=swiftshader"; + WCHAR *cmdline_new = NULL; + + if (cmd_line && wcsstr( cmd_line, L"UplayWebCore.exe" )) + { + FIXME( "HACK: appending %s to command line %s.\n", debugstr_w(opt), debugstr_w(cmd_line) ); + + cmdline_new = heap_alloc( sizeof(WCHAR) * (lstrlenW(cmd_line) + lstrlenW(opt) + 1) ); + lstrcpyW(cmdline_new, cmd_line); + lstrcatW(cmdline_new, opt); + } + + tidy_cmdline = get_file_name( cmdline_new ? cmdline_new : cmd_line, name, ARRAY_SIZE(name) ); + + if (!tidy_cmdline) + { + heap_free( cmdline_new ); + return FALSE; + } + + if (cmdline_new) + { + if (cmdline_new == tidy_cmdline) cmd_line = NULL; + else heap_free( cmdline_new ); + } app_name = name; } From 208608ad6b64c3e966860ab0273c251a85417616 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 26 Jul 2021 17:36:04 +0300 Subject: [PATCH 0501/2777] kernel32: Align stack pointer for lstrcpyA() on x64. For Blood of Steel crash on launch. CW-Bug-Id: #19148 --- dlls/kernel32/virtual.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/dlls/kernel32/virtual.c b/dlls/kernel32/virtual.c index f5693de4e28..800c25d34cd 100644 --- a/dlls/kernel32/virtual.c +++ b/dlls/kernel32/virtual.c @@ -36,6 +36,7 @@ #include "psapi.h" #include "wine/exception.h" #include "wine/debug.h" +#include "wine/asm.h" #include "kernel_private.h" @@ -294,7 +295,8 @@ LPWSTR WINAPI lstrcatW( LPWSTR dst, LPCWSTR src ) * lstrcpyA (KERNEL32.@) * lstrcpy (KERNEL32.@) */ -LPSTR WINAPI lstrcpyA( LPSTR dst, LPCSTR src ) +#ifdef __x86_64__ +LPSTR WINAPI lstrcpyA_impl( LPSTR dst, LPCSTR src ) { __TRY { @@ -310,6 +312,42 @@ LPSTR WINAPI lstrcpyA( LPSTR dst, LPCSTR src ) return dst; } +__ASM_GLOBAL_FUNC( lstrcpyA, + ".byte 0x48, 0x8d, 0xa4, 0x24, 0x00, 0x00, 0x00, 0x00\n\t" + "pushq %rbp\n\t" + __ASM_SEH(".seh_pushreg %rbp\n\t") + __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t") + __ASM_CFI(".cfi_rel_offset %rbp,0\n\t") + "movq %rsp,%rbp\n\t" + __ASM_SEH(".seh_setframe %rbp,0\n\t") + __ASM_CFI(".cfi_def_cfa_register %rbp\n\t") + __ASM_SEH(".seh_endprologue\n\t") + "subq $0x20,%rsp\n\t" + "andq $~15,%rsp\n\t" + "call " __ASM_NAME("lstrcpyA_impl") "\n\t" + "leaq 0(%rbp),%rsp\n\t" + __ASM_CFI(".cfi_def_cfa_register %rsp\n\t") + "popq %rbp\n\t" + __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t") + __ASM_CFI(".cfi_same_value %rbp\n\t") + "ret" ) +#else /* __x86_64__ */ +LPSTR WINAPI lstrcpyA( LPSTR dst, LPCSTR src ) +{ + __TRY + { + /* this is how Windows does it */ + memmove( dst, src, strlen(src)+1 ); + } + __EXCEPT( badptr_handler ) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return NULL; + } + __ENDTRY + return dst; +} +#endif /*********************************************************************** * lstrcpyW (KERNEL32.@) From bcb3038e71ab9690a17fa0398c219d379c26cc0c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 14 Jul 2021 20:45:38 +0300 Subject: [PATCH 0502/2777] ntdll: Add stub implementation for NtSetInformationFile(FileAllocationInformation). CW-Bug-Id: #19085 --- dlls/ntdll/unix/file.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 5f617418a4c..cd3b1ed97be 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4616,6 +4616,15 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, else status = STATUS_INVALID_PARAMETER_3; break; + case FileAllocationInformation: + { + const FILE_ALLOCATION_INFORMATION *info = ptr; + + FIXME("FileAllocationInformation AllocationSize %p stub.\n", (void *)(ULONG_PTR)info->AllocationSize.QuadPart); + io->u.Status = STATUS_SUCCESS; + break; + } + case FilePipeInformation: if (len >= sizeof(FILE_PIPE_INFORMATION)) { From 8e1c957bb472573ea3ee197d66fc501f6ecdf1a4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 14 Jul 2021 20:43:39 +0300 Subject: [PATCH 0503/2777] ntdll: Support '\??\GlobalRoot' prefix in get_dos_prefix_len(). CW-Bug-Id: #19085 --- dlls/ntdll/unix/file.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index cd3b1ed97be..281736fdd47 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -3087,16 +3087,31 @@ static inline int get_dos_prefix_len( const UNICODE_STRING *name ) { static const WCHAR nt_prefixW[] = {'\\','?','?','\\'}; static const WCHAR dosdev_prefixW[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\'}; + static const WCHAR globalrootW[] = {'\\','?','?','\\','G','l','o','b','a','l','R','o','o','t'}; + int prefix_len = 0; + WCHAR *prefix; + USHORT length; - if (name->Length >= sizeof(nt_prefixW) && - !memcmp( name->Buffer, nt_prefixW, sizeof(nt_prefixW) )) - return ARRAY_SIZE( nt_prefixW ); + prefix = name->Buffer; + length = name->Length; - if (name->Length >= sizeof(dosdev_prefixW) && - !wcsnicmp( name->Buffer, dosdev_prefixW, ARRAY_SIZE( dosdev_prefixW ))) - return ARRAY_SIZE( dosdev_prefixW ); + if (length >= ARRAY_SIZE( globalrootW ) && + !wcsnicmp( prefix, globalrootW, ARRAY_SIZE( globalrootW ))) + { + WARN("Stripping off GlobalRoot prefix.\n"); + prefix += ARRAY_SIZE( globalrootW ); + prefix_len += ARRAY_SIZE( globalrootW ); + length -= ARRAY_SIZE( globalrootW ); + } - return 0; + if (length >= sizeof(nt_prefixW) && + !memcmp( prefix, nt_prefixW, sizeof(nt_prefixW) )) + prefix_len += ARRAY_SIZE( nt_prefixW ); + else if (length >= sizeof(dosdev_prefixW) && + !wcsnicmp( prefix, dosdev_prefixW, ARRAY_SIZE( dosdev_prefixW ))) + prefix_len += ARRAY_SIZE( dosdev_prefixW ); + + return prefix_len; } From d5fdc49f531febe5fe3f59b9d2e28e6686a580ea Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 16 Sep 2021 18:01:42 +0300 Subject: [PATCH 0504/2777] kernelbase: Return an error from InitializeProcessForWsWatch() stub. CW-Bug-Id: #19445 For DeathLoop. --- dlls/kernelbase/debug.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/kernelbase/debug.c b/dlls/kernelbase/debug.c index cd8e0d7f87d..378531acc62 100644 --- a/dlls/kernelbase/debug.c +++ b/dlls/kernelbase/debug.c @@ -1502,7 +1502,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetWsChangesEx( HANDLE process, PSAPI_WS_WATCH_INF BOOL WINAPI /* DECLSPEC_HOTPATCH */ InitializeProcessForWsWatch( HANDLE process ) { FIXME( "(process=%p): stub\n", process ); - return TRUE; + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; } From 0d08f505a3d8b05aff48518dfe60d6af7a984f24 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 19 Nov 2021 16:30:57 +0300 Subject: [PATCH 0505/2777] kernelbase: HACK: Force CEF in process GPU rendering for Paradox launcher. To be removed once other process Vulkan rendering is implemented. CW-Bug-Id: #19617 Signed-off-by: Paul Gofman --- dlls/kernelbase/process.c | 49 ++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 5498604a135..8c7e8c9f62a 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -494,6 +494,33 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalA( HANDLE token, const char * return ret; } +static const WCHAR *hack_append_command_line( const WCHAR *cmd ) +{ + static const struct + { + const WCHAR *exe_name; + const WCHAR *append; + } + options[] = + { + {L"UplayWebCore.exe", L" --use-gl=swiftshader"}, + {L"Paradox Launcher.exe", L" --use-gl=swiftshader --in-process-gpu"}, + }; + unsigned int i; + + if (!cmd) return NULL; + + for (i = 0; i < ARRAY_SIZE(options); ++i) + { + if (wcsstr( cmd, options[i].exe_name )) + { + FIXME( "HACK: appending %s to command line.\n", debugstr_w(options[i].append) ); + return options[i].append; + } + } + return NULL; +} + /********************************************************************** * CreateProcessInternalW (kernelbase.@) */ @@ -510,6 +537,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR RTL_USER_PROCESS_PARAMETERS *params = NULL; RTL_USER_PROCESS_INFORMATION rtl_info; HANDLE parent = 0, debug = 0; + const WCHAR *append; ULONG nt_flags = 0; NTSTATUS status; @@ -527,33 +555,38 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR return FALSE; swprintf( tidy_cmdline, lstrlenW(app_name) + 3, L"\"%s\"", app_name ); } + else if ((append = hack_append_command_line( app_name ))) + { + tidy_cmdline = RtlAllocateHeap( GetProcessHeap(), 0, + sizeof(WCHAR) * (lstrlenW(cmd_line) + lstrlenW(append) + 1) ); + lstrcpyW(tidy_cmdline, cmd_line); + lstrcatW(tidy_cmdline, append); + } } else { - static const WCHAR *opt = L" --use-gl=swiftshader"; WCHAR *cmdline_new = NULL; - if (cmd_line && wcsstr( cmd_line, L"UplayWebCore.exe" )) + if ((append = hack_append_command_line( cmd_line ))) { - FIXME( "HACK: appending %s to command line %s.\n", debugstr_w(opt), debugstr_w(cmd_line) ); - - cmdline_new = heap_alloc( sizeof(WCHAR) * (lstrlenW(cmd_line) + lstrlenW(opt) + 1) ); + cmdline_new = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(WCHAR) + * (lstrlenW(cmd_line) + lstrlenW(append) + 1) ); lstrcpyW(cmdline_new, cmd_line); - lstrcatW(cmdline_new, opt); + lstrcatW(cmdline_new, append); } tidy_cmdline = get_file_name( cmdline_new ? cmdline_new : cmd_line, name, ARRAY_SIZE(name) ); if (!tidy_cmdline) { - heap_free( cmdline_new ); + HeapFree( GetProcessHeap(), 0, cmdline_new ); return FALSE; } if (cmdline_new) { if (cmdline_new == tidy_cmdline) cmd_line = NULL; - else heap_free( cmdline_new ); + else HeapFree( GetProcessHeap(), 0, cmdline_new ); } app_name = name; } From e3a69ec9b089def18b2be66809106880bd9641db Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 21 Jan 2022 14:42:12 -0500 Subject: [PATCH 0506/2777] kernelbase: Add stub for GetConsoleSelectionInfo. Signed-off-by: Derek Lesho --- dlls/kernel32/kernel32.spec | 2 +- dlls/kernelbase/console.c | 8 ++++++++ dlls/kernelbase/kernelbase.spec | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 1a4976c2638..3260a16d2a5 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -617,7 +617,7 @@ @ stdcall -import GetConsoleProcessList(ptr long) @ stdcall -import GetConsoleScreenBufferInfo(long ptr) @ stdcall -import GetConsoleScreenBufferInfoEx(long ptr) -# @ stub GetConsoleSelectionInfo +@ stdcall -import GetConsoleSelectionInfo(ptr) @ stdcall -import GetConsoleTitleA(ptr long) @ stdcall -import GetConsoleTitleW(ptr long) @ stdcall -import GetConsoleWindow() diff --git a/dlls/kernelbase/console.c b/dlls/kernelbase/console.c index 7cd87f53b3c..38d09d6c60f 100644 --- a/dlls/kernelbase/console.c +++ b/dlls/kernelbase/console.c @@ -1025,6 +1025,14 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetConsoleScreenBufferInfoEx( HANDLE handle, } +BOOL WINAPI DECLSPEC_HOTPATCH GetConsoleSelectionInfo(CONSOLE_SELECTION_INFO *info) +{ + FIXME("stub (%p)\n", info); + info->dwFlags = CONSOLE_NO_SELECTION; + return TRUE; +} + + /****************************************************************************** * GetConsoleTitleA (kernelbase.@) */ diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index e77cdf1543e..92421ec4ceb 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -472,6 +472,7 @@ @ stdcall GetConsoleProcessList(ptr long) @ stdcall GetConsoleScreenBufferInfo(long ptr) @ stdcall GetConsoleScreenBufferInfoEx(long ptr) +@ stdcall GetConsoleSelectionInfo(ptr) @ stdcall GetConsoleTitleA(ptr long) @ stdcall GetConsoleTitleW(ptr long) @ stdcall GetConsoleWindow() From edd4a004a15f26f2b7ddf9edd464b89648b7d4db Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Tue, 30 Mar 2021 21:45:05 -0400 Subject: [PATCH 0507/2777] kernelbase: Redirect BattlEye Launcher process creation to game executable. Signed-off-by: Derek Lesho CW-Bug-Id: #16650 --- dlls/kernelbase/process.c | 200 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 8c7e8c9f62a..c2b04bc76b7 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -28,6 +28,7 @@ #include "windef.h" #include "winbase.h" #include "winnls.h" +#include "winver.h" #include "wincontypes.h" #include "winternl.h" @@ -494,6 +495,197 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalA( HANDLE token, const char * return ret; } +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]; + WCHAR *p; + UINT 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 ); + if (!GetFullPathNameW( full_path, MAX_PATH, full_path, NULL )) lstrcpynW( full_path, app_name, MAX_PATH ); + + /* We detect the BattlEye launcher executable through the product name property, as the executable name varies */ + size = GetFileVersionInfoSizeExW(0, full_path, NULL); + if (!size) + return 0; + + block = HeapAlloc( GetProcessHeap(), 0, size ); + + if (!GetFileVersionInfoExW(0, full_path, 0, size, block)) + { + HeapFree( GetProcessHeap(), 0, block ); + return 0; + } + + if (!VerQueryValueA(block, "\\VarFileInfo\\Translation", (void **) &translation, &size) || size != 4) + { + HeapFree( GetProcessHeap(), 0, block ); + return 0; + } + + sprintf(buf, "\\StringFileInfo\\%08lx\\ProductName", MAKELONG(HIWORD(*translation), LOWORD(*translation))); + + if (!VerQueryValueA(block, buf, (void **) &product_name, &size)) + { + HeapFree( GetProcessHeap(), 0, block ); + return 0; + } + + if (strcmp(product_name, "BattlEye Launcher")) + { + HeapFree( GetProcessHeap(), 0, block); + return 0; + } + + 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, (DWORD *)&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); + + if ((wcslen(app_name) - launcher_exe_len) + game_exe_len + 1 > new_name_len) + { + 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); + + /* find and replace executable name in command line, and add BE argument */ + p = *cmd_line; + if (p[0] == '\"') + 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); + + /* freed by parent function */ + new_cmd_line = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ); + + 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); + } + + 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); + } + + *cmd_line = new_cmd_line; + } + + HeapFree( GetProcessHeap(), 0, configs ); + return 1; +} + static const WCHAR *hack_append_command_line( const WCHAR *cmd ) { static const struct @@ -591,6 +783,14 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR app_name = name; } + p = tidy_cmdline; + if (battleye_launcher_redirect_hack( app_name, name, ARRAY_SIZE(name), &tidy_cmdline )) + { + app_name = name; + if (p != tidy_cmdline && p != cmd_line) + HeapFree( GetProcessHeap(), 0, p ); + } + /* Warn if unsupported features are used */ if (flags & (IDLE_PRIORITY_CLASS | HIGH_PRIORITY_CLASS | REALTIME_PRIORITY_CLASS | From b9df2883adebeb8ecd5859d154febb5f138766ae Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 21 Jan 2022 14:40:43 -0500 Subject: [PATCH 0508/2777] 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 | 118 ++++++++++++++++++++++++++++ 4 files changed, 141 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 84006a06a45..7da4db714c4 100644 --- a/configure.ac +++ b/configure.ac @@ -3321,6 +3321,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/certutil) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index c2b04bc76b7..45107649b3b 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -497,18 +497,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; UINT 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 ); @@ -549,96 +546,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, (DWORD *)&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; @@ -646,43 +562,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..004a7d1a711 --- /dev/null +++ b/programs/belauncher/main.c @@ -0,0 +1,118 @@ +#define WIN32_LEAN_AND_MEAN +#include +#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) arg_len = 0; + else + { + 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 4ea8300c4ec538e738a63cc5b144787a7d936a04 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 26 Mar 2021 10:48:14 -0400 Subject: [PATCH 0509/2777] ntdll: Try to load builtin DLLs from Battleye Runtime directory. Signed-off-by: Derek Lesho CW-Bug-Id: #16650 --- dlls/ntdll/unix/loader.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 9464d0b745c..9fd59ba9a5a 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -532,11 +532,14 @@ static const char *get_pe_dir( WORD machine ) static void set_dll_path(void) { - char *p, *path = getenv( "WINEDLLPATH" ); + char *p, *path = getenv( "WINEDLLPATH" ), *be_runtime = getenv( "PROTON_BATTLEYE_RUNTIME" ); int i, count = 0; if (path) for (p = path, count = 1; *p; p++) if (*p == ':') count++; + if (be_runtime) + count += 2; + dll_paths = malloc( (count + 2) * sizeof(*dll_paths) ); count = 0; @@ -549,6 +552,24 @@ static void set_dll_path(void) free( path ); } + if (be_runtime) + { + const char lib32[] = "/v1/lib/wine/"; + const char lib64[] = "/v1/lib64/wine/"; + + p = malloc( strlen(be_runtime) + strlen(lib32) + 1 ); + strcpy(p, be_runtime); + strcat(p, lib32); + + dll_paths[count++] = p; + + p = malloc( strlen(be_runtime) + strlen(lib64) + 1 ); + strcpy(p, be_runtime); + strcat(p, lib64); + + dll_paths[count++] = p; + } + for (i = 0; i < count; i++) dll_path_maxlen = max( dll_path_maxlen, strlen(dll_paths[i]) ); dll_paths[count] = NULL; } From 53e94f59eb67b069ed0c0af67f0f789c068bc33b Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Mon, 6 Dec 2021 15:13:40 +0100 Subject: [PATCH 0510/2777] ntdll: Load EAC bridge files from PROTON_EAC_RUNTIME path. --- dlls/ntdll/unix/loader.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 9fd59ba9a5a..f916d6732bf 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -532,7 +532,7 @@ static const char *get_pe_dir( WORD machine ) static void set_dll_path(void) { - char *p, *path = getenv( "WINEDLLPATH" ), *be_runtime = getenv( "PROTON_BATTLEYE_RUNTIME" ); + char *p, *path = getenv( "WINEDLLPATH" ), *be_runtime = getenv( "PROTON_BATTLEYE_RUNTIME" ), *eac_runtime = getenv( "PROTON_EAC_RUNTIME" ); int i, count = 0; if (path) for (p = path, count = 1; *p; p++) if (*p == ':') count++; @@ -540,6 +540,9 @@ static void set_dll_path(void) if (be_runtime) count += 2; + if (eac_runtime) + count += 2; + dll_paths = malloc( (count + 2) * sizeof(*dll_paths) ); count = 0; @@ -570,6 +573,24 @@ static void set_dll_path(void) dll_paths[count++] = p; } + if (eac_runtime) + { + const char lib32[] = "/v2/lib32/"; + const char lib64[] = "/v2/lib64/"; + + p = malloc( strlen(eac_runtime) + strlen(lib32) + 1 ); + strcpy(p, eac_runtime); + strcat(p, lib32); + + dll_paths[count++] = p; + + p = malloc( strlen(eac_runtime) + strlen(lib64) + 1 ); + strcpy(p, eac_runtime); + strcat(p, lib64); + + dll_paths[count++] = p; + } + for (i = 0; i < count; i++) dll_path_maxlen = max( dll_path_maxlen, strlen(dll_paths[i]) ); dll_paths[count] = NULL; } From fb2fe09e9e553b5869ec0d86f2181bbc4fb16f12 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Tue, 18 Jan 2022 17:16:15 -0500 Subject: [PATCH 0511/2777] ntdll: Only load EAC bridge when Linux library is present. --- dlls/ntdll/unix/loadorder.c | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/dlls/ntdll/unix/loadorder.c b/dlls/ntdll/unix/loadorder.c index aa987a80186..3d9575d83f2 100644 --- a/dlls/ntdll/unix/loadorder.c +++ b/dlls/ntdll/unix/loadorder.c @@ -378,6 +378,10 @@ void set_load_order_app_name( const WCHAR *app_name ) */ enum loadorder get_load_order( const UNICODE_STRING *nt_name ) { + static const WCHAR easyanticheat_x86W[] = {'e','a','s','y','a','n','t','i','c','h','e','a','t','_','x','8','6','.','d','l','l',0}; + static const WCHAR easyanticheat_x64W[] = {'e','a','s','y','a','n','t','i','c','h','e','a','t','_','x','6','4','.','d','l','l',0}; + static const WCHAR soW[] = {'s','o',0}; + static const WCHAR prefixW[] = {'\\','?','?','\\'}; enum loadorder ret = LO_INVALID; const WCHAR *path = nt_name->Buffer; @@ -391,6 +395,41 @@ enum loadorder get_load_order( const UNICODE_STRING *nt_name ) TRACE("looking for %s\n", debugstr_w(path)); + /* HACK: special logic for easyanticheat bridge: only load the bridge (builtin) if there exists a native version of the library next to the windows version */ + basename = get_basename((WCHAR *)path); + if (!wcsicmp(basename, easyanticheat_x86W) || !wcsicmp(basename, easyanticheat_x64W)) + { + UNICODE_STRING eac_unix_name; + OBJECT_ATTRIBUTES attr; + char *unix_path = NULL; + NTSTATUS status; + + len = wcslen(nt_name->Buffer); + eac_unix_name.Buffer = malloc( (len + 1) * sizeof(WCHAR) ); + wcscpy(eac_unix_name.Buffer, nt_name->Buffer); + + basename = get_basename(eac_unix_name.Buffer); + wcscpy(&basename[18], soW); + eac_unix_name.Length = eac_unix_name.MaximumLength = wcslen(eac_unix_name.Buffer) * sizeof(WCHAR); + InitializeObjectAttributes(&attr, &eac_unix_name, 0, NULL, NULL); + + if (!(status = nt_to_unix_file_name(&attr, &unix_path, FILE_OPEN))) + { + free(unix_path); + free(eac_unix_name.Buffer); + ret = LO_BUILTIN; + TRACE( "got hardcoded %s for %s, as the eac unix library is present\n", debugstr_loadorder(ret), debugstr_w(path) ); + return ret; + } + else + { + ret = LO_NATIVE; + TRACE( "got hardcoded %s for %s, as the eac unix library (%s) is not present. status %x\n", debugstr_loadorder(ret), debugstr_w(path), debugstr_w(eac_unix_name.Buffer), (int)status ); + free(eac_unix_name.Buffer); + return ret; + } + } + /* Strip path information if the module resides in the system directory */ if (!wcsnicmp( system_dir + 4, path, wcslen(system_dir) - 4 )) From db147f4e0821458f5503f7e5476eef059c77b3a0 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 16 Feb 2022 14:24:41 -0500 Subject: [PATCH 0512/2777] kernelbase: Don't load EAC bridge in the EAC Launcher process. Signed-off-by: Derek Lesho --- dlls/kernelbase/process.c | 64 ++++++++++++++++++++++++++++--------- dlls/ntdll/unix/loadorder.c | 21 ++++++++++++ 2 files changed, 70 insertions(+), 15 deletions(-) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 45107649b3b..9024980d86d 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -495,39 +495,35 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalA( HANDLE token, const char * return ret; } -static int battleye_launcher_redirect_hack(const WCHAR *app_name, WCHAR *new_name, DWORD new_name_len, WCHAR **cmd_line) +/* Returns TRUE if the product name of the app matches the parameter */ +static BOOL product_name_matches(const WCHAR *app_name, const char *match) { - static const WCHAR belauncherW[] = L"c:\\windows\\system32\\belauncher.exe"; - WCHAR full_path[MAX_PATH]; - WCHAR *p; - UINT size; - void *block; DWORD *translation; - char buf[100]; char *product_name; - WCHAR *new_cmd_line; + char buf[100]; + void *block; + UINT size; if (!GetLongPathNameW( app_name, full_path, MAX_PATH )) lstrcpynW( full_path, app_name, MAX_PATH ); if (!GetFullPathNameW( full_path, MAX_PATH, full_path, NULL )) lstrcpynW( full_path, app_name, MAX_PATH ); - /* We detect the BattlEye launcher executable through the product name property, as the executable name varies */ size = GetFileVersionInfoSizeExW(0, full_path, NULL); if (!size) - return 0; + return FALSE; block = HeapAlloc( GetProcessHeap(), 0, size ); if (!GetFileVersionInfoExW(0, full_path, 0, size, block)) { HeapFree( GetProcessHeap(), 0, block ); - return 0; + return FALSE; } if (!VerQueryValueA(block, "\\VarFileInfo\\Translation", (void **) &translation, &size) || size != 4) { HeapFree( GetProcessHeap(), 0, block ); - return 0; + return FALSE; } sprintf(buf, "\\StringFileInfo\\%08lx\\ProductName", MAKELONG(HIWORD(*translation), LOWORD(*translation))); @@ -535,16 +531,28 @@ static int battleye_launcher_redirect_hack(const WCHAR *app_name, WCHAR *new_nam if (!VerQueryValueA(block, buf, (void **) &product_name, &size)) { HeapFree( GetProcessHeap(), 0, block ); - return 0; + return FALSE; } - if (strcmp(product_name, "BattlEye Launcher")) + if (strcmp(product_name, match)) { HeapFree( GetProcessHeap(), 0, block); - return 0; + return FALSE; } HeapFree( GetProcessHeap(), 0, block ); + return TRUE; +} + +static int battleye_launcher_redirect_hack(const WCHAR *app_name, WCHAR *new_name, DWORD new_name_len, WCHAR **cmd_line) +{ + static const WCHAR belauncherW[] = L"c:\\windows\\system32\\belauncher.exe"; + WCHAR *new_cmd_line; + WCHAR *p; + + /* We detect the BattlEye launcher executable through the product name property, as the executable name varies */ + if (!product_name_matches(app_name, "BattlEye Launcher")) + return 0; TRACE("Detected launch of a BattlEye Launcher, redirecting to Proton version.\n"); @@ -712,6 +720,32 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR goto done; } + /* Set PROTON_EAC_LAUNCHER_PROCESS when launching the EAC launcher to let ntdll know to load the native EAC client library. + - We don't do this check in ntdll itself because it's harder to get the product name there + - we don't overwrite WINEDLLOVERRIDES because it's fetched from the unix environment */ + { + UNICODE_STRING is_eac_launcher_us; + UNICODE_STRING one_us; + + WCHAR *new_env = RtlAllocateHeap( GetProcessHeap(), 0, params->EnvironmentSize ); + memcpy(new_env, params->Environment, params->EnvironmentSize); + + RtlDestroyProcessParameters( params ); + + RtlInitUnicodeString( &is_eac_launcher_us, L"PROTON_EAC_LAUNCHER_PROCESS" ); + RtlInitUnicodeString( &one_us, L"1" ); + RtlSetEnvironmentVariable( &new_env, &is_eac_launcher_us, product_name_matches(app_name, "EasyAntiCheat Launcher") ? &one_us : NULL ); + + params = create_process_params( app_name, tidy_cmdline, cur_dir, new_env, flags | CREATE_UNICODE_ENVIRONMENT, startup_info ); + + RtlFreeHeap(GetProcessHeap(), 0, new_env); + if (!params) + { + status = STATUS_NO_MEMORY; + goto done; + } + } + if (flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)) { if ((status = DbgUiConnectToDbg())) goto done; diff --git a/dlls/ntdll/unix/loadorder.c b/dlls/ntdll/unix/loadorder.c index 3d9575d83f2..a13d54ec263 100644 --- a/dlls/ntdll/unix/loadorder.c +++ b/dlls/ntdll/unix/loadorder.c @@ -59,6 +59,7 @@ static HANDLE std_key; static HANDLE app_key; static BOOL init_done; static BOOL main_exe_loaded; +static BOOL eac_launcher_process; /*************************************************************************** @@ -362,11 +363,24 @@ static enum loadorder get_load_order_value( HANDLE std_key, HANDLE app_key, WCHA */ void set_load_order_app_name( const WCHAR *app_name ) { + static const WCHAR eac_launcherW[] = {'P','R','O','T','O','N','_','E','A','C','_','L','A','U','N','C','H','E','R','_','P','R','O','C','E','S','S',0}; const WCHAR *p; if ((p = wcsrchr( app_name, '\\' ))) app_name = p + 1; app_key = open_app_key( app_name ); main_exe_loaded = TRUE; + + p = NtCurrentTeb()->Peb->ProcessParameters->Environment; + while(*p) + { + if (!wcsncmp( p, eac_launcherW, ARRAY_SIZE(eac_launcherW) - 1 )) + { + eac_launcher_process = TRUE; + break; + } + + p += wcslen(p) + 1; + } } @@ -404,6 +418,13 @@ enum loadorder get_load_order( const UNICODE_STRING *nt_name ) char *unix_path = NULL; NTSTATUS status; + if (eac_launcher_process) + { + ret = LO_NATIVE; + TRACE("got hardcoded %s for %s, as this is the EAC launcher process\n", debugstr_loadorder(ret), debugstr_w(path) ); + return ret; + } + len = wcslen(nt_name->Buffer); eac_unix_name.Buffer = malloc( (len + 1) * sizeof(WCHAR) ); wcscpy(eac_unix_name.Buffer, nt_name->Buffer); From 02d00097671fc2bebb9c8221dc771bcd636a9c4d Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 16 Feb 2022 14:26:51 -0500 Subject: [PATCH 0513/2777] ntdll: Decide load order of easyanticheat.dll based off bridge detection logic. Signed-off-by: Derek Lesho --- dlls/ntdll/unix/loadorder.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/loadorder.c b/dlls/ntdll/unix/loadorder.c index a13d54ec263..bbe50928880 100644 --- a/dlls/ntdll/unix/loadorder.c +++ b/dlls/ntdll/unix/loadorder.c @@ -394,6 +394,7 @@ enum loadorder get_load_order( const UNICODE_STRING *nt_name ) { static const WCHAR easyanticheat_x86W[] = {'e','a','s','y','a','n','t','i','c','h','e','a','t','_','x','8','6','.','d','l','l',0}; static const WCHAR easyanticheat_x64W[] = {'e','a','s','y','a','n','t','i','c','h','e','a','t','_','x','6','4','.','d','l','l',0}; + static const WCHAR easyanticheatW[] = {'e','a','s','y','a','n','t','i','c','h','e','a','t','.','d','l','l',0}; static const WCHAR soW[] = {'s','o',0}; static const WCHAR prefixW[] = {'\\','?','?','\\'}; @@ -411,7 +412,7 @@ enum loadorder get_load_order( const UNICODE_STRING *nt_name ) /* HACK: special logic for easyanticheat bridge: only load the bridge (builtin) if there exists a native version of the library next to the windows version */ basename = get_basename((WCHAR *)path); - if (!wcsicmp(basename, easyanticheat_x86W) || !wcsicmp(basename, easyanticheat_x64W)) + if (!wcsicmp(basename, easyanticheat_x86W) || !wcsicmp(basename, easyanticheat_x64W) || !wcsicmp(basename, easyanticheatW)) { UNICODE_STRING eac_unix_name; OBJECT_ATTRIBUTES attr; @@ -426,10 +427,12 @@ enum loadorder get_load_order( const UNICODE_STRING *nt_name ) } len = wcslen(nt_name->Buffer); - eac_unix_name.Buffer = malloc( (len + 1) * sizeof(WCHAR) ); + eac_unix_name.Buffer = malloc( (len + 5) * sizeof(WCHAR) ); wcscpy(eac_unix_name.Buffer, nt_name->Buffer); basename = get_basename(eac_unix_name.Buffer); + if (!wcsicmp(basename, easyanticheatW)) + wcscpy(basename, easyanticheat_x64W); wcscpy(&basename[18], soW); eac_unix_name.Length = eac_unix_name.MaximumLength = wcslen(eac_unix_name.Buffer) * sizeof(WCHAR); InitializeObjectAttributes(&attr, &eac_unix_name, 0, NULL, NULL); From a38d5f3c7c2d23948b257e02c9f361a00b0a27fc Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 11 Mar 2022 15:46:11 +0300 Subject: [PATCH 0514/2777] kernelbase: HACK: Force CEF swiftshader for Montaro/nw.exe. CW-Bug-Id: #20284 --- dlls/kernelbase/process.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 9024980d86d..f16f1182906 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -601,6 +601,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"Montaro\\nw.exe", L" --use-gl=swiftshader"}, }; unsigned int i; From 934dbec68550527ed0858c407c2c944d0341456b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Sun, 22 May 2022 11:53:12 -0500 Subject: [PATCH 0515/2777] kernelbase: HACK: Force CEF swiftshader for EpicOnlineServicesUIHelper. Enabling other process window rendering makes it dependent on the missing d3dcompiler features. CW-Bug-Id: #20680 --- dlls/kernelbase/process.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index f16f1182906..e194bf2b517 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -602,6 +602,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"Montaro\\nw.exe", L" --use-gl=swiftshader"}, + {L"EpicOnlineServicesUIHelper", L" --use-gl=desktop"}, }; unsigned int i; From 4ad36715d8b4135112a279b7c6d7cdcf0aef0b3d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 24 Jun 2022 13:03:05 -0500 Subject: [PATCH 0516/2777] ntdll: HACK: Enable WINESTEAMNOEXEC for CoD Black Ops II Multiplayer and Zombies. CW-Bug-Id: #20869 --- dlls/ntdll/unix/loader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index f916d6732bf..96b75ef26ab 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2245,7 +2245,7 @@ static void hacks_init(void) ERR("HACK: Simulating sched quantum in fsync.\n"); env_str = getenv("SteamGameId"); - if (env_str && !strcmp(env_str, "50130")) + if (env_str && (!strcmp(env_str, "50130") || !strcmp(env_str, "202990") || !strcmp(env_str, "212910"))) setenv("WINESTEAMNOEXEC", "1", 0); } From 446d1361148c4c0ab6826b361b9ff6bba59c5a3e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 3 Aug 2022 11:56:39 -0500 Subject: [PATCH 0517/2777] ntdll: HACK: Add an option to report ntdll from RtlPcToFileHeader() for PC in Unix lib. CW-Bug-Id: #21065 (to be dropped once we have no blocking calls to Unix native libs going wthout wine_syscall_dispatcher). --- dlls/ntdll/loader.c | 9 +++++++++ dlls/ntdll/unix/loader.c | 26 +++++++++++++++++++++++--- dlls/ntdll/unixlib.h | 1 + 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index a2e63d57f35..a331c84635e 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -4403,6 +4403,15 @@ PVOID WINAPI RtlPcToFileHeader( PVOID pc, PVOID *address ) RtlEnterCriticalSection( &loader_section ); if (!LdrFindEntryForAddress( pc, &module )) ret = module->DllBase; RtlLeaveCriticalSection( &loader_section ); + + if (!ret && NTDLL_UNIX_CALL( is_pc_in_native_so, pc )) + { + LDR_DATA_TABLE_ENTRY *mod; + + mod = CONTAINING_RECORD( node_ntdll->Modules.Flink, LDR_DATA_TABLE_ENTRY, NodeModuleLink ); + ret = mod->DllBase; + } + *address = ret; return ret; } diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 96b75ef26ab..8e744dafe15 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2210,6 +2210,21 @@ static NTSTATUS steamclient_setup_trampolines( void *args ) return STATUS_SUCCESS; } +static BOOL report_native_pc_as_ntdll; + +static NTSTATUS is_pc_in_native_so(void *pc) +{ + Dl_info info; + + if (!report_native_pc_as_ntdll || !dladdr( pc, &info )) return FALSE; + + TRACE( "pc %p, module %s.\n", pc, debugstr_a(info.dli_fname) ); + + if (strstr( info.dli_fname, ".dll.so")) return FALSE; + + return TRUE; +} + /*********************************************************************** * __wine_unix_call_funcs */ @@ -2219,6 +2234,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = unwind_builtin_dll, system_time_precise, steamclient_setup_trampolines, + is_pc_in_native_so, }; BOOL ac_odyssey; @@ -2228,7 +2244,7 @@ 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 *env_str; + const char *env_str, *sgi; if (main_argc > 1 && strstr(main_argv[1], ac_odyssey_exe)) { @@ -2244,9 +2260,13 @@ static void hacks_init(void) if (fsync_simulate_sched_quantum) ERR("HACK: Simulating sched quantum in fsync.\n"); - env_str = getenv("SteamGameId"); - if (env_str && (!strcmp(env_str, "50130") || !strcmp(env_str, "202990") || !strcmp(env_str, "212910"))) + sgi = getenv("SteamGameId"); + if (sgi && (!strcmp(sgi, "50130") || !strcmp(sgi, "202990") || !strcmp(sgi, "212910"))) setenv("WINESTEAMNOEXEC", "1", 0); + + env_str = getenv("WINE_UNIX_PC_AS_NTDLL"); + if (env_str) report_native_pc_as_ntdll = atoi(env_str); + else if (sgi) report_native_pc_as_ntdll = !strcmp(sgi, "700330"); } #ifdef _WIN64 diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index 36b0ded3bc9..59a5a46d806 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -50,6 +50,7 @@ enum ntdll_unix_funcs unix_unwind_builtin_dll, unix_system_time_precise, unix_steamclient_setup_trampolines, + unix_is_pc_in_native_so, }; extern unixlib_handle_t ntdll_unix_handle; From 7d9113929ee2339848b1327c684ca020fb97c188 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 19 Nov 2021 16:30:57 +0300 Subject: [PATCH 0518/2777] wine.inf: Restore default libglesv2 load order for Paradox launcher. Remove order override instead of reverting commit 13ac81ffd075d9e92486a395be9cfe822562e718 to correctly update existing prefixes. CW-Bug-Id: #19617 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 6ee10ca6db4..7825d886f92 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2769,6 +2769,7 @@ HKCU,Software\Wine\AppDefaults\BlackOps3.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\NFS16.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\DIRT5.exe\DllOverrides,"atiadlxx",,"builtin" +HKCU,Software\Wine\AppDefaults\Paradox Launcher.exe\DllOverrides,,4, HKCU,Software\Wine\AppDefaults\gotg.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\RelicCardinal.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\Avengers.exe\DllOverrides,"atiadlxx",,"builtin" From 89f71711a4db779cbd65617c144b91192703518c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 17 Aug 2022 18:22:35 -0500 Subject: [PATCH 0519/2777] ntdll: Enable WINE_FSYNC_SIMULATE_SCHED_QUANTUM for Planet Zoo. CW-Bug-Id: #21142 --- dlls/ntdll/unix/loader.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 8e744dafe15..015ce9dac7c 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2256,7 +2256,10 @@ static void hacks_init(void) 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); + fsync_simulate_sched_quantum = fsync_simulate_sched_quantum || !!strstr(main_argv[1], "PlanetZoo.exe"); + } if (fsync_simulate_sched_quantum) ERR("HACK: Simulating sched quantum in fsync.\n"); From cfd79adfcc8eb7a16fdb5cf26f4689e322b32cec Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 9 Sep 2022 17:37:39 -0500 Subject: [PATCH 0520/2777] ntdll: Enable WINE_FSYNC_SIMULATE_SCHED_QUANTUM for GTA5. CW-Bug-Id: #21194 --- dlls/ntdll/unix/loader.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 015ce9dac7c..4c1ddef54b4 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2259,6 +2259,7 @@ static void hacks_init(void) { fsync_simulate_sched_quantum = !!strstr(main_argv[1], upc_exe); fsync_simulate_sched_quantum = fsync_simulate_sched_quantum || !!strstr(main_argv[1], "PlanetZoo.exe"); + fsync_simulate_sched_quantum = fsync_simulate_sched_quantum || !!strstr(main_argv[1], "GTA5.exe"); } if (fsync_simulate_sched_quantum) ERR("HACK: Simulating sched quantum in fsync.\n"); From b3dd812c8f84407e90a344bb3e20b03270138ac4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 9 Sep 2022 18:21:26 -0500 Subject: [PATCH 0521/2777] ntdll: HACK: Add WINE_ALERT_SIMULATE_SCHED_QUANTUM option. And enable it for GTA 5. CW-Bug-Id: #21194 --- dlls/ntdll/unix/loader.c | 11 +++++++++++ dlls/ntdll/unix/sync.c | 8 ++++++++ dlls/ntdll/unix/unix_private.h | 1 + 3 files changed, 20 insertions(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 4c1ddef54b4..ef9c49cfc12 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2239,6 +2239,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = BOOL ac_odyssey; BOOL fsync_simulate_sched_quantum; +BOOL alert_simulate_sched_quantum; static void hacks_init(void) { @@ -2264,6 +2265,16 @@ static void hacks_init(void) if (fsync_simulate_sched_quantum) ERR("HACK: Simulating sched quantum in fsync.\n"); + env_str = getenv("WINE_ALERT_SIMULATE_SCHED_QUANTUM"); + if (env_str) + alert_simulate_sched_quantum = !!atoi(env_str); + else if (main_argc > 1) + { + alert_simulate_sched_quantum = !!strstr(main_argv[1], "GTA5.exe"); + } + if (alert_simulate_sched_quantum) + ERR("HACK: Simulating sched quantum in NtWaitForAlertByThreadId.\n"); + sgi = getenv("SteamGameId"); if (sgi && (!strcmp(sgi, "50130") || !strcmp(sgi, "202990") || !strcmp(sgi, "212910"))) setenv("WINESTEAMNOEXEC", "1", 0); diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 8aef63c95c4..62a8d9d3171 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -2621,6 +2621,7 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEGER *timeout ) { union tid_alert_entry *entry = get_tid_alert_entry( NtCurrentTeb()->ClientId.UniqueThread ); + BOOL waited = FALSE; NTSTATUS status; TRACE( "%p %s\n", address, debugstr_timeout( timeout ) ); @@ -2656,8 +2657,15 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG else ret = futex_wait( futex, 0, NULL ); + if (!timeout || timeout->QuadPart) + waited = TRUE; + if (ret == -1 && errno == ETIMEDOUT) return STATUS_TIMEOUT; } + + if (alert_simulate_sched_quantum && waited) + usleep(0); + return STATUS_ALERTED; } #endif diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 2740fe10128..87c1ffacc8e 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -151,6 +151,7 @@ extern struct ldt_copy __wine_ldt_copy DECLSPEC_HIDDEN; extern BOOL ac_odyssey DECLSPEC_HIDDEN; extern BOOL fsync_simulate_sched_quantum DECLSPEC_HIDDEN; +extern BOOL alert_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 e4e41e3112444e6783bb4b61b75ec938fcf16af9 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 29 Jun 2022 14:09:43 -0500 Subject: [PATCH 0522/2777] ntdll: HACK: Add WINE_NO_PRIV_ELEVATION option and auto enable it for Aquarist - My First Job. CW-Bug-Id: #20846 --- dlls/ntdll/unix/loader.c | 5 +++++ dlls/ntdll/unix/security.c | 3 +++ dlls/ntdll/unix/unix_private.h | 1 + 3 files changed, 9 insertions(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index ef9c49cfc12..ebfe3aef72d 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2240,6 +2240,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = BOOL ac_odyssey; BOOL fsync_simulate_sched_quantum; BOOL alert_simulate_sched_quantum; +BOOL no_priv_elevation; static void hacks_init(void) { @@ -2279,6 +2280,10 @@ static void hacks_init(void) if (sgi && (!strcmp(sgi, "50130") || !strcmp(sgi, "202990") || !strcmp(sgi, "212910"))) setenv("WINESTEAMNOEXEC", "1", 0); + env_str = getenv("WINE_NO_PRIV_ELEVATION"); + if (env_str) no_priv_elevation = atoi(env_str); + else if (sgi) no_priv_elevation = !strcmp(sgi, "1584660"); + env_str = getenv("WINE_UNIX_PC_AS_NTDLL"); if (env_str) report_native_pc_as_ntdll = atoi(env_str); else if (sgi) report_native_pc_as_ntdll = !strcmp(sgi, "700330"); diff --git a/dlls/ntdll/unix/security.c b/dlls/ntdll/unix/security.c index 35e5c6abf99..e334c38d5e4 100644 --- a/dlls/ntdll/unix/security.c +++ b/dlls/ntdll/unix/security.c @@ -405,6 +405,8 @@ NTSTATUS WINAPI NtQueryInformationToken( HANDLE token, TOKEN_INFORMATION_CLASS c if (!status) *type = reply->elevation; } SERVER_END_REQ; + if (!status && no_priv_elevation) + *(TOKEN_ELEVATION_TYPE *)info = TokenElevationTypeLimited; break; case TokenElevation: @@ -415,6 +417,7 @@ NTSTATUS WINAPI NtQueryInformationToken( HANDLE token, TOKEN_INFORMATION_CLASS c req->handle = wine_server_obj_handle( token ); status = wine_server_call( req ); if (!status) elevation->TokenIsElevated = (reply->elevation == TokenElevationTypeFull); + if (!status && no_priv_elevation) elevation->TokenIsElevated = 0; } SERVER_END_REQ; break; diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 87c1ffacc8e..576fa80730d 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -152,6 +152,7 @@ extern struct ldt_copy __wine_ldt_copy DECLSPEC_HIDDEN; extern BOOL ac_odyssey DECLSPEC_HIDDEN; extern BOOL fsync_simulate_sched_quantum DECLSPEC_HIDDEN; extern BOOL alert_simulate_sched_quantum DECLSPEC_HIDDEN; +extern BOOL no_priv_elevation DECLSPEC_HIDDEN; extern void init_environment( int argc, char *argv[], char *envp[] ) DECLSPEC_HIDDEN; extern void init_startup_info(void) DECLSPEC_HIDDEN; From 974a863e9437326b365f2d78069927f47da9fb3c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 15 Jul 2022 20:00:08 -0500 Subject: [PATCH 0523/2777] ntdll: HACK: Report LocalSystem accound SID for MicrosoftEdgeUpdate. CW-Bug-Id: #20967 --- dlls/ntdll/unix/loader.c | 8 ++++++++ dlls/ntdll/unix/security.c | 22 ++++++++++++++++++++++ dlls/ntdll/unix/unix_private.h | 1 + 3 files changed, 31 insertions(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index ebfe3aef72d..a0e671bc475 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2241,6 +2241,7 @@ BOOL ac_odyssey; BOOL fsync_simulate_sched_quantum; BOOL alert_simulate_sched_quantum; BOOL no_priv_elevation; +BOOL localsystem_sid; static void hacks_init(void) { @@ -2287,6 +2288,13 @@ static void hacks_init(void) env_str = getenv("WINE_UNIX_PC_AS_NTDLL"); if (env_str) report_native_pc_as_ntdll = atoi(env_str); else if (sgi) report_native_pc_as_ntdll = !strcmp(sgi, "700330"); + + if (main_argc > 1 && strstr(main_argv[1], "MicrosoftEdgeUpdate.exe")) + { + ERR("HACK: reporting LocalSystem account SID.\n"); + localsystem_sid = TRUE; + return; + } } #ifdef _WIN64 diff --git a/dlls/ntdll/unix/security.c b/dlls/ntdll/unix/security.c index e334c38d5e4..f984fea149b 100644 --- a/dlls/ntdll/unix/security.c +++ b/dlls/ntdll/unix/security.c @@ -209,6 +209,28 @@ NTSTATUS WINAPI NtQueryInformationToken( HANDLE token, TOKEN_INFORMATION_CLASS c switch (class) { case TokenUser: + if (localsystem_sid) + { + static const struct sid local_system_sid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_LOCAL_SYSTEM_RID } }; + DWORD sid_len = offsetof( struct sid, sub_auth[local_system_sid.sub_count] ); + TOKEN_USER *tuser; + PSID sid; + + if (retlen) *retlen = sid_len + sizeof(TOKEN_USER); + if (sid_len + sizeof(TOKEN_USER) > length) + { + status = STATUS_BUFFER_TOO_SMALL; + } + else + { + tuser = info; + sid = tuser + 1; + tuser->User.Sid = sid; + tuser->User.Attributes = 0; + memcpy( sid, &local_system_sid, sid_len ); + } + break; + } SERVER_START_REQ( get_token_sid ) { TOKEN_USER *tuser = info; diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 576fa80730d..40cf3553ffe 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -153,6 +153,7 @@ extern BOOL ac_odyssey DECLSPEC_HIDDEN; extern BOOL fsync_simulate_sched_quantum DECLSPEC_HIDDEN; extern BOOL alert_simulate_sched_quantum DECLSPEC_HIDDEN; extern BOOL no_priv_elevation DECLSPEC_HIDDEN; +extern BOOL localsystem_sid DECLSPEC_HIDDEN; extern void init_environment( int argc, char *argv[], char *envp[] ) DECLSPEC_HIDDEN; extern void init_startup_info(void) DECLSPEC_HIDDEN; From 7fdc765e3f12a20b9c03661614f83d68a0d8beb1 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 28 Oct 2022 20:24:29 -0500 Subject: [PATCH 0524/2777] kernelbase: HACK: Force GL QtWebEngine rendering for EADesktop. CW-Bug-Id: #21497 --- dlls/kernelbase/process.c | 31 +++++++++++++++++++++++++++++++ dlls/ntdll/unix/loader.c | 8 ++++++++ 2 files changed, 39 insertions(+) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index e194bf2b517..b72506a2063 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -1855,6 +1855,37 @@ BOOL WINAPI DECLSPEC_HOTPATCH SetEnvironmentVariableW( LPCWSTR name, LPCWSTR val return FALSE; } + if (name && !lstrcmpW( name, L"QT_OPENGL" ) && value && !lstrcmpW( value, L"angle" )) + { + static const WCHAR *names[] = + { + L"\\EADesktop.exe", + L"\\Link2EA.exe", + L"\\EAConnect_microsoft.exe", + L"\\EALaunchHelper.exe", + L"\\EACrashReporter.exe", + L"EA Desktop\\ErrorReporter.exe", + }; + unsigned int i, len; + WCHAR module[256]; + DWORD size; + + if ((size = GetModuleFileNameW( NULL, module, ARRAY_SIZE(module) )) && size < ARRAY_SIZE(module)) + { + for (i = 0; i < ARRAY_SIZE(names); ++i) + { + len = lstrlenW(names[i]); + if (size > len && !memcmp( module + size - len, names[i], len * sizeof(*module) )) + { + value = L"desktop"; + FIXME( "HACK: setting QT_OPENGL=desktop.\n" ); + break; + } + } + } + } + + RtlInitUnicodeString( &us_name, name ); if (value) { diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index a0e671bc475..e89b10fa74e 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2295,6 +2295,14 @@ static void hacks_init(void) localsystem_sid = TRUE; return; } + + if (main_argc > 1 && (strstr(main_argv[1], "\\EADesktop.exe") || strstr(main_argv[1], "\\Link2EA.exe") + || strstr(main_argv[1], "EA Desktop\\ErrorReporter.exe") || strstr(main_argv[1], "\\EAConnect_microsoft.exe") + || strstr(main_argv[1], "\\EALaunchHelper.exe") || strstr(main_argv[1], "\\EACrashReporter.exe"))) + { + ERR("HACK: setting LIBGL_ALWAYS_SOFTWARE.\n"); + setenv("LIBGL_ALWAYS_SOFTWARE", "1", 0); + } } #ifdef _WIN64 From 9d672c92f570be2789e2814f5413efcc7a466193 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 20 Jun 2022 12:24:04 -0500 Subject: [PATCH 0525/2777] winex11.drv: HACK: Add WINE_SHARE_ALL_GL_CONTEXTS environment variable. And auto enable it for Eador. Masters of the Broken World. CW-Bug-Id: #20830 wglShareLists() cannot be properly implemented on top of glX context sharing. --- dlls/winex11.drv/opengl.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 96a8526604b..10d25c9e631 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1733,6 +1733,34 @@ static BOOL glxdrv_wglCopyContext(struct wgl_context *src, struct wgl_context *d return TRUE; } +static int share_all_contexts = -1; + +static GLXContext get_common_context( GLXFBConfig fbconfig ) +{ + static GLXContext common_context; + + if (share_all_contexts == -1) + { + const char *e = getenv( "WINE_SHARE_ALL_GL_CONTEXTS" ); + const char *sgi = getenv( "SteamGameId" ); + + if (e) + share_all_contexts = !!atoi(e); + else + share_all_contexts = sgi && !strcmp( sgi, "232050" ); + + if (share_all_contexts) + FIXME( "HACK: sharing all the GL contexts.\n" ); + } + + if (!share_all_contexts) return NULL; + + if (!common_context) + common_context = pglXCreateNewContext( gdi_display, fbconfig, GLX_RGBA_TYPE, NULL, TRUE ); + + return common_context; +} + /*********************************************************************** * glxdrv_wglCreateContext */ @@ -1751,7 +1779,7 @@ static struct wgl_context *glxdrv_wglCreateContext( HDC hdc ) { ret->hdc = hdc; ret->fmt = gl->format; - ret->ctx = create_glxcontext(gdi_display, ret, NULL); + ret->ctx = create_glxcontext(gdi_display, ret, get_common_context( ret->fmt->fbconfig )); pthread_mutex_lock( &context_mutex ); list_add_head( &context_list, &ret->entry ); pthread_mutex_unlock( &context_mutex ); @@ -1931,6 +1959,8 @@ static BOOL glxdrv_wglShareLists(struct wgl_context *org, struct wgl_context *de * current or when it hasn't shared display lists before. */ + if (share_all_contexts == 1) return TRUE; + if((org->has_been_current && dest->has_been_current) || dest->has_been_current) { ERR("Could not share display lists, one of the contexts has been current already !\n"); @@ -2095,7 +2125,8 @@ static struct wgl_context *X11DRV_wglCreateContextAttribsARB( HDC hdc, struct wg } X11DRV_expect_error(gdi_display, GLXErrorHandler, NULL); - ret->ctx = create_glxcontext(gdi_display, ret, hShareContext ? hShareContext->ctx : NULL); + ret->ctx = create_glxcontext(gdi_display, ret, + hShareContext ? hShareContext->ctx : get_common_context( ret->fmt->fbconfig )); XSync(gdi_display, False); if ((err = X11DRV_check_error()) || !ret->ctx) { From 84e1e3543d8a39a0d41fa726812fd48fa1ca01d9 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 20 Jun 2022 12:43:39 -0500 Subject: [PATCH 0526/2777] winex11.drv: HACK: Enable WINE_SHARE_ALL_GL_CONTEXTS for Cossacks 3. CW-Bug-Id: #20532 --- dlls/winex11.drv/opengl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 10d25c9e631..06c11e9be13 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1747,7 +1747,7 @@ static GLXContext get_common_context( GLXFBConfig fbconfig ) if (e) share_all_contexts = !!atoi(e); else - share_all_contexts = sgi && !strcmp( sgi, "232050" ); + share_all_contexts = sgi && (!strcmp( sgi, "232050" ) || !strcmp( sgi, "333420" )); if (share_all_contexts) FIXME( "HACK: sharing all the GL contexts.\n" ); From fe48e24745b71b45a487c40d52362dd013158f26 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 28 Oct 2022 20:25:39 -0500 Subject: [PATCH 0527/2777] winex11.drv: HACK: Enable WINE_SHARE_ALL_GL_CONTEXTS for EADesktop. CW-Bug-Id: #21497 --- dlls/winex11.drv/opengl.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 06c11e9be13..6b789680335 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1747,8 +1747,24 @@ static GLXContext get_common_context( GLXFBConfig fbconfig ) if (e) share_all_contexts = !!atoi(e); else + { share_all_contexts = sgi && (!strcmp( sgi, "232050" ) || !strcmp( sgi, "333420" )); - + if (!share_all_contexts) + { + static const WCHAR ea_desktop[] = u"EADesktop.exe"; + UNICODE_STRING *name; + DWORD len, name_len; + + name = &NtCurrentTeb()->Peb->ProcessParameters->ImagePathName; + len = name->Length / sizeof(WCHAR); + if (len && !name->Buffer[len]) --len; + name_len = sizeof(ea_desktop) / sizeof(*ea_desktop) - 1; + + if (len >= name_len) + share_all_contexts = !memcmp( name->Buffer + len - name_len, ea_desktop, + name_len * sizeof(*ea_desktop) ); + } + } if (share_all_contexts) FIXME( "HACK: sharing all the GL contexts.\n" ); } From 503743054209946e75cbbef63c30183604872fed Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 17 Nov 2021 19:34:29 +0300 Subject: [PATCH 0528/2777] twinapi.appcore.dll: Stub DLL. CW-Bug-Id: #19649 --- configure.ac | 1 + dlls/twinapi.appcore.dll/Makefile.in | 6 + dlls/twinapi.appcore.dll/main.c | 157 ++++++++++++++++++ dlls/twinapi.appcore.dll/twinapi.appcore.spec | 3 + 4 files changed, 167 insertions(+) create mode 100644 dlls/twinapi.appcore.dll/Makefile.in create mode 100644 dlls/twinapi.appcore.dll/main.c create mode 100644 dlls/twinapi.appcore.dll/twinapi.appcore.spec diff --git a/configure.ac b/configure.ac index 7da4db714c4..f9f47903338 100644 --- a/configure.ac +++ b/configure.ac @@ -3066,6 +3066,7 @@ WINE_CONFIG_MAKEFILE(dlls/twain.dll16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/twain_32) WINE_CONFIG_MAKEFILE(dlls/twain_32/tests) WINE_CONFIG_MAKEFILE(dlls/typelib.dll16,enable_win16) +WINE_CONFIG_MAKEFILE(dlls/twinapi.appcore.dll) WINE_CONFIG_MAKEFILE(dlls/tzres) WINE_CONFIG_MAKEFILE(dlls/ucrtbase) WINE_CONFIG_MAKEFILE(dlls/ucrtbase/tests) diff --git a/dlls/twinapi.appcore.dll/Makefile.in b/dlls/twinapi.appcore.dll/Makefile.in new file mode 100644 index 00000000000..d9375a5e8f4 --- /dev/null +++ b/dlls/twinapi.appcore.dll/Makefile.in @@ -0,0 +1,6 @@ +EXTRADEFS = -DWINE_NO_LONG_TYPES +MODULE = twinapi.appcore.dll +IMPORTS = combase + +C_SRCS = \ + main.c diff --git a/dlls/twinapi.appcore.dll/main.c b/dlls/twinapi.appcore.dll/main.c new file mode 100644 index 00000000000..9de8b65f945 --- /dev/null +++ b/dlls/twinapi.appcore.dll/main.c @@ -0,0 +1,157 @@ +/* + * Copyright 2021 Paul Gofman 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 + */ + +#include + +#define COBJMACROS +#include "initguid.h" +#include "windef.h" +#include "winbase.h" +#include "winstring.h" +#include "wine/debug.h" +#include "objbase.h" + +#include "activation.h" + +#include "windows.foundation.h" + +WINE_DEFAULT_DEBUG_CHANNEL(twinapi); + +static const char *debugstr_hstring(HSTRING hstr) +{ + const WCHAR *str; + UINT32 len; + if (hstr && !((ULONG_PTR)hstr >> 16)) return "(invalid)"; + str = WindowsGetStringRawBuffer(hstr, &len); + return wine_dbgstr_wn(str, len); +} + +struct twinapi_appcore +{ + IActivationFactory IActivationFactory_iface; + LONG ref; +}; + +static inline struct twinapi_appcore *impl_from_IActivationFactory(IActivationFactory *iface) +{ + return CONTAINING_RECORD(iface, struct twinapi_appcore, IActivationFactory_iface); +} + +static HRESULT STDMETHODCALLTYPE twinapi_appcore_QueryInterface( + IActivationFactory *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_IAgileObject) || + IsEqualGUID(iid, &IID_IActivationFactory)) + { + IUnknown_AddRef(iface); + *out = iface; + return S_OK; + } + + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE twinapi_appcore_AddRef( + IActivationFactory *iface) +{ + struct twinapi_appcore *impl = impl_from_IActivationFactory(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + TRACE("iface %p, ref %u.\n", iface, ref); + return ref; +} + +static ULONG STDMETHODCALLTYPE twinapi_appcore_Release( + IActivationFactory *iface) +{ + struct twinapi_appcore *impl = impl_from_IActivationFactory(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p, ref %u.\n", iface, ref); + return ref; +} + +static HRESULT STDMETHODCALLTYPE twinapi_appcore_GetIids( + IActivationFactory *iface, ULONG *iid_count, IID **iids) +{ + FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE twinapi_appcore_GetRuntimeClassName( + IActivationFactory *iface, HSTRING *class_name) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE twinapi_appcore_GetTrustLevel( + IActivationFactory *iface, TrustLevel *trust_level) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE twinapi_appcore_ActivateInstance( + IActivationFactory *iface, IInspectable **instance) +{ + FIXME("iface %p, instance %p stub!\n", iface, instance); + return E_NOTIMPL; +} + +static const struct IActivationFactoryVtbl activation_factory_vtbl = +{ + twinapi_appcore_QueryInterface, + twinapi_appcore_AddRef, + twinapi_appcore_Release, + /* IInspectable methods */ + twinapi_appcore_GetIids, + twinapi_appcore_GetRuntimeClassName, + twinapi_appcore_GetTrustLevel, + /* IActivationFactory methods */ + twinapi_appcore_ActivateInstance, +}; + +static struct twinapi_appcore twinapi_appcore = +{ + {&activation_factory_vtbl}, + 1 +}; + +HRESULT WINAPI DllCanUnloadNow(void) +{ + return S_FALSE; +} + +HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out) +{ + FIXME("clsid %s, riid %s, out %p stub!\n", debugstr_guid(clsid), debugstr_guid(riid), out); + return CLASS_E_CLASSNOTAVAILABLE; +} + +HRESULT WINAPI DllGetActivationFactory(HSTRING classid, IActivationFactory **factory) +{ + TRACE("classid %s, factory %p.\n", debugstr_hstring(classid), factory); + *factory = &twinapi_appcore.IActivationFactory_iface; + IUnknown_AddRef(*factory); + return S_OK; +} diff --git a/dlls/twinapi.appcore.dll/twinapi.appcore.spec b/dlls/twinapi.appcore.dll/twinapi.appcore.spec new file mode 100644 index 00000000000..721493229c2 --- /dev/null +++ b/dlls/twinapi.appcore.dll/twinapi.appcore.spec @@ -0,0 +1,3 @@ +1 stdcall -private DllCanUnloadNow() +2 stdcall -private DllGetActivationFactory(ptr ptr) +3 stdcall -private DllGetClassObject(ptr ptr ptr) From 5b14d318d836e400d7e13178a4bff2ed5f1659e4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 17 Nov 2021 22:34:20 +0300 Subject: [PATCH 0529/2777] twinapi.appcore.dll: Stub implement IEasClientDeviceInformation. CW-Bug-Id: #19649 --- dlls/twinapi.appcore.dll/Makefile.in | 2 + dlls/twinapi.appcore.dll/classes.idl | 23 +++ dlls/twinapi.appcore.dll/main.c | 142 +++++++++++++++++- include/Makefile.in | 1 + ...ecurity.exchangeactivesyncprovisioning.idl | 61 ++++++++ 5 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 dlls/twinapi.appcore.dll/classes.idl create mode 100644 include/windows.security.exchangeactivesyncprovisioning.idl diff --git a/dlls/twinapi.appcore.dll/Makefile.in b/dlls/twinapi.appcore.dll/Makefile.in index d9375a5e8f4..1f7b969fe80 100644 --- a/dlls/twinapi.appcore.dll/Makefile.in +++ b/dlls/twinapi.appcore.dll/Makefile.in @@ -4,3 +4,5 @@ IMPORTS = combase C_SRCS = \ main.c + +IDL_SRCS = classes.idl diff --git a/dlls/twinapi.appcore.dll/classes.idl b/dlls/twinapi.appcore.dll/classes.idl new file mode 100644 index 00000000000..56ea8096642 --- /dev/null +++ b/dlls/twinapi.appcore.dll/classes.idl @@ -0,0 +1,23 @@ +/* + * Runtime Classes for windows.media.devices.dll + * + * Copyright 2021 Paul Gofman 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 + */ + +#pragma makedep register + +#include "windows.security.exchangeactivesyncprovisioning.idl" diff --git a/dlls/twinapi.appcore.dll/main.c b/dlls/twinapi.appcore.dll/main.c index 9de8b65f945..3842e36153c 100644 --- a/dlls/twinapi.appcore.dll/main.c +++ b/dlls/twinapi.appcore.dll/main.c @@ -28,7 +28,11 @@ #include "activation.h" +#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections #include "windows.foundation.h" +#define WIDL_using_Windows_Security_ExchangeActiveSyncProvisioning +#include "windows.security.exchangeactivesyncprovisioning.h" WINE_DEFAULT_DEBUG_CHANNEL(twinapi); @@ -44,9 +48,15 @@ static const char *debugstr_hstring(HSTRING hstr) struct twinapi_appcore { IActivationFactory IActivationFactory_iface; + IEasClientDeviceInformation IEasClientDeviceInformation_iface; LONG ref; }; +static inline struct twinapi_appcore *impl_from_IEasClientDeviceInformation(IEasClientDeviceInformation *iface) +{ + return CONTAINING_RECORD(iface, struct twinapi_appcore, IEasClientDeviceInformation_iface); +} + static inline struct twinapi_appcore *impl_from_IActivationFactory(IActivationFactory *iface) { return CONTAINING_RECORD(iface, struct twinapi_appcore, IActivationFactory_iface); @@ -55,6 +65,8 @@ static inline struct twinapi_appcore *impl_from_IActivationFactory(IActivationFa static HRESULT STDMETHODCALLTYPE twinapi_appcore_QueryInterface( IActivationFactory *iface, REFIID iid, void **out) { + struct twinapi_appcore *impl = impl_from_IActivationFactory(iface); + TRACE("iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out); if (IsEqualGUID(iid, &IID_IUnknown) || @@ -67,6 +79,13 @@ static HRESULT STDMETHODCALLTYPE twinapi_appcore_QueryInterface( return S_OK; } + if (IsEqualGUID(iid, &IID_IEasClientDeviceInformation)) + { + IUnknown_AddRef(iface); + *out = &impl->IEasClientDeviceInformation_iface; + return S_OK; + } + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); *out = NULL; return E_NOINTERFACE; @@ -114,8 +133,12 @@ static HRESULT STDMETHODCALLTYPE twinapi_appcore_GetTrustLevel( static HRESULT STDMETHODCALLTYPE twinapi_appcore_ActivateInstance( IActivationFactory *iface, IInspectable **instance) { - FIXME("iface %p, instance %p stub!\n", iface, instance); - return E_NOTIMPL; + FIXME("iface %p, instance %p semi-stub!\n", iface, instance); + + IActivationFactory_AddRef(iface); + *instance = (IInspectable *)iface; + + return S_OK; } static const struct IActivationFactoryVtbl activation_factory_vtbl = @@ -131,9 +154,124 @@ static const struct IActivationFactoryVtbl activation_factory_vtbl = twinapi_appcore_ActivateInstance, }; +static HRESULT WINAPI eas_client_devinfo_QueryInterface(IEasClientDeviceInformation *iface, + REFIID riid, void **ppvObject) +{ + struct twinapi_appcore *This = impl_from_IEasClientDeviceInformation(iface); + return twinapi_appcore_QueryInterface(&This->IActivationFactory_iface, riid, ppvObject); +} + +static ULONG WINAPI eas_client_devinfo_AddRef(IEasClientDeviceInformation *iface) +{ + struct twinapi_appcore *This = impl_from_IEasClientDeviceInformation(iface); + return twinapi_appcore_AddRef(&This->IActivationFactory_iface); +} + +static ULONG WINAPI eas_client_devinfo_Release(IEasClientDeviceInformation *iface) +{ + struct twinapi_appcore *This = impl_from_IEasClientDeviceInformation(iface); + return twinapi_appcore_Release(&This->IActivationFactory_iface); +} + +static HRESULT WINAPI eas_client_devinfo_GetIids(IEasClientDeviceInformation *iface, + ULONG *iidCount, IID **iids) +{ + struct twinapi_appcore *This = impl_from_IEasClientDeviceInformation(iface); + return twinapi_appcore_GetIids(&This->IActivationFactory_iface, iidCount, iids); +} + +static HRESULT WINAPI eas_client_devinfo_GetRuntimeClassName(IEasClientDeviceInformation *iface, + HSTRING *className) +{ + struct twinapi_appcore *This = impl_from_IEasClientDeviceInformation(iface); + return twinapi_appcore_GetRuntimeClassName(&This->IActivationFactory_iface, className); +} + +static HRESULT WINAPI eas_client_devinfo_GetTrustLevel(IEasClientDeviceInformation *iface, + TrustLevel *trustLevel) +{ + struct twinapi_appcore *This = impl_from_IEasClientDeviceInformation(iface); + return twinapi_appcore_GetTrustLevel(&This->IActivationFactory_iface, trustLevel); +} + +static HRESULT WINAPI eas_client_devinfo_get_Id(IEasClientDeviceInformation *iface, GUID* value) +{ + FIXME("iface %p, value %p stub.\n", iface, value); + + return E_NOTIMPL; +} + +static HRESULT WINAPI eas_client_devinfo_get_OperatingSystem(IEasClientDeviceInformation *iface, + HSTRING* value) +{ + FIXME("iface %p, value %p stub.\n", iface, value); + + WindowsCreateString(NULL, 0, value); + + return E_NOTIMPL; +} + +static HRESULT WINAPI eas_client_devinfo_get_FriendlyName(IEasClientDeviceInformation *iface, + HSTRING* value) +{ + FIXME("iface %p, value %p stub.\n", iface, value); + + WindowsCreateString(NULL, 0, value); + + return E_NOTIMPL; +} + +static HRESULT WINAPI eas_client_devinfo_get_SystemManufacturer(IEasClientDeviceInformation *iface, + HSTRING* value) +{ + FIXME("iface %p, value %p stub.\n", iface, value); + + WindowsCreateString(NULL, 0, value); + + return E_NOTIMPL; +} + +static HRESULT WINAPI eas_client_devinfo_get_SystemProductName(IEasClientDeviceInformation *iface, + HSTRING* value) +{ + FIXME("iface %p, value %p stub.\n", iface, value); + + WindowsCreateString(NULL, 0, value); + + return E_NOTIMPL; +} + +static HRESULT WINAPI eas_client_devinfo_get_SystemSku(IEasClientDeviceInformation *iface, + HSTRING* value) +{ + FIXME("iface %p, value %p stub.\n", iface, value); + + WindowsCreateString(NULL, 0, value); + + return E_NOTIMPL; +} + +static IEasClientDeviceInformationVtbl eas_client_devinfo_vtbl = { + eas_client_devinfo_QueryInterface, + eas_client_devinfo_AddRef, + eas_client_devinfo_Release, + /* IInspectable methods */ + eas_client_devinfo_GetIids, + eas_client_devinfo_GetRuntimeClassName, + eas_client_devinfo_GetTrustLevel, + /* IEasClientDeviceInformation methods */ + eas_client_devinfo_get_Id, + eas_client_devinfo_get_OperatingSystem, + eas_client_devinfo_get_FriendlyName, + eas_client_devinfo_get_SystemManufacturer, + eas_client_devinfo_get_SystemProductName, + eas_client_devinfo_get_SystemSku, +}; + static struct twinapi_appcore twinapi_appcore = { {&activation_factory_vtbl}, + {&eas_client_devinfo_vtbl}, 1 }; diff --git a/include/Makefile.in b/include/Makefile.in index 54cbf4d955c..8ea42337ba3 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -815,6 +815,7 @@ SOURCES = \ windows.media.speechrecognition.idl \ windows.media.speechsynthesis.idl \ windows.security.cryptography.idl \ + windows.security.exchangeactivesyncprovisioning.idl \ windows.storage.streams.idl \ windows.system.idl \ windows.system.power.idl \ diff --git a/include/windows.security.exchangeactivesyncprovisioning.idl b/include/windows.security.exchangeactivesyncprovisioning.idl new file mode 100644 index 00000000000..1b2a743b057 --- /dev/null +++ b/include/windows.security.exchangeactivesyncprovisioning.idl @@ -0,0 +1,61 @@ +/* + * Copyright 2021 Paul Gofman 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 + */ + +#ifdef __WIDL__ +#pragma winrt ns_prefix +#endif + +import "inspectable.idl"; +import "eventtoken.idl"; +import "windows.foundation.idl"; + +namespace Windows { + namespace Security { + namespace ExchangeActiveSyncProvisioning { + interface IEasClientDeviceInformation; + runtimeclass EasClientDeviceInformation; + } + } +} + +namespace Windows { + namespace Security { + namespace ExchangeActiveSyncProvisioning { + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + [exclusiveto(Windows.Security.ExchangeActiveSyncProvisioning.EasClientDeviceInformation)] + [uuid(54DFD981-1968-4CA3-B958-E595D16505EB)] + interface IEasClientDeviceInformation : IInspectable + { + [propget] HRESULT Id([out] [retval] GUID* value); + [propget] HRESULT OperatingSystem([out] [retval] HSTRING* value); + [propget] HRESULT FriendlyName([out] [retval] HSTRING* value); + [propget] HRESULT SystemManufacturer([out] [retval] HSTRING* value); + [propget] HRESULT SystemProductName([out] [retval] HSTRING* value); + [propget] HRESULT SystemSku([out] [retval] HSTRING* value); + } + + [activatable(Windows.Foundation.UniversalApiContract, 1.0)] + [contract(Windows.Foundation.UniversalApiContract, 1.0)] + [threading(both)] + runtimeclass EasClientDeviceInformation + { + [default] interface Windows.Security.ExchangeActiveSyncProvisioning.IEasClientDeviceInformation; + } + } + } +} From 8fb18db3604ac92b0f0c3f0ed9523036fa3a40ad Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Sun, 10 Oct 2021 22:03:21 +0200 Subject: [PATCH 0530/2777] HACK: ntdll: Support x86_64 syscall emulation for Red Dead Redemption 2. CW-Bug-Id: #19085 --- dlls/ntdll/unix/signal_x86_64.c | 62 +++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index b1425066db4..a001f5c0113 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1867,6 +1867,45 @@ static void sigsys_handler( int signal, siginfo_t *siginfo, void *sigcontext ) ctx->uc_mcontext.gregs[REG_EFL] &= ~0x100; /* clear single-step flag */ ctx->uc_mcontext.gregs[REG_RIP] = (ULONG64)__wine_syscall_dispatcher_prolog_end; } + +static struct +{ + unsigned int win_syscall_nr; + unsigned int wine_syscall_nr; + void *function; +} +syscall_nr_translation[] = +{ + {0x19, ~0u, NtQueryInformationProcess}, + {0x36, ~0u, NtQuerySystemInformation}, + {0xec, ~0u, NtGetContextThread}, + {0x55, ~0u, NtCreateFile}, + {0x08, ~0u, NtWriteFile}, + {0x06, ~0u, NtReadFile}, + {0x0f, ~0u, NtClose}, + {0x23, ~0u, NtQueryVirtualMemory}, +}; + +static void sigsys_handler_rdr2( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + ucontext_t *ctx = sigcontext; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(syscall_nr_translation); ++i) + { + if (ctx->uc_mcontext.gregs[REG_RAX] == syscall_nr_translation[i].win_syscall_nr) + { + ctx->uc_mcontext.gregs[REG_RAX] = syscall_nr_translation[i].wine_syscall_nr; + sigsys_handler( signal, siginfo, sigcontext ); + return; + } + } + + if (ctx->uc_mcontext.gregs[REG_RAX] == 0xffff) + sigsys_handler( signal, siginfo, sigcontext ); + else + FIXME_(seh)("Unhandled syscall %#llx.\n", ctx->uc_mcontext.gregs[REG_RAX]); +} #endif #ifdef HAVE_SECCOMP @@ -1946,6 +1985,7 @@ static void install_bpf(struct sigaction *sig_act) long (WINAPI *test_syscall)(long sc_number); struct syscall_frame *frame = amd64_thread_data()->syscall_frame; struct sock_fprog prog; + unsigned int i, j; NTSTATUS status; if ((ULONG_PTR)sc_seccomp < NATIVE_SYSCALL_ADDRESS_START @@ -1960,6 +2000,28 @@ static void install_bpf(struct sigaction *sig_act) sig_act->sa_sigaction = sigsys_handler; memset(&prog, 0, sizeof(prog)); + { + const char *sgi = getenv("SteamGameId"); + if (sgi && (!strcmp(sgi, "1174180") || !strcmp(sgi, "1404210"))) + { + /* Use specific signal handler. */ + sig_act->sa_sigaction = sigsys_handler_rdr2; + + for (i = 0; i < KeServiceDescriptorTable->ServiceLimit; ++i) + { + for (j = 0; j < ARRAY_SIZE(syscall_nr_translation); ++j) + if ((void *)KeServiceDescriptorTable->ServiceTable[i] == syscall_nr_translation[j].function) + { + syscall_nr_translation[j].wine_syscall_nr = i; + break; + } + } + + for (j = 0; j < ARRAY_SIZE(syscall_nr_translation); ++j) + assert( syscall_nr_translation[j].wine_syscall_nr != ~0u ); + } + } + sigaction(SIGSYS, sig_act, NULL); frame->syscall_flags = syscall_flags; From 0a424564fc63420a50473ee825bad46631fc6c0c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 14 Sep 2021 23:03:54 +0300 Subject: [PATCH 0531/2777] Bump current build number to 18363 (Win10 1909). CW-Bug-Id: #19427 For DeathLoop. --- dlls/kernel32/version.rc | 8 ++++---- dlls/kernelbase/version.c | 2 +- dlls/ntdll/unix/signal_x86_64.c | 2 +- dlls/ntdll/version.c | 2 +- loader/wine.inf.in | 8 ++++---- programs/wineboot/wineboot.c | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/dlls/kernel32/version.rc b/dlls/kernel32/version.rc index b6002f51f7a..c58acb8a8b6 100644 --- a/dlls/kernel32/version.rc +++ b/dlls/kernel32/version.rc @@ -26,9 +26,9 @@ LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT #define WINE_FILENAME_STR "kernel32.dll" /* these values come from Windows 10 Version 1909 */ -#define WINE_FILEVERSION 10,0,18362,1350 -#define WINE_FILEVERSION_STR "10.0.18362.1350" -#define WINE_PRODUCTVERSION 10,0,18362,1350 -#define WINE_PRODUCTVERSION_STR "10.0.18362.1350" +#define WINE_FILEVERSION 10,0,18363,900 +#define WINE_FILEVERSION_STR "10.0.18363.900" +#define WINE_PRODUCTVERSION 10,0,18363,900 +#define WINE_PRODUCTVERSION_STR "10.0.18363.900" #include "wine/wine_common_ver.rc" diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c index 874798ff17d..6e74aae6c2b 100644 --- a/dlls/kernelbase/version.c +++ b/dlls/kernelbase/version.c @@ -158,7 +158,7 @@ static const struct }, /* Windows 10 */ { - { 10, 0, 18362 }, + { 10, 0, 0x47bb }, {0x8e0f7a12,0xbfb3,0x4fe8,{0xb9,0xa5,0x48,0xfd,0x50,0xa1,0x5a,0x9a}} } }; diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index a001f5c0113..ead69ed2ef6 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1878,7 +1878,7 @@ syscall_nr_translation[] = { {0x19, ~0u, NtQueryInformationProcess}, {0x36, ~0u, NtQuerySystemInformation}, - {0xec, ~0u, NtGetContextThread}, + {0xed, ~0u, NtGetContextThread}, {0x55, ~0u, NtCreateFile}, {0x08, ~0u, NtWriteFile}, {0x06, ~0u, NtReadFile}, diff --git a/dlls/ntdll/version.c b/dlls/ntdll/version.c index 410a091d6f6..79e2f46ed18 100644 --- a/dlls/ntdll/version.c +++ b/dlls/ntdll/version.c @@ -167,7 +167,7 @@ static const RTL_OSVERSIONINFOEXW VersionData[NB_WINDOWS_VERSIONS] = }, /* WIN10 */ { - sizeof(RTL_OSVERSIONINFOEXW), 10, 0, 18362, VER_PLATFORM_WIN32_NT, + sizeof(RTL_OSVERSIONINFOEXW), 10, 0, 0x47bb, VER_PLATFORM_WIN32_NT, L"", 0, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0 }, diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 7825d886f92..12e157773c4 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2484,8 +2484,8 @@ HKLM,%CurrentVersionNT%,"CurrentVersion",2,"10.0" HKLM,%CurrentVersionNT%,"CurrentMajorVersionNumber",0x10001,10 HKLM,%CurrentVersionNT%,"CurrentMinorVersionNumber",0x10001,0 HKLM,%CurrentVersionNT%,"CSDVersion",2,"" -HKLM,%CurrentVersionNT%,"CurrentBuild",2,"17763" -HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"17763" +HKLM,%CurrentVersionNT%,"CurrentBuild",2,"18363" +HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"18363" HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ @@ -2502,8 +2502,8 @@ HKLM,%Control%\Session Manager\Environment,"OS",2,"Windows_NT" [VersionInfo.ntamd64] HKLM,%CurrentVersionNT%,"CurrentVersion",2,"10.0" HKLM,%CurrentVersionNT%,"CSDVersion",2,"" -HKLM,%CurrentVersionNT%,"CurrentBuild",2,"17763" -HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"17763" +HKLM,%CurrentVersionNT%,"CurrentBuild",2,"18363" +HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"18363" HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c index 8cd230afea8..84c5487ce12 100644 --- a/programs/wineboot/wineboot.c +++ b/programs/wineboot/wineboot.c @@ -1587,7 +1587,7 @@ static void update_user_profile(void) static void update_win_version(void) { - static const WCHAR win10_buildW[] = L"17763"; + static const WCHAR win10_buildW[] = L"18363"; HKEY cv_h; DWORD type, sz; From 36c2c1adfe6f3a2aa361569fc9327bed35e9f780 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 29 Sep 2021 14:39:06 +0300 Subject: [PATCH 0532/2777] wine.inf: Add ReleaseId value to %CurrentVersionNT%. CW-Bug-Id: #19484 --- loader/wine.inf.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 12e157773c4..fdf426546e3 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2495,6 +2495,7 @@ HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 HKLM,%CurrentVersionNT%,"ProductName",2,"Microsoft Windows 10" +HKLM,%CurrentVersionNT%,"ReleaseId",,"1909" HKLM,%Control%\ProductOptions,"ProductType",2,"WinNT" HKLM,%Control%\Windows,"CSDVersion",0x10003,0x0 HKLM,%Control%\Session Manager\Environment,"OS",2,"Windows_NT" @@ -2513,6 +2514,7 @@ HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 HKLM,%CurrentVersionNT%,"ProductName",2,"Microsoft Windows 10" +HKLM,%CurrentVersionNT%,"ReleaseId",,"1909" HKLM,%Control%\ProductOptions,"ProductType",2,"WinNT" HKLM,%Control%\Windows,"CSDVersion",0x10003,0x0 HKLM,%Control%\Session Manager\Environment,"OS",2,"Windows_NT" From 7cd05a3b9bde2533d167c1b6f1f9d83676c23229 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 10 Nov 2021 20:30:40 +0300 Subject: [PATCH 0533/2777] wine.inf: HACK: Spoof Win81 for msedgewebview2.exe. A proper fix depends on other process window Vulkan rendering and Direct Compositing implementation. CW-Bug-ID: #19618 For FH5. --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index fdf426546e3..7b725d7ac5f 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2774,6 +2774,7 @@ HKCU,Software\Wine\AppDefaults\DIRT5.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\Paradox Launcher.exe\DllOverrides,,4, 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" HKCU,Software\Wine\AppDefaults\GW2.Main_Win64_Retail.exe\DllOverrides,"atiadlxx",,"builtin" From 0fa76dd66a8f35716e5c3b3cd5612e9c00c0bbd8 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 14 Jan 2022 11:46:04 +0300 Subject: [PATCH 0534/2777] Bump current build number to 19043 (Win10 2009). --- dlls/kernel32/version.rc | 10 +++++----- dlls/kernelbase/version.c | 2 +- dlls/ntdll/unix/signal_x86_64.c | 3 ++- dlls/ntdll/version.c | 2 +- loader/wine.inf.in | 14 ++++++++------ programs/wineboot/wineboot.c | 2 +- 6 files changed, 18 insertions(+), 15 deletions(-) diff --git a/dlls/kernel32/version.rc b/dlls/kernel32/version.rc index c58acb8a8b6..f91262dfa8e 100644 --- a/dlls/kernel32/version.rc +++ b/dlls/kernel32/version.rc @@ -25,10 +25,10 @@ LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT #define WINE_FILEDESCRIPTION_STR "Wine kernel DLL" #define WINE_FILENAME_STR "kernel32.dll" -/* these values come from Windows 10 Version 1909 */ -#define WINE_FILEVERSION 10,0,18363,900 -#define WINE_FILEVERSION_STR "10.0.18363.900" -#define WINE_PRODUCTVERSION 10,0,18363,900 -#define WINE_PRODUCTVERSION_STR "10.0.18363.900" +/* these values come from Windows 10 Version 2009 */ +#define WINE_FILEVERSION 10,0,19043,1466 +#define WINE_FILEVERSION_STR "10.0.19043.1466" +#define WINE_PRODUCTVERSION 10,0,19043,1466 +#define WINE_PRODUCTVERSION_STR "10.0.19043.1466" #include "wine/wine_common_ver.rc" diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c index 6e74aae6c2b..e1336130b01 100644 --- a/dlls/kernelbase/version.c +++ b/dlls/kernelbase/version.c @@ -158,7 +158,7 @@ static const struct }, /* Windows 10 */ { - { 10, 0, 0x47bb }, + { 10, 0, 0x4a63 }, {0x8e0f7a12,0xbfb3,0x4fe8,{0xb9,0xa5,0x48,0xfd,0x50,0xa1,0x5a,0x9a}} } }; diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index ead69ed2ef6..65d00b32bf6 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1868,6 +1868,7 @@ static void sigsys_handler( int signal, siginfo_t *siginfo, void *sigcontext ) ctx->uc_mcontext.gregs[REG_RIP] = (ULONG64)__wine_syscall_dispatcher_prolog_end; } +/* syscall numbers are for Windows 10 2009 (build 19043) */ static struct { unsigned int win_syscall_nr; @@ -1878,7 +1879,7 @@ syscall_nr_translation[] = { {0x19, ~0u, NtQueryInformationProcess}, {0x36, ~0u, NtQuerySystemInformation}, - {0xed, ~0u, NtGetContextThread}, + {0xf2, ~0u, NtGetContextThread}, {0x55, ~0u, NtCreateFile}, {0x08, ~0u, NtWriteFile}, {0x06, ~0u, NtReadFile}, diff --git a/dlls/ntdll/version.c b/dlls/ntdll/version.c index 79e2f46ed18..4e6a34fca27 100644 --- a/dlls/ntdll/version.c +++ b/dlls/ntdll/version.c @@ -167,7 +167,7 @@ static const RTL_OSVERSIONINFOEXW VersionData[NB_WINDOWS_VERSIONS] = }, /* WIN10 */ { - sizeof(RTL_OSVERSIONINFOEXW), 10, 0, 0x47bb, VER_PLATFORM_WIN32_NT, + sizeof(RTL_OSVERSIONINFOEXW), 10, 0, 0x4a63, VER_PLATFORM_WIN32_NT, L"", 0, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0 }, diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 7b725d7ac5f..302ec4bd2a9 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2484,8 +2484,8 @@ HKLM,%CurrentVersionNT%,"CurrentVersion",2,"10.0" HKLM,%CurrentVersionNT%,"CurrentMajorVersionNumber",0x10001,10 HKLM,%CurrentVersionNT%,"CurrentMinorVersionNumber",0x10001,0 HKLM,%CurrentVersionNT%,"CSDVersion",2,"" -HKLM,%CurrentVersionNT%,"CurrentBuild",2,"18363" -HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"18363" +HKLM,%CurrentVersionNT%,"CurrentBuild",2,"19043" +HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"19043" HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ @@ -2494,8 +2494,9 @@ HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 +HKLM,%CurrentVersionNT%,"DisplayVersion",2,"21H1" HKLM,%CurrentVersionNT%,"ProductName",2,"Microsoft Windows 10" -HKLM,%CurrentVersionNT%,"ReleaseId",,"1909" +HKLM,%CurrentVersionNT%,"ReleaseId",,"2009" HKLM,%Control%\ProductOptions,"ProductType",2,"WinNT" HKLM,%Control%\Windows,"CSDVersion",0x10003,0x0 HKLM,%Control%\Session Manager\Environment,"OS",2,"Windows_NT" @@ -2503,8 +2504,8 @@ HKLM,%Control%\Session Manager\Environment,"OS",2,"Windows_NT" [VersionInfo.ntamd64] HKLM,%CurrentVersionNT%,"CurrentVersion",2,"10.0" HKLM,%CurrentVersionNT%,"CSDVersion",2,"" -HKLM,%CurrentVersionNT%,"CurrentBuild",2,"18363" -HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"18363" +HKLM,%CurrentVersionNT%,"CurrentBuild",2,"19043" +HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"19043" HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ @@ -2513,8 +2514,9 @@ HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 +HKLM,%CurrentVersionNT%,"DisplayVersion",2,"21H1" HKLM,%CurrentVersionNT%,"ProductName",2,"Microsoft Windows 10" -HKLM,%CurrentVersionNT%,"ReleaseId",,"1909" +HKLM,%CurrentVersionNT%,"ReleaseId",,"2009" HKLM,%Control%\ProductOptions,"ProductType",2,"WinNT" HKLM,%Control%\Windows,"CSDVersion",0x10003,0x0 HKLM,%Control%\Session Manager\Environment,"OS",2,"Windows_NT" diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c index 84c5487ce12..d10705a0819 100644 --- a/programs/wineboot/wineboot.c +++ b/programs/wineboot/wineboot.c @@ -1587,7 +1587,7 @@ static void update_user_profile(void) static void update_win_version(void) { - static const WCHAR win10_buildW[] = L"18363"; + static const WCHAR win10_buildW[] = L"19043"; HKEY cv_h; DWORD type, sz; From 0ce02051dbc22fd2c7a42a0f4305c09273aa10d3 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Sat, 18 Dec 2021 00:24:39 +0300 Subject: [PATCH 0535/2777] ntdll: Change module search order in LdrFindEntryForAddress(). CW-Bug-Id: #19827 To be dropped once we have module search tree implementation. --- dlls/ntdll/loader.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index a331c84635e..2801227d518 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -1803,10 +1803,10 @@ NTSTATUS WINAPI LdrFindEntryForAddress( const void *addr, PLDR_DATA_TABLE_ENTRY PLIST_ENTRY mark, entry; PLDR_DATA_TABLE_ENTRY mod; - mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList; - for (entry = mark->Flink; entry != mark; entry = entry->Flink) + mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; + for (entry = mark->Blink; entry != mark; entry = entry->Blink) { - mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); + mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); if (mod->DllBase <= addr && (const char *)addr < (char*)mod->DllBase + mod->SizeOfImage) { From 96b05bf5eaacb8ec76991711d21132c15eadbe9a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 4 Jan 2022 17:41:46 +0300 Subject: [PATCH 0536/2777] advapi32: Initialize computer SID from registry. CW-Bug-Id: #19702 --- dlls/advapi32/security.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/dlls/advapi32/security.c b/dlls/advapi32/security.c index 599199c325c..2072608c94b 100644 --- a/dlls/advapi32/security.c +++ b/dlls/advapi32/security.c @@ -244,12 +244,42 @@ BOOL ADVAPI_IsLocalComputer(LPCWSTR ServerName) return Result; } +static BOOL WINAPI init_computer_sid( INIT_ONCE *init_once, void *parameter, void **context ) +{ + DWORD *sub_authority = parameter; + unsigned int i, count; + DWORD len, index; + BOOL found = FALSE; + DWORD values[3]; + char buffer[64]; + LSTATUS status; + + len = ARRAY_SIZE(buffer); + index = 0; + while (!(status = RegEnumKeyExA( HKEY_USERS, index, buffer, &len, NULL, NULL, NULL, NULL ))) + { + count = sscanf(buffer, "S-1-5-21-%lu-%lu-%lu", &values[0], &values[1], &values[2]); + if (count == 3) + { + if (found) + ERR( "Multiple users are not supported.\n" ); + for (i = 0; i < 3; ++i) + sub_authority[i] = values[i]; + found = TRUE; + } + ++index; + len = ARRAY_SIZE(buffer); + } + return found; +} + /************************************************************ * ADVAPI_GetComputerSid */ BOOL ADVAPI_GetComputerSid(PSID sid) { - static const struct /* same fields as struct SID */ + static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; + static struct /* same fields as struct SID */ { BYTE Revision; BYTE SubAuthorityCount; @@ -258,6 +288,9 @@ BOOL ADVAPI_GetComputerSid(PSID sid) } computer_sid = { SID_REVISION, 4, { SECURITY_NT_AUTHORITY }, { SECURITY_NT_NON_UNIQUE, 0, 0, 0 } }; + if (!InitOnceExecuteOnce( &init_once, init_computer_sid, computer_sid.SubAuthority + 1, NULL )) + ERR( "Could not initialize computer sid.\n" ); + memcpy( sid, &computer_sid, sizeof(computer_sid) ); return TRUE; } From 27e416884eac939fdca9ed32a3202b8b2f7b1754 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 4 Jan 2022 17:42:35 +0300 Subject: [PATCH 0537/2777] sechost: Initialize computer SID from registry. CW-Bug-Id: #19702 --- dlls/sechost/security.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/dlls/sechost/security.c b/dlls/sechost/security.c index 88f5aa7f5ae..f5a56b13922 100644 --- a/dlls/sechost/security.c +++ b/dlls/sechost/security.c @@ -581,9 +581,39 @@ BOOL WINAPI DECLSPEC_HOTPATCH ConvertSecurityDescriptorToStringSecurityDescripto return TRUE; } +static BOOL WINAPI init_computer_sid( INIT_ONCE *init_once, void *parameter, void **context ) +{ + DWORD *sub_authority = parameter; + unsigned int i, count; + DWORD len, index; + BOOL found = FALSE; + UINT values[3]; + char buffer[64]; + LSTATUS status; + + len = ARRAY_SIZE(buffer); + index = 0; + while (!(status = RegEnumKeyExA( HKEY_USERS, index, buffer, &len, NULL, NULL, NULL, NULL ))) + { + count = sscanf(buffer, "S-1-5-21-%u-%u-%u", &values[0], &values[1], &values[2]); + if (count == 3) + { + if (found) + ERR( "Multiple users are not supported.\n" ); + for (i = 0; i < 3; ++i) + sub_authority[i] = values[i]; + found = TRUE; + } + ++index; + len = ARRAY_SIZE(buffer); + } + return found; +} + static BOOL get_computer_sid( PSID sid ) { - static const struct /* same fields as struct SID */ + static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; + static struct /* same fields as struct SID */ { BYTE Revision; BYTE SubAuthorityCount; @@ -592,6 +622,9 @@ static BOOL get_computer_sid( PSID sid ) } computer_sid = { SID_REVISION, 4, { SECURITY_NT_AUTHORITY }, { SECURITY_NT_NON_UNIQUE, 0, 0, 0 } }; + if (!InitOnceExecuteOnce( &init_once, init_computer_sid, computer_sid.SubAuthority + 1, NULL )) + ERR( "Could not initialize computer sid.\n" ); + memcpy( sid, &computer_sid, sizeof(computer_sid) ); return TRUE; } From 9162ee864a435f806e8a2cb64dcb52c2ece282fb Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 22 Dec 2021 00:52:53 +0300 Subject: [PATCH 0538/2777] server: Initialize local user SID with unique values. CW-Bug-Id: #19702 --- server/main.c | 2 ++ server/security.h | 4 +++- server/token.c | 35 ++++++++++++++++++++++++++++++++++- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/server/main.c b/server/main.c index 4de74ebe7ac..898e9af202d 100644 --- a/server/main.c +++ b/server/main.c @@ -34,6 +34,7 @@ #include "thread.h" #include "request.h" #include "unicode.h" +#include "security.h" #include "esync.h" #include "fsync.h" @@ -243,6 +244,7 @@ int main( int argc, char *argv[] ) if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() ); set_current_time(); init_signals(); + init_user_sid(); init_directories( load_intl_file() ); init_threading(); init_registry(); diff --git a/server/security.h b/server/security.h index 58ab1594eae..8bba8c59565 100644 --- a/server/security.h +++ b/server/security.h @@ -45,7 +45,7 @@ extern const struct luid SeImpersonatePrivilege; extern const struct luid SeCreateGlobalPrivilege; extern const struct sid world_sid; -extern const struct sid local_user_sid; +extern struct sid local_user_sid; extern const struct sid local_system_sid; extern const struct sid builtin_users_sid; extern const struct sid builtin_admins_sid; @@ -60,6 +60,7 @@ struct ace unsigned int mask; }; + /* token functions */ extern struct token *get_token_obj( struct process *process, obj_handle_t handle, unsigned int access ); @@ -122,6 +123,7 @@ static inline struct ace *set_ace( struct ace *ace, const struct sid *sid, unsig extern void security_set_thread_token( struct thread *thread, obj_handle_t handle ); extern const struct sid *security_unix_uid_to_sid( uid_t uid ); +extern void init_user_sid(void); extern int check_object_access( struct token *token, struct object *obj, unsigned int *access ); static inline int thread_single_check_privilege( struct thread *thread, struct luid priv ) diff --git a/server/token.c b/server/token.c index f9ee2b61398..6ab8848230f 100644 --- a/server/token.c +++ b/server/token.c @@ -23,11 +23,15 @@ #include "config.h" #include +#include #include #include #include #include #include +#ifdef HAVE_STDINT_H +#include +#endif #include "ntstatus.h" #define WIN32_NO_STATUS @@ -73,7 +77,7 @@ struct sid_attrs const struct sid world_sid = { SID_REVISION, 1, SECURITY_WORLD_SID_AUTHORITY, { SECURITY_WORLD_RID } }; const struct sid local_system_sid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_LOCAL_SYSTEM_RID } }; const struct sid high_label_sid = { SID_REVISION, 1, SECURITY_MANDATORY_LABEL_AUTHORITY, { SECURITY_MANDATORY_HIGH_RID } }; -const struct sid local_user_sid = { SID_REVISION, 5, SECURITY_NT_AUTHORITY, { SECURITY_NT_NON_UNIQUE, 0, 0, 0, 1000 } }; + struct sid local_user_sid = { SID_REVISION, 5, SECURITY_NT_AUTHORITY, { SECURITY_NT_NON_UNIQUE, 0, 0, 0, 1000 } }; const struct sid builtin_admins_sid = { SID_REVISION, 2, SECURITY_NT_AUTHORITY, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS } }; const struct sid builtin_users_sid = { SID_REVISION, 2, SECURITY_NT_AUTHORITY, { SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS } }; const struct sid domain_users_sid = { SID_REVISION, 5, SECURITY_NT_AUTHORITY, { SECURITY_NT_NON_UNIQUE, 0, 0, 0, DOMAIN_GROUP_RID_USERS } }; @@ -201,6 +205,35 @@ const struct sid *security_unix_uid_to_sid( uid_t uid ) return &anonymous_logon_sid; } +void init_user_sid(void) +{ + char machine_id[17]; + uint64_t id; + size_t n; + FILE *f; + + f = fopen( "/etc/machine-id", "r" ); + if (!f) + { + fprintf( stderr, "Failed to open /etc/machine-id, error %s.\n", strerror( errno )); + return; + } + + n = fread( machine_id, sizeof(*machine_id), 16, f ); + fclose(f); + + if (n != 16) + { + fprintf( stderr, "Failed to read /etc/machine-id, error %s.\n", strerror( errno )); + return; + } + machine_id[n] = 0; + id = strtoull( machine_id, NULL, 0x10 ); + local_user_sid.sub_auth[1] = id >> 32; + local_user_sid.sub_auth[2] = id & 0xffffffff; + local_user_sid.sub_auth[3] = getuid(); +} + static int acl_is_valid( const struct acl *acl, data_size_t size ) { ULONG i; From 1b13f01ad0d01dbb27d9f8f45de2409180817444 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 22 Dec 2021 00:57:25 +0300 Subject: [PATCH 0539/2777] wine.inf: Set a valid Win10 ProductId. CW-Bug-Id: #19702 --- loader/wine.inf.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 302ec4bd2a9..7e87d964614 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -358,7 +358,7 @@ HKCU,%CurrentVersion%\Run,,16 HKCU,%CurrentVersionNT%\Winlogon,,16 HKLM,%CurrentVersion%,"CommonFilesDir",,"%16427%" HKLM,%CurrentVersion%,"FirstInstallDateTime",1,21,81,7c,23 -HKLM,%CurrentVersion%,"ProductId",,"12345-oem-0000001-54321" +HKLM,%CurrentVersion%,"ProductId",,"00330-50000-00000-AAOEM" HKLM,%CurrentVersion%,"ProgramFilesDir",,"%16422%" HKLM,%CurrentVersion%,"ProgramFilesPath",0x20000,"%%ProgramFiles%%" HKLM,%CurrentVersion%,"RegisteredOrganization",2,"" @@ -383,7 +383,7 @@ HKLM,%CurrentVersion%\Shell Extensions\Approved,,16 HKLM,%CurrentVersion%\Time Zones,"SymbolicLinkValue",0x60000,"\Registry\Machine\%CurrentVersionNT%\Time Zones" HKLM,%CurrentVersion%\Uninstall,,16 HKLM,%CurrentVersionNT%,"InstallDate",0x10003,1273299354 -HKLM,%CurrentVersionNT%,"ProductId",,"12345-oem-0000001-54321" +HKLM,%CurrentVersionNT%,"ProductId",,"00330-50000-00000-AAOEM" HKLM,%CurrentVersionNT%,"RegisteredOrganization",2,"" HKLM,%CurrentVersionNT%,"RegisteredOwner",2,"" HKLM,%CurrentVersionNT%,"SystemRoot",,"%10%" From b5f8db7f98ffffd39f5544f9ef58daef8a6db108 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 22 Dec 2021 00:59:32 +0300 Subject: [PATCH 0540/2777] wineboot: Generate better DigitalProductId. CW-Bug-Id: #19702 --- loader/wine.inf.in | 4 +-- programs/wineboot/wineboot.c | 48 ++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 7e87d964614..5e21b6d38ed 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2487,7 +2487,7 @@ HKLM,%CurrentVersionNT%,"CSDVersion",2,"" HKLM,%CurrentVersionNT%,"CurrentBuild",2,"19043" HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"19043" HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" -HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ +HKLM,%CurrentVersionNT%,"DigitalProductId",2,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ @@ -2507,7 +2507,7 @@ HKLM,%CurrentVersionNT%,"CSDVersion",2,"" HKLM,%CurrentVersionNT%,"CurrentBuild",2,"19043" HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"19043" HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" -HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ +HKLM,%CurrentVersionNT%,"DigitalProductId",2,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c index d10705a0819..ee9660af80b 100644 --- a/programs/wineboot/wineboot.c +++ b/programs/wineboot/wineboot.c @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -1777,6 +1778,52 @@ static void usage( int status ) exit( status ); } +static void create_digitalproductid(void) +{ + BYTE digital_product_id[0xa4]; + char product_id[256]; + LSTATUS status; + unsigned int i; + DWORD size; + DWORD type; + HKEY key; + + if ((status = RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion", + 0, KEY_ALL_ACCESS, &key ))) + return; + size = sizeof(product_id); + status = RegQueryValueExA( key, "ProductId", NULL, &type, (BYTE *)product_id, &size ); + if (status) goto done; + if (!size) goto done; + if (product_id[size - 1]) + { + if (size == sizeof(product_id)) goto done; + product_id[size++] = 0; + } + + if (!RegQueryValueExA( key, "DigitalProductId", NULL, &type, NULL, &size ) && size == sizeof(digital_product_id)) + { + if (RegQueryValueExA( key, "DigitalProductId", NULL, &type, digital_product_id, &size )) + goto done; + for (i = 0; i < size; ++i) + if (digital_product_id[i]) break; + if (i < size) goto done; + } + + memset( digital_product_id, 0, sizeof(digital_product_id) ); + *(DWORD *)digital_product_id = sizeof(digital_product_id); + digital_product_id[4] = 3; + strcpy( (char *)digital_product_id + 8, product_id ); + *(DWORD *)(digital_product_id + 0x20) = 0x0cec; + *(DWORD *)(digital_product_id + 0x34) = 0x0cec; + strcpy( (char *)digital_product_id + 0x24, "[TH] X19-99481" ); + digital_product_id[0x42] = 8; + RtlGenRandom( digital_product_id + 0x38, 0x18 ); + RegSetValueExA( key, "DigitalProductId", 0, REG_BINARY, digital_product_id, sizeof(digital_product_id) ); +done: + RegCloseKey( key ); +} + int __cdecl main( int argc, char *argv[] ) { /* First, set the current directory to SystemRoot */ @@ -1889,6 +1936,7 @@ int __cdecl main( int argc, char *argv[] ) } if (init || update) update_wineprefix( update ); + create_digitalproductid(); create_volatile_environment_registry_key(); ProcessRunKeys( HKEY_LOCAL_MACHINE, L"RunOnce", TRUE, TRUE ); From f484fd72a4735d4f6c9b9de04bbea493cfe54bd4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 1 Apr 2022 17:39:50 +0300 Subject: [PATCH 0541/2777] msvcrt: HACK: Introduce asm wrapper for _isatty on x64. CW-Bug-Id: #20419 --- dlls/msvcrt/file.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dlls/msvcrt/file.c b/dlls/msvcrt/file.c index e72784eef41..8a9c89b9be5 100644 --- a/dlls/msvcrt/file.c +++ b/dlls/msvcrt/file.c @@ -44,6 +44,7 @@ #include "mtdll.h" #include "wine/debug.h" +#include "wine/asm.h" WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); @@ -818,12 +819,28 @@ static int msvcrt_flush_buffer(FILE* file) /********************************************************************* * _isatty (MSVCRT.@) */ +#ifdef __x86_64__ +int CDECL MSVCRT__isatty(int fd) +{ + TRACE(":fd (%d)\n",fd); + + return get_ioinfo_nolock(fd)->wxflag & WX_TTY; +} +__ASM_GLOBAL_FUNC( _isatty, + "sub $0x30,%rsp\n\t" + "lea MSVCRT___pioinfo(%rip),%rdx\n\t" + "nop;nop;nop;nop;nop;nop;nop;nop;nop\n\t" + "add $0x30,%rsp\n\t" + "jmp " __ASM_NAME( "MSVCRT__isatty" ) ) +#else int CDECL _isatty(int fd) { TRACE(":fd (%d)\n",fd); return get_ioinfo_nolock(fd)->wxflag & WX_TTY; } +#endif + /* INTERNAL: Allocate stdio file buffer */ static BOOL msvcrt_alloc_buffer(FILE* file) From f95c93b63fef3376973b993363b62573c50e7031 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Thu, 30 Sep 2021 14:38:33 +0200 Subject: [PATCH 0542/2777] sechost: Fake presence of BEService service for ARK: Survival Evolved. The game uses the presence and status of BEService to determine whether or not the game is running in BattlEye. Since with the Proton Bridge we don't have a dedicated background service, we can just pretend the service is always running. CW-Bug-Id: #16650 --- dlls/sechost/service.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/dlls/sechost/service.c b/dlls/sechost/service.c index 011533b883e..dfa1634db07 100644 --- a/dlls/sechost/service.c +++ b/dlls/sechost/service.c @@ -315,6 +315,8 @@ SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenServiceW( SC_HANDLE manager, const WCHAR SC_RPC_HANDLE handle = NULL; DWORD err; + char str[64]; + TRACE( "%p %s %#lx\n", manager, debugstr_w(name), access ); if (!manager) @@ -323,6 +325,14 @@ SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenServiceW( SC_HANDLE manager, const WCHAR return NULL; } + /* HACK for ARK: Survivial Evolved checking the status of BEService to determine whether BE is enabled. */ + if(GetEnvironmentVariableA("SteamGameId", str, sizeof(str)) && !strcmp(str, "346110") && + !wcscmp(name, L"BEService")) + { + WARN("HACK: returning fake service handle for BEService.\n"); + return (void *)0xdeadbeef; + } + __TRY { err = svcctl_OpenServiceW( manager, name, access, &handle ); @@ -1107,6 +1117,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceStatusEx( SC_HANDLE service, SC_STATUS { DWORD err; + char str[64]; + TRACE( "%p %d %p %ld %p\n", service, level, buffer, size, ret_size ); if (level != SC_STATUS_PROCESS_INFO) return set_error( ERROR_INVALID_LEVEL ); @@ -1117,6 +1129,24 @@ BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceStatusEx( SC_HANDLE service, SC_STATUS return set_error( ERROR_INSUFFICIENT_BUFFER ); } + /* HACK for ARK: Survivial Evolved checking the status of BEService to determine whether BE is enabled. */ + if(GetEnvironmentVariableA("SteamGameId", str, sizeof(str)) && !strcmp(str, "346110") && + service == (void *)0xdeadbeef) + { + SERVICE_STATUS_PROCESS *status = (SERVICE_STATUS_PROCESS *)buffer; + WARN("HACK: returning fake data for BEService.\n"); + status->dwServiceType = SERVICE_WIN32_OWN_PROCESS; + status->dwCurrentState = SERVICE_RUNNING; + status->dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP; + status->dwWin32ExitCode = NO_ERROR; + status->dwServiceSpecificExitCode = 0; + status->dwCheckPoint = 0; + status->dwWaitHint = 0; + status->dwProcessId = 0xdeadbee0; + status->dwServiceFlags = 0; + return TRUE; + } + __TRY { err = svcctl_QueryServiceStatusEx( service, level, buffer, size, ret_size ); From e47b94164b6dd326fdaac83ab5a2e2cd60a630c6 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Tue, 22 Feb 2022 13:12:09 -0500 Subject: [PATCH 0543/2777] Fall Guys EOS overlay in process GPU. --- dlls/kernelbase/process.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index b72506a2063..a332bce17e7 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -602,6 +602,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"Montaro\\nw.exe", L" --use-gl=swiftshader"}, + {L"EOSOverlayRenderer-Win64-Shipping.exe", L" --use-gl=swiftshader --in-process-gpu"}, {L"EpicOnlineServicesUIHelper", L" --use-gl=desktop"}, }; unsigned int i; From de40c52f997ce146aa365b86f1d1b4e63e92ba8a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 8 Apr 2022 20:35:03 +0300 Subject: [PATCH 0544/2777] wined3d: Post WM_ACTIVATEAPP upon receiving WM_SIZE in device_process_message(). CW-Bug-Id: #20422 --- dlls/wined3d/device.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index b294af3c5fa..d5ae5dc1fcc 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -6236,6 +6236,11 @@ LRESULT device_process_message(struct wined3d_device *device, HWND window, BOOL DefWindowProcA(window, message, wparam, lparam); } } + else if (message == WM_SIZE) + { + if (!IsIconic(window)) + PostMessageW(window, WM_ACTIVATEAPP, 1, GetCurrentThreadId()); + } if (unicode) return CallWindowProcW(proc, window, message, wparam, lparam); From c70622fa7e73c4a9c7fcf203a05cb12baa622e70 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 8 Apr 2022 20:34:07 +0300 Subject: [PATCH 0545/2777] wined3d: Ignore multiple app activation messages in device_process_message(). CW-Bug-Id: #20422 CW-Bug-Id: #21462 --- dlls/wined3d/device.c | 13 +++++-- dlls/wined3d/wined3d_main.c | 71 ++++++++++++++++++++++++++++++++++ dlls/wined3d/wined3d_private.h | 6 +++ 3 files changed, 87 insertions(+), 3 deletions(-) diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index d5ae5dc1fcc..e50ef5112b5 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -6213,7 +6213,10 @@ LRESULT device_process_message(struct wined3d_device *device, HWND window, BOOL } else if (message == WM_DISPLAYCHANGE) { + BOOL inside_mode_change = wined3d_set_inside_mode_change(window, TRUE); + device->device_parent->ops->mode_changed(device->device_parent); + wined3d_set_inside_mode_change(window, inside_mode_change); } else if (message == WM_ACTIVATEAPP) { @@ -6223,8 +6226,12 @@ LRESULT device_process_message(struct wined3d_device *device, HWND window, BOOL * (e.g. Deus Ex: GOTY) to destroy the device, so take care to * deactivate the implicit swapchain last, and to avoid accessing the * "device" pointer afterwards. */ - while (i--) - wined3d_swapchain_activate(device->swapchains[i], wparam); + if (!wparam || !wined3d_get_activate_processed(window)) + { + wined3d_set_activate_processed(window, !!wparam); + while (i--) + wined3d_swapchain_activate(device->swapchains[i], wparam); + } } else if (message == WM_SYSCOMMAND) { @@ -6236,7 +6243,7 @@ LRESULT device_process_message(struct wined3d_device *device, HWND window, BOOL DefWindowProcA(window, message, wparam, lparam); } } - else if (message == WM_SIZE) + else if (message == WM_SIZE && !wined3d_get_inside_mode_change(window)) { if (!IsIconic(window)) PostMessageW(window, WM_ACTIVATEAPP, 1, GetCurrentThreadId()); diff --git a/dlls/wined3d/wined3d_main.c b/dlls/wined3d/wined3d_main.c index bcaf1651db8..cbe7f65a841 100644 --- a/dlls/wined3d/wined3d_main.c +++ b/dlls/wined3d/wined3d_main.c @@ -39,6 +39,8 @@ struct wined3d_wndproc HWND window; BOOL unicode; BOOL filter; + BOOL activate_processed; + BOOL inside_mode_change; WNDPROC proc; struct wined3d_device *device; uint32_t flags; @@ -622,6 +624,73 @@ BOOL wined3d_filter_messages(HWND window, BOOL filter) return ret; } +BOOL wined3d_get_activate_processed(HWND window) +{ + struct wined3d_wndproc *entry; + BOOL ret; + + wined3d_wndproc_mutex_lock(); + + if (!(entry = wined3d_find_wndproc(window, NULL))) + { + wined3d_wndproc_mutex_unlock(); + return FALSE; + } + ret = entry->activate_processed; + wined3d_wndproc_mutex_unlock(); + return ret; +} + +void wined3d_set_activate_processed(HWND window, BOOL activate_processed) +{ + struct wined3d_wndproc *entry; + + wined3d_wndproc_mutex_lock(); + + if (!(entry = wined3d_find_wndproc(window, NULL))) + { + wined3d_wndproc_mutex_unlock(); + return; + } + entry->activate_processed = activate_processed; + wined3d_wndproc_mutex_unlock(); +} + +BOOL wined3d_get_inside_mode_change(HWND window) +{ + struct wined3d_wndproc *entry; + BOOL ret; + + wined3d_wndproc_mutex_lock(); + + if (!(entry = wined3d_find_wndproc(window, NULL))) + { + wined3d_wndproc_mutex_unlock(); + return FALSE; + } + ret = entry->inside_mode_change; + wined3d_wndproc_mutex_unlock(); + return ret; +} + +BOOL wined3d_set_inside_mode_change(HWND window, BOOL inside_mode_change) +{ + struct wined3d_wndproc *entry; + BOOL ret; + + wined3d_wndproc_mutex_lock(); + + if (!(entry = wined3d_find_wndproc(window, NULL))) + { + wined3d_wndproc_mutex_unlock(); + return FALSE; + } + ret = entry->inside_mode_change; + entry->inside_mode_change = inside_mode_change; + wined3d_wndproc_mutex_unlock(); + return ret; +} + static LRESULT CALLBACK wined3d_wndproc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) { struct wined3d_wndproc *entry; @@ -758,6 +827,8 @@ BOOL CDECL wined3d_register_window(struct wined3d *wined3d, HWND window, entry->device = device; entry->wined3d = wined3d; entry->flags = flags; + entry->activate_processed = FALSE; + entry->inside_mode_change = FALSE; wined3d_wndproc_mutex_unlock(); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 7abf77bb445..c2e28a14881 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -3796,6 +3796,12 @@ struct wined3d }; BOOL wined3d_filter_messages(HWND window, BOOL filter) DECLSPEC_HIDDEN; +BOOL wined3d_get_activate_processed(HWND window) DECLSPEC_HIDDEN; +void wined3d_set_activate_processed(HWND window, BOOL activate_processed) DECLSPEC_HIDDEN; +BOOL wined3d_get_inside_mode_change(HWND window) DECLSPEC_HIDDEN; +BOOL wined3d_set_inside_mode_change(HWND window, BOOL inside_mode_change) DECLSPEC_HIDDEN; + + HRESULT wined3d_init(struct wined3d *wined3d, uint32_t flags) DECLSPEC_HIDDEN; void wined3d_unregister_window(HWND window) DECLSPEC_HIDDEN; From 39aa8b38eb0b4195c70c93ecd1aeca9da210ba74 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 11 Nov 2022 15:44:05 -0600 Subject: [PATCH 0546/2777] gdi32: Add stub for D3DKMTEnumAdapters2(). CW-Bug-Id: #21558 --- dlls/gdi32/gdi32.spec | 1 + dlls/gdi32/objects.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/dlls/gdi32/gdi32.spec b/dlls/gdi32/gdi32.spec index d6a0ad90e1e..92b9663fde5 100644 --- a/dlls/gdi32/gdi32.spec +++ b/dlls/gdi32/gdi32.spec @@ -79,6 +79,7 @@ @ stdcall D3DKMTCreateDevice(ptr) win32u.NtGdiDdDDICreateDevice @ stdcall D3DKMTDestroyDCFromMemory(ptr) win32u.NtGdiDdDDIDestroyDCFromMemory @ stdcall D3DKMTDestroyDevice(ptr) win32u.NtGdiDdDDIDestroyDevice +@ stdcall D3DKMTEnumAdapters2(ptr) @ stdcall D3DKMTEscape(ptr) win32u.NtGdiDdDDIEscape @ stdcall D3DKMTOpenAdapterFromDeviceName(ptr) win32u.NtGdiDdDDIOpenAdapterFromDeviceName @ stdcall D3DKMTOpenAdapterFromGdiDisplayName(ptr) diff --git a/dlls/gdi32/objects.c b/dlls/gdi32/objects.c index 42bf6fcf111..24ac5b015ea 100644 --- a/dlls/gdi32/objects.c +++ b/dlls/gdi32/objects.c @@ -971,6 +971,12 @@ NTSTATUS WINAPI D3DKMTOpenAdapterFromGdiDisplayName( D3DKMT_OPENADAPTERFROMGDIDI return status; } +NTSTATUS WINAPI D3DKMTEnumAdapters2( const void *param ) +{ + FIXME( "param %p stub.\n", param ); + return STATUS_NOT_SUPPORTED; +} + /*********************************************************************** * SetObjectOwner (GDI32.@) */ From 9bb1cb8c30ae76716b9819fa777f611a470c785a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 4 Nov 2020 18:08:21 +0300 Subject: [PATCH 0547/2777] ws2_32: HACK Fail 'download-alt.easyanticheat.net' DNS name resolution. CW-Bug-Id: #16695 --- dlls/ws2_32/protocol.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/dlls/ws2_32/protocol.c b/dlls/ws2_32/protocol.c index 1f840832c7a..fb22c0b5805 100644 --- a/dlls/ws2_32/protocol.c +++ b/dlls/ws2_32/protocol.c @@ -146,6 +146,25 @@ static int dns_only_query( const char *node, const struct addrinfo *hints, struc return 0; } +static BOOL eac_download_hack(void) +{ + static int eac_download_hack_enabled = -1; + char str[64]; + + if (eac_download_hack_enabled == -1) + { + if (GetEnvironmentVariableA("WINE_DISABLE_EAC_ALT_DOWNLOAD", str, sizeof(str))) + eac_download_hack_enabled = !!atoi(str); + else + eac_download_hack_enabled = GetEnvironmentVariableA("SteamGameId", str, sizeof(str)) + && !strcmp(str, "626690"); + + if (eac_download_hack_enabled) + ERR("HACK: failing download-alt.easyanticheat.net resolution.\n"); + } + return eac_download_hack_enabled; +} + /*********************************************************************** * getaddrinfo (ws2_32.@) */ @@ -167,6 +186,12 @@ int WINAPI getaddrinfo( const char *node, const char *service, if (node) { + if (eac_download_hack() && !strcmp(node, "download-alt.easyanticheat.net")) + { + SetLastError(WSAHOST_NOT_FOUND); + return WSAHOST_NOT_FOUND; + } + if (!node[0]) { if (!(fqdn = get_fqdn())) return WSA_NOT_ENOUGH_MEMORY; @@ -925,6 +950,12 @@ struct hostent * WINAPI gethostbyname( const char *name ) return NULL; } + if (eac_download_hack() && name && !strcmp(name, "download-alt.easyanticheat.net")) + { + SetLastError( WSAHOST_NOT_FOUND ); + return NULL; + } + if ((ret = WS_CALL( gethostname, ¶ms ))) { SetLastError( ret ); From ead84c4c04b0ffda5ec47848710928cbc27aec1d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 15 Jun 2022 17:21:55 -0500 Subject: [PATCH 0548/2777] ntdll: Do not open directory file when setting the same directory path. CW-Bug-Id: #20815 --- dlls/ntdll/path.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/dlls/ntdll/path.c b/dlls/ntdll/path.c index 8956ff07f6c..da6f55ddb83 100644 --- a/dlls/ntdll/path.c +++ b/dlls/ntdll/path.c @@ -914,13 +914,13 @@ ULONG WINAPI RtlGetCurrentDirectory_U(ULONG buflen, LPWSTR buf) NTSTATUS WINAPI RtlSetCurrentDirectory_U(const UNICODE_STRING* dir) { FILE_FS_DEVICE_INFORMATION device_info; + ULONG size, compare_size; OBJECT_ATTRIBUTES attr; UNICODE_STRING newdir; IO_STATUS_BLOCK io; CURDIR *curdir; HANDLE handle; NTSTATUS nts; - ULONG size; PWSTR ptr; newdir.Buffer = NULL; @@ -938,6 +938,22 @@ NTSTATUS WINAPI RtlSetCurrentDirectory_U(const UNICODE_STRING* dir) goto out; } + size = newdir.Length / sizeof(WCHAR); + ptr = newdir.Buffer; + ptr += 4; /* skip \??\ prefix */ + size -= 4; + + if (size && ptr[size - 1] == '\\') compare_size = size - 1; + else compare_size = size; + + if (curdir->DosPath.Length == (compare_size + 1) * sizeof(WCHAR) + && !memcmp( curdir->DosPath.Buffer, ptr, compare_size * sizeof(WCHAR) )) + { + TRACE( "dir %s is the same as current.\n", debugstr_us(dir) ); + nts = STATUS_SUCCESS; + goto out; + } + attr.Length = sizeof(attr); attr.RootDirectory = 0; attr.Attributes = OBJ_CASE_INSENSITIVE; @@ -962,10 +978,6 @@ NTSTATUS WINAPI RtlSetCurrentDirectory_U(const UNICODE_STRING* dir) curdir->Handle = handle; /* append trailing \ if missing */ - size = newdir.Length / sizeof(WCHAR); - ptr = newdir.Buffer; - ptr += 4; /* skip \??\ prefix */ - size -= 4; if (size && ptr[size - 1] != '\\') ptr[size++] = '\\'; /* convert \??\UNC\ path to \\ prefix */ From 48b1fae6c8149900d05a054344fdff6680a93996 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 13 Jul 2022 19:56:49 -0500 Subject: [PATCH 0549/2777] user32: Send WM_NCPAINT as notify message in send_ncpaint(). CW-Bug-Id: #20969 --- dlls/win32u/dce.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 1cc6a0d605e..234030440f0 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -1214,7 +1214,7 @@ static HRGN send_ncpaint( HWND hwnd, HWND *child, UINT *flags ) if (style & WS_VSCROLL) set_standard_scroll_painted( hwnd, SB_VERT, FALSE ); - send_message( hwnd, WM_NCPAINT, (WPARAM)whole_rgn, 0 ); + send_notify_message( hwnd, WM_NCPAINT, (WPARAM)whole_rgn, 0, FALSE ); } if (whole_rgn > (HRGN)1) NtGdiDeleteObjectApp( whole_rgn ); } From 603d1d7d6552ae9dc1b079894bd41f68601e7959 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 24 May 2022 16:27:08 -0500 Subject: [PATCH 0550/2777] user32: Flush driver display in ReleaseDC() for other process window. CW-Bug-Id: #19779 --- dlls/win32u/dce.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 234030440f0..f4292dc36a8 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -1026,6 +1026,9 @@ HDC WINAPI NtUserGetDCEx( HWND hwnd, HRGN clip_rgn, DWORD flags ) */ INT WINAPI NtUserReleaseDC( HWND hwnd, HDC hdc ) { + if (hwnd && !is_current_process_window( hwnd )) + user_driver->pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 ); + return release_dc( hwnd, hdc, FALSE ); } From 322a16e3d5c91df4a989e49e77419c0e50bf4a6b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 8 Jul 2022 20:01:17 -0500 Subject: [PATCH 0551/2777] win32u: Don't load bitmap only TTF fonts without bitmap table. CW-Bug-Id: #20934 --- dlls/win32u/freetype.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/freetype.c b/dlls/win32u/freetype.c index fd402758daa..416927c3a67 100644 --- a/dlls/win32u/freetype.c +++ b/dlls/win32u/freetype.c @@ -254,6 +254,8 @@ MAKE_FUNCPTR(FcStrSetMember); #define GET_BE_DWORD(x) RtlUlongByteSwap(x) #endif +#define MS_EBDT_TAG MS_MAKE_TAG('E','B','D','T') + /* 'gasp' flags */ #define GASP_GRIDFIT 0x01 #define GASP_DOGRAY 0x02 @@ -1177,6 +1179,8 @@ static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr struct stat st; DWORD face_count; int fd, length; + FT_Error error; + FT_ULong len; TRACE( "unix_name %s, face_index %u, data_ptr %p, data_size %u, flags %#x\n", unix_name, face_index, data_ptr, data_size, flags ); @@ -1268,7 +1272,20 @@ static struct unix_face *unix_face_create( const char *unix_name, void *data_ptr This->ntm_flags = get_ntm_flags( This->ft_face ); This->font_version = get_font_version( This->ft_face ); - if (!This->scalable) get_bitmap_size( This->ft_face, &This->size ); + if (!This->scalable) + { + error = pFT_Load_Sfnt_Table( This->ft_face, RtlUlongByteSwap(MS_EBDT_TAG), 0, NULL, &len ); + if (error == FT_Err_Table_Missing) + { + WARN( "EBDT table is missing in bitmap only font %s.\n", + debugstr_w(ft_face_get_family_name( This->ft_face, system_lcid ))); + pFT_Done_Face( This->ft_face ); + free( This ); + This = NULL; + goto done; + } + get_bitmap_size( This->ft_face, &This->size ); + } get_fontsig( This->ft_face, &This->fs ); } else From e952e181159f044df03981ae7807fbb1adee1749 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 17 Sep 2021 21:49:11 +0300 Subject: [PATCH 0552/2777] advapi32: HACK: Don't free provider library in CryptReleaseContext() for DeathLoop. CW-Bug-Id: #19427 Avoids a lockup in DeathLoop. To be dropped once we have a GetModuleHandle() not blocking on the loader lock. --- dlls/advapi32/crypt.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/dlls/advapi32/crypt.c b/dlls/advapi32/crypt.c index 66ad7db3ab2..22bcf03bba7 100644 --- a/dlls/advapi32/crypt.c +++ b/dlls/advapi32/crypt.c @@ -645,9 +645,19 @@ BOOL WINAPI CryptReleaseContext (HCRYPTPROV hProv, DWORD dwFlags) if (InterlockedDecrement(&pProv->refcount) == 0) { + static unsigned int once; + char sgi[64]; + ret = pProv->pFuncs->pCPReleaseContext(pProv->hPrivate, dwFlags); pProv->dwMagic = 0; - FreeLibrary(pProv->hModule); + if(GetEnvironmentVariableA("SteamGameId", sgi, sizeof(sgi)) && !strcmp(sgi, "1252330")) + { + if (!once++) FIXME("HACK: not freeing provider library.\n"); + } + else + { + FreeLibrary(pProv->hModule); + } #if 0 CRYPT_Free(pProv->pVTable->pContextInfo); #endif From 6a792171c72e6f28c75dfcb240699a1c2ebc6017 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 16 Jun 2022 13:41:44 -0500 Subject: [PATCH 0553/2777] ntdll: Factor out validate_context_xstate() function. CW-Bug-Id: #20821 --- dlls/ntdll/unix/signal_i386.c | 4 +--- dlls/ntdll/unix/signal_x86_64.c | 4 +--- dlls/ntdll/unix/thread.c | 17 +++++++++++++++++ dlls/ntdll/unix/unix_private.h | 1 + 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 3b1d5b13dd1..0e2ce558ac0 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1106,9 +1106,7 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) XSTATE *xstate = (XSTATE *)((char *)context_ex + context_ex->XState.Offset); unsigned int mask; - if (context_ex->XState.Length < offsetof(XSTATE, YmmContext) - || context_ex->XState.Length > sizeof(XSTATE)) - return STATUS_INVALID_PARAMETER; + if (!validate_context_xstate( context )) return STATUS_INVALID_PARAMETER; mask = (xstate_compaction_enabled ? xstate->CompactionMask : xstate->Mask) & XSTATE_MASK_GSSE; xstate->Mask = frame->xstate.Mask & mask; diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 65d00b32bf6..adc02ecabd1 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1181,9 +1181,7 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) XSTATE *xstate = (XSTATE *)((char *)context_ex + context_ex->XState.Offset); unsigned int mask; - if (context_ex->XState.Length < offsetof(XSTATE, YmmContext) - || context_ex->XState.Length > sizeof(XSTATE)) - return STATUS_INVALID_PARAMETER; + if (!validate_context_xstate( context )) return STATUS_INVALID_PARAMETER; mask = (xstate_compaction_enabled ? xstate->CompactionMask : xstate->Mask) & XSTATE_MASK_GSSE; xstate->Mask = frame->xstate.Mask & mask; diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index edeb355c7cb..8dd28617411 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -160,6 +160,23 @@ void fpu_to_fpux( XMM_SAVE_AREA32 *fpux, const I386_FLOATING_SAVE_AREA *fpu ) } +/*********************************************************************** + * validate_context_xstate + */ +BOOL validate_context_xstate( CONTEXT *context ) +{ + CONTEXT_EX *context_ex; + + context_ex = (CONTEXT_EX *)(context + 1); + + if (context_ex->XState.Length < offsetof(XSTATE, YmmContext) + || context_ex->XState.Length > sizeof(XSTATE)) + return FALSE; + + return TRUE; +} + + /*********************************************************************** * get_server_context_flags */ diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 40cf3553ffe..e9fb0513120 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -197,6 +197,7 @@ extern void DECLSPEC_NORETURN abort_process( int status ) DECLSPEC_HIDDEN; extern void DECLSPEC_NORETURN exit_process( int status ) DECLSPEC_HIDDEN; extern void wait_suspend( CONTEXT *context ) DECLSPEC_HIDDEN; extern NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance ) DECLSPEC_HIDDEN; +extern BOOL validate_context_xstate( CONTEXT *context ) DECLSPEC_HIDDEN; extern NTSTATUS set_thread_context( HANDLE handle, const void *context, BOOL *self, USHORT machine ) DECLSPEC_HIDDEN; extern NTSTATUS get_thread_context( HANDLE handle, void *context, BOOL *self, USHORT machine ) DECLSPEC_HIDDEN; extern unsigned int alloc_object_attributes( const OBJECT_ATTRIBUTES *attr, struct object_attributes **ret, From eff1dfd6daf986c96824e8b7ed3fcc2d2c5e5a8f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 16 Jun 2022 13:50:10 -0500 Subject: [PATCH 0554/2777] ntdll: Validate context xstate at once in NtGetContextThread(). CW-Bug-Id: #20821 --- dlls/ntdll/unix/signal_i386.c | 4 ++-- dlls/ntdll/unix/signal_x86_64.c | 4 ++-- dlls/ntdll/unix/thread.c | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 0e2ce558ac0..a19d7be8b89 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1007,6 +1007,8 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) BOOL use_cached_debug_regs = FALSE; NTSTATUS ret; + if (!validate_context_xstate( context )) return STATUS_INVALID_PARAMETER; + if (self && needed_flags & CONTEXT_DEBUG_REGISTERS) { /* debug registers require a server call if hw breakpoints are enabled */ @@ -1106,8 +1108,6 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) XSTATE *xstate = (XSTATE *)((char *)context_ex + context_ex->XState.Offset); unsigned int mask; - if (!validate_context_xstate( context )) return STATUS_INVALID_PARAMETER; - mask = (xstate_compaction_enabled ? xstate->CompactionMask : xstate->Mask) & XSTATE_MASK_GSSE; xstate->Mask = frame->xstate.Mask & mask; xstate->CompactionMask = xstate_compaction_enabled ? (0x8000000000000000 | mask) : 0; diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index adc02ecabd1..883f1c10327 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1091,6 +1091,8 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) BOOL use_cached_debug_regs = FALSE; BOOL self = (handle == GetCurrentThread()); + if (!validate_context_xstate( context )) return STATUS_INVALID_PARAMETER; + if (self && needed_flags & CONTEXT_DEBUG_REGISTERS) { /* debug registers require a server call if hw breakpoints are enabled */ @@ -1181,8 +1183,6 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) XSTATE *xstate = (XSTATE *)((char *)context_ex + context_ex->XState.Offset); unsigned int mask; - if (!validate_context_xstate( context )) return STATUS_INVALID_PARAMETER; - mask = (xstate_compaction_enabled ? xstate->CompactionMask : xstate->Mask) & XSTATE_MASK_GSSE; xstate->Mask = frame->xstate.Mask & mask; xstate->CompactionMask = xstate_compaction_enabled ? (0x8000000000000000 | mask) : 0; diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 8dd28617411..1dad8fa9889 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -167,6 +167,8 @@ BOOL validate_context_xstate( CONTEXT *context ) { CONTEXT_EX *context_ex; + if (!((context->ContextFlags & 0x40) && (cpu_info.ProcessorFeatureBits & CPU_FEATURE_AVX))) return TRUE; + context_ex = (CONTEXT_EX *)(context + 1); if (context_ex->XState.Length < offsetof(XSTATE, YmmContext) From ad3952f60829524c897f6d5b9c5479af08576647 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 16 Jun 2022 13:25:39 -0500 Subject: [PATCH 0555/2777] ntdll: Validate xstate alignment in validate_context_xstate(). CW-Bug-Id: #20821 --- dlls/ntdll/tests/exception.c | 14 ++++++++++++++ dlls/ntdll/unix/thread.c | 2 ++ 2 files changed, 16 insertions(+) diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 4bf2e4ec78e..dd5cdcafd64 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -9498,6 +9498,7 @@ static void test_extended_context(void) CONTEXT_EX *context_ex; CONTEXT *context; unsigned data[8]; + NTSTATUS status; HANDLE thread; ULONG64 mask; XSTATE *xs; @@ -10280,6 +10281,19 @@ static void test_extended_context(void) thread = CreateThread(NULL, 0, test_extended_context_thread, 0, CREATE_SUSPENDED, NULL); ok(!!thread, "Failed to create thread.\n"); + /* Unaligned xstate. */ + length = sizeof(context_buffer); + memset(context_buffer, 0xcc, sizeof(context_buffer)); + bret = pInitializeContext(context_buffer, CONTEXT_FULL | CONTEXT_XSTATE | CONTEXT_FLOATING_POINT, + &context, &length); + ok(bret, "Got unexpected bret %#x.\n", bret); + context_ex = (CONTEXT_EX *)(context + 1); + context_ex->XState.Offset += 0x10; + status = pNtGetContextThread(thread, context); + ok(status == STATUS_INVALID_PARAMETER, "Unexpected status %#lx.\n", status); + status = pNtGetContextThread(GetCurrentThread(), context); + ok(status == STATUS_INVALID_PARAMETER, "Unexpected status %#lx.\n", status); + bret = pInitializeContext(context_buffer, CONTEXT_FULL | CONTEXT_XSTATE | CONTEXT_FLOATING_POINT, &context, &length); ok(bret, "Got unexpected bret %#x.\n", bret); diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 1dad8fa9889..a263f71b7da 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -175,6 +175,8 @@ BOOL validate_context_xstate( CONTEXT *context ) || context_ex->XState.Length > sizeof(XSTATE)) return FALSE; + if (((ULONG_PTR)context_ex + context_ex->XState.Offset) & 63) return FALSE; + return TRUE; } From 1c167c818fdcef8e69cbefb59419fc7eae024b4b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 5 Jan 2022 13:31:14 +0300 Subject: [PATCH 0556/2777] audioses: Add stub dll. CW-Bug-Id: #19918 --- configure.ac | 1 + dlls/audioses/Makefile.in | 1 + dlls/audioses/audioses.spec | 11 +++++++++++ 3 files changed, 13 insertions(+) create mode 100644 dlls/audioses/Makefile.in create mode 100644 dlls/audioses/audioses.spec diff --git a/configure.ac b/configure.ac index f9f47903338..a7268c12d15 100644 --- a/configure.ac +++ b/configure.ac @@ -2397,6 +2397,7 @@ WINE_CONFIG_MAKEFILE(dlls/atl90) WINE_CONFIG_MAKEFILE(dlls/atlthunk) WINE_CONFIG_MAKEFILE(dlls/atlthunk/tests) WINE_CONFIG_MAKEFILE(dlls/atmlib) +WINE_CONFIG_MAKEFILE(dlls/audioses) WINE_CONFIG_MAKEFILE(dlls/authz) WINE_CONFIG_MAKEFILE(dlls/avicap32) WINE_CONFIG_MAKEFILE(dlls/avifil32) diff --git a/dlls/audioses/Makefile.in b/dlls/audioses/Makefile.in new file mode 100644 index 00000000000..370949ea4fe --- /dev/null +++ b/dlls/audioses/Makefile.in @@ -0,0 +1 @@ +MODULE = audioses.dll diff --git a/dlls/audioses/audioses.spec b/dlls/audioses/audioses.spec new file mode 100644 index 00000000000..a1884e53243 --- /dev/null +++ b/dlls/audioses/audioses.spec @@ -0,0 +1,11 @@ +# @ stub AUDIOSES_1 +# @ stub AUDIOSES_2 +# @ stub AUDIOSES_3 +# @ stub AUDIOSES_4 +# @ stub AUDIOSES_5 +# @ stub DllCanUnloadNow +# @ stub AUDIOSES_7 +# @ stub DllGetActivationFactory +# @ stub DllGetClassObject +# @ stub DllRegisterServer +# @ stub DllUnregisterServer From a6121a6c2dc63a94aa60a053c71dc15fd53f327e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Sat, 12 Nov 2022 14:03:56 -0600 Subject: [PATCH 0557/2777] win32u: Send notify message in NtUserFlashWindowEx(). CW-Bug-Id: #21562 --- dlls/win32u/window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 69b6ccc8f9a..36a28c50c65 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -4521,7 +4521,7 @@ BOOL WINAPI NtUserFlashWindowEx( FLASHWINFO *info ) else wparam = (hwnd == NtUserGetForegroundWindow()); release_win_ptr( win ); - send_message( hwnd, WM_NCACTIVATE, wparam, 0 ); + send_notify_message( hwnd, WM_NCACTIVATE, wparam, 0, 0 ); user_driver->pFlashWindowEx( info ); return wparam; } From a09eb5d6cf3cc2b81efb2e946283f4ed3301b1c9 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 12 Aug 2022 18:12:29 -0500 Subject: [PATCH 0558/2777] ddraw: Force x87 arithmetic. CW-Bug-Id: #21119 --- dlls/ddraw/ddraw_private.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h index 09e8133350b..2f0633fb05b 100644 --- a/dlls/ddraw/ddraw_private.h +++ b/dlls/ddraw/ddraw_private.h @@ -19,6 +19,10 @@ #ifndef __WINE_DLLS_DDRAW_DDRAW_PRIVATE_H #define __WINE_DLLS_DDRAW_DDRAW_PRIVATE_H +#ifdef __i386__ +#pragma GCC target ("fpmath=387") +#endif + #include #include #include From a706e43bcdf7d58a6c519742a3b9afcf233289b9 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 1 Feb 2022 22:39:42 +0300 Subject: [PATCH 0559/2777] 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 e3ac98aa5e6..3cfeddbeeab 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -285,7 +285,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 2448f591189..eb1785ca6a3 100644 --- a/include/wine/asm.h +++ b/include/wine/asm.h @@ -56,6 +56,7 @@ # define __ASM_SEH(str) # else # define __ASM_SEH(str) str +# define __ASM_SEH_SUPPORTED # endif #else # define __ASM_SEH(str) From e8bad2e88ae3cbf619b76ebe10b26c58ee0981d3 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 4 Nov 2022 19:53:30 -0600 Subject: [PATCH 0560/2777] winegstreamer: Sort streams by stream sequential number when QuickTime demuxer is used. CW-Bug-Id: #21352 --- dlls/winegstreamer/wg_parser.c | 45 +++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index d57fac97d10..1864bac516f 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -102,6 +102,7 @@ struct wg_parser bool use_opengl; GstContext *context; + bool using_qtdemux; }; struct wg_parser_stream @@ -122,6 +123,8 @@ struct wg_parser_stream uint64_t duration; gchar *tags[WG_PARSER_TAG_COUNT]; + gchar *stream_id; + int seq_id; }; static NTSTATUS wg_parser_get_stream_count(void *args) @@ -506,6 +509,8 @@ static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad, GST_WARNING("Disabled video acceleration since it breaks in wine."); return GST_AUTOPLUG_SELECT_SKIP; } + if (!strcmp(name, "QuickTime demuxer")) + parser->using_qtdemux = true; return GST_AUTOPLUG_SELECT_TRY; } @@ -537,12 +542,38 @@ static GValueArray *autoplug_sort_cb(GstElement *bin, GstPad *pad, return ret; } +static int streams_compare(const void *comp1, const void *comp2) +{ + const struct wg_parser_stream * const *stream1 = comp1; + const struct wg_parser_stream * const *stream2 = comp2; + const char *s1, *s2; + int ret; + + s1 = (*stream1)->stream_id ? strchr((*stream1)->stream_id, '/') : NULL; + s2 = (*stream2)->stream_id ? strchr((*stream2)->stream_id, '/') : NULL; + + if (!s1 || !s2) + { + if (!s1 && !s2) + return (*stream1)->seq_id - (*stream2)->seq_id; + if (!s1) + return -1; + return 1; + } + if ((ret = strcmp(s1, s2))) + return ret; + return (*stream1)->seq_id - (*stream2)->seq_id; +} + static void no_more_pads_cb(GstElement *element, gpointer user) { struct wg_parser *parser = user; GST_DEBUG("parser %p.", parser); + if (parser->using_qtdemux) + qsort(parser->streams, parser->stream_count, sizeof(*parser->streams), streams_compare); + pthread_mutex_lock(&parser->mutex); parser->no_more_pads = true; pthread_mutex_unlock(&parser->mutex); @@ -801,7 +832,7 @@ GstElement *create_element(const char *name, const char *plugin_set) return element; } -static struct wg_parser_stream *create_stream(struct wg_parser *parser) +static struct wg_parser_stream *create_stream(struct wg_parser *parser, gchar *id) { struct wg_parser_stream *stream, **new_array; char pad_name[19]; @@ -815,6 +846,8 @@ static struct wg_parser_stream *create_stream(struct wg_parser *parser) gst_segment_init(&stream->segment, GST_FORMAT_UNDEFINED); + stream->stream_id = id; + stream->seq_id = parser->stream_count; stream->parser = parser; stream->number = parser->stream_count; stream->current_format.major_type = WG_MAJOR_TYPE_UNKNOWN; @@ -856,6 +889,10 @@ static void free_stream(struct wg_parser_stream *stream) if (stream->tags[i]) g_free(stream->tags[i]); } + + if (stream->stream_id) + g_free(stream->stream_id); + free(stream); } @@ -876,7 +913,7 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) caps = gst_pad_query_caps(pad, NULL); name = gst_structure_get_name(gst_caps_get_structure(caps, 0)); - if (!(stream = create_stream(parser))) + if (!(stream = create_stream(parser, gst_pad_get_stream_id(pad)))) goto out; if (!strcmp(name, "video/x-raw") && parser->use_opengl) @@ -1774,7 +1811,7 @@ static BOOL mpeg_audio_parser_init_gst(struct wg_parser *parser) return FALSE; } - if (!(stream = create_stream(parser))) + if (!(stream = create_stream(parser, NULL))) return FALSE; gst_object_ref(stream->their_src = gst_element_get_static_pad(element, "src")); @@ -1808,7 +1845,7 @@ static BOOL wave_parser_init_gst(struct wg_parser *parser) return FALSE; } - if (!(stream = create_stream(parser))) + if (!(stream = create_stream(parser, NULL))) return FALSE; stream->their_src = gst_element_get_static_pad(element, "src"); From b64a621f178353e52336b8f141c2ad9cd06630b2 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 14 Nov 2022 13:39:39 -0600 Subject: [PATCH 0561/2777] windowscodecs: HACK: Avoid using __builtin_frame_address() for setjmp(). This is a workaround to compiler bug (observed with Mingw / Gcc 10.x). CW-Bug-Id: #21563 --- dlls/windowscodecs/wincodecs_private.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h index 6a5c4604cf5..45c6d108561 100644 --- a/dlls/windowscodecs/wincodecs_private.h +++ b/dlls/windowscodecs/wincodecs_private.h @@ -397,4 +397,9 @@ extern HRESULT CommonDecoder_CreateInstance(struct decoder *decoder, extern HRESULT CommonEncoder_CreateInstance(struct encoder *encoder, const struct encoder_info *encoder_info, REFIID iid, void** ppv) DECLSPEC_HIDDEN; +#ifdef _WIN64 +#undef setjmp +#define setjmp(buf) _setjmpex(buf, NULL) +#endif + #endif /* WINCODECS_PRIVATE_H */ From 86013011fc76c0c16a713addec2ec885a6e14ccd Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 10 Mar 2022 17:58:41 +0300 Subject: [PATCH 0562/2777] ntdll: HACK: Delay resuming thread after suspending self. CW-Bug-Id: #20270 Fixes a random hang on exit in Little Nightmares 2. --- dlls/ntdll/unix/thread.c | 5 ++++- server/thread.c | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index a263f71b7da..71247118cb3 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -1588,6 +1588,7 @@ NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access, */ NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *count ) { + BOOL self = FALSE; unsigned int ret; SERVER_START_REQ( suspend_thread ) @@ -1595,10 +1596,12 @@ NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *count ) req->handle = wine_server_obj_handle( handle ); if (!(ret = wine_server_call( req ))) { - if (count) *count = reply->count; + self = reply->count & 0x80000000; + if (count) *count = reply->count & 0x7fffffff; } } SERVER_END_REQ; + if (self) usleep( 0 ); return ret; } diff --git a/server/thread.c b/server/thread.c index c82225fb050..d728c1a2160 100644 --- a/server/thread.c +++ b/server/thread.c @@ -931,7 +931,11 @@ int suspend_thread( struct thread *thread ) int old_count = thread->suspend; if (thread->suspend < MAXIMUM_SUSPEND_COUNT) { - if (!(thread->process->suspend + thread->suspend++)) stop_thread( thread ); + if (!(thread->process->suspend + thread->suspend++)) + { + stop_thread( thread ); + if (thread == current) return old_count | 0x80000000; + } } else set_error( STATUS_SUSPEND_COUNT_EXCEEDED ); return old_count; From 4fd446bd2e3e289ff792c5315d8291fbcad7aca5 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Mon, 23 May 2022 13:17:32 -0500 Subject: [PATCH 0563/2777] ntdll: Disable 16-bit TIB hack MechWarrior Online (342200) writes directly to the SubSystemTib field, which Wine would interpret to mean it's a 16-bit executable and then crash. We're unlikely to run into any real 16-bit applications in Proton (they won't work on modern Windows, anyway), so let's just disable that hack entirely. CW-Bug-Id: #20673 --- dlls/kernelbase/loader.c | 2 +- dlls/ntdll/env.c | 2 +- dlls/ntdll/path.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dlls/kernelbase/loader.c b/dlls/kernelbase/loader.c index 0fd2d7b7c99..af3c193f331 100644 --- a/dlls/kernelbase/loader.c +++ b/dlls/kernelbase/loader.c @@ -302,7 +302,7 @@ DWORD WINAPI DECLSPEC_HOTPATCH GetModuleFileNameW( HMODULE module, LPWSTR filena UNICODE_STRING name; NTSTATUS status; - if (!module && ((win16_tib = NtCurrentTeb()->Tib.SubSystemTib)) && win16_tib->exe_name) + if (!module && (0 && (win16_tib = NtCurrentTeb()->Tib.SubSystemTib)) && win16_tib->exe_name) { len = min( size, win16_tib->exe_name->Length / sizeof(WCHAR) ); memcpy( filename, win16_tib->exe_name->Buffer, len * sizeof(WCHAR) ); diff --git a/dlls/ntdll/env.c b/dlls/ntdll/env.c index 6db6cee17cd..7d993cd799c 100644 --- a/dlls/ntdll/env.c +++ b/dlls/ntdll/env.c @@ -589,7 +589,7 @@ NTSTATUS WINAPI RtlCreateProcessParametersEx( RTL_USER_PROCESS_PARAMETERS **resu if (!DllPath) DllPath = &null_str; if (!CurrentDirectoryName) { - if (NtCurrentTeb()->Tib.SubSystemTib) /* FIXME: hack */ + if (0 && NtCurrentTeb()->Tib.SubSystemTib) /* FIXME: hack */ curdir = ((WIN16_SUBSYSTEM_TIB *)NtCurrentTeb()->Tib.SubSystemTib)->curdir.DosPath; else curdir = cur_params->CurrentDirectory.DosPath; diff --git a/dlls/ntdll/path.c b/dlls/ntdll/path.c index da6f55ddb83..dda6ba4ee53 100644 --- a/dlls/ntdll/path.c +++ b/dlls/ntdll/path.c @@ -528,7 +528,7 @@ static ULONG get_full_path_helper(LPCWSTR name, LPWSTR buffer, ULONG size) RtlAcquirePebLock(); - if (NtCurrentTeb()->Tib.SubSystemTib) /* FIXME: hack */ + if (0 && NtCurrentTeb()->Tib.SubSystemTib) /* FIXME: hack */ cd = &((WIN16_SUBSYSTEM_TIB *)NtCurrentTeb()->Tib.SubSystemTib)->curdir.DosPath; else cd = &NtCurrentTeb()->Peb->ProcessParameters->CurrentDirectory.DosPath; @@ -883,7 +883,7 @@ ULONG WINAPI RtlGetCurrentDirectory_U(ULONG buflen, LPWSTR buf) RtlAcquirePebLock(); - if (NtCurrentTeb()->Tib.SubSystemTib) /* FIXME: hack */ + if (0 && NtCurrentTeb()->Tib.SubSystemTib) /* FIXME: hack */ us = &((WIN16_SUBSYSTEM_TIB *)NtCurrentTeb()->Tib.SubSystemTib)->curdir.DosPath; else us = &NtCurrentTeb()->Peb->ProcessParameters->CurrentDirectory.DosPath; @@ -927,7 +927,7 @@ NTSTATUS WINAPI RtlSetCurrentDirectory_U(const UNICODE_STRING* dir) RtlAcquirePebLock(); - if (NtCurrentTeb()->Tib.SubSystemTib) /* FIXME: hack */ + if (0 && NtCurrentTeb()->Tib.SubSystemTib) /* FIXME: hack */ curdir = &((WIN16_SUBSYSTEM_TIB *)NtCurrentTeb()->Tib.SubSystemTib)->curdir; else curdir = &NtCurrentTeb()->Peb->ProcessParameters->CurrentDirectory; From 10edd84bb5a520b7313d68554c33e6828e9da12e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 8 Apr 2022 20:30:55 +0300 Subject: [PATCH 0564/2777] wine.inf: Set display mode parameters for Star Wars: Episode I Racer. CW-Bug-Id: #20422 --- loader/wine.inf.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 5e21b6d38ed..d6040e30dd9 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2781,3 +2781,5 @@ HKCU,Software\Wine\AppDefaults\Avengers.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\starwarssquadrons.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\GW2.Main_Win64_Retail.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\Spider-Man.exe\DllOverrides,"atiadlxx",,"builtin" +HKLM,Software\Wow6432Node\lucasarts entertainment company llc\Star Wars: Episode I Racer\v1.0,"Display Height",0x10001,480 +HKLM,Software\Wow6432Node\lucasarts entertainment company llc\Star Wars: Episode I Racer\v1.0,"Display Width",0x10001,640 From b47234b2b75321f4818f491ccc32928d07e3474b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 21 Oct 2022 12:11:06 -0500 Subject: [PATCH 0565/2777] wine.inf: Use built-in atiadlxx for Uncharted Legacy of Thieves Collection. CW-Bug-Id: #21433 --- loader/wine.inf.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index d6040e30dd9..9b080bbbf85 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2763,6 +2763,8 @@ HKCU,Software\Wine\AppDefaults\MonsterHunterRise.exe\DllOverrides,"amd_ags_x64", HKCU,Software\Wine\AppDefaults\Sam4.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\Sam4_Unrestricted.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"amd_ags_x64",,"disabled" +HKCU,Software\Wine\AppDefaults\u4.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" +HKCU,Software\Wine\AppDefaults\tll.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" ;;App-specific overrides for atiadlxx.dll. HKCU,Software\Wine\AppDefaults\s2_sp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\s2_mp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" From 66ffcc11cd2459df90342bef3e1494f103f7b9fa Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Wed, 17 Oct 2018 04:13:37 -0700 Subject: [PATCH 0566/2777] ntdll/loader: add support for overriding IMAGE_FILE_LARGE_ADDRESS_AWARE Signed-off-by: Steven Noonan --- dlls/kernel32/heap.c | 8 +++++++- dlls/ntdll/ntdll.spec | 1 + dlls/ntdll/unix/loader.c | 1 + dlls/ntdll/unix/server.c | 4 ++-- dlls/ntdll/unix/unix_private.h | 2 ++ dlls/ntdll/unix/virtual.c | 13 +++++++++++++ 6 files changed, 26 insertions(+), 3 deletions(-) diff --git a/dlls/kernel32/heap.c b/dlls/kernel32/heap.c index 3ea3b348376..91d9f12f26e 100644 --- a/dlls/kernel32/heap.c +++ b/dlls/kernel32/heap.c @@ -44,6 +44,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(globalmem); BOOLEAN WINAPI RtlGetUserInfoHeap( HANDLE handle, ULONG flags, void *ptr, void **user_value, ULONG *user_flags ); BOOLEAN WINAPI RtlSetUserValueHeap( HANDLE handle, ULONG flags, void *ptr, void *user_value ); +extern BOOL CDECL __wine_needs_override_large_address_aware(void); + /*********************************************************************** * HeapCreate (KERNEL32.@) * @@ -426,6 +428,7 @@ VOID WINAPI GlobalMemoryStatus( LPMEMORYSTATUS lpBuffer ) OSVERSIONINFOW osver; #ifndef _WIN64 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( GetModuleHandleW(0) ); + static int force_large_address_aware = -1; #endif /* Because GlobalMemoryStatus is identical to GlobalMemoryStatusEX save @@ -452,6 +455,8 @@ VOID WINAPI GlobalMemoryStatus( LPMEMORYSTATUS lpBuffer ) lpBuffer->dwAvailVirtual = memstatus.ullAvailVirtual; #ifndef _WIN64 + if (force_large_address_aware == -1) + force_large_address_aware = __wine_needs_override_large_address_aware(); if ( osver.dwMajorVersion >= 5 || osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) { lpBuffer->dwTotalPhys = min( memstatus.ullTotalPhys, MAXDWORD ); @@ -465,7 +470,8 @@ VOID WINAPI GlobalMemoryStatus( LPMEMORYSTATUS lpBuffer ) /* values are limited to 2Gb unless the app has the IMAGE_FILE_LARGE_ADDRESS_AWARE flag */ /* page file sizes are not limited (Adobe Illustrator 8 depends on this) */ - if (!(nt->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)) + if (!(nt->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) && + !force_large_address_aware) { if (lpBuffer->dwTotalPhys > MAXLONG) lpBuffer->dwTotalPhys = MAXLONG; if (lpBuffer->dwAvailPhys > MAXLONG) lpBuffer->dwAvailPhys = MAXLONG; diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 05999131fc5..3052e2afff2 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -1713,3 +1713,4 @@ # Filesystem @ stdcall -syscall wine_nt_to_unix_file_name(ptr ptr ptr long) @ stdcall -syscall wine_unix_to_nt_file_name(str ptr ptr) +@ cdecl -syscall __wine_needs_override_large_address_aware() diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index e89b10fa74e..434ff40717a 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -358,6 +358,7 @@ static void * const syscalls[] = NtWriteVirtualMemory, NtYieldExecution, __wine_dbg_write, + __wine_needs_override_large_address_aware, __wine_set_unix_env, __wine_unix_spawnvp, wine_nt_to_unix_file_name, diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 3df115ccea6..1235c2cc5b4 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -1603,8 +1603,8 @@ void server_init_process_done(void) #ifdef __APPLE__ send_server_task_port(); #endif - if (main_image_info.ImageCharacteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) - virtual_set_large_address_space(); + if ((main_image_info.ImageCharacteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) + || __wine_needs_override_large_address_aware()) virtual_set_large_address_space(); /* Install signal handlers; this cannot be done earlier, since we cannot * send exceptions to the debugger before the create process event that diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index e9fb0513120..7c7391b5d38 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -499,4 +499,6 @@ static inline NTSTATUS map_section( HANDLE mapping, void **ptr, SIZE_T *size, UL 0, NULL, size, ViewShare, 0, protect ); } +BOOL CDECL __wine_needs_override_large_address_aware(void); + #endif /* __NTDLL_UNIX_PRIVATE_H */ diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 904aa20764e..d890cf73b50 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -3777,6 +3777,19 @@ static void virtual_release_address_space(void) while (mmap_enum_reserved_areas( free_reserved_memory, &range, 0 )) /* nothing */; } +BOOL CDECL __wine_needs_override_large_address_aware(void) +{ + static int needs_override = -1; + + if (needs_override == -1) + { + const char *str = getenv( "WINE_LARGE_ADDRESS_AWARE" ); + + needs_override = !str || atoi(str) == 1; + } + return needs_override; +} + /*********************************************************************** * virtual_set_large_address_space From c98101f3e821ae2e36d19a6b243639abaa2c0825 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 11 Nov 2022 17:51:26 -0600 Subject: [PATCH 0567/2777] ntdll/tests: Add tests for freeing a part of view. --- dlls/ntdll/tests/virtual.c | 70 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index 6831fe3c522..8e94566fb7f 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -1639,21 +1639,85 @@ static void test_syscalls(void) static void test_NtFreeVirtualMemory(void) { + void *addr1, *addr; NTSTATUS status; - void *addr1; SIZE_T size; size = 0x10000; addr1 = NULL; - status = NtAllocateVirtualMemory(NtCurrentProcess(), &addr1, 0, &size, MEM_RESERVE, PAGE_READWRITE); + status = NtAllocateVirtualMemory(NtCurrentProcess(), &addr1, 0, &size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); size = 0; status = NtFreeVirtualMemory(NULL, &addr1, &size, MEM_RELEASE); ok(status == STATUS_INVALID_HANDLE, "Unexpected status %08lx.\n", status); + addr = (char *)addr1 + 0x1000; + size = 0; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); + ok(status == STATUS_FREE_VM_NOT_AT_BASE, "Unexpected status %08lx.\n", status); + + size = 0x11000; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + todo_wine ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + + addr = (char *)addr1 + 0x1001; + size = 0xffff; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); + todo_wine ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + ok(size == 0xffff, "Unexpected size %p.\n", (void *)size); + ok(addr == (char *)addr1 + 0x1001, "Got addr %p, addr1 %p.\n", addr, addr1); + + size = 0xfff; + addr = (char *)addr1 + 0x1001; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); + todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + *(volatile char *)addr1 = 1; + *((volatile char *)addr1 + 0x2000) = 1; + todo_wine ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); + todo_wine ok(addr == (char *)addr1 + 0x1000, "Got addr %p, addr1 %p.\n", addr, addr1); + + size = 0xfff; + addr = (char *)addr1 + 1; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); + todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + *((volatile char *)addr1 + 0x2000) = 1; + todo_wine ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); + todo_wine ok(addr == addr1, "Got addr %p, addr1 %p.\n", addr, addr1); + + size = 0x1000; + addr = addr1; + status = NtAllocateVirtualMemory(NtCurrentProcess(), &addr, 0, &size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(addr == addr1, "Unexpected addr %p, addr1 %p.\n", addr, addr1); + ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); + + size = 0x10000; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_DECOMMIT); + todo_wine ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + + size = 0x10000; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE); + todo_wine ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + + size = 0; + addr = (char *)addr1 + 0x1000; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); + todo_wine ok(status == STATUS_MEMORY_NOT_ALLOCATED, "Unexpected status %08lx.\n", status); + + size = 0x1000; + addr = (char *)addr1 + 0x1000; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_DECOMMIT); + todo_wine ok(status == STATUS_MEMORY_NOT_ALLOCATED, "Unexpected status %08lx.\n", status); + + size = 0; + addr = (char *)addr1 + 0x2000; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); + todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + + size = 0x1000; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE); + todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); } static void test_prefetch(void) From aa0fcbe181fd5676cc84d034ffe30d9221f3161a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 11 Nov 2022 17:56:42 -0600 Subject: [PATCH 0568/2777] kernelbase: Validate nonzero size for MEM_RELEASE in VirtualFreeEx(). --- dlls/kernelbase/memory.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c index 4bcd4a639f6..fb4fa5d8d2e 100644 --- a/dlls/kernelbase/memory.c +++ b/dlls/kernelbase/memory.c @@ -447,6 +447,12 @@ BOOL WINAPI DECLSPEC_HOTPATCH VirtualFree( void *addr, SIZE_T size, DWORD type ) */ BOOL WINAPI DECLSPEC_HOTPATCH VirtualFreeEx( HANDLE process, void *addr, SIZE_T size, DWORD type ) { + if (type == MEM_RELEASE && size) + { + WARN( "Trying to release memory with specified size.\n" ); + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } return set_ntstatus( NtFreeVirtualMemory( process, &addr, &size, type )); } From c837a2119b6d2ae66c02715de598efcde20e29d1 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 11 Nov 2022 18:12:47 -0600 Subject: [PATCH 0569/2777] ntdll: Fix size validation in NtFreeVirtualMemory(). --- dlls/ntdll/tests/virtual.c | 16 ++++++++-------- dlls/ntdll/unix/virtual.c | 26 ++++++++++++++++++-------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index 8e94566fb7f..81e9bd0bda3 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -1659,12 +1659,12 @@ static void test_NtFreeVirtualMemory(void) size = 0x11000; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE); - todo_wine ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); addr = (char *)addr1 + 0x1001; size = 0xffff; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); - todo_wine ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); ok(size == 0xffff, "Unexpected size %p.\n", (void *)size); ok(addr == (char *)addr1 + 0x1001, "Got addr %p, addr1 %p.\n", addr, addr1); @@ -1674,16 +1674,16 @@ static void test_NtFreeVirtualMemory(void) todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); *(volatile char *)addr1 = 1; *((volatile char *)addr1 + 0x2000) = 1; - todo_wine ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); - todo_wine ok(addr == (char *)addr1 + 0x1000, "Got addr %p, addr1 %p.\n", addr, addr1); + ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); + ok(addr == (char *)addr1 + 0x1000, "Got addr %p, addr1 %p.\n", addr, addr1); size = 0xfff; addr = (char *)addr1 + 1; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); *((volatile char *)addr1 + 0x2000) = 1; - todo_wine ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); - todo_wine ok(addr == addr1, "Got addr %p, addr1 %p.\n", addr, addr1); + ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); + ok(addr == addr1, "Got addr %p, addr1 %p.\n", addr, addr1); size = 0x1000; addr = addr1; @@ -1703,12 +1703,12 @@ static void test_NtFreeVirtualMemory(void) size = 0; addr = (char *)addr1 + 0x1000; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); - todo_wine ok(status == STATUS_MEMORY_NOT_ALLOCATED, "Unexpected status %08lx.\n", status); + ok(status == STATUS_MEMORY_NOT_ALLOCATED, "Unexpected status %08lx.\n", status); size = 0x1000; addr = (char *)addr1 + 0x1000; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_DECOMMIT); - todo_wine ok(status == STATUS_MEMORY_NOT_ALLOCATED, "Unexpected status %08lx.\n", status); + ok(status == STATUS_MEMORY_NOT_ALLOCATED, "Unexpected status %08lx.\n", status); size = 0; addr = (char *)addr1 + 0x2000; diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index d890cf73b50..6488dae2ea1 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -4128,26 +4128,36 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si if (addr == (void *)1 && !size && type == MEM_RELEASE) virtual_release_address_space(); else status = STATUS_INVALID_PARAMETER; } - else if (!(view = find_view( base, size )) || !is_view_valloc( view )) - { - status = STATUS_INVALID_PARAMETER; - } + else if (!(view = find_view( base, 0 ))) status = STATUS_MEMORY_NOT_ALLOCATED; + else if (!is_view_valloc( view )) status = STATUS_INVALID_PARAMETER; else if (type == MEM_RELEASE) { /* Free the pages */ - if (size) status = STATUS_INVALID_PARAMETER; - else if (base != view->base) status = STATUS_FREE_VM_NOT_AT_BASE; + if (size && (char *)view->base + view->size - base < size) status = STATUS_UNABLE_TO_FREE_VM; + else if (!size && base != view->base) status = STATUS_FREE_VM_NOT_AT_BASE; else { + if (!size) size = view->size; + + if (size == view->size) + { + assert( base == view->base ); + delete_view( view ); + } + else + { + FIXME( "Parial view release is not supported.\n" ); + status = STATUS_INVALID_PARAMETER; + } *addr_ptr = base; - *size_ptr = view->size; - delete_view( view ); + *size_ptr = size; } } else if (type == MEM_DECOMMIT) { if (!size && base != view->base) status = STATUS_FREE_VM_NOT_AT_BASE; + else if (base - (char *)view->base + size > view->size) status = STATUS_UNABLE_TO_FREE_VM; else status = decommit_pages( view, base - (char *)view->base, size ); if (status == STATUS_SUCCESS) { From 9e743561b08e59a12ecec05ae5cee3ea02554f8e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 11 Nov 2022 18:30:20 -0600 Subject: [PATCH 0570/2777] ntdll: Fully support unaligned views in free ranges management. --- dlls/ntdll/unix/virtual.c | 41 ++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 6488dae2ea1..767cfd39443 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -754,18 +754,19 @@ static void free_ranges_insert_view( struct file_view *view ) assert( range != free_ranges_end ); assert( range->end > view_base || next != free_ranges_end ); - /* this happens because virtual_alloc_thread_stack shrinks a view, then creates another one on top, - * or because AT_ROUND_TO_PAGE was used with NtMapViewOfSection to force 4kB aligned mapping. */ - if ((range->end > view_base && range->base >= view_end) || - (range->end == view_base && next->base >= view_end)) - { - /* on Win64, assert that it's correctly aligned so we're not going to be in trouble later */ -#ifdef _WIN64 - assert( view->base == view_base ); -#endif - WARN( "range %p - %p is already mapped\n", view_base, view_end ); + /* Free ranges addresses are aligned at granularity_mask while the views may be not. */ + + if (range->base > view_base) + view_base = range->base; + if (range->end < view_end) + view_end = range->end; + if (range->end == view_base && next->base >= view_end) + view_end = view_base; + + TRACE( "%p - %p, aligned %p - %p.\n", view->base, (char *)view->base + view->size, view_base, view_end ); + + if (view_end <= view_base) return; - } /* this should never happen */ if (range->base > view_base || range->end < view_end) @@ -815,9 +816,7 @@ static void free_ranges_remove_view( struct file_view *view ) struct range_entry *range = free_ranges_lower_bound( view_base ); struct range_entry *next = range + 1; - /* It's possible to use AT_ROUND_TO_PAGE on 32bit with NtMapViewOfSection to force 4kB alignment, - * and this breaks our assumptions. Look at the views around to check if the range is still in use. */ -#ifndef _WIN64 + /* Free ranges addresses are aligned at granularity_mask while the views may be not. */ struct file_view *prev_view = RB_ENTRY_VALUE( rb_prev( &view->entry ), struct file_view, entry ); struct file_view *next_view = RB_ENTRY_VALUE( rb_next( &view->entry ), struct file_view, entry ); void *prev_view_base = prev_view ? ROUND_ADDR( prev_view->base, granularity_mask ) : NULL; @@ -825,13 +824,15 @@ static void free_ranges_remove_view( struct file_view *view ) void *next_view_base = next_view ? ROUND_ADDR( next_view->base, granularity_mask ) : NULL; void *next_view_end = next_view ? ROUND_ADDR( (char *)next_view->base + next_view->size + granularity_mask, granularity_mask ) : NULL; - if ((prev_view_base < view_end && prev_view_end > view_base) || - (next_view_base < view_end && next_view_end > view_base)) - { - WARN( "range %p - %p is still mapped\n", view_base, view_end ); + if (prev_view_end && prev_view_end > view_base && prev_view_base < view_end) + view_base = prev_view_end; + if (next_view_base && next_view_base < view_end && next_view_end > view_base) + view_end = next_view_base; + + TRACE( "%p - %p, aligned %p - %p.\n", view->base, (char *)view->base + view->size, view_base, view_end ); + + if (view_end <= view_base) return; - } -#endif /* free_ranges initial value is such that the view is either inside range or before another one. */ assert( range != free_ranges_end ); From 94ef404194dcea8f88b29c427956d1e3063dd6a1 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 11 Nov 2022 18:37:43 -0600 Subject: [PATCH 0571/2777] ntdll: Factor out some view manipulation functions. --- dlls/ntdll/unix/virtual.c | 47 +++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 767cfd39443..5d78c9b8334 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -1547,6 +1547,31 @@ static struct file_view *alloc_view(void) } +/*********************************************************************** + * free_view + * + * Free memory for view structure. virtual_mutex must be held by caller. + */ +static void free_view( struct file_view *view ) +{ + *(struct file_view **)view = next_free_view; + next_free_view = view; +} + + +/*********************************************************************** + * unregister_view + * + * Remove view from the tree and update free ranges. virtual_mutex must be held by caller. + */ +static void unregister_view( struct file_view *view ) +{ + if (mmap_is_in_reserved_area( view->base, view->size )) + free_ranges_remove_view( view ); + wine_rb_remove( &views_tree, &view->entry ); +} + + /*********************************************************************** * delete_view * @@ -1556,11 +1581,21 @@ static void delete_view( struct file_view *view ) /* [in] View */ { if (!(view->protect & VPROT_SYSTEM)) unmap_area( view->base, view->size ); set_page_vprot( view->base, view->size, 0 ); + unregister_view( view ); + free_view( view ); +} + + +/*********************************************************************** + * register_view + * + * Add view to the tree and update free ranges. virtual_mutex must be held by caller. + */ +static void register_view( struct file_view *view ) +{ + wine_rb_put( &views_tree, view->base, &view->entry ); if (mmap_is_in_reserved_area( view->base, view->size )) - free_ranges_remove_view( view ); - wine_rb_remove( &views_tree, &view->entry ); - *(struct file_view **)view = next_free_view; - next_free_view = view; + free_ranges_insert_view( view ); } @@ -1604,9 +1639,7 @@ static NTSTATUS create_view( struct file_view **view_ret, void *base, size_t siz view->protect = vprot; set_page_vprot( base, size, vprot ); - wine_rb_put( &views_tree, view->base, &view->entry ); - if (mmap_is_in_reserved_area( view->base, view->size )) - free_ranges_insert_view( view ); + register_view( view ); *view_ret = view; From b3dd1e816d9195bbe8717f1b8799166770042170 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 11 Nov 2022 18:41:50 -0600 Subject: [PATCH 0572/2777] ntdll: Support partial view release in NtFreeVirtualMemory(). --- dlls/ntdll/tests/virtual.c | 14 ++++++------- dlls/ntdll/unix/virtual.c | 42 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index 81e9bd0bda3..0dccb35bd27 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -1671,7 +1671,7 @@ static void test_NtFreeVirtualMemory(void) size = 0xfff; addr = (char *)addr1 + 0x1001; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); *(volatile char *)addr1 = 1; *((volatile char *)addr1 + 0x2000) = 1; ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); @@ -1680,7 +1680,7 @@ static void test_NtFreeVirtualMemory(void) size = 0xfff; addr = (char *)addr1 + 1; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); *((volatile char *)addr1 + 0x2000) = 1; ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); ok(addr == addr1, "Got addr %p, addr1 %p.\n", addr, addr1); @@ -1688,17 +1688,17 @@ static void test_NtFreeVirtualMemory(void) size = 0x1000; addr = addr1; status = NtAllocateVirtualMemory(NtCurrentProcess(), &addr, 0, &size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); ok(addr == addr1, "Unexpected addr %p, addr1 %p.\n", addr, addr1); ok(size == 0x1000, "Unexpected size %p.\n", (void *)size); size = 0x10000; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_DECOMMIT); - todo_wine ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); size = 0x10000; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE); - todo_wine ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); size = 0; addr = (char *)addr1 + 0x1000; @@ -1713,11 +1713,11 @@ static void test_NtFreeVirtualMemory(void) size = 0; addr = (char *)addr1 + 0x2000; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr, &size, MEM_RELEASE); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); size = 0x1000; status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); } static void test_prefetch(void) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 5d78c9b8334..8d6ca7d110a 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -4181,8 +4181,46 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si } else { - FIXME( "Parial view release is not supported.\n" ); - status = STATUS_INVALID_PARAMETER; + struct file_view *new_view = NULL; + + if (view->base != base && base + size != (char *)view->base + view->size + && !(new_view = alloc_view())) + { + ERR( "out of memory for %p-%p\n", base, (char *)base + size ); + return STATUS_NO_MEMORY; + } + unregister_view( view ); + + if (new_view) + { + new_view->base = base + size; + new_view->size = (char *)view->base + view->size - (char *)new_view->base; + new_view->protect = view->protect; + + view->size = base - (char *)view->base; + register_view( view ); + register_view( new_view ); + + VIRTUAL_DEBUG_DUMP_VIEW( view ); + VIRTUAL_DEBUG_DUMP_VIEW( new_view ); + } + else + { + if (view->base == base) + { + view->base = base + size; + view->size -= size; + } + else + { + view->size = base - (char *)view->base; + } + register_view( view ); + VIRTUAL_DEBUG_DUMP_VIEW( view ); + } + + set_page_vprot( base, size, 0 ); + unmap_area( base, size ); } *addr_ptr = base; *size_ptr = size; From d79403ef3eacd8c7e8d313361b849ce46f8fc635 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 4 Oct 2022 20:26:39 -0500 Subject: [PATCH 0573/2777] ntdll: Add logging for free ranges. --- dlls/ntdll/unix/virtual.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 8d6ca7d110a..3df24755729 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -78,6 +78,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(virtual); WINE_DECLARE_DEBUG_CHANNEL(module); +WINE_DECLARE_DEBUG_CHANNEL(virtual_ranges); struct preload_info { @@ -188,6 +189,7 @@ static struct list teb_list = LIST_INIT( teb_list ); #define ROUND_SIZE(addr,size) (((SIZE_T)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask) #define VIRTUAL_DEBUG_DUMP_VIEW(view) do { if (TRACE_ON(virtual)) dump_view(view); } while (0) +#define VIRTUAL_DEBUG_DUMP_RANGES() do { if (TRACE_ON(virtual_ranges)) dump_free_ranges(); } while (0) #ifndef MAP_NORESERVE #define MAP_NORESERVE 0 @@ -737,6 +739,12 @@ static struct range_entry *free_ranges_lower_bound( void *addr ) return begin; } +static void dump_free_ranges(void) +{ + struct range_entry *r; + for (r = free_ranges; r != free_ranges_end; ++r) + TRACE_(virtual_ranges)("%p - %p.\n", r->base, r->end); +} /*********************************************************************** * free_ranges_insert_view @@ -766,7 +774,10 @@ static void free_ranges_insert_view( struct file_view *view ) TRACE( "%p - %p, aligned %p - %p.\n", view->base, (char *)view->base + view->size, view_base, view_end ); if (view_end <= view_base) + { + VIRTUAL_DEBUG_DUMP_RANGES(); return; + } /* this should never happen */ if (range->base > view_base || range->end < view_end) @@ -794,16 +805,19 @@ static void free_ranges_insert_view( struct file_view *view ) else range->base = view_end; - if (range->base < range->end) return; - + if (range->base < range->end) + { + VIRTUAL_DEBUG_DUMP_RANGES(); + return; + } /* and possibly remove it if it's now empty */ memmove( range, next, (free_ranges_end - next) * sizeof(struct range_entry) ); free_ranges_end -= 1; assert( free_ranges_end - free_ranges > 0 ); } + VIRTUAL_DEBUG_DUMP_RANGES(); } - /*********************************************************************** * free_ranges_remove_view * @@ -832,8 +846,10 @@ static void free_ranges_remove_view( struct file_view *view ) TRACE( "%p - %p, aligned %p - %p.\n", view->base, (char *)view->base + view->size, view_base, view_end ); if (view_end <= view_base) + { + VIRTUAL_DEBUG_DUMP_RANGES(); return; - + } /* free_ranges initial value is such that the view is either inside range or before another one. */ assert( range != free_ranges_end ); assert( range->end > view_base || next != free_ranges_end ); @@ -875,6 +891,7 @@ static void free_ranges_remove_view( struct file_view *view ) range->base = view_base; range->end = view_end; } + VIRTUAL_DEBUG_DUMP_RANGES(); } From f384257e898eada9ced2f9dfdac4f874762d5cd4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 10 Nov 2022 18:40:18 -0600 Subject: [PATCH 0574/2777] ntdll: Handle NULL process handle in MapViewOfFile3(). Based on a patch by Nikolay Sivov. --- dlls/kernelbase/memory.c | 2 ++ dlls/ntdll/tests/virtual.c | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c index fb4fa5d8d2e..47a2127452f 100644 --- a/dlls/kernelbase/memory.c +++ b/dlls/kernelbase/memory.c @@ -255,6 +255,8 @@ LPVOID WINAPI DECLSPEC_HOTPATCH MapViewOfFile3( HANDLE handle, HANDLE process, P LARGE_INTEGER off; void *addr; + if (!process) process = GetCurrentProcess(); + addr = baseaddr; off.QuadPart = offset; if (!set_ntstatus( NtMapViewOfSectionEx( handle, process, &addr, &off, &size, alloc_type, protection, diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index 0dccb35bd27..486efabaf70 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -1060,6 +1060,13 @@ static void test_NtMapViewOfSection(void) process = create_target_process("sleep"); ok(process != NULL, "Can't start process\n"); + ptr = NULL; + size = 0; + offset.QuadPart = 0; + status = NtMapViewOfSection(mapping, NULL, &ptr, 0, 0, &offset, &size, 1, 0, PAGE_READWRITE); + ok(status == STATUS_INVALID_HANDLE, "NtMapViewOfSection returned %08lx\n", status); + ok(!((ULONG_PTR)ptr & 0xffff), "returned memory %p is not aligned to 64k\n", ptr); + ptr = NULL; size = 0; offset.QuadPart = 0; @@ -1303,6 +1310,12 @@ static void test_NtMapViewOfSectionEx(void) process = create_target_process("sleep"); ok(process != NULL, "Can't start process\n"); + ptr = NULL; + size = 0; + offset.QuadPart = 0; + status = pNtMapViewOfSectionEx(mapping, NULL, &ptr, &offset, &size, 0, PAGE_READWRITE, NULL, 0); + ok(status == STATUS_INVALID_HANDLE, "Unexpected status %08lx\n", status); + ptr = NULL; size = 0; offset.QuadPart = 0; From c18c2f9b98f7dd3ddb8542b6b443273aa7d85e46 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 10 Nov 2022 18:43:05 -0600 Subject: [PATCH 0575/2777] ntdll: Support MEM_PRESERVE_PLACEHOLDER in NtFreeVirtualMemory(). Based on a patch by Nikolay Sivov. --- dlls/ntdll/unix/virtual.c | 46 +++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 3df24755729..86b2946b4df 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -125,6 +125,7 @@ struct file_view #define VPROT_WRITEWATCH 0x40 /* per-mapping protection flags */ #define VPROT_SYSTEM 0x0200 /* system view (underlying mmap not under our control) */ +#define VPROT_PLACEHOLDER 0x0400 /* Conversion from VPROT_* to Win32 flags */ static const BYTE VIRTUAL_Win32Flags[16] = @@ -1109,6 +1110,8 @@ static void dump_view( struct file_view *view ) TRACE( "View: %p - %p", addr, addr + view->size - 1 ); if (view->protect & VPROT_SYSTEM) TRACE( " (builtin image)\n" ); + else if (view->protect & VPROT_PLACEHOLDER) + TRACE( " (placeholder)\n" ); else if (view->protect & SEC_IMAGE) TRACE( " (image)\n" ); else if (view->protect & SEC_FILE) @@ -4181,7 +4184,7 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si } else if (!(view = find_view( base, 0 ))) status = STATUS_MEMORY_NOT_ALLOCATED; else if (!is_view_valloc( view )) status = STATUS_INVALID_PARAMETER; - else if (type == MEM_RELEASE) + else if (type == MEM_RELEASE || (type == (MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER))) { /* Free the pages */ @@ -4191,14 +4194,15 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si { if (!size) size = view->size; - if (size == view->size) + if (type == MEM_RELEASE && size == view->size) { assert( base == view->base ); delete_view( view ); } else { - struct file_view *new_view = NULL; + struct file_view *new_view = NULL, *preserve_view = NULL; + int preserve_whole; if (view->base != base && base + size != (char *)view->base + view->size && !(new_view = alloc_view())) @@ -4206,7 +4210,8 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si ERR( "out of memory for %p-%p\n", base, (char *)base + size ); return STATUS_NO_MEMORY; } - unregister_view( view ); + preserve_whole = (size == view->size); + if (!preserve_whole) unregister_view( view ); if (new_view) { @@ -4221,7 +4226,7 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si VIRTUAL_DEBUG_DUMP_VIEW( view ); VIRTUAL_DEBUG_DUMP_VIEW( new_view ); } - else + else if (!preserve_whole) { if (view->base == base) { @@ -4236,8 +4241,35 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si VIRTUAL_DEBUG_DUMP_VIEW( view ); } - set_page_vprot( base, size, 0 ); - unmap_area( base, size ); + if (type & MEM_PRESERVE_PLACEHOLDER) + { + if (preserve_whole) + { + view->protect = VPROT_PLACEHOLDER; + preserve_view = view; + } + else + { + if (!(preserve_view = alloc_view())) + { + ERR( "out of memory for %p-%p\n", base, (char *)base + size ); + return STATUS_NO_MEMORY; + } + preserve_view->base = base; + preserve_view->size = size; + preserve_view->protect = VPROT_PLACEHOLDER; + register_view( preserve_view ); + } + set_page_vprot( base, size, 0 ); + if (anon_mmap_fixed(base, size, 0, 0) != base) + ERR("anon_mmap_fixed failed, err %s.\n", strerror(errno)); + VIRTUAL_DEBUG_DUMP_VIEW( preserve_view ); + } + else + { + set_page_vprot( base, size, 0 ); + unmap_area( base, size ); + } } *addr_ptr = base; *size_ptr = size; From 63faebe2ddd1ee010fef96b3aba2dec60e49b92f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 10 Nov 2022 18:48:14 -0600 Subject: [PATCH 0576/2777] ntdll: Pass allocation type to map_view(). Based on a patch by Nikolay Sivov. --- dlls/ntdll/unix/virtual.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 86b2946b4df..ce1f57a9686 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -1997,8 +1997,9 @@ static NTSTATUS map_fixed_area( void *base, size_t size, unsigned int vprot ) * virtual_mutex must be held by caller. */ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, - int top_down, unsigned int vprot, ULONG_PTR limit, size_t align_mask ) + unsigned int alloc_type, unsigned int vprot, ULONG_PTR limit, size_t align_mask ) { + int top_down = alloc_type & MEM_TOP_DOWN; void *ptr; NTSTATUS status; @@ -2213,7 +2214,7 @@ static NTSTATUS allocate_dos_memory( struct file_view **view, unsigned int vprot if (mmap_is_in_reserved_area( low_64k, dosmem_size - 0x10000 ) != 1) { addr = anon_mmap_tryfixed( low_64k, dosmem_size - 0x10000, unix_prot, 0 ); - if (addr == MAP_FAILED) return map_view( view, NULL, dosmem_size, FALSE, vprot, 0, 0 ); + if (addr == MAP_FAILED) return map_view( view, NULL, dosmem_size, 0, vprot, 0, 0 ); } /* now try to allocate the low 64K too */ @@ -3244,7 +3245,7 @@ NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, ULONG_PTR zero_bits, SI server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - if ((status = map_view( &view, NULL, size + extra_size, FALSE, + if ((status = map_view( &view, NULL, size + extra_size, 0, VPROT_READ | VPROT_WRITE | VPROT_COMMITTED, get_zero_bits_mask( zero_bits ), 0 )) != STATUS_SUCCESS) goto done; From c5d8fd113077585647c3035e094048babc0430ce Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 10 Nov 2022 18:53:10 -0600 Subject: [PATCH 0577/2777] ntdll: Support MEM_RESERVE_PLACEHOLDER in NtAllocateVirtualMemoryEx(). Based on a patch by Nikolay Sivov. --- dlls/ntdll/unix/virtual.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index ce1f57a9686..a93e1fd59d1 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -3922,13 +3922,18 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ /* Compute the alloc type flags */ - if (!(type & (MEM_COMMIT | MEM_RESERVE | MEM_RESET)) || - (type & ~(MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN | MEM_WRITE_WATCH | MEM_RESET))) + if (!(type & (MEM_COMMIT | MEM_RESERVE | MEM_RESET))) { WARN("called with wrong alloc type flags (%08x) !\n", (int)type); return STATUS_INVALID_PARAMETER; } + if (type & MEM_RESERVE_PLACEHOLDER && (protect != PAGE_NOACCESS)) + { + WARN("Wrong protect %#x for placeholder.\n", (unsigned int)protect); + return STATUS_INVALID_PARAMETER; + } + /* Reserve the memory */ server_enter_uninterrupted_section( &virtual_mutex, &sigset ); @@ -3939,6 +3944,7 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ { if (type & MEM_COMMIT) vprot |= VPROT_COMMITTED; if (type & MEM_WRITE_WATCH) vprot |= VPROT_WRITEWATCH; + if (type & MEM_RESERVE_PLACEHOLDER) vprot |= VPROT_PLACEHOLDER; if (protect & PAGE_NOCACHE) vprot |= SEC_NOCACHE; if (vprot & VPROT_WRITECOPY) status = STATUS_INVALID_PAGE_PROTECTION; @@ -3958,6 +3964,7 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ { if (!(view = find_view( base, size ))) status = STATUS_NOT_MAPPED_VIEW; else if (view->protect & SEC_FILE) status = STATUS_ALREADY_COMMITTED; + else if (view->protect & VPROT_PLACEHOLDER) status = STATUS_CONFLICTING_ADDRESSES; else if (!(status = set_protection( view, base, size, protect )) && (view->protect & SEC_RESERVE)) { SERVER_START_REQ( add_mapping_committed_range ) @@ -3991,6 +3998,7 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR zero_bits, SIZE_T *size_ptr, ULONG type, ULONG protect ) { + static const ULONG type_mask = MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN | MEM_WRITE_WATCH | MEM_RESET; ULONG_PTR limit; TRACE("%p %p %08lx %x %08x\n", process, *ret, *size_ptr, (int)type, (int)protect ); @@ -4002,6 +4010,12 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z if (!is_wow64 && zero_bits >= 32) return STATUS_INVALID_PARAMETER_3; #endif + if (type & ~type_mask) + { + WARN("Called with wrong alloc type flags %08x.\n", (int)type); + return STATUS_INVALID_PARAMETER; + } + if (process != NtCurrentProcess()) { apc_call_t call; @@ -4044,6 +4058,8 @@ NTSTATUS WINAPI NtAllocateVirtualMemoryEx( HANDLE process, PVOID *ret, SIZE_T *s ULONG protect, MEM_EXTENDED_PARAMETER *parameters, ULONG count ) { + static const ULONG type_mask = MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN | MEM_WRITE_WATCH + | MEM_RESET | MEM_RESERVE_PLACEHOLDER; ULONG_PTR limit = 0; ULONG_PTR align = 0; @@ -4052,6 +4068,12 @@ NTSTATUS WINAPI NtAllocateVirtualMemoryEx( HANDLE process, PVOID *ret, SIZE_T *s if (count && !parameters) return STATUS_INVALID_PARAMETER; + if (type & ~type_mask) + { + WARN("Called with wrong alloc type flags %08x.\n", (int)type); + return STATUS_INVALID_PARAMETER; + } + if (count) { MEM_ADDRESS_REQUIREMENTS *r = NULL; From 843ce03a904cc82082f21585b0f483061f8111bf Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 10 Nov 2022 18:58:26 -0600 Subject: [PATCH 0578/2777] ntdll: Support MEM_REPLACE_PLACEHOLDER in NtAllocateVirtualMemoryEx(). --- dlls/ntdll/unix/virtual.c | 41 +++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index a93e1fd59d1..7d8961c4eec 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -126,6 +126,7 @@ struct file_view /* per-mapping protection flags */ #define VPROT_SYSTEM 0x0200 /* system view (underlying mmap not under our control) */ #define VPROT_PLACEHOLDER 0x0400 +#define VPROT_FROMPLACEHOLDER 0x0800 /* Conversion from VPROT_* to Win32 flags */ static const BYTE VIRTUAL_Win32Flags[16] = @@ -2003,6 +2004,31 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, void *ptr; NTSTATUS status; + if (alloc_type & MEM_REPLACE_PLACEHOLDER) + { + if ((*view_ret = find_view( base, 0 ))) + { + TRACE( "found view %p, size %p, protect %#x.\n", + (*view_ret)->base, (void *)(*view_ret)->size, (*view_ret)->protect ); + if ((*view_ret)->base != base || (*view_ret)->size != size) + return STATUS_CONFLICTING_ADDRESSES; + if (!((*view_ret)->protect & VPROT_PLACEHOLDER)) + { + TRACE("Wrong protect %#x for MEM_REPLACE_PLACEHOLDER.\n", (*view_ret)->protect); + return STATUS_INVALID_PARAMETER; + } + (*view_ret)->protect = vprot | VPROT_FROMPLACEHOLDER; + + if (!set_vprot( *view_ret, base, size, vprot | VPROT_COMMITTED )) + ERR("set_protection failed.\n"); + if (vprot & VPROT_WRITEWATCH) + reset_write_watches( base, size ); + return STATUS_SUCCESS; + } + TRACE("MEM_REPLACE_PLACEHOLDER view not found.\n"); + return STATUS_INVALID_PARAMETER; + } + if (base) { if (is_beyond_limit( base, size, address_space_limit )) @@ -3898,7 +3924,7 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ if (*ret) { - if (type & MEM_RESERVE) /* Round down to 64k boundary */ + if (type & MEM_RESERVE && !(type & MEM_REPLACE_PLACEHOLDER)) /* Round down to 64k boundary */ base = ROUND_ADDR( *ret, granularity_mask ); else base = ROUND_ADDR( *ret, page_mask ); @@ -3922,7 +3948,8 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ /* Compute the alloc type flags */ - if (!(type & (MEM_COMMIT | MEM_RESERVE | MEM_RESET))) + if (!(type & (MEM_COMMIT | MEM_RESERVE | MEM_RESET)) + || (type & MEM_REPLACE_PLACEHOLDER && !(type & MEM_RESERVE))) { WARN("called with wrong alloc type flags (%08x) !\n", (int)type); return STATUS_INVALID_PARAMETER; @@ -3949,7 +3976,7 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ if (vprot & VPROT_WRITECOPY) status = STATUS_INVALID_PAGE_PROTECTION; else if (is_dos_memory) status = allocate_dos_memory( &view, vprot ); - else status = map_view( &view, base, size, type & MEM_TOP_DOWN, vprot, limit, + else status = map_view( &view, base, size, type & (MEM_TOP_DOWN | MEM_REPLACE_PLACEHOLDER), vprot, limit, align ? align - 1 : granularity_mask ); if (status == STATUS_SUCCESS) base = view->base; @@ -4059,7 +4086,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemoryEx( HANDLE process, PVOID *ret, SIZE_T *s ULONG count ) { static const ULONG type_mask = MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN | MEM_WRITE_WATCH - | MEM_RESET | MEM_RESERVE_PLACEHOLDER; + | MEM_RESET | MEM_RESERVE_PLACEHOLDER | MEM_REPLACE_PLACEHOLDER; ULONG_PTR limit = 0; ULONG_PTR align = 0; @@ -4213,6 +4240,12 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si if (size && (char *)view->base + view->size - base < size) status = STATUS_UNABLE_TO_FREE_VM; else if (!size && base != view->base) status = STATUS_FREE_VM_NOT_AT_BASE; + else if (type == (MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER) && !size) status = STATUS_INVALID_PARAMETER_3; + else if (type == (MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER) && !((view->protect & VPROT_FROMPLACEHOLDER) + || (view->protect & VPROT_PLACEHOLDER && size != view->size))) + { + status = STATUS_CONFLICTING_ADDRESSES; + } else { if (!size) size = view->size; From 2faf72057f3d05e18f288ba70ede8af7b71b5382 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 10 Nov 2022 19:01:50 -0600 Subject: [PATCH 0579/2777] ntdll: Support MEM_REPLACE_PLACEHOLDER in virtual_map_section(). Based on a patch by Nikolay Sivov. --- dlls/ntdll/unix/virtual.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 7d8961c4eec..101d5673129 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -2709,7 +2709,8 @@ static unsigned int virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG_P server_enter_uninterrupted_section( &virtual_mutex, &sigset ); - res = map_view( &view, base, size, alloc_type & MEM_TOP_DOWN, vprot, get_zero_bits_mask( zero_bits ), 0 ); + res = map_view( &view, base, size, alloc_type & (MEM_TOP_DOWN | MEM_REPLACE_PLACEHOLDER), + vprot, get_zero_bits_mask( zero_bits ), 0 ); if (res) goto done; TRACE( "handle=%p size=%lx offset=%s\n", handle, size, wine_dbgstr_longlong(offset.QuadPart) ); From 7469c7e58c48326ed9bed83e994a5c351cf5c0b9 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 9 Nov 2022 21:23:19 -0600 Subject: [PATCH 0580/2777] ntdll/tests: Add more tests for placeholders. --- dlls/kernelbase/tests/process.c | 15 ++- dlls/ntdll/tests/virtual.c | 227 +++++++++++++++++++++++--------- 2 files changed, 179 insertions(+), 63 deletions(-) diff --git a/dlls/kernelbase/tests/process.c b/dlls/kernelbase/tests/process.c index ed213f1f7b6..0d75c6e2dda 100644 --- a/dlls/kernelbase/tests/process.c +++ b/dlls/kernelbase/tests/process.c @@ -168,7 +168,6 @@ static void test_VirtualAlloc2(void) /* Placeholder splitting functionality */ placeholder1 = pVirtualAlloc2(NULL, NULL, 2 * size, MEM_RESERVE_PLACEHOLDER | MEM_RESERVE, PAGE_NOACCESS, NULL, 0); - todo_wine ok(!!placeholder1, "Failed to create a placeholder range.\n"); if (!placeholder1) return; @@ -206,6 +205,20 @@ static void test_VirtualAlloc2(void) view2 = pMapViewOfFile3(section, NULL, placeholder2, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0); ok(!!view2, "Failed to map a section.\n"); + memset(&info, 0, sizeof(info)); + VirtualQuery(placeholder1, &info, sizeof(info)); + ok(info.AllocationProtect == PAGE_READWRITE, "Unexpected protection %#lx.\n", info.AllocationProtect); + ok(info.State == MEM_COMMIT, "Unexpected state %#lx.\n", info.State); + ok(info.Type == MEM_MAPPED, "Unexpected type %#lx.\n", info.Type); + ok(info.RegionSize == size, "Unexpected size.\n"); + + memset(&info, 0, sizeof(info)); + VirtualQuery(placeholder2, &info, sizeof(info)); + ok(info.AllocationProtect == PAGE_READWRITE, "Unexpected protection %#lx.\n", info.AllocationProtect); + ok(info.State == MEM_COMMIT, "Unexpected state %#lx.\n", info.State); + ok(info.Type == MEM_MAPPED, "Unexpected type %#lx.\n", info.Type); + ok(info.RegionSize == size, "Unexpected size.\n"); + CloseHandle(section); UnmapViewOfFile(view1); UnmapViewOfFile(view2); diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index 486efabaf70..b41f42ac9d1 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -291,9 +291,13 @@ static void check_region_size_(void *p, SIZE_T s, unsigned int line) static void test_NtAllocateVirtualMemoryEx(void) { + MEMORY_BASIC_INFORMATION mbi; + void *addresses[16]; SIZE_T size, size2; char *p, *p1, *p2; + ULONG granularity; NTSTATUS status; + ULONG_PTR count; void *addr1; if (!pNtAllocateVirtualMemoryEx) @@ -329,98 +333,197 @@ static void test_NtAllocateVirtualMemoryEx(void) status = NtAllocateVirtualMemory(NtCurrentProcess(), &addr1, 0, &size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS); ok(status == STATUS_INVALID_PARAMETER, "Unexpected status %08lx.\n", status); + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, + PAGE_READWRITE, NULL, 0); + ok(status == STATUS_INVALID_PARAMETER, "Unexpected status %08lx.\n", status); + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, NULL, 0); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - if (addr1) - { - size = 0; - status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - } + size = 0x10000; + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_COMMIT | MEM_REPLACE_PLACEHOLDER, + PAGE_READWRITE, NULL, 0); + ok(!status, "Unexpected status %08lx.\n", status); + + memset(addr1, 0xcc, size); + + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&addr1, &size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + ok(!status, "Unexpected status %08lx.\n", status); + + size = 0x10000; + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_COMMIT | MEM_REPLACE_PLACEHOLDER, + PAGE_READONLY, NULL, 0); + ok(!status, "Unexpected status %08lx.\n", status); + + ok(!*(unsigned int *)addr1, "Got %#x.\n", *(unsigned int *)addr1); + + status = NtQueryVirtualMemory( NtCurrentProcess(), addr1, MemoryBasicInformation, &mbi, sizeof(mbi), &size ); + ok(!status, "Unexpected status %08lx.\n", status); + ok(mbi.AllocationProtect == PAGE_READONLY, "Unexpected protection %#lx.\n", mbi.AllocationProtect); + ok(mbi.State == MEM_COMMIT, "Unexpected state %#lx.\n", mbi.State); + ok(mbi.Type == MEM_PRIVATE, "Unexpected type %#lx.\n", mbi.Type); + ok(mbi.RegionSize == 0x10000, "Unexpected size.\n"); + + size = 0x10000; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&addr1, &size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + ok(!status, "Unexpected status %08lx.\n", status); + + status = NtQueryVirtualMemory( NtCurrentProcess(), addr1, MemoryBasicInformation, &mbi, sizeof(mbi), &size ); + ok(!status, "Unexpected status %08lx.\n", status); + ok(mbi.AllocationProtect == PAGE_NOACCESS, "Unexpected protection %#lx.\n", mbi.AllocationProtect); + ok(mbi.State == MEM_RESERVE, "Unexpected state %#lx.\n", mbi.State); + ok(mbi.Type == MEM_PRIVATE, "Unexpected type %#lx.\n", mbi.Type); + ok(mbi.RegionSize == 0x10000, "Unexpected size.\n"); + + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, + PAGE_NOACCESS, NULL, 0); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE, + PAGE_NOACCESS, NULL, 0); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + + size = 0x1000; + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_REPLACE_PLACEHOLDER, + PAGE_NOACCESS, NULL, 0); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + + size = 0x10000; + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_COMMIT, PAGE_READWRITE, NULL, 0); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + + size = 0x10000; + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0); + ok(status == STATUS_INVALID_PARAMETER, "Unexpected status %08lx.\n", status); + + size = 0x10000; + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_COMMIT | MEM_REPLACE_PLACEHOLDER, + PAGE_READWRITE, NULL, 0); + ok(status == STATUS_INVALID_PARAMETER, "Unexpected status %08lx.\n", status); + + size = 0x10000; + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, + MEM_WRITE_WATCH | MEM_RESERVE | MEM_REPLACE_PLACEHOLDER, + PAGE_READONLY, NULL, 0); + ok(!status, "Unexpected status %08lx.\n", status); + + size = 0x10000; + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_COMMIT, PAGE_READWRITE, NULL, 0); + ok(!status, "Unexpected status %08lx.\n", status); + + status = NtQueryVirtualMemory( NtCurrentProcess(), addr1, MemoryBasicInformation, &mbi, sizeof(mbi), &size ); + ok(!status, "Unexpected status %08lx.\n", status); + ok(mbi.AllocationProtect == PAGE_READONLY, "Unexpected protection %#lx.\n", mbi.AllocationProtect); + ok(mbi.State == MEM_COMMIT, "Unexpected state %#lx.\n", mbi.State); + ok(mbi.Type == MEM_PRIVATE, "Unexpected type %#lx.\n", mbi.Type); + ok(mbi.RegionSize == 0x10000, "Unexpected size.\n"); + + size = 0x10000; + count = ARRAY_SIZE(addresses); + status = NtGetWriteWatch( NtCurrentProcess(), WRITE_WATCH_FLAG_RESET, addr1, size, + addresses, &count, &granularity ); + ok(!status, "Unexpected status %08lx.\n", status); + ok(!count, "Unexpected count %u.\n", (unsigned int)count); + trace("addr1 %p, addresses[0] %p.\n", addr1, addresses[0]); + *((char *)addr1 + 0x1000) = 1; + count = ARRAY_SIZE(addresses); + status = NtGetWriteWatch( NtCurrentProcess(), WRITE_WATCH_FLAG_RESET, addr1, size, + addresses, &count, &granularity ); + ok(!status, "Unexpected status %08lx.\n", status); + ok(count == 1, "Unexpected count %u.\n", (unsigned int)count); + ok(addresses[0] == (char *)addr1 + 0x1000, "Unexpected address %p.\n", addresses[0]); + + size = 0; + status = NtFreeVirtualMemory(NtCurrentProcess(), &addr1, &size, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); /* Placeholder region splitting. */ + addr1 = NULL; + size = 0x10000; + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE, + PAGE_NOACCESS, NULL, 0); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + p = addr1; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p, &size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p, &size, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + /* Split in three regions. */ addr1 = NULL; size = 0x10000; status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, NULL, 0); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - if (status == STATUS_SUCCESS) - { - p = addr1; - p1 = p + size / 2; - p2 = p1 + size / 4; - size2 = size / 4; - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - - check_region_size(p, size / 2); - check_region_size(p1, size / 4); - check_region_size(p2, size - size / 2 - size / 4); - - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p, &size2, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - } + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&addr1, &size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + + p = addr1; + p1 = p + size / 2; + p2 = p1 + size / 4; + size2 = size / 4; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + + check_region_size(p, size / 2); + check_region_size(p1, size / 4); + check_region_size(p2, size - size / 2 - size / 4); + + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p, &size2, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); /* Split in two regions, specifying lower part. */ addr1 = NULL; size = 0x10000; status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, NULL, 0); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - if (status == STATUS_SUCCESS) - { - p1 = addr1; - p2 = p1 + size / 4; - size2 = size / 4; - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - ok(p1 == addr1, "Unexpected address.\n"); - - check_region_size(p1, size / 4); - check_region_size(p2, size - size / 4); - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - } + size2 = 0; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&addr1, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + ok(status == STATUS_INVALID_PARAMETER_3, "Unexpected status %08lx.\n", status); + + p1 = addr1; + p2 = p1 + size / 4; + size2 = size / 4; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(p1 == addr1, "Unexpected address.\n"); + + check_region_size(p1, size / 4); + check_region_size(p2, size - size / 4); + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); /* Split in two regions, specifying second half. */ addr1 = NULL; size = 0x10000; status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), &addr1, &size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, NULL, 0); - todo_wine ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - if (status == STATUS_SUCCESS) - { - p1 = addr1; - p2 = p1 + size / 2; - - size2 = size / 2; - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - ok(p2 == p1 + size / 2, "Unexpected address.\n"); - check_region_size(p1, size / 2); - check_region_size(p2, size / 2); - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE); - ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); - } + p1 = addr1; + p2 = p1 + size / 2; + + size2 = size / 2; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + ok(p2 == p1 + size / 2, "Unexpected address.\n"); + check_region_size(p1, size / 2); + check_region_size(p2, size / 2); + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); } static void test_NtAllocateVirtualMemoryEx_address_requirements(void) From 0f9d76de3a3c0839a5dcaf8704555a19782a66b6 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 10 Nov 2022 19:02:50 -0600 Subject: [PATCH 0581/2777] ntdll: Support MEM_COALESCE_PLACEHOLDERS in NtFreeVirtualMemory(). --- dlls/ntdll/tests/virtual.c | 53 +++++++++++++++++++++++++++++++++++++- dlls/ntdll/unix/virtual.c | 24 +++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index b41f42ac9d1..11ccca2ffb4 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -499,11 +499,62 @@ static void test_NtAllocateVirtualMemoryEx(void) check_region_size(p1, size / 4); check_region_size(p2, size - size / 4); - status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE); + + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size, MEM_COALESCE_PLACEHOLDERS); + ok(status == STATUS_INVALID_PARAMETER_4, "Unexpected status %08lx.\n", status); + + size2 = size + 0x1000; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + + size2 = size - 0x1000; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + + p1 = (char *)addr1 + 0x1000; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + p1 = addr1; + + size2 = 0; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS); + ok(status == STATUS_INVALID_PARAMETER_3, "Unexpected status %08lx.\n", status); + + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size, MEM_RELEASE); + ok(status == STATUS_UNABLE_TO_FREE_VM, "Unexpected status %08lx.\n", status); + + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + check_region_size(p1, size); + + size2 = size / 4; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + check_region_size(p1, size / 4); + check_region_size(p2, size - size / 4); + + size2 = size - size / 4; + status = pNtAllocateVirtualMemoryEx(NtCurrentProcess(), (void **)&p2, &size2, MEM_RESERVE | MEM_REPLACE_PLACEHOLDER, + PAGE_READWRITE, NULL, 0); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + + size2 = size - size / 4; status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p2, &size2, MEM_RELEASE); ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size, MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS); + ok(status == STATUS_CONFLICTING_ADDRESSES, "Unexpected status %08lx.\n", status); + + size2 = size / 4; + status = NtFreeVirtualMemory(NtCurrentProcess(), (void **)&p1, &size2, MEM_RELEASE); + ok(status == STATUS_SUCCESS, "Unexpected status %08lx.\n", status); + /* Split in two regions, specifying second half. */ addr1 = NULL; size = 0x10000; diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 101d5673129..95600e01563 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -4343,6 +4343,30 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si *size_ptr = size; } } + else if (type & MEM_COALESCE_PLACEHOLDERS) + { + struct file_view *next_view = RB_ENTRY_VALUE( rb_next( &view->entry ), struct file_view, entry ); + + if (type != (MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS)) status = STATUS_INVALID_PARAMETER_4; + else if (!size) status = STATUS_INVALID_PARAMETER_3; + else if (!next_view || (char *)view->base + view->size != next_view->base + || base != view->base || size != view->size + next_view->size + || !(view->protect & VPROT_PLACEHOLDER) || !(next_view->protect & VPROT_PLACEHOLDER)) + { + status = STATUS_CONFLICTING_ADDRESSES; + } + else + { + unregister_view( view ); + unregister_view( next_view ); + + view->size += next_view->size; + free_view( next_view ); + + register_view( view ); + VIRTUAL_DEBUG_DUMP_VIEW( view ); + } + } else { WARN("called with wrong free type flags (%08x) !\n", (int)type); From 58770925b5a4f58ff297fa827e5373318beff0bf Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 11 Nov 2022 12:41:31 -0600 Subject: [PATCH 0582/2777] ntdll: Factor out unmap_view_of_section() function. --- dlls/ntdll/unix/virtual.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 95600e01563..3b4aa96e775 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -5013,11 +5013,7 @@ NTSTATUS WINAPI NtMapViewOfSectionEx( HANDLE handle, HANDLE process, PVOID *addr return NtMapViewOfSection( handle, process, addr_ptr, 0, 0, offset_ptr, size_ptr, ViewShare, alloc_type, protect ); } -/*********************************************************************** - * NtUnmapViewOfSection (NTDLL.@) - * ZwUnmapViewOfSection (NTDLL.@) - */ -NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) +NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr ) { struct file_view *view; unsigned int status = STATUS_NOT_MAPPED_VIEW; @@ -5074,6 +5070,15 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) return status; } +/*********************************************************************** + * NtUnmapViewOfSection (NTDLL.@) + * ZwUnmapViewOfSection (NTDLL.@) + */ +NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) +{ + return unmap_view_of_section( process, addr ); +} + /*********************************************************************** * NtUnmapViewOfSectionEx (NTDLL.@) * ZwUnmapViewOfSectionEx (NTDLL.@) @@ -5081,7 +5086,7 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) NTSTATUS WINAPI NtUnmapViewOfSectionEx( HANDLE process, PVOID addr, ULONG flags ) { if (flags) FIXME("Ignoring flags %#x.\n", (int)flags); - return NtUnmapViewOfSection( process, addr ); + return unmap_view_of_section( process, addr ); } /****************************************************************************** From a888859842ec06a2d355c00cad4a9928075e7abd Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 11 Nov 2022 12:54:19 -0600 Subject: [PATCH 0583/2777] ntdll: Support MEM_PRESERVE_PLACEHOLDER in NtUnmapViewOfSectionEx(). --- dlls/kernelbase/tests/process.c | 53 +++++++++++++++++++++++++++++++-- dlls/ntdll/unix/server.c | 2 +- dlls/ntdll/unix/virtual.c | 25 +++++++++++++--- server/protocol.def | 1 + 4 files changed, 73 insertions(+), 8 deletions(-) diff --git a/dlls/kernelbase/tests/process.c b/dlls/kernelbase/tests/process.c index 0d75c6e2dda..5221a102863 100644 --- a/dlls/kernelbase/tests/process.c +++ b/dlls/kernelbase/tests/process.c @@ -41,6 +41,7 @@ static PVOID (WINAPI *pVirtualAllocFromApp)(PVOID, SIZE_T, DWORD, DWORD); static HANDLE (WINAPI *pOpenFileMappingFromApp)( ULONG, BOOL, LPCWSTR); static HANDLE (WINAPI *pCreateFileMappingFromApp)(HANDLE, PSECURITY_ATTRIBUTES, ULONG, ULONG64, PCWSTR); static LPVOID (WINAPI *pMapViewOfFileFromApp)(HANDLE, ULONG, ULONG64, SIZE_T); +static BOOL (WINAPI *pUnmapViewOfFile2)(HANDLE, void *, ULONG); static void test_CompareObjectHandles(void) { @@ -166,6 +167,13 @@ static void test_VirtualAlloc2(void) ret = VirtualFree(addr, 0, MEM_RELEASE); ok(ret, "Unexpected return value %d, error %lu.\n", ret, GetLastError()); + placeholder1 = pVirtualAlloc2(NULL, NULL, 2 * size, MEM_RESERVE, PAGE_NOACCESS, NULL, 0); + ok(!!placeholder1, "Failed to create a placeholder range.\n"); + ret = VirtualFree(placeholder1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got ret %d, error %lu.\n", ret, GetLastError()); + ret = VirtualFree(placeholder1, 0, MEM_RELEASE); + ok(ret, "Unexpected return value %d, error %lu.\n", ret, GetLastError()); + /* Placeholder splitting functionality */ placeholder1 = pVirtualAlloc2(NULL, NULL, 2 * size, MEM_RESERVE_PLACEHOLDER | MEM_RESERVE, PAGE_NOACCESS, NULL, 0); ok(!!placeholder1, "Failed to create a placeholder range.\n"); @@ -199,11 +207,20 @@ static void test_VirtualAlloc2(void) section = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL); ok(!!section, "Failed to create a section.\n"); - view1 = pMapViewOfFile3(section, NULL, placeholder1, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0); + view1 = pMapViewOfFile3(section, NULL, NULL, 0, size, 0, PAGE_READWRITE, NULL, 0); ok(!!view1, "Failed to map a section.\n"); + ret = VirtualFree( view1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER ); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got ret %d, error %lu.\n", ret, GetLastError()); + ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, MEM_PRESERVE_PLACEHOLDER); + ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got ret %d, error %lu.\n", ret, GetLastError()); + ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, 0); + ok(ret, "Got error %lu.\n", GetLastError()); + + view1 = pMapViewOfFile3(section, NULL, placeholder1, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0); + ok(view1 == placeholder1, "Address does not match.\n"); view2 = pMapViewOfFile3(section, NULL, placeholder2, 0, size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, NULL, 0); - ok(!!view2, "Failed to map a section.\n"); + ok(view2 == placeholder2, "Address does not match.\n"); memset(&info, 0, sizeof(info)); VirtualQuery(placeholder1, &info, sizeof(info)); @@ -220,7 +237,34 @@ static void test_VirtualAlloc2(void) ok(info.RegionSize == size, "Unexpected size.\n"); CloseHandle(section); - UnmapViewOfFile(view1); + ret = pUnmapViewOfFile2(NULL, view1, MEM_PRESERVE_PLACEHOLDER); + ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Got error %lu.\n", GetLastError()); + + ret = VirtualFree( placeholder1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER ); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got ret %d, error %lu.\n", ret, GetLastError()); + + ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, MEM_PRESERVE_PLACEHOLDER); + ok(ret, "Got error %lu.\n", GetLastError()); + memset(&info, 0, sizeof(info)); + VirtualQuery(placeholder1, &info, sizeof(info)); + ok(info.AllocationProtect == PAGE_NOACCESS, "Unexpected protection %#lx.\n", info.AllocationProtect); + ok(info.State == MEM_RESERVE, "Unexpected state %#lx.\n", info.State); + ok(info.Type == MEM_PRIVATE, "Unexpected type %#lx.\n", info.Type); + ok(info.RegionSize == size, "Unexpected size.\n"); + + ret = pUnmapViewOfFile2(GetCurrentProcess(), view1, MEM_PRESERVE_PLACEHOLDER); + ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got error %lu.\n", GetLastError()); + + ret = UnmapViewOfFile(view1); + ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got error %lu.\n", GetLastError()); + + ret = VirtualFree( placeholder1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER ); + ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got ret %d, error %lu.\n", ret, GetLastError()); + ret = VirtualFreeEx(GetCurrentProcess(), placeholder1, size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER ); + ok(!ret && GetLastError() == ERROR_INVALID_ADDRESS, "Got ret %d, error %lu.\n", ret, GetLastError()); + ret = VirtualFree(placeholder1, 0, MEM_RELEASE); + ok(ret, "Got error %lu.\n", GetLastError()); + UnmapViewOfFile(view2); VirtualFree(placeholder1, 0, MEM_RELEASE); @@ -250,6 +294,8 @@ static void test_VirtualAlloc2(void) p1 = p; p2 = p + size / 2; + ret = VirtualFree(p1, 0, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "Got ret %d, error %lu.\n", ret, GetLastError()); ret = VirtualFree(p1, size / 2, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER); ok(ret, "Failed to split a placeholder.\n"); check_region_size(p1, size / 2); @@ -447,6 +493,7 @@ static void init_funcs(void) X(VirtualAlloc2); X(VirtualAlloc2FromApp); X(VirtualAllocFromApp); + X(UnmapViewOfFile2); hmod = GetModuleHandleA("ntdll.dll"); diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 1235c2cc5b4..0658185c2e1 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -549,7 +549,7 @@ static void invoke_system_apc( const apc_call_t *call, apc_result_t *result, BOO result->type = call->type; addr = wine_server_get_ptr( call->unmap_view.addr ); if ((ULONG_PTR)addr == call->unmap_view.addr) - result->unmap_view.status = NtUnmapViewOfSection( NtCurrentProcess(), addr ); + result->unmap_view.status = NtUnmapViewOfSectionEx( NtCurrentProcess(), addr, call->unmap_view.flags ); else result->unmap_view.status = STATUS_INVALID_PARAMETER; break; diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 3b4aa96e775..027650b5448 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -5013,7 +5013,7 @@ NTSTATUS WINAPI NtMapViewOfSectionEx( HANDLE handle, HANDLE process, PVOID *addr return NtMapViewOfSection( handle, process, addr_ptr, 0, 0, offset_ptr, size_ptr, ViewShare, alloc_type, protect ); } -NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr ) +static NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr, ULONG flags ) { struct file_view *view; unsigned int status = STATUS_NOT_MAPPED_VIEW; @@ -5028,6 +5028,7 @@ NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr ) call.unmap_view.type = APC_UNMAP_VIEW; call.unmap_view.addr = wine_server_client_ptr( addr ); + call.unmap_view.flags = flags; status = server_queue_process_apc( process, &call, &result ); if (status == STATUS_SUCCESS) status = result.unmap_view.status; return status; @@ -5036,6 +5037,11 @@ NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr ) server_enter_uninterrupted_section( &virtual_mutex, &sigset ); if ((view = find_view( addr, 0 )) && !is_view_valloc( view )) { + if (flags & MEM_PRESERVE_PLACEHOLDER && !(view->protect & VPROT_FROMPLACEHOLDER)) + { + status = STATUS_CONFLICTING_ADDRESSES; + goto done; + } if (view->protect & VPROT_SYSTEM) { struct builtin_module *builtin; @@ -5062,10 +5068,21 @@ NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr ) if (!status) { if (view->protect & SEC_IMAGE) release_builtin_module( view->base ); - delete_view( view ); + if (flags & MEM_PRESERVE_PLACEHOLDER) + { + view->protect = VPROT_PLACEHOLDER; + set_page_vprot( view->base, view->size, 0 ); + if (anon_mmap_fixed(view->base, view->size, 0, 0) != view->base) + ERR("anon_mmap_fixed failed, err %s.\n", strerror(errno)); + } + else + { + delete_view( view ); + } } else FIXME( "failed to unmap %p %x\n", view->base, status ); } +done: server_leave_uninterrupted_section( &virtual_mutex, &sigset ); return status; } @@ -5076,7 +5093,7 @@ NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr ) */ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) { - return unmap_view_of_section( process, addr ); + return unmap_view_of_section( process, addr, 0 ); } /*********************************************************************** @@ -5086,7 +5103,7 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr ) NTSTATUS WINAPI NtUnmapViewOfSectionEx( HANDLE process, PVOID addr, ULONG flags ) { if (flags) FIXME("Ignoring flags %#x.\n", (int)flags); - return unmap_view_of_section( process, addr ); + return unmap_view_of_section( process, addr, flags ); } /****************************************************************************** diff --git a/server/protocol.def b/server/protocol.def index 3a2101b08df..deb246584e4 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -602,6 +602,7 @@ typedef union enum apc_type type; /* APC_UNMAP_VIEW */ int __pad; client_ptr_t addr; /* view address */ + unsigned int flags; /* unmap flags */ } unmap_view; struct { From c7b15bb988e59b7e27644d4eae30966a2886cb46 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 14 Jan 2020 21:39:23 +0300 Subject: [PATCH 0584/2777] ntdll: Increase step after failed map attempt in try_map_free_area(). --- dlls/ntdll/unix/virtual.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 027650b5448..5d08aebd8ee 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -1311,6 +1311,7 @@ static void* try_map_free_area( void *base, void *end, ptrdiff_t step, step == 0) break; start = (char *)start + step; + step *= 2; } return NULL; From ce9a0b09c53b4e25836e271657aaca5126b69064 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 23 Jul 2020 18:40:39 +0300 Subject: [PATCH 0585/2777] ntdll: Increase free ranges view block size on 64 bit. --- dlls/ntdll/unix/virtual.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 5d08aebd8ee..d4efff54478 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -214,7 +214,11 @@ static int pagemap_fd, pagemap_reset_fd, clear_refs_fd; static void reset_write_watches( void *base, SIZE_T size ); static struct file_view *view_block_start, *view_block_end, *next_free_view; +#ifdef _WIN64 +static const size_t view_block_size = 0x200000; +#else static const size_t view_block_size = 0x100000; +#endif static void *preload_reserve_start; static void *preload_reserve_end; static BOOL force_exec_prot; /* whether to force PROT_EXEC on all PROT_READ mmaps */ From 65e9547323d87e414d7652c3baff9a2c970e9005 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 25 Nov 2019 12:19:20 +0300 Subject: [PATCH 0586/2777] ntdll: Force virtual memory allocation order. Windows allocates virtual memory strictly bottom up or top down depending on the requested flags (when ASLR is disabled). Modern Linux VM allocator always allocates memory top down. Some applications break if the allocated memory addresses are from higher memory than they expect. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48175 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46568 --- dlls/ntdll/unix/virtual.c | 450 +++++++++++++++++++------------------- 1 file changed, 227 insertions(+), 223 deletions(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index d4efff54478..d68a66582c5 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -1250,44 +1250,15 @@ static struct file_view *find_view_range( const void *addr, size_t size ) return NULL; } - -/*********************************************************************** - * find_view_inside_range - * - * Find first (resp. last, if top_down) view inside a range. - * virtual_mutex must be held by caller. - */ -static struct wine_rb_entry *find_view_inside_range( void **base_ptr, void **end_ptr, int top_down ) +struct alloc_area { - struct wine_rb_entry *first = NULL, *ptr = views_tree.root; - void *base = *base_ptr, *end = *end_ptr; - - /* find the first (resp. last) view inside the range */ - while (ptr) - { - struct file_view *view = WINE_RB_ENTRY_VALUE( ptr, struct file_view, entry ); - if ((char *)view->base + view->size >= (char *)end) - { - end = min( end, view->base ); - ptr = ptr->left; - } - else if (view->base <= base) - { - base = max( (char *)base, (char *)view->base + view->size ); - ptr = ptr->right; - } - else - { - first = ptr; - ptr = top_down ? ptr->right : ptr->left; - } - } - - *base_ptr = base; - *end_ptr = end; - return first; -} - + char *map_area_start, *map_area_end, *result; + size_t size; + ptrdiff_t step; + int unix_prot; + BOOL top_down; + UINT_PTR align_mask; +}; /*********************************************************************** * try_map_free_area @@ -1321,110 +1292,6 @@ static void* try_map_free_area( void *base, void *end, ptrdiff_t step, return NULL; } - -/*********************************************************************** - * map_free_area - * - * Find a free area between views inside the specified range and map it. - * virtual_mutex must be held by caller. - */ -static void *map_free_area( void *base, void *end, size_t size, int top_down, int unix_prot, size_t align_mask ) -{ - struct wine_rb_entry *first = find_view_inside_range( &base, &end, top_down ); - ptrdiff_t step = top_down ? -(align_mask + 1) : (align_mask + 1); - void *start; - - if (top_down) - { - start = ROUND_ADDR( (char *)end - size, align_mask ); - if (start >= end || start < base) return NULL; - - while (first) - { - struct file_view *view = WINE_RB_ENTRY_VALUE( first, struct file_view, entry ); - if ((start = try_map_free_area( (char *)view->base + view->size, (char *)start + size, step, - start, size, unix_prot ))) break; - start = ROUND_ADDR( (char *)view->base - size, align_mask ); - /* stop if remaining space is not large enough */ - if (!start || start >= end || start < base) return NULL; - first = rb_prev( first ); - } - } - else - { - start = ROUND_ADDR( (char *)base + align_mask, align_mask ); - if (!start || start >= end || (char *)end - (char *)start < size) return NULL; - - while (first) - { - struct file_view *view = WINE_RB_ENTRY_VALUE( first, struct file_view, entry ); - if ((start = try_map_free_area( start, view->base, step, - start, size, unix_prot ))) break; - start = ROUND_ADDR( (char *)view->base + view->size + align_mask, align_mask ); - /* stop if remaining space is not large enough */ - if (!start || start >= end || (char *)end - (char *)start < size) return NULL; - first = rb_next( first ); - } - } - - if (!first) - return try_map_free_area( base, end, step, start, size, unix_prot ); - - return start; -} - - -/*********************************************************************** - * find_reserved_free_area - * - * Find a free area between views inside the specified range. - * virtual_mutex must be held by caller. - * The range must be inside the preloader reserved range. - */ -static void *find_reserved_free_area( void *base, void *end, size_t size, int top_down, size_t align_mask ) -{ - struct range_entry *range; - void *start; - - base = ROUND_ADDR( (char *)base + align_mask, align_mask ); - end = (char *)ROUND_ADDR( (char *)end - size, align_mask ) + size; - - if (top_down) - { - start = (char *)end - size; - range = free_ranges_lower_bound( start ); - assert(range != free_ranges_end && range->end >= start); - - if ((char *)range->end - (char *)start < size) start = ROUND_ADDR( (char *)range->end - size, align_mask ); - do - { - if (start >= end || start < base || (char *)end - (char *)start < size) return NULL; - if (start < range->end && start >= range->base && (char *)range->end - (char *)start >= size) break; - if (--range < free_ranges) return NULL; - start = ROUND_ADDR( (char *)range->end - size, align_mask ); - } - while (1); - } - else - { - start = base; - range = free_ranges_lower_bound( start ); - assert(range != free_ranges_end && range->end >= start); - - if (start < range->base) start = ROUND_ADDR( (char *)range->base + align_mask, align_mask ); - do - { - if (start >= end || start < base || (char *)end - (char *)start < size) return NULL; - if (start < range->end && start >= range->base && (char *)range->end - (char *)start >= size) break; - if (++range == free_ranges_end) return NULL; - start = ROUND_ADDR( (char *)range->base + align_mask, align_mask ); - } - while (1); - } - return start; -} - - /*********************************************************************** * add_reserved_area * @@ -1592,8 +1459,7 @@ static void free_view( struct file_view *view ) */ static void unregister_view( struct file_view *view ) { - if (mmap_is_in_reserved_area( view->base, view->size )) - free_ranges_remove_view( view ); + free_ranges_remove_view( view ); wine_rb_remove( &views_tree, &view->entry ); } @@ -1620,8 +1486,7 @@ static void delete_view( struct file_view *view ) /* [in] View */ static void register_view( struct file_view *view ) { wine_rb_put( &views_tree, view->base, &view->entry ); - if (mmap_is_in_reserved_area( view->base, view->size )) - free_ranges_insert_view( view ); + free_ranges_insert_view( view ); } @@ -1896,55 +1761,229 @@ static inline void *unmap_extra_space( void *ptr, size_t total_size, size_t want return ptr; } - -struct alloc_area +static int alloc_area_in_reserved_or_between_callback( void *start, SIZE_T size, void *arg ) { - size_t size; - int top_down; - void *limit; - void *result; - size_t align_mask; -}; + char *intersect_start, *intersect_end; + char *end = (char *)start + size; + struct alloc_area *area = arg; + UINT_PTR align_mask; + char *alloc_start; -/*********************************************************************** - * alloc_reserved_area_callback - * - * Try to map some space inside a reserved area. Callback for mmap_enum_reserved_areas. - */ -static int alloc_reserved_area_callback( void *start, SIZE_T size, void *arg ) -{ - struct alloc_area *alloc = arg; - void *end = (char *)start + size; + align_mask = area->align_mask; + + if (area->top_down) + { + if (area->map_area_start >= end) + return 1; + + if (area->map_area_end <= (char *)start) + return 0; + + if ((ULONG_PTR)area->map_area_end < area->size) + return 1; + + intersect_start = max((char *)start, area->map_area_start); + intersect_end = min((char *)end, area->map_area_end); + assert(intersect_start <= intersect_end); + if (area->map_area_end - intersect_end >= area->size) + { + alloc_start = ROUND_ADDR( (char *)area->map_area_end - size, align_mask ); + if ((area->result = try_map_free_area( intersect_end, alloc_start + size, area->step, + alloc_start, area->size, area->unix_prot ))) + return 1; + } - if (start < address_space_start) start = address_space_start; - if (is_beyond_limit( start, size, alloc->limit )) end = alloc->limit; - if (start >= end) return 0; + if (intersect_end - intersect_start >= area->size) + { + alloc_start = ROUND_ADDR( intersect_end - area->size, align_mask ); + if (alloc_start >= intersect_start) + { + if ((area->result = anon_mmap_fixed( alloc_start, area->size, + area->unix_prot, 0 )) != alloc_start) + ERR("Could not map in reserved area, alloc_start %p, size %p.\n", + alloc_start, (void *)area->size); + return 1; + } + } - /* make sure we don't touch the preloader reserved range */ - if (preload_reserve_end >= start) + area->map_area_end = intersect_start; + if (area->map_area_end - area->map_area_start < area->size) + return 1; + } + else { - if (preload_reserve_end >= end) + if (area->map_area_end <= (char *)start) + return 1; + + if (area->map_area_start >= (char *)end) + return 0; + + if (area->map_area_start + align_mask < area->map_area_start) + return 1; + + intersect_start = max((char *)start, area->map_area_start); + intersect_end = min((char *)end, area->map_area_end); + assert(intersect_start <= intersect_end); + + if (intersect_start - area->map_area_start >= area->size) { - if (preload_reserve_start <= start) return 0; /* no space in that area */ - if (preload_reserve_start < end) end = preload_reserve_start; + alloc_start = ROUND_ADDR( area->map_area_start + align_mask, align_mask ); + if ((area->result = try_map_free_area( area->map_area_start, intersect_start, area->step, + alloc_start, area->size, area->unix_prot ))) + return 1; } - else if (preload_reserve_start <= start) start = preload_reserve_end; - else + + if (intersect_end - intersect_start >= area->size) { - /* range is split in two by the preloader reservation, try first part */ - if ((alloc->result = find_reserved_free_area( start, preload_reserve_start, alloc->size, - alloc->top_down, alloc->align_mask ))) + alloc_start = ROUND_ADDR( intersect_start + align_mask, align_mask ); + if (alloc_start + area->size <= intersect_end) + { + if ((area->result = anon_mmap_fixed( alloc_start, area->size, area->unix_prot, 0 )) != alloc_start) + ERR("Could not map in reserved area, alloc_start %p, size %p.\n", alloc_start, (void *)area->size); return 1; - /* then fall through to try second part */ - start = preload_reserve_end; + } } + area->map_area_start = intersect_end; + if (area->map_area_end - area->map_area_start < area->size) + return 1; } - if ((alloc->result = find_reserved_free_area( start, end, alloc->size, alloc->top_down, alloc->align_mask ))) - return 1; return 0; } +static void *alloc_free_area_in_range( struct alloc_area *area, char *base, char *end ) +{ + UINT_PTR align_mask = area->align_mask; + char *start; + + TRACE("range %p-%p.\n", base, end); + + if (base >= end) + return NULL; + + area->map_area_start = base; + area->map_area_end = end; + + if (area->top_down) + { + if ((ULONG_PTR)end < area->size) return NULL; + start = ROUND_ADDR( end - area->size, align_mask ); + if (start >= end || start < base) return NULL; + } + else + { + if (base + align_mask < base) return NULL; + start = ROUND_ADDR( base + align_mask, align_mask ); + if (!start || start >= end || (char *)end - (char *)start < area->size) + return NULL; + } + + mmap_enum_reserved_areas( alloc_area_in_reserved_or_between_callback, area, area->top_down ); + + if (area->result) + return area->result; + + if (area->top_down) + { + if ((ULONG_PTR)area->map_area_end < area->size) return NULL; + start = ROUND_ADDR( area->map_area_end - area->size, align_mask ); + if (start >= area->map_area_end || start < area->map_area_start) + return NULL; + + return try_map_free_area( area->map_area_start, start + area->size, area->step, + start, area->size, area->unix_prot ); + } + else + { + if (area->map_area_start + align_mask < area->map_area_start) return NULL; + start = ROUND_ADDR( area->map_area_start + align_mask, align_mask ); + if (!start || start >= area->map_area_end + || area->map_area_end - start < area->size) + return NULL; + + return try_map_free_area( start, area->map_area_end, area->step, + start, area->size, area->unix_prot ); + } +} + +static void *alloc_free_area( void *limit, size_t size, BOOL top_down, int unix_prot, UINT_PTR align_mask ) +{ + struct range_entry *range, *ranges_start, *ranges_end; + char *reserve_start, *reserve_end; + struct alloc_area area; + char *base, *end; + int ranges_inc; + + TRACE("limit %p, size %p, top_down %#x.\n", limit, (void *)size, top_down); + + if (top_down) + { + ranges_start = free_ranges_end - 1; + ranges_end = free_ranges - 1; + ranges_inc = -1; + } + else + { + ranges_start = free_ranges; + ranges_end = free_ranges_end; + ranges_inc = 1; + } + + memset( &area, 0, sizeof(area) ); + area.step = top_down ? -(align_mask + 1) : (align_mask + 1); + area.size = size; + area.top_down = top_down; + area.unix_prot = unix_prot; + area.align_mask = align_mask; + + reserve_start = preload_reserve_start; + reserve_end = preload_reserve_end; + + for (range = ranges_start; range != ranges_end; range += ranges_inc) + { + base = range->base; + end = range->end; + + TRACE("range %p-%p.\n", base, end); + + if (base >= (char *)limit) + continue; + + if (base < (char *)address_space_start) + base = (char *)address_space_start; + if (end > (char *)limit) + end = (char *)limit; + + if (reserve_end >= base) + { + if (reserve_end >= end) + { + if (reserve_start <= base) + continue; /* no space in that area */ + + if (reserve_start < end) + end = reserve_start; + } + else if (reserve_start <= base) + { + base = reserve_end; + } + else + { + /* range is split in two by the preloader reservation, try first part. */ + if ((area.result = alloc_free_area_in_range( &area, base, reserve_start ))) + break; + /* then fall through to try second part. */ + base = reserve_end; + } + } + + if ((area.result = alloc_free_area_in_range( &area, base, end ))) + break; + } + return NULL; +} + /*********************************************************************** * map_fixed_area * @@ -2009,6 +2048,8 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, void *ptr; NTSTATUS status; + limit = limit ? min( limit + 1, (UINT_PTR)user_space_limit) : (UINT_PTR)user_space_limit; + if (alloc_type & MEM_REPLACE_PLACEHOLDER) { if ((*view_ret = find_view( base, 0 ))) @@ -2034,6 +2075,8 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, return STATUS_INVALID_PARAMETER; } + if (!align_mask) align_mask = granularity_mask; + if (base) { if (is_beyond_limit( base, size, address_space_limit )) @@ -2042,52 +2085,10 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, if (status != STATUS_SUCCESS) return status; ptr = base; } - else + else if (!(ptr = alloc_free_area( (void *)limit, size, top_down, get_unix_prot( vprot ), align_mask ))) { - struct alloc_area alloc; - size_t view_size; - - if (!align_mask) align_mask = granularity_mask; - view_size = size + align_mask + 1; - - alloc.size = size; - alloc.top_down = top_down; - alloc.limit = limit ? min( (void *)(limit + 1), user_space_limit ) : user_space_limit; - alloc.align_mask = align_mask; - - if (mmap_enum_reserved_areas( alloc_reserved_area_callback, &alloc, top_down )) - { - ptr = alloc.result; - TRACE( "got mem in reserved area %p-%p\n", ptr, (char *)ptr + size ); - if (anon_mmap_fixed( ptr, size, get_unix_prot(vprot), 0 ) != ptr) - return STATUS_INVALID_PARAMETER; - goto done; - } - - if (limit) - { - if (!(ptr = map_free_area( address_space_start, alloc.limit, size, - top_down, get_unix_prot(vprot), align_mask ))) - return STATUS_NO_MEMORY; - TRACE( "got mem with map_free_area %p-%p\n", ptr, (char *)ptr + size ); - goto done; - } - - for (;;) - { - if ((ptr = anon_mmap_alloc( view_size, get_unix_prot(vprot) )) == MAP_FAILED) - { - if (errno == ENOMEM) return STATUS_NO_MEMORY; - return STATUS_INVALID_PARAMETER; - } - TRACE( "got mem with anon mmap %p-%p\n", ptr, (char *)ptr + size ); - /* if we got something beyond the user limit, unmap it and retry */ - if (is_beyond_limit( ptr, view_size, user_space_limit )) add_reserved_area( ptr, view_size ); - else break; - } - ptr = unmap_extra_space( ptr, view_size, size, align_mask ); + return STATUS_NO_MEMORY; } -done: status = create_view( view_ret, ptr, size, vprot ); if (status != STATUS_SUCCESS) unmap_area( ptr, size ); return status; @@ -2746,6 +2747,7 @@ static unsigned int virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG_P done: server_leave_uninterrupted_section( &virtual_mutex, &sigset ); if (needs_close) close( unix_handle ); + TRACE("status %#x.\n", res); return res; } @@ -2833,6 +2835,7 @@ void virtual_init(void) if (preload_reserve_start) address_space_start = min( address_space_start, preload_reserve_start ); } + TRACE("preload reserve %p-%p.\n", preload_reserve_start, preload_reserve_end); } /* try to find space in a reserved area for the views and pages protection table */ @@ -5697,6 +5700,7 @@ NTSTATUS WINAPI NtWow64AllocateVirtualMemory64( HANDLE process, ULONG64 *ret, UL *ret = (ULONG_PTR)base; *size_ptr = size; } + TRACE("status %#x.\n", status); return status; } From ce4e81644fbb1ecb3360f92e8b178f59d6b9ba36 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 2 Jun 2020 21:06:33 +0300 Subject: [PATCH 0587/2777] ntdll: Exclude natively mapped areas from free areas list. --- dlls/ntdll/unix/virtual.c | 118 ++++++++++++++++++++++++++++++++------ 1 file changed, 100 insertions(+), 18 deletions(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index d68a66582c5..b8dc029f15f 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -127,6 +127,7 @@ struct file_view #define VPROT_SYSTEM 0x0200 /* system view (underlying mmap not under our control) */ #define VPROT_PLACEHOLDER 0x0400 #define VPROT_FROMPLACEHOLDER 0x0800 +#define VPROT_NATIVE 0x1000 /* Conversion from VPROT_* to Win32 flags */ static const BYTE VIRTUAL_Win32Flags[16] = @@ -1113,7 +1114,9 @@ static void dump_view( struct file_view *view ) BYTE prot = get_page_vprot( addr ); TRACE( "View: %p - %p", addr, addr + view->size - 1 ); - if (view->protect & VPROT_SYSTEM) + if (view->protect & VPROT_NATIVE) + TRACE(" (native)\n"); + else if (view->protect & VPROT_SYSTEM) TRACE( " (builtin image)\n" ); else if (view->protect & VPROT_PLACEHOLDER) TRACE( " (placeholder)\n" ); @@ -1258,6 +1261,8 @@ struct alloc_area int unix_prot; BOOL top_down; UINT_PTR align_mask; + char *native_mapped; + size_t native_mapped_size; }; /*********************************************************************** @@ -1266,21 +1271,28 @@ struct alloc_area * Try mmaping some expected free memory region, eventually stepping and * retrying inside it, and return where it actually succeeded, or NULL. */ -static void* try_map_free_area( void *base, void *end, ptrdiff_t step, - void *start, size_t size, int unix_prot ) +static void* try_map_free_area( struct alloc_area *area, void *base, void *end, void *start ) { + ptrdiff_t step = area->step; + UINT_PTR abs_step = step > 0 ? step : -step; void *ptr; - while (start && base <= start && (char*)start + size <= (char*)end) + while (start && base <= start && (char*)start + area->size <= (char*)end) { - if ((ptr = anon_mmap_tryfixed( start, size, unix_prot, 0 )) != MAP_FAILED) return start; + if ((ptr = anon_mmap_tryfixed( start, area->size, area->unix_prot, 0 )) != MAP_FAILED) return start; TRACE( "Found free area is already mapped, start %p.\n", start ); if (errno != EEXIST) { ERR( "mmap() error %s, range %p-%p, unix_prot %#x.\n", - strerror(errno), start, (char *)start + size, unix_prot ); + strerror(errno), start, (char *)start + area->size, area->unix_prot ); return NULL; } + if (!area->native_mapped && step && abs_step < (granularity_mask + 1) * 2) + { + area->native_mapped = start; + area->native_mapped_size = abs_step; + area->native_mapped_size = min(area->native_mapped_size, (char *)end - (char *)start); + } if ((step > 0 && (char *)end - (char *)start < step) || (step < 0 && (char *)start - (char *)base < -step) || step == 0) @@ -1787,9 +1799,9 @@ static int alloc_area_in_reserved_or_between_callback( void *start, SIZE_T size, assert(intersect_start <= intersect_end); if (area->map_area_end - intersect_end >= area->size) { - alloc_start = ROUND_ADDR( (char *)area->map_area_end - size, align_mask ); - if ((area->result = try_map_free_area( intersect_end, alloc_start + size, area->step, - alloc_start, area->size, area->unix_prot ))) + alloc_start = ROUND_ADDR( (char *)area->map_area_end - area->size, align_mask ); + if ((area->result = try_map_free_area( area, intersect_end, + alloc_start + size, alloc_start ))) return 1; } @@ -1828,8 +1840,8 @@ static int alloc_area_in_reserved_or_between_callback( void *start, SIZE_T size, if (intersect_start - area->map_area_start >= area->size) { alloc_start = ROUND_ADDR( area->map_area_start + align_mask, align_mask ); - if ((area->result = try_map_free_area( area->map_area_start, intersect_start, area->step, - alloc_start, area->size, area->unix_prot ))) + if ((area->result = try_map_free_area( area, area->map_area_start, + intersect_start, alloc_start ))) return 1; } @@ -1890,8 +1902,7 @@ static void *alloc_free_area_in_range( struct alloc_area *area, char *base, char if (start >= area->map_area_end || start < area->map_area_start) return NULL; - return try_map_free_area( area->map_area_start, start + area->size, area->step, - start, area->size, area->unix_prot ); + return try_map_free_area( area, area->map_area_start, start + area->size, start ); } else { @@ -1901,8 +1912,7 @@ static void *alloc_free_area_in_range( struct alloc_area *area, char *base, char || area->map_area_end - start < area->size) return NULL; - return try_map_free_area( start, area->map_area_end, area->step, - start, area->size, area->unix_prot ); + return try_map_free_area( area, start, area->map_area_end, start ); } } @@ -1913,6 +1923,7 @@ static void *alloc_free_area( void *limit, size_t size, BOOL top_down, int unix_ struct alloc_area area; char *base, *end; int ranges_inc; + UINT status; TRACE("limit %p, size %p, top_down %#x.\n", limit, (void *)size, top_down); @@ -1981,7 +1992,58 @@ static void *alloc_free_area( void *limit, size_t size, BOOL top_down, int unix_ if ((area.result = alloc_free_area_in_range( &area, base, end ))) break; } - return NULL; + + if (area.native_mapped) + { + char *native_mapped_start, *native_mapped_end; + + TRACE("Excluding %p - %p from free list.\n", + area.native_mapped, (char *)area.native_mapped + area.native_mapped_size ); + + native_mapped_start = ROUND_ADDR(area.native_mapped, granularity_mask); + native_mapped_end = ROUND_ADDR((char *)area.native_mapped + area.native_mapped_size + granularity_mask, + granularity_mask); + + if (area.result >= native_mapped_end || area.result + size < native_mapped_start) + /* In case of top down allocation try_map_free_area() result area can overlap the + * area previously marked as native if the latter was unmapped behind our back. */ + { + struct file_view *prev, *next; + + prev = find_view_range( native_mapped_start - 1, native_mapped_end - native_mapped_start + 2 ); + if (prev && (char *)prev->base >= native_mapped_end) + { + next = prev; + prev = WINE_RB_ENTRY_VALUE( rb_prev( &next->entry ), struct file_view, entry ); + } + else if (prev) + { + next = WINE_RB_ENTRY_VALUE( rb_next( &prev->entry ), struct file_view, entry ); + } + else + { + next = NULL; + } + + if (prev && prev->protect & VPROT_NATIVE && (char *)prev->base + prev->size >= native_mapped_start) + { + assert( (char *)prev->base + prev->size == native_mapped_start ); + native_mapped_start = prev->base; + delete_view( prev ); + } + if (next && next->protect & VPROT_NATIVE && native_mapped_end >= (char *)next->base) + { + assert( native_mapped_end == (char *)next->base ); + native_mapped_end = (char *)next->base + next->size; + delete_view( next ); + } + if ((status = create_view( &next, native_mapped_start, native_mapped_end - native_mapped_start, + VPROT_SYSTEM | VPROT_NATIVE ))) + ERR("Could not create view for natively mapped area, status %#x.\n", status); + } + } + + return area.result; } /*********************************************************************** @@ -2035,6 +2097,17 @@ static NTSTATUS map_fixed_area( void *base, size_t size, unsigned int vprot ) return STATUS_SUCCESS; } +static void clear_native_views(void) +{ + struct file_view *view, *next_view; + + WINE_RB_FOR_EACH_ENTRY_DESTRUCTOR( view, next_view, &views_tree, struct file_view, entry ) + { + if (view->protect & VPROT_NATIVE) + delete_view( view ); + } +} + /*********************************************************************** * map_view * @@ -2087,7 +2160,11 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, } else if (!(ptr = alloc_free_area( (void *)limit, size, top_down, get_unix_prot( vprot ), align_mask ))) { - return STATUS_NO_MEMORY; + WARN("Allocation failed, clearing native views.\n"); + + clear_native_views(); + if (!(ptr = alloc_free_area( (void *)limit, size, top_down, get_unix_prot( vprot ), align_mask ))) + return STATUS_NO_MEMORY; } status = create_view( view_ret, ptr, size, vprot ); if (status != STATUS_SUCCESS) unmap_area( ptr, size ); @@ -3806,7 +3883,12 @@ void virtual_set_force_exec( BOOL enable ) WINE_RB_FOR_EACH_ENTRY( view, &views_tree, struct file_view, entry ) { /* file mappings are always accessible */ - BYTE commit = is_view_valloc( view ) ? 0 : VPROT_COMMITTED; + BYTE commit; + + if (view->protect & VPROT_NATIVE) + continue; + + commit = is_view_valloc( view ) ? 0 : VPROT_COMMITTED; mprotect_range( view->base, view->size, commit, 0 ); } From 979bae0f0260e2b1e9dd1aee149229d8cb610b97 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Sat, 11 Dec 2021 12:23:17 +0100 Subject: [PATCH 0588/2777] winevulkan: Add struct unwrappers for vrclient. --- dlls/winevulkan/vulkan.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 1df10cc89a6..40c02ed0ac6 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -1885,3 +1885,43 @@ NTSTATUS vk_is_available_device_function32(void *arg) struct wine_device *device = wine_device_from_handle(UlongToPtr(params->device)); return !!vk_funcs->p_vkGetDeviceProcAddr(device->device, UlongToPtr(params->name)); } + +VkDevice WINAPI __wine_get_native_VkDevice(VkDevice handle) +{ + struct wine_device *device = wine_device_from_handle(handle); + + return device->device; +} + +VkInstance WINAPI __wine_get_native_VkInstance(VkInstance handle) +{ + struct wine_instance *instance = wine_instance_from_handle(handle);; + + return instance->instance; +} + +VkPhysicalDevice WINAPI __wine_get_native_VkPhysicalDevice(VkPhysicalDevice handle) +{ + struct wine_phys_dev *phys_dev = wine_phys_dev_from_handle(handle); + + return phys_dev->phys_dev; +} + +VkQueue WINAPI __wine_get_native_VkQueue(VkQueue handle) +{ + struct wine_queue *queue = wine_queue_from_handle(handle); + + return queue->queue; +} + +VkPhysicalDevice WINAPI __wine_get_wrapped_VkPhysicalDevice(VkInstance handle, VkPhysicalDevice native_phys_dev) +{ + struct wine_instance *instance = wine_instance_from_handle(handle); + uint32_t i; + for(i = 0; i < instance->phys_dev_count; ++i){ + if(instance->phys_devs[i]->phys_dev == native_phys_dev) + return instance->phys_devs[i]->handle; + } + WARN("Unknown native physical device: %p\n", native_phys_dev); + return NULL; +} From b434c7a68f8acea0d1f4c216e6719380d4449b2d Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 18 Jun 2019 14:55:34 -0500 Subject: [PATCH 0589/2777] Revert "winevulkan: Check if instance extensions are supported." This reverts commit e84999bd7ab859746e893ed2d49b1d42b0323c3a. Vulkan VR games will try to load some extensions that winevulkan doesn't support. --- dlls/winevulkan/vulkan.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 40c02ed0ac6..c12c22198ad 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -536,11 +536,6 @@ static VkResult wine_vk_instance_convert_create_info(struct conversion_context * { const char *extension_name = dst->ppEnabledExtensionNames[i]; TRACE("Extension %u: %s.\n", i, debugstr_a(extension_name)); - if (!wine_vk_instance_extension_supported(extension_name)) - { - WARN("Extension %s is not supported.\n", debugstr_a(extension_name)); - return VK_ERROR_EXTENSION_NOT_PRESENT; - } if (!strcmp(extension_name, "VK_EXT_debug_utils") || !strcmp(extension_name, "VK_EXT_debug_report")) { object->enable_wrapper_list = VK_TRUE; From ae36981a1e09d6812e013ff2a660f4bfec7c332e Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 25 Sep 2018 14:53:05 -0500 Subject: [PATCH 0590/2777] Revert "winevulkan: Check if device extensions are supported." This reverts commit 4907ffdf2a15ab3a1e3749def37f4be67b758a35. Vulkan VR games will try to load some extensions that winevulkan doesn't support. --- dlls/winevulkan/vulkan.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index c12c22198ad..6f5b7c4a029 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -407,11 +407,6 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de { const char *extension_name = dst->ppEnabledExtensionNames[i]; TRACE("Extension %u: %s.\n", i, debugstr_a(extension_name)); - if (!wine_vk_device_extension_supported(extension_name)) - { - WARN("Extension %s is not supported.\n", debugstr_a(extension_name)); - return VK_ERROR_EXTENSION_NOT_PRESENT; - } } if (phys_dev->external_memory_align) From 08495a0ba1d76947624d3d9bf165516c04d8518b Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Mon, 4 Jan 2021 14:25:06 -0600 Subject: [PATCH 0591/2777] wine.inf: Add OpenXR registry entries --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 9b080bbbf85..a18177a4d42 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2724,6 +2724,7 @@ HKLM,Software\Wow6432Node\Valve\Steam,"InstallPath",,"%16422%\Steam" HKLM,Software\NVIDIA Corporation\Global\NGXCore,"FullPath",,"C:\Windows\System32" [ProtonOverrides] +HKLM,Software\Khronos\OpenXR\1,"ActiveRuntime",,"C:\openxr\wineopenxr64.json" ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" HKCU,Software\Wine\DllOverrides,"msvcp100",0x2,"native,builtin" From 25ee79e476440f1bca507dfa3f0bf29ec6bd5ba3 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Thu, 21 Jan 2021 11:54:10 -0600 Subject: [PATCH 0592/2777] vulkan-1: Prefer builtin Games that ship their own vulkan-1 will be broken with your VR wrappers. --- dlls/vulkan-1/Makefile.in | 2 -- 1 file changed, 2 deletions(-) diff --git a/dlls/vulkan-1/Makefile.in b/dlls/vulkan-1/Makefile.in index 9c4dca9a880..398e96b8385 100644 --- a/dlls/vulkan-1/Makefile.in +++ b/dlls/vulkan-1/Makefile.in @@ -2,8 +2,6 @@ MODULE = vulkan-1.dll IMPORTS = user32 IMPORTLIB = vulkan-1 -EXTRADLLFLAGS = -Wb,--prefer-native - RC_SRCS = version.rc C_SRCS = \ From ca1865bdfa82c6707f1e948dd840336d9c223e10 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Sun, 10 Oct 2021 21:52:26 +0200 Subject: [PATCH 0593/2777] winevulkan: Retrieve XR extensions from the environment --- dlls/winevulkan/vulkan.c | 100 +++++++++++++++++++++++++++++++++++---- 1 file changed, 91 insertions(+), 9 deletions(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 6f5b7c4a029..dcc609f1fb9 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -391,10 +391,68 @@ static void wine_vk_device_get_queues(struct wine_device *device, } } +static char **parse_xr_extensions(unsigned int *len) +{ + char *xr_str, *iter, *start, **list; + unsigned int extension_count = 0, o = 0; + + xr_str = getenv("__WINE_OPENXR_VK_DEVICE_EXTENSIONS"); + if (!xr_str) + { + *len = 0; + return NULL; + } + xr_str = strdup(xr_str); + + TRACE("got var: %s\n", xr_str); + + iter = xr_str; + while(*iter){ + if(*iter++ == ' ') + extension_count++; + } + /* count the one ending in NUL */ + if(iter != xr_str) + extension_count++; + if(!extension_count){ + *len = 0; + return NULL; + } + + TRACE("counted %u extensions\n", extension_count); + + list = malloc(extension_count * sizeof(char *)); + + start = iter = xr_str; + do{ + if(*iter == ' '){ + *iter = 0; + list[o++] = strdup(start); + TRACE("added %s to list\n", list[o-1]); + iter++; + start = iter; + }else if(*iter == 0){ + list[o++] = strdup(start); + TRACE("added %s to list\n", list[o-1]); + break; + }else{ + iter++; + } + }while(1); + + free(xr_str); + + *len = extension_count; + + return list; +} + static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_dev, struct conversion_context *ctx, const VkDeviceCreateInfo *src, VkDeviceCreateInfo *dst) { - unsigned int i; + static const char *wine_xr_extension_name = "VK_WINE_openxr_device_extensions"; + unsigned int i, append_xr = 0; + char **xr_extensions_list; *dst = *src; @@ -407,18 +465,42 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de { const char *extension_name = dst->ppEnabledExtensionNames[i]; TRACE("Extension %u: %s.\n", i, debugstr_a(extension_name)); + + if (!strcmp(extension_name, wine_xr_extension_name)) + append_xr = 1; } - if (phys_dev->external_memory_align) + if (append_xr) + xr_extensions_list = parse_xr_extensions(&append_xr); + + if (phys_dev->external_memory_align || append_xr) { const char **new_extensions; - - new_extensions = conversion_context_alloc(ctx, (dst->enabledExtensionCount + 2) * - sizeof(*dst->ppEnabledExtensionNames)); - memcpy(new_extensions, src->ppEnabledExtensionNames, - dst->enabledExtensionCount * sizeof(*dst->ppEnabledExtensionNames)); - new_extensions[dst->enabledExtensionCount++] = "VK_KHR_external_memory"; - new_extensions[dst->enabledExtensionCount++] = "VK_EXT_external_memory_host"; + unsigned int o = 0, count; + + count = dst->enabledExtensionCount; + if (phys_dev->external_memory_align) + count += 2; + if (append_xr) + count += append_xr - 1; + new_extensions = conversion_context_alloc(ctx, count * sizeof(*dst->ppEnabledExtensionNames)); + for (i = 0; i < dst->enabledExtensionCount; ++i) + { + if (append_xr && !strcmp(src->ppEnabledExtensionNames[i], wine_xr_extension_name)) + continue; + new_extensions[o++] = src->ppEnabledExtensionNames[i]; + } + if (phys_dev->external_memory_align) + { + new_extensions[o++] = "VK_KHR_external_memory"; + new_extensions[o++] = "VK_EXT_external_memory_host"; + } + for (i = 0; i < append_xr; ++i) + { + TRACE("\t%s\n", xr_extensions_list[i]); + new_extensions[o++] = xr_extensions_list[i]; + } + dst->enabledExtensionCount = count; dst->ppEnabledExtensionNames = new_extensions; } From 03887568a766b06d95a3b5da66e78a09bcb2e608 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 13 Dec 2022 19:23:48 -0600 Subject: [PATCH 0594/2777] winevulkan, winex11.drv: Add custom Vk structures for creating instance and device through OpenXR. --- dlls/winevulkan/make_vulkan | 35 ++++++++++++++++++++++++++++++++++- dlls/winevulkan/vulkan.c | 24 ++++++++++++++++++++++-- dlls/winex11.drv/vulkan.c | 20 +++++++++++++++++++- 3 files changed, 75 insertions(+), 4 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 801b804745f..8850ab11c64 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -2392,7 +2392,18 @@ class StructConversionFunction(object): body += " default:\n" if self.direction == Direction.INPUT: - body += ident + "FIXME(\"Unhandled sType %u.\", in_header->sType);\n" + body += ident + "if ((in_header->sType >> 16) == 0x7ead)\n" + body += ident + "{\n" + body += ident + " VkBaseOutStructure *out_ext = conversion_context_alloc(ctx, 32);\n"; + body += ident + " memcpy(out_ext, in_header, 32);\n"; + body += ident + " out_ext->pNext = NULL;\n"; + body += ident + " out_header->pNext = (void *)out_ext;\n"; + body += ident + " out_header = (void *)out_ext;\n"; + body += ident + "}\n" + body += ident + "else\n" + body += ident + "{\n" + body += ident + " FIXME(\"Unhandled sType %u.\\n\", in_header->sType);\n" + body += ident + "}\n" body += " break;\n" body += " }\n" body += " }\n" @@ -3115,6 +3126,28 @@ class VkGenerator(object): f.write(" name -= 2;\n\n") f.write(" return get_vulkan_driver_device_proc_addr(vulkan_funcs, name);\n}\n\n") + f.write("typedef VkResult (WINAPI *PFN_native_vkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *,\n") + f.write(" void * (*)(VkInstance, const char *), void *);\n"); + f.write("typedef VkResult (WINAPI *PFN_native_vkCreateDevice)(VkPhysicalDevice, const VkDeviceCreateInfo *, const VkAllocationCallbacks *, VkDevice *,\n"); + f.write(" void * (*)(VkInstance, const char *), void *);\n\n"); + f.write("typedef struct VkCreateInfoWineDeviceCallback {\n"); + f.write(" VkStructureType sType;\n"); + f.write(" const void* pNext;\n"); + f.write(" PFN_native_vkCreateDevice native_create_callback;\n"); + f.write(" void* context;\n"); + f.write("} VkCreateInfoWineDeviceCallback;\n"); + + f.write("#define VK_STRUCTURE_TYPE_CREATE_INFO_WINE_DEVICE_CALLBACK 2125312001\n"); + + f.write("typedef struct VkCreateInfoWineInstanceCallback {\n"); + f.write(" VkStructureType sType;\n"); + f.write(" const void* pNext;\n"); + f.write(" PFN_native_vkCreateInstance native_create_callback;\n"); + f.write(" void* context;\n"); + f.write("} VkCreateInfoWineInstanceCallback;\n"); + + f.write("#define VK_STRUCTURE_TYPE_CREATE_INFO_WINE_INSTANCE_CALLBACK 2125312002\n"); + f.write("#endif /* __WINE_VULKAN_DRIVER_H */\n") def generate_vulkan_spec(self, f): diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index dcc609f1fb9..2a3fdc6cfcd 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -452,9 +452,12 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de { static const char *wine_xr_extension_name = "VK_WINE_openxr_device_extensions"; unsigned int i, append_xr = 0; + VkBaseOutStructure *header; char **xr_extensions_list; *dst = *src; + if ((header = (VkBaseOutStructure *)dst->pNext) && header->sType == VK_STRUCTURE_TYPE_CREATE_INFO_WINE_DEVICE_CALLBACK) + dst->pNext = header->pNext; /* Should be filtered out by loader as ICDs don't support layers. */ dst->enabledLayerCount = 0; @@ -801,6 +804,9 @@ VkResult wine_vkCreateDevice(VkPhysicalDevice phys_dev_handle, const VkDeviceCre void *client_ptr) { struct wine_phys_dev *phys_dev = wine_phys_dev_from_handle(phys_dev_handle); + PFN_native_vkCreateDevice native_create_device = NULL; + void *native_create_device_context = NULL; + VkCreateInfoWineDeviceCallback *callback; VkDevice device_handle = client_ptr; VkDeviceCreateInfo create_info_host; struct VkQueue_T *queue_handles; @@ -829,11 +835,25 @@ VkResult wine_vkCreateDevice(VkPhysicalDevice phys_dev_handle, const VkDeviceCre object->phys_dev = phys_dev; + if ((callback = (VkCreateInfoWineDeviceCallback *)create_info->pNext) + && callback->sType == VK_STRUCTURE_TYPE_CREATE_INFO_WINE_DEVICE_CALLBACK) + { + native_create_device = callback->native_create_callback; + native_create_device_context = callback->context; + } + init_conversion_context(&ctx); res = wine_vk_device_convert_create_info(phys_dev, &ctx, create_info, &create_info_host); if (res == VK_SUCCESS) - res = phys_dev->instance->funcs.p_vkCreateDevice(phys_dev->phys_dev, - &create_info_host, NULL /* allocator */, &object->device); + { + if (native_create_device) + res = native_create_device(phys_dev->phys_dev, + &create_info_host, NULL /* allocator */, &object->device, + vk_funcs->p_vkGetInstanceProcAddr, native_create_device_context); + else + res = phys_dev->instance->funcs.p_vkCreateDevice(phys_dev->phys_dev, + &create_info_host, NULL /* allocator */, &object->device); + } free_conversion_context(&ctx); WINE_VK_ADD_DISPATCHABLE_MAPPING(phys_dev->instance, device_handle, object->device, object); if (res != VK_SUCCESS) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 101504a7887..14fe8654f46 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -156,6 +156,7 @@ static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo { unsigned int i; const char **enabled_extensions = NULL; + VkBaseOutStructure *header; dst->sType = src->sType; dst->flags = src->flags; @@ -166,6 +167,9 @@ static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo dst->enabledExtensionCount = 0; dst->ppEnabledExtensionNames = NULL; + if ((header = (VkBaseOutStructure *)dst->pNext) && header->sType == VK_STRUCTURE_TYPE_CREATE_INFO_WINE_INSTANCE_CALLBACK) + dst->pNext = header->pNext; + if (src->enabledExtensionCount > 0) { enabled_extensions = calloc(src->enabledExtensionCount, sizeof(*src->ppEnabledExtensionNames)); @@ -256,6 +260,9 @@ void vulkan_thread_detach(void) static VkResult X11DRV_vkCreateInstance(const VkInstanceCreateInfo *create_info, const VkAllocationCallbacks *allocator, VkInstance *instance) { + PFN_native_vkCreateInstance native_create_instance = NULL; + void *native_create_instance_context = NULL; + VkCreateInfoWineInstanceCallback *callback; VkInstanceCreateInfo create_info_host; VkResult res; TRACE("create_info %p, allocator %p, instance %p\n", create_info, allocator, instance); @@ -263,6 +270,13 @@ static VkResult X11DRV_vkCreateInstance(const VkInstanceCreateInfo *create_info, if (allocator) FIXME("Support for allocation callbacks not implemented yet\n"); + if ((callback = (VkCreateInfoWineInstanceCallback *)create_info->pNext) + && callback->sType == VK_STRUCTURE_TYPE_CREATE_INFO_WINE_INSTANCE_CALLBACK) + { + native_create_instance = callback->native_create_callback; + native_create_instance_context = callback->context; + } + /* Perform a second pass on converting VkInstanceCreateInfo. Winevulkan * performed a first pass in which it handles everything except for WSI * functionality such as VK_KHR_win32_surface. Handle this now. @@ -274,7 +288,11 @@ static VkResult X11DRV_vkCreateInstance(const VkInstanceCreateInfo *create_info, return res; } - res = pvkCreateInstance(&create_info_host, NULL /* allocator */, instance); + if (native_create_instance) + res = native_create_instance(&create_info_host, NULL /* allocator */, instance, + pvkGetInstanceProcAddr, native_create_instance_context); + else + res = pvkCreateInstance(&create_info_host, NULL /* allocator */, instance); free((void *)create_info_host.ppEnabledExtensionNames); return res; From 6c4870857328cfb9383186f0d128ad9d9a265f02 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Tue, 27 Apr 2021 10:51:12 +0200 Subject: [PATCH 0595/2777] HACK: winex11.drv: Fix drawing of layered windows with a client window. CW-Bug-Id: #18807 --- dlls/winex11.drv/event.c | 5 ++++- dlls/winex11.drv/x11drv.h | 2 ++ dlls/winex11.drv/x11drv_main.c | 12 ++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index ef1d6aa534f..48c62f64ee6 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1021,7 +1021,10 @@ static BOOL X11DRV_Expose( HWND hwnd, XEvent *xev ) rect.right = pos.x + event->width; rect.bottom = pos.y + event->height; - if (event->window != data->client_window) + if (layered_window_client_hack && event->window == data->client_window) + OffsetRect( &rect, data->client_rect.left - data->whole_rect.left, + data->client_rect.top - data->whole_rect.top ); + if (layered_window_client_hack || event->window != data->client_window) { if (data->surface) { diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 0435339a9a0..998cd411d0d 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -955,4 +955,6 @@ static inline UINT asciiz_to_unicode( WCHAR *dst, const char *src ) return (p - dst) * sizeof(WCHAR); } +extern BOOL layered_window_client_hack; + #endif /* __WINE_X11DRV_H */ diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index b19027e5b26..d115fdf8dc9 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -93,6 +93,7 @@ char *process_name = NULL; WNDPROC client_foreign_window_proc = NULL; HANDLE steam_overlay_event; HANDLE steam_keyboard_event; +BOOL layered_window_client_hack = FALSE; static x11drv_error_callback err_callback; /* current callback for error */ static Display *err_callback_display; /* display callback is set for */ @@ -753,6 +754,17 @@ static NTSTATUS x11drv_init( void *arg ) X11DRV_InitMouse( gdi_display ); if (use_xim) use_xim = X11DRV_InitXIM( input_style ); + { + const char *sgi = getenv("SteamGameId"); + const char *e = getenv("WINE_LAYERED_WINDOW_CLIENT_HACK"); + layered_window_client_hack = + (sgi && ( + strcmp(sgi, "435150") == 0 || /* Divinity: Original Sin 2 launcher */ + strcmp(sgi, "227020") == 0 /* Rise of Venice launcher */ + )) || + (e && *e != '\0' && *e != '0'); + } + init_user_driver(); X11DRV_DisplayDevices_Init(FALSE); *params->show_systray = show_systray; From bffb8cb2d33718af4babefc7e5832ae308d67e6e Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Thu, 3 Feb 2022 09:51:28 +0100 Subject: [PATCH 0596/2777] 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 (which happened in libx11 1.7.4). 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 6b789680335..0f3d0760aa3 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2110,6 +2110,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"); + free(ret); + release_gl_drawable(gl); + return NULL; + } pContextAttribList[0] = GLX_CONTEXT_FLAGS_ARB; pContextAttribList[1] = attribList[1]; pContextAttribList += 2; From c2a5c514b1c80e24fb0a44cca42722bdb7e7f0c9 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Fri, 14 Jan 2022 09:46:20 +0100 Subject: [PATCH 0597/2777] HACK: riched20: Ignore WM_SETFONT for Grand Theft Auto V. CW-Bug-Id: #19917 --- dlls/riched20/editor.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c index 57601745ab2..c4b4d7e72be 100644 --- a/dlls/riched20/editor.c +++ b/dlls/riched20/editor.c @@ -3576,6 +3576,20 @@ LRESULT editor_handle_message( ME_TextEditor *editor, UINT msg, WPARAM wParam, CHARFORMAT2W fmt; HDC hDC; BOOL bRepaint = LOWORD(lParam); + const char *sgi = getenv("STEAM_COMPAT_APP_ID"); + + /* Grand Theft Auto V installer tries to set font for license + * richedit to Arial, which breaks CJK languages. Given that the + * RTF already has reasonable fonts set, we can just ignore the + * message. This can be removed once our richedit is able to do + * font substitution properly. CW bug #19917. + * + * It's important that STEAM_COMPAT_APP_ID environment variable is + * used instead of the usual SteamGameId, because the latter is + * not available during the configuration stage, when the + * installer is run. */ + if (sgi && strcmp(sgi, "271590") == 0) + return 0; if (!wParam) wParam = (WPARAM)GetStockObject(SYSTEM_FONT); From b4829fcece4f6c30319051d17d5fb3353ec3467d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 22 Mar 2022 21:44:24 +0300 Subject: [PATCH 0598/2777] ntdll: HACK: Also use Windows syscall numbers for Swords of Legends Online. CW-Bug-Id: #20330 --- dlls/ntdll/unix/signal_x86_64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 883f1c10327..3eb24aeaefe 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2001,7 +2001,7 @@ static void install_bpf(struct sigaction *sig_act) { const char *sgi = getenv("SteamGameId"); - if (sgi && (!strcmp(sgi, "1174180") || !strcmp(sgi, "1404210"))) + if (sgi && (!strcmp(sgi, "1174180") || !strcmp(sgi, "1404210") || !strcmp(sgi, "1418100"))) { /* Use specific signal handler. */ sig_act->sa_sigaction = sigsys_handler_rdr2; From 696e45a9c8a92634d6fdcf03974f72ca969e3808 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 20 May 2022 18:47:05 -0500 Subject: [PATCH 0599/2777] winex11.drv: Sync calls to vkQueuePresentKHR(). CW-Bug-Id: #18863 --- dlls/winex11.drv/vulkan.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 14fe8654f46..92157d005b7 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -660,11 +660,14 @@ static VkResult X11DRV_vkGetSwapchainImagesKHR(VkDevice device, static VkResult X11DRV_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *present_info) { + static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; VkResult res; TRACE("%p, %p\n", queue, present_info); + pthread_mutex_lock( &lock ); res = pvkQueuePresentKHR(queue, present_info); + pthread_mutex_unlock( &lock ); if (TRACE_ON(fps)) { From e023129a383e7555e3ed169c6903f95b677d8098 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 31 Aug 2021 00:41:15 +0300 Subject: [PATCH 0600/2777] winex11.drv: HACK: Mind insert_after X11DRV_WindowPosChanged in some cases. Fixes FH4 rendering black window until focus is lost. CW-Bug-Id: #19335 --- dlls/winex11.drv/window.c | 50 +++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 79918dc6b9e..dfb8b9a4348 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1486,16 +1486,18 @@ void X11DRV_X_to_window_rect( struct x11drv_win_data *data, RECT *rect, int x, i * * Synchronize the X window position with the Windows one */ -static void sync_window_position( struct x11drv_win_data *data, +static HWND sync_window_position( struct x11drv_win_data *data, UINT swp_flags, const RECT *old_window_rect, const RECT *old_whole_rect, const RECT *old_client_rect ) { DWORD style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); DWORD ex_style = NtUserGetWindowLongW( data->hwnd, GWL_EXSTYLE ); + HWND prev_window = NULL; + RECT original_rect = {0}; XWindowChanges changes; unsigned int mask = 0; - if (data->managed && data->iconic) return; + if (data->managed && data->iconic) return NULL; /* resizing a managed maximized window is not allowed */ if (!(style & WS_MAXIMIZE) || !data->managed) @@ -1522,9 +1524,10 @@ static void sync_window_position( struct x11drv_win_data *data, { /* find window that this one must be after */ HWND prev = NtUserGetWindowRelative( data->hwnd, GW_HWNDPREV ); + while (prev && !(NtUserGetWindowLongW( prev, GWL_STYLE ) & WS_VISIBLE)) prev = NtUserGetWindowRelative( prev, GW_HWNDPREV ); - if (!prev) /* top child */ + if (!(prev_window = prev)) /* top child */ { changes.stack_mode = Above; mask |= CWStackMode; @@ -1538,6 +1541,7 @@ static void sync_window_position( struct x11drv_win_data *data, update_net_wm_states( data ); data->configure_serial = NextRequest( data->display ); XReconfigureWMWindow( data->display, data->whole_window, data->vis.screen, mask, &changes ); + #ifdef HAVE_LIBXSHAPE if (IsRectEmpty( old_window_rect ) != IsRectEmpty( &data->window_rect )) sync_window_region( data, (HRGN)1 ); @@ -1558,6 +1562,8 @@ static void sync_window_position( struct x11drv_win_data *data, (int)(data->whole_rect.right - data->whole_rect.left), (int)(data->whole_rect.bottom - data->whole_rect.top), changes.sibling, mask, data->configure_serial ); + + return prev_window; } @@ -2779,6 +2785,25 @@ BOOL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags, } +static void restack_windows( struct x11drv_win_data *data, HWND prev ) +{ + struct x11drv_win_data *prev_data; + + TRACE("data->hwnd %p, prev %p.\n", data->hwnd, prev); + + while (prev) + { + if (!(prev_data = get_win_data( prev ))) break; + + TRACE( "Raising window %p.\n", prev ); + + if (prev_data->whole_window && data->display == prev_data->display) + XRaiseWindow( prev_data->display, prev_data->whole_window ); + release_win_data( prev_data ); + prev = NtUserGetWindowRelative( prev, GW_HWNDPREV ); + } +} + /*********************************************************************** * WindowPosChanged (X11DRV.@) */ @@ -2791,6 +2816,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, struct x11drv_win_data *data; UINT new_style = NtUserGetWindowLongW( hwnd, GWL_STYLE ); RECT old_window_rect, old_whole_rect, old_client_rect; + HWND prev_window = NULL; int event_type; if (!(data = get_win_data( hwnd ))) return; @@ -2893,7 +2919,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, /* don't change position if we are about to minimize or maximize a managed window */ if ((!event_type || event_type == PropertyNotify) && !(data->managed && (swp_flags & SWP_STATECHANGED) && (new_style & (WS_MINIMIZE|WS_MAXIMIZE)))) - sync_window_position( data, swp_flags, &old_window_rect, &old_whole_rect, &old_client_rect ); + prev_window = sync_window_position( data, swp_flags, &old_window_rect, &old_whole_rect, &old_client_rect ); if ((new_style & WS_VISIBLE) && ((new_style & WS_MINIMIZE) || is_window_rect_mapped( rectWindow ))) @@ -2909,6 +2935,10 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, release_win_data( data ); if (needs_icon) fetch_icon_data( hwnd, 0, 0 ); if (needs_map) map_window( hwnd, new_style ); + + if (!(data = get_win_data( hwnd ))) return; + restack_windows( data, prev_window ); + release_win_data( data ); return; } else if ((swp_flags & SWP_STATECHANGED) && (!data->iconic != !(new_style & WS_MINIMIZE))) @@ -2925,10 +2955,20 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, else { if (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)) set_wm_hints( data ); - if (!event_type || event_type == PropertyNotify) update_net_wm_states( data ); + if (!event_type || event_type == PropertyNotify) + { + update_net_wm_states( data ); + if (!prev_window && insert_after && data->net_wm_state & (1 << NET_WM_STATE_FULLSCREEN)) + { + prev_window = NtUserGetWindowRelative( hwnd, GW_HWNDPREV ); + if (prev_window != insert_after) prev_window = NULL; + } + } } } + restack_windows( data, prev_window ); + XFlush( data->display ); /* make sure changes are done before we start painting again */ if (data->surface && data->vis.visualid != default_visual.visualid) data->surface->funcs->flush( data->surface ); From 1f67e221c607ef5d499b153e275eded0bfe1594e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 24 Jun 2022 18:53:58 -0500 Subject: [PATCH 0601/2777] winex11.drv: Add an option to always Increment configure_serial in X11DRV_WindowPosChanged(). And enable it for Dokyusei Bangin' Summer. CW-Bug-Id: #20665 --- dlls/winex11.drv/window.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index dfb8b9a4348..755e725fbdb 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2784,6 +2784,20 @@ BOOL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags, return TRUE; } +static BOOL option_increament_configure_serial(void) +{ + static int increment = -1; + if (increment == -1) + { + const char *e = getenv( "WINE_INCREMENT_CONFIGURE_SERIAL" ); + + if (e) + increment = atoi( e ); + else + increment = (e = getenv( "SteamGameId" )) && !strcmp( e, "1689910" ); + } + return increment; +} static void restack_windows( struct x11drv_win_data *data, HWND prev ) { @@ -2917,9 +2931,13 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, } /* don't change position if we are about to minimize or maximize a managed window */ - if ((!event_type || event_type == PropertyNotify) && - !(data->managed && (swp_flags & SWP_STATECHANGED) && (new_style & (WS_MINIMIZE|WS_MAXIMIZE)))) - prev_window = sync_window_position( data, swp_flags, &old_window_rect, &old_whole_rect, &old_client_rect ); + if (!event_type || event_type == PropertyNotify) + { + if (!(data->managed && (swp_flags & SWP_STATECHANGED) && (new_style & (WS_MINIMIZE|WS_MAXIMIZE)))) + prev_window = sync_window_position( data, swp_flags, &old_window_rect, &old_whole_rect, &old_client_rect ); + else if (option_increament_configure_serial()) + data->configure_serial = NextRequest( data->display ); + } if ((new_style & WS_VISIBLE) && ((new_style & WS_MINIMIZE) || is_window_rect_mapped( rectWindow ))) From 29fb0539c5c1fb065311a73a12fe5500c84c3bc4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 7 Dec 2020 12:59:55 +0300 Subject: [PATCH 0602/2777] bcrypt: Implement DH. --- dlls/bcrypt/bcrypt_internal.h | 18 ++ dlls/bcrypt/bcrypt_main.c | 126 +++++++++++- dlls/bcrypt/gnutls.c | 359 +++++++++++++++++++++++++++++++++- include/bcrypt.h | 29 +++ 4 files changed, 522 insertions(+), 10 deletions(-) diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h index 98223e90ac6..f0eaa6ad4fb 100644 --- a/dlls/bcrypt/bcrypt_internal.h +++ b/dlls/bcrypt/bcrypt_internal.h @@ -131,6 +131,7 @@ enum alg_id ALG_ID_RSA, /* secret agreement */ + ALG_ID_DH, ALG_ID_ECDH_P256, ALG_ID_ECDH_P384, @@ -173,6 +174,8 @@ struct key_symmetric }; #define KEY_FLAG_LEGACY_DSA_V2 0x00000001 +#define KEY_FLAG_DH_PARAMS_SET 0x00000002 +#define KEY_FLAG_FINALIZED 0x00000004 struct key_asymmetric { @@ -196,6 +199,8 @@ struct key struct secret { struct object hdr; + UCHAR *data; + ULONG data_len; }; struct key_symmetric_set_auth_data_params @@ -281,6 +286,9 @@ struct key_asymmetric_verify_params #define KEY_EXPORT_FLAG_PUBLIC 0x00000001 #define KEY_EXPORT_FLAG_RSA_FULL 0x00000002 +#define KEY_EXPORT_FLAG_DH_FULL 0x00000004 +#define KEY_EXPORT_FLAG_DH_PARAMETERS 0x00000008 + struct key_asymmetric_export_params { struct key *key; @@ -291,6 +299,8 @@ struct key_asymmetric_export_params }; #define KEY_IMPORT_FLAG_PUBLIC 0x00000001 +#define KEY_IMPORT_FLAG_DH_FULL 0x00000004 +#define KEY_IMPORT_FLAG_DH_PARAMETERS 0x00000008 struct key_asymmetric_import_params { struct key *key; @@ -299,6 +309,13 @@ struct key_asymmetric_import_params ULONG len; }; +struct key_secret_agreement_params +{ + struct key *privkey; + struct key *pubkey; + struct secret *secret; +}; + enum key_funcs { unix_process_attach, @@ -318,6 +335,7 @@ enum key_funcs unix_key_asymmetric_destroy, unix_key_asymmetric_export, unix_key_asymmetric_import, + unix_key_secret_agreement, }; #endif /* __BCRYPT_INTERNAL_H */ diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index cf05e8b4d44..72a7b1915f2 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -112,6 +112,7 @@ builtin_algorithms[] = { BCRYPT_MD4_ALGORITHM, BCRYPT_HASH_INTERFACE, 270, 16, 512 }, { BCRYPT_MD2_ALGORITHM, BCRYPT_HASH_INTERFACE, 270, 16, 128 }, { BCRYPT_RSA_ALGORITHM, BCRYPT_ASYMMETRIC_ENCRYPTION_INTERFACE, 0, 0, 0 }, + { BCRYPT_DH_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, { BCRYPT_ECDH_P256_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, { BCRYPT_ECDH_P384_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, { BCRYPT_RSA_SIGN_ALGORITHM, BCRYPT_SIGNATURE_INTERFACE, 0, 0, 0 }, @@ -870,6 +871,20 @@ static NTSTATUS get_hash_property( const struct hash *hash, const WCHAR *prop, U return status; } +static NTSTATUS get_dh_property( const struct key *key, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size ) +{ + struct key_asymmetric_export_params params; + + if (wcscmp( prop, BCRYPT_DH_PARAMETERS )) return STATUS_NOT_SUPPORTED; + + params.key = (struct key *)key; + params.flags = KEY_EXPORT_FLAG_DH_PARAMETERS; + params.buf = buf; + params.len = size; + params.ret_len = ret_size; + return UNIX_CALL( key_asymmetric_export, ¶ms ); +} + static NTSTATUS get_key_property( const struct key *key, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size ) { switch (key->alg_id) @@ -881,6 +896,9 @@ static NTSTATUS get_key_property( const struct key *key, const WCHAR *prop, UCHA if (!wcscmp( prop, BCRYPT_AUTH_TAG_LENGTH )) return STATUS_NOT_SUPPORTED; return get_aes_property( key->u.s.mode, prop, buf, size, ret_size ); + case ALG_ID_DH: + return get_dh_property( key, prop, buf, size, ret_size ); + default: FIXME( "unsupported algorithm %u\n", key->alg_id ); return STATUS_NOT_IMPLEMENTED; @@ -1130,6 +1148,8 @@ static NTSTATUS key_asymmetric_create( enum alg_id alg_id, ULONG bitlen, struct return STATUS_NOT_IMPLEMENTED; } + if (alg_id == ALG_ID_DH && bitlen < 512) return STATUS_INVALID_PARAMETER; + if (!(key = calloc( 1, sizeof(*key) ))) return STATUS_NO_MEMORY; key->hdr.magic = MAGIC_KEY; key->alg_id = alg_id; @@ -1269,6 +1289,7 @@ static NTSTATUS key_import( struct algorithm *alg, const WCHAR *type, BCRYPT_KEY static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size ) { struct key_asymmetric_export_params params; + BOOL dh_private = FALSE; if (!wcscmp( type, BCRYPT_KEY_DATA_BLOB )) { @@ -1328,6 +1349,15 @@ static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, U params.ret_len = size; return UNIX_CALL( key_asymmetric_export, ¶ms ); } + else if (!wcscmp( type, BCRYPT_DH_PUBLIC_BLOB ) || (dh_private = !wcscmp( type, BCRYPT_DH_PRIVATE_BLOB ))) + { + params.key = key; + params.flags = dh_private ? KEY_EXPORT_FLAG_DH_FULL : 0; + params.buf = output; + params.len = output_len; + params.ret_len = size; + return UNIX_CALL( key_asymmetric_export, ¶ms ); + } FIXME( "unsupported key type %s\n", debugstr_w(type) ); return STATUS_NOT_IMPLEMENTED; @@ -1529,7 +1559,6 @@ static void key_destroy( struct key *key ) } else UNIX_CALL( key_asymmetric_destroy, key ); - destroy_object( &key->hdr ); } @@ -1537,6 +1566,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP ULONG input_len ) { struct key_asymmetric_import_params params; + BOOL dh_private = FALSE; struct key *key; NTSTATUS status; ULONG size; @@ -1591,6 +1621,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP } *ret_key = key; + key->u.a.flags |= KEY_FLAG_FINALIZED; return STATUS_SUCCESS; } else if (!wcscmp( type, BCRYPT_ECCPRIVATE_BLOB )) @@ -1638,6 +1669,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP } *ret_key = key; + key->u.a.flags |= KEY_FLAG_FINALIZED; return STATUS_SUCCESS; } else if (!wcscmp( type, BCRYPT_RSAPUBLIC_BLOB )) @@ -1663,6 +1695,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP } *ret_key = key; + key->u.a.flags |= KEY_FLAG_FINALIZED; return STATUS_SUCCESS; } else if (!wcscmp( type, BCRYPT_RSAPRIVATE_BLOB ) || !wcscmp( type, BCRYPT_RSAFULLPRIVATE_BLOB )) @@ -1685,6 +1718,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP } *ret_key = key; + key->u.a.flags |= KEY_FLAG_FINALIZED; return STATUS_SUCCESS; } else if (!wcscmp( type, BCRYPT_DSA_PUBLIC_BLOB )) @@ -1707,6 +1741,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP } *ret_key = key; + key->u.a.flags |= KEY_FLAG_FINALIZED; return STATUS_SUCCESS; } else if (!wcscmp( type, LEGACY_DSA_V2_PRIVATE_BLOB )) @@ -1747,6 +1782,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP } *ret_key = key; + key->u.a.flags |= KEY_FLAG_FINALIZED; return STATUS_SUCCESS; } else if (!wcscmp( type, LEGACY_DSA_V2_PUBLIC_BLOB )) /* not supported on native */ @@ -1783,6 +1819,41 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP } *ret_key = key; + key->u.a.flags |= KEY_FLAG_FINALIZED; + return STATUS_SUCCESS; + } + else if (!wcscmp( type, BCRYPT_DH_PUBLIC_BLOB ) || (dh_private = !wcscmp( type, BCRYPT_DH_PRIVATE_BLOB ))) + { + BCRYPT_DH_KEY_BLOB *h = (BCRYPT_DH_KEY_BLOB *)input; + ULONG size; + + if (alg->id != ALG_ID_DH) return STATUS_NOT_SUPPORTED; + if (h->dwMagic != (dh_private ? BCRYPT_DH_PRIVATE_MAGIC : BCRYPT_DH_PUBLIC_MAGIC)) + { + WARN("unexpected dwMagic %#lx.\n", h->dwMagic); + return STATUS_INVALID_PARAMETER; + } + + size = sizeof(*h) + h->cbKey * 3; + if (dh_private) + size += h->cbKey; + if (input_len != size) return STATUS_INVALID_PARAMETER; + if (h->cbKey * 8 < 512) return STATUS_INVALID_PARAMETER; + + if ((status = key_asymmetric_create( alg->id, h->cbKey * 8, &key ))) return status; + + params.key = key; + params.flags = dh_private ? KEY_IMPORT_FLAG_DH_FULL : 0; + params.buf = input; + params.len = input_len; + if ((status = UNIX_CALL( key_asymmetric_import, ¶ms ))) + { + key_destroy( key ); + return status; + } + + *ret_key = key; + key->u.a.flags |= KEY_FLAG_FINALIZED; return STATUS_SUCCESS; } @@ -1828,11 +1899,15 @@ NTSTATUS WINAPI BCryptGenerateKeyPair( BCRYPT_ALG_HANDLE handle, BCRYPT_KEY_HAND NTSTATUS WINAPI BCryptFinalizeKeyPair( BCRYPT_KEY_HANDLE handle, ULONG flags ) { struct key *key = get_key_object( handle ); + NTSTATUS ret; TRACE( "%p, %#lx\n", key, flags ); if (!key) return STATUS_INVALID_HANDLE; - return UNIX_CALL( key_asymmetric_generate, key ); + if (!(ret = UNIX_CALL( key_asymmetric_generate, key ))) + key->u.a.flags |= KEY_FLAG_FINALIZED; + + return ret; } NTSTATUS WINAPI BCryptImportKey( BCRYPT_ALG_HANDLE handle, BCRYPT_KEY_HANDLE decrypt_key, const WCHAR *type, @@ -2146,6 +2221,21 @@ NTSTATUS WINAPI BCryptSetProperty( BCRYPT_HANDLE handle, const WCHAR *prop, UCHA case MAGIC_KEY: { struct key *key = (struct key *)object; + + if (key->alg_id == ALG_ID_DH) + { + if (!lstrcmpW( prop, BCRYPT_DH_PARAMETERS )) + { + struct key_asymmetric_import_params params; + + params.key = key; + params.flags = KEY_IMPORT_FLAG_DH_PARAMETERS; + params.buf = value; + params.len = size; + return UNIX_CALL( key_asymmetric_import, ¶ms ); + } + return STATUS_NOT_IMPLEMENTED; + } return set_key_property( key, prop, value, size, flags ); } default: @@ -2308,30 +2398,54 @@ NTSTATUS WINAPI BCryptDeriveKeyPBKDF2( BCRYPT_ALG_HANDLE handle, UCHAR *pwd, ULO NTSTATUS WINAPI BCryptSecretAgreement( BCRYPT_KEY_HANDLE privkey_handle, BCRYPT_KEY_HANDLE pubkey_handle, BCRYPT_SECRET_HANDLE *ret_handle, ULONG flags ) { + struct key_secret_agreement_params params; struct key *privkey = get_key_object( privkey_handle ); struct key *pubkey = get_key_object( pubkey_handle ); struct secret *secret; + NTSTATUS status; FIXME( "%p, %p, %p, %#lx\n", privkey_handle, pubkey_handle, ret_handle, flags ); if (!privkey || !pubkey) return STATUS_INVALID_HANDLE; if (!is_agreement_key( privkey ) || !is_agreement_key( pubkey )) return STATUS_NOT_SUPPORTED; if (!ret_handle) return STATUS_INVALID_PARAMETER; + if (is_symmetric_key( privkey ) || privkey->alg_id != pubkey->alg_id) return STATUS_INVALID_PARAMETER; + if (!(privkey->u.a.flags & pubkey->u.a.flags & KEY_FLAG_FINALIZED)) return STATUS_INVALID_PARAMETER; + if (privkey->u.a.bitlen != pubkey->u.a.bitlen) return STATUS_INVALID_PARAMETER; if (!(secret = calloc( 1, sizeof(*secret) ))) return STATUS_NO_MEMORY; - secret->hdr.magic = MAGIC_SECRET; + if (!(secret->data = malloc( privkey->u.a.bitlen / 8 ))) + { + free( secret ); + return STATUS_NO_MEMORY; + } - *ret_handle = secret; - return STATUS_SUCCESS; + params.privkey = privkey; + params.pubkey = pubkey; + params.secret = secret; + + if ((status = UNIX_CALL( key_secret_agreement, ¶ms ))) + { + free( secret->data ); + free( secret ); + } + else + { + secret->hdr.magic = MAGIC_SECRET; + *ret_handle = secret; + } + return status; } NTSTATUS WINAPI BCryptDestroySecret( BCRYPT_SECRET_HANDLE handle ) { struct secret *secret = get_secret_object( handle ); - FIXME( "%p\n", handle ); + TRACE( "%p\n", handle ); if (!secret) return STATUS_INVALID_HANDLE; + secret->hdr.magic = 0; + free( secret->data ); destroy_object( &secret->hdr ); return STATUS_SUCCESS; } diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index 89e5c91776d..4a9f223a838 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -79,6 +79,12 @@ typedef enum typedef struct gnutls_x509_spki_st *gnutls_x509_spki_t; #endif +struct dh_key_data +{ + UCHAR *pubkey; /* Used for DH private key only. */ + UCHAR *privkey; /* Used for DH private key only. */ +}; + union key_data { gnutls_cipher_hd_t cipher; @@ -87,6 +93,11 @@ union key_data gnutls_privkey_t privkey; gnutls_pubkey_t pubkey; } a; + struct /* DH */ + { + UCHAR *privkey; + UCHAR *pubkey; + } d; }; C_ASSERT( sizeof(union key_data) <= sizeof(((struct key *)0)->private) ); @@ -95,6 +106,29 @@ static union key_data *key_data( struct key *key ) return (union key_data *)key->private; } +static unsigned int dh_pubkey_len( struct key *key ) +{ + return sizeof(BCRYPT_DH_KEY_BLOB) + key->u.a.bitlen / 8 * 3; +} + +static void dh_key_free( struct key *key ) +{ + free( key_data(key)->d.privkey ); + free( key_data(key)->d.pubkey ); +} + +static void dh_key_alloc( struct key *key ) +{ + unsigned int bitlen = key->u.a.bitlen; + + if (key_data(key)->d.pubkey) return; + + key_data(key)->d.privkey = calloc( 1, bitlen / 8 ); + key_data(key)->d.pubkey = calloc( 1, dh_pubkey_len( key )); +} + +static BOOL dh_supported; + /* Not present in gnutls version < 3.0 */ static int (*pgnutls_cipher_tag)(gnutls_cipher_hd_t, void *, size_t); static int (*pgnutls_cipher_add_auth)(gnutls_cipher_hd_t, const void *, size_t); @@ -144,6 +178,17 @@ static void (*pgnutls_x509_spki_set_rsa_pss_params)(gnutls_x509_spki_t, gnutls_d static int (*pgnutls_pubkey_set_spki)(gnutls_pubkey_t, const gnutls_x509_spki_t, unsigned int); static int (*pgnutls_privkey_set_spki)(gnutls_privkey_t, const gnutls_x509_spki_t, unsigned int); +static int (*pgnutls_dh_params_init)(gnutls_dh_params_t * dh_params); +static void (*pgnutls_dh_params_deinit)(gnutls_dh_params_t dh_params); +static int (*pgnutls_dh_params_generate2)(gnutls_dh_params_t dparams, unsigned int bits); +static int (*pgnutls_dh_params_import_raw2)(gnutls_dh_params_t dh_params, const gnutls_datum_t * prime, + const gnutls_datum_t * generator, unsigned key_bits); +static int (*pgnutls_dh_params_export_raw)(gnutls_dh_params_t params, gnutls_datum_t * prime, + gnutls_datum_t * generator, unsigned int *bits); +static int (*pgnutls_dh_generate_key)(gnutls_dh_params_t dh_params, gnutls_datum_t *priv_key, gnutls_datum_t *pub_key); +static int (*pgnutls_dh_compute_key)(gnutls_dh_params_t dh_params, const gnutls_datum_t *priv_key, + const gnutls_datum_t *pub_key, const gnutls_datum_t *peer_key, gnutls_datum_t *Z); + static void *libgnutls_handle; #define MAKE_FUNCPTR(f) static typeof(f) * p##f MAKE_FUNCPTR(gnutls_cipher_decrypt2); @@ -392,6 +437,39 @@ static NTSTATUS gnutls_process_attach( void *args ) pgnutls_perror( ret ); goto fail; } + if (!(pgnutls_dh_params_init = dlsym( libgnutls_handle, "gnutls_dh_params_init" ))) + { + WARN("gnutls_dh_params_init not found\n"); + } + if (!(pgnutls_dh_params_deinit = dlsym( libgnutls_handle, "gnutls_dh_params_deinit" ))) + { + WARN("gnutls_dh_params_deinit not found\n"); + } + if (!(pgnutls_dh_params_generate2 = dlsym( libgnutls_handle, "gnutls_dh_params_generate2" ))) + { + WARN("gnutls_dh_params_generate2 not found\n"); + } + if (!(pgnutls_dh_params_import_raw2 = dlsym( libgnutls_handle, "gnutls_dh_params_import_raw2" ))) + { + WARN("gnutls_dh_params_import_raw2 not found\n"); + } + if (!(pgnutls_dh_params_export_raw = dlsym( libgnutls_handle, "gnutls_dh_params_export_raw" ))) + { + WARN("gnutls_dh_params_export_raw not found\n"); + } + if (!(pgnutls_dh_generate_key = dlsym( libgnutls_handle, "_gnutls_dh_generate_key" )) + && !(pgnutls_dh_generate_key = dlsym( libgnutls_handle, "gnutls_dh_generate_key" ))) + { + WARN("gnutls_dh_generate_key not found\n"); + } + if (!(pgnutls_dh_compute_key = dlsym( libgnutls_handle, "_gnutls_dh_compute_key" )) + && !(pgnutls_dh_compute_key = dlsym( libgnutls_handle, "gnutls_dh_compute_key" ))) + { + WARN("gnutls_dh_compute_key not found\n"); + } + + dh_supported = pgnutls_dh_params_init && pgnutls_dh_params_generate2 && pgnutls_dh_params_import_raw2 + && pgnutls_dh_generate_key && pgnutls_dh_compute_key; if (TRACE_ON( bcrypt )) { @@ -951,6 +1029,89 @@ static NTSTATUS key_export_dsa_capi_public( struct key *key, UCHAR *buf, ULONG l return status; } +static NTSTATUS CDECL key_dh_generate( struct key *key ) +{ + gnutls_datum_t prime, generator, privkey, pubkey; + NTSTATUS status = STATUS_SUCCESS; + gnutls_dh_params_t dh_params; + ULONG key_length; + int ret; + + if (!dh_supported) + { + ERR("DH is not available.\n"); + return STATUS_NOT_IMPLEMENTED; + } + + if ((ret = pgnutls_dh_params_init( &dh_params ))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + + key_length = key->u.a.bitlen / 8; + + if (!(key->u.a.flags & KEY_FLAG_DH_PARAMS_SET)) + { + /* Generate parameters, export and then import them back below. + * The bitlen in dh parameters (which is later used for keys generation) + * is not set to gnutls_dh_params_generate2 'bits' parameter as one + * could expect. gnutls_dh_params_generate2 generates 'q' (which is not + * actually needed for DH) with the estimated bit length and then + * sets the bit length to the 'q' bitlength. */ + dh_key_alloc( key ); + + if ((ret = pgnutls_dh_params_generate2( dh_params, key->u.a.bitlen ))) + { + pgnutls_perror( ret ); + pgnutls_dh_params_deinit( dh_params ); + return STATUS_INTERNAL_ERROR; + } + if ((ret = pgnutls_dh_params_export_raw( dh_params, &prime, &generator, NULL ))) + { + pgnutls_perror( ret ); + pgnutls_dh_params_deinit( dh_params ); + return STATUS_INTERNAL_ERROR; + } + + export_gnutls_datum( (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1), key_length, &prime, 1 ); + export_gnutls_datum( (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1) + key_length, + key_length, &generator, 1 ); + free( prime.data ); + free( generator.data ); + + key->u.a.flags |= KEY_FLAG_DH_PARAMS_SET; + } + + prime.size = generator.size = key_length; + prime.data = (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1); + generator.data = (BYTE *)((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1) + key_length; + + if ((ret = pgnutls_dh_params_import_raw2( dh_params, &prime, &generator, key->u.a.bitlen ))) + { + pgnutls_perror( ret ); + pgnutls_dh_params_deinit( dh_params ); + return STATUS_INTERNAL_ERROR; + } + + if ((ret = pgnutls_dh_generate_key( dh_params, &privkey, &pubkey ))) + { + pgnutls_perror( ret ); + pgnutls_dh_params_deinit( dh_params ); + return STATUS_INTERNAL_ERROR; + } + + export_gnutls_datum( (BYTE *)((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1) + 2 * key_length, + key_length, &pubkey, 1 ); + export_gnutls_datum( key_data(key)->d.privkey, key_length, &privkey, 1); + + free( privkey.data ); + free( pubkey.data ); + pgnutls_dh_params_deinit( dh_params ); + + return status; +} + static NTSTATUS key_asymmetric_generate( void *args ) { struct key *key = args; @@ -961,7 +1122,7 @@ static NTSTATUS key_asymmetric_generate( void *args ) int ret; if (!libgnutls_handle) return STATUS_INTERNAL_ERROR; - if (key_data(key)->a.privkey) return STATUS_INVALID_HANDLE; + if (key->alg_id != ALG_ID_DH && key_data(key)->a.privkey) return STATUS_INVALID_HANDLE; switch (key->alg_id) { @@ -988,6 +1149,9 @@ static NTSTATUS key_asymmetric_generate( void *args ) bitlen = GNUTLS_CURVE_TO_BITS( GNUTLS_ECC_CURVE_SECP384R1 ); break; + case ALG_ID_DH: + return key_dh_generate( key ); + default: FIXME( "algorithm %u not supported\n", key->alg_id ); return STATUS_NOT_SUPPORTED; @@ -1000,6 +1164,7 @@ static NTSTATUS key_asymmetric_generate( void *args ) } if ((ret = pgnutls_pubkey_init( &pubkey ))) { + ERR("gnutls error bitlen %u.\n", bitlen); pgnutls_perror( ret ); pgnutls_privkey_deinit( privkey ); return STATUS_INTERNAL_ERROR; @@ -1557,6 +1722,44 @@ static NTSTATUS key_asymmetric_export( void *args ) return key_export_dsa_capi( key, params->buf, params->len, params->ret_len ); return STATUS_NOT_IMPLEMENTED; + case ALG_ID_DH: + if (!(key->u.a.flags & KEY_FLAG_FINALIZED)) return STATUS_INVALID_HANDLE; + if (flags & KEY_EXPORT_FLAG_DH_PARAMETERS) + { + BCRYPT_DH_PARAMETER_HEADER *h; + unsigned int data_size; + + data_size = sizeof(BCRYPT_DH_PARAMETER_HEADER) + key->u.a.bitlen / 8 * 2; + if (params->ret_len) *params->ret_len = data_size; + if (!params->buf) return STATUS_SUCCESS; + if (params->len < data_size) return STATUS_BUFFER_TOO_SMALL; + + h = (BCRYPT_DH_PARAMETER_HEADER *)params->buf; + h->cbLength = data_size; + h->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC; + h->cbKeyLength = key->u.a.bitlen / 8; + memcpy( h + 1, (BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1, h->cbKeyLength * 2); + } + else + { + BCRYPT_DH_KEY_BLOB *h = (BCRYPT_DH_KEY_BLOB *)params->buf; + BOOL dh_private = flags & KEY_EXPORT_FLAG_DH_FULL; + + *params->ret_len = dh_pubkey_len( key ); + if (dh_private) + *params->ret_len += key->u.a.bitlen / 8; + + if (params->len < *params->ret_len) return STATUS_SUCCESS; + + memcpy(params->buf, key_data(key)->d.pubkey, dh_pubkey_len( key )); + if (dh_private) + memcpy(params->buf + dh_pubkey_len( key ), key_data(key)->d.privkey, key->u.a.bitlen / 8); + + h->dwMagic = dh_private ? BCRYPT_DH_PRIVATE_MAGIC : BCRYPT_DH_PUBLIC_MAGIC; + h->cbKey = key->u.a.bitlen / 8; + } + return STATUS_SUCCESS; + default: FIXME( "algorithm %u not yet supported\n", key->alg_id ); return STATUS_NOT_IMPLEMENTED; @@ -1604,6 +1807,49 @@ static NTSTATUS key_asymmetric_import( void *args ) FIXME( "DSA private key not supported\n" ); return STATUS_NOT_IMPLEMENTED; + case ALG_ID_DH: + if (flags & KEY_IMPORT_FLAG_DH_PARAMETERS) + { + const BCRYPT_DH_PARAMETER_HEADER *h = (const BCRYPT_DH_PARAMETER_HEADER *)params->buf; + ULONG param_size = sizeof(BCRYPT_DH_PARAMETER_HEADER) + key->u.a.bitlen / 8 * 2; + + if (key->u.a.flags & KEY_FLAG_FINALIZED) return STATUS_INVALID_HANDLE; + if (params->len < param_size) return STATUS_BUFFER_TOO_SMALL; + if (!h || h->cbLength != param_size || h->dwMagic != BCRYPT_DH_PARAMETERS_MAGIC + || h->cbKeyLength != key->u.a.bitlen / 8) + return STATUS_INVALID_PARAMETER; + + dh_key_alloc( key ); + memcpy((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1, h + 1, h->cbKeyLength * 2); + key->u.a.flags |= KEY_FLAG_DH_PARAMS_SET; + } + else + { + BCRYPT_DH_KEY_BLOB *h = (BCRYPT_DH_KEY_BLOB *)params->buf; + BOOL dh_private = flags & KEY_IMPORT_FLAG_DH_FULL; + ULONG size; + + if (h->dwMagic != (dh_private ? BCRYPT_DH_PRIVATE_MAGIC : BCRYPT_DH_PUBLIC_MAGIC)) + { + WARN("unexpected dwMagic %#x.\n", (int)h->dwMagic); + return STATUS_INVALID_PARAMETER; + } + + size = sizeof(*h) + h->cbKey * 3; + if (dh_private) + size += h->cbKey; + if (params->len != size) return STATUS_INVALID_PARAMETER; + if (h->cbKey * 8 < 512) return STATUS_INVALID_PARAMETER; + + dh_key_alloc( key ); + + memcpy( key_data(key)->d.pubkey, params->buf, dh_pubkey_len( key )); + + if (dh_private) + memcpy( key_data(key)->d.privkey, params->buf + sizeof(*h) + h->cbKey * 3, h->cbKey); + } + return STATUS_SUCCESS; + default: FIXME( "algorithm %u not yet supported\n", key->alg_id ); return STATUS_NOT_IMPLEMENTED; @@ -2018,8 +2264,15 @@ static NTSTATUS key_asymmetric_destroy( void *args ) { struct key *key = args; - if (key_data(key)->a.privkey) pgnutls_privkey_deinit( key_data(key)->a.privkey ); - if (key_data(key)->a.pubkey) pgnutls_pubkey_deinit( key_data(key)->a.pubkey ); + if (key->alg_id == ALG_ID_DH) + { + dh_key_free( key ); + } + else + { + if (key_data(key)->a.privkey) pgnutls_privkey_deinit( key_data(key)->a.privkey ); + if (key_data(key)->a.pubkey) pgnutls_pubkey_deinit( key_data(key)->a.pubkey ); + } return STATUS_SUCCESS; } @@ -2094,6 +2347,7 @@ static NTSTATUS dup_privkey( struct key *key_orig, struct key *key_copy ) } break; } + default: ERR( "unhandled algorithm %u\n", key_orig->alg_id ); return STATUS_INTERNAL_ERROR; @@ -2187,6 +2441,19 @@ static NTSTATUS key_asymmetric_duplicate( void *args ) const struct key_asymmetric_duplicate_params *params = args; NTSTATUS status; + if (params->key_orig->alg_id == ALG_ID_DH) + { + union key_data *s = key_data( params->key_orig ); + union key_data *d = key_data( params->key_copy ); + if (s->d.privkey) + { + dh_key_alloc( params->key_copy ); + memcpy( d->d.privkey, s->d.privkey, params->key_orig->u.a.bitlen / 8 ); + memcpy( d->d.pubkey, s->d.pubkey, dh_pubkey_len( params->key_orig )); + } + return STATUS_SUCCESS; + } + if (key_data(params->key_orig)->a.privkey && (status = dup_privkey( params->key_orig, params->key_copy ))) return status; @@ -2245,6 +2512,89 @@ static NTSTATUS key_asymmetric_encrypt( void *args ) return status; } +static NTSTATUS key_secret_agreement( void *args ) +{ + struct key_secret_agreement_params *params = args; + struct secret *secret; + struct key *priv_key; + struct key *peer_key; + int ret; + + priv_key = params->privkey; + peer_key = params->pubkey; + secret = params->secret; + + switch (priv_key->alg_id) + { + case ALG_ID_DH: + { + gnutls_datum_t prime, generator, priv, peer, secret_datum; + gnutls_dh_params_t dh_params; + ULONG key_length; + + if (!dh_supported) + { + ERR("DH is not available.\n"); + return STATUS_NOT_IMPLEMENTED; + } + + if ((ret = pgnutls_dh_params_init( &dh_params ))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } + + key_length = priv_key->u.a.bitlen / 8; + + prime.size = generator.size = key_length; + prime.data = (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key_data(priv_key)->d.pubkey + 1); + generator.data = (BYTE *)((BCRYPT_DH_KEY_BLOB *)key_data(priv_key)->d.pubkey + 1) + key_length; + + if ((ret = pgnutls_dh_params_import_raw2( dh_params, &prime, &generator, priv_key->u.a.bitlen ))) + { + pgnutls_perror( ret ); + pgnutls_dh_params_deinit( dh_params ); + return STATUS_INTERNAL_ERROR; + } + + priv.size = peer.size = key_length; + priv.data = key_data(priv_key)->d.privkey; + peer.data = key_data(peer_key)->d.pubkey + sizeof(BCRYPT_DH_KEY_BLOB) + key_length * 2; + + if (memcmp((BCRYPT_DH_KEY_BLOB *)key_data(priv_key)->d.pubkey + 1, + key_data(peer_key)->d.pubkey + sizeof(BCRYPT_DH_KEY_BLOB), key_length * 2)) + { + ERR("peer DH paramaters do not match.\n"); + pgnutls_dh_params_deinit( dh_params ); + return STATUS_INTERNAL_ERROR; + } + + if ((ret = pgnutls_dh_compute_key( dh_params, &priv, NULL, &peer, &secret_datum ))) + { + ERR("Error computing shared key.\n"); + pgnutls_perror( ret ); + pgnutls_dh_params_deinit( dh_params ); + return STATUS_INTERNAL_ERROR; + } + + TRACE("secret_datum.size %u, key_length %u.\n", secret_datum.size, (int)key_length); + export_gnutls_datum( secret->data, key_length, &secret_datum, 1 ); + secret->data_len = key_length; + free( secret_datum.data ); + break; + } + + case ALG_ID_ECDH_P256: + FIXME("ECDH is not supported.\n"); + break; + + default: + ERR( "unhandled algorithm %u\n", priv_key->alg_id ); + return STATUS_INVALID_HANDLE; + } + return STATUS_SUCCESS; +} + const unixlib_entry_t __wine_unix_call_funcs[] = { gnutls_process_attach, @@ -2263,7 +2613,8 @@ const unixlib_entry_t __wine_unix_call_funcs[] = key_asymmetric_verify, key_asymmetric_destroy, key_asymmetric_export, - key_asymmetric_import + key_asymmetric_import, + key_secret_agreement, }; #ifdef _WIN64 diff --git a/include/bcrypt.h b/include/bcrypt.h index 6822491ed36..34c79d9cbf4 100644 --- a/include/bcrypt.h +++ b/include/bcrypt.h @@ -62,6 +62,8 @@ typedef LONG NTSTATUS; #define BCRYPT_OPAQUE_KEY_BLOB L"OpaqueKeyBlob" #define BCRYPT_KEY_DATA_BLOB L"KeyDataBlob" #define BCRYPT_AES_WRAP_KEY_BLOB L"Rfc3565KeyWrapBlob" +#define BCRYPT_DH_PUBLIC_BLOB L"DHPUBLICBLOB" +#define BCRYPT_DH_PRIVATE_BLOB L"DHPRIVATEBLOB" #define BCRYPT_ECCPUBLIC_BLOB L"ECCPUBLICBLOB" #define BCRYPT_ECCPRIVATE_BLOB L"ECCPRIVATEBLOB" #define BCRYPT_RSAPUBLIC_BLOB L"RSAPUBLICBLOB" @@ -82,6 +84,7 @@ typedef LONG NTSTATUS; #define BCRYPT_3DES_ALGORITHM L"3DES" #define BCRYPT_AES_ALGORITHM L"AES" #define BCRYPT_DES_ALGORITHM L"DES" +#define BCRYPT_DH_ALGORITHM L"DH" #define BCRYPT_DSA_ALGORITHM L"DSA" #define BCRYPT_ECDH_P256_ALGORITHM L"ECDH_P256" #define BCRYPT_ECDH_P384_ALGORITHM L"ECDH_P384" @@ -113,6 +116,8 @@ typedef LONG NTSTATUS; #define BCRYPT_KDF_TLS_PRF L"TLS_PRF" #define BCRYPT_KDF_SP80056A_CONCAT L"SP800_56A_CONCAT" #define BCRYPT_KDF_RAW_SECRET L"TRUNCATE" + +#define BCRYPT_DH_PARAMETERS L"DHParameters" #else static const WCHAR BCRYPT_ALGORITHM_NAME[] = {'A','l','g','o','r','i','t','h','m','N','a','m','e',0}; static const WCHAR BCRYPT_AUTH_TAG_LENGTH[] = {'A','u','t','h','T','a','g','L','e','n','g','t','h',0}; @@ -135,6 +140,8 @@ static const WCHAR BCRYPT_SIGNATURE_LENGTH[] = {'S','i','g','n','a','t','u','r', static const WCHAR BCRYPT_OPAQUE_KEY_BLOB[] = {'O','p','a','q','u','e','K','e','y','B','l','o','b',0}; static const WCHAR BCRYPT_KEY_DATA_BLOB[] = {'K','e','y','D','a','t','a','B','l','o','b',0}; static const WCHAR BCRYPT_AES_WRAP_KEY_BLOB[] = {'R','f','c','3','5','6','5','K','e','y','W','r','a','p','B','l','o','b',0}; +static const WCHAR BCRYPT_DH_PUBLIC_BLOB[] = {'D','H','P','U','B','L','I','C','B','L','O','B',0}; +static const WCHAR BCRYPT_DH_PRIVATE_BLOB[] = {'D','H','P','R','I','V','A','T','E','B','L','O','B',0}; static const WCHAR BCRYPT_ECCPUBLIC_BLOB[] = {'E','C','C','P','U','B','L','I','C','B','L','O','B',0}; static const WCHAR BCRYPT_ECCPRIVATE_BLOB[] = {'E','C','C','P','R','I','V','A','T','E','B','L','O','B',0}; static const WCHAR BCRYPT_RSAPUBLIC_BLOB[] = {'R','S','A','P','U','B','L','I','C','B','L','O','B',0}; @@ -157,6 +164,7 @@ static const WCHAR MS_PLATFORM_CRYPTO_PROVIDER[] = \ static const WCHAR BCRYPT_3DES_ALGORITHM[] = {'3','D','E','S',0}; static const WCHAR BCRYPT_AES_ALGORITHM[] = {'A','E','S',0}; static const WCHAR BCRYPT_DES_ALGORITHM[] = {'D','E','S',0}; +static const WCHAR BCRYPT_DH_ALGORITHM[] = {'D','H',0}; static const WCHAR BCRYPT_DSA_ALGORITHM[] = {'D','S','A',0}; static const WCHAR BCRYPT_ECDH_P256_ALGORITHM[] = {'E','C','D','H','_','P','2','5','6',0}; static const WCHAR BCRYPT_ECDH_P384_ALGORITHM[] = {'E','C','D','H','_','P','3','8','4',0}; @@ -188,6 +196,7 @@ static const WCHAR BCRYPT_KDF_HMAC[] = {'H','M','A','C',0}; static const WCHAR BCRYPT_KDF_TLS_PRF[] = {'T','L','S','_','P','R','F',0}; static const WCHAR BCRYPT_KDF_SP80056A_CONCAT[] = {'S','P','8','0','0','_','5','6','A','_','C','O','N','C','A','T',0}; static const WCHAR BCRYPT_KDF_RAW_SECRET[] = {'T','R','U','N','C','A','T','E',0}; +#define BCRYPT_DH_PARAMETERS u"DHParameters" #endif #define BCRYPT_ECDSA_PUBLIC_P256_MAGIC 0x31534345 @@ -320,6 +329,15 @@ typedef struct _BCRYPT_DSA_KEY_BLOB #define BCRYPT_DSA_PUBLIC_MAGIC_V2 0x32425044 #define BCRYPT_DSA_PRIVATE_MAGIC_V2 0x32565044 +typedef struct _BCRYPT_DH_KEY_BLOB +{ + ULONG dwMagic; + ULONG cbKey; +} BCRYPT_DH_KEY_BLOB, *PBCRYPT_DH_KEY_BLOB; + +#define BCRYPT_DH_PUBLIC_MAGIC 0x42504844 +#define BCRYPT_DH_PRIVATE_MAGIC 0x56504844 + typedef enum { DSA_HASH_ALGORITHM_SHA1, @@ -379,6 +397,15 @@ typedef struct _BCRYPT_KEY_DATA_BLOB_HEADER ULONG cbKeyData; } BCRYPT_KEY_DATA_BLOB_HEADER, *PBCRYPT_KEY_DATA_BLOB_HEADER; +typedef struct _BCRYPT_DH_PARAMETER_HEADER +{ + ULONG cbLength; + ULONG dwMagic; + ULONG cbKeyLength; +} BCRYPT_DH_PARAMETER_HEADER; + +#define BCRYPT_DH_PARAMETERS_MAGIC 0x4d504844 + #define KDF_HASH_ALGORITHM 0x00000000 #define KDF_SECRET_PREPEND 0x00000001 #define KDF_SECRET_APPEND 0x00000002 @@ -408,6 +435,8 @@ typedef PVOID BCRYPT_HANDLE; typedef PVOID BCRYPT_HASH_HANDLE; typedef PVOID BCRYPT_SECRET_HANDLE; +#define BCRYPT_NO_KEY_VALIDATION 0x00000008 + /* Pseudo handles */ #define BCRYPT_MD2_ALG_HANDLE ((BCRYPT_ALG_HANDLE)0x00000001) #define BCRYPT_MD4_ALG_HANDLE ((BCRYPT_ALG_HANDLE)0x00000011) From f730ca784e1d027b674b65c3de0d5b04cf0930f1 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 9 Dec 2020 20:10:13 +0300 Subject: [PATCH 0603/2777] bcrypt: Implement BCryptDeriveKey() for _KDF_RAW_SECRET. Extracted from the patch implementing ECDH on top of gcrypt by Derek Lesho. --- dlls/bcrypt/bcrypt_main.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index 72a7b1915f2..e6016a062c5 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -2455,12 +2455,35 @@ NTSTATUS WINAPI BCryptDeriveKey( BCRYPT_SECRET_HANDLE handle, const WCHAR *kdf, { struct secret *secret = get_secret_object( handle ); - FIXME( "%p, %s, %p, %p, %lu, %p, %#lx\n", secret, debugstr_w(kdf), parameter, derived, derived_size, result, flags ); + TRACE( "%p, %s, %p, %p, %lu, %p, %#lx\n", secret, debugstr_w(kdf), parameter, derived, derived_size, result, flags ); if (!secret) return STATUS_INVALID_HANDLE; if (!kdf) return STATUS_INVALID_PARAMETER; - return STATUS_INTERNAL_ERROR; + if (flags) FIXME("flags ignored: %#lx\n", flags); + + if (!(lstrcmpW( kdf, BCRYPT_KDF_RAW_SECRET ))) + { + ULONG secret_length = secret->data_len; + unsigned int i;; + + if (!derived) + { + *result = secret_length; + return STATUS_SUCCESS; + } + + /* outputs in little endian for some reason */ + for (i = 0; i < min(secret_length, derived_size); i++) + { + derived[i] = secret->data[secret_length - i - 1]; + } + + *result = i; + return STATUS_SUCCESS; + } + FIXME( "Derivation function %s not supported.\n", debugstr_w(kdf) ); + return STATUS_NOT_IMPLEMENTED; } BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) From ebc03fd79e25ca53582d14a7098b2cb454a10018 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Tue, 7 Jan 2020 14:22:49 -0600 Subject: [PATCH 0604/2777] bcrypt: Implement BCRYPT_KDF_HASH. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47699 Signed-off-by: Derek Lesho --- dlls/bcrypt/bcrypt_main.c | 107 ++++++++++++++++++++++++++++++++++++- dlls/bcrypt/tests/bcrypt.c | 3 +- 2 files changed, 107 insertions(+), 3 deletions(-) diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index e6016a062c5..bcb7a692ffd 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -2462,7 +2462,112 @@ NTSTATUS WINAPI BCryptDeriveKey( BCRYPT_SECRET_HANDLE handle, const WCHAR *kdf, if (flags) FIXME("flags ignored: %#lx\n", flags); - if (!(lstrcmpW( kdf, BCRYPT_KDF_RAW_SECRET ))) + if (!(lstrcmpW( kdf, BCRYPT_KDF_HASH ))) + { + unsigned int i; + BCryptBuffer *hash_algorithm = NULL; + BCryptBuffer *secret_prepend = NULL; + BCryptBuffer *secret_append = NULL; + enum alg_id hash_alg_id; + ULONG hash_length; + struct hash_impl hash; + NTSTATUS status; + + if (parameter) + { + for (i = 0; i < parameter->cBuffers; i++) + { + BCryptBuffer *cur_buffer = ¶meter->pBuffers[i]; + switch(cur_buffer->BufferType) + { + case KDF_HASH_ALGORITHM: + if (hash_algorithm) + FIXME("Duplicate KDF_HASH_ALGORITHM, untested\n"); + hash_algorithm = cur_buffer; + break; + case KDF_SECRET_PREPEND: + if (secret_prepend) + FIXME("Multiple prefixes unsupported\n"); + secret_prepend = cur_buffer; + break; + case KDF_SECRET_APPEND: + if (secret_append) + FIXME("Multiple suffixes unsupported\n"); + secret_append = cur_buffer; + break; + default: + FIXME("Unsupported BCRYPT_KDF_HASH parameter type %#lx\n", cur_buffer->BufferType); + break; + } + } + } + + if (!(hash_algorithm)) + hash_alg_id = ALG_ID_SHA1; + else + { + for (i = 0; i < ARRAY_SIZE( builtin_algorithms ); i++) + { + if (!lstrcmpW( hash_algorithm->pvBuffer, builtin_algorithms[i].name)) + { + hash_alg_id = i; + break; + } + } + if (i == ARRAY_SIZE(builtin_algorithms)) + { + WARN("Algorithm %s not found\n", debugstr_w(hash_algorithm->pvBuffer)); + return STATUS_NOT_SUPPORTED; + } + if (builtin_algorithms[hash_alg_id].class != BCRYPT_HASH_INTERFACE) + { + WARN("Incorrect class %lu\n", builtin_algorithms[hash_alg_id].class); + return STATUS_NOT_SUPPORTED; + } + } + + hash_length = builtin_algorithms[hash_alg_id].hash_length; + + if (!derived) + { + *result = hash_length; + return STATUS_SUCCESS; + } + + if ((status = hash_init(&hash, hash_alg_id))) + { + return status; + } + + if (secret_prepend) + { + hash_update(&hash, hash_alg_id, secret_prepend->pvBuffer, secret_prepend->cbBuffer); + } + + hash_update(&hash, hash_alg_id, secret->data, secret->data_len); + + if (secret_append) + { + hash_update(&hash, hash_alg_id, secret_append->pvBuffer, secret_append->cbBuffer); + } + + if (derived_size >= hash_length) + { + hash_finish(&hash, hash_alg_id, derived); + *result = hash_length; + } + else + { + UCHAR *output = malloc(hash_length); + hash_finish(&hash, hash_alg_id, output); + memcpy(derived, output, derived_size); + free(output); + *result = derived_size; + } + + return STATUS_SUCCESS; + } + else if (!(lstrcmpW( kdf, BCRYPT_KDF_RAW_SECRET ))) { ULONG secret_length = secret->data_len; unsigned int i;; diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index 5d1a80f330b..80c98736c56 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -2862,7 +2862,7 @@ static void test_ECDH(void) buf = malloc(size); status = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, &hash_params, buf, size, &size, 0); ok(status == STATUS_SUCCESS, "got %#lx\n", status); - ok(!(memcmp(hashed_secret, buf, size)), "wrong data\n"); + todo_wine ok(!(memcmp(hashed_secret, buf, size)), "wrong data\n"); free(buf); /* ulVersion is not verified */ @@ -3428,7 +3428,6 @@ static void test_SecretAgreement(void) ok(status == STATUS_INVALID_PARAMETER, "got %#lx\n", status); status = BCryptDeriveKey(secret, L"HASH", NULL, NULL, 0, &size, 0); - todo_wine ok(status == STATUS_SUCCESS, "got %#lx\n", status); status = BCryptDestroyHash(secret); From b3871641d57b3f3ce26530de4411d33fce322a2f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 3 Mar 2021 21:58:44 +0300 Subject: [PATCH 0605/2777] bcrypt/tests: Add test for DH secret agreement. --- dlls/bcrypt/tests/bcrypt.c | 358 +++++++++++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index 80c98736c56..3ec20b62175 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -3452,6 +3452,362 @@ static void test_SecretAgreement(void) ok(status == STATUS_SUCCESS, "got %#lx\n", status); } +static void test_dh_SecretAgreement(void) +{ + static BCryptBuffer hash_param_buffers[] = + { + { + sizeof(BCRYPT_SHA256_ALGORITHM), + KDF_HASH_ALGORITHM, + (void *)BCRYPT_SHA256_ALGORITHM, + } + }; + + static BCryptBufferDesc hash_params = + { + BCRYPTBUFFER_VERSION, + ARRAY_SIZE(hash_param_buffers), + hash_param_buffers, + }; + + static const ULONG private_key_data[] = + { + 0xc4caf69c, 0x57b4db27, 0x36f7135f, 0x5ccba686, 0xc37b8819, 0x1d35c9b2, 0xbb07a1cf, 0x0c5d1c1b, + 0xc79acb10, 0x31dfdabb, 0x702e02b9, 0x1efab345, 0x262a8074, 0x5edf7698, 0x9b9dc630, 0x13c34b93, + 0xacbc928b, 0xb79eed8c, 0x7413dce9, 0xa5521280, 0x88d8e695, 0xa310269f, 0xca7c5719, 0xcd0c775b, + 0x9a6e2cf2, 0x9e235c51, 0xf49db62d, 0x28e72424, 0x4a44da5a, 0x3d98268d, 0x8e4d2be3, 0x254e44e6, + + 0x18a67e55, 0x572e13a1, 0x46f81ca8, 0xc331c9b9, 0xf8fe3dd4, 0x8a889e5a, 0x6c0505fd, 0xbd97a121, + 0xed2dbd67, 0xf39efa8e, 0x36f9c287, 0xf6bbfa6c, 0x461e42ad, 0x17dc170e, 0xc002dc2e, 0x4813d9a4, + 0x0b6fabb8, 0x6a9e1860, 0xa8a8cbd9, 0xb7ed6b5d, 0xabb34d23, 0xf2fbe1fd, 0x8670df1e, 0xba7fa4e6, + 0xf7039712, 0x94448f30, 0xe10c812e, 0x3e311976, 0xcfdd72c4, 0xbdbea98f, 0xc9a540d6, 0x89646d57, + + 0x7ab63b33, 0x03a1e9b6, 0x947f7a9b, 0x5ae59eeb, 0x1d12eb05, 0x3f425d92, 0xe028c6ba, 0xbf90ddc9, + 0xb554f55a, 0x7aeb88b6, 0x4a443a5f, 0xbab35111, 0x82c78a0c, 0x298dd482, 0x02937cb1, 0xc94cdc2e, + 0x59b010eb, 0x3bbc0a2b, 0xd845fee0, 0x04c1d0db, 0x0c8c9424, 0x1cafd4b2, 0x9aa7aed9, 0x6a478486, + 0xa8841fd7, 0xbfeff40a, 0x8fd7bcc5, 0x3bb28977, 0x2b9a7955, 0xa55cd2e4, 0x1b6ad657, 0x067cdf21, + + 0x06f36920, 0x63280e1b, 0xf17d930f, 0xa06e74a8, 0x463b3a6f, 0x2a464507, 0x93f8a982, 0x8f620a7d, + 0xeda32d11, 0x9706a6d4, 0x33dce588, 0x75a1c446, 0x048ab567, 0xd735aafa, 0x806f7c1c, 0xdcb9651a, + 0x26acf3b4, 0x45f91cc9, 0x2a0de6fc, 0xf3c03d0c, 0xf5aee0aa, 0x3eeaaf36, 0x18ccee61, 0x83faa783, + 0x4b2b5250, 0xf4ccea22, 0x5ac0714b, 0x3f0b2bc6, 0x481b13ce, 0x12040ea7, 0x66e0bbed, 0x158e1a67, + }; + static const ULONG raw_shared_secret[] = + { + 0x375d89b5, 0x35a9c270, 0xfbc5ba82, 0x09eb3069, 0xd50965b0, 0xace510f7, 0x981e8731, 0x80a76115, + 0xf386d348, 0xca17b8df, 0x0b0e84ec, 0xf81f756e, 0x5030fa20, 0x03113b71, 0x97b7e879, 0x899b5fae, + 0xe6913299, 0x09270076, 0x39bc813a, 0xde3ef070, 0x65ad5b3a, 0x2b7c4ba4, 0x86c98ef9, 0x3236feaf, + 0x3e0253f7, 0x0489d2dd, 0x97669a3d, 0x50242fca, 0x5d4aecb1, 0xcf2d805f, 0x2258afff, 0x750e92cd, + }; + static const ULONG sha1_shared_secret[] = + { + 0x0babba9c, 0x0bdeacbd, 0x04e36574, 0xdd504dcd, 0x0cd88db0, + }; + static const ULONG sha256_shared_secret[] = + { + 0x3213db5b, 0x8cc8250b, 0xc829eaab, 0x00933709, 0x68160aa9, 0xfb9f1e20, 0xf92368e6, 0x2b8e18eb, + }; + + BCRYPT_DH_PARAMETER_HEADER *dh_header; + BCRYPT_SECRET_HANDLE secret, secret2; + BCRYPT_DH_KEY_BLOB *dh_key_blob; + static const ULONG length = 1024; + BCRYPT_KEY_HANDLE key, key2; + BCRYPT_ALG_HANDLE alg; + UCHAR buffer[2048]; + NTSTATUS status; + unsigned int i; + ULONG size; + + status = BCryptOpenAlgorithmProvider(&alg, BCRYPT_DH_ALGORITHM, NULL, 0); + ok(!status, "got %08lx\n", status); + if (status) + return; + + key = NULL; + + status = BCryptGenerateKeyPair(alg, &key, 256, 0); + ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status); + + status = BCryptGenerateKeyPair(alg, &key, length, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(key != NULL, "key not set\n"); + + memset(buffer, 0xcc, sizeof(buffer)); + status = BCryptGetProperty(key, BCRYPT_DH_PARAMETERS, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptExportKey(key, NULL, BCRYPT_DH_PUBLIC_BLOB, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptFinalizeKeyPair(key, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + size = 0xdeadbeef; + status = BCryptGetProperty(key, BCRYPT_DH_PARAMETERS, NULL, sizeof(buffer), &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_PARAMETER_HEADER) + length / 8 * 2, "Got unexpected size %lu.\n", size); + + size = 0xdeadbeef; + status = BCryptGetProperty(key, BCRYPT_DH_PARAMETERS, buffer, 28, &size, 0); + ok(status == STATUS_BUFFER_TOO_SMALL, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_PARAMETER_HEADER) + length / 8 * 2, "Got unexpected size %lu.\n", size); + + size = 0xdeadbeef; + status = BCryptGetProperty(key, BCRYPT_DH_PARAMETERS, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_PARAMETER_HEADER) + length / 8 * 2, "Got unexpected size %lu.\n", size); + + dh_header = (BCRYPT_DH_PARAMETER_HEADER *)buffer; + ok(dh_header->cbLength == sizeof(*dh_header) + length / 8 * 2, "Got unexpected length %lu.\n", dh_header->cbLength); + ok(dh_header->cbKeyLength == length / 8, "Got unexpected length %lu.\n", dh_header->cbKeyLength); + ok(dh_header->dwMagic == BCRYPT_DH_PARAMETERS_MAGIC, "Got unexpected magic %#lx.\n", dh_header->dwMagic); + + status = BCryptDestroyKey(key); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + dh_key_blob = (BCRYPT_DH_KEY_BLOB *)buffer; + dh_key_blob->dwMagic = BCRYPT_DH_PRIVATE_MAGIC; + dh_key_blob->cbKey = length / 8; + memcpy(dh_key_blob + 1, private_key_data, sizeof(private_key_data)); + size = sizeof(buffer); + status = BCryptImportKeyPair(alg, NULL, BCRYPT_DH_PRIVATE_BLOB, &key, buffer, size, 0); + ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status); + size = sizeof(*dh_key_blob) + length / 8 * 4; + status = BCryptImportKeyPair(alg, NULL, BCRYPT_DH_PRIVATE_BLOB, &key, buffer, size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + memset(buffer, 0xcc, sizeof(buffer)); + size = 0xdeadbeef; + status = BCryptExportKey(key, NULL, BCRYPT_DH_PUBLIC_BLOB, NULL, 0, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_KEY_BLOB) + length / 8 * 3, "Got unexpected size %lu.\n", size); + + size = 0xdeadbeef; + status = BCryptExportKey(key, NULL, BCRYPT_DH_PUBLIC_BLOB, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_KEY_BLOB) + length / 8 * 3, "Got unexpected size %lu.\n", size); + dh_key_blob = (BCRYPT_DH_KEY_BLOB *)buffer; + ok(dh_key_blob->dwMagic == BCRYPT_DH_PUBLIC_MAGIC, "Got unexpected magic %#lx.\n", dh_key_blob->dwMagic); + ok(dh_key_blob->cbKey == length / 8, "Got unexpected length %lu.\n", dh_key_blob->cbKey); + ok(!memcmp(dh_key_blob + 1, private_key_data, length / 8 * 3), "Key data does not match.\n"); + + status = BCryptGenerateKeyPair(alg, &key2, length, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + dh_header = (BCRYPT_DH_PARAMETER_HEADER *)buffer; + dh_header->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC; + dh_header->cbLength = sizeof(*dh_header) + length / 8 * 2; + dh_header->cbKeyLength = length / 8; + memcpy(dh_header + 1, private_key_data, length / 8 * 2); + status = BCryptSetProperty(key2, BCRYPT_DH_PARAMETERS, buffer, dh_header->cbLength, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptFinalizeKeyPair(key2, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptExportKey(key2, NULL, BCRYPT_DH_PUBLIC_BLOB, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == sizeof(BCRYPT_DH_KEY_BLOB) + length / 8 * 3, "Got unexpected size %lu.\n", size); + ok(dh_key_blob->dwMagic == BCRYPT_DH_PUBLIC_MAGIC, "Got unexpected dwMagic %#lx.\n", dh_key_blob->dwMagic); + ok(dh_key_blob->cbKey == length / 8, "Got unexpected length %lu.\n", dh_key_blob->cbKey); + ok(!memcmp(dh_key_blob + 1, private_key_data, length / 8 * 2), "DH parameters do not match.\n"); + ok(memcmp((BYTE *)(dh_key_blob + 1) + length / 8 * 2, (BYTE *)private_key_data + length / 8 * 2, length / 8), + "Random public key data matches.\n"); + + memset(buffer, 0xcc, sizeof(buffer)); + status = BCryptExportKey(key, NULL, BCRYPT_DH_PRIVATE_BLOB, buffer, sizeof(buffer), &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + dh_key_blob = (BCRYPT_DH_KEY_BLOB *)buffer; + ok(size == sizeof(BCRYPT_DH_KEY_BLOB) + length / 8 * 4, "Got unexpected size %lu.\n", size); + ok(dh_key_blob->dwMagic == BCRYPT_DH_PRIVATE_MAGIC, "Got unexpected dwMagic %#lx.\n", dh_key_blob->dwMagic); + ok(dh_key_blob->cbKey == length / 8, "Got unexpected length %lu.\n", dh_key_blob->cbKey); + ok(!memcmp(dh_key_blob + 1, private_key_data, length / 8 * 4), "Private key data does not match.\n"); + + status = BCryptSecretAgreement(NULL, key, &secret, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptSecretAgreement(key, NULL, &secret, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptSecretAgreement(key, key, NULL, 0); + ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status); + + status = BCryptSecretAgreement(key, key, &secret, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptDeriveKey(NULL, L"HASH", NULL, NULL, 0, &size, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptDeriveKey(key, L"HASH", NULL, NULL, 0, &size, 0); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptDeriveKey(secret, NULL, NULL, NULL, 0, &size, 0); + ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status); + + size = 0xdeadbeef; + status = BCryptDeriveKey(secret, L"HASH", NULL, NULL, 0, &size, 0); + ok(size == 20, "Got unexpected size %lu.\n", size); + + size = 0xdeadbeef; + status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, NULL, 0, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == length / 8, "Got unexpected size %lu.\n", size); + + status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, buffer, 128, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == length / 8, "Got unexpected size %lu.\n", size); + ok(!memcmp(buffer, raw_shared_secret, size), "Raw shared secret data does not match.\n"); + + size = sizeof(buffer); + memset(buffer, 0xcc, sizeof(buffer)); + status = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, NULL, buffer, 128, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == 20, "Got unexpected size %lu.\n", size); + ok(!memcmp(buffer, sha1_shared_secret, sizeof(sha1_shared_secret)), "sha1 shared secret data does not match.\n"); + + size = sizeof(buffer); + status = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, &hash_params, buffer, size, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == 32, "Got unexpected size %lu.\n", size); + ok(!memcmp(buffer, sha256_shared_secret, sizeof(sha256_shared_secret)), "sha1 shared secret data does not match.\n"); + + for (i = size; i < sizeof(buffer); ++i) + if (buffer[i] != 0xcc) + break; + ok(i == sizeof(buffer), "Buffer modified at %i, value %#x.\n", i, buffer[i]); + + status = BCryptDestroySecret(secret); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptSecretAgreement(key, key2, &secret, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptSecretAgreement(key2, key, &secret2, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, buffer, 128, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, buffer + size, 128, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(!memcmp(buffer, buffer + size, size), "Shared secrets do not match.\n"); + + status = BCryptDestroyHash(secret); + ok(status == STATUS_INVALID_PARAMETER, "got %08lx\n", status); + + status = BCryptDestroyKey(secret); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptDestroySecret(NULL); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptDestroySecret(alg); + ok(status == STATUS_INVALID_HANDLE, "got %08lx\n", status); + + status = BCryptDestroySecret(secret); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptDestroyKey(key); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptDestroyKey(key2); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptCloseAlgorithmProvider(alg, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); +} + +static void test_dh_SecretAgreement_values(void) +{ + static const ULONG private_key_data[] = + { + 0xffffffff, 0xffffffff, 0xa2da0fc9, 0x34c26821, 0x8b62c6c4, 0xd11cdc80, 0x084e0229, 0x74cc678a, + 0xa6be0b02, 0x229b133b, 0x79084a51, 0xdd04348e, 0xb31995ef, 0x1b433acd, 0x6d0a2b30, 0x37145ff2, + 0x6d35e14f, 0x45c2516d, 0x76b585e4, 0xc67e5e62, 0xe9424cf4, 0x6bed37a6, 0xb65cff0b, 0xedb706f4, + 0xfb6b38ee, 0xa59f895a, 0x11249fae, 0xe61f4b7c, 0x51662849, 0x8153e6ec, 0xffffffff, 0xffffffff, + + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000000, + + 0xa0c3c734, 0xc130c92d, 0x5265abf8, 0xff409f17, 0xbcdce187, 0xff64dae3, 0x170560aa, 0xb2423ed8, + 0x9ee5a8b9, 0x92548030, 0x02bba1f9, 0x823e39a4, 0x69c438f5, 0xf91016ac, 0x89bfd166, 0x7f996446, + 0x86224203, 0x15bf689c, 0x619354a4, 0x0c1d3a1f, 0x11bcf3d2, 0x58aae029, 0x41c69824, 0x3fafc179, + 0xa742747c, 0x60658c7a, 0xd3b0bde4, 0x78d3f08b, 0x6cefa061, 0x33752536, 0xe84d4901, 0x48cd73f4, + + 0x8d449700, 0x1f95120e, 0xceb31745, 0x3663177b, 0xbd9bb2d5, 0x9c23c0d9, 0x814d34f8, 0xbc54edb0, + 0xb874659a, 0x3bac8a30, 0xa1f3dd46, 0x1705c900, 0xbc46fefe, 0x7d13875b, 0x3064351a, 0x4bd89a1c, + 0x9e938761, 0x931949db, 0x34490719, 0x84fb08ca, 0xa9dd355a, 0x5b3f5061, 0x2ac96663, 0xc594429e, + 0xbe58395d, 0x2f7d872a, 0x303d37b3, 0xa3a9b606, 0x735a6732, 0xa095bd95, 0x3d55a7c3, 0x00e54635, + }; + static const ULONG peer_key_data[] = + { + 0xffffffff, 0xffffffff, 0xa2da0fc9, 0x34c26821, 0x8b62c6c4, 0xd11cdc80, 0x084e0229, 0x74cc678a, + 0xa6be0b02, 0x229b133b, 0x79084a51, 0xdd04348e, 0xb31995ef, 0x1b433acd, 0x6d0a2b30, 0x37145ff2, + 0x6d35e14f, 0x45c2516d, 0x76b585e4, 0xc67e5e62, 0xe9424cf4, 0x6bed37a6, 0xb65cff0b, 0xedb706f4, + 0xfb6b38ee, 0xa59f895a, 0x11249fae, 0xe61f4b7c, 0x51662849, 0x8153e6ec, 0xffffffff, 0xffffffff, + + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000000, + + 0x3bf7404b, 0x6284fffe, 0x97c0d565, 0xd830c658, 0xcc21bf39, 0xcae45bb6, 0x019df7df, 0xbf4cd293, + 0x6bf1989d, 0x78a81f52, 0xa4ed861c, 0x6bacf493, 0xa3e700d1, 0xd06cc206, 0x411b9727, 0x01e9c9ab, + 0x9b7e6efa, 0xf46bb25d, 0xd1027242, 0x6130787c, 0xa7b87d8b, 0xfee41492, 0x50db6213, 0x321199b6, + 0x7dace53a, 0xe8b1ec51, 0x2181b113, 0x3b33e3c0, 0x5b3a2d67, 0xbd34f0c1, 0x7037c542, 0x4a8d5540, + }; + static const ULONG raw_shared_secret[] = + { + 0x0815f37d, 0x19ee74ab, 0x9f63f123, 0xe1b3f10c, 0xbcc9be83, 0xaddf5b9d, 0x28174e72, 0xf8a33825, + 0xfc74e47d, 0x2c950888, 0xf5b776d9, 0xfc712fef, 0x5b213b32, 0x489a9829, 0xfc0a4d1d, 0x6e641d3b, + 0x3bb2ff57, 0x63500318, 0x081ee54f, 0xf33a2805, 0xb3759e98, 0xa9a64afe, 0x964b8897, 0x04691bbc, + 0x80f4aae1, 0x617405ee, 0xab71724d, 0x6c10c214, 0x6f60b96f, 0xdc777b0b, 0x22f40d4f, 0x8a1c4eb5, + }; + + BCRYPT_DH_KEY_BLOB *dh_key_blob; + static const ULONG length = 1024; + BCRYPT_KEY_HANDLE key, key2; + BCRYPT_SECRET_HANDLE secret; + BCRYPT_ALG_HANDLE alg; + UCHAR buffer[2048]; + NTSTATUS status; + ULONG size; + + status = BCryptOpenAlgorithmProvider(&alg, BCRYPT_DH_ALGORITHM, NULL, 0); + ok(!status, "got %08lx\n", status); + + dh_key_blob = (BCRYPT_DH_KEY_BLOB *)buffer; + dh_key_blob->dwMagic = BCRYPT_DH_PRIVATE_MAGIC; + dh_key_blob->cbKey = length / 8; + memcpy(dh_key_blob + 1, private_key_data, sizeof(private_key_data)); + + size = sizeof(*dh_key_blob) + length / 8 * 4; + status = BCryptImportKeyPair(alg, NULL, BCRYPT_DH_PRIVATE_BLOB, &key, buffer, size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + dh_key_blob = (BCRYPT_DH_KEY_BLOB *)buffer; + dh_key_blob->dwMagic = BCRYPT_DH_PUBLIC_MAGIC; + dh_key_blob->cbKey = length / 8; + memcpy(dh_key_blob + 1, peer_key_data, sizeof(peer_key_data)); + + size = sizeof(*dh_key_blob) + length / 8 * 3; + status = BCryptImportKeyPair(alg, NULL, BCRYPT_DH_PUBLIC_BLOB, &key2, buffer, size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptSecretAgreement(key, key2, &secret, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + + status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, buffer, 128, &size, 0); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + ok(size == length / 8, "Got unexpected size %lu.\n", size); + ok(!memcmp(buffer, raw_shared_secret, size), "Raw shared secret data does not match.\n"); + + status = BCryptDestroySecret(secret); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptDestroyKey(key); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); + status = BCryptDestroyKey(key2); + ok(status == STATUS_SUCCESS, "got %08lx\n", status); +} + START_TEST(bcrypt) { HMODULE module; @@ -3488,6 +3844,8 @@ START_TEST(bcrypt) test_DSA(); test_SecretAgreement(); test_rsa_encrypt(); + test_dh_SecretAgreement(); + test_dh_SecretAgreement_values(); FreeLibrary(module); } From b0c2492c38a33c37e8877a1572eb0679b948a96f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 11 Dec 2020 04:07:13 +0300 Subject: [PATCH 0606/2777] bcrypt: Reimplement DH using libgmp instead of private gnutls functions. --- configure.ac | 8 ++ dlls/bcrypt/Makefile.in | 2 +- dlls/bcrypt/gnutls.c | 300 +++++++++++++++++++++++++++++----------- 3 files changed, 228 insertions(+), 82 deletions(-) diff --git a/configure.ac b/configure.ac index a7268c12d15..c9bc5897f91 100644 --- a/configure.ac +++ b/configure.ac @@ -1419,6 +1419,14 @@ fi WINE_WARNING_WITH(gnutls,[test "x$ac_cv_lib_soname_gnutls" = "x"], [libgnutls ${notice_platform}development files not found, no schannel support.]) +dnl **** Check for libgmp **** +if test "x$with_gnutls" != "xno" +then + WINE_PACKAGE_FLAGS(GMP,[gmp],[-lgmp],,, + [AC_CHECK_HEADERS([gmp.h], + [WINE_CHECK_SONAME(gmp,__gmpz_init,,[GMP_CFLAGS=""],[$GMP_LIBS],[[libgmp-*]])])]) +fi + dnl **** Check for SANE **** if test "x$with_sane" != "xno" then diff --git a/dlls/bcrypt/Makefile.in b/dlls/bcrypt/Makefile.in index 11f4acea4f2..b8531957f63 100644 --- a/dlls/bcrypt/Makefile.in +++ b/dlls/bcrypt/Makefile.in @@ -2,7 +2,7 @@ MODULE = bcrypt.dll IMPORTS = advapi32 IMPORTLIB = bcrypt UNIXLIB = bcrypt.so -UNIX_CFLAGS = $(GNUTLS_CFLAGS) +UNIX_CFLAGS = $(GNUTLS_CFLAGS) $(GMP_CFLAGS) C_SRCS = \ bcrypt_main.c \ diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index 4a9f223a838..d0cc55136e1 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -48,6 +48,15 @@ #include "wine/debug.h" +#include + +#ifdef HAVE_GMP_H +#include +#endif + +#include +#include + WINE_DEFAULT_DEBUG_CHANNEL(bcrypt); WINE_DECLARE_DEBUG_CHANNEL(winediag); @@ -127,8 +136,6 @@ static void dh_key_alloc( struct key *key ) key_data(key)->d.pubkey = calloc( 1, dh_pubkey_len( key )); } -static BOOL dh_supported; - /* Not present in gnutls version < 3.0 */ static int (*pgnutls_cipher_tag)(gnutls_cipher_hd_t, void *, size_t); static int (*pgnutls_cipher_add_auth)(gnutls_cipher_hd_t, const void *, size_t); @@ -185,11 +192,9 @@ static int (*pgnutls_dh_params_import_raw2)(gnutls_dh_params_t dh_params, const const gnutls_datum_t * generator, unsigned key_bits); static int (*pgnutls_dh_params_export_raw)(gnutls_dh_params_t params, gnutls_datum_t * prime, gnutls_datum_t * generator, unsigned int *bits); -static int (*pgnutls_dh_generate_key)(gnutls_dh_params_t dh_params, gnutls_datum_t *priv_key, gnutls_datum_t *pub_key); -static int (*pgnutls_dh_compute_key)(gnutls_dh_params_t dh_params, const gnutls_datum_t *priv_key, - const gnutls_datum_t *pub_key, const gnutls_datum_t *peer_key, gnutls_datum_t *Z); static void *libgnutls_handle; + #define MAKE_FUNCPTR(f) static typeof(f) * p##f MAKE_FUNCPTR(gnutls_cipher_decrypt2); MAKE_FUNCPTR(gnutls_cipher_deinit); @@ -209,6 +214,22 @@ MAKE_FUNCPTR(gnutls_pubkey_deinit); MAKE_FUNCPTR(gnutls_pubkey_encrypt_data); MAKE_FUNCPTR(gnutls_pubkey_import_privkey); MAKE_FUNCPTR(gnutls_pubkey_init); + +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) +static BOOL dh_supported; +static void *libgmp_handle; + +MAKE_FUNCPTR(mpz_init); +MAKE_FUNCPTR(mpz_clear); +MAKE_FUNCPTR(mpz_cmp); +MAKE_FUNCPTR(_mpz_cmp_ui); +MAKE_FUNCPTR(mpz_sizeinbase); +MAKE_FUNCPTR(mpz_import); +MAKE_FUNCPTR(mpz_export); +MAKE_FUNCPTR(mpz_mod); +MAKE_FUNCPTR(mpz_powm); +MAKE_FUNCPTR(mpz_sub_ui); +#endif #undef MAKE_FUNCPTR static int compat_gnutls_cipher_tag(gnutls_cipher_hd_t handle, void *tag, size_t tag_size) @@ -398,6 +419,37 @@ static NTSTATUS gnutls_process_attach( void *args ) LOAD_FUNCPTR(gnutls_pubkey_init); #undef LOAD_FUNCPTR +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) +#define LOAD_FUNCPTR_STR(f) #f +#define LOAD_FUNCPTR(f) \ + if (!(p##f = dlsym( libgmp_handle, LOAD_FUNCPTR_STR(f) ))) \ + { \ + ERR( "failed to load %s\n", LOAD_FUNCPTR_STR(f) ); \ + goto fail; \ + } + + if ((libgmp_handle = dlopen( SONAME_LIBGMP, RTLD_NOW ))) + { + LOAD_FUNCPTR(mpz_init); + LOAD_FUNCPTR(mpz_clear); + LOAD_FUNCPTR(mpz_cmp); + LOAD_FUNCPTR(_mpz_cmp_ui); + LOAD_FUNCPTR(mpz_sizeinbase); + LOAD_FUNCPTR(mpz_import); + LOAD_FUNCPTR(mpz_export); + LOAD_FUNCPTR(mpz_mod); + LOAD_FUNCPTR(mpz_powm); + LOAD_FUNCPTR(mpz_sub_ui); + } + else + { + ERR_(winediag)( "failed to load libgmp, no support for DH\n" ); + goto fail; + } +#undef LOAD_FUNCPTR +#undef LOAD_FUNCPTR_STR +#endif + #define LOAD_FUNCPTR_OPT(f) \ if (!(p##f = dlsym( libgnutls_handle, #f ))) \ { \ @@ -457,19 +509,13 @@ static NTSTATUS gnutls_process_attach( void *args ) { WARN("gnutls_dh_params_export_raw not found\n"); } - if (!(pgnutls_dh_generate_key = dlsym( libgnutls_handle, "_gnutls_dh_generate_key" )) - && !(pgnutls_dh_generate_key = dlsym( libgnutls_handle, "gnutls_dh_generate_key" ))) - { - WARN("gnutls_dh_generate_key not found\n"); - } - if (!(pgnutls_dh_compute_key = dlsym( libgnutls_handle, "_gnutls_dh_compute_key" )) - && !(pgnutls_dh_compute_key = dlsym( libgnutls_handle, "gnutls_dh_compute_key" ))) - { - WARN("gnutls_dh_compute_key not found\n"); - } +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) dh_supported = pgnutls_dh_params_init && pgnutls_dh_params_generate2 && pgnutls_dh_params_import_raw2 - && pgnutls_dh_generate_key && pgnutls_dh_compute_key; + && libgmp_handle; +#else + ERR_(winediag)("Compiled without DH support.\n"); +#endif if (TRACE_ON( bcrypt )) { @@ -482,6 +528,14 @@ static NTSTATUS gnutls_process_attach( void *args ) fail: dlclose( libgnutls_handle ); libgnutls_handle = NULL; + +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) + if (libgmp_handle) + { + dlclose( libgmp_handle ); + libgmp_handle = NULL; + } +#endif return STATUS_DLL_NOT_FOUND; } @@ -494,6 +548,11 @@ static NTSTATUS gnutls_process_detach( void *args ) libgnutls_handle = NULL; } return STATUS_SUCCESS; + +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) + dlclose( libgmp_handle ); + libgmp_handle = NULL; +#endif } struct buffer @@ -1029,12 +1088,61 @@ static NTSTATUS key_export_dsa_capi_public( struct key *key, UCHAR *buf, ULONG l return status; } +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) +static NTSTATUS CDECL gen_random(void *buffer, unsigned int length) +{ + unsigned int read_size; + int dev_random; + + dev_random = open("/dev/urandom", O_RDONLY); + if (dev_random == -1) + { + FIXME("couldn't open /dev/urandom.\n"); + return STATUS_INTERNAL_ERROR; + } + + read_size = read(dev_random, buffer, length); + close(dev_random); + if (read_size != length) + { + FIXME("Could not read from /dev/urandom."); + return STATUS_INTERNAL_ERROR; + } + return STATUS_SUCCESS; +} + +static void import_mpz(mpz_t value, const void *input, unsigned int length) +{ + pmpz_import(value, length, 1, 1, 0, 0, input); +} + +static void export_mpz(void *output, unsigned int length, const mpz_t value) +{ + size_t export_length; + unsigned int offset; + + export_length = (pmpz_sizeinbase(value, 2) + 7) / 8; + assert(export_length <= length); + offset = length - export_length; + memset(output, 0, offset); + pmpz_export((BYTE *)output + offset, &export_length, 1, 1, 0, 0, value); + if (!export_length) + { + ERR("Zero export length, value bits %u.\n", (unsigned)pmpz_sizeinbase(value, 2)); + memset((BYTE *)output + offset, 0, length - offset); + } + else + { + assert(export_length + offset == length); + } +} + static NTSTATUS CDECL key_dh_generate( struct key *key ) { - gnutls_datum_t prime, generator, privkey, pubkey; NTSTATUS status = STATUS_SUCCESS; - gnutls_dh_params_t dh_params; + mpz_t p, psub1, g, privkey, pubkey; ULONG key_length; + unsigned int i; int ret; if (!dh_supported) @@ -1043,22 +1151,18 @@ static NTSTATUS CDECL key_dh_generate( struct key *key ) return STATUS_NOT_IMPLEMENTED; } - if ((ret = pgnutls_dh_params_init( &dh_params ))) - { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; - } - key_length = key->u.a.bitlen / 8; if (!(key->u.a.flags & KEY_FLAG_DH_PARAMS_SET)) { - /* Generate parameters, export and then import them back below. - * The bitlen in dh parameters (which is later used for keys generation) - * is not set to gnutls_dh_params_generate2 'bits' parameter as one - * could expect. gnutls_dh_params_generate2 generates 'q' (which is not - * actually needed for DH) with the estimated bit length and then - * sets the bit length to the 'q' bitlength. */ + gnutls_datum_t prime, generator; + gnutls_dh_params_t dh_params; + + if ((ret = pgnutls_dh_params_init( &dh_params ))) + { + pgnutls_perror( ret ); + return STATUS_INTERNAL_ERROR; + } dh_key_alloc( key ); if ((ret = pgnutls_dh_params_generate2( dh_params, key->u.a.bitlen ))) @@ -1073,6 +1177,8 @@ static NTSTATUS CDECL key_dh_generate( struct key *key ) pgnutls_dh_params_deinit( dh_params ); return STATUS_INTERNAL_ERROR; } + pgnutls_dh_params_deinit( dh_params ); + export_gnutls_datum( (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1), key_length, &prime, 1 ); export_gnutls_datum( (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1) + key_length, @@ -1083,34 +1189,73 @@ static NTSTATUS CDECL key_dh_generate( struct key *key ) key->u.a.flags |= KEY_FLAG_DH_PARAMS_SET; } - prime.size = generator.size = key_length; - prime.data = (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1); - generator.data = (BYTE *)((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1) + key_length; + pmpz_init(p); + pmpz_init(psub1); + pmpz_init(g); + pmpz_init(pubkey); + pmpz_init(privkey); - if ((ret = pgnutls_dh_params_import_raw2( dh_params, &prime, &generator, key->u.a.bitlen ))) + import_mpz(p, (BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1, key_length); + if (!mpz_sgn(p)) { - pgnutls_perror( ret ); - pgnutls_dh_params_deinit( dh_params ); - return STATUS_INTERNAL_ERROR; + ERR("Got zero modulus.\n"); + status = STATUS_INTERNAL_ERROR; + goto done; } + pmpz_sub_ui(psub1, p, 1); - if ((ret = pgnutls_dh_generate_key( dh_params, &privkey, &pubkey ))) + import_mpz(g, (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1) + key_length, key_length); + if (!mpz_sgn(g)) { - pgnutls_perror( ret ); - pgnutls_dh_params_deinit( dh_params ); - return STATUS_INTERNAL_ERROR; + ERR("Got zero generator.\n"); + status = STATUS_INTERNAL_ERROR; + goto done; } + for (i = 0; i < 3; ++i) + { + if ((status = gen_random(key_data(key)->d.privkey, key_length))) + { + goto done; + } + import_mpz(privkey, key_data(key)->d.privkey, key_length); - export_gnutls_datum( (BYTE *)((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1) + 2 * key_length, - key_length, &pubkey, 1 ); - export_gnutls_datum( key_data(key)->d.privkey, key_length, &privkey, 1); + pmpz_mod(privkey, privkey, p); + pmpz_powm(pubkey, g, privkey, p); + if (p_mpz_cmp_ui(pubkey, 1)) + break; + } + if (i == 3) + { + ERR("Could not generate key after 3 iterations.\n"); + status = STATUS_INTERNAL_ERROR; + goto done; + } + + if (pmpz_cmp(pubkey, psub1) >= 0) + { + ERR("pubkey > p - 1.\n"); + status = STATUS_INTERNAL_ERROR; + goto done; + } - free( privkey.data ); - free( pubkey.data ); - pgnutls_dh_params_deinit( dh_params ); + export_mpz(key_data(key)->d.privkey, key_length, privkey); + export_mpz((UCHAR *)((BCRYPT_DH_KEY_BLOB *)key_data(key)->d.pubkey + 1) + 2 * key_length, key_length, pubkey); +done: + pmpz_clear(psub1); + pmpz_clear(p); + pmpz_clear(g); + pmpz_clear(pubkey); + pmpz_clear(privkey); return status; } +#else +static NTSTATUS CDECL key_dh_generate( struct key *key ) +{ + ERR("Compiled without DH support.\n"); + return STATUS_NOT_IMPLEMENTED; +} +#endif static NTSTATUS key_asymmetric_generate( void *args ) { @@ -2518,8 +2663,6 @@ static NTSTATUS key_secret_agreement( void *args ) struct secret *secret; struct key *priv_key; struct key *peer_key; - int ret; - priv_key = params->privkey; peer_key = params->pubkey; secret = params->secret; @@ -2527,9 +2670,9 @@ static NTSTATUS key_secret_agreement( void *args ) switch (priv_key->alg_id) { case ALG_ID_DH: +#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) { - gnutls_datum_t prime, generator, priv, peer, secret_datum; - gnutls_dh_params_t dh_params; + mpz_t p, priv, peer, k; ULONG key_length; if (!dh_supported) @@ -2538,51 +2681,46 @@ static NTSTATUS key_secret_agreement( void *args ) return STATUS_NOT_IMPLEMENTED; } - if ((ret = pgnutls_dh_params_init( &dh_params ))) - { - pgnutls_perror( ret ); - return STATUS_INTERNAL_ERROR; - } - key_length = priv_key->u.a.bitlen / 8; - prime.size = generator.size = key_length; - prime.data = (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key_data(priv_key)->d.pubkey + 1); - generator.data = (BYTE *)((BCRYPT_DH_KEY_BLOB *)key_data(priv_key)->d.pubkey + 1) + key_length; - - if ((ret = pgnutls_dh_params_import_raw2( dh_params, &prime, &generator, priv_key->u.a.bitlen ))) - { - pgnutls_perror( ret ); - pgnutls_dh_params_deinit( dh_params ); - return STATUS_INTERNAL_ERROR; - } - - priv.size = peer.size = key_length; - priv.data = key_data(priv_key)->d.privkey; - peer.data = key_data(peer_key)->d.pubkey + sizeof(BCRYPT_DH_KEY_BLOB) + key_length * 2; - if (memcmp((BCRYPT_DH_KEY_BLOB *)key_data(priv_key)->d.pubkey + 1, key_data(peer_key)->d.pubkey + sizeof(BCRYPT_DH_KEY_BLOB), key_length * 2)) { ERR("peer DH paramaters do not match.\n"); - pgnutls_dh_params_deinit( dh_params ); return STATUS_INTERNAL_ERROR; } - if ((ret = pgnutls_dh_compute_key( dh_params, &priv, NULL, &peer, &secret_datum ))) + pmpz_init(p); + pmpz_init(priv); + pmpz_init(peer); + pmpz_init(k); + + import_mpz(p, (BCRYPT_DH_KEY_BLOB *)key_data(priv_key)->d.pubkey + 1, key_length); + if (pmpz_sizeinbase(p, 2) < 2) { - ERR("Error computing shared key.\n"); - pgnutls_perror( ret ); - pgnutls_dh_params_deinit( dh_params ); + ERR("Invalid prime.\n"); + pmpz_clear(p); + pmpz_clear(priv); + pmpz_clear(peer); + pmpz_clear(k); return STATUS_INTERNAL_ERROR; } - - TRACE("secret_datum.size %u, key_length %u.\n", secret_datum.size, (int)key_length); - export_gnutls_datum( secret->data, key_length, &secret_datum, 1 ); + import_mpz(priv, key_data(priv_key)->d.privkey, key_length); + import_mpz(peer, key_data(peer_key)->d.pubkey + sizeof(BCRYPT_DH_KEY_BLOB) + key_length * 2, key_length); + pmpz_powm(k, peer, priv, p); + export_mpz(secret->data, key_length, k); secret->data_len = key_length; - free( secret_datum.data ); + + pmpz_clear(p); + pmpz_clear(priv); + pmpz_clear(peer); + pmpz_clear(k); break; } +#else + ERR_(winediag)("Compiled without DH support.\n"); + return STATUS_NOT_IMPLEMENTED; +#endif case ALG_ID_ECDH_P256: FIXME("ECDH is not supported.\n"); From b1fb742375ee1b0dc0a785be39cf1faa667a87c7 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Tue, 8 Dec 2020 01:43:33 +0300 Subject: [PATCH 0607/2777] bcrypt: Add support for calculating secret ecc keys. (updated by Paul Gofman) For Rainbow 6: Siege. --- configure.ac | 14 +++ dlls/bcrypt/gnutls.c | 228 ++++++++++++++++++++++++++++++++++++- dlls/bcrypt/tests/bcrypt.c | 11 +- 3 files changed, 248 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index c9bc5897f91..68bac283502 100644 --- a/configure.ac +++ b/configure.ac @@ -32,6 +32,7 @@ AC_ARG_WITH(dbus, AS_HELP_STRING([--without-dbus],[do not use DBus (dynamic AC_ARG_WITH(float-abi, AS_HELP_STRING([--with-float-abi=abi],[specify the ABI (soft|softfp|hard) for ARM platforms])) AC_ARG_WITH(fontconfig,AS_HELP_STRING([--without-fontconfig],[do not use fontconfig])) AC_ARG_WITH(freetype, AS_HELP_STRING([--without-freetype],[do not use the FreeType library])) +AC_ARG_WITH(gcrypt, AS_HELP_STRING([--without-gcrypt],[do not use libgcrypt])) AC_ARG_WITH(gettext, AS_HELP_STRING([--without-gettext],[do not use gettext])) AC_ARG_WITH(gettextpo, AS_HELP_STRING([--with-gettextpo],[use the GetTextPO library to rebuild po files]), [if test "x$withval" = "xno"; then ac_cv_header_gettext_po_h=no; fi]) @@ -1810,6 +1811,19 @@ fi WINE_NOTICE_WITH(vulkan,[test "x$ac_cv_lib_soname_vulkan" = "x" -a "x$ac_cv_lib_soname_MoltenVK" = "x"], [libvulkan and libMoltenVK ${notice_platform}development files not found, Vulkan won't be supported.]) +dnl **** Check for gcrypt **** +if test "x$with_gcrypt" != "xno" +then + WINE_PACKAGE_FLAGS(GCRYPT,[libgcrypt],,,, + [AC_CHECK_HEADERS([gcrypt.h]) + if test "$ac_cv_header_gcrypt_h" = "yes" + then + WINE_CHECK_SONAME(gcrypt,gcry_sexp_build,,,[$GCRYPT_LIBS]) + fi]) +fi +WINE_NOTICE_WITH(gcrypt,[test "x$ac_cv_lib_soname_gcrypt" = "x"], + [libgcrypt ${notice_platform}development files not found, GCRYPT won't be supported.]) + dnl **** Check for gcc specific options **** if test "x${GCC}" = "xyes" diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index d0cc55136e1..90c019672a2 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -57,6 +57,10 @@ #include #include +#ifdef HAVE_GCRYPT_H +#include +#endif + WINE_DEFAULT_DEBUG_CHANNEL(bcrypt); WINE_DECLARE_DEBUG_CHANNEL(winediag); @@ -193,6 +197,12 @@ static int (*pgnutls_dh_params_import_raw2)(gnutls_dh_params_t dh_params, const static int (*pgnutls_dh_params_export_raw)(gnutls_dh_params_t params, gnutls_datum_t * prime, gnutls_datum_t * generator, unsigned int *bits); +static int (*pgnutls_ecdh_compute_key)(gnutls_ecc_curve_t curve, + const gnutls_datum_t *x, const gnutls_datum_t *y, + const gnutls_datum_t *k, + const gnutls_datum_t *peer_x, const gnutls_datum_t *peer_y, + gnutls_datum_t *Z); + static void *libgnutls_handle; #define MAKE_FUNCPTR(f) static typeof(f) * p##f @@ -230,6 +240,24 @@ MAKE_FUNCPTR(mpz_mod); MAKE_FUNCPTR(mpz_powm); MAKE_FUNCPTR(mpz_sub_ui); #endif + +#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) +static BOOL gcrypt_available; +static void *libgcrypt_handle; + +MAKE_FUNCPTR(gcry_check_version); +MAKE_FUNCPTR(gcry_sexp_build); +MAKE_FUNCPTR(gcry_pk_encrypt); +MAKE_FUNCPTR(gcry_mpi_new); +MAKE_FUNCPTR(gcry_mpi_print); +MAKE_FUNCPTR(gcry_sexp_release); +MAKE_FUNCPTR(gcry_mpi_release); +MAKE_FUNCPTR(gcry_strsource); +MAKE_FUNCPTR(gcry_strerror); +MAKE_FUNCPTR(gcry_sexp_find_token); +MAKE_FUNCPTR(gcry_sexp_nth_mpi); +#endif + #undef MAKE_FUNCPTR static int compat_gnutls_cipher_tag(gnutls_cipher_hd_t handle, void *tag, size_t tag_size) @@ -450,6 +478,36 @@ static NTSTATUS gnutls_process_attach( void *args ) #undef LOAD_FUNCPTR_STR #endif +#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) +#define LOAD_FUNCPTR(f) \ + if (!(p##f = dlsym( libgcrypt_handle, #f ))) \ + { \ + WARN( "failed to load %s\n", #f ); \ + gcrypt_available = FALSE; \ + } + + if ((libgcrypt_handle = dlopen( SONAME_LIBGCRYPT, RTLD_NOW ))) + { + gcrypt_available = TRUE; + + LOAD_FUNCPTR(gcry_check_version); + LOAD_FUNCPTR(gcry_sexp_build); + LOAD_FUNCPTR(gcry_pk_encrypt); + LOAD_FUNCPTR(gcry_mpi_new); + LOAD_FUNCPTR(gcry_mpi_print); + LOAD_FUNCPTR(gcry_sexp_release); + LOAD_FUNCPTR(gcry_mpi_release); + LOAD_FUNCPTR(gcry_strsource); + LOAD_FUNCPTR(gcry_strerror); + LOAD_FUNCPTR(gcry_sexp_find_token); + LOAD_FUNCPTR(gcry_sexp_nth_mpi); + } + else + WARN("failed to load gcrypt, no support for ECC secret agreement\n"); + +#undef LOAD_FUNCPTR +#endif + #define LOAD_FUNCPTR_OPT(f) \ if (!(p##f = dlsym( libgnutls_handle, #f ))) \ { \ @@ -517,6 +575,12 @@ static NTSTATUS gnutls_process_attach( void *args ) ERR_(winediag)("Compiled without DH support.\n"); #endif + if (!(pgnutls_ecdh_compute_key = dlsym( libgnutls_handle, "_gnutls_ecdh_compute_key" )) + && !(pgnutls_ecdh_compute_key = dlsym( libgnutls_handle, "gnutls_ecdh_compute_key" ))) + { + WARN("gnutls_ecdh_compute_key not found\n"); + } + if (TRACE_ON( bcrypt )) { pgnutls_global_set_log_level( 4 ); @@ -553,6 +617,11 @@ static NTSTATUS gnutls_process_detach( void *args ) dlclose( libgmp_handle ); libgmp_handle = NULL; #endif + +#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) + dlclose( libgcrypt_handle ); + libgcrypt_handle = NULL; +#endif } struct buffer @@ -2657,12 +2726,66 @@ static NTSTATUS key_asymmetric_encrypt( void *args ) return status; } +#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) +static NTSTATUS gcrypt_extract_result_into_secret(gcry_sexp_t result, struct secret *secret) +{ + NTSTATUS status = STATUS_SUCCESS; + gcry_mpi_t fullcoords = NULL; + gcry_sexp_t fragment = NULL; + UCHAR *tmp_buffer = NULL; + gcry_error_t err; + size_t size; + + fragment = pgcry_sexp_find_token( result, "s", 0 ); + if (!fragment) + { + status = STATUS_NO_MEMORY; + goto done; + } + + fullcoords = pgcry_sexp_nth_mpi( fragment, 1, GCRYMPI_FMT_USG ); + if (!fullcoords) + { + status = STATUS_NO_MEMORY; + goto done; + } + + if ((err = pgcry_mpi_print( GCRYMPI_FMT_USG, NULL, 0, &size, fullcoords)) ) + { + ERR("Error = %s/%s.\n", pgcry_strsource( err ), pgcry_strerror( err )); + status = STATUS_INTERNAL_ERROR; + goto done; + } + + tmp_buffer = malloc(size); + if ((err = pgcry_mpi_print( GCRYMPI_FMT_STD, tmp_buffer, size, NULL, fullcoords)) ) + { + ERR( "Error = %s/%s.\n", pgcry_strsource(err), pgcry_strerror(err) ); + status = STATUS_INTERNAL_ERROR; + goto done; + } + + memcpy( secret->data, tmp_buffer + size % 2, size / 2 ); + secret->data_len = size / 2; + +done: + free( tmp_buffer ); + + pgcry_mpi_release( fullcoords ); + pgcry_sexp_release( fragment ); + + return status; +} +#endif + + static NTSTATUS key_secret_agreement( void *args ) { struct key_secret_agreement_params *params = args; struct secret *secret; struct key *priv_key; struct key *peer_key; + priv_key = params->privkey; peer_key = params->pubkey; secret = params->secret; @@ -2723,8 +2846,111 @@ static NTSTATUS key_secret_agreement( void *args ) #endif case ALG_ID_ECDH_P256: - FIXME("ECDH is not supported.\n"); + case ALG_ID_ECDH_P384: +/* this is necessary since GNUTLS doesn't support ECDH public key encryption, maybe we can replace this when it does: + https://github.com/gnutls/gnutls/blob/cdc4fc288d87f91f974aa23b6e8595a53970ce00/lib/nettle/pk.c#L495 */ +#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) + { + gcry_sexp_t xchg_result = NULL; + gcry_sexp_t privkey = NULL; + gcry_sexp_t pubkey = NULL; + const char *pubkey_format; + BCRYPT_ECCKEY_BLOB *h; + UCHAR *privkey_blob; + UCHAR *pubkey_raw; + gcry_error_t err; + ULONG key_length; + NTSTATUS status; + ULONG key_len; + + if (!gcrypt_available) + { + ERR("ECDH secret agreement is not available.\n"); + return STATUS_NOT_IMPLEMENTED; + } + + if (priv_key->alg_id == ALG_ID_ECDH_P256) + { + pubkey_format = "NIST P-256"; + key_length = 32; + } + else if (priv_key->alg_id == ALG_ID_ECDH_P384) + { + pubkey_format = "NIST P-384"; + key_length = 48; + } + else return STATUS_NOT_IMPLEMENTED; + + if (key_length != priv_key->u.a.bitlen / 8) + { + ERR( "Key length mismatch, key->u.a.bitlen %u, key_length %u.\n", (int)priv_key->u.a.bitlen, + (int)key_length ); + return STATUS_INVALID_PARAMETER; + } + + if ((status = key_export_ecc( priv_key, NULL, 0, &key_len ))) + return status; + privkey_blob = malloc( key_len ); + if ((status = key_export_ecc( priv_key, privkey_blob, key_len, &key_len ))) + { + free( privkey_blob ); + return status; + } + + if ((status = key_export_ecc_public( peer_key, NULL, 0, &key_len ))) + return status; + h = malloc( key_len ); + if ((status = key_export_ecc_public( peer_key, (UCHAR *)h, key_len, &key_len ))) + { + free( privkey_blob ); + return status; + } + + /* copy public key into temporary buffer so we can prepend 0x04 (to indicate it is uncompressed) */ + pubkey_raw = malloc( (key_length * 2) + 1 ); + pubkey_raw[0] = 0x04; + memcpy( pubkey_raw + 1, h + 1, key_length * 2 ); + free( h ); + + err = pgcry_sexp_build( &pubkey, NULL, "(key-data(public-key(ecdh(curve %s)(q %b))))", pubkey_format, + (key_length * 2) + 1, pubkey_raw ); + free( pubkey_raw ); + if (err) + { + free( privkey_blob ); + ERR( "Failed to build gcrypt public key. err %s/%s\n", pgcry_strsource( err ), pgcry_strerror( err )); + return STATUS_INTERNAL_ERROR; + } + + err = pgcry_sexp_build( &privkey, NULL, "(data(flags raw)(value %b))", key_length, + privkey_blob + sizeof(BCRYPT_ECCKEY_BLOB) + key_length * 2 ); + free( privkey_blob ); + if (err) + { + pgcry_sexp_release( pubkey ); + return STATUS_INTERNAL_ERROR; + } + err = pgcry_pk_encrypt( &xchg_result, privkey, pubkey ); + pgcry_sexp_release( privkey ); + pgcry_sexp_release( pubkey ); + if (err) + { + ERR( "Failed to perform key exchange. err %s/%s\n", pgcry_strsource( err ), pgcry_strerror( err )); + return STATUS_INTERNAL_ERROR; + } + status = gcrypt_extract_result_into_secret( xchg_result, secret ); + pgcry_sexp_release(xchg_result); + if (status) + { + ERR("Failed to extract secret key.\n"); + return status; + } break; + } +#else + WARN("Compiled without ECC secret support.\n"); + return STATUS_NOT_IMPLEMENTED; +#endif default: ERR( "unhandled algorithm %u\n", priv_key->alg_id ); diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index 3ec20b62175..e17a2aa63bb 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -2843,10 +2843,13 @@ static void test_ECDH(void) win_skip("BCRYPT_KDF_RAW_SECRET not supported\n"); goto raw_secret_end; } - todo_wine ok(status == STATUS_SUCCESS, "got %#lx\n", status); - if (status != STATUS_SUCCESS) goto raw_secret_end; + ok(status == STATUS_SUCCESS, "got %#lx\n", status); ok(size == 32, "size of secret key incorrect, got %lu, expected 32\n", size); + if (!size) + goto raw_secret_end; + + buf = malloc(size); status = BCryptDeriveKey(secret, BCRYPT_KDF_RAW_SECRET, NULL, buf, size, &size, 0); ok(status == STATUS_SUCCESS, "got %#lx\n", status); @@ -2855,14 +2858,14 @@ static void test_ECDH(void) raw_secret_end: status = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, &hash_params, NULL, 0, &size, 0); - todo_wine ok (status == STATUS_SUCCESS, "got %#lx\n", status); + ok (status == STATUS_SUCCESS, "got %#lx\n", status); if (status != STATUS_SUCCESS) goto derive_end; ok (size == 20, "got %lu\n", size); buf = malloc(size); status = BCryptDeriveKey(secret, BCRYPT_KDF_HASH, &hash_params, buf, size, &size, 0); ok(status == STATUS_SUCCESS, "got %#lx\n", status); - todo_wine ok(!(memcmp(hashed_secret, buf, size)), "wrong data\n"); + ok(!(memcmp(hashed_secret, buf, size)), "wrong data\n"); free(buf); /* ulVersion is not verified */ From 1e2eb84a519573bf8b3671310cf4cd1d1526071a Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 1 Oct 2021 14:34:58 +0200 Subject: [PATCH 0608/2777] bcrypt: Add support for OAEP-padded asymmetric key decryption. (updated by Paul Gofman) For DayZ. CW-Bug-Id: #18973 --- dlls/bcrypt/bcrypt_internal.h | 2 + dlls/bcrypt/bcrypt_main.c | 9 +- dlls/bcrypt/gnutls.c | 166 ++++++++++++++++++++++++++++++++++ dlls/bcrypt/tests/bcrypt.c | 9 +- 4 files changed, 174 insertions(+), 12 deletions(-) diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h index f0eaa6ad4fb..6dcf0c3d999 100644 --- a/dlls/bcrypt/bcrypt_internal.h +++ b/dlls/bcrypt/bcrypt_internal.h @@ -253,6 +253,8 @@ struct key_asymmetric_encrypt_params UCHAR *output; ULONG output_len; ULONG *ret_len; + void *padding; + ULONG flags; }; struct key_asymmetric_duplicate_params diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index bcb7a692ffd..af4b5321701 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -715,7 +715,7 @@ static NTSTATUS get_rsa_property( enum chain_mode mode, const WCHAR *prop, UCHAR { *ret_size = sizeof(ULONG); if (size < sizeof(ULONG)) return STATUS_BUFFER_TOO_SMALL; - if (buf) *(ULONG *)buf = BCRYPT_SUPPORTED_PAD_PKCS1_SIG; + if (buf) *(ULONG *)buf = BCRYPT_SUPPORTED_PAD_PKCS1_SIG | BCRYPT_SUPPORTED_PAD_OAEP; return STATUS_SUCCESS; } @@ -2138,11 +2138,6 @@ NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp } else { - if (flags & BCRYPT_PAD_NONE || flags & BCRYPT_PAD_OAEP) - { - FIXME( "flags %#lx not implemented\n", flags ); - return STATUS_NOT_IMPLEMENTED; - } if (!is_asymmetric_encryption_key( key )) return STATUS_NOT_SUPPORTED; asymmetric_params.input = input; @@ -2151,6 +2146,8 @@ NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp asymmetric_params.output = output; asymmetric_params.output_len = output_len; asymmetric_params.ret_len = ret_len; + asymmetric_params.padding = padding; + asymmetric_params.flags = flags; ret = UNIX_CALL(key_asymmetric_encrypt, &asymmetric_params); } diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c index 90c019672a2..fa48159cb6b 100644 --- a/dlls/bcrypt/gnutls.c +++ b/dlls/bcrypt/gnutls.c @@ -256,6 +256,7 @@ MAKE_FUNCPTR(gcry_strsource); MAKE_FUNCPTR(gcry_strerror); MAKE_FUNCPTR(gcry_sexp_find_token); MAKE_FUNCPTR(gcry_sexp_nth_mpi); +MAKE_FUNCPTR(gcry_sexp_nth_data); #endif #undef MAKE_FUNCPTR @@ -501,6 +502,7 @@ static NTSTATUS gnutls_process_attach( void *args ) LOAD_FUNCPTR(gcry_strerror); LOAD_FUNCPTR(gcry_sexp_find_token); LOAD_FUNCPTR(gcry_sexp_nth_mpi); + LOAD_FUNCPTR(gcry_sexp_nth_data); } else WARN("failed to load gcrypt, no support for ECC secret agreement\n"); @@ -2700,6 +2702,167 @@ static NTSTATUS key_asymmetric_decrypt( void *args ) return status; } +#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) +const char * gcrypt_hash_algorithm_name(LPCWSTR alg_id) +{ + if (!wcscmp( alg_id, BCRYPT_SHA1_ALGORITHM )) return "sha1"; + if (!wcscmp( alg_id, BCRYPT_SHA256_ALGORITHM )) return "sha256"; + if (!wcscmp( alg_id, BCRYPT_SHA384_ALGORITHM )) return "sha384"; + if (!wcscmp( alg_id, BCRYPT_SHA512_ALGORITHM )) return "sha512"; + if (!wcscmp( alg_id, BCRYPT_MD2_ALGORITHM )) return "md2"; + if (!wcscmp( alg_id, BCRYPT_MD5_ALGORITHM )) return "md5"; + return NULL; +} + +static NTSTATUS key_asymmetric_encrypt_gcrypt( void *args ) +{ + const struct key_asymmetric_encrypt_params *params = args; + struct key *key = params->key; + UCHAR *input = params->input; + ULONG input_len = params->input_len; + UCHAR *output = params->output; + ULONG *ret_len = params->ret_len; + void *padding = params->padding; + ULONG flags = params->flags; + BCRYPT_OAEP_PADDING_INFO *oaep_info = padding; + NTSTATUS status; + gcry_sexp_t sexp_pubkey = NULL; + gcry_sexp_t sexp_result = NULL; + gcry_sexp_t sexp_input = NULL; + BCRYPT_RSAKEY_BLOB *rsa_blob; + gcry_sexp_t mpi_a = NULL; + const void *result; + size_t result_len; + gcry_error_t err; + ULONG len; + + if (!gcrypt_available) + { + ERR("Asymmetric encryption not available.\n"); + return STATUS_INTERNAL_ERROR; + } + + if (key->alg_id != ALG_ID_RSA) + { + FIXME("Unsupported algorithm id: %u\n", key->alg_id); + return STATUS_INTERNAL_ERROR; + } + + if (flags == BCRYPT_PAD_NONE && input_len != key->u.a.bitlen / 8) + { + WARN( "Invalid input_len %u for BCRYPT_PAD_NONE.\n", (int)input_len ); + return STATUS_INVALID_PARAMETER; + } + + /* import RSA key */ + if ((status = key_export_rsa_public( key, NULL, 0, &len ))) + { + ERR( "Key export failed.\n" ); + return status; + } + rsa_blob = malloc( len ); + if ((status = key_export_rsa_public( key, (UCHAR *)rsa_blob, len, &len ))) + { + ERR( "Key export failed.\n" ); + return status; + } + err = pgcry_sexp_build(&sexp_pubkey, NULL, + "(public-key(rsa (e %b)(n %b)))", + rsa_blob->cbPublicExp, + (UCHAR *)(rsa_blob + 1), + rsa_blob->cbModulus, + (UCHAR *)(rsa_blob + 1) + rsa_blob->cbPublicExp); + free( rsa_blob ); + if (err) + { + ERR("Failed to build gcrypt public key\n"); + goto done; + } + + /* import input data with necessary padding */ + if (flags == BCRYPT_PAD_PKCS1) + { + err = pgcry_sexp_build(&sexp_input, NULL, + "(data(flags pkcs1)(value %b))", + input_len, + input); + } + else if (flags == BCRYPT_PAD_OAEP) + { + if (oaep_info->pbLabel) + err = pgcry_sexp_build(&sexp_input, NULL, + "(data(flags oaep)(hash-algo %s)(label %b)(value %b))", + gcrypt_hash_algorithm_name(oaep_info->pszAlgId), + oaep_info->cbLabel, + oaep_info->pbLabel, + input_len, + input); + else + err = pgcry_sexp_build(&sexp_input, NULL, + "(data(flags oaep)(hash-algo %s)(value %b))", + gcrypt_hash_algorithm_name(oaep_info->pszAlgId), + input_len, + input); + } + else if (flags == BCRYPT_PAD_NONE) + { + err = pgcry_sexp_build(&sexp_input, NULL, + "(data(flags raw)(value %b))", + input_len, + input); + } + else + { + status = STATUS_INVALID_PARAMETER; + goto done; + } + + if (err) + { + ERR("Failed to build gcrypt padded input data\n"); + goto done; + } + + if ((err = pgcry_pk_encrypt(&sexp_result, sexp_input, sexp_pubkey))) + { + ERR("Failed to encrypt data\n"); + goto done; + } + + mpi_a = pgcry_sexp_find_token(sexp_result, "a", 0); + result = pgcry_sexp_nth_data(mpi_a, 1, &result_len); + + *ret_len = result_len; + + if (params->output_len >= result_len) memcpy(output, result, result_len); + else if (params->output_len == 0) status = STATUS_SUCCESS; + else status = STATUS_BUFFER_TOO_SMALL; + +done: + pgcry_sexp_release(sexp_input); + pgcry_sexp_release(sexp_pubkey); + pgcry_sexp_release(sexp_result); + pgcry_sexp_release(mpi_a); + + if (status) + return status; + + if (err) + { + ERR("Error = %s/%s\n", pgcry_strsource (err), pgcry_strerror (err)); + return STATUS_INTERNAL_ERROR; + } + + return STATUS_SUCCESS; +} +#else +static NTSTATUS key_asymmetric_encrypt_gcrypt( void *args ) +{ + ERR("Asymmetric key encryption not supported without gcrypt.\n"); + return STATUS_NOT_IMPLEMENTED; +} +#endif + static NTSTATUS key_asymmetric_encrypt( void *args ) { const struct key_asymmetric_encrypt_params *params = args; @@ -2709,6 +2872,9 @@ static NTSTATUS key_asymmetric_encrypt( void *args ) if (!key_data(params->key)->a.pubkey) return STATUS_INVALID_HANDLE; + if (params->flags == BCRYPT_PAD_NONE || params->flags == BCRYPT_PAD_OAEP) + return key_asymmetric_encrypt_gcrypt( args ); + d.data = params->input; d.size = params->input_len; if ((ret = pgnutls_pubkey_encrypt_data(key_data(params->key)->a.pubkey, 0, &d, &e))) diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index e17a2aa63bb..bc355c6d821 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -2305,7 +2305,6 @@ static void test_rsa_encrypt(void) ret = BCryptImportKeyPair(rsa, NULL, BCRYPT_RSAPRIVATE_BLOB, &key, rsaPrivateBlob, sizeof(rsaPrivateBlob), 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); - todo_wine { /* No padding */ memset(input_no_padding, 0, sizeof(input_no_padding)); strcpy((char *)input_no_padding, "Hello World"); @@ -2334,9 +2333,8 @@ static void test_rsa_encrypt(void) BCryptDecrypt(key, encrypted_a, encrypted_size, NULL, NULL, 0, NULL, 0, &decrypted_size, BCRYPT_PAD_NONE); decrypted = malloc(decrypted_size); BCryptDecrypt(key, encrypted_a, encrypted_size, NULL, NULL, 0, decrypted, decrypted_size, &decrypted_size, BCRYPT_PAD_NONE); - ok(!memcmp(decrypted, input_no_padding, sizeof(input_no_padding)), "Decrypted output it's not what expected\n"); + todo_wine ok(!memcmp(decrypted, input_no_padding, sizeof(input_no_padding)), "Decrypted output it's not what expected\n"); free(decrypted); - } encrypted_size = 60; /* PKCS1 Padding */ @@ -2362,7 +2360,6 @@ static void test_rsa_encrypt(void) ok(!memcmp(decrypted, input, sizeof(input)), "Decrypted output it's not what expected\n"); free(decrypted); - todo_wine { encrypted_size = 60; /* OAEP Padding */ ret = BCryptEncrypt(key, input, sizeof(input), &oaep_pad, NULL, 0, NULL, 0, &encrypted_size, BCRYPT_PAD_OAEP); @@ -2383,8 +2380,8 @@ static void test_rsa_encrypt(void) BCryptDecrypt(key, encrypted_a, encrypted_size, &oaep_pad, NULL, 0, NULL, 0, &decrypted_size, BCRYPT_PAD_OAEP); decrypted = malloc(decrypted_size); BCryptDecrypt(key, encrypted_a, encrypted_size, &oaep_pad, NULL, 0, decrypted, decrypted_size, &decrypted_size, BCRYPT_PAD_OAEP); - ok(!memcmp(decrypted, input, sizeof(input)), "Decrypted output it's not what expected\n"); - } + todo_wine ok(!memcmp(decrypted, input, sizeof(input)), "Decrypted output it's not what expected\n"); + free(decrypted); free(encrypted_a); From 32a1156ebb6f76dd04f9c982d196a79a46871ff0 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Sun, 10 Oct 2021 20:53:45 +0200 Subject: [PATCH 0609/2777] HACK: winex11.drv: Workaround issue with Into The Breach fullscreen mode. --- dlls/winex11.drv/event.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 48c62f64ee6..f53ddcbdf55 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1233,6 +1233,21 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) /* Compare what has changed */ + { + const char *steamgameid = getenv( "SteamGameId" ); + + if (steamgameid && !strcmp( steamgameid, "590380" )) + { + /* Into The Breach is extremely picky about the size of its window. */ + if (NtUserIsWindowRectFullScreen( &data->whole_rect ) && NtUserIsWindowRectFullScreen( &rect )) + { + TRACE( "window is fullscreen and new size is also fullscreen, so preserving window size\n" ); + rect.right = rect.left + (data->whole_rect.right - data->whole_rect.left); + rect.bottom = rect.top + (data->whole_rect.bottom - data->whole_rect.top); + } + } + } + x = rect.left; y = rect.top; cx = rect.right - rect.left; From 216369590b7cef69774cc6b4e9758c7563aed5ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 14 Dec 2022 21:21:50 +0100 Subject: [PATCH 0610/2777] HACK: winex11.drv: Workaround focusing out of exclusive fullscreen windows. This retargets some old window manager workarounds which don't seem to be required anymore for the original issues but is still necessary to be able to focus out of exclusive fullscreen windows. Original commits were: commit e35f70c300b8f59e1d45e7c9d7b3b93d55741955 Author: Andrew Eikum Date: Tue Sep 18 08:11:59 2018 -0500 winex11: Don't set ABOVE on minimized fullscreened windows This is a workaround for mutter bug #306. commit 41022f9151475da15ec64a2ac64fd4830253e3f5 Author: Andrew Eikum Date: Mon Jun 1 09:18:35 2020 -0500 winex11.drv: Don't set ABOVE for fullscreen windows on KDE --- dlls/winex11.drv/window.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 755e725fbdb..8b92a944aaa 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1202,7 +1202,15 @@ void update_net_wm_states( struct x11drv_win_data *data ) new_state |= (1 << NET_WM_STATE_MAXIMIZED); ex_style = NtUserGetWindowLongW( data->hwnd, GWL_EXSTYLE ); - if (ex_style & WS_EX_TOPMOST) + if ((ex_style & WS_EX_TOPMOST) && + /* This workaround was initially targetting some mutter and KDE issues, but + * removing it causes failure to focus out from exclusive fullscreen windows. + * + * Many games do not have any specific logic to get out of exclusive fullscreen + * mode, and we have currently no way to tell exclusive fullscreen from a window + * with topmost + fullscreen styles, so we cannot properly implement it either. + */ + !(new_state & (1 << NET_WM_STATE_FULLSCREEN))) new_state |= (1 << NET_WM_STATE_ABOVE); if (!data->add_taskbar) { From f0fff8f52a7406b13bffd5fedc15fbbd252fb85e Mon Sep 17 00:00:00 2001 From: Kai Krakow Date: Sun, 10 Oct 2021 20:48:24 +0200 Subject: [PATCH 0611/2777] winex11.drv: Bypass compositor in fullscreen mode. Bypass the compositor in fullscreen mode. This reduces stutter introduced by window updates in the background and also allows for maybe a few more FPS. To not change the visual appearance of the desktop for windowed games, this hack only enables itself when the game was switched to fullscreen mode, and returns to default WM setting when the game leaves fullscreen mode. Compositors tend to cause severe stutter if the game is GPU-bound. --- dlls/winex11.drv/window.c | 7 +++++++ dlls/winex11.drv/x11drv.h | 1 + dlls/winex11.drv/x11drv_main.c | 1 + 3 files changed, 9 insertions(+) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 8b92a944aaa..66abe4e0373 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1184,6 +1184,7 @@ static void update_net_wm_fullscreen_monitors( struct x11drv_win_data *data ) void update_net_wm_states( struct x11drv_win_data *data ) { UINT i, style, ex_style, new_state = 0; + unsigned long net_wm_bypass_compositor = 0; if (!data->managed) return; if (data->whole_window == root_window) return; @@ -1196,7 +1197,10 @@ void update_net_wm_states( struct x11drv_win_data *data ) if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION) new_state |= (1 << NET_WM_STATE_MAXIMIZED); else if (!(style & WS_MINIMIZE)) + { + net_wm_bypass_compositor = 1; new_state |= (1 << NET_WM_STATE_FULLSCREEN); + } } else if (style & WS_MAXIMIZE) new_state |= (1 << NET_WM_STATE_MAXIMIZED); @@ -1274,6 +1278,9 @@ void update_net_wm_states( struct x11drv_win_data *data ) } data->net_wm_state = new_state; update_net_wm_fullscreen_monitors( data ); + + XChangeProperty( data->display, data->whole_window, x11drv_atom(_NET_WM_BYPASS_COMPOSITOR), XA_CARDINAL, + 32, PropModeReplace, (unsigned char *)&net_wm_bypass_compositor, 1 ); } /*********************************************************************** diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 998cd411d0d..3839b4ded0c 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -499,6 +499,7 @@ enum x11drv_atoms XATOM__NET_SYSTEM_TRAY_OPCODE, XATOM__NET_SYSTEM_TRAY_S0, XATOM__NET_SYSTEM_TRAY_VISUAL, + XATOM__NET_WM_BYPASS_COMPOSITOR, XATOM__NET_WM_FULLSCREEN_MONITORS, XATOM__NET_WM_ICON, XATOM__NET_WM_MOVERESIZE, diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index d115fdf8dc9..9942a5428b9 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -169,6 +169,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = "_NET_SYSTEM_TRAY_OPCODE", "_NET_SYSTEM_TRAY_S0", "_NET_SYSTEM_TRAY_VISUAL", + "_NET_WM_BYPASS_COMPOSITOR", "_NET_WM_FULLSCREEN_MONITORS", "_NET_WM_ICON", "_NET_WM_MOVERESIZE", From 3ad9c46f556ce7088b9b21367eb793bbcfdca1f7 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Mon, 6 Apr 2020 15:30:40 +0800 Subject: [PATCH 0612/2777] winex11.drv: Bypass compositor only when a window is full virtual screen. Bypass compositor only when a window is full virtual screen. Otherwise, it might cause flicking on other monitors. Signed-off-by: Zhiyi Zhang --- dlls/winex11.drv/window.c | 10 +++++++++- dlls/winex11.drv/x11drv.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 66abe4e0373..9e24e3a1634 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -388,6 +388,13 @@ static inline BOOL is_window_resizable( struct x11drv_win_data *data, DWORD styl return NtUserIsWindowRectFullScreen( &data->whole_rect ); } +BOOL is_window_rect_full_virtual_screen( const RECT *rect ) +{ + RECT virtual_rect = NtUserGetVirtualScreenRect(); + return (rect->left <= virtual_rect.left && rect->right >= virtual_rect.right && + rect->top <= virtual_rect.top && rect->bottom >= virtual_rect.bottom); +} + /*********************************************************************** * get_mwm_decorations */ @@ -1198,7 +1205,8 @@ void update_net_wm_states( struct x11drv_win_data *data ) new_state |= (1 << NET_WM_STATE_MAXIMIZED); else if (!(style & WS_MINIMIZE)) { - net_wm_bypass_compositor = 1; + if (is_window_rect_full_virtual_screen( &data->whole_rect )) + net_wm_bypass_compositor = 1; new_state |= (1 << NET_WM_STATE_FULLSCREEN); } } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 3839b4ded0c..7afd4b6287f 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -721,6 +721,7 @@ typedef int (*x11drv_error_callback)( Display *display, XErrorEvent *event, void extern void X11DRV_expect_error( Display *display, x11drv_error_callback callback, void *arg ) DECLSPEC_HIDDEN; extern int X11DRV_check_error(void) DECLSPEC_HIDDEN; extern void X11DRV_X_to_window_rect( struct x11drv_win_data *data, RECT *rect, int x, int y, int cx, int cy ) DECLSPEC_HIDDEN; +extern BOOL is_window_rect_full_virtual_screen( const RECT *rect ) DECLSPEC_HIDDEN; extern POINT virtual_screen_to_root( INT x, INT y ) DECLSPEC_HIDDEN; extern POINT root_to_virtual_screen( INT x, INT y ) DECLSPEC_HIDDEN; extern RECT get_host_primary_monitor_rect(void) DECLSPEC_HIDDEN; From fbe2072413c2c5498e5c15f5365089b18a32000b Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Tue, 26 May 2020 22:36:07 +0800 Subject: [PATCH 0613/2777] winex11.drv: Do not move window with _NET_WM_STATE_FULLSCREEN set. Signed-off-by: Zhiyi Zhang --- dlls/winex11.drv/window.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 9e24e3a1634..ffe917156a6 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1515,8 +1515,8 @@ static HWND sync_window_position( struct x11drv_win_data *data, { DWORD style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); DWORD ex_style = NtUserGetWindowLongW( data->hwnd, GWL_EXSTYLE ); - HWND prev_window = NULL; RECT original_rect = {0}; + HWND prev_window = NULL; XWindowChanges changes; unsigned int mask = 0; @@ -1561,10 +1561,21 @@ static HWND sync_window_position( struct x11drv_win_data *data, set_size_hints( data, style ); set_mwm_hints( data, style, ex_style ); + /* KWin doesn't allow moving a window with _NET_WM_STATE_FULLSCREEN set. So we need to remove + * _NET_WM_STATE_FULLSCREEN before moving the window and restore it later */ + if (wm_is_kde( data->display ) && NtUserIsWindowRectFullScreen( &data->whole_rect )) + { + original_rect = data->whole_rect; + SetRectEmpty( &data->whole_rect ); + } update_net_wm_states( data ); data->configure_serial = NextRequest( data->display ); XReconfigureWMWindow( data->display, data->whole_window, data->vis.screen, mask, &changes ); - + if (!IsRectEmpty( &original_rect )) + { + data->whole_rect = original_rect; + update_net_wm_states( data ); + } #ifdef HAVE_LIBXSHAPE if (IsRectEmpty( old_window_rect ) != IsRectEmpty( &data->window_rect )) sync_window_region( data, (HRGN)1 ); From 17818437e4f7e97d21dafa5acac31c3e21db4fd4 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Wed, 11 Nov 2020 10:41:42 +0800 Subject: [PATCH 0614/2777] winex11.drv: Call XIconifyWindow() after XMapWindow() with a minimized window. Mutter always unminimizes a window when handling map requests. So a window could be in normal state as far as Mutter concerns while Wine mistakenly considers it still minimized. Fix Disgaea PC black screen after Alt+Tab in fullscreen mode. CW-Bug-Id: #18364 Signed-off-by: Zhiyi Zhang --- dlls/winex11.drv/window.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index ffe917156a6..6d63df67a8f 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1373,6 +1373,9 @@ static void map_window( HWND hwnd, DWORD new_style ) update_net_wm_states( data ); sync_window_style( data ); XMapWindow( data->display, data->whole_window ); + /* Mutter always unminimizes windows when handling map requests. Restore iconic state */ + if (new_style & WS_MINIMIZE) + XIconifyWindow( data->display, data->whole_window, data->vis.screen ); XFlush( data->display ); if (data->surface && data->vis.visualid != default_visual.visualid) data->surface->funcs->flush( data->surface ); @@ -2999,9 +3002,17 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, data->iconic = (new_style & WS_MINIMIZE) != 0; TRACE( "changing win %p iconic state to %u\n", data->hwnd, data->iconic ); if (data->iconic) + { XIconifyWindow( data->display, data->whole_window, data->vis.screen ); + } else if (is_window_rect_mapped( rectWindow )) + { + /* whole_window could be both iconic and mapped. Since XMapWindow() doesn't do + * anything if the window is already mapped, we need to unmap it first */ + if (data->mapped) + XUnmapWindow( data->display, data->whole_window ); XMapWindow( data->display, data->whole_window ); + } update_net_wm_states( data ); } else From f55471e0a4f07e857c310eea44dbe2fc69491799 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 1 Mar 2022 22:11:17 +0300 Subject: [PATCH 0615/2777] winex11.drv: Generate EDID if one is not available from xrandr. CW-Bug-Id: #20204 CW-Bug-Id: #19217 --- dlls/winex11.drv/xrandr.c | 110 ++++++++++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 11 deletions(-) diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c index 1c106c4f985..c24b36729f0 100644 --- a/dlls/winex11.drv/xrandr.c +++ b/dlls/winex11.drv/xrandr.c @@ -39,6 +39,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(xrandr); #include #include #include +#include #include "x11drv.h" #define VK_NO_PROTOTYPES @@ -446,23 +447,108 @@ static void get_screen_size( XRRScreenResources *resources, unsigned int *width, } } -static unsigned int get_edid( RROutput output, unsigned char **prop ) +static unsigned int get_edid( RROutput output, unsigned char **prop, + XRROutputInfo *output_info, XRRScreenResources *screen_resources ) { - int result, actual_format; + unsigned int mwidth, mheight, i; unsigned long bytes_after, len; + unsigned char *edid, *p, c; + int result, actual_format; + XRRModeInfo *mode; Atom actual_type; + *prop = NULL; result = pXRRGetOutputProperty( gdi_display, output, x11drv_atom(EDID), 0, 128, FALSE, FALSE, AnyPropertyType, &actual_type, &actual_format, &len, - &bytes_after, prop ); + &bytes_after, &edid ); + if (result == Success && len) + { + if (!(*prop = malloc( len ))) + { + XFree( edid ); + return 0; + } + memcpy( *prop, edid, len ); + return len; + } - if (result != Success) + WARN( "Could not retrieve EDID property for output %#lx.\n", output ); + if (!output_info->npreferred) { - WARN("Could not retrieve EDID property for output %#lx.\n", output); - *prop = NULL; + WARN( "No preferred modes for output %#lx.\n", output ); return 0; } - return len; + if (output_info->npreferred > 1) + WARN( "%u preferred modes for output %#lx, using first one.\n", output_info->npreferred, output ); + + for (i = 0; i < screen_resources->nmode; ++i) + if (screen_resources->modes[i].id == output_info->modes[0]) break; + + if (i == screen_resources->nmode) + { + ERR("Preferred mode not found for output %#lx.\n", output); + return 0; + } + + mode = &screen_resources->modes[i]; + + mwidth = mode->width / 60; /* Fake ~150dpi. */ + mheight = mode->height / 60; + + edid = calloc( 1, 128 ); + *prop = edid; + *(uint64_t *)edid = 0x00ffffffffffff00; + edid[18] = 1; + edid[19] = 4; + edid[20] = 0xa0; /* Digital input, 8 bit depth. */ + edid[21] = mwidth; + edid[22] = mheight; + edid[24] = 0x6; + for (i = 0; i < 16; ++i) edid[38 + i] = 1; + + p = edid + 54; + *(uint16_t *)&p[0] = mode->dotClock / 10000; + p[2] = mode->width; + p[3] = mode->hTotal - mode->width; + p[4] = (((mode->hTotal - mode->width) >> 8) & 0xf) | (((mode->width >> 8) & 0xf) << 4); + p[5] = mode->height; + p[6] = mode->vTotal - mode->height; + p[7] = (((mode->vTotal - mode->height) >> 8) & 0xf) | (((mode->height >> 8) & 0xf) << 4); + p[8] = mode->hSyncStart - mode->width; + p[9] = mode->hSyncEnd - mode->hSyncStart; + p[10] = (((mode->vSyncStart - mode->height) & 0xf) << 4) | ((mode->vSyncEnd - mode->vSyncStart) & 0xf); + p[11] = ((((mode->hSyncStart - mode->width) >> 8) & 3) << 6) + | ((((mode->hSyncEnd - mode->hSyncStart) >> 8) & 3) << 4) + | ((((mode->vSyncStart - mode->height) >> 4) & 3) << 2) + | (((mode->vSyncEnd - mode->vSyncStart) >> 4) & 3); + p[12] = mwidth; + p[13] = mheight; + p[14] = (((mwidth >> 8) & 0xf) << 4) | ((mheight >> 8) & 0xf); + if (mode->modeFlags & RR_Interlace) + p[17] |= 0x80; + p[17] |= 3 << 3; + if (mode->modeFlags & RR_HSyncPositive) + p[17] |= 2; + if (mode->modeFlags & RR_VSyncPositive) + p[17] |= 4; + + if (mode->modeFlags & (RR_DoubleScan | RR_PixelMultiplex | RR_DoubleClock | RR_ClockDivideBy2)) + FIXME( "Unsupported flags %#lx.\n", mode->modeFlags ); + + p += 18; + p[3] = 0xfc; + strcpy( (char *)p + 5, "Default" ); + + p += 18; + p[3] = 0x10; + p += 18; + p[3] = 0x10; + + c = 0; + for (i = 0; i < 127; ++i) + c += edid[i]; + edid[127] = 256 - c; + return 128; } static void set_screen_size( int width, int height ) @@ -1054,7 +1140,8 @@ static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **ne { lstrcpyW( monitors[monitor_count].name, generic_nonpnp_monitorW ); monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED; - monitors[monitor_count].edid_len = get_edid( adapter_id, &monitors[monitor_count].edid ); + monitors[monitor_count].edid_len = get_edid( adapter_id, &monitors[monitor_count].edid, + output_info, screen_resources ); monitor_count = 1; } /* Active monitors, need to find other monitors with the same coordinates as mirrored */ @@ -1112,7 +1199,8 @@ static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **ne primary_index = monitor_count; monitors[monitor_count].edid_len = get_edid( screen_resources->outputs[i], - &monitors[monitor_count].edid ); + &monitors[monitor_count].edid, + enum_output_info, screen_resources ); monitor_count++; } @@ -1156,7 +1244,7 @@ static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **ne for (i = 0; i < monitor_count; i++) { if (monitors[i].edid) - XFree( monitors[i].edid ); + free( monitors[i].edid ); } free( monitors ); ERR("Failed to get monitors\n"); @@ -1171,7 +1259,7 @@ static void xrandr14_free_monitors( struct gdi_monitor *monitors, int count ) for (i = 0; i < count; i++) { if (monitors[i].edid) - XFree( monitors[i].edid ); + free( monitors[i].edid ); } free( monitors ); } From a4b87091305879f6c2e49dbb83cd9f92ff45210c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 9 Jun 2022 13:52:21 -0500 Subject: [PATCH 0616/2777] winex11.drv: HACK: Add timeout for unmap_notify wait in set_mwm_hints(). This is a change to the old hack: "HACK: mutter: winex11.drv: Workaround mutter issue #649." In case the earlier messages have not been processed yet the wait may hang forever. An example of such sequence is hiding a window and then changing (possible another window's) styles without pumping messages in between. Indirectly related to Bug #20769, Bug #16369. CW-Bug-Id: #20769 CW-Bug-Id: #16369 --- dlls/winex11.drv/window.c | 41 +++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 6d63df67a8f..f9529a1c83a 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -26,6 +26,7 @@ #include "config.h" +#include #include #include #include @@ -844,12 +845,21 @@ static void set_size_hints( struct x11drv_win_data *data, DWORD style ) XFree( size_hints ); } +struct is_unmap_notify_param +{ + struct x11drv_win_data *data; + BOOL found; +}; + static Bool is_unmap_notify( Display *display, XEvent *event, XPointer arg ) { - struct x11drv_win_data *data = (struct x11drv_win_data *)arg; - return event->xany.serial >= data->unmapnotify_serial && - event->xany.window == data->whole_window && - event->type == UnmapNotify; + struct is_unmap_notify_param *p = (struct is_unmap_notify_param *)arg; + + if (!p->found) + p->found = event->type == UnmapNotify && + event->xany.serial >= p->data->unmapnotify_serial && + event->xany.window == p->data->whole_window; + return False; } /*********************************************************************** @@ -911,18 +921,33 @@ static void set_mwm_hints( struct x11drv_win_data *data, UINT style, UINT ex_sty x11drv_atom(_MOTIF_WM_HINTS), 32, PropModeReplace, (unsigned char*)&mwm_hints, sizeof(mwm_hints)/sizeof(long) ); - if (enable_mutter_workaround) + if (enable_mutter_workaround && mapped) { + DWORD end = NtGetTickCount() + 100; + struct is_unmap_notify_param p; + struct pollfd pfd; XEvent event; + int timeout; /* workaround for mutter gitlab bug #649, wait for the map notify * event each time the decorations are modified before modifying * them again. */ - if (mapped) + p.data = data; + p.found = FALSE; + TRACE("workaround mutter bug #649, waiting for UnmapNotify\n"); + pfd.fd = ConnectionNumber(data->display); + pfd.events = POLLIN; + for (;;) { - TRACE("workaround mutter bug #649, waiting for UnmapNotify\n"); - XPeekIfEvent( data->display, &event, is_unmap_notify, (XPointer)data ); + XCheckIfEvent( data->display, &event, is_unmap_notify, (XPointer)&p ); + if (p.found) break; + timeout = end - NtGetTickCount(); + if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1) + { + WARN( "window %p/%lx unmap_notify wait timed out.\n", data->hwnd, data->whole_window ); + break; + } } } From 9a11330a06fac8d8f973cc25a6be1a79308eea18 Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Sat, 11 Dec 2021 12:38:26 +0100 Subject: [PATCH 0617/2777] HACK: winevulkan: Add vkGetPhysicalDeviceProperties thunks to fake NVIDIA PCI IDs as AMD Needed for RDR2 with NVIDIA cards, otherwise game crashes or gets stuck trying to load nvapi64.dll --- dlls/winevulkan/loader.c | 50 +++++++++++++++++++++++++++++++++ dlls/winevulkan/make_vulkan | 1 + dlls/winevulkan/vulkan_loader.h | 3 ++ 3 files changed, 54 insertions(+) diff --git a/dlls/winevulkan/loader.c b/dlls/winevulkan/loader.c index 19fd240f0cb..fa5fd3d3020 100644 --- a/dlls/winevulkan/loader.c +++ b/dlls/winevulkan/loader.c @@ -430,6 +430,32 @@ static void fill_luid_property(VkPhysicalDeviceProperties2 *properties2) device_node_mask); } +void WINAPI vkGetPhysicalDeviceProperties(VkPhysicalDevice physical_device, + VkPhysicalDeviceProperties *properties) +{ + struct vkGetPhysicalDeviceProperties_params params; + NTSTATUS status; + + TRACE("%p, %p\n", physical_device, properties); + + params.physicalDevice = physical_device; + params.pProperties = properties; + status = UNIX_CALL(vkGetPhysicalDeviceProperties, ¶ms); + assert(!status); + + { + const char *sgi = getenv("WINE_HIDE_NVIDIA_GPU"); + if (sgi && *sgi != '0') + { + if (properties->vendorID == 0x10de /* NVIDIA */) + { + properties->vendorID = 0x1002; /* AMD */ + properties->deviceID = 0x67df; /* RX 480 */ + } + } + } +} + void WINAPI vkGetPhysicalDeviceProperties2(VkPhysicalDevice phys_dev, VkPhysicalDeviceProperties2 *properties2) { @@ -443,6 +469,18 @@ void WINAPI vkGetPhysicalDeviceProperties2(VkPhysicalDevice phys_dev, status = UNIX_CALL(vkGetPhysicalDeviceProperties2, ¶ms); assert(!status); fill_luid_property(properties2); + + { + const char *sgi = getenv("WINE_HIDE_NVIDIA_GPU"); + if (sgi && *sgi != '0') + { + if (properties2->properties.vendorID == 0x10de /* NVIDIA */) + { + properties2->properties.vendorID = 0x1002; /* AMD */ + properties2->properties.deviceID = 0x67df; /* RX 480 */ + } + } + } } void WINAPI vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice phys_dev, @@ -458,6 +496,18 @@ void WINAPI vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice phys_dev, status = UNIX_CALL(vkGetPhysicalDeviceProperties2KHR, ¶ms); assert(!status); fill_luid_property(properties2); + + { + const char *sgi = getenv("WINE_HIDE_NVIDIA_GPU"); + if (sgi && *sgi != '0') + { + if (properties2->properties.vendorID == 0x10de /* NVIDIA */) + { + properties2->properties.vendorID = 0x1002; /* AMD */ + properties2->properties.deviceID = 0x67df; /* RX 480 */ + } + } + } } VkResult WINAPI vkCreateDevice(VkPhysicalDevice phys_dev, const VkDeviceCreateInfo *create_info, diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 8850ab11c64..3e53cd9ffff 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -199,6 +199,7 @@ FUNCTION_OVERRIDES = { "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, + "vkGetPhysicalDeviceProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE}, "vkGetPhysicalDeviceProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE}, "vkGetPhysicalDeviceProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE}, diff --git a/dlls/winevulkan/vulkan_loader.h b/dlls/winevulkan/vulkan_loader.h index 24052c8690d..24be960e4c3 100644 --- a/dlls/winevulkan/vulkan_loader.h +++ b/dlls/winevulkan/vulkan_loader.h @@ -20,6 +20,9 @@ #ifndef __WINE_VULKAN_LOADER_H #define __WINE_VULKAN_LOADER_H +#include +#include + #include "ntstatus.h" #define WIN32_NO_STATUS #include From 75bb972ae218a67a7a70f7157f6c5a9bd861392a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 12:55:42 +0100 Subject: [PATCH 0618/2777] HACK: winex11: Support faking AMD PCI IDs for NVIDIA cards --- dlls/winex11.drv/display.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c index a68e5a9671f..96cb1d6369d 100644 --- a/dlls/winex11.drv/display.c +++ b/dlls/winex11.drv/display.c @@ -575,6 +575,18 @@ BOOL X11DRV_UpdateDisplayDevices( const struct gdi_device_manager *device_manage for (gpu = 0; gpu < gpu_count; gpu++) { + { + const char *sgi = getenv("WINE_HIDE_NVIDIA_GPU"); + if (sgi && *sgi != '0') + { + if (gpus[gpu].vendor_id == 0x10de /* NVIDIA */) + { + gpus[gpu].vendor_id = 0x1002; /* AMD */ + gpus[gpu].device_id = 0x67df; /* RX 480 */ + } + } + } + device_manager->add_gpu( &gpus[gpu], param ); /* Initialize adapters */ From cc5abf894a82b7dd14e0732125085f8b698cf8e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 12:57:48 +0100 Subject: [PATCH 0619/2777] winex11.drv: Add a GPU for each Vulkan device that was not tied to an XRandR provider. This assures that each Vulkan device has a LUID assigned (see X11DRV_InitGpu and VkPhysicalDeviceIDProperties). LUIDs are important for DirectX <-> Vulkan interop. VKD3D-Proton and DXVK's DXGI use that to identify which underlaying Vulkan device to use for the selected adapter. This change fixes GPU selection in Hitman 2 in DX12 mode. Without it VKD3D-Proton resorts to a heuristic (vid/pid matching, and if that fails use the first device in enumeration order) which can select the wrong one on some multi-GPU Nvidia setups due to nvapihack. This also fixes Forza Horizon 4 on Wayland as XWayland doesn't expose providers which results in missing LUIDs even for the GPU driving the outputs. CW-Bug-Id: #18737 CW-Bug-Id: #18925 --- dlls/winex11.drv/xrandr.c | 149 +++++++++++++++++++++++++++++++++++--- 1 file changed, 139 insertions(+), 10 deletions(-) diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c index c24b36729f0..fd2b759e822 100644 --- a/dlls/winex11.drv/xrandr.c +++ b/dlls/winex11.drv/xrandr.c @@ -700,6 +700,113 @@ static BOOL is_crtc_primary( RECT primary, const XRRCrtcInfo *crtc ) crtc->y + crtc->height == primary.bottom; } +static void add_remaining_gpus_via_vulkan( struct gdi_gpu **gpus, int *count ) +{ + static const char *extensions[] = + { + VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, + }; + const struct vulkan_funcs *vulkan_funcs = get_vulkan_driver( WINE_VULKAN_DRIVER_VERSION ); + PFN_vkGetPhysicalDeviceProperties2KHR pvkGetPhysicalDeviceProperties2KHR; + PFN_vkEnumeratePhysicalDevices pvkEnumeratePhysicalDevices; + uint32_t device_count; + VkPhysicalDevice *vk_physical_devices = NULL; + VkPhysicalDeviceProperties2 properties2; + VkInstanceCreateInfo create_info; + VkPhysicalDeviceIDProperties id; + VkInstance vk_instance = NULL; + INT gpu_idx, device_idx; + INT original_gpu_count = *count; + struct gdi_gpu *new_gpu; + BOOL new; + VkResult vr; + + memset( &create_info, 0, sizeof(create_info) ); + create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + create_info.enabledExtensionCount = ARRAY_SIZE(extensions); + create_info.ppEnabledExtensionNames = extensions; + vr = vulkan_funcs->p_vkCreateInstance( &create_info, NULL, &vk_instance ); + + if (vr != VK_SUCCESS) + { + WARN("Failed to create a Vulkan instance, vr %d.\n", vr); + goto done; + } + +#define LOAD_VK_FUNC(f) \ + if (!(p##f = (void *)vulkan_funcs->p_vkGetInstanceProcAddr( vk_instance, #f ))) \ + { \ + WARN("Failed to load " #f ".\n"); \ + goto done; \ + } + + LOAD_VK_FUNC(vkEnumeratePhysicalDevices) + LOAD_VK_FUNC(vkGetPhysicalDeviceProperties2KHR) +#undef LOAD_VK_FUNC + + vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, NULL ); + if (vr != VK_SUCCESS || !device_count) + { + WARN("No Vulkan device found, vr %d, device_count %d.\n", vr, device_count); + goto done; + } + + if (!(vk_physical_devices = calloc( device_count, sizeof(*vk_physical_devices) ))) + goto done; + + vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, vk_physical_devices ); + if (vr != VK_SUCCESS) + { + WARN("vkEnumeratePhysicalDevices failed, vr %d.\n", vr); + goto done; + } + + for (device_idx = 0; device_idx < device_count; ++device_idx) + { + memset( &id, 0, sizeof(id) ); + id.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES; + properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + properties2.pNext = &id; + + pvkGetPhysicalDeviceProperties2KHR( vk_physical_devices[device_idx], &properties2 ); + + /* Ignore Khronos vendor IDs */ + if (properties2.properties.vendorID >= 0x10000) + continue; + + new = TRUE; + for (gpu_idx = 0; gpu_idx < original_gpu_count; ++gpu_idx) + { + if (!memcmp( &(*gpus)[gpu_idx].vulkan_uuid, id.deviceUUID, sizeof(id.deviceUUID) )) + { + new = FALSE; + break; + } + } + + if (!new) + continue; + + *gpus = realloc( *gpus, (*count + 1) * sizeof(**gpus) ); + if (!gpus) goto done; + new_gpu = &(*gpus)[(*count)++]; + memset( new_gpu, 0, sizeof(*new_gpu) ); + new_gpu->id = -1; + + memcpy( &new_gpu->vulkan_uuid, id.deviceUUID, sizeof(id.deviceUUID) ); + new_gpu->vendor_id = properties2.properties.vendorID; + new_gpu->device_id = properties2.properties.deviceID; + ntdll_umbstowcs( properties2.properties.deviceName, -1, new_gpu->name, ARRAY_SIZE(new_gpu->name) ); + + TRACE("Added a new GPU via Vulkan: %04x:%04x %s\n", new_gpu->vendor_id, new_gpu->device_id, debugstr_w(new_gpu->name)); + } + +done: + free( vk_physical_devices ); + if (vk_instance) + vulkan_funcs->p_vkDestroyInstance( vk_instance, NULL ); +} + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR) static BOOL get_gpu_properties_from_vulkan( struct gdi_gpu *gpu, const XRRProviderInfo *provider_info, @@ -836,6 +943,7 @@ static BOOL xrandr14_get_gpus2( struct gdi_gpu **new_gpus, int *count, BOOL get_ XRRProviderInfo *provider_info = NULL; XRRCrtcInfo *crtc_info = NULL; INT primary_provider = -1; + INT gpu_count = 0; RECT primary_rect; BOOL ret = FALSE; DWORD len; @@ -849,22 +957,17 @@ static BOOL xrandr14_get_gpus2( struct gdi_gpu **new_gpus, int *count, BOOL get_ if (!provider_resources) goto done; - gpus = calloc( provider_resources->nproviders ? provider_resources->nproviders : 1, sizeof(*gpus) ); - if (!gpus) - goto done; - /* Some XRandR implementations don't support providers. * In this case, report a fake one to try searching adapters in screen resources */ if (!provider_resources->nproviders) { WARN("XRandR implementation doesn't report any providers, faking one.\n"); - lstrcpyW( gpus[0].name, wine_adapterW ); - *new_gpus = gpus; - *count = 1; - ret = TRUE; - goto done; + goto fallback; } + gpus = calloc( provider_resources->nproviders, sizeof(*gpus) ); + if (!gpus) goto done; + primary_rect = get_primary_rect( screen_resources ); for (i = 0; i < provider_resources->nproviders; ++i) { @@ -898,6 +1001,7 @@ static BOOL xrandr14_get_gpus2( struct gdi_gpu **new_gpus, int *count, BOOL get_ /* FIXME: Add an alternate method of getting PCI IDs, for systems that don't support Vulkan */ } pXRRFreeProviderInfo( provider_info ); + gpu_count++; } /* Make primary GPU the first */ @@ -908,8 +1012,29 @@ static BOOL xrandr14_get_gpus2( struct gdi_gpu **new_gpus, int *count, BOOL get_ gpus[primary_provider] = tmp; } +fallback: + /* Add the Vulkan only GPUs only if we need all the detailed properties */ + if (get_properties) + add_remaining_gpus_via_vulkan( &gpus, &gpu_count ); + + if (gpu_count == 0) + { + /* we need at least one for get_adapters() / get_id() */ + gpus = calloc( 1, sizeof(*gpus) ); + if (!gpus) goto done; + lstrcpyW( gpus[0].name, wine_adapterW ); + gpu_count = 1; + } + else if (gpus[0].id == -1) + { + /* the only GPUs we have are from Vulkan, mark the first one + * as main so that we can use screen resources for adapters, + * see xrandr14_get_adapters() */ + gpus[0].id = 0; + } + *new_gpus = gpus; - *count = provider_resources->nproviders; + *count = gpu_count; ret = TRUE; done: if (provider_resources) @@ -954,6 +1079,10 @@ static BOOL xrandr14_get_adapters( ULONG_PTR gpu_id, struct gdi_adapter **new_ad if (!screen_resources) goto done; + /* Vulkan-only, adapter-less GPU */ + if (gpu_id == -1) + goto done; + if (gpu_id) { provider_info = pXRRGetProviderInfo( gdi_display, screen_resources, gpu_id ); From 9c1e802db75e7475913ce7d9d39048641dce5034 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 21 Apr 2022 18:55:00 +0300 Subject: [PATCH 0620/2777] winevulkan: HACK: Add WINE_HIDE_VANGOGH_GPU environment variable. And auto enable it for Serious Sam 4. CW-Bug-Id: #20527 --- dlls/winevulkan/loader.c | 54 ++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/dlls/winevulkan/loader.c b/dlls/winevulkan/loader.c index fa5fd3d3020..e3fc5738e00 100644 --- a/dlls/winevulkan/loader.c +++ b/dlls/winevulkan/loader.c @@ -430,6 +430,34 @@ static void fill_luid_property(VkPhysicalDeviceProperties2 *properties2) device_node_mask); } +static void fixup_device_id(VkPhysicalDeviceProperties *properties) +{ + const char *sgi; + if (properties->vendorID == 0x10de /* NVIDIA */) + { + sgi = getenv("WINE_HIDE_NVIDIA_GPU"); + if (sgi && *sgi != '0') + { + { + properties->vendorID = 0x1002; /* AMD */ + properties->deviceID = 0x67df; /* RX 480 */ + } + } + } + else if (properties->vendorID && properties->vendorID == 0x1002 && properties->deviceID == 0x163f) + { + /* AMD VAN GOGH */ + BOOL hide; + sgi = getenv("WINE_HIDE_VANGOGH_GPU"); + if (sgi) + hide = *sgi != '0'; + else + hide = (sgi = getenv("SteamGameId")) && !strcmp(sgi, "257420"); + if (hide) + properties->deviceID = 0x687f; /* Radeon RX Vega 56/64 */ + } +} + void WINAPI vkGetPhysicalDeviceProperties(VkPhysicalDevice physical_device, VkPhysicalDeviceProperties *properties) { @@ -442,18 +470,7 @@ void WINAPI vkGetPhysicalDeviceProperties(VkPhysicalDevice physical_device, params.pProperties = properties; status = UNIX_CALL(vkGetPhysicalDeviceProperties, ¶ms); assert(!status); - - { - const char *sgi = getenv("WINE_HIDE_NVIDIA_GPU"); - if (sgi && *sgi != '0') - { - if (properties->vendorID == 0x10de /* NVIDIA */) - { - properties->vendorID = 0x1002; /* AMD */ - properties->deviceID = 0x67df; /* RX 480 */ - } - } - } + fixup_device_id(properties); } void WINAPI vkGetPhysicalDeviceProperties2(VkPhysicalDevice phys_dev, @@ -469,18 +486,7 @@ void WINAPI vkGetPhysicalDeviceProperties2(VkPhysicalDevice phys_dev, status = UNIX_CALL(vkGetPhysicalDeviceProperties2, ¶ms); assert(!status); fill_luid_property(properties2); - - { - const char *sgi = getenv("WINE_HIDE_NVIDIA_GPU"); - if (sgi && *sgi != '0') - { - if (properties2->properties.vendorID == 0x10de /* NVIDIA */) - { - properties2->properties.vendorID = 0x1002; /* AMD */ - properties2->properties.deviceID = 0x67df; /* RX 480 */ - } - } - } + fixup_device_id(&properties2->properties); } void WINAPI vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice phys_dev, From 826348cfda863c5dcbc537ce36e49fcfb1963b65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 12 Mar 2021 18:27:41 +0100 Subject: [PATCH 0621/2777] winex11.drv: Store swapchain surfaces associations. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on a patch from Felix Hädicke . Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45277 CW-Bug-Id: 16608 --- dlls/winex11.drv/vulkan.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 92157d005b7..ec095ca89e8 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -50,6 +50,7 @@ WINE_DECLARE_DEBUG_CHANNEL(fps); static pthread_mutex_t vulkan_mutex; static XContext vulkan_hwnd_context; +static XContext vulkan_swapchain_context; #define VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR 1000004000 @@ -141,6 +142,8 @@ static void wine_vk_init(void) #undef LOAD_OPTIONAL_FUNCPTR vulkan_hwnd_context = XUniqueContext(); + vulkan_swapchain_context = XUniqueContext(); + return; fail: @@ -304,6 +307,8 @@ static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device, { struct wine_vk_surface *x11_surface = surface_from_handle(create_info->surface); VkSwapchainCreateInfoKHR create_info_host; + VkResult result; + TRACE("%p %p %p %p\n", device, create_info, allocator, swapchain); if (allocator) @@ -315,7 +320,14 @@ static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device, create_info_host = *create_info; create_info_host.surface = x11_surface->surface; - return pvkCreateSwapchainKHR(device, &create_info_host, NULL /* allocator */, swapchain); + result = pvkCreateSwapchainKHR(device, &create_info_host, NULL /* allocator */, swapchain); + if (result == VK_SUCCESS) + { + pthread_mutex_lock(&vulkan_mutex); + XSaveContext(gdi_display, (XID)(*swapchain), vulkan_swapchain_context, (char *)wine_vk_surface_grab(x11_surface)); + pthread_mutex_unlock(&vulkan_mutex); + } + return result; } static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, @@ -427,12 +439,20 @@ static void X11DRV_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface static void X11DRV_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *allocator) { + struct wine_vk_surface *surface; + TRACE("%p, 0x%s %p\n", device, wine_dbgstr_longlong(swapchain), allocator); if (allocator) FIXME("Support for allocation callbacks not implemented yet\n"); pvkDestroySwapchainKHR(device, swapchain, NULL /* allocator */); + + pthread_mutex_lock(&vulkan_mutex); + if (!XFindContext(gdi_display, (XID)swapchain, vulkan_swapchain_context, (char **)&surface)) + wine_vk_surface_release(surface); + XDeleteContext(gdi_display, (XID)swapchain, vulkan_swapchain_context); + pthread_mutex_unlock(&vulkan_mutex); } static VkResult X11DRV_vkEnumerateInstanceExtensionProperties(const char *layer_name, From 6c14702944d263cd7e08b6dea61568b0bb71371f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 13 Dec 2022 17:51:41 +0100 Subject: [PATCH 0622/2777] winex11.drv: Hook vkAcquireNextImage(2)KHR functions. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45277 --- dlls/winemac.drv/vulkan.c | 2 ++ dlls/winevulkan/make_vulkan | 3 +++ dlls/winex11.drv/vulkan.c | 19 +++++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/dlls/winemac.drv/vulkan.c b/dlls/winemac.drv/vulkan.c index 00f5e8465ab..0c1a11af63d 100644 --- a/dlls/winemac.drv/vulkan.c +++ b/dlls/winemac.drv/vulkan.c @@ -591,6 +591,8 @@ static VkSurfaceKHR macdrv_wine_get_native_surface(VkSurfaceKHR surface) static const struct vulkan_funcs vulkan_funcs = { + NULL, + NULL, macdrv_vkCreateInstance, macdrv_vkCreateSwapchainKHR, macdrv_vkCreateWin32SurfaceKHR, diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 3e53cd9ffff..d38d5564fb9 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -240,6 +240,9 @@ FUNCTION_OVERRIDES = { "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, + "vkAcquireNextImageKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, + "vkAcquireNextImage2KHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, + # VK_KHR_external_fence_capabilities "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index ec095ca89e8..620c306de22 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -75,6 +75,7 @@ typedef struct VkXlibSurfaceCreateInfoKHR Window window; } VkXlibSurfaceCreateInfoKHR; +static VkResult (*pvkAcquireNextImageKHR)(VkDevice, VkSwapchainKHR, uint64_t, VkSemaphore, VkFence, uint32_t *); static VkResult (*pvkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *); static VkResult (*pvkCreateSwapchainKHR)(VkDevice, const VkSwapchainCreateInfoKHR *, const VkAllocationCallbacks *, VkSwapchainKHR *); static VkResult (*pvkCreateXlibSurfaceKHR)(VkInstance, const VkXlibSurfaceCreateInfoKHR *, const VkAllocationCallbacks *, VkSurfaceKHR *); @@ -118,6 +119,7 @@ static void wine_vk_init(void) #define LOAD_FUNCPTR(f) if (!(p##f = dlsym(vulkan_handle, #f))) goto fail #define LOAD_OPTIONAL_FUNCPTR(f) p##f = dlsym(vulkan_handle, #f) + LOAD_FUNCPTR(vkAcquireNextImageKHR); LOAD_FUNCPTR(vkCreateInstance); LOAD_FUNCPTR(vkCreateSwapchainKHR); LOAD_FUNCPTR(vkCreateXlibSurfaceKHR); @@ -678,6 +680,21 @@ static VkResult X11DRV_vkGetSwapchainImagesKHR(VkDevice device, return pvkGetSwapchainImagesKHR(device, swapchain, count, images); } +static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, + VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, + VkFence fence, uint32_t *image_index) +{ + return pvkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, image_index); +} + +static VkResult X11DRV_vkAcquireNextImage2KHR(VkDevice device, + const VkAcquireNextImageInfoKHR *acquire_info, uint32_t *image_index) +{ + static int once; + if (!once++) FIXME("Emulating vkGetPhysicalDeviceSurfaceCapabilities2KHR with vkGetPhysicalDeviceSurfaceCapabilitiesKHR, pNext is ignored.\n"); + return X11DRV_vkAcquireNextImageKHR(device, acquire_info->swapchain, acquire_info->timeout, acquire_info->semaphore, acquire_info->fence, image_index); +} + static VkResult X11DRV_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *present_info) { static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; @@ -724,6 +741,8 @@ static VkSurfaceKHR X11DRV_wine_get_native_surface(VkSurfaceKHR surface) static const struct vulkan_funcs vulkan_funcs = { + X11DRV_vkAcquireNextImage2KHR, + X11DRV_vkAcquireNextImageKHR, X11DRV_vkCreateInstance, X11DRV_vkCreateSwapchainKHR, X11DRV_vkCreateWin32SurfaceKHR, From bfbfad91f6b896b38411e99f652c03520ee733ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 22 Oct 2021 00:23:49 +0200 Subject: [PATCH 0623/2777] winex11.drv: Rename X11DRV_FLUSH_GL_DRAWABLE to X11DRV_PRESENT_DRAWABLE. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45277 CW-Bug-Id: 16608 --- dlls/winex11.drv/init.c | 8 ++++---- dlls/winex11.drv/opengl.c | 43 ++++++++++++++++++--------------------- dlls/winex11.drv/x11drv.h | 8 ++++---- 3 files changed, 28 insertions(+), 31 deletions(-) diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index 7e343591413..c23c0f0645e 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -244,16 +244,16 @@ static INT CDECL X11DRV_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOI return TRUE; } break; - case X11DRV_FLUSH_GL_DRAWABLE: - if (in_count >= sizeof(struct x11drv_escape_flush_gl_drawable)) + case X11DRV_PRESENT_DRAWABLE: + if (in_count >= sizeof(struct x11drv_escape_present_drawable)) { - const struct x11drv_escape_flush_gl_drawable *data = in_data; + const struct x11drv_escape_present_drawable *data = in_data; RECT rect = physDev->dc_rect; OffsetRect( &rect, -physDev->dc_rect.left, -physDev->dc_rect.top ); if (data->flush) XFlush( gdi_display ); XSetFunction( gdi_display, physDev->gc, GXcopy ); - XCopyArea( gdi_display, data->gl_drawable, physDev->drawable, physDev->gc, + XCopyArea( gdi_display, data->drawable, physDev->drawable, physDev->gc, 0, 0, rect.right, rect.bottom, physDev->dc_rect.left, physDev->dc_rect.top ); add_device_bounds( physDev, &rect ); diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 0f3d0760aa3..3205711eca4 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2005,20 +2005,20 @@ static BOOL glxdrv_wglShareLists(struct wgl_context *org, struct wgl_context *de static void wglFinish(void) { - struct x11drv_escape_flush_gl_drawable escape; + struct x11drv_escape_present_drawable escape; struct gl_drawable *gl; struct wgl_context *ctx = NtCurrentTeb()->glContext; - escape.code = X11DRV_FLUSH_GL_DRAWABLE; - escape.gl_drawable = 0; + escape.code = X11DRV_PRESENT_DRAWABLE; + escape.drawable = 0; escape.flush = FALSE; if ((gl = get_gl_drawable( NtUserWindowFromDC( ctx->hdc ), 0 ))) { switch (gl->type) { - case DC_GL_PIXMAP_WIN: escape.gl_drawable = gl->pixmap; break; - case DC_GL_CHILD_WIN: escape.gl_drawable = gl->window; break; + case DC_GL_PIXMAP_WIN: escape.drawable = gl->pixmap; break; + case DC_GL_CHILD_WIN: escape.drawable = gl->window; break; default: break; } sync_context(ctx); @@ -2026,26 +2026,25 @@ static void wglFinish(void) } pglFinish(); - if (escape.gl_drawable) - NtGdiExtEscape( ctx->hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); + if (escape.drawable) NtGdiExtEscape( ctx->hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); } static void wglFlush(void) { - struct x11drv_escape_flush_gl_drawable escape; + struct x11drv_escape_present_drawable escape; struct gl_drawable *gl; struct wgl_context *ctx = NtCurrentTeb()->glContext; - escape.code = X11DRV_FLUSH_GL_DRAWABLE; - escape.gl_drawable = 0; + escape.code = X11DRV_PRESENT_DRAWABLE; + escape.drawable = 0; escape.flush = FALSE; if ((gl = get_gl_drawable( NtUserWindowFromDC( ctx->hdc ), 0 ))) { switch (gl->type) { - case DC_GL_PIXMAP_WIN: escape.gl_drawable = gl->pixmap; break; - case DC_GL_CHILD_WIN: escape.gl_drawable = gl->window; break; + case DC_GL_PIXMAP_WIN: escape.drawable = gl->pixmap; break; + case DC_GL_CHILD_WIN: escape.drawable = gl->window; break; default: break; } sync_context(ctx); @@ -2053,8 +2052,7 @@ static void wglFlush(void) } pglFlush(); - if (escape.gl_drawable) - NtGdiExtEscape( ctx->hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); + if (escape.drawable) NtGdiExtEscape( ctx->hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); } static const GLubyte *wglGetString(GLenum name) @@ -3389,15 +3387,15 @@ static void X11DRV_WineGL_LoadExtensions(void) */ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) { - struct x11drv_escape_flush_gl_drawable escape; + struct x11drv_escape_present_drawable escape; struct gl_drawable *gl; struct wgl_context *ctx = NtCurrentTeb()->glContext; INT64 ust, msc, sbc, target_sbc = 0; TRACE("(%p)\n", hdc); - escape.code = X11DRV_FLUSH_GL_DRAWABLE; - escape.gl_drawable = 0; + escape.code = X11DRV_PRESENT_DRAWABLE; + escape.drawable = 0; escape.flush = !pglXWaitForSbcOML; if (!(gl = get_gl_drawable( NtUserWindowFromDC( hdc ), hdc ))) @@ -3418,7 +3416,7 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) { case DC_GL_PIXMAP_WIN: if (ctx) sync_context( ctx ); - escape.gl_drawable = gl->pixmap; + escape.drawable = gl->pixmap; if (pglXCopySubBufferMESA) { /* (glX)SwapBuffers has an implicit glFlush effect, however * GLX_MESA_copy_sub_buffer doesn't. Make sure GL is flushed before @@ -3439,10 +3437,10 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) case DC_GL_WINDOW: case DC_GL_CHILD_WIN: if (ctx) sync_context( ctx ); - if (gl->type == DC_GL_CHILD_WIN) escape.gl_drawable = gl->window; + if (gl->type == DC_GL_CHILD_WIN) escape.drawable = gl->window; /* fall through */ default: - if (escape.gl_drawable && pglXSwapBuffersMscOML) + if (escape.drawable && pglXSwapBuffersMscOML) { pglFlush(); target_sbc = pglXSwapBuffersMscOML( gdi_display, gl->drawable, 0, 0, 0 ); @@ -3452,13 +3450,12 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) break; } - if (escape.gl_drawable && pglXWaitForSbcOML) + if (escape.drawable && pglXWaitForSbcOML) pglXWaitForSbcOML( gdi_display, gl->drawable, target_sbc, &ust, &msc, &sbc ); release_gl_drawable( gl ); - if (escape.gl_drawable) - NtGdiExtEscape( ctx->hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); + if (escape.drawable) NtGdiExtEscape( ctx->hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); return TRUE; } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 7afd4b6287f..4a08407e783 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -346,7 +346,7 @@ enum x11drv_escape_codes X11DRV_GET_DRAWABLE, /* get current drawable for a DC */ X11DRV_START_EXPOSURES, /* start graphics exposures */ X11DRV_END_EXPOSURES, /* end graphics exposures */ - X11DRV_FLUSH_GL_DRAWABLE /* flush changes made to the gl drawable */ + X11DRV_PRESENT_DRAWABLE, /* present the drawable on screen */ }; struct x11drv_escape_set_drawable @@ -365,10 +365,10 @@ struct x11drv_escape_get_drawable int pixel_format; /* internal GL pixel format */ }; -struct x11drv_escape_flush_gl_drawable +struct x11drv_escape_present_drawable { - enum x11drv_escape_codes code; /* escape code (X11DRV_FLUSH_GL_DRAWABLE) */ - Drawable gl_drawable; /* GL drawable */ + enum x11drv_escape_codes code; /* escape code (X11DRV_PRESENT_DRAWABLE) */ + Drawable drawable; /* GL / VK drawable */ BOOL flush; /* flush X11 before copying */ }; From f187dc66b41a1bb2055c977b5f3b0360bbe0a715 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 13 Dec 2022 18:00:04 +0100 Subject: [PATCH 0624/2777] winex11.drv: Support child window vulkan rendering. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on a patch from Felix Hädicke . Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45277 CW-Bug-Id: 16608 --- dlls/winex11.drv/vulkan.c | 93 +++++++++++++++++++++++++++++++++++---- dlls/winex11.drv/window.c | 15 +++++++ dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 100 insertions(+), 9 deletions(-) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 620c306de22..feaa572af1d 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -35,6 +35,7 @@ #include "wine/debug.h" #include "x11drv.h" +#include "xcomposite.h" #define VK_NO_PROTOTYPES #define WINE_VK_HOST @@ -62,6 +63,8 @@ struct wine_vk_surface struct list entry; Window window; VkSurfaceKHR surface; /* native surface */ + BOOL offscreen; /* drawable is offscreen */ + HDC hdc; HWND hwnd; DWORD hwnd_thread_id; }; @@ -232,15 +235,54 @@ static void wine_vk_surface_release(struct wine_vk_surface *surface) void wine_vk_surface_destroy(HWND hwnd) { struct wine_vk_surface *surface; + HDC hdc = 0; + pthread_mutex_lock(&vulkan_mutex); if (!XFindContext(gdi_display, (XID)hwnd, vulkan_hwnd_context, (char **)&surface)) { + hdc = surface->hdc; surface->hwnd_thread_id = 0; - surface->hwnd = NULL; + surface->hwnd = 0; + surface->hdc = 0; wine_vk_surface_release(surface); } XDeleteContext(gdi_display, (XID)hwnd, vulkan_hwnd_context); pthread_mutex_unlock(&vulkan_mutex); + if (hdc) NtUserReleaseDC(hwnd, hdc); +} + +static BOOL wine_vk_surface_set_offscreen(struct wine_vk_surface *surface, BOOL offscreen) +{ +#ifdef SONAME_LIBXCOMPOSITE + if (usexcomposite) + { + if (!surface->offscreen && offscreen) + { + FIXME("Redirecting vulkan surface offscreen, expect degraded performance.\n"); + pXCompositeRedirectWindow(gdi_display, surface->window, CompositeRedirectManual); + } + else if (surface->offscreen && !offscreen) + { + FIXME("Putting vulkan surface back onscreen, expect standard performance.\n"); + pXCompositeUnredirectWindow(gdi_display, surface->window, CompositeRedirectManual); + } + surface->offscreen = offscreen; + return TRUE; + } +#endif + + if (offscreen) FIXME("Application requires child window rendering, which is not implemented yet!\n"); + surface->offscreen = offscreen; + return !offscreen; +} + +void sync_vk_surface(HWND hwnd, BOOL known_child) +{ + struct wine_vk_surface *surface; + pthread_mutex_lock(&vulkan_mutex); + if (!XFindContext(gdi_display, (XID)hwnd, vulkan_hwnd_context, (char **)&surface)) + wine_vk_surface_set_offscreen(surface, known_child); + pthread_mutex_unlock(&vulkan_mutex); } void vulkan_thread_detach(void) @@ -339,19 +381,13 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, VkResult res; VkXlibSurfaceCreateInfoKHR create_info_host; struct wine_vk_surface *x11_surface; + HWND parent; TRACE("%p %p %p %p\n", instance, create_info, allocator, surface); if (allocator) FIXME("Support for allocation callbacks not implemented yet\n"); - /* TODO: support child window rendering. */ - if (create_info->hwnd && NtUserGetAncestor(create_info->hwnd, GA_PARENT) != NtUserGetDesktopWindow()) - { - FIXME("Application requires child window rendering, which is not implemented yet!\n"); - return VK_ERROR_INCOMPATIBLE_DRIVER; - } - x11_surface = calloc(1, sizeof(*x11_surface)); if (!x11_surface) return VK_ERROR_OUT_OF_HOST_MEMORY; @@ -360,6 +396,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, x11_surface->hwnd = create_info->hwnd; if (x11_surface->hwnd) { + x11_surface->hdc = NtUserGetDC(create_info->hwnd); x11_surface->window = create_client_window(create_info->hwnd, &default_visual); x11_surface->hwnd_thread_id = NtUserGetWindowThread(x11_surface->hwnd, NULL); } @@ -377,6 +414,17 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, goto err; } + if (!(parent = create_info->hwnd)) + TRACE("Creation window not provided\n"); + else if (NtUserGetWindowRelative( parent, GW_CHILD ) || NtUserGetAncestor( parent, GA_PARENT ) != NtUserGetDesktopWindow()) + { + if (!wine_vk_surface_set_offscreen(x11_surface, TRUE)) + { + res = VK_ERROR_INCOMPATIBLE_DRIVER; + goto err; + } + } + create_info_host.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; create_info_host.pNext = NULL; create_info_host.flags = 0; /* reserved */ @@ -684,7 +732,30 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *image_index) { - return pvkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, image_index); + struct x11drv_escape_present_drawable escape; + struct wine_vk_surface *surface = NULL; + VkResult result; + HDC hdc = 0; + + pthread_mutex_lock(&vulkan_mutex); + if (!XFindContext(gdi_display, (XID)swapchain, vulkan_swapchain_context, (char **)&surface)) + { + wine_vk_surface_grab(surface); + hdc = surface->hdc; + } + pthread_mutex_unlock(&vulkan_mutex); + + result = pvkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, image_index); + if (result == VK_SUCCESS && hdc && surface && surface->offscreen) + { + escape.code = X11DRV_PRESENT_DRAWABLE; + escape.drawable = surface->window; + escape.flush = TRUE; + NtGdiExtEscape(hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (char *)&escape, 0, NULL); + } + + if (surface) wine_vk_surface_release(surface); + return result; } static VkResult X11DRV_vkAcquireNextImage2KHR(VkDevice device, @@ -806,6 +877,10 @@ void wine_vk_surface_destroy(HWND hwnd) { } +void sync_vk_surface(HWND hwnd, BOOL known_child) +{ +} + void vulkan_thread_detach(void) { } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index f9529a1c83a..4fc9f579cd9 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2040,6 +2040,15 @@ void X11DRV_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style ) { struct x11drv_win_data *data; DWORD changed = style->styleNew ^ style->styleOld; + HWND parent = NtUserGetAncestor( hwnd, GA_PARENT ); + + if (offset == GWL_STYLE && (changed & WS_CHILD)) + { + if (NtUserGetWindowRelative( parent, GW_CHILD ) || NtUserGetAncestor( parent, GA_PARENT ) != NtUserGetDesktopWindow()) + sync_vk_surface( parent, TRUE ); + else + sync_vk_surface( parent, FALSE ); + } if (hwnd == NtUserGetDesktopWindow()) return; if (!(data = get_win_data( hwnd ))) return; @@ -2066,6 +2075,10 @@ void X11DRV_DestroyWindow( HWND hwnd ) { struct x11drv_thread_data *thread_data = x11drv_thread_data(); struct x11drv_win_data *data; + HWND parent = NtUserGetAncestor( hwnd, GA_PARENT ); + + if (!NtUserGetWindowRelative( parent, GW_CHILD ) && NtUserGetAncestor( parent, GA_PARENT ) == NtUserGetDesktopWindow()) + sync_vk_surface( parent, FALSE ); if (!(data = get_win_data( hwnd ))) return; @@ -2283,6 +2296,7 @@ static struct x11drv_win_data *X11DRV_create_win_data( HWND hwnd, const RECT *wi * that will need clipping support. */ sync_gl_drawable( parent, TRUE ); + sync_vk_surface( parent, TRUE ); display = thread_init_display(); init_clip_window(); /* make sure the clip window is initialized in this thread */ @@ -2762,6 +2776,7 @@ void X11DRV_SetParent( HWND hwnd, HWND parent, HWND old_parent ) * that will need clipping support. */ sync_gl_drawable( parent, TRUE ); + sync_vk_surface( parent, TRUE ); fetch_icon_data( hwnd, 0, 0 ); } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 4a08407e783..9ecd63ba7b1 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -667,6 +667,7 @@ extern void sync_gl_drawable( HWND hwnd, BOOL known_child ) DECLSPEC_HIDDEN; extern void set_gl_drawable_parent( HWND hwnd, HWND parent ) DECLSPEC_HIDDEN; extern void destroy_gl_drawable( HWND hwnd ) DECLSPEC_HIDDEN; extern void wine_vk_surface_destroy( HWND hwnd ) DECLSPEC_HIDDEN; +extern void sync_vk_surface( HWND hwnd, BOOL known_child ) DECLSPEC_HIDDEN; extern void vulkan_thread_detach(void) DECLSPEC_HIDDEN; extern void wait_for_withdrawn_state( HWND hwnd, BOOL set ) DECLSPEC_HIDDEN; From 041e5c654f434d0dccd1d8fc18044f258bca54d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 22 Oct 2021 00:49:09 +0200 Subject: [PATCH 0625/2777] winex11.drv: Wait on vkAcquireNextImageKHR before flushing. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To prevent tearing, when present mode is mailbox or fifo. Based on a patch from Felix Hädicke . Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45277 CW-Bug-Id: 16608 --- dlls/winex11.drv/vulkan.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index feaa572af1d..abebef29b1c 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -63,6 +63,7 @@ struct wine_vk_surface struct list entry; Window window; VkSurfaceKHR surface; /* native surface */ + VkPresentModeKHR present_mode; BOOL offscreen; /* drawable is offscreen */ HDC hdc; HWND hwnd; @@ -99,6 +100,9 @@ static VkResult (*pvkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice, uint3 static VkBool32 (*pvkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice, uint32_t, Display *, VisualID); static VkResult (*pvkGetSwapchainImagesKHR)(VkDevice, VkSwapchainKHR, uint32_t *, VkImage *); static VkResult (*pvkQueuePresentKHR)(VkQueue, const VkPresentInfoKHR *); +static VkResult (*pvkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout); +static VkResult (*pvkCreateFence)(VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence); +static void (*pvkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator); static void *X11DRV_get_vk_device_proc_addr(const char *name); static void *X11DRV_get_vk_instance_proc_addr(VkInstance instance, const char *name); @@ -143,6 +147,9 @@ static void wine_vk_init(void) LOAD_FUNCPTR(vkQueuePresentKHR); LOAD_OPTIONAL_FUNCPTR(vkGetDeviceGroupSurfacePresentModesKHR); LOAD_OPTIONAL_FUNCPTR(vkGetPhysicalDevicePresentRectanglesKHR); + LOAD_FUNCPTR(vkWaitForFences); + LOAD_FUNCPTR(vkCreateFence); + LOAD_FUNCPTR(vkDestroyFence); #undef LOAD_FUNCPTR #undef LOAD_OPTIONAL_FUNCPTR @@ -364,6 +371,11 @@ static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device, create_info_host = *create_info; create_info_host.surface = x11_surface->surface; + /* force fifo when running offscreen so the acquire fence is more likely to be vsynced */ + if (x11_surface->offscreen && create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR) + create_info_host.presentMode = VK_PRESENT_MODE_FIFO_KHR; + x11_surface->present_mode = create_info->presentMode; + result = pvkCreateSwapchainKHR(device, &create_info_host, NULL /* allocator */, swapchain); if (result == VK_SUCCESS) { @@ -732,9 +744,12 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *image_index) { + static int once; struct x11drv_escape_present_drawable escape; struct wine_vk_surface *surface = NULL; VkResult result; + VkFence orig_fence; + BOOL wait_fence = FALSE; HDC hdc = 0; pthread_mutex_lock(&vulkan_mutex); @@ -745,15 +760,35 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, } pthread_mutex_unlock(&vulkan_mutex); + if (!surface || !surface->offscreen) + wait_fence = FALSE; + else if (surface->present_mode == VK_PRESENT_MODE_MAILBOX_KHR || + surface->present_mode == VK_PRESENT_MODE_FIFO_KHR) + wait_fence = TRUE; + + orig_fence = fence; + if (wait_fence && !fence) + { + VkFenceCreateInfo create_info; + create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + create_info.pNext = NULL; + create_info.flags = 0; + pvkCreateFence(device, &create_info, NULL, &fence); + } + result = pvkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, image_index); if (result == VK_SUCCESS && hdc && surface && surface->offscreen) { + if (wait_fence) pvkWaitForFences(device, 1, &fence, 0, timeout); escape.code = X11DRV_PRESENT_DRAWABLE; escape.drawable = surface->window; escape.flush = TRUE; NtGdiExtEscape(hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (char *)&escape, 0, NULL); + if (surface->present_mode == VK_PRESENT_MODE_MAILBOX_KHR) + if (once++) FIXME("Application requires child window rendering with mailbox present mode, expect possible tearing!\n"); } + if (fence != orig_fence) pvkDestroyFence(device, fence, NULL); if (surface) wine_vk_surface_release(surface); return result; } From d7233b0472ad4daa114266a1dd89dea6e8e36fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 12 Mar 2021 00:10:49 +0100 Subject: [PATCH 0626/2777] winex11.drv: Move Xfixes extension query to process_attach. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45277 CW-Bug-Id: 16608 --- dlls/winex11.drv/clipboard.c | 26 ++------------ dlls/winex11.drv/x11drv.h | 2 ++ dlls/winex11.drv/x11drv_main.c | 63 ++++++++++++++++++++++++++++++++++ dlls/winex11.drv/xfixes.h | 36 +++++++++++++++++++ 4 files changed, 103 insertions(+), 24 deletions(-) create mode 100644 dlls/winex11.drv/xfixes.h diff --git a/dlls/winex11.drv/clipboard.c b/dlls/winex11.drv/clipboard.c index e91368d69e7..327e74d73dd 100644 --- a/dlls/winex11.drv/clipboard.c +++ b/dlls/winex11.drv/clipboard.c @@ -83,6 +83,7 @@ #include "ntstatus.h" #define WIN32_NO_STATUS #include "x11drv.h" +#include "xfixes.h" #ifdef HAVE_X11_EXTENSIONS_XFIXES_H #include @@ -199,7 +200,6 @@ static UINT rendered_formats; static ULONG last_clipboard_update; static struct clipboard_format **current_x11_formats; static unsigned int nb_current_x11_formats; -static BOOL use_xfixes; Display *clipboard_display = NULL; @@ -2170,28 +2170,6 @@ static BOOL selection_notify_event( HWND hwnd, XEvent *event ) static void xfixes_init(void) { #ifdef SONAME_LIBXFIXES - typeof(XFixesSelectSelectionInput) *pXFixesSelectSelectionInput; - typeof(XFixesQueryExtension) *pXFixesQueryExtension; - typeof(XFixesQueryVersion) *pXFixesQueryVersion; - - int event_base, error_base; - int major = 3, minor = 0; - void *handle; - - handle = dlopen(SONAME_LIBXFIXES, RTLD_NOW); - if (!handle) return; - - pXFixesQueryExtension = dlsym(handle, "XFixesQueryExtension"); - if (!pXFixesQueryExtension) return; - pXFixesQueryVersion = dlsym(handle, "XFixesQueryVersion"); - if (!pXFixesQueryVersion) return; - pXFixesSelectSelectionInput = dlsym(handle, "XFixesSelectSelectionInput"); - if (!pXFixesSelectSelectionInput) return; - - if (!pXFixesQueryExtension(clipboard_display, &event_base, &error_base)) - return; - pXFixesQueryVersion(clipboard_display, &major, &minor); - use_xfixes = (major >= 1); if (!use_xfixes) return; pXFixesSelectSelectionInput(clipboard_display, import_window, x11drv_atom(CLIPBOARD), @@ -2205,7 +2183,7 @@ static void xfixes_init(void) XFixesSelectionWindowDestroyNotifyMask | XFixesSelectionClientCloseNotifyMask); } - X11DRV_register_event_handler(event_base + XFixesSelectionNotify, + X11DRV_register_event_handler(xfixes_event_base + XFixesSelectionNotify, selection_notify_event, "XFixesSelectionNotify"); TRACE("xfixes succesully initialized\n"); #else diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 9ecd63ba7b1..06264d333cd 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -447,6 +447,7 @@ extern BOOL show_systray DECLSPEC_HIDDEN; extern BOOL grab_pointer DECLSPEC_HIDDEN; extern BOOL grab_fullscreen DECLSPEC_HIDDEN; extern BOOL usexcomposite DECLSPEC_HIDDEN; +extern BOOL use_xfixes DECLSPEC_HIDDEN; extern BOOL managed_mode DECLSPEC_HIDDEN; extern BOOL decorated_mode DECLSPEC_HIDDEN; extern BOOL private_color_map DECLSPEC_HIDDEN; @@ -454,6 +455,7 @@ extern int primary_monitor DECLSPEC_HIDDEN; extern int copy_default_colors DECLSPEC_HIDDEN; extern int alloc_system_colors DECLSPEC_HIDDEN; extern int xrender_error_base DECLSPEC_HIDDEN; +extern int xfixes_event_base DECLSPEC_HIDDEN; extern char *process_name DECLSPEC_HIDDEN; extern Display *clipboard_display DECLSPEC_HIDDEN; extern WNDPROC client_foreign_window_proc; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 9942a5428b9..b64116cda40 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -52,6 +52,7 @@ #include "x11drv.h" #include "winreg.h" #include "xcomposite.h" +#include "xfixes.h" #include "wine/server.h" #include "wine/debug.h" #include "wine/list.h" @@ -72,6 +73,7 @@ Window root_window; BOOL usexvidmode = TRUE; BOOL usexrandr = TRUE; BOOL usexcomposite = TRUE; +BOOL use_xfixes = FALSE; BOOL use_xkb = TRUE; BOOL use_take_focus = FALSE; BOOL use_primary_selection = FALSE; @@ -89,6 +91,7 @@ BOOL shape_layered_windows = TRUE; int copy_default_colors = 128; int alloc_system_colors = 256; int xrender_error_base = 0; +int xfixes_event_base = 0; char *process_name = NULL; WNDPROC client_foreign_window_proc = NULL; HANDLE steam_overlay_event; @@ -612,6 +615,63 @@ static void X11DRV_XComposite_Init(void) } #endif /* defined(SONAME_LIBXCOMPOSITE) */ +#ifdef SONAME_LIBXFIXES + +#define MAKE_FUNCPTR(f) typeof(f) * p##f; +MAKE_FUNCPTR(XFixesQueryExtension) +MAKE_FUNCPTR(XFixesQueryVersion) +MAKE_FUNCPTR(XFixesCreateRegion) +MAKE_FUNCPTR(XFixesCreateRegionFromGC) +MAKE_FUNCPTR(XFixesSelectSelectionInput) +#undef MAKE_FUNCPTR + +static void x11drv_load_xfixes(void) +{ + int event, error, major = 3, minor = 0; + void *xfixes; + + if (!(xfixes = dlopen(SONAME_LIBXFIXES, RTLD_NOW))) + { + WARN("Xfixes library %s not found, disabled.\n", SONAME_LIBXFIXES); + return; + } + +#define LOAD_FUNCPTR(f) \ + if (!(p##f = dlsym(xfixes, #f))) \ + { \ + WARN("Xfixes function %s not found, disabled\n", #f); \ + dlclose(xfixes); \ + return; \ + } + LOAD_FUNCPTR(XFixesQueryExtension) + LOAD_FUNCPTR(XFixesQueryVersion) + LOAD_FUNCPTR(XFixesCreateRegion) + LOAD_FUNCPTR(XFixesCreateRegionFromGC) + LOAD_FUNCPTR(XFixesSelectSelectionInput) +#undef LOAD_FUNCPTR + + if (!pXFixesQueryExtension(gdi_display, &event, &error)) + { + WARN("Xfixes extension not found, disabled.\n"); + dlclose(xfixes); + return; + } + + if (!pXFixesQueryVersion(gdi_display, &major, &minor) || + major < 2) + { + WARN("Xfixes version 2.0 not found, disabled.\n"); + dlclose(xfixes); + return; + } + + TRACE("Xfixes, error %d, event %d, version %d.%d found\n", + error, event, major, minor); + use_xfixes = TRUE; + xfixes_event_base = event; +} +#endif /* SONAME_LIBXFIXES */ + static void init_visuals( Display *display, int screen ) { int count; @@ -743,6 +803,9 @@ static NTSTATUS x11drv_init( void *arg ) X11DRV_XF86VM_Init(); /* initialize XRandR */ X11DRV_XRandR_Init(); +#ifdef SONAME_LIBXFIXES + x11drv_load_xfixes(); +#endif #ifdef SONAME_LIBXCOMPOSITE X11DRV_XComposite_Init(); #endif diff --git a/dlls/winex11.drv/xfixes.h b/dlls/winex11.drv/xfixes.h new file mode 100644 index 00000000000..3ab31201d3d --- /dev/null +++ b/dlls/winex11.drv/xfixes.h @@ -0,0 +1,36 @@ +/* + * Wine X11DRV Xfixes interface + * + * 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 + */ +#ifndef __WINE_XFIXES_H +#define __WINE_XFIXES_H + +#ifndef __WINE_CONFIG_H +# error You must include config.h to use this header +#endif + +#ifdef SONAME_LIBXFIXES +#include +#define MAKE_FUNCPTR(f) extern typeof(f) * p##f DECLSPEC_HIDDEN; +MAKE_FUNCPTR(XFixesQueryExtension) +MAKE_FUNCPTR(XFixesQueryVersion) +MAKE_FUNCPTR(XFixesSelectSelectionInput) +#undef MAKE_FUNCPTR +#endif /* defined(SONAME_LIBXFIXES) */ + +#endif /* __WINE_XFIXES_H */ From a15544ca625d03e2a7560ebeb22eb3c134ac8ea7 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 31 Mar 2020 20:07:49 +0300 Subject: [PATCH 0627/2777] winex11.drv: Remove active client window from window data before deleting it. CW-Bug-ID: #19216 Fixes a crash with BadDrawable X error which happens when client window is used in windows.c:sync_client_position() after the GL drawable has been deleted. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49649 --- 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 3205711eca4..e38c6a62227 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -221,6 +221,7 @@ enum dc_gl_type struct gl_drawable { LONG ref; /* reference count */ + HWND hwnd; enum dc_gl_type type; /* type of GL surface */ GLXDrawable drawable; /* drawable for rendering with GL */ Window window; /* window if drawable is a GLXWindow */ @@ -1156,10 +1157,23 @@ static void release_gl_drawable( struct gl_drawable *gl ) { case DC_GL_WINDOW: case DC_GL_CHILD_WIN: + { + struct x11drv_win_data *data = get_win_data( gl->hwnd ); + TRACE( "destroying %lx drawable %lx\n", gl->window, gl->drawable ); + if (data) + { + if (data->client_window == gl->window) + { + XDeleteContext( data->display, data->client_window, winContext ); + data->client_window = 0; + } + release_win_data( data ); + } pglXDestroyWindow( gdi_display, gl->drawable ); XDestroyWindow( gdi_display, gl->window ); break; + } case DC_GL_PIXMAP_WIN: TRACE( "destroying pixmap %lx drawable %lx\n", gl->pixmap, gl->drawable ); pglXDestroyPixmap( gdi_display, gl->drawable ); @@ -1320,6 +1334,7 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel /* Default GLX and WGL swap interval is 1, but in case of glXSwapIntervalSGI * there is no way to query it, so we have to store it here. */ + gl->hwnd = hwnd; gl->swap_interval = 1; gl->refresh_swap_interval = TRUE; gl->format = format; From b21bea6e45a9e67fb7524c4361c485f40dbe45f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 22 Oct 2021 01:01:24 +0200 Subject: [PATCH 0628/2777] winex11.drv: Support multiple vulkan surfaces per HWND. Fixes games failing to render after displaying a video, e.g. Age of Empires II (2013). https://github.com/doitsujin/dxvk/issues/1726 --- dlls/winex11.drv/vulkan.c | 51 ++++++++++++++++++++------------------- dlls/winex11.drv/window.c | 2 +- dlls/winex11.drv/x11drv.h | 2 +- 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index abebef29b1c..d50b40eab56 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -50,7 +50,6 @@ WINE_DECLARE_DEBUG_CHANNEL(fps); static pthread_mutex_t vulkan_mutex; -static XContext vulkan_hwnd_context; static XContext vulkan_swapchain_context; #define VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR 1000004000 @@ -153,7 +152,6 @@ static void wine_vk_init(void) #undef LOAD_FUNCPTR #undef LOAD_OPTIONAL_FUNCPTR - vulkan_hwnd_context = XUniqueContext(); vulkan_swapchain_context = XUniqueContext(); return; @@ -239,23 +237,30 @@ static void wine_vk_surface_release(struct wine_vk_surface *surface) free(surface); } -void wine_vk_surface_destroy(HWND hwnd) +void wine_vk_surface_destroy(struct wine_vk_surface *surface) { - struct wine_vk_surface *surface; - HDC hdc = 0; + TRACE("Detaching surface %p, hwnd %p.\n", surface, surface->hwnd); + XReparentWindow(gdi_display, surface->window, get_dummy_parent(), 0, 0); + XSync(gdi_display, False); + if (surface->hdc) NtUserReleaseDC(surface->hwnd, surface->hdc); + surface->hwnd_thread_id = 0; + surface->hwnd = 0; + surface->hdc = 0; + wine_vk_surface_release(surface); +} + +void destroy_vk_surface(HWND hwnd) +{ + struct wine_vk_surface *surface, *next; pthread_mutex_lock(&vulkan_mutex); - if (!XFindContext(gdi_display, (XID)hwnd, vulkan_hwnd_context, (char **)&surface)) + LIST_FOR_EACH_ENTRY_SAFE(surface, next, &surface_list, struct wine_vk_surface, entry) { - hdc = surface->hdc; - surface->hwnd_thread_id = 0; - surface->hwnd = 0; - surface->hdc = 0; - wine_vk_surface_release(surface); + if (surface->hwnd != hwnd) + continue; + wine_vk_surface_destroy(surface); } - XDeleteContext(gdi_display, (XID)hwnd, vulkan_hwnd_context); pthread_mutex_unlock(&vulkan_mutex); - if (hdc) NtUserReleaseDC(hwnd, hdc); } static BOOL wine_vk_surface_set_offscreen(struct wine_vk_surface *surface, BOOL offscreen) @@ -287,8 +292,12 @@ void sync_vk_surface(HWND hwnd, BOOL known_child) { struct wine_vk_surface *surface; pthread_mutex_lock(&vulkan_mutex); - if (!XFindContext(gdi_display, (XID)hwnd, vulkan_hwnd_context, (char **)&surface)) + LIST_FOR_EACH_ENTRY(surface, &surface_list, struct wine_vk_surface, entry) + { + if (surface->hwnd != hwnd) + continue; wine_vk_surface_set_offscreen(surface, known_child); + } pthread_mutex_unlock(&vulkan_mutex); } @@ -302,11 +311,7 @@ void vulkan_thread_detach(void) { if (surface->hwnd_thread_id != thread_id) continue; - - TRACE("Detaching surface %p, hwnd %p.\n", surface, surface->hwnd); - XReparentWindow(gdi_display, surface->window, get_dummy_parent(), 0, 0); - XSync(gdi_display, False); - wine_vk_surface_destroy(surface->hwnd); + wine_vk_surface_destroy(surface); } pthread_mutex_unlock(&vulkan_mutex); } @@ -430,6 +435,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, TRACE("Creation window not provided\n"); else if (NtUserGetWindowRelative( parent, GW_CHILD ) || NtUserGetAncestor( parent, GA_PARENT ) != NtUserGetDesktopWindow()) { + TRACE("hwnd %p creating offscreen child window surface\n", x11_surface->hwnd); if (!wine_vk_surface_set_offscreen(x11_surface, TRUE)) { res = VK_ERROR_INCOMPATIBLE_DRIVER; @@ -451,11 +457,6 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, } pthread_mutex_lock(&vulkan_mutex); - if (x11_surface->hwnd) - { - wine_vk_surface_destroy( x11_surface->hwnd ); - XSaveContext(gdi_display, (XID)create_info->hwnd, vulkan_hwnd_context, (char *)wine_vk_surface_grab(x11_surface)); - } list_add_tail(&surface_list, &x11_surface->entry); pthread_mutex_unlock(&vulkan_mutex); @@ -908,7 +909,7 @@ const struct vulkan_funcs *get_vulkan_driver(UINT version) return NULL; } -void wine_vk_surface_destroy(HWND hwnd) +void destroy_vk_surface(HWND hwnd) { } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 4fc9f579cd9..459b631ec54 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2093,7 +2093,7 @@ void X11DRV_DestroyWindow( HWND hwnd ) release_win_data( data ); free( data ); destroy_gl_drawable( hwnd ); - wine_vk_surface_destroy( hwnd ); + destroy_vk_surface( hwnd ); } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 06264d333cd..81c318af9a6 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -668,7 +668,7 @@ extern Window get_dummy_parent(void) DECLSPEC_HIDDEN; extern void sync_gl_drawable( HWND hwnd, BOOL known_child ) DECLSPEC_HIDDEN; extern void set_gl_drawable_parent( HWND hwnd, HWND parent ) DECLSPEC_HIDDEN; extern void destroy_gl_drawable( HWND hwnd ) DECLSPEC_HIDDEN; -extern void wine_vk_surface_destroy( HWND hwnd ) DECLSPEC_HIDDEN; +extern void destroy_vk_surface( HWND hwnd ) DECLSPEC_HIDDEN; extern void sync_vk_surface( HWND hwnd, BOOL known_child ) DECLSPEC_HIDDEN; extern void vulkan_thread_detach(void) DECLSPEC_HIDDEN; From 544bd97c1c2e713a761a583be7286c3effa05b0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 22 Oct 2021 00:12:16 +0200 Subject: [PATCH 0629/2777] winex11.drv: Resize vulkan surfaces client rect size changes. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45277 CW-Bug-Id: 16608 --- dlls/winex11.drv/vulkan.c | 16 ++++++++++++++++ dlls/winex11.drv/window.c | 1 + dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 18 insertions(+) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index d50b40eab56..21ec0729691 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -288,6 +288,18 @@ static BOOL wine_vk_surface_set_offscreen(struct wine_vk_surface *surface, BOOL return !offscreen; } +void resize_vk_surfaces(HWND hwnd, Window active, int mask, XWindowChanges *changes) +{ + struct wine_vk_surface *surface; + pthread_mutex_lock(&vulkan_mutex); + LIST_FOR_EACH_ENTRY(surface, &surface_list, struct wine_vk_surface, entry) + { + if (surface->hwnd != hwnd) continue; + if (surface->window != active) XConfigureWindow(gdi_display, surface->window, mask, changes); + } + pthread_mutex_unlock(&vulkan_mutex); +} + void sync_vk_surface(HWND hwnd, BOOL known_child) { struct wine_vk_surface *surface; @@ -913,6 +925,10 @@ void destroy_vk_surface(HWND hwnd) { } +void resize_vk_surfaces(HWND hwnd, Window active, int mask, XWindowChanges changes) +{ +} + void sync_vk_surface(HWND hwnd, BOOL known_child) { } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 459b631ec54..752fee6f803 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1657,6 +1657,7 @@ static void sync_client_position( struct x11drv_win_data *data, TRACE( "setting client win %lx pos %d,%d,%dx%d changes=%x\n", data->client_window, changes.x, changes.y, changes.width, changes.height, mask ); XConfigureWindow( data->display, data->client_window, mask, &changes ); + resize_vk_surfaces( data->hwnd, data->client_window, mask, &changes ); } } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 81c318af9a6..81f1bf4576d 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -670,6 +670,7 @@ extern void set_gl_drawable_parent( HWND hwnd, HWND parent ) DECLSPEC_HIDDEN; extern void destroy_gl_drawable( HWND hwnd ) DECLSPEC_HIDDEN; extern void destroy_vk_surface( HWND hwnd ) DECLSPEC_HIDDEN; extern void sync_vk_surface( HWND hwnd, BOOL known_child ) DECLSPEC_HIDDEN; +extern void resize_vk_surfaces( HWND hwnd, Window active, int mask, XWindowChanges *changes ) DECLSPEC_HIDDEN; extern void vulkan_thread_detach(void) DECLSPEC_HIDDEN; extern void wait_for_withdrawn_state( HWND hwnd, BOOL set ) DECLSPEC_HIDDEN; From 6c30500e3115b53121518b1442d731209272bb70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 22 Oct 2021 00:22:00 +0200 Subject: [PATCH 0630/2777] winex11.drv: Update client_window pointer on surface destroy. To prevent reusing already destroyed client_window with the thread display requests. This lets us restore another client window, as the primary client window. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45277 CW-Bug-Id: 16608 --- dlls/winex11.drv/vulkan.c | 20 ++++++++++++++++++++ dlls/winex11.drv/window.c | 16 ++++++++++++++++ dlls/winex11.drv/x11drv.h | 2 ++ 3 files changed, 38 insertions(+) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 21ec0729691..a2c33eefac6 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -313,6 +313,24 @@ void sync_vk_surface(HWND hwnd, BOOL known_child) pthread_mutex_unlock(&vulkan_mutex); } +Window wine_vk_active_surface( HWND hwnd ) +{ + struct wine_vk_surface *surface, *active = NULL; + Window window; + + pthread_mutex_lock(&vulkan_mutex); + LIST_FOR_EACH_ENTRY(surface, &surface_list, struct wine_vk_surface, entry) + { + if (surface->hwnd != hwnd) continue; + active = surface; + } + if (!active) window = None; + else window = active->window; + pthread_mutex_unlock(&vulkan_mutex); + + return window; +} + void vulkan_thread_detach(void) { struct wine_vk_surface *surface, *next; @@ -496,6 +514,7 @@ static void X11DRV_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface const VkAllocationCallbacks *allocator) { struct wine_vk_surface *x11_surface = surface_from_handle(surface); + HWND hwnd = x11_surface->hwnd; TRACE("%p 0x%s %p\n", instance, wine_dbgstr_longlong(surface), allocator); @@ -508,6 +527,7 @@ static void X11DRV_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface pvkDestroySurfaceKHR(instance, x11_surface->surface, NULL /* allocator */); wine_vk_surface_release(x11_surface); + update_client_window(hwnd); } } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 752fee6f803..39e7d650534 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1762,6 +1762,22 @@ Window get_dummy_parent(void) } +/********************************************************************** + * update_client_window + */ +void update_client_window( HWND hwnd ) +{ + struct x11drv_win_data *data; + if ((data = get_win_data( hwnd ))) + { + data->client_window = wine_vk_active_surface( hwnd ); + /* make sure any request that could use old client window has been flushed */ + XFlush( data->display ); + release_win_data( data ); + } +} + + /********************************************************************** * create_dummy_client_window */ diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 81f1bf4576d..e1c4a144172 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -671,6 +671,7 @@ extern void destroy_gl_drawable( HWND hwnd ) DECLSPEC_HIDDEN; extern void destroy_vk_surface( HWND hwnd ) DECLSPEC_HIDDEN; extern void sync_vk_surface( HWND hwnd, BOOL known_child ) DECLSPEC_HIDDEN; extern void resize_vk_surfaces( HWND hwnd, Window active, int mask, XWindowChanges *changes ) DECLSPEC_HIDDEN; +extern Window wine_vk_active_surface( HWND hwnd ) DECLSPEC_HIDDEN; extern void vulkan_thread_detach(void) DECLSPEC_HIDDEN; extern void wait_for_withdrawn_state( HWND hwnd, BOOL set ) DECLSPEC_HIDDEN; @@ -681,6 +682,7 @@ extern void update_net_wm_states( struct x11drv_win_data *data ) DECLSPEC_HIDDEN extern void make_window_embedded( struct x11drv_win_data *data ) DECLSPEC_HIDDEN; extern Window create_dummy_client_window(void) DECLSPEC_HIDDEN; extern Window create_client_window( HWND hwnd, const XVisualInfo *visual ) DECLSPEC_HIDDEN; +extern void update_client_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *vis, BOOL use_alpha ) DECLSPEC_HIDDEN; extern void change_systray_owner( Display *display, Window systray_window ) DECLSPEC_HIDDEN; extern HWND create_foreign_window( Display *display, Window window ) DECLSPEC_HIDDEN; From 72229b58aa797bcac364968be89a12f8a607893d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 12:10:00 +0100 Subject: [PATCH 0631/2777] winex11.drv: Support concurrent Vulkan surfaces using XComposite. --- dlls/winex11.drv/vulkan.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index a2c33eefac6..1cacdca5cfb 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -63,6 +63,7 @@ struct wine_vk_surface Window window; VkSurfaceKHR surface; /* native surface */ VkPresentModeKHR present_mode; + BOOL known_child; /* hwnd is or has a child */ BOOL offscreen; /* drawable is offscreen */ HDC hdc; HWND hwnd; @@ -303,12 +304,21 @@ void resize_vk_surfaces(HWND hwnd, Window active, int mask, XWindowChanges *chan void sync_vk_surface(HWND hwnd, BOOL known_child) { struct wine_vk_surface *surface; + UINT surface_count = 0; + pthread_mutex_lock(&vulkan_mutex); LIST_FOR_EACH_ENTRY(surface, &surface_list, struct wine_vk_surface, entry) { - if (surface->hwnd != hwnd) - continue; - wine_vk_surface_set_offscreen(surface, known_child); + if (surface->hwnd != hwnd) continue; + surface->known_child = known_child; + surface_count++; + } + TRACE("hwnd %p surface_count %u known_child %u\n", hwnd, surface_count, known_child); + LIST_FOR_EACH_ENTRY(surface, &surface_list, struct wine_vk_surface, entry) + { + if (surface->hwnd != hwnd) continue; + if (surface_count > 1) wine_vk_surface_set_offscreen(surface, TRUE); + else wine_vk_surface_set_offscreen(surface, known_child); } pthread_mutex_unlock(&vulkan_mutex); } @@ -316,6 +326,7 @@ void sync_vk_surface(HWND hwnd, BOOL known_child) Window wine_vk_active_surface( HWND hwnd ) { struct wine_vk_surface *surface, *active = NULL; + UINT surface_count = 0; Window window; pthread_mutex_lock(&vulkan_mutex); @@ -323,9 +334,16 @@ Window wine_vk_active_surface( HWND hwnd ) { if (surface->hwnd != hwnd) continue; active = surface; + surface_count++; } if (!active) window = None; - else window = active->window; + else + { + TRACE("hwnd %p surface_count %u known_child %u\n", hwnd, surface_count, active->known_child); + if (surface_count > 1) wine_vk_surface_set_offscreen(active, TRUE); + else wine_vk_surface_set_offscreen(active, active->known_child); + window = active->window; + } pthread_mutex_unlock(&vulkan_mutex); return window; @@ -427,7 +445,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, { VkResult res; VkXlibSurfaceCreateInfoKHR create_info_host; - struct wine_vk_surface *x11_surface; + struct wine_vk_surface *x11_surface, *other; HWND parent; TRACE("%p %p %p %p\n", instance, create_info, allocator, surface); @@ -441,6 +459,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, x11_surface->ref = 1; x11_surface->hwnd = create_info->hwnd; + x11_surface->known_child = FALSE; if (x11_surface->hwnd) { x11_surface->hdc = NtUserGetDC(create_info->hwnd); @@ -465,6 +484,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, TRACE("Creation window not provided\n"); else if (NtUserGetWindowRelative( parent, GW_CHILD ) || NtUserGetAncestor( parent, GA_PARENT ) != NtUserGetDesktopWindow()) { + x11_surface->known_child = TRUE; TRACE("hwnd %p creating offscreen child window surface\n", x11_surface->hwnd); if (!wine_vk_surface_set_offscreen(x11_surface, TRUE)) { @@ -487,6 +507,13 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, } pthread_mutex_lock(&vulkan_mutex); + LIST_FOR_EACH_ENTRY(other, &surface_list, struct wine_vk_surface, entry) + { + if (other->hwnd != x11_surface->hwnd) continue; + TRACE("hwnd %p already has a swapchain, moving surface offscreen\n", x11_surface->hwnd); + wine_vk_surface_set_offscreen(other, TRUE); + wine_vk_surface_set_offscreen(x11_surface, TRUE); + } list_add_tail(&surface_list, &x11_surface->entry); pthread_mutex_unlock(&vulkan_mutex); From cf1a2abe9ae63157016b7bf853b1c21cc0472b66 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 22 Nov 2021 20:00:43 +0200 Subject: [PATCH 0632/2777] winex11: Consider only Vulkan surfaces with swapchains for offscreen rendering. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "A native window cannot be associated with more than one non-retired swapchain at a time."[1] The hack introduced in 81f5a09134e5 ("winex11: Allow multiple vulkan surfaces per hwnd") sends surfaces for offscreen rendering using XComposite when there are multiple surfaces associated with a single hwnd. That's overzealous though, as some of the swapchains may be already destroyed. E.g. DOOM Eternal with vsync enabled does the following: vkCreateWin32SurfaceKHR(vk_inst, &surface_create_info, NULL, &old_surface) vkCreateSwapchainKHR(vk_inst, &sc_create_info, NULL, &old_sc); vkDestroySwapchainKHR(vk_inst, old_sc, NULL); /* old_surface never gets destroyed */ vkCreateWin32SurfaceKHR(vk_inst, &surface_create_info, NULL, &new_surface); vkCreateSwapchainKHR(vk_inst, &sc_create_info, NULL, &new_swapchain); Which makes the hack kick in and degrades the performance. This change makes sure that we only count surfaces that have any swapchains associated with them, whether they are retired or not. That's a bit of oversimplification, as swapchain can get retired without new swapchain being created: "Upon calling vkCreateSwapchainKHR with an oldSwapchain that is not VK_NULL_HANDLE, oldSwapchain is retired — even if creation of the new swapchain fails. The new swapchain is created in the non-retired state whether or not oldSwapchain is VK_NULL_HANDLE."[2] but that's unlikely to happen and cause problems. [1]: https://khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkSwapchainKHR.html [2]: https://khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkSwapchainCreateInfoKHR.html CW-Bug-Id: #19666 --- dlls/winex11.drv/vulkan.c | 47 ++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 1cacdca5cfb..629cb9d1ea3 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -65,6 +65,7 @@ struct wine_vk_surface VkPresentModeKHR present_mode; BOOL known_child; /* hwnd is or has a child */ BOOL offscreen; /* drawable is offscreen */ + LONG swapchain_count; /* surface can have one active an many retired swapchains */ HDC hdc; HWND hwnd; DWORD hwnd_thread_id; @@ -304,43 +305,43 @@ void resize_vk_surfaces(HWND hwnd, Window active, int mask, XWindowChanges *chan void sync_vk_surface(HWND hwnd, BOOL known_child) { struct wine_vk_surface *surface; - UINT surface_count = 0; + UINT surface_with_swapchain_count = 0; pthread_mutex_lock(&vulkan_mutex); LIST_FOR_EACH_ENTRY(surface, &surface_list, struct wine_vk_surface, entry) { if (surface->hwnd != hwnd) continue; + if (surface->swapchain_count) surface_with_swapchain_count++; surface->known_child = known_child; - surface_count++; } - TRACE("hwnd %p surface_count %u known_child %u\n", hwnd, surface_count, known_child); + TRACE("hwnd %p surface_with_swapchain_count %u known_child %u\n", hwnd, surface_with_swapchain_count, known_child); LIST_FOR_EACH_ENTRY(surface, &surface_list, struct wine_vk_surface, entry) { if (surface->hwnd != hwnd) continue; - if (surface_count > 1) wine_vk_surface_set_offscreen(surface, TRUE); + if (surface_with_swapchain_count > 1) wine_vk_surface_set_offscreen(surface, TRUE); else wine_vk_surface_set_offscreen(surface, known_child); } pthread_mutex_unlock(&vulkan_mutex); } -Window wine_vk_active_surface( HWND hwnd ) +Window wine_vk_active_surface(HWND hwnd) { struct wine_vk_surface *surface, *active = NULL; - UINT surface_count = 0; + UINT surface_with_swapchain_count = 0; Window window; pthread_mutex_lock(&vulkan_mutex); LIST_FOR_EACH_ENTRY(surface, &surface_list, struct wine_vk_surface, entry) { if (surface->hwnd != hwnd) continue; + if (surface->swapchain_count) surface_with_swapchain_count++; active = surface; - surface_count++; } if (!active) window = None; else { - TRACE("hwnd %p surface_count %u known_child %u\n", hwnd, surface_count, active->known_child); - if (surface_count > 1) wine_vk_surface_set_offscreen(active, TRUE); + TRACE("hwnd %p surface_with_swapchain_count %u known_child %u\n", hwnd, surface_with_swapchain_count, active->known_child); + if (surface_with_swapchain_count > 1) wine_vk_surface_set_offscreen(active, TRUE); else wine_vk_surface_set_offscreen(active, active->known_child); window = active->window; } @@ -409,7 +410,7 @@ static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *create_info, const VkAllocationCallbacks *allocator, VkSwapchainKHR *swapchain) { - struct wine_vk_surface *x11_surface = surface_from_handle(create_info->surface); + struct wine_vk_surface *other, *x11_surface = surface_from_handle(create_info->surface); VkSwapchainCreateInfoKHR create_info_host; VkResult result; @@ -429,13 +430,22 @@ static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device, create_info_host.presentMode = VK_PRESENT_MODE_FIFO_KHR; x11_surface->present_mode = create_info->presentMode; + pthread_mutex_lock(&vulkan_mutex); + LIST_FOR_EACH_ENTRY(other, &surface_list, struct wine_vk_surface, entry) + { + if (other->hwnd != x11_surface->hwnd) continue; + if (!other->swapchain_count) continue; + TRACE("hwnd %p already has a swapchain, moving surface offscreen\n", x11_surface->hwnd); + wine_vk_surface_set_offscreen(other, TRUE); + wine_vk_surface_set_offscreen(x11_surface, TRUE); + } result = pvkCreateSwapchainKHR(device, &create_info_host, NULL /* allocator */, swapchain); if (result == VK_SUCCESS) { - pthread_mutex_lock(&vulkan_mutex); + x11_surface->swapchain_count++; XSaveContext(gdi_display, (XID)(*swapchain), vulkan_swapchain_context, (char *)wine_vk_surface_grab(x11_surface)); - pthread_mutex_unlock(&vulkan_mutex); } + pthread_mutex_unlock(&vulkan_mutex); return result; } @@ -445,7 +455,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, { VkResult res; VkXlibSurfaceCreateInfoKHR create_info_host; - struct wine_vk_surface *x11_surface, *other; + struct wine_vk_surface *x11_surface; HWND parent; TRACE("%p %p %p %p\n", instance, create_info, allocator, surface); @@ -460,6 +470,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, x11_surface->ref = 1; x11_surface->hwnd = create_info->hwnd; x11_surface->known_child = FALSE; + x11_surface->swapchain_count = 0; if (x11_surface->hwnd) { x11_surface->hdc = NtUserGetDC(create_info->hwnd); @@ -507,13 +518,6 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, } pthread_mutex_lock(&vulkan_mutex); - LIST_FOR_EACH_ENTRY(other, &surface_list, struct wine_vk_surface, entry) - { - if (other->hwnd != x11_surface->hwnd) continue; - TRACE("hwnd %p already has a swapchain, moving surface offscreen\n", x11_surface->hwnd); - wine_vk_surface_set_offscreen(other, TRUE); - wine_vk_surface_set_offscreen(x11_surface, TRUE); - } list_add_tail(&surface_list, &x11_surface->entry); pthread_mutex_unlock(&vulkan_mutex); @@ -572,7 +576,10 @@ static void X11DRV_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapcha pthread_mutex_lock(&vulkan_mutex); if (!XFindContext(gdi_display, (XID)swapchain, vulkan_swapchain_context, (char **)&surface)) + { + surface->swapchain_count--; wine_vk_surface_release(surface); + } XDeleteContext(gdi_display, (XID)swapchain, vulkan_swapchain_context); pthread_mutex_unlock(&vulkan_mutex); } From ad40cdcb153bee6981cdab40e99933c5630d9999 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Tue, 23 Nov 2021 13:54:34 +0200 Subject: [PATCH 0633/2777] winex11: Don't consider swapchain-less Vulkan surfaces active. --- dlls/winex11.drv/vulkan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 629cb9d1ea3..6574b483ee1 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -334,8 +334,9 @@ Window wine_vk_active_surface(HWND hwnd) LIST_FOR_EACH_ENTRY(surface, &surface_list, struct wine_vk_surface, entry) { if (surface->hwnd != hwnd) continue; - if (surface->swapchain_count) surface_with_swapchain_count++; + if (!surface->swapchain_count) continue; active = surface; + surface_with_swapchain_count++; } if (!active) window = None; else From 54ecfca27da20e7a30297c27294751d5c43d7526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 20 Jan 2023 11:48:36 +0100 Subject: [PATCH 0634/2777] winex11: Keep a vulkan surface reference in the surface list. We will release the from the list, in destroy_vk_surface, and not having a reference causes use after free. CW-Bug-Id: 16608 CW-Bug-Id: 21817 --- dlls/winex11.drv/vulkan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 6574b483ee1..aa097d2095c 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -522,7 +522,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, list_add_tail(&surface_list, &x11_surface->entry); pthread_mutex_unlock(&vulkan_mutex); - *surface = (uintptr_t)x11_surface; + *surface = (uintptr_t)wine_vk_surface_grab(x11_surface); TRACE("Created surface=0x%s\n", wine_dbgstr_longlong(*surface)); return VK_SUCCESS; From c46b1bee66abb1d76e5584b532e9f0e15f45fd1c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 22 Feb 2022 18:11:13 +0300 Subject: [PATCH 0635/2777] winex11.drv: Also treat VK_SUBOPTIMAL_KHR as success in X11DRV_vkAcquireNextImageKHR(). CW-Bug-Id: #20200 --- dlls/winex11.drv/vulkan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index aa097d2095c..18e5d71a3ee 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -845,7 +845,7 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, } result = pvkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, image_index); - if (result == VK_SUCCESS && hdc && surface && surface->offscreen) + if ((result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) && hdc && surface && surface->offscreen) { if (wait_fence) pvkWaitForFences(device, 1, &fence, 0, timeout); escape.code = X11DRV_PRESENT_DRAWABLE; From 1f8722b1882e244ee9d80eb1a7508cc445a92c04 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 9 May 2022 12:44:00 -0500 Subject: [PATCH 0636/2777] winex11.drv: Reparent client window back to whole window when reactivating it. CW-Bug-Id: #20614 Related to Vulkan child window / multiple swapchains handling, specificall this commit: "winex11.drv: Update client_window pointer on surface destroy." When the client window is replaced by the new one it gets reparented to dummy window (effectively hidden). When another swapchain gets deleted and the previous client window is brought back onscreen, in the current logic it makes sense to make it visible child of the whole window again. --- dlls/winex11.drv/window.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 39e7d650534..195e113f4c6 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1768,9 +1768,19 @@ Window get_dummy_parent(void) void update_client_window( HWND hwnd ) { struct x11drv_win_data *data; + Window old_active; + if ((data = get_win_data( hwnd ))) { + old_active = data->client_window; data->client_window = wine_vk_active_surface( hwnd ); + if (data->client_window && data->whole_window && old_active != data->client_window) + { + TRACE( "%p reparent xwin %lx/%lx\n", data->hwnd, data->whole_window, data->client_window ); + XReparentWindow( data->display, data->client_window, data->whole_window, + data->client_rect.left - data->whole_rect.left, + data->client_rect.top - data->whole_rect.top ); + } /* make sure any request that could use old client window has been flushed */ XFlush( data->display ); release_win_data( data ); From fd848e9cc3daf3477bad6194390a8a7b19b248a6 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 20 May 2022 16:20:29 -0500 Subject: [PATCH 0637/2777] winex11.drv: Also call sync_vk_surface() for the child window when WS_CHILD is changed. CW-Bug-Id: #19945 --- dlls/winex11.drv/window.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 195e113f4c6..1723efeb802 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2075,6 +2075,7 @@ void X11DRV_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style ) sync_vk_surface( parent, TRUE ); else sync_vk_surface( parent, FALSE ); + sync_vk_surface( hwnd, style->styleNew & WS_CHILD ); } if (hwnd == NtUserGetDesktopWindow()) return; From d9ac5d07f2d61784c332f6ce8db9675196fb22a0 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Sun, 22 May 2022 12:53:05 -0500 Subject: [PATCH 0638/2777] winex11.drv: Get window DC each time for blitting. Keeping it since the surface creation doesn't look right, it may affect app's GDI operations and window may be deleted while the surface stays valid. CW-Bug-Id: #20680 --- dlls/winex11.drv/vulkan.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 18e5d71a3ee..4745aa3982c 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -66,7 +66,6 @@ struct wine_vk_surface BOOL known_child; /* hwnd is or has a child */ BOOL offscreen; /* drawable is offscreen */ LONG swapchain_count; /* surface can have one active an many retired swapchains */ - HDC hdc; HWND hwnd; DWORD hwnd_thread_id; }; @@ -245,10 +244,8 @@ void wine_vk_surface_destroy(struct wine_vk_surface *surface) XReparentWindow(gdi_display, surface->window, get_dummy_parent(), 0, 0); XSync(gdi_display, False); - if (surface->hdc) NtUserReleaseDC(surface->hwnd, surface->hdc); surface->hwnd_thread_id = 0; surface->hwnd = 0; - surface->hdc = 0; wine_vk_surface_release(surface); } @@ -474,7 +471,6 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, x11_surface->swapchain_count = 0; if (x11_surface->hwnd) { - x11_surface->hdc = NtUserGetDC(create_info->hwnd); x11_surface->window = create_client_window(create_info->hwnd, &default_visual); x11_surface->hwnd_thread_id = NtUserGetWindowThread(x11_surface->hwnd, NULL); } @@ -822,10 +818,7 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, pthread_mutex_lock(&vulkan_mutex); if (!XFindContext(gdi_display, (XID)swapchain, vulkan_swapchain_context, (char **)&surface)) - { wine_vk_surface_grab(surface); - hdc = surface->hdc; - } pthread_mutex_unlock(&vulkan_mutex); if (!surface || !surface->offscreen) @@ -845,7 +838,11 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, } result = pvkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, image_index); - if ((result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) && hdc && surface && surface->offscreen) + + if ((result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) && surface && surface->offscreen) + hdc = NtUserGetDCEx(surface->hwnd, 0, DCX_USESTYLE | DCX_CACHE); + + if (hdc) { if (wait_fence) pvkWaitForFences(device, 1, &fence, 0, timeout); escape.code = X11DRV_PRESENT_DRAWABLE; @@ -854,6 +851,7 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, NtGdiExtEscape(hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (char *)&escape, 0, NULL); if (surface->present_mode == VK_PRESENT_MODE_MAILBOX_KHR) if (once++) FIXME("Application requires child window rendering with mailbox present mode, expect possible tearing!\n"); + NtUserReleaseDC(surface->hwnd, hdc); } if (fence != orig_fence) pvkDestroyFence(device, fence, NULL); From 95656f6a95e38f10f4fdfd370071ee5f01c022dc Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 20 May 2022 18:45:15 -0500 Subject: [PATCH 0639/2777] winex11.drv: HACK: Add an option to support GDI blits from unmapped Vulkan windows. And enable it for Disgaea 5 Complete. CW-Bug-Id: #19945 --- dlls/winex11.drv/vulkan.c | 89 +++++++++++++++++++++++++++++----- dlls/winex11.drv/window.c | 7 +++ dlls/winex11.drv/x11drv.h | 2 + dlls/winex11.drv/x11drv_main.c | 8 +++ 4 files changed, 95 insertions(+), 11 deletions(-) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 4745aa3982c..6cbfb6d9fa6 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -68,6 +68,7 @@ struct wine_vk_surface LONG swapchain_count; /* surface can have one active an many retired swapchains */ HWND hwnd; DWORD hwnd_thread_id; + BOOL gdi_blit_source; /* HACK: gdi blits from the window should work with Vulkan rendered contents. */ }; typedef struct VkXlibSurfaceCreateInfoKHR @@ -262,6 +263,17 @@ void destroy_vk_surface(HWND hwnd) pthread_mutex_unlock(&vulkan_mutex); } +static void set_dc_drawable( HDC hdc, Drawable drawable, const RECT *rect ) +{ + struct x11drv_escape_set_drawable escape; + + escape.code = X11DRV_SET_DRAWABLE; + escape.mode = IncludeInferiors; + escape.drawable = drawable; + escape.dc_rect = *rect; + NtGdiExtEscape( hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); +} + static BOOL wine_vk_surface_set_offscreen(struct wine_vk_surface *surface, BOOL offscreen) { #ifdef SONAME_LIBXCOMPOSITE @@ -316,7 +328,7 @@ void sync_vk_surface(HWND hwnd, BOOL known_child) { if (surface->hwnd != hwnd) continue; if (surface_with_swapchain_count > 1) wine_vk_surface_set_offscreen(surface, TRUE); - else wine_vk_surface_set_offscreen(surface, known_child); + else wine_vk_surface_set_offscreen(surface, known_child || surface->gdi_blit_source); } pthread_mutex_unlock(&vulkan_mutex); } @@ -331,7 +343,7 @@ Window wine_vk_active_surface(HWND hwnd) LIST_FOR_EACH_ENTRY(surface, &surface_list, struct wine_vk_surface, entry) { if (surface->hwnd != hwnd) continue; - if (!surface->swapchain_count) continue; + if (!surface->swapchain_count || surface->gdi_blit_source) continue; active = surface; surface_with_swapchain_count++; } @@ -348,6 +360,25 @@ Window wine_vk_active_surface(HWND hwnd) return window; } +BOOL wine_vk_direct_window_draw( HWND hwnd ) +{ + struct wine_vk_surface *surface; + BOOL ret = FALSE; + + pthread_mutex_lock(&vulkan_mutex); + LIST_FOR_EACH_ENTRY(surface, &surface_list, struct wine_vk_surface, entry) + { + if (surface->hwnd != hwnd) continue; + if (surface->gdi_blit_source) + { + ret = TRUE; + break; + } + } + pthread_mutex_unlock(&vulkan_mutex); + return ret; +} + void vulkan_thread_detach(void) { struct wine_vk_surface *surface, *next; @@ -488,11 +519,26 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, goto err; } + if (vulkan_gdi_blit_source_hack) + { + RECT rect; + + NtUserGetWindowRect( create_info->hwnd, &rect ); + if (!is_window_rect_mapped( &rect )) + { + FIXME("HACK: setting gdi_blit_source for hwnd %p, surface %p.\n", x11_surface->hwnd, x11_surface); + x11_surface->gdi_blit_source = TRUE; + XReparentWindow( gdi_display, x11_surface->window, get_dummy_parent(), 0, 0 ); + } + } + if (!(parent = create_info->hwnd)) - TRACE("Creation window not provided\n"); + x11_surface->known_child = FALSE; else if (NtUserGetWindowRelative( parent, GW_CHILD ) || NtUserGetAncestor( parent, GA_PARENT ) != NtUserGetDesktopWindow()) - { x11_surface->known_child = TRUE; + + if (x11_surface->known_child || x11_surface->gdi_blit_source) + { TRACE("hwnd %p creating offscreen child window surface\n", x11_surface->hwnd); if (!wine_vk_surface_set_offscreen(x11_surface, TRUE)) { @@ -520,6 +566,13 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, *surface = (uintptr_t)wine_vk_surface_grab(x11_surface); + if (x11_surface->gdi_blit_source) + { + /* Make sure window gets surface destroyed. */ + UINT flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW | + SWP_DEFERERASE | SWP_NOSENDCHANGING | SWP_STATECHANGED; + NtUserSetWindowPos( x11_surface->hwnd, 0, 0, 0, 0, 0, flags ); + } TRACE("Created surface=0x%s\n", wine_dbgstr_longlong(*surface)); return VK_SUCCESS; @@ -811,10 +864,12 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, static int once; struct x11drv_escape_present_drawable escape; struct wine_vk_surface *surface = NULL; + DWORD dc_flags = DCX_USESTYLE; VkResult result; VkFence orig_fence; BOOL wait_fence = FALSE; HDC hdc = 0; + RECT rect; pthread_mutex_lock(&vulkan_mutex); if (!XFindContext(gdi_display, (XID)swapchain, vulkan_swapchain_context, (char **)&surface)) @@ -840,17 +895,29 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, result = pvkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, image_index); if ((result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) && surface && surface->offscreen) - hdc = NtUserGetDCEx(surface->hwnd, 0, DCX_USESTYLE | DCX_CACHE); + { + if (!surface->gdi_blit_source) + dc_flags |= DCX_CACHE; + hdc = NtUserGetDCEx(surface->hwnd, 0, dc_flags); + } if (hdc) { if (wait_fence) pvkWaitForFences(device, 1, &fence, 0, timeout); - escape.code = X11DRV_PRESENT_DRAWABLE; - escape.drawable = surface->window; - escape.flush = TRUE; - NtGdiExtEscape(hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (char *)&escape, 0, NULL); - if (surface->present_mode == VK_PRESENT_MODE_MAILBOX_KHR) - if (once++) FIXME("Application requires child window rendering with mailbox present mode, expect possible tearing!\n"); + if (surface->gdi_blit_source) + { + NtUserGetClientRect( surface->hwnd, &rect ); + set_dc_drawable( hdc, surface->window, &rect ); + } + else + { + escape.code = X11DRV_PRESENT_DRAWABLE; + escape.drawable = surface->window; + escape.flush = TRUE; + NtGdiExtEscape(hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (char *)&escape, 0, NULL); + if (surface->present_mode == VK_PRESENT_MODE_MAILBOX_KHR) + if (once++) FIXME("Application requires child window rendering with mailbox present mode, expect possible tearing!\n"); + } NtUserReleaseDC(surface->hwnd, hdc); } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 1723efeb802..8c8a432754e 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2857,6 +2857,13 @@ BOOL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags, if (!data->whole_window && !data->embedded) goto done; if (swp_flags & SWP_HIDEWINDOW) goto done; if (data->use_alpha) goto done; + + if (wine_vk_direct_window_draw( hwnd )) + { + if (*surface) window_surface_release( *surface ); + *surface = NULL; + goto done; + } if (!get_surface_rect( visible_rect, &surface_rect )) goto done; if (*surface) window_surface_release( *surface ); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index e1c4a144172..1c53c4a3275 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -672,6 +672,7 @@ extern void destroy_vk_surface( HWND hwnd ) DECLSPEC_HIDDEN; extern void sync_vk_surface( HWND hwnd, BOOL known_child ) DECLSPEC_HIDDEN; extern void resize_vk_surfaces( HWND hwnd, Window active, int mask, XWindowChanges *changes ) DECLSPEC_HIDDEN; extern Window wine_vk_active_surface( HWND hwnd ) DECLSPEC_HIDDEN; +extern BOOL wine_vk_direct_window_draw( HWND hwnd ) DECLSPEC_HIDDEN; extern void vulkan_thread_detach(void) DECLSPEC_HIDDEN; extern void wait_for_withdrawn_state( HWND hwnd, BOOL set ) DECLSPEC_HIDDEN; @@ -964,5 +965,6 @@ static inline UINT asciiz_to_unicode( WCHAR *dst, const char *src ) } extern BOOL layered_window_client_hack; +extern BOOL vulkan_gdi_blit_source_hack; #endif /* __WINE_X11DRV_H */ diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index b64116cda40..6d5facc99c4 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -97,6 +97,7 @@ WNDPROC client_foreign_window_proc = NULL; HANDLE steam_overlay_event; HANDLE steam_keyboard_event; BOOL layered_window_client_hack = FALSE; +BOOL vulkan_gdi_blit_source_hack = FALSE; static x11drv_error_callback err_callback; /* current callback for error */ static Display *err_callback_display; /* display callback is set for */ @@ -827,6 +828,13 @@ static NTSTATUS x11drv_init( void *arg ) strcmp(sgi, "227020") == 0 /* Rise of Venice launcher */ )) || (e && *e != '\0' && *e != '0'); + + e = getenv("WINE_VK_GDI_BLIT_SOURCE_HACK"); + vulkan_gdi_blit_source_hack = + (sgi && ( + !strcmp(sgi, "803600") /* Disgaea 5 Complete */ + )) || + (e && *e != '\0' && *e != '0'); } init_user_driver(); From 6e1fe5808030cb492bd4d1db2998c8437e84291a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Sat, 21 May 2022 20:01:08 -0500 Subject: [PATCH 0640/2777] winex11.drv: Implement other process window Vulkan rendering. CW-Bug-Id: #20680 --- dlls/winex11.drv/vulkan.c | 93 +++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 9 deletions(-) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 6cbfb6d9fa6..b8b05123381 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -69,6 +69,10 @@ struct wine_vk_surface HWND hwnd; DWORD hwnd_thread_id; BOOL gdi_blit_source; /* HACK: gdi blits from the window should work with Vulkan rendered contents. */ + BOOL other_process; + Colormap client_colormap; + HDC draw_dc; + unsigned int width, height; }; typedef struct VkXlibSurfaceCreateInfoKHR @@ -233,8 +237,12 @@ static void wine_vk_surface_release(struct wine_vk_surface *surface) pthread_mutex_unlock(&vulkan_mutex); } + if (surface->draw_dc) + NtGdiDeleteObjectApp(surface->draw_dc); if (surface->window) XDestroyWindow(gdi_display, surface->window); + if (surface->client_colormap) + XFreeColormap( gdi_display, surface->client_colormap ); free(surface); } @@ -369,7 +377,7 @@ BOOL wine_vk_direct_window_draw( HWND hwnd ) LIST_FOR_EACH_ENTRY(surface, &surface_list, struct wine_vk_surface, entry) { if (surface->hwnd != hwnd) continue; - if (surface->gdi_blit_source) + if (surface->gdi_blit_source && !surface->other_process) { ret = TRUE; break; @@ -455,7 +463,9 @@ static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device, create_info_host.surface = x11_surface->surface; /* force fifo when running offscreen so the acquire fence is more likely to be vsynced */ - if (x11_surface->offscreen && create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR) + if (x11_surface->gdi_blit_source) + create_info_host.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; + else if (x11_surface->offscreen && create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR) create_info_host.presentMode = VK_PRESENT_MODE_FIFO_KHR; x11_surface->present_mode = create_info->presentMode; @@ -485,7 +495,9 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, VkResult res; VkXlibSurfaceCreateInfoKHR create_info_host; struct wine_vk_surface *x11_surface; + DWORD hwnd_pid; HWND parent; + RECT rect; TRACE("%p %p %p %p\n", instance, create_info, allocator, surface); @@ -502,8 +514,49 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, x11_surface->swapchain_count = 0; if (x11_surface->hwnd) { - x11_surface->window = create_client_window(create_info->hwnd, &default_visual); - x11_surface->hwnd_thread_id = NtUserGetWindowThread(x11_surface->hwnd, NULL); + x11_surface->hwnd_thread_id = NtUserGetWindowThread(x11_surface->hwnd, &hwnd_pid); + if (x11_surface->hwnd_thread_id && hwnd_pid != GetCurrentProcessId()) + { + XSetWindowAttributes attr; + + WARN("Other process window %p.\n", x11_surface->hwnd); + NtUserGetClientRect( x11_surface->hwnd, &rect ); + x11_surface->width = max( rect.right - rect.left, 1 ); + x11_surface->height = max( rect.bottom - rect.top, 1 ); + x11_surface->client_colormap = XCreateColormap( gdi_display, get_dummy_parent(), default_visual.visual, + (default_visual.class == PseudoColor || default_visual.class == GrayScale + || default_visual.class == DirectColor) ? AllocAll : AllocNone ); + attr.colormap = x11_surface->client_colormap; + attr.bit_gravity = NorthWestGravity; + attr.win_gravity = NorthWestGravity; + attr.backing_store = NotUseful; + attr.border_pixel = 0; + x11_surface->window = XCreateWindow( gdi_display, + get_dummy_parent(), + 0, 0, x11_surface->width, x11_surface->height, 0, + default_visual.depth, InputOutput, + default_visual.visual, CWBitGravity | CWWinGravity | + CWBackingStore | CWColormap | CWBorderPixel, &attr ); + if (x11_surface->window) + { + const WCHAR displayW[] = {'D','I','S','P','L','A','Y',0}; + UNICODE_STRING device_str; + + XMapWindow( gdi_display, x11_surface->window ); + XSync( gdi_display, False ); + x11_surface->gdi_blit_source = TRUE; + x11_surface->other_process = TRUE; + + RtlInitUnicodeString( &device_str, displayW ); + x11_surface->draw_dc = NtGdiOpenDCW( &device_str, NULL, NULL, 0, TRUE, NULL, NULL, NULL ); + + set_dc_drawable( x11_surface->draw_dc, x11_surface->window, &rect ); + } + } + else + { + x11_surface->window = create_client_window(create_info->hwnd, &default_visual); + } } else { @@ -519,7 +572,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, goto err; } - if (vulkan_gdi_blit_source_hack) + if (!x11_surface->gdi_blit_source && vulkan_gdi_blit_source_hack) { RECT rect; @@ -566,7 +619,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, *surface = (uintptr_t)wine_vk_surface_grab(x11_surface); - if (x11_surface->gdi_blit_source) + if (x11_surface->gdi_blit_source && !x11_surface->other_process) { /* Make sure window gets surface destroyed. */ UINT flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW | @@ -878,7 +931,7 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, if (!surface || !surface->offscreen) wait_fence = FALSE; - else if (surface->present_mode == VK_PRESENT_MODE_MAILBOX_KHR || + else if (surface->other_process || surface->present_mode == VK_PRESENT_MODE_MAILBOX_KHR || surface->present_mode == VK_PRESENT_MODE_FIFO_KHR) wait_fence = TRUE; @@ -896,7 +949,7 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, if ((result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) && surface && surface->offscreen) { - if (!surface->gdi_blit_source) + if (!surface->gdi_blit_source || surface->other_process) dc_flags |= DCX_CACHE; hdc = NtUserGetDCEx(surface->hwnd, 0, dc_flags); } @@ -906,8 +959,30 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, if (wait_fence) pvkWaitForFences(device, 1, &fence, 0, timeout); if (surface->gdi_blit_source) { + unsigned int width, height; + NtUserGetClientRect( surface->hwnd, &rect ); - set_dc_drawable( hdc, surface->window, &rect ); + if (surface->other_process) + { + width = max( rect.right - rect.left, 1 ); + height = max( rect.bottom - rect.top, 1 ); + if (!NtGdiStretchBlt(hdc, rect.left, rect.top, width, + height, surface->draw_dc, 0, 0, + width, height, SRCCOPY, 0)) + ERR("StretchBlt failed.\n"); + if (width != surface->width || height != surface->height) + { + TRACE("Resizing.\n"); + XMoveResizeWindow( gdi_display, surface->window, 0, 0, width, height); + set_dc_drawable( surface->draw_dc, surface->window, &rect ); + surface->width = width; + surface->height = height; + } + } + else + { + set_dc_drawable( hdc, surface->window, &rect ); + } } else { From 264a28026e6847f53d38dbfd3c74930ebe2b610e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 22 Jun 2022 13:20:15 -0500 Subject: [PATCH 0641/2777] winex11.drv: Add WINE_DISABLE_VULKAN_OPWR option. CW-Bug-Id: #20680 --- dlls/winex11.drv/vulkan.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index b8b05123381..6ade7c2260c 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -27,6 +27,7 @@ #include "config.h" #include +#include #include #include @@ -488,6 +489,17 @@ static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device, return result; } +static BOOL disable_opwr(void) +{ + static int disable = -1; + if (disable == -1) + { + const char *e = getenv("WINE_DISABLE_VULKAN_OPWR"); + disable = e && atoi(e); + } + return disable; +} + static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *create_info, const VkAllocationCallbacks *allocator, VkSurfaceKHR *surface) @@ -520,6 +532,14 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, XSetWindowAttributes attr; WARN("Other process window %p.\n", x11_surface->hwnd); + + if (disable_opwr() && x11_surface->hwnd != NtUserGetDesktopWindow()) + { + ERR("HACK: Failing surface creation for other process window %p.\n", create_info->hwnd); + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto err; + } + NtUserGetClientRect( x11_surface->hwnd, &rect ); x11_surface->width = max( rect.right - rect.left, 1 ); x11_surface->height = max( rect.bottom - rect.top, 1 ); From c74c588f3d6f60a16713871e13a4cd50bcf233f3 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 10 Sep 2021 22:21:13 +0300 Subject: [PATCH 0642/2777] winex11.drv: Create offscreen GL drawable for layered windows managed through UpdateLayeredWindow(). CW-Bug-ID: #19216 --- dlls/winex11.drv/opengl.c | 70 +++++++++++++++++++++++++++++---------- dlls/winex11.drv/window.c | 37 +++++++++++++++++++++ dlls/winex11.drv/x11drv.h | 3 ++ 3 files changed, 92 insertions(+), 18 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index e38c6a62227..150c3bbf525 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -218,6 +218,12 @@ enum dc_gl_type DC_GL_PBUFFER /* pseudo memory DC using a PBuffer */ }; +enum dc_gl_layered_type +{ + DC_GL_LAYERED_NONE, + DC_GL_LAYERED_UPDATES, +}; + struct gl_drawable { LONG ref; /* reference count */ @@ -228,6 +234,7 @@ struct gl_drawable Pixmap pixmap; /* base pixmap if drawable is a GLXPixmap */ const struct wgl_pixel_format *format; /* pixel format for the drawable */ SIZE pixmap_size; /* pixmap size for GLXPixmap drawables */ + enum dc_gl_layered_type layered_type; int swap_interval; BOOL refresh_swap_interval; BOOL mutable_pf; @@ -1314,6 +1321,19 @@ static GLXContext create_glxcontext(Display *display, struct wgl_context *contex } +static enum dc_gl_layered_type get_gl_layered_type( HWND hwnd ) +{ + struct x11drv_win_data *data; + enum dc_gl_layered_type ret; + + if (!(data = get_win_data( hwnd ))) return DC_GL_LAYERED_NONE; + ret = data->layered && !data->layered_attributes ? DC_GL_LAYERED_UPDATES : DC_GL_LAYERED_NONE; + release_win_data( data ); + + return ret; +} + + /*********************************************************************** * create_gl_drawable */ @@ -1341,8 +1361,24 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel gl->ref = 1; gl->mutable_pf = mutable_pf; - if (!known_child && !NtUserGetWindowRelative( hwnd, GW_CHILD ) && - NtUserGetAncestor( hwnd, GA_PARENT ) == NtUserGetDesktopWindow()) /* childless top-level window */ + gl->layered_type = get_gl_layered_type( hwnd ); + + if (gl->layered_type) + { + detach_client_window( hwnd ); + gl->type = DC_GL_PIXMAP_WIN; + gl->pixmap = XCreatePixmap( gdi_display, root_window, width, height, visual->depth ); + if (gl->pixmap) + { + gl->drawable = pglXCreatePixmap( gdi_display, gl->format->fbconfig, gl->pixmap, NULL ); + if (!gl->drawable) XFreePixmap( gdi_display, gl->pixmap ); + gl->pixmap_size.cx = width; + gl->pixmap_size.cy = height; + } + TRACE( "%p created pixmap drawable %lx for layered window, type %u.\n", hwnd, gl->drawable, gl->layered_type ); + } + else if (!known_child && !NtUserGetWindowRelative( hwnd, GW_CHILD ) && + NtUserGetAncestor( hwnd, GA_PARENT ) == NtUserGetDesktopWindow()) /* childless top-level window */ { gl->type = DC_GL_WINDOW; gl->window = create_client_window( hwnd, visual ); @@ -1472,24 +1508,22 @@ static BOOL set_pixel_format(HDC hdc, int format, BOOL allow_change) */ void sync_gl_drawable( HWND hwnd, BOOL known_child ) { + enum dc_gl_layered_type new_layered_type; struct gl_drawable *old, *new; if (!(old = get_gl_drawable( hwnd, 0 ))) return; - switch (old->type) + new_layered_type = get_gl_layered_type( hwnd ); + if (old->type == DC_GL_PIXMAP_WIN || (known_child && old->type == DC_GL_WINDOW) + || old->layered_type != new_layered_type) { - case DC_GL_WINDOW: - if (!known_child) break; /* Still a childless top-level window */ - /* fall through */ - case DC_GL_PIXMAP_WIN: - if (!(new = create_gl_drawable( hwnd, old->format, known_child, old->mutable_pf ))) break; - mark_drawable_dirty( old, new ); - XFlush( gdi_display ); - TRACE( "Recreated GL drawable %lx to replace %lx\n", new->drawable, old->drawable ); - release_gl_drawable( new ); - break; - default: - break; + if ((new = create_gl_drawable( hwnd, old->format, known_child, old->mutable_pf ))) + { + mark_drawable_dirty( old, new ); + XFlush( gdi_display ); + TRACE( "Recreated GL drawable %lx to replace %lx\n", new->drawable, old->drawable ); + release_gl_drawable( new ); + } } release_gl_drawable( old ); } @@ -2032,7 +2066,7 @@ static void wglFinish(void) { switch (gl->type) { - case DC_GL_PIXMAP_WIN: escape.drawable = gl->pixmap; break; + case DC_GL_PIXMAP_WIN: if (!gl->layered_type) escape.drawable = gl->pixmap; break; case DC_GL_CHILD_WIN: escape.drawable = gl->window; break; default: break; } @@ -2058,7 +2092,7 @@ static void wglFlush(void) { switch (gl->type) { - case DC_GL_PIXMAP_WIN: escape.drawable = gl->pixmap; break; + case DC_GL_PIXMAP_WIN: if (!gl->layered_type) escape.drawable = gl->pixmap; break; case DC_GL_CHILD_WIN: escape.drawable = gl->window; break; default: break; } @@ -3431,7 +3465,7 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) { case DC_GL_PIXMAP_WIN: if (ctx) sync_context( ctx ); - escape.drawable = gl->pixmap; + if (!gl->layered_type) escape.drawable = gl->pixmap; if (pglXCopySubBufferMESA) { /* (glX)SwapBuffers has an implicit glFlush effect, however * GLX_MESA_copy_sub_buffer doesn't. Make sure GL is flushed before diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 8c8a432754e..27ff3df063a 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1788,6 +1788,30 @@ void update_client_window( HWND hwnd ) } +/********************************************************************** + * detach_client_window + */ +void detach_client_window( HWND hwnd ) +{ + struct x11drv_win_data *data; + + if (!(data = get_win_data( hwnd ))) return; + + if (!data->client_window) + { + release_win_data( data ); + return; + } + + XDeleteContext( data->display, data->client_window, winContext ); + XReparentWindow( gdi_display, data->client_window, get_dummy_parent(), 0, 0 ); + TRACE( "%p reparent xwin %lx/%lx\n", data->hwnd, data->whole_window, data->client_window ); + data->client_window = 0; + XFlush( data->display ); + release_win_data( data ); +} + + /********************************************************************** * create_dummy_client_window */ @@ -2068,6 +2092,7 @@ void X11DRV_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style ) struct x11drv_win_data *data; DWORD changed = style->styleNew ^ style->styleOld; HWND parent = NtUserGetAncestor( hwnd, GA_PARENT ); + BOOL need_sync_gl = FALSE; if (offset == GWL_STYLE && (changed & WS_CHILD)) { @@ -2087,12 +2112,15 @@ void X11DRV_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style ) if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */ { data->layered = FALSE; + data->layered_attributes = FALSE; + need_sync_gl = TRUE; set_window_visual( data, &default_visual, FALSE ); sync_window_opacity( data->display, data->whole_window, 0, 0, 0 ); if (data->surface) set_surface_color_key( data->surface, CLR_INVALID ); } done: release_win_data( data ); + if (need_sync_gl) sync_gl_drawable( hwnd, FALSE ); } @@ -3230,6 +3258,7 @@ void X11DRV_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw ) void X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags ) { struct x11drv_win_data *data = get_win_data( hwnd ); + BOOL need_sync_gl; if (data) { @@ -3240,7 +3269,9 @@ void X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWO if (data->surface) set_surface_color_key( data->surface, (flags & LWA_COLORKEY) ? key : CLR_INVALID ); + need_sync_gl = !data->layered || !data->layered_attributes; data->layered = TRUE; + data->layered_attributes = TRUE; if (!data->mapped) /* mapping is delayed until attributes are set */ { DWORD style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); @@ -3250,10 +3281,12 @@ void X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWO { release_win_data( data ); map_window( hwnd, style ); + if (need_sync_gl) sync_gl_drawable( hwnd, FALSE ); return; } } release_win_data( data ); + if (need_sync_gl) sync_gl_drawable( hwnd, FALSE ); } else { @@ -3282,12 +3315,14 @@ BOOL X11DRV_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info, BITMAPINFO *bmi = (BITMAPINFO *)buffer; void *src_bits, *dst_bits; RECT rect, src_rect; + BOOL need_sync_gl; HDC hdc = 0; HBITMAP dib; BOOL mapped, ret = FALSE; if (!(data = get_win_data( hwnd ))) return FALSE; + need_sync_gl = !data->layered; data->layered = TRUE; if (!data->embedded && argb_visual.visualid) set_window_visual( data, &argb_visual, TRUE ); @@ -3317,6 +3352,8 @@ BOOL X11DRV_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info, map_window( hwnd, style ); } + if (need_sync_gl) sync_gl_drawable( hwnd, FALSE ); + if (!surface) return FALSE; if (!info->hdcSrc) { diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 1c53c4a3275..ec56e8ab329 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -642,6 +642,8 @@ struct x11drv_win_data BOOL embedded : 1; /* is window an XEMBED client? */ BOOL shaped : 1; /* is window using a custom region shape? */ BOOL layered : 1; /* is window layered and with valid attributes? */ + BOOL layered_attributes : 1; + /* is layered window has leyered attributes set (or otherwise managed with UpdateLayeredWindow()? */ BOOL use_alpha : 1; /* does window use an alpha channel? */ BOOL skip_taskbar : 1; /* does window should be deleted from taskbar */ BOOL add_taskbar : 1; /* does window should be added to taskbar regardless of style */ @@ -684,6 +686,7 @@ extern void make_window_embedded( struct x11drv_win_data *data ) DECLSPEC_HIDDEN extern Window create_dummy_client_window(void) DECLSPEC_HIDDEN; extern Window create_client_window( HWND hwnd, const XVisualInfo *visual ) DECLSPEC_HIDDEN; extern void update_client_window( HWND hwnd ) DECLSPEC_HIDDEN; +extern void detach_client_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *vis, BOOL use_alpha ) DECLSPEC_HIDDEN; extern void change_systray_owner( Display *display, Window systray_window ) DECLSPEC_HIDDEN; extern HWND create_foreign_window( Display *display, Window window ) DECLSPEC_HIDDEN; From 074776d7448d9b02cd90e77d692ff281601a8825 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 13 Sep 2021 00:39:05 +0300 Subject: [PATCH 0643/2777] winex11.drv: Always sync windowless GL drawables on size change. CW-Bug-ID: #19216 --- dlls/winex11.drv/window.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 27ff3df063a..8844cac6a6c 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2971,6 +2971,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, UINT new_style = NtUserGetWindowLongW( hwnd, GWL_STYLE ); RECT old_window_rect, old_whole_rect, old_client_rect; HWND prev_window = NULL; + BOOL needs_resize; int event_type; if (!(data = get_win_data( hwnd ))) return; @@ -3031,13 +3032,13 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, sync_client_position( data, &old_client_rect, &old_whole_rect ); + needs_resize = !data->client_window && (data->client_rect.right - data->client_rect.left != + old_client_rect.right - old_client_rect.left || + data->client_rect.bottom - data->client_rect.top != + old_client_rect.bottom - old_client_rect.top); + if (!data->whole_window) { - BOOL needs_resize = (!data->client_window && - (data->client_rect.right - data->client_rect.left != - old_client_rect.right - old_client_rect.left || - data->client_rect.bottom - data->client_rect.top != - old_client_rect.bottom - old_client_rect.top)); release_win_data( data ); if (needs_resize) sync_gl_drawable( hwnd, FALSE ); return; @@ -3140,6 +3141,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, data->surface->funcs->flush( data->surface ); release_win_data( data ); + if (needs_resize) sync_gl_drawable( hwnd, FALSE ); } /* check if the window icon should be hidden (i.e. moved off-screen) */ From 6b372dbc3321a57ec8b0534bc4d06c0afcfad59a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 10 Sep 2021 21:51:14 +0300 Subject: [PATCH 0644/2777] user32: Allow using surface to paint the client area of OpenGL windows. CW-Bug-ID: #19216 --- dlls/win32u/dce.c | 16 +++++----------- server/window.c | 3 ++- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index f4292dc36a8..76a1260ef25 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -463,7 +463,6 @@ static void update_visible_region( struct dce *dce ) HRGN vis_rgn = 0; HWND top_win = 0; DWORD flags = dce->flags; - DWORD paint_flags = 0; size_t size = 256; RECT win_rect, top_rect; WND *win; @@ -500,7 +499,6 @@ static void update_visible_region( struct dce *dce ) top_rect.top = reply->top_rect.top; top_rect.right = reply->top_rect.right; top_rect.bottom = reply->top_rect.bottom; - paint_flags = reply->paint_flags; } else size = reply->total_size; } @@ -515,16 +513,12 @@ static void update_visible_region( struct dce *dce ) if (dce->clip_rgn) NtGdiCombineRgn( vis_rgn, vis_rgn, dce->clip_rgn, (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF ); - /* don't use a surface to paint the client area of OpenGL windows */ - if (!(paint_flags & SET_WINPOS_PIXEL_FORMAT) || (flags & DCX_WINDOW)) + win = get_win_ptr( top_win ); + if (win && win != WND_DESKTOP && win != WND_OTHER_PROCESS) { - win = get_win_ptr( top_win ); - if (win && win != WND_DESKTOP && win != WND_OTHER_PROCESS) - { - surface = win->surface; - if (surface) window_surface_add_ref( surface ); - release_win_ptr( win ); - } + surface = win->surface; + if (surface) window_surface_add_ref( surface ); + release_win_ptr( win ); } if (!surface) SetRectEmpty( &top_rect ); diff --git a/server/window.c b/server/window.c index 26eb52badc3..302aa2e6071 100644 --- a/server/window.c +++ b/server/window.c @@ -1250,7 +1250,8 @@ static struct region *get_surface_region( struct window *win ) set_region_rect( clip, &win->client_rect ); if (win->win_region && !intersect_window_region( clip, win )) goto error; - if ((win->paint_flags & PAINT_HAS_PIXEL_FORMAT) && !subtract_region( region, region, clip )) + if (!(win->ex_style & WS_EX_LAYERED) && (win->paint_flags & PAINT_HAS_PIXEL_FORMAT) + && !subtract_region( region, region, clip )) goto error; /* clip children */ From c2db8156651923499107aa5c2d37f428d1b71a60 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 9 Sep 2021 21:16:26 +0300 Subject: [PATCH 0645/2777] winex11.drv: Use window surface for GL presentation for layered windows. CW-Bug-ID: #19216 --- dlls/winex11.drv/opengl.c | 85 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 4 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 150c3bbf525..af7aac39ea0 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -222,6 +222,7 @@ enum dc_gl_layered_type { DC_GL_LAYERED_NONE, DC_GL_LAYERED_UPDATES, + DC_GL_LAYERED_ATTRIBUTES, }; struct gl_drawable @@ -1327,7 +1328,8 @@ static enum dc_gl_layered_type get_gl_layered_type( HWND hwnd ) enum dc_gl_layered_type ret; if (!(data = get_win_data( hwnd ))) return DC_GL_LAYERED_NONE; - ret = data->layered && !data->layered_attributes ? DC_GL_LAYERED_UPDATES : DC_GL_LAYERED_NONE; + if (data->layered) ret = data->layered_attributes ? DC_GL_LAYERED_ATTRIBUTES : DC_GL_LAYERED_UPDATES; + else ret = DC_GL_LAYERED_NONE; release_win_data( data ); return ret; @@ -2052,17 +2054,87 @@ static BOOL glxdrv_wglShareLists(struct wgl_context *org, struct wgl_context *de return FALSE; } +static void update_window_surface(struct gl_drawable *gl, HWND hwnd) +{ + char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; + BITMAPINFO *bmi = (BITMAPINFO *)buffer; + struct window_surface *surface; + struct x11drv_win_data *data; + unsigned int y, width, height, stride, pitch; + BYTE *dst_bits, *src_bits; + XImage *image; + RECT rect; + + TRACE( "gl %p, hwnd %p, gl->layered_type %u.\n", gl, hwnd, gl->layered_type ); + + if (gl->layered_type != DC_GL_LAYERED_ATTRIBUTES || !gl->pixmap) return; + + if (!(data = get_win_data( hwnd ))) return; + + surface = data->surface; + if (!surface) + { + TRACE( "No surface.\n" ); + release_win_data( data ); + return; + } + + rect = data->client_rect; + OffsetRect( &rect, -data->whole_rect.left, -data->whole_rect.top ); + + dst_bits = surface->funcs->get_info( surface, bmi ); + surface->funcs->lock( surface ); + + rect.right = min( rect.right, abs( bmi->bmiHeader.biWidth )); + rect.bottom = min( rect.bottom, abs( bmi->bmiHeader.biHeight )); + + width = min( rect.right - rect.left, gl->pixmap_size.cx ); + height = min( rect.bottom - rect.top, gl->pixmap_size.cy ); + + image = XGetImage( gdi_display, gl->pixmap, 0, 0, width, height, + AllPlanes, ZPixmap ); + if (!image) + { + TRACE( "NULL image.\n" ); + goto done; + } + + if (image->bits_per_pixel != bmi->bmiHeader.biBitCount) + { + static unsigned int once; + + if (!once++) + FIXME("Bits per pixel does not match, image %u, bmi %u.\n", image->bits_per_pixel, bmi->bmiHeader.biBitCount); + goto done; + } + + stride = bmi->bmiHeader.biBitCount / 8; + pitch = (bmi->bmiHeader.biWidth * stride + 3) & ~3; + src_bits = (BYTE *)image->data; + for (y = 0; y < height; ++y) + memcpy( dst_bits + (y + rect.top) * pitch + rect.left * stride, + src_bits + y * image->bytes_per_line, width * stride ); + + add_bounds_rect( surface->funcs->get_bounds( surface ), &rect ); + +done: + surface->funcs->unlock( surface ); + if (image) XDestroyImage( image ); + release_win_data( data ); +} + static void wglFinish(void) { struct x11drv_escape_present_drawable escape; struct gl_drawable *gl; struct wgl_context *ctx = NtCurrentTeb()->glContext; + HWND hwnd; escape.code = X11DRV_PRESENT_DRAWABLE; escape.drawable = 0; escape.flush = FALSE; - if ((gl = get_gl_drawable( NtUserWindowFromDC( ctx->hdc ), 0 ))) + if ((gl = get_gl_drawable( (hwnd = NtUserWindowFromDC( ctx->hdc )), 0 ))) { switch (gl->type) { @@ -2071,6 +2143,7 @@ static void wglFinish(void) default: break; } sync_context(ctx); + update_window_surface( gl, hwnd ); release_gl_drawable( gl ); } @@ -2083,12 +2156,13 @@ static void wglFlush(void) struct x11drv_escape_present_drawable escape; struct gl_drawable *gl; struct wgl_context *ctx = NtCurrentTeb()->glContext; + HWND hwnd; escape.code = X11DRV_PRESENT_DRAWABLE; escape.drawable = 0; escape.flush = FALSE; - if ((gl = get_gl_drawable( NtUserWindowFromDC( ctx->hdc ), 0 ))) + if ((gl = get_gl_drawable( (hwnd = NtUserWindowFromDC( ctx->hdc )), 0 ))) { switch (gl->type) { @@ -2097,6 +2171,7 @@ static void wglFlush(void) default: break; } sync_context(ctx); + update_window_surface( gl, hwnd ); release_gl_drawable( gl ); } @@ -3440,6 +3515,7 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) struct gl_drawable *gl; struct wgl_context *ctx = NtCurrentTeb()->glContext; INT64 ust, msc, sbc, target_sbc = 0; + HWND hwnd; TRACE("(%p)\n", hdc); @@ -3447,7 +3523,7 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) escape.drawable = 0; escape.flush = !pglXWaitForSbcOML; - if (!(gl = get_gl_drawable( NtUserWindowFromDC( hdc ), hdc ))) + if (!(gl = get_gl_drawable( (hwnd = NtUserWindowFromDC( hdc )), hdc ))) { RtlSetLastWin32Error( ERROR_INVALID_HANDLE ); return FALSE; @@ -3502,6 +3578,7 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) if (escape.drawable && pglXWaitForSbcOML) pglXWaitForSbcOML( gdi_display, gl->drawable, target_sbc, &ust, &msc, &sbc ); + update_window_surface( gl, hwnd ); release_gl_drawable( gl ); if (escape.drawable) NtGdiExtEscape( ctx->hdc, NULL, 0, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); From ea5d171c8acc741146c752ad5e4ba90066164938 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Thu, 15 Dec 2022 14:20:01 +0100 Subject: [PATCH 0646/2777] mfreadwrite/reader: Consider the transform output attributes for creating shared samples. Some application (e.g., Trailmakers) set MF_SA_D3D11_SHARED_WITHOUT_MUTEX on the transform's output attributes rather than on the reader's attributes. CW-Bug-Id: #19126 CW-Bug-Id: #20985 --- dlls/mfreadwrite/reader.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index aaf46292da4..1384616da64 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -2120,20 +2120,33 @@ static HRESULT source_reader_set_compatible_media_type(struct source_reader *rea } static HRESULT source_reader_create_sample_allocator_attributes(const struct source_reader *reader, - IMFAttributes **attributes) + struct media_stream *stream, IMFAttributes **attributes) { - UINT32 shared = 0, shared_without_mutex = 0; + UINT32 reader_shared = 0, reader_shared_without_mutex = 0; + UINT32 output_shared = 0, output_shared_without_mutex = 0; HRESULT hr; if (FAILED(hr = MFCreateAttributes(attributes, 1))) return hr; - IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED, &shared); - IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &shared_without_mutex); + IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED, &reader_shared); + IMFAttributes_GetUINT32(reader->attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &reader_shared_without_mutex); - if (shared_without_mutex) + if (stream->decoder.transform) + { + IMFAttributes *output_attributes; + + if (SUCCEEDED(IMFTransform_GetOutputStreamAttributes(stream->decoder.transform, 0, &output_attributes))) + { + IMFAttributes_GetUINT32(output_attributes, &MF_SA_D3D11_SHARED, &output_shared); + IMFAttributes_GetUINT32(output_attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &output_shared_without_mutex); + IMFAttributes_Release(output_attributes); + } + } + + if (reader_shared_without_mutex || output_shared_without_mutex) hr = IMFAttributes_SetUINT32(*attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, TRUE); - else if (shared) + else if (reader_shared || output_shared) hr = IMFAttributes_SetUINT32(*attributes, &MF_SA_D3D11_SHARED, TRUE); return hr; @@ -2169,7 +2182,7 @@ static HRESULT source_reader_setup_sample_allocator(struct source_reader *reader return hr; } - if (FAILED(hr = source_reader_create_sample_allocator_attributes(reader, &attributes))) + if (FAILED(hr = source_reader_create_sample_allocator_attributes(reader, stream, &attributes))) WARN("Failed to create allocator attributes, hr %#lx.\n", hr); if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(stream->allocator, 2, 8, From c42c848ff6fe77f9aa4c9261920642217dbf5995 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 6 Jun 2022 14:16:00 +0200 Subject: [PATCH 0647/2777] mfplat/buffer: Optimize locking a DXGI surface buffer. CW-Bug-Id: #19126 --- dlls/mfplat/buffer.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index 94f34b236f5..97c1ceb5d44 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -56,6 +56,7 @@ struct buffer unsigned int height; int pitch; unsigned int locks; + MF2DBuffer_LockFlags lock_flags; p_copy_image_func copy_image; } _2d; struct @@ -998,9 +999,14 @@ static HRESULT dxgi_surface_buffer_map(struct buffer *buffer) ID3D11Texture2D_GetDevice(buffer->dxgi_surface.texture, &device); ID3D11Device_GetImmediateContext(device, &immediate_context); - ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, - 0, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.texture, buffer->dxgi_surface.sub_resource_idx, NULL); + if (buffer->_2d.lock_flags == MF2DBuffer_LockFlags_Read || buffer->_2d.lock_flags == MF2DBuffer_LockFlags_ReadWrite) + { + ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, + 0, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.texture, buffer->dxgi_surface.sub_resource_idx, NULL); + } + + // TODO: fix _Map flags memset(&buffer->dxgi_surface.map_desc, 0, sizeof(buffer->dxgi_surface.map_desc)); if (FAILED(hr = ID3D11DeviceContext_Map(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0, D3D11_MAP_READ_WRITE, 0, &buffer->dxgi_surface.map_desc))) @@ -1024,8 +1030,11 @@ static void dxgi_surface_buffer_unmap(struct buffer *buffer) ID3D11DeviceContext_Unmap(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0); memset(&buffer->dxgi_surface.map_desc, 0, sizeof(buffer->dxgi_surface.map_desc)); - ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.texture, - buffer->dxgi_surface.sub_resource_idx, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0, NULL); + if (buffer->_2d.lock_flags == MF2DBuffer_LockFlags_Write || buffer->_2d.lock_flags == MF2DBuffer_LockFlags_ReadWrite) + { + ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.texture, + buffer->dxgi_surface.sub_resource_idx, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0, NULL); + } ID3D11DeviceContext_Release(immediate_context); ID3D11Device_Release(device); @@ -1053,6 +1062,7 @@ static HRESULT WINAPI dxgi_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat if (SUCCEEDED(hr)) { + buffer->_2d.lock_flags = MF2DBuffer_LockFlags_ReadWrite; hr = dxgi_surface_buffer_map(buffer); if (SUCCEEDED(hr)) { @@ -1122,7 +1132,14 @@ static HRESULT dxgi_surface_buffer_lock(struct buffer *buffer, MF2DBuffer_LockFl if (buffer->_2d.linear_buffer) hr = MF_E_UNEXPECTED; else if (!buffer->_2d.locks++) + { + buffer->_2d.lock_flags = flags; hr = dxgi_surface_buffer_map(buffer); + } + else if (buffer->_2d.lock_flags != flags) + { + WARN("relocking DXGI surface buffer %p with different flags!\n", buffer); + } if (SUCCEEDED(hr)) { From 737c30ae820e7bcc20d8f0db0ef6a0a7f7eb31cd Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 6 Jun 2022 15:10:55 +0200 Subject: [PATCH 0648/2777] mfplat/buffer: Use appropriate Map flags. CW-Bug-Id: #19126 --- dlls/mfplat/buffer.c | 70 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index 97c1ceb5d44..6cdc57692a0 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -967,8 +967,27 @@ static HRESULT dxgi_surface_buffer_create_readback_texture(struct buffer *buffer { D3D11_TEXTURE2D_DESC texture_desc; ID3D11Device *device; + UINT cpu_usage; HRESULT hr; + switch (buffer->_2d.lock_flags) + { + case MF2DBuffer_LockFlags_Read: + cpu_usage = D3D11_CPU_ACCESS_READ; + break; + + case MF2DBuffer_LockFlags_Write: + cpu_usage = D3D11_CPU_ACCESS_WRITE; + break; + + case MF2DBuffer_LockFlags_ReadWrite: + cpu_usage = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + break; + + default: + return E_INVALIDARG; + } + if (buffer->dxgi_surface.rb_texture) return S_OK; @@ -977,7 +996,7 @@ static HRESULT dxgi_surface_buffer_create_readback_texture(struct buffer *buffer ID3D11Texture2D_GetDesc(buffer->dxgi_surface.texture, &texture_desc); texture_desc.Usage = D3D11_USAGE_STAGING; texture_desc.BindFlags = 0; - texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + texture_desc.CPUAccessFlags = cpu_usage; texture_desc.MiscFlags = 0; texture_desc.MipLevels = 1; if (FAILED(hr = ID3D11Device_CreateTexture2D(device, &texture_desc, NULL, &buffer->dxgi_surface.rb_texture))) @@ -992,7 +1011,30 @@ static HRESULT dxgi_surface_buffer_map(struct buffer *buffer) { ID3D11DeviceContext *immediate_context; ID3D11Device *device; + D3D11_MAP map_type; HRESULT hr; + BOOL copy; + + switch (buffer->_2d.lock_flags) + { + case MF2DBuffer_LockFlags_Read: + map_type = D3D11_MAP_READ; + copy = TRUE; + break; + + case MF2DBuffer_LockFlags_Write: + map_type = D3D11_MAP_WRITE; + copy = FALSE; + break; + + case MF2DBuffer_LockFlags_ReadWrite: + map_type = D3D11_MAP_READ_WRITE; + copy = TRUE; + break; + + default: + return E_INVALIDARG; + } if (FAILED(hr = dxgi_surface_buffer_create_readback_texture(buffer))) return hr; @@ -1000,16 +1042,15 @@ static HRESULT dxgi_surface_buffer_map(struct buffer *buffer) ID3D11Texture2D_GetDevice(buffer->dxgi_surface.texture, &device); ID3D11Device_GetImmediateContext(device, &immediate_context); - if (buffer->_2d.lock_flags == MF2DBuffer_LockFlags_Read || buffer->_2d.lock_flags == MF2DBuffer_LockFlags_ReadWrite) + if (copy) { ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.texture, buffer->dxgi_surface.sub_resource_idx, NULL); } - // TODO: fix _Map flags memset(&buffer->dxgi_surface.map_desc, 0, sizeof(buffer->dxgi_surface.map_desc)); if (FAILED(hr = ID3D11DeviceContext_Map(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, - 0, D3D11_MAP_READ_WRITE, 0, &buffer->dxgi_surface.map_desc))) + 0, map_type, 0, &buffer->dxgi_surface.map_desc))) { WARN("Failed to map readback texture, hr %#lx.\n", hr); } @@ -1024,13 +1065,32 @@ static void dxgi_surface_buffer_unmap(struct buffer *buffer) { ID3D11DeviceContext *immediate_context; ID3D11Device *device; + BOOL copy; + + switch (buffer->_2d.lock_flags) + { + case MF2DBuffer_LockFlags_Read: + copy = FALSE; + break; + + case MF2DBuffer_LockFlags_Write: + copy = TRUE; + break; + + case MF2DBuffer_LockFlags_ReadWrite: + copy = TRUE; + break; + + default: + copy = FALSE; + } ID3D11Texture2D_GetDevice(buffer->dxgi_surface.texture, &device); ID3D11Device_GetImmediateContext(device, &immediate_context); ID3D11DeviceContext_Unmap(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0); memset(&buffer->dxgi_surface.map_desc, 0, sizeof(buffer->dxgi_surface.map_desc)); - if (buffer->_2d.lock_flags == MF2DBuffer_LockFlags_Write || buffer->_2d.lock_flags == MF2DBuffer_LockFlags_ReadWrite) + if (copy) { ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.texture, buffer->dxgi_surface.sub_resource_idx, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0, NULL); From 46f4598d6afbe000e30bf295176221217bf67013 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Thu, 10 Sep 2020 11:07:01 -0500 Subject: [PATCH 0649/2777] HACK: ntdll: Don't let applications change permissions on wine's files The 2019 VCRuntime installer will chmod a+w on files that it can't open for writing, which would leak through the library symlinks and modify the global installation. --- dlls/ntdll/unix/file.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 281736fdd47..8498298fd07 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1616,9 +1616,24 @@ static int fd_set_dos_attrib( int fd, UINT attr ) else return xattr_fremove( fd, SAMBA_XATTR_DOS_ATTRIB ); } +static unsigned int server_get_unix_name( HANDLE handle, char **unix_name ); + +/* return TRUE if this is a file owned by Wine which applications should not try to mess with. */ +static BOOL is_wine_file( HANDLE handle ) +{ + char *unix_name; + BOOL ret; + + if (server_get_unix_name( handle, &unix_name )) + return FALSE; + ret = strstr(unix_name, "/lib/wine/" ) || strstr( unix_name, "/lib64/wine/" ) ||strstr( unix_name, "/share/wine/" ); + free(unix_name); + return ret; +} + /* set the stat info and file attributes for a file (by file descriptor) */ -NTSTATUS fd_set_file_info( int fd, UINT attr ) +NTSTATUS fd_set_file_info( int fd, UINT attr, HANDLE handle ) { struct stat st; @@ -1632,8 +1647,16 @@ NTSTATUS fd_set_file_info( int fd, UINT attr ) } else { - /* add write permission only where we already have read permission */ - st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~start_umask); + if (is_wine_file(handle)) + { + TRACE("HACK: Not giving write permission to wine file!\n"); + return STATUS_ACCESS_DENIED; + } + else + { + /* add write permission only where we already have read permission */ + st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~start_umask); + } } if (fchmod( fd, st.st_mode ) == -1) return errno_to_status( errno ); @@ -4592,7 +4615,7 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, status = set_file_times( fd, &mtime, &atime ); if (status == STATUS_SUCCESS && info->FileAttributes) - status = fd_set_file_info( fd, info->FileAttributes ); + status = fd_set_file_info( fd, info->FileAttributes, handle ); if (needs_close) close( fd ); } From a7a9522614eef4d597b7f51c0b6b3179fd9435a9 Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Wed, 1 Apr 2020 11:47:05 -0500 Subject: [PATCH 0650/2777] winebrowser: Restore original LD_LIBRARY_PATH before calling to system --- dlls/ntdll/unix/env.c | 3 ++- programs/winebrowser/main.c | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c index 931da192916..a388aa7168c 100644 --- a/dlls/ntdll/unix/env.c +++ b/dlls/ntdll/unix/env.c @@ -2426,6 +2426,7 @@ void WINAPI RtlSetLastWin32Error( DWORD err ) */ ULONG WINAPI __wine_set_unix_env( const char *var, const char *val ) { - setenv(var, val, 1); + if (!val) unsetenv(var); + else setenv(var, val, 1); return 0; } diff --git a/programs/winebrowser/main.c b/programs/winebrowser/main.c index 369ecb98002..d183b07a921 100644 --- a/programs/winebrowser/main.c +++ b/programs/winebrowser/main.c @@ -63,6 +63,19 @@ static char *strdup_unixcp( const WCHAR *str ) return ret; } +ULONG WINAPI __wine_set_unix_env( const char *var, const char *val ); + +static void restore_system_environment(void) +{ + const char* orig_ld_path = getenv("ORIG_LD_LIBRARY_PATH"); + + if (orig_ld_path) + { + __wine_set_unix_env("LD_LIBRARY_PATH", orig_ld_path); + __wine_set_unix_env("ORIG_LD_LIBRARY_PATH", NULL); + } +} + /* try to launch a unix app from a comma separated string of app names */ static int launch_app( const WCHAR *candidates, const WCHAR *argv1 ) { @@ -72,6 +85,11 @@ static int launch_app( const WCHAR *candidates, const WCHAR *argv1 ) if (!(cmdline = strdup_unixcp( argv1 ))) return 1; + /* PROTON HACK: Restore ORIG_LD_LIBRARY_PATH to LD_LIBRARY_PATH. + * System programs may not work correctly with our libraries, in + * particular gio on Ubuntu 19.04 is broken by our libgio. */ + restore_system_environment(); + while (*candidates) { WCHAR **args = CommandLineToArgvW( candidates, &count ); From 8a2c4df6d193d0da6a6c1d409db3a8c5bed08ca7 Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Wed, 4 Mar 2020 18:49:37 +0100 Subject: [PATCH 0651/2777] HACK: ntdll: Mark first gta5.exe page as copied. --- dlls/ntdll/unix/virtual.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index b8dc029f15f..73c2c88b600 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -123,6 +123,7 @@ struct file_view #define VPROT_GUARD 0x10 #define VPROT_COMMITTED 0x20 #define VPROT_WRITEWATCH 0x40 +#define VPROT_COPIED 0x80 /* per-mapping protection flags */ #define VPROT_SYSTEM 0x0200 /* system view (underlying mmap not under our control) */ #define VPROT_PLACEHOLDER 0x0400 @@ -1076,7 +1077,8 @@ static const char *get_prot_str( BYTE prot ) buffer[0] = (prot & VPROT_COMMITTED) ? 'c' : '-'; buffer[1] = (prot & VPROT_GUARD) ? 'g' : ((prot & VPROT_WRITEWATCH) ? 'H' : '-'); buffer[2] = (prot & VPROT_READ) ? 'r' : '-'; - buffer[3] = (prot & VPROT_WRITECOPY) ? 'W' : ((prot & VPROT_WRITE) ? 'w' : '-'); + buffer[3] = (prot & VPROT_WRITECOPY) ? (prot & VPROT_COPIED ? 'w' : 'W') + : ((prot & VPROT_WRITE) ? 'w' : '-'); buffer[4] = (prot & VPROT_EXEC) ? 'x' : '-'; buffer[5] = 0; return buffer; @@ -1566,7 +1568,11 @@ static NTSTATUS create_view( struct file_view **view_ret, void *base, size_t siz */ static DWORD get_win32_prot( BYTE vprot, unsigned int map_prot ) { - DWORD ret = VIRTUAL_Win32Flags[vprot & 0x0f]; + DWORD ret; + + if ((vprot & (VPROT_COPIED | VPROT_WRITECOPY)) == (VPROT_COPIED | VPROT_WRITECOPY)) + vprot = (vprot & ~VPROT_WRITECOPY) | VPROT_WRITE; + ret = VIRTUAL_Win32Flags[vprot & 0x0f]; if (vprot & VPROT_GUARD) ret |= PAGE_GUARD; if (map_prot & SEC_NOCACHE) ret |= PAGE_NOCACHE; return ret; @@ -4526,6 +4532,24 @@ NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T { old = get_win32_prot( vprot, view->protect ); status = set_protection( view, base, size, new_prot ); + + /* GTA5 HACK: Mark first page as copied. */ + if (status == STATUS_SUCCESS && (view->protect & SEC_IMAGE) && + base == (void*)NtCurrentTeb()->Peb->ImageBaseAddress) + { + const WCHAR gta5W[] = { 'g','t','a','5','.','e','x','e',0 }; + WCHAR *name, *p; + + name = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer; + p = wcsrchr(name, '\\'); + p = p ? p+1 : name; + + if(!wcsicmp(p, gta5W)) + { + FIXME("HACK: changing GTA5.exe vprot\n"); + set_page_vprot_bits(base, page_size, VPROT_COPIED, 0); + } + } } else status = STATUS_NOT_COMMITTED; } From 09f264fb2fce4044c0187a2e0259c0fd1f70a07a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= Date: Tue, 30 Nov 2021 16:32:34 +0300 Subject: [PATCH 0652/2777] ntdll: Implement opening files through nt device paths. CW-Bug-Id: #19697 For Eternal Return. --- dlls/ntdll/tests/file.c | 25 +++++++- dlls/ntdll/unix/file.c | 134 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 156 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 6433e8548c1..60916bc777b 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -136,19 +136,23 @@ static void WINAPI apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved ) static void create_file_test(void) { + static const WCHAR notepadW[] = {'n','o','t','e','p','a','d','.','e','x','e',0}; static const WCHAR systemrootW[] = {'\\','S','y','s','t','e','m','R','o','o','t', '\\','f','a','i','l','i','n','g',0}; + static const WCHAR systemrootExplorerW[] = {'\\','S','y','s','t','e','m','R','o','o','t', + '\\','e','x','p','l','o','r','e','r','.','e','x','e',0}; static const WCHAR questionmarkInvalidNameW[] = {'a','f','i','l','e','?',0}; static const WCHAR pipeInvalidNameW[] = {'a','|','b',0}; static const WCHAR pathInvalidNtW[] = {'\\','\\','?','\\',0}; static const WCHAR pathInvalidNt2W[] = {'\\','?','?','\\',0}; static const WCHAR pathInvalidDosW[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\',0}; static const char testdata[] = "Hello World"; + static const WCHAR sepW[] = {'\\',0}; FILE_NETWORK_OPEN_INFORMATION info; UNICODE_STRING nameW, null_string; NTSTATUS status; HANDLE dir, file; - WCHAR path[MAX_PATH]; + WCHAR path[MAX_PATH], temp[MAX_PATH]; OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK io; LARGE_INTEGER offset; @@ -347,6 +351,25 @@ static void create_file_test(void) status = pNtQueryFullAttributesFile( &attr, &info ); ok( status == STATUS_OBJECT_NAME_INVALID, "query %s failed %lx\n", wine_dbgstr_w(nameW.Buffer), status ); + + GetWindowsDirectoryW( path, MAX_PATH ); + path[2] = 0; + ok( QueryDosDeviceW( path, temp, MAX_PATH ), + "QueryDosDeviceW failed with error %u\n", GetLastError() ); + lstrcatW( temp, sepW ); + lstrcatW( temp, path+3 ); + lstrcatW( temp, sepW ); + lstrcatW( temp, notepadW ); + + pRtlInitUnicodeString( &nameW, temp ); + status = pNtQueryFullAttributesFile( &attr, &info ); + ok( status == STATUS_SUCCESS, + "query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); + + pRtlInitUnicodeString( &nameW, systemrootExplorerW ); + status = pNtQueryFullAttributesFile( &attr, &info ); + ok( status == STATUS_SUCCESS, + "query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status ); } static void open_file_test(void) diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 8498298fd07..500575bb26c 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -3608,7 +3608,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char /****************************************************************************** - * nt_to_unix_file_name + * nt_to_unix_file_name_internal * * Convert a file name from NT namespace to Unix namespace. * @@ -3616,7 +3616,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char * element doesn't have to exist; in that case STATUS_NO_SUCH_FILE is * returned, but the unix name is still filled in properly. */ -NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, UINT disposition ) +NTSTATUS nt_to_unix_file_name_internal( const OBJECT_ATTRIBUTES *attr, char **name_ret, UINT disposition ) { enum server_fd_type type; int old_cwd, root_fd, needs_close; @@ -3677,6 +3677,136 @@ NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, U } +/* read the contents of an NT symlink object */ +static NTSTATUS read_nt_symlink( HANDLE root, UNICODE_STRING *name, WCHAR *target, size_t length ) +{ + OBJECT_ATTRIBUTES attr; + UNICODE_STRING targetW; + NTSTATUS status; + HANDLE handle; + + attr.Length = sizeof(attr); + attr.RootDirectory = root; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.ObjectName = name; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + if (!(status = NtOpenSymbolicLinkObject( &handle, SYMBOLIC_LINK_QUERY, &attr ))) + { + targetW.Buffer = target; + targetW.MaximumLength = (length - 1) * sizeof(WCHAR); + status = NtQuerySymbolicLinkObject( handle, &targetW, NULL ); + NtClose( handle ); + } + + return status; +} + +/* try to find dos device based on nt device name */ +static NTSTATUS nt_to_dos_device( WCHAR *name, size_t length, WCHAR *device_ret ) +{ + static const WCHAR dosdevicesW[] = {'\\','D','o','s','D','e','v','i','c','e','s',0}; + UNICODE_STRING dosdevW = { sizeof(dosdevicesW) - sizeof(WCHAR), sizeof(dosdevicesW), (WCHAR *)dosdevicesW }; + WCHAR symlinkW[MAX_DIR_ENTRY_LEN]; + OBJECT_ATTRIBUTES attr; + NTSTATUS status; + char data[1024]; + HANDLE handle; + ULONG ctx = 0; + + DIRECTORY_BASIC_INFORMATION *info = (DIRECTORY_BASIC_INFORMATION *)data; + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &dosdevW; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + status = NtOpenDirectoryObject( &handle, FILE_LIST_DIRECTORY, &attr ); + if (status) return STATUS_BAD_DEVICE_TYPE; + + while (!NtQueryDirectoryObject( handle, info, sizeof(data), TRUE, FALSE, &ctx, NULL )) + { + if (read_nt_symlink( handle, &info->ObjectName, symlinkW, MAX_DIR_ENTRY_LEN )) continue; + if (wcsnicmp( symlinkW, name, length )) continue; + if (info->ObjectName.Length != 2 * sizeof(WCHAR) || info->ObjectName.Buffer[1] != ':') continue; + + *device_ret = info->ObjectName.Buffer[0]; + NtClose( handle ); + return STATUS_SUCCESS; + } + + NtClose( handle ); + return STATUS_BAD_DEVICE_TYPE; +} + +/****************************************************************************** + * nt_to_unix_file_name + * + * Convert a file name from NT namespace to Unix namespace. + * + * If disposition is not FILE_OPEN or FILE_OVERWRITE, the last path + * element doesn't have to exist; in that case STATUS_NO_SUCH_FILE is + * returned, but the unix name is still filled in properly. + */ +NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, UINT disposition ) +{ + static const WCHAR systemrootW[] = {'\\','S','y','s','t','e','m','R','o','o','t','\\',0}; + static const WCHAR dosprefixW[] = {'\\','?','?','\\'}; + static const WCHAR deviceW[] = {'\\','D','e','v','i','c','e','\\',0}; + WCHAR *name, *ptr, *prefix, buffer[3] = {'c',':',0}; + UNICODE_STRING dospathW, *nameW; + OBJECT_ATTRIBUTES attr_copy; + size_t offset, name_len; + NTSTATUS status; + + if (attr->RootDirectory) return nt_to_unix_file_name_internal( attr, name_ret, disposition ); + + nameW = attr->ObjectName; + + if (nameW->Length >= sizeof(deviceW) - sizeof(WCHAR) + && !wcsnicmp( nameW->Buffer, deviceW, ARRAY_SIZE(deviceW) - 1 )) + { + offset = sizeof(deviceW) / sizeof(WCHAR); + while (offset * sizeof(WCHAR) < nameW->Length && nameW->Buffer[ offset ] != '\\') offset++; + if ((status = nt_to_dos_device( nameW->Buffer, offset, buffer ))) return status; + prefix = buffer; + } + else if (nameW->Length >= sizeof(systemrootW) - sizeof(WCHAR) && + !wcsnicmp( nameW->Buffer, systemrootW, ARRAY_SIZE(systemrootW) - 1 )) + { + offset = (sizeof(systemrootW) - 1) / sizeof(WCHAR); + prefix = user_shared_data->NtSystemRoot; + } + else + return nt_to_unix_file_name_internal( attr, name_ret, disposition ); + + name_len = sizeof(dosprefixW) + wcslen(prefix) * sizeof(WCHAR) + + sizeof(WCHAR) /* '\\' */ + nameW->Length - offset * sizeof(WCHAR) + sizeof(WCHAR); + if (!(name = malloc( name_len ))) + return STATUS_NO_MEMORY; + + ptr = name; + memcpy( ptr, dosprefixW, sizeof(dosprefixW) ); + ptr += sizeof(dosprefixW) / sizeof(WCHAR); + wcscpy( ptr, prefix ); + ptr += wcslen(ptr); + *ptr++ = '\\'; + memcpy( ptr, nameW->Buffer + offset, nameW->Length - offset * sizeof(WCHAR) ); + ptr[ nameW->Length / sizeof(WCHAR) - offset ] = 0; + + dospathW.Buffer = name; + dospathW.Length = wcslen( name ) * sizeof(WCHAR); + attr_copy = *attr; + attr_copy.ObjectName = &dospathW; + status = nt_to_unix_file_name_internal( &attr_copy, name_ret, disposition ); + + free( name ); + return status; +} + /****************************************************************************** * wine_nt_to_unix_file_name * From 179b64c4014246649d4a2164da587c8ea2223111 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 11 Oct 2021 11:13:39 +0200 Subject: [PATCH 0653/2777] ntdll: Resolve drive symlinks when querying section names. Based on a patch by Sebastian Lackner. For BeamNG.drive. CW-Bug-Id: 18793 --- dlls/ntdll/unix/virtual.c | 84 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 73c2c88b600..df1482823b9 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -71,6 +71,7 @@ #include "windef.h" #include "winnt.h" #include "winternl.h" +#include "ddk/wdm.h" #include "wine/list.h" #include "wine/rbtree.h" #include "unix_private.h" @@ -4885,6 +4886,86 @@ static NTSTATUS get_working_set_ex( HANDLE process, LPCVOID addr, return STATUS_SUCCESS; } +static NTSTATUS read_nt_symlink( UNICODE_STRING *name, WCHAR *target, DWORD size ) +{ + NTSTATUS status; + OBJECT_ATTRIBUTES attr; + HANDLE handle; + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.ObjectName = name; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + if (!(status = NtOpenSymbolicLinkObject( &handle, SYMBOLIC_LINK_QUERY, &attr ))) + { + UNICODE_STRING targetW; + targetW.Buffer = target; + targetW.MaximumLength = (size - 1) * sizeof(WCHAR); + status = NtQuerySymbolicLinkObject( handle, &targetW, NULL ); + if (!status) target[targetW.Length / sizeof(WCHAR)] = 0; + NtClose( handle ); + } + return status; +} + +static NTSTATUS resolve_drive_symlink( UNICODE_STRING *name, SIZE_T max_name_len, SIZE_T *ret_len, NTSTATUS status ) +{ + static int enabled = -1; + + static const WCHAR dosprefixW[] = {'\\','?','?','\\'}; + UNICODE_STRING device_name; + SIZE_T required_length, symlink_len; + WCHAR symlink[256]; + size_t offset = 0; + + if (enabled == -1) + { + const char *sgi = getenv("SteamGameId"); + + enabled = sgi && !strcmp(sgi, "284160"); + } + if (!enabled) return status; + if (status == STATUS_INFO_LENGTH_MISMATCH) + { + /* FIXME */ + *ret_len += 64; + return status; + } + if (status) return status; + + if (name->Length < sizeof(dosprefixW) || + memcmp( name->Buffer, dosprefixW, sizeof(dosprefixW) )) + return STATUS_SUCCESS; + + offset = ARRAY_SIZE(dosprefixW); + while (offset * sizeof(WCHAR) < name->Length && name->Buffer[ offset ] != '\\') offset++; + + device_name = *name; + device_name.Length = offset * sizeof(WCHAR); + if ((status = read_nt_symlink( &device_name, symlink, ARRAY_SIZE( symlink )))) + { + ERR("read_nt_symlink failed, status %#x.\n", (int)status); + return status; + } + symlink_len = wcslen( symlink ); + required_length = symlink_len * sizeof(WCHAR) + + name->Length - offset * sizeof(WCHAR) + sizeof(WCHAR); + if (ret_len) + *ret_len = sizeof(MEMORY_SECTION_NAME) + required_length; + if (required_length > max_name_len) + return STATUS_INFO_LENGTH_MISMATCH; + + memmove( name->Buffer + symlink_len, name->Buffer + offset, name->Length - offset * sizeof(WCHAR) ); + memcpy( name->Buffer, symlink, symlink_len * sizeof(WCHAR) ); + name->MaximumLength = required_length; + name->Length = required_length - sizeof(WCHAR); + name->Buffer[name->Length / sizeof(WCHAR)] = 0; + return STATUS_SUCCESS; +} + static unsigned int get_memory_section_name( HANDLE process, LPCVOID addr, MEMORY_SECTION_NAME *info, SIZE_T len, SIZE_T *ret_len ) { @@ -4913,7 +4994,8 @@ static unsigned int get_memory_section_name( HANDLE process, LPCVOID addr, } } SERVER_END_REQ; - return status; + + return resolve_drive_symlink( &info->SectionFileName, len - sizeof(*info), ret_len, status ); } From 8fd2138e76a43f420650e2d27738ac0ff6a523c3 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 14 Dec 2021 13:01:58 +0100 Subject: [PATCH 0654/2777] HACK: server: Fake success when trying to bind to an IPX address. --- server/sock.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/sock.c b/server/sock.c index 851723a9d03..eba045c88a7 100644 --- a/server/sock.c +++ b/server/sock.c @@ -2928,7 +2928,11 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) if (check_addr_usage( sock, &bind_addr, v6only )) return; - if (bind( unix_fd, &bind_addr.addr, unix_len ) < 0) + /* Quake (and similar family) fails if we can't bind to an IPX address. This often + * doesn't work on Linux, so just fake success. */ + if (unix_addr.addr.sa_family == AF_IPX) + fprintf( stderr, "wine: HACK: Faking AF_IPX bind success.\n" ); + else if (bind( unix_fd, &bind_addr.addr, unix_len ) < 0) { if (errno == EADDRINUSE && sock->reuseaddr) errno = EACCES; From 9b32dfec0175e35a6b650a95c72a9c584313dece Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 28 Dec 2021 12:05:22 -0600 Subject: [PATCH 0655/2777] xaudio2: Prefer native This should be safe now on 64-bit due to the top-down allocation patches. --- dlls/x3daudio1_0/Makefile.in | 2 ++ dlls/x3daudio1_1/Makefile.in | 2 ++ dlls/x3daudio1_2/Makefile.in | 2 ++ dlls/x3daudio1_3/Makefile.in | 2 ++ dlls/x3daudio1_4/Makefile.in | 2 ++ dlls/x3daudio1_5/Makefile.in | 2 ++ dlls/x3daudio1_6/Makefile.in | 2 ++ dlls/x3daudio1_7/Makefile.in | 2 ++ dlls/xactengine2_0/Makefile.in | 2 ++ dlls/xactengine2_4/Makefile.in | 2 ++ dlls/xactengine2_7/Makefile.in | 2 ++ dlls/xactengine2_9/Makefile.in | 2 ++ dlls/xactengine3_0/Makefile.in | 2 ++ dlls/xactengine3_1/Makefile.in | 2 ++ dlls/xactengine3_2/Makefile.in | 2 ++ dlls/xactengine3_3/Makefile.in | 2 ++ dlls/xactengine3_4/Makefile.in | 2 ++ dlls/xactengine3_5/Makefile.in | 2 ++ dlls/xactengine3_6/Makefile.in | 2 ++ dlls/xactengine3_7/Makefile.in | 2 ++ dlls/xapofx1_1/Makefile.in | 2 ++ dlls/xapofx1_2/Makefile.in | 2 ++ dlls/xapofx1_3/Makefile.in | 2 ++ dlls/xapofx1_4/Makefile.in | 2 ++ dlls/xapofx1_5/Makefile.in | 2 ++ dlls/xaudio2_0/Makefile.in | 2 ++ dlls/xaudio2_1/Makefile.in | 2 ++ dlls/xaudio2_2/Makefile.in | 2 ++ dlls/xaudio2_3/Makefile.in | 2 ++ dlls/xaudio2_4/Makefile.in | 2 ++ dlls/xaudio2_5/Makefile.in | 2 ++ dlls/xaudio2_6/Makefile.in | 2 ++ dlls/xaudio2_7/Makefile.in | 2 ++ dlls/xaudio2_8/Makefile.in | 2 ++ dlls/xaudio2_9/Makefile.in | 2 ++ 35 files changed, 70 insertions(+) diff --git a/dlls/x3daudio1_0/Makefile.in b/dlls/x3daudio1_0/Makefile.in index 7e6bba4a018..d6bc81637f4 100644 --- a/dlls/x3daudio1_0/Makefile.in +++ b/dlls/x3daudio1_0/Makefile.in @@ -4,5 +4,7 @@ PARENTSRC = ../xaudio2_7 IMPORTS = $(FAUDIO_PE_LIBS) EXTRAINCL = $(FAUDIO_PE_CFLAGS) +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ x3daudio.c diff --git a/dlls/x3daudio1_1/Makefile.in b/dlls/x3daudio1_1/Makefile.in index c1a1e0aa647..2bfcd9aee01 100644 --- a/dlls/x3daudio1_1/Makefile.in +++ b/dlls/x3daudio1_1/Makefile.in @@ -4,5 +4,7 @@ PARENTSRC = ../xaudio2_7 IMPORTS = $(FAUDIO_PE_LIBS) EXTRAINCL = $(FAUDIO_PE_CFLAGS) +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ x3daudio.c diff --git a/dlls/x3daudio1_2/Makefile.in b/dlls/x3daudio1_2/Makefile.in index 603e33e2d31..5d8ff406275 100644 --- a/dlls/x3daudio1_2/Makefile.in +++ b/dlls/x3daudio1_2/Makefile.in @@ -4,5 +4,7 @@ PARENTSRC = ../xaudio2_7 IMPORTS = $(FAUDIO_PE_LIBS) EXTRAINCL = $(FAUDIO_PE_CFLAGS) +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ x3daudio.c diff --git a/dlls/x3daudio1_3/Makefile.in b/dlls/x3daudio1_3/Makefile.in index 5bfa657cd9d..e78c861dbc9 100644 --- a/dlls/x3daudio1_3/Makefile.in +++ b/dlls/x3daudio1_3/Makefile.in @@ -4,5 +4,7 @@ PARENTSRC = ../xaudio2_7 IMPORTS = $(FAUDIO_PE_LIBS) EXTRAINCL = $(FAUDIO_PE_CFLAGS) +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ x3daudio.c diff --git a/dlls/x3daudio1_4/Makefile.in b/dlls/x3daudio1_4/Makefile.in index f75f39d8610..c92b62734fa 100644 --- a/dlls/x3daudio1_4/Makefile.in +++ b/dlls/x3daudio1_4/Makefile.in @@ -4,5 +4,7 @@ PARENTSRC = ../xaudio2_7 IMPORTS = $(FAUDIO_PE_LIBS) EXTRAINCL = $(FAUDIO_PE_CFLAGS) +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ x3daudio.c diff --git a/dlls/x3daudio1_5/Makefile.in b/dlls/x3daudio1_5/Makefile.in index fcb6e2866b2..fb8ea571fa1 100644 --- a/dlls/x3daudio1_5/Makefile.in +++ b/dlls/x3daudio1_5/Makefile.in @@ -4,5 +4,7 @@ PARENTSRC = ../xaudio2_7 IMPORTS = $(FAUDIO_PE_LIBS) EXTRAINCL = $(FAUDIO_PE_CFLAGS) +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ x3daudio.c diff --git a/dlls/x3daudio1_6/Makefile.in b/dlls/x3daudio1_6/Makefile.in index 896bab407b2..ab6daa14982 100644 --- a/dlls/x3daudio1_6/Makefile.in +++ b/dlls/x3daudio1_6/Makefile.in @@ -4,5 +4,7 @@ PARENTSRC = ../xaudio2_7 IMPORTS = $(FAUDIO_PE_LIBS) EXTRAINCL = $(FAUDIO_PE_CFLAGS) +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ x3daudio.c diff --git a/dlls/x3daudio1_7/Makefile.in b/dlls/x3daudio1_7/Makefile.in index c6a8ed5102a..1819a787bfb 100644 --- a/dlls/x3daudio1_7/Makefile.in +++ b/dlls/x3daudio1_7/Makefile.in @@ -4,5 +4,7 @@ PARENTSRC = ../xaudio2_7 IMPORTS = $(FAUDIO_PE_LIBS) EXTRAINCL = $(FAUDIO_PE_CFLAGS) +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ x3daudio.c diff --git a/dlls/xactengine2_0/Makefile.in b/dlls/xactengine2_0/Makefile.in index 5c4b635b060..3b846b57cfd 100644 --- a/dlls/xactengine2_0/Makefile.in +++ b/dlls/xactengine2_0/Makefile.in @@ -4,6 +4,8 @@ EXTRAINCL = $(FAUDIO_PE_CFLAGS) EXTRADEFS = -DXACT3_VER=0x0200 PARENTSRC = ../xactengine3_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ xact_dll.c diff --git a/dlls/xactengine2_4/Makefile.in b/dlls/xactengine2_4/Makefile.in index 2b5fd547b61..3aaaf161669 100644 --- a/dlls/xactengine2_4/Makefile.in +++ b/dlls/xactengine2_4/Makefile.in @@ -4,6 +4,8 @@ EXTRAINCL = $(FAUDIO_PE_CFLAGS) EXTRADEFS = -DXACT3_VER=0x0204 PARENTSRC = ../xactengine3_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ xact_dll.c diff --git a/dlls/xactengine2_7/Makefile.in b/dlls/xactengine2_7/Makefile.in index 6861555b23b..8cb340df7b7 100644 --- a/dlls/xactengine2_7/Makefile.in +++ b/dlls/xactengine2_7/Makefile.in @@ -4,6 +4,8 @@ EXTRAINCL = $(FAUDIO_PE_CFLAGS) EXTRADEFS = -DXACT3_VER=0x0207 PARENTSRC = ../xactengine3_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ xact_dll.c diff --git a/dlls/xactengine2_9/Makefile.in b/dlls/xactengine2_9/Makefile.in index e5f8c83e962..7b6be338b10 100644 --- a/dlls/xactengine2_9/Makefile.in +++ b/dlls/xactengine2_9/Makefile.in @@ -4,6 +4,8 @@ EXTRAINCL = $(FAUDIO_PE_CFLAGS) EXTRADEFS = -DXACT3_VER=0x0209 PARENTSRC = ../xactengine3_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ xact_dll.c diff --git a/dlls/xactengine3_0/Makefile.in b/dlls/xactengine3_0/Makefile.in index 10259e44ee0..4ac9ceffda1 100644 --- a/dlls/xactengine3_0/Makefile.in +++ b/dlls/xactengine3_0/Makefile.in @@ -4,6 +4,8 @@ EXTRAINCL = $(FAUDIO_PE_CFLAGS) EXTRADEFS = -DXACT3_VER=0x0300 PARENTSRC = ../xactengine3_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ xact_dll.c diff --git a/dlls/xactengine3_1/Makefile.in b/dlls/xactengine3_1/Makefile.in index 3105c3443bd..8a4857aff64 100644 --- a/dlls/xactengine3_1/Makefile.in +++ b/dlls/xactengine3_1/Makefile.in @@ -4,6 +4,8 @@ EXTRAINCL = $(FAUDIO_PE_CFLAGS) EXTRADEFS = -DXACT3_VER=0x0301 PARENTSRC = ../xactengine3_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ xact_dll.c diff --git a/dlls/xactengine3_2/Makefile.in b/dlls/xactengine3_2/Makefile.in index 92481ba1e26..670209953ed 100644 --- a/dlls/xactengine3_2/Makefile.in +++ b/dlls/xactengine3_2/Makefile.in @@ -4,6 +4,8 @@ EXTRAINCL = $(FAUDIO_PE_CFLAGS) EXTRADEFS = -DXACT3_VER=0x0302 PARENTSRC = ../xactengine3_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ xact_dll.c diff --git a/dlls/xactengine3_3/Makefile.in b/dlls/xactengine3_3/Makefile.in index 1963f033557..781cc7139d2 100644 --- a/dlls/xactengine3_3/Makefile.in +++ b/dlls/xactengine3_3/Makefile.in @@ -4,6 +4,8 @@ EXTRAINCL = $(FAUDIO_PE_CFLAGS) EXTRADEFS = -DXACT3_VER=0x0303 PARENTSRC = ../xactengine3_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ xact_dll.c diff --git a/dlls/xactengine3_4/Makefile.in b/dlls/xactengine3_4/Makefile.in index 5d639c4e7ad..d63360bd100 100644 --- a/dlls/xactengine3_4/Makefile.in +++ b/dlls/xactengine3_4/Makefile.in @@ -4,6 +4,8 @@ EXTRAINCL = $(FAUDIO_PE_CFLAGS) EXTRADEFS = -DXACT3_VER=0x0304 PARENTSRC = ../xactengine3_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ xact_dll.c diff --git a/dlls/xactengine3_5/Makefile.in b/dlls/xactengine3_5/Makefile.in index 47731dd7017..ef2b6c2d303 100644 --- a/dlls/xactengine3_5/Makefile.in +++ b/dlls/xactengine3_5/Makefile.in @@ -4,6 +4,8 @@ EXTRAINCL = $(FAUDIO_PE_CFLAGS) EXTRADEFS = -DXACT3_VER=0x0305 PARENTSRC = ../xactengine3_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ xact_dll.c diff --git a/dlls/xactengine3_6/Makefile.in b/dlls/xactengine3_6/Makefile.in index b0e235ecd08..ba73e069505 100644 --- a/dlls/xactengine3_6/Makefile.in +++ b/dlls/xactengine3_6/Makefile.in @@ -4,6 +4,8 @@ EXTRAINCL = $(FAUDIO_PE_CFLAGS) EXTRADEFS = -DXACT3_VER=0x0306 PARENTSRC = ../xactengine3_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ xact_dll.c diff --git a/dlls/xactengine3_7/Makefile.in b/dlls/xactengine3_7/Makefile.in index 128a41cf59a..65a6f0f2fc5 100644 --- a/dlls/xactengine3_7/Makefile.in +++ b/dlls/xactengine3_7/Makefile.in @@ -3,6 +3,8 @@ IMPORTS = $(FAUDIO_PE_LIBS) ole32 uuid EXTRAINCL = $(FAUDIO_PE_CFLAGS) EXTRADEFS = -DXACT3_VER=0x0307 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ xact_dll.c diff --git a/dlls/xapofx1_1/Makefile.in b/dlls/xapofx1_1/Makefile.in index 1eb2e2210c0..af6c647534f 100644 --- a/dlls/xapofx1_1/Makefile.in +++ b/dlls/xapofx1_1/Makefile.in @@ -4,6 +4,8 @@ IMPORTS = $(FAUDIO_PE_LIBS) ole32 EXTRAINCL = $(FAUDIO_PE_CFLAGS) PARENTSRC = ../xaudio2_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ xapo.c \ xapofx.c \ diff --git a/dlls/xapofx1_2/Makefile.in b/dlls/xapofx1_2/Makefile.in index 38db115b39a..a9574f08ffd 100644 --- a/dlls/xapofx1_2/Makefile.in +++ b/dlls/xapofx1_2/Makefile.in @@ -4,6 +4,8 @@ IMPORTS = $(FAUDIO_PE_LIBS) ole32 EXTRAINCL = $(FAUDIO_PE_CFLAGS) PARENTSRC = ../xaudio2_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ xapo.c \ xapofx.c \ diff --git a/dlls/xapofx1_3/Makefile.in b/dlls/xapofx1_3/Makefile.in index 409fc9ad55b..6fc3971c3b4 100644 --- a/dlls/xapofx1_3/Makefile.in +++ b/dlls/xapofx1_3/Makefile.in @@ -4,6 +4,8 @@ IMPORTS = $(FAUDIO_PE_LIBS) ole32 EXTRAINCL = $(FAUDIO_PE_CFLAGS) PARENTSRC = ../xaudio2_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ xapo.c \ xapofx.c \ diff --git a/dlls/xapofx1_4/Makefile.in b/dlls/xapofx1_4/Makefile.in index 63eccff64b0..ba659ef04fd 100644 --- a/dlls/xapofx1_4/Makefile.in +++ b/dlls/xapofx1_4/Makefile.in @@ -4,6 +4,8 @@ IMPORTS = $(FAUDIO_PE_LIBS) ole32 EXTRAINCL = $(FAUDIO_PE_CFLAGS) PARENTSRC = ../xaudio2_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ xapo.c \ xapofx.c \ diff --git a/dlls/xapofx1_5/Makefile.in b/dlls/xapofx1_5/Makefile.in index fc692d781db..647171e3982 100644 --- a/dlls/xapofx1_5/Makefile.in +++ b/dlls/xapofx1_5/Makefile.in @@ -4,6 +4,8 @@ IMPORTS = $(FAUDIO_PE_LIBS) ole32 EXTRAINCL = $(FAUDIO_PE_CFLAGS) PARENTSRC = ../xaudio2_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ xapo.c \ xapofx.c \ diff --git a/dlls/xaudio2_0/Makefile.in b/dlls/xaudio2_0/Makefile.in index 860e03e716f..ce1c310d026 100644 --- a/dlls/xaudio2_0/Makefile.in +++ b/dlls/xaudio2_0/Makefile.in @@ -4,6 +4,8 @@ IMPORTS = $(FAUDIO_PE_LIBS) advapi32 ole32 user32 uuid EXTRAINCL = $(FAUDIO_PE_CFLAGS) PARENTSRC = ../xaudio2_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ compat.c \ xapo.c \ diff --git a/dlls/xaudio2_1/Makefile.in b/dlls/xaudio2_1/Makefile.in index fa942761308..7a636dffbf9 100644 --- a/dlls/xaudio2_1/Makefile.in +++ b/dlls/xaudio2_1/Makefile.in @@ -4,6 +4,8 @@ IMPORTS = $(FAUDIO_PE_LIBS) advapi32 ole32 user32 uuid EXTRAINCL = $(FAUDIO_PE_CFLAGS) PARENTSRC = ../xaudio2_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ compat.c \ xapo.c \ diff --git a/dlls/xaudio2_2/Makefile.in b/dlls/xaudio2_2/Makefile.in index 26eee0a6f31..1e83a9ed8e1 100644 --- a/dlls/xaudio2_2/Makefile.in +++ b/dlls/xaudio2_2/Makefile.in @@ -4,6 +4,8 @@ IMPORTS = $(FAUDIO_PE_LIBS) advapi32 ole32 user32 uuid EXTRAINCL = $(FAUDIO_PE_CFLAGS) PARENTSRC = ../xaudio2_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ compat.c \ xapo.c \ diff --git a/dlls/xaudio2_3/Makefile.in b/dlls/xaudio2_3/Makefile.in index f6c555a9a3b..8a608ca6a08 100644 --- a/dlls/xaudio2_3/Makefile.in +++ b/dlls/xaudio2_3/Makefile.in @@ -4,6 +4,8 @@ IMPORTS = $(FAUDIO_PE_LIBS) advapi32 ole32 user32 uuid EXTRAINCL = $(FAUDIO_PE_CFLAGS) PARENTSRC = ../xaudio2_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ compat.c \ xapo.c \ diff --git a/dlls/xaudio2_4/Makefile.in b/dlls/xaudio2_4/Makefile.in index 33bd0c155db..3219943b70e 100644 --- a/dlls/xaudio2_4/Makefile.in +++ b/dlls/xaudio2_4/Makefile.in @@ -4,6 +4,8 @@ IMPORTS = $(FAUDIO_PE_LIBS) advapi32 ole32 user32 uuid EXTRAINCL = $(FAUDIO_PE_CFLAGS) PARENTSRC = ../xaudio2_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ compat.c \ xapo.c \ diff --git a/dlls/xaudio2_5/Makefile.in b/dlls/xaudio2_5/Makefile.in index c4035aeb13f..35711bf0506 100644 --- a/dlls/xaudio2_5/Makefile.in +++ b/dlls/xaudio2_5/Makefile.in @@ -4,6 +4,8 @@ IMPORTS = $(FAUDIO_PE_LIBS) advapi32 ole32 user32 uuid EXTRAINCL = $(FAUDIO_PE_CFLAGS) PARENTSRC = ../xaudio2_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ compat.c \ xapo.c \ diff --git a/dlls/xaudio2_6/Makefile.in b/dlls/xaudio2_6/Makefile.in index dbe2ae7829f..f034a3a15d0 100644 --- a/dlls/xaudio2_6/Makefile.in +++ b/dlls/xaudio2_6/Makefile.in @@ -4,6 +4,8 @@ IMPORTS = $(FAUDIO_PE_LIBS) advapi32 ole32 user32 uuid EXTRAINCL = $(FAUDIO_PE_CFLAGS) PARENTSRC = ../xaudio2_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ compat.c \ xapo.c \ diff --git a/dlls/xaudio2_7/Makefile.in b/dlls/xaudio2_7/Makefile.in index ef3987b693e..2b4fe67ea95 100644 --- a/dlls/xaudio2_7/Makefile.in +++ b/dlls/xaudio2_7/Makefile.in @@ -3,6 +3,8 @@ MODULE = xaudio2_7.dll IMPORTS = $(FAUDIO_PE_LIBS) advapi32 ole32 user32 uuid EXTRAINCL = $(FAUDIO_PE_CFLAGS) +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ compat.c \ x3daudio.c \ diff --git a/dlls/xaudio2_8/Makefile.in b/dlls/xaudio2_8/Makefile.in index 3e00abd892d..152715f8802 100644 --- a/dlls/xaudio2_8/Makefile.in +++ b/dlls/xaudio2_8/Makefile.in @@ -4,6 +4,8 @@ IMPORTS = $(FAUDIO_PE_LIBS) advapi32 ole32 user32 uuid EXTRAINCL = $(FAUDIO_PE_CFLAGS) PARENTSRC = ../xaudio2_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ compat.c \ x3daudio.c \ diff --git a/dlls/xaudio2_9/Makefile.in b/dlls/xaudio2_9/Makefile.in index eb299816b55..55017871b2f 100644 --- a/dlls/xaudio2_9/Makefile.in +++ b/dlls/xaudio2_9/Makefile.in @@ -4,6 +4,8 @@ IMPORTS = $(FAUDIO_PE_LIBS) advapi32 ole32 user32 uuid EXTRAINCL = $(FAUDIO_PE_CFLAGS) PARENTSRC = ../xaudio2_7 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ compat.c \ x3daudio.c \ From d8bf2c7476c39d0e231b08b3ae006cfc5227c8c7 Mon Sep 17 00:00:00 2001 From: Esme Povirk Date: Tue, 6 Sep 2022 13:40:05 -0500 Subject: [PATCH 0656/2777] Enable field-loading hack for Primal Carnage: Extinction. --- dlls/mscoree/metahost.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/mscoree/metahost.c b/dlls/mscoree/metahost.c index d35064e9af3..23dd34ed6e3 100644 --- a/dlls/mscoree/metahost.c +++ b/dlls/mscoree/metahost.c @@ -1872,6 +1872,12 @@ static MonoAssembly* CDECL wine_mono_assembly_preload_hook_fn(MonoAssemblyName * "317940", /* Karmaflow */ "namespace ContentBrowser { class IContentBrowserBackendInterface {} class Package {} } " }, + { + "UnrealEdCSharp", + "UnrealEdCSharp.dll", + "321360", /* Primal Carnage: Extinction */ + "namespace ContentBrowser { class IContentBrowserBackendInterface {} class Package {} } " + }, }; for (i = 0; i < ARRAY_SIZE(assembly_hacks); ++i) From 5f6111f02152b502b1537d15fc2c0b51b3ade1cb Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 12 Oct 2022 19:24:45 -0500 Subject: [PATCH 0657/2777] ntdll: Enable LFH in RtlCreateHeap(). CW-Bug-Id: #21364 --- dlls/ntdll/heap.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 9b8ecdc487a..76e0e04f09d 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -1400,6 +1400,13 @@ HANDLE WINAPI RtlCreateHeap( ULONG flags, void *addr, SIZE_T total_size, SIZE_T list_init( &process_heap->entry ); } + if (!(flags & HEAP_CREATE_ENABLE_EXECUTE)) + { + ULONG hci = 2; + + RtlSetHeapInformation(heap, HeapCompatibilityInformation, &hci, sizeof(hci)); + } + return heap; } @@ -2062,7 +2069,7 @@ NTSTATUS WINAPI RtlSetHeapInformation( HANDLE handle, HEAP_INFORMATION_CLASS inf FIXME( "HeapCompatibilityInformation %lu not implemented!\n", compat_info ); return STATUS_UNSUCCESSFUL; } - if (InterlockedCompareExchange( &heap->compat_info, compat_info, HEAP_STD )) return STATUS_UNSUCCESSFUL; + InterlockedCompareExchange( &heap->compat_info, compat_info, HEAP_STD ); return STATUS_SUCCESS; } From 5769d2a22fb33de8968860da210ecfd1f4048673 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 15 Mar 2021 13:10:16 -0500 Subject: [PATCH 0658/2777] ntdll: HACK: Add WINE_HEAP_DELAY_FREE variable to force the use of pending free buffer. CW-Bug-Id: #20334 --- dlls/ntdll/heap.c | 9 ++++++--- dlls/ntdll/loader.c | 43 +++++++++++++++++++++-------------------- dlls/ntdll/ntdll_misc.h | 2 ++ 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 76e0e04f09d..9dc0f0e8908 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -225,6 +225,8 @@ C_ASSERT( offsetof(struct heap, subheap) <= REGION_ALIGN - 1 ); #define HEAP_DEF_SIZE (0x40000 * BLOCK_ALIGN) #define MAX_FREE_PENDING 1024 /* max number of free requests to delay */ +BOOL delay_heap_free = FALSE; + static struct heap *process_heap; /* main process heap */ /* check if memory range a contains memory range b */ @@ -1286,8 +1288,8 @@ static void heap_set_debug_flags( HANDLE handle ) } } - if ((heap->flags & HEAP_GROWABLE) && !heap->pending_free && - ((flags & HEAP_FREE_CHECKING_ENABLED) || RUNNING_ON_VALGRIND)) + if (delay_heap_free || ((heap->flags & HEAP_GROWABLE) && !heap->pending_free && + ((flags & HEAP_FREE_CHECKING_ENABLED) || RUNNING_ON_VALGRIND))) { heap->pending_free = RtlAllocateHeap( handle, HEAP_ZERO_MEMORY, MAX_FREE_PENDING * sizeof(*heap->pending_free) ); @@ -2069,7 +2071,8 @@ NTSTATUS WINAPI RtlSetHeapInformation( HANDLE handle, HEAP_INFORMATION_CLASS inf FIXME( "HeapCompatibilityInformation %lu not implemented!\n", compat_info ); return STATUS_UNSUCCESSFUL; } - InterlockedCompareExchange( &heap->compat_info, compat_info, HEAP_STD ); + if (!delay_heap_free) + InterlockedCompareExchange( &heap->compat_info, compat_info, HEAP_STD ); return STATUS_SUCCESS; } diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 2801227d518..a93ff3048b3 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -3071,29 +3071,19 @@ static WCHAR *strstriW( const WCHAR *str, const WCHAR *sub ) return NULL; } -static WCHAR *get_env( const WCHAR *var ) +static BOOL get_env( const WCHAR *var, WCHAR *val, unsigned int len ) { UNICODE_STRING name, value; - RtlInitUnicodeString( &name, var ); - value.Length = 0; - value.MaximumLength = 0; - value.Buffer = NULL; - - if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL) { - - value.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, value.Length + sizeof(WCHAR) ); - value.MaximumLength = value.Length; + name.Length = wcslen( var ) * sizeof(WCHAR); + name.MaximumLength = name.Length + sizeof(WCHAR); + name.Buffer = (WCHAR *)var; - if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_SUCCESS) { - value.Buffer[value.Length / sizeof(WCHAR)] = 0; - return value.Buffer; - } - - RtlFreeHeap( GetProcessHeap(), 0, value.Buffer ); - } + value.Length = 0; + value.MaximumLength = len; + value.Buffer = val; - return NULL; + return !RtlQueryEnvironmentVariable_U( NULL, &name, &value ); } /*********************************************************************** @@ -3161,8 +3151,9 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, UNI * Some games try to load mfc42.dll, but then proceed to not use it. * Just return a handle to kernel32 in that case. */ - WCHAR *sgi = get_env( L"SteamGameId" ); - if (sgi) + WCHAR sgi[32]; + + if (get_env( L"SteamGameId", sgi, sizeof(sgi) )) { if (!wcscmp( sgi, L"105450") && strstriW( libname, L"mfc42" )) @@ -3170,7 +3161,6 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, UNI WARN_(loaddll)( "Using a fake mfc42 handle\n" ); status = find_dll_file( load_path, L"kernel32.dll", nt_name, pwm, mapping, image_info, id ); } - RtlFreeHeap(GetProcessHeap(), 0, sgi); } } return status; @@ -4193,6 +4183,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR ANSI_STRING func_name; WINE_MODREF *kernel32; PEB *peb = NtCurrentTeb()->Peb; + WCHAR env_str[16]; NtQueryVirtualMemory( GetCurrentProcess(), LdrInitializeThunk, MemoryBasicInformation, &meminfo, sizeof(meminfo), NULL ); @@ -4204,6 +4195,16 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR peb->TlsBitmap = &tls_bitmap; peb->TlsExpansionBitmap = &tls_expansion_bitmap; peb->LoaderLock = &loader_section; + + if (get_env( L"WINE_HEAP_DELAY_FREE", env_str, sizeof(env_str)) ) + { + if (env_str[0] == L'1') + { + ERR( "Enabling heap free delay hack.\n" ); + delay_heap_free = TRUE; + } + } + peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL ); RtlInitializeBitMap( &tls_bitmap, peb->TlsBitmapBits, sizeof(peb->TlsBitmapBits) * 8 ); diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index d141fac99d4..28519099e27 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -45,6 +45,8 @@ static const UINT_PTR page_size = 0x1000; extern UINT_PTR page_size DECLSPEC_HIDDEN; #endif +extern BOOL delay_heap_free DECLSPEC_HIDDEN; + /* exceptions */ extern LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context ) DECLSPEC_HIDDEN; extern void DECLSPEC_NORETURN raise_status( NTSTATUS status, EXCEPTION_RECORD *rec ) DECLSPEC_HIDDEN; From df92aaae9290b1b3fd8df168266af6458df8ea76 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Mon, 21 Mar 2022 14:02:30 -0500 Subject: [PATCH 0659/2777] msv1_0: Downgrade missing ntlm_auth message This appears in almost every log and is almost never actually a problem. --- dlls/msv1_0/unixlib.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dlls/msv1_0/unixlib.c b/dlls/msv1_0/unixlib.c index 779250fc650..8a023c2d498 100644 --- a/dlls/msv1_0/unixlib.c +++ b/dlls/msv1_0/unixlib.c @@ -40,7 +40,6 @@ #include "unixlib.h" WINE_DEFAULT_DEBUG_CHANNEL(ntlm); -WINE_DECLARE_DEBUG_CHANNEL(winediag); #define INITIAL_BUFFER_SIZE 200 @@ -229,7 +228,7 @@ static NTSTATUS ntlm_check_version( void *args ) status = STATUS_SUCCESS; } - if (status) ERR_(winediag)( "ntlm_auth was not found. Make sure that ntlm_auth >= 3.0.25 is in your path. " + if (status) WARN( "ntlm_auth was not found. Make sure that ntlm_auth >= 3.0.25 is in your path. " "Usually, you can find it in the winbind package of your distribution.\n" ); ntlm_cleanup( &ctx ); return status; From 02c7b4807c3ada679893e9d82bcedd6219c8625b Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Fri, 25 Feb 2022 11:03:00 +0800 Subject: [PATCH 0660/2777] HACK: ntdll: Replace STATUS_NETWORK_UNREACHABLE with STATUS_SUCCESS in sock_send() for VRChat UDP sockets. On Windows, when resuming from sleep and network is temporarily unavailable but network adapters are still up, send() for UDP sockets sliently drop UDP packets and report STATUS_SUCCESS. On Linux, sendmsg() reports ENETUNREACH, which eventually translated to winsock error WSAENETUNREACH and make VRChat show an internal error message and hang. CW-Bug-Id: #20008 Signed-off-by: Zhiyi Zhang --- dlls/ntdll/unix/socket.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index ac351a17a70..f4ea5e93ea0 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -152,6 +152,8 @@ struct async_transmit_ioctl LARGE_INTEGER offset; }; +static int get_sock_type( HANDLE handle ); + static NTSTATUS sock_errno_to_status( int err ) { switch (err) @@ -1045,6 +1047,21 @@ static NTSTATUS try_send( int fd, struct async_send_ioctl *async ) return STATUS_SUCCESS; } +static void hack_update_status( HANDLE handle, unsigned int *status ) +{ + /* HACK: VRChat relies on send() reporting STATUS_SUCCESS for dropped UDP sockets when the + * network is actually lost but network adapters are still up on Windows. Fix VRChat internal + * error bug when resuming from sleep */ + const char *appid; + + if (*status == STATUS_NETWORK_UNREACHABLE && get_sock_type( handle ) == SOCK_DGRAM + && (appid = getenv( "SteamAppId" )) && !strcmp( appid, "438100" )) + { + WARN( "Replacing STATUS_NETWORK_UNREACHABLE with STATUS_SUCCESS for VRChat.\n" ); + *status = STATUS_SUCCESS; + } +} + static BOOL async_send_proc( void *user, ULONG_PTR *info, unsigned int *status ) { struct async_send_ioctl *async = user; @@ -1059,6 +1076,7 @@ static BOOL async_send_proc( void *user, ULONG_PTR *info, unsigned int *status ) *status = try_send( fd, async ); TRACE( "got status %#x\n", *status ); + hack_update_status( async->io.handle, status ); if (needs_close) close( fd ); @@ -1125,6 +1143,8 @@ static NTSTATUS sock_send( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi ULONG_PTR information; status = try_send( fd, async ); + hack_update_status( handle, &status ); + if (status == STATUS_DEVICE_NOT_READY && (force_async || !nonblocking)) status = STATUS_PENDING; @@ -1195,7 +1215,6 @@ static NTSTATUS sock_ioctl_send( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap return sock_send( handle, event, apc, apc_user, io, fd, async, force_async ); } - NTSTATUS sock_write( HANDLE handle, int fd, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io, const void *buffer, ULONG length ) { From d851c6edef1a93f003577f46bfd4d08360cb2241 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 10 Feb 2022 16:17:41 +0300 Subject: [PATCH 0661/2777] 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 9bdb2f6d6fb..46ddfc91246 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -1273,6 +1273,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 4483303decc..49535567486 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -1031,6 +1031,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 a19d7be8b89..a8b68bdb412 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1799,6 +1799,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 3eb24aeaefe..b52d50a7820 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2159,6 +2159,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 7c7391b5d38..a08626e3db9 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -93,7 +93,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 = 0x100000; -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) @@ -342,6 +343,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 df1482823b9..e48eed27101 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -3351,6 +3351,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; @@ -3395,6 +3396,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 | VPROT_READ ); + mprotect_range( kernel_stack, kernel_stack_guard_size, 0, 0 ); } /* note: limit is lower than base since the stack grows down */ From 9ee88665f3cf29ecf712a4518b275e7e7e1ebeb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=BCller?= Date: Thu, 1 Jun 2017 06:04:53 +0200 Subject: [PATCH 0662/2777] ntdll: Fix holes in ELF mappings. (v2) Based on a patch by Andrew Wesie. Included to fix crash on startup of WRC8. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44650 Link: https://github.com/wine-staging/wine-staging/tree/v6.3/patches/ntdll-Builtin_Prot Link: https://github.com/ValveSoftware/wine/pull/121 CW-Bug-Id: #19337 --- dlls/ntdll/unix/virtual.c | 25 +++++++++++++++++++++++++ dlls/psapi/tests/psapi_main.c | 14 +++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index e48eed27101..d90c8af6e6e 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -3508,6 +3508,16 @@ static NTSTATUS grow_thread_stack( char *page, struct thread_stack_info *stack_i } +/*********************************************************************** + * is_system_range + */ +static inline BOOL is_system_range( const void *addr, size_t size ) +{ + struct file_view *view = find_view( addr, size ); + return view && (view->protect & VPROT_SYSTEM); +} + + /*********************************************************************** * virtual_handle_fault */ @@ -3544,6 +3554,21 @@ NTSTATUS virtual_handle_fault( void *addr, DWORD err, void *stack ) ret = STATUS_SUCCESS; } } + else if (!err && (get_unix_prot( vprot ) & PROT_READ) && is_system_range( page, page_size )) + { + int unix_prot = get_unix_prot( vprot ); + unsigned char vec; + + TRACE("yolo\n"); + + mprotect_range( page, page_size, 0, 0 ); + if (!mincore( page, page_size, &vec ) && (vec & 1)) + ret = STATUS_SUCCESS; + else if (anon_mmap_fixed( page, page_size, unix_prot, 0 ) == page) + ret = STATUS_SUCCESS; + else + set_page_vprot_bits( page, page_size, 0, VPROT_READ | VPROT_EXEC ); + } mutex_unlock( &virtual_mutex ); return ret; } diff --git a/dlls/psapi/tests/psapi_main.c b/dlls/psapi/tests/psapi_main.c index 185a4062092..d2589efd325 100644 --- a/dlls/psapi/tests/psapi_main.c +++ b/dlls/psapi/tests/psapi_main.c @@ -194,6 +194,7 @@ static void test_EnumProcessModules(void) static void test_GetModuleInformation(void) { HMODULE hMod = GetModuleHandleA(NULL); + DWORD *tmp, counter = 0; MODULEINFO info; DWORD ret; @@ -213,10 +214,21 @@ static void test_GetModuleInformation(void) GetModuleInformation(hpQV, hMod, &info, sizeof(info)-1); ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "expected error=ERROR_INSUFFICIENT_BUFFER but got %ld\n", GetLastError()); - SetLastError(0xdeadbeef); ret = GetModuleInformation(hpQV, hMod, &info, sizeof(info)); ok(ret == 1, "failed with %ld\n", GetLastError()); ok(info.lpBaseOfDll == hMod, "lpBaseOfDll=%p hMod=%p\n", info.lpBaseOfDll, hMod); + + hMod = LoadLibraryA("shell32.dll"); + ok(hMod != NULL, "Failed to load shell32.dll, error: %u\n", GetLastError()); + + ret = GetModuleInformation(hpQV, hMod, &info, sizeof(info)); + ok(ret == 1, "failed with %d\n", GetLastError()); + info.SizeOfImage /= sizeof(DWORD); + for (tmp = (DWORD *)hMod; info.SizeOfImage; info.SizeOfImage--) + counter ^= *tmp++; + trace("xor of shell32: %08x\n", counter); + + FreeLibrary(hMod); } static BOOL check_with_margin(SIZE_T perf, SIZE_T sysperf, int margin) From ea284b0383185ed4ba7a29a8bf69ddb0085aa111 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 17 Nov 2022 20:00:24 -0600 Subject: [PATCH 0663/2777] ntdll: Return FILE_DEVICE_UNKNOWN for Unix FIFOs and sockets from get_device_info(). CW-Bug-Id: #21570 --- dlls/ntdll/unix/file.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 500575bb26c..9de7e536304 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -6967,7 +6967,7 @@ NTSTATUS get_device_info( int fd, FILE_FS_DEVICE_INFORMATION *info ) } else if (S_ISFIFO( st.st_mode ) || S_ISSOCK( st.st_mode )) { - info->DeviceType = FILE_DEVICE_NAMED_PIPE; + info->DeviceType = FILE_DEVICE_UNKNOWN; } else if (is_device_placeholder( fd )) { @@ -7076,10 +7076,11 @@ NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, IO_STATUS_BLOCK *io void *buffer, ULONG length, FS_INFORMATION_CLASS info_class ) { + enum server_fd_type fd_type; int fd, needs_close; unsigned int status; - status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ); + status = server_get_unix_fd( handle, 0, &fd, &needs_close, &fd_type, NULL ); if (status == STATUS_BAD_DEVICE_TYPE) { struct async_irp *async; @@ -7146,7 +7147,15 @@ NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, IO_STATUS_BLOCK *io { FILE_FS_DEVICE_INFORMATION *info = buffer; - if ((status = get_device_info( fd, info )) == STATUS_SUCCESS) + if (fd_type == FD_TYPE_SOCKET || fd_type == FD_TYPE_PIPE) + { + info->Characteristics = 0; + info->DeviceType = FILE_DEVICE_NAMED_PIPE; + status = STATUS_SUCCESS; + } + else status = get_device_info( fd, info ); + + if (!status) io->Information = sizeof(*info); } break; From 0c0d7303ccdb509ef70e3534df68d4fab7018ca8 Mon Sep 17 00:00:00 2001 From: Etaash Mathamsetty Date: Sat, 19 Nov 2022 14:52:08 -0500 Subject: [PATCH 0664/2777] kernel32: Implement various transacted file APIs Link: https://gitlab.winehq.org/wine/wine/-/merge_requests/1145 CW-Bug-Id: #21447 --- dlls/kernel32/kernel32.spec | 22 ++++--- dlls/kernel32/path.c | 123 ++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 10 deletions(-) diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 3260a16d2a5..caa2f42d07c 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -272,8 +272,8 @@ @ stdcall -import CreateDirectoryA(str ptr) @ stdcall CreateDirectoryExA(str str ptr) @ stdcall -import CreateDirectoryExW(wstr wstr ptr) -# @ stub CreateDirectoryTransactedA -# @ stub CreateDirectoryTransactedW +@ stdcall CreateDirectoryTransactedA(str str ptr ptr) +@ stdcall CreateDirectoryTransactedW(wstr wstr ptr ptr) @ stdcall -import CreateDirectoryW(wstr ptr) @ stdcall -import CreateEventA(ptr long long str) @ stdcall -import CreateEventExA(ptr str long long) @@ -283,12 +283,14 @@ @ stdcall -import CreateFiberEx(long long long ptr ptr) @ stdcall -import CreateFile2(wstr long long long ptr) @ stdcall -import CreateFileA(str long long ptr long long long) +@ stdcall CreateFileTransactedA(str long long ptr long long long ptr ptr ptr) @ stdcall CreateFileMappingA(long ptr long long long str) # @ stub CreateFileMappingNumaA @ stdcall CreateFileMappingFromApp(long ptr long int64 wstr) kernelbase.CreateFileMappingFromApp @ stdcall -import CreateFileMappingNumaW(long ptr long long long wstr long) @ stdcall -import CreateFileMappingW(long ptr long long long wstr) @ stdcall -import CreateFileW(wstr long long ptr long long long) +@ stdcall CreateFileTransactedW(wstr long long ptr long long long ptr ptr ptr) @ stdcall -import CreateHardLinkA(str str ptr) @ stdcall CreateHardLinkTransactedA(str str ptr ptr) @ stdcall CreateHardLinkTransactedW(wstr wstr ptr ptr) @@ -365,8 +367,8 @@ @ stdcall DeleteCriticalSection(ptr) NTDLL.RtlDeleteCriticalSection @ stdcall -import DeleteFiber(ptr) @ stdcall -import DeleteFileA(str) -# @ stub DeleteFileTransactedA -# @ stub DeleteFileTransactedW +@ stdcall DeleteFileTransactedA(str ptr) +@ stdcall DeleteFileTransactedW(wstr ptr) @ stdcall -import DeleteFileW(wstr) @ stdcall -import DeleteProcThreadAttributeList(ptr) # @ stub DisableThreadProfiling @@ -487,8 +489,8 @@ @ stdcall -import FindFirstFileExW(wstr long ptr long ptr long) # @ stub FindFirstFileNameTransactedW # @ stub FindFirstFileNameW -# @ stub FindFirstFileTransactedA -# @ stub FindFirstFileTransactedW +@ stdcall FindFirstFileTransactedA(str long ptr long ptr long ptr) +@ stdcall FindFirstFileTransactedW(wstr long ptr long ptr long ptr) @ stdcall -import FindFirstFileW(wstr ptr) # @ stub FindFirstStreamTransactedW @ stdcall -import FindFirstStreamW(wstr long ptr long) @@ -676,8 +678,8 @@ @ stdcall -import GetFileAttributesA(str) @ stdcall -import GetFileAttributesExA(str long ptr) @ stdcall -import GetFileAttributesExW(wstr long ptr) -# @ stub GetFileAttributesTransactedA -# @ stub GetFileAttributesTransactedW +@ stdcall GetFileAttributesTransactedA(str long ptr ptr) +@ stdcall GetFileAttributesTransactedW(wstr long ptr ptr) @ stdcall -import GetFileAttributesW(wstr) # @ stub GetFileBandwidthReservation @ stdcall -import GetFileInformationByHandle(long ptr) @@ -1293,8 +1295,8 @@ @ stdcall -import ReplaceFile(wstr wstr wstr long ptr ptr) ReplaceFileW @ stdcall ReplaceFileA(str str str long ptr ptr) @ stdcall -import ReplaceFileW(wstr wstr wstr long ptr ptr) -# @ stub RemoveDirectoryTransactedA -# @ stub RemoveDirectoryTransactedW +@ stdcall RemoveDirectoryTransactedA(str ptr) +@ stdcall RemoveDirectoryTransactedW(wstr ptr) @ stdcall -import RemoveDllDirectory(ptr) # @ stub RemoveSecureMemoryCacheCallback # @ stub ReplacePartitionUnit diff --git a/dlls/kernel32/path.c b/dlls/kernel32/path.c index 2dd3eac3c26..f916606ef13 100644 --- a/dlls/kernel32/path.c +++ b/dlls/kernel32/path.c @@ -158,6 +158,129 @@ BOOL WINAPI MoveFileTransactedW(const WCHAR *source, const WCHAR *dest, LPPROGRE return FALSE; } +/************************************************************************* + * CreateFileTransactedA (KERNEL32.@) + */ +HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileTransactedA( LPCSTR name, DWORD access, DWORD sharing, + LPSECURITY_ATTRIBUTES sa, DWORD creation, + DWORD attributes, HANDLE template, + HANDLE transaction, PUSHORT pusMiniVersion, + PVOID pExtendedParameter ) +{ + FIXME( "(%s %lx %lx %p %lx %lx %p %p %p %p), semi-stub\n", debugstr_a(name), access, sharing, sa, + creation, attributes, template, transaction, pusMiniVersion, pExtendedParameter ); + + return CreateFileA( name, access, sharing, sa, creation, attributes, template ); +} + +/************************************************************************* + * CreateFileTransactedW (KERNEL32.@) + */ +HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileTransactedW( LPCWSTR name, DWORD access, DWORD sharing, + LPSECURITY_ATTRIBUTES sa, DWORD creation, + DWORD attributes, HANDLE template, HANDLE transaction, + PUSHORT pusMiniVersion, PVOID pExtendedParameter ) +{ + FIXME( "(%s %lx %lx %p %lx %lx %p %p %p %p), semi-stub\n", debugstr_w(name), access, sharing, sa, + creation, attributes, template, transaction, pusMiniVersion, pExtendedParameter ); + + return CreateFileW( name, access, sharing, sa, creation, attributes, template ); +} + +/*********************************************************************** + * CreateDirectoryTransactedA (KERNEL32.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH CreateDirectoryTransactedA(LPCSTR template, LPCSTR path, LPSECURITY_ATTRIBUTES sa, HANDLE hTransaction) +{ + FIXME("(%s %s %p %p), semi-stub\n", debugstr_a(template), debugstr_a(path), sa, hTransaction); + return CreateDirectoryExA(template, path, sa); +} + +/*********************************************************************** + * CreateDirectoryTransactedW (KERNEL32.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH CreateDirectoryTransactedW(LPCWSTR template, LPCWSTR path, LPSECURITY_ATTRIBUTES sa, HANDLE hTransaction) +{ + FIXME("(%s %s %p %p), semi-stub\n", debugstr_w(template), debugstr_w(path), sa, hTransaction); + return CreateDirectoryExW(template, path, sa); +} + +/*********************************************************************** + * DeleteFileTransactedA (KERNEL32.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH DeleteFileTransactedA(LPCSTR path, HANDLE hTransaction) +{ + FIXME("(%s %p): semi-stub\n", debugstr_a(path), hTransaction); + return DeleteFileA(path); +} + +/*********************************************************************** + * DeleteFileTransactedW (KERNEL32.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH DeleteFileTransactedW(LPCWSTR path, HANDLE hTransaction) +{ + FIXME("(%s %p): semi-stub\n", debugstr_w(path), hTransaction); + return DeleteFileW(path); +} + +/****************************************************************************** + * FindFirstFileTransactedA (KERNEL32.@) + */ +HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileTransactedA(LPCSTR filename, FINDEX_INFO_LEVELS level, + LPVOID data, FINDEX_SEARCH_OPS search_op, + LPVOID filter, DWORD flags, HANDLE hTransaction) +{ + FIXME( "(%s %d %p %d %p %lx %p): semi-stub\n", debugstr_a(filename), level, data, search_op, filter, flags, hTransaction ); + return FindFirstFileExA(filename, level, data, search_op, filter, flags); +} + +/****************************************************************************** + * FindFirstFileTransactedW (KERNEL32.@) + */ +HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileTransactedW(LPCWSTR filename, FINDEX_INFO_LEVELS level, + LPVOID data, FINDEX_SEARCH_OPS search_op, + LPVOID filter, DWORD flags, HANDLE hTransaction) +{ + FIXME( "(%s %d %p %d %p %lx %p): semi-stub\n", debugstr_w(filename), level, data, search_op, filter, flags, hTransaction ); + return FindFirstFileExW(filename, level, data, search_op, filter, flags); +} + +/************************************************************************** + * GetFileAttributesTransactedA (KERNEL32.@) + */ +DWORD WINAPI DECLSPEC_HOTPATCH GetFileAttributesTransactedA(LPCSTR name, GET_FILEEX_INFO_LEVELS level, LPVOID ptr, HANDLE hTransaction) +{ + FIXME("(%s %p): semi-stub\n", debugstr_a(name), hTransaction); + return GetFileAttributesExA(name, level, ptr); +} + +/************************************************************************** + * GetFileAttributesTransactedW (KERNEL32.@) + */ +DWORD WINAPI DECLSPEC_HOTPATCH GetFileAttributesTransactedW(LPCWSTR name, GET_FILEEX_INFO_LEVELS level, void *ptr, HANDLE hTransaction) +{ + FIXME("(%s %p): semi-stub\n", debugstr_w(name), hTransaction); + return GetFileAttributesExW(name, level, ptr); +} + +/*********************************************************************** + * RemoveDirectoryTransactedA (KERNEL32.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH RemoveDirectoryTransactedA( LPCSTR path, HANDLE hTransaction ) +{ + FIXME("(%s %p), semi-stub\n", debugstr_a(path), hTransaction); + return RemoveDirectoryA(path); +} + +/*********************************************************************** + * RemoveDirectoryTransactedW (KERNEL32.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH RemoveDirectoryTransactedW( LPCWSTR path, HANDLE hTransaction ) +{ + FIXME("(%s %p), semi-stub\n", debugstr_w(path), hTransaction); + return RemoveDirectoryW(path); +} + /************************************************************************** * MoveFileWithProgressA (KERNEL32.@) */ From b6914f2617fbf3551fc2b24b308e56e4720143fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Fri, 13 Dec 2019 15:54:28 +0200 Subject: [PATCH 0665/2777] dwmapi: Improve DwmGetWindowAttribute stub. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/dwmapi/dwmapi_main.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/dlls/dwmapi/dwmapi_main.c b/dlls/dwmapi/dwmapi_main.c index 9ec03185f36..2347ae9cb0b 100644 --- a/dlls/dwmapi/dwmapi_main.c +++ b/dlls/dwmapi/dwmapi_main.c @@ -198,7 +198,31 @@ HRESULT WINAPI DwmGetWindowAttribute(HWND hwnd, DWORD attribute, PVOID pv_attrib { FIXME("(%p %ld %p %ld) stub\n", hwnd, attribute, pv_attribute, size); - return E_NOTIMPL; + if (!hwnd) return E_HANDLE; + if (!pv_attribute) return E_INVALIDARG; + + switch (attribute) + { + case DWMWA_NCRENDERING_ENABLED: + if (size < sizeof(BOOL)) return E_INVALIDARG; + + WARN("DWMWA_NCRENDERING_ENABLED: always returning FALSE.\n"); + *(BOOL*)(pv_attribute) = FALSE; + break; + + case DWMWA_CLOAKED: + if (size < sizeof(DWORD)) return E_INVALIDARG; + + WARN("DWMWA_CLOAKED: always returning 0.\n"); + *(DWORD*)(pv_attribute) = 0; + break; + + default: + FIXME("unimplemented attribute %ld, size %lu, for hwnd %p.\n", attribute, size, hwnd); + return E_INVALIDARG; + } + + return S_OK; } /********************************************************************** From faea14f8643f3e59bd405c4926613f94cb9586e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Fri, 13 Dec 2019 15:54:30 +0200 Subject: [PATCH 0666/2777] dwmapi: Add partial implementation of DWMWA_EXTENDED_FRAME_BOUNDS. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/dwmapi/Makefile.in | 1 + dlls/dwmapi/dwmapi_main.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/dlls/dwmapi/Makefile.in b/dlls/dwmapi/Makefile.in index 37411a57608..3822e512aa0 100644 --- a/dlls/dwmapi/Makefile.in +++ b/dlls/dwmapi/Makefile.in @@ -1,6 +1,7 @@ MODULE = dwmapi.dll IMPORTS = user32 IMPORTLIB = dwmapi +IMPORTS = user32 EXTRADLLFLAGS = -Wb,--prefer-native diff --git a/dlls/dwmapi/dwmapi_main.c b/dlls/dwmapi/dwmapi_main.c index 2347ae9cb0b..973af052a4a 100644 --- a/dlls/dwmapi/dwmapi_main.c +++ b/dlls/dwmapi/dwmapi_main.c @@ -210,6 +210,13 @@ HRESULT WINAPI DwmGetWindowAttribute(HWND hwnd, DWORD attribute, PVOID pv_attrib *(BOOL*)(pv_attribute) = FALSE; break; + case DWMWA_EXTENDED_FRAME_BOUNDS: + if (size < sizeof(RECT)) return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + + WARN("DWMWA_EXTENDED_FRAME_BOUNDS: returning window rect.\n"); + GetWindowRect(hwnd, pv_attribute); + break; + case DWMWA_CLOAKED: if (size < sizeof(DWORD)) return E_INVALIDARG; From 83cce44c3884dd410216a90fb3fc082938df0295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Thu, 23 Jun 2022 19:47:44 +0300 Subject: [PATCH 0667/2777] user32: HACK: Do not reply to message sent from FFXIV Launcher via ReplyMessage. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is because wine-gecko is what (wrongly) calls ReplyMessage on FFXIV Launcher's msg, causing it to receive the reply too early and instantly quit before displaying the "not enough disk space" message box. Fixing it properly is difficult due to Microsoft's poor API design. CW-Bug-Id: #20491 Signed-off-by: Gabriel Ivăncescu --- dlls/win32u/message.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 5829580c000..afb79ac7403 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1189,6 +1189,19 @@ static void reply_message( struct received_message_info *info, LRESULT result, M SERVER_END_REQ; } +static BOOL is_ffxiv_launcher_msg(const MSG *msg) +{ + static const WCHAR ffxiv_class[] = u"FFXIVLauncher"; + WCHAR class[ARRAY_SIZE(ffxiv_class)]; + UNICODE_STRING name = { .Buffer = class, .MaximumLength = sizeof(class) }; + + if(msg->message < WM_USER || msg->message >= WM_APP) + return FALSE; + return (NtUserGetClassName( msg->hwnd, FALSE, &name ) == ARRAY_SIZE(ffxiv_class) - 1) && + !wcscmp( class, ffxiv_class ); +} + + /*********************************************************************** * reply_message_result * @@ -1201,6 +1214,7 @@ BOOL reply_message_result( LRESULT result ) while (info && info->type == MSG_CLIENT_MESSAGE) info = info->prev; if (!info) return FALSE; + if (is_ffxiv_launcher_msg( &info->msg )) return FALSE; /* FIXME HACK */ reply_message( info, result, NULL ); return TRUE; } From 8d1e816b79375cef8003b0f44daad23d1ba84994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:10:32 +0100 Subject: [PATCH 0668/2777] fshack: winex11: Split WM_X11DRV_DESKTOP_RESIZED logic to a separate helper. --- dlls/winex11.drv/window.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 8844cac6a6c..eeab1072039 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -3437,6 +3437,26 @@ static void taskbar_delete_tab( HWND hwnd ) release_win_data( data ); } +static void handle_window_desktop_resize( struct x11drv_win_data *data, UINT old_x, UINT old_y ) +{ + /* update the full screen state */ + update_net_wm_states( data ); + + if (data->whole_window) + { + /* sync window position with the new virtual screen rect */ + POINT old_pos = {.x = data->whole_rect.left - old_x, .y = data->whole_rect.top - old_y}; + POINT pos = virtual_screen_to_root( data->whole_rect.left, data->whole_rect.top ); + XWindowChanges changes = {.x = pos.x, .y = pos.y}; + UINT mask = 0; + + if (old_pos.x != pos.x) mask |= CWX; + if (old_pos.y != pos.y) mask |= CWY; + + if (mask) XReconfigureWMWindow( data->display, data->whole_window, data->vis.screen, mask, &changes ); + } +} + /********************************************************************** * X11DRV_WindowMessage (X11DRV.@) */ @@ -3458,23 +3478,7 @@ LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) case WM_X11DRV_DESKTOP_RESIZED: if ((data = get_win_data( hwnd ))) { - /* update the full screen state */ - update_net_wm_states( data ); - - if (data->whole_window) - { - /* sync window position with the new virtual screen rect */ - POINT old_pos = {.x = data->whole_rect.left - wp, .y = data->whole_rect.top - lp}; - POINT pos = virtual_screen_to_root( data->whole_rect.left, data->whole_rect.top ); - XWindowChanges changes = {.x = pos.x, .y = pos.y}; - UINT mask = 0; - - if (old_pos.x != pos.x) mask |= CWX; - if (old_pos.y != pos.y) mask |= CWY; - - if (mask) XReconfigureWMWindow( data->display, data->whole_window, data->vis.screen, mask, &changes ); - } - + handle_window_desktop_resize( data, wp, lp ); release_win_data( data ); } return 0; From 7f798c9be8b321d3a5cc47e4c2f683430f8d9014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:10:32 +0100 Subject: [PATCH 0669/2777] fshack: winex11: Introduce a new Fullscreen Hack settings handler. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on work by Zhiyi Zhang, includes work by Giovanni Mascellani, Rémi Bernon, Arkadiusz Hiler, Kai Krakow, Joshua Ashton, Zebediah Figura, and Matteo Bruni. --- dlls/winex11.drv/Makefile.in | 1 + dlls/winex11.drv/display.c | 42 +- dlls/winex11.drv/fs.c | 937 +++++++++++++++++++++++++++++++++ dlls/winex11.drv/x11drv.h | 46 ++ dlls/winex11.drv/x11drv_main.c | 11 +- 5 files changed, 1023 insertions(+), 14 deletions(-) create mode 100644 dlls/winex11.drv/fs.c diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in index bdc4ebf8aed..c9e76002b2c 100644 --- a/dlls/winex11.drv/Makefile.in +++ b/dlls/winex11.drv/Makefile.in @@ -13,6 +13,7 @@ C_SRCS = \ display.c \ dllmain.c \ event.c \ + fs.c \ graphics.c \ ime.c \ init.c \ diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c index 96cb1d6369d..25b7070a315 100644 --- a/dlls/winex11.drv/display.c +++ b/dlls/winex11.drv/display.c @@ -63,6 +63,11 @@ void X11DRV_Settings_SetHandler(const struct x11drv_settings_handler *new_handle } } +struct x11drv_settings_handler X11DRV_Settings_GetHandler(void) +{ + return settings_handler; +} + /*********************************************************************** * Default handlers if resolution switching is not enabled * @@ -380,7 +385,6 @@ static LONG apply_display_settings( DEVMODEW *displays, ULONG_PTR *ids, BOOL do_ */ LONG X11DRV_ChangeDisplaySettings( LPDEVMODEW displays, LPCWSTR primary_name, HWND hwnd, DWORD flags, LPVOID lpvoid ) { - INT left_most = INT_MAX, top_most = INT_MAX; LONG count, ret = DISP_CHANGE_BADPARAM; ULONG_PTR *ids; DEVMODEW *mode; @@ -388,18 +392,13 @@ LONG X11DRV_ChangeDisplaySettings( LPDEVMODEW displays, LPCWSTR primary_name, HW /* Convert virtual screen coordinates to root coordinates, and find display ids. * We cannot safely get the ids while changing modes, as the backend state may be invalidated. */ - for (count = 0, mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode), count++) - { - left_most = min( left_most, mode->dmPosition.x ); - top_most = min( top_most, mode->dmPosition.y ); - } + for (count = 0, mode = displays; mode->dmSize; mode = NEXT_DEVMODEW( mode )) count++; if (!(ids = calloc( count, sizeof(*ids) ))) return DISP_CHANGE_FAILED; for (count = 0, mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode), count++) { - if (!settings_handler.get_id( mode->dmDeviceName, !wcsicmp( mode->dmDeviceName, primary_name ), ids + count )) goto done; - mode->dmPosition.x -= left_most; - mode->dmPosition.y -= top_most; + BOOL is_primary = !wcsicmp( mode->dmDeviceName, primary_name ); + if (!settings_handler.get_id( mode->dmDeviceName, is_primary, ids + count )) goto done; } /* Detach displays first to free up CRTCs */ @@ -414,21 +413,33 @@ LONG X11DRV_ChangeDisplaySettings( LPDEVMODEW displays, LPCWSTR primary_name, HW POINT virtual_screen_to_root(INT x, INT y) { - RECT virtual = NtUserGetVirtualScreenRect(); + RECT virtual = fs_hack_get_real_virtual_screen(); POINT pt; - pt.x = x - virtual.left; - pt.y = y - virtual.top; + TRACE( "from %d,%d\n", x, y ); + + pt.x = x; + pt.y = y; + fs_hack_point_user_to_real( &pt ); + TRACE( "to real %s\n", wine_dbgstr_point( &pt ) ); + + pt.x -= virtual.left; + pt.y -= virtual.top; + TRACE( "to root %s\n", wine_dbgstr_point( &pt ) ); return pt; } POINT root_to_virtual_screen(INT x, INT y) { - RECT virtual = NtUserGetVirtualScreenRect(); + RECT virtual = fs_hack_get_real_virtual_screen(); POINT pt; + TRACE( "from root %d,%d\n", x, y ); pt.x = x + virtual.left; pt.y = y + virtual.top; + TRACE( "to real %s\n", wine_dbgstr_point( &pt ) ); + fs_hack_point_real_to_user( &pt ); + TRACE( "to user %s\n", wine_dbgstr_point( &pt ) ); return pt; } @@ -536,6 +547,11 @@ void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler } } +struct x11drv_display_device_handler X11DRV_DisplayDevices_GetHandler(void) +{ + return host_handler; +} + void X11DRV_DisplayDevices_RegisterEventHandlers(void) { struct x11drv_display_device_handler *handler = is_virtual_desktop() ? &desktop_handler : &host_handler; diff --git a/dlls/winex11.drv/fs.c b/dlls/winex11.drv/fs.c new file mode 100644 index 00000000000..851ff888e64 --- /dev/null +++ b/dlls/winex11.drv/fs.c @@ -0,0 +1,937 @@ +/* + * Fullscreen Hack + * + * Simulate monitor resolution change + * + * Copyright 2020 Andrew Eikum for CodeWeavers + * Copyright 2020 Zhiyi Zhang 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 + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include +#include + +#include "x11drv.h" +#include "wine/debug.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(fshack); + +static struct x11drv_display_device_handler real_device_handler; +static struct x11drv_settings_handler real_settings_handler; + +static BOOL initialized; + +/* A table of resolutions some games expect but host system may not report */ +static SIZE fs_monitor_sizes[] = +{ + {640, 480}, /* 4:3 */ + {800, 600}, /* 4:3 */ + {1024, 768}, /* 4:3 */ + {1600, 1200}, /* 4:3 */ + {960, 540}, /* 16:9 */ + {1280, 720}, /* 16:9 */ + {1600, 900}, /* 16:9 */ + {1920, 1080}, /* 16:9 */ + {2560, 1440}, /* 16:9 */ + {2880, 1620}, /* 16:9 */ + {3200, 1800}, /* 16:9 */ + {1440, 900}, /* 8:5 */ + {1680, 1050}, /* 8:5 */ + {1920, 1200}, /* 8:5 */ + {2560, 1600}, /* 8:5 */ + {1440, 960}, /* 3:2 */ + {1920, 1280}, /* 3:2 */ + {2560, 1080}, /* 21:9 ultra-wide */ + {1920, 800}, /* 12:5 */ + {3840, 1600}, /* 12:5 */ + {1280, 1024}, /* 5:4 */ +}; + +/* A fake monitor for the fullscreen hack */ +struct fs_monitor +{ + struct list entry; + UINT_PTR gpu_id; + UINT_PTR adapter_id; + + DEVMODEW user_mode; /* Mode changed to by users */ + DEVMODEW real_mode; /* Mode actually used by the host system */ + double user_to_real_scale; /* Scale factor from fake monitor to real monitor */ + POINT top_left; /* Top left corner of the fake monitor rectangle in real virtual screen coordinates */ +}; + +/* Access to fs_monitors is protected by fs_lock */ +static pthread_mutex_t fs_lock = PTHREAD_MUTEX_INITIALIZER; +static struct list fs_monitors = LIST_INIT( fs_monitors ); + +#define NEXT_DEVMODEW(mode) ((DEVMODEW *)((char *)((mode) + 1) + (mode)->dmDriverExtra)) + +static const char *debugstr_devmode( const DEVMODEW *devmode ) +{ + char buffer[256], *buf = buffer; + + if (devmode->dmFields & DM_BITSPERPEL) + buf += sprintf( buf, "bits %u ", (int)devmode->dmBitsPerPel ); + if (devmode->dmFields & DM_PELSWIDTH) + buf += sprintf( buf, "width %u ", (int)devmode->dmPelsWidth ); + if (devmode->dmFields & DM_PELSHEIGHT) + buf += sprintf( buf, "height %u ", (int)devmode->dmPelsHeight ); + if (devmode->dmFields & DM_DISPLAYFREQUENCY) + buf += sprintf( buf, "%u Hz ", (int)devmode->dmDisplayFrequency ); + if (devmode->dmFields & DM_POSITION) + buf += sprintf( buf, "pos (%d,%d) ", (int)devmode->dmPosition.x, (int)devmode->dmPosition.y ); + if (devmode->dmFields & DM_DISPLAYFLAGS) + buf += sprintf( buf, "flags %#x ", (int)devmode->dmDisplayFlags ); + if (devmode->dmFields & DM_DISPLAYORIENTATION) + buf += sprintf( buf, "orientation %u ", (int)devmode->dmDisplayOrientation ); + + return wine_dbg_sprintf("%s", buffer); +} + +static struct fs_monitor *find_adapter_monitor( struct list *monitors, struct gdi_adapter *adapter, DEVMODEW *mode ) +{ + struct fs_monitor *monitor; + + LIST_FOR_EACH_ENTRY( monitor, monitors, struct fs_monitor, entry ) + { + if (monitor->real_mode.dmPosition.x != mode->dmPosition.x) continue; + if (monitor->real_mode.dmPosition.y != mode->dmPosition.y) continue; + if (monitor->real_mode.dmPelsWidth != mode->dmPelsWidth) continue; + if (monitor->real_mode.dmPelsHeight != mode->dmPelsHeight) continue; + return monitor; + } + + return NULL; +} + +static void update_gpu_monitor_list( struct gdi_gpu *gpu, struct list *monitors ) +{ + struct gdi_adapter *adapters; + struct fs_monitor *monitor; + int count; + + if (!real_device_handler.get_adapters( gpu->id, &adapters, &count )) return; + + while (count--) + { + struct gdi_adapter *adapter = adapters + count; + DEVMODEW mode = {0}; + + TRACE( "adapter %p id %p\n", adapter, (void *)adapter->id ); + + if (!real_settings_handler.get_current_mode( adapter->id, &mode )) + { + WARN( "Failed to get current display mode\n" ); + continue; + } + + if ((monitor = find_adapter_monitor( monitors, adapter, &mode ))) + { + TRACE( "Reusing monitor %p, mode %s\n", monitor, debugstr_devmode( &mode ) ); + list_remove( &monitor->entry ); + } + else if (!(monitor = calloc( 1, sizeof(*monitor) ))) + { + WARN( "Failed to allocate monitor\n" ); + continue; + } + else + { + monitor->gpu_id = gpu->id; + monitor->user_mode = mode; + monitor->real_mode = mode; + monitor->user_to_real_scale = 1.0; + monitor->top_left.x = mode.dmPosition.x; + monitor->top_left.y = mode.dmPosition.y; + + TRACE( "Created monitor %p, mode %s\n", monitor, debugstr_devmode( &mode ) ); + } + + monitor->adapter_id = adapter->id; + list_add_tail( &fs_monitors, &monitor->entry ); + } + + real_device_handler.free_adapters( adapters ); +} + +static void update_monitor_list( struct gdi_gpu *gpus, int count ) +{ + struct list monitors = LIST_INIT( monitors ); + struct fs_monitor *monitor, *next; + + list_move_tail( &monitors, &fs_monitors ); + + while (count--) + { + struct list gpu_monitors = LIST_INIT( gpu_monitors ); + struct gdi_gpu *gpu = gpus + count; + + TRACE( "gpu %p id %p\n", gpu, (void *)gpu->id ); + + LIST_FOR_EACH_ENTRY_SAFE( monitor, next, &monitors, struct fs_monitor, entry ) + { + if (monitor->gpu_id != gpu->id) continue; + list_remove( &monitor->entry ); + list_add_tail( &gpu_monitors, &monitor->entry ); + } + + update_gpu_monitor_list( gpu, &gpu_monitors ); + + list_move_tail( &monitors, &gpu_monitors ); + } + + LIST_FOR_EACH_ENTRY_SAFE( monitor, next, &monitors, struct fs_monitor, entry ) + { + TRACE( "Removing stale monitor %p with gpu id %p, adapter id %p\n", + monitor, (void *)monitor->gpu_id, (void *)monitor->adapter_id ); + free( monitor ); + } +} + +static void modes_append( DEVMODEW *modes, UINT *mode_count, UINT *resolutions, DEVMODEW *mode ) +{ + BOOL is_new_resolution; + const char *appid; + int i; + + /* Titan Souls renders incorrectly if we report modes smaller than 800x600 */ + if ((appid = getenv( "SteamAppId" )) && !strcmp( appid, "297130" )) + { + if (mode->dmDisplayOrientation == DMDO_DEFAULT || mode->dmDisplayOrientation == DMDO_180) + { + if (mode->dmPelsHeight <= 600 && !(mode->dmPelsHeight == 600 && mode->dmPelsWidth == 800)) return; + } + else + { + if (mode->dmPelsWidth <= 600 && !(mode->dmPelsWidth == 600 && mode->dmPelsHeight == 800)) return; + } + } + + is_new_resolution = TRUE; + + for (i = 0; i < *mode_count; ++i) + { + if (modes[i].dmPelsWidth != mode->dmPelsWidth) continue; + if (modes[i].dmPelsHeight != mode->dmPelsHeight) continue; + is_new_resolution = FALSE; + + if (modes[i].dmBitsPerPel != mode->dmBitsPerPel) continue; + if (modes[i].dmDisplayFrequency != mode->dmDisplayFrequency) continue; + if (modes[i].dmDisplayOrientation != mode->dmDisplayOrientation) continue; + return; /* The exact mode is already added, nothing to do */ + } + + if (is_new_resolution) + { + /* Some games crash if we report too many unique resolutions (in terms of HxW) */ + if (limit_number_of_resolutions && *resolutions >= limit_number_of_resolutions) return; + *resolutions = *resolutions + 1; + } + + mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | + DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY; + mode->dmSize = sizeof(DEVMODEW); + mode->dmDriverExtra = 0; + mode->dmDisplayFlags = 0; + + TRACE( "adding mode %s\n", debugstr_devmode(mode) ); + + modes[*mode_count] = *mode; + *mode_count = *mode_count + 1; +} + +static void monitor_get_modes( struct fs_monitor *monitor, DEVMODEW **modes, UINT *mode_count ) +{ + UINT i, j, max_count, real_mode_count, resolutions = 0; + DEVMODEW *real_modes, *real_mode, mode_host = {0}; + + *mode_count = 0; + *modes = NULL; + + if (!real_settings_handler.get_current_mode( monitor->adapter_id, &mode_host )) return; + /* Fullscreen hack doesn't support changing display orientations */ + if (!real_settings_handler.get_modes( monitor->adapter_id, 0, &real_modes, &real_mode_count )) return; + + max_count = ARRAY_SIZE(fs_monitor_sizes) * DEPTH_COUNT + real_mode_count; + if (!(*modes = calloc( max_count, sizeof(DEVMODEW) ))) + { + real_settings_handler.free_modes( real_modes ); + return; + } + + /* Add the current mode early, in case we have to limit */ + modes_append( *modes, mode_count, &resolutions, &mode_host ); + + /* Linux reports far fewer resolutions than Windows. Add modes that some games may expect. */ + for (i = 0; i < ARRAY_SIZE(fs_monitor_sizes); ++i) + { + DEVMODEW mode = mode_host; + + if (mode_host.dmDisplayOrientation == DMDO_DEFAULT || + mode_host.dmDisplayOrientation == DMDO_180) + { + mode.dmPelsWidth = fs_monitor_sizes[i].cx; + mode.dmPelsHeight = fs_monitor_sizes[i].cy; + } + else + { + mode.dmPelsWidth = fs_monitor_sizes[i].cy; + mode.dmPelsHeight = fs_monitor_sizes[i].cx; + } + + /* Don't report modes that are larger than the current mode */ + if (mode.dmPelsWidth > mode_host.dmPelsWidth) continue; + if (mode.dmPelsHeight > mode_host.dmPelsHeight) continue; + + for (j = 0; j < DEPTH_COUNT; ++j) + { + mode.dmBitsPerPel = depths[j]; + mode.dmDisplayFrequency = 60; + modes_append( *modes, mode_count, &resolutions, &mode ); + } + } + + for (i = 0, real_mode = real_modes; i < real_mode_count; ++i) + { + DEVMODEW mode = *real_mode; + + /* Don't report modes that are larger than the current mode */ + if (mode.dmPelsWidth <= mode_host.dmPelsWidth && mode.dmPelsHeight <= mode_host.dmPelsHeight) + modes_append( *modes, mode_count, &resolutions, &mode ); + + real_mode = NEXT_DEVMODEW(real_mode); + } + + real_settings_handler.free_modes( real_modes ); +} + +static struct fs_monitor *monitor_from_adapter_id( ULONG_PTR adapter_id ) +{ + struct fs_monitor *monitor; + struct gdi_gpu *gpus; + int count; + + LIST_FOR_EACH_ENTRY( monitor, &fs_monitors, struct fs_monitor, entry ) + if (monitor->adapter_id == adapter_id) return monitor; + + if (real_device_handler.get_gpus( &gpus, &count )) + { + update_monitor_list( gpus, count ); + real_device_handler.free_gpus( gpus ); + + LIST_FOR_EACH_ENTRY( monitor, &fs_monitors, struct fs_monitor, entry ) + if (monitor->adapter_id == adapter_id) return monitor; + } + + WARN( "Failed to find monitor for adapter id %p\n", (void *)adapter_id ); + return NULL; +} + +static BOOL fs_get_modes( ULONG_PTR adapter_id, DWORD flags, DEVMODEW **new_modes, UINT *mode_count ) +{ + struct fs_monitor *monitor; + + TRACE( "adapter_id %#zx, flags %#x, modes %p, modes_count %p\n", + (size_t)adapter_id, (int)flags, new_modes, mode_count ); + + pthread_mutex_lock( &fs_lock ); + + if ((monitor = monitor_from_adapter_id( adapter_id ))) + monitor_get_modes( monitor, new_modes, mode_count ); + + pthread_mutex_unlock( &fs_lock ); + return monitor && *new_modes; +} + +static void fs_free_modes( DEVMODEW *modes ) +{ + free( modes ); +} + +static BOOL fs_get_current_mode( ULONG_PTR adapter_id, DEVMODEW *mode ) +{ + struct fs_monitor *monitor; + + TRACE( "adapter_id %p, mode %p\n", (void *)adapter_id, mode ); + + pthread_mutex_lock( &fs_lock ); + if ((monitor = monitor_from_adapter_id( adapter_id ))) + *mode = monitor->user_mode; + pthread_mutex_unlock( &fs_lock ); + + return !!monitor; +} + +static LONG fs_set_current_mode( ULONG_PTR adapter_id, const DEVMODEW *user_mode ) +{ + WCHAR device_name[CCHDEVICENAME]; + struct fs_monitor *fs_monitor; + DEVMODEW real_mode; + double scale; + + TRACE( "id %p, mode %s\n", (void *)adapter_id, debugstr_devmode( user_mode ) ); + + pthread_mutex_lock( &fs_lock ); + + if (!(fs_monitor = monitor_from_adapter_id( adapter_id ))) + { + pthread_mutex_unlock( &fs_lock ); + return DISP_CHANGE_FAILED; + } + + if (is_detached_mode( &fs_monitor->real_mode ) && !is_detached_mode( user_mode )) + { + FIXME( "Attaching adapters is unsupported with fullscreen hack.\n" ); + return DISP_CHANGE_SUCCESSFUL; + } + + /* Real modes may be changed since initialization */ + if (!real_settings_handler.get_current_mode( adapter_id, &real_mode )) + { + pthread_mutex_unlock( &fs_lock ); + return DISP_CHANGE_FAILED; + } + + fs_monitor->user_mode = *user_mode; + fs_monitor->real_mode = real_mode; + lstrcpyW( fs_monitor->user_mode.dmDeviceName, device_name ); + + if (is_detached_mode( user_mode )) + { + fs_monitor->user_to_real_scale = 0; + fs_monitor->top_left.x = 0; + fs_monitor->top_left.y = 0; + } + /* Integer scaling */ + else if (fs_hack_is_integer()) + { + scale = min( real_mode.dmPelsWidth / user_mode->dmPelsWidth, + real_mode.dmPelsHeight / user_mode->dmPelsHeight ); + fs_monitor->user_to_real_scale = scale; + fs_monitor->top_left.x = real_mode.dmPosition.x + + (real_mode.dmPelsWidth - user_mode->dmPelsWidth * scale) / 2; + fs_monitor->top_left.y = real_mode.dmPosition.y + + (real_mode.dmPelsHeight - user_mode->dmPelsHeight * scale) / 2; + } + /* If real mode is narrower than fake mode, scale to fit width */ + else if ((double)real_mode.dmPelsWidth / (double)real_mode.dmPelsHeight < + (double)user_mode->dmPelsWidth / (double)user_mode->dmPelsHeight) + { + scale = (double)real_mode.dmPelsWidth / (double)user_mode->dmPelsWidth; + fs_monitor->user_to_real_scale = scale; + fs_monitor->top_left.x = real_mode.dmPosition.x; + fs_monitor->top_left.y = real_mode.dmPosition.y + + (real_mode.dmPelsHeight - user_mode->dmPelsHeight * scale) / 2; + } + /* Else scale to fit height */ + else + { + scale = (double)real_mode.dmPelsHeight / (double)user_mode->dmPelsHeight; + fs_monitor->user_to_real_scale = scale; + fs_monitor->top_left.x = real_mode.dmPosition.x + + (real_mode.dmPelsWidth - user_mode->dmPelsWidth * scale) / 2; + fs_monitor->top_left.y = real_mode.dmPosition.y; + } + + TRACE( "real_mode x %d y %d width %d height %d\n", (int)real_mode.dmPosition.x, + (int)real_mode.dmPosition.y, (int)real_mode.dmPelsWidth, (int)real_mode.dmPelsHeight ); + TRACE( "user_mode x %d y %d width %d height %d\n", (int)user_mode->dmPosition.x, + (int)user_mode->dmPosition.y, (int)user_mode->dmPelsWidth, (int)user_mode->dmPelsHeight ); + TRACE( "user_to_real_scale %lf\n", fs_monitor->user_to_real_scale ); + TRACE( "top left corner:%s\n", wine_dbgstr_point( &fs_monitor->top_left ) ); + + pthread_mutex_unlock( &fs_lock ); + return DISP_CHANGE_SUCCESSFUL; +} + +/* Display device handler functions */ + +static BOOL fs_get_gpus( struct gdi_gpu **gpus, int *count ) +{ + struct list monitors = LIST_INIT( monitors ); + + TRACE( "gpus %p, count %p\n", gpus, count ); + + if (!real_device_handler.get_gpus( gpus, count )) return FALSE; + + pthread_mutex_lock( &fs_lock ); + update_monitor_list( *gpus, *count ); + pthread_mutex_unlock( &fs_lock ); + + return TRUE; +} + +static BOOL fs_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **new_monitors, int *count ) +{ + struct fs_monitor *fs_monitor; + struct gdi_monitor *monitor; + RECT rect; + INT i; + + TRACE( "adapter_id %p, monitors %p, count %p\n", (void *)adapter_id, new_monitors, count ); + + if (!real_device_handler.get_monitors( adapter_id, new_monitors, count )) return FALSE; + + pthread_mutex_lock( &fs_lock ); + + for (i = 0; i < *count; ++i) + { + monitor = &(*new_monitors)[i]; + + LIST_FOR_EACH_ENTRY( fs_monitor, &fs_monitors, struct fs_monitor, entry ) + { + rect.left = fs_monitor->real_mode.dmPosition.x; + rect.top = fs_monitor->real_mode.dmPosition.y; + rect.right = rect.left + fs_monitor->real_mode.dmPelsWidth; + rect.bottom = rect.top + fs_monitor->real_mode.dmPelsHeight; + + if (EqualRect( &rect, &monitor->rc_monitor )) + { + monitor->rc_monitor.left = fs_monitor->user_mode.dmPosition.x; + monitor->rc_monitor.top = fs_monitor->user_mode.dmPosition.y; + monitor->rc_monitor.right = monitor->rc_monitor.left + fs_monitor->user_mode.dmPelsWidth; + monitor->rc_monitor.bottom = monitor->rc_monitor.top + fs_monitor->user_mode.dmPelsHeight; + monitor->rc_work = monitor->rc_monitor; + monitor->state_flags = DISPLAY_DEVICE_ATTACHED; + if (fs_monitor->user_mode.dmPelsWidth && fs_monitor->user_mode.dmPelsHeight) + monitor->state_flags |= DISPLAY_DEVICE_ACTIVE; + } + } + } + + pthread_mutex_unlock( &fs_lock ); + + return TRUE; +} + +/* Fullscreen hack helpers */ + +static struct fs_monitor *monitor_from_handle( HMONITOR handle ) +{ + MONITORINFOEXW info = {.cbSize = sizeof(MONITORINFOEXW)}; + ULONG_PTR adapter_id; + BOOL is_primary; + + TRACE( "handle %p\n", handle ); + + if (!initialized) return NULL; + + if (!NtUserGetMonitorInfo( handle, (MONITORINFO *)&info )) return NULL; + is_primary = !!(info.dwFlags & MONITORINFOF_PRIMARY); + if (!real_settings_handler.get_id( info.szDevice, is_primary, &adapter_id )) return FALSE; + return monitor_from_adapter_id( adapter_id ); +} + +/* Return whether fullscreen hack is enabled on a specific monitor */ +BOOL fs_hack_enabled( HMONITOR monitor ) +{ + struct fs_monitor *fs_monitor; + BOOL enabled = FALSE; + + TRACE( "monitor %p\n", monitor ); + + pthread_mutex_lock( &fs_lock ); + fs_monitor = monitor_from_handle( monitor ); + if (fs_monitor && (fs_monitor->user_mode.dmPelsWidth != fs_monitor->real_mode.dmPelsWidth || + fs_monitor->user_mode.dmPelsHeight != fs_monitor->real_mode.dmPelsHeight)) + enabled = TRUE; + pthread_mutex_unlock( &fs_lock ); + TRACE( "enabled: %s\n", enabled ? "TRUE" : "FALSE" ); + return enabled; +} + +BOOL fs_hack_mapping_required( HMONITOR monitor ) +{ + BOOL required; + + TRACE( "monitor %p\n", monitor ); + + /* steamcompmgr does our mapping for us */ + required = !wm_is_steamcompmgr( NULL ) && fs_hack_enabled( monitor ); + TRACE( "required: %s\n", required ? "TRUE" : "FALSE" ); + return required; +} + +/* Return whether integer scaling is on */ +BOOL fs_hack_is_integer(void) +{ + static int is_int = -1; + if (is_int < 0) + { + const char *e = getenv( "WINE_FULLSCREEN_INTEGER_SCALING" ); + is_int = e && strcmp( e, "0" ); + } + TRACE( "is_interger_scaling: %s\n", is_int ? "TRUE" : "FALSE" ); + return is_int; +} + +HMONITOR fs_hack_monitor_from_rect( const RECT *in_rect ) +{ + RECT rect = *in_rect; + + TRACE( "rect %s\n", wine_dbgstr_rect( &rect ) ); + rect.right = rect.left + 1; + rect.bottom = rect.top + 1; + return NtUserMonitorFromRect( &rect, MONITOR_DEFAULTTOPRIMARY ); +} + +/* Get the monitor a window is on. MonitorFromWindow() doesn't work here because it finds the + * monitor with the maximum overlapped rectangle when a window is spanned over two monitors, whereas + * for the fullscreen hack, the monitor where the left top corner of the window is on is the correct + * one. For example, a game with a window of 3840x2160 changes the primary monitor to 1280x720, if + * there is a secondary monitor of 3840x2160 to the right, MonitorFromWindow() will return the + * secondary monitor instead of the primary one. */ +HMONITOR fs_hack_monitor_from_hwnd( HWND hwnd ) +{ + RECT rect = {0}; + + if (!NtUserGetWindowRect( hwnd, &rect )) ERR( "Invalid hwnd %p.\n", hwnd ); + + TRACE( "hwnd %p rect %s\n", hwnd, wine_dbgstr_rect( &rect ) ); + return fs_hack_monitor_from_rect( &rect ); +} + +/* Return the rectangle of a monitor in current mode in user virtual screen coordinates */ +RECT fs_hack_current_mode( HMONITOR monitor ) +{ + struct fs_monitor *fs_monitor; + RECT rect = {0}; + + TRACE( "monitor %p\n", monitor ); + + pthread_mutex_lock( &fs_lock ); + fs_monitor = monitor_from_handle( monitor ); + if (!fs_monitor) + { + pthread_mutex_unlock( &fs_lock ); + return rect; + } + + rect.left = fs_monitor->user_mode.dmPosition.x; + rect.top = fs_monitor->user_mode.dmPosition.y; + rect.right = rect.left + fs_monitor->user_mode.dmPelsWidth; + rect.bottom = rect.top + fs_monitor->user_mode.dmPelsHeight; + pthread_mutex_unlock( &fs_lock ); + TRACE( "current mode rect: %s\n", wine_dbgstr_rect( &rect ) ); + return rect; +} + +/* Return the rectangle of a monitor in real mode in real virtual screen coordinates */ +RECT fs_hack_real_mode( HMONITOR monitor ) +{ + struct fs_monitor *fs_monitor; + RECT rect = {0}; + + TRACE( "monitor %p\n", monitor ); + + pthread_mutex_lock( &fs_lock ); + fs_monitor = monitor_from_handle( monitor ); + if (!fs_monitor) + { + pthread_mutex_unlock( &fs_lock ); + return rect; + } + + rect.left = fs_monitor->real_mode.dmPosition.x; + rect.top = fs_monitor->real_mode.dmPosition.y; + rect.right = rect.left + fs_monitor->real_mode.dmPelsWidth; + rect.bottom = rect.top + fs_monitor->real_mode.dmPelsHeight; + pthread_mutex_unlock( &fs_lock ); + TRACE( "real mode rect: %s\n", wine_dbgstr_rect( &rect ) ); + return rect; +} + +/* Return whether width and height are the same as the current mode used by a monitor */ +BOOL fs_hack_matches_current_mode( HMONITOR monitor, INT width, INT height ) +{ + MONITORINFO info = {.cbSize = sizeof(MONITORINFO)}; + BOOL matched; + + TRACE( "monitor %p\n", monitor ); + + if (!NtUserGetMonitorInfo( monitor, &info )) return FALSE; + + matched = (width == info.rcMonitor.right - info.rcMonitor.left) && + (height == info.rcMonitor.bottom - info.rcMonitor.top); + TRACE( "matched: %s\n", matched ? "TRUE" : "FALSE" ); + + return matched; +} + +/* Transform a point in user virtual screen coordinates to real virtual screen coordinates */ +void fs_hack_point_user_to_real( POINT *pos ) +{ + struct fs_monitor *fs_monitor; + RECT rect; + + TRACE( "from %s\n", wine_dbgstr_point( pos ) ); + + if (wm_is_steamcompmgr( NULL )) return; + + pthread_mutex_lock( &fs_lock ); + LIST_FOR_EACH_ENTRY( fs_monitor, &fs_monitors, struct fs_monitor, entry ) + { + rect.left = fs_monitor->user_mode.dmPosition.x; + rect.top = fs_monitor->user_mode.dmPosition.y; + rect.right = rect.left + fs_monitor->user_mode.dmPelsWidth; + rect.bottom = rect.top + fs_monitor->user_mode.dmPelsHeight; + + if (PtInRect( &rect, *pos )) + { + pos->x -= fs_monitor->user_mode.dmPosition.x; + pos->y -= fs_monitor->user_mode.dmPosition.y; + pos->x = lround( pos->x * fs_monitor->user_to_real_scale ); + pos->y = lround( pos->y * fs_monitor->user_to_real_scale ); + pos->x += fs_monitor->top_left.x; + pos->y += fs_monitor->top_left.y; + pthread_mutex_unlock( &fs_lock ); + TRACE( "to %s\n", wine_dbgstr_point( pos ) ); + return; + } + } + pthread_mutex_unlock( &fs_lock ); + WARN( "%s not transformed.\n", wine_dbgstr_point( pos ) ); +} + +/* Transform a point in real virtual screen coordinates to user virtual screen coordinates */ +void fs_hack_point_real_to_user( POINT *pos ) +{ + struct fs_monitor *fs_monitor; + RECT rect; + + TRACE( "from %s\n", wine_dbgstr_point( pos ) ); + + if (wm_is_steamcompmgr( NULL )) return; + + pthread_mutex_lock( &fs_lock ); + LIST_FOR_EACH_ENTRY( fs_monitor, &fs_monitors, struct fs_monitor, entry ) + { + rect.left = fs_monitor->real_mode.dmPosition.x; + rect.top = fs_monitor->real_mode.dmPosition.y; + rect.right = rect.left + fs_monitor->real_mode.dmPelsWidth; + rect.bottom = rect.top + fs_monitor->real_mode.dmPelsHeight; + + if (PtInRect( &rect, *pos )) + { + pos->x -= fs_monitor->top_left.x; + pos->y -= fs_monitor->top_left.y; + pos->x = lround( pos->x / fs_monitor->user_to_real_scale ); + pos->y = lround( pos->y / fs_monitor->user_to_real_scale ); + pos->x += fs_monitor->user_mode.dmPosition.x; + pos->y += fs_monitor->user_mode.dmPosition.y; + pos->x = max( pos->x, fs_monitor->user_mode.dmPosition.x ); + pos->y = max( pos->y, fs_monitor->user_mode.dmPosition.y ); + pos->x = min( pos->x, fs_monitor->user_mode.dmPosition.x + + (INT)fs_monitor->user_mode.dmPelsWidth - 1 ); + pos->y = min( pos->y, fs_monitor->user_mode.dmPosition.y + + (INT)fs_monitor->user_mode.dmPelsHeight - 1 ); + pthread_mutex_unlock( &fs_lock ); + TRACE( "to %s\n", wine_dbgstr_point( pos ) ); + return; + } + } + pthread_mutex_unlock( &fs_lock ); + WARN( "%s not transformed.\n", wine_dbgstr_point( pos ) ); +} + +/* Transform RGNDATA in user virtual screen coordinates to real virtual screen coordinates. + * This is for clipping. Be sure to use Unsorted for Xlib calls after this transformation because + * this may break the requirement of using YXBanded. For example, say there are two monitors aligned + * horizontally with the primary monitor on the right. Each of monitor is of real resolution + * 1920x1080 and the fake primary monitor resolution is 1024x768. Then (0, 10, 1024, 768) should be + * transformed to (0, 14, 1920, 1080). While (1024, 10, 2944, 1080) should be transformed to + * (1920, 10, 3840, 1080) and this is breaking YXBanded because it requires y in non-decreasing order */ +void fs_hack_rgndata_user_to_real( RGNDATA *data ) +{ + unsigned int i; + XRectangle *xrect; + RECT rect; + + if (!data || wm_is_steamcompmgr( NULL )) return; + + xrect = (XRectangle *)data->Buffer; + for (i = 0; i < data->rdh.nCount; i++) + { + rect.left = xrect[i].x; + rect.top = xrect[i].y; + rect.right = xrect[i].x + xrect[i].width; + rect.bottom = xrect[i].y + xrect[i].height; + TRACE( "from rect %s\n", wine_dbgstr_rect( &rect ) ); + fs_hack_rect_user_to_real( &rect ); + TRACE( "to rect %s\n", wine_dbgstr_rect( &rect ) ); + xrect[i].x = rect.left; + xrect[i].y = rect.top; + xrect[i].width = rect.right - rect.left; + xrect[i].height = rect.bottom - rect.top; + } +} + +/* Transform a rectangle in user virtual screen coordinates to real virtual screen coordinates. A + * difference compared to fs_hack_point_user_to_real() is that fs_hack_point_user_to_real() finds + * the wrong monitor if the point is on the right edge of the monitor rectangle. For example, when + * there are two monitors of real size 1920x1080, the primary monitor is of user mode 1024x768 and + * the secondary monitor is to the right. Rectangle (0, 0, 1024, 768) should transform to + * (0, 0, 1920, 1080). If (1024, 768) is passed to fs_hack_point_user_to_real(), + * fs_hack_point_user_to_real() will think (1024, 768) is on the secondary monitor, ends up + * returning a wrong result to callers. */ +void fs_hack_rect_user_to_real( RECT *rect ) +{ + struct fs_monitor *fs_monitor; + HMONITOR monitor; + RECT point; + + TRACE( "from %s\n", wine_dbgstr_rect( rect ) ); + + if (wm_is_steamcompmgr( NULL )) return; + + SetRect( &point, rect->left, rect->top, rect->left + 1, rect->top + 1 ); + monitor = NtUserMonitorFromRect( &point, MONITOR_DEFAULTTONEAREST ); + pthread_mutex_lock( &fs_lock ); + fs_monitor = monitor_from_handle( monitor ); + if (!fs_monitor) + { + pthread_mutex_unlock( &fs_lock ); + WARN( "%s not transformed.\n", wine_dbgstr_rect( rect ) ); + return; + } + + OffsetRect( rect, -fs_monitor->user_mode.dmPosition.x, + -fs_monitor->user_mode.dmPosition.y ); + rect->left = lround( rect->left * fs_monitor->user_to_real_scale ); + rect->right = lround( rect->right * fs_monitor->user_to_real_scale ); + rect->top = lround( rect->top * fs_monitor->user_to_real_scale ); + rect->bottom = lround( rect->bottom * fs_monitor->user_to_real_scale ); + OffsetRect( rect, fs_monitor->top_left.x, fs_monitor->top_left.y ); + pthread_mutex_unlock( &fs_lock ); + TRACE( "to %s\n", wine_dbgstr_rect( rect ) ); +} + +/* Get the user_to_real_scale value in a monitor */ +double fs_hack_get_user_to_real_scale( HMONITOR monitor ) +{ + struct fs_monitor *fs_monitor; + double scale = 1.0; + + TRACE( "monitor %p\n", monitor ); + + if (wm_is_steamcompmgr( NULL )) return scale; + + pthread_mutex_lock( &fs_lock ); + fs_monitor = monitor_from_handle( monitor ); + if (!fs_monitor) + { + pthread_mutex_unlock( &fs_lock ); + return scale; + } + scale = fs_monitor->user_to_real_scale; + + pthread_mutex_unlock( &fs_lock ); + TRACE( "scale %lf\n", scale ); + return scale; +} + +/* Get the scaled scree size of a monitor */ +SIZE fs_hack_get_scaled_screen_size( HMONITOR monitor ) +{ + struct fs_monitor *fs_monitor; + SIZE size = {0}; + + TRACE( "monitor %p\n", monitor ); + + pthread_mutex_lock( &fs_lock ); + fs_monitor = monitor_from_handle( monitor ); + if (!fs_monitor) + { + pthread_mutex_unlock( &fs_lock ); + return size; + } + + if (wm_is_steamcompmgr( NULL )) + { + pthread_mutex_unlock( &fs_lock ); + size.cx = fs_monitor->user_mode.dmPelsWidth; + size.cy = fs_monitor->user_mode.dmPelsHeight; + TRACE( "width %d height %d\n", (int)size.cx, (int)size.cy ); + return size; + } + + size.cx = lround( fs_monitor->user_mode.dmPelsWidth * fs_monitor->user_to_real_scale ); + size.cy = lround( fs_monitor->user_mode.dmPelsHeight * fs_monitor->user_to_real_scale ); + pthread_mutex_unlock( &fs_lock ); + TRACE( "width %d height %d\n", (int)size.cx, (int)size.cy ); + return size; +} + +/* Get the real virtual screen size instead of virtual screen size using fake modes */ +RECT fs_hack_get_real_virtual_screen(void) +{ + struct fs_monitor *fs_monitor; + RECT rect, virtual = {0}; + + pthread_mutex_lock( &fs_lock ); + LIST_FOR_EACH_ENTRY( fs_monitor, &fs_monitors, struct fs_monitor, entry ) + { + rect.left = fs_monitor->real_mode.dmPosition.x; + rect.top = fs_monitor->real_mode.dmPosition.y; + rect.right = rect.left + fs_monitor->real_mode.dmPelsWidth; + rect.bottom = rect.top + fs_monitor->real_mode.dmPelsHeight; + + union_rect( &virtual, &virtual, &rect ); + } + pthread_mutex_unlock( &fs_lock ); + TRACE( "real virtual screen rect:%s\n", wine_dbgstr_rect( &virtual ) ); + return virtual; +} + +/* Initialize the fullscreen hack, which is a layer on top of real settings handlers and real + * display device handlers */ +void fs_hack_init(void) +{ + struct x11drv_display_device_handler device_handler; + struct x11drv_settings_handler settings_handler; + + real_device_handler = X11DRV_DisplayDevices_GetHandler(); + real_settings_handler = X11DRV_Settings_GetHandler(); + + settings_handler.name = "Fullscreen Hack"; + settings_handler.priority = 500; + settings_handler.get_id = real_settings_handler.get_id; + settings_handler.get_modes = fs_get_modes; + settings_handler.free_modes = fs_free_modes; + settings_handler.get_current_mode = fs_get_current_mode; + settings_handler.set_current_mode = fs_set_current_mode; + X11DRV_Settings_SetHandler( &settings_handler ); + + device_handler.name = "Fullscreen Hack"; + device_handler.priority = 500; + device_handler.get_gpus = fs_get_gpus; + device_handler.get_adapters = real_device_handler.get_adapters; + device_handler.get_monitors = fs_get_monitors; + device_handler.free_gpus = real_device_handler.free_gpus; + device_handler.free_adapters = real_device_handler.free_adapters; + device_handler.free_monitors = real_device_handler.free_monitors; + device_handler.register_event_handlers = NULL; + X11DRV_DisplayDevices_SetHandler( &device_handler ); + + initialized = TRUE; +} diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index ec56e8ab329..9cec0391aff 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -454,6 +454,7 @@ extern BOOL private_color_map DECLSPEC_HIDDEN; extern int primary_monitor DECLSPEC_HIDDEN; extern int copy_default_colors DECLSPEC_HIDDEN; extern int alloc_system_colors DECLSPEC_HIDDEN; +extern int limit_number_of_resolutions DECLSPEC_HIDDEN; extern int xrender_error_base DECLSPEC_HIDDEN; extern int xfixes_event_base DECLSPEC_HIDDEN; extern char *process_name DECLSPEC_HIDDEN; @@ -638,6 +639,7 @@ struct x11drv_win_data BOOL pending_fullscreen : 1; /* HACK: pending change to fullscreen state */ BOOL managed : 1; /* is window managed? */ BOOL mapped : 1; /* is window mapped? (in either normal or iconic state) */ + BOOL fs_hack : 1; /* is window forced / faking fullscreen? */ BOOL iconic : 1; /* is window in iconic state? */ BOOL embedded : 1; /* is window an XEMBED client? */ BOOL shaped : 1; /* is window using a custom region shape? */ @@ -697,6 +699,24 @@ extern void *uri_list_to_drop_files( const void *data, size_t size, size_t *ret_ extern BOOL wm_is_mutter(Display *) DECLSPEC_HIDDEN; extern BOOL wm_is_steamcompmgr(Display *) DECLSPEC_HIDDEN; +extern BOOL fs_hack_enabled( HMONITOR monitor ) DECLSPEC_HIDDEN; +extern BOOL fs_hack_mapping_required( HMONITOR monitor ) DECLSPEC_HIDDEN; +extern BOOL fs_hack_is_integer(void) DECLSPEC_HIDDEN; +extern HMONITOR fs_hack_monitor_from_hwnd( HWND hwnd ) DECLSPEC_HIDDEN; +extern HMONITOR fs_hack_monitor_from_rect( const RECT *rect ) DECLSPEC_HIDDEN; +extern BOOL fs_hack_matches_current_mode( HMONITOR monitor, INT width, INT height ) DECLSPEC_HIDDEN; +extern RECT fs_hack_current_mode( HMONITOR monitor ) DECLSPEC_HIDDEN; +extern RECT fs_hack_real_mode( HMONITOR monitor ) DECLSPEC_HIDDEN; +extern void fs_hack_point_user_to_real( POINT *pos ) DECLSPEC_HIDDEN; +extern void fs_hack_point_real_to_user( POINT *pos ) DECLSPEC_HIDDEN; +extern void fs_hack_rect_user_to_real( RECT *rect ) DECLSPEC_HIDDEN; +extern void fs_hack_rgndata_user_to_real( RGNDATA *data ) DECLSPEC_HIDDEN; +extern double fs_hack_get_user_to_real_scale( HMONITOR ) DECLSPEC_HIDDEN; +extern SIZE fs_hack_get_scaled_screen_size( HMONITOR monitor ) DECLSPEC_HIDDEN; +extern RECT fs_hack_get_real_virtual_screen(void) DECLSPEC_HIDDEN; +extern void fs_hack_init(void) DECLSPEC_HIDDEN; +extern int mode_compare( const void *p1, const void *p2 ) DECLSPEC_HIDDEN; + static inline void mirror_rect( const RECT *window_rect, RECT *rect ) { int width = window_rect->right - window_rect->left; @@ -790,6 +810,7 @@ struct x11drv_settings_handler }; extern void X11DRV_Settings_SetHandler(const struct x11drv_settings_handler *handler) DECLSPEC_HIDDEN; +extern struct x11drv_settings_handler X11DRV_Settings_GetHandler(void) DECLSPEC_HIDDEN; extern void X11DRV_init_desktop( Window win, unsigned int width, unsigned int height ) DECLSPEC_HIDDEN; extern void X11DRV_resize_desktop(void) DECLSPEC_HIDDEN; @@ -848,6 +869,7 @@ struct x11drv_display_device_handler extern BOOL get_host_primary_gpu(struct gdi_gpu *gpu) DECLSPEC_HIDDEN; extern void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler *handler) DECLSPEC_HIDDEN; +extern struct x11drv_display_device_handler X11DRV_DisplayDevices_GetHandler(void) DECLSPEC_HIDDEN; extern void X11DRV_DisplayDevices_Init(BOOL force) DECLSPEC_HIDDEN; extern void X11DRV_DisplayDevices_RegisterEventHandlers(void) DECLSPEC_HIDDEN; extern BOOL X11DRV_DisplayDevices_SupportEventHandlers(void) DECLSPEC_HIDDEN; @@ -946,6 +968,30 @@ static inline BOOL intersect_rect( RECT *dst, const RECT *src1, const RECT *src2 return !IsRectEmpty( dst ); } +static inline void union_rect( RECT *dest, const RECT *src1, const RECT *src2 ) +{ + if (IsRectEmpty( src1 )) + { + if (IsRectEmpty( src2 )) + { + reset_bounds( dest ); + return; + } + else *dest = *src2; + } + else + { + if (IsRectEmpty( src2 )) *dest = *src1; + else + { + dest->left = min( src1->left, src2->left ); + dest->right = max( src1->right, src2->right ); + dest->top = min( src1->top, src2->top ); + dest->bottom = max( src1->bottom, src2->bottom ); + } + } +} + /* registry helpers */ extern HKEY open_hkcu_key( const char *name ) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 6d5facc99c4..fefe8ddcec0 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -70,7 +70,7 @@ XPixmapFormatValues **pixmap_formats; Atom systray_atom = 0; unsigned int screen_bpp; Window root_window; -BOOL usexvidmode = TRUE; +BOOL usexvidmode = FALSE; BOOL usexrandr = TRUE; BOOL usexcomposite = TRUE; BOOL use_xfixes = FALSE; @@ -90,6 +90,7 @@ BOOL client_side_with_render = TRUE; BOOL shape_layered_windows = TRUE; int copy_default_colors = 128; int alloc_system_colors = 256; +int limit_number_of_resolutions = 0; int xrender_error_base = 0; int xfixes_event_base = 0; char *process_name = NULL; @@ -551,6 +552,9 @@ static void setup_options(void) if (!get_config_key( hkey, appkey, "AllocSystemColors", buffer, sizeof(buffer) )) alloc_system_colors = wcstol( buffer, NULL, 0 ); + if (!get_config_key( hkey, appkey, "LimitNumberOfResolutions", buffer, sizeof(buffer) )) + limit_number_of_resolutions = wcstol( buffer, NULL, 0 ); + get_config_key( hkey, appkey, "InputStyle", input_style, sizeof(input_style) ); NtClose( appkey ); @@ -819,6 +823,11 @@ static NTSTATUS x11drv_init( void *arg ) X11DRV_InitMouse( gdi_display ); if (use_xim) use_xim = X11DRV_InitXIM( input_style ); + { + const char *e = getenv("WINE_DISABLE_FULLSCREEN_HACK"); + if (!e || *e == '\0' || *e == '0') fs_hack_init(); + } + { const char *sgi = getenv("SteamGameId"); const char *e = getenv("WINE_LAYERED_WINDOW_CLIENT_HACK"); From c44a7c6e793106445b29c8d6f873998ddda6911d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 21:27:30 +0100 Subject: [PATCH 0670/2777] fshack: wine.inf: Limit resolution count for some games. These games have a bug where they crash with more than about 32 resolutions. This happens even on Windows. --- loader/wine.inf.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index a18177a4d42..db78c0ca70f 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2786,3 +2786,8 @@ HKCU,Software\Wine\AppDefaults\GW2.Main_Win64_Retail.exe\DllOverrides,"atiadlxx" HKCU,Software\Wine\AppDefaults\Spider-Man.exe\DllOverrides,"atiadlxx",,"builtin" HKLM,Software\Wow6432Node\lucasarts entertainment company llc\Star Wars: Episode I Racer\v1.0,"Display Height",0x10001,480 HKLM,Software\Wow6432Node\lucasarts entertainment company llc\Star Wars: Episode I Racer\v1.0,"Display Width",0x10001,640 +;;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" +HKCU,Software\Wine\AppDefaults\NieRAutomata.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"32" +HKCU,Software\Wine\AppDefaults\SpellForce.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"16" From 6dc71e28f9a02df3eb099538fd0bd33a69885524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:10:32 +0100 Subject: [PATCH 0671/2777] fshack: winex11: Remap mouse coordinates when fshack is active. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on work by Zhiyi Zhang, includes work by Giovanni Mascellani, Rémi Bernon, Arkadiusz Hiler, Kai Krakow, Joshua Ashton, Zebediah Figura, and Matteo Bruni. --- dlls/winex11.drv/mouse.c | 46 +++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 14fa5bc56d1..4142536b96f 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -442,6 +442,7 @@ static BOOL grab_clipping_window( const RECT *clip ) Window clip_window; HWND msg_hwnd = 0; POINT pos; + RECT real_clip; if (NtUserGetWindowThread( NtUserGetDesktopWindow(), NULL ) == GetCurrentThreadId()) return TRUE; /* don't clip in the desktop process */ @@ -461,9 +462,21 @@ static BOOL grab_clipping_window( const RECT *clip ) TRACE( "clipping to %s win %lx\n", wine_dbgstr_rect(clip), clip_window ); if (!data->clip_hwnd) XUnmapWindow( data->display, clip_window ); + + TRACE( "user clip rect %s\n", wine_dbgstr_rect( clip ) ); + + real_clip = *clip; + fs_hack_rect_user_to_real( &real_clip ); + pos = virtual_screen_to_root( clip->left, clip->top ); + + TRACE( "setting real clip to %s x (%d,%d)\n", wine_dbgstr_point( &pos ), + (int)real_clip.right - (int)real_clip.left, + (int)real_clip.bottom - (int)real_clip.top ); + XMoveResizeWindow( data->display, clip_window, pos.x, pos.y, - max( 1, clip->right - clip->left ), max( 1, clip->bottom - clip->top ) ); + max( 1, real_clip.right - real_clip.left ), + max( 1, real_clip.bottom - real_clip.top ) ); XMapWindow( data->display, clip_window ); /* if the rectangle is shrinking we may get a pointer warp */ @@ -642,11 +655,17 @@ static void map_event_coords( HWND hwnd, Window window, Window event_root, int x thread_data = x11drv_thread_data(); if (!thread_data->clip_hwnd) return; if (thread_data->clip_window != window) return; - pt.x += clip_rect.left; - pt.y += clip_rect.top; + pt.x = clip_rect.left; + pt.y = clip_rect.top; + fs_hack_point_user_to_real( &pt ); + + pt.x += input->u.mi.dx; + pt.y += input->u.mi.dy; + fs_hack_point_real_to_user( &pt ); } else if ((data = get_win_data( hwnd ))) { + if (data->fs_hack) fs_hack_point_real_to_user( &pt ); if (window == root_window) pt = root_to_virtual_screen( pt.x, pt.y ); else if (event_root == root_window) pt = root_to_virtual_screen( x_root, y_root ); else @@ -1554,11 +1573,13 @@ BOOL X11DRV_SetCursorPos( INT x, INT y ) struct x11drv_thread_data *data = x11drv_init_thread_data(); POINT pos = virtual_screen_to_root( x, y ); + TRACE( "real setting to %s\n", wine_dbgstr_point( &pos ) ); + XWarpPointer( data->display, root_window, root_window, 0, 0, 0, 0, pos.x, pos.y ); data->warp_serial = NextRequest( data->display ); XNoOp( data->display ); XFlush( data->display ); /* avoids bad mouse lag in games that do their own mouse warping */ - TRACE( "warped to %d,%d serial %lu\n", x, y, data->warp_serial ); + TRACE( "warped to (fake) %d,%d serial %lu\n", x, y, data->warp_serial ); return TRUE; } @@ -1885,9 +1906,11 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input ) { struct x11drv_thread_data *thread_data = x11drv_thread_data(); XIValuatorClassInfo *x = &thread_data->x_valuator, *y = &thread_data->y_valuator; - double x_value = 0, y_value = 0, x_scale, y_scale; + double x_value = 0, y_value = 0, x_scale, y_scale, user_to_real_scale; const double *values = event->valuators.values; RECT virtual_rect; + HMONITOR monitor; + POINT pt; int i; if (x->number < 0 || y->number < 0) return FALSE; @@ -1943,6 +1966,19 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input ) return FALSE; } + if (input->u.mi.dwFlags & MOUSEEVENTF_ABSOLUTE) + fs_hack_point_real_to_user( (POINT *)&input->u.mi.dx ); + else + { + RECT rect; + NtUserGetCursorPos( &pt ); + SetRect( &rect, pt.x, pt.y, pt.x + 1, pt.y + 1 ); + monitor = NtUserMonitorFromRect( &rect, MONITOR_DEFAULTTONULL ); + user_to_real_scale = fs_hack_get_user_to_real_scale( monitor ); + input->u.mi.dx = lround( (double)input->u.mi.dx / user_to_real_scale ); + input->u.mi.dy = lround( (double)input->u.mi.dy / user_to_real_scale ); + } + return TRUE; } From b81fa1b7641f48fadd9f5303135f453342a617c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:10:32 +0100 Subject: [PATCH 0672/2777] fshack: winex11: Force windows fullscreen state when fshack is active. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on work by Zhiyi Zhang, includes work by Giovanni Mascellani, Rémi Bernon, Arkadiusz Hiler, Kai Krakow, Joshua Ashton, Zebediah Figura, and Matteo Bruni. fshack: winex11: Use gdi_display for client_window requests. CW-Bug-Id: 16608 fshack: winex11: Resize child window client_windows too. CW-Bug-Id: 16608 fshack: winex11: Factor and fix fshack window resize helper. Fixing some incorrect window positions with Proton 8.0. --- dlls/win32u/window.c | 38 +++++++ dlls/winex11.drv/event.c | 18 +++- dlls/winex11.drv/window.c | 203 ++++++++++++++++++++++++++++++++++++-- dlls/winex11.drv/x11drv.h | 1 - include/ntuser.h | 13 +++ 5 files changed, 263 insertions(+), 10 deletions(-) diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 36a28c50c65..726ac15fc34 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -653,6 +653,38 @@ HWND *list_window_children( HDESK desktop, HWND hwnd, UNICODE_STRING *class, DWO return NULL; } +static BOOL enum_window_children( HWND *list, WNDENUMPROC func, LPARAM lParam ) +{ + HWND *child_list; + BOOL ret = FALSE; + + for ( ; *list; list++) + { + if (!is_window( *list )) continue; + child_list = list_window_children( 0, *list, NULL, 0 ); + ret = func( *list, lParam ); + if (child_list) + { + if (ret) ret = enum_window_children( child_list, func, lParam ); + free( child_list ); + } + if (!ret) return FALSE; + } + + return TRUE; +} + +static BOOL enum_child_windows( HWND parent, WNDENUMPROC func, LPARAM lParam ) +{ + HWND *list; + BOOL ret; + + if (!(list = list_window_children( 0, parent, NULL, 0 ))) return FALSE; + ret = enum_window_children( list, func, lParam ); + free( list ); + return ret; +} + /***************************************************************** * NtUserGetAncestor (win32u.@) */ @@ -5576,6 +5608,12 @@ ULONG_PTR WINAPI NtUserCallHwndParam( HWND hwnd, DWORD_PTR param, DWORD code ) case NtUserCallHwndParam_ShowOwnedPopups: return show_owned_popups( hwnd, param ); + case NtUserCallHwndParam_EnumChildWindows: + { + struct enum_child_windows_params *params = (void *)param; + return enum_child_windows( hwnd, params->proc, params->lparam ); + } + /* temporary exports */ case NtUserSetWindowStyle: { diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index f53ddcbdf55..f8ab367acfd 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1223,8 +1223,21 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) } else pos = root_to_virtual_screen( x, y ); - X11DRV_X_to_window_rect( data, &rect, pos.x, pos.y, event->width, event->height ); - if (root_coords) NtUserMapWindowPoints( 0, parent, (POINT *)&rect, 2 ); + if (data->fs_hack) + { + MONITORINFO info = {.cbSize = sizeof(MONITORINFO)}; + HMONITOR monitor; + + monitor = fs_hack_monitor_from_hwnd( hwnd ); + NtUserGetMonitorInfo( monitor, &info ); + rect = info.rcMonitor; + TRACE( "monitor %p rect: %s\n", monitor, wine_dbgstr_rect( &rect ) ); + } + else + { + X11DRV_X_to_window_rect( data, &rect, pos.x, pos.y, event->width, event->height ); + if (root_coords) NtUserMapWindowPoints( 0, parent, (POINT *)&rect, 2 ); + } TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n", hwnd, data->whole_window, (int)rect.left, (int)rect.top, @@ -1690,6 +1703,7 @@ static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event ) Window win, w_aux_root, w_aux_child; if (!(data = get_win_data( hWnd ))) return; + ERR( "TODO: fs hack\n" ); cx = data->whole_rect.right - data->whole_rect.left; cy = data->whole_rect.bottom - data->whole_rect.top; win = data->whole_window; diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index eeab1072039..151cda11d9a 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -485,6 +485,12 @@ static void sync_window_region( struct x11drv_win_data *data, HRGN win_region ) HRGN hrgn = win_region; if (!data->whole_window) return; + + if (data->fs_hack) + { + ERR( "shaped windows with fs hack not supported, things may go badly\n" ); + } + data->shaped = FALSE; if (IsRectEmpty( &data->window_rect )) /* set an empty shape */ @@ -1217,6 +1223,7 @@ void update_net_wm_states( struct x11drv_win_data *data ) { UINT i, style, ex_style, new_state = 0; unsigned long net_wm_bypass_compositor = 0; + HMONITOR monitor; if (!data->managed) return; if (data->whole_window == root_window) return; @@ -1224,15 +1231,20 @@ void update_net_wm_states( struct x11drv_win_data *data ) style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); if (style & WS_MINIMIZE) new_state |= data->net_wm_state & ((1 << NET_WM_STATE_FULLSCREEN)|(1 << NET_WM_STATE_MAXIMIZED)); - if (NtUserIsWindowRectFullScreen( &data->whole_rect )) + monitor = fs_hack_monitor_from_hwnd( data->hwnd ); + if ((!data->fs_hack || fs_hack_enabled( monitor )) && NtUserIsWindowRectFullScreen( &data->whole_rect )) { if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION) new_state |= (1 << NET_WM_STATE_MAXIMIZED); else if (!(style & WS_MINIMIZE)) { - if (is_window_rect_full_virtual_screen( &data->whole_rect )) - net_wm_bypass_compositor = 1; - new_state |= (1 << NET_WM_STATE_FULLSCREEN); + if (!wm_is_steamcompmgr( data->display ) || !fs_hack_enabled( monitor )) + { + /* when fs hack is enabled, we don't want steamcompmgr to resize the window to be fullscreened */ + if (is_window_rect_full_virtual_screen( &data->whole_rect )) + net_wm_bypass_compositor = 1; + new_state |= (1 << NET_WM_STATE_FULLSCREEN); + } } } else if (style & WS_MAXIMIZE) @@ -1553,8 +1565,22 @@ static HWND sync_window_position( struct x11drv_win_data *data, /* resizing a managed maximized window is not allowed */ if (!(style & WS_MAXIMIZE) || !data->managed) { - changes.width = data->whole_rect.right - data->whole_rect.left; - changes.height = data->whole_rect.bottom - data->whole_rect.top; + if (data->fs_hack) + { + HMONITOR monitor; + RECT rect; + + monitor = fs_hack_monitor_from_hwnd( data->hwnd ); + rect = fs_hack_real_mode( monitor ); + changes.width = rect.right - rect.left; + changes.height = rect.bottom - rect.top; + TRACE( "change width:%d height:%d\n", changes.width, changes.height ); + } + else + { + changes.width = data->whole_rect.right - data->whole_rect.left; + changes.height = data->whole_rect.bottom - data->whole_rect.top; + } /* if window rect is empty force size to 1x1 */ if (changes.width <= 0 || changes.height <= 0) changes.width = changes.height = 1; if (changes.width > 65535) changes.width = 65535; @@ -1652,6 +1678,21 @@ static void sync_client_position( struct x11drv_win_data *data, if (changes.width != old_client_rect->right - old_client_rect->left) mask |= CWWidth; if (changes.height != old_client_rect->bottom - old_client_rect->top) mask |= CWHeight; + if (data->fs_hack) + { + HMONITOR monitor; + RECT rect; + + monitor = fs_hack_monitor_from_hwnd( data->hwnd ); + rect = fs_hack_real_mode( monitor ); + changes.x = 0; + changes.y = 0; + changes.width = rect.right - rect.left; + changes.height = rect.bottom - rect.top; + mask = CWX | CWY | CWWidth | CWHeight; + TRACE( "x:%d y:%d width:%d height:%d\n", changes.x, changes.y, changes.width, changes.height ); + } + if (mask) { TRACE( "setting client win %lx pos %d,%d,%dx%d changes=%x\n", @@ -1874,6 +1915,17 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual ) cx = min( max( 1, data->client_rect.right - data->client_rect.left ), 65535 ); cy = min( max( 1, data->client_rect.bottom - data->client_rect.top ), 65535 ); + if (data->fs_hack) + { + HMONITOR monitor = fs_hack_monitor_from_hwnd( hwnd ); + RECT rect = fs_hack_real_mode( monitor ); + cx = rect.right - rect.left; + cy = rect.bottom - rect.top; + + TRACE( "width:%d height:%d\n", cx, cy ); + } + + TRACE( "setting client rect: %u, %u x %ux%u\n", x, y, cx, cy ); ret = data->client_window = XCreateWindow( gdi_display, data->whole_window ? data->whole_window : dummy_parent, x, y, cx, cy, 0, default_visual.depth, InputOutput, @@ -1882,6 +1934,8 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual ) if (data->client_window) { XSaveContext( data->display, data->client_window, winContext, (char *)data->hwnd ); + /* Save to gdi_display as well for fullscreen hack, needed in X11DRV_query_fs_hack() */ + XSaveContext( gdi_display, data->client_window, winContext, (char *)data->hwnd ); XMapWindow( gdi_display, data->client_window ); XSync( gdi_display, False ); if (data->whole_window) XSelectInput( data->display, data->client_window, ExposureMask ); @@ -1940,11 +1994,26 @@ static void create_whole_window( struct x11drv_win_data *data ) mask = get_window_attributes( data, &attr ); + attr.background_pixel = XBlackPixel( data->display, data->vis.screen ); + mask |= CWBackPixel; + if (!(cx = data->whole_rect.right - data->whole_rect.left)) cx = 1; else if (cx > 65535) cx = 65535; if (!(cy = data->whole_rect.bottom - data->whole_rect.top)) cy = 1; else if (cy > 65535) cy = 65535; + if (data->fs_hack) + { + RECT rect = {0, 0, 0, 0}; + HMONITOR monitor; + + monitor = fs_hack_monitor_from_hwnd( data->hwnd ); + rect = fs_hack_real_mode( monitor ); + cx = rect.right - rect.left; + cy = rect.bottom - rect.top; + TRACE( "width:%d height:%d\n", cx, cy ); + } + pos = virtual_screen_to_root( data->whole_rect.left, data->whole_rect.top ); data->whole_window = XCreateWindow( data->display, root_window, pos.x, pos.y, cx, cy, 0, data->vis.depth, InputOutput, @@ -2851,6 +2920,85 @@ static inline BOOL get_surface_rect( const RECT *visible_rect, RECT *surface_rec return TRUE; } +static BOOL CALLBACK update_child_window_fshack( HWND hwnd, LPARAM enable ); + +static void window_update_fshack( struct x11drv_win_data *data, const RECT *window_rect_virt, + const RECT *client_rect_virt, BOOL enable ) +{ + BOOL set_hints = window_rect_virt == NULL; /* don't change hints yet in X11DRV_WindowPosChanging */ + RECT window_rect_host, client_rect_host; + + if (wm_is_steamcompmgr( data->display )) return; + if (!!data->fs_hack == !!enable) return; + data->fs_hack = enable; + + if (!window_rect_virt) window_rect_virt = &data->window_rect; + if (!client_rect_virt) client_rect_virt = &data->client_rect; + + if (!enable) + { + window_rect_host = *window_rect_virt; + client_rect_host = data->client_rect; + OffsetRect( &client_rect_host, -data->whole_rect.left, -data->whole_rect.top ); + } + else + { + HMONITOR monitor = fs_hack_monitor_from_hwnd( data->hwnd ); + window_rect_host = fs_hack_real_mode( monitor ); + + if (data->whole_window) /* HACK: top-level window, pretend client rect covers it fully */ + client_rect_host = window_rect_host; + else + { + client_rect_host = *client_rect_virt; + NtUserClientToScreen( data->hwnd, (POINT *)&client_rect_host.left ); + NtUserClientToScreen( data->hwnd, (POINT *)&client_rect_host.right ); + fs_hack_rect_user_to_real( &client_rect_host ); + OffsetRect( &client_rect_host, -window_rect_host.left, -window_rect_host.top ); + } + } + + FIXME( "%sbling fshack for hwnd %p, mapping virt window %s, client %s to host window %s, client %s.\n", + enable ? "Ena" : "Disa", data->hwnd, wine_dbgstr_rect( window_rect_virt ), wine_dbgstr_rect( client_rect_virt ), + wine_dbgstr_rect( &window_rect_host ), wine_dbgstr_rect( &client_rect_host ) ); + + if (data->whole_window) + { + POINT top_left = *(POINT *)&window_rect_host; + OffsetRect( &window_rect_host, -top_left.x, -top_left.y ); + + if (set_hints) set_wm_hints( data ); + + window_rect_host.right = min( max( window_rect_host.right, 1 ), 65535 ); + window_rect_host.bottom = min( max( window_rect_host.bottom, 1 ), 65535 ); + XMoveResizeWindow( data->display, data->whole_window, top_left.x, top_left.y, window_rect_host.right, window_rect_host.bottom ); + + if (set_hints) update_net_wm_states( data ); + } + + if (data->client_window) + { + POINT top_left = *(POINT *)&client_rect_host; + OffsetRect( &client_rect_host, -top_left.x, -top_left.y ); + + client_rect_host.right = min( max( client_rect_host.right, 1 ), 65535 ); + client_rect_host.bottom = min( max( client_rect_host.bottom, 1 ), 65535 ); + XMoveResizeWindow( gdi_display, data->client_window, top_left.x, top_left.y, client_rect_host.right, client_rect_host.bottom ); + + sync_gl_drawable( data->hwnd, !data->whole_window ); + } + + NtUserEnumChildWindows( data->hwnd, update_child_window_fshack, enable ); +} + +static BOOL CALLBACK update_child_window_fshack( HWND hwnd, LPARAM enable ) +{ + struct x11drv_win_data *data; + if (!(data = get_win_data( hwnd ))) return TRUE; + if (data->client_window) window_update_fshack( data, NULL, NULL, enable ); + release_win_data( data ); + return TRUE; +} /*********************************************************************** * WindowPosChanging (X11DRV.@) @@ -2864,9 +3012,17 @@ BOOL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags, DWORD flags; COLORREF key; BOOL layered = NtUserGetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED; + HMONITOR monitor; if (!data && !(data = X11DRV_create_win_data( hwnd, window_rect, client_rect ))) return TRUE; + monitor = fs_hack_monitor_from_rect( window_rect ); + if (fs_hack_enabled( monitor ) && fs_hack_matches_current_mode( monitor, window_rect->right - window_rect->left, + window_rect->bottom - window_rect->top )) + window_update_fshack( data, window_rect, client_rect, TRUE ); + else + window_update_fshack( data, window_rect, client_rect, FALSE ); + /* check if we need to switch the window to managed */ if (!data->managed && data->whole_window && is_window_managed( hwnd, swp_flags, window_rect )) { @@ -3046,6 +3202,8 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, set_hwnd_style_props( data->display, data->whole_window, data->hwnd ); + if (data->fs_hack) sync_gl_drawable( hwnd, FALSE ); + /* check if we are currently processing an event relevant to this window */ event_type = 0; if (thread_data && @@ -3168,6 +3326,7 @@ UINT X11DRV_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp ) DWORD style = NtUserGetWindowLongW( hwnd, GWL_STYLE ); struct x11drv_thread_data *thread_data = x11drv_thread_data(); struct x11drv_win_data *data = get_win_data( hwnd ); + HMONITOR monitor; if (!data || !data->whole_window) goto done; if (style & WS_MINIMIZE) @@ -3197,7 +3356,21 @@ UINT X11DRV_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp ) &root, &x, &y, &width, &height, &border, &depth ); XTranslateCoordinates( thread_data->display, data->whole_window, root, 0, 0, &x, &y, &top ); pos = root_to_virtual_screen( x, y ); - X11DRV_X_to_window_rect( data, rect, pos.x, pos.y, width, height ); + monitor = fs_hack_monitor_from_hwnd( hwnd ); + if (data->fs_hack || + (fs_hack_enabled( monitor ) && + fs_hack_matches_current_mode( monitor, rect->right - rect->left, rect->bottom - rect->top ))) + { + MONITORINFO info = {.cbSize = sizeof(MONITORINFO)}; + NtUserGetMonitorInfo( monitor, &info ); + X11DRV_X_to_window_rect( data, rect, info.rcMonitor.left, info.rcMonitor.top, + info.rcMonitor.right - info.rcMonitor.left, + info.rcMonitor.bottom - info.rcMonitor.top ); + } + else + { + X11DRV_X_to_window_rect( data, rect, pos.x, pos.y, width, height ); + } swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE); done: @@ -3439,6 +3612,16 @@ static void taskbar_delete_tab( HWND hwnd ) static void handle_window_desktop_resize( struct x11drv_win_data *data, UINT old_x, UINT old_y ) { + HMONITOR monitor = fs_hack_monitor_from_hwnd( data->hwnd ); + + if (fs_hack_mapping_required( monitor ) && + fs_hack_matches_current_mode( monitor, data->whole_rect.right - data->whole_rect.left, + data->whole_rect.bottom - data->whole_rect.top )) + { + window_update_fshack( data, NULL, NULL, TRUE ); + return; + } + /* update the full screen state */ update_net_wm_states( data ); @@ -3452,9 +3635,15 @@ static void handle_window_desktop_resize( struct x11drv_win_data *data, UINT old if (old_pos.x != pos.x) mask |= CWX; if (old_pos.y != pos.y) mask |= CWY; + if (data->fs_hack) mask |= CWX | CWY; if (mask) XReconfigureWMWindow( data->display, data->whole_window, data->vis.screen, mask, &changes ); } + + if (!fs_hack_mapping_required( monitor ) || + !fs_hack_matches_current_mode( monitor, data->whole_rect.right - data->whole_rect.left, + data->whole_rect.bottom - data->whole_rect.top )) + window_update_fshack( data, NULL, NULL, FALSE ); } /********************************************************************** diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 9cec0391aff..6cd236e876a 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -715,7 +715,6 @@ extern double fs_hack_get_user_to_real_scale( HMONITOR ) DECLSPEC_HIDDEN; extern SIZE fs_hack_get_scaled_screen_size( HMONITOR monitor ) DECLSPEC_HIDDEN; extern RECT fs_hack_get_real_virtual_screen(void) DECLSPEC_HIDDEN; extern void fs_hack_init(void) DECLSPEC_HIDDEN; -extern int mode_compare( const void *p1, const void *p2 ) DECLSPEC_HIDDEN; static inline void mirror_rect( const RECT *window_rect, RECT *rect ) { diff --git a/include/ntuser.h b/include/ntuser.h index ee97f535534..97659711310 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -1333,6 +1333,7 @@ enum NtUserCallHwndParam_SetWindowContextHelpId, NtUserCallHwndParam_SetWindowPixelFormat, NtUserCallHwndParam_ShowOwnedPopups, + NtUserCallHwndParam_EnumChildWindows, /* temporary exports */ NtUserSetWindowStyle, }; @@ -1508,4 +1509,16 @@ static inline BOOL NtUserShowOwnedPopups( HWND hwnd, BOOL show ) return NtUserCallHwndParam( hwnd, show, NtUserCallHwndParam_ShowOwnedPopups ); } +struct enum_child_windows_params +{ + WNDENUMPROC proc; + LPARAM lparam; +}; + +static inline BOOL NtUserEnumChildWindows( HWND hwnd, WNDENUMPROC proc, LPARAM lparam ) +{ + struct enum_child_windows_params params = {.proc = proc, .lparam = lparam}; + return NtUserCallHwndParam( hwnd, (UINT_PTR)¶ms, NtUserCallHwndParam_EnumChildWindows ); +} + #endif /* _NTUSER_ */ From 80aebe4f8c2e72137d9611b6d125084e3fa78676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:10:32 +0100 Subject: [PATCH 0673/2777] fshack: winex11: Support xrender scaling according to fake resolution. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on work by Zhiyi Zhang, includes work by Giovanni Mascellani, Rémi Bernon, Arkadiusz Hiler, Kai Krakow, Joshua Ashton, Zebediah Figura, and Matteo Bruni. --- dlls/winex11.drv/graphics.c | 3 +- dlls/winex11.drv/xrender.c | 136 +++++++++++++++++++++++++++++++----- 2 files changed, 122 insertions(+), 17 deletions(-) diff --git a/dlls/winex11.drv/graphics.c b/dlls/winex11.drv/graphics.c index 54e6b9b2084..fbc1c9cde1b 100644 --- a/dlls/winex11.drv/graphics.c +++ b/dlls/winex11.drv/graphics.c @@ -256,8 +256,9 @@ static void update_x11_clipping( X11DRV_PDEVICE *physDev, HRGN rgn ) } else if ((data = X11DRV_GetRegionData( rgn, 0 ))) { + fs_hack_rgndata_user_to_real( data ); XSetClipRectangles( gdi_display, physDev->gc, physDev->dc_rect.left, physDev->dc_rect.top, - (XRectangle *)data->Buffer, data->rdh.nCount, YXBanded ); + (XRectangle *)data->Buffer, data->rdh.nCount, Unsorted ); free( data ); } } diff --git a/dlls/winex11.drv/xrender.c b/dlls/winex11.drv/xrender.c index bb38fd90584..718c9b6ea60 100644 --- a/dlls/winex11.drv/xrender.c +++ b/dlls/winex11.drv/xrender.c @@ -470,6 +470,7 @@ static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn ) } else if ((data = X11DRV_GetRegionData( rgn, 0 ))) { + fs_hack_rgndata_user_to_real( data ); pXRenderSetPictureClipRectangles( gdi_display, dev->pict, dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top, (XRectangle *)data->Buffer, data->rdh.nCount ); @@ -1449,13 +1450,71 @@ static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha, XFreePixmap( gdi_display, mask_pixmap ); } +/* if we are letterboxing, draw black bars */ +static void fs_hack_draw_black_bars( HMONITOR monitor, Picture dst_pict ) +{ + static const XRenderColor black = {0, 0, 0, 0xffff}; + POINT tl, br; /* top-left / bottom-right */ + RECT user_rect = fs_hack_current_mode( monitor ); + RECT real_rect = fs_hack_real_mode( monitor ); + SIZE scaled_screen = fs_hack_get_scaled_screen_size( monitor ); + XRenderPictureAttributes pa; + + /* first unclip the picture, so that we can actually draw them */ + pa.clip_mask = None; + pXRenderChangePicture( gdi_display, dst_pict, CPClipMask, &pa ); + + tl.x = user_rect.left; + tl.y = user_rect.top; + fs_hack_point_user_to_real( &tl ); + tl.x = tl.x - real_rect.left; + tl.y = tl.y - real_rect.top; + br.x = tl.x + scaled_screen.cx; + br.y = tl.y + scaled_screen.cy; + + if (tl.x > 0) + { + /* black bars left & right */ + pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, &black, 0, 0, /* x, y */ + tl.x, real_rect.bottom - real_rect.top ); /* w, h */ + pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, &black, br.x, 0, + real_rect.right - real_rect.left - br.x, real_rect.bottom - real_rect.top ); + } + else if (tl.y > 0) + { + /* black bars top & bottom */ + pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, &black, 0, 0, + real_rect.right - real_rect.left, tl.y ); + pXRenderFillRectangle( gdi_display, PictOpSrc, dst_pict, &black, 0, br.y, + real_rect.right - real_rect.left, real_rect.bottom - real_rect.top - br.y ); + } +} + /* Helper function for (stretched) blitting using xrender */ -static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict, - int x_src, int y_src, int width_src, int height_src, - int x_dst, int y_dst, int width_dst, int height_dst, - double xscale, double yscale ) +static void xrender_blit( struct xrender_physdev *physdev, int op, Picture src_pict, Picture mask_pict, + Picture dst_pict, int x_src, int y_src, int width_src, int height_src, int x_dst, + int y_dst, int width_dst, int height_dst, double xscale, double yscale ) { int x_offset, y_offset; + HMONITOR monitor; + + monitor = fs_hack_monitor_from_hwnd( NtUserWindowFromDC( physdev->dev.hdc ) ); + if (fs_hack_mapping_required( monitor )) + { + double user_to_real_scale; + POINT p; + p.x = x_dst; + p.y = y_dst; + fs_hack_point_user_to_real( &p ); + x_dst = p.x; + y_dst = p.y; + + user_to_real_scale = fs_hack_get_user_to_real_scale( monitor ); + width_dst *= user_to_real_scale; + height_dst *= user_to_real_scale; + xscale /= user_to_real_scale; + yscale /= user_to_real_scale; + } if (width_src < 0) { @@ -1496,6 +1555,8 @@ static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture d } pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict, x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst ); + + if (fs_hack_mapping_required( monitor )) fs_hack_draw_black_bars( monitor, dst_pict ); } /* Helper function for (stretched) mono->color blitting using xrender */ @@ -1655,7 +1716,7 @@ static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xr if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32) mask_pict = get_no_alpha_mask(); - xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, + xrender_blit( physdev_dst, PictOpSrc, src_pict, mask_pict, dst_pict, physdev_src->x11dev->dc_rect.left + src->x, physdev_src->x11dev->dc_rect.top + src->y, src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale ); @@ -1679,6 +1740,7 @@ static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask RGNDATA *clip_data = NULL; if (clip) clip_data = X11DRV_GetRegionData( clip, 0 ); + fs_hack_rgndata_user_to_real( clip_data ); x_dst = dst->x; y_dst = dst->y; dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, 0, NULL ); @@ -1701,7 +1763,7 @@ static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask } else xscale = yscale = 1; /* no scaling needed with a repeating source */ - xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height, + xrender_blit( physdev, PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale ); if (drawable) pXRenderFreePicture( gdi_display, dst_pict ); @@ -1717,6 +1779,11 @@ static BOOL CDECL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords * struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev ); struct xrender_physdev *physdev_src = get_xrender_dev( src_dev ); BOOL stretch = (src->width != dst->width) || (src->height != dst->height); + HMONITOR monitor; + + TRACE( "src %d,%d %dx%d vis=%s dst %d,%d %dx%d vis=%s rop=%06x\n", src->x, src->y, src->width, + src->height, wine_dbgstr_rect( &src->visrect ), dst->x, dst->y, dst->width, dst->height, + wine_dbgstr_rect( &dst->visrect ), (int)rop ); if (src_dev->funcs != dst_dev->funcs) { @@ -1728,6 +1795,9 @@ static BOOL CDECL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords * if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO) goto x11drv_fallback; + monitor = fs_hack_monitor_from_hwnd( NtUserWindowFromDC( dst_dev->hdc ) ); + if (fs_hack_mapping_required( monitor )) stretch = TRUE; + /* if not stretching, we only need to handle format conversion */ if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback; @@ -1746,8 +1816,21 @@ static BOOL CDECL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords * tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL ); XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors ); XSetGraphicsExposures( gdi_display, tmpGC, False ); - tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left, - tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth ); + + if (fs_hack_mapping_required( monitor )) + { + double user_to_real_scale; + SIZE size; + + user_to_real_scale = fs_hack_get_user_to_real_scale( monitor ); + size.cx = (tmp.visrect.right - tmp.visrect.left) * user_to_real_scale; + size.cy = (tmp.visrect.bottom - tmp.visrect.top) * user_to_real_scale; + tmp_pixmap = XCreatePixmap( gdi_display, root_window, size.cx, size.cy, + physdev_dst->pict_format->depth ); + } + else tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left, + tmp.visrect.bottom - tmp.visrect.top, + physdev_dst->pict_format->depth ); xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp ); execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop ); @@ -1782,6 +1865,10 @@ static DWORD CDECL xrenderdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info Picture src_pict, mask_pict = 0; BOOL use_repeat; + TRACE( "src %d,%d %dx%d vis=%s dst %d,%d %dx%d vis=%s rop=%06x\n", src->x, src->y, src->width, + src->height, wine_dbgstr_rect( &src->visrect ), dst->x, dst->y, dst->width, dst->height, + wine_dbgstr_rect( &dst->visrect ), (int)rop ); + dst_format = physdev->format; src_format = get_xrender_format_from_bitmapinfo( info ); if (!(pict_format = pict_formats[src_format])) goto update_format; @@ -1806,6 +1893,7 @@ static DWORD CDECL xrenderdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info if (rop != SRCCOPY) { BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip ); + HMONITOR monitor; /* make coordinates relative to tmp pixmap */ tmp = *dst; @@ -1816,13 +1904,29 @@ static DWORD CDECL xrenderdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL ); XSetSubwindowMode( gdi_display, gc, IncludeInferiors ); XSetGraphicsExposures( gdi_display, gc, False ); - tmp_pixmap = XCreatePixmap( gdi_display, root_window, - tmp.visrect.right - tmp.visrect.left, - tmp.visrect.bottom - tmp.visrect.top, - physdev->pict_format->depth ); + + monitor = fs_hack_monitor_from_hwnd( NtUserWindowFromDC( dev->hdc ) ); + if (fs_hack_mapping_required( monitor )) + { + double user_to_real_scale; + SIZE size; + + user_to_real_scale = fs_hack_get_user_to_real_scale( monitor ); + size.cx = (tmp.visrect.right - tmp.visrect.left) * user_to_real_scale; + size.cy = (tmp.visrect.bottom - tmp.visrect.top) * user_to_real_scale; + tmp_pixmap = XCreatePixmap( gdi_display, root_window, size.cx, size.cy, + physdev->pict_format->depth ); + } + else + { + tmp_pixmap = XCreatePixmap( gdi_display, root_window, + tmp.visrect.right - tmp.visrect.left, + tmp.visrect.bottom - tmp.visrect.top, + physdev->pict_format->depth ); + } xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format, - NULL, tmp_pixmap, src, &tmp, use_repeat ); + physdev, tmp_pixmap, src, &tmp, use_repeat ); execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop ); XFreePixmap( gdi_display, tmp_pixmap ); @@ -1899,7 +2003,7 @@ static DWORD CDECL xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const s pthread_mutex_lock( &xrender_mutex ); mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 ); - xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, + xrender_blit( physdev, PictOpOver, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height, physdev->x11dev->dc_rect.left + dst->x, physdev->x11dev->dc_rect.top + dst->y, @@ -1988,7 +2092,7 @@ static BOOL CDECL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords * pthread_mutex_lock( &xrender_mutex ); mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 ); - xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, + xrender_blit( physdev_dst, PictOpOver, src_pict, mask_pict, dst_pict, physdev_src->x11dev->dc_rect.left + src->x, physdev_src->x11dev->dc_rect.top + src->y, src->width, src->height, @@ -2091,7 +2195,7 @@ static BOOL CDECL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, U dst_pict = get_xrender_picture( physdev, 0, NULL ); src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 ); - xrender_blit( PictOpSrc, src_pict, 0, dst_pict, + xrender_blit( physdev, PictOpSrc, src_pict, 0, dst_pict, 0, 0, rc.right - rc.left, rc.bottom - rc.top, physdev->x11dev->dc_rect.left + rc.left, physdev->x11dev->dc_rect.top + rc.top, From 110748bf4001a30d9185cf7da860a4b72164f45c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:10:32 +0100 Subject: [PATCH 0674/2777] fshack: winex11: Support opengl scaling according to fake resolution. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on work by Zhiyi Zhang, includes work by Giovanni Mascellani, Rémi Bernon, Arkadiusz Hiler, Kai Krakow, Joshua Ashton, Zebediah Figura, and Matteo Bruni. --- dlls/winex11.drv/opengl.c | 521 +++++++++++++++++++++++++++++++++++++- 1 file changed, 516 insertions(+), 5 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index af7aac39ea0..4888e57de56 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -43,6 +43,10 @@ #include "winternl.h" #include "wine/debug.h" +#ifndef ARRAY_SIZE +#define ARRAY_SIZE( array ) (sizeof(array) / sizeof((array)[0])) +#endif + #ifdef SONAME_LIBGL WINE_DEFAULT_DEBUG_CHANNEL(wgl); @@ -206,6 +210,13 @@ struct wgl_context struct gl_drawable *drawables[2]; struct gl_drawable *new_drawables[2]; BOOL refresh_drawables; + BOOL fs_hack; + BOOL fs_hack_integer; + GLuint fs_hack_fbo, fs_hack_resolve_fbo; + GLuint fs_hack_color_texture, fs_hack_ds_texture; + GLuint fs_hack_color_renderbuffer, fs_hack_color_resolve_renderbuffer, fs_hack_ds_renderbuffer; + POINT setup_for; + GLuint current_draw_fbo, current_read_fbo; struct list entry; }; @@ -239,6 +250,10 @@ struct gl_drawable int swap_interval; BOOL refresh_swap_interval; BOOL mutable_pf; + BOOL fs_hack; + BOOL fs_hack_did_swapbuf; + BOOL fs_hack_context_set_up; + BOOL has_scissor_indexed; }; struct wgl_pbuffer @@ -375,6 +390,10 @@ static int (*pglXSwapIntervalSGI)(int); static void* (*pglXAllocateMemoryNV)(GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); static void (*pglXFreeMemoryNV)(GLvoid *pointer); +static void (*pglScissorIndexed)( GLuint, GLint, GLint, GLsizei, GLsizei ); +static void (*pglScissorIndexedv)( GLuint, const GLint * ); +static void (*pglGetIntegeri_v)( GLenum, GLuint, GLint * ); + /* MESA GLX Extensions */ static void (*pglXCopySubBufferMESA)(Display *dpy, GLXDrawable drawable, int x, int y, int width, int height); static int (*pglXSwapIntervalMESA)(unsigned int interval); @@ -398,6 +417,29 @@ static void wglFinish(void); static void wglFlush(void); static const GLubyte *wglGetString(GLenum name); +/* Fullscreen hack */ +static void (*pglBindFramebuffer)( GLenum target, GLuint framebuffer ); +static void (*pglBindFramebufferEXT)( GLenum target, GLuint framebuffer ); +static void (*pglBindRenderbuffer)( GLenum target, GLuint renderbuffer ); +static void (*pglBlitFramebuffer)( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, + GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter ); +void (*pglDeleteFramebuffers)( GLsizei n, const GLuint *framebuffers ); +void (*pglDeleteRenderbuffers)( GLsizei n, const GLuint *renderbuffers ); +static void (*pglDrawBuffer)( GLenum buffer ); +static void (*pglFramebufferRenderbuffer)( GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer ); +static void (*pglFramebufferTexture2D)( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ); +static void (*pglGenFramebuffers)( GLsizei n, GLuint *ids ); +static void (*pglGenRenderbuffers)( GLsizei n, GLuint *renderbuffers ); +static void (*pglReadBuffer)( GLenum src ); +static void (*pglRenderbufferStorage)( GLenum target, GLenum internalformat, GLsizei width, GLsizei height ); +static void (*pglRenderbufferStorageMultisample)( GLenum target, GLsizei samples, GLenum internalformat, + GLsizei width, GLsizei height ); + +static void wglBindFramebuffer( GLenum target, GLuint framebuffer ); +static void wglBindFramebufferEXT( GLenum target, GLuint framebuffer ); +static void wglDrawBuffer( GLenum buffer ); +static void wglReadBuffer( GLenum src ); + /* check if the extension is present in the list */ static BOOL has_extension( const char *list, const char *ext ) { @@ -573,9 +615,11 @@ static void init_opengl(void) /* redirect some standard OpenGL functions */ #define REDIRECT(func) \ do { p##func = opengl_funcs.gl.p_##func; opengl_funcs.gl.p_##func = w##func; } while(0) + REDIRECT( glDrawBuffer ); REDIRECT( glFinish ); REDIRECT( glFlush ); REDIRECT( glGetString ); + REDIRECT( glReadBuffer ); #undef REDIRECT pglXGetProcAddressARB = dlsym(opengl_handle, "glXGetProcAddressARB"); @@ -584,6 +628,22 @@ static void init_opengl(void) goto failed; } + /* Fullscreen hack */ +#define LOAD_FUNCPTR(func) p##func = (void *)pglXGetProcAddressARB((const unsigned char *)#func); + LOAD_FUNCPTR( glBindFramebuffer ); + LOAD_FUNCPTR( glBindFramebufferEXT ); + LOAD_FUNCPTR( glBindRenderbuffer ); + LOAD_FUNCPTR( glBlitFramebuffer ); + LOAD_FUNCPTR( glDeleteFramebuffers ); + LOAD_FUNCPTR( glDeleteRenderbuffers ); + LOAD_FUNCPTR( glFramebufferRenderbuffer ); + LOAD_FUNCPTR( glFramebufferTexture2D ); + LOAD_FUNCPTR( glGenFramebuffers ); + LOAD_FUNCPTR( glGenRenderbuffers ); + LOAD_FUNCPTR( glRenderbufferStorage ); + LOAD_FUNCPTR( glRenderbufferStorageMultisample ); +#undef LOAD_FUNCPTR + #define LOAD_FUNCPTR(f) do if((p##f = (void*)pglXGetProcAddressARB((const unsigned char*)#f)) == NULL) \ { \ ERR( "%s not found in libGL, disabling OpenGL.\n", #f ); \ @@ -634,6 +694,10 @@ static void init_opengl(void) /* NV GLX Extension */ LOAD_FUNCPTR(glXAllocateMemoryNV); LOAD_FUNCPTR(glXFreeMemoryNV); + + LOAD_FUNCPTR(glScissorIndexed); + LOAD_FUNCPTR(glScissorIndexedv); + LOAD_FUNCPTR(glGetIntegeri_v); #undef LOAD_FUNCPTR if(!X11DRV_WineGL_InitOpenglInfo()) goto failed; @@ -724,6 +788,13 @@ static void init_opengl(void) pglXSwapBuffersMscOML = pglXGetProcAddressARB( (const GLubyte *)"glXSwapBuffersMscOML" ); } + if (has_extension( glExtensions, "GL_ARB_viewport_array" )) + { + opengl_funcs.ext.p_glGetIntegeri_v = pglGetIntegeri_v; + opengl_funcs.ext.p_glScissorIndexed = pglScissorIndexed; + opengl_funcs.ext.p_glScissorIndexedv = pglScissorIndexedv; + } + X11DRV_WineGL_LoadExtensions(); init_pixel_formats( gdi_display ); return; @@ -1382,10 +1453,16 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel else if (!known_child && !NtUserGetWindowRelative( hwnd, GW_CHILD ) && NtUserGetAncestor( hwnd, GA_PARENT ) == NtUserGetDesktopWindow()) /* childless top-level window */ { + struct x11drv_win_data *data; + gl->type = DC_GL_WINDOW; gl->window = create_client_window( hwnd, visual ); if (gl->window) gl->drawable = pglXCreateWindow( gdi_display, gl->format->fbconfig, gl->window, NULL ); + data = get_win_data( hwnd ); + gl->fs_hack = data->fs_hack; + if (gl->fs_hack) TRACE( "Window %p has the fullscreen hack enabled\n", hwnd ); + release_win_data( data ); TRACE( "%p created client %lx drawable %lx\n", hwnd, gl->window, gl->drawable ); } #ifdef SONAME_LIBXCOMPOSITE @@ -1512,6 +1589,9 @@ void sync_gl_drawable( HWND hwnd, BOOL known_child ) { enum dc_gl_layered_type new_layered_type; struct gl_drawable *old, *new; + struct x11drv_win_data *data; + + TRACE( "%p\n", hwnd ); if (!(old = get_gl_drawable( hwnd, 0 ))) return; @@ -1527,6 +1607,15 @@ void sync_gl_drawable( HWND hwnd, BOOL known_child ) release_gl_drawable( new ); } } + + if (DC_GL_PIXMAP_WIN != old->type) + { + data = get_win_data( hwnd ); + old->fs_hack = data->fs_hack; + if (old->fs_hack) TRACE( "Window %p has the fullscreen hack enabled\n", hwnd ); + release_win_data( data ); + } + release_gl_drawable( old ); } @@ -1891,6 +1980,8 @@ static BOOL glxdrv_wglDeleteContext(struct wgl_context *ctx) static PROC glxdrv_wglGetProcAddress(LPCSTR lpszProc) { if (!strncmp(lpszProc, "wgl", 3)) return NULL; + if (!strcmp( lpszProc, "glBindFramebuffer" )) return (PROC)(void *)wglBindFramebuffer; + if (!strcmp( lpszProc, "glBindFramebufferEXT" )) return (PROC)(void *)wglBindFramebufferEXT; return pglXGetProcAddressARB((const GLubyte*)lpszProc); } @@ -1910,12 +2001,243 @@ static void set_context_drawables( struct wgl_context *ctx, struct gl_drawable * for (i = 0; i < 4; i++) release_gl_drawable( prev[i] ); } +struct fs_hack_fbconfig_attribs +{ + int render_type; + int buffer_size; + int red_size; + int green_size; + int blue_size; + int alpha_size; + int depth_size; + int stencil_size; + int doublebuffer; + int samples; + int srgb; +}; + +struct fs_hack_fbo_attachments_config +{ + GLint color_internalformat; + GLenum color_format; + GLenum color_type; + GLint ds_internalformat; + GLenum ds_format; + GLenum ds_type; + int samples; +}; + +static void fs_hack_get_attachments_config( struct gl_drawable *gl, struct fs_hack_fbconfig_attribs *attribs, + struct fs_hack_fbo_attachments_config *config ) +{ + if (attribs->render_type != GLX_RGBA_BIT) + FIXME( "Unsupported GLX_RENDER_TYPE %#x.\n", attribs->render_type ); + if (attribs->red_size != 8 || attribs->green_size != 8 || attribs->blue_size != 8) + FIXME( "Unsupported RGBA color sizes {%u, %u, %u, %u}.\n", attribs->red_size, + attribs->green_size, attribs->blue_size, attribs->alpha_size ); + if (attribs->srgb) config->color_internalformat = attribs->alpha_size ? GL_SRGB8_ALPHA8 : GL_SRGB8; + else config->color_internalformat = attribs->alpha_size ? GL_RGBA8 : GL_RGB8; + config->color_format = GL_BGRA; + config->color_type = GL_UNSIGNED_INT_8_8_8_8_REV; + if (attribs->depth_size || attribs->stencil_size) + { + if (attribs->depth_size != 24) FIXME( "Unsupported depth buffer size %u.\n", attribs->depth_size ); + if (attribs->stencil_size && attribs->stencil_size != 8) + FIXME( "Unsupported stencil buffer size %u.\n", attribs->stencil_size ); + config->ds_internalformat = attribs->stencil_size ? GL_DEPTH24_STENCIL8 : GL_DEPTH_COMPONENT24; + config->ds_format = attribs->stencil_size ? GL_DEPTH_STENCIL : GL_DEPTH_COMPONENT; + config->ds_type = attribs->stencil_size ? GL_UNSIGNED_INT_24_8 : GL_UNSIGNED_INT; + } + else + { + config->ds_internalformat = config->ds_format = config->ds_type = 0; + } + config->samples = attribs->samples; +} + +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; + float prev_clear_color[4]; + unsigned int i; + struct fs_hack_fbo_attachments_config config; + struct fs_hack_fbconfig_attribs attribs; + static const struct fbconfig_attribs_query + { + int attribute; + unsigned int offset; + } + queries[] = + { + {GLX_RENDER_TYPE, offsetof(struct fs_hack_fbconfig_attribs, render_type)}, + {GLX_BUFFER_SIZE, offsetof(struct fs_hack_fbconfig_attribs, buffer_size)}, + {GLX_RED_SIZE, offsetof(struct fs_hack_fbconfig_attribs, red_size)}, + {GLX_GREEN_SIZE, offsetof(struct fs_hack_fbconfig_attribs, green_size)}, + {GLX_BLUE_SIZE, offsetof(struct fs_hack_fbconfig_attribs, blue_size)}, + {GLX_ALPHA_SIZE, offsetof(struct fs_hack_fbconfig_attribs, alpha_size)}, + {GLX_DEPTH_SIZE, offsetof(struct fs_hack_fbconfig_attribs, depth_size)}, + {GLX_STENCIL_SIZE, offsetof(struct fs_hack_fbconfig_attribs, stencil_size)}, + {GLX_DOUBLEBUFFER, offsetof(struct fs_hack_fbconfig_attribs, doublebuffer)}, + {GLX_SAMPLES_ARB, offsetof(struct fs_hack_fbconfig_attribs, samples)}, + {GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, offsetof(struct fs_hack_fbconfig_attribs, srgb)}, + }; + BYTE *ptr = (BYTE *)&attribs; + + if (ctx->fs_hack) + { + MONITORINFO info = {.cbSize = sizeof(MONITORINFO)}; + HMONITOR monitor; + int width, height; + + monitor = fs_hack_monitor_from_hwnd( NtUserWindowFromDC( ctx->hdc ) ); + NtUserGetMonitorInfo( monitor, &info ); + width = info.rcMonitor.right - info.rcMonitor.left; + height = info.rcMonitor.bottom - info.rcMonitor.top; + + TRACE( "Render buffer width:%d height:%d\n", width, height ); + + opengl_funcs.gl.p_glGetIntegerv( GL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&prev_draw_fbo ); + opengl_funcs.gl.p_glGetIntegerv( GL_READ_FRAMEBUFFER_BINDING, (GLint *)&prev_read_fbo ); + opengl_funcs.gl.p_glGetIntegerv( GL_TEXTURE_BINDING_2D, (GLint *)&prev_texture ); + opengl_funcs.gl.p_glGetIntegerv( GL_RENDERBUFFER_BINDING, (GLint *)&prev_renderbuffer ); + opengl_funcs.gl.p_glGetFloatv( GL_COLOR_CLEAR_VALUE, prev_clear_color ); + TRACE( "Previous draw FBO %u, read FBO %u for ctx %p\n", prev_draw_fbo, prev_read_fbo, ctx ); + + if (!ctx->fs_hack_fbo) + { + pglGenFramebuffers( 1, &ctx->fs_hack_fbo ); + pglGenFramebuffers( 1, &ctx->fs_hack_resolve_fbo ); + TRACE( "Created FBO %u for fullscreen hack.\n", ctx->fs_hack_fbo ); + } + pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_fbo ); + + for (i = 0; i < ARRAY_SIZE(queries); ++i) + pglXGetFBConfigAttrib( gdi_display, gl->format->fbconfig, queries[i].attribute, + (int *)&ptr[queries[i].offset] ); + fs_hack_get_attachments_config( gl, &attribs, &config ); + + if (config.samples) + { + if (!ctx->fs_hack_color_renderbuffer) + pglGenRenderbuffers( 1, &ctx->fs_hack_color_renderbuffer ); + pglBindRenderbuffer( GL_RENDERBUFFER, ctx->fs_hack_color_renderbuffer ); + pglRenderbufferStorageMultisample( GL_RENDERBUFFER, config.samples, + config.color_internalformat, width, height ); + pglFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + ctx->fs_hack_color_renderbuffer ); + TRACE( "Created renderbuffer %u for fullscreen hack.\n", ctx->fs_hack_color_renderbuffer ); + pglGenRenderbuffers( 1, &ctx->fs_hack_color_resolve_renderbuffer ); + pglBindRenderbuffer( GL_RENDERBUFFER, ctx->fs_hack_color_resolve_renderbuffer ); + pglRenderbufferStorage( GL_RENDERBUFFER, config.color_internalformat, width, height ); + pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_resolve_fbo ); + pglFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + ctx->fs_hack_color_resolve_renderbuffer ); + pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_fbo ); + pglBindRenderbuffer( GL_RENDERBUFFER, prev_renderbuffer ); + TRACE( "Also created renderbuffer %u and FBO %u for color resolve.\n", + ctx->fs_hack_color_resolve_renderbuffer, ctx->fs_hack_resolve_fbo ); + } + else + { + if (!ctx->fs_hack_color_texture) + opengl_funcs.gl.p_glGenTextures( 1, &ctx->fs_hack_color_texture ); + 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 ); + opengl_funcs.gl.p_glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0 ); + opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, prev_texture ); + pglFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + ctx->fs_hack_color_texture, 0 ); + TRACE( "Created texture %u for fullscreen hack.\n", ctx->fs_hack_color_texture ); + } + + if (config.ds_internalformat) + { + if (config.samples) + { + if (!ctx->fs_hack_ds_renderbuffer) pglGenRenderbuffers( 1, &ctx->fs_hack_ds_renderbuffer ); + pglBindRenderbuffer( GL_RENDERBUFFER, ctx->fs_hack_ds_renderbuffer ); + pglRenderbufferStorageMultisample( GL_RENDERBUFFER, config.samples, + config.ds_internalformat, width, height ); + pglBindRenderbuffer( GL_RENDERBUFFER, prev_renderbuffer ); + if (attribs.depth_size) + pglFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, ctx->fs_hack_ds_renderbuffer ); + if (attribs.stencil_size) + pglFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, ctx->fs_hack_ds_renderbuffer ); + TRACE( "Created DS renderbuffer %u for fullscreen hack.\n", ctx->fs_hack_ds_renderbuffer ); + } + else + { + if (!ctx->fs_hack_ds_texture) + opengl_funcs.gl.p_glGenTextures( 1, &ctx->fs_hack_ds_texture ); + 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 ); + opengl_funcs.gl.p_glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0 ); + opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, prev_texture ); + if (attribs.depth_size) + pglFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, ctx->fs_hack_ds_texture, 0 ); + if (attribs.stencil_size) + pglFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + GL_TEXTURE_2D, ctx->fs_hack_ds_texture, 0 ); + TRACE( "Created DS texture %u for fullscreen hack.\n", ctx->fs_hack_ds_texture ); + } + } + + opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); + if (!gl->fs_hack_context_set_up) opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT ); + pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); + pglDrawBuffer( GL_BACK ); + if (!gl->fs_hack_context_set_up) opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT ); + opengl_funcs.gl.p_glClearColor( prev_clear_color[0], prev_clear_color[1], + prev_clear_color[2], prev_clear_color[3] ); + wglBindFramebuffer( GL_DRAW_FRAMEBUFFER, prev_draw_fbo ); + wglBindFramebuffer( GL_READ_FRAMEBUFFER, prev_read_fbo ); + + ctx->setup_for.x = width; + ctx->setup_for.y = height; + gl->has_scissor_indexed = has_extension( glExtensions, "GL_ARB_viewport_array" ); + ctx->fs_hack_integer = fs_hack_is_integer(); + gl->fs_hack_context_set_up = TRUE; + } + else + { + TRACE( "Releasing fullscreen hack texture %u and FBO %u\n", ctx->fs_hack_color_texture, ctx->fs_hack_fbo ); + if (ctx->current_draw_fbo == ctx->fs_hack_fbo) + { + pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); + ctx->current_draw_fbo = 0; + } + if (ctx->current_read_fbo == ctx->fs_hack_fbo) + { + pglBindFramebuffer( GL_READ_FRAMEBUFFER, 0 ); + ctx->current_read_fbo = 0; + } + + pglDeleteRenderbuffers( 1, &ctx->fs_hack_ds_renderbuffer ); + pglDeleteRenderbuffers( 1, &ctx->fs_hack_color_resolve_renderbuffer ); + pglDeleteRenderbuffers( 1, &ctx->fs_hack_color_renderbuffer ); + opengl_funcs.gl.p_glDeleteTextures( 1, &ctx->fs_hack_ds_texture ); + opengl_funcs.gl.p_glDeleteTextures( 1, &ctx->fs_hack_color_texture ); + ctx->fs_hack_color_renderbuffer = ctx->fs_hack_color_resolve_renderbuffer = ctx->fs_hack_ds_renderbuffer = 0; + ctx->fs_hack_color_texture = ctx->fs_hack_ds_texture = 0; + pglDeleteFramebuffers( 1, &ctx->fs_hack_resolve_fbo ); + pglDeleteFramebuffers( 1, &ctx->fs_hack_fbo ); + ctx->fs_hack_fbo = 0; + + gl->fs_hack_context_set_up = FALSE; + } +} + /*********************************************************************** * glxdrv_wglMakeCurrent */ static BOOL glxdrv_wglMakeCurrent(HDC hdc, struct wgl_context *ctx) { - BOOL ret = FALSE; + BOOL ret = FALSE, setup_fs_hack = FALSE; struct gl_drawable *gl; TRACE("(%p,%p)\n", hdc, ctx); @@ -1944,10 +2266,17 @@ static BOOL glxdrv_wglMakeCurrent(HDC hdc, struct wgl_context *ctx) if (ret) { NtCurrentTeb()->glContext = ctx; - ctx->has_been_current = TRUE; + if (ctx->fs_hack != gl->fs_hack || (ctx->fs_hack && ctx->drawables[0] != gl)) + setup_fs_hack = TRUE; ctx->hdc = hdc; set_context_drawables( ctx, gl, gl ); ctx->refresh_drawables = FALSE; + if (setup_fs_hack) + { + ctx->fs_hack = gl->fs_hack; + fs_hack_setup_context( ctx, gl ); + } + ctx->has_been_current = TRUE; pthread_mutex_unlock( &context_mutex ); goto done; } @@ -1961,12 +2290,149 @@ static BOOL glxdrv_wglMakeCurrent(HDC hdc, struct wgl_context *ctx) return ret; } +static void wglBindFramebuffer( GLenum target, GLuint framebuffer ) +{ + struct wgl_context *ctx = NtCurrentTeb()->glContext; + + TRACE( "target %#x, framebuffer %u\n", target, framebuffer ); + if (ctx->fs_hack && !framebuffer) framebuffer = ctx->fs_hack_fbo; + + if (target == GL_DRAW_FRAMEBUFFER || target == GL_FRAMEBUFFER) ctx->current_draw_fbo = framebuffer; + if (target == GL_READ_FRAMEBUFFER || target == GL_FRAMEBUFFER) ctx->current_read_fbo = framebuffer; + + pglBindFramebuffer( target, framebuffer ); +} + +static void wglBindFramebufferEXT( GLenum target, GLuint framebuffer ) +{ + struct wgl_context *ctx = NtCurrentTeb()->glContext; + + TRACE( "target %#x, framebuffer %u\n", target, framebuffer ); + if (ctx->fs_hack && !framebuffer) framebuffer = ctx->fs_hack_fbo; + + if (target == GL_DRAW_FRAMEBUFFER || target == GL_FRAMEBUFFER) ctx->current_draw_fbo = framebuffer; + if (target == GL_READ_FRAMEBUFFER || target == GL_FRAMEBUFFER) ctx->current_read_fbo = framebuffer; + + pglBindFramebufferEXT( target, framebuffer ); +} + +static void wglDrawBuffer( GLenum buffer ) +{ + struct wgl_context *ctx = NtCurrentTeb()->glContext; + + if (ctx->fs_hack && ctx->current_draw_fbo == ctx->fs_hack_fbo) + { + TRACE( "Overriding %#x with GL_COLOR_ATTACHMENT0\n", buffer ); + buffer = GL_COLOR_ATTACHMENT0; + } + pglDrawBuffer( buffer ); +} + +static void wglReadBuffer( GLenum buffer ) +{ + struct wgl_context *ctx = NtCurrentTeb()->glContext; + + if (ctx->fs_hack && ctx->current_read_fbo == ctx->fs_hack_fbo) + { + TRACE( "Overriding %#x with GL_COLOR_ATTACHMENT0\n", buffer ); + buffer = GL_COLOR_ATTACHMENT0; + } + pglReadBuffer( buffer ); +} + +static void fs_hack_blit_framebuffer( struct gl_drawable *gl, GLenum draw_buffer ) +{ + struct wgl_context *ctx = NtCurrentTeb()->glContext; + SIZE scaled, src, real; + GLuint prev_draw_fbo, prev_read_fbo; + GLint prev_scissor[4]; + RECT user_rect, real_rect; + POINT scaled_origin; + float prev_clear_color[4]; + HMONITOR monitor; + + monitor = fs_hack_monitor_from_hwnd( NtUserWindowFromDC( ctx->hdc ) ); + scaled = fs_hack_get_scaled_screen_size( monitor ); + user_rect = fs_hack_current_mode( monitor ); + real_rect = fs_hack_real_mode( monitor ); + src.cx = user_rect.right - user_rect.left; + src.cy = user_rect.bottom - user_rect.top; + real.cx = real_rect.right - real_rect.left; + real.cy = real_rect.bottom - real_rect.top; + scaled_origin.x = user_rect.left; + scaled_origin.y = user_rect.top; + fs_hack_point_user_to_real( &scaled_origin ); + scaled_origin.x -= real_rect.left; + scaled_origin.y -= real_rect.top; + + TRACE( "scaled:%dx%d src:%dx%d real:%dx%d user_rect:%s real_rect:%s scaled_origin:%s\n", + (int)scaled.cx, (int)scaled.cy, (int)src.cx, (int)src.cy, (int)real.cx, (int)real.cy, + wine_dbgstr_rect( &user_rect ), wine_dbgstr_rect( &real_rect ), wine_dbgstr_point( &scaled_origin ) ); + + if (ctx->setup_for.x != src.cx || ctx->setup_for.y != src.cy) fs_hack_setup_context( ctx, gl ); + + TRACE( "Blitting from FBO %u %ux%u to %ux%u\n", ctx->fs_hack_fbo, + (int)src.cx, (int)src.cy, (int)scaled.cx, (int)scaled.cy ); + + opengl_funcs.gl.p_glGetIntegerv( GL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&prev_draw_fbo ); + opengl_funcs.gl.p_glGetIntegerv( GL_READ_FRAMEBUFFER_BINDING, (GLint *)&prev_read_fbo ); + TRACE( "Previous draw FBO %u, read FBO %u\n", prev_draw_fbo, prev_read_fbo ); + + if (gl->has_scissor_indexed) + { + opengl_funcs.ext.p_glGetIntegeri_v( GL_SCISSOR_BOX, 0, prev_scissor ); + opengl_funcs.ext.p_glScissorIndexed( 0, 0, 0, real.cx, real.cy ); + } + else + { + opengl_funcs.gl.p_glGetIntegerv( GL_SCISSOR_BOX, prev_scissor ); + opengl_funcs.gl.p_glScissor( 0, 0, real.cx, real.cy ); + } + + pglBindFramebuffer( GL_READ_FRAMEBUFFER, ctx->fs_hack_fbo ); + if (ctx->fs_hack_color_resolve_renderbuffer) + { + pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_resolve_fbo ); + pglBlitFramebuffer( 0, 0, src.cx, src.cy, 0, 0, src.cx, src.cy, GL_COLOR_BUFFER_BIT, GL_NEAREST ); + pglBindFramebuffer( GL_READ_FRAMEBUFFER, ctx->fs_hack_resolve_fbo ); + } + pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); + + // HACK + // pglDrawBuffer( draw_buffer ); + pglDrawBuffer( GL_BACK ); + + opengl_funcs.gl.p_glGetFloatv( GL_COLOR_CLEAR_VALUE, prev_clear_color ); + opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); + opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT ); + opengl_funcs.gl.p_glClearColor( prev_clear_color[0], prev_clear_color[1], prev_clear_color[2], + prev_clear_color[3] ); + + pglBlitFramebuffer( 0, 0, src.cx, src.cy, scaled_origin.x, scaled_origin.y, + scaled_origin.x + scaled.cx, scaled_origin.y + scaled.cy, + GL_COLOR_BUFFER_BIT, ctx->fs_hack_integer ? GL_NEAREST : GL_LINEAR ); + // HACK + if (draw_buffer == GL_FRONT) pglXSwapBuffers( gdi_display, gl->drawable ); + + if (gl->has_scissor_indexed) + { + opengl_funcs.ext.p_glScissorIndexedv( 0, prev_scissor ); + } + else + { + opengl_funcs.gl.p_glScissor( prev_scissor[0], prev_scissor[1], prev_scissor[2], prev_scissor[3] ); + } + + pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, prev_draw_fbo ); + pglBindFramebuffer( GL_READ_FRAMEBUFFER, prev_read_fbo ); +} + /*********************************************************************** * X11DRV_wglMakeContextCurrentARB */ static BOOL X11DRV_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, struct wgl_context *ctx ) { - BOOL ret = FALSE; + BOOL ret = FALSE, setup_fs_hack = FALSE; struct gl_drawable *draw_gl, *read_gl = NULL; TRACE("(%p,%p,%p)\n", draw_hdc, read_hdc, ctx); @@ -1989,11 +2455,18 @@ static BOOL X11DRV_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, struct read_gl ? read_gl->drawable : 0, ctx->ctx); if (ret) { - ctx->has_been_current = TRUE; + NtCurrentTeb()->glContext = ctx; + if (ctx->fs_hack != draw_gl->fs_hack || (ctx->fs_hack && ctx->drawables[0] != draw_gl)) + setup_fs_hack = TRUE; ctx->hdc = draw_hdc; set_context_drawables( ctx, draw_gl, read_gl ); ctx->refresh_drawables = FALSE; - NtCurrentTeb()->glContext = ctx; + if (setup_fs_hack) + { + ctx->fs_hack = draw_gl->fs_hack; + fs_hack_setup_context( ctx, draw_gl ); + } + ctx->has_been_current = TRUE; pthread_mutex_unlock( &context_mutex ); goto done; } @@ -2143,6 +2616,19 @@ static void wglFinish(void) default: break; } sync_context(ctx); + + if (gl->fs_hack) + { + ctx->fs_hack = gl->fs_hack; + if (!gl->fs_hack_context_set_up) fs_hack_setup_context( ctx, gl ); + if (!gl->fs_hack_did_swapbuf) fs_hack_blit_framebuffer( gl, GL_FRONT ); + } + else if (gl->fs_hack_context_set_up) + { + ctx->fs_hack = FALSE; + fs_hack_setup_context( ctx, gl ); + } + update_window_surface( gl, hwnd ); release_gl_drawable( gl ); } @@ -2171,6 +2657,19 @@ static void wglFlush(void) default: break; } sync_context(ctx); + + if (gl->fs_hack) + { + ctx->fs_hack = gl->fs_hack; + if (!gl->fs_hack_context_set_up) fs_hack_setup_context( ctx, gl ); + if (!gl->fs_hack_did_swapbuf) fs_hack_blit_framebuffer( gl, GL_FRONT ); + } + else if (gl->fs_hack_context_set_up) + { + ctx->fs_hack = FALSE; + fs_hack_setup_context( ctx, gl ); + } + update_window_surface( gl, hwnd ); release_gl_drawable( gl ); } @@ -3571,6 +4070,18 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) target_sbc = pglXSwapBuffersMscOML( gdi_display, gl->drawable, 0, 0, 0 ); break; } + if (gl->fs_hack) + { + ctx->fs_hack = gl->fs_hack; + if (!gl->fs_hack_context_set_up) fs_hack_setup_context( ctx, gl ); + fs_hack_blit_framebuffer( gl, GL_BACK ); + gl->fs_hack_did_swapbuf = TRUE; + } + else if (gl->fs_hack_context_set_up) + { + ctx->fs_hack = FALSE; + fs_hack_setup_context( ctx, gl ); + } pglXSwapBuffers(gdi_display, gl->drawable); break; } From ac1f4bddc040df62b4b78717b351ca9ab4893232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:32:39 +0100 Subject: [PATCH 0675/2777] fshack: winex11: Protect fshack framebuffer from glFramebufferTexture2D(). glFramebufferTexture2D() just fails with default framebuffer. But when we have substitued fshack framebuffer setting the texture destroys it instead. CW-Bug-Id: #20669 --- dlls/winex11.drv/opengl.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 4888e57de56..29a550bbd84 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -439,6 +439,7 @@ static void wglBindFramebuffer( GLenum target, GLuint framebuffer ); static void wglBindFramebufferEXT( GLenum target, GLuint framebuffer ); static void wglDrawBuffer( GLenum buffer ); static void wglReadBuffer( GLenum src ); +static void wglFramebufferTexture2D( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ); /* check if the extension is present in the list */ static BOOL has_extension( const char *list, const char *ext ) @@ -1982,6 +1983,7 @@ static PROC glxdrv_wglGetProcAddress(LPCSTR lpszProc) if (!strncmp(lpszProc, "wgl", 3)) return NULL; if (!strcmp( lpszProc, "glBindFramebuffer" )) return (PROC)(void *)wglBindFramebuffer; if (!strcmp( lpszProc, "glBindFramebufferEXT" )) return (PROC)(void *)wglBindFramebufferEXT; + if (!strcmp( lpszProc, "glFramebufferTexture2D" )) return (PROC)(void *)wglFramebufferTexture2D; return pglXGetProcAddressARB((const GLubyte*)lpszProc); } @@ -2290,6 +2292,30 @@ static BOOL glxdrv_wglMakeCurrent(HDC hdc, struct wgl_context *ctx) return ret; } +static void wglFramebufferTexture2D( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ) +{ + struct wgl_context *ctx = NtCurrentTeb()->glContext; + + TRACE( "target %#x, attachment %#x, textarget %#x, texture %u, level %u.\n", target, attachment, + textarget, texture, level ); + + if (ctx->fs_hack) + { + /* glFramebufferTexture2D should fail for default framebuffer 0. + * Let it fail and relay appropriate error instead of breaking fs_hack FBO. */ + if (ctx->current_read_fbo == ctx->fs_hack_fbo) pglBindFramebuffer( GL_READ_FRAMEBUFFER, 0 ); + if (ctx->current_draw_fbo == ctx->fs_hack_fbo) pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); + } + pglFramebufferTexture2D( target, attachment, textarget, texture, level ); + if (ctx->fs_hack) + { + if (ctx->current_read_fbo == ctx->fs_hack_fbo) + pglBindFramebuffer( GL_READ_FRAMEBUFFER, ctx->fs_hack_fbo ); + if (ctx->current_draw_fbo == ctx->fs_hack_fbo) + pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_fbo ); + } +} + static void wglBindFramebuffer( GLenum target, GLuint framebuffer ) { struct wgl_context *ctx = NtCurrentTeb()->glContext; From e0f66e15450df6b26854f6d28b62d46b1fab46eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:10:52 +0100 Subject: [PATCH 0676/2777] fshack: winevulkan: Hook and wrap swapchain objects. --- dlls/winevulkan/loader.c | 40 +++++++++++++++++++++++++ dlls/winevulkan/make_vulkan | 6 ++-- dlls/winevulkan/vulkan.c | 50 ++++++++++++++++++++++++++++++++ dlls/winevulkan/vulkan_loader.h | 10 +++++++ dlls/winevulkan/vulkan_private.h | 13 +++++++++ 5 files changed, 117 insertions(+), 2 deletions(-) diff --git a/dlls/winevulkan/loader.c b/dlls/winevulkan/loader.c index e3fc5738e00..97f079b54a8 100644 --- a/dlls/winevulkan/loader.c +++ b/dlls/winevulkan/loader.c @@ -658,6 +658,46 @@ void WINAPI vkFreeCommandBuffers(VkDevice device, VkCommandPool cmd_pool, uint32 } } +VkResult WINAPI vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain) +{ + struct vkCreateSwapchainKHR_params params; + struct vk_swapchain *swapchain; + NTSTATUS status; + + if (!(swapchain = malloc(sizeof(*swapchain)))) + return VK_ERROR_OUT_OF_HOST_MEMORY; + swapchain->unix_handle = 0; + + params.device = device; + params.pCreateInfo = pCreateInfo; + params.pAllocator = pAllocator; + params.pSwapchain = pSwapchain; + params.client_ptr = swapchain; + status = UNIX_CALL(vkCreateSwapchainKHR, ¶ms); + assert(!status); + if (!swapchain->unix_handle) + free(swapchain); + return params.result; +} + +void WINAPI vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR handle, const VkAllocationCallbacks *pAllocator) +{ + struct vk_swapchain *swapchain = swapchain_from_handle(handle); + struct vkDestroySwapchainKHR_params params; + NTSTATUS status; + + if (!swapchain) + return; + + params.device = device; + params.swapchain = handle; + params.pAllocator = pAllocator; + status = UNIX_CALL(vkDestroySwapchainKHR, ¶ms); + assert(!status); + free(swapchain); +} + static BOOL WINAPI call_vulkan_debug_report_callback( struct wine_vk_debug_report_params *params, ULONG size ) { return params->user_callback(params->flags, params->object_type, params->object_handle, params->location, diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index d38d5564fb9..b07f4939da4 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -235,8 +235,8 @@ FUNCTION_OVERRIDES = { "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, # VK_KHR_swapchain - "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, - "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, + "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE, "extra_param" : "client_ptr"}, + "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE}, "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, @@ -1085,6 +1085,8 @@ class VkHandle(object): def native_handle(self, name): """ Provide access to the native handle of a wrapped object. """ + if self.name == "VkSwapchainKHR": + return "wine_swapchain_from_handle({0})->swapchain".format(name) if self.name == "VkCommandBuffer": return "wine_cmd_buffer_from_handle({0})->command_buffer".format(name) if self.name == "VkCommandPool": diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 2a3fdc6cfcd..01ff1100a5d 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -1536,6 +1536,42 @@ void wine_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(VkPhysicalDevice phy properties->externalSemaphoreFeatures = 0; } +VkResult wine_vkCreateSwapchainKHR(VkDevice device_handle, const VkSwapchainCreateInfoKHR *info, const VkAllocationCallbacks *allocator, + VkSwapchainKHR *swapchain, void *client_ptr) +{ + struct wine_device *device = wine_device_from_handle(device_handle); + VkSwapchainCreateInfoKHR create_info_host = *info; + struct vk_swapchain *handle = client_ptr; + struct wine_swapchain *object; + VkResult res; + + if (!(object = calloc(1, sizeof(*object)))) + { + ERR("Failed to allocate memory for swapchain\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + if (create_info_host.surface) + create_info_host.surface = wine_surface_from_handle(create_info_host.surface)->driver_surface; + if (create_info_host.oldSwapchain) + create_info_host.oldSwapchain = wine_swapchain_from_handle(create_info_host.oldSwapchain)->swapchain; + + res = device->funcs.p_vkCreateSwapchainKHR(device->device, &create_info_host, NULL, &object->swapchain); + + if (res != VK_SUCCESS) + { + free(object); + return res; + } + + object->handle = (uintptr_t)handle; + handle->unix_handle = (uintptr_t)object; + WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance, object->handle, object->swapchain, object); + *swapchain = object->handle; + + return res; +} + VkResult wine_vkCreateWin32SurfaceKHR(VkInstance handle, const VkWin32SurfaceCreateInfoKHR *createInfo, const VkAllocationCallbacks *allocator, VkSurfaceKHR *surface) { @@ -1938,6 +1974,20 @@ void wine_vkDestroyDebugReportCallbackEXT(VkInstance handle, VkDebugReportCallba free(object); } +void wine_vkDestroySwapchainKHR(VkDevice device_handle, VkSwapchainKHR handle, const VkAllocationCallbacks *allocator) +{ + struct wine_device *device = wine_device_from_handle(device_handle); + struct wine_swapchain *swapchain = wine_swapchain_from_handle(handle); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, swapchain); + + device->funcs.p_vkDestroySwapchainKHR(device->device, swapchain->swapchain, NULL); + free(swapchain); +} + #ifdef _WIN64 NTSTATUS vk_is_available_instance_function(void *arg) diff --git a/dlls/winevulkan/vulkan_loader.h b/dlls/winevulkan/vulkan_loader.h index 24be960e4c3..311e2ef8f1b 100644 --- a/dlls/winevulkan/vulkan_loader.h +++ b/dlls/winevulkan/vulkan_loader.h @@ -83,6 +83,16 @@ struct VkDevice_T struct VkQueue_T queues[1]; }; +struct vk_swapchain +{ + UINT64 unix_handle; +}; + +static inline struct vk_swapchain *swapchain_from_handle(VkSwapchainKHR handle) +{ + return (struct vk_swapchain *)(uintptr_t)handle; +} + struct vk_command_pool { UINT64 unix_handle; diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 60e21114940..9fc73445247 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -72,6 +72,19 @@ static inline struct wine_device *wine_device_from_handle(VkDevice handle) return (struct wine_device *)(uintptr_t)handle->base.unix_handle; } +struct wine_swapchain +{ + VkSwapchainKHR handle; + VkSwapchainKHR swapchain; /* native swapchain */ + struct wine_vk_mapping mapping; +}; + +static inline struct wine_swapchain *wine_swapchain_from_handle(VkSwapchainKHR handle) +{ + struct vk_swapchain *client_ptr = swapchain_from_handle(handle); + return (struct wine_swapchain *)(uintptr_t)client_ptr->unix_handle; +} + struct wine_debug_utils_messenger; struct wine_debug_report_callback From 2c90134977f523921484e035fab2321a8a50e00a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:10:52 +0100 Subject: [PATCH 0677/2777] fshack: winevulkan: Support vulkan scaling according to fake resolution. Includes work by Georg Lehmann, Zhiyi Zhang, Brendan Shanks, and Joshua Ashton. --- dlls/winevulkan/make_vulkan | 10 +- dlls/winevulkan/vulkan.c | 1225 ++++++++++++++++++++++++++++++ dlls/winevulkan/vulkan_private.h | 32 + 3 files changed, 1265 insertions(+), 2 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index b07f4939da4..da0523e30ce 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -237,8 +237,8 @@ FUNCTION_OVERRIDES = { # VK_KHR_swapchain "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE, "extra_param" : "client_ptr"}, "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE}, - "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, - "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, + "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE}, + "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE}, "vkAcquireNextImageKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, "vkAcquireNextImage2KHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, @@ -3099,6 +3099,12 @@ class VkGenerator(object): f.write("\n") f.write(" /* winevulkan specific functions */\n") f.write(" VkSurfaceKHR (*p_wine_get_native_surface)(VkSurfaceKHR);\n") + f.write(" /* Optional. Returns TRUE if FS hack is active, otherwise returns FALSE. If\n") + f.write(" * it returns TRUE, then real_sz will contain the actual display\n") + f.write(" * resolution; user_sz will contain the app's requested mode; and dst_blit\n") + f.write(" * will contain the area to blit the user image to in real coordinates.\n") + f.write(" * All parameters are optional. */\n") + f.write(" VkBool32 (*query_fs_hack)(VkSurfaceKHR surface, VkExtent2D *real_sz, VkExtent2D *user_sz, VkRect2D *dst_blit, VkFilter *filter);\n") f.write("};\n\n") f.write("extern const struct vulkan_funcs * __wine_get_vulkan_driver(UINT version);\n\n") diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 01ff1100a5d..aebb0c7f62c 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -22,6 +22,7 @@ #endif #include "config.h" +#include #include #include "vulkan_private.h" @@ -1536,6 +1537,610 @@ void wine_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(VkPhysicalDevice phy properties->externalSemaphoreFeatures = 0; } +/* +#version 450 + +layout(binding = 0) uniform sampler2D texSampler; +layout(binding = 1, rgba8) uniform writeonly image2D outImage; +layout(push_constant) uniform pushConstants { + //both in real image coords + vec2 offset; + vec2 extents; +} constants; + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +void main() +{ + vec2 texcoord = (vec2(gl_GlobalInvocationID.xy) - constants.offset) / constants.extents; + vec4 c = texture(texSampler, texcoord); + imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), c.bgra); +} +*/ +const uint32_t blit_comp_spv[] = { + 0x07230203,0x00010000,0x00080006,0x00000037,0x00000000,0x00020011,0x00000001,0x0006000b, + 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, + 0x0006000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x0000000d,0x00060010,0x00000004, + 0x00000011,0x00000008,0x00000008,0x00000001,0x00030003,0x00000002,0x000001c2,0x00040005, + 0x00000004,0x6e69616d,0x00000000,0x00050005,0x00000009,0x63786574,0x64726f6f,0x00000000, + 0x00080005,0x0000000d,0x475f6c67,0x61626f6c,0x766e496c,0x7461636f,0x496e6f69,0x00000044, + 0x00060005,0x00000012,0x68737570,0x736e6f43,0x746e6174,0x00000073,0x00050006,0x00000012, + 0x00000000,0x7366666f,0x00007465,0x00050006,0x00000012,0x00000001,0x65747865,0x0073746e, + 0x00050005,0x00000014,0x736e6f63,0x746e6174,0x00000073,0x00030005,0x00000021,0x00000063, + 0x00050005,0x00000025,0x53786574,0x6c706d61,0x00007265,0x00050005,0x0000002c,0x4974756f, + 0x6567616d,0x00000000,0x00040047,0x0000000d,0x0000000b,0x0000001c,0x00050048,0x00000012, + 0x00000000,0x00000023,0x00000000,0x00050048,0x00000012,0x00000001,0x00000023,0x00000008, + 0x00030047,0x00000012,0x00000002,0x00040047,0x00000025,0x00000022,0x00000000,0x00040047, + 0x00000025,0x00000021,0x00000000,0x00040047,0x0000002c,0x00000022,0x00000000,0x00040047, + 0x0000002c,0x00000021,0x00000001,0x00030047,0x0000002c,0x00000019,0x00040047,0x00000036, + 0x0000000b,0x00000019,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016, + 0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000002,0x00040020,0x00000008, + 0x00000007,0x00000007,0x00040015,0x0000000a,0x00000020,0x00000000,0x00040017,0x0000000b, + 0x0000000a,0x00000003,0x00040020,0x0000000c,0x00000001,0x0000000b,0x0004003b,0x0000000c, + 0x0000000d,0x00000001,0x00040017,0x0000000e,0x0000000a,0x00000002,0x0004001e,0x00000012, + 0x00000007,0x00000007,0x00040020,0x00000013,0x00000009,0x00000012,0x0004003b,0x00000013, + 0x00000014,0x00000009,0x00040015,0x00000015,0x00000020,0x00000001,0x0004002b,0x00000015, + 0x00000016,0x00000000,0x00040020,0x00000017,0x00000009,0x00000007,0x0004002b,0x00000015, + 0x0000001b,0x00000001,0x00040017,0x0000001f,0x00000006,0x00000004,0x00040020,0x00000020, + 0x00000007,0x0000001f,0x00090019,0x00000022,0x00000006,0x00000001,0x00000000,0x00000000, + 0x00000000,0x00000001,0x00000000,0x0003001b,0x00000023,0x00000022,0x00040020,0x00000024, + 0x00000000,0x00000023,0x0004003b,0x00000024,0x00000025,0x00000000,0x0004002b,0x00000006, + 0x00000028,0x00000000,0x00090019,0x0000002a,0x00000006,0x00000001,0x00000000,0x00000000, + 0x00000000,0x00000002,0x00000004,0x00040020,0x0000002b,0x00000000,0x0000002a,0x0004003b, + 0x0000002b,0x0000002c,0x00000000,0x00040017,0x00000030,0x00000015,0x00000002,0x0004002b, + 0x0000000a,0x00000034,0x00000008,0x0004002b,0x0000000a,0x00000035,0x00000001,0x0006002c, + 0x0000000b,0x00000036,0x00000034,0x00000034,0x00000035,0x00050036,0x00000002,0x00000004, + 0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008,0x00000009,0x00000007, + 0x0004003b,0x00000020,0x00000021,0x00000007,0x0004003d,0x0000000b,0x0000000f,0x0000000d, + 0x0007004f,0x0000000e,0x00000010,0x0000000f,0x0000000f,0x00000000,0x00000001,0x00040070, + 0x00000007,0x00000011,0x00000010,0x00050041,0x00000017,0x00000018,0x00000014,0x00000016, + 0x0004003d,0x00000007,0x00000019,0x00000018,0x00050083,0x00000007,0x0000001a,0x00000011, + 0x00000019,0x00050041,0x00000017,0x0000001c,0x00000014,0x0000001b,0x0004003d,0x00000007, + 0x0000001d,0x0000001c,0x00050088,0x00000007,0x0000001e,0x0000001a,0x0000001d,0x0003003e, + 0x00000009,0x0000001e,0x0004003d,0x00000023,0x00000026,0x00000025,0x0004003d,0x00000007, + 0x00000027,0x00000009,0x00070058,0x0000001f,0x00000029,0x00000026,0x00000027,0x00000002, + 0x00000028,0x0003003e,0x00000021,0x00000029,0x0004003d,0x0000002a,0x0000002d,0x0000002c, + 0x0004003d,0x0000000b,0x0000002e,0x0000000d,0x0007004f,0x0000000e,0x0000002f,0x0000002e, + 0x0000002e,0x00000000,0x00000001,0x0004007c,0x00000030,0x00000031,0x0000002f,0x0004003d, + 0x0000001f,0x00000032,0x00000021,0x0009004f,0x0000001f,0x00000033,0x00000032,0x00000032, + 0x00000002,0x00000001,0x00000000,0x00000003,0x00040063,0x0000002d,0x00000031,0x00000033, + 0x000100fd,0x00010038 +}; + +static VkResult create_pipeline(struct wine_device *device, struct wine_swapchain *swapchain, VkShaderModule shaderModule) +{ + VkComputePipelineCreateInfo pipelineInfo = {0}; + VkResult res; + + pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + pipelineInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + pipelineInfo.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; + pipelineInfo.stage.module = shaderModule; + pipelineInfo.stage.pName = "main"; + pipelineInfo.layout = swapchain->pipeline_layout; + pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; + pipelineInfo.basePipelineIndex = -1; + + res = device->funcs.p_vkCreateComputePipelines(device->device, VK_NULL_HANDLE, 1, &pipelineInfo, + NULL, &swapchain->pipeline); + if (res != VK_SUCCESS) + { + ERR("vkCreateComputePipelines: %d\n", res); + return res; + } + + return VK_SUCCESS; +} + +static VkResult create_descriptor_set(struct wine_device *device, struct wine_swapchain *swapchain, + struct fs_hack_image *hack) +{ + VkDescriptorImageInfo userDescriptorImageInfo = {0}, realDescriptorImageInfo = {0}; + VkDescriptorSetAllocateInfo descriptorAllocInfo = {0}; + VkWriteDescriptorSet descriptorWrites[2] = {{0}, {0}}; + VkResult res; + + descriptorAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descriptorAllocInfo.descriptorPool = swapchain->descriptor_pool; + descriptorAllocInfo.descriptorSetCount = 1; + descriptorAllocInfo.pSetLayouts = &swapchain->descriptor_set_layout; + + res = device->funcs.p_vkAllocateDescriptorSets(device->device, &descriptorAllocInfo, &hack->descriptor_set); + if (res != VK_SUCCESS) + { + ERR("vkAllocateDescriptorSets: %d\n", res); + return res; + } + + userDescriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + userDescriptorImageInfo.imageView = hack->user_view; + userDescriptorImageInfo.sampler = swapchain->sampler; + + realDescriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + realDescriptorImageInfo.imageView = hack->blit_view; + + descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrites[0].dstSet = hack->descriptor_set; + descriptorWrites[0].dstBinding = 0; + descriptorWrites[0].dstArrayElement = 0; + descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorWrites[0].descriptorCount = 1; + descriptorWrites[0].pImageInfo = &userDescriptorImageInfo; + + descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrites[1].dstSet = hack->descriptor_set; + descriptorWrites[1].dstBinding = 1; + descriptorWrites[1].dstArrayElement = 0; + descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + descriptorWrites[1].descriptorCount = 1; + descriptorWrites[1].pImageInfo = &realDescriptorImageInfo; + + device->funcs.p_vkUpdateDescriptorSets(device->device, 2, descriptorWrites, 0, NULL); + + return VK_SUCCESS; +} + +static VkResult init_blit_images(struct wine_device *device, struct wine_swapchain *swapchain) +{ + VkResult res; + VkSamplerCreateInfo samplerInfo = {0}; + VkDescriptorPoolSize poolSizes[2] = {{0}, {0}}; + VkDescriptorPoolCreateInfo poolInfo = {0}; + VkDescriptorSetLayoutBinding layoutBindings[2] = {{0}, {0}}; + VkDescriptorSetLayoutCreateInfo descriptorLayoutInfo = {0}; + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {0}; + VkPushConstantRange pushConstants; + VkShaderModuleCreateInfo shaderInfo = {0}; + VkShaderModule shaderModule = 0; + VkDeviceSize blitMemTotal = 0, offs; + VkImageCreateInfo imageInfo = {0}; + VkMemoryRequirements blitMemReq; + VkMemoryAllocateInfo allocInfo = {0}; + VkPhysicalDeviceMemoryProperties memProperties; + VkImageViewCreateInfo viewInfo = {0}; + uint32_t blit_memory_type = -1, i; + + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = swapchain->fs_hack_filter; + samplerInfo.minFilter = swapchain->fs_hack_filter; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + samplerInfo.anisotropyEnable = VK_FALSE; + samplerInfo.maxAnisotropy = 1; + samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + samplerInfo.unnormalizedCoordinates = VK_FALSE; + samplerInfo.compareEnable = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.mipLodBias = 0.0f; + samplerInfo.minLod = 0.0f; + samplerInfo.maxLod = 0.0f; + + res = device->funcs.p_vkCreateSampler(device->device, &samplerInfo, NULL, &swapchain->sampler); + if (res != VK_SUCCESS) + { + WARN("vkCreateSampler failed, res=%d\n", res); + return res; + } + + poolSizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + poolSizes[0].descriptorCount = swapchain->n_images; + poolSizes[1].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + poolSizes[1].descriptorCount = swapchain->n_images; + + poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + poolInfo.poolSizeCount = 2; + poolInfo.pPoolSizes = poolSizes; + poolInfo.maxSets = swapchain->n_images; + + res = device->funcs.p_vkCreateDescriptorPool(device->device, &poolInfo, NULL, &swapchain->descriptor_pool); + if (res != VK_SUCCESS) + { + ERR("vkCreateDescriptorPool: %d\n", res); + goto fail; + } + + layoutBindings[0].binding = 0; + layoutBindings[0].descriptorCount = 1; + layoutBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + layoutBindings[0].pImmutableSamplers = NULL; + layoutBindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + + layoutBindings[1].binding = 1; + layoutBindings[1].descriptorCount = 1; + layoutBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + layoutBindings[1].pImmutableSamplers = NULL; + layoutBindings[1].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + + descriptorLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorLayoutInfo.bindingCount = 2; + descriptorLayoutInfo.pBindings = layoutBindings; + + res = device->funcs.p_vkCreateDescriptorSetLayout(device->device, &descriptorLayoutInfo, NULL, + &swapchain->descriptor_set_layout); + if (res != VK_SUCCESS) + { + ERR("vkCreateDescriptorSetLayout: %d\n", res); + goto fail; + } + + pushConstants.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + pushConstants.offset = 0; + pushConstants.size = 4 * sizeof(float); /* 2 * vec2 */ + + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.setLayoutCount = 1; + pipelineLayoutInfo.pSetLayouts = &swapchain->descriptor_set_layout; + pipelineLayoutInfo.pushConstantRangeCount = 1; + pipelineLayoutInfo.pPushConstantRanges = &pushConstants; + + res = device->funcs.p_vkCreatePipelineLayout(device->device, &pipelineLayoutInfo, NULL, + &swapchain->pipeline_layout); + if (res != VK_SUCCESS) + { + ERR("vkCreatePipelineLayout: %d\n", res); + goto fail; + } + + shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + shaderInfo.codeSize = sizeof(blit_comp_spv); + shaderInfo.pCode = blit_comp_spv; + + res = device->funcs.p_vkCreateShaderModule(device->device, &shaderInfo, NULL, &shaderModule); + if (res != VK_SUCCESS) + { + ERR("vkCreateShaderModule: %d\n", res); + goto fail; + } + + res = create_pipeline(device, swapchain, shaderModule); + if (res != VK_SUCCESS) + goto fail; + + device->funcs.p_vkDestroyShaderModule(device->device, shaderModule, NULL); + + if (!(swapchain->surface_usage & VK_IMAGE_USAGE_STORAGE_BIT)) + { + TRACE("using intermediate blit images\n"); + /* create intermediate blit images */ + for (i = 0; i < swapchain->n_images; ++i) + { + struct fs_hack_image *hack = &swapchain->fs_hack_images[i]; + + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.extent.width = swapchain->real_extent.width; + imageInfo.extent.height = swapchain->real_extent.height; + imageInfo.extent.depth = 1; + imageInfo.mipLevels = 1; + imageInfo.arrayLayers = 1; + imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM; + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + res = device->funcs.p_vkCreateImage(device->device, &imageInfo, NULL, &hack->blit_image); + if (res != VK_SUCCESS) + { + ERR("vkCreateImage failed: %d\n", res); + goto fail; + } + + device->funcs.p_vkGetImageMemoryRequirements(device->device, hack->blit_image, &blitMemReq); + + offs = blitMemTotal % blitMemReq.alignment; + if (offs) + blitMemTotal += blitMemReq.alignment - offs; + + blitMemTotal += blitMemReq.size; + } + + /* allocate backing memory */ + device->phys_dev->instance->funcs.p_vkGetPhysicalDeviceMemoryProperties(device->phys_dev->phys_dev, &memProperties); + + for (i = 0; i < memProperties.memoryTypeCount; i++) + { + UINT flag = memProperties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + if (flag == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) + { + if (blitMemReq.memoryTypeBits & (1 << i)) + { + blit_memory_type = i; + break; + } + } + } + + if (blit_memory_type == -1) + { + ERR("unable to find suitable memory type\n"); + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = blitMemTotal; + allocInfo.memoryTypeIndex = blit_memory_type; + + res = device->funcs.p_vkAllocateMemory(device->device, &allocInfo, NULL, &swapchain->blit_image_memory); + if (res != VK_SUCCESS) + { + ERR("vkAllocateMemory: %d\n", res); + goto fail; + } + + /* bind backing memory and create imageviews */ + blitMemTotal = 0; + for (i = 0; i < swapchain->n_images; ++i) + { + struct fs_hack_image *hack = &swapchain->fs_hack_images[i]; + + device->funcs.p_vkGetImageMemoryRequirements(device->device, hack->blit_image, &blitMemReq); + + offs = blitMemTotal % blitMemReq.alignment; + if (offs) + blitMemTotal += blitMemReq.alignment - offs; + + res = device->funcs.p_vkBindImageMemory(device->device, hack->blit_image, + swapchain->blit_image_memory, blitMemTotal); + if (res != VK_SUCCESS) + { + ERR("vkBindImageMemory: %d\n", res); + goto fail; + } + + blitMemTotal += blitMemReq.size; + } + } + else + TRACE("blitting directly to swapchain images\n"); + + /* create imageviews */ + for (i = 0; i < swapchain->n_images; ++i) + { + struct fs_hack_image *hack = &swapchain->fs_hack_images[i]; + + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = hack->blit_image ? hack->blit_image : hack->swapchain_image; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = VK_FORMAT_R8G8B8A8_UNORM; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = 1; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = 1; + + res = device->funcs.p_vkCreateImageView(device->device, &viewInfo, NULL, &hack->blit_view); + if (res != VK_SUCCESS) + { + ERR("vkCreateImageView(blit): %d\n", res); + goto fail; + } + + res = create_descriptor_set(device, swapchain, hack); + if (res != VK_SUCCESS) + goto fail; + } + + return VK_SUCCESS; + +fail: + for (i = 0; i < swapchain->n_images; ++i) + { + struct fs_hack_image *hack = &swapchain->fs_hack_images[i]; + + device->funcs.p_vkDestroyImageView(device->device, hack->blit_view, NULL); + hack->blit_view = VK_NULL_HANDLE; + + device->funcs.p_vkDestroyImage(device->device, hack->blit_image, NULL); + hack->blit_image = VK_NULL_HANDLE; + } + + device->funcs.p_vkDestroyShaderModule(device->device, shaderModule, NULL); + + device->funcs.p_vkDestroyPipeline(device->device, swapchain->pipeline, NULL); + swapchain->pipeline = VK_NULL_HANDLE; + + device->funcs.p_vkDestroyPipelineLayout(device->device, swapchain->pipeline_layout, NULL); + swapchain->pipeline_layout = VK_NULL_HANDLE; + + device->funcs.p_vkDestroyDescriptorSetLayout(device->device, swapchain->descriptor_set_layout, NULL); + swapchain->descriptor_set_layout = VK_NULL_HANDLE; + + device->funcs.p_vkDestroyDescriptorPool(device->device, swapchain->descriptor_pool, NULL); + swapchain->descriptor_pool = VK_NULL_HANDLE; + + device->funcs.p_vkFreeMemory(device->device, swapchain->blit_image_memory, NULL); + swapchain->blit_image_memory = VK_NULL_HANDLE; + + device->funcs.p_vkDestroySampler(device->device, swapchain->sampler, NULL); + swapchain->sampler = VK_NULL_HANDLE; + + return res; +} + +static void destroy_fs_hack_image(struct wine_device *device, struct wine_swapchain *swapchain, + struct fs_hack_image *hack) +{ + device->funcs.p_vkDestroyImageView(device->device, hack->user_view, NULL); + device->funcs.p_vkDestroyImageView(device->device, hack->blit_view, NULL); + device->funcs.p_vkDestroyImage(device->device, hack->user_image, NULL); + device->funcs.p_vkDestroyImage(device->device, hack->blit_image, NULL); + if (hack->cmd) + device->funcs.p_vkFreeCommandBuffers(device->device, swapchain->cmd_pools[hack->cmd_queue_idx], + 1, &hack->cmd); + device->funcs.p_vkDestroySemaphore(device->device, hack->blit_finished, NULL); +} + +static VkResult init_fs_hack_images(struct wine_device *device, struct wine_swapchain *swapchain, + VkSwapchainCreateInfoKHR *createinfo) +{ + VkResult res; + VkImage *real_images = NULL; + VkDeviceSize userMemTotal = 0, offs; + VkImageCreateInfo imageInfo = {0}; + VkSemaphoreCreateInfo semaphoreInfo = {0}; + VkMemoryRequirements userMemReq; + VkMemoryAllocateInfo allocInfo = {0}; + VkPhysicalDeviceMemoryProperties memProperties; + VkImageViewCreateInfo viewInfo = {0}; + uint32_t count, i = 0, user_memory_type = -1; + + res = device->funcs.p_vkGetSwapchainImagesKHR(device->device, swapchain->swapchain, &count, NULL); + if (res != VK_SUCCESS) + { + WARN("vkGetSwapchainImagesKHR failed, res=%d\n", res); + return res; + } + + real_images = malloc(count * sizeof(VkImage)); + swapchain->cmd_pools = calloc(device->queue_count, sizeof(VkCommandPool)); + swapchain->fs_hack_images = calloc(count, sizeof(struct fs_hack_image)); + if (!real_images || !swapchain->cmd_pools || !swapchain->fs_hack_images) + goto fail; + + res = device->funcs.p_vkGetSwapchainImagesKHR(device->device, swapchain->swapchain, &count, real_images); + if (res != VK_SUCCESS) + { + WARN("vkGetSwapchainImagesKHR failed, res=%d\n", res); + goto fail; + } + + /* create user images */ + for (i = 0; i < count; ++i) + { + struct fs_hack_image *hack = &swapchain->fs_hack_images[i]; + + hack->swapchain_image = real_images[i]; + + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + res = device->funcs.p_vkCreateSemaphore(device->device, &semaphoreInfo, NULL, &hack->blit_finished); + if (res != VK_SUCCESS) + { + WARN("vkCreateSemaphore failed, res=%d\n", res); + goto fail; + } + + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.extent.width = swapchain->user_extent.width; + imageInfo.extent.height = swapchain->user_extent.height; + imageInfo.extent.depth = 1; + imageInfo.mipLevels = 1; + imageInfo.arrayLayers = createinfo->imageArrayLayers; + imageInfo.format = createinfo->imageFormat; + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.usage = createinfo->imageUsage | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + imageInfo.sharingMode = createinfo->imageSharingMode; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageInfo.queueFamilyIndexCount = createinfo->queueFamilyIndexCount; + imageInfo.pQueueFamilyIndices = createinfo->pQueueFamilyIndices; + res = device->funcs.p_vkCreateImage(device->device, &imageInfo, NULL, &hack->user_image); + if (res != VK_SUCCESS) + { + ERR("vkCreateImage failed: %d\n", res); + goto fail; + } + + device->funcs.p_vkGetImageMemoryRequirements(device->device, hack->user_image, &userMemReq); + + offs = userMemTotal % userMemReq.alignment; + if (offs) + userMemTotal += userMemReq.alignment - offs; + + userMemTotal += userMemReq.size; + + swapchain->n_images++; + } + + /* allocate backing memory */ + device->phys_dev->instance->funcs.p_vkGetPhysicalDeviceMemoryProperties(device->phys_dev->phys_dev, &memProperties); + + for (i = 0; i < memProperties.memoryTypeCount; i++) + { + UINT flag = memProperties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + if (flag == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) + { + if (userMemReq.memoryTypeBits & (1 << i)) + { + user_memory_type = i; + break; + } + } + } + + if (user_memory_type == -1) + { + ERR("unable to find suitable memory type\n"); + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = userMemTotal; + allocInfo.memoryTypeIndex = user_memory_type; + + res = device->funcs.p_vkAllocateMemory(device->device, &allocInfo, NULL, &swapchain->user_image_memory); + if (res != VK_SUCCESS) + { + ERR("vkAllocateMemory: %d\n", res); + goto fail; + } + + /* bind backing memory and create imageviews */ + userMemTotal = 0; + for (i = 0; i < count; ++i) + { + device->funcs.p_vkGetImageMemoryRequirements(device->device, swapchain->fs_hack_images[i].user_image, &userMemReq); + + offs = userMemTotal % userMemReq.alignment; + if (offs) + userMemTotal += userMemReq.alignment - offs; + + res = device->funcs.p_vkBindImageMemory(device->device, swapchain->fs_hack_images[i].user_image, + swapchain->user_image_memory, userMemTotal); + if (res != VK_SUCCESS) + { + ERR("vkBindImageMemory: %d\n", res); + goto fail; + } + + userMemTotal += userMemReq.size; + + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = swapchain->fs_hack_images[i].user_image; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = createinfo->imageFormat; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = 1; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = 1; + + res = device->funcs.p_vkCreateImageView(device->device, &viewInfo, NULL, + &swapchain->fs_hack_images[i].user_view); + if (res != VK_SUCCESS) + { + ERR("vkCreateImageView(user): %d\n", res); + goto fail; + } + } + + free(real_images); + + return VK_SUCCESS; + +fail: + for (i = 0; i < swapchain->n_images; ++i) destroy_fs_hack_image(device, swapchain, &swapchain->fs_hack_images[i]); + free(real_images); + free(swapchain->cmd_pools); + free(swapchain->fs_hack_images); + return res; +} + VkResult wine_vkCreateSwapchainKHR(VkDevice device_handle, const VkSwapchainCreateInfoKHR *info, const VkAllocationCallbacks *allocator, VkSwapchainKHR *swapchain, void *client_ptr) { @@ -1543,6 +2148,7 @@ VkResult wine_vkCreateSwapchainKHR(VkDevice device_handle, const VkSwapchainCrea VkSwapchainCreateInfoKHR create_info_host = *info; struct vk_swapchain *handle = client_ptr; struct wine_swapchain *object; + VkExtent2D user_sz; VkResult res; if (!(object = calloc(1, sizeof(*object)))) @@ -1556,6 +2162,41 @@ VkResult wine_vkCreateSwapchainKHR(VkDevice device_handle, const VkSwapchainCrea if (create_info_host.oldSwapchain) create_info_host.oldSwapchain = wine_swapchain_from_handle(create_info_host.oldSwapchain)->swapchain; + if (vk_funcs->query_fs_hack && + vk_funcs->query_fs_hack(create_info_host.surface, &object->real_extent, &user_sz, + &object->blit_dst, &object->fs_hack_filter) && + create_info_host.imageExtent.width == user_sz.width && + create_info_host.imageExtent.height == user_sz.height) + { + uint32_t count; + VkSurfaceCapabilitiesKHR caps = {0}; + + device->phys_dev->instance->funcs.p_vkGetPhysicalDeviceQueueFamilyProperties(device->phys_dev->phys_dev, &count, NULL); + + device->queue_props = malloc(sizeof(VkQueueFamilyProperties) * count); + + device->phys_dev->instance->funcs.p_vkGetPhysicalDeviceQueueFamilyProperties(device->phys_dev->phys_dev, &count, device->queue_props); + + res = device->phys_dev->instance->funcs.p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device->phys_dev->phys_dev, create_info_host.surface, &caps); + if (res != VK_SUCCESS) + { + TRACE("vkGetPhysicalDeviceSurfaceCapabilities failed, res=%d\n", res); + free(object); + return res; + } + + object->surface_usage = caps.supportedUsageFlags; + TRACE("surface usage flags: 0x%x\n", object->surface_usage); + + create_info_host.imageExtent = object->real_extent; + create_info_host.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; /* XXX: check if supported by surface */ + + if (create_info_host.imageFormat != VK_FORMAT_B8G8R8A8_UNORM && create_info_host.imageFormat != VK_FORMAT_B8G8R8A8_SRGB) + FIXME("swapchain image format is not BGRA8 UNORM/SRGB. Things may go badly. %d\n", create_info_host.imageFormat); + + object->fs_hack_enabled = TRUE; + } + res = device->funcs.p_vkCreateSwapchainKHR(device->device, &create_info_host, NULL, &object->swapchain); if (res != VK_SUCCESS) @@ -1564,6 +2205,33 @@ VkResult wine_vkCreateSwapchainKHR(VkDevice device_handle, const VkSwapchainCrea return res; } + if (object->fs_hack_enabled) + { + object->user_extent = info->imageExtent; + + res = init_fs_hack_images(device, object, &create_info_host); + if (res != VK_SUCCESS) + { + ERR("creating fs hack images failed: %d\n", res); + device->funcs.p_vkDestroySwapchainKHR(device->device, object->swapchain, NULL); + WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, object); + free(object); + return res; + } + + /* FIXME: would be nice to do this on-demand, but games can use up all + * memory so we fail to allocate later */ + res = init_blit_images(device, object); + if (res != VK_SUCCESS) + { + ERR("creating blit images failed: %d\n", res); + device->funcs.p_vkDestroySwapchainKHR(device->device, object->swapchain, NULL); + WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, object); + free(object); + return res; + } + } + object->handle = (uintptr_t)handle; handle->unix_handle = (uintptr_t)object; WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance, object->handle, object->swapchain, object); @@ -1830,6 +2498,7 @@ VkResult wine_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice handle, struct wine_phys_dev *phys_dev = wine_phys_dev_from_handle(handle); struct wine_surface *surface = wine_surface_from_handle(surface_handle); VkResult res; + VkExtent2D user_res; res = phys_dev->instance->funcs.p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_dev->phys_dev, surface->driver_surface, capabilities); @@ -1837,6 +2506,14 @@ VkResult wine_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice handle, if (res == VK_SUCCESS) adjust_max_image_count(phys_dev, capabilities); + if (res == VK_SUCCESS && vk_funcs->query_fs_hack && + vk_funcs->query_fs_hack(surface->driver_surface, NULL, &user_res, NULL, NULL)) + { + capabilities->currentExtent = user_res; + capabilities->minImageExtent = user_res; + capabilities->maxImageExtent = user_res; + } + return res; } @@ -1848,6 +2525,7 @@ VkResult wine_vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice handle struct wine_surface *surface = wine_surface_from_handle(surface_info->surface); VkPhysicalDeviceSurfaceInfo2KHR host_info; VkResult res; + VkExtent2D user_res; host_info.sType = surface_info->sType; host_info.pNext = surface_info->pNext; @@ -1858,6 +2536,14 @@ VkResult wine_vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice handle if (res == VK_SUCCESS) adjust_max_image_count(phys_dev, &capabilities->surfaceCapabilities); + if (res == VK_SUCCESS && vk_funcs->query_fs_hack && + vk_funcs->query_fs_hack(wine_surface_from_handle(surface_info->surface)->driver_surface, NULL, &user_res, NULL, NULL)) + { + capabilities->surfaceCapabilities.currentExtent = user_res; + capabilities->surfaceCapabilities.minImageExtent = user_res; + capabilities->surfaceCapabilities.maxImageExtent = user_res; + } + return res; } @@ -1978,16 +2664,555 @@ void wine_vkDestroySwapchainKHR(VkDevice device_handle, VkSwapchainKHR handle, c { struct wine_device *device = wine_device_from_handle(device_handle); struct wine_swapchain *swapchain = wine_swapchain_from_handle(handle); + uint32_t i; if (allocator) FIXME("Support for allocation callbacks not implemented yet\n"); + if (swapchain->fs_hack_enabled) + { + for (i = 0; i < swapchain->n_images; ++i) destroy_fs_hack_image(device, swapchain, &swapchain->fs_hack_images[i]); + + for (i = 0; i < device->queue_count; ++i) + if (swapchain->cmd_pools[i]) + device->funcs.p_vkDestroyCommandPool(device->device, swapchain->cmd_pools[i], NULL); + + device->funcs.p_vkDestroyPipeline(device->device, swapchain->pipeline, NULL); + device->funcs.p_vkDestroyPipelineLayout(device->device, swapchain->pipeline_layout, NULL); + device->funcs.p_vkDestroyDescriptorSetLayout(device->device, swapchain->descriptor_set_layout, NULL); + device->funcs.p_vkDestroyDescriptorPool(device->device, swapchain->descriptor_pool, NULL); + device->funcs.p_vkDestroySampler(device->device, swapchain->sampler, NULL); + device->funcs.p_vkFreeMemory(device->device, swapchain->user_image_memory, NULL); + device->funcs.p_vkFreeMemory(device->device, swapchain->blit_image_memory, NULL); + free(swapchain->cmd_pools); + free(swapchain->fs_hack_images); + } + WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, swapchain); device->funcs.p_vkDestroySwapchainKHR(device->device, swapchain->swapchain, NULL); free(swapchain); } +VkResult wine_vkGetSwapchainImagesKHR(VkDevice device_handle, VkSwapchainKHR handle, + uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) +{ + struct wine_device *device = wine_device_from_handle(device_handle); + struct wine_swapchain *swapchain = wine_swapchain_from_handle(handle); + uint32_t i; + + if (pSwapchainImages && swapchain->fs_hack_enabled) + { + if (*pSwapchainImageCount > swapchain->n_images) + *pSwapchainImageCount = swapchain->n_images; + for (i = 0; i < *pSwapchainImageCount; ++i) pSwapchainImages[i] = swapchain->fs_hack_images[i].user_image; + return *pSwapchainImageCount == swapchain->n_images ? VK_SUCCESS : VK_INCOMPLETE; + } + + return device->funcs.p_vkGetSwapchainImagesKHR(device->device, swapchain->swapchain, + pSwapchainImageCount, pSwapchainImages); +} + +static VkCommandBuffer create_hack_cmd(struct wine_queue *queue, struct wine_swapchain *swapchain, uint32_t queue_idx) +{ + VkCommandBufferAllocateInfo allocInfo = {0}; + VkCommandBuffer cmd; + VkResult result; + + if (!swapchain->cmd_pools[queue_idx]) + { + VkCommandPoolCreateInfo poolInfo = {0}; + + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.queueFamilyIndex = queue_idx; + + result = queue->device->funcs.p_vkCreateCommandPool(queue->device->device, &poolInfo, NULL, + &swapchain->cmd_pools[queue_idx]); + if (result != VK_SUCCESS) + { + ERR("vkCreateCommandPool failed, res=%d\n", result); + return NULL; + } + } + + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = swapchain->cmd_pools[queue_idx]; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandBufferCount = 1; + + result = queue->device->funcs.p_vkAllocateCommandBuffers(queue->device->device, &allocInfo, &cmd); + if (result != VK_SUCCESS) + { + ERR("vkAllocateCommandBuffers failed, res=%d\n", result); + return NULL; + } + + return cmd; +} + +static VkResult record_compute_cmd(struct wine_device *device, struct wine_swapchain *swapchain, + struct fs_hack_image *hack) +{ + VkResult result; + VkImageCopy region = {0}; + VkImageMemoryBarrier barriers[3] = {{0}}; + VkCommandBufferBeginInfo beginInfo = {0}; + float constants[4]; + + TRACE("recording compute command\n"); + +#if 0 + /* DOOM runs out of memory when allocating blit images after loading. */ + if(!swapchain->blit_image_memory){ + result = init_blit_images(device, swapchain); + if(result != VK_SUCCESS) + return result; + } +#endif + + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + + device->funcs.p_vkBeginCommandBuffer(hack->cmd, &beginInfo); + + /* for the cs we run... */ + /* transition user image from PRESENT_SRC to SHADER_READ */ + barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barriers[0].oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + barriers[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].image = hack->user_image; + barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[0].subresourceRange.baseMipLevel = 0; + barriers[0].subresourceRange.levelCount = 1; + barriers[0].subresourceRange.baseArrayLayer = 0; + barriers[0].subresourceRange.layerCount = 1; + barriers[0].srcAccessMask = 0; + barriers[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + /* storage image... */ + /* transition blit image from whatever to GENERAL */ + barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barriers[1].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + barriers[1].newLayout = VK_IMAGE_LAYOUT_GENERAL; + barriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[1].image = hack->blit_image ? hack->blit_image : hack->swapchain_image; + barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[1].subresourceRange.baseMipLevel = 0; + barriers[1].subresourceRange.levelCount = 1; + barriers[1].subresourceRange.baseArrayLayer = 0; + barriers[1].subresourceRange.layerCount = 1; + barriers[1].srcAccessMask = 0; + barriers[1].dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + + device->funcs.p_vkCmdPipelineBarrier(hack->cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 2, barriers); + + /* perform blit shader */ + device->funcs.p_vkCmdBindPipeline(hack->cmd, VK_PIPELINE_BIND_POINT_COMPUTE, swapchain->pipeline); + + device->funcs.p_vkCmdBindDescriptorSets(hack->cmd, VK_PIPELINE_BIND_POINT_COMPUTE, + swapchain->pipeline_layout, 0, 1, &hack->descriptor_set, 0, NULL); + + /* vec2: blit dst offset in real coords */ + constants[0] = swapchain->blit_dst.offset.x; + constants[1] = swapchain->blit_dst.offset.y; + /* vec2: blit dst extents in real coords */ + constants[2] = swapchain->blit_dst.extent.width; + constants[3] = swapchain->blit_dst.extent.height; + device->funcs.p_vkCmdPushConstants(hack->cmd, swapchain->pipeline_layout, + VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(constants), constants); + + /* local sizes in shader are 8 */ + device->funcs.p_vkCmdDispatch(hack->cmd, ceil(swapchain->real_extent.width / 8.), + ceil(swapchain->real_extent.height / 8.), 1); + + /* transition user image from SHADER_READ back to PRESENT_SRC */ + barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barriers[0].oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barriers[0].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].image = hack->user_image; + barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[0].subresourceRange.baseMipLevel = 0; + barriers[0].subresourceRange.levelCount = 1; + barriers[0].subresourceRange.baseArrayLayer = 0; + barriers[0].subresourceRange.layerCount = 1; + barriers[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + barriers[0].dstAccessMask = 0; + + device->funcs.p_vkCmdPipelineBarrier( + hack->cmd, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + 0, + 0, NULL, + 0, NULL, + 1, barriers + ); + + if (hack->blit_image) + { + /* for the copy... */ + /* no transition, just a barrier for our access masks (w -> r) */ + barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barriers[0].oldLayout = VK_IMAGE_LAYOUT_GENERAL; + barriers[0].newLayout = VK_IMAGE_LAYOUT_GENERAL; + barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].image = hack->blit_image; + barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[0].subresourceRange.baseMipLevel = 0; + barriers[0].subresourceRange.levelCount = 1; + barriers[0].subresourceRange.baseArrayLayer = 0; + barriers[0].subresourceRange.layerCount = 1; + barriers[0].srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + barriers[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + + /* for the copy... */ + /* transition swapchain image from whatever to TRANSFER_DST + * we don't care about the contents... */ + barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barriers[1].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + barriers[1].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[1].image = hack->swapchain_image; + barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[1].subresourceRange.baseMipLevel = 0; + barriers[1].subresourceRange.levelCount = 1; + barriers[1].subresourceRange.baseArrayLayer = 0; + barriers[1].subresourceRange.layerCount = 1; + barriers[1].srcAccessMask = 0; + barriers[1].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + + device->funcs.p_vkCmdPipelineBarrier(hack->cmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 2, barriers); + + /* copy from blit image to swapchain image */ + region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.srcSubresource.layerCount = 1; + region.srcOffset.x = 0; + region.srcOffset.y = 0; + region.srcOffset.z = 0; + region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.dstSubresource.layerCount = 1; + region.dstOffset.x = 0; + region.dstOffset.y = 0; + region.dstOffset.z = 0; + region.extent.width = swapchain->real_extent.width; + region.extent.height = swapchain->real_extent.height; + region.extent.depth = 1; + + device->funcs.p_vkCmdCopyImage(hack->cmd, hack->blit_image, VK_IMAGE_LAYOUT_GENERAL, + hack->swapchain_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + /* transition swapchain image from TRANSFER_DST_OPTIMAL to PRESENT_SRC */ + barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barriers[0].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].image = hack->swapchain_image; + barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[0].subresourceRange.baseMipLevel = 0; + barriers[0].subresourceRange.levelCount = 1; + barriers[0].subresourceRange.baseArrayLayer = 0; + barriers[0].subresourceRange.layerCount = 1; + barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barriers[0].dstAccessMask = 0; + + device->funcs.p_vkCmdPipelineBarrier(hack->cmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, barriers); + } + else + { + /* transition swapchain image from GENERAL to PRESENT_SRC */ + barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barriers[0].oldLayout = VK_IMAGE_LAYOUT_GENERAL; + barriers[0].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].image = hack->swapchain_image; + barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[0].subresourceRange.baseMipLevel = 0; + barriers[0].subresourceRange.levelCount = 1; + barriers[0].subresourceRange.baseArrayLayer = 0; + barriers[0].subresourceRange.layerCount = 1; + barriers[0].srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + barriers[0].dstAccessMask = 0; + + device->funcs.p_vkCmdPipelineBarrier(hack->cmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, barriers); + } + + result = device->funcs.p_vkEndCommandBuffer(hack->cmd); + if (result != VK_SUCCESS) + { + ERR("vkEndCommandBuffer: %d\n", result); + return result; + } + + return VK_SUCCESS; +} + +static VkResult record_graphics_cmd(struct wine_device *device, struct wine_swapchain *swapchain, + struct fs_hack_image *hack) +{ + VkClearColorValue black = {{0.f, 0.f, 0.f}}; + VkCommandBufferBeginInfo beginInfo = {0}; + VkImageMemoryBarrier barriers[2] = {{0}}; + VkImageSubresourceRange range = {0}; + VkImageBlit blitregion = {0}; + VkResult result; + + TRACE("recording graphics command\n"); + + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + + device->funcs.p_vkBeginCommandBuffer(hack->cmd, &beginInfo); + + /* transition real image from whatever to TRANSFER_DST_OPTIMAL */ + barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barriers[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + barriers[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].image = hack->swapchain_image; + barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[0].subresourceRange.baseMipLevel = 0; + barriers[0].subresourceRange.levelCount = 1; + barriers[0].subresourceRange.baseArrayLayer = 0; + barriers[0].subresourceRange.layerCount = 1; + barriers[0].srcAccessMask = 0; + barriers[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + + /* transition user image from PRESENT_SRC to TRANSFER_SRC_OPTIMAL */ + barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barriers[1].oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + barriers[1].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[1].image = hack->user_image; + barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[1].subresourceRange.baseMipLevel = 0; + barriers[1].subresourceRange.levelCount = 1; + barriers[1].subresourceRange.baseArrayLayer = 0; + barriers[1].subresourceRange.layerCount = 1; + barriers[1].srcAccessMask = 0; + barriers[1].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + + device->funcs.p_vkCmdPipelineBarrier(hack->cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 2, barriers); + + /* clear the image */ + range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + range.baseMipLevel = 0; + range.levelCount = 1; + range.baseArrayLayer = 0; + range.layerCount = 1; + + device->funcs.p_vkCmdClearColorImage(hack->cmd, hack->swapchain_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &black, 1, &range); + + /* perform blit */ + blitregion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blitregion.srcSubresource.layerCount = 1; + blitregion.srcOffsets[0].x = 0; + blitregion.srcOffsets[0].y = 0; + blitregion.srcOffsets[0].z = 0; + blitregion.srcOffsets[1].x = swapchain->user_extent.width; + blitregion.srcOffsets[1].y = swapchain->user_extent.height; + blitregion.srcOffsets[1].z = 1; + blitregion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blitregion.dstSubresource.layerCount = 1; + blitregion.dstOffsets[0].x = swapchain->blit_dst.offset.x; + blitregion.dstOffsets[0].y = swapchain->blit_dst.offset.y; + blitregion.dstOffsets[0].z = 0; + blitregion.dstOffsets[1].x = swapchain->blit_dst.offset.x + swapchain->blit_dst.extent.width; + blitregion.dstOffsets[1].y = swapchain->blit_dst.offset.y + swapchain->blit_dst.extent.height; + blitregion.dstOffsets[1].z = 1; + + device->funcs.p_vkCmdBlitImage(hack->cmd, hack->user_image, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, hack->swapchain_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blitregion, swapchain->fs_hack_filter); + + /* transition real image from TRANSFER_DST to PRESENT_SRC */ + barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barriers[0].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].image = hack->swapchain_image; + barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[0].subresourceRange.baseMipLevel = 0; + barriers[0].subresourceRange.levelCount = 1; + barriers[0].subresourceRange.baseArrayLayer = 0; + barriers[0].subresourceRange.layerCount = 1; + barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barriers[0].dstAccessMask = 0; + + /* transition user image from TRANSFER_SRC_OPTIMAL to back to PRESENT_SRC */ + barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barriers[1].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barriers[1].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + barriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[1].image = hack->user_image; + barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[1].subresourceRange.baseMipLevel = 0; + barriers[1].subresourceRange.levelCount = 1; + barriers[1].subresourceRange.baseArrayLayer = 0; + barriers[1].subresourceRange.layerCount = 1; + barriers[1].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + barriers[1].dstAccessMask = 0; + + device->funcs.p_vkCmdPipelineBarrier(hack->cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 2, barriers); + + result = device->funcs.p_vkEndCommandBuffer(hack->cmd); + if (result != VK_SUCCESS) + { + ERR("vkEndCommandBuffer: %d\n", result); + return result; + } + + return VK_SUCCESS; +} + +VkResult wine_vkQueuePresentKHR(VkQueue queue_handle, const VkPresentInfoKHR *pPresentInfo) +{ + struct wine_queue *queue = wine_queue_from_handle(queue_handle); + VkCommandBuffer *blit_cmds = NULL; + struct wine_swapchain *swapchain; + VkPresentInfoKHR our_presentInfo; + VkSubmitInfo submitInfo = {0}; + uint32_t i, n_hacks = 0; + VkSemaphore blit_sema; + VkSwapchainKHR *arr; + uint32_t queue_idx; + VkResult res; + + TRACE("%p, %p\n", queue, pPresentInfo); + + our_presentInfo = *pPresentInfo; + + for (i = 0; i < our_presentInfo.swapchainCount; ++i) + { + swapchain = wine_swapchain_from_handle(our_presentInfo.pSwapchains[i]); + + if (swapchain->fs_hack_enabled) + { + struct fs_hack_image *hack = &swapchain->fs_hack_images[our_presentInfo.pImageIndices[i]]; + + if (!blit_cmds) + { + queue_idx = queue->family_index; + blit_cmds = malloc(our_presentInfo.swapchainCount * sizeof(VkCommandBuffer)); + blit_sema = hack->blit_finished; + } + + if (!hack->cmd || hack->cmd_queue_idx != queue_idx) + { + if (hack->cmd) + queue->device->funcs.p_vkFreeCommandBuffers(queue->device->device, + swapchain->cmd_pools[hack->cmd_queue_idx], 1, &hack->cmd); + + hack->cmd_queue_idx = queue_idx; + hack->cmd = create_hack_cmd(queue, swapchain, queue_idx); + + if (!hack->cmd) + { + free(blit_cmds); + return VK_ERROR_DEVICE_LOST; + } + + if (queue->device->queue_props[queue_idx].queueFlags & VK_QUEUE_GRAPHICS_BIT) + res = record_graphics_cmd(queue->device, swapchain, hack); + else if (queue->device->queue_props[queue_idx].queueFlags & VK_QUEUE_COMPUTE_BIT) + res = record_compute_cmd(queue->device, swapchain, hack); + else + { + ERR("Present queue is neither graphics nor compute queue!\n"); + res = VK_ERROR_DEVICE_LOST; + } + + if (res != VK_SUCCESS) + { + queue->device->funcs.p_vkFreeCommandBuffers(queue->device->device, + swapchain->cmd_pools[hack->cmd_queue_idx], 1, &hack->cmd); + hack->cmd = NULL; + free(blit_cmds); + return res; + } + } + + blit_cmds[n_hacks] = hack->cmd; + + ++n_hacks; + } + } + + if (n_hacks > 0) + { + VkPipelineStageFlags waitStage, *waitStages, *waitStages_arr = NULL; + + if (pPresentInfo->waitSemaphoreCount > 1) + { + waitStages_arr = malloc(sizeof(VkPipelineStageFlags) * pPresentInfo->waitSemaphoreCount); + for (i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) waitStages_arr[i] = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + waitStages = waitStages_arr; + } + else + { + waitStage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + waitStages = &waitStage; + } + + /* blit user image to real image */ + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.waitSemaphoreCount = pPresentInfo->waitSemaphoreCount; + submitInfo.pWaitSemaphores = pPresentInfo->pWaitSemaphores; + submitInfo.pWaitDstStageMask = waitStages; + submitInfo.commandBufferCount = n_hacks; + submitInfo.pCommandBuffers = blit_cmds; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &blit_sema; + + res = queue->device->funcs.p_vkQueueSubmit(queue->queue, 1, &submitInfo, VK_NULL_HANDLE); + if (res != VK_SUCCESS) + ERR("vkQueueSubmit: %d\n", res); + + free(waitStages_arr); + free(blit_cmds); + + our_presentInfo.waitSemaphoreCount = 1; + our_presentInfo.pWaitSemaphores = &blit_sema; + } + + arr = malloc(our_presentInfo.swapchainCount * sizeof(VkSwapchainKHR)); + if (!arr) + { + ERR("Failed to allocate memory for swapchain array\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + for (i = 0; i < our_presentInfo.swapchainCount; ++i) + arr[i] = wine_swapchain_from_handle(our_presentInfo.pSwapchains[i])->swapchain; + + our_presentInfo.pSwapchains = arr; + + res = queue->device->funcs.p_vkQueuePresentKHR(queue->queue, &our_presentInfo); + + free(arr); + + return res; +} + #ifdef _WIN64 NTSTATUS vk_is_available_instance_function(void *arg) diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 9fc73445247..d84333d7951 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -64,6 +64,8 @@ struct wine_device struct wine_queue *queues; uint32_t queue_count; + VkQueueFamilyProperties *queue_props; + struct wine_vk_mapping mapping; }; @@ -72,10 +74,40 @@ static inline struct wine_device *wine_device_from_handle(VkDevice handle) return (struct wine_device *)(uintptr_t)handle->base.unix_handle; } +struct fs_hack_image +{ + uint32_t cmd_queue_idx; + VkCommandBuffer cmd; + VkImage swapchain_image; + VkImage blit_image; + VkImage user_image; + VkSemaphore blit_finished; + VkImageView user_view, blit_view; + VkDescriptorSet descriptor_set; +}; + struct wine_swapchain { VkSwapchainKHR handle; VkSwapchainKHR swapchain; /* native swapchain */ + + /* fs hack data below */ + BOOL fs_hack_enabled; + VkExtent2D user_extent; + VkExtent2D real_extent; + VkImageUsageFlags surface_usage; + VkRect2D blit_dst; + VkCommandPool *cmd_pools; /* VkCommandPool[device->queue_count] */ + VkDeviceMemory user_image_memory, blit_image_memory; + uint32_t n_images; + struct fs_hack_image *fs_hack_images; /* struct fs_hack_image[n_images] */ + VkFilter fs_hack_filter; + VkSampler sampler; + VkDescriptorPool descriptor_pool; + VkDescriptorSetLayout descriptor_set_layout; + VkPipelineLayout pipeline_layout; + VkPipeline pipeline; + struct wine_vk_mapping mapping; }; From 093ed1e1c7f1f2496c2e558117beb252bdc9f9e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:43:12 +0100 Subject: [PATCH 0678/2777] fshack: winevulkan: Fixes and improvements. Old fshack causes radv assertions because of image view format mismatches. Changes: - drop the vkCmdBlitImage path, it's impossible to keep without VK_KHR_swapchain_mutable_format. - drop the compute+copy path, all drivers support swapchains with storage usage, no reason to keep untested code around. - interpolate in linear color space for slightly better results - improve compute path by interpolating at the pixel center - fix all validation errors Signed-off-by: Georg Lehmann Link: https://github.com/ValveSoftware/wine/pull/158 --- dlls/winevulkan/loader.c | 14 - dlls/winevulkan/vulkan.c | 536 ++++++++----------------------- dlls/winevulkan/vulkan_loader.h | 14 + dlls/winevulkan/vulkan_private.h | 4 +- 4 files changed, 149 insertions(+), 419 deletions(-) diff --git a/dlls/winevulkan/loader.c b/dlls/winevulkan/loader.c index 97f079b54a8..ba2a1d23bc7 100644 --- a/dlls/winevulkan/loader.c +++ b/dlls/winevulkan/loader.c @@ -39,20 +39,6 @@ static HINSTANCE hinstance; static void *wine_vk_get_global_proc_addr(const char *name); -#define wine_vk_find_struct(s, t) wine_vk_find_struct_((void *)s, VK_STRUCTURE_TYPE_##t) -static void *wine_vk_find_struct_(void *s, VkStructureType t) -{ - VkBaseOutStructure *header; - - for (header = s; header; header = header->pNext) - { - if (header->sType == t) - return header; - } - - return NULL; -} - VkResult WINAPI vkEnumerateInstanceLayerProperties(uint32_t *count, VkLayerProperties *properties) { TRACE("%p, %p\n", count, properties); diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index aebb0c7f62c..5cde473d41f 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -847,6 +847,28 @@ VkResult wine_vkCreateDevice(VkPhysicalDevice phys_dev_handle, const VkDeviceCre res = wine_vk_device_convert_create_info(phys_dev, &ctx, create_info, &create_info_host); if (res == VK_SUCCESS) { + VkPhysicalDeviceFeatures features = {0}; + VkPhysicalDeviceFeatures2 *features2; + + /* Enable shaderStorageImageWriteWithoutFormat for fshack + * This is available on all hardware and driver combinations we care about. + */ + if (create_info_host.pEnabledFeatures) + { + features = *create_info_host.pEnabledFeatures; + features.shaderStorageImageWriteWithoutFormat = VK_TRUE; + create_info_host.pEnabledFeatures = &features; + } + if ((features2 = wine_vk_find_struct(&create_info_host, PHYSICAL_DEVICE_FEATURES_2))) + { + features2->features.shaderStorageImageWriteWithoutFormat = VK_TRUE; + } + else if (!create_info_host.pEnabledFeatures) + { + features.shaderStorageImageWriteWithoutFormat = VK_TRUE; + create_info_host.pEnabledFeatures = &features; + } + if (native_create_device) res = native_create_device(phys_dev->phys_dev, &create_info_host, NULL /* allocator */, &object->device, @@ -1538,60 +1560,79 @@ void wine_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(VkPhysicalDevice phy } /* -#version 450 +#version 460 + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; layout(binding = 0) uniform sampler2D texSampler; -layout(binding = 1, rgba8) uniform writeonly image2D outImage; +layout(binding = 1) uniform writeonly image2D outImage; layout(push_constant) uniform pushConstants { //both in real image coords vec2 offset; vec2 extents; } constants; -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - void main() { vec2 texcoord = (vec2(gl_GlobalInvocationID.xy) - constants.offset) / constants.extents; vec4 c = texture(texSampler, texcoord); - imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), c.bgra); + + // Convert linear -> srgb + bvec3 isLo = lessThanEqual(c.rgb, vec3(0.0031308f)); + vec3 loPart = c.rgb * 12.92f; + vec3 hiPart = pow(c.rgb, vec3(5.0f / 12.0f)) * 1.055f - 0.055f; + c.rgb = mix(hiPart, loPart, isLo); + + imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), c); } + */ const uint32_t blit_comp_spv[] = { - 0x07230203,0x00010000,0x00080006,0x00000037,0x00000000,0x00020011,0x00000001,0x0006000b, - 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, - 0x0006000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x0000000d,0x00060010,0x00000004, - 0x00000011,0x00000008,0x00000008,0x00000001,0x00030003,0x00000002,0x000001c2,0x00040005, - 0x00000004,0x6e69616d,0x00000000,0x00050005,0x00000009,0x63786574,0x64726f6f,0x00000000, - 0x00080005,0x0000000d,0x475f6c67,0x61626f6c,0x766e496c,0x7461636f,0x496e6f69,0x00000044, - 0x00060005,0x00000012,0x68737570,0x736e6f43,0x746e6174,0x00000073,0x00050006,0x00000012, - 0x00000000,0x7366666f,0x00007465,0x00050006,0x00000012,0x00000001,0x65747865,0x0073746e, - 0x00050005,0x00000014,0x736e6f63,0x746e6174,0x00000073,0x00030005,0x00000021,0x00000063, - 0x00050005,0x00000025,0x53786574,0x6c706d61,0x00007265,0x00050005,0x0000002c,0x4974756f, - 0x6567616d,0x00000000,0x00040047,0x0000000d,0x0000000b,0x0000001c,0x00050048,0x00000012, - 0x00000000,0x00000023,0x00000000,0x00050048,0x00000012,0x00000001,0x00000023,0x00000008, - 0x00030047,0x00000012,0x00000002,0x00040047,0x00000025,0x00000022,0x00000000,0x00040047, - 0x00000025,0x00000021,0x00000000,0x00040047,0x0000002c,0x00000022,0x00000000,0x00040047, - 0x0000002c,0x00000021,0x00000001,0x00030047,0x0000002c,0x00000019,0x00040047,0x00000036, - 0x0000000b,0x00000019,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016, - 0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000002,0x00040020,0x00000008, - 0x00000007,0x00000007,0x00040015,0x0000000a,0x00000020,0x00000000,0x00040017,0x0000000b, - 0x0000000a,0x00000003,0x00040020,0x0000000c,0x00000001,0x0000000b,0x0004003b,0x0000000c, - 0x0000000d,0x00000001,0x00040017,0x0000000e,0x0000000a,0x00000002,0x0004001e,0x00000012, - 0x00000007,0x00000007,0x00040020,0x00000013,0x00000009,0x00000012,0x0004003b,0x00000013, - 0x00000014,0x00000009,0x00040015,0x00000015,0x00000020,0x00000001,0x0004002b,0x00000015, - 0x00000016,0x00000000,0x00040020,0x00000017,0x00000009,0x00000007,0x0004002b,0x00000015, - 0x0000001b,0x00000001,0x00040017,0x0000001f,0x00000006,0x00000004,0x00040020,0x00000020, - 0x00000007,0x0000001f,0x00090019,0x00000022,0x00000006,0x00000001,0x00000000,0x00000000, - 0x00000000,0x00000001,0x00000000,0x0003001b,0x00000023,0x00000022,0x00040020,0x00000024, - 0x00000000,0x00000023,0x0004003b,0x00000024,0x00000025,0x00000000,0x0004002b,0x00000006, - 0x00000028,0x00000000,0x00090019,0x0000002a,0x00000006,0x00000001,0x00000000,0x00000000, - 0x00000000,0x00000002,0x00000004,0x00040020,0x0000002b,0x00000000,0x0000002a,0x0004003b, - 0x0000002b,0x0000002c,0x00000000,0x00040017,0x00000030,0x00000015,0x00000002,0x0004002b, - 0x0000000a,0x00000034,0x00000008,0x0004002b,0x0000000a,0x00000035,0x00000001,0x0006002c, - 0x0000000b,0x00000036,0x00000034,0x00000034,0x00000035,0x00050036,0x00000002,0x00000004, - 0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008,0x00000009,0x00000007, - 0x0004003b,0x00000020,0x00000021,0x00000007,0x0004003d,0x0000000b,0x0000000f,0x0000000d, + 0x07230203,0x00010000,0x0008000a,0x0000005e,0x00000000,0x00020011,0x00000001,0x00020011, + 0x00000038,0x0006000b,0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e, + 0x00000000,0x00000001,0x0006000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x0000000d, + 0x00060010,0x00000004,0x00000011,0x00000008,0x00000008,0x00000001,0x00030003,0x00000002, + 0x000001cc,0x00040005,0x00000004,0x6e69616d,0x00000000,0x00050005,0x00000009,0x63786574, + 0x64726f6f,0x00000000,0x00080005,0x0000000d,0x475f6c67,0x61626f6c,0x766e496c,0x7461636f, + 0x496e6f69,0x00000044,0x00060005,0x00000012,0x68737570,0x736e6f43,0x746e6174,0x00000073, + 0x00050006,0x00000012,0x00000000,0x7366666f,0x00007465,0x00050006,0x00000012,0x00000001, + 0x65747865,0x0073746e,0x00050005,0x00000014,0x736e6f63,0x746e6174,0x00000073,0x00030005, + 0x00000021,0x00000063,0x00050005,0x00000025,0x53786574,0x6c706d61,0x00007265,0x00040005, + 0x0000002d,0x6f4c7369,0x00000000,0x00040005,0x00000035,0x61506f6c,0x00007472,0x00040005, + 0x0000003a,0x61506968,0x00007472,0x00050005,0x00000055,0x4974756f,0x6567616d,0x00000000, + 0x00040047,0x0000000d,0x0000000b,0x0000001c,0x00050048,0x00000012,0x00000000,0x00000023, + 0x00000000,0x00050048,0x00000012,0x00000001,0x00000023,0x00000008,0x00030047,0x00000012, + 0x00000002,0x00040047,0x00000025,0x00000022,0x00000000,0x00040047,0x00000025,0x00000021, + 0x00000000,0x00040047,0x00000055,0x00000022,0x00000000,0x00040047,0x00000055,0x00000021, + 0x00000001,0x00030047,0x00000055,0x00000019,0x00040047,0x0000005d,0x0000000b,0x00000019, + 0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020, + 0x00040017,0x00000007,0x00000006,0x00000002,0x00040020,0x00000008,0x00000007,0x00000007, + 0x00040015,0x0000000a,0x00000020,0x00000000,0x00040017,0x0000000b,0x0000000a,0x00000003, + 0x00040020,0x0000000c,0x00000001,0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001, + 0x00040017,0x0000000e,0x0000000a,0x00000002,0x0004001e,0x00000012,0x00000007,0x00000007, + 0x00040020,0x00000013,0x00000009,0x00000012,0x0004003b,0x00000013,0x00000014,0x00000009, + 0x00040015,0x00000015,0x00000020,0x00000001,0x0004002b,0x00000015,0x00000016,0x00000000, + 0x00040020,0x00000017,0x00000009,0x00000007,0x0004002b,0x00000015,0x0000001b,0x00000001, + 0x00040017,0x0000001f,0x00000006,0x00000004,0x00040020,0x00000020,0x00000007,0x0000001f, + 0x00090019,0x00000022,0x00000006,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001, + 0x00000000,0x0003001b,0x00000023,0x00000022,0x00040020,0x00000024,0x00000000,0x00000023, + 0x0004003b,0x00000024,0x00000025,0x00000000,0x0004002b,0x00000006,0x00000028,0x00000000, + 0x00020014,0x0000002a,0x00040017,0x0000002b,0x0000002a,0x00000003,0x00040020,0x0000002c, + 0x00000007,0x0000002b,0x00040017,0x0000002e,0x00000006,0x00000003,0x0004002b,0x00000006, + 0x00000031,0x3b4d2e1c,0x0006002c,0x0000002e,0x00000032,0x00000031,0x00000031,0x00000031, + 0x00040020,0x00000034,0x00000007,0x0000002e,0x0004002b,0x00000006,0x00000038,0x414eb852, + 0x0004002b,0x00000006,0x0000003d,0x3ed55555,0x0006002c,0x0000002e,0x0000003e,0x0000003d, + 0x0000003d,0x0000003d,0x0004002b,0x00000006,0x00000040,0x3f870a3d,0x0004002b,0x00000006, + 0x00000042,0x3d6147ae,0x0004002b,0x0000000a,0x00000049,0x00000000,0x00040020,0x0000004a, + 0x00000007,0x00000006,0x0004002b,0x0000000a,0x0000004d,0x00000001,0x0004002b,0x0000000a, + 0x00000050,0x00000002,0x00090019,0x00000053,0x00000006,0x00000001,0x00000000,0x00000000, + 0x00000000,0x00000002,0x00000000,0x00040020,0x00000054,0x00000000,0x00000053,0x0004003b, + 0x00000054,0x00000055,0x00000000,0x00040017,0x00000059,0x00000015,0x00000002,0x0004002b, + 0x0000000a,0x0000005c,0x00000008,0x0006002c,0x0000000b,0x0000005d,0x0000005c,0x0000005c, + 0x0000004d,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005, + 0x0004003b,0x00000008,0x00000009,0x00000007,0x0004003b,0x00000020,0x00000021,0x00000007, + 0x0004003b,0x0000002c,0x0000002d,0x00000007,0x0004003b,0x00000034,0x00000035,0x00000007, + 0x0004003b,0x00000034,0x0000003a,0x00000007,0x0004003d,0x0000000b,0x0000000f,0x0000000d, 0x0007004f,0x0000000e,0x00000010,0x0000000f,0x0000000f,0x00000000,0x00000001,0x00040070, 0x00000007,0x00000011,0x00000010,0x00050041,0x00000017,0x00000018,0x00000014,0x00000016, 0x0004003d,0x00000007,0x00000019,0x00000018,0x00050083,0x00000007,0x0000001a,0x00000011, @@ -1599,12 +1640,27 @@ const uint32_t blit_comp_spv[] = { 0x0000001d,0x0000001c,0x00050088,0x00000007,0x0000001e,0x0000001a,0x0000001d,0x0003003e, 0x00000009,0x0000001e,0x0004003d,0x00000023,0x00000026,0x00000025,0x0004003d,0x00000007, 0x00000027,0x00000009,0x00070058,0x0000001f,0x00000029,0x00000026,0x00000027,0x00000002, - 0x00000028,0x0003003e,0x00000021,0x00000029,0x0004003d,0x0000002a,0x0000002d,0x0000002c, - 0x0004003d,0x0000000b,0x0000002e,0x0000000d,0x0007004f,0x0000000e,0x0000002f,0x0000002e, - 0x0000002e,0x00000000,0x00000001,0x0004007c,0x00000030,0x00000031,0x0000002f,0x0004003d, - 0x0000001f,0x00000032,0x00000021,0x0009004f,0x0000001f,0x00000033,0x00000032,0x00000032, - 0x00000002,0x00000001,0x00000000,0x00000003,0x00040063,0x0000002d,0x00000031,0x00000033, - 0x000100fd,0x00010038 + 0x00000028,0x0003003e,0x00000021,0x00000029,0x0004003d,0x0000001f,0x0000002f,0x00000021, + 0x0008004f,0x0000002e,0x00000030,0x0000002f,0x0000002f,0x00000000,0x00000001,0x00000002, + 0x000500bc,0x0000002b,0x00000033,0x00000030,0x00000032,0x0003003e,0x0000002d,0x00000033, + 0x0004003d,0x0000001f,0x00000036,0x00000021,0x0008004f,0x0000002e,0x00000037,0x00000036, + 0x00000036,0x00000000,0x00000001,0x00000002,0x0005008e,0x0000002e,0x00000039,0x00000037, + 0x00000038,0x0003003e,0x00000035,0x00000039,0x0004003d,0x0000001f,0x0000003b,0x00000021, + 0x0008004f,0x0000002e,0x0000003c,0x0000003b,0x0000003b,0x00000000,0x00000001,0x00000002, + 0x0007000c,0x0000002e,0x0000003f,0x00000001,0x0000001a,0x0000003c,0x0000003e,0x0005008e, + 0x0000002e,0x00000041,0x0000003f,0x00000040,0x00060050,0x0000002e,0x00000043,0x00000042, + 0x00000042,0x00000042,0x00050083,0x0000002e,0x00000044,0x00000041,0x00000043,0x0003003e, + 0x0000003a,0x00000044,0x0004003d,0x0000002e,0x00000045,0x0000003a,0x0004003d,0x0000002e, + 0x00000046,0x00000035,0x0004003d,0x0000002b,0x00000047,0x0000002d,0x000600a9,0x0000002e, + 0x00000048,0x00000047,0x00000046,0x00000045,0x00050041,0x0000004a,0x0000004b,0x00000021, + 0x00000049,0x00050051,0x00000006,0x0000004c,0x00000048,0x00000000,0x0003003e,0x0000004b, + 0x0000004c,0x00050041,0x0000004a,0x0000004e,0x00000021,0x0000004d,0x00050051,0x00000006, + 0x0000004f,0x00000048,0x00000001,0x0003003e,0x0000004e,0x0000004f,0x00050041,0x0000004a, + 0x00000051,0x00000021,0x00000050,0x00050051,0x00000006,0x00000052,0x00000048,0x00000002, + 0x0003003e,0x00000051,0x00000052,0x0004003d,0x00000053,0x00000056,0x00000055,0x0004003d, + 0x0000000b,0x00000057,0x0000000d,0x0007004f,0x0000000e,0x00000058,0x00000057,0x00000057, + 0x00000000,0x00000001,0x0004007c,0x00000059,0x0000005a,0x00000058,0x0004003d,0x0000001f, + 0x0000005b,0x00000021,0x00040063,0x00000056,0x0000005a,0x0000005b,0x000100fd,0x00010038 }; static VkResult create_pipeline(struct wine_device *device, struct wine_swapchain *swapchain, VkShaderModule shaderModule) @@ -1692,13 +1748,8 @@ static VkResult init_blit_images(struct wine_device *device, struct wine_swapcha VkPushConstantRange pushConstants; VkShaderModuleCreateInfo shaderInfo = {0}; VkShaderModule shaderModule = 0; - VkDeviceSize blitMemTotal = 0, offs; - VkImageCreateInfo imageInfo = {0}; - VkMemoryRequirements blitMemReq; - VkMemoryAllocateInfo allocInfo = {0}; - VkPhysicalDeviceMemoryProperties memProperties; VkImageViewCreateInfo viewInfo = {0}; - uint32_t blit_memory_type = -1, i; + uint32_t i; samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; samplerInfo.magFilter = swapchain->fs_hack_filter; @@ -1708,7 +1759,7 @@ static VkResult init_blit_images(struct wine_device *device, struct wine_swapcha samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; samplerInfo.anisotropyEnable = VK_FALSE; samplerInfo.maxAnisotropy = 1; - samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; samplerInfo.unnormalizedCoordinates = VK_FALSE; samplerInfo.compareEnable = VK_FALSE; samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; @@ -1800,112 +1851,15 @@ static VkResult init_blit_images(struct wine_device *device, struct wine_swapcha device->funcs.p_vkDestroyShaderModule(device->device, shaderModule, NULL); - if (!(swapchain->surface_usage & VK_IMAGE_USAGE_STORAGE_BIT)) - { - TRACE("using intermediate blit images\n"); - /* create intermediate blit images */ - for (i = 0; i < swapchain->n_images; ++i) - { - struct fs_hack_image *hack = &swapchain->fs_hack_images[i]; - - imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent.width = swapchain->real_extent.width; - imageInfo.extent.height = swapchain->real_extent.height; - imageInfo.extent.depth = 1; - imageInfo.mipLevels = 1; - imageInfo.arrayLayers = 1; - imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM; - imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; - res = device->funcs.p_vkCreateImage(device->device, &imageInfo, NULL, &hack->blit_image); - if (res != VK_SUCCESS) - { - ERR("vkCreateImage failed: %d\n", res); - goto fail; - } - - device->funcs.p_vkGetImageMemoryRequirements(device->device, hack->blit_image, &blitMemReq); - - offs = blitMemTotal % blitMemReq.alignment; - if (offs) - blitMemTotal += blitMemReq.alignment - offs; - - blitMemTotal += blitMemReq.size; - } - - /* allocate backing memory */ - device->phys_dev->instance->funcs.p_vkGetPhysicalDeviceMemoryProperties(device->phys_dev->phys_dev, &memProperties); - - for (i = 0; i < memProperties.memoryTypeCount; i++) - { - UINT flag = memProperties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - if (flag == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) - { - if (blitMemReq.memoryTypeBits & (1 << i)) - { - blit_memory_type = i; - break; - } - } - } - - if (blit_memory_type == -1) - { - ERR("unable to find suitable memory type\n"); - res = VK_ERROR_OUT_OF_HOST_MEMORY; - goto fail; - } - - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.allocationSize = blitMemTotal; - allocInfo.memoryTypeIndex = blit_memory_type; - - res = device->funcs.p_vkAllocateMemory(device->device, &allocInfo, NULL, &swapchain->blit_image_memory); - if (res != VK_SUCCESS) - { - ERR("vkAllocateMemory: %d\n", res); - goto fail; - } - - /* bind backing memory and create imageviews */ - blitMemTotal = 0; - for (i = 0; i < swapchain->n_images; ++i) - { - struct fs_hack_image *hack = &swapchain->fs_hack_images[i]; - - device->funcs.p_vkGetImageMemoryRequirements(device->device, hack->blit_image, &blitMemReq); - - offs = blitMemTotal % blitMemReq.alignment; - if (offs) - blitMemTotal += blitMemReq.alignment - offs; - - res = device->funcs.p_vkBindImageMemory(device->device, hack->blit_image, - swapchain->blit_image_memory, blitMemTotal); - if (res != VK_SUCCESS) - { - ERR("vkBindImageMemory: %d\n", res); - goto fail; - } - - blitMemTotal += blitMemReq.size; - } - } - else - TRACE("blitting directly to swapchain images\n"); - /* create imageviews */ for (i = 0; i < swapchain->n_images; ++i) { struct fs_hack_image *hack = &swapchain->fs_hack_images[i]; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.image = hack->blit_image ? hack->blit_image : hack->swapchain_image; + viewInfo.image = hack->swapchain_image; viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.format = VK_FORMAT_R8G8B8A8_UNORM; + viewInfo.format = VK_FORMAT_B8G8R8A8_UNORM; viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; viewInfo.subresourceRange.baseMipLevel = 0; viewInfo.subresourceRange.levelCount = 1; @@ -1933,9 +1887,6 @@ static VkResult init_blit_images(struct wine_device *device, struct wine_swapcha device->funcs.p_vkDestroyImageView(device->device, hack->blit_view, NULL); hack->blit_view = VK_NULL_HANDLE; - - device->funcs.p_vkDestroyImage(device->device, hack->blit_image, NULL); - hack->blit_image = VK_NULL_HANDLE; } device->funcs.p_vkDestroyShaderModule(device->device, shaderModule, NULL); @@ -1952,9 +1903,6 @@ static VkResult init_blit_images(struct wine_device *device, struct wine_swapcha device->funcs.p_vkDestroyDescriptorPool(device->device, swapchain->descriptor_pool, NULL); swapchain->descriptor_pool = VK_NULL_HANDLE; - device->funcs.p_vkFreeMemory(device->device, swapchain->blit_image_memory, NULL); - swapchain->blit_image_memory = VK_NULL_HANDLE; - device->funcs.p_vkDestroySampler(device->device, swapchain->sampler, NULL); swapchain->sampler = VK_NULL_HANDLE; @@ -1967,7 +1915,6 @@ static void destroy_fs_hack_image(struct wine_device *device, struct wine_swapch device->funcs.p_vkDestroyImageView(device->device, hack->user_view, NULL); device->funcs.p_vkDestroyImageView(device->device, hack->blit_view, NULL); device->funcs.p_vkDestroyImage(device->device, hack->user_image, NULL); - device->funcs.p_vkDestroyImage(device->device, hack->blit_image, NULL); if (hack->cmd) device->funcs.p_vkFreeCommandBuffers(device->device, swapchain->cmd_pools[hack->cmd_queue_idx], 1, &hack->cmd); @@ -1975,7 +1922,7 @@ static void destroy_fs_hack_image(struct wine_device *device, struct wine_swapch } static VkResult init_fs_hack_images(struct wine_device *device, struct wine_swapchain *swapchain, - VkSwapchainCreateInfoKHR *createinfo) + const VkSwapchainCreateInfoKHR *createinfo) { VkResult res; VkImage *real_images = NULL; @@ -2033,11 +1980,17 @@ static VkResult init_fs_hack_images(struct wine_device *device, struct wine_swap imageInfo.format = createinfo->imageFormat; imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.usage = createinfo->imageUsage | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + imageInfo.usage = createinfo->imageUsage | VK_IMAGE_USAGE_SAMPLED_BIT; imageInfo.sharingMode = createinfo->imageSharingMode; imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageInfo.queueFamilyIndexCount = createinfo->queueFamilyIndexCount; imageInfo.pQueueFamilyIndices = createinfo->pQueueFamilyIndices; + + if (createinfo->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) + imageInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT; + else if (createinfo->imageFormat != VK_FORMAT_B8G8R8A8_SRGB) + imageInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + res = device->funcs.p_vkCreateImage(device->device, &imageInfo, NULL, &hack->user_image); if (res != VK_SUCCESS) { @@ -2113,7 +2066,7 @@ static VkResult init_fs_hack_images(struct wine_device *device, struct wine_swap viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = swapchain->fs_hack_images[i].user_image; viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.format = createinfo->imageFormat; + viewInfo.format = VK_FORMAT_B8G8R8A8_SRGB; viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; viewInfo.subresourceRange.baseMipLevel = 0; viewInfo.subresourceRange.levelCount = 1; @@ -2185,13 +2138,14 @@ VkResult wine_vkCreateSwapchainKHR(VkDevice device_handle, const VkSwapchainCrea return res; } - object->surface_usage = caps.supportedUsageFlags; - TRACE("surface usage flags: 0x%x\n", object->surface_usage); + if (!(caps.supportedUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT)) + FIXME("Swapchain does not support required VK_IMAGE_USAGE_STORAGE_BIT\n"); create_info_host.imageExtent = object->real_extent; - create_info_host.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; /* XXX: check if supported by surface */ + create_info_host.imageFormat = VK_FORMAT_B8G8R8A8_UNORM; + create_info_host.imageUsage = VK_IMAGE_USAGE_STORAGE_BIT; - if (create_info_host.imageFormat != VK_FORMAT_B8G8R8A8_UNORM && create_info_host.imageFormat != VK_FORMAT_B8G8R8A8_SRGB) + if (info->imageFormat != VK_FORMAT_B8G8R8A8_UNORM && info->imageFormat != VK_FORMAT_B8G8R8A8_SRGB) FIXME("swapchain image format is not BGRA8 UNORM/SRGB. Things may go badly. %d\n", create_info_host.imageFormat); object->fs_hack_enabled = TRUE; @@ -2209,7 +2163,7 @@ VkResult wine_vkCreateSwapchainKHR(VkDevice device_handle, const VkSwapchainCrea { object->user_extent = info->imageExtent; - res = init_fs_hack_images(device, object, &create_info_host); + res = init_fs_hack_images(device, object, info); if (res != VK_SUCCESS) { ERR("creating fs hack images failed: %d\n", res); @@ -2219,8 +2173,6 @@ VkResult wine_vkCreateSwapchainKHR(VkDevice device_handle, const VkSwapchainCrea return res; } - /* FIXME: would be nice to do this on-demand, but games can use up all - * memory so we fail to allocate later */ res = init_blit_images(device, object); if (res != VK_SUCCESS) { @@ -2683,7 +2635,6 @@ void wine_vkDestroySwapchainKHR(VkDevice device_handle, VkSwapchainKHR handle, c device->funcs.p_vkDestroyDescriptorPool(device->device, swapchain->descriptor_pool, NULL); device->funcs.p_vkDestroySampler(device->device, swapchain->sampler, NULL); device->funcs.p_vkFreeMemory(device->device, swapchain->user_image_memory, NULL); - device->funcs.p_vkFreeMemory(device->device, swapchain->blit_image_memory, NULL); free(swapchain->cmd_pools); free(swapchain->fs_hack_images); } @@ -2754,22 +2705,12 @@ static VkResult record_compute_cmd(struct wine_device *device, struct wine_swapc struct fs_hack_image *hack) { VkResult result; - VkImageCopy region = {0}; VkImageMemoryBarrier barriers[3] = {{0}}; VkCommandBufferBeginInfo beginInfo = {0}; float constants[4]; TRACE("recording compute command\n"); -#if 0 - /* DOOM runs out of memory when allocating blit images after loading. */ - if(!swapchain->blit_image_memory){ - result = init_blit_images(device, swapchain); - if(result != VK_SUCCESS) - return result; - } -#endif - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; @@ -2792,13 +2733,13 @@ static VkResult record_compute_cmd(struct wine_device *device, struct wine_swapc barriers[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; /* storage image... */ - /* transition blit image from whatever to GENERAL */ + /* transition swapchain image from whatever to GENERAL */ barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; barriers[1].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; barriers[1].newLayout = VK_IMAGE_LAYOUT_GENERAL; barriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[1].image = hack->blit_image ? hack->blit_image : hack->swapchain_image; + barriers[1].image = hack->swapchain_image; barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; barriers[1].subresourceRange.baseMipLevel = 0; barriers[1].subresourceRange.levelCount = 1; @@ -2819,6 +2760,11 @@ static VkResult record_compute_cmd(struct wine_device *device, struct wine_swapc /* vec2: blit dst offset in real coords */ constants[0] = swapchain->blit_dst.offset.x; constants[1] = swapchain->blit_dst.offset.y; + + /* offset by 0.5f because sampling is relative to pixel center */ + constants[0] -= 0.5f * swapchain->blit_dst.extent.width / swapchain->user_extent.width; + constants[1] -= 0.5f * swapchain->blit_dst.extent.height / swapchain->user_extent.height; + /* vec2: blit dst extents in real coords */ constants[2] = swapchain->blit_dst.extent.width; constants[3] = swapchain->blit_dst.extent.height; @@ -2844,234 +2790,22 @@ static VkResult record_compute_cmd(struct wine_device *device, struct wine_swapc barriers[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT; barriers[0].dstAccessMask = 0; - device->funcs.p_vkCmdPipelineBarrier( - hack->cmd, - VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - 0, - 0, NULL, - 0, NULL, - 1, barriers - ); - - if (hack->blit_image) - { - /* for the copy... */ - /* no transition, just a barrier for our access masks (w -> r) */ - barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barriers[0].oldLayout = VK_IMAGE_LAYOUT_GENERAL; - barriers[0].newLayout = VK_IMAGE_LAYOUT_GENERAL; - barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[0].image = hack->blit_image; - barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barriers[0].subresourceRange.baseMipLevel = 0; - barriers[0].subresourceRange.levelCount = 1; - barriers[0].subresourceRange.baseArrayLayer = 0; - barriers[0].subresourceRange.layerCount = 1; - barriers[0].srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - barriers[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - - /* for the copy... */ - /* transition swapchain image from whatever to TRANSFER_DST - * we don't care about the contents... */ - barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barriers[1].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - barriers[1].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[1].image = hack->swapchain_image; - barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barriers[1].subresourceRange.baseMipLevel = 0; - barriers[1].subresourceRange.levelCount = 1; - barriers[1].subresourceRange.baseArrayLayer = 0; - barriers[1].subresourceRange.layerCount = 1; - barriers[1].srcAccessMask = 0; - barriers[1].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - - device->funcs.p_vkCmdPipelineBarrier(hack->cmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 2, barriers); - - /* copy from blit image to swapchain image */ - region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.srcSubresource.layerCount = 1; - region.srcOffset.x = 0; - region.srcOffset.y = 0; - region.srcOffset.z = 0; - region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.dstSubresource.layerCount = 1; - region.dstOffset.x = 0; - region.dstOffset.y = 0; - region.dstOffset.z = 0; - region.extent.width = swapchain->real_extent.width; - region.extent.height = swapchain->real_extent.height; - region.extent.depth = 1; - - device->funcs.p_vkCmdCopyImage(hack->cmd, hack->blit_image, VK_IMAGE_LAYOUT_GENERAL, - hack->swapchain_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - - /* transition swapchain image from TRANSFER_DST_OPTIMAL to PRESENT_SRC */ - barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barriers[0].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[0].image = hack->swapchain_image; - barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barriers[0].subresourceRange.baseMipLevel = 0; - barriers[0].subresourceRange.levelCount = 1; - barriers[0].subresourceRange.baseArrayLayer = 0; - barriers[0].subresourceRange.layerCount = 1; - barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barriers[0].dstAccessMask = 0; - - device->funcs.p_vkCmdPipelineBarrier(hack->cmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, barriers); - } - else - { - /* transition swapchain image from GENERAL to PRESENT_SRC */ - barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barriers[0].oldLayout = VK_IMAGE_LAYOUT_GENERAL; - barriers[0].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[0].image = hack->swapchain_image; - barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barriers[0].subresourceRange.baseMipLevel = 0; - barriers[0].subresourceRange.levelCount = 1; - barriers[0].subresourceRange.baseArrayLayer = 0; - barriers[0].subresourceRange.layerCount = 1; - barriers[0].srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - barriers[0].dstAccessMask = 0; - - device->funcs.p_vkCmdPipelineBarrier(hack->cmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, barriers); - } - - result = device->funcs.p_vkEndCommandBuffer(hack->cmd); - if (result != VK_SUCCESS) - { - ERR("vkEndCommandBuffer: %d\n", result); - return result; - } - - return VK_SUCCESS; -} - -static VkResult record_graphics_cmd(struct wine_device *device, struct wine_swapchain *swapchain, - struct fs_hack_image *hack) -{ - VkClearColorValue black = {{0.f, 0.f, 0.f}}; - VkCommandBufferBeginInfo beginInfo = {0}; - VkImageMemoryBarrier barriers[2] = {{0}}; - VkImageSubresourceRange range = {0}; - VkImageBlit blitregion = {0}; - VkResult result; - - TRACE("recording graphics command\n"); - - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; - - device->funcs.p_vkBeginCommandBuffer(hack->cmd, &beginInfo); - - /* transition real image from whatever to TRANSFER_DST_OPTIMAL */ - barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barriers[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - barriers[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[0].image = hack->swapchain_image; - barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barriers[0].subresourceRange.baseMipLevel = 0; - barriers[0].subresourceRange.levelCount = 1; - barriers[0].subresourceRange.baseArrayLayer = 0; - barriers[0].subresourceRange.layerCount = 1; - barriers[0].srcAccessMask = 0; - barriers[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - - /* transition user image from PRESENT_SRC to TRANSFER_SRC_OPTIMAL */ - barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barriers[1].oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - barriers[1].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - barriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[1].image = hack->user_image; - barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barriers[1].subresourceRange.baseMipLevel = 0; - barriers[1].subresourceRange.levelCount = 1; - barriers[1].subresourceRange.baseArrayLayer = 0; - barriers[1].subresourceRange.layerCount = 1; - barriers[1].srcAccessMask = 0; - barriers[1].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - - device->funcs.p_vkCmdPipelineBarrier(hack->cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 2, barriers); - - /* clear the image */ - range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - range.baseMipLevel = 0; - range.levelCount = 1; - range.baseArrayLayer = 0; - range.layerCount = 1; - - device->funcs.p_vkCmdClearColorImage(hack->cmd, hack->swapchain_image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &black, 1, &range); - - /* perform blit */ - blitregion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blitregion.srcSubresource.layerCount = 1; - blitregion.srcOffsets[0].x = 0; - blitregion.srcOffsets[0].y = 0; - blitregion.srcOffsets[0].z = 0; - blitregion.srcOffsets[1].x = swapchain->user_extent.width; - blitregion.srcOffsets[1].y = swapchain->user_extent.height; - blitregion.srcOffsets[1].z = 1; - blitregion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blitregion.dstSubresource.layerCount = 1; - blitregion.dstOffsets[0].x = swapchain->blit_dst.offset.x; - blitregion.dstOffsets[0].y = swapchain->blit_dst.offset.y; - blitregion.dstOffsets[0].z = 0; - blitregion.dstOffsets[1].x = swapchain->blit_dst.offset.x + swapchain->blit_dst.extent.width; - blitregion.dstOffsets[1].y = swapchain->blit_dst.offset.y + swapchain->blit_dst.extent.height; - blitregion.dstOffsets[1].z = 1; - - device->funcs.p_vkCmdBlitImage(hack->cmd, hack->user_image, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, hack->swapchain_image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blitregion, swapchain->fs_hack_filter); - - /* transition real image from TRANSFER_DST to PRESENT_SRC */ - barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barriers[0].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[0].image = hack->swapchain_image; - barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barriers[0].subresourceRange.baseMipLevel = 0; - barriers[0].subresourceRange.levelCount = 1; - barriers[0].subresourceRange.baseArrayLayer = 0; - barriers[0].subresourceRange.layerCount = 1; - barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barriers[0].dstAccessMask = 0; - - /* transition user image from TRANSFER_SRC_OPTIMAL to back to PRESENT_SRC */ + /* transition swapchain image from GENERAL to PRESENT_SRC */ barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barriers[1].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barriers[1].oldLayout = VK_IMAGE_LAYOUT_GENERAL; barriers[1].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; barriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[1].image = hack->user_image; + barriers[1].image = hack->swapchain_image; barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; barriers[1].subresourceRange.baseMipLevel = 0; barriers[1].subresourceRange.levelCount = 1; barriers[1].subresourceRange.baseArrayLayer = 0; barriers[1].subresourceRange.layerCount = 1; - barriers[1].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + barriers[1].srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; barriers[1].dstAccessMask = 0; - device->funcs.p_vkCmdPipelineBarrier(hack->cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, + device->funcs.p_vkCmdPipelineBarrier(hack->cmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 2, barriers); result = device->funcs.p_vkEndCommandBuffer(hack->cmd); @@ -3131,13 +2865,11 @@ VkResult wine_vkQueuePresentKHR(VkQueue queue_handle, const VkPresentInfoKHR *pP return VK_ERROR_DEVICE_LOST; } - if (queue->device->queue_props[queue_idx].queueFlags & VK_QUEUE_GRAPHICS_BIT) - res = record_graphics_cmd(queue->device, swapchain, hack); - else if (queue->device->queue_props[queue_idx].queueFlags & VK_QUEUE_COMPUTE_BIT) + if (queue->device->queue_props[queue_idx].queueFlags & VK_QUEUE_COMPUTE_BIT) /* TODO */ res = record_compute_cmd(queue->device, swapchain, hack); else { - ERR("Present queue is neither graphics nor compute queue!\n"); + ERR("Present queue does not support compute!\n"); res = VK_ERROR_DEVICE_LOST; } diff --git a/dlls/winevulkan/vulkan_loader.h b/dlls/winevulkan/vulkan_loader.h index 311e2ef8f1b..0d0d9c0bee6 100644 --- a/dlls/winevulkan/vulkan_loader.h +++ b/dlls/winevulkan/vulkan_loader.h @@ -158,6 +158,20 @@ struct is_available_device_function_params const char *name; }; +#define wine_vk_find_struct(s, t) wine_vk_find_struct_((void *)s, VK_STRUCTURE_TYPE_##t) +static inline void *wine_vk_find_struct_(void *s, VkStructureType t) +{ + VkBaseOutStructure *header; + + for (header = s; header; header = header->pNext) + { + if (header->sType == t) + return header; + } + + return NULL; +} + #define UNIX_CALL(code, params) WINE_UNIX_CALL(unix_ ## code, params) #endif /* __WINE_VULKAN_LOADER_H */ diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index d84333d7951..a4898389275 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -79,7 +79,6 @@ struct fs_hack_image uint32_t cmd_queue_idx; VkCommandBuffer cmd; VkImage swapchain_image; - VkImage blit_image; VkImage user_image; VkSemaphore blit_finished; VkImageView user_view, blit_view; @@ -95,10 +94,9 @@ struct wine_swapchain BOOL fs_hack_enabled; VkExtent2D user_extent; VkExtent2D real_extent; - VkImageUsageFlags surface_usage; VkRect2D blit_dst; VkCommandPool *cmd_pools; /* VkCommandPool[device->queue_count] */ - VkDeviceMemory user_image_memory, blit_image_memory; + VkDeviceMemory user_image_memory; uint32_t n_images; struct fs_hack_image *fs_hack_images; /* struct fs_hack_image[n_images] */ VkFilter fs_hack_filter; From 2c05c3e6db5a18536db700dba3512e5fba4263d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:10:32 +0100 Subject: [PATCH 0679/2777] fshack: winex11: Support vulkan scaling according to fake resolution. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on work by Zhiyi Zhang, includes work by Giovanni Mascellani, Rémi Bernon, Arkadiusz Hiler, Kai Krakow, Joshua Ashton, Zebediah Figura, and Matteo Bruni. --- dlls/winex11.drv/vulkan.c | 63 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 6ade7c2260c..635ac6dc4cf 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -1073,6 +1073,68 @@ static VkSurfaceKHR X11DRV_wine_get_native_surface(VkSurfaceKHR surface) return x11_surface->surface; } +static VkBool32 X11DRV_query_fs_hack( VkSurfaceKHR surface, VkExtent2D *real_sz, + VkExtent2D *user_sz, VkRect2D *dst_blit, VkFilter *filter ) +{ + struct wine_vk_surface *x11_surface = surface_from_handle( surface ); + HMONITOR monitor; + HWND hwnd; + + if (wm_is_steamcompmgr( gdi_display )) return VK_FALSE; + if (x11_surface->other_process) return VK_FALSE; + + if (XFindContext( gdi_display, x11_surface->window, winContext, (char **)&hwnd ) != 0) + { + ERR( "Failed to find hwnd context\n" ); + return VK_FALSE; + } + + monitor = fs_hack_monitor_from_hwnd( hwnd ); + if (fs_hack_enabled( monitor )) + { + RECT real_rect = fs_hack_real_mode( monitor ); + RECT user_rect = fs_hack_current_mode( monitor ); + SIZE scaled = fs_hack_get_scaled_screen_size( monitor ); + POINT scaled_origin; + + scaled_origin.x = user_rect.left; + scaled_origin.y = user_rect.top; + fs_hack_point_user_to_real( &scaled_origin ); + scaled_origin.x -= real_rect.left; + scaled_origin.y -= real_rect.top; + + TRACE( "real_rect:%s user_rect:%s scaled:%dx%d scaled_origin:%s\n", + wine_dbgstr_rect( &real_rect ), wine_dbgstr_rect( &user_rect ), + (int)scaled.cx, (int)scaled.cy, wine_dbgstr_point( &scaled_origin ) ); + + if (real_sz) + { + real_sz->width = real_rect.right - real_rect.left; + real_sz->height = real_rect.bottom - real_rect.top; + } + + if (user_sz) + { + user_sz->width = user_rect.right - user_rect.left; + user_sz->height = user_rect.bottom - user_rect.top; + } + + if (dst_blit) + { + dst_blit->offset.x = scaled_origin.x; + dst_blit->offset.y = scaled_origin.y; + dst_blit->extent.width = scaled.cx; + dst_blit->extent.height = scaled.cy; + } + + if (filter) *filter = fs_hack_is_integer() ? VK_FILTER_NEAREST : VK_FILTER_LINEAR; + + return VK_TRUE; + } + + return VK_FALSE; +} + static const struct vulkan_funcs vulkan_funcs = { X11DRV_vkAcquireNextImage2KHR, @@ -1099,6 +1161,7 @@ static const struct vulkan_funcs vulkan_funcs = X11DRV_vkQueuePresentKHR, X11DRV_wine_get_native_surface, + X11DRV_query_fs_hack, }; static void *X11DRV_get_vk_device_proc_addr(const char *name) From 509c88b3615b3f997bce5dd4a03e013c62d88060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:24:41 +0100 Subject: [PATCH 0680/2777] fshack: winex11: Simply scale offscreen vulkan surfaces. They will be copied manually onto the screen, so we don't need to scale them to the screen dimensions. CW-Bug-Id: 16608 --- dlls/winex11.drv/vulkan.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 635ac6dc4cf..8f9b08135b9 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -1090,7 +1090,7 @@ static VkBool32 X11DRV_query_fs_hack( VkSurfaceKHR surface, VkExtent2D *real_sz, } monitor = fs_hack_monitor_from_hwnd( hwnd ); - if (fs_hack_enabled( monitor )) + if (fs_hack_enabled( monitor ) && !x11_surface->offscreen) { RECT real_rect = fs_hack_real_mode( monitor ); RECT user_rect = fs_hack_current_mode( monitor ); @@ -1131,6 +1131,37 @@ static VkBool32 X11DRV_query_fs_hack( VkSurfaceKHR surface, VkExtent2D *real_sz, return VK_TRUE; } + else if (fs_hack_enabled( monitor )) + { + double scale = fs_hack_get_user_to_real_scale( monitor ); + RECT client_rect; + + NtUserGetClientRect( hwnd, &client_rect ); + + if (real_sz) + { + real_sz->width = (client_rect.right - client_rect.left) * scale; + real_sz->height = (client_rect.bottom - client_rect.top) * scale; + } + + if (user_sz) + { + user_sz->width = client_rect.right - client_rect.left; + user_sz->height = client_rect.bottom - client_rect.top; + } + + if (dst_blit) + { + dst_blit->offset.x = client_rect.left * scale; + dst_blit->offset.y = client_rect.top * scale; + dst_blit->extent.width = (client_rect.right - client_rect.left) * scale; + dst_blit->extent.height = (client_rect.bottom - client_rect.top) * scale; + } + + if (filter) *filter = fs_hack_is_integer() ? VK_FILTER_NEAREST : VK_FILTER_LINEAR; + + return VK_TRUE; + } return VK_FALSE; } From 33ee3441954bc2e8a85522c5e9c68bd328cc7387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 17 May 2021 10:54:27 +0200 Subject: [PATCH 0681/2777] fshack: winex11: Transform X11DRV_FLUSH_VK_DRAWABLE rects. CW-Bug-Id: #16608 --- dlls/winex11.drv/init.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index c23c0f0645e..bd53421dd5b 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -249,13 +249,15 @@ static INT CDECL X11DRV_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOI { const struct x11drv_escape_present_drawable *data = in_data; RECT rect = physDev->dc_rect; + RECT real_rect = physDev->dc_rect; + fs_hack_rect_user_to_real( &real_rect ); OffsetRect( &rect, -physDev->dc_rect.left, -physDev->dc_rect.top ); if (data->flush) XFlush( gdi_display ); XSetFunction( gdi_display, physDev->gc, GXcopy ); XCopyArea( gdi_display, data->drawable, physDev->drawable, physDev->gc, - 0, 0, rect.right, rect.bottom, - physDev->dc_rect.left, physDev->dc_rect.top ); + 0, 0, real_rect.right - real_rect.left, real_rect.bottom - real_rect.top, + real_rect.left, real_rect.top ); add_device_bounds( physDev, &rect ); return TRUE; } From 59f41e0d65f55cbe4ca1ba6d9475c1d655d703d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:16:41 +0100 Subject: [PATCH 0682/2777] fshack: winex11: Clear fs hack depth / stencil attachment. --- dlls/winex11.drv/opengl.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 29a550bbd84..eb696d2ea97 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2060,7 +2060,8 @@ static void fs_hack_get_attachments_config( struct gl_drawable *gl, struct fs_ha 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; - float prev_clear_color[4]; + float prev_clear_color[4], prev_clear_depth; + int prev_clear_stencil; unsigned int i; struct fs_hack_fbo_attachments_config config; struct fs_hack_fbconfig_attribs attribs; @@ -2103,6 +2104,8 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * opengl_funcs.gl.p_glGetIntegerv( GL_TEXTURE_BINDING_2D, (GLint *)&prev_texture ); opengl_funcs.gl.p_glGetIntegerv( GL_RENDERBUFFER_BINDING, (GLint *)&prev_renderbuffer ); opengl_funcs.gl.p_glGetFloatv( GL_COLOR_CLEAR_VALUE, prev_clear_color ); + opengl_funcs.gl.p_glGetFloatv( GL_DEPTH_CLEAR_VALUE, &prev_clear_depth ); + opengl_funcs.gl.p_glGetIntegerv( GL_STENCIL_CLEAR_VALUE, &prev_clear_stencil ); TRACE( "Previous draw FBO %u, read FBO %u for ctx %p\n", prev_draw_fbo, prev_read_fbo, ctx ); if (!ctx->fs_hack_fbo) @@ -2189,13 +2192,23 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * } } - opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); - if (!gl->fs_hack_context_set_up) opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT ); + 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 ); + } pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); pglDrawBuffer( GL_BACK ); - if (!gl->fs_hack_context_set_up) opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT ); - opengl_funcs.gl.p_glClearColor( prev_clear_color[0], prev_clear_color[1], - prev_clear_color[2], prev_clear_color[3] ); + if (!gl->fs_hack_context_set_up) + { + opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT ); + opengl_funcs.gl.p_glClearColor( prev_clear_color[0], prev_clear_color[1], + prev_clear_color[2], prev_clear_color[3] ); + opengl_funcs.gl.p_glClearDepth( prev_clear_depth ); + opengl_funcs.gl.p_glClearStencil( prev_clear_stencil ); + } wglBindFramebuffer( GL_DRAW_FRAMEBUFFER, prev_draw_fbo ); wglBindFramebuffer( GL_READ_FRAMEBUFFER, prev_read_fbo ); From 9c088990e47ebc0d38bd95fd43a8af6cd633ea4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 21:11:10 +0100 Subject: [PATCH 0683/2777] fshack: winex11: Support adjusting gamma in the fshack CW-Bug-Id: 16421 --- dlls/winex11.drv/fs.c | 34 ++ dlls/winex11.drv/opengl.c | 665 ++++++++++++++++++++++++++++++++---- dlls/winex11.drv/x11drv.h | 2 + dlls/winex11.drv/xvidmode.c | 22 +- 4 files changed, 648 insertions(+), 75 deletions(-) diff --git a/dlls/winex11.drv/fs.c b/dlls/winex11.drv/fs.c index 851ff888e64..bf1766cfb15 100644 --- a/dlls/winex11.drv/fs.c +++ b/dlls/winex11.drv/fs.c @@ -84,6 +84,10 @@ struct fs_monitor static pthread_mutex_t fs_lock = PTHREAD_MUTEX_INITIALIZER; static struct list fs_monitors = LIST_INIT( fs_monitors ); +static WORD gamma_ramp_i[GAMMA_RAMP_SIZE * 3]; +static float gamma_ramp[GAMMA_RAMP_SIZE * 4]; +static LONG gamma_serial; + #define NEXT_DEVMODEW(mode) ((DEVMODEW *)((char *)((mode) + 1) + (mode)->dmDriverExtra)) static const char *debugstr_devmode( const DEVMODEW *devmode ) @@ -935,3 +939,33 @@ void fs_hack_init(void) initialized = TRUE; } + +const float *fs_hack_get_gamma_ramp( LONG *serial ) +{ + if (gamma_serial == 0) return NULL; + if (serial) *serial = gamma_serial; + return gamma_ramp; +} + +void fs_hack_set_gamma_ramp( const WORD *ramp ) +{ + int i; + if (memcmp( gamma_ramp_i, ramp, sizeof(gamma_ramp_i) ) == 0) + { + /* identical */ + return; + } + for (i = 0; i < GAMMA_RAMP_SIZE; ++i) + { + gamma_ramp[i * 4] = ramp[i] / 65535.f; + gamma_ramp[i * 4 + 1] = ramp[i + GAMMA_RAMP_SIZE] / 65535.f; + gamma_ramp[i * 4 + 2] = ramp[i + 2 * GAMMA_RAMP_SIZE] / 65535.f; + } + memcpy( gamma_ramp_i, ramp, sizeof(gamma_ramp_i) ); + InterlockedIncrement( &gamma_serial ); + TRACE( "new gamma serial: %u\n", (int)gamma_serial ); + if (gamma_serial == 0) + { + InterlockedIncrement( &gamma_serial ); + } +} diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index eb696d2ea97..2ba04e23449 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -212,9 +212,11 @@ struct wgl_context BOOL refresh_drawables; BOOL fs_hack; BOOL fs_hack_integer; + BOOL is_core; GLuint fs_hack_fbo, fs_hack_resolve_fbo; GLuint fs_hack_color_texture, fs_hack_ds_texture; - GLuint fs_hack_color_renderbuffer, fs_hack_color_resolve_renderbuffer, fs_hack_ds_renderbuffer; + GLuint fs_hack_color_renderbuffer, fs_hack_ds_renderbuffer; + GLuint fs_hack_gamma_pgm, ramp_ubo; POINT setup_for; GLuint current_draw_fbo, current_read_fbo; struct list entry; @@ -254,6 +256,11 @@ struct gl_drawable BOOL fs_hack_did_swapbuf; BOOL fs_hack_context_set_up; BOOL has_scissor_indexed; + BOOL has_clip_control; + BOOL has_ati_frag_shader; + BOOL has_fragment_program; + BOOL has_vertex_program; + LONG last_gamma_serial; }; struct wgl_pbuffer @@ -390,10 +397,6 @@ static int (*pglXSwapIntervalSGI)(int); static void* (*pglXAllocateMemoryNV)(GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); static void (*pglXFreeMemoryNV)(GLvoid *pointer); -static void (*pglScissorIndexed)( GLuint, GLint, GLint, GLsizei, GLsizei ); -static void (*pglScissorIndexedv)( GLuint, const GLint * ); -static void (*pglGetIntegeri_v)( GLenum, GLuint, GLint * ); - /* MESA GLX Extensions */ static void (*pglXCopySubBufferMESA)(Display *dpy, GLXDrawable drawable, int x, int y, int width, int height); static int (*pglXSwapIntervalMESA)(unsigned int interval); @@ -418,23 +421,59 @@ static void wglFlush(void); static const GLubyte *wglGetString(GLenum name); /* Fullscreen hack */ +static void (*pglActiveTexture)( GLenum texture ); +static void (*pglAttachShader)( GLuint program, GLuint shader ); +static void (*pglBindBuffer)( GLenum target, GLuint buffer ); +static void (*pglBindBufferBase)( GLenum target, GLuint index, GLuint buffer ); +static void (*pglBindBufferRange)( GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size ); static void (*pglBindFramebuffer)( GLenum target, GLuint framebuffer ); static void (*pglBindFramebufferEXT)( GLenum target, GLuint framebuffer ); static void (*pglBindRenderbuffer)( GLenum target, GLuint renderbuffer ); +static void (*pglBindSampler)( GLuint target, GLuint sampler ); static void (*pglBlitFramebuffer)( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter ); -void (*pglDeleteFramebuffers)( GLsizei n, const GLuint *framebuffers ); -void (*pglDeleteRenderbuffers)( GLsizei n, const GLuint *renderbuffers ); +static void (*pglBufferData)( GLenum target, GLsizeiptr size, const void *data, GLenum usage ); +static void (*pglClipControl)( GLenum origin, GLenum depth ); +static void (*pglColorMaski)( GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a ); +static void (*pglCompileShader)( GLuint shader ); +static GLuint (*pglCreateProgram)(void); +static GLuint (*pglCreateShader)( GLenum type ); +static void (*pglDeleteBuffers)( GLsizei n, GLuint *buffers ); +static void (*pglDeleteFramebuffers)( GLsizei n, const GLuint *framebuffers ); +static void (*pglDeleteProgram)( GLuint program ); +static void (*pglDeleteRenderbuffers)( GLsizei n, const GLuint *renderbuffers ); +static void (*pglDeleteShader)( GLuint shader ); +static void (*pglDrawArrays)( GLenum mode, GLint first, GLsizei count ); static void (*pglDrawBuffer)( GLenum buffer ); static void (*pglFramebufferRenderbuffer)( GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer ); static void (*pglFramebufferTexture2D)( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ); +static void (*pglGenBuffers)( GLsizei n, GLuint *buffers ); static void (*pglGenFramebuffers)( GLsizei n, GLuint *ids ); +static void (*pglGetBooleani_v)( GLenum target, GLuint index, GLboolean *data ); +static void (*pglGetInteger64i_v)( GLenum target, GLuint index, GLint64 *data ); +static void (*pglGetIntegeri_v)( GLenum, GLuint, GLint * ); +static void (*pglGetFloati_v)( GLenum, GLuint, GLfloat * ); static void (*pglGenRenderbuffers)( GLsizei n, GLuint *renderbuffers ); +static void (*pglGetProgramiv)( GLuint program, GLenum pname, GLint *params ); +static void (*pglGetProgramInfoLog)( GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog ); +static void (*pglGetShaderiv)( GLuint shader, GLenum pname, GLint *params ); +static void (*pglGetShaderInfoLog)( GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog ); +static GLuint (*pglGetUniformBlockIndex)( GLuint program, const GLchar *uniformBlockName ); +static GLint (*pglGetUniformLocation)( GLuint program, const GLchar *name ); +static void (*pglLinkProgram)( GLuint program ); static void (*pglReadBuffer)( GLenum src ); static void (*pglRenderbufferStorage)( GLenum target, GLenum internalformat, GLsizei width, GLsizei height ); static void (*pglRenderbufferStorageMultisample)( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height ); - +static void (*pglScissorIndexed)( GLuint, GLint, GLint, GLsizei, GLsizei ); +static void (*pglScissorIndexedv)( GLuint, const GLint * ); +static void (*pglShaderSource)( GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length ); +static void (*pglUniformBlockBinding)( GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding ); +static void (*pglUniform1i)( GLint location, GLint v0 ); +static void (*pglUseProgram)( GLuint program ); +static void (*pglViewportIndexedf)( GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h ); +static void (*pglViewportIndexedfv)( GLuint index, const GLfloat *v ); +static void (*pglGetFramebufferAttachmentParameteriv)( GLenum target, GLenum attachment, GLenum pname, GLint *params ); static void wglBindFramebuffer( GLenum target, GLuint framebuffer ); static void wglBindFramebufferEXT( GLenum target, GLuint framebuffer ); static void wglDrawBuffer( GLenum buffer ); @@ -631,18 +670,55 @@ static void init_opengl(void) /* Fullscreen hack */ #define LOAD_FUNCPTR(func) p##func = (void *)pglXGetProcAddressARB((const unsigned char *)#func); + LOAD_FUNCPTR( glActiveTexture ); + LOAD_FUNCPTR( glAttachShader ); + LOAD_FUNCPTR( glBindBuffer ); + LOAD_FUNCPTR( glBindBufferBase ); + LOAD_FUNCPTR( glBindBufferRange ); LOAD_FUNCPTR( glBindFramebuffer ); LOAD_FUNCPTR( glBindFramebufferEXT ); LOAD_FUNCPTR( glBindRenderbuffer ); + LOAD_FUNCPTR( glBindSampler ); LOAD_FUNCPTR( glBlitFramebuffer ); + LOAD_FUNCPTR( glBufferData ); + LOAD_FUNCPTR( glClipControl ); + LOAD_FUNCPTR( glColorMaski ); + LOAD_FUNCPTR( glCompileShader ); + LOAD_FUNCPTR( glCreateProgram ); + LOAD_FUNCPTR( glCreateShader ); + LOAD_FUNCPTR( glDeleteBuffers ); LOAD_FUNCPTR( glDeleteFramebuffers ); + LOAD_FUNCPTR( glDeleteProgram ); LOAD_FUNCPTR( glDeleteRenderbuffers ); + LOAD_FUNCPTR( glDeleteShader ); + LOAD_FUNCPTR( glDrawArrays ); LOAD_FUNCPTR( glFramebufferRenderbuffer ); LOAD_FUNCPTR( glFramebufferTexture2D ); + LOAD_FUNCPTR( glGenBuffers ); LOAD_FUNCPTR( glGenFramebuffers ); + LOAD_FUNCPTR( glGetBooleani_v ); + LOAD_FUNCPTR( glGetInteger64i_v ); + LOAD_FUNCPTR( glGetIntegeri_v ); + LOAD_FUNCPTR( glGetFloati_v ); LOAD_FUNCPTR( glGenRenderbuffers ); + LOAD_FUNCPTR( glGetProgramiv ); + LOAD_FUNCPTR( glGetProgramInfoLog ); + LOAD_FUNCPTR( glGetShaderiv ); + LOAD_FUNCPTR( glGetShaderInfoLog ); + LOAD_FUNCPTR( glGetUniformBlockIndex ); + LOAD_FUNCPTR( glGetUniformLocation ); + LOAD_FUNCPTR( glLinkProgram ); LOAD_FUNCPTR( glRenderbufferStorage ); LOAD_FUNCPTR( glRenderbufferStorageMultisample ); + LOAD_FUNCPTR( glScissorIndexed ); + LOAD_FUNCPTR( glScissorIndexedv ); + LOAD_FUNCPTR( glShaderSource ); + LOAD_FUNCPTR( glUniformBlockBinding ); + LOAD_FUNCPTR( glUniform1i ); + LOAD_FUNCPTR( glUseProgram ); + LOAD_FUNCPTR( glViewportIndexedf ); + LOAD_FUNCPTR( glViewportIndexedfv ); + LOAD_FUNCPTR( glGetFramebufferAttachmentParameteriv ); #undef LOAD_FUNCPTR #define LOAD_FUNCPTR(f) do if((p##f = (void*)pglXGetProcAddressARB((const unsigned char*)#f)) == NULL) \ @@ -695,10 +771,6 @@ static void init_opengl(void) /* NV GLX Extension */ LOAD_FUNCPTR(glXAllocateMemoryNV); LOAD_FUNCPTR(glXFreeMemoryNV); - - LOAD_FUNCPTR(glScissorIndexed); - LOAD_FUNCPTR(glScissorIndexedv); - LOAD_FUNCPTR(glGetIntegeri_v); #undef LOAD_FUNCPTR if(!X11DRV_WineGL_InitOpenglInfo()) goto failed; @@ -789,13 +861,6 @@ static void init_opengl(void) pglXSwapBuffersMscOML = pglXGetProcAddressARB( (const GLubyte *)"glXSwapBuffersMscOML" ); } - if (has_extension( glExtensions, "GL_ARB_viewport_array" )) - { - opengl_funcs.ext.p_glGetIntegeri_v = pglGetIntegeri_v; - opengl_funcs.ext.p_glScissorIndexed = pglScissorIndexed; - opengl_funcs.ext.p_glScissorIndexedv = pglScissorIndexedv; - } - X11DRV_WineGL_LoadExtensions(); init_pixel_formats( gdi_display ); return; @@ -1612,7 +1677,7 @@ void sync_gl_drawable( HWND hwnd, BOOL known_child ) if (DC_GL_PIXMAP_WIN != old->type) { data = get_win_data( hwnd ); - old->fs_hack = data->fs_hack; + old->fs_hack = data->fs_hack || fs_hack_get_gamma_ramp( NULL ) != NULL; if (old->fs_hack) TRACE( "Window %p has the fullscreen hack enabled\n", hwnd ); release_win_data( data ); } @@ -2015,7 +2080,6 @@ struct fs_hack_fbconfig_attribs int stencil_size; int doublebuffer; int samples; - int srgb; }; struct fs_hack_fbo_attachments_config @@ -2037,8 +2101,7 @@ static void fs_hack_get_attachments_config( struct gl_drawable *gl, struct fs_ha if (attribs->red_size != 8 || attribs->green_size != 8 || attribs->blue_size != 8) FIXME( "Unsupported RGBA color sizes {%u, %u, %u, %u}.\n", attribs->red_size, attribs->green_size, attribs->blue_size, attribs->alpha_size ); - if (attribs->srgb) config->color_internalformat = attribs->alpha_size ? GL_SRGB8_ALPHA8 : GL_SRGB8; - else config->color_internalformat = attribs->alpha_size ? GL_RGBA8 : GL_RGB8; + config->color_internalformat = attribs->alpha_size ? GL_SRGB8_ALPHA8 : GL_SRGB8; config->color_format = GL_BGRA; config->color_type = GL_UNSIGNED_INT_8_8_8_8_REV; if (attribs->depth_size || attribs->stencil_size) @@ -2057,6 +2120,162 @@ static void fs_hack_get_attachments_config( struct gl_drawable *gl, struct fs_ha config->samples = attribs->samples; } +static const float *fs_hack_get_default_gamma_ramp(void) +{ + static float default_gamma_ramp[GAMMA_RAMP_SIZE * 4]; + static BOOL initialized; + unsigned int i; + + if (!initialized) + { + for (i = 0; i < GAMMA_RAMP_SIZE; i++) + default_gamma_ramp[i * 4] = default_gamma_ramp[i * 4 + 1] = default_gamma_ramp[i * 4 + 2] = i / (float)( GAMMA_RAMP_SIZE - 1 ); + initialized = TRUE; + } + return default_gamma_ramp; +} + +static const char *fs_hack_gamma_vertex_shader_src = +"#version 330\n" +"\n" +"const vec4 square[4] = vec4[4](\n" +" vec4(-1.0, -1.0, 0.0, 1.0),\n" +" vec4(-1.0, 1.0, 0.0, 1.0),\n" +" vec4(1.0, -1.0, 0.0, 1.0),\n" +" vec4(1.0, 1.0, 0.0, 1.0)\n" +");\n" +"const vec2 texsq[4] = vec2[4](\n" +" vec2(0.0, 0.0),\n" +" vec2(0.0, 1.0),\n" +" vec2(1.0, 0.0),\n" +" vec2(1.0, 1.0)\n" +");\n" +"\n" +"out vec2 texCoord;\n" +"\n" +"void main(void)\n" +"{\n" +" gl_Position = square[gl_VertexID];\n" +" texCoord = texsq[gl_VertexID];\n" +"}\n" +; + +static const char *fs_hack_gamma_frag_shader_src = +"#version 330\n" +"\n" +"uniform sampler2D tex;\n" +"in vec2 texCoord;\n" +"layout (std140) uniform ramp {\n" +" vec3 values[256];\n" +"};\n" +"\n" +"layout(location = 0) out vec4 outColor;\n" +"\n" +"void main(void)\n" +"{\n" +" vec4 lookup = texture(tex, texCoord) * 255.0;\n" +" outColor.r = values[int(lookup.r)].r;\n" +" outColor.g = values[int(lookup.g)].g;\n" +" outColor.b = values[int(lookup.b)].b;\n" +" outColor.a = 1.0;\n" +"}\n" +; + +static void fs_hack_setup_gamma_shader( struct wgl_context *ctx, struct gl_drawable *gl ) +{ + GLint success; + GLuint vshader, fshader, program, ramp_index, tex_loc, prev_program; + char errstr[512]; + const float *default_gamma_ramp = fs_hack_get_default_gamma_ramp(); + + opengl_funcs.gl.p_glGetIntegerv( GL_CURRENT_PROGRAM, (GLint *)&prev_program ); + /* vertex shader */ + vshader = pglCreateShader( GL_VERTEX_SHADER ); + if (vshader == 0) + { + ERR( "Failed to create gamma vertex shader\n" ); + return; + } + pglShaderSource( vshader, 1, &fs_hack_gamma_vertex_shader_src, NULL ); + pglCompileShader( vshader ); + + pglGetShaderiv( vshader, GL_COMPILE_STATUS, &success ); + if (!success) + { + pglGetShaderInfoLog( vshader, sizeof(errstr), NULL, errstr ); + ERR( "Compiling gamma vertex shader failed: %s\n", errstr ); + pglDeleteShader( vshader ); + return; + } + + /* fragment shader */ + fshader = pglCreateShader( GL_FRAGMENT_SHADER ); + if (fshader == 0) + { + ERR( "Failed to create gamma fragment shader\n" ); + pglDeleteShader( vshader ); + return; + } + pglShaderSource( fshader, 1, &fs_hack_gamma_frag_shader_src, NULL ); + pglCompileShader( fshader ); + + pglGetShaderiv( fshader, GL_COMPILE_STATUS, &success ); + if (!success) + { + pglGetShaderInfoLog( fshader, sizeof(errstr), NULL, errstr ); + ERR( "Compiling gamma fragment shader failed: %s\n", errstr ); + pglDeleteShader( fshader ); + pglDeleteShader( vshader ); + return; + } + + /* gamma program */ + program = pglCreateProgram(); + if (program == 0) + { + ERR( "Failed to create gamma program\n" ); + pglDeleteShader( fshader ); + pglDeleteShader( vshader ); + return; + } + + pglAttachShader( program, vshader ); + pglAttachShader( program, fshader ); + + pglLinkProgram( program ); + + pglGetProgramiv( program, GL_LINK_STATUS, &success ); + if (!success) + { + pglGetProgramInfoLog( program, sizeof(errstr), NULL, errstr ); + ERR( "Linking gamma shader failed: %s\n", errstr ); + pglDeleteProgram( program ); + pglDeleteShader( fshader ); + pglDeleteShader( vshader ); + return; + } + + pglDeleteShader( fshader ); + pglDeleteShader( vshader ); + + pglGenBuffers( 1, &ctx->ramp_ubo ); + pglBindBuffer( GL_UNIFORM_BUFFER, ctx->ramp_ubo ); + pglBufferData( GL_UNIFORM_BUFFER, sizeof(float) * 4 * GAMMA_RAMP_SIZE, default_gamma_ramp, GL_DYNAMIC_DRAW ); + gl->last_gamma_serial = 0; + + ramp_index = pglGetUniformBlockIndex( program, "ramp" ); + pglUniformBlockBinding( program, ramp_index, 0 ); + + pglUseProgram( program ); + + tex_loc = pglGetUniformLocation( program, "tex" ); + pglUniform1i( tex_loc, 0 ); + + ctx->fs_hack_gamma_pgm = program; + + pglUseProgram( prev_program ); +} + 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; @@ -2082,7 +2301,6 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * {GLX_STENCIL_SIZE, offsetof(struct fs_hack_fbconfig_attribs, stencil_size)}, {GLX_DOUBLEBUFFER, offsetof(struct fs_hack_fbconfig_attribs, doublebuffer)}, {GLX_SAMPLES_ARB, offsetof(struct fs_hack_fbconfig_attribs, samples)}, - {GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, offsetof(struct fs_hack_fbconfig_attribs, srgb)}, }; BYTE *ptr = (BYTE *)&attribs; @@ -2091,6 +2309,7 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * MONITORINFO info = {.cbSize = sizeof(MONITORINFO)}; HMONITOR monitor; int width, height; + GLuint profile; monitor = fs_hack_monitor_from_hwnd( NtUserWindowFromDC( ctx->hdc ) ); NtUserGetMonitorInfo( monitor, &info ); @@ -2099,6 +2318,9 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * TRACE( "Render buffer width:%d height:%d\n", width, height ); + opengl_funcs.gl.p_glGetIntegerv( GL_CONTEXT_PROFILE_MASK, (GLint *)&profile ); + ctx->is_core = (profile & GL_CONTEXT_CORE_PROFILE_BIT) != 0; + opengl_funcs.gl.p_glGetIntegerv( GL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&prev_draw_fbo ); opengl_funcs.gl.p_glGetIntegerv( GL_READ_FRAMEBUFFER_BINDING, (GLint *)&prev_read_fbo ); opengl_funcs.gl.p_glGetIntegerv( GL_TEXTURE_BINDING_2D, (GLint *)&prev_texture ); @@ -2114,13 +2336,26 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * pglGenFramebuffers( 1, &ctx->fs_hack_resolve_fbo ); TRACE( "Created FBO %u for fullscreen hack.\n", ctx->fs_hack_fbo ); } - pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_fbo ); + pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); for (i = 0; i < ARRAY_SIZE(queries); ++i) pglXGetFBConfigAttrib( gdi_display, gl->format->fbconfig, queries[i].attribute, (int *)&ptr[queries[i].offset] ); + + pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_fbo ); + 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 ); + 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 ); + opengl_funcs.gl.p_glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0 ); + opengl_funcs.gl.p_glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + ctx->fs_hack_integer ? GL_NEAREST : GL_LINEAR ); + opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, prev_texture ); + TRACE( "Created texture %u for fullscreen hack.\n", ctx->fs_hack_color_texture ); + if (config.samples) { if (!ctx->fs_hack_color_renderbuffer) @@ -2130,30 +2365,18 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * config.color_internalformat, width, height ); pglFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, ctx->fs_hack_color_renderbuffer ); - TRACE( "Created renderbuffer %u for fullscreen hack.\n", ctx->fs_hack_color_renderbuffer ); - pglGenRenderbuffers( 1, &ctx->fs_hack_color_resolve_renderbuffer ); - pglBindRenderbuffer( GL_RENDERBUFFER, ctx->fs_hack_color_resolve_renderbuffer ); - pglRenderbufferStorage( GL_RENDERBUFFER, config.color_internalformat, width, height ); + TRACE( "Created renderbuffer %u and FBO %u for fullscreen hack.\n", + ctx->fs_hack_color_renderbuffer, ctx->fs_hack_resolve_fbo ); pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_resolve_fbo ); - pglFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, - ctx->fs_hack_color_resolve_renderbuffer ); + pglFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + ctx->fs_hack_color_texture, 0 ); pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_fbo ); pglBindRenderbuffer( GL_RENDERBUFFER, prev_renderbuffer ); - TRACE( "Also created renderbuffer %u and FBO %u for color resolve.\n", - ctx->fs_hack_color_resolve_renderbuffer, ctx->fs_hack_resolve_fbo ); } else { - if (!ctx->fs_hack_color_texture) - opengl_funcs.gl.p_glGenTextures( 1, &ctx->fs_hack_color_texture ); - 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 ); - opengl_funcs.gl.p_glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0 ); - opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, prev_texture ); pglFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ctx->fs_hack_color_texture, 0 ); - TRACE( "Created texture %u for fullscreen hack.\n", ctx->fs_hack_color_texture ); } if (config.ds_internalformat) @@ -2192,6 +2415,8 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * } } + fs_hack_setup_gamma_shader( ctx, gl ); + if (!gl->fs_hack_context_set_up) { opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); @@ -2215,6 +2440,13 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * ctx->setup_for.x = width; ctx->setup_for.y = height; gl->has_scissor_indexed = has_extension( glExtensions, "GL_ARB_viewport_array" ); + gl->has_clip_control = has_extension( glExtensions, "GL_ARB_clip_control" ); + gl->has_ati_frag_shader = !ctx->is_core && + has_extension( glExtensions, "GL_ATI_fragment_shader" ); + gl->has_fragment_program = !ctx->is_core && + has_extension( glExtensions, "GL_ARB_fragment_program" ); + gl->has_vertex_program = !ctx->is_core && + has_extension( glExtensions, "GL_ARB_vertex_program" ); ctx->fs_hack_integer = fs_hack_is_integer(); gl->fs_hack_context_set_up = TRUE; } @@ -2232,12 +2464,15 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * ctx->current_read_fbo = 0; } + pglDeleteBuffers( 1, &ctx->ramp_ubo ); + pglDeleteProgram( ctx->fs_hack_gamma_pgm ); + ctx->fs_hack_gamma_pgm = 0; + pglDeleteRenderbuffers( 1, &ctx->fs_hack_ds_renderbuffer ); - pglDeleteRenderbuffers( 1, &ctx->fs_hack_color_resolve_renderbuffer ); pglDeleteRenderbuffers( 1, &ctx->fs_hack_color_renderbuffer ); opengl_funcs.gl.p_glDeleteTextures( 1, &ctx->fs_hack_ds_texture ); opengl_funcs.gl.p_glDeleteTextures( 1, &ctx->fs_hack_color_texture ); - ctx->fs_hack_color_renderbuffer = ctx->fs_hack_color_resolve_renderbuffer = ctx->fs_hack_ds_renderbuffer = 0; + ctx->fs_hack_color_renderbuffer = ctx->fs_hack_ds_renderbuffer = 0; ctx->fs_hack_color_texture = ctx->fs_hack_ds_texture = 0; pglDeleteFramebuffers( 1, &ctx->fs_hack_resolve_fbo ); pglDeleteFramebuffers( 1, &ctx->fs_hack_fbo ); @@ -2379,16 +2614,284 @@ static void wglReadBuffer( GLenum buffer ) pglReadBuffer( buffer ); } +struct fs_hack_gl_state +{ + GLuint draw_fbo; + GLuint read_fbo; + GLuint program; + GLuint bound_texture; + GLint active_texture; + GLint clip_origin, clip_depth_mode; + GLuint ubo; + GLint64 ubo_size, ubo_start; + GLint viewporti[4]; + GLfloat viewportf[4]; + float clear_color[4]; + GLboolean scissor_test, cull_face, blend, alpha_test, depth_test, stencil_test; + GLboolean arb_frag, arb_vert, ati_frag, fb_srgb; + GLboolean clip_distance[8]; + GLboolean color_mask[4]; + GLuint sampler; +}; + +#define SET 0 +#define RESET 1 + +static void fs_hack_handle_enable_switch( int mode, GLenum cap, GLboolean *b, BOOL new ) +{ + if (mode == SET) + { + *b = opengl_funcs.gl.p_glIsEnabled( cap ); + if (new) opengl_funcs.gl.p_glEnable( cap ); + else opengl_funcs.gl.p_glDisable( cap ); + } + else + { + if (*b) opengl_funcs.gl.p_glEnable( cap ); + else opengl_funcs.gl.p_glDisable( cap ); + } +} + +static void fs_hack_handle_fbo_state( int mode, struct gl_drawable *gl, struct wgl_context *ctx, + struct fs_hack_gl_state *state, const SIZE *real, + const SIZE *scaled, const POINT *scaled_origin ) +{ + if (mode == SET) + { + opengl_funcs.gl.p_glGetIntegerv( GL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&state->draw_fbo ); + opengl_funcs.gl.p_glGetIntegerv( GL_READ_FRAMEBUFFER_BINDING, (GLint *)&state->read_fbo ); + TRACE( "Previous draw FBO %u, read FBO %u\n", state->draw_fbo, state->read_fbo ); + } + else + { + pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, state->draw_fbo ); + pglBindFramebuffer( GL_READ_FRAMEBUFFER, state->read_fbo ); + } +} + +static void fs_hack_handle_clip_control( int mode, struct gl_drawable *gl, struct wgl_context *ctx, + struct fs_hack_gl_state *state, const SIZE *real, + const SIZE *scaled, const POINT *scaled_origin ) +{ + if (!gl->has_clip_control) return; + + if (mode == SET) + { + opengl_funcs.gl.p_glGetIntegerv( GL_CLIP_ORIGIN, (GLint *)&state->clip_origin ); + opengl_funcs.gl.p_glGetIntegerv( GL_CLIP_DEPTH_MODE, (GLint *)&state->clip_depth_mode ); + + pglClipControl( GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE ); + } + else + { + pglClipControl( state->clip_origin, state->clip_depth_mode ); + } +} + +static void fs_hack_handle_shaders( int mode, struct gl_drawable *gl, struct wgl_context *ctx, + struct fs_hack_gl_state *state, const SIZE *real, + const SIZE *scaled, const POINT *scaled_origin ) +{ + if (gl->has_fragment_program) + fs_hack_handle_enable_switch( mode, GL_FRAGMENT_PROGRAM_ARB, &state->arb_frag, FALSE ); + if (gl->has_vertex_program) + fs_hack_handle_enable_switch( mode, GL_VERTEX_PROGRAM_ARB, &state->arb_vert, FALSE ); + fs_hack_handle_enable_switch( mode, GL_FRAMEBUFFER_SRGB, &state->fb_srgb, TRUE ); + + if (gl->has_ati_frag_shader) + fs_hack_handle_enable_switch( mode, GL_FRAGMENT_SHADER_ATI, &state->ati_frag, FALSE ); + + if (mode == SET) + { + opengl_funcs.gl.p_glGetIntegerv( GL_CURRENT_PROGRAM, (GLint *)&state->program ); + + pglGetIntegeri_v( GL_UNIFORM_BUFFER_BINDING, 0, (GLint *)&state->ubo ); + pglGetInteger64i_v( GL_UNIFORM_BUFFER_START, 0, &state->ubo_start ); + pglGetInteger64i_v( GL_UNIFORM_BUFFER_SIZE, 0, &state->ubo_size ); + + opengl_funcs.gl.p_glGetIntegerv( GL_ACTIVE_TEXTURE, &state->active_texture ); + pglActiveTexture( GL_TEXTURE0 ); + opengl_funcs.gl.p_glGetIntegerv( GL_TEXTURE_BINDING_2D, (GLint *)&state->bound_texture ); + pglGetIntegeri_v( GL_SAMPLER_BINDING, 0, (GLint *)&state->sampler ); + + pglBindBufferBase( GL_UNIFORM_BUFFER, 0, ctx->ramp_ubo ); + + opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, ctx->fs_hack_color_texture ); + pglBindSampler( 0, 0 ); + + pglUseProgram( ctx->fs_hack_gamma_pgm ); + } + else + { + pglUseProgram( state->program ); + + pglBindSampler( 0, state->sampler ); + + opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, state->bound_texture ); + pglActiveTexture( state->active_texture ); + + pglBindBufferRange( GL_UNIFORM_BUFFER, 0, state->ubo, state->ubo_start, state->ubo_size ); + } +} + +static void fs_hack_handle_viewport( int mode, struct gl_drawable *gl, struct wgl_context *ctx, + struct fs_hack_gl_state *state, const SIZE *real, + const SIZE *scaled, const POINT *scaled_origin ) +{ + if (mode == SET) + { + if (gl->has_scissor_indexed) + { + pglGetFloati_v( GL_VIEWPORT, 0, state->viewportf ); + pglViewportIndexedf( 0, scaled_origin->x, scaled_origin->y, scaled->cx, scaled->cy ); + } + else + { + opengl_funcs.gl.p_glGetIntegerv( GL_VIEWPORT, state->viewporti ); + opengl_funcs.gl.p_glViewport( scaled_origin->x, scaled_origin->y, scaled->cx, scaled->cy ); + } + } + else + { + if (gl->has_scissor_indexed) + { + pglViewportIndexedfv( 0, state->viewportf ); + } + else + { + opengl_funcs.gl.p_glViewport( state->viewporti[0], state->viewporti[1], + state->viewporti[2], state->viewporti[3] ); + } + } +} + +static void fs_hack_handle_clear_color( int mode, struct gl_drawable *gl, struct wgl_context *ctx, + struct fs_hack_gl_state *state, const SIZE *real, + const SIZE *scaled, const POINT *scaled_origin ) +{ + if (mode == SET) + { + opengl_funcs.gl.p_glGetFloatv( GL_COLOR_CLEAR_VALUE, state->clear_color ); + opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); + } + else + { + opengl_funcs.gl.p_glClearColor( state->clear_color[0], state->clear_color[1], + state->clear_color[2], state->clear_color[3] ); + } +} + +static void fs_hack_handle_clip_distance( int mode, struct gl_drawable *gl, struct wgl_context *ctx, + struct fs_hack_gl_state *state, const SIZE *real, + const SIZE *scaled, const POINT *scaled_origin ) +{ + unsigned int i; + if (mode == SET) + { + for (i = 0; i < ARRAY_SIZE(state->clip_distance); ++i) + { + state->clip_distance[i] = opengl_funcs.gl.p_glIsEnabled( GL_CLIP_DISTANCE0 + i ); + opengl_funcs.gl.p_glDisable( GL_CLIP_DISTANCE0 + i ); + } + } + else + { + for (i = 0; i < ARRAY_SIZE(state->clip_distance); ++i) + { + if (state->clip_distance[i]) opengl_funcs.gl.p_glEnable( GL_CLIP_DISTANCE0 + i ); + } + } +} + +static void fs_hack_handle_color_mask( int mode, struct gl_drawable *gl, struct wgl_context *ctx, + struct fs_hack_gl_state *state, const SIZE *real, + const SIZE *scaled, const POINT *scaled_origin ) +{ + if (mode == SET) + { + pglGetBooleani_v( GL_COLOR_WRITEMASK, 0, state->color_mask ); + + pglColorMaski( 0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); + } + else + { + pglColorMaski( 0, state->color_mask[0], state->color_mask[1], state->color_mask[2], state->color_mask[3] ); + } +} + +static void fs_hack_handle_scissor( int mode, struct gl_drawable *gl, struct wgl_context *ctx, + struct fs_hack_gl_state *state, const SIZE *real, + const SIZE *scaled, const POINT *scaled_origin ) +{ + fs_hack_handle_enable_switch( mode, GL_SCISSOR_TEST, &state->scissor_test, FALSE ); +} + +static void fs_hack_handle_cull_face( int mode, struct gl_drawable *gl, struct wgl_context *ctx, + struct fs_hack_gl_state *state, const SIZE *real, + const SIZE *scaled, const POINT *scaled_origin ) +{ + fs_hack_handle_enable_switch( mode, GL_CULL_FACE, &state->cull_face, FALSE ); +} + +static void fs_hack_handle_blend( int mode, struct gl_drawable *gl, struct wgl_context *ctx, + struct fs_hack_gl_state *state, const SIZE *real, + const SIZE *scaled, const POINT *scaled_origin ) +{ + fs_hack_handle_enable_switch( mode, GL_BLEND, &state->blend, FALSE ); +} + +static void fs_hack_handle_alpha_test( int mode, struct gl_drawable *gl, struct wgl_context *ctx, + struct fs_hack_gl_state *state, const SIZE *real, + const SIZE *scaled, const POINT *scaled_origin ) +{ + if (ctx->is_core) return; + + fs_hack_handle_enable_switch( mode, GL_ALPHA_TEST, &state->alpha_test, FALSE ); +} + +static void fs_hack_handle_ds_test( int mode, struct gl_drawable *gl, struct wgl_context *ctx, + struct fs_hack_gl_state *state, const SIZE *real, + const SIZE *scaled, const POINT *scaled_origin ) +{ + fs_hack_handle_enable_switch( mode, GL_DEPTH_TEST, &state->depth_test, FALSE ); + fs_hack_handle_enable_switch( mode, GL_STENCIL_TEST, &state->stencil_test, FALSE ); +} + static void fs_hack_blit_framebuffer( struct gl_drawable *gl, GLenum draw_buffer ) { + static const struct + { + void (*state_handler)(int mode, struct gl_drawable *gl, struct wgl_context *ctx, + struct fs_hack_gl_state *state, const SIZE *real, + const SIZE *scaled, const POINT *scaled_origin); + } + general_state_handlers[] = + { + {fs_hack_handle_fbo_state}, + {fs_hack_handle_scissor}, + {fs_hack_handle_clear_color}, + }, + draw_state_handlers[] = + { + {fs_hack_handle_clip_control}, + {fs_hack_handle_shaders}, + {fs_hack_handle_viewport}, + {fs_hack_handle_cull_face}, + {fs_hack_handle_clip_distance}, + {fs_hack_handle_color_mask}, + {fs_hack_handle_blend}, + {fs_hack_handle_alpha_test}, + {fs_hack_handle_ds_test}, + }; struct wgl_context *ctx = NtCurrentTeb()->glContext; SIZE scaled, src, real; - GLuint prev_draw_fbo, prev_read_fbo; - GLint prev_scissor[4]; RECT user_rect, real_rect; POINT scaled_origin; - float prev_clear_color[4]; HMONITOR monitor; + struct fs_hack_gl_state state; + const float *gamma_ramp; + LONG gamma_serial; + unsigned int i; monitor = fs_hack_monitor_from_hwnd( NtUserWindowFromDC( ctx->hdc ) ); scaled = fs_hack_get_scaled_screen_size( monitor ); @@ -2404,32 +2907,36 @@ static void fs_hack_blit_framebuffer( struct gl_drawable *gl, GLenum draw_buffer scaled_origin.x -= real_rect.left; scaled_origin.y -= real_rect.top; + gamma_ramp = fs_hack_get_gamma_ramp( &gamma_serial ); + TRACE( "scaled:%dx%d src:%dx%d real:%dx%d user_rect:%s real_rect:%s scaled_origin:%s\n", (int)scaled.cx, (int)scaled.cy, (int)src.cx, (int)src.cy, (int)real.cx, (int)real.cy, wine_dbgstr_rect( &user_rect ), wine_dbgstr_rect( &real_rect ), wine_dbgstr_point( &scaled_origin ) ); if (ctx->setup_for.x != src.cx || ctx->setup_for.y != src.cy) fs_hack_setup_context( ctx, gl ); - TRACE( "Blitting from FBO %u %ux%u to %ux%u\n", ctx->fs_hack_fbo, + /* Can't stretch blit with multisampled renderbuffers */ + if (ctx->fs_hack_color_renderbuffer && !gamma_ramp) + { + gamma_ramp = fs_hack_get_default_gamma_ramp(); + gamma_serial = 0; + } + + TRACE( "Stretching from FBO %u %ux%u to %ux%u\n", ctx->fs_hack_fbo, (int)src.cx, (int)src.cy, (int)scaled.cx, (int)scaled.cy ); - opengl_funcs.gl.p_glGetIntegerv( GL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&prev_draw_fbo ); - opengl_funcs.gl.p_glGetIntegerv( GL_READ_FRAMEBUFFER_BINDING, (GLint *)&prev_read_fbo ); - TRACE( "Previous draw FBO %u, read FBO %u\n", prev_draw_fbo, prev_read_fbo ); + for (i = 0; i < ARRAY_SIZE(general_state_handlers); i++) + general_state_handlers[i].state_handler( SET, gl, ctx, &state, &real, &scaled, &scaled_origin ); - if (gl->has_scissor_indexed) + if (gamma_ramp) { - opengl_funcs.ext.p_glGetIntegeri_v( GL_SCISSOR_BOX, 0, prev_scissor ); - opengl_funcs.ext.p_glScissorIndexed( 0, 0, 0, real.cx, real.cy ); - } - else - { - opengl_funcs.gl.p_glGetIntegerv( GL_SCISSOR_BOX, prev_scissor ); - opengl_funcs.gl.p_glScissor( 0, 0, real.cx, real.cy ); + for (i = 0; i < ARRAY_SIZE(draw_state_handlers); i++) + draw_state_handlers[i].state_handler( SET, gl, ctx, &state, &real, &scaled, &scaled_origin ); } pglBindFramebuffer( GL_READ_FRAMEBUFFER, ctx->fs_hack_fbo ); - if (ctx->fs_hack_color_resolve_renderbuffer) + + if (ctx->fs_hack_color_renderbuffer) { pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_resolve_fbo ); pglBlitFramebuffer( 0, 0, src.cx, src.cy, 0, 0, src.cx, src.cy, GL_COLOR_BUFFER_BIT, GL_NEAREST ); @@ -2441,29 +2948,39 @@ static void fs_hack_blit_framebuffer( struct gl_drawable *gl, GLenum draw_buffer // pglDrawBuffer( draw_buffer ); pglDrawBuffer( GL_BACK ); - opengl_funcs.gl.p_glGetFloatv( GL_COLOR_CLEAR_VALUE, prev_clear_color ); - opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT ); - opengl_funcs.gl.p_glClearColor( prev_clear_color[0], prev_clear_color[1], prev_clear_color[2], - prev_clear_color[3] ); - pglBlitFramebuffer( 0, 0, src.cx, src.cy, scaled_origin.x, scaled_origin.y, - scaled_origin.x + scaled.cx, scaled_origin.y + scaled.cy, - GL_COLOR_BUFFER_BIT, ctx->fs_hack_integer ? GL_NEAREST : GL_LINEAR ); - // HACK - if (draw_buffer == GL_FRONT) pglXSwapBuffers( gdi_display, gl->drawable ); - - if (gl->has_scissor_indexed) + if (gamma_ramp) { - opengl_funcs.ext.p_glScissorIndexedv( 0, prev_scissor ); + if (gamma_serial != gl->last_gamma_serial) + { + TRACE( "updating gamma ramp (serial: %u)\n", (int)gamma_serial ); + + pglBufferData( GL_UNIFORM_BUFFER, sizeof(float) * 4 * GAMMA_RAMP_SIZE, gamma_ramp, GL_DYNAMIC_DRAW ); + + gl->last_gamma_serial = gamma_serial; + } + + pglDrawArrays( GL_TRIANGLE_STRIP, 0, 4 ); } else { - opengl_funcs.gl.p_glScissor( prev_scissor[0], prev_scissor[1], prev_scissor[2], prev_scissor[3] ); + pglBlitFramebuffer( 0, 0, src.cx, src.cy, scaled_origin.x, scaled_origin.y, + scaled_origin.x + scaled.cx, scaled_origin.y + scaled.cy, + GL_COLOR_BUFFER_BIT, ctx->fs_hack_integer ? GL_NEAREST : GL_LINEAR ); + } + + // HACK + if (draw_buffer == GL_FRONT) pglXSwapBuffers( gdi_display, gl->drawable ); + + if (gamma_ramp) + { + for (i = 0; i < ARRAY_SIZE(draw_state_handlers); i++) + draw_state_handlers[i].state_handler( RESET, gl, ctx, &state, NULL, NULL, NULL ); } - pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, prev_draw_fbo ); - pglBindFramebuffer( GL_READ_FRAMEBUFFER, prev_read_fbo ); + for (i = 0; i < ARRAY_SIZE(general_state_handlers); i++) + general_state_handlers[i].state_handler( RESET, gl, ctx, &state, NULL, NULL, NULL ); } /*********************************************************************** diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 6cd236e876a..3e5385679c2 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -715,6 +715,8 @@ extern double fs_hack_get_user_to_real_scale( HMONITOR ) DECLSPEC_HIDDEN; extern SIZE fs_hack_get_scaled_screen_size( HMONITOR monitor ) DECLSPEC_HIDDEN; extern RECT fs_hack_get_real_virtual_screen(void) DECLSPEC_HIDDEN; extern void fs_hack_init(void) DECLSPEC_HIDDEN; +extern const float *fs_hack_get_gamma_ramp( LONG *serial ); +extern void fs_hack_set_gamma_ramp( const WORD *ramp ); static inline void mirror_rect( const RECT *window_rect, RECT *rect ) { diff --git a/dlls/winex11.drv/xvidmode.c b/dlls/winex11.drv/xvidmode.c index ae8116da7b8..10248890900 100644 --- a/dlls/winex11.drv/xvidmode.c +++ b/dlls/winex11.drv/xvidmode.c @@ -552,6 +552,25 @@ void X11DRV_XF86VM_Init(void) #endif /* SONAME_LIBXXF86VM */ +static BOOL CALLBACK gammahack_UpdateWindowGamma( HWND hwnd, LPARAM lparam ) +{ + /* XXX: Technically, the ramp should only apply to windows on the given + * device, but I can't think of a situation in which that would matter. */ + + sync_gl_drawable( hwnd, FALSE ); + + return TRUE; +} + +static BOOL gamma_hack_SetGammaRamp( PHYSDEV dev, const WORD *ramp ) +{ + fs_hack_set_gamma_ramp( ramp ); + + NtUserEnumChildWindows( NtUserGetDesktopWindow(), gammahack_UpdateWindowGamma, 0 ); + + return TRUE; +} + /*********************************************************************** * GetDeviceGammaRamp (X11DRV.@) * @@ -578,7 +597,8 @@ BOOL CDECL X11DRV_GetDeviceGammaRamp(PHYSDEV dev, LPVOID ramp) BOOL CDECL X11DRV_SetDeviceGammaRamp(PHYSDEV dev, LPVOID ramp) { #ifdef SONAME_LIBXXF86VM - return X11DRV_XF86VM_SetGammaRamp(ramp); + if (!X11DRV_XF86VM_SetGammaRamp(ramp)) return gamma_hack_SetGammaRamp(dev, ramp); + return TRUE; #else return FALSE; #endif From e0f855a161b092138d905a7117932c7206f108b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:22:21 +0100 Subject: [PATCH 0684/2777] fshack: winex11: Setup gamma shader only once per context. Fixes GL objects leak and avoids unneccessary shader recreation when the fs_hack_setup_context() is called due to switching GL drawable. For Star Wars - Knights of the Old Republic blank screen. CW-Bug-Id: #19002 --- dlls/winex11.drv/opengl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 2ba04e23449..8ef588e3ebd 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2188,6 +2188,10 @@ static void fs_hack_setup_gamma_shader( struct wgl_context *ctx, struct gl_drawa char errstr[512]; const float *default_gamma_ramp = fs_hack_get_default_gamma_ramp(); + gl->last_gamma_serial = 0; + + if (ctx->fs_hack_gamma_pgm) return; + opengl_funcs.gl.p_glGetIntegerv( GL_CURRENT_PROGRAM, (GLint *)&prev_program ); /* vertex shader */ vshader = pglCreateShader( GL_VERTEX_SHADER ); @@ -2261,7 +2265,6 @@ static void fs_hack_setup_gamma_shader( struct wgl_context *ctx, struct gl_drawa pglGenBuffers( 1, &ctx->ramp_ubo ); pglBindBuffer( GL_UNIFORM_BUFFER, ctx->ramp_ubo ); pglBufferData( GL_UNIFORM_BUFFER, sizeof(float) * 4 * GAMMA_RAMP_SIZE, default_gamma_ramp, GL_DYNAMIC_DRAW ); - gl->last_gamma_serial = 0; ramp_index = pglGetUniformBlockIndex( program, "ramp" ); pglUniformBlockBinding( program, ramp_index, 0 ); From b80bf22104e11bb99e71dc209639a7e4217ba89c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:22:48 +0100 Subject: [PATCH 0685/2777] fshack: winex11: Track if multisample resolve is needed in gl_drawable. As that changes per drawable and not per context. --- dlls/winex11.drv/opengl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 8ef588e3ebd..984a28e2d8b 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -255,6 +255,7 @@ struct gl_drawable BOOL fs_hack; BOOL fs_hack_did_swapbuf; BOOL fs_hack_context_set_up; + BOOL fs_hack_needs_resolve; BOOL has_scissor_indexed; BOOL has_clip_control; BOOL has_ati_frag_shader; @@ -2361,6 +2362,7 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * if (config.samples) { + gl->fs_hack_needs_resolve = TRUE; if (!ctx->fs_hack_color_renderbuffer) pglGenRenderbuffers( 1, &ctx->fs_hack_color_renderbuffer ); pglBindRenderbuffer( GL_RENDERBUFFER, ctx->fs_hack_color_renderbuffer ); @@ -2378,6 +2380,7 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * } else { + gl->fs_hack_needs_resolve = FALSE; pglFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ctx->fs_hack_color_texture, 0 ); } @@ -2919,7 +2922,7 @@ static void fs_hack_blit_framebuffer( struct gl_drawable *gl, GLenum draw_buffer if (ctx->setup_for.x != src.cx || ctx->setup_for.y != src.cy) fs_hack_setup_context( ctx, gl ); /* Can't stretch blit with multisampled renderbuffers */ - if (ctx->fs_hack_color_renderbuffer && !gamma_ramp) + if (gl->fs_hack_needs_resolve && !gamma_ramp) { gamma_ramp = fs_hack_get_default_gamma_ramp(); gamma_serial = 0; @@ -2939,7 +2942,7 @@ static void fs_hack_blit_framebuffer( struct gl_drawable *gl, GLenum draw_buffer pglBindFramebuffer( GL_READ_FRAMEBUFFER, ctx->fs_hack_fbo ); - if (ctx->fs_hack_color_renderbuffer) + if (gl->fs_hack_needs_resolve) { pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_resolve_fbo ); pglBlitFramebuffer( 0, 0, src.cx, src.cy, 0, 0, src.cx, src.cy, GL_COLOR_BUFFER_BIT, GL_NEAREST ); From 2a69c24baea9e4eda19b5c4126c02cd10db640ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:23:17 +0100 Subject: [PATCH 0686/2777] fshack: winex11: Destroy fshack GL objects only at GL context destroy. --- dlls/winex11.drv/opengl.c | 53 +++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 984a28e2d8b..66982d0ee10 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2012,6 +2012,34 @@ static struct wgl_context *glxdrv_wglCreateContext( HDC hdc ) return ret; } +static void fs_hack_destroy_context( struct wgl_context *ctx ) +{ + GLXContext prev_context; + GLXDrawable prev_drawable; + + if (!ctx->drawables[0]) return; + + prev_context = pglXGetCurrentContext(); + prev_drawable = pglXGetCurrentDrawable(); + pglXMakeCurrent( gdi_display, ctx->drawables[0]->drawable, ctx->ctx ); + + pglDeleteBuffers( 1, &ctx->ramp_ubo ); + pglDeleteProgram( ctx->fs_hack_gamma_pgm ); + ctx->fs_hack_gamma_pgm = 0; + + if (ctx->fs_hack_ds_renderbuffer) pglDeleteRenderbuffers( 1, &ctx->fs_hack_ds_renderbuffer ); + if (ctx->fs_hack_color_renderbuffer) pglDeleteRenderbuffers( 1, &ctx->fs_hack_color_renderbuffer ); + if (ctx->fs_hack_ds_texture) opengl_funcs.gl.p_glDeleteTextures( 1, &ctx->fs_hack_ds_texture ); + if (ctx->fs_hack_color_texture) opengl_funcs.gl.p_glDeleteTextures( 1, &ctx->fs_hack_color_texture ); + ctx->fs_hack_color_renderbuffer = ctx->fs_hack_ds_renderbuffer = 0; + ctx->fs_hack_color_texture = ctx->fs_hack_ds_texture = 0; + if (ctx->fs_hack_resolve_fbo) pglDeleteFramebuffers( 1, &ctx->fs_hack_resolve_fbo ); + if (ctx->fs_hack_fbo) pglDeleteFramebuffers( 1, &ctx->fs_hack_fbo ); + ctx->fs_hack_resolve_fbo = ctx->fs_hack_fbo = 0; + + pglXMakeCurrent( gdi_display, prev_drawable, prev_context ); +} + /*********************************************************************** * glxdrv_wglDeleteContext */ @@ -2021,6 +2049,8 @@ static BOOL glxdrv_wglDeleteContext(struct wgl_context *ctx) TRACE("(%p)\n", ctx); + fs_hack_destroy_context( ctx ); + pthread_mutex_lock( &context_mutex ); list_remove( &ctx->entry ); LIST_FOR_EACH_ENTRY( pb, &pbuffer_list, struct wgl_pbuffer, entry ) @@ -2337,7 +2367,6 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * if (!ctx->fs_hack_fbo) { pglGenFramebuffers( 1, &ctx->fs_hack_fbo ); - pglGenFramebuffers( 1, &ctx->fs_hack_resolve_fbo ); TRACE( "Created FBO %u for fullscreen hack.\n", ctx->fs_hack_fbo ); } pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); @@ -2363,6 +2392,13 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * if (config.samples) { gl->fs_hack_needs_resolve = TRUE; + + if (!ctx->fs_hack_resolve_fbo) + { + pglGenFramebuffers( 1, &ctx->fs_hack_resolve_fbo ); + TRACE( "Created resolve FBO %u for fullscreen hack.\n", ctx->fs_hack_resolve_fbo ); + } + if (!ctx->fs_hack_color_renderbuffer) pglGenRenderbuffers( 1, &ctx->fs_hack_color_renderbuffer ); pglBindRenderbuffer( GL_RENDERBUFFER, ctx->fs_hack_color_renderbuffer ); @@ -2469,21 +2505,6 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * pglBindFramebuffer( GL_READ_FRAMEBUFFER, 0 ); ctx->current_read_fbo = 0; } - - pglDeleteBuffers( 1, &ctx->ramp_ubo ); - pglDeleteProgram( ctx->fs_hack_gamma_pgm ); - ctx->fs_hack_gamma_pgm = 0; - - pglDeleteRenderbuffers( 1, &ctx->fs_hack_ds_renderbuffer ); - pglDeleteRenderbuffers( 1, &ctx->fs_hack_color_renderbuffer ); - opengl_funcs.gl.p_glDeleteTextures( 1, &ctx->fs_hack_ds_texture ); - opengl_funcs.gl.p_glDeleteTextures( 1, &ctx->fs_hack_color_texture ); - ctx->fs_hack_color_renderbuffer = ctx->fs_hack_ds_renderbuffer = 0; - ctx->fs_hack_color_texture = ctx->fs_hack_ds_texture = 0; - pglDeleteFramebuffers( 1, &ctx->fs_hack_resolve_fbo ); - pglDeleteFramebuffers( 1, &ctx->fs_hack_fbo ); - ctx->fs_hack_fbo = 0; - gl->fs_hack_context_set_up = FALSE; } } From a19c3f044a416f4be8f92ed9e5804b0541464346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:23:32 +0100 Subject: [PATCH 0687/2777] fshack: winex11: Set viewport in fs_hack_setup_context(). For Star Wars - Knights of the Old Republic blank screen. CW-Bug-Id: #19002 --- dlls/winex11.drv/opengl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 66982d0ee10..e8a4bdee078 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2459,6 +2459,8 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * fs_hack_setup_gamma_shader( ctx, gl ); + if (!ctx->has_been_current) opengl_funcs.gl.p_glViewport( 0, 0, width, height ); + if (!gl->fs_hack_context_set_up) { opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); From 01537721ed9858878d1ce118ecd9da39f0db3063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:23:47 +0100 Subject: [PATCH 0688/2777] fshack: winex11: Also enable fshack for drawable due to gamma in create_gl_drawable(). For Star Wars - Knights of the Old Republic blank screen. CW-Bug-Id: #19002 --- dlls/winex11.drv/opengl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index e8a4bdee078..e133e720637 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1527,7 +1527,7 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel if (gl->window) gl->drawable = pglXCreateWindow( gdi_display, gl->format->fbconfig, gl->window, NULL ); data = get_win_data( hwnd ); - gl->fs_hack = data->fs_hack; + gl->fs_hack = data->fs_hack || fs_hack_get_gamma_ramp( NULL ); if (gl->fs_hack) TRACE( "Window %p has the fullscreen hack enabled\n", hwnd ); release_win_data( data ); TRACE( "%p created client %lx drawable %lx\n", hwnd, gl->window, gl->drawable ); From c2a80026056ad031319c9665c5f1d449cd11bda9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:24:01 +0100 Subject: [PATCH 0689/2777] fshack: winex11: Use window dimensions in GL if fshack is enabled for gamma only. For Star Wars - Knights of the Old Republic blank screen. CW-Bug-Id: #19002 fshack: winex11: Use window size for texture and framebuffers in fs_hack_setup_context(). For Star Wars - Knights of the Old Republic blank screen. CW-Bug-Id: #19002 --- dlls/winex11.drv/opengl.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index e133e720637..7993b4e4384 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2340,15 +2340,16 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * if (ctx->fs_hack) { - MONITORINFO info = {.cbSize = sizeof(MONITORINFO)}; - HMONITOR monitor; int width, height; + RECT rect = {0}; GLuint profile; + HWND hwnd; - monitor = fs_hack_monitor_from_hwnd( NtUserWindowFromDC( ctx->hdc ) ); - NtUserGetMonitorInfo( monitor, &info ); - width = info.rcMonitor.right - info.rcMonitor.left; - height = info.rcMonitor.bottom - info.rcMonitor.top; + hwnd = NtUserWindowFromDC( ctx->hdc ); + NtUserGetClientRect( hwnd, &rect ); + + width = rect.right - rect.left; + height = rect.bottom - rect.top; TRACE( "Render buffer width:%d height:%d\n", width, height ); @@ -2914,18 +2915,32 @@ static void fs_hack_blit_framebuffer( struct gl_drawable *gl, GLenum draw_buffer }; struct wgl_context *ctx = NtCurrentTeb()->glContext; SIZE scaled, src, real; - RECT user_rect, real_rect; + RECT user_rect = {0}, real_rect; POINT scaled_origin; HMONITOR monitor; struct fs_hack_gl_state state; const float *gamma_ramp; LONG gamma_serial; unsigned int i; + HWND hwnd; + + hwnd = NtUserWindowFromDC( ctx->hdc ); + monitor = fs_hack_monitor_from_hwnd( hwnd ); + + if (fs_hack_enabled( monitor )) + { + user_rect = fs_hack_current_mode( monitor ); + real_rect = fs_hack_real_mode( monitor ); + scaled = fs_hack_get_scaled_screen_size( monitor ); + } + else + { + NtUserGetClientRect( hwnd, &user_rect ); + real_rect = user_rect; + scaled.cx = user_rect.right - user_rect.left; + scaled.cy = user_rect.bottom - user_rect.top; + } - monitor = fs_hack_monitor_from_hwnd( NtUserWindowFromDC( ctx->hdc ) ); - scaled = fs_hack_get_scaled_screen_size( monitor ); - user_rect = fs_hack_current_mode( monitor ); - real_rect = fs_hack_real_mode( monitor ); src.cx = user_rect.right - user_rect.left; src.cy = user_rect.bottom - user_rect.top; real.cx = real_rect.right - real_rect.left; From f2bb49fc6bdab103f7371d5242c6c7355fbc42c8 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 4 Feb 2022 16:03:22 +0300 Subject: [PATCH 0690/2777] fshack: winex11: 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 | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 7993b4e4384..79fdbaa4d48 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2464,10 +2464,23 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * 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 b98c508d6cf214bbdc931b99441ba029cf233e9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 14:31:54 +0100 Subject: [PATCH 0691/2777] fshack: winex11: 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 79fdbaa4d48..7205024061d 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2310,6 +2310,49 @@ 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; @@ -2380,7 +2423,9 @@ 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 ); + if (!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 ); @@ -2442,7 +2487,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 9f0cd0fe6553b1cea5c109dfc9d68f5702d9b8b6 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 30 Mar 2022 16:46:17 +0300 Subject: [PATCH 0692/2777] fshack: winex11: Interpolate looked up colour in gamma shader. CW-Bug-Id: #20400 --- dlls/winex11.drv/opengl.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 7205024061d..41a44befc86 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2202,12 +2202,19 @@ static const char *fs_hack_gamma_frag_shader_src = "\n" "layout(location = 0) out vec4 outColor;\n" "\n" +"vec3 color_from_index(vec3 index)\n" +"{\n" +" ivec3 i = ivec3(index);\n" +" return vec3(values[i.r].r, values[i.g].g, values[i.b].b);\n" +"}\n" +"\n" "void main(void)\n" "{\n" -" vec4 lookup = texture(tex, texCoord) * 255.0;\n" -" outColor.r = values[int(lookup.r)].r;\n" -" outColor.g = values[int(lookup.g)].g;\n" -" outColor.b = values[int(lookup.b)].b;\n" +" vec3 lookup = texture(tex, texCoord).xyz * 255.0;\n" +" vec3 lookup1, lookup2;\n" +" lookup1 = floor(lookup);\n" +" lookup2 = ceil(lookup);\n" +" outColor.xyz = mix(color_from_index(lookup1), color_from_index(lookup2), lookup - lookup1);\n" " outColor.a = 1.0;\n" "}\n" ; From 14538757201c8bc801ac508eda165ff86f234886 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 31 Oct 2022 18:35:03 -0600 Subject: [PATCH 0693/2777] fshack: winex11: Enable specific names for textures for Quake III Arena. CW-Bug-Id: #21474 --- dlls/winex11.drv/opengl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 41a44befc86..60b24a511d4 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2344,7 +2344,7 @@ static void gen_texture( struct wgl_context *ctx, GLuint *tex, enum fshack_textu { const char *sgi = getenv( "SteamGameId" ); - texture_name_hack = sgi && !strcmp( sgi, "6020" ); + texture_name_hack = sgi && (!strcmp( sgi, "6020" ) || !strcmp( sgi, "2200" )); } if (!texture_name_hack || opengl_funcs.gl.p_glIsTexture( texture_names[type] )) From 42fe3a8a90dcba4a98c5e5d15086d407a002cc77 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 31 Oct 2022 18:40:10 -0600 Subject: [PATCH 0694/2777] fshack: winex11: Enable specific names for textures for Quake III Team Arena. CW-Bug-Id: #21474 --- dlls/winex11.drv/opengl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 60b24a511d4..a96ef3bec1a 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2344,7 +2344,7 @@ static void gen_texture( struct wgl_context *ctx, GLuint *tex, enum fshack_textu { const char *sgi = getenv( "SteamGameId" ); - texture_name_hack = sgi && (!strcmp( sgi, "6020" ) || !strcmp( sgi, "2200" )); + texture_name_hack = sgi && (!strcmp( sgi, "6020" ) || !strcmp( sgi, "2200" ) || !strcmp( sgi, "2350" )); } if (!texture_name_hack || opengl_funcs.gl.p_glIsTexture( texture_names[type] )) From 83d0c968d2dd39f4501b7145f56b47b023efda19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 30 Jan 2023 11:20:36 +0100 Subject: [PATCH 0695/2777] fshack: winex11: Always send WM_X11DRV_DESKTOP_RESIZED to sync fshack. CW-Bug-Id: #21836 --- dlls/winex11.drv/desktop.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c index 89a703bff7b..f46fe0f5fa2 100644 --- a/dlls/winex11.drv/desktop.c +++ b/dlls/winex11.drv/desktop.c @@ -472,9 +472,9 @@ void X11DRV_resize_desktop(void) SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE ); ungrab_clipping_window(); - if (old_virtual_rect.left != virtual_rect.left || old_virtual_rect.top != virtual_rect.top) - send_message_timeout( HWND_BROADCAST, WM_X11DRV_DESKTOP_RESIZED, old_virtual_rect.left, - old_virtual_rect.top, SMTO_ABORTIFHUNG, 2000, FALSE ); + /* HACK: always send the desktop resize notification, to eventually update fshack on windows */ + send_message_timeout( HWND_BROADCAST, WM_X11DRV_DESKTOP_RESIZED, old_virtual_rect.left, + old_virtual_rect.top, SMTO_ABORTIFHUNG, 2000, FALSE ); /* forward clip_fullscreen_window request to the foreground window */ send_notify_message( NtUserGetForegroundWindow(), WM_X11DRV_CLIP_CURSOR_REQUEST, TRUE, TRUE ); From 353a9c144f6e05569ddd9473d35e082c825abac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 13 Feb 2023 14:22:17 +0100 Subject: [PATCH 0696/2777] fshack: winex11: Invalidate swapchains on fshack enable/disable. CW-Bug-Id: #21836 --- dlls/winex11.drv/vulkan.c | 41 +++++++++++++++++++++++++++++++++++++++ dlls/winex11.drv/window.c | 1 + dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 43 insertions(+) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 8f9b08135b9..cae182fe89a 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -71,6 +71,7 @@ struct wine_vk_surface DWORD hwnd_thread_id; BOOL gdi_blit_source; /* HACK: gdi blits from the window should work with Vulkan rendered contents. */ BOOL other_process; + BOOL invalidated; Colormap client_colormap; HDC draw_dc; unsigned int width, height; @@ -342,6 +343,18 @@ void sync_vk_surface(HWND hwnd, BOOL known_child) pthread_mutex_unlock(&vulkan_mutex); } +void invalidate_vk_surfaces(HWND hwnd) +{ + struct wine_vk_surface *surface; + pthread_mutex_lock(&vulkan_mutex); + LIST_FOR_EACH_ENTRY(surface, &surface_list, struct wine_vk_surface, entry) + { + if (surface->hwnd != hwnd) continue; + surface->invalidated = TRUE; + } + pthread_mutex_unlock(&vulkan_mutex); +} + Window wine_vk_active_surface(HWND hwnd) { struct wine_vk_surface *surface, *active = NULL; @@ -469,6 +482,7 @@ static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device, else if (x11_surface->offscreen && create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR) create_info_host.presentMode = VK_PRESENT_MODE_FIFO_KHR; x11_surface->present_mode = create_info->presentMode; + x11_surface->invalidated = FALSE; pthread_mutex_lock(&vulkan_mutex); LIST_FOR_EACH_ENTRY(other, &surface_list, struct wine_vk_surface, entry) @@ -1017,6 +1031,10 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, } if (fence != orig_fence) pvkDestroyFence(device, fence, NULL); + + if (result == VK_SUCCESS && surface && surface->invalidated) + result = VK_SUBOPTIMAL_KHR; + if (surface) wine_vk_surface_release(surface); return result; } @@ -1061,6 +1079,25 @@ static VkResult X11DRV_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR * } } + if (res == VK_SUCCESS) + { + struct wine_vk_surface *surface; + BOOL invalidated = FALSE; + unsigned int i; + + pthread_mutex_lock(&vulkan_mutex); + for (i = 0; i < present_info->swapchainCount; ++i) + { + if (!XFindContext(gdi_display, (XID)present_info->pSwapchains[i], vulkan_swapchain_context, (char **)&surface) + && surface->invalidated) + { + invalidated = TRUE; + break; + } + } + pthread_mutex_unlock(&vulkan_mutex); + if (invalidated) res = VK_SUBOPTIMAL_KHR; + } return res; } @@ -1242,6 +1279,10 @@ void sync_vk_surface(HWND hwnd, BOOL known_child) { } +void invalidate_vk_surfaces(HWND hwnd) +{ +} + void vulkan_thread_detach(void) { } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 151cda11d9a..9be7df091ec 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2986,6 +2986,7 @@ static void window_update_fshack( struct x11drv_win_data *data, const RECT *wind XMoveResizeWindow( gdi_display, data->client_window, top_left.x, top_left.y, client_rect_host.right, client_rect_host.bottom ); sync_gl_drawable( data->hwnd, !data->whole_window ); + invalidate_vk_surfaces( data->hwnd ); } NtUserEnumChildWindows( data->hwnd, update_child_window_fshack, enable ); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 3e5385679c2..20aeebcab94 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -675,6 +675,7 @@ extern void destroy_gl_drawable( HWND hwnd ) DECLSPEC_HIDDEN; extern void destroy_vk_surface( HWND hwnd ) DECLSPEC_HIDDEN; extern void sync_vk_surface( HWND hwnd, BOOL known_child ) DECLSPEC_HIDDEN; extern void resize_vk_surfaces( HWND hwnd, Window active, int mask, XWindowChanges *changes ) DECLSPEC_HIDDEN; +extern void invalidate_vk_surfaces( HWND hwnd ) DECLSPEC_HIDDEN; extern Window wine_vk_active_surface( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL wine_vk_direct_window_draw( HWND hwnd ) DECLSPEC_HIDDEN; extern void vulkan_thread_detach(void) DECLSPEC_HIDDEN; From 7c5a5621bcc18c84fe01b7dbd3c7195caacf3e70 Mon Sep 17 00:00:00 2001 From: Ivo Ivanov Date: Tue, 25 Oct 2022 14:53:57 +0300 Subject: [PATCH 0697/2777] winebus.sys: Enable hidraw for Simucube racing wheels and Fanatec pedals. Signed-off-by: Ivo Ivanov --- dlls/winebus.sys/bus_udev.c | 3 ++- dlls/winebus.sys/unix_private.h | 2 ++ dlls/winebus.sys/unixlib.c | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 34538ed2a5e..3f7eaba3790 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -1697,7 +1697,8 @@ static void udev_add_device(struct udev_device *dev, int fd) memcpy(desc.serialnumber, zeros, sizeof(zeros)); } - if (!is_dualshock4_gamepad(desc.vid, desc.pid) && !is_dualsense_gamepad(desc.vid, desc.pid) && !is_thrustmaster_hotas(desc.vid, desc.pid)) + if (!is_dualshock4_gamepad(desc.vid, desc.pid) && !is_dualsense_gamepad(desc.vid, desc.pid) && !is_thrustmaster_hotas(desc.vid, desc.pid) && + !is_simucube_wheel(desc.vid, desc.pid) && !is_fanatec_pedals(desc.vid, desc.pid)) { TRACE("hidraw %s: deferring %s to a different backend\n", debugstr_a(devnode), debugstr_device_desc(&desc)); close(fd); diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index a03200361ad..64161f9e236 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -273,5 +273,7 @@ BOOL is_dualshock4_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_dualsense_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_logitech_g920(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_thrustmaster_hotas(WORD vid, WORD pid) DECLSPEC_HIDDEN; +BOOL is_simucube_wheel(WORD vid, WORD pid) DECLSPEC_HIDDEN; +BOOL is_fanatec_pedals(WORD vid, WORD pid) DECLSPEC_HIDDEN; #endif /* __WINEBUS_UNIX_PRIVATE_H */ diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c index 5e7ce71779f..588ba7c2b93 100644 --- a/dlls/winebus.sys/unixlib.c +++ b/dlls/winebus.sys/unixlib.c @@ -110,6 +110,24 @@ BOOL is_thrustmaster_hotas(WORD vid, WORD pid) return vid == 0x044F && (pid == 0xB679 || pid == 0xB687 || pid == 0xB10A); } +BOOL is_simucube_wheel(WORD vid, WORD pid) +{ + if (vid != 0x16D0) return FALSE; + if (pid == 0x0D61) return TRUE; /* Simucube 2 Sport */ + if (pid == 0x0D60) return TRUE; /* Simucube 2 Pro */ + if (pid == 0x0D5F) return TRUE; /* Simucube 2 Ultimate */ + if (pid == 0x0D5A) return TRUE; /* Simucube 1 */ + return FALSE; +} + +BOOL is_fanatec_pedals(WORD vid, WORD pid) +{ + if (vid != 0x0EB7) return FALSE; + if (pid == 0x183B) return TRUE; /* Fanatec ClubSport Pedals v3 */ + if (pid == 0x1839) return TRUE; /* Fanatec ClubSport Pedals v1/v2 */ + return FALSE; +} + struct mouse_device { struct unix_device unix_device; From 7381d5384508a4ce29c1ff0702dc4c2a898a5585 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 5 Dec 2022 22:31:40 +0200 Subject: [PATCH 0698/2777] winebus.sys/sdl: Don't consider wheels / flight sticks as controllers. CW-Bug-Id: #21657 --- dlls/winebus.sys/bus_sdl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 960781fb2e4..f4414ae1f50 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -963,6 +963,7 @@ static void sdl_add_device(unsigned int index) SDL_Joystick* joystick; SDL_JoystickID id; + SDL_JoystickType joystick_type; SDL_GameController *controller = NULL; const char *product, *sdl_serial, *str; char guid_str[33], buffer[ARRAY_SIZE(desc.product)]; @@ -974,7 +975,10 @@ static void sdl_add_device(unsigned int index) return; } - if (options.map_controllers && pSDL_IsGameController(index)) + joystick_type = pSDL_JoystickGetType(joystick); + if (options.map_controllers && pSDL_IsGameController(index) + && joystick_type != SDL_JOYSTICK_TYPE_WHEEL + && joystick_type != SDL_JOYSTICK_TYPE_FLIGHT_STICK) controller = pSDL_GameControllerOpen(index); if (controller) product = pSDL_GameControllerName(controller); From d453328f9a1577036e428aba1cea44e1632ae195 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Fri, 2 Dec 2022 20:56:46 +0200 Subject: [PATCH 0699/2777] dinput: Don't apply G920 mapping when used through windows.gaming.input. Our windows.gaming.input.dll implementation is built on top of dinput while on Windows it seems to be completely independent. This means it doesn't respect the mapping entries created by Logitech's drivers for dinput and does regular axis mapping on top of hid. Because of that we have to ignore our dinput mapping for the device when we know it was opened through the special WGI GUID. --- dlls/dinput/joystick_hid.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index aa20a36e28c..ab4a799ff9f 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -176,6 +176,7 @@ struct hid_joystick { struct dinput_device base; LONG internal_ref; + BOOL wgi_device; HANDLE device; OVERLAPPED read_ovl; @@ -579,7 +580,7 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, case MAKELONG(HID_USAGE_GENERIC_RX, HID_USAGE_PAGE_GENERIC): case MAKELONG(HID_USAGE_GENERIC_RY, HID_USAGE_PAGE_GENERIC): case MAKELONG(HID_USAGE_GENERIC_RZ, HID_USAGE_PAGE_GENERIC): - if (impl->attrs.VendorID == VID_LOGITECH && impl->attrs.ProductID == PID_LOGITECH_G920) + if (!impl->wgi_device && impl->attrs.VendorID == VID_LOGITECH && impl->attrs.ProductID == PID_LOGITECH_G920) { if (j == HID_USAGE_GENERIC_X) { @@ -2108,6 +2109,7 @@ HRESULT hid_joystick_create_device( struct dinput *dinput, const GUID *guid, IDi &attrs, &impl->caps, dinput->dwVersion ); else { + impl->wgi_device = TRUE; wcscpy( impl->device_path, *(const WCHAR **)guid ); hr = hid_joystick_device_try_open( impl->device_path, &impl->device, &impl->preparsed, &attrs, &impl->caps, &impl->base.instance, dinput->dwVersion ); From 19b24ec7f142cab52c16020c60173905b2c98049 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Mon, 11 Oct 2021 11:01:33 +0200 Subject: [PATCH 0700/2777] msctf: Use list to keep thread managers. Thread managers were stored in thread local storage, which have a major flaw that they can't not be released by another thread. Signed-off-by: Zhiyi Zhang --- dlls/msctf/msctf.c | 46 +++++++---------------- dlls/msctf/msctf_internal.h | 1 - dlls/msctf/threadmgr.c | 73 ++++++++++++++++++++++++++++++++----- 3 files changed, 76 insertions(+), 44 deletions(-) diff --git a/dlls/msctf/msctf.c b/dlls/msctf/msctf.c index 0b1a3fbce15..c0dd2c21675 100644 --- a/dlls/msctf/msctf.c +++ b/dlls/msctf/msctf.c @@ -67,7 +67,6 @@ static UINT array_size; static struct list AtsList = LIST_INIT(AtsList); static UINT activated = 0; -DWORD tlsIndex = 0; TfClientId processId = 0; ITfCompartmentMgr *globalCompartmentMgr = NULL; @@ -395,23 +394,19 @@ HRESULT add_active_textservice(TF_LANGUAGEPROFILE *lp) ActivatedTextService *actsvr; ITfCategoryMgr *catmgr; AtsEntry *entry; - ITfThreadMgrEx *tm = TlsGetValue(tlsIndex); + ITfThreadMgr *tm; ITfClientId *clientid; - if (!tm) return E_UNEXPECTED; + if (FAILED(TF_GetThreadMgr(&tm))) return E_UNEXPECTED; actsvr = HeapAlloc(GetProcessHeap(),0,sizeof(ActivatedTextService)); - if (!actsvr) return E_OUTOFMEMORY; + if (!actsvr) goto fail; - ITfThreadMgrEx_QueryInterface(tm, &IID_ITfClientId, (void **)&clientid); + ITfThreadMgr_QueryInterface(tm, &IID_ITfClientId, (void **)&clientid); ITfClientId_GetClientId(clientid, &lp->clsid, &actsvr->tid); ITfClientId_Release(clientid); - if (!actsvr->tid) - { - HeapFree(GetProcessHeap(),0,actsvr); - return E_OUTOFMEMORY; - } + if (!actsvr->tid) goto fail; actsvr->pITfTextInputProcessor = NULL; actsvr->LanguageProfile = *lp; @@ -438,20 +433,21 @@ HRESULT add_active_textservice(TF_LANGUAGEPROFILE *lp) deactivate_remove_conflicting_ts(&actsvr->LanguageProfile.catid); if (activated > 0) - activate_given_ts(actsvr, tm); + activate_given_ts(actsvr, (ITfThreadMgrEx *)tm); entry = HeapAlloc(GetProcessHeap(),0,sizeof(AtsEntry)); - - if (!entry) - { - HeapFree(GetProcessHeap(),0,actsvr); - return E_OUTOFMEMORY; - } + if (!entry) goto fail; entry->ats = actsvr; list_add_head(&AtsList, &entry->entry); + ITfThreadMgr_Release(tm); return S_OK; + +fail: + ITfThreadMgr_Release(tm); + HeapFree(GetProcessHeap(), 0, actsvr); + return E_OUTOFMEMORY; } BOOL get_active_textservice(REFCLSID rclsid, TF_LANGUAGEPROFILE *profile) @@ -555,11 +551,9 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD fdwReason, LPVOID fImpLoad) switch (fdwReason) { case DLL_PROCESS_ATTACH: - tlsIndex = TlsAlloc(); break; case DLL_PROCESS_DETACH: if (fImpLoad) break; - TlsFree(tlsIndex); break; } return TRUE; @@ -593,20 +587,6 @@ HRESULT WINAPI TF_CreateThreadMgr(ITfThreadMgr **pptim) return ThreadMgr_Constructor(NULL,(IUnknown**)pptim); } -/*********************************************************************** - * TF_GetThreadMgr (MSCTF.@) - */ -HRESULT WINAPI TF_GetThreadMgr(ITfThreadMgr **pptim) -{ - TRACE("\n"); - *pptim = TlsGetValue(tlsIndex); - - if (*pptim) - ITfThreadMgr_AddRef(*pptim); - - return S_OK; -} - /*********************************************************************** * SetInputScope(MSCTF.@) */ diff --git a/dlls/msctf/msctf_internal.h b/dlls/msctf/msctf_internal.h index 45a39806c22..84f8ebf81c2 100644 --- a/dlls/msctf/msctf_internal.h +++ b/dlls/msctf/msctf_internal.h @@ -36,7 +36,6 @@ #define COOKIE_MAGIC_INPUTPROCESSORPROFILEACTIVATIONSINK 0x00b0 #define COOKIE_MAGIC_ACTIVELANGSINK 0x00c0 -extern DWORD tlsIndex DECLSPEC_HIDDEN; extern TfClientId processId DECLSPEC_HIDDEN; extern ITfCompartmentMgr *globalCompartmentMgr DECLSPEC_HIDDEN; diff --git a/dlls/msctf/threadmgr.c b/dlls/msctf/threadmgr.c index b3cd5fee981..f164afc57d7 100644 --- a/dlls/msctf/threadmgr.c +++ b/dlls/msctf/threadmgr.c @@ -37,6 +37,17 @@ WINE_DEFAULT_DEBUG_CHANNEL(msctf); +static CRITICAL_SECTION ThreadMgrCs; +static CRITICAL_SECTION_DEBUG ThreadMgrCsDebug = +{ + 0, 0, &ThreadMgrCs, + {&ThreadMgrCsDebug.ProcessLocksList, + &ThreadMgrCsDebug.ProcessLocksList }, + 0, 0, {(DWORD_PTR)(__FILE__ ": ThreadMgrCs")} +}; +static CRITICAL_SECTION ThreadMgrCs = {&ThreadMgrCsDebug, -1, 0, 0, 0, 0}; +struct list ThreadMgrList = LIST_INIT(ThreadMgrList); + typedef struct tagPreservedKey { struct list entry; @@ -98,6 +109,9 @@ typedef struct tagACLMulti { struct list ThreadMgrEventSink; struct list UIElementSink; struct list InputProcessorProfileActivationSink; + + DWORD threadId; + struct list entry; } ThreadMgr; typedef struct tagEnumTfDocumentMgr { @@ -110,6 +124,11 @@ typedef struct tagEnumTfDocumentMgr { static HRESULT EnumTfDocumentMgr_Constructor(struct list* head, IEnumTfDocumentMgrs **ppOut); +static inline ThreadMgr *impl_from_ITfThreadMgr(ITfThreadMgr *iface) +{ + return CONTAINING_RECORD(iface, ThreadMgr, ITfThreadMgrEx_iface); +} + static inline ThreadMgr *impl_from_ITfThreadMgrEx(ITfThreadMgrEx *iface) { return CONTAINING_RECORD(iface, ThreadMgr, ITfThreadMgrEx_iface); @@ -155,6 +174,35 @@ static inline EnumTfDocumentMgr *impl_from_IEnumTfDocumentMgrs(IEnumTfDocumentMg return CONTAINING_RECORD(iface, EnumTfDocumentMgr, IEnumTfDocumentMgrs_iface); } +/*********************************************************************** + * TF_GetThreadMgr (MSCTF.@) + */ +HRESULT WINAPI TF_GetThreadMgr(ITfThreadMgr **pptim) +{ + DWORD id = GetCurrentThreadId(); + ThreadMgr *cursor; + + TRACE("%p\n", pptim); + + if (!pptim) + return E_INVALIDARG; + + EnterCriticalSection(&ThreadMgrCs); + LIST_FOR_EACH_ENTRY(cursor, &ThreadMgrList, ThreadMgr, entry) + { + if (cursor->threadId == id) + { + ITfThreadMgrEx_AddRef(&cursor->ITfThreadMgrEx_iface); + *pptim = (ITfThreadMgr *)&cursor->ITfThreadMgrEx_iface; + LeaveCriticalSection(&ThreadMgrCs); + return S_OK; + } + } + LeaveCriticalSection(&ThreadMgrCs); + *pptim = NULL; + return E_FAIL; +} + static void ThreadMgr_Destructor(ThreadMgr *This) { struct list *cursor, *cursor2; @@ -163,7 +211,9 @@ static void ThreadMgr_Destructor(ThreadMgr *This) if (This->focusHook) UnhookWindowsHookEx(This->focusHook); - TlsSetValue(tlsIndex,NULL); + EnterCriticalSection(&ThreadMgrCs); + list_remove(&This->entry); + LeaveCriticalSection(&ThreadMgrCs); TRACE("destroying %p\n", This); if (This->focus) ITfDocumentMgr_Release(This->focus); @@ -386,17 +436,20 @@ static HRESULT WINAPI ThreadMgr_SetFocus(ITfThreadMgrEx *iface, ITfDocumentMgr * static LRESULT CALLBACK ThreadFocusHookProc(int nCode, WPARAM wParam, LPARAM lParam) { + ITfThreadMgr *ThreadMgr_iface; ThreadMgr *This; - This = TlsGetValue(tlsIndex); - if (!This) + if (FAILED(TF_GetThreadMgr(&ThreadMgr_iface))) { ERR("Hook proc but no ThreadMgr for this thread. Serious Error\n"); return 0; } + + This = impl_from_ITfThreadMgr(ThreadMgr_iface); if (!This->focusHook) { ERR("Hook proc but no ThreadMgr focus Hook. Serious Error\n"); + ITfThreadMgr_Release(ThreadMgr_iface); return 0; } @@ -417,6 +470,7 @@ static LRESULT CALLBACK ThreadFocusHookProc(int nCode, WPARAM wParam, LPARAM lPa } } + ITfThreadMgr_Release(ThreadMgr_iface); return CallNextHookEx(This->focusHook, nCode, wParam, lParam); } @@ -1346,13 +1400,8 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) return CLASS_E_NOAGGREGATION; /* Only 1 ThreadMgr is created per thread */ - This = TlsGetValue(tlsIndex); - if (This) - { - ThreadMgr_AddRef(&This->ITfThreadMgrEx_iface); - *ppOut = (IUnknown*)&This->ITfThreadMgrEx_iface; + if (SUCCEEDED(TF_GetThreadMgr((ITfThreadMgr **)ppOut))) return S_OK; - } This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ThreadMgr)); if (This == NULL) @@ -1367,7 +1416,6 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) This->ITfUIElementMgr_iface.lpVtbl = &ThreadMgrUIElementMgrVtbl; This->ITfSourceSingle_iface.lpVtbl = &SourceSingleVtbl; This->refCount = 1; - TlsSetValue(tlsIndex,This); CompartmentMgr_Constructor((IUnknown*)&This->ITfThreadMgrEx_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr); @@ -1384,6 +1432,11 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) list_init(&This->UIElementSink); list_init(&This->InputProcessorProfileActivationSink); + This->threadId = GetCurrentThreadId(); + EnterCriticalSection(&ThreadMgrCs); + list_add_tail(&ThreadMgrList, &This->entry); + LeaveCriticalSection(&ThreadMgrCs); + TRACE("returning %p\n", This); *ppOut = (IUnknown *)&This->ITfThreadMgrEx_iface; return S_OK; From 3e79671233c509c4ebad59bc4f7cb962108cd85c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Dec 2022 23:28:52 +0100 Subject: [PATCH 0701/2777] dsound: Initialize primary buffer with device's channel layout Fixes surround sound in some games, like Borderlands GOTY and Dead Space. --- dlls/dsound/dsound.c | 77 +----------------------------------- dlls/dsound/dsound_private.h | 1 - dlls/dsound/primary.c | 75 ++++++++++++++++++++++++++++++++++- 3 files changed, 76 insertions(+), 77 deletions(-) diff --git a/dlls/dsound/dsound.c b/dlls/dsound/dsound.c index f2aea64eeed..a08cb340fd8 100644 --- a/dlls/dsound/dsound.c +++ b/dlls/dsound/dsound.c @@ -23,7 +23,6 @@ #include #include #include -#include #define COBJMACROS @@ -137,9 +136,9 @@ static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice) device->ref = 1; device->priolevel = DSSCL_NORMAL; device->stopped = 1; - device->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE); - DSOUND_ParseSpeakerConfig(device); + device->speaker_config = 0; + device->num_speakers = 0; /* 3D listener initial parameters */ device->ds3dl.dwSize = sizeof(DS3DLISTENER); @@ -1124,75 +1123,3 @@ HRESULT WINAPI DirectSoundCreate8( return hr; } - -void DSOUND_ParseSpeakerConfig(DirectSoundDevice *device) -{ - switch (DSSPEAKER_CONFIG(device->speaker_config)) { - case DSSPEAKER_MONO: - device->speaker_angles[0] = M_PI/180.0f * 0.0f; - device->speaker_num[0] = 0; - device->num_speakers = 1; - device->lfe_channel = -1; - break; - - case DSSPEAKER_STEREO: - case DSSPEAKER_HEADPHONE: - device->speaker_angles[0] = M_PI/180.0f * -90.0f; - device->speaker_angles[1] = M_PI/180.0f * 90.0f; - device->speaker_num[0] = 0; /* Left */ - device->speaker_num[1] = 1; /* Right */ - device->num_speakers = 2; - device->lfe_channel = -1; - break; - - case DSSPEAKER_QUAD: - device->speaker_angles[0] = M_PI/180.0f * -135.0f; - device->speaker_angles[1] = M_PI/180.0f * -45.0f; - device->speaker_angles[2] = M_PI/180.0f * 45.0f; - device->speaker_angles[3] = M_PI/180.0f * 135.0f; - device->speaker_num[0] = 2; /* Rear left */ - device->speaker_num[1] = 0; /* Front left */ - device->speaker_num[2] = 1; /* Front right */ - device->speaker_num[3] = 3; /* Rear right */ - device->num_speakers = 4; - device->lfe_channel = -1; - break; - - case DSSPEAKER_5POINT1_BACK: - device->speaker_angles[0] = M_PI/180.0f * -135.0f; - device->speaker_angles[1] = M_PI/180.0f * -45.0f; - device->speaker_angles[2] = M_PI/180.0f * 0.0f; - device->speaker_angles[3] = M_PI/180.0f * 45.0f; - device->speaker_angles[4] = M_PI/180.0f * 135.0f; - device->speaker_angles[5] = 9999.0f; - device->speaker_num[0] = 4; /* Rear left */ - device->speaker_num[1] = 0; /* Front left */ - device->speaker_num[2] = 2; /* Front centre */ - device->speaker_num[3] = 1; /* Front right */ - device->speaker_num[4] = 5; /* Rear right */ - device->speaker_num[5] = 3; /* LFE */ - device->num_speakers = 6; - device->lfe_channel = 3; - break; - - case DSSPEAKER_5POINT1_SURROUND: - device->speaker_angles[0] = M_PI/180.0f * -90.0f; - device->speaker_angles[1] = M_PI/180.0f * -30.0f; - device->speaker_angles[2] = M_PI/180.0f * 0.0f; - device->speaker_angles[3] = M_PI/180.0f * 30.0f; - device->speaker_angles[4] = M_PI/180.0f * 90.0f; - device->speaker_angles[5] = 9999.0f; - device->speaker_num[0] = 4; /* Rear left */ - device->speaker_num[1] = 0; /* Front left */ - device->speaker_num[2] = 2; /* Front centre */ - device->speaker_num[3] = 1; /* Front right */ - device->speaker_num[4] = 5; /* Rear right */ - device->speaker_num[5] = 3; /* LFE */ - device->num_speakers = 6; - device->lfe_channel = 3; - break; - - default: - WARN("unknown speaker_config %lu\n", device->speaker_config); - } -} diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index 18dc369db5c..c39d9ec40ea 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -208,7 +208,6 @@ HRESULT IKsPrivatePropertySetImpl_Create(REFIID riid, void **ppv) DECLSPEC_HIDDE HRESULT DSOUND_Create(REFIID riid, void **ppv) DECLSPEC_HIDDEN; HRESULT DSOUND_Create8(REFIID riid, void **ppv) DECLSPEC_HIDDEN; HRESULT IDirectSoundImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_ds8) DECLSPEC_HIDDEN; -void DSOUND_ParseSpeakerConfig(DirectSoundDevice *device) DECLSPEC_HIDDEN; /* primary.c */ diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c index 4f46f57926d..5746798b663 100644 --- a/dlls/dsound/primary.c +++ b/dlls/dsound/primary.c @@ -24,6 +24,7 @@ */ #include +#include #define COBJMACROS #define NONAMELESSUNION @@ -109,6 +110,78 @@ static DWORD DSOUND_FindSpeakerConfig(IMMDevice *mmdevice, int channels) return def; } +static void DSOUND_ParseSpeakerConfig(DirectSoundDevice *device) +{ + switch (DSSPEAKER_CONFIG(device->speaker_config)) { + case DSSPEAKER_MONO: + device->speaker_angles[0] = M_PI/180.0f * 0.0f; + device->speaker_num[0] = 0; + device->num_speakers = 1; + device->lfe_channel = -1; + break; + + case DSSPEAKER_STEREO: + case DSSPEAKER_HEADPHONE: + device->speaker_angles[0] = M_PI/180.0f * -90.0f; + device->speaker_angles[1] = M_PI/180.0f * 90.0f; + device->speaker_num[0] = 0; /* Left */ + device->speaker_num[1] = 1; /* Right */ + device->num_speakers = 2; + device->lfe_channel = -1; + break; + + case DSSPEAKER_QUAD: + device->speaker_angles[0] = M_PI/180.0f * -135.0f; + device->speaker_angles[1] = M_PI/180.0f * -45.0f; + device->speaker_angles[2] = M_PI/180.0f * 45.0f; + device->speaker_angles[3] = M_PI/180.0f * 135.0f; + device->speaker_num[0] = 2; /* Rear left */ + device->speaker_num[1] = 0; /* Front left */ + device->speaker_num[2] = 1; /* Front right */ + device->speaker_num[3] = 3; /* Rear right */ + device->num_speakers = 4; + device->lfe_channel = -1; + break; + + case DSSPEAKER_5POINT1_BACK: + device->speaker_angles[0] = M_PI/180.0f * -135.0f; + device->speaker_angles[1] = M_PI/180.0f * -45.0f; + device->speaker_angles[2] = M_PI/180.0f * 0.0f; + device->speaker_angles[3] = M_PI/180.0f * 45.0f; + device->speaker_angles[4] = M_PI/180.0f * 135.0f; + device->speaker_angles[5] = 9999.0f; + device->speaker_num[0] = 4; /* Rear left */ + device->speaker_num[1] = 0; /* Front left */ + device->speaker_num[2] = 2; /* Front centre */ + device->speaker_num[3] = 1; /* Front right */ + device->speaker_num[4] = 5; /* Rear right */ + device->speaker_num[5] = 3; /* LFE */ + device->num_speakers = 6; + device->lfe_channel = 3; + break; + + case DSSPEAKER_5POINT1_SURROUND: + device->speaker_angles[0] = M_PI/180.0f * -90.0f; + device->speaker_angles[1] = M_PI/180.0f * -30.0f; + device->speaker_angles[2] = M_PI/180.0f * 0.0f; + device->speaker_angles[3] = M_PI/180.0f * 30.0f; + device->speaker_angles[4] = M_PI/180.0f * 90.0f; + device->speaker_angles[5] = 9999.0f; + device->speaker_num[0] = 4; /* Rear left */ + device->speaker_num[1] = 0; /* Front left */ + device->speaker_num[2] = 2; /* Front centre */ + device->speaker_num[3] = 1; /* Front right */ + device->speaker_num[4] = 5; /* Rear right */ + device->speaker_num[5] = 3; /* LFE */ + device->num_speakers = 6; + device->lfe_channel = 3; + break; + + default: + WARN("unknown speaker_config %lu\n", device->speaker_config); + } +} + static HRESULT DSOUND_WaveFormat(DirectSoundDevice *device, IAudioClient *client, BOOL forcewave, WAVEFORMATEX **wfx) { @@ -123,7 +196,7 @@ static HRESULT DSOUND_WaveFormat(DirectSoundDevice *device, IAudioClient *client if (FAILED(hr)) return hr; - if (mixwfe->Format.nChannels < device->num_speakers) { + if (device->num_speakers == 0 || mixwfe->Format.nChannels < device->num_speakers) { device->speaker_config = DSOUND_FindSpeakerConfig(device->mmdevice, mixwfe->Format.nChannels); DSOUND_ParseSpeakerConfig(device); } else if (mixwfe->Format.nChannels > device->num_speakers) { From e3be8d46b0f86461d4d9b00357a39190f3bb3fbc Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Mon, 31 Jan 2022 10:57:51 -0600 Subject: [PATCH 0702/2777] mmdevapi: Force PCM format for DeviceFormat property Native xaudio2 returns this format directly from GetDeviceDetails. Far Cry 4 expects to get a PCM format from GetDeviceDetails, so we need to set it to PCM here. --- dlls/mmdevapi/devenum.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/dlls/mmdevapi/devenum.c b/dlls/mmdevapi/devenum.c index 69e13a498cf..adb5eff5f23 100644 --- a/dlls/mmdevapi/devenum.c +++ b/dlls/mmdevapi/devenum.c @@ -470,6 +470,7 @@ static HRESULT set_format(MMDevice *dev) HRESULT hr; IAudioClient *client; WAVEFORMATEX *fmt; + WAVEFORMATEXTENSIBLE *fmtex; PROPVARIANT pv = { VT_EMPTY }; hr = drvs.pGetAudioEndpoint(&dev->devguid, &dev->IMMDevice_iface, &client); @@ -484,6 +485,24 @@ static HRESULT set_format(MMDevice *dev) IAudioClient_Release(client); + /* for most devices, native Windows only allows PCM formats for + * DeviceFormat. GetMixFormat often returns float. */ + if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ + fmtex = (WAVEFORMATEXTENSIBLE *)fmt; + if(IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)){ + fmt->wBitsPerSample = 16; + fmt->nBlockAlign = fmt->wBitsPerSample * fmt->nChannels / 8; + fmt->nAvgBytesPerSec = fmt->nSamplesPerSec * fmt->nBlockAlign; + fmtex->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + fmtex->Samples.wValidBitsPerSample = fmt->wBitsPerSample; + } + }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT){ + fmt->wFormatTag = WAVE_FORMAT_PCM; + fmt->wBitsPerSample = 16; + fmt->nBlockAlign = fmt->wBitsPerSample * fmt->nChannels / 8; + fmt->nAvgBytesPerSec = fmt->nSamplesPerSec * fmt->nBlockAlign; + } + pv.vt = VT_BLOB; pv.blob.cbSize = sizeof(WAVEFORMATEX) + fmt->cbSize; pv.blob.pBlobData = (BYTE*)fmt; From bfa43454c61b733b724164846c4d5afbc52e5280 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Thu, 3 Nov 2022 18:54:06 +0200 Subject: [PATCH 0703/2777] HACK: winegstreamer: Detect h264 use and create a tag file. CW-Bug-Id: #21473 --- dlls/winegstreamer/unix_private.h | 35 +++++++++++++++++++++++++++++++ dlls/winegstreamer/wg_parser.c | 15 +++++++++++++ dlls/winegstreamer/wg_transform.c | 4 ++++ 3 files changed, 54 insertions(+) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 09eb42da755..6c66ec4711b 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -25,6 +25,11 @@ #include +#include +#include +#include +#include + extern bool init_gstreamer(void) DECLSPEC_HIDDEN; extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; extern bool append_element(GstBin *bin, GstElement *element, GstElement **first, GstElement **last) DECLSPEC_HIDDEN; @@ -47,4 +52,34 @@ extern void wg_allocator_destroy(GstAllocator *allocator) DECLSPEC_HIDDEN; extern void wg_allocator_release_sample(GstAllocator *allocator, struct wg_sample *sample, bool discard_data) DECLSPEC_HIDDEN; +static inline void touch_h264_used_tag(void) +{ + const char *e; + + GST_LOG("h264 is used"); + + if ((e = getenv("STEAM_COMPAT_SHADER_PATH"))) + { + char buffer[PATH_MAX]; + int fd; + + snprintf(buffer, sizeof(buffer), "%s/h264-used", e); + + fd = open(buffer, O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (fd == -1) + { + GST_WARNING("Failed to open/create \"%s/h264-used\"", e); + return; + } + + futimens(fd, NULL); + + close(fd); + } + else + { + GST_WARNING("STEAM_COMPAT_SHADER_PATH not set, cannot create h264-used file"); + } +} + #endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 1864bac516f..4f07cbe8de7 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -489,6 +489,19 @@ static NTSTATUS wg_parser_stream_notify_qos(void *args) return S_OK; } +gboolean caps_detect_h264(GstCapsFeatures *features, GstStructure *structure, gpointer user_data) +{ + const char *cap_name = gst_structure_get_name(structure); + + if (!strcmp(cap_name, "video/x-h264")) + { + touch_h264_used_tag(); + return FALSE; + } + + return TRUE; +} + static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad, GstCaps *caps, GstElementFactory *fact, gpointer user) { @@ -497,6 +510,8 @@ static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad, GST_INFO("Using \"%s\".", name); + gst_caps_foreach(caps, caps_detect_h264, NULL); + if (parser->error) return GST_AUTOPLUG_SELECT_SKIP; if (strstr(name, "Player protection")) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 0e4e6d998b4..823a82e4793 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -361,6 +361,10 @@ NTSTATUS wg_transform_create(void *args) const gchar *media_type; GstEvent *event; + /* to detect h264_decoder_create() */ + if (input_format.major_type == WG_MAJOR_TYPE_VIDEO_H264) + touch_h264_used_tag(); + if (!init_gstreamer()) return STATUS_UNSUCCESSFUL; From c1612ac6c803616366c2bd55595419cfaebd3b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Fri, 24 Apr 2020 14:37:58 +0300 Subject: [PATCH 0704/2777] server: Try to retrieve the unix name on handles created from file descriptors. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46070 Signed-off-by: Gabriel Ivăncescu Fixes Unity of Command II, and possibly other games that use Python38.dll. --- server/fd.c | 39 +++++++++++++++++++++++++++++++++++++++ server/file.c | 1 + server/file.h | 2 ++ 3 files changed, 42 insertions(+) diff --git a/server/fd.c b/server/fd.c index d6ae8d08a1c..cb7f67a4863 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2149,6 +2149,45 @@ struct fd *create_anonymous_fd( const struct fd_ops *fd_user_ops, int unix_fd, s return NULL; } +void set_unix_name_of_fd( struct fd *fd, const struct stat *fd_st ) +{ +#ifdef __linux__ + static const char procfs_fmt[] = "/proc/self/fd/%d"; + + char path[PATH_MAX], procfs_path[sizeof(procfs_fmt) - 2 /* %d */ + 11]; + struct stat path_st; + ssize_t len; + + sprintf( procfs_path, procfs_fmt, fd->unix_fd ); + len = readlink( procfs_path, path, sizeof(path) ); + if (len == -1 || len >= sizeof(path) ) + return; + path[len] = '\0'; + + /* Make sure it's an absolute path, has at least one hardlink, and the same inode */ + if (path[0] != '/' || stat( path, &path_st ) || path_st.st_nlink < 1 || + path_st.st_dev != fd_st->st_dev || path_st.st_ino != fd_st->st_ino) + return; + + if (!(fd->unix_name = mem_alloc( len + 1 ))) + return; + memcpy( fd->unix_name, path, len + 1 ); + +#elif defined(F_GETPATH) + char path[PATH_MAX]; + size_t size; + + if (fcntl( fd->unix_fd, F_GETPATH, path ) == -1 || path[0] != '/') + return; + + size = strlen(path) + 1; + if (!(fd->unix_name = mem_alloc( size ))) + return; + memcpy( fd->unix_name, path, size ); + +#endif +} + /* retrieve the object that is using an fd */ void *get_fd_user( struct fd *fd ) { diff --git a/server/file.c b/server/file.c index 500ffcac153..bea0d09f9de 100644 --- a/server/file.c +++ b/server/file.c @@ -157,6 +157,7 @@ struct file *create_file_for_fd( int fd, unsigned int access, unsigned int shari release_object( file ); return NULL; } + set_unix_name_of_fd( file->fd, &st ); allow_fd_caching( file->fd ); return file; } diff --git a/server/file.h b/server/file.h index ffcbe102156..df3b3b3ae4a 100644 --- a/server/file.h +++ b/server/file.h @@ -22,6 +22,7 @@ #define __WINE_SERVER_FILE_H #include +#include #include "object.h" @@ -85,6 +86,7 @@ extern struct fd *open_fd( struct fd *root, const char *name, struct unicode_str unsigned int sharing, unsigned int options ); extern struct fd *create_anonymous_fd( const struct fd_ops *fd_user_ops, int unix_fd, struct object *user, unsigned int options ); +extern void set_unix_name_of_fd( struct fd *fd, const struct stat *fd_st ); extern struct fd *dup_fd_object( struct fd *orig, unsigned int access, unsigned int sharing, unsigned int options ); extern struct fd *get_fd_object_for_mapping( struct fd *fd, unsigned int access, unsigned int sharing ); From 0083e278c102dc0252718d80e53cac40cc970378 Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Tue, 19 Oct 2021 10:39:18 +0200 Subject: [PATCH 0705/2777] HACK: user32: Process WM_PAINT in peek_message for WS_EX_COMPOSITED windows. CW-Bug-Id: #19488 --- dlls/win32u/message.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index afb79ac7403..8cc6c13bd52 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2168,6 +2168,15 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, info.msg.wParam = result.wparam; info.msg.lParam = result.lparam; } + /* CXHACK 19488 */ + if (info.msg.message == WM_PAINT && + flags == (PM_REMOVE | PM_QS_INPUT | PM_QS_POSTMESSAGE | PM_QS_PAINT | PM_QS_SENDMESSAGE) && + (get_window_long( info.msg.hwnd, GWL_EXSTYLE ) & WS_EX_COMPOSITED )) + { + send_message( info.msg.hwnd, info.msg.message, info.msg.wParam, info.msg.lParam ); + flags &= ~PM_QS_PAINT; + continue; + } *msg = info.msg; msg->pt = point_phys_to_win_dpi( info.msg.hwnd, info.msg.pt ); thread_info->client_info.message_pos = MAKELONG( msg->pt.x, msg->pt.y ); From 995bff44020fdcd3d3273a2b2c263e6f65223b77 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Wed, 8 Dec 2021 23:36:27 +0100 Subject: [PATCH 0706/2777] kernelbase: Ignore LOAD_LIBRARY_SEARCH_SYSTEM32 flags for webservices.dll in LoadLibraryExW. CW-Bug-Id: #18637 --- dlls/kernelbase/loader.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dlls/kernelbase/loader.c b/dlls/kernelbase/loader.c index af3c193f331..e5b8bfe7f17 100644 --- a/dlls/kernelbase/loader.c +++ b/dlls/kernelbase/loader.c @@ -526,6 +526,14 @@ HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryExW( LPCWSTR name, HANDLE file, DWOR SetLastError( ERROR_INVALID_PARAMETER ); return 0; } + + /* HACK: allow webservices.dll to be shipped together with remote debugger tools. */ + if (flags == LOAD_LIBRARY_SEARCH_SYSTEM32 && !file && !wcscmp( name, L"webservices.dll" )) + { + FIXME( "HACK: ignoring LOAD_LIBRARY_SEARCH_SYSTEM32 for webservices.dll\n" ); + flags = 0; + } + RtlInitUnicodeString( &str, name ); if (str.Buffer[str.Length/sizeof(WCHAR) - 1] != ' ') return load_library( &str, flags ); From a2ff8ee9a1c48fc347048df4ab9b31d5b0a08cf9 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Mon, 8 Mar 2021 16:41:19 +0100 Subject: [PATCH 0707/2777] webservices: Prefer native. CW-Bug-Id: #18637 --- dlls/webservices/Makefile.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/webservices/Makefile.in b/dlls/webservices/Makefile.in index b58714d3253..c1a6b1438ea 100644 --- a/dlls/webservices/Makefile.in +++ b/dlls/webservices/Makefile.in @@ -2,6 +2,8 @@ MODULE = webservices.dll IMPORTLIB = webservices IMPORTS = winhttp rpcrt4 user32 ws2_32 +EXTRADLLFLAGS = -Wb,--prefer-native + C_SRCS = \ channel.c \ error.c \ From 59194479274e82b1b0a9f98ea8e7278f447e0270 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 22 Jun 2022 10:36:46 -0500 Subject: [PATCH 0708/2777] opengl32: HACK: Fixup shaders for Cossacks 3. CW-Bug-Id: #20865 --- dlls/opengl32/make_opengl | 2 + dlls/opengl32/thunks.c | 18 +------- dlls/opengl32/wgl.c | 94 +++++++++++++++++++++++++++++++++++++++ include/wine/wgl_driver.h | 2 +- 4 files changed, 99 insertions(+), 17 deletions(-) diff --git a/dlls/opengl32/make_opengl b/dlls/opengl32/make_opengl index b1161632f81..761ffceced2 100755 --- a/dlls/opengl32/make_opengl +++ b/dlls/opengl32/make_opengl @@ -172,6 +172,8 @@ my %manual_win_thunks = "glMapNamedBufferEXT" => 1, "glMapNamedBufferRange" => 1, "glMapNamedBufferRangeEXT" => 1, + "glShaderSource" => 1, + "glShaderSourceARB" => 1, "glUnmapBuffer" => 1, "glUnmapBufferARB" => 1, "glUnmapNamedBuffer" => 1, diff --git a/dlls/opengl32/thunks.c b/dlls/opengl32/thunks.c index e90409de76f..69be625e6f5 100644 --- a/dlls/opengl32/thunks.c +++ b/dlls/opengl32/thunks.c @@ -17979,22 +17979,6 @@ static void WINAPI glShaderOp3EXT( GLenum op, GLuint res, GLuint arg1, GLuint ar if ((status = UNIX_CALL( glShaderOp3EXT, &args ))) WARN( "glShaderOp3EXT returned %#lx\n", status ); } -static void WINAPI glShaderSource( GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length ) -{ - struct glShaderSource_params args = { .teb = NtCurrentTeb(), .shader = shader, .count = count, .string = string, .length = length }; - NTSTATUS status; - TRACE( "shader %d, count %d, string %p, length %p\n", shader, count, string, length ); - if ((status = UNIX_CALL( glShaderSource, &args ))) WARN( "glShaderSource returned %#lx\n", status ); -} - -static void WINAPI glShaderSourceARB( GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length ) -{ - struct glShaderSourceARB_params args = { .teb = NtCurrentTeb(), .shaderObj = shaderObj, .count = count, .string = string, .length = length }; - NTSTATUS status; - TRACE( "shaderObj %d, count %d, string %p, length %p\n", shaderObj, count, string, length ); - if ((status = UNIX_CALL( glShaderSourceARB, &args ))) WARN( "glShaderSourceARB returned %#lx\n", status ); -} - static void WINAPI glShaderStorageBlockBinding( GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding ) { struct glShaderStorageBlockBinding_params args = { .teb = NtCurrentTeb(), .program = program, .storageBlockIndex = storageBlockIndex, .storageBlockBinding = storageBlockBinding }; @@ -24342,6 +24326,8 @@ extern void * WINAPI glMapNamedBuffer( GLuint buffer, GLenum access ) DECLSPEC_H extern void * WINAPI glMapNamedBufferEXT( GLuint buffer, GLenum access ) DECLSPEC_HIDDEN; extern void * WINAPI glMapNamedBufferRange( GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access ) DECLSPEC_HIDDEN; extern void * WINAPI glMapNamedBufferRangeEXT( GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access ) DECLSPEC_HIDDEN; +extern void WINAPI glShaderSource( GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length ) DECLSPEC_HIDDEN; +extern void WINAPI glShaderSourceARB( GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length ) DECLSPEC_HIDDEN; extern GLboolean WINAPI glUnmapBuffer( GLenum target ) DECLSPEC_HIDDEN; extern GLboolean WINAPI glUnmapBufferARB( GLenum target ) DECLSPEC_HIDDEN; extern GLboolean WINAPI glUnmapNamedBuffer( GLuint buffer ) DECLSPEC_HIDDEN; diff --git a/dlls/opengl32/wgl.c b/dlls/opengl32/wgl.c index f57f7703409..0441f9db888 100644 --- a/dlls/opengl32/wgl.c +++ b/dlls/opengl32/wgl.c @@ -1277,6 +1277,100 @@ static BOOL WINAPI call_opengl_debug_message_callback( struct wine_gl_debug_mess return TRUE; } +static char *fixup_shader( GLsizei count, const GLchar *const*string, const GLint *length ) +{ + static int needs_fixup = -1; + static unsigned int once; + + const char add_ext[] = "#version 120\r\n" + "#extension GL_ARB_explicit_uniform_location : enable\r\n" + "#extension GL_ARB_explicit_attrib_location : enable\r\n"; + const char search_str[] = "uniform mat4 boneMatrices[NBONES];"; + const char prepend_str[] = "layout(location = 2) "; + unsigned int search_len, new_len; + const char *p, *next; + BOOL found = FALSE; + char *new, *out; + + if (needs_fixup == -1) + { + const char *sgi = getenv("SteamGameId"); + + needs_fixup = sgi && !strcmp( sgi, "333420" ); + } + + if (!needs_fixup) return NULL; + + if (length || count != 1) return NULL; + + if (!once++) + FIXME( "HACK: Fixing up shader.\n" ); + + TRACE( "Appending extension string.\n" ); + new_len = strlen( *string ) + sizeof(prepend_str) - 1 + sizeof(add_ext); + new = out = malloc( new_len ); + memcpy( out, add_ext, sizeof(add_ext) - 1 ); + out += sizeof(add_ext) - 1; + + search_len = sizeof(search_str) - 1; + next = *string; + while (*(p = next)) + { + while (*next && *next != '\r' && *next != '\n') ++next; + + if (next - p == search_len && !memcmp( p, search_str, search_len )) + { + TRACE( "Adding explicit location.\n" ); + memcpy( out, *string, p - *string ); + out += p - *string; + memcpy( out, prepend_str, sizeof(prepend_str) - 1 ); + out += sizeof(prepend_str) - 1; + strcpy( out, p ); + found = TRUE; + break; + } + + while (*next == '\n' || *next == '\r') ++next; + } + if (!found) + strcpy( out, *string ); + + return new; +} + +void WINAPI glShaderSource( GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length ) +{ + struct glShaderSource_params args = { .teb = NtCurrentTeb(), .shader = shader, .count = count, .string = string, .length = length }; + NTSTATUS status; + char *new; + TRACE( "shader %d, count %d, string %p, length %p\n", shader, count, string, length ); + if ((new = fixup_shader( count, string, length ))) + { + args.string = (const GLchar **)&new; + args.count = 1; + args.length = NULL; + } + if ((status = UNIX_CALL( glShaderSource, &args ))) WARN( "glShaderSource returned %#lx\n", status ); + free( new ); +} + +void WINAPI glShaderSourceARB( GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length ) +{ + struct glShaderSourceARB_params args = { .teb = NtCurrentTeb(), .shaderObj = shaderObj, .count = count, .string = string, .length = length }; + NTSTATUS status; + char *new; + TRACE( "shaderObj %d, count %d, string %p, length %p\n", shaderObj, count, string, length ); + if ((new = fixup_shader( count, string, length ))) + { + args.string = (const GLcharARB **)&new; + args.count = 1; + args.length = NULL; + } + if ((status = UNIX_CALL( glShaderSourceARB, &args ))) WARN( "glShaderSourceARB returned %#lx\n", status ); + free( new ); +} + + /*********************************************************************** * OpenGL initialisation routine */ diff --git a/include/wine/wgl_driver.h b/include/wine/wgl_driver.h index ed11d8caa0e..919245fa1cf 100644 --- a/include/wine/wgl_driver.h +++ b/include/wine/wgl_driver.h @@ -7,7 +7,7 @@ #define WINE_GLAPI #endif -#define WINE_WGL_DRIVER_VERSION 23 +#define WINE_WGL_DRIVER_VERSION 24 struct wgl_context; struct wgl_pbuffer; From 4b1c34a1064c27ed9a578dedab6d5ca220f0c458 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 17 Jun 2022 10:02:28 -0500 Subject: [PATCH 0709/2777] winex11.drv: Always call XSync() in destroy_whole_window() if there is client window. Fixes Cossacks III hanging on start with black screen and X error & fault in log. https://gitlab.winehq.org/wine/wine/-/merge_requests/264 --- dlls/winex11.drv/window.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 9be7df091ec..e6cae0684d9 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2073,6 +2073,8 @@ static void destroy_whole_window( struct x11drv_win_data *data, BOOL already_des } return; } + if (data->client_window && !already_destroyed) + XSync( data->display, False ); } else { From 31e0395950217576ee0fae2d6e84b83db1ab6c52 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Thu, 24 Jun 2021 17:27:08 +0200 Subject: [PATCH 0710/2777] HACK: win32u/font: Support font linking for Arial and Courier New. This helps the Rockstar installer to fallback to appropriate fonts for CJK languages. CW-Bug-Id: #18969 CW-Bug-Id: #19917 --- dlls/win32u/font.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/font.c b/dlls/win32u/font.c index c3ba1a9a377..679da4cc83a 100644 --- a/dlls/win32u/font.c +++ b/dlls/win32u/font.c @@ -1556,6 +1556,14 @@ static const WCHAR ms_minchoW[] = {'M','S',' ','M','i','n','c','h','o',0}; static const WCHAR ms_p_minchoW[] = {'M','S',' ','P','M','i','n','c','h','o',0}; +static const WCHAR arialW[] = + {'A','r','i','a','l',0}; +static const WCHAR arial_boldW[] = + {'A','r','i','a','l',' ','B','o','l','d',0}; +static const WCHAR courier_newW[] = + {'C','o','u','r','i','e','r',' ','N','e','w',0}; +static const WCHAR courier_new_boldW[] = + {'C','o','u','r','i','e','r',' ','N','e','w',' ','B','o','l','d',0}; static const WCHAR * const font_links_list[] = { @@ -3098,6 +3106,10 @@ static void update_font_system_link_info(void) } set_multi_value_key(hkey, link_reg->font_name, link, len); } + set_multi_value_key(hkey, arialW, link, len); + set_multi_value_key(hkey, arial_boldW, link, len); + set_multi_value_key(hkey, courier_newW, link, len); + set_multi_value_key(hkey, courier_new_boldW, link, len); NtClose( hkey ); } } @@ -3136,7 +3148,13 @@ static void update_codepage( UINT screen_dpi ) if (query_reg_ascii_value( wine_fonts_key, "Codepages", info, sizeof(value_buffer) )) { cp_match = !wcscmp( (const WCHAR *)info->Data, cpbufW ); - if (cp_match && screen_dpi == font_dpi) return; /* already set correctly */ + if (cp_match && screen_dpi == font_dpi) + { + /* already set correctly, but, as a HACK, update font link + info anyway, so that old Proton prefixes are fixed */ + update_font_system_link_info(); + return; + } TRACE( "updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n", debugstr_w((const WCHAR *)info->Data), font_dpi, ansi_cp.CodePage, oem_cp.CodePage, screen_dpi ); } From 11ed7c74db2e3775dfe54ce9e32331c032fb2210 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 20 Dec 2022 13:56:34 -0600 Subject: [PATCH 0711/2777] ntdll: Stop unwinding in RtlCaptureStackBackTrace() if unwind data is unavailable on x64. CW-Bug-Id: #21719 --- dlls/ntdll/signal_x86_64.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index e7afdf22a0e..32cc0b3e8b6 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -259,7 +259,7 @@ static void dump_scope_table( ULONG64 base, const SCOPE_TABLE *table ) static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEXT *context ) { LDR_DATA_TABLE_ENTRY *module; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; dispatch->ImageBase = 0; dispatch->ScopeIndex = 0; @@ -290,7 +290,11 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX } if (status != STATUS_UNSUCCESSFUL) return status; } - else WARN( "exception data not found in %s\n", debugstr_w(module->BaseDllName.Buffer) ); + else + { + WARN( "exception data not found in %s\n", debugstr_w(module->BaseDllName.Buffer) ); + status = STATUS_UNSUCCESSFUL; + } /* no exception information, treat as a leaf function */ @@ -298,7 +302,7 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX dispatch->LanguageHandler = NULL; context->Rip = *(ULONG64 *)context->Rsp; context->Rsp = context->Rsp + sizeof(ULONG64); - return STATUS_SUCCESS; + return status ? STATUS_NOT_FOUND : STATUS_SUCCESS; } @@ -440,7 +444,7 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_contex for (;;) { status = virtual_unwind( UNW_FLAG_EHANDLER, &dispatch, &context ); - if (status != STATUS_SUCCESS) return status; + if (status != STATUS_SUCCESS && status != STATUS_NOT_FOUND) return status; unwind_done: if (!dispatch.EstablisherFrame) break; @@ -1338,7 +1342,7 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec for (;;) { status = virtual_unwind( UNW_FLAG_UHANDLER, &dispatch, &new_context ); - if (status != STATUS_SUCCESS) raise_status( status, rec ); + if (status != STATUS_SUCCESS && status != STATUS_NOT_FOUND) raise_status( status, rec ); unwind_done: if (!dispatch.EstablisherFrame) break; From df6011e1fcf2e3e7607053244de369cf7d6dd094 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 21 Dec 2022 15:45:58 -0600 Subject: [PATCH 0712/2777] amd_ags_x64: Copy native module to a temporary file for getting version info. Otherwise we are searching for version info in our builtin module (that changed with Wine 8.0). --- dlls/amd_ags_x64/amd_ags_x64_main.c | 34 ++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index b58926c928c..97cc6d48afa 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -240,29 +240,48 @@ static enum amd_ags_version determine_ags_version(void) UINT vallen, i; VS_FIXEDFILEINFO *info; UINT16 major, minor, patch; + WCHAR dllname[MAX_PATH], temp_path[MAX_PATH], temp_name[MAX_PATH]; - infosize = GetFileVersionInfoSizeW(L"amd_ags_x64.dll", NULL); + *temp_name = 0; + if (!(infosize = GetModuleFileNameW(GetModuleHandleW(L"amd_ags_x64.dll"), dllname, ARRAY_SIZE(dllname))) + || infosize == ARRAY_SIZE(dllname)) + { + ERR("GetModuleFileNameW failed.\n"); + goto done; + } + if (!GetTempPathW(MAX_PATH, temp_path) || !GetTempFileNameW(temp_path, L"tmp", 0, temp_name)) + { + ERR("Failed getting temp file name.\n"); + goto done; + } + if (!CopyFileW(dllname, temp_name, FALSE)) + { + ERR("Failed to copy file.\n"); + goto done; + } + + infosize = GetFileVersionInfoSizeW(temp_name, NULL); if (!infosize) { - WARN("Unable to determine desired version of amd_ags_x64.dll.\n"); + ERR("Unable to determine desired version of amd_ags_x64.dll.\n"); goto done; } if (!(infobuf = heap_alloc(infosize))) { - WARN("Failed to allocate memory.\n"); + ERR("Failed to allocate memory.\n"); goto done; } - if (!GetFileVersionInfoW(L"amd_ags_x64.dll", 0, infosize, infobuf)) + if (!GetFileVersionInfoW(temp_name, 0, infosize, infobuf)) { - WARN("Unable to determine desired version of amd_ags_x64.dll.\n"); + ERR("Unable to determine desired version of amd_ags_x64.dll.\n"); goto done; } if (!VerQueryValueW(infobuf, L"\\", &val, &vallen) || (vallen != sizeof(VS_FIXEDFILEINFO))) { - WARN("Unable to determine desired version of amd_ags_x64.dll.\n"); + ERR("Unable to determine desired version of amd_ags_x64.dll.\n"); goto done; } @@ -284,6 +303,9 @@ static enum amd_ags_version determine_ags_version(void) } done: + if (*temp_name) + DeleteFileW(temp_name); + heap_free(infobuf); TRACE("Using AGS v%d.%d.%d interface\n", amd_ags_info[ret].major, amd_ags_info[ret].minor, amd_ags_info[ret].patch); From b6f9556d6c668e4113dd57b6e0fdb11b7a4962d5 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 29 Nov 2022 16:40:42 -0600 Subject: [PATCH 0713/2777] ntdll: Improve faults logging. CW-Bug-Id: #21601 --- dlls/ntdll/signal_i386.c | 12 +++++++ dlls/ntdll/signal_x86_64.c | 27 ++++++++++++--- dlls/ntdll/unix/loader.c | 37 ++++++++++++++++++++ dlls/ntdll/unix/signal_i386.c | 3 ++ dlls/ntdll/unix/signal_x86_64.c | 61 +++++++++++++++++++++++++++++++++ dlls/ntdll/unix/unix_private.h | 3 ++ dlls/ntdll/unixlib.h | 14 ++++++++ 7 files changed, 153 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index 9709be34f8c..5d451220e01 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -179,6 +179,18 @@ NTSTATUS WINAPI dispatch_exception( EXCEPTION_RECORD *rec, CONTEXT *context ) for (c = 0; c < rec->NumberParameters; c++) TRACE( " info[%ld]=%08Ix\n", c, rec->ExceptionInformation[c] ); + if (WINE_BACKTRACE_LOG_ON()) + { + struct debugstr_pc_args params; + char buffer[256]; + + params.pc = rec->ExceptionAddress; + params.buffer = buffer; + params.size = sizeof(buffer); + if (!NTDLL_UNIX_CALL( debugstr_pc, ¶ms )) + WINE_BACKTRACE_LOG( "--- Exception %#lx at %s.\n", rec->ExceptionCode, buffer ); + } + if (rec->ExceptionCode == EXCEPTION_WINE_STUB) { if (rec->ExceptionInformation[1] >> 16) diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index 32cc0b3e8b6..f41a09f9ca4 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -253,10 +253,18 @@ static void dump_scope_table( ULONG64 base, const SCOPE_TABLE *table ) } +static BOOL need_backtrace( DWORD exc_code ) +{ + if (!WINE_BACKTRACE_LOG_ON()) return FALSE; + return exc_code != EXCEPTION_WINE_NAME_THREAD && exc_code != DBG_PRINTEXCEPTION_WIDE_C + && exc_code != DBG_PRINTEXCEPTION_C && exc_code != EXCEPTION_WINE_CXX_EXCEPTION + && exc_code != 0x6ba; +} + /*********************************************************************** * virtual_unwind */ -static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEXT *context ) +static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEXT *context, BOOL dump_backtrace ) { LDR_DATA_TABLE_ENTRY *module; NTSTATUS status = STATUS_SUCCESS; @@ -269,6 +277,14 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX if ((dispatch->FunctionEntry = lookup_function_info( context->Rip, &dispatch->ImageBase, &module ))) { + if (dump_backtrace) + { + if (module) + WINE_BACKTRACE_LOG( "%p: %s + %p.\n", (void *)context->Rip, debugstr_w(module->BaseDllName.Buffer), + (void *)((char *)context->Rip - (char *)dispatch->ImageBase) ); + else + WINE_BACKTRACE_LOG( "%p: unknown module.\n", (void *)context->Rip ); + } dispatch->LanguageHandler = RtlVirtualUnwind( type, dispatch->ImageBase, context->Rip, dispatch->FunctionEntry, context, &dispatch->HandlerData, &dispatch->EstablisherFrame, @@ -443,7 +459,7 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_contex dispatch.HistoryTable = &table; for (;;) { - status = virtual_unwind( UNW_FLAG_EHANDLER, &dispatch, &context ); + status = virtual_unwind( UNW_FLAG_EHANDLER, &dispatch, &context, need_backtrace( rec->ExceptionCode )); if (status != STATUS_SUCCESS && status != STATUS_NOT_FOUND) return status; unwind_done: @@ -529,6 +545,9 @@ NTSTATUS WINAPI dispatch_exception( EXCEPTION_RECORD *rec, CONTEXT *context ) NTSTATUS status; DWORD c; + if (need_backtrace( rec->ExceptionCode )) + WINE_BACKTRACE_LOG( "--- Exception %#x.\n", (int)rec->ExceptionCode ); + TRACE_(seh)( "code=%lx flags=%lx addr=%p ip=%Ix\n", rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, context->Rip ); for (c = 0; c < min( EXCEPTION_MAXIMUM_PARAMETERS, rec->NumberParameters ); c++) @@ -1341,7 +1360,7 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec for (;;) { - status = virtual_unwind( UNW_FLAG_UHANDLER, &dispatch, &new_context ); + status = virtual_unwind( UNW_FLAG_UHANDLER, &dispatch, &new_context, FALSE ); if (status != STATUS_SUCCESS && status != STATUS_NOT_FOUND) raise_status( status, rec ); unwind_done: @@ -1587,7 +1606,7 @@ USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, if (hash) *hash = 0; for (i = 0; i < skip + count; i++) { - status = virtual_unwind( UNW_FLAG_NHANDLER, &dispatch, &context ); + status = virtual_unwind( UNW_FLAG_NHANDLER, &dispatch, &context, FALSE ); if (status != STATUS_SUCCESS) return i; if (!dispatch.EstablisherFrame) break; diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 434ff40717a..cdbdecd520c 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2211,6 +2211,42 @@ static NTSTATUS steamclient_setup_trampolines( void *args ) return STATUS_SUCCESS; } +static BOOL debugstr_pc_impl( void *pc, char *buffer, unsigned int size ) +{ + unsigned int len; + char *s = buffer; + Dl_info info; + + snprintf( s, size, "%p:", pc ); + if (!dladdr( pc, &info )) return FALSE; + + s += (len = strlen( s )); + size -= len; + snprintf( s, size, " %s + %#zx", info.dli_fname, (char *)pc - (char *)info.dli_fbase ); + if (info.dli_sname) + { + s += (len = strlen( s )); + size -= len; + snprintf( s, size, " (%s + %#zx)", info.dli_sname, (char *)pc - (char *)info.dli_saddr ); + } + return TRUE; +} + +static NTSTATUS debugstr_pc( void *args ) +{ + struct debugstr_pc_args *params = args; + + return debugstr_pc_impl( params->pc, params->buffer, params->size ) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; +} + +const char * CDECL wine_debuginfostr_pc( void *pc ) +{ + char buffer[256]; + + debugstr_pc_impl( pc, buffer, sizeof(buffer) ); + return __wine_dbg_strdup( buffer ); +} + static BOOL report_native_pc_as_ntdll; static NTSTATUS is_pc_in_native_so(void *pc) @@ -2236,6 +2272,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = system_time_precise, steamclient_setup_trampolines, is_pc_in_native_so, + debugstr_pc, }; BOOL ac_odyssey; diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index a8b68bdb412..b2dfe82beb5 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1817,6 +1817,9 @@ static BOOL handle_syscall_fault( ucontext_t *sigcontext, void *stack_ptr, } else { + WINE_BACKTRACE_LOG( "--- Exception %#lx at %s.\n", rec->ExceptionCode, + wine_debuginfostr_pc( rec->ExceptionAddress )); + TRACE( "returning to user mode ip=%08x ret=%08lx\n", frame->eip, rec->ExceptionCode ); stack = (UINT *)frame; *(--stack) = rec->ExceptionCode; diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index b52d50a7820..51b9b79d931 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -561,6 +561,7 @@ static NTSTATUS dwarf_virtual_unwind( ULONG64 ip, ULONG64 *frame,CONTEXT *contex TRACE( "function %lx base %p cie %p len %x id %x version %x aug '%s' code_align %lu data_align %ld retaddr %s\n", ip, bases->func, cie, cie->length, cie->id, cie->version, cie->augmentation, info.code_align, info.data_align, dwarf_reg_names[info.retaddr_reg] ); + WINE_BACKTRACE_LOG( "%s.\n", wine_debuginfostr_pc((void *)context->Rip) ); end = NULL; for (augmentation = cie->augmentation; *augmentation; augmentation++) @@ -2132,6 +2133,47 @@ static inline BOOL handle_interrupt( ucontext_t *sigcontext, EXCEPTION_RECORD *r return TRUE; } +static void WINAPI dump_syscall_fault( CONTEXT *context, DWORD exc_code ) +{ + struct syscall_frame *frame = amd64_thread_data()->syscall_frame; + struct unwind_builtin_dll_params params; + + __TRY + { + DISPATCHER_CONTEXT dispatch; + + context->ContextFlags &= ~0x40; + + dispatch.EstablisherFrame = context->Rsp; + dispatch.TargetIp = 0; + dispatch.ContextRecord = context; + dispatch.HistoryTable = NULL; + + params.type = UNW_FLAG_UHANDLER; + params.dispatch = &dispatch; + params.context = context; + + while (1) + { + if (context->Rip >= (ULONG_PTR)__wine_syscall_dispatcher + && context->Rip <= (ULONG_PTR)__wine_syscall_dispatcher_return) + { + WINE_BACKTRACE_LOG( "__wine_syscall_dispatcher.\n" ); + break; + } + if (unwind_builtin_dll( ¶ms )) + break; + } + } + __EXCEPT + { + WINE_BACKTRACE_LOG( "Fault during unwind.\n" ); + } + __ENDTRY + + WINE_BACKTRACE_LOG( "returning to user mode ip=%016lx ret=%08x\n", frame->rip, exc_code ); + __wine_syscall_dispatcher_return( frame, exc_code ); +} /*********************************************************************** * handle_syscall_fault @@ -2173,6 +2215,25 @@ static BOOL handle_syscall_fault( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, } else { + const char *kernel_stack = ntdll_get_thread_data()->kernel_stack; + char *stack = (char *)RSP_sig(sigcontext); + + WINE_BACKTRACE_LOG( "--- Exception %#x at %s.\n", rec->ExceptionCode, + wine_debuginfostr_pc( rec->ExceptionAddress )); + + if (!process_exiting && WINE_BACKTRACE_LOG_ON() && stack > kernel_stack + kernel_stack_guard_size + 4096) + { + stack = (char *)((ULONG_PTR)stack & ~(ULONG_PTR)15); + stack -= sizeof(*context); + RCX_sig(sigcontext) = (ULONG_PTR)stack; + RDX_sig(sigcontext) = rec->ExceptionCode; + memcpy( stack, context, sizeof(*context) ); + stack -= 0x28; + RIP_sig(sigcontext) = (ULONG_PTR)dump_syscall_fault; + RSP_sig(sigcontext) = (ULONG_PTR)stack; + return TRUE; + } + TRACE_(seh)( "returning to user mode ip=%016lx ret=%08x\n", frame->rip, rec->ExceptionCode ); RCX_sig(sigcontext) = (ULONG_PTR)frame; RDX_sig(sigcontext) = rec->ExceptionCode; diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index a08626e3db9..9a97a1ed3c3 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -309,6 +309,9 @@ extern ULONG WINAPI __wine_set_unix_env( const char *var, const char *val ) DECL #define IMAGE_DLLCHARACTERISTICS_PREFER_NATIVE 0x0010 /* Wine extension */ +extern void CDECL set_unix_env(const char *var, const char *val) DECLSPEC_HIDDEN; +extern const char * CDECL wine_debuginfostr_pc(void *pc) DECLSPEC_HIDDEN; + #define TICKSPERSEC 10000000 #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)86400) diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index 59a5a46d806..f0cf12b904c 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -44,6 +44,13 @@ struct steamclient_setup_trampolines_params HMODULE tgt_mod; }; +struct debugstr_pc_args +{ + void *pc; + char *buffer; + unsigned int size; +}; + enum ntdll_unix_funcs { unix_load_so_dll, @@ -51,10 +58,17 @@ enum ntdll_unix_funcs unix_system_time_precise, unix_steamclient_setup_trampolines, unix_is_pc_in_native_so, + unix_debugstr_pc, }; extern unixlib_handle_t ntdll_unix_handle; #define NTDLL_UNIX_CALL( func, params ) __wine_unix_call_dispatcher( ntdll_unix_handle, unix_ ## func, params ) +#define WINE_BACKTRACE_LOG_ON() WARN_ON(seh) + +#define WINE_BACKTRACE_LOG(args...) do { \ + WARN_(seh)("backtrace: " args); \ + } while (0) + #endif /* __NTDLL_UNIXLIB_H */ From dc82796447c47f096641578cdef081eeab96c001 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 19 May 2021 13:33:36 -0400 Subject: [PATCH 0714/2777] winevulkan: Implement VK_KHR_external_memory_win32 for buffers. Signed-off-by: Derek Lesho --- dlls/vulkan-1/tests/vulkan.c | 5 +- dlls/winevulkan/make_vulkan | 48 ++++-- dlls/winevulkan/vulkan.c | 260 +++++++++++++++++++++++++++++-- dlls/winevulkan/vulkan_private.h | 9 ++ 4 files changed, 292 insertions(+), 30 deletions(-) diff --git a/dlls/vulkan-1/tests/vulkan.c b/dlls/vulkan-1/tests/vulkan.c index b9a36a55653..7ee73bdca5d 100644 --- a/dlls/vulkan-1/tests/vulkan.c +++ b/dlls/vulkan-1/tests/vulkan.c @@ -620,8 +620,9 @@ static void import_memory(VkDevice vk_device, VkMemoryAllocateInfo alloc_info, V import_handle_info.name = L"wine_test_buffer_export_name"; vr = vkAllocateMemory(vk_device, &alloc_info, NULL, &memory); - ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); - vkFreeMemory(vk_device, memory, NULL); + todo_wine ok(vr == VK_SUCCESS, "vkAllocateMemory failed, VkResult %d.\n", vr); + if (vr == VK_SUCCESS) + vkFreeMemory(vk_device, memory, NULL); } } diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index da0523e30ce..5e545754aa4 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -113,7 +113,6 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_physical_device_drm", "VK_GOOGLE_surfaceless_query", "VK_KHR_external_fence_fd", - "VK_KHR_external_memory_fd", "VK_KHR_external_semaphore_fd", "VK_SEC_amigo_profiling", # Angle specific. @@ -129,7 +128,6 @@ UNSUPPORTED_EXTENSIONS = [ # winevulkan may nonetheless use, or extensions we want to generate headers for # but not expose to applications (useful for test commits) UNEXPOSED_EXTENSIONS = { - "VK_KHR_external_memory_win32", } # The Vulkan loader provides entry-points for core functionality and important @@ -195,7 +193,7 @@ FUNCTION_OVERRIDES = { "vkEnumerateDeviceLayerProperties": {"dispatch": True, "driver": False, "thunk": ThunkType.NONE}, "vkEnumeratePhysicalDeviceGroups" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, - "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, @@ -212,7 +210,7 @@ FUNCTION_OVERRIDES = { "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE}, "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetDeviceQueue2" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, - "vkAllocateMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, + "vkAllocateMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE, "extra_param" : "pAllocateInfo"}, "vkFreeMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkMapMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkUnmapMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, @@ -247,7 +245,7 @@ FUNCTION_OVERRIDES = { "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, # VK_KHR_external_memory_capabilities - "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetPhysicalDeviceExternalBufferPropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, # VK_KHR_external_semaphore_capabilities @@ -271,12 +269,20 @@ FUNCTION_OVERRIDES = { # VK_EXT_debug_report "vkCreateDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkDestroyDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, + + # VK_KHR_external_memory_win32 + "vkGetMemoryWin32HandleKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetMemoryWin32HandlePropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, } STRUCT_CHAIN_CONVERSIONS = { # Ignore to not confuse host loader. "VkDeviceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"], "VkInstanceCreateInfo": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"], + + # Structs which require pNext chain modification + "VkBufferCreateInfo": [], + "VkMemoryAllocateInfo": ["VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR", "VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"], } # Some struct members are conditionally ignored and callers are free to leave them uninitialized. @@ -739,7 +745,14 @@ class VkFunction(object): proto += ", ".join([p.definition() for p in self.params]) if is_thunk and self.extra_param: - proto += ", void *" + self.extra_param + extra_param_is_new = True + for p in self.params: + if p.name == self.extra_param: + extra_param_is_new = False + if extra_param_is_new: + proto += ", void *" + self.extra_param + else: + proto += ", void *win_" + self.extra_param if postfix is not None: proto += ") {0}".format(postfix) @@ -816,7 +829,7 @@ class VkFunction(object): if conv: params += ", UlongToPtr({0}{1})".format(params_prefix, self.extra_param) else: - params += ", {0}{1}".format(params_prefix, self.extra_param) + params += ", (void *){0}{1}".format(params_prefix, self.extra_param) if unwrap or self.thunk_type == ThunkType.PUBLIC: func_prefix = "{0}.p_".format(self.params[0].dispatch_table(params_prefix, conv)) @@ -891,9 +904,12 @@ class VkFunction(object): if conv: thunk += " struct\n" thunk += " {\n" + extra_param_is_new = True for p in self.params: thunk += " {0};\n".format(p.definition(conv=True, is_member=True)) - if self.extra_param: + if p.name == self.extra_param: + extra_param_is_new = False + if self.extra_param and extra_param_is_new: thunk += " PTR32 {0};\n".format(self.extra_param) if self.type != "void": thunk += " {0} result;\n".format(self.type) @@ -1481,7 +1497,8 @@ class VkMember(VkVariable): return "{0}{1} = {2} ? {3} : 0;\n".format(output, self.name, self.value(input, conv), handle.driver_handle(self.value(input, conv))) else: - return "{0}{1} = {2};\n".format(output, self.name, handle.driver_handle(self.value(input, conv))) + input_name = "{0}{1}".format(input, self.name) + return "{0}{1} = {2} ? {3} : VK_NULL_HANDLE;\n".format(output, self.name, input_name, handle.driver_handle(self.value(input, conv))) elif self.is_generic_handle(): if direction == Direction.OUTPUT: LOGGER.err("OUTPUT parameter {0}.{1} cannot be unwrapped".format(self.type, self.name)) @@ -2342,9 +2359,12 @@ class StructConversionFunction(object): ident = " " if self.direction == Direction.INPUT and self.type in STRUCT_CHAIN_CONVERSIONS: + has_any_chain_conversions = False for i in STRUCT_CHAIN_CONVERSIONS[self.type]: body += " case {0}:\n".format(i) - body += ident + "break;\n" + has_any_chain_conversions = True + if has_any_chain_conversions: + body += ident + "break;\n" for ext in self.operand.struct_extensions: if not ext.required: @@ -2354,6 +2374,8 @@ class StructConversionFunction(object): continue stype = next(x for x in ext.members if x.name == "sType").values + if self.type in STRUCT_CHAIN_CONVERSIONS and stype in STRUCT_CHAIN_CONVERSIONS[self.type]: + continue win_type = ext.name + "32" if self.conv and ext.needs_win32_type() else ext.name if self.direction == Direction.INPUT: in_type = "const " + win_type @@ -2967,9 +2989,13 @@ class VkGenerator(object): f.write("struct {0}_params\n".format(vk_func.name)) f.write("{\n"); + extra_param_is_new = True for p in vk_func.params: f.write(" {0};\n".format(p.definition(is_member=True))) - if vk_func.extra_param: + if p.name == vk_func.extra_param: + extra_param_is_new = False + + if vk_func.extra_param and extra_param_is_new: f.write(" void *{0};\n".format(vk_func.extra_param)) if vk_func.type != "void": f.write(" {0} result;\n".format(vk_func.type)) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 5cde473d41f..85c8f6318a6 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -24,6 +24,11 @@ #include "config.h" #include #include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "wine/server.h" #include "vulkan_private.h" #include "wine/vulkan_driver.h" @@ -274,6 +279,15 @@ static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance */ for (i = 0; i < num_host_properties; i++) { + if (!strcmp(host_properties[i].extensionName, "VK_KHR_external_memory_fd")) + { + TRACE("Substituting VK_KHR_external_memory_fd for VK_KHR_external_memory_win32\n"); + + snprintf(host_properties[i].extensionName, sizeof(host_properties[i].extensionName), + VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME); + host_properties[i].specVersion = VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION; + } + if (wine_vk_device_extension_supported(host_properties[i].extensionName)) { TRACE("Enabling extension '%s' for physical device %p\n", host_properties[i].extensionName, object); @@ -452,7 +466,7 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de struct conversion_context *ctx, const VkDeviceCreateInfo *src, VkDeviceCreateInfo *dst) { static const char *wine_xr_extension_name = "VK_WINE_openxr_device_extensions"; - unsigned int i, append_xr = 0; + unsigned int i, append_xr = 0, replace_win32 = 0; VkBaseOutStructure *header; char **xr_extensions_list; @@ -472,12 +486,14 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de if (!strcmp(extension_name, wine_xr_extension_name)) append_xr = 1; + else if (!strcmp(extension_name, "VK_KHR_external_memory_win32")) + replace_win32 = 1; } if (append_xr) xr_extensions_list = parse_xr_extensions(&append_xr); - if (phys_dev->external_memory_align || append_xr) + if (phys_dev->external_memory_align || append_xr || replace_win32) { const char **new_extensions; unsigned int o = 0, count; @@ -492,7 +508,10 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de { if (append_xr && !strcmp(src->ppEnabledExtensionNames[i], wine_xr_extension_name)) continue; - new_extensions[o++] = src->ppEnabledExtensionNames[i]; + if (replace_win32 && !strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_memory_win32")) + new_extensions[o++] = "VK_KHR_external_memory_fd"; + else + new_extensions[o++] = src->ppEnabledExtensionNames[i]; } if (phys_dev->external_memory_align) { @@ -1331,18 +1350,71 @@ void wine_vkGetPhysicalDeviceExternalFencePropertiesKHR(VkPhysicalDevice phys_de properties->externalFenceFeatures = 0; } -void wine_vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice phys_dev, +static inline void wine_vk_normalize_handle_types_win(VkExternalMemoryHandleTypeFlags *types) +{ + *types &= + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT; +} + +static inline void wine_vk_normalize_handle_types_host(VkExternalMemoryHandleTypeFlags *types) +{ + *types &= + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT | +/* predicated on VK_KHR_external_memory_dma_buf + VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT | */ + VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT; +} + +static void wine_vk_get_physical_device_external_buffer_properties(struct wine_phys_dev *phys_dev, + void (*p_vkGetPhysicalDeviceExternalBufferProperties)(VkPhysicalDevice, const VkPhysicalDeviceExternalBufferInfo *, VkExternalBufferProperties *), + const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) +{ + VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info; + + wine_vk_normalize_handle_types_win(&buffer_info_dup.handleType); + if (buffer_info_dup.handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + buffer_info_dup.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + wine_vk_normalize_handle_types_host(&buffer_info_dup.handleType); + + if (buffer_info->handleType && !buffer_info_dup.handleType) + { + memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties)); + return; + } + + p_vkGetPhysicalDeviceExternalBufferProperties(phys_dev->phys_dev, &buffer_info_dup, properties); + + if (properties->externalMemoryProperties.exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + properties->externalMemoryProperties.exportFromImportedHandleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + wine_vk_normalize_handle_types_win(&properties->externalMemoryProperties.exportFromImportedHandleTypes); + + if (properties->externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + properties->externalMemoryProperties.compatibleHandleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + wine_vk_normalize_handle_types_win(&properties->externalMemoryProperties.compatibleHandleTypes); +} + +void wine_vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice phys_dev_handle, const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) { - memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties)); + struct wine_phys_dev *phys_dev = wine_phys_dev_from_handle(phys_dev_handle); + wine_vk_get_physical_device_external_buffer_properties(phys_dev, phys_dev->instance->funcs.p_vkGetPhysicalDeviceExternalBufferProperties, buffer_info, properties); } -void wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice phys_dev, +void wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice phys_dev_handle, const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) { - memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties)); + struct wine_phys_dev *phys_dev = wine_phys_dev_from_handle(phys_dev_handle); + wine_vk_get_physical_device_external_buffer_properties(phys_dev, phys_dev->instance->funcs.p_vkGetPhysicalDeviceExternalBufferPropertiesKHR, buffer_info, properties); } VkResult wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev_handle, @@ -2239,10 +2311,26 @@ void wine_vkDestroySurfaceKHR(VkInstance handle, VkSurfaceKHR surface, free(object); } +static HANDLE create_gpu_resource(int fd, LPCWSTR name) +{ + HANDLE ret = INVALID_HANDLE_VALUE; + + TRACE("Creating shared vulkan resource fd %d name %s.\n", fd, debugstr_w(name)); + + if (name) + FIXME("Naming gpu resources not supported.\n"); + + wine_server_fd_to_handle(fd, GENERIC_ALL, 0, &ret); + + return ret; +} + VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *alloc_info, - const VkAllocationCallbacks *allocator, VkDeviceMemory *ret) + const VkAllocationCallbacks *allocator, VkDeviceMemory *ret, + void *win_pAllocateInfo) { struct wine_device *device = wine_device_from_handle(handle); + const VkMemoryAllocateInfo *win_alloc_info = win_pAllocateInfo; struct wine_device_memory *memory; VkMemoryAllocateInfo info = *alloc_info; VkImportMemoryHostPointerInfoEXT host_pointer_info; @@ -2250,12 +2338,74 @@ VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *allo void *mapping = NULL; VkResult result; - /* For host visible memory, we try to use VK_EXT_external_memory_host on wow64 - * to ensure that mapped pointer is 32-bit. */ + const VkImportMemoryWin32HandleInfoKHR *handle_import_info; + const VkExportMemoryWin32HandleInfoKHR *handle_export_info; + VkExportMemoryAllocateInfo *export_info; + VkImportMemoryFdInfoKHR fd_import_info; + VkMemoryGetFdInfoKHR get_fd_info; + int fd; + + if (!(memory = calloc(sizeof(*memory), 1))) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + memory->handle = INVALID_HANDLE_VALUE; + fd_import_info.fd = -1; + fd_import_info.pNext = NULL; + + /* find and process handle import/export info and grab it */ + handle_import_info = wine_vk_find_struct(win_alloc_info, IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR); + handle_export_info = wine_vk_find_struct(win_alloc_info, EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR); + if (handle_export_info && handle_export_info->pAttributes && handle_export_info->pAttributes->lpSecurityDescriptor) + FIXME("Support for custom security descriptor not implemented.\n"); + + if ((export_info = wine_vk_find_struct(alloc_info, EXPORT_MEMORY_ALLOCATE_INFO))) + { + memory->handle_types = export_info->handleTypes; + if (export_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + export_info->handleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + wine_vk_normalize_handle_types_host(&export_info->handleTypes); + } + mem_flags = device->phys_dev->memory_properties.memoryTypes[alloc_info->memoryTypeIndex].propertyFlags; - if (device->phys_dev->external_memory_align && (mem_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + + /* Vulkan consumes imported FDs, but not imported HANDLEs */ + if (handle_import_info) + { + fd_import_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; + fd_import_info.pNext = info.pNext; + fd_import_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + info.pNext = &fd_import_info; + + switch (handle_import_info->handleType) + { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: + if (handle_import_info->handle) + NtDuplicateObject( NtCurrentProcess(), handle_import_info->handle, NtCurrentProcess(), &memory->handle, 0, 0, DUPLICATE_SAME_ACCESS ); + else if (handle_import_info->name) + FIXME("Importing device memory by resource name not supported.\n"); + break; + default: + WARN("Invalid handle type %08x passed in.\n", handle_import_info->handleType); + result = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto done; + } + + if (memory->handle != INVALID_HANDLE_VALUE) + wine_server_handle_to_fd(memory->handle, FILE_READ_DATA, &fd_import_info.fd, NULL); + + if (fd_import_info.fd == -1) + { + TRACE("Couldn't access resource handle or name. type=%08x handle=%p name=%s\n", handle_import_info->handleType, handle_import_info->handle, + handle_import_info->name ? debugstr_w(handle_import_info->name) : ""); + result = VK_ERROR_INVALID_EXTERNAL_HANDLE; + goto done; + } + } + else if (device->phys_dev->external_memory_align && (mem_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && !find_next_struct(alloc_info->pNext, VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT)) { + /* For host visible memory, we try to use VK_EXT_external_memory_host on wow64 + * to ensure that mapped pointer is 32-bit. */ VkMemoryHostPointerPropertiesEXT props = { .sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT, @@ -2271,6 +2421,7 @@ VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *allo MEM_COMMIT, PAGE_READWRITE)) { ERR("NtAllocateVirtualMemory failed\n"); + free(memory); return VK_ERROR_OUT_OF_HOST_MEMORY; } @@ -2279,6 +2430,7 @@ VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *allo if (result != VK_SUCCESS) { ERR("vkGetMemoryHostPointerPropertiesEXT failed: %d\n", result); + free(memory); return result; } @@ -2318,18 +2470,45 @@ VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *allo } } - if (!(memory = malloc(sizeof(*memory)))) - return VK_ERROR_OUT_OF_HOST_MEMORY; - result = device->funcs.p_vkAllocateMemory(device->device, &info, NULL, &memory->memory); + if (result == VK_SUCCESS && memory->handle == INVALID_HANDLE_VALUE && export_info && export_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + { + get_fd_info.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; + get_fd_info.pNext = NULL; + get_fd_info.memory = memory->memory; + get_fd_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + + if (device->funcs.p_vkGetMemoryFdKHR(device->device, &get_fd_info, &fd) == VK_SUCCESS) + { + memory->handle = create_gpu_resource(fd, handle_export_info ? handle_export_info->name : NULL); + memory->access = handle_export_info ? handle_export_info->dwAccess : GENERIC_ALL; + if (handle_export_info && handle_export_info->pAttributes) + memory->inherit = handle_export_info->pAttributes->bInheritHandle; + else + memory->inherit = FALSE; + close(fd); + } + + if (memory->handle == INVALID_HANDLE_VALUE) + { + device->funcs.p_vkFreeMemory(device->device, memory->memory, NULL); + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto done; + } + } +done: if (result != VK_SUCCESS) { + if (fd_import_info.fd != -1) + close(fd_import_info.fd); + if (memory->handle != INVALID_HANDLE_VALUE) + NtClose(memory->handle); free(memory); return result; } memory->mapping = mapping; - *ret = (VkDeviceMemory)(uintptr_t)memory; + *ret = wine_device_memory_to_handle(memory); return VK_SUCCESS; } @@ -2350,6 +2529,9 @@ void wine_vkFreeMemory(VkDevice handle, VkDeviceMemory memory_handle, const VkAl NtFreeVirtualMemory(GetCurrentProcess(), &memory->mapping, &alloc_size, MEM_RELEASE); } + if (memory->handle != INVALID_HANDLE_VALUE) + NtClose(memory->handle); + free(memory); } @@ -2395,10 +2577,16 @@ VkResult wine_vkCreateBuffer(VkDevice handle, const VkBufferCreateInfo *create_i const VkAllocationCallbacks *allocator, VkBuffer *buffer) { struct wine_device *device = wine_device_from_handle(handle); - VkExternalMemoryBufferCreateInfo external_memory_info; + VkExternalMemoryBufferCreateInfo external_memory_info, *ext_info; VkBufferCreateInfo info = *create_info; - if (device->phys_dev->external_memory_align && + if ((ext_info = wine_vk_find_struct(create_info, EXTERNAL_MEMORY_BUFFER_CREATE_INFO))) + { + if (ext_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + ext_info->handleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + wine_vk_normalize_handle_types_host(&ext_info->handleTypes); + } + else if (device->phys_dev->external_memory_align && !find_next_struct(info.pNext, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO)) { external_memory_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO; @@ -2958,6 +3146,8 @@ NTSTATUS vk_is_available_device_function(void *arg) { struct is_available_device_function_params *params = arg; struct wine_device *device = wine_device_from_handle(params->device); + if (!strcmp(params->name, "vkGetMemoryWin32HandleKHR") || !strcmp(params->name, "vkGetMemoryWin32HandlePropertiesKHR")) + params->name = "vkGetMemoryFdKHR"; return !!vk_funcs->p_vkGetDeviceProcAddr(device->device, params->name); } @@ -2982,6 +3172,9 @@ NTSTATUS vk_is_available_device_function32(void *arg) UINT32 name; } *params = arg; struct wine_device *device = wine_device_from_handle(UlongToPtr(params->device)); + char *name = UlongToPtr(params->name); + if (!strcmp(name, "vkGetMemoryWin32HandleKHR") || !strcmp(name, "vkGetMemoryWin32HandlePropertiesKHR")) + return !!vk_funcs->p_vkGetDeviceProcAddr(device->device, "vkGetMemoryFdKHR"); return !!vk_funcs->p_vkGetDeviceProcAddr(device->device, UlongToPtr(params->name)); } @@ -3024,3 +3217,36 @@ VkPhysicalDevice WINAPI __wine_get_wrapped_VkPhysicalDevice(VkInstance handle, V WARN("Unknown native physical device: %p\n", native_phys_dev); return NULL; } + +VkResult wine_vkGetMemoryWin32HandleKHR(VkDevice device, const VkMemoryGetWin32HandleInfoKHR *handle_info, HANDLE *handle) +{ + struct wine_device_memory *dev_mem = wine_device_memory_from_handle(handle_info->memory); + const VkBaseInStructure *chain; + + TRACE("%p, %p %p\n", device, handle_info, handle); + + if (!(dev_mem->handle_types & handle_info->handleType)) + return VK_ERROR_UNKNOWN; + + if ((chain = handle_info->pNext)) + FIXME("Ignoring a linked structure of type %u.\n", chain->sType); + + switch(handle_info->handleType) + { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: + return !NtDuplicateObject( NtCurrentProcess(), dev_mem->handle, NtCurrentProcess(), handle, dev_mem->access, dev_mem->inherit ? OBJ_INHERIT : 0, 0) ? + VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY; + default: + FIXME("Unable to get handle of type %x, did the application ignore the capabilities?\n", handle_info->handleType); + return VK_ERROR_UNKNOWN; + } +} + +VkResult wine_vkGetMemoryWin32HandlePropertiesKHR(VkDevice device, VkExternalMemoryHandleTypeFlagBits type, HANDLE handle, VkMemoryWin32HandlePropertiesKHR *properties) +{ + TRACE("%p %u %p %p\n", device, type, handle, properties); + + /* VUID-vkGetMemoryWin32HandlePropertiesKHR-handleType-00666 + handleType must not be one of the handle types defined as opaque */ + return VK_ERROR_INVALID_EXTERNAL_HANDLE; +} diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index a4898389275..2d660d8aca9 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -218,9 +218,18 @@ static inline struct wine_cmd_pool *wine_cmd_pool_from_handle(VkCommandPool hand struct wine_device_memory { VkDeviceMemory memory; + VkExternalMemoryHandleTypeFlagBits handle_types; + BOOL inherit; + DWORD access; + HANDLE handle; void *mapping; }; +static inline VkDeviceMemory wine_device_memory_to_handle(struct wine_device_memory *device_memory) +{ + return (VkDeviceMemory)(uintptr_t)device_memory; +} + static inline struct wine_device_memory *wine_device_memory_from_handle(VkDeviceMemory handle) { return (struct wine_device_memory *)(uintptr_t)handle; From 591eff805ff2f5182c1077f8c15a28020f83a264 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 22 Dec 2022 11:09:20 -0600 Subject: [PATCH 0715/2777] winevulkan: Factor out wine_vk_get_physical_device_image_format_properties_2(). --- dlls/winevulkan/vulkan.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 85c8f6318a6..8ad760cbe3f 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -1417,15 +1417,14 @@ void wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice phys_d wine_vk_get_physical_device_external_buffer_properties(phys_dev, phys_dev->instance->funcs.p_vkGetPhysicalDeviceExternalBufferPropertiesKHR, buffer_info, properties); } -VkResult wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev_handle, - const VkPhysicalDeviceImageFormatInfo2 *format_info, - VkImageFormatProperties2 *properties) +static VkResult wine_vk_get_physical_device_image_format_properties_2(struct wine_phys_dev *phys_dev, + VkResult (*p_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice, const VkPhysicalDeviceImageFormatInfo2 *, VkImageFormatProperties2 *), + const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties) { - struct wine_phys_dev *phys_dev = wine_phys_dev_from_handle(phys_dev_handle); VkExternalImageFormatProperties *external_image_properties; VkResult res; - res = phys_dev->instance->funcs.p_vkGetPhysicalDeviceImageFormatProperties2(phys_dev->phys_dev, + res = p_vkGetPhysicalDeviceImageFormatProperties2(phys_dev->phys_dev, format_info, properties); if ((external_image_properties = find_next_struct(properties, @@ -1436,31 +1435,29 @@ VkResult wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_de p->exportFromImportedHandleTypes = 0; p->compatibleHandleTypes = 0; } - return res; } +VkResult wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev_handle, + const VkPhysicalDeviceImageFormatInfo2 *format_info, + VkImageFormatProperties2 *properties) +{ + struct wine_phys_dev *phys_dev = wine_phys_dev_from_handle(phys_dev_handle); + + return wine_vk_get_physical_device_image_format_properties_2(phys_dev, + phys_dev->instance->funcs.p_vkGetPhysicalDeviceImageFormatProperties2, + format_info, properties); +} + VkResult wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice phys_dev_handle, const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties) { struct wine_phys_dev *phys_dev = wine_phys_dev_from_handle(phys_dev_handle); - VkExternalImageFormatProperties *external_image_properties; - VkResult res; - res = phys_dev->instance->funcs.p_vkGetPhysicalDeviceImageFormatProperties2KHR(phys_dev->phys_dev, + return wine_vk_get_physical_device_image_format_properties_2(phys_dev, + phys_dev->instance->funcs.p_vkGetPhysicalDeviceImageFormatProperties2KHR, format_info, properties); - - if ((external_image_properties = find_next_struct(properties, - VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES))) - { - VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties; - p->externalMemoryFeatures = 0; - p->exportFromImportedHandleTypes = 0; - p->compatibleHandleTypes = 0; - } - - return res; } /* From ntdll/unix/sync.c */ From f7e504c248a5d7cacf8fb3eadd8c8071718fa4a0 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 19 May 2021 13:38:12 -0400 Subject: [PATCH 0716/2777] winevulkan: Implement VK_KHR_external_memory_win32 for images. Signed-off-by: Derek Lesho --- dlls/winevulkan/make_vulkan | 2 ++ dlls/winevulkan/vulkan.c | 39 +++++++++++++++++++++++++++++++------ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 5e545754aa4..c47ad6e16a8 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -282,7 +282,9 @@ STRUCT_CHAIN_CONVERSIONS = { # Structs which require pNext chain modification "VkBufferCreateInfo": [], + "VkImageCreateInfo": [], "VkMemoryAllocateInfo": ["VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR", "VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"], + "VkPhysicalDeviceImageFormatInfo2": [], } # Some struct members are conditionally ignored and callers are free to leave them uninitialized. diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 8ad760cbe3f..feafc14dbe5 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -1421,9 +1421,26 @@ static VkResult wine_vk_get_physical_device_image_format_properties_2(struct win VkResult (*p_vkGetPhysicalDeviceImageFormatProperties2)(VkPhysicalDevice, const VkPhysicalDeviceImageFormatInfo2 *, VkImageFormatProperties2 *), const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties) { + VkPhysicalDeviceExternalImageFormatInfo *external_image_info; VkExternalImageFormatProperties *external_image_properties; VkResult res; + if ((external_image_info = find_next_struct(format_info, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO)) + && external_image_info->handleType) + { + wine_vk_normalize_handle_types_win(&external_image_info->handleType); + + if (external_image_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + external_image_info->handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + + wine_vk_normalize_handle_types_host(&external_image_info->handleType); + if (!external_image_info->handleType) + { + FIXME("Unsupported handle type %#x.\n", external_image_info->handleType); + return VK_ERROR_FORMAT_NOT_SUPPORTED; + } + } + res = p_vkGetPhysicalDeviceImageFormatProperties2(phys_dev->phys_dev, format_info, properties); @@ -1431,9 +1448,14 @@ static VkResult wine_vk_get_physical_device_image_format_properties_2(struct win VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES))) { VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties; - p->externalMemoryFeatures = 0; - p->exportFromImportedHandleTypes = 0; - p->compatibleHandleTypes = 0; + + if (p->exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + p->exportFromImportedHandleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + wine_vk_normalize_handle_types_win(&p->exportFromImportedHandleTypes); + + if (p->compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) + p->compatibleHandleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + wine_vk_normalize_handle_types_win(&p->compatibleHandleTypes); } return res; } @@ -2599,11 +2621,16 @@ VkResult wine_vkCreateImage(VkDevice handle, const VkImageCreateInfo *create_inf const VkAllocationCallbacks *allocator, VkImage *image) { struct wine_device *device = wine_device_from_handle(handle); - VkExternalMemoryImageCreateInfo external_memory_info; + VkExternalMemoryImageCreateInfo external_memory_info, *update_info; VkImageCreateInfo info = *create_info; - if (device->phys_dev->external_memory_align && - !find_next_struct(info.pNext, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO)) + if ((update_info = find_next_struct(info.pNext, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO))) + { + if (update_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR) + update_info->handleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + wine_vk_normalize_handle_types_host(&update_info->handleTypes); + } + else if (device->phys_dev->external_memory_align) { external_memory_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO; external_memory_info.pNext = info.pNext; From e28fcec6531187ba83def125f34e3424a4111e31 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 13 Oct 2021 13:16:44 +0200 Subject: [PATCH 0717/2777] winevulkan: Implement support for KMT handles and named objects. --- configure.ac | 1 + dlls/sharedgpures.sys/Makefile.in | 6 + dlls/sharedgpures.sys/shared_resource.c | 348 ++++++++++++++++++++ dlls/sharedgpures.sys/sharedgpures.sys.spec | 1 + dlls/winevulkan/vulkan.c | 190 ++++++++++- dlls/winevulkan/vulkan_private.h | 7 + include/ddk/wdm.h | 1 + loader/wine.inf.in | 13 + 8 files changed, 552 insertions(+), 15 deletions(-) create mode 100644 dlls/sharedgpures.sys/Makefile.in create mode 100644 dlls/sharedgpures.sys/shared_resource.c create mode 100644 dlls/sharedgpures.sys/sharedgpures.sys.spec diff --git a/configure.ac b/configure.ac index 68bac283502..5c168213481 100644 --- a/configure.ac +++ b/configure.ac @@ -3037,6 +3037,7 @@ WINE_CONFIG_MAKEFILE(dlls/setupapi/tests) WINE_CONFIG_MAKEFILE(dlls/setupx.dll16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/sfc) WINE_CONFIG_MAKEFILE(dlls/sfc_os) +WINE_CONFIG_MAKEFILE(dlls/sharedgpures.sys) WINE_CONFIG_MAKEFILE(dlls/shcore) WINE_CONFIG_MAKEFILE(dlls/shcore/tests) WINE_CONFIG_MAKEFILE(dlls/shdoclc) diff --git a/dlls/sharedgpures.sys/Makefile.in b/dlls/sharedgpures.sys/Makefile.in new file mode 100644 index 00000000000..2d64a476826 --- /dev/null +++ b/dlls/sharedgpures.sys/Makefile.in @@ -0,0 +1,6 @@ +MODULE = sharedgpures.sys +IMPORTS = ntoskrnl +EXTRADLLFLAGS = -Wl,--subsystem,native -mno-cygwin + +C_SRCS = \ + shared_resource.c diff --git a/dlls/sharedgpures.sys/shared_resource.c b/dlls/sharedgpures.sys/shared_resource.c new file mode 100644 index 00000000000..a2883fb65b9 --- /dev/null +++ b/dlls/sharedgpures.sys/shared_resource.c @@ -0,0 +1,348 @@ +#include + +#define NONAMELESSUNION +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "winioctl.h" + +#include "ddk/wdm.h" + +#include "wine/debug.h" +#include "wine/list.h" +#include "wine/server.h" + +WINE_DEFAULT_DEBUG_CHANNEL(sharedgpures); + +static DRIVER_OBJECT *sharedgpures_driver; + +struct shared_resource +{ + unsigned int ref_count; + void *unix_resource; + WCHAR *name; +}; + +static struct shared_resource *resource_pool; +static unsigned int resource_pool_size; + +/* TODO: If/when ntoskrnl gets support for referencing user handles directly, remove this function */ +static void *reference_client_handle(obj_handle_t handle) +{ + HANDLE client_process, kernel_handle; + OBJECT_ATTRIBUTES attr; + void *object = NULL; + CLIENT_ID cid; + + attr.Length = sizeof(OBJECT_ATTRIBUTES); + attr.RootDirectory = 0; + attr.Attributes = OBJ_KERNEL_HANDLE; + attr.ObjectName = NULL; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + cid.UniqueProcess = PsGetCurrentProcessId(); + cid.UniqueThread = 0; + + if (NtOpenProcess(&client_process, PROCESS_ALL_ACCESS, &attr, &cid) != STATUS_SUCCESS) + return NULL; + + if (NtDuplicateObject(client_process, wine_server_ptr_handle(handle), NtCurrentProcess(), &kernel_handle, + 0, OBJ_KERNEL_HANDLE, DUPLICATE_SAME_ACCESS) != STATUS_SUCCESS) + { + NtClose(client_process); + return NULL; + } + + ObReferenceObjectByHandle(kernel_handle, 0, NULL, KernelMode, &object, NULL); + + NtClose(client_process); + NtClose(kernel_handle); + + return object; +} + +#define IOCTL_SHARED_GPU_RESOURCE_CREATE CTL_CODE(FILE_DEVICE_VIDEO, 0, METHOD_BUFFERED, FILE_WRITE_ACCESS) + +struct shared_resource_create +{ + obj_handle_t unix_handle; + WCHAR name[1]; +}; + +static NTSTATUS shared_resource_create(struct shared_resource **res, void *buff, SIZE_T insize, IO_STATUS_BLOCK *iosb) +{ + struct shared_resource_create *input = buff; + void *unix_resource; + unsigned int i; + LPWSTR name; + + if (insize < sizeof(*input)) + return STATUS_INFO_LENGTH_MISMATCH; + + if (input->name[ ((insize - offsetof(struct shared_resource_create, name)) / sizeof(WCHAR)) - 1 ]) + return STATUS_INVALID_PARAMETER; + + if (!(unix_resource = reference_client_handle(input->unix_handle))) + return STATUS_INVALID_HANDLE; + + if (insize == sizeof(*input)) + name = NULL; + else + { + name = ExAllocatePoolWithTag(NonPagedPool, insize - offsetof(struct shared_resource_create, name), 0); + wcscpy(name, &input->name[0]); + } + + for (i = 0; i < resource_pool_size; i++) + if (!resource_pool[i].ref_count) + break; + + if (i == resource_pool_size) + { + struct shared_resource *expanded_pool = + ExAllocatePoolWithTag(NonPagedPool, sizeof(struct shared_resource) * (resource_pool_size + 1024), 0); + + if (resource_pool) + { + memcpy(expanded_pool, resource_pool, resource_pool_size * sizeof(struct shared_resource)); + ExFreePoolWithTag(resource_pool, 0); + } + + memset(&expanded_pool[resource_pool_size], 0, 1024 * sizeof (struct shared_resource)); + + resource_pool = expanded_pool; + resource_pool_size += 1024; + } + + *res = &resource_pool[i]; + (*res)->ref_count = 1; + (*res)->unix_resource = unix_resource; + (*res)->name = name; + + iosb->Information = 0; + return STATUS_SUCCESS; +} + +#define IOCTL_SHARED_GPU_RESOURCE_OPEN CTL_CODE(FILE_DEVICE_VIDEO, 1, METHOD_BUFFERED, FILE_WRITE_ACCESS) + +struct shared_resource_open +{ + obj_handle_t kmt_handle; + WCHAR name[1]; +}; + +static unsigned int kmt_to_index(obj_handle_t kmt) +{ + if (!(kmt & 0x40000000) || (kmt - 2) % 4) + return -1; + return (((unsigned int) kmt & ~0x40000000) - 2) / 4; +} + +static NTSTATUS shared_resource_open(struct shared_resource **res, void *buff, SIZE_T insize, IO_STATUS_BLOCK *iosb) +{ + struct shared_resource_open *input = buff; + unsigned int i; + + if (insize < sizeof(*input)) + return STATUS_INFO_LENGTH_MISMATCH; + + if (input->kmt_handle) + { + if (kmt_to_index(input->kmt_handle) >= resource_pool_size) + return STATUS_INVALID_HANDLE; + + *res = &resource_pool[kmt_to_index(input->kmt_handle)]; + } + else + { + if (input->name[ ((insize - offsetof(struct shared_resource_open, name)) / sizeof(WCHAR)) - 1 ]) + return STATUS_INVALID_PARAMETER; + + /* name lookup */ + for (i = 0; i < resource_pool_size; i++) + { + if (!wcscmp(resource_pool[i].name, &input->name[0])) + { + *res = &resource_pool[i]; + break; + } + } + + if (i == resource_pool_size) + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + (*res)->ref_count++; + iosb->Information = 0; + return STATUS_SUCCESS; +} + +#define IOCTL_SHARED_GPU_RESOURCE_GETKMT CTL_CODE(FILE_DEVICE_VIDEO, 2, METHOD_BUFFERED, FILE_READ_ACCESS) + +static obj_handle_t index_to_kmt(unsigned int idx) +{ + return (idx * 4 + 2) | 0x40000000; +} + +static NTSTATUS shared_resource_getkmt(struct shared_resource *res, void *buff, SIZE_T outsize, IO_STATUS_BLOCK *iosb) +{ + if (outsize < sizeof(unsigned int)) + return STATUS_INFO_LENGTH_MISMATCH; + + *((unsigned int *)buff) = index_to_kmt(res - resource_pool); + + iosb->Information = sizeof(unsigned int); + return STATUS_SUCCESS; +} + +/* TODO: If/when ntoskrnl gets support for opening user handles directly, remove this function */ +static obj_handle_t open_client_handle(void *object) +{ + HANDLE client_process, kernel_handle, handle = NULL; + OBJECT_ATTRIBUTES attr; + CLIENT_ID cid; + + attr.Length = sizeof(OBJECT_ATTRIBUTES); + attr.RootDirectory = 0; + attr.Attributes = OBJ_KERNEL_HANDLE; + attr.ObjectName = NULL; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + cid.UniqueProcess = PsGetCurrentProcessId(); + cid.UniqueThread = 0; + + if (NtOpenProcess(&client_process, PROCESS_ALL_ACCESS, &attr, &cid) != STATUS_SUCCESS) + return 0; + + if (ObOpenObjectByPointer(object, 0, NULL, GENERIC_ALL, NULL, KernelMode, &kernel_handle) != STATUS_SUCCESS) + { + NtClose(client_process); + return 0; + } + + NtDuplicateObject(NtCurrentProcess(), kernel_handle, client_process, &handle, + 0, 0, DUPLICATE_SAME_ACCESS); + + NtClose(client_process); + NtClose(kernel_handle); + + return wine_server_obj_handle(handle); +} + +#define IOCTL_SHARED_GPU_RESOURCE_GET_UNIX_RESOURCE CTL_CODE(FILE_DEVICE_VIDEO, 3, METHOD_BUFFERED, FILE_READ_ACCESS) + +static NTSTATUS shared_resource_get_unix_resource(struct shared_resource *res, void *buff, SIZE_T outsize, IO_STATUS_BLOCK *iosb) +{ + if (outsize < sizeof(obj_handle_t)) + return STATUS_INFO_LENGTH_MISMATCH; + + *((obj_handle_t *)buff) = open_client_handle(res->unix_resource); + + iosb->Information = sizeof(obj_handle_t); + return STATUS_SUCCESS; +} + +static NTSTATUS WINAPI dispatch_create(DEVICE_OBJECT *device, IRP *irp) +{ + irp->IoStatus.u.Status = STATUS_SUCCESS; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +} + +static NTSTATUS WINAPI dispatch_close(DEVICE_OBJECT *device, IRP *irp) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); + struct shared_resource *res = stack->FileObject->FsContext; + + TRACE("Freeing shared resouce %p.\n", res); + + if (res) + { + res->ref_count--; + if (!res->ref_count && res->unix_resource) + { + /* TODO: see if its possible to destroy the object here (unlink?) */ + ObDereferenceObject(res->unix_resource); + res->unix_resource = NULL; + } + } + + irp->IoStatus.u.Status = STATUS_SUCCESS; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return STATUS_SUCCESS; +} + +static NTSTATUS WINAPI dispatch_ioctl(DEVICE_OBJECT *device, IRP *irp) +{ + IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); + struct shared_resource **res = (struct shared_resource **) &stack->FileObject->FsContext; + NTSTATUS status; + + TRACE( "ioctl %#lx insize %lu outsize %lu\n", + stack->Parameters.DeviceIoControl.IoControlCode, + stack->Parameters.DeviceIoControl.InputBufferLength, + stack->Parameters.DeviceIoControl.OutputBufferLength ); + + switch (stack->Parameters.DeviceIoControl.IoControlCode) + { + case IOCTL_SHARED_GPU_RESOURCE_CREATE: + status = shared_resource_create( res, + irp->AssociatedIrp.SystemBuffer, + stack->Parameters.DeviceIoControl.InputBufferLength, + &irp->IoStatus ); + break; + case IOCTL_SHARED_GPU_RESOURCE_OPEN: + status = shared_resource_open( res, + irp->AssociatedIrp.SystemBuffer, + stack->Parameters.DeviceIoControl.InputBufferLength, + &irp->IoStatus ); + break; + case IOCTL_SHARED_GPU_RESOURCE_GETKMT: + status = shared_resource_getkmt( *res, + irp->AssociatedIrp.SystemBuffer, + stack->Parameters.DeviceIoControl.OutputBufferLength, + &irp->IoStatus ); + break; + case IOCTL_SHARED_GPU_RESOURCE_GET_UNIX_RESOURCE: + status = shared_resource_get_unix_resource( *res, + irp->AssociatedIrp.SystemBuffer, + stack->Parameters.DeviceIoControl.OutputBufferLength, + &irp->IoStatus ); + break; + default: + FIXME( "ioctl %#lx not supported\n", stack->Parameters.DeviceIoControl.IoControlCode ); + status = STATUS_NOT_SUPPORTED; + break; + } + + irp->IoStatus.u.Status = status; + IoCompleteRequest( irp, IO_NO_INCREMENT ); + return status; +} + +NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) +{ + static const WCHAR device_nameW[] = L"\\Device\\SharedGpuResource"; + static const WCHAR link_nameW[] = L"\\??\\SharedGpuResource"; + UNICODE_STRING device_name, link_name; + DEVICE_OBJECT *device; + NTSTATUS status; + + sharedgpures_driver = driver; + + driver->MajorFunction[IRP_MJ_CREATE] = dispatch_create; + driver->MajorFunction[IRP_MJ_CLOSE] = dispatch_close; + driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = dispatch_ioctl; + + RtlInitUnicodeString(&device_name, device_nameW); + RtlInitUnicodeString(&link_name, link_nameW); + + if ((status = IoCreateDevice(driver, 0, &device_name, 0, 0, FALSE, &device))) + return status; + + return IoCreateSymbolicLink(&link_name, &device_name); +} diff --git a/dlls/sharedgpures.sys/sharedgpures.sys.spec b/dlls/sharedgpures.sys/sharedgpures.sys.spec new file mode 100644 index 00000000000..76421d7e35b --- /dev/null +++ b/dlls/sharedgpures.sys/sharedgpures.sys.spec @@ -0,0 +1 @@ +# nothing to export diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index feafc14dbe5..4b317b36e60 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -28,6 +28,9 @@ #include "ntstatus.h" #define WIN32_NO_STATUS +#include "windef.h" +#include "winnt.h" +#include "winioctl.h" #include "wine/server.h" #include "vulkan_private.h" @@ -1373,6 +1376,10 @@ static inline void wine_vk_normalize_handle_types_host(VkExternalMemoryHandleTyp VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT; } +static const VkExternalMemoryHandleTypeFlagBits wine_vk_handle_over_fd_types = + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT; + static void wine_vk_get_physical_device_external_buffer_properties(struct wine_phys_dev *phys_dev, void (*p_vkGetPhysicalDeviceExternalBufferProperties)(VkPhysicalDevice, const VkPhysicalDeviceExternalBufferInfo *, VkExternalBufferProperties *), const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties) @@ -1380,7 +1387,7 @@ static void wine_vk_get_physical_device_external_buffer_properties(struct wine_p VkPhysicalDeviceExternalBufferInfo buffer_info_dup = *buffer_info; wine_vk_normalize_handle_types_win(&buffer_info_dup.handleType); - if (buffer_info_dup.handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + if (buffer_info_dup.handleType & wine_vk_handle_over_fd_types) buffer_info_dup.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; wine_vk_normalize_handle_types_host(&buffer_info_dup.handleType); @@ -1393,11 +1400,11 @@ static void wine_vk_get_physical_device_external_buffer_properties(struct wine_p p_vkGetPhysicalDeviceExternalBufferProperties(phys_dev->phys_dev, &buffer_info_dup, properties); if (properties->externalMemoryProperties.exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) - properties->externalMemoryProperties.exportFromImportedHandleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + properties->externalMemoryProperties.exportFromImportedHandleTypes |= wine_vk_handle_over_fd_types; wine_vk_normalize_handle_types_win(&properties->externalMemoryProperties.exportFromImportedHandleTypes); if (properties->externalMemoryProperties.compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) - properties->externalMemoryProperties.compatibleHandleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + properties->externalMemoryProperties.compatibleHandleTypes |= wine_vk_handle_over_fd_types; wine_vk_normalize_handle_types_win(&properties->externalMemoryProperties.compatibleHandleTypes); } @@ -1430,7 +1437,7 @@ static VkResult wine_vk_get_physical_device_image_format_properties_2(struct win { wine_vk_normalize_handle_types_win(&external_image_info->handleType); - if (external_image_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + if (external_image_info->handleType & wine_vk_handle_over_fd_types) external_image_info->handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; wine_vk_normalize_handle_types_host(&external_image_info->handleType); @@ -1450,11 +1457,11 @@ static VkResult wine_vk_get_physical_device_image_format_properties_2(struct win VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties; if (p->exportFromImportedHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) - p->exportFromImportedHandleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + p->exportFromImportedHandleTypes |= wine_vk_handle_over_fd_types; wine_vk_normalize_handle_types_win(&p->exportFromImportedHandleTypes); if (p->compatibleHandleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) - p->compatibleHandleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + p->compatibleHandleTypes |= wine_vk_handle_over_fd_types; wine_vk_normalize_handle_types_win(&p->compatibleHandleTypes); } return res; @@ -2330,18 +2337,154 @@ void wine_vkDestroySurfaceKHR(VkInstance handle, VkSurfaceKHR surface, free(object); } +#define IOCTL_SHARED_GPU_RESOURCE_CREATE CTL_CODE(FILE_DEVICE_VIDEO, 0, METHOD_BUFFERED, FILE_WRITE_ACCESS) + +struct shared_resource_create +{ + obj_handle_t unix_handle; + WCHAR name[1]; +}; + static HANDLE create_gpu_resource(int fd, LPCWSTR name) { - HANDLE ret = INVALID_HANDLE_VALUE; + static const WCHAR shared_gpu_resourceW[] = {'\\','?','?','\\','S','h','a','r','e','d','G','p','u','R','e','s','o','u','r','c','e',0}; + HANDLE unix_resource = INVALID_HANDLE_VALUE; + struct shared_resource_create *inbuff; + UNICODE_STRING shared_gpu_resource_us; + HANDLE shared_resource; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK iosb; + NTSTATUS status; + DWORD in_size; TRACE("Creating shared vulkan resource fd %d name %s.\n", fd, debugstr_w(name)); + if (wine_server_fd_to_handle(fd, GENERIC_ALL, 0, &unix_resource) != STATUS_SUCCESS) + return INVALID_HANDLE_VALUE; + + init_unicode_string(&shared_gpu_resource_us, shared_gpu_resourceW); + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.Attributes = 0; + attr.ObjectName = &shared_gpu_resource_us; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + if ((status = NtCreateFile(&shared_resource, GENERIC_READ | GENERIC_WRITE, &attr, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, 0, NULL, 0))) + { + ERR("Failed to load open a shared resource handle, status %#lx.\n", (long int)status); + NtClose(unix_resource); + return INVALID_HANDLE_VALUE; + } + + in_size = sizeof(*inbuff) + (name ? lstrlenW(name) * sizeof(WCHAR) : 0); + inbuff = calloc(1, in_size); + inbuff->unix_handle = wine_server_obj_handle(unix_resource); + if (name) + lstrcpyW(&inbuff->name[0], name); + + if ((status = NtDeviceIoControlFile(shared_resource, NULL, NULL, NULL, &iosb, IOCTL_SHARED_GPU_RESOURCE_CREATE, + inbuff, in_size, NULL, 0))) + + free(inbuff); + NtClose(unix_resource); + + if (status) + { + ERR("Failed to create video resource, status %#lx.\n", (long int)status); + NtClose(shared_resource); + return INVALID_HANDLE_VALUE; + } + + return shared_resource; +} + +#define IOCTL_SHARED_GPU_RESOURCE_OPEN CTL_CODE(FILE_DEVICE_VIDEO, 1, METHOD_BUFFERED, FILE_WRITE_ACCESS) + +struct shared_resource_open +{ + obj_handle_t kmt_handle; + WCHAR name[1]; +}; + +static HANDLE open_shared_resource(HANDLE kmt_handle, LPCWSTR name) +{ + static const WCHAR shared_gpu_resourceW[] = {'\\','?','?','\\','S','h','a','r','e','d','G','p','u','R','e','s','o','u','r','c','e',0}; + UNICODE_STRING shared_gpu_resource_us; + struct shared_resource_open *inbuff; + HANDLE shared_resource; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK iosb; + NTSTATUS status; + DWORD in_size; + + init_unicode_string(&shared_gpu_resource_us, shared_gpu_resourceW); + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.Attributes = 0; + attr.ObjectName = &shared_gpu_resource_us; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + if ((status = NtCreateFile(&shared_resource, GENERIC_READ | GENERIC_WRITE, &attr, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, 0, NULL, 0))) + { + ERR("Failed to load open a shared resource handle, status %#lx.\n", (long int)status); + return INVALID_HANDLE_VALUE; + } + + in_size = sizeof(*inbuff) + (name ? lstrlenW(name) * sizeof(WCHAR) : 0); + inbuff = calloc(1, in_size); + inbuff->kmt_handle = wine_server_obj_handle(kmt_handle); if (name) - FIXME("Naming gpu resources not supported.\n"); + lstrcpyW(&inbuff->name[0], name); + + status = NtDeviceIoControlFile(shared_resource, NULL, NULL, NULL, &iosb, IOCTL_SHARED_GPU_RESOURCE_OPEN, + inbuff, in_size, NULL, 0); - wine_server_fd_to_handle(fd, GENERIC_ALL, 0, &ret); + free(inbuff); - return ret; + if (status) + { + ERR("Failed to open video resource, status %#lx.\n", (long int)status); + NtClose(shared_resource); + return INVALID_HANDLE_VALUE; + } + + return shared_resource; +} + +#define IOCTL_SHARED_GPU_RESOURCE_GET_UNIX_RESOURCE CTL_CODE(FILE_DEVICE_VIDEO, 3, METHOD_BUFFERED, FILE_READ_ACCESS) + +static int get_shared_resource_fd(HANDLE shared_resource) +{ + IO_STATUS_BLOCK iosb; + obj_handle_t unix_resource; + NTSTATUS status; + int ret; + + if (NtDeviceIoControlFile(shared_resource, NULL, NULL, NULL, &iosb, IOCTL_SHARED_GPU_RESOURCE_GET_UNIX_RESOURCE, + NULL, 0, &unix_resource, sizeof(unix_resource))) + return -1; + + status = wine_server_handle_to_fd(wine_server_ptr_handle(unix_resource), FILE_READ_DATA, &ret, NULL); + NtClose(wine_server_ptr_handle(unix_resource)); + return status == STATUS_SUCCESS ? ret : -1; +} + +#define IOCTL_SHARED_GPU_RESOURCE_GETKMT CTL_CODE(FILE_DEVICE_VIDEO, 2, METHOD_BUFFERED, FILE_READ_ACCESS) + +static HANDLE get_shared_resource_kmt_handle(HANDLE shared_resource) +{ + IO_STATUS_BLOCK iosb; + obj_handle_t kmt_handle; + + if (NtDeviceIoControlFile(shared_resource, NULL, NULL, NULL, &iosb, IOCTL_SHARED_GPU_RESOURCE_GETKMT, + NULL, 0, &kmt_handle, sizeof(kmt_handle))) + return INVALID_HANDLE_VALUE; + + return wine_server_ptr_handle(kmt_handle); } VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *alloc_info, @@ -2380,7 +2523,7 @@ VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *allo if ((export_info = wine_vk_find_struct(alloc_info, EXPORT_MEMORY_ALLOCATE_INFO))) { memory->handle_types = export_info->handleTypes; - if (export_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + if (export_info->handleTypes & wine_vk_handle_over_fd_types) export_info->handleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; wine_vk_normalize_handle_types_host(&export_info->handleTypes); } @@ -2401,7 +2544,16 @@ VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *allo if (handle_import_info->handle) NtDuplicateObject( NtCurrentProcess(), handle_import_info->handle, NtCurrentProcess(), &memory->handle, 0, 0, DUPLICATE_SAME_ACCESS ); else if (handle_import_info->name) - FIXME("Importing device memory by resource name not supported.\n"); + memory->handle = open_shared_resource( 0, handle_import_info->name ); + break; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT: + /* FIXME: the spec says that device memory imported from a KMT handle doesn't keep a reference to the underyling payload. + This means that in cases where on windows an application leaks VkDeviceMemory objects, we leak the full payload. To + fix this, we would need wine_dev_mem objects to store no reference to the payload, that means no host VkDeviceMemory + object (as objects imported from FDs hold a reference to the payload), and no win32 handle to the object. We would then + extend make_vulkan to have the thunks converting wine_dev_mem to native handles open the VkDeviceMemory from the KMT + handle, use it in the host function, then close it again. */ + memory->handle = open_shared_resource( handle_import_info->handle, NULL ); break; default: WARN("Invalid handle type %08x passed in.\n", handle_import_info->handleType); @@ -2410,7 +2562,7 @@ VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *allo } if (memory->handle != INVALID_HANDLE_VALUE) - wine_server_handle_to_fd(memory->handle, FILE_READ_DATA, &fd_import_info.fd, NULL); + fd_import_info.fd = get_shared_resource_fd(memory->handle); if (fd_import_info.fd == -1) { @@ -2601,7 +2753,7 @@ VkResult wine_vkCreateBuffer(VkDevice handle, const VkBufferCreateInfo *create_i if ((ext_info = wine_vk_find_struct(create_info, EXTERNAL_MEMORY_BUFFER_CREATE_INFO))) { - if (ext_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) + if (ext_info->handleTypes & wine_vk_handle_over_fd_types) ext_info->handleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; wine_vk_normalize_handle_types_host(&ext_info->handleTypes); } @@ -2626,7 +2778,7 @@ VkResult wine_vkCreateImage(VkDevice handle, const VkImageCreateInfo *create_inf if ((update_info = find_next_struct(info.pNext, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO))) { - if (update_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR) + if (update_info->handleTypes & wine_vk_handle_over_fd_types) update_info->handleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; wine_vk_normalize_handle_types_host(&update_info->handleTypes); } @@ -3246,6 +3398,7 @@ VkResult wine_vkGetMemoryWin32HandleKHR(VkDevice device, const VkMemoryGetWin32H { struct wine_device_memory *dev_mem = wine_device_memory_from_handle(handle_info->memory); const VkBaseInStructure *chain; + HANDLE ret; TRACE("%p, %p %p\n", device, handle_info, handle); @@ -3260,6 +3413,13 @@ VkResult wine_vkGetMemoryWin32HandleKHR(VkDevice device, const VkMemoryGetWin32H case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: return !NtDuplicateObject( NtCurrentProcess(), dev_mem->handle, NtCurrentProcess(), handle, dev_mem->access, dev_mem->inherit ? OBJ_INHERIT : 0, 0) ? VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT: + { + if ((ret = get_shared_resource_kmt_handle(dev_mem->handle)) == INVALID_HANDLE_VALUE) + return VK_ERROR_OUT_OF_HOST_MEMORY; + *handle = ret; + return VK_SUCCESS; + } default: FIXME("Unable to get handle of type %x, did the application ignore the capabilities?\n", handle_info->handleType); return VK_ERROR_UNKNOWN; diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 2d660d8aca9..28350764da0 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -379,4 +379,11 @@ static inline void *find_next_struct(const void *s, VkStructureType t) return NULL; } +static inline void init_unicode_string( UNICODE_STRING *str, const WCHAR *data ) +{ + str->Length = lstrlenW(data) * sizeof(WCHAR); + str->MaximumLength = str->Length + sizeof(WCHAR); + str->Buffer = (WCHAR *)data; +} + #endif /* __WINE_VULKAN_PRIVATE_H */ diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h index 321b07b84fa..55d610fe1ca 100644 --- a/include/ddk/wdm.h +++ b/include/ddk/wdm.h @@ -1835,6 +1835,7 @@ NTSTATUS WINAPI ObRegisterCallbacks(POB_CALLBACK_REGISTRATION, void**); NTSTATUS WINAPI ObReferenceObjectByHandle(HANDLE,ACCESS_MASK,POBJECT_TYPE,KPROCESSOR_MODE,PVOID*,POBJECT_HANDLE_INFORMATION); NTSTATUS WINAPI ObReferenceObjectByName(UNICODE_STRING*,ULONG,ACCESS_STATE*,ACCESS_MASK,POBJECT_TYPE,KPROCESSOR_MODE,void*,void**); NTSTATUS WINAPI ObReferenceObjectByPointer(void*,ACCESS_MASK,POBJECT_TYPE,KPROCESSOR_MODE); +NTSTATUS WINAPI ObOpenObjectByPointer(void *,ULONG,ACCESS_STATE*,ACCESS_MASK,POBJECT_TYPE,KPROCESSOR_MODE,HANDLE*); void WINAPI ObUnRegisterCallbacks(void*); NTSTATUS WINAPI PoCallDriver(DEVICE_OBJECT*,IRP*); diff --git a/loader/wine.inf.in b/loader/wine.inf.in index db78c0ca70f..a16ad974592 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -196,6 +196,7 @@ AddService=Winmgmt,0,WinmgmtService AddService=wuauserv,0,wuauService AddService=NDIS,0x800,NDISService AddService=nsiproxy,0x800,NsiProxyService +AddService=SharedGpuResources,0x800,SharedGpuResourcesService [DefaultInstall.NT.Services] AddService=BITS,0,BITSService @@ -215,6 +216,7 @@ AddService=Winmgmt,0,WinmgmtService AddService=wuauserv,0,wuauService AddService=NDIS,0x800,NDISService AddService=nsiproxy,0x800,NsiProxyService +AddService=SharedGpuResources,0x800,SharedGpuResourcesService [DefaultInstall.ntamd64.Services] AddService=BITS,0,BITSService @@ -234,6 +236,7 @@ AddService=Winmgmt,0,WinmgmtService AddService=wuauserv,0,wuauService AddService=NDIS,0x800,NDISService AddService=nsiproxy,0x800,NsiProxyService +AddService=SharedGpuResources,0x800,SharedGpuResourcesService [DefaultInstall.ntarm64.Services] AddService=BITS,0,BITSService @@ -253,6 +256,7 @@ AddService=Winmgmt,0,WinmgmtService AddService=wuauserv,0,wuauService AddService=NDIS,0x800,NDISService AddService=nsiproxy,0x800,NsiProxyService +AddService=SharedGpuResources,0x800,SharedGpuResourcesService [Strings] MciExtStr="Software\Microsoft\Windows NT\CurrentVersion\MCI Extensions" @@ -2341,6 +2345,15 @@ LoadOrderGroup="System Bus Extender" [NsiProxyServiceKeys] HKR,,"Tag",0x10001,1 +[SharedGpuResourcesService] +Description="Shared GPU Resources Manager Service" +DisplayName="Shared GPU Resources Manager" +ServiceBinary="%12%\sharedgpures.sys" +ServiceType=1 +StartType=2 +ErrorControl=1 +LoadOrderGroup="System Bus Extender" + [RpcSsService] Description="RPC service" DisplayName="Remote Procedure Call (RPC)" From 1cebc8ca830218ac72bdf6a4c7d2eaeaf4730309 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 13 Oct 2021 13:34:49 +0200 Subject: [PATCH 0718/2777] sharedgpures: Add support for arbitrary metadata. --- dlls/sharedgpures.sys/shared_resource.c | 57 +++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/dlls/sharedgpures.sys/shared_resource.c b/dlls/sharedgpures.sys/shared_resource.c index a2883fb65b9..0f554d22e93 100644 --- a/dlls/sharedgpures.sys/shared_resource.c +++ b/dlls/sharedgpures.sys/shared_resource.c @@ -23,6 +23,8 @@ struct shared_resource unsigned int ref_count; void *unix_resource; WCHAR *name; + void *metadata; + SIZE_T metadata_size; }; static struct shared_resource *resource_pool; @@ -246,6 +248,33 @@ static NTSTATUS shared_resource_get_unix_resource(struct shared_resource *res, v return STATUS_SUCCESS; } +#define IOCTL_SHARED_GPU_RESOURCE_SET_METADATA CTL_CODE(FILE_DEVICE_VIDEO, 4, METHOD_BUFFERED, FILE_WRITE_ACCESS) + +static NTSTATUS shared_resource_set_metadata(struct shared_resource *res, void *buff, SIZE_T insize, IO_STATUS_BLOCK *iosb) +{ + res->metadata = ExAllocatePoolWithTag(NonPagedPool, insize, 0); + memcpy(res->metadata, buff, insize); + res->metadata_size = insize; + + iosb->Information = 0; + return STATUS_SUCCESS; +} + +#define IOCTL_SHARED_GPU_RESOURCE_GET_METADATA CTL_CODE(FILE_DEVICE_VIDEO, 5, METHOD_BUFFERED, FILE_READ_ACCESS) + +static NTSTATUS shared_resource_get_metadata(struct shared_resource *res, void *buff, SIZE_T outsize, IO_STATUS_BLOCK *iosb) +{ + if (!res->metadata) + return STATUS_NOT_FOUND; + + if (res->metadata_size > outsize) + return STATUS_BUFFER_TOO_SMALL; + + memcpy(buff, res->metadata, res->metadata_size); + iosb->Information = res->metadata_size; + return STATUS_SUCCESS; +} + static NTSTATUS WINAPI dispatch_create(DEVICE_OBJECT *device, IRP *irp) { irp->IoStatus.u.Status = STATUS_SUCCESS; @@ -263,11 +292,19 @@ static NTSTATUS WINAPI dispatch_close(DEVICE_OBJECT *device, IRP *irp) if (res) { res->ref_count--; - if (!res->ref_count && res->unix_resource) + if (!res->ref_count) { - /* TODO: see if its possible to destroy the object here (unlink?) */ - ObDereferenceObject(res->unix_resource); - res->unix_resource = NULL; + if (res->unix_resource) + { + /* TODO: see if its possible to destroy the object here (unlink?) */ + ObDereferenceObject(res->unix_resource); + res->unix_resource = NULL; + } + if (res->metadata) + { + ExFreePoolWithTag(res->metadata, 0); + res->metadata = NULL; + } } } @@ -313,6 +350,18 @@ static NTSTATUS WINAPI dispatch_ioctl(DEVICE_OBJECT *device, IRP *irp) stack->Parameters.DeviceIoControl.OutputBufferLength, &irp->IoStatus ); break; + case IOCTL_SHARED_GPU_RESOURCE_SET_METADATA: + status = shared_resource_set_metadata( *res, + irp->AssociatedIrp.SystemBuffer, + stack->Parameters.DeviceIoControl.InputBufferLength, + &irp->IoStatus ); + break; + case IOCTL_SHARED_GPU_RESOURCE_GET_METADATA: + status = shared_resource_get_metadata( *res, + irp->AssociatedIrp.SystemBuffer, + stack->Parameters.DeviceIoControl.OutputBufferLength, + &irp->IoStatus ); + break; default: FIXME( "ioctl %#lx not supported\n", stack->Parameters.DeviceIoControl.IoControlCode ); status = STATUS_NOT_SUPPORTED; From 0df885eee53d1c9f083dbfa0f0f96534dbcc6945 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 13 Jul 2022 13:08:41 -0400 Subject: [PATCH 0719/2777] ntoskrnl, server: Support referencing section objects. Needed for the shared resource manager to track the shared memory object for shared fences. --- dlls/ntoskrnl.exe/ntoskrnl.c | 12 +++++++++++- server/mapping.c | 14 +++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index cc30750a160..945f590c6a4 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -260,6 +260,15 @@ POBJECT_TYPE WINAPI ObGetObjectType( void *object ) return header->type; } +static const WCHAR section_type_name[] = {'S','e','c','t','i','o','n',0}; + +static struct _OBJECT_TYPE section_type = +{ + section_type_name +}; + +static POBJECT_TYPE p_section_type = §ion_type; + static const POBJECT_TYPE *known_types[] = { &ExEventObjectType, @@ -269,7 +278,8 @@ static const POBJECT_TYPE *known_types[] = &IoFileObjectType, &PsProcessType, &PsThreadType, - &SeTokenObjectType + &SeTokenObjectType, + &p_section_type, }; DECLARE_CRITICAL_SECTION(handle_map_cs); diff --git a/server/mapping.c b/server/mapping.c index 4c90673a5c5..67896165048 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -160,6 +160,7 @@ struct type_descr mapping_type = struct mapping { struct object obj; /* object header */ + struct list kernel_object; /* list of kernel object pointers */ mem_size_t size; /* mapping size */ unsigned int flags; /* SEC_* flags */ struct fd *fd; /* fd for mapped file */ @@ -171,6 +172,7 @@ struct mapping static void mapping_dump( struct object *obj, int verbose ); static struct fd *mapping_get_fd( struct object *obj ); +static struct list *mapping_get_kernel_obj_list( struct object *obj ); static void mapping_destroy( struct object *obj ); static enum server_fd_type mapping_get_fd_type( struct fd *fd ); @@ -195,7 +197,7 @@ static const struct object_ops mapping_ops = directory_link_name, /* link_name */ default_unlink_name, /* unlink_name */ no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ + mapping_get_kernel_obj_list, /* get_kernel_obj_list */ no_close_handle, /* close_handle */ mapping_destroy /* destroy */ }; @@ -903,6 +905,8 @@ static struct mapping *create_mapping( struct object *root, const struct unicode if (get_error() == STATUS_OBJECT_NAME_EXISTS) return mapping; /* Nothing else to do */ + list_init( &mapping->kernel_object ); + mapping->size = size; mapping->fd = NULL; mapping->shared = NULL; @@ -995,6 +999,8 @@ struct mapping *create_fd_mapping( struct object *root, const struct unicode_str if (!(mapping = create_named_object( root, &mapping_ops, name, attr, sd ))) return NULL; if (get_error() == STATUS_OBJECT_NAME_EXISTS) return mapping; /* Nothing else to do */ + list_init( &mapping->kernel_object ); + mapping->shared = NULL; mapping->committed = NULL; mapping->flags = SEC_FILE; @@ -1101,6 +1107,12 @@ static struct fd *mapping_get_fd( struct object *obj ) return (struct fd *)grab_object( mapping->fd ); } +static struct list *mapping_get_kernel_obj_list( struct object *obj ) +{ + struct mapping *mapping = (struct mapping *)obj; + return &mapping->kernel_object; +} + static void mapping_destroy( struct object *obj ) { struct mapping *mapping = (struct mapping *)obj; From 100969a15e10c5b4ea960253a233ad17e8438fe5 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 13 Jul 2022 13:11:22 -0400 Subject: [PATCH 0720/2777] sharedgpures.sys: Keep index into resource pool in FsContext instead of direct pointer to resource. This fixes the errors due to the pointers in FsContext becoming invalid when the resource pool was expanded. Signed-off-by: Derek Lesho --- dlls/sharedgpures.sys/shared_resource.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/dlls/sharedgpures.sys/shared_resource.c b/dlls/sharedgpures.sys/shared_resource.c index 0f554d22e93..27f22f6985c 100644 --- a/dlls/sharedgpures.sys/shared_resource.c +++ b/dlls/sharedgpures.sys/shared_resource.c @@ -285,7 +285,7 @@ static NTSTATUS WINAPI dispatch_create(DEVICE_OBJECT *device, IRP *irp) static NTSTATUS WINAPI dispatch_close(DEVICE_OBJECT *device, IRP *irp) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp); - struct shared_resource *res = stack->FileObject->FsContext; + struct shared_resource *res = &resource_pool[ (UINT_PTR) stack->FileObject->FsContext ]; TRACE("Freeing shared resouce %p.\n", res); @@ -316,7 +316,7 @@ static NTSTATUS WINAPI dispatch_close(DEVICE_OBJECT *device, IRP *irp) static NTSTATUS WINAPI dispatch_ioctl(DEVICE_OBJECT *device, IRP *irp) { IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); - struct shared_resource **res = (struct shared_resource **) &stack->FileObject->FsContext; + struct shared_resource *res = &resource_pool[ (UINT_PTR) stack->FileObject->FsContext ]; NTSTATUS status; TRACE( "ioctl %#lx insize %lu outsize %lu\n", @@ -327,37 +327,37 @@ static NTSTATUS WINAPI dispatch_ioctl(DEVICE_OBJECT *device, IRP *irp) switch (stack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_SHARED_GPU_RESOURCE_CREATE: - status = shared_resource_create( res, + status = shared_resource_create( &res, irp->AssociatedIrp.SystemBuffer, stack->Parameters.DeviceIoControl.InputBufferLength, &irp->IoStatus ); break; case IOCTL_SHARED_GPU_RESOURCE_OPEN: - status = shared_resource_open( res, + status = shared_resource_open( &res, irp->AssociatedIrp.SystemBuffer, stack->Parameters.DeviceIoControl.InputBufferLength, &irp->IoStatus ); break; case IOCTL_SHARED_GPU_RESOURCE_GETKMT: - status = shared_resource_getkmt( *res, + status = shared_resource_getkmt( res, irp->AssociatedIrp.SystemBuffer, stack->Parameters.DeviceIoControl.OutputBufferLength, &irp->IoStatus ); break; case IOCTL_SHARED_GPU_RESOURCE_GET_UNIX_RESOURCE: - status = shared_resource_get_unix_resource( *res, + status = shared_resource_get_unix_resource( res, irp->AssociatedIrp.SystemBuffer, stack->Parameters.DeviceIoControl.OutputBufferLength, &irp->IoStatus ); break; case IOCTL_SHARED_GPU_RESOURCE_SET_METADATA: - status = shared_resource_set_metadata( *res, + status = shared_resource_set_metadata( res, irp->AssociatedIrp.SystemBuffer, stack->Parameters.DeviceIoControl.InputBufferLength, &irp->IoStatus ); break; case IOCTL_SHARED_GPU_RESOURCE_GET_METADATA: - status = shared_resource_get_metadata( *res, + status = shared_resource_get_metadata( res, irp->AssociatedIrp.SystemBuffer, stack->Parameters.DeviceIoControl.OutputBufferLength, &irp->IoStatus ); @@ -368,6 +368,9 @@ static NTSTATUS WINAPI dispatch_ioctl(DEVICE_OBJECT *device, IRP *irp) break; } + if (!status) + stack->FileObject->FsContext = (void *)(UINT_PTR)(res - resource_pool); + irp->IoStatus.u.Status = status; IoCompleteRequest( irp, IO_NO_INCREMENT ); return status; From 5002c6949eac5c50a4f02bb74a6c5d75888c07c7 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 13 Jul 2022 13:14:04 -0400 Subject: [PATCH 0721/2777] sharedgpures.sys: Add support for associating additional NT objects with shared resources. This is then used to share a shared memory section for shared fences --- dlls/sharedgpures.sys/shared_resource.c | 91 +++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/dlls/sharedgpures.sys/shared_resource.c b/dlls/sharedgpures.sys/shared_resource.c index 27f22f6985c..d8eaea26348 100644 --- a/dlls/sharedgpures.sys/shared_resource.c +++ b/dlls/sharedgpures.sys/shared_resource.c @@ -25,6 +25,8 @@ struct shared_resource WCHAR *name; void *metadata; SIZE_T metadata_size; + void **object_pool; + unsigned int object_pool_count; }; static struct shared_resource *resource_pool; @@ -275,6 +277,70 @@ static NTSTATUS shared_resource_get_metadata(struct shared_resource *res, void * return STATUS_SUCCESS; } +#define IOCTL_SHARED_GPU_RESOURCE_SET_OBJECT CTL_CODE(FILE_DEVICE_VIDEO, 6, METHOD_BUFFERED, FILE_WRITE_ACCESS) + +struct shared_resource_set_object +{ + unsigned int index; + obj_handle_t handle; +}; + +static NTSTATUS shared_resource_set_object(struct shared_resource *res, void *buff, SIZE_T insize, IO_STATUS_BLOCK *iosb) +{ + struct shared_resource_set_object *params = buff; + void *object; + + if (insize < sizeof(*params)) + return STATUS_INFO_LENGTH_MISMATCH; + + if (!(object = reference_client_handle(params->handle))) + return STATUS_INVALID_HANDLE; + + if (params->index >= res->object_pool_count) + { + void **expanded_pool = ExAllocatePoolWithTag(NonPagedPool, (params->index + 1) * sizeof(void *), 0); + + if (res->object_pool) + { + memcpy(expanded_pool, res->object_pool, res->object_pool_count * sizeof(void *)); + ExFreePoolWithTag(res->object_pool, 0); + } + + memset(&expanded_pool[res->object_pool_count], 0, (params->index + 1 - res->object_pool_count) * sizeof (void *)); + + res->object_pool = expanded_pool; + res->object_pool_count = params->index + 1; + } + + if (res->object_pool[params->index]) + ObDereferenceObject(res->object_pool[params->index]); + + res->object_pool[params->index] = object; + + iosb->Information = 0; + return STATUS_SUCCESS; +} + +#define IOCTL_SHARED_GPU_RESOURCE_GET_OBJECT CTL_CODE(FILE_DEVICE_VIDEO, 6, METHOD_BUFFERED, FILE_READ_ACCESS) + +static NTSTATUS shared_resource_get_object(struct shared_resource *res, void *buff, SIZE_T insize, SIZE_T outsize, IO_STATUS_BLOCK *iosb) +{ + unsigned int index; + + if (insize < sizeof(unsigned int) || outsize < sizeof(obj_handle_t)) + return STATUS_INFO_LENGTH_MISMATCH; + + index = *(unsigned int *)buff; + + if (index >= res->object_pool_count || !res->object_pool[index]) + return STATUS_INVALID_PARAMETER; + + *((obj_handle_t *)buff) = open_client_handle(res->object_pool[index]); + + iosb->Information = sizeof(obj_handle_t); + return STATUS_SUCCESS; +} + static NTSTATUS WINAPI dispatch_create(DEVICE_OBJECT *device, IRP *irp) { irp->IoStatus.u.Status = STATUS_SUCCESS; @@ -305,6 +371,18 @@ static NTSTATUS WINAPI dispatch_close(DEVICE_OBJECT *device, IRP *irp) ExFreePoolWithTag(res->metadata, 0); res->metadata = NULL; } + if (res->object_pool) + { + unsigned int i; + for (i = 0; i < res->object_pool_count; i++) + { + if (res->object_pool[i]) + ObDereferenceObject(res->object_pool[i]); + } + ExFreePoolWithTag(res->object_pool, 0); + res->object_pool = NULL; + res->object_pool_count = 0; + } } } @@ -362,6 +440,19 @@ static NTSTATUS WINAPI dispatch_ioctl(DEVICE_OBJECT *device, IRP *irp) stack->Parameters.DeviceIoControl.OutputBufferLength, &irp->IoStatus ); break; + case IOCTL_SHARED_GPU_RESOURCE_SET_OBJECT: + status = shared_resource_set_object( res, + irp->AssociatedIrp.SystemBuffer, + stack->Parameters.DeviceIoControl.InputBufferLength, + &irp->IoStatus ); + break; + case IOCTL_SHARED_GPU_RESOURCE_GET_OBJECT: + status = shared_resource_get_object( res, + irp->AssociatedIrp.SystemBuffer, + stack->Parameters.DeviceIoControl.InputBufferLength, + stack->Parameters.DeviceIoControl.OutputBufferLength, + &irp->IoStatus); + break; default: FIXME( "ioctl %#lx not supported\n", stack->Parameters.DeviceIoControl.IoControlCode ); status = STATUS_NOT_SUPPORTED; From ea28c56f01157000eec544b4717a73a5d28f9aa6 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 22 Apr 2022 11:53:02 -0400 Subject: [PATCH 0722/2777] winevulkan: Implement VK_KHR_external_semaphore_win32 for OPAQUE_WIN32 handleType. --- dlls/winevulkan/make_vulkan | 12 ++- dlls/winevulkan/vulkan.c | 176 ++++++++++++++++++++++++++++++++++-- 2 files changed, 175 insertions(+), 13 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index c47ad6e16a8..9b3ce451145 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -100,7 +100,6 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_hdr_metadata", # Needs WSI work. "VK_GOOGLE_display_timing", "VK_KHR_external_fence_win32", - "VK_KHR_external_semaphore_win32", # Relates to external_semaphore and needs type conversions in bitflags. "VK_KHR_shared_presentable_image", # Needs WSI work. "VK_KHR_win32_keyed_mutex", @@ -113,7 +112,6 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_physical_device_drm", "VK_GOOGLE_surfaceless_query", "VK_KHR_external_fence_fd", - "VK_KHR_external_semaphore_fd", "VK_SEC_amigo_profiling", # Angle specific. # Extensions which require callback handling @@ -195,7 +193,7 @@ FUNCTION_OVERRIDES = { "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceExternalBufferProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, - "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkGetPhysicalDeviceProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE}, "vkGetPhysicalDeviceProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE}, @@ -249,7 +247,7 @@ FUNCTION_OVERRIDES = { "vkGetPhysicalDeviceImageFormatProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, # VK_KHR_external_semaphore_capabilities - "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, # VK_KHR_device_group_creation "vkEnumeratePhysicalDeviceGroupsKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, @@ -273,6 +271,11 @@ FUNCTION_OVERRIDES = { # VK_KHR_external_memory_win32 "vkGetMemoryWin32HandleKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetMemoryWin32HandlePropertiesKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + + #VK_KHR_external_semaphore_win32 + "vkCreateSemaphore" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE, "extra_param" : "pCreateInfo"}, + "vkGetSemaphoreWin32HandleKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkImportSemaphoreWin32HandleKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, } STRUCT_CHAIN_CONVERSIONS = { @@ -285,6 +288,7 @@ STRUCT_CHAIN_CONVERSIONS = { "VkImageCreateInfo": [], "VkMemoryAllocateInfo": ["VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR", "VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"], "VkPhysicalDeviceImageFormatInfo2": [], + "VkSemaphoreCreateInfo": ["VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR"], } # Some struct members are conditionally ignored and callers are free to leave them uninitialized. diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 4b317b36e60..dbc857c0111 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -290,6 +290,14 @@ static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME); host_properties[i].specVersion = VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION; } + if (!strcmp(host_properties[i].extensionName, "VK_KHR_external_semaphore_fd")) + { + TRACE("Substituting VK_KHR_external_semaphore_fd for VK_KHR_external_semaphore_win32\n"); + + snprintf(host_properties[i].extensionName, sizeof(host_properties[i].extensionName), + VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME); + host_properties[i].specVersion = VK_KHR_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION; + } if (wine_vk_device_extension_supported(host_properties[i].extensionName)) { @@ -489,7 +497,7 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de if (!strcmp(extension_name, wine_xr_extension_name)) append_xr = 1; - else if (!strcmp(extension_name, "VK_KHR_external_memory_win32")) + else if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_memory_win32") || !strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_semaphore_win32")) replace_win32 = 1; } @@ -513,6 +521,8 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de continue; if (replace_win32 && !strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_memory_win32")) new_extensions[o++] = "VK_KHR_external_memory_fd"; + else if (replace_win32 && !strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_semaphore_win32")) + new_extensions[o++] = "VK_KHR_external_semaphore_fd"; else new_extensions[o++] = src->ppEnabledExtensionNames[i]; } @@ -1639,22 +1649,69 @@ VkResult wine_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(VkPhysicalDevice ha return res; } -void wine_vkGetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice phys_dev, +static inline void wine_vk_normalize_semaphore_handle_types_win(VkExternalSemaphoreHandleTypeFlags *types) +{ + *types &= + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT | + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT | + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT; +} + +static inline void wine_vk_normalize_semaphore_handle_types_host(VkExternalSemaphoreHandleTypeFlags *types) +{ + *types &= + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT | + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; +} + +static void wine_vk_get_physical_device_external_semaphore_properties(struct wine_phys_dev *phys_dev, + void (*p_vkGetPhysicalDeviceExternalSemaphoreProperties)(VkPhysicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo *, VkExternalSemaphoreProperties *), + const VkPhysicalDeviceExternalSemaphoreInfo *semaphore_info, VkExternalSemaphoreProperties *properties) +{ + VkPhysicalDeviceExternalSemaphoreInfo semaphore_info_dup = *semaphore_info; + + wine_vk_normalize_semaphore_handle_types_win(&semaphore_info_dup.handleType); + if (semaphore_info_dup.handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT) + semaphore_info_dup.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; + wine_vk_normalize_semaphore_handle_types_host(&semaphore_info_dup.handleType); + + if (semaphore_info->handleType && !semaphore_info_dup.handleType) + { + properties->exportFromImportedHandleTypes = 0; + properties->compatibleHandleTypes = 0; + properties->externalSemaphoreFeatures = 0; + return; + } + + p_vkGetPhysicalDeviceExternalSemaphoreProperties(phys_dev->phys_dev, &semaphore_info_dup, properties); + + if (properties->exportFromImportedHandleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) + properties->exportFromImportedHandleTypes |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT; + wine_vk_normalize_semaphore_handle_types_win(&properties->exportFromImportedHandleTypes); + + if (properties->compatibleHandleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) + properties->compatibleHandleTypes |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT; + wine_vk_normalize_semaphore_handle_types_win(&properties->compatibleHandleTypes); +} + +void wine_vkGetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice phys_dev_handle, const VkPhysicalDeviceExternalSemaphoreInfo *info, VkExternalSemaphoreProperties *properties) { - properties->exportFromImportedHandleTypes = 0; - properties->compatibleHandleTypes = 0; - properties->externalSemaphoreFeatures = 0; + struct wine_phys_dev *phys_dev = wine_phys_dev_from_handle(phys_dev_handle); + + TRACE("%p, %p, %p\n", phys_dev, info, properties); + wine_vk_get_physical_device_external_semaphore_properties(phys_dev, phys_dev->instance->funcs.p_vkGetPhysicalDeviceExternalSemaphoreProperties, info, properties); } -void wine_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(VkPhysicalDevice phys_dev, +void wine_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(VkPhysicalDevice phys_dev_handle, const VkPhysicalDeviceExternalSemaphoreInfo *info, VkExternalSemaphoreProperties *properties) { - properties->exportFromImportedHandleTypes = 0; - properties->compatibleHandleTypes = 0; - properties->externalSemaphoreFeatures = 0; + struct wine_phys_dev *phys_dev = wine_phys_dev_from_handle(phys_dev_handle); + + TRACE("%p, %p, %p\n", phys_dev, info, properties); + wine_vk_get_physical_device_external_semaphore_properties(phys_dev, phys_dev->instance->funcs.p_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR, info, properties); } /* @@ -3324,6 +3381,10 @@ NTSTATUS vk_is_available_device_function(void *arg) struct wine_device *device = wine_device_from_handle(params->device); if (!strcmp(params->name, "vkGetMemoryWin32HandleKHR") || !strcmp(params->name, "vkGetMemoryWin32HandlePropertiesKHR")) params->name = "vkGetMemoryFdKHR"; + else if (!strcmp(params->name, "vkGetSemaphoreWin32HandleKHR")) + params->name = "vkGetSemaphoreFdKHR"; + else if (!strcmp(params->name, "vkImportSemaphoreWin32HandleKHR")) + params->name = "vkImportSemaphoreFdKHR"; return !!vk_funcs->p_vkGetDeviceProcAddr(device->device, params->name); } @@ -3351,6 +3412,10 @@ NTSTATUS vk_is_available_device_function32(void *arg) char *name = UlongToPtr(params->name); if (!strcmp(name, "vkGetMemoryWin32HandleKHR") || !strcmp(name, "vkGetMemoryWin32HandlePropertiesKHR")) return !!vk_funcs->p_vkGetDeviceProcAddr(device->device, "vkGetMemoryFdKHR"); + if (!strcmp(name, "vkGetSemaphoreWin32HandleKHR")) + return !!vk_funcs->p_vkGetDeviceProcAddr(device->device, "vkGetSemaphoreFdKHR"); + if (!strcmp(name, "vkImportSemaphoreWin32HandleKHR")) + return !!vk_funcs->p_vkGetDeviceProcAddr(device->device, "vkImportSemaphoreFdKHR"); return !!vk_funcs->p_vkGetDeviceProcAddr(device->device, UlongToPtr(params->name)); } @@ -3434,3 +3499,96 @@ VkResult wine_vkGetMemoryWin32HandlePropertiesKHR(VkDevice device, VkExternalMem handleType must not be one of the handle types defined as opaque */ return VK_ERROR_INVALID_EXTERNAL_HANDLE; } + + +VkResult wine_vkCreateSemaphore(VkDevice device_handle, const VkSemaphoreCreateInfo *create_info, + const VkAllocationCallbacks *allocator, VkSemaphore *semaphore, void *win_create_info) +{ + struct wine_device *device = wine_device_from_handle(device_handle); + VkExportSemaphoreCreateInfo *export_semaphore_info; + + TRACE("%p %p %p %p", device, create_info, allocator, semaphore); + + if ((export_semaphore_info = wine_vk_find_struct(create_info, EXPORT_SEMAPHORE_CREATE_INFO))) + { + if (export_semaphore_info->handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT) + export_semaphore_info->handleTypes |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; + wine_vk_normalize_semaphore_handle_types_host(&export_semaphore_info->handleTypes); + } + + if (wine_vk_find_struct(win_create_info, EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR)) + FIXME("VkExportSemaphoreWin32HandleInfoKHR unhandled.\n"); + + return device->funcs.p_vkCreateSemaphore(device->device, create_info, NULL, semaphore); +} + +VkResult wine_vkGetSemaphoreWin32HandleKHR(VkDevice device_handle, const VkSemaphoreGetWin32HandleInfoKHR *handle_info, + HANDLE *handle) +{ + struct wine_device *device = wine_device_from_handle(device_handle); + VkSemaphoreGetFdInfoKHR fd_info; + VkResult res; + int fd; + + fd_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR; + fd_info.pNext = handle_info->pNext; + fd_info.semaphore = handle_info->semaphore; + fd_info.handleType = handle_info->handleType; + if (fd_info.handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT) + fd_info.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; + wine_vk_normalize_semaphore_handle_types_host(&fd_info.handleType); + + res = device->funcs.p_vkGetSemaphoreFdKHR(device->device, &fd_info, &fd); + + if (res != VK_SUCCESS) + return res; + + if (wine_server_fd_to_handle(fd, GENERIC_ALL, 0, handle) != STATUS_SUCCESS) + { + close(fd); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + return VK_SUCCESS; +} + +VkResult wine_vkImportSemaphoreWin32HandleKHR(VkDevice device_handle, + const VkImportSemaphoreWin32HandleInfoKHR *handle_info) +{ + struct wine_device *device = wine_device_from_handle(device_handle); + VkImportSemaphoreFdInfoKHR fd_info; + VkResult res; + int fd; + + fd_info.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR; + fd_info.pNext = handle_info->pNext; + fd_info.semaphore = handle_info->semaphore; + fd_info.flags = handle_info->flags; + fd_info.handleType = handle_info->handleType; + + if (fd_info.handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT) + { + if (handle_info->name) + { + FIXME("Importing win32 semaphore by name not supported.\n"); + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + } + + fd_info.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; + if (wine_server_handle_to_fd(handle_info->handle, GENERIC_ALL, &fd, NULL) != STATUS_SUCCESS) + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + } + wine_vk_normalize_semaphore_handle_types_host(&fd_info.handleType); + + if (!fd_info.handleType) + { + FIXME("Importing win32 semaphore with handle type %#x not supported.\n", handle_info->handleType); + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + } + + /* importing FDs transfers ownership, importing NT handles does not */ + if ((res = device->funcs.p_vkImportSemaphoreFdKHR(device->device, &fd_info)) != VK_SUCCESS) + close(fd); + + return res; +} From 722e87a48b692d35c9dbb89594ac692a9986b967 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 23 Dec 2022 17:49:37 -0600 Subject: [PATCH 0723/2777] winevulkan: Don't convert handles in "unwrapped" conversions. --- dlls/winevulkan/make_vulkan | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 9b3ce451145..f311e0fad53 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -1504,7 +1504,10 @@ class VkMember(VkVariable): self.value(input, conv), handle.driver_handle(self.value(input, conv))) else: input_name = "{0}{1}".format(input, self.name) - return "{0}{1} = {2} ? {3} : VK_NULL_HANDLE;\n".format(output, self.name, input_name, handle.driver_handle(self.value(input, conv))) + if unwrap: + return "{0}{1} = {2} ? {3} : VK_NULL_HANDLE;\n".format(output, self.name, input_name, handle.driver_handle(self.value(input, conv))) + else: + return "{0}{1} = {2};\n".format(output, self.name, self.value(input, conv)) elif self.is_generic_handle(): if direction == Direction.OUTPUT: LOGGER.err("OUTPUT parameter {0}.{1} cannot be unwrapped".format(self.type, self.name)) From f3f7edb8701d6dad01fadcf7816bf55916a2505a Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Thu, 14 Jul 2022 15:36:52 -0400 Subject: [PATCH 0724/2777] winevulkan: Add initial support for D3D12-Fence compatible timeline semaphores. --- dlls/winevulkan/make_vulkan | 21 + dlls/winevulkan/vulkan.c | 814 +++++++++++++++++++++++++++++-- dlls/winevulkan/vulkan_private.h | 39 ++ 3 files changed, 833 insertions(+), 41 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index f311e0fad53..a3fde3ef48f 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -214,6 +214,12 @@ FUNCTION_OVERRIDES = { "vkUnmapMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkCreateBuffer" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkCreateImage" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, + "vkGetSemaphoreCounterValue" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, + "vkSignalSemaphore" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, + "vkWaitSemaphores" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, + "vkQueueBindSparse" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, + "vkQueueSubmit" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, + "vkQueueSubmit2" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, # VK_KHR_surface "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE}, @@ -276,6 +282,15 @@ FUNCTION_OVERRIDES = { "vkCreateSemaphore" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE, "extra_param" : "pCreateInfo"}, "vkGetSemaphoreWin32HandleKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkImportSemaphoreWin32HandleKHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + + # VK_KHR_timeline_semaphore + "vkDestroySemaphore" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkGetSemaphoreCounterValueKHR" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, + "vkSignalSemaphoreKHR" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, + "vkWaitSemaphoresKHR" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, + + # VK_KHR_synchronization2 + "vkQueueSubmit2KHR" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, } STRUCT_CHAIN_CONVERSIONS = { @@ -288,7 +303,11 @@ STRUCT_CHAIN_CONVERSIONS = { "VkImageCreateInfo": [], "VkMemoryAllocateInfo": ["VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR", "VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR"], "VkPhysicalDeviceImageFormatInfo2": [], + "VkPhysicalDeviceExternalSemaphoreInfo": [], "VkSemaphoreCreateInfo": ["VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR"], + "VkSubmitInfo": [], + "VkSubmitInfo2": [], + "VkBindSparseInfo" : [], } # Some struct members are conditionally ignored and callers are free to leave them uninitialized. @@ -1123,6 +1142,8 @@ class VkHandle(object): return "wine_instance_from_handle({0})->instance".format(name) if self.name == "VkDeviceMemory": return "wine_device_memory_from_handle({0})->memory".format(name) + if self.name == "VkSemaphore": + return "wine_semaphore_host_handle( wine_semaphore_from_handle({0}) )".format(name) if self.name == "VkPhysicalDevice": return "wine_phys_dev_from_handle({0})->phys_dev".format(name) if self.name == "VkQueue": diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index dbc857c0111..957aee7f940 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "ntstatus.h" #define WIN32_NO_STATUS @@ -477,7 +478,7 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de struct conversion_context *ctx, const VkDeviceCreateInfo *src, VkDeviceCreateInfo *dst) { static const char *wine_xr_extension_name = "VK_WINE_openxr_device_extensions"; - unsigned int i, append_xr = 0, replace_win32 = 0; + unsigned int i, append_xr = 0, replace_win32 = 0, append_timeline = 1; VkBaseOutStructure *header; char **xr_extensions_list; @@ -499,12 +500,26 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de append_xr = 1; else if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_memory_win32") || !strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_semaphore_win32")) replace_win32 = 1; + else if (!strcmp(extension_name, "VK_KHR_timeline_semaphore")) + append_timeline = 0; + } + if (append_timeline) + { + append_timeline = 0; + for (i = 0; i < phys_dev->extension_count; ++i) + { + if (!strcmp(phys_dev->extensions[i].extensionName, "VK_KHR_timeline_semaphore")) + { + append_timeline = 1; + break; + } + } } if (append_xr) xr_extensions_list = parse_xr_extensions(&append_xr); - if (phys_dev->external_memory_align || append_xr || replace_win32) + if (phys_dev->external_memory_align || append_xr || replace_win32 || append_timeline) { const char **new_extensions; unsigned int o = 0, count; @@ -514,6 +529,9 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de count += 2; if (append_xr) count += append_xr - 1; + if (append_timeline) + ++count; + new_extensions = conversion_context_alloc(ctx, count * sizeof(*dst->ppEnabledExtensionNames)); for (i = 0; i < dst->enabledExtensionCount; ++i) { @@ -536,6 +554,8 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de TRACE("\t%s\n", xr_extensions_list[i]); new_extensions[o++] = xr_extensions_list[i]; } + if (append_timeline) + new_extensions[o++] = "VK_KHR_timeline_semaphore"; dst->enabledExtensionCount = count; dst->ppEnabledExtensionNames = new_extensions; } @@ -1669,11 +1689,37 @@ static void wine_vk_get_physical_device_external_semaphore_properties(struct win const VkPhysicalDeviceExternalSemaphoreInfo *semaphore_info, VkExternalSemaphoreProperties *properties) { VkPhysicalDeviceExternalSemaphoreInfo semaphore_info_dup = *semaphore_info; + VkSemaphoreTypeCreateInfo semaphore_type_info, *p_semaphore_type_info; - wine_vk_normalize_semaphore_handle_types_win(&semaphore_info_dup.handleType); - if (semaphore_info_dup.handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT) - semaphore_info_dup.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; - wine_vk_normalize_semaphore_handle_types_host(&semaphore_info_dup.handleType); + switch(semaphore_info->handleType) + { + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT: + semaphore_info_dup.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; + break; + case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT: + { + if ((p_semaphore_type_info = wine_vk_find_struct(&semaphore_info_dup, SEMAPHORE_TYPE_CREATE_INFO))) + { + p_semaphore_type_info->semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE; + p_semaphore_type_info->initialValue = 0; + } + else + { + semaphore_type_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO; + semaphore_type_info.pNext = semaphore_info_dup.pNext; + semaphore_type_info.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE; + semaphore_type_info.initialValue = 0; + + semaphore_info_dup.pNext = &semaphore_type_info; + } + + semaphore_info_dup.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; + break; + } + default: + semaphore_info_dup.handleType = 0; + break; + } if (semaphore_info->handleType && !semaphore_info_dup.handleType) { @@ -1686,11 +1732,11 @@ static void wine_vk_get_physical_device_external_semaphore_properties(struct win p_vkGetPhysicalDeviceExternalSemaphoreProperties(phys_dev->phys_dev, &semaphore_info_dup, properties); if (properties->exportFromImportedHandleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) - properties->exportFromImportedHandleTypes |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT; + properties->exportFromImportedHandleTypes = semaphore_info->handleType; wine_vk_normalize_semaphore_handle_types_win(&properties->exportFromImportedHandleTypes); if (properties->compatibleHandleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) - properties->compatibleHandleTypes |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT; + properties->compatibleHandleTypes = semaphore_info->handleType; wine_vk_normalize_semaphore_handle_types_win(&properties->compatibleHandleTypes); } @@ -3239,7 +3285,7 @@ static VkResult record_compute_cmd(struct wine_device *device, struct wine_swapc return VK_SUCCESS; } -VkResult wine_vkQueuePresentKHR(VkQueue queue_handle, const VkPresentInfoKHR *pPresentInfo) +VkResult fshack_vk_queue_present(VkQueue queue_handle, const VkPresentInfoKHR *pPresentInfo) { struct wine_queue *queue = wine_queue_from_handle(queue_handle); VkCommandBuffer *blit_cmds = NULL; @@ -3500,73 +3546,305 @@ VkResult wine_vkGetMemoryWin32HandlePropertiesKHR(VkDevice device, VkExternalMem return VK_ERROR_INVALID_EXTERNAL_HANDLE; } +#define IOCTL_SHARED_GPU_RESOURCE_SET_OBJECT CTL_CODE(FILE_DEVICE_VIDEO, 6, METHOD_BUFFERED, FILE_WRITE_ACCESS) + +static bool set_shared_resource_object(HANDLE shared_resource, unsigned int index, HANDLE handle) +{ + IO_STATUS_BLOCK iosb; + struct shared_resource_set_object + { + unsigned int index; + obj_handle_t handle; + } params; + + params.index = index; + params.handle = wine_server_obj_handle(handle); + + return NtDeviceIoControlFile(shared_resource, NULL, NULL, NULL, &iosb, IOCTL_SHARED_GPU_RESOURCE_SET_OBJECT, + ¶ms, sizeof(params), NULL, 0) == STATUS_SUCCESS; +} + +#define IOCTL_SHARED_GPU_RESOURCE_GET_OBJECT CTL_CODE(FILE_DEVICE_VIDEO, 6, METHOD_BUFFERED, FILE_READ_ACCESS) + +static HANDLE get_shared_resource_object(HANDLE shared_resource, unsigned int index) +{ + IO_STATUS_BLOCK iosb; + obj_handle_t handle; + + if (NtDeviceIoControlFile(shared_resource, NULL, NULL, NULL, &iosb, IOCTL_SHARED_GPU_RESOURCE_GET_OBJECT, + &index, sizeof(index), &handle, sizeof(handle))) + return NULL; + + return wine_server_ptr_handle(handle); +} + +static void d3d12_semaphore_lock(struct wine_semaphore *semaphore) +{ + assert( semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT ); + pthread_mutex_lock(&semaphore->d3d12_fence_shm->mutex); +} + +static void d3d12_semaphore_unlock(struct wine_semaphore *semaphore) +{ + assert( semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT ); + pthread_mutex_unlock(&semaphore->d3d12_fence_shm->mutex); +} VkResult wine_vkCreateSemaphore(VkDevice device_handle, const VkSemaphoreCreateInfo *create_info, const VkAllocationCallbacks *allocator, VkSemaphore *semaphore, void *win_create_info) { struct wine_device *device = wine_device_from_handle(device_handle); - VkExportSemaphoreCreateInfo *export_semaphore_info; - TRACE("%p %p %p %p", device, create_info, allocator, semaphore); + VkExportSemaphoreWin32HandleInfoKHR *export_handle_info = wine_vk_find_struct(win_create_info, EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR); + VkExportSemaphoreCreateInfo *export_semaphore_info, timeline_export_info; + VkSemaphoreCreateInfo create_info_dup = *create_info; + VkSemaphoreTypeCreateInfo *found_type_info, type_info; + VkSemaphoreGetFdInfoKHR fd_info; + pthread_mutexattr_t mutex_attr; + struct wine_semaphore *object; + OBJECT_ATTRIBUTES attr; + HANDLE section_handle; + LARGE_INTEGER li; + VkResult res; + SIZE_T size; + int fd; + + TRACE("(%p, %p, %p, %p)\n", device, create_info, allocator, semaphore); - if ((export_semaphore_info = wine_vk_find_struct(create_info, EXPORT_SEMAPHORE_CREATE_INFO))) + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + if (!(object = calloc(1, sizeof(*object)))) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + object->handle = INVALID_HANDLE_VALUE; + + if ((export_semaphore_info = wine_vk_find_struct(&create_info_dup, EXPORT_SEMAPHORE_CREATE_INFO))) { + object->export_types = export_semaphore_info->handleTypes; if (export_semaphore_info->handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT) export_semaphore_info->handleTypes |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; wine_vk_normalize_semaphore_handle_types_host(&export_semaphore_info->handleTypes); } - if (wine_vk_find_struct(win_create_info, EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR)) - FIXME("VkExportSemaphoreWin32HandleInfoKHR unhandled.\n"); + if ((res = device->funcs.p_vkCreateSemaphore(device->device, &create_info_dup, NULL, &object->semaphore)) != VK_SUCCESS) + goto done; - return device->funcs.p_vkCreateSemaphore(device->device, create_info, NULL, semaphore); + if (export_semaphore_info && export_semaphore_info->handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) + { + fd_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR; + fd_info.pNext = NULL; + fd_info.semaphore = object->semaphore; + fd_info.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; + + if ((res = device->funcs.p_vkGetSemaphoreFdKHR(device->device, &fd_info, &fd)) == VK_SUCCESS) + { + object->handle = create_gpu_resource(fd, export_handle_info ? export_handle_info->name : NULL); + close(fd); + } + + if (object->handle == INVALID_HANDLE_VALUE) + { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto done; + } + } + else if (object->export_types & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + { + /* compatibleHandleTypes doesn't include any other types */ + assert(object->export_types == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT); + object->handle_type = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT; + + timeline_export_info.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO; + timeline_export_info.pNext = NULL; + timeline_export_info.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; + + type_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO; + type_info.pNext = &timeline_export_info; + type_info.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE; + type_info.initialValue = 0; + + create_info_dup.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + create_info_dup.pNext = &type_info; + create_info_dup.flags = 0; + + if ((res = device->funcs.p_vkCreateSemaphore(device->device, &create_info_dup, NULL, &object->fence_timeline_semaphore)) != VK_SUCCESS) + goto done; + + fd_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR; + fd_info.pNext = NULL; + fd_info.semaphore = object->fence_timeline_semaphore; + fd_info.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; + + if ((res = device->funcs.p_vkGetSemaphoreFdKHR(device->device, &fd_info, &fd)) == VK_SUCCESS) + { + object->handle = create_gpu_resource(fd, export_handle_info ? export_handle_info->name : NULL); + close(fd); + } + + if (object->handle == INVALID_HANDLE_VALUE) + { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto done; + } + + /* Shared Fence Memory */ + InitializeObjectAttributes(&attr, NULL, 0, NULL, NULL); + size = li.QuadPart = sizeof(*object->d3d12_fence_shm); + if (NtCreateSection(§ion_handle, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE, &attr, &li, PAGE_READWRITE, SEC_COMMIT, NULL)) + { + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto done; + } + + if (!set_shared_resource_object(object->handle, 0, section_handle)) + { + NtClose(section_handle); + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto done; + } + + if (NtMapViewOfSection(section_handle, GetCurrentProcess(), (void**) &object->d3d12_fence_shm, 0, 0, NULL, &size, ViewShare, 0, PAGE_READWRITE)) + { + NtClose(section_handle); + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto done; + } + + NtClose(section_handle); + + if ((found_type_info = wine_vk_find_struct(create_info, SEMAPHORE_TYPE_CREATE_INFO))) + object->d3d12_fence_shm->virtual_value = found_type_info->initialValue; + + pthread_mutexattr_init(&mutex_attr); + pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED); + if (pthread_mutex_init(&object->d3d12_fence_shm->mutex, &mutex_attr)) + { + pthread_mutexattr_destroy(&mutex_attr); + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto done; + } + pthread_mutexattr_destroy(&mutex_attr); + + WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance, object, object->fence_timeline_semaphore, object); + } + if (object->fence_timeline_semaphore == VK_NULL_HANDLE) + WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance, object, object->semaphore, object); + *semaphore = wine_semaphore_to_handle(object); + + done: + + if (res != VK_SUCCESS) + { + if (object->d3d12_fence_shm) + { + pthread_mutex_destroy(&object->d3d12_fence_shm->mutex); + NtUnmapViewOfSection(GetCurrentProcess(), object->d3d12_fence_shm); + } + if (object->handle != INVALID_HANDLE_VALUE) + NtClose(object->handle); + if (object->semaphore != VK_NULL_HANDLE) + device->funcs.p_vkDestroySemaphore(device->device, object->semaphore, NULL); + if (object->fence_timeline_semaphore != VK_NULL_HANDLE) + device->funcs.p_vkDestroySemaphore(device->device, object->fence_timeline_semaphore, NULL); + free(object); + } + + return res; } VkResult wine_vkGetSemaphoreWin32HandleKHR(VkDevice device_handle, const VkSemaphoreGetWin32HandleInfoKHR *handle_info, HANDLE *handle) +{ + struct wine_semaphore *semaphore = wine_semaphore_from_handle(handle_info->semaphore); + + if (!(semaphore->export_types & handle_info->handleType)) + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + + if (NtDuplicateObject( NtCurrentProcess(), semaphore->handle, NtCurrentProcess(), handle, 0, 0, DUPLICATE_SAME_ACCESS )) + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + + return VK_SUCCESS; +} + +void wine_vkDestroySemaphore(VkDevice device_handle, VkSemaphore semaphore_handle, const VkAllocationCallbacks *allocator) { struct wine_device *device = wine_device_from_handle(device_handle); - VkSemaphoreGetFdInfoKHR fd_info; - VkResult res; - int fd; + struct wine_semaphore *semaphore = wine_semaphore_from_handle(semaphore_handle); - fd_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR; - fd_info.pNext = handle_info->pNext; - fd_info.semaphore = handle_info->semaphore; - fd_info.handleType = handle_info->handleType; - if (fd_info.handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT) - fd_info.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; - wine_vk_normalize_semaphore_handle_types_host(&fd_info.handleType); + TRACE("%p, %p, %p\n", device, semaphore, allocator); - res = device->funcs.p_vkGetSemaphoreFdKHR(device->device, &fd_info, &fd); + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); - if (res != VK_SUCCESS) - return res; + if (!semaphore) + return; - if (wine_server_fd_to_handle(fd, GENERIC_ALL, 0, handle) != STATUS_SUCCESS) - { - close(fd); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } + if (semaphore->handle != INVALID_HANDLE_VALUE) + NtClose(semaphore->handle); - return VK_SUCCESS; + if (semaphore->d3d12_fence_shm) + NtUnmapViewOfSection(GetCurrentProcess(), semaphore->d3d12_fence_shm); + + WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, semaphore); + device->funcs.p_vkDestroySemaphore(device->device, semaphore->semaphore, NULL); + + if (semaphore->fence_timeline_semaphore) + device->funcs.p_vkDestroySemaphore(device->device, semaphore->fence_timeline_semaphore, NULL); + + free(semaphore); } VkResult wine_vkImportSemaphoreWin32HandleKHR(VkDevice device_handle, const VkImportSemaphoreWin32HandleInfoKHR *handle_info) { struct wine_device *device = wine_device_from_handle(device_handle); + struct wine_semaphore *semaphore = wine_semaphore_from_handle(handle_info->semaphore); + struct wine_semaphore output_semaphore; + VkSemaphoreTypeCreateInfo type_info; VkImportSemaphoreFdInfoKHR fd_info; + VkSemaphoreCreateInfo create_info; + HANDLE d3d12_fence_shm; + NTSTATUS stat; VkResult res; - int fd; + SIZE_T size; + + TRACE("(%p, %p). semaphore = %p handle = %p\n", device, handle_info, semaphore, handle_info->handle); + + if (handle_info->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT && !semaphore->fence_timeline_semaphore) + { + type_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO; + type_info.pNext = NULL; + type_info.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE; + type_info.initialValue = 0; + + create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + create_info.pNext = &type_info; + create_info.flags = 0; + + if ((res = device->funcs.p_vkCreateSemaphore(device->device, &create_info, NULL, &semaphore->fence_timeline_semaphore)) != VK_SUCCESS) + { + ERR("Failed to create timeline semaphore backing D3D12 semaphore. vr %d.\n", res); + return res; + }; + + WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, semaphore); + WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance, semaphore, semaphore->fence_timeline_semaphore, semaphore); + } + + output_semaphore = *semaphore; + output_semaphore.handle = NULL; + output_semaphore.handle_type = handle_info->handleType; + output_semaphore.d3d12_fence_shm = NULL; fd_info.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR; fd_info.pNext = handle_info->pNext; - fd_info.semaphore = handle_info->semaphore; + fd_info.semaphore = wine_semaphore_host_handle(&output_semaphore); fd_info.flags = handle_info->flags; fd_info.handleType = handle_info->handleType; - if (fd_info.handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT) + if (handle_info->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT || + handle_info->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) { if (handle_info->name) { @@ -3574,10 +3852,49 @@ VkResult wine_vkImportSemaphoreWin32HandleKHR(VkDevice device_handle, return VK_ERROR_INVALID_EXTERNAL_HANDLE; } + if (NtDuplicateObject( NtCurrentProcess(), handle_info->handle, NtCurrentProcess(), &output_semaphore.handle, 0, 0, DUPLICATE_SAME_ACCESS )) + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + fd_info.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; - if (wine_server_handle_to_fd(handle_info->handle, GENERIC_ALL, &fd, NULL) != STATUS_SUCCESS) + if ((fd_info.fd = get_shared_resource_fd(output_semaphore.handle)) == -1) + { + WARN("Invalid handle %p.\n", handle_info->handle); + NtClose(output_semaphore.handle); return VK_ERROR_INVALID_EXTERNAL_HANDLE; + } + + if (handle_info->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + { + if (handle_info->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) + { + FIXME("Temporarily importing d3d12 fences unsupported.\n"); + close(fd_info.fd); + NtClose(output_semaphore.handle); + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + } + + if (!(d3d12_fence_shm = get_shared_resource_object(output_semaphore.handle, 0))) + { + ERR("Failed to get D3D12 semaphore memory.\n"); + close(fd_info.fd); + NtClose(output_semaphore.handle); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + size = sizeof(*output_semaphore.d3d12_fence_shm); + if ((stat = NtMapViewOfSection(d3d12_fence_shm, GetCurrentProcess(), (void**) &output_semaphore.d3d12_fence_shm, 0, 0, NULL, &size, ViewShare, 0, PAGE_READWRITE))) + { + ERR("Failed to map D3D12 semaphore memory. stat %#x.\n", (int)stat); + close(fd_info.fd); + NtClose(d3d12_fence_shm); + NtClose(output_semaphore.handle); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + NtClose(d3d12_fence_shm); + } } + wine_vk_normalize_semaphore_handle_types_host(&fd_info.handleType); if (!fd_info.handleType) @@ -3586,9 +3903,424 @@ VkResult wine_vkImportSemaphoreWin32HandleKHR(VkDevice device_handle, return VK_ERROR_INVALID_EXTERNAL_HANDLE; } - /* importing FDs transfers ownership, importing NT handles does not */ - if ((res = device->funcs.p_vkImportSemaphoreFdKHR(device->device, &fd_info)) != VK_SUCCESS) - close(fd); + if ((res = device->funcs.p_vkImportSemaphoreFdKHR(device->device, &fd_info)) == VK_SUCCESS) + { + if (semaphore->handle) + NtClose(semaphore->handle); + if (semaphore->d3d12_fence_shm) + NtUnmapViewOfSection(GetCurrentProcess(), semaphore->d3d12_fence_shm); + + *semaphore = output_semaphore; + } + else + { + if (output_semaphore.handle) + NtClose(output_semaphore.handle); + if (output_semaphore.d3d12_fence_shm) + NtUnmapViewOfSection(GetCurrentProcess(), output_semaphore.d3d12_fence_shm); + + /* importing FDs transfers ownership, importing NT handles does not */ + close(fd_info.fd); + } return res; } + +static VkResult vk_get_semaphore_counter_value(VkDevice device_handle, VkSemaphore semaphore_handle, uint64_t *value, bool khr) +{ + struct wine_semaphore *semaphore = wine_semaphore_from_handle(semaphore_handle); + struct wine_device *device = wine_device_from_handle(device_handle); + + if (khr) + return device->funcs.p_vkGetSemaphoreCounterValueKHR(device->device, wine_semaphore_host_handle(semaphore), value); + else + return device->funcs.p_vkGetSemaphoreCounterValue(device->device, wine_semaphore_host_handle(semaphore), value); +} + +static VkResult wine_vk_get_semaphore_counter_value(VkDevice device_handle, VkSemaphore semaphore_handle, uint64_t *value, bool khr) +{ + struct wine_semaphore *semaphore = wine_semaphore_from_handle(semaphore_handle); + + if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + { + d3d12_semaphore_lock(semaphore); + *value = semaphore->d3d12_fence_shm->virtual_value; + d3d12_semaphore_unlock(semaphore); + return VK_SUCCESS; + } + + return vk_get_semaphore_counter_value(device_handle, semaphore_handle, value, khr); +} + +VkResult wine_vkGetSemaphoreCounterValue(VkDevice device_handle, VkSemaphore semaphore_handle, uint64_t *value) +{ + return wine_vk_get_semaphore_counter_value(device_handle, semaphore_handle, value, false); +} + +VkResult wine_vkGetSemaphoreCounterValueKHR(VkDevice device_handle, VkSemaphore semaphore_handle, uint64_t *value) +{ + return wine_vk_get_semaphore_counter_value(device_handle, semaphore_handle, value, true); +} + +static VkResult vk_signal_semaphore(VkDevice device_handle, const VkSemaphoreSignalInfo *signal_info, bool khr) +{ + struct wine_semaphore *semaphore = wine_semaphore_from_handle(signal_info->semaphore); + struct wine_device *device = wine_device_from_handle(device_handle); + VkSemaphoreSignalInfo dup_signal_info = *signal_info; + + dup_signal_info.semaphore = wine_semaphore_host_handle(semaphore); + if (khr) + return device->funcs.p_vkSignalSemaphoreKHR(device->device, &dup_signal_info); + else + return device->funcs.p_vkSignalSemaphore(device->device, &dup_signal_info); +} + +static NTSTATUS wine_vk_signal_semaphore(VkDevice device, const VkSemaphoreSignalInfo *signal_info, bool khr) +{ + struct wine_semaphore *semaphore = wine_semaphore_from_handle(signal_info->semaphore); + + TRACE("(%p, %p)\n", device, signal_info); + + if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + { + FIXME("Signalling D3D12-Fence compatible timeline semaphore not supported.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + return vk_signal_semaphore(device, signal_info, khr); +} + +VkResult wine_vkSignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo *signal_info) +{ + return wine_vk_signal_semaphore(device, signal_info, false); +} + +VkResult wine_vkSignalSemaphoreKHR(VkDevice device, const VkSemaphoreSignalInfo *signal_info) +{ + return wine_vk_signal_semaphore(device, signal_info, true); +} + +static VkSemaphore *unwrap_semaphore_array(const VkSemaphore *in, uint32_t count, struct conversion_context *ctx) +{ + VkSemaphore *out; + unsigned int i; + + if (!in || !count) return NULL; + + out = conversion_context_alloc(ctx, count * sizeof(*out)); + for (i = 0; i < count; ++i) + out[i] = in[i] ? wine_semaphore_host_handle(wine_semaphore_from_handle(in[i])) : VK_NULL_HANDLE; + + return out; +} + +static VkResult vk_wait_semaphores(struct wine_device *device, const VkSemaphoreWaitInfo *wait_info, uint64_t timeout, bool khr) +{ + VkSemaphoreWaitInfo wait_info_dup = *wait_info; + struct conversion_context ctx; + VkResult ret; + + init_conversion_context(&ctx); + wait_info_dup.pSemaphores = unwrap_semaphore_array(wait_info->pSemaphores, wait_info->semaphoreCount, &ctx); + if (khr) + ret = device->funcs.p_vkWaitSemaphoresKHR(device->device, &wait_info_dup, timeout); + else + ret = device->funcs.p_vkWaitSemaphores(device->device, &wait_info_dup, timeout); + free_conversion_context(&ctx); + return ret; +} + +static VkResult wine_vk_wait_semaphores(VkDevice device_handle, const VkSemaphoreWaitInfo *wait_info, uint64_t timeout, bool khr) +{ + unsigned int i; + + TRACE("(%p, %p, 0x%s)\n", device_handle, wait_info, wine_dbgstr_longlong(timeout)); + + for (i = 0; i < wait_info->semaphoreCount; i++) + { + struct wine_semaphore *semaphore = wine_semaphore_from_handle(wait_info->pSemaphores[i]); + + if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + { + FIXME("Waiting on D3D12-Fence compatible timeline semaphores not supported."); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } + return vk_wait_semaphores(wine_device_from_handle(device_handle), wait_info, timeout, khr); +} + +VkResult wine_vkWaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo *wait_info, uint64_t timeout) +{ + return wine_vk_wait_semaphores(device, wait_info, timeout, false); +} + +VkResult wine_vkWaitSemaphoresKHR(VkDevice device, const VkSemaphoreWaitInfo *wait_info, uint64_t timeout) +{ + return wine_vk_wait_semaphores(device, wait_info, timeout, true); +} + +VkResult vk_queue_submit_unwrap(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo *submits_orig, VkFence fence) +{ + struct conversion_context ctx; + VkSubmitInfo *submits; + unsigned int i, j; + VkResult ret; + + init_conversion_context(&ctx); + MEMDUP(&ctx, submits, submits_orig, submit_count); + for (i = 0; i < submit_count; ++i) + { + submits[i].pWaitSemaphores = unwrap_semaphore_array(submits[i].pWaitSemaphores, submits[i].waitSemaphoreCount, &ctx); + submits[i].pSignalSemaphores = unwrap_semaphore_array(submits[i].pSignalSemaphores, submits[i].signalSemaphoreCount, &ctx); + if (submits[i].pCommandBuffers && submits[i].commandBufferCount) + { + VkCommandBuffer *out; + + out = conversion_context_alloc(&ctx, submits[i].commandBufferCount * sizeof(*out)); + for (j = 0; j < submits[i].commandBufferCount; ++j) + out[j] = wine_cmd_buffer_from_handle(submits[i].pCommandBuffers[j])->command_buffer; + submits[i].pCommandBuffers = out; + } + } + ret = queue->device->funcs.p_vkQueueSubmit(queue->queue, submit_count, submits, fence); + free_conversion_context(&ctx); + return ret; +} + +VkResult wine_vkQueueSubmit(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo *submits, VkFence fence) +{ + struct wine_queue *queue = wine_queue_from_handle(queue_handle); + unsigned int i, k; + + TRACE("(%p %u %p 0x%s)\n", queue_handle, submit_count, submits, wine_dbgstr_longlong(fence)); + + for (i = 0; i < submit_count; i++) + { + for (k = 0; k < submits[i].waitSemaphoreCount; k++) + { + if (wine_semaphore_from_handle(submits[i].pWaitSemaphores[k])->handle_type == + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + { + FIXME("Queue submissions with waits on D3D12-Fence compatible timeline semaphores not supported.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } + + for (k = 0; k < submits[i].signalSemaphoreCount; k++) + { + if (wine_semaphore_from_handle(submits[i].pSignalSemaphores[k])->handle_type == + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + { + FIXME("Queue submissions with signalling D3D12-Fence compatible timeline semaphores not supported.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } + } + return vk_queue_submit_unwrap(queue, submit_count, submits, fence); +} + +static void duplicate_array_for_unwrapping(struct conversion_context *ctx, void **ptr, unsigned int size) +{ + void *out; + + if (!*ptr || !size) + return; + + out = conversion_context_alloc(ctx, size); + memcpy(out, *ptr, size); + *ptr = out; +} + +VkResult vk_queue_submit_2_unwrap(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo2 *submits_orig, + VkFence fence, bool khr) +{ + struct conversion_context ctx; + VkSubmitInfo2 *submits; + unsigned int i, j; + VkResult ret; + + init_conversion_context(&ctx); + MEMDUP(&ctx, submits, submits_orig, submit_count); + for (i = 0; i < submit_count; ++i) + { + duplicate_array_for_unwrapping(&ctx, (void **)&submits[i].pWaitSemaphoreInfos, + submits[i].waitSemaphoreInfoCount * sizeof(*submits[i].pWaitSemaphoreInfos)); + for (j = 0; j < submits[i].waitSemaphoreInfoCount; ++j) + if (submits[i].pWaitSemaphoreInfos[j].semaphore) + ((VkSemaphoreSubmitInfo *)submits[i].pWaitSemaphoreInfos)[j].semaphore + = wine_semaphore_host_handle(wine_semaphore_from_handle(submits[i].pWaitSemaphoreInfos[j].semaphore)); + + duplicate_array_for_unwrapping(&ctx, (void **)&submits[i].pSignalSemaphoreInfos, + submits[i].signalSemaphoreInfoCount * sizeof(*submits[i].pSignalSemaphoreInfos)); + for (j = 0; j < submits[i].signalSemaphoreInfoCount; ++j) + if (submits[i].pSignalSemaphoreInfos[j].semaphore) + ((VkSemaphoreSubmitInfo *)submits[i].pSignalSemaphoreInfos)[j].semaphore + = wine_semaphore_host_handle(wine_semaphore_from_handle(submits[i].pSignalSemaphoreInfos[j].semaphore)); + + if (submits[i].pCommandBufferInfos && submits[i].commandBufferInfoCount) + { + duplicate_array_for_unwrapping(&ctx, (void **)&submits[i].pCommandBufferInfos, + submits[i].commandBufferInfoCount * sizeof(*submits[i].pCommandBufferInfos)); + for (j = 0; j < submits[i].commandBufferInfoCount; ++j) + ((VkCommandBufferSubmitInfo *)submits[i].pCommandBufferInfos)[j].commandBuffer + = wine_cmd_buffer_from_handle(submits[i].pCommandBufferInfos[j].commandBuffer)->command_buffer; + } + } + if (khr) + ret = queue->device->funcs.p_vkQueueSubmit2KHR(queue->queue, submit_count, submits, fence); + else + ret = queue->device->funcs.p_vkQueueSubmit2(queue->queue, submit_count, submits, fence); + free_conversion_context(&ctx); + return ret; +} + +static VkResult vk_queue_submit_2(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence, bool khr) +{ + struct wine_queue *queue = wine_queue_from_handle(queue_handle); + unsigned int i, k; + + TRACE("(%p, %u, %p, %s)\n", queue_handle, submit_count, submits, wine_dbgstr_longlong(fence)); + + for (i = 0; i < submit_count; i++) + { + for (k = 0; k < submits[i].waitSemaphoreInfoCount; k++) + { + if (wine_semaphore_from_handle(submits[i].pWaitSemaphoreInfos[k].semaphore)->handle_type == + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + { + FIXME("Queue submissions with waits on D3D12-Fence compatible timeline semaphores not supported.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } + + for (k = 0; k < submits[i].signalSemaphoreInfoCount; k++) + { + if (wine_semaphore_from_handle(submits[i].pSignalSemaphoreInfos[k].semaphore)->handle_type == + VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + { + FIXME("Queue submissions signalling D3D12-Fence compatible timeline semaphores not supported.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } + } + + return vk_queue_submit_2_unwrap(queue, submit_count, submits, fence, khr); +} + +VkResult wine_vkQueueSubmit2(VkQueue queue, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence) +{ + return vk_queue_submit_2(queue, submit_count, submits, fence, false); +} + +VkResult wine_vkQueueSubmit2KHR(VkQueue queue, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence) +{ + return vk_queue_submit_2(queue, submit_count, submits, fence, true); +} + +VkResult wine_vkQueuePresentKHR(VkQueue queue_handle, const VkPresentInfoKHR *present_info) +{ + VkPresentInfoKHR host_present_info = *present_info; + struct wine_semaphore *semaphore; + struct conversion_context ctx; + unsigned int i; + VkResult ret; + + TRACE("%p %p\n", queue_handle, present_info); + + for (i = 0; i < present_info->waitSemaphoreCount; ++i) + { + semaphore = wine_semaphore_from_handle(present_info->pWaitSemaphores[i]); + + if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + { + FIXME("Waiting on D3D12-Fence compatible timeline semaphore not supported.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } + + init_conversion_context(&ctx); + host_present_info.pWaitSemaphores = unwrap_semaphore_array(present_info->pWaitSemaphores, present_info->waitSemaphoreCount, &ctx); + ret = fshack_vk_queue_present(queue_handle, &host_present_info); + free_conversion_context(&ctx); + return ret; +} + +VkResult wine_vkQueueBindSparse(VkQueue queue_handle, uint32_t bind_info_count, const VkBindSparseInfo *bind_info, VkFence fence) +{ + struct wine_queue *queue = wine_queue_from_handle(queue_handle); + struct wine_semaphore *semaphore; + struct conversion_context ctx; + VkBindSparseInfo *batch; + unsigned int i, j, k; + VkResult ret; + + TRACE("(%p, %u, %p, 0x%s)\n", queue, bind_info_count, bind_info, wine_dbgstr_longlong(fence)); + + for (i = 0; i < bind_info_count; i++) + { + batch = (VkBindSparseInfo *)&bind_info[i]; + + for (k = 0; k < batch->waitSemaphoreCount; k++) + { + semaphore = wine_semaphore_from_handle(batch->pWaitSemaphores[k]); + + if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + { + FIXME("Waiting on D3D12-Fence compatible timeline semaphore not supported.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } + + for(k = 0; k < batch->signalSemaphoreCount; k++) + { + semaphore = wine_semaphore_from_handle(batch->pSignalSemaphores[k]); + + if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + { + FIXME("Signalling D3D12-Fence compatible timeline semaphore not supported.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } + } + + init_conversion_context(&ctx); + for (i = 0; i < bind_info_count; ++i) + { + batch = (VkBindSparseInfo *)&bind_info[i]; + batch->pWaitSemaphores = unwrap_semaphore_array(batch->pWaitSemaphores, batch->waitSemaphoreCount, &ctx); + batch->pSignalSemaphores = unwrap_semaphore_array(batch->pSignalSemaphores, batch->signalSemaphoreCount, &ctx); + + duplicate_array_for_unwrapping(&ctx, (void **)&batch->pBufferBinds, batch->bufferBindCount * sizeof(*batch->pBufferBinds)); + for (j = 0; j < batch->bufferBindCount; ++j) + { + VkSparseBufferMemoryBindInfo *bind = (VkSparseBufferMemoryBindInfo *)&batch->pBufferBinds[j]; + duplicate_array_for_unwrapping(&ctx, (void **)&bind->pBinds, bind->bindCount * sizeof(*bind->pBinds)); + for (k = 0; k < bind->bindCount; ++k) + if (bind->pBinds[k].memory) + ((VkSparseMemoryBind *)bind->pBinds)[k].memory = wine_device_memory_from_handle(bind->pBinds[k].memory)->memory; + } + + duplicate_array_for_unwrapping(&ctx, (void **)&batch->pImageOpaqueBinds, batch->imageOpaqueBindCount * sizeof(*batch->pImageOpaqueBinds)); + for (j = 0; j < batch->imageOpaqueBindCount; ++j) + { + VkSparseImageOpaqueMemoryBindInfo *bind = (VkSparseImageOpaqueMemoryBindInfo *)&batch->pImageOpaqueBinds[j]; + duplicate_array_for_unwrapping(&ctx, (void **)&bind->pBinds, bind->bindCount * sizeof(*bind->pBinds)); + for (k = 0; k < bind->bindCount; ++k) + if (bind->pBinds[k].memory) + ((VkSparseMemoryBind *)bind->pBinds)[k].memory = wine_device_memory_from_handle(bind->pBinds[k].memory)->memory; + } + + duplicate_array_for_unwrapping(&ctx, (void **)&batch->pImageBinds, batch->imageBindCount * sizeof(*batch->pImageBinds)); + for (j = 0; j < batch->imageBindCount; ++j) + { + VkSparseImageMemoryBindInfo *bind = (VkSparseImageMemoryBindInfo *)&batch->pImageBinds[j]; + duplicate_array_for_unwrapping(&ctx, (void **)&bind->pBinds, bind->bindCount * sizeof(*bind->pBinds)); + for (k = 0; k < bind->bindCount; ++k) + if (bind->pBinds[k].memory) + ((VkSparseImageMemoryBind *)bind->pBinds)[k].memory = wine_device_memory_from_handle(bind->pBinds[k].memory)->memory; + } + } + ret = queue->device->funcs.p_vkQueueBindSparse(queue->queue, bind_info_count, bind_info, fence); + free_conversion_context(&ctx); + return ret; +} diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 28350764da0..0e7a159e934 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -321,6 +321,42 @@ static inline void free_conversion_context(struct conversion_context *pool) free(entry); } +struct wine_semaphore +{ + VkSemaphore semaphore; + VkSemaphore fence_timeline_semaphore; + + VkExternalSemaphoreHandleTypeFlagBits export_types; + + struct wine_vk_mapping mapping; + + /* mutable members */ + VkExternalSemaphoreHandleTypeFlagBits handle_type; + HANDLE handle; + struct + { + pthread_mutex_t mutex; + uint64_t virtual_value; + } *d3d12_fence_shm; +}; + +static inline struct wine_semaphore *wine_semaphore_from_handle(VkSemaphore handle) +{ + return (struct wine_semaphore *)(uintptr_t)handle; +} + +static inline VkSemaphore wine_semaphore_to_handle(struct wine_semaphore *semaphore) +{ + return (VkSemaphore)(uintptr_t)semaphore; +} + +static inline VkSemaphore wine_semaphore_host_handle(struct wine_semaphore *semaphore) +{ + if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + return semaphore->fence_timeline_semaphore; + return semaphore->semaphore; +} + static inline void *conversion_context_alloc(struct conversion_context *pool, size_t size) { if (pool->used + size <= sizeof(pool->buffer)) @@ -386,4 +422,7 @@ static inline void init_unicode_string( UNICODE_STRING *str, const WCHAR *data ) str->Buffer = (WCHAR *)data; } +#define MEMDUP(ctx, dst, src, count) dst = conversion_context_alloc(ctx, sizeof(*dst) * count); \ + memcpy((void *)dst, src, sizeof(*dst) * count); + #endif /* __WINE_VULKAN_PRIVATE_H */ From 6d2a0863d60e67825a30c7e735b68e5c01f48fb3 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Thu, 14 Jul 2022 16:40:17 -0400 Subject: [PATCH 0725/2777] winevulkan: Implement vkWaitForFences and vkSignalSemaphore for D3D12-Fence compatible timeline semaphores. --- dlls/winevulkan/vulkan.c | 276 ++++++++++++++++++++++++++++++- dlls/winevulkan/vulkan_private.h | 20 ++- 2 files changed, 289 insertions(+), 7 deletions(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 957aee7f940..e59d9dfcf98 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include #include "ntstatus.h" #define WIN32_NO_STATUS @@ -3590,6 +3593,108 @@ static void d3d12_semaphore_unlock(struct wine_semaphore *semaphore) pthread_mutex_unlock(&semaphore->d3d12_fence_shm->mutex); } +/* returns -1 when there is no queued update that would satisfy the wait */ +static uint64_t d3d12_semaphore_try_get_wait_value_locked(struct wine_semaphore *semaphore, uint64_t virtual_value, + struct VkQueue_T *waiting_queue) +{ + struct pending_update *update; + uint64_t ret = -1; + unsigned int i; + + if (semaphore->d3d12_fence_shm->virtual_value >= virtual_value) + return 0; + + return ret; +} + +static struct pending_wait *d3d12_semaphore_push_wait_locked(struct wine_semaphore *semaphore, uint64_t virtual_value) +{ + struct pending_wait *wait; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(semaphore->d3d12_fence_shm->pending_waits); i++) + { + wait = &semaphore->d3d12_fence_shm->pending_waits[i]; + if (!wait->present) + break; + } + + if (i == ARRAY_SIZE(semaphore->d3d12_fence_shm->pending_waits)) + { + FIXME("Failed to wait on semaphore %p, maximum waits exceeded.\n", semaphore); + return NULL; + } + + wait->present = true; + wait->satisfied = false; + wait->virtual_value = virtual_value; + wait->physical_value = 0; + + return wait; +} + +static uint64_t d3d12_semaphore_pop_wait_locked(struct wine_semaphore *semaphore, struct pending_wait *wait) +{ + wait->satisfied = false; + wait->present = false; + + return wait->physical_value; +} + +static void d3d12_semaphore_satisfy_waits_locked(struct wine_semaphore *semaphore, uint64_t virtual_value, + uint64_t physical_value) +{ + struct pending_wait *wait; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(semaphore->d3d12_fence_shm->pending_waits); i++) + { + wait = &semaphore->d3d12_fence_shm->pending_waits[i]; + + if (wait->present && !wait->satisfied && wait->virtual_value <= virtual_value) + { + wait->satisfied = true; + wait->physical_value = physical_value; + pthread_cond_signal(&wait->cond); + } + } +} + +static bool d3d12_semaphore_pop_pending_signal_locked(struct wine_semaphore *semaphore, uint64_t phys_val, struct pending_update *ret) +{ + struct pending_update *update; + unsigned int i; + + for (i = 0; i < semaphore->d3d12_fence_shm->pending_updates_count; i++) + { + if (semaphore->d3d12_fence_shm->pending_updates[i].physical_value == phys_val) + { + update = &semaphore->d3d12_fence_shm->pending_updates[i]; + if (ret) + *ret = *update; + *update = semaphore->d3d12_fence_shm->pending_updates[--semaphore->d3d12_fence_shm->pending_updates_count]; + return true; + } + } + + return false; +} + +static void d3d12_semaphore_update_phys_val_locked(struct wine_semaphore *sem, uint64_t phys_val) +{ + struct pending_update pending; + + /* Based off linked VKD3D-Proton implementation, but we don't signal CPU waits here. + * https://github.com/HansKristian-Work/vkd3d-proton/blob/829ac72e3d381006a843c183e613e8ee77e0b292/libs/vkd3d/command.c#L758 */ + while (sem->d3d12_fence_shm->physical_value < phys_val) + { + sem->d3d12_fence_shm->physical_value++; + + if (d3d12_semaphore_pop_pending_signal_locked(sem, sem->d3d12_fence_shm->physical_value, &pending)) + sem->d3d12_fence_shm->virtual_value = pending.virtual_value; + } +} + VkResult wine_vkCreateSemaphore(VkDevice device_handle, const VkSemaphoreCreateInfo *create_info, const VkAllocationCallbacks *allocator, VkSemaphore *semaphore, void *win_create_info) { @@ -3602,9 +3707,11 @@ VkResult wine_vkCreateSemaphore(VkDevice device_handle, const VkSemaphoreCreateI VkSemaphoreGetFdInfoKHR fd_info; pthread_mutexattr_t mutex_attr; struct wine_semaphore *object; + pthread_condattr_t cond_attr; OBJECT_ATTRIBUTES attr; HANDLE section_handle; LARGE_INTEGER li; + unsigned int i; VkResult res; SIZE_T size; int fd; @@ -3726,6 +3833,14 @@ VkResult wine_vkCreateSemaphore(VkDevice device_handle, const VkSemaphoreCreateI } pthread_mutexattr_destroy(&mutex_attr); + for (i = 0; i < ARRAY_SIZE(object->d3d12_fence_shm->pending_waits); i++) + { + pthread_condattr_init(&cond_attr); + pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED); + pthread_cond_init(&object->d3d12_fence_shm->pending_waits[i].cond, &cond_attr); + pthread_condattr_destroy(&cond_attr); + } + WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance, object, object->fence_timeline_semaphore, object); } if (object->fence_timeline_semaphore == VK_NULL_HANDLE) @@ -3977,14 +4092,41 @@ static VkResult vk_signal_semaphore(VkDevice device_handle, const VkSemaphoreSig static NTSTATUS wine_vk_signal_semaphore(VkDevice device, const VkSemaphoreSignalInfo *signal_info, bool khr) { + uint64_t phys_val; + VkResult vr; + struct wine_semaphore *semaphore = wine_semaphore_from_handle(signal_info->semaphore); TRACE("(%p, %p)\n", device, signal_info); if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) { - FIXME("Signalling D3D12-Fence compatible timeline semaphore not supported.\n"); - return VK_ERROR_OUT_OF_HOST_MEMORY; + VkSemaphoreSignalInfo step_signal_info; + + d3d12_semaphore_lock(semaphore); + + assert(semaphore->d3d12_fence_shm->counter == phys_val); + phys_val++; + + semaphore->d3d12_fence_shm->counter = semaphore->d3d12_fence_shm->physical_value = phys_val; + + step_signal_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO; + step_signal_info.pNext = NULL; + step_signal_info.semaphore = signal_info->semaphore; + step_signal_info.value = phys_val; + + vr = vk_signal_semaphore(device, &step_signal_info, khr); + if (vr != VK_SUCCESS) + { + d3d12_semaphore_unlock(semaphore); + return vr; + } + + d3d12_semaphore_satisfy_waits_locked(semaphore, signal_info->value, 0); + semaphore->d3d12_fence_shm->virtual_value = signal_info->value; + + d3d12_semaphore_unlock(semaphore); + return VK_SUCCESS; } return vk_signal_semaphore(device, signal_info, khr); @@ -4032,21 +4174,143 @@ static VkResult vk_wait_semaphores(struct wine_device *device, const VkSemaphore static VkResult wine_vk_wait_semaphores(VkDevice device_handle, const VkSemaphoreWaitInfo *wait_info, uint64_t timeout, bool khr) { - unsigned int i; + VkSemaphoreWaitInfo wait_info_dup = *wait_info; + struct timespec abs_timeout, start_time; + struct pending_wait **pending_waits; + struct pending_wait *pending_wait; + unsigned int i, remaining_waits; + VkSemaphore* semaphores_dup; + uint64_t *values_dup; + uint64_t phys_val; + int wait_stat; + VkResult res; TRACE("(%p, %p, 0x%s)\n", device_handle, wait_info, wine_dbgstr_longlong(timeout)); + if (timeout) + { + clock_gettime(CLOCK_REALTIME, &start_time); + + abs_timeout.tv_sec = start_time.tv_sec + (timeout / NANOSECONDS_IN_A_SECOND); + abs_timeout.tv_nsec = start_time.tv_nsec + (timeout % NANOSECONDS_IN_A_SECOND); + if (abs_timeout.tv_nsec >= NANOSECONDS_IN_A_SECOND) + { + abs_timeout.tv_sec++; + abs_timeout.tv_nsec-=NANOSECONDS_IN_A_SECOND; + } + } + + wait_info_dup.pSemaphores = semaphores_dup = calloc(wait_info->semaphoreCount, sizeof(VkSemaphore)); + wait_info_dup.pValues = values_dup = calloc(wait_info->semaphoreCount, sizeof(uint64_t)); + pending_waits = calloc(wait_info->semaphoreCount, sizeof(struct pending_wait *)); + for (i = 0; i < wait_info->semaphoreCount; i++) { struct wine_semaphore *semaphore = wine_semaphore_from_handle(wait_info->pSemaphores[i]); + semaphores_dup[i] = wait_info->pSemaphores[i]; + values_dup[i] = wait_info->pValues[i]; + if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) { - FIXME("Waiting on D3D12-Fence compatible timeline semaphores not supported."); - return VK_ERROR_OUT_OF_HOST_MEMORY; + d3d12_semaphore_lock(semaphore); + if ((values_dup[i] = d3d12_semaphore_try_get_wait_value_locked(semaphore, wait_info->pValues[i], NULL)) == -1) + { + if (!timeout) + { + d3d12_semaphore_unlock(semaphore); + continue; + } + + pending_wait = d3d12_semaphore_push_wait_locked(semaphore, wait_info->pValues[i]); + + if (wait_info->flags & VK_SEMAPHORE_WAIT_ANY_BIT) + { + /* Keep scheduling a wait of current physical_value+1 until the desired virtual value is signaled */ + values_dup[i] = semaphore->d3d12_fence_shm->physical_value + 1; + pending_waits[i] = pending_wait; + } + else + { + while (!pending_wait->satisfied && wait_stat != ETIMEDOUT) + wait_stat = pthread_cond_timedwait(&pending_wait->cond, &semaphore->d3d12_fence_shm->mutex, &abs_timeout); + + values_dup[i] = d3d12_semaphore_pop_wait_locked(semaphore, pending_wait); + + if (wait_stat == ETIMEDOUT) + { + d3d12_semaphore_unlock(semaphore); + free(semaphores_dup); + free(values_dup); + free(pending_waits); + return VK_TIMEOUT; + } + } + } + d3d12_semaphore_unlock(semaphore); + } + } + do + { + if (timeout) + { + clock_gettime(CLOCK_REALTIME, &start_time); + + if (start_time.tv_sec > abs_timeout.tv_sec || + (start_time.tv_sec == abs_timeout.tv_sec && start_time.tv_nsec >= abs_timeout.tv_nsec)) + timeout = 0; + else + timeout = ((abs_timeout.tv_sec - start_time.tv_sec) * NANOSECONDS_IN_A_SECOND) + + (abs_timeout.tv_nsec - start_time.tv_nsec); + } + + remaining_waits = 0; + res = vk_wait_semaphores(wine_device_from_handle(device_handle), &wait_info_dup, timeout, khr); + + for (i = 0; i < wait_info->semaphoreCount; i++) + { + struct wine_semaphore * semaphore = wine_semaphore_from_handle(wait_info->pSemaphores[i]); + + if (pending_waits[i]) + { + remaining_waits++; + + d3d12_semaphore_lock(semaphore); + if (res != VK_SUCCESS || pending_waits[i]->satisfied) + { + values_dup[i] = pending_waits[i]->physical_value; + d3d12_semaphore_pop_wait_locked(semaphore, pending_waits[i]); + pending_waits[i] = NULL; + } + d3d12_semaphore_unlock(semaphore); + } } } - return vk_wait_semaphores(wine_device_from_handle(device_handle), wait_info, timeout, khr); + while (res == VK_SUCCESS && remaining_waits); + + /* Make sure the physical value we waited on is processed before returning */ + for (i = 0; i < wait_info_dup.semaphoreCount; i++) + { + struct wine_semaphore *semaphore = wine_semaphore_from_handle(wait_info_dup.pSemaphores[i]); + + if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + { + d3d12_semaphore_lock(semaphore); + if (wait_info->flags & VK_SEMAPHORE_WAIT_ANY_BIT) + { + if (!vk_get_semaphore_counter_value(device_handle, semaphores_dup[i], &phys_val, khr)) + d3d12_semaphore_update_phys_val_locked(semaphore, phys_val); + } + else + d3d12_semaphore_update_phys_val_locked(semaphore, values_dup[i]); + d3d12_semaphore_unlock(semaphore); + } + } + + free(semaphores_dup); + free(values_dup); + free(pending_waits); + return res; } VkResult wine_vkWaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo *wait_info, uint64_t timeout) diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 0e7a159e934..db22b0df890 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -24,6 +24,7 @@ #define VK_NO_PROTOTYPES #include +#include #include "vulkan_loader.h" #include "vulkan_thunks.h" @@ -336,7 +337,24 @@ struct wine_semaphore struct { pthread_mutex_t mutex; - uint64_t virtual_value; + uint64_t virtual_value, physical_value, counter; + + struct pending_wait + { + bool present, satisfied; + uint64_t virtual_value; + uint64_t physical_value; + pthread_cond_t cond; + } pending_waits[100]; + + struct pending_update + { + uint64_t virtual_value; + uint64_t physical_value; + pid_t signalling_pid; + struct wine_queue *signalling_queue; + } pending_updates[100]; + uint32_t pending_updates_count; } *d3d12_fence_shm; }; From ac20bc2ef828f9347d0308ac7ae19cf8e884c59a Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 15 Jul 2022 11:35:28 -0400 Subject: [PATCH 0726/2777] winevulkan: Support waiting for and signalling D3D12-Fence style timeline semaphores in Vulkan Queues. --- dlls/winevulkan/make_vulkan | 52 ++- dlls/winevulkan/vulkan.c | 691 +++++++++++++++++++++++++++++-- dlls/winevulkan/vulkan_private.h | 18 + 3 files changed, 711 insertions(+), 50 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index a3fde3ef48f..1df70450312 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -218,8 +218,9 @@ FUNCTION_OVERRIDES = { "vkSignalSemaphore" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, "vkWaitSemaphores" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, "vkQueueBindSparse" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, - "vkQueueSubmit" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, + "vkQueueSubmit" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE, "extra_param" : "pSubmits"}, "vkQueueSubmit2" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, + "vkQueueWaitIdle" : {"dispatch": True, "driver": False, "thunk" : ThunkType.NONE}, # VK_KHR_surface "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE}, @@ -305,11 +306,16 @@ STRUCT_CHAIN_CONVERSIONS = { "VkPhysicalDeviceImageFormatInfo2": [], "VkPhysicalDeviceExternalSemaphoreInfo": [], "VkSemaphoreCreateInfo": ["VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR"], - "VkSubmitInfo": [], + "VkSubmitInfo": ["VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR"], "VkSubmitInfo2": [], "VkBindSparseInfo" : [], } +STRUCT_COPY = { + "VkSubmitInfo", + "VkSubmitInfo2", +}; + # Some struct members are conditionally ignored and callers are free to leave them uninitialized. # We can't deduce that from XML, so we allow expressing it here. MEMBER_LENGTH_EXPRESSIONS = { @@ -1361,6 +1367,9 @@ class VkVariable(object): if struct.needs_conversion(conv, unwrap, Direction.OUTPUT, is_const): conversions.append(StructConversionFunction(struct, Direction.OUTPUT, conv, unwrap, is_const)) + if struct.name in STRUCT_COPY: + conversions.append(StructConversionFunction(struct, Direction.INPUT, False, unwrap, is_const, True)) + if self.is_static_array() or self.is_dynamic_array(): for conv in [False, True]: if self.needs_conversion(conv, unwrap, Direction.INPUT, parent_const): @@ -1487,7 +1496,7 @@ class VkMember(VkVariable): values=values, object_type=object_type, bit_width=bit_width, returnedonly=returnedonly, parent=parent, selection=selection, selector=selector) - def copy(self, input, output, direction, conv, unwrap): + def copy(self, input, output, direction, conv, unwrap, copy): """ Helper method for use by conversion logic to generate a C-code statement to copy this member. - `conv` indicates whether the statement is in a struct alignment conversion path. """ @@ -1545,6 +1554,8 @@ class VkMember(VkVariable): elif self.is_static_array(): bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type) return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count) + elif self.is_dynamic_array() and copy: + return "MEMDUP(ctx, {0}{1}, {2}{1}, {3});\n".format(output, self.name, input, self.get_dyn_array_len(input, conv)) elif direction == Direction.INPUT: return "{0}{1} = {2};\n".format(output, self.name, self.value(input, conv)) elif conv and direction == Direction.OUTPUT and self.is_pointer(): @@ -2260,21 +2271,25 @@ class VkStruct(Sequence): class StructConversionFunction(object): - def __init__(self, struct, direction, conv, unwrap, const): + def __init__(self, struct, direction, conv, unwrap, const, copy=False): self.direction = direction self.operand = struct self.type = struct.name self.conv = conv self.unwrap = unwrap or not self.operand.needs_unwrapping() self.const = const + self.copy = copy - name = "convert_{0}_".format(self.type) - win_type = "win32" if self.conv else "win64" - host_part = "host" if self.unwrap else "unwrapped_host" - if self.direction == Direction.INPUT: - name += "{0}_to_{1}".format(win_type, host_part) - else: # Direction.OUTPUT - name += "{0}_to_{1}".format(host_part, win_type) + if copy: + name = "copy_{0}".format(self.type) + else: + name = "convert_{0}_".format(self.type) + win_type = "win32" if self.conv else "win64" + host_part = "host" if self.unwrap else "unwrapped_host" + if self.direction == Direction.INPUT: + name += "{0}_to_{1}".format(win_type, host_part) + else: # Direction.OUTPUT + name += "{0}_to_{1}".format(host_part, win_type) self.name = name def __eq__(self, other): @@ -2306,7 +2321,7 @@ class StructConversionFunction(object): body = "" - if not self.conv: + if not self.conv and not self.copy: body += "#ifdef _WIN64\n" needs_alloc = self.direction != Direction.OUTPUT and self.operand.needs_alloc(self.conv, self.unwrap) @@ -2316,8 +2331,11 @@ class StructConversionFunction(object): if self.direction == Direction.OUTPUT and self.const: win_type = "const " + win_type - if self.conv: + if self.copy: + body += "void {0}(".format(self.name) + else: body += "static inline void {0}(".format(self.name) + if self.conv: if self.direction == Direction.OUTPUT: params = ["const {0} *in".format(self.type), "{0} *out".format(win_type)] @@ -2334,8 +2352,6 @@ class StructConversionFunction(object): body += ")\n" else: - body += "static inline void {0}(".format(self.name) - params = ["const {0} *in".format(self.type), "{0} *out".format(self.type)] # Generate parameter list @@ -2375,7 +2391,7 @@ class StructConversionFunction(object): body += " || ".join("selector == {}".format(s) for s in m.selection) body += ")\n " - body += " " + m.copy("in->", "out->", self.direction, self.conv, self.unwrap) + body += " " + m.copy("in->", "out->", self.direction, self.conv, self.unwrap, self.copy) if needs_extensions: if self.conv and self.direction == Direction.INPUT: @@ -2435,7 +2451,7 @@ class StructConversionFunction(object): copy_body += ident + "out_ext->pNext = NULL;\n" continue - copy_body += ident + m.copy("in_ext->", "out_ext->", self.direction, self.conv, True) + copy_body += ident + m.copy("in_ext->", "out_ext->", self.direction, self.conv, True, self.copy) # Generate the definition of "in_ext" if we need it if "in_ext->" in copy_body: @@ -2470,7 +2486,7 @@ class StructConversionFunction(object): body += " FIXME(\"Unexpected pNext\\n\");\n" body += "}\n" - if not self.conv: + if not self.conv and not self.copy: body += "#endif /* _WIN64 */\n" body += "\n" diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index e59d9dfcf98..e41eb3376f9 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -36,6 +36,7 @@ #include "winnt.h" #include "winioctl.h" #include "wine/server.h" +#include "wine/list.h" #include "vulkan_private.h" #include "wine/vulkan_driver.h" @@ -242,6 +243,7 @@ static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance struct wine_phys_dev *object; uint32_t num_host_properties, num_properties = 0; VkExtensionProperties *host_properties = NULL; + VkPhysicalDeviceProperties physdev_properties; BOOL have_external_memory_host = FALSE; VkResult res; unsigned int i, j; @@ -253,6 +255,9 @@ static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance object->handle = handle; object->phys_dev = phys_dev; + instance->funcs.p_vkGetPhysicalDeviceProperties(phys_dev, &physdev_properties); + object->api_version = physdev_properties.apiVersion; + handle->base.unix_handle = (uintptr_t)object; WINE_VK_ADD_DISPATCHABLE_MAPPING(instance, handle, phys_dev, object); @@ -397,6 +402,14 @@ static void wine_vk_device_get_queues(struct wine_device *device, queue->queue_index = i; queue->flags = flags; + pthread_mutex_init(&queue->submissions_mutex, NULL); + pthread_cond_init(&queue->submissions_cond, NULL); + list_init(&queue->submissions); + + pthread_mutex_init(&queue->signaller_mutex, NULL); + pthread_cond_init(&queue->signaller_cond, NULL); + list_init(&queue->signal_ops); + /* The Vulkan spec says: * * "vkGetDeviceQueue must only be used to get queues that were created @@ -566,6 +579,11 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de return VK_SUCCESS; } +static bool is_virtual_queue(struct wine_queue *queue) +{ + return __atomic_load_n(&queue->virtual_queue, __ATOMIC_ACQUIRE); +} + /* Helper function used for freeing a device structure. This function supports full * and partial object cleanups and can thus be used for vkCreateDevice failures. */ @@ -582,6 +600,28 @@ static void wine_vk_device_free(struct wine_device *device) for (i = 0; i < device->queue_count; i++) { queue = &device->queues[i]; + + if (is_virtual_queue(queue)) + { + pthread_mutex_lock(&queue->submissions_mutex); + pthread_mutex_lock(&queue->signaller_mutex); + queue->stop = 1; + pthread_mutex_unlock(&queue->submissions_mutex); + pthread_mutex_unlock(&queue->signaller_mutex); + + pthread_cond_signal(&queue->submissions_cond); + pthread_cond_signal(&queue->signaller_cond); + + pthread_join(queue->virtual_queue_thread, NULL); + pthread_join(queue->signal_thread, NULL); + } + + pthread_mutex_destroy(&queue->submissions_mutex); + pthread_mutex_destroy(&queue->signaller_mutex); + + pthread_cond_destroy(&queue->submissions_cond); + pthread_cond_destroy(&queue->signaller_cond); + if (queue && queue->queue) WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, queue); } @@ -1057,6 +1097,8 @@ VkResult wine_vkCreateInstance(const VkInstanceCreateInfo *create_info, app_info->engineVersion); TRACE("API version %#x.\n", app_info->apiVersion); + object->api_version = app_info->apiVersion; + if (app_info->pEngineName && !strcmp(app_info->pEngineName, "idTech")) object->quirks |= WINEVULKAN_QUIRK_GET_DEVICE_PROC_ADDR; } @@ -3595,7 +3637,7 @@ static void d3d12_semaphore_unlock(struct wine_semaphore *semaphore) /* returns -1 when there is no queued update that would satisfy the wait */ static uint64_t d3d12_semaphore_try_get_wait_value_locked(struct wine_semaphore *semaphore, uint64_t virtual_value, - struct VkQueue_T *waiting_queue) + struct wine_queue *waiting_queue) { struct pending_update *update; uint64_t ret = -1; @@ -3604,6 +3646,19 @@ static uint64_t d3d12_semaphore_try_get_wait_value_locked(struct wine_semaphore if (semaphore->d3d12_fence_shm->virtual_value >= virtual_value) return 0; + for (i = 0; i < semaphore->d3d12_fence_shm->pending_updates_count; i++) + { + update = &semaphore->d3d12_fence_shm->pending_updates[i]; + + if (update->virtual_value < virtual_value) + continue; + + if (update->signalling_pid == getpid() && waiting_queue && update->signalling_queue == waiting_queue) + return 0; + + ret = min(ret, update->physical_value); + } + return ret; } @@ -3660,6 +3715,34 @@ static void d3d12_semaphore_satisfy_waits_locked(struct wine_semaphore *semaphor } } +static uint64_t d3d12_semaphore_add_pending_signal_locked(struct wine_semaphore *semaphore, uint64_t virtual_value, + struct wine_queue *signalling_queue) +{ + struct pending_update *update; + + if (semaphore->d3d12_fence_shm->pending_updates_count == ARRAY_SIZE(semaphore->d3d12_fence_shm->pending_updates)) + { + /* Called from Unix thread, can't use Wine traces. */ + fprintf(stderr, "winevulkan/d3d12_semaphore_add_pending_signal_locked: maximum concurrent signals exceeded.\n"); + return 0; + } + + update = &semaphore->d3d12_fence_shm->pending_updates[ + semaphore->d3d12_fence_shm->pending_updates_count++]; + + update->virtual_value = virtual_value; + update->physical_value = ++semaphore->d3d12_fence_shm->counter; + update->signalling_pid = getpid(); + update->signalling_queue = signalling_queue; + + return update->physical_value; +} + +static struct pending_update d3d12_semaphore_peek_added_signal_locked(struct wine_semaphore *semaphore) +{ + return semaphore->d3d12_fence_shm->pending_updates[semaphore->d3d12_fence_shm->pending_updates_count - 1]; +} + static bool d3d12_semaphore_pop_pending_signal_locked(struct wine_semaphore *semaphore, uint64_t phys_val, struct pending_update *ret) { struct pending_update *update; @@ -4101,27 +4184,41 @@ static NTSTATUS wine_vk_signal_semaphore(VkDevice device, const VkSemaphoreSigna if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) { - VkSemaphoreSignalInfo step_signal_info; - d3d12_semaphore_lock(semaphore); - assert(semaphore->d3d12_fence_shm->counter == phys_val); - phys_val++; - - semaphore->d3d12_fence_shm->counter = semaphore->d3d12_fence_shm->physical_value = phys_val; - - step_signal_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO; - step_signal_info.pNext = NULL; - step_signal_info.semaphore = signal_info->semaphore; - step_signal_info.value = phys_val; - - vr = vk_signal_semaphore(device, &step_signal_info, khr); - if (vr != VK_SUCCESS) + /* vkWaitSemaphore w/ WAIT_ANY wakes on every physical value increment to check if the wait is satisfied, so + if there are no scheduled signals, step the physical value */ + if ((vr = vk_get_semaphore_counter_value(device, signal_info->semaphore, &phys_val, khr)) != VK_SUCCESS) { d3d12_semaphore_unlock(semaphore); return vr; } + d3d12_semaphore_update_phys_val_locked(semaphore, phys_val); + + if (!semaphore->d3d12_fence_shm->pending_updates_count) + { + VkSemaphoreSignalInfo step_signal_info; + + assert(semaphore->d3d12_fence_shm->counter == phys_val); + phys_val++; + + semaphore->d3d12_fence_shm->counter = semaphore->d3d12_fence_shm->physical_value = phys_val; + + step_signal_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO; + step_signal_info.pNext = NULL; + step_signal_info.semaphore = signal_info->semaphore; + step_signal_info.value = phys_val; + + vr = vk_signal_semaphore(device, &step_signal_info, khr); + if (vr != VK_SUCCESS) + { + d3d12_semaphore_unlock(semaphore); + return vr; + } + } + + /* If a queue is already waiting on the pending physical value of a previous submit, this won't wake it up. */ d3d12_semaphore_satisfy_waits_locked(semaphore, signal_info->value, 0); semaphore->d3d12_fence_shm->virtual_value = signal_info->value; @@ -4351,33 +4448,460 @@ VkResult vk_queue_submit_unwrap(struct wine_queue *queue, uint32_t submit_count, return ret; } -VkResult wine_vkQueueSubmit(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo *submits, VkFence fence) +struct signal_op +{ + enum + { + SIGNAL_TYPE_SEMAPHORE, + } signal_type; + + union + { + struct + { + struct wine_semaphore *obj; + uint64_t phys_val; + + bool khr; + } semaphore; + }; + + struct list entry; +}; + +static void *queue_signaller_worker(void *arg) +{ + struct wine_queue *queue = arg; + VkSemaphoreWaitInfo wait_info; + struct signal_op *signal_op; + VkSemaphore sem_handle; + bool device_lost; + VkResult vr; + + for (;;) + { + pthread_mutex_lock(&queue->signaller_mutex); + + while (!queue->stop && list_empty(&queue->signal_ops)) + pthread_cond_wait(&queue->signaller_cond, &queue->signaller_mutex); + + if (queue->stop) + { + assert( list_empty(&queue->signal_ops) ); + pthread_mutex_unlock(&queue->signaller_mutex); + return NULL; + } + + signal_op = LIST_ENTRY(list_head(&queue->signal_ops), struct signal_op, entry); + list_remove(&signal_op->entry); + + device_lost = queue->device_lost; + + pthread_mutex_unlock(&queue->signaller_mutex); + + if (signal_op->signal_type == SIGNAL_TYPE_SEMAPHORE) + { + wait_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO; + wait_info.pNext = NULL; + wait_info.flags = 0; + wait_info.semaphoreCount = 1; + sem_handle = wine_semaphore_to_handle(signal_op->semaphore.obj); + wait_info.pSemaphores = &sem_handle; + wait_info.pValues = &signal_op->semaphore.phys_val; + if (!device_lost && (vr = vk_wait_semaphores(queue->device, &wait_info, -1, signal_op->semaphore.khr)) < 0) + { + /* likely GPU hang */ + fprintf(stderr, "winevulkan/queue_signaller_worker: Semaphore wait failed, vr %d.\n", vr); + continue; + } + + d3d12_semaphore_lock(signal_op->semaphore.obj); + d3d12_semaphore_update_phys_val_locked(signal_op->semaphore.obj, signal_op->semaphore.phys_val); + d3d12_semaphore_unlock(signal_op->semaphore.obj); + } + + free(signal_op); + } + + return NULL; +} + +struct struct_chain_def +{ + VkStructureType sType; + unsigned int size; +}; + +void copy_VkSubmitInfo(struct conversion_context *ctx, const VkSubmitInfo *in, VkSubmitInfo *out); +static VkSubmitInfo *copy_VkSubmitInfo_array(struct conversion_context *ctx, const VkSubmitInfo *in, uint32_t submit_count) +{ + VkSubmitInfo *out = conversion_context_alloc(ctx, sizeof(*out) * submit_count); + unsigned int i; + + for (i = 0; i < submit_count; i++) + copy_VkSubmitInfo(ctx, &in[i], &out[i]); + return out; +} + +void copy_VkSubmitInfo2(struct conversion_context *ctx, const VkSubmitInfo2 *in, VkSubmitInfo2 *out); +static VkSubmitInfo2 *copy_VkSubmitInfo2_array(struct conversion_context *ctx, const VkSubmitInfo2 *in, uint32_t submit_count) +{ + VkSubmitInfo2 *out = conversion_context_alloc(ctx, sizeof(*out) * submit_count); + unsigned int i; + + for (i = 0; i < submit_count; i++) + copy_VkSubmitInfo2(ctx, &in[i], &out[i]); + return out; +} + +struct queue_submit_unit +{ + uint32_t submit_count; + VkSubmitInfo *submits; + VkSubmitInfo2 *submits2; + VkFence fence; + bool khr; + + struct pending_wait **waits; + + struct list entry; + struct conversion_context ctx; +}; + +/* Abstracts away the differences between VkSubmitInfo and VkSubmitInfo2. */ +static bool for_each_d3d12_semaphore(struct queue_submit_unit *unit, bool signal, + struct wine_semaphore **semaphore_out, uint64_t **value_out, uint32_t counter) +{ + VkTimelineSemaphoreSubmitInfo *timeline_values; + struct wine_semaphore *semaphore; + unsigned int i, j, k; + uint32_t sem_count; + + for (i = 0, k = 0; i < unit->submit_count; i++) + { + if (unit->submits) + { + timeline_values = wine_vk_find_struct(&unit->submits[i], TIMELINE_SEMAPHORE_SUBMIT_INFO); + + if (signal) + sem_count = unit->submits[i].signalSemaphoreCount; + else + sem_count = unit->submits[i].waitSemaphoreCount; + + for (j = 0; j < sem_count; j++) + { + if (signal) + semaphore = wine_semaphore_from_handle(unit->submits[i].pSignalSemaphores[j]); + else + semaphore = wine_semaphore_from_handle(unit->submits[i].pWaitSemaphores[j]); + + if (semaphore->handle_type != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + continue; + + if (k++ == counter) + { + *semaphore_out = semaphore; + if (signal) + *value_out = (uint64_t *) &timeline_values->pSignalSemaphoreValues[j]; + else + *value_out = (uint64_t *) &timeline_values->pWaitSemaphoreValues[j]; + return true; + } + } + } + else + { + if (signal) + sem_count = unit->submits2[i].signalSemaphoreInfoCount; + else + sem_count = unit->submits2[i].waitSemaphoreInfoCount; + + for (j = 0; j < sem_count; j++) + { + if (signal) + semaphore = wine_semaphore_from_handle(unit->submits2[i].pSignalSemaphoreInfos[j].semaphore); + else + semaphore = wine_semaphore_from_handle(unit->submits2[i].pWaitSemaphoreInfos[j].semaphore); + + if (semaphore->handle_type != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + continue; + + if (k++ == counter) + { + *semaphore_out = semaphore; + if (signal) + *value_out = (uint64_t *) &unit->submits2[i].pSignalSemaphoreInfos[j].value; + else + *value_out = (uint64_t *) &unit->submits2[i].pWaitSemaphoreInfos[j].value; + return true; + } + } + } + } + + return false; +} + +VkResult vk_queue_submit_2_unwrap(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence, bool khr); + +static void *virtual_queue_worker(void *arg) +{ + struct wine_queue *queue = (struct wine_queue *)arg; + struct queue_submit_unit *submit_unit; + struct signal_op *signal_op; + struct wine_semaphore *sem; + struct pending_wait *wait; + bool device_lost = false; + uint64_t *timeline_value; + unsigned int i; + VkResult vr; + + for (;;) + { + pthread_mutex_lock(&queue->submissions_mutex); + + while (!queue->stop && list_empty(&queue->submissions)) + pthread_cond_wait(&queue->submissions_cond, &queue->submissions_mutex); + + if (queue->stop) + { + assert( list_empty(&queue->submissions) ); + pthread_mutex_unlock(&queue->submissions_mutex); + return NULL; + } + + submit_unit = LIST_ENTRY(list_head(&queue->submissions), struct queue_submit_unit, entry); + list_remove(&submit_unit->entry); + + pthread_mutex_unlock(&queue->submissions_mutex); + + if (device_lost) + goto free_submit_unit; + + /* Wait for all fences to have a pending signal */ + for (i = 0; for_each_d3d12_semaphore(submit_unit, false, &sem, &timeline_value, i); i++) + { + if ((wait = submit_unit->waits[i++])) + { + assert(wait); + d3d12_semaphore_lock(sem); + + while (!wait->satisfied) + pthread_cond_wait(&wait->cond, &sem->d3d12_fence_shm->mutex); + + *timeline_value = d3d12_semaphore_pop_wait_locked(sem, wait); + + d3d12_semaphore_unlock(sem); + } + } + + for (i = 0; for_each_d3d12_semaphore(submit_unit, true, &sem, &timeline_value, i); i++) + { + d3d12_semaphore_lock(sem); + + *timeline_value = d3d12_semaphore_add_pending_signal_locked(sem, *timeline_value, queue); + } + + if (submit_unit->submits) + vr = vk_queue_submit_unwrap(queue, submit_unit->submit_count, submit_unit->submits, VK_NULL_HANDLE); + else + vr = vk_queue_submit_2_unwrap(queue, submit_unit->submit_count, submit_unit->submits2, + VK_NULL_HANDLE, submit_unit->khr); + + pthread_mutex_lock(&queue->signaller_mutex); + + for (i = 0; for_each_d3d12_semaphore(submit_unit, true, &sem, &timeline_value, i); i++) + { + if (vr == VK_SUCCESS) + { + struct pending_update added_signal = d3d12_semaphore_peek_added_signal_locked(sem); + d3d12_semaphore_satisfy_waits_locked(sem, added_signal.virtual_value, added_signal.physical_value); + + signal_op = malloc(sizeof(*signal_op)); + signal_op->signal_type = SIGNAL_TYPE_SEMAPHORE; + signal_op->semaphore.obj = sem; + signal_op->semaphore.phys_val = added_signal.physical_value; + signal_op->semaphore.khr = submit_unit->khr; + + list_add_tail(&queue->signal_ops, &signal_op->entry); + } + else + { + d3d12_semaphore_pop_pending_signal_locked(sem, *timeline_value, NULL); + } + + d3d12_semaphore_unlock(sem); + } + + pthread_cond_signal(&queue->signaller_cond); + pthread_mutex_unlock(&queue->signaller_mutex); + + if (vr != VK_SUCCESS) + { + fprintf(stderr, "winevulkan/virtual_queue_worker: queue submission failed with %d, treating as DEVICE_LOST.\n", vr); + pthread_mutex_lock(&queue->submissions_mutex); + queue->device_lost = device_lost = true; + pthread_mutex_unlock(&queue->submissions_mutex); + } + +free_submit_unit: + free_conversion_context(&submit_unit->ctx); + free(submit_unit->waits); + free(submit_unit); + + pthread_mutex_lock(&queue->submissions_mutex); + if (list_empty(&queue->submissions)) + { + queue->processing = false; + } + pthread_cond_signal(&queue->submissions_cond); + pthread_mutex_unlock(&queue->submissions_mutex); + } + + return NULL; +} + +static void init_virtual_queue(struct wine_queue *queue) +{ + if (is_virtual_queue(queue)) + return; + + pthread_mutex_lock(&queue->submissions_mutex); + + if (queue->virtual_queue) + { + pthread_mutex_unlock(&queue->submissions_mutex); + return; + } + + __atomic_store_n(&queue->virtual_queue, 1, __ATOMIC_RELEASE); + + pthread_create(&queue->virtual_queue_thread, NULL, virtual_queue_worker, queue); + pthread_create(&queue->signal_thread, NULL, queue_signaller_worker, queue); + + queue->virtual_queue = true; + + pthread_mutex_unlock(&queue->submissions_mutex); +} + +static NTSTATUS virtual_queue_submit(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo *submits, + VkFence fence, void *submits_win_ptr) +{ + VkTimelineSemaphoreSubmitInfo *timeline_submit_info, *host_timeline_values; + const VkSubmitInfo *submits_win = submits_win_ptr; + VkD3D12FenceSubmitInfoKHR *d3d12_submit_info; + struct queue_submit_unit *submit_unit; + struct wine_semaphore *sem; + unsigned int i, j, k; + uint64_t wait_value; + bool device_lost; + + if (fence != VK_NULL_HANDLE) + { + FIXME("Signalling fences in queue submissions involving D3D12-Fence compatible timeline semaphores not supported.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + init_virtual_queue(queue); + + pthread_mutex_lock(&queue->submissions_mutex); + device_lost = queue->device_lost; + pthread_mutex_unlock(&queue->submissions_mutex); + if (device_lost) + return VK_ERROR_DEVICE_LOST; + + submit_unit = malloc(sizeof(*submit_unit)); + init_conversion_context(&submit_unit->ctx); + submit_unit->submit_count = submit_count; + submit_unit->submits = copy_VkSubmitInfo_array(&submit_unit->ctx, submits, submit_count); + submit_unit->submits2 = NULL; + submit_unit->waits = NULL; + submit_unit->khr = queue->device->phys_dev->api_version < VK_API_VERSION_1_2 || + queue->device->phys_dev->instance->api_version < VK_API_VERSION_1_2; + + /* As D3D12 fences are rewindable, we add the wait synchronously as not to miss a temporarily signalled value + between vkQueueSubmit and processing the submit unit*/ + for (i = 0, k = 0; i < submit_count; i++) + { + timeline_submit_info = wine_vk_find_struct(&submits[i], TIMELINE_SEMAPHORE_SUBMIT_INFO); + d3d12_submit_info = wine_vk_find_struct(&submits_win[i], D3D12_FENCE_SUBMIT_INFO_KHR); + + host_timeline_values = wine_vk_find_struct(&submit_unit->submits[i], TIMELINE_SEMAPHORE_SUBMIT_INFO); + + if (d3d12_submit_info && !host_timeline_values) + { + host_timeline_values = conversion_context_alloc(&submit_unit->ctx, sizeof(*host_timeline_values)); + host_timeline_values->sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; + host_timeline_values->pNext = submit_unit->submits[i].pNext; + host_timeline_values->waitSemaphoreValueCount = d3d12_submit_info->waitSemaphoreValuesCount; + MEMDUP(&submit_unit->ctx, host_timeline_values->pWaitSemaphoreValues, d3d12_submit_info->pWaitSemaphoreValues, + d3d12_submit_info->waitSemaphoreValuesCount); + host_timeline_values->signalSemaphoreValueCount = d3d12_submit_info->signalSemaphoreValuesCount; + MEMDUP(&submit_unit->ctx, host_timeline_values->pSignalSemaphoreValues, d3d12_submit_info->pSignalSemaphoreValues, + d3d12_submit_info->signalSemaphoreValuesCount); + submit_unit->submits[i].pNext = host_timeline_values; + } + + for (j = 0; j < submits[i].waitSemaphoreCount; j++) + { + sem = wine_semaphore_from_handle(submits[i].pWaitSemaphores[j]); + + if (sem->handle_type != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + continue; + + if (timeline_submit_info) + wait_value = timeline_submit_info->pWaitSemaphoreValues[j]; + else + wait_value = d3d12_submit_info->pWaitSemaphoreValues[j]; + + submit_unit->waits = realloc(submit_unit->waits, (k + 1) * sizeof(*submit_unit->waits)); + submit_unit->waits[k] = NULL; + + d3d12_semaphore_lock(sem); + + if ((((uint64_t*)host_timeline_values->pWaitSemaphoreValues)[j] = + d3d12_semaphore_try_get_wait_value_locked(sem, wait_value, queue)) == -1) + submit_unit->waits[k] = d3d12_semaphore_push_wait_locked(sem, wait_value); + + d3d12_semaphore_unlock(sem); + k++; + } + } + + pthread_mutex_lock(&queue->submissions_mutex); + queue->processing = true; + list_add_tail(&queue->submissions, &submit_unit->entry); + pthread_cond_signal(&queue->submissions_cond); + pthread_mutex_unlock(&queue->submissions_mutex); + + return VK_SUCCESS; +} + +VkResult wine_vkQueueSubmit(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo *submits, VkFence fence, + void *submits_win) { struct wine_queue *queue = wine_queue_from_handle(queue_handle); unsigned int i, k; TRACE("(%p %u %p 0x%s)\n", queue_handle, submit_count, submits, wine_dbgstr_longlong(fence)); + if (is_virtual_queue(queue)) + return virtual_queue_submit(queue, submit_count, submits, fence, submits_win); + for (i = 0; i < submit_count; i++) { for (k = 0; k < submits[i].waitSemaphoreCount; k++) { if (wine_semaphore_from_handle(submits[i].pWaitSemaphores[k])->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - { - FIXME("Queue submissions with waits on D3D12-Fence compatible timeline semaphores not supported.\n"); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } + return virtual_queue_submit(queue, submit_count, submits, fence, submits_win); } for (k = 0; k < submits[i].signalSemaphoreCount; k++) { if (wine_semaphore_from_handle(submits[i].pSignalSemaphores[k])->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - { - FIXME("Queue submissions with signalling D3D12-Fence compatible timeline semaphores not supported.\n"); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } + return virtual_queue_submit(queue, submit_count, submits, fence, submits_win); } } return vk_queue_submit_unwrap(queue, submit_count, submits, fence); @@ -4395,6 +4919,77 @@ static void duplicate_array_for_unwrapping(struct conversion_context *ctx, void *ptr = out; } +static NTSTATUS virtual_queue_submit2(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence, bool khr) +{ + VkSemaphoreSubmitInfo *sem_submit_info; + struct queue_submit_unit *submit_unit; + VkSubmitInfo2 *queue_submit; + struct wine_semaphore *sem; + unsigned int i, j, k; + uint64_t wait_value; + bool device_lost; + + init_virtual_queue(queue); + + pthread_mutex_lock(&queue->submissions_mutex); + device_lost = queue->device_lost; + pthread_mutex_unlock(&queue->submissions_mutex); + if (device_lost) + return VK_ERROR_DEVICE_LOST; + + submit_unit = malloc(sizeof(*submit_unit)); + init_conversion_context(&submit_unit->ctx); + submit_unit->submit_count = submit_count; + submit_unit->submits = NULL; + submit_unit->submits2 = copy_VkSubmitInfo2_array(&submit_unit->ctx, submits, submit_count); + submit_unit->fence = fence; + submit_unit->waits = NULL; + submit_unit->khr = khr; + + /* As D3D12 fences are rewindable, we add the wait synchronously as not to miss a temporarily signalled value + between vkQueueSubmit and processing the submit unit */ + for (i = 0, k = 0; i < submit_count; i++) + { + queue_submit = &submit_unit->submits2[i]; + + for (j = 0; j < queue_submit->waitSemaphoreInfoCount; j++) + { + sem_submit_info = (VkSemaphoreSubmitInfo *) &queue_submit->pWaitSemaphoreInfos[j]; + sem = wine_semaphore_from_handle(sem_submit_info->semaphore); + + if (sem->handle_type != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + continue; + + wait_value = sem_submit_info->value; + + submit_unit->waits = realloc(submit_unit->waits, (k + 1) * sizeof(*submit_unit->waits)); + submit_unit->waits[k] = NULL; + + d3d12_semaphore_lock(sem); + + if ((sem_submit_info->value = + d3d12_semaphore_try_get_wait_value_locked(sem, wait_value, queue)) == -1) + submit_unit->waits[k] = d3d12_semaphore_push_wait_locked(sem, wait_value); + + d3d12_semaphore_unlock(sem); + k++; + } + } + + pthread_mutex_lock(&queue->submissions_mutex); + queue->processing = true; + if (fence) + { + wine_fence_from_handle(fence)->queue = queue; + wine_fence_from_handle(fence)->wait_assist = true; + } + list_add_tail(&queue->submissions, &submit_unit->entry); + pthread_cond_signal(&queue->submissions_cond); + pthread_mutex_unlock(&queue->submissions_mutex); + + return VK_SUCCESS; +} + VkResult vk_queue_submit_2_unwrap(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo2 *submits_orig, VkFence fence, bool khr) { @@ -4445,26 +5040,23 @@ static VkResult vk_queue_submit_2(VkQueue queue_handle, uint32_t submit_count, c TRACE("(%p, %u, %p, %s)\n", queue_handle, submit_count, submits, wine_dbgstr_longlong(fence)); + if (is_virtual_queue(queue)) + return virtual_queue_submit2(queue, submit_count, submits, fence, khr); + for (i = 0; i < submit_count; i++) { for (k = 0; k < submits[i].waitSemaphoreInfoCount; k++) { if (wine_semaphore_from_handle(submits[i].pWaitSemaphoreInfos[k].semaphore)->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - { - FIXME("Queue submissions with waits on D3D12-Fence compatible timeline semaphores not supported.\n"); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } + return virtual_queue_submit2(queue, submit_count, submits, fence, khr); } for (k = 0; k < submits[i].signalSemaphoreInfoCount; k++) { if (wine_semaphore_from_handle(submits[i].pSignalSemaphoreInfos[k].semaphore)->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - { - FIXME("Queue submissions signalling D3D12-Fence compatible timeline semaphores not supported.\n"); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } + return virtual_queue_submit2(queue, submit_count, submits, fence, khr); } } @@ -4483,6 +5075,7 @@ VkResult wine_vkQueueSubmit2KHR(VkQueue queue, uint32_t submit_count, const VkSu VkResult wine_vkQueuePresentKHR(VkQueue queue_handle, const VkPresentInfoKHR *present_info) { + struct wine_queue *queue = wine_queue_from_handle(queue_handle); VkPresentInfoKHR host_present_info = *present_info; struct wine_semaphore *semaphore; struct conversion_context ctx; @@ -4502,6 +5095,14 @@ VkResult wine_vkQueuePresentKHR(VkQueue queue_handle, const VkPresentInfoKHR *pr } } + if (is_virtual_queue(queue)) + { + pthread_mutex_lock(&queue->submissions_mutex); + while (queue->processing) + pthread_cond_wait(&queue->submissions_cond, &queue->submissions_mutex); + pthread_mutex_unlock(&queue->submissions_mutex); + } + init_conversion_context(&ctx); host_present_info.pWaitSemaphores = unwrap_semaphore_array(present_info->pWaitSemaphores, present_info->waitSemaphoreCount, &ctx); ret = fshack_vk_queue_present(queue_handle, &host_present_info); @@ -4520,6 +5121,15 @@ VkResult wine_vkQueueBindSparse(VkQueue queue_handle, uint32_t bind_info_count, TRACE("(%p, %u, %p, 0x%s)\n", queue, bind_info_count, bind_info, wine_dbgstr_longlong(fence)); + if (is_virtual_queue(queue)) + { + FIXME("Can't process sparse bind calls on virtual queue, flushing.\n"); + pthread_mutex_lock(&queue->submissions_mutex); + while (queue->processing) + pthread_cond_wait(&queue->submissions_cond, &queue->submissions_mutex); + pthread_mutex_unlock(&queue->submissions_mutex); + } + for (i = 0; i < bind_info_count; i++) { batch = (VkBindSparseInfo *)&bind_info[i]; @@ -4588,3 +5198,20 @@ VkResult wine_vkQueueBindSparse(VkQueue queue_handle, uint32_t bind_info_count, free_conversion_context(&ctx); return ret; } + +VkResult wine_vkQueueWaitIdle(VkQueue queue_handle) +{ + struct wine_queue *queue = wine_queue_from_handle(queue_handle); + + TRACE("(%p)\n", queue); + + if (is_virtual_queue(queue)) + { + pthread_mutex_lock(&queue->submissions_mutex); + while (queue->processing) + pthread_cond_wait(&queue->submissions_cond, &queue->submissions_mutex); + pthread_mutex_unlock(&queue->submissions_mutex); + } + + return queue->device->funcs.p_vkQueueWaitIdle(queue->queue); +} diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index db22b0df890..2f0b6a084ba 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -142,6 +142,7 @@ struct wine_instance */ struct wine_phys_dev **phys_devs; uint32_t phys_dev_count; + uint32_t api_version; VkBool32 enable_wrapper_list; struct list wrappers; @@ -172,6 +173,7 @@ struct wine_phys_dev VkPhysicalDeviceMemoryProperties memory_properties; VkExtensionProperties *extensions; uint32_t extension_count; + uint32_t api_version; uint32_t external_memory_align; @@ -194,6 +196,22 @@ struct wine_queue uint32_t queue_index; VkDeviceQueueCreateFlags flags; + bool virtual_queue; + bool processing; + bool device_lost; + + pthread_t virtual_queue_thread; + pthread_mutex_t submissions_mutex; + pthread_cond_t submissions_cond; + struct list submissions; + + pthread_t signal_thread; + pthread_mutex_t signaller_mutex; + pthread_cond_t signaller_cond; + struct list signal_ops; + + bool stop; + struct wine_vk_mapping mapping; }; From 221912a31286735ba9d281fb66bf919d95e68d4d Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 15 Jul 2022 11:41:10 -0400 Subject: [PATCH 0727/2777] winevulkan: Add support for signalling VkFence from virtualized VkQueues. --- dlls/winevulkan/make_vulkan | 6 + dlls/winevulkan/vulkan.c | 285 ++++++++++++++++++++++++++++--- dlls/winevulkan/vulkan_private.h | 20 +++ 3 files changed, 292 insertions(+), 19 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 1df70450312..c2eb72f374a 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -202,8 +202,10 @@ FUNCTION_OVERRIDES = { # Device functions "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE}, "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE, "extra_param" : "client_ptr"}, + "vkCreateFence" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE}, "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE}, + "vkDestroyFence" : {"dispatch" : True, "driver" : False, "thunk": ThunkType.NONE}, "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE}, "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE}, "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, @@ -215,7 +217,9 @@ FUNCTION_OVERRIDES = { "vkCreateBuffer" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkCreateImage" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkGetSemaphoreCounterValue" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, + "vkResetFences" : {"dispatch" : True, "driver": False, "thunk" : ThunkType.PRIVATE}, "vkSignalSemaphore" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, + "vkWaitForFences" : {"dispatch": True, "driver": False, "thunk": ThunkType.PRIVATE}, "vkWaitSemaphores" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, "vkQueueBindSparse" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, "vkQueueSubmit" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE, "extra_param" : "pSubmits"}, @@ -1150,6 +1154,8 @@ class VkHandle(object): return "wine_device_memory_from_handle({0})->memory".format(name) if self.name == "VkSemaphore": return "wine_semaphore_host_handle( wine_semaphore_from_handle({0}) )".format(name) + if self.name == "VkFence": + return "wine_fence_from_handle({0})->fence".format(name) if self.name == "VkPhysicalDevice": return "wine_phys_dev_from_handle({0})->phys_dev".format(name) if self.name == "VkQueue": diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index e41eb3376f9..f9321399e9d 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include "ntstatus.h" #define WIN32_NO_STATUS @@ -4420,8 +4422,9 @@ VkResult wine_vkWaitSemaphoresKHR(VkDevice device, const VkSemaphoreWaitInfo *wa return wine_vk_wait_semaphores(device, wait_info, timeout, true); } -VkResult vk_queue_submit_unwrap(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo *submits_orig, VkFence fence) +VkResult vk_queue_submit_unwrap(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo *submits_orig, VkFence fence_handle) { + struct wine_fence *fence = fence_handle ? wine_fence_from_handle(fence_handle) : NULL; struct conversion_context ctx; VkSubmitInfo *submits; unsigned int i, j; @@ -4443,7 +4446,12 @@ VkResult vk_queue_submit_unwrap(struct wine_queue *queue, uint32_t submit_count, submits[i].pCommandBuffers = out; } } - ret = queue->device->funcs.p_vkQueueSubmit(queue->queue, submit_count, submits, fence); + + + if (fence) + fence->queue = queue; + + ret = queue->device->funcs.p_vkQueueSubmit(queue->queue, submit_count, submits, fence ? fence->fence : VK_NULL_HANDLE); free_conversion_context(&ctx); return ret; } @@ -4453,6 +4461,7 @@ struct signal_op enum { SIGNAL_TYPE_SEMAPHORE, + SIGNAL_TYPE_FENCE, } signal_type; union @@ -4464,6 +4473,8 @@ struct signal_op bool khr; } semaphore; + + struct wine_fence *fence; }; struct list entry; @@ -4476,6 +4487,7 @@ static void *queue_signaller_worker(void *arg) struct signal_op *signal_op; VkSemaphore sem_handle; bool device_lost; + uint64_t buf; VkResult vr; for (;;) @@ -4519,6 +4531,19 @@ static void *queue_signaller_worker(void *arg) d3d12_semaphore_update_phys_val_locked(signal_op->semaphore.obj, signal_op->semaphore.phys_val); d3d12_semaphore_unlock(signal_op->semaphore.obj); } + else + { + if (!device_lost && (vr = queue->device->funcs.p_vkWaitForFences + (queue->device->device, 1, &signal_op->fence->fence, VK_TRUE, -1)) < 0) + { + /* likely GPU hang */ + fprintf(stderr, "winevulkan/queue_signaller_worker: Fence wait failed, vr %d.\n", vr); + continue; + } + + buf = 1; + assert( write(signal_op->fence->eventfd, &buf, sizeof(buf)) != -1 ); + } free(signal_op); } @@ -4651,6 +4676,7 @@ static void *virtual_queue_worker(void *arg) struct signal_op *signal_op; struct wine_semaphore *sem; struct pending_wait *wait; + struct wine_fence *fence; bool device_lost = false; uint64_t *timeline_value; unsigned int i; @@ -4703,10 +4729,10 @@ static void *virtual_queue_worker(void *arg) } if (submit_unit->submits) - vr = vk_queue_submit_unwrap(queue, submit_unit->submit_count, submit_unit->submits, VK_NULL_HANDLE); + vr = vk_queue_submit_unwrap(queue, submit_unit->submit_count, submit_unit->submits, submit_unit->fence); else vr = vk_queue_submit_2_unwrap(queue, submit_unit->submit_count, submit_unit->submits2, - VK_NULL_HANDLE, submit_unit->khr); + submit_unit->fence, submit_unit->khr); pthread_mutex_lock(&queue->signaller_mutex); @@ -4733,6 +4759,15 @@ static void *virtual_queue_worker(void *arg) d3d12_semaphore_unlock(sem); } + if (vr == VK_SUCCESS && (fence = wine_fence_from_handle(submit_unit->fence))) + { + signal_op = malloc(sizeof(*signal_op)); + signal_op->signal_type = SIGNAL_TYPE_FENCE; + signal_op->fence = fence; + + list_add_tail(&queue->signal_ops, &signal_op->entry); + } + pthread_cond_signal(&queue->signaller_cond); pthread_mutex_unlock(&queue->signaller_mutex); @@ -4742,6 +4777,12 @@ static void *virtual_queue_worker(void *arg) pthread_mutex_lock(&queue->submissions_mutex); queue->device_lost = device_lost = true; pthread_mutex_unlock(&queue->submissions_mutex); + + if ((fence = wine_fence_from_handle(submit_unit->fence))) + { + uint64_t buf = 1; + assert( write(fence->eventfd, &buf, sizeof(buf)) != -1 ); + } } free_submit_unit: @@ -4796,12 +4837,6 @@ static NTSTATUS virtual_queue_submit(struct wine_queue *queue, uint32_t submit_c uint64_t wait_value; bool device_lost; - if (fence != VK_NULL_HANDLE) - { - FIXME("Signalling fences in queue submissions involving D3D12-Fence compatible timeline semaphores not supported.\n"); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } - init_virtual_queue(queue); pthread_mutex_lock(&queue->submissions_mutex); @@ -4815,6 +4850,7 @@ static NTSTATUS virtual_queue_submit(struct wine_queue *queue, uint32_t submit_c submit_unit->submit_count = submit_count; submit_unit->submits = copy_VkSubmitInfo_array(&submit_unit->ctx, submits, submit_count); submit_unit->submits2 = NULL; + submit_unit->fence = fence; submit_unit->waits = NULL; submit_unit->khr = queue->device->phys_dev->api_version < VK_API_VERSION_1_2 || queue->device->phys_dev->instance->api_version < VK_API_VERSION_1_2; @@ -4870,6 +4906,11 @@ static NTSTATUS virtual_queue_submit(struct wine_queue *queue, uint32_t submit_c pthread_mutex_lock(&queue->submissions_mutex); queue->processing = true; + if (fence) + { + wine_fence_from_handle(fence)->queue = queue; + wine_fence_from_handle(fence)->wait_assist = true; + } list_add_tail(&queue->submissions, &submit_unit->entry); pthread_cond_signal(&queue->submissions_cond); pthread_mutex_unlock(&queue->submissions_mutex); @@ -4991,8 +5032,9 @@ static NTSTATUS virtual_queue_submit2(struct wine_queue *queue, uint32_t submit_ } VkResult vk_queue_submit_2_unwrap(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo2 *submits_orig, - VkFence fence, bool khr) + VkFence fence_handle, bool khr) { + struct wine_fence *fence = fence_handle ? wine_fence_from_handle(fence_handle) : NULL; struct conversion_context ctx; VkSubmitInfo2 *submits; unsigned int i, j; @@ -5025,23 +5067,27 @@ VkResult vk_queue_submit_2_unwrap(struct wine_queue *queue, uint32_t submit_coun = wine_cmd_buffer_from_handle(submits[i].pCommandBufferInfos[j].commandBuffer)->command_buffer; } } + if (fence) + fence->queue = queue; + if (khr) - ret = queue->device->funcs.p_vkQueueSubmit2KHR(queue->queue, submit_count, submits, fence); + ret = queue->device->funcs.p_vkQueueSubmit2KHR(queue->queue, submit_count, submits, fence ? fence->fence : VK_NULL_HANDLE); else - ret = queue->device->funcs.p_vkQueueSubmit2(queue->queue, submit_count, submits, fence); + ret = queue->device->funcs.p_vkQueueSubmit2(queue->queue, submit_count, submits, fence ? fence->fence : VK_NULL_HANDLE); + free_conversion_context(&ctx); return ret; } -static VkResult vk_queue_submit_2(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence, bool khr) +static VkResult vk_queue_submit_2(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence_handle, bool khr) { struct wine_queue *queue = wine_queue_from_handle(queue_handle); unsigned int i, k; - TRACE("(%p, %u, %p, %s)\n", queue_handle, submit_count, submits, wine_dbgstr_longlong(fence)); + TRACE("(%p, %u, %p, %s)\n", queue_handle, submit_count, submits, wine_dbgstr_longlong(fence_handle)); if (is_virtual_queue(queue)) - return virtual_queue_submit2(queue, submit_count, submits, fence, khr); + return virtual_queue_submit2(queue, submit_count, submits, fence_handle, khr); for (i = 0; i < submit_count; i++) { @@ -5049,18 +5095,18 @@ static VkResult vk_queue_submit_2(VkQueue queue_handle, uint32_t submit_count, c { if (wine_semaphore_from_handle(submits[i].pWaitSemaphoreInfos[k].semaphore)->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - return virtual_queue_submit2(queue, submit_count, submits, fence, khr); + return virtual_queue_submit2(queue, submit_count, submits, fence_handle, khr); } for (k = 0; k < submits[i].signalSemaphoreInfoCount; k++) { if (wine_semaphore_from_handle(submits[i].pSignalSemaphoreInfos[k].semaphore)->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - return virtual_queue_submit2(queue, submit_count, submits, fence, khr); + return virtual_queue_submit2(queue, submit_count, submits, fence_handle, khr); } } - return vk_queue_submit_2_unwrap(queue, submit_count, submits, fence, khr); + return vk_queue_submit_2_unwrap(queue, submit_count, submits, fence_handle, khr); } VkResult wine_vkQueueSubmit2(VkQueue queue, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence) @@ -5199,6 +5245,207 @@ VkResult wine_vkQueueBindSparse(VkQueue queue_handle, uint32_t bind_info_count, return ret; } +VkResult wine_vkCreateFence(VkDevice device_handle, const VkFenceCreateInfo *create_info, const VkAllocationCallbacks *allocator, VkFence *fence) +{ + struct wine_device *device = wine_device_from_handle(device_handle); + struct wine_fence *object; + VkResult vr; + + TRACE("(%p, %p, %p, %p)\n", device, create_info, allocator, fence); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + if (!(object = calloc(1, sizeof(*object)))) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + if ((object->eventfd = eventfd(0, EFD_CLOEXEC)) == -1) + ERR("Failed to create eventfd for fence.\n"); + + if ((vr = device->funcs.p_vkCreateFence(device->device, create_info, NULL, &object->fence)) == VK_SUCCESS) + *fence = wine_fence_to_handle(object); + else + free(object); + + return vr; +} + +void wine_vkDestroyFence(VkDevice device_handle, VkFence fence_handle, const VkAllocationCallbacks *allocator) +{ + struct wine_device *device = wine_device_from_handle(device_handle); + struct wine_fence *fence = wine_fence_from_handle(fence_handle); + + TRACE("(%p, %p, %p)\n", device, fence, allocator); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + if (!fence_handle) + return; + + if (fence->eventfd != -1) + close(fence->eventfd); + + device->funcs.p_vkDestroyFence(device->device, fence->fence, allocator); + free(fence); +} + +static VkFence *unwrap_fence_array(const VkFence *in, uint32_t count, struct conversion_context *ctx) +{ + VkFence *out; + unsigned int i; + + if (!in || !count) return NULL; + + out = conversion_context_alloc(ctx, count * sizeof(*out)); + for (i = 0; i < count; ++i) + out[i] = in[i] ? wine_fence_from_handle(in[i])->fence : VK_NULL_HANDLE; + + return out; +} + +VkResult wine_vkResetFences(VkDevice device_handle, uint32_t fence_count, const VkFence *fences) +{ + struct wine_device *device = wine_device_from_handle(device_handle); + struct conversion_context ctx; + struct wine_fence *fence; + VkFence *fences_unwrap; + unsigned int i; + uint64_t buf; + VkResult vr; + + TRACE("(%p, %u, %p)\n", device, fence_count, fences); + + init_conversion_context(&ctx); + fences_unwrap = unwrap_fence_array(fences, fence_count, &ctx); + vr = device->funcs.p_vkResetFences(device->device, fence_count, fences_unwrap); + free_conversion_context(&ctx); + if (vr) + return vr; + + for (i = 0; i < fence_count; i++) + { + fence = wine_fence_from_handle(fences[i]); + + fence->queue = NULL; + fence->swapchain = NULL; + if (fence->wait_assist) + { + fence->wait_assist = false; + if (read(fence->eventfd, &buf, sizeof(buf)) == -1) + ERR("Failed to reset event fd.\n"); + } + } + + return VK_SUCCESS; +} + +VkResult wine_vkWaitForFences(VkDevice device_handle, uint32_t fence_count, const VkFence *fences, + VkBool32 wait_all, uint64_t timeout) +{ + struct wine_device *device = wine_device_from_handle(device_handle); + struct signal_op *signal_op; + bool assisted_wait = false; + struct wine_fence *fence; + struct pollfd *wait_fds; + struct pollfd wait_fd; + unsigned int i; + VkResult vr; + int ret; + + TRACE("(%p, %u, %p, %u, 0x%s)\n", device, fence_count, fences, wait_all, wine_dbgstr_longlong(timeout)); + + for (i = 0; i < fence_count; i++) + { + fence = wine_fence_from_handle(fences[i]); + if (!fence->wait_assist) + continue; + + if (!wait_all && fence_count > 1) + { + assisted_wait = true; + break; + } + + wait_fd.fd = fence->eventfd; + wait_fd.events = POLLIN; + ret = poll(&wait_fd, 1, timeout / 1000000); + if (ret == -1) + { + ERR("Failed to poll wait assisted fence.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + if (!ret) + return VK_TIMEOUT; + + if (wait_fd.revents & (POLLERR | POLLHUP | POLLNVAL)) + ERR("Polling on fd %d returned %#x.", fence->eventfd, wait_fd.revents); + return VK_SUCCESS; + } + + if (assisted_wait) + { + /* Turn all non assisted waits into assisted waits, then poll on all */ + wait_fds = malloc( sizeof(wait_fds[0]) * fence_count ); + + for (i = 0; i < fence_count; i++) + { + if (!fence->wait_assist) + { + assert(fence->queue || fence->swapchain); + + if (fence->queue) + { + fence->wait_assist = true; + + /* If virtual-queue requiring work was submitted after the work signalling this mutex, + * we will end up unnecessarily waiting on that work first, + * but this will only happen once per queue */ + init_virtual_queue(fence->queue); + + signal_op = malloc(sizeof(*signal_op)); + signal_op->signal_type = SIGNAL_TYPE_FENCE; + signal_op->fence = fence; + + pthread_mutex_lock(&fence->queue->signaller_mutex); + list_add_tail(&fence->queue->signal_ops, &signal_op->entry); + pthread_cond_signal(&fence->queue->signaller_cond); + pthread_mutex_unlock(&fence->queue->signaller_mutex); + } + else + { + FIXME("Wait assist for swapchain signaled fences not supported.\n"); + free(wait_fds); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } + + wait_fds[i].fd = fence->eventfd; + wait_fds[i].events = POLLIN; + } + + if (poll(wait_fds, fence_count, timeout / 1000000) == -1) + { + ERR("Failed to poll wait assisted fences.\n"); + vr = VK_ERROR_OUT_OF_HOST_MEMORY; + } + + free(wait_fds); + } + else + { + struct conversion_context ctx; + VkFence *fences_unwrap; + + init_conversion_context(&ctx); + fences_unwrap = unwrap_fence_array(fences, fence_count, &ctx); + vr = device->funcs.p_vkWaitForFences(device->device, fence_count, fences_unwrap, wait_all, timeout); + free_conversion_context(&ctx); + } + + return vr; +} + VkResult wine_vkQueueWaitIdle(VkQueue queue_handle) { struct wine_queue *queue = wine_queue_from_handle(queue_handle); diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 2f0b6a084ba..245c81419a0 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -393,6 +393,26 @@ static inline VkSemaphore wine_semaphore_host_handle(struct wine_semaphore *sema return semaphore->semaphore; } +struct wine_fence +{ + VkFence fence; + + struct wine_queue *queue; + struct wine_swapchain *swapchain; + bool wait_assist; + int eventfd; +}; + +static inline struct wine_fence *wine_fence_from_handle(VkFence handle) +{ + return (struct wine_fence *)(uintptr_t)handle; +} + +static inline VkFence wine_fence_to_handle(struct wine_fence *fence) +{ + return (VkFence)(uintptr_t)fence; +} + static inline void *conversion_context_alloc(struct conversion_context *pool, size_t size) { if (pool->used + size <= sizeof(pool->buffer)) From 5152033a65b8f7e98d825973a849153c68c0d4cc Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Mon, 1 Aug 2022 17:01:18 -0400 Subject: [PATCH 0728/2777] winevulkan: Flush virtual queue before providing native handle. --- dlls/winevulkan/vulkan.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index f9321399e9d..e17e207d76a 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -3537,6 +3537,15 @@ VkQueue WINAPI __wine_get_native_VkQueue(VkQueue handle) { struct wine_queue *queue = wine_queue_from_handle(handle); + if (is_virtual_queue(queue)) + { + FIXME("VR is using native handle of virtualized queue, this is untested.\n"); + pthread_mutex_lock(&queue->submissions_mutex); + while (queue->processing) + pthread_cond_wait(&queue->submissions_cond, &queue->submissions_mutex); + pthread_mutex_unlock(&queue->submissions_mutex); + } + return queue->queue; } From c68312129c201e8d5e50958dafcceea48ca79cc0 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Thu, 11 Aug 2022 10:57:01 -0400 Subject: [PATCH 0729/2777] winevulkan: Allowing importing D3D11 Texture handles as Vulkan memory objects. --- dlls/winevulkan/vulkan.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index e17e207d76a..156215bbbf4 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -1455,7 +1455,9 @@ static inline void wine_vk_normalize_handle_types_host(VkExternalMemoryHandleTyp static const VkExternalMemoryHandleTypeFlagBits wine_vk_handle_over_fd_types = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT | - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT; + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT; static void wine_vk_get_physical_device_external_buffer_properties(struct wine_phys_dev *phys_dev, void (*p_vkGetPhysicalDeviceExternalBufferProperties)(VkPhysicalDevice, const VkPhysicalDeviceExternalBufferInfo *, VkExternalBufferProperties *), @@ -2691,12 +2693,14 @@ VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *allo switch (handle_import_info->handleType) { case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT: if (handle_import_info->handle) NtDuplicateObject( NtCurrentProcess(), handle_import_info->handle, NtCurrentProcess(), &memory->handle, 0, 0, DUPLICATE_SAME_ACCESS ); else if (handle_import_info->name) memory->handle = open_shared_resource( 0, handle_import_info->name ); break; case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT: + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT: /* FIXME: the spec says that device memory imported from a KMT handle doesn't keep a reference to the underyling payload. This means that in cases where on windows an application leaks VkDeviceMemory objects, we leak the full payload. To fix this, we would need wine_dev_mem objects to store no reference to the payload, that means no host VkDeviceMemory @@ -3578,9 +3582,11 @@ VkResult wine_vkGetMemoryWin32HandleKHR(VkDevice device, const VkMemoryGetWin32H switch(handle_info->handleType) { case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT: return !NtDuplicateObject( NtCurrentProcess(), dev_mem->handle, NtCurrentProcess(), handle, dev_mem->access, dev_mem->inherit ? OBJ_INHERIT : 0, 0) ? VK_SUCCESS : VK_ERROR_OUT_OF_HOST_MEMORY; case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT: + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT: { if ((ret = get_shared_resource_kmt_handle(dev_mem->handle)) == INVALID_HANDLE_VALUE) return VK_ERROR_OUT_OF_HOST_MEMORY; From 99ec6833def7e0f8290c0062351c50431de36742 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Mon, 22 Aug 2022 16:20:23 -0400 Subject: [PATCH 0730/2777] winevulkan: Fix vkWaitSemaphores implementation with 32-bit time_t value. --- dlls/winevulkan/vulkan.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 156215bbbf4..1e907461974 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -4295,6 +4296,7 @@ static VkResult wine_vk_wait_semaphores(VkDevice device_handle, const VkSemaphor unsigned int i, remaining_waits; VkSemaphore* semaphores_dup; uint64_t *values_dup; + int64_t tv_sec_wide; uint64_t phys_val; int wait_stat; VkResult res; @@ -4305,13 +4307,18 @@ static VkResult wine_vk_wait_semaphores(VkDevice device_handle, const VkSemaphor { clock_gettime(CLOCK_REALTIME, &start_time); - abs_timeout.tv_sec = start_time.tv_sec + (timeout / NANOSECONDS_IN_A_SECOND); + abs_timeout.tv_sec = tv_sec_wide = start_time.tv_sec + (timeout / NANOSECONDS_IN_A_SECOND); abs_timeout.tv_nsec = start_time.tv_nsec + (timeout % NANOSECONDS_IN_A_SECOND); if (abs_timeout.tv_nsec >= NANOSECONDS_IN_A_SECOND) { abs_timeout.tv_sec++; + tv_sec_wide++; abs_timeout.tv_nsec-=NANOSECONDS_IN_A_SECOND; } + + /* tv_sec is still! 32-bit on x86 */ + if (tv_sec_wide > abs_timeout.tv_sec) + abs_timeout.tv_sec = INT_MAX; } wait_info_dup.pSemaphores = semaphores_dup = calloc(wait_info->semaphoreCount, sizeof(VkSemaphore)); From 27baf0f5af8793d108de8f8615b7a7a752db32a7 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 27 Dec 2022 15:29:17 -0600 Subject: [PATCH 0731/2777] winevulkan: Remove extra index increment in virtual_queue_worker(). --- dlls/winevulkan/vulkan.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 1e907461974..d8741e07384 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -4729,9 +4729,8 @@ static void *virtual_queue_worker(void *arg) /* Wait for all fences to have a pending signal */ for (i = 0; for_each_d3d12_semaphore(submit_unit, false, &sem, &timeline_value, i); i++) { - if ((wait = submit_unit->waits[i++])) + if ((wait = submit_unit->waits[i])) { - assert(wait); d3d12_semaphore_lock(sem); while (!wait->satisfied) From 4deb9cac53fbce0bac375d485aba6791d7037c7f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 27 Dec 2022 17:50:14 -0600 Subject: [PATCH 0732/2777] winevulkan: Rename for_each_d3d12_semaphore() into get_semaphore_by_index(). --- dlls/winevulkan/vulkan.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index d8741e07384..d97c9439e0b 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -4616,7 +4616,7 @@ struct queue_submit_unit }; /* Abstracts away the differences between VkSubmitInfo and VkSubmitInfo2. */ -static bool for_each_d3d12_semaphore(struct queue_submit_unit *unit, bool signal, +static bool get_semaphore_by_index(struct queue_submit_unit *unit, bool signal, struct wine_semaphore **semaphore_out, uint64_t **value_out, uint32_t counter) { VkTimelineSemaphoreSubmitInfo *timeline_values; @@ -4727,7 +4727,7 @@ static void *virtual_queue_worker(void *arg) goto free_submit_unit; /* Wait for all fences to have a pending signal */ - for (i = 0; for_each_d3d12_semaphore(submit_unit, false, &sem, &timeline_value, i); i++) + for (i = 0; get_semaphore_by_index(submit_unit, false, &sem, &timeline_value, i); i++) { if ((wait = submit_unit->waits[i])) { @@ -4742,7 +4742,7 @@ static void *virtual_queue_worker(void *arg) } } - for (i = 0; for_each_d3d12_semaphore(submit_unit, true, &sem, &timeline_value, i); i++) + for (i = 0; get_semaphore_by_index(submit_unit, true, &sem, &timeline_value, i); i++) { d3d12_semaphore_lock(sem); @@ -4757,7 +4757,7 @@ static void *virtual_queue_worker(void *arg) pthread_mutex_lock(&queue->signaller_mutex); - for (i = 0; for_each_d3d12_semaphore(submit_unit, true, &sem, &timeline_value, i); i++) + for (i = 0; get_semaphore_by_index(submit_unit, true, &sem, &timeline_value, i); i++) { if (vr == VK_SUCCESS) { From 145f580cf412cf6d875f0e2d16a014805e6d43ab Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 27 Dec 2022 17:59:06 -0600 Subject: [PATCH 0733/2777] winevulkan: Only append VK_KHR_timeline_semaphore for Vk API version < 1.2. --- dlls/winevulkan/vulkan.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index d97c9439e0b..13e6b2fe40e 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -522,6 +522,8 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de else if (!strcmp(extension_name, "VK_KHR_timeline_semaphore")) append_timeline = 0; } + if (append_timeline) + append_timeline = phys_dev->api_version < VK_API_VERSION_1_2 || phys_dev->instance->api_version < VK_API_VERSION_1_2; if (append_timeline) { append_timeline = 0; @@ -1748,6 +1750,25 @@ static void wine_vk_get_physical_device_external_semaphore_properties(struct win break; case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT: { + unsigned int i; + + if (phys_dev->api_version < VK_API_VERSION_1_2 || + phys_dev->instance->api_version < VK_API_VERSION_1_2) + { + for (i = 0; i < phys_dev->extension_count; i++) + { + if (!strcmp(phys_dev->extensions[i].extensionName, "VK_KHR_timeline_semaphore")) + break; + } + if (i == phys_dev->extension_count) + { + properties->exportFromImportedHandleTypes = 0; + properties->compatibleHandleTypes = 0; + properties->externalSemaphoreFeatures = 0; + return; + } + } + if ((p_semaphore_type_info = wine_vk_find_struct(&semaphore_info_dup, SEMAPHORE_TYPE_CREATE_INFO))) { p_semaphore_type_info->semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE; From bd38bbf085851d2429ee957fba479dc7c0b3b912 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 29 Dec 2022 11:30:18 -0600 Subject: [PATCH 0734/2777] ntdll: HACK: Load Unix libs at once in load_builtin_unixlib(). CW-Bug-Id: #21736 --- dlls/ntdll/unix/virtual.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index d90c8af6e6e..837ecd878dd 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -718,6 +718,7 @@ NTSTATUS load_builtin_unixlib( void *module, const char *name ) if (builtin->module != module) continue; if (!builtin->unix_path) builtin->unix_path = strdup( name ); else status = STATUS_IMAGE_ALREADY_LOADED; + if (!builtin->unix_handle) builtin->unix_handle = dlopen( builtin->unix_path, RTLD_NOW ); break; } server_leave_uninterrupted_section( &virtual_mutex, &sigset ); From 29f13b4330c8f0f620d2951ddeaec745f2ff5a94 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 20 Dec 2022 13:38:58 -0500 Subject: [PATCH 0735/2777] tabtip: Create tabtip.exe. TabTIP: Tablet text input panel. This program watches for editable text input fields gaining focus and runs an event handler when this occurs. Signed-off-by: Connor McAdams CW-Bug-Id: #18351 --- configure.ac | 1 + programs/tabtip/Makefile.in | 7 + programs/tabtip/tabtip.c | 365 ++++++++++++++++++++++++++++++++++++ 3 files changed, 373 insertions(+) create mode 100644 programs/tabtip/Makefile.in create mode 100644 programs/tabtip/tabtip.c diff --git a/configure.ac b/configure.ac index 5c168213481..03806f6189e 100644 --- a/configure.ac +++ b/configure.ac @@ -3428,6 +3428,7 @@ WINE_CONFIG_MAKEFILE(programs/start) WINE_CONFIG_MAKEFILE(programs/subst) WINE_CONFIG_MAKEFILE(programs/svchost) WINE_CONFIG_MAKEFILE(programs/systeminfo) +WINE_CONFIG_MAKEFILE(programs/tabtip) WINE_CONFIG_MAKEFILE(programs/taskkill) WINE_CONFIG_MAKEFILE(programs/tasklist) WINE_CONFIG_MAKEFILE(programs/taskmgr) diff --git a/programs/tabtip/Makefile.in b/programs/tabtip/Makefile.in new file mode 100644 index 00000000000..4023382c61b --- /dev/null +++ b/programs/tabtip/Makefile.in @@ -0,0 +1,7 @@ +EXTRADEFS = -DWINE_NO_LONG_TYPES +MODULE = tabtip.exe +IMPORTS = uuid ole32 user32 oleacc uiautomationcore rpcrt4 shell32 + +EXTRADLLFLAGS = -mconsole -municode -mno-cygwin + +C_SRCS = tabtip.c diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c new file mode 100644 index 00000000000..45f77b66412 --- /dev/null +++ b/programs/tabtip/tabtip.c @@ -0,0 +1,365 @@ +/* + * Copyright 2021 Connor McAdams + * + * 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 + */ + +#include "windows.h" +#define COBJMACROS +#include +#include "uiautomation.h" +#include "ole2.h" +#include "strsafe.h" +#include "oleacc.h" +#include "shellapi.h" +#include +#include + +#include "wine/debug.h" +#ifndef UNICODE +#define UNICODE +#endif + +WINE_DEFAULT_DEBUG_CHANNEL(tabtip); + +extern HANDLE CDECL __wine_make_process_system(void); +LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +enum { + EVENT_PGM_EXIT, + EVENT_WINE_EXIT, + THREAD_EVENT_COUNT, +}; + +struct thread_data { + HANDLE events[THREAD_EVENT_COUNT]; + HWND main_hwnd; +}; + +typedef struct { + IUIAutomationFocusChangedEventHandler IUIAutomationFocusChangedEventHandler_iface; + LONG ref; +} event_data; + +static DWORD last_keyup_event; +static BOOL keyboard_up; + +static const char *ct_id_str[] = { + "UIA_ButtonControlTypeId (50000)", + "UIA_CalendarControlTypeId (50001)", + "UIA_CheckBoxControlTypeId (50002)", + "UIA_ComboBoxControlTypeId (50003)", + "UIA_EditControlTypeId (50004)", + "UIA_HyperlinkControlTypeId (50005)", + "UIA_ImageControlTypeId (50006)", + "UIA_ListItemControlTypeId (50007)", + "UIA_ListControlTypeId (50008)", + "UIA_MenuControlTypeId (50009)", + "UIA_MenuBarControlTypeId (50010)", + "UIA_MenuItemControlTypeId (50011)", + "UIA_ProgressBarControlTypeId (50012)", + "UIA_RadioButtonControlTypeId (50013)", + "UIA_ScrollBarControlTypeId (50014)", + "UIA_SliderControlTypeId (50015)", + "UIA_SpinnerControlTypeId (50016)", + "UIA_StatusBarControlTypeId (50017)", + "UIA_TabControlTypeId (50018)", + "UIA_TabItemControlTypeId (50019)", + "UIA_TextControlTypeId (50020)", + "UIA_ToolBarControlTypeId (50021)", + "UIA_ToolTipControlTypeId (50022)", + "UIA_TreeControlTypeId (50023)", + "UIA_TreeItemControlTypeId (50024)", + "UIA_CustomControlTypeId (50025)", + "UIA_GroupControlTypeId (50026)", + "UIA_ThumbControlTypeId (50027)", + "UIA_DataGridControlTypeId (50028)", + "UIA_DataItemControlTypeId (50029)", + "UIA_DocumentControlTypeId (50030)", + "UIA_SplitButtonControlTypeId (50031)", + "UIA_WindowControlTypeId (50032)", + "UIA_PaneControlTypeId (50033)", + "UIA_HeaderControlTypeId (50034)", + "UIA_HeaderItemControlTypeId (50035)", + "UIA_TableControlTypeId (50036)", + "UIA_TitleBarControlTypeId (50037)", + "UIA_SeparatorControlTypeId (50038)", + "UIA_SemanticZoomControlTypeId (50039)", + "UIA_AppBarControlTypeId (50040)", +}; + +/* + * IUIAutomationFocusChangedEventHandler vtbl. + */ +static inline event_data *impl_from_uia_focus_event(IUIAutomationFocusChangedEventHandler *iface) +{ + return CONTAINING_RECORD(iface, event_data, IUIAutomationFocusChangedEventHandler_iface); +} + +HRESULT WINAPI uia_focus_event_QueryInterface(IUIAutomationFocusChangedEventHandler *iface, + REFIID riid, void **ppv) +{ + event_data *This = impl_from_uia_focus_event(iface); + + WINE_TRACE("This %p, %s\n", This, debugstr_guid( riid )); + if (IsEqualIID(riid, &IID_IUIAutomationFocusChangedEventHandler) || + IsEqualIID(riid, &IID_IUnknown)) { + *ppv = iface; + } else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUIAutomationFocusChangedEventHandler_AddRef(iface); + return S_OK; +} + +ULONG WINAPI uia_focus_event_AddRef(IUIAutomationFocusChangedEventHandler* iface) +{ + event_data *This = impl_from_uia_focus_event(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + WINE_TRACE("This %p, ref %d\n", This, ref); + + return ref; +} + +ULONG WINAPI uia_focus_event_Release(IUIAutomationFocusChangedEventHandler* iface) +{ + event_data *This = impl_from_uia_focus_event(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + WINE_TRACE("This %p, ref %d\n", This, ref); + + return ref; +} + +/*** IUIAutomationFocusChangedEventHandler methods ***/ +HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChangedEventHandler *iface, + IUIAutomationElement *sender) +{ + event_data *This = impl_from_uia_focus_event(iface); + + WINE_TRACE("This %p, sender %p\n", This, sender); + if (sender) + { + VARIANT var; + INT ct_id; + BSTR name; + + IUIAutomationElement_get_CurrentControlType(sender, &ct_id); + IUIAutomationElement_get_CurrentName(sender, &name); + IUIAutomationElement_GetCurrentPropertyValue(sender, UIA_IsKeyboardFocusablePropertyId, &var); + + if ((last_keyup_event < (GetTickCount() - 5000)) && + ct_id == UIA_EditControlTypeId && (V_VT(&var) == VT_BOOL && V_BOOL(&var))) + { + if (!keyboard_up) + { + WINE_TRACE("Keyboard up!\n"); + keyboard_up = TRUE; + ShellExecuteW(NULL, NULL, L"steam://open/keyboard", NULL, NULL, SW_SHOWNOACTIVATE); + + last_keyup_event = GetTickCount(); + } + } + else + { + if (keyboard_up) + { + WINE_TRACE("Keyboard down!\n"); + keyboard_up = FALSE; + } + } + + if (ct_id >= 50000) + ct_id -= 50000; + else + ct_id = 0; + + WINE_TRACE("element name: %s, ct_id %s\n", wine_dbgstr_w(name), ct_id_str[ct_id]); + } + + return S_OK; +} + +IUIAutomationFocusChangedEventHandlerVtbl uia_focus_event_vtbl = { + uia_focus_event_QueryInterface, + uia_focus_event_AddRef, + uia_focus_event_Release, + uia_focus_event_HandleFocusChangedEvent, +}; + +static HRESULT create_uia_event_handler(IUIAutomation **uia_iface, event_data *data) +{ + HRESULT hr; + + hr = CoCreateInstance(&CLSID_CUIAutomation, NULL, CLSCTX_INPROC_SERVER, + &IID_IUIAutomation, (void **)uia_iface); + if (FAILED(hr)) + { + ERR("Failed to create IUIAutomation interface, hr %#x\n", hr); + return hr; + } + + data->IUIAutomationFocusChangedEventHandler_iface.lpVtbl = &uia_focus_event_vtbl; + data->ref = 1; + + hr = IUIAutomation_AddFocusChangedEventHandler(*uia_iface, NULL, + &data->IUIAutomationFocusChangedEventHandler_iface); + if (FAILED(hr)) + ERR("Failed to add focus changed event handler, hr %#x\n", hr); + + return hr; +} + +static DWORD WINAPI tabtip_exit_watcher(LPVOID lpParam) +{ + struct thread_data *data = (struct thread_data *)lpParam; + DWORD event; + + event = WaitForMultipleObjects(THREAD_EVENT_COUNT, data->events, FALSE, INFINITE); + switch (event) + { + case EVENT_PGM_EXIT: + break; + + case EVENT_WINE_EXIT: + PostMessageW(data->main_hwnd, WM_DESTROY, 0, 0); + break; + + default: + break; + } + + return 0; +} + +int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) +{ + HANDLE wine_exit_event, pgm_exit_event, started_event; + // Register the window class. + const wchar_t CLASS_NAME[] = L"IPTip_Main_Window"; + struct thread_data t_data = { }; + IUIAutomation *uia_iface; + WNDCLASSW wc = { }; + event_data data = { }; + MSG msg = { }; + int ret = 0; + HWND hwnd; + + wine_exit_event = pgm_exit_event = started_event = NULL; + last_keyup_event = 0; + keyboard_up = FALSE; + + NtSetInformationProcess( GetCurrentProcess(), ProcessWineMakeProcessSystem, + &wine_exit_event, sizeof(HANDLE *) ); + pgm_exit_event = CreateEventW(NULL, 0, 0, NULL); + started_event = CreateEventW(NULL, TRUE, FALSE, L"TABTIP_STARTED_EVENT"); + + if (!pgm_exit_event || !wine_exit_event || !started_event) + { + ERR("Failed to create event handles!\n"); + ret = -1; + goto exit; + } + + wc.lpfnWndProc = WindowProc; + wc.hInstance = hInstance; + wc.lpszClassName = CLASS_NAME; + + RegisterClassW(&wc); + + hwnd = CreateWindowExW(0, CLASS_NAME, + L"Input", WS_OVERLAPPEDWINDOW, 4, 4, 0, 0, NULL, + NULL, hInstance, NULL); + + if (!hwnd) + { + ERR("Failed to create hwnd!\n"); + ret = -1; + goto exit; + } + + if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) + { + ERR("CoInitialize failed!\n"); + ret = -1; + goto exit; + } + + if (FAILED(create_uia_event_handler(&uia_iface, &data))) + { + ret = -1; + goto exit; + } + + t_data.events[EVENT_WINE_EXIT] = wine_exit_event; + t_data.events[EVENT_PGM_EXIT] = pgm_exit_event; + t_data.main_hwnd = hwnd; + + SetEvent(started_event); + CreateThread(NULL, 0, tabtip_exit_watcher, &t_data, 0, NULL); + + while (GetMessageW(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + SetEvent(pgm_exit_event); + IUIAutomation_RemoveAllEventHandlers(uia_iface); + IUIAutomation_Release(uia_iface); + + CoUninitialize(); + +exit: + + if (wine_exit_event) + CloseHandle(wine_exit_event); + + if (pgm_exit_event) + CloseHandle(pgm_exit_event); + + if (started_event) + CloseHandle(started_event); + + return ret; +} + +LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_DESTROY: + PostQuitMessage(0); + return 0; + + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + + FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1)); + + EndPaint(hwnd, &ps); + } + return 0; + default: + break; + } + + return DefWindowProcW(hwnd, uMsg, wParam, lParam); +} From 0a206e20dd6b1c952c87971d60a5a3cbab9d050e Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 8 Sep 2021 18:04:33 -0400 Subject: [PATCH 0736/2777] tabtip: Retrieve bounding rectangle for focused element. Retrieve the bounding rectangle of the focused accessible object, and pass this data to the steam OSK link if it's retrieved. Signed-off-by: Connor McAdams CW-Bug-Id: #18351 --- programs/tabtip/tabtip.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c index 45f77b66412..2a976ef2d29 100644 --- a/programs/tabtip/tabtip.c +++ b/programs/tabtip/tabtip.c @@ -155,12 +155,14 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged WINE_TRACE("This %p, sender %p\n", This, sender); if (sender) { + RECT rect = { 0 }; VARIANT var; INT ct_id; BSTR name; IUIAutomationElement_get_CurrentControlType(sender, &ct_id); IUIAutomationElement_get_CurrentName(sender, &name); + IUIAutomationElement_get_CurrentBoundingRectangle(sender, &rect); IUIAutomationElement_GetCurrentPropertyValue(sender, UIA_IsKeyboardFocusablePropertyId, &var); if ((last_keyup_event < (GetTickCount() - 5000)) && @@ -170,7 +172,16 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged { WINE_TRACE("Keyboard up!\n"); keyboard_up = TRUE; - ShellExecuteW(NULL, NULL, L"steam://open/keyboard", NULL, NULL, SW_SHOWNOACTIVATE); + if (rect.left || rect.top || rect.right || rect.bottom) + { + WCHAR link_buf[1024]; + + wsprintfW(link_buf, L"steam://open/keyboard?XPosition=%d&YPosition=%d&Width=%d&Height=%d&Mode=0", + rect.left, rect.top, (rect.right - rect.left), (rect.bottom - rect.top)); + ShellExecuteW(NULL, NULL, link_buf, NULL, NULL, SW_SHOWNOACTIVATE); + } + else + ShellExecuteW(NULL, NULL, L"steam://open/keyboard", NULL, NULL, SW_SHOWNOACTIVATE); last_keyup_event = GetTickCount(); } @@ -189,7 +200,8 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged else ct_id = 0; - WINE_TRACE("element name: %s, ct_id %s\n", wine_dbgstr_w(name), ct_id_str[ct_id]); + WINE_TRACE("element name: %s, ct_id %s, rect { %d, %d } - { %d, %d }\n", wine_dbgstr_w(name), ct_id_str[ct_id], + rect.left, rect.top, rect.right, rect.bottom); } return S_OK; From ab83ca71f172c3c7b33e24d71f634bf1f0db7174 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Thu, 9 Sep 2021 14:02:08 -0400 Subject: [PATCH 0737/2777] tabtip: Only trigger steam OSK link if we're running on Steam Deck. Signed-off-by: Connor McAdams CW-Bug-Id: #18351 --- programs/tabtip/tabtip.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c index 2a976ef2d29..e8f1fc9ba6e 100644 --- a/programs/tabtip/tabtip.c +++ b/programs/tabtip/tabtip.c @@ -55,6 +55,7 @@ typedef struct { static DWORD last_keyup_event; static BOOL keyboard_up; +static BOOL use_steam_osk; static const char *ct_id_str[] = { "UIA_ButtonControlTypeId (50000)", @@ -165,7 +166,7 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged IUIAutomationElement_get_CurrentBoundingRectangle(sender, &rect); IUIAutomationElement_GetCurrentPropertyValue(sender, UIA_IsKeyboardFocusablePropertyId, &var); - if ((last_keyup_event < (GetTickCount() - 5000)) && + if (use_steam_osk && (last_keyup_event < (GetTickCount() - 5000)) && ct_id == UIA_EditControlTypeId && (V_VT(&var) == VT_BOOL && V_BOOL(&var))) { if (!keyboard_up) @@ -259,6 +260,18 @@ static DWORD WINAPI tabtip_exit_watcher(LPVOID lpParam) return 0; } +static void tabtip_use_osk_check(void) +{ + const char *var = getenv("SteamDeck"); + + if (var && !strcmp(var, "1")) + use_steam_osk = TRUE; + else + use_steam_osk = FALSE; + + WINE_TRACE("use_steam_osk=%d\n", use_steam_osk); +} + int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) { HANDLE wine_exit_event, pgm_exit_event, started_event; @@ -275,6 +288,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine wine_exit_event = pgm_exit_event = started_event = NULL; last_keyup_event = 0; keyboard_up = FALSE; + tabtip_use_osk_check(); NtSetInformationProcess( GetCurrentProcess(), ProcessWineMakeProcessSystem, &wine_exit_event, sizeof(HANDLE *) ); From 212428cb5c988bd9fdec6a8d8a6271a29ac5c222 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Thu, 4 Nov 2021 11:54:50 -0400 Subject: [PATCH 0738/2777] tabtip: Close keyboard upon focus loss. Call new "steam://close/keyboard" link upon edit control focus loss, to make sure keyboard is closed. Signed-off-by: Connor McAdams CW-Bug-Id: #18351 --- programs/tabtip/tabtip.c | 1 + 1 file changed, 1 insertion(+) diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c index e8f1fc9ba6e..31b62c2bae9 100644 --- a/programs/tabtip/tabtip.c +++ b/programs/tabtip/tabtip.c @@ -192,6 +192,7 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged if (keyboard_up) { WINE_TRACE("Keyboard down!\n"); + ShellExecuteW(NULL, NULL, L"steam://close/keyboard", NULL, NULL, SW_SHOWNOACTIVATE); keyboard_up = FALSE; } } From 957bc974ee64f681d31908a477f42981825265b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 30 Nov 2021 09:29:21 +0100 Subject: [PATCH 0739/2777] tabtip: Set started event before creating a window. CW-Bug-Id: #18351 CW-Bug-Id: #19584 --- programs/tabtip/tabtip.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c index 31b62c2bae9..c035dd11ea2 100644 --- a/programs/tabtip/tabtip.c +++ b/programs/tabtip/tabtip.c @@ -303,6 +303,21 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine goto exit; } + if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) + { + ERR("CoInitialize failed!\n"); + ret = -1; + goto exit; + } + + SetEvent(started_event); + + if (FAILED(create_uia_event_handler(&uia_iface, &data))) + { + ret = -1; + goto exit; + } + wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.lpszClassName = CLASS_NAME; @@ -320,24 +335,9 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine goto exit; } - if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) - { - ERR("CoInitialize failed!\n"); - ret = -1; - goto exit; - } - - if (FAILED(create_uia_event_handler(&uia_iface, &data))) - { - ret = -1; - goto exit; - } - t_data.events[EVENT_WINE_EXIT] = wine_exit_event; t_data.events[EVENT_PGM_EXIT] = pgm_exit_event; t_data.main_hwnd = hwnd; - - SetEvent(started_event); CreateThread(NULL, 0, tabtip_exit_watcher, &t_data, 0, NULL); while (GetMessageW(&msg, NULL, 0, 0)) From 9171cc44be3d9d026d14c7c0ee094b37f0249ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 Nov 2021 18:59:13 +0100 Subject: [PATCH 0740/2777] explorer: Start tabtip process before the main loop. CW-Bug-Id: #18351 CW-Bug-Id: #19584 --- programs/explorer/desktop.c | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c index 96673adc254..4fdeb96e8a3 100644 --- a/programs/explorer/desktop.c +++ b/programs/explorer/desktop.c @@ -1031,6 +1031,38 @@ static inline BOOL is_whitespace(WCHAR c) return c == ' ' || c == '\t'; } +static HANDLE start_tabtip_process(void) +{ + static const WCHAR tabtip_started_event[] = L"TABTIP_STARTED_EVENT"; + PROCESS_INFORMATION pi; + STARTUPINFOW si = { sizeof(si) }; + HANDLE wait_handles[2]; + + if (!CreateProcessW(L"C:\\windows\\system32\\tabtip.exe", NULL, + NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi)) + { + WINE_ERR("Couldn't start tabtip.exe: error %lu\n", GetLastError()); + return FALSE; + } + CloseHandle(pi.hThread); + + wait_handles[0] = CreateEventW(NULL, TRUE, FALSE, tabtip_started_event); + wait_handles[1] = pi.hProcess; + + /* wait for the event to become available or the process to exit */ + if ((WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE)) == WAIT_OBJECT_0 + 1) + { + DWORD exit_code; + GetExitCodeProcess(pi.hProcess, &exit_code); + WINE_ERR("Unexpected termination of tabtip.exe - exit code %ld\n", exit_code); + CloseHandle(wait_handles[0]); + return pi.hProcess; + } + + CloseHandle(wait_handles[0]); + return pi.hProcess; +} + /* main desktop management function */ void manage_desktop( WCHAR *arg ) { @@ -1039,6 +1071,7 @@ void manage_desktop( WCHAR *arg ) GUID guid; MSG msg; HWND hwnd; + HANDLE taptip; HMODULE graphics_driver; unsigned int width, height; WCHAR *cmdline = NULL, *driver = NULL; @@ -1151,6 +1184,9 @@ void manage_desktop( WCHAR *arg ) desktopshellbrowserwindow_init(); shellwindows_init(); + /* FIXME: hack, run tabtip.exe on startup. */ + taptip = start_tabtip_process(); + /* run the desktop message loop */ if (hwnd) { @@ -1161,6 +1197,10 @@ void manage_desktop( WCHAR *arg ) if (pShellDDEInit) pShellDDEInit( FALSE ); + TerminateProcess( taptip, 0 ); + WaitForSingleObject( taptip, INFINITE ); + CloseHandle( taptip ); + ExitProcess( 0 ); } From aceed2e66b5db7d17011db7c52b8d32fe29a4c48 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 23 Nov 2021 17:09:13 -0500 Subject: [PATCH 0741/2777] tabtip: Check UIA_ValueIsReadOnlyPropertyId before triggering OSK. Signed-off-by: Connor McAdams --- programs/tabtip/tabtip.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c index c035dd11ea2..1f6e852b370 100644 --- a/programs/tabtip/tabtip.c +++ b/programs/tabtip/tabtip.c @@ -147,6 +147,14 @@ ULONG WINAPI uia_focus_event_Release(IUIAutomationFocusChangedEventHandler* ifac return ref; } +static BOOL variant_to_bool(VARIANT *v) +{ + if (V_VT(v) == VT_BOOL && (V_BOOL(v) == VARIANT_TRUE)) + return TRUE; + + return FALSE; +} + /*** IUIAutomationFocusChangedEventHandler methods ***/ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChangedEventHandler *iface, IUIAutomationElement *sender) @@ -157,7 +165,7 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged if (sender) { RECT rect = { 0 }; - VARIANT var; + VARIANT var, var2; INT ct_id; BSTR name; @@ -165,9 +173,10 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged IUIAutomationElement_get_CurrentName(sender, &name); IUIAutomationElement_get_CurrentBoundingRectangle(sender, &rect); IUIAutomationElement_GetCurrentPropertyValue(sender, UIA_IsKeyboardFocusablePropertyId, &var); + IUIAutomationElement_GetCurrentPropertyValue(sender, UIA_ValueIsReadOnlyPropertyId, &var2); if (use_steam_osk && (last_keyup_event < (GetTickCount() - 5000)) && - ct_id == UIA_EditControlTypeId && (V_VT(&var) == VT_BOOL && V_BOOL(&var))) + (ct_id == UIA_EditControlTypeId) && variant_to_bool(&var) && !variant_to_bool(&var2)) { if (!keyboard_up) { From cb670501ad473ae6f322e546d871295c5863ce59 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 23 Nov 2021 17:11:26 -0500 Subject: [PATCH 0742/2777] tabtip: Free returned UI Automation element name string. Signed-off-by: Connor McAdams --- programs/tabtip/Makefile.in | 2 +- programs/tabtip/tabtip.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/programs/tabtip/Makefile.in b/programs/tabtip/Makefile.in index 4023382c61b..2b723aea879 100644 --- a/programs/tabtip/Makefile.in +++ b/programs/tabtip/Makefile.in @@ -1,6 +1,6 @@ EXTRADEFS = -DWINE_NO_LONG_TYPES MODULE = tabtip.exe -IMPORTS = uuid ole32 user32 oleacc uiautomationcore rpcrt4 shell32 +IMPORTS = uuid ole32 user32 oleacc uiautomationcore rpcrt4 shell32 oleaut32 EXTRADLLFLAGS = -mconsole -municode -mno-cygwin diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c index 1f6e852b370..e07c5ed6bb4 100644 --- a/programs/tabtip/tabtip.c +++ b/programs/tabtip/tabtip.c @@ -213,6 +213,7 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged WINE_TRACE("element name: %s, ct_id %s, rect { %d, %d } - { %d, %d }\n", wine_dbgstr_w(name), ct_id_str[ct_id], rect.left, rect.top, rect.right, rect.bottom); + SysFreeString(name); } return S_OK; From 99e5d2975cd5764913f9b29a6d3ebc9f3e70fb23 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 23 Nov 2021 17:14:15 -0500 Subject: [PATCH 0743/2777] tabtip: Simplify OSK triggering conditions. Get rid of old, no longer necessary OSK trigger conditions. First is the delay between subsequent OSK trigger events, which was necessary when the big picture mode OSK would steal focus, but no longer applies here. Also allow for the OSK to be triggered even if the last focused control triggered the OSK, as sometimes a subsequent text field is selected without a non-edit control inbetween. Signed-off-by: Connor McAdams --- programs/tabtip/tabtip.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c index e07c5ed6bb4..0f90c1778cd 100644 --- a/programs/tabtip/tabtip.c +++ b/programs/tabtip/tabtip.c @@ -53,7 +53,6 @@ typedef struct { LONG ref; } event_data; -static DWORD last_keyup_event; static BOOL keyboard_up; static BOOL use_steam_osk; @@ -175,26 +174,21 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged IUIAutomationElement_GetCurrentPropertyValue(sender, UIA_IsKeyboardFocusablePropertyId, &var); IUIAutomationElement_GetCurrentPropertyValue(sender, UIA_ValueIsReadOnlyPropertyId, &var2); - if (use_steam_osk && (last_keyup_event < (GetTickCount() - 5000)) && - (ct_id == UIA_EditControlTypeId) && variant_to_bool(&var) && !variant_to_bool(&var2)) + if (use_steam_osk && (ct_id == UIA_EditControlTypeId) && variant_to_bool(&var) && + !variant_to_bool(&var2)) { - if (!keyboard_up) + WINE_TRACE("Keyboard up!\n"); + keyboard_up = TRUE; + if (rect.left || rect.top || rect.right || rect.bottom) { - WINE_TRACE("Keyboard up!\n"); - keyboard_up = TRUE; - if (rect.left || rect.top || rect.right || rect.bottom) - { - WCHAR link_buf[1024]; - - wsprintfW(link_buf, L"steam://open/keyboard?XPosition=%d&YPosition=%d&Width=%d&Height=%d&Mode=0", - rect.left, rect.top, (rect.right - rect.left), (rect.bottom - rect.top)); - ShellExecuteW(NULL, NULL, link_buf, NULL, NULL, SW_SHOWNOACTIVATE); - } - else - ShellExecuteW(NULL, NULL, L"steam://open/keyboard", NULL, NULL, SW_SHOWNOACTIVATE); - - last_keyup_event = GetTickCount(); + WCHAR link_buf[1024]; + + wsprintfW(link_buf, L"steam://open/keyboard?XPosition=%d&YPosition=%d&Width=%d&Height=%d&Mode=0", + rect.left, rect.top, (rect.right - rect.left), (rect.bottom - rect.top)); + ShellExecuteW(NULL, NULL, link_buf, NULL, NULL, SW_SHOWNOACTIVATE); } + else + ShellExecuteW(NULL, NULL, L"steam://open/keyboard", NULL, NULL, SW_SHOWNOACTIVATE); } else { @@ -297,7 +291,6 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine HWND hwnd; wine_exit_event = pgm_exit_event = started_event = NULL; - last_keyup_event = 0; keyboard_up = FALSE; tabtip_use_osk_check(); From 47ea6e8dca69d71d551190405688c2c79825bf6c Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Thu, 20 Oct 2022 10:36:53 -0400 Subject: [PATCH 0744/2777] tabtip: Add support for disabling OSK auto-popup on specific steam app ids. CW-Bug-Id: #21421 --- programs/tabtip/tabtip.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c index 0f90c1778cd..53669fe117b 100644 --- a/programs/tabtip/tabtip.c +++ b/programs/tabtip/tabtip.c @@ -265,6 +265,10 @@ static DWORD WINAPI tabtip_exit_watcher(LPVOID lpParam) return 0; } +static const char *osk_disable_appids[] = { + "1182900", /* A Plague Tale: Requiem */ +}; + static void tabtip_use_osk_check(void) { const char *var = getenv("SteamDeck"); @@ -274,6 +278,21 @@ static void tabtip_use_osk_check(void) else use_steam_osk = FALSE; + if ((var = getenv("SteamAppId"))) + { + int i; + + for (i = 0; i < ARRAY_SIZE(osk_disable_appids); i++) + { + if (!strcmp(var, osk_disable_appids[i])) + { + WINE_TRACE("Disabling OSK auto-popup for appid %s\n", var); + use_steam_osk = FALSE; + break; + } + } + } + WINE_TRACE("use_steam_osk=%d\n", use_steam_osk); } From 898ec70af2d863faeea80d81e2d7781eff56e48d Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 7 Dec 2022 12:47:30 -0500 Subject: [PATCH 0745/2777] tabtip: Add steam app id argument to on-screen keyboard invocation links. CW-Bug-Id: #21613 --- programs/tabtip/tabtip.c | 46 ++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c index 53669fe117b..d9806ecfedb 100644 --- a/programs/tabtip/tabtip.c +++ b/programs/tabtip/tabtip.c @@ -55,6 +55,7 @@ typedef struct { static BOOL keyboard_up; static BOOL use_steam_osk; +static unsigned int steam_app_id; static const char *ct_id_str[] = { "UIA_ButtonControlTypeId (50000)", @@ -163,6 +164,7 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged WINE_TRACE("This %p, sender %p\n", This, sender); if (sender) { + WCHAR link_buf[1024] = { 0 }; RECT rect = { 0 }; VARIANT var, var2; INT ct_id; @@ -177,29 +179,40 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged if (use_steam_osk && (ct_id == UIA_EditControlTypeId) && variant_to_bool(&var) && !variant_to_bool(&var2)) { - WINE_TRACE("Keyboard up!\n"); - keyboard_up = TRUE; + WCHAR *cur_buf_pos = link_buf; + + if (steam_app_id) + cur_buf_pos += wsprintfW(cur_buf_pos, L"steam://open/keyboard?AppID=%d", steam_app_id); + else + cur_buf_pos += wsprintfW(cur_buf_pos, L"steam://open/keyboard"); + if (rect.left || rect.top || rect.right || rect.bottom) { - WCHAR link_buf[1024]; - - wsprintfW(link_buf, L"steam://open/keyboard?XPosition=%d&YPosition=%d&Width=%d&Height=%d&Mode=0", - rect.left, rect.top, (rect.right - rect.left), (rect.bottom - rect.top)); - ShellExecuteW(NULL, NULL, link_buf, NULL, NULL, SW_SHOWNOACTIVATE); + if (steam_app_id) + wsprintfW(cur_buf_pos, L"&XPosition=%d&YPosition=%d&Width=%d&Height=%d&Mode=0", + rect.left, rect.top, (rect.right - rect.left), (rect.bottom - rect.top)); + else + wsprintfW(cur_buf_pos, L"?XPosition=%d&YPosition=%d&Width=%d&Height=%d&Mode=0", + rect.left, rect.top, (rect.right - rect.left), (rect.bottom - rect.top)); } - else - ShellExecuteW(NULL, NULL, L"steam://open/keyboard", NULL, NULL, SW_SHOWNOACTIVATE); + + WINE_TRACE("Keyboard up!\n"); + keyboard_up = TRUE; } - else + else if (keyboard_up) { - if (keyboard_up) - { - WINE_TRACE("Keyboard down!\n"); - ShellExecuteW(NULL, NULL, L"steam://close/keyboard", NULL, NULL, SW_SHOWNOACTIVATE); - keyboard_up = FALSE; - } + if (steam_app_id) + wsprintfW(link_buf, L"steam://close/keyboard?AppID=%d", steam_app_id); + else + wsprintfW(link_buf, L"steam://close/keyboard"); + + WINE_TRACE("Keyboard down!\n"); + keyboard_up = FALSE; } + if (lstrlenW(link_buf)) + ShellExecuteW(NULL, NULL, link_buf, NULL, NULL, SW_SHOWNOACTIVATE); + if (ct_id >= 50000) ct_id -= 50000; else @@ -291,6 +304,7 @@ static void tabtip_use_osk_check(void) break; } } + steam_app_id = strtol(var, NULL, 10); } WINE_TRACE("use_steam_osk=%d\n", use_steam_osk); From 15f093970d28aa4686643952993290d89c4168ae Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Fri, 6 Jan 2023 14:49:16 -0500 Subject: [PATCH 0746/2777] tabtip: Disable OSK auto popup for A Plague Tale: Innocence. A Plague Tale: Innocence spawns a short lived window containing an edit control that is never visible to the user. In order to avoid this triggering the OSK to popup briefly, just disable OSK auto popup for this game. CW-Bug-Id: #21421 --- programs/tabtip/tabtip.c | 1 + 1 file changed, 1 insertion(+) diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c index d9806ecfedb..f7c08ec187a 100644 --- a/programs/tabtip/tabtip.c +++ b/programs/tabtip/tabtip.c @@ -280,6 +280,7 @@ static DWORD WINAPI tabtip_exit_watcher(LPVOID lpParam) static const char *osk_disable_appids[] = { "1182900", /* A Plague Tale: Requiem */ + "752590", /* A Plague Tale: Innocence */ }; static void tabtip_use_osk_check(void) From bd118e20891560fbd2ef27574ad422d582117f4d Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Fri, 10 Feb 2023 15:32:02 -0500 Subject: [PATCH 0747/2777] explorer: Only start tabtip process if desktop window is successfully created. This avoids creating an extra short-lived tabtip process when another process has created the desktop window first. Signed-off-by: Connor McAdams --- programs/explorer/desktop.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c index 4fdeb96e8a3..14b2cbc2aff 100644 --- a/programs/explorer/desktop.c +++ b/programs/explorer/desktop.c @@ -1071,7 +1071,7 @@ void manage_desktop( WCHAR *arg ) GUID guid; MSG msg; HWND hwnd; - HANDLE taptip; + HANDLE tabtip = NULL; HMODULE graphics_driver; unsigned int width, height; WCHAR *cmdline = NULL, *driver = NULL; @@ -1184,12 +1184,12 @@ void manage_desktop( WCHAR *arg ) desktopshellbrowserwindow_init(); shellwindows_init(); - /* FIXME: hack, run tabtip.exe on startup. */ - taptip = start_tabtip_process(); - /* run the desktop message loop */ if (hwnd) { + /* FIXME: hack, run tabtip.exe on startup. */ + tabtip = start_tabtip_process(); + WINE_TRACE( "desktop message loop starting on hwnd %p\n", hwnd ); while (GetMessageW( &msg, 0, 0, 0 )) DispatchMessageW( &msg ); WINE_TRACE( "desktop message loop exiting for hwnd %p\n", hwnd ); @@ -1197,9 +1197,12 @@ void manage_desktop( WCHAR *arg ) if (pShellDDEInit) pShellDDEInit( FALSE ); - TerminateProcess( taptip, 0 ); - WaitForSingleObject( taptip, INFINITE ); - CloseHandle( taptip ); + if (tabtip) + { + TerminateProcess( tabtip, 0 ); + WaitForSingleObject( tabtip, INFINITE ); + CloseHandle( tabtip ); + } ExitProcess( 0 ); } From d3cf94ff5075dcc84c7c37ffc485dd70752620d0 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 20 Dec 2022 14:19:23 -0500 Subject: [PATCH 0748/2777] uiautomationcore: Add support for UIA_BoundingRectanglePropertyId. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 162 +++++++++++++++++++-- dlls/uiautomationcore/uia_client.c | 39 +++++ dlls/uiautomationcore/uia_ids.c | 3 +- 3 files changed, 188 insertions(+), 16 deletions(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 3756b5cbf1a..ec5ab46f8f3 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -1128,8 +1128,10 @@ static struct Provider HWND override_hwnd; struct Provider_prop_override *prop_override; int prop_override_count; + struct UiaRect bounds_rect; } Provider, Provider2, Provider_child, Provider_child2; static struct Provider Provider_hwnd, Provider_nc, Provider_proxy, Provider_proxy2, Provider_override; +static void initialize_provider(struct Provider *prov, int prov_opts, HWND hwnd, BOOL initialize_nav_links); static const WCHAR *uia_bstr_prop_str = L"uia-string"; static const ULONG uia_i4_prop_val = 0xdeadbeef; @@ -1187,6 +1189,8 @@ enum { FRAG_NAVIGATE, FRAG_GET_RUNTIME_ID, FRAG_GET_FRAGMENT_ROOT, + FRAG_GET_BOUNDING_RECT, + FRAG_GET_EMBEDDED_FRAGMENT_ROOTS, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, }; @@ -1197,6 +1201,8 @@ static const char *prov_method_str[] = { "Navigate", "GetRuntimeId", "get_FragmentRoot", + "get_BoundingRectangle", + "GetEmbeddedFragmentRoots", "GetOverrideProviderForHwnd", }; @@ -1891,8 +1897,15 @@ static HRESULT WINAPI ProviderFragment_GetRuntimeId(IRawElementProviderFragment static HRESULT WINAPI ProviderFragment_get_BoundingRectangle(IRawElementProviderFragment *iface, struct UiaRect *ret_val) { - ok(0, "unexpected call\n"); - return E_NOTIMPL; + struct Provider *This = impl_from_ProviderFragment(iface); + + add_method_call(This, FRAG_GET_BOUNDING_RECT); + if (This->expected_tid) + ok(This->expected_tid == GetCurrentThreadId(), "Unexpected tid %ld\n", GetCurrentThreadId()); + This->last_call_tid = GetCurrentThreadId(); + + *ret_val = This->bounds_rect; + return S_OK; } static HRESULT WINAPI ProviderFragment_GetEmbeddedFragmentRoots(IRawElementProviderFragment *iface, @@ -2189,6 +2202,20 @@ DEFINE_PROVIDER(child_child2); DEFINE_PROVIDER(child2_child); DEFINE_PROVIDER(child2_child_child); +/* + * This sequence of method calls is always used when creating an HUIANODE from + * an IRawElementProviderSimple. + */ +#define NODE_CREATE_SEQ(prov) \ + { prov , PROV_GET_PROVIDER_OPTIONS }, \ + /* Win10v1507 and below call this. */ \ + { prov , PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ \ + { prov , PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, \ + { prov , PROV_GET_PROPERTY_VALUE }, \ + { prov , FRAG_NAVIGATE }, /* NavigateDirection_Parent */ \ + { prov , PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL } \ + + static IAccessible *acc_client; static IRawElementProviderSimple *prov_root; static LRESULT WINAPI test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) @@ -4570,6 +4597,80 @@ static const struct prov_method_sequence get_elem_arr_prop_seq[] = { { 0 } }; +static const struct prov_method_sequence get_bounding_rect_seq[] = { + NODE_CREATE_SEQ(&Provider_child), + { &Provider_child, FRAG_GET_BOUNDING_RECT }, + /* + * Win10v21H2+ and above call these, attempting to get the fragment root's + * HWND. I'm guessing this is an attempt to get the HWND's DPI for DPI scaling. + */ + { &Provider_child, FRAG_GET_FRAGMENT_ROOT, METHOD_OPTIONAL }, + { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider, FRAG_GET_FRAGMENT_ROOT, METHOD_OPTIONAL }, + { 0 } +}; + +static const struct prov_method_sequence get_empty_bounding_rect_seq[] = { + { &Provider_child, FRAG_GET_BOUNDING_RECT }, + { 0 } +}; + +static void set_uia_rect(struct UiaRect *rect, double left, double top, double width, double height) +{ + rect->left = left; + rect->top = top; + rect->width = width; + rect->height = height; +} + +#define check_uia_rect_val( v, rect ) \ + check_uia_rect_val_( (v), (rect), __FILE__, __LINE__) +static void check_uia_rect_val_(VARIANT *v, struct UiaRect *rect, const char *file, int line) +{ + LONG lbound, ubound, elems, idx; + SAFEARRAY *sa; + double tmp[4]; + VARTYPE vt; + HRESULT hr; + UINT dims; + + ok_(file, line)(V_VT(v) == (VT_R8 | VT_ARRAY), "Unexpected rect VT hr %d.\n", V_VT(v)); + if (V_VT(v) != (VT_R8 | VT_ARRAY)) + return; + + sa = V_ARRAY(v); + hr = SafeArrayGetVartype(sa, &vt); + ok_(file, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok_(file, line)(vt == VT_R8, "Unexpected vt %d\n", vt); + + dims = SafeArrayGetDim(sa); + ok_(file, line)(dims == 1, "Unexpected dims %d\n", dims); + + lbound = ubound = elems = 0; + hr = SafeArrayGetLBound(sa, 1, &lbound); + ok_(file, line)(hr == S_OK, "Unexpected hr %#lx for SafeArrayGetLBound\n", hr); + ok_(file, line)(lbound == 0, "Unexpected lbound %ld\n", lbound); + + hr = SafeArrayGetUBound(sa, 1, &ubound); + ok_(file, line)(hr == S_OK, "Unexpected hr %#lx for SafeArrayGetUBound\n", hr); + ok_(file, line)(ubound == 3, "Unexpected ubound %ld\n", ubound); + + elems = (ubound - lbound) + 1; + ok_(file, line)(elems == 4, "Unexpected rect elems %ld\n", elems); + + for (idx = 0; idx < ARRAY_SIZE(tmp); idx++) + { + hr = SafeArrayGetElement(sa, &idx, &tmp[idx]); + ok_(file, line)(hr == S_OK, "Unexpected hr %#lx for SafeArrayGetElement at idx %ld.\n", hr, idx); + } + + ok_(file, line)(tmp[0] == rect->left, "Unexpected left value %f, expected %f\n", tmp[0], rect->left); + ok_(file, line)(tmp[1] == rect->top, "Unexpected top value %f, expected %f\n", tmp[1], rect->top); + ok_(file, line)(tmp[2] == rect->width, "Unexpected width value %f, expected %f\n", tmp[2], rect->width); + ok_(file, line)(tmp[3] == rect->height, "Unexpected height value %f, expected %f\n", tmp[3], rect->height); +} + static void check_uia_prop_val(PROPERTYID prop_id, enum UIAutomationType type, VARIANT *v) { LONG idx; @@ -4765,6 +4866,7 @@ static const struct uia_element_property element_properties[] = { static void test_UiaGetPropertyValue(void) { const struct uia_element_property *elem_prop; + struct UiaRect rect; IUnknown *unk_ns; unsigned int i; HUIANODE node; @@ -4831,6 +4933,48 @@ static void test_UiaGetPropertyValue(void) ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref); + /* + * Windows 7 will call get_FragmentRoot in an endless loop until the fragment root returns an HWND. + * It's the only version with this behavior. + */ + if (!UiaLookupId(AutomationIdentifierType_Property, &OptimizeForVisualContent_Property_GUID)) + { + win_skip("Skipping UIA_BoundingRectanglePropertyId tests for Win7\n"); + goto exit; + } + + initialize_provider(&Provider, ProviderOptions_ServerSideProvider, NULL, FALSE); + initialize_provider(&Provider_child, ProviderOptions_ServerSideProvider, NULL, FALSE); + node = (void *)0xdeadbeef; + hr = UiaNodeFromProvider(&Provider_child.IRawElementProviderSimple_iface, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_child.ref); + + /* Non-empty bounding rectangle, will return a VT_R8 SAFEARRAY. */ + set_uia_rect(&rect, 0, 0, 50, 50); + Provider_child.bounds_rect = rect; + hr = UiaGetPropertyValue(node, UIA_BoundingRectanglePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_uia_rect_val(&v, &rect); + VariantClear(&v); + + ok_method_sequence(get_bounding_rect_seq, "get_bounding_rect_seq"); + + /* Empty bounding rectangle will return ReservedNotSupportedValue. */ + set_uia_rect(&rect, 0, 0, 0, 0); + Provider_child.bounds_rect = rect; + hr = UiaGetPropertyValue(node, UIA_BoundingRectanglePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(V_VT(&v) == VT_UNKNOWN, "Unexpected vt %d\n", V_VT(&v)); + ok(V_UNKNOWN(&v) == unk_ns, "unexpected IUnknown %p\n", V_UNKNOWN(&v)); + VariantClear(&v); + ok_method_sequence(get_empty_bounding_rect_seq, "get_empty_bounding_rect_seq"); + + ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); + ok(Provider_child.ref == 1, "Unexpected refcnt %ld\n", Provider_child.ref); + initialize_provider(&Provider_child, ProviderOptions_ServerSideProvider, NULL, FALSE); + +exit: IUnknown_Release(unk_ns); CoUninitialize(); } @@ -6901,19 +7045,6 @@ static void test_cache_req_sa_(SAFEARRAY *sa, LONG exp_lbound[2], LONG exp_elems } } -/* - * This sequence of method calls is always used when creating an HUIANODE from - * an IRawElementProviderSimple. - */ -#define NODE_CREATE_SEQ(prov) \ - { prov , PROV_GET_PROVIDER_OPTIONS }, \ - /* Win10v1507 and below call this. */ \ - { prov , PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ \ - { prov , PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, \ - { prov , PROV_GET_PROPERTY_VALUE }, \ - { prov , FRAG_NAVIGATE }, /* NavigateDirection_Parent */ \ - { prov , PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL } \ - static const struct prov_method_sequence cache_req_seq1[] = { { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId. */ { 0 } @@ -8240,6 +8371,7 @@ static void initialize_provider(struct Provider *prov, int prov_opts, HWND hwnd, prov->override_hwnd = NULL; prov->prop_override = NULL; prov->prop_override_count = 0; + memset(&prov->bounds_rect, 0, sizeof(prov->bounds_rect)); if (initialize_nav_links) { prov->frag_root = NULL; diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 14f9977a4d6..860a917c423 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -1391,6 +1391,45 @@ static HRESULT uia_provider_get_special_prop_val(struct uia_provider *prov, break; } + case UIA_BoundingRectanglePropertyId: + { + IRawElementProviderFragment *elfrag; + struct UiaRect rect = { 0 }; + double rect_vals[4]; + SAFEARRAY *sa; + LONG idx; + + hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderFragment, (void **)&elfrag); + if (FAILED(hr) || !elfrag) + break; + + hr = IRawElementProviderFragment_get_BoundingRectangle(elfrag, &rect); + IRawElementProviderFragment_Release(elfrag); + if (FAILED(hr) || (rect.width <= 0 || rect.height <= 0)) + break; + + if (!(sa = SafeArrayCreateVector(VT_R8, 0, ARRAY_SIZE(rect_vals)))) + break; + + rect_vals[0] = rect.left; + rect_vals[1] = rect.top; + rect_vals[2] = rect.width; + rect_vals[3] = rect.height; + for (idx = 0; idx < ARRAY_SIZE(rect_vals); idx++) + { + hr = SafeArrayPutElement(sa, &idx, &rect_vals[idx]); + if (FAILED(hr)) + { + SafeArrayDestroy(sa); + break; + } + } + + V_VT(ret_val) = VT_R8 | VT_ARRAY; + V_ARRAY(ret_val) = sa; + break; + } + default: break; } diff --git a/dlls/uiautomationcore/uia_ids.c b/dlls/uiautomationcore/uia_ids.c index a3a60c8aec9..53e0f70b38d 100644 --- a/dlls/uiautomationcore/uia_ids.c +++ b/dlls/uiautomationcore/uia_ids.c @@ -211,7 +211,8 @@ static const struct uia_prop_info default_uia_properties[] = { PROP_TYPE_ELEM_PROP, UIAutomationType_Bool, }, { &IsWindowPatternAvailable_Property_GUID, UIA_IsWindowPatternAvailablePropertyId, }, { &RangeValue_Minimum_Property_GUID, UIA_RangeValueMinimumPropertyId, }, - { &BoundingRectangle_Property_GUID, UIA_BoundingRectanglePropertyId, }, + { &BoundingRectangle_Property_GUID, UIA_BoundingRectanglePropertyId, + PROP_TYPE_SPECIAL, UIAutomationType_Rect, }, { &LegacyIAccessible_Value_Property_GUID, UIA_LegacyIAccessibleValuePropertyId, }, { &IsDragPatternAvailable_Property_GUID, UIA_IsDragPatternAvailablePropertyId, }, { &DescribedBy_Property_GUID, UIA_DescribedByPropertyId, From 20c9c3f0421725447226697e010b63c83c515579 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 7 Nov 2022 07:40:30 -0500 Subject: [PATCH 0749/2777] uiautomationcore: Implement get_BoundingRectangle for MSAA providers. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 79 ++++++++++++++++++++++ dlls/uiautomationcore/uia_provider.c | 30 +++++++- 2 files changed, 107 insertions(+), 2 deletions(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index ec5ab46f8f3..687283f1ccc 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -3334,7 +3334,9 @@ static void test_UiaProviderFromIAccessible(void) { ILegacyIAccessibleProvider *accprov; IRawElementProviderSimple *elprov, *elprov2; + IRawElementProviderFragment *elfrag; enum ProviderOptions prov_opt; + struct UiaRect rect; IAccessible *acc; IUnknown *unk; WNDCLASSA cls; @@ -3852,6 +3854,83 @@ static void test_UiaProviderFromIAccessible(void) IRawElementProviderSimple_Release(elprov); ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref); + /* + * Test IRawElementProviderFragment_get_BoundingRectangle. + */ + set_accessible_props(&Accessible, ROLE_SYSTEM_DOCUMENT, STATE_SYSTEM_FOCUSABLE, 0, L"acc_name", 25, 25, 50, 50); + /* Test the case where Accessible is not the root for its HWND. */ + acc_client = NULL; + hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); + + hr = IRawElementProviderSimple_QueryInterface(elprov, &IID_IRawElementProviderFragment, (void **)&elfrag); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!elfrag, "elfrag == NULL\n"); + + SET_EXPECT(winproc_GETOBJECT_CLIENT); + SET_EXPECT(Accessible_get_accRole); + SET_EXPECT(Accessible_get_accState); + SET_EXPECT(Accessible_accLocation); + hr = IRawElementProviderFragment_get_BoundingRectangle(elfrag, &rect); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(rect.left == (double)Accessible.left, "Unexpected left value %f\n", rect.left); + ok(rect.top == (double)Accessible.top, "Unexpected top value %f\n", rect.top); + ok(rect.width == (double)Accessible.width, "Unexpected width value %f\n", rect.width); + ok(rect.height == (double)Accessible.height, "Unexpected height value %f\n", rect.height); + CHECK_CALLED(winproc_GETOBJECT_CLIENT); + CHECK_CALLED(Accessible_get_accRole); + CHECK_CALLED(Accessible_get_accState); + CHECK_CALLED(Accessible_accLocation); + + /* If Accessible has STATE_SYSTEM_OFFSCREEN, it will return an empty rect. */ + set_accessible_props(&Accessible, ROLE_SYSTEM_DOCUMENT, STATE_SYSTEM_OFFSCREEN, 0, L"acc_name", 0, 0, 50, 50); + SET_EXPECT(Accessible_get_accState); + hr = IRawElementProviderFragment_get_BoundingRectangle(elfrag, &rect); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(rect.left == 0.0, "Unexpected left value %f\n", rect.left); + ok(rect.top == 0.0, "Unexpected top value %f\n", rect.top); + ok(rect.width == 0.0, "Unexpected width value %f\n", rect.width); + ok(rect.height == 0.0, "Unexpected height value %f\n", rect.height); + CHECK_CALLED(Accessible_get_accState); + + IRawElementProviderFragment_Release(elfrag); + IRawElementProviderSimple_Release(elprov); + ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref); + + /* Test case where accessible is the root accessible. */ + set_accessible_props(&Accessible, ROLE_SYSTEM_DOCUMENT, 0, 0, L"acc_name", 0, 0, 0, 0); + acc_client = &Accessible.IAccessible_iface; + hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); + + hr = IRawElementProviderSimple_QueryInterface(elprov, &IID_IRawElementProviderFragment, (void **)&elfrag); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!elfrag, "elfrag == NULL\n"); + + SET_EXPECT(winproc_GETOBJECT_CLIENT); + hr = IRawElementProviderFragment_get_BoundingRectangle(elfrag, &rect); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(rect.left == 0.0, "Unexpected left value %f\n", rect.left); + ok(rect.top == 0.0, "Unexpected top value %f\n", rect.top); + ok(rect.width == 0.0, "Unexpected width value %f\n", rect.width); + ok(rect.height == 0.0, "Unexpected height value %f\n", rect.height); + CHECK_CALLED(winproc_GETOBJECT_CLIENT); + + /* Second call does nothing. */ + hr = IRawElementProviderFragment_get_BoundingRectangle(elfrag, &rect); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(rect.left == 0.0, "Unexpected left value %f\n", rect.left); + ok(rect.top == 0.0, "Unexpected top value %f\n", rect.top); + ok(rect.width == 0.0, "Unexpected width value %f\n", rect.width); + ok(rect.height == 0.0, "Unexpected height value %f\n", rect.height); + + IRawElementProviderFragment_Release(elfrag); + IRawElementProviderSimple_Release(elprov); + ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref); + acc_client = NULL; + test_uia_prov_from_acc_properties(); test_uia_prov_from_acc_navigation(); test_uia_prov_from_acc_ia2(); diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index fc718fabe43..a207c840ede 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -874,8 +874,34 @@ static HRESULT WINAPI msaa_fragment_GetRuntimeId(IRawElementProviderFragment *if static HRESULT WINAPI msaa_fragment_get_BoundingRectangle(IRawElementProviderFragment *iface, struct UiaRect *ret_val) { - FIXME("%p, %p: stub!\n", iface, ret_val); - return E_NOTIMPL; + struct msaa_provider *msaa_prov = impl_from_msaa_fragment(iface); + LONG left, top, width, height; + HRESULT hr; + + TRACE("%p, %p\n", iface, ret_val); + + memset(ret_val, 0, sizeof(*ret_val)); + + /* + * If this IAccessible is at the root of its HWND, the BaseHwnd provider + * will supply the bounding rectangle. + */ + if (msaa_check_root_acc(msaa_prov)) + return S_OK; + + if (msaa_check_acc_state(msaa_prov->acc, msaa_prov->cid, STATE_SYSTEM_OFFSCREEN)) + return S_OK; + + hr = IAccessible_accLocation(msaa_prov->acc, &left, &top, &width, &height, msaa_prov->cid); + if (FAILED(hr)) + return hr; + + ret_val->left = left; + ret_val->top = top; + ret_val->width = width; + ret_val->height = height; + + return S_OK; } static HRESULT WINAPI msaa_fragment_GetEmbeddedFragmentRoots(IRawElementProviderFragment *iface, From 9223658893f35349ac3a04b177525c3112e11162 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 7 Nov 2022 09:42:19 -0500 Subject: [PATCH 0750/2777] uiautomationcore: Add support for UIA_NamePropertyId to MSAA providers. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 28 ++++++++++++++++++++++ dlls/uiautomationcore/uia_provider.c | 13 ++++++++++ 2 files changed, 41 insertions(+) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 687283f1ccc..87b0be1608a 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -3328,6 +3328,34 @@ static void test_uia_prov_from_acc_properties(void) IRawElementProviderSimple_Release(elprov); ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref); + + /* UIA_NamePropertyId tests. */ + set_accessible_props(&Accessible, 0, 0, 0, L"Accessible", 0, 0, 0, 0); + hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); + + SET_EXPECT(Accessible_get_accName); + VariantInit(&v); + hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_NamePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(V_VT(&v) == VT_BSTR, "Unexpected VT %d\n", V_VT(&v)); + ok(!lstrcmpW(V_BSTR(&v), Accessible.name), "Unexpected BSTR %s\n", wine_dbgstr_w(V_BSTR(&v))); + VariantClear(&v); + CHECK_CALLED(Accessible_get_accName); + + /* Name is not cached. */ + set_accessible_props(&Accessible, 0, 0, 0, L"Accessible2", 0, 0, 0, 0); + SET_EXPECT(Accessible_get_accName); + hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_NamePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(V_VT(&v) == VT_BSTR, "Unexpected VT %d\n", V_VT(&v)); + ok(!lstrcmpW(V_BSTR(&v), Accessible.name), "Unexpected BSTR %s\n", wine_dbgstr_w(V_BSTR(&v))); + VariantClear(&v); + CHECK_CALLED(Accessible_get_accName); + + IRawElementProviderSimple_Release(elprov); + ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref); } static void test_UiaProviderFromIAccessible(void) diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index a207c840ede..da533157cbd 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -670,6 +670,19 @@ HRESULT WINAPI msaa_provider_GetPropertyValue(IRawElementProviderSimple *iface, STATE_SYSTEM_PROTECTED)); break; + case UIA_NamePropertyId: + { + BSTR name; + + hr = IAccessible_get_accName(msaa_prov->acc, msaa_prov->cid, &name); + if (SUCCEEDED(hr) && name) + { + V_VT(ret_val) = VT_BSTR; + V_BSTR(ret_val) = name; + } + break; + } + default: FIXME("Unimplemented propertyId %d\n", prop_id); break; From b0f9776186b11460d09d4737ee24fb5b55b1ac24 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 7 Nov 2022 14:44:39 -0500 Subject: [PATCH 0751/2777] uiautomationcore: Partially implement UiaProviderForNonClient. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 123 +++++++++++++++ dlls/uiautomationcore/uia_provider.c | 159 ++++++++++++++++++++ dlls/uiautomationcore/uiautomationcore.spec | 2 +- include/uiautomationcoreapi.h | 1 + 4 files changed, 284 insertions(+), 1 deletion(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 87b0be1608a..188f980f36f 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -29,6 +29,7 @@ #include "wine/test.h" static HRESULT (WINAPI *pUiaProviderFromIAccessible)(IAccessible *, long, DWORD, IRawElementProviderSimple **); +static HRESULT (WINAPI *pUiaProviderForNonClient)(HWND, long, long, IRawElementProviderSimple **); static HRESULT (WINAPI *pUiaDisconnectProvider)(IRawElementProviderSimple *); #define DEFINE_EXPECT(func) \ @@ -68,6 +69,7 @@ static HRESULT (WINAPI *pUiaDisconnectProvider)(IRawElementProviderSimple *); #define UIA_RUNTIME_ID_PREFIX 42 DEFINE_EXPECT(winproc_GETOBJECT_CLIENT); +DEFINE_EXPECT(winproc_GETOBJECT); DEFINE_EXPECT(prov_callback_base_hwnd); DEFINE_EXPECT(prov_callback_nonclient); DEFINE_EXPECT(prov_callback_proxy); @@ -2218,11 +2220,18 @@ DEFINE_PROVIDER(child2_child_child); static IAccessible *acc_client; static IRawElementProviderSimple *prov_root; +static LPARAM exp_objid; static LRESULT WINAPI test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_GETOBJECT: + if (exp_objid) + { + CHECK_EXPECT(winproc_GETOBJECT); + ok(exp_objid == lParam, "Unexpected objid %ld\n", lParam); + } + if (lParam == (DWORD)OBJID_CLIENT) { CHECK_EXPECT(winproc_GETOBJECT_CLIENT); @@ -9414,6 +9423,114 @@ static void test_UiaFind(void) CoUninitialize(); } +static const long nc_objids[] = { OBJID_VSCROLL, OBJID_HSCROLL, OBJID_TITLEBAR, OBJID_MENU, OBJID_SIZEGRIP }; +static void test_UiaProviderForNonClient(void) +{ + IRawElementProviderSimple *elprov, *elprov2; + enum ProviderOptions prov_opts; + WNDCLASSA cls; + HRESULT hr; + HWND hwnd; + VARIANT v; + int i; + + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + cls.style = 0; + cls.lpfnWndProc = test_wnd_proc; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(NULL); + cls.hIcon = 0; + cls.hCursor = NULL; + cls.hbrBackground = NULL; + cls.lpszMenuName = NULL; + cls.lpszClassName = "UiaProviderForNonClient class"; + + RegisterClassA(&cls); + + hr = pUiaProviderForNonClient(NULL, OBJID_WINDOW, CHILDID_SELF, &elprov); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + ok(!elprov, "elprov != NULL\n"); + + hr = pUiaProviderForNonClient((HWND)0xdeadbeef, OBJID_WINDOW, CHILDID_SELF, &elprov); + ok(hr == UIA_E_ELEMENTNOTAVAILABLE, "Unexpected hr %#lx.\n", hr); + ok(!elprov, "elprov != NULL\n"); + + hwnd = CreateWindowA("UiaProviderForNonClient class", "Test window", WS_OVERLAPPEDWINDOW, + 0, 0, 100, 100, NULL, NULL, NULL, NULL); + + /* OBJID_CLIENT isn't a valid object id. */ + hr = pUiaProviderForNonClient(hwnd, OBJID_CLIENT, CHILDID_SELF, &elprov); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + ok(!elprov, "elprov != NULL\n"); + + /* NULL elprov. */ + hr = pUiaProviderForNonClient(hwnd, OBJID_WINDOW, CHILDID_SELF, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + /* OBJID_WINDOW gets the nonclient provider for the entire HWND. */ + hr = pUiaProviderForNonClient(hwnd, OBJID_WINDOW, CHILDID_SELF, &elprov); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!elprov, "elprov == NULL\n"); + + hr = IRawElementProviderSimple_get_ProviderOptions(elprov, &prov_opts); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(prov_opts == (ProviderOptions_ClientSideProvider | ProviderOptions_NonClientAreaProvider | + ProviderOptions_ProviderOwnsSetFocus), "Unexpected provider options %#x\n", prov_opts); + + VariantInit(&v); + hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_ProviderDescriptionPropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(V_VT(&v) == VT_BSTR, "V_VT(&v) = %d\n", V_VT(&v)); + VariantClear(&v); + + hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_IsKeyboardFocusablePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(V_VT(&v) == VT_BOOL, "V_VT(&v) = %d\n", V_VT(&v)); + ok(check_variant_bool(&v, TRUE), "V_BOOL(&v) = %#x\n", V_BOOL(&v)); + VariantClear(&v); + + hr = IRawElementProviderSimple_get_HostRawElementProvider(elprov, &elprov2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!elprov2, "elprov == NULL, elprov %p\n", elprov2); + IRawElementProviderSimple_Release(elprov2); + + IRawElementProviderSimple_Release(elprov); + + /* Test each valid nonclient area OBJID. */ + for (i = 0; i < ARRAY_SIZE(nc_objids); i++) + { + exp_objid = nc_objids[i]; + SET_EXPECT(winproc_GETOBJECT); + hr = pUiaProviderForNonClient(hwnd, nc_objids[i], CHILDID_SELF, &elprov); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(!!elprov, "elprov == NULL\n"); + todo_wine CHECK_CALLED(winproc_GETOBJECT); + + if (!elprov) + continue; + + hr = IRawElementProviderSimple_get_ProviderOptions(elprov, &prov_opts); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(prov_opts == (ProviderOptions_ClientSideProvider | ProviderOptions_UseComThreading), + "Unexpected provider options %#x\n", prov_opts); + + hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_ProviderDescriptionPropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(V_VT(&v) == VT_BSTR, "V_VT(&v) = %d\n", V_VT(&v)); + VariantClear(&v); + + IRawElementProviderSimple_Release(elprov); + } + + exp_objid = 0; + + DestroyWindow(hwnd); + UnregisterClassA("UiaProviderForNonClient class", NULL); + CoUninitialize(); +} + /* * Once a process returns a UI Automation provider with * UiaReturnRawElementProvider it ends up in an implicit MTA until exit. This @@ -9488,6 +9605,12 @@ START_TEST(uiautomation) else win_skip("UiaProviderFromIAccessible not exported by uiautomationcore.dll\n"); + pUiaProviderForNonClient = (void *)GetProcAddress(uia_dll, "UiaProviderForNonClient"); + if (pUiaProviderForNonClient) + test_UiaProviderForNonClient(); + else + win_skip("UiaProviderForNonClient not exported by uiautomationcore.dll\n"); + FreeLibrary(uia_dll); } } diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index da533157cbd..4fb57e1013d 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -1165,6 +1165,165 @@ HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD return S_OK; } +/* + * UiaProviderForNonClient IRawElementProviderSimple interface. + */ +struct nc_provider { + IRawElementProviderSimple IRawElementProviderSimple_iface; + LONG refcount; + + HWND hwnd; +}; + +static inline struct nc_provider *impl_from_nc_provider(IRawElementProviderSimple *iface) +{ + return CONTAINING_RECORD(iface, struct nc_provider, IRawElementProviderSimple_iface); +} + +HRESULT WINAPI nc_provider_QueryInterface(IRawElementProviderSimple *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IRawElementProviderSimple) || IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else + return E_NOINTERFACE; + + IRawElementProviderSimple_AddRef(iface); + return S_OK; +} + +ULONG WINAPI nc_provider_AddRef(IRawElementProviderSimple *iface) +{ + struct nc_provider *nc_prov = impl_from_nc_provider(iface); + ULONG refcount = InterlockedIncrement(&nc_prov->refcount); + + TRACE("%p, refcount %ld\n", iface, refcount); + + return refcount; +} + +ULONG WINAPI nc_provider_Release(IRawElementProviderSimple *iface) +{ + struct nc_provider *nc_prov = impl_from_nc_provider(iface); + ULONG refcount = InterlockedDecrement(&nc_prov->refcount); + + TRACE("%p, refcount %ld\n", iface, refcount); + + if (!refcount) + { + heap_free(nc_prov); + } + + return refcount; +} + +HRESULT WINAPI nc_provider_get_ProviderOptions(IRawElementProviderSimple *iface, + enum ProviderOptions *ret_val) +{ + TRACE("%p, %p\n", iface, ret_val); + *ret_val = ProviderOptions_ClientSideProvider | ProviderOptions_NonClientAreaProvider | + ProviderOptions_ProviderOwnsSetFocus; + return S_OK; +} + +HRESULT WINAPI nc_provider_GetPatternProvider(IRawElementProviderSimple *iface, + PATTERNID pattern_id, IUnknown **ret_val) +{ + FIXME("%p, %d, %p: stub\n", iface, pattern_id, ret_val); + *ret_val = NULL; + return E_NOTIMPL; +} + +HRESULT WINAPI nc_provider_GetPropertyValue(IRawElementProviderSimple *iface, + PROPERTYID prop_id, VARIANT *ret_val) +{ + TRACE("%p, %d, %p\n", iface, prop_id, ret_val); + + VariantInit(ret_val); + switch (prop_id) + { + case UIA_ProviderDescriptionPropertyId: + V_VT(ret_val) = VT_BSTR; + V_BSTR(ret_val) = SysAllocString(L"Wine: Non-Client Proxy"); + break; + + case UIA_IsKeyboardFocusablePropertyId: + variant_init_bool(ret_val, TRUE); + break; + + default: + break; + } + + return S_OK; +} + +HRESULT WINAPI nc_provider_get_HostRawElementProvider(IRawElementProviderSimple *iface, + IRawElementProviderSimple **ret_val) +{ + struct nc_provider *nc_prov = impl_from_nc_provider(iface); + + TRACE("%p, %p\n", iface, ret_val); + + return UiaHostProviderFromHwnd(nc_prov->hwnd, ret_val); +} + +static const IRawElementProviderSimpleVtbl nc_provider_vtbl = { + nc_provider_QueryInterface, + nc_provider_AddRef, + nc_provider_Release, + nc_provider_get_ProviderOptions, + nc_provider_GetPatternProvider, + nc_provider_GetPropertyValue, + nc_provider_get_HostRawElementProvider, +}; + +HRESULT WINAPI UiaProviderForNonClient(HWND hwnd, long objid, long child_id, + IRawElementProviderSimple **elprov) +{ + TRACE("(%p, %ld, %ld, %p): stub\n", hwnd, objid, child_id, elprov); + + if (!elprov) + return E_INVALIDARG; + + *elprov = NULL; + if (!hwnd) + return E_INVALIDARG; + + if (!IsWindow(hwnd)) + return UIA_E_ELEMENTNOTAVAILABLE; + + switch (objid) + { + case OBJID_WINDOW: + { + struct nc_provider *nc_prov = heap_alloc_zero(sizeof(*nc_prov)); + + if (!nc_prov) + return E_OUTOFMEMORY; + + nc_prov->IRawElementProviderSimple_iface.lpVtbl = &nc_provider_vtbl; + nc_prov->refcount = 1; + nc_prov->hwnd = hwnd; + *elprov = &nc_prov->IRawElementProviderSimple_iface; + break; + } + + case OBJID_VSCROLL: + case OBJID_HSCROLL: + case OBJID_TITLEBAR: + case OBJID_MENU: + case OBJID_SIZEGRIP: + FIXME("Nonclient proxy for objid %ld currently unimplemented\n", objid); + return E_NOTIMPL; + + default: + return E_INVALIDARG; + } + + return S_OK; +} + /* * UI Automation provider thread functions. */ diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec index 11ca7be7f97..390fe2f07f5 100644 --- a/dlls/uiautomationcore/uiautomationcore.spec +++ b/dlls/uiautomationcore/uiautomationcore.spec @@ -82,7 +82,7 @@ @ stdcall UiaNodeFromProvider(ptr ptr) @ stdcall UiaNodeRelease(ptr) @ stub UiaPatternRelease -#@ stub UiaProviderForNonClient +@ stdcall UiaProviderForNonClient(ptr long long ptr) @ stdcall UiaProviderFromIAccessible(ptr long long ptr) @ stub UiaRaiseAsyncContentLoadedEvent @ stdcall UiaRaiseAutomationEvent(ptr long) diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h index ef94c72d162..6e60db4a76d 100644 --- a/include/uiautomationcoreapi.h +++ b/include/uiautomationcoreapi.h @@ -424,6 +424,7 @@ HRESULT WINAPI UiaAddEvent(HUIANODE huianode, EVENTID event_id, UiaEventCallback HRESULT WINAPI UiaRemoveEvent(HUIAEVENT huiaevent); HRESULT WINAPI UiaEventAddWindow(HUIAEVENT huiaevent, HWND hwnd); HRESULT WINAPI UiaEventRemoveWindow(HUIAEVENT huiaevent, HWND hwnd); +HRESULT WINAPI UiaProviderForNonClient(HWND hwnd, long objid, long child_id, IRawElementProviderSimple **elprov); #ifdef __cplusplus } From 955371aa6d08de3ed9ddfa120ef6ed27f523f619 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 20 Dec 2022 14:36:49 -0500 Subject: [PATCH 0752/2777] uiautomationcore: Add support for default ProviderType_Proxy. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 244 ++++++++++++++++++++- dlls/uiautomationcore/uia_client.c | 30 ++- dlls/uiautomationcore/uia_private.h | 2 + dlls/uiautomationcore/uia_provider.c | 60 +++-- 4 files changed, 304 insertions(+), 32 deletions(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 188f980f36f..ed7abb22887 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -85,6 +85,7 @@ DEFINE_EXPECT(Accessible_get_accState); DEFINE_EXPECT(Accessible_accLocation); DEFINE_EXPECT(Accessible_get_accChild); DEFINE_EXPECT(Accessible_get_uniqueID); +DEFINE_EXPECT(Accessible_QI_IAccIdentity); DEFINE_EXPECT(Accessible2_get_accParent); DEFINE_EXPECT(Accessible2_get_accChildCount); DEFINE_EXPECT(Accessible2_get_accName); @@ -172,7 +173,10 @@ static HRESULT WINAPI Accessible_QueryInterface(IAccessible *iface, REFIID riid, { if (This == &Accessible2) CHECK_EXPECT(Accessible2_QI_IAccIdentity); - ok(This == &Accessible2, "unexpected call\n"); + else if (This == &Accessible) + CHECK_EXPECT(Accessible_QI_IAccIdentity); + + ok(This == &Accessible2 || This == &Accessible, "unexpected call\n"); return E_NOINTERFACE; } @@ -6071,7 +6075,7 @@ static void test_UiaNodeFromHandle(const char *name) hr = UiaNodeFromHandle(hwnd, &node); todo_wine ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); CHECK_CALLED(winproc_GETOBJECT_UiaRoot); - todo_wine CHECK_CALLED(winproc_GETOBJECT_CLIENT); + CHECK_CALLED(winproc_GETOBJECT_CLIENT); /* * COM initialized, no provider returned by UiaReturnRawElementProvider. @@ -6083,9 +6087,9 @@ static void test_UiaNodeFromHandle(const char *name) SET_EXPECT(winproc_GETOBJECT_UiaRoot); SET_EXPECT_MULTI(winproc_GETOBJECT_CLIENT, 2); hr = UiaNodeFromHandle(hwnd, &node); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); CHECK_CALLED(winproc_GETOBJECT_UiaRoot); - todo_wine CHECK_CALLED(winproc_GETOBJECT_CLIENT); + CHECK_CALLED(winproc_GETOBJECT_CLIENT); hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); @@ -6099,7 +6103,7 @@ static void test_UiaNodeFromHandle(const char *name) VariantClear(&v); } - todo_wine ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); + ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); /* * COM initialized, but provider passed into UiaReturnRawElementProvider @@ -6112,9 +6116,9 @@ static void test_UiaNodeFromHandle(const char *name) SET_EXPECT(winproc_GETOBJECT_UiaRoot); SET_EXPECT_MULTI(winproc_GETOBJECT_CLIENT, 2); hr = UiaNodeFromHandle(hwnd, &node); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); CHECK_CALLED(winproc_GETOBJECT_UiaRoot); - todo_wine CHECK_CALLED(winproc_GETOBJECT_CLIENT); + CHECK_CALLED(winproc_GETOBJECT_CLIENT); hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); @@ -6129,7 +6133,7 @@ static void test_UiaNodeFromHandle(const char *name) } ok_method_sequence(node_from_hwnd1, "node_from_hwnd1"); - todo_wine ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); + ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); /* * COM initialized, but provider passed into UiaReturnRawElementProvider @@ -6148,10 +6152,10 @@ static void test_UiaNodeFromHandle(const char *name) Provider.runtime_id[0] = UiaAppendRuntimeId; Provider.runtime_id[1] = 1; hr = UiaNodeFromHandle(hwnd, &node); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(Provider.ref == 1 || broken(Provider.ref == 2), "Unexpected refcnt %ld\n", Provider.ref); CHECK_CALLED(winproc_GETOBJECT_UiaRoot); - todo_wine CHECK_CALLED(winproc_GETOBJECT_CLIENT); + CHECK_CALLED(winproc_GETOBJECT_CLIENT); hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); @@ -6172,7 +6176,7 @@ static void test_UiaNodeFromHandle(const char *name) VariantClear(&v); } ok_method_sequence(node_from_hwnd9, "node_from_hwnd9"); - todo_wine ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); + ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); /* * Bug on Windows 8 through Win10v1709 - if we have a RuntimeId failure, * refcount doesn't get decremented. @@ -9531,6 +9535,223 @@ static void test_UiaProviderForNonClient(void) CoUninitialize(); } +static void test_default_proxy_providers(void) +{ + struct node_provider_desc exp_node_desc[4]; + LONG exp_lbound[2], exp_elems[2], i; + struct UiaCacheRequest cache_req; + SAFEARRAY *out_req; + BSTR tree_struct; + HWND hwnd, hwnd2; + HUIANODE node; + WNDCLASSA cls; + HRESULT hr; + VARIANT v; + + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + cls.style = 0; + cls.lpfnWndProc = test_wnd_proc; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(NULL); + cls.hIcon = 0; + cls.hCursor = NULL; + cls.hbrBackground = NULL; + cls.lpszMenuName = NULL; + cls.lpszClassName = "default_proxy_provider class"; + + RegisterClassA(&cls); + + cls.lpfnWndProc = child_test_wnd_proc; + cls.lpszClassName = "default_proxy_provider child class"; + RegisterClassA(&cls); + + hwnd = CreateWindowA("default_proxy_provider class", "Test window", WS_OVERLAPPEDWINDOW, + 0, 0, 100, 100, NULL, NULL, NULL, NULL); + + prov_root = NULL; + acc_client = &Accessible.IAccessible_iface; + + initialize_provider(&Provider, ProviderOptions_ClientSideProvider, hwnd, FALSE); + set_accessible_props(&Accessible, ROLE_SYSTEM_TEXT, STATE_SYSTEM_FOCUSABLE, 0, L"Accessible", 0, 0, 20, 20); + ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref); + + SET_EXPECT(Accessible_QI_IAccIdentity); + SET_EXPECT(Accessible_get_accParent); + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(winproc_GETOBJECT_CLIENT); + hr = UiaNodeFromProvider(&Provider.IRawElementProviderSimple_iface, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + ok(Accessible.ref > 1, "Unexpected refcnt %ld\n", Accessible.ref); + todo_wine CHECK_CALLED(Accessible_QI_IAccIdentity); + todo_wine CHECK_CALLED(Accessible_get_accParent); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(winproc_GETOBJECT_CLIENT); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Nonclient", NULL, FALSE); + check_node_provider_desc(V_BSTR(&v), L"Main", NULL, TRUE); + VariantClear(&v); + } + + SET_EXPECT(Accessible_get_accRole); + hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(V_VT(&v) == VT_I4, "Unexpected VT %d\n", V_VT(&v)); + ok(V_I4(&v) == UIA_EditControlTypeId, "Unexpected I4 %#lx\n", V_I4(&v)); + VariantClear(&v); + CHECK_CALLED(Accessible_get_accRole); + + UiaNodeRelease(node); + ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref); + ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref); + + /* + * Test default edit MSAA proxy. + */ + hwnd2 = CreateWindowA("EDIT", "", WS_VISIBLE | WS_CHILD | ES_PASSWORD, + 0, 0, 100, 100, hwnd, NULL, NULL, NULL); + initialize_provider(&Provider, ProviderOptions_ClientSideProvider, hwnd2, FALSE); + + /* Tries to get override provider from parent HWND. */ + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + hr = UiaNodeFromProvider(&Provider.IRawElementProviderSimple_iface, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Main", NULL, FALSE); + check_node_provider_desc(V_BSTR(&v), L"Annotation", NULL, TRUE); + VariantClear(&v); + } + + hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(V_VT(&v) == VT_I4, "Unexpected VT %d\n", V_VT(&v)); + ok(V_I4(&v) == UIA_EditControlTypeId, "Unexpected I4 %#lx\n", V_I4(&v)); + VariantClear(&v); + + hr = UiaGetPropertyValue(node, UIA_IsPasswordPropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(V_VT(&v) == VT_BOOL, "Unexpected VT %d\n", V_VT(&v)); + ok(check_variant_bool(&v, TRUE), "V_BOOL(&v) = %#x\n", V_BOOL(&v)); + VariantClear(&v); + + UiaNodeRelease(node); + DestroyWindow(hwnd2); + + /* + * Test default BaseHwnd provider. Unlike the other default providers, the + * default BaseHwnd IRawElementProviderSimple is not available to test + * directly. To isolate the BaseHwnd provider, we set the node's nonclient + * provider to Provider_nc, and its Main provider to Provider. These + * providers will return nothing so that we can isolate properties coming + * from the BaseHwnd provider. + */ + hwnd2 = CreateWindowA("default_proxy_provider child class", "Test child window", WS_CHILD, + 0, 0, 50, 50, hwnd, NULL, NULL, NULL); + initialize_provider(&Provider_nc, ProviderOptions_ClientSideProvider | ProviderOptions_NonClientAreaProvider, hwnd2, FALSE); + set_provider_nav_ifaces(&Provider, NULL, NULL, NULL, NULL, NULL, NULL); + set_provider_nav_ifaces(&Provider_nc, NULL, NULL, NULL, NULL, NULL, NULL); + initialize_provider(&Provider, ProviderOptions_ServerSideProvider, hwnd2, FALSE); + Provider_nc.ignore_hwnd_prop = Provider.ignore_hwnd_prop = TRUE; + child_win_prov_root = &Provider.IRawElementProviderSimple_iface; + + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + hr = UiaNodeFromProvider(&Provider_nc.IRawElementProviderSimple_iface, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + ok(Provider_nc.ref == 2, "Unexpected refcnt %ld\n", Provider_nc.ref); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2); + check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", NULL, TRUE); + VariantClear(&v); + } + + Provider.ret_invalid_prop_type = Provider_nc.ret_invalid_prop_type = TRUE; + + /* + * Default BaseHwnd provider has a control type of Window. + * Actually apparently Pane for child windows? + */ + hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + todo_wine ok(V_VT(&v) == VT_I4, "Unexpected VT %d\n", V_VT(&v)); + todo_wine ok(V_I4(&v) == UIA_WindowControlTypeId, "Unexpected I4 %#lx\n", V_I4(&v)); + VariantClear(&v); + + /* Default BaseHwnd provider has its name property set to the window name. */ + hr = UiaGetPropertyValue(node, UIA_NamePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + todo_wine ok(V_VT(&v) == VT_BSTR, "Unexpected VT %d\n", V_VT(&v)); + if (V_VT(&v) == VT_BSTR) + ok(!lstrcmpW(V_BSTR(&v), L"Test child window"), "Unexpected BSTR %s\n", wine_dbgstr_w(V_BSTR(&v))); + VariantClear(&v); + + for (i = 0; i < ARRAY_SIZE(exp_node_desc); i++) + init_node_provider_desc(&exp_node_desc[i], GetCurrentProcessId(), NULL); + + prov_root = &Provider2.IRawElementProviderSimple_iface; + init_node_provider_desc(&exp_node_desc[0], GetCurrentProcessId(), hwnd); + add_provider_desc(&exp_node_desc[0], L"Main", L"Provider2", FALSE); + add_provider_desc(&exp_node_desc[0], L"Nonclient", NULL, FALSE); + add_provider_desc(&exp_node_desc[0], L"Hwnd", NULL, TRUE); + set_cache_request(&cache_req, NULL, TreeScope_Element, NULL, 0, NULL, 0, AutomationElementMode_Full); + tree_struct = NULL; out_req = NULL; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + hr = UiaNavigate(node, NavigateDirection_Parent, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + todo_wine ok(Provider2.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + + if (tree_struct) + { + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + } + UiaNodeRelease(node); + + set_accessible_props(&Accessible, 0, 0, 0, NULL, 0, 0, 0, 0); + initialize_provider(&Provider, ProviderOptions_ServerSideProvider, NULL, FALSE); + initialize_provider(&Provider_nc, ProviderOptions_ClientSideProvider | ProviderOptions_NonClientAreaProvider, NULL, FALSE); + set_provider_nav_ifaces(&Provider, NULL, NULL, NULL, NULL, &Provider_child, &Provider_child2); + set_provider_nav_ifaces(&Provider_nc, NULL, NULL, NULL, NULL, &Provider_nc_child, &Provider_nc_child2); + child_win_prov_root = prov_root = NULL; + acc_client = NULL; + + DestroyWindow(hwnd); + UnregisterClassA("default_proxy_provider class", NULL); + UnregisterClassA("default_proxy_provider child class", NULL); + + CoUninitialize(); +} + /* * Once a process returns a UI Automation provider with * UiaReturnRawElementProvider it ends up in an implicit MTA until exit. This @@ -9597,6 +9818,7 @@ START_TEST(uiautomation) test_UiaGetUpdatedCache(); test_UiaNavigate(); test_UiaFind(); + test_default_proxy_providers(); if (uia_dll) { pUiaProviderFromIAccessible = (void *)GetProcAddress(uia_dll, "UiaProviderFromIAccessible"); diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 860a917c423..2de390c652b 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -2481,11 +2481,26 @@ HRESULT WINAPI UiaHUiaNodeFromVariant(VARIANT *in_val, HUIANODE *huianode) static SAFEARRAY WINAPI *default_uia_provider_callback(HWND hwnd, enum ProviderType prov_type) { + IRawElementProviderSimple *elprov = NULL; + HRESULT hr; + switch (prov_type) { case ProviderType_Proxy: - FIXME("Default ProviderType_Proxy MSAA provider unimplemented.\n"); + { + IAccessible *acc; + + hr = AccessibleObjectFromWindow(hwnd, OBJID_CLIENT, &IID_IAccessible, (void **)&acc); + if (FAILED(hr) || !acc) + break; + + hr = create_msaa_provider(acc, CHILDID_SELF, hwnd, TRUE, &elprov); + if (FAILED(hr)) + WARN("Failed to create MSAA proxy provider with hr %#lx\n", hr); + + IAccessible_Release(acc); break; + } case ProviderType_NonClientArea: FIXME("Default ProviderType_NonClientArea provider unimplemented.\n"); @@ -2499,6 +2514,19 @@ static SAFEARRAY WINAPI *default_uia_provider_callback(HWND hwnd, enum ProviderT break; } + if (elprov) + { + SAFEARRAY *sa; + LONG idx = 0; + + sa = SafeArrayCreateVector(VT_UNKNOWN, 0, 1); + if (sa) + SafeArrayPutElement(sa, &idx, (void *)elprov); + + IRawElementProviderSimple_Release(elprov); + return sa; + } + return NULL; } diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 63820d0b937..4fcb0bc0bb2 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -104,3 +104,5 @@ const struct uia_prop_info *uia_prop_info_from_id(PROPERTYID prop_id) DECLSPEC_H void uia_stop_provider_thread(void) DECLSPEC_HIDDEN; void uia_provider_thread_remove_node(HUIANODE node) DECLSPEC_HIDDEN; LRESULT uia_lresult_from_node(HUIANODE huianode) DECLSPEC_HIDDEN; +HRESULT create_msaa_provider(IAccessible *acc, long child_id, HWND hwnd, BOOL known_root_acc, + IRawElementProviderSimple **elprov) DECLSPEC_HIDDEN; diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index 4fb57e1013d..e06002164c8 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -770,7 +770,7 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface, else acc = msaa_prov->acc; - hr = UiaProviderFromIAccessible(acc, CHILDID_SELF, 0, &elprov); + hr = create_msaa_provider(acc, CHILDID_SELF, NULL, FALSE, &elprov); if (SUCCEEDED(hr)) { struct msaa_provider *prov = impl_from_msaa_provider(elprov); @@ -801,7 +801,7 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface, if (FAILED(hr) || !acc) break; - hr = UiaProviderFromIAccessible(acc, child_id, 0, &elprov); + hr = create_msaa_provider(acc, child_id, NULL, FALSE, &elprov); if (SUCCEEDED(hr)) { struct msaa_provider *prov = impl_from_msaa_provider(elprov); @@ -851,7 +851,7 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface, if (FAILED(hr) || !acc) break; - hr = UiaProviderFromIAccessible(acc, child_id, 0, &elprov); + hr = create_msaa_provider(acc, child_id, NULL, FALSE, &elprov); if (SUCCEEDED(hr)) { struct msaa_provider *prov = impl_from_msaa_provider(elprov); @@ -1097,13 +1097,48 @@ static const ILegacyIAccessibleProviderVtbl msaa_acc_provider_vtbl = { msaa_acc_provider_get_DefaultAction, }; +HRESULT create_msaa_provider(IAccessible *acc, long child_id, HWND hwnd, BOOL known_root_acc, + IRawElementProviderSimple **elprov) +{ + struct msaa_provider *msaa_prov = heap_alloc_zero(sizeof(*msaa_prov)); + + if (!msaa_prov) + return E_OUTOFMEMORY; + + msaa_prov->IRawElementProviderSimple_iface.lpVtbl = &msaa_provider_vtbl; + msaa_prov->IRawElementProviderFragment_iface.lpVtbl = &msaa_fragment_vtbl; + msaa_prov->ILegacyIAccessibleProvider_iface.lpVtbl = &msaa_acc_provider_vtbl; + msaa_prov->refcount = 1; + variant_init_i4(&msaa_prov->cid, child_id); + msaa_prov->acc = acc; + IAccessible_AddRef(acc); + msaa_prov->ia2 = msaa_acc_get_ia2(acc); + + if (!hwnd) + { + HRESULT hr; + + hr = WindowFromAccessibleObject(acc, &msaa_prov->hwnd); + if (FAILED(hr)) + WARN("WindowFromAccessibleObject failed with hr %#lx\n", hr); + } + else + msaa_prov->hwnd = hwnd; + + if (known_root_acc) + msaa_prov->root_acc_check_ran = msaa_prov->is_root_acc = TRUE; + + *elprov = &msaa_prov->IRawElementProviderSimple_iface; + + return S_OK; +} + /*********************************************************************** * UiaProviderFromIAccessible (uiautomationcore.@) */ HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD flags, IRawElementProviderSimple **elprov) { - struct msaa_provider *msaa_prov; IServiceProvider *serv_prov; HWND hwnd = NULL; HRESULT hr; @@ -1147,22 +1182,7 @@ HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD if (!hwnd) return E_FAIL; - msaa_prov = heap_alloc_zero(sizeof(*msaa_prov)); - if (!msaa_prov) - return E_OUTOFMEMORY; - - msaa_prov->IRawElementProviderSimple_iface.lpVtbl = &msaa_provider_vtbl; - msaa_prov->IRawElementProviderFragment_iface.lpVtbl = &msaa_fragment_vtbl; - msaa_prov->ILegacyIAccessibleProvider_iface.lpVtbl = &msaa_acc_provider_vtbl; - msaa_prov->refcount = 1; - msaa_prov->hwnd = hwnd; - variant_init_i4(&msaa_prov->cid, child_id); - msaa_prov->acc = acc; - IAccessible_AddRef(acc); - msaa_prov->ia2 = msaa_acc_get_ia2(acc); - *elprov = &msaa_prov->IRawElementProviderSimple_iface; - - return S_OK; + return create_msaa_provider(acc, child_id, hwnd, FALSE, elprov); } /* From c8f7c0262235a5d366f6b9b92a352e358c94fd57 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 9 Nov 2022 13:06:43 -0500 Subject: [PATCH 0753/2777] uiautomationcore: Add a basic default ProviderType_BaseHwnd provider. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 9 +- dlls/uiautomationcore/uia_client.c | 4 +- dlls/uiautomationcore/uia_private.h | 1 + dlls/uiautomationcore/uia_provider.c | 220 +++++++++++++++++++++ 4 files changed, 228 insertions(+), 6 deletions(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index ed7abb22887..70e0334e9c8 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -9698,16 +9698,15 @@ static void test_default_proxy_providers(void) */ hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine ok(V_VT(&v) == VT_I4, "Unexpected VT %d\n", V_VT(&v)); - todo_wine ok(V_I4(&v) == UIA_WindowControlTypeId, "Unexpected I4 %#lx\n", V_I4(&v)); + ok(V_VT(&v) == VT_I4, "Unexpected VT %d\n", V_VT(&v)); + ok(V_I4(&v) == UIA_PaneControlTypeId, "Unexpected I4 %#lx\n", V_I4(&v)); VariantClear(&v); /* Default BaseHwnd provider has its name property set to the window name. */ hr = UiaGetPropertyValue(node, UIA_NamePropertyId, &v); ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine ok(V_VT(&v) == VT_BSTR, "Unexpected VT %d\n", V_VT(&v)); - if (V_VT(&v) == VT_BSTR) - ok(!lstrcmpW(V_BSTR(&v), L"Test child window"), "Unexpected BSTR %s\n", wine_dbgstr_w(V_BSTR(&v))); + ok(V_VT(&v) == VT_BSTR, "Unexpected VT %d\n", V_VT(&v)); + ok(!lstrcmpW(V_BSTR(&v), L"Test child window"), "Unexpected BSTR %s\n", wine_dbgstr_w(V_BSTR(&v))); VariantClear(&v); for (i = 0; i < ARRAY_SIZE(exp_node_desc); i++) diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 2de390c652b..0fe76823d7e 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -2507,7 +2507,9 @@ static SAFEARRAY WINAPI *default_uia_provider_callback(HWND hwnd, enum ProviderT break; case ProviderType_BaseHwnd: - FIXME("Default ProviderType_BaseHwnd provider unimplemented.\n"); + hr = create_base_hwnd_provider(hwnd, &elprov); + if (FAILED(hr)) + WARN("Failed to create BaseHwnd provider with hr %#lx\n", hr); break; default: diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 4fcb0bc0bb2..7905f509c62 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -106,3 +106,4 @@ void uia_provider_thread_remove_node(HUIANODE node) DECLSPEC_HIDDEN; LRESULT uia_lresult_from_node(HUIANODE huianode) DECLSPEC_HIDDEN; HRESULT create_msaa_provider(IAccessible *acc, long child_id, HWND hwnd, BOOL known_root_acc, IRawElementProviderSimple **elprov) DECLSPEC_HIDDEN; +HRESULT create_base_hwnd_provider(HWND hwnd, IRawElementProviderSimple **elprov) DECLSPEC_HIDDEN; diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index e06002164c8..6eb9bcdd41e 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -1344,6 +1344,226 @@ HRESULT WINAPI UiaProviderForNonClient(HWND hwnd, long objid, long child_id, return S_OK; } +/* + * HWND helper functions. + */ +static HRESULT win_get_name(HWND hwnd, BSTR *name) +{ + WCHAR buf[1024]; + BOOL succeeded; + UINT i, len; + + *name = NULL; + succeeded = SendMessageTimeoutW(hwnd, WM_GETTEXT, ARRAY_SIZE(buf), (LPARAM)buf, 0, 1000, (PDWORD_PTR)&len); + if (!succeeded || !len) + return S_FALSE; + + for (i = 0; i < len; i++) + { + if (buf[i] == '&') + { + len--; + memmove(buf + i, (buf + i) + 1, (len - i ) * sizeof(WCHAR)); + break; + } + } + + *name = SysAllocStringLen(buf, len); + return *name ? S_OK : E_OUTOFMEMORY; +} + +static BOOL is_top_level_hwnd(HWND hwnd) +{ + if (GetAncestor(hwnd, GA_PARENT) == GetDesktopWindow()) + return TRUE; + + return FALSE; +} + +static BOOL check_for_hwnd_window_pattern(HWND hwnd) +{ + LONG_PTR style, ex_style; + + ex_style = GetWindowLongPtrW(hwnd, GWL_EXSTYLE); + if (ex_style & WS_EX_APPWINDOW) + return TRUE; + + style = GetWindowLongPtrW(hwnd, GWL_STYLE); + if (!style) + return FALSE; + + if (!((style & WS_BORDER) && (style & WS_DLGFRAME))) + { + if (ex_style & WS_EX_TOOLWINDOW) + return FALSE; + if (style & WS_POPUP) + return FALSE; + } + + if (!is_top_level_hwnd(hwnd) && !(ex_style & WS_EX_MDICHILD)) + return FALSE; + + return TRUE; +} + +/* + * Default ProviderType_BaseHwnd IRawElementProviderSimple interface. + */ +struct base_hwnd_provider { + IRawElementProviderSimple IRawElementProviderSimple_iface; + LONG refcount; + + HWND hwnd; +}; + +static inline struct base_hwnd_provider *impl_from_base_hwnd_provider(IRawElementProviderSimple *iface) +{ + return CONTAINING_RECORD(iface, struct base_hwnd_provider, IRawElementProviderSimple_iface); +} + +HRESULT WINAPI base_hwnd_provider_QueryInterface(IRawElementProviderSimple *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IRawElementProviderSimple) || IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else + return E_NOINTERFACE; + + IRawElementProviderSimple_AddRef(iface); + return S_OK; +} + +ULONG WINAPI base_hwnd_provider_AddRef(IRawElementProviderSimple *iface) +{ + struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_provider(iface); + ULONG refcount = InterlockedIncrement(&base_hwnd_prov->refcount); + + TRACE("%p, refcount %ld\n", iface, refcount); + + return refcount; +} + +ULONG WINAPI base_hwnd_provider_Release(IRawElementProviderSimple *iface) +{ + struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_provider(iface); + ULONG refcount = InterlockedDecrement(&base_hwnd_prov->refcount); + + TRACE("%p, refcount %ld\n", iface, refcount); + + if (!refcount) + { + heap_free(base_hwnd_prov); + } + + return refcount; +} + +HRESULT WINAPI base_hwnd_provider_get_ProviderOptions(IRawElementProviderSimple *iface, + enum ProviderOptions *ret_val) +{ + TRACE("%p, %p\n", iface, ret_val); + *ret_val = ProviderOptions_ClientSideProvider; + return S_OK; +} + +HRESULT WINAPI base_hwnd_provider_GetPatternProvider(IRawElementProviderSimple *iface, + PATTERNID pattern_id, IUnknown **ret_val) +{ + FIXME("%p, %d, %p: stub\n", iface, pattern_id, ret_val); + *ret_val = NULL; + return E_NOTIMPL; +} + +HRESULT WINAPI base_hwnd_provider_GetPropertyValue(IRawElementProviderSimple *iface, + PROPERTYID prop_id, VARIANT *ret_val) +{ + struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_provider(iface); + HRESULT hr; + + TRACE("%p, %d, %p\n", iface, prop_id, ret_val); + + VariantInit(ret_val); + switch (prop_id) + { + case UIA_ProviderDescriptionPropertyId: + V_VT(ret_val) = VT_BSTR; + V_BSTR(ret_val) = SysAllocString(L"Wine: HWND Proxy"); + break; + + case UIA_NativeWindowHandlePropertyId: + V_VT(ret_val) = VT_I4; + V_I4(ret_val) = HandleToUlong(base_hwnd_prov->hwnd); + break; + + case UIA_ControlTypePropertyId: + V_VT(ret_val) = VT_I4; + if (check_for_hwnd_window_pattern(base_hwnd_prov->hwnd)) + V_I4(ret_val) = UIA_WindowControlTypeId; + else + V_I4(ret_val) = UIA_PaneControlTypeId; + break; + + case UIA_NamePropertyId: + { + BSTR name; + + hr = win_get_name(base_hwnd_prov->hwnd, &name); + if (SUCCEEDED(hr) && name) + { + V_VT(ret_val) = VT_BSTR; + V_BSTR(ret_val) = name; + } + break; + } + + default: + break; + } + + return S_OK; +} + +HRESULT WINAPI base_hwnd_provider_get_HostRawElementProvider(IRawElementProviderSimple *iface, + IRawElementProviderSimple **ret_val) +{ + TRACE("%p, %p\n", iface, ret_val); + *ret_val = NULL; + return S_OK; +} + +static const IRawElementProviderSimpleVtbl base_hwnd_provider_vtbl = { + base_hwnd_provider_QueryInterface, + base_hwnd_provider_AddRef, + base_hwnd_provider_Release, + base_hwnd_provider_get_ProviderOptions, + base_hwnd_provider_GetPatternProvider, + base_hwnd_provider_GetPropertyValue, + base_hwnd_provider_get_HostRawElementProvider, +}; + +HRESULT create_base_hwnd_provider(HWND hwnd, IRawElementProviderSimple **elprov) +{ + struct base_hwnd_provider *base_hwnd_prov; + + *elprov = NULL; + + if (!hwnd) + return E_INVALIDARG; + + if (!IsWindow(hwnd)) + return UIA_E_ELEMENTNOTAVAILABLE; + + if (!(base_hwnd_prov = heap_alloc_zero(sizeof(*base_hwnd_prov)))) + return E_OUTOFMEMORY; + + base_hwnd_prov->IRawElementProviderSimple_iface.lpVtbl = &base_hwnd_provider_vtbl; + base_hwnd_prov->refcount = 1; + base_hwnd_prov->hwnd = hwnd; + *elprov = &base_hwnd_prov->IRawElementProviderSimple_iface; + + return S_OK; +} + /* * UI Automation provider thread functions. */ From ed63e38965798446c005fe16cf3d89d4b5f41144 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 9 Nov 2022 13:09:37 -0500 Subject: [PATCH 0754/2777] uiautomationcore: Add default ProviderType_NonClientArea provider. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_client.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 0fe76823d7e..390b311e644 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -2503,7 +2503,9 @@ static SAFEARRAY WINAPI *default_uia_provider_callback(HWND hwnd, enum ProviderT } case ProviderType_NonClientArea: - FIXME("Default ProviderType_NonClientArea provider unimplemented.\n"); + hr = UiaProviderForNonClient(hwnd, OBJID_WINDOW, CHILDID_SELF, &elprov); + if (FAILED(hr)) + WARN("Failed to create NonClientArea provider with hr %#lx\n", hr); break; case ProviderType_BaseHwnd: From 576955977d44bb65dd94d463e28f9a7646ff5343 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 9 Nov 2022 14:10:34 -0500 Subject: [PATCH 0755/2777] uiautomationcore: Implement UIA_BoundingRectanglePropertyId for default ProviderType_BaseHwnd provider. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_provider.c | 109 +++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index 6eb9bcdd41e..b1929657f80 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -1411,6 +1411,7 @@ static BOOL check_for_hwnd_window_pattern(HWND hwnd) */ struct base_hwnd_provider { IRawElementProviderSimple IRawElementProviderSimple_iface; + IRawElementProviderFragment IRawElementProviderFragment_iface; LONG refcount; HWND hwnd; @@ -1423,9 +1424,13 @@ static inline struct base_hwnd_provider *impl_from_base_hwnd_provider(IRawElemen HRESULT WINAPI base_hwnd_provider_QueryInterface(IRawElementProviderSimple *iface, REFIID riid, void **ppv) { + struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_provider(iface); + *ppv = NULL; if (IsEqualIID(riid, &IID_IRawElementProviderSimple) || IsEqualIID(riid, &IID_IUnknown)) *ppv = iface; + else if (IsEqualIID(riid, &IID_IRawElementProviderFragment)) + *ppv = &base_hwnd_prov->IRawElementProviderFragment_iface; else return E_NOINTERFACE; @@ -1541,6 +1546,109 @@ static const IRawElementProviderSimpleVtbl base_hwnd_provider_vtbl = { base_hwnd_provider_get_HostRawElementProvider, }; +/* + * IRawElementProviderFragment interface for default ProviderType_BaseHwnd + * providers. + */ +static inline struct base_hwnd_provider *impl_from_base_hwnd_fragment(IRawElementProviderFragment *iface) +{ + return CONTAINING_RECORD(iface, struct base_hwnd_provider, IRawElementProviderFragment_iface); +} + +static HRESULT WINAPI base_hwnd_fragment_QueryInterface(IRawElementProviderFragment *iface, REFIID riid, + void **ppv) +{ + struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_fragment(iface); + return IRawElementProviderSimple_QueryInterface(&base_hwnd_prov->IRawElementProviderSimple_iface, riid, ppv); +} + +static ULONG WINAPI base_hwnd_fragment_AddRef(IRawElementProviderFragment *iface) +{ + struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_fragment(iface); + return IRawElementProviderSimple_AddRef(&base_hwnd_prov->IRawElementProviderSimple_iface); +} + +static ULONG WINAPI base_hwnd_fragment_Release(IRawElementProviderFragment *iface) +{ + struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_fragment(iface); + return IRawElementProviderSimple_Release(&base_hwnd_prov->IRawElementProviderSimple_iface); +} + +static HRESULT WINAPI base_hwnd_fragment_Navigate(IRawElementProviderFragment *iface, + enum NavigateDirection direction, IRawElementProviderFragment **ret_val) +{ + FIXME("%p, %d, %p: stub\n", iface, direction, ret_val); + *ret_val = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI base_hwnd_fragment_GetRuntimeId(IRawElementProviderFragment *iface, + SAFEARRAY **ret_val) +{ + FIXME("%p, %p: stub!\n", iface, ret_val); + *ret_val = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI base_hwnd_fragment_get_BoundingRectangle(IRawElementProviderFragment *iface, + struct UiaRect *ret_val) +{ + struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_fragment(iface); + RECT rect = { 0 }; + + TRACE("%p, %p\n", iface, ret_val); + + memset(ret_val, 0, sizeof(*ret_val)); + + /* Top level minimized window - Return empty rect. */ + if (is_top_level_hwnd(base_hwnd_prov->hwnd) && IsIconic(base_hwnd_prov->hwnd)) + return S_OK; + + if (GetWindowRect(base_hwnd_prov->hwnd, &rect)) + { + ret_val->left = rect.left; + ret_val->top = rect.top; + ret_val->width = (rect.right - rect.left); + ret_val->height = (rect.bottom - rect.top); + } + + return S_OK; +} + +static HRESULT WINAPI base_hwnd_fragment_GetEmbeddedFragmentRoots(IRawElementProviderFragment *iface, + SAFEARRAY **ret_val) +{ + FIXME("%p, %p: stub!\n", iface, ret_val); + *ret_val = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI base_hwnd_fragment_SetFocus(IRawElementProviderFragment *iface) +{ + FIXME("%p: stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI base_hwnd_fragment_get_FragmentRoot(IRawElementProviderFragment *iface, + IRawElementProviderFragmentRoot **ret_val) +{ + FIXME("%p, %p: stub!\n", iface, ret_val); + *ret_val = NULL; + return E_NOTIMPL; +} + +static const IRawElementProviderFragmentVtbl base_hwnd_fragment_vtbl = { + base_hwnd_fragment_QueryInterface, + base_hwnd_fragment_AddRef, + base_hwnd_fragment_Release, + base_hwnd_fragment_Navigate, + base_hwnd_fragment_GetRuntimeId, + base_hwnd_fragment_get_BoundingRectangle, + base_hwnd_fragment_GetEmbeddedFragmentRoots, + base_hwnd_fragment_SetFocus, + base_hwnd_fragment_get_FragmentRoot, +}; + HRESULT create_base_hwnd_provider(HWND hwnd, IRawElementProviderSimple **elprov) { struct base_hwnd_provider *base_hwnd_prov; @@ -1557,6 +1665,7 @@ HRESULT create_base_hwnd_provider(HWND hwnd, IRawElementProviderSimple **elprov) return E_OUTOFMEMORY; base_hwnd_prov->IRawElementProviderSimple_iface.lpVtbl = &base_hwnd_provider_vtbl; + base_hwnd_prov->IRawElementProviderFragment_iface.lpVtbl = &base_hwnd_fragment_vtbl; base_hwnd_prov->refcount = 1; base_hwnd_prov->hwnd = hwnd; *elprov = &base_hwnd_prov->IRawElementProviderSimple_iface; From 62a71a47aad864fe953f4eddd60afcacb6f9cb70 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 9 Nov 2022 15:06:39 -0500 Subject: [PATCH 0756/2777] uiautomationcore: Implement NavigateDirection_Parent navigation for default ProviderType_BaseHwnd provider. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 20 +++--- dlls/uiautomationcore/uia_provider.c | 83 +++++++++++++++++++++- 2 files changed, 90 insertions(+), 13 deletions(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 70e0334e9c8..2c76e1b6053 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -9722,18 +9722,16 @@ static void test_default_proxy_providers(void) SET_EXPECT(winproc_GETOBJECT_UiaRoot); hr = UiaNavigate(node, NavigateDirection_Parent, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine ok(!!out_req, "out_req == NULL\n"); - todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); - todo_wine ok(Provider2.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); - todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + ok(!!out_req, "out_req == NULL\n"); + ok(!!tree_struct, "tree_struct == NULL\n"); + ok(Provider2.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); - if (tree_struct) - { - exp_lbound[0] = exp_lbound[1] = 0; - exp_elems[0] = exp_elems[1] = 1; - test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); - ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); - } UiaNodeRelease(node); set_accessible_props(&Accessible, 0, 0, 0, NULL, 0, 0, 0, 0); diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index b1929657f80..296172e7529 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -1406,6 +1406,35 @@ static BOOL check_for_hwnd_window_pattern(HWND hwnd) return TRUE; } +static BOOL hwnd_is_visible(HWND hwnd) +{ + RECT rect; + + if (!IsWindowVisible(hwnd)) + return FALSE; + + if (!GetWindowRect(hwnd, &rect)) + return FALSE; + + if ((rect.right - rect.left) <= 0 || (rect.bottom - rect.top) <= 0) + return FALSE; + + return TRUE; +} + +static HWND get_real_hwnd_owner(HWND hwnd) +{ + HWND owner = GetWindow(hwnd, GW_OWNER); + + if (!owner) + return NULL; + + if (!hwnd_is_visible(owner)) + return NULL; + + return owner; +} + /* * Default ProviderType_BaseHwnd IRawElementProviderSimple interface. */ @@ -1577,9 +1606,59 @@ static ULONG WINAPI base_hwnd_fragment_Release(IRawElementProviderFragment *ifac static HRESULT WINAPI base_hwnd_fragment_Navigate(IRawElementProviderFragment *iface, enum NavigateDirection direction, IRawElementProviderFragment **ret_val) { - FIXME("%p, %d, %p: stub\n", iface, direction, ret_val); + struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_fragment(iface); + IRawElementProviderSimple *elprov = NULL; + HRESULT hr; + + TRACE("%p, %d, %p\n", iface, direction, ret_val); + *ret_val = NULL; - return E_NOTIMPL; + switch (direction) + { + case NavigateDirection_Parent: + { + HWND parent = GetAncestor(base_hwnd_prov->hwnd, GA_PARENT); + + if (parent == GetDesktopWindow()) + { + HWND owner = get_real_hwnd_owner(parent); + + if (owner) + parent = owner; + } + + if (parent) + { + hr = create_base_hwnd_provider(parent, &elprov); + if (FAILED(hr)) + WARN("Failed to create parent provider with hr %#lx\n", hr); + } + break; + } + + case NavigateDirection_FirstChild: + case NavigateDirection_LastChild: + case NavigateDirection_NextSibling: + case NavigateDirection_PreviousSibling: + FIXME("Unimplemented NavigateDirection %d\n", direction); + break; + + default: + FIXME("Invalid NavigateDirection %d\n", direction); + return E_INVALIDARG; + } + + if (elprov) + { + IRawElementProviderFragment *elfrag; + + hr = IRawElementProviderSimple_QueryInterface(elprov, &IID_IRawElementProviderFragment, (void **)&elfrag); + IRawElementProviderSimple_Release(elprov); + if (SUCCEEDED(hr)) + *ret_val = elfrag; + } + + return S_OK; } static HRESULT WINAPI base_hwnd_fragment_GetRuntimeId(IRawElementProviderFragment *iface, From c54eccbe61923e75913d77b5296d2687593d5ebc Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Thu, 10 Nov 2022 12:57:05 -0500 Subject: [PATCH 0757/2777] uiautomationcore: Implement NavigateDirection_{First/Last}Child navigation for default ProviderType_BaseHwnd provider. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_provider.c | 85 ++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index 296172e7529..9cfb5d37f82 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -1435,6 +1435,50 @@ static HWND get_real_hwnd_owner(HWND hwnd) return owner; } +static HWND get_visible_sibling_hwnd(HWND hwnd, int dir, BOOL include_self, HWND hwnd_owner) +{ + const int gw_arg = (dir == NavigateDirection_NextSibling) ? GW_HWNDNEXT : GW_HWNDPREV; + + if (!hwnd) + return NULL; + + if (!include_self) + hwnd = GetWindow(hwnd, gw_arg); + + for (; hwnd; hwnd = GetWindow(hwnd, gw_arg)) + { + HWND owner; + + if (!hwnd_is_visible(hwnd)) + continue; + + owner = get_real_hwnd_owner(hwnd); + if (owner != hwnd_owner) + continue; + + break; + } + + return hwnd; +} + +static HWND get_valid_child_hwnd(HWND parent, int dir) +{ + HWND scan; + + if (!is_top_level_hwnd(parent)) + return NULL; + + scan = GetWindow(GetDesktopWindow(), GW_CHILD); + if (dir == NavigateDirection_LastChild) + scan = GetWindow(scan, GW_HWNDLAST); + + if (dir == NavigateDirection_FirstChild) + return get_visible_sibling_hwnd(scan, NavigateDirection_NextSibling, TRUE, parent); + else + return get_visible_sibling_hwnd(scan, NavigateDirection_PreviousSibling, TRUE, parent); +} + /* * Default ProviderType_BaseHwnd IRawElementProviderSimple interface. */ @@ -1637,7 +1681,48 @@ static HRESULT WINAPI base_hwnd_fragment_Navigate(IRawElementProviderFragment *i } case NavigateDirection_FirstChild: + { + HWND child; + + child = get_valid_child_hwnd(base_hwnd_prov->hwnd, direction); + if (!child) + { + child = GetWindow(base_hwnd_prov->hwnd, GW_CHILD); + child = get_visible_sibling_hwnd(child, NavigateDirection_NextSibling, TRUE, NULL); + } + + if (child) + { + hr = create_base_hwnd_provider(child, &elprov); + if (FAILED(hr)) + WARN("Failed to create child provider with hr %#lx\n", hr); + } + break; + } + case NavigateDirection_LastChild: + { + HWND child; + + child = GetWindow(base_hwnd_prov->hwnd, GW_CHILD); + if (child) + { + child = GetWindow(child, GW_HWNDLAST); + child = get_visible_sibling_hwnd(child, NavigateDirection_PreviousSibling, TRUE, NULL); + } + + if (!child) + child = get_valid_child_hwnd(base_hwnd_prov->hwnd, direction); + + if (child) + { + hr = create_base_hwnd_provider(child, &elprov); + if (FAILED(hr)) + WARN("Failed to create child provider with hr %#lx\n", hr); + } + break; + } + case NavigateDirection_NextSibling: case NavigateDirection_PreviousSibling: FIXME("Unimplemented NavigateDirection %d\n", direction); From 4e7b441a1db6240debb4067cb96685ac26147cd1 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 21 Dec 2022 12:22:18 -0500 Subject: [PATCH 0758/2777] uiautomationcore: Implement IRawElementProvider::get_FragmentRoot for base HWND provider. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_provider.c | 69 +++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index 9cfb5d37f82..08f71213fa1 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -1485,6 +1485,7 @@ static HWND get_valid_child_hwnd(HWND parent, int dir) struct base_hwnd_provider { IRawElementProviderSimple IRawElementProviderSimple_iface; IRawElementProviderFragment IRawElementProviderFragment_iface; + IRawElementProviderFragmentRoot IRawElementProviderFragmentRoot_iface; LONG refcount; HWND hwnd; @@ -1504,6 +1505,8 @@ HRESULT WINAPI base_hwnd_provider_QueryInterface(IRawElementProviderSimple *ifac *ppv = iface; else if (IsEqualIID(riid, &IID_IRawElementProviderFragment)) *ppv = &base_hwnd_prov->IRawElementProviderFragment_iface; + else if (IsEqualIID(riid, &IID_IRawElementProviderFragmentRoot)) + *ppv = &base_hwnd_prov->IRawElementProviderFragmentRoot_iface; else return E_NOINTERFACE; @@ -1796,9 +1799,20 @@ static HRESULT WINAPI base_hwnd_fragment_SetFocus(IRawElementProviderFragment *i static HRESULT WINAPI base_hwnd_fragment_get_FragmentRoot(IRawElementProviderFragment *iface, IRawElementProviderFragmentRoot **ret_val) { - FIXME("%p, %p: stub!\n", iface, ret_val); + IRawElementProviderSimple *elprov; + HRESULT hr; + + TRACE("%p, %p\n", iface, ret_val); + *ret_val = NULL; - return E_NOTIMPL; + hr = create_base_hwnd_provider(GetDesktopWindow(), &elprov); + if (FAILED(hr) || !elprov) + return hr; + + hr = IRawElementProviderSimple_QueryInterface(elprov, &IID_IRawElementProviderFragmentRoot, (void **)ret_val); + IRawElementProviderSimple_Release(elprov); + + return hr; } static const IRawElementProviderFragmentVtbl base_hwnd_fragment_vtbl = { @@ -1813,6 +1827,56 @@ static const IRawElementProviderFragmentVtbl base_hwnd_fragment_vtbl = { base_hwnd_fragment_get_FragmentRoot, }; +/* + * IRawElementProviderFragmentRoot interface for default ProviderType_BaseHwnd + * providers. + */ +static inline struct base_hwnd_provider *impl_from_base_hwnd_fragment_root(IRawElementProviderFragmentRoot *iface) +{ + return CONTAINING_RECORD(iface, struct base_hwnd_provider, IRawElementProviderFragmentRoot_iface); +} + +static HRESULT WINAPI base_hwnd_fragment_root_QueryInterface(IRawElementProviderFragmentRoot *iface, REFIID riid, + void **ppv) +{ + struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_fragment_root(iface); + return IRawElementProviderSimple_QueryInterface(&base_hwnd_prov->IRawElementProviderSimple_iface, riid, ppv); +} + +static ULONG WINAPI base_hwnd_fragment_root_AddRef(IRawElementProviderFragmentRoot *iface) +{ + struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_fragment_root(iface); + return IRawElementProviderSimple_AddRef(&base_hwnd_prov->IRawElementProviderSimple_iface); +} + +static ULONG WINAPI base_hwnd_fragment_root_Release(IRawElementProviderFragmentRoot *iface) +{ + struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_fragment_root(iface); + return IRawElementProviderSimple_Release(&base_hwnd_prov->IRawElementProviderSimple_iface); +} + +static HRESULT WINAPI base_hwnd_fragment_root_ElementProviderFromPoint(IRawElementProviderFragmentRoot *iface, + double x, double y, IRawElementProviderFragment **ret_val) +{ + FIXME("%p, %f, %f, %p: stub\n", iface, x, y, ret_val); + return E_NOTIMPL; +} + +static HRESULT WINAPI base_hwnd_fragment_root_GetFocus(IRawElementProviderFragmentRoot *iface, + IRawElementProviderFragment **ret_val) +{ + FIXME("%p, %p: stub\n", iface, ret_val); + return E_NOTIMPL; +} + +static const IRawElementProviderFragmentRootVtbl base_hwnd_fragment_root_vtbl = { + base_hwnd_fragment_root_QueryInterface, + base_hwnd_fragment_root_AddRef, + base_hwnd_fragment_root_Release, + base_hwnd_fragment_root_ElementProviderFromPoint, + base_hwnd_fragment_root_GetFocus, +}; + HRESULT create_base_hwnd_provider(HWND hwnd, IRawElementProviderSimple **elprov) { struct base_hwnd_provider *base_hwnd_prov; @@ -1830,6 +1894,7 @@ HRESULT create_base_hwnd_provider(HWND hwnd, IRawElementProviderSimple **elprov) base_hwnd_prov->IRawElementProviderSimple_iface.lpVtbl = &base_hwnd_provider_vtbl; base_hwnd_prov->IRawElementProviderFragment_iface.lpVtbl = &base_hwnd_fragment_vtbl; + base_hwnd_prov->IRawElementProviderFragmentRoot_iface.lpVtbl = &base_hwnd_fragment_root_vtbl; base_hwnd_prov->refcount = 1; base_hwnd_prov->hwnd = hwnd; *elprov = &base_hwnd_prov->IRawElementProviderSimple_iface; From eb3a3ecaba48db8dc1cc1a15cf06c7639980cbb9 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 21 Dec 2022 12:30:59 -0500 Subject: [PATCH 0759/2777] uiautomationcore: Implement ::GetEmbeddedFragmentRoots for default ProviderType_BaseHwnd provider. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_client.c | 31 --------- dlls/uiautomationcore/uia_main.c | 1 - dlls/uiautomationcore/uia_private.h | 31 +++++++++ dlls/uiautomationcore/uia_provider.c | 94 ++++++++++++++++++++++++++-- 4 files changed, 121 insertions(+), 36 deletions(-) diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 390b311e644..9274c01ede2 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -19,42 +19,11 @@ #include "uia_private.h" #include "wine/debug.h" -#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(uiautomation); static const struct UiaCondition UiaFalseCondition = { ConditionType_False }; -static BOOL uia_array_reserve(void **elements, SIZE_T *capacity, SIZE_T count, SIZE_T size) -{ - SIZE_T max_capacity, new_capacity; - void *new_elements; - - if (count <= *capacity) - return TRUE; - - max_capacity = ~(SIZE_T)0 / size; - if (count > max_capacity) - return FALSE; - - new_capacity = max(1, *capacity); - while (new_capacity < count && new_capacity <= max_capacity / 2) - new_capacity *= 2; - if (new_capacity < count) - new_capacity = count; - - if (!*elements) - new_elements = heap_alloc_zero(new_capacity * size); - else - new_elements = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *elements, new_capacity * size); - if (!new_elements) - return FALSE; - - *elements = new_elements; - *capacity = new_capacity; - return TRUE; -} - struct uia_node_array { HUIANODE *nodes; int node_count; diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 2c741398c82..65d9257bc0e 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -23,7 +23,6 @@ #include "uia_private.h" #include "wine/debug.h" -#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(uiautomation); diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 7905f509c62..71bc41dc3e8 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -21,6 +21,7 @@ #include "uiautomation.h" #include "uia_classes.h" #include "wine/list.h" +#include "wine/heap.h" extern HMODULE huia_module DECLSPEC_HIDDEN; @@ -91,6 +92,36 @@ static inline struct uia_provider *impl_from_IWineUiaProvider(IWineUiaProvider * return CONTAINING_RECORD(iface, struct uia_provider, IWineUiaProvider_iface); } +static inline BOOL uia_array_reserve(void **elements, SIZE_T *capacity, SIZE_T count, SIZE_T size) +{ + SIZE_T max_capacity, new_capacity; + void *new_elements; + + if (count <= *capacity) + return TRUE; + + max_capacity = ~(SIZE_T)0 / size; + if (count > max_capacity) + return FALSE; + + new_capacity = max(1, *capacity); + while (new_capacity < count && new_capacity <= max_capacity / 2) + new_capacity *= 2; + if (new_capacity < count) + new_capacity = count; + + if (!*elements) + new_elements = heap_alloc_zero(new_capacity * size); + else + new_elements = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *elements, new_capacity * size); + if (!new_elements) + return FALSE; + + *elements = new_elements; + *capacity = new_capacity; + return TRUE; +} + /* uia_client.c */ int uia_compare_safearrays(SAFEARRAY *sa1, SAFEARRAY *sa2, int prop_type) DECLSPEC_HIDDEN; int get_node_provider_type_at_idx(struct uia_node *node, int idx) DECLSPEC_HIDDEN; diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index 08f71213fa1..a62b241e76f 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -20,7 +20,6 @@ #include "ocidl.h" #include "wine/debug.h" -#include "wine/heap.h" #include "wine/rbtree.h" #include "initguid.h" #include "wine/iaccessible2.h" @@ -1479,6 +1478,67 @@ static HWND get_valid_child_hwnd(HWND parent, int dir) return get_visible_sibling_hwnd(scan, NavigateDirection_PreviousSibling, TRUE, parent); } +struct uia_fragment_array { + IRawElementProviderSimple **roots; + int root_count; + SIZE_T root_arr_size; +}; + +static const WCHAR *ignored_window_classes[] = { + L"OleMainThreadWndClass", + L"IME", +}; + +static HRESULT get_all_hwnd_fragment_roots(struct uia_fragment_array *arr, HWND hwnd, BOOL is_root) +{ + int loop_count; + HRESULT hr; + HWND child; + + if (!is_root) + { + IRawElementProviderSimple *elprov; + WCHAR buf[256] = { 0 }; + + if (GetClassNameW(hwnd, buf, ARRAY_SIZE(buf))) + { + int i; + + for (i = 0; i < ARRAY_SIZE(ignored_window_classes); i++) + { + if (!lstrcmpW(buf, ignored_window_classes[i])) + return S_OK; + } + } + + if (!uia_array_reserve((void **)&arr->roots, &arr->root_arr_size, arr->root_count + 1, + sizeof(elprov))) + return E_OUTOFMEMORY; + + hr = create_base_hwnd_provider(hwnd, &elprov); + if (SUCCEEDED(hr)) + { + arr->roots[arr->root_count] = elprov; + arr->root_count++; + return S_OK; + } + } + + loop_count = 0; + for (child = GetWindow(hwnd, GW_CHILD); child && (loop_count < 1024); child = GetWindow(child, GW_HWNDNEXT)) + { + if (hwnd_is_visible(child)) + { + hr = get_all_hwnd_fragment_roots(arr, child, FALSE); + if (FAILED(hr)) + return hr; + } + loop_count++; + } + + return S_OK; +} + /* * Default ProviderType_BaseHwnd IRawElementProviderSimple interface. */ @@ -1785,9 +1845,35 @@ static HRESULT WINAPI base_hwnd_fragment_get_BoundingRectangle(IRawElementProvid static HRESULT WINAPI base_hwnd_fragment_GetEmbeddedFragmentRoots(IRawElementProviderFragment *iface, SAFEARRAY **ret_val) { - FIXME("%p, %p: stub!\n", iface, ret_val); - *ret_val = NULL; - return E_NOTIMPL; + struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_fragment(iface); + struct uia_fragment_array arr = { 0 }; + HRESULT hr; + + TRACE("%p, %p\n", iface, ret_val); + + hr = get_all_hwnd_fragment_roots(&arr, base_hwnd_prov->hwnd, TRUE); + if (FAILED(hr)) + return hr; + + if (arr.root_count) + { + SAFEARRAY *sa; + LONG idx; + + if (!(sa = SafeArrayCreateVector(VT_UNKNOWN, 0, arr.root_count))) + return E_FAIL; + + for (idx = 0; idx < arr.root_count; idx++) + { + SafeArrayPutElement(sa, &idx, (IUnknown *)arr.roots[idx]); + IRawElementProviderSimple_Release(arr.roots[idx]); + } + + heap_free(arr.roots); + *ret_val = sa; + } + + return S_OK; } static HRESULT WINAPI base_hwnd_fragment_SetFocus(IRawElementProviderFragment *iface) From 98a43ad897d57af30f884868388bc89fb440d1df Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 13 Dec 2022 12:59:48 -0500 Subject: [PATCH 0760/2777] include: Fully define uiautomationclient interfaces. Signed-off-by: Connor McAdams --- include/uiautomationclient.idl | 730 +++++++++++++++++++++++++++++++-- include/uiautomationcore.idl | 92 +++++ 2 files changed, 782 insertions(+), 40 deletions(-) diff --git a/include/uiautomationclient.idl b/include/uiautomationclient.idl index ffef7b840fb..4579e4db652 100644 --- a/include/uiautomationclient.idl +++ b/include/uiautomationclient.idl @@ -622,25 +622,298 @@ library UIAutomationClient { [in] int changesCount); } - interface IUIAutomationNotificationEventHandler; - - interface IUIAutomationInvokePattern; - interface IUIAutomationDockPattern; - interface IUIAutomationExpandCollapsePattern; - interface IUIAutomationGridPattern; - interface IUIAutomationGridItemPattern; - interface IUIAutomationMultipleViewPattern; - interface IUIAutomationObjectModelPattern; - interface IUIAutomationRangeValuePattern; - interface IUIAutomationScrollPattern; - interface IUIAutomationScrollItemPattern; - interface IUIAutomationSelectionPattern; - interface IUIAutomationSelectionItemPattern; - interface IUIAutomationSynchronizedInputPattern; - interface IUIAutomationTablePattern; - interface IUIAutomationTableItemPattern; - interface IUIAutomationTogglePattern; - interface IUIAutomationTransformPattern; + [ + object, + uuid(c7cb2637-e6c2-4d0c-85de-4948c02175c7), + pointer_default(unique), + oleautomation + ] + interface IUIAutomationNotificationEventHandler : IUnknown + { + HRESULT HandleNotificationEvent( + [in] IUIAutomationElement *sender, + enum NotificationKind notificationKind, + enum NotificationProcessing notificationProcessing, + [in] BSTR displayString, + [in] BSTR activityId); + } + + [ + object, + uuid(fb377fbe-8ea6-46d5-9c73-6499642d3059), + pointer_default(unique) + ] + interface IUIAutomationInvokePattern : IUnknown + { + HRESULT Invoke(); + } + + [ + object, + uuid(fde5ef97-1464-48f6-90bf-43d0948e86ec), + pointer_default(unique) + ] + interface IUIAutomationDockPattern : IUnknown + { + HRESULT SetDockPosition([in] enum DockPosition dockPos); + [propget] HRESULT CurrentDockPosition([out, retval] enum DockPosition *retVal); + [propget] HRESULT CachedDockPosition([out, retval] enum DockPosition *retVal); + } + + [ + object, + uuid(619be086-1f4e-4ee4-bafa-210128738730), + pointer_default(unique) + ] + interface IUIAutomationExpandCollapsePattern : IUnknown + { + HRESULT Expand(); + HRESULT Collapse(); + [propget] HRESULT CurrentExpandCollapseState([out, retval] enum ExpandCollapseState *retVal); + [propget] HRESULT CachedExpandCollapseState([out, retval] enum ExpandCollapseState *retVal); + } + + [ + object, + uuid(414c3cdc-856b-4f5b-8538-3131c6302550), + pointer_default(unique) + ] + interface IUIAutomationGridPattern : IUnknown + { + HRESULT GetItem( + [in] int row, + [in] int column, + [out, retval] IUIAutomationElement **element); + + [propget] HRESULT CurrentRowCount([out, retval] int *retVal); + [propget] HRESULT CurrentColumnCount([out, retval] int *retVal); + [propget] HRESULT CachedRowCount([out, retval] int *retVal); + [propget] HRESULT CachedColumnCount([out, retval] int *retVal); + } + + [ + object, + uuid(78f8ef57-66c3-4e09-bd7c-e79b2004894d), + pointer_default(unique) + ] + interface IUIAutomationGridItemPattern : IUnknown + { + [propget] HRESULT CurrentContainingGrid([out, retval] IUIAutomationElement **retVal); + [propget] HRESULT CurrentRow([out, retval] int *retVal); + [propget] HRESULT CurrentColumn([out, retval] int *retVal); + [propget] HRESULT CurrentRowSpan([out, retval] int *retVal); + [propget] HRESULT CurrentColumnSpan([out, retval] int *retVal); + [propget] HRESULT CachedContainingGrid([out, retval] IUIAutomationElement **retVal); + [propget] HRESULT CachedRow([out, retval] int *retVal); + [propget] HRESULT CachedColumn([out, retval] int *retVal); + [propget] HRESULT CachedRowSpan([out, retval] int *retVal); + [propget] HRESULT CachedColumnSpan([out, retval] int *retVal); + } + + [ + object, + uuid(8d253c91-1dc5-4bb5-b18f-ade16fa495e8), + pointer_default(unique) + ] + interface IUIAutomationMultipleViewPattern : IUnknown + { + HRESULT GetViewName( + [in] int view, + [out, retval] BSTR *name); + + HRESULT SetCurrentView([in] int view); + + [propget] HRESULT CurrentCurrentView([out, retval] int *retVal); + HRESULT GetCurrentSupportedViews([out, retval] SAFEARRAY(int) *retVal); + + [propget] HRESULT CachedCurrentView([out, retval] int *retVal); + HRESULT GetCachedSupportedViews([out, retval] SAFEARRAY(int) *retVal); + } + + [ + object, + uuid(71c284b3-c14d-4d14-981e-19751b0d756d), + pointer_default(unique) + ] + interface IUIAutomationObjectModelPattern : IUnknown + { + HRESULT GetUnderlyingObjectModel([out, retval] IUnknown **retVal); + } + + [ + object, + uuid(59213f4f-7346-49e5-b120-80555987a148), + pointer_default(unique) + ] + interface IUIAutomationRangeValuePattern : IUnknown + { + HRESULT SetValue([in] double val); + + [propget] HRESULT CurrentValue([out, retval] double *retVal); + [propget] HRESULT CurrentIsReadOnly([out, retval] BOOL *retVal); + [propget] HRESULT CurrentMaximum([out, retval] double *retVal); + [propget] HRESULT CurrentMinimum([out, retval] double *retVal); + [propget] HRESULT CurrentLargeChange([out, retval] double *retVal); + [propget] HRESULT CurrentSmallChange([out, retval] double *retVal); + + [propget] HRESULT CachedValue([out, retval] double *retVal); + [propget] HRESULT CachedIsReadOnly([out, retval] BOOL *retVal); + [propget] HRESULT CachedMaximum([out, retval] double *retVal); + [propget] HRESULT CachedMinimum([out, retval] double *retVal); + [propget] HRESULT CachedLargeChange([out, retval] double *retVal); + [propget] HRESULT CachedSmallChange([out, retval] double *retVal); + } + + [ + object, + uuid(88f4d42a-e881-459d-a77c-73bbbb7e02dc), + pointer_default(unique) + ] + interface IUIAutomationScrollPattern : IUnknown + { + HRESULT Scroll( + [in] enum ScrollAmount horizontalAmount, + [in] enum ScrollAmount verticalAmount); + HRESULT SetScrollPercent( + [in] double horizontalPercent, + [in] double verticalPercent); + + [propget] HRESULT CurrentHorizontalScrollPercent([out, retval] double *retVal); + [propget] HRESULT CurrentVerticalScrollPercent([out, retval] double *retVal); + [propget] HRESULT CurrentHorizontalViewSize([out, retval] double *retVal); + [propget] HRESULT CurrentVerticalViewSize([out, retval] double *retVal); + [propget] HRESULT CurrentHorizontallyScrollable([out, retval] BOOL *retVal); + [propget] HRESULT CurrentVerticallyScrollable([out, retval] BOOL *retVal); + + [propget] HRESULT CachedHorizontalScrollPercent([out, retval] double *retVal); + [propget] HRESULT CachedVerticalScrollPercent([out, retval] double *retVal); + [propget] HRESULT CachedHorizontalViewSize([out, retval] double *retVal); + [propget] HRESULT CachedVerticalViewSize([out, retval] double *retVal); + [propget] HRESULT CachedHorizontallyScrollable([out, retval] BOOL *retVal); + [propget] HRESULT CachedVerticallyScrollable([out, retval] BOOL *retVal); + } + + [ + object, + uuid(b488300f-d015-4f19-9c29-bb595e3645ef), + pointer_default(unique) + ] + interface IUIAutomationScrollItemPattern : IUnknown + { + HRESULT ScrollIntoView(); + } + + [ + object, + uuid(5ed5202e-b2ac-47a6-b638-4b0bf140d78e), + pointer_default(unique) + ] + interface IUIAutomationSelectionPattern : IUnknown + { + HRESULT GetCurrentSelection([out, retval] IUIAutomationElementArray **retVal); + [propget] HRESULT CurrentCanSelectMultiple([out, retval] BOOL *retVal); + [propget] HRESULT CurrentIsSelectionRequired([out, retval] BOOL *retVal); + + HRESULT GetCachedSelection([out, retval] IUIAutomationElementArray **retVal); + [propget] HRESULT CachedCanSelectMultiple([out, retval] BOOL *retVal); + [propget] HRESULT CachedIsSelectionRequired([out, retval] BOOL *retVal); + } + + [ + object, + uuid(a8efa66a-0fda-421a-9194-38021f3578ea), + pointer_default(unique) + ] + interface IUIAutomationSelectionItemPattern : IUnknown + { + HRESULT Select(); + HRESULT AddToSelection(); + HRESULT RemoveFromSelection(); + + [propget] HRESULT CurrentIsSelected([out, retval] BOOL *retVal); + [propget] HRESULT CurrentSelectionContainer([out, retval] IUIAutomationElement **retVal); + + [propget] HRESULT CachedIsSelected([out, retval] BOOL *retVal); + [propget] HRESULT CachedSelectionContainer([out, retval] IUIAutomationElement **retVal); + } + + [ + object, + uuid(2233be0b-afb7-448b-9fda-3b378aa5eae1), + pointer_default(unique) + ] + interface IUIAutomationSynchronizedInputPattern : IUnknown + { + HRESULT StartListening([in] enum SynchronizedInputType inputType); + HRESULT Cancel(); + } + + [ + object, + uuid(620e691c-ea96-4710-a850-754b24ce2417), + pointer_default(unique) + ] + interface IUIAutomationTablePattern : IUnknown + { + HRESULT GetCurrentRowHeaders([out, retval] IUIAutomationElementArray **retVal); + HRESULT GetCurrentColumnHeaders([out, retval] IUIAutomationElementArray **retVal); + [propget] HRESULT CurrentRowOrColumnMajor([out, retval] enum RowOrColumnMajor *retVal); + + HRESULT GetCachedRowHeaders([out, retval] IUIAutomationElementArray **retVal); + HRESULT GetCachedColumnHeaders([out, retval] IUIAutomationElementArray **retVal); + [propget] HRESULT CachedRowOrColumnMajor([out, retval] enum RowOrColumnMajor *retVal); + } + + [ + object, + uuid(0b964eb3-ef2e-4464-9c79-61d61737a27e), + pointer_default(unique) + ] + interface IUIAutomationTableItemPattern : IUnknown + { + HRESULT GetCurrentRowHeaderItems([out, retval] IUIAutomationElementArray **retVal); + HRESULT GetCurrentColumnHeaderItems([out, retval] IUIAutomationElementArray **retVal); + + HRESULT GetCachedRowHeaderItems([out, retval] IUIAutomationElementArray **retVal); + HRESULT GetCachedColumnHeaderItems([out, retval] IUIAutomationElementArray **retVal); + } + + [ + object, + uuid(94cf8058-9b8d-4ab9-8bfd-4cd0a33c8c70), + pointer_default(unique) + ] + interface IUIAutomationTogglePattern : IUnknown + { + HRESULT Toggle(); + + [propget] HRESULT CurrentToggleState([out, retval] enum ToggleState *retVal); + [propget] HRESULT CachedToggleState([out, retval] enum ToggleState *retVal); + } + + [ + object, + uuid(a9b55844-a55d-4ef0-926d-569c16ff89bb), + pointer_default(unique) + ] + interface IUIAutomationTransformPattern : IUnknown + { + HRESULT Move( + [in] double x, + [in] double y); + HRESULT Resize( + [in] double width, + [in] double height); + HRESULT Rotate([in] double degrees); + + [propget] HRESULT CurrentCanMove([out, retval] BOOL *retVal); + [propget] HRESULT CurrentCanResize([out, retval] BOOL *retVal); + [propget] HRESULT CurrentCanRotate([out, retval] BOOL *retVal); + + [propget] HRESULT CachedCanMove([out, retval] BOOL *retVal); + [propget] HRESULT CachedCanResize([out, retval] BOOL *retVal); + [propget] HRESULT CachedCanRotate([out, retval] BOOL *retVal); + } [ object, @@ -685,14 +958,162 @@ library UIAutomationClient { [propget] HRESULT CachedWindowInteractionState([out, retval] enum WindowInteractionState *retVal); } - interface IUIAutomationTextRange; - interface IUIAutomationTextRange2; - interface IUIAutomationTextRangeArray; - interface IUIAutomationTextPattern; - interface IUIAutomationTextPattern2; - interface IUIAutomationTextEditPattern; - interface IUIAutomationCustomNavigationPattern; - interface IUIAutomationActiveTextPositionChangedEventHandler; + [ + object, + uuid(a543cc6a-f4ae-494b-8239-c814481187a8), + pointer_default(unique) + ] + interface IUIAutomationTextRange : IUnknown + { + HRESULT Clone([out, retval] IUIAutomationTextRange **clonedRange); + HRESULT Compare( + [in] IUIAutomationTextRange *range, + [out, retval] BOOL *areSame); + HRESULT CompareEndpoints( + [in] enum TextPatternRangeEndpoint srcEndPoint, + [in] IUIAutomationTextRange *range, + [in] enum TextPatternRangeEndpoint targetEndPoint, + [out, retval] int *compValue); + + HRESULT ExpandToEnclosingUnit([in] enum TextUnit textUnit); + + HRESULT FindAttribute( + [in] TEXTATTRIBUTEID attr, + [in] VARIANT val, + [in] BOOL backward, + [out, retval] IUIAutomationTextRange **found); + HRESULT FindText( + [in] BSTR text, + [in] BOOL backward, + [in] BOOL ignoreCase, + [out, retval] IUIAutomationTextRange **found); + + HRESULT GetAttributeValue( + [in] TEXTATTRIBUTEID attr, + [out, retval] VARIANT *value); + HRESULT GetBoundingRectangles([out, retval] SAFEARRAY(double) *boundingRects); + HRESULT GetEnclosingElement([out, retval] IUIAutomationElement **enclosingElement); + HRESULT GetText( + [in] int maxLength, + [out, retval] BSTR *text); + + HRESULT Move( + [in] enum TextUnit unit, + [in] int count, + [out, retval] int *moved); + HRESULT MoveEndpointByUnit( + [in] enum TextPatternRangeEndpoint endpoint, + [in] enum TextUnit unit, + [in] int count, + [out, retval] int *moved); + HRESULT MoveEndpointByRange( + [in] enum TextPatternRangeEndpoint srcEndPoint, + [in] IUIAutomationTextRange *range, + [in] enum TextPatternRangeEndpoint targetEndPoint); + + HRESULT Select(); + HRESULT AddToSelection(); + HRESULT RemoveFromSelection( ); + HRESULT ScrollIntoView([in] BOOL alignToTop); + + HRESULT GetChildren([out, retval] IUIAutomationElementArray **children); + } + + [ + object, + uuid(bb9b40e0-5e04-46bd-9be0-4b601b9afad4), + pointer_default(unique) + ] + interface IUIAutomationTextRange2 : IUIAutomationTextRange + { + HRESULT ShowContextMenu(); + } + + [ + object, + uuid(ce4ae76a-e717-4c98-81ea-47371d028eb6), + pointer_default(unique) + ] + interface IUIAutomationTextRangeArray : IUnknown + { + [propget] HRESULT Length([out, retval] int *length); + HRESULT GetElement( + [in] int index, + [out, retval] IUIAutomationTextRange **element); + } + + [ + object, + uuid(32eba289-3583-42c9-9c59-3b6d9a1e9b6a), + pointer_default(unique) + ] + interface IUIAutomationTextPattern : IUnknown + { + HRESULT RangeFromPoint( + [in] POINT pt, + [out, retval] IUIAutomationTextRange **range); + HRESULT RangeFromChild( + [in] IUIAutomationElement *child, + [out, retval] IUIAutomationTextRange **range); + + HRESULT GetSelection([out, retval] IUIAutomationTextRangeArray **ranges); + HRESULT GetVisibleRanges([out, retval] IUIAutomationTextRangeArray **ranges); + [propget] HRESULT DocumentRange([out, retval] IUIAutomationTextRange **range); + [propget] HRESULT SupportedTextSelection([out, retval] enum SupportedTextSelection *supportedTextSelection); + + } + + [ + object, + uuid(506a921a-fcc9-409f-b23b-37eb74106872), + pointer_default(unique) + ] + interface IUIAutomationTextPattern2 : IUIAutomationTextPattern + { + HRESULT RangeFromAnnotation( + [in] IUIAutomationElement *annotation, + [out, retval] IUIAutomationTextRange **range); + + HRESULT GetCaretRange( + [out] BOOL *isActive, + [out, retval] IUIAutomationTextRange **range); + } + + [ + object, + uuid(17e21576-996c-4870-99d9-bff323380c06), + pointer_default(unique) + ] + interface IUIAutomationTextEditPattern : IUIAutomationTextPattern + { + HRESULT GetActiveComposition([out, retval] IUIAutomationTextRange **range); + HRESULT GetConversionTarget([out, retval] IUIAutomationTextRange **range); + } + + [ + object, + uuid(01ea217a-1766-47ed-a6cc-acf492854b1f), + pointer_default(unique) + ] + interface IUIAutomationCustomNavigationPattern : IUnknown + { + HRESULT Navigate( + [in] enum NavigateDirection direction, + [out, retval] IUIAutomationElement **pRetVal); + } + + [ + object, + uuid(f97933b0-8dae-4496-8997-5ba015fe0d82), + pointer_default(unique), + oleautomation + ] + interface IUIAutomationActiveTextPositionChangedEventHandler : IUnknown + { + HRESULT HandleActiveTextPositionChangedEvent( + [in] IUIAutomationElement *sender, + [in] IUIAutomationTextRange *range); + } [ object, @@ -730,16 +1151,175 @@ library UIAutomationClient { HRESULT GetIAccessible([out, retval] IAccessible **ppAccessible); }; - interface IUIAutomationItemContainerPattern; - interface IUIAutomationVirtualizedItemPattern; - interface IUIAutomationAnnotationPattern; - interface IUIAutomationStylesPattern; - interface IUIAutomationSpreadsheetPattern; - interface IUIAutomationSpreadsheetItemPattern; - interface IUIAutomationTransformPattern2; - interface IUIAutomationTextChildPattern; - interface IUIAutomationDragPattern; - interface IUIAutomationDropTargetPattern; + [ + object, + uuid(c690fdb2-27a8-423c-812d-429773c9084e), + pointer_default(unique) + ] + interface IUIAutomationItemContainerPattern : IUnknown + { + HRESULT FindItemByProperty( + [in] IUIAutomationElement *pStartAfter, + [in] PROPERTYID propertyId, + [in] VARIANT value, + [out, retval] IUIAutomationElement **pFound); + }; + + [ + object, + uuid(6ba3d7a6-04cf-4f11-8793-a8d1cde9969f), + pointer_default(unique) + ] + interface IUIAutomationVirtualizedItemPattern : IUnknown + { + HRESULT Realize(); + }; + + [ + object, + uuid(9a175b21-339e-41b1-8e8b-623f6b681098), + pointer_default(unique) + ] + interface IUIAutomationAnnotationPattern : IUnknown + { + [propget] HRESULT CurrentAnnotationTypeId([out, retval] int *retVal); + [propget] HRESULT CurrentAnnotationTypeName([out, retval] BSTR *retVal); + [propget] HRESULT CurrentAuthor( [out, retval] BSTR *retVal); + [propget] HRESULT CurrentDateTime( [out, retval] BSTR *retVal); + [propget] HRESULT CurrentTarget( [out, retval] IUIAutomationElement **retVal); + + [propget] HRESULT CachedAnnotationTypeId([out, retval] int *retVal); + [propget] HRESULT CachedAnnotationTypeName([out, retval] BSTR *retVal); + [propget] HRESULT CachedAuthor( [out, retval] BSTR *retVal); + [propget] HRESULT CachedDateTime( [out, retval] BSTR *retVal); + [propget] HRESULT CachedTarget( [out, retval] IUIAutomationElement **retVal); + }; + + [ + object, + uuid(85b5f0a2-bd79-484a-ad2b-388c9838d5fb), + pointer_default(unique) + ] + interface IUIAutomationStylesPattern : IUnknown + { + [propget] HRESULT CurrentStyleId([out, retval] int *retVal); + [propget] HRESULT CurrentStyleName([out, retval] BSTR *retVal); + [propget] HRESULT CurrentFillColor([out, retval] int *retVal); + [propget] HRESULT CurrentFillPatternStyle([out, retval] BSTR *retVal); + [propget] HRESULT CurrentShape([out, retval] BSTR *retVal); + [propget] HRESULT CurrentFillPatternColor([out, retval] int *retVal); + [propget] HRESULT CurrentExtendedProperties([out, retval] BSTR *retVal); + HRESULT GetCurrentExtendedPropertiesAsArray( + [out, size_is( ,*propertyCount)] struct ExtendedProperty **propertyArray, + [out] int *propertyCount); + + [propget] HRESULT CachedStyleId([out, retval] int *retVal); + [propget] HRESULT CachedStyleName([out, retval] BSTR *retVal); + [propget] HRESULT CachedFillColor([out, retval] int *retVal); + [propget] HRESULT CachedFillPatternStyle([out, retval] BSTR *retVal); + [propget] HRESULT CachedShape([out, retval] BSTR *retVal); + [propget] HRESULT CachedFillPatternColor([out, retval] int *retVal); + [propget] HRESULT CachedExtendedProperties([out, retval] BSTR *retVal); + HRESULT GetCachedExtendedPropertiesAsArray( + [out, size_is( ,*propertyCount)] struct ExtendedProperty **propertyArray, + [out] int *propertyCount); + }; + + [ + object, + uuid(7517a7c8-faae-4de9-9f08-29b91e8595c1), + pointer_default(unique) + ] + interface IUIAutomationSpreadsheetPattern : IUnknown + { + HRESULT GetItemByName( + [in] BSTR name, + [out, retval] IUIAutomationElement **element); + }; + + [ + object, + uuid(7d4fb86c-8d34-40e1-8e83-62c15204e335), + pointer_default(unique) + ] + interface IUIAutomationSpreadsheetItemPattern : IUnknown + { + [propget] HRESULT CurrentFormula([out, retval] BSTR *retVal); + HRESULT GetCurrentAnnotationObjects([out, retval] IUIAutomationElementArray **retVal); + HRESULT GetCurrentAnnotationTypes([out, retval] SAFEARRAY(int) *retVal); + + [propget] HRESULT CachedFormula([out, retval] BSTR *retVal); + HRESULT GetCachedAnnotationObjects([out, retval] IUIAutomationElementArray **retVal); + HRESULT GetCachedAnnotationTypes([out, retval] SAFEARRAY(int) *retVal); + }; + + [ + object, + uuid(6d74d017-6ecb-4381-b38b-3c17a48ff1c2), + pointer_default(unique) + ] + interface IUIAutomationTransformPattern2 : IUIAutomationTransformPattern + { + HRESULT Zoom([in] double zoomValue); + HRESULT ZoomByUnit([in] enum ZoomUnit zoomUnit); + + [propget] HRESULT CurrentCanZoom([out, retval] BOOL *retVal); + [propget] HRESULT CachedCanZoom([out, retval] BOOL *retVal); + + [propget] HRESULT CurrentZoomLevel([out, retval] double *retVal); + [propget] HRESULT CachedZoomLevel([out, retval] double *retVal); + + [propget] HRESULT CurrentZoomMinimum([out, retval] double *retVal); + [propget] HRESULT CachedZoomMinimum([out, retval] double *retVal); + + [propget] HRESULT CurrentZoomMaximum([out, retval] double *retVal); + [propget] HRESULT CachedZoomMaximum([out, retval] double *retVal); + } + + [ + object, + uuid(6552b038-ae05-40c8-abfd-aa08352aab86), + pointer_default(unique) + ] + interface IUIAutomationTextChildPattern : IUnknown + { + [propget] HRESULT TextContainer([out, retval] IUIAutomationElement **container); + [propget] HRESULT TextRange([out, retval] IUIAutomationTextRange **range); + } + + [ + object, + uuid(1dc7b570-1f54-4bad-bcda-d36a722fb7bd), + pointer_default(unique) + ] + interface IUIAutomationDragPattern : IUnknown + { + [propget] HRESULT CurrentIsGrabbed([out, retval] BOOL *retVal); + [propget] HRESULT CachedIsGrabbed([out, retval] BOOL *retVal); + + [propget] HRESULT CurrentDropEffect([out, retval] BSTR *retVal); + [propget] HRESULT CachedDropEffect([out, retval] BSTR *retVal); + + [propget] HRESULT CurrentDropEffects([out, retval] SAFEARRAY(BSTR) *retVal); + [propget] HRESULT CachedDropEffects([out, retval] SAFEARRAY(BSTR) *retVal); + + HRESULT GetCurrentGrabbedItems([out, retval] IUIAutomationElementArray **retVal); + HRESULT GetCachedGrabbedItems([out, retval] IUIAutomationElementArray **retVal); + } + + [ + object, + uuid(69a095f7-eee4-430e-a46b-fb73b1ae39a5), + pointer_default(unique) + ] + interface IUIAutomationDropTargetPattern : IUnknown + { + [propget] HRESULT CurrentDropTargetEffect([out, retval] BSTR *retVal); + [propget] HRESULT CachedDropTargetEffect([out, retval] BSTR *retVal); + + [propget] HRESULT CurrentDropTargetEffects([out, retval] SAFEARRAY(BSTR) *retVal); + [propget] HRESULT CachedDropTargetEffects([out, retval] SAFEARRAY(BSTR) *retVal); + } [ object, @@ -1033,9 +1613,79 @@ library UIAutomationClient { [out, retval] IUIAutomationElement **element); } - interface IUIAutomationProxyFactory; - interface IUIAutomationProxyFactoryEntry; - interface IUIAutomationProxyFactoryMapping; + [ + object, + uuid(85b94ecd-849d-42b6-b94d-d6db23fdf5a4), + pointer_default(unique) + ] + interface IUIAutomationProxyFactory : IUnknown + { + HRESULT CreateProvider( + [in] UIA_HWND hwnd, + [in] LONG idObject, + [in] LONG idChild, + [out, retval] IRawElementProviderSimple **provider); + + [propget] HRESULT ProxyFactoryId([out, retval] BSTR *factoryId); + } + + [ + object, + uuid(d50e472e-b64b-490c-bca1-d30696f9f289), + pointer_default(unique) + ] + interface IUIAutomationProxyFactoryEntry : IUnknown + { + [propget] HRESULT ProxyFactory([out, retval] IUIAutomationProxyFactory **factory); + + [propget] HRESULT ClassName([out, retval] BSTR *className); + [propget] HRESULT ImageName([out, retval] BSTR *imageName); + [propget] HRESULT AllowSubstringMatch([out, retval] BOOL *allowSubstringMatch); + [propget] HRESULT CanCheckBaseClass([out, retval] BOOL *canCheckBaseClass); + [propget] HRESULT NeedsAdviseEvents([out, retval] BOOL *adviseEvents); + + [propput] HRESULT ClassName([in] LPCWSTR className); + [propput] HRESULT ImageName([in] LPCWSTR imageName); + [propput] HRESULT AllowSubstringMatch([in] BOOL allowSubstringMatch); + [propput] HRESULT CanCheckBaseClass([in] BOOL canCheckBaseClass); + [propput] HRESULT NeedsAdviseEvents([in] BOOL adviseEvents); + + HRESULT SetWinEventsForAutomationEvent( + [in] EVENTID eventId, + [in] PROPERTYID propertyId, + [in] SAFEARRAY(UINT) winEvents); + HRESULT GetWinEventsForAutomationEvent( + [in] EVENTID eventId, + [in] PROPERTYID propertyId, + [out, retval] SAFEARRAY(UINT) *winEvents); + } + + [ + object, + uuid(09e31e18-872d-4873-93d1-1e541ec133fd), + pointer_default(unique) + ] + interface IUIAutomationProxyFactoryMapping : IUnknown + { + [propget] HRESULT Count([out, retval] UINT *count); + + HRESULT GetTable([out, retval] SAFEARRAY(IUIAutomationProxyFactoryEntry) *table); + HRESULT GetEntry( + [in] UINT index, + [out, retval] IUIAutomationProxyFactoryEntry **entry); + + HRESULT SetTable([in] SAFEARRAY(IUIAutomationProxyFactoryEntry) factoryList); + HRESULT InsertEntries( + [in] UINT before, + [in] SAFEARRAY(IUIAutomationProxyFactoryEntry) factoryList); + HRESULT InsertEntry( + [in] UINT before, + [in] IUIAutomationProxyFactoryEntry *factory); + + HRESULT RemoveEntry([in] UINT index); + HRESULT ClearTable(); + HRESULT RestoreDefaultTable(); + } [ object, diff --git a/include/uiautomationcore.idl b/include/uiautomationcore.idl index 98894407441..715d9cf4b9e 100644 --- a/include/uiautomationcore.idl +++ b/include/uiautomationcore.idl @@ -63,12 +63,59 @@ enum OrientationType { OrientationType_Vertical = 0x0002, }; +enum DockPosition { + DockPosition_Top = 0x0000, + DockPosition_Left = 0x0001, + DockPosition_Bottom = 0x0002, + DockPosition_Right = 0x0003, + DockPosition_Fill = 0x0004, + DockPosition_None = 0x0005, +}; + +enum ExpandCollapseState { + ExpandCollapseState_Collapsed = 0x0000, + ExpandCollapseState_Expanded = 0x0001, + ExpandCollapseState_PartiallyExpanded = 0x0002, + ExpandCollapseState_LeafNode = 0x0003, +}; + +enum ScrollAmount { + ScrollAmount_LargeDecrement = 0x0000, + ScrollAmount_SmallDecrement = 0x0001, + ScrollAmount_NoAmount = 0x0002, + ScrollAmount_LargeIncrement = 0x0003, + ScrollAmount_SmallIncrement = 0x0004, +}; + +enum RowOrColumnMajor { + RowOrColumnMajor_RowMajor = 0x0000, + RowOrColumnMajor_ColumnMajor = 0x0001, + RowOrColumnMajor_Indeterminate = 0x0002, +}; + +enum ToggleState { + ToggleState_Off = 0x0000, + ToggleState_On = 0x0001, + ToggleState_Indeterminate = 0x0002, +}; + enum WindowVisualState { WindowVisualState_Normal = 0x0000, WindowVisualState_Maximized = 0x0001, WindowVisualState_Minimized = 0x0002, }; +enum SynchronizedInputType { + SynchronizedInputType_KeyUp = 0x0001, + SynchronizedInputType_KeyDown = 0x0002, + SynchronizedInputType_LeftMouseUp = 0x0004, + SynchronizedInputType_LeftMouseDown = 0x0008, + SynchronizedInputType_RightMouseUp = 0x0010, + SynchronizedInputType_RightMouseDown = 0x0020, +}; + +cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(SynchronizedInputType)") + enum WindowInteractionState { WindowInteractionState_Running = 0x0000, WindowInteractionState_Closing = 0x0001, @@ -77,12 +124,57 @@ enum WindowInteractionState { WindowInteractionState_NotResponding = 0x0004, }; +enum TextUnit { + TextUnit_Character = 0x0000, + TextUnit_Format = 0x0001, + TextUnit_Word = 0x0002, + TextUnit_Line = 0x0003, + TextUnit_Paragraph = 0x0004, + TextUnit_Page = 0x0005, + TextUnit_Document = 0x0006, +}; + +enum TextPatternRangeEndpoint { + TextPatternRangeEndpoint_Start = 0x0000, + TextPatternRangeEndpoint_End = 0x0001, +}; + +enum SupportedTextSelection { + SupportedTextSelection_None = 0x0000, + SupportedTextSelection_Single = 0x0001, + SupportedTextSelection_Multiple = 0x0002, +}; + enum LiveSetting { Off = 0x0000, Polite = 0x0001, Assertive = 0x0002, }; +enum ZoomUnit { + ZoomUnit_NoAmount = 0x0000, + ZoomUnit_LargeDecrement = 0x0001, + ZoomUnit_SmallDecrement = 0x0002, + ZoomUnit_LargeIncrement = 0x0003, + ZoomUnit_SmallIncrement = 0x0004, +}; + +enum NotificationProcessing { + NotificationProcessing_ImportantAll = 0x0000, + NotificationProcessing_ImportantMostRecent = 0x0001, + NotificationProcessing_All = 0x0002, + NotificationProcessing_MostRecent = 0x0003, + NotificationProcessing_CurrentThenMostRecent = 0x0004, +}; + +enum NotificationKind { + NotificationKind_ItemAdded = 0x0000, + NotificationKind_ItemRemoved = 0x0001, + NotificationKind_ActionCompleted = 0x0002, + NotificationKind_ActionAborted = 0x0003, + NotificationKind_Other = 0x0004, +}; + typedef int PROPERTYID; typedef int PATTERNID; typedef int EVENTID; From 6746bad90f56eb11ad02dd77fa6894bb65eb3207 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 29 Nov 2022 12:34:28 -0500 Subject: [PATCH 0761/2777] uiautomationcore: Implement UiaLookupId for AutomationIdentifierType_Event GUIDs. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 55 +++++++++++ dlls/uiautomationcore/uia_classes.idl | 6 ++ dlls/uiautomationcore/uia_ids.c | 110 ++++++++++++++++++++- include/uiautomationclient.idl | 2 + include/uiautomationcoreapi.h | 39 ++++++++ 5 files changed, 211 insertions(+), 1 deletion(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 2c76e1b6053..5fc5cbe4dbb 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -4169,6 +4169,47 @@ static const struct uia_lookup_id uia_property_lookup_ids[] = { { &IsDialog_Property_GUID, UIA_IsDialogPropertyId }, }; +static const struct uia_lookup_id uia_event_lookup_ids[] = { + { &ToolTipOpened_Event_GUID, UIA_ToolTipOpenedEventId }, + { &ToolTipClosed_Event_GUID, UIA_ToolTipClosedEventId }, + { &StructureChanged_Event_GUID, UIA_StructureChangedEventId }, + { &MenuOpened_Event_GUID, UIA_MenuOpenedEventId }, + { &AutomationPropertyChanged_Event_GUID, UIA_AutomationPropertyChangedEventId }, + { &AutomationFocusChanged_Event_GUID, UIA_AutomationFocusChangedEventId }, + { &AsyncContentLoaded_Event_GUID, UIA_AsyncContentLoadedEventId }, + { &MenuClosed_Event_GUID, UIA_MenuClosedEventId }, + { &LayoutInvalidated_Event_GUID, UIA_LayoutInvalidatedEventId }, + { &Invoke_Invoked_Event_GUID, UIA_Invoke_InvokedEventId }, + { &SelectionItem_ElementAddedToSelectionEvent_Event_GUID, UIA_SelectionItem_ElementAddedToSelectionEventId }, + { &SelectionItem_ElementRemovedFromSelectionEvent_Event_GUID, UIA_SelectionItem_ElementRemovedFromSelectionEventId }, + { &SelectionItem_ElementSelectedEvent_Event_GUID, UIA_SelectionItem_ElementSelectedEventId }, + { &Selection_InvalidatedEvent_Event_GUID, UIA_Selection_InvalidatedEventId }, + { &Text_TextSelectionChangedEvent_Event_GUID, UIA_Text_TextSelectionChangedEventId }, + { &Text_TextChangedEvent_Event_GUID, UIA_Text_TextChangedEventId }, + { &Window_WindowOpened_Event_GUID, UIA_Window_WindowOpenedEventId }, + { &Window_WindowClosed_Event_GUID, UIA_Window_WindowClosedEventId }, + { &MenuModeStart_Event_GUID, UIA_MenuModeStartEventId }, + { &MenuModeEnd_Event_GUID, UIA_MenuModeEndEventId }, + { &InputReachedTarget_Event_GUID, UIA_InputReachedTargetEventId }, + { &InputReachedOtherElement_Event_GUID, UIA_InputReachedOtherElementEventId }, + { &InputDiscarded_Event_GUID, UIA_InputDiscardedEventId }, + /* Implemented on Win8+ */ + { &SystemAlert_Event_GUID, UIA_SystemAlertEventId }, + { &LiveRegionChanged_Event_GUID, UIA_LiveRegionChangedEventId }, + { &HostedFragmentRootsInvalidated_Event_GUID, UIA_HostedFragmentRootsInvalidatedEventId }, + { &Drag_DragStart_Event_GUID, UIA_Drag_DragStartEventId }, + { &Drag_DragCancel_Event_GUID, UIA_Drag_DragCancelEventId }, + { &Drag_DragComplete_Event_GUID, UIA_Drag_DragCompleteEventId }, + { &DropTarget_DragEnter_Event_GUID, UIA_DropTarget_DragEnterEventId }, + { &DropTarget_DragLeave_Event_GUID, UIA_DropTarget_DragLeaveEventId }, + { &DropTarget_Dropped_Event_GUID, UIA_DropTarget_DroppedEventId }, + { &TextEdit_TextChanged_Event_GUID, UIA_TextEdit_TextChangedEventId }, + { &TextEdit_ConversionTargetChanged_Event_GUID, UIA_TextEdit_ConversionTargetChangedEventId }, + /* Implemented on Win10v1809+. */ + { &Changes_Event_GUID, UIA_ChangesEventId }, + { &Notification_Event_GUID, UIA_NotificationEventId }, +}; + static void test_UiaLookupId(void) { unsigned int i; @@ -4186,6 +4227,20 @@ static void test_UiaLookupId(void) ok(prop_id == uia_property_lookup_ids[i].id, "Unexpected Property id, expected %d, got %d\n", uia_property_lookup_ids[i].id, prop_id); } + + for (i = 0; i < ARRAY_SIZE(uia_event_lookup_ids); i++) + { + int event_id = UiaLookupId(AutomationIdentifierType_Event, uia_event_lookup_ids[i].guid); + + if (!event_id) + { + win_skip("No eventId for GUID %s, skipping further tests.\n", debugstr_guid(uia_event_lookup_ids[i].guid)); + break; + } + + ok(event_id == uia_event_lookup_ids[i].id, "Unexpected event id, expected %d, got %d\n", + uia_event_lookup_ids[i].id, event_id); + } } static const struct prov_method_sequence node_from_prov1[] = { diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index 2dc7981b702..ace1c12e70c 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -27,6 +27,12 @@ struct uia_prop_info { int type; }; +struct uia_event_info { + const GUID *guid; + int event_id; + int event_arg_type; +}; + [ version(1.0), uuid(8a9ca8eb-856b-43d9-abd7-4a590054064f), diff --git a/dlls/uiautomationcore/uia_ids.c b/dlls/uiautomationcore/uia_ids.c index 53e0f70b38d..dec07c8a62f 100644 --- a/dlls/uiautomationcore/uia_ids.c +++ b/dlls/uiautomationcore/uia_ids.c @@ -30,6 +30,13 @@ static int __cdecl uia_property_guid_compare(const void *a, const void *b) return memcmp(guid, property->guid, sizeof(*guid)); } +static int __cdecl uia_event_guid_compare(const void *a, const void *b) +{ + const GUID *guid = a; + const struct uia_event_info *event = b; + return memcmp(guid, event->guid, sizeof(*guid)); +} + /* Sorted by GUID. */ static const struct uia_prop_info default_uia_properties[] = { { &AutomationId_Property_GUID, UIA_AutomationIdPropertyId, @@ -309,6 +316,96 @@ const struct uia_prop_info *uia_prop_info_from_id(PROPERTYID prop_id) return &default_uia_properties[prop_id_idx[prop_id - PROP_ID_MIN]]; } +/* Sorted by GUID. */ +static const struct uia_event_info default_uia_events[] = { + { &Selection_InvalidatedEvent_Event_GUID, UIA_Selection_InvalidatedEventId, + EventArgsType_Simple, }, + { &Window_WindowOpened_Event_GUID, UIA_Window_WindowOpenedEventId, + EventArgsType_Simple, }, + { &TextEdit_TextChanged_Event_GUID, UIA_TextEdit_TextChangedEventId, + EventArgsType_TextEditTextChanged, }, + { &Drag_DragStart_Event_GUID, UIA_Drag_DragStartEventId, + EventArgsType_Simple, }, + { &Changes_Event_GUID, UIA_ChangesEventId, + EventArgsType_Changes, }, + { &DropTarget_DragLeave_Event_GUID, UIA_DropTarget_DragLeaveEventId, + EventArgsType_Simple, }, + { &AutomationFocusChanged_Event_GUID, UIA_AutomationFocusChangedEventId, + EventArgsType_Simple, }, + { &AsyncContentLoaded_Event_GUID, UIA_AsyncContentLoadedEventId, + EventArgsType_AsyncContentLoaded, }, + { &MenuModeStart_Event_GUID, UIA_MenuModeStartEventId, + EventArgsType_Simple, }, + { &HostedFragmentRootsInvalidated_Event_GUID, UIA_HostedFragmentRootsInvalidatedEventId, + EventArgsType_Simple, }, + { &LayoutInvalidated_Event_GUID, UIA_LayoutInvalidatedEventId, + EventArgsType_Simple, }, + { &MenuOpened_Event_GUID, UIA_MenuOpenedEventId, + EventArgsType_Simple, }, + { &SystemAlert_Event_GUID, UIA_SystemAlertEventId, + EventArgsType_Simple, }, + { &StructureChanged_Event_GUID, UIA_StructureChangedEventId, + EventArgsType_StructureChanged, }, + { &InputDiscarded_Event_GUID, UIA_InputDiscardedEventId, + EventArgsType_Simple, }, + { &MenuClosed_Event_GUID, UIA_MenuClosedEventId, + EventArgsType_Simple, }, + { &Text_TextChangedEvent_Event_GUID, UIA_Text_TextChangedEventId, + EventArgsType_Simple, }, + { &TextEdit_ConversionTargetChanged_Event_GUID, UIA_TextEdit_ConversionTargetChangedEventId, + EventArgsType_Simple, }, + { &Drag_DragComplete_Event_GUID, UIA_Drag_DragCompleteEventId, + EventArgsType_Simple, }, + { &InputReachedOtherElement_Event_GUID, UIA_InputReachedOtherElementEventId, + EventArgsType_Simple, }, + { &LiveRegionChanged_Event_GUID, UIA_LiveRegionChangedEventId, + EventArgsType_Simple, }, + { &InputReachedTarget_Event_GUID, UIA_InputReachedTargetEventId, + EventArgsType_Simple, }, + { &DropTarget_DragEnter_Event_GUID, UIA_DropTarget_DragEnterEventId, + EventArgsType_Simple, }, + { &MenuModeEnd_Event_GUID, UIA_MenuModeEndEventId, + EventArgsType_Simple, }, + { &Text_TextSelectionChangedEvent_Event_GUID, UIA_Text_TextSelectionChangedEventId, + EventArgsType_Simple, }, + { &AutomationPropertyChanged_Event_GUID, UIA_AutomationPropertyChangedEventId, + EventArgsType_PropertyChanged, }, + { &SelectionItem_ElementRemovedFromSelectionEvent_Event_GUID, UIA_SelectionItem_ElementRemovedFromSelectionEventId, + EventArgsType_Simple, }, + { &SelectionItem_ElementAddedToSelectionEvent_Event_GUID, UIA_SelectionItem_ElementAddedToSelectionEventId, + EventArgsType_Simple, }, + { &DropTarget_Dropped_Event_GUID, UIA_DropTarget_DroppedEventId, + EventArgsType_Simple, }, + { &ToolTipClosed_Event_GUID, UIA_ToolTipClosedEventId, + EventArgsType_Simple, }, + { &Invoke_Invoked_Event_GUID, UIA_Invoke_InvokedEventId, + EventArgsType_Simple, }, + { &Notification_Event_GUID, UIA_NotificationEventId, + EventArgsType_Notification, }, + { &Window_WindowClosed_Event_GUID, UIA_Window_WindowClosedEventId, + EventArgsType_WindowClosed, }, + { &Drag_DragCancel_Event_GUID, UIA_Drag_DragCancelEventId, + EventArgsType_Simple, }, + { &SelectionItem_ElementSelectedEvent_Event_GUID, UIA_SelectionItem_ElementSelectedEventId, + EventArgsType_Simple, }, + { &ToolTipOpened_Event_GUID, UIA_ToolTipOpenedEventId, + EventArgsType_Simple, }, +}; + +#define EVENT_ID_MIN 20000 +#define EVENT_ID_MAX (EVENT_ID_MIN + ARRAY_SIZE(default_uia_events)) + +static const struct uia_event_info *uia_event_info_from_guid(const GUID *guid) +{ + struct uia_event_info *event; + + if ((event = bsearch(guid, default_uia_events, ARRAY_SIZE(default_uia_events), sizeof(*event), + uia_event_guid_compare))) + return event; + + return NULL; +} + /*********************************************************************** * UiaLookupId (uiautomationcore.@) */ @@ -332,8 +429,19 @@ int WINAPI UiaLookupId(enum AutomationIdentifierType type, const GUID *guid) break; } - case AutomationIdentifierType_Pattern: case AutomationIdentifierType_Event: + { + const struct uia_event_info *event = uia_event_info_from_guid(guid); + + if (event) + ret_id = event->event_id; + else + FIXME("Failed to find eventId for GUID %s\n", debugstr_guid(guid)); + + break; + } + + case AutomationIdentifierType_Pattern: case AutomationIdentifierType_ControlType: case AutomationIdentifierType_TextAttribute: case AutomationIdentifierType_LandmarkType: diff --git a/include/uiautomationclient.idl b/include/uiautomationclient.idl index 4579e4db652..ce0402a5d33 100644 --- a/include/uiautomationclient.idl +++ b/include/uiautomationclient.idl @@ -156,6 +156,8 @@ library UIAutomationClient { const long UIA_DropTarget_DroppedEventId = 20031; const long UIA_TextEdit_TextChangedEventId = 20032; const long UIA_TextEdit_ConversionTargetChangedEventId = 20033; + const long UIA_ChangesEventId = 20034; + const long UIA_NotificationEventId = 20035; /* }; */ diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h index 6e60db4a76d..64a1a80768d 100644 --- a/include/uiautomationcoreapi.h +++ b/include/uiautomationcoreapi.h @@ -221,6 +221,45 @@ DEFINE_GUID(Selection2_ItemCount_Property_GUID, 0xbb49eb9f,0x456d DEFINE_GUID(HeadingLevel_Property_GUID, 0x29084272,0xaaaf,0x4a30,0x87,0x96,0x3c,0x12,0xf6,0x2b,0x6b,0xbb); DEFINE_GUID(IsDialog_Property_GUID, 0x9d0dfb9b,0x8436,0x4501,0xbb,0xbb,0xe5,0x34,0xa4,0xfb,0x3b,0x3f); +/* + * AutomationIdentifierType_Event GUIDs. + */ +DEFINE_GUID(ToolTipOpened_Event_GUID, 0x3f4b97ff,0x2edc,0x451d,0xbc,0xa4,0x95,0xa3,0x18,0x8d,0x5b,0x03); +DEFINE_GUID(ToolTipClosed_Event_GUID, 0x276d71ef,0x24a9,0x49b6,0x8e,0x97,0xda,0x98,0xb4,0x01,0xbb,0xcd); +DEFINE_GUID(StructureChanged_Event_GUID, 0x59977961,0x3edd,0x4b11,0xb1,0x3b,0x67,0x6b,0x2a,0x2a,0x6c,0xa9); +DEFINE_GUID(MenuOpened_Event_GUID, 0xebe2e945,0x66ca,0x4ed1,0x9f,0xf8,0x2a,0xd7,0xdf,0x0a,0x1b,0x08); +DEFINE_GUID(AutomationPropertyChanged_Event_GUID, 0x2527fba1,0x8d7a,0x4630,0xa4,0xcc,0xe6,0x63,0x15,0x94,0x2f,0x52); +DEFINE_GUID(AutomationFocusChanged_Event_GUID, 0xb68a1f17,0xf60d,0x41a7,0xa3,0xcc,0xb0,0x52,0x92,0x15,0x5f,0xe0); +DEFINE_GUID(AsyncContentLoaded_Event_GUID, 0x5fdee11c,0xd2fa,0x4fb9,0x90,0x4e,0x5c,0xbe,0xe8,0x94,0xd5,0xef); +DEFINE_GUID(MenuClosed_Event_GUID, 0x3cf1266e,0x1582,0x4041,0xac,0xd7,0x88,0xa3,0x5a,0x96,0x52,0x97); +DEFINE_GUID(LayoutInvalidated_Event_GUID, 0xed7d6544,0xa6bd,0x4595,0x9b,0xae,0x3d,0x28,0x94,0x6c,0xc7,0x15); +DEFINE_GUID(Invoke_Invoked_Event_GUID, 0xdfd699f0,0xc915,0x49dd,0xb4,0x22,0xdd,0xe7,0x85,0xc3,0xd2,0x4b); +DEFINE_GUID(SelectionItem_ElementAddedToSelectionEvent_Event_GUID, 0x3c822dd1,0xc407,0x4dba,0x91,0xdd,0x79,0xd4,0xae,0xd0,0xae,0xc6); +DEFINE_GUID(SelectionItem_ElementRemovedFromSelectionEvent_Event_GUID, 0x097fa8a9,0x7079,0x41af,0x8b,0x9c,0x09,0x34,0xd8,0x30,0x5e,0x5c); +DEFINE_GUID(SelectionItem_ElementSelectedEvent_Event_GUID, 0xb9c7dbfb,0x4ebe,0x4532,0xaa,0xf4,0x00,0x8c,0xf6,0x47,0x23,0x3c); +DEFINE_GUID(Selection_InvalidatedEvent_Event_GUID, 0xcac14904,0x16b4,0x4b53,0x8e,0x47,0x4c,0xb1,0xdf,0x26,0x7b,0xb7); +DEFINE_GUID(Text_TextSelectionChangedEvent_Event_GUID, 0x918edaa1,0x71b3,0x49ae,0x97,0x41,0x79,0xbe,0xb8,0xd3,0x58,0xf3); +DEFINE_GUID(Text_TextChangedEvent_Event_GUID, 0x4a342082,0xf483,0x48c4,0xac,0x11,0xa8,0x4b,0x43,0x5e,0x2a,0x84); +DEFINE_GUID(Window_WindowOpened_Event_GUID, 0xd3e81d06,0xde45,0x4f2f,0x96,0x33,0xde,0x9e,0x02,0xfb,0x65,0xaf); +DEFINE_GUID(Window_WindowClosed_Event_GUID, 0xedf141f8,0xfa67,0x4e22,0xbb,0xf7,0x94,0x4e,0x05,0x73,0x5e,0xe2); +DEFINE_GUID(MenuModeStart_Event_GUID, 0x18d7c631,0x166a,0x4ac9,0xae,0x3b,0xef,0x4b,0x54,0x20,0xe6,0x81); +DEFINE_GUID(MenuModeEnd_Event_GUID, 0x9ecd4c9f,0x80dd,0x47b8,0x82,0x67,0x5a,0xec,0x06,0xbb,0x2c,0xff); +DEFINE_GUID(InputReachedTarget_Event_GUID, 0x93ed549a,0x0549,0x40f0,0xbe,0xdb,0x28,0xe4,0x4f,0x7d,0xe2,0xa3); +DEFINE_GUID(InputReachedOtherElement_Event_GUID, 0xed201d8a,0x4e6c,0x415e,0xa8,0x74,0x24,0x60,0xc9,0xb6,0x6b,0xa8); +DEFINE_GUID(InputDiscarded_Event_GUID, 0x7f36c367,0x7b18,0x417c,0x97,0xe3,0x9d,0x58,0xdd,0xc9,0x44,0xab); +DEFINE_GUID(SystemAlert_Event_GUID, 0xd271545d,0x7a3a,0x47a7,0x84,0x74,0x81,0xd2,0x9a,0x24,0x51,0xc9); +DEFINE_GUID(LiveRegionChanged_Event_GUID, 0x102d5e90,0xe6a9,0x41b6,0xb1,0xc5,0xa9,0xb1,0x92,0x9d,0x95,0x10); +DEFINE_GUID(HostedFragmentRootsInvalidated_Event_GUID, 0xe6bdb03e,0x0921,0x4ec5,0x8d,0xcf,0xea,0xe8,0x77,0xb0,0x42,0x6b); +DEFINE_GUID(Drag_DragStart_Event_GUID, 0x883a480b,0x3aa9,0x429d,0x95,0xe4,0xd9,0xc8,0xd0,0x11,0xf0,0xdd); +DEFINE_GUID(Drag_DragCancel_Event_GUID, 0xc3ede6fa,0x3451,0x4e0f,0x9e,0x71,0xdf,0x9c,0x28,0x0a,0x46,0x57); +DEFINE_GUID(Drag_DragComplete_Event_GUID, 0x38e96188,0xef1f,0x463e,0x91,0xca,0x3a,0x77,0x92,0xc2,0x9c,0xaf); +DEFINE_GUID(DropTarget_DragEnter_Event_GUID, 0xaad9319b,0x032c,0x4a88,0x96,0x1d,0x1c,0xf5,0x79,0x58,0x1e,0x34); +DEFINE_GUID(DropTarget_DragLeave_Event_GUID, 0x0f82eb15,0x24a2,0x4988,0x92,0x17,0xde,0x16,0x2a,0xee,0x27,0x2b); +DEFINE_GUID(DropTarget_Dropped_Event_GUID, 0x622cead8,0x1edb,0x4a3d,0xab,0xbc,0xbe,0x22,0x11,0xff,0x68,0xb5); +DEFINE_GUID(TextEdit_TextChanged_Event_GUID, 0x120b0308,0xec22,0x4eb8,0x9c,0x98,0x98,0x67,0xcd,0xa1,0xb1,0x65); +DEFINE_GUID(TextEdit_ConversionTargetChanged_Event_GUID, 0x3388c183,0xed4f,0x4c8b,0x9b,0xaa,0x36,0x4d,0x51,0xd8,0x84,0x7f); +DEFINE_GUID(Changes_Event_GUID, 0x7df26714,0x614f,0x4e05,0x94,0x88,0x71,0x6c,0x5b,0xa1,0x94,0x36); +DEFINE_GUID(Notification_Event_GUID, 0x72c5a2f7,0x9788,0x480f,0xb8,0xeb,0x4d,0xee,0x00,0xf6,0x18,0x6f); enum AutomationIdentifierType { From 2fe9dc9fbdc2e8e48a7f4da27f59a8867e524526 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 27 Dec 2022 14:56:21 -0500 Subject: [PATCH 0762/2777] uiautomationcore: Register all UI Automation typelibs. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/Makefile.in | 4 +++- dlls/uiautomationcore/uia_classes.idl | 1 + dlls/uiautomationcore/uia_classes_client.idl | 21 ++++++++++++++++++++ dlls/uiautomationcore/uia_classes_core.idl | 21 ++++++++++++++++++++ include/uiautomationclient.idl | 1 + include/uiautomationcore.idl | 1 + 6 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 dlls/uiautomationcore/uia_classes_client.idl create mode 100644 dlls/uiautomationcore/uia_classes_core.idl diff --git a/dlls/uiautomationcore/Makefile.in b/dlls/uiautomationcore/Makefile.in index 9910e8e336e..a597c580b24 100644 --- a/dlls/uiautomationcore/Makefile.in +++ b/dlls/uiautomationcore/Makefile.in @@ -11,4 +11,6 @@ C_SRCS = \ uia_provider.c IDL_SRCS = \ - uia_classes.idl + uia_classes.idl \ + uia_classes_client.idl \ + uia_classes_core.idl diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index ace1c12e70c..44479303888 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -36,6 +36,7 @@ struct uia_event_info { [ version(1.0), uuid(8a9ca8eb-856b-43d9-abd7-4a590054064f), + id(1), ] library UIA_wine_private { diff --git a/dlls/uiautomationcore/uia_classes_client.idl b/dlls/uiautomationcore/uia_classes_client.idl new file mode 100644 index 00000000000..f6dcb236bea --- /dev/null +++ b/dlls/uiautomationcore/uia_classes_client.idl @@ -0,0 +1,21 @@ +/* + * Copyright 2022 Connor McAdams 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 + */ + +#pragma makedep regtypelib + +#include "uiautomationclient.idl" diff --git a/dlls/uiautomationcore/uia_classes_core.idl b/dlls/uiautomationcore/uia_classes_core.idl new file mode 100644 index 00000000000..a0a1ebb2bf0 --- /dev/null +++ b/dlls/uiautomationcore/uia_classes_core.idl @@ -0,0 +1,21 @@ +/* + * Copyright 2022 Connor McAdams 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 + */ + +#pragma makedep regtypelib + +#include "uiautomationcore.idl" diff --git a/include/uiautomationclient.idl b/include/uiautomationclient.idl index ce0402a5d33..7a0b50288d4 100644 --- a/include/uiautomationclient.idl +++ b/include/uiautomationclient.idl @@ -69,6 +69,7 @@ typedef void * UIA_HWND; [ uuid(944de083-8fb8-45cf-bcb7-c477acb2f897), lcid(0), + id(2), version(1.0) ] library UIAutomationClient { diff --git a/include/uiautomationcore.idl b/include/uiautomationcore.idl index 715d9cf4b9e..ad6140f41b0 100644 --- a/include/uiautomationcore.idl +++ b/include/uiautomationcore.idl @@ -201,6 +201,7 @@ struct UiaChangeInfo { version(1.0), uuid(930299ce-9965-4dec-b0f4-a54848d4b667), lcid(0), + id(3), hidden ] library UIA From c53a8105e3dc565db0d756ea0756be211e0ca8d7 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 14 Dec 2022 10:58:10 -0500 Subject: [PATCH 0763/2777] uiautomationcore: Add stub IUIAutomation implementation. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/Makefile.in | 1 + dlls/uiautomationcore/tests/uiautomation.c | 46 ++ dlls/uiautomationcore/uia_com_client.c | 702 ++++++++++++++++++++ dlls/uiautomationcore/uia_main.c | 127 ++++ dlls/uiautomationcore/uia_private.h | 3 + dlls/uiautomationcore/uiautomationcore.spec | 2 +- 6 files changed, 880 insertions(+), 1 deletion(-) create mode 100644 dlls/uiautomationcore/uia_com_client.c diff --git a/dlls/uiautomationcore/Makefile.in b/dlls/uiautomationcore/Makefile.in index a597c580b24..28d814e6ee6 100644 --- a/dlls/uiautomationcore/Makefile.in +++ b/dlls/uiautomationcore/Makefile.in @@ -6,6 +6,7 @@ EXTRADLLFLAGS = -Wb,--prefer-native C_SRCS = \ uia_client.c \ + uia_com_client.c \ uia_ids.c \ uia_main.c \ uia_provider.c diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 5fc5cbe4dbb..7b9e25f32a7 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -9804,6 +9804,51 @@ static void test_default_proxy_providers(void) CoUninitialize(); } +struct uia_com_classes { + const GUID *clsid; + const GUID *iid; +}; + +static const struct uia_com_classes com_classes[] = { + { &CLSID_CUIAutomation, &IID_IUIAutomation }, + { &CLSID_CUIAutomation8, &IID_IUIAutomation }, + { &CLSID_CUIAutomation8, &IID_IUIAutomation2 }, + { &CLSID_CUIAutomation8, &IID_IUIAutomation3 }, + { &CLSID_CUIAutomation8, &IID_IUIAutomation4 }, + { &CLSID_CUIAutomation8, &IID_IUIAutomation5 }, + { &CLSID_CUIAutomation8, &IID_IUIAutomation6 }, +}; + +static void test_CUIAutomation(void) +{ + IUIAutomation *uia_iface; + HRESULT hr; + int i; + + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + for (i = 0; i < ARRAY_SIZE(com_classes); i++) + { + uia_iface = NULL; + hr = CoCreateInstance(com_classes[i].clsid, NULL, CLSCTX_INPROC_SERVER, com_classes[i].iid, + (void **)&uia_iface); + + if (i && (hr == E_NOINTERFACE)) + { + win_skip("No object for clsid %s, iid %s, skipping further tests.\n", debugstr_guid(com_classes[i].clsid), + debugstr_guid(com_classes[i].iid)); + break; + } + + ok(hr == S_OK, "Failed to create interface for clsid %s, iid %s, hr %#lx\n", + debugstr_guid(com_classes[i].clsid), debugstr_guid(com_classes[i].iid), hr); + ok(!!uia_iface, "uia_iface == NULL\n"); + IUIAutomation_Release(uia_iface); + } + + CoUninitialize(); +} + /* * Once a process returns a UI Automation provider with * UiaReturnRawElementProvider it ends up in an implicit MTA until exit. This @@ -9871,6 +9916,7 @@ START_TEST(uiautomation) test_UiaNavigate(); test_UiaFind(); test_default_proxy_providers(); + test_CUIAutomation(); if (uia_dll) { pUiaProviderFromIAccessible = (void *)GetProcAddress(uia_dll, "UiaProviderFromIAccessible"); diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c new file mode 100644 index 00000000000..6b25e851c04 --- /dev/null +++ b/dlls/uiautomationcore/uia_com_client.c @@ -0,0 +1,702 @@ +/* + * Copyright 2022 Connor McAdams 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 + */ + +#include "uia_private.h" + +#include "wine/debug.h" +#include "wine/heap.h" + +WINE_DEFAULT_DEBUG_CHANNEL(uiautomation); + +/* + * IUIAutomation interface. + */ +struct uia_iface { + IUIAutomation6 IUIAutomation6_iface; + LONG ref; + + BOOL is_cui8; +}; + +static inline struct uia_iface *impl_from_IUIAutomation6(IUIAutomation6 *iface) +{ + return CONTAINING_RECORD(iface, struct uia_iface, IUIAutomation6_iface); +} + +static HRESULT WINAPI uia_iface_QueryInterface(IUIAutomation6 *iface, REFIID riid, void **ppv) +{ + struct uia_iface *uia_iface = impl_from_IUIAutomation6(iface); + + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUIAutomation) || IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else if (uia_iface->is_cui8 && + (IsEqualIID(riid, &IID_IUIAutomation2) || + IsEqualIID(riid, &IID_IUIAutomation3) || + IsEqualIID(riid, &IID_IUIAutomation4) || + IsEqualIID(riid, &IID_IUIAutomation5) || + IsEqualIID(riid, &IID_IUIAutomation6))) + *ppv = iface; + else + return E_NOINTERFACE; + + IUIAutomation6_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI uia_iface_AddRef(IUIAutomation6 *iface) +{ + struct uia_iface *uia_iface = impl_from_IUIAutomation6(iface); + ULONG ref = InterlockedIncrement(&uia_iface->ref); + + TRACE("%p, refcount %ld\n", uia_iface, ref); + return ref; +} + +static ULONG WINAPI uia_iface_Release(IUIAutomation6 *iface) +{ + struct uia_iface *uia_iface = impl_from_IUIAutomation6(iface); + ULONG ref = InterlockedDecrement(&uia_iface->ref); + + TRACE("%p, refcount %ld\n", uia_iface, ref); + if (!ref) + heap_free(uia_iface); + return ref; +} + +static HRESULT WINAPI uia_iface_CompareElements(IUIAutomation6 *iface, IUIAutomationElement *elem1, + IUIAutomationElement *elem2, BOOL *match) +{ + FIXME("%p, %p, %p, %p: stub\n", iface, elem1, elem2, match); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_CompareRuntimeIds(IUIAutomation6 *iface, SAFEARRAY *rt_id1, SAFEARRAY *rt_id2, + BOOL *match) +{ + FIXME("%p, %p, %p, %p: stub\n", iface, rt_id1, rt_id2, match); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_GetRootElement(IUIAutomation6 *iface, IUIAutomationElement **root) +{ + FIXME("%p, %p: stub\n", iface, root); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_ElementFromHandle(IUIAutomation6 *iface, UIA_HWND hwnd, IUIAutomationElement **out_elem) +{ + FIXME("%p, %p, %p: stub\n", iface, hwnd, out_elem); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_ElementFromPoint(IUIAutomation6 *iface, POINT pt, IUIAutomationElement **out_elem) +{ + FIXME("%p, %s, %p: stub\n", iface, wine_dbgstr_point(&pt), out_elem); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_GetFocusedElement(IUIAutomation6 *iface, IUIAutomationElement **out_elem) +{ + FIXME("%p, %p: stub\n", iface, out_elem); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_GetRootElementBuildCache(IUIAutomation6 *iface, IUIAutomationCacheRequest *cache_req, + IUIAutomationElement **out_root) +{ + FIXME("%p, %p, %p: stub\n", iface, cache_req, out_root); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_ElementFromHandleBuildCache(IUIAutomation6 *iface, UIA_HWND hwnd, + IUIAutomationCacheRequest *cache_req, IUIAutomationElement **out_elem) +{ + FIXME("%p, %p, %p, %p: stub\n", iface, hwnd, cache_req, out_elem); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_ElementFromPointBuildCache(IUIAutomation6 *iface, POINT pt, + IUIAutomationCacheRequest *cache_req, IUIAutomationElement **out_elem) +{ + FIXME("%p, %s, %p, %p: stub\n", iface, wine_dbgstr_point(&pt), cache_req, out_elem); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_GetFocusedElementBuildCache(IUIAutomation6 *iface, + IUIAutomationCacheRequest *cache_req, IUIAutomationElement **out_elem) +{ + FIXME("%p, %p, %p: stub\n", iface, cache_req, out_elem); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_CreateTreeWalker(IUIAutomation6 *iface, IUIAutomationCondition *cond, + IUIAutomationTreeWalker **out_walker) +{ + FIXME("%p, %p, %p: stub\n", iface, cond, out_walker); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_get_ControlViewWalker(IUIAutomation6 *iface, IUIAutomationTreeWalker **out_walker) +{ + FIXME("%p, %p: stub\n", iface, out_walker); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_get_ContentViewWalker(IUIAutomation6 *iface, IUIAutomationTreeWalker **out_walker) +{ + FIXME("%p, %p: stub\n", iface, out_walker); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_get_RawViewWalker(IUIAutomation6 *iface, IUIAutomationTreeWalker **out_walker) +{ + FIXME("%p, %p: stub\n", iface, out_walker); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_get_RawViewCondition(IUIAutomation6 *iface, IUIAutomationCondition **out_condition) +{ + FIXME("%p, %p: stub\n", iface, out_condition); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_get_ControlViewCondition(IUIAutomation6 *iface, IUIAutomationCondition **out_condition) +{ + FIXME("%p, %p: stub\n", iface, out_condition); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_get_ContentViewCondition(IUIAutomation6 *iface, IUIAutomationCondition **out_condition) +{ + FIXME("%p, %p: stub\n", iface, out_condition); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_CreateCacheRequest(IUIAutomation6 *iface, IUIAutomationCacheRequest **out_cache_req) +{ + FIXME("%p, %p: stub\n", iface, out_cache_req); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_CreateTrueCondition(IUIAutomation6 *iface, IUIAutomationCondition **out_condition) +{ + FIXME("%p, %p: stub\n", iface, out_condition); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_CreateFalseCondition(IUIAutomation6 *iface, IUIAutomationCondition **out_condition) +{ + FIXME("%p, %p: stub\n", iface, out_condition); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_CreatePropertyCondition(IUIAutomation6 *iface, PROPERTYID prop_id, VARIANT val, + IUIAutomationCondition **out_condition) +{ + FIXME("%p, %d, %s, %p: stub\n", iface, prop_id, debugstr_variant(&val), out_condition); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_CreatePropertyConditionEx(IUIAutomation6 *iface, PROPERTYID prop_id, VARIANT val, + enum PropertyConditionFlags flags, IUIAutomationCondition **out_condition) +{ + FIXME("%p, %d, %s, %#x, %p: stub\n", iface, prop_id, debugstr_variant(&val), flags, out_condition); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_CreateAndCondition(IUIAutomation6 *iface, IUIAutomationCondition *cond1, + IUIAutomationCondition *cond2, IUIAutomationCondition **out_condition) +{ + FIXME("%p, %p, %p, %p: stub\n", iface, cond1, cond2, out_condition); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_CreateAndConditionFromArray(IUIAutomation6 *iface, SAFEARRAY *conds, + IUIAutomationCondition **out_condition) +{ + FIXME("%p, %p, %p: stub\n", iface, conds, out_condition); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_CreateAndConditionFromNativeArray(IUIAutomation6 *iface, IUIAutomationCondition **conds, + int conds_count, IUIAutomationCondition **out_condition) +{ + FIXME("%p, %p, %d, %p: stub\n", iface, conds, conds_count, out_condition); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_CreateOrCondition(IUIAutomation6 *iface, IUIAutomationCondition *cond1, + IUIAutomationCondition *cond2, IUIAutomationCondition **out_condition) +{ + FIXME("%p, %p, %p, %p: stub\n", iface, cond1, cond2, out_condition); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_CreateOrConditionFromArray(IUIAutomation6 *iface, SAFEARRAY *conds, + IUIAutomationCondition **out_condition) +{ + FIXME("%p, %p, %p: stub\n", iface, conds, out_condition); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_CreateOrConditionFromNativeArray(IUIAutomation6 *iface, IUIAutomationCondition **conds, + int conds_count, IUIAutomationCondition **out_condition) +{ + FIXME("%p, %p, %d, %p: stub\n", iface, conds, conds_count, out_condition); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_CreateNotCondition(IUIAutomation6 *iface, IUIAutomationCondition *cond, + IUIAutomationCondition **out_condition) +{ + FIXME("%p, %p, %p: stub\n", iface, cond, out_condition); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_AddAutomationEventHandler(IUIAutomation6 *iface, EVENTID event_id, + IUIAutomationElement *elem, enum TreeScope scope, IUIAutomationCacheRequest *cache_req, + IUIAutomationEventHandler *handler) +{ + FIXME("%p, %d, %p, %#x, %p, %p: stub\n", iface, event_id, elem, scope, cache_req, handler); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_RemoveAutomationEventHandler(IUIAutomation6 *iface, EVENTID event_id, + IUIAutomationElement *elem, IUIAutomationEventHandler *handler) +{ + FIXME("%p, %d, %p, %p: stub\n", iface, event_id, elem, handler); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_AddPropertyChangedEventHandlerNativeArray(IUIAutomation6 *iface, + IUIAutomationElement *elem, enum TreeScope scope, IUIAutomationCacheRequest *cache_req, + IUIAutomationPropertyChangedEventHandler *handler, PROPERTYID *props, int props_count) +{ + FIXME("%p, %p, %#x, %p, %p, %p, %d: stub\n", iface, elem, scope, cache_req, handler, props, props_count); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_AddPropertyChangedEventHandler(IUIAutomation6 *iface, + IUIAutomationElement *elem, enum TreeScope scope, IUIAutomationCacheRequest *cache_req, + IUIAutomationPropertyChangedEventHandler *handler, SAFEARRAY *props) +{ + FIXME("%p, %p, %#x, %p, %p, %p: stub\n", iface, elem, scope, cache_req, handler, props); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_RemovePropertyChangedEventHandler(IUIAutomation6 *iface, + IUIAutomationElement *elem, IUIAutomationPropertyChangedEventHandler *handler) +{ + FIXME("%p, %p, %p: stub\n", iface, elem, handler); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_AddStructureChangedEventHandler(IUIAutomation6 *iface, + IUIAutomationElement *elem, enum TreeScope scope, IUIAutomationCacheRequest *cache_req, + IUIAutomationStructureChangedEventHandler *handler) +{ + FIXME("%p, %p, %#x, %p, %p: stub\n", iface, elem, scope, cache_req, handler); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_RemoveStructureChangedEventHandler(IUIAutomation6 *iface, + IUIAutomationElement *elem, IUIAutomationStructureChangedEventHandler *handler) +{ + FIXME("%p, %p, %p: stub\n", iface, elem, handler); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_AddFocusChangedEventHandler(IUIAutomation6 *iface, + IUIAutomationCacheRequest *cache_req, IUIAutomationFocusChangedEventHandler *handler) +{ + FIXME("%p, %p, %p: stub\n", iface, cache_req, handler); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_RemoveFocusChangedEventHandler(IUIAutomation6 *iface, + IUIAutomationFocusChangedEventHandler *handler) +{ + FIXME("%p, %p: stub\n", iface, handler); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_RemoveAllEventHandlers(IUIAutomation6 *iface) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_IntNativeArrayToSafeArray(IUIAutomation6 *iface, int *arr, int arr_count, + SAFEARRAY **out_sa) +{ + FIXME("%p, %p, %d, %p: stub\n", iface, arr, arr_count, out_sa); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_IntSafeArrayToNativeArray(IUIAutomation6 *iface, SAFEARRAY *sa, int **out_arr, + int *out_arr_count) +{ + FIXME("%p, %p, %p, %p: stub\n", iface, sa, out_arr, out_arr_count); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_RectToVariant(IUIAutomation6 *iface, RECT rect, VARIANT *out_var) +{ + FIXME("%p, %s, %p: stub\n", iface, wine_dbgstr_rect(&rect), out_var); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_VariantToRect(IUIAutomation6 *iface, VARIANT var, RECT *out_rect) +{ + FIXME("%p, %s, %p: stub\n", iface, debugstr_variant(&var), out_rect); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_SafeArrayToRectNativeArray(IUIAutomation6 *iface, SAFEARRAY *sa, RECT **out_rect_arr, + int *out_rect_arr_count) +{ + FIXME("%p, %p, %p, %p: stub\n", iface, sa, out_rect_arr, out_rect_arr_count); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_CreateProxyFactoryEntry(IUIAutomation6 *iface, IUIAutomationProxyFactory *factory, + IUIAutomationProxyFactoryEntry **out_entry) +{ + FIXME("%p, %p, %p: stub\n", iface, factory, out_entry); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_get_ProxyFactoryMapping(IUIAutomation6 *iface, + IUIAutomationProxyFactoryMapping **out_factory_map) +{ + FIXME("%p, %p: stub\n", iface, out_factory_map); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_GetPropertyProgrammaticName(IUIAutomation6 *iface, PROPERTYID prop_id, BSTR *out_name) +{ + FIXME("%p, %d, %p: stub\n", iface, prop_id, out_name); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_GetPatternProgrammaticName(IUIAutomation6 *iface, PATTERNID pattern_id, BSTR *out_name) +{ + FIXME("%p, %d, %p: stub\n", iface, pattern_id, out_name); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_PollForPotentialSupportedPatterns(IUIAutomation6 *iface, IUIAutomationElement *elem, + SAFEARRAY **out_pattern_ids, SAFEARRAY **out_pattern_names) +{ + FIXME("%p, %p, %p, %p: stub\n", iface, elem, out_pattern_ids, out_pattern_names); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_PollForPotentialSupportedProperties(IUIAutomation6 *iface, IUIAutomationElement *elem, + SAFEARRAY **out_prop_ids, SAFEARRAY **out_prop_names) +{ + FIXME("%p, %p, %p, %p: stub\n", iface, elem, out_prop_ids, out_prop_names); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_CheckNotSupported(IUIAutomation6 *iface, VARIANT in_val, BOOL *match) +{ + FIXME("%p, %s, %p: stub\n", iface, debugstr_variant(&in_val), match); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_get_ReservedNotSupportedValue(IUIAutomation6 *iface, IUnknown **out_unk) +{ + FIXME("%p, %p: stub\n", iface, out_unk); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_get_ReservedMixedAttributeValue(IUIAutomation6 *iface, IUnknown **out_unk) +{ + FIXME("%p, %p: stub\n", iface, out_unk); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_ElementFromIAccessible(IUIAutomation6 *iface, IAccessible *acc, int cid, + IUIAutomationElement **out_elem) +{ + FIXME("%p, %p, %d, %p: stub\n", iface, acc, cid, out_elem); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_ElementFromIAccessibleBuildCache(IUIAutomation6 *iface, IAccessible *acc, int cid, + IUIAutomationCacheRequest *cache_req, IUIAutomationElement **out_elem) +{ + FIXME("%p, %p, %d, %p, %p: stub\n", iface, acc, cid, cache_req, out_elem); + return E_NOTIMPL; +} + +/* IUIAutomation2 methods */ +static HRESULT WINAPI uia_iface_get_AutoSetFocus(IUIAutomation6 *iface, BOOL *out_auto_set_focus) +{ + FIXME("%p, %p: stub\n", iface, out_auto_set_focus); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_put_AutoSetFocus(IUIAutomation6 *iface, BOOL auto_set_focus) +{ + FIXME("%p, %d: stub\n", iface, auto_set_focus); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_get_ConnectionTimeout(IUIAutomation6 *iface, DWORD *out_timeout) +{ + FIXME("%p, %p: stub\n", iface, out_timeout); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_put_ConnectionTimeout(IUIAutomation6 *iface, DWORD timeout) +{ + FIXME("%p, %ld: stub\n", iface, timeout); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_get_TransactionTimeout(IUIAutomation6 *iface, DWORD *out_timeout) +{ + FIXME("%p, %p: stub\n", iface, out_timeout); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_put_TransactionTimeout(IUIAutomation6 *iface, DWORD timeout) +{ + FIXME("%p, %ld: stub\n", iface, timeout); + return E_NOTIMPL; +} + +/* IUIAutomation3 methods */ +static HRESULT WINAPI uia_iface_AddTextEditTextChangedEventHandler(IUIAutomation6 *iface, IUIAutomationElement *elem, + enum TreeScope scope, enum TextEditChangeType change_type, IUIAutomationCacheRequest *cache_req, + IUIAutomationTextEditTextChangedEventHandler *handler) +{ + FIXME("%p, %p, %#x, %d, %p, %p: stub\n", iface, elem, scope, change_type, cache_req, handler); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_RemoveTextEditTextChangedEventHandler(IUIAutomation6 *iface, IUIAutomationElement *elem, + IUIAutomationTextEditTextChangedEventHandler *handler) +{ + FIXME("%p, %p, %p: stub\n", iface, elem, handler); + return E_NOTIMPL; +} + +/* IUIAutomation4 methods */ +static HRESULT WINAPI uia_iface_AddChangesEventHandler(IUIAutomation6 *iface, IUIAutomationElement *elem, + enum TreeScope scope, int *change_types, int change_types_count, IUIAutomationCacheRequest *cache_req, + IUIAutomationChangesEventHandler *handler) +{ + FIXME("%p, %p, %#x, %p, %d, %p, %p: stub\n", iface, elem, scope, change_types, change_types_count, cache_req, + handler); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_RemoveChangesEventHandler(IUIAutomation6 *iface, IUIAutomationElement *elem, + IUIAutomationChangesEventHandler *handler) +{ + FIXME("%p, %p, %p: stub\n", iface, elem, handler); + return E_NOTIMPL; +} + +/* IUIAutomation5 methods */ +static HRESULT WINAPI uia_iface_AddNotificationEventHandler(IUIAutomation6 *iface, IUIAutomationElement *elem, + enum TreeScope scope, IUIAutomationCacheRequest *cache_req, IUIAutomationNotificationEventHandler *handler) +{ + FIXME("%p, %p, %#x, %p, %p: stub\n", iface, elem, scope, cache_req, handler); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_RemoveNotificationEventHandler(IUIAutomation6 *iface, IUIAutomationElement *elem, + IUIAutomationNotificationEventHandler *handler) +{ + FIXME("%p, %p, %p: stub\n", iface, elem, handler); + return E_NOTIMPL; +} + +/* IUIAutomation6 methods */ +static HRESULT WINAPI uia_iface_CreateEventHandlerGroup(IUIAutomation6 *iface, + IUIAutomationEventHandlerGroup **out_handler_group) +{ + FIXME("%p, %p: stub\n", iface, out_handler_group); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_AddEventHandlerGroup(IUIAutomation6 *iface, IUIAutomationElement *elem, + IUIAutomationEventHandlerGroup *handler_group) +{ + FIXME("%p, %p, %p: stub\n", iface, elem, handler_group); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_RemoveEventHandlerGroup(IUIAutomation6 *iface, IUIAutomationElement *elem, + IUIAutomationEventHandlerGroup *handler_group) +{ + FIXME("%p, %p, %p: stub\n", iface, elem, handler_group); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_get_ConnectionRecoveryBehavior(IUIAutomation6 *iface, + enum ConnectionRecoveryBehaviorOptions *out_conn_recovery_opts) +{ + FIXME("%p, %p: stub\n", iface, out_conn_recovery_opts); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_put_ConnectionRecoveryBehavior(IUIAutomation6 *iface, + enum ConnectionRecoveryBehaviorOptions conn_recovery_opts) +{ + FIXME("%p, %#x: stub\n", iface, conn_recovery_opts); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_get_CoalesceEvents(IUIAutomation6 *iface, + enum CoalesceEventsOptions *out_coalesce_events_opts) +{ + FIXME("%p, %p: stub\n", iface, out_coalesce_events_opts); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_put_CoalesceEvents(IUIAutomation6 *iface, + enum CoalesceEventsOptions coalesce_events_opts) +{ + FIXME("%p, %#x: stub\n", iface, coalesce_events_opts); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_AddActiveTextPositionChangedEventHandler(IUIAutomation6 *iface, + IUIAutomationElement *elem, enum TreeScope scope, IUIAutomationCacheRequest *cache_req, + IUIAutomationActiveTextPositionChangedEventHandler *handler) +{ + FIXME("%p, %p, %#x, %p, %p: stub\n", iface, elem, scope, cache_req, handler); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_iface_RemoveActiveTextPositionChangedEventHandler(IUIAutomation6 *iface, + IUIAutomationElement *elem, IUIAutomationActiveTextPositionChangedEventHandler *handler) +{ + FIXME("%p, %p, %p\n", iface, elem, handler); + return E_NOTIMPL; +} + +static const IUIAutomation6Vtbl uia_iface_vtbl = { + uia_iface_QueryInterface, + uia_iface_AddRef, + uia_iface_Release, + /* IUIAutomation methods */ + uia_iface_CompareElements, + uia_iface_CompareRuntimeIds, + uia_iface_GetRootElement, + uia_iface_ElementFromHandle, + uia_iface_ElementFromPoint, + uia_iface_GetFocusedElement, + uia_iface_GetRootElementBuildCache, + uia_iface_ElementFromHandleBuildCache, + uia_iface_ElementFromPointBuildCache, + uia_iface_GetFocusedElementBuildCache, + uia_iface_CreateTreeWalker, + uia_iface_get_ControlViewWalker, + uia_iface_get_ContentViewWalker, + uia_iface_get_RawViewWalker, + uia_iface_get_RawViewCondition, + uia_iface_get_ControlViewCondition, + uia_iface_get_ContentViewCondition, + uia_iface_CreateCacheRequest, + uia_iface_CreateTrueCondition, + uia_iface_CreateFalseCondition, + uia_iface_CreatePropertyCondition, + uia_iface_CreatePropertyConditionEx, + uia_iface_CreateAndCondition, + uia_iface_CreateAndConditionFromArray, + uia_iface_CreateAndConditionFromNativeArray, + uia_iface_CreateOrCondition, + uia_iface_CreateOrConditionFromArray, + uia_iface_CreateOrConditionFromNativeArray, + uia_iface_CreateNotCondition, + uia_iface_AddAutomationEventHandler, + uia_iface_RemoveAutomationEventHandler, + uia_iface_AddPropertyChangedEventHandlerNativeArray, + uia_iface_AddPropertyChangedEventHandler, + uia_iface_RemovePropertyChangedEventHandler, + uia_iface_AddStructureChangedEventHandler, + uia_iface_RemoveStructureChangedEventHandler, + uia_iface_AddFocusChangedEventHandler, + uia_iface_RemoveFocusChangedEventHandler, + uia_iface_RemoveAllEventHandlers, + uia_iface_IntNativeArrayToSafeArray, + uia_iface_IntSafeArrayToNativeArray, + uia_iface_RectToVariant, + uia_iface_VariantToRect, + uia_iface_SafeArrayToRectNativeArray, + uia_iface_CreateProxyFactoryEntry, + uia_iface_get_ProxyFactoryMapping, + uia_iface_GetPropertyProgrammaticName, + uia_iface_GetPatternProgrammaticName, + uia_iface_PollForPotentialSupportedPatterns, + uia_iface_PollForPotentialSupportedProperties, + uia_iface_CheckNotSupported, + uia_iface_get_ReservedNotSupportedValue, + uia_iface_get_ReservedMixedAttributeValue, + uia_iface_ElementFromIAccessible, + uia_iface_ElementFromIAccessibleBuildCache, + /* IUIAutomation2 methods */ + uia_iface_get_AutoSetFocus, + uia_iface_put_AutoSetFocus, + uia_iface_get_ConnectionTimeout, + uia_iface_put_ConnectionTimeout, + uia_iface_get_TransactionTimeout, + uia_iface_put_TransactionTimeout, + /* IUIAutomation3 methods */ + uia_iface_AddTextEditTextChangedEventHandler, + uia_iface_RemoveTextEditTextChangedEventHandler, + /* IUIAutomation4 methods */ + uia_iface_AddChangesEventHandler, + uia_iface_RemoveChangesEventHandler, + /* IUIAutomation5 methods */ + uia_iface_AddNotificationEventHandler, + uia_iface_RemoveNotificationEventHandler, + /* IUIAutomation6 methods */ + uia_iface_CreateEventHandlerGroup, + uia_iface_AddEventHandlerGroup, + uia_iface_RemoveEventHandlerGroup, + uia_iface_get_ConnectionRecoveryBehavior, + uia_iface_put_ConnectionRecoveryBehavior, + uia_iface_get_CoalesceEvents, + uia_iface_put_CoalesceEvents, + uia_iface_AddActiveTextPositionChangedEventHandler, + uia_iface_RemoveActiveTextPositionChangedEventHandler, +}; + +HRESULT create_uia_iface(IUnknown **iface, BOOL is_cui8) +{ + struct uia_iface *uia; + + uia = heap_alloc_zero(sizeof(*uia)); + if (!uia) + return E_OUTOFMEMORY; + + uia->IUIAutomation6_iface.lpVtbl = &uia_iface_vtbl; + uia->is_cui8 = is_cui8; + uia->ref = 1; + + *iface = (IUnknown *)&uia->IUIAutomation6_iface; + return S_OK; +} diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 65d9257bc0e..3522e205628 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -360,3 +360,130 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *reserved) return TRUE; } + +/* UIAutomation ClassFactory */ +struct uia_cf { + IClassFactory IClassFactory_iface; + LONG ref; + + const GUID *clsid; +}; + +static struct uia_cf *impl_from_IClassFactory(IClassFactory *iface) +{ + return CONTAINING_RECORD(iface, struct uia_cf, IClassFactory_iface); +} + +static HRESULT WINAPI uia_cf_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else + return E_NOINTERFACE; + + IClassFactory_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI uia_cf_AddRef(IClassFactory *iface) +{ + struct uia_cf *cf = impl_from_IClassFactory(iface); + ULONG ref = InterlockedIncrement(&cf->ref); + + TRACE("%p, refcount %ld\n", cf, ref); + + return ref; +} + +static ULONG WINAPI uia_cf_Release(IClassFactory *iface) +{ + struct uia_cf *cf = impl_from_IClassFactory(iface); + ULONG ref = InterlockedDecrement(&cf->ref); + + TRACE("%p, refcount %ld\n", cf, ref); + + if (!ref) + heap_free(cf); + + return ref; +} + +static HRESULT WINAPI uia_cf_CreateInstance(IClassFactory *iface, IUnknown *pouter, REFIID riid, void **ppv) +{ + struct uia_cf *cf = impl_from_IClassFactory(iface); + IUnknown *obj = NULL; + HRESULT hr; + + TRACE("%p, %p, %s, %p\n", iface, pouter, debugstr_guid(riid), ppv); + + *ppv = NULL; + if (pouter) + return CLASS_E_NOAGGREGATION; + + if (IsEqualGUID(cf->clsid, &CLSID_CUIAutomation) && (IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_IUIAutomation))) + hr = create_uia_iface(&obj, FALSE); + else if (IsEqualGUID(cf->clsid, &CLSID_CUIAutomation8) && (IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_IUIAutomation) || IsEqualGUID(riid, &IID_IUIAutomation2) || + IsEqualGUID(riid, &IID_IUIAutomation3) || IsEqualGUID(riid, &IID_IUIAutomation4) || + IsEqualGUID(riid, &IID_IUIAutomation5) || IsEqualGUID(riid, &IID_IUIAutomation6))) + hr = create_uia_iface(&obj, TRUE); + else + return E_NOINTERFACE; + + if (SUCCEEDED(hr) && obj) + { + hr = IUnknown_QueryInterface(obj, riid, ppv); + IUnknown_Release(obj); + } + + return hr; +} + +static HRESULT WINAPI uia_cf_LockServer(IClassFactory *iface, BOOL do_lock) +{ + FIXME("%p, %d: stub\n", iface, do_lock); + return S_OK; +} + +static const IClassFactoryVtbl uia_cf_Vtbl = +{ + uia_cf_QueryInterface, + uia_cf_AddRef, + uia_cf_Release, + uia_cf_CreateInstance, + uia_cf_LockServer +}; + +static inline HRESULT create_uia_cf(REFCLSID clsid, REFIID riid, void **ppv) +{ + struct uia_cf *cf = heap_alloc_zero(sizeof(*cf)); + HRESULT hr; + + *ppv = NULL; + if (!cf) + return E_OUTOFMEMORY; + + cf->IClassFactory_iface.lpVtbl = &uia_cf_Vtbl; + cf->clsid = clsid; + cf->ref = 1; + + hr = IClassFactory_QueryInterface(&cf->IClassFactory_iface, riid, ppv); + IClassFactory_Release(&cf->IClassFactory_iface); + + return hr; +} + +/*********************************************************************** + * DllGetClassObject (uiautomationcore.@) + */ +HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **ppv) +{ + TRACE("(%s, %s, %p)\n", debugstr_guid(clsid), debugstr_guid(riid), ppv); + + if (IsEqualGUID(clsid, &CLSID_CUIAutomation) || IsEqualGUID(clsid, &CLSID_CUIAutomation8)) + return create_uia_cf(clsid, riid, ppv); + + return CLASS_E_CLASSNOTAVAILABLE; +} diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 71bc41dc3e8..8a1ddeb5453 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -128,6 +128,9 @@ int get_node_provider_type_at_idx(struct uia_node *node, int idx) DECLSPEC_HIDDE HRESULT create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE *out_node, BOOL get_hwnd_providers) DECLSPEC_HIDDEN; +/* uia_com_client.c */ +HRESULT create_uia_iface(IUnknown **iface, BOOL is_cui8) DECLSPEC_HIDDEN; + /* uia_ids.c */ const struct uia_prop_info *uia_prop_info_from_id(PROPERTYID prop_id) DECLSPEC_HIDDEN; diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec index 390fe2f07f5..666b10e3317 100644 --- a/dlls/uiautomationcore/uiautomationcore.spec +++ b/dlls/uiautomationcore/uiautomationcore.spec @@ -1,5 +1,5 @@ @ stdcall -private DllCanUnloadNow() -@ stub DllGetClassObject +@ stdcall -private DllGetClassObject(ptr ptr ptr) @ stdcall -private DllRegisterServer() @ stdcall -private DllUnregisterServer() @ stub DockPattern_SetDockPosition From d6787580c8adf7f972c43cbcfd657a5758c3662f Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 28 Dec 2022 10:44:29 -0500 Subject: [PATCH 0764/2777] uiautomationcore: Implement IUIAutomation::ElementFromHandle. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_com_client.c | 930 ++++++++++++++++++++++++- 1 file changed, 928 insertions(+), 2 deletions(-) diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 6b25e851c04..3906d7170e4 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -23,6 +23,924 @@ WINE_DEFAULT_DEBUG_CHANNEL(uiautomation); +/* + * IUIAutomationElement interface. + */ +struct uia_element { + IUIAutomationElement9 IUIAutomationElement9_iface; + LONG ref; + + HUIANODE node; +}; + +static inline struct uia_element *impl_from_IUIAutomationElement9(IUIAutomationElement9 *iface) +{ + return CONTAINING_RECORD(iface, struct uia_element, IUIAutomationElement9_iface); +} + +static HRESULT WINAPI uia_element_QueryInterface(IUIAutomationElement9 *iface, REFIID riid, void **ppv) +{ + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IUIAutomationElement) || + IsEqualIID(riid, &IID_IUIAutomationElement2) || IsEqualIID(riid, &IID_IUIAutomationElement3) || + IsEqualIID(riid, &IID_IUIAutomationElement4) || IsEqualIID(riid, &IID_IUIAutomationElement5) || + IsEqualIID(riid, &IID_IUIAutomationElement6) || IsEqualIID(riid, &IID_IUIAutomationElement7) || + IsEqualIID(riid, &IID_IUIAutomationElement8) || IsEqualIID(riid, &IID_IUIAutomationElement9)) + *ppv = iface; + else + return E_NOINTERFACE; + + IUIAutomationElement9_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI uia_element_AddRef(IUIAutomationElement9 *iface) +{ + struct uia_element *element = impl_from_IUIAutomationElement9(iface); + ULONG ref = InterlockedIncrement(&element->ref); + + TRACE("%p, refcount %ld\n", element, ref); + return ref; +} + +static ULONG WINAPI uia_element_Release(IUIAutomationElement9 *iface) +{ + struct uia_element *element = impl_from_IUIAutomationElement9(iface); + ULONG ref = InterlockedDecrement(&element->ref); + + TRACE("%p, refcount %ld\n", element, ref); + if (!ref) + { + UiaNodeRelease(element->node); + heap_free(element); + } + + return ref; +} + +static HRESULT WINAPI uia_element_SetFocus(IUIAutomationElement9 *iface) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_GetRuntimeId(IUIAutomationElement9 *iface, SAFEARRAY **runtime_id) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_FindFirst(IUIAutomationElement9 *iface, enum TreeScope scope, + IUIAutomationCondition *condition, IUIAutomationElement **found) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_FindAll(IUIAutomationElement9 *iface, enum TreeScope scope, + IUIAutomationCondition *condition, IUIAutomationElementArray **found) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_FindFirstBuildCache(IUIAutomationElement9 *iface, enum TreeScope scope, + IUIAutomationCondition *condition, IUIAutomationCacheRequest *cache_req, IUIAutomationElement **found) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_FindAllBuildCache(IUIAutomationElement9 *iface, enum TreeScope scope, + IUIAutomationCondition *condition, IUIAutomationCacheRequest *cache_req, IUIAutomationElementArray **found) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_BuildUpdatedCache(IUIAutomationElement9 *iface, IUIAutomationCacheRequest *cache_req, + IUIAutomationElement **updated_elem) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_GetCurrentPropertyValue(IUIAutomationElement9 *iface, PROPERTYID prop_id, + VARIANT *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_GetCurrentPropertyValueEx(IUIAutomationElement9 *iface, PROPERTYID prop_id, + BOOL ignore_default, VARIANT *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_GetCachedPropertyValue(IUIAutomationElement9 *iface, PROPERTYID prop_id, + VARIANT *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_GetCachedPropertyValueEx(IUIAutomationElement9 *iface, PROPERTYID prop_id, + BOOL ignore_default, VARIANT *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_GetCurrentPatternAs(IUIAutomationElement9 *iface, PATTERNID pattern_id, + REFIID riid, void **out_pattern) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_GetCachedPatternAs(IUIAutomationElement9 *iface, PATTERNID pattern_id, + REFIID riid, void **out_pattern) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_GetCurrentPattern(IUIAutomationElement9 *iface, PATTERNID pattern_id, + IUnknown **out_pattern) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_GetCachedPattern(IUIAutomationElement9 *iface, PATTERNID pattern_id, + IUnknown **patternObject) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_GetCachedParent(IUIAutomationElement9 *iface, IUIAutomationElement **parent) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_GetCachedChildren(IUIAutomationElement9 *iface, + IUIAutomationElementArray **children) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentProcessId(IUIAutomationElement9 *iface, int *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentControlType(IUIAutomationElement9 *iface, CONTROLTYPEID *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentLocalizedControlType(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentName(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentAcceleratorKey(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentAccessKey(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentHasKeyboardFocus(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentIsKeyboardFocusable(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentIsEnabled(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentAutomationId(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentClassName(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentHelpText(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentCulture(IUIAutomationElement9 *iface, int *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentIsControlElement(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentIsContentElement(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentIsPassword(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentNativeWindowHandle(IUIAutomationElement9 *iface, UIA_HWND *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentItemType(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentIsOffscreen(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentOrientation(IUIAutomationElement9 *iface, enum OrientationType *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentFrameworkId(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentIsRequiredForForm(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentItemStatus(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentBoundingRectangle(IUIAutomationElement9 *iface, RECT *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentLabeledBy(IUIAutomationElement9 *iface, IUIAutomationElement **ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentAriaRole(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentAriaProperties(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentIsDataValidForForm(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentControllerFor(IUIAutomationElement9 *iface, + IUIAutomationElementArray **ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentDescribedBy(IUIAutomationElement9 *iface, + IUIAutomationElementArray **ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentFlowsTo(IUIAutomationElement9 *iface, IUIAutomationElementArray **ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentProviderDescription(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedProcessId(IUIAutomationElement9 *iface, int *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedControlType(IUIAutomationElement9 *iface, CONTROLTYPEID *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedLocalizedControlType(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedName(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedAcceleratorKey(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedAccessKey(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedHasKeyboardFocus(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedIsKeyboardFocusable(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedIsEnabled(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedAutomationId(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedClassName(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedHelpText(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedCulture(IUIAutomationElement9 *iface, int *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedIsControlElement(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedIsContentElement(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedIsPassword(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedNativeWindowHandle(IUIAutomationElement9 *iface, UIA_HWND *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedItemType(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedIsOffscreen(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedOrientation(IUIAutomationElement9 *iface, + enum OrientationType *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedFrameworkId(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedIsRequiredForForm(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedItemStatus(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedBoundingRectangle(IUIAutomationElement9 *iface, RECT *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedLabeledBy(IUIAutomationElement9 *iface, IUIAutomationElement **ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedAriaRole(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedAriaProperties(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedIsDataValidForForm(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedControllerFor(IUIAutomationElement9 *iface, + IUIAutomationElementArray **ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedDescribedBy(IUIAutomationElement9 *iface, + IUIAutomationElementArray **ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedFlowsTo(IUIAutomationElement9 *iface, IUIAutomationElementArray **ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedProviderDescription(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_GetClickablePoint(IUIAutomationElement9 *iface, POINT *clickable, BOOL *got_clickable) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentOptimizeForVisualContent(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedOptimizeForVisualContent(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentLiveSetting(IUIAutomationElement9 *iface, enum LiveSetting *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedLiveSetting(IUIAutomationElement9 *iface, enum LiveSetting *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentFlowsFrom(IUIAutomationElement9 *iface, + IUIAutomationElementArray **ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedFlowsFrom(IUIAutomationElement9 *iface, IUIAutomationElementArray **ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_ShowContextMenu(IUIAutomationElement9 *iface) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentIsPeripheral(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedIsPeripheral(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentPositionInSet(IUIAutomationElement9 *iface, int *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentSizeOfSet(IUIAutomationElement9 *iface, int *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentLevel(IUIAutomationElement9 *iface, int *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentAnnotationTypes(IUIAutomationElement9 *iface, SAFEARRAY **ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentAnnotationObjects(IUIAutomationElement9 *iface, + IUIAutomationElementArray **ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedPositionInSet(IUIAutomationElement9 *iface, int *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedSizeOfSet(IUIAutomationElement9 *iface, int *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedLevel(IUIAutomationElement9 *iface, int *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedAnnotationTypes(IUIAutomationElement9 *iface, SAFEARRAY **ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedAnnotationObjects(IUIAutomationElement9 *iface, + IUIAutomationElementArray **ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentLandmarkType(IUIAutomationElement9 *iface, LANDMARKTYPEID *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentLocalizedLandmarkType(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedLandmarkType(IUIAutomationElement9 *iface, LANDMARKTYPEID *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedLocalizedLandmarkType(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentFullDescription(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedFullDescription(IUIAutomationElement9 *iface, BSTR *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_FindFirstWithOptions(IUIAutomationElement9 *iface, enum TreeScope scope, + IUIAutomationCondition *condition, enum TreeTraversalOptions traversal_opts, IUIAutomationElement *root, + IUIAutomationElement **found) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_FindAllWithOptions(IUIAutomationElement9 *iface, enum TreeScope scope, + IUIAutomationCondition *condition, enum TreeTraversalOptions traversal_opts, IUIAutomationElement *root, + IUIAutomationElementArray **found) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_FindFirstWithOptionsBuildCache(IUIAutomationElement9 *iface, enum TreeScope scope, + IUIAutomationCondition *condition, IUIAutomationCacheRequest *cache_req, + enum TreeTraversalOptions traversal_opts, IUIAutomationElement *root, IUIAutomationElement **found) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_FindAllWithOptionsBuildCache(IUIAutomationElement9 *iface, enum TreeScope scope, + IUIAutomationCondition *condition, IUIAutomationCacheRequest *cache_req, + enum TreeTraversalOptions traversal_opts, IUIAutomationElement *root, IUIAutomationElementArray **found) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_GetCurrentMetadataValue(IUIAutomationElement9 *iface, int target_id, + METADATAID metadata_id, VARIANT *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentHeadingLevel(IUIAutomationElement9 *iface, HEADINGLEVELID *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedHeadingLevel(IUIAutomationElement9 *iface, HEADINGLEVELID *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CurrentIsDialog(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_element_get_CachedIsDialog(IUIAutomationElement9 *iface, BOOL *ret_val) +{ + FIXME("%p: stub\n", iface); + return E_NOTIMPL; +} + +static const IUIAutomationElement9Vtbl uia_element_vtbl = { + uia_element_QueryInterface, + uia_element_AddRef, + uia_element_Release, + uia_element_SetFocus, + uia_element_GetRuntimeId, + uia_element_FindFirst, + uia_element_FindAll, + uia_element_FindFirstBuildCache, + uia_element_FindAllBuildCache, + uia_element_BuildUpdatedCache, + uia_element_GetCurrentPropertyValue, + uia_element_GetCurrentPropertyValueEx, + uia_element_GetCachedPropertyValue, + uia_element_GetCachedPropertyValueEx, + uia_element_GetCurrentPatternAs, + uia_element_GetCachedPatternAs, + uia_element_GetCurrentPattern, + uia_element_GetCachedPattern, + uia_element_GetCachedParent, + uia_element_GetCachedChildren, + uia_element_get_CurrentProcessId, + uia_element_get_CurrentControlType, + uia_element_get_CurrentLocalizedControlType, + uia_element_get_CurrentName, + uia_element_get_CurrentAcceleratorKey, + uia_element_get_CurrentAccessKey, + uia_element_get_CurrentHasKeyboardFocus, + uia_element_get_CurrentIsKeyboardFocusable, + uia_element_get_CurrentIsEnabled, + uia_element_get_CurrentAutomationId, + uia_element_get_CurrentClassName, + uia_element_get_CurrentHelpText, + uia_element_get_CurrentCulture, + uia_element_get_CurrentIsControlElement, + uia_element_get_CurrentIsContentElement, + uia_element_get_CurrentIsPassword, + uia_element_get_CurrentNativeWindowHandle, + uia_element_get_CurrentItemType, + uia_element_get_CurrentIsOffscreen, + uia_element_get_CurrentOrientation, + uia_element_get_CurrentFrameworkId, + uia_element_get_CurrentIsRequiredForForm, + uia_element_get_CurrentItemStatus, + uia_element_get_CurrentBoundingRectangle, + uia_element_get_CurrentLabeledBy, + uia_element_get_CurrentAriaRole, + uia_element_get_CurrentAriaProperties, + uia_element_get_CurrentIsDataValidForForm, + uia_element_get_CurrentControllerFor, + uia_element_get_CurrentDescribedBy, + uia_element_get_CurrentFlowsTo, + uia_element_get_CurrentProviderDescription, + uia_element_get_CachedProcessId, + uia_element_get_CachedControlType, + uia_element_get_CachedLocalizedControlType, + uia_element_get_CachedName, + uia_element_get_CachedAcceleratorKey, + uia_element_get_CachedAccessKey, + uia_element_get_CachedHasKeyboardFocus, + uia_element_get_CachedIsKeyboardFocusable, + uia_element_get_CachedIsEnabled, + uia_element_get_CachedAutomationId, + uia_element_get_CachedClassName, + uia_element_get_CachedHelpText, + uia_element_get_CachedCulture, + uia_element_get_CachedIsControlElement, + uia_element_get_CachedIsContentElement, + uia_element_get_CachedIsPassword, + uia_element_get_CachedNativeWindowHandle, + uia_element_get_CachedItemType, + uia_element_get_CachedIsOffscreen, + uia_element_get_CachedOrientation, + uia_element_get_CachedFrameworkId, + uia_element_get_CachedIsRequiredForForm, + uia_element_get_CachedItemStatus, + uia_element_get_CachedBoundingRectangle, + uia_element_get_CachedLabeledBy, + uia_element_get_CachedAriaRole, + uia_element_get_CachedAriaProperties, + uia_element_get_CachedIsDataValidForForm, + uia_element_get_CachedControllerFor, + uia_element_get_CachedDescribedBy, + uia_element_get_CachedFlowsTo, + uia_element_get_CachedProviderDescription, + uia_element_GetClickablePoint, + uia_element_get_CurrentOptimizeForVisualContent, + uia_element_get_CachedOptimizeForVisualContent, + uia_element_get_CurrentLiveSetting, + uia_element_get_CachedLiveSetting, + uia_element_get_CurrentFlowsFrom, + uia_element_get_CachedFlowsFrom, + uia_element_ShowContextMenu, + uia_element_get_CurrentIsPeripheral, + uia_element_get_CachedIsPeripheral, + uia_element_get_CurrentPositionInSet, + uia_element_get_CurrentSizeOfSet, + uia_element_get_CurrentLevel, + uia_element_get_CurrentAnnotationTypes, + uia_element_get_CurrentAnnotationObjects, + uia_element_get_CachedPositionInSet, + uia_element_get_CachedSizeOfSet, + uia_element_get_CachedLevel, + uia_element_get_CachedAnnotationTypes, + uia_element_get_CachedAnnotationObjects, + uia_element_get_CurrentLandmarkType, + uia_element_get_CurrentLocalizedLandmarkType, + uia_element_get_CachedLandmarkType, + uia_element_get_CachedLocalizedLandmarkType, + uia_element_get_CurrentFullDescription, + uia_element_get_CachedFullDescription, + uia_element_FindFirstWithOptions, + uia_element_FindAllWithOptions, + uia_element_FindFirstWithOptionsBuildCache, + uia_element_FindAllWithOptionsBuildCache, + uia_element_GetCurrentMetadataValue, + uia_element_get_CurrentHeadingLevel, + uia_element_get_CachedHeadingLevel, + uia_element_get_CurrentIsDialog, + uia_element_get_CachedIsDialog, +}; + +static HRESULT create_uia_element(IUIAutomationElement **iface, HUIANODE node) +{ + struct uia_element *element = heap_alloc_zero(sizeof(*element)); + + *iface = NULL; + if (!element) + return E_OUTOFMEMORY; + + element->IUIAutomationElement9_iface.lpVtbl = &uia_element_vtbl; + element->ref = 1; + element->node = node; + + *iface = (IUIAutomationElement *)&element->IUIAutomationElement9_iface; + return S_OK; +} /* * IUIAutomation interface. */ @@ -101,8 +1019,16 @@ static HRESULT WINAPI uia_iface_GetRootElement(IUIAutomation6 *iface, IUIAutomat static HRESULT WINAPI uia_iface_ElementFromHandle(IUIAutomation6 *iface, UIA_HWND hwnd, IUIAutomationElement **out_elem) { - FIXME("%p, %p, %p: stub\n", iface, hwnd, out_elem); - return E_NOTIMPL; + HUIANODE node; + HRESULT hr; + + TRACE("%p, %p, %p\n", iface, hwnd, out_elem); + + hr = UiaNodeFromHandle((HWND)hwnd, &node); + if (FAILED(hr) || !node) + return hr; + + return create_uia_element(out_elem, node); } static HRESULT WINAPI uia_iface_ElementFromPoint(IUIAutomation6 *iface, POINT pt, IUIAutomationElement **out_elem) From dd719886488c2760527526195574f2cdec507461 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 28 Dec 2022 10:46:48 -0500 Subject: [PATCH 0765/2777] uiautomationcore: Implement IUIAutomationElement::get_CurrentControlType. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_com_client.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 3906d7170e4..586af5fc3c3 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -201,8 +201,19 @@ static HRESULT WINAPI uia_element_get_CurrentProcessId(IUIAutomationElement9 *if static HRESULT WINAPI uia_element_get_CurrentControlType(IUIAutomationElement9 *iface, CONTROLTYPEID *ret_val) { - FIXME("%p: stub\n", iface); - return E_NOTIMPL; + struct uia_element *element = impl_from_IUIAutomationElement9(iface); + HRESULT hr; + VARIANT v; + + TRACE("%p, %p\n", element, ret_val); + + *ret_val = 0; + VariantInit(&v); + hr = UiaGetPropertyValue(element->node, UIA_ControlTypePropertyId, &v); + if (SUCCEEDED(hr) && V_VT(&v) == VT_I4) + *ret_val = V_I4(&v); + + return S_OK; } static HRESULT WINAPI uia_element_get_CurrentLocalizedControlType(IUIAutomationElement9 *iface, BSTR *ret_val) From 557ac2d56a5bd1404c2ca460efe954b0a5640b54 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 28 Dec 2022 10:48:58 -0500 Subject: [PATCH 0766/2777] uiautomationcore: Implement IUIAutomationElement::get_CurrentName. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_com_client.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 586af5fc3c3..75dab9588a4 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -224,8 +224,19 @@ static HRESULT WINAPI uia_element_get_CurrentLocalizedControlType(IUIAutomationE static HRESULT WINAPI uia_element_get_CurrentName(IUIAutomationElement9 *iface, BSTR *ret_val) { - FIXME("%p: stub\n", iface); - return E_NOTIMPL; + struct uia_element *element = impl_from_IUIAutomationElement9(iface); + HRESULT hr; + VARIANT v; + + TRACE("%p, %p\n", element, ret_val); + + *ret_val = NULL; + VariantInit(&v); + hr = UiaGetPropertyValue(element->node, UIA_NamePropertyId, &v); + if (SUCCEEDED(hr) && V_VT(&v) == VT_BSTR) + *ret_val = V_BSTR(&v); + + return S_OK; } static HRESULT WINAPI uia_element_get_CurrentAcceleratorKey(IUIAutomationElement9 *iface, BSTR *ret_val) From 12b09148974a16150613f737f999ff12ff5d5b17 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 28 Dec 2022 10:50:32 -0500 Subject: [PATCH 0767/2777] uiautomationcore: Implement IUIAutomationElement::get_CurrentBoundingRectangle. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_com_client.c | 27 ++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 75dab9588a4..7288ae69aef 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -355,8 +355,31 @@ static HRESULT WINAPI uia_element_get_CurrentItemStatus(IUIAutomationElement9 *i static HRESULT WINAPI uia_element_get_CurrentBoundingRectangle(IUIAutomationElement9 *iface, RECT *ret_val) { - FIXME("%p: stub\n", iface); - return E_NOTIMPL; + struct uia_element *element = impl_from_IUIAutomationElement9(iface); + HRESULT hr; + VARIANT v; + + TRACE("%p, %p\n", element, ret_val); + + memset(ret_val, 0, sizeof(*ret_val)); + VariantInit(&v); + hr = UiaGetPropertyValue(element->node, UIA_BoundingRectanglePropertyId, &v); + if (SUCCEEDED(hr) && V_VT(&v) == (VT_R8 | VT_ARRAY)) + { + double vals[4]; + LONG idx; + + for (idx = 0; idx < ARRAY_SIZE(vals); idx++) + SafeArrayGetElement(V_ARRAY(&v), &idx, &vals[idx]); + + ret_val->left = vals[0]; + ret_val->top = vals[1]; + ret_val->right = ret_val->left + vals[2]; + ret_val->bottom = ret_val->top + vals[3]; + VariantClear(&v); + } + + return S_OK; } static HRESULT WINAPI uia_element_get_CurrentLabeledBy(IUIAutomationElement9 *iface, IUIAutomationElement **ret_val) From fd2e0fdbd7352ffab3343de5e58841c318a6d8c4 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 28 Dec 2022 10:54:28 -0500 Subject: [PATCH 0768/2777] uiautomationcore: Implement IUIAutomationElement::GetCurrentPropertyValue{Ex}. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_com_client.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 7288ae69aef..1eb19bd73db 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -127,15 +127,28 @@ static HRESULT WINAPI uia_element_BuildUpdatedCache(IUIAutomationElement9 *iface static HRESULT WINAPI uia_element_GetCurrentPropertyValue(IUIAutomationElement9 *iface, PROPERTYID prop_id, VARIANT *ret_val) { - FIXME("%p: stub\n", iface); - return E_NOTIMPL; + TRACE("%p, %d, %p\n", iface, prop_id, ret_val); + + return IUIAutomationElement9_GetCurrentPropertyValueEx(iface, prop_id, FALSE, ret_val); } static HRESULT WINAPI uia_element_GetCurrentPropertyValueEx(IUIAutomationElement9 *iface, PROPERTYID prop_id, BOOL ignore_default, VARIANT *ret_val) { - FIXME("%p: stub\n", iface); - return E_NOTIMPL; + struct uia_element *element = impl_from_IUIAutomationElement9(iface); + HRESULT hr; + VARIANT v; + + TRACE("%p, %d, %d, %p\n", iface, prop_id, ignore_default, ret_val); + + if (!ignore_default) + FIXME("Default property values currently unimplemented\n"); + + VariantInit(&v); + hr = UiaGetPropertyValue(element->node, prop_id, &v); + *ret_val = v; + + return hr; } static HRESULT WINAPI uia_element_GetCachedPropertyValue(IUIAutomationElement9 *iface, PROPERTYID prop_id, From f3289bb1ab7639d23deb391bd41849f881fd40d8 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Thu, 29 Dec 2022 11:13:06 -0500 Subject: [PATCH 0769/2777] uiautomationcore: Add support for marking an MSAA proxy as being a clientside provider. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_client.c | 2 +- dlls/uiautomationcore/uia_private.h | 2 +- dlls/uiautomationcore/uia_provider.c | 22 ++++++++++++++++------ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 9274c01ede2..d0333c385e6 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -2463,7 +2463,7 @@ static SAFEARRAY WINAPI *default_uia_provider_callback(HWND hwnd, enum ProviderT if (FAILED(hr) || !acc) break; - hr = create_msaa_provider(acc, CHILDID_SELF, hwnd, TRUE, &elprov); + hr = create_msaa_provider(acc, CHILDID_SELF, hwnd, TRUE, TRUE, &elprov); if (FAILED(hr)) WARN("Failed to create MSAA proxy provider with hr %#lx\n", hr); diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 8a1ddeb5453..5fb42ef86f4 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -138,6 +138,6 @@ const struct uia_prop_info *uia_prop_info_from_id(PROPERTYID prop_id) DECLSPEC_H void uia_stop_provider_thread(void) DECLSPEC_HIDDEN; void uia_provider_thread_remove_node(HUIANODE node) DECLSPEC_HIDDEN; LRESULT uia_lresult_from_node(HUIANODE huianode) DECLSPEC_HIDDEN; -HRESULT create_msaa_provider(IAccessible *acc, long child_id, HWND hwnd, BOOL known_root_acc, +HRESULT create_msaa_provider(IAccessible *acc, long child_id, HWND hwnd, BOOL known_root_acc, BOOL clientside_prov, IRawElementProviderSimple **elprov) DECLSPEC_HIDDEN; HRESULT create_base_hwnd_provider(HWND hwnd, IRawElementProviderSimple **elprov) DECLSPEC_HIDDEN; diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index a62b241e76f..66665d92d33 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -510,6 +510,7 @@ struct msaa_provider { BOOL root_acc_check_ran; BOOL is_root_acc; + BOOL clientside_prov; IAccessible *parent; INT child_pos; @@ -594,8 +595,16 @@ ULONG WINAPI msaa_provider_Release(IRawElementProviderSimple *iface) HRESULT WINAPI msaa_provider_get_ProviderOptions(IRawElementProviderSimple *iface, enum ProviderOptions *ret_val) { + struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface); + TRACE("%p, %p\n", iface, ret_val); - *ret_val = ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading; + + *ret_val = ProviderOptions_UseComThreading; + if (msaa_prov->clientside_prov) + *ret_val |= ProviderOptions_ClientSideProvider; + else + *ret_val |= ProviderOptions_ServerSideProvider; + return S_OK; } @@ -769,7 +778,7 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface, else acc = msaa_prov->acc; - hr = create_msaa_provider(acc, CHILDID_SELF, NULL, FALSE, &elprov); + hr = create_msaa_provider(acc, CHILDID_SELF, NULL, FALSE, msaa_prov->clientside_prov, &elprov); if (SUCCEEDED(hr)) { struct msaa_provider *prov = impl_from_msaa_provider(elprov); @@ -800,7 +809,7 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface, if (FAILED(hr) || !acc) break; - hr = create_msaa_provider(acc, child_id, NULL, FALSE, &elprov); + hr = create_msaa_provider(acc, child_id, NULL, FALSE, msaa_prov->clientside_prov, &elprov); if (SUCCEEDED(hr)) { struct msaa_provider *prov = impl_from_msaa_provider(elprov); @@ -850,7 +859,7 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface, if (FAILED(hr) || !acc) break; - hr = create_msaa_provider(acc, child_id, NULL, FALSE, &elprov); + hr = create_msaa_provider(acc, child_id, NULL, FALSE, msaa_prov->clientside_prov, &elprov); if (SUCCEEDED(hr)) { struct msaa_provider *prov = impl_from_msaa_provider(elprov); @@ -1096,7 +1105,7 @@ static const ILegacyIAccessibleProviderVtbl msaa_acc_provider_vtbl = { msaa_acc_provider_get_DefaultAction, }; -HRESULT create_msaa_provider(IAccessible *acc, long child_id, HWND hwnd, BOOL known_root_acc, +HRESULT create_msaa_provider(IAccessible *acc, long child_id, HWND hwnd, BOOL known_root_acc, BOOL clientside_prov, IRawElementProviderSimple **elprov) { struct msaa_provider *msaa_prov = heap_alloc_zero(sizeof(*msaa_prov)); @@ -1112,6 +1121,7 @@ HRESULT create_msaa_provider(IAccessible *acc, long child_id, HWND hwnd, BOOL kn msaa_prov->acc = acc; IAccessible_AddRef(acc); msaa_prov->ia2 = msaa_acc_get_ia2(acc); + msaa_prov->clientside_prov = clientside_prov; if (!hwnd) { @@ -1181,7 +1191,7 @@ HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD if (!hwnd) return E_FAIL; - return create_msaa_provider(acc, child_id, hwnd, FALSE, elprov); + return create_msaa_provider(acc, child_id, hwnd, FALSE, FALSE, elprov); } /* From b3f41f2ff4bfa1d385b098a4ead208f5506a75ac Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Fri, 30 Dec 2022 14:30:14 -0500 Subject: [PATCH 0770/2777] uiautomationcore: Add a timeout for sending WM_GETOBJECT messages. Prevents an indefinite hang on some CEF HWNDs. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_client.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index d0333c385e6..83c19fcc2e5 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -2102,22 +2102,25 @@ static HRESULT uia_node_from_lresult(LRESULT lr, HUIANODE *huianode) */ static HRESULT uia_get_provider_from_hwnd(struct uia_node *node) { - struct uia_get_node_prov_args args; + struct uia_get_node_prov_args args = { 0 }; + BOOL succeeded; if (!uia_start_client_thread()) return E_FAIL; SetLastError(NOERROR); - args.lr = SendMessageW(node->hwnd, WM_GETOBJECT, 0, UiaRootObjectId); - if (GetLastError() == ERROR_INVALID_WINDOW_HANDLE) + succeeded = SendMessageTimeoutW(node->hwnd, WM_GETOBJECT, 0, UiaRootObjectId, 0, 1000, (PDWORD_PTR)&args.lr); + if (!succeeded || !args.lr) { uia_stop_client_thread(); - return UIA_E_ELEMENTNOTAVAILABLE; - } + if (!succeeded) + { + if (GetLastError() == ERROR_TIMEOUT) + return UIA_E_TIMEOUT; + else + return UIA_E_ELEMENTNOTAVAILABLE; + } - if (!args.lr) - { - uia_stop_client_thread(); return S_FALSE; } From 045731a5e0cc7f5933d5b6824fa64a1547dd5442 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Thu, 4 Nov 2021 11:00:56 -0400 Subject: [PATCH 0771/2777] HACK: user32: Handle OBJID_QUERYCLASSNAMEIDX for user32 edit control. Due to Wine's implementation of RealGetWindowClass being broken for subclassed controls, we'll need to respond to OBJID_QUERYCLASSNAMEIDX to know that we have an edit control. Signed-off-by: Connor McAdams CW-Bug-Id: #18351 --- dlls/user32/edit.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/user32/edit.c b/dlls/user32/edit.c index 74411d385e2..2e651e455dd 100644 --- a/dlls/user32/edit.c +++ b/dlls/user32/edit.c @@ -5237,6 +5237,12 @@ LRESULT EditWndProc_common( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, B } break; + case WM_GETOBJECT: + if (lParam == (DWORD)OBJID_QUERYCLASSNAMEIDX) + result = 0x10004; + + break; + default: result = DefWindowProcT(hwnd, msg, wParam, lParam, unicode); break; From 0ca1ca4da548a30700961a479de1965ad6497f18 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 23 Aug 2021 10:24:29 -0400 Subject: [PATCH 0772/2777] uiautomationcore: Add UiaRaiseStructureChangedEvent stub. Signed-off-by: Connor McAdams CW-Bug-Id: #18351 --- dlls/uiautomationcore/uia_main.c | 10 ++++++++++ dlls/uiautomationcore/uiautomationcore.spec | 2 +- include/uiautomationcoreapi.h | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 3522e205628..874b3440ff1 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -316,6 +316,16 @@ HRESULT WINAPI UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple return S_OK; } +/*********************************************************************** + * UiaRaiseStructureChangedEvent (uiautomationcore.@) + */ +HRESULT WINAPI UiaRaiseStructureChangedEvent(IRawElementProviderSimple *provider, enum StructureChangeType struct_change_type, + int *runtime_id, int runtime_id_len) +{ + FIXME("(%p, %d, %p, %d): stub\n", provider, struct_change_type, runtime_id, runtime_id_len); + return S_OK; +} + HRESULT WINAPI UiaHostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **provider) { struct hwnd_host_provider *host_prov; diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec index 666b10e3317..32f5510021a 100644 --- a/dlls/uiautomationcore/uiautomationcore.spec +++ b/dlls/uiautomationcore/uiautomationcore.spec @@ -89,7 +89,7 @@ @ stdcall UiaRaiseAutomationPropertyChangedEvent(ptr long int128 int128) #@ stub UiaRaiseChangesEvent #@ stub UiaRaiseNotificationEvent -@ stub UiaRaiseStructureChangedEvent +@ stdcall UiaRaiseStructureChangedEvent(ptr long ptr long) #@ stub UiaRaiseTextEditTextChangedEvent @ stdcall UiaRegisterProviderCallback(ptr) @ stdcall UiaRemoveEvent(ptr) diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h index 64a1a80768d..7c8a5bd2839 100644 --- a/include/uiautomationcoreapi.h +++ b/include/uiautomationcoreapi.h @@ -440,6 +440,8 @@ int WINAPI UiaLookupId(enum AutomationIdentifierType type, const GUID *guid); BOOL WINAPI UiaPatternRelease(HUIAPATTERNOBJECT hobj); HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *provider, EVENTID id); HRESULT WINAPI UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple *, PROPERTYID, VARIANT, VARIANT); +HRESULT WINAPI UiaRaiseStructureChangedEvent(IRawElementProviderSimple *provider, enum StructureChangeType struct_change_type, + int *runtime_id, int runtime_id_len); void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *pCallback); LRESULT WINAPI UiaReturnRawElementProvider(HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple *elprov); BOOL WINAPI UiaTextRangeRelease(HUIATEXTRANGE hobj); From 46b3e6b384f369775a31ca85e9cddbdf6e03bcdc Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 11 Oct 2021 20:21:00 -0400 Subject: [PATCH 0773/2777] uiautomationcore: Add UiaRaiseAsyncContentLoadedEvent stub. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_main.c | 11 +++++++++++ dlls/uiautomationcore/uiautomationcore.spec | 2 +- include/uiautomationcoreapi.h | 2 ++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 874b3440ff1..e158e754fac 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -326,6 +326,17 @@ HRESULT WINAPI UiaRaiseStructureChangedEvent(IRawElementProviderSimple *provider return S_OK; } +/*********************************************************************** + * UiaRaiseAsyncContentLoadedEvent (uiautomationcore.@) + */ +HRESULT WINAPI UiaRaiseAsyncContentLoadedEvent(IRawElementProviderSimple *provider, + enum AsyncContentLoadedState async_content_loaded_state, + double percent_complete) +{ + FIXME("(%p, %d, %f): stub\n", provider, async_content_loaded_state, percent_complete); + return S_OK; +} + HRESULT WINAPI UiaHostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **provider) { struct hwnd_host_provider *host_prov; diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec index 32f5510021a..09a53f86114 100644 --- a/dlls/uiautomationcore/uiautomationcore.spec +++ b/dlls/uiautomationcore/uiautomationcore.spec @@ -84,7 +84,7 @@ @ stub UiaPatternRelease @ stdcall UiaProviderForNonClient(ptr long long ptr) @ stdcall UiaProviderFromIAccessible(ptr long long ptr) -@ stub UiaRaiseAsyncContentLoadedEvent +@ stdcall UiaRaiseAsyncContentLoadedEvent(ptr long double) @ stdcall UiaRaiseAutomationEvent(ptr long) @ stdcall UiaRaiseAutomationPropertyChangedEvent(ptr long int128 int128) #@ stub UiaRaiseChangesEvent diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h index 7c8a5bd2839..1031467e0a4 100644 --- a/include/uiautomationcoreapi.h +++ b/include/uiautomationcoreapi.h @@ -440,6 +440,8 @@ int WINAPI UiaLookupId(enum AutomationIdentifierType type, const GUID *guid); BOOL WINAPI UiaPatternRelease(HUIAPATTERNOBJECT hobj); HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *provider, EVENTID id); HRESULT WINAPI UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple *, PROPERTYID, VARIANT, VARIANT); +HRESULT WINAPI UiaRaiseAsyncContentLoadedEvent(IRawElementProviderSimple *provider, + enum AsyncContentLoadedState async_content_loaded_state, double percent_complete); HRESULT WINAPI UiaRaiseStructureChangedEvent(IRawElementProviderSimple *provider, enum StructureChangeType struct_change_type, int *runtime_id, int runtime_id_len); void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *pCallback); From 004081e7156439002e8264f19776cab099fd4afe Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 11 Oct 2021 20:26:30 -0400 Subject: [PATCH 0774/2777] uiautomationcore: Add UiaRaiseTextEditTextChangedEvent stub. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_main.c | 10 ++++++++++ dlls/uiautomationcore/uiautomationcore.spec | 2 +- include/uiautomationcoreapi.h | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index e158e754fac..a47b09a8f7d 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -337,6 +337,16 @@ HRESULT WINAPI UiaRaiseAsyncContentLoadedEvent(IRawElementProviderSimple *provid return S_OK; } +/*********************************************************************** + * UiaRaiseTextEditTextChangedEvent (uiautomationcore.@) + */ +HRESULT WINAPI UiaRaiseTextEditTextChangedEvent(IRawElementProviderSimple *provider, + enum TextEditChangeType text_edit_change_type, SAFEARRAY *changed_data) +{ + FIXME("(%p, %d, %p): stub\n", provider, text_edit_change_type, changed_data); + return S_OK; +} + HRESULT WINAPI UiaHostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **provider) { struct hwnd_host_provider *host_prov; diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec index 09a53f86114..4cef3063b79 100644 --- a/dlls/uiautomationcore/uiautomationcore.spec +++ b/dlls/uiautomationcore/uiautomationcore.spec @@ -90,7 +90,7 @@ #@ stub UiaRaiseChangesEvent #@ stub UiaRaiseNotificationEvent @ stdcall UiaRaiseStructureChangedEvent(ptr long ptr long) -#@ stub UiaRaiseTextEditTextChangedEvent +@ stdcall UiaRaiseTextEditTextChangedEvent(ptr long ptr) @ stdcall UiaRegisterProviderCallback(ptr) @ stdcall UiaRemoveEvent(ptr) @ stdcall UiaReturnRawElementProvider(long long long ptr) diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h index 1031467e0a4..5c66e6b59d5 100644 --- a/include/uiautomationcoreapi.h +++ b/include/uiautomationcoreapi.h @@ -442,6 +442,8 @@ HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *provider, EVEN HRESULT WINAPI UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple *, PROPERTYID, VARIANT, VARIANT); HRESULT WINAPI UiaRaiseAsyncContentLoadedEvent(IRawElementProviderSimple *provider, enum AsyncContentLoadedState async_content_loaded_state, double percent_complete); +HRESULT WINAPI UiaRaiseTextEditTextChangedEvent(IRawElementProviderSimple *provider, enum TextEditChangeType text_edit_change_type, + SAFEARRAY *changed_data); HRESULT WINAPI UiaRaiseStructureChangedEvent(IRawElementProviderSimple *provider, enum StructureChangeType struct_change_type, int *runtime_id, int runtime_id_len); void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *pCallback); From 28c686e5953472d7573f0e09c7bfd05ab0992b34 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 11 Oct 2021 20:30:28 -0400 Subject: [PATCH 0775/2777] uiautomationcore: Add UiaRaiseNotificationEvent stub. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_main.c | 12 ++++++++++++ dlls/uiautomationcore/uiautomationcore.spec | 2 +- include/uiautomationcoreapi.h | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index a47b09a8f7d..2f7010eefcf 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -347,6 +347,18 @@ HRESULT WINAPI UiaRaiseTextEditTextChangedEvent(IRawElementProviderSimple *provi return S_OK; } +/*********************************************************************** + * UiaRaiseNotificationEvent (uiautomationcore.@) + */ +HRESULT WINAPI UiaRaiseNotificationEvent(IRawElementProviderSimple *provider, + enum NotificationKind notification_kind, enum NotificationProcessing notification_processing, + BSTR display_str, BSTR activity_id) +{ + FIXME("(%p, %d, %d, %s, %s): stub\n", provider, notification_kind, notification_processing, + debugstr_w(display_str), debugstr_w(activity_id)); + return S_OK; +} + HRESULT WINAPI UiaHostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **provider) { struct hwnd_host_provider *host_prov; diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec index 4cef3063b79..ff35a6ed1a6 100644 --- a/dlls/uiautomationcore/uiautomationcore.spec +++ b/dlls/uiautomationcore/uiautomationcore.spec @@ -88,7 +88,7 @@ @ stdcall UiaRaiseAutomationEvent(ptr long) @ stdcall UiaRaiseAutomationPropertyChangedEvent(ptr long int128 int128) #@ stub UiaRaiseChangesEvent -#@ stub UiaRaiseNotificationEvent +@ stdcall UiaRaiseNotificationEvent(ptr long long wstr wstr) @ stdcall UiaRaiseStructureChangedEvent(ptr long ptr long) @ stdcall UiaRaiseTextEditTextChangedEvent(ptr long ptr) @ stdcall UiaRegisterProviderCallback(ptr) diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h index 5c66e6b59d5..dd2caf46d9d 100644 --- a/include/uiautomationcoreapi.h +++ b/include/uiautomationcoreapi.h @@ -446,6 +446,8 @@ HRESULT WINAPI UiaRaiseTextEditTextChangedEvent(IRawElementProviderSimple *provi SAFEARRAY *changed_data); HRESULT WINAPI UiaRaiseStructureChangedEvent(IRawElementProviderSimple *provider, enum StructureChangeType struct_change_type, int *runtime_id, int runtime_id_len); +HRESULT WINAPI UiaRaiseNotificationEvent(IRawElementProviderSimple *provider, enum NotificationKind notification_kind, + enum NotificationProcessing notification_processing, BSTR display_str, BSTR activity_id); void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *pCallback); LRESULT WINAPI UiaReturnRawElementProvider(HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple *elprov); BOOL WINAPI UiaTextRangeRelease(HUIATEXTRANGE hobj); From a34fb84969529f9c1ae19b9dad132843158b9ae7 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 11 Oct 2021 20:35:28 -0400 Subject: [PATCH 0776/2777] uiautomationcore: Add UiaRaiseChangesEvent stub. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_main.c | 10 ++++++++++ dlls/uiautomationcore/uiautomationcore.spec | 2 +- include/uiautomationcoreapi.h | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 2f7010eefcf..8ce36f8fd76 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -359,6 +359,16 @@ HRESULT WINAPI UiaRaiseNotificationEvent(IRawElementProviderSimple *provider, return S_OK; } +/*********************************************************************** + * UiaRaiseChangesEvent (uiautomationcore.@) + */ +HRESULT WINAPI UiaRaiseChangesEvent(IRawElementProviderSimple *provider, int event_id_count, + struct UiaChangeInfo *uia_changes) +{ + FIXME("(%p, %d, %p): stub\n", provider, event_id_count, uia_changes); + return S_OK; +} + HRESULT WINAPI UiaHostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **provider) { struct hwnd_host_provider *host_prov; diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec index ff35a6ed1a6..c1a1d843ceb 100644 --- a/dlls/uiautomationcore/uiautomationcore.spec +++ b/dlls/uiautomationcore/uiautomationcore.spec @@ -87,7 +87,7 @@ @ stdcall UiaRaiseAsyncContentLoadedEvent(ptr long double) @ stdcall UiaRaiseAutomationEvent(ptr long) @ stdcall UiaRaiseAutomationPropertyChangedEvent(ptr long int128 int128) -#@ stub UiaRaiseChangesEvent +@ stdcall UiaRaiseChangesEvent(ptr long ptr) @ stdcall UiaRaiseNotificationEvent(ptr long long wstr wstr) @ stdcall UiaRaiseStructureChangedEvent(ptr long ptr long) @ stdcall UiaRaiseTextEditTextChangedEvent(ptr long ptr) diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h index dd2caf46d9d..6a6ad54e4f4 100644 --- a/include/uiautomationcoreapi.h +++ b/include/uiautomationcoreapi.h @@ -448,6 +448,7 @@ HRESULT WINAPI UiaRaiseStructureChangedEvent(IRawElementProviderSimple *provider int *runtime_id, int runtime_id_len); HRESULT WINAPI UiaRaiseNotificationEvent(IRawElementProviderSimple *provider, enum NotificationKind notification_kind, enum NotificationProcessing notification_processing, BSTR display_str, BSTR activity_id); +HRESULT WINAPI UiaRaiseChangesEvent(IRawElementProviderSimple *provider, int event_id_count, struct UiaChangeInfo *uia_changes); void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *pCallback); LRESULT WINAPI UiaReturnRawElementProvider(HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple *elprov); BOOL WINAPI UiaTextRangeRelease(HUIATEXTRANGE hobj); From 794db7f117dbef845c3efaff34af574d8b83833b Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 9 Jan 2023 11:45:49 -0500 Subject: [PATCH 0777/2777] include: Define UI Automation pattern provider interfaces. Signed-off-by: Connor McAdams --- include/uiautomationcore.idl | 601 +++++++++++++++++++++++++++++++++++ 1 file changed, 601 insertions(+) diff --git a/include/uiautomationcore.idl b/include/uiautomationcore.idl index ad6140f41b0..319bc7be475 100644 --- a/include/uiautomationcore.idl +++ b/include/uiautomationcore.idl @@ -191,6 +191,11 @@ struct UiaRect { double height; }; +struct UiaPoint { + double x; + double y; +}; + struct UiaChangeInfo { int uiaId; VARIANT payload; @@ -342,6 +347,602 @@ library UIA [propget] HRESULT DefaultAction([out, retval] BSTR *pszDefaultAction); } + [ + object, + uuid(159bc72c-4ad3-485e-9637-d7052edf0146), + pointer_default(unique), + oleautomation + ] + interface IDockProvider : IUnknown + { + HRESULT SetDockPosition([in] enum DockPosition dockPosition); + [propget] HRESULT DockPosition([out, retval] enum DockPosition *pRetVal); + }; + + [ + object, + uuid(d847d3a5-cab0-4a98-8c32-ecb45c59ad24), + pointer_default(unique), + oleautomation + ] + interface IExpandCollapseProvider : IUnknown + { + HRESULT Expand(); + HRESULT Collapse(); + [propget] HRESULT ExpandCollapseState([out, retval] enum ExpandCollapseState *pRetVal); + }; + + [ + object, + uuid(b17d6187-0907-464b-a168-0ef17a1572b1), + pointer_default(unique), + oleautomation + ] + interface IGridProvider : IUnknown + { + HRESULT GetItem( + [in] int row, + [in] int column, + [out, retval] IRawElementProviderSimple **pRetVal); + + [propget] HRESULT RowCount([out, retval] int *pRetVal); + [propget] HRESULT ColumnCount([out, retval] int *pRetVal); + }; + + [ + object, + uuid(d02541f1-fb81-4d64-ae32-f520f8a6dbd1), + pointer_default(unique), + oleautomation + ] + interface IGridItemProvider : IUnknown + { + [propget] HRESULT Row([out, retval] int *pRetVal); + [propget] HRESULT Column([out, retval] int *pRetVal); + [propget] HRESULT RowSpan([out, retval] int *pRetVal); + [propget] HRESULT ColumnSpan([out, retval] int *pRetVal); + [propget] HRESULT ContainingGrid([out, retval] IRawElementProviderSimple **pRetVal); + }; + + [ + object, + uuid(54fcb24b-e18e-47a2-b4d3-eccbe77599a2), + pointer_default(unique), + oleautomation + ] + interface IInvokeProvider : IUnknown + { + HRESULT Invoke(); + }; + + [ + object, + uuid(6278cab1-b556-4a1a-b4e0-418acc523201), + pointer_default(unique), + oleautomation + ] + interface IMultipleViewProvider : IUnknown + { + HRESULT GetViewName( + [in] int viewId, + [out, retval] BSTR *pRetVal); + + HRESULT SetCurrentView([in] int viewId); + [propget] HRESULT CurrentView([out, retval] int *pRetVal); + HRESULT GetSupportedViews([out, retval] SAFEARRAY(int) *pRetVal); + }; + + [ + object, + uuid(36dc7aef-33e6-4691-afe1-2be7274b3d33), + pointer_default(unique), + oleautomation + ] + interface IRangeValueProvider : IUnknown + { + HRESULT SetValue([in] double val); + [propget] HRESULT Value([out, retval] double *pRetVal); + [propget] HRESULT IsReadOnly([out, retval] BOOL *pRetVal); + [propget] HRESULT Maximum([out, retval] double *pRetVal); + [propget] HRESULT Minimum([out, retval] double *pRetVal); + [propget] HRESULT LargeChange([out, retval] double *pRetVal); + [propget] HRESULT SmallChange([out, retval] double *pRetVal); + }; + + [ + object, + uuid(2360c714-4bf1-4b26-ba65-9b21316127eb), + pointer_default(unique), + oleautomation + ] + interface IScrollItemProvider : IUnknown + { + HRESULT ScrollIntoView(); + }; + + [ + object, + uuid(fb8b03af-3bdf-48d4-bd36-1a65793be168), + pointer_default(unique), + oleautomation + ] + interface ISelectionProvider : IUnknown + { + /* + * FIXME: Current versions of Windows SDK use + * SAFEARRAY(IRawElementProviderSimple *) instead of + * SAFEARRAY(VARIANT). + */ + HRESULT GetSelection([out, retval] SAFEARRAY(VARIANT) *pRetVal); + [propget] HRESULT CanSelectMultiple([out, retval] BOOL *pRetVal); + [propget] HRESULT IsSelectionRequired([out, retval] BOOL *pRetVal); + }; + + [ + object, + uuid(b38b8077-1fc3-42a5-8cae-d40c2215055a), + pointer_default(unique), + oleautomation + ] + interface IScrollProvider : IUnknown + { + HRESULT Scroll( + [in] enum ScrollAmount horizontalAmount, + [in] enum ScrollAmount verticalAmount); + HRESULT SetScrollPercent( + [in] double horizontalPercent, + [in] double verticalPercent); + + [propget] HRESULT HorizontalScrollPercent([out, retval] double *pRetVal); + [propget] HRESULT VerticalScrollPercent([out, retval] double *pRetVal); + [propget] HRESULT HorizontalViewSize([out, retval] double *pRetVal); + [propget] HRESULT VerticalViewSize([out, retval] double *pRetVal); + [propget] HRESULT HorizontallyScrollable([out, retval] BOOL *pRetVal); + [propget] HRESULT VerticallyScrollable([out, retval] BOOL *pRetVal); + }; + + [ + object, + uuid(2acad808-b2d4-452d-a407-91ff1ad167b2), + pointer_default(unique), + oleautomation + ] + interface ISelectionItemProvider : IUnknown + { + HRESULT Select(); + HRESULT AddToSelection(); + HRESULT RemoveFromSelection(); + [propget] HRESULT IsSelected([out, retval] BOOL *pRetVal); + [propget] HRESULT SelectionContainer([out, retval] IRawElementProviderSimple **pRetVal); + }; + + [ + object, + uuid(29db1a06-02ce-4cf7-9b42-565d4fab20ee), + pointer_default(unique), + oleautomation + ] + interface ISynchronizedInputProvider : IUnknown + { + HRESULT StartListening([in] enum SynchronizedInputType inputType); + HRESULT Cancel(); + }; + + [ + object, + uuid(9c860395-97b3-490a-b52a-858cc22af166), + pointer_default(unique), + oleautomation + ] + interface ITableProvider : IUnknown + { + /* + * FIXME: Current versions of Windows SDK use + * SAFEARRAY(IRawElementProviderSimple *) instead of + * SAFEARRAY(VARIANT). + */ + HRESULT GetRowHeaders([out, retval] SAFEARRAY(VARIANT) *pRetVal); + HRESULT GetColumnHeaders([out, retval] SAFEARRAY(VARIANT) *pRetVal); + [propget] HRESULT RowOrColumnMajor([out, retval] enum RowOrColumnMajor *pRetVal); + }; + + [ + object, + uuid(b9734fa6-771f-4d78-9c90-2517999349cd), + pointer_default(unique), + oleautomation + ] + interface ITableItemProvider : IUnknown + { + /* + * FIXME: Current versions of Windows SDK use + * SAFEARRAY(IRawElementProviderSimple *) instead of + * SAFEARRAY(VARIANT). + */ + HRESULT GetRowHeaderItems([out, retval] SAFEARRAY(VARIANT) *pRetVal); + HRESULT GetColumnHeaderItems([out, retval] SAFEARRAY(VARIANT) *pRetVal); + }; + + [ + object, + uuid(56d00bd0-c4f4-433c-a836-1a52a57e0892), + pointer_default(unique), + oleautomation + ] + interface IToggleProvider : IUnknown + { + HRESULT Toggle(); + [propget] HRESULT ToggleState([out, retval] enum ToggleState *pRetVal); + }; + + [ + object, + uuid(6829ddc4-4f91-4ffa-b86f-bd3e2987cb4c), + pointer_default(unique), + oleautomation + ] + interface ITransformProvider : IUnknown + { + HRESULT Move( + [in] double x, + [in] double y); + HRESULT Resize( + [in] double width, + [in] double height); + + HRESULT Rotate([in] double degrees); + [propget] HRESULT CanMove([out, retval] BOOL *pRetVal); + [propget] HRESULT CanResize([out, retval] BOOL *pRetVal); + [propget] HRESULT CanRotate([out, retval] BOOL *pRetVal); + }; + + [ + object, + uuid(c7935180-6fb3-4201-b174-7df73adbf64a), + pointer_default(unique), + oleautomation + ] + interface IValueProvider : IUnknown + { + HRESULT SetValue([in] LPCWSTR val); + [propget] HRESULT Value([out, retval] BSTR *pRetVal); + [propget] HRESULT IsReadOnly([out, retval] BOOL *pRetVal); + }; + + [ + object, + uuid(987df77b-db06-4d77-8f8a-86a9c3bb90b9), + pointer_default(unique), + oleautomation + ] + interface IWindowProvider : IUnknown + { + HRESULT SetVisualState([in] enum WindowVisualState state); + HRESULT Close(); + + HRESULT WaitForInputIdle( + [in] int milliseconds, + [out, retval] BOOL *pRetVal); + + [propget] HRESULT CanMaximize([out, retval] BOOL *pRetVal); + [propget] HRESULT CanMinimize([out, retval] BOOL *pRetVal); + [propget] HRESULT IsModal([out, retval] BOOL *pRetVal); + [propget] HRESULT WindowVisualState([out, retval] enum WindowVisualState *pRetVal); + [propget] HRESULT WindowInteractionState([out, retval] enum WindowInteractionState *pRetVal); + [propget] HRESULT IsTopmost([out, retval] BOOL *pRetVal); + }; + + [ + object, + uuid(e747770b-39ce-4382-ab30-d8fb3f336f24), + pointer_default(unique), + oleautomation + ] + interface IItemContainerProvider : IUnknown + { + HRESULT FindItemByProperty( + [in] IRawElementProviderSimple *pStartAfter, + [in] PROPERTYID propertyId, + [in] VARIANT value, + [out, retval] IRawElementProviderSimple **pFound); + }; + + [ + object, + uuid(cb98b665-2d35-4fac-ad35-f3c60d0c0b8b), + pointer_default(unique), + oleautomation + ] + interface IVirtualizedItemProvider : IUnknown + { + HRESULT Realize(); + }; + + [ + object, + uuid(3ad86ebd-f5ef-483d-bb18-b1042a475d64), + pointer_default(unique), + oleautomation + ] + interface IObjectModelProvider : IUnknown + { + HRESULT GetUnderlyingObjectModel([out, retval] IUnknown **ppUnknown); + }; + + [ + object, + uuid(f95c7e80-bd63-4601-9782-445ebff011fc), + pointer_default(unique), + oleautomation + ] + interface IAnnotationProvider : IUnknown + { + [propget] HRESULT AnnotationTypeId([out, retval] int *retVal); + [propget] HRESULT AnnotationTypeName([out, retval] BSTR *retVal); + [propget] HRESULT Author([out, retval] BSTR *retVal); + [propget] HRESULT DateTime([out, retval] BSTR *retVal); + [propget] HRESULT Target([out, retval] IRawElementProviderSimple **retVal); + }; + + [ + object, + uuid(19b6b649-f5d7-4a6d-bdcb-129252be588a), + pointer_default(unique), + oleautomation + ] + interface IStylesProvider : IUnknown + { + [propget] HRESULT StyleId([out, retval] int *retVal); + [propget] HRESULT StyleName([out, retval] BSTR *retVal); + [propget] HRESULT FillColor([out, retval] int *retVal); + [propget] HRESULT FillPatternStyle([out, retval] BSTR *retVal); + [propget] HRESULT Shape([out, retval] BSTR *retVal); + [propget] HRESULT FillPatternColor([out, retval] int *retVal); + [propget] HRESULT ExtendedProperties([out, retval] BSTR *retVal); + }; + + [ + object, + uuid(6f6b5d35-5525-4f80-b758-85473832ffc7), + pointer_default(unique), + oleautomation + ] + interface ISpreadsheetProvider : IUnknown + { + HRESULT GetItemByName( + [in] LPCWSTR name, + [out, retval] IRawElementProviderSimple **pRetVal); + }; + + [ + object, + uuid(eaed4660-7b3d-4879-a2e6-365ce603f3d0), + pointer_default(unique), + oleautomation + ] + interface ISpreadsheetItemProvider : IUnknown + { + [propget] HRESULT Formula([out, retval] BSTR *pRetVal); + + /* + * FIXME: Current versions of Windows SDK use + * SAFEARRAY(IRawElementProviderSimple *) instead of + * SAFEARRAY(VARIANT). + */ + HRESULT GetAnnotationObjects([out, retval] SAFEARRAY(VARIANT) *pRetVal); + HRESULT GetAnnotationTypes([out, retval] SAFEARRAY(int) *pRetVal); + }; + + [ + object, + uuid(4758742f-7ac2-460c-bc48-09fc09308a93), + pointer_default(unique), + oleautomation + ] + interface ITransformProvider2 : ITransformProvider + { + HRESULT Zoom([in] double zoom); + [propget] HRESULT CanZoom([out, retval] BOOL *pRetVal); + [propget] HRESULT ZoomLevel([out, retval] double *pRetVal); + [propget] HRESULT ZoomMinimum([out, retval] double *pRetVal); + [propget] HRESULT ZoomMaximum([out, retval] double *pRetVal); + HRESULT ZoomByUnit([in] enum ZoomUnit zoomUnit); + } + + [ + object, + uuid(6aa7bbbb-7ff9-497d-904f-d20b897929d8), + pointer_default(unique), + oleautomation + ] + interface IDragProvider : IUnknown + { + [propget] HRESULT IsGrabbed([out, retval] BOOL *pRetVal); + [propget] HRESULT DropEffect([out, retval] BSTR *pRetVal); + [propget] HRESULT DropEffects([out, retval] SAFEARRAY(BSTR) *pRetVal); + + /* + * FIXME: Current versions of Windows SDK use + * SAFEARRAY(IRawElementProviderSimple *) instead of + * SAFEARRAY(VARIANT). + */ + HRESULT GetGrabbedItems([out, retval] SAFEARRAY(VARIANT) *pRetVal); + }; + + [ + object, + uuid(bae82bfd-358a-481c-85a0-d8b4d90a5d61), + pointer_default(unique), + oleautomation + ] + interface IDropTargetProvider : IUnknown + { + [propget] HRESULT DropTargetEffect([out, retval] BSTR *pRetVal); + [propget] HRESULT DropTargetEffects([out, retval] SAFEARRAY(BSTR) *pRetVal); + }; + + interface ITextRangeProvider; + [ + object, + uuid(3589c92c-63f3-4367-99bb-ada653b77cf2), + pointer_default(unique), + oleautomation + ] + interface ITextProvider : IUnknown + { + /* + * FIXME: Current versions of Windows SDK use + * SAFEARRAY(ITextRangeProvider *) instead of + * SAFEARRAY(VARIANT). + */ + HRESULT GetSelection([out, retval] SAFEARRAY(VARIANT) *pRetVal); + HRESULT GetVisibleRanges([out, retval] SAFEARRAY(VARIANT) *pRetVal); + + HRESULT RangeFromChild( + [in] IRawElementProviderSimple *childElement, + [out, retval] ITextRangeProvider **pRetVal); + HRESULT RangeFromPoint( + [in] struct UiaPoint point, + [out, retval] ITextRangeProvider **pRetVal); + + [propget] HRESULT DocumentRange([out, retval] ITextRangeProvider **pRetVal); + [propget] HRESULT SupportedTextSelection([out, retval] enum SupportedTextSelection *pRetVal); + }; + + [ + object, + uuid(0dc5e6ed-3e16-4bf1-8f9a-a979878bc195), + pointer_default(unique), + oleautomation + ] + interface ITextProvider2 : ITextProvider + { + HRESULT RangeFromAnnotation( + [in] IRawElementProviderSimple *annotationElement, + [out, retval] ITextRangeProvider **pRetVal); + HRESULT GetCaretRange( + [out] BOOL *isActive, + [out, retval] ITextRangeProvider **pRetVal); + } + + [ + object, + uuid(ea3605b4-3a05-400e-b5f9-4e91b40f6176), + pointer_default(unique), + oleautomation + ] + interface ITextEditProvider : ITextProvider + { + HRESULT GetActiveComposition([out, retval] ITextRangeProvider **pRetVal); + HRESULT GetConversionTarget([out, retval] ITextRangeProvider **pRetVal); + } + + [ + object, + uuid(5347ad7b-c355-46f8-aff5-909033582f63), + pointer_default(unique), + oleautomation + ] + interface ITextRangeProvider : IUnknown + { + HRESULT Clone([out, retval] ITextRangeProvider **pRetVal); + + HRESULT Compare( + [in] ITextRangeProvider *range, + [out, retval] BOOL *pRetVal); + HRESULT CompareEndpoints( + [in] enum TextPatternRangeEndpoint endpoint, + [in] ITextRangeProvider *targetRange, + [in] enum TextPatternRangeEndpoint targetEndpoint, + [out, retval] int *pRetVal); + + HRESULT ExpandToEnclosingUnit([in] enum TextUnit unit); + + HRESULT FindAttribute( + [in] TEXTATTRIBUTEID attributeId, + [in] VARIANT val, + [in] BOOL backward, + [out, retval] ITextRangeProvider **pRetVal); + HRESULT FindText( + [in] BSTR text, + [in] BOOL backward, + [in] BOOL ignoreCase, + [out, retval] ITextRangeProvider **pRetVal); + + HRESULT GetAttributeValue( + [in] TEXTATTRIBUTEID attributeId, + [out, retval] VARIANT *pRetVal); + + HRESULT GetBoundingRectangles([out, retval] SAFEARRAY(double) *pRetVal); + HRESULT GetEnclosingElement([out, retval] IRawElementProviderSimple **pRetVal); + + HRESULT GetText( + [in] int maxLength, + [out, retval] BSTR *pRetVal); + + HRESULT Move( + [in] enum TextUnit unit, + [in] int count, + [out, retval] int *pRetVal); + HRESULT MoveEndpointByUnit( + [in] enum TextPatternRangeEndpoint endpoint, + [in] enum TextUnit unit, + [in] int count, + [out, retval] int *pRetVal); + HRESULT MoveEndpointByRange( + [in] enum TextPatternRangeEndpoint endpoint, + [in] ITextRangeProvider *targetRange, + [in] enum TextPatternRangeEndpoint targetEndpoint); + + HRESULT Select(); + HRESULT AddToSelection(); + HRESULT RemoveFromSelection(); + HRESULT ScrollIntoView([in] BOOL alignToTop); + + /* + * FIXME: Current versions of Windows SDK use + * SAFEARRAY(IRawElementProviderSimple *) instead of + * SAFEARRAY(VARIANT). + */ + HRESULT GetChildren([out, retval] SAFEARRAY(VARIANT) *pRetVal); + }; + + [ + object, + uuid(9bbce42c-1921-4f18-89ca-dba1910a0386), + pointer_default(unique), + oleautomation + ] + interface ITextRangeProvider2 : ITextRangeProvider + { + HRESULT ShowContextMenu(); + } + + [ + object, + uuid(4c2de2b9-c88f-4f88-a111-f1d336b7d1a9), + pointer_default(unique), + oleautomation + ] + interface ITextChildProvider : IUnknown + { + [propget] HRESULT TextContainer([out, retval] IRawElementProviderSimple **pRetVal); + [propget] HRESULT TextRange([out, retval] ITextRangeProvider **pRetVal); + }; + + [ + object, + uuid(2062a28a-8c07-4b94-8e12-7037c622aeb8), + pointer_default(unique), + oleautomation + ] + interface ICustomNavigationProvider : IUnknown + { + HRESULT Navigate( + [in] enum NavigateDirection direction, + [out, retval] IRawElementProviderSimple **pRetVal); + } + enum UIAutomationType { UIAutomationType_Int = 0x01, UIAutomationType_Bool = 0x02, From fc8fefea313883b88cc2fdfe710d78caa169945d Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 17 Jan 2023 11:33:16 -0500 Subject: [PATCH 0778/2777] uiautomationcore: Implement UiaLookupId for AutomationIdentifierType_Pattern GUIDs. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 53 +++++++++++ dlls/uiautomationcore/uia_classes.idl | 6 ++ dlls/uiautomationcore/uia_ids.c | 101 +++++++++++++++++++++ include/uiautomationcoreapi.h | 38 ++++++++ 4 files changed, 198 insertions(+) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 7b9e25f32a7..e3660ababd1 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -4210,6 +4210,45 @@ static const struct uia_lookup_id uia_event_lookup_ids[] = { { &Notification_Event_GUID, UIA_NotificationEventId }, }; +static const struct uia_lookup_id uia_pattern_lookup_ids[] = { + { &Invoke_Pattern_GUID, UIA_InvokePatternId }, + { &Selection_Pattern_GUID, UIA_SelectionPatternId }, + { &Value_Pattern_GUID, UIA_ValuePatternId }, + { &RangeValue_Pattern_GUID, UIA_RangeValuePatternId }, + { &Scroll_Pattern_GUID, UIA_ScrollPatternId }, + { &ExpandCollapse_Pattern_GUID, UIA_ExpandCollapsePatternId }, + { &Grid_Pattern_GUID, UIA_GridPatternId }, + { &GridItem_Pattern_GUID, UIA_GridItemPatternId }, + { &MultipleView_Pattern_GUID, UIA_MultipleViewPatternId }, + { &Window_Pattern_GUID, UIA_WindowPatternId }, + { &SelectionItem_Pattern_GUID, UIA_SelectionItemPatternId }, + { &Dock_Pattern_GUID, UIA_DockPatternId }, + { &Table_Pattern_GUID, UIA_TablePatternId }, + { &TableItem_Pattern_GUID, UIA_TableItemPatternId }, + { &Text_Pattern_GUID, UIA_TextPatternId }, + { &Toggle_Pattern_GUID, UIA_TogglePatternId }, + { &Transform_Pattern_GUID, UIA_TransformPatternId }, + { &ScrollItem_Pattern_GUID, UIA_ScrollItemPatternId }, + { &LegacyIAccessible_Pattern_GUID, UIA_LegacyIAccessiblePatternId }, + { &ItemContainer_Pattern_GUID, UIA_ItemContainerPatternId }, + { &VirtualizedItem_Pattern_GUID, UIA_VirtualizedItemPatternId }, + { &SynchronizedInput_Pattern_GUID, UIA_SynchronizedInputPatternId }, + /* Implemented on Win8+ */ + { &ObjectModel_Pattern_GUID, UIA_ObjectModelPatternId }, + { &Annotation_Pattern_GUID, UIA_AnnotationPatternId }, + { &Text_Pattern2_GUID, UIA_TextPattern2Id }, + { &Styles_Pattern_GUID, UIA_StylesPatternId }, + { &Spreadsheet_Pattern_GUID, UIA_SpreadsheetPatternId }, + { &SpreadsheetItem_Pattern_GUID, UIA_SpreadsheetItemPatternId }, + { &Tranform_Pattern2_GUID, UIA_TransformPattern2Id }, + { &TextChild_Pattern_GUID, UIA_TextChildPatternId }, + { &Drag_Pattern_GUID, UIA_DragPatternId }, + { &DropTarget_Pattern_GUID, UIA_DropTargetPatternId }, + { &TextEdit_Pattern_GUID, UIA_TextEditPatternId }, + /* Implemented on Win10+. */ + { &CustomNavigation_Pattern_GUID, UIA_CustomNavigationPatternId }, +}; + static void test_UiaLookupId(void) { unsigned int i; @@ -4241,6 +4280,20 @@ static void test_UiaLookupId(void) ok(event_id == uia_event_lookup_ids[i].id, "Unexpected event id, expected %d, got %d\n", uia_event_lookup_ids[i].id, event_id); } + + for (i = 0; i < ARRAY_SIZE(uia_pattern_lookup_ids); i++) + { + int pattern_id = UiaLookupId(AutomationIdentifierType_Pattern, uia_pattern_lookup_ids[i].guid); + + if (!pattern_id) + { + win_skip("No patternId for GUID %s, skipping further tests.\n", debugstr_guid(uia_pattern_lookup_ids[i].guid)); + break; + } + + ok(pattern_id == uia_pattern_lookup_ids[i].id, "Unexpected pattern id, expected %d, got %d\n", + uia_pattern_lookup_ids[i].id, pattern_id); + } } static const struct prov_method_sequence node_from_prov1[] = { diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index 44479303888..12848934112 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -33,6 +33,12 @@ struct uia_event_info { int event_arg_type; }; +struct uia_pattern_info { + const GUID *guid; + int pattern_id; + const GUID *pattern_iid; +}; + [ version(1.0), uuid(8a9ca8eb-856b-43d9-abd7-4a590054064f), diff --git a/dlls/uiautomationcore/uia_ids.c b/dlls/uiautomationcore/uia_ids.c index dec07c8a62f..f51b6375841 100644 --- a/dlls/uiautomationcore/uia_ids.c +++ b/dlls/uiautomationcore/uia_ids.c @@ -37,6 +37,13 @@ static int __cdecl uia_event_guid_compare(const void *a, const void *b) return memcmp(guid, event->guid, sizeof(*guid)); } +static int __cdecl uia_pattern_guid_compare(const void *a, const void *b) +{ + const GUID *guid = a; + const struct uia_pattern_info *pattern = b; + return memcmp(guid, pattern->guid, sizeof(*guid)); +} + /* Sorted by GUID. */ static const struct uia_prop_info default_uia_properties[] = { { &AutomationId_Property_GUID, UIA_AutomationIdPropertyId, @@ -406,6 +413,89 @@ static const struct uia_event_info *uia_event_info_from_guid(const GUID *guid) return NULL; } +/* Sorted by GUID. */ +static const struct uia_pattern_info default_uia_patterns[] = { + { &ScrollItem_Pattern_GUID, UIA_ScrollItemPatternId, + &IID_IScrollItemProvider, }, + { &Tranform_Pattern2_GUID, UIA_TransformPattern2Id, + &IID_ITransformProvider2, }, + { &ItemContainer_Pattern_GUID, UIA_ItemContainerPatternId, + &IID_IItemContainerProvider, }, + { &Drag_Pattern_GUID, UIA_DragPatternId, + &IID_IDragProvider, }, + { &Window_Pattern_GUID, UIA_WindowPatternId, + &IID_IWindowProvider, }, + { &VirtualizedItem_Pattern_GUID, UIA_VirtualizedItemPatternId, + &IID_IVirtualizedItemProvider, }, + { &Dock_Pattern_GUID, UIA_DockPatternId, + &IID_IDockProvider, }, + { &Styles_Pattern_GUID, UIA_StylesPatternId, + &IID_IStylesProvider, }, + { &DropTarget_Pattern_GUID, UIA_DropTargetPatternId, + &IID_IDropTargetProvider, }, + { &Text_Pattern_GUID, UIA_TextPatternId, + &IID_ITextProvider, }, + { &Toggle_Pattern_GUID, UIA_TogglePatternId, + &IID_IToggleProvider, }, + { &GridItem_Pattern_GUID, UIA_GridItemPatternId, + &IID_IGridItemProvider, }, + { &RangeValue_Pattern_GUID, UIA_RangeValuePatternId, + &IID_IRangeValueProvider, }, + { &TextEdit_Pattern_GUID, UIA_TextEditPatternId, + &IID_ITextEditProvider, }, + { &CustomNavigation_Pattern_GUID, UIA_CustomNavigationPatternId, + &IID_ICustomNavigationProvider, }, + { &Table_Pattern_GUID, UIA_TablePatternId, + &IID_ITableProvider, }, + { &Value_Pattern_GUID, UIA_ValuePatternId, + &IID_IValueProvider, }, + { &LegacyIAccessible_Pattern_GUID, UIA_LegacyIAccessiblePatternId, + &IID_ILegacyIAccessibleProvider, }, + { &Text_Pattern2_GUID, UIA_TextPattern2Id, + &IID_ITextProvider2, }, + { &ExpandCollapse_Pattern_GUID, UIA_ExpandCollapsePatternId, + &IID_IExpandCollapseProvider, }, + { &SynchronizedInput_Pattern_GUID, UIA_SynchronizedInputPatternId, + &IID_ISynchronizedInputProvider, }, + { &Scroll_Pattern_GUID, UIA_ScrollPatternId, + &IID_IScrollProvider, }, + { &TextChild_Pattern_GUID, UIA_TextChildPatternId, + &IID_ITextChildProvider, }, + { &TableItem_Pattern_GUID, UIA_TableItemPatternId, + &IID_ITableItemProvider, }, + { &Spreadsheet_Pattern_GUID, UIA_SpreadsheetPatternId, + &IID_ISpreadsheetProvider, }, + { &Grid_Pattern_GUID, UIA_GridPatternId, + &IID_IGridProvider, }, + { &Annotation_Pattern_GUID, UIA_AnnotationPatternId, + &IID_IAnnotationProvider, }, + { &Transform_Pattern_GUID, UIA_TransformPatternId, + &IID_ITransformProvider, }, + { &MultipleView_Pattern_GUID, UIA_MultipleViewPatternId, + &IID_IMultipleViewProvider, }, + { &Selection_Pattern_GUID, UIA_SelectionPatternId, + &IID_ISelectionProvider, }, + { &SelectionItem_Pattern_GUID, UIA_SelectionItemPatternId, + &IID_ISelectionItemProvider, }, + { &Invoke_Pattern_GUID, UIA_InvokePatternId, + &IID_IInvokeProvider, }, + { &ObjectModel_Pattern_GUID, UIA_ObjectModelPatternId, + &IID_IObjectModelProvider, }, + { &SpreadsheetItem_Pattern_GUID, UIA_SpreadsheetItemPatternId, + &IID_ISpreadsheetItemProvider, }, +}; + +static const struct uia_pattern_info *uia_pattern_info_from_guid(const GUID *guid) +{ + struct uia_pattern_info *pattern; + + if ((pattern = bsearch(guid, default_uia_patterns, ARRAY_SIZE(default_uia_patterns), sizeof(*pattern), + uia_pattern_guid_compare))) + return pattern; + + return NULL; +} + /*********************************************************************** * UiaLookupId (uiautomationcore.@) */ @@ -442,6 +532,17 @@ int WINAPI UiaLookupId(enum AutomationIdentifierType type, const GUID *guid) } case AutomationIdentifierType_Pattern: + { + const struct uia_pattern_info *pattern = uia_pattern_info_from_guid(guid); + + if (pattern) + ret_id = pattern->pattern_id; + else + FIXME("Failed to find patternId for GUID %s\n", debugstr_guid(guid)); + + break; + } + case AutomationIdentifierType_ControlType: case AutomationIdentifierType_TextAttribute: case AutomationIdentifierType_LandmarkType: diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h index 6a6ad54e4f4..97522062dd9 100644 --- a/include/uiautomationcoreapi.h +++ b/include/uiautomationcoreapi.h @@ -261,6 +261,44 @@ DEFINE_GUID(TextEdit_ConversionTargetChanged_Event_GUID, 0x3388c18 DEFINE_GUID(Changes_Event_GUID, 0x7df26714,0x614f,0x4e05,0x94,0x88,0x71,0x6c,0x5b,0xa1,0x94,0x36); DEFINE_GUID(Notification_Event_GUID, 0x72c5a2f7,0x9788,0x480f,0xb8,0xeb,0x4d,0xee,0x00,0xf6,0x18,0x6f); +/* + * AutomationIdentifierType_Pattern GUIDs. + */ +DEFINE_GUID(Invoke_Pattern_GUID, 0xd976c2fc,0x66ea,0x4a6e,0xb2,0x8f,0xc2,0x4c,0x75,0x46,0xad,0x37); +DEFINE_GUID(Selection_Pattern_GUID, 0x66e3b7e8,0xd821,0x4d25,0x87,0x61,0x43,0x5d,0x2c,0x8b,0x25,0x3f); +DEFINE_GUID(Value_Pattern_GUID, 0x17faad9e,0xc877,0x475b,0xb9,0x33,0x77,0x33,0x27,0x79,0xb6,0x37); +DEFINE_GUID(RangeValue_Pattern_GUID, 0x18b00d87,0xb1c9,0x476a,0xbf,0xbd,0x5f,0x0b,0xdb,0x92,0x6f,0x63); +DEFINE_GUID(Scroll_Pattern_GUID, 0x895fa4b4,0x759d,0x4c50,0x8e,0x15,0x03,0x46,0x06,0x72,0x00,0x3c); +DEFINE_GUID(ExpandCollapse_Pattern_GUID, 0xae05efa2,0xf9d1,0x428a,0x83,0x4c,0x53,0xa5,0xc5,0x2f,0x9b,0x8b); +DEFINE_GUID(Grid_Pattern_GUID, 0x260a2ccb,0x93a8,0x4e44,0xa4,0xc1,0x3d,0xf3,0x97,0xf2,0xb0,0x2b); +DEFINE_GUID(GridItem_Pattern_GUID, 0xf2d5c877,0xa462,0x4957,0xa2,0xa5,0x2c,0x96,0xb3,0x03,0xbc,0x63); +DEFINE_GUID(MultipleView_Pattern_GUID, 0x547a6ae4,0x113f,0x47c4,0x85,0x0f,0xdb,0x4d,0xfa,0x46,0x6b,0x1d); +DEFINE_GUID(Window_Pattern_GUID, 0x27901735,0xc760,0x4994,0xad,0x11,0x59,0x19,0xe6,0x06,0xb1,0x10); +DEFINE_GUID(SelectionItem_Pattern_GUID, 0x9bc64eeb,0x87c7,0x4b28,0x94,0xbb,0x4d,0x9f,0xa4,0x37,0xb6,0xef); +DEFINE_GUID(Dock_Pattern_GUID, 0x9cbaa846,0x83c8,0x428d,0x82,0x7f,0x7e,0x60,0x63,0xfe,0x06,0x20); +DEFINE_GUID(Table_Pattern_GUID, 0xc415218e,0xa028,0x461e,0xaa,0x92,0x8f,0x92,0x5c,0xf7,0x93,0x51); +DEFINE_GUID(TableItem_Pattern_GUID, 0xdf1343bd,0x1888,0x4a29,0xa5,0x0c,0xb9,0x2e,0x6d,0xe3,0x7f,0x6f); +DEFINE_GUID(Text_Pattern_GUID, 0x8615f05d,0x7de5,0x44fd,0xa6,0x79,0x2c,0xa4,0xb4,0x60,0x33,0xa8); +DEFINE_GUID(Toggle_Pattern_GUID, 0x0b419760,0xe2f4,0x43ff,0x8c,0x5f,0x94,0x57,0xc8,0x2b,0x56,0xe9); +DEFINE_GUID(Transform_Pattern_GUID, 0x24b46fdb,0x587e,0x49f1,0x9c,0x4a,0xd8,0xe9,0x8b,0x66,0x4b,0x7b); +DEFINE_GUID(ScrollItem_Pattern_GUID, 0x4591d005,0xa803,0x4d5c,0xb4,0xd5,0x8d,0x28,0x00,0xf9,0x06,0xa7); +DEFINE_GUID(LegacyIAccessible_Pattern_GUID, 0x54cc0a9f,0x3395,0x48af,0xba,0x8d,0x73,0xf8,0x56,0x90,0xf3,0xe0); +DEFINE_GUID(ItemContainer_Pattern_GUID, 0x3d13da0f,0x8b9a,0x4a99,0x85,0xfa,0xc5,0xc9,0xa6,0x9f,0x1e,0xd4); +DEFINE_GUID(VirtualizedItem_Pattern_GUID, 0xf510173e,0x2e71,0x45e9,0xa6,0xe5,0x62,0xf6,0xed,0x82,0x89,0xd5); +DEFINE_GUID(SynchronizedInput_Pattern_GUID, 0x05c288a6,0xc47b,0x488b,0xb6,0x53,0x33,0x97,0x7a,0x55,0x1b,0x8b); +DEFINE_GUID(ObjectModel_Pattern_GUID, 0x3e04acfe,0x08fc,0x47ec,0x96,0xbc,0x35,0x3f,0xa3,0xb3,0x4a,0xa7); +DEFINE_GUID(Annotation_Pattern_GUID, 0xf6c72ad7,0x356c,0x4850,0x92,0x91,0x31,0x6f,0x60,0x8a,0x8c,0x84); +DEFINE_GUID(Text_Pattern2_GUID, 0x498479a2,0x5b22,0x448d,0xb6,0xe4,0x64,0x74,0x90,0x86,0x06,0x98); +DEFINE_GUID(Styles_Pattern_GUID, 0x1ae62655,0xda72,0x4d60,0xa1,0x53,0xe5,0xaa,0x69,0x88,0xe3,0xbf); +DEFINE_GUID(Spreadsheet_Pattern_GUID, 0x6a5b24c9,0x9d1e,0x4b85,0x9e,0x44,0xc0,0x2e,0x31,0x69,0xb1,0x0b); +DEFINE_GUID(SpreadsheetItem_Pattern_GUID, 0x32cf83ff,0xf1a8,0x4a8c,0x86,0x58,0xd4,0x7b,0xa7,0x4e,0x20,0xba); +DEFINE_GUID(Tranform_Pattern2_GUID, 0x8afcfd07,0xa369,0x44de,0x98,0x8b,0x2f,0x7f,0xf4,0x9f,0xb8,0xa8); +DEFINE_GUID(TextChild_Pattern_GUID, 0x7533cab7,0x3bfe,0x41ef,0x9e,0x85,0xe2,0x63,0x8c,0xbe,0x16,0x9e); +DEFINE_GUID(Drag_Pattern_GUID, 0xc0bee21f,0xccb3,0x4fed,0x99,0x5b,0x11,0x4f,0x6e,0x3d,0x27,0x28); +DEFINE_GUID(DropTarget_Pattern_GUID, 0x0bcbec56,0xbd34,0x4b7b,0x9f,0xd5,0x26,0x59,0x90,0x5e,0xa3,0xdc); +DEFINE_GUID(TextEdit_Pattern_GUID, 0x69f3ff89,0x5af9,0x4c75,0x93,0x40,0xf2,0xde,0x29,0x2e,0x45,0x91); +DEFINE_GUID(CustomNavigation_Pattern_GUID, 0xafea938a,0x621e,0x4054,0xbb,0x2c,0x2f,0x46,0x11,0x4d,0xac,0x3f); + enum AutomationIdentifierType { AutomationIdentifierType_Property, From c8a6810692123705783e1d2aa2c36d103e29467d Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 17 Jan 2023 14:22:05 -0500 Subject: [PATCH 0779/2777] uiautomationcore: Use SendMessageCallback in node_from_lresult() to prevent a deadlock. If we pass a node to the provider thread that contains a provider that was created in an STA with the ProviderOptions_UseComThreading flag set, we can deadlock when attempting to get a runtime ID from the proxy. To avoid this, use SendMessageCallback and pump the message queue until we get a result from the provider thread. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 30 ++++++++++++++++++ dlls/uiautomationcore/uia_provider.c | 36 +++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index e3660ababd1..ce550d20686 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -5703,6 +5703,14 @@ static const struct prov_method_sequence node_from_hwnd9[] = { { 0 } }; +static const struct prov_method_sequence node_from_hwnd10[] = { + NODE_CREATE_SEQ(&Provider), + /* Next two only done on Windows 8+. */ + { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, + { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { 0 } +}; static const struct prov_method_sequence disconnect_prov1[] = { { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, /* Win10v1507 and below call this. */ @@ -5984,6 +5992,28 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param) Sleep(50); ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref); + /* ProviderOptions_UseComThreading test from a separate thread. */ + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + /* Only sent on Win7. */ + SET_EXPECT(winproc_GETOBJECT_CLIENT); + prov_root = &Provider.IRawElementProviderSimple_iface; + initialize_provider(&Provider, ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading, NULL, FALSE); + Provider.frag_root = NULL; + Provider.runtime_id[0] = Provider.runtime_id[1] = 0xdeadbeef; + hr = UiaNodeFromHandle(hwnd, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + called_winproc_GETOBJECT_CLIENT = expect_winproc_GETOBJECT_CLIENT = 0; + + ok_method_sequence(node_from_hwnd10, "node_from_hwnd10"); + + ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); + /* Win10v1809 can be slow to call Release on Provider. */ + if (Provider.ref != 1) + Sleep(50); + ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref); + if (!pUiaDisconnectProvider) { win_skip("UiaDisconnectProvider not exported by uiautomationcore.dll\n"); diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index 66665d92d33..cd1d8934a55 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -2297,6 +2297,19 @@ void uia_stop_provider_thread(void) LeaveCriticalSection(&provider_thread_cs); } +struct uia_lresult_from_node_data { + LRESULT lr; + BOOL returned; +}; + +static void CALLBACK uia_lresult_from_node_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT lresult) +{ + struct uia_lresult_from_node_data *cb_data = (struct uia_lresult_from_node_data *)data; + + cb_data->lr = lresult; + cb_data->returned = TRUE; +} + /* * Pass our IWineUiaNode interface to the provider thread for marshaling. UI * Automation has to work regardless of whether or not COM is initialized on @@ -2304,13 +2317,34 @@ void uia_stop_provider_thread(void) */ LRESULT uia_lresult_from_node(HUIANODE huianode) { + struct uia_lresult_from_node_data cb_data = { 0 }; + if (!uia_start_provider_thread()) { UiaNodeRelease(huianode); return 0; } - return SendMessageW(provider_thread.hwnd, WM_GET_OBJECT_UIA_NODE, 0, (LPARAM)huianode); + if (!SendMessageCallbackW(provider_thread.hwnd, WM_GET_OBJECT_UIA_NODE, 0, (LPARAM)huianode, + uia_lresult_from_node_callback, (ULONG_PTR)&cb_data)) + { + WARN("SendMessageCallback failed, error %ld\n", GetLastError()); + UiaNodeRelease(huianode); + return 0; + } + + while (!cb_data.returned) + { + MSG msg; + + if (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + + return cb_data.lr; } /*********************************************************************** From d2b684d860f61df9487a4ee627fcebb830a21d59 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 25 Jan 2023 11:11:16 -0500 Subject: [PATCH 0780/2777] uiautomationcore/tests: Add tests for non-nested node events. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 469 ++++++++++++++++++++- include/uiautomationcore.idl | 16 + 2 files changed, 483 insertions(+), 2 deletions(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index ce550d20686..44b80473d29 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -74,6 +74,7 @@ DEFINE_EXPECT(prov_callback_base_hwnd); DEFINE_EXPECT(prov_callback_nonclient); DEFINE_EXPECT(prov_callback_proxy); DEFINE_EXPECT(prov_callback_parent_proxy); +DEFINE_EXPECT(uia_event_callback); DEFINE_EXPECT(winproc_GETOBJECT_UiaRoot); DEFINE_EXPECT(child_winproc_GETOBJECT_UiaRoot); DEFINE_EXPECT(Accessible_accNavigate); @@ -1115,6 +1116,7 @@ static struct Provider IRawElementProviderFragment IRawElementProviderFragment_iface; IRawElementProviderFragmentRoot IRawElementProviderFragmentRoot_iface; IRawElementProviderHwndOverride IRawElementProviderHwndOverride_iface; + IRawElementProviderAdviseEvents IRawElementProviderAdviseEvents_iface; LONG ref; const char *prov_name; @@ -1198,6 +1200,8 @@ enum { FRAG_GET_BOUNDING_RECT, FRAG_GET_EMBEDDED_FRAGMENT_ROOTS, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, + ADVISE_EVENTS_EVENT_ADDED, + ADVISE_EVENTS_EVENT_REMOVED, }; static const char *prov_method_str[] = { @@ -1210,6 +1214,8 @@ static const char *prov_method_str[] = { "get_BoundingRectangle", "GetEmbeddedFragmentRoots", "GetOverrideProviderForHwnd", + "AdviseEventAdded", + "AdviseEventRemoved", }; static const char *get_prov_method_str(int method) @@ -1527,6 +1533,8 @@ HRESULT WINAPI ProviderSimple_QueryInterface(IRawElementProviderSimple *iface, R *ppv = &This->IRawElementProviderFragmentRoot_iface; else if (IsEqualIID(riid, &IID_IRawElementProviderHwndOverride)) *ppv = &This->IRawElementProviderHwndOverride_iface; + else if (IsEqualIID(riid, &IID_IRawElementProviderAdviseEvents)) + *ppv = &This->IRawElementProviderAdviseEvents_iface; else return E_NOINTERFACE; @@ -1917,9 +1925,15 @@ static HRESULT WINAPI ProviderFragment_get_BoundingRectangle(IRawElementProvider static HRESULT WINAPI ProviderFragment_GetEmbeddedFragmentRoots(IRawElementProviderFragment *iface, SAFEARRAY **ret_val) { - ok(0, "unexpected call\n"); + struct Provider *This = impl_from_ProviderFragment(iface); + + add_method_call(This, FRAG_GET_EMBEDDED_FRAGMENT_ROOTS); + if (This->expected_tid) + ok(This->expected_tid == GetCurrentThreadId(), "Unexpected tid %ld\n", GetCurrentThreadId()); + This->last_call_tid = GetCurrentThreadId(); + *ret_val = NULL; - return E_NOTIMPL; + return S_OK; } static HRESULT WINAPI ProviderFragment_SetFocus(IRawElementProviderFragment *iface) @@ -2054,12 +2068,71 @@ static const IRawElementProviderHwndOverrideVtbl ProviderHwndOverrideVtbl = { ProviderHwndOverride_GetOverrideProviderForHwnd, }; +static inline struct Provider *impl_from_ProviderAdviseEvents(IRawElementProviderAdviseEvents *iface) +{ + return CONTAINING_RECORD(iface, struct Provider, IRawElementProviderAdviseEvents_iface); +} + +static HRESULT WINAPI ProviderAdviseEvents_QueryInterface(IRawElementProviderAdviseEvents *iface, REFIID riid, + void **ppv) +{ + struct Provider *Provider = impl_from_ProviderAdviseEvents(iface); + return IRawElementProviderSimple_QueryInterface(&Provider->IRawElementProviderSimple_iface, riid, ppv); +} + +static ULONG WINAPI ProviderAdviseEvents_AddRef(IRawElementProviderAdviseEvents *iface) +{ + struct Provider *Provider = impl_from_ProviderAdviseEvents(iface); + return IRawElementProviderSimple_AddRef(&Provider->IRawElementProviderSimple_iface); +} + +static ULONG WINAPI ProviderAdviseEvents_Release(IRawElementProviderAdviseEvents *iface) +{ + struct Provider *Provider = impl_from_ProviderAdviseEvents(iface); + return IRawElementProviderSimple_Release(&Provider->IRawElementProviderSimple_iface); +} + +static HRESULT WINAPI ProviderAdviseEvents_AdviseEventAdded(IRawElementProviderAdviseEvents *iface, + EVENTID event_id, SAFEARRAY *prop_ids) +{ + struct Provider *This = impl_from_ProviderAdviseEvents(iface); + + add_method_call(This, ADVISE_EVENTS_EVENT_ADDED); + if (This->expected_tid) + ok(This->expected_tid == GetCurrentThreadId(), "Unexpected tid %ld\n", GetCurrentThreadId()); + This->last_call_tid = GetCurrentThreadId(); + + return S_OK; +} + +static HRESULT WINAPI ProviderAdviseEvents_AdviseEventRemoved(IRawElementProviderAdviseEvents *iface, + EVENTID event_id, SAFEARRAY *prop_ids) +{ + struct Provider *This = impl_from_ProviderAdviseEvents(iface); + + add_method_call(This, ADVISE_EVENTS_EVENT_REMOVED); + if (This->expected_tid) + ok(This->expected_tid == GetCurrentThreadId(), "Unexpected tid %ld\n", GetCurrentThreadId()); + This->last_call_tid = GetCurrentThreadId(); + + return S_OK; +} + +static const IRawElementProviderAdviseEventsVtbl ProviderAdviseEventsVtbl = { + ProviderAdviseEvents_QueryInterface, + ProviderAdviseEvents_AddRef, + ProviderAdviseEvents_Release, + ProviderAdviseEvents_AdviseEventAdded, + ProviderAdviseEvents_AdviseEventRemoved, +}; + static struct Provider Provider = { { &ProviderSimpleVtbl }, { &ProviderFragmentVtbl }, { &ProviderFragmentRootVtbl }, { &ProviderHwndOverrideVtbl }, + { &ProviderAdviseEventsVtbl }, 1, "Provider", NULL, NULL, @@ -2074,6 +2147,7 @@ static struct Provider Provider2 = { &ProviderFragmentVtbl }, { &ProviderFragmentRootVtbl }, { &ProviderHwndOverrideVtbl }, + { &ProviderAdviseEventsVtbl }, 1, "Provider2", NULL, NULL, @@ -2088,6 +2162,7 @@ static struct Provider Provider_child = { &ProviderFragmentVtbl }, { &ProviderFragmentRootVtbl }, { &ProviderHwndOverrideVtbl }, + { &ProviderAdviseEventsVtbl }, 1, "Provider_child", &Provider.IRawElementProviderFragment_iface, &Provider.IRawElementProviderFragmentRoot_iface, @@ -2102,6 +2177,7 @@ static struct Provider Provider_child2 = { &ProviderFragmentVtbl }, { &ProviderFragmentRootVtbl }, { &ProviderHwndOverrideVtbl }, + { &ProviderAdviseEventsVtbl }, 1, "Provider_child2", &Provider.IRawElementProviderFragment_iface, &Provider.IRawElementProviderFragmentRoot_iface, @@ -2116,6 +2192,7 @@ static struct Provider Provider_hwnd = { &ProviderFragmentVtbl }, { &ProviderFragmentRootVtbl }, { &ProviderHwndOverrideVtbl }, + { &ProviderAdviseEventsVtbl }, 1, "Provider_hwnd", NULL, NULL, @@ -2130,6 +2207,7 @@ static struct Provider Provider_nc = { &ProviderFragmentVtbl }, { &ProviderFragmentRootVtbl }, { &ProviderHwndOverrideVtbl }, + { &ProviderAdviseEventsVtbl }, 1, "Provider_nc", NULL, NULL, @@ -2145,6 +2223,7 @@ static struct Provider Provider_proxy = { &ProviderFragmentVtbl }, { &ProviderFragmentRootVtbl }, { &ProviderHwndOverrideVtbl }, + { &ProviderAdviseEventsVtbl }, 1, "Provider_proxy", NULL, NULL, @@ -2160,6 +2239,7 @@ static struct Provider Provider_proxy2 = { &ProviderFragmentVtbl }, { &ProviderFragmentRootVtbl }, { &ProviderHwndOverrideVtbl }, + { &ProviderAdviseEventsVtbl }, 1, "Provider_proxy2", NULL, NULL, @@ -2175,6 +2255,7 @@ static struct Provider Provider_override = { &ProviderFragmentVtbl }, { &ProviderFragmentRootVtbl }, { &ProviderHwndOverrideVtbl }, + { &ProviderAdviseEventsVtbl }, 1, "Provider_override", NULL, NULL, @@ -2191,6 +2272,7 @@ static struct Provider Provider_override = { &ProviderFragmentVtbl }, \ { &ProviderFragmentRootVtbl }, \ { &ProviderHwndOverrideVtbl }, \ + { &ProviderAdviseEventsVtbl }, \ 1, \ "Provider_" # name "", \ NULL, NULL, \ @@ -9932,6 +10014,388 @@ static void test_CUIAutomation(void) CoUninitialize(); } +#define NODE_CREATE_SEQ3(prov) \ + { prov , PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, \ + /* Win10v1507 and below call this. */ \ + { prov , PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ \ + { prov , PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, \ + { prov , PROV_GET_PROPERTY_VALUE }, \ + { prov , FRAG_NAVIGATE }, /* NavigateDirection_Parent */ \ + { prov , PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL } \ + +static const struct prov_method_sequence event_seq1[] = { + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win8+. */ + { 0 }, +}; + +static const struct prov_method_sequence event_seq2[] = { + { &Provider, FRAG_GET_RUNTIME_ID }, + { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ + { &Provider, FRAG_GET_FRAGMENT_ROOT }, + { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win8+. */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ + { &Provider, ADVISE_EVENTS_EVENT_ADDED }, + { 0 }, +}; + +static const struct prov_method_sequence event_seq3[] = { + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win8+. */ + NODE_CREATE_SEQ3(&Provider), + { &Provider, FRAG_GET_RUNTIME_ID }, + { 0 }, +}; + +static const struct prov_method_sequence event_seq4[] = { + { &Provider, ADVISE_EVENTS_EVENT_REMOVED }, + { 0 }, +}; + +static const struct prov_method_sequence event_seq5[] = { + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win8+. */ + NODE_CREATE_SEQ3(&Provider), + { &Provider, FRAG_GET_RUNTIME_ID }, + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId. */ + { 0 }, +}; + +static const struct prov_method_sequence event_seq6[] = { + { &Provider, FRAG_GET_RUNTIME_ID }, + { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ + { &Provider, FRAG_GET_FRAGMENT_ROOT }, + { &Provider, FRAG_GET_EMBEDDED_FRAGMENT_ROOTS, METHOD_TODO }, + { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win8+. */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ + { &Provider, ADVISE_EVENTS_EVENT_ADDED }, + { 0 }, +}; + +static const struct prov_method_sequence event_seq7[] = { + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win8+. */ + NODE_CREATE_SEQ3(&Provider), + { &Provider, FRAG_GET_RUNTIME_ID }, + /* Only done on Win10v1507 and below. */ + { &Provider, FRAG_NAVIGATE, METHOD_OPTIONAL }, /* NavigateDirection_Parent */ + { 0 }, +}; + +static const struct prov_method_sequence event_seq8[] = { + { &Provider_child_child, PROV_GET_PROVIDER_OPTIONS }, + { &Provider_child_child, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win8+. */ + NODE_CREATE_SEQ3(&Provider_child_child), + { &Provider_child_child, FRAG_GET_RUNTIME_ID }, + { &Provider_child_child, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + NODE_CREATE_SEQ(&Provider_child), + { &Provider_child, FRAG_GET_RUNTIME_ID }, + { 0 }, +}; + +static const struct prov_method_sequence event_seq9[] = { + { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, + { &Provider_child, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win8+. */ + NODE_CREATE_SEQ3(&Provider_child), + { &Provider_child, FRAG_GET_RUNTIME_ID }, + { &Provider_child, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + NODE_CREATE_SEQ(&Provider), + { &Provider, FRAG_GET_RUNTIME_ID }, + { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId. */ + { 0 }, +}; + +static const struct prov_method_sequence event_seq10[] = { + { &Provider_child_child, PROV_GET_PROVIDER_OPTIONS }, + { &Provider_child_child, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win8+. */ + NODE_CREATE_SEQ3(&Provider_child_child), + { &Provider_child_child, FRAG_GET_RUNTIME_ID }, + { &Provider_child_child, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + NODE_CREATE_SEQ(&Provider_child), + { &Provider_child, FRAG_GET_RUNTIME_ID }, + { &Provider_child, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + NODE_CREATE_SEQ(&Provider), + { &Provider, FRAG_GET_RUNTIME_ID }, + { &Provider_child_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId. */ + { 0 }, +}; + +static const struct prov_method_sequence event_seq11[] = { + { &Provider, FRAG_GET_RUNTIME_ID }, + { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ + { &Provider, FRAG_GET_FRAGMENT_ROOT }, + { &Provider, FRAG_GET_EMBEDDED_FRAGMENT_ROOTS, METHOD_TODO }, + { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win8+. */ + { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ + { &Provider2, ADVISE_EVENTS_EVENT_ADDED }, + { 0 }, +}; + +static const struct prov_method_sequence event_seq12[] = { + { &Provider2, ADVISE_EVENTS_EVENT_REMOVED }, + { 0 }, +}; + +static const struct UiaCacheRequest DefaultCacheReq = { + (struct UiaCondition *)&UiaTrueCondition, + TreeScope_Element, + NULL, 0, + NULL, 0, + AutomationElementMode_Full, +}; + +static struct EventData { + LONG exp_lbound[2]; + LONG exp_elems[2]; + struct node_provider_desc exp_node_desc; + const WCHAR *exp_tree_struct; +} EventData; + +static void WINAPI uia_event_callback(struct UiaEventArgs *args, SAFEARRAY *req_data, BSTR tree_struct) +{ + CHECK_EXPECT(uia_event_callback); + + test_cache_req_sa(req_data, EventData.exp_lbound, EventData.exp_elems, &EventData.exp_node_desc); + ok(!wcscmp(tree_struct, EventData.exp_tree_struct), "tree structure %s\n", debugstr_w(tree_struct)); + + SafeArrayDestroy(req_data); + SysFreeString(tree_struct); +} + +struct event_test_thread_data { + HUIAEVENT event; + DWORD exp_thread_id; +}; + +static DWORD WINAPI uia_add_event_test_thread(LPVOID param) +{ + struct event_test_thread_data *data = (struct event_test_thread_data *)param; + HRESULT hr; + + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + hr = UiaRemoveEvent(data->event); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + ok(Provider2.ref == 1, "Unexpected refcnt %ld\n", Provider2.ref); + if (SUCCEEDED(hr)) + ok_method_sequence(event_seq12, "event_seq12"); + + todo_wine ok(Provider2.last_call_tid == data->exp_thread_id || + broken(Provider2.last_call_tid == GetCurrentThreadId()), "Expected method call on separate thread\n"); + + CoUninitialize(); + return 0; +} + +static void test_UiaAddEvent(void) +{ + struct event_test_thread_data thread_data = { 0 }; + HUIAEVENT event; + HUIANODE node; + HANDLE thread; + HRESULT hr; + VARIANT v; + + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + /* + * Raise event without any registered event handlers. + */ + initialize_provider(&Provider, ProviderOptions_ServerSideProvider, NULL, TRUE); + hr = UiaRaiseAutomationEvent(&Provider.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr) && sequence_cnt) + ok_method_sequence(event_seq1, "event_seq1"); + + hr = UiaNodeFromProvider(&Provider.IRawElementProviderSimple_iface, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), NULL); + check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", TRUE); + VariantClear(&v); + } + ok_method_sequence(node_from_prov2, NULL); + + /* + * Register an event on a node without an HWND/RuntimeId. The event will + * be created successfully, but without any way to match a provider to + * this node, we won't be able to trigger the event handler. + */ + event = NULL; + Provider.frag_root = &Provider.IRawElementProviderFragmentRoot_iface; + hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback, TreeScope_Element, NULL, 0, + (struct UiaCacheRequest *)&DefaultCacheReq, &event); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(!!event, "event == NULL\n"); + todo_wine ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); + if (SUCCEEDED(hr)) + ok_method_sequence(event_seq2, "event_seq2"); + + /* + * Even though we raise an event on the same provider as the one our node + * currently represents, without an HWND/RuntimeId, we have no way to + * match them. The event handler will not be called. + */ + hr = UiaRaiseAutomationEvent(&Provider.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr) && sequence_cnt) + ok_method_sequence(event_seq3, "event_seq3"); + + hr = UiaRemoveEvent(event); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + if (SUCCEEDED(hr)) + ok_method_sequence(event_seq4, "event_seq4"); + + /* + * Register an event on the same node again, except this time we have a + * runtimeID. + */ + event = NULL; + Provider.runtime_id[0] = Provider.runtime_id[1] = 0xdeadbeef; + hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback, TreeScope_Element, NULL, 0, + (struct UiaCacheRequest *)&DefaultCacheReq, &event); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(!!event, "event == NULL\n"); + todo_wine ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); + if (SUCCEEDED(hr)) + ok_method_sequence(event_seq2, "event_seq2"); + + /* Event handler is called since we can match our providers by runtime ID. */ + EventData.exp_elems[0] = EventData.exp_elems[1] = 1; + EventData.exp_tree_struct = L"P)"; + init_node_provider_desc(&EventData.exp_node_desc, GetCurrentProcessId(), NULL); + add_provider_desc(&EventData.exp_node_desc, L"Main", L"Provider", TRUE); + SET_EXPECT(uia_event_callback); + hr = UiaRaiseAutomationEvent(&Provider.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine CHECK_CALLED(uia_event_callback); + if (SUCCEEDED(hr) && sequence_cnt) + ok_method_sequence(event_seq5, "event_seq5"); + + hr = UiaRemoveEvent(event); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + if (SUCCEEDED(hr)) + ok_method_sequence(event_seq4, "event_seq4"); + + /* Create an event with TreeScope_Children. */ + initialize_provider(&Provider_child, ProviderOptions_ServerSideProvider, NULL, TRUE); + provider_add_child(&Provider, &Provider_child); + initialize_provider(&Provider_child_child, ProviderOptions_ServerSideProvider, NULL, TRUE); + provider_add_child(&Provider_child, &Provider_child_child); + hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback, TreeScope_Children, NULL, 0, + (struct UiaCacheRequest *)&DefaultCacheReq, &event); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(!!event, "event == NULL\n"); + todo_wine ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); + if (SUCCEEDED(hr)) + ok_method_sequence(event_seq6, "event_seq6"); + + /* + * Only TreeScope_Children and not TreeScope_Element, handler won't be + * called. + */ + hr = UiaRaiseAutomationEvent(&Provider.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr) && sequence_cnt) + ok_method_sequence(event_seq7, "event_seq7"); + + /* Provider_child_child is not a direct child, handler won't be called. */ + hr = UiaRaiseAutomationEvent(&Provider_child_child.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr) && sequence_cnt) + ok_method_sequence(event_seq8, "event_seq8"); + + /* Raised an event on Provider_child, handler will be called. */ + init_node_provider_desc(&EventData.exp_node_desc, GetCurrentProcessId(), NULL); + add_provider_desc(&EventData.exp_node_desc, L"Main", L"Provider_child", TRUE); + SET_EXPECT(uia_event_callback); + hr = UiaRaiseAutomationEvent(&Provider_child.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine CHECK_CALLED(uia_event_callback); + if (SUCCEEDED(hr) && sequence_cnt) + ok_method_sequence(event_seq9, "event_seq9"); + + hr = UiaRemoveEvent(event); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + if (SUCCEEDED(hr)) + ok_method_sequence(event_seq4, "event_seq4"); + + /* Create an event with TreeScope_Descendants. */ + hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback, TreeScope_Element | TreeScope_Descendants, NULL, 0, + (struct UiaCacheRequest *)&DefaultCacheReq, &event); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(!!event, "event == NULL\n"); + todo_wine ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); + if (SUCCEEDED(hr)) + ok_method_sequence(event_seq6, "event_seq6"); + + /* Raised an event on Provider_child_child. */ + init_node_provider_desc(&EventData.exp_node_desc, GetCurrentProcessId(), NULL); + add_provider_desc(&EventData.exp_node_desc, L"Main", L"Provider_child_child", TRUE); + SET_EXPECT(uia_event_callback); + hr = UiaRaiseAutomationEvent(&Provider_child_child.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine CHECK_CALLED(uia_event_callback); + if (SUCCEEDED(hr) && sequence_cnt) + ok_method_sequence(event_seq10, "event_seq10"); + + hr = UiaRemoveEvent(event); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + if (SUCCEEDED(hr)) + ok_method_sequence(event_seq4, "event_seq4"); + + CoUninitialize(); + + /* + * When adding an event, each node provider's fragment root is queried + * for, and if one is retrieved, it's IRawElementProviderAdviseEvents + * interface is used. On Win10v1809+, ProviderOptions_UseComThreading is + * respected for these interfaces. Set Provider2 as the fragment root here + * to test this. + */ + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + initialize_provider(&Provider2, ProviderOptions_UseComThreading | ProviderOptions_ServerSideProvider, NULL, TRUE); + Provider.frag_root = &Provider2.IRawElementProviderFragmentRoot_iface; + hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback, TreeScope_Element | TreeScope_Descendants, NULL, 0, + (struct UiaCacheRequest *)&DefaultCacheReq, &event); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(!!event, "event == NULL\n"); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + todo_wine ok(Provider2.ref > 1, "Unexpected refcnt %ld\n", Provider2.ref); + if (SUCCEEDED(hr)) + ok_method_sequence(event_seq11, "event_seq11"); + + thread_data.exp_thread_id = GetCurrentThreadId(); + thread_data.event = event; + thread = CreateThread(NULL, 0, uia_add_event_test_thread, (void *)&thread_data, 0, NULL); + while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0) + { + MSG msg; + + while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + CloseHandle(thread); + + UiaNodeRelease(node); + ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref); + + CoUninitialize(); +} + /* * Once a process returns a UI Automation provider with * UiaReturnRawElementProvider it ends up in an implicit MTA until exit. This @@ -10000,6 +10464,7 @@ START_TEST(uiautomation) test_UiaFind(); test_default_proxy_providers(); test_CUIAutomation(); + test_UiaAddEvent(); if (uia_dll) { pUiaProviderFromIAccessible = (void *)GetProcAddress(uia_dll, "UiaProviderFromIAccessible"); diff --git a/include/uiautomationcore.idl b/include/uiautomationcore.idl index 319bc7be475..074e4c4dfb6 100644 --- a/include/uiautomationcore.idl +++ b/include/uiautomationcore.idl @@ -316,6 +316,22 @@ library UIA [out, retval] IRawElementProviderSimple **pRetVal); } + [ + object, + uuid(a407b27b-0f6d-4427-9292-473c7bf93258), + pointer_default(unique), + oleautomation + ] + interface IRawElementProviderAdviseEvents : IUnknown + { + HRESULT AdviseEventAdded( + [in] EVENTID eventId, + [in] SAFEARRAY(PROPERTYID) propertyIDs); + HRESULT AdviseEventRemoved( + [in] EVENTID eventId, + [in] SAFEARRAY(PROPERTYID) propertyIDs); + } + [ object, uuid(e44c3566-915d-4070-99c6-047bff5a08f5), From 68a9d2ac4499ed94aff28fb3af027e1079e04acb Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 25 Jan 2023 11:51:56 -0500 Subject: [PATCH 0781/2777] uiautomationcore: Partially implement UiaAddEvent. Create an entry into the client event list. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 47 ++--- dlls/uiautomationcore/uia_classes.idl | 10 + dlls/uiautomationcore/uia_client.c | 223 ++++++++++++++++++++- dlls/uiautomationcore/uia_ids.c | 16 ++ dlls/uiautomationcore/uia_private.h | 1 + 5 files changed, 269 insertions(+), 28 deletions(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 44b80473d29..209cfa9f667 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10031,10 +10031,10 @@ static const struct prov_method_sequence event_seq1[] = { static const struct prov_method_sequence event_seq2[] = { { &Provider, FRAG_GET_RUNTIME_ID }, { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ - { &Provider, FRAG_GET_FRAGMENT_ROOT }, + { &Provider, FRAG_GET_FRAGMENT_ROOT, METHOD_TODO }, { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win8+. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ - { &Provider, ADVISE_EVENTS_EVENT_ADDED }, + { &Provider, ADVISE_EVENTS_EVENT_ADDED, METHOD_TODO }, { 0 }, }; @@ -10063,11 +10063,11 @@ static const struct prov_method_sequence event_seq5[] = { static const struct prov_method_sequence event_seq6[] = { { &Provider, FRAG_GET_RUNTIME_ID }, { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ - { &Provider, FRAG_GET_FRAGMENT_ROOT }, + { &Provider, FRAG_GET_FRAGMENT_ROOT, METHOD_TODO }, { &Provider, FRAG_GET_EMBEDDED_FRAGMENT_ROOTS, METHOD_TODO }, { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win8+. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ - { &Provider, ADVISE_EVENTS_EVENT_ADDED }, + { &Provider, ADVISE_EVENTS_EVENT_ADDED, METHOD_TODO }, { 0 }, }; @@ -10122,11 +10122,11 @@ static const struct prov_method_sequence event_seq10[] = { static const struct prov_method_sequence event_seq11[] = { { &Provider, FRAG_GET_RUNTIME_ID }, { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ - { &Provider, FRAG_GET_FRAGMENT_ROOT }, + { &Provider, FRAG_GET_FRAGMENT_ROOT, METHOD_TODO }, { &Provider, FRAG_GET_EMBEDDED_FRAGMENT_ROOTS, METHOD_TODO }, { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win8+. */ { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ - { &Provider2, ADVISE_EVENTS_EVENT_ADDED }, + { &Provider2, ADVISE_EVENTS_EVENT_ADDED, METHOD_TODO }, { 0 }, }; @@ -10230,11 +10230,10 @@ static void test_UiaAddEvent(void) Provider.frag_root = &Provider.IRawElementProviderFragmentRoot_iface; hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback, TreeScope_Element, NULL, 0, (struct UiaCacheRequest *)&DefaultCacheReq, &event); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(!!event, "event == NULL\n"); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!event, "event == NULL\n"); todo_wine ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); - if (SUCCEEDED(hr)) - ok_method_sequence(event_seq2, "event_seq2"); + ok_method_sequence(event_seq2, "event_seq2"); /* * Even though we raise an event on the same provider as the one our node @@ -10260,11 +10259,10 @@ static void test_UiaAddEvent(void) Provider.runtime_id[0] = Provider.runtime_id[1] = 0xdeadbeef; hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback, TreeScope_Element, NULL, 0, (struct UiaCacheRequest *)&DefaultCacheReq, &event); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(!!event, "event == NULL\n"); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!event, "event == NULL\n"); todo_wine ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); - if (SUCCEEDED(hr)) - ok_method_sequence(event_seq2, "event_seq2"); + ok_method_sequence(event_seq2, "event_seq2"); /* Event handler is called since we can match our providers by runtime ID. */ EventData.exp_elems[0] = EventData.exp_elems[1] = 1; @@ -10291,11 +10289,10 @@ static void test_UiaAddEvent(void) provider_add_child(&Provider_child, &Provider_child_child); hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback, TreeScope_Children, NULL, 0, (struct UiaCacheRequest *)&DefaultCacheReq, &event); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(!!event, "event == NULL\n"); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!event, "event == NULL\n"); todo_wine ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); - if (SUCCEEDED(hr)) - ok_method_sequence(event_seq6, "event_seq6"); + ok_method_sequence(event_seq6, "event_seq6"); /* * Only TreeScope_Children and not TreeScope_Element, handler won't be @@ -10331,11 +10328,10 @@ static void test_UiaAddEvent(void) /* Create an event with TreeScope_Descendants. */ hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback, TreeScope_Element | TreeScope_Descendants, NULL, 0, (struct UiaCacheRequest *)&DefaultCacheReq, &event); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(!!event, "event == NULL\n"); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!event, "event == NULL\n"); todo_wine ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); - if (SUCCEEDED(hr)) - ok_method_sequence(event_seq6, "event_seq6"); + ok_method_sequence(event_seq6, "event_seq6"); /* Raised an event on Provider_child_child. */ init_node_provider_desc(&EventData.exp_node_desc, GetCurrentProcessId(), NULL); @@ -10368,12 +10364,11 @@ static void test_UiaAddEvent(void) Provider.frag_root = &Provider2.IRawElementProviderFragmentRoot_iface; hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback, TreeScope_Element | TreeScope_Descendants, NULL, 0, (struct UiaCacheRequest *)&DefaultCacheReq, &event); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(!!event, "event == NULL\n"); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!event, "event == NULL\n"); ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); todo_wine ok(Provider2.ref > 1, "Unexpected refcnt %ld\n", Provider2.ref); - if (SUCCEEDED(hr)) - ok_method_sequence(event_seq11, "event_seq11"); + ok_method_sequence(event_seq11, "event_seq11"); thread_data.exp_thread_id = GetCurrentThreadId(); thread_data.event = event; diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index 12848934112..3f43e2c70ec 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -48,6 +48,16 @@ library UIA_wine_private { importlib("stdole2.tlb"); + [ + object, + uuid(5e60162c-ab0e-4e22-a61d-3a3acd442aba), + pointer_default(unique), + oleautomation, + ] + interface IWineUiaEvent : IUnknown + { + } + [ object, uuid(57865755-6c05-4522-98df-4ca658b768ef), diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 83c19fcc2e5..8f26e893fca 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -19,11 +19,200 @@ #include "uia_private.h" #include "wine/debug.h" +#include "wine/rbtree.h" WINE_DEFAULT_DEBUG_CHANNEL(uiautomation); static const struct UiaCondition UiaFalseCondition = { ConditionType_False }; +#define EVENT_TYPE_LOCAL 0 +struct uia_event +{ + IWineUiaEvent IWineUiaEvent_iface; + LONG ref; + + SAFEARRAY *runtime_id; + LONG event_cookie; + int event_id; + int scope; + + struct list event_list_entry; + struct uia_client_event_data_map_entry *event_data; + int event_type; + union + { + struct { + struct UiaCacheRequest *cache_req; + UiaEventCallback *cback; + } local; + } u; +}; + +/* + * UI Automation client event list. + */ +static struct uia_client_events +{ + struct rb_tree event_map; + LONG event_count; +} client_events; + +struct uia_client_event_data_map_entry +{ + struct rb_entry entry; + + int event_id; + struct list local_events_list; +}; + +static int uia_event_map_id_compare(const void *key, const struct rb_entry *entry) +{ + struct uia_client_event_data_map_entry *event_entry = RB_ENTRY_VALUE(entry, struct uia_client_event_data_map_entry, entry); + int *event_id = (int *)key; + + return (event_entry->event_id > (*event_id)) - (event_entry->event_id < (*event_id)); +} + +static HRESULT uia_get_event_data_for_event(struct uia_client_event_data_map_entry **event_data, + int event_id, BOOL create_new) +{ + *event_data = NULL; + + if (!client_events.event_count && !create_new) + return S_OK; + + /* First, attempt to find an existing event_data structure. */ + if (client_events.event_count) + { + struct rb_entry *rb_entry; + + rb_entry = rb_get(&client_events.event_map, &event_id); + if (rb_entry) + { + *event_data = RB_ENTRY_VALUE(rb_entry, struct uia_client_event_data_map_entry, entry); + return S_OK; + } + } + + if (create_new) + { + struct uia_client_event_data_map_entry *data = heap_alloc_zero(sizeof(*data)); + + if (!data) + return E_OUTOFMEMORY; + + data->event_id = event_id; + list_init(&data->local_events_list); + + if (InterlockedIncrement(&client_events.event_count) == 1) + rb_init(&client_events.event_map, uia_event_map_id_compare); + rb_put(&client_events.event_map, &event_id, &data->entry); + + *event_data = data; + } + + return S_OK; +} + +static HRESULT uia_client_add_event(struct uia_event *event) +{ + struct uia_client_event_data_map_entry *event_data; + HRESULT hr; + + hr = uia_get_event_data_for_event(&event_data, event->event_id, TRUE); + if (FAILED(hr)) + return hr; + + list_add_head(&event_data->local_events_list, &event->event_list_entry); + event->event_data = event_data; + + return S_OK; +} + +/* + * IWineUiaEvent interface. + */ +static inline struct uia_event *impl_from_IWineUiaEvent(IWineUiaEvent *iface) +{ + return CONTAINING_RECORD(iface, struct uia_event, IWineUiaEvent_iface); +} + +static HRESULT WINAPI uia_event_QueryInterface(IWineUiaEvent *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IWineUiaEvent) || IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else + return E_NOINTERFACE; + + IWineUiaEvent_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI uia_event_AddRef(IWineUiaEvent *iface) +{ + struct uia_event *event = impl_from_IWineUiaEvent(iface); + ULONG ref = InterlockedIncrement(&event->ref); + + TRACE("%p, refcount %ld\n", event, ref); + return ref; +} + +static ULONG WINAPI uia_event_Release(IWineUiaEvent *iface) +{ + struct uia_event *event = impl_from_IWineUiaEvent(iface); + ULONG ref = InterlockedDecrement(&event->ref); + + TRACE("%p, refcount %ld\n", event, ref); + if (!ref) + { + if (event->event_data) + { + list_remove(&event->event_list_entry); + if (list_empty(&event->event_data->local_events_list)) + { + rb_remove(&client_events.event_map, &event->event_data->entry); + heap_free(event->event_data); + InterlockedDecrement(&client_events.event_count); + } + } + + SafeArrayDestroy(event->runtime_id); + heap_free(event); + } + + return ref; +} + +static const IWineUiaEventVtbl uia_event_vtbl = { + uia_event_QueryInterface, + uia_event_AddRef, + uia_event_Release, +}; + +static struct uia_event *create_uia_event(int event_id, int scope, struct UiaCacheRequest *cache_req, + UiaEventCallback *cback, SAFEARRAY *runtime_id) +{ + struct uia_event *event = heap_alloc_zero(sizeof(*event)); + static LONG next_event_cookie; + + if (!event) + return NULL; + + event->IWineUiaEvent_iface.lpVtbl = &uia_event_vtbl; + event->ref = 1; + event->event_cookie = InterlockedIncrement(&next_event_cookie); + event->runtime_id = runtime_id; + event->event_id = event_id; + event->scope = scope; + + event->event_type = EVENT_TYPE_LOCAL; + event->u.local.cache_req = cache_req; + event->u.local.cback = cback; + + return event; +} + struct uia_node_array { HUIANODE *nodes; int node_count; @@ -3063,9 +3252,39 @@ HRESULT WINAPI UiaFind(HUIANODE huianode, struct UiaFindParams *find_params, str HRESULT WINAPI UiaAddEvent(HUIANODE huianode, EVENTID event_id, UiaEventCallback *callback, enum TreeScope scope, PROPERTYID *prop_ids, int prop_ids_count, struct UiaCacheRequest *cache_req, HUIAEVENT *huiaevent) { - FIXME("(%p, %d, %p, %#x, %p, %d, %p, %p)\n", huianode, event_id, callback, scope, prop_ids, prop_ids_count, + const struct uia_event_info *event_info = uia_event_info_from_id(event_id); + struct uia_event *event; + SAFEARRAY *sa; + HRESULT hr; + + TRACE("(%p, %d, %p, %#x, %p, %d, %p, %p)\n", huianode, event_id, callback, scope, prop_ids, prop_ids_count, cache_req, huiaevent); - return E_NOTIMPL; + + if (!callback || !cache_req || !huiaevent || !event_info) + return E_INVALIDARG; + + *huiaevent = NULL; + + hr = UiaGetRuntimeId(huianode, &sa); + if (FAILED(hr)) + return hr; + + if (!(event = create_uia_event(event_id, scope, cache_req, callback, sa))) + { + SafeArrayDestroy(sa); + return E_OUTOFMEMORY; + } + + hr = uia_client_add_event(event); + if (FAILED(hr)) + { + IWineUiaEvent_Release(&event->IWineUiaEvent_iface); + return hr; + } + + *huiaevent = (HUIAEVENT)event; + + return S_OK; } /*********************************************************************** diff --git a/dlls/uiautomationcore/uia_ids.c b/dlls/uiautomationcore/uia_ids.c index f51b6375841..a594f630c9b 100644 --- a/dlls/uiautomationcore/uia_ids.c +++ b/dlls/uiautomationcore/uia_ids.c @@ -399,6 +399,14 @@ static const struct uia_event_info default_uia_events[] = { EventArgsType_Simple, }, }; +static const int event_id_idx[] = { + 0x23, 0x1d, 0x0d, 0x0b, 0x19, 0x06, 0x07, 0x0f, + 0x0a, 0x1e, 0x1b, 0x1a, 0x22, 0x00, 0x18, 0x10, + 0x01, 0x20, 0x08, 0x17, 0x15, 0x13, 0x0e, 0x0c, + 0x14, 0x09, 0x03, 0x21, 0x12, 0x16, 0x05, 0x1c, + 0x02, 0x11, 0x04, 0x1f, +}; + #define EVENT_ID_MIN 20000 #define EVENT_ID_MAX (EVENT_ID_MIN + ARRAY_SIZE(default_uia_events)) @@ -413,6 +421,14 @@ static const struct uia_event_info *uia_event_info_from_guid(const GUID *guid) return NULL; } +const struct uia_event_info *uia_event_info_from_id(EVENTID event_id) +{ + if ((event_id < EVENT_ID_MIN) || (event_id > EVENT_ID_MAX)) + return NULL; + + return &default_uia_events[event_id_idx[event_id - EVENT_ID_MIN]]; +} + /* Sorted by GUID. */ static const struct uia_pattern_info default_uia_patterns[] = { { &ScrollItem_Pattern_GUID, UIA_ScrollItemPatternId, diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 5fb42ef86f4..a977f37bf2d 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -133,6 +133,7 @@ HRESULT create_uia_iface(IUnknown **iface, BOOL is_cui8) DECLSPEC_HIDDEN; /* uia_ids.c */ const struct uia_prop_info *uia_prop_info_from_id(PROPERTYID prop_id) DECLSPEC_HIDDEN; +const struct uia_event_info *uia_event_info_from_id(EVENTID event_id) DECLSPEC_HIDDEN; /* uia_provider.c */ void uia_stop_provider_thread(void) DECLSPEC_HIDDEN; From 3faa96fba7e5300cbfc969fcba9f8d8ebe202678 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Fri, 9 Dec 2022 14:18:33 -0500 Subject: [PATCH 0782/2777] uiautomationcore: Implement UiaRemoveEvent. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 29 +++++++++------------- dlls/uiautomationcore/uia_client.c | 19 ++++++++++++-- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 209cfa9f667..a88649b4cf7 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10047,7 +10047,7 @@ static const struct prov_method_sequence event_seq3[] = { }; static const struct prov_method_sequence event_seq4[] = { - { &Provider, ADVISE_EVENTS_EVENT_REMOVED }, + { &Provider, ADVISE_EVENTS_EVENT_REMOVED, METHOD_TODO }, { 0 }, }; @@ -10131,7 +10131,7 @@ static const struct prov_method_sequence event_seq11[] = { }; static const struct prov_method_sequence event_seq12[] = { - { &Provider2, ADVISE_EVENTS_EVENT_REMOVED }, + { &Provider2, ADVISE_EVENTS_EVENT_REMOVED, METHOD_TODO }, { 0 }, }; @@ -10174,11 +10174,10 @@ static DWORD WINAPI uia_add_event_test_thread(LPVOID param) CoInitializeEx(NULL, COINIT_MULTITHREADED); hr = UiaRemoveEvent(data->event); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); ok(Provider2.ref == 1, "Unexpected refcnt %ld\n", Provider2.ref); - if (SUCCEEDED(hr)) - ok_method_sequence(event_seq12, "event_seq12"); + ok_method_sequence(event_seq12, "event_seq12"); todo_wine ok(Provider2.last_call_tid == data->exp_thread_id || broken(Provider2.last_call_tid == GetCurrentThreadId()), "Expected method call on separate thread\n"); @@ -10246,10 +10245,9 @@ static void test_UiaAddEvent(void) ok_method_sequence(event_seq3, "event_seq3"); hr = UiaRemoveEvent(event); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); - if (SUCCEEDED(hr)) - ok_method_sequence(event_seq4, "event_seq4"); + ok_method_sequence(event_seq4, "event_seq4"); /* * Register an event on the same node again, except this time we have a @@ -10277,10 +10275,9 @@ static void test_UiaAddEvent(void) ok_method_sequence(event_seq5, "event_seq5"); hr = UiaRemoveEvent(event); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); - if (SUCCEEDED(hr)) - ok_method_sequence(event_seq4, "event_seq4"); + ok_method_sequence(event_seq4, "event_seq4"); /* Create an event with TreeScope_Children. */ initialize_provider(&Provider_child, ProviderOptions_ServerSideProvider, NULL, TRUE); @@ -10320,10 +10317,9 @@ static void test_UiaAddEvent(void) ok_method_sequence(event_seq9, "event_seq9"); hr = UiaRemoveEvent(event); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); - if (SUCCEEDED(hr)) - ok_method_sequence(event_seq4, "event_seq4"); + ok_method_sequence(event_seq4, "event_seq4"); /* Create an event with TreeScope_Descendants. */ hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback, TreeScope_Element | TreeScope_Descendants, NULL, 0, @@ -10344,10 +10340,9 @@ static void test_UiaAddEvent(void) ok_method_sequence(event_seq10, "event_seq10"); hr = UiaRemoveEvent(event); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); - if (SUCCEEDED(hr)) - ok_method_sequence(event_seq4, "event_seq4"); + ok_method_sequence(event_seq4, "event_seq4"); CoUninitialize(); diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 8f26e893fca..a507fa64291 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -190,6 +190,14 @@ static const IWineUiaEventVtbl uia_event_vtbl = { uia_event_Release, }; +static struct uia_event *unsafe_impl_from_IWineUiaEvent(IWineUiaEvent *iface) +{ + if (!iface || (iface->lpVtbl != &uia_event_vtbl)) + return NULL; + + return CONTAINING_RECORD(iface, struct uia_event, IWineUiaEvent_iface); +} + static struct uia_event *create_uia_event(int event_id, int scope, struct UiaCacheRequest *cache_req, UiaEventCallback *cback, SAFEARRAY *runtime_id) { @@ -3292,8 +3300,15 @@ HRESULT WINAPI UiaAddEvent(HUIANODE huianode, EVENTID event_id, UiaEventCallback */ HRESULT WINAPI UiaRemoveEvent(HUIAEVENT huiaevent) { - FIXME("(%p): stub\n", huiaevent); - return E_NOTIMPL; + struct uia_event *event = unsafe_impl_from_IWineUiaEvent((IWineUiaEvent *)huiaevent); + + TRACE("(%p)\n", event); + + if (!event) + return E_INVALIDARG; + + IWineUiaEvent_Release(&event->IWineUiaEvent_iface); + return S_OK; } /*********************************************************************** From 616bea86ecfc52746f24828ce77eda6b5e3c542d Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Fri, 9 Dec 2022 15:50:51 -0500 Subject: [PATCH 0783/2777] uiautomationcore: Implement UiaRaiseAutomationEvent. Feels like it's probably good for now, but will potentially get reworked later. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 21 ++-- dlls/uiautomationcore/uia_client.c | 133 +++++++++++++++++++++ dlls/uiautomationcore/uia_main.c | 9 -- 3 files changed, 141 insertions(+), 22 deletions(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index a88649b4cf7..8ce2c07d931 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10270,9 +10270,8 @@ static void test_UiaAddEvent(void) SET_EXPECT(uia_event_callback); hr = UiaRaiseAutomationEvent(&Provider.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine CHECK_CALLED(uia_event_callback); - if (SUCCEEDED(hr) && sequence_cnt) - ok_method_sequence(event_seq5, "event_seq5"); + CHECK_CALLED(uia_event_callback); + ok_method_sequence(event_seq5, "event_seq5"); hr = UiaRemoveEvent(event); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -10297,14 +10296,12 @@ static void test_UiaAddEvent(void) */ hr = UiaRaiseAutomationEvent(&Provider.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (SUCCEEDED(hr) && sequence_cnt) - ok_method_sequence(event_seq7, "event_seq7"); + ok_method_sequence(event_seq7, "event_seq7"); /* Provider_child_child is not a direct child, handler won't be called. */ hr = UiaRaiseAutomationEvent(&Provider_child_child.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (SUCCEEDED(hr) && sequence_cnt) - ok_method_sequence(event_seq8, "event_seq8"); + ok_method_sequence(event_seq8, "event_seq8"); /* Raised an event on Provider_child, handler will be called. */ init_node_provider_desc(&EventData.exp_node_desc, GetCurrentProcessId(), NULL); @@ -10312,9 +10309,8 @@ static void test_UiaAddEvent(void) SET_EXPECT(uia_event_callback); hr = UiaRaiseAutomationEvent(&Provider_child.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine CHECK_CALLED(uia_event_callback); - if (SUCCEEDED(hr) && sequence_cnt) - ok_method_sequence(event_seq9, "event_seq9"); + CHECK_CALLED(uia_event_callback); + ok_method_sequence(event_seq9, "event_seq9"); hr = UiaRemoveEvent(event); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -10335,9 +10331,8 @@ static void test_UiaAddEvent(void) SET_EXPECT(uia_event_callback); hr = UiaRaiseAutomationEvent(&Provider_child_child.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine CHECK_CALLED(uia_event_callback); - if (SUCCEEDED(hr) && sequence_cnt) - ok_method_sequence(event_seq10, "event_seq10"); + CHECK_CALLED(uia_event_callback); + ok_method_sequence(event_seq10, "event_seq10"); hr = UiaRemoveEvent(event); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index a507fa64291..affd30dca68 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -3328,3 +3328,136 @@ HRESULT WINAPI UiaEventRemoveWindow(HUIAEVENT huiaevent, HWND hwnd) FIXME("(%p, %p): stub\n", huiaevent, hwnd); return E_NOTIMPL; } + +static HRESULT uia_process_event(HUIANODE node, struct UiaEventArgs *args, SAFEARRAY *rt_id, + struct uia_event *event) +{ + struct uia_node *node_data = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)node); + SAFEARRAY *sa = rt_id; + int height = 0; + HUIANODE node2; + HRESULT hr; + + IWineUiaEvent_AddRef(&event->IWineUiaEvent_iface); + IWineUiaNode_AddRef(&node_data->IWineUiaNode_iface); + while (1) + { + int cmp = -1; + if (sa) + { + cmp = uia_compare_safearrays(sa, event->runtime_id, UIAutomationType_IntArray); + if (sa != rt_id) + SafeArrayDestroy(sa); + sa = NULL; + } + + if (!cmp && ((!height && (event->scope & TreeScope_Element)) || + (height && (event->scope & (TreeScope_Descendants | TreeScope_Children))))) + { + if (event->event_type == EVENT_TYPE_LOCAL) + { + SAFEARRAY *out_req; + BSTR tree_struct; + + hr = UiaGetUpdatedCache(node, event->u.local.cache_req, NormalizeState_None, NULL, &out_req, + &tree_struct); + if (SUCCEEDED(hr)) + event->u.local.cback(args, out_req, tree_struct); + } + + break; + } + + if ((!height && !(event->scope & (TreeScope_Descendants | TreeScope_Children))) || + (height == 1 && !(event->scope & TreeScope_Descendants))) + break; + + node2 = NULL; + hr = navigate_uia_node(node_data, NavigateDirection_Parent, &node2); + if (FAILED(hr) || !node2) + break; + + height++; + IWineUiaNode_Release(&node_data->IWineUiaNode_iface); + node_data = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)node2); + + hr = UiaGetRuntimeId(node2, &sa); + if (FAILED(hr)) + WARN("UiaGetRuntimeId failed with hr %#lx\n", hr); + } + IWineUiaNode_Release(&node_data->IWineUiaNode_iface); + IWineUiaEvent_Release(&event->IWineUiaEvent_iface); + + return S_OK; +} + +static HRESULT uia_raise_event(IRawElementProviderSimple *elprov, struct UiaEventArgs *args) +{ + struct uia_client_event_data_map_entry *event_data; + enum ProviderOptions prov_opts; + struct list *cursor, *cursor2; + HUIANODE node; + SAFEARRAY *sa; + HRESULT hr; + + hr = IRawElementProviderSimple_get_ProviderOptions(elprov, &prov_opts); + if (FAILED(hr)) + return hr; + + hr = uia_get_event_data_for_event(&event_data, args->EventId, FALSE); + if (FAILED(hr) || !event_data) + return hr; + + /* Events raised on client-side providers stay in process. */ + if ((prov_opts & ProviderOptions_ClientSideProvider) && list_empty(&event_data->local_events_list)) + return hr; + + if (prov_opts & ProviderOptions_ServerSideProvider) + hr = create_uia_node_from_elprov(elprov, &node, FALSE); + else + hr = create_uia_node_from_elprov(elprov, &node, TRUE); + if (FAILED(hr)) + return hr; + + hr = UiaGetRuntimeId(node, &sa); + if (FAILED(hr)) + { + UiaNodeRelease(node); + return hr; + } + + LIST_FOR_EACH_SAFE(cursor, cursor2, &event_data->local_events_list) + { + struct uia_event *event = LIST_ENTRY(cursor, struct uia_event, event_list_entry); + + hr = uia_process_event(node, args, sa, event); + if (FAILED(hr)) + WARN("uia_process_event failed with hr %#lx\n", hr); + } + + SafeArrayDestroy(sa); + UiaNodeRelease(node); + + return hr; +} + +/*********************************************************************** + * UiaRaiseAutomationEvent (uiautomationcore.@) + */ +HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *elprov, EVENTID id) +{ + const struct uia_event_info *event_info = uia_event_info_from_id(id); + struct UiaEventArgs args = { EventArgsType_Simple, id }; + HRESULT hr; + + TRACE("(%p, %d)\n", elprov, id); + + if (!event_info || event_info->event_arg_type != EventArgsType_Simple) + return E_INVALIDARG; + + hr = uia_raise_event(elprov, &args); + if (FAILED(hr)) + return hr; + + return S_OK; +} diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 8ce36f8fd76..2f257c36e98 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -298,15 +298,6 @@ HRESULT WINAPI UiaGetReservedNotSupportedValue(IUnknown **value) return S_OK; } -/*********************************************************************** - * UiaRaiseAutomationEvent (uiautomationcore.@) - */ -HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *provider, EVENTID id) -{ - FIXME("(%p, %d): stub\n", provider, id); - return S_OK; -} - /*********************************************************************** * UiaRaiseAutomationPropertyChangedEvent (uiautomationcore.@) */ From 02c9386ed1a93a020be464c7259b0ab51682af39 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 25 Jan 2023 12:03:07 -0500 Subject: [PATCH 0784/2777] uiautomationcore: Add support for advising providers of events being added/removed. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 26 +-- dlls/uiautomationcore/uia_classes.idl | 11 + dlls/uiautomationcore/uia_client.c | 221 +++++++++++++++++++++ 3 files changed, 245 insertions(+), 13 deletions(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 8ce2c07d931..14c0ba5bf13 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10031,10 +10031,10 @@ static const struct prov_method_sequence event_seq1[] = { static const struct prov_method_sequence event_seq2[] = { { &Provider, FRAG_GET_RUNTIME_ID }, { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ - { &Provider, FRAG_GET_FRAGMENT_ROOT, METHOD_TODO }, + { &Provider, FRAG_GET_FRAGMENT_ROOT }, { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win8+. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ - { &Provider, ADVISE_EVENTS_EVENT_ADDED, METHOD_TODO }, + { &Provider, ADVISE_EVENTS_EVENT_ADDED }, { 0 }, }; @@ -10047,7 +10047,7 @@ static const struct prov_method_sequence event_seq3[] = { }; static const struct prov_method_sequence event_seq4[] = { - { &Provider, ADVISE_EVENTS_EVENT_REMOVED, METHOD_TODO }, + { &Provider, ADVISE_EVENTS_EVENT_REMOVED }, { 0 }, }; @@ -10063,11 +10063,11 @@ static const struct prov_method_sequence event_seq5[] = { static const struct prov_method_sequence event_seq6[] = { { &Provider, FRAG_GET_RUNTIME_ID }, { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ - { &Provider, FRAG_GET_FRAGMENT_ROOT, METHOD_TODO }, + { &Provider, FRAG_GET_FRAGMENT_ROOT }, { &Provider, FRAG_GET_EMBEDDED_FRAGMENT_ROOTS, METHOD_TODO }, { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win8+. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ - { &Provider, ADVISE_EVENTS_EVENT_ADDED, METHOD_TODO }, + { &Provider, ADVISE_EVENTS_EVENT_ADDED }, { 0 }, }; @@ -10122,16 +10122,16 @@ static const struct prov_method_sequence event_seq10[] = { static const struct prov_method_sequence event_seq11[] = { { &Provider, FRAG_GET_RUNTIME_ID }, { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ - { &Provider, FRAG_GET_FRAGMENT_ROOT, METHOD_TODO }, + { &Provider, FRAG_GET_FRAGMENT_ROOT }, { &Provider, FRAG_GET_EMBEDDED_FRAGMENT_ROOTS, METHOD_TODO }, { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win8+. */ { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ - { &Provider2, ADVISE_EVENTS_EVENT_ADDED, METHOD_TODO }, + { &Provider2, ADVISE_EVENTS_EVENT_ADDED }, { 0 }, }; static const struct prov_method_sequence event_seq12[] = { - { &Provider2, ADVISE_EVENTS_EVENT_REMOVED, METHOD_TODO }, + { &Provider2, ADVISE_EVENTS_EVENT_REMOVED }, { 0 }, }; @@ -10231,7 +10231,7 @@ static void test_UiaAddEvent(void) (struct UiaCacheRequest *)&DefaultCacheReq, &event); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!!event, "event == NULL\n"); - todo_wine ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); + ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); ok_method_sequence(event_seq2, "event_seq2"); /* @@ -10259,7 +10259,7 @@ static void test_UiaAddEvent(void) (struct UiaCacheRequest *)&DefaultCacheReq, &event); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!!event, "event == NULL\n"); - todo_wine ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); + ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); ok_method_sequence(event_seq2, "event_seq2"); /* Event handler is called since we can match our providers by runtime ID. */ @@ -10287,7 +10287,7 @@ static void test_UiaAddEvent(void) (struct UiaCacheRequest *)&DefaultCacheReq, &event); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!!event, "event == NULL\n"); - todo_wine ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); + ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); ok_method_sequence(event_seq6, "event_seq6"); /* @@ -10322,7 +10322,7 @@ static void test_UiaAddEvent(void) (struct UiaCacheRequest *)&DefaultCacheReq, &event); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!!event, "event == NULL\n"); - todo_wine ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); + ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); ok_method_sequence(event_seq6, "event_seq6"); /* Raised an event on Provider_child_child. */ @@ -10357,7 +10357,7 @@ static void test_UiaAddEvent(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!!event, "event == NULL\n"); ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); - todo_wine ok(Provider2.ref > 1, "Unexpected refcnt %ld\n", Provider2.ref); + ok(Provider2.ref > 1, "Unexpected refcnt %ld\n", Provider2.ref); ok_method_sequence(event_seq11, "event_seq11"); thread_data.exp_thread_id = GetCurrentThreadId(); diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index 3f43e2c70ec..d52daa558de 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -58,6 +58,16 @@ library UIA_wine_private { } + [ + object, + uuid(9a754e12-e570-49ab-b223-6f6871007d28), + pointer_default(unique), + ] + interface IWineUiaAdviseEvents : IUnknown + { + HRESULT advise_events([in]BOOL advise_removed, [in]long event_id, [in]SAFEARRAY *prop_ids); + } + [ object, uuid(57865755-6c05-4522-98df-4ca658b768ef), @@ -70,6 +80,7 @@ library UIA_wine_private HRESULT get_prov_opts([out, retval]int *out_opts); HRESULT has_parent([out, retval]BOOL *out_val); HRESULT navigate([in]int nav_dir, [out, retval]VARIANT *ret_val); + HRESULT attach_event([in]LONG_PTR huiaevent); } [ diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index affd30dca68..c1928c61e05 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -36,6 +36,10 @@ struct uia_event int event_id; int scope; + IWineUiaAdviseEvents **adv_events_ifaces; + int adv_events_ifaces_count; + SIZE_T adv_events_ifaces_arr_size; + struct list event_list_entry; struct uia_client_event_data_map_entry *event_data; int event_type; @@ -166,6 +170,9 @@ static ULONG WINAPI uia_event_Release(IWineUiaEvent *iface) TRACE("%p, refcount %ld\n", event, ref); if (!ref) { + HRESULT hr; + int i; + if (event->event_data) { list_remove(&event->event_list_entry); @@ -177,6 +184,17 @@ static ULONG WINAPI uia_event_Release(IWineUiaEvent *iface) } } + for (i = 0; i < event->adv_events_ifaces_count; i++) + { + hr = IWineUiaAdviseEvents_advise_events(event->adv_events_ifaces[i], TRUE, event->event_id, NULL); + if (FAILED(hr)) + WARN("advise_events failed with hr %#lx\n", hr); + IWineUiaAdviseEvents_Release(event->adv_events_ifaces[i]); + } + + if (event->adv_events_ifaces) + heap_free(event->adv_events_ifaces); + SafeArrayDestroy(event->runtime_id); heap_free(event); } @@ -221,6 +239,101 @@ static struct uia_event *create_uia_event(int event_id, int scope, struct UiaCac return event; } +/* + * IWineUiaAdviseEvents interface. + */ +struct uia_advise_events { + IWineUiaAdviseEvents IWineUiaAdviseEvents_iface; + LONG ref; + + IRawElementProviderAdviseEvents *advise_events; +}; + +static inline struct uia_advise_events *impl_from_IWineUiaAdviseEvents(IWineUiaAdviseEvents *iface) +{ + return CONTAINING_RECORD(iface, struct uia_advise_events, IWineUiaAdviseEvents_iface); +} + +static HRESULT WINAPI uia_advise_events_QueryInterface(IWineUiaAdviseEvents *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IWineUiaAdviseEvents) || IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else + return E_NOINTERFACE; + + IWineUiaAdviseEvents_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI uia_advise_events_AddRef(IWineUiaAdviseEvents *iface) +{ + struct uia_advise_events *adv_events = impl_from_IWineUiaAdviseEvents(iface); + ULONG ref = InterlockedIncrement(&adv_events->ref); + + TRACE("%p, refcount %ld\n", adv_events, ref); + return ref; +} + +static ULONG WINAPI uia_advise_events_Release(IWineUiaAdviseEvents *iface) +{ + struct uia_advise_events *adv_events = impl_from_IWineUiaAdviseEvents(iface); + ULONG ref = InterlockedDecrement(&adv_events->ref); + + TRACE("%p, refcount %ld\n", adv_events, ref); + if (!ref) + { + IRawElementProviderAdviseEvents_Release(adv_events->advise_events); + heap_free(adv_events); + } + + return ref; +} + +static HRESULT WINAPI uia_advise_events_advise_events(IWineUiaAdviseEvents *iface, BOOL advise_removed, + long event_id, SAFEARRAY *prop_ids) +{ + struct uia_advise_events *adv_events = impl_from_IWineUiaAdviseEvents(iface); + HRESULT hr; + + TRACE("%p, %d, %p\n", adv_events, advise_removed, prop_ids); + + if (advise_removed) + hr = IRawElementProviderAdviseEvents_AdviseEventRemoved(adv_events->advise_events, event_id, prop_ids); + else + hr = IRawElementProviderAdviseEvents_AdviseEventAdded(adv_events->advise_events, event_id, prop_ids); + if (FAILED(hr)) + WARN("AdviseEvents failed with hr %#lx\n", hr); + + return S_OK; +} + +static const IWineUiaAdviseEventsVtbl uia_advise_events_vtbl = { + uia_advise_events_QueryInterface, + uia_advise_events_AddRef, + uia_advise_events_Release, + uia_advise_events_advise_events, +}; + +static HRESULT create_wine_uia_advise_events(IRawElementProviderAdviseEvents *advise_events, + IWineUiaAdviseEvents **out_events) +{ + struct uia_advise_events *adv_events; + + *out_events = NULL; + + if (!(adv_events = heap_alloc_zero(sizeof(*adv_events)))) + return E_OUTOFMEMORY; + + adv_events->IWineUiaAdviseEvents_iface.lpVtbl = &uia_advise_events_vtbl; + adv_events->ref = 1; + adv_events->advise_events = advise_events; + *out_events = &adv_events->IWineUiaAdviseEvents_iface; + + IRawElementProviderAdviseEvents_AddRef(advise_events); + return S_OK; +} + struct uia_node_array { HUIANODE *nodes; int node_count; @@ -626,6 +739,21 @@ static HRESULT get_navigate_from_node_provider(IWineUiaNode *node, int idx, int return hr; } +static HRESULT attach_event_to_node_provider(IWineUiaNode *node, int idx, HUIAEVENT event) +{ + IWineUiaProvider *prov; + HRESULT hr; + + hr = IWineUiaNode_get_provider(node, idx, &prov); + if (FAILED(hr)) + return hr; + + hr = IWineUiaProvider_attach_event(prov, (LONG_PTR)event); + IWineUiaProvider_Release(prov); + + return hr; +} + /* * IWineUiaNode interface. */ @@ -1301,6 +1429,29 @@ static HRESULT traverse_uia_node_tree(HUIANODE huianode, struct UiaCondition *vi return hr; } +static HRESULT attach_event_to_uia_node(struct uia_event *event, HUIANODE node) +{ + struct uia_node *node_data = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)node); + HRESULT hr = S_OK; + int i; + + for (i = 0; i < node_data->prov_count; i++) + { + hr = attach_event_to_node_provider(&node_data->IWineUiaNode_iface, i, (HUIAEVENT)event); + if (FAILED(hr)) + WARN("attach_event_to_node_provider failed with hr %#lx\n", hr); + } + + for (i = 0; i < event->adv_events_ifaces_count; i++) + { + hr = IWineUiaAdviseEvents_advise_events(event->adv_events_ifaces[i], FALSE, event->event_id, NULL); + if (FAILED(hr)) + WARN("advise_events failed with hr %#lx\n", hr); + } + + return hr; +} + /* * IWineUiaProvider interface. */ @@ -1706,6 +1857,64 @@ static HRESULT WINAPI uia_provider_navigate(IWineUiaProvider *iface, int nav_dir return S_OK; } +static HRESULT WINAPI uia_provider_attach_event(IWineUiaProvider *iface, LONG_PTR huiaevent) +{ + struct uia_event *event = unsafe_impl_from_IWineUiaEvent((IWineUiaEvent *)huiaevent); + struct uia_provider *prov = impl_from_IWineUiaProvider(iface); + IRawElementProviderFragmentRoot *elroot; + IWineUiaAdviseEvents *adv_event = NULL; + IRawElementProviderFragment *elfrag; + HRESULT hr; + + TRACE("%p, %#Ix\n", iface, huiaevent); + + if (!event) + { + WARN("Failed to get event structure\n"); + return E_FAIL; + } + + hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderFragment, (void **)&elfrag); + if (FAILED(hr) || !elfrag) + return S_OK; + + hr = IRawElementProviderFragment_get_FragmentRoot(elfrag, &elroot); + IRawElementProviderFragment_Release(elfrag); + if (FAILED(hr) || !elroot) + return S_OK; + + if (elroot) + { + IRawElementProviderAdviseEvents *advise_events; + + hr = IRawElementProviderFragmentRoot_QueryInterface(elroot, &IID_IRawElementProviderAdviseEvents, + (void **)&advise_events); + IRawElementProviderFragmentRoot_Release(elroot); + if (SUCCEEDED(hr) && advise_events) + { + hr = create_wine_uia_advise_events(advise_events, &adv_event); + if (FAILED(hr)) + { + WARN("create_wine_uia_advise_events failed with hr %#lx\n", hr); + adv_event = NULL; + } + + IRawElementProviderAdviseEvents_Release(advise_events); + } + } + + if (adv_event) + { + if (!uia_array_reserve((void **)&event->adv_events_ifaces, &event->adv_events_ifaces_arr_size, + event->adv_events_ifaces_count + 1, sizeof(*event->adv_events_ifaces))) + return E_OUTOFMEMORY; + event->adv_events_ifaces[event->adv_events_ifaces_count] = adv_event; + event->adv_events_ifaces_count++; + } + + return S_OK; +} + static const IWineUiaProviderVtbl uia_provider_vtbl = { uia_provider_QueryInterface, uia_provider_AddRef, @@ -1714,6 +1923,7 @@ static const IWineUiaProviderVtbl uia_provider_vtbl = { uia_provider_get_prov_opts, uia_provider_has_parent, uia_provider_navigate, + uia_provider_attach_event, }; static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProviderSimple *elprov, @@ -2114,6 +2324,12 @@ static HRESULT WINAPI uia_nested_node_provider_navigate(IWineUiaProvider *iface, return S_OK; } +static HRESULT WINAPI uia_nested_node_provider_attach_event(IWineUiaProvider *iface, LONG_PTR huiaevent) +{ + FIXME("%p, %#Ix: stub\n", iface, huiaevent); + return E_NOTIMPL; +} + static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = { uia_nested_node_provider_QueryInterface, uia_nested_node_provider_AddRef, @@ -2122,6 +2338,7 @@ static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = { uia_nested_node_provider_get_prov_opts, uia_nested_node_provider_has_parent, uia_nested_node_provider_navigate, + uia_nested_node_provider_attach_event, }; static BOOL is_nested_node_provider(IWineUiaProvider *iface) @@ -3283,6 +3500,10 @@ HRESULT WINAPI UiaAddEvent(HUIANODE huianode, EVENTID event_id, UiaEventCallback return E_OUTOFMEMORY; } + hr = attach_event_to_uia_node(event, huianode); + if (FAILED(hr)) + WARN("attach_event_to_uia_node failed with hr %#lx\n", hr); + hr = uia_client_add_event(event); if (FAILED(hr)) { From fd46cb8d072ab14f97fa6dc1fede46f697245fe6 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 18 Jan 2023 13:58:16 -0500 Subject: [PATCH 0785/2777] uiautomationcore: Add global interface table helper functions. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_client.c | 128 ++++++++++++++++++----------- 1 file changed, 80 insertions(+), 48 deletions(-) diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index c1928c61e05..b3063e94fd8 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -25,6 +25,79 @@ WINE_DEFAULT_DEBUG_CHANNEL(uiautomation); static const struct UiaCondition UiaFalseCondition = { ConditionType_False }; +static HRESULT get_global_interface_table(IGlobalInterfaceTable **git) +{ + HRESULT hr; + + hr = CoCreateInstance(&CLSID_StdGlobalInterfaceTable, NULL, + CLSCTX_INPROC_SERVER, &IID_IGlobalInterfaceTable, (void **)git); + if (FAILED(hr)) + WARN("Failed to get GlobalInterfaceTable, hr %#lx\n", hr); + + return hr; +} + +static HRESULT register_interface_in_git(IUnknown *iface, REFIID riid, DWORD *ret_cookie) +{ + IGlobalInterfaceTable *git; + DWORD git_cookie; + HRESULT hr; + + *ret_cookie = 0; + hr = get_global_interface_table(&git); + if (FAILED(hr)) + return hr; + + hr = IGlobalInterfaceTable_RegisterInterfaceInGlobal(git, iface, riid, &git_cookie); + if (FAILED(hr)) + { + WARN("Failed to register interface in GlobalInterfaceTable, hr %#lx\n", hr); + return hr; + } + + *ret_cookie = git_cookie; + + return S_OK; +} + +static HRESULT unregister_interface_in_git(DWORD git_cookie) +{ + IGlobalInterfaceTable *git; + HRESULT hr; + + hr = get_global_interface_table(&git); + if (FAILED(hr)) + return hr; + + hr = IGlobalInterfaceTable_RevokeInterfaceFromGlobal(git, git_cookie); + if (FAILED(hr)) + WARN("Failed to revoke interface from GlobalInterfaceTable, hr %#lx\n", hr); + + return hr; +} + +static HRESULT get_interface_in_git(REFIID riid, DWORD git_cookie, IUnknown **ret_iface) +{ + IGlobalInterfaceTable *git; + IUnknown *iface; + HRESULT hr; + + hr = get_global_interface_table(&git); + if (FAILED(hr)) + return hr; + + hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(git, git_cookie, riid, (void **)&iface); + if (FAILED(hr)) + { + ERR("Failed to get interface from Global Interface Table, hr %#lx\n", hr); + return hr; + } + + *ret_iface = iface; + + return S_OK; +} + #define EVENT_TYPE_LOCAL 0 struct uia_event { @@ -566,18 +639,6 @@ static void uia_node_ptr_to_unk_safearray(VARIANT *in) } } -static HRESULT get_global_interface_table(IGlobalInterfaceTable **git) -{ - HRESULT hr; - - hr = CoCreateInstance(&CLSID_StdGlobalInterfaceTable, NULL, - CLSCTX_INPROC_SERVER, &IID_IGlobalInterfaceTable, (void **)git); - if (FAILED(hr)) - WARN("Failed to get GlobalInterfaceTable, hr %#lx\n", hr); - - return hr; -} - static HWND get_hwnd_from_provider(IRawElementProviderSimple *elprov) { IRawElementProviderSimple *host_prov; @@ -792,16 +853,8 @@ static ULONG WINAPI uia_node_Release(IWineUiaNode *iface) { if (node->git_cookie[i]) { - IGlobalInterfaceTable *git; - HRESULT hr; - - hr = get_global_interface_table(&git); - if (SUCCEEDED(hr)) - { - hr = IGlobalInterfaceTable_RevokeInterfaceFromGlobal(git, node->git_cookie[i]); - if (FAILED(hr)) - WARN("Failed to get revoke provider interface from Global Interface Table, hr %#lx\n", hr); - } + if (FAILED(unregister_interface_in_git(node->git_cookie[i]))) + WARN("Failed to get revoke provider interface from GIT\n"); } if (node->prov[i]) @@ -836,21 +889,13 @@ static HRESULT WINAPI uia_node_get_provider(IWineUiaNode *iface, int idx, IWineU prov_type = get_node_provider_type_at_idx(node, idx); if (node->git_cookie[prov_type]) { - IGlobalInterfaceTable *git; IWineUiaProvider *prov; HRESULT hr; - hr = get_global_interface_table(&git); + hr = get_interface_in_git(&IID_IWineUiaProvider, node->git_cookie[prov_type], (IUnknown **)&prov); if (FAILED(hr)) return hr; - hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(git, node->git_cookie[prov_type], - &IID_IWineUiaProvider, (void **)&prov); - if (FAILED(hr)) - { - ERR("Failed to get provider interface from GlobalInterfaceTable, hr %#lx\n", hr); - return hr; - } *out_prov = prov; } else @@ -906,16 +951,8 @@ static HRESULT WINAPI uia_node_disconnect(IWineUiaNode *iface) prov_type = get_node_provider_type_at_idx(node, 0); if (node->git_cookie[prov_type]) { - IGlobalInterfaceTable *git; - HRESULT hr; - - hr = get_global_interface_table(&git); - if (SUCCEEDED(hr)) - { - hr = IGlobalInterfaceTable_RevokeInterfaceFromGlobal(git, node->git_cookie[prov_type]); - if (FAILED(hr)) - WARN("Failed to get revoke provider interface from Global Interface Table, hr %#lx\n", hr); - } + if (FAILED(unregister_interface_in_git(node->git_cookie[prov_type]))) + WARN("Failed to get revoke provider interface from GIT\n"); node->git_cookie[prov_type] = 0; } @@ -1003,7 +1040,6 @@ static HRESULT prepare_uia_node(struct uia_node *node) for (i = 0; i < PROV_TYPE_COUNT; i++) { enum ProviderOptions prov_opts; - IGlobalInterfaceTable *git; struct uia_provider *prov; HRESULT hr; @@ -1024,12 +1060,8 @@ static HRESULT prepare_uia_node(struct uia_node *node) */ if (prov_opts & ProviderOptions_UseComThreading) { - hr = get_global_interface_table(&git); - if (FAILED(hr)) - return hr; - - hr = IGlobalInterfaceTable_RegisterInterfaceInGlobal(git, (IUnknown *)&prov->IWineUiaProvider_iface, - &IID_IWineUiaProvider, &node->git_cookie[i]); + hr = register_interface_in_git((IUnknown *)&prov->IWineUiaProvider_iface, &IID_IWineUiaProvider, + &node->git_cookie[i]); if (FAILED(hr)) return hr; } From c2654a83825ca6676664bd0fc8f39f955f526b2c Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 18 Jan 2023 14:35:08 -0500 Subject: [PATCH 0786/2777] uiautomationcore: Respect ProviderOptions_UseComThreading on advise events interfaces. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 2 +- dlls/uiautomationcore/uia_client.c | 54 +++++++++++++++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 14c0ba5bf13..a5eb15089e5 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10179,7 +10179,7 @@ static DWORD WINAPI uia_add_event_test_thread(LPVOID param) ok(Provider2.ref == 1, "Unexpected refcnt %ld\n", Provider2.ref); ok_method_sequence(event_seq12, "event_seq12"); - todo_wine ok(Provider2.last_call_tid == data->exp_thread_id || + ok(Provider2.last_call_tid == data->exp_thread_id || broken(Provider2.last_call_tid == GetCurrentThreadId()), "Expected method call on separate thread\n"); CoUninitialize(); diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index b3063e94fd8..6f97e1dd507 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -320,6 +320,7 @@ struct uia_advise_events { LONG ref; IRawElementProviderAdviseEvents *advise_events; + DWORD git_cookie; }; static inline struct uia_advise_events *impl_from_IWineUiaAdviseEvents(IWineUiaAdviseEvents *iface) @@ -356,6 +357,12 @@ static ULONG WINAPI uia_advise_events_Release(IWineUiaAdviseEvents *iface) TRACE("%p, refcount %ld\n", adv_events, ref); if (!ref) { + if (adv_events->git_cookie) + { + if (FAILED(unregister_interface_in_git(adv_events->git_cookie))) + WARN("Failed to revoke advise events interface from GIT\n"); + } + IRawElementProviderAdviseEvents_Release(adv_events->advise_events); heap_free(adv_events); } @@ -367,17 +374,33 @@ static HRESULT WINAPI uia_advise_events_advise_events(IWineUiaAdviseEvents *ifac long event_id, SAFEARRAY *prop_ids) { struct uia_advise_events *adv_events = impl_from_IWineUiaAdviseEvents(iface); + IRawElementProviderAdviseEvents *advise_events; HRESULT hr; TRACE("%p, %d, %p\n", adv_events, advise_removed, prop_ids); + if (adv_events->git_cookie) + { + hr = get_interface_in_git(&IID_IRawElementProviderAdviseEvents, adv_events->git_cookie, + (IUnknown **)&advise_events); + if (FAILED(hr)) + return hr; + } + else + { + advise_events = adv_events->advise_events; + IRawElementProviderAdviseEvents_AddRef(advise_events); + } + if (advise_removed) - hr = IRawElementProviderAdviseEvents_AdviseEventRemoved(adv_events->advise_events, event_id, prop_ids); + hr = IRawElementProviderAdviseEvents_AdviseEventRemoved(advise_events, event_id, prop_ids); else - hr = IRawElementProviderAdviseEvents_AdviseEventAdded(adv_events->advise_events, event_id, prop_ids); + hr = IRawElementProviderAdviseEvents_AdviseEventAdded(advise_events, event_id, prop_ids); if (FAILED(hr)) WARN("AdviseEvents failed with hr %#lx\n", hr); + IRawElementProviderAdviseEvents_Release(advise_events); + return S_OK; } @@ -392,12 +415,39 @@ static HRESULT create_wine_uia_advise_events(IRawElementProviderAdviseEvents *ad IWineUiaAdviseEvents **out_events) { struct uia_advise_events *adv_events; + IRawElementProviderSimple *elprov; + enum ProviderOptions prov_opts; + HRESULT hr; *out_events = NULL; + hr = IRawElementProviderAdviseEvents_QueryInterface(advise_events, &IID_IRawElementProviderSimple, + (void **)&elprov); + if (FAILED(hr) || !elprov) + { + ERR("Failed to get IRawElementProviderSimple from advise events\n"); + return E_FAIL; + } + + hr = IRawElementProviderSimple_get_ProviderOptions(elprov, &prov_opts); + IRawElementProviderSimple_Release(elprov); + if (FAILED(hr)) + prov_opts = 0; + if (!(adv_events = heap_alloc_zero(sizeof(*adv_events)))) return E_OUTOFMEMORY; + if (prov_opts & ProviderOptions_UseComThreading) + { + hr = register_interface_in_git((IUnknown *)advise_events, &IID_IRawElementProviderAdviseEvents, + &adv_events->git_cookie); + if (FAILED(hr)) + { + heap_free(adv_events); + return hr; + } + } + adv_events->IWineUiaAdviseEvents_iface.lpVtbl = &uia_advise_events_vtbl; adv_events->ref = 1; adv_events->advise_events = advise_events; From 4278865e5c036f95aca5a910a53cb8f3e6b53d75 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 25 Jan 2023 12:15:30 -0500 Subject: [PATCH 0787/2777] uiautomationcore: Add support for advising embedded fragment root providers of events being added/removed. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 80 +++++++++++++++++++++- dlls/uiautomationcore/uia_client.c | 66 +++++++++++++++--- 2 files changed, 136 insertions(+), 10 deletions(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index a5eb15089e5..a05483614f8 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -1137,6 +1137,8 @@ static struct Provider struct Provider_prop_override *prop_override; int prop_override_count; struct UiaRect bounds_rect; + IRawElementProviderFragmentRoot **embedded_frag_roots; + int embedded_frag_roots_count; } Provider, Provider2, Provider_child, Provider_child2; static struct Provider Provider_hwnd, Provider_nc, Provider_proxy, Provider_proxy2, Provider_override; static void initialize_provider(struct Provider *prov, int prov_opts, HWND hwnd, BOOL initialize_nav_links); @@ -1933,6 +1935,23 @@ static HRESULT WINAPI ProviderFragment_GetEmbeddedFragmentRoots(IRawElementProvi This->last_call_tid = GetCurrentThreadId(); *ret_val = NULL; + if (This->embedded_frag_roots && This->embedded_frag_roots_count) + { + SAFEARRAY *sa; + LONG idx; + + if (!(sa = SafeArrayCreateVector(VT_UNKNOWN, 0, This->embedded_frag_roots_count))) + return E_FAIL; + + for (idx = 0; idx < This->embedded_frag_roots_count; idx++) + SafeArrayPutElement(sa, &idx, (IUnknown *)This->embedded_frag_roots[idx]); + + if (This == &Provider_child) + This->embedded_frag_roots_count = 0; + + *ret_val = sa; + } + return S_OK; } @@ -8712,6 +8731,8 @@ static void initialize_provider(struct Provider *prov, int prov_opts, HWND hwnd, prov->prop_override = NULL; prov->prop_override_count = 0; memset(&prov->bounds_rect, 0, sizeof(prov->bounds_rect)); + prov->embedded_frag_roots = NULL; + prov->embedded_frag_roots_count = 0; if (initialize_nav_links) { prov->frag_root = NULL; @@ -10064,7 +10085,7 @@ static const struct prov_method_sequence event_seq6[] = { { &Provider, FRAG_GET_RUNTIME_ID }, { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ { &Provider, FRAG_GET_FRAGMENT_ROOT }, - { &Provider, FRAG_GET_EMBEDDED_FRAGMENT_ROOTS, METHOD_TODO }, + { &Provider, FRAG_GET_EMBEDDED_FRAGMENT_ROOTS }, { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win8+. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ { &Provider, ADVISE_EVENTS_EVENT_ADDED }, @@ -10123,7 +10144,7 @@ static const struct prov_method_sequence event_seq11[] = { { &Provider, FRAG_GET_RUNTIME_ID }, { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ { &Provider, FRAG_GET_FRAGMENT_ROOT }, - { &Provider, FRAG_GET_EMBEDDED_FRAGMENT_ROOTS, METHOD_TODO }, + { &Provider, FRAG_GET_EMBEDDED_FRAGMENT_ROOTS }, { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win8+. */ { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ { &Provider2, ADVISE_EVENTS_EVENT_ADDED }, @@ -10135,6 +10156,36 @@ static const struct prov_method_sequence event_seq12[] = { { 0 }, }; +static const struct prov_method_sequence event_seq13[] = { + { &Provider, FRAG_GET_RUNTIME_ID }, + { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ + { &Provider, FRAG_GET_FRAGMENT_ROOT }, + { &Provider, FRAG_GET_EMBEDDED_FRAGMENT_ROOTS }, + { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win8+. */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ + NODE_CREATE_SEQ3(&Provider_child), + { &Provider_child, FRAG_GET_FRAGMENT_ROOT }, + { &Provider_child, FRAG_GET_EMBEDDED_FRAGMENT_ROOTS }, + { &Provider_child, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win8+. */ + { &Provider_child, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ + NODE_CREATE_SEQ3(&Provider_child2), + { &Provider_child2, FRAG_GET_FRAGMENT_ROOT }, + { &Provider_child2, FRAG_GET_EMBEDDED_FRAGMENT_ROOTS }, + { &Provider_child2, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win8+. */ + { &Provider_child2, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ + { &Provider, ADVISE_EVENTS_EVENT_ADDED }, + { &Provider_child, ADVISE_EVENTS_EVENT_ADDED }, + { &Provider_child2, ADVISE_EVENTS_EVENT_ADDED }, + { 0 }, +}; + +static const struct prov_method_sequence event_seq14[] = { + { &Provider, ADVISE_EVENTS_EVENT_REMOVED }, + { &Provider_child, ADVISE_EVENTS_EVENT_REMOVED }, + { &Provider_child2, ADVISE_EVENTS_EVENT_REMOVED }, + { 0 }, +}; + static const struct UiaCacheRequest DefaultCacheReq = { (struct UiaCondition *)&UiaTrueCondition, TreeScope_Element, @@ -10188,6 +10239,8 @@ static DWORD WINAPI uia_add_event_test_thread(LPVOID param) static void test_UiaAddEvent(void) { + IRawElementProviderFragmentRoot *embedded_roots[2] = { &Provider_child.IRawElementProviderFragmentRoot_iface, + &Provider_child2.IRawElementProviderFragmentRoot_iface }; struct event_test_thread_data thread_data = { 0 }; HUIAEVENT event; HUIANODE node; @@ -10375,6 +10428,29 @@ static void test_UiaAddEvent(void) } CloseHandle(thread); + /* Test retrieving AdviseEvents on embedded fragment roots. */ + Provider.frag_root = &Provider.IRawElementProviderFragmentRoot_iface; + Provider.embedded_frag_roots = embedded_roots; + Provider.embedded_frag_roots_count = ARRAY_SIZE(embedded_roots); + Provider_child.frag_root = &Provider_child.IRawElementProviderFragmentRoot_iface; + Provider_child2.frag_root = &Provider_child2.IRawElementProviderFragmentRoot_iface; + + hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback, TreeScope_Element | TreeScope_Descendants, NULL, 0, + (struct UiaCacheRequest *)&DefaultCacheReq, &event); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!event, "event == NULL\n"); + ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); + ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_child.ref); + ok(Provider_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_child2.ref); + ok_method_sequence(event_seq13, "event_seq13"); + + hr = UiaRemoveEvent(event); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + ok(Provider_child.ref == 1, "Unexpected refcnt %ld\n", Provider_child.ref); + ok(Provider_child2.ref == 1, "Unexpected refcnt %ld\n", Provider_child2.ref); + ok_method_sequence(event_seq14, "event_seq14"); + UiaNodeRelease(node); ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref); diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 6f97e1dd507..83e29508544 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -1511,12 +1511,13 @@ static HRESULT traverse_uia_node_tree(HUIANODE huianode, struct UiaCondition *vi return hr; } -static HRESULT attach_event_to_uia_node(struct uia_event *event, HUIANODE node) +static HRESULT attach_event_to_uia_node(struct uia_event *event, HUIANODE node, BOOL advise_events) { struct uia_node *node_data = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)node); HRESULT hr = S_OK; - int i; + int i, prev_count; + prev_count = event->adv_events_ifaces_count; for (i = 0; i < node_data->prov_count; i++) { hr = attach_event_to_node_provider(&node_data->IWineUiaNode_iface, i, (HUIAEVENT)event); @@ -1524,11 +1525,14 @@ static HRESULT attach_event_to_uia_node(struct uia_event *event, HUIANODE node) WARN("attach_event_to_node_provider failed with hr %#lx\n", hr); } - for (i = 0; i < event->adv_events_ifaces_count; i++) + if (prev_count != event->adv_events_ifaces_count && advise_events) { - hr = IWineUiaAdviseEvents_advise_events(event->adv_events_ifaces[i], FALSE, event->event_id, NULL); - if (FAILED(hr)) - WARN("advise_events failed with hr %#lx\n", hr); + for (i = prev_count; i < event->adv_events_ifaces_count; i++) + { + hr = IWineUiaAdviseEvents_advise_events(event->adv_events_ifaces[i], FALSE, event->event_id, NULL); + if (FAILED(hr)) + WARN("advise_events failed with hr %#lx\n", hr); + } } return hr; @@ -1946,6 +1950,8 @@ static HRESULT WINAPI uia_provider_attach_event(IWineUiaProvider *iface, LONG_PT IRawElementProviderFragmentRoot *elroot; IWineUiaAdviseEvents *adv_event = NULL; IRawElementProviderFragment *elfrag; + SAFEARRAY *embedded_roots = NULL; + LONG i, idx, lbound, elems; HRESULT hr; TRACE("%p, %#Ix\n", iface, huiaevent); @@ -1961,10 +1967,22 @@ static HRESULT WINAPI uia_provider_attach_event(IWineUiaProvider *iface, LONG_PT return S_OK; hr = IRawElementProviderFragment_get_FragmentRoot(elfrag, &elroot); - IRawElementProviderFragment_Release(elfrag); if (FAILED(hr) || !elroot) return S_OK; + /* + * For now, we only support embedded fragment roots on providers that + * don't represent a nested node. + */ + if (event->scope & (TreeScope_Descendants | TreeScope_Children) && !prov->return_nested_node) + { + hr = IRawElementProviderFragment_GetEmbeddedFragmentRoots(elfrag, &embedded_roots); + if (FAILED(hr)) + WARN("GetEmbeddedFragmentRoots failed with hr %#lx\n", hr); + } + + IRawElementProviderFragment_Release(elfrag); + if (elroot) { IRawElementProviderAdviseEvents *advise_events; @@ -1994,6 +2012,38 @@ static HRESULT WINAPI uia_provider_attach_event(IWineUiaProvider *iface, LONG_PT event->adv_events_ifaces_count++; } + if (embedded_roots && SUCCEEDED(get_safearray_bounds(embedded_roots, &lbound, &elems))) + { + HUIANODE node; + + for (i = 0; i < elems; i++) + { + IRawElementProviderSimple *elprov; + IUnknown *unk; + + idx = lbound + i; + hr = SafeArrayGetElement(embedded_roots, &idx, &unk); + if (FAILED(hr)) + break; + + hr = IUnknown_QueryInterface(unk, &IID_IRawElementProviderSimple, (void **)&elprov); + IUnknown_Release(unk); + if (FAILED(hr)) + break; + + hr = create_uia_node_from_elprov(elprov, &node, !prov->return_nested_node); + IRawElementProviderSimple_Release(elprov); + if (SUCCEEDED(hr) && node) + { + hr = attach_event_to_uia_node(event, node, FALSE); + if (FAILED(hr)) + WARN("attach_event_to_uia_node failed with hr %#lx\n", hr); + UiaNodeRelease(node); + } + } + } + SafeArrayDestroy(embedded_roots); + return S_OK; } @@ -3582,7 +3632,7 @@ HRESULT WINAPI UiaAddEvent(HUIANODE huianode, EVENTID event_id, UiaEventCallback return E_OUTOFMEMORY; } - hr = attach_event_to_uia_node(event, huianode); + hr = attach_event_to_uia_node(event, huianode, TRUE); if (FAILED(hr)) WARN("attach_event_to_uia_node failed with hr %#lx\n", hr); From 958a4514101a5f73a40d8a026470928736d7e3ae Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 25 Jan 2023 12:20:30 -0500 Subject: [PATCH 0788/2777] uiautomationcore/tests: Add tests for cross-process events. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/tests/uiautomation.c | 162 ++++++++++++++++++++- 1 file changed, 160 insertions(+), 2 deletions(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index a05483614f8..134c5c7b005 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10199,6 +10199,7 @@ static struct EventData { LONG exp_elems[2]; struct node_provider_desc exp_node_desc; const WCHAR *exp_tree_struct; + HANDLE event_handle; } EventData; static void WINAPI uia_event_callback(struct UiaEventArgs *args, SAFEARRAY *req_data, BSTR tree_struct) @@ -10210,11 +10211,79 @@ static void WINAPI uia_event_callback(struct UiaEventArgs *args, SAFEARRAY *req_ SafeArrayDestroy(req_data); SysFreeString(tree_struct); + if (EventData.event_handle) + SetEvent(EventData.event_handle); +} + +enum { + WM_UIA_TEST_RAISE_SERVERSIDE_EVENT = WM_USER, + WM_UIA_TEST_RAISE_CLIENTSIDE_EVENT, + WM_UIA_TEST_RAISE_SERVERSIDE_CHILD_EVENT, +}; + +static void test_UiaAddEvent_client_proc(void) +{ + HUIAEVENT event; + HUIANODE node; + HRESULT hr; + HWND hwnd; + VARIANT v; + DWORD pid; + + hwnd = FindWindowA("UiaAddEvent class", "Test window"); + + CoInitializeEx(NULL, COINIT_MULTITHREADED); + hr = UiaNodeFromHandle(hwnd, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = UiaGetPropertyValue(node, UIA_LabeledByPropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); + + node = NULL; + hr = UiaHUiaNodeFromVariant(&v, &node); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(!!node, "node == NULL\n"); + + GetWindowThreadProcessId(hwnd, &pid); + EventData.exp_elems[0] = EventData.exp_elems[1] = 1; + EventData.exp_tree_struct = L"P)"; + init_node_provider_desc(&EventData.exp_node_desc, pid, NULL); + add_provider_desc(&EventData.exp_node_desc, L"Main", L"Provider_child", TRUE); + EventData.event_handle = CreateEventW(NULL, FALSE, FALSE, NULL); + + hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback, TreeScope_Element | TreeScope_Descendants, NULL, 0, + (struct UiaCacheRequest *)&DefaultCacheReq, &event); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!event, "event == NULL\n"); + ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); + + SET_EXPECT(uia_event_callback); + PostMessageW(hwnd, WM_UIA_TEST_RAISE_SERVERSIDE_EVENT, 0, 0); + todo_wine ok(!WaitForSingleObject(EventData.event_handle, 500), "Wait for event_handle failed.\n"); + todo_wine CHECK_CALLED(uia_event_callback); + + EventData.exp_elems[0] = EventData.exp_elems[1] = 1; + EventData.exp_tree_struct = L"P)"; + init_node_provider_desc(&EventData.exp_node_desc, pid, NULL); + add_provider_desc(&EventData.exp_node_desc, L"Main", L"Provider_child_child", TRUE); + SET_EXPECT(uia_event_callback); + PostMessageW(hwnd, WM_UIA_TEST_RAISE_SERVERSIDE_CHILD_EVENT, 0, 0); + todo_wine ok(!WaitForSingleObject(EventData.event_handle, 500), "Wait for event_handle failed.\n"); + todo_wine CHECK_CALLED(uia_event_callback); + + PostMessageW(hwnd, WM_UIA_TEST_RAISE_CLIENTSIDE_EVENT, 0, 0); + hr = UiaRemoveEvent(event); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + CloseHandle(EventData.event_handle); + CoUninitialize(); } struct event_test_thread_data { HUIAEVENT event; DWORD exp_thread_id; + HWND hwnd; }; static DWORD WINAPI uia_add_event_test_thread(LPVOID param) @@ -10237,19 +10306,33 @@ static DWORD WINAPI uia_add_event_test_thread(LPVOID param) return 0; } -static void test_UiaAddEvent(void) +static void test_UiaAddEvent(const char *name) { IRawElementProviderFragmentRoot *embedded_roots[2] = { &Provider_child.IRawElementProviderFragmentRoot_iface, &Provider_child2.IRawElementProviderFragmentRoot_iface }; struct event_test_thread_data thread_data = { 0 }; + PROCESS_INFORMATION proc; + char cmdline[MAX_PATH]; + WNDCLASSA cls = { 0 }; + STARTUPINFOA startup; HUIAEVENT event; + DWORD exit_code; HUIANODE node; HANDLE thread; HRESULT hr; + HWND hwnd; VARIANT v; CoInitializeEx(NULL, COINIT_MULTITHREADED); + cls.lpfnWndProc = test_wnd_proc; + cls.hInstance = GetModuleHandleA(NULL); + cls.lpszClassName = "UiaAddEvent class"; + RegisterClassA(&cls); + + hwnd = CreateWindowA("UiaAddEvent class", "Test window", WS_OVERLAPPEDWINDOW, + 0, 0, 100, 100, NULL, NULL, NULL, NULL); + /* * Raise event without any registered event handlers. */ @@ -10415,6 +10498,7 @@ static void test_UiaAddEvent(void) thread_data.exp_thread_id = GetCurrentThreadId(); thread_data.event = event; + thread_data.hwnd = hwnd; thread = CreateThread(NULL, 0, uia_add_event_test_thread, (void *)&thread_data, 0, NULL); while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0) { @@ -10453,6 +10537,78 @@ static void test_UiaAddEvent(void) UiaNodeRelease(node); ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref); + CoUninitialize(); + + CoInitializeEx(NULL, COINIT_MULTITHREADED); + initialize_provider(&Provider, ProviderOptions_ServerSideProvider, hwnd, TRUE); + Provider.ignore_hwnd_prop = TRUE; + Provider.frag_root = &Provider.IRawElementProviderFragmentRoot_iface; + + initialize_provider(&Provider_child, ProviderOptions_ServerSideProvider, NULL, TRUE); + Provider_child.runtime_id[0] = 0xdeadbeef; + Provider_child.runtime_id[1] = 0x01; + + initialize_provider(&Provider_child_child, ProviderOptions_ServerSideProvider, NULL, TRUE); + provider_add_child(&Provider_child, &Provider_child_child); + Provider_child_child.runtime_id[0] = 0xdeadbeef; + Provider_child_child.runtime_id[1] = 0x02; + + prov_root = &Provider.IRawElementProviderSimple_iface; + sprintf(cmdline, "\"%s\" uiautomation UiaAddEvent_client_proc", name); + memset(&startup, 0, sizeof(startup)); + startup.cb = sizeof(startup); + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + /* Only sent on Win7. */ + SET_EXPECT(winproc_GETOBJECT_CLIENT); + CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &proc); + while (MsgWaitForMultipleObjects(1, &proc.hProcess, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0) + { + MSG msg; + while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) + { + switch (msg.message) + { + case WM_UIA_TEST_RAISE_SERVERSIDE_EVENT: + initialize_provider(&Provider_child, ProviderOptions_ServerSideProvider, NULL, TRUE); + Provider_child.runtime_id[0] = 0xdeadbeef; + Provider_child.runtime_id[1] = 0x01; + hr = UiaRaiseAutomationEvent(&Provider_child.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + break; + + case WM_UIA_TEST_RAISE_CLIENTSIDE_EVENT: + initialize_provider(&Provider_child, ProviderOptions_ClientSideProvider, NULL, TRUE); + Provider_child.runtime_id[0] = 0xdeadbeef; + Provider_child.runtime_id[1] = 0x01; + hr = UiaRaiseAutomationEvent(&Provider_child.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + break; + + case WM_UIA_TEST_RAISE_SERVERSIDE_CHILD_EVENT: + hr = UiaRaiseAutomationEvent(&Provider_child_child.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + break; + + default: + break; + } + + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + + GetExitCodeProcess(proc.hProcess, &exit_code); + if (exit_code > 255) + ok(0, "unhandled exception %08x in child process %04x\n", (UINT)exit_code, (UINT)GetProcessId(proc.hProcess)); + else if (exit_code) + ok(0, "%u failures in child process\n", (UINT)exit_code); + + flush_method_sequence(); + CloseHandle(proc.hProcess); + + DestroyWindow(hwnd); + UnregisterClassA("UiaAddEvent class", NULL); CoUninitialize(); } @@ -10506,6 +10662,8 @@ START_TEST(uiautomation) test_UiaNodeFromHandle_client_proc(); else if (!strcmp(argv[2], "UiaRegisterProviderCallback")) test_UiaRegisterProviderCallback(); + else if (!strcmp(argv[2], "UiaAddEvent_client_proc")) + test_UiaAddEvent_client_proc(); FreeLibrary(uia_dll); return; @@ -10525,7 +10683,7 @@ START_TEST(uiautomation) test_UiaFind(); test_default_proxy_providers(); test_CUIAutomation(); - test_UiaAddEvent(); + test_UiaAddEvent(argv[0]); if (uia_dll) { pUiaProviderFromIAccessible = (void *)GetProcAddress(uia_dll, "UiaProviderFromIAccessible"); From 6965394645871bbe4bc09b618394b30a4be532a8 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 23 Jan 2023 14:18:46 -0500 Subject: [PATCH 0789/2777] uiautomationcore: Add IWineUiaEvent::detach() method. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_classes.idl | 1 + dlls/uiautomationcore/uia_client.c | 32 +++++++++++++++++++-------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index d52daa558de..d8c9d18c826 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -56,6 +56,7 @@ library UIA_wine_private ] interface IWineUiaEvent : IUnknown { + HRESULT detach(); } [ diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 83e29508544..244edf3a644 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -243,9 +243,6 @@ static ULONG WINAPI uia_event_Release(IWineUiaEvent *iface) TRACE("%p, refcount %ld\n", event, ref); if (!ref) { - HRESULT hr; - int i; - if (event->event_data) { list_remove(&event->event_list_entry); @@ -257,6 +254,23 @@ static ULONG WINAPI uia_event_Release(IWineUiaEvent *iface) } } + SafeArrayDestroy(event->runtime_id); + heap_free(event); + } + + return ref; +} + +static HRESULT WINAPI uia_event_detach(IWineUiaEvent *iface) +{ + struct uia_event *event = impl_from_IWineUiaEvent(iface); + HRESULT hr; + int i; + + TRACE("%p\n", event); + + if (event->adv_events_ifaces && event->adv_events_ifaces_count) + { for (i = 0; i < event->adv_events_ifaces_count; i++) { hr = IWineUiaAdviseEvents_advise_events(event->adv_events_ifaces[i], TRUE, event->event_id, NULL); @@ -265,20 +279,19 @@ static ULONG WINAPI uia_event_Release(IWineUiaEvent *iface) IWineUiaAdviseEvents_Release(event->adv_events_ifaces[i]); } - if (event->adv_events_ifaces) - heap_free(event->adv_events_ifaces); - - SafeArrayDestroy(event->runtime_id); - heap_free(event); + heap_free(event->adv_events_ifaces); + event->adv_events_ifaces_count = 0; + event->adv_events_ifaces = NULL; } - return ref; + return S_OK; } static const IWineUiaEventVtbl uia_event_vtbl = { uia_event_QueryInterface, uia_event_AddRef, uia_event_Release, + uia_event_detach, }; static struct uia_event *unsafe_impl_from_IWineUiaEvent(IWineUiaEvent *iface) @@ -3660,6 +3673,7 @@ HRESULT WINAPI UiaRemoveEvent(HUIAEVENT huiaevent) if (!event) return E_INVALIDARG; + IWineUiaEvent_detach(&event->IWineUiaEvent_iface); IWineUiaEvent_Release(&event->IWineUiaEvent_iface); return S_OK; } From 6c8adad4c0d3d96ea1a13d6ea23270f7f417af5d Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 23 Jan 2023 15:40:42 -0500 Subject: [PATCH 0790/2777] uiautomationcore: Add support for attaching events to nested node providers. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_classes.idl | 4 + dlls/uiautomationcore/uia_client.c | 254 +++++++++++++++++++++++++- dlls/uiautomationcore/uia_private.h | 1 + dlls/uiautomationcore/uia_provider.c | 2 +- 4 files changed, 255 insertions(+), 6 deletions(-) diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index d8c9d18c826..58cc32db787 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -57,6 +57,8 @@ library UIA_wine_private interface IWineUiaEvent : IUnknown { HRESULT detach(); + HRESULT get_event_data([out, retval]GUID *event_guid, [out, retval]VARIANT *runtime_id, + [out, retval]long *scope); } [ @@ -96,5 +98,7 @@ library UIA_wine_private HRESULT get_prop_val([in]const GUID *prop_guid, [out, retval]VARIANT *ret_val); HRESULT disconnect(); HRESULT get_hwnd([out, retval]ULONG *out_hwnd); + HRESULT add_event([in]IWineUiaEvent *event_iface, [in]long proc_id, [in]long event_cookie, + [out, retval]IWineUiaEvent **ret_event); } } diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 244edf3a644..380c9c5c3eb 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -99,6 +99,7 @@ static HRESULT get_interface_in_git(REFIID riid, DWORD git_cookie, IUnknown **re } #define EVENT_TYPE_LOCAL 0 +#define EVENT_TYPE_REMOTE 1 struct uia_event { IWineUiaEvent IWineUiaEvent_iface; @@ -121,7 +122,18 @@ struct uia_event struct { struct UiaCacheRequest *cache_req; UiaEventCallback *cback; + DWORD git_cookie; + + /* Array of remote events attached to this local HUIAEVENT. */ + IWineUiaEvent **remote_events; + int remote_events_count; + SIZE_T remote_events_arr_size; } local; + struct { + struct rb_entry remote_event_entry; + IWineUiaEvent *event_iface; + LONG proc_id; + } remote; } u; }; @@ -132,14 +144,37 @@ static struct uia_client_events { struct rb_tree event_map; LONG event_count; + + /* + * We need an rb_tree entry to use as a way to lookup a remote event by + * process_id and event_cookie to avoid creating duplicate events. + */ + struct rb_tree remote_event_map; } client_events; +struct uia_event_identifier { + LONG event_cookie; + LONG proc_id; +}; + +static int uia_remote_event_identifier_compare(const void *key, const struct rb_entry *entry) +{ + struct uia_event *event = RB_ENTRY_VALUE(entry, struct uia_event, u.remote.remote_event_entry); + struct uia_event_identifier *event_id = (struct uia_event_identifier *)key; + + if (event_id->proc_id != event->u.remote.proc_id) + return (event_id->proc_id > event->u.remote.proc_id) - (event_id->proc_id < event->u.remote.proc_id); + else + return (event_id->event_cookie > event->event_cookie) - (event_id->event_cookie < event->event_cookie); +} + struct uia_client_event_data_map_entry { struct rb_entry entry; int event_id; struct list local_events_list; + struct list remote_events_list; }; static int uia_event_map_id_compare(const void *key, const struct rb_entry *entry) @@ -180,9 +215,13 @@ static HRESULT uia_get_event_data_for_event(struct uia_client_event_data_map_ent data->event_id = event_id; list_init(&data->local_events_list); + list_init(&data->remote_events_list); if (InterlockedIncrement(&client_events.event_count) == 1) + { rb_init(&client_events.event_map, uia_event_map_id_compare); + rb_init(&client_events.remote_event_map, uia_remote_event_identifier_compare); + } rb_put(&client_events.event_map, &event_id, &data->entry); *event_data = data; @@ -200,12 +239,34 @@ static HRESULT uia_client_add_event(struct uia_event *event) if (FAILED(hr)) return hr; - list_add_head(&event_data->local_events_list, &event->event_list_entry); + if (event->event_type == EVENT_TYPE_LOCAL) + list_add_head(&event_data->local_events_list, &event->event_list_entry); + else + { + struct uia_event_identifier event_identifier = { event->event_cookie, event->u.remote.proc_id }; + + list_add_head(&event_data->remote_events_list, &event->event_list_entry); + rb_put(&client_events.remote_event_map, &event_identifier, &event->u.remote.remote_event_entry); + } event->event_data = event_data; return S_OK; } +static struct uia_event *uia_client_find_remote_event(LONG event_cookie, LONG proc_id) +{ + struct uia_event_identifier event_identifier = { event_cookie, proc_id }; + struct rb_entry *rb_entry; + + if (!client_events.event_count) + return NULL; + + if ((rb_entry = rb_get(&client_events.remote_event_map, &event_identifier))) + return RB_ENTRY_VALUE(rb_entry, struct uia_event, u.remote.remote_event_entry); + + return NULL; +} + /* * IWineUiaEvent interface. */ @@ -246,7 +307,14 @@ static ULONG WINAPI uia_event_Release(IWineUiaEvent *iface) if (event->event_data) { list_remove(&event->event_list_entry); - if (list_empty(&event->event_data->local_events_list)) + + if (event->event_type == EVENT_TYPE_REMOTE) + { + rb_remove(&client_events.remote_event_map, &event->u.remote.remote_event_entry); + IWineUiaEvent_detach(iface); + } + + if (list_empty(&event->event_data->local_events_list) && list_empty(&event->event_data->remote_events_list)) { rb_remove(&client_events.event_map, &event->event_data->entry); heap_free(event->event_data); @@ -284,6 +352,54 @@ static HRESULT WINAPI uia_event_detach(IWineUiaEvent *iface) event->adv_events_ifaces = NULL; } + if ((event->event_type == EVENT_TYPE_LOCAL) && event->u.local.remote_events && event->u.local.remote_events_count) + { + for (i = 0; i < event->u.local.remote_events_count; i++) + { + hr = IWineUiaEvent_detach(event->u.local.remote_events[i]); + if (FAILED(hr)) + WARN("remote event detach failed with hr %#lx\n", hr); + IWineUiaEvent_Release(event->u.local.remote_events[i]); + } + + heap_free(event->u.local.remote_events); + event->u.local.remote_events = NULL; + event->u.local.remote_events_count = 0; + } + + if ((event->event_type == EVENT_TYPE_REMOTE) && event->u.remote.event_iface) + { + IWineUiaEvent_Release(event->u.remote.event_iface); + event->u.remote.event_iface = NULL; + uia_stop_provider_thread(); + } + + return S_OK; +} + +static HRESULT WINAPI uia_event_get_event_data(IWineUiaEvent *iface, GUID *event_guid, VARIANT *runtime_id, + long *scope) +{ + struct uia_event *event = impl_from_IWineUiaEvent(iface); + const struct uia_event_info *event_info; + HRESULT hr; + + TRACE("%p, %p, %p, %p\n", iface, event_guid, runtime_id, scope); + + event_info = uia_event_info_from_id(event->event_id); + memcpy(event_guid, event_info->guid, sizeof(*event_guid)); + *scope = event->scope; + + VariantInit(runtime_id); + if (event->runtime_id) + { + hr = SafeArrayCopy(event->runtime_id, &V_ARRAY(runtime_id)); + if (SUCCEEDED(hr)) + V_VT(runtime_id) = VT_I4 | VT_ARRAY; + else + WARN("SafeArrayCopy failed with hr %#lx\n", hr); + } + return S_OK; } @@ -292,6 +408,7 @@ static const IWineUiaEventVtbl uia_event_vtbl = { uia_event_AddRef, uia_event_Release, uia_event_detach, + uia_event_get_event_data, }; static struct uia_event *unsafe_impl_from_IWineUiaEvent(IWineUiaEvent *iface) @@ -325,6 +442,43 @@ static struct uia_event *create_uia_event(int event_id, int scope, struct UiaCac return event; } +static struct uia_event *create_remote_uia_event(IWineUiaEvent *event_iface, LONG event_cookie, LONG proc_id) +{ + struct uia_event *event = heap_alloc_zero(sizeof(*event)); + GUID event_guid = { 0 }; + VARIANT rt_id; + long scope; + HRESULT hr; + + if (!event) + return NULL; + + VariantInit(&rt_id); + IWineUiaEvent_AddRef(event_iface); + hr = IWineUiaEvent_get_event_data(event_iface, &event_guid, &rt_id, &scope); + if (FAILED(hr)) + { + WARN("get_event_data failed with hr %#lx\n", hr); + IWineUiaEvent_Release(event_iface); + heap_free(event); + return NULL; + } + + event->IWineUiaEvent_iface.lpVtbl = &uia_event_vtbl; + event->ref = 1; + event->event_cookie = event_cookie; + if (V_VT(&rt_id) == (VT_ARRAY | VT_I4)) + event->runtime_id = V_ARRAY(&rt_id); + event->event_id = UiaLookupId(AutomationIdentifierType_Event, &event_guid); + event->scope = scope; + + event->event_type = EVENT_TYPE_REMOTE; + event->u.remote.event_iface = event_iface; + event->u.remote.proc_id = proc_id; + + return event; +} + /* * IWineUiaAdviseEvents interface. */ @@ -1039,6 +1193,44 @@ static HRESULT WINAPI uia_node_get_hwnd(IWineUiaNode *iface, ULONG *out_hwnd) return S_OK; } +static HRESULT attach_event_to_uia_node(struct uia_event *event, HUIANODE node, BOOL advise_events); +static HRESULT WINAPI uia_node_add_event(IWineUiaNode *iface, IWineUiaEvent *event_iface, long proc_id, + long event_cookie, IWineUiaEvent **ret_event) +{ + struct uia_node *node = impl_from_IWineUiaNode(iface); + struct uia_event *remote_event; + HRESULT hr; + + TRACE("%p, %p, %#lx, %ld, %p\n", node, event_iface, proc_id, event_cookie, ret_event); + + *ret_event = NULL; + + remote_event = uia_client_find_remote_event(event_cookie, proc_id); + if (!remote_event) + { + remote_event = create_remote_uia_event(event_iface, event_cookie, proc_id); + if (!remote_event) + { + WARN("Failed to create remote event\n"); + return E_FAIL; + } + + hr = uia_client_add_event(remote_event); + if (FAILED(hr)) + { + WARN("Failed to add remote event, hr %#lx\n", hr); + return hr; + } + + uia_start_provider_thread(); + *ret_event = &remote_event->IWineUiaEvent_iface; + } + + attach_event_to_uia_node(remote_event, (HUIANODE)iface, TRUE); + + return S_OK; +} + static const IWineUiaNodeVtbl uia_node_vtbl = { uia_node_QueryInterface, uia_node_AddRef, @@ -1047,6 +1239,7 @@ static const IWineUiaNodeVtbl uia_node_vtbl = { uia_node_get_prop_val, uia_node_disconnect, uia_node_get_hwnd, + uia_node_add_event, }; static struct uia_node *unsafe_impl_from_IWineUiaNode(IWineUiaNode *iface) @@ -2471,8 +2664,41 @@ static HRESULT WINAPI uia_nested_node_provider_navigate(IWineUiaProvider *iface, static HRESULT WINAPI uia_nested_node_provider_attach_event(IWineUiaProvider *iface, LONG_PTR huiaevent) { - FIXME("%p, %#Ix: stub\n", iface, huiaevent); - return E_NOTIMPL; + struct uia_nested_node_provider *prov = impl_from_nested_node_IWineUiaProvider(iface); + struct uia_event *event = unsafe_impl_from_IWineUiaEvent((IWineUiaEvent *)huiaevent); + IWineUiaEvent *remote_event; + HRESULT hr; + + TRACE("%p, %#Ix\n", iface, huiaevent); + + hr = IWineUiaNode_add_event(prov->nested_node, &event->IWineUiaEvent_iface, GetCurrentProcessId(), + event->event_cookie, &remote_event); + if (FAILED(hr)) + WARN("add_event failed with hr %#lx\n", hr); + + if (remote_event) + { + if (!uia_array_reserve((void **)&event->u.local.remote_events, &event->u.local.remote_events_arr_size, + event->u.local.remote_events_count + 1, sizeof(*event->u.local.remote_events))) + return E_OUTOFMEMORY; + + if (!event->u.local.remote_events_count) + { + uia_start_client_thread(); + hr = register_interface_in_git((IUnknown *)&event->IWineUiaEvent_iface, &IID_IWineUiaEvent, + &event->u.local.git_cookie); + if (FAILED(hr)) + { + WARN("Failed to register event interface in git, hr %#lx\n", hr); + heap_free(event->u.local.remote_events); + return hr; + } + } + event->u.local.remote_events[event->u.local.remote_events_count] = remote_event; + event->u.local.remote_events_count++; + } + + return S_OK; } static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = { @@ -3673,7 +3899,25 @@ HRESULT WINAPI UiaRemoveEvent(HUIAEVENT huiaevent) if (!event) return E_INVALIDARG; - IWineUiaEvent_detach(&event->IWineUiaEvent_iface); + if (event->u.local.git_cookie) + { + IWineUiaEvent *event_iface; + HRESULT hr; + + hr = get_interface_in_git(&IID_IWineUiaEvent, event->u.local.git_cookie, (IUnknown **)&event_iface); + if (SUCCEEDED(hr)) + { + IWineUiaEvent_detach(event_iface); + IWineUiaEvent_Release(event_iface); + } + + unregister_interface_in_git(event->u.local.git_cookie); + event->u.local.git_cookie = 0; + uia_stop_client_thread(); + } + else + IWineUiaEvent_detach(&event->IWineUiaEvent_iface); + IWineUiaEvent_Release(&event->IWineUiaEvent_iface); return S_OK; } diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index a977f37bf2d..b8fb7b51d7c 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -137,6 +137,7 @@ const struct uia_event_info *uia_event_info_from_id(EVENTID event_id) DECLSPEC_H /* uia_provider.c */ void uia_stop_provider_thread(void) DECLSPEC_HIDDEN; +BOOL uia_start_provider_thread(void) DECLSPEC_HIDDEN; void uia_provider_thread_remove_node(HUIANODE node) DECLSPEC_HIDDEN; LRESULT uia_lresult_from_node(HUIANODE huianode) DECLSPEC_HIDDEN; HRESULT create_msaa_provider(IAccessible *acc, long child_id, HWND hwnd, BOOL known_root_acc, BOOL clientside_prov, diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index cd1d8934a55..74c1056e9d2 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -2235,7 +2235,7 @@ static DWORD WINAPI uia_provider_thread_proc(void *arg) FreeLibraryAndExitThread(huia_module, 0); } -static BOOL uia_start_provider_thread(void) +BOOL uia_start_provider_thread(void) { BOOL started = TRUE; From 25c6e9ec39f1b05d3d7acceacaa6006e134dfc35 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 24 Jan 2023 13:28:35 -0500 Subject: [PATCH 0791/2777] uiautomationcore: Introduce custom uia_event_args structure. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_client.c | 90 ++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 6 deletions(-) diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 380c9c5c3eb..b1d99bb0a6d 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -267,6 +267,77 @@ static struct uia_event *uia_client_find_remote_event(LONG event_cookie, LONG pr return NULL; } +struct uia_event_args +{ + LONG ref; + + union { + struct UiaEventArgs simple_args; + struct UiaPropertyChangedEventArgs prop_change_args; + struct UiaStructureChangedEventArgs struct_change_args; + struct UiaAsyncContentLoadedEventArgs async_loaded_args; + struct UiaWindowClosedEventArgs window_closed_args; + struct UiaTextEditTextChangedEventArgs text_edit_change_args; + struct UiaChangesEventArgs changes_args; + } u; +}; + +static struct uia_event_args *create_uia_event_args(const struct uia_event_info *event_info) +{ + struct uia_event_args *args = heap_alloc_zero(sizeof(*args)); + + if (!args) + return NULL; + + args->u.simple_args.Type = event_info->event_arg_type; + args->u.simple_args.EventId = event_info->event_id; + args->ref = 1; + + return args; +} + +static void uia_event_args_release(struct uia_event_args *args) +{ + if (!InterlockedDecrement(&args->ref)) + { + switch (args->u.simple_args.Type) + { + case EventArgsType_Simple: + break; + + case EventArgsType_PropertyChanged: + VariantClear(&args->u.prop_change_args.OldValue); + VariantClear(&args->u.prop_change_args.NewValue); + break; + + case EventArgsType_StructureChanged: + heap_free(args->u.struct_change_args.pRuntimeId); + break; + + case EventArgsType_AsyncContentLoaded: + break; + + case EventArgsType_WindowClosed: + heap_free(args->u.window_closed_args.pRuntimeId); + break; + + case EventArgsType_TextEditTextChanged: + SafeArrayDestroy(args->u.text_edit_change_args.pTextChange); + break; + + /* FIXME: Need to clear out each individual UiaChangeInfo struct. */ + case EventArgsType_Changes: + heap_free(args->u.changes_args.pUiaChanges); + break; + + default: + break; + } + + heap_free(args); + } +} + /* * IWineUiaEvent interface. */ @@ -3940,7 +4011,7 @@ HRESULT WINAPI UiaEventRemoveWindow(HUIAEVENT huiaevent, HWND hwnd) return E_NOTIMPL; } -static HRESULT uia_process_event(HUIANODE node, struct UiaEventArgs *args, SAFEARRAY *rt_id, +static HRESULT uia_process_event(HUIANODE node, struct uia_event_args *args, SAFEARRAY *rt_id, struct uia_event *event) { struct uia_node *node_data = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)node); @@ -3973,7 +4044,7 @@ static HRESULT uia_process_event(HUIANODE node, struct UiaEventArgs *args, SAFEA hr = UiaGetUpdatedCache(node, event->u.local.cache_req, NormalizeState_None, NULL, &out_req, &tree_struct); if (SUCCEEDED(hr)) - event->u.local.cback(args, out_req, tree_struct); + event->u.local.cback(&args->u.simple_args, out_req, tree_struct); } break; @@ -4002,7 +4073,7 @@ static HRESULT uia_process_event(HUIANODE node, struct UiaEventArgs *args, SAFEA return S_OK; } -static HRESULT uia_raise_event(IRawElementProviderSimple *elprov, struct UiaEventArgs *args) +static HRESULT uia_raise_event(IRawElementProviderSimple *elprov, struct uia_event_args *args) { struct uia_client_event_data_map_entry *event_data; enum ProviderOptions prov_opts; @@ -4015,7 +4086,7 @@ static HRESULT uia_raise_event(IRawElementProviderSimple *elprov, struct UiaEven if (FAILED(hr)) return hr; - hr = uia_get_event_data_for_event(&event_data, args->EventId, FALSE); + hr = uia_get_event_data_for_event(&event_data, args->u.simple_args.EventId, FALSE); if (FAILED(hr) || !event_data) return hr; @@ -4058,17 +4129,24 @@ static HRESULT uia_raise_event(IRawElementProviderSimple *elprov, struct UiaEven HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *elprov, EVENTID id) { const struct uia_event_info *event_info = uia_event_info_from_id(id); - struct UiaEventArgs args = { EventArgsType_Simple, id }; + struct uia_event_args *args; HRESULT hr; TRACE("(%p, %d)\n", elprov, id); + if (!event_info || event_info->event_arg_type != EventArgsType_Simple) return E_INVALIDARG; - hr = uia_raise_event(elprov, &args); + args = create_uia_event_args(event_info); + if (!args) + return E_OUTOFMEMORY; + + hr = uia_raise_event(elprov, args); if (FAILED(hr)) return hr; + uia_event_args_release(args); + return S_OK; } From 195f1f713c08c8760bafe3e67924c88cbd1a8a88 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 24 Jan 2023 13:51:17 -0500 Subject: [PATCH 0792/2777] uiautomationcore: Add raise_event method to IWineUiaEvent. When upstreaming, we'll need to change this. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_classes.idl | 1 + dlls/uiautomationcore/uia_client.c | 262 +++++++++++++++++++++++++- 2 files changed, 261 insertions(+), 2 deletions(-) diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index 58cc32db787..052b2022d2a 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -59,6 +59,7 @@ library UIA_wine_private HRESULT detach(); HRESULT get_event_data([out, retval]GUID *event_guid, [out, retval]VARIANT *runtime_id, [out, retval]long *scope); + HRESULT raise_event([in]VARIANT node, [in]BOOL needs_clientside); } [ diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index b1d99bb0a6d..802a43fb483 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -98,8 +98,6 @@ static HRESULT get_interface_in_git(REFIID riid, DWORD git_cookie, IUnknown **re return S_OK; } -#define EVENT_TYPE_LOCAL 0 -#define EVENT_TYPE_REMOTE 1 struct uia_event { IWineUiaEvent IWineUiaEvent_iface; @@ -114,6 +112,8 @@ struct uia_event int adv_events_ifaces_count; SIZE_T adv_events_ifaces_arr_size; + BOOL started_event_thread; + struct list event_list_entry; struct uia_client_event_data_map_entry *event_data; int event_type; @@ -338,6 +338,219 @@ static void uia_event_args_release(struct uia_event_args *args) } } +/* + * UI Automation event thread functions. + */ +struct uia_event_thread +{ + HANDLE hthread; + HWND hwnd; + LONG ref; + + struct list *event_queue; +}; + +static struct uia_event_thread event_thread; +static CRITICAL_SECTION event_thread_cs; +static CRITICAL_SECTION_DEBUG event_thread_cs_debug = +{ + 0, 0, &event_thread_cs, + { &event_thread_cs_debug.ProcessLocksList, &event_thread_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": event_thread_cs") } +}; +static CRITICAL_SECTION event_thread_cs = { &event_thread_cs_debug, -1, 0, 0, 0, 0 }; + +/* +EVENT_TYPE_LOCAL 0 +EVENT_TYPE_REMOTE 1 +*/ +struct uia_queue_event +{ + struct uia_event *event; + + VARIANT node; + BOOL needs_clientside; + struct uia_event_args *args; + + struct list event_queue_entry; +}; + +static HRESULT create_uia_queue_event(struct uia_event *event, VARIANT node, BOOL needs_clientside, + struct uia_event_args *args, struct uia_queue_event **out_queue_event) +{ + struct uia_queue_event *queue_event = heap_alloc_zero(sizeof(*queue_event)); + + *out_queue_event = NULL; + if (!queue_event) + return E_OUTOFMEMORY; + + IWineUiaEvent_AddRef(&event->IWineUiaEvent_iface); + queue_event->event = event; + queue_event->node = node; + queue_event->needs_clientside = needs_clientside; + queue_event->args = args; + + *out_queue_event = queue_event; + return S_OK; +} + +#define WM_UIA_EVENT_THREAD_RAISE_EVENT (WM_USER + 1) +#define WM_UIA_EVENT_THREAD_STOP (WM_USER + 2) +static LRESULT CALLBACK uia_event_thread_msg_proc(HWND hwnd, UINT msg, WPARAM wparam, + LPARAM lparam) +{ + switch (msg) + { + default: + break; + } + + return DefWindowProcW(hwnd, msg, wparam, lparam); +} + +static HRESULT uia_node_from_lresult(LRESULT lr, HUIANODE *huianode); +static HRESULT uia_event_thread_process_queue(struct list *event_queue) +{ + struct list *cursor, *cursor2; + + LIST_FOR_EACH_SAFE(cursor, cursor2, event_queue) + { + struct uia_queue_event *event = LIST_ENTRY(cursor, struct uia_queue_event, event_queue_entry); + HUIANODE node; + HRESULT hr; + + list_remove(cursor); + if (event->event->event_type == EVENT_TYPE_LOCAL) + { + hr = uia_node_from_lresult((LRESULT)V_I4(&event->node), &node); + if (SUCCEEDED(hr) && node) + { + SAFEARRAY *out_req; + BSTR tree_struct; + + hr = UiaGetUpdatedCache(node, event->event->u.local.cache_req, NormalizeState_None, NULL, &out_req, + &tree_struct); + if (SUCCEEDED(hr)) + event->event->u.local.cback(&event->args->u.simple_args, out_req, tree_struct); + UiaNodeRelease(node); + } + } + else + FIXME("EVENT_TYPE_REMOTE currently unhandled.\n"); + + uia_event_args_release(event->args); + IWineUiaEvent_Release(&event->event->IWineUiaEvent_iface); + heap_free(event); + } + + return S_OK; +} + +static DWORD WINAPI uia_event_thread_proc(void *arg) +{ + HANDLE initialized_event = arg; + struct list event_queue; + HWND hwnd; + MSG msg; + + list_init(&event_queue); + CoInitializeEx(NULL, COINIT_MULTITHREADED); + hwnd = CreateWindowW(L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); + if (!hwnd) + { + WARN("CreateWindow failed: %ld\n", GetLastError()); + CoUninitialize(); + FreeLibraryAndExitThread(huia_module, 1); + } + + SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)uia_event_thread_msg_proc); + event_thread.hwnd = hwnd; + event_thread.event_queue = &event_queue; + + /* Initialization complete, thread can now process window messages. */ + SetEvent(initialized_event); + TRACE("Event thread started.\n"); + while (GetMessageW(&msg, NULL, 0, 0)) + { + if (msg.message == WM_UIA_EVENT_THREAD_STOP || msg.message == WM_UIA_EVENT_THREAD_RAISE_EVENT) + { + HRESULT hr; + + hr = uia_event_thread_process_queue(&event_queue); + if (FAILED(hr)) + WARN("Process queue failed with hr %#lx\n", hr); + + if (msg.message == WM_UIA_EVENT_THREAD_STOP) + break; + } + + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + TRACE("Shutting down UI Automation event thread.\n"); + + DestroyWindow(hwnd); + CoUninitialize(); + FreeLibraryAndExitThread(huia_module, 0); +} + +static BOOL uia_start_event_thread(void) +{ + BOOL started = TRUE; + + EnterCriticalSection(&event_thread_cs); + if (++event_thread.ref == 1) + { + HANDLE ready_event = NULL; + HANDLE events[2]; + HMODULE hmodule; + DWORD wait_obj; + + /* Increment DLL reference count. */ + GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + (const WCHAR *)uia_start_event_thread, &hmodule); + + events[0] = ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!(event_thread.hthread = CreateThread(NULL, 0, uia_event_thread_proc, + ready_event, 0, NULL))) + { + FreeLibrary(hmodule); + started = FALSE; + goto exit; + } + + events[1] = event_thread.hthread; + wait_obj = WaitForMultipleObjects(2, events, FALSE, INFINITE); + if (wait_obj != WAIT_OBJECT_0) + { + CloseHandle(event_thread.hthread); + started = FALSE; + } + +exit: + if (ready_event) + CloseHandle(ready_event); + if (!started) + memset(&event_thread, 0, sizeof(event_thread)); + } + + LeaveCriticalSection(&event_thread_cs); + return started; +} + +static void uia_stop_event_thread(void) +{ + EnterCriticalSection(&event_thread_cs); + if (!--event_thread.ref) + { + PostMessageW(event_thread.hwnd, WM_UIA_EVENT_THREAD_STOP, 0, 0); + CloseHandle(event_thread.hthread); + memset(&event_thread, 0, sizeof(event_thread)); + } + LeaveCriticalSection(&event_thread_cs); +} + /* * IWineUiaEvent interface. */ @@ -393,6 +606,9 @@ static ULONG WINAPI uia_event_Release(IWineUiaEvent *iface) } } + if (event->started_event_thread) + uia_stop_event_thread(); + SafeArrayDestroy(event->runtime_id); heap_free(event); } @@ -474,12 +690,49 @@ static HRESULT WINAPI uia_event_get_event_data(IWineUiaEvent *iface, GUID *event return S_OK; } +static HRESULT WINAPI uia_event_raise_event(IWineUiaEvent *iface, VARIANT node, BOOL needs_clientside) +{ + struct uia_event *event = impl_from_IWineUiaEvent(iface); + const struct uia_event_info *event_info; + struct uia_queue_event *queue_event; + struct uia_event_args *args; + HRESULT hr; + + TRACE("%p, %s, %d\n", iface, debugstr_variant(&node), needs_clientside); + + if (event->event_type != EVENT_TYPE_LOCAL) + { + ERR("raise_event should only be called on EVENT_TYPE_LOCAL events\n"); + return E_NOTIMPL; + } + + event_info = uia_event_info_from_id(event->event_id); + args = create_uia_event_args(event_info); + if (!args) + return E_OUTOFMEMORY; + + hr = create_uia_queue_event(event, node, needs_clientside, args, &queue_event); + if (FAILED(hr)) + return hr; + + EnterCriticalSection(&event_thread_cs); + if (event_thread.event_queue) + { + list_add_tail(event_thread.event_queue, &queue_event->event_queue_entry); + PostMessageW(event_thread.hwnd, WM_UIA_EVENT_THREAD_RAISE_EVENT, 0, 0); + } + LeaveCriticalSection(&event_thread_cs); + + return S_OK; +} + static const IWineUiaEventVtbl uia_event_vtbl = { uia_event_QueryInterface, uia_event_AddRef, uia_event_Release, uia_event_detach, uia_event_get_event_data, + uia_event_raise_event, }; static struct uia_event *unsafe_impl_from_IWineUiaEvent(IWineUiaEvent *iface) @@ -2764,6 +3017,11 @@ static HRESULT WINAPI uia_nested_node_provider_attach_event(IWineUiaProvider *if heap_free(event->u.local.remote_events); return hr; } + + if (uia_start_event_thread()) + event->started_event_thread = TRUE; + else + WARN("Failed to start event thread.\n"); } event->u.local.remote_events[event->u.local.remote_events_count] = remote_event; event->u.local.remote_events_count++; From d143e4fffa1abd018966e968100b7f6f7cf56d5b Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 24 Jan 2023 14:45:35 -0500 Subject: [PATCH 0793/2777] uiautomationcore: Add support for raising remote UIA events. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_client.c | 123 ++++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-) diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 802a43fb483..cd2ccd624bd 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -98,6 +98,8 @@ static HRESULT get_interface_in_git(REFIID riid, DWORD git_cookie, IUnknown **re return S_OK; } +#define EVENT_TYPE_LOCAL 0 +#define EVENT_TYPE_REMOTE 1 struct uia_event { IWineUiaEvent IWineUiaEvent_iface; @@ -409,6 +411,7 @@ static LRESULT CALLBACK uia_event_thread_msg_proc(HWND hwnd, UINT msg, WPARAM wp } static HRESULT uia_node_from_lresult(LRESULT lr, HUIANODE *huianode); +static HRESULT clone_uia_node(HUIANODE in_node, HUIANODE *out_node); static HRESULT uia_event_thread_process_queue(struct list *event_queue) { struct list *cursor, *cursor2; @@ -436,8 +439,33 @@ static HRESULT uia_event_thread_process_queue(struct list *event_queue) } } else - FIXME("EVENT_TYPE_REMOTE currently unhandled.\n"); + { + HUIANODE node2; + LRESULT lr; + VARIANT v; + + hr = UiaHUiaNodeFromVariant(&event->node, &node); + if (FAILED(hr)) + goto next_event; + + hr = clone_uia_node(node, &node2); + UiaNodeRelease(node); + if (FAILED(hr)) + goto next_event; + + if ((lr = uia_lresult_from_node(node2))) + { + V_VT(&v) = VT_I4; + V_I4(&v) = lr; + hr = IWineUiaEvent_raise_event(event->event->u.remote.event_iface, v, event->needs_clientside); + if (FAILED(hr)) + WARN("IWineUiaEvent_raise_event failed with hr %#lx\n", hr); + } + else + UiaNodeRelease(node2); + } +next_event: uia_event_args_release(event->args); IWineUiaEvent_Release(&event->event->IWineUiaEvent_iface); heap_free(event); @@ -1547,6 +1575,10 @@ static HRESULT WINAPI uia_node_add_event(IWineUiaNode *iface, IWineUiaEvent *eve } uia_start_provider_thread(); + if (uia_start_event_thread()) + remote_event->started_event_thread = TRUE; + else + WARN("Failed to start event thread.\n"); *ret_event = &remote_event->IWineUiaEvent_iface; } @@ -2068,6 +2100,65 @@ static HRESULT attach_event_to_uia_node(struct uia_event *event, HUIANODE node, return hr; } +static HRESULT clone_uia_node(HUIANODE in_node, HUIANODE *out_node) +{ + struct uia_node *in_node_data = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)in_node); + struct uia_node *node; + HRESULT hr; + int i; + + node = heap_alloc_zero(sizeof(*node)); + if (!node) + return E_OUTOFMEMORY; + + node->IWineUiaNode_iface.lpVtbl = &uia_node_vtbl; + node->hwnd = in_node_data->hwnd; + list_init(&node->prov_thread_list_entry); + list_init(&node->node_map_list_entry); + node->ref = 1; + + for (i = 0; i < PROV_TYPE_COUNT; i++) + { + struct uia_provider *prov, *prov2; + + /* Only regular providers should be being cloned. */ + if (!in_node_data->prov[i] || is_nested_node_provider(in_node_data->prov[i])) + continue; + + if (!(prov = heap_alloc_zero(sizeof(*prov)))) + { + IWineUiaNode_Release(&node->IWineUiaNode_iface); + return E_OUTOFMEMORY; + } + + prov2 = impl_from_IWineUiaProvider(in_node_data->prov[i]); + *prov = *prov2; + IRawElementProviderSimple_AddRef(prov->elprov); + prov->ref = 1; + + node->prov[i] = &prov->IWineUiaProvider_iface; + node->prov_count++; + + if (!in_node_data->git_cookie[i]) + continue; + + hr = register_interface_in_git((IUnknown *)node->prov[i], &IID_IWineUiaProvider, &node->git_cookie[i]); + if (FAILED(hr)) + { + IWineUiaNode_Release(&node->IWineUiaNode_iface); + return hr; + } + } + + node->parent_link_idx = in_node_data->parent_link_idx; + node->creator_prov_idx = in_node_data->creator_prov_idx; + node->creator_prov_type = in_node_data->creator_prov_type; + + *out_node = (void *)&node->IWineUiaNode_iface; + + return S_OK; +} + /* * IWineUiaProvider interface. */ @@ -4304,6 +4395,27 @@ static HRESULT uia_process_event(HUIANODE node, struct uia_event_args *args, SAF if (SUCCEEDED(hr)) event->u.local.cback(&args->u.simple_args, out_req, tree_struct); } + else + { + struct uia_queue_event *queue_event; + VARIANT v; + + get_variant_for_node(node, &v); + hr = create_uia_queue_event(event, v, FALSE, args, &queue_event); + if (SUCCEEDED(hr)) + { + IWineUiaNode_AddRef((IWineUiaNode *)node); + InterlockedIncrement(&args->ref); + + EnterCriticalSection(&event_thread_cs); + if (event_thread.event_queue) + { + list_add_tail(event_thread.event_queue, &queue_event->event_queue_entry); + PostMessageW(event_thread.hwnd, WM_UIA_EVENT_THREAD_RAISE_EVENT, 0, 0); + } + LeaveCriticalSection(&event_thread_cs); + } + } break; } @@ -4366,6 +4478,15 @@ static HRESULT uia_raise_event(IRawElementProviderSimple *elprov, struct uia_eve return hr; } + LIST_FOR_EACH_SAFE(cursor, cursor2, &event_data->remote_events_list) + { + struct uia_event *event = LIST_ENTRY(cursor, struct uia_event, event_list_entry); + + hr = uia_process_event(node, args, sa, event); + if (FAILED(hr)) + WARN("uia_process_event failed with hr %#lx\n", hr); + } + LIST_FOR_EACH_SAFE(cursor, cursor2, &event_data->local_events_list) { struct uia_event *event = LIST_ENTRY(cursor, struct uia_event, event_list_entry); From 091295caf55be0f7e528f49602613c49ed6ad20e Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 25 Jan 2023 12:24:40 -0500 Subject: [PATCH 0794/2777] uiautomationcore: Implement UiaEventAddWindow. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_client.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index cd2ccd624bd..772246b0ed1 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -4347,8 +4347,25 @@ HRESULT WINAPI UiaRemoveEvent(HUIAEVENT huiaevent) */ HRESULT WINAPI UiaEventAddWindow(HUIAEVENT huiaevent, HWND hwnd) { - FIXME("(%p, %p): stub\n", huiaevent, hwnd); - return E_NOTIMPL; + struct uia_event *event = unsafe_impl_from_IWineUiaEvent((IWineUiaEvent *)huiaevent); + HUIANODE node; + HRESULT hr; + + TRACE("(%p, %p)\n", event, hwnd); + + if (!event) + return E_INVALIDARG; + + hr = UiaNodeFromHandle(hwnd, &node); + if (FAILED(hr)) + return hr; + + hr = attach_event_to_uia_node(event, node, TRUE); + UiaNodeRelease(node); + if (FAILED(hr)) + WARN("Failed to attach event to node, hr %#lx\n", hr); + + return hr; } /*********************************************************************** From 794e18cab26e9eb9fb602636a5da907e9ac8f452 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 31 Jan 2023 11:19:59 -0500 Subject: [PATCH 0795/2777] uiautomationcore: Implement IUIAutomation::{Add/Remove}FocusChangedEventHandler. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_client.c | 55 ++-- dlls/uiautomationcore/uia_com_client.c | 401 ++++++++++++++++++++++++- dlls/uiautomationcore/uia_private.h | 24 ++ 3 files changed, 444 insertions(+), 36 deletions(-) diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 772246b0ed1..35c24b45356 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -123,6 +123,7 @@ struct uia_event { struct { struct UiaCacheRequest *cache_req; + void *event_handler_data; UiaEventCallback *cback; DWORD git_cookie; @@ -269,21 +270,6 @@ static struct uia_event *uia_client_find_remote_event(LONG event_cookie, LONG pr return NULL; } -struct uia_event_args -{ - LONG ref; - - union { - struct UiaEventArgs simple_args; - struct UiaPropertyChangedEventArgs prop_change_args; - struct UiaStructureChangedEventArgs struct_change_args; - struct UiaAsyncContentLoadedEventArgs async_loaded_args; - struct UiaWindowClosedEventArgs window_closed_args; - struct UiaTextEditTextChangedEventArgs text_edit_change_args; - struct UiaChangesEventArgs changes_args; - } u; -}; - static struct uia_event_args *create_uia_event_args(const struct uia_event_info *event_info) { struct uia_event_args *args = heap_alloc_zero(sizeof(*args)); @@ -425,6 +411,7 @@ static HRESULT uia_event_thread_process_queue(struct list *event_queue) list_remove(cursor); if (event->event->event_type == EVENT_TYPE_LOCAL) { + event->args->event_handler_data = event->event->u.local.event_handler_data; hr = uia_node_from_lresult((LRESULT)V_I4(&event->node), &node); if (SUCCEEDED(hr) && node) { @@ -772,7 +759,7 @@ static struct uia_event *unsafe_impl_from_IWineUiaEvent(IWineUiaEvent *iface) } static struct uia_event *create_uia_event(int event_id, int scope, struct UiaCacheRequest *cache_req, - UiaEventCallback *cback, SAFEARRAY *runtime_id) + UiaEventCallback *cback, SAFEARRAY *runtime_id, void *event_handler_data) { struct uia_event *event = heap_alloc_zero(sizeof(*event)); static LONG next_event_cookie; @@ -789,6 +776,7 @@ static struct uia_event *create_uia_event(int event_id, int scope, struct UiaCac event->event_type = EVENT_TYPE_LOCAL; event->u.local.cache_req = cache_req; + event->u.local.event_handler_data = event_handler_data; event->u.local.cback = cback; return event; @@ -4262,30 +4250,21 @@ HRESULT WINAPI UiaFind(HUIANODE huianode, struct UiaFindParams *find_params, str return hr; } -/*********************************************************************** - * UiaAddEvent (uiautomationcore.@) - */ -HRESULT WINAPI UiaAddEvent(HUIANODE huianode, EVENTID event_id, UiaEventCallback *callback, enum TreeScope scope, - PROPERTYID *prop_ids, int prop_ids_count, struct UiaCacheRequest *cache_req, HUIAEVENT *huiaevent) +HRESULT uia_add_event(HUIANODE huianode, EVENTID event_id, UiaEventCallback *callback, enum TreeScope scope, + PROPERTYID *prop_ids, int prop_ids_count, struct UiaCacheRequest *cache_req, void *event_handler_data, + HUIAEVENT *huiaevent) { - const struct uia_event_info *event_info = uia_event_info_from_id(event_id); struct uia_event *event; SAFEARRAY *sa; HRESULT hr; - TRACE("(%p, %d, %p, %#x, %p, %d, %p, %p)\n", huianode, event_id, callback, scope, prop_ids, prop_ids_count, - cache_req, huiaevent); - - if (!callback || !cache_req || !huiaevent || !event_info) - return E_INVALIDARG; - *huiaevent = NULL; hr = UiaGetRuntimeId(huianode, &sa); if (FAILED(hr)) return hr; - if (!(event = create_uia_event(event_id, scope, cache_req, callback, sa))) + if (!(event = create_uia_event(event_id, scope, cache_req, callback, sa, event_handler_data))) { SafeArrayDestroy(sa); return E_OUTOFMEMORY; @@ -4307,6 +4286,23 @@ HRESULT WINAPI UiaAddEvent(HUIANODE huianode, EVENTID event_id, UiaEventCallback return S_OK; } +/*********************************************************************** + * UiaAddEvent (uiautomationcore.@) + */ +HRESULT WINAPI UiaAddEvent(HUIANODE huianode, EVENTID event_id, UiaEventCallback *callback, enum TreeScope scope, + PROPERTYID *prop_ids, int prop_ids_count, struct UiaCacheRequest *cache_req, HUIAEVENT *huiaevent) +{ + const struct uia_event_info *event_info = uia_event_info_from_id(event_id); + + TRACE("(%p, %d, %p, %#x, %p, %d, %p, %p)\n", huianode, event_id, callback, scope, prop_ids, prop_ids_count, + cache_req, huiaevent); + + if (!callback || !cache_req || !huiaevent || !event_info) + return E_INVALIDARG; + + return uia_add_event(huianode, event_id, callback, scope, prop_ids, prop_ids_count, cache_req, NULL, huiaevent); +} + /*********************************************************************** * UiaRemoveEvent (uiautomationcore.@) */ @@ -4508,6 +4504,7 @@ static HRESULT uia_raise_event(IRawElementProviderSimple *elprov, struct uia_eve { struct uia_event *event = LIST_ENTRY(cursor, struct uia_event, event_list_entry); + args->event_handler_data = event->u.local.event_handler_data; hr = uia_process_event(node, args, sa, event); if (FAILED(hr)) WARN("uia_process_event failed with hr %#lx\n", hr); diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 1eb19bd73db..20d6447e621 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -23,9 +23,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(uiautomation); -/* - * IUIAutomationElement interface. - */ struct uia_element { IUIAutomationElement9 IUIAutomationElement9_iface; LONG ref; @@ -38,6 +35,371 @@ static inline struct uia_element *impl_from_IUIAutomationElement9(IUIAutomationE return CONTAINING_RECORD(iface, struct uia_element, IUIAutomationElement9_iface); } +enum uia_com_event_types { + UIA_COM_FOCUS_EVENT_TYPE, + UIA_COM_EVENT_TYPE_COUNT, +}; + +struct uia_com_event { + struct list main_event_list_entry; + struct list event_type_list_entry; + + const struct uia_event_info *event_info; + struct UiaCacheRequest cache_req; + IUIAutomationElement *elem; + HUIAEVENT uia_event; + + int event_type; + union { + IUnknown *handler; + IUIAutomationFocusChangedEventHandler *focus_handler; + } u; +}; + +/* + * UI Automation COM client event thread functions. + */ +struct uia_com_event_thread +{ + HANDLE hthread; + HWND hwnd; + LONG ref; + + struct list events_list; + struct list event_type_list[UIA_COM_EVENT_TYPE_COUNT]; +}; + +static struct uia_com_event_thread com_event_thread; +static CRITICAL_SECTION com_event_thread_cs; +static CRITICAL_SECTION_DEBUG com_event_thread_cs_debug = +{ + 0, 0, &com_event_thread_cs, + { &com_event_thread_cs_debug.ProcessLocksList, &com_event_thread_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": com_event_thread_cs") } +}; +static CRITICAL_SECTION com_event_thread_cs = { &com_event_thread_cs_debug, -1, 0, 0, 0, 0 }; + +#define WM_UIA_COM_EVENT_THREAD_STOP (WM_USER + 2) +static LRESULT CALLBACK uia_com_event_thread_msg_proc(HWND hwnd, UINT msg, WPARAM wparam, + LPARAM lparam) +{ + switch (msg) + { + default: + break; + } + + return DefWindowProcW(hwnd, msg, wparam, lparam); +} + +static const WCHAR *ignored_window_classes[] = { + L"OleMainThreadWndClass", + L"IME", + L"Message", +}; + +void CALLBACK window_create_proc(HWINEVENTHOOK hook, DWORD event, HWND hwnd, LONG objid, LONG cid, DWORD thread, + DWORD event_time) +{ + struct list *cursor, *cursor2; + WCHAR buf[256] = { 0 }; + + if (objid != OBJID_WINDOW) + return; + + if (GetClassNameW(hwnd, buf, ARRAY_SIZE(buf))) + { + int i; + + for (i = 0; i < ARRAY_SIZE(ignored_window_classes); i++) + { + if (!lstrcmpW(buf, ignored_window_classes[i])) + return; + } + } + + LIST_FOR_EACH_SAFE(cursor, cursor2, &com_event_thread.events_list) + { + struct uia_com_event *event = LIST_ENTRY(cursor, struct uia_com_event, main_event_list_entry); + HRESULT hr; + + hr = UiaEventAddWindow(event->uia_event, hwnd); + if (FAILED(hr)) + WARN("UiaEventAddWindow failed with hr %#lx\n", hr); + } +} + +static DWORD WINAPI uia_com_event_thread_proc(void *arg) +{ + HANDLE initialized_event = arg; + HWND hwnd; + MSG msg; + + CoInitializeEx(NULL, COINIT_MULTITHREADED); + hwnd = CreateWindowW(L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); + if (!hwnd) + { + WARN("CreateWindow failed: %ld\n", GetLastError()); + CoUninitialize(); + FreeLibraryAndExitThread(huia_module, 1); + } + + SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)uia_com_event_thread_msg_proc); + com_event_thread.hwnd = hwnd; + SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE, 0, window_create_proc, 0, 0, WINEVENT_OUTOFCONTEXT); + + /* Initialization complete, thread can now process window messages. */ + SetEvent(initialized_event); + TRACE("Event thread started.\n"); + while (GetMessageW(&msg, NULL, 0, 0)) + { + if (msg.message == WM_UIA_COM_EVENT_THREAD_STOP) + break; + + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + TRACE("Shutting down UI Automation COM event thread.\n"); + + DestroyWindow(hwnd); + CoUninitialize(); + FreeLibraryAndExitThread(huia_module, 0); +} + +static BOOL uia_start_com_event_thread(void) +{ + BOOL started = TRUE; + + EnterCriticalSection(&com_event_thread_cs); + if (++com_event_thread.ref == 1) + { + HANDLE ready_event = NULL; + HANDLE events[2]; + HMODULE hmodule; + DWORD wait_obj; + int i; + + /* Increment DLL reference count. */ + GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + (const WCHAR *)uia_start_com_event_thread, &hmodule); + + list_init(&com_event_thread.events_list); + for (i = 0; i < UIA_COM_EVENT_TYPE_COUNT; i++) + list_init(&com_event_thread.event_type_list[i]); + + events[0] = ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!(com_event_thread.hthread = CreateThread(NULL, 0, uia_com_event_thread_proc, + ready_event, 0, NULL))) + { + FreeLibrary(hmodule); + started = FALSE; + goto exit; + } + + events[1] = com_event_thread.hthread; + wait_obj = WaitForMultipleObjects(2, events, FALSE, INFINITE); + if (wait_obj != WAIT_OBJECT_0) + { + CloseHandle(com_event_thread.hthread); + started = FALSE; + } + +exit: + if (ready_event) + CloseHandle(ready_event); + if (!started) + memset(&com_event_thread, 0, sizeof(com_event_thread)); + } + + LeaveCriticalSection(&com_event_thread_cs); + return started; +} + +static void uia_stop_com_event_thread(void) +{ + EnterCriticalSection(&com_event_thread_cs); + if (!--com_event_thread.ref) + { + PostMessageW(com_event_thread.hwnd, WM_UIA_COM_EVENT_THREAD_STOP, 0, 0); + CloseHandle(com_event_thread.hthread); + memset(&com_event_thread, 0, sizeof(com_event_thread)); + } + LeaveCriticalSection(&com_event_thread_cs); +} + +static HRESULT create_uia_element(IUIAutomationElement **iface, HUIANODE node); +static void WINAPI uia_com_event_callback(struct UiaEventArgs *args, SAFEARRAY *req_data, BSTR tree_struct) +{ + struct uia_event_args *event_args = impl_from_UiaEventArgs(args); + struct uia_com_event *com_event; + IUIAutomationElement *elem; + LONG idx[2] = { 0 }; + HUIANODE node; + HRESULT hr; + VARIANT v; + + TRACE("%p, %p, %p\n", args, req_data, tree_struct); + + hr = SafeArrayGetElement(req_data, idx, &v); + if (FAILED(hr)) + WARN("%d: hr %#lx\n", __LINE__, hr); + + hr = UiaHUiaNodeFromVariant(&v, &node); + if (FAILED(hr)) + WARN("%d: hr %#lx\n", __LINE__, hr); + VariantClear(&v); + + hr = create_uia_element(&elem, node); + if (FAILED(hr)) + WARN("%d: hr %#lx\n", __LINE__, hr); + + com_event = (struct uia_com_event *)event_args->event_handler_data; + switch (args->Type) + { + case EventArgsType_Simple: + if (args->EventId == UIA_AutomationFocusChangedEventId) + hr = IUIAutomationFocusChangedEventHandler_HandleFocusChangedEvent(com_event->u.focus_handler, elem); + break; + + case EventArgsType_PropertyChanged: + case EventArgsType_StructureChanged: + case EventArgsType_AsyncContentLoaded: + case EventArgsType_WindowClosed: + case EventArgsType_TextEditTextChanged: + case EventArgsType_Changes: + default: + break; + } + + if (FAILED(hr)) + WARN("Event handler failed with hr %#lx\n", hr); + + IUIAutomationElement_Release(elem); + SafeArrayDestroy(req_data); + SysFreeString(tree_struct); +} + +static const struct UiaCondition UiaTrueCondition = { ConditionType_True }; +static const struct UiaCacheRequest DefaultCacheReq = { + (struct UiaCondition *)&UiaTrueCondition, + TreeScope_Element, + NULL, 0, + NULL, 0, + AutomationElementMode_Full, +}; + +static HRESULT add_uia_com_event(const struct uia_event_info *event_info, int com_event_type, + IUIAutomationElement *elem, IUnknown *handler, int scope, int *prop_ids, int prop_ids_count, + struct UiaCacheRequest *cache_req) +{ + struct uia_com_event *com_event = heap_alloc_zero(sizeof(*com_event)); + struct uia_element *element; + HUIAEVENT event; + HRESULT hr; + + element = impl_from_IUIAutomationElement9((IUIAutomationElement9 *)elem); + hr = uia_add_event(element->node, event_info->event_id, (UiaEventCallback *)uia_com_event_callback, scope, + prop_ids, prop_ids_count, cache_req, (void *)com_event, &event); + if (FAILED(hr)) + { + heap_free(com_event); + return hr; + } + + if (!uia_start_com_event_thread()) + { + ERR("Failed to start COM event thread!\n"); + heap_free(com_event); + return E_FAIL; + } + + switch (com_event_type) + { + case UIA_COM_FOCUS_EVENT_TYPE: + hr = IUnknown_QueryInterface(handler, &IID_IUIAutomationFocusChangedEventHandler, + (void **)&com_event->u.focus_handler); + break; + + default: + break; + } + + if (FAILED(hr)) + { + ERR("Failed to get event handler interface, hr %#lx\n", hr); + uia_stop_com_event_thread(); + heap_free(com_event); + return hr; + } + + com_event->cache_req = *cache_req; + com_event->uia_event = event; + com_event->event_info = event_info; + list_add_tail(&com_event_thread.events_list, &com_event->main_event_list_entry); + list_add_tail(&com_event_thread.event_type_list[com_event_type], &com_event->event_type_list_entry); + + return S_OK; +} + +static void remove_uia_com_event(struct uia_com_event *event) +{ + HRESULT hr; + + list_remove(&event->main_event_list_entry); + list_remove(&event->event_type_list_entry); + hr = UiaRemoveEvent(event->uia_event); + if (FAILED(hr)) + WARN("UiaRemoveEvent failed with hr %#lx\n", hr); + + if (event->elem) + IUIAutomationElement_Release(event->elem); + IUnknown_Release(event->u.handler); + heap_free(event); + + uia_stop_com_event_thread(); +} + +static HRESULT find_uia_com_event(const struct uia_event_info *event_info, int com_event_type, + IUIAutomationElement *elem, IUnknown *handler, struct uia_com_event **out_event) +{ + struct list *cursor, *cursor2; + IUnknown *unk, *unk2; + HRESULT hr; + + *out_event = NULL; + hr = IUnknown_QueryInterface(handler, &IID_IUnknown, (void **)&unk); + if (FAILED(hr) || !unk) + return hr; + + LIST_FOR_EACH_SAFE(cursor, cursor2, &com_event_thread.event_type_list[com_event_type]) + { + struct uia_com_event *event = LIST_ENTRY(cursor, struct uia_com_event, event_type_list_entry); + HRESULT hr; + + if (event->event_info != event_info) + continue; + + hr = IUnknown_QueryInterface(event->u.handler, &IID_IUnknown, (void **)&unk2); + if (FAILED(hr) || !unk2) + continue; + + if ((unk == unk2) && (!elem || (elem == event->elem))) + *out_event = event; + + IUnknown_Release(unk2); + if (*out_event) + break; + } + + IUnknown_Release(unk); + + return S_OK; +} + +/* + * IUIAutomationElement interface. + */ static HRESULT WINAPI uia_element_QueryInterface(IUIAutomationElement9 *iface, REFIID riid, void **ppv) { if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IUIAutomationElement) || @@ -1309,15 +1671,40 @@ static HRESULT WINAPI uia_iface_RemoveStructureChangedEventHandler(IUIAutomation static HRESULT WINAPI uia_iface_AddFocusChangedEventHandler(IUIAutomation6 *iface, IUIAutomationCacheRequest *cache_req, IUIAutomationFocusChangedEventHandler *handler) { - FIXME("%p, %p, %p: stub\n", iface, cache_req, handler); - return E_NOTIMPL; + const struct uia_event_info *event_info = uia_event_info_from_id(UIA_AutomationFocusChangedEventId); + IUIAutomationElement *element; + HRESULT hr; + + TRACE("%p, %p, %p\n", iface, cache_req, handler); + + if (cache_req) + FIXME("Cache req parameter currently ignored\n"); + + hr = IUIAutomation6_ElementFromHandle(iface, GetDesktopWindow(), &element); + if (FAILED(hr) || !element) + { + WARN("Failed to get desktop element, hr %#lx\n", hr); + return hr; + } + + return add_uia_com_event(event_info, UIA_COM_FOCUS_EVENT_TYPE, element, (IUnknown *)handler, TreeScope_SubTree, NULL, + 0, (struct UiaCacheRequest *)&DefaultCacheReq); } static HRESULT WINAPI uia_iface_RemoveFocusChangedEventHandler(IUIAutomation6 *iface, IUIAutomationFocusChangedEventHandler *handler) { - FIXME("%p, %p: stub\n", iface, handler); - return E_NOTIMPL; + const struct uia_event_info *event_info = uia_event_info_from_id(UIA_AutomationFocusChangedEventId); + struct uia_com_event *event; + HRESULT hr; + + TRACE("%p, %p\n", iface, handler); + + hr = find_uia_com_event(event_info, UIA_COM_FOCUS_EVENT_TYPE, NULL, (IUnknown *)handler, &event); + if (SUCCEEDED(hr) && event) + remove_uia_com_event(event); + + return S_OK; } static HRESULT WINAPI uia_iface_RemoveAllEventHandlers(IUIAutomation6 *iface) diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index b8fb7b51d7c..31581930311 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -122,11 +122,35 @@ static inline BOOL uia_array_reserve(void **elements, SIZE_T *capacity, SIZE_T c return TRUE; } +struct uia_event_args +{ + LONG ref; + + union { + struct UiaEventArgs simple_args; + struct UiaPropertyChangedEventArgs prop_change_args; + struct UiaStructureChangedEventArgs struct_change_args; + struct UiaAsyncContentLoadedEventArgs async_loaded_args; + struct UiaWindowClosedEventArgs window_closed_args; + struct UiaTextEditTextChangedEventArgs text_edit_change_args; + struct UiaChangesEventArgs changes_args; + } u; + void *event_handler_data; +}; + +static inline struct uia_event_args *impl_from_UiaEventArgs(struct UiaEventArgs *args) +{ + return CONTAINING_RECORD(args, struct uia_event_args, u.simple_args); +} + /* uia_client.c */ int uia_compare_safearrays(SAFEARRAY *sa1, SAFEARRAY *sa2, int prop_type) DECLSPEC_HIDDEN; int get_node_provider_type_at_idx(struct uia_node *node, int idx) DECLSPEC_HIDDEN; HRESULT create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE *out_node, BOOL get_hwnd_providers) DECLSPEC_HIDDEN; +HRESULT uia_add_event(HUIANODE huianode, EVENTID event_id, UiaEventCallback *callback, enum TreeScope scope, + PROPERTYID *prop_ids, int prop_ids_count, struct UiaCacheRequest *cache_req, void *event_handler_data, + HUIAEVENT *huiaevent) DECLSPEC_HIDDEN; /* uia_com_client.c */ HRESULT create_uia_iface(IUnknown **iface, BOOL is_cui8) DECLSPEC_HIDDEN; From ec8f74f28300f436bd6176f03e29472e2d885ff3 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 25 Jan 2023 14:33:39 -0500 Subject: [PATCH 0796/2777] uiautomationcore: Add special UIA_RuntimeIdPropertyId handling for WPF providers. Wine-Mono currently doesn't support marshaling method arguments that return an array, which means IRawElementProviderFragment::GetRuntimeId won't work. Instead, use GetPropertyValue, which returns a VARIANT. This makes use of a quirk in WPF providers, as UIA_RuntimeIdPropertyId isn't supposed to be returned from IRawElementProviderSimple::GetPropertyValue. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_client.c | 52 +++++++++++++++++++++++++---- dlls/uiautomationcore/uia_private.h | 1 + 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 35c24b45356..ccf0abe90a4 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -1642,12 +1642,26 @@ static HRESULT prepare_uia_node(struct uia_node *node) enum ProviderOptions prov_opts; struct uia_provider *prov; HRESULT hr; + VARIANT v; /* Only regular providers need to be queried for UseComThreading. */ if (!node->prov[i] || is_nested_node_provider(node->prov[i])) continue; prov = impl_from_IWineUiaProvider(node->prov[i]); + + /* + * wine-mono currently doesn't support marshaling for return array + * method arguments, so we'll need to avoid this. + */ + hr = IRawElementProviderSimple_GetPropertyValue(prov->elprov, UIA_FrameworkIdPropertyId, &v); + if (SUCCEEDED(hr) && V_VT(&v) == VT_BSTR) + { + if (!wcscmp(V_BSTR(&v), L"WPF")) + prov->is_wpf_prov = TRUE; + VariantClear(&v); + } + hr = IRawElementProviderSimple_get_ProviderOptions(prov->elprov, &prov_opts); if (FAILED(hr)) continue; @@ -2353,14 +2367,38 @@ static HRESULT uia_provider_get_special_prop_val(struct uia_provider *prov, LONG lbound; int val; - hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderFragment, (void **)&elfrag); - if (FAILED(hr) || !elfrag) - break; + /* + * HACK: UIA_RuntimeIdPropertyId requires calling + * IRawElementProviderFragment::GetRuntimeId, which returns an array as a + * method argument. This is currently unsupported in wine-mono, so + * instead we'll get the runtime ID from + * IRawElementProviderSimple::GetPropertyValue. + */ + if (prov->is_wpf_prov) + { + VARIANT v; - hr = IRawElementProviderFragment_GetRuntimeId(elfrag, &sa); - IRawElementProviderFragment_Release(elfrag); - if (FAILED(hr) || !sa) - break; + VariantInit(&v); + hr = IRawElementProviderSimple_GetPropertyValue(prov->elprov, prop_info->prop_id, &v); + if (FAILED(hr) || (V_VT(&v) != (VT_I4 | VT_ARRAY))) + { + VariantClear(&v); + break; + } + + sa = V_ARRAY(&v); + } + else + { + hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderFragment, (void **)&elfrag); + if (FAILED(hr) || !elfrag) + break; + + hr = IRawElementProviderFragment_GetRuntimeId(elfrag, &sa); + IRawElementProviderFragment_Release(elfrag); + if (FAILED(hr) || !sa) + break; + } hr = SafeArrayGetLBound(sa, 1, &lbound); if (FAILED(hr)) diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 31581930311..802229ae159 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -85,6 +85,7 @@ struct uia_provider { BOOL return_nested_node; BOOL parent_check_ran; BOOL has_parent; + BOOL is_wpf_prov; }; static inline struct uia_provider *impl_from_IWineUiaProvider(IWineUiaProvider *iface) From 3d697fd325d30f3e2d22f0a919107ef2fdb55d1a Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 25 Jan 2023 14:46:55 -0500 Subject: [PATCH 0797/2777] uiautomationcore: Always match events registered on the desktop node. We can safely assume that if an event was created on the desktop node, any event raised falls within its scope. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_client.c | 99 ++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 32 deletions(-) diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index ccf0abe90a4..2f5764de428 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -4411,6 +4411,48 @@ HRESULT WINAPI UiaEventRemoveWindow(HUIAEVENT huiaevent, HWND hwnd) return E_NOTIMPL; } +static void uia_event_invoke_callback(HUIANODE node, struct uia_event_args *args, struct uia_event *event) +{ + HRESULT hr; + + if (event->event_type == EVENT_TYPE_LOCAL) + { + SAFEARRAY *out_req; + BSTR tree_struct; + + hr = UiaGetUpdatedCache(node, event->u.local.cache_req, NormalizeState_None, NULL, &out_req, + &tree_struct); + if (SUCCEEDED(hr)) + event->u.local.cback(&args->u.simple_args, out_req, tree_struct); + } + else + { + struct uia_queue_event *queue_event; + VARIANT v; + + get_variant_for_node(node, &v); + hr = create_uia_queue_event(event, v, FALSE, args, &queue_event); + if (SUCCEEDED(hr)) + { + EnterCriticalSection(&event_thread_cs); + if (event_thread.event_queue) + { + InterlockedIncrement(&args->ref); + IWineUiaNode_AddRef((IWineUiaNode *)node); + list_add_tail(event_thread.event_queue, &queue_event->event_queue_entry); + PostMessageW(event_thread.hwnd, WM_UIA_EVENT_THREAD_RAISE_EVENT, 0, 0); + } + else + { + IWineUiaEvent_Release(&event->IWineUiaEvent_iface); + heap_free(queue_event); + } + LeaveCriticalSection(&event_thread_cs); + } + } +} + +static SAFEARRAY *uia_desktop_node_rt_id; static HRESULT uia_process_event(HUIANODE node, struct uia_event_args *args, SAFEARRAY *rt_id, struct uia_event *event) { @@ -4421,6 +4463,16 @@ static HRESULT uia_process_event(HUIANODE node, struct uia_event_args *args, SAF HRESULT hr; IWineUiaEvent_AddRef(&event->IWineUiaEvent_iface); + + /* For events registered on the desktop node, always match. */ + if (uia_desktop_node_rt_id && (event->scope & (TreeScope_Descendants | TreeScope_Children)) && + !uia_compare_safearrays(event->runtime_id, uia_desktop_node_rt_id, UIAutomationType_IntArray)) + { + uia_event_invoke_callback(node, args, event); + IWineUiaEvent_Release(&event->IWineUiaEvent_iface); + return S_OK; + } + IWineUiaNode_AddRef(&node_data->IWineUiaNode_iface); while (1) { @@ -4436,38 +4488,7 @@ static HRESULT uia_process_event(HUIANODE node, struct uia_event_args *args, SAF if (!cmp && ((!height && (event->scope & TreeScope_Element)) || (height && (event->scope & (TreeScope_Descendants | TreeScope_Children))))) { - if (event->event_type == EVENT_TYPE_LOCAL) - { - SAFEARRAY *out_req; - BSTR tree_struct; - - hr = UiaGetUpdatedCache(node, event->u.local.cache_req, NormalizeState_None, NULL, &out_req, - &tree_struct); - if (SUCCEEDED(hr)) - event->u.local.cback(&args->u.simple_args, out_req, tree_struct); - } - else - { - struct uia_queue_event *queue_event; - VARIANT v; - - get_variant_for_node(node, &v); - hr = create_uia_queue_event(event, v, FALSE, args, &queue_event); - if (SUCCEEDED(hr)) - { - IWineUiaNode_AddRef((IWineUiaNode *)node); - InterlockedIncrement(&args->ref); - - EnterCriticalSection(&event_thread_cs); - if (event_thread.event_queue) - { - list_add_tail(event_thread.event_queue, &queue_event->event_queue_entry); - PostMessageW(event_thread.hwnd, WM_UIA_EVENT_THREAD_RAISE_EVENT, 0, 0); - } - LeaveCriticalSection(&event_thread_cs); - } - } - + uia_event_invoke_callback(node, args, event); break; } @@ -4503,6 +4524,20 @@ static HRESULT uia_raise_event(IRawElementProviderSimple *elprov, struct uia_eve SAFEARRAY *sa; HRESULT hr; + /* Create the desktop node runtime ID safearray, if it hasn't been already. */ + if (!uia_desktop_node_rt_id) + { + SAFEARRAY *sa2; + + if ((sa2 = SafeArrayCreateVector(VT_I4, 0, 2))) + { + if (SUCCEEDED(write_runtime_id_base(sa2, GetDesktopWindow()))) + uia_desktop_node_rt_id = sa2; + else + SafeArrayDestroy(sa2); + } + } + hr = IRawElementProviderSimple_get_ProviderOptions(elprov, &prov_opts); if (FAILED(hr)) return hr; From e6a89407a7b2a6bad812c6435e18e73b2fd61762 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Thu, 29 Dec 2022 10:26:51 -0500 Subject: [PATCH 0798/2777] uiautomationcore: Always return TRUE from UiaClientsAreListening(). Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 2f257c36e98..6818e39951d 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -265,7 +265,7 @@ static const IRawElementProviderSimpleVtbl hwnd_host_provider_vtbl = { BOOL WINAPI UiaClientsAreListening(void) { FIXME("()\n"); - return FALSE; + return TRUE; } /*********************************************************************** From 1feac807695b2da86979dcb0914a3b957b8cff4f Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 31 Jan 2023 12:23:10 -0500 Subject: [PATCH 0799/2777] uiautomationcore: Store winevents in a custom queue to avoid reentrancy issues. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_com_client.c | 139 ++++++++++++++++++++++--- 1 file changed, 125 insertions(+), 14 deletions(-) diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 20d6447e621..295df3e7562 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -65,6 +65,7 @@ struct uia_com_event_thread HWND hwnd; LONG ref; + struct list *winevent_queue; struct list events_list; struct list event_type_list[UIA_COM_EVENT_TYPE_COUNT]; }; @@ -79,6 +80,7 @@ static CRITICAL_SECTION_DEBUG com_event_thread_cs_debug = }; static CRITICAL_SECTION com_event_thread_cs = { &com_event_thread_cs_debug, -1, 0, 0, 0, 0 }; +#define WM_UIA_COM_EVENT_THREAD_PROCESS_WINEVENT (WM_USER + 1) #define WM_UIA_COM_EVENT_THREAD_STOP (WM_USER + 2) static LRESULT CALLBACK uia_com_event_thread_msg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) @@ -92,21 +94,57 @@ static LRESULT CALLBACK uia_com_event_thread_msg_proc(HWND hwnd, UINT msg, WPARA return DefWindowProcW(hwnd, msg, wparam, lparam); } +struct uia_queue_winevent +{ + DWORD event_id; + HWND hwnd; + LONG objid; + LONG cid; + DWORD thread; + DWORD event_time; + + struct list winevent_queue_entry; +}; + +void CALLBACK uia_com_client_winevent_proc(HWINEVENTHOOK hook, DWORD event, HWND hwnd, LONG objid, LONG cid, + DWORD thread, DWORD event_time) +{ + struct uia_queue_winevent *queue_winevent = heap_alloc_zero(sizeof(*queue_winevent)); + + TRACE("%p, %ld, %p, %ld, %ld, %ld, %ld\n", hook, event, hwnd, objid, cid, thread, event_time); + + if (!queue_winevent) + { + ERR("Failed to allocate queue_winevent\n"); + return; + } + + queue_winevent->event_id = event; + queue_winevent->hwnd = hwnd; + queue_winevent->objid = objid; + queue_winevent->cid = cid; + queue_winevent->thread = thread; + queue_winevent->event_time = event_time; + EnterCriticalSection(&com_event_thread_cs); + if (com_event_thread.winevent_queue) + list_add_tail(com_event_thread.winevent_queue, &queue_winevent->winevent_queue_entry); + else + heap_free(queue_winevent); + LeaveCriticalSection(&com_event_thread_cs); + + PostMessageW(com_event_thread.hwnd, WM_UIA_COM_EVENT_THREAD_PROCESS_WINEVENT, 0, 0); +} + static const WCHAR *ignored_window_classes[] = { L"OleMainThreadWndClass", L"IME", L"Message", }; -void CALLBACK window_create_proc(HWINEVENTHOOK hook, DWORD event, HWND hwnd, LONG objid, LONG cid, DWORD thread, - DWORD event_time) +static BOOL is_ignored_hwnd(HWND hwnd) { - struct list *cursor, *cursor2; WCHAR buf[256] = { 0 }; - if (objid != OBJID_WINDOW) - return; - if (GetClassNameW(hwnd, buf, ARRAY_SIZE(buf))) { int i; @@ -114,27 +152,88 @@ void CALLBACK window_create_proc(HWINEVENTHOOK hook, DWORD event, HWND hwnd, LON for (i = 0; i < ARRAY_SIZE(ignored_window_classes); i++) { if (!lstrcmpW(buf, ignored_window_classes[i])) - return; + return TRUE; + } + } + + return FALSE; +} + +static HRESULT uia_com_event_thread_handle_winevent(struct uia_queue_winevent *winevent) +{ + switch (winevent->event_id) + { + case EVENT_OBJECT_CREATE: + { + struct list *cursor, *cursor2; + + if (winevent->objid != OBJID_WINDOW) + break; + + LIST_FOR_EACH_SAFE(cursor, cursor2, &com_event_thread.events_list) + { + struct uia_com_event *event = LIST_ENTRY(cursor, struct uia_com_event, main_event_list_entry); + HRESULT hr; + + hr = UiaEventAddWindow(event->uia_event, winevent->hwnd); + if (FAILED(hr)) + WARN("UiaEventAddWindow failed with hr %#lx\n", hr); } + break; } - LIST_FOR_EACH_SAFE(cursor, cursor2, &com_event_thread.events_list) + default: + break; + } + + return S_OK; +} + +static HRESULT uia_com_event_thread_process_winevent_queue(struct list *winevent_queue) +{ + struct uia_queue_winevent prev_winevent = { 0 }; + struct list *cursor, *cursor2; + + if (list_empty(winevent_queue)) + return S_OK; + + LIST_FOR_EACH_SAFE(cursor, cursor2, winevent_queue) { - struct uia_com_event *event = LIST_ENTRY(cursor, struct uia_com_event, main_event_list_entry); + struct uia_queue_winevent *winevent = LIST_ENTRY(cursor, struct uia_queue_winevent, winevent_queue_entry); HRESULT hr; - hr = UiaEventAddWindow(event->uia_event, hwnd); + list_remove(cursor); + TRACE("Processing: event_id %ld, hwnd %p, objid %ld, cid %ld, thread %ld, event_time %ld\n", winevent->event_id, + winevent->hwnd,winevent->objid, winevent->cid, winevent->thread, winevent->event_time); + + if (is_ignored_hwnd(winevent->hwnd) || ((prev_winevent.event_id == winevent->event_id) && + (prev_winevent.hwnd == winevent->hwnd) && (prev_winevent.objid == winevent->objid) && + (prev_winevent.cid == winevent->cid) && (prev_winevent.thread == winevent->thread) && + (prev_winevent.event_time == winevent->event_time))) + { + heap_free(winevent); + continue; + } + + hr = uia_com_event_thread_handle_winevent(winevent); if (FAILED(hr)) - WARN("UiaEventAddWindow failed with hr %#lx\n", hr); + WARN("Failed to handle winevent, hr %#lx\n", hr); + prev_winevent = *winevent; + heap_free(winevent); } + + return S_OK; } static DWORD WINAPI uia_com_event_thread_proc(void *arg) { HANDLE initialized_event = arg; + struct list winevent_queue; + HWINEVENTHOOK hook; HWND hwnd; MSG msg; + list_init(&winevent_queue); CoInitializeEx(NULL, COINIT_MULTITHREADED); hwnd = CreateWindowW(L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); if (!hwnd) @@ -146,15 +245,26 @@ static DWORD WINAPI uia_com_event_thread_proc(void *arg) SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)uia_com_event_thread_msg_proc); com_event_thread.hwnd = hwnd; - SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_CREATE, 0, window_create_proc, 0, 0, WINEVENT_OUTOFCONTEXT); + com_event_thread.winevent_queue = &winevent_queue; + hook = SetWinEventHook(EVENT_MIN, EVENT_MAX, 0, uia_com_client_winevent_proc, 0, 0, + WINEVENT_OUTOFCONTEXT); /* Initialization complete, thread can now process window messages. */ SetEvent(initialized_event); TRACE("Event thread started.\n"); while (GetMessageW(&msg, NULL, 0, 0)) { - if (msg.message == WM_UIA_COM_EVENT_THREAD_STOP) - break; + if (msg.message == WM_UIA_COM_EVENT_THREAD_STOP || msg.message == WM_UIA_COM_EVENT_THREAD_PROCESS_WINEVENT) + { + HRESULT hr; + + hr = uia_com_event_thread_process_winevent_queue(&winevent_queue); + if (FAILED(hr)) + WARN("Process winevent queue failed with hr %#lx\n", hr); + + if (msg.message == WM_UIA_COM_EVENT_THREAD_STOP) + break; + } TranslateMessage(&msg); DispatchMessageW(&msg); @@ -162,6 +272,7 @@ static DWORD WINAPI uia_com_event_thread_proc(void *arg) TRACE("Shutting down UI Automation COM event thread.\n"); + UnhookWinEvent(hook); DestroyWindow(hwnd); CoUninitialize(); FreeLibraryAndExitThread(huia_module, 0); From 7223d6979bad7eed18f237d96ecf362405a52077 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Fri, 30 Dec 2022 14:29:37 -0500 Subject: [PATCH 0800/2777] uiautomationcore: Add support for handling EVENT_OBJECT_FOCUS winevents. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_com_client.c | 37 ++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 295df3e7562..3109a126f4c 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -182,6 +182,43 @@ static HRESULT uia_com_event_thread_handle_winevent(struct uia_queue_winevent *w break; } + case EVENT_OBJECT_FOCUS: + { + IRawElementProviderSimple *elprov = NULL; + HRESULT hr; + + if (winevent->cid == CHILDID_SELF) + { + hr = create_base_hwnd_provider(winevent->hwnd, &elprov); + if (FAILED(hr)) + WARN("Failed to create BaseHwnd provider with hr %#lx\n", hr); + } + else + { + IAccessible *acc = NULL; + VARIANT v; + + hr = AccessibleObjectFromEvent(winevent->hwnd, winevent->objid, winevent->cid, &acc, &v); + if (FAILED(hr) || !acc) + break; + + hr = create_msaa_provider(acc, V_I4(&v), winevent->hwnd, FALSE, TRUE, &elprov); + IAccessible_Release(acc); + if (FAILED(hr)) + WARN("Failed to create MSAA proxy provider with hr %#lx\n", hr); + } + + if (!elprov) + break; + + hr = UiaRaiseAutomationEvent(elprov, UIA_AutomationFocusChangedEventId); + if (FAILED(hr)) + WARN("Failed to raise event with hr %#lx\n", hr); + + IRawElementProviderSimple_Release(elprov); + break; + } + default: break; } From f2bf1ae299b2755e2dc58caa6cec81e0ac3a0d30 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 9 Jan 2023 13:07:33 -0500 Subject: [PATCH 0801/2777] uiautomationcore: Add support for UIA_ValueIsReadOnlyPropertyId. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_classes.idl | 1 + dlls/uiautomationcore/uia_client.c | 40 +++++++++++++++++++++++++++ dlls/uiautomationcore/uia_ids.c | 23 ++++++++++++++- dlls/uiautomationcore/uia_private.h | 8 ++++++ dlls/uiautomationcore/uia_provider.c | 6 ---- 5 files changed, 71 insertions(+), 7 deletions(-) diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index 052b2022d2a..7a3884add1c 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -25,6 +25,7 @@ struct uia_prop_info { int prop_id; int prop_type; int type; + int pattern_id; }; struct uia_event_info { diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 2f5764de428..43d974fd5ca 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -2487,6 +2487,43 @@ static HRESULT uia_provider_get_special_prop_val(struct uia_provider *prov, return S_OK; } +static HRESULT uia_provider_get_pattern_prop_val(struct uia_provider *prov, + const struct uia_prop_info *prop_info, VARIANT *ret_val) +{ + const struct uia_pattern_info *pattern_info = uia_pattern_info_from_id(prop_info->pattern_id); + IUnknown *unk, *pattern_prov; + HRESULT hr; + + unk = pattern_prov = NULL; + hr = IRawElementProviderSimple_GetPatternProvider(prov->elprov, prop_info->pattern_id, &unk); + if (FAILED(hr) || !unk) + return S_OK; + + hr = IUnknown_QueryInterface(unk, pattern_info->pattern_iid, (void **)&pattern_prov); + IUnknown_Release(unk); + if (FAILED(hr) || !pattern_prov) + return S_OK; + + switch (prop_info->prop_id) + { + case UIA_ValueIsReadOnlyPropertyId: + { + BOOL val; + + hr = IValueProvider_get_IsReadOnly((IValueProvider *)pattern_prov, &val); + if (SUCCEEDED(hr)) + variant_init_bool(ret_val, val); + break; + } + + default: + break; + } + + IUnknown_Release(pattern_prov); + return S_OK; +} + static HRESULT WINAPI uia_provider_get_prop_val(IWineUiaProvider *iface, const struct uia_prop_info *prop_info, VARIANT *ret_val) { @@ -2503,6 +2540,9 @@ static HRESULT WINAPI uia_provider_get_prop_val(IWineUiaProvider *iface, case PROP_TYPE_SPECIAL: return uia_provider_get_special_prop_val(prov, prop_info, ret_val); + case PROP_TYPE_PATTERN_PROP: + return uia_provider_get_pattern_prop_val(prov, prop_info, ret_val); + default: break; } diff --git a/dlls/uiautomationcore/uia_ids.c b/dlls/uiautomationcore/uia_ids.c index a594f630c9b..a3ab9f494b0 100644 --- a/dlls/uiautomationcore/uia_ids.c +++ b/dlls/uiautomationcore/uia_ids.c @@ -97,7 +97,9 @@ static const struct uia_prop_info default_uia_properties[] = { { &IsDropTargetPatternAvailable_Property_GUID, UIA_IsDropTargetPatternAvailablePropertyId, }, { &Dock_DockPosition_Property_GUID, UIA_DockDockPositionPropertyId, }, { &Styles_StyleId_Property_GUID, UIA_StylesStyleIdPropertyId, }, - { &Value_IsReadOnly_Property_GUID, UIA_ValueIsReadOnlyPropertyId, }, + { &Value_IsReadOnly_Property_GUID, UIA_ValueIsReadOnlyPropertyId, + PROP_TYPE_PATTERN_PROP, UIAutomationType_Bool, + UIA_ValuePatternId, }, { &IsSpreadsheetPatternAvailable_Property_GUID, UIA_IsSpreadsheetPatternAvailablePropertyId, }, { &Styles_StyleName_Property_GUID, UIA_StylesStyleNamePropertyId, }, { &IsAnnotationPatternAvailable_Property_GUID, UIA_IsAnnotationPatternAvailablePropertyId, }, @@ -501,6 +503,17 @@ static const struct uia_pattern_info default_uia_patterns[] = { &IID_ISpreadsheetItemProvider, }, }; +static const int pattern_id_idx[] = { + 0x1f, 0x1d, 0x10, 0x0c, 0x15, 0x13, 0x19, 0x0b, + 0x1c, 0x04, 0x1e, 0x06, 0x0f, 0x17, 0x09, 0x0a, + 0x1b, 0x00, 0x11, 0x02, 0x05, 0x14, 0x20, 0x1a, + 0x12, 0x07, 0x18, 0x21, 0x01, 0x16, 0x03, 0x08, + 0x0d, 0x0e, +}; + +#define PATTERN_ID_MIN 10000 +#define PATTERN_ID_MAX (PATTERN_ID_MIN + ARRAY_SIZE(default_uia_patterns)) + static const struct uia_pattern_info *uia_pattern_info_from_guid(const GUID *guid) { struct uia_pattern_info *pattern; @@ -512,6 +525,14 @@ static const struct uia_pattern_info *uia_pattern_info_from_guid(const GUID *gui return NULL; } +const struct uia_pattern_info *uia_pattern_info_from_id(PATTERNID pattern_id) +{ + if ((pattern_id < PATTERN_ID_MIN) || (pattern_id > PATTERN_ID_MAX)) + return NULL; + + return &default_uia_patterns[pattern_id_idx[pattern_id - PATTERN_ID_MIN]]; +} + /*********************************************************************** * UiaLookupId (uiautomationcore.@) */ diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 802229ae159..efb0c129104 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -29,6 +29,7 @@ enum uia_prop_type { PROP_TYPE_UNKNOWN, PROP_TYPE_ELEM_PROP, PROP_TYPE_SPECIAL, + PROP_TYPE_PATTERN_PROP, }; /* @@ -144,6 +145,12 @@ static inline struct uia_event_args *impl_from_UiaEventArgs(struct UiaEventArgs return CONTAINING_RECORD(args, struct uia_event_args, u.simple_args); } +static inline void variant_init_bool(VARIANT *v, BOOL val) +{ + V_VT(v) = VT_BOOL; + V_BOOL(v) = val ? VARIANT_TRUE : VARIANT_FALSE; +} + /* uia_client.c */ int uia_compare_safearrays(SAFEARRAY *sa1, SAFEARRAY *sa2, int prop_type) DECLSPEC_HIDDEN; int get_node_provider_type_at_idx(struct uia_node *node, int idx) DECLSPEC_HIDDEN; @@ -159,6 +166,7 @@ HRESULT create_uia_iface(IUnknown **iface, BOOL is_cui8) DECLSPEC_HIDDEN; /* uia_ids.c */ const struct uia_prop_info *uia_prop_info_from_id(PROPERTYID prop_id) DECLSPEC_HIDDEN; const struct uia_event_info *uia_event_info_from_id(EVENTID event_id) DECLSPEC_HIDDEN; +const struct uia_pattern_info *uia_pattern_info_from_id(PATTERNID pattern_id) DECLSPEC_HIDDEN; /* uia_provider.c */ void uia_stop_provider_thread(void) DECLSPEC_HIDDEN; diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index 74c1056e9d2..359547a3ac5 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -34,12 +34,6 @@ static void variant_init_i4(VARIANT *v, int val) V_I4(v) = val; } -static void variant_init_bool(VARIANT *v, BOOL val) -{ - V_VT(v) = VT_BOOL; - V_BOOL(v) = val ? VARIANT_TRUE : VARIANT_FALSE; -} - static BOOL msaa_check_acc_state(IAccessible *acc, VARIANT cid, ULONG flag) { HRESULT hr; From a32049e5b99980ee3e744c690295acdb3a68b040 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Mon, 9 Jan 2023 14:23:00 -0500 Subject: [PATCH 0802/2777] uiautomationcore: Implement UiaNodeFromFocus(). Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_classes.idl | 1 + dlls/uiautomationcore/uia_client.c | 173 ++++++++++++++++++++ dlls/uiautomationcore/uiautomationcore.spec | 2 +- include/uiautomationcoreapi.h | 1 + 4 files changed, 176 insertions(+), 1 deletion(-) diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index 7a3884add1c..50a1edd1b59 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -86,6 +86,7 @@ library UIA_wine_private HRESULT has_parent([out, retval]BOOL *out_val); HRESULT navigate([in]int nav_dir, [out, retval]VARIANT *ret_val); HRESULT attach_event([in]LONG_PTR huiaevent); + HRESULT get_focus([out, retval]VARIANT *ret_val); } [ diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 43d974fd5ca..6f3f50e88e6 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -1372,6 +1372,22 @@ static HRESULT attach_event_to_node_provider(IWineUiaNode *node, int idx, HUIAEV return hr; } +static HRESULT get_focus_from_node_provider(IWineUiaNode *node, int idx, VARIANT *ret_val) +{ + IWineUiaProvider *prov; + HRESULT hr; + + VariantInit(ret_val); + hr = IWineUiaNode_get_provider(node, idx, &prov); + if (FAILED(hr)) + return hr; + + hr = IWineUiaProvider_get_focus(prov, ret_val); + IWineUiaProvider_Release(prov); + + return hr; +} + /* * IWineUiaNode interface. */ @@ -1684,6 +1700,41 @@ static HRESULT prepare_uia_node(struct uia_node *node) return S_OK; } +static HRESULT get_focused_uia_node(HUIANODE in_node, BOOL ignore_creator, HUIANODE *out_node) +{ + struct uia_node *node = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)in_node); + HRESULT hr; + VARIANT v; + int i; + + *out_node = NULL; + if (!node) + return E_INVALIDARG; + + VariantInit(&v); + for (i = 0; i < node->prov_count; i++) + { + if (ignore_creator && (i == node->creator_prov_idx)) + continue; + + hr = get_focus_from_node_provider(&node->IWineUiaNode_iface, i, &v); + if (FAILED(hr)) + return hr; + + if (V_VT(&v) == VT_EMPTY) + continue; + + hr = UiaHUiaNodeFromVariant(&v, out_node); + if (FAILED(hr)) + { + out_node = NULL; + return hr; + } + } + + return S_OK; +} + static BOOL node_creator_is_parent_link(struct uia_node *node) { if (node->creator_prov_idx == node->parent_link_idx) @@ -2734,6 +2785,53 @@ static HRESULT WINAPI uia_provider_attach_event(IWineUiaProvider *iface, LONG_PT return S_OK; } +static HRESULT WINAPI uia_provider_get_focus(IWineUiaProvider *iface, VARIANT *out_val) +{ + struct uia_provider *prov = impl_from_IWineUiaProvider(iface); + IRawElementProviderFragmentRoot *elroot; + IRawElementProviderFragment *elfrag; + IUnknown *unk, *unk2; + HRESULT hr; + + TRACE("%p, %p\n", iface, out_val); + + VariantInit(out_val); + hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderFragmentRoot, (void **)&elroot); + if (FAILED(hr) || !elroot) + return S_OK; + + hr = IRawElementProviderFragmentRoot_GetFocus(elroot, &elfrag); + IRawElementProviderFragmentRoot_Release(elroot); + if (FAILED(hr) || !elfrag) + return hr; + + IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IUnknown, (void **)&unk); + IRawElementProviderFragment_QueryInterface(elfrag, &IID_IUnknown, (void **)&unk2); + + /* + * We only want to return a node if the focused provider is different than + * the current provider. + */ + if (unk != unk2) + { + IRawElementProviderSimple *elprov; + + hr = IRawElementProviderFragment_QueryInterface(elfrag, &IID_IRawElementProviderSimple, (void **)&elprov); + IRawElementProviderFragment_Release(elfrag); + if (SUCCEEDED(hr) && elprov) + { + hr = get_variant_for_elprov_node(elprov, prov->return_nested_node, out_val); + if (FAILED(hr)) + VariantClear(out_val); + } + } + + IUnknown_Release(unk); + IUnknown_Release(unk2); + + return hr; +} + static const IWineUiaProviderVtbl uia_provider_vtbl = { uia_provider_QueryInterface, uia_provider_AddRef, @@ -2743,6 +2841,7 @@ static const IWineUiaProviderVtbl uia_provider_vtbl = { uia_provider_has_parent, uia_provider_navigate, uia_provider_attach_event, + uia_provider_get_focus, }; static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProviderSimple *elprov, @@ -3187,6 +3286,30 @@ static HRESULT WINAPI uia_nested_node_provider_attach_event(IWineUiaProvider *if return S_OK; } +static HRESULT WINAPI uia_nested_node_provider_get_focus(IWineUiaProvider *iface, VARIANT *out_val) +{ + struct uia_nested_node_provider *prov = impl_from_nested_node_IWineUiaProvider(iface); + HUIANODE node; + HRESULT hr; + VARIANT v; + + TRACE("%p, %p\n", iface, out_val); + + VariantInit(out_val); + hr = get_focus_from_node_provider(prov->nested_node, 0, &v); + if (FAILED(hr) || V_VT(&v) == VT_EMPTY) + return hr; + + hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node); + if (FAILED(hr)) + return hr; + + get_variant_for_node(node, out_val); + VariantClear(&v); + + return S_OK; +} + static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = { uia_nested_node_provider_QueryInterface, uia_nested_node_provider_AddRef, @@ -3196,6 +3319,7 @@ static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = { uia_nested_node_provider_has_parent, uia_nested_node_provider_navigate, uia_nested_node_provider_attach_event, + uia_nested_node_provider_get_focus, }; static BOOL is_nested_node_provider(IWineUiaProvider *iface) @@ -3446,6 +3570,55 @@ HRESULT WINAPI UiaNodeFromHandle(HWND hwnd, HUIANODE *huianode) return S_OK; } +/*********************************************************************** + * UiaNodeFromFocus (uiautomationcore.@) + */ +HRESULT WINAPI UiaNodeFromFocus(struct UiaCacheRequest *cache_req, SAFEARRAY **out_req, BSTR *tree_struct) +{ + HUIANODE node, node2; + HRESULT hr; + + TRACE("(%p, %p, %p)\n", cache_req, out_req, tree_struct); + + if (!cache_req || !out_req || !tree_struct) + return E_INVALIDARG; + + *out_req = NULL; + *tree_struct = NULL; + + hr = UiaNodeFromHandle(GetDesktopWindow(), &node); + if (FAILED(hr)) + return hr; + + hr = get_focused_uia_node(node, FALSE, &node2); + if (FAILED(hr)) + { + UiaNodeRelease(node); + return hr; + } + + while (node2) + { + UiaNodeRelease(node); + + node = node2; + node2 = NULL; + hr = get_focused_uia_node(node, TRUE, &node2); + if (FAILED(hr)) + { + UiaNodeRelease(node); + return hr; + } + } + + hr = UiaGetUpdatedCache(node, cache_req, NormalizeState_None, NULL, out_req, tree_struct); + if (FAILED(hr)) + WARN("UiaGetUpdatedCache failed with hr %#lx\n", hr); + UiaNodeRelease(node); + + return S_OK; +} + /*********************************************************************** * UiaNodeRelease (uiautomationcore.@) */ diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec index c1a1d843ceb..68089d1cce3 100644 --- a/dlls/uiautomationcore/uiautomationcore.spec +++ b/dlls/uiautomationcore/uiautomationcore.spec @@ -76,7 +76,7 @@ #@ stub UiaIAccessibleFromProvider @ stdcall UiaLookupId(long ptr) @ stdcall UiaNavigate(ptr long ptr ptr ptr ptr) -@ stub UiaNodeFromFocus +@ stdcall UiaNodeFromFocus(ptr ptr ptr) @ stdcall UiaNodeFromHandle(long ptr) @ stub UiaNodeFromPoint @ stdcall UiaNodeFromProvider(ptr ptr) diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h index 97522062dd9..835125a288a 100644 --- a/include/uiautomationcoreapi.h +++ b/include/uiautomationcoreapi.h @@ -511,6 +511,7 @@ HRESULT WINAPI UiaRemoveEvent(HUIAEVENT huiaevent); HRESULT WINAPI UiaEventAddWindow(HUIAEVENT huiaevent, HWND hwnd); HRESULT WINAPI UiaEventRemoveWindow(HUIAEVENT huiaevent, HWND hwnd); HRESULT WINAPI UiaProviderForNonClient(HWND hwnd, long objid, long child_id, IRawElementProviderSimple **elprov); +HRESULT WINAPI UiaNodeFromFocus(struct UiaCacheRequest *cache_req, SAFEARRAY **out_req, BSTR *tree_struct); #ifdef __cplusplus } From b6cb582e301f859a786f320d5d44e51c1edbec53 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 10 Jan 2023 13:08:48 -0500 Subject: [PATCH 0803/2777] uiautomationcore: Implement ::GetFocus for default ProviderType_BaseHwnd provider. Signed-off-by: Connor McAdams --- dlls/uiautomationcore/uia_provider.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index 359547a3ac5..a89ab965846 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -1955,8 +1955,29 @@ static HRESULT WINAPI base_hwnd_fragment_root_ElementProviderFromPoint(IRawEleme static HRESULT WINAPI base_hwnd_fragment_root_GetFocus(IRawElementProviderFragmentRoot *iface, IRawElementProviderFragment **ret_val) { - FIXME("%p, %p: stub\n", iface, ret_val); - return E_NOTIMPL; + GUITHREADINFO info = { sizeof(info) }; + IRawElementProviderSimple *elprov; + HRESULT hr; + + TRACE("%p, %p\n", iface, ret_val); + + *ret_val = NULL; + if (!GetGUIThreadInfo(0, &info)) + { + WARN("GetGUIThreadInfo failed\n"); + return E_FAIL; + } + + hr = create_base_hwnd_provider(info.hwndFocus, &elprov); + if (FAILED(hr) || !elprov) + { + WARN("create_base_hwnd_provider failed with hr %#lx\n", hr); + return hr; + } + + hr = IRawElementProviderSimple_QueryInterface(elprov, &IID_IRawElementProviderFragment, (void **)ret_val); + IRawElementProviderSimple_Release(elprov); + return hr; } static const IRawElementProviderFragmentRootVtbl base_hwnd_fragment_root_vtbl = { From 177ce2a1acc0e9fbd65779f272d6c7972ec55d20 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 11 Jan 2023 13:04:18 -0500 Subject: [PATCH 0804/2777] combase: Further fix a race in find_proxy_manager(). The race was previously mitigated by making sure the refcnt wasn't 0, but there will also be a race if we AddRef and reach a refcnt of 1 due to having a prior refcnt of 0. Signed-off-by: Connor McAdams --- dlls/combase/marshal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/combase/marshal.c b/dlls/combase/marshal.c index a3da851b139..088160ab167 100644 --- a/dlls/combase/marshal.c +++ b/dlls/combase/marshal.c @@ -1949,7 +1949,7 @@ static BOOL find_proxy_manager(struct apartment * apt, OXID oxid, OID oid, struc /* be careful of a race with ClientIdentity_Release, which would * cause us to return a proxy which is in the process of being * destroyed */ - if (IMultiQI_AddRef(&proxy->IMultiQI_iface) != 0) + if (IMultiQI_AddRef(&proxy->IMultiQI_iface) > 1) { *proxy_found = proxy; found = TRUE; From 00cb510bb36c9bcb5a214997ccdb1fabe6ca2c6c Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 11 Jan 2023 13:11:05 -0500 Subject: [PATCH 0805/2777] oleaut32: Fix a race condition in TLB_ReadTypeLib. Avoid returning a typelib from the cache that is in the middle of being removed. Signed-off-by: Connor McAdams --- dlls/oleaut32/typelib.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index d92d0234c6c..5e72e45fde6 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -3342,11 +3342,22 @@ static HRESULT TLB_ReadTypeLib(LPCWSTR pszFileName, LPWSTR pszPath, UINT cchPath { if (!wcsicmp(entry->path, pszPath) && entry->index == index) { - TRACE("cache hit\n"); - *ppTypeLib = &entry->ITypeLib2_iface; - ITypeLib2_AddRef(*ppTypeLib); - LeaveCriticalSection(&cache_section); - return S_OK; + /* + * Avoid a race condition where a cached entry has been released, + * but not yet removed from the cache. + */ + if (ITypeLib2_AddRef(&entry->ITypeLib2_iface) > 1) + { + TRACE("cache hit\n"); + *ppTypeLib = &entry->ITypeLib2_iface; + LeaveCriticalSection(&cache_section); + return S_OK; + } + else + { + entry->ref = 0; + break; + } } } LeaveCriticalSection(&cache_section); From 831c47e314266f3baed0e19ef5adff59f02894b9 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Tue, 3 Jan 2023 15:07:32 -0500 Subject: [PATCH 0806/2777] windows.media.speech: HACK: Don't invoke passed in async handler interface for Forza Horizon 5. Invoking the interface causes the code to go further and causes a segfault on an unimplemented interface. Avoid this by never triggering the async handler. Signed-off-by: Connor McAdams --- dlls/windows.media.speech/async.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dlls/windows.media.speech/async.c b/dlls/windows.media.speech/async.c index 3c5f450cc65..5d82c06193b 100644 --- a/dlls/windows.media.speech/async.c +++ b/dlls/windows.media.speech/async.c @@ -490,10 +490,19 @@ static HRESULT WINAPI async_inspectable_put_Completed( IAsyncOperation_IInspecta IAsyncOperationCompletedHandler_IInspectable *handler ) { struct async_inspectable *impl = impl_from_IAsyncOperation_IInspectable(iface); + const char *var = getenv("SteamAppId"); HRESULT hr = S_OK; TRACE("iface %p, handler %p.\n", iface, handler); + /* + * HACK: Forza Horizon 5 will segfault when trying to get an interface if + * we invoke the handler, so we should just return S_OK and let it hang + * indefinitely. + */ + if (var && !strcmp(var, "1551360")) + return S_OK; + EnterCriticalSection(&impl->cs); if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; From 1ef497308cd7437db3bbdd62a07518bac692749e Mon Sep 17 00:00:00 2001 From: Esme Povirk Date: Wed, 6 Oct 2021 15:44:57 -0500 Subject: [PATCH 0807/2777] setupapi: Compare dll files before overwriting them. This is mainly to prevent us from clobbering reflinks created by the proton script, and to make sure dll symlinks (which we can't overwrite) are still registered properly. CW-Bug-Id: #18633 --- dlls/setupapi/fakedll.c | 151 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 138 insertions(+), 13 deletions(-) diff --git a/dlls/setupapi/fakedll.c b/dlls/setupapi/fakedll.c index 725b28a253e..235e7f622b8 100644 --- a/dlls/setupapi/fakedll.c +++ b/dlls/setupapi/fakedll.c @@ -430,7 +430,7 @@ static const WCHAR *enum_load_path( unsigned int idx ) } /* try to load a pre-compiled fake dll */ -static void *load_fake_dll( const WCHAR *name, SIZE_T *size ) +static void *load_fake_dll( const WCHAR *name, SIZE_T *size, WCHAR **out_filename ) { const WCHAR *build_dir = _wgetenv( L"WINEBUILDDIR" ); const WCHAR *path; @@ -478,11 +478,94 @@ static void *load_fake_dll( const WCHAR *name, SIZE_T *size ) } done: + if (res == 1) + { + *out_filename = HeapAlloc( GetProcessHeap(), 0, (wcslen( ptr ) + 1) * sizeof(WCHAR) ); + wcscpy( *out_filename, ptr ); + HeapFree( GetProcessHeap(), 0, file ); + return data; + } HeapFree( GetProcessHeap(), 0, file ); - if (res == 1) return data; return NULL; } +/* Check if the 2 files are already the same */ +static BOOL fake_dll_matches( const WCHAR *source, const WCHAR *dest ) +{ + WIN32_FILE_ATTRIBUTE_DATA data1, data2; + HANDLE h; + char *buf; + DWORD size, bytesread; + BOOL result; + + if (!GetFileAttributesExW( source, GetFileExInfoStandard, &data1 )) + return FALSE; + + if (!GetFileAttributesExW( dest, GetFileExInfoStandard, &data2 )) + return FALSE; + + if ((data2.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT) + /* If it's a symlink, assume it was put there by the proton script and is therefore correct */ + return TRUE; + + if (data1.nFileSizeHigh != 0 || + data2.nFileSizeHigh != 0 || + data1.nFileSizeLow != data2.nFileSizeLow) + { + return FALSE; + } + + size = data1.nFileSizeLow; + + /* If size and mtime matches, don't bother comparing contents */ + if ((data1.ftLastWriteTime.dwLowDateTime != 0 || data1.ftLastWriteTime.dwHighDateTime != 0) && + data1.ftLastWriteTime.dwLowDateTime == data2.ftLastWriteTime.dwLowDateTime && + data1.ftLastWriteTime.dwHighDateTime == data2.ftLastWriteTime.dwHighDateTime) + return TRUE; + + buf = HeapAlloc( GetProcessHeap(), 0, size * 2 ); + + if (!buf) + return FALSE; + + h = CreateFileW( source, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL ); + if (h == INVALID_HANDLE_VALUE) + { + HeapFree( GetProcessHeap(), 0, buf ); + return FALSE; + } + + if (!ReadFile( h, buf, size, &bytesread, NULL ) || bytesread != size) + { + CloseHandle( h ); + HeapFree( GetProcessHeap(), 0, buf ); + return FALSE; + } + + CloseHandle( h ); + + h = CreateFileW( dest, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL ); + if (h == INVALID_HANDLE_VALUE) + { + HeapFree( GetProcessHeap(), 0, buf ); + return FALSE; + } + + if (!ReadFile( h, buf + size, size, &bytesread, NULL ) || bytesread != size) + { + CloseHandle( h ); + HeapFree( GetProcessHeap(), 0, buf ); + return FALSE; + } + + CloseHandle( h ); + + result = !memcmp( buf, buf + size, size ); + + HeapFree( GetProcessHeap(), 0, buf ); + return result; +} + /* create the fake dll destination file */ static HANDLE create_dest_file( const WCHAR *name, BOOL delete ) { @@ -910,7 +993,11 @@ static int install_fake_dll( WCHAR *dest, WCHAR *file, BOOL delete, struct list destname[len] = 0; if (!add_handled_dll( destname )) ret = -1; - if (ret != -1) + if (ret != -1 && fake_dll_matches( file, dest )) + { + register_fake_dll( dest, data, size, delay_copy ); + } + else if (ret != -1) { HANDLE h = create_dest_file( dest, delete ); @@ -942,6 +1029,13 @@ static void delay_copy_files( struct list *delay_copy ) LIST_FOR_EACH_ENTRY_SAFE( copy, next, delay_copy, struct delay_copy, entry ) { list_remove( ©->entry ); + + if ( fake_dll_matches( copy->src, copy->dest ) ) + { + HeapFree( GetProcessHeap(), 0, copy ); + continue; + } + ret = read_file( copy->src, &data, &size ); if (ret != 1) { @@ -1054,6 +1148,7 @@ BOOL create_fake_dll( const WCHAR *name, const WCHAR *source ) BOOL ret; SIZE_T size; const WCHAR *filename; + WCHAR *source_filename; void *buffer; BOOL delete = !wcscmp( source, L"-" ); /* '-' source means delete the file */ @@ -1070,25 +1165,55 @@ BOOL create_fake_dll( const WCHAR *name, const WCHAR *source ) add_handled_dll( filename ); - if (!(h = create_dest_file( name, delete ))) return TRUE; /* not a fake dll */ - if (h == INVALID_HANDLE_VALUE) return FALSE; + if (delete) + { + if (!(h = create_dest_file( name, delete ))) return TRUE; /* not a fake dll */ + if (h == INVALID_HANDLE_VALUE) return FALSE; + + /* '-' source means delete the file */ + TRACE( "deleting %s\n", debugstr_w(name) ); + ret = FALSE; - if ((buffer = load_fake_dll( source, &size ))) + CloseHandle( h ); + DeleteFileW( name ); + } + else if ((buffer = load_fake_dll( source, &size, &source_filename ))) { - DWORD written; + if (fake_dll_matches( source_filename, name )) + { + HeapFree( GetProcessHeap(), 0, source_filename ); + + register_fake_dll( name, buffer, size, &delay_copy ); + ret = TRUE; + } + else + { + DWORD written; + + HeapFree( GetProcessHeap(), 0, source_filename ); - ret = (WriteFile( h, buffer, size, &written, NULL ) && written == size); - if (ret) register_fake_dll( name, buffer, size, &delay_copy ); - else ERR( "failed to write to %s (error=%lu)\n", debugstr_w(name), GetLastError() ); + if (!(h = create_dest_file( name, FALSE ))) return TRUE; /* not a fake dll */ + if (h == INVALID_HANDLE_VALUE) return FALSE; + + ret = (WriteFile( h, buffer, size, &written, NULL ) && written == size); + if (ret) register_fake_dll( name, buffer, size, &delay_copy ); + else ERR( "failed to write to %s (error=%lu)\n", debugstr_w(name), GetLastError() ); + + CloseHandle( h ); + if (!ret) DeleteFileW( name ); + } } else { + if (!(h = create_dest_file( name, FALSE ))) return TRUE; /* not a fake dll */ + if (h == INVALID_HANDLE_VALUE) return FALSE; + WARN( "fake dll %s not found for %s\n", debugstr_w(source), debugstr_w(name) ); ret = build_fake_dll( h, name ); - } - CloseHandle( h ); - if (!ret) DeleteFileW( name ); + CloseHandle( h ); + if (!ret) DeleteFileW( name ); + } delay_copy_files( &delay_copy ); return ret; From 403e91b5ffa0982396673ddf15c7801736af62ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:54 +0200 Subject: [PATCH 0808/2777] mshtml: Don't release the frame returned by get_frame_by_name. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It does *not* add a ref to the returned frame. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlwindow.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 732f5ec7316..f013ba20d1c 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3593,8 +3593,6 @@ static HRESULT WINAPI WindowDispEx_GetDispID(IDispatchEx *iface, BSTR bstrName, if(SUCCEEDED(hres) && frame) { global_prop_t *prop; - IHTMLWindow2_Release(&frame->base.IHTMLWindow2_iface); - prop = alloc_global_prop(window, GLOBAL_FRAMEVAR, bstrName); if(!prop) return E_OUTOFMEMORY; From af4fbe385c2bfd099622084b84c2ee97bbbd1a33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:54 +0200 Subject: [PATCH 0809/2777] mshtml: Don't hold ref to the created window in the FrameBase. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note that for the case when mozwindow_to_window returns an existing window, no ref is added to it anyway, so this is just leaking. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlframe.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/htmlframe.c b/dlls/mshtml/htmlframe.c index e1b1562b0dc..38bb53dc551 100644 --- a/dlls/mshtml/htmlframe.c +++ b/dlls/mshtml/htmlframe.c @@ -48,9 +48,14 @@ static HRESULT set_frame_doc(HTMLFrameBase *frame, nsIDOMDocument *nsdoc) return E_FAIL; window = mozwindow_to_window(mozwindow); - if(!window && frame->element.node.doc->browser) + if(!window && frame->element.node.doc->browser) { hres = create_outer_window(frame->element.node.doc->browser, mozwindow, frame->element.node.doc->outer_window, &window); + + /* Don't hold ref to the created window; the parent keeps ref to it */ + if(SUCCEEDED(hres)) + IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface); + } mozIDOMWindowProxy_Release(mozwindow); if(FAILED(hres)) return hres; From dc7ad10e2a7c8beb11a9d2de4c71ab9fa38cbc45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:54 +0200 Subject: [PATCH 0810/2777] mshtml: Release the image factory's dispex. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlimg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/htmlimg.c b/dlls/mshtml/htmlimg.c index c0333cab858..01cc8405f87 100644 --- a/dlls/mshtml/htmlimg.c +++ b/dlls/mshtml/htmlimg.c @@ -855,8 +855,10 @@ static ULONG WINAPI HTMLImageElementFactory_Release(IHTMLImageElementFactory *if TRACE("(%p) ref=%ld\n", This, ref); - if(!ref) + if(!ref) { + release_dispex(&This->dispex); free(This); + } return ref; } From 175d00f7c78b57a2ebc9c99cde59fff52e56387a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:55 +0200 Subject: [PATCH 0811/2777] mshtml: Don't initialize HTMLElement dispex for Option constructor. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's not an element, so it doesn't even implement those interfaces. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlselect.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dlls/mshtml/htmlselect.c b/dlls/mshtml/htmlselect.c index 4dfbbd916a7..c5610b41a1d 100644 --- a/dlls/mshtml/htmlselect.c +++ b/dlls/mshtml/htmlselect.c @@ -646,7 +646,6 @@ static dispex_static_data_t HTMLOptionElementFactory_dispex = { &HTMLOptionElementFactory_dispex_vtbl, IHTMLOptionElementFactory_tid, HTMLOptionElementFactory_iface_tids, - HTMLElement_init_dispex_info }; HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow *window, HTMLOptionElementFactory **ret_ptr) From a3115104d781225fbd1bccb94964935c4ae24579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:55 +0200 Subject: [PATCH 0812/2777] mshtml/tests: Fix EventObj leak in onclick test. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/tests/events.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index cd6006805d4..30b6d8799b6 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -1270,6 +1270,7 @@ static HRESULT WINAPI submit_onclick_attached_check_cancel(IDispatchEx *iface, D ok(event != NULL, "event == NULL\n"); test_event_cancelbubble(event, VARIANT_TRUE); + IHTMLEventObj_Release(event); return S_OK; } From f17a8cc24ee4f8bf4575e363170e9c0f702c7b0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:55 +0200 Subject: [PATCH 0813/2777] mshtml/tests: Fix window leaks in dom tests. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/tests/dom.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 6a960bfa21f..c9c52776fa9 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -1350,6 +1350,7 @@ static IHTMLDocument2 *_get_doc_node(unsigned line, IHTMLDocument2 *doc) hres = IHTMLWindow2_get_document(window, &ret); ok_(__FILE__,line)(hres == S_OK, "get_document failed: %08lx\n", hres); ok_(__FILE__,line)(ret != NULL, "document = NULL\n"); + IHTMLWindow2_Release(window); return ret; } @@ -6313,6 +6314,7 @@ static void test_location(IHTMLDocument2 *doc) ok(hres == S_OK, "get_location failed: %08lx\n", hres); ok(location == location2, "location != location2\n"); IHTMLLocation_Release(location2); + IHTMLWindow2_Release(window); test_ifaces((IUnknown*)location, location_iids); test_disp2((IUnknown*)location, &DIID_DispHTMLLocation, &IID_IHTMLLocation, NULL, L"about:blank"); @@ -7564,6 +7566,7 @@ static void test_xhr(IHTMLDocument2 *doc) SysFreeString(str); IHTMLWindow2_Release(window); + IDispatchEx_Release(dispex); } static void test_defaults(IHTMLDocument2 *doc) From f796cddc71e102edacf84c5ec7144ac26af74092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:55 +0200 Subject: [PATCH 0814/2777] mshtml: Implement location props when there's no URI. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmldoc.c | 3 ++ dlls/mshtml/htmllocation.c | 38 +++++++--------- dlls/mshtml/tests/htmllocation.c | 75 +++++++++++++++++++------------- 3 files changed, 63 insertions(+), 53 deletions(-) diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 90c4706abee..66b593920e2 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -1175,6 +1175,9 @@ static HRESULT WINAPI HTMLDocument_get_domain(IHTMLDocument2 *iface, BSTR *p) return E_NOTIMPL; } + if(This->outer_window && !This->outer_window->uri) + return E_FAIL; + nsAString_Init(&nsstr, NULL); nsres = nsIDOMHTMLDocument_GetDomain(This->html_document, &nsstr); if(NS_SUCCEEDED(nsres) && This->outer_window && This->outer_window->uri) { diff --git a/dlls/mshtml/htmllocation.c b/dlls/mshtml/htmllocation.c index 5376b3b8329..066ebb4f5e6 100644 --- a/dlls/mshtml/htmllocation.c +++ b/dlls/mshtml/htmllocation.c @@ -38,12 +38,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); static HRESULT get_url(HTMLLocation *This, const WCHAR **ret) { - if(!This->window || !This->window->base.outer_window || !This->window->base.outer_window->url) { - FIXME("No current URL\n"); - return E_NOTIMPL; - } - - *ret = This->window->base.outer_window->url; + if(!This->window || !This->window->base.outer_window || !This->window->base.outer_window->url) + *ret = L"about:blank"; + else + *ret = This->window->base.outer_window->url; return S_OK; } @@ -295,10 +293,8 @@ static HRESULT WINAPI HTMLLocation_get_protocol(IHTMLLocation *iface, BSTR *p) if(!p) return E_POINTER; - if(!(uri = get_uri(This))) { - FIXME("No current URI\n"); - return E_NOTIMPL; - } + if(!(uri = get_uri(This))) + return (*p = SysAllocString(L"about:")) ? S_OK : E_OUTOFMEMORY; hres = IUri_GetSchemeName(uri, &protocol); if(FAILED(hres)) @@ -388,8 +384,8 @@ static HRESULT WINAPI HTMLLocation_get_hostname(IHTMLLocation *iface, BSTR *p) return E_POINTER; if(!(uri = get_uri(This))) { - FIXME("No current URI\n"); - return E_NOTIMPL; + *p = NULL; + return S_OK; } hres = IUri_GetHost(uri, &hostname); @@ -425,8 +421,8 @@ static HRESULT WINAPI HTMLLocation_get_port(IHTMLLocation *iface, BSTR *p) return E_POINTER; if(!(uri = get_uri(This))) { - FIXME("No current URI\n"); - return E_NOTIMPL; + *p = NULL; + return S_OK; } hres = IUri_GetPort(uri, &port); @@ -466,10 +462,8 @@ static HRESULT WINAPI HTMLLocation_get_pathname(IHTMLLocation *iface, BSTR *p) if(!p) return E_POINTER; - if(!(uri = get_uri(This))) { - FIXME("No current URI\n"); - return E_NOTIMPL; - } + if(!(uri = get_uri(This))) + return (*p = SysAllocString(L"blank")) ? S_OK : E_OUTOFMEMORY; hres = IUri_GetPath(uri, &path); if(FAILED(hres)) @@ -504,8 +498,8 @@ static HRESULT WINAPI HTMLLocation_get_search(IHTMLLocation *iface, BSTR *p) return E_POINTER; if(!(uri = get_uri(This))) { - FIXME("No current URI\n"); - return E_NOTIMPL; + *p = NULL; + return S_OK; } hres = IUri_GetQuery(uri, &query); @@ -562,8 +556,8 @@ static HRESULT WINAPI HTMLLocation_get_hash(IHTMLLocation *iface, BSTR *p) return E_POINTER; if(!(uri = get_uri(This))) { - FIXME("No current URI\n"); - return E_NOTIMPL; + *p = NULL; + return S_OK; } hres = IUri_GetFragment(uri, &hash); diff --git a/dlls/mshtml/tests/htmllocation.c b/dlls/mshtml/tests/htmllocation.c index 0b241085af2..222b9553816 100644 --- a/dlls/mshtml/tests/htmllocation.c +++ b/dlls/mshtml/tests/htmllocation.c @@ -39,6 +39,18 @@ struct location_test { }; static const struct location_test location_tests[] = { + { + "Empty", + NULL, + "about:blank", + "about:", + NULL, + NULL, + NULL, + "blank", + NULL, + NULL + }, { "HTTP", "http://www.winehq.org?search#hash", @@ -187,7 +199,7 @@ static void test_hostname(IHTMLLocation *loc, IHTMLDocument2 *doc, const struct SysFreeString(str); hres = IHTMLDocument2_get_domain(doc, &str); - ok(hres == S_OK, "%s: get_domain failed: 0x%08lx\n", test->name, hres); + ok(hres == (test->url ? S_OK : E_FAIL), "%s: get_domain failed: 0x%08lx\n", test->name, hres); if(hres == S_OK) ok(str_eq_wa(str, test->hostname ? test->hostname : ""), "%s: expected retrieved domain to be L\"%s\", was: %s\n", @@ -280,7 +292,7 @@ static void perform_test(const struct location_test* test) WCHAR url[INTERNET_MAX_URL_LENGTH]; HRESULT hres; IBindCtx *bc; - IMoniker *url_mon; + IMoniker *url_mon = NULL; IPersistMoniker *persist_mon; IHTMLDocument2 *doc; IHTMLDocument6 *doc6; @@ -291,12 +303,14 @@ static void perform_test(const struct location_test* test) if(FAILED(hres)) return; - MultiByteToWideChar(CP_ACP, 0, test->url, -1, url, ARRAY_SIZE(url)); - hres = CreateURLMoniker(NULL, url, &url_mon); - ok(hres == S_OK, "%s: CreateURLMoniker failed: 0x%08lx\n", test->name, hres); - if(FAILED(hres)){ - IBindCtx_Release(bc); - return; + if(test->url) { + MultiByteToWideChar(CP_ACP, 0, test->url, -1, url, ARRAY_SIZE(url)); + hres = CreateURLMoniker(NULL, url, &url_mon); + ok(hres == S_OK, "%s: CreateURLMoniker failed: 0x%08lx\n", test->name, hres); + if(FAILED(hres)){ + IBindCtx_Release(bc); + return; + } } hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, @@ -307,7 +321,7 @@ static void perform_test(const struct location_test* test) #endif ok(hres == S_OK, "%s: CoCreateInstance failed: 0x%08lx\n", test->name, hres); if(FAILED(hres)){ - IMoniker_Release(url_mon); + if(url_mon) IMoniker_Release(url_mon); IBindCtx_Release(bc); return; } @@ -317,38 +331,39 @@ static void perform_test(const struct location_test* test) IHTMLDocument6_Release(doc6); }else{ win_skip("%s: Could not get IHTMLDocument6, probably too old IE. Requires IE 8+\n", test->name); - IMoniker_Release(url_mon); + if(url_mon) IMoniker_Release(url_mon); IBindCtx_Release(bc); return; } - hres = IHTMLDocument2_QueryInterface(doc, &IID_IPersistMoniker, - (void**)&persist_mon); - ok(hres == S_OK, "%s: IHTMlDocument2_QueryInterface failed: 0x%08lx\n", test->name, hres); - if(FAILED(hres)){ - IHTMLDocument2_Release(doc); - IMoniker_Release(url_mon); - IBindCtx_Release(bc); - return; - } - - hres = IPersistMoniker_Load(persist_mon, FALSE, url_mon, bc, - STGM_SHARE_EXCLUSIVE | STGM_READWRITE); - ok(hres == S_OK, "%s: IPersistMoniker_Load failed: 0x%08lx\n", test->name, hres); - if(FAILED(hres)){ + if(url_mon) { + hres = IHTMLDocument2_QueryInterface(doc, &IID_IPersistMoniker, + (void**)&persist_mon); + ok(hres == S_OK, "%s: IHTMlDocument2_QueryInterface failed: 0x%08lx\n", test->name, hres); + if(FAILED(hres)){ + IHTMLDocument2_Release(doc); + IMoniker_Release(url_mon); + IBindCtx_Release(bc); + return; + } + + hres = IPersistMoniker_Load(persist_mon, FALSE, url_mon, bc, + STGM_SHARE_EXCLUSIVE | STGM_READWRITE); + ok(hres == S_OK, "%s: IPersistMoniker_Load failed: 0x%08lx\n", test->name, hres); IPersistMoniker_Release(persist_mon); - IHTMLDocument2_Release(doc); IMoniker_Release(url_mon); - IBindCtx_Release(bc); - return; + + if(FAILED(hres)){ + IHTMLDocument2_Release(doc); + IBindCtx_Release(bc); + return; + } } hres = IHTMLDocument2_get_location(doc, &location); ok(hres == S_OK, "%s: IHTMLDocument2_get_location failed: 0x%08lx\n", test->name, hres); if(FAILED(hres)){ - IPersistMoniker_Release(persist_mon); IHTMLDocument2_Release(doc); - IMoniker_Release(url_mon); IBindCtx_Release(bc); return; } @@ -363,9 +378,7 @@ static void perform_test(const struct location_test* test) test_hash(location, test); IHTMLLocation_Release(location); - IPersistMoniker_Release(persist_mon); IHTMLDocument2_Release(doc); - IMoniker_Release(url_mon); IBindCtx_Release(bc); } From b5cd78bf9ea58ad1e76784f8787b3e5a2f0aa2b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:55 +0200 Subject: [PATCH 0815/2777] mshtml: Set SCRIPTPROP_ABBREVIATE_GLOBALNAME_RESOLUTION properly. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/script.c | 12 +- dlls/mshtml/tests/script.c | 376 ++++++++++++++++++++++++++++++++++--- 2 files changed, 362 insertions(+), 26 deletions(-) diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c index 5321080a8f9..7c9fd1887d1 100644 --- a/dlls/mshtml/script.c +++ b/dlls/mshtml/script.c @@ -201,9 +201,17 @@ static BOOL init_script_engine(ScriptHost *script_host) hres = IActiveScript_AddNamedItem(script_host->script, L"window", SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS); if(SUCCEEDED(hres)) { + const struct list *list = &script_host->window->script_hosts, *head = list_head(list); V_VT(&var) = VT_BOOL; - V_BOOL(&var) = VARIANT_TRUE; + V_BOOL(&var) = head ? VARIANT_FALSE : VARIANT_TRUE; set_script_prop(script_host, SCRIPTPROP_ABBREVIATE_GLOBALNAME_RESOLUTION, &var); + + /* if this was second engine added, also set it to first engine, since it used to be TRUE */ + if(head && !list_next(list, head)) { + ScriptHost *first_host = LIST_ENTRY(head, ScriptHost, entry); + if(first_host->script) + set_script_prop(first_host, SCRIPTPROP_ABBREVIATE_GLOBALNAME_RESOLUTION, &var); + } }else { WARN("AddNamedItem failed: %08lx\n", hres); } @@ -708,7 +716,6 @@ static ScriptHost *create_script_host(HTMLInnerWindow *window, const GUID *guid) ret->script_state = SCRIPTSTATE_UNINITIALIZED; ret->guid = *guid; - list_add_tail(&window->script_hosts, &ret->entry); hres = CoCreateInstance(&ret->guid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, &IID_IActiveScript, (void**)&ret->script); @@ -717,6 +724,7 @@ static ScriptHost *create_script_host(HTMLInnerWindow *window, const GUID *guid) else if(!init_script_engine(ret)) release_script_engine(ret); + list_add_tail(&window->script_hosts, &ret->entry); return ret; } diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index 8d9ff3cd3f7..c06009d1996 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -103,21 +103,33 @@ const GUID GUID_CUSTOM_CONFIRMOBJECTSAFETY = DEFINE_EXPECT(CreateInstance); +DEFINE_EXPECT(CreateInstance2); DEFINE_EXPECT(GetInterfaceSafetyOptions); DEFINE_EXPECT(SetInterfaceSafetyOptions); +DEFINE_EXPECT(GetInterfaceSafetyOptions2); +DEFINE_EXPECT(SetInterfaceSafetyOptions2); DEFINE_EXPECT(InitNew); +DEFINE_EXPECT(InitNew2); DEFINE_EXPECT(Close); +DEFINE_EXPECT(Close2); DEFINE_EXPECT(SetProperty_HACK_TRIDENTEVENTSINK); DEFINE_EXPECT(SetProperty_INVOKEVERSIONING); DEFINE_EXPECT(SetProperty_ABBREVIATE_GLOBALNAME_RESOLUTION_FALSE); DEFINE_EXPECT(SetProperty_ABBREVIATE_GLOBALNAME_RESOLUTION_TRUE); +DEFINE_EXPECT(SetProperty2_HACK_TRIDENTEVENTSINK); +DEFINE_EXPECT(SetProperty2_INVOKEVERSIONING); +DEFINE_EXPECT(SetProperty2_ABBREVIATE_GLOBALNAME_RESOLUTION_FALSE); +DEFINE_EXPECT(SetProperty2_ABBREVIATE_GLOBALNAME_RESOLUTION_TRUE); DEFINE_EXPECT(SetScriptSite); +DEFINE_EXPECT(SetScriptSite2); DEFINE_EXPECT(GetScriptState); DEFINE_EXPECT(SetScriptState_STARTED); DEFINE_EXPECT(SetScriptState_CONNECTED); DEFINE_EXPECT(SetScriptState_DISCONNECTED); DEFINE_EXPECT(AddNamedItem); +DEFINE_EXPECT(AddNamedItem2); DEFINE_EXPECT(ParseScriptText_script); +DEFINE_EXPECT(ParseScriptText_script2); DEFINE_EXPECT(ParseScriptText_execScript); DEFINE_EXPECT(GetScriptDispatch); DEFINE_EXPECT(funcDisp); @@ -140,7 +152,6 @@ DEFINE_EXPECT(ChangeType_bstr); DEFINE_EXPECT(ChangeType_dispatch); DEFINE_EXPECT(GetTypeInfo); -#define TESTSCRIPT_CLSID "{178fc163-f585-4e24-9c13-4bb7faf80746}" #define TESTACTIVEX_CLSID "{178fc163-f585-4e24-9c13-4bb7faf80646}" #define DISPID_SCRIPT_TESTPROP 0x100000 @@ -161,8 +172,10 @@ DEFINE_EXPECT(GetTypeInfo); #define DISPID_EXTERNAL_TESTHOSTCTX 0x30000C #define DISPID_EXTERNAL_GETMIMETYPE 0x30000D -static const GUID CLSID_TestScript = - {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x07,0x46}}; +static const GUID CLSID_TestScript[] = { + {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x07,0x46}}, + {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x08,0x46}}, +}; static const GUID CLSID_TestActiveX = {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x06,0x46}}; @@ -178,25 +191,25 @@ static HRESULT ax_getopt_hres = S_OK, ax_setopt_dispex_hres = S_OK; static HRESULT ax_setopt_disp_caller_hres = S_OK, ax_setopt_disp_data_hres = S_OK; static BOOL skip_loadobject_tests; -static IActiveScriptSite *site; -static SCRIPTSTATE state; +static IActiveScriptSite *site, *site2; +static SCRIPTSTATE state, state2; -static BOOL init_key(const char *key_name, const char *def_value, BOOL init) +static BOOL init_key(const WCHAR *key_name, const WCHAR *def_value, BOOL init) { HKEY hkey; DWORD res; if(!init) { - RegDeleteKeyA(HKEY_CLASSES_ROOT, key_name); + RegDeleteKeyW(HKEY_CLASSES_ROOT, key_name); return TRUE; } - res = RegCreateKeyA(HKEY_CLASSES_ROOT, key_name, &hkey); + res = RegCreateKeyW(HKEY_CLASSES_ROOT, key_name, &hkey); if(res != ERROR_SUCCESS) return FALSE; if(def_value) - res = RegSetValueA(hkey, NULL, REG_SZ, def_value, strlen(def_value)); + res = RegSetValueW(hkey, NULL, REG_SZ, def_value, wcslen(def_value)); RegCloseKey(hkey); @@ -1927,9 +1940,9 @@ static IObjectSafety AXObjectSafety = { &AXObjectSafetyVtbl }; static BOOL set_safe_reg(BOOL safe_call, BOOL safe_data) { - return init_key("CLSID\\"TESTACTIVEX_CLSID"\\Implemented Categories\\{7dd95801-9882-11cf-9fa9-00aa006c42c4}", + return init_key(L"CLSID\\"TESTACTIVEX_CLSID"\\Implemented Categories\\{7dd95801-9882-11cf-9fa9-00aa006c42c4}", NULL, safe_call) - && init_key("CLSID\\"TESTACTIVEX_CLSID"\\Implemented Categories\\{7dd95802-9882-11cf-9fa9-00aa006c42c4}", + && init_key(L"CLSID\\"TESTACTIVEX_CLSID"\\Implemented Categories\\{7dd95802-9882-11cf-9fa9-00aa006c42c4}", NULL, safe_data); } @@ -3336,6 +3349,260 @@ static const IActiveScriptVtbl ActiveScriptVtbl = { static IActiveScript ActiveScript = { &ActiveScriptVtbl }; +static HRESULT WINAPI ObjectSafety2_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid, + DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions) +{ + CHECK_EXPECT(GetInterfaceSafetyOptions2); + + ok(IsEqualGUID(&IID_IActiveScriptParse, riid), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + ok(pdwSupportedOptions != NULL, "pdwSupportedOptions == NULL\n"); + ok(pdwEnabledOptions != NULL, "pdwEnabledOptions == NULL\n"); + + *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA | INTERFACE_USES_DISPEX | INTERFACE_USES_SECURITY_MANAGER; + *pdwEnabledOptions = INTERFACE_USES_DISPEX; + + return S_OK; +} + +static HRESULT WINAPI ObjectSafety2_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid, + DWORD dwOptionSetMask, DWORD dwEnabledOptions) +{ + CHECK_EXPECT(SetInterfaceSafetyOptions2); + + ok(IsEqualGUID(&IID_IActiveScriptParse, riid), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + + ok(dwOptionSetMask == (INTERFACESAFE_FOR_UNTRUSTED_DATA | INTERFACE_USES_DISPEX | INTERFACE_USES_SECURITY_MANAGER), + "dwOptionSetMask = %08lx\n", dwOptionSetMask); + ok(dwEnabledOptions == (INTERFACESAFE_FOR_UNTRUSTED_DATA | INTERFACE_USES_DISPEX | INTERFACE_USES_SECURITY_MANAGER), + "dwEnabledOptions = %08lx\n", dwOptionSetMask); + + return S_OK; +} + +static const IObjectSafetyVtbl ObjectSafety2Vtbl = { + ObjectSafety_QueryInterface, + ObjectSafety_AddRef, + ObjectSafety_Release, + ObjectSafety2_GetInterfaceSafetyOptions, + ObjectSafety2_SetInterfaceSafetyOptions +}; + +static IObjectSafety ObjectSafety2 = { &ObjectSafety2Vtbl }; + +static HRESULT WINAPI ActiveScriptProperty2_SetProperty(IActiveScriptProperty *iface, DWORD dwProperty, + VARIANT *pvarIndex, VARIANT *pvarValue) +{ + switch(dwProperty) { + case SCRIPTPROP_HACK_TRIDENTEVENTSINK: + CHECK_EXPECT(SetProperty2_HACK_TRIDENTEVENTSINK); + ok(V_VT(pvarValue) == VT_BOOL, "V_VT(pvarValue) = %d\n", V_VT(pvarValue)); + ok(V_BOOL(pvarValue) == VARIANT_TRUE, "V_BOOL(pvarValue) = %x\n", V_BOOL(pvarValue)); + break; + case SCRIPTPROP_INVOKEVERSIONING: + CHECK_EXPECT(SetProperty2_INVOKEVERSIONING); + ok(V_VT(pvarValue) == VT_I4, "V_VT(pvarValue) = %d\n", V_VT(pvarValue)); + ok(V_I4(pvarValue) == 1, "V_I4(pvarValue) = %ld\n", V_I4(pvarValue)); + break; + case SCRIPTPROP_ABBREVIATE_GLOBALNAME_RESOLUTION: + if(V_BOOL(pvarValue)) + CHECK_EXPECT(SetProperty2_ABBREVIATE_GLOBALNAME_RESOLUTION_TRUE); + else { + CHECK_EXPECT(SetProperty2_ABBREVIATE_GLOBALNAME_RESOLUTION_FALSE); + SET_EXPECT(SetProperty_ABBREVIATE_GLOBALNAME_RESOLUTION_FALSE); + } + ok(V_VT(pvarValue) == VT_BOOL, "V_VT(pvarValue) = %d\n", V_VT(pvarValue)); + break; + case 0x70000003: /* Undocumented property set by IE10 */ + return E_NOTIMPL; + default: + ok(0, "unexpected property %08lx\n", dwProperty); + return E_NOTIMPL; + } + + ok(!pvarIndex, "pvarIndex != NULL\n"); + ok(pvarValue != NULL, "pvarValue == NULL\n"); + + return S_OK; +} + +static const IActiveScriptPropertyVtbl ActiveScriptProperty2Vtbl = { + ActiveScriptProperty_QueryInterface, + ActiveScriptProperty_AddRef, + ActiveScriptProperty_Release, + ActiveScriptProperty_GetProperty, + ActiveScriptProperty2_SetProperty +}; + +static IActiveScriptProperty ActiveScriptProperty2 = { &ActiveScriptProperty2Vtbl }; + +static HRESULT WINAPI ActiveScriptParse2_InitNew(IActiveScriptParse *iface) +{ + CHECK_EXPECT(InitNew2); + return S_OK; +} + +static HRESULT WINAPI ActiveScriptParse2_ParseScriptText(IActiveScriptParse *iface, LPCOLESTR pstrCode, + LPCOLESTR pstrItemName, IUnknown *punkContext, LPCOLESTR pstrDelimiter, CTXARG_T dwSourceContextCookie, + ULONG ulStartingLine, DWORD dwFlags, VARIANT *pvarResult, EXCEPINFO *pexcepinfo) +{ + ok(pvarResult != NULL, "pvarResult == NULL\n"); + ok(pexcepinfo != NULL, "pexcepinfo == NULL\n"); + + if(!lstrcmpW(pstrCode, L"second script")) { + CHECK_EXPECT(ParseScriptText_script2); + ok(!lstrcmpW(pstrItemName, L"window"), "pstrItemName = %s\n", wine_dbgstr_w(pstrItemName)); + ok(!lstrcmpW(pstrDelimiter, L""), "pstrDelimiter = %s\n", wine_dbgstr_w(pstrDelimiter)); + ok(dwFlags == (SCRIPTTEXT_ISVISIBLE | SCRIPTTEXT_HOSTMANAGESSOURCE), "dwFlags = %08lx\n", dwFlags); + return S_OK; + } + + ok(0, "unexpected script %s\n", wine_dbgstr_w(pstrCode)); + return E_FAIL; +} + +static const IActiveScriptParseVtbl ActiveScriptParse2Vtbl = { + ActiveScriptParse_QueryInterface, + ActiveScriptParse_AddRef, + ActiveScriptParse_Release, + ActiveScriptParse2_InitNew, + ActiveScriptParse_AddScriptlet, + ActiveScriptParse2_ParseScriptText +}; + +static IActiveScriptParse ActiveScriptParse2 = { &ActiveScriptParse2Vtbl }; + +static HRESULT WINAPI ActiveScript2_QueryInterface(IActiveScript *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IActiveScript, riid)) { + *ppv = iface; + return S_OK; + } + + if(IsEqualGUID(&IID_IActiveScriptParse, riid)) { + *ppv = &ActiveScriptParse2; + return S_OK; + } + + if(IsEqualGUID(&IID_IActiveScriptParseProcedure2, riid)) { + *ppv = &ActiveScriptParseProcedure; + return S_OK; + } + + if(IsEqualGUID(&IID_IActiveScriptProperty, riid)) { + *ppv = &ActiveScriptProperty2; + return S_OK; + } + + if(IsEqualGUID(&IID_IObjectSafety, riid)) { + *ppv = &ObjectSafety2; + return S_OK; + } + + if(IsEqualGUID(&IID_IActiveScriptDebug, riid)) + return E_NOINTERFACE; + + trace("QI(%s)\n", wine_dbgstr_guid(riid)); + return E_NOINTERFACE; +} + +static HRESULT WINAPI ActiveScript2_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass) +{ + HRESULT hres; + + CHECK_EXPECT(SetScriptSite2); + ok(pass != NULL, "pass == NULL\n"); + ok(pass != site, "pass == site\n"); + + hres = IActiveScriptSite_OnStateChange(pass, (state2 = SCRIPTSTATE_INITIALIZED)); + ok(hres == S_OK, "OnStateChange failed: %08lx\n", hres); + + site2 = pass; + IActiveScriptSite_AddRef(site2); + return S_OK; +} + +static HRESULT WINAPI ActiveScript2_SetScriptState(IActiveScript *iface, SCRIPTSTATE ss) +{ + HRESULT hres = IActiveScriptSite_OnStateChange(site2, (state2 = ss)); + ok(hres == S_OK, "OnStateChange failed: %08lx\n", hres); + return S_OK; +} + +static HRESULT WINAPI ActiveScript2_GetScriptState(IActiveScript *iface, SCRIPTSTATE *pssState) +{ + *pssState = state2; + return S_OK; +} + +static HRESULT WINAPI ActiveScript2_Close(IActiveScript *iface) +{ + CHECK_EXPECT(Close2); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScript2_AddNamedItem(IActiveScript *iface, LPCOLESTR pstrName, DWORD dwFlags) +{ + IHTMLWindow2 *window, *window2; + IUnknown *unk = NULL; + HRESULT hres; + + CHECK_EXPECT(AddNamedItem2); + ok(!wcscmp(pstrName, L"window"), "pstrName = %s\n", wine_dbgstr_w(pstrName)); + ok(dwFlags == (SCRIPTITEM_ISVISIBLE | SCRIPTITEM_ISSOURCE | SCRIPTITEM_GLOBALMEMBERS), "dwFlags = %lx\n", dwFlags); + + hres = IActiveScriptSite_GetItemInfo(site2, L"window", SCRIPTINFO_IUNKNOWN, &unk, NULL); + ok(hres == S_OK, "GetItemInfo failed: %08lx\n", hres); + ok(unk != NULL, "unk == NULL\n"); + + /* Native is pretty broken here, it gives a different IUnknown than first site's SCRIPTINFO_IUNKNOWN, + * and querying for IDispatchEx gives different interfaces on both these *and* our window_dispex! + * That said, querying for IHTMLWindow2 *does* give the same interface for both?!? + */ + hres = IDispatchEx_QueryInterface(window_dispex, &IID_IHTMLWindow2, (void**)&window); + ok(hres == S_OK, "Could not get IHTMLWindow2 interface: %08lx\n", hres); + hres = IUnknown_QueryInterface(unk, &IID_IHTMLWindow2, (void**)&window2); + ok(hres == S_OK, "Could not get IHTMLWindow2 interface: %08lx\n", hres); + ok(window == window2, "first site window != second site window\n"); + IHTMLWindow2_Release(window2); + IHTMLWindow2_Release(window); + + IUnknown_Release(unk); + + /* IE8 */ + CHECK_CALLED_BROKEN(SetProperty_ABBREVIATE_GLOBALNAME_RESOLUTION_TRUE); + SET_EXPECT(SetProperty2_ABBREVIATE_GLOBALNAME_RESOLUTION_FALSE); + return S_OK; +} + +static HRESULT WINAPI ActiveScript2_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName, IDispatch **ppdisp) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static const IActiveScriptVtbl ActiveScript2Vtbl = { + ActiveScript2_QueryInterface, + ActiveScript_AddRef, + ActiveScript_Release, + ActiveScript2_SetScriptSite, + ActiveScript_GetScriptSite, + ActiveScript2_SetScriptState, + ActiveScript2_GetScriptState, + ActiveScript2_Close, + ActiveScript2_AddNamedItem, + ActiveScript_AddTypeLib, + ActiveScript2_GetScriptDispatch, + ActiveScript_GetCurrentScriptThreadID, + ActiveScript_GetScriptThreadID, + ActiveScript_GetScriptThreadState, + ActiveScript_InterruptScriptThread, + ActiveScript_Clone +}; + +static IActiveScript ActiveScript2 = { &ActiveScript2Vtbl }; + static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) { *ppv = NULL; @@ -3388,7 +3655,25 @@ static const IClassFactoryVtbl ClassFactoryVtbl = { ClassFactory_LockServer }; -static IClassFactory script_cf = { &ClassFactoryVtbl }; +static HRESULT WINAPI ClassFactory2_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv) +{ + CHECK_EXPECT(CreateInstance2); + + ok(!outer, "outer = %p\n", outer); + ok(IsEqualGUID(&IID_IActiveScript, riid), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = &ActiveScript2; + return S_OK; +} + +static const IClassFactoryVtbl ClassFactory2Vtbl = { + ClassFactory_QueryInterface, + ClassFactory_AddRef, + ClassFactory_Release, + ClassFactory2_CreateInstance, + ClassFactory_LockServer +}; + +static IClassFactory script_cf[] = { { &ClassFactoryVtbl }, { &ClassFactory2Vtbl } }; typedef struct { IInternetProtocolEx IInternetProtocolEx_iface; @@ -3901,7 +4186,8 @@ static IClassFactory protocol_cf = { &ProtocolCFVtbl }; static const char simple_script_str[] = "" "

" - "" + "" + "" ""; static void test_exec_script(IHTMLDocument2 *doc, const WCHAR *codew, const WCHAR *langw) @@ -3945,49 +4231,72 @@ static void test_simple_script(void) return; SET_EXPECT(CreateInstance); + SET_EXPECT(CreateInstance2); SET_EXPECT(GetInterfaceSafetyOptions); SET_EXPECT(SetInterfaceSafetyOptions); + SET_EXPECT(GetInterfaceSafetyOptions2); + SET_EXPECT(SetInterfaceSafetyOptions2); SET_EXPECT(SetProperty_INVOKEVERSIONING); /* IE8 */ + SET_EXPECT(SetProperty2_INVOKEVERSIONING); /* IE8 */ SET_EXPECT(SetProperty_HACK_TRIDENTEVENTSINK); + SET_EXPECT(SetProperty2_HACK_TRIDENTEVENTSINK); SET_EXPECT(InitNew); + SET_EXPECT(InitNew2); SET_EXPECT(SetScriptSite); + SET_EXPECT(SetScriptSite2); SET_EXPECT(GetScriptState); SET_EXPECT(SetScriptState_STARTED); SET_EXPECT(AddNamedItem); + SET_EXPECT(AddNamedItem2); SET_EXPECT(SetProperty_ABBREVIATE_GLOBALNAME_RESOLUTION_TRUE); /* IE8 */ SET_EXPECT(ParseScriptText_script); + SET_EXPECT(ParseScriptText_script2); SET_EXPECT(SetScriptState_CONNECTED); load_doc(doc, simple_script_str); CHECK_CALLED(CreateInstance); + CHECK_CALLED(CreateInstance2); CHECK_CALLED(GetInterfaceSafetyOptions); CHECK_CALLED(SetInterfaceSafetyOptions); + CHECK_CALLED(GetInterfaceSafetyOptions2); + CHECK_CALLED(SetInterfaceSafetyOptions2); CHECK_CALLED_BROKEN(SetProperty_INVOKEVERSIONING); /* IE8 */ + CHECK_CALLED_BROKEN(SetProperty2_INVOKEVERSIONING); /* IE8 */ CHECK_CALLED(SetProperty_HACK_TRIDENTEVENTSINK); + CHECK_CALLED(SetProperty2_HACK_TRIDENTEVENTSINK); CHECK_CALLED(InitNew); + CHECK_CALLED(InitNew2); CHECK_CALLED(SetScriptSite); + CHECK_CALLED(SetScriptSite2); CHECK_CALLED(GetScriptState); CHECK_CALLED(SetScriptState_STARTED); CHECK_CALLED(AddNamedItem); - CHECK_CALLED_BROKEN(SetProperty_ABBREVIATE_GLOBALNAME_RESOLUTION_TRUE); /* IE8 */ + CHECK_CALLED(AddNamedItem2); + CHECK_CALLED_BROKEN(SetProperty_ABBREVIATE_GLOBALNAME_RESOLUTION_FALSE); /* IE8 */ + CHECK_CALLED_BROKEN(SetProperty2_ABBREVIATE_GLOBALNAME_RESOLUTION_FALSE); /* IE8 */ CHECK_CALLED(ParseScriptText_script); + CHECK_CALLED(ParseScriptText_script2); CHECK_CALLED(SetScriptState_CONNECTED); - test_exec_script(doc, L"execScript call", L"TestScript"); + test_exec_script(doc, L"execScript call", L"TestScript1"); if(site) IActiveScriptSite_Release(site); + if(site2) + IActiveScriptSite_Release(site2); if(window_dispex) IDispatchEx_Release(window_dispex); SET_EXPECT(SetScriptState_DISCONNECTED); SET_EXPECT(Close); + SET_EXPECT(Close2); IHTMLDocument2_Release(doc); CHECK_CALLED(SetScriptState_DISCONNECTED); CHECK_CALLED(Close); + CHECK_CALLED(Close2); } static void run_from_moniker(IMoniker *mon) @@ -4193,16 +4502,33 @@ static void run_js_tests(void) static BOOL init_registry(BOOL init) { - return init_key("TestScript\\CLSID", TESTSCRIPT_CLSID, init) - && init_key("CLSID\\"TESTSCRIPT_CLSID"\\Implemented Categories\\{F0B7A1A1-9847-11CF-8F20-00805F2CD064}", - NULL, init) - && init_key("CLSID\\"TESTSCRIPT_CLSID"\\Implemented Categories\\{F0B7A1A2-9847-11CF-8F20-00805F2CD064}", - NULL, init); + static const WCHAR fmt[] = L"CLSID\\%s\\Implemented Categories\\{%08lX-9847-11CF-8F20-00805F2CD064}"; + WCHAR *clsid, buf[ARRAY_SIZE(fmt) + 40]; + BOOL ret = TRUE; + HRESULT hres; + unsigned i; + + for(i = 0; i < ARRAY_SIZE(CLSID_TestScript) && ret; i++) { + hres = StringFromCLSID(&CLSID_TestScript[i], &clsid); + ok(hres == S_OK, "StringFromCLSID failed: %08lx\n", hres); + + swprintf(buf, ARRAY_SIZE(buf), L"TestScript%u\\CLSID", i + 1); + if((ret = init_key(buf, clsid, init))) { + swprintf(buf, ARRAY_SIZE(buf), fmt, clsid, 0xf0b7a1a1); + if((ret = init_key(buf, NULL, init))) { + swprintf(buf, ARRAY_SIZE(buf), fmt, clsid, 0xf0b7a1a2); + ret = init_key(buf, NULL, init); + } + } + CoTaskMemFree(clsid); + } + return ret; } static BOOL register_script_engine(void) { DWORD regid; + unsigned i; HRESULT hres; if(!init_registry(TRUE)) { @@ -4210,9 +4536,11 @@ static BOOL register_script_engine(void) return FALSE; } - hres = CoRegisterClassObject(&CLSID_TestScript, (IUnknown *)&script_cf, - CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®id); - ok(hres == S_OK, "Could not register script engine: %08lx\n", hres); + for(i = 0; i < ARRAY_SIZE(CLSID_TestScript); i++) { + hres = CoRegisterClassObject(&CLSID_TestScript[i], (IUnknown *)&script_cf[i], + CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®id); + ok(hres == S_OK, "Could not register TestScript%u engine: %08lx\n", i + 1, hres); + } return TRUE; } @@ -4299,7 +4627,7 @@ START_TEST(script) test_simple_script(); init_registry(FALSE); }else { - skip("Could not register TestScript engine\n"); + skip("Could not register TestScript engines\n"); } run_js_tests(); }else { From b43b3d8c5dc7c4f1c6787f2807adfe7bafc13b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:55 +0200 Subject: [PATCH 0816/2777] jscript: Implement SID_GetCaller for QueryService. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/dispex.c | 9 ++ dlls/jscript/jscript.c | 17 +++- dlls/jscript/jscript.h | 3 + dlls/jscript/jsutils.c | 9 ++ dlls/jscript/tests/caller.c | 158 ++++++++++++++++++++++++++++++++++-- 5 files changed, 187 insertions(+), 9 deletions(-) diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 2c35f2ae9cc..4b56ec9fc70 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -1900,6 +1900,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { jsdisp_t *This = impl_from_IDispatchEx(iface); + IServiceProvider *prev_caller; dispex_prop_t *prop; jsexcept_t ei; HRESULT hres; @@ -1917,6 +1918,11 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc enter_script(This->ctx, &ei); + prev_caller = This->ctx->jscaller->caller; + This->ctx->jscaller->caller = pspCaller; + if(pspCaller) + IServiceProvider_AddRef(pspCaller); + switch(wFlags) { case DISPATCH_METHOD|DISPATCH_PROPERTYGET: wFlags = DISPATCH_METHOD; @@ -2000,6 +2006,9 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc break; } + This->ctx->jscaller->caller = prev_caller; + if(pspCaller) + IServiceProvider_Release(pspCaller); return leave_script(This->ctx, hres); } diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index f5331a13b96..401f6ca85b0 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -428,6 +428,17 @@ static void release_named_item_list(JScript *This) } } +static HRESULT exec_global_code(script_ctx_t *ctx, bytecode_t *code, jsval_t *r) +{ + IServiceProvider *prev_caller = ctx->jscaller->caller; + HRESULT hres; + + ctx->jscaller->caller = SP_CALLER_UNINITIALIZED; + hres = exec_source(ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, 0, NULL, r); + ctx->jscaller->caller = prev_caller; + return hres; +} + static void exec_queued_code(JScript *This) { bytecode_t *iter; @@ -436,7 +447,7 @@ static void exec_queued_code(JScript *This) LIST_FOR_EACH_ENTRY(iter, &This->queued_code, bytecode_t, entry) { enter_script(This->ctx, &ei); - hres = exec_source(This->ctx, EXEC_GLOBAL, iter, &iter->global_code, NULL, NULL, NULL, 0, NULL, NULL); + hres = exec_global_code(This->ctx, iter, NULL); leave_script(This->ctx, hres); if(FAILED(hres)) break; @@ -1103,7 +1114,7 @@ static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface, if(dwFlags & SCRIPTTEXT_ISEXPRESSION) { jsval_t r; - hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, 0, NULL, &r); + hres = exec_global_code(This->ctx, code, &r); if(SUCCEEDED(hres)) { if(pvarResult) hres = jsval_to_variant(r, pvarResult); @@ -1122,7 +1133,7 @@ static HRESULT WINAPI JScriptParse_ParseScriptText(IActiveScriptParse *iface, if(!pvarResult && !is_started(This->ctx)) { list_add_tail(&This->queued_code, &code->entry); }else { - hres = exec_source(This->ctx, EXEC_GLOBAL, code, &code->global_code, NULL, NULL, NULL, 0, NULL, NULL); + hres = exec_global_code(This->ctx, code, NULL); if(code->is_persistent) list_add_tail(&This->persistent_code, &code->entry); else diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index b633f390508..36a6d23c917 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -331,12 +331,15 @@ typedef struct { void release_cc(cc_ctx_t*) DECLSPEC_HIDDEN; +#define SP_CALLER_UNINITIALIZED ((IServiceProvider*)IntToPtr(-1)) + typedef struct { IServiceProvider IServiceProvider_iface; LONG ref; script_ctx_t *ctx; + IServiceProvider *caller; } JSCaller; #include "jsval.h" diff --git a/dlls/jscript/jsutils.c b/dlls/jscript/jsutils.c index 3dfcd08f14c..a26b63833ee 100644 --- a/dlls/jscript/jsutils.c +++ b/dlls/jscript/jsutils.c @@ -1034,6 +1034,14 @@ static HRESULT WINAPI JSCaller_QueryService(IServiceProvider *iface, REFGUID gui { JSCaller *This = impl_from_IServiceProvider(iface); + if(IsEqualGUID(guidService, &SID_GetCaller)) { + TRACE("(%p)->(SID_GetCaller)\n", This); + *ppv = NULL; + if(!This->caller) + return S_OK; + return (This->caller == SP_CALLER_UNINITIALIZED) ? E_NOINTERFACE : IServiceProvider_QueryInterface(This->caller, riid, ppv); + } + if(IsEqualGUID(guidService, &SID_VariantConversion) && This->ctx && This->ctx->active_script) { TRACE("(%p)->(SID_VariantConversion)\n", This); return IActiveScript_QueryInterface(This->ctx->active_script, riid, ppv); @@ -1063,6 +1071,7 @@ HRESULT create_jscaller(script_ctx_t *ctx) ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl; ret->ref = 1; ret->ctx = ctx; + ret->caller = SP_CALLER_UNINITIALIZED; ctx->jscaller = ret; return S_OK; diff --git a/dlls/jscript/tests/caller.c b/dlls/jscript/tests/caller.c index 836f5a820a1..a70ab5bae1e 100644 --- a/dlls/jscript/tests/caller.c +++ b/dlls/jscript/tests/caller.c @@ -74,14 +74,22 @@ static const CLSID CLSID_JScript = #define CLEAR_CALLED(func) \ expect_ ## func = called_ ## func = FALSE +DEFINE_EXPECT(sp_caller_QI_NULL); DEFINE_EXPECT(testArgConv); +DEFINE_EXPECT(testGetCaller); +DEFINE_EXPECT(testGetCaller_no_args); +DEFINE_EXPECT(testGetCaller_two_args); DEFINE_EXPECT(OnEnterScript); DEFINE_EXPECT(OnLeaveScript); +static IActiveScriptParse *active_script_parser; static IVariantChangeType *script_change_type; static IDispatch *stored_obj; +static IDispatchEx *test_get_caller_func; +static IServiceProvider *test_get_caller_sp; #define DISPID_TEST_TESTARGCONV 0x1000 +#define DISPID_TEST_TESTGETCALLER 0x1001 typedef struct { int int_result; @@ -254,6 +262,55 @@ static void test_caller(IServiceProvider *caller, IDispatch *arg_obj) IVariantChangeType_Release(change_type); } +static IServiceProvider sp_caller_obj; + +static HRESULT WINAPI sp_caller_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IServiceProvider, riid)) + *ppv = &sp_caller_obj; + else { + ok(IsEqualGUID(&IID_NULL, riid), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + CHECK_EXPECT(sp_caller_QI_NULL); + *ppv = NULL; + return E_NOINTERFACE; + } + + return S_OK; +} + +static ULONG WINAPI sp_caller_AddRef(IServiceProvider *iface) +{ + return 2; +} + +static ULONG WINAPI sp_caller_Release(IServiceProvider *iface) +{ + return 1; +} + +static HRESULT WINAPI sp_caller_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + if(IsEqualGUID(guidService, &SID_GetCaller)) { + ok(IsEqualGUID(riid, &IID_IServiceProvider), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return S_OK; + } + + ok(0, "unexpected guidService %s with riid %s\n", wine_dbgstr_guid(guidService), wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl sp_caller_vtbl = { + sp_caller_QueryInterface, + sp_caller_AddRef, + sp_caller_Release, + sp_caller_QueryService +}; + +static IServiceProvider sp_caller_obj = { &sp_caller_vtbl }; + static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) { if(IsEqualGUID(riid, &IID_IUnknown)) { @@ -350,6 +407,11 @@ static HRESULT WINAPI Test_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD gr *pid = DISPID_TEST_TESTARGCONV; return S_OK; } + if(!lstrcmpW(bstrName, L"testGetCaller")) { + ok(grfdex == fdexNameCaseSensitive, "grfdex = %lx\n", grfdex); + *pid = DISPID_TEST_TESTGETCALLER; + return S_OK; + } return E_NOTIMPL; } @@ -357,6 +419,9 @@ static HRESULT WINAPI Test_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD gr static HRESULT WINAPI Test_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { + IServiceProvider *caller = (void*)0xdeadbeef; + HRESULT hres; + ok(pspCaller != NULL, "pspCaller == NULL\n"); switch(id) { @@ -380,6 +445,66 @@ static HRESULT WINAPI Test_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WO IDispatch_AddRef(stored_obj); break; + case DISPID_TEST_TESTGETCALLER: + ok(wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(!pvarRes, "pvarRes != NULL\n"); + ok(pei != NULL, "pei == NULL\n"); + + if(pdp->cArgs == 0) { + void *iface = (void*)0xdeadbeef; + + CHECK_EXPECT(testGetCaller_no_args); + CHECK_CALLED(OnEnterScript); + + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + SET_EXPECT(testGetCaller_two_args); + hres = IActiveScriptParse_ParseScriptText(active_script_parser, L"testGetCaller(1,2)", + NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + ok(hres == S_OK, "ParseScriptText failed: %08lx\n", hres); + CHECK_CALLED(testGetCaller_two_args); + CHECK_CALLED(OnLeaveScript); + CHECK_CALLED(OnEnterScript); + SET_EXPECT(OnLeaveScript); + + hres = IServiceProvider_QueryService(pspCaller, &SID_GetCaller, &IID_IServiceProvider, (void**)&caller); + ok(hres == S_OK, "Could not get SID_GetCaller service: %08lx\n", hres); + ok(caller == test_get_caller_sp, "caller != test_get_caller_sp\n"); + if(caller) IServiceProvider_Release(caller); + + if(test_get_caller_sp) + SET_EXPECT(sp_caller_QI_NULL); + hres = IServiceProvider_QueryService(pspCaller, &SID_GetCaller, &IID_NULL, &iface); + ok(hres == (test_get_caller_sp ? E_NOINTERFACE : S_OK), "Could not query SID_GetCaller with IID_NULL: %08lx\n", hres); + ok(iface == NULL, "iface != NULL\n"); + if(test_get_caller_sp) + CHECK_CALLED(sp_caller_QI_NULL); + }else if(pdp->cArgs == 1) { + CHECK_EXPECT(testGetCaller); + ok(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg)); + + hres = IServiceProvider_QueryService(pspCaller, &SID_GetCaller, &IID_IServiceProvider, (void**)&caller); + ok(hres == E_NOINTERFACE, "QueryService(SID_GetCaller) returned: %08lx\n", hres); + ok(caller == NULL, "caller != NULL\n"); + + hres = IDispatch_QueryInterface(V_DISPATCH(pdp->rgvarg), &IID_IDispatchEx, (void**)&test_get_caller_func); + ok(hres == S_OK, "Could not get IDispatchEx interface: %08lx\n", hres); + }else { + CHECK_EXPECT(testGetCaller_two_args); + ok(pdp->cArgs == 2, "cArgs = %d\n", pdp->cArgs); + ok(V_VT(&pdp->rgvarg[0]) == VT_I4, "V_VT(rgvarg[0]) = %d\n", V_VT(&pdp->rgvarg[0])); + ok(V_VT(&pdp->rgvarg[1]) == VT_I4, "V_VT(rgvarg[1]) = %d\n", V_VT(&pdp->rgvarg[1])); + ok(V_I4(&pdp->rgvarg[0]) == 2, "V_I4(rgvarg[0]) = %ld\n", V_I4(&pdp->rgvarg[0])); + ok(V_I4(&pdp->rgvarg[1]) == 1, "V_I4(rgvarg[1]) = %ld\n", V_I4(&pdp->rgvarg[1])); + + hres = IServiceProvider_QueryService(pspCaller, &SID_GetCaller, &IID_IServiceProvider, (void**)&caller); + ok(hres == E_NOINTERFACE, "QueryService(SID_GetCaller) returned: %08lx\n", hres); + ok(caller == NULL, "caller != NULL\n"); + } + break; + default: ok(0, "unexpected call\n"); return E_NOTIMPL; @@ -542,22 +667,25 @@ static IActiveScriptParse *create_script(void) static void run_scripts(void) { - IActiveScriptParse *parser; + DISPPARAMS dp = { 0 }; HRESULT hres; - parser = create_script(); + active_script_parser = create_script(); - hres = IActiveScriptParse_QueryInterface(parser, &IID_IVariantChangeType, (void**)&script_change_type); + hres = IActiveScriptParse_QueryInterface(active_script_parser, &IID_IVariantChangeType, (void**)&script_change_type); ok(hres == S_OK, "Could not get IVariantChangeType iface: %08lx\n", hres); SET_EXPECT(OnEnterScript); /* checked in callback */ SET_EXPECT(testArgConv); - parse_script(parser, + SET_EXPECT(testGetCaller); + parse_script(active_script_parser, L"var obj = {" L" toString: function() { return 'strval'; }," L" valueOf: function() { return 10; }" L"};" - L"testArgConv(obj);"); + L"testArgConv(obj);" + L"testGetCaller(function() { testGetCaller(); });"); + CHECK_CALLED(testGetCaller); CHECK_CALLED(testArgConv); CHECK_CALLED(OnLeaveScript); /* set in callback */ @@ -565,7 +693,25 @@ static void run_scripts(void) IDispatch_Release(stored_obj); IVariantChangeType_Release(script_change_type); - IActiveScriptParse_Release(parser); + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + SET_EXPECT(testGetCaller_no_args); + hres = IDispatchEx_InvokeEx(test_get_caller_func, DISPID_VALUE, 0, DISPATCH_METHOD, &dp, NULL, NULL, NULL); + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + CHECK_CALLED(testGetCaller_no_args); + CHECK_CALLED(OnLeaveScript); + test_get_caller_sp = &sp_caller_obj; + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + SET_EXPECT(testGetCaller_no_args); + hres = IDispatchEx_InvokeEx(test_get_caller_func, DISPID_VALUE, 0, DISPATCH_METHOD, &dp, NULL, NULL, test_get_caller_sp); + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + CHECK_CALLED(testGetCaller_no_args); + CHECK_CALLED(OnLeaveScript); + IDispatchEx_Release(test_get_caller_func); + + IActiveScriptParse_Release(active_script_parser); + active_script_parser = NULL; } static BOOL check_jscript(void) From aee70ef7793f01c8a1fd043bd5a9f6b9f740bc73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:55 +0200 Subject: [PATCH 0817/2777] vbscript: Add a ServiceProvider stub. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/vbscript/vbdisp.c | 4 +- dlls/vbscript/vbscript.c | 83 ++++++++++++++++++++++++++++++++++++++++ dlls/vbscript/vbscript.h | 7 ++++ 3 files changed, 92 insertions(+), 2 deletions(-) diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index e19ed2b53d4..13236ad4b29 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -1661,7 +1661,7 @@ HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, DISPPARAMS *dp, hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); if(SUCCEEDED(hres)) { - hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, dp, retv, &ei, NULL /* CALLER_FIXME */); + hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, dp, retv, &ei, &ctx->vbcaller->IServiceProvider_iface); IDispatchEx_Release(dispex); }else { UINT err = 0; @@ -1699,7 +1699,7 @@ HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); if(SUCCEEDED(hres)) { - hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, dp, NULL, &ei, NULL /* FIXME! */); + hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, dp, NULL, &ei, &ctx->vbcaller->IServiceProvider_iface); IDispatchEx_Release(dispex); }else { UINT err = 0; diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index b6364410931..d010ba4b51d 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -366,6 +366,80 @@ static void decrease_state(VBScript *This, SCRIPTSTATE state) } } +static inline struct vbcaller *vbcaller_from_IServiceProvider(IServiceProvider *iface) +{ + return CONTAINING_RECORD(iface, struct vbcaller, IServiceProvider_iface); +} + +static HRESULT WINAPI vbcaller_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + struct vbcaller *This = vbcaller_from_IServiceProvider(iface); + + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IServiceProvider, riid)) { + *ppv = &This->IServiceProvider_iface; + }else { + WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI vbcaller_AddRef(IServiceProvider *iface) +{ + struct vbcaller *This = vbcaller_from_IServiceProvider(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI vbcaller_Release(IServiceProvider *iface) +{ + struct vbcaller *This = vbcaller_from_IServiceProvider(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if(!ref) + free(This); + + return ref; +} + +static HRESULT WINAPI vbcaller_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + struct vbcaller *This = vbcaller_from_IServiceProvider(iface); + + FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv); + + *ppv = NULL; + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl ServiceProviderVtbl = { + vbcaller_QueryInterface, + vbcaller_AddRef, + vbcaller_Release, + vbcaller_QueryService +}; + +static struct vbcaller *create_vbcaller(void) +{ + struct vbcaller *ret; + + ret = malloc(sizeof(*ret)); + if(ret) { + ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl; + ret->ref = 1; + } + return ret; +} + static inline VBScriptError *impl_from_IActiveScriptError(IActiveScriptError *iface) { return CONTAINING_RECORD(iface, VBScriptError, IActiveScriptError_iface); @@ -545,6 +619,7 @@ static ULONG WINAPI VBScript_Release(IActiveScript *iface) if(!ref) { decrease_state(This, SCRIPTSTATE_CLOSED); detach_global_objects(This->ctx); + IServiceProvider_Release(&This->ctx->vbcaller->IServiceProvider_iface); free(This->ctx); free(This); } @@ -1102,6 +1177,7 @@ static const IObjectSafetyVtbl VBScriptSafetyVtbl = { HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppv) { + struct vbcaller *vbcaller; script_ctx_t *ctx; VBScript *ret; HRESULT hres; @@ -1112,6 +1188,11 @@ HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pU if(!ret) return E_OUTOFMEMORY; + if(!(vbcaller = create_vbcaller())) { + free(ret); + return E_OUTOFMEMORY; + } + ret->IActiveScript_iface.lpVtbl = &VBScriptVtbl; ret->IActiveScriptDebug_iface.lpVtbl = &VBScriptDebugVtbl; ret->IActiveScriptParse_iface.lpVtbl = &VBScriptParseVtbl; @@ -1123,10 +1204,12 @@ HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pU ctx = ret->ctx = calloc(1, sizeof(*ctx)); if(!ctx) { + IServiceProvider_Release(&vbcaller->IServiceProvider_iface); free(ret); return E_OUTOFMEMORY; } + ctx->vbcaller = vbcaller; ctx->safeopt = INTERFACE_USES_DISPEX; list_init(&ctx->objects); list_init(&ctx->code_list); diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 8286b37bbab..c42b0d31391 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -180,12 +180,19 @@ static inline VARIANT *get_arg(DISPPARAMS *dp, DWORD i) return dp->rgvarg + dp->cArgs-i-1; } +struct vbcaller { + IServiceProvider IServiceProvider_iface; + + LONG ref; +}; + struct _script_ctx_t { IActiveScriptSite *site; LCID lcid; UINT codepage; IInternetHostSecurityManager *secmgr; + struct vbcaller *vbcaller; DWORD safeopt; ScriptDisp *script_obj; From 5dfdddac337e86c5e31d0bbea93026f7a6bb25c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:55 +0200 Subject: [PATCH 0818/2777] vbscript: Implement SID_GetCaller for QueryService. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/vbscript/tests/Makefile.in | 1 + dlls/vbscript/tests/caller.c | 524 ++++++++++++++++++++++++++++++++ dlls/vbscript/vbdisp.c | 45 ++- dlls/vbscript/vbscript.c | 17 +- dlls/vbscript/vbscript.h | 4 + 5 files changed, 582 insertions(+), 9 deletions(-) create mode 100644 dlls/vbscript/tests/caller.c diff --git a/dlls/vbscript/tests/Makefile.in b/dlls/vbscript/tests/Makefile.in index 35379baf198..927280bef22 100644 --- a/dlls/vbscript/tests/Makefile.in +++ b/dlls/vbscript/tests/Makefile.in @@ -2,6 +2,7 @@ TESTDLL = vbscript.dll IMPORTS = oleaut32 ole32 advapi32 C_SRCS = \ + caller.c \ createobj.c \ run.c \ vbscript.c diff --git a/dlls/vbscript/tests/caller.c b/dlls/vbscript/tests/caller.c new file mode 100644 index 00000000000..d5c723e50cf --- /dev/null +++ b/dlls/vbscript/tests/caller.c @@ -0,0 +1,524 @@ +/* + * Copyright 2023 Gabriel Ivăncescu 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 + */ + +#include + +#define COBJMACROS +#define CONST_VTABLE + +#include +#include +#include +#include + +#include "wine/test.h" + +#ifdef _WIN64 + +#define IActiveScriptParse_QueryInterface IActiveScriptParse64_QueryInterface +#define IActiveScriptParse_Release IActiveScriptParse64_Release +#define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew +#define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText + +#else + +#define IActiveScriptParse_QueryInterface IActiveScriptParse32_QueryInterface +#define IActiveScriptParse_Release IActiveScriptParse32_Release +#define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew +#define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText + +#endif + +extern const CLSID CLSID_VBScript; + +#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + expect_ ## func = TRUE + +#define CHECK_EXPECT2(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func = TRUE; \ + }while(0) + +#define CHECK_EXPECT(func) \ + do { \ + CHECK_EXPECT2(func); \ + expect_ ## func = FALSE; \ + }while(0) + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +#define CLEAR_CALLED(func) \ + expect_ ## func = called_ ## func = FALSE + +DEFINE_EXPECT(sp_caller_QI_NULL); +DEFINE_EXPECT(testGetCaller); +DEFINE_EXPECT(testGetCaller_no_args); +DEFINE_EXPECT(testGetCaller_two_args); +DEFINE_EXPECT(OnEnterScript); +DEFINE_EXPECT(OnLeaveScript); + +static IActiveScript *active_script; +static IServiceProvider *test_get_caller_sp; + +#define DISPID_TEST_TESTGETCALLER 0x1000 + +#define parse_script(a,s) _parse_script(__LINE__,a,s) +static void _parse_script(unsigned line, IActiveScript *active_script, const WCHAR *script) +{ + IActiveScriptParse *parser; + HRESULT hres; + + hres = IActiveScript_QueryInterface(active_script, &IID_IActiveScriptParse, (void**)&parser); + ok_(__FILE__,line)(hres == S_OK, "Could not get IActiveScriptParse: %08lx\n", hres); + + hres = IActiveScriptParse_ParseScriptText(parser, script, NULL, NULL, NULL, 0, 0, 0, NULL, NULL); + ok_(__FILE__,line)(hres == S_OK, "ParseScriptText failed: %08lx\n", hres); + IActiveScriptParse_Release(parser); +} + +static IServiceProvider sp_caller_obj; + +static HRESULT WINAPI sp_caller_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IServiceProvider, riid)) + *ppv = &sp_caller_obj; + else { + ok(IsEqualGUID(&IID_NULL, riid), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + CHECK_EXPECT(sp_caller_QI_NULL); + *ppv = NULL; + return E_NOINTERFACE; + } + + return S_OK; +} + +static ULONG WINAPI sp_caller_AddRef(IServiceProvider *iface) +{ + return 2; +} + +static ULONG WINAPI sp_caller_Release(IServiceProvider *iface) +{ + return 1; +} + +static HRESULT WINAPI sp_caller_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + if(IsEqualGUID(guidService, &SID_GetCaller)) { + ok(IsEqualGUID(riid, &IID_IServiceProvider), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return S_OK; + } + + ok(0, "unexpected guidService %s with riid %s\n", wine_dbgstr_guid(guidService), wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl sp_caller_vtbl = { + sp_caller_QueryInterface, + sp_caller_AddRef, + sp_caller_Release, + sp_caller_QueryService +}; + +static IServiceProvider sp_caller_obj = { &sp_caller_vtbl }; + +static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown)) { + *ppv = iface; + }else if(IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, &IID_IDispatchEx)) { + *ppv = iface; + }else if(IsEqualGUID(&IID_IObjectSafety, riid)) { + ok(0, "Unexpected IID_IObjectSafety query\n"); + }else { + *ppv = NULL; + return E_NOINTERFACE; + } + + return S_OK; +} + +static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface) +{ + return 2; +} + +static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface) +{ + return 1; +} + +static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, LPOLESTR *rgszNames, + UINT cNames, LCID lcid, DISPID *rgDispId) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Test_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) +{ + if(!lstrcmpW(bstrName, L"testGetCaller")) { + ok(grfdex == fdexNameCaseInsensitive, "grfdex = %lx\n", grfdex); + *pid = DISPID_TEST_TESTGETCALLER; + return S_OK; + } + + return E_NOTIMPL; +} + +static HRESULT WINAPI Test_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + IServiceProvider *caller = (void*)0xdeadbeef; + HRESULT hres; + + ok(pspCaller != NULL, "pspCaller == NULL\n"); + + switch(id) { + case DISPID_TEST_TESTGETCALLER: + ok(wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags); + ok(pdp != NULL, "pdp == NULL\n"); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(!pvarRes, "pvarRes != NULL\n"); + ok(pei != NULL, "pei == NULL\n"); + + if(pdp->cArgs == 0) { + void *iface = (void*)0xdeadbeef; + + CHECK_EXPECT(testGetCaller_no_args); + CHECK_CALLED(OnEnterScript); + + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + SET_EXPECT(testGetCaller_two_args); + parse_script(active_script, L"Call testGetCaller(1,2)"); + CHECK_CALLED(testGetCaller_two_args); + CHECK_CALLED(OnLeaveScript); + CHECK_CALLED(OnEnterScript); + SET_EXPECT(OnLeaveScript); + + hres = IServiceProvider_QueryService(pspCaller, &SID_GetCaller, &IID_IServiceProvider, (void**)&caller); + ok(hres == S_OK, "Could not get SID_GetCaller service: %08lx\n", hres); + ok(caller == test_get_caller_sp, "caller != test_get_caller_sp\n"); + if(caller) IServiceProvider_Release(caller); + + if(test_get_caller_sp) + SET_EXPECT(sp_caller_QI_NULL); + hres = IServiceProvider_QueryService(pspCaller, &SID_GetCaller, &IID_NULL, &iface); + ok(hres == (test_get_caller_sp ? E_NOINTERFACE : S_OK), "Could not query SID_GetCaller with IID_NULL: %08lx\n", hres); + ok(iface == NULL, "iface != NULL\n"); + if(test_get_caller_sp) + CHECK_CALLED(sp_caller_QI_NULL); + }else if(pdp->cArgs == 1) { + CHECK_EXPECT(testGetCaller); + ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs); + ok(V_VT(pdp->rgvarg) == VT_I2, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg)); + ok(V_I2(pdp->rgvarg) == 42, "V_I2(rgvarg) = %d\n", V_I2(pdp->rgvarg)); + + hres = IServiceProvider_QueryService(pspCaller, &SID_GetCaller, &IID_IServiceProvider, (void**)&caller); + ok(hres == E_NOINTERFACE, "QueryService(SID_GetCaller) returned: %08lx\n", hres); + ok(caller == NULL, "caller != NULL\n"); + }else { + CHECK_EXPECT(testGetCaller_two_args); + ok(pdp->cArgs == 2, "cArgs = %d\n", pdp->cArgs); + ok(V_VT(&pdp->rgvarg[0]) == VT_I2, "V_VT(rgvarg[0]) = %d\n", V_VT(&pdp->rgvarg[0])); + ok(V_VT(&pdp->rgvarg[1]) == VT_I2, "V_VT(rgvarg[1]) = %d\n", V_VT(&pdp->rgvarg[1])); + ok(V_I2(&pdp->rgvarg[0]) == 2, "V_I2(rgvarg[0]) = %d\n", V_I2(&pdp->rgvarg[0])); + ok(V_I2(&pdp->rgvarg[1]) == 1, "V_I2(rgvarg[1]) = %d\n", V_I2(&pdp->rgvarg[1])); + + hres = IServiceProvider_QueryService(pspCaller, &SID_GetCaller, &IID_IServiceProvider, (void**)&caller); + ok(hres == E_NOINTERFACE, "QueryService(SID_GetCaller) returned: %08lx\n", hres); + ok(caller == NULL, "caller != NULL\n"); + } + break; + + default: + ok(0, "unexpected call\n"); + return E_NOTIMPL; + } + + return S_OK; +} + +static IDispatchExVtbl testObjVtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + Test_GetDispID, + Test_InvokeEx, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static IDispatchEx testObj = { &testObjVtbl }; + +static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(&IID_IUnknown, riid)) { + *ppv = iface; + }else if(IsEqualGUID(&IID_IActiveScriptSite, riid)) { + *ppv = iface; + }else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface) +{ + return 2; +} + +static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface) +{ + return 1; +} + +static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid) +{ + *plcid = GetUserDefaultLCID(); + return S_OK; +} + +static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName, + DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti) +{ + ok(dwReturnMask == SCRIPTINFO_IUNKNOWN, "unexpected dwReturnMask %lx\n", dwReturnMask); + ok(!ppti, "ppti != NULL\n"); + ok(!lstrcmpW(pstrName, L"test"), "pstrName = %s\n", wine_dbgstr_w(pstrName)); + + *ppiunkItem = (IUnknown*)&testObj; + return S_OK; +} + +static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *pbstrVersion) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface, + const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE ssScriptState) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface) +{ + CHECK_EXPECT(OnEnterScript); + return E_NOTIMPL; +} + +static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface) +{ + CHECK_EXPECT(OnLeaveScript); + return E_NOTIMPL; +} + +static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = { + ActiveScriptSite_QueryInterface, + ActiveScriptSite_AddRef, + ActiveScriptSite_Release, + ActiveScriptSite_GetLCID, + ActiveScriptSite_GetItemInfo, + ActiveScriptSite_GetDocVersionString, + ActiveScriptSite_OnScriptTerminate, + ActiveScriptSite_OnStateChange, + ActiveScriptSite_OnScriptError, + ActiveScriptSite_OnEnterScript, + ActiveScriptSite_OnLeaveScript +}; + +static IActiveScriptSite ActiveScriptSite = { &ActiveScriptSiteVtbl }; + +static IActiveScript *create_script(void) +{ + IActiveScriptParse *parser; + IActiveScript *script; + HRESULT hres; + + hres = CoCreateInstance(&CLSID_VBScript, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, + &IID_IActiveScript, (void**)&script); + if(FAILED(hres)) + return NULL; + + hres = IActiveScript_QueryInterface(script, &IID_IActiveScriptParse, (void**)&parser); + ok(hres == S_OK, "Could not get IActiveScriptParse: %08lx\n", hres); + + hres = IActiveScriptParse_InitNew(parser); + ok(hres == S_OK, "InitNew failed: %08lx\n", hres); + IActiveScriptParse_Release(parser); + + hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite); + ok(hres == S_OK, "SetScriptSite failed: %08lx\n", hres); + + hres = IActiveScript_AddNamedItem(script, L"test", + SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS); + ok(hres == S_OK, "AddNamedItem failed: %08lx\n", hres); + + hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_STARTED); + ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08lx\n", hres); + + return script; +} + +static void run_scripts(void) +{ + DISPPARAMS dp = { 0 }; + IDispatchEx *dispex; + IDispatch *disp; + DISPID dispid; + HRESULT hres; + BSTR bstr; + + active_script = create_script(); + + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + SET_EXPECT(testGetCaller); + parse_script(active_script, + L"Sub testGetCallerFunc\nCall testGetCaller\nEnd Sub\n" + L"Call testGetCaller(42)"); + CHECK_CALLED(testGetCaller); + CHECK_CALLED(OnLeaveScript); + CHECK_CALLED(OnEnterScript); + + hres = IActiveScript_GetScriptDispatch(active_script, NULL, &disp); + ok(hres == S_OK, "GetScriptDispatch failed: %08lx\n", hres); + hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx: %08lx\n", hres); + IDispatch_Release(disp); + bstr = SysAllocString(L"testGetCallerFunc"); + hres = IDispatchEx_GetDispID(dispex, bstr, 0, &dispid); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + SysFreeString(bstr); + + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + SET_EXPECT(testGetCaller_no_args); + hres = IDispatchEx_InvokeEx(dispex, dispid, 0, DISPATCH_METHOD, &dp, NULL, NULL, NULL); + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + CHECK_CALLED(testGetCaller_no_args); + CHECK_CALLED(OnLeaveScript); + test_get_caller_sp = &sp_caller_obj; + SET_EXPECT(OnEnterScript); + SET_EXPECT(OnLeaveScript); + SET_EXPECT(testGetCaller_no_args); + hres = IDispatchEx_InvokeEx(dispex, dispid, 0, DISPATCH_METHOD, &dp, NULL, NULL, test_get_caller_sp); + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + CHECK_CALLED(testGetCaller_no_args); + CHECK_CALLED(OnLeaveScript); + IDispatchEx_Release(dispex); + + IActiveScript_Release(active_script); + active_script = NULL; +} + +START_TEST(caller) +{ + CoInitialize(NULL); + + run_scripts(); + + CoUninitialize(); +} diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index 13236ad4b29..0ede0cfd6ba 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -413,6 +413,8 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { vbdisp_t *This = impl_from_IDispatchEx(iface); + IServiceProvider *prev_caller; + HRESULT hres; TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); @@ -422,7 +424,17 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc if(pvarRes) V_VT(pvarRes) = VT_EMPTY; - return invoke_vbdisp(This, id, wFlags, TRUE, pdp, pvarRes); + prev_caller = This->desc->ctx->vbcaller->caller; + This->desc->ctx->vbcaller->caller = pspCaller; + if(pspCaller) + IServiceProvider_AddRef(pspCaller); + + hres = invoke_vbdisp(This, id, wFlags, TRUE, pdp, pvarRes); + + This->desc->ctx->vbcaller->caller = prev_caller; + if(pspCaller) + IServiceProvider_Release(pspCaller); + return hres; } static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) @@ -1414,6 +1426,7 @@ static HRESULT WINAPI ScriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface); + IServiceProvider *prev_caller; HRESULT hres; TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); @@ -1421,11 +1434,18 @@ static HRESULT WINAPI ScriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc if (!This->ctx) return E_UNEXPECTED; + prev_caller = This->ctx->vbcaller->caller; + This->ctx->vbcaller->caller = pspCaller; + if(pspCaller) + IServiceProvider_AddRef(pspCaller); + if (id & DISPID_FUNCTION_MASK) { id &= ~DISPID_FUNCTION_MASK; - if (id > This->global_funcs_cnt) - return DISP_E_MEMBERNOTFOUND; + if (id > This->global_funcs_cnt) { + hres = DISP_E_MEMBERNOTFOUND; + goto done; + } switch (wFlags) { @@ -1438,19 +1458,28 @@ static HRESULT WINAPI ScriptDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc hres = E_NOTIMPL; } - return hres; + goto done; } - if (id > This->global_vars_cnt) - return DISP_E_MEMBERNOTFOUND; + if (id > This->global_vars_cnt) { + hres = DISP_E_MEMBERNOTFOUND; + goto done; + } if (This->global_vars[id - 1]->is_const) { FIXME("const not supported\n"); - return E_NOTIMPL; + hres = E_NOTIMPL; + goto done; } - return invoke_variant_prop(This->ctx, &This->global_vars[id - 1]->v, wFlags, pdp, pvarRes); + hres = invoke_variant_prop(This->ctx, &This->global_vars[id - 1]->v, wFlags, pdp, pvarRes); + +done: + This->ctx->vbcaller->caller = prev_caller; + if(pspCaller) + IServiceProvider_Release(pspCaller); + return hres; } static HRESULT WINAPI ScriptDisp_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index d010ba4b51d..39a5e3b1648 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -96,6 +96,7 @@ static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res ScriptDisp *obj = ctx->script_obj; function_t *func_iter, **new_funcs; dynamic_var_t *var, **new_vars; + IServiceProvider *prev_caller; size_t cnt, i; HRESULT hres; @@ -185,7 +186,12 @@ static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res } code->pending_exec = FALSE; - return exec_script(ctx, TRUE, &code->main_code, NULL, NULL, res); + + prev_caller = ctx->vbcaller->caller; + ctx->vbcaller->caller = SP_CALLER_UNINITIALIZED; + hres = exec_script(ctx, TRUE, &code->main_code, NULL, NULL, res); + ctx->vbcaller->caller = prev_caller; + return hres; } static void exec_queued_code(script_ctx_t *ctx) @@ -415,6 +421,14 @@ static HRESULT WINAPI vbcaller_QueryService(IServiceProvider *iface, REFGUID gui { struct vbcaller *This = vbcaller_from_IServiceProvider(iface); + if(IsEqualGUID(guidService, &SID_GetCaller)) { + TRACE("(%p)->(SID_GetCaller)\n", This); + *ppv = NULL; + if(!This->caller) + return S_OK; + return (This->caller == SP_CALLER_UNINITIALIZED) ? E_NOINTERFACE : IServiceProvider_QueryInterface(This->caller, riid, ppv); + } + FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv); *ppv = NULL; @@ -436,6 +450,7 @@ static struct vbcaller *create_vbcaller(void) if(ret) { ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl; ret->ref = 1; + ret->caller = SP_CALLER_UNINITIALIZED; } return ret; } diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index c42b0d31391..5b0a2222767 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -180,10 +180,14 @@ static inline VARIANT *get_arg(DISPPARAMS *dp, DWORD i) return dp->rgvarg + dp->cArgs-i-1; } +#define SP_CALLER_UNINITIALIZED ((IServiceProvider*)IntToPtr(-1)) + struct vbcaller { IServiceProvider IServiceProvider_iface; LONG ref; + + IServiceProvider *caller; }; struct _script_ctx_t { From ae34f4d49d51666de5688d7398e392e9211b1675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:55 +0200 Subject: [PATCH 0819/2777] include/mshtml: Add the other IHTMLEventObj* interfaces. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- include/mshtmdid.h | 11 ++ include/mshtml.idl | 357 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 368 insertions(+) diff --git a/include/mshtmdid.h b/include/mshtmdid.h index 0e95a7d7165..5aca030bd10 100644 --- a/include/mshtmdid.h +++ b/include/mshtmdid.h @@ -3487,6 +3487,17 @@ /* IHTMLEventObj4 */ #define DISPID_IHTMLEVENTOBJ4_WHEELDELTA DISPID_EVENTOBJ+51 +/* IHTMLEventObj5 */ +#define DISPID_IHTMLEVENTOBJ5_URL DISPID_EVENTOBJ+52 +#define DISPID_IHTMLEVENTOBJ5_DATA DISPID_EVENTOBJ+54 +#define DISPID_IHTMLEVENTOBJ5_SOURCE DISPID_EVENTOBJ+55 +#define DISPID_IHTMLEVENTOBJ5_ORIGIN DISPID_EVENTOBJ+53 +#define DISPID_IHTMLEVENTOBJ5_ISSESSION DISPID_EVENTOBJ+56 + +/* IHTMLEventObj6 */ +#define DISPID_IHTMLEVENTOBJ6_ACTIONURL DISPID_EVENTOBJ+58 +#define DISPID_IHTMLEVENTOBJ6_BUTTONID DISPID_EVENTOBJ+57 + /* IHTMLStyleMedia */ #define DISPID_IHTMLSTYLEMEDIA_TYPE DISPID_STYLEMEDIA+1 #define DISPID_IHTMLSTYLEMEDIA_MATCHMEDIUM DISPID_STYLEMEDIA+2 diff --git a/include/mshtml.idl b/include/mshtml.idl index eff87a4593e..f3c675e012d 100644 --- a/include/mshtml.idl +++ b/include/mshtml.idl @@ -19382,6 +19382,327 @@ interface IHTMLEventObj : IDispatch HRESULT srcFilter([retval, out] IDispatch **p); } +/***************************************************************************** + * IHTMLEventObj2 interface + */ +[ + odl, + oleautomation, + dual, + uuid(3050f48B-98b5-11cf-bb82-00aa00bdce0b) +] +interface IHTMLEventObj2 : IDispatch +{ + [id(DISPID_IHTMLEVENTOBJ2_SETATTRIBUTE)] + HRESULT setAttribute( + [in] BSTR strAttributeName, + [in] VARIANT AttributeValue, + [in, defaultvalue(1)] LONG lFlags); + + [id(DISPID_IHTMLEVENTOBJ2_GETATTRIBUTE)] + HRESULT getAttribute( + [in] BSTR strAttributeName, + [in, defaultvalue(0)] LONG lFlags, + [out, retval] VARIANT *AttributeValue); + + [id(DISPID_IHTMLEVENTOBJ2_REMOVEATTRIBUTE)] + HRESULT removeAttribute( + [in] BSTR strAttributeName, + [in, defaultvalue(1)] LONG lFlags, + [out, retval] VARIANT_BOOL *pfSuccess); + + [propput, id(DISPID_IHTMLEVENTOBJ2_PROPERTYNAME)] + HRESULT propertyName([in] BSTR v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_PROPERTYNAME)] + HRESULT propertyName([out, retval] BSTR *p); + + [propputref, id(DISPID_IHTMLEVENTOBJ2_BOOKMARKS)] + HRESULT bookmarks([in] IHTMLBookmarkCollection *v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_BOOKMARKS)] + HRESULT bookmarks([out, retval] IHTMLBookmarkCollection **p); + + [propputref, id(DISPID_IHTMLEVENTOBJ2_RECORDSET)] + HRESULT recordset([in] IDispatch *v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_RECORDSET)] + HRESULT recordset([out, retval] IDispatch **p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_DATAFLD)] + HRESULT dataFld([in] BSTR v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_DATAFLD)] + HRESULT dataFld([out, retval] BSTR *p); + + [propputref, id(DISPID_IHTMLEVENTOBJ2_BOUNDELEMENTS)] + HRESULT boundElements([in] IHTMLElementCollection *v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_BOUNDELEMENTS)] + HRESULT boundElements([out, retval] IHTMLElementCollection **p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_REPEAT)] + HRESULT repeat([in] VARIANT_BOOL v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_REPEAT)] + HRESULT repeat([out, retval] VARIANT_BOOL *p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_SRCURN)] + HRESULT srcUrn([in] BSTR v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_SRCURN)] + HRESULT srcUrn([out, retval] BSTR *p); + + [propputref, id(DISPID_IHTMLEVENTOBJ2_SRCELEMENT)] + HRESULT srcElement([in] IHTMLElement *v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_SRCELEMENT)] + HRESULT srcElement([out, retval] IHTMLElement **p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_ALTKEY)] + HRESULT altKey([in] VARIANT_BOOL v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_ALTKEY)] + HRESULT altKey([out, retval] VARIANT_BOOL *p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_CTRLKEY)] + HRESULT ctrlKey([in] VARIANT_BOOL v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_CTRLKEY)] + HRESULT ctrlKey([out, retval] VARIANT_BOOL *p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_SHIFTKEY)] + HRESULT shiftKey([in] VARIANT_BOOL v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_SHIFTKEY)] + HRESULT shiftKey([out, retval] VARIANT_BOOL *p); + + [propputref, id(DISPID_IHTMLEVENTOBJ2_FROMELEMENT)] + HRESULT fromElement([in] IHTMLElement *v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_FROMELEMENT)] + HRESULT fromElement([out, retval] IHTMLElement **p); + + [propputref, id(DISPID_IHTMLEVENTOBJ2_TOELEMENT)] + HRESULT toElement([in] IHTMLElement *v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_TOELEMENT)] + HRESULT toElement([out, retval] IHTMLElement **p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_BUTTON)] + HRESULT button([in] long v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_BUTTON)] + HRESULT button([out, retval] long *p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_TYPE)] + HRESULT type([in] BSTR v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_TYPE)] + HRESULT type([out, retval] BSTR *p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_QUALIFIER)] + HRESULT qualifier([in] BSTR v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_QUALIFIER)] + HRESULT qualifier([out, retval] BSTR *p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_REASON)] + HRESULT reason([in] long v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_REASON)] + HRESULT reason([out, retval] long *p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_X)] + HRESULT x([in] long v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_X)] + HRESULT x([out, retval] long *p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_Y)] + HRESULT y([in] long v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_Y)] + HRESULT y([out, retval] long *p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_CLIENTX)] + HRESULT clientX([in] long v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_CLIENTX)] + HRESULT clientX([out, retval] long *p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_CLIENTY)] + HRESULT clientY([in] long v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_CLIENTY)] + HRESULT clientY([out, retval] long *p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_OFFSETX)] + HRESULT offsetX([in] long v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_OFFSETX)] + HRESULT offsetX([out, retval] long *p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_OFFSETY)] + HRESULT offsetY([in] long v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_OFFSETY)] + HRESULT offsetY([out, retval] long *p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_SCREENX)] + HRESULT screenX([in] long v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_SCREENX)] + HRESULT screenX([out, retval] long *p); + + [propput, id(DISPID_IHTMLEVENTOBJ2_SCREENY)] + HRESULT screenY([in] long v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_SCREENY)] + HRESULT screenY([out, retval] long *p); + + [propputref, id(DISPID_IHTMLEVENTOBJ2_SRCFILTER)] + HRESULT srcFilter([in] IDispatch *v); + + [propget, id(DISPID_IHTMLEVENTOBJ2_SRCFILTER)] + HRESULT srcFilter([out, retval] IDispatch **p); + + [propget, id(DISPID_IHTMLEVENTOBJ2_DATATRANSFER)] + HRESULT dataTransfer([out, retval] IHTMLDataTransfer **p); +} + +/***************************************************************************** + * IHTMLEventObj3 interface + */ +[ + odl, + oleautomation, + dual, + uuid(3050f680-98b5-11cf-bb82-00aa00bdce0b) +] +interface IHTMLEventObj3 : IDispatch +{ + [propget, id(DISPID_IHTMLEVENTOBJ3_CONTENTOVERFLOW)] + HRESULT contentOverflow([out, retval] VARIANT_BOOL *p); + + [propput, id(DISPID_IHTMLEVENTOBJ3_SHIFTLEFT)] + HRESULT shiftLeft([in] VARIANT_BOOL v); + + [propget, id(DISPID_IHTMLEVENTOBJ3_SHIFTLEFT)] + HRESULT shiftLeft([out, retval] VARIANT_BOOL *p); + + [propput, id(DISPID_IHTMLEVENTOBJ3_ALTLEFT)] + HRESULT altLeft([in] VARIANT_BOOL v); + + [propget, id(DISPID_IHTMLEVENTOBJ3_ALTLEFT)] + HRESULT altLeft([out, retval] VARIANT_BOOL *p); + + [propput, id(DISPID_IHTMLEVENTOBJ3_CTRLLEFT)] + HRESULT ctrlLeft([in] VARIANT_BOOL v); + + [propget, id(DISPID_IHTMLEVENTOBJ3_CTRLLEFT)] + HRESULT ctrlLeft([out, retval] VARIANT_BOOL *p); + + [propget, id(DISPID_IHTMLEVENTOBJ3_IMECOMPOSITIONCHANGE), hidden, restricted, nonbrowsable] + HRESULT imeCompositionChange([out, retval] LONG_PTR *p); + + [propget, id(DISPID_IHTMLEVENTOBJ3_IMENOTIFYCOMMAND), hidden, restricted, nonbrowsable] + HRESULT imeNotifyCommand([out, retval] LONG_PTR *p); + + [propget, id(DISPID_IHTMLEVENTOBJ3_IMENOTIFYDATA), hidden, restricted, nonbrowsable] + HRESULT imeNotifyData([out, retval] LONG_PTR *p); + + [propget, id(DISPID_IHTMLEVENTOBJ3_IMEREQUEST), hidden, restricted, nonbrowsable] + HRESULT imeRequest([out, retval] LONG_PTR *p); + + [propget, id(DISPID_IHTMLEVENTOBJ3_IMEREQUESTDATA), hidden, restricted, nonbrowsable] + HRESULT imeRequestData([out, retval] LONG_PTR *p); + + [propget, id(DISPID_IHTMLEVENTOBJ3_KEYBOARDLAYOUT), hidden, restricted, nonbrowsable] + HRESULT keyboardLayout([out, retval] LONG_PTR *p); + + [propget, id(DISPID_IHTMLEVENTOBJ3_BEHAVIORCOOKIE)] + HRESULT behaviorCookie([out, retval] long *p); + + [propget, id(DISPID_IHTMLEVENTOBJ3_BEHAVIORPART)] + HRESULT behaviorPart([out, retval] long *p); + + [propget, id(DISPID_IHTMLEVENTOBJ3_NEXTPAGE)] + HRESULT nextPage([out, retval] BSTR *p); +} + +/***************************************************************************** + * IHTMLEventObj4 interface + */ +[ + odl, + oleautomation, + dual, + uuid(3050f814-98b5-11cf-bb82-00aa00bdce0b) +] +interface IHTMLEventObj4 : IDispatch +{ + [propget, id(DISPID_IHTMLEVENTOBJ4_WHEELDELTA)] + HRESULT wheelDelta([out, retval] long *p); +} + +/***************************************************************************** + * IHTMLEventObj5 interface + */ +[ + odl, + oleautomation, + dual, + uuid(30510478-98b5-11cf-bb82-00aa00bdce0b) +] +interface IHTMLEventObj5 : IDispatch +{ + [propput, id(DISPID_IHTMLEVENTOBJ5_URL)] + HRESULT url([in] BSTR v); + + [propget, id(DISPID_IHTMLEVENTOBJ5_URL)] + HRESULT url([out, retval] BSTR *p); + + [propput, id(DISPID_IHTMLEVENTOBJ5_DATA)] + HRESULT data([in] BSTR v); + + [propget, id(DISPID_IHTMLEVENTOBJ5_DATA)] + HRESULT data([out, retval] BSTR *p); + + [propget, id(DISPID_IHTMLEVENTOBJ5_SOURCE)] + HRESULT source([out, retval] IDispatch **p); + + [propput, id(DISPID_IHTMLEVENTOBJ5_ORIGIN)] + HRESULT origin([in] BSTR v); + + [propget, id(DISPID_IHTMLEVENTOBJ5_ORIGIN)] + HRESULT origin([out, retval] BSTR *p); + + [propput, id(DISPID_IHTMLEVENTOBJ5_ISSESSION), hidden, restricted, nonbrowsable] + HRESULT issession([in] VARIANT_BOOL v); + + [propget, id(DISPID_IHTMLEVENTOBJ5_ISSESSION), hidden, restricted, nonbrowsable] + HRESULT issession([out, retval] VARIANT_BOOL *p); +} + +/***************************************************************************** + * IHTMLEventObj6 interface + */ +[ + odl, + oleautomation, + dual, + uuid(30510734-98b5-11cf-bb82-00aa00bdce0b) +] +interface IHTMLEventObj6 : IDispatch +{ + [propget, id(DISPID_IHTMLEVENTOBJ6_ACTIONURL)] + HRESULT actionURL([out, retval] BSTR *p); + + [propget, id(DISPID_IHTMLEVENTOBJ6_BUTTONID)] + HRESULT buttonID([out, retval] long *p); +} + /***************************************************************************** * DispCEventObj dispinterface */ @@ -19635,6 +19956,42 @@ methods: [propget, id(DISPID_IHTMLEVENTOBJ4_WHEELDELTA)] LONG wheelDelta(); + + [propput, id(DISPID_IHTMLEVENTOBJ5_URL)] + void url(BSTR v); + + [propget, id(DISPID_IHTMLEVENTOBJ5_URL)] + BSTR url(); + + [propput, id(DISPID_IHTMLEVENTOBJ5_DATA)] + void data(BSTR v); + + [propget, id(DISPID_IHTMLEVENTOBJ5_DATA)] + BSTR data(); + + [propget, id(DISPID_IHTMLEVENTOBJ5_SOURCE)] + IDispatch *source(); + + [propput, id(DISPID_IHTMLEVENTOBJ5_ORIGIN)] + void origin(BSTR v); + + [propget, id(DISPID_IHTMLEVENTOBJ5_ORIGIN)] + BSTR origin(); + + [propput, id(DISPID_IHTMLEVENTOBJ5_ISSESSION), hidden, restricted, nonbrowsable] + void issession(VARIANT_BOOL v); + + [propget, id(DISPID_IHTMLEVENTOBJ5_ISSESSION), hidden, restricted, nonbrowsable] + VARIANT_BOOL issession(); + + [propget, id(DISPID_IHTMLEVENTOBJ6_ACTIONURL)] + BSTR actionURL(); + + [propget, id(DISPID_IHTMLEVENTOBJ6_BUTTONID)] + long buttonID(); + + [propget, id(DISPID_IHTMLDOMCONSTRUCTOR_CONSTRUCTOR), hidden] + IDispatch *constructor(); } /***************************************************************************** From cfb400f1b0f731083f87f0db44205f1716e4f65e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:56 +0200 Subject: [PATCH 0820/2777] jscript: Pass the correct ServiceProvider when invoking external prop. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/array.c | 18 +++-- dlls/jscript/dispex.c | 23 ++++--- dlls/jscript/engine.c | 10 +-- dlls/jscript/function.c | 2 +- dlls/jscript/jscript.h | 2 +- dlls/jscript/json.c | 4 +- dlls/jscript/set.c | 3 +- dlls/jscript/tests/run.c | 143 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 178 insertions(+), 27 deletions(-) diff --git a/dlls/jscript/array.c b/dlls/jscript/array.c index 341505a335c..198fc3c16c1 100644 --- a/dlls/jscript/array.c +++ b/dlls/jscript/array.c @@ -1061,7 +1061,8 @@ static HRESULT Array_every(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigne args[0] = value; args[1] = jsval_number(i); args[2] = jsval_obj(jsthis); - hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res); + hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res, + &ctx->jscaller->IServiceProvider_iface); jsval_release(value); if(FAILED(hres)) goto done; @@ -1128,7 +1129,8 @@ static HRESULT Array_filter(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsign args[0] = value; args[1] = jsval_number(i); args[2] = jsval_obj(jsthis); - hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res); + hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res, + &ctx->jscaller->IServiceProvider_iface); if(SUCCEEDED(hres)) { hres = to_boolean(res, &boolval); jsval_release(res); @@ -1190,7 +1192,8 @@ static HRESULT Array_forEach(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsig args[0] = value; args[1] = jsval_number(i); args[2] = jsval_obj(jsthis); - hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res); + hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res, + &ctx->jscaller->IServiceProvider_iface); jsval_release(value); if(FAILED(hres)) goto done; @@ -1365,7 +1368,8 @@ static HRESULT Array_map(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned callback_args[1] = jsval_number(k); callback_args[2] = jsval_obj(jsthis); - hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, 3, callback_args, &mapped_value); + hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, 3, callback_args, &mapped_value, + &ctx->jscaller->IServiceProvider_iface); jsval_release(callback_args[0]); if(FAILED(hres)) break; @@ -1432,7 +1436,8 @@ static HRESULT Array_reduce(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsign callback_args[0] = acc; callback_args[2] = jsval_number(k); callback_args[3] = jsval_obj(jsthis); - hres = disp_call_value(ctx, callback, jsval_undefined(), DISPATCH_METHOD, ARRAY_SIZE(callback_args), callback_args, &new_acc); + hres = disp_call_value(ctx, callback, jsval_undefined(), DISPATCH_METHOD, ARRAY_SIZE(callback_args), + callback_args, &new_acc, &ctx->jscaller->IServiceProvider_iface); jsval_release(callback_args[1]); if(FAILED(hres)) break; @@ -1493,7 +1498,8 @@ static HRESULT Array_some(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned args[0] = value; args[1] = jsval_number(i); args[2] = jsval_obj(jsthis); - hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res); + hres = disp_call_value(ctx, callback, context_this, DISPATCH_METHOD, ARRAY_SIZE(args), args, &res, + &ctx->jscaller->IServiceProvider_iface); jsval_release(value); if(FAILED(hres)) goto done; diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 4b56ec9fc70..73a4a5bbecd 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -574,7 +574,7 @@ static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t return disp_call_value(This->ctx, get_object(prop->u.val), jsval_disp(jsthis ? jsthis : (IDispatch*)&This->IDispatchEx_iface), - flags, argc, argv, r); + flags, argc, argv, r, caller); } case PROP_ACCESSOR: case PROP_IDX: { @@ -587,7 +587,7 @@ static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t if(is_object_instance(val)) { hres = disp_call_value(This->ctx, get_object(val), jsval_disp(jsthis ? jsthis : (IDispatch*)&This->IDispatchEx_iface), - flags, argc, argv, r); + flags, argc, argv, r, caller); }else { FIXME("invoke %s\n", debugstr_jsval(val)); hres = E_NOTIMPL; @@ -2364,7 +2364,7 @@ HRESULT jsdisp_call(jsdisp_t *disp, DISPID id, WORD flags, unsigned argc, jsval_ if(!prop) return DISP_E_MEMBERNOTFOUND; - return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL); + return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, &disp->ctx->jscaller->IServiceProvider_iface); } HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) @@ -2379,10 +2379,11 @@ HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned if(!prop || prop->type == PROP_DELETED) return JS_E_INVALID_PROPERTY; - return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, NULL); + return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, &disp->ctx->jscaller->IServiceProvider_iface); } -static HRESULT disp_invoke(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, DISPPARAMS *params, VARIANT *r) +static HRESULT disp_invoke(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, DISPPARAMS *params, VARIANT *r, + IServiceProvider *caller) { IDispatchEx *dispex; EXCEPINFO ei; @@ -2391,7 +2392,7 @@ static HRESULT disp_invoke(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD f memset(&ei, 0, sizeof(ei)); hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); if(SUCCEEDED(hres)) { - hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, params, r, &ei, &ctx->jscaller->IServiceProvider_iface); + hres = IDispatchEx_InvokeEx(dispex, id, ctx->lcid, flags, params, r, &ei, caller); IDispatchEx_Release(dispex); }else { UINT err = 0; @@ -2489,7 +2490,7 @@ HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, uns } V_VT(&retv) = VT_EMPTY; - hres = disp_invoke(ctx, disp, id, flags, &dp, ret ? &retv : NULL); + hres = disp_invoke(ctx, disp, id, flags, &dp, ret ? &retv : NULL, &ctx->jscaller->IServiceProvider_iface); for(i=0; ijscaller->IServiceProvider_iface); VariantClear(&var); } @@ -2773,7 +2774,7 @@ HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val jsdisp_release(jsdisp); V_VT(&var) = VT_EMPTY; - hres = disp_invoke(ctx, disp, id, INVOKE_PROPERTYGET, &dp, &var); + hres = disp_invoke(ctx, disp, id, INVOKE_PROPERTYGET, &dp, &var, &ctx->jscaller->IServiceProvider_iface); if(SUCCEEDED(hres)) { hres = variant_to_jsval(ctx, &var, val); VariantClear(&var); diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index b0557065e69..459d1e833df 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -327,7 +327,7 @@ static HRESULT exprval_call(script_ctx_t *ctx, exprval_t *ref, WORD flags, unsig return E_FAIL; } - return disp_call_value(ctx, get_object(v), jsval_undefined(), flags, argc, argv, r); + return disp_call_value(ctx, get_object(v), jsval_undefined(), flags, argc, argv, r, &ctx->jscaller->IServiceProvider_iface); } case EXPRVAL_IDREF: /* ECMA-262 3rd Edition 11.2.3.7 / ECMA-262 5.1 Edition 11.2.3.6 * @@ -340,7 +340,7 @@ static HRESULT exprval_call(script_ctx_t *ctx, exprval_t *ref, WORD flags, unsig FIXME("invoke %s\n", debugstr_jsval(v)); hres = E_FAIL; }else { - hres = disp_call_value(ctx, get_object(v), jsval_undefined(), flags, argc, argv, r); + hres = disp_call_value(ctx, get_object(v), jsval_undefined(), flags, argc, argv, r, &ctx->jscaller->IServiceProvider_iface); } jsval_release(v); return hres; @@ -351,7 +351,7 @@ static HRESULT exprval_call(script_ctx_t *ctx, exprval_t *ref, WORD flags, unsig hres = to_object(ctx, ref->u.val, &obj); if(SUCCEEDED(hres)) { - hres = disp_call_value(ctx, obj, jsval_undefined(), flags, argc, argv, r); + hres = disp_call_value(ctx, obj, jsval_undefined(), flags, argc, argv, r, &ctx->jscaller->IServiceProvider_iface); IDispatch_Release(obj); } return hres; @@ -1421,7 +1421,7 @@ static HRESULT interp_new(script_ctx_t *ctx) clear_acc(ctx); return disp_call_value(ctx, get_object(constr), jsval_undefined(), DISPATCH_CONSTRUCT | DISPATCH_JSCRIPT_CALLEREXECSSOURCE, - argc, stack_args(ctx, argc), &ctx->acc); + argc, stack_args(ctx, argc), &ctx->acc, &ctx->jscaller->IServiceProvider_iface); } /* ECMA-262 3rd Edition 11.2.3 */ @@ -1439,7 +1439,7 @@ static HRESULT interp_call(script_ctx_t *ctx) clear_acc(ctx); return disp_call_value(ctx, get_object(obj), jsval_undefined(), DISPATCH_METHOD | DISPATCH_JSCRIPT_CALLEREXECSSOURCE, - argn, stack_args(ctx, argn), do_ret ? &ctx->acc : NULL); + argn, stack_args(ctx, argn), do_ret ? &ctx->acc : NULL, &ctx->jscaller->IServiceProvider_iface); } /* ECMA-262 3rd Edition 11.2.3 */ diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 5f210a04050..c3b22eb843c 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -411,7 +411,7 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi hres = function->vtbl->call(ctx, function, this_val, flags, cnt, args, r); }else { jsval_t res; - hres = disp_call_value(ctx, get_object(vthis), this_val, DISPATCH_METHOD, cnt, args, &res); + hres = disp_call_value(ctx, get_object(vthis), this_val, DISPATCH_METHOD, cnt, args, &res, &ctx->jscaller->IServiceProvider_iface); if(SUCCEEDED(hres)) { if(r) *r = res; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 36a6d23c917..04b3a6cc8c9 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -240,7 +240,7 @@ HRESULT init_dispex_from_constr(jsdisp_t*,script_ctx_t*,const builtin_info_t*,js HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; HRESULT disp_call_name(script_ctx_t*,IDispatch*,const WCHAR*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; -HRESULT disp_call_value(script_ctx_t*,IDispatch*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; +HRESULT disp_call_value(script_ctx_t*,IDispatch*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*,IServiceProvider*) DECLSPEC_HIDDEN; HRESULT jsdisp_call_value(jsdisp_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; HRESULT jsdisp_call(jsdisp_t*,DISPID,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; HRESULT jsdisp_call_name(jsdisp_t*,const WCHAR*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; diff --git a/dlls/jscript/json.c b/dlls/jscript/json.c index e36c4973ef2..d2be768ffea 100644 --- a/dlls/jscript/json.c +++ b/dlls/jscript/json.c @@ -350,8 +350,8 @@ static jsval_t transform_json_object(struct transform_json_object_ctx *proc_ctx, } args[0] = jsval_string(name); - proc_ctx->hres = disp_call_value(proc_ctx->ctx, proc_ctx->reviver, jsval_obj(holder), - DISPATCH_METHOD, ARRAY_SIZE(args), args, &res); + proc_ctx->hres = disp_call_value(proc_ctx->ctx, proc_ctx->reviver, jsval_obj(holder), DISPATCH_METHOD, + ARRAY_SIZE(args), args, &res, &proc_ctx->ctx->jscaller->IServiceProvider_iface); return FAILED(proc_ctx->hres) ? jsval_undefined() : res; } diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index eca26a890f7..cd2ef4bd269 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -208,7 +208,8 @@ static HRESULT iterate_map(MapInstance *map, script_ctx_t *ctx, unsigned argc, j args[1] = entry->key; args[2] = jsval_obj(&map->dispex); grab_map_entry(entry); - hres = disp_call_value(ctx, get_object(argv[0]), context_this, DISPATCH_METHOD, ARRAY_SIZE(args), args, &v); + hres = disp_call_value(ctx, get_object(argv[0]), context_this, DISPATCH_METHOD, ARRAY_SIZE(args), + args, &v, &ctx->jscaller->IServiceProvider_iface); iter = list_next(&map->entries, iter); release_map_entry(entry); if(FAILED(hres)) diff --git a/dlls/jscript/tests/run.c b/dlls/jscript/tests/run.c index 21f09474fee..c5d9c47e63c 100644 --- a/dlls/jscript/tests/run.c +++ b/dlls/jscript/tests/run.c @@ -114,6 +114,9 @@ DEFINE_EXPECT(testobj_newenum); DEFINE_EXPECT(testobj_getidfail_d); DEFINE_EXPECT(testobj_tolocalestr_d); DEFINE_EXPECT(testobj_tolocalestr_i); +DEFINE_EXPECT(test_caller_get); +DEFINE_EXPECT(test_caller_null); +DEFINE_EXPECT(test_caller_obj); DEFINE_EXPECT(testdestrobj); DEFINE_EXPECT(enumvariant_next_0); DEFINE_EXPECT(enumvariant_next_1); @@ -333,6 +336,44 @@ static IEnumVARIANTVtbl testEnumVARIANTVtbl = { static IEnumVARIANT testEnumVARIANT = { &testEnumVARIANTVtbl }; +static HRESULT WINAPI sp_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IServiceProvider, riid)) { + *ppv = iface; + return S_OK; + } + + ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOTIMPL; +} + +static ULONG WINAPI sp_AddRef(IServiceProvider *iface) +{ + return 2; +} + +static ULONG WINAPI sp_Release(IServiceProvider *iface) +{ + return 1; +} + +static HRESULT WINAPI sp_QueryService(IServiceProvider *iface, REFGUID guidService, REFIID riid, void **ppv) +{ + ok(0, "unexpected call %s\n", wine_dbgstr_guid(guidService)); + *ppv = NULL; + return E_NOTIMPL; +} + +static const IServiceProviderVtbl sp_vtbl = { + sp_QueryInterface, + sp_AddRef, + sp_Release, + sp_QueryService +}; + +static IServiceProvider sp_obj = { &sp_vtbl }; + static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv) { *ppv = NULL; @@ -629,6 +670,61 @@ static IDispatchExVtbl testObjVtbl = { static IDispatchEx testObj = { &testObjVtbl }; +static HRESULT WINAPI testcallerobj_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + ok(id == DISPID_VALUE, "id = %ld\n", id); + ok(pdp != NULL, "pdp == NULL\n"); + ok(pvarRes != NULL, "pvarRes == NULL\n"); + ok(V_VT(pvarRes) == VT_EMPTY, "V_VT(pvarRes) = %d\n", V_VT(pvarRes)); + if(wFlags == DISPATCH_PROPERTYGET) { + CHECK_EXPECT(test_caller_get); + ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n"); + ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pei != NULL, "pei == NULL\n"); + ok(pspCaller != NULL, "pspCaller == NULL\n"); + ok(pspCaller != &sp_obj, "pspCaller == sp_obj\n"); + V_VT(pvarRes) = VT_DISPATCH; + V_DISPATCH(pvarRes) = (IDispatch*)iface; + }else if(pspCaller) { + CHECK_EXPECT(test_caller_obj); + ok(wFlags == DISPATCH_METHOD, "wFlags = %04x\n", wFlags); + ok(pdp->rgdispidNamedArgs != NULL, "rgdispidNamedArgs == NULL\n"); + ok(pdp->cNamedArgs == 1, "cNamedArgs = %d\n", pdp->cNamedArgs); + ok(pspCaller == &sp_obj, "pspCaller != sp_obj\n"); + V_VT(pvarRes) = VT_I4; + V_I4(pvarRes) = 137; + }else { + CHECK_EXPECT(test_caller_null); + ok(wFlags == DISPATCH_METHOD, "wFlags = %04x\n", wFlags); + ok(pdp->rgdispidNamedArgs != NULL, "rgdispidNamedArgs == NULL\n"); + ok(pdp->cNamedArgs == 1, "cNamedArgs = %d\n", pdp->cNamedArgs); + V_VT(pvarRes) = VT_I4; + V_I4(pvarRes) = 42; + } + return S_OK; +} + +static IDispatchExVtbl testcallerobj_vtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + testcallerobj_InvokeEx, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; + +static IDispatchEx testcallerobj = { &testcallerobj_vtbl }; + static LONG test_destr_ref; static ULONG WINAPI testDestrObj_AddRef(IDispatchEx *iface) @@ -3214,6 +3310,7 @@ static void test_script_exprs(void) static void test_invokeex(void) { + static DISPID propput_dispid = DISPID_PROPERTYPUT; DISPPARAMS dp = {NULL}, dp_max = {NULL}; DISPID func_id, max_id, prop_id; IActiveScript *script; @@ -3442,6 +3539,52 @@ static void test_invokeex(void) IDispatchEx_Release(dispex); IActiveScript_Release(script); + + /* test InvokeEx with host prop and custom caller */ + hres = parse_script_expr(L"var o = {}; o", &v, &script); + ok(hres == S_OK, "parse_script_expr failed: %08lx\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(v) = %d\n", V_VT(&v)); + + hres = IDispatch_QueryInterface(V_DISPATCH(&v), &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx iface: %08lx\n", hres); + VariantClear(&v); + + str = SysAllocString(L"caller"); + hres = IDispatchEx_GetDispID(dispex, str, fdexNameEnsure, &func_id); + SysFreeString(str); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + + SET_EXPECT(test_caller_get); + dp.cArgs = dp.cNamedArgs = 1; + dp.rgvarg = &arg; + dp.rgdispidNamedArgs = &propput_dispid; + V_VT(&arg) = VT_DISPATCH; + V_DISPATCH(&arg) = (IDispatch*)&testcallerobj; + hres = IDispatchEx_InvokeEx(dispex, func_id, 0, DISPATCH_PROPERTYPUT, &dp, NULL, NULL, NULL); + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + todo_wine + CHECK_CALLED(test_caller_get); + + SET_EXPECT(test_caller_null); + dp.cArgs = dp.cNamedArgs = 0; + dp.rgvarg = NULL; + dp.rgdispidNamedArgs = NULL; + hres = IDispatchEx_InvokeEx(dispex, func_id, 0, DISPATCH_METHOD, &dp, &v, NULL, NULL); + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + ok(V_VT(&v) == VT_I4, "V_VT(v) = %d\n", V_VT(&v)); + ok(V_I4(&v) == 42, "V_I4(v) = %s\n", wine_dbgstr_variant(&v)); + CHECK_CALLED(test_caller_null); + V_VT(&v) = VT_EMPTY; + + SET_EXPECT(test_caller_obj); + hres = IDispatchEx_InvokeEx(dispex, func_id, 0, DISPATCH_METHOD, &dp, &v, NULL, &sp_obj); + ok(hres == S_OK, "InvokeEx failed: %08lx\n", hres); + ok(V_VT(&v) == VT_I4, "V_VT(v) = %d\n", V_VT(&v)); + ok(V_I4(&v) == 137, "V_I4(v) = %s\n", wine_dbgstr_variant(&v)); + CHECK_CALLED(test_caller_obj); + + IDispatchEx_Release(dispex); + IActiveScript_Release(script); } static void test_destructors(void) From 17c82dc2a72e354b8c48be52b31a6385c1826f91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:56 +0200 Subject: [PATCH 0821/2777] mshtml: Return undefined from window.XMLHttpRequest for uninitialized documents. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- Add a bunch of tests along the way which verify existing behavior is mostly correct. --- dlls/mshtml/htmlwindow.c | 5 ++ dlls/mshtml/tests/dom.c | 114 +++++++++++++++++++++++++++++- dlls/mshtml/tests/events.c | 139 +++++++++++++++++++++++++++++++++++++ 3 files changed, 257 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index f013ba20d1c..c4c6a99f5f3 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -2038,6 +2038,11 @@ static HRESULT WINAPI HTMLWindow5_get_XMLHttpRequest(IHTMLWindow5 *iface, VARIAN TRACE("(%p)->(%p)\n", This, p); + if(This->outer_window->readystate == READYSTATE_UNINITIALIZED) { + V_VT(p) = VT_EMPTY; + return S_OK; + } + if(!window->xhr_factory) { HRESULT hres; diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index c9c52776fa9..0d29f66744b 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -11736,12 +11736,23 @@ static void test_quirks_mode(void) static void test_document_mode_lock(void) { + IHTMLOptionElementFactory *option, *option2; + IHTMLDocument2 *doc, *doc_node, *doc_node2; + IHTMLImageElementFactory *image, *image2; + IOmNavigator *navigator, *navigator2; + IHTMLLocation *location, *location2; + IHTMLPerformance *perf, *perf2; + IOmHistory *history, *history2; + IHTMLScreen *screen, *screen2; IEventTarget *event_target; IPersistStreamInit *init; - IHTMLDocument2 *doc; + IHTMLWindow7 *window7; + IHTMLWindow5 *window5; + IHTMLWindow2 *window; IStream *stream; HRESULT hres; HGLOBAL mem; + VARIANT var; SIZE_T len; MSG msg; @@ -11754,6 +11765,49 @@ static void test_document_mode_lock(void) ok(hres == E_NOINTERFACE, "QueryInterface(IID_IEventTarget) returned %08lx.\n", hres); ok(event_target == NULL, "event_target != NULL\n"); + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_document(window, &doc_node); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_location(window, &location); + ok(hres == S_OK, "get_location failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_navigator(window, &navigator); + ok(hres == S_OK, "get_navigator failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_history(window, &history); + ok(hres == S_OK, "get_history failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_screen(window, &screen); + ok(hres == S_OK, "get_screen failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_Image(window, &image); + ok(hres == S_OK, "get_image failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_Option(window, &option); + ok(hres == S_OK, "get_option failed: %08lx\n", hres); + + V_VT(&var) = VT_NULL; + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow5, (void**)&window5); + ok(hres == S_OK, "Could not get IHTMLWindow5: %08lx\n", hres); + hres = IHTMLWindow5_get_XMLHttpRequest(window5, &var); + ok(hres == S_OK, "get_XMLHttpRequest failed: %08lx\n", hres); + ok(V_VT(&var) == VT_EMPTY, "V_VT(XMLHttpRequest) = %d\n", V_VT(&var)); + IHTMLWindow5_Release(window5); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow7, (void**)&window7); + ok(hres == S_OK, "Could not get IHTMLWindow7: %08lx\n", hres); + hres = IHTMLWindow7_get_performance(window7, &var); + ok(hres == S_OK, "get_performance failed: %08lx\n", hres); + ok(V_VT(&var) == VT_DISPATCH, "V_VT(performance) = %d\n", V_VT(&var)); + hres = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IHTMLPerformance, (void**)&perf); + ok(hres == S_OK, "Could not get IHTMLPerformance: %08lx\n", hres); + IHTMLWindow7_Release(window7); + IHTMLWindow2_Release(window); + VariantClear(&var); + len = strlen(doc_blank_ie9); mem = GlobalAlloc(0, len); memcpy(mem, doc_blank_ie9, len); @@ -11780,6 +11834,64 @@ static void test_document_mode_lock(void) ok(event_target != NULL, "event_target == NULL\n"); IEventTarget_Release(event_target); + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_document(window, &doc_node2); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + ok(doc_node != doc_node2, "doc_node == doc_node2\n"); + IHTMLDocument2_Release(doc_node2); + IHTMLDocument2_Release(doc_node); + + hres = IHTMLWindow2_get_location(window, &location2); + ok(hres == S_OK, "get_location failed: %08lx\n", hres); + todo_wine + ok(location == location2, "location != location2\n"); + IHTMLLocation_Release(location2); + IHTMLLocation_Release(location); + + hres = IHTMLWindow2_get_navigator(window, &navigator2); + ok(hres == S_OK, "get_navigator failed: %08lx\n", hres); + ok(navigator != navigator2, "navigator == navigator2\n"); + IOmNavigator_Release(navigator2); + IOmNavigator_Release(navigator); + + hres = IHTMLWindow2_get_history(window, &history2); + ok(hres == S_OK, "get_history failed: %08lx\n", hres); + ok(history != history2, "history == history2\n"); + IOmHistory_Release(history2); + IOmHistory_Release(history); + + hres = IHTMLWindow2_get_screen(window, &screen2); + ok(hres == S_OK, "get_screen failed: %08lx\n", hres); + ok(screen != screen2, "screen == screen2\n"); + IHTMLScreen_Release(screen2); + IHTMLScreen_Release(screen); + + hres = IHTMLWindow2_get_Image(window, &image2); + ok(hres == S_OK, "get_image failed: %08lx\n", hres); + ok(image != image2, "image == image2\n"); + IHTMLImageElementFactory_Release(image2); + IHTMLImageElementFactory_Release(image); + + hres = IHTMLWindow2_get_Option(window, &option2); + ok(hres == S_OK, "get_option failed: %08lx\n", hres); + ok(option != option2, "option == option2\n"); + IHTMLOptionElementFactory_Release(option2); + IHTMLOptionElementFactory_Release(option); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow7, (void**)&window7); + ok(hres == S_OK, "Could not get IHTMLWindow7: %08lx\n", hres); + hres = IHTMLWindow7_get_performance(window7, &var); + ok(hres == S_OK, "get_performance failed: %08lx\n", hres); + ok(V_VT(&var) == VT_DISPATCH, "V_VT(performance) = %d\n", V_VT(&var)); + hres = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IHTMLPerformance, (void**)&perf2); + ok(hres == S_OK, "Could not get IHTMLPerformance: %08lx\n", hres); + ok(perf != perf2, "perf == perf2\n"); + IHTMLWindow7_Release(window7); + IHTMLWindow2_Release(window); + VariantClear(&var); + set_client_site(doc, FALSE); IHTMLDocument2_Release(doc); } diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 30b6d8799b6..196ab3160a7 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -3135,9 +3135,22 @@ static void test_iframe_connections(IHTMLDocument2 *doc) static void test_doc_obj(IHTMLDocument2 *doc) { DISPID dispid, import_node_id, has_own_prop_id; + IHTMLOptionElementFactory *option, *option2; + IHTMLImageElementFactory *image, *image2; + IHTMLXMLHttpRequestFactory *xhr, *xhr2; + IHTMLDocument2 *doc_node, *doc_node2; + IOmNavigator *navigator, *navigator2; + IHTMLLocation *location, *location2; int orig_doc_mode = document_mode; + IHTMLStorage *storage, *storage2; + IHTMLPerformance *perf, *perf2; + IOmHistory *history, *history2; + IHTMLScreen *screen, *screen2; IEventTarget *event_target; DISPPARAMS dp = { 0 }; + IHTMLWindow7 *window7; + IHTMLWindow6 *window6; + IHTMLWindow5 *window5; IDispatchEx *dispex; IHTMLElement *body; VARIANT res, arg; @@ -3246,6 +3259,54 @@ static void test_doc_obj(IHTMLDocument2 *doc) SysFreeString(V_BSTR(&arg)); } + /* test window props during navigation */ + hres = IHTMLWindow2_get_document(window, &doc_node); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_location(window, &location); + ok(hres == S_OK, "get_location failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_navigator(window, &navigator); + ok(hres == S_OK, "get_navigator failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_history(window, &history); + ok(hres == S_OK, "get_history failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_screen(window, &screen); + ok(hres == S_OK, "get_screen failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_Image(window, &image); + ok(hres == S_OK, "get_image failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_Option(window, &option); + ok(hres == S_OK, "get_option failed: %08lx\n", hres); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow5, (void**)&window5); + ok(hres == S_OK, "Could not get IHTMLWindow5: %08lx\n", hres); + hres = IHTMLWindow5_get_XMLHttpRequest(window5, &res); + ok(hres == S_OK, "get_XMLHttpRequest failed: %08lx\n", hres); + ok(V_VT(&res) == VT_DISPATCH, "V_VT(XMLHttpRequest) = %d\n", V_VT(&res)); + hres = IDispatch_QueryInterface(V_DISPATCH(&res), &IID_IHTMLXMLHttpRequestFactory, (void**)&xhr); + ok(hres == S_OK, "Could not get IHTMLXMLHttpRequestFactory: %08lx\n", hres); + IHTMLWindow5_Release(window5); + VariantClear(&res); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow6, (void**)&window6); + ok(hres == S_OK, "Could not get IHTMLWindow6: %08lx\n", hres); + hres = IHTMLWindow6_get_sessionStorage(window6, &storage); + ok(hres == S_OK, "get_sessionStorage failed: %08lx\n", hres); + IHTMLWindow6_Release(window6); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow7, (void**)&window7); + ok(hres == S_OK, "Could not get IHTMLWindow7: %08lx\n", hres); + hres = IHTMLWindow7_get_performance(window7, &res); + ok(hres == S_OK, "get_performance failed: %08lx\n", hres); + ok(V_VT(&res) == VT_DISPATCH, "V_VT(performance) = %d\n", V_VT(&res)); + hres = IDispatch_QueryInterface(V_DISPATCH(&res), &IID_IHTMLPerformance, (void**)&perf); + ok(hres == S_OK, "Could not get IHTMLPerformance: %08lx\n", hres); + IHTMLWindow7_Release(window7); + VariantClear(&res); + /* Navigate to a different document mode page, checking using the same doc obj. Test that it breaks COM rules, since IEventTarget is conditionally exposed. All the events registered on the old doc node are also removed. @@ -3286,6 +3347,84 @@ static void test_doc_obj(IHTMLDocument2 *doc) ok(hres == S_OK, "GetIDsOfNames(importNode) returned: %08lx\n", hres); ok(dispid != import_node_id, "importNode on new doc node == old created importNode\n"); } + + hres = IHTMLWindow2_get_document(window, &doc_node2); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + ok(doc_node != doc_node2, "doc_node == doc_node2\n"); + IHTMLDocument2_Release(doc_node2); + IHTMLDocument2_Release(doc_node); + + hres = IHTMLWindow2_get_location(window, &location2); + ok(hres == S_OK, "get_location failed: %08lx\n", hres); + todo_wine + ok(location == location2, "location != location2\n"); + IHTMLLocation_Release(location2); + IHTMLLocation_Release(location); + + hres = IHTMLWindow2_get_navigator(window, &navigator2); + ok(hres == S_OK, "get_navigator failed: %08lx\n", hres); + ok(navigator != navigator2, "navigator == navigator2\n"); + IOmNavigator_Release(navigator2); + IOmNavigator_Release(navigator); + + hres = IHTMLWindow2_get_history(window, &history2); + ok(hres == S_OK, "get_history failed: %08lx\n", hres); + ok(history != history2, "history == history2\n"); + IOmHistory_Release(history2); + IOmHistory_Release(history); + + hres = IHTMLWindow2_get_screen(window, &screen2); + ok(hres == S_OK, "get_screen failed: %08lx\n", hres); + ok(screen != screen2, "screen == screen2\n"); + IHTMLScreen_Release(screen2); + IHTMLScreen_Release(screen); + + hres = IHTMLWindow2_get_Image(window, &image2); + ok(hres == S_OK, "get_image failed: %08lx\n", hres); + ok(image != image2, "image == image2\n"); + IHTMLImageElementFactory_Release(image2); + IHTMLImageElementFactory_Release(image); + + hres = IHTMLWindow2_get_Option(window, &option2); + ok(hres == S_OK, "get_option failed: %08lx\n", hres); + ok(option != option2, "option == option2\n"); + IHTMLOptionElementFactory_Release(option2); + IHTMLOptionElementFactory_Release(option); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow5, (void**)&window5); + ok(hres == S_OK, "Could not get IHTMLWindow5: %08lx\n", hres); + hres = IHTMLWindow5_get_XMLHttpRequest(window5, &res); + ok(hres == S_OK, "get_XMLHttpRequest failed: %08lx\n", hres); + ok(V_VT(&res) == VT_DISPATCH, "V_VT(XMLHttpRequest) = %d\n", V_VT(&res)); + hres = IDispatch_QueryInterface(V_DISPATCH(&res), &IID_IHTMLXMLHttpRequestFactory, (void**)&xhr2); + ok(hres == S_OK, "Could not get IHTMLXMLHttpRequestFactory: %08lx\n", hres); + ok(xhr != xhr2, "xhr == xhr2\n"); + IHTMLXMLHttpRequestFactory_Release(xhr2); + IHTMLXMLHttpRequestFactory_Release(xhr); + IHTMLWindow5_Release(window5); + VariantClear(&res); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow6, (void**)&window6); + ok(hres == S_OK, "Could not get IHTMLWindow6: %08lx\n", hres); + hres = IHTMLWindow6_get_sessionStorage(window6, &storage2); + ok(hres == S_OK, "get_sessionStorage failed: %08lx\n", hres); + ok(storage != storage2, "storage == storage2\n"); + IHTMLStorage_Release(storage2); + IHTMLStorage_Release(storage); + IHTMLWindow6_Release(window6); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow7, (void**)&window7); + ok(hres == S_OK, "Could not get IHTMLWindow7: %08lx\n", hres); + hres = IHTMLWindow7_get_performance(window7, &res); + ok(hres == S_OK, "get_performance failed: %08lx\n", hres); + ok(V_VT(&res) == VT_DISPATCH, "V_VT(performance) = %d\n", V_VT(&res)); + hres = IDispatch_QueryInterface(V_DISPATCH(&res), &IID_IHTMLPerformance, (void**)&perf2); + ok(hres == S_OK, "Could not get IHTMLPerformance: %08lx\n", hres); + ok(perf != perf2, "perf == perf2\n"); + IHTMLPerformance_Release(perf2); + IHTMLPerformance_Release(perf); + IHTMLWindow7_Release(window7); + VariantClear(&res); } static void test_create_event(IHTMLDocument2 *doc) From 184df679bc47f13db9f408f3372d8185081523df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:56 +0200 Subject: [PATCH 0822/2777] mshtml: Tie window.location to the outer window. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even in IE9+ modes, it's still a non-JS object. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmllocation.c | 31 ++++++++++++++----------------- dlls/mshtml/htmlwindow.c | 16 ++++++++-------- dlls/mshtml/mshtml_private.h | 7 +++---- dlls/mshtml/tests/dom.c | 1 - dlls/mshtml/tests/events.c | 1 - 5 files changed, 25 insertions(+), 31 deletions(-) diff --git a/dlls/mshtml/htmllocation.c b/dlls/mshtml/htmllocation.c index 066ebb4f5e6..5c31ee02e04 100644 --- a/dlls/mshtml/htmllocation.c +++ b/dlls/mshtml/htmllocation.c @@ -38,18 +38,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); static HRESULT get_url(HTMLLocation *This, const WCHAR **ret) { - if(!This->window || !This->window->base.outer_window || !This->window->base.outer_window->url) + if(!This->window || !This->window->url) *ret = L"about:blank"; else - *ret = This->window->base.outer_window->url; + *ret = This->window->url; return S_OK; } static IUri *get_uri(HTMLLocation *This) { - if(!This->window || !This->window->base.outer_window) - return NULL; - return This->window->base.outer_window->uri; + return This->window ? This->window->uri : NULL; } static HRESULT get_url_components(HTMLLocation *This, URL_COMPONENTSW *url) @@ -165,12 +163,12 @@ static HRESULT WINAPI HTMLLocation_put_href(IHTMLLocation *iface, BSTR v) TRACE("(%p)->(%s)\n", This, debugstr_w(v)); - if(!This->window || !This->window->base.outer_window) { + if(!This->window) { FIXME("No window available\n"); return E_FAIL; } - return navigate_url(This->window->base.outer_window, v, This->window->base.outer_window->uri, BINDING_NAVIGATED); + return navigate_url(This->window, v, This->window->uri, BINDING_NAVIGATED); } static HRESULT WINAPI HTMLLocation_get_href(IHTMLLocation *iface, BSTR *p) @@ -523,7 +521,7 @@ static HRESULT WINAPI HTMLLocation_put_hash(IHTMLLocation *iface, BSTR v) TRACE("(%p)->(%s)\n", This, debugstr_w(v)); - if(!This->window || !This->window->base.outer_window) { + if(!This->window) { FIXME("No window available\n"); return E_FAIL; } @@ -536,7 +534,7 @@ static HRESULT WINAPI HTMLLocation_put_hash(IHTMLLocation *iface, BSTR v) memcpy(hash + 1, v, size - sizeof(WCHAR)); } - hres = navigate_url(This->window->base.outer_window, hash, This->window->base.outer_window->uri, BINDING_NAVIGATED); + hres = navigate_url(This->window, hash, This->window->uri, BINDING_NAVIGATED); if(hash != v) free(hash); @@ -585,12 +583,12 @@ static HRESULT WINAPI HTMLLocation_reload(IHTMLLocation *iface, VARIANT_BOOL fla } /* reload is supposed to fail if called from a script with different origin, but IE doesn't care */ - if(!is_main_content_window(This->window->base.outer_window)) { + if(!is_main_content_window(This->window)) { FIXME("Unsupported on iframe\n"); return E_NOTIMPL; } - return reload_page(This->window->base.outer_window); + return reload_page(This->window); } static HRESULT WINAPI HTMLLocation_replace(IHTMLLocation *iface, BSTR bstr) @@ -599,13 +597,12 @@ static HRESULT WINAPI HTMLLocation_replace(IHTMLLocation *iface, BSTR bstr) TRACE("(%p)->(%s)\n", This, debugstr_w(bstr)); - if(!This->window || !This->window->base.outer_window) { + if(!This->window) { FIXME("No window available\n"); return E_FAIL; } - return navigate_url(This->window->base.outer_window, bstr, This->window->base.outer_window->uri, - BINDING_NAVIGATED|BINDING_REPLACE); + return navigate_url(This->window, bstr, This->window->uri, BINDING_NAVIGATED | BINDING_REPLACE); } static HRESULT WINAPI HTMLLocation_assign(IHTMLLocation *iface, BSTR bstr) @@ -659,14 +656,14 @@ static const tid_t HTMLLocation_iface_tids[] = { 0 }; static dispex_static_data_t HTMLLocation_dispex = { - L"Object", + L"Location", NULL, DispHTMLLocation_tid, HTMLLocation_iface_tids }; -HRESULT HTMLLocation_Create(HTMLInnerWindow *window, HTMLLocation **ret) +HRESULT HTMLLocation_Create(HTMLOuterWindow *window, HTMLLocation **ret) { HTMLLocation *location; @@ -679,7 +676,7 @@ HRESULT HTMLLocation_Create(HTMLInnerWindow *window, HTMLLocation **ret) location->window = window; init_dispatch(&location->dispex, (IUnknown*)&location->IHTMLLocation_iface, &HTMLLocation_dispex, - dispex_compat_mode(&window->event_target.dispex)); + COMPAT_MODE_QUIRKS); *ret = location; return S_OK; diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index c4c6a99f5f3..9f623e77f77 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -67,7 +67,7 @@ static inline BOOL is_outer_window(HTMLWindow *window) return &window->outer_window->base == window; } -static HRESULT get_location(HTMLInnerWindow *This, HTMLLocation **ret) +static HRESULT get_location(HTMLOuterWindow *This, HTMLLocation **ret) { if(!This->location) { HRESULT hres; @@ -237,6 +237,11 @@ static void release_outer_window(HTMLOuterWindow *This) if(This->base.inner_window) detach_inner_window(This->base.inner_window); + if(This->location) { + This->location->window = NULL; + IHTMLLocation_Release(&This->location->IHTMLLocation_iface); + } + if(This->frame_element) This->frame_element->content_window = NULL; @@ -269,11 +274,6 @@ static void release_inner_window(HTMLInnerWindow *This) free(This->global_props[i].name); free(This->global_props); - if(This->location) { - This->location->window = NULL; - IHTMLLocation_Release(&This->location->IHTMLLocation_iface); - } - if(This->image_factory) { This->image_factory->window = NULL; IHTMLImageElementFactory_Release(&This->image_factory->IHTMLImageElementFactory_iface); @@ -809,7 +809,7 @@ static HRESULT WINAPI HTMLWindow2_get_location(IHTMLWindow2 *iface, IHTMLLocatio TRACE("(%p)->(%p)\n", This, p); - hres = get_location(This->inner_window, &location); + hres = get_location(This->outer_window, &location); if(FAILED(hres)) return hres; @@ -3922,7 +3922,7 @@ static HRESULT IHTMLWindow2_location_hook(DispatchEx *dispex, WORD flags, DISPPA TRACE("forwarding to location.href\n"); - hres = get_location(This, &location); + hres = get_location(This->base.outer_window, &location); if(FAILED(hres)) return hres; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index d5a9e02aa13..c614ca99fba 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -492,7 +492,7 @@ struct HTMLLocation { LONG ref; - HTMLInnerWindow *window; + HTMLOuterWindow *window; }; typedef struct { @@ -575,6 +575,7 @@ struct HTMLOuterWindow { unsigned readystate_pending; HTMLInnerWindow *pending_window; + HTMLLocation *location; IMoniker *mon; IUri *uri; IUri *uri_nofrag; @@ -618,8 +619,6 @@ struct HTMLInnerWindow { LONG task_magic; - HTMLLocation *location; - IMoniker *mon; nsChannelBSC *bscallback; struct list bindings; @@ -993,7 +992,7 @@ void get_top_window(HTMLOuterWindow*,HTMLOuterWindow**) DECLSPEC_HIDDEN; HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow*,HTMLOptionElementFactory**) DECLSPEC_HIDDEN; HRESULT HTMLImageElementFactory_Create(HTMLInnerWindow*,HTMLImageElementFactory**) DECLSPEC_HIDDEN; HRESULT HTMLXMLHttpRequestFactory_Create(HTMLInnerWindow*,HTMLXMLHttpRequestFactory**) DECLSPEC_HIDDEN; -HRESULT HTMLLocation_Create(HTMLInnerWindow*,HTMLLocation**) DECLSPEC_HIDDEN; +HRESULT HTMLLocation_Create(HTMLOuterWindow*,HTMLLocation**) DECLSPEC_HIDDEN; HRESULT create_navigator(compat_mode_t,IOmNavigator**) DECLSPEC_HIDDEN; HRESULT create_html_screen(compat_mode_t,IHTMLScreen**) DECLSPEC_HIDDEN; HRESULT create_performance(HTMLInnerWindow*,IHTMLPerformance**) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 0d29f66744b..ab771a0751a 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -11845,7 +11845,6 @@ static void test_document_mode_lock(void) hres = IHTMLWindow2_get_location(window, &location2); ok(hres == S_OK, "get_location failed: %08lx\n", hres); - todo_wine ok(location == location2, "location != location2\n"); IHTMLLocation_Release(location2); IHTMLLocation_Release(location); diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 196ab3160a7..2165410e62d 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -3356,7 +3356,6 @@ static void test_doc_obj(IHTMLDocument2 *doc) hres = IHTMLWindow2_get_location(window, &location2); ok(hres == S_OK, "get_location failed: %08lx\n", hres); - todo_wine ok(location == location2, "location != location2\n"); IHTMLLocation_Release(location2); IHTMLLocation_Release(location); From 219ab51cb0bd2034f8af6493d38f29ec636dd249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:56 +0200 Subject: [PATCH 0823/2777] mshtml: Embed the HTMLLocation into the outer window. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gets rid of the issues with the cyclic dependency or detached location. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmllocation.c | 80 ++++++------------------------------ dlls/mshtml/htmlwindow.c | 32 ++++----------- dlls/mshtml/mshtml_private.h | 8 +--- 3 files changed, 23 insertions(+), 97 deletions(-) diff --git a/dlls/mshtml/htmllocation.c b/dlls/mshtml/htmllocation.c index 5c31ee02e04..d9e458d9c5f 100644 --- a/dlls/mshtml/htmllocation.c +++ b/dlls/mshtml/htmllocation.c @@ -36,28 +36,19 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); -static HRESULT get_url(HTMLLocation *This, const WCHAR **ret) +static inline HTMLOuterWindow *get_window(HTMLLocation *This) { - if(!This->window || !This->window->url) - *ret = L"about:blank"; - else - *ret = This->window->url; - return S_OK; + return CONTAINING_RECORD(This, HTMLOuterWindow, location); } static IUri *get_uri(HTMLLocation *This) { - return This->window ? This->window->uri : NULL; + return get_window(This)->uri; } static HRESULT get_url_components(HTMLLocation *This, URL_COMPONENTSW *url) { - const WCHAR *doc_url; - HRESULT hres; - - hres = get_url(This, &doc_url); - if(FAILED(hres)) - return hres; + const WCHAR *doc_url = get_window(This)->url ? get_window(This)->url : L"about:blank"; if(!InternetCrackUrlW(doc_url, 0, 0, url)) { FIXME("InternetCrackUrlW failed: 0x%08lx\n", GetLastError()); @@ -102,28 +93,13 @@ static HRESULT WINAPI HTMLLocation_QueryInterface(IHTMLLocation *iface, REFIID r static ULONG WINAPI HTMLLocation_AddRef(IHTMLLocation *iface) { HTMLLocation *This = impl_from_IHTMLLocation(iface); - LONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p) ref=%ld\n", This, ref); - - return ref; + return IHTMLWindow2_AddRef(&get_window(This)->base.IHTMLWindow2_iface); } static ULONG WINAPI HTMLLocation_Release(IHTMLLocation *iface) { HTMLLocation *This = impl_from_IHTMLLocation(iface); - LONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p) ref=%ld\n", This, ref); - - if(!ref) { - if(This->window) - This->window->location = NULL; - release_dispex(&This->dispex); - free(This); - } - - return ref; + return IHTMLWindow2_Release(&get_window(This)->base.IHTMLWindow2_iface); } static HRESULT WINAPI HTMLLocation_GetTypeInfoCount(IHTMLLocation *iface, UINT *pctinfo) @@ -163,12 +139,7 @@ static HRESULT WINAPI HTMLLocation_put_href(IHTMLLocation *iface, BSTR v) TRACE("(%p)->(%s)\n", This, debugstr_w(v)); - if(!This->window) { - FIXME("No window available\n"); - return E_FAIL; - } - - return navigate_url(This->window, v, This->window->uri, BINDING_NAVIGATED); + return navigate_url(get_window(This), v, get_uri(This), BINDING_NAVIGATED); } static HRESULT WINAPI HTMLLocation_get_href(IHTMLLocation *iface, BSTR *p) @@ -521,11 +492,6 @@ static HRESULT WINAPI HTMLLocation_put_hash(IHTMLLocation *iface, BSTR v) TRACE("(%p)->(%s)\n", This, debugstr_w(v)); - if(!This->window) { - FIXME("No window available\n"); - return E_FAIL; - } - if(hash[0] != '#') { unsigned size = (1 /* # */ + wcslen(v) + 1) * sizeof(WCHAR); if(!(hash = malloc(size))) @@ -534,7 +500,7 @@ static HRESULT WINAPI HTMLLocation_put_hash(IHTMLLocation *iface, BSTR v) memcpy(hash + 1, v, size - sizeof(WCHAR)); } - hres = navigate_url(This->window, hash, This->window->uri, BINDING_NAVIGATED); + hres = navigate_url(get_window(This), hash, get_uri(This), BINDING_NAVIGATED); if(hash != v) free(hash); @@ -577,18 +543,13 @@ static HRESULT WINAPI HTMLLocation_reload(IHTMLLocation *iface, VARIANT_BOOL fla TRACE("(%p)->(%x)\n", This, flag); - if(!This->window) { - FIXME("No window available\n"); - return E_FAIL; - } - /* reload is supposed to fail if called from a script with different origin, but IE doesn't care */ - if(!is_main_content_window(This->window)) { + if(!is_main_content_window(get_window(This))) { FIXME("Unsupported on iframe\n"); return E_NOTIMPL; } - return reload_page(This->window); + return reload_page(get_window(This)); } static HRESULT WINAPI HTMLLocation_replace(IHTMLLocation *iface, BSTR bstr) @@ -597,12 +558,7 @@ static HRESULT WINAPI HTMLLocation_replace(IHTMLLocation *iface, BSTR bstr) TRACE("(%p)->(%s)\n", This, debugstr_w(bstr)); - if(!This->window) { - FIXME("No window available\n"); - return E_FAIL; - } - - return navigate_url(This->window, bstr, This->window->uri, BINDING_NAVIGATED | BINDING_REPLACE); + return navigate_url(get_window(This), bstr, get_uri(This), BINDING_NAVIGATED | BINDING_REPLACE); } static HRESULT WINAPI HTMLLocation_assign(IHTMLLocation *iface, BSTR bstr) @@ -662,22 +618,10 @@ static dispex_static_data_t HTMLLocation_dispex = { HTMLLocation_iface_tids }; - -HRESULT HTMLLocation_Create(HTMLOuterWindow *window, HTMLLocation **ret) +void HTMLLocation_Init(HTMLLocation *location) { - HTMLLocation *location; - - location = malloc(sizeof(*location)); - if(!location) - return E_OUTOFMEMORY; - location->IHTMLLocation_iface.lpVtbl = &HTMLLocationVtbl; - location->ref = 1; - location->window = window; init_dispatch(&location->dispex, (IUnknown*)&location->IHTMLLocation_iface, &HTMLLocation_dispex, COMPAT_MODE_QUIRKS); - - *ret = location; - return S_OK; } diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 9f623e77f77..d32b6743e9b 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -67,19 +67,13 @@ static inline BOOL is_outer_window(HTMLWindow *window) return &window->outer_window->base == window; } -static HRESULT get_location(HTMLOuterWindow *This, HTMLLocation **ret) +static void get_location(HTMLOuterWindow *This, HTMLLocation **ret) { - if(!This->location) { - HRESULT hres; + if(!This->location.dispex.outer) + HTMLLocation_Init(&This->location); - hres = HTMLLocation_Create(This, &This->location); - if(FAILED(hres)) - return hres; - } - - IHTMLLocation_AddRef(&This->location->IHTMLLocation_iface); - *ret = This->location; - return S_OK; + IHTMLLocation_AddRef(&This->location.IHTMLLocation_iface); + *ret = &This->location; } void get_top_window(HTMLOuterWindow *window, HTMLOuterWindow **ret) @@ -237,10 +231,8 @@ static void release_outer_window(HTMLOuterWindow *This) if(This->base.inner_window) detach_inner_window(This->base.inner_window); - if(This->location) { - This->location->window = NULL; - IHTMLLocation_Release(&This->location->IHTMLLocation_iface); - } + if(This->location.dispex.outer) + release_dispex(&This->location.dispex); if(This->frame_element) This->frame_element->content_window = NULL; @@ -805,14 +797,10 @@ static HRESULT WINAPI HTMLWindow2_get_location(IHTMLWindow2 *iface, IHTMLLocatio { HTMLWindow *This = impl_from_IHTMLWindow2(iface); HTMLLocation *location; - HRESULT hres; TRACE("(%p)->(%p)\n", This, p); - hres = get_location(This->outer_window, &location); - if(FAILED(hres)) - return hres; - + get_location(This->outer_window, &location); *p = &location->IHTMLLocation_iface; return S_OK; } @@ -3922,9 +3910,7 @@ static HRESULT IHTMLWindow2_location_hook(DispatchEx *dispex, WORD flags, DISPPA TRACE("forwarding to location.href\n"); - hres = get_location(This->base.outer_window, &location); - if(FAILED(hres)) - return hres; + get_location(This->base.outer_window, &location); hres = IDispatchEx_InvokeEx(&location->dispex.IDispatchEx_iface, DISPID_VALUE, 0, flags, dp, res, ei, caller); IHTMLLocation_Release(&location->IHTMLLocation_iface); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index c614ca99fba..dbf7b922997 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -489,10 +489,6 @@ typedef struct { struct HTMLLocation { DispatchEx dispex; IHTMLLocation IHTMLLocation_iface; - - LONG ref; - - HTMLOuterWindow *window; }; typedef struct { @@ -575,7 +571,7 @@ struct HTMLOuterWindow { unsigned readystate_pending; HTMLInnerWindow *pending_window; - HTMLLocation *location; + HTMLLocation location; IMoniker *mon; IUri *uri; IUri *uri_nofrag; @@ -992,7 +988,7 @@ void get_top_window(HTMLOuterWindow*,HTMLOuterWindow**) DECLSPEC_HIDDEN; HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow*,HTMLOptionElementFactory**) DECLSPEC_HIDDEN; HRESULT HTMLImageElementFactory_Create(HTMLInnerWindow*,HTMLImageElementFactory**) DECLSPEC_HIDDEN; HRESULT HTMLXMLHttpRequestFactory_Create(HTMLInnerWindow*,HTMLXMLHttpRequestFactory**) DECLSPEC_HIDDEN; -HRESULT HTMLLocation_Create(HTMLOuterWindow*,HTMLLocation**) DECLSPEC_HIDDEN; +void HTMLLocation_Init(HTMLLocation*) DECLSPEC_HIDDEN; HRESULT create_navigator(compat_mode_t,IOmNavigator**) DECLSPEC_HIDDEN; HRESULT create_html_screen(compat_mode_t,IHTMLScreen**) DECLSPEC_HIDDEN; HRESULT create_performance(HTMLInnerWindow*,IHTMLPerformance**) DECLSPEC_HIDDEN; From 0decbbad797b85d7594914bc1c6eb65019216643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:56 +0200 Subject: [PATCH 0824/2777] mshtml: Set outer window to uninitialized page when document obj is released. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlwindow.c | 45 +++++++++++++++++- dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/oleobj.c | 15 +++++- dlls/mshtml/tests/events.c | 92 ++++++++++++++++++++++++++++++++++++ dlls/mshtml/tests/htmldoc.c | 36 +++++++++++++- dlls/mshtml/tests/script.c | 17 +++++++ 6 files changed, 201 insertions(+), 5 deletions(-) diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index d32b6743e9b..5e8ec4207bd 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -2865,7 +2865,7 @@ static HRESULT WINAPI HTMLPrivateWindow_GetAddressBarUrl(IHTMLPrivateWindow *ifa if(!url) return E_INVALIDARG; - *url = SysAllocString(This->outer_window->url); + *url = SysAllocString(This->outer_window->url ? This->outer_window->url : L"about:blank"); return S_OK; } @@ -4155,6 +4155,49 @@ HRESULT create_pending_window(HTMLOuterWindow *outer_window, nsChannelBSC *chann return S_OK; } +void set_window_uninitialized(HTMLOuterWindow *window, HTMLDocumentNode *doc_node) +{ + nsIDOMDOMImplementation *implementation; + nsIDOMDocument *nsdoc; + nsAString nsstr; + nsresult nsres; + HRESULT hres; + + window->readystate = READYSTATE_UNINITIALIZED; + set_current_uri(window, NULL); + if(window->mon) { + IMoniker_Release(window->mon); + window->mon = NULL; + } + + hres = create_pending_window(window, NULL); + if(FAILED(hres)) + return; + + nsres = nsIDOMDocument_GetImplementation(doc_node->dom_document, &implementation); + if(NS_FAILED(nsres)) + return; + + nsAString_InitDepend(&nsstr, L""); + nsres = nsIDOMDOMImplementation_CreateHTMLDocument(implementation, &nsstr, &nsdoc); + nsIDOMDOMImplementation_Release(implementation); + nsAString_Finish(&nsstr); + if(NS_FAILED(nsres)) + return; + + hres = create_document_node(nsdoc, window->browser, window->pending_window, COMPAT_MODE_QUIRKS, &window->pending_window->doc); + nsIDOMDocument_Release(nsdoc); + if(FAILED(hres)) + return; + window->pending_window->doc->doc_obj = NULL; + window->pending_window->doc->cp_container.forward_container = NULL; + + if(window->base.inner_window) + detach_inner_window(window->base.inner_window); + window->base.inner_window = window->pending_window; + window->pending_window = NULL; +} + HRESULT update_window_doc(HTMLInnerWindow *window) { HTMLOuterWindow *outer_window = window->base.outer_window; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index dbf7b922997..ed7f44420fa 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -982,6 +982,7 @@ HRESULT create_document_node(nsIDOMDocument*,GeckoBrowser*,HTMLInnerWindow*, HRESULT create_doctype_node(HTMLDocumentNode*,nsIDOMNode*,HTMLDOMNode**) DECLSPEC_HIDDEN; HRESULT create_outer_window(GeckoBrowser*,mozIDOMWindowProxy*,HTMLOuterWindow*,HTMLOuterWindow**) DECLSPEC_HIDDEN; +void set_window_uninitialized(HTMLOuterWindow*,HTMLDocumentNode*) DECLSPEC_HIDDEN; HRESULT update_window_doc(HTMLInnerWindow*) DECLSPEC_HIDDEN; HTMLOuterWindow *mozwindow_to_window(const mozIDOMWindowProxy*) DECLSPEC_HIDDEN; void get_top_window(HTMLOuterWindow*,HTMLOuterWindow**) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/oleobj.c b/dlls/mshtml/oleobj.c index d1853435606..6167dbdde74 100644 --- a/dlls/mshtml/oleobj.c +++ b/dlls/mshtml/oleobj.c @@ -3440,8 +3440,19 @@ static ULONG WINAPI HTMLDocumentObj_Release(IUnknown *iface) if(!ref) { if(This->doc_node) { - This->doc_node->doc_obj = NULL; - IHTMLDOMNode_Release(&This->doc_node->node.IHTMLDOMNode_iface); + HTMLDocumentNode *doc_node = This->doc_node; + + /* The nscontainer holds a ref as well as us, so only do it if anyone else is holding it */ + if(This->window->base.ref > 2) { + /* Protect against re-entry */ + This->ref = 1; + set_window_uninitialized(This->window, doc_node); + assert(This->ref == 1); + This->ref = 0; + } + + doc_node->doc_obj = NULL; + IHTMLDOMNode_Release(&doc_node->node.IHTMLDOMNode_iface); } if(This->window) IHTMLWindow2_Release(&This->window->base.IHTMLWindow2_iface); diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 2165410e62d..503f95bcc7c 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -5754,6 +5754,97 @@ static void test_empty_document(void) IHTMLDocument2_Release(doc); } +static void test_document_close(void) +{ + IHTMLPrivateWindow *priv_window; + IHTMLDocument2 *doc, *doc_node; + IHTMLDocument3 *doc3; + IHTMLWindow2 *window; + IHTMLElement *elem; + HRESULT hres; + BSTR bstr; + + doc = create_document_with_origin(input_doc_str); + if(!doc) + return; + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_document(window, &doc_node); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLPrivateWindow, (void**)&priv_window); + ok(hres == S_OK, "Could not get IHTMLPrivateWindow) interface: %08lx\n", hres); + hres = IHTMLPrivateWindow_GetAddressBarUrl(priv_window, &bstr); + ok(hres == S_OK, "GetAddressBarUrl failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"http://winetest.example.org/"), "unexpected address bar: %s\n", wine_dbgstr_w(bstr)); + IHTMLPrivateWindow_Release(priv_window); + SysFreeString(bstr); + + elem = get_elem_id(doc_node, L"inputid"); + IHTMLElement_Release(elem); + + set_client_site(doc, FALSE); + IHTMLDocument2_Release(doc); + + hres = IHTMLWindow2_get_document(window, &doc); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + ok(doc != doc_node, "doc == doc_node\n"); + + hres = IHTMLDocument2_get_readyState(doc_node, &bstr); + ok(hres == S_OK, "get_readyState failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"uninitialized"), "readyState = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + hres = IHTMLDocument2_get_readyState(doc, &bstr); + ok(hres == S_OK, "get_readyState failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"uninitialized"), "readyState = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLPrivateWindow, (void**)&priv_window); + ok(hres == S_OK, "Could not get IHTMLPrivateWindow) interface: %08lx\n", hres); + hres = IHTMLPrivateWindow_GetAddressBarUrl(priv_window, &bstr); + ok(hres == S_OK, "GetAddressBarUrl failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"about:blank"), "unexpected address bar: %s\n", wine_dbgstr_w(bstr)); + IHTMLPrivateWindow_Release(priv_window); + SysFreeString(bstr); + + bstr = SysAllocString(L"inputid"); + doc3 = get_doc3_iface((IUnknown*)doc); + hres = IHTMLDocument3_getElementById(doc3, bstr, &elem); + ok(hres == S_OK, "getElementById returned: %08lx\n", hres); + ok(elem == NULL, "elem != NULL\n"); + IHTMLDocument3_Release(doc3); + SysFreeString(bstr); + + IHTMLDocument2_Release(doc_node); + IHTMLDocument2_Release(doc); + IHTMLWindow2_Release(window); + + doc = create_document(); + if(!doc) + return; + set_client_site(doc, TRUE); + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_document(window, &doc_node); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + + set_client_site(doc, FALSE); + IHTMLDocument2_Release(doc); + + hres = IHTMLWindow2_get_document(window, &doc); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + ok(doc != doc_node, "doc == doc_node\n"); + + IHTMLDocument2_Release(doc_node); + IHTMLDocument2_Release(doc); + IHTMLWindow2_Release(window); +} + static void test_storage_events(const char *doc_str) { static struct { @@ -6030,6 +6121,7 @@ START_TEST(events) } test_empty_document(); + test_document_close(); test_storage_events(empty_doc_str); if(is_ie9plus) test_storage_events(empty_doc_ie9_str); diff --git a/dlls/mshtml/tests/htmldoc.c b/dlls/mshtml/tests/htmldoc.c index e4780e9c379..d723df0ecd8 100644 --- a/dlls/mshtml/tests/htmldoc.c +++ b/dlls/mshtml/tests/htmldoc.c @@ -8260,10 +8260,12 @@ static void test_doc_domain(IHTMLDocument2 *doc) static void test_HTMLDocument_http(BOOL with_wbapp) { + IHTMLDocument2 *doc, *doc_node; + IHTMLWindow2 *window; IMoniker *http_mon; - IHTMLDocument2 *doc; - ULONG ref; HRESULT hres; + ULONG ref; + BSTR bstr; trace("Testing HTMLDocument (http%s)...\n", with_wbapp ? " with IWebBrowserApp" : ""); @@ -8327,12 +8329,42 @@ static void test_HTMLDocument_http(BOOL with_wbapp) test_IsDirty(doc, S_FALSE); test_GetCurMoniker((IUnknown*)doc, NULL, prev_url, support_wbapp); + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_document(window, &doc_node); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + + hres = IHTMLDocument2_get_readyState(doc_node, &bstr); + ok(hres == S_OK, "get_readyState failed: %08lx\n", hres); + todo_wine_if(support_wbapp) + ok(!wcscmp(bstr, support_wbapp ? L"interactive" : L"complete"), "readyState = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + if(view) IOleDocumentView_Release(view); view = NULL; release_document(doc); + hres = IHTMLWindow2_get_document(window, &doc); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + ok(doc != doc_node, "doc == doc_node\n"); + + hres = IHTMLDocument2_get_readyState(doc_node, &bstr); + ok(hres == S_OK, "get_readyState failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"uninitialized"), "readyState = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + hres = IHTMLDocument2_get_readyState(doc, &bstr); + ok(hres == S_OK, "get_readyState failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"uninitialized"), "readyState = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + IHTMLDocument2_Release(doc_node); + IHTMLDocument2_Release(doc); + IHTMLWindow2_Release(window); + ref = IMoniker_Release(http_mon); ok(!ref, "ref=%ld, expected 0\n", ref); } diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index c06009d1996..b3b78070f50 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -4224,7 +4224,10 @@ static void test_exec_script(IHTMLDocument2 *doc, const WCHAR *codew, const WCHA static void test_simple_script(void) { + IHTMLDocument2 *doc_node; + IHTMLWindow2 *window; IHTMLDocument2 *doc; + HRESULT hres; doc = create_document(); if(!doc) @@ -4288,6 +4291,12 @@ static void test_simple_script(void) if(window_dispex) IDispatchEx_Release(window_dispex); + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_document(window, &doc_node); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + SET_EXPECT(SetScriptState_DISCONNECTED); SET_EXPECT(Close); SET_EXPECT(Close2); @@ -4297,6 +4306,14 @@ static void test_simple_script(void) CHECK_CALLED(SetScriptState_DISCONNECTED); CHECK_CALLED(Close); CHECK_CALLED(Close2); + + hres = IHTMLWindow2_get_document(window, &doc); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + ok(doc != doc_node, "doc == doc_node\n"); + + IHTMLDocument2_Release(doc_node); + IHTMLDocument2_Release(doc); + IHTMLWindow2_Release(window); } static void run_from_moniker(IMoniker *mon) From 0be1b2ea2b0ba48738865b2398a6f014ea77b8c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:56 +0200 Subject: [PATCH 0825/2777] mshtml: Return proper errors when navigating with no browser. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlwindow.c | 2 +- dlls/mshtml/navigate.c | 3 +++ dlls/mshtml/tests/events.c | 22 +++++++++++++++++++++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 5e8ec4207bd..740d342087c 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -2794,7 +2794,7 @@ static HRESULT WINAPI HTMLPrivateWindow_SuperNavigate(IHTMLPrivateWindow *iface, debugstr_variant(post_data_var), debugstr_variant(headers_var), flags); if(!window || !window->browser) - return E_UNEXPECTED; + return E_FAIL; if(window->browser->doc->hostui) { hres = IDocHostUIHandler_TranslateUrl(window->browser->doc->hostui, 0, url, &translated_url); diff --git a/dlls/mshtml/navigate.c b/dlls/mshtml/navigate.c index fd92483cbf5..7d5932df989 100644 --- a/dlls/mshtml/navigate.c +++ b/dlls/mshtml/navigate.c @@ -2636,6 +2636,9 @@ HRESULT navigate_url(HTMLOuterWindow *window, const WCHAR *new_url, IUri *base_u BSTR display_uri; HRESULT hres; + if(!window->browser) + return E_UNEXPECTED; + if(new_url && base_uri) hres = CoInternetCombineUrlEx(base_uri, new_url, URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO, &nav_uri, 0); diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 503f95bcc7c..0f16f0b554a 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -5758,11 +5758,13 @@ static void test_document_close(void) { IHTMLPrivateWindow *priv_window; IHTMLDocument2 *doc, *doc_node; + IHTMLLocation *location; IHTMLDocument3 *doc3; IHTMLWindow2 *window; IHTMLElement *elem; + BSTR bstr, bstr2; HRESULT hres; - BSTR bstr; + VARIANT v; doc = create_document_with_origin(input_doc_str); if(!doc) @@ -5842,6 +5844,24 @@ static void test_document_close(void) IHTMLDocument2_Release(doc_node); IHTMLDocument2_Release(doc); + + bstr = SysAllocString(L"about:blank"); + hres = IHTMLWindow2_get_location(window, &location); + ok(hres == S_OK, "get_location failed: %08lx\n", hres); + hres = IHTMLLocation_put_href(location, bstr); + ok(hres == E_UNEXPECTED, "put_href returned: %08lx\n", hres); + IHTMLLocation_Release(location); + + V_VT(&v) = VT_EMPTY; + bstr2 = SysAllocString(L""); + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLPrivateWindow, (void**)&priv_window); + ok(hres == S_OK, "Could not get IHTMLPrivateWindow) interface: %08lx\n", hres); + hres = IHTMLPrivateWindow_SuperNavigate(priv_window, bstr, bstr2, NULL, NULL, &v, &v, 0); + ok(hres == E_FAIL, "SuperNavigate returned: %08lx\n", hres); + IHTMLPrivateWindow_Release(priv_window); + SysFreeString(bstr2); + SysFreeString(bstr); + IHTMLWindow2_Release(window); } From af6d409577a47462bccb43da286c4b443f478745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:56 +0200 Subject: [PATCH 0826/2777] mshtml: Keep a ref to the outer window from detached inner windows. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Accessing the outer window from an inner window (such as its event target) should always be valid, even if it's not referring to the same inner window, because the outer window is supposed to proxy all requests to the "current" inner window. Signed-off-by: Gabriel Ivăncescu --- This is especially needed by the patch that will give refs to the outer window to all external callers, since inner windows are an implementation detail. Consider the case where an external event handler for a detached inner window is fired, but after that patch, such inner window's event target needs to obtain the actual outer window, so it must always be available. --- dlls/mshtml/htmlwindow.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 740d342087c..635f88b7266 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -104,10 +104,11 @@ static inline HRESULT get_window_event(HTMLWindow *window, eventid_t eid, VARIAN return get_event_handler(&window->inner_window->event_target, eid, var); } -static void detach_inner_window(HTMLInnerWindow *window) +static ULONG detach_inner_window(HTMLInnerWindow *window) { HTMLOuterWindow *outer_window = window->base.outer_window; HTMLDocumentNode *doc = window->doc; + ULONG ref = 0; while(!list_empty(&window->children)) { HTMLOuterWindow *child = LIST_ENTRY(list_tail(&window->children), HTMLOuterWindow, sibling_entry); @@ -130,12 +131,18 @@ static void detach_inner_window(HTMLInnerWindow *window) abort_window_bindings(window); remove_target_tasks(window->task_magic); release_script_hosts(window); - window->base.outer_window = NULL; - if(outer_window && outer_window->base.inner_window == window) { + if(outer_window) { + assert(outer_window->base.inner_window == window); + + /* Detached inner windows hold a ref to the outer window */ + IHTMLWindow2_AddRef(&outer_window->base.IHTMLWindow2_iface); + outer_window->base.inner_window = NULL; - IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface); + ref = IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface); } + + return ref; } static inline HTMLWindow *impl_from_IHTMLWindow2(IHTMLWindow2 *iface) @@ -228,8 +235,6 @@ static void release_outer_window(HTMLOuterWindow *This) remove_target_tasks(This->task_magic); set_current_mon(This, NULL, 0); set_current_uri(This, NULL); - if(This->base.inner_window) - detach_inner_window(This->base.inner_window); if(This->location.dispex.outer) release_dispex(&This->location.dispex); @@ -248,10 +253,18 @@ static void release_outer_window(HTMLOuterWindow *This) static void release_inner_window(HTMLInnerWindow *This) { + HTMLOuterWindow *outer_window = This->base.outer_window; unsigned i; TRACE("%p\n", This); + /* If we're releasing inner window, it means we're already detached + from the outer window, and detached inner windows hold a ref to it */ + if(outer_window) { + This->base.outer_window = NULL; + IHTMLWindow2_Release(&outer_window->base.IHTMLWindow2_iface); + } + detach_inner_window(This); if(This->doc) { @@ -317,6 +330,12 @@ static ULONG WINAPI HTMLWindow2_Release(IHTMLWindow2 *iface) TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { + if(is_outer_window(This) && This->inner_window) { + /* Detached inner windows hold a ref to the outer window, + so return the ref to us if it's still alive after */ + return detach_inner_window(This->inner_window) ? 1 : 0; + } + if (This->console) IWineMSHTMLConsole_Release(This->console); From 17a544cf8691b9c0a9e49741bfa4eb002bf65464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:56 +0200 Subject: [PATCH 0827/2777] mshtml: Get rid of outer window NULL checks from inner windows. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Detached inner windows now hold valid pointers to the outer window. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmldoc.c | 2 +- dlls/mshtml/htmlform.c | 2 +- dlls/mshtml/htmlwindow.c | 45 ++++++++++++++++----------------------- dlls/mshtml/mutation.c | 4 ++-- dlls/mshtml/omnavigator.c | 2 +- dlls/mshtml/script.c | 2 +- 6 files changed, 24 insertions(+), 33 deletions(-) diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 66b593920e2..a07462f827f 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -3648,7 +3648,7 @@ static HRESULT WINAPI HTMLDocument7_get_defaultView(IHTMLDocument7 *iface, IHTML TRACE("(%p)->(%p)\n", This, p); - if(This->window && This->window->base.outer_window) { + if(This->window) { *p = &This->window->base.outer_window->base.IHTMLWindow2_iface; IHTMLWindow2_AddRef(*p); }else { diff --git a/dlls/mshtml/htmlform.c b/dlls/mshtml/htmlform.c index 8a15bbf307d..505e8330cb9 100644 --- a/dlls/mshtml/htmlform.c +++ b/dlls/mshtml/htmlform.c @@ -570,7 +570,7 @@ static HRESULT WINAPI HTMLFormElement_submit(IHTMLFormElement *iface) if(This->element.node.doc) { HTMLDocumentNode *doc = This->element.node.doc; - if(doc->window && doc->window->base.outer_window) + if(doc->window) this_window = doc->window->base.outer_window; } if(!this_window) { diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 635f88b7266..f81cb15b30e 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -650,7 +650,7 @@ static HRESULT WINAPI HTMLWindow2_alert(IHTMLWindow2 *iface, BSTR message) TRACE("(%p)->(%s)\n", This, debugstr_w(message)); - if(!This->outer_window || !This->outer_window->browser) + if(!This->outer_window->browser) return E_UNEXPECTED; if(!LoadStringW(get_shdoclc(), IDS_MESSAGE_BOX_TITLE, title, ARRAY_SIZE(title))) { @@ -683,7 +683,7 @@ static HRESULT WINAPI HTMLWindow2_confirm(IHTMLWindow2 *iface, BSTR message, if(!confirmed) return E_INVALIDARG; - if(!This->outer_window || !This->outer_window->browser) + if(!This->outer_window->browser) return E_UNEXPECTED; if(!LoadStringW(get_shdoclc(), IDS_MESSAGE_BOX_TITLE, wszTitle, ARRAY_SIZE(wszTitle))) { @@ -777,7 +777,7 @@ static HRESULT WINAPI HTMLWindow2_prompt(IHTMLWindow2 *iface, BSTR message, TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(message), debugstr_w(dststr), textdata); - if(!This->outer_window || !This->outer_window->browser) + if(!This->outer_window->browser) return E_UNEXPECTED; if(textdata) V_VT(textdata) = VT_NULL; @@ -908,7 +908,7 @@ static HRESULT WINAPI HTMLWindow2_close(IHTMLWindow2 *iface) TRACE("(%p)\n", This); - if(!window || !window->browser) { + if(!window->browser) { FIXME("No document object\n"); return E_FAIL; } @@ -1015,7 +1015,7 @@ static HRESULT WINAPI HTMLWindow2_open(IHTMLWindow2 *iface, BSTR url, BSTR name, if(replace) FIXME("unsupported relace argument\n"); - if(!window || !window->browser || !window->uri_nofrag) + if(!window->browser || !window->uri_nofrag) return E_UNEXPECTED; if(name && *name == '_') { @@ -1372,7 +1372,7 @@ static HRESULT WINAPI HTMLWindow2_focus(IHTMLWindow2 *iface) TRACE("(%p)->()\n", This); - if(!This->outer_window || !This->outer_window->browser) + if(!This->outer_window->browser) return E_UNEXPECTED; SetFocus(This->outer_window->browser->doc->hwnd); @@ -1539,7 +1539,7 @@ static HRESULT WINAPI HTMLWindow2_get_external(IHTMLWindow2 *iface, IDispatch ** TRACE("(%p)->(%p)\n", This, p); - if(!This->outer_window || !This->outer_window->browser) + if(!This->outer_window->browser) return E_UNEXPECTED; *p = NULL; @@ -2380,9 +2380,6 @@ static HRESULT WINAPI HTMLWindow7_getComputedStyle(IHTMLWindow7 *iface, IHTMLDOM TRACE("(%p)->(%p %s %p)\n", This, node, debugstr_w(pseudo_elt), p); - if(!This->outer_window || !This->inner_window) - return E_UNEXPECTED; - hres = IHTMLDOMNode_QueryInterface(node, &IID_IHTMLElement, (void**)&elem); if(FAILED(hres)) return hres; @@ -2812,7 +2809,7 @@ static HRESULT WINAPI HTMLPrivateWindow_SuperNavigate(IHTMLPrivateWindow *iface, TRACE("(%p)->(%s %s %s %s %s %s %lx)\n", This, debugstr_w(url), debugstr_w(arg2), debugstr_w(arg3), debugstr_w(arg4), debugstr_variant(post_data_var), debugstr_variant(headers_var), flags); - if(!window || !window->browser) + if(!window->browser) return E_FAIL; if(window->browser->doc->hostui) { @@ -3586,6 +3583,7 @@ static HRESULT WINAPI WindowDispEx_GetDispID(IDispatchEx *iface, BSTR bstrName, { HTMLWindow *This = impl_from_IDispatchEx(iface); HTMLInnerWindow *window = This->inner_window; + HTMLOuterWindow *frame; HRESULT hres; TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(bstrName), grfdex, pid); @@ -3598,20 +3596,16 @@ static HRESULT WINAPI WindowDispEx_GetDispID(IDispatchEx *iface, BSTR bstrName, if(hres != DISP_E_UNKNOWNNAME) return hres; - if(This->outer_window) { - HTMLOuterWindow *frame; - - hres = get_frame_by_name(This->outer_window, bstrName, FALSE, &frame); - if(SUCCEEDED(hres) && frame) { - global_prop_t *prop; + hres = get_frame_by_name(This->outer_window, bstrName, FALSE, &frame); + if(SUCCEEDED(hres) && frame) { + global_prop_t *prop; - prop = alloc_global_prop(window, GLOBAL_FRAMEVAR, bstrName); - if(!prop) - return E_OUTOFMEMORY; + prop = alloc_global_prop(window, GLOBAL_FRAMEVAR, bstrName); + if(!prop) + return E_OUTOFMEMORY; - *pid = prop_to_dispid(window, prop); - return S_OK; - } + *pid = prop_to_dispid(window, prop); + return S_OK; } if(window->doc) { @@ -3750,7 +3744,7 @@ static HRESULT WINAPI HTMLWindowSP_QueryService(IServiceProvider *iface, REFGUID TRACE("(%p)->(%s %s %p)\n", This, debugstr_mshtml_guid(guidService), debugstr_mshtml_guid(riid), ppv); - if(!This->outer_window || !This->outer_window->browser) + if(!This->outer_window->browser) return E_NOINTERFACE; return IServiceProvider_QueryService(&This->outer_window->browser->doc->IServiceProvider_iface, @@ -3852,9 +3846,6 @@ static HRESULT HTMLWindow_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD return E_NOTIMPL; } case GLOBAL_FRAMEVAR: - if(!This->base.outer_window) - return E_UNEXPECTED; - switch(flags) { case DISPATCH_PROPERTYGET: { HTMLOuterWindow *frame; diff --git a/dlls/mshtml/mutation.c b/dlls/mshtml/mutation.c index e308c1af31b..92f0c82b276 100644 --- a/dlls/mshtml/mutation.c +++ b/dlls/mshtml/mutation.c @@ -400,7 +400,7 @@ static void set_document_mode(HTMLDocumentNode *doc, compat_mode_t document_mode TRACE("%p: %d\n", doc, document_mode); - max_compat_mode = doc->window && doc->window->base.outer_window + max_compat_mode = doc->window ? get_max_compat_mode(doc->window->base.outer_window->uri) : COMPAT_MODE_IE11; if(max_compat_mode < document_mode) { @@ -859,7 +859,7 @@ static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface, but it is not set by default on native, and the behavior is still different. This was tested by removing all iexplore.exe values from any FeatureControl subkeys, and renaming the test executable to iexplore.exe, which changed its default compat mode in such cases. */ - if(This->window && This->window->base.outer_window && is_iexplore()) { + if(This->window && is_iexplore()) { HTMLOuterWindow *window = This->window->base.outer_window; DWORD zone; HRESULT hres; diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index aa9f33567c2..aad722ab0b8 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -673,7 +673,7 @@ static HRESULT WINAPI OmHistory_get_length(IOmHistory *iface, short *p) TRACE("(%p)->(%p)\n", This, p); - if(This->window && This->window->base.outer_window) + if(This->window) browser = This->window->base.outer_window->browser; *p = browser && browser->doc->travel_log diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c index 7c9fd1887d1..f87ebe8aee1 100644 --- a/dlls/mshtml/script.c +++ b/dlls/mshtml/script.c @@ -509,7 +509,7 @@ static HRESULT WINAPI ActiveScriptSiteWindow_GetWindow(IActiveScriptSiteWindow * TRACE("(%p)->(%p)\n", This, phwnd); - if(!This->window || !This->window->base.outer_window) + if(!This->window) return E_UNEXPECTED; *phwnd = This->window->base.outer_window->browser->doc->hwnd; From 43d326b6807d5a9915622fa6e9a9b05b4ba9c374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:57 +0200 Subject: [PATCH 0828/2777] mshtml: Expose and use an EventTarget iface on the outer window. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The inner window is an implementation detail and should never be accessed directly by non-mshtml code. Signed-off-by: Gabriel Ivăncescu --- Needed by next patch as well to complete this. --- dlls/mshtml/htmldoc.c | 2 + dlls/mshtml/htmlelem.c | 1 + dlls/mshtml/htmlevent.c | 29 +++++++-- dlls/mshtml/htmlevent.h | 1 + dlls/mshtml/htmlwindow.c | 112 ++++++++++++++++++++++++++++++++++- dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/events.c | 18 ++++++ dlls/mshtml/xmlhttprequest.c | 1 + 8 files changed, 159 insertions(+), 6 deletions(-) diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index a07462f827f..c69fface8c3 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -369,6 +369,7 @@ static event_target_vtbl_t DocumentType_event_target_vtbl = { { NULL, }, + NULL, DocumentType_get_gecko_target, NULL, NULL, @@ -6130,6 +6131,7 @@ static const event_target_vtbl_t HTMLDocumentNode_event_target_vtbl = { HTMLDocumentNode_get_compat_mode, NULL }, + NULL, HTMLDocumentNode_get_gecko_target, HTMLDocumentNode_bind_event, NULL, diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index b66b0c22552..5574fc075d3 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -7240,6 +7240,7 @@ static event_target_vtbl_t HTMLElement_event_target_vtbl = { NULL, HTMLElement_populate_props }, + NULL, HTMLElement_get_gecko_target, HTMLElement_bind_event, HTMLElement_event_target_dispatch_nsevent_hook, diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index bcde9f38bba..3fc7d0bc567 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -318,6 +318,21 @@ static void remove_event_listener(EventTarget *event_target, const WCHAR *type_n } } +static IEventTarget *get_event_target_iface(EventTarget *event_target) +{ + const event_target_vtbl_t *vtbl = dispex_get_vtbl(&event_target->dispex); + IEventTarget *ret; + + if(vtbl && vtbl->get_dispatch_this) { + IDispatch *disp = vtbl->get_dispatch_this(&event_target->dispex); + IDispatch_QueryInterface(disp, &IID_IEventTarget, (void**)&ret); + }else { + ret = &event_target->IEventTarget_iface; + IEventTarget_AddRef(ret); + } + return ret; +} + static HRESULT get_gecko_target(IEventTarget*,nsIDOMEventTarget**); typedef struct { @@ -1036,7 +1051,7 @@ static HRESULT WINAPI DOMEvent_get_currentTarget(IDOMEvent *iface, IEventTarget TRACE("(%p)->(%p)\n", This, p); if(This->current_target) - IEventTarget_AddRef(*p = &This->current_target->IEventTarget_iface); + *p = get_event_target_iface(This->current_target); else *p = NULL; return S_OK; @@ -1069,7 +1084,7 @@ static HRESULT WINAPI DOMEvent_get_target(IDOMEvent *iface, IEventTarget **p) TRACE("(%p)->(%p)\n", This, p); if(This->target) - IEventTarget_AddRef(*p = &This->target->IEventTarget_iface); + *p = get_event_target_iface(This->target); else *p = NULL; return S_OK; @@ -3393,10 +3408,10 @@ static BOOL is_cp_event(cp_static_data_t *data, DISPID dispid) static void call_event_handlers(EventTarget *event_target, DOMEvent *event, dispatch_mode_t dispatch_mode) { const listener_container_t *container = get_listener_container(event_target, event->type, FALSE); + const event_target_vtbl_t *vtbl = dispex_get_vtbl(&event_target->dispex); event_listener_t *listener, listeners_buf[8], *listeners = listeners_buf; unsigned listeners_cnt, listeners_size; ConnectionPointContainer *cp_container = NULL; - const event_target_vtbl_t *vtbl = NULL; BOOL skip_onevent_listener = FALSE; VARIANT v; HRESULT hres; @@ -3417,6 +3432,8 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event, disp V_VT(&arg) = VT_DISPATCH; V_DISPATCH(&arg) = (IDispatch*)&event_target->dispex.IDispatchEx_iface; V_VT(&v) = VT_EMPTY; + if(vtbl && vtbl->get_dispatch_this) + V_DISPATCH(&arg) = vtbl->get_dispatch_this(&event_target->dispex); TRACE("%p %s >>>\n", event_target, debugstr_w(event->type)); hres = call_disp_func(listener->function, &dp, &v); @@ -3493,6 +3510,9 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event, disp V_VT(args) = VT_DISPATCH; V_DISPATCH(args) = (IDispatch*)&event_target->dispex.IDispatchEx_iface; + if(vtbl && vtbl->get_dispatch_this) + V_DISPATCH(args) = vtbl->get_dispatch_this(&event_target->dispex); + V_VT(args+1) = VT_DISPATCH; V_DISPATCH(args+1) = dispatch_mode == DISPATCH_LEGACY ? (IDispatch*)event->event_obj : (IDispatch*)&event->IDOMEvent_iface; @@ -3549,8 +3569,7 @@ static void call_event_handlers(EventTarget *event_target, DOMEvent *event, disp if(listeners != listeners_buf) free(listeners); - if(event->phase != DEP_CAPTURING_PHASE && event_info[event->event_id].dispid - && (vtbl = dispex_get_vtbl(&event_target->dispex)) && vtbl->get_cp_container) + if(event->phase != DEP_CAPTURING_PHASE && event_info[event->event_id].dispid && vtbl && vtbl->get_cp_container) cp_container = vtbl->get_cp_container(&event_target->dispex); if(cp_container) { if(cp_container->cps) { diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index 54cc5b5932a..e23e0c29a97 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -130,6 +130,7 @@ void detach_nsevent(HTMLDocumentNode*,const WCHAR*) DECLSPEC_HIDDEN; /* We extend dispex vtbl for EventTarget functions to avoid separated vtbl. */ typedef struct { dispex_static_data_vtbl_t dispex_vtbl; + IDispatch *(*get_dispatch_this)(DispatchEx*); nsISupports *(*get_gecko_target)(DispatchEx*); void (*bind_event)(DispatchEx*,eventid_t); HRESULT (*dispatch_nsevent_hook)(DispatchEx*,DOMEvent*); diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index f81cb15b30e..45eaa85e15e 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -201,8 +201,16 @@ static HRESULT WINAPI HTMLWindow2_QueryInterface(IHTMLWindow2 *iface, REFIID rii }else if(dispex_query_interface(&This->inner_window->event_target.dispex, riid, ppv)) { assert(!*ppv); return E_NOINTERFACE; + }else if(IsEqualGUID(&IID_IEventTarget, riid)) { + if(!This->inner_window->doc || This->inner_window->doc->document_mode < COMPAT_MODE_IE9) { + *ppv = NULL; + return E_NOINTERFACE; + } + *ppv = &This->IEventTarget_iface; }else { - return EventTarget_QI(&This->inner_window->event_target, riid, ppv); + WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); + *ppv = NULL; + return E_NOINTERFACE; } IUnknown_AddRef((IUnknown*)*ppv); @@ -3710,6 +3718,100 @@ static const IDispatchExVtbl WindowDispExVtbl = { WindowDispEx_GetNameSpaceParent }; +static inline HTMLWindow *impl_from_IEventTarget(IEventTarget *iface) +{ + return CONTAINING_RECORD(iface, HTMLWindow, IEventTarget_iface); +} + +static HRESULT WINAPI WindowEventTarget_QueryInterface(IEventTarget *iface, REFIID riid, void **ppv) +{ + HTMLWindow *This = impl_from_IEventTarget(iface); + + return IHTMLWindow2_QueryInterface(&This->IHTMLWindow2_iface, riid, ppv); +} + +static ULONG WINAPI WindowEventTarget_AddRef(IEventTarget *iface) +{ + HTMLWindow *This = impl_from_IEventTarget(iface); + + return IHTMLWindow2_AddRef(&This->IHTMLWindow2_iface); +} + +static ULONG WINAPI WindowEventTarget_Release(IEventTarget *iface) +{ + HTMLWindow *This = impl_from_IEventTarget(iface); + + return IHTMLWindow2_Release(&This->IHTMLWindow2_iface); +} + +static HRESULT WINAPI WindowEventTarget_GetTypeInfoCount(IEventTarget *iface, UINT *pctinfo) +{ + HTMLWindow *This = impl_from_IEventTarget(iface); + + return IDispatchEx_GetTypeInfoCount(&This->IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI WindowEventTarget_GetTypeInfo(IEventTarget *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLWindow *This = impl_from_IEventTarget(iface); + + return IDispatchEx_GetTypeInfo(&This->IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI WindowEventTarget_GetIDsOfNames(IEventTarget *iface, REFIID riid, LPOLESTR *rgszNames, + UINT cNames, LCID lcid, DISPID *rgDispId) +{ + HTMLWindow *This = impl_from_IEventTarget(iface); + + return IDispatchEx_GetIDsOfNames(&This->IDispatchEx_iface, riid, rgszNames, cNames, lcid, rgDispId); +} + +static HRESULT WINAPI WindowEventTarget_Invoke(IEventTarget *iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLWindow *This = impl_from_IEventTarget(iface); + + return IDispatchEx_Invoke(&This->IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, pDispParams, + pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI WindowEventTarget_addEventListener(IEventTarget *iface, BSTR type, IDispatch *listener, + VARIANT_BOOL capture) +{ + HTMLWindow *This = impl_from_IEventTarget(iface); + + return IEventTarget_addEventListener(&This->inner_window->event_target.IEventTarget_iface, type, listener, capture); +} + +static HRESULT WINAPI WindowEventTarget_removeEventListener(IEventTarget *iface, BSTR type, IDispatch *listener, + VARIANT_BOOL capture) +{ + HTMLWindow *This = impl_from_IEventTarget(iface); + + return IEventTarget_removeEventListener(&This->inner_window->event_target.IEventTarget_iface, type, listener, capture); +} + +static HRESULT WINAPI WindowEventTarget_dispatchEvent(IEventTarget *iface, IDOMEvent *event_iface, VARIANT_BOOL *result) +{ + HTMLWindow *This = impl_from_IEventTarget(iface); + + return IEventTarget_dispatchEvent(&This->inner_window->event_target.IEventTarget_iface, event_iface, result); +} + +static const IEventTargetVtbl EventTargetVtbl = { + WindowEventTarget_QueryInterface, + WindowEventTarget_AddRef, + WindowEventTarget_Release, + WindowEventTarget_GetTypeInfoCount, + WindowEventTarget_GetTypeInfo, + WindowEventTarget_GetIDsOfNames, + WindowEventTarget_Invoke, + WindowEventTarget_addEventListener, + WindowEventTarget_removeEventListener, + WindowEventTarget_dispatchEvent +}; + static inline HTMLWindow *impl_from_IServiceProvider(IServiceProvider *iface) { return CONTAINING_RECORD(iface, HTMLWindow, IServiceProvider_iface); @@ -3896,6 +3998,12 @@ static compat_mode_t HTMLWindow_get_compat_mode(DispatchEx *dispex) return lock_document_mode(This->doc); } +static IDispatch *HTMLWindow_get_dispatch_this(DispatchEx *dispex) +{ + HTMLInnerWindow *This = impl_from_DispatchEx(dispex); + return (IDispatch*)&This->base.outer_window->base.IHTMLWindow2_iface; +} + static nsISupports *HTMLWindow_get_gecko_target(DispatchEx *dispex) { HTMLInnerWindow *This = impl_from_DispatchEx(dispex); @@ -4005,6 +4113,7 @@ static const event_target_vtbl_t HTMLWindow_event_target_vtbl = { HTMLWindow_get_compat_mode, NULL }, + HTMLWindow_get_dispatch_this, HTMLWindow_get_gecko_target, HTMLWindow_bind_event, NULL, @@ -4043,6 +4152,7 @@ static void *alloc_window(size_t size) window->IHTMLWindow7_iface.lpVtbl = &HTMLWindow7Vtbl; window->IHTMLPrivateWindow_iface.lpVtbl = &HTMLPrivateWindowVtbl; window->IDispatchEx_iface.lpVtbl = &WindowDispExVtbl; + window->IEventTarget_iface.lpVtbl = &EventTargetVtbl; window->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl; window->ITravelLogClient_iface.lpVtbl = &TravelLogClientVtbl; window->IObjectIdentity_iface.lpVtbl = &ObjectIdentityVtbl; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index ed7f44420fa..81a0fd3a7ff 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -538,6 +538,7 @@ struct HTMLWindow { IHTMLWindow7 IHTMLWindow7_iface; IHTMLPrivateWindow IHTMLPrivateWindow_iface; IDispatchEx IDispatchEx_iface; + IEventTarget IEventTarget_iface; IServiceProvider IServiceProvider_iface; ITravelLogClient ITravelLogClient_iface; IObjectIdentity IObjectIdentity_iface; diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 0f16f0b554a..6c56f364e30 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -1461,8 +1461,26 @@ EVENT_HANDLER_FUNC_OBJ(onvisibilitychange); static HRESULT WINAPI onbeforeunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { + IEventTarget *event_target; + IHTMLWindow2 *window2; + IDOMEvent *event; + HRESULT hres; + CHECK_EXPECT(onbeforeunload); test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + + hres = IDispatch_QueryInterface(V_DISPATCH(&pdp->rgvarg[1]), &IID_IDOMEvent, (void**)&event); + ok(hres == S_OK, "Could not get IDOMEvent iface: %08lx\n", hres); + hres = IDOMEvent_get_target(event, &event_target); + ok(hres == S_OK, "get_target failed: %08lx\n", hres); + IDOMEvent_Release(event); + + hres = IEventTarget_QueryInterface(event_target, &IID_IHTMLWindow2, (void**)&window2); + ok(hres == S_OK, "Could not get IHTMLWindow2 iface: %08lx\n", hres); + ok(window2 == window, "event_target's window iface != window\n"); + IHTMLWindow2_Release(window2); + + IEventTarget_Release(event_target); return S_OK; } diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index b4269bbe8d1..f26a013fc64 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1358,6 +1358,7 @@ static event_target_vtbl_t HTMLXMLHttpRequest_event_target_vtbl = { { NULL, }, + NULL, HTMLXMLHttpRequest_get_gecko_target, HTMLXMLHttpRequest_bind_event }; From 52b574fad3658e4e47928df3510df6411814303d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:57 +0200 Subject: [PATCH 0829/2777] mshtml: Always return outer window to external callers. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The inner window is an implementation detail and should never be accessed directly by non-mshtml code. Signed-off-by: Gabriel Ivăncescu --- Needed by next patch, because we'll have to move the script. Note that this is more correct as the "proxy" window is likely to be an alias to the outer window or similar thing (i.e. one window that remains even through navigation), and is possible because of the previous patch which fixes the behavior on release, since now the script will hold a ref to the outer window as it should. --- dlls/mshtml/htmlevent.c | 2 +- dlls/mshtml/htmlwindow.c | 15 ++++++++------- dlls/mshtml/script.c | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 3fc7d0bc567..f3cbe49c4f3 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -1320,7 +1320,7 @@ static HRESULT WINAPI DOMUIEvent_get_view(IDOMUIEvent *iface, IHTMLWindow2 **p) mozIDOMWindowProxy_Release(moz_window); } if(view) - IHTMLWindow2_AddRef((*p = &view->base.inner_window->base.IHTMLWindow2_iface)); + IHTMLWindow2_AddRef((*p = &view->base.IHTMLWindow2_iface)); else *p = NULL; return S_OK; diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 45eaa85e15e..cdb0c632da9 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -579,11 +579,12 @@ static HRESULT WINAPI HTMLWindow2_get_length(IHTMLWindow2 *iface, LONG *p) static HRESULT WINAPI HTMLWindow2_get_frames(IHTMLWindow2 *iface, IHTMLFramesCollection2 **p) { HTMLWindow *This = impl_from_IHTMLWindow2(iface); + FIXME("(%p)->(%p): semi-stub\n", This, p); /* FIXME: Should return a separate Window object */ - *p = (IHTMLFramesCollection2*)&This->IHTMLWindow2_iface; - IHTMLWindow2_AddRef(iface); + *p = (IHTMLFramesCollection2*)&This->outer_window->base.IHTMLWindow2_iface; + IHTMLWindow2_AddRef(&This->outer_window->base.IHTMLWindow2_iface); return S_OK; } @@ -1064,8 +1065,8 @@ static HRESULT WINAPI HTMLWindow2_get_self(IHTMLWindow2 *iface, IHTMLWindow2 **p TRACE("(%p)->(%p)\n", This, p); /* FIXME: We should return kind of proxy window here. */ - IHTMLWindow2_AddRef(&This->IHTMLWindow2_iface); - *p = &This->IHTMLWindow2_iface; + *p = &This->outer_window->base.IHTMLWindow2_iface; + IHTMLWindow2_AddRef(*p); return S_OK; } @@ -1090,8 +1091,8 @@ static HRESULT WINAPI HTMLWindow2_get_window(IHTMLWindow2 *iface, IHTMLWindow2 * TRACE("(%p)->(%p)\n", This, p); /* FIXME: We should return kind of proxy window here. */ - IHTMLWindow2_AddRef(&This->IHTMLWindow2_iface); - *p = &This->IHTMLWindow2_iface; + *p = &This->outer_window->base.IHTMLWindow2_iface; + IHTMLWindow2_AddRef(*p); return S_OK; } @@ -3960,7 +3961,7 @@ static HRESULT HTMLWindow_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD return DISP_E_MEMBERNOTFOUND; V_VT(res) = VT_DISPATCH; - V_DISPATCH(res) = (IDispatch*)&frame->base.inner_window->base.IHTMLWindow2_iface; + V_DISPATCH(res) = (IDispatch*)&frame->base.IHTMLWindow2_iface; IDispatch_AddRef(V_DISPATCH(res)); return S_OK; } diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c index f87ebe8aee1..9ed08d69de9 100644 --- a/dlls/mshtml/script.c +++ b/dlls/mshtml/script.c @@ -369,7 +369,7 @@ static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPC return E_FAIL; /* FIXME: Return proxy object */ - *ppiunkItem = (IUnknown*)&This->window->base.IHTMLWindow2_iface; + *ppiunkItem = (IUnknown*)&This->window->base.outer_window->base.IHTMLWindow2_iface; IUnknown_AddRef(*ppiunkItem); return S_OK; From 5a8a434ae13246020c9769bb57a58c89987c6f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:57 +0200 Subject: [PATCH 0830/2777] mshtml: Move the script hosts from the initial empty document. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- Tested in next patch, as we'll need the command target for the script site. --- dlls/mshtml/htmlscript.h | 1 + dlls/mshtml/htmlwindow.c | 5 ++++- dlls/mshtml/script.c | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/htmlscript.h b/dlls/mshtml/htmlscript.h index 5b8b90e57a2..680ad9aa9a7 100644 --- a/dlls/mshtml/htmlscript.h +++ b/dlls/mshtml/htmlscript.h @@ -39,6 +39,7 @@ HRESULT script_elem_from_nsscript(nsIDOMHTMLScriptElement*,HTMLScriptElement**) void bind_event_scripts(HTMLDocumentNode*) DECLSPEC_HIDDEN; HRESULT load_script(HTMLScriptElement*,const WCHAR*,BOOL) DECLSPEC_HIDDEN; +void move_script_hosts(HTMLInnerWindow*,HTMLInnerWindow*) DECLSPEC_HIDDEN; void release_script_hosts(HTMLInnerWindow*) DECLSPEC_HIDDEN; void connect_scripts(HTMLInnerWindow*) DECLSPEC_HIDDEN; void doc_insert_script(HTMLInnerWindow*,HTMLScriptElement*,BOOL) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index cdb0c632da9..65af600c633 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -4351,8 +4351,11 @@ HRESULT update_window_doc(HTMLInnerWindow *window) return S_OK; } - if(outer_window->base.inner_window) + if(outer_window->base.inner_window) { + if(!outer_window->base.inner_window->performance_timing->navigation_start_time) + move_script_hosts(outer_window->base.inner_window, window); detach_inner_window(outer_window->base.inner_window); + } outer_window->base.inner_window = window; outer_window->pending_window = NULL; diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c index 9ed08d69de9..85d185f3251 100644 --- a/dlls/mshtml/script.c +++ b/dlls/mshtml/script.c @@ -1763,6 +1763,22 @@ void update_browser_script_mode(GeckoBrowser *browser, IUri *uri) ERR("JavaScript setup failed: %08lx\n", nsres); } +void move_script_hosts(HTMLInnerWindow *window, HTMLInnerWindow *new_window) +{ + ScriptHost *iter, *iter2; + + if(list_empty(&window->script_hosts)) + return; + + LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &window->script_hosts, ScriptHost, entry) { + iter->window = new_window; + list_remove(&iter->entry); + list_add_tail(&new_window->script_hosts, &iter->entry); + } + + lock_document_mode(new_window->doc); +} + void release_script_hosts(HTMLInnerWindow *window) { script_queue_entry_t *queue_iter; From 980cc8693a12de963726ad0cc8aa6171aa1ed4b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:57 +0200 Subject: [PATCH 0831/2777] mshtml: Implement IActiveScriptSite service. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With IOleCommandTarget stub, since it's the interface used. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlscript.h | 3 + dlls/mshtml/script.c | 78 ++++++++++++ dlls/mshtml/service.c | 16 +++ dlls/mshtml/tests/events.c | 27 +++++ dlls/mshtml/tests/htmldoc.c | 52 ++++++++ dlls/mshtml/tests/script.c | 228 ++++++++++++++++++++++++++++++++++-- 6 files changed, 395 insertions(+), 9 deletions(-) diff --git a/dlls/mshtml/htmlscript.h b/dlls/mshtml/htmlscript.h index 680ad9aa9a7..5f6e8aa8cdc 100644 --- a/dlls/mshtml/htmlscript.h +++ b/dlls/mshtml/htmlscript.h @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "activscp.h" + struct HTMLScriptElement { HTMLElement element; @@ -48,3 +50,4 @@ HRESULT exec_script(HTMLInnerWindow*,const WCHAR*,const WCHAR*,VARIANT*) DECLSPE void update_browser_script_mode(GeckoBrowser*,IUri*) DECLSPEC_HIDDEN; BOOL find_global_prop(HTMLInnerWindow*,BSTR,DWORD,ScriptHost**,DISPID*) DECLSPEC_HIDDEN; IDispatch *get_script_disp(ScriptHost*) DECLSPEC_HIDDEN; +IActiveScriptSite *get_first_script_site(HTMLInnerWindow*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c index 85d185f3251..5ab60ee928e 100644 --- a/dlls/mshtml/script.c +++ b/dlls/mshtml/script.c @@ -74,6 +74,7 @@ struct ScriptHost { IActiveScriptSiteUIControl IActiveScriptSiteUIControl_iface; IActiveScriptSiteDebug IActiveScriptSiteDebug_iface; IServiceProvider IServiceProvider_iface; + IOleCommandTarget IOleCommandTarget_iface; LONG ref; @@ -299,6 +300,9 @@ static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, }else if(IsEqualGUID(&IID_IServiceProvider, riid)) { TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv); *ppv = &This->IServiceProvider_iface; + }else if(IsEqualGUID(&IID_IOleCommandTarget, riid)) { + TRACE("(%p)->(IID_IOleCommandTarget %p)\n", This, ppv); + *ppv = &This->IOleCommandTarget_iface; }else if(IsEqualGUID(&IID_ICanHandleException, riid)) { TRACE("(%p)->(IID_ICanHandleException not supported %p)\n", This, ppv); return E_NOINTERFACE; @@ -666,6 +670,18 @@ static HRESULT WINAPI ASServiceProvider_QueryService(IServiceProvider *iface, RE { ScriptHost *This = impl_from_IServiceProvider(iface); + if(IsEqualGUID(&IID_IActiveScriptSite, guidService)) { + ScriptHost *script_host = This; + + TRACE("(%p)->(IID_IActiveScriptSite)\n", This); + + /* Use first script site if available */ + if(This->window && !list_empty(&This->window->script_hosts)) + script_host = LIST_ENTRY(list_head(&This->window->script_hosts), ScriptHost, entry); + + return IActiveScriptSite_QueryInterface(&script_host->IActiveScriptSite_iface, riid, ppv); + } + if(IsEqualGUID(&SID_SInternetHostSecurityManager, guidService)) { TRACE("(%p)->(SID_SInternetHostSecurityManager)\n", This); @@ -696,6 +712,57 @@ static const IServiceProviderVtbl ASServiceProviderVtbl = { ASServiceProvider_QueryService }; +static inline ScriptHost *impl_from_IOleCommandTarget(IOleCommandTarget *iface) +{ + return CONTAINING_RECORD(iface, ScriptHost, IOleCommandTarget_iface); +} + +static HRESULT WINAPI OleCommandTarget_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv) +{ + ScriptHost *This = impl_from_IOleCommandTarget(iface); + return IActiveScriptSite_QueryInterface(&This->IActiveScriptSite_iface, riid, ppv); +} + +static ULONG WINAPI OleCommandTarget_AddRef(IOleCommandTarget *iface) +{ + ScriptHost *This = impl_from_IOleCommandTarget(iface); + return IActiveScriptSite_AddRef(&This->IActiveScriptSite_iface); +} + +static ULONG WINAPI OleCommandTarget_Release(IOleCommandTarget *iface) +{ + ScriptHost *This = impl_from_IOleCommandTarget(iface); + return IActiveScriptSite_Release(&This->IActiveScriptSite_iface); +} + +static HRESULT WINAPI OleCommandTarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup, + ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText) +{ + ScriptHost *This = impl_from_IOleCommandTarget(iface); + + FIXME("(%p)->(%s %ld %p %p)\n", This, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText); + + return E_NOTIMPL; +} + +static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup, + DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) +{ + ScriptHost *This = impl_from_IOleCommandTarget(iface); + + FIXME("(%p)->(%s %ld %ld %s %p)\n", This, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, wine_dbgstr_variant(pvaIn), pvaOut); + + return E_NOTIMPL; +} + +static const IOleCommandTargetVtbl OleCommandTargetVtbl = { + OleCommandTarget_QueryInterface, + OleCommandTarget_AddRef, + OleCommandTarget_Release, + OleCommandTarget_QueryStatus, + OleCommandTarget_Exec +}; + static ScriptHost *create_script_host(HTMLInnerWindow *window, const GUID *guid) { ScriptHost *ret; @@ -711,6 +778,7 @@ static ScriptHost *create_script_host(HTMLInnerWindow *window, const GUID *guid) ret->IActiveScriptSiteUIControl_iface.lpVtbl = &ActiveScriptSiteUIControlVtbl; ret->IActiveScriptSiteDebug_iface.lpVtbl = &ActiveScriptSiteDebugVtbl; ret->IServiceProvider_iface.lpVtbl = &ASServiceProviderVtbl; + ret->IOleCommandTarget_iface.lpVtbl = &OleCommandTargetVtbl; ret->ref = 1; ret->window = window; ret->script_state = SCRIPTSTATE_UNINITIALIZED; @@ -1460,6 +1528,16 @@ IDispatch *get_script_disp(ScriptHost *script_host) return disp; } +IActiveScriptSite *get_first_script_site(HTMLInnerWindow *window) +{ + if(list_empty(&window->script_hosts)) { + ScriptHost *script_host = create_script_host(window, &CLSID_JScript); + if(!script_host) + return NULL; + } + return &LIST_ENTRY(list_head(&window->script_hosts), ScriptHost, entry)->IActiveScriptSite_iface; +} + static EventTarget *find_event_target(HTMLDocumentNode *doc, HTMLScriptElement *script_elem) { EventTarget *event_target = NULL; diff --git a/dlls/mshtml/service.c b/dlls/mshtml/service.c index 1f440b846e8..f7a4003462c 100644 --- a/dlls/mshtml/service.c +++ b/dlls/mshtml/service.c @@ -29,6 +29,7 @@ #include "wine/debug.h" #include "mshtml_private.h" +#include "htmlscript.h" WINE_DEFAULT_DEBUG_CHANNEL(mshtml); @@ -360,6 +361,21 @@ static HRESULT WINAPI DocNodeServiceProvider_QueryService(IServiceProvider *ifac { HTMLDocumentNode *This = HTMLDocumentNode_from_IServiceProvider(iface); + if(IsEqualGUID(&IID_IActiveScriptSite, guidService)) { + IActiveScriptSite *site; + + TRACE("IID_IActiveScriptSite\n"); + + if(!This->window) { + FIXME("No window\n"); + return E_NOTIMPL; + } + + if(!(site = get_first_script_site(This->window))) + return E_OUTOFMEMORY; + return IActiveScriptSite_QueryInterface(site, riid, ppv); + } + if(IsEqualGUID(&SID_SContainerDispatch, guidService)) { TRACE("SID_SContainerDispatch\n"); return IHTMLDocument2_QueryInterface(&This->IHTMLDocument2_iface, riid, ppv); diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 6c56f364e30..f15080dc87c 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -35,6 +35,8 @@ #include "shdeprecated.h" #include "dispex.h" +extern const IID IID_IActiveScriptSite; + #define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE @@ -3164,11 +3166,14 @@ static void test_doc_obj(IHTMLDocument2 *doc) IHTMLPerformance *perf, *perf2; IOmHistory *history, *history2; IHTMLScreen *screen, *screen2; + IOleCommandTarget *cmdtarget; IEventTarget *event_target; + IUnknown *site, *site2; DISPPARAMS dp = { 0 }; IHTMLWindow7 *window7; IHTMLWindow6 *window6; IHTMLWindow5 *window5; + IServiceProvider *sp; IDispatchEx *dispex; IHTMLElement *body; VARIANT res, arg; @@ -3325,6 +3330,16 @@ static void test_doc_obj(IHTMLDocument2 *doc) IHTMLWindow7_Release(window7); VariantClear(&res); + /* and script sites */ + hres = IHTMLDocument2_QueryInterface(doc_node, &IID_IServiceProvider, (void**)&sp); + ok(hres == S_OK, "Could not get IServiceProvider iface: %08lx\n", hres); + hres = IServiceProvider_QueryService(sp, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&cmdtarget); + ok(hres == S_OK, "QueryService(IID_IActiveScriptSite->IID_IOleCommandTarget) failed: %08lx\n", hres); + hres = IOleCommandTarget_QueryInterface(cmdtarget, &IID_IActiveScriptSite, (void**)&site); + ok(hres == S_OK, "Command Target QI for IActiveScriptSite failed: %08lx\n", hres); + IOleCommandTarget_Release(cmdtarget); + IServiceProvider_Release(sp); + /* Navigate to a different document mode page, checking using the same doc obj. Test that it breaks COM rules, since IEventTarget is conditionally exposed. All the events registered on the old doc node are also removed. @@ -3369,8 +3384,20 @@ static void test_doc_obj(IHTMLDocument2 *doc) hres = IHTMLWindow2_get_document(window, &doc_node2); ok(hres == S_OK, "get_document failed: %08lx\n", hres); ok(doc_node != doc_node2, "doc_node == doc_node2\n"); + + hres = IHTMLDocument2_QueryInterface(doc_node2, &IID_IServiceProvider, (void**)&sp); + ok(hres == S_OK, "Could not get IServiceProvider iface: %08lx\n", hres); + hres = IServiceProvider_QueryService(sp, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&cmdtarget); + ok(hres == S_OK, "QueryService(IID_IActiveScriptSite->IID_IOleCommandTarget) failed: %08lx\n", hres); + hres = IOleCommandTarget_QueryInterface(cmdtarget, &IID_IActiveScriptSite, (void**)&site2); + ok(hres == S_OK, "Command Target QI for IActiveScriptSite failed: %08lx\n", hres); + ok(site != site2, "site == site2\n"); + IOleCommandTarget_Release(cmdtarget); IHTMLDocument2_Release(doc_node2); IHTMLDocument2_Release(doc_node); + IServiceProvider_Release(sp); + IUnknown_Release(site2); + IUnknown_Release(site); hres = IHTMLWindow2_get_location(window, &location2); ok(hres == S_OK, "get_location failed: %08lx\n", hres); diff --git a/dlls/mshtml/tests/htmldoc.c b/dlls/mshtml/tests/htmldoc.c index d723df0ecd8..e22be960210 100644 --- a/dlls/mshtml/tests/htmldoc.c +++ b/dlls/mshtml/tests/htmldoc.c @@ -53,6 +53,7 @@ DEFINE_GUID(IID_IProxyManager,0x00000008,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00, DEFINE_OLEGUID(CGID_DocHostCmdPriv, 0x000214D4L, 0, 0); DEFINE_GUID(SID_SContainerDispatch,0xb722be00,0x4e68,0x101b,0xa2,0xbc,0x00,0xaa,0x00,0x40,0x47,0x70); DEFINE_GUID(outer_test_iid,0xabcabc00,0,0,0,0,0,0,0,0,0,0x66); +extern const IID IID_IActiveScriptSite; #define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE @@ -8527,8 +8528,11 @@ static void test_submit(void) static void test_QueryService(IHTMLDocument2 *doc, BOOL success) { IHTMLWindow2 *window, *sp_window; + IOleCommandTarget *cmdtarget; + IHTMLDocument2 *doc_node; IServiceProvider *sp; IHlinkFrame *hf; + IUnknown *unk; HRESULT hres; hres = IHTMLDocument2_QueryInterface(doc, &IID_IServiceProvider, (void**)&sp); @@ -8545,6 +8549,9 @@ static void test_QueryService(IHTMLDocument2 *doc, BOOL success) ok(hf == &HlinkFrame, "hf != HlinkFrame\n"); IHlinkFrame_Release(hf); + hres = IServiceProvider_QueryService(sp, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&cmdtarget); + ok(hres == E_NOINTERFACE, "QueryService(IID_IActiveScriptSite->IID_IOleCommandTarget) returned: %08lx\n", hres); + IServiceProvider_Release(sp); hres = IHTMLDocument2_get_parentWindow(doc, &window); @@ -8563,8 +8570,28 @@ static void test_QueryService(IHTMLDocument2 *doc, BOOL success) ok(hf == &HlinkFrame, "hf != HlinkFrame\n"); IHlinkFrame_Release(hf); + hres = IServiceProvider_QueryService(sp, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&cmdtarget); + ok(hres == E_NOINTERFACE, "QueryService(IID_IActiveScriptSite->IID_IOleCommandTarget) returned: %08lx\n", hres); + IServiceProvider_Release(sp); + + hres = IHTMLWindow2_get_document(window, &doc_node); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); IHTMLWindow2_Release(window); + + hres = IHTMLDocument2_QueryInterface(doc_node, &IID_IServiceProvider, (void**)&sp); + ok(hres == S_OK, "Could not get IServiceProvider iface: %08lx\n", hres); + IHTMLDocument2_Release(doc_node); + + hres = IServiceProvider_QueryService(sp, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&cmdtarget); + ok(hres == S_OK, "QueryService(IID_IActiveScriptSite->IID_IOleCommandTarget) failed: %08lx\n", hres); + ok(cmdtarget != NULL, "cmdtarget == NULL\n"); + hres = IOleCommandTarget_QueryInterface(cmdtarget, &IID_IActiveScriptSite, (void**)&unk); + ok(hres == S_OK, "Command Target QI for IActiveScriptSite failed: %08lx\n", hres); + IUnknown_Release(unk); + + IOleCommandTarget_Release(cmdtarget); + IServiceProvider_Release(sp); } static void test_HTMLDocument_StreamLoad(void) @@ -9078,8 +9105,10 @@ static BOOL check_ie(void) static void test_ServiceProvider(void) { IHTMLDocument3 *doc3, *doc3_2; + IOleCommandTarget *cmdtarget; IServiceProvider *provider; IHTMLDocument2 *doc, *doc2; + IHTMLWindow2 *window; IUnknown *unk; HRESULT hres; @@ -9115,6 +9144,29 @@ static void test_ServiceProvider(void) ok(hres == S_OK, "QueryService(HTMLEditServices) failed: %08lx\n", hres); IUnknown_Release(unk); + hres = IServiceProvider_QueryService(provider, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&cmdtarget); + ok(hres == E_NOINTERFACE, "QueryService(IID_IActiveScriptSite->IID_IOleCommandTarget) returned: %08lx\n", hres); + IServiceProvider_Release(provider); + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_document(window, &doc2); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + IHTMLWindow2_Release(window); + + hres = IHTMLDocument2_QueryInterface(doc2, &IID_IServiceProvider, (void**)&provider); + ok(hres == S_OK, "Could not get IServiceProvider iface: %08lx\n", hres); + IHTMLDocument2_Release(doc2); + + hres = IServiceProvider_QueryService(provider, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&cmdtarget); + ok(hres == S_OK, "QueryService(IID_IActiveScriptSite->IID_IOleCommandTarget) failed: %08lx\n", hres); + ok(cmdtarget != NULL, "cmdtarget == NULL\n"); + hres = IOleCommandTarget_QueryInterface(cmdtarget, &IID_IActiveScriptSite, (void**)&unk); + ok(hres == S_OK, "Command Target QI for IActiveScriptSite failed: %08lx\n", hres); + IUnknown_Release(unk); + + IOleCommandTarget_Release(cmdtarget); IServiceProvider_Release(provider); release_document(doc); } diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index b3b78070f50..f36d00bb407 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -130,6 +130,7 @@ DEFINE_EXPECT(AddNamedItem); DEFINE_EXPECT(AddNamedItem2); DEFINE_EXPECT(ParseScriptText_script); DEFINE_EXPECT(ParseScriptText_script2); +DEFINE_EXPECT(ParseScriptText_script_with_prescript_site); DEFINE_EXPECT(ParseScriptText_execScript); DEFINE_EXPECT(GetScriptDispatch); DEFINE_EXPECT(funcDisp); @@ -183,6 +184,7 @@ static BOOL is_ie9plus, is_english; static IHTMLDocument2 *notif_doc; static IOleDocumentView *view; static IDispatchEx *window_dispex; +static IHTMLDocument2 *doc_obj; static BOOL doc_complete; static IDispatch *script_disp; static BOOL ax_objsafe; @@ -1678,7 +1680,8 @@ static IHTMLDocument2 *create_document(void) todo_wine #endif ok(hres == S_OK, "CoCreateInstance failed: %08lx\n", hres); - return SUCCEEDED(hres) ? doc : NULL; + doc_obj = SUCCEEDED(hres) ? doc : NULL; + return doc_obj; } static void load_string(IHTMLDocument2 *doc, const char *str) @@ -2813,10 +2816,34 @@ static void test_ui(void) static void test_sp(void) { - IServiceProvider *sp; + IServiceProvider *sp, *doc_sp, *doc_obj_sp, *window_sp; + IOleCommandTarget *cmdtarget; + IHTMLWindow2 *window; + IHTMLDocument2 *doc; IUnknown *unk; HRESULT hres; + hres = IDispatchEx_QueryInterface(window_dispex, &IID_IHTMLWindow2, (void**)&window); + ok(hres == S_OK, "QueryInterface(IHTMLWindow2) failed: %08lx\n", hres); + ok(window != NULL, "window is NULL\n"); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IServiceProvider, (void**)&window_sp); + ok(hres == S_OK, "Could not get IServiceProvider iface: %08lx\n", hres); + ok(window_sp != NULL, "window service provider is NULL\n"); + + hres = IHTMLWindow2_get_document(window, &doc); + ok(hres == S_OK, "QueryInterface(IHTMLDocument2) failed: %08lx\n", hres); + ok(doc != NULL, "doc is NULL\n"); + ok(doc != doc_obj, "doc node == doc obj\n"); + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IServiceProvider, (void**)&doc_sp); + ok(hres == S_OK, "Could not get IServiceProvider iface: %08lx\n", hres); + ok(doc_sp != NULL, "doc service provider is NULL\n"); + IHTMLDocument2_Release(doc); + hres = IHTMLDocument2_QueryInterface(doc_obj, &IID_IServiceProvider, (void**)&doc_obj_sp); + ok(hres == S_OK, "Could not get IServiceProvider iface: %08lx\n", hres); + ok(doc_obj_sp != NULL, "doc_obj service provider is NULL\n"); + hres = IActiveScriptSite_QueryInterface(site, &IID_IServiceProvider, (void**)&sp); ok(hres == S_OK, "Could not get IServiceProvider iface: %08lx\n", hres); @@ -2824,7 +2851,60 @@ static void test_sp(void) ok(hres == S_OK, "Could not get SID_SContainerDispatch service: %08lx\n", hres); IUnknown_Release(unk); + hres = IServiceProvider_QueryService(sp, &SID_GetCaller, &IID_IServiceProvider, (void**)&unk); + ok(hres == E_NOINTERFACE, "QueryService(SID_GetCaller) returned: %08lx\n", hres); + hres = IServiceProvider_QueryService(doc_sp, &SID_GetCaller, &IID_IServiceProvider, (void**)&unk); + ok(hres == E_NOINTERFACE, "QueryService(SID_GetCaller) returned: %08lx\n", hres); + hres = IServiceProvider_QueryService(doc_obj_sp, &SID_GetCaller, &IID_IServiceProvider, (void**)&unk); + ok(hres == E_NOINTERFACE, "QueryService(SID_GetCaller) returned: %08lx\n", hres); + hres = IServiceProvider_QueryService(window_sp, &SID_GetCaller, &IID_IServiceProvider, (void**)&unk); + ok(hres == E_NOINTERFACE, "QueryService(SID_GetCaller) returned: %08lx\n", hres); + + hres = IServiceProvider_QueryService(sp, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&cmdtarget); + ok(hres == S_OK, "QueryService(IActiveScriptSite->IOleCommandTarget) failed: %08lx\n", hres); + ok(cmdtarget != NULL, "IOleCommandTarget is NULL\n"); + + hres = IActiveScriptSite_QueryInterface(site, &IID_IOleCommandTarget, (void**)&unk); + ok(hres == S_OK, "QueryInterface(IOleCommandTarget) failed: %08lx\n", hres); + ok(unk != NULL, "QueryInterface(IOleCommandTarget) is NULL\n"); + ok(cmdtarget == (IOleCommandTarget*)unk, "cmdtarget from QS not same as from QI\n"); + IUnknown_Release(unk); + hres = IServiceProvider_QueryService(doc_sp, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&unk); + ok(hres == S_OK, "QueryService(IActiveScriptSite->IOleCommandTarget) failed: %08lx\n", hres); + ok(cmdtarget == (IOleCommandTarget*)unk, "IActiveScriptSite service from document provider not same as site's\n"); + IUnknown_Release(unk); + hres = IServiceProvider_QueryService(doc_obj_sp, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&unk); + ok(hres == E_NOINTERFACE, "QueryService(IActiveScriptSite->IOleCommandTarget) returned: %08lx\n", hres); + hres = IServiceProvider_QueryService(window_sp, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&unk); + ok(hres == E_NOINTERFACE, "QueryService(IActiveScriptSite->IOleCommandTarget) returned: %08lx\n", hres); + + if(site2) { + IOleCommandTarget *cmdtarget2; + IServiceProvider *sp2; + + hres = IActiveScriptSite_QueryInterface(site2, &IID_IServiceProvider, (void**)&sp2); + ok(hres == S_OK, "Could not get IServiceProvider iface: %08lx\n", hres); + + hres = IServiceProvider_QueryService(sp2, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&cmdtarget2); + ok(hres == S_OK, "QueryService(IActiveScriptSite->IOleCommandTarget) failed: %08lx\n", hres); + ok(cmdtarget2 != NULL, "IOleCommandTarget is NULL\n"); + + hres = IActiveScriptSite_QueryInterface(site2, &IID_IOleCommandTarget, (void**)&unk); + ok(hres == S_OK, "QueryInterface(IOleCommandTarget) failed: %08lx\n", hres); + ok(unk != NULL, "QueryInterface(IOleCommandTarget) is NULL\n"); + ok(cmdtarget2 != (IOleCommandTarget*)unk, "cmdtarget from site2's QS same as from QI\n"); + ok(cmdtarget2 == cmdtarget, "site1's cmdtarget not same as site2's\n"); + IOleCommandTarget_Release(cmdtarget2); + IServiceProvider_Release(sp2); + IUnknown_Release(unk); + } + + IOleCommandTarget_Release(cmdtarget); + IServiceProvider_Release(window_sp); + IServiceProvider_Release(doc_obj_sp); + IServiceProvider_Release(doc_sp); IServiceProvider_Release(sp); + IHTMLWindow2_Release(window); } static void test_script_run(void) @@ -3085,6 +3165,12 @@ static HRESULT WINAPI ActiveScriptParse_ParseScriptText(IActiveScriptParse *ifac test_script_run(); return S_OK; + }else if(!lstrcmpW(pstrCode, L"with pre-script site")) { + CHECK_EXPECT(ParseScriptText_script_with_prescript_site); + ok(!lstrcmpW(pstrItemName, L"window"), "pstrItemName = %s\n", wine_dbgstr_w(pstrItemName)); + ok(!lstrcmpW(pstrDelimiter, L""), "pstrDelimiter = %s\n", wine_dbgstr_w(pstrDelimiter)); + ok(dwFlags == (SCRIPTTEXT_ISVISIBLE|SCRIPTTEXT_HOSTMANAGESSOURCE), "dwFlags = %lx\n", dwFlags); + return S_OK; } ok(0, "unexpected script %s\n", wine_dbgstr_w(pstrCode)); @@ -3160,6 +3246,8 @@ static HRESULT WINAPI ActiveScript_SetScriptSite(IActiveScript *iface, IActiveSc CHECK_EXPECT(SetScriptSite); ok(pass != NULL, "pass == NULL\n"); + if(site2) + ok(pass != site2, "pass == pre-script site\n"); hres = IActiveScriptSite_QueryInterface(pass, &IID_IActiveScriptSiteInterruptPoll, (void**)&poll); ok(hres == S_OK, "Could not get IActiveScriptSiteInterruptPoll interface: %08lx\n", hres); @@ -3453,6 +3541,7 @@ static HRESULT WINAPI ActiveScriptParse2_ParseScriptText(IActiveScriptParse *ifa ok(!lstrcmpW(pstrItemName, L"window"), "pstrItemName = %s\n", wine_dbgstr_w(pstrItemName)); ok(!lstrcmpW(pstrDelimiter, L""), "pstrDelimiter = %s\n", wine_dbgstr_w(pstrDelimiter)); ok(dwFlags == (SCRIPTTEXT_ISVISIBLE | SCRIPTTEXT_HOSTMANAGESSOURCE), "dwFlags = %08lx\n", dwFlags); + test_sp(); return S_OK; } @@ -4190,6 +4279,12 @@ static const char simple_script_str[] = "" ""; +static const char simple_script_with_prescript_site_str[] = + "" + "" + "" + ""; + static void test_exec_script(IHTMLDocument2 *doc, const WCHAR *codew, const WCHAR *langw) { IHTMLWindow2 *window; @@ -4224,10 +4319,16 @@ static void test_exec_script(IHTMLDocument2 *doc, const WCHAR *codew, const WCHA static void test_simple_script(void) { + IOleCommandTarget *cmdtarget; IHTMLDocument2 *doc_node; + IServiceProvider *sp; IHTMLWindow2 *window; + IHTMLDocument6 *doc6; IHTMLDocument2 *doc; + DISPID dispid; HRESULT hres; + VARIANT v; + BSTR bstr; doc = create_document(); if(!doc) @@ -4284,13 +4385,6 @@ static void test_simple_script(void) test_exec_script(doc, L"execScript call", L"TestScript1"); - if(site) - IActiveScriptSite_Release(site); - if(site2) - IActiveScriptSite_Release(site2); - if(window_dispex) - IDispatchEx_Release(window_dispex); - hres = IHTMLDocument2_get_parentWindow(doc, &window); ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); @@ -4307,6 +4401,16 @@ static void test_simple_script(void) CHECK_CALLED(Close); CHECK_CALLED(Close2); + if(site) + IActiveScriptSite_Release(site); + if(site2) + IActiveScriptSite_Release(site2); + if(window_dispex) + IDispatchEx_Release(window_dispex); + site = NULL; + site2 = NULL; + window_dispex = NULL; + hres = IHTMLWindow2_get_document(window, &doc); ok(hres == S_OK, "get_document failed: %08lx\n", hres); ok(doc != doc_node, "doc == doc_node\n"); @@ -4314,6 +4418,112 @@ static void test_simple_script(void) IHTMLDocument2_Release(doc_node); IHTMLDocument2_Release(doc); IHTMLWindow2_Release(window); + + /* Obtaining the IActiveScriptSite before any script engines creates a site with JScript engine, + and is preserved after document gets loaded, and even keeps it from changing its compat mode. */ + doc = create_document(); + if(!doc) + return; + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_document(window, &doc_node); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + IHTMLWindow2_Release(window); + + hres = IHTMLDocument2_QueryInterface(doc_node, &IID_IServiceProvider, (void**)&sp); + ok(hres == S_OK, "Could not get IServiceProvider iface: %08lx\n", hres); + IHTMLDocument2_Release(doc_node); + + hres = IServiceProvider_QueryService(sp, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&cmdtarget); + ok(hres == S_OK, "QueryService(IID_IActiveScriptSite->IID_IOleCommandTarget) failed: %08lx\n", hres); + ok(cmdtarget != NULL, "cmdtarget == NULL\n"); + + hres = IOleCommandTarget_QueryInterface(cmdtarget, &IID_IActiveScriptSite, (void**)&site2); + ok(hres == S_OK, "Command Target QI for IActiveScriptSite failed: %08lx\n", hres); + ok(site2 != NULL, "IActiveScriptSite is NULL\n"); + IOleCommandTarget_Release(cmdtarget); + IServiceProvider_Release(sp); + + SET_EXPECT(CreateInstance); + SET_EXPECT(GetInterfaceSafetyOptions); + SET_EXPECT(SetInterfaceSafetyOptions); + SET_EXPECT(SetProperty_INVOKEVERSIONING); /* IE8 */ + SET_EXPECT(SetProperty_HACK_TRIDENTEVENTSINK); + SET_EXPECT(InitNew); + SET_EXPECT(SetScriptSite); + SET_EXPECT(GetScriptState); + SET_EXPECT(SetScriptState_STARTED); + SET_EXPECT(AddNamedItem); + SET_EXPECT(SetProperty_ABBREVIATE_GLOBALNAME_RESOLUTION_FALSE); /* IE8 */ + SET_EXPECT(ParseScriptText_script_with_prescript_site); + SET_EXPECT(SetScriptState_CONNECTED); + + load_doc(doc, simple_script_with_prescript_site_str); + + CHECK_CALLED(CreateInstance); + CHECK_CALLED(GetInterfaceSafetyOptions); + CHECK_CALLED(SetInterfaceSafetyOptions); + CHECK_CALLED_BROKEN(SetProperty_INVOKEVERSIONING); /* IE8 */ + CHECK_CALLED(SetProperty_HACK_TRIDENTEVENTSINK); + CHECK_CALLED(InitNew); + CHECK_CALLED(SetScriptSite); + CHECK_CALLED(GetScriptState); + CHECK_CALLED(SetScriptState_STARTED); + CHECK_CALLED(AddNamedItem); + CHECK_CALLED_BROKEN(SetProperty_ABBREVIATE_GLOBALNAME_RESOLUTION_FALSE); /* IE8 */ + CHECK_CALLED(ParseScriptText_script_with_prescript_site); + CHECK_CALLED(SetScriptState_CONNECTED); + + if(site) + IActiveScriptSite_Release(site); + + bstr = SysAllocString(L"fail_prop"); + hres = IHTMLDocument2_GetIDsOfNames(doc, &IID_NULL, &bstr, 1, 0, &dispid); + ok(hres == DISP_E_UNKNOWNNAME, "GetIDsOfNames(fail_prop) returned: %08lx\n", hres); + SysFreeString(bstr); + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + + hres = IHTMLWindow2_get_document(window, &doc_node); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + IHTMLWindow2_Release(window); + + hres = IHTMLDocument2_QueryInterface(doc_node, &IID_IHTMLDocument6, (void**)&doc6); + ok(hres == S_OK, "Could not get IHTMLDocument6 iface: %08lx\n", hres); + hres = IHTMLDocument6_get_documentMode(doc6, &v); + ok(V_VT(&v) == VT_R4, "V_VT(documentMode) = %d\n", V_VT(&v)); + ok(V_R4(&v) == 5.0, "V_R4(documentMode) = %f\n", V_R4(&v)); + IHTMLDocument6_Release(doc6); + + hres = IHTMLDocument2_QueryInterface(doc_node, &IID_IServiceProvider, (void**)&sp); + ok(hres == S_OK, "Could not get IServiceProvider iface: %08lx\n", hres); + IHTMLDocument2_Release(doc_node); + + hres = IServiceProvider_QueryService(sp, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&cmdtarget); + ok(hres == S_OK, "QueryService(IID_IActiveScriptSite->IID_IOleCommandTarget) failed: %08lx\n", hres); + ok(cmdtarget != NULL, "cmdtarget == NULL\n"); + + hres = IOleCommandTarget_QueryInterface(cmdtarget, &IID_IActiveScriptSite, (void**)&site); + ok(hres == S_OK, "Command Target QI for IActiveScriptSite failed: %08lx\n", hres); + ok(site == site2, "site != site2\n"); + IOleCommandTarget_Release(cmdtarget); + IServiceProvider_Release(sp); + + SET_EXPECT(SetScriptState_DISCONNECTED); + SET_EXPECT(Close); + + IHTMLDocument2_Release(doc); + + CHECK_CALLED(SetScriptState_DISCONNECTED); + CHECK_CALLED(Close); + + IActiveScriptSite_Release(site2); + IActiveScriptSite_Release(site); + if(window_dispex) + IDispatchEx_Release(window_dispex); } static void run_from_moniker(IMoniker *mon) From 14709e75343c453d65810a02efc68d2f8dd614ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:57 +0200 Subject: [PATCH 0832/2777] mshtml: Implement Exec for CGID_ScriptSite's CMDID_SCRIPTSITE_SECURITY_WINDOW. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/script.c | 29 +++++++++++++++++++++++++++-- dlls/mshtml/tests/script.c | 16 +++++++++++++++- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c index 5ab60ee928e..98525dbb978 100644 --- a/dlls/mshtml/script.c +++ b/dlls/mshtml/script.c @@ -750,9 +750,34 @@ static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID { ScriptHost *This = impl_from_IOleCommandTarget(iface); - FIXME("(%p)->(%s %ld %ld %s %p)\n", This, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, wine_dbgstr_variant(pvaIn), pvaOut); + TRACE("(%p)->(%s %ld %ld %s %p)\n", This, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, wine_dbgstr_variant(pvaIn), pvaOut); - return E_NOTIMPL; + if(!pguidCmdGroup) { + FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup)); + return OLECMDERR_E_UNKNOWNGROUP; + } + + if(IsEqualGUID(&CGID_ScriptSite, pguidCmdGroup)) { + switch(nCmdID) { + case CMDID_SCRIPTSITE_SECURITY_WINDOW: + if(!This->window) { + FIXME("No window\n"); + return E_FAIL; + } + V_VT(pvaOut) = VT_DISPATCH; + V_DISPATCH(pvaOut) = (IDispatch*)&This->window->base.outer_window->base.IHTMLWindow2_iface; + IDispatch_AddRef(V_DISPATCH(pvaOut)); + break; + + default: + FIXME("Unsupported nCmdID %ld of CGID_ScriptSite group\n", nCmdID); + return OLECMDERR_E_NOTSUPPORTED; + } + return S_OK; + } + + FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup)); + return OLECMDERR_E_UNKNOWNGROUP; } static const IOleCommandTargetVtbl OleCommandTargetVtbl = { diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index f36d00bb407..42c599e90d3 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -2817,11 +2817,12 @@ static void test_ui(void) static void test_sp(void) { IServiceProvider *sp, *doc_sp, *doc_obj_sp, *window_sp; + IHTMLWindow2 *window, *cmdtarget_window; IOleCommandTarget *cmdtarget; - IHTMLWindow2 *window; IHTMLDocument2 *doc; IUnknown *unk; HRESULT hres; + VARIANT var; hres = IDispatchEx_QueryInterface(window_dispex, &IID_IHTMLWindow2, (void**)&window); ok(hres == S_OK, "QueryInterface(IHTMLWindow2) failed: %08lx\n", hres); @@ -2899,6 +2900,19 @@ static void test_sp(void) IUnknown_Release(unk); } + V_VT(&var) = VT_EMPTY; + hres = IOleCommandTarget_Exec(cmdtarget, &CGID_ScriptSite, CMDID_SCRIPTSITE_SECURITY_WINDOW, 0, NULL, &var); + ok(hres == S_OK, "Exec failed: %08lx\n", hres); + ok(V_VT(&var) == VT_DISPATCH, "V_VT(CMDID_SCRIPTSITE_SECURITY_WINDOW) = %d\n", V_VT(&var)); + ok(V_DISPATCH(&var) != NULL, "V_DISPATCH(CMDID_SCRIPTSITE_SECURITY_WINDOW) = NULL\n"); + + hres = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IHTMLWindow2, (void**)&cmdtarget_window); + ok(hres == S_OK, "QueryInterface(IHTMLWindow2) failed: %08lx\n", hres); + ok(cmdtarget_window != NULL, "cmdtarget_window is NULL\n"); + ok(window == cmdtarget_window, "window != cmdtarget_window\n"); + IHTMLWindow2_Release(cmdtarget_window); + VariantClear(&var); + IOleCommandTarget_Release(cmdtarget); IServiceProvider_Release(window_sp); IServiceProvider_Release(doc_obj_sp); From bb1f99d3b8964d1aa01dd49fb8ba49eb77d373d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:57 +0200 Subject: [PATCH 0833/2777] vbscript: Implement IActiveScriptSite service. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/vbscript/tests/caller.c | 11 +++++++++++ dlls/vbscript/vbscript.c | 9 +++++++++ dlls/vbscript/vbscript.h | 1 + 3 files changed, 21 insertions(+) diff --git a/dlls/vbscript/tests/caller.c b/dlls/vbscript/tests/caller.c index d5c723e50cf..89311945257 100644 --- a/dlls/vbscript/tests/caller.c +++ b/dlls/vbscript/tests/caller.c @@ -74,6 +74,7 @@ extern const CLSID CLSID_VBScript; expect_ ## func = called_ ## func = FALSE DEFINE_EXPECT(sp_caller_QI_NULL); +DEFINE_EXPECT(site_QI_NULL); DEFINE_EXPECT(testGetCaller); DEFINE_EXPECT(testGetCaller_no_args); DEFINE_EXPECT(testGetCaller_two_args); @@ -290,6 +291,8 @@ static HRESULT WINAPI Test_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WO if(test_get_caller_sp) CHECK_CALLED(sp_caller_QI_NULL); }else if(pdp->cArgs == 1) { + IUnknown *unk; + CHECK_EXPECT(testGetCaller); ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs); ok(V_VT(pdp->rgvarg) == VT_I2, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg)); @@ -298,6 +301,12 @@ static HRESULT WINAPI Test_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WO hres = IServiceProvider_QueryService(pspCaller, &SID_GetCaller, &IID_IServiceProvider, (void**)&caller); ok(hres == E_NOINTERFACE, "QueryService(SID_GetCaller) returned: %08lx\n", hres); ok(caller == NULL, "caller != NULL\n"); + + SET_EXPECT(site_QI_NULL); + hres = IServiceProvider_QueryService(pspCaller, &IID_IActiveScriptSite, &IID_NULL, (void**)&unk); + ok(hres == E_NOINTERFACE, "QueryService(IActiveScriptSite->NULL) returned: %08lx\n", hres); + ok(!unk, "unk != NULL\n"); + CHECK_CALLED(site_QI_NULL); }else { CHECK_EXPECT(testGetCaller_two_args); ok(pdp->cArgs == 2, "cArgs = %d\n", pdp->cArgs); @@ -347,6 +356,8 @@ static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, }else if(IsEqualGUID(&IID_IActiveScriptSite, riid)) { *ppv = iface; }else { + if(IsEqualGUID(&IID_NULL, riid)) + CHECK_EXPECT(site_QI_NULL); *ppv = NULL; return E_NOINTERFACE; } diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c index 39a5e3b1648..84a8e0bb97f 100644 --- a/dlls/vbscript/vbscript.c +++ b/dlls/vbscript/vbscript.c @@ -421,6 +421,14 @@ static HRESULT WINAPI vbcaller_QueryService(IServiceProvider *iface, REFGUID gui { struct vbcaller *This = vbcaller_from_IServiceProvider(iface); + if(IsEqualGUID(guidService, &IID_IActiveScriptSite)) { + TRACE("(%p)->(IID_IActiveScriptSite)\n", This); + if(This->ctx->site) + return IActiveScriptSite_QueryInterface(This->ctx->site, riid, ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + if(IsEqualGUID(guidService, &SID_GetCaller)) { TRACE("(%p)->(SID_GetCaller)\n", This); *ppv = NULL; @@ -1224,6 +1232,7 @@ HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pU return E_OUTOFMEMORY; } + vbcaller->ctx = ctx; ctx->vbcaller = vbcaller; ctx->safeopt = INTERFACE_USES_DISPEX; list_init(&ctx->objects); diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 5b0a2222767..ab8f2d82bee 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -187,6 +187,7 @@ struct vbcaller { LONG ref; + script_ctx_t *ctx; IServiceProvider *caller; }; From 4b96b5a5bb5153870686bee3913bd17bd774385a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:57 +0200 Subject: [PATCH 0834/2777] jscript: Implement IActiveScriptSite service. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/jsutils.c | 8 ++++++++ dlls/jscript/tests/caller.c | 10 ++++++++++ dlls/mshtml/tests/script.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/dlls/jscript/jsutils.c b/dlls/jscript/jsutils.c index a26b63833ee..9309b457a59 100644 --- a/dlls/jscript/jsutils.c +++ b/dlls/jscript/jsutils.c @@ -1034,6 +1034,14 @@ static HRESULT WINAPI JSCaller_QueryService(IServiceProvider *iface, REFGUID gui { JSCaller *This = impl_from_IServiceProvider(iface); + if(IsEqualGUID(guidService, &IID_IActiveScriptSite)) { + TRACE("(%p)->(IID_IActiveScriptSite)\n", This); + if(This->ctx && This->ctx->site) + return IActiveScriptSite_QueryInterface(This->ctx->site, riid, ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + if(IsEqualGUID(guidService, &SID_GetCaller)) { TRACE("(%p)->(SID_GetCaller)\n", This); *ppv = NULL; diff --git a/dlls/jscript/tests/caller.c b/dlls/jscript/tests/caller.c index a70ab5bae1e..154342df345 100644 --- a/dlls/jscript/tests/caller.c +++ b/dlls/jscript/tests/caller.c @@ -75,6 +75,7 @@ static const CLSID CLSID_JScript = expect_ ## func = called_ ## func = FALSE DEFINE_EXPECT(sp_caller_QI_NULL); +DEFINE_EXPECT(site_QI_NULL); DEFINE_EXPECT(testArgConv); DEFINE_EXPECT(testGetCaller); DEFINE_EXPECT(testGetCaller_no_args); @@ -251,6 +252,7 @@ static void test_change_types(IVariantChangeType *change_type, IDispatch *obj_di static void test_caller(IServiceProvider *caller, IDispatch *arg_obj) { IVariantChangeType *change_type; + IUnknown *unk; HRESULT hres; hres = IServiceProvider_QueryService(caller, &SID_VariantConversion, &IID_IVariantChangeType, (void**)&change_type); @@ -260,6 +262,12 @@ static void test_caller(IServiceProvider *caller, IDispatch *arg_obj) test_change_types(change_type, arg_obj); IVariantChangeType_Release(change_type); + + SET_EXPECT(site_QI_NULL); + hres = IServiceProvider_QueryService(caller, &IID_IActiveScriptSite, &IID_NULL, (void**)&unk); + ok(hres == E_NOINTERFACE, "Querying for IActiveScriptSite->NULL returned: %08lx\n", hres); + ok(!unk, "unk != NULL\n"); + CHECK_CALLED(site_QI_NULL); } static IServiceProvider sp_caller_obj; @@ -540,6 +548,8 @@ static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, }else if(IsEqualGUID(&IID_IActiveScriptSite, riid)) { *ppv = iface; }else { + if(IsEqualGUID(&IID_NULL, riid)) + CHECK_EXPECT(site_QI_NULL); *ppv = NULL; return E_NOINTERFACE; } diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index 42c599e90d3..d6bf258607b 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -296,6 +296,36 @@ static BSTR get_mime_type_display_name(const WCHAR *content_type) return SysAllocString(L"File"); } +static void test_sp_caller(IServiceProvider *sp) +{ + IOleCommandTarget *cmdtarget; + IServiceProvider *caller; + IHTMLWindow2 *window; + HRESULT hres; + VARIANT var; + + hres = IServiceProvider_QueryService(sp, &SID_GetCaller, &IID_IServiceProvider, (void**)&caller); + ok(hres == S_OK, "QueryService(SID_GetCaller) returned: %08lx\n", hres); + ok(!caller, "caller != NULL\n"); + + hres = IServiceProvider_QueryService(sp, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&cmdtarget); + ok(hres == S_OK, "QueryService(IActiveScriptSite->IOleCommandTarget) failed: %08lx\n", hres); + ok(cmdtarget != NULL, "IOleCommandTarget is NULL\n"); + + V_VT(&var) = VT_EMPTY; + hres = IOleCommandTarget_Exec(cmdtarget, &CGID_ScriptSite, CMDID_SCRIPTSITE_SECURITY_WINDOW, 0, NULL, &var); + ok(hres == S_OK, "Exec failed: %08lx\n", hres); + ok(V_VT(&var) == VT_DISPATCH, "V_VT(CMDID_SCRIPTSITE_SECURITY_WINDOW) = %d\n", V_VT(&var)); + ok(V_DISPATCH(&var) != NULL, "V_DISPATCH(CMDID_SCRIPTSITE_SECURITY_WINDOW) = NULL\n"); + IOleCommandTarget_Release(cmdtarget); + + hres = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IHTMLWindow2, (void**)&window); + ok(hres == S_OK, "QueryInterface(IHTMLWindow2) failed: %08lx\n", hres); + ok(window != NULL, "window is NULL\n"); + IHTMLWindow2_Release(window); + VariantClear(&var); +} + static void test_script_vars(unsigned argc, VARIANTARG *argv) { static const WCHAR *const jsobj_names[] = { L"abc", L"foO", L"bar", L"TostRing", L"hasownpropERty" }; @@ -963,6 +993,7 @@ static HRESULT WINAPI externalDisp_InvokeEx(IDispatchEx *iface, DISPID id, LCID ok(!pvarRes, "pvarRes != NULL\n"); ok(pei != NULL, "pei == NULL\n"); + test_sp_caller(pspCaller); return S_OK; case DISPID_EXTERNAL_TODO_WINE_OK: From 8c5e34be131e00e65ac0138fd500c0dffbc61234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:57 +0200 Subject: [PATCH 0835/2777] mshtml: Expose the other IHTMLEventObj* props. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlevent.c | 1112 +++++++++++++++++++++++++++++++++ dlls/mshtml/mshtml_private.h | 5 + dlls/mshtml/tests/events.c | 58 +- dlls/mshtml/tests/events.html | 17 + 4 files changed, 1184 insertions(+), 8 deletions(-) diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index f3cbe49c4f3..cf192b94026 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -349,6 +349,11 @@ static DOMUIEvent *DOMUIEvent_from_DOMEvent(DOMEvent *event) typedef struct { DispatchEx dispex; IHTMLEventObj IHTMLEventObj_iface; + IHTMLEventObj2 IHTMLEventObj2_iface; + IHTMLEventObj3 IHTMLEventObj3_iface; + IHTMLEventObj4 IHTMLEventObj4_iface; + IHTMLEventObj5 IHTMLEventObj5_iface; + IHTMLEventObj6 IHTMLEventObj6_iface; LONG ref; @@ -371,6 +376,16 @@ static HRESULT WINAPI HTMLEventObj_QueryInterface(IHTMLEventObj *iface, REFIID r *ppv = &This->IHTMLEventObj_iface; }else if(IsEqualGUID(&IID_IHTMLEventObj, riid)) { *ppv = &This->IHTMLEventObj_iface; + }else if(IsEqualGUID(&IID_IHTMLEventObj2, riid)) { + *ppv = &This->IHTMLEventObj2_iface; + }else if(IsEqualGUID(&IID_IHTMLEventObj3, riid)) { + *ppv = &This->IHTMLEventObj3_iface; + }else if(IsEqualGUID(&IID_IHTMLEventObj4, riid)) { + *ppv = &This->IHTMLEventObj4_iface; + }else if(IsEqualGUID(&IID_IHTMLEventObj5, riid)) { + *ppv = &This->IHTMLEventObj5_iface; + }else if(IsEqualGUID(&IID_IHTMLEventObj6, riid)) { + *ppv = &This->IHTMLEventObj6_iface; }else if(dispex_query_interface(&This->dispex, riid, ppv)) { return *ppv ? S_OK : E_NOINTERFACE; }else { @@ -887,8 +902,1100 @@ static inline HTMLEventObj *unsafe_impl_from_IHTMLEventObj(IHTMLEventObj *iface) return iface->lpVtbl == &HTMLEventObjVtbl ? impl_from_IHTMLEventObj(iface) : NULL; } +static inline HTMLEventObj *impl_from_IHTMLEventObj2(IHTMLEventObj2 *iface) +{ + return CONTAINING_RECORD(iface, HTMLEventObj, IHTMLEventObj2_iface); +} + +static HRESULT WINAPI HTMLEventObj2_QueryInterface(IHTMLEventObj2 *iface, REFIID riid, void **ppv) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return IHTMLEventObj_QueryInterface(&This->IHTMLEventObj_iface, riid, ppv); +} + +static ULONG WINAPI HTMLEventObj2_AddRef(IHTMLEventObj2 *iface) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return IHTMLEventObj_AddRef(&This->IHTMLEventObj_iface); +} + +static ULONG WINAPI HTMLEventObj2_Release(IHTMLEventObj2 *iface) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return IHTMLEventObj_Release(&This->IHTMLEventObj_iface); +} + +static HRESULT WINAPI HTMLEventObj2_GetTypeInfoCount(IHTMLEventObj2 *iface, UINT *pctinfo) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLEventObj2_GetTypeInfo(IHTMLEventObj2 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLEventObj2_GetIDsOfNames(IHTMLEventObj2 *iface, REFIID riid,LPOLESTR *rgszNames, + UINT cNames, LCID lcid, DISPID *rgDispId) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, lcid, rgDispId); +} + +static HRESULT WINAPI HTMLEventObj2_Invoke(IHTMLEventObj2 *iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, pDispParams, + pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLEventObj2_setAttribute(IHTMLEventObj2 *iface, BSTR strAttributeName, VARIANT AttributeValue, LONG lFlags) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%s %s %08lx)\n", This, debugstr_w(strAttributeName), debugstr_variant(&AttributeValue), lFlags); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_getAttribute(IHTMLEventObj2 *iface, BSTR strAttributeName, LONG lFlags, VARIANT *AttributeValue) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%s %08lx %p)\n", This, debugstr_w(strAttributeName), lFlags, AttributeValue); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_removeAttribute(IHTMLEventObj2 *iface, BSTR strAttributeName, LONG lFlags, VARIANT_BOOL *pfSuccess) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%s %lx %p)\n", This, debugstr_w(strAttributeName), lFlags, pfSuccess); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_put_propertyName(IHTMLEventObj2 *iface, BSTR v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_propertyName(IHTMLEventObj2 *iface, BSTR *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_put_bookmarks(IHTMLEventObj2 *iface, IHTMLBookmarkCollection *v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%p)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_bookmarks(IHTMLEventObj2 *iface, IHTMLBookmarkCollection **p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_put_recordset(IHTMLEventObj2 *iface, IDispatch *v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%p)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_recordset(IHTMLEventObj2 *iface, IDispatch **p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_put_dataFld(IHTMLEventObj2 *iface, BSTR v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_dataFld(IHTMLEventObj2 *iface, BSTR *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_put_boundElements(IHTMLEventObj2 *iface, IHTMLElementCollection *v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%p)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_boundElements(IHTMLEventObj2 *iface, IHTMLElementCollection **p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_put_repeat(IHTMLEventObj2 *iface, VARIANT_BOOL v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%x)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_repeat(IHTMLEventObj2 *iface, VARIANT_BOOL *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_put_srcUrn(IHTMLEventObj2 *iface, BSTR v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_srcUrn(IHTMLEventObj2 *iface, BSTR *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_put_srcElement(IHTMLEventObj2 *iface, IHTMLElement *v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%p)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_srcElement(IHTMLEventObj2 *iface, IHTMLElement **p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_srcElement(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_altKey(IHTMLEventObj2 *iface, VARIANT_BOOL v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%x)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_altKey(IHTMLEventObj2 *iface, VARIANT_BOOL *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_altKey(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_ctrlKey(IHTMLEventObj2 *iface, VARIANT_BOOL v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%x)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_ctrlKey(IHTMLEventObj2 *iface, VARIANT_BOOL *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_ctrlKey(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_shiftKey(IHTMLEventObj2 *iface, VARIANT_BOOL v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%x)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_shiftKey(IHTMLEventObj2 *iface, VARIANT_BOOL *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_shiftKey(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_fromElement(IHTMLEventObj2 *iface, IHTMLElement *v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%p)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_fromElement(IHTMLEventObj2 *iface, IHTMLElement **p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_fromElement(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_toElement(IHTMLEventObj2 *iface, IHTMLElement *v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%p)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_toElement(IHTMLEventObj2 *iface, IHTMLElement **p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_toElement(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_button(IHTMLEventObj2 *iface, LONG v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%ld)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_button(IHTMLEventObj2 *iface, LONG *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_button(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_type(IHTMLEventObj2 *iface, BSTR v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_type(IHTMLEventObj2 *iface, BSTR *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_type(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_qualifier(IHTMLEventObj2 *iface, BSTR v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_qualifier(IHTMLEventObj2 *iface, BSTR *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_qualifier(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_reason(IHTMLEventObj2 *iface, LONG v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%ld)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_reason(IHTMLEventObj2 *iface, LONG *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_reason(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_x(IHTMLEventObj2 *iface, LONG v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%ld)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_x(IHTMLEventObj2 *iface, LONG *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_x(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_y(IHTMLEventObj2 *iface, LONG v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%ld)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_y(IHTMLEventObj2 *iface, LONG *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_y(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_clientX(IHTMLEventObj2 *iface, LONG v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%ld)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_clientX(IHTMLEventObj2 *iface, LONG *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_clientX(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_clientY(IHTMLEventObj2 *iface, LONG v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%ld)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_clientY(IHTMLEventObj2 *iface, LONG *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_clientY(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_offsetX(IHTMLEventObj2 *iface, LONG v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%ld)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_offsetX(IHTMLEventObj2 *iface, LONG *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_offsetX(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_offsetY(IHTMLEventObj2 *iface, LONG v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%ld)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_offsetY(IHTMLEventObj2 *iface, LONG *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_offsetY(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_screenX(IHTMLEventObj2 *iface, LONG v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%ld)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_screenX(IHTMLEventObj2 *iface, LONG *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_screenX(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_screenY(IHTMLEventObj2 *iface, LONG v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%ld)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_screenY(IHTMLEventObj2 *iface, LONG *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_screenY(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_put_srcFilter(IHTMLEventObj2 *iface, IDispatch *v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%p)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj2_get_srcFilter(IHTMLEventObj2 *iface, IDispatch **p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + return HTMLEventObj_get_srcFilter(&This->IHTMLEventObj_iface, p); +} + +static HRESULT WINAPI HTMLEventObj2_get_dataTransfer(IHTMLEventObj2 *iface, IHTMLDataTransfer **p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj2(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static const IHTMLEventObj2Vtbl HTMLEventObj2Vtbl = { + HTMLEventObj2_QueryInterface, + HTMLEventObj2_AddRef, + HTMLEventObj2_Release, + HTMLEventObj2_GetTypeInfoCount, + HTMLEventObj2_GetTypeInfo, + HTMLEventObj2_GetIDsOfNames, + HTMLEventObj2_Invoke, + HTMLEventObj2_setAttribute, + HTMLEventObj2_getAttribute, + HTMLEventObj2_removeAttribute, + HTMLEventObj2_put_propertyName, + HTMLEventObj2_get_propertyName, + HTMLEventObj2_put_bookmarks, + HTMLEventObj2_get_bookmarks, + HTMLEventObj2_put_recordset, + HTMLEventObj2_get_recordset, + HTMLEventObj2_put_dataFld, + HTMLEventObj2_get_dataFld, + HTMLEventObj2_put_boundElements, + HTMLEventObj2_get_boundElements, + HTMLEventObj2_put_repeat, + HTMLEventObj2_get_repeat, + HTMLEventObj2_put_srcUrn, + HTMLEventObj2_get_srcUrn, + HTMLEventObj2_put_srcElement, + HTMLEventObj2_get_srcElement, + HTMLEventObj2_put_altKey, + HTMLEventObj2_get_altKey, + HTMLEventObj2_put_ctrlKey, + HTMLEventObj2_get_ctrlKey, + HTMLEventObj2_put_shiftKey, + HTMLEventObj2_get_shiftKey, + HTMLEventObj2_put_fromElement, + HTMLEventObj2_get_fromElement, + HTMLEventObj2_put_toElement, + HTMLEventObj2_get_toElement, + HTMLEventObj2_put_button, + HTMLEventObj2_get_button, + HTMLEventObj2_put_type, + HTMLEventObj2_get_type, + HTMLEventObj2_put_qualifier, + HTMLEventObj2_get_qualifier, + HTMLEventObj2_put_reason, + HTMLEventObj2_get_reason, + HTMLEventObj2_put_x, + HTMLEventObj2_get_x, + HTMLEventObj2_put_y, + HTMLEventObj2_get_y, + HTMLEventObj2_put_clientX, + HTMLEventObj2_get_clientX, + HTMLEventObj2_put_clientY, + HTMLEventObj2_get_clientY, + HTMLEventObj2_put_offsetX, + HTMLEventObj2_get_offsetX, + HTMLEventObj2_put_offsetY, + HTMLEventObj2_get_offsetY, + HTMLEventObj2_put_screenX, + HTMLEventObj2_get_screenX, + HTMLEventObj2_put_screenY, + HTMLEventObj2_get_screenY, + HTMLEventObj2_put_srcFilter, + HTMLEventObj2_get_srcFilter, + HTMLEventObj2_get_dataTransfer +}; + +static inline HTMLEventObj *impl_from_IHTMLEventObj3(IHTMLEventObj3 *iface) +{ + return CONTAINING_RECORD(iface, HTMLEventObj, IHTMLEventObj3_iface); +} + +static HRESULT WINAPI HTMLEventObj3_QueryInterface(IHTMLEventObj3 *iface, REFIID riid, void **ppv) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + return IHTMLEventObj_QueryInterface(&This->IHTMLEventObj_iface, riid, ppv); +} + +static ULONG WINAPI HTMLEventObj3_AddRef(IHTMLEventObj3 *iface) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + return IHTMLEventObj_AddRef(&This->IHTMLEventObj_iface); +} + +static ULONG WINAPI HTMLEventObj3_Release(IHTMLEventObj3 *iface) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + return IHTMLEventObj_Release(&This->IHTMLEventObj_iface); +} + +static HRESULT WINAPI HTMLEventObj3_GetTypeInfoCount(IHTMLEventObj3 *iface, UINT *pctinfo) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLEventObj3_GetTypeInfo(IHTMLEventObj3 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLEventObj3_GetIDsOfNames(IHTMLEventObj3 *iface, REFIID riid,LPOLESTR *rgszNames, + UINT cNames, LCID lcid, DISPID *rgDispId) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, lcid, rgDispId); +} + +static HRESULT WINAPI HTMLEventObj3_Invoke(IHTMLEventObj3 *iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, pDispParams, + pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLEventObj3_get_contentOverflow(IHTMLEventObj3 *iface, VARIANT_BOOL *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj3_put_shiftLeft(IHTMLEventObj3 *iface, VARIANT_BOOL v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + + FIXME("(%p)->(%x)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj3_get_shiftLeft(IHTMLEventObj3 *iface, VARIANT_BOOL *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj3_put_altLeft(IHTMLEventObj3 *iface, VARIANT_BOOL v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + + FIXME("(%p)->(%x)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj3_get_altLeft(IHTMLEventObj3 *iface, VARIANT_BOOL *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj3_put_ctrlLeft(IHTMLEventObj3 *iface, VARIANT_BOOL v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + + FIXME("(%p)->(%x)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj3_get_ctrlLeft(IHTMLEventObj3 *iface, VARIANT_BOOL *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj3_get_imeCompositionChange(IHTMLEventObj3 *iface, LONG_PTR *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj3_get_imeNotifyCommand(IHTMLEventObj3 *iface, LONG_PTR *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj3_get_imeNotifyData(IHTMLEventObj3 *iface, LONG_PTR *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj3_get_imeRequest(IHTMLEventObj3 *iface, LONG_PTR *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj3_get_imeRequestData(IHTMLEventObj3 *iface, LONG_PTR *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj3_get_keyboardLayout(IHTMLEventObj3 *iface, LONG_PTR *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj3_get_behaviorCookie(IHTMLEventObj3 *iface, LONG *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj3_get_behaviorPart(IHTMLEventObj3 *iface, LONG *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj3_get_nextPage(IHTMLEventObj3 *iface, BSTR *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj3(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static const IHTMLEventObj3Vtbl HTMLEventObj3Vtbl = { + HTMLEventObj3_QueryInterface, + HTMLEventObj3_AddRef, + HTMLEventObj3_Release, + HTMLEventObj3_GetTypeInfoCount, + HTMLEventObj3_GetTypeInfo, + HTMLEventObj3_GetIDsOfNames, + HTMLEventObj3_Invoke, + HTMLEventObj3_get_contentOverflow, + HTMLEventObj3_put_shiftLeft, + HTMLEventObj3_get_shiftLeft, + HTMLEventObj3_put_altLeft, + HTMLEventObj3_get_altLeft, + HTMLEventObj3_put_ctrlLeft, + HTMLEventObj3_get_ctrlLeft, + HTMLEventObj3_get_imeCompositionChange, + HTMLEventObj3_get_imeNotifyCommand, + HTMLEventObj3_get_imeNotifyData, + HTMLEventObj3_get_imeRequest, + HTMLEventObj3_get_imeRequestData, + HTMLEventObj3_get_keyboardLayout, + HTMLEventObj3_get_behaviorCookie, + HTMLEventObj3_get_behaviorPart, + HTMLEventObj3_get_nextPage +}; + +static inline HTMLEventObj *impl_from_IHTMLEventObj4(IHTMLEventObj4 *iface) +{ + return CONTAINING_RECORD(iface, HTMLEventObj, IHTMLEventObj4_iface); +} + +static HRESULT WINAPI HTMLEventObj4_QueryInterface(IHTMLEventObj4 *iface, REFIID riid, void **ppv) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj4(iface); + return IHTMLEventObj_QueryInterface(&This->IHTMLEventObj_iface, riid, ppv); +} + +static ULONG WINAPI HTMLEventObj4_AddRef(IHTMLEventObj4 *iface) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj4(iface); + return IHTMLEventObj_AddRef(&This->IHTMLEventObj_iface); +} + +static ULONG WINAPI HTMLEventObj4_Release(IHTMLEventObj4 *iface) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj4(iface); + return IHTMLEventObj_Release(&This->IHTMLEventObj_iface); +} + +static HRESULT WINAPI HTMLEventObj4_GetTypeInfoCount(IHTMLEventObj4 *iface, UINT *pctinfo) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj4(iface); + return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLEventObj4_GetTypeInfo(IHTMLEventObj4 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj4(iface); + return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLEventObj4_GetIDsOfNames(IHTMLEventObj4 *iface, REFIID riid,LPOLESTR *rgszNames, + UINT cNames, LCID lcid, DISPID *rgDispId) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj4(iface); + return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, lcid, rgDispId); +} + +static HRESULT WINAPI HTMLEventObj4_Invoke(IHTMLEventObj4 *iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj4(iface); + return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, pDispParams, + pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLEventObj4_get_wheelDelta(IHTMLEventObj4 *iface, LONG *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj4(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static const IHTMLEventObj4Vtbl HTMLEventObj4Vtbl = { + HTMLEventObj4_QueryInterface, + HTMLEventObj4_AddRef, + HTMLEventObj4_Release, + HTMLEventObj4_GetTypeInfoCount, + HTMLEventObj4_GetTypeInfo, + HTMLEventObj4_GetIDsOfNames, + HTMLEventObj4_Invoke, + HTMLEventObj4_get_wheelDelta +}; + +static inline HTMLEventObj *impl_from_IHTMLEventObj5(IHTMLEventObj5 *iface) +{ + return CONTAINING_RECORD(iface, HTMLEventObj, IHTMLEventObj5_iface); +} + +static HRESULT WINAPI HTMLEventObj5_QueryInterface(IHTMLEventObj5 *iface, REFIID riid, void **ppv) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + return IHTMLEventObj_QueryInterface(&This->IHTMLEventObj_iface, riid, ppv); +} + +static ULONG WINAPI HTMLEventObj5_AddRef(IHTMLEventObj5 *iface) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + return IHTMLEventObj_AddRef(&This->IHTMLEventObj_iface); +} + +static ULONG WINAPI HTMLEventObj5_Release(IHTMLEventObj5 *iface) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + return IHTMLEventObj_Release(&This->IHTMLEventObj_iface); +} + +static HRESULT WINAPI HTMLEventObj5_GetTypeInfoCount(IHTMLEventObj5 *iface, UINT *pctinfo) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLEventObj5_GetTypeInfo(IHTMLEventObj5 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLEventObj5_GetIDsOfNames(IHTMLEventObj5 *iface, REFIID riid,LPOLESTR *rgszNames, + UINT cNames, LCID lcid, DISPID *rgDispId) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, lcid, rgDispId); +} + +static HRESULT WINAPI HTMLEventObj5_Invoke(IHTMLEventObj5 *iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, pDispParams, + pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLEventObj5_put_url(IHTMLEventObj5 *iface, BSTR v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + + return DISP_E_MEMBERNOTFOUND; +} + +static HRESULT WINAPI HTMLEventObj5_get_url(IHTMLEventObj5 *iface, BSTR *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + + FIXME("(%p)->(%p)\n", This, p); + + *p = NULL; + return S_OK; +} + +static HRESULT WINAPI HTMLEventObj5_put_data(IHTMLEventObj5 *iface, BSTR v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj5_get_data(IHTMLEventObj5 *iface, BSTR *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + + FIXME("(%p)->(%p)\n", This, p); + + *p = NULL; + return S_OK; +} + +static HRESULT WINAPI HTMLEventObj5_get_source(IHTMLEventObj5 *iface, IDispatch **p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + + FIXME("(%p)->(%p)\n", This, p); + + *p = NULL; + return S_OK; +} + +static HRESULT WINAPI HTMLEventObj5_put_origin(IHTMLEventObj5 *iface, BSTR v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + + return DISP_E_MEMBERNOTFOUND; +} + +static HRESULT WINAPI HTMLEventObj5_get_origin(IHTMLEventObj5 *iface, BSTR *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + + FIXME("(%p)->(%p)\n", This, p); + + *p = NULL; + return S_OK; +} + +static HRESULT WINAPI HTMLEventObj5_put_issession(IHTMLEventObj5 *iface, VARIANT_BOOL v) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + + FIXME("(%p)->(%x)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj5_get_issession(IHTMLEventObj5 *iface, VARIANT_BOOL *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static const IHTMLEventObj5Vtbl HTMLEventObj5Vtbl = { + HTMLEventObj5_QueryInterface, + HTMLEventObj5_AddRef, + HTMLEventObj5_Release, + HTMLEventObj5_GetTypeInfoCount, + HTMLEventObj5_GetTypeInfo, + HTMLEventObj5_GetIDsOfNames, + HTMLEventObj5_Invoke, + HTMLEventObj5_put_url, + HTMLEventObj5_get_url, + HTMLEventObj5_put_data, + HTMLEventObj5_get_data, + HTMLEventObj5_get_source, + HTMLEventObj5_put_origin, + HTMLEventObj5_get_origin, + HTMLEventObj5_put_issession, + HTMLEventObj5_get_issession +}; + +static inline HTMLEventObj *impl_from_IHTMLEventObj6(IHTMLEventObj6 *iface) +{ + return CONTAINING_RECORD(iface, HTMLEventObj, IHTMLEventObj6_iface); +} + +static HRESULT WINAPI HTMLEventObj6_QueryInterface(IHTMLEventObj6 *iface, REFIID riid, void **ppv) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj6(iface); + return IHTMLEventObj_QueryInterface(&This->IHTMLEventObj_iface, riid, ppv); +} + +static ULONG WINAPI HTMLEventObj6_AddRef(IHTMLEventObj6 *iface) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj6(iface); + return IHTMLEventObj_AddRef(&This->IHTMLEventObj_iface); +} + +static ULONG WINAPI HTMLEventObj6_Release(IHTMLEventObj6 *iface) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj6(iface); + return IHTMLEventObj_Release(&This->IHTMLEventObj_iface); +} + +static HRESULT WINAPI HTMLEventObj6_GetTypeInfoCount(IHTMLEventObj6 *iface, UINT *pctinfo) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj6(iface); + return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLEventObj6_GetTypeInfo(IHTMLEventObj6 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj6(iface); + return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLEventObj6_GetIDsOfNames(IHTMLEventObj6 *iface, REFIID riid,LPOLESTR *rgszNames, + UINT cNames, LCID lcid, DISPID *rgDispId) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj6(iface); + return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, lcid, rgDispId); +} + +static HRESULT WINAPI HTMLEventObj6_Invoke(IHTMLEventObj6 *iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj6(iface); + return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, pDispParams, + pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLEventObj6_get_actionURL(IHTMLEventObj6 *iface, BSTR *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj6(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLEventObj6_get_buttonID(IHTMLEventObj6 *iface, LONG *p) +{ + HTMLEventObj *This = impl_from_IHTMLEventObj6(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static const IHTMLEventObj6Vtbl HTMLEventObj6Vtbl = { + HTMLEventObj6_QueryInterface, + HTMLEventObj6_AddRef, + HTMLEventObj6_Release, + HTMLEventObj6_GetTypeInfoCount, + HTMLEventObj6_GetTypeInfo, + HTMLEventObj6_GetIDsOfNames, + HTMLEventObj6_Invoke, + HTMLEventObj6_get_actionURL, + HTMLEventObj6_get_buttonID +}; + static const tid_t HTMLEventObj_iface_tids[] = { IHTMLEventObj_tid, + IHTMLEventObj2_tid, + IHTMLEventObj3_tid, + IHTMLEventObj4_tid, + IHTMLEventObj5_tid, + IHTMLEventObj6_tid, 0 }; @@ -908,6 +2015,11 @@ static HTMLEventObj *alloc_event_obj(DOMEvent *event, compat_mode_t compat_mode) return NULL; event_obj->IHTMLEventObj_iface.lpVtbl = &HTMLEventObjVtbl; + event_obj->IHTMLEventObj2_iface.lpVtbl = &HTMLEventObj2Vtbl; + event_obj->IHTMLEventObj3_iface.lpVtbl = &HTMLEventObj3Vtbl; + event_obj->IHTMLEventObj4_iface.lpVtbl = &HTMLEventObj4Vtbl; + event_obj->IHTMLEventObj5_iface.lpVtbl = &HTMLEventObj5Vtbl; + event_obj->IHTMLEventObj6_iface.lpVtbl = &HTMLEventObj6Vtbl; event_obj->ref = 1; event_obj->event = event; if(event) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 81a0fd3a7ff..b8aec96bae1 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -207,6 +207,11 @@ typedef struct EventTarget EventTarget; XIID(IHTMLElementCollection) \ XIID(IHTMLEmbedElement) \ XIID(IHTMLEventObj) \ + XIID(IHTMLEventObj2) \ + XIID(IHTMLEventObj3) \ + XIID(IHTMLEventObj4) \ + XIID(IHTMLEventObj5) \ + XIID(IHTMLEventObj6) \ XIID(IHTMLFiltersCollection) \ XIID(IHTMLFormElement) \ XIID(IHTMLFrameBase) \ diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index f15080dc87c..13d64ff5b0c 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -388,6 +388,9 @@ static void _elem_fire_event(unsigned line, IUnknown *unk, const WCHAR *event, V static void _test_event_args(unsigned line, const IID *dispiid, DISPID id, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { + IHTMLEventObj *window_event, *event_obj = NULL; + HRESULT hres; + ok_(__FILE__,line) (id == DISPID_VALUE, "id = %ld\n", id); ok_(__FILE__,line) (wFlags == DISPATCH_METHOD, "wFlags = %x\n", wFlags); ok_(__FILE__,line) (pdp != NULL, "pdp == NULL\n"); @@ -405,10 +408,11 @@ static void _test_event_args(unsigned line, const IID *dispiid, DISPID id, WORD if(dispiid) _test_disp(line, (IUnknown*)V_DISPATCH(pdp->rgvarg), dispiid); + hres = IHTMLWindow2_get_event(window, &window_event); + ok(hres == S_OK, "get_event failed: %08lx\n", hres); + if(pdp->cArgs > 1) { - IHTMLEventObj *window_event, *event_obj; IDOMEvent *event; - HRESULT hres; hres = IDispatch_QueryInterface(V_DISPATCH(pdp->rgvarg+1), &IID_IDOMEvent, (void**)&event); if(in_fire_event) @@ -418,24 +422,62 @@ static void _test_event_args(unsigned line, const IID *dispiid, DISPID id, WORD hres = IDispatch_QueryInterface(V_DISPATCH(pdp->rgvarg+1), &IID_IHTMLEventObj, (void**)&event_obj); if(in_fire_event) - ok(hres == S_OK, "Could not get IDOMEventObj iface: %08lx\n", hres); + ok(hres == S_OK, "Could not get IHTMLEventObj iface: %08lx\n", hres); else ok(hres == E_NOINTERFACE, "QI(IID_IHTMLEventObj) returned %08lx\n", hres); if(event) IDOMEvent_Release(event); - if(event_obj) - IHTMLEventObj_Release(event_obj); - hres = IHTMLWindow2_get_event(window, &window_event); - ok(hres == S_OK, "get_event failed: %08lx\n", hres); if(window_event) { todo_wine_if(in_fire_event) ok(!iface_cmp((IUnknown*)V_DISPATCH(pdp->rgvarg+1), (IUnknown*)window_event), "window_event != event arg\n"); - IHTMLEventObj_Release(window_event); } } + + if(window_event) { + if(!event_obj) + event_obj = window_event; + else + IHTMLEventObj_Release(window_event); + } + + if(event_obj) { + IHTMLEventObj5 *event_obj5; + IDispatch *disp; + BSTR bstr; + + hres = IHTMLEventObj_QueryInterface(event_obj, &IID_IHTMLEventObj5, (void**)&event_obj5); + ok(hres == S_OK, "Could not get IHTMLEventObj5: %08lx\n", hres); + IHTMLEventObj_Release(event_obj); + + hres = IHTMLEventObj5_get_data(event_obj5, &bstr); + ok(hres == S_OK, "get_data failed: %08lx\n", hres); + ok(!bstr, "data = %s\n", wine_dbgstr_w(bstr)); + + hres = IHTMLEventObj5_get_origin(event_obj5, &bstr); + ok(hres == S_OK, "get_origin failed: %08lx\n", hres); + ok(!bstr, "origin = %s\n", wine_dbgstr_w(bstr)); + + hres = IHTMLEventObj5_get_source(event_obj5, &disp); + ok(hres == S_OK, "get_source failed: %08lx\n", hres); + ok(!disp, "source != NULL\n"); + + hres = IHTMLEventObj5_get_url(event_obj5, &bstr); + ok(hres == S_OK, "get_url failed: %08lx\n", hres); + ok(!bstr, "url = %s\n", wine_dbgstr_w(bstr)); + + bstr = SysAllocString(L"foobar"); + hres = IHTMLEventObj5_put_origin(event_obj5, bstr); + ok(hres == DISP_E_MEMBERNOTFOUND, "put_origin returned: %08lx\n", hres); + + hres = IHTMLEventObj5_put_url(event_obj5, bstr); + ok(hres == DISP_E_MEMBERNOTFOUND, "put_url returned: %08lx\n", hres); + SysFreeString(bstr); + + IHTMLEventObj5_Release(event_obj5); + } } #define test_attached_event_args(a,b,c,d,e) _test_attached_event_args(__LINE__,a,b,c,d,e) diff --git a/dlls/mshtml/tests/events.html b/dlls/mshtml/tests/events.html index 955e4853b92..e9a39e59b91 100644 --- a/dlls/mshtml/tests/events.html +++ b/dlls/mshtml/tests/events.html @@ -283,7 +283,24 @@ document.body.removeChild(div); } +function test_event_obj_props(e) { + var i, props = [ + "actionURL", "altKey", "altLeft", "behaviorCookie", "behaviorPart", "bookmarks", "boundElements", "button", "buttonID", + "cancelBubble", "clientX", "clientY", "contentOverflow", "ctrlKey", "ctrlLeft", "data", "dataFld", "dataTransfer", + "fromElement", "keyCode", "nextPage", "offsetX", "offsetY", "origin", "propertyName", "qualifier", "reason", "recordset", + "repeat", "returnValue", "screenX", "screenY", "shiftKey", "shiftLeft", "source", "srcElement", "srcFilter", "srcUrn", + "toElement", "type", "url", "wheelDelta", "x", "y", "getAttribute", "setAttribute", "removeAttribute" ]; + for(i = 0; i < props.length; i++) + ok(props[i] in e, props[i] + " not in event obj"); + + props = [ "imeCompositionChange", "imeNotifyCommand", "imeNotifyData", "imeRequest", "imeRequestData", "issession", "keyboardLayout" ]; + for(i = 0; i < props.length; i++) + todo_wine. + ok(!(props[i] in e), props[i] + " in event obj"); +} + window.onload = function() { + test_event_obj_props(window.event); try { ok(inlscr_complete_called, "onreadystatechange not fired"); ok(extern_res_script_rs === "eval,complete1," || extern_res_script_rs == "loaded0,eval,complete1,", From 1840377d19d9f13aebc8f8cecddb80e6136dfea7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:58 +0200 Subject: [PATCH 0836/2777] mshtml: Don't expose "restricted" members. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/dispex.c | 2 ++ dlls/mshtml/tests/events.html | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 1d00012572b..87930a9aa9f 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -279,6 +279,8 @@ static void add_func_info(dispex_data_t *data, tid_t tid, const FUNCDESC *desc, if(name_override) name = SysAllocString(name_override); + else if(desc->wFuncFlags & FUNCFLAG_FRESTRICTED) + return; else { hres = ITypeInfo_GetDocumentation(dti, desc->memid, &name, NULL, NULL, NULL); if(FAILED(hres)) { diff --git a/dlls/mshtml/tests/events.html b/dlls/mshtml/tests/events.html index e9a39e59b91..5388ce1bf5a 100644 --- a/dlls/mshtml/tests/events.html +++ b/dlls/mshtml/tests/events.html @@ -295,7 +295,6 @@ props = [ "imeCompositionChange", "imeNotifyCommand", "imeNotifyData", "imeRequest", "imeRequestData", "issession", "keyboardLayout" ]; for(i = 0; i < props.length; i++) - todo_wine. ok(!(props[i] in e), props[i] + " in event obj"); } From a9ab089f0d4d62e733dc9b0331d7d50e5dce0413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:58 +0200 Subject: [PATCH 0837/2777] mshtml: Send proper legacy storage event with actual url. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- Will be tested in next patch when the url prop for the legacy event obj is implemented. --- dlls/mshtml/htmldoc.c | 2 +- dlls/mshtml/htmlevent.c | 4 ++-- dlls/mshtml/htmlevent.h | 2 +- dlls/mshtml/htmlstorage.c | 15 ++++++++++++--- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index c69fface8c3..62bafab858a 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -3048,7 +3048,7 @@ static HRESULT WINAPI HTMLDocument4_createEventObject(IHTMLDocument4 *iface, return E_NOTIMPL; } - return create_event_obj(dispex_compat_mode(&This->node.event_target.dispex), ppEventObj); + return create_event_obj(NULL, dispex_compat_mode(&This->node.event_target.dispex), ppEventObj); } static HRESULT WINAPI HTMLDocument4_fireEvent(IHTMLDocument4 *iface, BSTR bstrEventName, diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index cf192b94026..dfded8e2fc1 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -2029,11 +2029,11 @@ static HTMLEventObj *alloc_event_obj(DOMEvent *event, compat_mode_t compat_mode) return event_obj; } -HRESULT create_event_obj(compat_mode_t compat_mode, IHTMLEventObj **ret) +HRESULT create_event_obj(DOMEvent *event, compat_mode_t compat_mode, IHTMLEventObj **ret) { HTMLEventObj *event_obj; - event_obj = alloc_event_obj(NULL, compat_mode); + event_obj = alloc_event_obj(event, compat_mode); if(!event_obj) return E_OUTOFMEMORY; diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index e23e0c29a97..879f30013c5 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -110,7 +110,7 @@ HRESULT fire_event(HTMLDOMNode*,const WCHAR*,VARIANT*,VARIANT_BOOL*) DECLSPEC_HI void update_doc_cp_events(HTMLDocumentNode*,cp_static_data_t*) DECLSPEC_HIDDEN; HRESULT doc_init_events(HTMLDocumentNode*) DECLSPEC_HIDDEN; void detach_events(HTMLDocumentNode *doc) DECLSPEC_HIDDEN; -HRESULT create_event_obj(compat_mode_t,IHTMLEventObj**) DECLSPEC_HIDDEN; +HRESULT create_event_obj(DOMEvent*,compat_mode_t,IHTMLEventObj**) DECLSPEC_HIDDEN; void bind_target_event(HTMLDocumentNode*,EventTarget*,const WCHAR*,IDispatch*) DECLSPEC_HIDDEN; HRESULT ensure_doc_nsevent_handler(HTMLDocumentNode*,nsIDOMNode*,eventid_t) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/htmlstorage.c b/dlls/mshtml/htmlstorage.c index 21e3df5c3fb..30598113034 100644 --- a/dlls/mshtml/htmlstorage.c +++ b/dlls/mshtml/htmlstorage.c @@ -210,12 +210,21 @@ static void storage_event_proc(task_t *_task) struct storage_event_task *task = (struct storage_event_task*)_task; HTMLInnerWindow *window = task->window; DOMEvent *event = task->event; + compat_mode_t compat_mode; VARIANT_BOOL cancelled; + HRESULT hres; + VARIANT var; - if(event->event_id == EVENTID_STORAGE && dispex_compat_mode(&window->event_target.dispex) >= COMPAT_MODE_IE9) { + if(event->event_id == EVENTID_STORAGE && (compat_mode = dispex_compat_mode(&window->event_target.dispex)) >= COMPAT_MODE_IE9) { dispatch_event(&window->event_target, event); - if(window->doc) - fire_event(&window->doc->node, L"onstorage", NULL, &cancelled); + if(window->doc) { + hres = create_event_obj(event, compat_mode, (IHTMLEventObj**)&V_DISPATCH(&var)); + if(SUCCEEDED(hres)) { + V_VT(&var) = VT_DISPATCH; + fire_event(&window->doc->node, L"onstorage", &var, &cancelled); + IDispatch_Release(V_DISPATCH(&var)); + } + } }else if(window->doc) { dispatch_event(&window->doc->node.event_target, event); } From 41dcfea0da21ae8c248062854110c670d900af33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:58 +0200 Subject: [PATCH 0838/2777] mshtml: Implement `url` prop for StorageEvent objs. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlevent.c | 62 ++++++++++++++++++++++++++------------ dlls/mshtml/tests/events.c | 37 ++++++++++++++++++++++- 2 files changed, 79 insertions(+), 20 deletions(-) diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index dfded8e2fc1..62f16c8c672 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -346,6 +346,20 @@ static DOMUIEvent *DOMUIEvent_from_DOMEvent(DOMEvent *event) return CONTAINING_RECORD(event, DOMUIEvent, event); } +typedef struct { + DOMEvent event; + IDOMStorageEvent IDOMStorageEvent_iface; + BSTR key; + BSTR old_value; + BSTR new_value; + BSTR url; +} DOMStorageEvent; + +static DOMStorageEvent *DOMStorageEvent_from_DOMEvent(DOMEvent *event) +{ + return CONTAINING_RECORD(event, DOMStorageEvent, event); +} + typedef struct { DispatchEx dispex; IHTMLEventObj IHTMLEventObj_iface; @@ -1808,20 +1822,44 @@ static HRESULT WINAPI HTMLEventObj5_Invoke(IHTMLEventObj5 *iface, DISPID dispIdM static HRESULT WINAPI HTMLEventObj5_put_url(IHTMLEventObj5 *iface, BSTR v) { HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + IDOMStorageEvent *storage_event; + DOMStorageEvent *p; + BSTR url; - FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + TRACE("(%p)->(%s)\n", This, debugstr_w(v)); - return DISP_E_MEMBERNOTFOUND; + if(!v) + return E_POINTER; + + if(!This->event || FAILED(IDOMEvent_QueryInterface(&This->event->IDOMEvent_iface, &IID_IDOMStorageEvent, (void**)&storage_event))) + return DISP_E_MEMBERNOTFOUND; + IDOMStorageEvent_Release(storage_event); + + if(!(url = SysAllocString(v))) + return E_OUTOFMEMORY; + + p = DOMStorageEvent_from_DOMEvent(This->event); + SysFreeString(p->url); + p->url = url; + return S_OK; } static HRESULT WINAPI HTMLEventObj5_get_url(IHTMLEventObj5 *iface, BSTR *p) { HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + IDOMStorageEvent *storage_event; + HRESULT hres; - FIXME("(%p)->(%p)\n", This, p); + TRACE("(%p)->(%p)\n", This, p); - *p = NULL; - return S_OK; + if(!This->event || FAILED(IDOMEvent_QueryInterface(&This->event->IDOMEvent_iface, &IID_IDOMStorageEvent, (void**)&storage_event))) { + *p = NULL; + return S_OK; + } + + hres = IDOMStorageEvent_get_url(storage_event, p); + IDOMStorageEvent_Release(storage_event); + return hres; } static HRESULT WINAPI HTMLEventObj5_put_data(IHTMLEventObj5 *iface, BSTR v) @@ -3848,15 +3886,6 @@ static void DOMProgressEvent_destroy(DOMEvent *event) nsIDOMProgressEvent_Release(This->nsevent); } -typedef struct { - DOMEvent event; - IDOMStorageEvent IDOMStorageEvent_iface; - BSTR key; - BSTR old_value; - BSTR new_value; - BSTR url; -} DOMStorageEvent; - static inline DOMStorageEvent *impl_from_IDOMStorageEvent(IDOMStorageEvent *iface) { return CONTAINING_RECORD(iface, DOMStorageEvent, IDOMStorageEvent_iface); @@ -3991,11 +4020,6 @@ static const IDOMStorageEventVtbl DOMStorageEventVtbl = { DOMStorageEvent_initStorageEvent }; -static DOMStorageEvent *DOMStorageEvent_from_DOMEvent(DOMEvent *event) -{ - return CONTAINING_RECORD(event, DOMStorageEvent, event); -} - static void *DOMStorageEvent_query_interface(DOMEvent *event, REFIID riid) { DOMStorageEvent *storage_event = DOMStorageEvent_from_DOMEvent(event); diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 13d64ff5b0c..c944ac34fe5 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -3651,9 +3651,11 @@ static void test_storage_event(DISPPARAMS *params, BOOL doc_onstorage) { const WCHAR *expect_key = onstorage_expect_key, *expect_old_value = onstorage_expect_old_value, *expect_new_value = onstorage_expect_new_value; unsigned line = onstorage_expect_line; + IHTMLEventObj5 *event_obj5; IHTMLEventObj *event_obj; IDOMStorageEvent *event; IDispatchEx *dispex; + IDispatch *disp; HRESULT hres; unsigned i; DISPID id; @@ -3677,6 +3679,8 @@ static void test_storage_event(DISPPARAMS *params, BOOL doc_onstorage) hres = IDispatchEx_QueryInterface(dispex, &IID_IHTMLEventObj, (void**)&event_obj); ok_(__FILE__,line)(hres == S_OK, "Could not get IHTMLEventObj: %08lx\n", hres); + hres = IHTMLEventObj_QueryInterface(event_obj, &IID_IHTMLEventObj5, (void**)&event_obj5); + ok_(__FILE__,line)(hres == S_OK, "Could not get IHTMLEventObj5: %08lx\n", hres); IHTMLEventObj_Release(event_obj); for(i = 0; i < ARRAY_SIZE(props); i++) { @@ -3685,8 +3689,39 @@ static void test_storage_event(DISPPARAMS *params, BOOL doc_onstorage) ok_(__FILE__,line)(hres == DISP_E_UNKNOWNNAME, "GetDispID(%s) failed: %08lx\n", wine_dbgstr_w(bstr), hres); SysFreeString(bstr); } - IDispatchEx_Release(dispex); + + hres = IHTMLEventObj5_get_data(event_obj5, &bstr); + ok_(__FILE__,line)(hres == S_OK, "get_data failed: %08lx\n", hres); + ok_(__FILE__,line)(!bstr, "data = %s\n", wine_dbgstr_w(bstr)); + + hres = IHTMLEventObj5_get_origin(event_obj5, &bstr); + ok_(__FILE__,line)(hres == S_OK, "get_origin failed: %08lx\n", hres); + ok_(__FILE__,line)(!bstr, "origin = %s\n", wine_dbgstr_w(bstr)); + + hres = IHTMLEventObj5_get_source(event_obj5, &disp); + ok_(__FILE__,line)(hres == S_OK, "get_source failed: %08lx\n", hres); + ok_(__FILE__,line)(!disp, "source != NULL\n"); + + hres = IHTMLEventObj5_get_url(event_obj5, &bstr); + ok_(__FILE__,line)(hres == S_OK, "get_url failed: %08lx\n", hres); + ok_(__FILE__,line)(!wcscmp(bstr, L"http://winetest.example.org/"), "url = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + bstr = SysAllocString(L"barfoo"); + hres = IHTMLEventObj5_put_url(event_obj5, bstr); + ok_(__FILE__,line)(hres == S_OK, "put_url failed: %08lx\n", hres); + SysFreeString(bstr); + + hres = IHTMLEventObj5_get_url(event_obj5, &bstr); + ok_(__FILE__,line)(hres == S_OK, "get_url after put failed: %08lx\n", hres); + ok_(__FILE__,line)(!wcscmp(bstr, L"barfoo"), "url after put = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + hres = IHTMLEventObj5_put_url(event_obj5, NULL); + ok_(__FILE__,line)(hres == E_POINTER, "put_url NULL returned: %08lx\n", hres); + + IHTMLEventObj5_Release(event_obj5); return; } From a4ed5f910b663a662d0e8fb9f5150d980166e579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:58 +0200 Subject: [PATCH 0839/2777] mshtml: Use a hook to implement postMessage. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need the caller ServiceProvider to obtain the source. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlwindow.c | 353 +++++++++++++++------------ dlls/mshtml/mshtml_private_iface.idl | 2 - 2 files changed, 201 insertions(+), 154 deletions(-) diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 65af600c633..b9e0de81dd6 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -2225,6 +2225,77 @@ static HRESULT WINAPI HTMLWindow6_get_maxConnectionsPerServer(IHTMLWindow6 *ifac return E_NOTIMPL; } +static HRESULT check_target_origin(HTMLInnerWindow *window, const WCHAR *target_origin) +{ + IUri *uri, *target; + DWORD port, port2; + BSTR bstr, bstr2; + HRESULT hres; + + if(!target_origin) + return E_INVALIDARG; + + if(!wcscmp(target_origin, L"*")) + return S_OK; + + hres = create_uri(target_origin, Uri_CREATE_NOFRAG | Uri_CREATE_NO_DECODE_EXTRA_INFO, &target); + if(FAILED(hres)) + return hres; + + if(!(uri = window->base.outer_window->uri)) { + FIXME("window with no URI\n"); + hres = S_FALSE; + goto done; + } + + bstr = NULL; + hres = IUri_GetSchemeName(uri, &bstr); + if(hres != S_OK) { + SysFreeString(bstr); + goto done; + } + hres = IUri_GetSchemeName(target, &bstr2); + if(SUCCEEDED(hres)) { + if(hres == S_OK && wcsicmp(bstr, bstr2)) + hres = S_FALSE; + SysFreeString(bstr2); + } + SysFreeString(bstr); + if(hres != S_OK) + goto done; + + bstr = NULL; + hres = IUri_GetHost(uri, &bstr); + if(hres != S_OK) { + SysFreeString(bstr); + goto done; + } + hres = IUri_GetHost(target, &bstr2); + if(SUCCEEDED(hres)) { + if(hres == S_OK && wcsicmp(bstr, bstr2)) + hres = S_FALSE; + SysFreeString(bstr2); + } + SysFreeString(bstr); + if(hres != S_OK) + goto done; + + /* Legacy modes ignore port */ + if(dispex_compat_mode(&window->event_target.dispex) < COMPAT_MODE_IE9) + goto done; + + hres = IUri_GetPort(uri, &port); + if(hres != S_OK) + goto done; + hres = IUri_GetPort(target, &port2); + if(hres == S_OK && port != port2) + hres = S_FALSE; + +done: + IUri_Release(target); + return hres; +} + struct post_message_task { task_t header; HTMLInnerWindow *window; @@ -2244,6 +2315,77 @@ static void post_message_destr(task_t *_task) IHTMLWindow2_Release(&task->window->base.IHTMLWindow2_iface); } +static HRESULT post_message(HTMLInnerWindow *window, VARIANT msg, BSTR targetOrigin, VARIANT transfer, + IServiceProvider *caller, compat_mode_t compat_mode) +{ + DOMEvent *event; + HRESULT hres; + + if(V_VT(&transfer) != VT_EMPTY && V_VT(&transfer) != VT_ERROR) + FIXME("transfer not implemented, ignoring\n"); + + hres = check_target_origin(window, targetOrigin); + if(hres != S_OK) + return SUCCEEDED(hres) ? S_OK : hres; + + switch(V_VT(&msg)) { + case VT_EMPTY: + case VT_NULL: + case VT_VOID: + case VT_I1: + case VT_I2: + case VT_I4: + case VT_I8: + case VT_UI1: + case VT_UI2: + case VT_UI4: + case VT_UI8: + case VT_INT: + case VT_UINT: + case VT_R4: + case VT_R8: + case VT_BOOL: + case VT_BSTR: + case VT_CY: + case VT_DATE: + case VT_DECIMAL: + case VT_HRESULT: + break; + case VT_ERROR: + V_VT(&msg) = VT_EMPTY; + break; + default: + FIXME("Unsupported vt %d\n", V_VT(&msg)); + return E_NOTIMPL; + } + + if(!window->doc) { + FIXME("No document\n"); + return E_FAIL; + } + + hres = create_message_event(window->doc, &msg, &event); + if(FAILED(hres)) + return hres; + + if(compat_mode >= COMPAT_MODE_IE9) { + struct post_message_task *task; + if(!(task = malloc(sizeof(*task)))) { + IDOMEvent_Release(&event->IDOMEvent_iface); + return E_OUTOFMEMORY; + } + + task->event = event; + task->window = window; + IHTMLWindow2_AddRef(&task->window->base.IHTMLWindow2_iface); + return push_task(&task->header, post_message_proc, post_message_destr, window->task_magic); + } + + dispatch_event(&window->event_target, event); + IDOMEvent_Release(&event->IDOMEvent_iface); + return S_OK; +} + static HRESULT WINAPI HTMLWindow6_postMessage(IHTMLWindow6 *iface, BSTR msg, VARIANT targetOrigin) { HTMLWindow *This = impl_from_IHTMLWindow6(iface); @@ -2257,7 +2399,8 @@ static HRESULT WINAPI HTMLWindow6_postMessage(IHTMLWindow6 *iface, BSTR msg, VAR V_VT(&var) = VT_BSTR; V_BSTR(&var) = msg; V_VT(&transfer) = VT_EMPTY; - return IWineHTMLWindowPrivate_postMessage(&This->IWineHTMLWindowPrivate_iface, var, V_BSTR(&targetOrigin), transfer); + return post_message(This->inner_window, var, V_BSTR(&targetOrigin), transfer, NULL, + dispex_compat_mode(&This->inner_window->event_target.dispex)); } static HRESULT WINAPI HTMLWindow6_toStaticHTML(IHTMLWindow6 *iface, BSTR bstrHTML, BSTR *pbstrStaticHTML) @@ -3183,152 +3326,6 @@ static HRESULT WINAPI window_private_matchMedia(IWineHTMLWindowPrivate *iface, B return create_media_query_list(This, media_query, media_query_list); } -static HRESULT check_target_origin(HTMLInnerWindow *window, const WCHAR *target_origin) -{ - IUri *uri, *target; - DWORD port, port2; - BSTR bstr, bstr2; - HRESULT hres; - - if(!target_origin) - return E_INVALIDARG; - - if(!wcscmp(target_origin, L"*")) - return S_OK; - - hres = create_uri(target_origin, Uri_CREATE_NOFRAG | Uri_CREATE_NO_DECODE_EXTRA_INFO, &target); - if(FAILED(hres)) - return hres; - - if(!(uri = window->base.outer_window->uri)) { - FIXME("window with no URI\n"); - hres = S_FALSE; - goto done; - } - - bstr = NULL; - hres = IUri_GetSchemeName(uri, &bstr); - if(hres != S_OK) { - SysFreeString(bstr); - goto done; - } - hres = IUri_GetSchemeName(target, &bstr2); - if(SUCCEEDED(hres)) { - if(hres == S_OK && wcsicmp(bstr, bstr2)) - hres = S_FALSE; - SysFreeString(bstr2); - } - SysFreeString(bstr); - if(hres != S_OK) - goto done; - - bstr = NULL; - hres = IUri_GetHost(uri, &bstr); - if(hres != S_OK) { - SysFreeString(bstr); - goto done; - } - hres = IUri_GetHost(target, &bstr2); - if(SUCCEEDED(hres)) { - if(hres == S_OK && wcsicmp(bstr, bstr2)) - hres = S_FALSE; - SysFreeString(bstr2); - } - SysFreeString(bstr); - if(hres != S_OK) - goto done; - - /* Legacy modes ignore port */ - if(dispex_compat_mode(&window->event_target.dispex) < COMPAT_MODE_IE9) - goto done; - - hres = IUri_GetPort(uri, &port); - if(hres != S_OK) - goto done; - hres = IUri_GetPort(target, &port2); - if(hres == S_OK && port != port2) - hres = S_FALSE; - -done: - IUri_Release(target); - return hres; -} - -static HRESULT WINAPI window_private_postMessage(IWineHTMLWindowPrivate *iface, VARIANT msg, BSTR targetOrigin, VARIANT transfer) -{ - HTMLWindow *This = impl_from_IWineHTMLWindowPrivateVtbl(iface); - HTMLInnerWindow *window = This->inner_window; - DOMEvent *event; - HRESULT hres; - - TRACE("iface %p, msg %s, targetOrigin %s, transfer %s\n", iface, debugstr_variant(&msg), - debugstr_w(targetOrigin), debugstr_variant(&transfer)); - - if(V_VT(&transfer) != VT_EMPTY && V_VT(&transfer) != VT_ERROR) - FIXME("transfer not implemented, ignoring\n"); - - hres = check_target_origin(window, targetOrigin); - if(hres != S_OK) - return SUCCEEDED(hres) ? S_OK : hres; - - switch(V_VT(&msg)) { - case VT_EMPTY: - case VT_NULL: - case VT_VOID: - case VT_I1: - case VT_I2: - case VT_I4: - case VT_I8: - case VT_UI1: - case VT_UI2: - case VT_UI4: - case VT_UI8: - case VT_INT: - case VT_UINT: - case VT_R4: - case VT_R8: - case VT_BOOL: - case VT_BSTR: - case VT_CY: - case VT_DATE: - case VT_DECIMAL: - case VT_HRESULT: - break; - case VT_ERROR: - V_VT(&msg) = VT_EMPTY; - break; - default: - FIXME("Unsupported vt %d\n", V_VT(&msg)); - return E_NOTIMPL; - } - - if(!window->doc) { - FIXME("No document\n"); - return E_FAIL; - } - - hres = create_message_event(window->doc, &msg, &event); - if(FAILED(hres)) - return hres; - - if(dispex_compat_mode(&window->event_target.dispex) >= COMPAT_MODE_IE9) { - struct post_message_task *task; - if(!(task = malloc(sizeof(*task)))) { - IDOMEvent_Release(&event->IDOMEvent_iface); - return E_OUTOFMEMORY; - } - - task->event = event; - task->window = window; - IHTMLWindow2_AddRef(&task->window->base.IHTMLWindow2_iface); - return push_task(&task->header, post_message_proc, post_message_destr, window->task_magic); - } - - dispatch_event(&window->event_target, event); - IDOMEvent_Release(&event->IDOMEvent_iface); - return S_OK; -} - static HRESULT WINAPI window_private_get_console(IWineHTMLWindowPrivate *iface, IDispatch **console) { HTMLWindow *This = impl_from_IWineHTMLWindowPrivateVtbl(iface); @@ -3356,7 +3353,6 @@ static const IWineHTMLWindowPrivateVtbl WineHTMLWindowPrivateVtbl = { window_private_cancelAnimationFrame, window_private_get_console, window_private_matchMedia, - window_private_postMessage, }; static inline HTMLWindow *impl_from_IWineHTMLWindowCompatPrivateVtbl(IWineHTMLWindowCompatPrivate *iface) @@ -4057,6 +4053,57 @@ static HRESULT IHTMLWindow3_setTimeout_hook(DispatchEx *dispex, WORD flags, DISP return dispex_call_builtin(dispex, DISPID_IHTMLWINDOW3_SETTIMEOUT, &new_dp, res, ei, caller); } +static HRESULT IHTMLWindow6_postMessage_hook(DispatchEx *dispex, WORD flags, DISPPARAMS *dp, VARIANT *res, + EXCEPINFO *ei, IServiceProvider *caller) +{ + HTMLInnerWindow *This = impl_from_DispatchEx(dispex); + BSTR targetOrigin, converted_msg = NULL; + VARIANT msg, transfer, converted; + compat_mode_t compat_mode; + HRESULT hres; + + if(!(flags & DISPATCH_METHOD) || dp->cArgs < 2 || dp->cNamedArgs) + return S_FALSE; + compat_mode = dispex_compat_mode(&This->event_target.dispex); + + msg = dp->rgvarg[dp->cArgs - 1]; + V_VT(&transfer) = VT_EMPTY; + if(compat_mode >= COMPAT_MODE_IE10 && dp->cArgs > 2) + transfer = dp->rgvarg[dp->cArgs - 3]; + + TRACE("(%p)->(msg %s, targetOrigin %s, transfer %s)\n", This, debugstr_variant(&msg), + debugstr_variant(&dp->rgvarg[dp->cArgs - 2]), debugstr_variant(&transfer)); + + if(compat_mode < COMPAT_MODE_IE10 && V_VT(&msg) != VT_BSTR) { + hres = change_type(&msg, &dp->rgvarg[dp->cArgs - 1], VT_BSTR, caller); + if(FAILED(hres)) + return hres; + converted_msg = V_BSTR(&msg); + } + + if(V_VT(&dp->rgvarg[dp->cArgs - 2]) == VT_BSTR) { + targetOrigin = V_BSTR(&dp->rgvarg[dp->cArgs - 2]); + V_BSTR(&converted) = NULL; + }else { + if(compat_mode < COMPAT_MODE_IE10) { + SysFreeString(converted_msg); + return E_INVALIDARG; + } + hres = change_type(&converted, &dp->rgvarg[dp->cArgs - 2], VT_BSTR, caller); + if(FAILED(hres)) { + SysFreeString(converted_msg); + return hres; + } + targetOrigin = V_BSTR(&converted); + } + + hres = post_message(This, msg, targetOrigin, transfer, caller, compat_mode); + + SysFreeString(V_BSTR(&converted)); + SysFreeString(converted_msg); + return hres; +} + static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) { static const dispex_hook_t window2_hooks[] = { @@ -4082,6 +4129,10 @@ static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compa {DISPID_IHTMLWINDOW4_CREATEPOPUP, NULL}, {DISPID_UNKNOWN} }; + static const dispex_hook_t window6_hooks[] = { + {DISPID_IHTMLWINDOW6_POSTMESSAGE, IHTMLWindow6_postMessage_hook}, + {DISPID_UNKNOWN} + }; if(compat_mode >= COMPAT_MODE_IE9) dispex_info_add_interface(info, IHTMLWindow7_tid, NULL); @@ -4090,6 +4141,7 @@ static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compa if(compat_mode >= COMPAT_MODE_IE10) dispex_info_add_interface(info, IWineHTMLWindowPrivate_tid, NULL); + dispex_info_add_interface(info, IHTMLWindow6_tid, window6_hooks); dispex_info_add_interface(info, IHTMLWindow5_tid, NULL); dispex_info_add_interface(info, IHTMLWindow4_tid, compat_mode >= COMPAT_MODE_IE11 ? window4_ie11_hooks : NULL); dispex_info_add_interface(info, IHTMLWindow3_tid, compat_mode >= COMPAT_MODE_IE11 ? window3_ie11_hooks : window3_hooks); @@ -4124,10 +4176,7 @@ static const event_target_vtbl_t HTMLWindow_event_target_vtbl = { HTMLWindow_set_current_event }; -static const tid_t HTMLWindow_iface_tids[] = { - IHTMLWindow6_tid, - 0 -}; +static const tid_t HTMLWindow_iface_tids[] = { 0 }; static dispex_static_data_t HTMLWindow_dispex = { L"Window", diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl index 8e4a64bda39..512942d7809 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -112,8 +112,6 @@ interface IWineHTMLWindowPrivate : IDispatch HRESULT console([retval, out] IDispatch **console); [id(53)] HRESULT matchMedia([in] BSTR media_query, [retval, out] IDispatch **media_query_list); - [id(54)] - HRESULT postMessage([in] VARIANT msg, [in] BSTR targetOrigin, [in, optional] VARIANT transfer); } [ From 953c1401a2df9ad746ccf2d7d8401a3a5c7acd86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:58 +0200 Subject: [PATCH 0840/2777] mshtml: Implement `source` prop for MessageEvents. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlevent.c | 30 +- dlls/mshtml/htmlevent.h | 2 +- dlls/mshtml/htmlwindow.c | 77 +++- dlls/mshtml/tests/documentmode.js | 1 + dlls/mshtml/tests/events.c | 611 +++++++++++++++++++++++++++++ dlls/mshtml/tests/events.js | 13 +- dlls/mshtml/tests/rsrc.rc | 3 + dlls/mshtml/tests/send2parent.html | 3 + 8 files changed, 724 insertions(+), 16 deletions(-) create mode 100644 dlls/mshtml/tests/send2parent.html diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 62f16c8c672..f01d55bd31c 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -1884,11 +1884,19 @@ static HRESULT WINAPI HTMLEventObj5_get_data(IHTMLEventObj5 *iface, BSTR *p) static HRESULT WINAPI HTMLEventObj5_get_source(IHTMLEventObj5 *iface, IDispatch **p) { HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + IDOMMessageEvent *message_event; + HRESULT hres; - FIXME("(%p)->(%p)\n", This, p); + TRACE("(%p)->(%p)\n", This, p); - *p = NULL; - return S_OK; + if(!This->event || FAILED(IDOMEvent_QueryInterface(&This->event->IDOMEvent_iface, &IID_IDOMMessageEvent, (void**)&message_event))) { + *p = NULL; + return S_OK; + } + + hres = IDOMMessageEvent_get_source(message_event, (IHTMLWindow2**)p); + IDOMMessageEvent_Release(message_event); + return hres; } static HRESULT WINAPI HTMLEventObj5_put_origin(IHTMLEventObj5 *iface, BSTR v) @@ -3594,6 +3602,7 @@ static void DOMCustomEvent_destroy(DOMEvent *event) typedef struct { DOMEvent event; IDOMMessageEvent IDOMMessageEvent_iface; + IHTMLWindow2 *source; VARIANT data; } DOMMessageEvent; @@ -3688,8 +3697,12 @@ static HRESULT WINAPI DOMMessageEvent_get_origin(IDOMMessageEvent *iface, BSTR * static HRESULT WINAPI DOMMessageEvent_get_source(IDOMMessageEvent *iface, IHTMLWindow2 **p) { DOMMessageEvent *This = impl_from_IDOMMessageEvent(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + if((*p = This->source)) + IHTMLWindow2_AddRef(This->source); + return S_OK; } static HRESULT WINAPI DOMMessageEvent_initMessageEvent(IDOMMessageEvent *iface, BSTR type, VARIANT_BOOL can_bubble, @@ -3732,6 +3745,8 @@ static void *DOMMessageEvent_query_interface(DOMEvent *event, REFIID riid) static void DOMMessageEvent_destroy(DOMEvent *event) { DOMMessageEvent *message_event = DOMMessageEvent_from_DOMEvent(event); + if(message_event->source) + IHTMLWindow2_Release(message_event->source); VariantClear(&message_event->data); } @@ -4413,7 +4428,7 @@ HRESULT create_document_event(HTMLDocumentNode *doc, eventid_t event_id, DOMEven return S_OK; } -HRESULT create_message_event(HTMLDocumentNode *doc, VARIANT *data, DOMEvent **ret) +HRESULT create_message_event(HTMLDocumentNode *doc, IHTMLWindow2 *source, VARIANT *data, DOMEvent **ret) { DOMMessageEvent *message_event; DOMEvent *event; @@ -4431,6 +4446,9 @@ HRESULT create_message_event(HTMLDocumentNode *doc, VARIANT *data, DOMEvent **re return hres; } + message_event->source = source; + IHTMLWindow2_AddRef(message_event->source); + *ret = event; return S_OK; } diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index 879f30013c5..4403340a5f9 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -119,7 +119,7 @@ void dispatch_event(EventTarget*,DOMEvent*) DECLSPEC_HIDDEN; HRESULT create_document_event(HTMLDocumentNode*,eventid_t,DOMEvent**) DECLSPEC_HIDDEN; HRESULT create_document_event_str(HTMLDocumentNode*,const WCHAR*,IDOMEvent**) DECLSPEC_HIDDEN; HRESULT create_event_from_nsevent(nsIDOMEvent*,compat_mode_t,DOMEvent**) DECLSPEC_HIDDEN; -HRESULT create_message_event(HTMLDocumentNode*,VARIANT*,DOMEvent**) DECLSPEC_HIDDEN; +HRESULT create_message_event(HTMLDocumentNode*,IHTMLWindow2*,VARIANT*,DOMEvent**) DECLSPEC_HIDDEN; HRESULT create_storage_event(HTMLDocumentNode*,BSTR,BSTR,BSTR,const WCHAR*,BOOL,DOMEvent**) DECLSPEC_HIDDEN; void init_nsevents(HTMLDocumentNode*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index b9e0de81dd6..f056f39c09f 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -28,6 +28,7 @@ #include "wininet.h" #include "shlguid.h" #include "shobjidl.h" +#include "activscp.h" #include "exdispid.h" #define NO_SHLWAPI_REG @@ -2296,6 +2297,61 @@ static HRESULT check_target_origin(HTMLInnerWindow *window, const WCHAR *target_ return hres; } +static IHTMLWindow2 *get_source_window(IServiceProvider *caller, compat_mode_t compat_mode) +{ + IOleCommandTarget *cmdtarget, *parent_cmdtarget; + IServiceProvider *parent; + IHTMLWindow2 *source; + HRESULT hres; + VARIANT var; + + if(!caller) + return NULL; + + hres = IServiceProvider_QueryService(caller, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&cmdtarget); + if(hres != S_OK) + cmdtarget = NULL; + + if(compat_mode < COMPAT_MODE_IE9) { + /* Legacy modes query caller unconditionally, and use it instead, if it has a command target */ + hres = IServiceProvider_QueryService(caller, &SID_GetCaller, &IID_IServiceProvider, (void**)&parent); + if(hres == S_OK && parent) { + hres = IServiceProvider_QueryService(parent, &IID_IActiveScriptSite, &IID_IOleCommandTarget, (void**)&parent_cmdtarget); + IServiceProvider_Release(parent); + if(hres == S_OK && parent_cmdtarget) { + if(cmdtarget) + IOleCommandTarget_Release(cmdtarget); + cmdtarget = parent_cmdtarget; + } + } + } + + if(!cmdtarget) + return NULL; + + V_VT(&var) = VT_EMPTY; + hres = IOleCommandTarget_Exec(cmdtarget, &CGID_ScriptSite, CMDID_SCRIPTSITE_SECURITY_WINDOW, 0, NULL, &var); + IOleCommandTarget_Release(cmdtarget); + if(hres != S_OK) + return NULL; + + /* Native assumes it's VT_DISPATCH and doesn't check it */ + hres = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IHTMLWindow2, (void**)&source); + IDispatch_Release(V_DISPATCH(&var)); + if(hres != S_OK) + return NULL; + + if(compat_mode < COMPAT_MODE_IE9) { + IHTMLWindow2 *tmp; + hres = IHTMLWindow2_get_self(source, &tmp); + if(hres == S_OK) { + IHTMLWindow2_Release(source); + source = tmp; + } + } + return source; +} + struct post_message_task { task_t header; HTMLInnerWindow *window; @@ -2318,6 +2374,7 @@ static void post_message_destr(task_t *_task) static HRESULT post_message(HTMLInnerWindow *window, VARIANT msg, BSTR targetOrigin, VARIANT transfer, IServiceProvider *caller, compat_mode_t compat_mode) { + IHTMLWindow2 *source; DOMEvent *event; HRESULT hres; @@ -2328,6 +2385,13 @@ static HRESULT post_message(HTMLInnerWindow *window, VARIANT msg, BSTR targetOri if(hres != S_OK) return SUCCEEDED(hres) ? S_OK : hres; + source = get_source_window(caller, compat_mode); + if(!source) { + if(compat_mode < COMPAT_MODE_IE9) + return E_ABORT; + IHTMLWindow2_AddRef(source = &window->base.outer_window->base.IHTMLWindow2_iface); + } + switch(V_VT(&msg)) { case VT_EMPTY: case VT_NULL: @@ -2356,15 +2420,18 @@ static HRESULT post_message(HTMLInnerWindow *window, VARIANT msg, BSTR targetOri break; default: FIXME("Unsupported vt %d\n", V_VT(&msg)); + IHTMLWindow2_Release(source); return E_NOTIMPL; } if(!window->doc) { FIXME("No document\n"); + IHTMLWindow2_Release(source); return E_FAIL; } - hres = create_message_event(window->doc, &msg, &event); + hres = create_message_event(window->doc, source, &msg, &event); + IHTMLWindow2_Release(source); if(FAILED(hres)) return hres; @@ -2389,18 +2456,14 @@ static HRESULT post_message(HTMLInnerWindow *window, VARIANT msg, BSTR targetOri static HRESULT WINAPI HTMLWindow6_postMessage(IHTMLWindow6 *iface, BSTR msg, VARIANT targetOrigin) { HTMLWindow *This = impl_from_IHTMLWindow6(iface); - VARIANT var, transfer; TRACE("(%p)->(%s %s)\n", This, debugstr_w(msg), debugstr_variant(&targetOrigin)); if(V_VT(&targetOrigin) != VT_BSTR) return E_INVALIDARG; - V_VT(&var) = VT_BSTR; - V_BSTR(&var) = msg; - V_VT(&transfer) = VT_EMPTY; - return post_message(This->inner_window, var, V_BSTR(&targetOrigin), transfer, NULL, - dispex_compat_mode(&This->inner_window->event_target.dispex)); + /* This can't obtain the source, and never works even in IE9+ modes... */ + return E_ABORT; } static HRESULT WINAPI HTMLWindow6_toStaticHTML(IHTMLWindow6 *iface, BSTR bstrHTML, BSTR *pbstrStaticHTML) diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 760d8db5e38..9b1461e4f5c 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -2587,6 +2587,7 @@ async_test("postMessage", function() { ok(e === undefined, "e = " + e); else { ok(e.data === (v < 10 ? "10" : 10), "e.data = " + e.data); + ok(e.source === window, "e.source = " + e.source); next_test(); } } diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index c944ac34fe5..f2e735fabde 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -26,6 +26,7 @@ #include "windef.h" #include "winbase.h" #include "ole2.h" +#include "activscp.h" #include "mshtml.h" #include "mshtmdid.h" #include "mshtmhst.h" @@ -100,6 +101,7 @@ DEFINE_EXPECT(submit_onclick_attached_check_cancel); DEFINE_EXPECT(submit_onclick_setret); DEFINE_EXPECT(elem2_cp_onclick); DEFINE_EXPECT(iframe_onload); +DEFINE_EXPECT(onmessage); DEFINE_EXPECT(visibilitychange); DEFINE_EXPECT(onbeforeunload); DEFINE_EXPECT(iframe_onbeforeunload); @@ -113,6 +115,15 @@ DEFINE_EXPECT(window1_onstorage); DEFINE_EXPECT(doc2_onstorage); DEFINE_EXPECT(doc2_onstoragecommit); DEFINE_EXPECT(window2_onstorage); +DEFINE_EXPECT(QS_IActiveScriptSite); +DEFINE_EXPECT(QS_IActiveScriptSite_parent); +DEFINE_EXPECT(QS_IActiveScriptSite_parent2); +DEFINE_EXPECT(QS_IActiveScriptSite_parent3); +DEFINE_EXPECT(QS_IActiveScriptSite_parent4); +DEFINE_EXPECT(QS_GetCaller); +DEFINE_EXPECT(QS_GetCaller_parent2); +DEFINE_EXPECT(QS_GetCaller_parent3); +DEFINE_EXPECT(cmdtarget_Exec); static HWND container_hwnd = NULL; static IHTMLWindow2 *window; @@ -166,6 +177,14 @@ static const char input_doc_str[] = static const char iframe_doc_str[] = ""; +static const char iframe_doc_ie9_str[] = + "" + ""; + +static const char iframe_doc_ie11_str[] = + "" + ""; + static void navigate(IHTMLDocument2*,const WCHAR*); static BOOL iface_cmp(IUnknown *iface1, IUnknown *iface2) @@ -1478,6 +1497,80 @@ static HRESULT WINAPI iframe_onreadystatechange(IDispatchEx *iface, DISPID id, L EVENT_HANDLER_FUNC_OBJ(iframe_onreadystatechange); +static IHTMLWindow2 *onmessage_source; + +static HRESULT WINAPI onmessage(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + IHTMLWindow2 *source, *self; + HRESULT hres; + BSTR bstr; + + CHECK_EXPECT(onmessage); + + if(document_mode < 9) { + IHTMLEventObj5 *event_obj5; + IHTMLEventObj *event_obj; + IDispatch *disp; + + hres = IHTMLWindow2_get_event(window, &event_obj); + ok(hres == S_OK, "get_event failed: %08lx\n", hres); + + hres = IHTMLEventObj_get_type(event_obj, &bstr); + ok(hres == S_OK, "get_type failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"message"), "event type = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + hres = IHTMLEventObj_QueryInterface(event_obj, &IID_IHTMLEventObj5, (void**)&event_obj5); + ok(hres == S_OK, "Could not get IHTMLEventObj5: %08lx\n", hres); + IHTMLEventObj_Release(event_obj); + + hres = IHTMLEventObj5_get_url(event_obj5, &bstr); + ok(hres == S_OK, "get_url failed: %08lx\n", hres); + ok(!bstr, "url = %s\n", wine_dbgstr_w(bstr)); + + hres = IHTMLEventObj5_get_source(event_obj5, &disp); + ok(hres == S_OK, "get_source failed: %08lx\n", hres); + + hres = IDispatch_QueryInterface(disp, &IID_IHTMLWindow2, (void**)&source); + ok(hres == S_OK, "Could not get IHTMLWindow2: %08lx\n", hres); + IDispatch_Release(disp); + + hres = IHTMLWindow2_get_self(onmessage_source, &self); + ok(hres == S_OK, "get_self failed: %08lx\n", hres); + ok(source == self, "source != onmessage_source.self\n"); + IHTMLWindow2_Release(source); + IHTMLWindow2_Release(self); + + bstr = SysAllocString(L"foobar"); + hres = IHTMLEventObj5_put_url(event_obj5, bstr); + ok(hres == DISP_E_MEMBERNOTFOUND, "put_url returned: %08lx\n", hres); + SysFreeString(bstr); + + IHTMLEventObj5_Release(event_obj5); + }else { + IDOMMessageEvent *msg; + + hres = IDispatch_QueryInterface(V_DISPATCH(&pdp->rgvarg[1]), &IID_IDOMMessageEvent, (void**)&msg); + ok(hres == S_OK, "Could not get IDOMMessageEvent: %08lx\n", hres); + + hres = IDOMMessageEvent_get_data(msg, &bstr); + ok(hres == S_OK, "get_data failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"foobar"), "data = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + hres = IDOMMessageEvent_get_source(msg, &source); + ok(hres == S_OK, "get_source failed: %08lx\n", hres); + ok(source == onmessage_source, "source != onmessage_source\n"); + IHTMLWindow2_Release(source); + + IDOMMessageEvent_Release(msg); + } + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(onmessage); + static HRESULT WINAPI onvisibilitychange(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { @@ -1883,6 +1976,359 @@ static void pump_msgs(BOOL *b) } } +static IOleCommandTarget cmdtarget, cmdtarget_stub; + +static HRESULT WINAPI cmdtarget_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IOleCommandTarget)) + *ppv = &cmdtarget; + else { + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static ULONG WINAPI cmdtarget_AddRef(IOleCommandTarget *iface) +{ + return 2; +} + +static ULONG WINAPI cmdtarget_Release(IOleCommandTarget *iface) +{ + return 1; +} + +static HRESULT WINAPI cmdtarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup, + ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText) +{ + ok(0, "unexpected call\n"); + return OLECMDERR_E_UNKNOWNGROUP; +} + +static HRESULT WINAPI cmdtarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup, + DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) +{ + CHECK_EXPECT2(cmdtarget_Exec); + ok(pguidCmdGroup && IsEqualGUID(pguidCmdGroup, &CGID_ScriptSite), "pguidCmdGroup = %s\n", wine_dbgstr_guid(pguidCmdGroup)); + ok(nCmdID == CMDID_SCRIPTSITE_SECURITY_WINDOW, "nCmdID = %lu\n", nCmdID); + ok(!nCmdexecopt, "nCmdexecopt = %lu\n", nCmdexecopt); + ok(!pvaIn, "pvaIn != NULL\n"); + ok(pvaOut != NULL, "pvaOut = NULL\n"); + + /* Native ignores the VT and assumes VT_DISPATCH, and releases it + without VariantClear, since it crashes without AddRef below... */ + V_VT(pvaOut) = VT_NULL; + V_DISPATCH(pvaOut) = (IDispatch*)onmessage_source; + IDispatch_AddRef(V_DISPATCH(pvaOut)); + return S_OK; +} + +static const IOleCommandTargetVtbl cmdtarget_vtbl = { + cmdtarget_QueryInterface, + cmdtarget_AddRef, + cmdtarget_Release, + cmdtarget_QueryStatus, + cmdtarget_Exec +}; + +static IOleCommandTarget cmdtarget = { &cmdtarget_vtbl }; + +static HRESULT WINAPI cmdtarget_stub_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IOleCommandTarget)) + *ppv = &cmdtarget_stub; + else { + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static HRESULT WINAPI cmdtarget_stub_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup, + ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText) +{ + ok(0, "unexpected call\n"); + return OLECMDERR_E_UNKNOWNGROUP; +} + +static HRESULT WINAPI cmdtarget_stub_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup, + DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) +{ + ok(0, "unexpected call\n"); + return OLECMDERR_E_UNKNOWNGROUP; +} + +static const IOleCommandTargetVtbl cmdtarget_stub_vtbl = { + cmdtarget_stub_QueryInterface, + cmdtarget_AddRef, + cmdtarget_Release, + cmdtarget_stub_QueryStatus, + cmdtarget_stub_Exec +}; + +static IOleCommandTarget cmdtarget_stub = { &cmdtarget_stub_vtbl }; + +static IServiceProvider caller_sp, caller_sp_parent, caller_sp_stub, caller_sp2, caller_sp2_parent, caller_sp2_parent3; + +static HRESULT WINAPI caller_sp_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) + *ppv = &caller_sp; + else { + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static ULONG WINAPI caller_sp_AddRef(IServiceProvider *iface) +{ + return 2; +} + +static ULONG WINAPI caller_sp_Release(IServiceProvider *iface) +{ + return 1; +} + +static HRESULT WINAPI caller_sp_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + if(IsEqualGUID(guidService, &IID_IActiveScriptSite)) { + CHECK_EXPECT2(QS_IActiveScriptSite); + ok(IsEqualGUID(riid, &IID_IOleCommandTarget), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = (document_mode < 9) ? NULL : &cmdtarget; + return (document_mode < 9) ? E_NOINTERFACE : S_OK; + } + + if(IsEqualGUID(guidService, &SID_GetCaller)) { + CHECK_EXPECT(QS_GetCaller); + SET_EXPECT(QS_IActiveScriptSite_parent); + ok(IsEqualGUID(riid, &IID_IServiceProvider), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = &caller_sp_parent; + return S_OK; + } + + ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl caller_sp_vtbl = { + caller_sp_QueryInterface, + caller_sp_AddRef, + caller_sp_Release, + caller_sp_QueryService +}; + +static IServiceProvider caller_sp = { &caller_sp_vtbl }; + +static HRESULT WINAPI caller_sp_parent_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) + *ppv = &caller_sp_parent; + else { + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static HRESULT WINAPI caller_sp_parent_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + if(IsEqualGUID(guidService, &IID_IActiveScriptSite)) { + CHECK_EXPECT(QS_IActiveScriptSite_parent); + ok(IsEqualGUID(riid, &IID_IOleCommandTarget), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + + ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl caller_sp_parent_vtbl = { + caller_sp_parent_QueryInterface, + caller_sp_AddRef, + caller_sp_Release, + caller_sp_parent_QueryService +}; + +static IServiceProvider caller_sp_parent = { &caller_sp_parent_vtbl }; + +static HRESULT WINAPI caller_sp_stub_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) + *ppv = &caller_sp_stub; + else { + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static HRESULT WINAPI caller_sp_stub_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + if(IsEqualGUID(guidService, &IID_IActiveScriptSite)) { + CHECK_EXPECT2(QS_IActiveScriptSite); + *ppv = NULL; + return E_NOINTERFACE; + } + + if(IsEqualGUID(guidService, &SID_GetCaller)) { + CHECK_EXPECT(QS_GetCaller); + ok(IsEqualGUID(riid, &IID_IServiceProvider), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return S_OK; + } + + ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl caller_sp_stub_vtbl = { + caller_sp_stub_QueryInterface, + caller_sp_AddRef, + caller_sp_Release, + caller_sp_stub_QueryService +}; + +static IServiceProvider caller_sp_stub = { &caller_sp_stub_vtbl }; + +static HRESULT WINAPI caller_sp2_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) + *ppv = &caller_sp2; + else { + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static HRESULT WINAPI caller_sp2_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + if(IsEqualGUID(guidService, &IID_IActiveScriptSite)) { + CHECK_EXPECT2(QS_IActiveScriptSite_parent2); + ok(IsEqualGUID(riid, &IID_IOleCommandTarget), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = (document_mode < 9) ? &cmdtarget_stub : &cmdtarget; + return S_OK; + } + + if(IsEqualGUID(guidService, &SID_GetCaller)) { + CHECK_EXPECT(QS_GetCaller_parent2); + SET_EXPECT(QS_IActiveScriptSite_parent3); + ok(IsEqualGUID(riid, &IID_IServiceProvider), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = &caller_sp2_parent; + return S_OK; + } + + ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl caller_sp2_vtbl = { + caller_sp2_QueryInterface, + caller_sp_AddRef, + caller_sp_Release, + caller_sp2_QueryService +}; + +static IServiceProvider caller_sp2 = { &caller_sp2_vtbl }; + +static HRESULT WINAPI caller_sp2_parent_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) + *ppv = &caller_sp2_parent; + else { + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static HRESULT WINAPI caller_sp2_parent_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + if(IsEqualGUID(guidService, &IID_IActiveScriptSite)) { + CHECK_EXPECT2(QS_IActiveScriptSite_parent3); + ok(IsEqualGUID(riid, &IID_IOleCommandTarget), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = &cmdtarget; + return S_OK; + } + + if(IsEqualGUID(guidService, &SID_GetCaller)) { + CHECK_EXPECT(QS_GetCaller_parent3); + SET_EXPECT(QS_IActiveScriptSite_parent4); + ok(IsEqualGUID(riid, &IID_IServiceProvider), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = &caller_sp2_parent3; + return S_OK; + } + + ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl caller_sp2_parent_vtbl = { + caller_sp2_parent_QueryInterface, + caller_sp_AddRef, + caller_sp_Release, + caller_sp2_parent_QueryService +}; + +static IServiceProvider caller_sp2_parent = { &caller_sp2_parent_vtbl }; + +static HRESULT WINAPI caller_sp2_parent3_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) +{ + if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) + *ppv = &caller_sp2_parent3; + else { + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + +static HRESULT WINAPI caller_sp2_parent3_QueryService(IServiceProvider *iface, REFGUID guidService, + REFIID riid, void **ppv) +{ + if(IsEqualGUID(guidService, &IID_IActiveScriptSite)) { + CHECK_EXPECT(QS_IActiveScriptSite_parent4); + ok(IsEqualGUID(riid, &IID_IOleCommandTarget), "unexpected riid %s\n", wine_dbgstr_guid(riid)); + *ppv = NULL; + return S_OK; + } + + ok(0, "unexpected service %s\n", wine_dbgstr_guid(guidService)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static const IServiceProviderVtbl caller_sp2_parent3_vtbl = { + caller_sp2_parent3_QueryInterface, + caller_sp_AddRef, + caller_sp_Release, + caller_sp2_parent3_QueryService +}; + +static IServiceProvider caller_sp2_parent3 = { &caller_sp2_parent3_vtbl }; + static IConnectionPoint *get_cp(IUnknown *unk, REFIID riid) { IConnectionPointContainer *cp_container; @@ -2654,6 +3100,168 @@ static void test_focus(IHTMLDocument2 *doc) IHTMLElement4_Release(div); } +static void test_message_event(IHTMLDocument2 *doc) +{ + IHTMLFrameBase2 *iframe; + DISPPARAMS dp = { 0 }; + IHTMLWindow6 *window6; + IHTMLDocument6 *doc6; + IHTMLElement2 *elem; + IHTMLWindow2 *child; + IDispatchEx *dispex; + LONG ref, ref2; + DISPID dispid; + HRESULT hres; + VARIANT v[2]; + BSTR bstr; + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow6, (void**)&window6); + ok(hres == S_OK, "Could not get IHTMLWindow6 iface: %08lx\n", hres); + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument6, (void**)&doc6); + ok(hres == S_OK, "Could not get IHTMLDocument6 iface: %08lx\n", hres); + bstr = SysAllocString(L"ifr"); + hres = IHTMLDocument6_getElementById(doc6, bstr, &elem); + ok(hres == S_OK, "getElementById failed: %08lx\n", hres); + IHTMLDocument6_Release(doc6); + SysFreeString(bstr); + + hres = IHTMLElement2_QueryInterface(elem, &IID_IHTMLFrameBase2, (void**)&iframe); + ok(hres == S_OK, "Could not get IHTMLFrameBase2 iface: %08lx\n", hres); + IHTMLElement2_Release(elem); + hres = IHTMLFrameBase2_get_contentWindow(iframe, &child); + ok(hres == S_OK, "get_contentWindow failed: %08lx\n", hres); + IHTMLFrameBase2_Release(iframe); + + IHTMLWindow2_AddRef(child); + ref = IHTMLWindow2_Release(child); + + dp.cArgs = 2; + dp.rgvarg = v; + V_VT(&v[0]) = VT_DISPATCH; + V_DISPATCH(&v[0]) = (IDispatch*)&onmessage_obj; + hres = IHTMLWindow6_put_onmessage(window6, v[0]); + ok(hres == S_OK, "put_onmessage failed: %08lx\n", hres); + + V_VT(&v[0]) = VT_EMPTY; + hres = IHTMLWindow6_get_onmessage(window6, &v[0]); + ok(hres == S_OK, "get_onmessage failed: %08lx\n", hres); + ok(V_VT(&v[0]) == VT_DISPATCH, "V_VT(onmessage) = %d\n", V_VT(&v[0])); + ok(V_DISPATCH(&v[0]) == (IDispatch*)&onmessage_obj, "V_DISPATCH(onmessage) = %p\n", V_DISPATCH(&v[0])); + + if(document_mode >= 9) + add_event_listener((IUnknown*)doc, L"message", (IDispatch*)&onmessage_obj, VARIANT_TRUE); + + V_VT(&v[1]) = VT_BSTR; + V_BSTR(&v[1]) = SysAllocString(L"foobar"); + V_VT(&v[0]) = VT_BSTR; + V_BSTR(&v[0]) = SysAllocString(L"*"); + bstr = SysAllocString(L"foobar"); + hres = IHTMLWindow6_postMessage(window6, V_BSTR(&v[1]), v[0]); + ok(hres == E_ABORT, "postMessage returned: %08lx\n", hres); + IHTMLWindow6_Release(window6); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx iface: %08lx\n", hres); + + bstr = SysAllocString(L"postMessage"); + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &dispid); + ok(hres == S_OK, "GetDispID(postMessage) failed: %08lx\n", hres); + SysFreeString(bstr); + + onmessage_source = window; + hres = IDispatchEx_InvokeEx(dispex, dispid, 0, DISPATCH_METHOD, &dp, NULL, NULL, NULL); + ok(hres == (document_mode < 9 ? E_ABORT : S_OK), "InvokeEx(postMessage) returned: %08lx\n", hres); + if(hres == S_OK) { + SET_EXPECT(onmessage); + pump_msgs(&called_onmessage); + CHECK_CALLED(onmessage); + } + + if(document_mode < 9) + SET_EXPECT(QS_GetCaller); + SET_EXPECT(QS_IActiveScriptSite); + hres = IDispatchEx_InvokeEx(dispex, dispid, 0, DISPATCH_METHOD, &dp, NULL, NULL, &caller_sp_stub); + ok(hres == (document_mode < 9 ? E_ABORT : S_OK), "InvokeEx(postMessage) returned: %08lx\n", hres); + CHECK_CALLED(QS_IActiveScriptSite); + if(document_mode < 9) + CHECK_CALLED(QS_GetCaller); + else { + SET_EXPECT(onmessage); + pump_msgs(&called_onmessage); + CHECK_CALLED(onmessage); + } + + onmessage_source = child; + if(document_mode < 9) { + SET_EXPECT(QS_GetCaller); + SET_EXPECT(QS_IActiveScriptSite_parent); + }else { + SET_EXPECT(cmdtarget_Exec); + } + SET_EXPECT(QS_IActiveScriptSite); + hres = IDispatchEx_InvokeEx(dispex, dispid, 0, DISPATCH_METHOD, &dp, NULL, NULL, &caller_sp); + ok(hres == (document_mode < 9 ? E_ABORT : S_OK), "InvokeEx(postMessage) failed: %08lx\n", hres); + CHECK_CALLED(QS_IActiveScriptSite); + if(hres == S_OK) { + CHECK_CALLED(cmdtarget_Exec); + SET_EXPECT(onmessage); + pump_msgs(&called_onmessage); + CHECK_CALLED(onmessage); + } + + if(document_mode < 9) { + SET_EXPECT(QS_GetCaller_parent2); + SET_EXPECT(onmessage); + } + SET_EXPECT(QS_IActiveScriptSite_parent2); + SET_EXPECT(cmdtarget_Exec); + hres = IDispatchEx_InvokeEx(dispex, dispid, 0, DISPATCH_METHOD, &dp, NULL, NULL, &caller_sp2); + ok(hres == S_OK, "InvokeEx(postMessage) failed: %08lx\n", hres); + CHECK_CALLED(cmdtarget_Exec); + CHECK_CALLED(QS_IActiveScriptSite_parent2); + if(document_mode < 9) { + CHECK_CALLED(QS_IActiveScriptSite_parent3); + CHECK_CALLED(QS_GetCaller_parent2); + CHECK_CALLED(onmessage); + pump_msgs(NULL); + }else { + SET_EXPECT(onmessage); + pump_msgs(&called_onmessage); + CHECK_CALLED(onmessage); + } + + if(document_mode < 9) { + SET_EXPECT(QS_GetCaller_parent3); + SET_EXPECT(onmessage); + } + SET_EXPECT(QS_IActiveScriptSite_parent3); + SET_EXPECT(cmdtarget_Exec); + hres = IDispatchEx_InvokeEx(dispex, dispid, 0, DISPATCH_METHOD, &dp, NULL, NULL, &caller_sp2_parent); + ok(hres == S_OK, "InvokeEx(postMessage) failed: %08lx\n", hres); + CHECK_CALLED(cmdtarget_Exec); + CHECK_CALLED(QS_IActiveScriptSite_parent3); + if(document_mode < 9) { + CHECK_CALLED(QS_IActiveScriptSite_parent4); + CHECK_CALLED(QS_GetCaller_parent3); + CHECK_CALLED(onmessage); + pump_msgs(NULL); + }else { + SET_EXPECT(onmessage); + pump_msgs(&called_onmessage); + CHECK_CALLED(onmessage); + } + + onmessage_source = NULL; + VariantClear(&v[0]); + VariantClear(&v[1]); + IDispatchEx_Release(dispex); + + ref2 = IHTMLWindow2_Release(child); + if(document_mode < 9) + ok(ref2 == ref - 1, "ref = %ld, expected %ld\n", ref2, ref - 1); +} + static void test_visibilitychange(IHTMLDocument2 *doc) { if(!winetest_interactive) { @@ -6251,10 +6859,13 @@ START_TEST(events) run_test(input_doc_str, test_focus); run_test(empty_doc_str, test_submit); run_test(empty_doc_ie9_str, test_submit); + run_test(iframe_doc_str, test_message_event); run_test(iframe_doc_str, test_iframe_connections); if(is_ie9plus) { run_test_from_res(L"doc_with_prop.html", test_doc_obj); run_test_from_res(L"doc_with_prop_ie9.html", test_doc_obj); + run_test(iframe_doc_ie9_str, test_message_event); + run_test(iframe_doc_ie11_str, test_message_event); run_test_from_res(L"doc_with_prop_ie9.html", test_visibilitychange); run_test_from_res(L"blank_ie10.html", test_visibilitychange); run_test_from_res(L"iframe.html", test_unload_event); diff --git a/dlls/mshtml/tests/events.js b/dlls/mshtml/tests/events.js index 3b29798e9a1..f44cf5da610 100644 --- a/dlls/mshtml/tests/events.js +++ b/dlls/mshtml/tests/events.js @@ -824,14 +824,23 @@ async_test("img_wrong_content_type", function() { }); async_test("message event", function() { - var listener_called = false; + var listener_called = false, iframe = document.createElement("iframe"); window.addEventListener("message", function(e) { + if(listener_called) { + ok(e.data === "foobar", "e.data (diff origin) = " + e.data); + ok(e.source === iframe.contentWindow, "e.source (diff origin) not iframe.contentWindow"); + next_test(); + return; + } listener_called = true; ok(e.data === "test", "e.data = " + e.data); ok(e.bubbles === false, "bubbles = " + e.bubbles); ok(e.cancelable === false, "cancelable = " + e.cancelable); - next_test(); + ok(e.source === window, "e.source = " + e.source); + + iframe.src = "http://winetest.different.org:1234/send2parent.html"; + document.body.appendChild(iframe); }); window.postMessage("test", "httP://wineTest.example.org"); diff --git a/dlls/mshtml/tests/rsrc.rc b/dlls/mshtml/tests/rsrc.rc index 10b92ab78cb..9932e559eaf 100644 --- a/dlls/mshtml/tests/rsrc.rc +++ b/dlls/mshtml/tests/rsrc.rc @@ -88,6 +88,9 @@ doc_with_prop_ie9.html HTML "doc_with_prop_ie9.html" /* @makedep: iframe.html */ iframe.html HTML "iframe.html" +/* @makedep: send2parent.html */ +send2parent.html HTML "send2parent.html" + /* For res: protocol test: */ /* @makedep: jstest.html */ diff --git a/dlls/mshtml/tests/send2parent.html b/dlls/mshtml/tests/send2parent.html new file mode 100644 index 00000000000..4be6540726f --- /dev/null +++ b/dlls/mshtml/tests/send2parent.html @@ -0,0 +1,3 @@ + From 4f74241650caa044f70d1e5515d61f1b343c72ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:58 +0200 Subject: [PATCH 0841/2777] mshtml: Implement `data` getter for MessageEvent objs. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlevent.c | 14 +++++++++++--- dlls/mshtml/tests/events.c | 5 +++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index f01d55bd31c..fce129daa0a 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -1874,11 +1874,19 @@ static HRESULT WINAPI HTMLEventObj5_put_data(IHTMLEventObj5 *iface, BSTR v) static HRESULT WINAPI HTMLEventObj5_get_data(IHTMLEventObj5 *iface, BSTR *p) { HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + IDOMMessageEvent *message_event; + HRESULT hres; - FIXME("(%p)->(%p)\n", This, p); + TRACE("(%p)->(%p)\n", This, p); - *p = NULL; - return S_OK; + if(!This->event || FAILED(IDOMEvent_QueryInterface(&This->event->IDOMEvent_iface, &IID_IDOMMessageEvent, (void**)&message_event))) { + *p = NULL; + return S_OK; + } + + hres = IDOMMessageEvent_get_data(message_event, p); + IDOMMessageEvent_Release(message_event); + return hres; } static HRESULT WINAPI HTMLEventObj5_get_source(IHTMLEventObj5 *iface, IDispatch **p) diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index f2e735fabde..c902f16efcd 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -1529,6 +1529,11 @@ static HRESULT WINAPI onmessage(IDispatchEx *iface, DISPID id, LCID lcid, WORD w ok(hres == S_OK, "get_url failed: %08lx\n", hres); ok(!bstr, "url = %s\n", wine_dbgstr_w(bstr)); + hres = IHTMLEventObj5_get_data(event_obj5, &bstr); + ok(hres == S_OK, "get_data failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"foobar"), "data = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + hres = IHTMLEventObj5_get_source(event_obj5, &disp); ok(hres == S_OK, "get_source failed: %08lx\n", hres); From 12b4c49db75327def3b69d0b62474e1bba519b08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:58 +0200 Subject: [PATCH 0842/2777] mshtml: Implement `origin` prop for MessageEvents. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlevent.c | 63 ++++++++++++++++++++++++++++--- dlls/mshtml/tests/documentmode.js | 1 + dlls/mshtml/tests/events.c | 13 +++++++ dlls/mshtml/tests/events.js | 2 + 4 files changed, 73 insertions(+), 6 deletions(-) diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index fce129daa0a..4c84ae5917c 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -1919,11 +1919,19 @@ static HRESULT WINAPI HTMLEventObj5_put_origin(IHTMLEventObj5 *iface, BSTR v) static HRESULT WINAPI HTMLEventObj5_get_origin(IHTMLEventObj5 *iface, BSTR *p) { HTMLEventObj *This = impl_from_IHTMLEventObj5(iface); + IDOMMessageEvent *message_event; + HRESULT hres; - FIXME("(%p)->(%p)\n", This, p); + TRACE("(%p)->(%p)\n", This, p); - *p = NULL; - return S_OK; + if(!This->event || FAILED(IDOMEvent_QueryInterface(&This->event->IDOMEvent_iface, &IID_IDOMMessageEvent, (void**)&message_event))) { + *p = NULL; + return S_OK; + } + + hres = IDOMMessageEvent_get_origin(message_event, p); + IDOMMessageEvent_Release(message_event); + return hres; } static HRESULT WINAPI HTMLEventObj5_put_issession(IHTMLEventObj5 *iface, VARIANT_BOOL v) @@ -3611,6 +3619,7 @@ typedef struct { DOMEvent event; IDOMMessageEvent IDOMMessageEvent_iface; IHTMLWindow2 *source; + BSTR origin; VARIANT data; } DOMMessageEvent; @@ -3698,8 +3707,14 @@ static HRESULT DOMMessageEvent_get_data_hook(DispatchEx *dispex, WORD flags, DIS static HRESULT WINAPI DOMMessageEvent_get_origin(IDOMMessageEvent *iface, BSTR *p) { DOMMessageEvent *This = impl_from_IDOMMessageEvent(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + if(This->origin) + return (*p = SysAllocStringLen(This->origin, SysStringLen(This->origin))) ? S_OK : E_OUTOFMEMORY; + + *p = NULL; + return S_OK; } static HRESULT WINAPI DOMMessageEvent_get_source(IDOMMessageEvent *iface, IHTMLWindow2 **p) @@ -3755,6 +3770,7 @@ static void DOMMessageEvent_destroy(DOMEvent *event) DOMMessageEvent *message_event = DOMMessageEvent_from_DOMEvent(event); if(message_event->source) IHTMLWindow2_Release(message_event->source); + SysFreeString(message_event->origin); VariantClear(&message_event->data); } @@ -4439,21 +4455,56 @@ HRESULT create_document_event(HTMLDocumentNode *doc, eventid_t event_id, DOMEven HRESULT create_message_event(HTMLDocumentNode *doc, IHTMLWindow2 *source, VARIANT *data, DOMEvent **ret) { DOMMessageEvent *message_event; + BSTR bstr, origin = NULL; + IHTMLLocation *location; DOMEvent *event; HRESULT hres; + UINT len; - hres = create_document_event(doc, EVENTID_MESSAGE, &event); + hres = IHTMLWindow2_get_location(source, &location); + if(FAILED(hres)) + return hres; + + hres = IHTMLLocation_get_protocol(location, &bstr); + if(FAILED(hres)) { + IHTMLLocation_Release(location); + return hres; + } + len = SysStringLen(bstr); + SysFreeString(bstr); + + hres = IHTMLLocation_get_href(location, &bstr); + IHTMLLocation_Release(location); if(FAILED(hres)) return hres; + if(bstr) { + static const WCHAR delims[] = L"/\\"; + + if(bstr[len] == '/' && bstr[len + 1] == '/') + len += 2 + wcscspn(bstr + len + 2, delims); + + origin = SysAllocStringLen(bstr, len); + SysFreeString(bstr); + if(!origin) + return E_OUTOFMEMORY; + } + + hres = create_document_event(doc, EVENTID_MESSAGE, &event); + if(FAILED(hres)) { + SysFreeString(origin); + return hres; + } message_event = DOMMessageEvent_from_DOMEvent(event); V_VT(&message_event->data) = VT_EMPTY; hres = VariantCopy(&message_event->data, data); if(FAILED(hres)) { IDOMEvent_Release(&event->IDOMEvent_iface); + SysFreeString(origin); return hres; } + message_event->origin = origin; message_event->source = source; IHTMLWindow2_AddRef(message_event->source); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 9b1461e4f5c..d3cf8cb30b2 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -2588,6 +2588,7 @@ async_test("postMessage", function() { else { ok(e.data === (v < 10 ? "10" : 10), "e.data = " + e.data); ok(e.source === window, "e.source = " + e.source); + ok(e.origin === "http://winetest.example.org", "e.origin = " + e.origin); next_test(); } } diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index c902f16efcd..80a64c1a346 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -1534,6 +1534,11 @@ static HRESULT WINAPI onmessage(IDispatchEx *iface, DISPID id, LCID lcid, WORD w ok(!wcscmp(bstr, L"foobar"), "data = %s\n", wine_dbgstr_w(bstr)); SysFreeString(bstr); + hres = IHTMLEventObj5_get_origin(event_obj5, &bstr); + ok(hres == S_OK, "get_origin failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"about:"), "origin = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + hres = IHTMLEventObj5_get_source(event_obj5, &disp); ok(hres == S_OK, "get_source failed: %08lx\n", hres); @@ -1550,6 +1555,9 @@ static HRESULT WINAPI onmessage(IDispatchEx *iface, DISPID id, LCID lcid, WORD w bstr = SysAllocString(L"foobar"); hres = IHTMLEventObj5_put_url(event_obj5, bstr); ok(hres == DISP_E_MEMBERNOTFOUND, "put_url returned: %08lx\n", hres); + + hres = IHTMLEventObj5_put_origin(event_obj5, bstr); + ok(hres == DISP_E_MEMBERNOTFOUND, "put_origin returned: %08lx\n", hres); SysFreeString(bstr); IHTMLEventObj5_Release(event_obj5); @@ -1564,6 +1572,11 @@ static HRESULT WINAPI onmessage(IDispatchEx *iface, DISPID id, LCID lcid, WORD w ok(!wcscmp(bstr, L"foobar"), "data = %s\n", wine_dbgstr_w(bstr)); SysFreeString(bstr); + hres = IDOMMessageEvent_get_origin(msg, &bstr); + ok(hres == S_OK, "get_origin failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"about:"), "origin = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + hres = IDOMMessageEvent_get_source(msg, &source); ok(hres == S_OK, "get_source failed: %08lx\n", hres); ok(source == onmessage_source, "source != onmessage_source\n"); diff --git a/dlls/mshtml/tests/events.js b/dlls/mshtml/tests/events.js index f44cf5da610..1247c65e5bd 100644 --- a/dlls/mshtml/tests/events.js +++ b/dlls/mshtml/tests/events.js @@ -830,6 +830,7 @@ async_test("message event", function() { if(listener_called) { ok(e.data === "foobar", "e.data (diff origin) = " + e.data); ok(e.source === iframe.contentWindow, "e.source (diff origin) not iframe.contentWindow"); + ok(e.origin === "http://winetest.different.org:1234", "e.origin (diff origin) = " + e.origin); next_test(); return; } @@ -838,6 +839,7 @@ async_test("message event", function() { ok(e.bubbles === false, "bubbles = " + e.bubbles); ok(e.cancelable === false, "cancelable = " + e.cancelable); ok(e.source === window, "e.source = " + e.source); + ok(e.origin === "http://winetest.example.org", "e.origin = " + e.origin); iframe.src = "http://winetest.different.org:1234/send2parent.html"; document.body.appendChild(iframe); From 106f1cd06aa7ee1a3e39679381a5de47bce235d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:58 +0200 Subject: [PATCH 0843/2777] mshtml: Implement `initMessageEvent` for MessageEvents. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlevent.c | 48 ++++++++++- dlls/mshtml/tests/documentmode.js | 29 +++++++ dlls/mshtml/tests/events.c | 130 ++++++++++++++++++++++++++++++ dlls/mshtml/tests/events.js | 1 + 4 files changed, 206 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 4c84ae5917c..c3b279d809a 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -3682,6 +3682,11 @@ static HRESULT WINAPI DOMMessageEvent_get_data(IDOMMessageEvent *iface, BSTR *p) TRACE("(%p)->(%p)\n", This, p); + if(V_VT(&This->data) == VT_EMPTY) { + *p = SysAllocString(L""); + return S_OK; + } + if(V_VT(&This->data) != VT_BSTR) { FIXME("non-string data\n"); return E_NOTIMPL; @@ -3733,9 +3738,48 @@ static HRESULT WINAPI DOMMessageEvent_initMessageEvent(IDOMMessageEvent *iface, BSTR last_event_id, IHTMLWindow2 *source) { DOMMessageEvent *This = impl_from_IDOMMessageEvent(iface); - FIXME("(%p)->(%s %x %x %s %s %s %p)\n", This, debugstr_w(type), can_bubble, cancelable, + BSTR new_origin = NULL; + BSTR new_data = NULL; + HRESULT hres; + + TRACE("(%p)->(%s %x %x %s %s %s %p)\n", This, debugstr_w(type), can_bubble, cancelable, debugstr_w(data), debugstr_w(origin), debugstr_w(last_event_id), source); - return E_NOTIMPL; + + if(This->event.target) { + TRACE("called on already dispatched event\n"); + return S_OK; + } + + if((data && !(new_data = SysAllocString(data))) || + (origin && !(new_origin = SysAllocString(origin)))) { + hres = E_OUTOFMEMORY; + goto fail; + } + + hres = IDOMEvent_initEvent(&This->event.IDOMEvent_iface, type, can_bubble, cancelable); + if(FAILED(hres)) + goto fail; + + if(new_data) { + VariantClear(&This->data); + V_VT(&This->data) = VT_BSTR; + V_BSTR(&This->data) = new_data; + } + if(new_origin) { + SysFreeString(This->origin); + This->origin = new_origin; + } + if(This->source) + IHTMLWindow2_Release(This->source); + This->source = source; + if(source) + IHTMLWindow2_AddRef(source); + return S_OK; + +fail: + SysFreeString(new_origin); + SysFreeString(new_data); + return hres; } static const IDOMMessageEventVtbl DOMMessageEventVtbl = { diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index d3cf8cb30b2..4bb09616407 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -2578,6 +2578,32 @@ sync_test("__defineSetter__", function() { ok(x.setterVal === 9, "x.setterVal after setting bar = " + x.setterVal); }); +sync_test("initMessageEvent", function() { + var e, v = document.documentMode; + if(!document.createEvent) + return; + e = document.createEvent("MessageEvent"); + ok(e.data === (v < 10 ? "" : undefined), "e.data = " + e.data); + ok(e.bubbles === false, "bubbles = " + e.bubbles); + ok(e.cancelable === false, "cancelable = " + e.cancelable); + ok(e.source === null, "e.source = " + e.source); + ok(e.origin === "", "e.origin = " + e.origin); + + e.initMessageEvent("blah", true, true, 137, "wine", 1234, window); + ok(e.data === "137", "e.data = " + e.data); + ok(e.bubbles === true, "bubbles = " + e.bubbles); + ok(e.cancelable === true, "cancelable = " + e.cancelable); + ok(e.source === window, "e.source = " + e.source); + ok(e.origin === "wine", "e.origin = " + e.origin); + + e.initMessageEvent("abcd", false, false, "testdata", "origin", 42, null); + ok(e.data === "testdata", "e.data = " + e.data); + ok(e.bubbles === false, "bubbles = " + e.bubbles); + ok(e.cancelable === false, "cancelable = " + e.cancelable); + ok(e.source === null, "e.source = " + e.source); + ok(e.origin === "origin", "e.origin = " + e.origin); +}); + async_test("postMessage", function() { var v = document.documentMode; var onmessage_called = false; @@ -2589,6 +2615,9 @@ async_test("postMessage", function() { ok(e.data === (v < 10 ? "10" : 10), "e.data = " + e.data); ok(e.source === window, "e.source = " + e.source); ok(e.origin === "http://winetest.example.org", "e.origin = " + e.origin); + + e = document.createEvent("MessageEvent"); + ok(e.data === (v < 10 ? "" : undefined), "created e.data = " + e.data); next_test(); } } diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 80a64c1a346..f515d607ad0 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -3278,6 +3278,136 @@ static void test_message_event(IHTMLDocument2 *doc) ref2 = IHTMLWindow2_Release(child); if(document_mode < 9) ok(ref2 == ref - 1, "ref = %ld, expected %ld\n", ref2, ref - 1); + + if(document_mode >= 9) { + IDOMMessageEvent *msg_event = NULL; + IDocumentEvent *doc_event; + IHTMLWindow2 *source; + IDOMEvent *event; + UINT argerr; + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IDocumentEvent, (void**)&doc_event); + ok(hres == S_OK, "Could not get IDocumentEvent iface: %08lx\n", hres); + + bstr = SysAllocString(L"MessageEvent"); + hres = IDocumentEvent_createEvent(doc_event, bstr, &event); + ok(hres == S_OK, "createEvent failed: %08lx\n", hres); + IDocumentEvent_Release(doc_event); + SysFreeString(bstr); + + hres = IDOMEvent_QueryInterface(event, &IID_IDOMMessageEvent, (void**)&msg_event); + ok(hres == S_OK, "Could not get IDOMMessageEvent iface: %08lx\n", hres); + ok(msg_event != NULL, "msg_event = NULL\n"); + IDOMEvent_Release(event); + + hres = IDOMMessageEvent_get_source(msg_event, &source); + ok(hres == S_OK, "get_source failed: %08lx\n", hres); + ok(source == NULL, "uninitialized source != NULL\n"); + + hres = IDOMMessageEvent_get_origin(msg_event, &bstr); + ok(hres == S_OK, "get_origin failed: %08lx\n", hres); + ok(!bstr, "uninitialized origin = %s\n", wine_dbgstr_w(bstr)); + + /* IE10+ crash when using the get_data from the interface (because it's not a string yet?) */ + if(document_mode < 10) { + hres = IDOMMessageEvent_get_data(msg_event, &bstr); + ok(hres == S_OK, "get_data failed: %08lx\n", hres); + ok(!wcscmp(bstr, L""), "uninitialized data = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + bstr = SysAllocString(L"foobar"); + hres = IDOMMessageEvent_initMessageEvent(msg_event, bstr, VARIANT_FALSE, VARIANT_FALSE, bstr, bstr, NULL, window); + ok(hres == S_OK, "initMessageEvent failed: %08lx\n", hres); + SysFreeString(bstr); + + hres = IDOMMessageEvent_get_data(msg_event, &bstr); + ok(hres == S_OK, "get_data failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"foobar"), "data = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + hres = IDOMMessageEvent_get_source(msg_event, &source); + ok(hres == S_OK, "get_source failed: %08lx\n", hres); + ok(source == window, "source != window\n"); + IHTMLWindow2_Release(source); + + hres = IDOMMessageEvent_get_origin(msg_event, &bstr); + ok(hres == S_OK, "get_origin failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"foobar"), "origin = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + bstr = SysAllocString(L"barfoo"); + hres = IDOMMessageEvent_initMessageEvent(msg_event, bstr, VARIANT_FALSE, VARIANT_FALSE, NULL, NULL, NULL, NULL); + ok(hres == S_OK, "initMessageEvent failed: %08lx\n", hres); + SysFreeString(bstr); + + hres = IDOMMessageEvent_get_data(msg_event, &bstr); + ok(hres == S_OK, "get_data failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"foobar"), "data = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + hres = IDOMMessageEvent_get_source(msg_event, &source); + ok(hres == S_OK, "get_source failed: %08lx\n", hres); + ok(source == NULL, "source != NULL\n"); + + hres = IDOMMessageEvent_get_origin(msg_event, &bstr); + ok(hres == S_OK, "get_origin failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"foobar"), "origin = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + }else { + bstr = SysAllocString(L"data"); + hres = IDOMMessageEvent_GetIDsOfNames(msg_event, &IID_NULL, &bstr, 1, 0, &dispid); + ok(hres == S_OK, "GetIDsOfNames(data) failed: %08lx\n", hres); + SysFreeString(bstr); + + dp.cArgs = 0; + dp.rgvarg = NULL; + hres = IDOMMessageEvent_Invoke(msg_event, dispid, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &v[0], NULL, &argerr); + ok(hres == S_OK, "Invoke(data) failed: %08lx\n", hres); + ok(V_VT(&v[0]) == VT_EMPTY, "V_VT(uninitialized data) = %d\n", V_VT(&v[0])); + + bstr = SysAllocString(L"foobar"); + hres = IDOMMessageEvent_initMessageEvent(msg_event, bstr, VARIANT_FALSE, VARIANT_FALSE, bstr, bstr, NULL, window); + ok(hres == S_OK, "initMessageEvent failed: %08lx\n", hres); + SysFreeString(bstr); + + hres = IDOMMessageEvent_Invoke(msg_event, dispid, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &v[0], NULL, &argerr); + ok(hres == S_OK, "Invoke(data) failed: %08lx\n", hres); + ok(V_VT(&v[0]) == VT_BSTR, "V_VT(data) = %d\n", V_VT(&v[0])); + ok(!wcscmp(V_BSTR(&v[0]), L"foobar"), "V_BSTR(data) = %s\n", wine_dbgstr_w(V_BSTR(&v[0]))); + VariantClear(&v[0]); + + hres = IDOMMessageEvent_get_source(msg_event, &source); + ok(hres == S_OK, "get_source failed: %08lx\n", hres); + ok(source == window, "source != window\n"); + IHTMLWindow2_Release(source); + + hres = IDOMMessageEvent_get_origin(msg_event, &bstr); + ok(hres == S_OK, "get_origin failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"foobar"), "origin = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + + bstr = SysAllocString(L"barfoo"); + hres = IDOMMessageEvent_initMessageEvent(msg_event, bstr, VARIANT_FALSE, VARIANT_FALSE, NULL, NULL, NULL, NULL); + ok(hres == S_OK, "initMessageEvent failed: %08lx\n", hres); + SysFreeString(bstr); + + hres = IDOMMessageEvent_Invoke(msg_event, dispid, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &v[0], NULL, &argerr); + ok(hres == S_OK, "Invoke(data) failed: %08lx\n", hres); + ok(V_VT(&v[0]) == VT_BSTR, "V_VT(data) = %d\n", V_VT(&v[0])); + ok(!wcscmp(V_BSTR(&v[0]), L"foobar"), "V_BSTR(data) = %s\n", wine_dbgstr_w(V_BSTR(&v[0]))); + + hres = IDOMMessageEvent_get_source(msg_event, &source); + ok(hres == S_OK, "get_source failed: %08lx\n", hres); + ok(source == NULL, "source != NULL\n"); + + hres = IDOMMessageEvent_get_origin(msg_event, &bstr); + ok(hres == S_OK, "get_origin failed: %08lx\n", hres); + ok(!wcscmp(bstr, L"foobar"), "origin = %s\n", wine_dbgstr_w(bstr)); + SysFreeString(bstr); + } + + IDOMMessageEvent_Release(msg_event); + } } static void test_visibilitychange(IHTMLDocument2 *doc) diff --git a/dlls/mshtml/tests/events.js b/dlls/mshtml/tests/events.js index 1247c65e5bd..05f1375a591 100644 --- a/dlls/mshtml/tests/events.js +++ b/dlls/mshtml/tests/events.js @@ -835,6 +835,7 @@ async_test("message event", function() { return; } listener_called = true; + e.initMessageEvent("blah", true, true, "barfoo", "wine", 1234, window); ok(e.data === "test", "e.data = " + e.data); ok(e.bubbles === false, "bubbles = " + e.bubbles); ok(e.cancelable === false, "cancelable = " + e.cancelable); From 6b939fa36ba84afb9a13bfd1c8626697fd3239a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:58 +0200 Subject: [PATCH 0844/2777] jscript: Add initial implementation of ArrayBuffer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/Makefile.in | 1 + dlls/jscript/arraybuf.c | 190 +++++++++++++++++++++++++++++++++++++++ dlls/jscript/global.c | 4 + dlls/jscript/jscript.h | 5 +- dlls/jscript/object.c | 1 + dlls/mshtml/tests/es5.js | 48 ++++++++++ 6 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 dlls/jscript/arraybuf.c diff --git a/dlls/jscript/Makefile.in b/dlls/jscript/Makefile.in index 3e019201eb8..ccf38825dfa 100644 --- a/dlls/jscript/Makefile.in +++ b/dlls/jscript/Makefile.in @@ -4,6 +4,7 @@ IMPORTS = oleaut32 ole32 user32 advapi32 C_SRCS = \ activex.c \ array.c \ + arraybuf.c \ bool.c \ compile.c \ date.c \ diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c new file mode 100644 index 00000000000..4f2eeff66e8 --- /dev/null +++ b/dlls/jscript/arraybuf.c @@ -0,0 +1,190 @@ +/* + * Copyright 2023 Gabriel Ivăncescu 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 + */ + + +#include + +#include "jscript.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(jscript); + +typedef struct { + jsdisp_t dispex; + DWORD size; + DECLSPEC_ALIGN(sizeof(double)) BYTE buf[]; +} ArrayBufferInstance; + +static inline ArrayBufferInstance *arraybuf_from_jsdisp(jsdisp_t *jsdisp) +{ + return CONTAINING_RECORD(jsdisp, ArrayBufferInstance, dispex); +} + +static HRESULT ArrayBuffer_get_byteLength(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + TRACE("%p\n", jsthis); + + *r = jsval_number(arraybuf_from_jsdisp(jsthis)->size); + return S_OK; +} + +static HRESULT ArrayBuffer_slice(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + FIXME("not implemented\n"); + + return E_NOTIMPL; +} + +static const builtin_prop_t ArrayBuffer_props[] = { + {L"byteLength", NULL, 0, ArrayBuffer_get_byteLength}, + {L"slice", ArrayBuffer_slice, PROPF_METHOD|2}, +}; + +static const builtin_info_t ArrayBuffer_info = { + JSCLASS_ARRAYBUFFER, + NULL, + ARRAY_SIZE(ArrayBuffer_props), + ArrayBuffer_props, + NULL, + NULL +}; + +static const builtin_prop_t ArrayBufferInst_props[] = { + {L"byteLength", NULL, 0, ArrayBuffer_get_byteLength}, +}; + +static const builtin_info_t ArrayBufferInst_info = { + JSCLASS_ARRAYBUFFER, + NULL, + ARRAY_SIZE(ArrayBufferInst_props), + ArrayBufferInst_props, + NULL, + NULL +}; + +static HRESULT create_arraybuf(script_ctx_t *ctx, DWORD size, jsdisp_t **ret) +{ + ArrayBufferInstance *arraybuf; + HRESULT hres; + + if(!(arraybuf = calloc(1, FIELD_OFFSET(ArrayBufferInstance, buf[size])))) + return E_OUTOFMEMORY; + + hres = init_dispex_from_constr(&arraybuf->dispex, ctx, &ArrayBufferInst_info, ctx->arraybuf_constr); + if(FAILED(hres)) { + free(arraybuf); + return hres; + } + + arraybuf->size = size; + + *ret = &arraybuf->dispex; + return S_OK; +} + +static HRESULT ArrayBufferConstr_isView(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + FIXME("not implemented\n"); + + return E_NOTIMPL; +} + +static HRESULT ArrayBufferConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + DWORD size = 0; + jsdisp_t *obj; + HRESULT hres; + + TRACE("\n"); + + switch(flags) { + case DISPATCH_METHOD: + case DISPATCH_CONSTRUCT: { + if(argc) { + double n; + hres = to_integer(ctx, argv[0], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0) + return JS_E_INVALID_LENGTH; + if(n > (UINT_MAX - FIELD_OFFSET(ArrayBufferInstance, buf[0]))) + return E_OUTOFMEMORY; + size = n; + } + + if(r) { + hres = create_arraybuf(ctx, size, &obj); + if(FAILED(hres)) + return hres; + *r = jsval_obj(obj); + } + break; + } + default: + FIXME("unimplemented flags: %x\n", flags); + return E_NOTIMPL; + } + + return S_OK; +} + +static const builtin_prop_t ArrayBufferConstr_props[] = { + {L"isView", ArrayBufferConstr_isView, PROPF_METHOD|1}, +}; + +static const builtin_info_t ArrayBufferConstr_info = { + JSCLASS_FUNCTION, + Function_value, + ARRAY_SIZE(ArrayBufferConstr_props), + ArrayBufferConstr_props, + NULL, + NULL +}; + +HRESULT init_arraybuf_constructors(script_ctx_t *ctx) +{ + ArrayBufferInstance *arraybuf; + HRESULT hres; + + if(ctx->version < SCRIPTLANGUAGEVERSION_ES5) + return S_OK; + + if(!(arraybuf = calloc(1, FIELD_OFFSET(ArrayBufferInstance, buf[0])))) + return E_OUTOFMEMORY; + + hres = init_dispex(&arraybuf->dispex, ctx, &ArrayBuffer_info, ctx->object_prototype); + if(FAILED(hres)) { + free(arraybuf); + return hres; + } + + hres = create_builtin_constructor(ctx, ArrayBufferConstr_value, L"ArrayBuffer", &ArrayBufferConstr_info, + PROPF_CONSTR|1, &arraybuf->dispex, &ctx->arraybuf_constr); + jsdisp_release(&arraybuf->dispex); + if(FAILED(hres)) + return hres; + + hres = jsdisp_define_data_property(ctx->global, L"ArrayBuffer", PROPF_CONFIGURABLE | PROPF_WRITABLE, + jsval_obj(ctx->arraybuf_constr)); + + return hres; +} diff --git a/dlls/jscript/global.c b/dlls/jscript/global.c index 9dd969aa334..0ab17265b73 100644 --- a/dlls/jscript/global.c +++ b/dlls/jscript/global.c @@ -1143,5 +1143,9 @@ HRESULT init_global(script_ctx_t *ctx) if(FAILED(hres)) return hres; + hres = init_arraybuf_constructors(ctx); + if(FAILED(hres)) + return hres; + return init_set_constructor(ctx); } diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 04b3a6cc8c9..80755b47d0a 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -115,6 +115,7 @@ typedef enum { JSCLASS_ARGUMENTS, JSCLASS_VBARRAY, JSCLASS_JSON, + JSCLASS_ARRAYBUFFER, JSCLASS_MAP, JSCLASS_SET, } jsclass_t; @@ -415,10 +416,11 @@ struct _script_ctx_t { jsdisp_t *regexp_constr; jsdisp_t *string_constr; jsdisp_t *vbarray_constr; + jsdisp_t *arraybuf_constr; jsdisp_t *map_prototype; jsdisp_t *set_prototype; }; - jsdisp_t *global_objects[22]; + jsdisp_t *global_objects[23]; }; }; C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, set_prototype) == RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, global_objects)); @@ -434,6 +436,7 @@ HRESULT init_global(script_ctx_t*) DECLSPEC_HIDDEN; HRESULT init_function_constr(script_ctx_t*,jsdisp_t*) DECLSPEC_HIDDEN; HRESULT create_object_prototype(script_ctx_t*,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT init_set_constructor(script_ctx_t*) DECLSPEC_HIDDEN; +HRESULT init_arraybuf_constructors(script_ctx_t*) DECLSPEC_HIDDEN; HRESULT create_activex_constr(script_ctx_t*,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT create_array_constr(script_ctx_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index 4f6acacbc95..6d7816854e1 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -50,6 +50,7 @@ static HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns L"[object Object]", L"[object Object]", L"[object Object]", + L"[object ArrayBuffer]", L"[object Object]", L"[object Object]" }; diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index e13ad055f4f..c64f5d1f502 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -26,6 +26,7 @@ var JS_E_BOOLEAN_EXPECTED = 0x800a1392; var JS_E_VBARRAY_EXPECTED = 0x800a1395; var JS_E_ENUMERATOR_EXPECTED = 0x800a1397; var JS_E_REGEXP_EXPECTED = 0x800a1398; +var JS_E_INVALID_LENGTH = 0x800a13a5; var JS_E_INVALID_WRITABLE_PROP_DESC = 0x800a13ac; var JS_E_NONCONFIGURABLE_REDEFINED = 0x800a13d6; var JS_E_NONWRITABLE_MODIFIED = 0x800a13d7; @@ -1610,6 +1611,53 @@ sync_test("isFrozen", function() { } }); +sync_test("ArrayBuffers & Views", function() { + var r, buf; + + function test_own_props(obj_name, props) { + var obj = eval(obj_name); + for(var i = 0; i < props.length; i++) + ok(Object.prototype.hasOwnProperty.call(obj, props[i]), props[i] + " not a property of " + obj_name); + } + + function test_readonly(obj, prop, val) { + var name = Object.getPrototypeOf(obj).constructor.toString(); + name = name.substring(9, name.indexOf("(", 9)) + ".prototype." + prop; + obj[prop] = val + 42; + ok(obj[prop] === val, name + " not read-only"); + } + + test_own_props("ArrayBuffer", [ "isView" ]); + test_own_props("ArrayBuffer.prototype", [ "byteLength", "slice" ]); + test_own_data_prop_desc(ArrayBuffer.prototype, "byteLength", false, false, false); + + r = Object.prototype.toString.call(new ArrayBuffer()); + ok(r === "[object ArrayBuffer]", "Object toString(new ArrayBuffer()) = " + r); + r = ArrayBuffer.length; + ok(r === 1, "ArrayBuffer.length = " + r); + r = ArrayBuffer.isView.length; + ok(r === 1, "ArrayBuffer.isView.length = " + r); + r = ArrayBuffer.prototype.slice.length; + ok(r === 2, "ArrayBuffer.prototype.slice.length = " + r); + + try { + new ArrayBuffer(-1); + ok(false, "new ArrayBuffer(-1) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_INVALID_LENGTH, "new ArrayBuffer(-1) threw " + n); + } + + buf = new ArrayBuffer(); + ok(buf.byteLength === 0, "ArrayBuffer().byteLength = " + buf.byteLength); + buf = new ArrayBuffer(13.1); + ok(buf.byteLength === 13, "ArrayBuffer(13).byteLength = " + buf.byteLength); + buf = ArrayBuffer("10"); + ok(buf.byteLength === 10, "ArrayBuffer(10).byteLength = " + buf.byteLength); + test_readonly(buf, "byteLength", 10); + test_own_data_prop_desc(buf, "byteLength", false, false, false); +}); + sync_test("builtin_context", function() { var nullDisp = external.nullDisp; var tests = [ From 75ec6adf09057f79bebdf2b1786778b141133b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:59 +0200 Subject: [PATCH 0845/2777] jscript: Implement DataView. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/arraybuf.c | 570 +++++++++++++++++++++++++++++++++++++++ dlls/jscript/error.c | 4 + dlls/jscript/jscript.h | 8 +- dlls/jscript/jscript.rc | 4 + dlls/jscript/object.c | 1 + dlls/jscript/resource.h | 4 + dlls/mshtml/tests/es5.js | 262 +++++++++++++++++- 7 files changed, 851 insertions(+), 2 deletions(-) diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 4f2eeff66e8..c8a024346b9 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -31,11 +31,30 @@ typedef struct { DECLSPEC_ALIGN(sizeof(double)) BYTE buf[]; } ArrayBufferInstance; +typedef struct { + jsdisp_t dispex; + + jsdisp_t *buffer; + DWORD offset; + DWORD size; +} DataViewInstance; + static inline ArrayBufferInstance *arraybuf_from_jsdisp(jsdisp_t *jsdisp) { return CONTAINING_RECORD(jsdisp, ArrayBufferInstance, dispex); } +static inline DataViewInstance *dataview_from_jsdisp(jsdisp_t *jsdisp) +{ + return CONTAINING_RECORD(jsdisp, DataViewInstance, dispex); +} + +static inline ArrayBufferInstance *arraybuf_this(jsval_t vthis) +{ + jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + return (jsdisp && is_class(jsdisp, JSCLASS_ARRAYBUFFER)) ? arraybuf_from_jsdisp(jsdisp) : NULL; +} + static HRESULT ArrayBuffer_get_byteLength(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) { TRACE("%p\n", jsthis); @@ -160,10 +179,516 @@ static const builtin_info_t ArrayBufferConstr_info = { NULL }; +static inline DataViewInstance *dataview_this(jsval_t vthis) +{ + jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + return (jsdisp && is_class(jsdisp, JSCLASS_DATAVIEW)) ? dataview_from_jsdisp(jsdisp) : NULL; +} + +static HRESULT DataView_get_buffer(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + DataViewInstance *view; + + TRACE("\n"); + + if(!(view = dataview_this(vthis))) + return JS_E_NOT_DATAVIEW; + if(r) *r = jsval_obj(jsdisp_addref(view->buffer)); + return S_OK; +} + +static HRESULT DataView_get_byteLength(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + DataViewInstance *view; + + TRACE("\n"); + + if(!(view = dataview_this(vthis))) + return JS_E_NOT_DATAVIEW; + if(r) *r = jsval_number(view->size); + return S_OK; +} + +static HRESULT DataView_get_byteOffset(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + DataViewInstance *view; + + TRACE("\n"); + + if(!(view = dataview_this(vthis))) + return JS_E_NOT_DATAVIEW; + if(r) *r = jsval_number(view->offset); + return S_OK; +} + +static inline void copy_type_data(void *dst, const void *src, unsigned type_size, BOOL little_endian) +{ +#ifdef WORDS_BIGENDIAN + BOOL swap = little_endian; +#else + BOOL swap = !little_endian; +#endif + const BYTE *in = src; + BYTE *out = dst; + unsigned i; + + if(swap) + for(i = 0; i < type_size; i++) + out[i] = in[type_size - i - 1]; + else + memcpy(out, in, type_size); +} + +static HRESULT get_data(script_ctx_t *ctx, jsval_t vthis, unsigned argc, jsval_t *argv, unsigned type_size, void *ret) +{ + BOOL little_endian = FALSE; + DataViewInstance *view; + HRESULT hres; + DWORD offset; + BYTE *data; + double n; + + if(!(view = dataview_this(vthis))) + return JS_E_NOT_DATAVIEW; + if(!argc || is_undefined(argv[0])) + return JS_E_DATAVIEW_NO_ARGUMENT; + + hres = to_integer(ctx, argv[0], &n); + if(FAILED(hres)) + return hres; + + if(n < 0.0 || n >= view->size) + return JS_E_DATAVIEW_INVALID_ACCESS; + + offset = n; + if(view->size - offset < type_size) + return JS_E_DATAVIEW_INVALID_ACCESS; + data = &arraybuf_from_jsdisp(view->buffer)->buf[view->offset + offset]; + + if(type_size == 1) { + *(BYTE*)ret = data[0]; + return S_OK; + } + + if(argc > 1) { + hres = to_boolean(argv[1], &little_endian); + if(FAILED(hres)) + return hres; + } + + copy_type_data(ret, data, type_size, little_endian); + return S_OK; +} + +static HRESULT set_data(script_ctx_t *ctx, jsval_t vthis, unsigned argc, jsval_t *argv, unsigned type_size, const void *val) +{ + BOOL little_endian = FALSE; + DataViewInstance *view; + HRESULT hres; + DWORD offset; + BYTE *data; + double n; + + if(!(view = dataview_this(vthis))) + return JS_E_NOT_DATAVIEW; + if(is_undefined(argv[0]) || is_undefined(argv[1])) + return JS_E_DATAVIEW_NO_ARGUMENT; + + hres = to_integer(ctx, argv[0], &n); + if(FAILED(hres)) + return hres; + + if(n < 0.0 || n >= view->size) + return JS_E_DATAVIEW_INVALID_ACCESS; + + offset = n; + if(view->size - offset < type_size) + return JS_E_DATAVIEW_INVALID_ACCESS; + data = &arraybuf_from_jsdisp(view->buffer)->buf[view->offset + offset]; + + if(type_size == 1) { + data[0] = *(const BYTE*)val; + return S_OK; + } + + if(argc > 2) { + hres = to_boolean(argv[2], &little_endian); + if(FAILED(hres)) + return hres; + } + + copy_type_data(data, val, type_size, little_endian); + return S_OK; +} + +static HRESULT DataView_getFloat32(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + float v; + + TRACE("\n"); + + hres = get_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_number(v); + return S_OK; +} + +static HRESULT DataView_getFloat64(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + double v; + + TRACE("\n"); + + hres = get_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_number(v); + return S_OK; +} + +static HRESULT DataView_getInt8(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + INT8 v; + + TRACE("\n"); + + hres = get_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_number(v); + return S_OK; +} + +static HRESULT DataView_getInt16(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + INT16 v; + + TRACE("\n"); + + hres = get_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_number(v); + return S_OK; +} + +static HRESULT DataView_getInt32(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + INT32 v; + + TRACE("\n"); + + hres = get_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_number(v); + return S_OK; +} + +static HRESULT DataView_getUint8(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + UINT8 v; + + TRACE("\n"); + + hres = get_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_number(v); + return S_OK; +} + +static HRESULT DataView_getUint16(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + UINT16 v; + + TRACE("\n"); + + hres = get_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_number(v); + return S_OK; +} + +static HRESULT DataView_getUint32(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + UINT32 v; + + TRACE("\n"); + + hres = get_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_number(v); + return S_OK; +} + +static HRESULT DataView_setFloat32(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + double n; + float v; + + TRACE("\n"); + + if(argc < 2) + return JS_E_DATAVIEW_NO_ARGUMENT; + hres = to_number(ctx, argv[1], &n); + if(FAILED(hres)) + return hres; + v = n; /* FIXME: don't assume rounding mode is round-to-nearest ties-to-even */ + + hres = set_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_undefined(); + return S_OK; +} + +static HRESULT DataView_setFloat64(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + double v; + + TRACE("\n"); + + if(argc < 2) + return JS_E_DATAVIEW_NO_ARGUMENT; + hres = to_number(ctx, argv[1], &v); + if(FAILED(hres)) + return hres; + + hres = set_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_undefined(); + return S_OK; +} + +static HRESULT DataView_setInt8(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + INT32 n; + INT8 v; + + TRACE("\n"); + + if(argc < 2) + return JS_E_DATAVIEW_NO_ARGUMENT; + hres = to_int32(ctx, argv[1], &n); + if(FAILED(hres)) + return hres; + v = n; + + hres = set_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_undefined(); + return S_OK; +} + +static HRESULT DataView_setInt16(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + INT32 n; + INT16 v; + + TRACE("\n"); + + if(argc < 2) + return JS_E_DATAVIEW_NO_ARGUMENT; + hres = to_int32(ctx, argv[1], &n); + if(FAILED(hres)) + return hres; + v = n; + + hres = set_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_undefined(); + return S_OK; +} + +static HRESULT DataView_setInt32(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +{ + HRESULT hres; + INT32 v; + + TRACE("\n"); + + if(argc < 2) + return JS_E_DATAVIEW_NO_ARGUMENT; + hres = to_int32(ctx, argv[1], &v); + if(FAILED(hres)) + return hres; + + hres = set_data(ctx, vthis, argc, argv, sizeof(v), &v); + if(FAILED(hres)) + return hres; + if(r) *r = jsval_undefined(); + return S_OK; +} + +static const builtin_prop_t DataView_props[] = { + {L"getFloat32", DataView_getFloat32, PROPF_METHOD|1}, + {L"getFloat64", DataView_getFloat64, PROPF_METHOD|1}, + {L"getInt16", DataView_getInt16, PROPF_METHOD|1}, + {L"getInt32", DataView_getInt32, PROPF_METHOD|1}, + {L"getInt8", DataView_getInt8, PROPF_METHOD|1}, + {L"getUint16", DataView_getUint16, PROPF_METHOD|1}, + {L"getUint32", DataView_getUint32, PROPF_METHOD|1}, + {L"getUint8", DataView_getUint8, PROPF_METHOD|1}, + {L"setFloat32", DataView_setFloat32, PROPF_METHOD|1}, + {L"setFloat64", DataView_setFloat64, PROPF_METHOD|1}, + {L"setInt16", DataView_setInt16, PROPF_METHOD|1}, + {L"setInt32", DataView_setInt32, PROPF_METHOD|1}, + {L"setInt8", DataView_setInt8, PROPF_METHOD|1}, + {L"setUint16", DataView_setInt16, PROPF_METHOD|1}, + {L"setUint32", DataView_setInt32, PROPF_METHOD|1}, + {L"setUint8", DataView_setInt8, PROPF_METHOD|1}, +}; + +static void DataView_destructor(jsdisp_t *dispex) +{ + DataViewInstance *view = dataview_from_jsdisp(dispex); + if(view->buffer) + jsdisp_release(view->buffer); + free(view); +} + +static HRESULT DataView_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex) +{ + DataViewInstance *view = dataview_from_jsdisp(dispex); + return gc_process_linked_obj(gc_ctx, op, dispex, view->buffer, (void**)&view->buffer); +} + +static const builtin_info_t DataView_info = { + JSCLASS_DATAVIEW, + NULL, + ARRAY_SIZE(DataView_props), + DataView_props, + DataView_destructor, + NULL, + NULL, + NULL, + NULL, + DataView_gc_traverse +}; + +static const builtin_info_t DataViewInst_info = { + JSCLASS_DATAVIEW, + NULL, + 0, + NULL, + DataView_destructor, + NULL, + NULL, + NULL, + NULL, + DataView_gc_traverse +}; + +static HRESULT DataViewConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r) +{ + ArrayBufferInstance *arraybuf; + DataViewInstance *view; + DWORD offset = 0, size; + HRESULT hres; + + TRACE("\n"); + + switch(flags) { + case DISPATCH_METHOD: + case DISPATCH_CONSTRUCT: { + if(!argc || !(arraybuf = arraybuf_this(argv[0]))) + return JS_E_DATAVIEW_NO_ARGUMENT; + size = arraybuf->size; + + if(argc > 1) { + double offs, len, maxsize = size; + hres = to_integer(ctx, argv[1], &offs); + if(FAILED(hres)) + return hres; + if(offs < 0.0 || offs > maxsize) + return JS_E_DATAVIEW_INVALID_OFFSET; + offset = offs; + + if(argc > 2 && !is_undefined(argv[2])) { + hres = to_integer(ctx, argv[2], &len); + if(FAILED(hres)) + return hres; + if(len < 0.0 || offs+len > maxsize) + return JS_E_DATAVIEW_INVALID_OFFSET; + size = len; + }else + size -= offset; + } + + if(!r) + return S_OK; + + if(!(view = calloc(1, sizeof(DataViewInstance)))) + return E_OUTOFMEMORY; + + hres = init_dispex_from_constr(&view->dispex, ctx, &DataViewInst_info, ctx->dataview_constr); + if(FAILED(hres)) { + free(view); + return hres; + } + + view->buffer = jsdisp_addref(&arraybuf->dispex); + view->offset = offset; + view->size = size; + + *r = jsval_obj(&view->dispex); + break; + } + default: + FIXME("unimplemented flags: %x\n", flags); + return E_NOTIMPL; + } + + return S_OK; +} + +static const builtin_info_t DataViewConstr_info = { + JSCLASS_FUNCTION, + Function_value, + 0, + NULL, + NULL, + NULL +}; + HRESULT init_arraybuf_constructors(script_ctx_t *ctx) { + static const struct { + const WCHAR *name; + builtin_invoke_t get; + } DataView_getters[] = { + { L"buffer", DataView_get_buffer }, + { L"byteLength", DataView_get_byteLength }, + { L"byteOffset", DataView_get_byteOffset }, + }; ArrayBufferInstance *arraybuf; + DataViewInstance *view; + property_desc_t desc; HRESULT hres; + unsigned i; if(ctx->version < SCRIPTLANGUAGEVERSION_ES5) return S_OK; @@ -185,6 +710,51 @@ HRESULT init_arraybuf_constructors(script_ctx_t *ctx) hres = jsdisp_define_data_property(ctx->global, L"ArrayBuffer", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->arraybuf_constr)); + if(FAILED(hres)) + return hres; + + if(!(view = calloc(1, sizeof(DataViewInstance)))) + return E_OUTOFMEMORY; + + hres = create_arraybuf(ctx, 0, &view->buffer); + if(FAILED(hres)) { + free(view); + return hres; + } + + hres = init_dispex(&view->dispex, ctx, &DataView_info, ctx->object_prototype); + if(FAILED(hres)) { + jsdisp_release(view->buffer); + free(view); + return hres; + } + + desc.flags = PROPF_CONFIGURABLE; + desc.mask = PROPF_CONFIGURABLE | PROPF_ENUMERABLE; + desc.explicit_getter = desc.explicit_setter = TRUE; + desc.explicit_value = FALSE; + desc.setter = NULL; + + for(i = 0; i < ARRAY_SIZE(DataView_getters); i++) { + hres = create_builtin_function(ctx, DataView_getters[i].get, NULL, NULL, PROPF_METHOD, NULL, &desc.getter); + if(SUCCEEDED(hres)) { + hres = jsdisp_define_property(&view->dispex, DataView_getters[i].name, &desc); + jsdisp_release(desc.getter); + } + if(FAILED(hres)) { + jsdisp_release(&view->dispex); + return hres; + } + } + + hres = create_builtin_constructor(ctx, DataViewConstr_value, L"DataView", &DataViewConstr_info, + PROPF_CONSTR|1, &view->dispex, &ctx->dataview_constr); + jsdisp_release(&view->dispex); + if(FAILED(hres)) + return hres; + + hres = jsdisp_define_data_property(ctx->global, L"DataView", PROPF_CONFIGURABLE | PROPF_WRITABLE, + jsval_obj(ctx->dataview_constr)); return hres; } diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index 244d9af0532..3819f550b9f 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -482,6 +482,8 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_OBJECT_NONEXTENSIBLE: case JS_E_NONCONFIGURABLE_REDEFINED: case JS_E_NONWRITABLE_MODIFIED: + case JS_E_NOT_DATAVIEW: + case JS_E_DATAVIEW_NO_ARGUMENT: case JS_E_PROP_DESC_MISMATCH: case JS_E_INVALID_WRITABLE_PROP_DESC: constr = ctx->type_error_constr; @@ -491,6 +493,8 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_FRACTION_DIGITS_OUT_OF_RANGE: case JS_E_PRECISION_OUT_OF_RANGE: case JS_E_INVALID_LENGTH: + case JS_E_DATAVIEW_INVALID_ACCESS: + case JS_E_DATAVIEW_INVALID_OFFSET: constr = ctx->range_error_constr; break; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 80755b47d0a..05495ba0c4d 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -116,6 +116,7 @@ typedef enum { JSCLASS_VBARRAY, JSCLASS_JSON, JSCLASS_ARRAYBUFFER, + JSCLASS_DATAVIEW, JSCLASS_MAP, JSCLASS_SET, } jsclass_t; @@ -417,10 +418,11 @@ struct _script_ctx_t { jsdisp_t *string_constr; jsdisp_t *vbarray_constr; jsdisp_t *arraybuf_constr; + jsdisp_t *dataview_constr; jsdisp_t *map_prototype; jsdisp_t *set_prototype; }; - jsdisp_t *global_objects[23]; + jsdisp_t *global_objects[24]; }; }; C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, set_prototype) == RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, global_objects)); @@ -540,6 +542,10 @@ static inline DWORD make_grfdex(script_ctx_t *ctx, DWORD flags) #define JS_E_OBJECT_NONEXTENSIBLE MAKE_JSERROR(IDS_OBJECT_NONEXTENSIBLE) #define JS_E_NONCONFIGURABLE_REDEFINED MAKE_JSERROR(IDS_NONCONFIGURABLE_REDEFINED) #define JS_E_NONWRITABLE_MODIFIED MAKE_JSERROR(IDS_NONWRITABLE_MODIFIED) +#define JS_E_NOT_DATAVIEW MAKE_JSERROR(IDS_NOT_DATAVIEW) +#define JS_E_DATAVIEW_NO_ARGUMENT MAKE_JSERROR(IDS_DATAVIEW_NO_ARGUMENT) +#define JS_E_DATAVIEW_INVALID_ACCESS MAKE_JSERROR(IDS_DATAVIEW_INVALID_ACCESS) +#define JS_E_DATAVIEW_INVALID_OFFSET MAKE_JSERROR(IDS_DATAVIEW_INVALID_OFFSET) #define JS_E_WRONG_THIS MAKE_JSERROR(IDS_WRONG_THIS) #define JS_E_PROP_DESC_MISMATCH MAKE_JSERROR(IDS_PROP_DESC_MISMATCH) #define JS_E_INVALID_WRITABLE_PROP_DESC MAKE_JSERROR(IDS_INVALID_WRITABLE_PROP_DESC) diff --git a/dlls/jscript/jscript.rc b/dlls/jscript/jscript.rc index de21a4aba0b..480d90bda92 100644 --- a/dlls/jscript/jscript.rc +++ b/dlls/jscript/jscript.rc @@ -75,6 +75,10 @@ STRINGTABLE IDS_OBJECT_NONEXTENSIBLE "Cannot define property '|': object is not extensible" IDS_NONCONFIGURABLE_REDEFINED "Cannot redefine non-configurable property '|'" IDS_NONWRITABLE_MODIFIED "Cannot modify non-writable property '|'" + IDS_NOT_DATAVIEW "'this' is not a DataView object" + IDS_DATAVIEW_NO_ARGUMENT "Required argument offset or value in DataView method is not specified" + IDS_DATAVIEW_INVALID_ACCESS "DataView operation access beyond specified buffer length" + IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" IDS_WRONG_THIS "'this' is not a | object" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index 6d7816854e1..cba35927378 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -52,6 +52,7 @@ static HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns L"[object Object]", L"[object ArrayBuffer]", L"[object Object]", + L"[object Object]", L"[object Object]" }; diff --git a/dlls/jscript/resource.h b/dlls/jscript/resource.h index f84d77c198f..f4e7c2ae76f 100644 --- a/dlls/jscript/resource.h +++ b/dlls/jscript/resource.h @@ -73,6 +73,10 @@ #define IDS_OBJECT_NONEXTENSIBLE 0x13D5 #define IDS_NONCONFIGURABLE_REDEFINED 0x13D6 #define IDS_NONWRITABLE_MODIFIED 0x13D7 +#define IDS_NOT_DATAVIEW 0x13DF +#define IDS_DATAVIEW_NO_ARGUMENT 0x13E0 +#define IDS_DATAVIEW_INVALID_ACCESS 0x13E1 +#define IDS_DATAVIEW_INVALID_OFFSET 0x13E2 #define IDS_WRONG_THIS 0x13FC /* FIXME: This is not compatible with native, but we would * conflict with IDS_UNSUPPORTED_ACTION otherwise */ diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index c64f5d1f502..15bd0a9bf5f 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -30,6 +30,10 @@ var JS_E_INVALID_LENGTH = 0x800a13a5; var JS_E_INVALID_WRITABLE_PROP_DESC = 0x800a13ac; var JS_E_NONCONFIGURABLE_REDEFINED = 0x800a13d6; var JS_E_NONWRITABLE_MODIFIED = 0x800a13d7; +var JS_E_NOT_DATAVIEW = 0x800a13df; +var JS_E_DATAVIEW_NO_ARGUMENT = 0x800a13e0; +var JS_E_DATAVIEW_INVALID_ACCESS = 0x800a13e1; +var JS_E_DATAVIEW_INVALID_OFFSET = 0x800a13e2; var JS_E_WRONG_THIS = 0x800a13fc; var tests = []; @@ -1612,7 +1616,18 @@ sync_test("isFrozen", function() { }); sync_test("ArrayBuffers & Views", function() { - var r, buf; + var i, r, buf, view, view2, arr; + + var types = [ + [ "Int8", 1 ], + [ "Uint8", 1 ], + [ "Int16", 2 ], + [ "Uint16", 2 ], + [ "Int32", 4 ], + [ "Uint32", 4 ], + [ "Float32", 4 ], + [ "Float64", 8 ] + ]; function test_own_props(obj_name, props) { var obj = eval(obj_name); @@ -1620,6 +1635,12 @@ sync_test("ArrayBuffers & Views", function() { ok(Object.prototype.hasOwnProperty.call(obj, props[i]), props[i] + " not a property of " + obj_name); } + function test_not_own_props(obj_name, props) { + var obj = eval(obj_name); + for(var i = 0; i < props.length; i++) + ok(!Object.prototype.hasOwnProperty.call(obj, props[i]), props[i] + " is a property of " + obj_name); + } + function test_readonly(obj, prop, val) { var name = Object.getPrototypeOf(obj).constructor.toString(); name = name.substring(9, name.indexOf("(", 9)) + ".prototype." + prop; @@ -1656,6 +1677,245 @@ sync_test("ArrayBuffers & Views", function() { ok(buf.byteLength === 10, "ArrayBuffer(10).byteLength = " + buf.byteLength); test_readonly(buf, "byteLength", 10); test_own_data_prop_desc(buf, "byteLength", false, false, false); + + test_own_props("DataView.prototype", [ + "buffer", "byteLength", "byteOffset", + "getInt8", "setInt8", "getUint8", "setUint8", + "getInt16", "setInt16", "getUint16", "setUint16", + "getInt32", "setInt32", "getUint32", "setUint32", + "getFloat32", "setFloat32", "getFloat64", "setFloat64" + ]); + + r = Object.prototype.toString.call(new DataView(buf)); + ok(r === "[object Object]", "Object toString(new DataView(buf)) = " + r); + r = DataView.length; + ok(r === 1, "DataView.length = " + r); + + /* DataView.prototype has actual accessors, but others don't */ + arr = [ "buffer", "byteLength", "byteOffset" ]; + for(i = 0; i < arr.length; i++) { + var prop = arr[i], desc = Object.getOwnPropertyDescriptor(DataView.prototype, prop); + ok(!("value" in desc), "DataView: value is in desc"); + ok(!("writable" in desc), "DataView: writable is in desc"); + ok(desc.enumerable === false, "DataView: desc.enumerable = " + desc.enumerable); + ok(desc.configurable === true, "DataView: desc.configurable = " + desc.configurable); + ok(Object.getPrototypeOf(desc.get) === Function.prototype, "DataView: desc.get not a function: " + desc.get); + ok("set" in desc, "DataView: set is not in desc"); + ok(desc.set === undefined, "DataView: desc.set not undefined: " + desc.set); + try { + desc.get.call(null); + ok(false, "DataView: calling " + prop + " getter with null did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_DATAVIEW, "DataView: calling " + prop + " getter with null threw " + n); + } + try { + desc.get.call({}); + ok(false, "DataView: calling " + prop + " getter with an object did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_DATAVIEW, "DataView: calling " + prop + " getter with an object threw " + n); + } + try { + desc.get.call(DataView); + ok(false, "DataView: calling " + prop + " getter with DataView constructor did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_DATAVIEW, "DataView: calling " + prop + " getter with DataView constructor threw " + n); + } + try { + desc.get.call(new ArrayBuffer()); + ok(false, "DataView: calling " + prop + " getter with ArrayBuffer did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_DATAVIEW, "DataView: calling " + prop + " getter with ArrayBuffer threw " + n); + } + r = desc.get.call(DataView.prototype); + if(prop === "buffer") + ok(Object.getPrototypeOf(r) === ArrayBuffer.prototype, "DataView: calling " + prop + " getter with DataView.prototype returned " + r); + else + ok(r === 0, "DataView: calling " + prop + " getter with DataView.prototype returned " + r); + } + + try { + new DataView(); + ok(false, "new DataView() did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_DATAVIEW_NO_ARGUMENT, "new DataView() threw " + n); + } + try { + new DataView(ArrayBuffer); + ok(false, "new DataView(ArrayBuffer) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_DATAVIEW_NO_ARGUMENT, "new DataView(ArrayBuffer) threw " + n); + } + try { + new DataView(buf, -1); + ok(false, "new DataView(buf, -1) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_DATAVIEW_INVALID_OFFSET, "new DataView(buf, -1) threw " + n); + } + try { + new DataView(buf, 11); + ok(false, "new DataView(buf, 11) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_DATAVIEW_INVALID_OFFSET, "new DataView(buf, 11) threw " + n); + } + try { + new DataView(buf, 9, 2); + ok(false, "new DataView(buf, 9, 2) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_DATAVIEW_INVALID_OFFSET, "new DataView(buf, 9, 2) threw " + n); + } + + view = new DataView(buf, 9, 1); + ok(view.buffer === buf, "DataView(buf, 9, 1).buffer = " + view.buffer); + ok(view.byteLength === 1, "DataView(buf, 9, 1).byteLength = " + view.byteLength); + ok(view.byteOffset === 9, "DataView(buf, 9, 1).byteOffset = " + view.byteOffset); + test_readonly(view, "byteLength", 1); + test_readonly(view, "byteOffset", 9); + test_not_own_props("view", [ "buffer", "byteLength", "byteOffset" ]); + + view = new DataView(buf, 10); + ok(view.buffer === buf, "DataView(buf, 10).buffer = " + view.buffer); + ok(view.byteLength === 0, "DataView(buf, 10).byteLength = " + view.byteLength); + ok(view.byteOffset === 10, "DataView(buf, 10).byteOffset = " + view.byteOffset); + view = new DataView(buf, 1, 7); + ok(view.buffer === buf, "DataView(buf, 1, 7).buffer = " + view.buffer); + ok(view.byteLength === 7, "DataView(buf, 1, 7).byteLength = " + view.byteLength); + ok(view.byteOffset === 1, "DataView(buf, 1, 7).byteOffset = " + view.byteOffset); + view2 = new DataView(buf, 6); + ok(view2.buffer === buf, "DataView(buf, 6).buffer = " + view2.buffer); + ok(view2.byteLength === 4, "DataView(buf, 6).byteLength = " + view2.byteLength); + ok(view2.byteOffset === 6, "DataView(buf, 6).byteOffset = " + view2.byteOffset); + view = DataView(buf); + ok(view.buffer === buf, "DataView(buf).buffer = " + view.buffer); + ok(view.byteLength === 10, "DataView(buf).byteLength = " + view.byteLength); + ok(view.byteOffset === 0, "DataView(buf).byteOffset = " + view.byteOffset); + + for(i = 0; i < 10; i++) { + r = view.getInt8(i); + ok(r === 0, "view byte " + i + " = " + r); + } + + for(i = 0; i < types.length; i++) { + var method = "get" + types[i][0], offs = 11 - types[i][1]; + r = DataView.prototype[method].length; + ok(r === 1, "DataView.prototype." + method + ".length = " + r); + try { + view[method](); + ok(false, "view." + method + "() did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_DATAVIEW_NO_ARGUMENT, "view." + method + "() threw " + n); + } + try { + view[method](-1); + ok(false, "view." + method + "(-1) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_DATAVIEW_INVALID_ACCESS, "view." + method + "(-1) threw " + n); + } + try { + view[method](offs); + ok(false, "view." + method + "(" + offs + ") did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_DATAVIEW_INVALID_ACCESS, "view." + method + "(" + offs + ") threw " + n); + } + try { + view[method].call(null, 0); + ok(false, "view." + method + "(0) with null context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_DATAVIEW, "view." + method + "(0) with null context threw " + n); + } + try { + view[method].call({}, 0); + ok(false, "view." + method + "(0) with an object context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_DATAVIEW, "view." + method + "(0) with an object context threw " + n); + } + method = "set" + types[i][0]; + r = DataView.prototype[method].length; + ok(r === 1, "DataView.prototype." + method + ".length = " + r); + try { + view[method](); + ok(false, "view." + method + "() did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_DATAVIEW_NO_ARGUMENT, "view." + method + "() threw " + n); + } + try { + view[method](0); + ok(false, "view." + method + "(0) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_DATAVIEW_NO_ARGUMENT, "view." + method + "(0) threw " + n); + } + try { + view[method](-1, 0); + ok(false, "view." + method + "(-1, 0) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_DATAVIEW_INVALID_ACCESS, "view." + method + "(-1, 0) threw " + n); + } + try { + view[method](offs, 0); + ok(false, "view." + method + "(" + offs + ", 0) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_DATAVIEW_INVALID_ACCESS, "view." + method + "(" + offs + ", 0) threw " + n); + } + try { + view[method].call(null, 0, 0); + ok(false, "view." + method + "(0, 0) with null context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_DATAVIEW, "view." + method + "(0, 0) with null context threw " + n); + } + try { + view[method].call({}, 0, 0); + ok(false, "view." + method + "(0, 0) with an object context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_DATAVIEW, "view." + method + "(0, 0) with an object context threw " + n); + } + } + + r = view.setInt8(1, -257); + ok(r === undefined, "view.setInt8(1, -1) returned " + r); + r = view.getUint16(0); + ok(r === 255, "view.getUint16(0) returned " + r); + r = view.getUint16(0, true); + ok(r === 65280, "view.getUint16(0, true) returned " + r); + r = view.setUint32(2, "12345678", true); + ok(r === undefined, "view.setUint32(2, '12345678', true) returned " + r); + r = view.getInt32(1); + ok(r === -11640388, "view.getInt32(1) returned " + r); + r = view.setInt16(3, 65535, true); + ok(r === undefined, "view.setInt16(3, 65535) returned " + r); + r = view.getUint16(3); + ok(r === 65535, "view.getUint16(3) returned " + r); + r = view.setUint32(0, -2, true); + ok(r === undefined, "view.setUint32(0, -2) returned " + r); + r = view.getInt32(0, true); + ok(r === -2, "view.getInt32(0) returned " + r); + r = view.setFloat32(6, 1234.5, true); + ok(r === undefined, "view.setFloat32(6, 1234.5) returned " + r); + r = view2.getFloat32(0, true); + ok(r === 1234.5, "view2.getFloat32(0) returned " + r); + + /* setters differing only in signedness have identical behavior, but they're not the same methods */ + ok(view.setInt8 !== view.setUint8, "setInt8 and setUint8 are the same method"); + ok(view.setInt16 !== view.setUint16, "setInt16 and setUint16 are the same method"); + ok(view.setInt32 !== view.setUint32, "setInt32 and setUint32 are the same method"); }); sync_test("builtin_context", function() { From 693c01fff029a17327ac5a77781d88442061b29d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:59 +0200 Subject: [PATCH 0846/2777] jscript: Implement ArrayBuffer.prototype.slice. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/arraybuf.c | 49 ++++++++++++++++++++++++++++++++++++++-- dlls/jscript/error.c | 1 + dlls/jscript/jscript.h | 1 + dlls/jscript/jscript.rc | 1 + dlls/jscript/resource.h | 1 + dlls/mshtml/tests/es5.js | 46 ++++++++++++++++++++++++++++++++++++- 6 files changed, 96 insertions(+), 3 deletions(-) diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index c8a024346b9..90052de2b99 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -55,6 +55,8 @@ static inline ArrayBufferInstance *arraybuf_this(jsval_t vthis) return (jsdisp && is_class(jsdisp, JSCLASS_ARRAYBUFFER)) ? arraybuf_from_jsdisp(jsdisp) : NULL; } +static HRESULT create_arraybuf(script_ctx_t*,DWORD,jsdisp_t**); + static HRESULT ArrayBuffer_get_byteLength(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) { TRACE("%p\n", jsthis); @@ -66,9 +68,52 @@ static HRESULT ArrayBuffer_get_byteLength(script_ctx_t *ctx, jsdisp_t *jsthis, j static HRESULT ArrayBuffer_slice(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - FIXME("not implemented\n"); + ArrayBufferInstance *arraybuf; + DWORD begin = 0, end, size; + jsdisp_t *obj; + HRESULT hres; + double n; - return E_NOTIMPL; + TRACE("\n"); + + if(!(arraybuf = arraybuf_this(vthis))) + return JS_E_ARRAYBUFFER_EXPECTED; + end = arraybuf->size; + if(!r) + return S_OK; + + if(argc) { + hres = to_integer(ctx, argv[0], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0) + n += arraybuf->size; + if(n >= 0.0 && n < arraybuf->size) { + begin = n; + if(argc > 1 && !is_undefined(argv[1])) { + hres = to_integer(ctx, argv[1], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0) + n += arraybuf->size; + if(n >= 0.0) { + end = n < arraybuf->size ? n : arraybuf->size; + end = end < begin ? begin : end; + }else + end = begin; + } + }else + end = 0; + } + + size = end - begin; + hres = create_arraybuf(ctx, size, &obj); + if(FAILED(hres)) + return hres; + memcpy(arraybuf_from_jsdisp(obj)->buf, arraybuf->buf + begin, size); + + *r = jsval_obj(obj); + return S_OK; } static const builtin_prop_t ArrayBuffer_props[] = { diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index 3819f550b9f..53fe63746e3 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -484,6 +484,7 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_NONWRITABLE_MODIFIED: case JS_E_NOT_DATAVIEW: case JS_E_DATAVIEW_NO_ARGUMENT: + case JS_E_ARRAYBUFFER_EXPECTED: case JS_E_PROP_DESC_MISMATCH: case JS_E_INVALID_WRITABLE_PROP_DESC: constr = ctx->type_error_constr; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 05495ba0c4d..9066dc9fa54 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -547,6 +547,7 @@ static inline DWORD make_grfdex(script_ctx_t *ctx, DWORD flags) #define JS_E_DATAVIEW_INVALID_ACCESS MAKE_JSERROR(IDS_DATAVIEW_INVALID_ACCESS) #define JS_E_DATAVIEW_INVALID_OFFSET MAKE_JSERROR(IDS_DATAVIEW_INVALID_OFFSET) #define JS_E_WRONG_THIS MAKE_JSERROR(IDS_WRONG_THIS) +#define JS_E_ARRAYBUFFER_EXPECTED MAKE_JSERROR(IDS_ARRAYBUFFER_EXPECTED) #define JS_E_PROP_DESC_MISMATCH MAKE_JSERROR(IDS_PROP_DESC_MISMATCH) #define JS_E_INVALID_WRITABLE_PROP_DESC MAKE_JSERROR(IDS_INVALID_WRITABLE_PROP_DESC) diff --git a/dlls/jscript/jscript.rc b/dlls/jscript/jscript.rc index 480d90bda92..acc2626a89d 100644 --- a/dlls/jscript/jscript.rc +++ b/dlls/jscript/jscript.rc @@ -80,6 +80,7 @@ STRINGTABLE IDS_DATAVIEW_INVALID_ACCESS "DataView operation access beyond specified buffer length" IDS_DATAVIEW_INVALID_OFFSET "DataView constructor argument offset is invalid" IDS_WRONG_THIS "'this' is not a | object" + IDS_ARRAYBUFFER_EXPECTED "ArrayBuffer object expected" IDS_PROP_DESC_MISMATCH "Property cannot have both accessors and a value" IDS_COMPILATION_ERROR "Microsoft JScript compilation error" diff --git a/dlls/jscript/resource.h b/dlls/jscript/resource.h index f4e7c2ae76f..f9b8121deb4 100644 --- a/dlls/jscript/resource.h +++ b/dlls/jscript/resource.h @@ -78,6 +78,7 @@ #define IDS_DATAVIEW_INVALID_ACCESS 0x13E1 #define IDS_DATAVIEW_INVALID_OFFSET 0x13E2 #define IDS_WRONG_THIS 0x13FC +#define IDS_ARRAYBUFFER_EXPECTED 0x15E4 /* FIXME: This is not compatible with native, but we would * conflict with IDS_UNSUPPORTED_ACTION otherwise */ #define IDS_PROP_DESC_MISMATCH 0x1F00 diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 15bd0a9bf5f..08db6d488be 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -35,6 +35,7 @@ var JS_E_DATAVIEW_NO_ARGUMENT = 0x800a13e0; var JS_E_DATAVIEW_INVALID_ACCESS = 0x800a13e1; var JS_E_DATAVIEW_INVALID_OFFSET = 0x800a13e2; var JS_E_WRONG_THIS = 0x800a13fc; +var JS_E_ARRAYBUFFER_EXPECTED = 0x800a15e4; var tests = []; @@ -1616,7 +1617,7 @@ sync_test("isFrozen", function() { }); sync_test("ArrayBuffers & Views", function() { - var i, r, buf, view, view2, arr; + var i, r, buf, buf2, view, view2, arr; var types = [ [ "Int8", 1 ], @@ -1661,6 +1662,20 @@ sync_test("ArrayBuffers & Views", function() { r = ArrayBuffer.prototype.slice.length; ok(r === 2, "ArrayBuffer.prototype.slice.length = " + r); + try { + ArrayBuffer.prototype.slice.call(null); + ok(false, "ArrayBuffer: calling slice with null context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_ARRAYBUFFER_EXPECTED, "ArrayBuffer: calling slice with null context threw " + n); + } + try { + ArrayBuffer.prototype.slice.call({}); + ok(false, "ArrayBuffer: calling slice with an object context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_ARRAYBUFFER_EXPECTED, "ArrayBuffer: calling slice with an object context threw " + n); + } try { new ArrayBuffer(-1); ok(false, "new ArrayBuffer(-1) did not throw exception"); @@ -1912,10 +1927,39 @@ sync_test("ArrayBuffers & Views", function() { r = view2.getFloat32(0, true); ok(r === 1234.5, "view2.getFloat32(0) returned " + r); + r = buf.slice(-9, 1); + ok(r instanceof ArrayBuffer, "buf.slice did not return an ArrayBuffer"); + ok(r.byteLength === 0, "buf.slice(-9, 1).byteLength = " + r.byteLength); + r = buf.slice(); + ok(r.byteLength === 10, "buf.slice().byteLength = " + r.byteLength); + r = buf.slice(9, 16); + ok(r.byteLength === 1, "buf.slice(9, 16).byteLength = " + r.byteLength); + r = buf.slice(-9, -1); + ok(r.byteLength === 8, "buf.slice(-9, -1).byteLength = " + r.byteLength); + /* setters differing only in signedness have identical behavior, but they're not the same methods */ ok(view.setInt8 !== view.setUint8, "setInt8 and setUint8 are the same method"); ok(view.setInt16 !== view.setUint16, "setInt16 and setUint16 are the same method"); ok(view.setInt32 !== view.setUint32, "setInt32 and setUint32 are the same method"); + + /* slice makes a copy */ + buf2 = buf.slice(-9); + ok(buf2.byteLength === 9, "buf.slice(-9).byteLength = " + buf2.byteLength); + view2 = DataView(buf2, 1); + ok(view2.byteLength === 8, "buf.slice(-9) view(1).byteLength = " + view2.byteLength); + + r = view2.getUint32(0); + ok(r === 4294967040, "buf.slice(-9) view(1).getUint32(0) returned " + r); + view2.setInt16(0, -5); + r = view2.getUint16(1); + ok(r === 64511, "buf.slice(-9) view(1).getUint16(1) returned " + r); + r = view.getInt32(1); + ok(r === -1, "view.getInt32(1) after slice changed returned " + r); + + r = view2.setFloat64(0, 11.875); + ok(r === undefined, "buf.slice(-9) view(1).setFloat64(0, 11.875) returned " + r); + r = view2.getFloat64(0); + ok(r === 11.875, "buf.slice(-9) view(1).getFloat64(0) returned " + r); }); sync_test("builtin_context", function() { From 929a2ad32c9a81a7e7212bf82fd87af62f552011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:59 +0200 Subject: [PATCH 0847/2777] jscript: Add initial implementation of Typed Arrays. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Typed Arrays have special properties (even according to the spec); they override all positive indices, and operations on them must be special cased. Presumably (on native) this is done for performance reasons, as they are used as actual data arrays which are expected to perform well with millions of iterations and elements (e.g. using them to store and manipulate an image). The only time we still create a PROP_IDX on them is when the DISPID is requested or when enumerating (same reason). Note that even the behavior is special; defining an indexed prop on a typed array for indices out of bounds of the array doesn't do anything, although it does throw if flags don't match (since it's not configurable). Redefining an index within bounds throws if flags don't match, but otherwise acts like a normal setter (coerces it into the underlying data type). delete always returns false, even for out of bounds indices, despite them not being props (hasOwnProperty returns false). The prototype is also not consulted for any positive indices, but is for negative (unlike the spec says, native differs here), i.e. the positive indices behavior is completely overridden, even for those out of bounds. Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/arraybuf.c | 354 +++++++++++++++++++++++++++++++++++++++ dlls/jscript/dispex.c | 99 ++++++++++- dlls/jscript/error.c | 3 + dlls/jscript/jscript.h | 19 ++- dlls/jscript/jscript.rc | 3 + dlls/jscript/object.c | 8 + dlls/jscript/resource.h | 3 + dlls/mshtml/tests/es5.js | 189 ++++++++++++++++++++- 8 files changed, 670 insertions(+), 8 deletions(-) diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 90052de2b99..8d3c56a27ca 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -39,6 +39,14 @@ typedef struct { DWORD size; } DataViewInstance; +typedef struct { + jsdisp_t dispex; + + jsdisp_t *buffer; + DWORD offset; + DWORD length; +} TypedArrayInstance; + static inline ArrayBufferInstance *arraybuf_from_jsdisp(jsdisp_t *jsdisp) { return CONTAINING_RECORD(jsdisp, ArrayBufferInstance, dispex); @@ -49,6 +57,11 @@ static inline DataViewInstance *dataview_from_jsdisp(jsdisp_t *jsdisp) return CONTAINING_RECORD(jsdisp, DataViewInstance, dispex); } +static inline TypedArrayInstance *typedarr_from_jsdisp(jsdisp_t *jsdisp) +{ + return CONTAINING_RECORD(jsdisp, TypedArrayInstance, dispex); +} + static inline ArrayBufferInstance *arraybuf_this(jsval_t vthis) { jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; @@ -719,6 +732,310 @@ static const builtin_info_t DataViewConstr_info = { NULL }; +#define TYPEDARRAY_LIST \ +X(Int8Array, JSCLASS_INT8ARRAY, INT8, to_int32, INT) \ +X(Int16Array, JSCLASS_INT16ARRAY, INT16, to_int32, INT) \ +X(Int32Array, JSCLASS_INT32ARRAY, INT32, to_int32, INT) \ +X(Uint8Array, JSCLASS_UINT8ARRAY, UINT8, to_int32, INT) \ +X(Uint16Array, JSCLASS_UINT16ARRAY, UINT16, to_int32, INT) \ +X(Uint32Array, JSCLASS_UINT32ARRAY, UINT32, to_int32, INT) \ +X(Float32Array, JSCLASS_FLOAT32ARRAY, float, to_number, double) \ +X(Float64Array, JSCLASS_FLOAT64ARRAY, double, to_number, double) + +#define TYPEDARRAY_INDEX(JSCLASS) ((JSCLASS) - FIRST_TYPEDARRAY_JSCLASS) + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) [TYPEDARRAY_INDEX(JSCLASS)] = L"" #NAME, +static const WCHAR *const TypedArray_name[] = { TYPEDARRAY_LIST }; +#undef X + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) [TYPEDARRAY_INDEX(JSCLASS)] = sizeof(TYPE), +static const unsigned TypedArray_elem_size[] = { TYPEDARRAY_LIST }; +#undef X + +static inline TypedArrayInstance *typedarr_this(jsval_t vthis, jsclass_t jsclass) +{ + jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL; + return (jsdisp && is_class(jsdisp, jsclass)) ? typedarr_from_jsdisp(jsdisp) : NULL; +} + +static HRESULT TypedArray_get_buffer(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + TRACE("%p\n", jsthis); + + *r = jsval_obj(jsdisp_addref(typedarr_from_jsdisp(jsthis)->buffer)); + return S_OK; +} + +static HRESULT TypedArray_get_byteLength(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + TRACE("%p\n", jsthis); + + *r = jsval_number(typedarr_from_jsdisp(jsthis)->length * TypedArray_elem_size[TYPEDARRAY_INDEX(jsthis->builtin_info->class)]); + return S_OK; +} + +static HRESULT TypedArray_get_byteOffset(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + TRACE("%p\n", jsthis); + + *r = jsval_number(typedarr_from_jsdisp(jsthis)->offset); + return S_OK; +} + +static HRESULT TypedArray_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) +{ + TRACE("%p\n", jsthis); + + *r = jsval_number(typedarr_from_jsdisp(jsthis)->length); + return S_OK; +} + +static HRESULT TypedArray_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r, jsclass_t jsclass) +{ + TypedArrayInstance *typedarr; + + FIXME("not implemented\n"); + + if(!(typedarr = typedarr_this(vthis, jsclass))) + return JS_E_NOT_TYPEDARRAY; + return E_NOTIMPL; +} + +static HRESULT TypedArray_subarray(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r, jsclass_t jsclass) +{ + TypedArrayInstance *typedarr; + + FIXME("not implemented\n"); + + if(!(typedarr = typedarr_this(vthis, jsclass))) + return JS_E_NOT_TYPEDARRAY; + return E_NOTIMPL; +} + +static unsigned TypedArray_idx_length(jsdisp_t *jsdisp) +{ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(jsdisp); + return typedarr->length; +} + +static void TypedArray_destructor(jsdisp_t *dispex) +{ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); + if(typedarr->buffer) + jsdisp_release(typedarr->buffer); + free(typedarr); +} + +static HRESULT TypedArray_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, jsdisp_t *dispex) +{ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(dispex); + return gc_process_linked_obj(gc_ctx, op, dispex, typedarr->buffer, (void**)&typedarr->buffer); +} + +static const builtin_prop_t TypedArrayInst_props[] = { + {L"buffer", NULL, 0, TypedArray_get_buffer}, + {L"byteLength", NULL, 0, TypedArray_get_byteLength}, + {L"byteOffset", NULL, 0, TypedArray_get_byteOffset}, + {L"length", NULL, 0, TypedArray_get_length}, +}; + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) \ +static HRESULT NAME ##_idx_get(jsdisp_t *jsdisp, unsigned idx, jsval_t *r) \ +{ \ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(jsdisp); \ + \ + TRACE("%p[%u]\n", typedarr, idx); \ + \ + if(idx >= typedarr->length) \ + *r = jsval_undefined(); \ + else \ + *r = jsval_number(*(TYPE*)&arraybuf_from_jsdisp(typedarr->buffer)->buf[typedarr->offset + idx * sizeof(TYPE)]); \ + return S_OK; \ +} \ + \ +static HRESULT NAME ##_idx_put(jsdisp_t *jsdisp, unsigned idx, jsval_t val) \ +{ \ + TypedArrayInstance *typedarr = typedarr_from_jsdisp(jsdisp); \ + HRESULT hres; \ + NUM_TYPE n; \ + \ + TRACE("%p[%u] = %s\n", typedarr, idx, debugstr_jsval(val)); \ + \ + if(idx >= typedarr->length) \ + return S_OK; \ + \ + hres = CONVERT(jsdisp->ctx, val, &n); \ + if(SUCCEEDED(hres)) \ + *(TYPE*)&arraybuf_from_jsdisp(typedarr->buffer)->buf[typedarr->offset + idx * sizeof(TYPE)] = n; \ + return hres; \ +} \ + \ +static HRESULT NAME ##_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, \ + jsval_t *r) \ +{ \ + return TypedArray_set(ctx, vthis, flags, argc, argv, r, JSCLASS); \ +} \ + \ +static HRESULT NAME ##_subarray(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, \ + jsval_t *r) \ +{ \ + return TypedArray_subarray(ctx, vthis, flags, argc, argv, r, JSCLASS); \ +} \ + \ +static const builtin_prop_t NAME ##_props[] = { \ + {L"buffer", NULL, 0, TypedArray_get_buffer}, \ + {L"byteLength", NULL, 0, TypedArray_get_byteLength}, \ + {L"byteOffset", NULL, 0, TypedArray_get_byteOffset}, \ + {L"length", NULL, 0, TypedArray_get_length}, \ + {L"set", NAME ##_set, PROPF_METHOD|2}, \ + {L"subarray", NAME ##_subarray, PROPF_METHOD|2}, \ +}; +TYPEDARRAY_LIST +#undef X + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) \ +[TYPEDARRAY_INDEX(JSCLASS)] = \ +{ \ + JSCLASS, \ + NULL, \ + ARRAY_SIZE(NAME ##_props), \ + NAME ##_props, \ + TypedArray_destructor, \ + NULL, \ + TypedArray_idx_length, \ + NAME ##_idx_get, \ + NAME ##_idx_put, \ + TypedArray_gc_traverse \ +}, +static const builtin_info_t TypedArray_info[] = { TYPEDARRAY_LIST }; +#undef X + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) \ +[TYPEDARRAY_INDEX(JSCLASS)] = \ +{ \ + JSCLASS, \ + NULL, \ + ARRAY_SIZE(TypedArrayInst_props), \ + TypedArrayInst_props, \ + TypedArray_destructor, \ + NULL, \ + TypedArray_idx_length, \ + NAME ##_idx_get, \ + NAME ##_idx_put, \ + TypedArray_gc_traverse \ +}, +static const builtin_info_t TypedArrayInst_info[] = { TYPEDARRAY_LIST }; +#undef X + +static HRESULT create_typedarr(script_ctx_t *ctx, jsclass_t jsclass, jsdisp_t *buffer, DWORD offset, DWORD length, + jsdisp_t **ret) +{ + TypedArrayInstance *typedarr; + HRESULT hres; + + if(!(typedarr = calloc(1, sizeof(TypedArrayInstance)))) + return E_OUTOFMEMORY; + + hres = init_dispex_from_constr(&typedarr->dispex, ctx, &TypedArrayInst_info[TYPEDARRAY_INDEX(jsclass)], + ctx->typedarr_constr[TYPEDARRAY_INDEX(jsclass)]); + if(FAILED(hres)) { + free(typedarr); + return hres; + } + + typedarr->buffer = jsdisp_addref(buffer); + typedarr->offset = offset; + typedarr->length = length; + + *ret = &typedarr->dispex; + return S_OK; +} + +static HRESULT TypedArrayConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r, jsclass_t jsclass) +{ + const unsigned typedarr_idx = TYPEDARRAY_INDEX(jsclass); + unsigned elem_size = TypedArray_elem_size[typedarr_idx]; + jsdisp_t *typedarr, *buffer = NULL; + DWORD offset = 0, length = 0; + HRESULT hres; + double n; + + TRACE("\n"); + + switch(flags) { + case DISPATCH_METHOD: + case DISPATCH_CONSTRUCT: { + if(argc) { + if(is_object_instance(argv[0])) { + jsdisp_t *obj = to_jsdisp(get_object(argv[0])); + + if(!obj) + return JS_E_TYPEDARRAY_BAD_CTOR_ARG; + + FIXME("Construction from object not implemented\n"); + return E_NOTIMPL; + }else if(is_number(argv[0])) { + hres = to_integer(ctx, argv[0], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + if(n * elem_size > (UINT_MAX - FIELD_OFFSET(ArrayBufferInstance, buf[0]))) + return E_OUTOFMEMORY; + length = n; + }else + return JS_E_TYPEDARRAY_BAD_CTOR_ARG; + } + + if(!r) + return S_OK; + + if(!buffer) { + hres = create_arraybuf(ctx, length * elem_size, &buffer); + if(FAILED(hres)) + return hres; + } + + hres = create_typedarr(ctx, jsclass, buffer, offset, length, &typedarr); + jsdisp_release(buffer); + if(FAILED(hres)) + return hres; + + *r = jsval_obj(typedarr); + break; + } + default: + FIXME("unimplemented flags: %x\n", flags); + return E_NOTIMPL; + } + + return S_OK; +} + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) \ +static HRESULT NAME ## Constr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) \ +{ \ + return TypedArrayConstr_value(ctx, vthis, flags, argc, argv, r, JSCLASS); \ +} +TYPEDARRAY_LIST +#undef X + +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) [TYPEDARRAY_INDEX(JSCLASS)] = NAME ## Constr_value, +static const builtin_invoke_t TypedArray_constr[] = { TYPEDARRAY_LIST }; +#undef X + +static const builtin_info_t TypedArrayConstr_info = { + JSCLASS_FUNCTION, + Function_value, + 0, + NULL, + NULL, + NULL +}; + HRESULT init_arraybuf_constructors(script_ctx_t *ctx) { static const struct { @@ -730,6 +1047,7 @@ HRESULT init_arraybuf_constructors(script_ctx_t *ctx) { L"byteOffset", DataView_get_byteOffset }, }; ArrayBufferInstance *arraybuf; + TypedArrayInstance *typedarr; DataViewInstance *view; property_desc_t desc; HRESULT hres; @@ -800,6 +1118,42 @@ HRESULT init_arraybuf_constructors(script_ctx_t *ctx) hres = jsdisp_define_data_property(ctx->global, L"DataView", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->dataview_constr)); + if(FAILED(hres)) + return hres; + + for(i = 0; i < ARRAY_SIZE(TypedArray_info); i++) { + if(!(typedarr = calloc(1, sizeof(TypedArrayInstance)))) + return E_OUTOFMEMORY; + + hres = create_arraybuf(ctx, 0, &typedarr->buffer); + if(FAILED(hres)) { + free(typedarr); + return hres; + } + + hres = init_dispex(&typedarr->dispex, ctx, &TypedArray_info[i], ctx->object_prototype); + if(FAILED(hres)) { + jsdisp_release(typedarr->buffer); + free(typedarr); + return hres; + } + + hres = create_builtin_constructor(ctx, TypedArray_constr[i], TypedArray_name[i], &TypedArrayConstr_info, + PROPF_CONSTR|1, &typedarr->dispex, &ctx->typedarr_constr[i]); + jsdisp_release(&typedarr->dispex); + if(FAILED(hres)) + return hres; + + hres = jsdisp_define_data_property(ctx->typedarr_constr[i], L"BYTES_PER_ELEMENT", 0, + jsval_number(TypedArray_elem_size[i])); + if(FAILED(hres)) + return hres; + + hres = jsdisp_define_data_property(ctx->global, TypedArray_name[i], PROPF_CONFIGURABLE | PROPF_WRITABLE, + jsval_obj(ctx->typedarr_constr[i])); + if(FAILED(hres)) + return hres; + } return hres; } diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 73a4a5bbecd..27745fb9178 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -17,6 +17,7 @@ */ #include +#include #include "jscript.h" #include "engine.h" @@ -109,6 +110,29 @@ static inline BOOL is_function_prop(dispex_prop_t *prop) return ret; } +static inline BOOL override_idx(jsdisp_t *This, const WCHAR *name, unsigned *ret_idx) +{ + /* Typed Arrays override every positive index */ + if(This->builtin_info->class >= FIRST_TYPEDARRAY_JSCLASS && This->builtin_info->class <= LAST_TYPEDARRAY_JSCLASS) { + const WCHAR *ptr; + unsigned idx = 0; + + for(ptr = name; is_digit(*ptr) && idx <= (UINT_MAX-9 / 10); ptr++) + idx = idx*10 + (*ptr-'0'); + if(!*ptr) { + *ret_idx = idx; + return TRUE; + }else { + while(is_digit(*ptr)) ptr++; + if(!*ptr) { + *ret_idx = UINT_MAX; + return TRUE; + } + } + } + return FALSE; +} + static DWORD get_flags(jsdisp_t *This, dispex_prop_t *prop) { if(prop->type == PROP_PROTREF) { @@ -633,6 +657,7 @@ static HRESULT fill_props(jsdisp_t *obj) static HRESULT fill_protrefs(jsdisp_t *This) { dispex_prop_t *iter, *prop; + unsigned idx; HRESULT hres; hres = fill_props(This); @@ -647,6 +672,8 @@ static HRESULT fill_protrefs(jsdisp_t *This) return hres; for(iter = This->prototype->props; iter < This->prototype->props+This->prototype->prop_cnt; iter++) { + if(override_idx(This, iter->name, &idx)) + continue; hres = find_prop_name(This, iter->hash, iter->name, FALSE, &prop); if(FAILED(hres)) return hres; @@ -2042,6 +2069,7 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bst { jsdisp_t *This = impl_from_IDispatchEx(iface); dispex_prop_t *prop; + unsigned idx; BOOL b; HRESULT hres; @@ -2050,6 +2078,9 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bst if(grfdex & ~(fdexNameCaseSensitive|fdexNameCaseInsensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) FIXME("Unsupported grfdex %lx\n", grfdex); + if(override_idx(This, bstrName, &idx)) + return S_OK; + hres = find_prop_name(This, string_hash(bstrName), bstrName, grfdex & fdexNameCaseInsensitive, &prop); if(FAILED(hres)) return hres; @@ -2313,9 +2344,17 @@ jsdisp_t *iface_to_jsdisp(IDispatch *iface) HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID *id) { dispex_prop_t *prop; + unsigned idx; HRESULT hres; - if(jsdisp->extensible && (flags & fdexNameEnsure)) + if(override_idx(jsdisp, name, &idx)) { + if(idx >= jsdisp->builtin_info->idx_length(jsdisp)) { + *id = DISPID_UNKNOWN; + return DISP_E_UNKNOWNNAME; + } + hres = find_prop_name(jsdisp, string_hash(name), name, FALSE, &prop); + } + else if(jsdisp->extensible && (flags & fdexNameEnsure)) hres = ensure_prop_name(jsdisp, name, PROPF_ENUMERABLE | PROPF_CONFIGURABLE | PROPF_WRITABLE, flags & fdexNameCaseInsensitive, &prop); else @@ -2608,8 +2647,12 @@ HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, jsval_t vthis, WORD HRESULT jsdisp_propput(jsdisp_t *obj, const WCHAR *name, DWORD flags, BOOL throw, jsval_t val) { dispex_prop_t *prop; + unsigned idx; HRESULT hres; + if(override_idx(obj, name, &idx)) + return obj->builtin_info->idx_put(obj, idx, val); + if(obj->extensible) hres = ensure_prop_name(obj, name, flags, FALSE, &prop); else @@ -2712,8 +2755,12 @@ HRESULT disp_propput_name(script_ctx_t *ctx, IDispatch *disp, const WCHAR *name, HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val) { dispex_prop_t *prop; + unsigned idx; HRESULT hres; + if(override_idx(obj, name, &idx)) + return obj->builtin_info->idx_get(obj, idx, val); + hres = find_prop_name_prot(obj, string_hash(name), name, FALSE, &prop); if(FAILED(hres)) return hres; @@ -2732,6 +2779,9 @@ HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r) dispex_prop_t *prop; HRESULT hres; + if(obj->builtin_info->class >= FIRST_TYPEDARRAY_JSCLASS && obj->builtin_info->class <= LAST_TYPEDARRAY_JSCLASS) + return obj->builtin_info->idx_get(obj, idx, r); + swprintf(name, ARRAY_SIZE(name), L"%d", idx); hres = find_prop_name_prot(obj, string_hash(name), name, FALSE, &prop); @@ -2789,6 +2839,9 @@ HRESULT jsdisp_delete_idx(jsdisp_t *obj, DWORD idx) BOOL b; HRESULT hres; + if(obj->builtin_info->class >= FIRST_TYPEDARRAY_JSCLASS && obj->builtin_info->class <= LAST_TYPEDARRAY_JSCLASS) + return S_OK; + swprintf(buf, ARRAY_SIZE(buf), L"%d", idx); hres = find_prop_name(obj, string_hash(buf), buf, FALSE, &prop); @@ -2880,6 +2933,7 @@ HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL if(jsdisp) { dispex_prop_t *prop; const WCHAR *ptr; + unsigned idx; ptr = jsstr_flatten(name); if(!ptr) { @@ -2887,12 +2941,17 @@ HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL return E_OUTOFMEMORY; } - hres = find_prop_name(jsdisp, string_hash(ptr), ptr, FALSE, &prop); - if(prop) { - hres = delete_prop(prop, ret); - }else { - *ret = TRUE; + if(override_idx(jsdisp, ptr, &idx)) { + *ret = FALSE; hres = S_OK; + }else { + hres = find_prop_name(jsdisp, string_hash(ptr), ptr, FALSE, &prop); + if(prop) { + hres = delete_prop(prop, ret); + }else { + *ret = TRUE; + hres = S_OK; + } } jsdisp_release(jsdisp); @@ -2932,8 +2991,25 @@ HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_onl property_desc_t *desc) { dispex_prop_t *prop; + unsigned idx; HRESULT hres; + if(override_idx(obj, name, &idx)) { + if(idx >= obj->builtin_info->idx_length(obj)) + return DISP_E_UNKNOWNNAME; + + memset(desc, 0, sizeof(*desc)); + if(!flags_only) { + hres = obj->builtin_info->idx_get(obj, idx, &desc->value); + if(FAILED(hres)) + return hres; + } + desc->flags = PROPF_ENUMERABLE | PROPF_WRITABLE; + desc->mask = PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE; + desc->explicit_value = TRUE; + return S_OK; + } + hres = find_prop_name(obj, string_hash(name), name, FALSE, &prop); if(FAILED(hres)) return hres; @@ -2976,8 +3052,19 @@ HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_onl HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t *desc) { dispex_prop_t *prop; + unsigned idx; HRESULT hres; + if(override_idx(obj, name, &idx)) { + if((desc->flags & desc->mask) != (desc->mask & (PROPF_WRITABLE | PROPF_ENUMERABLE))) + return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name); + if(desc->explicit_value) + return obj->builtin_info->idx_put(obj, idx, desc->value); + if(desc->explicit_getter || desc->explicit_setter) + return throw_error(obj->ctx, JS_E_NONCONFIGURABLE_REDEFINED, name); + return obj->builtin_info->idx_put(obj, idx, jsval_undefined()); + } + hres = find_prop_name(obj, string_hash(name), name, FALSE, &prop); if(FAILED(hres)) return hres; diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index 53fe63746e3..f8633774d89 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -482,6 +482,8 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_OBJECT_NONEXTENSIBLE: case JS_E_NONCONFIGURABLE_REDEFINED: case JS_E_NONWRITABLE_MODIFIED: + case JS_E_TYPEDARRAY_BAD_CTOR_ARG: + case JS_E_NOT_TYPEDARRAY: case JS_E_NOT_DATAVIEW: case JS_E_DATAVIEW_NO_ARGUMENT: case JS_E_ARRAYBUFFER_EXPECTED: @@ -494,6 +496,7 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_FRACTION_DIGITS_OUT_OF_RANGE: case JS_E_PRECISION_OUT_OF_RANGE: case JS_E_INVALID_LENGTH: + case JS_E_TYPEDARRAY_INVALID_OFFSLEN: case JS_E_DATAVIEW_INVALID_ACCESS: case JS_E_DATAVIEW_INVALID_OFFSET: constr = ctx->range_error_constr; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 9066dc9fa54..571a77c0808 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -117,10 +117,23 @@ typedef enum { JSCLASS_JSON, JSCLASS_ARRAYBUFFER, JSCLASS_DATAVIEW, + JSCLASS_INT8ARRAY, + JSCLASS_INT16ARRAY, + JSCLASS_INT32ARRAY, + JSCLASS_UINT8ARRAY, + JSCLASS_UINT16ARRAY, + JSCLASS_UINT32ARRAY, + JSCLASS_FLOAT32ARRAY, + JSCLASS_FLOAT64ARRAY, JSCLASS_MAP, JSCLASS_SET, + + FIRST_TYPEDARRAY_JSCLASS = JSCLASS_INT8ARRAY, + LAST_TYPEDARRAY_JSCLASS = JSCLASS_FLOAT64ARRAY, } jsclass_t; +enum { NUM_TYPEDARRAY_TYPES = LAST_TYPEDARRAY_JSCLASS - FIRST_TYPEDARRAY_JSCLASS + 1 }; + jsdisp_t *iface_to_jsdisp(IDispatch*) DECLSPEC_HIDDEN; typedef HRESULT (*builtin_invoke_t)(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*); @@ -419,10 +432,11 @@ struct _script_ctx_t { jsdisp_t *vbarray_constr; jsdisp_t *arraybuf_constr; jsdisp_t *dataview_constr; + jsdisp_t *typedarr_constr[NUM_TYPEDARRAY_TYPES]; jsdisp_t *map_prototype; jsdisp_t *set_prototype; }; - jsdisp_t *global_objects[24]; + jsdisp_t *global_objects[24 + NUM_TYPEDARRAY_TYPES]; }; }; C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, set_prototype) == RTL_SIZEOF_THROUGH_FIELD(script_ctx_t, global_objects)); @@ -542,6 +556,9 @@ static inline DWORD make_grfdex(script_ctx_t *ctx, DWORD flags) #define JS_E_OBJECT_NONEXTENSIBLE MAKE_JSERROR(IDS_OBJECT_NONEXTENSIBLE) #define JS_E_NONCONFIGURABLE_REDEFINED MAKE_JSERROR(IDS_NONCONFIGURABLE_REDEFINED) #define JS_E_NONWRITABLE_MODIFIED MAKE_JSERROR(IDS_NONWRITABLE_MODIFIED) +#define JS_E_TYPEDARRAY_BAD_CTOR_ARG MAKE_JSERROR(IDS_TYPEDARRAY_BAD_CTOR_ARG) +#define JS_E_NOT_TYPEDARRAY MAKE_JSERROR(IDS_NOT_TYPEDARRAY) +#define JS_E_TYPEDARRAY_INVALID_OFFSLEN MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_OFFSLEN) #define JS_E_NOT_DATAVIEW MAKE_JSERROR(IDS_NOT_DATAVIEW) #define JS_E_DATAVIEW_NO_ARGUMENT MAKE_JSERROR(IDS_DATAVIEW_NO_ARGUMENT) #define JS_E_DATAVIEW_INVALID_ACCESS MAKE_JSERROR(IDS_DATAVIEW_INVALID_ACCESS) diff --git a/dlls/jscript/jscript.rc b/dlls/jscript/jscript.rc index acc2626a89d..2139fcdbbe8 100644 --- a/dlls/jscript/jscript.rc +++ b/dlls/jscript/jscript.rc @@ -75,6 +75,9 @@ STRINGTABLE IDS_OBJECT_NONEXTENSIBLE "Cannot define property '|': object is not extensible" IDS_NONCONFIGURABLE_REDEFINED "Cannot redefine non-configurable property '|'" IDS_NONWRITABLE_MODIFIED "Cannot modify non-writable property '|'" + IDS_NOT_TYPEDARRAY "'this' is not a typed array object" + IDS_TYPEDARRAY_BAD_CTOR_ARG "Typed array constructor argument is invalid" + IDS_TYPEDARRAY_INVALID_OFFSLEN "Invalid offset/length when creating typed array" IDS_NOT_DATAVIEW "'this' is not a DataView object" IDS_DATAVIEW_NO_ARGUMENT "Required argument offset or value in DataView method is not specified" IDS_DATAVIEW_INVALID_ACCESS "DataView operation access beyond specified buffer length" diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index cba35927378..cb374e0441d 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -52,6 +52,14 @@ static HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns L"[object Object]", L"[object ArrayBuffer]", L"[object Object]", + L"[object Int8Array]", + L"[object Int16Array]", + L"[object Int32Array]", + L"[object Uint8Array]", + L"[object Uint16Array]", + L"[object Uint32Array]", + L"[object Float32Array]", + L"[object Float64Array]", L"[object Object]", L"[object Object]" }; diff --git a/dlls/jscript/resource.h b/dlls/jscript/resource.h index f9b8121deb4..401fb852d38 100644 --- a/dlls/jscript/resource.h +++ b/dlls/jscript/resource.h @@ -73,6 +73,9 @@ #define IDS_OBJECT_NONEXTENSIBLE 0x13D5 #define IDS_NONCONFIGURABLE_REDEFINED 0x13D6 #define IDS_NONWRITABLE_MODIFIED 0x13D7 +#define IDS_TYPEDARRAY_BAD_CTOR_ARG 0x13DA +#define IDS_NOT_TYPEDARRAY 0x13DB +#define IDS_TYPEDARRAY_INVALID_OFFSLEN 0x13DC #define IDS_NOT_DATAVIEW 0x13DF #define IDS_DATAVIEW_NO_ARGUMENT 0x13E0 #define IDS_DATAVIEW_INVALID_ACCESS 0x13E1 diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 08db6d488be..6ed780d9b0b 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -30,6 +30,9 @@ var JS_E_INVALID_LENGTH = 0x800a13a5; var JS_E_INVALID_WRITABLE_PROP_DESC = 0x800a13ac; var JS_E_NONCONFIGURABLE_REDEFINED = 0x800a13d6; var JS_E_NONWRITABLE_MODIFIED = 0x800a13d7; +var JS_E_TYPEDARRAY_BAD_CTOR_ARG = 0x800a13da; +var JS_E_NOT_TYPEDARRAY = 0x800a13db; +var JS_E_TYPEDARRAY_INVALID_OFFSLEN = 0x800a13dc; var JS_E_NOT_DATAVIEW = 0x800a13df; var JS_E_DATAVIEW_NO_ARGUMENT = 0x800a13e0; var JS_E_DATAVIEW_INVALID_ACCESS = 0x800a13e1; @@ -1617,7 +1620,7 @@ sync_test("isFrozen", function() { }); sync_test("ArrayBuffers & Views", function() { - var i, r, buf, buf2, view, view2, arr; + var i, r, buf, buf2, view, view2, arr, arr2; var types = [ [ "Int8", 1 ], @@ -1960,6 +1963,190 @@ sync_test("ArrayBuffers & Views", function() { ok(r === undefined, "buf.slice(-9) view(1).setFloat64(0, 11.875) returned " + r); r = view2.getFloat64(0); ok(r === 11.875, "buf.slice(-9) view(1).getFloat64(0) returned " + r); + + for(i = 0; i < types.length; i++) { + var arrType = types[i][0] + "Array", typeSz = types[i][1]; + test_own_props(arrType, [ "BYTES_PER_ELEMENT" ]); + test_not_own_props(arrType, [ "from", "of" ]); + test_own_props(arrType + ".prototype", [ "buffer", "byteLength", "byteOffset", "length", "set", "subarray" ]); + test_not_own_props(arrType + ".prototype", [ + "at", "copyWithin", "entries", "every", "fill", "filter", "find", "findIndex", "forEach", + "includes", "indexOf", "join", "keys", "lastIndexOf", "map", "reduce", "reduceRight", + "reverse", "slice", "some", "sort", "toLocaleString", "toString", "values" + ]); + + arr = eval(arrType); + test_own_data_prop_desc(arr, "BYTES_PER_ELEMENT", false, false, false); + ok(arr.BYTES_PER_ELEMENT === typeSz, arrType + ".BYTES_PER_ELEMENT = " + arr.BYTES_PER_ELEMENT); + r = arr.length; + ok(r === 1, arrType + ".length = " + r); + r = arr.prototype.set.length; + ok(r === 2, arrType + ".prototype.set.length = " + r); + r = arr.prototype.subarray.length; + ok(r === 2, arrType + ".prototype.subarray.length = " + r); + + r = eval("Object.getPrototypeOf(" + arrType + ")"); + ok(r === Function.prototype, arrType + "'s prototype is not Function.prototype: " + r); + r = eval("Object.getPrototypeOf(" + arrType + ".prototype)"); + ok(r === Object.prototype, arrType + ".prototype's prototype is not Object.prototype: " + r); + r = eval("Object.prototype.toString.call(new " + arrType + "(3))"); + ok(r === "[object " + arrType + "]", "Object toString(new " + arrType + "(3)) = " + r); + r = eval(arrType + ".prototype"); + test_own_data_prop_desc(r, "byteLength", false, false, false); + test_own_data_prop_desc(r, "byteOffset", false, false, false); + test_own_data_prop_desc(r, "length", false, false, false); + test_own_data_prop_desc(r, "buffer", false, false, false); + + try { + eval("new " + arrType + "(-1)"); + ok(false, "new " + arrType + "(-1) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, "new " + arrType + "(-1) threw " + n); + } + try { + eval("new " + arrType + "('9')"); + ok(false, "new " + arrType + "('9') did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_BAD_CTOR_ARG, "new " + arrType + "('9') threw " + n); + } + try { + eval("new " + arrType + "(null)"); + ok(false, "new " + arrType + "(null) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_BAD_CTOR_ARG, "new " + arrType + "(null) threw " + n); + } + + arr = eval("new " + arrType + "()"); + ok(arr.byteLength === 0, arrType + "().byteLength = " + arr.byteLength); + ok(arr.byteOffset === 0, arrType + "().byteOffset = " + arr.byteOffset); + ok(arr.length === 0, arrType + "().length = " + arr.length); + ok(arr.buffer.byteLength === 0, arrType + "().buffer.byteLength = " + arr.buffer.byteLength); + test_readonly(arr, "byteLength", 0); + test_readonly(arr, "byteOffset", 0); + test_readonly(arr, "length", 0); + test_own_data_prop_desc(arr, "byteLength", false, false, false); + test_own_data_prop_desc(arr, "byteOffset", false, false, false); + test_own_data_prop_desc(arr, "length", false, false, false); + test_own_data_prop_desc(arr, "buffer", false, false, false); + + Object.freeze(arr); + ok(Object.isFrozen(arr) === true, arrType + "() not frozen"); + + arr = eval(arrType + "(9.1)"); + ok(arr.byteLength === 9 * typeSz, arrType + "(9.1).byteLength = " + arr.byteLength); + ok(arr.byteOffset === 0, arrType + "(9.1).byteOffset = " + arr.byteOffset); + ok(arr.length === 9, arrType + "(9.1).length = " + arr.length); + ok(arr.buffer.byteLength === arr.byteLength, arrType + "(9.1).buffer.byteLength = " + arr.buffer.byteLength); + for(var j = 0; j < 9; j++) + ok(arr[j] === 0, "arr[" + j + "] = " + arr[j]); + arr[5] = 42; + ok(arr[5] === 42, arrType + "(9.1)[5] = " + arr[5]); + arr[9] = 50; + ok(arr[9] === undefined, arrType + "(9.1)[9] = " + arr[9]); + + eval(arrType + ".prototype[6] = 'foo'"); + r = eval(arrType + ".prototype[6]"); + ok(r === undefined, arrType + ".prototype[6] = " + r); + ok(arr[6] === 0, arrType + "(9.1)[6] after set in prototype = " + arr[6]); + arr[6] = 0; + ok(Object.prototype.hasOwnProperty.call(arr, "6"), "'6' not a property of " + arrType + "(9.1)[6]"); + test_own_data_prop_desc(arr, "6", true, true, false); + r = (delete arr[6]); + ok(r === false, "delete " + arrType + "(9.1)[6] returned " + r); + try { + Object.defineProperty(arr, "6", {writable: false, enumerable: false, configurable: true, value: 10}); + ok(false, "redefining " + arrType + "(9.1)[6] with different flags did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NONCONFIGURABLE_REDEFINED, "redefining " + arrType + "(9.1)[6] with different flags threw " + n); + } + Object.defineProperty(arr, "6", {writable: true, enumerable: true, configurable: false, value: 10}); + ok(arr[6] === 10, arrType + "(9.1)[6] after definition = " + arr[6]); + Object.defineProperty(arr, "6", {writable: true, enumerable: true, configurable: false, value: "foo"}); + if(arrType.substr(0, 5) === "Float") + ok(arr[6] !== arr[6] /* NaN */, arrType + "(9.1)[6] after definition to string = " + arr[6]); + else + ok(arr[6] === 0, arrType + "(9.1)[6] after definition to string = " + arr[6]); + + eval(arrType + ".prototype[100] = 'foobar'"); + r = eval(arrType + ".prototype[100]"); + ok(r === undefined, arrType + ".prototype[100] = " + r); + ok(arr[100] === undefined, arrType + "(9.1)[100] after set in prototype = " + arr[100]); + arr[100] = 0; + ok(arr[100] === undefined, arrType + "(9.1)[100] after set to zero = " + arr[100]); + ok(!Object.prototype.hasOwnProperty.call(arr, "100"), "'100' is a property of " + arrType + "(9.1)[100]"); + r = (delete arr[100]); + ok(r === false, "delete " + arrType + "(9.1)[100] returned " + r); + try { + Object.defineProperty(arr, "100", {writable: false, enumerable: false, configurable: true, value: 10}); + ok(false, "redefining " + arrType + "(9.1)[100] with different flags did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NONCONFIGURABLE_REDEFINED, "redefining " + arrType + "(9.1)[100] with different flags threw " + n); + } + Object.defineProperty(arr, "100", {writable: true, enumerable: true, configurable: false, value: 10}); + ok(arr[100] === undefined, arrType + "(9.1)[100] after defined to 10 = " + arr[100]); + ok(!Object.prototype.hasOwnProperty.call(arr, "100"), "'100' is a property of " + arrType + "(9.1)[100] after definition"); + ok(arr[100] === undefined, arrType + "(9.1)[100] after definition = " + arr[100]); + + r = 0; + for(var idx in arr) { + ok(idx === ""+r, arrType + "(9.1) enum idx " + r + " = " + idx); + r++; + } + ok(r === 9, arrType + "(9.1) enum did " + r + " iterations"); + + eval(arrType + ".prototype[-1] = 'barfoo'"); + r = eval(arrType + ".prototype[-1]"); + ok(r === "barfoo", arrType + ".prototype[-1] = " + r); + ok(arr[-1] === "barfoo", arrType + "(9.1)[-1] after set in prototype = " + arr[-1]); + + eval(arrType + ".prototype.foo = 'bar'"); + r = eval(arrType + ".prototype.foo = 'bar'"); + ok(r === "bar", arrType + ".prototype.foo = " + r); + ok(arr.foo === "bar", arrType + "(9.1).foo after set in prototype = " + arr.foo); + Object.freeze(arr); + ok(Object.isFrozen(arr) === true, arrType + "(9.1) not frozen"); + arr = eval(arrType + ".prototype"); + delete arr[-1]; + delete arr.foo; + } + + arr = new Int16Array(2); + arr[0] = 65535; + arr[1] = -65535; + ok(arr[0] == -1, "16-bit arr[0] after overflow = " + arr[0]); + ok(arr[1] == 1, "16-bit arr[1] after overflow = " + arr[1]); + + arr = new Uint8Array(2); + arr[0] = -2; + arr[1] = 258; + ok(arr[0] == 254, "8-bit arr[0] after overflow = " + arr[0]); + ok(arr[1] == 2, "8-bit arr[1] after overflow = " + arr[1]); + + arr = new Int8Array(); + arr2 = new Int32Array(); + + /* methods are incompatible, even though thrown error is not explicit */ + ok(Uint16Array.prototype.subarray !== Int32Array.prototype.subarray, "Uint16Array and Int32Array have same subarray methods"); + ok(Int8Array.prototype.set !== Float32Array.prototype.set, "Int8Array and Float32Array have same set methods"); + try { + Uint8Array.prototype.set.call(arr, [12, 50]); + ok(false, "calling Uint8Array's set with Int8Array context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_TYPEDARRAY, "calling Uint8Array's set with Int8Array context threw " + n); + } + try { + Uint32Array.prototype.subarray.call(arr2, 0); + ok(false, "calling Uint32Array's subarray with Int32Array context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_TYPEDARRAY, "calling Uint32Array's subarray with Int32Array context threw " + n); + } }); sync_test("builtin_context", function() { From 8805a5d01d5d3428bb6f626ff600f0a699557122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:59 +0200 Subject: [PATCH 0848/2777] jscript: Implement Typed Array construction on ArrayBuffers. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/arraybuf.c | 35 ++++++++++++++++++++++-- dlls/mshtml/tests/es5.js | 57 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 8d3c56a27ca..bb086609267 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -975,8 +975,39 @@ static HRESULT TypedArrayConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD fla if(!obj) return JS_E_TYPEDARRAY_BAD_CTOR_ARG; - FIXME("Construction from object not implemented\n"); - return E_NOTIMPL; + if(obj->builtin_info->class == JSCLASS_ARRAYBUFFER) { + ArrayBufferInstance *arraybuf = arraybuf_from_jsdisp(obj); + + if(argc > 1) { + hres = to_integer(ctx, argv[1], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0 || n > arraybuf->size) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + offset = n; + if(offset % elem_size) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + } + if(argc > 2 && !is_undefined(argv[2])) { + hres = to_integer(ctx, argv[2], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0 || n > UINT_MAX) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + length = n; + if(offset + length * elem_size > arraybuf->size) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + }else { + length = arraybuf->size - offset; + if(length % elem_size) + return JS_E_TYPEDARRAY_INVALID_OFFSLEN; + length /= elem_size; + } + buffer = jsdisp_addref(&arraybuf->dispex); + }else { + FIXME("Construction from object not implemented\n"); + return E_NOTIMPL; + } }else if(is_number(argv[0])) { hres = to_integer(ctx, argv[0], &n); if(FAILED(hres)) diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 6ed780d9b0b..0921d029ee2 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -1997,6 +1997,7 @@ sync_test("ArrayBuffers & Views", function() { test_own_data_prop_desc(r, "length", false, false, false); test_own_data_prop_desc(r, "buffer", false, false, false); + buf = ArrayBuffer(34); try { eval("new " + arrType + "(-1)"); ok(false, "new " + arrType + "(-1) did not throw exception"); @@ -2004,6 +2005,27 @@ sync_test("ArrayBuffers & Views", function() { var n = ex.number >>> 0; ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, "new " + arrType + "(-1) threw " + n); } + try { + eval("new " + arrType + "(buf, -1)"); + ok(false, "new " + arrType + "(buf, -1) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, "new " + arrType + "(buf, -1) threw " + n); + } + try { + eval("new " + arrType + "(buf, 36)"); + ok(false, "new " + arrType + "(buf, 36) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, "new " + arrType + "(buf, 36) threw " + n); + } + try { + eval("new " + arrType + "(buf, 32, 4)"); + ok(false, "new " + arrType + "(buf, 32, 4) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, "new " + arrType + "(buf, 32, 4) threw " + n); + } try { eval("new " + arrType + "('9')"); ok(false, "new " + arrType + "('9') did not throw exception"); @@ -2018,6 +2040,26 @@ sync_test("ArrayBuffers & Views", function() { var n = ex.number >>> 0; ok(n === JS_E_TYPEDARRAY_BAD_CTOR_ARG, "new " + arrType + "(null) threw " + n); } + if(typeSz > 1) { + /* test misalignment */ + var a = typeSz >>> 1; + try { + eval("new " + arrType + "(buf, a, 1)"); + ok(false, "new " + arrType + "(buf, " + a + ", 1) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, "new " + arrType + "(buf, " + a + ", 1) threw " + n); + } + a += typeSz; + var b = new ArrayBuffer(a); + try { + eval("new " + arrType + "(b)"); + ok(false, "new " + arrType + "(new ArrayBuffer(" + a + ")) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, "new " + arrType + "(new ArrayBuffer(" + a + ")) threw " + n); + } + } arr = eval("new " + arrType + "()"); ok(arr.byteLength === 0, arrType + "().byteLength = " + arr.byteLength); @@ -2113,6 +2155,21 @@ sync_test("ArrayBuffers & Views", function() { arr = eval(arrType + ".prototype"); delete arr[-1]; delete arr.foo; + + name = arrType + "(buf, " + typeSz + ", 2)"; + arr = eval(name); + ok(arr.byteLength === 2 * typeSz, name + ".byteLength = " + arr.byteLength); + ok(arr.byteOffset === typeSz, name + ".byteOffset = " + arr.byteOffset); + ok(arr.length === 2, name + ".length = " + arr.length); + ok(arr.buffer === buf, name + ".buffer = " + arr.buffer); + view = DataView(buf); + view["set" + types[i][0]](typeSz, 10, true); + ok(arr[0] === 10, "arr[0] after DataView(buf).set" + types[i][0] + " = " + arr[0]); + arr[0] = 12; + r = view["get" + types[i][0]](typeSz, true); + ok(r === 12, "DataView(buf).get" + types[i][0] + " after arr[0] set = " + r); + Object.freeze(arr); + ok(Object.isFrozen(arr) === true, name + " not frozen"); } arr = new Int16Array(2); From 03a43f11bc9cd26cdcc17b9e4ec347c26bb3fc4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:59 +0200 Subject: [PATCH 0849/2777] jscript: Implement ArrayBuffer.isView. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/arraybuf.c | 15 +++++++++++++-- dlls/jscript/jscript.h | 2 ++ dlls/mshtml/tests/es5.js | 13 +++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index bb086609267..c50638652c8 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -179,9 +179,20 @@ static HRESULT create_arraybuf(script_ctx_t *ctx, DWORD size, jsdisp_t **ret) static HRESULT ArrayBufferConstr_isView(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { - FIXME("not implemented\n"); + BOOL ret = FALSE; + jsdisp_t *obj; - return E_NOTIMPL; + TRACE("\n"); + + if(!r) + return S_OK; + + if(argc && is_object_instance(argv[0]) && (obj = to_jsdisp(get_object(argv[0]))) && + obj->builtin_info->class >= FIRST_VIEW_JSCLASS && obj->builtin_info->class <= LAST_VIEW_JSCLASS) + ret = TRUE; + + *r = jsval_bool(ret); + return S_OK; } static HRESULT ArrayBufferConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 571a77c0808..4719b8bbb1e 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -130,6 +130,8 @@ typedef enum { FIRST_TYPEDARRAY_JSCLASS = JSCLASS_INT8ARRAY, LAST_TYPEDARRAY_JSCLASS = JSCLASS_FLOAT64ARRAY, + FIRST_VIEW_JSCLASS = JSCLASS_DATAVIEW, + LAST_VIEW_JSCLASS = JSCLASS_FLOAT64ARRAY, } jsclass_t; enum { NUM_TYPEDARRAY_TYPES = LAST_TYPEDARRAY_JSCLASS - FIRST_TYPEDARRAY_JSCLASS + 1 }; diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 0921d029ee2..246b8fe821e 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -1696,6 +1696,13 @@ sync_test("ArrayBuffers & Views", function() { test_readonly(buf, "byteLength", 10); test_own_data_prop_desc(buf, "byteLength", false, false, false); + ok(ArrayBuffer.isView() === false, "ArrayBuffer.isView() returned true"); + ok(ArrayBuffer.isView([]) === false, "ArrayBuffer.isView([]) returned true"); + ok(ArrayBuffer.isView({}) === false, "ArrayBuffer.isView({}) returned true"); + ok(ArrayBuffer.isView(undefined) === false, "ArrayBuffer.isView(undefined) returned true"); + ok(ArrayBuffer.isView(null) === false, "ArrayBuffer.isView(null) returned true"); + ok(ArrayBuffer.isView(buf) === false, "ArrayBuffer.isView(ArrayBuffer) returned true"); + test_own_props("DataView.prototype", [ "buffer", "byteLength", "byteOffset", "getInt8", "setInt8", "getUint8", "setUint8", @@ -1816,6 +1823,9 @@ sync_test("ArrayBuffers & Views", function() { ok(view.byteLength === 10, "DataView(buf).byteLength = " + view.byteLength); ok(view.byteOffset === 0, "DataView(buf).byteOffset = " + view.byteOffset); + ok(ArrayBuffer.isView(DataView) === false, "ArrayBuffer.isView(DataView) returned true"); + ok(ArrayBuffer.isView(view) === true, "ArrayBuffer.isView(DataView(buf)) returned false"); + for(i = 0; i < 10; i++) { r = view.getInt8(i); ok(r === 0, "view byte " + i + " = " + r); @@ -1950,6 +1960,8 @@ sync_test("ArrayBuffers & Views", function() { ok(buf2.byteLength === 9, "buf.slice(-9).byteLength = " + buf2.byteLength); view2 = DataView(buf2, 1); ok(view2.byteLength === 8, "buf.slice(-9) view(1).byteLength = " + view2.byteLength); + ok(ArrayBuffer.isView(buf2) === false, "ArrayBuffer.isView(buf.slice(-9)) returned true"); + ok(ArrayBuffer.isView(view2) === true, "ArrayBuffer.isView(DataView(buf.slice(-9))) returned false"); r = view2.getUint32(0); ok(r === 4294967040, "buf.slice(-9) view(1).getUint32(0) returned " + r); @@ -2074,6 +2086,7 @@ sync_test("ArrayBuffers & Views", function() { test_own_data_prop_desc(arr, "length", false, false, false); test_own_data_prop_desc(arr, "buffer", false, false, false); + ok(ArrayBuffer.isView(arr) === true, "ArrayBuffer.isView(" + arrType + "()) returned false"); Object.freeze(arr); ok(Object.isFrozen(arr) === true, arrType + "() not frozen"); From 6f0198668880cb27c70bf3c8a6061748477f81e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:59 +0200 Subject: [PATCH 0850/2777] jscript: Implement Typed Array construction from objects. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- fill_typedarr_data_from_object will also be used for 'set'. --- dlls/jscript/arraybuf.c | 67 ++++++++++++++++++++++++++++++++++++++-- dlls/mshtml/tests/es5.js | 47 +++++++++++++++++++++++++++- 2 files changed, 111 insertions(+), 3 deletions(-) diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index c50638652c8..63a602c8638 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -18,6 +18,7 @@ #include +#include #include "jscript.h" @@ -801,6 +802,40 @@ static HRESULT TypedArray_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_ return S_OK; } +static HRESULT fill_typedarr_data_from_object(script_ctx_t *ctx, BYTE *data, jsdisp_t *obj, DWORD length, jsclass_t jsclass) +{ + HRESULT hres = S_OK; + jsval_t val; + UINT32 i; + + switch(jsclass) { +#define X(NAME, JSCLASS, TYPE, CONVERT, NUM_TYPE) \ + case JSCLASS: \ + for(i = 0; i < length; i++) { \ + NUM_TYPE n; \ + \ + hres = jsdisp_get_idx(obj, i, &val); \ + if(FAILED(hres)) { \ + if(hres != DISP_E_UNKNOWNNAME) \ + break; \ + val = jsval_undefined(); \ + } \ + \ + hres = CONVERT(ctx, val, &n); \ + jsval_release(val); \ + if(FAILED(hres)) \ + break; \ + *(TYPE*)&data[i * sizeof(TYPE)] = n; \ + } \ + break; + TYPEDARRAY_LIST + DEFAULT_UNREACHABLE; +#undef X + } + + return hres; +} + static HRESULT TypedArray_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r, jsclass_t jsclass) { @@ -1016,8 +1051,36 @@ static HRESULT TypedArrayConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD fla } buffer = jsdisp_addref(&arraybuf->dispex); }else { - FIXME("Construction from object not implemented\n"); - return E_NOTIMPL; + jsval_t val; + UINT32 len; + DWORD size; + + hres = jsdisp_propget_name(obj, L"length", &val); + if(FAILED(hres)) + return hres; + if(is_undefined(val)) + return JS_E_TYPEDARRAY_BAD_CTOR_ARG; + + hres = to_uint32(ctx, val, &len); + jsval_release(val); + if(FAILED(hres)) + return hres; + + length = len; + size = length * elem_size; + if(size < length || size > (UINT_MAX - FIELD_OFFSET(ArrayBufferInstance, buf[0]))) + return E_OUTOFMEMORY; + + hres = create_arraybuf(ctx, size, &buffer); + if(FAILED(hres)) + return hres; + + hres = fill_typedarr_data_from_object(ctx, arraybuf_from_jsdisp(buffer)->buf, + obj, length, jsclass); + if(FAILED(hres)) { + jsdisp_release(buffer); + return hres; + } } }else if(is_number(argv[0])) { hres = to_integer(ctx, argv[0], &n); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 246b8fe821e..a5536466e7a 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2052,6 +2052,13 @@ sync_test("ArrayBuffers & Views", function() { var n = ex.number >>> 0; ok(n === JS_E_TYPEDARRAY_BAD_CTOR_ARG, "new " + arrType + "(null) threw " + n); } + try { + eval("new " + arrType + "({})"); + ok(false, "new " + arrType + "({}) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_BAD_CTOR_ARG, "new " + arrType + "({}) threw " + n); + } if(typeSz > 1) { /* test misalignment */ var a = typeSz >>> 1; @@ -2169,6 +2176,23 @@ sync_test("ArrayBuffers & Views", function() { delete arr[-1]; delete arr.foo; + arr2 = { length: 4 }; + arr2[0] = 1.5; + arr2[1] = '3'; + arr2[3] = 12; + var name = arrType + "(array-like object)"; + arr = eval(arrType + "(arr2)"); + ok(arr.byteLength === 4 * typeSz, name + ".byteLength = " + arr.byteLength); + ok(arr.byteOffset === 0, name + ".byteOffset = " + arr.byteOffset); + ok(arr.length === 4, name + ".length = " + arr.length); + if(isNaN(arr[2])) { + ok(arr[0] === 1.5, name + "[0] = " + arr[0]); + ok(arr[1] === 3, name + "[1] = " + arr[1]); + ok(arr[3] === 12, name + "[3] = " + arr[3]); + }else + for(var j = 0; j < 4; j++) + ok(arr[j] === [1, 3, 0, 12][j], name + "[" + j + "] = " + arr[j]); + name = arrType + "(buf, " + typeSz + ", 2)"; arr = eval(name); ok(arr.byteLength === 2 * typeSz, name + ".byteLength = " + arr.byteLength); @@ -2183,7 +2207,28 @@ sync_test("ArrayBuffers & Views", function() { ok(r === 12, "DataView(buf).get" + types[i][0] + " after arr[0] set = " + r); Object.freeze(arr); ok(Object.isFrozen(arr) === true, name + " not frozen"); - } + + arr2 = eval(arrType + "(arr)"); + ok(arr2.byteLength === arr.byteLength, name + " copy.byteLength = " + arr2.byteLength); + ok(arr2.byteOffset === 0, name + " copy.byteOffset = " + arr2.byteOffset); + ok(arr2.length === arr.length, name + " copy.length = " + arr2.length); + ok(arr2.buffer !== arr.buffer, name + " copy.buffer = " + arr2.buffer); + } + + arr = new Float32Array(3); + arr[0] = 1.125; + arr[1] = 2.25; + arr[2] = 3.375; + arr2 = new Uint16Array(arr); + ok(arr[0] === 1.125, "arr[0] = " + arr[0]); + ok(arr[1] === 2.25, "arr[1] = " + arr[1]); + ok(arr[2] === 3.375, "arr[2] = " + arr[2]); + ok(arr2[0] === 1, "arr2[0] = " + arr2[0]); + ok(arr2[1] === 2, "arr2[1] = " + arr2[1]); + ok(arr2[2] === 3, "arr2[2] = " + arr2[2]); + arr2[0] = 100; + ok(arr[0] === 1.125, "arr[0] after arr2[0] changed = " + arr[0]); + ok(arr2[0] === 100, "arr2[0] after change = " + arr2[0]); arr = new Int16Array(2); arr[0] = 65535; From 9d931dfbd22a9197d657627f2ba79c3bc9c8781b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:59 +0200 Subject: [PATCH 0851/2777] jscript: Implement 'subarray' for Typed Arrays. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/arraybuf.c | 44 ++++++++++++++++++++++++++++++-- dlls/jscript/error.c | 1 + dlls/jscript/jscript.h | 1 + dlls/jscript/jscript.rc | 1 + dlls/jscript/resource.h | 1 + dlls/mshtml/tests/es5.js | 55 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 101 insertions(+), 2 deletions(-) diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 63a602c8638..489bfade2c7 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -770,6 +770,8 @@ static inline TypedArrayInstance *typedarr_this(jsval_t vthis, jsclass_t jsclass return (jsdisp && is_class(jsdisp, jsclass)) ? typedarr_from_jsdisp(jsdisp) : NULL; } +static HRESULT create_typedarr(script_ctx_t*,jsclass_t,jsdisp_t*,DWORD,DWORD,jsdisp_t**); + static HRESULT TypedArray_get_buffer(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) { TRACE("%p\n", jsthis); @@ -852,12 +854,50 @@ static HRESULT TypedArray_subarray(script_ctx_t *ctx, jsval_t vthis, WORD flags, jsval_t *r, jsclass_t jsclass) { TypedArrayInstance *typedarr; + DWORD begin = 0, end; + jsdisp_t *obj; + HRESULT hres; + double n; - FIXME("not implemented\n"); + TRACE("\n"); if(!(typedarr = typedarr_this(vthis, jsclass))) return JS_E_NOT_TYPEDARRAY; - return E_NOTIMPL; + if(!argc) + return JS_E_TYPEDARRAY_INVALID_SUBARRAY; + if(!r) + return S_OK; + + hres = to_integer(ctx, argv[0], &n); + if(FAILED(hres)) + return hres; + end = typedarr->length; + if(n < 0.0) + n += typedarr->length; + if(n >= 0.0) + begin = n < typedarr->length ? n : typedarr->length; + + if(argc > 1 && !is_undefined(argv[1])) { + hres = to_integer(ctx, argv[1], &n); + if(FAILED(hres)) + return hres; + if(n < 0.0) + n += typedarr->length; + if(n >= 0.0) { + end = n < typedarr->length ? n : typedarr->length; + end = end < begin ? begin : end; + }else + end = begin; + } + + hres = create_typedarr(ctx, jsclass, typedarr->buffer, + typedarr->offset + begin * TypedArray_elem_size[TYPEDARRAY_INDEX(jsclass)], + end - begin, &obj); + if(FAILED(hres)) + return hres; + + *r = jsval_obj(obj); + return S_OK; } static unsigned TypedArray_idx_length(jsdisp_t *jsdisp) diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index f8633774d89..8e813c55923 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -497,6 +497,7 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_PRECISION_OUT_OF_RANGE: case JS_E_INVALID_LENGTH: case JS_E_TYPEDARRAY_INVALID_OFFSLEN: + case JS_E_TYPEDARRAY_INVALID_SUBARRAY: case JS_E_DATAVIEW_INVALID_ACCESS: case JS_E_DATAVIEW_INVALID_OFFSET: constr = ctx->range_error_constr; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 4719b8bbb1e..220100aa345 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -561,6 +561,7 @@ static inline DWORD make_grfdex(script_ctx_t *ctx, DWORD flags) #define JS_E_TYPEDARRAY_BAD_CTOR_ARG MAKE_JSERROR(IDS_TYPEDARRAY_BAD_CTOR_ARG) #define JS_E_NOT_TYPEDARRAY MAKE_JSERROR(IDS_NOT_TYPEDARRAY) #define JS_E_TYPEDARRAY_INVALID_OFFSLEN MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_OFFSLEN) +#define JS_E_TYPEDARRAY_INVALID_SUBARRAY MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_SUBARRAY) #define JS_E_NOT_DATAVIEW MAKE_JSERROR(IDS_NOT_DATAVIEW) #define JS_E_DATAVIEW_NO_ARGUMENT MAKE_JSERROR(IDS_DATAVIEW_NO_ARGUMENT) #define JS_E_DATAVIEW_INVALID_ACCESS MAKE_JSERROR(IDS_DATAVIEW_INVALID_ACCESS) diff --git a/dlls/jscript/jscript.rc b/dlls/jscript/jscript.rc index 2139fcdbbe8..aee62c82c4e 100644 --- a/dlls/jscript/jscript.rc +++ b/dlls/jscript/jscript.rc @@ -78,6 +78,7 @@ STRINGTABLE IDS_NOT_TYPEDARRAY "'this' is not a typed array object" IDS_TYPEDARRAY_BAD_CTOR_ARG "Typed array constructor argument is invalid" IDS_TYPEDARRAY_INVALID_OFFSLEN "Invalid offset/length when creating typed array" + IDS_TYPEDARRAY_INVALID_SUBARRAY "Invalid begin/end value in typed array subarray method" IDS_NOT_DATAVIEW "'this' is not a DataView object" IDS_DATAVIEW_NO_ARGUMENT "Required argument offset or value in DataView method is not specified" IDS_DATAVIEW_INVALID_ACCESS "DataView operation access beyond specified buffer length" diff --git a/dlls/jscript/resource.h b/dlls/jscript/resource.h index 401fb852d38..04f7fbaff38 100644 --- a/dlls/jscript/resource.h +++ b/dlls/jscript/resource.h @@ -76,6 +76,7 @@ #define IDS_TYPEDARRAY_BAD_CTOR_ARG 0x13DA #define IDS_NOT_TYPEDARRAY 0x13DB #define IDS_TYPEDARRAY_INVALID_OFFSLEN 0x13DC +#define IDS_TYPEDARRAY_INVALID_SUBARRAY 0x13DD #define IDS_NOT_DATAVIEW 0x13DF #define IDS_DATAVIEW_NO_ARGUMENT 0x13E0 #define IDS_DATAVIEW_INVALID_ACCESS 0x13E1 diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index a5536466e7a..7972209cac2 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -33,6 +33,7 @@ var JS_E_NONWRITABLE_MODIFIED = 0x800a13d7; var JS_E_TYPEDARRAY_BAD_CTOR_ARG = 0x800a13da; var JS_E_NOT_TYPEDARRAY = 0x800a13db; var JS_E_TYPEDARRAY_INVALID_OFFSLEN = 0x800a13dc; +var JS_E_TYPEDARRAY_INVALID_SUBARRAY = 0x800a13dd; var JS_E_NOT_DATAVIEW = 0x800a13df; var JS_E_DATAVIEW_NO_ARGUMENT = 0x800a13e0; var JS_E_DATAVIEW_INVALID_ACCESS = 0x800a13e1; @@ -2213,6 +2214,60 @@ sync_test("ArrayBuffers & Views", function() { ok(arr2.byteOffset === 0, name + " copy.byteOffset = " + arr2.byteOffset); ok(arr2.length === arr.length, name + " copy.length = " + arr2.length); ok(arr2.buffer !== arr.buffer, name + " copy.buffer = " + arr2.buffer); + arr2 = arr.subarray(undefined, "1"); + ok(arr2.byteLength === typeSz, name + " subarray(undefined, '1').byteLength = " + arr2.byteLength); + ok(arr2.byteOffset === arr.byteOffset, name + " subarray(undefined, '1').byteOffset = " + arr2.byteOffset); + ok(arr2.length === 1, name + " subarray(undefined, '1').length = " + arr2.length); + ok(arr2.buffer === arr.buffer, name + " subarray(undefined, '1').buffer = " + arr2.buffer); + + name = arrType + "(10)"; + arr = eval(name); + try { + arr.subarray.call(null, 0); + ok(false, arrType + ": calling subarray with null context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_TYPEDARRAY, arrType + ": calling subarray with null context threw " + n); + } + try { + arr.subarray.call({}, 0); + ok(false, arrType + ": calling subarray with an object context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_TYPEDARRAY, arrType + ": calling subarray with an object context threw " + n); + } + try { + arr.subarray(); + ok(false, name + " subarray() did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_SUBARRAY, name + " subarray() threw " + n); + } + arr2 = arr.subarray(4); + ok(arr2.byteLength === 6 * typeSz, name + ".subarray(4).byteLength = " + arr2.byteLength); + ok(arr2.byteOffset === 4 * typeSz, name + ".subarray(4).byteOffset = " + arr2.byteOffset); + ok(arr2.length === 6, name + ".subarray(4).length = " + arr2.length); + ok(arr2.buffer === arr.buffer, name + ".subarray(4).buffer = " + arr2.buffer); + arr2 = arr.subarray(4, 2); + ok(arr2.byteLength === 0, name + ".subarray(4, 2).byteLength = " + arr2.byteLength); + ok(arr2.byteOffset === 4 * typeSz, name + ".subarray(4, 2).byteOffset = " + arr2.byteOffset); + ok(arr2.length === 0, name + ".subarray(4, 2).length = " + arr2.length); + ok(arr2.buffer === arr.buffer, name + ".subarray(4, 2).buffer = " + arr2.buffer); + arr2 = arr.subarray(-3, 100); + ok(arr2.byteLength === 3 * typeSz, name + ".subarray(-3, 100).byteLength = " + arr2.byteLength); + ok(arr2.byteOffset === 7 * typeSz, name + ".subarray(-3, 100).byteOffset = " + arr2.byteOffset); + ok(arr2.length === 3, name + ".subarray(-3, 100).length = " + arr2.length); + ok(arr2.buffer === arr.buffer, name + ".subarray(-3, 100).buffer = " + arr2.buffer); + arr2 = arr.subarray(42, -1); + ok(arr2.byteLength === 0, name + ".subarray(42, -1).byteLength = " + arr2.byteLength); + ok(arr2.byteOffset === 10 * typeSz, name + ".subarray(42, -1).byteOffset = " + arr2.byteOffset); + ok(arr2.length === 0, name + ".subarray(42, -1).length = " + arr2.length); + ok(arr2.buffer === arr.buffer, name + ".subarray(42, -1).buffer = " + arr2.buffer); + arr2 = arr.subarray(2, -3); + ok(arr2.byteLength === 5 * typeSz, name + ".subarray(2, -3).byteLength = " + arr2.byteLength); + ok(arr2.byteOffset === 2 * typeSz, name + ".subarray(2, -3).byteOffset = " + arr2.byteOffset); + ok(arr2.length === 5, name + ".subarray(2, -3).length = " + arr2.length); + ok(arr2.buffer === arr.buffer, name + ".subarray(2, -3).buffer = " + arr2.buffer); } arr = new Float32Array(3); From dd39d60faf531c5380d0ad572fc9f80bc948f9ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:59 +0200 Subject: [PATCH 0852/2777] jscript: Implement 'set' for Typed Arrays. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/arraybuf.c | 75 ++++++++++++++++++++++++++++++- dlls/jscript/error.c | 1 + dlls/jscript/jscript.h | 1 + dlls/jscript/jscript.rc | 1 + dlls/jscript/resource.h | 1 + dlls/mshtml/tests/es5.js | 97 +++++++++++++++++++++++++++++++++++++++- 6 files changed, 172 insertions(+), 4 deletions(-) diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 489bfade2c7..e8a7472c508 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -841,13 +841,84 @@ static HRESULT fill_typedarr_data_from_object(script_ctx_t *ctx, BYTE *data, jsd static HRESULT TypedArray_set(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r, jsclass_t jsclass) { + const unsigned elem_size = TypedArray_elem_size[TYPEDARRAY_INDEX(jsclass)]; TypedArrayInstance *typedarr; + DWORD begin = 0, size; + BYTE *dest, *data; + IDispatch *disp; + jsdisp_t *obj; + HRESULT hres; + jsval_t val; + UINT32 len; + double n; - FIXME("not implemented\n"); + TRACE("\n"); if(!(typedarr = typedarr_this(vthis, jsclass))) return JS_E_NOT_TYPEDARRAY; - return E_NOTIMPL; + if(!argc) + return JS_E_TYPEDARRAY_INVALID_SOURCE; + + hres = to_object(ctx, argv[0], &disp); + if(FAILED(hres)) + return JS_E_TYPEDARRAY_INVALID_SOURCE; + + if(!(obj = to_jsdisp(disp))) { + FIXME("Non-JS array object\n"); + hres = JS_E_TYPEDARRAY_INVALID_SOURCE; + goto done; + } + + hres = jsdisp_propget_name(obj, L"length", &val); + if(FAILED(hres)) + goto done; + + hres = to_uint32(ctx, val, &len); + jsval_release(val); + if(FAILED(hres)) + goto done; + + if(argc > 1) { + hres = to_integer(ctx, argv[1], &n); + if(FAILED(hres)) + goto done; + if(n < 0.0 || n > typedarr->length) { + hres = JS_E_TYPEDARRAY_INVALID_OFFSLEN; + goto done; + } + begin = n; + } + + if(len > typedarr->length - begin) { + hres = JS_E_TYPEDARRAY_INVALID_OFFSLEN; + goto done; + } + size = len * elem_size; + dest = data = &arraybuf_from_jsdisp(typedarr->buffer)->buf[typedarr->offset + begin * elem_size]; + + /* If they overlap, make a temporary copy */ + if(obj->builtin_info->class >= FIRST_TYPEDARRAY_JSCLASS && obj->builtin_info->class <= LAST_TYPEDARRAY_JSCLASS) { + TypedArrayInstance *src_arr = typedarr_from_jsdisp(obj); + const BYTE *src = arraybuf_from_jsdisp(src_arr->buffer)->buf + src_arr->offset; + + if(dest < src + len * TypedArray_elem_size[TYPEDARRAY_INDEX(obj->builtin_info->class)] && + dest + size > src) { + if(!(data = malloc(size))) { + hres = E_OUTOFMEMORY; + goto done; + } + } + } + + hres = fill_typedarr_data_from_object(ctx, data, obj, len, jsclass); + if(SUCCEEDED(hres) && dest != data) { + memcpy(dest, data, size); + free(data); + } + +done: + IDispatch_Release(disp); + return hres; } static HRESULT TypedArray_subarray(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index 8e813c55923..80b8f61e437 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -484,6 +484,7 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_NONWRITABLE_MODIFIED: case JS_E_TYPEDARRAY_BAD_CTOR_ARG: case JS_E_NOT_TYPEDARRAY: + case JS_E_TYPEDARRAY_INVALID_SOURCE: case JS_E_NOT_DATAVIEW: case JS_E_DATAVIEW_NO_ARGUMENT: case JS_E_ARRAYBUFFER_EXPECTED: diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 220100aa345..d11a25ad9a0 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -562,6 +562,7 @@ static inline DWORD make_grfdex(script_ctx_t *ctx, DWORD flags) #define JS_E_NOT_TYPEDARRAY MAKE_JSERROR(IDS_NOT_TYPEDARRAY) #define JS_E_TYPEDARRAY_INVALID_OFFSLEN MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_OFFSLEN) #define JS_E_TYPEDARRAY_INVALID_SUBARRAY MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_SUBARRAY) +#define JS_E_TYPEDARRAY_INVALID_SOURCE MAKE_JSERROR(IDS_TYPEDARRAY_INVALID_SOURCE) #define JS_E_NOT_DATAVIEW MAKE_JSERROR(IDS_NOT_DATAVIEW) #define JS_E_DATAVIEW_NO_ARGUMENT MAKE_JSERROR(IDS_DATAVIEW_NO_ARGUMENT) #define JS_E_DATAVIEW_INVALID_ACCESS MAKE_JSERROR(IDS_DATAVIEW_INVALID_ACCESS) diff --git a/dlls/jscript/jscript.rc b/dlls/jscript/jscript.rc index aee62c82c4e..4b6abbc5906 100644 --- a/dlls/jscript/jscript.rc +++ b/dlls/jscript/jscript.rc @@ -79,6 +79,7 @@ STRINGTABLE IDS_TYPEDARRAY_BAD_CTOR_ARG "Typed array constructor argument is invalid" IDS_TYPEDARRAY_INVALID_OFFSLEN "Invalid offset/length when creating typed array" IDS_TYPEDARRAY_INVALID_SUBARRAY "Invalid begin/end value in typed array subarray method" + IDS_TYPEDARRAY_INVALID_SOURCE "Invalid source in typed array set" IDS_NOT_DATAVIEW "'this' is not a DataView object" IDS_DATAVIEW_NO_ARGUMENT "Required argument offset or value in DataView method is not specified" IDS_DATAVIEW_INVALID_ACCESS "DataView operation access beyond specified buffer length" diff --git a/dlls/jscript/resource.h b/dlls/jscript/resource.h index 04f7fbaff38..9247f00f62b 100644 --- a/dlls/jscript/resource.h +++ b/dlls/jscript/resource.h @@ -77,6 +77,7 @@ #define IDS_NOT_TYPEDARRAY 0x13DB #define IDS_TYPEDARRAY_INVALID_OFFSLEN 0x13DC #define IDS_TYPEDARRAY_INVALID_SUBARRAY 0x13DD +#define IDS_TYPEDARRAY_INVALID_SOURCE 0x13DE #define IDS_NOT_DATAVIEW 0x13DF #define IDS_DATAVIEW_NO_ARGUMENT 0x13E0 #define IDS_DATAVIEW_INVALID_ACCESS 0x13E1 diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 7972209cac2..cef24052c9f 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -34,6 +34,7 @@ var JS_E_TYPEDARRAY_BAD_CTOR_ARG = 0x800a13da; var JS_E_NOT_TYPEDARRAY = 0x800a13db; var JS_E_TYPEDARRAY_INVALID_OFFSLEN = 0x800a13dc; var JS_E_TYPEDARRAY_INVALID_SUBARRAY = 0x800a13dd; +var JS_E_TYPEDARRAY_INVALID_SOURCE = 0x800a13de; var JS_E_NOT_DATAVIEW = 0x800a13df; var JS_E_DATAVIEW_NO_ARGUMENT = 0x800a13e0; var JS_E_DATAVIEW_INVALID_ACCESS = 0x800a13e1; @@ -2268,6 +2269,87 @@ sync_test("ArrayBuffers & Views", function() { ok(arr2.byteOffset === 2 * typeSz, name + ".subarray(2, -3).byteOffset = " + arr2.byteOffset); ok(arr2.length === 5, name + ".subarray(2, -3).length = " + arr2.length); ok(arr2.buffer === arr.buffer, name + ".subarray(2, -3).buffer = " + arr2.buffer); + + try { + arr.set.call(null, [1]); + ok(false, arrType + ": calling set with null context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_TYPEDARRAY, arrType + ": calling set with null context threw " + n); + } + try { + arr.set.call({}, [1]); + ok(false, arrType + ": calling set with an object context did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_NOT_TYPEDARRAY, arrType + ": calling set with an object context threw " + n); + } + try { + arr.set(); + ok(false, name + ".set() did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_SOURCE, name + ".set() threw " + n); + } + try { + arr.set(null); + ok(false, name + ".set(null) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_SOURCE, name + ".set(null) threw " + n); + } + try { + arr.set([1,2,3], 8); + ok(false, name + ".set([1,2,3], 8) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, name + ".set([1,2,3], 8) threw " + n); + } + try { + arr.set([99], -3); + ok(false, name + ".set([99], -3) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_TYPEDARRAY_INVALID_OFFSLEN, name + ".set([99], -3) threw " + n); + } + + r = arr.set(5); + ok(r === undefined, name + ".set(5) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === 0, name + ".set(5): arr[" + j + "] = " + arr[j]); + + r = arr.set({}); + ok(r === undefined, name + ".set({}) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === 0, name + ".set({}): arr[" + j + "] = " + arr[j]); + + r = arr.set("12"); + ok(r === undefined, name + ".set('12') returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === [ 1, 2, 0, 0, 0, 0, 0, 0, 0, 0 ][j], name + ".set('12'): arr[" + j + "] = " + arr[j]); + + arr2 = { length: 2 }; + arr2[0] = 9; + arr2[1] = 7; + r = arr.set(arr2); + ok(r === undefined, name + ".set(array-like obj) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === [ 9, 7, 0, 0, 0, 0, 0, 0, 0, 0 ][j], name + ".set(array-like obj): arr[" + j + "] = " + arr[j]); + + r = arr.set([12, 10, 11], 3); + ok(r === undefined, name + ".set([12, 10, 11], 3) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === [ 9, 7, 0, 12, 10, 11, 0, 0, 0, 0 ][j], name + ".set([12, 10, 11], 3): arr[" + j + "] = " + arr[j]); + + r = arr.set(arr.subarray(4, 6), 5); + ok(r === undefined, name + ".set(arr.subarray(4, 2), 5) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === [ 9, 7, 0, 12, 10, 10, 11, 0, 0, 0 ][j], name + ".set(arr.subarray(4, 2), 5): arr[" + j + "] = " + arr[j]); + + r = arr.set(arr.subarray(3, 7), 2); + ok(r === undefined, name + ".set(arr.subarray(3, 7), 2) returned " + r); + for(var j = 0; j < 10; j++) + ok(arr[j] === [ 9, 7, 12, 10, 10, 11, 11, 0, 0, 0 ][j], name + ".set(arr.subarray(3, 7), 2): arr[" + j + "] = " + arr[j]); } arr = new Float32Array(3); @@ -2297,8 +2379,19 @@ sync_test("ArrayBuffers & Views", function() { ok(arr[0] == 254, "8-bit arr[0] after overflow = " + arr[0]); ok(arr[1] == 2, "8-bit arr[1] after overflow = " + arr[1]); - arr = new Int8Array(); - arr2 = new Int32Array(); + arr = new Int8Array(12); + arr.set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); + for(var j = 0; j < 12; j++) + ok(arr[j] === j + 1, "sequential arr[" + j + "] = " + arr[j]); + arr2 = new Int32Array(arr.buffer); + ok(arr2.buffer === arr.buffer, "arr2.buffer = " + arr2.buffer); + for(var j = 0; j < 3; j++) + ok(arr2[j] === [ 0x04030201, 0x08070605, 0x0c0b0a09 ][j], "sequential 32-bit arr[" + j + "] = " + arr2[j]); + + /* test overlap */ + arr2.set(arr.subarray(1, 4)); + for(var j = 0; j < 3; j++) + ok(arr2[j] === j + 2, "arr with overlap[" + j + "] = " + arr[j]); /* methods are incompatible, even though thrown error is not explicit */ ok(Uint16Array.prototype.subarray !== Int32Array.prototype.subarray, "Uint16Array and Int32Array have same subarray methods"); From 13979c01a613a38238b6f18cb8a8b468ed029f58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:59 +0200 Subject: [PATCH 0853/2777] jscript: Implement Uint8ClampedArray. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/arraybuf.c | 18 ++++++++++++++++++ dlls/jscript/jscript.h | 1 + dlls/jscript/object.c | 1 + dlls/mshtml/tests/es5.js | 12 ++++++++++++ 4 files changed, 32 insertions(+) diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index e8a7472c508..e5c22df53c4 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -17,6 +17,7 @@ */ +#include #include #include @@ -744,11 +745,28 @@ static const builtin_info_t DataViewConstr_info = { NULL }; +static HRESULT clamped_u8(script_ctx_t *ctx, jsval_t v, UINT8 *ret) +{ + HRESULT hres; + double n; + + hres = to_number(ctx, v, &n); + if(FAILED(hres)) + return hres; + + if(!isfinite(n)) + *ret = (n == INFINITY ? 255 : 0); + else + *ret = (n >= 255.0 ? 255 : n <= 0 ? 0 : lround(n)); + return S_OK; +} + #define TYPEDARRAY_LIST \ X(Int8Array, JSCLASS_INT8ARRAY, INT8, to_int32, INT) \ X(Int16Array, JSCLASS_INT16ARRAY, INT16, to_int32, INT) \ X(Int32Array, JSCLASS_INT32ARRAY, INT32, to_int32, INT) \ X(Uint8Array, JSCLASS_UINT8ARRAY, UINT8, to_int32, INT) \ +X(Uint8ClampedArray, JSCLASS_UINT8CLAMPEDARRAY, UINT8, clamped_u8, UINT8) \ X(Uint16Array, JSCLASS_UINT16ARRAY, UINT16, to_int32, INT) \ X(Uint32Array, JSCLASS_UINT32ARRAY, UINT32, to_int32, INT) \ X(Float32Array, JSCLASS_FLOAT32ARRAY, float, to_number, double) \ diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index d11a25ad9a0..99ae3364ccc 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -121,6 +121,7 @@ typedef enum { JSCLASS_INT16ARRAY, JSCLASS_INT32ARRAY, JSCLASS_UINT8ARRAY, + JSCLASS_UINT8CLAMPEDARRAY, JSCLASS_UINT16ARRAY, JSCLASS_UINT32ARRAY, JSCLASS_FLOAT32ARRAY, diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index cb374e0441d..ff818bdb87b 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -56,6 +56,7 @@ static HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns L"[object Int16Array]", L"[object Int32Array]", L"[object Uint8Array]", + L"[object Uint8ClampedArray]", L"[object Uint16Array]", L"[object Uint32Array]", L"[object Float32Array]", diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index cef24052c9f..9a5b7d50991 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2410,6 +2410,18 @@ sync_test("ArrayBuffers & Views", function() { var n = ex.number >>> 0; ok(n === JS_E_NOT_TYPEDARRAY, "calling Uint32Array's subarray with Int32Array context threw " + n); } + + /* clamped array */ + arr = new Uint8ClampedArray(7); + arr2 = new Uint8Array(7); + arr.set ([42, -1, 999, 0.9, NaN, Infinity, -Infinity]); + arr2.set([42, -1, 999, 0.9, NaN, Infinity, -Infinity]); + for(var j = 0; j < 7; j++) { + ok(arr[j] === [42, 0, 255, 1, 0, 255, 0][j], "clamped arr[" + j + "] = " + arr[j]); + ok(arr2[j] === [42, 255, 231, 0, 0, 0, 0][j], "non-clamped arr[" + j + "] = " + arr2[j]); + } + r = Object.prototype.toString.call(arr); + ok(r === "[object Uint8ClampedArray]", "Object toString for Uint8ClampedArray = " + r); }); sync_test("builtin_context", function() { From e7a916c6677918875f778eee9f90f41b7f085321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:12:59 +0200 Subject: [PATCH 0854/2777] jscript: Allow ES5 keywords in identifiers. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- For some reason, they had to be duplicated in LabelledStatement, otherwise it would generate conflicts. Either using 'Identifier', or 'tIdentifier | ES5Keyword', would have extra conflicts for reasons I cannot understand. --- dlls/jscript/parser.y | 44 ++++++++++++++++++++++++++-------------- dlls/mshtml/tests/es5.js | 24 ++++++++++++++++++++-- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/dlls/jscript/parser.y b/dlls/jscript/parser.y index 42d695e0846..5ba633235d0 100644 --- a/dlls/jscript/parser.y +++ b/dlls/jscript/parser.y @@ -221,7 +221,7 @@ static expression_t *new_prop_and_value_expression(parser_ctx_t*,property_list_t %type MemberExpression %type PrimaryExpression %type GetterSetterMethod -%type Identifier_opt +%type Identifier Identifier_opt %type VariableDeclarationList %type VariableDeclarationListNoIn %type VariableDeclaration @@ -241,10 +241,11 @@ static expression_t *new_prop_and_value_expression(parser_ctx_t*,property_list_t %type PropertyName %type BooleanLiteral %type AssignOper -%type IdentifierName ReservedAsIdentifier +%type IdentifierName ReservedAsIdentifier ES5Keyword %nonassoc LOWER_THAN_ELSE -%nonassoc kELSE +%nonassoc kELSE kIN kINSTANCEOF ':' +%nonassoc kGET kLET kSET %% @@ -268,9 +269,9 @@ FunctionStatementList FunctionExpression : kFUNCTION left_bracket FormalParameterList_opt right_bracket '{' FunctionBody '}' { $$ = new_function_expression(ctx, NULL, $3, $6, NULL, ctx->begin + @1, @7 - @1 + 1); } - | kFUNCTION tIdentifier left_bracket FormalParameterList_opt right_bracket '{' FunctionBody '}' + | kFUNCTION Identifier left_bracket FormalParameterList_opt right_bracket '{' FunctionBody '}' { $$ = new_function_expression(ctx, $2, $4, $7, NULL, ctx->begin + @1, @8 - @1 + 1); } - | kFUNCTION tIdentifier kDCOL tIdentifier left_bracket FormalParameterList_opt right_bracket '{' FunctionBody '}' + | kFUNCTION Identifier kDCOL Identifier left_bracket FormalParameterList_opt right_bracket '{' FunctionBody '}' { $$ = new_function_expression(ctx, $4, $6, $9, $2, ctx->begin + @1, @10 - @1 + 1); } /* ECMA-262 10th Edition 14.1 */ @@ -279,8 +280,8 @@ FunctionBody /* ECMA-262 3rd Edition 13 */ FormalParameterList - : tIdentifier { $$ = new_parameter_list(ctx, $1); } - | FormalParameterList ',' tIdentifier + : Identifier { $$ = new_parameter_list(ctx, $1); } + | FormalParameterList ',' Identifier { $$ = parameter_list_add(ctx, $1, $3); } /* ECMA-262 3rd Edition 13 */ @@ -381,12 +382,12 @@ VariableDeclarationListNoIn /* ECMA-262 3rd Edition 12.2 */ VariableDeclaration - : tIdentifier Initialiser_opt + : Identifier Initialiser_opt { $$ = new_variable_declaration(ctx, $1, $2); } /* ECMA-262 3rd Edition 12.2 */ VariableDeclarationNoIn - : tIdentifier InitialiserNoIn_opt + : Identifier InitialiserNoIn_opt { $$ = new_variable_declaration(ctx, $1, $2); } /* ECMA-262 3rd Edition 12.2 */ @@ -479,6 +480,12 @@ WithStatement LabelledStatement : tIdentifier ':' Statement { $$ = new_labelled_statement(ctx, @$, $1, $3); } + | kGET ':' Statement + { $$ = new_labelled_statement(ctx, @$, $1, $3); } + | kSET ':' Statement + { $$ = new_labelled_statement(ctx, @$, $1, $3); } + | kLET ':' Statement + { $$ = new_labelled_statement(ctx, @$, $1, $3); } /* ECMA-262 3rd Edition 12.11 */ SwitchStatement @@ -527,7 +534,7 @@ TryStatement /* ECMA-262 3rd Edition 12.14 */ Catch - : kCATCH left_bracket tIdentifier right_bracket Block + : kCATCH left_bracket Identifier right_bracket Block { $$ = new_catch_block(ctx, $3, $5); } /* ECMA-262 3rd Edition 12.14 */ @@ -786,7 +793,7 @@ ArgumentList /* ECMA-262 3rd Edition 11.1 */ PrimaryExpression : kTHIS { $$ = new_expression(ctx, EXPR_THIS, 0); } - | tIdentifier { $$ = new_identifier_expression(ctx, $1); } + | Identifier { $$ = new_identifier_expression(ctx, $1); } | Literal { $$ = new_literal_expression(ctx, $1); } | ArrayLiteral { $$ = $1; } | ObjectLiteral { $$ = $1; } @@ -860,7 +867,11 @@ PropertyName /* ECMA-262 3rd Edition 7.6 */ Identifier_opt : /* empty*/ { $$ = NULL; } - | tIdentifier { $$ = $1; } + | Identifier { $$ = $1; } + +Identifier + : tIdentifier { $$ = $1; } + | ES5Keyword { $$ = $1; } /* ECMA-262 5.1 Edition 7.6 */ IdentifierName @@ -890,15 +901,12 @@ ReservedAsIdentifier | kFINALLY { $$ = $1; } | kFOR { $$ = $1; } | kFUNCTION { $$ = $1; } - | kGET { $$ = $1; } | kIF { $$ = $1; } | kIN { $$ = $1; } | kINSTANCEOF { $$ = $1; } - | kLET { $$ = $1; } | kNEW { $$ = $1; } | kNULL { $$ = $1; } | kRETURN { $$ = $1; } - | kSET { $$ = $1; } | kSWITCH { $$ = $1; } | kTHIS { $$ = $1; } | kTHROW { $$ = $1; } @@ -909,6 +917,12 @@ ReservedAsIdentifier | kVOID { $$ = $1; } | kWHILE { $$ = $1; } | kWITH { $$ = $1; } + | ES5Keyword { $$ = $1; } + +ES5Keyword + : kGET { $$ = $1; } + | kLET { $$ = $1; } + | kSET { $$ = $1; } /* ECMA-262 3rd Edition 7.8 */ Literal diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 9a5b7d50991..d69a80a5814 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -453,7 +453,14 @@ sync_test("array_sort", function() { }); sync_test("identifier_keywords", function() { + function get(let, set) { { get instanceof (Object); } return let + set; } + set: var let = get(1, 2); + { get: 10 } + var set = 0; var o = { + get: get, + set: set, + let: let, if: 1, default: 2, function: 3, @@ -466,8 +473,8 @@ sync_test("identifier_keywords", function() { else: true, finally: true, for: true, - in: true, - instanceof: true, + set in(x) { }, + get instanceof() { return 3; }, new: true, return: true, switch: true, @@ -488,6 +495,19 @@ sync_test("identifier_keywords", function() { ok(o.if === 1, "o.if = " + o.if); ok(ro().default === 2, "ro().default = " + ro().default); ok(o.false === true, "o.false = " + o.false); + ok(o.get === get, "o.let = " + o.get); + ok(o.set === set, "o.let = " + o.set); + ok(o.let === let, "o.let = " + o.let); + ok(o.instanceof === 3, "o.instanceof = " + o.instanceof); + + var tmp = false; + try { + eval('function var() { }'); + } + catch(set) { + tmp = true; + } + ok(tmp === true, "Expected exception for 'function var() { }'"); }); function test_own_data_prop_desc(obj, prop, expected_writable, expected_enumerable, From 169372a662bded2dfbc04ccb9a8453606fa966ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:00 +0200 Subject: [PATCH 0855/2777] jscript: Handle DISP_E_MEMBERNOTFOUND when retrieving props. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will be needed for asynchronous props, like for the localStorage object, when it becomes a JS object. Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/dispex.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 27745fb9178..1086791753b 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2418,7 +2418,8 @@ HRESULT jsdisp_call_name(jsdisp_t *disp, const WCHAR *name, WORD flags, unsigned if(!prop || prop->type == PROP_DELETED) return JS_E_INVALID_PROPERTY; - return invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, &disp->ctx->jscaller->IServiceProvider_iface); + hres = invoke_prop_func(disp, to_disp(disp), prop, flags, argc, argv, r, &disp->ctx->jscaller->IServiceProvider_iface); + return (hres == DISP_E_MEMBERNOTFOUND) ? JS_E_INVALID_PROPERTY : hres; } static HRESULT disp_invoke(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, DISPPARAMS *params, VARIANT *r, @@ -2770,7 +2771,12 @@ HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val) return S_OK; } - return prop_get(obj, prop, val); + hres = prop_get(obj, prop, val); + if(hres == DISP_E_MEMBERNOTFOUND) { + *val = jsval_undefined(); + return S_OK; + } + return hres; } HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r) @@ -2793,7 +2799,12 @@ HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r) return DISP_E_UNKNOWNNAME; } - return prop_get(obj, prop, r); + hres = prop_get(obj, prop, r); + if(hres == DISP_E_MEMBERNOTFOUND) { + *r = jsval_undefined(); + return DISP_E_UNKNOWNNAME; + } + return hres; } HRESULT jsdisp_propget(jsdisp_t *jsdisp, DISPID id, jsval_t *val) @@ -3028,7 +3039,7 @@ HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_onl if(!flags_only) { hres = prop_get(obj, prop, &desc->value); if(FAILED(hres)) - return hres; + return (hres == DISP_E_MEMBERNOTFOUND) ? DISP_E_UNKNOWNNAME : hres; } break; case PROP_ACCESSOR: From 1e5d0c7ddd67c41deb2a746852239a0ed4e45b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:00 +0200 Subject: [PATCH 0856/2777] mshtml: Pass a generic "this" dispatch when invoking builtin functions. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And return proper error value, since it will be normal to fail (incompatible object). For hooks make sure to validate the "this" object before calling. Signed-off-by: Gabriel Ivăncescu --- This is needed by next patch, where generic "this" objects can be supplied. The vtbl hack is temporary until we have the private proxy interface, otherwise it can regress (and tests fail). With the private interface it will be generic and not hardcoding any vtbl. --- dlls/mshtml/dispex.c | 153 ++++++++++++++++++++++----------------- dlls/mshtml/htmldoc.c | 2 +- dlls/mshtml/htmlwindow.c | 2 +- 3 files changed, 90 insertions(+), 67 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 87930a9aa9f..75e32440b10 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -126,6 +126,8 @@ PRIVATE_TID_LIST #undef XDIID }; +static inline DispatchEx *get_dispex_for_hook(IUnknown*); + static HRESULT load_typelib(void) { WCHAR module_path[MAX_PATH + 3]; @@ -755,12 +757,11 @@ static HRESULT dispex_value(DispatchEx *This, LCID lcid, WORD flags, DISPPARAMS return S_OK; } -static HRESULT typeinfo_invoke(DispatchEx *This, func_info_t *func, WORD flags, DISPPARAMS *dp, VARIANT *res, +static HRESULT typeinfo_invoke(IUnknown *iface, func_info_t *func, WORD flags, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei) { DISPPARAMS params = {dp->rgvarg, NULL, dp->cArgs, 0}; ITypeInfo *ti; - IUnknown *unk; UINT argerr=0; HRESULT hres; @@ -775,16 +776,7 @@ static HRESULT typeinfo_invoke(DispatchEx *This, func_info_t *func, WORD flags, return hres; } - hres = IUnknown_QueryInterface(This->outer, tid_ids[func->tid], (void**)&unk); - if(FAILED(hres)) { - ERR("Could not get iface %s: %08lx\n", debugstr_mshtml_guid(tid_ids[func->tid]), hres); - return E_FAIL; - } - - hres = ITypeInfo_Invoke(ti, unk, func->id, flags, ¶ms, res, ei, &argerr); - - IUnknown_Release(unk); - return hres; + return ITypeInfo_Invoke(ti, iface, func->id, flags, ¶ms, res, ei, &argerr); } static inline func_disp_t *impl_from_IUnknown(IUnknown *iface) @@ -1106,9 +1098,8 @@ HRESULT change_type(VARIANT *dst, VARIANT *src, VARTYPE vt, IServiceProvider *ca return VariantChangeType(dst, src, 0, vt); } -static HRESULT builtin_propget(DispatchEx *This, func_info_t *func, DISPPARAMS *dp, VARIANT *res) +static HRESULT builtin_propget(IUnknown *iface, func_info_t *func, DISPPARAMS *dp, VARIANT *res) { - IUnknown *iface; HRESULT hres; if(dp && dp->cArgs) { @@ -1118,24 +1109,20 @@ static HRESULT builtin_propget(DispatchEx *This, func_info_t *func, DISPPARAMS * assert(func->get_vtbl_off); - hres = IUnknown_QueryInterface(This->outer, tid_ids[func->tid], (void**)&iface); - if(SUCCEEDED(hres)) { - switch(func->prop_vt) { + switch(func->prop_vt) { #define CASE_VT(vt,type,access) \ - case vt: { \ - type val; \ - hres = ((HRESULT (WINAPI*)(IUnknown*,type*))((void**)iface->lpVtbl)[func->get_vtbl_off])(iface,&val); \ - if(SUCCEEDED(hres)) \ - access(res) = val; \ - } \ - break - BUILTIN_TYPES_SWITCH; + case vt: { \ + type val; \ + hres = ((HRESULT (WINAPI*)(IUnknown*,type*))((void**)iface->lpVtbl)[func->get_vtbl_off])(iface,&val); \ + if(SUCCEEDED(hres)) \ + access(res) = val; \ + } \ + break + BUILTIN_TYPES_SWITCH; #undef CASE_VT - default: - FIXME("Unhandled vt %d\n", func->prop_vt); - hres = E_NOTIMPL; - } - IUnknown_Release(iface); + default: + FIXME("Unhandled vt %d\n", func->prop_vt); + hres = E_NOTIMPL; } if(FAILED(hres)) @@ -1146,10 +1133,9 @@ static HRESULT builtin_propget(DispatchEx *This, func_info_t *func, DISPPARAMS * return S_OK; } -static HRESULT builtin_propput(DispatchEx *This, func_info_t *func, DISPPARAMS *dp, IServiceProvider *caller) +static HRESULT builtin_propput(DispatchEx *This, IUnknown *iface, func_info_t *func, DISPPARAMS *dp, IServiceProvider *caller) { VARIANT *v, tmpv; - IUnknown *iface; HRESULT hres; if(dp->cArgs != 1 || (dp->cNamedArgs == 1 && *dp->rgdispidNamedArgs != DISPID_PROPERTYPUT) @@ -1175,21 +1161,16 @@ static HRESULT builtin_propput(DispatchEx *This, func_info_t *func, DISPPARAMS * v = &tmpv; } - hres = IUnknown_QueryInterface(This->outer, tid_ids[func->tid], (void**)&iface); - if(SUCCEEDED(hres)) { - switch(func->prop_vt) { + switch(func->prop_vt) { #define CASE_VT(vt,type,access) \ - case vt: \ - hres = ((HRESULT (WINAPI*)(IUnknown*,type))((void**)iface->lpVtbl)[func->put_vtbl_off])(iface,access(v)); \ - break - BUILTIN_TYPES_SWITCH; + case vt: \ + hres = ((HRESULT (WINAPI*)(IUnknown*,type))((void**)iface->lpVtbl)[func->put_vtbl_off])(iface,access(v)); \ + break + BUILTIN_TYPES_SWITCH; #undef CASE_VT - default: - FIXME("Unimplemented vt %d\n", func->prop_vt); - hres = E_NOTIMPL; - } - - IUnknown_Release(iface); + default: + FIXME("Unimplemented vt %d\n", func->prop_vt); + hres = E_NOTIMPL; } if(v == &tmpv) @@ -1197,32 +1178,40 @@ static HRESULT builtin_propput(DispatchEx *This, func_info_t *func, DISPPARAMS * return hres; } -static HRESULT invoke_builtin_function(DispatchEx *This, func_info_t *func, DISPPARAMS *dp, +static HRESULT invoke_builtin_function(IDispatch *this_obj, func_info_t *func, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { VARIANT arg_buf[MAX_ARGS], *arg_ptrs[MAX_ARGS], *arg, retv, ret_ref, vhres; unsigned i, nconv = 0; + DispatchEx *dispex; IUnknown *iface; HRESULT hres; - if(func->hook) { - hres = func->hook(This, DISPATCH_METHOD, dp, res, ei, caller); - if(hres != S_FALSE) + hres = IDispatch_QueryInterface(this_obj, tid_ids[func->tid], (void**)&iface); + if(FAILED(hres) || !iface) + return E_UNEXPECTED; + + if(func->hook && (dispex = get_dispex_for_hook(iface))) { + hres = func->hook(dispex, DISPATCH_METHOD, dp, res, ei, caller); + IDispatchEx_Release(&dispex->IDispatchEx_iface); + if(hres != S_FALSE) { + IUnknown_Release(iface); return hres; + } } - if(!func->call_vtbl_off) - return typeinfo_invoke(This, func, DISPATCH_METHOD, dp, res, ei); + if(!func->call_vtbl_off) { + hres = typeinfo_invoke(iface, func, DISPATCH_METHOD, dp, res, ei); + IUnknown_Release(iface); + return hres; + } if(dp->cArgs + func->default_value_cnt < func->argc) { FIXME("Invalid argument count (expected %u, got %u)\n", func->argc, dp->cArgs); + IUnknown_Release(iface); return E_INVALIDARG; } - hres = IUnknown_QueryInterface(This->outer, tid_ids[func->tid], (void**)&iface); - if(FAILED(hres)) - return hres; - for(i=0; i < func->argc; i++) { BOOL own_value = FALSE; if(i >= dp->cArgs) { @@ -1335,7 +1324,7 @@ static HRESULT function_invoke(DispatchEx *This, func_info_t *func, WORD flags, } } - hres = invoke_builtin_function(This, func, dp, res, ei, caller); + hres = invoke_builtin_function((IDispatch*)&This->IDispatchEx_iface, func, dp, res, ei, caller); break; case DISPATCH_PROPERTYGET: { func_obj_entry_t *entry; @@ -1392,6 +1381,7 @@ static HRESULT invoke_builtin_prop(DispatchEx *This, DISPID id, LCID lcid, WORD VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { func_info_t *func; + IUnknown *iface; HRESULT hres; hres = get_builtin_func(This->info, id, &func); @@ -1403,36 +1393,43 @@ static HRESULT invoke_builtin_prop(DispatchEx *This, DISPID id, LCID lcid, WORD if(func->func_disp_idx >= 0) return function_invoke(This, func, flags, dp, res, ei, caller); + hres = IDispatchEx_QueryInterface(&This->IDispatchEx_iface, tid_ids[func->tid], (void**)&iface); + if(FAILED(hres) || !iface) + return E_UNEXPECTED; + if(func->hook) { hres = func->hook(This, flags, dp, res, ei, caller); - if(hres != S_FALSE) + if(hres != S_FALSE) { + IUnknown_Release(iface); return hres; + } } switch(flags) { case DISPATCH_PROPERTYPUT: if(res) V_VT(res) = VT_EMPTY; - hres = builtin_propput(This, func, dp, caller); + hres = builtin_propput(This, iface, func, dp, caller); break; case DISPATCH_PROPERTYGET: - hres = builtin_propget(This, func, dp, res); + hres = builtin_propget(iface, func, dp, res); break; default: if(!func->get_vtbl_off) { - hres = typeinfo_invoke(This, func, flags, dp, res, ei); + hres = typeinfo_invoke(iface, func, flags, dp, res, ei); }else { VARIANT v; - hres = builtin_propget(This, func, NULL, &v); + hres = builtin_propget(iface, func, NULL, &v); if(FAILED(hres)) - return hres; + break; if(flags != (DISPATCH_PROPERTYGET|DISPATCH_METHOD) || dp->cArgs) { if(V_VT(&v) != VT_DISPATCH) { FIXME("Not a function %s flags %08x\n", debugstr_variant(&v), flags); VariantClear(&v); - return E_FAIL; + hres = E_FAIL; + break; } hres = invoke_disp_value(This, V_DISPATCH(&v), lcid, flags, dp, res, ei, caller); @@ -1445,6 +1442,7 @@ static HRESULT invoke_builtin_prop(DispatchEx *This, DISPID id, LCID lcid, WORD } } + IUnknown_Release(iface); return hres; } @@ -1458,7 +1456,7 @@ HRESULT dispex_call_builtin(DispatchEx *dispex, DISPID id, DISPPARAMS *dp, if(FAILED(hres)) return hres; - return invoke_builtin_function(dispex, func, dp, res, ei, caller); + return invoke_builtin_function((IDispatch*)&dispex->IDispatchEx_iface, func, dp, res, ei, caller); } HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success) @@ -1482,6 +1480,7 @@ HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success) VARIANT var; DISPPARAMS dp = {&var,NULL,1,0}; func_info_t *func; + IUnknown *iface; HRESULT hres; hres = get_builtin_func(This->info, id, &func); @@ -1514,8 +1513,10 @@ HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success) } *success = VARIANT_TRUE; + IDispatchEx_QueryInterface(&This->IDispatchEx_iface, tid_ids[func->tid], (void**)&iface); + V_VT(&var) = VT_EMPTY; - hres = builtin_propput(This, func, &dp, NULL); + hres = builtin_propput(This, iface, func, &dp, NULL); if(FAILED(hres)) { VARIANT *ref; hres = dispex_get_dprop_ref(This, func->name, FALSE, &ref); @@ -1524,6 +1525,7 @@ HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success) else VariantClear(ref); } + IUnknown_Release(iface); return S_OK; } default: @@ -1971,6 +1973,27 @@ static IDispatchExVtbl DispatchExVtbl = { DispatchEx_GetNameSpaceParent }; +extern const IDispatchExVtbl WindowDispExVtbl DECLSPEC_HIDDEN; +extern const IDispatchExVtbl DocDispatchExVtbl DECLSPEC_HIDDEN; +static inline DispatchEx *get_dispex_for_hook(IUnknown *iface) +{ + IDispatchEx *dispex; + + if(FAILED(IUnknown_QueryInterface(iface, &IID_IDispatchEx, (void**)&dispex)) || !dispex) + return NULL; + + /* FIXME: Handle these generically (needs private interface) */ + if(dispex->lpVtbl == &DispatchExVtbl) + return impl_from_IDispatchEx(dispex); + if(dispex->lpVtbl == &WindowDispExVtbl) + return &CONTAINING_RECORD(dispex, HTMLWindow, IDispatchEx_iface)->inner_window->event_target.dispex; + if(dispex->lpVtbl == &DocDispatchExVtbl) + return &CONTAINING_RECORD(dispex, HTMLDocumentNode, IDispatchEx_iface)->node.event_target.dispex; + + IDispatchEx_Release(dispex); + return NULL; +} + BOOL dispex_query_interface(DispatchEx *This, REFIID riid, void **ppv) { if(IsEqualGUID(&IID_IDispatch, riid)) diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 62bafab858a..bd43612e48a 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -5165,7 +5165,7 @@ static HRESULT WINAPI DocDispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnkn return IDispatchEx_GetNameSpaceParent(&This->node.event_target.dispex.IDispatchEx_iface, ppunk); } -static const IDispatchExVtbl DocDispatchExVtbl = { +const IDispatchExVtbl DocDispatchExVtbl = { DocDispatchEx_QueryInterface, DocDispatchEx_AddRef, DocDispatchEx_Release, diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index f056f39c09f..a9a4b7fdd27 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3760,7 +3760,7 @@ static HRESULT WINAPI WindowDispEx_GetNameSpaceParent(IDispatchEx *iface, IUnkno return S_OK; } -static const IDispatchExVtbl WindowDispExVtbl = { +const IDispatchExVtbl WindowDispExVtbl = { WindowDispEx_QueryInterface, WindowDispEx_AddRef, WindowDispEx_Release, From 32e65fe2df123faa4276f228fda051b76b34eed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:00 +0200 Subject: [PATCH 0857/2777] mshtml: Implement apply & call for builtin function objects. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For document modes <= IE8, native exposes the apply/call props, and implements them to work similar to the jscript builtins. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/dispex.c | 197 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 192 insertions(+), 5 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 75e32440b10..974e4f0d0dd 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -127,6 +127,7 @@ PRIVATE_TID_LIST }; static inline DispatchEx *get_dispex_for_hook(IUnknown*); +static HRESULT invoke_builtin_function(IDispatch*,func_info_t*,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*); static HRESULT load_typelib(void) { @@ -835,6 +836,145 @@ static const IUnknownVtbl FunctionUnkVtbl = { Function_Release }; +static HRESULT function_apply(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + IDispatchEx *dispex = NULL; + DISPPARAMS params = { 0 }; + IDispatch *this_obj; + DISPID dispid; + UINT argc = 0; + VARIANT *arg; + HRESULT hres; + VARIANT var; + + arg = dp->rgvarg + dp->cArgs - 1; + if(dp->cArgs < 1 || V_VT(arg) != VT_DISPATCH || !V_DISPATCH(arg)) + return CTL_E_ILLEGALFUNCTIONCALL; + this_obj = V_DISPATCH(arg); + + if(dp->cArgs >= 2) { + UINT i, err = 0; + IDispatch *disp; + BSTR name; + + arg--; + if((V_VT(arg) & ~VT_BYREF) != VT_DISPATCH) + return CTL_E_ILLEGALFUNCTIONCALL; + disp = (V_VT(arg) & VT_BYREF) ? *(IDispatch**)(V_BYREF(arg)) : V_DISPATCH(arg); + + /* get the array length */ + if(!(name = SysAllocString(L"length"))) + return E_OUTOFMEMORY; + + hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); + if(SUCCEEDED(hres) && dispex) + hres = IDispatchEx_GetDispID(dispex, name, fdexNameCaseSensitive, &dispid); + else { + hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, &dispid); + dispex = NULL; + } + SysFreeString(name); + if(FAILED(hres) || dispid == DISPID_UNKNOWN) { + hres = CTL_E_ILLEGALFUNCTIONCALL; + goto fail; + } + + if(dispex) + hres = IDispatchEx_InvokeEx(dispex, dispid, lcid, DISPATCH_PROPERTYGET, ¶ms, res, ei, caller); + else + hres = IDispatch_Invoke(disp, dispid, &IID_NULL, lcid, DISPATCH_PROPERTYGET, ¶ms, res, ei, &err); + if(FAILED(hres)) + goto fail; + + if(V_VT(res) == VT_I4) + V_I4(&var) = V_I4(res); + else { + V_VT(&var) = VT_EMPTY; + hres = change_type(&var, res, VT_I4, caller); + } + VariantClear(res); + if(FAILED(hres) || V_I4(&var) < 0) { + hres = CTL_E_ILLEGALFUNCTIONCALL; + goto fail; + } + params.cArgs = V_I4(&var); + + /* alloc new params */ + if(params.cArgs) { + if(!(params.rgvarg = malloc(params.cArgs * sizeof(VARIANTARG)))) { + hres = E_OUTOFMEMORY; + goto fail; + } + for(i = 0; i < params.cArgs; i++) { + WCHAR buf[12]; + + arg = params.rgvarg + params.cArgs - i - 1; + swprintf(buf, ARRAY_SIZE(buf), L"%u", i); + if(!(name = SysAllocString(buf))) { + hres = E_OUTOFMEMORY; + break; + } + if(dispex) + hres = IDispatchEx_GetDispID(dispex, name, fdexNameCaseSensitive, &dispid); + else + hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, &dispid); + SysFreeString(name); + if(FAILED(hres)) { + if(hres == DISP_E_UNKNOWNNAME) { + V_VT(arg) = VT_EMPTY; + continue; + } + hres = CTL_E_ILLEGALFUNCTIONCALL; + break; + } + if(dispex) + hres = IDispatchEx_InvokeEx(dispex, dispid, lcid, DISPATCH_PROPERTYGET, NULL, arg, ei, caller); + else + hres = IDispatch_Invoke(disp, dispid, &IID_NULL, lcid, DISPATCH_PROPERTYGET, NULL, arg, ei, &err); + if(FAILED(hres)) + break; + } + argc = i; + if(argc < params.cArgs) + goto cleanup; + } + } + + hres = invoke_builtin_function(this_obj, func->info, ¶ms, res, ei, caller); + +cleanup: + while(argc--) + VariantClear(¶ms.rgvarg[params.cArgs - argc - 1]); + free(params.rgvarg); +fail: + if(dispex) + IDispatchEx_Release(dispex); + return (hres == E_UNEXPECTED) ? CTL_E_ILLEGALFUNCTIONCALL : hres; +} + +static HRESULT function_call(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + DISPPARAMS params = { dp->rgvarg, NULL, dp->cArgs - 1, 0 }; + VARIANT *arg; + HRESULT hres; + + arg = dp->rgvarg + dp->cArgs - 1; + if(dp->cArgs < 1 || V_VT(arg) != VT_DISPATCH || !V_DISPATCH(arg)) + return CTL_E_ILLEGALFUNCTIONCALL; + + hres = invoke_builtin_function(V_DISPATCH(arg), func->info, ¶ms, res, ei, caller); + + return (hres == E_UNEXPECTED) ? CTL_E_ILLEGALFUNCTIONCALL : hres; +} + +static const struct { + const WCHAR *name; + HRESULT (*invoke)(func_disp_t*,DISPPARAMS*,LCID,VARIANT*,EXCEPINFO*,IServiceProvider*); +} function_props[] = { + { L"apply", function_apply }, + { L"call", function_call } +}; + static inline func_disp_t *impl_from_DispatchEx(DispatchEx *iface) { return CONTAINING_RECORD(iface, func_disp_t, dispex); @@ -854,7 +994,7 @@ static HRESULT function_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPAR case DISPATCH_METHOD: if(!This->obj) return E_UNEXPECTED; - hres = dispex_call_builtin(This->obj, This->info->id, params, res, ei, caller); + hres = invoke_builtin_function((IDispatch*)&This->obj->IDispatchEx_iface, This->info, params, res, ei, caller); break; case DISPATCH_PROPERTYGET: { unsigned name_len; @@ -895,10 +1035,57 @@ static HRESULT function_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPAR return hres; } +static HRESULT function_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid) +{ + DWORD i; + + for(i = 0; i < ARRAY_SIZE(function_props); i++) { + if((flags & fdexNameCaseInsensitive) ? wcsicmp(name, function_props[i].name) : wcscmp(name, function_props[i].name)) + continue; + *dispid = MSHTML_DISPID_CUSTOM_MIN + i; + return S_OK; + } + return DISP_E_UNKNOWNNAME; +} + +static HRESULT function_get_name(DispatchEx *dispex, DISPID id, BSTR *name) +{ + DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN; + + if(idx >= ARRAY_SIZE(function_props)) + return DISP_E_MEMBERNOTFOUND; + + return (*name = SysAllocString(function_props[idx].name)) ? S_OK : E_OUTOFMEMORY; +} + +static HRESULT function_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, + VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + func_disp_t *This = impl_from_DispatchEx(dispex); + DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN; + + if(idx >= ARRAY_SIZE(function_props)) + return DISP_E_MEMBERNOTFOUND; + + switch(flags) { + case DISPATCH_METHOD|DISPATCH_PROPERTYGET: + if(!res) + return E_INVALIDARG; + /* fall through */ + case DISPATCH_METHOD: + return function_props[idx].invoke(This, params, lcid, res, ei, caller); + default: + return MSHTML_E_INVALID_PROPERTY; + } + + return S_OK; +} + static const dispex_static_data_vtbl_t function_dispex_vtbl = { function_value, - NULL, - NULL, + function_get_dispid, + function_get_name, + function_invoke, NULL }; @@ -1293,7 +1480,7 @@ static HRESULT invoke_builtin_function(IDispatch *this_obj, func_info_t *func, D return V_ERROR(&vhres); } -static HRESULT function_invoke(DispatchEx *This, func_info_t *func, WORD flags, DISPPARAMS *dp, VARIANT *res, +static HRESULT func_invoke(DispatchEx *This, func_info_t *func, WORD flags, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { HRESULT hres; @@ -1391,7 +1578,7 @@ static HRESULT invoke_builtin_prop(DispatchEx *This, DISPID id, LCID lcid, WORD return hres; if(func->func_disp_idx >= 0) - return function_invoke(This, func, flags, dp, res, ei, caller); + return func_invoke(This, func, flags, dp, res, ei, caller); hres = IDispatchEx_QueryInterface(&This->IDispatchEx_iface, tid_ids[func->tid], (void**)&iface); if(FAILED(hres) || !iface) From f6d8f64676e83668dccf90627e4b8e10bd95adc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:00 +0200 Subject: [PATCH 0858/2777] jscript: Move the native function's toString implementation to a helper. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- So it can be re-used for proxy accessors. --- dlls/jscript/function.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index c3b22eb843c..513dee71809 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -658,9 +658,8 @@ static HRESULT NativeFunction_call(script_ctx_t *ctx, FunctionInstance *func, js return function->proc(ctx, vthis, flags & ~DISPATCH_JSCRIPT_INTERNAL_MASK, argc, argv, r); } -static HRESULT NativeFunction_toString(FunctionInstance *func, jsstr_t **ret) +static HRESULT native_code_toString(const WCHAR *name, jsstr_t **ret) { - NativeFunction *function = (NativeFunction*)func; DWORD name_len; jsstr_t *str; WCHAR *ptr; @@ -668,14 +667,14 @@ static HRESULT NativeFunction_toString(FunctionInstance *func, jsstr_t **ret) static const WCHAR native_prefixW[] = L"\nfunction "; static const WCHAR native_suffixW[] = L"() {\n [native code]\n}\n"; - name_len = function->name ? lstrlenW(function->name) : 0; + name_len = name ? lstrlenW(name) : 0; str = jsstr_alloc_buf(ARRAY_SIZE(native_prefixW) + ARRAY_SIZE(native_suffixW) + name_len - 2, &ptr); if(!str) return E_OUTOFMEMORY; memcpy(ptr, native_prefixW, sizeof(native_prefixW)); ptr += ARRAY_SIZE(native_prefixW) - 1; - memcpy(ptr, function->name, name_len*sizeof(WCHAR)); + memcpy(ptr, name, name_len*sizeof(WCHAR)); ptr += name_len; memcpy(ptr, native_suffixW, sizeof(native_suffixW)); @@ -683,6 +682,12 @@ static HRESULT NativeFunction_toString(FunctionInstance *func, jsstr_t **ret) return S_OK; } +static HRESULT NativeFunction_toString(FunctionInstance *func, jsstr_t **ret) +{ + NativeFunction *function = (NativeFunction*)func; + return native_code_toString(function->name, ret); +} + static function_code_t *NativeFunction_get_code(FunctionInstance *function) { return NULL; From 809927b0667ef53ab0c71a2e8f0eb096f5f3db08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:00 +0200 Subject: [PATCH 0859/2777] mshtml: Move the dispex's invoke and member delete into helpers. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- These will be used to bypass the proxy later. --- dlls/mshtml/dispex.c | 215 ++++++++++++++++++----------------- dlls/mshtml/htmldoc.c | 4 +- dlls/mshtml/htmlelem.c | 4 +- dlls/mshtml/htmlframe.c | 8 +- dlls/mshtml/htmlwindow.c | 6 +- dlls/mshtml/mshtml_private.h | 2 + 6 files changed, 126 insertions(+), 113 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 974e4f0d0dd..c6f3a128690 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1854,8 +1854,7 @@ static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); - return IDispatchEx_InvokeEx(&This->IDispatchEx_iface, dispIdMember, lcid, wFlags, pDispParams, - pVarResult, pExcepInfo, NULL); + return dispex_invoke(This, dispIdMember, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, NULL); } static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) @@ -1888,86 +1887,10 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { DispatchEx *This = impl_from_IDispatchEx(iface); - HRESULT hres; TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); - if(!ensure_real_info(This)) - return E_OUTOFMEMORY; - - if(wFlags == (DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF)) - wFlags = DISPATCH_PROPERTYPUT; - - switch(get_dispid_type(id)) { - case DISPEXPROP_CUSTOM: - if(!This->info->desc->vtbl || !This->info->desc->vtbl->invoke) - return DISP_E_MEMBERNOTFOUND; - return This->info->desc->vtbl->invoke(This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); - - case DISPEXPROP_DYNAMIC: { - DWORD idx = id - DISPID_DYNPROP_0; - dynamic_prop_t *prop; - - if(!get_dynamic_data(This) || This->dynamic_data->prop_cnt <= idx) - return DISP_E_MEMBERNOTFOUND; - - prop = This->dynamic_data->props+idx; - - switch(wFlags) { - case DISPATCH_METHOD|DISPATCH_PROPERTYGET: - if(!pvarRes) - return E_INVALIDARG; - /* fall through */ - case DISPATCH_METHOD: - if(V_VT(&prop->var) != VT_DISPATCH) { - FIXME("invoke %s\n", debugstr_variant(&prop->var)); - return E_NOTIMPL; - } - - return invoke_disp_value(This, V_DISPATCH(&prop->var), lcid, wFlags, pdp, pvarRes, pei, pspCaller); - case DISPATCH_PROPERTYGET: - if(prop->flags & DYNPROP_DELETED) - return DISP_E_MEMBERNOTFOUND; - V_VT(pvarRes) = VT_EMPTY; - return variant_copy(pvarRes, &prop->var); - case DISPATCH_PROPERTYPUT: - if(pdp->cArgs != 1 || (pdp->cNamedArgs == 1 && *pdp->rgdispidNamedArgs != DISPID_PROPERTYPUT) - || pdp->cNamedArgs > 1) { - FIXME("invalid args\n"); - return E_INVALIDARG; - } - - TRACE("put %s\n", debugstr_variant(pdp->rgvarg)); - VariantClear(&prop->var); - hres = variant_copy(&prop->var, pdp->rgvarg); - if(FAILED(hres)) - return hres; - - prop->flags &= ~DYNPROP_DELETED; - return S_OK; - default: - FIXME("unhandled wFlags %x\n", wFlags); - return E_NOTIMPL; - } - } - case DISPEXPROP_BUILTIN: - if(wFlags == DISPATCH_CONSTRUCT) { - if(id == DISPID_VALUE) { - if(This->info->desc->vtbl && This->info->desc->vtbl->value) { - return This->info->desc->vtbl->value(This, lcid, wFlags, pdp, pvarRes, pei, pspCaller); - } - FIXME("DISPATCH_CONSTRUCT flag but missing value function\n"); - return E_FAIL; - } - FIXME("DISPATCH_CONSTRUCT flag without DISPID_VALUE\n"); - return E_FAIL; - } - - return invoke_builtin_prop(This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); - default: - assert(0); - return E_FAIL; - } + return dispex_invoke(This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); } static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR name, DWORD grfdex) @@ -1986,7 +1909,7 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR nam compat_mode < COMPAT_MODE_IE9 ? hres : S_OK; } - return IDispatchEx_DeleteMemberByDispID(&This->IDispatchEx_iface, id); + return dispex_delete_prop(This, id); } static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) @@ -1995,28 +1918,7 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID TRACE("(%p)->(%lx)\n", This, id); - if(is_custom_dispid(id) && This->info->desc->vtbl && This->info->desc->vtbl->delete) - return This->info->desc->vtbl->delete(This, id); - - if(dispex_compat_mode(This) < COMPAT_MODE_IE8) { - /* Not implemented by IE */ - return E_NOTIMPL; - } - - if(is_dynamic_dispid(id)) { - DWORD idx = id - DISPID_DYNPROP_0; - dynamic_prop_t *prop; - - if(!get_dynamic_data(This) || idx >= This->dynamic_data->prop_cnt) - return S_OK; - - prop = This->dynamic_data->props + idx; - VariantClear(&prop->var); - prop->flags |= DYNPROP_DELETED; - return S_OK; - } - - return S_OK; + return dispex_delete_prop(This, id); } static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) @@ -2203,6 +2105,115 @@ BOOL dispex_query_interface(DispatchEx *This, REFIID riid, void **ppv) return TRUE; } +HRESULT dispex_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *res, + EXCEPINFO *pei, IServiceProvider *caller) +{ + HRESULT hres; + + if(!ensure_real_info(dispex)) + return E_OUTOFMEMORY; + + if(wFlags == (DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF)) + wFlags = DISPATCH_PROPERTYPUT; + + switch(get_dispid_type(id)) { + case DISPEXPROP_CUSTOM: + if(!dispex->info->desc->vtbl || !dispex->info->desc->vtbl->invoke) + return DISP_E_MEMBERNOTFOUND; + return dispex->info->desc->vtbl->invoke(dispex, id, lcid, wFlags, pdp, res, pei, caller); + + case DISPEXPROP_DYNAMIC: { + DWORD idx = id - DISPID_DYNPROP_0; + dynamic_prop_t *prop; + + if(!get_dynamic_data(dispex) || dispex->dynamic_data->prop_cnt <= idx) + return DISP_E_MEMBERNOTFOUND; + + prop = dispex->dynamic_data->props+idx; + + switch(wFlags) { + case DISPATCH_METHOD|DISPATCH_PROPERTYGET: + if(!res) + return E_INVALIDARG; + /* fall through */ + case DISPATCH_METHOD: + if(V_VT(&prop->var) != VT_DISPATCH) { + FIXME("invoke %s\n", debugstr_variant(&prop->var)); + return E_NOTIMPL; + } + + return invoke_disp_value(dispex, V_DISPATCH(&prop->var), lcid, wFlags, pdp, res, pei, caller); + case DISPATCH_PROPERTYGET: + if(prop->flags & DYNPROP_DELETED) + return DISP_E_MEMBERNOTFOUND; + V_VT(res) = VT_EMPTY; + return variant_copy(res, &prop->var); + case DISPATCH_PROPERTYPUT: + if(pdp->cArgs != 1 || (pdp->cNamedArgs == 1 && *pdp->rgdispidNamedArgs != DISPID_PROPERTYPUT) + || pdp->cNamedArgs > 1) { + FIXME("invalid args\n"); + return E_INVALIDARG; + } + + TRACE("put %s\n", debugstr_variant(pdp->rgvarg)); + VariantClear(&prop->var); + hres = variant_copy(&prop->var, pdp->rgvarg); + if(FAILED(hres)) + return hres; + + prop->flags &= ~DYNPROP_DELETED; + return S_OK; + default: + FIXME("unhandled wFlags %x\n", wFlags); + return E_NOTIMPL; + } + } + case DISPEXPROP_BUILTIN: + if(wFlags == DISPATCH_CONSTRUCT) { + if(id == DISPID_VALUE) { + if(dispex->info->desc->vtbl && dispex->info->desc->vtbl->value) { + return dispex->info->desc->vtbl->value(dispex, lcid, wFlags, pdp, res, pei, caller); + } + FIXME("DISPATCH_CONSTRUCT flag but missing value function\n"); + return E_FAIL; + } + FIXME("DISPATCH_CONSTRUCT flag without DISPID_VALUE\n"); + return E_FAIL; + } + + return invoke_builtin_prop(dispex, id, lcid, wFlags, pdp, res, pei, caller); + default: + assert(0); + return E_FAIL; + } +} + +HRESULT dispex_delete_prop(DispatchEx *dispex, DISPID id) +{ + if(is_custom_dispid(id) && dispex->info->desc->vtbl && dispex->info->desc->vtbl->delete) + return dispex->info->desc->vtbl->delete(dispex, id); + + if(dispex_compat_mode(dispex) < COMPAT_MODE_IE8) { + /* Not implemented by IE */ + return E_NOTIMPL; + } + + if(is_dynamic_dispid(id)) { + DWORD idx = id - DISPID_DYNPROP_0; + dynamic_prop_t *prop; + + if(!get_dynamic_data(dispex) || idx >= dispex->dynamic_data->prop_cnt) + return S_OK; + + prop = dispex->dynamic_data->props + idx; + VariantClear(&prop->var); + prop->flags |= DYNPROP_DELETED; + return S_OK; + } + + return S_OK; +} + void dispex_traverse(DispatchEx *This, nsCycleCollectionTraversalCallback *cb) { dynamic_prop_t *prop; diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index bd43612e48a..a5e647c86d9 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -6116,8 +6116,8 @@ static HRESULT HTMLDocumentNode_location_hook(DispatchEx *dispex, WORD flags, DI if(!(flags & DISPATCH_PROPERTYPUT) || !This->outer_window) return S_FALSE; - return IDispatchEx_InvokeEx(&This->outer_window->base.IDispatchEx_iface, DISPID_IHTMLWINDOW2_LOCATION, - 0, flags, dp, res, ei, caller); + return dispex_invoke(&This->outer_window->base.inner_window->event_target.dispex, + DISPID_IHTMLWINDOW2_LOCATION, 0, flags, dp, res, ei, caller); } static const event_target_vtbl_t HTMLDocumentNode_event_target_vtbl = { diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 5574fc075d3..5afe4af69b2 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -2564,8 +2564,8 @@ static HRESULT WINAPI HTMLElement_toString(IHTMLElement *iface, BSTR *String) if(!String) return E_INVALIDARG; - hres = IDispatchEx_InvokeEx(&This->node.event_target.dispex.IDispatchEx_iface, DISPID_VALUE, - LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, NULL, &var, NULL, NULL); + hres = dispex_invoke(&This->node.event_target.dispex, DISPID_VALUE, LOCALE_SYSTEM_DEFAULT, + DISPATCH_PROPERTYGET, NULL, &var, NULL, NULL); if(SUCCEEDED(hres)) { assert(V_VT(&var) == VT_BSTR); *String = V_BSTR(&var); diff --git a/dlls/mshtml/htmlframe.c b/dlls/mshtml/htmlframe.c index 38bb53dc551..8d84ce54e58 100644 --- a/dlls/mshtml/htmlframe.c +++ b/dlls/mshtml/htmlframe.c @@ -970,8 +970,8 @@ static HRESULT HTMLFrameElement_invoke(HTMLDOMNode *iface, DISPID id, LCID lcid, return E_FAIL; } - return IDispatchEx_InvokeEx(&This->framebase.content_window->base.IDispatchEx_iface, id, lcid, - flags, params, res, ei, caller); + return dispex_invoke(&This->framebase.content_window->base.inner_window->event_target.dispex, + id, lcid, flags, params, res, ei, caller); } static HRESULT HTMLFrameElement_bind_to_tree(HTMLDOMNode *iface) @@ -1557,8 +1557,8 @@ static HRESULT HTMLIFrame_invoke(HTMLDOMNode *iface, DISPID id, LCID lcid, return E_FAIL; } - return IDispatchEx_InvokeEx(&This->framebase.content_window->base.IDispatchEx_iface, id, lcid, - flags, params, res, ei, caller); + return dispex_invoke(&This->framebase.content_window->base.inner_window->event_target.dispex, + id, lcid, flags, params, res, ei, caller); } static HRESULT HTMLIFrame_get_readystate(HTMLDOMNode *iface, BSTR *p) diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index a9a4b7fdd27..c63d26d68a2 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -4001,7 +4001,7 @@ static HRESULT HTMLWindow_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD prop->type = GLOBAL_DISPEXVAR; prop->id = dispex_id; - return IDispatchEx_InvokeEx(&This->event_target.dispex.IDispatchEx_iface, dispex_id, 0, flags, params, res, ei, caller); + return dispex_invoke(&This->event_target.dispex, dispex_id, 0, flags, params, res, ei, caller); } default: FIXME("Not supported flags: %x\n", flags); @@ -4029,7 +4029,7 @@ static HRESULT HTMLWindow_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD return E_NOTIMPL; } case GLOBAL_DISPEXVAR: - return IDispatchEx_InvokeEx(&This->event_target.dispex.IDispatchEx_iface, prop->id, 0, flags, params, res, ei, caller); + return dispex_invoke(&This->event_target.dispex, prop->id, 0, flags, params, res, ei, caller); default: ERR("invalid type %d\n", prop->type); hres = DISP_E_MEMBERNOTFOUND; @@ -4090,7 +4090,7 @@ static HRESULT IHTMLWindow2_location_hook(DispatchEx *dispex, WORD flags, DISPPA get_location(This->base.outer_window, &location); - hres = IDispatchEx_InvokeEx(&location->dispex.IDispatchEx_iface, DISPID_VALUE, 0, flags, dp, res, ei, caller); + hres = dispex_invoke(&location->dispex, DISPID_VALUE, 0, flags, dp, res, ei, caller); IHTMLLocation_Release(&location->IHTMLLocation_iface); return hres; } diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index b8aec96bae1..980efe78611 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -414,6 +414,8 @@ HRESULT dispex_get_dprop_ref(DispatchEx*,const WCHAR*,BOOL,VARIANT**) DECLSPEC_H HRESULT get_dispids(tid_t,DWORD*,DISPID**) DECLSPEC_HIDDEN; HRESULT remove_attribute(DispatchEx*,DISPID,VARIANT_BOOL*) DECLSPEC_HIDDEN; HRESULT dispex_get_dynid(DispatchEx*,const WCHAR*,BOOL,DISPID*) DECLSPEC_HIDDEN; +HRESULT dispex_invoke(DispatchEx*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*) DECLSPEC_HIDDEN; +HRESULT dispex_delete_prop(DispatchEx*,DISPID) DECLSPEC_HIDDEN; void dispex_traverse(DispatchEx*,nsCycleCollectionTraversalCallback*) DECLSPEC_HIDDEN; void dispex_unlink(DispatchEx*) DECLSPEC_HIDDEN; void release_typelib(void) DECLSPEC_HIDDEN; From f57cd658990b560a126c2f32e918145e94b0ad26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:00 +0200 Subject: [PATCH 0860/2777] mshtml: Move the window's custom prop lookup into a helper. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlwindow.c | 42 ++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index c63d26d68a2..1a8c1265440 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3647,28 +3647,17 @@ HRESULT search_window_props(HTMLInnerWindow *This, BSTR bstrName, DWORD grfdex, return DISP_E_UNKNOWNNAME; } -static HRESULT WINAPI WindowDispEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) +static HRESULT lookup_custom_prop(HTMLWindow *html_window, BSTR name, DISPID *pid) { - HTMLWindow *This = impl_from_IDispatchEx(iface); - HTMLInnerWindow *window = This->inner_window; + HTMLInnerWindow *window = html_window->inner_window; HTMLOuterWindow *frame; HRESULT hres; - TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(bstrName), grfdex, pid); - - hres = search_window_props(window, bstrName, grfdex, pid); - if(hres != DISP_E_UNKNOWNNAME) - return hres; - - hres = IDispatchEx_GetDispID(&window->base.inner_window->event_target.dispex.IDispatchEx_iface, bstrName, grfdex, pid); - if(hres != DISP_E_UNKNOWNNAME) - return hres; - - hres = get_frame_by_name(This->outer_window, bstrName, FALSE, &frame); + hres = get_frame_by_name(html_window->outer_window, name, FALSE, &frame); if(SUCCEEDED(hres) && frame) { global_prop_t *prop; - prop = alloc_global_prop(window, GLOBAL_FRAMEVAR, bstrName); + prop = alloc_global_prop(window, GLOBAL_FRAMEVAR, name); if(!prop) return E_OUTOFMEMORY; @@ -3681,11 +3670,11 @@ static HRESULT WINAPI WindowDispEx_GetDispID(IDispatchEx *iface, BSTR bstrName, IHTMLElement *elem; hres = IHTMLDocument3_getElementById(&window->base.inner_window->doc->IHTMLDocument3_iface, - bstrName, &elem); + name, &elem); if(SUCCEEDED(hres) && elem) { IHTMLElement_Release(elem); - prop = alloc_global_prop(window, GLOBAL_ELEMENTVAR, bstrName); + prop = alloc_global_prop(window, GLOBAL_ELEMENTVAR, name); if(!prop) return E_OUTOFMEMORY; @@ -3697,6 +3686,25 @@ static HRESULT WINAPI WindowDispEx_GetDispID(IDispatchEx *iface, BSTR bstrName, return DISP_E_UNKNOWNNAME; } +static HRESULT WINAPI WindowDispEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) +{ + HTMLWindow *This = impl_from_IDispatchEx(iface); + HTMLInnerWindow *window = This->inner_window; + HRESULT hres; + + TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(bstrName), grfdex, pid); + + hres = search_window_props(window, bstrName, grfdex, pid); + if(hres != DISP_E_UNKNOWNNAME) + return hres; + + hres = IDispatchEx_GetDispID(&window->base.inner_window->event_target.dispex.IDispatchEx_iface, bstrName, grfdex, pid); + if(hres != DISP_E_UNKNOWNNAME) + return hres; + + return lookup_custom_prop(This, bstrName, pid); +} + static HRESULT WINAPI WindowDispEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { From 32164d8953c67cd0aa9002898f19a99954a0a409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:00 +0200 Subject: [PATCH 0861/2777] mshtml: Pass along a separate "this" dispatch object when invoking. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed for jscript proxies, so that the accessors or functions are called on the right object, instead of the prototype. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/dispex.c | 44 +++++++++++++++++++----------------- dlls/mshtml/htmldoc.c | 5 ++-- dlls/mshtml/htmlelem.c | 21 ++++++++--------- dlls/mshtml/htmlelemcol.c | 4 ++-- dlls/mshtml/htmlform.c | 2 +- dlls/mshtml/htmlframe.c | 8 +++---- dlls/mshtml/htmlnode.c | 4 ++-- dlls/mshtml/htmlobject.c | 2 +- dlls/mshtml/htmlselect.c | 4 ++-- dlls/mshtml/htmlstorage.c | 4 ++-- dlls/mshtml/htmlstylesheet.c | 8 +++---- dlls/mshtml/htmlwindow.c | 11 +++++---- dlls/mshtml/mshtml_private.h | 6 ++--- 13 files changed, 63 insertions(+), 60 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index c6f3a128690..0a079626a95 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1058,8 +1058,8 @@ static HRESULT function_get_name(DispatchEx *dispex, DISPID id, BSTR *name) return (*name = SysAllocString(function_props[idx].name)) ? S_OK : E_OUTOFMEMORY; } -static HRESULT function_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, - VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT function_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, + DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { func_disp_t *This = impl_from_DispatchEx(dispex); DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN; @@ -1115,7 +1115,7 @@ static func_disp_t *create_func_disp(DispatchEx *obj, func_info_t *info) return ret; } -static HRESULT invoke_disp_value(DispatchEx *This, IDispatch *func_disp, LCID lcid, WORD flags, DISPPARAMS *dp, +static HRESULT invoke_disp_value(IDispatch *this_obj, IDispatch *func_disp, LCID lcid, WORD flags, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { DISPID named_arg = DISPID_THIS; @@ -1136,7 +1136,7 @@ static HRESULT invoke_disp_value(DispatchEx *This, IDispatch *func_disp, LCID lc memcpy(new_dp.rgvarg+1, dp->rgvarg, dp->cArgs*sizeof(VARIANTARG)); V_VT(new_dp.rgvarg) = VT_DISPATCH; - V_DISPATCH(new_dp.rgvarg) = (IDispatch*)&This->IDispatchEx_iface; + V_DISPATCH(new_dp.rgvarg) = this_obj; hres = IDispatch_QueryInterface(func_disp, &IID_IDispatchEx, (void**)&dispex); TRACE(">>>\n"); @@ -1480,7 +1480,7 @@ static HRESULT invoke_builtin_function(IDispatch *this_obj, func_info_t *func, D return V_ERROR(&vhres); } -static HRESULT func_invoke(DispatchEx *This, func_info_t *func, WORD flags, DISPPARAMS *dp, VARIANT *res, +static HRESULT func_invoke(DispatchEx *This, IDispatch *this_obj, func_info_t *func, WORD flags, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { HRESULT hres; @@ -1506,12 +1506,12 @@ static HRESULT func_invoke(DispatchEx *This, func_info_t *func, WORD flags, DISP return E_FAIL; } - hres = invoke_disp_value(This, V_DISPATCH(&entry->val), 0, flags, dp, res, ei, NULL); + hres = invoke_disp_value(this_obj, V_DISPATCH(&entry->val), 0, flags, dp, res, ei, NULL); break; } } - hres = invoke_builtin_function((IDispatch*)&This->IDispatchEx_iface, func, dp, res, ei, caller); + hres = invoke_builtin_function(this_obj, func, dp, res, ei, caller); break; case DISPATCH_PROPERTYGET: { func_obj_entry_t *entry; @@ -1564,9 +1564,10 @@ static HRESULT func_invoke(DispatchEx *This, func_info_t *func, WORD flags, DISP return hres; } -static HRESULT invoke_builtin_prop(DispatchEx *This, DISPID id, LCID lcid, WORD flags, DISPPARAMS *dp, - VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT invoke_builtin_prop(DispatchEx *This, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, + DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { + DispatchEx *dispex; func_info_t *func; IUnknown *iface; HRESULT hres; @@ -1578,14 +1579,15 @@ static HRESULT invoke_builtin_prop(DispatchEx *This, DISPID id, LCID lcid, WORD return hres; if(func->func_disp_idx >= 0) - return func_invoke(This, func, flags, dp, res, ei, caller); + return func_invoke(This, this_obj, func, flags, dp, res, ei, caller); - hres = IDispatchEx_QueryInterface(&This->IDispatchEx_iface, tid_ids[func->tid], (void**)&iface); + hres = IDispatch_QueryInterface(this_obj, tid_ids[func->tid], (void**)&iface); if(FAILED(hres) || !iface) return E_UNEXPECTED; - if(func->hook) { - hres = func->hook(This, flags, dp, res, ei, caller); + if(func->hook && (dispex = get_dispex_for_hook(iface))) { + hres = func->hook(dispex, flags, dp, res, ei, caller); + IDispatchEx_Release(&dispex->IDispatchEx_iface); if(hres != S_FALSE) { IUnknown_Release(iface); return hres; @@ -1619,7 +1621,7 @@ static HRESULT invoke_builtin_prop(DispatchEx *This, DISPID id, LCID lcid, WORD break; } - hres = invoke_disp_value(This, V_DISPATCH(&v), lcid, flags, dp, res, ei, caller); + hres = invoke_disp_value(this_obj, V_DISPATCH(&v), lcid, flags, dp, res, ei, caller); IDispatch_Release(V_DISPATCH(&v)); }else if(res) { *res = v; @@ -1854,7 +1856,7 @@ static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); - return dispex_invoke(This, dispIdMember, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, NULL); + return dispex_invoke(This, (IDispatch*)iface, dispIdMember, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, NULL); } static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid) @@ -1890,7 +1892,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); - return dispex_invoke(This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); + return dispex_invoke(This, (IDispatch*)iface, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); } static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR name, DWORD grfdex) @@ -2105,8 +2107,8 @@ BOOL dispex_query_interface(DispatchEx *This, REFIID riid, void **ppv) return TRUE; } -HRESULT dispex_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *res, - EXCEPINFO *pei, IServiceProvider *caller) +HRESULT dispex_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *res, EXCEPINFO *pei, IServiceProvider *caller) { HRESULT hres; @@ -2120,7 +2122,7 @@ HRESULT dispex_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD wFlags, DIS case DISPEXPROP_CUSTOM: if(!dispex->info->desc->vtbl || !dispex->info->desc->vtbl->invoke) return DISP_E_MEMBERNOTFOUND; - return dispex->info->desc->vtbl->invoke(dispex, id, lcid, wFlags, pdp, res, pei, caller); + return dispex->info->desc->vtbl->invoke(dispex, this_obj, id, lcid, wFlags, pdp, res, pei, caller); case DISPEXPROP_DYNAMIC: { DWORD idx = id - DISPID_DYNPROP_0; @@ -2142,7 +2144,7 @@ HRESULT dispex_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD wFlags, DIS return E_NOTIMPL; } - return invoke_disp_value(dispex, V_DISPATCH(&prop->var), lcid, wFlags, pdp, res, pei, caller); + return invoke_disp_value(this_obj, V_DISPATCH(&prop->var), lcid, wFlags, pdp, res, pei, caller); case DISPATCH_PROPERTYGET: if(prop->flags & DYNPROP_DELETED) return DISP_E_MEMBERNOTFOUND; @@ -2181,7 +2183,7 @@ HRESULT dispex_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD wFlags, DIS return E_FAIL; } - return invoke_builtin_prop(dispex, id, lcid, wFlags, pdp, res, pei, caller); + return invoke_builtin_prop(dispex, this_obj, id, lcid, wFlags, pdp, res, pei, caller); default: assert(0); return E_FAIL; diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index a5e647c86d9..c7b329034cd 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -5962,8 +5962,8 @@ static HRESULT HTMLDocumentNode_get_name(DispatchEx *dispex, DISPID id, BSTR *na return (*name = SysAllocString(This->elem_vars[idx])) ? S_OK : E_OUTOFMEMORY; } -static HRESULT HTMLDocumentNode_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, - VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT HTMLDocumentNode_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, + DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { HTMLDocumentNode *This = impl_from_DispatchEx(dispex); nsIDOMElement *nselem; @@ -6117,6 +6117,7 @@ static HRESULT HTMLDocumentNode_location_hook(DispatchEx *dispex, WORD flags, DI return S_FALSE; return dispex_invoke(&This->outer_window->base.inner_window->event_target.dispex, + (IDispatch*)&This->outer_window->base.inner_window->base.IHTMLWindow2_iface, DISPID_IHTMLWINDOW2_LOCATION, 0, flags, dp, res, ei, caller); } diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 5afe4af69b2..a2461c9b3bc 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -1122,8 +1122,8 @@ static HRESULT HTMLRectCollection_get_name(DispatchEx *dispex, DISPID id, BSTR * return (*name = SysAllocStringLen(buf, len)) ? S_OK : E_OUTOFMEMORY; } -static HRESULT HTMLRectCollection_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, - VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT HTMLRectCollection_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, + DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { HTMLRectCollection *This = HTMLRectCollection_from_DispatchEx(dispex); @@ -2564,8 +2564,8 @@ static HRESULT WINAPI HTMLElement_toString(IHTMLElement *iface, BSTR *String) if(!String) return E_INVALIDARG; - hres = dispex_invoke(&This->node.event_target.dispex, DISPID_VALUE, LOCALE_SYSTEM_DEFAULT, - DISPATCH_PROPERTYGET, NULL, &var, NULL, NULL); + hres = dispex_invoke(&This->node.event_target.dispex, (IDispatch*)&This->node.event_target.dispex.IDispatchEx_iface, + DISPID_VALUE, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, NULL, &var, NULL, NULL); if(SUCCEEDED(hres)) { assert(V_VT(&var) == VT_BSTR); *String = V_BSTR(&var); @@ -6852,14 +6852,13 @@ static HRESULT HTMLElement_get_name(DispatchEx *dispex, DISPID id, BSTR *name) return DISP_E_MEMBERNOTFOUND; } -static HRESULT HTMLElement_invoke(DispatchEx *dispex, DISPID id, LCID lcid, - WORD flags, DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, - IServiceProvider *caller) +static HRESULT HTMLElement_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID lcid, + WORD flags, DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { HTMLElement *This = impl_from_DispatchEx(dispex); if(This->node.vtbl->invoke) - return This->node.vtbl->invoke(&This->node, id, lcid, flags, + return This->node.vtbl->invoke(&This->node, this_obj, id, lcid, flags, params, res, ei, caller); ERR("(%p): element has no invoke method\n", This); @@ -7918,8 +7917,8 @@ static HRESULT HTMLFiltersCollection_get_name(DispatchEx *dispex, DISPID id, BST return (*name = SysAllocStringLen(buf, len)) ? S_OK : E_OUTOFMEMORY; } -static HRESULT HTMLFiltersCollection_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, - VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT HTMLFiltersCollection_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, + DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { TRACE("(%p)->(%lx %lx %x %p %p %p)\n", dispex, id, lcid, flags, params, res, ei); @@ -8653,7 +8652,7 @@ static HRESULT HTMLAttributeCollection_get_name(DispatchEx *dispex, DISPID id, B return E_NOTIMPL; } -static HRESULT HTMLAttributeCollection_invoke(DispatchEx *dispex, DISPID id, LCID lcid, +static HRESULT HTMLAttributeCollection_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { HTMLAttributeCollection *This = HTMLAttributeCollection_from_DispatchEx(dispex); diff --git a/dlls/mshtml/htmlelemcol.c b/dlls/mshtml/htmlelemcol.c index 6172bc2d57e..031028989fb 100644 --- a/dlls/mshtml/htmlelemcol.c +++ b/dlls/mshtml/htmlelemcol.c @@ -595,8 +595,8 @@ static HRESULT HTMLElementCollection_get_name(DispatchEx *dispex, DISPID id, BST return (*name = SysAllocStringLen(buf, len)) ? S_OK : E_OUTOFMEMORY; } -static HRESULT HTMLElementCollection_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, - VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT HTMLElementCollection_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, + DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { HTMLElementCollection *This = impl_from_DispatchEx(dispex); DWORD idx; diff --git a/dlls/mshtml/htmlform.c b/dlls/mshtml/htmlform.c index 505e8330cb9..6429b6b9ed7 100644 --- a/dlls/mshtml/htmlform.c +++ b/dlls/mshtml/htmlform.c @@ -923,7 +923,7 @@ static HRESULT HTMLFormElement_dispex_get_name(HTMLDOMNode *iface, DISPID id, BS return (*name = SysAllocStringLen(buf, len)) ? S_OK : E_OUTOFMEMORY; } -static HRESULT HTMLFormElement_invoke(HTMLDOMNode *iface, +static HRESULT HTMLFormElement_invoke(HTMLDOMNode *iface, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { diff --git a/dlls/mshtml/htmlframe.c b/dlls/mshtml/htmlframe.c index 8d84ce54e58..992ec13d6e5 100644 --- a/dlls/mshtml/htmlframe.c +++ b/dlls/mshtml/htmlframe.c @@ -960,7 +960,7 @@ static HRESULT HTMLFrameElement_get_name(HTMLDOMNode *iface, DISPID id, BSTR *na return *name ? S_OK : E_OUTOFMEMORY; } -static HRESULT HTMLFrameElement_invoke(HTMLDOMNode *iface, DISPID id, LCID lcid, +static HRESULT HTMLFrameElement_invoke(HTMLDOMNode *iface, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { HTMLFrameElement *This = frame_from_HTMLDOMNode(iface); @@ -971,7 +971,7 @@ static HRESULT HTMLFrameElement_invoke(HTMLDOMNode *iface, DISPID id, LCID lcid, } return dispex_invoke(&This->framebase.content_window->base.inner_window->event_target.dispex, - id, lcid, flags, params, res, ei, caller); + this_obj, id, lcid, flags, params, res, ei, caller); } static HRESULT HTMLFrameElement_bind_to_tree(HTMLDOMNode *iface) @@ -1547,7 +1547,7 @@ static HRESULT HTMLIFrame_get_name(HTMLDOMNode *iface, DISPID id, BSTR *name) return *name ? S_OK : E_OUTOFMEMORY; } -static HRESULT HTMLIFrame_invoke(HTMLDOMNode *iface, DISPID id, LCID lcid, +static HRESULT HTMLIFrame_invoke(HTMLDOMNode *iface, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { HTMLIFrame *This = iframe_from_HTMLDOMNode(iface); @@ -1558,7 +1558,7 @@ static HRESULT HTMLIFrame_invoke(HTMLDOMNode *iface, DISPID id, LCID lcid, } return dispex_invoke(&This->framebase.content_window->base.inner_window->event_target.dispex, - id, lcid, flags, params, res, ei, caller); + this_obj, id, lcid, flags, params, res, ei, caller); } static HRESULT HTMLIFrame_get_readystate(HTMLDOMNode *iface, BSTR *p) diff --git a/dlls/mshtml/htmlnode.c b/dlls/mshtml/htmlnode.c index 5d70b09e234..6961c823f62 100644 --- a/dlls/mshtml/htmlnode.c +++ b/dlls/mshtml/htmlnode.c @@ -401,8 +401,8 @@ static HRESULT HTMLDOMChildrenCollection_get_name(DispatchEx *dispex, DISPID id, return (*name = SysAllocStringLen(buf, len)) ? S_OK : E_OUTOFMEMORY; } -static HRESULT HTMLDOMChildrenCollection_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, - VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT HTMLDOMChildrenCollection_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, + DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { HTMLDOMChildrenCollection *This = impl_from_DispatchEx(dispex); diff --git a/dlls/mshtml/htmlobject.c b/dlls/mshtml/htmlobject.c index 60746562692..b5ae14f0d32 100644 --- a/dlls/mshtml/htmlobject.c +++ b/dlls/mshtml/htmlobject.c @@ -718,7 +718,7 @@ static HRESULT HTMLObjectElement_dispex_get_name(HTMLDOMNode *iface, DISPID id, return E_NOTIMPL; } -static HRESULT HTMLObjectElement_invoke(HTMLDOMNode *iface, DISPID id, LCID lcid, +static HRESULT HTMLObjectElement_invoke(HTMLDOMNode *iface, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { HTMLObjectElement *This = impl_from_HTMLDOMNode(iface); diff --git a/dlls/mshtml/htmlselect.c b/dlls/mshtml/htmlselect.c index c5610b41a1d..b4275a2d5ae 100644 --- a/dlls/mshtml/htmlselect.c +++ b/dlls/mshtml/htmlselect.c @@ -1414,8 +1414,8 @@ static HRESULT HTMLSelectElement_dispex_get_name(HTMLDOMNode *iface, DISPID id, return (*name = SysAllocStringLen(buf, len)) ? S_OK : E_OUTOFMEMORY; } -static HRESULT HTMLSelectElement_invoke(HTMLDOMNode *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, - VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT HTMLSelectElement_invoke(HTMLDOMNode *iface, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, + DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { HTMLSelectElement *This = impl_from_HTMLDOMNode(iface); diff --git a/dlls/mshtml/htmlstorage.c b/dlls/mshtml/htmlstorage.c index 30598113034..153dcfaa204 100644 --- a/dlls/mshtml/htmlstorage.c +++ b/dlls/mshtml/htmlstorage.c @@ -1170,8 +1170,8 @@ static HRESULT HTMLStorage_get_name(DispatchEx *dispex, DISPID id, BSTR *name) return (*name = SysAllocString(This->props[idx])) ? S_OK : E_OUTOFMEMORY; } -static HRESULT HTMLStorage_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, - VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT HTMLStorage_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, + DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { HTMLStorage *This = impl_from_DispatchEx(dispex); DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN; diff --git a/dlls/mshtml/htmlstylesheet.c b/dlls/mshtml/htmlstylesheet.c index 59680d720e2..611f966228e 100644 --- a/dlls/mshtml/htmlstylesheet.c +++ b/dlls/mshtml/htmlstylesheet.c @@ -425,8 +425,8 @@ static HRESULT HTMLStyleSheetRulesCollection_get_name(DispatchEx *dispex, DISPID return (*name = SysAllocStringLen(buf, len)) ? S_OK : E_OUTOFMEMORY; } -static HRESULT HTMLStyleSheetRulesCollection_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, - VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT HTMLStyleSheetRulesCollection_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, + DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { HTMLStyleSheetRulesCollection *This = HTMLStyleSheetRulesCollection_from_DispatchEx(dispex); @@ -852,8 +852,8 @@ static HRESULT HTMLStyleSheetsCollection_get_name(DispatchEx *dispex, DISPID id, return (*name = SysAllocStringLen(buf, len)) ? S_OK : E_OUTOFMEMORY; } -static HRESULT HTMLStyleSheetsCollection_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, - VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT HTMLStyleSheetsCollection_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, + DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { HTMLStyleSheetsCollection *This = HTMLStyleSheetsCollection_from_DispatchEx(dispex); diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 1a8c1265440..9c850c3a82a 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3944,8 +3944,8 @@ static HRESULT HTMLWindow_get_name(DispatchEx *dispex, DISPID id, BSTR *name) return (*name = SysAllocString(This->global_props[idx].name)) ? S_OK : E_OUTOFMEMORY; } -static HRESULT HTMLWindow_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params, - VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +static HRESULT HTMLWindow_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, + DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { HTMLInnerWindow *This = impl_from_DispatchEx(dispex); global_prop_t *prop; @@ -4009,7 +4009,7 @@ static HRESULT HTMLWindow_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD prop->type = GLOBAL_DISPEXVAR; prop->id = dispex_id; - return dispex_invoke(&This->event_target.dispex, dispex_id, 0, flags, params, res, ei, caller); + return dispex_invoke(&This->event_target.dispex, this_obj, dispex_id, 0, flags, params, res, ei, caller); } default: FIXME("Not supported flags: %x\n", flags); @@ -4037,7 +4037,7 @@ static HRESULT HTMLWindow_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD return E_NOTIMPL; } case GLOBAL_DISPEXVAR: - return dispex_invoke(&This->event_target.dispex, prop->id, 0, flags, params, res, ei, caller); + return dispex_invoke(&This->event_target.dispex, this_obj, prop->id, 0, flags, params, res, ei, caller); default: ERR("invalid type %d\n", prop->type); hres = DISP_E_MEMBERNOTFOUND; @@ -4098,7 +4098,8 @@ static HRESULT IHTMLWindow2_location_hook(DispatchEx *dispex, WORD flags, DISPPA get_location(This->base.outer_window, &location); - hres = dispex_invoke(&location->dispex, DISPID_VALUE, 0, flags, dp, res, ei, caller); + hres = dispex_invoke(&location->dispex, (IDispatch*)&location->IHTMLLocation_iface, + DISPID_VALUE, 0, flags, dp, res, ei, caller); IHTMLLocation_Release(&location->IHTMLLocation_iface); return hres; } diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 980efe78611..f4f1987954a 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -344,7 +344,7 @@ typedef struct { HRESULT (*value)(DispatchEx*,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*); HRESULT (*get_dispid)(DispatchEx*,BSTR,DWORD,DISPID*); HRESULT (*get_name)(DispatchEx*,DISPID,BSTR*); - HRESULT (*invoke)(DispatchEx*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*); + HRESULT (*invoke)(DispatchEx*,IDispatch*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*); HRESULT (*delete)(DispatchEx*,DISPID); HRESULT (*next_dispid)(DispatchEx*,DISPID,DISPID*); compat_mode_t (*get_compat_mode)(DispatchEx*); @@ -414,7 +414,7 @@ HRESULT dispex_get_dprop_ref(DispatchEx*,const WCHAR*,BOOL,VARIANT**) DECLSPEC_H HRESULT get_dispids(tid_t,DWORD*,DISPID**) DECLSPEC_HIDDEN; HRESULT remove_attribute(DispatchEx*,DISPID,VARIANT_BOOL*) DECLSPEC_HIDDEN; HRESULT dispex_get_dynid(DispatchEx*,const WCHAR*,BOOL,DISPID*) DECLSPEC_HIDDEN; -HRESULT dispex_invoke(DispatchEx*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*) DECLSPEC_HIDDEN; +HRESULT dispex_invoke(DispatchEx*,IDispatch*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*) DECLSPEC_HIDDEN; HRESULT dispex_delete_prop(DispatchEx*,DISPID) DECLSPEC_HIDDEN; void dispex_traverse(DispatchEx*,nsCycleCollectionTraversalCallback*) DECLSPEC_HIDDEN; void dispex_unlink(DispatchEx*) DECLSPEC_HIDDEN; @@ -820,7 +820,7 @@ typedef struct { HRESULT (*get_readystate)(HTMLDOMNode*,BSTR*); HRESULT (*get_dispid)(HTMLDOMNode*,BSTR,DWORD,DISPID*); HRESULT (*get_name)(HTMLDOMNode*,DISPID,BSTR*); - HRESULT (*invoke)(HTMLDOMNode*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*); + HRESULT (*invoke)(HTMLDOMNode*,IDispatch*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*); HRESULT (*bind_to_tree)(HTMLDOMNode*); void (*traverse)(HTMLDOMNode*,nsCycleCollectionTraversalCallback*); void (*unlink)(HTMLDOMNode*); From 9fdffe57729ff8c98a029c82e49c4fd2f72d6fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:00 +0200 Subject: [PATCH 0862/2777] mshtml: Always initialize refcount and vtable before calling init_dispatch. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This ensures that init_dispatch is always able to use IUnknown methods on the outer, which is going to be needed when initializing the proxy. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/dispex.c | 2 +- dlls/mshtml/htmldoc.c | 5 ++--- dlls/mshtml/htmlevent.c | 2 +- dlls/mshtml/omnavigator.c | 5 +++-- dlls/mshtml/range.c | 10 +++++----- dlls/mshtml/selection.c | 6 +++--- dlls/mshtml/xmlhttprequest.c | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 0a079626a95..00235b27a7e 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1107,10 +1107,10 @@ static func_disp_t *create_func_disp(DispatchEx *obj, func_info_t *info) return NULL; ret->IUnknown_iface.lpVtbl = &FunctionUnkVtbl; - init_dispatch(&ret->dispex, &ret->IUnknown_iface, &function_dispex, dispex_compat_mode(obj)); ret->ref = 1; ret->obj = obj; ret->info = info; + init_dispatch(&ret->dispex, &ret->IUnknown_iface, &function_dispex, dispex_compat_mode(obj)); return ret; } diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index c7b329034cd..a0235cb55e2 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -6295,13 +6295,12 @@ HRESULT create_document_node(nsIDOMDocument *nsdoc, GeckoBrowser *browser, HTMLI doc->html_document = NULL; } + doc->node.vtbl = &HTMLDocumentNodeImplVtbl; HTMLDOMNode_Init(doc, &doc->node, (nsIDOMNode*)doc->dom_document, &HTMLDocumentNode_dispex); init_document_mutation(doc); doc_init_events(doc); - doc->node.vtbl = &HTMLDocumentNodeImplVtbl; - list_add_head(&browser->document_nodes, &doc->browser_entry); doc->browser = browser; @@ -6330,8 +6329,8 @@ static HRESULT create_document_fragment(nsIDOMNode *nsnode, HTMLDocumentNode *do IHTMLWindow2_AddRef(&doc_frag->window->base.IHTMLWindow2_iface); - HTMLDOMNode_Init(doc_node, &doc_frag->node, nsnode, &HTMLDocumentNode_dispex); doc_frag->node.vtbl = &HTMLDocumentFragmentImplVtbl; + HTMLDOMNode_Init(doc_node, &doc_frag->node, nsnode, &HTMLDocumentNode_dispex); doc_frag->document_mode = lock_document_mode(doc_node); *ret = doc_frag; diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index c3b279d809a..2e264b5c08d 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -5676,8 +5676,8 @@ static int event_id_cmp(const void *key, const struct wine_rb_entry *entry) void EventTarget_Init(EventTarget *event_target, IUnknown *outer, dispex_static_data_t *dispex_data, compat_mode_t compat_mode) { - init_dispatch(&event_target->dispex, outer, dispex_data, compat_mode); event_target->IEventTarget_iface.lpVtbl = &EventTargetVtbl; + init_dispatch(&event_target->dispex, outer, dispex_data, compat_mode); wine_rb_init(&event_target->handler_map, event_id_cmp); } diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index aad722ab0b8..057ba402d9d 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -737,11 +737,12 @@ HRESULT create_history(HTMLInnerWindow *window, OmHistory **ret) if(!history) return E_OUTOFMEMORY; - init_dispatch(&history->dispex, (IUnknown*)&history->IOmHistory_iface, &OmHistory_dispex, - dispex_compat_mode(&window->event_target.dispex)); history->IOmHistory_iface.lpVtbl = &OmHistoryVtbl; history->ref = 1; + init_dispatch(&history->dispex, (IUnknown*)&history->IOmHistory_iface, &OmHistory_dispex, + dispex_compat_mode(&window->event_target.dispex)); + history->window = window; *ret = history; diff --git a/dlls/mshtml/range.c b/dlls/mshtml/range.c index 23a42987841..2124ae15f4a 100644 --- a/dlls/mshtml/range.c +++ b/dlls/mshtml/range.c @@ -1734,13 +1734,13 @@ HRESULT HTMLTxtRange_Create(HTMLDocumentNode *doc, nsIDOMRange *nsrange, IHTMLTx if(!ret) return E_OUTOFMEMORY; - init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLTxtRange_iface, &HTMLTxtRange_dispex, - dispex_compat_mode(&doc->node.event_target.dispex)); - ret->IHTMLTxtRange_iface.lpVtbl = &HTMLTxtRangeVtbl; ret->IOleCommandTarget_iface.lpVtbl = &OleCommandTargetVtbl; ret->ref = 1; + init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLTxtRange_iface, &HTMLTxtRange_dispex, + dispex_compat_mode(&doc->node.event_target.dispex)); + if(nsrange) nsIDOMRange_AddRef(nsrange); ret->nsrange = nsrange; @@ -2080,11 +2080,11 @@ HRESULT create_dom_range(nsIDOMRange *nsrange, compat_mode_t compat_mode, IHTMLD if(!ret) return E_OUTOFMEMORY; - init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLDOMRange_iface, &HTMLDOMRange_dispex, compat_mode); - ret->IHTMLDOMRange_iface.lpVtbl = &HTMLDOMRangeVtbl; ret->ref = 1; + init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLDOMRange_iface, &HTMLDOMRange_dispex, compat_mode); + if(nsrange) nsIDOMRange_AddRef(nsrange); ret->nsrange = nsrange; diff --git a/dlls/mshtml/selection.c b/dlls/mshtml/selection.c index 03a330d3f30..3b7769da759 100644 --- a/dlls/mshtml/selection.c +++ b/dlls/mshtml/selection.c @@ -349,14 +349,14 @@ HRESULT HTMLSelectionObject_Create(HTMLDocumentNode *doc, nsISelection *nsselect if(!selection) return E_OUTOFMEMORY; - init_dispatch(&selection->dispex, (IUnknown*)&selection->IHTMLSelectionObject_iface, - &HTMLSelectionObject_dispex, dispex_compat_mode(&doc->node.event_target.dispex)); - selection->IHTMLSelectionObject_iface.lpVtbl = &HTMLSelectionObjectVtbl; selection->IHTMLSelectionObject2_iface.lpVtbl = &HTMLSelectionObject2Vtbl; selection->ref = 1; selection->nsselection = nsselection; /* We shouldn't call AddRef here */ + init_dispatch(&selection->dispex, (IUnknown*)&selection->IHTMLSelectionObject_iface, + &HTMLSelectionObject_dispex, dispex_compat_mode(&doc->node.event_target.dispex)); + selection->doc = doc; list_add_head(&doc->selection_list, &selection->entry); diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index f26a013fc64..aa5cf3552a4 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1486,9 +1486,9 @@ static HRESULT WINAPI HTMLXMLHttpRequestFactory_create(IHTMLXMLHttpRequestFactor ret->IHTMLXMLHttpRequest2_iface.lpVtbl = &HTMLXMLHttpRequest2Vtbl; ret->IWineXMLHttpRequestPrivate_iface.lpVtbl = &WineXMLHttpRequestPrivateVtbl; ret->IProvideClassInfo2_iface.lpVtbl = &ProvideClassInfo2Vtbl; + ret->ref = 1; EventTarget_Init(&ret->event_target, (IUnknown*)&ret->IHTMLXMLHttpRequest_iface, &HTMLXMLHttpRequest_dispex, This->window->doc->document_mode); - ret->ref = 1; *p = &ret->IHTMLXMLHttpRequest_iface; return S_OK; From cc957d4386b5f7987314c8ead76d3b91dd1d0ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:00 +0200 Subject: [PATCH 0863/2777] mshtml: Initialize performance.navigation when creating the performance. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- We'll use the window to init its dispex, and this avoids circular ref. --- dlls/mshtml/omnavigator.c | 40 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 057ba402d9d..72b72531490 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -2110,8 +2110,7 @@ static ULONG WINAPI HTMLPerformance_Release(IHTMLPerformance *iface) if(!ref) { IHTMLPerformanceTiming_Release(&This->timing->IHTMLPerformanceTiming_iface); - if(This->navigation) - IHTMLPerformanceNavigation_Release(This->navigation); + IHTMLPerformanceNavigation_Release(This->navigation); release_dispex(&This->dispex); free(This); } @@ -2161,24 +2160,6 @@ static HRESULT WINAPI HTMLPerformance_get_navigation(IHTMLPerformance *iface, TRACE("(%p)->(%p)\n", This, p); - if(!This->navigation) { - HTMLPerformanceNavigation *navigation; - - navigation = calloc(1, sizeof(*navigation)); - if(!navigation) - return E_OUTOFMEMORY; - - navigation->IHTMLPerformanceNavigation_iface.lpVtbl = &HTMLPerformanceNavigationVtbl; - navigation->ref = 1; - navigation->timing = This->timing; - IHTMLPerformanceTiming_AddRef(&This->timing->IHTMLPerformanceTiming_iface); - - init_dispatch(&navigation->dispex, (IUnknown*)&navigation->IHTMLPerformanceNavigation_iface, - &HTMLPerformanceNavigation_dispex, dispex_compat_mode(&This->dispex)); - - This->navigation = &navigation->IHTMLPerformanceNavigation_iface; - } - IHTMLPerformanceNavigation_AddRef(*p = This->navigation); return S_OK; } @@ -2237,20 +2218,35 @@ static dispex_static_data_t HTMLPerformance_dispex = { HRESULT create_performance(HTMLInnerWindow *window, IHTMLPerformance **ret) { compat_mode_t compat_mode = dispex_compat_mode(&window->event_target.dispex); + HTMLPerformanceNavigation *navigation; HTMLPerformance *performance; performance = calloc(1, sizeof(*performance)); if(!performance) return E_OUTOFMEMORY; + navigation = calloc(1, sizeof(*navigation)); + if(!navigation) { + free(performance); + return E_OUTOFMEMORY; + } + performance->IHTMLPerformance_iface.lpVtbl = &HTMLPerformanceVtbl; + performance->navigation = &navigation->IHTMLPerformanceNavigation_iface; + performance->timing = window->performance_timing; performance->ref = 1; + IHTMLPerformanceTiming_AddRef(&performance->timing->IHTMLPerformanceTiming_iface); init_dispatch(&performance->dispex, (IUnknown*)&performance->IHTMLPerformance_iface, &HTMLPerformance_dispex, compat_mode); - performance->timing = window->performance_timing; - IHTMLPerformanceTiming_AddRef(&performance->timing->IHTMLPerformanceTiming_iface); + navigation->IHTMLPerformanceNavigation_iface.lpVtbl = &HTMLPerformanceNavigationVtbl; + navigation->ref = 1; + navigation->timing = window->performance_timing; + IHTMLPerformanceTiming_AddRef(&navigation->timing->IHTMLPerformanceTiming_iface); + + init_dispatch(&navigation->dispex, (IUnknown*)&navigation->IHTMLPerformanceNavigation_iface, + &HTMLPerformanceNavigation_dispex, compat_mode); init_dispatch(&performance->timing->dispex, (IUnknown*)&performance->timing->IHTMLPerformanceTiming_iface, &HTMLPerformanceTiming_dispex, compat_mode); From 9f4a0caf6c43440e38a07c32eb353accd254bced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:01 +0200 Subject: [PATCH 0864/2777] mshtml: Pass the inner window to init_dispatch. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently not used, but it will be used to initialize the proxy for non-delay-init dispex, since the window itself is the global object and should always have proxy available. This will also be needed later for legacy "prototypes" (in IE8 and below modes) where we'll have links to them from the window, so it will be needed anyway. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/dispex.c | 5 ++- dlls/mshtml/htmlattr.c | 5 ++- dlls/mshtml/htmlcurstyle.c | 2 +- dlls/mshtml/htmldoc.c | 42 +++++++++-------- dlls/mshtml/htmlelem.c | 57 +++++++++++++---------- dlls/mshtml/htmlelemcol.c | 25 ++++++----- dlls/mshtml/htmlevent.c | 87 +++++++++++++++++++++--------------- dlls/mshtml/htmlevent.h | 5 ++- dlls/mshtml/htmlform.c | 3 +- dlls/mshtml/htmlimg.c | 2 +- dlls/mshtml/htmllocation.c | 8 ++-- dlls/mshtml/htmlnode.c | 17 ++++--- dlls/mshtml/htmlselect.c | 2 +- dlls/mshtml/htmlstorage.c | 7 ++- dlls/mshtml/htmlstyle.c | 11 ++--- dlls/mshtml/htmlstyle.h | 5 ++- dlls/mshtml/htmlstyleelem.c | 3 +- dlls/mshtml/htmlstylesheet.c | 44 +++++++++++------- dlls/mshtml/htmltable.c | 6 +-- dlls/mshtml/htmlwindow.c | 17 ++++--- dlls/mshtml/mshtml_private.h | 50 ++++++++++----------- dlls/mshtml/nsembed.c | 3 +- dlls/mshtml/nsevents.c | 10 ++--- dlls/mshtml/omnavigator.c | 44 +++++++++++------- dlls/mshtml/range.c | 7 +-- dlls/mshtml/selection.c | 3 +- dlls/mshtml/xmlhttprequest.c | 10 +++-- 27 files changed, 278 insertions(+), 202 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 00235b27a7e..ce662dac57e 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1110,7 +1110,7 @@ static func_disp_t *create_func_disp(DispatchEx *obj, func_info_t *info) ret->ref = 1; ret->obj = obj; ret->info = info; - init_dispatch(&ret->dispex, &ret->IUnknown_iface, &function_dispex, dispex_compat_mode(obj)); + init_dispatch(&ret->dispex, &ret->IUnknown_iface, &function_dispex, NULL, dispex_compat_mode(obj)); return ret; } @@ -2284,7 +2284,8 @@ void release_dispex(DispatchEx *This) free(This->dynamic_data); } -void init_dispatch(DispatchEx *dispex, IUnknown *outer, dispex_static_data_t *data, compat_mode_t compat_mode) +void init_dispatch(DispatchEx *dispex, IUnknown *outer, dispex_static_data_t *data, HTMLInnerWindow *window, + compat_mode_t compat_mode) { assert(compat_mode < COMPAT_MODE_CNT); diff --git a/dlls/mshtml/htmlattr.c b/dlls/mshtml/htmlattr.c index b7e40a23d55..cf512f88526 100644 --- a/dlls/mshtml/htmlattr.c +++ b/dlls/mshtml/htmlattr.c @@ -497,7 +497,8 @@ HTMLDOMAttribute *unsafe_impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute *iface) return iface->lpVtbl == &HTMLDOMAttributeVtbl ? impl_from_IHTMLDOMAttribute(iface) : NULL; } -HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLElement *elem, DISPID dispid, compat_mode_t compat_mode, HTMLDOMAttribute **attr) +HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLDocumentNode *doc, HTMLElement *elem, DISPID dispid, + compat_mode_t compat_mode, HTMLDOMAttribute **attr) { HTMLAttributeCollection *col; HTMLDOMAttribute *ret; @@ -514,7 +515,7 @@ HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLElement *elem, DISPID dis ret->elem = elem; init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLDOMAttribute_iface, - &HTMLDOMAttribute_dispex, compat_mode); + &HTMLDOMAttribute_dispex, get_inner_window(doc), compat_mode); /* For attributes attached to an element, (elem,dispid) pair should be valid used for its operation. */ if(elem) { diff --git a/dlls/mshtml/htmlcurstyle.c b/dlls/mshtml/htmlcurstyle.c index c7a9a3c086d..63eadd9057b 100644 --- a/dlls/mshtml/htmlcurstyle.c +++ b/dlls/mshtml/htmlcurstyle.c @@ -1357,7 +1357,7 @@ HRESULT HTMLCurrentStyle_Create(HTMLElement *elem, IHTMLCurrentStyle **p) ret->IHTMLCurrentStyle4_iface.lpVtbl = &HTMLCurrentStyle4Vtbl; init_css_style(&ret->css_style, nsstyle, HTMLCurrentStyle_QI, &HTMLCurrentStyle_dispex, - dispex_compat_mode(&elem->node.event_target.dispex)); + get_inner_window(elem->node.doc), dispex_compat_mode(&elem->node.event_target.dispex)); nsIDOMCSSStyleDeclaration_Release(nsstyle); IHTMLElement_AddRef(&elem->IHTMLElement_iface); diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index a0235cb55e2..aecf9e540c1 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -148,6 +148,12 @@ UINT get_document_charset(HTMLDocumentNode *doc) return doc->charset = ret; } +/* Get inner window even for document nodes with no window */ +HTMLInnerWindow *get_inner_window(HTMLDocumentNode *doc) +{ + return doc->window ? doc->window : doc->doc_obj->window->base.inner_window; +} + typedef struct { HTMLDOMNode node; IDOMDocumentType IDOMDocumentType_iface; @@ -623,7 +629,7 @@ static HRESULT WINAPI HTMLDocument_get_images(IHTMLDocument2 *iface, IHTMLElemen } if(nscoll) { - *p = create_collection_from_htmlcol(nscoll, This->document_mode); + *p = create_collection_from_htmlcol(nscoll, This, This->document_mode); nsIDOMHTMLCollection_Release(nscoll); } @@ -660,7 +666,7 @@ static HRESULT WINAPI HTMLDocument_get_applets(IHTMLDocument2 *iface, IHTMLEleme } if(nscoll) { - *p = create_collection_from_htmlcol(nscoll, This->document_mode); + *p = create_collection_from_htmlcol(nscoll, This, This->document_mode); nsIDOMHTMLCollection_Release(nscoll); } @@ -697,7 +703,7 @@ static HRESULT WINAPI HTMLDocument_get_links(IHTMLDocument2 *iface, IHTMLElement } if(nscoll) { - *p = create_collection_from_htmlcol(nscoll, This->document_mode); + *p = create_collection_from_htmlcol(nscoll, This, This->document_mode); nsIDOMHTMLCollection_Release(nscoll); } @@ -734,7 +740,7 @@ static HRESULT WINAPI HTMLDocument_get_forms(IHTMLDocument2 *iface, IHTMLElement } if(nscoll) { - *p = create_collection_from_htmlcol(nscoll, This->document_mode); + *p = create_collection_from_htmlcol(nscoll, This, This->document_mode); nsIDOMHTMLCollection_Release(nscoll); } @@ -771,7 +777,7 @@ static HRESULT WINAPI HTMLDocument_get_anchors(IHTMLDocument2 *iface, IHTMLEleme } if(nscoll) { - *p = create_collection_from_htmlcol(nscoll, This->document_mode); + *p = create_collection_from_htmlcol(nscoll, This, This->document_mode); nsIDOMHTMLCollection_Release(nscoll); } @@ -861,7 +867,7 @@ static HRESULT WINAPI HTMLDocument_get_scripts(IHTMLDocument2 *iface, IHTMLEleme } if(nscoll) { - *p = create_collection_from_htmlcol(nscoll, This->document_mode); + *p = create_collection_from_htmlcol(nscoll, This, This->document_mode); nsIDOMHTMLCollection_Release(nscoll); } @@ -2041,8 +2047,7 @@ static HRESULT WINAPI HTMLDocument_get_styleSheets(IHTMLDocument2 *iface, return map_nsresult(nsres); } - hres = create_style_sheet_collection(nsstylelist, - dispex_compat_mode(&This->node.event_target.dispex), p); + hres = create_style_sheet_collection(nsstylelist, This, p); nsIDOMStyleSheetList_Release(nsstylelist); return hres; } @@ -2111,8 +2116,7 @@ static HRESULT WINAPI HTMLDocument_createStyleSheet(IHTMLDocument2 *iface, BSTR if(bstrHref && *bstrHref) { FIXME("semi-stub for href %s\n", debugstr_w(bstrHref)); - return create_style_sheet(NULL, dispex_compat_mode(&This->node.event_target.dispex), - ppnewStyleSheet); + return create_style_sheet(NULL, This, ppnewStyleSheet); } hres = create_element(This, L"style", &elem); @@ -2745,7 +2749,7 @@ static HRESULT WINAPI HTMLDocument3_getElementsByName(IHTMLDocument3 *iface, BST return E_FAIL; } - *ppelColl = create_collection_from_nodelist(node_list, This->document_mode); + *ppelColl = create_collection_from_nodelist(node_list, This); nsIDOMNodeList_Release(node_list); return S_OK; } @@ -2819,7 +2823,7 @@ static HRESULT WINAPI HTMLDocument3_getElementsByTagName(IHTMLDocument3 *iface, } - *pelColl = create_collection_from_nodelist(nslist, This->document_mode); + *pelColl = create_collection_from_nodelist(nslist, This); nsIDOMNodeList_Release(nslist); return S_OK; @@ -3003,8 +3007,7 @@ static HRESULT WINAPI HTMLDocument4_get_namespaces(IHTMLDocument4 *iface, IDispa if(!This->namespaces) { HRESULT hres; - hres = create_namespace_collection(dispex_compat_mode(&This->node.event_target.dispex), - &This->namespaces); + hres = create_namespace_collection(This, &This->namespaces); if(FAILED(hres)) return hres; } @@ -3048,7 +3051,7 @@ static HRESULT WINAPI HTMLDocument4_createEventObject(IHTMLDocument4 *iface, return E_NOTIMPL; } - return create_event_obj(NULL, dispex_compat_mode(&This->node.event_target.dispex), ppEventObj); + return create_event_obj(This, NULL, ppEventObj); } static HRESULT WINAPI HTMLDocument4_fireEvent(IHTMLDocument4 *iface, BSTR bstrEventName, @@ -3242,7 +3245,8 @@ static HRESULT WINAPI HTMLDocument5_createAttribute(IHTMLDocument5 *iface, BSTR TRACE("(%p)->(%s %p)\n", This, debugstr_w(bstrattrName), ppattribute); - hres = HTMLDOMAttribute_Create(bstrattrName, NULL, 0, dispex_compat_mode(&This->node.event_target.dispex), &attr); + hres = HTMLDOMAttribute_Create(bstrattrName, This, NULL, 0, + dispex_compat_mode(&This->node.event_target.dispex), &attr); if(FAILED(hres)) return hres; @@ -3801,7 +3805,7 @@ static HRESULT WINAPI HTMLDocument7_getElementsByClassName(IHTMLDocument7 *iface } - *pel = create_collection_from_nodelist(nslist, This->document_mode); + *pel = create_collection_from_nodelist(nslist, This); nsIDOMNodeList_Release(nslist); return S_OK; } @@ -4783,7 +4787,7 @@ static HRESULT WINAPI DocumentSelector_querySelectorAll(IDocumentSelector *iface return map_nsresult(nsres); } - hres = create_child_collection(node_list, dispex_compat_mode(&This->node.event_target.dispex), pel); + hres = create_child_collection(node_list, This, pel); nsIDOMNodeList_Release(node_list); return hres; } @@ -5671,7 +5675,7 @@ static HRESULT WINAPI DocumentRange_createRange(IDocumentRange *iface, IHTMLDOMR if(NS_FAILED(nsIDOMDocument_CreateRange(This->dom_document, &nsrange))) return E_FAIL; - hres = create_dom_range(nsrange, dispex_compat_mode(&This->node.event_target.dispex), p); + hres = create_dom_range(nsrange, This, p); nsIDOMRange_Release(nsrange); return hres; } diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index a2461c9b3bc..6cc8aad4d81 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -348,7 +348,7 @@ static inline HTMLFiltersCollection *impl_from_IHTMLFiltersCollection(IHTMLFilte return CONTAINING_RECORD(iface, HTMLFiltersCollection, IHTMLFiltersCollection_iface); } -static HRESULT create_filters_collection(compat_mode_t compat_mode, IHTMLFiltersCollection **ret); +static HRESULT create_filters_collection(HTMLElement *elem, IHTMLFiltersCollection **ret); static inline HTMLElement *impl_from_IHTMLElement(IHTMLElement *iface) { @@ -752,7 +752,8 @@ static dispex_static_data_t HTMLRect_dispex = { HTMLRect_iface_tids }; -static HRESULT create_html_rect(nsIDOMClientRect *nsrect, compat_mode_t compat_mode, IHTMLRect **ret) +static HRESULT create_html_rect(nsIDOMClientRect *nsrect, HTMLInnerWindow *window, compat_mode_t compat_mode, + IHTMLRect **ret) { HTMLRect *rect; @@ -763,7 +764,7 @@ static HRESULT create_html_rect(nsIDOMClientRect *nsrect, compat_mode_t compat_m rect->IHTMLRect_iface.lpVtbl = &HTMLRectVtbl; rect->ref = 1; - init_dispatch(&rect->dispex, (IUnknown*)&rect->IHTMLRect_iface, &HTMLRect_dispex, compat_mode); + init_dispatch(&rect->dispex, (IUnknown*)&rect->IHTMLRect_iface, &HTMLRect_dispex, window, compat_mode); nsIDOMClientRect_AddRef(nsrect); rect->nsrect = nsrect; @@ -778,6 +779,7 @@ typedef struct { LONG ref; + HTMLInnerWindow *window; nsIDOMClientRectList *rect_list; } HTMLRectCollection; @@ -961,6 +963,7 @@ static ULONG WINAPI HTMLRectCollection_Release(IHTMLRectCollection *iface) if(!ref) { if(This->rect_list) nsIDOMClientRectList_Release(This->rect_list); + IHTMLWindow2_Release(&This->window->base.IHTMLWindow2_iface); release_dispex(&This->dispex); free(This); } @@ -1058,7 +1061,7 @@ static HRESULT WINAPI HTMLRectCollection_item(IHTMLRectCollection *iface, VARIAN return S_OK; } - hres = create_html_rect(nsrect, dispex_compat_mode(&This->dispex), &rect); + hres = create_html_rect(nsrect, This->window, dispex_compat_mode(&This->dispex), &rect); nsIDOMClientRect_Release(nsrect); if(FAILED(hres)) return hres; @@ -1142,7 +1145,7 @@ static HRESULT HTMLRectCollection_invoke(DispatchEx *dispex, IDispatch *this_obj return DISP_E_MEMBERNOTFOUND; } - hres = create_html_rect(rect, dispex_compat_mode(&This->dispex), &html_rect); + hres = create_html_rect(rect, This->window, dispex_compat_mode(&This->dispex), &html_rect); nsIDOMClientRect_Release(rect); if(FAILED(hres)) return hres; @@ -2532,7 +2535,7 @@ static HRESULT WINAPI HTMLElement_get_filters(IHTMLElement *iface, IHTMLFiltersC if(!p) return E_POINTER; - return create_filters_collection(dispex_compat_mode(&This->node.event_target.dispex), p); + return create_filters_collection(This, p); } static HRESULT WINAPI HTMLElement_put_ondragstart(IHTMLElement *iface, VARIANT v) @@ -2717,7 +2720,7 @@ static HRESULT WINAPI HTMLElement_get_children(IHTMLElement *iface, IDispatch ** return E_FAIL; } - *p = (IDispatch*)create_collection_from_nodelist(nsnode_list, This->node.doc->document_mode); + *p = (IDispatch*)create_collection_from_nodelist(nsnode_list, This->node.doc); nsIDOMNodeList_Release(nsnode_list); return S_OK; @@ -3192,8 +3195,11 @@ static HRESULT WINAPI HTMLElement2_getClientRects(IHTMLElement2 *iface, IHTMLRec rects->IHTMLRectCollection_iface.lpVtbl = &HTMLRectCollectionVtbl; rects->ref = 1; rects->rect_list = rect_list; - init_dispatch(&rects->dispex, (IUnknown*)&rects->IHTMLRectCollection_iface, - &HTMLRectCollection_dispex, dispex_compat_mode(&This->node.event_target.dispex)); + rects->window = get_inner_window(This->node.doc); + IHTMLWindow2_AddRef(&rects->window->base.IHTMLWindow2_iface); + + init_dispatch(&rects->dispex, (IUnknown*)&rects->IHTMLRectCollection_iface, &HTMLRectCollection_dispex, + rects->window, dispex_compat_mode(&This->node.event_target.dispex)); *pRectCol = &rects->IHTMLRectCollection_iface; return S_OK; @@ -3219,7 +3225,7 @@ static HRESULT WINAPI HTMLElement2_getBoundingClientRect(IHTMLElement2 *iface, I return E_FAIL; } - hres = create_html_rect(nsrect, dispex_compat_mode(&This->node.event_target.dispex), pRect); + hres = create_html_rect(nsrect, get_inner_window(This->node.doc), dispex_compat_mode(&This->node.event_target.dispex), pRect); nsIDOMClientRect_Release(nsrect); return hres; @@ -3946,7 +3952,7 @@ static HRESULT WINAPI HTMLElement2_getElementsByTagName(IHTMLElement2 *iface, BS TRACE("(%p)->(%s %p)\n", This, debugstr_w(v), pelColl); if(!This->dom_element) { - *pelColl = create_collection_from_htmlcol(NULL, This->node.doc->document_mode); + *pelColl = create_collection_from_htmlcol(NULL, This->node.doc, dispex_compat_mode(&This->node.event_target.dispex)); return S_OK; } @@ -3958,7 +3964,7 @@ static HRESULT WINAPI HTMLElement2_getElementsByTagName(IHTMLElement2 *iface, BS return E_FAIL; } - *pelColl = create_collection_from_htmlcol(nscol, dispex_compat_mode(&This->node.event_target.dispex)); + *pelColl = create_collection_from_htmlcol(nscol, This->node.doc, dispex_compat_mode(&This->node.event_target.dispex)); nsIDOMHTMLCollection_Release(nscol); return S_OK; } @@ -5111,7 +5117,7 @@ static HRESULT WINAPI HTMLElement6_getElementsByClassName(IHTMLElement6 *iface, } } - *pel = create_collection_from_htmlcol(nscol, dispex_compat_mode(&This->node.event_target.dispex)); + *pel = create_collection_from_htmlcol(nscol, This->node.doc, dispex_compat_mode(&This->node.event_target.dispex)); nsIDOMHTMLCollection_Release(nscol); return S_OK; } @@ -6385,7 +6391,7 @@ static HRESULT WINAPI ElementSelector_querySelectorAll(IElementSelector *iface, return map_nsresult(nsres); } - hres = create_child_collection(node_list, dispex_compat_mode(&This->node.event_target.dispex), pel); + hres = create_child_collection(node_list, This->node.doc, pel); nsIDOMNodeList_Release(node_list); return hres; } @@ -7529,7 +7535,7 @@ static dispex_static_data_t token_list_dispex = { token_list_iface_tids }; -static HRESULT create_token_list(compat_mode_t compat_mode, IHTMLElement *element, IWineDOMTokenList **ret) +static HRESULT create_token_list(compat_mode_t compat_mode, HTMLElement *element, IWineDOMTokenList **ret) { struct token_list *obj; @@ -7542,9 +7548,10 @@ static HRESULT create_token_list(compat_mode_t compat_mode, IHTMLElement *elemen obj->IWineDOMTokenList_iface.lpVtbl = &WineDOMTokenListVtbl; obj->ref = 1; - init_dispatch(&obj->dispex, (IUnknown*)&obj->IWineDOMTokenList_iface, &token_list_dispex, compat_mode); - IHTMLElement_AddRef(element); - obj->element = element; + init_dispatch(&obj->dispex, (IUnknown*)&obj->IWineDOMTokenList_iface, &token_list_dispex, + get_inner_window(element->node.doc), compat_mode); + IHTMLElement_AddRef(&element->IHTMLElement_iface); + obj->element = &element->IHTMLElement_iface; *ret = &obj->IWineDOMTokenList_iface; return S_OK; @@ -7618,7 +7625,7 @@ static HRESULT WINAPI htmlelement_private_get_classList(IWineHTMLElementPrivate TRACE("iface %p, class_list %p.\n", iface, class_list); - return create_token_list(dispex_compat_mode(&This->node.event_target.dispex), &This->IHTMLElement_iface, + return create_token_list(dispex_compat_mode(&This->node.event_target.dispex), This, (IWineDOMTokenList **)class_list); } @@ -7949,8 +7956,9 @@ static dispex_static_data_t HTMLFiltersCollection_dispex = { HTMLFiltersCollection_iface_tids }; -static HRESULT create_filters_collection(compat_mode_t compat_mode, IHTMLFiltersCollection **ret) +static HRESULT create_filters_collection(HTMLElement *elem, IHTMLFiltersCollection **ret) { + compat_mode_t compat_mode = dispex_compat_mode(&elem->node.event_target.dispex); HTMLFiltersCollection *collection; if(!(collection = malloc(sizeof(HTMLFiltersCollection)))) @@ -7960,7 +7968,8 @@ static HRESULT create_filters_collection(compat_mode_t compat_mode, IHTMLFilters collection->ref = 1; init_dispatch(&collection->dispex, (IUnknown*)&collection->IHTMLFiltersCollection_iface, - &HTMLFiltersCollection_dispex, min(compat_mode, COMPAT_MODE_IE8)); + &HTMLFiltersCollection_dispex, get_inner_window(elem->node.doc), + min(compat_mode, COMPAT_MODE_IE8)); *ret = &collection->IHTMLFiltersCollection_iface; return S_OK; @@ -8048,7 +8057,8 @@ static inline HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, LONG return E_UNEXPECTED; } - hres = HTMLDOMAttribute_Create(NULL, This->elem, id, dispex_compat_mode(&This->elem->node.event_target.dispex), attr); + hres = HTMLDOMAttribute_Create(NULL, This->elem->node.doc, This->elem, id, + dispex_compat_mode(&This->elem->node.event_target.dispex), attr); if(FAILED(hres)) return hres; } @@ -8730,7 +8740,8 @@ HRESULT HTMLElement_get_attr_col(HTMLDOMNode *iface, HTMLAttributeCollection **a This->attrs->elem = This; list_init(&This->attrs->attrs); init_dispatch(&This->attrs->dispex, (IUnknown*)&This->attrs->IHTMLAttributeCollection_iface, - &HTMLAttributeCollection_dispex, dispex_compat_mode(&iface->event_target.dispex)); + &HTMLAttributeCollection_dispex, get_inner_window(This->node.doc), + dispex_compat_mode(&iface->event_target.dispex)); *ac = This->attrs; return S_OK; diff --git a/dlls/mshtml/htmlelemcol.c b/dlls/mshtml/htmlelemcol.c index 031028989fb..e24b1a3c30a 100644 --- a/dlls/mshtml/htmlelemcol.c +++ b/dlls/mshtml/htmlelemcol.c @@ -35,6 +35,7 @@ typedef struct { DispatchEx dispex; IHTMLElementCollection IHTMLElementCollection_iface; + HTMLInnerWindow *window; HTMLElement **elems; DWORD len; @@ -62,7 +63,7 @@ static inline HTMLElement *elem_from_HTMLDOMNode(HTMLDOMNode *iface) return CONTAINING_RECORD(iface, HTMLElement, node); } -static IHTMLElementCollection *HTMLElementCollection_Create(HTMLElement**,DWORD,compat_mode_t); +static IHTMLElementCollection *HTMLElementCollection_Create(HTMLElement**,DWORD,HTMLInnerWindow*,compat_mode_t); static void elem_vector_add(elem_vector_t *buf, HTMLElement *elem) { @@ -259,6 +260,7 @@ static ULONG WINAPI HTMLElementCollection_Release(IHTMLElementCollection *iface) node_release(&This->elems[i]->node); free(This->elems); + IHTMLWindow2_Release(&This->window->base.IHTMLWindow2_iface); release_dispex(&This->dispex); free(This); } @@ -461,7 +463,7 @@ static HRESULT WINAPI HTMLElementCollection_item(IHTMLElementCollection *iface, if(buf.len > 1) { elem_vector_normalize(&buf); - *pdisp = (IDispatch*)HTMLElementCollection_Create(buf.buf, buf.len, + *pdisp = (IDispatch*)HTMLElementCollection_Create(buf.buf, buf.len, This->window, dispex_compat_mode(&This->dispex)); }else { if(buf.len == 1) { @@ -524,7 +526,7 @@ static HRESULT WINAPI HTMLElementCollection_tags(IHTMLElementCollection *iface, TRACE("found %ld tags\n", buf.len); - *pdisp = (IDispatch*)HTMLElementCollection_Create(buf.buf, buf.len, + *pdisp = (IDispatch*)HTMLElementCollection_Create(buf.buf, buf.len, This->window, dispex_compat_mode(&This->dispex)); return S_OK; } @@ -694,11 +696,11 @@ IHTMLElementCollection *create_all_collection(HTMLDOMNode *node, BOOL include_ro create_all_list(node, &buf); elem_vector_normalize(&buf); - return HTMLElementCollection_Create(buf.buf, buf.len, + return HTMLElementCollection_Create(buf.buf, buf.len, get_inner_window(node->doc), dispex_compat_mode(&node->event_target.dispex)); } -IHTMLElementCollection *create_collection_from_nodelist(nsIDOMNodeList *nslist, compat_mode_t compat_mode) +IHTMLElementCollection *create_collection_from_nodelist(nsIDOMNodeList *nslist, HTMLDocumentNode *doc) { UINT32 length = 0, i; HTMLDOMNode *node; @@ -730,10 +732,11 @@ IHTMLElementCollection *create_collection_from_nodelist(nsIDOMNodeList *nslist, buf.buf = NULL; } - return HTMLElementCollection_Create(buf.buf, buf.len, compat_mode); + return HTMLElementCollection_Create(buf.buf, buf.len, get_inner_window(doc), doc->document_mode); } -IHTMLElementCollection *create_collection_from_htmlcol(nsIDOMHTMLCollection *nscol, compat_mode_t compat_mode) +IHTMLElementCollection *create_collection_from_htmlcol(nsIDOMHTMLCollection *nscol, HTMLDocumentNode *doc, + compat_mode_t compat_mode) { UINT32 length = 0, i; elem_vector_t buf; @@ -766,7 +769,7 @@ IHTMLElementCollection *create_collection_from_htmlcol(nsIDOMHTMLCollection *nsc return NULL; } - return HTMLElementCollection_Create(buf.buf, buf.len, compat_mode); + return HTMLElementCollection_Create(buf.buf, buf.len, get_inner_window(doc), compat_mode); } HRESULT get_elem_source_index(HTMLElement *elem, LONG *ret) @@ -838,7 +841,7 @@ HRESULT get_elem_source_index(HTMLElement *elem, LONG *ret) } static IHTMLElementCollection *HTMLElementCollection_Create(HTMLElement **elems, DWORD len, - compat_mode_t compat_mode) + HTMLInnerWindow *window, compat_mode_t compat_mode) { HTMLElementCollection *ret = calloc(1, sizeof(HTMLElementCollection)); @@ -849,9 +852,11 @@ static IHTMLElementCollection *HTMLElementCollection_Create(HTMLElement **elems, ret->ref = 1; ret->elems = elems; ret->len = len; + ret->window = window; + IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface); init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLElementCollection_iface, - &HTMLElementCollection_dispex, compat_mode); + &HTMLElementCollection_dispex, window, compat_mode); TRACE("ret=%p len=%ld\n", ret, len); diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 2e264b5c08d..d3f2763c08e 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -2068,7 +2068,7 @@ static dispex_static_data_t HTMLEventObj_dispex = { HTMLEventObj_iface_tids }; -static HTMLEventObj *alloc_event_obj(DOMEvent *event, compat_mode_t compat_mode) +static HTMLEventObj *alloc_event_obj(DOMEvent *event, HTMLInnerWindow *window, compat_mode_t compat_mode) { HTMLEventObj *event_obj; @@ -2087,15 +2087,15 @@ static HTMLEventObj *alloc_event_obj(DOMEvent *event, compat_mode_t compat_mode) if(event) IDOMEvent_AddRef(&event->IDOMEvent_iface); - init_dispatch(&event_obj->dispex, (IUnknown*)&event_obj->IHTMLEventObj_iface, &HTMLEventObj_dispex, compat_mode); + init_dispatch(&event_obj->dispex, (IUnknown*)&event_obj->IHTMLEventObj_iface, &HTMLEventObj_dispex, window, compat_mode); return event_obj; } -HRESULT create_event_obj(DOMEvent *event, compat_mode_t compat_mode, IHTMLEventObj **ret) +HRESULT create_event_obj(HTMLDocumentNode *doc, DOMEvent *event, IHTMLEventObj **ret) { HTMLEventObj *event_obj; - event_obj = alloc_event_obj(event, compat_mode); + event_obj = alloc_event_obj(event, get_inner_window(doc), dispex_compat_mode(&doc->node.event_target.dispex)); if(!event_obj) return E_OUTOFMEMORY; @@ -2159,6 +2159,7 @@ static ULONG WINAPI DOMEvent_Release(IDOMEvent *iface) This->destroy(This); if(This->target) IEventTarget_Release(&This->target->IEventTarget_iface); + IHTMLWindow2_Release(&This->window->base.IHTMLWindow2_iface); nsIDOMEvent_Release(This->nsevent); release_dispex(&This->dispex); free(This->type); @@ -4240,7 +4241,7 @@ dispex_static_data_t DOMStorageEvent_dispex = { }; static void *event_ctor(unsigned size, dispex_static_data_t *dispex_data, void *(*query_interface)(DOMEvent*,REFIID), - void (*destroy)(DOMEvent*), nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) + void (*destroy)(DOMEvent*), nsIDOMEvent *nsevent, HTMLInnerWindow *window, eventid_t event_id, compat_mode_t compat_mode) { DOMEvent *event = calloc(1, size); @@ -4251,6 +4252,9 @@ static void *event_ctor(unsigned size, dispex_static_data_t *dispex_data, void * event->destroy = destroy; event->ref = 1; event->event_id = event_id; + event->window = window; + IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface); + if(event_id != EVENTID_LAST) { event->type = wcsdup(event_info[event_id].name); if(!event->type) { @@ -4264,7 +4268,7 @@ static void *event_ctor(unsigned size, dispex_static_data_t *dispex_data, void * event->time_stamp = get_time_stamp(); - init_dispatch(&event->dispex, (IUnknown*)&event->IDOMEvent_iface, dispex_data, compat_mode); + init_dispatch(&event->dispex, (IUnknown*)&event->IDOMEvent_iface, dispex_data, window, compat_mode); return event; } @@ -4274,25 +4278,28 @@ static void fill_parent_ui_event(nsIDOMEvent *nsevent, DOMUIEvent *ui_event) nsIDOMEvent_QueryInterface(nsevent, &IID_nsIDOMUIEvent, (void**)&ui_event->nsevent); } -static DOMEvent *generic_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) +static DOMEvent *generic_event_ctor(void *iface, nsIDOMEvent *nsevent, HTMLInnerWindow *window, + eventid_t event_id, compat_mode_t compat_mode) { - return event_ctor(sizeof(DOMEvent), &DOMEvent_dispex, NULL, NULL, nsevent, event_id, compat_mode); + return event_ctor(sizeof(DOMEvent), &DOMEvent_dispex, NULL, NULL, nsevent, window, event_id, compat_mode); } -static DOMEvent *ui_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) +static DOMEvent *ui_event_ctor(void *iface, nsIDOMEvent *nsevent, HTMLInnerWindow *window, + eventid_t event_id, compat_mode_t compat_mode) { DOMUIEvent *ui_event = event_ctor(sizeof(DOMUIEvent), &DOMUIEvent_dispex, - DOMUIEvent_query_interface, DOMUIEvent_destroy, nsevent, event_id, compat_mode); + DOMUIEvent_query_interface, DOMUIEvent_destroy, nsevent, window, event_id, compat_mode); if(!ui_event) return NULL; ui_event->IDOMUIEvent_iface.lpVtbl = &DOMUIEventVtbl; ui_event->nsevent = iface; return &ui_event->event; } -static DOMEvent *mouse_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) +static DOMEvent *mouse_event_ctor(void *iface, nsIDOMEvent *nsevent, HTMLInnerWindow *window, + eventid_t event_id, compat_mode_t compat_mode) { DOMMouseEvent *mouse_event = event_ctor(sizeof(DOMMouseEvent), &DOMMouseEvent_dispex, - DOMMouseEvent_query_interface, DOMMouseEvent_destroy, nsevent, event_id, compat_mode); + DOMMouseEvent_query_interface, DOMMouseEvent_destroy, nsevent, window, event_id, compat_mode); if(!mouse_event) return NULL; mouse_event->IDOMMouseEvent_iface.lpVtbl = &DOMMouseEventVtbl; mouse_event->nsevent = iface; @@ -4300,10 +4307,11 @@ static DOMEvent *mouse_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_t e return &mouse_event->ui_event.event; } -static DOMEvent *keyboard_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) +static DOMEvent *keyboard_event_ctor(void *iface, nsIDOMEvent *nsevent, HTMLInnerWindow *window, + eventid_t event_id, compat_mode_t compat_mode) { DOMKeyboardEvent *keyboard_event = event_ctor(sizeof(DOMKeyboardEvent), &DOMKeyboardEvent_dispex, - DOMKeyboardEvent_query_interface, DOMKeyboardEvent_destroy, nsevent, event_id, compat_mode); + DOMKeyboardEvent_query_interface, DOMKeyboardEvent_destroy, nsevent, window, event_id, compat_mode); if(!keyboard_event) return NULL; keyboard_event->IDOMKeyboardEvent_iface.lpVtbl = &DOMKeyboardEventVtbl; keyboard_event->nsevent = iface; @@ -4311,53 +4319,58 @@ static DOMEvent *keyboard_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_ return &keyboard_event->ui_event.event; } -static DOMEvent *page_transition_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) +static DOMEvent *page_transition_event_ctor(void *iface, nsIDOMEvent *nsevent, HTMLInnerWindow *window, + eventid_t event_id, compat_mode_t compat_mode) { DOMPageTransitionEvent *page_transition_event = event_ctor(sizeof(DOMCustomEvent), &DOMPageTransitionEvent_dispex, - DOMPageTransitionEvent_query_interface, NULL, nsevent, event_id, compat_mode); + DOMPageTransitionEvent_query_interface, NULL, nsevent, window, event_id, compat_mode); if(!page_transition_event) return NULL; page_transition_event->IWinePageTransitionEvent_iface.lpVtbl = &DOMPageTransitionEventVtbl; return &page_transition_event->event; } -static DOMEvent *custom_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) +static DOMEvent *custom_event_ctor(void *iface, nsIDOMEvent *nsevent, HTMLInnerWindow *window, + eventid_t event_id, compat_mode_t compat_mode) { DOMCustomEvent *custom_event = event_ctor(sizeof(DOMCustomEvent), &DOMCustomEvent_dispex, - DOMCustomEvent_query_interface, DOMCustomEvent_destroy, nsevent, event_id, compat_mode); + DOMCustomEvent_query_interface, DOMCustomEvent_destroy, nsevent, window, event_id, compat_mode); if(!custom_event) return NULL; custom_event->IDOMCustomEvent_iface.lpVtbl = &DOMCustomEventVtbl; nsIDOMCustomEvent_Release(iface); return &custom_event->event; } -static DOMEvent *progress_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) +static DOMEvent *progress_event_ctor(void *iface, nsIDOMEvent *nsevent, HTMLInnerWindow *window, + eventid_t event_id, compat_mode_t compat_mode) { DOMProgressEvent *progress_event; if(compat_mode < COMPAT_MODE_IE10) - return event_ctor(sizeof(DOMEvent), &DOMEvent_dispex, NULL, NULL, nsevent, event_id, compat_mode); + return event_ctor(sizeof(DOMEvent), &DOMEvent_dispex, NULL, NULL, nsevent, window, event_id, compat_mode); if(!(progress_event = event_ctor(sizeof(DOMProgressEvent), &DOMProgressEvent_dispex, - DOMProgressEvent_query_interface, DOMProgressEvent_destroy, nsevent, event_id, compat_mode))) + DOMProgressEvent_query_interface, DOMProgressEvent_destroy, nsevent, window, event_id, compat_mode))) return NULL; progress_event->IDOMProgressEvent_iface.lpVtbl = &DOMProgressEventVtbl; progress_event->nsevent = iface; return &progress_event->event; } -static DOMEvent *message_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) +static DOMEvent *message_event_ctor(void *iface, nsIDOMEvent *nsevent, HTMLInnerWindow *window, + eventid_t event_id, compat_mode_t compat_mode) { DOMMessageEvent *message_event = event_ctor(sizeof(DOMMessageEvent), &DOMMessageEvent_dispex, - DOMMessageEvent_query_interface, DOMMessageEvent_destroy, nsevent, event_id, compat_mode); + DOMMessageEvent_query_interface, DOMMessageEvent_destroy, nsevent, window, event_id, compat_mode); if(!message_event) return NULL; message_event->IDOMMessageEvent_iface.lpVtbl = &DOMMessageEventVtbl; return &message_event->event; } -static DOMEvent *storage_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) +static DOMEvent *storage_event_ctor(void *iface, nsIDOMEvent *nsevent, HTMLInnerWindow *window, + eventid_t event_id, compat_mode_t compat_mode) { DOMStorageEvent *storage_event = event_ctor(sizeof(DOMStorageEvent), &DOMStorageEvent_dispex, - DOMStorageEvent_query_interface, DOMStorageEvent_destroy, nsevent, event_id, compat_mode); + DOMStorageEvent_query_interface, DOMStorageEvent_destroy, nsevent, window, event_id, compat_mode); if(!storage_event) return NULL; storage_event->IDOMStorageEvent_iface.lpVtbl = &DOMStorageEventVtbl; return &storage_event->event; @@ -4365,7 +4378,7 @@ static DOMEvent *storage_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_t static const struct { REFIID iid; - DOMEvent *(*ctor)(void *iface, nsIDOMEvent *nsevent, eventid_t, compat_mode_t); + DOMEvent *(*ctor)(void *iface, nsIDOMEvent *nsevent, HTMLInnerWindow*, eventid_t, compat_mode_t); } event_types_ctor_table[] = { [EVENT_TYPE_EVENT] = { NULL, generic_event_ctor }, [EVENT_TYPE_UIEVENT] = { &IID_nsIDOMUIEvent, ui_event_ctor }, @@ -4381,8 +4394,8 @@ static const struct { [EVENT_TYPE_STORAGE] = { NULL, storage_event_ctor }, }; -static DOMEvent *alloc_event(nsIDOMEvent *nsevent, compat_mode_t compat_mode, event_type_t event_type, - eventid_t event_id) +static DOMEvent *alloc_event(nsIDOMEvent *nsevent, HTMLInnerWindow *window, compat_mode_t compat_mode, + event_type_t event_type, eventid_t event_id) { void *iface = NULL; DOMEvent *event; @@ -4391,12 +4404,12 @@ static DOMEvent *alloc_event(nsIDOMEvent *nsevent, compat_mode_t compat_mode, ev nsIDOMEvent_QueryInterface(nsevent, event_types_ctor_table[event_type].iid, &iface); /* Transfer the iface ownership to the ctor on success */ - if(!(event = event_types_ctor_table[event_type].ctor(iface, nsevent, event_id, compat_mode)) && iface) + if(!(event = event_types_ctor_table[event_type].ctor(iface, nsevent, window, event_id, compat_mode)) && iface) nsISupports_Release(iface); return event; } -HRESULT create_event_from_nsevent(nsIDOMEvent *nsevent, compat_mode_t compat_mode, DOMEvent **ret_event) +HRESULT create_event_from_nsevent(nsIDOMEvent *nsevent, HTMLInnerWindow *window, compat_mode_t compat_mode, DOMEvent **ret_event) { event_type_t event_type = EVENT_TYPE_EVENT; eventid_t event_id = EVENTID_LAST; @@ -4428,7 +4441,7 @@ HRESULT create_event_from_nsevent(nsIDOMEvent *nsevent, compat_mode_t compat_mod } } - event = alloc_event(nsevent, compat_mode, event_type, event_id); + event = alloc_event(nsevent, window, compat_mode, event_type, event_id); if(!event) return E_OUTOFMEMORY; @@ -4461,7 +4474,7 @@ HRESULT create_document_event_str(HTMLDocumentNode *doc, const WCHAR *type, IDOM } } - event = alloc_event(nsevent, dispex_compat_mode(&doc->node.event_target.dispex), + event = alloc_event(nsevent, get_inner_window(doc), dispex_compat_mode(&doc->node.event_target.dispex), event_type, EVENTID_LAST); nsIDOMEvent_Release(nsevent); if(!event) @@ -4486,7 +4499,7 @@ HRESULT create_document_event(HTMLDocumentNode *doc, eventid_t event_id, DOMEven return E_FAIL; } - event = alloc_event(nsevent, doc->document_mode, event_info[event_id].type, event_id); + event = alloc_event(nsevent, get_inner_window(doc), doc->document_mode, event_info[event_id].type, event_id); if(!event) return E_OUTOFMEMORY; @@ -4925,7 +4938,7 @@ static HRESULT dispatch_event_object(EventTarget *event_target, DOMEvent *event, } while(iter); if(!event->event_obj && !event->no_event_obj) { - event_obj_ref = alloc_event_obj(event, dispex_compat_mode(&event->dispex)); + event_obj_ref = alloc_event_obj(event, event->window, dispex_compat_mode(&event->dispex)); if(event_obj_ref) event->event_obj = &event_obj_ref->IHTMLEventObj_iface; } @@ -5046,7 +5059,7 @@ HRESULT fire_event(HTMLDOMNode *node, const WCHAR *event_name, VARIANT *event_va } if(!event_obj) { - event_obj = alloc_event_obj(NULL, dispex_compat_mode(&node->event_target.dispex)); + event_obj = alloc_event_obj(NULL, get_inner_window(node->doc), dispex_compat_mode(&node->event_target.dispex)); if(!event_obj) return E_OUTOFMEMORY; } @@ -5674,10 +5687,10 @@ static int event_id_cmp(const void *key, const struct wine_rb_entry *entry) } void EventTarget_Init(EventTarget *event_target, IUnknown *outer, dispex_static_data_t *dispex_data, - compat_mode_t compat_mode) + HTMLInnerWindow *window) { event_target->IEventTarget_iface.lpVtbl = &EventTargetVtbl; - init_dispatch(&event_target->dispex, outer, dispex_data, compat_mode); + init_dispatch(&event_target->dispex, outer, dispex_data, window, window ? window->doc->document_mode : COMPAT_MODE_NONE); wine_rb_init(&event_target->handler_map, event_id_cmp); } diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index 4403340a5f9..d6bf65edc38 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -80,6 +80,7 @@ typedef struct DOMEvent { void *(*query_interface)(struct DOMEvent*,REFIID); void (*destroy)(struct DOMEvent*); + HTMLInnerWindow *window; nsIDOMEvent *nsevent; eventid_t event_id; @@ -110,7 +111,7 @@ HRESULT fire_event(HTMLDOMNode*,const WCHAR*,VARIANT*,VARIANT_BOOL*) DECLSPEC_HI void update_doc_cp_events(HTMLDocumentNode*,cp_static_data_t*) DECLSPEC_HIDDEN; HRESULT doc_init_events(HTMLDocumentNode*) DECLSPEC_HIDDEN; void detach_events(HTMLDocumentNode *doc) DECLSPEC_HIDDEN; -HRESULT create_event_obj(DOMEvent*,compat_mode_t,IHTMLEventObj**) DECLSPEC_HIDDEN; +HRESULT create_event_obj(HTMLDocumentNode*,DOMEvent*,IHTMLEventObj**) DECLSPEC_HIDDEN; void bind_target_event(HTMLDocumentNode*,EventTarget*,const WCHAR*,IDispatch*) DECLSPEC_HIDDEN; HRESULT ensure_doc_nsevent_handler(HTMLDocumentNode*,nsIDOMNode*,eventid_t) DECLSPEC_HIDDEN; @@ -118,7 +119,7 @@ void dispatch_event(EventTarget*,DOMEvent*) DECLSPEC_HIDDEN; HRESULT create_document_event(HTMLDocumentNode*,eventid_t,DOMEvent**) DECLSPEC_HIDDEN; HRESULT create_document_event_str(HTMLDocumentNode*,const WCHAR*,IDOMEvent**) DECLSPEC_HIDDEN; -HRESULT create_event_from_nsevent(nsIDOMEvent*,compat_mode_t,DOMEvent**) DECLSPEC_HIDDEN; +HRESULT create_event_from_nsevent(nsIDOMEvent*,HTMLInnerWindow*,compat_mode_t,DOMEvent**) DECLSPEC_HIDDEN; HRESULT create_message_event(HTMLDocumentNode*,IHTMLWindow2*,VARIANT*,DOMEvent**) DECLSPEC_HIDDEN; HRESULT create_storage_event(HTMLDocumentNode*,BSTR,BSTR,BSTR,const WCHAR*,BOOL,DOMEvent**) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/htmlform.c b/dlls/mshtml/htmlform.c index 6429b6b9ed7..0eca4b2c6ed 100644 --- a/dlls/mshtml/htmlform.c +++ b/dlls/mshtml/htmlform.c @@ -452,7 +452,8 @@ static HRESULT WINAPI HTMLFormElement_get_elements(IHTMLFormElement *iface, IDis return E_FAIL; } - *p = (IDispatch*)create_collection_from_htmlcol(elements, dispex_compat_mode(&This->element.node.event_target.dispex)); + *p = (IDispatch*)create_collection_from_htmlcol(elements, This->element.node.doc, + dispex_compat_mode(&This->element.node.event_target.dispex)); nsIDOMHTMLCollection_Release(elements); return S_OK; } diff --git a/dlls/mshtml/htmlimg.c b/dlls/mshtml/htmlimg.c index 01cc8405f87..593fca8cb7a 100644 --- a/dlls/mshtml/htmlimg.c +++ b/dlls/mshtml/htmlimg.c @@ -1048,7 +1048,7 @@ HRESULT HTMLImageElementFactory_Create(HTMLInnerWindow *window, HTMLImageElement ret->window = window; init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLImageElementFactory_iface, - &HTMLImageElementFactory_dispex, dispex_compat_mode(&window->event_target.dispex)); + &HTMLImageElementFactory_dispex, window, dispex_compat_mode(&window->event_target.dispex)); *ret_val = ret; return S_OK; diff --git a/dlls/mshtml/htmllocation.c b/dlls/mshtml/htmllocation.c index d9e458d9c5f..410d4d72aeb 100644 --- a/dlls/mshtml/htmllocation.c +++ b/dlls/mshtml/htmllocation.c @@ -618,10 +618,10 @@ static dispex_static_data_t HTMLLocation_dispex = { HTMLLocation_iface_tids }; -void HTMLLocation_Init(HTMLLocation *location) +void HTMLLocation_Init(HTMLOuterWindow *window) { - location->IHTMLLocation_iface.lpVtbl = &HTMLLocationVtbl; + window->location.IHTMLLocation_iface.lpVtbl = &HTMLLocationVtbl; - init_dispatch(&location->dispex, (IUnknown*)&location->IHTMLLocation_iface, &HTMLLocation_dispex, - COMPAT_MODE_QUIRKS); + init_dispatch(&window->location.dispex, (IUnknown*)&window->location.IHTMLLocation_iface, &HTMLLocation_dispex, + window->base.inner_window, COMPAT_MODE_QUIRKS); } diff --git a/dlls/mshtml/htmlnode.c b/dlls/mshtml/htmlnode.c index 6961c823f62..2be5012941f 100644 --- a/dlls/mshtml/htmlnode.c +++ b/dlls/mshtml/htmlnode.c @@ -452,7 +452,7 @@ static dispex_static_data_t HTMLDOMChildrenCollection_dispex = { HTMLDOMNode_init_dispex_info }; -HRESULT create_child_collection(nsIDOMNodeList *nslist, compat_mode_t compat_mode, IHTMLDOMChildrenCollection **ret) +HRESULT create_child_collection(nsIDOMNodeList *nslist, HTMLDocumentNode *doc, IHTMLDOMChildrenCollection **ret) { HTMLDOMChildrenCollection *collection; @@ -466,7 +466,8 @@ HRESULT create_child_collection(nsIDOMNodeList *nslist, compat_mode_t compat_mod collection->nslist = nslist; init_dispatch(&collection->dispex, (IUnknown*)&collection->IHTMLDOMChildrenCollection_iface, - &HTMLDOMChildrenCollection_dispex, compat_mode); + &HTMLDOMChildrenCollection_dispex, get_inner_window(doc), + dispex_compat_mode(&doc->node.event_target.dispex)); *ret = &collection->IHTMLDOMChildrenCollection_iface; return S_OK; @@ -637,8 +638,7 @@ static HRESULT WINAPI HTMLDOMNode_get_childNodes(IHTMLDOMNode *iface, IDispatch return hres; } - hres = create_child_collection(nslist, dispex_compat_mode(&This->event_target.dispex), - (IHTMLDOMChildrenCollection**)p); + hres = create_child_collection(nslist, This->doc, (IHTMLDOMChildrenCollection**)p); nsIDOMNodeList_Release(nslist); return hres; } @@ -1474,6 +1474,7 @@ static const NodeImplVtbl HTMLDOMNodeImplVtbl = { void HTMLDOMNode_Init(HTMLDocumentNode *doc, HTMLDOMNode *node, nsIDOMNode *nsnode, dispex_static_data_t *dispex_data) { + HTMLInnerWindow *window = NULL; nsresult nsres; node->IHTMLDOMNode_iface.lpVtbl = &HTMLDOMNodeVtbl; @@ -1481,12 +1482,14 @@ void HTMLDOMNode_Init(HTMLDocumentNode *doc, HTMLDOMNode *node, nsIDOMNode *nsno node->IHTMLDOMNode3_iface.lpVtbl = &HTMLDOMNode3Vtbl; ccref_init(&node->ccref, 1); - EventTarget_Init(&node->event_target, (IUnknown*)&node->IHTMLDOMNode_iface, dispex_data, doc->document_mode); - - if(&doc->node != node) + if(&doc->node != node) { IHTMLDOMNode_AddRef(&doc->node.IHTMLDOMNode_iface); + window = get_inner_window(doc); + } node->doc = doc; + EventTarget_Init(&node->event_target, (IUnknown*)&node->IHTMLDOMNode_iface, dispex_data, window); + nsIDOMNode_AddRef(nsnode); node->nsnode = nsnode; diff --git a/dlls/mshtml/htmlselect.c b/dlls/mshtml/htmlselect.c index b4275a2d5ae..b1fa5407383 100644 --- a/dlls/mshtml/htmlselect.c +++ b/dlls/mshtml/htmlselect.c @@ -661,7 +661,7 @@ HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow *window, HTMLOptionEleme ret->window = window; init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLOptionElementFactory_iface, - &HTMLOptionElementFactory_dispex, dispex_compat_mode(&window->event_target.dispex)); + &HTMLOptionElementFactory_dispex, window, dispex_compat_mode(&window->event_target.dispex)); *ret_ptr = ret; return S_OK; diff --git a/dlls/mshtml/htmlstorage.c b/dlls/mshtml/htmlstorage.c index 153dcfaa204..543ff2b8149 100644 --- a/dlls/mshtml/htmlstorage.c +++ b/dlls/mshtml/htmlstorage.c @@ -210,15 +210,14 @@ static void storage_event_proc(task_t *_task) struct storage_event_task *task = (struct storage_event_task*)_task; HTMLInnerWindow *window = task->window; DOMEvent *event = task->event; - compat_mode_t compat_mode; VARIANT_BOOL cancelled; HRESULT hres; VARIANT var; - if(event->event_id == EVENTID_STORAGE && (compat_mode = dispex_compat_mode(&window->event_target.dispex)) >= COMPAT_MODE_IE9) { + if(event->event_id == EVENTID_STORAGE && dispex_compat_mode(&window->event_target.dispex) >= COMPAT_MODE_IE9) { dispatch_event(&window->event_target, event); if(window->doc) { - hres = create_event_obj(event, compat_mode, (IHTMLEventObj**)&V_DISPATCH(&var)); + hres = create_event_obj(window->doc, event, (IHTMLEventObj**)&V_DISPATCH(&var)); if(SUCCEEDED(hres)) { V_VT(&var) = VT_DISPATCH; fire_event(&window->doc->node, L"onstorage", &var, &cancelled); @@ -1492,7 +1491,7 @@ HRESULT create_html_storage(HTMLInnerWindow *window, BOOL local, IHTMLStorage ** storage->window = window; init_dispatch(&storage->dispex, (IUnknown*)&storage->IHTMLStorage_iface, &HTMLStorage_dispex, - dispex_compat_mode(&window->event_target.dispex)); + window, dispex_compat_mode(&window->event_target.dispex)); *p = &storage->IHTMLStorage_iface; return S_OK; diff --git a/dlls/mshtml/htmlstyle.c b/dlls/mshtml/htmlstyle.c index 703fbeeb942..701b6ebe670 100644 --- a/dlls/mshtml/htmlstyle.c +++ b/dlls/mshtml/htmlstyle.c @@ -10059,7 +10059,7 @@ static HRESULT get_style_from_elem(HTMLElement *elem, nsIDOMCSSStyleDeclaration } void init_css_style(CSSStyle *style, nsIDOMCSSStyleDeclaration *nsstyle, style_qi_t qi, - dispex_static_data_t *dispex_info, compat_mode_t compat_mode) + dispex_static_data_t *dispex_info, HTMLInnerWindow *window, compat_mode_t compat_mode) { style->IHTMLCSSStyleDeclaration_iface.lpVtbl = &HTMLCSSStyleDeclarationVtbl; style->IHTMLCSSStyleDeclaration2_iface.lpVtbl = &HTMLCSSStyleDeclaration2Vtbl; @@ -10069,7 +10069,7 @@ void init_css_style(CSSStyle *style, nsIDOMCSSStyleDeclaration *nsstyle, style_q nsIDOMCSSStyleDeclaration_AddRef(nsstyle); init_dispatch(&style->dispex, (IUnknown*)&style->IHTMLCSSStyleDeclaration_iface, - dispex_info, compat_mode); + dispex_info, window, compat_mode); } HRESULT HTMLStyle_Create(HTMLElement *elem, HTMLStyle **ret) @@ -10098,7 +10098,7 @@ HRESULT HTMLStyle_Create(HTMLElement *elem, HTMLStyle **ret) style->elem = elem; init_css_style(&style->css_style, nsstyle, HTMLStyle_QI, &HTMLStyle_dispex, - dispex_compat_mode(&elem->node.event_target.dispex)); + get_inner_window(elem->node.doc), dispex_compat_mode(&elem->node.event_target.dispex)); *ret = style; return S_OK; @@ -10115,14 +10115,15 @@ static dispex_static_data_t HTMLW3CComputedStyle_dispex = { CSSStyle_init_dispex_info }; -HRESULT create_computed_style(nsIDOMCSSStyleDeclaration *nsstyle, compat_mode_t compat_mode, IHTMLCSSStyleDeclaration **p) +HRESULT create_computed_style(nsIDOMCSSStyleDeclaration *nsstyle, HTMLInnerWindow *window, + compat_mode_t compat_mode, IHTMLCSSStyleDeclaration **p) { CSSStyle *style; if(!(style = calloc(1, sizeof(*style)))) return E_OUTOFMEMORY; - init_css_style(style, nsstyle, NULL, &HTMLW3CComputedStyle_dispex, compat_mode); + init_css_style(style, nsstyle, NULL, &HTMLW3CComputedStyle_dispex, window, compat_mode); *p = &style->IHTMLCSSStyleDeclaration_iface; return S_OK; } diff --git a/dlls/mshtml/htmlstyle.h b/dlls/mshtml/htmlstyle.h index e14c1274360..dc6a2dbb0c7 100644 --- a/dlls/mshtml/htmlstyle.h +++ b/dlls/mshtml/htmlstyle.h @@ -152,9 +152,10 @@ typedef enum { } styleid_t; HRESULT HTMLStyle_Create(HTMLElement*,HTMLStyle**) DECLSPEC_HIDDEN; -HRESULT create_computed_style(nsIDOMCSSStyleDeclaration*,compat_mode_t,IHTMLCSSStyleDeclaration**) DECLSPEC_HIDDEN; +HRESULT create_computed_style(nsIDOMCSSStyleDeclaration*,HTMLInnerWindow*,compat_mode_t, + IHTMLCSSStyleDeclaration**) DECLSPEC_HIDDEN; void init_css_style(CSSStyle*,nsIDOMCSSStyleDeclaration*,style_qi_t, - dispex_static_data_t*,compat_mode_t) DECLSPEC_HIDDEN; + dispex_static_data_t*,HTMLInnerWindow*,compat_mode_t) DECLSPEC_HIDDEN; void CSSStyle_init_dispex_info(dispex_data_t *info, compat_mode_t mode) DECLSPEC_HIDDEN; extern const dispex_static_data_vtbl_t CSSStyle_dispex_vtbl DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/htmlstyleelem.c b/dlls/mshtml/htmlstyleelem.c index d0465d1495a..fae644c9fc9 100644 --- a/dlls/mshtml/htmlstyleelem.c +++ b/dlls/mshtml/htmlstyleelem.c @@ -199,8 +199,7 @@ static HRESULT WINAPI HTMLStyleElement_get_styleSheet(IHTMLStyleElement *iface, assert(nsres == NS_OK); if(ss) { - HRESULT hres = create_style_sheet(ss, dispex_compat_mode(&This->element.node.event_target.dispex), - &This->style_sheet); + HRESULT hres = create_style_sheet(ss, This->element.node.doc, &This->style_sheet); nsIDOMStyleSheet_Release(ss); if(FAILED(hres)) return hres; diff --git a/dlls/mshtml/htmlstylesheet.c b/dlls/mshtml/htmlstylesheet.c index 611f966228e..9ec406f84f3 100644 --- a/dlls/mshtml/htmlstylesheet.c +++ b/dlls/mshtml/htmlstylesheet.c @@ -38,6 +38,7 @@ struct HTMLStyleSheet { LONG ref; + HTMLInnerWindow *window; nsIDOMCSSStyleSheet *nsstylesheet; }; @@ -47,6 +48,7 @@ struct HTMLStyleSheetsCollection { LONG ref; + HTMLDocumentNode *doc; nsIDOMStyleSheetList *nslist; }; @@ -65,6 +67,7 @@ struct HTMLStyleSheetRulesCollection { LONG ref; + HTMLInnerWindow *window; nsIDOMCSSRuleList *nslist; }; @@ -217,8 +220,8 @@ static dispex_static_data_t HTMLStyleSheetRule_dispex = { HTMLStyleSheetRule_iface_tids }; -static HRESULT create_style_sheet_rule(nsIDOMCSSRule *nsstylesheetrule, compat_mode_t compat_mode, - IHTMLStyleSheetRule **ret) +static HRESULT create_style_sheet_rule(nsIDOMCSSRule *nsstylesheetrule, HTMLInnerWindow *window, + compat_mode_t compat_mode, IHTMLStyleSheetRule **ret) { HTMLStyleSheetRule *rule; nsresult nsres; @@ -231,7 +234,7 @@ static HRESULT create_style_sheet_rule(nsIDOMCSSRule *nsstylesheetrule, compat_m rule->nsstylesheetrule = NULL; init_dispatch(&rule->dispex, (IUnknown *)&rule->IHTMLStyleSheetRule_iface, &HTMLStyleSheetRule_dispex, - compat_mode); + window, compat_mode); if (nsstylesheetrule) { @@ -291,6 +294,7 @@ static ULONG WINAPI HTMLStyleSheetRulesCollection_Release(IHTMLStyleSheetRulesCo TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { + IHTMLWindow2_Release(&This->window->base.IHTMLWindow2_iface); release_dispex(&This->dispex); if(This->nslist) nsIDOMCSSRuleList_Release(This->nslist); @@ -367,7 +371,7 @@ static HRESULT WINAPI HTMLStyleSheetRulesCollection_item(IHTMLStyleSheetRulesCol if(!nsstylesheetrule) return E_INVALIDARG; - hres = create_style_sheet_rule(nsstylesheetrule, dispex_compat_mode(&This->dispex), p); + hres = create_style_sheet_rule(nsstylesheetrule, This->window, dispex_compat_mode(&This->dispex), p); nsIDOMCSSRule_Release(nsstylesheetrule); return hres; } @@ -447,7 +451,7 @@ static HRESULT HTMLStyleSheetRulesCollection_invoke(DispatchEx *dispex, IDispatc return S_OK; } - hres = create_style_sheet_rule(nsstylesheetrule, dispex_compat_mode(&This->dispex), &stylesheetrule); + hres = create_style_sheet_rule(nsstylesheetrule, This->window, dispex_compat_mode(&This->dispex), &stylesheetrule); nsIDOMCSSRule_Release(nsstylesheetrule); if(FAILED(hres)) return hres; @@ -482,8 +486,8 @@ static dispex_static_data_t HTMLStyleSheetRulesCollection_dispex = { HTMLStyleSheetRulesCollection_iface_tids }; -static HRESULT create_style_sheet_rules_collection(nsIDOMCSSRuleList *nslist, compat_mode_t compat_mode, - IHTMLStyleSheetRulesCollection **ret) +static HRESULT create_style_sheet_rules_collection(nsIDOMCSSRuleList *nslist, HTMLInnerWindow *window, + compat_mode_t compat_mode, IHTMLStyleSheetRulesCollection **ret) { HTMLStyleSheetRulesCollection *collection; @@ -493,9 +497,11 @@ static HRESULT create_style_sheet_rules_collection(nsIDOMCSSRuleList *nslist, co collection->IHTMLStyleSheetRulesCollection_iface.lpVtbl = &HTMLStyleSheetRulesCollectionVtbl; collection->ref = 1; collection->nslist = nslist; + collection->window = window; + IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface); init_dispatch(&collection->dispex, (IUnknown*)&collection->IHTMLStyleSheetRulesCollection_iface, - &HTMLStyleSheetRulesCollection_dispex, compat_mode); + &HTMLStyleSheetRulesCollection_dispex, window, compat_mode); if(nslist) nsIDOMCSSRuleList_AddRef(nslist); @@ -676,6 +682,7 @@ static ULONG WINAPI HTMLStyleSheetsCollection_Release(IHTMLStyleSheetsCollection TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { + IHTMLDOMNode_Release(&This->doc->node.IHTMLDOMNode_iface); release_dispex(&This->dispex); if(This->nslist) nsIDOMStyleSheetList_Release(This->nslist); @@ -777,7 +784,7 @@ static HRESULT WINAPI HTMLStyleSheetsCollection_item(IHTMLStyleSheetsCollection return E_INVALIDARG; } - hres = create_style_sheet(nsstylesheet, dispex_compat_mode(&This->dispex), &stylesheet); + hres = create_style_sheet(nsstylesheet, This->doc, &stylesheet); nsIDOMStyleSheet_Release(nsstylesheet); if(FAILED(hres)) return hres; @@ -874,7 +881,7 @@ static HRESULT HTMLStyleSheetsCollection_invoke(DispatchEx *dispex, IDispatch *t return S_OK; } - hres = create_style_sheet(nsstylesheet, dispex_compat_mode(&This->dispex), &stylesheet); + hres = create_style_sheet(nsstylesheet, This->doc, &stylesheet); nsIDOMStyleSheet_Release(nsstylesheet); if(FAILED(hres)) return hres; @@ -909,7 +916,7 @@ static dispex_static_data_t HTMLStyleSheetsCollection_dispex = { HTMLStyleSheetsCollection_iface_tids }; -HRESULT create_style_sheet_collection(nsIDOMStyleSheetList *nslist, compat_mode_t compat_mode, +HRESULT create_style_sheet_collection(nsIDOMStyleSheetList *nslist, HTMLDocumentNode *doc, IHTMLStyleSheetsCollection **ret) { HTMLStyleSheetsCollection *collection; @@ -919,13 +926,16 @@ HRESULT create_style_sheet_collection(nsIDOMStyleSheetList *nslist, compat_mode_ collection->IHTMLStyleSheetsCollection_iface.lpVtbl = &HTMLStyleSheetsCollectionVtbl; collection->ref = 1; + collection->doc = doc; + IHTMLDOMNode_AddRef(&doc->node.IHTMLDOMNode_iface); if(nslist) nsIDOMStyleSheetList_AddRef(nslist); collection->nslist = nslist; init_dispatch(&collection->dispex, (IUnknown*)&collection->IHTMLStyleSheetsCollection_iface, - &HTMLStyleSheetsCollection_dispex, compat_mode); + &HTMLStyleSheetsCollection_dispex, get_inner_window(doc), + dispex_compat_mode(&doc->node.event_target.dispex)); *ret = &collection->IHTMLStyleSheetsCollection_iface; return S_OK; @@ -980,6 +990,7 @@ static ULONG WINAPI HTMLStyleSheet_Release(IHTMLStyleSheet *iface) TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { + IHTMLWindow2_Release(&This->window->base.IHTMLWindow2_iface); release_dispex(&This->dispex); if(This->nsstylesheet) nsIDOMCSSStyleSheet_Release(This->nsstylesheet); @@ -1274,7 +1285,7 @@ static HRESULT WINAPI HTMLStyleSheet_get_rules(IHTMLStyleSheet *iface, return E_FAIL; } - hres = create_style_sheet_rules_collection(nslist, dispex_compat_mode(&This->dispex), p); + hres = create_style_sheet_rules_collection(nslist, This->window, dispex_compat_mode(&This->dispex), p); nsIDOMCSSRuleList_Release(nslist); return hres; } @@ -1480,8 +1491,9 @@ static dispex_static_data_t HTMLStyleSheet_dispex = { HTMLStyleSheet_init_dispex_info }; -HRESULT create_style_sheet(nsIDOMStyleSheet *nsstylesheet, compat_mode_t compat_mode, IHTMLStyleSheet **ret) +HRESULT create_style_sheet(nsIDOMStyleSheet *nsstylesheet, HTMLDocumentNode *doc, IHTMLStyleSheet **ret) { + HTMLInnerWindow *window = get_inner_window(doc); HTMLStyleSheet *style_sheet; nsresult nsres; @@ -1492,9 +1504,11 @@ HRESULT create_style_sheet(nsIDOMStyleSheet *nsstylesheet, compat_mode_t compat_ style_sheet->IHTMLStyleSheet4_iface.lpVtbl = &HTMLStyleSheet4Vtbl; style_sheet->ref = 1; style_sheet->nsstylesheet = NULL; + style_sheet->window = window; + IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface); init_dispatch(&style_sheet->dispex, (IUnknown*)&style_sheet->IHTMLStyleSheet_iface, - &HTMLStyleSheet_dispex, compat_mode); + &HTMLStyleSheet_dispex, window, dispex_compat_mode(&doc->node.event_target.dispex)); if(nsstylesheet) { nsres = nsIDOMStyleSheet_QueryInterface(nsstylesheet, &IID_nsIDOMCSSStyleSheet, diff --git a/dlls/mshtml/htmltable.c b/dlls/mshtml/htmltable.c index df2cb92b8c9..6cfae9cee79 100644 --- a/dlls/mshtml/htmltable.c +++ b/dlls/mshtml/htmltable.c @@ -817,7 +817,7 @@ static HRESULT WINAPI HTMLTableRow_get_cells(IHTMLTableRow *iface, IHTMLElementC return E_FAIL; } - *p = create_collection_from_htmlcol(nscol, dispex_compat_mode(&This->element.node.event_target.dispex)); + *p = create_collection_from_htmlcol(nscol, This->element.node.doc, dispex_compat_mode(&This->element.node.event_target.dispex)); nsIDOMHTMLCollection_Release(nscol); return S_OK; @@ -1422,7 +1422,7 @@ static HRESULT WINAPI HTMLTable_get_rows(IHTMLTable *iface, IHTMLElementCollecti return E_FAIL; } - *p = create_collection_from_htmlcol(nscol, dispex_compat_mode(&This->element.node.event_target.dispex)); + *p = create_collection_from_htmlcol(nscol, This->element.node.doc, dispex_compat_mode(&This->element.node.event_target.dispex)); nsIDOMHTMLCollection_Release(nscol); return S_OK; @@ -1537,7 +1537,7 @@ static HRESULT WINAPI HTMLTable_get_tBodies(IHTMLTable *iface, IHTMLElementColle return E_FAIL; } - *p = create_collection_from_htmlcol(nscol, dispex_compat_mode(&This->element.node.event_target.dispex)); + *p = create_collection_from_htmlcol(nscol, This->element.node.doc, dispex_compat_mode(&This->element.node.event_target.dispex)); nsIDOMHTMLCollection_Release(nscol); return S_OK; diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 9c850c3a82a..b564f90f16e 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -71,7 +71,7 @@ static inline BOOL is_outer_window(HTMLWindow *window) static void get_location(HTMLOuterWindow *This, HTMLLocation **ret) { if(!This->location.dispex.outer) - HTMLLocation_Init(&This->location); + HTMLLocation_Init(This); IHTMLLocation_AddRef(&This->location.IHTMLLocation_iface); *ret = &This->location; @@ -311,8 +311,10 @@ static void release_inner_window(HTMLInnerWindow *This) IOmHistory_Release(&This->history->IOmHistory_iface); } - if(This->navigator) + if(This->navigator) { + detach_navigator(This->navigator); IOmNavigator_Release(This->navigator); + } if(This->session_storage) { detach_html_storage(This->session_storage); IHTMLStorage_Release(This->session_storage); @@ -956,7 +958,7 @@ static HRESULT WINAPI HTMLWindow2_get_navigator(IHTMLWindow2 *iface, IOmNavigato if(!window->navigator) { HRESULT hres; - hres = create_navigator(dispex_compat_mode(&window->event_target.dispex), &window->navigator); + hres = create_navigator(window, &window->navigator); if(FAILED(hres)) return hres; } @@ -1345,7 +1347,7 @@ static HRESULT WINAPI HTMLWindow2_get_screen(IHTMLWindow2 *iface, IHTMLScreen ** if(!window->screen) { HRESULT hres; - hres = create_html_screen(dispex_compat_mode(&window->event_target.dispex), &window->screen); + hres = create_html_screen(window, &window->screen); if(FAILED(hres)) return hres; } @@ -2623,7 +2625,8 @@ static HRESULT WINAPI HTMLWindow7_getComputedStyle(IHTMLWindow7 *iface, IHTMLDOM return S_OK; } - hres = create_computed_style(nsstyle, dispex_compat_mode(&This->inner_window->event_target.dispex), p); + hres = create_computed_style(nsstyle, This->inner_window, + dispex_compat_mode(&This->inner_window->event_target.dispex), p); nsIDOMCSSStyleDeclaration_Release(nsstyle); return hres; } @@ -3396,7 +3399,7 @@ static HRESULT WINAPI window_private_get_console(IWineHTMLWindowPrivate *iface, TRACE("iface %p, console %p.\n", iface, console); if (!This->console) - create_console(dispex_compat_mode(&This->inner_window->event_target.dispex), &This->console); + create_console(This->inner_window, &This->console); *console = (IDispatch *)This->console; if (This->console) @@ -4310,7 +4313,7 @@ static HRESULT create_inner_window(HTMLOuterWindow *outer_window, IMoniker *mon, window->base.inner_window = window; EventTarget_Init(&window->event_target, (IUnknown*)&window->base.IHTMLWindow2_iface, - &HTMLWindow_dispex, COMPAT_MODE_NONE); + &HTMLWindow_dispex, NULL); window->task_magic = get_task_target_magic(); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index f4f1987954a..83bd7593af9 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -76,11 +76,20 @@ #define MSHTML_E_INVALID_ACTION 0x800a01bd #define MSHTML_E_NODOC 0x800a025c +typedef struct HTMLWindow HTMLWindow; +typedef struct HTMLInnerWindow HTMLInnerWindow; +typedef struct HTMLOuterWindow HTMLOuterWindow; +typedef struct HTMLDocumentNode HTMLDocumentNode; +typedef struct HTMLDocumentObj HTMLDocumentObj; +typedef struct HTMLFrameBase HTMLFrameBase; +typedef struct GeckoBrowser GeckoBrowser; +typedef struct HTMLAttributeCollection HTMLAttributeCollection; typedef struct DOMEvent DOMEvent; typedef struct HTMLDOMNode HTMLDOMNode; typedef struct ConnectionPoint ConnectionPoint; typedef struct BSCallback BSCallback; typedef struct EventTarget EventTarget; +typedef struct ScriptHost ScriptHost; #define TID_LIST \ XIID(NULL) \ @@ -406,7 +415,7 @@ extern void (__cdecl *ccp_init)(ExternalCycleCollectionParticipant*,const CCObjC extern void (__cdecl *describe_cc_node)(nsCycleCollectingAutoRefCnt*,const char*,nsCycleCollectionTraversalCallback*) DECLSPEC_HIDDEN; extern void (__cdecl *note_cc_edge)(nsISupports*,const char*,nsCycleCollectionTraversalCallback*) DECLSPEC_HIDDEN; -void init_dispatch(DispatchEx*,IUnknown*,dispex_static_data_t*,compat_mode_t) DECLSPEC_HIDDEN; +void init_dispatch(DispatchEx*,IUnknown*,dispex_static_data_t*,HTMLInnerWindow*,compat_mode_t) DECLSPEC_HIDDEN; void release_dispex(DispatchEx*) DECLSPEC_HIDDEN; BOOL dispex_query_interface(DispatchEx*,REFIID,void**) DECLSPEC_HIDDEN; HRESULT change_type(VARIANT*,VARIANT*,VARTYPE,IServiceProvider*) DECLSPEC_HIDDEN; @@ -435,17 +444,6 @@ typedef enum { dispex_prop_type_t get_dispid_type(DISPID) DECLSPEC_HIDDEN; -typedef struct HTMLWindow HTMLWindow; -typedef struct HTMLInnerWindow HTMLInnerWindow; -typedef struct HTMLOuterWindow HTMLOuterWindow; -typedef struct HTMLDocumentNode HTMLDocumentNode; -typedef struct HTMLDocumentObj HTMLDocumentObj; -typedef struct HTMLFrameBase HTMLFrameBase; -typedef struct GeckoBrowser GeckoBrowser; -typedef struct HTMLAttributeCollection HTMLAttributeCollection; - -typedef struct ScriptHost ScriptHost; - typedef enum { GLOBAL_SCRIPTVAR, GLOBAL_ELEMENTVAR, @@ -997,13 +995,14 @@ void get_top_window(HTMLOuterWindow*,HTMLOuterWindow**) DECLSPEC_HIDDEN; HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow*,HTMLOptionElementFactory**) DECLSPEC_HIDDEN; HRESULT HTMLImageElementFactory_Create(HTMLInnerWindow*,HTMLImageElementFactory**) DECLSPEC_HIDDEN; HRESULT HTMLXMLHttpRequestFactory_Create(HTMLInnerWindow*,HTMLXMLHttpRequestFactory**) DECLSPEC_HIDDEN; -void HTMLLocation_Init(HTMLLocation*) DECLSPEC_HIDDEN; -HRESULT create_navigator(compat_mode_t,IOmNavigator**) DECLSPEC_HIDDEN; -HRESULT create_html_screen(compat_mode_t,IHTMLScreen**) DECLSPEC_HIDDEN; +void HTMLLocation_Init(HTMLOuterWindow*) DECLSPEC_HIDDEN; +HRESULT create_navigator(HTMLInnerWindow*,IOmNavigator**) DECLSPEC_HIDDEN; +void detach_navigator(IOmNavigator*) DECLSPEC_HIDDEN; +HRESULT create_html_screen(HTMLInnerWindow*,IHTMLScreen**) DECLSPEC_HIDDEN; HRESULT create_performance(HTMLInnerWindow*,IHTMLPerformance**) DECLSPEC_HIDDEN; HRESULT create_performance_timing(HTMLPerformanceTiming**) DECLSPEC_HIDDEN; HRESULT create_history(HTMLInnerWindow*,OmHistory**) DECLSPEC_HIDDEN; -HRESULT create_namespace_collection(compat_mode_t,IHTMLNamespaceCollection**) DECLSPEC_HIDDEN; +HRESULT create_namespace_collection(HTMLDocumentNode*,IHTMLNamespaceCollection**) DECLSPEC_HIDDEN; HRESULT create_dom_implementation(HTMLDocumentNode*,IHTMLDOMImplementation**) DECLSPEC_HIDDEN; void detach_dom_implementation(IHTMLDOMImplementation*) DECLSPEC_HIDDEN; @@ -1046,6 +1045,7 @@ void hide_tooltip(HTMLDocumentObj*) DECLSPEC_HIDDEN; HRESULT get_client_disp_property(IOleClientSite*,DISPID,VARIANT*) DECLSPEC_HIDDEN; UINT get_document_charset(HTMLDocumentNode*) DECLSPEC_HIDDEN; +HTMLInnerWindow *get_inner_window(HTMLDocumentNode*) DECLSPEC_HIDDEN; HRESULT ProtocolFactory_Create(REFCLSID,REFIID,void**) DECLSPEC_HIDDEN; @@ -1111,10 +1111,10 @@ HRESULT get_readystate_string(READYSTATE,BSTR*) DECLSPEC_HIDDEN; HRESULT HTMLSelectionObject_Create(HTMLDocumentNode*,nsISelection*,IHTMLSelectionObject**) DECLSPEC_HIDDEN; HRESULT HTMLTxtRange_Create(HTMLDocumentNode*,nsIDOMRange*,IHTMLTxtRange**) DECLSPEC_HIDDEN; -HRESULT create_style_sheet(nsIDOMStyleSheet*,compat_mode_t,IHTMLStyleSheet**) DECLSPEC_HIDDEN; -HRESULT create_style_sheet_collection(nsIDOMStyleSheetList*,compat_mode_t, +HRESULT create_style_sheet(nsIDOMStyleSheet*,HTMLDocumentNode*,IHTMLStyleSheet**) DECLSPEC_HIDDEN; +HRESULT create_style_sheet_collection(nsIDOMStyleSheetList*,HTMLDocumentNode*, IHTMLStyleSheetsCollection**) DECLSPEC_HIDDEN; -HRESULT create_dom_range(nsIDOMRange*,compat_mode_t,IHTMLDOMRange**) DECLSPEC_HIDDEN; +HRESULT create_dom_range(nsIDOMRange*,HTMLDocumentNode*,IHTMLDOMRange**) DECLSPEC_HIDDEN; HRESULT create_markup_pointer(IMarkupPointer**) DECLSPEC_HIDDEN; void detach_document_node(HTMLDocumentNode*) DECLSPEC_HIDDEN; @@ -1167,7 +1167,7 @@ typedef struct { HTMLDOMAttribute *unsafe_impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute*) DECLSPEC_HIDDEN; -HRESULT HTMLDOMAttribute_Create(const WCHAR*,HTMLElement*,DISPID,compat_mode_t,HTMLDOMAttribute**) DECLSPEC_HIDDEN; +HRESULT HTMLDOMAttribute_Create(const WCHAR*,HTMLDocumentNode*,HTMLElement*,DISPID,compat_mode_t,HTMLDOMAttribute**) DECLSPEC_HIDDEN; HRESULT HTMLElement_Create(HTMLDocumentNode*,nsIDOMNode*,BOOL,HTMLElement**) DECLSPEC_HIDDEN; HRESULT HTMLCommentElement_Create(HTMLDocumentNode*,nsIDOMNode*,HTMLElement**) DECLSPEC_HIDDEN; @@ -1203,7 +1203,7 @@ HRESULT create_svg_element(HTMLDocumentNode*,nsIDOMSVGElement*,const WCHAR*,HTML void HTMLDOMNode_Init(HTMLDocumentNode*,HTMLDOMNode*,nsIDOMNode*,dispex_static_data_t*) DECLSPEC_HIDDEN; void HTMLElement_Init(HTMLElement*,HTMLDocumentNode*,nsIDOMElement*,dispex_static_data_t*) DECLSPEC_HIDDEN; -void EventTarget_Init(EventTarget*,IUnknown*,dispex_static_data_t*,compat_mode_t) DECLSPEC_HIDDEN; +void EventTarget_Init(EventTarget*,IUnknown*,dispex_static_data_t*,HTMLInnerWindow*) DECLSPEC_HIDDEN; HRESULT EventTarget_QI(EventTarget*,REFIID,void**) DECLSPEC_HIDDEN; void EventTarget_init_dispex_info(dispex_data_t*,compat_mode_t) DECLSPEC_HIDDEN; @@ -1234,9 +1234,9 @@ HRESULT handle_link_click_event(HTMLElement*,nsAString*,nsAString*,nsIDOMEvent*, HRESULT wrap_iface(IUnknown*,IUnknown*,IUnknown**) DECLSPEC_HIDDEN; IHTMLElementCollection *create_all_collection(HTMLDOMNode*,BOOL) DECLSPEC_HIDDEN; -IHTMLElementCollection *create_collection_from_nodelist(nsIDOMNodeList*,compat_mode_t) DECLSPEC_HIDDEN; -IHTMLElementCollection *create_collection_from_htmlcol(nsIDOMHTMLCollection*,compat_mode_t) DECLSPEC_HIDDEN; -HRESULT create_child_collection(nsIDOMNodeList*,compat_mode_t,IHTMLDOMChildrenCollection**) DECLSPEC_HIDDEN; +IHTMLElementCollection *create_collection_from_nodelist(nsIDOMNodeList*,HTMLDocumentNode*) DECLSPEC_HIDDEN; +IHTMLElementCollection *create_collection_from_htmlcol(nsIDOMHTMLCollection*,HTMLDocumentNode*,compat_mode_t) DECLSPEC_HIDDEN; +HRESULT create_child_collection(nsIDOMNodeList*,HTMLDocumentNode*,IHTMLDOMChildrenCollection**) DECLSPEC_HIDDEN; HRESULT attr_value_to_string(VARIANT*) DECLSPEC_HIDDEN; HRESULT get_elem_attr_value_by_dispid(HTMLElement*,DISPID,VARIANT*) DECLSPEC_HIDDEN; @@ -1466,5 +1466,5 @@ void set_statustext(HTMLDocumentObj*,INT,LPCWSTR) DECLSPEC_HIDDEN; IInternetSecurityManager *get_security_manager(void) DECLSPEC_HIDDEN; extern HINSTANCE hInst DECLSPEC_HIDDEN; -void create_console(compat_mode_t compat_mode, IWineMSHTMLConsole **ret) DECLSPEC_HIDDEN; +void create_console(HTMLInnerWindow *window, IWineMSHTMLConsole **ret) DECLSPEC_HIDDEN; HRESULT create_media_query_list(HTMLWindow *window, BSTR media_query, IDispatch **ret) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/nsembed.c b/dlls/mshtml/nsembed.c index b7518f55ef9..3244dca127c 100644 --- a/dlls/mshtml/nsembed.c +++ b/dlls/mshtml/nsembed.c @@ -1666,7 +1666,8 @@ static nsresult NSAPI nsContextMenuListener_OnShowContextMenu(nsIContextMenuList if(FAILED(hres)) return NS_ERROR_FAILURE; - hres = create_event_from_nsevent(aEvent, dispex_compat_mode(&node->event_target.dispex), &event); + hres = create_event_from_nsevent(aEvent, This->doc->window->base.inner_window, + dispex_compat_mode(&node->event_target.dispex), &event); if(SUCCEEDED(hres)) { dispatch_event(&node->event_target, event); IDOMEvent_Release(&event->IDOMEvent_iface); diff --git a/dlls/mshtml/nsevents.c b/dlls/mshtml/nsevents.c index b3616b64964..c8c999a74c4 100644 --- a/dlls/mshtml/nsevents.c +++ b/dlls/mshtml/nsevents.c @@ -240,7 +240,7 @@ static nsresult handle_dom_content_loaded(HTMLDocumentNode *doc, nsIDOMEvent *ns if(doc->window) doc->window->performance_timing->dom_content_loaded_event_start_time = get_time_stamp(); - hres = create_event_from_nsevent(nsevent, dispex_compat_mode(&doc->node.event_target.dispex), &event); + hres = create_event_from_nsevent(nsevent, get_inner_window(doc), dispex_compat_mode(&doc->node.event_target.dispex), &event); if(SUCCEEDED(hres)) { dispatch_event(&doc->node.event_target, event); IDOMEvent_Release(&event->IDOMEvent_iface); @@ -375,7 +375,7 @@ static nsresult handle_load(HTMLDocumentNode *doc, nsIDOMEvent *event) WARN("no dom_document\n"); } - hres = create_event_from_nsevent(event, dispex_compat_mode(&doc->node.event_target.dispex), &load_event); + hres = create_event_from_nsevent(event, doc->window, dispex_compat_mode(&doc->node.event_target.dispex), &load_event); if(SUCCEEDED(hres)) { dispatch_event(&doc->window->event_target, load_event); IDOMEvent_Release(&load_event->IDOMEvent_iface); @@ -395,7 +395,7 @@ static nsresult handle_beforeunload(HTMLDocumentNode *doc, nsIDOMEvent *nsevent) return NS_OK; /* Gecko dispatches this to the document, but IE dispatches it to the window */ - hres = create_event_from_nsevent(nsevent, dispex_compat_mode(&doc->node.event_target.dispex), &event); + hres = create_event_from_nsevent(nsevent, window, dispex_compat_mode(&doc->node.event_target.dispex), &event); if(SUCCEEDED(hres)) { dispatch_event(&window->event_target, event); IDOMEvent_Release(&event->IDOMEvent_iface); @@ -421,7 +421,7 @@ static nsresult handle_unload(HTMLDocumentNode *doc, nsIDOMEvent *nsevent) if(timing) timing->unload_event_start_time = get_time_stamp(); - hres = create_event_from_nsevent(nsevent, dispex_compat_mode(&doc->node.event_target.dispex), &event); + hres = create_event_from_nsevent(nsevent, window, dispex_compat_mode(&doc->node.event_target.dispex), &event); if(SUCCEEDED(hres)) { dispatch_event(&window->event_target, event); IDOMEvent_Release(&event->IDOMEvent_iface); @@ -467,7 +467,7 @@ static nsresult handle_htmlevent(HTMLDocumentNode *doc, nsIDOMEvent *nsevent) target = &node->event_target; } - hres = create_event_from_nsevent(nsevent, dispex_compat_mode(&doc->node.event_target.dispex), &event); + hres = create_event_from_nsevent(nsevent, get_inner_window(doc), dispex_compat_mode(&doc->node.event_target.dispex), &event); if(FAILED(hres)) { IEventTarget_Release(&target->IEventTarget_iface); return NS_OK; diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 72b72531490..f23d4c190c9 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -40,6 +40,7 @@ typedef struct { LONG ref; + HTMLInnerWindow *window; HTMLPluginsCollection *plugins; HTMLMimeTypesCollection *mime_types; } OmNavigator; @@ -330,7 +331,7 @@ HRESULT create_dom_implementation(HTMLDocumentNode *doc_node, IHTMLDOMImplementa dom_implementation->browser = doc_node->browser; init_dispatch(&dom_implementation->dispex, (IUnknown*)&dom_implementation->IHTMLDOMImplementation_iface, - &HTMLDOMImplementation_dispex, doc_node->document_mode); + &HTMLDOMImplementation_dispex, get_inner_window(doc_node), doc_node->document_mode); nsres = nsIDOMDocument_GetImplementation(doc_node->dom_document, &dom_implementation->implementation); if(NS_FAILED(nsres)) { @@ -564,7 +565,7 @@ static dispex_static_data_t HTMLScreen_dispex = { HTMLScreen_iface_tids }; -HRESULT create_html_screen(compat_mode_t compat_mode, IHTMLScreen **ret) +HRESULT create_html_screen(HTMLInnerWindow *window, IHTMLScreen **ret) { HTMLScreen *screen; @@ -575,7 +576,8 @@ HRESULT create_html_screen(compat_mode_t compat_mode, IHTMLScreen **ret) screen->IHTMLScreen_iface.lpVtbl = &HTMLSreenVtbl; screen->ref = 1; - init_dispatch(&screen->dispex, (IUnknown*)&screen->IHTMLScreen_iface, &HTMLScreen_dispex, compat_mode); + init_dispatch(&screen->dispex, (IUnknown*)&screen->IHTMLScreen_iface, &HTMLScreen_dispex, + window, dispex_compat_mode(&window->event_target.dispex)); *ret = &screen->IHTMLScreen_iface; return S_OK; @@ -741,7 +743,7 @@ HRESULT create_history(HTMLInnerWindow *window, OmHistory **ret) history->ref = 1; init_dispatch(&history->dispex, (IUnknown*)&history->IOmHistory_iface, &OmHistory_dispex, - dispex_compat_mode(&window->event_target.dispex)); + window, dispex_compat_mode(&window->event_target.dispex)); history->window = window; @@ -899,7 +901,7 @@ static HRESULT create_plugins_collection(OmNavigator *navigator, HTMLPluginsColl col->navigator = navigator; init_dispatch(&col->dispex, (IUnknown*)&col->IHTMLPluginsCollection_iface, - &HTMLPluginsCollection_dispex, dispex_compat_mode(&navigator->dispex)); + &HTMLPluginsCollection_dispex, navigator->window, dispex_compat_mode(&navigator->dispex)); *ret = col; return S_OK; @@ -1044,7 +1046,7 @@ static HRESULT create_mime_types_collection(OmNavigator *navigator, HTMLMimeType col->navigator = navigator; init_dispatch(&col->dispex, (IUnknown*)&col->IHTMLMimeTypesCollection_iface, - &HTMLMimeTypesCollection_dispex, dispex_compat_mode(&navigator->dispex)); + &HTMLMimeTypesCollection_dispex, navigator->window, dispex_compat_mode(&navigator->dispex)); *ret = col; return S_OK; @@ -1481,7 +1483,7 @@ static dispex_static_data_t OmNavigator_dispex = { OmNavigator_iface_tids }; -HRESULT create_navigator(compat_mode_t compat_mode, IOmNavigator **navigator) +HRESULT create_navigator(HTMLInnerWindow *window, IOmNavigator **navigator) { OmNavigator *ret; @@ -1491,13 +1493,21 @@ HRESULT create_navigator(compat_mode_t compat_mode, IOmNavigator **navigator) ret->IOmNavigator_iface.lpVtbl = &OmNavigatorVtbl; ret->ref = 1; + ret->window = window; - init_dispatch(&ret->dispex, (IUnknown*)&ret->IOmNavigator_iface, &OmNavigator_dispex, compat_mode); + init_dispatch(&ret->dispex, (IUnknown*)&ret->IOmNavigator_iface, &OmNavigator_dispex, + window, dispex_compat_mode(&window->event_target.dispex)); *navigator = &ret->IOmNavigator_iface; return S_OK; } +void detach_navigator(IOmNavigator *iface) +{ + OmNavigator *navigator = impl_from_IOmNavigator(iface); + navigator->window = NULL; +} + static inline HTMLPerformanceTiming *impl_from_IHTMLPerformanceTiming(IHTMLPerformanceTiming *iface) { return CONTAINING_RECORD(iface, HTMLPerformanceTiming, IHTMLPerformanceTiming_iface); @@ -2238,7 +2248,7 @@ HRESULT create_performance(HTMLInnerWindow *window, IHTMLPerformance **ret) IHTMLPerformanceTiming_AddRef(&performance->timing->IHTMLPerformanceTiming_iface); init_dispatch(&performance->dispex, (IUnknown*)&performance->IHTMLPerformance_iface, - &HTMLPerformance_dispex, compat_mode); + &HTMLPerformance_dispex, window, compat_mode); navigation->IHTMLPerformanceNavigation_iface.lpVtbl = &HTMLPerformanceNavigationVtbl; navigation->ref = 1; @@ -2246,10 +2256,10 @@ HRESULT create_performance(HTMLInnerWindow *window, IHTMLPerformance **ret) IHTMLPerformanceTiming_AddRef(&navigation->timing->IHTMLPerformanceTiming_iface); init_dispatch(&navigation->dispex, (IUnknown*)&navigation->IHTMLPerformanceNavigation_iface, - &HTMLPerformanceNavigation_dispex, compat_mode); + &HTMLPerformanceNavigation_dispex, window, compat_mode); init_dispatch(&performance->timing->dispex, (IUnknown*)&performance->timing->IHTMLPerformanceTiming_iface, - &HTMLPerformanceTiming_dispex, compat_mode); + &HTMLPerformanceTiming_dispex, window, compat_mode); *ret = &performance->IHTMLPerformance_iface; return S_OK; @@ -2396,7 +2406,7 @@ static dispex_static_data_t HTMLNamespaceCollection_dispex = { HTMLNamespaceCollection_iface_tids }; -HRESULT create_namespace_collection(compat_mode_t compat_mode, IHTMLNamespaceCollection **ret) +HRESULT create_namespace_collection(HTMLDocumentNode *doc_node, IHTMLNamespaceCollection **ret) { HTMLNamespaceCollection *namespaces; @@ -2406,7 +2416,8 @@ HRESULT create_namespace_collection(compat_mode_t compat_mode, IHTMLNamespaceCol namespaces->IHTMLNamespaceCollection_iface.lpVtbl = &HTMLNamespaceCollectionVtbl; namespaces->ref = 1; init_dispatch(&namespaces->dispex, (IUnknown*)&namespaces->IHTMLNamespaceCollection_iface, - &HTMLNamespaceCollection_dispex, compat_mode); + &HTMLNamespaceCollection_dispex, get_inner_window(doc_node), + dispex_compat_mode(&doc_node->node.event_target.dispex)); *ret = &namespaces->IHTMLNamespaceCollection_iface; return S_OK; } @@ -2652,7 +2663,7 @@ static dispex_static_data_t console_dispex = { console_iface_tids }; -void create_console(compat_mode_t compat_mode, IWineMSHTMLConsole **ret) +void create_console(HTMLInnerWindow *window, IWineMSHTMLConsole **ret) { struct console *obj; @@ -2665,7 +2676,8 @@ void create_console(compat_mode_t compat_mode, IWineMSHTMLConsole **ret) obj->IWineMSHTMLConsole_iface.lpVtbl = &WineMSHTMLConsoleVtbl; obj->ref = 1; - init_dispatch(&obj->dispex, (IUnknown*)&obj->IWineMSHTMLConsole_iface, &console_dispex, compat_mode); + init_dispatch(&obj->dispex, (IUnknown*)&obj->IWineMSHTMLConsole_iface, &console_dispex, + window, dispex_compat_mode(&window->event_target.dispex)); *ret = &obj->IWineMSHTMLConsole_iface; } @@ -2859,7 +2871,7 @@ HRESULT create_media_query_list(HTMLWindow *window, BSTR media_query, IDispatch media_query_list->IWineMSHTMLMediaQueryList_iface.lpVtbl = &media_query_list_vtbl; media_query_list->ref = 1; init_dispatch(&media_query_list->dispex, (IUnknown*)&media_query_list->IWineMSHTMLMediaQueryList_iface, - &media_query_list_dispex, dispex_compat_mode(&window->inner_window->event_target.dispex)); + &media_query_list_dispex, window->inner_window, dispex_compat_mode(&window->inner_window->event_target.dispex)); *ret = (IDispatch*)&media_query_list->IWineMSHTMLMediaQueryList_iface; return S_OK; diff --git a/dlls/mshtml/range.c b/dlls/mshtml/range.c index 2124ae15f4a..4be2b6499e0 100644 --- a/dlls/mshtml/range.c +++ b/dlls/mshtml/range.c @@ -1739,7 +1739,7 @@ HRESULT HTMLTxtRange_Create(HTMLDocumentNode *doc, nsIDOMRange *nsrange, IHTMLTx ret->ref = 1; init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLTxtRange_iface, &HTMLTxtRange_dispex, - dispex_compat_mode(&doc->node.event_target.dispex)); + get_inner_window(doc), dispex_compat_mode(&doc->node.event_target.dispex)); if(nsrange) nsIDOMRange_AddRef(nsrange); @@ -2072,7 +2072,7 @@ static dispex_static_data_t HTMLDOMRange_dispex = { HTMLDOMRange_iface_tids }; -HRESULT create_dom_range(nsIDOMRange *nsrange, compat_mode_t compat_mode, IHTMLDOMRange **p) +HRESULT create_dom_range(nsIDOMRange *nsrange, HTMLDocumentNode *doc, IHTMLDOMRange **p) { HTMLDOMRange *ret; @@ -2083,7 +2083,8 @@ HRESULT create_dom_range(nsIDOMRange *nsrange, compat_mode_t compat_mode, IHTMLD ret->IHTMLDOMRange_iface.lpVtbl = &HTMLDOMRangeVtbl; ret->ref = 1; - init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLDOMRange_iface, &HTMLDOMRange_dispex, compat_mode); + init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLDOMRange_iface, &HTMLDOMRange_dispex, + get_inner_window(doc), dispex_compat_mode(&doc->node.event_target.dispex)); if(nsrange) nsIDOMRange_AddRef(nsrange); diff --git a/dlls/mshtml/selection.c b/dlls/mshtml/selection.c index 3b7769da759..12bcd068108 100644 --- a/dlls/mshtml/selection.c +++ b/dlls/mshtml/selection.c @@ -355,7 +355,8 @@ HRESULT HTMLSelectionObject_Create(HTMLDocumentNode *doc, nsISelection *nsselect selection->nsselection = nsselection; /* We shouldn't call AddRef here */ init_dispatch(&selection->dispex, (IUnknown*)&selection->IHTMLSelectionObject_iface, - &HTMLSelectionObject_dispex, dispex_compat_mode(&doc->node.event_target.dispex)); + &HTMLSelectionObject_dispex, get_inner_window(doc), + dispex_compat_mode(&doc->node.event_target.dispex)); selection->doc = doc; list_add_head(&doc->selection_list, &selection->entry); diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index aa5cf3552a4..235850c772f 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -139,6 +139,7 @@ struct HTMLXMLHttpRequest { IProvideClassInfo2 IProvideClassInfo2_iface; LONG ref; response_type_t response_type; + HTMLInnerWindow *window; nsIXMLHttpRequest *nsxhr; XMLHttpReqEventListener *event_listener; }; @@ -232,7 +233,7 @@ static nsresult NSAPI XMLHttpReqEventListener_HandleEvent(nsIDOMEventListener *i if(!This->xhr) return NS_OK; - hres = create_event_from_nsevent(nsevent, dispex_compat_mode(&This->xhr->event_target.dispex), &event); + hres = create_event_from_nsevent(nsevent, This->xhr->window, dispex_compat_mode(&This->xhr->event_target.dispex), &event); if(SUCCEEDED(hres) ){ dispatch_event(&This->xhr->event_target, event); IDOMEvent_Release(&event->IDOMEvent_iface); @@ -300,6 +301,7 @@ static ULONG WINAPI HTMLXMLHttpRequest_Release(IHTMLXMLHttpRequest *iface) if(!ref) { if(This->event_listener) detach_xhr_event_listener(This->event_listener); + IHTMLWindow2_Release(&This->window->base.IHTMLWindow2_iface); release_event_target(&This->event_target); release_dispex(&This->event_target.dispex); nsIXMLHttpRequest_Release(This->nsxhr); @@ -1481,6 +1483,8 @@ static HRESULT WINAPI HTMLXMLHttpRequestFactory_create(IHTMLXMLHttpRequestFactor return E_OUTOFMEMORY; } ret->nsxhr = nsxhr; + ret->window = This->window; + IHTMLWindow2_AddRef(&This->window->base.IHTMLWindow2_iface); ret->IHTMLXMLHttpRequest_iface.lpVtbl = &HTMLXMLHttpRequestVtbl; ret->IHTMLXMLHttpRequest2_iface.lpVtbl = &HTMLXMLHttpRequest2Vtbl; @@ -1488,7 +1492,7 @@ static HRESULT WINAPI HTMLXMLHttpRequestFactory_create(IHTMLXMLHttpRequestFactor ret->IProvideClassInfo2_iface.lpVtbl = &ProvideClassInfo2Vtbl; ret->ref = 1; EventTarget_Init(&ret->event_target, (IUnknown*)&ret->IHTMLXMLHttpRequest_iface, - &HTMLXMLHttpRequest_dispex, This->window->doc->document_mode); + &HTMLXMLHttpRequest_dispex, This->window); *p = &ret->IHTMLXMLHttpRequest_iface; return S_OK; @@ -1561,7 +1565,7 @@ HRESULT HTMLXMLHttpRequestFactory_Create(HTMLInnerWindow* window, HTMLXMLHttpReq ret->window = window; init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLXMLHttpRequestFactory_iface, - &HTMLXMLHttpRequestFactory_dispex, dispex_compat_mode(&window->event_target.dispex)); + &HTMLXMLHttpRequestFactory_dispex, window, dispex_compat_mode(&window->event_target.dispex)); *ret_ptr = ret; return S_OK; From ede9fae2da98751c45fceacf2cb21a62176e9ff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:01 +0200 Subject: [PATCH 0865/2777] jscript: Fill the exception in a helper function and use deferred fill-in if needed. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/dispex.c | 30 ++++++++++++++++++------------ dlls/jscript/jscript.h | 1 + 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 1086791753b..dce70a0e315 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2453,22 +2453,28 @@ static HRESULT disp_invoke(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD f hres = IDispatch_Invoke(disp, id, &IID_NULL, ctx->lcid, flags, params, r, &ei, &err); } - if(hres == DISP_E_EXCEPTION) { - TRACE("DISP_E_EXCEPTION: %08lx %s %s\n", ei.scode, debugstr_w(ei.bstrSource), debugstr_w(ei.bstrDescription)); - reset_ei(ctx->ei); - ctx->ei->error = (SUCCEEDED(ei.scode) || ei.scode == DISP_E_EXCEPTION) ? E_FAIL : ei.scode; - if(ei.bstrSource) - ctx->ei->source = jsstr_alloc_len(ei.bstrSource, SysStringLen(ei.bstrSource)); - if(ei.bstrDescription) - ctx->ei->message = jsstr_alloc_len(ei.bstrDescription, SysStringLen(ei.bstrDescription)); - SysFreeString(ei.bstrSource); - SysFreeString(ei.bstrDescription); - SysFreeString(ei.bstrHelpFile); - } + if(hres == DISP_E_EXCEPTION) + disp_fill_exception(ctx, &ei); return hres; } +void disp_fill_exception(script_ctx_t *ctx, EXCEPINFO *ei) +{ + TRACE("DISP_E_EXCEPTION: %08lx %s %s\n", ei->scode, debugstr_w(ei->bstrSource), debugstr_w(ei->bstrDescription)); + reset_ei(ctx->ei); + if(ei->pfnDeferredFillIn) + ei->pfnDeferredFillIn(ei); + ctx->ei->error = (SUCCEEDED(ei->scode) || ei->scode == DISP_E_EXCEPTION) ? E_FAIL : ei->scode; + if(ei->bstrSource) + ctx->ei->source = jsstr_alloc_len(ei->bstrSource, SysStringLen(ei->bstrSource)); + if(ei->bstrDescription) + ctx->ei->message = jsstr_alloc_len(ei->bstrDescription, SysStringLen(ei->bstrDescription)); + SysFreeString(ei->bstrSource); + SysFreeString(ei->bstrDescription); + SysFreeString(ei->bstrHelpFile); +} + HRESULT disp_call(script_ctx_t *ctx, IDispatch *disp, DISPID id, WORD flags, unsigned argc, jsval_t *argv, jsval_t *ret) { VARIANT buf[6], retv; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 99ae3364ccc..fe798ffae79 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -256,6 +256,7 @@ HRESULT create_dispex(script_ctx_t*,const builtin_info_t*,jsdisp_t*,jsdisp_t**) HRESULT init_dispex(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*) DECLSPEC_HIDDEN; HRESULT init_dispex_from_constr(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*) DECLSPEC_HIDDEN; +void disp_fill_exception(script_ctx_t*,EXCEPINFO*) DECLSPEC_HIDDEN; HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; HRESULT disp_call_name(script_ctx_t*,IDispatch*,const WCHAR*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; HRESULT disp_call_value(script_ctx_t*,IDispatch*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*,IServiceProvider*) DECLSPEC_HIDDEN; From c6a36b42596fb6a97da226750dbc3a9e961050ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:01 +0200 Subject: [PATCH 0866/2777] jscript: Pass the correct ServiceProvider when invoking internal props. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- This is a no-op now, but will be required for forwarding it to the mshtml object. --- dlls/jscript/array.c | 2 +- dlls/jscript/dispex.c | 39 ++++++++++++++++++++------------------- dlls/jscript/function.c | 20 ++++++++++---------- dlls/jscript/jscript.h | 4 ++-- dlls/jscript/json.c | 3 ++- dlls/jscript/string.c | 2 +- 6 files changed, 36 insertions(+), 34 deletions(-) diff --git a/dlls/jscript/array.c b/dlls/jscript/array.c index 198fc3c16c1..12a09e020df 100644 --- a/dlls/jscript/array.c +++ b/dlls/jscript/array.c @@ -631,7 +631,7 @@ static HRESULT sort_cmp(script_ctx_t *ctx, jsdisp_t *cmp_func, jsval_t v1, jsval jsval_t res; double n; - hres = jsdisp_call_value(cmp_func, jsval_undefined(), DISPATCH_METHOD, 2, args, &res); + hres = jsdisp_call_value(cmp_func, jsval_undefined(), DISPATCH_METHOD, 2, args, &res, &ctx->jscaller->IServiceProvider_iface); if(FAILED(hres)) return hres; diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index dce70a0e315..e6c43f2771c 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -467,7 +467,7 @@ static HRESULT convert_params(script_ctx_t *ctx, const DISPPARAMS *dp, jsval_t * return S_OK; } -static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, jsval_t *r) +static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, jsval_t *r, IServiceProvider *caller) { jsdisp_t *prop_obj = This; HRESULT hres; @@ -486,8 +486,7 @@ static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, jsval_t *r) break; case PROP_ACCESSOR: if(prop->u.accessor.getter) { - hres = jsdisp_call_value(prop->u.accessor.getter, jsval_obj(This), - DISPATCH_METHOD, 0, NULL, r); + hres = jsdisp_call_value(prop->u.accessor.getter, jsval_obj(This), DISPATCH_METHOD, 0, NULL, r, caller); }else { *r = jsval_undefined(); hres = S_OK; @@ -510,7 +509,7 @@ static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, jsval_t *r) return hres; } -static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val) +static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val, IServiceProvider *caller) { HRESULT hres; @@ -553,7 +552,7 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val) TRACE("no setter\n"); return S_OK; } - return jsdisp_call_value(prop->u.accessor.setter, jsval_obj(This), DISPATCH_METHOD, 1, &val, NULL); + return jsdisp_call_value(prop->u.accessor.setter, jsval_obj(This), DISPATCH_METHOD, 1, &val, NULL, caller); case PROP_IDX: if(!This->builtin_info->idx_put) { TRACE("no put_idx\n"); @@ -604,7 +603,7 @@ static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t case PROP_IDX: { jsval_t val; - hres = prop_get(This, prop, &val); + hres = prop_get(This, prop, &val, caller); if(FAILED(hres)) return hres; @@ -1968,7 +1967,8 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc if(prop) hres = invoke_prop_func(This, passed_this, prop, wFlags, argc, argv, pvarRes ? &r : NULL, pspCaller); else - hres = jsdisp_call_value(This, passed_this ? jsval_disp(passed_this) : jsval_undefined(), wFlags, argc, argv, pvarRes ? &r : NULL); + hres = jsdisp_call_value(This, passed_this ? jsval_disp(passed_this) : jsval_undefined(), + wFlags, argc, argv, pvarRes ? &r : NULL, pspCaller); while(argc--) jsval_release(argv[argc]); @@ -1984,7 +1984,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc jsval_t r; if(prop) - hres = prop_get(This, prop, &r); + hres = prop_get(This, prop, &r, pspCaller); else { hres = to_primitive(This->ctx, jsval_obj(This), &r, NO_HINT); if(hres == JS_E_TO_PRIMITIVE) @@ -2023,7 +2023,7 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc if(FAILED(hres)) break; - hres = prop_put(This, prop, val); + hres = prop_put(This, prop, val, pspCaller); jsval_release(val); break; } @@ -2313,7 +2313,7 @@ HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const built if(SUCCEEDED(hres) && prop && prop->type!=PROP_DELETED) { jsval_t val; - hres = prop_get(constr, prop, &val); + hres = prop_get(constr, prop, &val, &ctx->jscaller->IServiceProvider_iface); if(FAILED(hres)) { ERR("Could not get prototype\n"); return hres; @@ -2372,14 +2372,15 @@ HRESULT jsdisp_get_id(jsdisp_t *jsdisp, const WCHAR *name, DWORD flags, DISPID * return DISP_E_UNKNOWNNAME; } -HRESULT jsdisp_call_value(jsdisp_t *jsfunc, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +HRESULT jsdisp_call_value(jsdisp_t *jsfunc, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, + jsval_t *r, IServiceProvider *caller) { HRESULT hres; assert(!(flags & ~(DISPATCH_METHOD|DISPATCH_CONSTRUCT|DISPATCH_JSCRIPT_INTERNAL_MASK))); if(is_class(jsfunc, JSCLASS_FUNCTION)) { - hres = Function_invoke(jsfunc, vthis, flags, argc, argv, r); + hres = Function_invoke(jsfunc, vthis, flags, argc, argv, r, caller); }else { if(!jsfunc->builtin_info->call) { WARN("Not a function\n"); @@ -2592,7 +2593,7 @@ HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, jsval_t vthis, WORD jsdisp = iface_to_jsdisp(disp); if(jsdisp && jsdisp->ctx == ctx) { - hres = jsdisp_call_value(jsdisp, vthis, flags, argc, argv, r); + hres = jsdisp_call_value(jsdisp, vthis, flags, argc, argv, r, caller); jsdisp_release(jsdisp); return hres; } @@ -2669,7 +2670,7 @@ HRESULT jsdisp_propput(jsdisp_t *obj, const WCHAR *name, DWORD flags, BOOL throw if(!prop || (prop->type == PROP_DELETED && !obj->extensible)) return throw ? JS_E_INVALID_ACTION : S_OK; - return prop_put(obj, prop, val); + return prop_put(obj, prop, val, &obj->ctx->jscaller->IServiceProvider_iface); } HRESULT jsdisp_propput_name(jsdisp_t *obj, const WCHAR *name, jsval_t val) @@ -2696,7 +2697,7 @@ HRESULT disp_propput(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t val) prop = get_prop(jsdisp, id); if(prop) - hres = prop_put(jsdisp, prop, val); + hres = prop_put(jsdisp, prop, val, &ctx->jscaller->IServiceProvider_iface); else hres = DISP_E_MEMBERNOTFOUND; @@ -2777,7 +2778,7 @@ HRESULT jsdisp_propget_name(jsdisp_t *obj, const WCHAR *name, jsval_t *val) return S_OK; } - hres = prop_get(obj, prop, val); + hres = prop_get(obj, prop, val, &obj->ctx->jscaller->IServiceProvider_iface); if(hres == DISP_E_MEMBERNOTFOUND) { *val = jsval_undefined(); return S_OK; @@ -2805,7 +2806,7 @@ HRESULT jsdisp_get_idx(jsdisp_t *obj, DWORD idx, jsval_t *r) return DISP_E_UNKNOWNNAME; } - hres = prop_get(obj, prop, r); + hres = prop_get(obj, prop, r, &obj->ctx->jscaller->IServiceProvider_iface); if(hres == DISP_E_MEMBERNOTFOUND) { *r = jsval_undefined(); return DISP_E_UNKNOWNNAME; @@ -2821,7 +2822,7 @@ HRESULT jsdisp_propget(jsdisp_t *jsdisp, DISPID id, jsval_t *val) if(!prop) return DISP_E_MEMBERNOTFOUND; - return prop_get(jsdisp, prop, val); + return prop_get(jsdisp, prop, val, &jsdisp->ctx->jscaller->IServiceProvider_iface); } HRESULT disp_propget(script_ctx_t *ctx, IDispatch *disp, DISPID id, jsval_t *val) @@ -3043,7 +3044,7 @@ HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_onl desc->mask |= PROPF_WRITABLE; desc->explicit_value = TRUE; if(!flags_only) { - hres = prop_get(obj, prop, &desc->value); + hres = prop_get(obj, prop, &desc->value, &obj->ctx->jscaller->IServiceProvider_iface); if(FAILED(hres)) return (hres == DISP_E_MEMBERNOTFOUND) ? DISP_E_UNKNOWNNAME : hres; } diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 513dee71809..b7b48840ab6 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -35,7 +35,7 @@ typedef struct { } FunctionInstance; struct _function_vtbl_t { - HRESULT (*call)(script_ctx_t*,FunctionInstance*,jsval_t,unsigned,unsigned,jsval_t*,jsval_t*); + HRESULT (*call)(script_ctx_t*,FunctionInstance*,jsval_t,unsigned,unsigned,jsval_t*,jsval_t*,IServiceProvider*); HRESULT (*toString)(FunctionInstance*,jsstr_t**); function_code_t* (*get_code)(FunctionInstance*); void (*destructor)(FunctionInstance*); @@ -272,7 +272,7 @@ void detach_arguments_object(jsdisp_t *args_disp) jsdisp_release(frame->arguments_obj); } -HRESULT Function_invoke(jsdisp_t *func_this, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) +HRESULT Function_invoke(jsdisp_t *func_this, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) { FunctionInstance *function; @@ -286,7 +286,7 @@ HRESULT Function_invoke(jsdisp_t *func_this, jsval_t vthis, WORD flags, unsigned return E_UNEXPECTED; } - return function->vtbl->call(function->dispex.ctx, function, vthis, flags, argc, argv, r); + return function->vtbl->call(function->dispex.ctx, function, vthis, flags, argc, argv, r, caller); } static HRESULT Function_get_length(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) @@ -408,7 +408,7 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi if(SUCCEEDED(hres)) { if(function) { - hres = function->vtbl->call(ctx, function, this_val, flags, cnt, args, r); + hres = function->vtbl->call(ctx, function, this_val, flags, cnt, args, r, &ctx->jscaller->IServiceProvider_iface); }else { jsval_t res; hres = disp_call_value(ctx, get_object(vthis), this_val, DISPATCH_METHOD, cnt, args, &res, &ctx->jscaller->IServiceProvider_iface); @@ -458,7 +458,7 @@ static HRESULT Function_call(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsig cnt = argc-1; } - hres = function->vtbl->call(ctx, function, this_val, flags, cnt, argv + 1, r); + hres = function->vtbl->call(ctx, function, this_val, flags, cnt, argv + 1, r, &ctx->jscaller->IServiceProvider_iface); jsval_release(this_val); return hres; @@ -513,7 +513,7 @@ HRESULT Function_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned ar return E_FAIL; } - return function->vtbl->call(ctx, function, vthis, flags, argc, argv, r); + return function->vtbl->call(ctx, function, vthis, flags, argc, argv, r, &ctx->jscaller->IServiceProvider_iface); } HRESULT Function_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r) @@ -649,7 +649,7 @@ static HRESULT create_function(script_ctx_t *ctx, const builtin_info_t *builtin_ } static HRESULT NativeFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags, - unsigned argc, jsval_t *argv, jsval_t *r) + unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) { NativeFunction *function = (NativeFunction*)func; @@ -811,7 +811,7 @@ static const builtin_info_t InterpretedFunction_info = { }; static HRESULT InterpretedFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags, - unsigned argc, jsval_t *argv, jsval_t *r) + unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) { InterpretedFunction *function = (InterpretedFunction*)func; IDispatch *this_obj = NULL; @@ -914,7 +914,7 @@ HRESULT create_source_function(script_ctx_t *ctx, bytecode_t *code, function_cod } static HRESULT BindFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags, - unsigned argc, jsval_t *argv, jsval_t *r) + unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) { BindFunction *function = (BindFunction*)func; jsval_t *call_args = NULL; @@ -935,7 +935,7 @@ static HRESULT BindFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsva memcpy(call_args + function->argc, argv, argc * sizeof(*call_args)); } - hres = function->target->vtbl->call(ctx, function->target, function->this, flags, call_argc, call_args, r); + hres = function->target->vtbl->call(ctx, function->target, function->this, flags, call_argc, call_args, r, caller); free(call_args); return hres; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index fe798ffae79..c01ca07bd8e 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -260,7 +260,7 @@ void disp_fill_exception(script_ctx_t*,EXCEPINFO*) DECLSPEC_HIDDEN; HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; HRESULT disp_call_name(script_ctx_t*,IDispatch*,const WCHAR*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; HRESULT disp_call_value(script_ctx_t*,IDispatch*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*,IServiceProvider*) DECLSPEC_HIDDEN; -HRESULT jsdisp_call_value(jsdisp_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; +HRESULT jsdisp_call_value(jsdisp_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*,IServiceProvider*) DECLSPEC_HIDDEN; HRESULT jsdisp_call(jsdisp_t*,DISPID,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; HRESULT jsdisp_call_name(jsdisp_t*,const WCHAR*,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; HRESULT disp_propget(script_ctx_t*,IDispatch*,DISPID,jsval_t*) DECLSPEC_HIDDEN; @@ -289,7 +289,7 @@ HRESULT create_builtin_function(script_ctx_t*,builtin_invoke_t,const WCHAR*,cons jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT create_builtin_constructor(script_ctx_t*,builtin_invoke_t,const WCHAR*,const builtin_info_t*,DWORD, jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; -HRESULT Function_invoke(jsdisp_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; +HRESULT Function_invoke(jsdisp_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*,IServiceProvider*) DECLSPEC_HIDDEN; HRESULT Function_value(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; HRESULT Function_get_value(script_ctx_t*,jsdisp_t*,jsval_t*) DECLSPEC_HIDDEN; diff --git a/dlls/jscript/json.c b/dlls/jscript/json.c index d2be768ffea..cce847ac968 100644 --- a/dlls/jscript/json.c +++ b/dlls/jscript/json.c @@ -775,7 +775,8 @@ static HRESULT stringify(stringify_ctx_t *ctx, jsdisp_t *object, const WCHAR *na } args[0] = jsval_string(name_str); args[1] = value; - hres = jsdisp_call_value(ctx->replacer, jsval_obj(object), DISPATCH_METHOD, ARRAY_SIZE(args), args, &v); + hres = jsdisp_call_value(ctx->replacer, jsval_obj(object), DISPATCH_METHOD, ARRAY_SIZE(args), args, + &v, &ctx->ctx->jscaller->IServiceProvider_iface); jsstr_release(name_str); jsval_release(value); if(FAILED(hres)) diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c index 14bcfbdaaf3..4faf8ea56c9 100644 --- a/dlls/jscript/string.c +++ b/dlls/jscript/string.c @@ -702,7 +702,7 @@ static HRESULT rep_call(script_ctx_t *ctx, jsdisp_t *func, } if(SUCCEEDED(hres)) - hres = jsdisp_call_value(func, jsval_undefined(), DISPATCH_METHOD, argc, argv, &val); + hres = jsdisp_call_value(func, jsval_undefined(), DISPATCH_METHOD, argc, argv, &val, &ctx->jscaller->IServiceProvider_iface); for(i=0; i <= match->paren_count; i++) jsstr_release(get_string(argv[i])); From d74761c0315a6cb26e05b93183a8ec214fdc193c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:01 +0200 Subject: [PATCH 0867/2777] jscript: Implement proxy objects along with a private interface. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Native mshtml objects act like JS objects in IE9+ mode (the JS engine is implemented in mshtml). This implements a sort of proxy JS objects for mshtml objects that export a new private (internal to Wine) interface, to achieve the same behavior. Another callback interface on jscript side is exposed to mshtml implicitly, which mshtml uses to callback or notify jscript of changes or things it needs (such as being unlinked from mshtml). The props that are forwarded to the mshtml side are stored as either proxy functions or accessors, or a new prop type (for custom values), which is only available for such proxy JS objects, and use the internal interface to forward them to mshtml. Some of this interface is close to IDispatch, but is separate for two reasons: it has to skip asking jscript again for the prop (unlike when it's accessed by non-JS code for example), and accessors may potentially have a different "this" pointer as well passed to them. Since it's purely internal, the private interfaces are not part of any typelib, and for simplicity they extend IDispatchEx, to keep one vtbl. A mshtml object can also be accessed by normal COM code, and it exposes the typical interfaces while also having the jscript props (as we check in tests), so we have to forward its calls to jscript, which might forward it back to mshtml, but only once. We can't expose the jscript proxy object directly at all. However, even on native, its DISPIDs are different than the ones in the .idl file, so it's fine to forward them to jscript. We query external IDispatch objects on demand for the interface. If it's available, we either create a JS proxy object that is associated with the mshtml object exposing the interface, or re-acquire another old one (possibly dangling with refcount zero). It is also associated on the mshtml side, but not via an actual strong ref, so that we keep a 1:1 mapping between the JS proxy object and the actual mshtml object, so it preserves the props, prototypes, and DISPIDs, but without creating a cyclic ref. As a consequence of this, we don't immediately free the jsdisp when its refcount reaches zero. Instead, we release the mshtml dispatch ref we hold, and wait for mshtml to callback and unlink us. It does that when it no longer needs it, such as when the mshtml dispatch was actually destroyed (no other refs to it). We can then free the jsdisp if it's dangling, or disassociate it from the proxy otherwise (needed for window). Signed-off-by: Gabriel Ivăncescu --- When proxy is created on JS side, when we retrieve it back it has to match the interfaces and pointers. This means that the mshtml dispatch itself has to callback into jscript to ask for its js props, if it's a proxy. And jscript will have to forward the proxy props on mshtml side by excluding such access back into itself (preventing infinite recursion). So if some code accesses a mshtml dispatch for a prop, the chain looks like the following: mshtml object without proxy: [mshtml] get prop->[mshtml] returns the prop mshtml object with js proxy accessing a pure js prop: [mshtml] get prop->[jscript] returns the js prop mshtml object with js proxy accessing its own prop: [mshtml] get prop->[jscript] forwards->[mshtml] returns its prop So no matter what props it has, jscript just forwards them with appropriate internal interface methods. Also, whenever we use an accessor, we have to pass the actual "this" pointer, which is needed when we move them to the prototypes later. This can't be done for normal dispatch objects, only our internal interface. --- dlls/jscript/dispex.c | 535 +++++++++++++++++++++++++++++++++-- dlls/jscript/engine.c | 17 +- dlls/jscript/function.c | 134 ++++++++- dlls/jscript/jscript.c | 5 + dlls/jscript/jscript.h | 68 ++++- dlls/jscript/jsutils.c | 16 +- dlls/jscript/object.c | 20 +- dlls/mshtml/mshtml_private.h | 63 +++++ 8 files changed, 823 insertions(+), 35 deletions(-) diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index e6c43f2771c..8fb80702697 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -36,6 +36,7 @@ typedef enum { PROP_BUILTIN, PROP_PROTREF, PROP_ACCESSOR, + PROP_PROXY, PROP_DELETED, PROP_IDX } prop_type_t; @@ -55,12 +56,15 @@ struct _dispex_prop_t { jsdisp_t *getter; jsdisp_t *setter; } accessor; + DISPID proxy_id; } u; int bucket_head; int bucket_next; }; +static HRESULT fix_overridden_prop(jsdisp_t *This, dispex_prop_t *prop); + static void fix_protref_prop(jsdisp_t *jsdisp, dispex_prop_t *prop) { DWORD ref; @@ -87,13 +91,16 @@ static inline DISPID prop_to_id(jsdisp_t *This, dispex_prop_t *prop) static inline dispex_prop_t *get_prop(jsdisp_t *This, DISPID id) { + dispex_prop_t *prop; DWORD idx = id - 1; if(idx >= This->prop_cnt) return NULL; - fix_protref_prop(This, &This->props[idx]); + prop = &This->props[idx]; - return This->props[idx].type == PROP_DELETED ? NULL : &This->props[idx]; + fix_overridden_prop(This, prop); + fix_protref_prop(This, prop); + return prop->type == PROP_DELETED ? NULL : prop; } static inline BOOL is_function_prop(dispex_prop_t *prop) @@ -257,6 +264,50 @@ static inline dispex_prop_t* alloc_prop(jsdisp_t *This, const WCHAR *name, prop_ return prop; } +static HRESULT alloc_proxy_prop(jsdisp_t *This, struct proxy_prop_info *info, dispex_prop_t **ret) +{ + dispex_prop_t *prop; + jsdisp_t *funcs[2]; + prop_type_t type; + HRESULT hres; + + if(!info->func[0].invoke) + type = PROP_PROXY; + else { + hres = create_proxy_functions(This, info, funcs); + if(FAILED(hres)) + return hres; + type = (info->flags & PROPF_METHOD) ? PROP_JSVAL : PROP_ACCESSOR; + } + + if((prop = *ret)) { + prop->type = type; + prop->flags = info->flags & PROPF_ALL; + }else { + prop = alloc_prop(This, info->name, type, info->flags & PROPF_ALL); + if(!prop) { + if(type != PROP_PROXY) { + jsdisp_release(funcs[0]); + if(funcs[1]) + jsdisp_release(funcs[1]); + } + return E_OUTOFMEMORY; + } + *ret = prop; + } + + if(type == PROP_PROXY) + prop->u.proxy_id = info->dispid; + else if(type == PROP_JSVAL) + prop->u.val = jsval_obj(funcs[0]); + else { + prop->u.accessor.getter = funcs[0]; + prop->u.accessor.setter = funcs[1]; + } + + return S_OK; +} + static dispex_prop_t *alloc_protref(jsdisp_t *This, const WCHAR *name, DWORD ref) { dispex_prop_t *ret; @@ -286,14 +337,26 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, This->props[bucket].bucket_head = pos; } + hres = fix_overridden_prop(This, &This->props[pos]); *ret = &This->props[pos]; - return S_OK; + return hres; } prev = pos; pos = This->props[pos].bucket_next; } + if(This->proxy) { + struct proxy_prop_info info; + hres = This->proxy->lpVtbl->PropGetInfo(This->proxy, name, case_insens, &info); + if(hres == S_OK) { + *ret = NULL; + return alloc_proxy_prop(This, &info, ret); + } + if(hres != DISP_E_UNKNOWNNAME) + return hres; + } + builtin = find_builtin_prop(This, name, case_insens); if(builtin) { unsigned flags = builtin->flags; @@ -410,12 +473,72 @@ static HRESULT ensure_prop_name(jsdisp_t *This, const WCHAR *name, DWORD create_ } prop->u.val = jsval_undefined(); + + if(This->proxy) { + struct proxy_prop_info info; + + info.name = name; + hres = This->proxy->lpVtbl->PropDefineOverride(This->proxy, &info); + if(hres == S_FALSE) + hres = S_OK; + else if(SUCCEEDED(hres)) + hres = alloc_proxy_prop(This, &info, &prop); + } } *ret = prop; return hres; } +static HRESULT fix_overridden_prop(jsdisp_t *This, dispex_prop_t *prop) +{ + struct proxy_prop_info info; + HRESULT hres; + + if(!This->proxy) + return S_OK; + + info.name = prop->name; + info.dispid = DISPID_UNKNOWN; + + switch(prop->type) { + case PROP_PROXY: + info.dispid = prop->u.proxy_id; + break; + case PROP_PROTREF: + case PROP_DELETED: + break; + default: + return S_OK; + } + + hres = This->proxy->lpVtbl->PropFixOverride(This->proxy, &info); + if(hres != S_OK) + return FAILED(hres) ? hres : S_OK; + + /* Either the prop was restored (to PROP_PROXY), or it was removed */ + if(info.dispid == DISPID_UNKNOWN) { + if(This->prototype) { + dispex_prop_t *prot_prop; + + hres = find_prop_name_prot(This->prototype, prop->hash, prop->name, FALSE, &prot_prop); + if(FAILED(hres)) + return hres; + if(prot_prop && prot_prop->type != PROP_DELETED) { + prop->type = PROP_PROTREF; + prop->u.ref = prot_prop - This->prototype->props; + return hres; + } + } + prop->type = PROP_DELETED; + }else { + info.func[0].invoke = NULL; + hres = alloc_proxy_prop(This, &info, &prop); + } + + return hres; +} + static IDispatch *get_this(DISPPARAMS *dp) { DWORD i; @@ -467,16 +590,88 @@ static HRESULT convert_params(script_ctx_t *ctx, const DISPPARAMS *dp, jsval_t * return S_OK; } +static HRESULT proxy_disp_call(jsdisp_t *This, jsval_t vthis, DISPID id, unsigned flags, unsigned argc, + jsval_t *argv, jsval_t *ret, IServiceProvider *caller) +{ + DISPPARAMS dp = { NULL, NULL, argc, 0 }; + IDispatch *this_obj, *converted = NULL; + script_ctx_t *ctx = This->ctx; + EXCEPINFO ei = { 0 }; + VARIANT buf[6], retv; + jsdisp_t *jsdisp; + HRESULT hres; + unsigned i; + + if(!ctx->global) + return E_UNEXPECTED; + + if(dp.cArgs <= ARRAY_SIZE(buf)) + dp.rgvarg = buf; + else if(!(dp.rgvarg = malloc(dp.cArgs * sizeof(*dp.rgvarg)))) + return E_OUTOFMEMORY; + + for(i = 0; i < dp.cArgs; i++) { + hres = jsval_to_variant(argv[i], &dp.rgvarg[dp.cArgs - i - 1]); + if(FAILED(hres)) + goto cleanup; + } + + if(is_undefined(vthis) || is_null(vthis)) + this_obj = lookup_global_host(ctx); + else { + hres = to_object(ctx, vthis, &converted); + if(FAILED(hres)) + goto cleanup; + this_obj = converted; + } + + jsdisp = to_jsdisp(this_obj); + if(jsdisp && jsdisp->proxy) + this_obj = (IDispatch*)jsdisp->proxy; + + V_VT(&retv) = VT_EMPTY; + flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK; + hres = This->proxy->lpVtbl->PropInvoke(This->proxy, this_obj, id, ctx->lcid, flags, &dp, ret ? &retv : NULL, &ei, caller); + if(converted) + IDispatch_Release(converted); + + if(hres == DISP_E_EXCEPTION) + disp_fill_exception(ctx, &ei); + else if(SUCCEEDED(hres) && ret) { + hres = variant_to_jsval(ctx, &retv, ret); + VariantClear(&retv); + } + +cleanup: + while(i--) + VariantClear(&dp.rgvarg[i]); + if(dp.rgvarg != buf) + free(dp.rgvarg); + return hres; +} + static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, jsval_t *r, IServiceProvider *caller) { jsdisp_t *prop_obj = This; HRESULT hres; + VARIANT var; while(prop->type == PROP_PROTREF) { prop_obj = prop_obj->prototype; prop = prop_obj->props + prop->u.ref; } + if(prop_obj->proxy) { + hres = prop_obj->proxy->lpVtbl->PropOverride(prop_obj->proxy, prop->name, &var); + if(hres != S_FALSE) { + if(SUCCEEDED(hres)) { + hres = variant_to_jsval(This->ctx, &var, r); + VariantClear(&var); + } + goto done; + } + } + switch(prop->type) { case PROP_BUILTIN: hres = prop->u.p->getter(This->ctx, This, r); @@ -492,6 +687,21 @@ static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, jsval_t *r, IServic hres = S_OK; } break; + case PROP_PROXY: { + DISPPARAMS dp = { 0 }; + EXCEPINFO ei = { 0 }; + + V_VT(&var) = VT_EMPTY; + hres = prop_obj->proxy->lpVtbl->PropInvoke(prop_obj->proxy, This->proxy ? (IDispatch*)This->proxy : to_disp(This), + prop->u.proxy_id, This->ctx->lcid, DISPATCH_PROPERTYGET, &dp, &var, &ei, caller); + if(hres == DISP_E_EXCEPTION) + disp_fill_exception(This->ctx, &ei); + else if(SUCCEEDED(hres)) { + hres = variant_to_jsval(This->ctx, &var, r); + VariantClear(&var); + } + break; + } case PROP_IDX: hres = prop_obj->builtin_info->idx_get(prop_obj, prop->u.idx, r); break; @@ -499,7 +709,10 @@ static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, jsval_t *r, IServic ERR("type %d\n", prop->type); return E_FAIL; } + if(SUCCEEDED(hres)) + hres = convert_to_proxy(This->ctx, r); +done: if(FAILED(hres)) { TRACE("fail %08lx\n", hres); return hres; @@ -511,6 +724,7 @@ static HRESULT prop_get(jsdisp_t *This, dispex_prop_t *prop, jsval_t *r, IServic static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val, IServiceProvider *caller) { + jsdisp_t *prop_obj = This; HRESULT hres; if(prop->type == PROP_PROTREF) { @@ -522,8 +736,10 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val, IServi prop_iter = prototype_iter->props + prop_iter->u.ref; } while(prop_iter->type == PROP_PROTREF); - if(prop_iter->type == PROP_ACCESSOR) + if(prop_iter->type == PROP_ACCESSOR) { + prop_obj = prototype_iter; prop = prop_iter; + } } switch(prop->type) { @@ -553,6 +769,25 @@ static HRESULT prop_put(jsdisp_t *This, dispex_prop_t *prop, jsval_t val, IServi return S_OK; } return jsdisp_call_value(prop->u.accessor.setter, jsval_obj(This), DISPATCH_METHOD, 1, &val, NULL, caller); + case PROP_PROXY: { + static DISPID propput_dispid = DISPID_PROPERTYPUT; + EXCEPINFO ei = { 0 }; + VARIANT var; + DISPPARAMS dp = { &var, &propput_dispid, 1, 1 }; + + if(!(prop->flags & PROPF_WRITABLE)) + return S_OK; + hres = jsval_to_variant(val, &var); + if(FAILED(hres)) + return hres; + + hres = prop_obj->proxy->lpVtbl->PropInvoke(prop_obj->proxy, This->proxy ? (IDispatch*)This->proxy : to_disp(This), + prop->u.proxy_id, This->ctx->lcid, DISPATCH_PROPERTYPUT, &dp, NULL, &ei, caller); + VariantClear(&var); + if(hres == DISP_E_EXCEPTION) + disp_fill_exception(This->ctx, &ei); + return hres; + } case PROP_IDX: if(!This->builtin_info->idx_put) { TRACE("no put_idx\n"); @@ -619,6 +854,9 @@ static HRESULT invoke_prop_func(jsdisp_t *This, IDispatch *jsthis, dispex_prop_t jsval_release(val); return hres; } + case PROP_PROXY: + return proxy_disp_call(This, jsval_disp(jsthis ? jsthis : (IDispatch*)&This->IDispatchEx_iface), + prop->u.proxy_id, flags, argc, argv, r, caller); case PROP_DELETED: assert(0); break; @@ -638,6 +876,12 @@ static HRESULT fill_props(jsdisp_t *obj) dispex_prop_t *prop; HRESULT hres; + if(obj->proxy) { + hres = obj->proxy->lpVtbl->PropEnum(obj->proxy); + if(FAILED(hres)) + return hres; + } + if(obj->builtin_info->idx_length) { unsigned i = 0, len = obj->builtin_info->idx_length(obj); WCHAR name[12]; @@ -862,7 +1106,7 @@ HRESULT gc_run(script_ctx_t *ctx) /* 2. Clear mark on objects with non-zero "external refcount" and all objects accessible from them */ LIST_FOR_EACH_ENTRY(obj, &ctx->objects, jsdisp_t, entry) { - if(!obj->ref || !obj->gc_marked) + if(!obj->gc_marked || (!obj->ref && (!obj->proxy || obj->proxy->lpVtbl->CanGC(obj->proxy)))) continue; hres = gc_stack_push(&gc_ctx, NULL); @@ -1881,7 +2125,7 @@ static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, if(cNames == 0) return S_OK; - hres = jsdisp_get_id(This, rgszNames[0], 0, rgDispId); + hres = jsdisp_get_id(This, rgszNames[0], This->proxy ? fdexNameCaseInsensitive : 0, rgDispId); if(FAILED(hres)) return hres; @@ -2039,13 +2283,21 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc return leave_script(This->ctx, hres); } -static HRESULT delete_prop(dispex_prop_t *prop, BOOL *ret) +static HRESULT delete_prop(jsdisp_t *prop_obj, dispex_prop_t *prop, BOOL *ret) { if(prop->type == PROP_PROTREF) { *ret = TRUE; return S_OK; } + if(prop_obj->proxy) { + HRESULT hres = prop_obj->proxy->lpVtbl->PropOverride(prop_obj->proxy, prop->name, NULL); + if(hres != S_FALSE) { + *ret = TRUE; + return hres; + } + } + if(!(prop->flags & PROPF_CONFIGURABLE)) { *ret = FALSE; return S_OK; @@ -2053,6 +2305,23 @@ static HRESULT delete_prop(dispex_prop_t *prop, BOOL *ret) *ret = TRUE; + if(prop->type == PROP_PROXY) { + HRESULT hres = prop_obj->proxy->lpVtbl->PropDelete(prop_obj->proxy, prop->u.proxy_id); + if(SUCCEEDED(hres)) + prop->type = PROP_DELETED; + return hres; + } + /* FIXME: Get rid of this once the builtin proxy props are moved to the prototype */ + if(prop_obj->proxy) { + if(prop->type == PROP_JSVAL && is_object_instance(prop->u.val) && + is_proxy_func(to_jsdisp(get_object(prop->u.val)))) { + return S_OK; + } + if(prop->type == PROP_ACCESSOR && + (is_proxy_func(prop->u.accessor.getter) || is_proxy_func(prop->u.accessor.setter))) { + return S_OK; + } + } if(prop->type == PROP_JSVAL) jsval_release(prop->u.val); if(prop->type == PROP_ACCESSOR) { @@ -2089,7 +2358,7 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bst return S_OK; } - return delete_prop(prop, &b); + return delete_prop(This, prop, &b); } static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) @@ -2106,7 +2375,7 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID return DISP_E_MEMBERNOTFOUND; } - return delete_prop(prop, &b); + return delete_prop(This, prop, &b); } static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) @@ -2155,7 +2424,108 @@ static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown return E_NOTIMPL; } -static IDispatchExVtbl DispatchExVtbl = { +static inline jsdisp_t *impl_from_IWineDispatchProxyCbPrivate(IWineDispatchProxyCbPrivate *iface) +{ + return impl_from_IDispatchEx((IDispatchEx*)iface); +} + +static HRESULT WINAPI WineDispatchProxyCbPrivate_InitProxy(IWineDispatchProxyCbPrivate *iface, IDispatch *obj) +{ + jsdisp_t *This = impl_from_IWineDispatchProxyCbPrivate(iface); + script_ctx_t *ctx = This->ctx; + jsval_t val = jsval_disp(obj); + HRESULT hres; + + if(!ctx->global) + return E_UNEXPECTED; /* Let caller know it has to initialize the host */ + + IDispatch_AddRef(obj); + hres = convert_to_proxy(ctx, &val); + if(SUCCEEDED(hres)) + jsval_release(val); + return hres; +} + +static void WINAPI WineDispatchProxyCbPrivate_Unlinked(IWineDispatchProxyCbPrivate *iface, BOOL persist) +{ + jsdisp_t *This = impl_from_IWineDispatchProxyCbPrivate(iface); + + if(!persist) { + IWineDispatchProxyPrivate *proxy = This->proxy; + + This->proxy = NULL; + if(!This->ref) { + jsdisp_free(This); + return; + } + + /* We hold a ref only when we're not dangling */ + IDispatchEx_Release((IDispatchEx*)proxy); + } + unlink_props(This); +} + +static HRESULT WINAPI WineDispatchProxyCbPrivate_HostUpdated(IWineDispatchProxyCbPrivate *iface, IActiveScript *script) +{ + jsdisp_t *This = impl_from_IWineDispatchProxyCbPrivate(iface); + script_ctx_t *ctx = get_script_ctx(script); + dispex_prop_t *prop, *end; + HRESULT hres; + BOOL b; + + if(!ctx || !ctx->global) + return S_OK; + + if(This->ctx != ctx) { + if(ctx->version < SCRIPTLANGUAGEVERSION_ES5) { + /* Incompatible compat mode, so unlink the proxy */ + *This->proxy->lpVtbl->GetProxyFieldRef(This->proxy) = NULL; + iface->lpVtbl->Unlinked(iface, FALSE); + return S_OK; + } + + if(This->ref) { + list_remove(&This->entry); + list_add_tail(&ctx->objects, &This->entry); + } + script_release(This->ctx); + script_addref(ctx); + This->ctx = ctx; + + hres = jsdisp_change_prototype(This, ctx->object_prototype); + if(FAILED(hres)) + return hres; + } + + /* It's safe to repopulate the builtin proxy props now, since the mode is already locked */ + for(prop = This->props, end = prop + This->prop_cnt; prop < end; prop++) { + struct proxy_prop_info info; + + if(prop->type == PROP_PROXY) + prop->type = PROP_DELETED; + else { + prop->flags |= PROPF_CONFIGURABLE; + delete_prop(This, prop, &b); + } + + hres = This->proxy->lpVtbl->PropGetInfo(This->proxy, prop->name, FALSE, &info); + if(hres == S_OK) + alloc_proxy_prop(This, &info, &prop); + } + + return S_OK; +} + +static HRESULT WINAPI WineDispatchProxyCbPrivate_PropEnum(IWineDispatchProxyCbPrivate *iface, const WCHAR *name) +{ + jsdisp_t *This = impl_from_IWineDispatchProxyCbPrivate(iface); + dispex_prop_t *prop; + + return find_prop_name(This, string_hash(name), name, FALSE, &prop); +} + +static IWineDispatchProxyCbPrivateVtbl WineDispatchProxyCbPrivateVtbl = { + { DispatchEx_QueryInterface, DispatchEx_AddRef, DispatchEx_Release, @@ -2171,17 +2541,24 @@ static IDispatchExVtbl DispatchExVtbl = { DispatchEx_GetMemberName, DispatchEx_GetNextDispID, DispatchEx_GetNameSpaceParent + }, + + /* IWineDispatchProxyCbPrivate extension */ + WineDispatchProxyCbPrivate_InitProxy, + WineDispatchProxyCbPrivate_Unlinked, + WineDispatchProxyCbPrivate_HostUpdated, + WineDispatchProxyCbPrivate_PropEnum }; jsdisp_t *as_jsdisp(IDispatch *disp) { - assert(disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl); + assert(disp->lpVtbl == (IDispatchVtbl*)&WineDispatchProxyCbPrivateVtbl); return impl_from_IDispatchEx((IDispatchEx*)disp); } jsdisp_t *to_jsdisp(IDispatch *disp) { - return disp->lpVtbl == (IDispatchVtbl*)&DispatchExVtbl ? impl_from_IDispatchEx((IDispatchEx*)disp) : NULL; + return disp->lpVtbl == (IDispatchVtbl*)&WineDispatchProxyCbPrivateVtbl ? impl_from_IDispatchEx((IDispatchEx*)disp) : NULL; } HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *builtin_info, jsdisp_t *prototype) @@ -2194,7 +2571,7 @@ HRESULT init_dispex(jsdisp_t *dispex, script_ctx_t *ctx, const builtin_info_t *b TRACE("%p (%p)\n", dispex, prototype); - dispex->IDispatchEx_iface.lpVtbl = &DispatchExVtbl; + dispex->IDispatchEx_iface.lpVtbl = (const IDispatchExVtbl*)&WineDispatchProxyCbPrivateVtbl; dispex->ref = 1; dispex->builtin_info = builtin_info; dispex->extensible = TRUE; @@ -2247,12 +2624,85 @@ HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, jsd return S_OK; } +static const builtin_info_t proxy_dispex_info = { + JSCLASS_OBJECT, + NULL, + 0, NULL, + NULL, + NULL +}; + +HRESULT convert_to_proxy(script_ctx_t *ctx, jsval_t *val) +{ + IWineDispatchProxyCbPrivate **proxy_ref; + IWineDispatchProxyPrivate *proxy; + jsdisp_t *jsdisp; + IDispatch *obj; + HRESULT hres; + + if(ctx->version < SCRIPTLANGUAGEVERSION_ES5 || !val || !is_object_instance(*val)) + return S_OK; + obj = get_object(*val); + if(to_jsdisp(obj)) + return S_OK; + + if(FAILED(IDispatch_QueryInterface(obj, &IID_IWineDispatchProxyPrivate, (void**)&proxy)) || !proxy) + return S_OK; + if(!proxy->lpVtbl->HasProxy(proxy)) { + IDispatchEx_Release((IDispatchEx*)proxy); + return S_OK; + } + IDispatch_Release(obj); + + proxy_ref = proxy->lpVtbl->GetProxyFieldRef(proxy); + if(*proxy_ref) { + /* Re-acquire the proxy if it's an old dangling proxy */ + jsdisp = impl_from_IWineDispatchProxyCbPrivate(*proxy_ref); + assert(jsdisp->proxy == proxy); + + if(!jsdisp->ref++) + list_add_tail(&jsdisp->ctx->objects, &jsdisp->entry); + else + IDispatchEx_Release((IDispatchEx*)proxy); /* already held by jsdisp */ + + TRACE("re-acquired %p\n", jsdisp); + *val = jsval_obj(jsdisp); + return S_OK; + } + + if(!ctx->global) { + FIXME("Script is uninitialized?\n"); + IDispatchEx_Release((IDispatchEx*)proxy); + return E_UNEXPECTED; + } + + hres = create_dispex(ctx, &proxy_dispex_info, ctx->object_prototype, &jsdisp); + if(FAILED(hres)) { + IDispatchEx_Release((IDispatchEx*)proxy); + return hres; + } + *proxy_ref = (IWineDispatchProxyCbPrivate*)&jsdisp->IDispatchEx_iface; + jsdisp->proxy = proxy; + + *val = jsval_obj(jsdisp); + return S_OK; +} + void jsdisp_free(jsdisp_t *obj) { dispex_prop_t *prop; list_remove(&obj->entry); + /* If it's a proxy, stay alive and keep it associated with the disp, since + we can be re-acquired at some later point. When the underlying disp is + actually destroyed, it should unlink us and then we free it for real. */ + if(obj->proxy) { + list_init(&obj->entry); + IDispatchEx_Release((IDispatchEx*)obj->proxy); + return; + } + TRACE("(%p)\n", obj); for(prop = obj->props; prop < obj->props+obj->prop_cnt; prop++) { @@ -2282,12 +2732,21 @@ void jsdisp_free(jsdisp_t *obj) free(obj); } +void jsdisp_reacquire(jsdisp_t *jsdisp) +{ + list_add_tail(&jsdisp->ctx->objects, &jsdisp->entry); + if(jsdisp->proxy) + IDispatchEx_AddRef((IDispatchEx*)jsdisp->proxy); +} + #ifdef TRACE_REFCNT jsdisp_t *jsdisp_addref(jsdisp_t *jsdisp) { ULONG ref = ++jsdisp->ref; TRACE("(%p) ref=%ld\n", jsdisp, ref); + if(ref == 1) + jsdisp_reacquire(jsdisp); return jsdisp; } @@ -2336,7 +2795,7 @@ HRESULT init_dispex_from_constr(jsdisp_t *dispex, script_ctx_t *ctx, const built jsdisp_t *iface_to_jsdisp(IDispatch *iface) { - return iface->lpVtbl == (const IDispatchVtbl*)&DispatchExVtbl + return iface->lpVtbl == (const IDispatchVtbl*)&WineDispatchProxyCbPrivateVtbl ? jsdisp_addref( impl_from_IDispatchEx((IDispatchEx*)iface)) : NULL; } @@ -2381,6 +2840,8 @@ HRESULT jsdisp_call_value(jsdisp_t *jsfunc, jsval_t vthis, WORD flags, unsigned if(is_class(jsfunc, JSCLASS_FUNCTION)) { hres = Function_invoke(jsfunc, vthis, flags, argc, argv, r, caller); + }else if(jsfunc->proxy) { + hres = proxy_disp_call(jsfunc, vthis, DISPID_VALUE, flags, argc, argv, r, caller); }else { if(!jsfunc->builtin_info->call) { WARN("Not a function\n"); @@ -2393,6 +2854,8 @@ HRESULT jsdisp_call_value(jsdisp_t *jsfunc, jsval_t vthis, WORD flags, unsigned flags &= ~DISPATCH_JSCRIPT_INTERNAL_MASK; hres = jsfunc->builtin_info->call(jsfunc->ctx, vthis, flags, argc, argv, r); } + if(SUCCEEDED(hres)) + hres = convert_to_proxy(jsfunc->ctx, r); return hres; } @@ -2601,7 +3064,7 @@ HRESULT disp_call_value(script_ctx_t *ctx, IDispatch *disp, jsval_t vthis, WORD jsdisp_release(jsdisp); if(is_object_instance(vthis) && (ctx->version < SCRIPTLANGUAGEVERSION_ES5 || - ((jsdisp = to_jsdisp(get_object(vthis))) && is_class(jsdisp, JSCLASS_OBJECT)))) + ((jsdisp = to_jsdisp(get_object(vthis))) && is_class(jsdisp, JSCLASS_OBJECT) && !jsdisp->proxy))) jsthis = get_object(vthis); else jsthis = NULL; @@ -2866,7 +3329,7 @@ HRESULT jsdisp_delete_idx(jsdisp_t *obj, DWORD idx) if(FAILED(hres) || !prop) return hres; - hres = delete_prop(prop, &b); + hres = delete_prop(obj, prop, &b); if(FAILED(hres)) return hres; return b ? S_OK : JS_E_INVALID_ACTION; @@ -2884,7 +3347,7 @@ HRESULT disp_delete(IDispatch *disp, DISPID id, BOOL *ret) prop = get_prop(jsdisp, id); if(prop) - hres = delete_prop(prop, ret); + hres = delete_prop(jsdisp, prop, ret); else hres = DISP_E_MEMBERNOTFOUND; @@ -2924,6 +3387,9 @@ HRESULT jsdisp_next_prop(jsdisp_t *obj, DISPID id, enum jsdisp_enum_type enum_ty } for(iter = &obj->props[idx]; iter < obj->props + obj->prop_cnt; iter++) { + hres = fix_overridden_prop(obj, iter); + if(FAILED(hres)) + return hres; if(iter->type == PROP_DELETED) continue; if(enum_type != JSDISP_ENUM_ALL && iter->type == PROP_PROTREF) @@ -2965,7 +3431,7 @@ HRESULT disp_delete_name(script_ctx_t *ctx, IDispatch *disp, jsstr_t *name, BOOL }else { hres = find_prop_name(jsdisp, string_hash(ptr), ptr, FALSE, &prop); if(prop) { - hres = delete_prop(prop, ret); + hres = delete_prop(jsdisp, prop, ret); }else { *ret = TRUE; hres = S_OK; @@ -3041,6 +3507,7 @@ HRESULT jsdisp_get_own_property(jsdisp_t *obj, const WCHAR *name, BOOL flags_onl case PROP_BUILTIN: case PROP_JSVAL: case PROP_IDX: + case PROP_PROXY: desc->mask |= PROPF_WRITABLE; desc->explicit_value = TRUE; if(!flags_only) { @@ -3093,6 +3560,38 @@ HRESULT jsdisp_define_property(jsdisp_t *obj, const WCHAR *name, property_desc_t if(!prop && !(prop = alloc_prop(obj, name, PROP_DELETED, 0))) return E_OUTOFMEMORY; + if(obj->proxy && desc->explicit_value) { + struct proxy_prop_info info; + + info.name = name; + hres = obj->proxy->lpVtbl->PropDefineOverride(obj->proxy, &info); + if(hres != S_FALSE) { + dispex_prop_t bak = *prop; + if(FAILED(hres)) + return hres; + hres = alloc_proxy_prop(obj, &info, &prop); + if(SUCCEEDED(hres)) { + hres = prop_put(obj, prop, desc->value, &obj->ctx->jscaller->IServiceProvider_iface); + if(SUCCEEDED(hres)) { + switch(bak.type) { + case PROP_JSVAL: + jsval_release(bak.u.val); + break; + case PROP_ACCESSOR: + if(bak.u.accessor.getter) jsdisp_release(bak.u.accessor.getter); + if(bak.u.accessor.setter) jsdisp_release(bak.u.accessor.setter); + break; + default: + break; + } + return S_OK; + } + } + *prop = bak; + return hres; + } + } + if(prop->type == PROP_DELETED || prop->type == PROP_PROTREF) { prop->flags = desc->flags; if(desc->explicit_getter || desc->explicit_setter) { diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index 459d1e833df..3109b1391e8 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -547,15 +547,24 @@ static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, BOOL *ret) { IObjectIdentity *identity; IUnknown *unk1, *unk2; + jsdisp_t *jsdisp; HRESULT hres; - if(disp1 == disp2) { - *ret = TRUE; + if(!disp1 || !disp2) { + *ret = (disp1 == disp2); return S_OK; } - if(!disp1 || !disp2) { - *ret = FALSE; + jsdisp = to_jsdisp(disp1); + if(jsdisp && jsdisp->proxy) + disp1 = (IDispatch*)jsdisp->proxy; + + jsdisp = to_jsdisp(disp2); + if(jsdisp && jsdisp->proxy) + disp2 = (IDispatch*)jsdisp->proxy; + + if(disp1 == disp2) { + *ret = TRUE; return S_OK; } diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index b7b48840ab6..c743d0b23a8 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -55,6 +55,12 @@ typedef struct { const WCHAR *name; } NativeFunction; +typedef struct { + FunctionInstance function; + struct proxy_func_invoker func; + const WCHAR *name; +} ProxyFunction; + typedef struct { FunctionInstance function; FunctionInstance *target; @@ -761,6 +767,129 @@ HRESULT create_builtin_constructor(script_ctx_t *ctx, builtin_invoke_t value_pro return S_OK; } +static HRESULT ProxyFunction_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags, + unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) +{ + ProxyFunction *function = (ProxyFunction*)func; + IDispatch *this_obj, *converted = NULL; + DISPPARAMS dp = { 0 }; + EXCEPINFO ei = { 0 }; + VARIANT buf[6], ret; + jsdisp_t *jsdisp; + HRESULT hres; + unsigned i; + + if(flags & DISPATCH_CONSTRUCT) + return E_UNEXPECTED; + + if(argc > function->function.length) + argc = function->function.length; + dp.cArgs = argc; + + if(argc <= ARRAY_SIZE(buf)) + dp.rgvarg = buf; + else if(!(dp.rgvarg = malloc(argc * sizeof(*dp.rgvarg)))) + return E_OUTOFMEMORY; + + for(i = 0; i < argc; i++) { + hres = jsval_to_variant(argv[i], &dp.rgvarg[argc - i - 1]); + if(FAILED(hres)) + goto cleanup; + } + + if(is_undefined(vthis) || is_null(vthis)) + this_obj = lookup_global_host(ctx); + else { + hres = to_object(ctx, vthis, &converted); + if(FAILED(hres)) + goto cleanup; + this_obj = converted; + } + + jsdisp = to_jsdisp(this_obj); + if(jsdisp && jsdisp->proxy) + this_obj = (IDispatch*)jsdisp->proxy; + + V_VT(&ret) = VT_EMPTY; + hres = function->func.invoke(this_obj, function->func.context, &dp, r ? &ret : NULL, &ei, caller); + if(converted) + IDispatch_Release(converted); + + if(hres == DISP_E_EXCEPTION) + disp_fill_exception(ctx, &ei); + else if(SUCCEEDED(hres) && r) { + hres = variant_to_jsval(ctx, &ret, r); + VariantClear(&ret); + } + +cleanup: + while(i) + VariantClear(&dp.rgvarg[argc - i--]); + if(dp.rgvarg != buf) + free(dp.rgvarg); + return hres; +} + +static HRESULT ProxyFunction_toString(FunctionInstance *func, jsstr_t **ret) +{ + ProxyFunction *function = (ProxyFunction*)func; + return native_code_toString(function->name, ret); +} + +static function_code_t *ProxyFunction_get_code(FunctionInstance *func) +{ + return NULL; +} + +static void ProxyFunction_destructor(FunctionInstance *func) +{ +} + +static const function_vtbl_t ProxyFunctionVtbl = { + ProxyFunction_call, + ProxyFunction_toString, + ProxyFunction_get_code, + ProxyFunction_destructor, + no_gc_traverse +}; + +HRESULT create_proxy_functions(jsdisp_t *jsdisp, const struct proxy_prop_info *info, jsdisp_t **funcs) +{ + ProxyFunction *function; + HRESULT hres; + + /* Method or Getter */ + hres = create_function(jsdisp->ctx, NULL, &ProxyFunctionVtbl, sizeof(ProxyFunction), + (info->flags & PROPF_METHOD) ? info->flags : PROPF_METHOD, FALSE, + NULL, (void**)&function); + if(FAILED(hres)) + return hres; + function->func = info->func[0]; + function->name = info->name; + funcs[0] = &function->function.dispex; + funcs[1] = NULL; + + /* Setter */ + if(info->func[1].invoke) { + hres = create_function(jsdisp->ctx, NULL, &ProxyFunctionVtbl, sizeof(ProxyFunction), + PROPF_METHOD|1, FALSE, NULL, (void**)&function); + if(FAILED(hres)) { + jsdisp_release(funcs[0]); + return hres; + } + function->func = info->func[1]; + function->name = info->name; + funcs[1] = &function->function.dispex; + } + + return S_OK; +} + +BOOL is_proxy_func(jsdisp_t *jsdisp) +{ + return jsdisp && is_class(jsdisp, JSCLASS_FUNCTION) && function_from_jsdisp(jsdisp)->vtbl == &ProxyFunctionVtbl; +} + /* * Create the actual prototype on demand, since it is a circular ref, which prevents the vast * majority of functions from being released quickly, leading to unnecessary scope detach. @@ -827,8 +956,11 @@ static HRESULT InterpretedFunction_call(script_ctx_t *ctx, FunctionInstance *fun return hres; this_obj = to_disp(new_obj); }else if(is_object_instance(vthis)) { + IDispatch_AddRef(get_object(vthis)); + hres = convert_to_proxy(ctx, &vthis); + if(FAILED(hres)) + return hres; this_obj = get_object(vthis); - IDispatch_AddRef(this_obj); }else if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5 && !is_undefined(vthis) && !is_null(vthis)) { hres = to_object(ctx, vthis, &this_obj); if(FAILED(hres)) diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index 401f6ca85b0..33cdf9ced1d 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -1450,3 +1450,8 @@ HRESULT create_jscript_object(BOOL is_encode, REFIID riid, void **ppv) IActiveScript_Release(&ret->IActiveScript_iface); return hres; } + +script_ctx_t *get_script_ctx(IActiveScript *script) +{ + return (script->lpVtbl == &JScriptVtbl) ? impl_from_IActiveScript(script)->ctx : NULL; +} diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index c01ca07bd8e..f59fa6c791c 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -46,6 +46,64 @@ #define SCRIPTLANGUAGEVERSION_ES5 0x102 #define SCRIPTLANGUAGEVERSION_ES6 0x103 +/* + * These are Wine jscript extensions, used for mshtml objects so they act like JS objects. + * Both extend IDispatchEx. IWineDispatchProxyCbPrivate is always available on jscript side. + * + * NOTE: Keep in sync with mshtml_private.h in mshtml.dll + */ +DEFINE_GUID(IID_IWineDispatchProxyPrivate, 0xd359f2fe,0x5531,0x741b,0xa4,0x1a,0x5c,0xf9,0x2e,0xdc,0x97,0x1b); +typedef struct _IWineDispatchProxyPrivate IWineDispatchProxyPrivate; +typedef struct _IWineDispatchProxyCbPrivate IWineDispatchProxyCbPrivate; + +struct proxy_func_invoker +{ + HRESULT (STDMETHODCALLTYPE *invoke)(IDispatch*,void*,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*); + void *context; +}; + +struct proxy_prop_info +{ + struct proxy_func_invoker func[2]; + const WCHAR *name; + DISPID dispid; + unsigned flags; +}; + +typedef struct { + IDispatchExVtbl dispex; + IWineDispatchProxyCbPrivate** (STDMETHODCALLTYPE *GetProxyFieldRef)(IWineDispatchProxyPrivate *This); + BOOL (STDMETHODCALLTYPE *HasProxy)(IWineDispatchProxyPrivate *This); + HRESULT (STDMETHODCALLTYPE *PropFixOverride)(IWineDispatchProxyPrivate *This, struct proxy_prop_info *info); + HRESULT (STDMETHODCALLTYPE *PropOverride)(IWineDispatchProxyPrivate *This, const WCHAR *name, VARIANT *value); + HRESULT (STDMETHODCALLTYPE *PropDefineOverride)(IWineDispatchProxyPrivate *This, struct proxy_prop_info *info); + HRESULT (STDMETHODCALLTYPE *PropGetInfo)(IWineDispatchProxyPrivate *This, const WCHAR *name, BOOL case_insens, struct proxy_prop_info *info); + HRESULT (STDMETHODCALLTYPE *PropInvoke)(IWineDispatchProxyPrivate *This, IDispatch *this_obj, DISPID id, LCID lcid, + DWORD flags, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller); + HRESULT (STDMETHODCALLTYPE *PropDelete)(IWineDispatchProxyPrivate *This, DISPID id); + HRESULT (STDMETHODCALLTYPE *PropEnum)(IWineDispatchProxyPrivate *This); + HRESULT (STDMETHODCALLTYPE *ToString)(IWineDispatchProxyPrivate *This, BSTR *string); + BOOL (STDMETHODCALLTYPE *CanGC)(IWineDispatchProxyPrivate *This); +} IWineDispatchProxyPrivateVtbl; + +typedef struct { + IDispatchExVtbl dispex; + HRESULT (STDMETHODCALLTYPE *InitProxy)(IWineDispatchProxyCbPrivate *This, IDispatch *obj); + void (STDMETHODCALLTYPE *Unlinked)(IWineDispatchProxyCbPrivate *This, BOOL persist); + HRESULT (STDMETHODCALLTYPE *HostUpdated)(IWineDispatchProxyCbPrivate *This, IActiveScript *script); + HRESULT (STDMETHODCALLTYPE *PropEnum)(IWineDispatchProxyCbPrivate *This, const WCHAR *name); +} IWineDispatchProxyCbPrivateVtbl; + +struct _IWineDispatchProxyPrivate { + const IWineDispatchProxyPrivateVtbl *lpVtbl; +}; + +struct _IWineDispatchProxyCbPrivate { + const IWineDispatchProxyCbPrivateVtbl *lpVtbl; +}; + + + typedef struct _jsval_t jsval_t; typedef struct _jsstr_t jsstr_t; typedef struct _jsexcept_t jsexcept_t; @@ -74,6 +132,7 @@ typedef struct jsdisp_t jsdisp_t; extern HINSTANCE jscript_hinstance DECLSPEC_HIDDEN; HRESULT get_dispatch_typeinfo(ITypeInfo**) DECLSPEC_HIDDEN; +/* NOTE: Keep in sync with mshtml_private.h in mshtml.dll */ #define PROPF_ARGMASK 0x00ff #define PROPF_METHOD 0x0100 #define PROPF_CONSTR 0x0200 @@ -205,6 +264,7 @@ struct jsdisp_t { script_ctx_t *ctx; jsdisp_t *prototype; + IWineDispatchProxyPrivate *proxy; const builtin_info_t *builtin_info; struct list entry; @@ -217,6 +277,7 @@ static inline IDispatch *to_disp(jsdisp_t *jsdisp) jsdisp_t *as_jsdisp(IDispatch*) DECLSPEC_HIDDEN; jsdisp_t *to_jsdisp(IDispatch*) DECLSPEC_HIDDEN; +void jsdisp_reacquire(jsdisp_t*) DECLSPEC_HIDDEN; void jsdisp_free(jsdisp_t*) DECLSPEC_HIDDEN; #ifndef TRACE_REFCNT @@ -229,7 +290,8 @@ void jsdisp_free(jsdisp_t*) DECLSPEC_HIDDEN; */ static inline jsdisp_t *jsdisp_addref(jsdisp_t *jsdisp) { - jsdisp->ref++; + if(!jsdisp->ref++) + jsdisp_reacquire(jsdisp); return jsdisp; } @@ -255,6 +317,7 @@ enum jsdisp_enum_type { HRESULT create_dispex(script_ctx_t*,const builtin_info_t*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT init_dispex(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*) DECLSPEC_HIDDEN; HRESULT init_dispex_from_constr(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*) DECLSPEC_HIDDEN; +HRESULT convert_to_proxy(script_ctx_t*,jsval_t*) DECLSPEC_HIDDEN; void disp_fill_exception(script_ctx_t*,EXCEPINFO*) DECLSPEC_HIDDEN; HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; @@ -289,6 +352,8 @@ HRESULT create_builtin_function(script_ctx_t*,builtin_invoke_t,const WCHAR*,cons jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT create_builtin_constructor(script_ctx_t*,builtin_invoke_t,const WCHAR*,const builtin_info_t*,DWORD, jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; +HRESULT create_proxy_functions(jsdisp_t*,const struct proxy_prop_info*,jsdisp_t**) DECLSPEC_HIDDEN; +BOOL is_proxy_func(jsdisp_t*) DECLSPEC_HIDDEN; HRESULT Function_invoke(jsdisp_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*,IServiceProvider*) DECLSPEC_HIDDEN; HRESULT Function_value(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; @@ -582,6 +647,7 @@ static inline BOOL is_jscript_error(HRESULT hres) const char *debugstr_jsval(const jsval_t) DECLSPEC_HIDDEN; HRESULT create_jscript_object(BOOL,REFIID,void**) DECLSPEC_HIDDEN; +script_ctx_t *get_script_ctx(IActiveScript*) DECLSPEC_HIDDEN; extern LONG module_ref DECLSPEC_HIDDEN; diff --git a/dlls/jscript/jsutils.c b/dlls/jscript/jsutils.c index 9309b457a59..39c8a1da9a5 100644 --- a/dlls/jscript/jsutils.c +++ b/dlls/jscript/jsutils.c @@ -286,7 +286,7 @@ HRESULT variant_to_jsval(script_ctx_t *ctx, VARIANT *var, jsval_t *r) } IDispatch_AddRef(V_DISPATCH(var)); *r = jsval_disp(V_DISPATCH(var)); - return S_OK; + return convert_to_proxy(ctx, r); } case VT_I1: *r = jsval_number(V_I1(var)); @@ -330,7 +330,7 @@ HRESULT variant_to_jsval(script_ctx_t *ctx, VARIANT *var, jsval_t *r) hres = IUnknown_QueryInterface(V_UNKNOWN(var), &IID_IDispatch, (void**)&disp); if(SUCCEEDED(hres)) { *r = jsval_disp(disp); - return S_OK; + return convert_to_proxy(ctx, r); } }else { *r = ctx->html_mode ? jsval_null() : jsval_null_disp(); @@ -344,6 +344,9 @@ HRESULT variant_to_jsval(script_ctx_t *ctx, VARIANT *var, jsval_t *r) HRESULT jsval_to_variant(jsval_t val, VARIANT *retv) { + jsdisp_t *jsdisp; + IDispatch *disp; + switch(jsval_type(val)) { case JSV_UNDEFINED: V_VT(retv) = VT_EMPTY; @@ -357,9 +360,14 @@ HRESULT jsval_to_variant(jsval_t val, VARIANT *retv) V_VT(retv) = VT_NULL; return S_OK; case JSV_OBJECT: + disp = get_object(val); + jsdisp = to_jsdisp(disp); + if(jsdisp && jsdisp->proxy) + disp = (IDispatch*)jsdisp->proxy; + + IDispatch_AddRef(disp); V_VT(retv) = VT_DISPATCH; - V_DISPATCH(retv) = get_object(val); - IDispatch_AddRef(get_object(val)); + V_DISPATCH(retv) = disp; return S_OK; case JSV_STRING: V_VT(retv) = VT_BSTR; diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index ff818bdb87b..8a2399d7ab3 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -29,7 +29,9 @@ static HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns { jsdisp_t *jsdisp; const WCHAR *str; + BSTR bstr = NULL; IDispatch *disp; + jsstr_t *ret; HRESULT hres; /* Keep in sync with jsclass_t enum */ @@ -67,6 +69,9 @@ static HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns TRACE("\n"); + if(!r) + return S_OK; + if(is_undefined(vthis) || is_null(vthis)) { if(ctx->version < SCRIPTLANGUAGEVERSION_ES5) str = L"[object Object]"; @@ -82,6 +87,9 @@ static HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns jsdisp = to_jsdisp(disp); if(!jsdisp) { str = L"[object Object]"; + }else if(jsdisp->proxy) { + hres = jsdisp->proxy->lpVtbl->ToString(jsdisp->proxy, &bstr); + str = bstr; }else if(names[jsdisp->builtin_info->class]) { str = names[jsdisp->builtin_info->class]; }else { @@ -94,13 +102,11 @@ static HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns return hres; set_output: - if(r) { - jsstr_t *ret; - ret = jsstr_alloc(str); - if(!ret) - return E_OUTOFMEMORY; - *r = jsval_string(ret); - } + ret = jsstr_alloc(str); + SysFreeString(bstr); + if(!ret) + return E_OUTOFMEMORY; + *r = jsval_string(ret); return S_OK; } diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 83bd7593af9..6667c753ab4 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -25,6 +25,7 @@ #include "hlink.h" #include "perhist.h" #include "dispex.h" +#include "activscp.h" #include "objsafe.h" #include "htiframe.h" #include "tlogstg.h" @@ -43,6 +44,68 @@ #include +/* NOTE: Keep in sync with jscript.h in jscript.dll */ +DEFINE_GUID(IID_IWineDispatchProxyPrivate, 0xd359f2fe,0x5531,0x741b,0xa4,0x1a,0x5c,0xf9,0x2e,0xdc,0x97,0x1b); +typedef struct _IWineDispatchProxyPrivate IWineDispatchProxyPrivate; +typedef struct _IWineDispatchProxyCbPrivate IWineDispatchProxyCbPrivate; + +struct proxy_func_invoker +{ + HRESULT (STDMETHODCALLTYPE *invoke)(IDispatch*,void*,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*); + void *context; +}; + +struct proxy_prop_info +{ + struct proxy_func_invoker func[2]; + const WCHAR *name; + DISPID dispid; + unsigned flags; +}; + +typedef struct { + IDispatchExVtbl dispex; + IWineDispatchProxyCbPrivate** (STDMETHODCALLTYPE *GetProxyFieldRef)(IWineDispatchProxyPrivate *This); + BOOL (STDMETHODCALLTYPE *HasProxy)(IWineDispatchProxyPrivate *This); + HRESULT (STDMETHODCALLTYPE *PropFixOverride)(IWineDispatchProxyPrivate *This, struct proxy_prop_info *info); + HRESULT (STDMETHODCALLTYPE *PropOverride)(IWineDispatchProxyPrivate *This, const WCHAR *name, VARIANT *value); + HRESULT (STDMETHODCALLTYPE *PropDefineOverride)(IWineDispatchProxyPrivate *This, struct proxy_prop_info *info); + HRESULT (STDMETHODCALLTYPE *PropGetInfo)(IWineDispatchProxyPrivate *This, const WCHAR *name, BOOL case_insens, struct proxy_prop_info *info); + HRESULT (STDMETHODCALLTYPE *PropInvoke)(IWineDispatchProxyPrivate *This, IDispatch *this_obj, DISPID id, LCID lcid, + DWORD flags, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller); + HRESULT (STDMETHODCALLTYPE *PropDelete)(IWineDispatchProxyPrivate *This, DISPID id); + HRESULT (STDMETHODCALLTYPE *PropEnum)(IWineDispatchProxyPrivate *This); + HRESULT (STDMETHODCALLTYPE *ToString)(IWineDispatchProxyPrivate *This, BSTR *string); + BOOL (STDMETHODCALLTYPE *CanGC)(IWineDispatchProxyPrivate *This); +} IWineDispatchProxyPrivateVtbl; + +typedef struct { + IDispatchExVtbl dispex; + HRESULT (STDMETHODCALLTYPE *InitProxy)(IWineDispatchProxyCbPrivate *This, IDispatch *obj); + void (STDMETHODCALLTYPE *Unlinked)(IWineDispatchProxyCbPrivate *This, BOOL persist); + HRESULT (STDMETHODCALLTYPE *HostUpdated)(IWineDispatchProxyCbPrivate *This, IActiveScript *script); + HRESULT (STDMETHODCALLTYPE *PropEnum)(IWineDispatchProxyCbPrivate *This, const WCHAR *name); +} IWineDispatchProxyCbPrivateVtbl; + +struct _IWineDispatchProxyPrivate { + const IWineDispatchProxyPrivateVtbl *lpVtbl; +}; + +struct _IWineDispatchProxyCbPrivate { + const IWineDispatchProxyCbPrivateVtbl *lpVtbl; +}; + +#define PROPF_ARGMASK 0x00ff +#define PROPF_METHOD 0x0100 +#define PROPF_CONSTR 0x0200 + +#define PROPF_ENUMERABLE 0x0400 +#define PROPF_WRITABLE 0x0800 +#define PROPF_CONFIGURABLE 0x1000 +#define PROPF_ALL (PROPF_ENUMERABLE | PROPF_WRITABLE | PROPF_CONFIGURABLE) + + + #define NS_ERROR_GENERATE_FAILURE(module,code) \ ((nsresult) (((UINT32)(1u<<31)) | ((UINT32)(module+0x45)<<16) | ((UINT32)(code)))) #define NS_ERROR_GENERATE_SUCCESS(module,code) \ From 1cd08ad0eb76f87e6212bf70bb3d10d67a2a9bd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:01 +0200 Subject: [PATCH 0868/2777] jscript: Convert named items to proxies when available. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/jscript.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index 33cdf9ced1d..b59814c215f 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -140,9 +140,11 @@ static void release_named_item_script_obj(named_item_t *item) item->script_obj = NULL; } -static HRESULT retrieve_named_item_disp(IActiveScriptSite *site, named_item_t *item) +static HRESULT retrieve_named_item_disp(script_ctx_t *ctx, IActiveScriptSite *site, named_item_t *item) { + IDispatch *disp; IUnknown *unk; + jsval_t val; HRESULT hr; if(!site) @@ -154,13 +156,19 @@ static HRESULT retrieve_named_item_disp(IActiveScriptSite *site, named_item_t *i return hr; } - hr = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp); + hr = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&disp); IUnknown_Release(unk); if(FAILED(hr)) { WARN("object does not implement IDispatch\n"); return hr; } + val = jsval_disp(disp); + hr = convert_to_proxy(ctx, &val); + if(FAILED(hr)) + return hr; + item->disp = get_object(val); + return S_OK; } @@ -177,7 +185,7 @@ named_item_t *lookup_named_item(script_ctx_t *ctx, const WCHAR *item_name, unsig } if(!item->disp && (flags || !(item->flags & SCRIPTITEM_CODEONLY))) { - hr = retrieve_named_item_disp(ctx->site, item); + hr = retrieve_named_item_disp(ctx, ctx->site, item); if(FAILED(hr)) continue; } @@ -770,7 +778,7 @@ static HRESULT WINAPI JScript_SetScriptSite(IActiveScript *iface, { if(!item->disp) { - hres = retrieve_named_item_disp(pass, item); + hres = retrieve_named_item_disp(This->ctx, pass, item); if(FAILED(hres)) return hres; } @@ -894,6 +902,7 @@ static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface, if(dwFlags & SCRIPTITEM_GLOBALMEMBERS) { IUnknown *unk; + jsval_t val; hres = IActiveScriptSite_GetItemInfo(This->site, pstrName, SCRIPTINFO_IUNKNOWN, &unk, NULL); if(FAILED(hres)) { @@ -907,6 +916,12 @@ static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface, WARN("object does not implement IDispatch\n"); return hres; } + + val = jsval_disp(disp); + hres = convert_to_proxy(This->ctx, &val); + if(FAILED(hres)) + return hres; + disp = get_object(val); } item = malloc(sizeof(*item)); From c8dbd0850b8e239128d263ccace52335d7526f65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:01 +0200 Subject: [PATCH 0869/2777] mshtml: Implement the private jscript proxy interface. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This implements the internal private interface for mshtml objects, so they can be used as JS proxy objects from jscript. Note that the association from these objects back to the JS proxy objects does not hold a ref to them, but only a weak ref, to prevent circular references. However, because the associated jsdisp remains alive even if it's dangling with a refcount of 0, the pointers are always valid until Unlinked is called on them via the callback, which invalidates them. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/dispex.c | 422 ++++++++++++++++++++++++++++-- dlls/mshtml/htmldoc.c | 195 +++++++++++++- dlls/mshtml/htmlelem.c | 1 + dlls/mshtml/htmlstorage.c | 24 ++ dlls/mshtml/htmlstyle.c | 15 +- dlls/mshtml/htmlwindow.c | 269 ++++++++++++++++++- dlls/mshtml/mshtml_private.h | 4 + dlls/mshtml/mutation.c | 30 ++- dlls/mshtml/script.c | 51 +++- dlls/mshtml/tests/documentmode.js | 9 +- dlls/mshtml/tests/dom.js | 132 ++++++++++ dlls/mshtml/tests/es5.js | 2 - dlls/mshtml/tests/events.c | 24 +- dlls/mshtml/tests/xhr.js | 1 - 14 files changed, 1116 insertions(+), 63 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index ce662dac57e..d90c272a4ab 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -126,7 +126,6 @@ PRIVATE_TID_LIST #undef XDIID }; -static inline DispatchEx *get_dispex_for_hook(IUnknown*); static HRESULT invoke_builtin_function(IDispatch*,func_info_t*,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*); static HRESULT load_typelib(void) @@ -1211,7 +1210,7 @@ static HRESULT get_builtin_func(dispex_data_t *data, DISPID id, func_info_t **re return DISP_E_MEMBERNOTFOUND; } -static HRESULT get_builtin_id(DispatchEx *This, BSTR name, DWORD grfdex, DISPID *ret) +HRESULT dispex_get_builtin_id(DispatchEx *This, BSTR name, DWORD grfdex, DISPID *ret) { int min, max, n, c; @@ -1247,6 +1246,22 @@ static HRESULT get_builtin_id(DispatchEx *This, BSTR name, DWORD grfdex, DISPID return DISP_E_UNKNOWNNAME; } +static inline DispatchEx *get_dispex_for_hook(IUnknown *iface) +{ + IWineDispatchProxyPrivate *itf; + DispatchEx *dispex; + + if(FAILED(IUnknown_QueryInterface(iface, &IID_IWineDispatchProxyPrivate, (void**)&itf)) || !itf) + return NULL; + dispex = CONTAINING_RECORD(itf->lpVtbl->GetProxyFieldRef(itf), DispatchEx, proxy); + + /* The dispex and the proxy interface requested might be different (e.g. inner vs outer windows) */ + IDispatchEx_AddRef(&dispex->IDispatchEx_iface); + IDispatchEx_Release((IDispatchEx*)itf); + + return dispex; +} + HRESULT change_type(VARIANT *dst, VARIANT *src, VARTYPE vt, IServiceProvider *caller) { V_VT(dst) = VT_EMPTY; @@ -1778,6 +1793,88 @@ static BOOL ensure_real_info(DispatchEx *dispex) return dispex->info != NULL; } +static HRESULT proxy_get_dispid(DispatchEx *dispex, const WCHAR *name, BOOL case_insens, DISPID *id) +{ + DWORD grfdex = case_insens ? fdexNameCaseInsensitive : fdexNameCaseSensitive; + dynamic_prop_t *dprop; + HRESULT hres; + BSTR bstr; + + if(!ensure_real_info(dispex) || !(bstr = SysAllocString(name))) + return E_OUTOFMEMORY; + + /* FIXME: move builtins to the prototype */ + hres = dispex_get_builtin_id(dispex, bstr, grfdex, id); + SysFreeString(bstr); + if(hres != DISP_E_UNKNOWNNAME) + return hres; + + hres = get_dynamic_prop(dispex, name, grfdex, &dprop); + if(FAILED(hres)) + return hres; + + *id = DISPID_DYNPROP_0 + (dprop - dispex->dynamic_data->props); + return S_OK; +} + +static HRESULT WINAPI proxy_func_invoke(IDispatch *this_obj, void *context, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + func_info_t *func = context; + return invoke_builtin_function(this_obj, func, dp, res, ei, caller); +} + +static HRESULT WINAPI proxy_getter_invoke(IDispatch *this_obj, void *context, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + func_info_t *func = context; + DispatchEx *dispex; + IUnknown *iface; + HRESULT hres; + + hres = IDispatch_QueryInterface(this_obj, tid_ids[func->tid], (void**)&iface); + if(FAILED(hres) || !iface) + return E_UNEXPECTED; + + if(func->hook && (dispex = get_dispex_for_hook(iface))) { + hres = func->hook(dispex, DISPATCH_PROPERTYGET, dp, res, ei, caller); + IDispatchEx_Release(&dispex->IDispatchEx_iface); + if(hres != S_FALSE) + goto done; + } + hres = builtin_propget(iface, func, dp, res); + +done: + IUnknown_Release(iface); + return hres; +} + +static HRESULT WINAPI proxy_setter_invoke(IDispatch *this_obj, void *context, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + static DISPID propput_dispid = DISPID_PROPERTYPUT; + func_info_t *func = context; + DispatchEx *dispex; + IUnknown *iface; + HRESULT hres; + + dp->cNamedArgs = 1; + dp->rgdispidNamedArgs = &propput_dispid; + + hres = IDispatch_QueryInterface(this_obj, tid_ids[func->tid], (void**)&iface); + if(FAILED(hres) || !iface) + return E_UNEXPECTED; + + if(func->hook && (dispex = get_dispex_for_hook(iface))) { + hres = func->hook(dispex, DISPATCH_PROPERTYPUT, dp, res, ei, caller); + IDispatchEx_Release(&dispex->IDispatchEx_iface); + if(hres != S_FALSE) + goto done; + } + hres = builtin_propput(NULL, iface, func, dp, caller); + +done: + IUnknown_Release(iface); + return hres; +} + static inline DispatchEx *impl_from_IDispatchEx(IDispatchEx *iface) { return CONTAINING_RECORD(iface, DispatchEx, IDispatchEx_iface); @@ -1837,6 +1934,10 @@ static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid, DispatchEx *This = impl_from_IDispatchEx(iface); HRESULT hres = S_OK; + if(This->proxy) + return IDispatchEx_GetIDsOfNames((IDispatchEx*)This->proxy, riid, rgszNames, + cNames, lcid, rgDispId); + TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); @@ -1853,6 +1954,10 @@ static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember, { DispatchEx *This = impl_from_IDispatchEx(iface); + if(This->proxy && dispIdMember >= 0) + return IDispatchEx_Invoke((IDispatchEx*)This->proxy, dispIdMember, riid, lcid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); + TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); @@ -1865,6 +1970,9 @@ static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DW dynamic_prop_t *dprop; HRESULT hres; + if(This->proxy) + return IDispatchEx_GetDispID((IDispatchEx*)This->proxy, bstrName, grfdex, pid); + TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(bstrName), grfdex, pid); if(grfdex & ~(fdexNameCaseSensitive|fdexNameCaseInsensitive|fdexNameEnsure|fdexNameImplicit|FDEX_VERSION_MASK)) @@ -1873,7 +1981,7 @@ static HRESULT WINAPI DispatchEx_GetDispID(IDispatchEx *iface, BSTR bstrName, DW if(!ensure_real_info(This)) return E_OUTOFMEMORY; - hres = get_builtin_id(This, bstrName, grfdex, pid); + hres = dispex_get_builtin_id(This, bstrName, grfdex, pid); if(hres != DISP_E_UNKNOWNNAME) return hres; @@ -1890,6 +1998,9 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc { DispatchEx *This = impl_from_IDispatchEx(iface); + if(This->proxy && id >= 0) + return IDispatchEx_InvokeEx((IDispatchEx*)This->proxy, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); + TRACE("(%p)->(%lx %lx %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); return dispex_invoke(This, (IDispatch*)iface, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller); @@ -1901,14 +2012,15 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR nam DISPID id; HRESULT hres; + if(This->proxy) + return IDispatchEx_DeleteMemberByName((IDispatchEx*)This->proxy, name, grfdex); + TRACE("(%p)->(%s %lx)\n", This, debugstr_w(name), grfdex); hres = IDispatchEx_GetDispID(&This->IDispatchEx_iface, name, grfdex & ~fdexNameEnsure, &id); if(FAILED(hres)) { - compat_mode_t compat_mode = dispex_compat_mode(This); TRACE("property %s not found\n", debugstr_w(name)); - return compat_mode < COMPAT_MODE_IE8 ? E_NOTIMPL : - compat_mode < COMPAT_MODE_IE9 ? hres : S_OK; + return dispex_compat_mode(This) < COMPAT_MODE_IE8 ? E_NOTIMPL : hres; } return dispex_delete_prop(This, id); @@ -1918,6 +2030,9 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID { DispatchEx *This = impl_from_IDispatchEx(iface); + if(This->proxy && id >= 0) + return IDispatchEx_DeleteMemberByDispID((IDispatchEx*)This->proxy, id); + TRACE("(%p)->(%lx)\n", This, id); return dispex_delete_prop(This, id); @@ -1926,6 +2041,10 @@ static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex) { DispatchEx *This = impl_from_IDispatchEx(iface); + + if(This->proxy && id >= 0) + return IDispatchEx_GetMemberProperties((IDispatchEx*)This->proxy, id, grfdexFetch, pgrfdex); + FIXME("(%p)->(%lx %lx %p)\n", This, id, grfdexFetch, pgrfdex); return E_NOTIMPL; } @@ -1936,6 +2055,9 @@ static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BS func_info_t *func; HRESULT hres; + if(This->proxy && id >= 0) + return IDispatchEx_GetMemberName((IDispatchEx*)This->proxy, id, pbstrName); + TRACE("(%p)->(%lx %p)\n", This, id, pbstrName); if(!ensure_real_info(This)) @@ -1991,6 +2113,9 @@ static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, func_info_t *func; HRESULT hres; + if(This->proxy) + return IDispatchEx_GetNextDispID((IDispatchEx*)This->proxy, grfdex, id, pid); + TRACE("(%p)->(%lx %lx %p)\n", This, grfdex, id, pid); if(!ensure_real_info(This)) @@ -2046,7 +2171,226 @@ static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown return E_NOTIMPL; } -static IDispatchExVtbl DispatchExVtbl = { +static inline DispatchEx *impl_from_IWineDispatchProxyPrivate(IWineDispatchProxyPrivate *iface) +{ + return impl_from_IDispatchEx((IDispatchEx*)iface); +} + +static IWineDispatchProxyCbPrivate** WINAPI WineDispatchProxyPrivate_GetProxyFieldRef(IWineDispatchProxyPrivate *iface) +{ + DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); + return &This->proxy; +} + +static BOOL WINAPI WineDispatchProxyPrivate_HasProxy(IWineDispatchProxyPrivate *iface) +{ + DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); + return This->info->compat_mode >= COMPAT_MODE_IE9; +} + +static HRESULT WINAPI WineDispatchProxyPrivate_PropFixOverride(IWineDispatchProxyPrivate *iface, struct proxy_prop_info *info) +{ + DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); + HRESULT hres; + + if(!This->info->desc->vtbl || !This->info->desc->vtbl->override) + return S_FALSE; + + /* We only care about custom props, as those are the only ones which can mismatch. + Some objects with custom props (such as the Storage objects) can be out of sync, + because the underlying storage is changed asynchronously (e.g. the backing file + in localStorage), so the prop may not exist at this point, even if it did before. */ + if(info->dispid != DISPID_UNKNOWN && !is_custom_dispid(info->dispid)) + return S_FALSE; + + hres = This->info->desc->vtbl->get_dispid(This, (WCHAR*)info->name, fdexNameCaseSensitive, &info->dispid); + if(hres == DISP_E_UNKNOWNNAME) { + if(info->dispid == DISPID_UNKNOWN) + return S_FALSE; + info->dispid = DISPID_UNKNOWN; + return S_OK; + } + if(FAILED(hres)) + return hres; + info->flags = PROPF_WRITABLE | PROPF_CONFIGURABLE | PROPF_ENUMERABLE; + return S_OK; +} + +static HRESULT WINAPI WineDispatchProxyPrivate_PropOverride(IWineDispatchProxyPrivate *iface, const WCHAR *name, VARIANT *value) +{ + DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); + + if(!This->info->desc->vtbl || !This->info->desc->vtbl->override) + return S_FALSE; + return This->info->desc->vtbl->override(This, name, value); +} + +static HRESULT WINAPI WineDispatchProxyPrivate_PropDefineOverride(IWineDispatchProxyPrivate *iface, struct proxy_prop_info *info) +{ + DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); + HRESULT hres; + + if(!This->info->desc->vtbl || !This->info->desc->vtbl->override) + return S_FALSE; + + hres = This->info->desc->vtbl->get_dispid(This, (WCHAR*)info->name, fdexNameEnsure | fdexNameCaseSensitive, &info->dispid); + if(FAILED(hres)) + return (hres == DISP_E_UNKNOWNNAME) ? S_FALSE : hres; + + info->func[0].invoke = NULL; + info->flags = PROPF_WRITABLE | PROPF_CONFIGURABLE | PROPF_ENUMERABLE; + return S_OK; +} + +static HRESULT WINAPI WineDispatchProxyPrivate_PropGetInfo(IWineDispatchProxyPrivate *iface, const WCHAR *name, + BOOL case_insens, struct proxy_prop_info *info) +{ + DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); + func_info_t *func; + HRESULT hres; + + info->func[0].invoke = NULL; + + hres = proxy_get_dispid(This, name, case_insens, &info->dispid); + if(FAILED(hres)) + return hres; + + if(is_dynamic_dispid(info->dispid)) { + info->name = This->dynamic_data->props[info->dispid - DISPID_DYNPROP_0].name; + info->flags = PROPF_WRITABLE | PROPF_CONFIGURABLE | PROPF_ENUMERABLE; + return S_OK; + } + + if(is_custom_dispid(info->dispid)) { + info->name = name; /* FIXME */ + info->flags = PROPF_WRITABLE; + if(This->info->desc->vtbl) { + if(This->info->desc->vtbl->delete) + info->flags |= PROPF_CONFIGURABLE; + if(This->info->desc->vtbl->next_dispid) + info->flags |= PROPF_ENUMERABLE; + } + return S_OK; + } + + hres = get_builtin_func(This->info, info->dispid, &func); + if(FAILED(hres)) + return (hres == DISP_E_MEMBERNOTFOUND) ? E_UNEXPECTED : hres; + info->func[0].context = info->func[1].context = func; + info->name = func->name; + + if(func->func_disp_idx >= 0) { + if(This->dynamic_data && This->dynamic_data->func_disps + && This->dynamic_data->func_disps[func->func_disp_idx].func_obj) { + func_obj_entry_t *entry = This->dynamic_data->func_disps + func->func_disp_idx; + + if((IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface != V_DISPATCH(&entry->val)) { + info->flags = PROPF_WRITABLE | PROPF_CONFIGURABLE; + return S_OK; + } + } + info->flags = PROPF_METHOD | func->argc | PROPF_WRITABLE | PROPF_CONFIGURABLE; + info->func[0].invoke = proxy_func_invoke; + return S_OK; + } + + info->flags = PROPF_CONFIGURABLE | (func->put_vtbl_off ? PROPF_WRITABLE : 0); + if(func->func_disp_idx == -1) + info->flags |= PROPF_ENUMERABLE; + info->func[0].invoke = proxy_getter_invoke; + info->func[1].invoke = func->put_vtbl_off ? proxy_setter_invoke : NULL; + return S_OK; +} + +static HRESULT WINAPI WineDispatchProxyPrivate_PropInvoke(IWineDispatchProxyPrivate *iface, IDispatch *this_obj, DISPID id, + LCID lcid, DWORD flags, DISPPARAMS *dp, VARIANT *ret, EXCEPINFO *ei, IServiceProvider *caller) +{ + DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); + + return dispex_invoke(This, this_obj, id, lcid, flags, dp, ret, ei, caller); +} + +static HRESULT WINAPI WineDispatchProxyPrivate_PropDelete(IWineDispatchProxyPrivate *iface, DISPID id) +{ + DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); + + return dispex_delete_prop(This, id); +} + +static HRESULT WINAPI WineDispatchProxyPrivate_PropEnum(IWineDispatchProxyPrivate *iface) +{ + DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); + IWineDispatchProxyCbPrivate *obj = This->proxy; + dynamic_prop_t *dyn_prop, *dyn_prop_end; + dispex_dynamic_data_t *dyn_data; + func_info_t *func, *func_end; + HRESULT hres; + HRESULT (STDMETHODCALLTYPE *callback)(IWineDispatchProxyCbPrivate*,const WCHAR*) = obj->lpVtbl->PropEnum; + + if(!ensure_real_info(This)) + return E_OUTOFMEMORY; + + for(func = This->info->funcs, func_end = func + This->info->func_cnt; func != func_end; func++) { + if(func->func_disp_idx == -1) { + hres = callback(obj, func->name); + if(FAILED(hres)) + return hres; + } + } + + if(This->info->desc->vtbl && This->info->desc->vtbl->next_dispid) { + const dispex_static_data_vtbl_t *vtbl = This->info->desc->vtbl; + DISPID id = DISPID_STARTENUM; + BSTR name; + + do { + hres = vtbl->next_dispid(This, id, &id); + if(hres != S_OK) + break; + hres = vtbl->get_name(This, id, &name); + if(SUCCEEDED(hres)) { + hres = callback(obj, name); + SysFreeString(name); + } + } while(SUCCEEDED(hres)); + + if(FAILED(hres)) + return hres; + } + + if(!(dyn_data = get_dynamic_data(This))) + return E_OUTOFMEMORY; + + for(dyn_prop = dyn_data->props, dyn_prop_end = dyn_prop + dyn_data->prop_cnt; dyn_prop != dyn_prop_end; dyn_prop++) { + if(!(dyn_prop->flags & (DYNPROP_DELETED | DYNPROP_HIDDEN))) { + hres = callback(obj, dyn_prop->name); + if(FAILED(hres)) + return hres; + } + } + + return S_OK; +} + +static HRESULT WINAPI WineDispatchProxyPrivate_ToString(IWineDispatchProxyPrivate *iface, BSTR *string) +{ + DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); + + return dispex_to_string(This, string); +} + +static BOOL WINAPI WineDispatchProxyPrivate_CanGC(IWineDispatchProxyPrivate *iface) +{ + DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); + IUnknown *outer = This->outer; + + /* Allow garbage collection only if the proxy is the only one holding a ref to us */ + IUnknown_AddRef(outer); + return IUnknown_Release(outer) == 1; +} + +static IWineDispatchProxyPrivateVtbl WineDispatchProxyPrivateVtbl = { + { DispatchEx_QueryInterface, DispatchEx_AddRef, DispatchEx_Release, @@ -2062,35 +2406,30 @@ static IDispatchExVtbl DispatchExVtbl = { DispatchEx_GetMemberName, DispatchEx_GetNextDispID, DispatchEx_GetNameSpaceParent + }, + + /* IWineDispatchProxyPrivate extension */ + WineDispatchProxyPrivate_GetProxyFieldRef, + WineDispatchProxyPrivate_HasProxy, + WineDispatchProxyPrivate_PropFixOverride, + WineDispatchProxyPrivate_PropOverride, + WineDispatchProxyPrivate_PropDefineOverride, + WineDispatchProxyPrivate_PropGetInfo, + WineDispatchProxyPrivate_PropInvoke, + WineDispatchProxyPrivate_PropDelete, + WineDispatchProxyPrivate_PropEnum, + WineDispatchProxyPrivate_ToString, + WineDispatchProxyPrivate_CanGC }; -extern const IDispatchExVtbl WindowDispExVtbl DECLSPEC_HIDDEN; -extern const IDispatchExVtbl DocDispatchExVtbl DECLSPEC_HIDDEN; -static inline DispatchEx *get_dispex_for_hook(IUnknown *iface) -{ - IDispatchEx *dispex; - - if(FAILED(IUnknown_QueryInterface(iface, &IID_IDispatchEx, (void**)&dispex)) || !dispex) - return NULL; - - /* FIXME: Handle these generically (needs private interface) */ - if(dispex->lpVtbl == &DispatchExVtbl) - return impl_from_IDispatchEx(dispex); - if(dispex->lpVtbl == &WindowDispExVtbl) - return &CONTAINING_RECORD(dispex, HTMLWindow, IDispatchEx_iface)->inner_window->event_target.dispex; - if(dispex->lpVtbl == &DocDispatchExVtbl) - return &CONTAINING_RECORD(dispex, HTMLDocumentNode, IDispatchEx_iface)->node.event_target.dispex; - - IDispatchEx_Release(dispex); - return NULL; -} - BOOL dispex_query_interface(DispatchEx *This, REFIID riid, void **ppv) { if(IsEqualGUID(&IID_IDispatch, riid)) *ppv = &This->IDispatchEx_iface; else if(IsEqualGUID(&IID_IDispatchEx, riid)) *ppv = &This->IDispatchEx_iface; + else if(IsEqualGUID(&IID_IWineDispatchProxyPrivate, riid)) + *ppv = &This->IDispatchEx_iface; else if(IsEqualGUID(&IID_IDispatchJS, riid)) *ppv = NULL; else if(IsEqualGUID(&IID_UndocumentedScriptIface, riid)) @@ -2257,6 +2596,9 @@ void release_dispex(DispatchEx *This) { dynamic_prop_t *prop; + if(This->proxy) + This->proxy->lpVtbl->Unlinked(This->proxy, FALSE); + if(!This->dynamic_data) return; @@ -2289,8 +2631,9 @@ void init_dispatch(DispatchEx *dispex, IUnknown *outer, dispex_static_data_t *da { assert(compat_mode < COMPAT_MODE_CNT); - dispex->IDispatchEx_iface.lpVtbl = &DispatchExVtbl; + dispex->IDispatchEx_iface.lpVtbl = (const IDispatchExVtbl*)&WineDispatchProxyPrivateVtbl; dispex->outer = outer; + dispex->proxy = NULL; dispex->dynamic_data = NULL; if(data->vtbl && data->vtbl->get_compat_mode) { @@ -2309,5 +2652,26 @@ void init_dispatch(DispatchEx *dispex, IUnknown *outer, dispex_static_data_t *da dispex->info = data->delayed_init_info; }else { dispex->info = ensure_dispex_info(data, compat_mode); + if(window) { + if(compat_mode >= COMPAT_MODE_IE9) { + IWineDispatchProxyCbPrivate *proxy = window->event_target.dispex.proxy; + if(!proxy) { + init_proxies(window); + proxy = window->event_target.dispex.proxy; + } + if(proxy) { + HRESULT hres = proxy->lpVtbl->InitProxy(proxy, (IDispatch*)&dispex->IDispatchEx_iface); + if(hres == E_UNEXPECTED) { + /* Possible element (e.g. + diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index ab771a0751a..ca1e0602a85 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -753,7 +753,10 @@ static void _test_class_info(unsigned line, IUnknown *unk, const CLSID *clsid) #define test_disp2(a,b,c,d,e) _test_disp2(__LINE__,a,b,c,d,e) static void _test_disp2(unsigned line, IUnknown *unk, const IID *diid, const IID *diid2, const CLSID *clsid, const WCHAR *val) { + IDispatchEx *dispex; IUnknown *u; + DISPID id; + BSTR bstr; IID iid; HRESULT hres; @@ -784,6 +787,28 @@ static void _test_disp2(unsigned line, IUnknown *unk, const IID *diid, const IID ok_(__FILE__,line)(hres == E_NOINTERFACE, "Got IProvideClassInfo iface\n"); ok_(__FILE__,line)(!u, "u = %p\n", u); } + + if(compat_mode >= COMPAT_IE9) { + dispex = _get_dispex_iface(line, unk); + bstr = SysAllocString(L"hasOwnProperty"); + hres = IDispatchEx_GetDispID(dispex, bstr, 0, &id); + ok_(__FILE__,line)(hres == S_OK, "GetDispID(hasOwnProperty) failed: %08lx\n", hres); + SysFreeString(bstr); + + bstr = SysAllocString(L"hasoWnPROperty"); + hres = IDispatchEx_GetIDsOfNames(dispex, &IID_NULL, &bstr, 1, 0, &id); + ok_(__FILE__,line)(hres == S_OK, "GetIDsOfNames(hasoWnPROperty) failed: %08lx\n", hres); + ok_(__FILE__,line)(id > 0, "Unexpected DISPID for hasoWnPROperty: %ld\n", id); + + hres = IDispatchEx_GetDispID(dispex, bstr, 0, &id); + ok_(__FILE__,line)(hres == DISP_E_UNKNOWNNAME, "GetDispID(hasoWnPROperty) returned %08lx\n", hres); + + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseInsensitive, &id); + ok_(__FILE__,line)(hres == S_OK, "GetDispID(hasoWnPROperty) with fdexNameCaseInsensitive failed: %08lx\n", hres); + ok_(__FILE__,line)(id > 0, "Unexpected DISPID for hasoWnPROperty with fdexNameCaseInsensitive: %ld\n", id); + SysFreeString(bstr); + IDispatchEx_Release(dispex); + } } #define test_disp(a,b,c,d) _test_disp(__LINE__,a,b,c,d) diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 600f4b0af3d..7170951459e 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -4071,7 +4071,6 @@ static void test_doc_obj(IHTMLDocument2 *doc) hres = IHTMLDocument2_Invoke(doc, has_own_prop_id, &IID_NULL, 0, DISPATCH_METHOD, &dp, &res, NULL, NULL); ok(hres == S_OK, "Invoke(hasOwnProperty(\"createElement\")) failed: %08lx\n", hres); ok(V_VT(&res) == VT_BOOL, "VT = %d\n", V_VT(&res)); - todo_wine ok(V_BOOL(&res) == VARIANT_FALSE, "hasOwnProperty(\"createElement\") = %d\n", V_BOOL(&res)); hres = IHTMLDocument2_GetIDsOfNames(doc, &IID_NULL, &V_BSTR(&arg), 1, 0, &dispid); @@ -4084,6 +4083,23 @@ static void test_doc_obj(IHTMLDocument2 *doc) ok(V_VT(&res) == VT_BOOL, "VT = %d\n", V_VT(&res)); ok(V_BOOL(&res) == VARIANT_TRUE, "hasOwnProperty(\"prop\") = %d\n", V_BOOL(&res)); SysFreeString(V_BSTR(&arg)); + + V_BSTR(&arg) = SysAllocString(L"proto_prop"); + hres = IHTMLDocument2_Invoke(doc, has_own_prop_id, &IID_NULL, 0, DISPATCH_METHOD, &dp, &res, NULL, NULL); + ok(hres == S_OK, "Invoke(hasOwnProperty(\"proto_prop\")) failed: %08lx\n", hres); + ok(V_VT(&res) == VT_BOOL, "VT = %d\n", V_VT(&res)); + ok(V_BOOL(&res) == VARIANT_FALSE, "hasOwnProperty(\"proto_prop\") = %d\n", V_BOOL(&res)); + + hres = IHTMLDocument2_GetIDsOfNames(doc, &IID_NULL, &V_BSTR(&arg), 1, 0, &dispid); + ok(hres == S_OK, "GetIDsOfNames(proto_prop) returned: %08lx\n", hres); + SysFreeString(V_BSTR(&arg)); + + dp.cArgs = 0; + dp.rgvarg = NULL; + hres = IHTMLDocument2_Invoke(doc, dispid, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &res, NULL, NULL); + ok(hres == S_OK, "Invoke(proto_prop) failed: %08lx\n", hres); + ok(V_VT(&res) == VT_BOOL, "VT(proto_prop) = %d\n", V_VT(&res)); + ok(V_BOOL(&res) == VARIANT_TRUE, "proto_prop = %d\n", V_BOOL(&res)); } /* test window props during navigation */ diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index d6bf258607b..1d6dbae4d7d 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -329,6 +329,7 @@ static void test_sp_caller(IServiceProvider *sp) static void test_script_vars(unsigned argc, VARIANTARG *argv) { static const WCHAR *const jsobj_names[] = { L"abc", L"foO", L"bar", L"TostRing", L"hasownpropERty" }; + static const WCHAR *const body_names[] = { L"BAcKgRound", L"bGcoLor", L"fooBar", L"vaLUEof", L"hasownPROperty" }; IHTMLBodyElement *body; IDispatchEx *disp; DISPID id, id2; @@ -412,6 +413,21 @@ static void test_script_vars(unsigned argc, VARIANTARG *argv) ok(hres == S_OK, "Could not get IHTMLBodyElement iface: %08lx\n", hres); IHTMLBodyElement_Release(body); + for(i = 0; i < ARRAY_SIZE(body_names); i++) { + bstr = SysAllocString(body_names[i]); + hres = IDispatchEx_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &id); + ok(hres == S_OK, "GetIDsOfNames(%s) failed: %08lx\n", debugstr_w(bstr), hres); + ok(id > 0, "Unexpected DISPID for %s: %ld\n", debugstr_w(bstr), id); + + hres = IDispatchEx_GetDispID(disp, bstr, 0, &id); + ok(hres == DISP_E_UNKNOWNNAME, "GetDispID(%s) returned %08lx, expected %08lx\n", debugstr_w(bstr), hres, DISP_E_UNKNOWNNAME); + + hres = IDispatchEx_GetDispID(disp, bstr, fdexNameCaseInsensitive, &id); + ok(hres == S_OK, "GetDispID(%s) with fdexNameCaseInsensitive failed: %08lx\n", debugstr_w(bstr), hres); + ok(id > 0, "Unexpected DISPID for %s: %ld\n", debugstr_w(bstr), id); + SysFreeString(bstr); + } + IDispatchEx_Release(disp); } diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 235850c772f..84ec1e2ec4c 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1369,9 +1369,10 @@ static const tid_t HTMLXMLHttpRequest_iface_tids[] = { IHTMLXMLHttpRequest2_tid, 0 }; -static dispex_static_data_t HTMLXMLHttpRequest_dispex = { +dispex_static_data_t HTMLXMLHttpRequest_dispex = { L"XMLHttpRequest", &HTMLXMLHttpRequest_event_target_vtbl.dispex_vtbl, + PROTO_ID_HTMLXMLHttpRequest, DispHTMLXMLHttpRequest_tid, HTMLXMLHttpRequest_iface_tids, HTMLXMLHttpRequest_init_dispex_info @@ -1548,6 +1549,7 @@ static const tid_t HTMLXMLHttpRequestFactory_iface_tids[] = { static dispex_static_data_t HTMLXMLHttpRequestFactory_dispex = { L"Function", &HTMLXMLHttpRequestFactory_dispex_vtbl, + PROTO_ID_NULL, IHTMLXMLHttpRequestFactory_tid, HTMLXMLHttpRequestFactory_iface_tids }; From 81c272a3830305b945d10994409bb9caf91278bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:02 +0200 Subject: [PATCH 0878/2777] mshtml: Reset builtin function props to their default values when deleted. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- The previous tests bailed out too early on IE8, and did not test builtin props, so I moved them around and added builtin functions as well. --- dlls/mshtml/dispex.c | 63 ++++++++++++++++++++----------- dlls/mshtml/tests/documentmode.js | 42 +++++++++++++++++---- 2 files changed, 77 insertions(+), 28 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 831811e90d8..d65da02ed65 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1749,6 +1749,26 @@ HRESULT dispex_call_builtin(DispatchEx *dispex, DISPID id, DISPPARAMS *dp, return invoke_builtin_function((IDispatch*)&dispex->IDispatchEx_iface, func, dp, res, ei, caller); } +static VARIANT_BOOL reset_builtin_func(DispatchEx *dispex, func_info_t *func) +{ + func_obj_entry_t *entry; + + if(!dispex->dynamic_data || !dispex->dynamic_data->func_disps || + !dispex->dynamic_data->func_disps[func->func_disp_idx].func_obj) + return VARIANT_FALSE; + + entry = dispex->dynamic_data->func_disps + func->func_disp_idx; + if(V_VT(&entry->val) == VT_DISPATCH && + V_DISPATCH(&entry->val) == (IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface) + return VARIANT_FALSE; + + VariantClear(&entry->val); + V_VT(&entry->val) = VT_DISPATCH; + V_DISPATCH(&entry->val) = (IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface; + IDispatch_AddRef(V_DISPATCH(&entry->val)); + return VARIANT_TRUE; +} + HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success) { switch(get_dispid_type(id)) { @@ -1779,26 +1799,7 @@ HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success) /* For builtin functions, we set their value to the original function. */ if(func->func_disp_idx >= 0) { - func_obj_entry_t *entry; - - if(!This->dynamic_data || !This->dynamic_data->func_disps - || !This->dynamic_data->func_disps[func->func_disp_idx].func_obj) { - *success = VARIANT_FALSE; - return S_OK; - } - - entry = This->dynamic_data->func_disps + func->func_disp_idx; - if(V_VT(&entry->val) == VT_DISPATCH - && V_DISPATCH(&entry->val) == (IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface) { - *success = VARIANT_FALSE; - return S_OK; - } - - VariantClear(&entry->val); - V_VT(&entry->val) = VT_DISPATCH; - V_DISPATCH(&entry->val) = (IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface; - IDispatch_AddRef(V_DISPATCH(&entry->val)); - *success = VARIANT_TRUE; + *success = reset_builtin_func(This, func); return S_OK; } *success = VARIANT_TRUE; @@ -2786,6 +2787,8 @@ HRESULT dispex_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID l HRESULT dispex_delete_prop(DispatchEx *dispex, DISPID id) { + HRESULT hres; + if(is_custom_dispid(id) && dispex->info->desc->vtbl && dispex->info->desc->vtbl->delete) return dispex->info->desc->vtbl->delete(dispex, id); @@ -2794,7 +2797,8 @@ HRESULT dispex_delete_prop(DispatchEx *dispex, DISPID id) return E_NOTIMPL; } - if(is_dynamic_dispid(id)) { + switch(get_dispid_type(id)) { + case DISPEXPROP_DYNAMIC: { DWORD idx = id - DISPID_DYNPROP_0; dynamic_prop_t *prop; @@ -2806,6 +2810,23 @@ HRESULT dispex_delete_prop(DispatchEx *dispex, DISPID id) prop->flags |= DYNPROP_DELETED; return S_OK; } + case DISPEXPROP_BUILTIN: { + func_info_t *func; + + if(!ensure_real_info(dispex)) + return E_OUTOFMEMORY; + + hres = get_builtin_func_prot(dispex, id, &func); + if(FAILED(hres)) + return hres; + + if(func->func_disp_idx >= 0) + reset_builtin_func(dispex, func); + return S_OK; + } + default: + break; + } return S_OK; } diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 01a26732835..e96acba9922 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1176,7 +1176,7 @@ sync_test("navigator", function() { sync_test("delete_prop", function() { var v = document.documentMode; - var obj = document.createElement("div"), r, obj2; + var obj = document.createElement("div"), r, obj2, func, prop; obj.prop1 = true; r = false; @@ -1192,6 +1192,40 @@ sync_test("delete_prop", function() { ok(!r, "got an unexpected exception"); ok(!("prop1" in obj), "prop1 is still in obj"); + /* builtin properties don't throw any exception, but are not really deleted */ + r = (delete obj.tagName); + ok(r, "delete returned " + r); + ok("tagName" in obj, "tagName deleted from obj"); + ok(obj.tagName === "DIV", "tagName = " + obj.tagName); + + prop = obj.id; + r = (delete obj.id); + ok(r, "delete returned " + r); + ok("id" in obj, "id deleted from obj"); + ok(obj.id === prop, "id = " + obj.id); + + obj.id = "1234"; + ok(obj.id === "1234", "id after set to 1234 = " + obj.id); + r = (delete obj.id); + ok(r, "delete returned " + r); + ok("id" in obj, "id deleted from obj"); + ok(obj.id === "1234", "id = " + obj.id); + + /* builtin functions get reset to their original values */ + func = function() { } + prop = obj.setAttribute; + r = (delete obj.setAttribute); + ok(r, "delete returned " + r); + ok("setAttribute" in obj, "setAttribute deleted from obj"); + ok(obj.setAttribute === prop, "setAttribute = " + obj.setAttribute); + + obj.setAttribute = func; + ok(obj.setAttribute === func, "setAttribute after set to func = " + obj.setAttribute); + r = (delete obj.setAttribute); + ok(r, "delete returned " + r); + ok("setAttribute" in obj, "setAttribute deleted from obj"); + ok(obj.setAttribute === prop, "setAttribute = " + obj.setAttribute); + /* again, this time prop1 does not exist */ r = false; try { @@ -1212,12 +1246,6 @@ sync_test("delete_prop", function() { ok("className" in obj, "className deleted from obj"); ok(obj.className === "", "className = " + obj.className); - /* builtin propertiles don't throw any exception, but are not really deleted */ - r = (delete obj.tagName); - ok(r, "delete returned " + r); - ok("tagName" in obj, "tagName deleted from obj"); - ok(obj.tagName === "DIV", "tagName = " + obj.tagName); - obj = document.querySelectorAll("*"); ok("0" in obj, "0 is not in obj"); obj2 = obj[0]; From 143bf055aa332e9269f1365a3f8482cb65feb002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:03 +0200 Subject: [PATCH 0879/2777] jscript: Move the prop lookup in the props list to a helper. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/dispex.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 50c471bb081..23073836dc0 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -320,12 +320,9 @@ static dispex_prop_t *alloc_protref(jsdisp_t *This, const WCHAR *name, DWORD ref return ret; } -static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, dispex_prop_t **ret) +static dispex_prop_t *find_prop_name_raw(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens) { - const builtin_prop_t *builtin; unsigned bucket, pos, prev = ~0; - dispex_prop_t *prop; - HRESULT hres; bucket = get_props_idx(This, hash); pos = This->props[bucket].bucket_head; @@ -337,14 +334,26 @@ static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, This->props[bucket].bucket_head = pos; } - hres = fix_overridden_prop(This, &This->props[pos]); - *ret = &This->props[pos]; - return hres; + return &This->props[pos]; } prev = pos; pos = This->props[pos].bucket_next; } + return NULL; +} + +static HRESULT find_prop_name(jsdisp_t *This, unsigned hash, const WCHAR *name, BOOL case_insens, dispex_prop_t **ret) +{ + dispex_prop_t *prop = find_prop_name_raw(This, hash, name, case_insens); + const builtin_prop_t *builtin; + HRESULT hres; + + if(prop) { + hres = fix_overridden_prop(This, prop); + *ret = prop; + return hres; + } if(This->proxy) { struct proxy_prop_info info; From 9e6815e18e5f4cf67555ddc2c5ba4349cabfbe2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:03 +0200 Subject: [PATCH 0880/2777] jscript: Set the global object to the global proxy, if available. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For ES5, the JS global object is "window", so any properties redefined on window will impact all the JS globals since it's the same object. This isn't just a matter of the window object "shadowing" the JS global object; deleting a JS global prop from window also deletes it from the JS global object. Signed-off-by: Gabriel Ivăncescu --- This is tested in next patch because we need to make the properties configurable to test it properly. We have to keep around the original js_global for later when multiple windows can share same ctx (tested when constructors are implemented properly). --- dlls/jscript/dispex.c | 58 +++++++++++++++++++++++++++++++ dlls/jscript/engine.c | 2 +- dlls/jscript/global.c | 8 ++++- dlls/jscript/jscript.c | 13 ++++++- dlls/jscript/jscript.h | 4 ++- dlls/mshtml/script.c | 6 +++- dlls/mshtml/tests/documentmode.js | 1 - 7 files changed, 86 insertions(+), 6 deletions(-) diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 23073836dc0..9dc906e5584 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2428,6 +2428,64 @@ static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown return E_NOTIMPL; } +/* ECMA-262 5.1 Edition 15.1 */ +HRESULT set_js_globals(jsdisp_t *obj) +{ + jsdisp_t *js_global = obj->ctx->js_global; + const builtin_prop_t *bprop, *bend; + dispex_prop_t *prop, *end, *dst; + HRESULT hres; + BOOL b; + + /* Reset builtins first */ + obj->builtin_info = js_global->builtin_info; + for(bprop = obj->builtin_info->props, bend = bprop + obj->builtin_info->props_cnt; bprop != bend; bprop++) { + unsigned hash = string_hash(bprop->name); + if(!(prop = find_prop_name_raw(obj, hash, bprop->name, FALSE)) || prop->type == PROP_BUILTIN) + continue; + if(bprop->flags & PROPF_METHOD) { + /* Make sure the builtin method is created as a function so it gets copied later */ + hres = find_prop_name(js_global, hash, bprop->name, FALSE, &prop); + if(FAILED(hres)) + return hres; + }else { + prop->flags |= PROPF_CONFIGURABLE; + delete_prop(obj, prop, &b); + prop->flags = (bprop->flags & PROPF_ALL) | (bprop->setter ? PROPF_WRITABLE : 0); + prop->type = PROP_BUILTIN; + prop->u.p = bprop; + } + } + + /* Copy the rest of the props */ + for(prop = js_global->props, end = prop + js_global->prop_cnt; prop != end; prop++) { + if(prop->type != PROP_JSVAL && prop->type != PROP_ACCESSOR) + continue; + + /* Alloc it ourselves so we don't look into proxy props when defining it */ + if(!(dst = find_prop_name_raw(obj, prop->hash, prop->name, FALSE))) { + if(!(dst = alloc_prop(obj, prop->name, PROP_DELETED, 0))) + return E_OUTOFMEMORY; + }else { + dst->flags |= PROPF_CONFIGURABLE; + delete_prop(obj, dst, &b); + } + + dst->flags = prop->flags; + dst->type = prop->type; + if(prop->type == PROP_JSVAL) { + hres = jsval_copy(prop->u.val, &dst->u.val); + if(FAILED(hres)) + return hres; + }else { + dst->u.accessor.getter = prop->u.accessor.getter ? jsdisp_addref(prop->u.accessor.getter) : NULL; + dst->u.accessor.setter = prop->u.accessor.setter ? jsdisp_addref(prop->u.accessor.setter) : NULL; + } + } + + return S_OK; +} + static HRESULT get_proxy_default_prototype(script_ctx_t *ctx, IWineDispatchProxyPrivate *proxy, jsdisp_t **prot) { IDispatch *disp = proxy->lpVtbl->GetDefaultPrototype(proxy, &ctx->proxy_prototypes); diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index 3109b1391e8..fb636afa9b4 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -715,7 +715,7 @@ static BOOL lookup_global_members(script_ctx_t *ctx, BSTR identifier, exprval_t HRESULT hres; LIST_FOR_EACH_ENTRY(item, &ctx->named_items, named_item_t, entry) { - if(item->flags & SCRIPTITEM_GLOBALMEMBERS) { + if((item->flags & SCRIPTITEM_GLOBALMEMBERS) && item->disp != (IDispatch*)&ctx->global->IDispatchEx_iface) { hres = disp_get_id(ctx, item->disp, identifier, identifier, 0, &id); if(SUCCEEDED(hres)) { if(ret) diff --git a/dlls/jscript/global.c b/dlls/jscript/global.c index 0ab17265b73..7bfd5815f0c 100644 --- a/dlls/jscript/global.c +++ b/dlls/jscript/global.c @@ -1147,5 +1147,11 @@ HRESULT init_global(script_ctx_t *ctx) if(FAILED(hres)) return hres; - return init_set_constructor(ctx); + hres = init_set_constructor(ctx); + if(FAILED(hres)) + return hres; + + if(ctx->js_global) jsdisp_release(ctx->js_global); + ctx->js_global = jsdisp_addref(ctx->global); + return hres; } diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index 67edebf6799..3b0c334b924 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -911,6 +911,7 @@ static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface, return E_UNEXPECTED; if(dwFlags & SCRIPTITEM_GLOBALMEMBERS) { + jsdisp_t *jsdisp; IUnknown *unk; jsval_t val; @@ -932,6 +933,16 @@ static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface, if(FAILED(hres)) return hres; disp = get_object(val); + + if((jsdisp = to_jsdisp(disp)) && jsdisp->proxy) { + hres = set_js_globals(jsdisp); + if(FAILED(hres)) { + jsdisp_release(jsdisp); + return hres; + } + jsdisp_release(This->ctx->global); + This->ctx->global = jsdisp_addref(jsdisp); + } } item = malloc(sizeof(*item)); @@ -988,7 +999,7 @@ static HRESULT WINAPI JScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR if(item->script_obj) script_obj = item->script_obj; } - *ppdisp = to_disp(script_obj); + *ppdisp = script_obj->proxy ? (IDispatch*)script_obj->proxy : to_disp(script_obj); IDispatch_AddRef(*ppdisp); return S_OK; } diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 88c9360ff28..1cd44e18458 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -328,6 +328,7 @@ HRESULT create_dispex(script_ctx_t*,const builtin_info_t*,jsdisp_t*,jsdisp_t**) HRESULT init_dispex(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*) DECLSPEC_HIDDEN; HRESULT init_dispex_from_constr(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*) DECLSPEC_HIDDEN; HRESULT convert_to_proxy(script_ctx_t*,jsval_t*) DECLSPEC_HIDDEN; +HRESULT set_js_globals(jsdisp_t*) DECLSPEC_HIDDEN; void disp_fill_exception(script_ctx_t*,EXCEPINFO*) DECLSPEC_HIDDEN; HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; @@ -489,6 +490,7 @@ struct _script_ctx_t { union { struct { jsdisp_t *global; + jsdisp_t *js_global; jsdisp_t *function_constr; jsdisp_t *array_constr; jsdisp_t *bool_constr; @@ -514,7 +516,7 @@ struct _script_ctx_t { jsdisp_t *map_prototype; jsdisp_t *set_prototype; }; - jsdisp_t *global_objects[24 + NUM_TYPEDARRAY_TYPES]; + jsdisp_t *global_objects[25 + NUM_TYPEDARRAY_TYPES]; }; struct proxy_prototypes *proxy_prototypes; }; diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c index 5ce1287d45a..923f46dbd28 100644 --- a/dlls/mshtml/script.c +++ b/dlls/mshtml/script.c @@ -1820,7 +1820,11 @@ BOOL find_global_prop(HTMLInnerWindow *window, BSTR name, DWORD flags, ScriptHos hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); if(SUCCEEDED(hres)) { - hres = IDispatchEx_GetDispID(dispex, name, flags & (~fdexNameEnsure), ret_id); + /* Avoid looking into ourselves if it's a proxy used as actual global object */ + if(dispex == &window->base.outer_window->base.IDispatchEx_iface) + hres = DISP_E_UNKNOWNNAME; + else + hres = IDispatchEx_GetDispID(dispex, name, flags & (~fdexNameEnsure), ret_id); IDispatchEx_Release(dispex); }else { FIXME("No IDispatchEx\n"); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index e96acba9922..a812f06ed14 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1283,7 +1283,6 @@ sync_test("delete_prop", function() { ok(r, "did not get an expected globalprop2 exception"); }else { ok(!r, "got an unexpected exception"); - todo_wine. ok(!("globalprop2" in obj), "globalprop2 is still in obj"); } From 9809a62e1e27d994ce6a2922717856b2785d6fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:03 +0200 Subject: [PATCH 0881/2777] jscript: Make most builtin global objects configurable. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/global.c | 42 ++++++++-------- dlls/jscript/set.c | 4 +- dlls/mshtml/tests/es5.js | 103 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 23 deletions(-) diff --git a/dlls/jscript/global.c b/dlls/jscript/global.c index 7bfd5815f0c..7240d90e12a 100644 --- a/dlls/jscript/global.c +++ b/dlls/jscript/global.c @@ -941,7 +941,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"Function", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Function", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->function_constr)); if(FAILED(hres)) return hres; @@ -950,7 +950,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"Object", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Object", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->object_constr)); if(FAILED(hres)) return hres; @@ -959,7 +959,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"Array", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Array", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->array_constr)); if(FAILED(hres)) return hres; @@ -968,7 +968,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"Boolean", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Boolean", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->bool_constr)); if(FAILED(hres)) return hres; @@ -977,7 +977,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"Date", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Date", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->date_constr)); if(FAILED(hres)) return hres; @@ -986,7 +986,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"Enumerator", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Enumerator", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->enumerator_constr)); if(FAILED(hres)) return hres; @@ -995,42 +995,42 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"Error", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Error", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->error_constr)); if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"EvalError", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"EvalError", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->eval_error_constr)); if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"RangeError", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"RangeError", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->range_error_constr)); if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"ReferenceError", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"ReferenceError", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->reference_error_constr)); if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"RegExpError", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"RegExpError", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->regexp_error_constr)); if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"SyntaxError", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"SyntaxError", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->syntax_error_constr)); if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"TypeError", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"TypeError", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->type_error_constr)); if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"URIError", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"URIError", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->uri_error_constr)); if(FAILED(hres)) return hres; @@ -1039,7 +1039,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"Number", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Number", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->number_constr)); if(FAILED(hres)) return hres; @@ -1048,7 +1048,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"RegExp", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"RegExp", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->regexp_constr)); if(FAILED(hres)) return hres; @@ -1057,7 +1057,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"String", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"String", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->string_constr)); if(FAILED(hres)) return hres; @@ -1066,7 +1066,7 @@ static HRESULT init_constructors(script_ctx_t *ctx, jsdisp_t *object_prototype) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"VBArray", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"VBArray", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(ctx->vbarray_constr)); if(FAILED(hres)) return hres; @@ -1103,7 +1103,7 @@ HRESULT init_global(script_ctx_t *ctx) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"Math", PROPF_WRITABLE, jsval_obj(math)); + hres = jsdisp_define_data_property(ctx->global, L"Math", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(math)); jsdisp_release(math); if(FAILED(hres)) return hres; @@ -1115,7 +1115,7 @@ HRESULT init_global(script_ctx_t *ctx) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"JSON", PROPF_WRITABLE, jsval_obj(json)); + hres = jsdisp_define_data_property(ctx->global, L"JSON", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(json)); jsdisp_release(json); if(FAILED(hres)) return hres; @@ -1125,7 +1125,7 @@ HRESULT init_global(script_ctx_t *ctx) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"ActiveXObject", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"ActiveXObject", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(constr)); jsdisp_release(constr); if(FAILED(hres)) diff --git a/dlls/jscript/set.c b/dlls/jscript/set.c index cd2ef4bd269..337b064b6c8 100644 --- a/dlls/jscript/set.c +++ b/dlls/jscript/set.c @@ -632,7 +632,7 @@ HRESULT init_set_constructor(script_ctx_t *ctx) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"Set", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Set", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(constructor)); jsdisp_release(constructor); if(FAILED(hres)) @@ -647,7 +647,7 @@ HRESULT init_set_constructor(script_ctx_t *ctx) if(FAILED(hres)) return hres; - hres = jsdisp_define_data_property(ctx->global, L"Map", PROPF_WRITABLE, + hres = jsdisp_define_data_property(ctx->global, L"Map", PROPF_CONFIGURABLE | PROPF_WRITABLE, jsval_obj(constructor)); jsdisp_release(constructor); return hres; diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index c5066d91469..d1eb6ae5ca3 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -22,6 +22,7 @@ var JS_E_NUMBER_EXPECTED = 0x800a1389; var JS_E_FUNCTION_EXPECTED = 0x800a138a; var JS_E_DATE_EXPECTED = 0x800a138e; var JS_E_OBJECT_EXPECTED = 0x800a138f; +var JS_E_UNDEFINED_VARIABLE = 0x800a1391; var JS_E_BOOLEAN_EXPECTED = 0x800a1392; var JS_E_VBARRAY_EXPECTED = 0x800a1395; var JS_E_ENUMERATOR_EXPECTED = 0x800a1397; @@ -2501,6 +2502,108 @@ sync_test("builtin_context", function() { ok(obj.valueOf() === 42, "obj = " + obj); }); +sync_test("builtin override", function() { + /* configurable */ + var builtins = [ + "ActiveXObject", + "Array", + "ArrayBuffer", + "Boolean", + "CollectGarbage", + "DataView", + "Date", + "decodeURI", + "decodeURIComponent", + "encodeURI", + "encodeURIComponent", + "Enumerator", + "Error", + "escape", + "EvalError", + "Float32Array", + "Float64Array", + "Function", + "Int8Array", + "Int16Array", + "Int32Array", + "isFinite", + "isNaN", + "JSON", + "Map", + "Math", + "Number", + "parseFloat", + "parseInt", + "RangeError", + "ReferenceError", + "RegExp", + "ScriptEngine", + "ScriptEngineBuildVersion", + "ScriptEngineMajorVersion", + "ScriptEngineMinorVersion", + "Set", + "String", + "SyntaxError", + "TypeError", + "Uint8Array", + "Uint16Array", + "Uint32Array", + "unescape", + "URIError", + "VBArray" + ]; + + var override = { + value: 12, + configurable: true, + writable: true + }; + for(var i = 0; i < builtins.length; i++) { + var desc = Object.getOwnPropertyDescriptor(window, builtins[i]), r; + ok(desc !== undefined, "getOwnPropertyDescriptor('" + builtins[i] + "' returned undefined"); + ok(desc.configurable === true, builtins[i] + " not configurable"); + ok(desc.enumerable === false, builtins[i] + " is enumerable"); + ok(desc.writable === true, builtins[i] + " not writable"); + + r = Object.defineProperty(window, builtins[i], override); + ok(r === window, "defineProperty('" + builtins[i] + "' returned " + r); + r = Object.getOwnPropertyDescriptor(window, builtins[i]); + ok(r !== undefined, "getOwnPropertyDescriptor('" + builtins[i] + "' after override returned undefined"); + ok(r.value === 12, builtins[i] + " value = " + r.value); + + r = eval(builtins[i]); + ok(r === window[builtins[i]], "Global " + builtins[i] + " does not match redefined window." + builtins[i]); + r = (delete window[builtins[i]]); + ok(r === true, "delete window." + builtins[i] + " returned " + r); + ok(!(builtins[i] in window), builtins[i] + " in window after delete"); + try { + eval(builtins[i]); + ok(false, "expected exception retrieving global " + builtins[i] + " after delete."); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === JS_E_UNDEFINED_VARIABLE, "retrieving global " + builtins[i] + " after delete threw " + n); + } + + r = Object.defineProperty(window, builtins[i], desc); + ok(r === window, "defineProperty('" + builtins[i] + "' to restore returned " + r); + } + + /* non-configurable */ + builtins = [ + "undefined", + "Infinity", + "NaN" + ]; + + for(var i = 0; i < builtins.length; i++) { + var desc = Object.getOwnPropertyDescriptor(window, builtins[i]), r; + ok(desc !== undefined, "getOwnPropertyDescriptor('" + builtins[i] + "' returned undefined"); + ok(desc.configurable === false, builtins[i] + " is configurable"); + ok(desc.enumerable === false, builtins[i] + " is enumerable"); + ok(desc.writable === false, builtins[i] + " is writable"); + } +}); + sync_test("host this", function() { var tests = [ undefined, null, external.nullDisp, function() {}, [0], "foobar", true, 42, new Number(42), external.testHostContext(true), window, document ]; var i, obj = Object.create(Function.prototype); From b69bd19f59295079bbe31d6310fe42d03c98865d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:03 +0200 Subject: [PATCH 0882/2777] mshtml: Consolidate the quirks mode/legacy factories into a common implementation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They all share the same layout, so move them into a common struct and access them using a table and array, so they can be iterated over. Signed-off-by: Gabriel Ivăncescu --- This simplifies further patches, especially when IE8 constructors are implemented, since there's a lot of them. Being able to iterate over them will pretty much be a necessity to keep it manageable. --- dlls/mshtml/htmlimg.c | 49 +++++----------- dlls/mshtml/htmlselect.c | 49 +++++----------- dlls/mshtml/htmlwindow.c | 105 ++++++++++++++++++----------------- dlls/mshtml/mshtml_private.h | 68 ++++++++++++----------- dlls/mshtml/xmlhttprequest.c | 49 +++++----------- 5 files changed, 135 insertions(+), 185 deletions(-) diff --git a/dlls/mshtml/htmlimg.c b/dlls/mshtml/htmlimg.c index e20e82dd690..4d5405ecb62 100644 --- a/dlls/mshtml/htmlimg.c +++ b/dlls/mshtml/htmlimg.c @@ -811,15 +811,15 @@ HRESULT HTMLImgElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTML return S_OK; } -static inline HTMLImageElementFactory *impl_from_IHTMLImageElementFactory(IHTMLImageElementFactory *iface) +static inline struct legacy_ctor *impl_from_IHTMLImageElementFactory(IHTMLImageElementFactory *iface) { - return CONTAINING_RECORD(iface, HTMLImageElementFactory, IHTMLImageElementFactory_iface); + return CONTAINING_RECORD(iface, struct legacy_ctor, IHTMLImageElementFactory_iface); } static HRESULT WINAPI HTMLImageElementFactory_QueryInterface(IHTMLImageElementFactory *iface, REFIID riid, void **ppv) { - HTMLImageElementFactory *This = impl_from_IHTMLImageElementFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLImageElementFactory(iface); TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); @@ -841,7 +841,7 @@ static HRESULT WINAPI HTMLImageElementFactory_QueryInterface(IHTMLImageElementFa static ULONG WINAPI HTMLImageElementFactory_AddRef(IHTMLImageElementFactory *iface) { - HTMLImageElementFactory *This = impl_from_IHTMLImageElementFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLImageElementFactory(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); @@ -851,7 +851,7 @@ static ULONG WINAPI HTMLImageElementFactory_AddRef(IHTMLImageElementFactory *ifa static ULONG WINAPI HTMLImageElementFactory_Release(IHTMLImageElementFactory *iface) { - HTMLImageElementFactory *This = impl_from_IHTMLImageElementFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLImageElementFactory(iface); LONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); @@ -867,14 +867,14 @@ static ULONG WINAPI HTMLImageElementFactory_Release(IHTMLImageElementFactory *if static HRESULT WINAPI HTMLImageElementFactory_GetTypeInfoCount(IHTMLImageElementFactory *iface, UINT *pctinfo) { - HTMLImageElementFactory *This = impl_from_IHTMLImageElementFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLImageElementFactory(iface); return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); } static HRESULT WINAPI HTMLImageElementFactory_GetTypeInfo(IHTMLImageElementFactory *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { - HTMLImageElementFactory *This = impl_from_IHTMLImageElementFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLImageElementFactory(iface); return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); } @@ -882,7 +882,7 @@ static HRESULT WINAPI HTMLImageElementFactory_GetIDsOfNames(IHTMLImageElementFac REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { - HTMLImageElementFactory *This = impl_from_IHTMLImageElementFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLImageElementFactory(iface); return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, lcid, rgDispId); } @@ -891,7 +891,7 @@ static HRESULT WINAPI HTMLImageElementFactory_Invoke(IHTMLImageElementFactory *i DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { - HTMLImageElementFactory *This = impl_from_IHTMLImageElementFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLImageElementFactory(iface); return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); } @@ -923,7 +923,7 @@ static LONG var_to_size(const VARIANT *v) static HRESULT WINAPI HTMLImageElementFactory_create(IHTMLImageElementFactory *iface, VARIANT width, VARIANT height, IHTMLImgElement **img_elem) { - HTMLImageElementFactory *This = impl_from_IHTMLImageElementFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLImageElementFactory(iface); HTMLDocumentNode *doc; IHTMLImgElement *img; HTMLElement *elem; @@ -973,7 +973,7 @@ static HRESULT WINAPI HTMLImageElementFactory_create(IHTMLImageElementFactory *i return S_OK; } -static const IHTMLImageElementFactoryVtbl HTMLImageElementFactoryVtbl = { +const IHTMLImageElementFactoryVtbl HTMLImageElementFactoryVtbl = { HTMLImageElementFactory_QueryInterface, HTMLImageElementFactory_AddRef, HTMLImageElementFactory_Release, @@ -984,16 +984,16 @@ static const IHTMLImageElementFactoryVtbl HTMLImageElementFactoryVtbl = { HTMLImageElementFactory_create }; -static inline HTMLImageElementFactory *impl_from_DispatchEx(DispatchEx *iface) +static inline struct legacy_ctor *impl_from_DispatchEx(DispatchEx *iface) { - return CONTAINING_RECORD(iface, HTMLImageElementFactory, dispex); + return CONTAINING_RECORD(iface, struct legacy_ctor, dispex); } static HRESULT HTMLImageElementFactory_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { - HTMLImageElementFactory *This = impl_from_DispatchEx(dispex); + struct legacy_ctor *This = impl_from_DispatchEx(dispex); IHTMLImgElement *img; VARIANT empty, *width, *height; HRESULT hres; @@ -1029,29 +1029,10 @@ static const dispex_static_data_vtbl_t HTMLImageElementFactory_dispex_vtbl = { NULL }; -static dispex_static_data_t HTMLImageElementFactory_dispex = { +dispex_static_data_t HTMLImageElementFactory_dispex = { L"Function", &HTMLImageElementFactory_dispex_vtbl, PROTO_ID_NULL, IHTMLImageElementFactory_tid, HTMLImageElementFactory_iface_tids }; - -HRESULT HTMLImageElementFactory_Create(HTMLInnerWindow *window, HTMLImageElementFactory **ret_val) -{ - HTMLImageElementFactory *ret; - - ret = malloc(sizeof(HTMLImageElementFactory)); - if(!ret) - return E_OUTOFMEMORY; - - ret->IHTMLImageElementFactory_iface.lpVtbl = &HTMLImageElementFactoryVtbl; - ret->ref = 1; - ret->window = window; - - init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLImageElementFactory_iface, - &HTMLImageElementFactory_dispex, window, dispex_compat_mode(&window->event_target.dispex)); - - *ret_val = ret; - return S_OK; -} diff --git a/dlls/mshtml/htmlselect.c b/dlls/mshtml/htmlselect.c index c7371826933..3f8b7866a66 100644 --- a/dlls/mshtml/htmlselect.c +++ b/dlls/mshtml/htmlselect.c @@ -447,15 +447,15 @@ HRESULT HTMLOptionElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, H return S_OK; } -static inline HTMLOptionElementFactory *impl_from_IHTMLOptionElementFactory(IHTMLOptionElementFactory *iface) +static inline struct legacy_ctor *impl_from_IHTMLOptionElementFactory(IHTMLOptionElementFactory *iface) { - return CONTAINING_RECORD(iface, HTMLOptionElementFactory, IHTMLOptionElementFactory_iface); + return CONTAINING_RECORD(iface, struct legacy_ctor, IHTMLOptionElementFactory_iface); } static HRESULT WINAPI HTMLOptionElementFactory_QueryInterface(IHTMLOptionElementFactory *iface, REFIID riid, void **ppv) { - HTMLOptionElementFactory *This = impl_from_IHTMLOptionElementFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLOptionElementFactory(iface); TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); @@ -479,7 +479,7 @@ static HRESULT WINAPI HTMLOptionElementFactory_QueryInterface(IHTMLOptionElement static ULONG WINAPI HTMLOptionElementFactory_AddRef(IHTMLOptionElementFactory *iface) { - HTMLOptionElementFactory *This = impl_from_IHTMLOptionElementFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLOptionElementFactory(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); @@ -489,7 +489,7 @@ static ULONG WINAPI HTMLOptionElementFactory_AddRef(IHTMLOptionElementFactory *i static ULONG WINAPI HTMLOptionElementFactory_Release(IHTMLOptionElementFactory *iface) { - HTMLOptionElementFactory *This = impl_from_IHTMLOptionElementFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLOptionElementFactory(iface); LONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); @@ -504,14 +504,14 @@ static ULONG WINAPI HTMLOptionElementFactory_Release(IHTMLOptionElementFactory * static HRESULT WINAPI HTMLOptionElementFactory_GetTypeInfoCount(IHTMLOptionElementFactory *iface, UINT *pctinfo) { - HTMLOptionElementFactory *This = impl_from_IHTMLOptionElementFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLOptionElementFactory(iface); return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); } static HRESULT WINAPI HTMLOptionElementFactory_GetTypeInfo(IHTMLOptionElementFactory *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { - HTMLOptionElementFactory *This = impl_from_IHTMLOptionElementFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLOptionElementFactory(iface); return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); } @@ -519,7 +519,7 @@ static HRESULT WINAPI HTMLOptionElementFactory_GetIDsOfNames(IHTMLOptionElementF LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { - HTMLOptionElementFactory *This = impl_from_IHTMLOptionElementFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLOptionElementFactory(iface); return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, lcid, rgDispId); } @@ -527,7 +527,7 @@ static HRESULT WINAPI HTMLOptionElementFactory_Invoke(IHTMLOptionElementFactory REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { - HTMLOptionElementFactory *This = impl_from_IHTMLOptionElementFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLOptionElementFactory(iface); return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); } @@ -536,7 +536,7 @@ static HRESULT WINAPI HTMLOptionElementFactory_create(IHTMLOptionElementFactory VARIANT text, VARIANT value, VARIANT defaultselected, VARIANT selected, IHTMLOptionElement **optelem) { - HTMLOptionElementFactory *This = impl_from_IHTMLOptionElementFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLOptionElementFactory(iface); nsIDOMElement *nselem; HTMLDOMNode *node; HRESULT hres; @@ -582,7 +582,7 @@ static HRESULT WINAPI HTMLOptionElementFactory_create(IHTMLOptionElementFactory return S_OK; } -static const IHTMLOptionElementFactoryVtbl HTMLOptionElementFactoryVtbl = { +const IHTMLOptionElementFactoryVtbl HTMLOptionElementFactoryVtbl = { HTMLOptionElementFactory_QueryInterface, HTMLOptionElementFactory_AddRef, HTMLOptionElementFactory_Release, @@ -593,16 +593,16 @@ static const IHTMLOptionElementFactoryVtbl HTMLOptionElementFactoryVtbl = { HTMLOptionElementFactory_create }; -static inline HTMLOptionElementFactory *HTMLOptionElementFactory_from_DispatchEx(DispatchEx *iface) +static inline struct legacy_ctor *HTMLOptionElementFactory_from_DispatchEx(DispatchEx *iface) { - return CONTAINING_RECORD(iface, HTMLOptionElementFactory, dispex); + return CONTAINING_RECORD(iface, struct legacy_ctor, dispex); } static HRESULT HTMLOptionElementFactory_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { - HTMLOptionElementFactory *This = HTMLOptionElementFactory_from_DispatchEx(dispex); + struct legacy_ctor *This = HTMLOptionElementFactory_from_DispatchEx(dispex); unsigned int i, argc = params->cArgs - params->cNamedArgs; IHTMLOptionElement *opt; VARIANT empty, *arg[4]; @@ -642,7 +642,7 @@ static const dispex_static_data_vtbl_t HTMLOptionElementFactory_dispex_vtbl = { NULL }; -static dispex_static_data_t HTMLOptionElementFactory_dispex = { +dispex_static_data_t HTMLOptionElementFactory_dispex = { L"Function", &HTMLOptionElementFactory_dispex_vtbl, PROTO_ID_NULL, @@ -650,25 +650,6 @@ static dispex_static_data_t HTMLOptionElementFactory_dispex = { HTMLOptionElementFactory_iface_tids, }; -HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow *window, HTMLOptionElementFactory **ret_ptr) -{ - HTMLOptionElementFactory *ret; - - ret = malloc(sizeof(*ret)); - if(!ret) - return E_OUTOFMEMORY; - - ret->IHTMLOptionElementFactory_iface.lpVtbl = &HTMLOptionElementFactoryVtbl; - ret->ref = 1; - ret->window = window; - - init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLOptionElementFactory_iface, - &HTMLOptionElementFactory_dispex, window, dispex_compat_mode(&window->event_target.dispex)); - - *ret_ptr = ret; - return S_OK; -} - struct HTMLSelectElement { HTMLElement element; diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 997d14ef115..6149774d6fb 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -152,6 +152,34 @@ static ULONG detach_inner_window(HTMLInnerWindow *window) return ref; } +static HRESULT get_legacy_ctor(HTMLInnerWindow *window, legacy_ctor_id_t ctor_id, dispex_static_data_t *dispex, + const void *vtbl, IDispatch **ret) +{ + struct legacy_ctor *ctor = window->legacy_ctors[ctor_id]; + + if(!ctor) { + ctor = malloc(sizeof(*ctor)); + if(!ctor) + return E_OUTOFMEMORY; + + ctor->IUnknown_iface.lpVtbl = vtbl; + ctor->ref = 1; + ctor->window = window; + window->legacy_ctors[ctor_id] = ctor; + + init_dispatch(&ctor->dispex, &ctor->IUnknown_iface, dispex, NULL, dispex_compat_mode(&window->event_target.dispex)); + } + + *ret = (IDispatch*)&ctor->dispex.IDispatchEx_iface; + IDispatch_AddRef(*ret); + return S_OK; +} + +static inline struct legacy_ctor *legacy_ctor_from_IDispatch(IDispatch *iface) +{ + return CONTAINING_RECORD((IDispatchEx*)iface, struct legacy_ctor, dispex.IDispatchEx_iface); +} + static inline HTMLWindow *impl_from_IHTMLWindow2(IHTMLWindow2 *iface) { return CONTAINING_RECORD(iface, HTMLWindow, IHTMLWindow2_iface); @@ -296,19 +324,11 @@ static void release_inner_window(HTMLInnerWindow *This) free(This->global_props[i].name); free(This->global_props); - if(This->image_factory) { - This->image_factory->window = NULL; - IHTMLImageElementFactory_Release(&This->image_factory->IHTMLImageElementFactory_iface); - } - - if(This->option_factory) { - This->option_factory->window = NULL; - IHTMLOptionElementFactory_Release(&This->option_factory->IHTMLOptionElementFactory_iface); - } - - if(This->xhr_factory) { - This->xhr_factory->window = NULL; - IHTMLXMLHttpRequestFactory_Release(&This->xhr_factory->IHTMLXMLHttpRequestFactory_iface); + for(i = 0; i < ARRAY_SIZE(This->legacy_ctors); i++) { + if(This->legacy_ctors[i]) { + This->legacy_ctors[i]->window = NULL; + IUnknown_Release(&This->legacy_ctors[i]->IUnknown_iface); + } } if(This->screen) @@ -815,21 +835,16 @@ static HRESULT WINAPI HTMLWindow2_get_Image(IHTMLWindow2 *iface, IHTMLImageEleme { HTMLWindow *This = impl_from_IHTMLWindow2(iface); HTMLInnerWindow *window = This->inner_window; + IDispatch *disp; + HRESULT hres; TRACE("(%p)->(%p)\n", This, p); - if(!window->image_factory) { - HRESULT hres; - - hres = HTMLImageElementFactory_Create(window, &window->image_factory); - if(FAILED(hres)) - return hres; - } - - *p = &window->image_factory->IHTMLImageElementFactory_iface; - IHTMLImageElementFactory_AddRef(*p); - - return S_OK; + hres = get_legacy_ctor(window, LEGACY_CTOR_ID_Image, &HTMLImageElementFactory_dispex, + &HTMLImageElementFactoryVtbl, &disp); + if(SUCCEEDED(hres)) + *p = &legacy_ctor_from_IDispatch(disp)->IHTMLImageElementFactory_iface; + return hres; } static HRESULT WINAPI HTMLWindow2_get_location(IHTMLWindow2 *iface, IHTMLLocation **p) @@ -1369,21 +1384,16 @@ static HRESULT WINAPI HTMLWindow2_get_Option(IHTMLWindow2 *iface, IHTMLOptionEle { HTMLWindow *This = impl_from_IHTMLWindow2(iface); HTMLInnerWindow *window = This->inner_window; + IDispatch *disp; + HRESULT hres; TRACE("(%p)->(%p)\n", This, p); - if(!window->option_factory) { - HRESULT hres; - - hres = HTMLOptionElementFactory_Create(window, &window->option_factory); - if(FAILED(hres)) - return hres; - } - - *p = &window->option_factory->IHTMLOptionElementFactory_iface; - IHTMLOptionElementFactory_AddRef(*p); - - return S_OK; + hres = get_legacy_ctor(window, LEGACY_CTOR_ID_Option, &HTMLOptionElementFactory_dispex, + &HTMLOptionElementFactoryVtbl, &disp); + if(SUCCEEDED(hres)) + *p = &legacy_ctor_from_IDispatch(disp)->IHTMLOptionElementFactory_iface; + return hres; } static HRESULT WINAPI HTMLWindow2_focus(IHTMLWindow2 *iface) @@ -2062,6 +2072,8 @@ static HRESULT WINAPI HTMLWindow5_get_XMLHttpRequest(IHTMLWindow5 *iface, VARIAN { HTMLWindow *This = impl_from_IHTMLWindow5(iface); HTMLInnerWindow *window = This->inner_window; + IDispatch *disp; + HRESULT hres; TRACE("(%p)->(%p)\n", This, p); @@ -2070,20 +2082,13 @@ static HRESULT WINAPI HTMLWindow5_get_XMLHttpRequest(IHTMLWindow5 *iface, VARIAN return S_OK; } - if(!window->xhr_factory) { - HRESULT hres; - - hres = HTMLXMLHttpRequestFactory_Create(window, &window->xhr_factory); - if(FAILED(hres)) { - return hres; - } + hres = get_legacy_ctor(window, LEGACY_CTOR_ID_HTMLXMLHttpRequest, &HTMLXMLHttpRequestFactory_dispex, + &HTMLXMLHttpRequestFactoryVtbl, &disp); + if(SUCCEEDED(hres)) { + V_VT(p) = VT_DISPATCH; + V_DISPATCH(p) = (IDispatch*)&legacy_ctor_from_IDispatch(disp)->IHTMLXMLHttpRequestFactory_iface; } - - V_VT(p) = VT_DISPATCH; - V_DISPATCH(p) = (IDispatch*)&window->xhr_factory->IHTMLXMLHttpRequestFactory_iface; - IDispatch_AddRef(V_DISPATCH(p)); - - return S_OK; + return hres; } static const IHTMLWindow5Vtbl HTMLWindow5Vtbl = { diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 492541149be..99fa79ad2c4 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -485,6 +485,18 @@ PROXY_PROTOTYPE_LIST #undef X } prototype_id_t; +typedef enum { +#define X(id, name, dispex, proto_id) LEGACY_CTOR_ID_ ## id, +LEGACY_PROTOTYPE_LIST +COMMON_PROTOTYPE_LIST +#undef X + /* extra ctors that share prototypes */ + LEGACY_CTOR_ID_Image, + LEGACY_CTOR_ID_Option, + + LEGACY_CTOR_COUNT +} legacy_ctor_id_t; + typedef enum { COMPAT_MODE_INVALID = -1, COMPAT_MODE_QUIRKS, @@ -618,6 +630,20 @@ typedef enum { dispex_prop_type_t get_dispid_type(DISPID) DECLSPEC_HIDDEN; +struct legacy_ctor { + DispatchEx dispex; + union { + IUnknown IUnknown_iface; + IHTMLOptionElementFactory IHTMLOptionElementFactory_iface; + IHTMLImageElementFactory IHTMLImageElementFactory_iface; + IHTMLXMLHttpRequestFactory IHTMLXMLHttpRequestFactory_iface; + }; + + LONG ref; + + HTMLInnerWindow *window; +}; + typedef enum { GLOBAL_SCRIPTVAR, GLOBAL_ELEMENTVAR, @@ -638,33 +664,6 @@ struct EventTarget { struct wine_rb_tree handler_map; }; -typedef struct { - DispatchEx dispex; - IHTMLOptionElementFactory IHTMLOptionElementFactory_iface; - - LONG ref; - - HTMLInnerWindow *window; -} HTMLOptionElementFactory; - -typedef struct { - DispatchEx dispex; - IHTMLImageElementFactory IHTMLImageElementFactory_iface; - - LONG ref; - - HTMLInnerWindow *window; -} HTMLImageElementFactory; - -typedef struct { - DispatchEx dispex; - IHTMLXMLHttpRequestFactory IHTMLXMLHttpRequestFactory_iface; - - LONG ref; - - HTMLInnerWindow *window; -} HTMLXMLHttpRequestFactory; - struct HTMLLocation { DispatchEx dispex; IHTMLLocation IHTMLLocation_iface; @@ -773,9 +772,6 @@ struct HTMLInnerWindow { IHTMLEventObj *event; - HTMLImageElementFactory *image_factory; - HTMLOptionElementFactory *option_factory; - HTMLXMLHttpRequestFactory *xhr_factory; IHTMLScreen *screen; OmHistory *history; IOmNavigator *navigator; @@ -798,6 +794,8 @@ struct HTMLInnerWindow { IMoniker *mon; nsChannelBSC *bscallback; struct list bindings; + + struct legacy_ctor *legacy_ctors[LEGACY_CTOR_COUNT]; }; typedef enum { @@ -1166,9 +1164,6 @@ void set_window_uninitialized(HTMLOuterWindow*,HTMLDocumentNode*) DECLSPEC_HIDDE HRESULT update_window_doc(HTMLInnerWindow*) DECLSPEC_HIDDEN; HTMLOuterWindow *mozwindow_to_window(const mozIDOMWindowProxy*) DECLSPEC_HIDDEN; void get_top_window(HTMLOuterWindow*,HTMLOuterWindow**) DECLSPEC_HIDDEN; -HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow*,HTMLOptionElementFactory**) DECLSPEC_HIDDEN; -HRESULT HTMLImageElementFactory_Create(HTMLInnerWindow*,HTMLImageElementFactory**) DECLSPEC_HIDDEN; -HRESULT HTMLXMLHttpRequestFactory_Create(HTMLInnerWindow*,HTMLXMLHttpRequestFactory**) DECLSPEC_HIDDEN; void HTMLLocation_Init(HTMLOuterWindow*) DECLSPEC_HIDDEN; HRESULT create_navigator(HTMLInnerWindow*,IOmNavigator**) DECLSPEC_HIDDEN; void detach_navigator(IOmNavigator*) DECLSPEC_HIDDEN; @@ -1643,6 +1638,13 @@ extern HINSTANCE hInst DECLSPEC_HIDDEN; void create_console(HTMLInnerWindow *window, IWineMSHTMLConsole **ret) DECLSPEC_HIDDEN; HRESULT create_media_query_list(HTMLWindow *window, BSTR media_query, IDispatch **ret) DECLSPEC_HIDDEN; +extern const IHTMLImageElementFactoryVtbl HTMLImageElementFactoryVtbl DECLSPEC_HIDDEN; +extern const IHTMLOptionElementFactoryVtbl HTMLOptionElementFactoryVtbl DECLSPEC_HIDDEN; +extern const IHTMLXMLHttpRequestFactoryVtbl HTMLXMLHttpRequestFactoryVtbl DECLSPEC_HIDDEN; +extern dispex_static_data_t HTMLImageElementFactory_dispex DECLSPEC_HIDDEN; +extern dispex_static_data_t HTMLOptionElementFactory_dispex DECLSPEC_HIDDEN; +extern dispex_static_data_t HTMLXMLHttpRequestFactory_dispex DECLSPEC_HIDDEN; + #define X(id, name, dispex, proto_id) extern dispex_static_data_t dispex DECLSPEC_HIDDEN; LEGACY_PROTOTYPE_LIST COMMON_PROTOTYPE_LIST diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 84ec1e2ec4c..a61a4f9f6ef 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1380,14 +1380,14 @@ dispex_static_data_t HTMLXMLHttpRequest_dispex = { /* IHTMLXMLHttpRequestFactory */ -static inline HTMLXMLHttpRequestFactory *impl_from_IHTMLXMLHttpRequestFactory(IHTMLXMLHttpRequestFactory *iface) +static inline struct legacy_ctor *impl_from_IHTMLXMLHttpRequestFactory(IHTMLXMLHttpRequestFactory *iface) { - return CONTAINING_RECORD(iface, HTMLXMLHttpRequestFactory, IHTMLXMLHttpRequestFactory_iface); + return CONTAINING_RECORD(iface, struct legacy_ctor, IHTMLXMLHttpRequestFactory_iface); } static HRESULT WINAPI HTMLXMLHttpRequestFactory_QueryInterface(IHTMLXMLHttpRequestFactory *iface, REFIID riid, void **ppv) { - HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLXMLHttpRequestFactory(iface); TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); @@ -1411,7 +1411,7 @@ static HRESULT WINAPI HTMLXMLHttpRequestFactory_QueryInterface(IHTMLXMLHttpReque static ULONG WINAPI HTMLXMLHttpRequestFactory_AddRef(IHTMLXMLHttpRequestFactory *iface) { - HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLXMLHttpRequestFactory(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); @@ -1421,7 +1421,7 @@ static ULONG WINAPI HTMLXMLHttpRequestFactory_AddRef(IHTMLXMLHttpRequestFactory static ULONG WINAPI HTMLXMLHttpRequestFactory_Release(IHTMLXMLHttpRequestFactory *iface) { - HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLXMLHttpRequestFactory(iface); LONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); @@ -1436,14 +1436,14 @@ static ULONG WINAPI HTMLXMLHttpRequestFactory_Release(IHTMLXMLHttpRequestFactory static HRESULT WINAPI HTMLXMLHttpRequestFactory_GetTypeInfoCount(IHTMLXMLHttpRequestFactory *iface, UINT *pctinfo) { - HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLXMLHttpRequestFactory(iface); return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); } static HRESULT WINAPI HTMLXMLHttpRequestFactory_GetTypeInfo(IHTMLXMLHttpRequestFactory *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { - HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLXMLHttpRequestFactory(iface); return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); } @@ -1451,7 +1451,7 @@ static HRESULT WINAPI HTMLXMLHttpRequestFactory_GetTypeInfo(IHTMLXMLHttpRequestF static HRESULT WINAPI HTMLXMLHttpRequestFactory_GetIDsOfNames(IHTMLXMLHttpRequestFactory *iface, REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { - HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLXMLHttpRequestFactory(iface); return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, lcid, rgDispId); @@ -1460,7 +1460,7 @@ static HRESULT WINAPI HTMLXMLHttpRequestFactory_GetIDsOfNames(IHTMLXMLHttpReques static HRESULT WINAPI HTMLXMLHttpRequestFactory_Invoke(IHTMLXMLHttpRequestFactory *iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { - HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLXMLHttpRequestFactory(iface); return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); @@ -1468,7 +1468,7 @@ static HRESULT WINAPI HTMLXMLHttpRequestFactory_Invoke(IHTMLXMLHttpRequestFactor static HRESULT WINAPI HTMLXMLHttpRequestFactory_create(IHTMLXMLHttpRequestFactory *iface, IHTMLXMLHttpRequest **p) { - HTMLXMLHttpRequestFactory *This = impl_from_IHTMLXMLHttpRequestFactory(iface); + struct legacy_ctor *This = impl_from_IHTMLXMLHttpRequestFactory(iface); HTMLXMLHttpRequest *ret; nsIXMLHttpRequest *nsxhr; @@ -1499,7 +1499,7 @@ static HRESULT WINAPI HTMLXMLHttpRequestFactory_create(IHTMLXMLHttpRequestFactor return S_OK; } -static const IHTMLXMLHttpRequestFactoryVtbl HTMLXMLHttpRequestFactoryVtbl = { +const IHTMLXMLHttpRequestFactoryVtbl HTMLXMLHttpRequestFactoryVtbl = { HTMLXMLHttpRequestFactory_QueryInterface, HTMLXMLHttpRequestFactory_AddRef, HTMLXMLHttpRequestFactory_Release, @@ -1510,15 +1510,15 @@ static const IHTMLXMLHttpRequestFactoryVtbl HTMLXMLHttpRequestFactoryVtbl = { HTMLXMLHttpRequestFactory_create }; -static inline HTMLXMLHttpRequestFactory *factory_from_DispatchEx(DispatchEx *iface) +static inline struct legacy_ctor *ctor_from_DispatchEx(DispatchEx *iface) { - return CONTAINING_RECORD(iface, HTMLXMLHttpRequestFactory, dispex); + return CONTAINING_RECORD(iface, struct legacy_ctor, dispex); } static HRESULT HTMLXMLHttpRequestFactory_value(DispatchEx *iface, LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { - HTMLXMLHttpRequestFactory *This = factory_from_DispatchEx(iface); + struct legacy_ctor *This = ctor_from_DispatchEx(iface); IHTMLXMLHttpRequest *xhr; HRESULT hres; @@ -1546,29 +1546,10 @@ static const tid_t HTMLXMLHttpRequestFactory_iface_tids[] = { IHTMLXMLHttpRequestFactory_tid, 0 }; -static dispex_static_data_t HTMLXMLHttpRequestFactory_dispex = { +dispex_static_data_t HTMLXMLHttpRequestFactory_dispex = { L"Function", &HTMLXMLHttpRequestFactory_dispex_vtbl, PROTO_ID_NULL, IHTMLXMLHttpRequestFactory_tid, HTMLXMLHttpRequestFactory_iface_tids }; - -HRESULT HTMLXMLHttpRequestFactory_Create(HTMLInnerWindow* window, HTMLXMLHttpRequestFactory **ret_ptr) -{ - HTMLXMLHttpRequestFactory *ret; - - ret = malloc(sizeof(*ret)); - if(!ret) - return E_OUTOFMEMORY; - - ret->IHTMLXMLHttpRequestFactory_iface.lpVtbl = &HTMLXMLHttpRequestFactoryVtbl; - ret->ref = 1; - ret->window = window; - - init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLXMLHttpRequestFactory_iface, - &HTMLXMLHttpRequestFactory_dispex, window, dispex_compat_mode(&window->event_target.dispex)); - - *ret_ptr = ret; - return S_OK; -} From e3290bd0a6ca19bea323d1eff6b0c8371346ff3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:03 +0200 Subject: [PATCH 0883/2777] mshtml: Allow dispex vtbl's value to override builtins. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Returning S_FALSE falls back to normal behavior. Signed-off-by: Gabriel Ivăncescu --- Necessary for next patch and later ones as well. --- dlls/mshtml/dispex.c | 9 ++++++--- dlls/mshtml/htmlimg.c | 3 +++ dlls/mshtml/htmlselect.c | 6 ++---- dlls/mshtml/xmlhttprequest.c | 6 ++---- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index d65da02ed65..24a42d456d3 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -780,9 +780,6 @@ static HRESULT dispex_value(DispatchEx *This, LCID lcid, WORD flags, DISPPARAMS { HRESULT hres; - if(This->info->desc->vtbl && This->info->desc->vtbl->value) - return This->info->desc->vtbl->value(This, lcid, flags, params, res, ei, caller); - switch(flags) { case DISPATCH_PROPERTYGET: V_VT(res) = VT_BSTR; @@ -1673,6 +1670,12 @@ static HRESULT invoke_builtin_prop(DispatchEx *This, IDispatch *this_obj, DISPID IUnknown *iface; HRESULT hres; + if(id == DISPID_VALUE && This->info->desc->vtbl && This->info->desc->vtbl->value) { + hres = This->info->desc->vtbl->value(This, lcid, flags, dp, res, ei, caller); + if(hres != S_FALSE) + return hres; + } + hres = get_builtin_func_prot(This, id, &func); if(id == DISPID_VALUE && hres == DISP_E_MEMBERNOTFOUND) return dispex_value(This, lcid, flags, dp, res, ei, caller); diff --git a/dlls/mshtml/htmlimg.c b/dlls/mshtml/htmlimg.c index 4d5405ecb62..f05316e810f 100644 --- a/dlls/mshtml/htmlimg.c +++ b/dlls/mshtml/htmlimg.c @@ -999,6 +999,9 @@ static HRESULT HTMLImageElementFactory_value(DispatchEx *dispex, LCID lcid, HRESULT hres; int argc = params->cArgs - params->cNamedArgs; + if(flags != DISPATCH_CONSTRUCT) + return S_FALSE; + V_VT(res) = VT_NULL; V_VT(&empty) = VT_EMPTY; diff --git a/dlls/mshtml/htmlselect.c b/dlls/mshtml/htmlselect.c index 3f8b7866a66..598ead27de3 100644 --- a/dlls/mshtml/htmlselect.c +++ b/dlls/mshtml/htmlselect.c @@ -608,10 +608,8 @@ static HRESULT HTMLOptionElementFactory_value(DispatchEx *dispex, LCID lcid, VARIANT empty, *arg[4]; HRESULT hres; - if(flags != DISPATCH_CONSTRUCT) { - FIXME("flags %x not supported\n", flags); - return E_NOTIMPL; - } + if(flags != DISPATCH_CONSTRUCT) + return S_FALSE; V_VT(res) = VT_NULL; V_VT(&empty) = VT_EMPTY; diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index a61a4f9f6ef..f3f58166242 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1524,10 +1524,8 @@ static HRESULT HTMLXMLHttpRequestFactory_value(DispatchEx *iface, LCID lcid, WOR TRACE("\n"); - if(flags != DISPATCH_CONSTRUCT) { - FIXME("flags %x not supported\n", flags); - return E_NOTIMPL; - } + if(flags != DISPATCH_CONSTRUCT) + return S_FALSE; hres = IHTMLXMLHttpRequestFactory_create(&This->IHTMLXMLHttpRequestFactory_iface, &xhr); if(FAILED(hres)) From be76272f0fc5c1040d9f2852c3359b748afd6d42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:03 +0200 Subject: [PATCH 0884/2777] mshtml: Implement prototypes for constructors in pre-IE9 modes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Functions called on the prototypes throw INVALID_PROPERTY, while accessors succeed but always return undefined (and setters do nothing). Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/dispex.c | 244 ++++++++++++++++++++++++++++++++++- dlls/mshtml/htmlimg.c | 7 +- dlls/mshtml/htmlselect.c | 7 +- dlls/mshtml/htmlwindow.c | 21 +-- dlls/mshtml/mshtml_private.h | 13 ++ dlls/mshtml/xmlhttprequest.c | 6 +- 6 files changed, 281 insertions(+), 17 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 24a42d456d3..b67a8b40de6 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -159,6 +159,25 @@ PROXY_PROTOTYPE_LIST #undef X }; +static const WCHAR legacy_prototype_nameW[] = L"[Interface prototype object]"; +static void legacy_prototype_init_dispex_info(dispex_data_t*,compat_mode_t); +static const dispex_static_data_vtbl_t legacy_prototype_dispex_vtbl; + +static dispex_static_data_t legacy_prototype_dispex[] = { +#define X(id, name, dispex, proto_id) \ +{ \ + legacy_prototype_nameW, \ + &legacy_prototype_dispex_vtbl, \ + PROTO_ID_NULL, \ + NULL_tid, \ + no_iface_tids, \ + legacy_prototype_init_dispex_info \ +}, +LEGACY_PROTOTYPE_LIST +COMMON_PROTOTYPE_LIST +#undef X +}; + static inline dispex_data_t *proxy_prototype_object_info(struct proxy_prototype *prot) { dispex_static_data_t *desc = CONTAINING_RECORD(prot->dispex.info->desc, struct prototype_static_data, dispex)->desc; @@ -470,6 +489,32 @@ static void add_func_info(dispex_data_t *data, tid_t tid, const FUNCDESC *desc, } } +static void copy_func_info(func_info_t *dst, func_info_t *src) +{ + unsigned i, argc = src->argc; + + *dst = *src; + dst->name = SysAllocString(src->name); + + if(src->arg_types) { + DWORD size = (argc + (src->prop_vt == VT_VOID ? 0 : 1)) * sizeof(*dst->arg_types); + dst->arg_types = malloc(size); + if(dst->arg_types) + memcpy(dst->arg_types, src->arg_types, size); + } + + if(src->arg_info) { + dst->arg_info = malloc(argc * sizeof(*dst->arg_info)); + if(dst->arg_info) { + for(i = 0; i < argc; i++) { + dst->arg_info[i].iid = src->arg_info[i].iid; + V_VT(&dst->arg_info[i].default_value) = VT_EMPTY; + VariantCopy(&dst->arg_info[i].default_value, &src->arg_info[i].default_value); + } + } + } +} + static HRESULT process_interface(dispex_data_t *data, tid_t tid, ITypeInfo *disp_typeinfo, const dispex_hook_t *hooks) { unsigned i = 7; /* skip IDispatch functions */ @@ -1610,6 +1655,8 @@ static HRESULT func_invoke(DispatchEx *This, IDispatch *this_obj, func_info_t *f } hres = invoke_builtin_function(this_obj, func, dp, res, ei, caller); + if(hres == E_UNEXPECTED && dispex_compat_mode(This) < COMPAT_MODE_IE9) + hres = MSHTML_E_INVALID_PROPERTY; break; case DISPATCH_PROPERTYGET: { func_obj_entry_t *entry; @@ -1686,8 +1733,13 @@ static HRESULT invoke_builtin_prop(DispatchEx *This, IDispatch *this_obj, DISPID return func_invoke(This, this_obj, func, flags, dp, res, ei, caller); hres = IDispatch_QueryInterface(this_obj, tid_ids[func->tid], (void**)&iface); - if(FAILED(hres) || !iface) - return E_UNEXPECTED; + if(FAILED(hres) || !iface) { + if(dispex_compat_mode(This) >= COMPAT_MODE_IE9) + return E_UNEXPECTED; + if(res) + V_VT(res) = VT_EMPTY; + return S_OK; + } if(func->hook && (dispex = get_dispex_for_hook(iface))) { hres = func->hook(dispex, flags, dp, res, ei, caller); @@ -1883,6 +1935,194 @@ static BOOL ensure_real_info(DispatchEx *dispex) return dispex->info != NULL; } +static inline struct legacy_prototype *legacy_prototype_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct legacy_prototype, IUnknown_iface); +} + +static HRESULT WINAPI legacy_prototype_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) +{ + struct legacy_prototype *This = legacy_prototype_from_IUnknown(iface); + + TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); + + if(IsEqualGUID(&IID_IUnknown, riid)) { + *ppv = &This->IUnknown_iface; + }else if(dispex_query_interface(&This->dispex, riid, ppv)) { + return *ppv ? S_OK : E_NOINTERFACE; + }else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI legacy_prototype_AddRef(IUnknown *iface) +{ + struct legacy_prototype *This = legacy_prototype_from_IUnknown(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI legacy_prototype_Release(IUnknown *iface) +{ + struct legacy_prototype *This = legacy_prototype_from_IUnknown(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if(!ref) { + release_dispex(&This->dispex); + free(This); + } + return ref; +} + +static const IUnknownVtbl legacy_prototype_vtbl = { + legacy_prototype_QueryInterface, + legacy_prototype_AddRef, + legacy_prototype_Release +}; + +struct legacy_prototype *get_legacy_prototype(HTMLInnerWindow *window, prototype_id_t prot_id, + compat_mode_t compat_mode) +{ + struct legacy_prototype *prot = window->legacy_prototypes[prot_id]; + + if(!prot) { + if(!(prot = malloc(sizeof(*prot)))) + return NULL; + + prot->IUnknown_iface.lpVtbl = &legacy_prototype_vtbl; + prot->ref = 1; + window->legacy_prototypes[prot_id] = prot; + + init_dispatch(&prot->dispex, &prot->IUnknown_iface, &legacy_prototype_dispex[prot_id], NULL, compat_mode); + } + + IUnknown_AddRef(&prot->IUnknown_iface); + return prot; +} + +static HRESULT legacy_prototype_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *params, + VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + switch(flags) { + case DISPATCH_METHOD|DISPATCH_PROPERTYGET: + if(!res) + return E_INVALIDARG; + /* fall through */ + case DISPATCH_METHOD: + case DISPATCH_CONSTRUCT: + return MSHTML_E_INVALID_ACTION; + case DISPATCH_PROPERTYGET: + if(!(V_BSTR(res) = SysAllocString(legacy_prototype_nameW))) + return E_OUTOFMEMORY; + V_VT(res) = VT_BSTR; + break; + case DISPATCH_PROPERTYPUTREF|DISPATCH_PROPERTYPUT: + case DISPATCH_PROPERTYPUTREF: + case DISPATCH_PROPERTYPUT: + break; + default: + return E_INVALIDARG; + } + return S_OK; +} + +static const dispex_static_data_vtbl_t legacy_prototype_dispex_vtbl = { + legacy_prototype_value, +}; + +static void legacy_prototype_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) +{ + prototype_id_t prot_id = info->desc - legacy_prototype_dispex; + dispex_data_t *data = ensure_dispex_info(prototype_static_data[prot_id].desc, compat_mode); + func_info_t *func; + unsigned i; + + if(!data) + return; + + /* Copy the info from the object instance data */ + func = realloc(info->funcs, data->func_size * sizeof(*func)); + if(!func) + return; + info->funcs = func; + info->func_cnt = data->func_cnt; + info->func_disp_cnt = data->func_disp_cnt; + info->func_size = data->func_size; + + for(i = 0; i < data->func_cnt; i++) { + copy_func_info(func, &data->funcs[i]); + func++; + } + memset(func, 0, (info->func_size - i) * sizeof(*func)); +} + +HRESULT legacy_ctor_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid) +{ + if((flags & fdexNameCaseInsensitive) ? !wcsicmp(name, L"prototype") : !wcscmp(name, L"prototype")) { + *dispid = MSHTML_DISPID_CUSTOM_MIN; + return S_OK; + } + return DISP_E_UNKNOWNNAME; +} + +HRESULT legacy_ctor_get_name(DispatchEx *dispex, DISPID id, BSTR *name) +{ + DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN; + + if(idx > 0) + return DISP_E_MEMBERNOTFOUND; + return (*name = SysAllocString(L"prototype")) ? S_OK : E_OUTOFMEMORY; +} + +HRESULT legacy_ctor_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, + DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + struct legacy_ctor *This = CONTAINING_RECORD(dispex, struct legacy_ctor, dispex); + DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN; + struct legacy_prototype *prot; + + if(idx > 0) + return DISP_E_MEMBERNOTFOUND; + + if(!This->window) + return E_UNEXPECTED; + + switch(flags) { + case DISPATCH_METHOD|DISPATCH_PROPERTYGET: + if(!res) + return E_INVALIDARG; + /* fall through */ + case DISPATCH_METHOD: + return MSHTML_E_INVALID_PROPERTY; + case DISPATCH_PROPERTYGET: + if(!(prot = get_legacy_prototype(This->window, This->prot_id, dispex_compat_mode(dispex)))) + return E_OUTOFMEMORY; + V_VT(res) = VT_DISPATCH; + V_DISPATCH(res) = (IDispatch*)&prot->dispex.IDispatchEx_iface; + break; + default: + return MSHTML_E_INVALID_PROPERTY; + } + + return S_OK; +} + +HRESULT legacy_ctor_delete(DispatchEx *dispex, DISPID id) +{ + DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN; + return dispex_compat_mode(dispex) < COMPAT_MODE_IE8 ? E_NOTIMPL : + idx > 0 ? S_OK : MSHTML_E_INVALID_PROPERTY; +} + static inline struct proxy_prototype *proxy_prototype_from_IUnknown(IUnknown *iface) { return CONTAINING_RECORD(iface, struct proxy_prototype, IUnknown_iface); diff --git a/dlls/mshtml/htmlimg.c b/dlls/mshtml/htmlimg.c index f05316e810f..516f82fd35c 100644 --- a/dlls/mshtml/htmlimg.c +++ b/dlls/mshtml/htmlimg.c @@ -1027,9 +1027,10 @@ static const tid_t HTMLImageElementFactory_iface_tids[] = { static const dispex_static_data_vtbl_t HTMLImageElementFactory_dispex_vtbl = { HTMLImageElementFactory_value, - NULL, - NULL, - NULL + legacy_ctor_get_dispid, + legacy_ctor_get_name, + legacy_ctor_invoke, + legacy_ctor_delete }; dispex_static_data_t HTMLImageElementFactory_dispex = { diff --git a/dlls/mshtml/htmlselect.c b/dlls/mshtml/htmlselect.c index 598ead27de3..a5eb45c889d 100644 --- a/dlls/mshtml/htmlselect.c +++ b/dlls/mshtml/htmlselect.c @@ -635,9 +635,10 @@ static const tid_t HTMLOptionElementFactory_iface_tids[] = { static const dispex_static_data_vtbl_t HTMLOptionElementFactory_dispex_vtbl = { HTMLOptionElementFactory_value, - NULL, - NULL, - NULL + legacy_ctor_get_dispid, + legacy_ctor_get_name, + legacy_ctor_invoke, + legacy_ctor_delete }; dispex_static_data_t HTMLOptionElementFactory_dispex = { diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 6149774d6fb..c9873ee7779 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -152,8 +152,8 @@ static ULONG detach_inner_window(HTMLInnerWindow *window) return ref; } -static HRESULT get_legacy_ctor(HTMLInnerWindow *window, legacy_ctor_id_t ctor_id, dispex_static_data_t *dispex, - const void *vtbl, IDispatch **ret) +static HRESULT get_legacy_ctor(HTMLInnerWindow *window, legacy_ctor_id_t ctor_id, prototype_id_t prot_id, + dispex_static_data_t *dispex, const void *vtbl, IDispatch **ret) { struct legacy_ctor *ctor = window->legacy_ctors[ctor_id]; @@ -164,6 +164,7 @@ static HRESULT get_legacy_ctor(HTMLInnerWindow *window, legacy_ctor_id_t ctor_id ctor->IUnknown_iface.lpVtbl = vtbl; ctor->ref = 1; + ctor->prot_id = prot_id; ctor->window = window; window->legacy_ctors[ctor_id] = ctor; @@ -331,6 +332,10 @@ static void release_inner_window(HTMLInnerWindow *This) } } + for(i = 0; i < ARRAY_SIZE(This->legacy_prototypes); i++) + if(This->legacy_prototypes[i]) + IUnknown_Release(&This->legacy_prototypes[i]->IUnknown_iface); + if(This->screen) IHTMLScreen_Release(This->screen); @@ -840,8 +845,8 @@ static HRESULT WINAPI HTMLWindow2_get_Image(IHTMLWindow2 *iface, IHTMLImageEleme TRACE("(%p)->(%p)\n", This, p); - hres = get_legacy_ctor(window, LEGACY_CTOR_ID_Image, &HTMLImageElementFactory_dispex, - &HTMLImageElementFactoryVtbl, &disp); + hres = get_legacy_ctor(window, LEGACY_CTOR_ID_Image, PROTO_ID_HTMLImgElement, + &HTMLImageElementFactory_dispex, &HTMLImageElementFactoryVtbl, &disp); if(SUCCEEDED(hres)) *p = &legacy_ctor_from_IDispatch(disp)->IHTMLImageElementFactory_iface; return hres; @@ -1389,8 +1394,8 @@ static HRESULT WINAPI HTMLWindow2_get_Option(IHTMLWindow2 *iface, IHTMLOptionEle TRACE("(%p)->(%p)\n", This, p); - hres = get_legacy_ctor(window, LEGACY_CTOR_ID_Option, &HTMLOptionElementFactory_dispex, - &HTMLOptionElementFactoryVtbl, &disp); + hres = get_legacy_ctor(window, LEGACY_CTOR_ID_Option, PROTO_ID_HTMLOptionElement, + &HTMLOptionElementFactory_dispex, &HTMLOptionElementFactoryVtbl, &disp); if(SUCCEEDED(hres)) *p = &legacy_ctor_from_IDispatch(disp)->IHTMLOptionElementFactory_iface; return hres; @@ -2082,8 +2087,8 @@ static HRESULT WINAPI HTMLWindow5_get_XMLHttpRequest(IHTMLWindow5 *iface, VARIAN return S_OK; } - hres = get_legacy_ctor(window, LEGACY_CTOR_ID_HTMLXMLHttpRequest, &HTMLXMLHttpRequestFactory_dispex, - &HTMLXMLHttpRequestFactoryVtbl, &disp); + hres = get_legacy_ctor(window, LEGACY_CTOR_ID_HTMLXMLHttpRequest, PROTO_ID_HTMLXMLHttpRequest, + &HTMLXMLHttpRequestFactory_dispex, &HTMLXMLHttpRequestFactoryVtbl, &disp); if(SUCCEEDED(hres)) { V_VT(p) = VT_DISPATCH; V_DISPATCH(p) = (IDispatch*)&legacy_ctor_from_IDispatch(disp)->IHTMLXMLHttpRequestFactory_iface; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 99fa79ad2c4..8479c24deca 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -641,9 +641,16 @@ struct legacy_ctor { LONG ref; + prototype_id_t prot_id; HTMLInnerWindow *window; }; +struct legacy_prototype { + IUnknown IUnknown_iface; + DispatchEx dispex; + LONG ref; +}; + typedef enum { GLOBAL_SCRIPTVAR, GLOBAL_ELEMENTVAR, @@ -796,6 +803,7 @@ struct HTMLInnerWindow { struct list bindings; struct legacy_ctor *legacy_ctors[LEGACY_CTOR_COUNT]; + struct legacy_prototype *legacy_prototypes[COMMON_PROTOTYPE_COUNT]; }; typedef enum { @@ -1164,6 +1172,11 @@ void set_window_uninitialized(HTMLOuterWindow*,HTMLDocumentNode*) DECLSPEC_HIDDE HRESULT update_window_doc(HTMLInnerWindow*) DECLSPEC_HIDDEN; HTMLOuterWindow *mozwindow_to_window(const mozIDOMWindowProxy*) DECLSPEC_HIDDEN; void get_top_window(HTMLOuterWindow*,HTMLOuterWindow**) DECLSPEC_HIDDEN; +struct legacy_prototype *get_legacy_prototype(HTMLInnerWindow*,prototype_id_t,compat_mode_t) DECLSPEC_HIDDEN; +HRESULT legacy_ctor_get_dispid(DispatchEx*,BSTR,DWORD,DISPID*) DECLSPEC_HIDDEN; +HRESULT legacy_ctor_get_name(DispatchEx*,DISPID,BSTR*) DECLSPEC_HIDDEN; +HRESULT legacy_ctor_invoke(DispatchEx*,IDispatch*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*) DECLSPEC_HIDDEN; +HRESULT legacy_ctor_delete(DispatchEx*,DISPID) DECLSPEC_HIDDEN; void HTMLLocation_Init(HTMLOuterWindow*) DECLSPEC_HIDDEN; HRESULT create_navigator(HTMLInnerWindow*,IOmNavigator**) DECLSPEC_HIDDEN; void detach_navigator(IOmNavigator*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index f3f58166242..f91b2dbc125 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1537,7 +1537,11 @@ static HRESULT HTMLXMLHttpRequestFactory_value(DispatchEx *iface, LCID lcid, WOR } static const dispex_static_data_vtbl_t HTMLXMLHttpRequestFactory_dispex_vtbl = { - HTMLXMLHttpRequestFactory_value + HTMLXMLHttpRequestFactory_value, + legacy_ctor_get_dispid, + legacy_ctor_get_name, + legacy_ctor_invoke, + legacy_ctor_delete }; static const tid_t HTMLXMLHttpRequestFactory_iface_tids[] = { From 65816ef1f774ab2d21f6f1a248d10e89d893125c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:03 +0200 Subject: [PATCH 0885/2777] mshtml: Retrieve legacy prototypes and associate them with respective objects. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This introduces a finalize_dispex in the vtbl, which will also be needed later when documents need to have different dispex data, depending on the compat mode, and need to be set delayed. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/dispex.c | 17 ++++++++++++++++- dlls/mshtml/htmldoc.c | 11 +++++++++++ dlls/mshtml/htmlelem.c | 1 + dlls/mshtml/htmllocation.c | 4 +++- dlls/mshtml/htmlwindow.c | 9 +++++++++ dlls/mshtml/mshtml_private.h | 4 ++++ dlls/mshtml/mutation.c | 15 +++++++++++++++ 7 files changed, 59 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index b67a8b40de6..bb9ee012a5d 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1931,7 +1931,7 @@ static BOOL ensure_real_info(DispatchEx *dispex) if(dispex->info != dispex->info->desc->delayed_init_info) return TRUE; - dispex->info = ensure_dispex_info(dispex->info->desc, dispex_compat_mode(dispex)); + dispex->info->desc->vtbl->finalize_dispex(dispex); return dispex->info != NULL; } @@ -3118,6 +3118,9 @@ void release_dispex(DispatchEx *This) if(This->proxy) This->proxy->lpVtbl->Unlinked(This->proxy, FALSE); + if(This->prototype) + IUnknown_Release(&This->prototype->IUnknown_iface); + if(!This->dynamic_data) return; @@ -3145,6 +3148,15 @@ void release_dispex(DispatchEx *This) free(This->dynamic_data); } +void finalize_delayed_init_dispex(DispatchEx *This, HTMLInnerWindow *window, dispex_static_data_t *data) +{ + compat_mode_t compat_mode = window->doc->document_mode; + + This->info = ensure_dispex_info(data, compat_mode); + if(!This->proxy && data->prototype_id < ARRAY_SIZE(window->legacy_prototypes)) + This->prototype = get_legacy_prototype(window, data->prototype_id, compat_mode); +} + void init_dispatch(DispatchEx *dispex, IUnknown *outer, dispex_static_data_t *data, HTMLInnerWindow *window, compat_mode_t compat_mode) { @@ -3153,6 +3165,7 @@ void init_dispatch(DispatchEx *dispex, IUnknown *outer, dispex_static_data_t *da dispex->IDispatchEx_iface.lpVtbl = (const IDispatchExVtbl*)&WineDispatchProxyPrivateVtbl; dispex->outer = outer; dispex->proxy = NULL; + dispex->prototype = NULL; dispex->dynamic_data = NULL; if(data->vtbl && data->vtbl->get_compat_mode) { @@ -3190,6 +3203,8 @@ void init_dispatch(DispatchEx *dispex, IUnknown *outer, dispex_static_data_t *da if(FAILED(hres)) ERR("InitProxy failed: %08lx\n", hres); } + }else if(data->prototype_id < ARRAY_SIZE(window->legacy_prototypes)) { + dispex->prototype = get_legacy_prototype(window, data->prototype_id, compat_mode); } } } diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 688c55206d0..377973a1796 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -6266,6 +6266,16 @@ static compat_mode_t HTMLDocumentNode_get_compat_mode(DispatchEx *dispex) return lock_document_mode(This); } +static void HTMLDocumentNode_finalize_dispex(DispatchEx *dispex) +{ + HTMLDocumentNode *This = impl_from_DispatchEx(dispex); + + lock_document_mode(This); + + /* FIXME: IE9 and IE10 have different dispex data */ + finalize_delayed_init_dispex(dispex, get_inner_window(This), &HTMLDocumentNode_dispex); +} + static nsISupports *HTMLDocumentNode_get_gecko_target(DispatchEx *dispex) { HTMLDocumentNode *This = impl_from_DispatchEx(dispex); @@ -6326,6 +6336,7 @@ static const event_target_vtbl_t HTMLDocumentNode_event_target_vtbl = { NULL, NULL, HTMLDocumentNode_get_compat_mode, + HTMLDocumentNode_finalize_dispex, NULL }, NULL, diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 766e7e3bf75..635b9497d04 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -7247,6 +7247,7 @@ static event_target_vtbl_t HTMLElement_event_target_vtbl = { NULL, NULL, NULL, + NULL, HTMLElement_populate_props }, NULL, diff --git a/dlls/mshtml/htmllocation.c b/dlls/mshtml/htmllocation.c index cb88bc300c8..d8265f3d02c 100644 --- a/dlls/mshtml/htmllocation.c +++ b/dlls/mshtml/htmllocation.c @@ -621,8 +621,10 @@ dispex_static_data_t HTMLLocation_dispex = { void HTMLLocation_Init(HTMLOuterWindow *window) { + compat_mode_t compat_mode = dispex_compat_mode(&window->base.inner_window->event_target.dispex); + window->location.IHTMLLocation_iface.lpVtbl = &HTMLLocationVtbl; init_dispatch(&window->location.dispex, (IUnknown*)&window->location.IHTMLLocation_iface, &HTMLLocation_dispex, - window->base.inner_window, COMPAT_MODE_QUIRKS); + window->base.inner_window, min(compat_mode, COMPAT_MODE_IE8)); } diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index c9873ee7779..a629d866cf9 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -4346,6 +4346,14 @@ static compat_mode_t HTMLWindow_get_compat_mode(DispatchEx *dispex) return compat_mode; } +static void HTMLWindow_finalize_dispex(DispatchEx *dispex) +{ + HTMLInnerWindow *This = impl_from_DispatchEx(dispex); + + HTMLWindow_get_compat_mode(dispex); + finalize_delayed_init_dispex(dispex, This, &HTMLWindow_dispex); +} + static IDispatch *HTMLWindow_get_dispatch_this(DispatchEx *dispex) { HTMLInnerWindow *This = impl_from_DispatchEx(dispex); @@ -4518,6 +4526,7 @@ static const event_target_vtbl_t HTMLWindow_event_target_vtbl = { NULL, NULL, HTMLWindow_get_compat_mode, + HTMLWindow_finalize_dispex, NULL }, HTMLWindow_get_dispatch_this, diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 8479c24deca..3fcad22f0bb 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -526,6 +526,7 @@ typedef struct dispex_dynamic_data_t dispex_dynamic_data_t; #define MSHTML_CUSTOM_DISPID_CNT (MSHTML_DISPID_CUSTOM_MAX-MSHTML_DISPID_CUSTOM_MIN) typedef struct DispatchEx DispatchEx; +struct legacy_prototype; typedef struct { HRESULT (*value)(DispatchEx*,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*); @@ -537,6 +538,7 @@ typedef struct { HRESULT (*override)(DispatchEx*,const WCHAR*,VARIANT*); HRESULT (*get_static_dispid)(compat_mode_t,BSTR,DWORD,DISPID*); compat_mode_t (*get_compat_mode)(DispatchEx*); + void (*finalize_dispex)(DispatchEx*); HRESULT (*populate_props)(DispatchEx*); } dispex_static_data_vtbl_t; @@ -567,6 +569,7 @@ struct DispatchEx { IUnknown *outer; IWineDispatchProxyCbPrivate *proxy; + struct legacy_prototype *prototype; dispex_data_t *info; dispex_dynamic_data_t *dynamic_data; @@ -601,6 +604,7 @@ extern void (__cdecl *note_cc_edge)(nsISupports*,const char*,nsCycleCollectionTr void init_proxies(HTMLInnerWindow*) DECLSPEC_HIDDEN; void init_dispatch(DispatchEx*,IUnknown*,dispex_static_data_t*,HTMLInnerWindow*,compat_mode_t) DECLSPEC_HIDDEN; +void finalize_delayed_init_dispex(DispatchEx*,HTMLInnerWindow*,dispex_static_data_t*) DECLSPEC_HIDDEN; void release_dispex(DispatchEx*) DECLSPEC_HIDDEN; BOOL dispex_query_interface(DispatchEx*,REFIID,void**) DECLSPEC_HIDDEN; HRESULT change_type(VARIANT*,VARIANT*,VARTYPE,IServiceProvider*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/mutation.c b/dlls/mshtml/mutation.c index c932f5017c0..2a014548a89 100644 --- a/dlls/mshtml/mutation.c +++ b/dlls/mshtml/mutation.c @@ -398,6 +398,17 @@ static void setup_doc_proxy(HTMLDocumentNode *doc) } } +static void update_location_dispex(HTMLDocumentNode *doc) +{ + HTMLOuterWindow *outer_window = doc->window->base.outer_window; + + if(outer_window->location.dispex.outer) { + if(outer_window->location.dispex.prototype) + IUnknown_Release(&outer_window->location.dispex.prototype->IUnknown_iface); + outer_window->location.dispex.prototype = get_legacy_prototype(doc->window, PROTO_ID_HTMLLocation, min(doc->document_mode, COMPAT_MODE_IE8)); + } +} + /* * We may change document mode only in early stage of document lifetime. * Later attempts will not have an effect. @@ -413,6 +424,10 @@ compat_mode_t lock_document_mode(HTMLDocumentNode *doc) methods so we can't rely on the delay init of the dispex to set them up. */ if(doc->document_mode >= COMPAT_MODE_IE9) setup_doc_proxy(doc); + + /* location is special case since it's tied to the outer window */ + if(doc->window) + update_location_dispex(doc); } return doc->document_mode; } From 1e41b252352fed559bb5298418d8f1a230ab015b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:03 +0200 Subject: [PATCH 0886/2777] mshtml: Lookup the legacy prototypes props if not available on the object. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Native's behavior in these modes tries to emulate jscript's prototypes. Signed-off-by: Gabriel Ivăncescu --- Note that only function builtins are looked up, the accessor builtins are irrelevant in legacy prototypes (because they always return undefined). --- dlls/mshtml/dispex.c | 130 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 107 insertions(+), 23 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index bb9ee012a5d..b8c2f1118b8 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -92,6 +92,7 @@ struct proxy_prototype { #define DYNPROP_DELETED 0x01 #define DYNPROP_HIDDEN 0x02 +#define DYNPROP_PROTREF 0x04 /* V_VT(var) == VT_EMPTY and V_UI4(var) == the ref */ typedef struct { DispatchEx dispex; @@ -185,6 +186,7 @@ static inline dispex_data_t *proxy_prototype_object_info(struct proxy_prototype } static func_disp_t *create_func_disp(DispatchEx*,func_info_t*); +static HRESULT get_dynamic_prop(DispatchEx*,const WCHAR*,DWORD,dynamic_prop_t**); static HRESULT invoke_builtin_function(IDispatch*,func_info_t*,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*); static inline struct proxy_prototype *to_proxy_prototype(DispatchEx*); @@ -719,6 +721,26 @@ static HRESULT variant_copy(VARIANT *dest, VARIANT *src) return VariantCopy(dest, src); } +static void fixup_prop_ref(DispatchEx *This, dynamic_prop_t *prop) +{ + dynamic_prop_t *prot_prop; + + if(prop->flags & DYNPROP_DELETED) { + if(!This->prototype || + FAILED(get_dynamic_prop(&This->prototype->dispex, prop->name, fdexNameCaseSensitive, &prot_prop))) + return; + if(!(prot_prop->flags & DYNPROP_DELETED)) { + prop->flags = DYNPROP_PROTREF; + V_UI4(&prop->var) = prot_prop - This->prototype->dispex.dynamic_data->props; + } + return; + } + + if((prop->flags & DYNPROP_PROTREF) && + (This->prototype->dispex.dynamic_data->props[V_UI4(&prop->var)].flags & DYNPROP_DELETED)) + prop->flags = DYNPROP_DELETED; +} + static inline dispex_dynamic_data_t *get_dynamic_data(DispatchEx *This) { if(This->dynamic_data) @@ -737,8 +759,8 @@ static inline dispex_dynamic_data_t *get_dynamic_data(DispatchEx *This) static HRESULT get_dynamic_prop(DispatchEx *This, const WCHAR *name, DWORD flags, dynamic_prop_t **ret) { const BOOL alloc = flags & fdexNameEnsure; + dynamic_prop_t *prop, *prot_prop = NULL; dispex_dynamic_data_t *data; - dynamic_prop_t *prop; data = get_dynamic_data(This); if(!data) @@ -746,6 +768,7 @@ static HRESULT get_dynamic_prop(DispatchEx *This, const WCHAR *name, DWORD flags for(prop = data->props; prop < data->props+data->prop_cnt; prop++) { if(flags & fdexNameCaseInsensitive ? !wcsicmp(prop->name, name) : !wcscmp(prop->name, name)) { + fixup_prop_ref(This, prop); if(prop->flags & DYNPROP_DELETED) { if(!alloc) return DISP_E_UNKNOWNNAME; @@ -756,7 +779,17 @@ static HRESULT get_dynamic_prop(DispatchEx *This, const WCHAR *name, DWORD flags } } - if(!alloc) + if(This->prototype) { + HRESULT hres = get_dynamic_prop(&This->prototype->dispex, name, fdexNameCaseSensitive, &prot_prop); + if(hres != DISP_E_UNKNOWNNAME) { + if(FAILED(hres)) + return hres; + if(prot_prop->flags & DYNPROP_DELETED) + prot_prop = NULL; + } + } + + if(!alloc && !prot_prop) return DISP_E_UNKNOWNNAME; TRACE("creating dynamic prop %s\n", debugstr_w(name)); @@ -785,6 +818,10 @@ static HRESULT get_dynamic_prop(DispatchEx *This, const WCHAR *name, DWORD flags VariantInit(&prop->var); prop->flags = 0; + if(prot_prop) { + prop->flags = DYNPROP_PROTREF; + V_UI4(&prop->var) = prot_prop - This->prototype->dispex.dynamic_data->props; + } data->prop_cnt++; *ret = prop; return S_OK; @@ -801,6 +838,7 @@ HRESULT dispex_get_dprop_ref(DispatchEx *This, const WCHAR *name, BOOL alloc, VA if(alloc) prop->flags |= DYNPROP_HIDDEN; + prop->flags &= ~DYNPROP_PROTREF; *ret = &prop->var; return S_OK; } @@ -816,6 +854,7 @@ HRESULT dispex_get_dynid(DispatchEx *This, const WCHAR *name, BOOL hidden, DISPI if(hidden) prop->flags |= DYNPROP_HIDDEN; + prop->flags &= ~DYNPROP_PROTREF; *id = DISPID_DYNPROP_0 + (prop - This->dynamic_data->props); return S_OK; } @@ -1263,11 +1302,33 @@ static HRESULT invoke_disp_value(IDispatch *this_obj, IDispatch *func_disp, LCID return hres; } -static HRESULT get_func_obj_entry(DispatchEx *This, func_info_t *func, func_obj_entry_t **ret) +static HRESULT get_func_obj_entry(DispatchEx *This, struct legacy_prototype *prototype, func_info_t *func, + func_obj_entry_t **ret) { dispex_dynamic_data_t *dynamic_data; func_obj_entry_t *entry; + /* Use the prototype's if it's not the default while ours is */ + if(prototype && prototype->dispex.dynamic_data && prototype->dispex.dynamic_data->func_disps && + prototype->dispex.dynamic_data->func_disps[func->func_disp_idx].func_obj) { + func_obj_entry_t *prot_entry = prototype->dispex.dynamic_data->func_disps + func->func_disp_idx; + + if(V_VT(&prot_entry->val) != VT_DISPATCH || + V_DISPATCH(&prot_entry->val) != (IDispatch*)&prot_entry->func_obj->dispex.IDispatchEx_iface) { + entry = NULL; + if(This->dynamic_data && This->dynamic_data->func_disps && + This->dynamic_data->func_disps[func->func_disp_idx].func_obj) { + entry = This->dynamic_data->func_disps + func->func_disp_idx; + + if(V_VT(&entry->val) == VT_DISPATCH && + V_DISPATCH(&entry->val) == (IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface) + entry = NULL; + } + *ret = entry ? entry : prot_entry; + return S_OK; + } + } + dynamic_data = get_dynamic_data(This); if(!dynamic_data) return E_OUTOFMEMORY; @@ -1626,6 +1687,7 @@ static HRESULT invoke_builtin_function(IDispatch *this_obj, func_info_t *func, D static HRESULT func_invoke(DispatchEx *This, IDispatch *this_obj, func_info_t *func, WORD flags, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { + func_obj_entry_t *entry; HRESULT hres; switch(flags) { @@ -1634,10 +1696,24 @@ static HRESULT func_invoke(DispatchEx *This, IDispatch *this_obj, func_info_t *f return E_INVALIDARG; /* fall through */ case DISPATCH_METHOD: - if(This->dynamic_data && This->dynamic_data->func_disps - && This->dynamic_data->func_disps[func->func_disp_idx].func_obj) { - func_obj_entry_t *entry = This->dynamic_data->func_disps + func->func_disp_idx; + entry = NULL; + + if(This->dynamic_data && This->dynamic_data->func_disps && + This->dynamic_data->func_disps[func->func_disp_idx].func_obj) { + entry = This->dynamic_data->func_disps + func->func_disp_idx; + + if(V_VT(&entry->val) == VT_DISPATCH && + V_DISPATCH(&entry->val) == (IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface) + entry = NULL; + } + + if(!entry && This->prototype) { + if(This->prototype->dispex.dynamic_data && This->prototype->dispex.dynamic_data->func_disps && + This->prototype->dispex.dynamic_data->func_disps[func->func_disp_idx].func_obj) + entry = This->prototype->dispex.dynamic_data->func_disps + func->func_disp_idx; + } + if(entry) { if(V_VT(&entry->val) != VT_DISPATCH) { FIXME("calling %s not supported\n", debugstr_variant(&entry->val)); return E_NOTIMPL; @@ -1658,9 +1734,7 @@ static HRESULT func_invoke(DispatchEx *This, IDispatch *this_obj, func_info_t *f if(hres == E_UNEXPECTED && dispex_compat_mode(This) < COMPAT_MODE_IE9) hres = MSHTML_E_INVALID_PROPERTY; break; - case DISPATCH_PROPERTYGET: { - func_obj_entry_t *entry; - + case DISPATCH_PROPERTYGET: if(func->id == DISPID_VALUE) { BSTR ret; @@ -1673,16 +1747,13 @@ static HRESULT func_invoke(DispatchEx *This, IDispatch *this_obj, func_info_t *f return S_OK; } - hres = get_func_obj_entry(This, func, &entry); + hres = get_func_obj_entry(This, This->prototype, func, &entry); if(FAILED(hres)) return hres; V_VT(res) = VT_EMPTY; return VariantCopy(res, &entry->val); - } - case DISPATCH_PROPERTYPUT: { - func_obj_entry_t *entry; - + case DISPATCH_PROPERTYPUT: if(dp->cArgs != 1 || (dp->cNamedArgs == 1 && *dp->rgdispidNamedArgs != DISPID_PROPERTYPUT) || dp->cNamedArgs > 1) { FIXME("invalid args\n"); @@ -1695,12 +1766,11 @@ static HRESULT func_invoke(DispatchEx *This, IDispatch *this_obj, func_info_t *f * Native probably uses some undocumented interface in this case, but it should * be fine for us to allow IDispatchEx handle that. */ - hres = get_func_obj_entry(This, func, &entry); + hres = get_func_obj_entry(This, NULL, func, &entry); if(FAILED(hres)) return hres; return VariantCopy(&entry->val, dp->rgvarg); - } default: FIXME("Unimplemented flags %x\n", flags); hres = E_NOTIMPL; @@ -1836,8 +1906,10 @@ HRESULT remove_attribute(DispatchEx *This, DISPID id, VARIANT_BOOL *success) dynamic_prop_t *prop; prop = This->dynamic_data->props+idx; - VariantClear(&prop->var); - prop->flags |= DYNPROP_DELETED; + if(!(prop->flags & DYNPROP_PROTREF)) { + VariantClear(&prop->var); + prop->flags |= DYNPROP_DELETED; + } *success = VARIANT_TRUE; return S_OK; } @@ -2561,8 +2633,9 @@ static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BS static HRESULT next_dynamic_id(DispatchEx *dispex, DWORD idx, DISPID *ret_id) { + /* FIXME: Go through PROTREFs? (must exclude props with same name as builtins) */ while(idx < dispex->dynamic_data->prop_cnt && - (dispex->dynamic_data->props[idx].flags & (DYNPROP_DELETED | DYNPROP_HIDDEN))) + (dispex->dynamic_data->props[idx].flags & (DYNPROP_DELETED | DYNPROP_HIDDEN | DYNPROP_PROTREF))) idx++; if(idx == dispex->dynamic_data->prop_cnt) { @@ -2860,7 +2933,7 @@ static HRESULT WINAPI WineDispatchProxyPrivate_PropEnum(IWineDispatchProxyPrivat return E_OUTOFMEMORY; for(dyn_prop = dyn_data->props, dyn_prop_end = dyn_prop + dyn_data->prop_cnt; dyn_prop != dyn_prop_end; dyn_prop++) { - if(!(dyn_prop->flags & (DYNPROP_DELETED | DYNPROP_HIDDEN))) { + if(!(dyn_prop->flags & (DYNPROP_DELETED | DYNPROP_HIDDEN | DYNPROP_PROTREF))) { hres = callback(obj, dyn_prop->name); if(FAILED(hres)) return hres; @@ -2977,6 +3050,12 @@ HRESULT dispex_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID l return E_INVALIDARG; /* fall through */ case DISPATCH_METHOD: + fixup_prop_ref(dispex, prop); + if(prop->flags & DYNPROP_DELETED) + return DISP_E_MEMBERNOTFOUND; + if(prop->flags & DYNPROP_PROTREF) + prop = &dispex->prototype->dispex.dynamic_data->props[V_UI4(&prop->var)]; + if(V_VT(&prop->var) != VT_DISPATCH) { FIXME("invoke %s\n", debugstr_variant(&prop->var)); return E_NOTIMPL; @@ -2984,8 +3063,11 @@ HRESULT dispex_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID l return invoke_disp_value(this_obj, V_DISPATCH(&prop->var), lcid, wFlags, pdp, res, pei, caller); case DISPATCH_PROPERTYGET: + fixup_prop_ref(dispex, prop); if(prop->flags & DYNPROP_DELETED) return DISP_E_MEMBERNOTFOUND; + if(prop->flags & DYNPROP_PROTREF) + prop = &dispex->prototype->dispex.dynamic_data->props[V_UI4(&prop->var)]; V_VT(res) = VT_EMPTY; return variant_copy(res, &prop->var); case DISPATCH_PROPERTYPUT: @@ -3001,7 +3083,7 @@ HRESULT dispex_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID l if(FAILED(hres)) return hres; - prop->flags &= ~DYNPROP_DELETED; + prop->flags &= ~(DYNPROP_DELETED | DYNPROP_PROTREF); return S_OK; default: FIXME("unhandled wFlags %x\n", wFlags); @@ -3049,8 +3131,10 @@ HRESULT dispex_delete_prop(DispatchEx *dispex, DISPID id) return S_OK; prop = dispex->dynamic_data->props + idx; - VariantClear(&prop->var); - prop->flags |= DYNPROP_DELETED; + if(!(prop->flags & DYNPROP_PROTREF)) { + VariantClear(&prop->var); + prop->flags |= DYNPROP_DELETED; + } return S_OK; } case DISPEXPROP_BUILTIN: { From 0d7a15d69097ae5bf025ffacc169f8c8b53486e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:03 +0200 Subject: [PATCH 0887/2777] mshtml: Implement constructors for builtin object proxies. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/dispex.c | 124 +++++++++++++++++- dlls/jscript/function.c | 155 +++++++++++++++++++++++ dlls/jscript/jscript.c | 14 +-- dlls/jscript/jscript.h | 11 +- dlls/mshtml/dispex.c | 238 ++++++++++++++++++++++++++++++++++- dlls/mshtml/htmldoc.c | 16 +++ dlls/mshtml/htmlimg.c | 3 + dlls/mshtml/htmlselect.c | 3 + dlls/mshtml/htmlwindow.c | 19 +++ dlls/mshtml/mshtml_private.h | 9 +- dlls/mshtml/xmlhttprequest.c | 3 + 11 files changed, 576 insertions(+), 19 deletions(-) diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 9dc906e5584..904e12a1960 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2429,7 +2429,7 @@ static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown } /* ECMA-262 5.1 Edition 15.1 */ -HRESULT set_js_globals(jsdisp_t *obj) +static HRESULT set_js_globals(jsdisp_t *obj) { jsdisp_t *js_global = obj->ctx->js_global; const builtin_prop_t *bprop, *bend; @@ -2508,6 +2508,45 @@ static HRESULT get_proxy_default_prototype(script_ctx_t *ctx, IWineDispatchProxy return S_OK; } +static HRESULT get_proxy_default_constructor(script_ctx_t *ctx, jsdisp_t *prot, jsdisp_t **ctor) +{ + IDispatch *disp = prot->proxy->lpVtbl->GetDefaultConstructor(prot->proxy, ctx->global->proxy, ctx->proxy_prototypes); + HRESULT hres; + jsval_t tmp; + + if(!disp) + return E_OUTOFMEMORY; + + tmp = jsval_disp(disp); + hres = convert_to_proxy(ctx, &tmp); + if(FAILED(hres)) + return hres; + *ctor = as_jsdisp(get_object(tmp)); + + hres = jsdisp_define_data_property(*ctor, L"prototype", 0, jsval_obj(prot)); + if(FAILED(hres)) + jsdisp_release(*ctor); + return hres; +} + +static HRESULT maybe_init_global_proxy(jsdisp_t *jsdisp) +{ + script_ctx_t *ctx = jsdisp->ctx; + jsdisp_t *tmp = ctx->global; + HRESULT hres; + + /* DefineConstructors may end up in CreateConstructor from GetDefaultConstructor via some + prototype's setup, which assumes the global to be the one required. Since we can have + window objects that are not the actual global (e.g. from iframe), set it temporarily. */ + ctx->global = jsdisp; + hres = jsdisp->proxy->lpVtbl->DefineConstructors(jsdisp->proxy, &ctx->proxy_prototypes); + ctx->global = tmp; + + if(hres == S_OK) + hres = set_js_globals(jsdisp); + return hres; +} + static inline jsdisp_t *impl_from_IWineDispatchProxyCbPrivate(IWineDispatchProxyCbPrivate *iface) { return impl_from_IDispatchEx((IDispatchEx*)iface); @@ -2604,7 +2643,74 @@ static HRESULT WINAPI WineDispatchProxyCbPrivate_HostUpdated(IWineDispatchProxyC alloc_proxy_prop(This, &info, &prop); } - return S_OK; + return maybe_init_global_proxy(This); +} + +static IDispatch* WINAPI WineDispatchProxyCbPrivate_CreateConstructor(IWineDispatchProxyCbPrivate *iface, + IDispatch *disp, const WCHAR *name) +{ + jsdisp_t *This = impl_from_IWineDispatchProxyCbPrivate(iface); + jsdisp_t *ctor; + HRESULT hres; + + hres = create_proxy_constructor(disp, name, This, &ctor); + return SUCCEEDED(hres) ? (IDispatch*)&ctor->IDispatchEx_iface : NULL; +} + +static HRESULT WINAPI WineDispatchProxyCbPrivate_DefineConstructor(IWineDispatchProxyCbPrivate *iface, + const WCHAR *name, IDispatch *prot_disp, IDispatch *ctor_disp) +{ + jsdisp_t *This = impl_from_IWineDispatchProxyCbPrivate(iface); + jsval_t val = jsval_disp(prot_disp); + unsigned hash = string_hash(name); + jsdisp_t *prot, *ctor; + dispex_prop_t *prop; + HRESULT hres; + BOOL b; + + hres = convert_to_proxy(This->ctx, &val); + if(FAILED(hres)) + return hres; + prot = as_jsdisp(get_object(val)); + + if(ctor_disp) + hres = create_proxy_constructor(ctor_disp, name, prot, &ctor); + else { + /* The prototype's proxy should have already set up the constructor, so it can't fail */ + val = jsval_disp(prot->proxy->lpVtbl->GetDefaultConstructor(prot->proxy, This->proxy, This->ctx->proxy_prototypes)); + convert_to_proxy(This->ctx, &val); + ctor = as_jsdisp(get_object(val)); + } + jsdisp_release(prot); + if(FAILED(hres)) + return hres; + + /* Remove the builtin proxy prop from the prototype (first time only), since it's part of the object itself */ + if(!find_prop_name_raw(This->prototype, hash, name, FALSE) && !alloc_prop(This->prototype, name, PROP_DELETED, 0)) { + hres = E_OUTOFMEMORY; + goto end; + } + + /* Define the constructor forcefully, so make sure to not look into the underlying proxy dispids, + otherwise it might pick up elements by this id. And if any found, force it to be configurable. */ + prop = find_prop_name_raw(This, hash, name, FALSE); + if(prop) { + prop->flags |= PROPF_CONFIGURABLE; + delete_prop(This, prop, &b); + }else if(!(prop = alloc_prop(This, name, PROP_DELETED, 0))) { + hres = E_OUTOFMEMORY; + goto end; + } + + hres = jsval_copy(jsval_obj(ctor), &prop->u.val); + if(FAILED(hres)) + goto end; + prop->type = PROP_JSVAL; + prop->flags = PROPF_WRITABLE | PROPF_CONFIGURABLE; + +end: + jsdisp_release(ctor); + return hres; } static HRESULT WINAPI WineDispatchProxyCbPrivate_PropEnum(IWineDispatchProxyCbPrivate *iface, const WCHAR *name) @@ -2638,6 +2744,8 @@ static IWineDispatchProxyCbPrivateVtbl WineDispatchProxyCbPrivateVtbl = { WineDispatchProxyCbPrivate_InitProxy, WineDispatchProxyCbPrivate_Unlinked, WineDispatchProxyCbPrivate_HostUpdated, + WineDispatchProxyCbPrivate_CreateConstructor, + WineDispatchProxyCbPrivate_DefineConstructor, WineDispatchProxyCbPrivate_PropEnum }; @@ -2777,10 +2885,14 @@ HRESULT convert_to_proxy(script_ctx_t *ctx, jsval_t *val) *proxy_ref = (IWineDispatchProxyCbPrivate*)&jsdisp->IDispatchEx_iface; jsdisp->proxy = proxy; if(proxy->lpVtbl->IsPrototype(proxy)) { - /* FIXME: use proper constructor */ - jsval_t ctor = jsval_null(); - - hres = jsdisp_define_data_property(jsdisp, L"constructor", PROPF_WRITABLE | PROPF_CONFIGURABLE, ctor); + jsdisp_t *ctor; + hres = get_proxy_default_constructor(ctx, jsdisp, &ctor); + if(SUCCEEDED(hres)) { + hres = jsdisp_define_data_property(jsdisp, L"constructor", PROPF_WRITABLE | PROPF_CONFIGURABLE, jsval_obj(ctor)); + jsdisp_release(ctor); + } + }else { + hres = maybe_init_global_proxy(jsdisp); } if(FAILED(hres)) { *proxy_ref = NULL; diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 2ada34e1543..83b33b68362 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -17,6 +17,7 @@ */ #include +#include #include "jscript.h" #include "engine.h" @@ -61,6 +62,17 @@ typedef struct { const WCHAR *name; } ProxyFunction; +typedef struct { + FunctionInstance function; + IDispatch *disp; + const WCHAR *name; +} ProxyConstructor; + +typedef struct { + FunctionInstance function; + ProxyConstructor *ctor; +} ProxyConstructorCreate; + typedef struct { FunctionInstance function; FunctionInstance *target; @@ -885,6 +897,149 @@ HRESULT create_proxy_functions(jsdisp_t *jsdisp, const struct proxy_prop_info *i return S_OK; } +static HRESULT ProxyConstructor_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags, + unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) +{ + ProxyConstructor *constructor = (ProxyConstructor*)func; + + return disp_call_value(ctx, constructor->disp, jsval_undefined(), flags & ~DISPATCH_JSCRIPT_INTERNAL_MASK, argc, argv, r, caller); +} + +static HRESULT ProxyConstructor_toString(FunctionInstance *func, jsstr_t **ret) +{ + ProxyConstructor *constructor = (ProxyConstructor*)func; + return native_code_toString(constructor->name, ret); +} + +static function_code_t *ProxyConstructor_get_code(FunctionInstance *func) +{ + return NULL; +} + +static void ProxyConstructor_destructor(FunctionInstance *func) +{ + ProxyConstructor *constructor = (ProxyConstructor*)func; + IDispatch_Release(constructor->disp); +} + +static const function_vtbl_t ProxyConstructorVtbl = { + ProxyConstructor_call, + ProxyConstructor_toString, + ProxyConstructor_get_code, + ProxyConstructor_destructor, + no_gc_traverse +}; + +static const builtin_prop_t ProxyConstructor_props[] = { + {L"arguments", NULL, 0, Function_get_arguments} +}; + +static const builtin_info_t ProxyConstructor_info = { + JSCLASS_FUNCTION, + Function_value, + ARRAY_SIZE(ProxyConstructor_props), + ProxyConstructor_props, + Function_destructor, + NULL +}; + +static HRESULT ProxyConstructorCreate_call(script_ctx_t *ctx, FunctionInstance *func, jsval_t vthis, unsigned flags, + unsigned argc, jsval_t *argv, jsval_t *r, IServiceProvider *caller) +{ + ProxyConstructorCreate *create = (ProxyConstructorCreate*)func; + + /* only allow calls since it's a method */ + if(!(flags & DISPATCH_METHOD)) + return E_UNEXPECTED; + + return disp_call_value(ctx, create->ctor->disp, jsval_undefined(), flags & ~DISPATCH_JSCRIPT_INTERNAL_MASK, argc, argv, r, caller); +} + +static HRESULT ProxyConstructorCreate_toString(FunctionInstance *func, jsstr_t **ret) +{ + return native_code_toString(L"create", ret); +} + +static function_code_t *ProxyConstructorCreate_get_code(FunctionInstance *func) +{ + return NULL; +} + +static void ProxyConstructorCreate_destructor(FunctionInstance *func) +{ + ProxyConstructorCreate *create = (ProxyConstructorCreate*)func; + if(create->ctor) + jsdisp_release(&create->ctor->function.dispex); +} + +static HRESULT ProxyConstructorCreate_gc_traverse(struct gc_ctx *gc_ctx, enum gc_traverse_op op, FunctionInstance *func) +{ + ProxyConstructorCreate *create = (ProxyConstructorCreate*)func; + return gc_process_linked_obj(gc_ctx, op, &create->function.dispex, &create->ctor->function.dispex, (void**)&create->ctor); +} + +static const function_vtbl_t ProxyConstructorCreateVtbl = { + ProxyConstructorCreate_call, + ProxyConstructorCreate_toString, + ProxyConstructorCreate_get_code, + ProxyConstructorCreate_destructor, + ProxyConstructorCreate_gc_traverse +}; + +static const builtin_info_t ProxyConstructorCreate_info = { + JSCLASS_FUNCTION, + Function_value, + ARRAY_SIZE(ProxyConstructor_props), + ProxyConstructor_props, + Function_destructor, + NULL, + NULL, + NULL, + NULL, + Function_gc_traverse +}; + +HRESULT create_proxy_constructor(IDispatch *disp, const WCHAR *name, jsdisp_t *prototype, jsdisp_t **ret) +{ + script_ctx_t *ctx = prototype->ctx; + ProxyConstructor *constructor; + HRESULT hres; + + /* create wrapper constructor function over the disp's value */ + hres = create_function(ctx, &ProxyConstructor_info, &ProxyConstructorVtbl, sizeof(ProxyConstructor), + PROPF_CONSTR, FALSE, NULL, (void**)&constructor); + if(FAILED(hres)) + return hres; + + IDispatch_AddRef(disp); + constructor->disp = disp; + constructor->name = name; + + hres = jsdisp_define_data_property(&constructor->function.dispex, L"prototype", 0, jsval_obj(prototype)); + if(SUCCEEDED(hres)) { + ProxyConstructorCreate *create; + + hres = create_function(ctx, &ProxyConstructorCreate_info, &ProxyConstructorCreateVtbl, sizeof(ProxyConstructorCreate), + PROPF_METHOD, FALSE, NULL, (void**)&create); + if(SUCCEEDED(hres)) { + create->ctor = constructor; + jsdisp_addref(&constructor->function.dispex); + + hres = jsdisp_define_data_property(&create->function.dispex, L"prototype", 0, jsval_null()); + if(SUCCEEDED(hres)) + hres = jsdisp_define_data_property(&constructor->function.dispex, L"create", 0, jsval_obj(&create->function.dispex)); + jsdisp_release(&create->function.dispex); + } + } + if(FAILED(hres)) { + jsdisp_release(&constructor->function.dispex); + return hres; + } + + *ret = &constructor->function.dispex; + return S_OK; +} + /* * Create the actual prototype on demand, since it is a circular ref, which prevents the vast * majority of functions from being released quickly, leading to unnecessary scope detach. diff --git a/dlls/jscript/jscript.c b/dlls/jscript/jscript.c index 3b0c334b924..2c3c259ed9a 100644 --- a/dlls/jscript/jscript.c +++ b/dlls/jscript/jscript.c @@ -505,9 +505,12 @@ static void decrease_state(JScript *This, SCRIPTSTATE state) } if(This->ctx->proxy_prototypes) { - for(i = 0; i < This->ctx->proxy_prototypes->num; i++) - if(This->ctx->proxy_prototypes->prototype[i]) - IDispatch_Release(This->ctx->proxy_prototypes->prototype[i]); + for(i = 0; i < This->ctx->proxy_prototypes->num; i++) { + if(This->ctx->proxy_prototypes->disp[i].prototype) + IDispatch_Release(This->ctx->proxy_prototypes->disp[i].prototype); + if(This->ctx->proxy_prototypes->disp[i].ctor) + IDispatch_Release(This->ctx->proxy_prototypes->disp[i].ctor); + } free(This->ctx->proxy_prototypes); This->ctx->proxy_prototypes = NULL; @@ -935,11 +938,6 @@ static HRESULT WINAPI JScript_AddNamedItem(IActiveScript *iface, disp = get_object(val); if((jsdisp = to_jsdisp(disp)) && jsdisp->proxy) { - hres = set_js_globals(jsdisp); - if(FAILED(hres)) { - jsdisp_release(jsdisp); - return hres; - } jsdisp_release(This->ctx->global); This->ctx->global = jsdisp_addref(jsdisp); } diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 1cd44e18458..7c9d234f822 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -59,7 +59,10 @@ typedef struct _IWineDispatchProxyCbPrivate IWineDispatchProxyCbPrivate; struct proxy_prototypes { unsigned int num; - IDispatch *prototype[]; + struct { + IDispatch *prototype; + IDispatch *ctor; + } disp[]; }; struct proxy_func_invoker @@ -80,6 +83,8 @@ typedef struct { IDispatchExVtbl dispex; IWineDispatchProxyCbPrivate** (STDMETHODCALLTYPE *GetProxyFieldRef)(IWineDispatchProxyPrivate *This); IDispatch* (STDMETHODCALLTYPE *GetDefaultPrototype)(IWineDispatchProxyPrivate *This, struct proxy_prototypes **prots_ref); + IDispatch* (STDMETHODCALLTYPE *GetDefaultConstructor)(IWineDispatchProxyPrivate *This, IWineDispatchProxyPrivate *window, struct proxy_prototypes *prots); + HRESULT (STDMETHODCALLTYPE *DefineConstructors)(IWineDispatchProxyPrivate *This, struct proxy_prototypes **prots_ref); BOOL (STDMETHODCALLTYPE *IsPrototype)(IWineDispatchProxyPrivate *This); HRESULT (STDMETHODCALLTYPE *PropFixOverride)(IWineDispatchProxyPrivate *This, struct proxy_prop_info *info); HRESULT (STDMETHODCALLTYPE *PropOverride)(IWineDispatchProxyPrivate *This, const WCHAR *name, VARIANT *value); @@ -98,6 +103,8 @@ typedef struct { HRESULT (STDMETHODCALLTYPE *InitProxy)(IWineDispatchProxyCbPrivate *This, IDispatch *obj); void (STDMETHODCALLTYPE *Unlinked)(IWineDispatchProxyCbPrivate *This, BOOL persist); HRESULT (STDMETHODCALLTYPE *HostUpdated)(IWineDispatchProxyCbPrivate *This, IActiveScript *script); + IDispatch* (STDMETHODCALLTYPE *CreateConstructor)(IWineDispatchProxyCbPrivate *This, IDispatch *disp, const WCHAR *name); + HRESULT (STDMETHODCALLTYPE *DefineConstructor)(IWineDispatchProxyCbPrivate *This, const WCHAR *name, IDispatch *prot, IDispatch *ctor); HRESULT (STDMETHODCALLTYPE *PropEnum)(IWineDispatchProxyCbPrivate *This, const WCHAR *name); } IWineDispatchProxyCbPrivateVtbl; @@ -328,7 +335,6 @@ HRESULT create_dispex(script_ctx_t*,const builtin_info_t*,jsdisp_t*,jsdisp_t**) HRESULT init_dispex(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*) DECLSPEC_HIDDEN; HRESULT init_dispex_from_constr(jsdisp_t*,script_ctx_t*,const builtin_info_t*,jsdisp_t*) DECLSPEC_HIDDEN; HRESULT convert_to_proxy(script_ctx_t*,jsval_t*) DECLSPEC_HIDDEN; -HRESULT set_js_globals(jsdisp_t*) DECLSPEC_HIDDEN; void disp_fill_exception(script_ctx_t*,EXCEPINFO*) DECLSPEC_HIDDEN; HRESULT disp_call(script_ctx_t*,IDispatch*,DISPID,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; @@ -364,6 +370,7 @@ HRESULT create_builtin_function(script_ctx_t*,builtin_invoke_t,const WCHAR*,cons HRESULT create_builtin_constructor(script_ctx_t*,builtin_invoke_t,const WCHAR*,const builtin_info_t*,DWORD, jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT create_proxy_functions(jsdisp_t*,const struct proxy_prop_info*,jsdisp_t**) DECLSPEC_HIDDEN; +HRESULT create_proxy_constructor(IDispatch*,const WCHAR*,jsdisp_t*,jsdisp_t**) DECLSPEC_HIDDEN; HRESULT Function_invoke(jsdisp_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*,IServiceProvider*) DECLSPEC_HIDDEN; HRESULT Function_value(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index b8c2f1118b8..7d2b4c01bff 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -25,6 +25,7 @@ #include "winbase.h" #include "winuser.h" #include "ole2.h" +#include "mshtmdid.h" #include "mscoree.h" #include "wine/debug.h" @@ -90,6 +91,12 @@ struct proxy_prototype { LONG ref; }; +struct proxy_ctor { + IUnknown IUnknown_iface; + DispatchEx dispex; + LONG ref; +}; + #define DYNPROP_DELETED 0x01 #define DYNPROP_HIDDEN 0x02 #define DYNPROP_PROTREF 0x04 /* V_VT(var) == VT_EMPTY and V_UI4(var) == the ref */ @@ -179,6 +186,22 @@ COMMON_PROTOTYPE_LIST #undef X }; +static const dispex_static_data_vtbl_t proxy_ctor_dispex_vtbl; + +static dispex_static_data_t proxy_ctor_dispex[] = { +#define X(id, name, dispex, proto_id) \ +{ \ + L ## name, \ + &proxy_ctor_dispex_vtbl, \ + PROTO_ID_Object, \ + NULL_tid, \ + no_iface_tids \ +}, +COMMON_PROTOTYPE_LIST +PROXY_PROTOTYPE_LIST +#undef X +}; + static inline dispex_data_t *proxy_prototype_object_info(struct proxy_prototype *prot) { dispex_static_data_t *desc = CONTAINING_RECORD(prot->dispex.info->desc, struct prototype_static_data, dispex)->desc; @@ -2289,12 +2312,12 @@ static IDispatch *get_default_prototype(prototype_id_t prot_id, compat_mode_t co return NULL; if(!*prots_ref) { - if(!(*prots_ref = calloc(1, FIELD_OFFSET(struct proxy_prototypes, prototype[num_prots])))) + if(!(*prots_ref = calloc(1, FIELD_OFFSET(struct proxy_prototypes, disp[num_prots])))) return NULL; (*prots_ref)->num = num_prots; } - entry = &(*prots_ref)->prototype[prot_id - LEGACY_PROTOTYPE_COUNT]; + entry = &(*prots_ref)->disp[prot_id - LEGACY_PROTOTYPE_COUNT].prototype; if(*entry) { IDispatch_AddRef(*entry); return *entry; @@ -2312,6 +2335,124 @@ static IDispatch *get_default_prototype(prototype_id_t prot_id, compat_mode_t co return *entry; } +static IDispatch *get_proxy_constructor_disp(HTMLInnerWindow *window, prototype_id_t prot_id) +{ + static const struct { + prototype_id_t prot_id; + dispex_static_data_t *dispex; + const void *vtbl; + } ctors[] = { + { PROTO_ID_HTMLImgElement, &HTMLImageElementFactory_dispex, &HTMLImageElementFactoryVtbl }, + { PROTO_ID_HTMLOptionElement, &HTMLOptionElementFactory_dispex, &HTMLOptionElementFactoryVtbl }, + { PROTO_ID_HTMLXMLHttpRequest, &HTMLXMLHttpRequestFactory_dispex, &HTMLXMLHttpRequestFactoryVtbl } + }; + struct legacy_ctor *ctor; + unsigned i; + + for(i = 0; i < ARRAY_SIZE(ctors); i++) + if(ctors[i].prot_id == prot_id) + break; + assert(i < ARRAY_SIZE(ctors)); + + if(!(ctor = malloc(sizeof(*ctor)))) + return NULL; + + ctor->IUnknown_iface.lpVtbl = ctors[i].vtbl; + ctor->ref = 1; + ctor->prot_id = prot_id; + ctor->window = window; + + /* Proxy constructor disps hold ref to window */ + IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface); + + init_dispatch(&ctor->dispex, &ctor->IUnknown_iface, ctors[i].dispex, NULL, dispex_compat_mode(&window->event_target.dispex)); + + return (IDispatch*)&ctor->dispex.IDispatchEx_iface; +} + +static inline struct proxy_ctor *proxy_ctor_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct proxy_ctor, IUnknown_iface); +} + +static HRESULT WINAPI proxy_ctor_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) +{ + struct proxy_ctor *This = proxy_ctor_from_IUnknown(iface); + + TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); + + if(IsEqualGUID(&IID_IUnknown, riid)) { + *ppv = &This->IUnknown_iface; + }else if(dispex_query_interface(&This->dispex, riid, ppv)) { + return *ppv ? S_OK : E_NOINTERFACE; + }else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI proxy_ctor_AddRef(IUnknown *iface) +{ + struct proxy_ctor *This = proxy_ctor_from_IUnknown(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI proxy_ctor_Release(IUnknown *iface) +{ + struct proxy_ctor *This = proxy_ctor_from_IUnknown(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if(!ref) { + release_dispex(&This->dispex); + free(This); + } + return ref; +} + +static const IUnknownVtbl proxy_ctor_vtbl = { + proxy_ctor_QueryInterface, + proxy_ctor_AddRef, + proxy_ctor_Release +}; + +static HRESULT proxy_ctor_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *params, + VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + switch(flags) { + case DISPATCH_METHOD|DISPATCH_PROPERTYGET: + if(!res) + return E_INVALIDARG; + /* fall through */ + case DISPATCH_METHOD: + case DISPATCH_CONSTRUCT: + return MSHTML_E_INVALID_ACTION; + case DISPATCH_PROPERTYGET: + V_VT(res) = VT_BSTR; + return dispex_to_string(dispex, &V_BSTR(res)); + case DISPATCH_PROPERTYPUTREF|DISPATCH_PROPERTYPUT: + case DISPATCH_PROPERTYPUTREF: + case DISPATCH_PROPERTYPUT: + break; + default: + return E_INVALIDARG; + } + return S_OK; +} + +static const dispex_static_data_vtbl_t proxy_ctor_dispex_vtbl = { + proxy_ctor_value, + NULL +}; + static HRESULT proxy_get_dispid(DispatchEx *dispex, const WCHAR *name, BOOL case_insens, DISPID *id) { DWORD grfdex = case_insens ? fdexNameCaseInsensitive : fdexNameCaseSensitive; @@ -2740,6 +2881,97 @@ static IDispatch* WINAPI WineDispatchProxyPrivate_GetDefaultPrototype(IWineDispa return get_default_prototype(prot_id, dispex_compat_mode(This), prots_ref); } +static IDispatch* WINAPI WineDispatchProxyPrivate_GetDefaultConstructor(IWineDispatchProxyPrivate *iface, + IWineDispatchProxyPrivate *window, struct proxy_prototypes *prots) +{ + DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); + struct proxy_prototype *prot = proxy_prototype_from_IUnknown(This->outer); + struct proxy_ctor *ctor; + prototype_id_t prot_id; + IDispatch **entry; + + prot_id = CONTAINING_RECORD(prot->dispex.info->desc, struct prototype_static_data, dispex) - prototype_static_data; + + entry = &prots->disp[prot_id - LEGACY_PROTOTYPE_COUNT].ctor; + if(*entry) { + IDispatch_AddRef(*entry); + return *entry; + } + + /* XMLHttpRequest is a special case */ + if(prot_id == PROTO_ID_HTMLXMLHttpRequest) { + IDispatch *disp = get_proxy_constructor_disp(CONTAINING_RECORD((IDispatchEx*)window, HTMLWindow, IDispatchEx_iface)->inner_window, prot_id); + if(disp) { + *entry = This->proxy->lpVtbl->CreateConstructor(This->proxy, disp, proxy_ctor_dispex[prot_id - LEGACY_PROTOTYPE_COUNT].name); + IDispatch_Release(disp); + if(*entry) { + IDispatch_AddRef(*entry); + return *entry; + } + } + } + + if(!(ctor = malloc(sizeof(*ctor)))) + return NULL; + + ctor->IUnknown_iface.lpVtbl = &proxy_ctor_vtbl; + ctor->ref = 2; /* the script's ctx also holds one ref */ + + init_dispatch(&ctor->dispex, &ctor->IUnknown_iface, &proxy_ctor_dispex[prot_id - LEGACY_PROTOTYPE_COUNT], + NULL, dispex_compat_mode(This)); + + *entry = (IDispatch*)&ctor->dispex.IDispatchEx_iface; + return *entry; +} + +static HRESULT WINAPI WineDispatchProxyPrivate_DefineConstructors(IWineDispatchProxyPrivate *iface, struct proxy_prototypes **prots_ref) +{ + static const struct { + const WCHAR *name; + prototype_id_t proto_id; + } extra_ctors[] = { + { L"Image", PROTO_ID_HTMLImgElement }, + { L"Option", PROTO_ID_HTMLOptionElement }, + }; + DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); + compat_mode_t compat_mode; + IDispatch *prot, *ctor; + unsigned int i; + HRESULT hres; + + if(!ensure_real_info(This)) + return E_OUTOFMEMORY; + if(This->info->desc != &HTMLWindow_dispex) + return S_FALSE; + compat_mode = dispex_compat_mode(This); + + for(i = 0; i < ARRAY_SIZE(proxy_ctor_dispex); i++) { + if(!(prot = get_default_prototype(i + LEGACY_PROTOTYPE_COUNT, compat_mode, prots_ref))) + return E_OUTOFMEMORY; + + hres = This->proxy->lpVtbl->DefineConstructor(This->proxy, proxy_ctor_dispex[i].name, prot, NULL); + if(FAILED(hres)) + return hres; + } + + for(i = 0; i < ARRAY_SIZE(extra_ctors); i++) { + if(!(ctor = get_proxy_constructor_disp(CONTAINING_RECORD(This, HTMLInnerWindow, event_target.dispex), + extra_ctors[i].proto_id))) + return E_OUTOFMEMORY; + + if(!(prot = get_default_prototype(extra_ctors[i].proto_id, compat_mode, prots_ref))) + hres = E_OUTOFMEMORY; + else + hres = This->proxy->lpVtbl->DefineConstructor(This->proxy, extra_ctors[i].name, prot, ctor); + + IDispatch_Release(ctor); + if(FAILED(hres)) + return hres; + } + + return S_OK; +} + static BOOL WINAPI WineDispatchProxyPrivate_IsPrototype(IWineDispatchProxyPrivate *iface) { DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); @@ -2982,6 +3214,8 @@ static IWineDispatchProxyPrivateVtbl WineDispatchProxyPrivateVtbl = { /* IWineDispatchProxyPrivate extension */ WineDispatchProxyPrivate_GetProxyFieldRef, WineDispatchProxyPrivate_GetDefaultPrototype, + WineDispatchProxyPrivate_GetDefaultConstructor, + WineDispatchProxyPrivate_DefineConstructors, WineDispatchProxyPrivate_IsPrototype, WineDispatchProxyPrivate_PropFixOverride, WineDispatchProxyPrivate_PropOverride, diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 377973a1796..a1f44a084fa 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -5202,6 +5202,20 @@ static IDispatch* WINAPI DocWineDispProxyPrivate_GetDefaultPrototype(IWineDispat return itf->lpVtbl->GetDefaultPrototype(itf, prots_ref); } +static IDispatch* WINAPI DocWineDispProxyPrivate_GetDefaultConstructor(IWineDispatchProxyPrivate *iface, + IWineDispatchProxyPrivate *window, struct proxy_prototypes *prots) +{ + HTMLDocumentNode *This = impl_from_IWineDispatchProxyPrivate(iface); + IWineDispatchProxyPrivate *itf = (IWineDispatchProxyPrivate*)&This->node.event_target.dispex.IDispatchEx_iface; + + return itf->lpVtbl->GetDefaultConstructor(itf, window, prots); +} + +static HRESULT WINAPI DocWineDispProxyPrivate_DefineConstructors(IWineDispatchProxyPrivate *iface, struct proxy_prototypes **prots_ref) +{ + return S_FALSE; +} + static BOOL WINAPI DocWineDispProxyPrivate_IsPrototype(IWineDispatchProxyPrivate *iface) { return FALSE; @@ -5363,6 +5377,8 @@ static const IWineDispatchProxyPrivateVtbl DocDispatchExVtbl = { /* IWineDispatchProxyPrivate extension */ DocWineDispProxyPrivate_GetProxyFieldRef, DocWineDispProxyPrivate_GetDefaultPrototype, + DocWineDispProxyPrivate_GetDefaultConstructor, + DocWineDispProxyPrivate_DefineConstructors, DocWineDispProxyPrivate_IsPrototype, DocWineDispProxyPrivate_PropFixOverride, DocWineDispProxyPrivate_PropOverride, diff --git a/dlls/mshtml/htmlimg.c b/dlls/mshtml/htmlimg.c index 516f82fd35c..44a782124f4 100644 --- a/dlls/mshtml/htmlimg.c +++ b/dlls/mshtml/htmlimg.c @@ -857,6 +857,9 @@ static ULONG WINAPI HTMLImageElementFactory_Release(IHTMLImageElementFactory *if TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { + /* Proxy constructor disps hold ref to window, others are always detached first */ + if(This->window) + IHTMLWindow2_Release(&This->window->base.IHTMLWindow2_iface); release_dispex(&This->dispex); free(This); } diff --git a/dlls/mshtml/htmlselect.c b/dlls/mshtml/htmlselect.c index a5eb45c889d..25030722b84 100644 --- a/dlls/mshtml/htmlselect.c +++ b/dlls/mshtml/htmlselect.c @@ -495,6 +495,9 @@ static ULONG WINAPI HTMLOptionElementFactory_Release(IHTMLOptionElementFactory * TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { + /* Proxy constructor disps hold ref to window, others are always detached first */ + if(This->window) + IHTMLWindow2_Release(&This->window->base.IHTMLWindow2_iface); release_dispex(&This->dispex); free(This); } diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index a629d866cf9..e6ea88cc1c3 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3887,6 +3887,23 @@ static IDispatch* WINAPI WindowWineDispProxyPrivate_GetDefaultPrototype(IWineDis return itf->lpVtbl->GetDefaultPrototype(itf, prots_ref); } +static IDispatch* WINAPI WindowWineDispProxyPrivate_GetDefaultConstructor(IWineDispatchProxyPrivate *iface, + IWineDispatchProxyPrivate *window, struct proxy_prototypes *prots) +{ + HTMLWindow *This = impl_from_IWineDispatchProxyPrivate(iface); + IWineDispatchProxyPrivate *itf = (IWineDispatchProxyPrivate*)&This->inner_window->event_target.dispex.IDispatchEx_iface; + + return itf->lpVtbl->GetDefaultConstructor(itf, window, prots); +} + +static HRESULT WINAPI WindowWineDispProxyPrivate_DefineConstructors(IWineDispatchProxyPrivate *iface, struct proxy_prototypes **prots_ref) +{ + HTMLWindow *This = impl_from_IWineDispatchProxyPrivate(iface); + IWineDispatchProxyPrivate *itf = (IWineDispatchProxyPrivate*)&This->inner_window->event_target.dispex.IDispatchEx_iface; + + return itf->lpVtbl->DefineConstructors(itf, prots_ref); +} + static BOOL WINAPI WindowWineDispProxyPrivate_IsPrototype(IWineDispatchProxyPrivate *iface) { return FALSE; @@ -4044,6 +4061,8 @@ static const IWineDispatchProxyPrivateVtbl WindowDispExVtbl = { /* IWineDispatchProxyPrivate extension */ WindowWineDispProxyPrivate_GetProxyFieldRef, WindowWineDispProxyPrivate_GetDefaultPrototype, + WindowWineDispProxyPrivate_GetDefaultConstructor, + WindowWineDispProxyPrivate_DefineConstructors, WindowWineDispProxyPrivate_IsPrototype, WindowWineDispProxyPrivate_PropFixOverride, WindowWineDispProxyPrivate_PropOverride, diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 3fcad22f0bb..217a75a946a 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -52,7 +52,10 @@ typedef struct _IWineDispatchProxyCbPrivate IWineDispatchProxyCbPrivate; struct proxy_prototypes { unsigned int num; - IDispatch *prototype[]; + struct { + IDispatch *prototype; + IDispatch *ctor; + } disp[]; }; struct proxy_func_invoker @@ -73,6 +76,8 @@ typedef struct { IDispatchExVtbl dispex; IWineDispatchProxyCbPrivate** (STDMETHODCALLTYPE *GetProxyFieldRef)(IWineDispatchProxyPrivate *This); IDispatch* (STDMETHODCALLTYPE *GetDefaultPrototype)(IWineDispatchProxyPrivate *This, struct proxy_prototypes **prots_ref); + IDispatch* (STDMETHODCALLTYPE *GetDefaultConstructor)(IWineDispatchProxyPrivate *This, IWineDispatchProxyPrivate *window, struct proxy_prototypes *prots); + HRESULT (STDMETHODCALLTYPE *DefineConstructors)(IWineDispatchProxyPrivate *This, struct proxy_prototypes **prots_ref); BOOL (STDMETHODCALLTYPE *IsPrototype)(IWineDispatchProxyPrivate *This); HRESULT (STDMETHODCALLTYPE *PropFixOverride)(IWineDispatchProxyPrivate *This, struct proxy_prop_info *info); HRESULT (STDMETHODCALLTYPE *PropOverride)(IWineDispatchProxyPrivate *This, const WCHAR *name, VARIANT *value); @@ -91,6 +96,8 @@ typedef struct { HRESULT (STDMETHODCALLTYPE *InitProxy)(IWineDispatchProxyCbPrivate *This, IDispatch *obj); void (STDMETHODCALLTYPE *Unlinked)(IWineDispatchProxyCbPrivate *This, BOOL persist); HRESULT (STDMETHODCALLTYPE *HostUpdated)(IWineDispatchProxyCbPrivate *This, IActiveScript *script); + IDispatch* (STDMETHODCALLTYPE *CreateConstructor)(IWineDispatchProxyCbPrivate *This, IDispatch *disp, const WCHAR *name); + HRESULT (STDMETHODCALLTYPE *DefineConstructor)(IWineDispatchProxyCbPrivate *This, const WCHAR *name, IDispatch *prot, IDispatch *ctor); HRESULT (STDMETHODCALLTYPE *PropEnum)(IWineDispatchProxyCbPrivate *This, const WCHAR *name); } IWineDispatchProxyCbPrivateVtbl; diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index f91b2dbc125..be657efae9d 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1427,6 +1427,9 @@ static ULONG WINAPI HTMLXMLHttpRequestFactory_Release(IHTMLXMLHttpRequestFactory TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { + /* Proxy constructor disps hold ref to window, others are always detached first */ + if(This->window) + IHTMLWindow2_Release(&This->window->base.IHTMLWindow2_iface); release_dispex(&This->dispex); free(This); } From 9b133266bae7dc0c39d8deafcc2281a5e75a2b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:04 +0200 Subject: [PATCH 0888/2777] mshtml/tests: Add tests for builtin object constructors and prototypes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/tests/documentmode.js | 502 +++++++++++++++++++++++++++++- dlls/mshtml/tests/dom.js | 9 + 2 files changed, 509 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index a812f06ed14..5fa9206ea8d 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -232,7 +232,7 @@ sync_test("builtin_toString", function() { ]; var v = document.documentMode, e; - function test(msg, obj, name, tostr) { + function test(msg, obj, name, tostr, ctor_name) { var s; if(obj.toString) { s = obj.toString(); @@ -242,6 +242,32 @@ sync_test("builtin_toString", function() { s = Object.prototype.toString.call(obj); todo_wine_if(name !== "HTMLElement" && s === "[object HTMLElement]"). ok(s === (v < 9 ? "[object Object]" : "[object " + name + "]"), msg + " Object.toString returned " + s); + + if(v >= 9) { + eval("var c = window." + name + ";"); + todo_wine_if(name !== "HTMLElement" && s === "[object HTMLElement]"). + ok(c !== undefined, name + " is undefined"); + if(!ctor_name) ctor_name = name; + if(c === undefined) return; /* todo_wine */ + + s = Object.getPrototypeOf(obj); + if(name === "Object") { + ok(s === null, msg + "'s proto is not null: " + s); + + s = Object.prototype.toString.call(c); + ok(s === "[object Function]", msg + " Object.toString on constructor returned " + s); + }else { + ok(s === c.prototype, msg + "'s proto is not its constructor's prototype"); + + s = Object.prototype.toString.call(c); + todo_wine_if(name !== "HTMLElement" && s === "[object HTMLElement]"). + ok(s === "[object " + ctor_name + "]", msg + " Object.toString on constructor returned " + s); + + s = Object.prototype.toString.call(c.prototype); + todo_wine_if(name !== "HTMLElement" && s === "[object HTMLElementPrototype]"). + ok(s === "[object " + name + "Prototype]", msg + " Object.toString on constructor.prototype returned " + s); + } + } } for(var i = 0; i < tags.length; i++) @@ -318,7 +344,7 @@ sync_test("builtin_toString", function() { test("textNode", document.createTextNode("testNode"), "Text", v < 9 ? "testNode" : null); test("textRange", txtRange, "TextRange"); test("window", window, "Window", "[object Window]"); - test("xmlHttpRequest", new XMLHttpRequest(), "XMLHttpRequest"); + test("xmlHttpRequest", new XMLHttpRequest(), "XMLHttpRequest", null, "Function"); if(v < 10) { test("namespaces", document.namespaces, "MSNamespaceInfoCollection"); } @@ -495,6 +521,471 @@ sync_test("builtin_obj", function() { } }); +sync_test("builtin_prototypes", function() { + var v = document.documentMode, r, obj, name, proto; + + var special_ctors = [ + [ "Image", [ "prototype", "arguments" ], [ "create", "length" ] ], + [ "Option", [ "prototype", "arguments" ], [ "create", "length" ] ], + [ "XMLHttpRequest", [ "prototype", "arguments", "create" ], [ "length" ] ] + ]; + for(var i = 0; i < special_ctors.length; i++) { + name = special_ctors[i][0]; + ok(Object.prototype.hasOwnProperty.call(window, name), name + " not a property of window."); + eval("obj = window." + name + ";"); + if(v < 9) { + ok(!Object.prototype.hasOwnProperty.call(obj, "arguments"), "arguments is a property of " + name + " constructor."); + ok(Object.prototype.hasOwnProperty.call(obj, "create"), "create not a property of " + name + " constructor."); + ok(!Object.prototype.hasOwnProperty.call(obj, "length"), "length is a property of " + name + " constructor."); + ok(Object.prototype.hasOwnProperty.call(obj, "prototype"), "prototype not a property of " + name + " constructor."); + ok(!("length" in obj), "length in " + name + " constructor."); + if(window.Window) + todo_wine. + ok(!Object.prototype.hasOwnProperty.call(window.Window.prototype, name), name + " is a property of window's prototype."); + }else { + if(special_ctors[i][1]) for(var j = 0; j < special_ctors[i][1].length; j++) + ok(Object.prototype.hasOwnProperty.call(obj, special_ctors[i][1][j]), special_ctors[i][1][j] + " not a property of " + name + " constructor."); + + if(special_ctors[i][2]) for(var j = 0; j < special_ctors[i][2].length; j++) + todo_wine_if(special_ctors[i][2][j] === "create" && name !== "XMLHttpRequest"). + ok(!Object.prototype.hasOwnProperty.call(obj, special_ctors[i][2][j]), special_ctors[i][2][j] + " is a property of " + name + " constructor."); + + ok(Object.getPrototypeOf(obj) === Function.prototype, "getPrototypeOf(" + name + " constructor) = " + Object.getPrototypeOf(obj)); + ok(!Object.prototype.hasOwnProperty.call(Object.getPrototypeOf(window), name), name + " is a property of window's prototype."); + + if(obj.create) { + proto = obj.prototype; + var func = obj.create; + var s = Object.prototype.toString.call(func); + ok(s === "[object Function]", "obj.create toString = " + s); + ok(Object.getPrototypeOf(func) === Function.prototype, "getPrototypeOf(" + name + ".create) = " + Object.getPrototypeOf(func)); + ok(Object.prototype.hasOwnProperty.call(func, "arguments"), "arguments not a property of " + name + ".create"); + ok(!Object.prototype.hasOwnProperty.call(func, "length"), "length is a property of " + name + ".create"); + ok(Object.prototype.hasOwnProperty.call(func, "prototype"), "prototype not a property of " + name + ".create"); + + obj = func(); + ok(Object.getPrototypeOf(obj) === proto, "getPrototypeOf(obj.create()) = " + Object.getPrototypeOf(obj)); + obj = func.call(Object); + ok(Object.getPrototypeOf(obj) === proto, "getPrototypeOf(obj.create() on Object) = " + Object.getPrototypeOf(obj)); + } + } + } + + function set_obj(n, o) { + name = n; + proto = null; + if(o) { + eval("proto = window." + n + ".prototype;"); + if(typeof o !== "boolean") { + obj = o; + return; + } + } + try { + eval("obj = new window." + n + "();"); + ok(o, "expected exception when creating " + name + "."); + }catch(ex) { + obj = null; + ok(!o, "did not expect exception when creating " + name + "."); + ok(ex.number == 0xa01bd - 0x80000000, "unexpected exception number when creating " + name + ": " + ex.number); + } + } + function test_prop(prop, own) { + if(own === undefined ? v < 9 : own) + ok(Object.prototype.hasOwnProperty.call(obj, prop), prop + " not a property of " + name + "."); + else + ok(!Object.prototype.hasOwnProperty.call(obj, prop), prop + " is a property of " + name + "."); + ok(Object.prototype.hasOwnProperty.call(proto, prop), prop + " not a property of " + name + ".prototype."); + } + function test_legacy_ctor(methods, props, non_props, set_prop, set_prop_val) { + if(v >= 9) + return; + ok(""+proto === "[Interface prototype object]", name + ".prototype = " + proto); + if(v < 8) + ok(proto.constructor === undefined, name + ".prototype.constructor = " + proto.constructor); + for(var i = 0; i < methods.length; i++) { + ok(methods[i] in proto, methods[i] + " not in " + name + ".prototype"); + var r = 0; + try { + eval("proto." + methods[i] + "();"); + }catch(ex) { + r = ex.number; + } + ok(r === 0xa01b6 - 0x80000000, name + ".prototype." + methods[i] + "() exception code = " + r); + eval("r = \"\"+proto." + methods[i] + ";"); + ok(r === "\nfunction " + methods[i] + "() {\n [native code]\n}\n", name + ".prototype." + methods[i] + " = " + r); + try { + eval("r = (delete proto." + methods[i] + ");"); + ok(v >= 8, "expected exception deleting " + name + ".prototype." + methods[i]); + ok(r === true, "delete " + name + ".prototype." + methods[i] + " returned " + r); + }catch(ex) { + ok(v < 8, "did not expect exception deleting " + name + ".prototype." + methods[i]); + } + eval("r = \"\"+proto." + methods[i] + ";"); + ok(r === "\nfunction " + methods[i] + "() {\n [native code]\n}\n", name + ".prototype." + methods[i] + " after delete = " + r); + ok(methods[i] in proto, methods[i] + " not in " + name + ".prototype after delete"); + + var func = function() { return "foobar"; } + eval("proto." + methods[i] + " = func;"); + eval("r = proto." + methods[i] + ";"); + ok(r === func, name + ".prototype." + methods[i] + " after set = " + r); + try { + eval("r = (delete proto." + methods[i] + ");"); + ok(v >= 8, "expected exception deleting " + name + ".prototype." + methods[i] + " after set"); + ok(r === true, "delete " + name + ".prototype." + methods[i] + " after set returned " + r); + eval("r = \"\"+proto." + methods[i] + ";"); + ok(r === "\nfunction " + methods[i] + "() {\n [native code]\n}\n", name + ".prototype." + methods[i] + " after second delete = " + r); + }catch(ex) { + ok(v < 8, "did not expect exception deleting " + name + ".prototype." + methods[i] + " after set"); + eval("r = proto." + methods[i] + ";"); + ok(r === func, name + ".prototype." + methods[i] + " after second delete = " + r); + } + eval("proto." + methods[i] + " = func;"); + eval("r = proto." + methods[i] + ";"); + ok(r === func, name + ".prototype." + methods[i] + " after second set = " + r); + } + for(var i = 0; i < props.length; i++) { + ok(props[i] in proto, props[i] + " not in " + name + ".prototype"); + eval("var r = proto." + props[i] + ";"); + ok(r === undefined, name + ".prototype." + props[i] + " = " + r); + try { + eval("r = (delete proto." + props[i] + ");"); + ok(v >= 8, "expected exception deleting " + name + ".prototype." + props[i]); + ok(r === true, "delete " + name + ".prototype." + props[i] + " returned " + r); + }catch(ex) { + ok(v < 8, "did not expect exception deleting " + name + ".prototype." + props[i]); + } + eval("r = proto." + props[i] + ";"); + ok(r === undefined, name + ".prototype." + props[i] + " after delete = " + r); + ok(props[i] in proto, props[i] + " not in " + name + ".prototype after delete"); + } + for(var i = 0; i < non_props.length; i++) + ok(!(non_props[i] in proto), non_props[i] + " in " + name + ".prototype"); + + eval("r = proto." + set_prop + ";"); + ok(r === undefined, name + ".prototype." + set_prop + " = " + r); + eval("proto." + set_prop + " = set_prop_val; r = proto." + set_prop + ";"); + ok(r === undefined, name + ".prototype." + set_prop + " after set = " + r); + + r = proto.winetestprop; + ok(r === undefined, name + ".prototype.winetestprop = " + r); + proto.winetestprop = "test"; + r = proto.winetestprop; + ok(r === "test", name + ".prototype.winetestprop after set = " + r); + } + + set_obj("XMLHttpRequest", true); + test_prop("open"); + test_prop("status"); + test_prop("onreadystatechange"); + test_legacy_ctor(["abort", "send"], ["readyState", "status"], ["selected", "src", "getAttribute"], "onreadystatechange", function(){}); + if(v < 9) { + r = obj.abort(); + ok(r === "foobar", "(new XMLHttpRequest).abort() returned " + r); + r = obj.winetestprop; + ok(r === "test", "(new XMLHttpRequest).winetestprop = " + r); + obj.winetestprop = "prop"; + r = obj.winetestprop; + ok(r === "prop", "(new XMLHttpRequest).winetestprop after set = " + r); + r = XMLHttpRequest.prototype.winetestprop; + ok(r === "test", "XMLHttpRequest.prototype.winetestprop after obj = " + r); + }else + ok(proto.constructor === window.XMLHttpRequest, "XMLHttpRequest.prototype.constructor = " + proto.constructor); + + set_obj("Image", true); + test_prop("src"); + test_prop("border"); + test_legacy_ctor(["getAttribute", "toString"], ["isMap", "alt"], ["selected", "send"], "src", "about:blank"); + if(v < 9) { + r = obj.toString(); + ok(r === "foobar", "(new Image).toString() returned " + r); + r = obj.winetestprop; + ok(r === "test", "(new Image).winetestprop = " + r); + obj.winetestprop = "prop"; + r = obj.winetestprop; + ok(r === "prop", "(new Image).winetestprop after set = " + r); + r = window.Image.prototype.winetestprop; + ok(r === "test", "Image.prototype.winetestprop after obj = " + r); + try { + r = (delete obj.winetestprop); + ok(v >= 8, "expected exception deleting (new Image).winetestprop"); + ok(r === true, "delete (new Image).winetestprop returned " + r); + }catch(ex) { + ok(v < 8, "did not expect exception deleting (new Image).winetestprop"); + } + r = obj.winetestprop; + ok(r === (v < 8 ? "prop" : "test"), "(new Image).winetestprop after delete = " + r); + obj = new window.Image(); + r = obj.winetestprop; + ok(r === "test", "(new Image).winetestprop second time = " + r); + window.Image.prototype.winetestprop = "string"; + r = obj.winetestprop; + ok(r === "string", "(new Image).winetestprop after change in prototype = " + r); + }else + ok(proto.constructor === window.HTMLImageElement, "Image.prototype.constructor = " + proto.constructor); + + set_obj("Option", true); + test_prop("text"); + test_prop("selected"); + test_legacy_ctor(["setAttribute", "contains"], ["index", "value"], ["src", "send"], "text", "foo"); + if(v < 9) { + r = obj.setAttribute("a", "b"); + ok(r === "foobar", "(new Option).setAttribute() returned " + r); + r = obj.winetestprop; + ok(r === "test", "(new Option).winetestprop = " + r); + obj.winetestprop = "prop"; + r = obj.winetestprop; + ok(r === "prop", "(new Option).winetestprop after set = " + r); + r = window.Option.prototype.winetestprop; + ok(r === "test", "Option.prototype.winetestprop after obj = " + r); + try { + r = (delete obj.winetestprop); + ok(v >= 8, "expected exception deleting (new Option).winetestprop"); + ok(r === true, "delete (new Option).winetestprop returned " + r); + }catch(ex) { + ok(v < 8, "did not expect exception deleting (new Option).winetestprop"); + } + r = obj.winetestprop; + ok(r === (v < 8 ? "prop" : "test"), "(new Option).winetestprop after delete = " + r); + obj = new window.Option(); + r = obj.winetestprop; + ok(r === "test", "(new Option).winetestprop second time = " + r); + window.Option.prototype.winetestprop = "string"; + r = obj.winetestprop; + ok(r === "string", "(new Option).winetestprop after change in prototype = " + r); + }else + ok(proto.constructor === window.HTMLOptionElement, "Option.prototype.constructor = " + proto.constructor); + + // other constructors don't support construction + set_obj("ClientRect"); + set_obj("ClientRectList"); + set_obj("Console"); + set_obj("CustomEvent"); + set_obj("DOMTokenList"); + set_obj("KeyboardEvent"); + set_obj("MessageEvent"); + set_obj("MouseEvent"); + set_obj("MSCSSRuleList"); + set_obj("MSCurrentStyleCSSProperties"); + set_obj("MSEventObj"); + set_obj("MSNamespaceInfoCollection"); + set_obj("MSSelection"); + set_obj("MSStyleCSSProperties"); + set_obj("Performance"); + set_obj("PerformanceNavigation"); + set_obj("PerformanceTiming"); + set_obj("UIEvent"); + if(v >= 9) { + set_obj("Attr"); + set_obj("CSSStyleDeclaration"); + set_obj("CSSStyleRule"); + set_obj("CSSStyleSheet"); + set_obj("DOMImplementation"); + set_obj("Event"); + set_obj("History"); + set_obj("HTMLCollection"); + set_obj("NamedNodeMap"); + set_obj("Navigator"); + set_obj("NodeList"); + set_obj("Screen"); + set_obj("Storage"); + set_obj("StyleSheetList"); + set_obj("Text"); + set_obj("TextRange"); + set_obj("Window"); + } + + // todo_wine + if(v === 8 && window.Event === undefined) + return; + + if(v >= 8 && v < 11) { + set_obj(v < 9 ? "Event" : "MSEventObj", document.createEventObject()); + test_prop("x"); + test_prop("y"); + test_prop("srcElement"); + test_prop("returnValue"); + + if(Object.create) { + obj = Object.create(proto); + test_prop("reason"); + test_prop("srcFilter"); + r = Object.prototype.toString.call(obj); + ok(r === "[object Object]", "Object.toString on obj created from MSEventObj.prototype returned " + r); + } + + var ctor = function() {}; + ctor.prototype = proto; + ctor.prototype.testWineProp = function() { return 42; }; + obj = new ctor(); + test_prop("shiftKey", false); + test_prop("testWineProp", false); + r = Object.prototype.toString.call(obj); + ok(r === "[object Object]", "Object.toString on custom obj returned " + r); + + r = (delete proto.shiftKey); + ok(r === true, "delete shiftKey returned " + r); + if(v < 9) + ok(Object.prototype.hasOwnProperty.call(proto, "shiftKey"), "shiftKey not a property anymore of Event.prototype."); + else { + ok(!Object.prototype.hasOwnProperty.call(proto, "shiftKey"), "shiftKey still a property of MSEventObj.prototype."); + proto.shiftKey = ctor; + ok(proto.shiftKey === ctor, "shiftKey = " + proto.shiftKey); + } + + r = (delete proto.testWineProp); + ok(r === true, "delete testWineProp returned " + r); + ok(!Object.prototype.hasOwnProperty.call(proto, "testWineProp"), "testWineProp still a property of " + name + ".prototype."); + } + + if(v >= 9) { + set_obj("Event", document.createEvent("Event")); + test_prop("initEvent"); + test_prop("currentTarget"); + + obj = Object.create(proto); + test_prop("eventPhase"); + test_prop("preventDefault"); + r = Object.prototype.toString.call(obj); + ok(r === "[object Object]", "Object.toString on obj created from Event.prototype returned " + r); + + var ctor = function() {}; + ctor.prototype = proto; + ctor.prototype.testWineProp = function() { return 42; }; + obj = new ctor(); + test_prop("timeStamp"); + test_prop("testWineProp"); + r = Object.prototype.toString.call(obj); + ok(r === "[object Object]", "Object.toString on custom obj returned " + r); + + r = (delete proto.timeStamp); + ok(r === true, "delete timeStamp returned " + r); + ok(!Object.prototype.hasOwnProperty.call(proto, "timeStamp"), "timeStamp still a property of Event.prototype."); + + r = (delete proto.testWineProp); + ok(r === true, "delete testWineProp returned " + r); + ok(!Object.prototype.hasOwnProperty.call(proto, "testWineProp"), "testWineProp still a property of Event.prototype."); + + proto.timeStamp = ctor; + ok(proto.timeStamp === ctor, "timeStamp = " + proto.timeStamp); + + set_obj("HTMLImageElement", document.createElement("img")); + document.body.setAttribute.call(obj, "width", "100"); + obj = Object.create(proto); + r = 0; + try { + document.body.setAttribute.call(obj, "width", "100"); + }catch(ex) { + r = ex.number; + } + ok(r === 0xffff - 0x80000000, "document.body.setAttribute.call(obj ...) exception code = " + r); + } + + if(v >= 8) { + obj = window.HTMLMetaElement; + ok(!("charset" in obj), "charset in HTMLMetaElement constructor."); + ok(!("setAttribute" in obj), "setAttribute in HTMLMetaElement constructor."); + ok(!Object.prototype.hasOwnProperty.call(obj, "charset"), "charset is a property of HTMLMetaElement constructor."); + if(Object.getPrototypeOf) + ok(Object.getPrototypeOf(obj) === Object.prototype, "getPrototypeOf(HTMLMetaElement constructor) = " + Object.getPrototypeOf(obj)); + r = 0; + try { + document.body.setAttribute.call(obj, "charset", "UTF-8"); + }catch(ex) { + r = ex.number; + } + ok(r === (v < 9 ? 0xa0005 : 0xffff) - 0x80000000, "setAttribute on HTMLMetaElement constructor error code = " + r); + + proto = window.HTMLMetaElement.prototype; + try { + window.HTMLMetaElement.prototype = Object.prototype; + ok(v >= 9, "expected exception setting HTMLMetaElement.prototype"); + }catch(ex) { + ok(v < 9, "did not expect exception setting HTMLMetaElement.prototype"); + ok(ex.number === 0xa01b6 - 0x80000000, "exception code setting HTMLMetaElement.prototype = " + ex.number); + } + ok(window.HTMLMetaElement.prototype === proto, "HTMLMetaElement.prototype = " + window.HTMLMetaElement.prototype); + ok(proto !== Object.prototype, "old prototype is Object.prototype"); + + obj = document.createElement("meta"); + ok("tagName" in obj, "tagName not in HTMLMetaElement"); + if(Object.getPrototypeOf) + ok(Object.getPrototypeOf(obj) === proto, "getPrototypeOf(meta element) = " + Object.getPrototypeOf(obj)); + + try { + r = (delete window.HTMLMetaElement.prototype); + ok(r === false, "delete HTMLMetaElement.prototype returned " + r); + ok(v >= 9, "expected exception deleting HTMLMetaElement.prototype"); + }catch(ex) { + ok(v < 9, "did not expect exception deleting HTMLMetaElement.prototype"); + ok(ex.number === 0xa01b6 - 0x80000000, "exception code deleting HTMLMetaElement.prototype = " + ex.number); + } + ok(Object.prototype.hasOwnProperty.call(window.HTMLMetaElement, "prototype"), "prototype not a property anymore of HTMLMetaElement."); + + try { + r = (delete window.HTMLMetaElement); + ok(r === true, "delete HTMLMetaElement returned " + r); + ok(v >= 9, "expected exception deleting HTMLMetaElement"); + ok(!Object.prototype.hasOwnProperty.call(window, "HTMLMetaElement"), "HTMLMetaElement still a property of window."); + }catch(ex) { + ok(v < 9, "did not expect exception deleting HTMLMetaElement"); + ok(ex.number === 0xa01bd - 0x80000000, "exception code deleting HTMLMetaElement = " + ex.number); + ok(Object.prototype.hasOwnProperty.call(window, "HTMLMetaElement"), "HTMLMetaElement not a property anymore of window."); + } + + obj = document.createElement("meta"); + ok("tagName" in obj, "tagName not in HTMLMetaElement"); + if(Object.getPrototypeOf) { + ok(Object.getPrototypeOf(obj) === proto, "getPrototypeOf(meta element) = " + Object.getPrototypeOf(obj)); + ok(window.HTMLMetaElement === undefined, "HTMLMetaElement = " + window.HTMLMetaElement); + } + + ok("setAttribute" in proto, "setAttribute not in proto."); + r = 0; + try { + obj.setAttribute.call(proto, "charset", "UTF-8"); + }catch(ex) { + r = ex.number; + } + todo_wine_if(v < 9). + ok(r === (v < 9 ? 0xa01b6 : 0xffff) - 0x80000000, "setAttribute on proto error code = " + r); + r = 0; + try { + proto.setAttribute("charset", "UTF-8"); + }catch(ex) { + r = ex.number; + } + ok(r === (v < 9 ? 0xa01b6 : 0xffff) - 0x80000000, "proto.setAttribute error code = " + r); + + ok(Object.prototype.hasOwnProperty.call(proto, "charset"), "charset not a property of proto."); + if(v < 9) { + proto.charset = "UTF-8"; + ok(proto.charset === undefined, "proto.charset = " + proto.charset); + }else { + r = Object.getOwnPropertyDescriptor(proto, "charset"); + ok(r.get.toString() === "\nfunction charset() {\n [native code]\n}\n", "charset.get = " + r.get.toString()); + ok(r.set.toString() === "\nfunction charset() {\n [native code]\n}\n", "charset.set = " + r.set.toString()); + ok(Object.getPrototypeOf(r.get) === Function.prototype, "unexpected charset.get prototype"); + ok(Object.getPrototypeOf(r.set) === Function.prototype, "unexpected charset.set prototype"); + + r = 0; + try { + proto.charset; + }catch(ex) { + r = ex.number; + } + ok(r === 0xffff - 0x80000000, "proto.charset error code = " + r); + r = 0; + try { + proto.charset = "UTF-8"; + }catch(ex) { + r = ex.number; + } + ok(r === 0xffff - 0x80000000, "set proto.charset error code = " + r); + } + } +}); + sync_test("elem_props", function() { var elem = document.documentElement; @@ -2561,6 +3052,13 @@ sync_test("__proto__", function() { ok(e.number === 0xa13b6 - 0x80000000 && e.name === "TypeError", "changing __proto__ on non-extensible object threw exception " + e.number + " (" + e.name + ")"); } + + obj = document.createElement("img"); + obj.__proto__ = ctor.prototype; + document.body.setAttribute.call(obj, "height", "101"); + r = document.body.getAttribute.call(obj, "height"); + ok(r === "101", "getAttribute(height) = " + r); + ok(!("getAttribute" in obj), "getAttribute exposed in obj"); }); sync_test("__defineGetter__", function() { diff --git a/dlls/mshtml/tests/dom.js b/dlls/mshtml/tests/dom.js index ee4de99dc2d..b3d30d44025 100644 --- a/dlls/mshtml/tests/dom.js +++ b/dlls/mshtml/tests/dom.js @@ -147,9 +147,18 @@ async_test("iframe_location", function() { iframe.onload = function() { ok(iframe.contentWindow.location.pathname === "/emptyfile", "path = " + iframe.contentWindow.location.pathname); + ok(iframe.contentWindow.Image !== undefined, "Image is undefined"); + ok(iframe.contentWindow.VBArray !== undefined, "VBArray is undefined"); + iframe.contentWindow.Image = undefined; + iframe.contentWindow.VBArray = undefined; + iframe.contentWindow.foobar = 1234; iframe.onload = function () { ok(iframe.contentWindow.location.pathname === "/empty/file", "path = " + iframe.contentWindow.location.pathname); + ok(iframe.contentWindow.Image !== undefined, "Image is undefined (2)"); + ok(iframe.contentWindow.VBArray !== undefined, "VBArray is undefined (2)"); + ok(!Object.prototype.hasOwnProperty.call(iframe.contentWindow, "foobar"), + "contentWindow has foobar"); next_test(); } iframe.src = "empty/file"; From 7c952adffb45b035ed78ba6dacf4abbbf788f610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:04 +0200 Subject: [PATCH 0889/2777] mshtml: Don't expose `create` for Image and Option constructors in IE9+ modes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/function.c | 31 +++++++++++++++++++++---------- dlls/mshtml/htmlimg.c | 12 +++++++----- dlls/mshtml/htmlselect.c | 12 +++++++----- dlls/mshtml/tests/documentmode.js | 1 - 4 files changed, 35 insertions(+), 21 deletions(-) diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 83b33b68362..2023ce27720 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -1017,18 +1017,29 @@ HRESULT create_proxy_constructor(IDispatch *disp, const WCHAR *name, jsdisp_t *p hres = jsdisp_define_data_property(&constructor->function.dispex, L"prototype", 0, jsval_obj(prototype)); if(SUCCEEDED(hres)) { + BSTR bstr = SysAllocString(L"create"); ProxyConstructorCreate *create; + DISPID dispid; - hres = create_function(ctx, &ProxyConstructorCreate_info, &ProxyConstructorCreateVtbl, sizeof(ProxyConstructorCreate), - PROPF_METHOD, FALSE, NULL, (void**)&create); - if(SUCCEEDED(hres)) { - create->ctor = constructor; - jsdisp_addref(&constructor->function.dispex); - - hres = jsdisp_define_data_property(&create->function.dispex, L"prototype", 0, jsval_null()); - if(SUCCEEDED(hres)) - hres = jsdisp_define_data_property(&constructor->function.dispex, L"create", 0, jsval_obj(&create->function.dispex)); - jsdisp_release(&create->function.dispex); + if(!bstr) + hres = E_OUTOFMEMORY; + else { + HRESULT prop_hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &bstr, 1, 0, &dispid); + SysFreeString(bstr); + + if(prop_hres == S_OK) { + hres = create_function(ctx, &ProxyConstructorCreate_info, &ProxyConstructorCreateVtbl, sizeof(ProxyConstructorCreate), + PROPF_METHOD, FALSE, NULL, (void**)&create); + if(SUCCEEDED(hres)) { + create->ctor = constructor; + jsdisp_addref(&constructor->function.dispex); + + hres = jsdisp_define_data_property(&create->function.dispex, L"prototype", 0, jsval_null()); + if(SUCCEEDED(hres)) + hres = jsdisp_define_data_property(&constructor->function.dispex, L"create", 0, jsval_obj(&create->function.dispex)); + jsdisp_release(&create->function.dispex); + } + } } } if(FAILED(hres)) { diff --git a/dlls/mshtml/htmlimg.c b/dlls/mshtml/htmlimg.c index 44a782124f4..995ca2f1fb1 100644 --- a/dlls/mshtml/htmlimg.c +++ b/dlls/mshtml/htmlimg.c @@ -1023,10 +1023,11 @@ static HRESULT HTMLImageElementFactory_value(DispatchEx *dispex, LCID lcid, return S_OK; } -static const tid_t HTMLImageElementFactory_iface_tids[] = { - IHTMLImageElementFactory_tid, - 0 -}; +static void HTMLImageElementFactory_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) +{ + if(compat_mode < COMPAT_MODE_IE9) + dispex_info_add_interface(info, IHTMLImageElementFactory_tid, NULL); +} static const dispex_static_data_vtbl_t HTMLImageElementFactory_dispex_vtbl = { HTMLImageElementFactory_value, @@ -1041,5 +1042,6 @@ dispex_static_data_t HTMLImageElementFactory_dispex = { &HTMLImageElementFactory_dispex_vtbl, PROTO_ID_NULL, IHTMLImageElementFactory_tid, - HTMLImageElementFactory_iface_tids + no_iface_tids, + HTMLImageElementFactory_init_dispex_info }; diff --git a/dlls/mshtml/htmlselect.c b/dlls/mshtml/htmlselect.c index 25030722b84..c96003b594d 100644 --- a/dlls/mshtml/htmlselect.c +++ b/dlls/mshtml/htmlselect.c @@ -631,10 +631,11 @@ static HRESULT HTMLOptionElementFactory_value(DispatchEx *dispex, LCID lcid, return S_OK; } -static const tid_t HTMLOptionElementFactory_iface_tids[] = { - IHTMLOptionElementFactory_tid, - 0 -}; +static void HTMLOptionElementFactory_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) +{ + if(compat_mode < COMPAT_MODE_IE9) + dispex_info_add_interface(info, IHTMLOptionElementFactory_tid, NULL); +} static const dispex_static_data_vtbl_t HTMLOptionElementFactory_dispex_vtbl = { HTMLOptionElementFactory_value, @@ -649,7 +650,8 @@ dispex_static_data_t HTMLOptionElementFactory_dispex = { &HTMLOptionElementFactory_dispex_vtbl, PROTO_ID_NULL, IHTMLOptionElementFactory_tid, - HTMLOptionElementFactory_iface_tids, + no_iface_tids, + HTMLOptionElementFactory_init_dispex_info }; struct HTMLSelectElement { diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 5fa9206ea8d..8a3292581ed 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -547,7 +547,6 @@ sync_test("builtin_prototypes", function() { ok(Object.prototype.hasOwnProperty.call(obj, special_ctors[i][1][j]), special_ctors[i][1][j] + " not a property of " + name + " constructor."); if(special_ctors[i][2]) for(var j = 0; j < special_ctors[i][2].length; j++) - todo_wine_if(special_ctors[i][2][j] === "create" && name !== "XMLHttpRequest"). ok(!Object.prototype.hasOwnProperty.call(obj, special_ctors[i][2][j]), special_ctors[i][2][j] + " is a property of " + name + " constructor."); ok(Object.getPrototypeOf(obj) === Function.prototype, "getPrototypeOf(" + name + " constructor) = " + Object.getPrototypeOf(obj)); From 2ef70f4daae6cd31b2b3f96c3b71b77b3ae5392e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:04 +0200 Subject: [PATCH 0890/2777] mshtml: Allow instanceof for proxy constructors. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even if they aren't functions. Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/engine.c | 2 +- dlls/jscript/jscript.h | 1 + dlls/jscript/tests/api.js | 1 + dlls/mshtml/dispex.c | 7 +++++++ dlls/mshtml/htmldoc.c | 6 ++++++ dlls/mshtml/htmlwindow.c | 6 ++++++ dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/es5.js | 19 +++++++++++++++++++ 8 files changed, 42 insertions(+), 1 deletion(-) diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c index fb636afa9b4..19823a172d7 100644 --- a/dlls/jscript/engine.c +++ b/dlls/jscript/engine.c @@ -1881,7 +1881,7 @@ static HRESULT interp_instanceof(script_ctx_t *ctx) return E_FAIL; } - if(is_class(obj, JSCLASS_FUNCTION)) { + if(is_class(obj, JSCLASS_FUNCTION) || (obj->proxy && obj->proxy->lpVtbl->IsConstructor(obj->proxy))) { hres = jsdisp_propget_name(obj, L"prototype", &prot); }else { hres = JS_E_FUNCTION_EXPECTED; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 7c9d234f822..6da6e6e153c 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -86,6 +86,7 @@ typedef struct { IDispatch* (STDMETHODCALLTYPE *GetDefaultConstructor)(IWineDispatchProxyPrivate *This, IWineDispatchProxyPrivate *window, struct proxy_prototypes *prots); HRESULT (STDMETHODCALLTYPE *DefineConstructors)(IWineDispatchProxyPrivate *This, struct proxy_prototypes **prots_ref); BOOL (STDMETHODCALLTYPE *IsPrototype)(IWineDispatchProxyPrivate *This); + BOOL (STDMETHODCALLTYPE *IsConstructor)(IWineDispatchProxyPrivate *This); HRESULT (STDMETHODCALLTYPE *PropFixOverride)(IWineDispatchProxyPrivate *This, struct proxy_prop_info *info); HRESULT (STDMETHODCALLTYPE *PropOverride)(IWineDispatchProxyPrivate *This, const WCHAR *name, VARIANT *value); HRESULT (STDMETHODCALLTYPE *PropDefineOverride)(IWineDispatchProxyPrivate *This, struct proxy_prop_info *info); diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index a3b2bbcbba5..a3f81da6f60 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -2666,6 +2666,7 @@ testException(function() {not_existing_variable.something();}, "E_UNDEFINED"); testException(function() {date();}, "E_NOT_FUNC"); testException(function() {arr();}, "E_NOT_FUNC"); testException(function() {(new Object) instanceof (new Object);}, "E_NOT_FUNC"); +testException(function() {var o = new Object(); o.prototype = new Object(); (new Object) instanceof o;}, "E_NOT_FUNC"); testException(function() {eval("nonexistingfunc()")}, "E_OBJECT_EXPECTED"); testException(function() {(new Object()) instanceof 3;}, "E_NOT_FUNC"); testException(function() {(new Object()) instanceof null;}, "E_NOT_FUNC"); diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 7d2b4c01bff..ed25c4f7cbd 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -2978,6 +2978,12 @@ static BOOL WINAPI WineDispatchProxyPrivate_IsPrototype(IWineDispatchProxyPrivat return to_proxy_prototype(This) != NULL; } +static BOOL WINAPI WineDispatchProxyPrivate_IsConstructor(IWineDispatchProxyPrivate *iface) +{ + DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); + return This->outer->lpVtbl == &proxy_ctor_vtbl; +} + static HRESULT WINAPI WineDispatchProxyPrivate_PropFixOverride(IWineDispatchProxyPrivate *iface, struct proxy_prop_info *info) { DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); @@ -3217,6 +3223,7 @@ static IWineDispatchProxyPrivateVtbl WineDispatchProxyPrivateVtbl = { WineDispatchProxyPrivate_GetDefaultConstructor, WineDispatchProxyPrivate_DefineConstructors, WineDispatchProxyPrivate_IsPrototype, + WineDispatchProxyPrivate_IsConstructor, WineDispatchProxyPrivate_PropFixOverride, WineDispatchProxyPrivate_PropOverride, WineDispatchProxyPrivate_PropDefineOverride, diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index a1f44a084fa..94357fae90a 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -5221,6 +5221,11 @@ static BOOL WINAPI DocWineDispProxyPrivate_IsPrototype(IWineDispatchProxyPrivate return FALSE; } +static BOOL WINAPI DocWineDispProxyPrivate_IsConstructor(IWineDispatchProxyPrivate *iface) +{ + return FALSE; +} + static HRESULT WINAPI DocWineDispProxyPrivate_PropFixOverride(IWineDispatchProxyPrivate *iface, struct proxy_prop_info *info) { HTMLDocumentNode *This = impl_from_IWineDispatchProxyPrivate(iface); @@ -5380,6 +5385,7 @@ static const IWineDispatchProxyPrivateVtbl DocDispatchExVtbl = { DocWineDispProxyPrivate_GetDefaultConstructor, DocWineDispProxyPrivate_DefineConstructors, DocWineDispProxyPrivate_IsPrototype, + DocWineDispProxyPrivate_IsConstructor, DocWineDispProxyPrivate_PropFixOverride, DocWineDispProxyPrivate_PropOverride, DocWineDispProxyPrivate_PropDefineOverride, diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index e6ea88cc1c3..f81a75a3b80 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -3909,6 +3909,11 @@ static BOOL WINAPI WindowWineDispProxyPrivate_IsPrototype(IWineDispatchProxyPriv return FALSE; } +static BOOL WINAPI WindowWineDispProxyPrivate_IsConstructor(IWineDispatchProxyPrivate *iface) +{ + return FALSE; +} + static HRESULT WINAPI WindowWineDispProxyPrivate_PropFixOverride(IWineDispatchProxyPrivate *iface, struct proxy_prop_info *info) { HTMLWindow *This = impl_from_IWineDispatchProxyPrivate(iface); @@ -4064,6 +4069,7 @@ static const IWineDispatchProxyPrivateVtbl WindowDispExVtbl = { WindowWineDispProxyPrivate_GetDefaultConstructor, WindowWineDispProxyPrivate_DefineConstructors, WindowWineDispProxyPrivate_IsPrototype, + WindowWineDispProxyPrivate_IsConstructor, WindowWineDispProxyPrivate_PropFixOverride, WindowWineDispProxyPrivate_PropOverride, WindowWineDispProxyPrivate_PropDefineOverride, diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 217a75a946a..b106e357385 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -79,6 +79,7 @@ typedef struct { IDispatch* (STDMETHODCALLTYPE *GetDefaultConstructor)(IWineDispatchProxyPrivate *This, IWineDispatchProxyPrivate *window, struct proxy_prototypes *prots); HRESULT (STDMETHODCALLTYPE *DefineConstructors)(IWineDispatchProxyPrivate *This, struct proxy_prototypes **prots_ref); BOOL (STDMETHODCALLTYPE *IsPrototype)(IWineDispatchProxyPrivate *This); + BOOL (STDMETHODCALLTYPE *IsConstructor)(IWineDispatchProxyPrivate *This); HRESULT (STDMETHODCALLTYPE *PropFixOverride)(IWineDispatchProxyPrivate *This, struct proxy_prop_info *info); HRESULT (STDMETHODCALLTYPE *PropOverride)(IWineDispatchProxyPrivate *This, const WCHAR *name, VARIANT *value); HRESULT (STDMETHODCALLTYPE *PropDefineOverride)(IWineDispatchProxyPrivate *This, struct proxy_prop_info *info); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index d1eb6ae5ca3..dba924eb8f5 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2942,6 +2942,25 @@ sync_test("functions scope", function() { })(); }); +sync_test("instanceof", function() { + var r; + + try { + ({} instanceof { prototype: {} }); + ok(false, "expected exception using it on non-function object"); + }catch(e) { + ok(e.number === 0xa138a - 0x80000000, "using it on non-function object threw " + e.number); + } + + r = (document.createElement("iframe") instanceof HTMLIFrameElement); + ok(r === true, "iframe element not instance of HTMLIFrameElement"); + r = (document.createElement("div") instanceof HTMLIFrameElement); + ok(r === false, "div element instance of HTMLIFrameElement"); + r = (document instanceof Node); + todo_wine. + ok(r === true, "document not instance of Node"); +}); + sync_test("console", function() { var except From a0f3906d6811997862ab5fbc0dd230234dd1ca46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:04 +0200 Subject: [PATCH 0891/2777] mshtml: Partially implement other legacy constructors. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The constructors are based on IHTMLDOMConstructorCollection, but the interface is not exposed on native. Some constructors are not implemented because we don't have the objects, so they are commented out, but kept there since the order must match when implemented. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/dispex.c | 39 +++++ dlls/mshtml/htmlwindow.c | 275 +++++++++++++++++++++++++++++- dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/documentmode.js | 161 ++++++++++++++++- dlls/mshtml/tests/dom.c | 4 + 5 files changed, 471 insertions(+), 9 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index ed25c4f7cbd..d4ee67b1326 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -2160,6 +2160,45 @@ static void legacy_prototype_init_dispex_info(dispex_data_t *info, compat_mode_t memset(func, 0, (info->func_size - i) * sizeof(*func)); } +HRESULT legacy_ctor_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *params, + VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + switch(flags) { + case DISPATCH_METHOD|DISPATCH_PROPERTYGET: + if(!res) + return E_INVALIDARG; + /* fall through */ + case DISPATCH_METHOD: + case DISPATCH_CONSTRUCT: + return MSHTML_E_INVALID_ACTION; + case DISPATCH_PROPERTYGET: { + static const WCHAR prefix[8] = L"[object "; + static const WCHAR suffix[] = L"]"; + WCHAR buf[ARRAY_SIZE(prefix) + 28 + ARRAY_SIZE(suffix)], *p = buf; + const WCHAR *name = dispex->info->desc->name; + unsigned len = wcslen(name); + + memcpy(p, prefix, sizeof(prefix)); + p += ARRAY_SIZE(prefix); + memcpy(p, name, len * sizeof(WCHAR)); + p += len; + memcpy(p, suffix, sizeof(suffix)); + + if(!(V_BSTR(res) = SysAllocString(buf))) + return E_OUTOFMEMORY; + V_VT(res) = VT_BSTR; + break; + } + case DISPATCH_PROPERTYPUTREF|DISPATCH_PROPERTYPUT: + case DISPATCH_PROPERTYPUTREF: + case DISPATCH_PROPERTYPUT: + break; + default: + return E_INVALIDARG; + } + return S_OK; +} + HRESULT legacy_ctor_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid) { if((flags & fdexNameCaseInsensitive) ? !wcsicmp(name, L"prototype") : !wcscmp(name, L"prototype")) { diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index f81a75a3b80..1b26c1bf081 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -176,11 +176,193 @@ static HRESULT get_legacy_ctor(HTMLInnerWindow *window, legacy_ctor_id_t ctor_id return S_OK; } +static inline struct legacy_ctor *legacy_ctor_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct legacy_ctor, IUnknown_iface); +} + static inline struct legacy_ctor *legacy_ctor_from_IDispatch(IDispatch *iface) { return CONTAINING_RECORD((IDispatchEx*)iface, struct legacy_ctor, dispex.IDispatchEx_iface); } +static HRESULT WINAPI legacy_ctor_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) +{ + struct legacy_ctor *This = legacy_ctor_from_IUnknown(iface); + + TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); + + if(IsEqualGUID(&IID_IUnknown, riid)) { + *ppv = &This->IUnknown_iface; + }else if(dispex_query_interface(&This->dispex, riid, ppv)) { + return *ppv ? S_OK : E_NOINTERFACE; + }else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI legacy_ctor_AddRef(IUnknown *iface) +{ + struct legacy_ctor *This = legacy_ctor_from_IUnknown(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI legacy_ctor_Release(IUnknown *iface) +{ + struct legacy_ctor *This = legacy_ctor_from_IUnknown(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if(!ref) { + release_dispex(&This->dispex); + free(This); + } + return ref; +} + +static const IUnknownVtbl legacy_ctor_vtbl = { + legacy_ctor_QueryInterface, + legacy_ctor_AddRef, + legacy_ctor_Release +}; + +static const dispex_static_data_vtbl_t legacy_ctor_dispex_vtbl = { + legacy_ctor_value, + legacy_ctor_get_dispid, + legacy_ctor_get_name, + legacy_ctor_invoke, + legacy_ctor_delete +}; + +static struct { + dispex_static_data_t dispex; + prototype_id_t prototype_id; +} legacy_ctor_static_data[] = { +#define X(name, proto_id) \ +{ \ + { \ + L ## name, \ + &legacy_ctor_dispex_vtbl, \ + PROTO_ID_NULL, \ + NULL_tid, \ + no_iface_tids \ + }, \ + proto_id \ +}, + X("Attr", PROTO_ID_HTMLDOMAttribute) + /* X("BehaviorUrnsCollection", PROTO_ID_?) */ + /* X("BookmarkCollection", PROTO_ID_?) */ + /* X("CompatibleInfo", PROTO_ID_?) */ + /* X("CompatibleInfoCollection", PROTO_ID_?) */ + /* X("ControlRangeCollection", PROTO_ID_?) */ + X("CSSCurrentStyleDeclaration", PROTO_ID_HTMLCurrentStyle) + X("CSSRuleList", PROTO_ID_HTMLStyleSheetRulesCollection) + /* X("CSSRuleStyleDeclaration", PROTO_ID_?) */ + X("CSSStyleDeclaration", PROTO_ID_HTMLW3CComputedStyle) + X("CSSStyleRule", PROTO_ID_HTMLStyleSheetRule) + X("CSSStyleSheet", PROTO_ID_HTMLStyleSheet) + /* X("DataTransfer", PROTO_ID_?) */ + X("DOMImplementation", PROTO_ID_HTMLDOMImplementation) + X("Element", PROTO_ID_HTMLElement) + X("Event", PROTO_ID_HTMLEventObj) + X("History", PROTO_ID_History) + /* X("HTCElementBehaviorDefaults", PROTO_ID_?) */ + X("HTMLAnchorElement", PROTO_ID_HTMLAnchorElement) + X("HTMLAreaElement", PROTO_ID_HTMLAreaElement) + /* X("HTMLAreasCollection", PROTO_ID_?) */ + /* X("HTMLBaseElement", PROTO_ID_?) */ + /* X("HTMLBaseFontElement", PROTO_ID_?) */ + /* X("HTMLBGSoundElement", PROTO_ID_?) */ + /* X("HTMLBlockElement", PROTO_ID_?) */ + X("HTMLBodyElement", PROTO_ID_HTMLBodyElement) + /* X("HTMLBRElement", PROTO_ID_?) */ + X("HTMLButtonElement", PROTO_ID_HTMLButtonElement) + X("HTMLCollection", PROTO_ID_HTMLElementCollection) + X("HTMLCommentElement", PROTO_ID_HTMLCommentElement) + /* X("HTMLDDElement", PROTO_ID_?) */ + /* X("HTMLDivElement", PROTO_ID_?) */ + /* X("HTMLDListElement", PROTO_ID_?) */ + X("HTMLDocument", PROTO_ID_HTMLDocument) + /* X("HTMLDTElement", PROTO_ID_?) */ + X("HTMLEmbedElement", PROTO_ID_HTMLEmbedElement) + /* X("HTMLFieldSetElement", PROTO_ID_?) */ + /* X("HTMLFontElement", PROTO_ID_?) */ + X("HTMLFormElement", PROTO_ID_HTMLFormElement) + X("HTMLFrameElement", PROTO_ID_HTMLFrameElement) + /* X("HTMLFrameSetElement", PROTO_ID_?) */ + X("HTMLGenericElement", PROTO_ID_HTMLGenericElement) + X("HTMLHeadElement", PROTO_ID_HTMLHeadElement) + /* X("HTMLHeadingElement", PROTO_ID_?) */ + /* X("HTMLHRElement", PROTO_ID_?) */ + X("HTMLHtmlElement", PROTO_ID_HTMLHtmlElement) + /* X("HTMLIFrameElement", PROTO_ID_?) */ + X("HTMLImageElement", PROTO_ID_HTMLImgElement) + X("HTMLInputElement", PROTO_ID_HTMLInputElement) + /* X("HTMLIsIndexElement", PROTO_ID_?) */ + X("HTMLLabelElement", PROTO_ID_HTMLLabelElement) + /* X("HTMLLegendElement", PROTO_ID_?) */ + /* X("HTMLLIElement", PROTO_ID_?) */ + X("HTMLLinkElement", PROTO_ID_HTMLLinkElement) + /* X("HTMLMapElement", PROTO_ID_?) */ + /* X("HTMLMarqueeElement", PROTO_ID_?) */ + X("HTMLMetaElement", PROTO_ID_HTMLMetaElement) + /* X("HTMLModelessDialog", PROTO_ID_?) */ + /* X("HTMLNamespaceInfo", PROTO_ID_?) */ + X("HTMLNamespaceInfoCollection", PROTO_ID_HTMLNamespaceCollection) + /* X("HTMLNextIdElement", PROTO_ID_?) */ + /* X("HTMLNoShowElement", PROTO_ID_?) */ + X("HTMLObjectElement", PROTO_ID_HTMLObjectElement) + /* X("HTMLOListElement", PROTO_ID_?) */ + X("HTMLOptionElement", PROTO_ID_HTMLOptionElement) + /* X("HTMLParagraphElement", PROTO_ID_?) */ + /* X("HTMLParamElement", PROTO_ID_?) */ + /* X("HTMLPhraseElement", PROTO_ID_?) */ + X("HTMLPluginsCollection", PROTO_ID_HTMLPluginsCollection) + /* X("HTMLPopup", PROTO_ID_?) */ + X("HTMLScriptElement", PROTO_ID_HTMLScriptElement) + X("HTMLSelectElement", PROTO_ID_HTMLSelectElement) + /* X("HTMLSpanElement", PROTO_ID_?) */ + /* X("HTMLStyleElement", PROTO_ID_?) */ + /* X("HTMLTableCaptionElement", PROTO_ID_?) */ + X("HTMLTableCellElement", PROTO_ID_HTMLTableCellElement) + /* X("HTMLTableColElement", PROTO_ID_?) */ + X("HTMLTableElement", PROTO_ID_HTMLTableElement) + X("HTMLTableRowElement", PROTO_ID_HTMLTableRowElement) + /* X("HTMLTableSectionElement", PROTO_ID_?) */ + X("HTMLTextAreaElement", PROTO_ID_HTMLTextAreaElement) + /* X("HTMLTextElement", PROTO_ID_?) */ + X("HTMLTitleElement", PROTO_ID_HTMLTitleElement) + /* X("HTMLUListElement", PROTO_ID_?) */ + X("HTMLUnknownElement", PROTO_ID_HTMLUnknownElement) + X("Location", PROTO_ID_HTMLLocation) + X("NamedNodeMap", PROTO_ID_HTMLAttributeCollection) + X("Navigator", PROTO_ID_Navigator) + X("NodeList", PROTO_ID_HTMLDOMChildrenCollection) + X("Screen", PROTO_ID_HTMLScreen) + X("Selection", PROTO_ID_HTMLSelectionObject) + /* X("StaticNodeList", PROTO_ID_?) */ + X("Storage", PROTO_ID_HTMLStorage) + X("StyleSheetList", PROTO_ID_HTMLStyleSheetsCollection) + /* X("StyleSheetPage", PROTO_ID_?) */ + /* X("StyleSheetPageList", PROTO_ID_?) */ + X("Text", PROTO_ID_HTMLDOMTextNode) + X("TextRange", PROTO_ID_HTMLTextRange) + /* X("TextRangeCollection", PROTO_ID_?) */ + X("TextRectangle", PROTO_ID_HTMLRect) + X("TextRectangleList", PROTO_ID_HTMLRectCollection) + X("Window", PROTO_ID_HTMLWindow) +#undef X +}; + static inline HTMLWindow *impl_from_IHTMLWindow2(IHTMLWindow2 *iface) { return CONTAINING_RECORD(iface, HTMLWindow, IHTMLWindow2_iface); @@ -3616,6 +3798,9 @@ static HRESULT WINAPI WindowDispEx_Invoke(IDispatchEx *iface, DISPID dispIdMembe static global_prop_t *alloc_global_prop(HTMLInnerWindow *This, global_prop_type_t type, BSTR name) { + if(This->global_prop_cnt > MSHTML_CUSTOM_DISPID_CNT - ARRAY_SIZE(legacy_ctor_static_data)) + return NULL; + if(This->global_prop_cnt == This->global_prop_size) { global_prop_t *new_props; DWORD new_size; @@ -3677,6 +3862,25 @@ HRESULT search_window_props(HTMLInnerWindow *This, BSTR bstrName, DWORD grfdex, return DISP_E_UNKNOWNNAME; } +static DISPID lookup_legacy_ctor_prop(HTMLInnerWindow *window, BSTR name) +{ + DWORD i, a = 0, b = ARRAY_SIZE(legacy_ctor_static_data); + int c; + + if(dispex_compat_mode(&window->event_target.dispex) != COMPAT_MODE_IE8) + return DISPID_UNKNOWN; + + while(a < b) { + i = (a + b) / 2; + c = wcscmp(legacy_ctor_static_data[i].dispex.name, name); + if(!c) + return i + (MSHTML_DISPID_CUSTOM_MAX - ARRAY_SIZE(legacy_ctor_static_data) + 1); + if(c > 0) b = i; + else a = i + 1; + } + return DISPID_UNKNOWN; +} + static HRESULT lookup_custom_prop(HTMLWindow *html_window, BSTR name, DISPID *pid) { HTMLInnerWindow *window = html_window->inner_window; @@ -3788,6 +3992,7 @@ static HRESULT WINAPI WindowDispEx_GetDispID(IDispatchEx *iface, BSTR bstrName, HTMLInnerWindow *window = This->inner_window; IWineDispatchProxyCbPrivate *proxy = window->event_target.dispex.proxy; HRESULT hres; + DISPID id; if(proxy) return IDispatchEx_GetDispID((IDispatchEx*)proxy, bstrName, grfdex, pid); @@ -3798,6 +4003,12 @@ static HRESULT WINAPI WindowDispEx_GetDispID(IDispatchEx *iface, BSTR bstrName, if(hres != DISP_E_UNKNOWNNAME) return hres; + id = lookup_legacy_ctor_prop(window, bstrName); + if(id != DISPID_UNKNOWN) { + *pid = id; + return S_OK; + } + hres = IDispatchEx_GetDispID(&window->base.inner_window->event_target.dispex.IDispatchEx_iface, bstrName, grfdex, pid); if(hres != DISP_E_UNKNOWNNAME) return hres; @@ -3815,18 +4026,35 @@ static HRESULT WINAPI WindowDispEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID static HRESULT WINAPI WindowDispEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex) { HTMLWindow *This = impl_from_IDispatchEx(iface); + IWineDispatchProxyCbPrivate *proxy = This->inner_window->event_target.dispex.proxy; + + if(proxy) + return IDispatchEx_DeleteMemberByName((IDispatchEx*)proxy, bstrName, grfdex); TRACE("(%p)->(%s %lx)\n", This, debugstr_w(bstrName), grfdex); + if(lookup_legacy_ctor_prop(This->inner_window, bstrName) != DISPID_UNKNOWN) + return MSHTML_E_INVALID_ACTION; + return IDispatchEx_DeleteMemberByName(&This->inner_window->event_target.dispex.IDispatchEx_iface, bstrName, grfdex); } static HRESULT WINAPI WindowDispEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id) { HTMLWindow *This = impl_from_IDispatchEx(iface); + IWineDispatchProxyCbPrivate *proxy = This->inner_window->event_target.dispex.proxy; + DWORD idx; + + if(proxy && id >= 0) + return IDispatchEx_DeleteMemberByDispID((IDispatchEx*)proxy, id); TRACE("(%p)->(%lx)\n", This, id); + idx = id - (MSHTML_DISPID_CUSTOM_MAX - ARRAY_SIZE(legacy_ctor_static_data) + 1); + if(idx < ARRAY_SIZE(legacy_ctor_static_data) && + dispex_compat_mode(&This->inner_window->event_target.dispex) == COMPAT_MODE_IE8) + return MSHTML_E_INVALID_ACTION; + return IDispatchEx_DeleteMemberByDispID(&This->inner_window->event_target.dispex.IDispatchEx_iface, id); } @@ -4232,11 +4460,19 @@ static HRESULT HTMLWindow_get_name(DispatchEx *dispex, DISPID id, BSTR *name) { HTMLInnerWindow *This = impl_from_DispatchEx(dispex); DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN; + const WCHAR *str; - if(idx >= This->global_prop_cnt) - return DISP_E_MEMBERNOTFOUND; + if(idx >= This->global_prop_cnt) { + idx = id - (MSHTML_DISPID_CUSTOM_MAX - ARRAY_SIZE(legacy_ctor_static_data) + 1); + if(idx >= ARRAY_SIZE(legacy_ctor_static_data) || + dispex_compat_mode(&This->event_target.dispex) != COMPAT_MODE_IE8) + return DISP_E_MEMBERNOTFOUND; - return (*name = SysAllocString(This->global_props[idx].name)) ? S_OK : E_OUTOFMEMORY; + str = legacy_ctor_static_data[idx].dispex.name; + }else { + str = This->global_props[idx].name; + } + return (*name = SysAllocString(str)) ? S_OK : E_OUTOFMEMORY; } static HRESULT HTMLWindow_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, @@ -4248,8 +4484,37 @@ static HRESULT HTMLWindow_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID HRESULT hres; idx = id - MSHTML_DISPID_CUSTOM_MIN; - if(idx >= This->global_prop_cnt) - return DISP_E_MEMBERNOTFOUND; + if(idx >= This->global_prop_cnt) { + idx = id - (MSHTML_DISPID_CUSTOM_MAX - ARRAY_SIZE(legacy_ctor_static_data) + 1); + if(idx >= ARRAY_SIZE(legacy_ctor_static_data) || + dispex_compat_mode(&This->event_target.dispex) != COMPAT_MODE_IE8) + return DISP_E_MEMBERNOTFOUND; + + switch(flags) { + case DISPATCH_METHOD|DISPATCH_PROPERTYGET: + if(!res) + return E_INVALIDARG; + /* fall through */ + case DISPATCH_METHOD: + case DISPATCH_CONSTRUCT: + return MSHTML_E_INVALID_ACTION; + case DISPATCH_PROPERTYGET: + /* For these generic constructors, LEGACY_CTOR_ID is the same as the PROTO_ID */ + hres = get_legacy_ctor(This, legacy_ctor_static_data[idx].prototype_id, legacy_ctor_static_data[idx].prototype_id, + &legacy_ctor_static_data[idx].dispex, &legacy_ctor_vtbl, &V_DISPATCH(res)); + if(FAILED(hres)) + return hres; + V_VT(res) = VT_DISPATCH; + break; + case DISPATCH_PROPERTYPUTREF|DISPATCH_PROPERTYPUT: + case DISPATCH_PROPERTYPUTREF: + case DISPATCH_PROPERTYPUT: + break; + default: + return E_INVALIDARG; + } + return S_OK; + } prop = This->global_props+idx; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index b106e357385..4fb4f272b6b 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -1185,6 +1185,7 @@ HRESULT update_window_doc(HTMLInnerWindow*) DECLSPEC_HIDDEN; HTMLOuterWindow *mozwindow_to_window(const mozIDOMWindowProxy*) DECLSPEC_HIDDEN; void get_top_window(HTMLOuterWindow*,HTMLOuterWindow**) DECLSPEC_HIDDEN; struct legacy_prototype *get_legacy_prototype(HTMLInnerWindow*,prototype_id_t,compat_mode_t) DECLSPEC_HIDDEN; +HRESULT legacy_ctor_value(DispatchEx*,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*); HRESULT legacy_ctor_get_dispid(DispatchEx*,BSTR,DWORD,DISPID*) DECLSPEC_HIDDEN; HRESULT legacy_ctor_get_name(DispatchEx*,DISPID,BSTR*) DECLSPEC_HIDDEN; HRESULT legacy_ctor_invoke(DispatchEx*,IDispatch*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 8a3292581ed..653c845fc88 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -794,10 +794,6 @@ sync_test("builtin_prototypes", function() { set_obj("Window"); } - // todo_wine - if(v === 8 && window.Event === undefined) - return; - if(v >= 8 && v < 11) { set_obj(v < 9 ? "Event" : "MSEventObj", document.createEventObject()); test_prop("x"); @@ -983,6 +979,163 @@ sync_test("builtin_prototypes", function() { ok(r === 0xffff - 0x80000000, "set proto.charset error code = " + r); } } + + + if(v < 9) { + // IHTMLDOMConstructorCollection props + var ctors = [ + [ "Attr" ], + [ "BehaviorUrnsCollection" ], + [ "BookmarkCollection" ], + [ "CSSCurrentStyleDeclaration" ], + [ "CSSRuleList" ], + [ "CSSRuleStyleDeclaration" ], + [ "CSSStyleDeclaration" ], + [ "CSSStyleRule" ], + [ "CSSStyleSheet" ], + [ "CompatibleInfo" ], + [ "CompatibleInfoCollection" ], + [ "ControlRangeCollection" ], + [ "DOMImplementation" ], + [ "DataTransfer" ], + [ "Element" ], + [ "Event" ], + [ "HTCElementBehaviorDefaults" ], + [ "HTMLAnchorElement" ], + [ "HTMLAreaElement" ], + [ "HTMLAreasCollection" ], + [ "HTMLBGSoundElement" ], + [ "HTMLBRElement" ], + [ "HTMLBaseElement" ], + [ "HTMLBaseFontElement" ], + [ "HTMLBlockElement" ], + [ "HTMLBodyElement" ], + [ "HTMLButtonElement" ], + [ "HTMLCollection" ], + [ "HTMLCommentElement" ], + [ "HTMLDDElement" ], + [ "HTMLDListElement" ], + [ "HTMLDTElement" ], + [ "HTMLDivElement" ], + [ "HTMLDocument" ], + [ "HTMLEmbedElement" ], + [ "HTMLFieldSetElement" ], + [ "HTMLFontElement" ], + [ "HTMLFormElement" ], + [ "HTMLFrameElement" ], + [ "HTMLFrameSetElement" ], + [ "HTMLGenericElement" ], + [ "HTMLHRElement" ], + [ "HTMLHeadElement" ], + [ "HTMLHeadingElement" ], + [ "HTMLHtmlElement" ], + [ "HTMLIFrameElement" ], + [ "HTMLImageElement" ], + [ "HTMLInputElement" ], + [ "HTMLIsIndexElement" ], + [ "HTMLLIElement" ], + [ "HTMLLabelElement" ], + [ "HTMLLegendElement" ], + [ "HTMLLinkElement" ], + [ "HTMLMapElement" ], + [ "HTMLMarqueeElement" ], + [ "HTMLMetaElement" ], + [ "HTMLModelessDialog" ], + [ "HTMLNamespaceInfo" ], + [ "HTMLNamespaceInfoCollection" ], + [ "HTMLNextIdElement" ], + [ "HTMLNoShowElement" ], + [ "HTMLOListElement" ], + [ "HTMLObjectElement" ], + [ "HTMLOptionElement" ], + [ "HTMLParagraphElement" ], + [ "HTMLParamElement" ], + [ "HTMLPhraseElement" ], + [ "HTMLPluginsCollection" ], + [ "HTMLPopup" ], + [ "HTMLScriptElement" ], + [ "HTMLSelectElement" ], + [ "HTMLSpanElement" ], + [ "HTMLStyleElement" ], + [ "HTMLTableCaptionElement" ], + [ "HTMLTableCellElement" ], + [ "HTMLTableColElement" ], + [ "HTMLTableElement" ], + [ "HTMLTableRowElement" ], + [ "HTMLTableSectionElement" ], + [ "HTMLTextAreaElement" ], + [ "HTMLTextElement" ], + [ "HTMLTitleElement" ], + [ "HTMLUListElement" ], + [ "HTMLUnknownElement" ], + [ "History" ], + [ "Image", 0, "HTMLImageElement" ], + [ "Location" ], + [ "NamedNodeMap" ], + [ "Navigator" ], + [ "NodeList" ], + [ "Option", 0, "HTMLOptionElement" ], + [ "Screen" ], + [ "Selection" ], + [ "StaticNodeList" ], + [ "Storage" ], + [ "StyleSheetList" ], + [ "StyleSheetPage" ], + [ "StyleSheetPageList" ], + [ "Text" ], + [ "TextRange" ], + [ "TextRangeCollection" ], + [ "TextRectangle" ], + [ "TextRectangleList" ], + [ "Window" ], + [ "XDomainRequest", 0 ], + [ "XMLHttpRequest", 0 ] + ]; + for(var i = 0; i < ctors.length; i++) { + if(!(ctors[i][0] in window) && (v >= 8 || ctors[i][0] === "XDomainRequest")) { + todo_wine.ok(false, ctors[i][0] + " not implemented"); + continue; + } + var a, b; + r = 0; + try { + eval("a = " + ctors[i][0] + "; b = window." + ctors[i][0] + ";"); + }catch(ex) { + r = ex.number; + } + if(r === 0x4001 - 0x80000000) /* todo_wine XDomainRequest */ + continue; + if(v < 8 && (ctors[i].length < 2 || v < ctors[i][1])) + ok(r === 0xa1391 - 0x80000000, ctors[i][0] + " not undefined: " + r); + else { + ok(r === 0, ctors[i][0] + " exception code: " + r); + ok(a === b, ctors[i][0] + ": " + a + " != " + b); + ok(ctors[i][0] in window, ctors[i][0] + " in window"); + if(v >= 8) + todo_wine_if(ctors[i][0] == "Image" || ctors[i][0] == "Option" || ctors[i][0] == "XMLHttpRequest"). + ok(!(ctors[i][0] in window.Window.prototype), ctors[i][0] + " in Window.prototype"); + r = "" + a; + todo_wine_if(ctors[i][0] == "Image" || ctors[i][0] == "Option" || ctors[i][0] == "XMLHttpRequest"). + ok(r === "[object " + ctors[i][ctors[i].length < 3 ? 0 : 2] + "]", ctors[i][0] + " returned " + r); + r = "" + a.prototype; + ok(r === "[Interface prototype object]", ctors[i][0] + ".prototype returned " + r); + + var props = [ "LookupGetter", "LookupSetter", "DefineGetter", "DefineSetter" ]; + for(var j = 0; j < props.length; j++) { + ok(!(props[j] in a.prototype), props[j] + " in " + ctors[i][0] + ".prototype"); + ok(!(props[j] in a), props[j] + " in " + ctors[i][0]); + } + ok(!("constructor" in a), "constructor in " + ctors[i][0]); + + if(v < 8 || ctors[i][0] === "HTMLModelessDialog") { + ok(!("constructor" in a.prototype), "constructor in " + ctors[i][0] + ".prototype"); + }else { + todo_wine. + ok("constructor" in a.prototype, "constructor not in " + ctors[i][0] + ".prototype"); + } + } + } + } }); sync_test("elem_props", function() { diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index ca1e0602a85..6b1290ca228 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -7267,6 +7267,7 @@ static void test_window(IHTMLDocument2 *doc) IHTMLWindow2 *window, *window2, *self, *parent; IHTMLWindow5 *window5; IHTMLWindow7 *window7; + IHTMLDOMConstructorCollection *ctor_col; IHTMLDocument2 *doc2 = NULL; IDispatch *disp; IUnknown *unk; @@ -7369,6 +7370,9 @@ static void test_window(IHTMLDocument2 *doc) win_skip("IHTMLWindow5 not supported!\n"); } + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLDOMConstructorCollection, (void**)&ctor_col); + ok(hres == E_NOINTERFACE, "QueryInterface for IHTMLDOMConstructorCollection returned %08lx\n", hres); + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow7, (void**)&window7); if(SUCCEEDED(hres)) { IHTMLCSSStyleDeclaration *computed_style; From 3d9eb299520c053b7ae7bea22c743b189b3d9659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:04 +0200 Subject: [PATCH 0892/2777] mshtml: Return invalid property when calling a method on a legacy prototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/dispex.c | 25 ++++++++++++++++++------- dlls/mshtml/tests/documentmode.js | 1 - 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index d4ee67b1326..f8d99117276 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -211,6 +211,7 @@ static inline dispex_data_t *proxy_prototype_object_info(struct proxy_prototype static func_disp_t *create_func_disp(DispatchEx*,func_info_t*); static HRESULT get_dynamic_prop(DispatchEx*,const WCHAR*,DWORD,dynamic_prop_t**); static HRESULT invoke_builtin_function(IDispatch*,func_info_t*,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*); +static inline BOOL is_legacy_prototype(IDispatch*); static inline struct proxy_prototype *to_proxy_prototype(DispatchEx*); static HRESULT load_typelib(void) @@ -988,11 +989,11 @@ static HRESULT function_apply(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARI { IDispatchEx *dispex = NULL; DISPPARAMS params = { 0 }; + HRESULT hres, errcode; IDispatch *this_obj; DISPID dispid; UINT argc = 0; VARIANT *arg; - HRESULT hres; VARIANT var; arg = dp->rgvarg + dp->cArgs - 1; @@ -1000,6 +1001,8 @@ static HRESULT function_apply(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARI return CTL_E_ILLEGALFUNCTIONCALL; this_obj = V_DISPATCH(arg); + errcode = is_legacy_prototype(this_obj) ? MSHTML_E_INVALID_PROPERTY : CTL_E_ILLEGALFUNCTIONCALL; + if(dp->cArgs >= 2) { UINT i, err = 0; IDispatch *disp; @@ -1007,7 +1010,7 @@ static HRESULT function_apply(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARI arg--; if((V_VT(arg) & ~VT_BYREF) != VT_DISPATCH) - return CTL_E_ILLEGALFUNCTIONCALL; + return errcode; disp = (V_VT(arg) & VT_BYREF) ? *(IDispatch**)(V_BYREF(arg)) : V_DISPATCH(arg); /* get the array length */ @@ -1023,7 +1026,7 @@ static HRESULT function_apply(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARI } SysFreeString(name); if(FAILED(hres) || dispid == DISPID_UNKNOWN) { - hres = CTL_E_ILLEGALFUNCTIONCALL; + hres = errcode; goto fail; } @@ -1042,7 +1045,7 @@ static HRESULT function_apply(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARI } VariantClear(res); if(FAILED(hres) || V_I4(&var) < 0) { - hres = CTL_E_ILLEGALFUNCTIONCALL; + hres = errcode; goto fail; } params.cArgs = V_I4(&var); @@ -1072,7 +1075,7 @@ static HRESULT function_apply(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARI V_VT(arg) = VT_EMPTY; continue; } - hres = CTL_E_ILLEGALFUNCTIONCALL; + hres = errcode; break; } if(dispex) @@ -1097,7 +1100,7 @@ static HRESULT function_apply(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARI fail: if(dispex) IDispatchEx_Release(dispex); - return (hres == E_UNEXPECTED) ? CTL_E_ILLEGALFUNCTIONCALL : hres; + return (hres == E_UNEXPECTED) ? errcode : hres; } static HRESULT function_call(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) @@ -1112,7 +1115,8 @@ static HRESULT function_call(func_disp_t *func, DISPPARAMS *dp, LCID lcid, VARIA hres = invoke_builtin_function(V_DISPATCH(arg), func->info, ¶ms, res, ei, caller); - return (hres == E_UNEXPECTED) ? CTL_E_ILLEGALFUNCTIONCALL : hres; + return (hres != E_UNEXPECTED) ? hres : + (is_legacy_prototype(V_DISPATCH(arg)) ? MSHTML_E_INVALID_PROPERTY : CTL_E_ILLEGALFUNCTIONCALL); } static const struct { @@ -3274,6 +3278,13 @@ static IWineDispatchProxyPrivateVtbl WineDispatchProxyPrivateVtbl = { WineDispatchProxyPrivate_CanGC }; +static inline BOOL is_legacy_prototype(IDispatch *disp) +{ + if(!disp || disp->lpVtbl != (const IDispatchVtbl*)&WineDispatchProxyPrivateVtbl) + return FALSE; + return (impl_from_IDispatchEx((IDispatchEx*)disp)->outer->lpVtbl == &legacy_prototype_vtbl); +} + BOOL dispex_query_interface(DispatchEx *This, REFIID riid, void **ppv) { if(IsEqualGUID(&IID_IDispatch, riid)) diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 653c845fc88..2f0130dac45 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -942,7 +942,6 @@ sync_test("builtin_prototypes", function() { }catch(ex) { r = ex.number; } - todo_wine_if(v < 9). ok(r === (v < 9 ? 0xa01b6 : 0xffff) - 0x80000000, "setAttribute on proto error code = " + r); r = 0; try { From 9af729b196d3f90781fd5d8f144e26754c6a1512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:04 +0200 Subject: [PATCH 0893/2777] mshtml: Use different legacy constructors for the builtin ones. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Image, Option and XMLHttpRequest are exposed due to the builtin getters of the window COM interfaces, but they do not actually return the same dispatch objects as the ones found by GetDispID, and neither is their default value the same. So use the legacy constructor lookup on them as well. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/dispex.c | 4 +- dlls/mshtml/htmlimg.c | 44 +++++++++++++++++---- dlls/mshtml/htmlselect.c | 44 +++++++++++++++++---- dlls/mshtml/htmlwindow.c | 63 +++++++++++++++++++++++-------- dlls/mshtml/mshtml_private.h | 7 ++++ dlls/mshtml/tests/documentmode.js | 1 - dlls/mshtml/tests/dom.c | 40 ++++++++++++++++++++ dlls/mshtml/xmlhttprequest.c | 27 ++++++++++++- 8 files changed, 197 insertions(+), 33 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index f8d99117276..77444a0ecb2 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -2385,8 +2385,8 @@ static IDispatch *get_proxy_constructor_disp(HTMLInnerWindow *window, prototype_ dispex_static_data_t *dispex; const void *vtbl; } ctors[] = { - { PROTO_ID_HTMLImgElement, &HTMLImageElementFactory_dispex, &HTMLImageElementFactoryVtbl }, - { PROTO_ID_HTMLOptionElement, &HTMLOptionElementFactory_dispex, &HTMLOptionElementFactoryVtbl }, + { PROTO_ID_HTMLImgElement, &HTMLImageCtor_dispex, &HTMLImageElementFactoryVtbl }, + { PROTO_ID_HTMLOptionElement, &HTMLOptionCtor_dispex, &HTMLOptionElementFactoryVtbl }, { PROTO_ID_HTMLXMLHttpRequest, &HTMLXMLHttpRequestFactory_dispex, &HTMLXMLHttpRequestFactoryVtbl } }; struct legacy_ctor *ctor; diff --git a/dlls/mshtml/htmlimg.c b/dlls/mshtml/htmlimg.c index 995ca2f1fb1..bd94ae64fa3 100644 --- a/dlls/mshtml/htmlimg.c +++ b/dlls/mshtml/htmlimg.c @@ -1023,25 +1023,55 @@ static HRESULT HTMLImageElementFactory_value(DispatchEx *dispex, LCID lcid, return S_OK; } -static void HTMLImageElementFactory_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) +static const dispex_static_data_vtbl_t HTMLImageElementFactory_dispex_vtbl = { + HTMLImageElementFactory_value, + legacy_ctor_get_dispid, + legacy_ctor_get_name, + legacy_ctor_invoke, + legacy_ctor_delete +}; + +static const tid_t HTMLImageElementFactory_iface_tids[] = { + IHTMLImageElementFactory_tid, + 0 +}; + +dispex_static_data_t HTMLImageElementFactory_dispex = { + L"HTMLImageElement", + &HTMLImageElementFactory_dispex_vtbl, + PROTO_ID_NULL, + IHTMLImageElementFactory_tid, + HTMLImageElementFactory_iface_tids +}; + +static HRESULT HTMLImageCtor_value(DispatchEx *iface, LCID lcid, WORD flags, DISPPARAMS *params, + VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + if(flags == DISPATCH_CONSTRUCT) + return HTMLImageElementFactory_value(iface, lcid, flags, params, res, ei, caller); + + return legacy_ctor_value(iface, lcid, flags, params, res, ei, caller); +} + +static void HTMLImageCtor_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) { if(compat_mode < COMPAT_MODE_IE9) dispex_info_add_interface(info, IHTMLImageElementFactory_tid, NULL); } -static const dispex_static_data_vtbl_t HTMLImageElementFactory_dispex_vtbl = { - HTMLImageElementFactory_value, +static const dispex_static_data_vtbl_t HTMLImageCtor_dispex_vtbl = { + HTMLImageCtor_value, legacy_ctor_get_dispid, legacy_ctor_get_name, legacy_ctor_invoke, legacy_ctor_delete }; -dispex_static_data_t HTMLImageElementFactory_dispex = { - L"Function", - &HTMLImageElementFactory_dispex_vtbl, +dispex_static_data_t HTMLImageCtor_dispex = { + L"HTMLImageElement", + &HTMLImageCtor_dispex_vtbl, PROTO_ID_NULL, IHTMLImageElementFactory_tid, no_iface_tids, - HTMLImageElementFactory_init_dispex_info + HTMLImageCtor_init_dispex_info }; diff --git a/dlls/mshtml/htmlselect.c b/dlls/mshtml/htmlselect.c index c96003b594d..c617b1fc605 100644 --- a/dlls/mshtml/htmlselect.c +++ b/dlls/mshtml/htmlselect.c @@ -631,27 +631,57 @@ static HRESULT HTMLOptionElementFactory_value(DispatchEx *dispex, LCID lcid, return S_OK; } -static void HTMLOptionElementFactory_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) +static const dispex_static_data_vtbl_t HTMLOptionElementFactory_dispex_vtbl = { + HTMLOptionElementFactory_value, + legacy_ctor_get_dispid, + legacy_ctor_get_name, + legacy_ctor_invoke, + legacy_ctor_delete +}; + +static const tid_t HTMLOptionElementFactory_iface_tids[] = { + IHTMLOptionElementFactory_tid, + 0 +}; + +dispex_static_data_t HTMLOptionElementFactory_dispex = { + L"HTMLOptionElement", + &HTMLOptionElementFactory_dispex_vtbl, + PROTO_ID_NULL, + IHTMLOptionElementFactory_tid, + HTMLOptionElementFactory_iface_tids +}; + +static HRESULT HTMLOptionCtor_value(DispatchEx *iface, LCID lcid, WORD flags, DISPPARAMS *params, + VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + if(flags == DISPATCH_CONSTRUCT) + return HTMLOptionElementFactory_value(iface, lcid, flags, params, res, ei, caller); + + return legacy_ctor_value(iface, lcid, flags, params, res, ei, caller); +} + +static void HTMLOptionCtor_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) { if(compat_mode < COMPAT_MODE_IE9) dispex_info_add_interface(info, IHTMLOptionElementFactory_tid, NULL); } -static const dispex_static_data_vtbl_t HTMLOptionElementFactory_dispex_vtbl = { - HTMLOptionElementFactory_value, +static const dispex_static_data_vtbl_t HTMLOptionCtor_dispex_vtbl = { + HTMLOptionCtor_value, legacy_ctor_get_dispid, legacy_ctor_get_name, legacy_ctor_invoke, legacy_ctor_delete }; -dispex_static_data_t HTMLOptionElementFactory_dispex = { - L"Function", - &HTMLOptionElementFactory_dispex_vtbl, +dispex_static_data_t HTMLOptionCtor_dispex = { + L"HTMLOptionElement", + &HTMLOptionCtor_dispex_vtbl, PROTO_ID_NULL, IHTMLOptionElementFactory_tid, no_iface_tids, - HTMLOptionElementFactory_init_dispex_info + HTMLOptionCtor_init_dispex_info }; struct HTMLSelectElement { diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 1b26c1bf081..62ba7cd6f06 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -243,6 +243,19 @@ static const dispex_static_data_vtbl_t legacy_ctor_dispex_vtbl = { legacy_ctor_delete }; +static const struct { + const WCHAR *name; + prototype_id_t prototype_id; + prototype_id_t ctor_id; + dispex_static_data_t *dispex; + const void *vtbl; +} special_ctor_static_data[] = { + { L"Image", PROTO_ID_HTMLImgElement, LEGACY_CTOR_ID_Image, &HTMLImageCtor_dispex, &HTMLImageElementFactoryVtbl }, + { L"Option", PROTO_ID_HTMLOptionElement, LEGACY_CTOR_ID_Option, &HTMLOptionCtor_dispex, &HTMLOptionElementFactoryVtbl }, + /* { L"XDomainRequest", PROTO_ID_?, LEGACY_CTOR_ID_?, ?, ? } */ + { L"XMLHttpRequest", PROTO_ID_HTMLXMLHttpRequest, LEGACY_CTOR_ID_HTMLXMLHttpRequest, &HTMLXMLHttpRequestCtor_dispex, &HTMLXMLHttpRequestFactoryVtbl } +}; + static struct { dispex_static_data_t dispex; prototype_id_t prototype_id; @@ -363,6 +376,8 @@ static struct { #undef X }; +enum { legacy_ctor_props_num = ARRAY_SIZE(special_ctor_static_data) + ARRAY_SIZE(legacy_ctor_static_data) }; + static inline HTMLWindow *impl_from_IHTMLWindow2(IHTMLWindow2 *iface) { return CONTAINING_RECORD(iface, HTMLWindow, IHTMLWindow2_iface); @@ -1027,7 +1042,7 @@ static HRESULT WINAPI HTMLWindow2_get_Image(IHTMLWindow2 *iface, IHTMLImageEleme TRACE("(%p)->(%p)\n", This, p); - hres = get_legacy_ctor(window, LEGACY_CTOR_ID_Image, PROTO_ID_HTMLImgElement, + hres = get_legacy_ctor(window, LEGACY_CTOR_ID_Image_builtin, PROTO_ID_HTMLImgElement, &HTMLImageElementFactory_dispex, &HTMLImageElementFactoryVtbl, &disp); if(SUCCEEDED(hres)) *p = &legacy_ctor_from_IDispatch(disp)->IHTMLImageElementFactory_iface; @@ -1576,7 +1591,7 @@ static HRESULT WINAPI HTMLWindow2_get_Option(IHTMLWindow2 *iface, IHTMLOptionEle TRACE("(%p)->(%p)\n", This, p); - hres = get_legacy_ctor(window, LEGACY_CTOR_ID_Option, PROTO_ID_HTMLOptionElement, + hres = get_legacy_ctor(window, LEGACY_CTOR_ID_Option_builtin, PROTO_ID_HTMLOptionElement, &HTMLOptionElementFactory_dispex, &HTMLOptionElementFactoryVtbl, &disp); if(SUCCEEDED(hres)) *p = &legacy_ctor_from_IDispatch(disp)->IHTMLOptionElementFactory_iface; @@ -2269,7 +2284,7 @@ static HRESULT WINAPI HTMLWindow5_get_XMLHttpRequest(IHTMLWindow5 *iface, VARIAN return S_OK; } - hres = get_legacy_ctor(window, LEGACY_CTOR_ID_HTMLXMLHttpRequest, PROTO_ID_HTMLXMLHttpRequest, + hres = get_legacy_ctor(window, LEGACY_CTOR_ID_HTMLXMLHttpRequest_builtin, PROTO_ID_HTMLXMLHttpRequest, &HTMLXMLHttpRequestFactory_dispex, &HTMLXMLHttpRequestFactoryVtbl, &disp); if(SUCCEEDED(hres)) { V_VT(p) = VT_DISPATCH; @@ -3798,7 +3813,7 @@ static HRESULT WINAPI WindowDispEx_Invoke(IDispatchEx *iface, DISPID dispIdMembe static global_prop_t *alloc_global_prop(HTMLInnerWindow *This, global_prop_type_t type, BSTR name) { - if(This->global_prop_cnt > MSHTML_CUSTOM_DISPID_CNT - ARRAY_SIZE(legacy_ctor_static_data)) + if(This->global_prop_cnt > MSHTML_CUSTOM_DISPID_CNT - legacy_ctor_props_num) return NULL; if(This->global_prop_cnt == This->global_prop_size) { @@ -3864,12 +3879,22 @@ HRESULT search_window_props(HTMLInnerWindow *This, BSTR bstrName, DWORD grfdex, static DISPID lookup_legacy_ctor_prop(HTMLInnerWindow *window, BSTR name) { - DWORD i, a = 0, b = ARRAY_SIZE(legacy_ctor_static_data); + DWORD i, a = 0, b = ARRAY_SIZE(special_ctor_static_data); int c; + while(a < b) { + i = (a + b) / 2; + c = wcscmp(special_ctor_static_data[i].name, name); + if(!c) + return i + (MSHTML_DISPID_CUSTOM_MAX - legacy_ctor_props_num + 1); + if(c > 0) b = i; + else a = i + 1; + } + if(dispex_compat_mode(&window->event_target.dispex) != COMPAT_MODE_IE8) return DISPID_UNKNOWN; + a = 0, b = ARRAY_SIZE(legacy_ctor_static_data); while(a < b) { i = (a + b) / 2; c = wcscmp(legacy_ctor_static_data[i].dispex.name, name); @@ -4050,10 +4075,12 @@ static HRESULT WINAPI WindowDispEx_DeleteMemberByDispID(IDispatchEx *iface, DISP TRACE("(%p)->(%lx)\n", This, id); - idx = id - (MSHTML_DISPID_CUSTOM_MAX - ARRAY_SIZE(legacy_ctor_static_data) + 1); - if(idx < ARRAY_SIZE(legacy_ctor_static_data) && - dispex_compat_mode(&This->inner_window->event_target.dispex) == COMPAT_MODE_IE8) - return MSHTML_E_INVALID_ACTION; + idx = id - (MSHTML_DISPID_CUSTOM_MAX - legacy_ctor_props_num + 1); + if(idx < legacy_ctor_props_num) { + if(idx < ARRAY_SIZE(special_ctor_static_data) || + dispex_compat_mode(&This->inner_window->event_target.dispex) == COMPAT_MODE_IE8) + return MSHTML_E_INVALID_ACTION; + } return IDispatchEx_DeleteMemberByDispID(&This->inner_window->event_target.dispex.IDispatchEx_iface, id); } @@ -4485,9 +4512,9 @@ static HRESULT HTMLWindow_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID idx = id - MSHTML_DISPID_CUSTOM_MIN; if(idx >= This->global_prop_cnt) { - idx = id - (MSHTML_DISPID_CUSTOM_MAX - ARRAY_SIZE(legacy_ctor_static_data) + 1); - if(idx >= ARRAY_SIZE(legacy_ctor_static_data) || - dispex_compat_mode(&This->event_target.dispex) != COMPAT_MODE_IE8) + idx = id - (MSHTML_DISPID_CUSTOM_MAX - legacy_ctor_props_num + 1); + if(idx >= legacy_ctor_props_num || (idx >= ARRAY_SIZE(special_ctor_static_data) && + dispex_compat_mode(&This->event_target.dispex) != COMPAT_MODE_IE8)) return DISP_E_MEMBERNOTFOUND; switch(flags) { @@ -4499,9 +4526,15 @@ static HRESULT HTMLWindow_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID case DISPATCH_CONSTRUCT: return MSHTML_E_INVALID_ACTION; case DISPATCH_PROPERTYGET: - /* For these generic constructors, LEGACY_CTOR_ID is the same as the PROTO_ID */ - hres = get_legacy_ctor(This, legacy_ctor_static_data[idx].prototype_id, legacy_ctor_static_data[idx].prototype_id, - &legacy_ctor_static_data[idx].dispex, &legacy_ctor_vtbl, &V_DISPATCH(res)); + if(idx < ARRAY_SIZE(special_ctor_static_data)) + hres = get_legacy_ctor(This, special_ctor_static_data[idx].ctor_id, special_ctor_static_data[idx].prototype_id, + special_ctor_static_data[idx].dispex, special_ctor_static_data[idx].vtbl, &V_DISPATCH(res)); + else { + /* For these generic constructors, LEGACY_CTOR_ID is the same as the PROTO_ID */ + idx -= ARRAY_SIZE(special_ctor_static_data); + hres = get_legacy_ctor(This, legacy_ctor_static_data[idx].prototype_id, legacy_ctor_static_data[idx].prototype_id, + &legacy_ctor_static_data[idx].dispex, &legacy_ctor_vtbl, &V_DISPATCH(res)); + } if(FAILED(hres)) return hres; V_VT(res) = VT_DISPATCH; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 4fb4f272b6b..bc7031ada2f 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -502,6 +502,10 @@ COMMON_PROTOTYPE_LIST LEGACY_CTOR_ID_Image, LEGACY_CTOR_ID_Option, + LEGACY_CTOR_ID_Image_builtin, + LEGACY_CTOR_ID_Option_builtin, + LEGACY_CTOR_ID_HTMLXMLHttpRequest_builtin, + LEGACY_CTOR_COUNT } legacy_ctor_id_t; @@ -1670,6 +1674,9 @@ extern const IHTMLXMLHttpRequestFactoryVtbl HTMLXMLHttpRequestFactoryVtbl DECLSP extern dispex_static_data_t HTMLImageElementFactory_dispex DECLSPEC_HIDDEN; extern dispex_static_data_t HTMLOptionElementFactory_dispex DECLSPEC_HIDDEN; extern dispex_static_data_t HTMLXMLHttpRequestFactory_dispex DECLSPEC_HIDDEN; +extern dispex_static_data_t HTMLImageCtor_dispex DECLSPEC_HIDDEN; +extern dispex_static_data_t HTMLOptionCtor_dispex DECLSPEC_HIDDEN; +extern dispex_static_data_t HTMLXMLHttpRequestCtor_dispex DECLSPEC_HIDDEN; #define X(id, name, dispex, proto_id) extern dispex_static_data_t dispex DECLSPEC_HIDDEN; LEGACY_PROTOTYPE_LIST diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 2f0130dac45..ab867a6f815 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1114,7 +1114,6 @@ sync_test("builtin_prototypes", function() { todo_wine_if(ctors[i][0] == "Image" || ctors[i][0] == "Option" || ctors[i][0] == "XMLHttpRequest"). ok(!(ctors[i][0] in window.Window.prototype), ctors[i][0] + " in Window.prototype"); r = "" + a; - todo_wine_if(ctors[i][0] == "Image" || ctors[i][0] == "Option" || ctors[i][0] == "XMLHttpRequest"). ok(r === "[object " + ctors[i][ctors[i].length < 3 ? 0 : 2] + "]", ctors[i][0] + " returned " + r); r = "" + a.prototype; ok(r === "[Interface prototype object]", ctors[i][0] + ".prototype returned " + r); diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 6b1290ca228..5e5cff26db9 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -2213,6 +2213,42 @@ static void _set_object_name(unsigned line, IHTMLElement *elem, const WCHAR *nam _test_object_name(line, elem, name); } +static void test_factory(void *window, void *factory, const WCHAR *name, const WCHAR *value) +{ + IDispatch *disp, *window_disp = window; + DISPPARAMS dp = { NULL, NULL, 0, 0 }; + BSTR bstr = SysAllocString(name); + VARIANT var, val; + DISPID dispid; + HRESULT hres; + + hres = IDispatch_GetIDsOfNames(window_disp, &IID_NULL, &bstr, 1, 0, &dispid); + SysFreeString(bstr); + ok(hres == S_OK, "GetIDsOfNames(%s) failed: %08lx\n", wine_dbgstr_w(name), hres); + + hres = IDispatch_Invoke(window_disp, dispid, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &var, NULL, NULL); + ok(hres == S_OK, "Invoke(%s) failed: %08lx\n", wine_dbgstr_w(name), hres); + ok(V_VT(&var) == VT_DISPATCH, "VT(%s) = %d\n", wine_dbgstr_w(name), V_VT(&var)); + + hres = IUnknown_QueryInterface((IUnknown*)factory, &IID_IDispatch, (void**)&disp); + ok(hres == S_OK, "Could not get IDispatch from %s factory: %08lx\n", wine_dbgstr_w(name), hres); + ok(disp != V_DISPATCH(&var), "window.%s and the builtin getter returned same dispatch\n", wine_dbgstr_w(name)); + + hres = IDispatch_Invoke(disp, DISPID_VALUE, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &val, NULL, NULL); + IDispatch_Release(disp); + ok(hres == S_OK, "Invoke(DISPID_VALUE) for %s builtin getter returned: %08lx\n", wine_dbgstr_w(name), hres); + ok(V_VT(&val) == VT_BSTR, "V_VT(value) for %s builtin getter = %d\n", wine_dbgstr_w(name), V_VT(&val)); + ok(!lstrcmpW(V_BSTR(&val), L"[object]"), "value for %s builtin getter = %s\n", wine_dbgstr_w(name), wine_dbgstr_w(V_BSTR(&val))); + VariantClear(&val); + + hres = IDispatch_Invoke(V_DISPATCH(&var), DISPID_VALUE, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &val, NULL, NULL); + VariantClear(&var); + ok(hres == S_OK, "Invoke(DISPID_VALUE) for %s: %08lx\n", wine_dbgstr_w(name), hres); + ok(V_VT(&val) == VT_BSTR, "V_VT(value) for %s = %d\n", wine_dbgstr_w(name), V_VT(&val)); + ok(!lstrcmpW(V_BSTR(&val), value), "value for %s = %s\n", wine_dbgstr_w(name), wine_dbgstr_w(V_BSTR(&val))); + VariantClear(&val); +} + #define create_option_elem(d,t,v) _create_option_elem(__LINE__,d,t,v) static IHTMLOptionElement *_create_option_elem(unsigned line, IHTMLDocument2 *doc, const WCHAR *txt, const WCHAR *val) @@ -2232,6 +2268,7 @@ static IHTMLOptionElement *_create_option_elem(unsigned line, IHTMLDocument2 *do IHTMLWindow2_Release(window); ok_(__FILE__,line) (hres == S_OK, "get_Option failed: %08lx\n", hres); + test_factory(window, factory, L"Option", L"[object HTMLOptionElement]"); test_disp((IUnknown*)factory, &IID_IHTMLOptionElementFactory, NULL, L"[object]"); V_VT(&text) = VT_BSTR; @@ -2335,6 +2372,7 @@ static IHTMLImgElement *_create_img_elem(unsigned line, IHTMLDocument2 *doc, ok_(__FILE__,line) (hres == S_OK, "get_Image failed: %08lx\n", hres); test_ifaces((IUnknown*)factory, img_factory_iids); + test_factory(window, factory, L"Image", L"[object HTMLImageElement]"); test_disp((IUnknown*)factory, &IID_IHTMLImageElementFactory, NULL, L"[object]"); if(wdth >= 0){ @@ -7229,6 +7267,8 @@ static void test_xmlhttprequest(IHTMLWindow5 *window) ok(hres == S_OK, "QueryInterface(&IID_IHTMLXMLHttpRequestFactory) failed: %08lx\n", hres); ok(factory != NULL, "factory == NULL\n"); + test_factory(window, factory, L"XMLHttpRequest", L"[object XMLHttpRequest]"); + xml = NULL; hres = IHTMLXMLHttpRequestFactory_create(factory, &xml); ok(hres == S_OK, "create failed: %08lx\n", hres); diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index be657efae9d..535e261af1a 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1552,9 +1552,34 @@ static const tid_t HTMLXMLHttpRequestFactory_iface_tids[] = { 0 }; dispex_static_data_t HTMLXMLHttpRequestFactory_dispex = { - L"Function", + L"XMLHttpRequest", &HTMLXMLHttpRequestFactory_dispex_vtbl, PROTO_ID_NULL, IHTMLXMLHttpRequestFactory_tid, HTMLXMLHttpRequestFactory_iface_tids }; + +static HRESULT HTMLXMLHttpRequestCtor_value(DispatchEx *iface, LCID lcid, WORD flags, DISPPARAMS *params, + VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + if(flags == DISPATCH_CONSTRUCT) + return HTMLXMLHttpRequestFactory_value(iface, lcid, flags, params, res, ei, caller); + + return legacy_ctor_value(iface, lcid, flags, params, res, ei, caller); +} + +static const dispex_static_data_vtbl_t HTMLXMLHttpRequestCtor_dispex_vtbl = { + HTMLXMLHttpRequestCtor_value, + legacy_ctor_get_dispid, + legacy_ctor_get_name, + legacy_ctor_invoke, + legacy_ctor_delete +}; + +dispex_static_data_t HTMLXMLHttpRequestCtor_dispex = { + L"XMLHttpRequest", + &HTMLXMLHttpRequestCtor_dispex_vtbl, + PROTO_ID_NULL, + IHTMLXMLHttpRequestFactory_tid, + HTMLXMLHttpRequestFactory_iface_tids +}; From ea358d60b97ffdf17afdcc46294317cad5ef9d01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:04 +0200 Subject: [PATCH 0894/2777] mshtml: Implement "constructor" property for legacy prototypes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/dispex.c | 70 +++++++++++++++++++++++++++++++ dlls/mshtml/htmlwindow.c | 7 +++- dlls/mshtml/mshtml_private.h | 2 + dlls/mshtml/tests/documentmode.js | 12 +++++- 4 files changed, 88 insertions(+), 3 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 77444a0ecb2..115d017d195 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -2099,6 +2099,7 @@ struct legacy_prototype *get_legacy_prototype(HTMLInnerWindow *window, prototype prot->IUnknown_iface.lpVtbl = &legacy_prototype_vtbl; prot->ref = 1; + prot->window = window; window->legacy_prototypes[prot_id] = prot; init_dispatch(&prot->dispex, &prot->IUnknown_iface, &legacy_prototype_dispex[prot_id], NULL, compat_mode); @@ -2108,6 +2109,11 @@ struct legacy_prototype *get_legacy_prototype(HTMLInnerWindow *window, prototype return prot; } +static inline struct legacy_prototype *legacy_prototype_from_DispatchEx(DispatchEx *iface) +{ + return CONTAINING_RECORD(iface, struct legacy_prototype, dispex); +} + static HRESULT legacy_prototype_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) { @@ -2134,8 +2140,72 @@ static HRESULT legacy_prototype_value(DispatchEx *dispex, LCID lcid, WORD flags, return S_OK; } +static HRESULT legacy_prototype_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid) +{ + if(dispex_compat_mode(dispex) == COMPAT_MODE_IE8) { + if((flags & fdexNameCaseInsensitive) ? !wcsicmp(name, L"constructor") : !wcscmp(name, L"constructor")) { + *dispid = MSHTML_DISPID_CUSTOM_MIN; + return S_OK; + } + } + return DISP_E_UNKNOWNNAME; +} + +static HRESULT legacy_prototype_get_name(DispatchEx *dispex, DISPID id, BSTR *name) +{ + DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN; + + if(idx > 0 || dispex_compat_mode(dispex) != COMPAT_MODE_IE8) + return DISP_E_MEMBERNOTFOUND; + return (*name = SysAllocString(L"constructor")) ? S_OK : E_OUTOFMEMORY; +} + +static HRESULT legacy_prototype_invoke(DispatchEx *dispex, IDispatch *this_obj, DISPID id, LCID lcid, WORD flags, + DISPPARAMS *params, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + static WCHAR ElementW[] = L"Element"; + struct legacy_prototype *This = legacy_prototype_from_DispatchEx(dispex); + prototype_id_t prot_id = This->dispex.info->desc - legacy_prototype_dispex; + DWORD idx = id - MSHTML_DISPID_CUSTOM_MIN; + HTMLInnerWindow *window = This->window; + DISPPARAMS dp = { 0 }; + + if(idx > 0 || dispex_compat_mode(dispex) != COMPAT_MODE_IE8) + return DISP_E_MEMBERNOTFOUND; + + if(!window) + return E_UNEXPECTED; + + switch(flags) { + case DISPATCH_METHOD|DISPATCH_PROPERTYGET: + if(!res) + return E_INVALIDARG; + /* fall through */ + case DISPATCH_METHOD: + return MSHTML_E_INVALID_PROPERTY; + case DISPATCH_PROPERTYGET: + if(prot_id < PROTO_ID_HTMLGenericElement && prot_id != PROTO_ID_HTMLUnknownElement) + break; + if(FAILED(IDispatchEx_GetDispID(&window->base.IDispatchEx_iface, ElementW, fdexNameCaseSensitive, &id))) + break; + return IDispatchEx_InvokeEx(&window->base.IDispatchEx_iface, id, lcid, DISPATCH_PROPERTYGET, &dp, res, ei, caller); + case DISPATCH_PROPERTYPUTREF|DISPATCH_PROPERTYPUT: + case DISPATCH_PROPERTYPUTREF: + case DISPATCH_PROPERTYPUT: + return S_OK; + default: + return MSHTML_E_INVALID_PROPERTY; + } + + V_VT(res) = VT_NULL; + return S_OK; +} + static const dispex_static_data_vtbl_t legacy_prototype_dispex_vtbl = { legacy_prototype_value, + legacy_prototype_get_dispid, + legacy_prototype_get_name, + legacy_prototype_invoke }; static void legacy_prototype_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 62ba7cd6f06..55b741b2bc8 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -529,9 +529,12 @@ static void release_inner_window(HTMLInnerWindow *This) } } - for(i = 0; i < ARRAY_SIZE(This->legacy_prototypes); i++) - if(This->legacy_prototypes[i]) + for(i = 0; i < ARRAY_SIZE(This->legacy_prototypes); i++) { + if(This->legacy_prototypes[i]) { + This->legacy_prototypes[i]->window = NULL; IUnknown_Release(&This->legacy_prototypes[i]->IUnknown_iface); + } + } if(This->screen) IHTMLScreen_Release(This->screen); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index bc7031ada2f..6539b78d7b7 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -665,6 +665,8 @@ struct legacy_prototype { IUnknown IUnknown_iface; DispatchEx dispex; LONG ref; + + HTMLInnerWindow *window; }; typedef enum { diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index ab867a6f815..632e13554af 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1128,8 +1128,18 @@ sync_test("builtin_prototypes", function() { if(v < 8 || ctors[i][0] === "HTMLModelessDialog") { ok(!("constructor" in a.prototype), "constructor in " + ctors[i][0] + ".prototype"); }else { - todo_wine. ok("constructor" in a.prototype, "constructor not in " + ctors[i][0] + ".prototype"); + b = a.prototype.constructor; + r = ctors[i][(ctors[i].length > 2) ? 2 : 0]; + var ctor = (r.length > 7 && r.slice(-7) === "Element") ? window.Element : null; + ok(b === ctor, ctors[i][0] + ".prototype.constructor = " + b); + a.prototype.constructor = "foobar"; + b = a.prototype.constructor; + ok(b === ctor, ctors[i][0] + ".prototype.constructor after set = " + b); + r = (delete a.prototype.constructor); + ok(r === true, "delete " + ctors[i][0] + ".prototype.constructor returned " + r); + b = a.prototype.constructor; + ok(b === ctor, ctors[i][0] + ".prototype.constructor after delete = " + b); } } } From 0fe830340979ca8c099216c29adc9992f8bdc848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:04 +0200 Subject: [PATCH 0895/2777] mshtml: Exclude the constructors from the Window prototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/dispex.c | 22 +++++++++++++++++++--- dlls/mshtml/tests/documentmode.js | 2 -- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 115d017d195..76654c8035c 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -2210,28 +2210,44 @@ static const dispex_static_data_vtbl_t legacy_prototype_dispex_vtbl = { static void legacy_prototype_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) { + static const DISPID empty_exclude_list[] = { DISPID_UNKNOWN }; + static const DISPID window_exclude_list[] = { + DISPID_IHTMLWINDOW2_IMAGE, + DISPID_IHTMLWINDOW2_OPTION, + DISPID_IHTMLWINDOW5_XMLHTTPREQUEST, + DISPID_UNKNOWN + }; prototype_id_t prot_id = info->desc - legacy_prototype_dispex; dispex_data_t *data = ensure_dispex_info(prototype_static_data[prot_id].desc, compat_mode); + const DISPID *exclude = empty_exclude_list; func_info_t *func; - unsigned i; + unsigned i, j; if(!data) return; + if(prototype_static_data[prot_id].desc == &HTMLWindow_dispex) + exclude = window_exclude_list; + /* Copy the info from the object instance data */ func = realloc(info->funcs, data->func_size * sizeof(*func)); if(!func) return; info->funcs = func; - info->func_cnt = data->func_cnt; info->func_disp_cnt = data->func_disp_cnt; info->func_size = data->func_size; for(i = 0; i < data->func_cnt; i++) { + for(j = 0; exclude[j] != DISPID_UNKNOWN; j++) + if(exclude[j] == data->funcs[i].id) + break; + if(exclude[j] != DISPID_UNKNOWN) + continue; copy_func_info(func, &data->funcs[i]); func++; } - memset(func, 0, (info->func_size - i) * sizeof(*func)); + info->func_cnt = func - info->funcs; + memset(func, 0, (info->func_size - info->func_cnt) * sizeof(*func)); } HRESULT legacy_ctor_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *params, diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 632e13554af..d7e622b8d94 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -540,7 +540,6 @@ sync_test("builtin_prototypes", function() { ok(Object.prototype.hasOwnProperty.call(obj, "prototype"), "prototype not a property of " + name + " constructor."); ok(!("length" in obj), "length in " + name + " constructor."); if(window.Window) - todo_wine. ok(!Object.prototype.hasOwnProperty.call(window.Window.prototype, name), name + " is a property of window's prototype."); }else { if(special_ctors[i][1]) for(var j = 0; j < special_ctors[i][1].length; j++) @@ -1111,7 +1110,6 @@ sync_test("builtin_prototypes", function() { ok(a === b, ctors[i][0] + ": " + a + " != " + b); ok(ctors[i][0] in window, ctors[i][0] + " in window"); if(v >= 8) - todo_wine_if(ctors[i][0] == "Image" || ctors[i][0] == "Option" || ctors[i][0] == "XMLHttpRequest"). ok(!(ctors[i][0] in window.Window.prototype), ctors[i][0] + " in Window.prototype"); r = "" + a; ok(r === "[object " + ctors[i][ctors[i].length < 3 ? 0 : 2] + "]", ctors[i][0] + " returned " + r); From 0a4543f621ad2688e52349c85e05e0a9cee9e797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:04 +0200 Subject: [PATCH 0896/2777] mshtml: Copy the builtin data to the proxy prototype on init. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit But exclude the ones found further up the prototype chain. Signed-off-by: Gabriel Ivăncescu --- This is a no-op for now but simplifies next patches. --- dlls/mshtml/dispex.c | 77 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 13 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 76654c8035c..39c092b2b1a 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -145,6 +145,7 @@ PRIVATE_TID_LIST }; const tid_t no_iface_tids[1] = { 0 }; +static void proxy_prototype_init_dispex_info(dispex_data_t*,compat_mode_t); static struct prototype_static_data { dispex_static_data_t dispex; @@ -157,7 +158,8 @@ static struct prototype_static_data { NULL, \ PROTO_ID_ ## proto_id, \ NULL_tid, \ - no_iface_tids \ + no_iface_tids, \ + proxy_prototype_init_dispex_info \ }, \ &dispex \ }, @@ -1408,13 +1410,8 @@ static HRESULT get_builtin_func(dispex_data_t *data, DISPID id, func_info_t **re static HRESULT get_builtin_func_prot(DispatchEx *This, DISPID id, func_info_t **ret) { - if(This->proxy) { - struct proxy_prototype *prot = to_proxy_prototype(This); - if(prot) - return get_builtin_func(proxy_prototype_object_info(prot), id, ret); - if(id != DISPID_VALUE && This->info->desc->prototype_id >= 0) - return DISP_E_MEMBERNOTFOUND; - } + if(This->proxy && !to_proxy_prototype(This) && id != DISPID_VALUE && This->info->desc->prototype_id >= 0) + return DISP_E_MEMBERNOTFOUND; return get_builtin_func(This->info, id, ret); } @@ -2406,9 +2403,65 @@ static inline struct proxy_prototype *to_proxy_prototype(DispatchEx *dispex) return (dispex->outer->lpVtbl == &proxy_prototype_vtbl) ? proxy_prototype_from_IUnknown(dispex->outer) : NULL; } +static void proxy_prototype_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) +{ + dispex_static_data_t *desc = CONTAINING_RECORD(info->desc, struct prototype_static_data, dispex)->desc; + dispex_data_t *data = ensure_dispex_info(desc, compat_mode); + prototype_id_t prot_id; + func_info_t *func; + unsigned i; + + if(!data) + return; + + /* Copy the info from the object instance data, but + exclude builtins found up the prototype chain. */ + func = realloc(info->funcs, data->func_size * sizeof(*func)); + if(!func) + return; + info->funcs = func; + info->func_disp_cnt = 0; + + for(i = 0; i < data->func_cnt; i++) { + BOOL found = FALSE; + + for(prot_id = info->desc->prototype_id; prot_id >= 0; prot_id = prototype_static_data[prot_id].dispex.prototype_id) { + dispex_data_t *chain_data = ensure_dispex_info(prototype_static_data[prot_id].desc, compat_mode); + DWORD a = 0, b = chain_data->func_cnt; + + while(a < b) { + DWORD idx = (a + b) / 2; + int c = wcsicmp(chain_data->name_table[idx]->name, data->funcs[i].name); + if(!c) { + found = TRUE; + break; + } + if(c > 0) b = idx; + else a = idx + 1; + } + if(found) + break; + } + if(found) + continue; + + copy_func_info(func, &data->funcs[i]); + if(func->func_disp_idx >= 0) + info->func_disp_cnt++; + func++; + } + + info->func_cnt = func - info->funcs; + info->func_size = max(info->func_cnt, 16); + func = realloc(info->funcs, info->func_size * sizeof(*func)); + if(func) + info->funcs = func; + memset(info->funcs + info->func_cnt, 0, (info->func_size - info->func_cnt) * sizeof(*func)); +} + static HRESULT get_prototype_builtin_id(struct proxy_prototype *prot, BSTR name, DWORD flags, DISPID *id) { - dispex_data_t *data = proxy_prototype_object_info(prot); + dispex_data_t *data = prot->dispex.info; func_info_t **funcs = data->name_table; DWORD i, a = 0, b = data->func_cnt; int c; @@ -2426,6 +2479,7 @@ static HRESULT get_prototype_builtin_id(struct proxy_prototype *prot, BSTR name, else a = i + 1; } + data = proxy_prototype_object_info(prot); if(data->desc->vtbl && data->desc->vtbl->get_static_dispid) return data->desc->vtbl->get_static_dispid(dispex_compat_mode(&prot->dispex), name, flags, id); return DISP_E_UNKNOWNNAME; @@ -2437,9 +2491,6 @@ static IDispatch *get_default_prototype(prototype_id_t prot_id, compat_mode_t co struct proxy_prototype *prot; IDispatch **entry; - if(!ensure_dispex_info(prototype_static_data[prot_id].desc, compat_mode)) - return NULL; - if(!*prots_ref) { if(!(*prots_ref = calloc(1, FIELD_OFFSET(struct proxy_prototypes, disp[num_prots])))) return NULL; @@ -3260,7 +3311,7 @@ static HRESULT WINAPI WineDispatchProxyPrivate_PropEnum(IWineDispatchProxyPrivat return E_OUTOFMEMORY; if(prot) { - dispex_data_t *info = proxy_prototype_object_info(prot); + dispex_data_t *info = prot->dispex.info; func = info->funcs; func_end = func + info->func_cnt; }else if(This->info->desc->prototype_id < 0) { From f0c0eda2c57fc2764c4f68adcfc7ae5b38aa8f45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:05 +0200 Subject: [PATCH 0897/2777] mshtml/tests: Add initial tests for IE9+ prototype chains. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/tests/documentmode.js | 42 +++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index d7e622b8d94..55f064cf3d8 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1141,6 +1141,48 @@ sync_test("builtin_prototypes", function() { } } } + }else { + var protos = [ + [ "ClientRect", "Object" ], + [ "ClientRectList", "Object" ], + [ "Console", "Object" ], + [ "CSSStyleDeclaration", "Object" ], + [ "DOMImplementation", "Object" ], + [ "DOMTokenList", "Object" ], + [ "Event", "Object" ], + [ "History", "Object" ], + [ "HTMLCollection", "Object" ], + [ "MediaQueryList", "Object" ], + [ "MimeTypeArray", "Object" ], + [ "MSCSSRuleList", "Object" ], + [ "MSEventObj", "Object" ], + [ "MSMimeTypesCollection", "Object" ], + [ "MSNamespaceInfoCollection", "Object" ], + [ "MSPluginsCollection", "Object" ], + [ "MSSelection", "Object" ], + [ "NamedNodeMap", "Object" ], + [ "Navigator", "Object" ], + [ "Node", "Object" ], + [ "NodeList", "Object" ], + [ "Performance", "Object" ], + [ "PerformanceNavigation", "Object" ], + [ "PerformanceTiming", "Object" ], + [ "PluginArray", "Object" ], + [ "Screen", "Object" ], + [ "Storage", "Object" ], + [ "StyleSheetList", "Object" ], + [ "TextRange", "Object" ], + [ "Window", "Object" ], + [ "XMLHttpRequest", "Object" ] + ]; + + for(var i = 0; i < protos.length; i++) { + if(!(protos[i][0] in window)) + continue; + var a, b; + eval("a = Object.getPrototypeOf(" + protos[i][0] + ".prototype); b = " + protos[i][1] + ".prototype;"); + ok(a === b, "getPrototypeOf(" + protos[i][0] + ".prototype) = " + a); + } } }); From f7f9c342b098a6ac2a1a6d5712606368cd157385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:05 +0200 Subject: [PATCH 0898/2777] mshtml: Expose ownerDocument from HTMLDOMNode in IE9+ modes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- This is required for and tested in next patch. Adding a separate test for it seems a bit redundant. --- dlls/mshtml/htmlnode.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/htmlnode.c b/dlls/mshtml/htmlnode.c index 0d5f2ef576f..91b66b154e3 100644 --- a/dlls/mshtml/htmlnode.c +++ b/dlls/mshtml/htmlnode.c @@ -1457,8 +1457,10 @@ static HRESULT HTMLDOMNode_clone(HTMLDOMNode *This, nsIDOMNode *nsnode, HTMLDOMN void HTMLDOMNode_init_dispex_info(dispex_data_t *info, compat_mode_t mode) { - if(mode >= COMPAT_MODE_IE9) + if(mode >= COMPAT_MODE_IE9) { + dispex_info_add_interface(info, IHTMLDOMNode2_tid, NULL); dispex_info_add_interface(info, IHTMLDOMNode3_tid, NULL); + } EventTarget_init_dispex_info(info, mode); } From 719429d0680ec4daa55b7c7f435ba302acb731fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:05 +0200 Subject: [PATCH 0899/2777] mshtml: Introduce CharacterDataPrototype and set it as TextPrototype's prototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The interface is abstract, and is only used in prototype chains (and constructor), so we needn't implement any of it. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmltextnode.c | 22 ++++++++++++++++++++++ dlls/mshtml/mshtml_private.h | 3 ++- dlls/mshtml/tests/documentmode.js | 24 ++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/htmltextnode.c b/dlls/mshtml/htmltextnode.c index 59826c35e70..1c8bb539675 100644 --- a/dlls/mshtml/htmltextnode.c +++ b/dlls/mshtml/htmltextnode.c @@ -25,6 +25,7 @@ #include "winbase.h" #include "winuser.h" #include "ole2.h" +#include "mshtmdid.h" #include "mshtml_private.h" @@ -40,6 +41,27 @@ struct HTMLDOMTextNode { nsIDOMText *nstext; }; +/* dummy dispex used only for CharacterDataPrototype in prototype chain */ +static void DOMCharacterData_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t textnode_hooks[] = { + {DISPID_IHTMLDOMTEXTNODE_TOSTRING}, + {DISPID_IHTMLDOMTEXTNODE_SPLITTEXT}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLDOMTextNode_tid, textnode_hooks); + dispex_info_add_interface(info, IHTMLDOMTextNode2_tid, NULL); +} + +dispex_static_data_t DOMCharacterData_dispex = { + L"CharacterData", + NULL, + PROTO_ID_DOMCharacterData, + NULL_tid, + no_iface_tids, + DOMCharacterData_init_dispex_info +}; + static inline HTMLDOMTextNode *impl_from_IHTMLDOMTextNode(IHTMLDOMTextNode *iface) { return CONTAINING_RECORD(iface, HTMLDOMTextNode, IHTMLDOMTextNode_iface); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 6539b78d7b7..e81b335f87a 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -407,7 +407,7 @@ PRIVATE_TID_LIST X(HTMLDOMAttribute, "Attr", HTMLDOMAttribute_dispex, Object) \ X(HTMLDOMChildrenCollection, "NodeList", HTMLDOMChildrenCollection_dispex, Object) \ X(HTMLDOMImplementation, "DOMImplementation", HTMLDOMImplementation_dispex, Object) \ - X(HTMLDOMTextNode, "Text", HTMLDOMTextNode_dispex, Object) \ + X(HTMLDOMTextNode, "Text", HTMLDOMTextNode_dispex, DOMCharacterData) \ X(HTMLDocument, "HTMLDocument", HTMLDocumentNode_dispex, Object) \ X(HTMLWindow, "Window", HTMLWindow_dispex, Object) \ X(HTMLAttributeCollection, "NamedNodeMap", HTMLAttributeCollection_dispex, Object) \ @@ -468,6 +468,7 @@ PRIVATE_TID_LIST X(DOMProgressEvent, "ProgressEvent", DOMProgressEvent_dispex, Object) \ X(DOMStorageEvent, "StorageEvent", DOMStorageEvent_dispex, Object) \ X(DOMUIEvent, "UIEvent", DOMUIEvent_dispex, Object) \ + X(DOMCharacterData, "CharacterData", DOMCharacterData_dispex, HTMLDOMNode) \ X(DocumentType, "DocumentType", DocumentType_dispex, Object) \ X(MediaQueryList, "MediaQueryList", media_query_list_dispex, Object) \ X(DOMTokenList, "DOMTokenList", DOMTokenList_dispex, Object) \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 55f064cf3d8..ca33079e1a9 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1143,6 +1143,7 @@ sync_test("builtin_prototypes", function() { } }else { var protos = [ + [ "CharacterData", "Node" ], [ "ClientRect", "Object" ], [ "ClientRectList", "Object" ], [ "Console", "Object" ], @@ -1171,6 +1172,7 @@ sync_test("builtin_prototypes", function() { [ "Screen", "Object" ], [ "Storage", "Object" ], [ "StyleSheetList", "Object" ], + [ "Text", "CharacterData" ], [ "TextRange", "Object" ], [ "Window", "Object" ], [ "XMLHttpRequest", "Object" ] @@ -1183,6 +1185,28 @@ sync_test("builtin_prototypes", function() { eval("a = Object.getPrototypeOf(" + protos[i][0] + ".prototype); b = " + protos[i][1] + ".prototype;"); ok(a === b, "getPrototypeOf(" + protos[i][0] + ".prototype) = " + a); } + + var Node_props = [ "addEventListener","appendChild","attributes","childNodes","cloneNode","compareDocumentPosition","dispatchEvent","firstChild", + "hasChildNodes","insertBefore","isDefaultNamespace","isEqualNode","isSameNode","isSupported","lastChild","localName", + "lookupNamespaceURI","lookupPrefix","namespaceURI","nextSibling","nodeName","nodeType","nodeValue","ownerDocument", + "parentNode","prefix","previousSibling","removeChild","removeEventListener","replaceChild","textContent" ]; + + protos = [ + [ "CharacterData", ["data","length"], Node_props ], + [ "Text", ["splitText"], ["data","length","appendData","deleteData","insertData","replaceData","substringData"] ] + ]; + + for(var i = 0; i < protos.length; i++) { + if(!(protos[i][0] in window)) + continue; + eval("r = " + protos[i][0] + ".prototype"); + for(var j = 0; j < protos[i][1].length; j++) + ok(Object.prototype.hasOwnProperty.call(r, protos[i][1][j]), protos[i][1][j] + " not a property of " + protos[i][0] + ".prototype"); + for(var j = 0; j < protos[i][2].length; j++) { + ok(!Object.prototype.hasOwnProperty.call(r, protos[i][2][j]), protos[i][2][j] + " is a property of " + protos[i][0] + ".prototype"); + ok(protos[i][2][j] in r, protos[i][2][j] + " not in " + protos[i][0] + ".prototype"); + } + } } }); From e166cabab674f3d3ef34de46cc010076fef21932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:05 +0200 Subject: [PATCH 0900/2777] mshtml: Set prototype of CommentPrototype to CharacterDataPrototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IHTMLDOMTextNode and IHTMLDOMTextNode2 are introduced to HTMLCommentElement as stubs, but not exposed, since they can be called from the CharacterDataPrototype. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlcomment.c | 222 ++++++++++++++++++++++++++++++ dlls/mshtml/mshtml_private.h | 2 +- dlls/mshtml/tests/documentmode.js | 4 +- 3 files changed, 226 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/htmlcomment.c b/dlls/mshtml/htmlcomment.c index 9c0b02163af..db1fb1dafc8 100644 --- a/dlls/mshtml/htmlcomment.c +++ b/dlls/mshtml/htmlcomment.c @@ -35,6 +35,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); struct HTMLCommentElement { HTMLElement element; IHTMLCommentElement IHTMLCommentElement_iface; + IHTMLDOMTextNode IHTMLDOMTextNode_iface; + IHTMLDOMTextNode2 IHTMLDOMTextNode2_iface; }; static inline HTMLCommentElement *impl_from_IHTMLCommentElement(IHTMLCommentElement *iface) @@ -140,6 +142,220 @@ static const IHTMLCommentElementVtbl HTMLCommentElementVtbl = { HTMLCommentElement_get_atomic }; +static inline HTMLCommentElement *impl_from_IHTMLDOMTextNode(IHTMLDOMTextNode *iface) +{ + return CONTAINING_RECORD(iface, HTMLCommentElement, IHTMLDOMTextNode_iface); +} + +static HRESULT WINAPI HTMLCommentElement_TextNode_QueryInterface(IHTMLDOMTextNode *iface, + REFIID riid, void **ppv) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode(iface); + + return IHTMLDOMNode_QueryInterface(&This->element.node.IHTMLDOMNode_iface, riid, ppv); +} + +static ULONG WINAPI HTMLCommentElement_TextNode_AddRef(IHTMLDOMTextNode *iface) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode(iface); + + return IHTMLDOMNode_AddRef(&This->element.node.IHTMLDOMNode_iface); +} + +static ULONG WINAPI HTMLCommentElement_TextNode_Release(IHTMLDOMTextNode *iface) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode(iface); + + return IHTMLDOMNode_Release(&This->element.node.IHTMLDOMNode_iface); +} + +static HRESULT WINAPI HTMLCommentElement_TextNode_GetTypeInfoCount(IHTMLDOMTextNode *iface, UINT *pctinfo) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode(iface); + return IDispatchEx_GetTypeInfoCount(&This->element.node.event_target.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLCommentElement_TextNode_GetTypeInfo(IHTMLDOMTextNode *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode(iface); + return IDispatchEx_GetTypeInfo(&This->element.node.event_target.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLCommentElement_TextNode_GetIDsOfNames(IHTMLDOMTextNode *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode(iface); + return IDispatchEx_GetIDsOfNames(&This->element.node.event_target.dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI HTMLCommentElement_TextNode_Invoke(IHTMLDOMTextNode *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode(iface); + return IDispatchEx_Invoke(&This->element.node.event_target.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, + wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLCommentElement_TextNode_put_data(IHTMLDOMTextNode *iface, BSTR v) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode(iface); + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCommentElement_TextNode_get_data(IHTMLDOMTextNode *iface, BSTR *p) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCommentElement_TextNode_toString(IHTMLDOMTextNode *iface, BSTR *String) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode(iface); + WARN("(%p)->(%p)\n", This, String); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCommentElement_TextNode_get_length(IHTMLDOMTextNode *iface, LONG *p) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCommentElement_TextNode_splitText(IHTMLDOMTextNode *iface, LONG offset, IHTMLDOMNode **pRetNode) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode(iface); + WARN("(%p)->(%ld %p)\n", This, offset, pRetNode); + return E_UNEXPECTED; +} + +static const IHTMLDOMTextNodeVtbl HTMLCommentElement_TextNodeVtbl = { + HTMLCommentElement_TextNode_QueryInterface, + HTMLCommentElement_TextNode_AddRef, + HTMLCommentElement_TextNode_Release, + HTMLCommentElement_TextNode_GetTypeInfoCount, + HTMLCommentElement_TextNode_GetTypeInfo, + HTMLCommentElement_TextNode_GetIDsOfNames, + HTMLCommentElement_TextNode_Invoke, + HTMLCommentElement_TextNode_put_data, + HTMLCommentElement_TextNode_get_data, + HTMLCommentElement_TextNode_toString, + HTMLCommentElement_TextNode_get_length, + HTMLCommentElement_TextNode_splitText +}; + +static inline HTMLCommentElement *impl_from_IHTMLDOMTextNode2(IHTMLDOMTextNode2 *iface) +{ + return CONTAINING_RECORD(iface, HTMLCommentElement, IHTMLDOMTextNode2_iface); +} + +static HRESULT WINAPI HTMLCommentElement_TextNode2_QueryInterface(IHTMLDOMTextNode2 *iface, REFIID riid, void **ppv) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode2(iface); + + return IHTMLDOMNode_QueryInterface(&This->element.node.IHTMLDOMNode_iface, riid, ppv); +} + +static ULONG WINAPI HTMLCommentElement_TextNode2_AddRef(IHTMLDOMTextNode2 *iface) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode2(iface); + + return IHTMLDOMNode_AddRef(&This->element.node.IHTMLDOMNode_iface); +} + +static ULONG WINAPI HTMLCommentElement_TextNode2_Release(IHTMLDOMTextNode2 *iface) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode2(iface); + + return IHTMLDOMNode_Release(&This->element.node.IHTMLDOMNode_iface); +} + +static HRESULT WINAPI HTMLCommentElement_TextNode2_GetTypeInfoCount(IHTMLDOMTextNode2 *iface, UINT *pctinfo) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode2(iface); + return IDispatchEx_GetTypeInfoCount(&This->element.node.event_target.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLCommentElement_TextNode2_GetTypeInfo(IHTMLDOMTextNode2 *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode2(iface); + return IDispatchEx_GetTypeInfo(&This->element.node.event_target.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLCommentElement_TextNode2_GetIDsOfNames(IHTMLDOMTextNode2 *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode2(iface); + return IDispatchEx_GetIDsOfNames(&This->element.node.event_target.dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI HTMLCommentElement_TextNode2_Invoke(IHTMLDOMTextNode2 *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode2(iface); + return IDispatchEx_Invoke(&This->element.node.event_target.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, + wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLCommentElement_TextNode2_substringData(IHTMLDOMTextNode2 *iface, LONG offset, LONG count, BSTR *string) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode2(iface); + FIXME("(%p)->(%ld %ld %p)\n", This, offset, count, string); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCommentElement_TextNode2_appendData(IHTMLDOMTextNode2 *iface, BSTR string) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode2(iface); + FIXME("(%p)->(%s)\n", This, debugstr_w(string)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCommentElement_TextNode2_insertData(IHTMLDOMTextNode2 *iface, LONG offset, BSTR string) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode2(iface); + FIXME("(%p)->(%ld %s)\n", This, offset, debugstr_w(string)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCommentElement_TextNode2_deleteData(IHTMLDOMTextNode2 *iface, LONG offset, LONG count) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode2(iface); + FIXME("(%p)->(%ld %ld)\n", This, offset, count); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCommentElement_TextNode2_replaceData(IHTMLDOMTextNode2 *iface, LONG offset, LONG count, BSTR string) +{ + HTMLCommentElement *This = impl_from_IHTMLDOMTextNode2(iface); + FIXME("(%p)->(%ld %ld %s)\n", This, offset, count, debugstr_w(string)); + return E_NOTIMPL; +} + +static const IHTMLDOMTextNode2Vtbl HTMLCommentElement_TextNode2Vtbl = { + HTMLCommentElement_TextNode2_QueryInterface, + HTMLCommentElement_TextNode2_AddRef, + HTMLCommentElement_TextNode2_Release, + HTMLCommentElement_TextNode2_GetTypeInfoCount, + HTMLCommentElement_TextNode2_GetTypeInfo, + HTMLCommentElement_TextNode2_GetIDsOfNames, + HTMLCommentElement_TextNode2_Invoke, + HTMLCommentElement_TextNode2_substringData, + HTMLCommentElement_TextNode2_appendData, + HTMLCommentElement_TextNode2_insertData, + HTMLCommentElement_TextNode2_deleteData, + HTMLCommentElement_TextNode2_replaceData +}; + static inline HTMLCommentElement *impl_from_HTMLDOMNode(HTMLDOMNode *iface) { return CONTAINING_RECORD(iface, HTMLCommentElement, element.node); @@ -154,6 +370,10 @@ static HRESULT HTMLCommentElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv if(IsEqualGUID(&IID_IHTMLCommentElement, riid)) { TRACE("(%p)->(IID_IHTMLCommentElement %p)\n", This, ppv); *ppv = &This->IHTMLCommentElement_iface; + }else if(IsEqualGUID(&IID_IHTMLDOMTextNode, riid)) { + *ppv = &This->IHTMLDOMTextNode_iface; + }else if(IsEqualGUID(&IID_IHTMLDOMTextNode2, riid)) { + *ppv = &This->IHTMLDOMTextNode2_iface; }else { return HTMLElement_QI(&This->element.node, riid, ppv); } @@ -218,6 +438,8 @@ HRESULT HTMLCommentElement_Create(HTMLDocumentNode *doc, nsIDOMNode *nsnode, HTM ret->element.node.vtbl = &HTMLCommentElementImplVtbl; ret->IHTMLCommentElement_iface.lpVtbl = &HTMLCommentElementVtbl; + ret->IHTMLDOMTextNode_iface.lpVtbl = &HTMLCommentElement_TextNodeVtbl; + ret->IHTMLDOMTextNode2_iface.lpVtbl = &HTMLCommentElement_TextNode2Vtbl; HTMLElement_Init(&ret->element, doc, NULL, &HTMLCommentElement_dispex); HTMLDOMNode_Init(doc, &ret->element.node, nsnode, &HTMLCommentElement_dispex); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index e81b335f87a..f060653fc83 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -434,7 +434,7 @@ PRIVATE_TID_LIST X(HTMLAreaElement, "HTMLAreaElement", HTMLAreaElement_dispex, Object) \ X(HTMLBodyElement, "HTMLBodyElement", HTMLBodyElement_dispex, Object) \ X(HTMLButtonElement, "HTMLButtonElement", HTMLButtonElement_dispex, Object) \ - X(HTMLCommentElement, "Comment", HTMLCommentElement_dispex, Object) \ + X(HTMLCommentElement, "Comment", HTMLCommentElement_dispex, DOMCharacterData) \ X(HTMLEmbedElement, "HTMLEmbedElement", HTMLEmbedElement_dispex, Object) \ X(HTMLFormElement, "HTMLFormElement", HTMLFormElement_dispex, Object) \ X(HTMLFrameElement, "HTMLFrameElement", HTMLFrameElement_dispex, Object) \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index ca33079e1a9..eb0d71e6fa9 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1146,6 +1146,7 @@ sync_test("builtin_prototypes", function() { [ "CharacterData", "Node" ], [ "ClientRect", "Object" ], [ "ClientRectList", "Object" ], + [ "Comment", "CharacterData" ], [ "Console", "Object" ], [ "CSSStyleDeclaration", "Object" ], [ "DOMImplementation", "Object" ], @@ -1192,7 +1193,8 @@ sync_test("builtin_prototypes", function() { "parentNode","prefix","previousSibling","removeChild","removeEventListener","replaceChild","textContent" ]; protos = [ - [ "CharacterData", ["data","length"], Node_props ], + [ "CharacterData", ["data","length","appendData"], Node_props ], + [ "Comment", ["text"], ["insertData","replaceData","substringData"] ], [ "Text", ["splitText"], ["data","length","appendData","deleteData","insertData","replaceData","substringData"] ] ]; From d2e947046b08ec3c7e06559f9af32904c76adf36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:05 +0200 Subject: [PATCH 0901/2777] mshtml: Set prototype of DocumentTypePrototype to NodePrototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/mshtml_private.h | 2 +- dlls/mshtml/tests/documentmode.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index f060653fc83..5d13b8a5561 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -469,7 +469,7 @@ PRIVATE_TID_LIST X(DOMStorageEvent, "StorageEvent", DOMStorageEvent_dispex, Object) \ X(DOMUIEvent, "UIEvent", DOMUIEvent_dispex, Object) \ X(DOMCharacterData, "CharacterData", DOMCharacterData_dispex, HTMLDOMNode) \ - X(DocumentType, "DocumentType", DocumentType_dispex, Object) \ + X(DocumentType, "DocumentType", DocumentType_dispex, HTMLDOMNode) \ X(MediaQueryList, "MediaQueryList", media_query_list_dispex, Object) \ X(DOMTokenList, "DOMTokenList", DOMTokenList_dispex, Object) \ X(HTMLDOMNode, "Node", HTMLDOMNode_dispex, Object) \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index eb0d71e6fa9..5ec646f72e7 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1149,6 +1149,7 @@ sync_test("builtin_prototypes", function() { [ "Comment", "CharacterData" ], [ "Console", "Object" ], [ "CSSStyleDeclaration", "Object" ], + [ "DocumentType", "Node" ], [ "DOMImplementation", "Object" ], [ "DOMTokenList", "Object" ], [ "Event", "Object" ], @@ -1195,6 +1196,7 @@ sync_test("builtin_prototypes", function() { protos = [ [ "CharacterData", ["data","length","appendData"], Node_props ], [ "Comment", ["text"], ["insertData","replaceData","substringData"] ], + [ "DocumentType", ["entities","internalSubset","name","notations","publicId","systemId"], Node_props ], [ "Text", ["splitText"], ["data","length","appendData","deleteData","insertData","replaceData","substringData"] ] ]; From f8616619104c8a9daed9904b93fb33b5c35cbfb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:05 +0200 Subject: [PATCH 0902/2777] mshtml: Set prototype of CustomEventPrototype and UIEventPrototype to EventPrototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/mshtml_private.h | 4 ++-- dlls/mshtml/tests/documentmode.js | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 5d13b8a5561..cb3e63ea79a 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -460,14 +460,14 @@ PRIVATE_TID_LIST #define PROXY_PROTOTYPE_LIST \ X(Console, "Console", console_dispex, Object) \ X(DOMEvent, "Event", DOMEvent_dispex, Object) \ - X(DOMCustomEvent, "CustomEvent", DOMCustomEvent_dispex, Object) \ + X(DOMCustomEvent, "CustomEvent", DOMCustomEvent_dispex, DOMEvent) \ X(DOMKeyboardEvent, "KeyboardEvent", DOMKeyboardEvent_dispex, Object) \ X(DOMMessageEvent, "MessageEvent", DOMMessageEvent_dispex, Object) \ X(DOMMouseEvent, "MouseEvent", DOMMouseEvent_dispex, Object) \ X(DOMPageTransitionEvent, "PageTransitionEvent", DOMPageTransitionEvent_dispex, Object) \ X(DOMProgressEvent, "ProgressEvent", DOMProgressEvent_dispex, Object) \ X(DOMStorageEvent, "StorageEvent", DOMStorageEvent_dispex, Object) \ - X(DOMUIEvent, "UIEvent", DOMUIEvent_dispex, Object) \ + X(DOMUIEvent, "UIEvent", DOMUIEvent_dispex, DOMEvent) \ X(DOMCharacterData, "CharacterData", DOMCharacterData_dispex, HTMLDOMNode) \ X(DocumentType, "DocumentType", DocumentType_dispex, HTMLDOMNode) \ X(MediaQueryList, "MediaQueryList", media_query_list_dispex, Object) \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 5ec646f72e7..ffc97927083 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1149,6 +1149,7 @@ sync_test("builtin_prototypes", function() { [ "Comment", "CharacterData" ], [ "Console", "Object" ], [ "CSSStyleDeclaration", "Object" ], + [ "CustomEvent", "Event" ], [ "DocumentType", "Node" ], [ "DOMImplementation", "Object" ], [ "DOMTokenList", "Object" ], @@ -1176,6 +1177,7 @@ sync_test("builtin_prototypes", function() { [ "StyleSheetList", "Object" ], [ "Text", "CharacterData" ], [ "TextRange", "Object" ], + [ "UIEvent", "Event" ], [ "Window", "Object" ], [ "XMLHttpRequest", "Object" ] ]; @@ -1188,6 +1190,8 @@ sync_test("builtin_prototypes", function() { ok(a === b, "getPrototypeOf(" + protos[i][0] + ".prototype) = " + a); } + var Event_props = [ "bubbles","cancelable","cancelBubble","currentTarget","defaultPrevented","eventPhase","initEvent","isTrusted", + "preventDefault","srcElement","stopImmediatePropagation","stopPropagation","target","timeStamp","type" ]; var Node_props = [ "addEventListener","appendChild","attributes","childNodes","cloneNode","compareDocumentPosition","dispatchEvent","firstChild", "hasChildNodes","insertBefore","isDefaultNamespace","isEqualNode","isSameNode","isSupported","lastChild","localName", "lookupNamespaceURI","lookupPrefix","namespaceURI","nextSibling","nodeName","nodeType","nodeValue","ownerDocument", @@ -1196,8 +1200,10 @@ sync_test("builtin_prototypes", function() { protos = [ [ "CharacterData", ["data","length","appendData"], Node_props ], [ "Comment", ["text"], ["insertData","replaceData","substringData"] ], + [ "CustomEvent", ["detail","initCustomEvent"], Event_props ], [ "DocumentType", ["entities","internalSubset","name","notations","publicId","systemId"], Node_props ], - [ "Text", ["splitText"], ["data","length","appendData","deleteData","insertData","replaceData","substringData"] ] + [ "Text", ["splitText"], ["data","length","appendData","deleteData","insertData","replaceData","substringData"] ], + [ "UIEvent", ["detail","initUIEvent","view"], Event_props ] ]; for(var i = 0; i < protos.length; i++) { From c082f32d629a6453d84a0e17db74a459dad0eec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:05 +0200 Subject: [PATCH 0903/2777] mshtml: Set prototype of MessageEventPrototype to EventPrototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/mshtml_private.h | 2 +- dlls/mshtml/tests/documentmode.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index cb3e63ea79a..2361c4264d4 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -462,7 +462,7 @@ PRIVATE_TID_LIST X(DOMEvent, "Event", DOMEvent_dispex, Object) \ X(DOMCustomEvent, "CustomEvent", DOMCustomEvent_dispex, DOMEvent) \ X(DOMKeyboardEvent, "KeyboardEvent", DOMKeyboardEvent_dispex, Object) \ - X(DOMMessageEvent, "MessageEvent", DOMMessageEvent_dispex, Object) \ + X(DOMMessageEvent, "MessageEvent", DOMMessageEvent_dispex, DOMEvent) \ X(DOMMouseEvent, "MouseEvent", DOMMouseEvent_dispex, Object) \ X(DOMPageTransitionEvent, "PageTransitionEvent", DOMPageTransitionEvent_dispex, Object) \ X(DOMProgressEvent, "ProgressEvent", DOMProgressEvent_dispex, Object) \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index ffc97927083..5fd5d66af4b 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1157,6 +1157,7 @@ sync_test("builtin_prototypes", function() { [ "History", "Object" ], [ "HTMLCollection", "Object" ], [ "MediaQueryList", "Object" ], + [ "MessageEvent", "Event" ], [ "MimeTypeArray", "Object" ], [ "MSCSSRuleList", "Object" ], [ "MSEventObj", "Object" ], @@ -1202,6 +1203,7 @@ sync_test("builtin_prototypes", function() { [ "Comment", ["text"], ["insertData","replaceData","substringData"] ], [ "CustomEvent", ["detail","initCustomEvent"], Event_props ], [ "DocumentType", ["entities","internalSubset","name","notations","publicId","systemId"], Node_props ], + [ "MessageEvent", ["data","initMessageEvent","origin","source"], Event_props ], [ "Text", ["splitText"], ["data","length","appendData","deleteData","insertData","replaceData","substringData"] ], [ "UIEvent", ["detail","initUIEvent","view"], Event_props ] ]; From f0eb936d38b2138a54d83add08115a9de9a658a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:05 +0200 Subject: [PATCH 0904/2777] mshtml: Set prototype of Keyboard/MouseEventPrototype to UIEventPrototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/mshtml_private.h | 4 ++-- dlls/mshtml/tests/documentmode.js | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 2361c4264d4..1792523040a 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -461,9 +461,9 @@ PRIVATE_TID_LIST X(Console, "Console", console_dispex, Object) \ X(DOMEvent, "Event", DOMEvent_dispex, Object) \ X(DOMCustomEvent, "CustomEvent", DOMCustomEvent_dispex, DOMEvent) \ - X(DOMKeyboardEvent, "KeyboardEvent", DOMKeyboardEvent_dispex, Object) \ + X(DOMKeyboardEvent, "KeyboardEvent", DOMKeyboardEvent_dispex, DOMUIEvent) \ X(DOMMessageEvent, "MessageEvent", DOMMessageEvent_dispex, DOMEvent) \ - X(DOMMouseEvent, "MouseEvent", DOMMouseEvent_dispex, Object) \ + X(DOMMouseEvent, "MouseEvent", DOMMouseEvent_dispex, DOMUIEvent) \ X(DOMPageTransitionEvent, "PageTransitionEvent", DOMPageTransitionEvent_dispex, Object) \ X(DOMProgressEvent, "ProgressEvent", DOMProgressEvent_dispex, Object) \ X(DOMStorageEvent, "StorageEvent", DOMStorageEvent_dispex, Object) \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 5fd5d66af4b..83a53d15d1b 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1156,9 +1156,11 @@ sync_test("builtin_prototypes", function() { [ "Event", "Object" ], [ "History", "Object" ], [ "HTMLCollection", "Object" ], + [ "KeyboardEvent", "UIEvent" ], [ "MediaQueryList", "Object" ], [ "MessageEvent", "Event" ], [ "MimeTypeArray", "Object" ], + [ "MouseEvent", "UIEvent" ], [ "MSCSSRuleList", "Object" ], [ "MSEventObj", "Object" ], [ "MSMimeTypesCollection", "Object" ], @@ -1203,7 +1205,9 @@ sync_test("builtin_prototypes", function() { [ "Comment", ["text"], ["insertData","replaceData","substringData"] ], [ "CustomEvent", ["detail","initCustomEvent"], Event_props ], [ "DocumentType", ["entities","internalSubset","name","notations","publicId","systemId"], Node_props ], + [ "KeyboardEvent", ["altKey","ctrlKey","getModifierState","initKeyboardEvent","key","metaKey"], ["detail","initUIEvent","view"] ], [ "MessageEvent", ["data","initMessageEvent","origin","source"], Event_props ], + [ "MouseEvent", ["button","clientX","initMouseEvent","offsetY","pageX","shiftKey","x","y"], ["detail","initUIEvent","view"] ], [ "Text", ["splitText"], ["data","length","appendData","deleteData","insertData","replaceData","substringData"] ], [ "UIEvent", ["detail","initUIEvent","view"], Event_props ] ]; From c6447a15af13611e0f7013649b083a78add24b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:05 +0200 Subject: [PATCH 0905/2777] mshtml: Set prototype of ProgressEventPrototype to EventPrototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/mshtml_private.h | 2 +- dlls/mshtml/tests/documentmode.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 1792523040a..910233abe54 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -465,7 +465,7 @@ PRIVATE_TID_LIST X(DOMMessageEvent, "MessageEvent", DOMMessageEvent_dispex, DOMEvent) \ X(DOMMouseEvent, "MouseEvent", DOMMouseEvent_dispex, DOMUIEvent) \ X(DOMPageTransitionEvent, "PageTransitionEvent", DOMPageTransitionEvent_dispex, Object) \ - X(DOMProgressEvent, "ProgressEvent", DOMProgressEvent_dispex, Object) \ + X(DOMProgressEvent, "ProgressEvent", DOMProgressEvent_dispex, DOMEvent) \ X(DOMStorageEvent, "StorageEvent", DOMStorageEvent_dispex, Object) \ X(DOMUIEvent, "UIEvent", DOMUIEvent_dispex, DOMEvent) \ X(DOMCharacterData, "CharacterData", DOMCharacterData_dispex, HTMLDOMNode) \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 83a53d15d1b..49daa2bc245 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1175,6 +1175,7 @@ sync_test("builtin_prototypes", function() { [ "PerformanceNavigation", "Object" ], [ "PerformanceTiming", "Object" ], [ "PluginArray", "Object" ], + [ "ProgressEvent", "Event" ], [ "Screen", "Object" ], [ "Storage", "Object" ], [ "StyleSheetList", "Object" ], @@ -1208,6 +1209,7 @@ sync_test("builtin_prototypes", function() { [ "KeyboardEvent", ["altKey","ctrlKey","getModifierState","initKeyboardEvent","key","metaKey"], ["detail","initUIEvent","view"] ], [ "MessageEvent", ["data","initMessageEvent","origin","source"], Event_props ], [ "MouseEvent", ["button","clientX","initMouseEvent","offsetY","pageX","shiftKey","x","y"], ["detail","initUIEvent","view"] ], + [ "ProgressEvent", ["initProgressEvent","lengthComputable","loaded","total"], Event_props ], [ "Text", ["splitText"], ["data","length","appendData","deleteData","insertData","replaceData","substringData"] ], [ "UIEvent", ["detail","initUIEvent","view"], Event_props ] ]; From 5adb4edb90e10a9a455d03da846a9720307be580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:05 +0200 Subject: [PATCH 0906/2777] mshtml: Set prototype of StorageEventPrototype to EventPrototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/mshtml_private.h | 2 +- dlls/mshtml/tests/documentmode.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 910233abe54..8fbc2dea2bb 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -466,7 +466,7 @@ PRIVATE_TID_LIST X(DOMMouseEvent, "MouseEvent", DOMMouseEvent_dispex, DOMUIEvent) \ X(DOMPageTransitionEvent, "PageTransitionEvent", DOMPageTransitionEvent_dispex, Object) \ X(DOMProgressEvent, "ProgressEvent", DOMProgressEvent_dispex, DOMEvent) \ - X(DOMStorageEvent, "StorageEvent", DOMStorageEvent_dispex, Object) \ + X(DOMStorageEvent, "StorageEvent", DOMStorageEvent_dispex, DOMEvent) \ X(DOMUIEvent, "UIEvent", DOMUIEvent_dispex, DOMEvent) \ X(DOMCharacterData, "CharacterData", DOMCharacterData_dispex, HTMLDOMNode) \ X(DocumentType, "DocumentType", DocumentType_dispex, HTMLDOMNode) \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 49daa2bc245..0ac2d5770b5 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1178,6 +1178,7 @@ sync_test("builtin_prototypes", function() { [ "ProgressEvent", "Event" ], [ "Screen", "Object" ], [ "Storage", "Object" ], + [ "StorageEvent", "Event" ], [ "StyleSheetList", "Object" ], [ "Text", "CharacterData" ], [ "TextRange", "Object" ], @@ -1210,6 +1211,7 @@ sync_test("builtin_prototypes", function() { [ "MessageEvent", ["data","initMessageEvent","origin","source"], Event_props ], [ "MouseEvent", ["button","clientX","initMouseEvent","offsetY","pageX","shiftKey","x","y"], ["detail","initUIEvent","view"] ], [ "ProgressEvent", ["initProgressEvent","lengthComputable","loaded","total"], Event_props ], + [ "StorageEvent", ["initStorageEvent","key","newValue","oldValue","storageArea"], Event_props ], [ "Text", ["splitText"], ["data","length","appendData","deleteData","insertData","replaceData","substringData"] ], [ "UIEvent", ["detail","initUIEvent","view"], Event_props ] ]; From b7dcf6fdd84d82764af06cc522bfb439928a152a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:06 +0200 Subject: [PATCH 0907/2777] mshtml: Set prototype of PageTransitionEventPrototype to EventPrototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/mshtml_private.h | 2 +- dlls/mshtml/tests/documentmode.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 8fbc2dea2bb..9b9990df463 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -464,7 +464,7 @@ PRIVATE_TID_LIST X(DOMKeyboardEvent, "KeyboardEvent", DOMKeyboardEvent_dispex, DOMUIEvent) \ X(DOMMessageEvent, "MessageEvent", DOMMessageEvent_dispex, DOMEvent) \ X(DOMMouseEvent, "MouseEvent", DOMMouseEvent_dispex, DOMUIEvent) \ - X(DOMPageTransitionEvent, "PageTransitionEvent", DOMPageTransitionEvent_dispex, Object) \ + X(DOMPageTransitionEvent, "PageTransitionEvent", DOMPageTransitionEvent_dispex, DOMEvent) \ X(DOMProgressEvent, "ProgressEvent", DOMProgressEvent_dispex, DOMEvent) \ X(DOMStorageEvent, "StorageEvent", DOMStorageEvent_dispex, DOMEvent) \ X(DOMUIEvent, "UIEvent", DOMUIEvent_dispex, DOMEvent) \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 0ac2d5770b5..3bf458ef393 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1171,6 +1171,7 @@ sync_test("builtin_prototypes", function() { [ "Navigator", "Object" ], [ "Node", "Object" ], [ "NodeList", "Object" ], + [ "PageTransitionEvent", "Event" ], [ "Performance", "Object" ], [ "PerformanceNavigation", "Object" ], [ "PerformanceTiming", "Object" ], From 444f1745bdc4ce5f147381ea2ccd1bce4c77f871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:06 +0200 Subject: [PATCH 0908/2777] mshtml: Introduce ElementPrototype and set it as HTMLElementPrototype's prototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The interface will be used for non-HTML elements (such as XML elements) and its prototype is also the prototype of HTMLElementPrototype. We exlude all the props that are part of HTMLElementPrototype though. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlelem.c | 240 ++++++++++++++++++++++++++++++ dlls/mshtml/mshtml_private.h | 3 +- dlls/mshtml/tests/documentmode.js | 23 +++ 3 files changed, 265 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 635b9497d04..09645a1876e 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -7260,6 +7260,246 @@ static event_target_vtbl_t HTMLElement_event_target_vtbl = { HTMLElement_set_current_event }; +static void DOMElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t elem_hooks[] = { + {DISPID_IHTMLELEMENT_CLASSNAME}, + {DISPID_IHTMLELEMENT_ID}, + {DISPID_IHTMLELEMENT_PARENTELEMENT}, + {DISPID_IHTMLELEMENT_STYLE}, + {DISPID_IHTMLELEMENT_ONHELP}, + {DISPID_IHTMLELEMENT_ONCLICK}, + {DISPID_IHTMLELEMENT_ONDBLCLICK}, + {DISPID_IHTMLELEMENT_ONKEYDOWN}, + {DISPID_IHTMLELEMENT_ONKEYUP}, + {DISPID_IHTMLELEMENT_ONKEYPRESS}, + {DISPID_IHTMLELEMENT_ONMOUSEOUT}, + {DISPID_IHTMLELEMENT_ONMOUSEOVER}, + {DISPID_IHTMLELEMENT_ONMOUSEMOVE}, + {DISPID_IHTMLELEMENT_ONMOUSEDOWN}, + {DISPID_IHTMLELEMENT_ONMOUSEUP}, + {DISPID_IHTMLELEMENT_DOCUMENT}, + {DISPID_IHTMLELEMENT_TITLE}, + {DISPID_IHTMLELEMENT_LANGUAGE}, + {DISPID_IHTMLELEMENT_ONSELECTSTART}, + {DISPID_IHTMLELEMENT_SCROLLINTOVIEW}, + {DISPID_IHTMLELEMENT_CONTAINS}, + {DISPID_IHTMLELEMENT_SOURCEINDEX}, + {DISPID_IHTMLELEMENT_RECORDNUMBER}, + {DISPID_IHTMLELEMENT_LANG}, + {DISPID_IHTMLELEMENT_OFFSETLEFT}, + {DISPID_IHTMLELEMENT_OFFSETTOP}, + {DISPID_IHTMLELEMENT_OFFSETWIDTH}, + {DISPID_IHTMLELEMENT_OFFSETHEIGHT}, + {DISPID_IHTMLELEMENT_OFFSETPARENT}, + {DISPID_IHTMLELEMENT_INNERHTML}, + {DISPID_IHTMLELEMENT_INNERTEXT}, + {DISPID_IHTMLELEMENT_OUTERHTML}, + {DISPID_IHTMLELEMENT_OUTERTEXT}, + {DISPID_IHTMLELEMENT_INSERTADJACENTHTML}, + {DISPID_IHTMLELEMENT_INSERTADJACENTTEXT}, + {DISPID_IHTMLELEMENT_PARENTTEXTEDIT}, + {DISPID_IHTMLELEMENT_ISTEXTEDIT}, + {DISPID_IHTMLELEMENT_CLICK}, + {DISPID_IHTMLELEMENT_FILTERS}, + {DISPID_IHTMLELEMENT_ONDRAGSTART}, + {DISPID_IHTMLELEMENT_TOSTRING}, + {DISPID_IHTMLELEMENT_ONBEFOREUPDATE}, + {DISPID_IHTMLELEMENT_ONAFTERUPDATE}, + {DISPID_IHTMLELEMENT_ONERRORUPDATE}, + {DISPID_IHTMLELEMENT_ONROWEXIT}, + {DISPID_IHTMLELEMENT_ONROWENTER}, + {DISPID_IHTMLELEMENT_ONDATASETCHANGED}, + {DISPID_IHTMLELEMENT_ONDATAAVAILABLE}, + {DISPID_IHTMLELEMENT_ONDATASETCOMPLETE}, + {DISPID_IHTMLELEMENT_ONFILTERCHANGE}, + {DISPID_IHTMLELEMENT_CHILDREN}, + {DISPID_IHTMLELEMENT_ALL}, + {DISPID_UNKNOWN} + }; + static const dispex_hook_t elem2_hooks[] = { + {DISPID_IHTMLELEMENT2_SCOPENAME}, + {DISPID_IHTMLELEMENT2_SETCAPTURE}, + {DISPID_IHTMLELEMENT2_RELEASECAPTURE}, + {DISPID_IHTMLELEMENT2_ONLOSECAPTURE}, + {DISPID_IHTMLELEMENT2_COMPONENTFROMPOINT}, + {DISPID_IHTMLELEMENT2_DOSCROLL}, + {DISPID_IHTMLELEMENT2_ONSCROLL}, + {DISPID_IHTMLELEMENT2_ONDRAG}, + {DISPID_IHTMLELEMENT2_ONDRAGEND}, + {DISPID_IHTMLELEMENT2_ONDRAGENTER}, + {DISPID_IHTMLELEMENT2_ONDRAGOVER}, + {DISPID_IHTMLELEMENT2_ONDRAGLEAVE}, + {DISPID_IHTMLELEMENT2_ONDROP}, + {DISPID_IHTMLELEMENT2_ONBEFORECUT}, + {DISPID_IHTMLELEMENT2_ONCUT}, + {DISPID_IHTMLELEMENT2_ONBEFORECOPY}, + {DISPID_IHTMLELEMENT2_ONCOPY}, + {DISPID_IHTMLELEMENT2_ONBEFOREPASTE}, + {DISPID_IHTMLELEMENT2_ONPASTE}, + {DISPID_IHTMLELEMENT2_CURRENTSTYLE}, + {DISPID_IHTMLELEMENT2_ONPROPERTYCHANGE}, + {DISPID_IHTMLELEMENT2_SETEXPRESSION}, + {DISPID_IHTMLELEMENT2_GETEXPRESSION}, + {DISPID_IHTMLELEMENT2_REMOVEEXPRESSION}, + {DISPID_IHTMLELEMENT2_TABINDEX}, + {DISPID_IHTMLELEMENT2_FOCUS}, + {DISPID_IHTMLELEMENT2_ACCESSKEY}, + {DISPID_IHTMLELEMENT2_ONBLUR}, + {DISPID_IHTMLELEMENT2_ONFOCUS}, + {DISPID_IHTMLELEMENT2_ONRESIZE}, + {DISPID_IHTMLELEMENT2_BLUR}, + {DISPID_IHTMLELEMENT2_ADDFILTER}, + {DISPID_IHTMLELEMENT2_REMOVEFILTER}, + {DISPID_IHTMLELEMENT2_ATTACHEVENT}, + {DISPID_IHTMLELEMENT2_DETACHEVENT}, + {DISPID_IHTMLELEMENT2_READYSTATE}, + {DISPID_IHTMLELEMENT2_ONREADYSTATECHANGE}, + {DISPID_IHTMLELEMENT2_ONROWSDELETE}, + {DISPID_IHTMLELEMENT2_ONROWSINSERTED}, + {DISPID_IHTMLELEMENT2_ONCELLCHANGE}, + {DISPID_IHTMLELEMENT2_DIR}, + {DISPID_IHTMLELEMENT2_CREATECONTROLRANGE}, + {DISPID_IHTMLELEMENT2_CLEARATTRIBUTES}, + {DISPID_IHTMLELEMENT2_MERGEATTRIBUTES}, + {DISPID_IHTMLELEMENT2_ONCONTEXTMENU}, + {DISPID_IHTMLELEMENT2_INSERTADJACENTELEMENT}, + {DISPID_IHTMLELEMENT2_APPLYELEMENT}, + {DISPID_IHTMLELEMENT2_GETADJACENTTEXT}, + {DISPID_IHTMLELEMENT2_REPLACEADJACENTTEXT}, + {DISPID_IHTMLELEMENT2_CANHAVECHILDREN}, + {DISPID_IHTMLELEMENT2_ADDBEHAVIOR}, + {DISPID_IHTMLELEMENT2_REMOVEBEHAVIOR}, + {DISPID_IHTMLELEMENT2_RUNTIMESTYLE}, + {DISPID_IHTMLELEMENT2_BEHAVIORURNS}, + {DISPID_IHTMLELEMENT2_TAGURN}, + {DISPID_IHTMLELEMENT2_ONBEFOREEDITFOCUS}, + {DISPID_IHTMLELEMENT2_READYSTATEVALUE}, + {DISPID_UNKNOWN} + }; + static const dispex_hook_t elem3_hooks[] = { + {DISPID_IHTMLELEMENT3_MERGEATTRIBUTES}, + {DISPID_IHTMLELEMENT3_ISMULTILINE}, + {DISPID_IHTMLELEMENT3_CANHAVEHTML}, + {DISPID_IHTMLELEMENT3_ONLAYOUTCOMPLETE}, + {DISPID_IHTMLELEMENT3_ONPAGE}, + {DISPID_IHTMLELEMENT3_INFLATEBLOCK}, + {DISPID_IHTMLELEMENT3_ONBEFOREDEACTIVATE}, + {DISPID_IHTMLELEMENT3_SETACTIVE}, + {DISPID_IHTMLELEMENT3_CONTENTEDITABLE}, + {DISPID_IHTMLELEMENT3_ISCONTENTEDITABLE}, + {DISPID_IHTMLELEMENT3_HIDEFOCUS}, + {DISPID_IHTMLELEMENT3_DISABLED}, + {DISPID_IHTMLELEMENT3_ISDISABLED}, + {DISPID_IHTMLELEMENT3_ONMOVE}, + {DISPID_IHTMLELEMENT3_ONCONTROLSELECT}, + {DISPID_IHTMLELEMENT3_FIREEVENT}, + {DISPID_IHTMLELEMENT3_ONRESIZESTART}, + {DISPID_IHTMLELEMENT3_ONRESIZEEND}, + {DISPID_IHTMLELEMENT3_ONMOVESTART}, + {DISPID_IHTMLELEMENT3_ONMOVEEND}, + {DISPID_IHTMLELEMENT3_ONMOUSEENTER}, + {DISPID_IHTMLELEMENT3_ONMOUSELEAVE}, + {DISPID_IHTMLELEMENT3_ONACTIVATE}, + {DISPID_IHTMLELEMENT3_ONDEACTIVATE}, + {DISPID_IHTMLELEMENT3_DRAGDROP}, + {DISPID_IHTMLELEMENT3_GLYPHMODE}, + {DISPID_UNKNOWN} + }; + static const dispex_hook_t elem4_hooks[] = { + {DISPID_IHTMLELEMENT4_ONMOUSEWHEEL}, + {DISPID_IHTMLELEMENT4_NORMALIZE}, + {DISPID_IHTMLELEMENT4_ONBEFOREACTIVATE}, + {DISPID_IHTMLELEMENT4_ONFOCUSIN}, + {DISPID_IHTMLELEMENT4_ONFOCUSOUT}, + {DISPID_UNKNOWN} + }; + static const dispex_hook_t elem6_ie10_hooks[] = { + {DISPID_IHTMLELEMENT6_HASATTRIBUTENS, IHTMLElement6_hasAttributeNS_hook}, + {DISPID_IHTMLELEMENT6_GETATTRIBUTENS, IHTMLElement6_getAttributeNS_hook}, + {DISPID_IHTMLELEMENT6_REMOVEATTRIBUTENS, IHTMLElement6_removeAttributeNS_hook}, + {DISPID_IHTMLELEMENT6_IE9_SETATTRIBUTE, IHTMLElement6_setAttribute_hook}, + + /* common for all supported modes */ + {DISPID_IHTMLELEMENT6_SETATTRIBUTENS, IHTMLElement6_setAttributeNS_hook}, + + {DISPID_IHTMLELEMENT6_IE9_NODENAME}, + {DISPID_IHTMLELEMENT6_GETELEMENTSBYCLASSNAME}, + {DISPID_IHTMLELEMENT6_ONABORT}, + {DISPID_IHTMLELEMENT6_ONCANPLAY}, + {DISPID_IHTMLELEMENT6_ONCANPLAYTHROUGH}, + {DISPID_IHTMLELEMENT6_ONCHANGE}, + {DISPID_IHTMLELEMENT6_ONDURATIONCHANGE}, + {DISPID_IHTMLELEMENT6_ONEMPTIED}, + {DISPID_IHTMLELEMENT6_ONENDED}, + {DISPID_IHTMLELEMENT6_ONERROR}, + {DISPID_IHTMLELEMENT6_ONINPUT}, + {DISPID_IHTMLELEMENT6_ONLOAD}, + {DISPID_IHTMLELEMENT6_ONLOADEDDATA}, + {DISPID_IHTMLELEMENT6_ONLOADEDMETADATA}, + {DISPID_IHTMLELEMENT6_ONLOADSTART}, + {DISPID_IHTMLELEMENT6_ONPAUSE}, + {DISPID_IHTMLELEMENT6_ONPLAY}, + {DISPID_IHTMLELEMENT6_ONPLAYING}, + {DISPID_IHTMLELEMENT6_ONPROGRESS}, + {DISPID_IHTMLELEMENT6_ONRATECHANGE}, + {DISPID_IHTMLELEMENT6_ONRESET}, + {DISPID_IHTMLELEMENT6_ONSEEKED}, + {DISPID_IHTMLELEMENT6_ONSEEKING}, + {DISPID_IHTMLELEMENT6_ONSELECT}, + {DISPID_IHTMLELEMENT6_ONSTALLED}, + {DISPID_IHTMLELEMENT6_ONSUBMIT}, + {DISPID_IHTMLELEMENT6_ONSUSPEND}, + {DISPID_IHTMLELEMENT6_ONTIMEUPDATE}, + {DISPID_IHTMLELEMENT6_ONVOLUMECHANGE}, + {DISPID_IHTMLELEMENT6_ONWAITING}, + {DISPID_IHTMLELEMENT6_IE9_HASATTRIBUTES}, + {DISPID_UNKNOWN} + }; + const dispex_hook_t *const elem6_hooks = elem6_ie10_hooks + 4; + static const dispex_hook_t elem7_hooks[] = { + {DISPID_IHTMLELEMENT7_ONMSPOINTERHOVER}, + {DISPID_IHTMLELEMENT7_ONMSTRANSITIONSTART}, + {DISPID_IHTMLELEMENT7_ONMSTRANSITIONEND}, + {DISPID_IHTMLELEMENT7_ONMSANIMATIONSTART}, + {DISPID_IHTMLELEMENT7_ONMSANIMATIONEND}, + {DISPID_IHTMLELEMENT7_ONMSANIMATIONITERATION}, + {DISPID_IHTMLELEMENT7_ONINVALID}, + {DISPID_IHTMLELEMENT7_XMSACCELERATORKEY}, + {DISPID_IHTMLELEMENT7_SPELLCHECK}, + {DISPID_IHTMLELEMENT7_ONMSMANIPULATIONSTATECHANGED}, + {DISPID_IHTMLELEMENT7_ONCUECHANGE}, + {DISPID_UNKNOWN} + }; + static const tid_t hookless_tids[] = { + IHTMLDOMNode_tid, + IHTMLDOMNode2_tid, + IElementSelector_tid, + IElementTraversal_tid, + 0 + }; + unsigned i; + + dispex_info_add_interface(info, IHTMLElement2_tid, elem2_hooks); + dispex_info_add_interface(info, IHTMLElement6_tid, mode >= COMPAT_MODE_IE10 ? elem6_ie10_hooks : elem6_hooks); + if(mode >= COMPAT_MODE_IE10) + dispex_info_add_interface(info, IHTMLElement7_tid, elem7_hooks); + dispex_info_add_interface(info, IHTMLElement_tid, elem_hooks); + dispex_info_add_interface(info, IHTMLElement3_tid, elem3_hooks); + dispex_info_add_interface(info, IHTMLElement4_tid, elem4_hooks); + for(i = 0; i < ARRAY_SIZE(hookless_tids); i++) + dispex_info_add_interface(info, hookless_tids[i], NULL); +} + +dispex_static_data_t DOMElement_dispex = { + L"Element", + NULL, + PROTO_ID_DOMElement, + NULL_tid, + no_iface_tids, + DOMElement_init_dispex_info +}; + struct token_list { DispatchEx dispex; IWineDOMTokenList IWineDOMTokenList_iface; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 9b9990df463..a824d22331c 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -428,7 +428,7 @@ PRIVATE_TID_LIST X(HTMLW3CComputedStyle, "CSSStyleDeclaration", HTMLW3CComputedStyle_dispex, Object) \ X(HTMLStyleSheet, "CSSStyleSheet", HTMLStyleSheet_dispex, Object) \ X(HTMLStyleSheetRule, "CSSStyleRule", HTMLStyleSheetRule_dispex, Object) \ - X(HTMLElement, "HTMLElement", HTMLElement_dispex, Object) \ + X(HTMLElement, "HTMLElement", HTMLElement_dispex, DOMElement) \ X(HTMLGenericElement, "HTMLUnknownElement", HTMLGenericElement_dispex, Object) \ X(HTMLAnchorElement, "HTMLAnchorElement", HTMLAnchorElement_dispex, Object) \ X(HTMLAreaElement, "HTMLAreaElement", HTMLAreaElement_dispex, Object) \ @@ -470,6 +470,7 @@ PRIVATE_TID_LIST X(DOMUIEvent, "UIEvent", DOMUIEvent_dispex, DOMEvent) \ X(DOMCharacterData, "CharacterData", DOMCharacterData_dispex, HTMLDOMNode) \ X(DocumentType, "DocumentType", DocumentType_dispex, HTMLDOMNode) \ + X(DOMElement, "Element", DOMElement_dispex, HTMLDOMNode) \ X(MediaQueryList, "MediaQueryList", media_query_list_dispex, Object) \ X(DOMTokenList, "DOMTokenList", DOMTokenList_dispex, Object) \ X(HTMLDOMNode, "Node", HTMLDOMNode_dispex, Object) \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 3bf458ef393..202a641ca54 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1153,9 +1153,11 @@ sync_test("builtin_prototypes", function() { [ "DocumentType", "Node" ], [ "DOMImplementation", "Object" ], [ "DOMTokenList", "Object" ], + [ "Element", "Node" ], [ "Event", "Object" ], [ "History", "Object" ], [ "HTMLCollection", "Object" ], + [ "HTMLElement", "Element" ], [ "KeyboardEvent", "UIEvent" ], [ "MediaQueryList", "Object" ], [ "MessageEvent", "Event" ], @@ -1196,8 +1198,27 @@ sync_test("builtin_prototypes", function() { ok(a === b, "getPrototypeOf(" + protos[i][0] + ".prototype) = " + a); } + var Elem_props = [ "clientHeight","clientLeft","clientTop","clientWidth","firstElementChild","getAttribute","getAttributeNode","getAttributeNodeNS", + "getAttributeNS","getBoundingClientRect","getClientRects","getElementsByTagName","getElementsByTagNameNS","hasAttribute", + "hasAttributeNS","lastElementChild","msMatchesSelector","nextElementSibling","previousElementSibling","querySelector", + "removeAttribute","removeAttributeNode","removeAttributeNS","scrollHeight","scrollLeft","scrollTop","scrollWidth","setAttribute", + "setAttributeNode","setAttributeNodeNS","setAttributeNS","tagName" ]; var Event_props = [ "bubbles","cancelable","cancelBubble","currentTarget","defaultPrevented","eventPhase","initEvent","isTrusted", "preventDefault","srcElement","stopImmediatePropagation","stopPropagation","target","timeStamp","type" ]; + var HtmlElem_props = [ "accessKey","applyElement","blur","canHaveHTML","children","className","clearAttributes","click","componentFromPoint", + "contains","contentEditable","createControlRange","currentStyle","dir","disabled","dragDrop","focus","getAdjacentText", + "getElementsByClassName","hideFocus","id","innerHTML","innerText","insertAdjacentElement","insertAdjacentHTML", + "insertAdjacentText","isContentEditable","isDisabled","isMultiLine","isTextEdit","lang","language","mergeAttributes", + "offsetHeight","offsetLeft","offsetParent","offsetTop","offsetWidth","onabort","onactivate","onbeforeactivate","onbeforecopy", + "onbeforecut","onbeforedeactivate","onbeforepaste","onblur","oncanplay","oncanplaythrough","onchange","onclick", + "oncontextmenu","oncopy","oncut","ondblclick","ondeactivate","ondrag","ondragend","ondragenter","ondragleave","ondragover", + "ondragstart","ondrop","ondurationchange","onemptied","onended","onerror","onfocus","onfocusin","onfocusout","onhelp", + "oninput","onkeydown","onkeypress","onkeyup","onload","onloadeddata","onloadedmetadata","onloadstart","onmousedown", + "onmouseleave","onmousemove","onmouseout","onmouseover","onmouseup","onmousewheel","onpaste","onpause","onplay","onplaying", + "onprogress","onratechange","onreset","onscroll","onseeked","onseeking","onselect","onselectstart","onstalled","onsubmit", + "onsuspend","ontimeupdate","onvolumechange","onwaiting","outerHTML","outerText","parentElement","parentTextEdit", + "recordNumber","releaseCapture","replaceAdjacentText","runtimeStyle","scrollIntoView","setActive","setCapture","sourceIndex", + "style","tabIndex","title","uniqueID","uniqueNumber" ]; var Node_props = [ "addEventListener","appendChild","attributes","childNodes","cloneNode","compareDocumentPosition","dispatchEvent","firstChild", "hasChildNodes","insertBefore","isDefaultNamespace","isEqualNode","isSameNode","isSupported","lastChild","localName", "lookupNamespaceURI","lookupPrefix","namespaceURI","nextSibling","nodeName","nodeType","nodeValue","ownerDocument", @@ -1208,6 +1229,8 @@ sync_test("builtin_prototypes", function() { [ "Comment", ["text"], ["insertData","replaceData","substringData"] ], [ "CustomEvent", ["detail","initCustomEvent"], Event_props ], [ "DocumentType", ["entities","internalSubset","name","notations","publicId","systemId"], Node_props ], + [ "Element", Elem_props, Node_props ], + [ "HTMLElement", HtmlElem_props, Elem_props ], [ "KeyboardEvent", ["altKey","ctrlKey","getModifierState","initKeyboardEvent","key","metaKey"], ["detail","initUIEvent","view"] ], [ "MessageEvent", ["data","initMessageEvent","origin","source"], Event_props ], [ "MouseEvent", ["button","clientX","initMouseEvent","offsetY","pageX","shiftKey","x","y"], ["detail","initUIEvent","view"] ], From 0d94c0ff3643314f317c8a114ccb550e9232bb32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:06 +0200 Subject: [PATCH 0909/2777] mshtml: Set prototype of other HTML elements to HTMLElementPrototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/mshtml_private.h | 52 +++++++++++++++---------------- dlls/mshtml/tests/documentmode.js | 28 +++++++++++++++++ 2 files changed, 54 insertions(+), 26 deletions(-) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index a824d22331c..eb8842c20db 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -429,33 +429,33 @@ PRIVATE_TID_LIST X(HTMLStyleSheet, "CSSStyleSheet", HTMLStyleSheet_dispex, Object) \ X(HTMLStyleSheetRule, "CSSStyleRule", HTMLStyleSheetRule_dispex, Object) \ X(HTMLElement, "HTMLElement", HTMLElement_dispex, DOMElement) \ - X(HTMLGenericElement, "HTMLUnknownElement", HTMLGenericElement_dispex, Object) \ - X(HTMLAnchorElement, "HTMLAnchorElement", HTMLAnchorElement_dispex, Object) \ - X(HTMLAreaElement, "HTMLAreaElement", HTMLAreaElement_dispex, Object) \ - X(HTMLBodyElement, "HTMLBodyElement", HTMLBodyElement_dispex, Object) \ - X(HTMLButtonElement, "HTMLButtonElement", HTMLButtonElement_dispex, Object) \ + X(HTMLGenericElement, "HTMLUnknownElement", HTMLGenericElement_dispex, HTMLElement) \ + X(HTMLAnchorElement, "HTMLAnchorElement", HTMLAnchorElement_dispex, HTMLElement) \ + X(HTMLAreaElement, "HTMLAreaElement", HTMLAreaElement_dispex, HTMLElement) \ + X(HTMLBodyElement, "HTMLBodyElement", HTMLBodyElement_dispex, HTMLElement) \ + X(HTMLButtonElement, "HTMLButtonElement", HTMLButtonElement_dispex, HTMLElement) \ X(HTMLCommentElement, "Comment", HTMLCommentElement_dispex, DOMCharacterData) \ - X(HTMLEmbedElement, "HTMLEmbedElement", HTMLEmbedElement_dispex, Object) \ - X(HTMLFormElement, "HTMLFormElement", HTMLFormElement_dispex, Object) \ - X(HTMLFrameElement, "HTMLFrameElement", HTMLFrameElement_dispex, Object) \ - X(HTMLHeadElement, "HTMLHeadElement", HTMLHeadElement_dispex, Object) \ - X(HTMLHtmlElement, "HTMLHtmlElement", HTMLHtmlElement_dispex, Object) \ - X(HTMLIFrameElement, "HTMLIFrameElement", HTMLIFrame_dispex, Object) \ - X(HTMLImgElement, "HTMLImageElement", HTMLImgElement_dispex, Object) \ - X(HTMLInputElement, "HTMLInputElement", HTMLInputElement_dispex, Object) \ - X(HTMLLabelElement, "HTMLLabelElement", HTMLLabelElement_dispex, Object) \ - X(HTMLLinkElement, "HTMLLinkElement", HTMLLinkElement_dispex, Object) \ - X(HTMLMetaElement, "HTMLMetaElement", HTMLMetaElement_dispex, Object) \ - X(HTMLObjectElement, "HTMLObjectElement", HTMLObjectElement_dispex, Object) \ - X(HTMLOptionElement, "HTMLOptionElement", HTMLOptionElement_dispex, Object) \ - X(HTMLScriptElement, "HTMLScriptElement", HTMLScriptElement_dispex, Object) \ - X(HTMLSelectElement, "HTMLSelectElement", HTMLSelectElement_dispex, Object) \ - X(HTMLStyleElement, "HTMLStyleElement", HTMLStyleElement_dispex, Object) \ - X(HTMLTableElement, "HTMLTableElement", HTMLTable_dispex, Object) \ - X(HTMLTableCellElement, "HTMLTableDataCellElement", HTMLTableCell_dispex, Object) \ - X(HTMLTableRowElement, "HTMLTableRowElement", HTMLTableRow_dispex, Object) \ - X(HTMLTextAreaElement, "HTMLTextAreaElement", HTMLTextAreaElement_dispex, Object) \ - X(HTMLTitleElement, "HTMLTitleElement", HTMLTitleElement_dispex, Object) + X(HTMLEmbedElement, "HTMLEmbedElement", HTMLEmbedElement_dispex, HTMLElement) \ + X(HTMLFormElement, "HTMLFormElement", HTMLFormElement_dispex, HTMLElement) \ + X(HTMLFrameElement, "HTMLFrameElement", HTMLFrameElement_dispex, HTMLElement) \ + X(HTMLHeadElement, "HTMLHeadElement", HTMLHeadElement_dispex, HTMLElement) \ + X(HTMLHtmlElement, "HTMLHtmlElement", HTMLHtmlElement_dispex, HTMLElement) \ + X(HTMLIFrameElement, "HTMLIFrameElement", HTMLIFrame_dispex, HTMLElement) \ + X(HTMLImgElement, "HTMLImageElement", HTMLImgElement_dispex, HTMLElement) \ + X(HTMLInputElement, "HTMLInputElement", HTMLInputElement_dispex, HTMLElement) \ + X(HTMLLabelElement, "HTMLLabelElement", HTMLLabelElement_dispex, HTMLElement) \ + X(HTMLLinkElement, "HTMLLinkElement", HTMLLinkElement_dispex, HTMLElement) \ + X(HTMLMetaElement, "HTMLMetaElement", HTMLMetaElement_dispex, HTMLElement) \ + X(HTMLObjectElement, "HTMLObjectElement", HTMLObjectElement_dispex, HTMLElement) \ + X(HTMLOptionElement, "HTMLOptionElement", HTMLOptionElement_dispex, HTMLElement) \ + X(HTMLScriptElement, "HTMLScriptElement", HTMLScriptElement_dispex, HTMLElement) \ + X(HTMLSelectElement, "HTMLSelectElement", HTMLSelectElement_dispex, HTMLElement) \ + X(HTMLStyleElement, "HTMLStyleElement", HTMLStyleElement_dispex, HTMLElement) \ + X(HTMLTableElement, "HTMLTableElement", HTMLTable_dispex, HTMLElement) \ + X(HTMLTableCellElement, "HTMLTableDataCellElement", HTMLTableCell_dispex, HTMLElement) \ + X(HTMLTableRowElement, "HTMLTableRowElement", HTMLTableRow_dispex, HTMLElement) \ + X(HTMLTextAreaElement, "HTMLTextAreaElement", HTMLTextAreaElement_dispex, HTMLElement) \ + X(HTMLTitleElement, "HTMLTitleElement", HTMLTitleElement_dispex, HTMLElement) #define PROXY_PROTOTYPE_LIST \ X(Console, "Console", console_dispex, Object) \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 202a641ca54..4a7ecf04323 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1156,8 +1156,34 @@ sync_test("builtin_prototypes", function() { [ "Element", "Node" ], [ "Event", "Object" ], [ "History", "Object" ], + [ "HTMLAnchorElement", "HTMLElement" ], + [ "HTMLAreaElement", "HTMLElement" ], + [ "HTMLBodyElement", "HTMLElement" ], + [ "HTMLButtonElement", "HTMLElement" ], [ "HTMLCollection", "Object" ], [ "HTMLElement", "Element" ], + [ "HTMLEmbedElement", "HTMLElement" ], + [ "HTMLFormElement", "HTMLElement" ], + [ "HTMLFrameElement", "HTMLElement" ], + [ "HTMLHeadElement", "HTMLElement" ], + [ "HTMLHtmlElement", "HTMLElement" ], + [ "HTMLIFrameElement", "HTMLElement" ], + [ "HTMLImgElement", "HTMLElement" ], + [ "HTMLInputElement", "HTMLElement" ], + [ "HTMLLabelElement", "HTMLElement" ], + [ "HTMLLinkElement", "HTMLElement" ], + [ "HTMLMetaElement", "HTMLElement" ], + [ "HTMLObjectElement", "HTMLElement" ], + [ "HTMLOptionElement", "HTMLElement" ], + [ "HTMLScriptElement", "HTMLElement" ], + [ "HTMLSelectElement", "HTMLElement" ], + [ "HTMLStyleElement", "HTMLElement" ], + [ "HTMLTableElement", "HTMLElement" ], + [ "HTMLTableRowElement", "HTMLElement" ], + [ "HTMLTextAreaElement", "HTMLElement" ], + [ "HTMLTitleElement", "HTMLElement" ], + [ "HTMLUnknownElement", "HTMLElement" ], + [ "Image", "HTMLElement" ], [ "KeyboardEvent", "UIEvent" ], [ "MediaQueryList", "Object" ], [ "MessageEvent", "Event" ], @@ -1173,6 +1199,7 @@ sync_test("builtin_prototypes", function() { [ "Navigator", "Object" ], [ "Node", "Object" ], [ "NodeList", "Object" ], + [ "Option", "HTMLElement" ], [ "PageTransitionEvent", "Event" ], [ "Performance", "Object" ], [ "PerformanceNavigation", "Object" ], @@ -1231,6 +1258,7 @@ sync_test("builtin_prototypes", function() { [ "DocumentType", ["entities","internalSubset","name","notations","publicId","systemId"], Node_props ], [ "Element", Elem_props, Node_props ], [ "HTMLElement", HtmlElem_props, Elem_props ], + [ "HTMLUnknownElement", ["recordset","namedRecordset"], HtmlElem_props ], [ "KeyboardEvent", ["altKey","ctrlKey","getModifierState","initKeyboardEvent","key","metaKey"], ["detail","initUIEvent","view"] ], [ "MessageEvent", ["data","initMessageEvent","origin","source"], Event_props ], [ "MouseEvent", ["button","clientX","initMouseEvent","offsetY","pageX","shiftKey","x","y"], ["detail","initUIEvent","view"] ], From 0f317e7359c476dec49c55fd8bba352fcaad1b50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:06 +0200 Subject: [PATCH 0910/2777] mshtml: Introduce HTMLTableCellElementPrototype and set it as HTMLTableDataCellElementPrototype's prototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The interface is abstract, and is only used in prototype chains (and constructor), so we needn't implement any of it. HTMLTableDataCellElementPrototype is, in fact, empty (other than its "constructor" prop). Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmltable.c | 15 +++++++++++++++ dlls/mshtml/mshtml_private.h | 5 +++-- dlls/mshtml/tests/documentmode.js | 6 ++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/htmltable.c b/dlls/mshtml/htmltable.c index cf5f2d93072..df5a6f0789f 100644 --- a/dlls/mshtml/htmltable.c +++ b/dlls/mshtml/htmltable.c @@ -551,6 +551,21 @@ HRESULT HTMLTableCell_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLE return S_OK; } +/* dummy dispex used only for HTMLTableCellElementPrototype in prototype chain */ +static void HTMLTableCellProt_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + dispex_info_add_interface(info, IHTMLTableCell_tid, NULL); +} + +dispex_static_data_t HTMLTableCellProt_dispex = { + L"HTMLTableCellElement", + NULL, + PROTO_ID_HTMLTableCellProt, + NULL_tid, + no_iface_tids, + HTMLTableCellProt_init_dispex_info +}; + struct HTMLTableRow { HTMLElement element; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index eb8842c20db..7e4bcac824a 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -452,7 +452,7 @@ PRIVATE_TID_LIST X(HTMLSelectElement, "HTMLSelectElement", HTMLSelectElement_dispex, HTMLElement) \ X(HTMLStyleElement, "HTMLStyleElement", HTMLStyleElement_dispex, HTMLElement) \ X(HTMLTableElement, "HTMLTableElement", HTMLTable_dispex, HTMLElement) \ - X(HTMLTableCellElement, "HTMLTableDataCellElement", HTMLTableCell_dispex, HTMLElement) \ + X(HTMLTableCellElement, "HTMLTableDataCellElement", HTMLTableCell_dispex, HTMLTableCellProt) \ X(HTMLTableRowElement, "HTMLTableRowElement", HTMLTableRow_dispex, HTMLElement) \ X(HTMLTextAreaElement, "HTMLTextAreaElement", HTMLTextAreaElement_dispex, HTMLElement) \ X(HTMLTitleElement, "HTMLTitleElement", HTMLTitleElement_dispex, HTMLElement) @@ -479,7 +479,8 @@ PRIVATE_TID_LIST X(HTMLPerformance, "Performance", HTMLPerformance_dispex, Object) \ X(HTMLPerformanceNavigation, "PerformanceNavigation", HTMLPerformanceNavigation_dispex, Object) \ X(HTMLPerformanceTiming, "PerformanceTiming", HTMLPerformanceTiming_dispex, Object) \ - X(HTMLStyle, "MSStyleCSSProperties", HTMLStyle_dispex, Object) + X(HTMLStyle, "MSStyleCSSProperties", HTMLStyle_dispex, Object) \ + X(HTMLTableCellProt, "HTMLTableCellElement", HTMLTableCellProt_dispex, HTMLElement) typedef enum { PROTO_ID_NULL = -2, diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 4a7ecf04323..2b4e24b75cc 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1178,6 +1178,8 @@ sync_test("builtin_prototypes", function() { [ "HTMLScriptElement", "HTMLElement" ], [ "HTMLSelectElement", "HTMLElement" ], [ "HTMLStyleElement", "HTMLElement" ], + [ "HTMLTableCellElement", "HTMLElement" ], + [ "HTMLTableDataCellElement", "HTMLTableCellElement" ], [ "HTMLTableElement", "HTMLElement" ], [ "HTMLTableRowElement", "HTMLElement" ], [ "HTMLTextAreaElement", "HTMLElement" ], @@ -1250,6 +1252,8 @@ sync_test("builtin_prototypes", function() { "hasChildNodes","insertBefore","isDefaultNamespace","isEqualNode","isSameNode","isSupported","lastChild","localName", "lookupNamespaceURI","lookupPrefix","namespaceURI","nextSibling","nodeName","nodeType","nodeValue","ownerDocument", "parentNode","prefix","previousSibling","removeChild","removeEventListener","replaceChild","textContent" ]; + var TableCell_props = [ "align","background","bgColor","borderColor","borderColorDark","borderColorLight","cellIndex","colSpan","height","noWrap", + "rowSpan","vAlign","width" ]; protos = [ [ "CharacterData", ["data","length","appendData"], Node_props ], @@ -1258,6 +1262,8 @@ sync_test("builtin_prototypes", function() { [ "DocumentType", ["entities","internalSubset","name","notations","publicId","systemId"], Node_props ], [ "Element", Elem_props, Node_props ], [ "HTMLElement", HtmlElem_props, Elem_props ], + [ "HTMLTableCellElement", TableCell_props, HtmlElem_props ], + [ "HTMLTableDataCellElement", [], TableCell_props ], [ "HTMLUnknownElement", ["recordset","namedRecordset"], HtmlElem_props ], [ "KeyboardEvent", ["altKey","ctrlKey","getModifierState","initKeyboardEvent","key","metaKey"], ["detail","initUIEvent","view"] ], [ "MessageEvent", ["data","initMessageEvent","origin","source"], Event_props ], From 594173d18cda27b34ffddbc43fce5f82454bf4c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:06 +0200 Subject: [PATCH 0911/2777] mshtml: Implement the relevant IHTMLStyle* interface props for HTMLCurrentStyle. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They'll use a common prototype, which is based on IHTMLStyle interface props, and will implicitly use this. The props not exposed by the prototype are not implemented and return E_UNEXPECTED, while setters are ignored (as would be if they weren't available on the object). Signed-off-by: Gabriel Ivăncescu --- Needed for next patch. --- dlls/mshtml/htmlcurstyle.c | 2839 ++++++++++++++++++++++++++++++++++++ 1 file changed, 2839 insertions(+) diff --git a/dlls/mshtml/htmlcurstyle.c b/dlls/mshtml/htmlcurstyle.c index bd816518793..ccaa2a42126 100644 --- a/dlls/mshtml/htmlcurstyle.c +++ b/dlls/mshtml/htmlcurstyle.c @@ -38,6 +38,11 @@ struct HTMLCurrentStyle { IHTMLCurrentStyle2 IHTMLCurrentStyle2_iface; IHTMLCurrentStyle3 IHTMLCurrentStyle3_iface; IHTMLCurrentStyle4 IHTMLCurrentStyle4_iface; + IHTMLStyle IHTMLStyle_iface; + IHTMLStyle2 IHTMLStyle2_iface; + IHTMLStyle3 IHTMLStyle3_iface; + IHTMLStyle5 IHTMLStyle5_iface; + IHTMLStyle6 IHTMLStyle6_iface; HTMLElement *elem; }; @@ -72,6 +77,31 @@ static inline HTMLCurrentStyle *impl_from_IHTMLCurrentStyle4(IHTMLCurrentStyle4 return CONTAINING_RECORD(iface, HTMLCurrentStyle, IHTMLCurrentStyle4_iface); } +static inline HTMLCurrentStyle *impl_from_IHTMLStyle(IHTMLStyle *iface) +{ + return CONTAINING_RECORD(iface, HTMLCurrentStyle, IHTMLStyle_iface); +} + +static inline HTMLCurrentStyle *impl_from_IHTMLStyle2(IHTMLStyle2 *iface) +{ + return CONTAINING_RECORD(iface, HTMLCurrentStyle, IHTMLStyle2_iface); +} + +static inline HTMLCurrentStyle *impl_from_IHTMLStyle3(IHTMLStyle3 *iface) +{ + return CONTAINING_RECORD(iface, HTMLCurrentStyle, IHTMLStyle3_iface); +} + +static inline HTMLCurrentStyle *impl_from_IHTMLStyle5(IHTMLStyle5 *iface) +{ + return CONTAINING_RECORD(iface, HTMLCurrentStyle, IHTMLStyle5_iface); +} + +static inline HTMLCurrentStyle *impl_from_IHTMLStyle6(IHTMLStyle6 *iface) +{ + return CONTAINING_RECORD(iface, HTMLCurrentStyle, IHTMLStyle6_iface); +} + static void *HTMLCurrentStyle_QI(CSSStyle *css_style, REFIID riid) { HTMLCurrentStyle *This = CONTAINING_RECORD(css_style, HTMLCurrentStyle, css_style); @@ -83,6 +113,16 @@ static void *HTMLCurrentStyle_QI(CSSStyle *css_style, REFIID riid) return &This->IHTMLCurrentStyle3_iface; if(IsEqualGUID(&IID_IHTMLCurrentStyle4, riid)) return &This->IHTMLCurrentStyle4_iface; + if(IsEqualGUID(&IID_IHTMLStyle, riid)) + return &This->IHTMLStyle_iface; + if(IsEqualGUID(&IID_IHTMLStyle2, riid)) + return &This->IHTMLStyle2_iface; + if(IsEqualGUID(&IID_IHTMLStyle3, riid)) + return &This->IHTMLStyle3_iface; + if(IsEqualGUID(&IID_IHTMLStyle5, riid)) + return &This->IHTMLStyle5_iface; + if(IsEqualGUID(&IID_IHTMLStyle6, riid)) + return &This->IHTMLStyle6_iface; return NULL; } @@ -1292,6 +1332,2800 @@ static const IHTMLCurrentStyle4Vtbl HTMLCurrentStyle4Vtbl = { HTMLCurrentStyle4_get_maxWidth }; +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_QueryInterface(IHTMLStyle *iface, REFIID riid, void **ppv) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + return IHTMLCurrentStyle_QueryInterface(&This->IHTMLCurrentStyle_iface, riid, ppv); +} + +static ULONG WINAPI HTMLCurrentStyle_HTMLStyle_AddRef(IHTMLStyle *iface) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + return IHTMLCurrentStyle_AddRef(&This->IHTMLCurrentStyle_iface); +} + +static ULONG WINAPI HTMLCurrentStyle_HTMLStyle_Release(IHTMLStyle *iface) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + return IHTMLCurrentStyle_Release(&This->IHTMLCurrentStyle_iface); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_GetTypeInfoCount(IHTMLStyle *iface, UINT *pctinfo) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + return IDispatchEx_GetTypeInfoCount(&This->css_style.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_GetTypeInfo(IHTMLStyle *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + return IDispatchEx_GetTypeInfo(&This->css_style.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_GetIDsOfNames(IHTMLStyle *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + return IDispatchEx_GetIDsOfNames(&This->css_style.dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_Invoke(IHTMLStyle *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + return IDispatchEx_Invoke(&This->css_style.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, + wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_fontFamily(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_fontFamily(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_fontStyle(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_fontStyle(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_fontVariant(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_fontVariant(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_fontWeight(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_fontWeight(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_fontSize(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_fontSize(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_font(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_font(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_color(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_color(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_background(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_background(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_backgroundColor(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_backgroundColor(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_backgroundImage(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_backgroundImage(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_backgroundRepeat(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_backgroundRepeat(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_backgroundAttachment(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_backgroundAttachment(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_backgroundPosition(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_backgroundPosition(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_backgroundPositionX(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_backgroundPositionX(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + TRACE("(%p)->(%p)\n", This, p); + return IHTMLCSSStyleDeclaration_get_backgroundPositionX(&This->css_style.IHTMLCSSStyleDeclaration_iface, p); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_backgroundPositionY(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_backgroundPositionY(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + TRACE("(%p)->(%p)\n", This, p); + return IHTMLCSSStyleDeclaration_get_backgroundPositionY(&This->css_style.IHTMLCSSStyleDeclaration_iface, p); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_wordSpacing(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_wordSpacing(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_letterSpacing(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_letterSpacing(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_textDecoration(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_textDecoration(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_textDecorationNone(IHTMLStyle *iface, VARIANT_BOOL v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%x)\n", This, v); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_textDecorationNone(IHTMLStyle *iface, VARIANT_BOOL *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_textDecorationUnderline(IHTMLStyle *iface, VARIANT_BOOL v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%x)\n", This, v); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_textDecorationUnderline(IHTMLStyle *iface, VARIANT_BOOL *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_textDecorationOverline(IHTMLStyle *iface, VARIANT_BOOL v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%x)\n", This, v); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_textDecorationOverline(IHTMLStyle *iface, VARIANT_BOOL *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_textDecorationLineThrough(IHTMLStyle *iface, VARIANT_BOOL v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%x)\n", This, v); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_textDecorationLineThrough(IHTMLStyle *iface, VARIANT_BOOL *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_textDecorationBlink(IHTMLStyle *iface, VARIANT_BOOL v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%x)\n", This, v); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_textDecorationBlink(IHTMLStyle *iface, VARIANT_BOOL *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_verticalAlign(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_verticalAlign(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_textTransform(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_textTransform(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_textAlign(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_textAlign(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_textIndent(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_textIndent(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_lineHeight(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_lineHeight(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_marginTop(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_marginTop(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_marginRight(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_marginRight(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_marginBottom(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_marginBottom(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_marginLeft(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_margin(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_margin(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_marginLeft(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_paddingTop(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_paddingTop(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_paddingRight(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_paddingRight(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_paddingBottom(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_paddingBottom(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_paddingLeft(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_paddingLeft(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_padding(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_padding(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_border(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_border(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderTop(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderTop(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderRight(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderRight(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderBottom(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderBottom(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderLeft(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderLeft(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderColor(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderColor(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderTopColor(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderTopColor(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderRightColor(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderRightColor(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderBottomColor(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderBottomColor(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderLeftColor(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderLeftColor(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderWidth(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderWidth(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderTopWidth(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderTopWidth(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderRightWidth(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderRightWidth(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderBottomWidth(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderBottomWidth(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderLeftWidth(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderLeftWidth(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderStyle(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderStyle(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderTopStyle(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderTopStyle(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderRightStyle(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderRightStyle(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderBottomStyle(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderBottomStyle(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_borderLeftStyle(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_borderLeftStyle(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_width(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_width(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_height(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_height(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_styleFloat(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_styleFloat(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + TRACE("(%p)->(%p)\n", This, p); + return get_current_style_property(This, STYLEID_FLOAT, p); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_clear(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_clear(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_display(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_display(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_visibility(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_visibility(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_listStyleType(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_listStyleType(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_listStylePosition(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_listStylePosition(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_listStyleImage(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_listStyleImage(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_listStyle(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_listStyle(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_whiteSpace(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_whiteSpace(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_top(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_top(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_left(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_left(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_position(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_zIndex(IHTMLStyle *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_zIndex(IHTMLStyle *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_overflow(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_overflow(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_pageBreakBefore(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_pageBreakBefore(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_pageBreakAfter(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_pageBreakAfter(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_cssText(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_cssText(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_pixelTop(IHTMLStyle *iface, LONG v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%ld)\n", This, v); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_pixelTop(IHTMLStyle *iface, LONG *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_pixelLeft(IHTMLStyle *iface, LONG v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%ld)\n", This, v); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_pixelLeft(IHTMLStyle *iface, LONG *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_pixelWidth(IHTMLStyle *iface, LONG v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->()\n", This); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_pixelWidth(IHTMLStyle *iface, LONG *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_pixelHeight(IHTMLStyle *iface, LONG v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%ld)\n", This, v); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_pixelHeight(IHTMLStyle *iface, LONG *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_posTop(IHTMLStyle *iface, float v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%f)\n", This, v); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_posTop(IHTMLStyle *iface, float *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_posLeft(IHTMLStyle *iface, float v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%f)\n", This, v); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_posLeft(IHTMLStyle *iface, float *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_posWidth(IHTMLStyle *iface, float v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%f)\n", This, v); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_posWidth(IHTMLStyle *iface, float *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_posHeight(IHTMLStyle *iface, float v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%f)\n", This, v); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_posHeight(IHTMLStyle *iface, float *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_cursor(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_cursor(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_clip(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_clip(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_put_filter(IHTMLStyle *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_get_filter(IHTMLStyle *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_setAttribute(IHTMLStyle *iface, BSTR strAttributeName, + VARIANT AttributeValue, LONG lFlags) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + FIXME("(%p)->(%s %s %08lx)\n", This, debugstr_w(strAttributeName), + debugstr_variant(&AttributeValue), lFlags); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_getAttribute(IHTMLStyle *iface, BSTR strAttributeName, + LONG lFlags, VARIANT *AttributeValue) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + FIXME("(%p)->(%s v%p %08lx)\n", This, debugstr_w(strAttributeName), AttributeValue, lFlags); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_removeAttribute(IHTMLStyle *iface, BSTR strAttributeName, + LONG lFlags, VARIANT_BOOL *pfSuccess) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + FIXME("(%p)->(%s %08lx %p)\n", This, debugstr_w(strAttributeName), lFlags, pfSuccess); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle_toString(IHTMLStyle *iface, BSTR *String) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle(iface); + WARN("(%p)->(%p)\n", This, String); + return E_UNEXPECTED; +} + +static const IHTMLStyleVtbl HTMLStyleVtbl = { + HTMLCurrentStyle_HTMLStyle_QueryInterface, + HTMLCurrentStyle_HTMLStyle_AddRef, + HTMLCurrentStyle_HTMLStyle_Release, + HTMLCurrentStyle_HTMLStyle_GetTypeInfoCount, + HTMLCurrentStyle_HTMLStyle_GetTypeInfo, + HTMLCurrentStyle_HTMLStyle_GetIDsOfNames, + HTMLCurrentStyle_HTMLStyle_Invoke, + HTMLCurrentStyle_HTMLStyle_put_fontFamily, + HTMLCurrentStyle_HTMLStyle_get_fontFamily, + HTMLCurrentStyle_HTMLStyle_put_fontStyle, + HTMLCurrentStyle_HTMLStyle_get_fontStyle, + HTMLCurrentStyle_HTMLStyle_put_fontVariant, + HTMLCurrentStyle_HTMLStyle_get_fontVariant, + HTMLCurrentStyle_HTMLStyle_put_fontWeight, + HTMLCurrentStyle_HTMLStyle_get_fontWeight, + HTMLCurrentStyle_HTMLStyle_put_fontSize, + HTMLCurrentStyle_HTMLStyle_get_fontSize, + HTMLCurrentStyle_HTMLStyle_put_font, + HTMLCurrentStyle_HTMLStyle_get_font, + HTMLCurrentStyle_HTMLStyle_put_color, + HTMLCurrentStyle_HTMLStyle_get_color, + HTMLCurrentStyle_HTMLStyle_put_background, + HTMLCurrentStyle_HTMLStyle_get_background, + HTMLCurrentStyle_HTMLStyle_put_backgroundColor, + HTMLCurrentStyle_HTMLStyle_get_backgroundColor, + HTMLCurrentStyle_HTMLStyle_put_backgroundImage, + HTMLCurrentStyle_HTMLStyle_get_backgroundImage, + HTMLCurrentStyle_HTMLStyle_put_backgroundRepeat, + HTMLCurrentStyle_HTMLStyle_get_backgroundRepeat, + HTMLCurrentStyle_HTMLStyle_put_backgroundAttachment, + HTMLCurrentStyle_HTMLStyle_get_backgroundAttachment, + HTMLCurrentStyle_HTMLStyle_put_backgroundPosition, + HTMLCurrentStyle_HTMLStyle_get_backgroundPosition, + HTMLCurrentStyle_HTMLStyle_put_backgroundPositionX, + HTMLCurrentStyle_HTMLStyle_get_backgroundPositionX, + HTMLCurrentStyle_HTMLStyle_put_backgroundPositionY, + HTMLCurrentStyle_HTMLStyle_get_backgroundPositionY, + HTMLCurrentStyle_HTMLStyle_put_wordSpacing, + HTMLCurrentStyle_HTMLStyle_get_wordSpacing, + HTMLCurrentStyle_HTMLStyle_put_letterSpacing, + HTMLCurrentStyle_HTMLStyle_get_letterSpacing, + HTMLCurrentStyle_HTMLStyle_put_textDecoration, + HTMLCurrentStyle_HTMLStyle_get_textDecoration, + HTMLCurrentStyle_HTMLStyle_put_textDecorationNone, + HTMLCurrentStyle_HTMLStyle_get_textDecorationNone, + HTMLCurrentStyle_HTMLStyle_put_textDecorationUnderline, + HTMLCurrentStyle_HTMLStyle_get_textDecorationUnderline, + HTMLCurrentStyle_HTMLStyle_put_textDecorationOverline, + HTMLCurrentStyle_HTMLStyle_get_textDecorationOverline, + HTMLCurrentStyle_HTMLStyle_put_textDecorationLineThrough, + HTMLCurrentStyle_HTMLStyle_get_textDecorationLineThrough, + HTMLCurrentStyle_HTMLStyle_put_textDecorationBlink, + HTMLCurrentStyle_HTMLStyle_get_textDecorationBlink, + HTMLCurrentStyle_HTMLStyle_put_verticalAlign, + HTMLCurrentStyle_HTMLStyle_get_verticalAlign, + HTMLCurrentStyle_HTMLStyle_put_textTransform, + HTMLCurrentStyle_HTMLStyle_get_textTransform, + HTMLCurrentStyle_HTMLStyle_put_textAlign, + HTMLCurrentStyle_HTMLStyle_get_textAlign, + HTMLCurrentStyle_HTMLStyle_put_textIndent, + HTMLCurrentStyle_HTMLStyle_get_textIndent, + HTMLCurrentStyle_HTMLStyle_put_lineHeight, + HTMLCurrentStyle_HTMLStyle_get_lineHeight, + HTMLCurrentStyle_HTMLStyle_put_marginTop, + HTMLCurrentStyle_HTMLStyle_get_marginTop, + HTMLCurrentStyle_HTMLStyle_put_marginRight, + HTMLCurrentStyle_HTMLStyle_get_marginRight, + HTMLCurrentStyle_HTMLStyle_put_marginBottom, + HTMLCurrentStyle_HTMLStyle_get_marginBottom, + HTMLCurrentStyle_HTMLStyle_put_marginLeft, + HTMLCurrentStyle_HTMLStyle_get_marginLeft, + HTMLCurrentStyle_HTMLStyle_put_margin, + HTMLCurrentStyle_HTMLStyle_get_margin, + HTMLCurrentStyle_HTMLStyle_put_paddingTop, + HTMLCurrentStyle_HTMLStyle_get_paddingTop, + HTMLCurrentStyle_HTMLStyle_put_paddingRight, + HTMLCurrentStyle_HTMLStyle_get_paddingRight, + HTMLCurrentStyle_HTMLStyle_put_paddingBottom, + HTMLCurrentStyle_HTMLStyle_get_paddingBottom, + HTMLCurrentStyle_HTMLStyle_put_paddingLeft, + HTMLCurrentStyle_HTMLStyle_get_paddingLeft, + HTMLCurrentStyle_HTMLStyle_put_padding, + HTMLCurrentStyle_HTMLStyle_get_padding, + HTMLCurrentStyle_HTMLStyle_put_border, + HTMLCurrentStyle_HTMLStyle_get_border, + HTMLCurrentStyle_HTMLStyle_put_borderTop, + HTMLCurrentStyle_HTMLStyle_get_borderTop, + HTMLCurrentStyle_HTMLStyle_put_borderRight, + HTMLCurrentStyle_HTMLStyle_get_borderRight, + HTMLCurrentStyle_HTMLStyle_put_borderBottom, + HTMLCurrentStyle_HTMLStyle_get_borderBottom, + HTMLCurrentStyle_HTMLStyle_put_borderLeft, + HTMLCurrentStyle_HTMLStyle_get_borderLeft, + HTMLCurrentStyle_HTMLStyle_put_borderColor, + HTMLCurrentStyle_HTMLStyle_get_borderColor, + HTMLCurrentStyle_HTMLStyle_put_borderTopColor, + HTMLCurrentStyle_HTMLStyle_get_borderTopColor, + HTMLCurrentStyle_HTMLStyle_put_borderRightColor, + HTMLCurrentStyle_HTMLStyle_get_borderRightColor, + HTMLCurrentStyle_HTMLStyle_put_borderBottomColor, + HTMLCurrentStyle_HTMLStyle_get_borderBottomColor, + HTMLCurrentStyle_HTMLStyle_put_borderLeftColor, + HTMLCurrentStyle_HTMLStyle_get_borderLeftColor, + HTMLCurrentStyle_HTMLStyle_put_borderWidth, + HTMLCurrentStyle_HTMLStyle_get_borderWidth, + HTMLCurrentStyle_HTMLStyle_put_borderTopWidth, + HTMLCurrentStyle_HTMLStyle_get_borderTopWidth, + HTMLCurrentStyle_HTMLStyle_put_borderRightWidth, + HTMLCurrentStyle_HTMLStyle_get_borderRightWidth, + HTMLCurrentStyle_HTMLStyle_put_borderBottomWidth, + HTMLCurrentStyle_HTMLStyle_get_borderBottomWidth, + HTMLCurrentStyle_HTMLStyle_put_borderLeftWidth, + HTMLCurrentStyle_HTMLStyle_get_borderLeftWidth, + HTMLCurrentStyle_HTMLStyle_put_borderStyle, + HTMLCurrentStyle_HTMLStyle_get_borderStyle, + HTMLCurrentStyle_HTMLStyle_put_borderTopStyle, + HTMLCurrentStyle_HTMLStyle_get_borderTopStyle, + HTMLCurrentStyle_HTMLStyle_put_borderRightStyle, + HTMLCurrentStyle_HTMLStyle_get_borderRightStyle, + HTMLCurrentStyle_HTMLStyle_put_borderBottomStyle, + HTMLCurrentStyle_HTMLStyle_get_borderBottomStyle, + HTMLCurrentStyle_HTMLStyle_put_borderLeftStyle, + HTMLCurrentStyle_HTMLStyle_get_borderLeftStyle, + HTMLCurrentStyle_HTMLStyle_put_width, + HTMLCurrentStyle_HTMLStyle_get_width, + HTMLCurrentStyle_HTMLStyle_put_height, + HTMLCurrentStyle_HTMLStyle_get_height, + HTMLCurrentStyle_HTMLStyle_put_styleFloat, + HTMLCurrentStyle_HTMLStyle_get_styleFloat, + HTMLCurrentStyle_HTMLStyle_put_clear, + HTMLCurrentStyle_HTMLStyle_get_clear, + HTMLCurrentStyle_HTMLStyle_put_display, + HTMLCurrentStyle_HTMLStyle_get_display, + HTMLCurrentStyle_HTMLStyle_put_visibility, + HTMLCurrentStyle_HTMLStyle_get_visibility, + HTMLCurrentStyle_HTMLStyle_put_listStyleType, + HTMLCurrentStyle_HTMLStyle_get_listStyleType, + HTMLCurrentStyle_HTMLStyle_put_listStylePosition, + HTMLCurrentStyle_HTMLStyle_get_listStylePosition, + HTMLCurrentStyle_HTMLStyle_put_listStyleImage, + HTMLCurrentStyle_HTMLStyle_get_listStyleImage, + HTMLCurrentStyle_HTMLStyle_put_listStyle, + HTMLCurrentStyle_HTMLStyle_get_listStyle, + HTMLCurrentStyle_HTMLStyle_put_whiteSpace, + HTMLCurrentStyle_HTMLStyle_get_whiteSpace, + HTMLCurrentStyle_HTMLStyle_put_top, + HTMLCurrentStyle_HTMLStyle_get_top, + HTMLCurrentStyle_HTMLStyle_put_left, + HTMLCurrentStyle_HTMLStyle_get_left, + HTMLCurrentStyle_HTMLStyle_get_position, + HTMLCurrentStyle_HTMLStyle_put_zIndex, + HTMLCurrentStyle_HTMLStyle_get_zIndex, + HTMLCurrentStyle_HTMLStyle_put_overflow, + HTMLCurrentStyle_HTMLStyle_get_overflow, + HTMLCurrentStyle_HTMLStyle_put_pageBreakBefore, + HTMLCurrentStyle_HTMLStyle_get_pageBreakBefore, + HTMLCurrentStyle_HTMLStyle_put_pageBreakAfter, + HTMLCurrentStyle_HTMLStyle_get_pageBreakAfter, + HTMLCurrentStyle_HTMLStyle_put_cssText, + HTMLCurrentStyle_HTMLStyle_get_cssText, + HTMLCurrentStyle_HTMLStyle_put_pixelTop, + HTMLCurrentStyle_HTMLStyle_get_pixelTop, + HTMLCurrentStyle_HTMLStyle_put_pixelLeft, + HTMLCurrentStyle_HTMLStyle_get_pixelLeft, + HTMLCurrentStyle_HTMLStyle_put_pixelWidth, + HTMLCurrentStyle_HTMLStyle_get_pixelWidth, + HTMLCurrentStyle_HTMLStyle_put_pixelHeight, + HTMLCurrentStyle_HTMLStyle_get_pixelHeight, + HTMLCurrentStyle_HTMLStyle_put_posTop, + HTMLCurrentStyle_HTMLStyle_get_posTop, + HTMLCurrentStyle_HTMLStyle_put_posLeft, + HTMLCurrentStyle_HTMLStyle_get_posLeft, + HTMLCurrentStyle_HTMLStyle_put_posWidth, + HTMLCurrentStyle_HTMLStyle_get_posWidth, + HTMLCurrentStyle_HTMLStyle_put_posHeight, + HTMLCurrentStyle_HTMLStyle_get_posHeight, + HTMLCurrentStyle_HTMLStyle_put_cursor, + HTMLCurrentStyle_HTMLStyle_get_cursor, + HTMLCurrentStyle_HTMLStyle_put_clip, + HTMLCurrentStyle_HTMLStyle_get_clip, + HTMLCurrentStyle_HTMLStyle_put_filter, + HTMLCurrentStyle_HTMLStyle_get_filter, + HTMLCurrentStyle_HTMLStyle_setAttribute, + HTMLCurrentStyle_HTMLStyle_getAttribute, + HTMLCurrentStyle_HTMLStyle_removeAttribute, + HTMLCurrentStyle_HTMLStyle_toString +}; + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_QueryInterface(IHTMLStyle2 *iface, REFIID riid, void **ppv) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + return IHTMLCurrentStyle_QueryInterface(&This->IHTMLCurrentStyle_iface, riid, ppv); +} + +static ULONG WINAPI HTMLCurrentStyle_HTMLStyle2_AddRef(IHTMLStyle2 *iface) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + return IHTMLCurrentStyle_AddRef(&This->IHTMLCurrentStyle_iface); +} + +static ULONG WINAPI HTMLCurrentStyle_HTMLStyle2_Release(IHTMLStyle2 *iface) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + return IHTMLCurrentStyle_Release(&This->IHTMLCurrentStyle_iface); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_GetTypeInfoCount(IHTMLStyle2 *iface, UINT *pctinfo) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + return IDispatchEx_GetTypeInfoCount(&This->css_style.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_GetTypeInfo(IHTMLStyle2 *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + return IDispatchEx_GetTypeInfo(&This->css_style.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_GetIDsOfNames(IHTMLStyle2 *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + return IDispatchEx_GetIDsOfNames(&This->css_style.dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_Invoke(IHTMLStyle2 *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + return IDispatchEx_Invoke(&This->css_style.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, + wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_tableLayout(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_tableLayout(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_borderCollapse(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_borderCollapse(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_direction(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_direction(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_behavior(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_behavior(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_setExpression(IHTMLStyle2 *iface, BSTR propname, BSTR expression, BSTR language) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s %s %s)\n", This, debugstr_w(propname), debugstr_w(expression), debugstr_w(language)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_getExpression(IHTMLStyle2 *iface, BSTR propname, VARIANT *expression) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s %p)\n", This, debugstr_w(propname), expression); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_removeExpression(IHTMLStyle2 *iface, BSTR propname, VARIANT_BOOL *pfSuccess) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s %p)\n", This, debugstr_w(propname), pfSuccess); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_position(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_position(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_unicodeBidi(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_unicodeBidi(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_bottom(IHTMLStyle2 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_bottom(IHTMLStyle2 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_right(IHTMLStyle2 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_right(IHTMLStyle2 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_pixelBottom(IHTMLStyle2 *iface, LONG v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%ld)\n", This, v); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_pixelBottom(IHTMLStyle2 *iface, LONG *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_pixelRight(IHTMLStyle2 *iface, LONG v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%ld)\n", This, v); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_pixelRight(IHTMLStyle2 *iface, LONG *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_posBottom(IHTMLStyle2 *iface, float v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%f)\n", This, v); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_posBottom(IHTMLStyle2 *iface, float *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_posRight(IHTMLStyle2 *iface, float v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%f)\n", This, v); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_posRight(IHTMLStyle2 *iface, float *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_imeMode(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_imeMode(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_rubyAlign(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_rubyAlign(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_rubyPosition(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_rubyPosition(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_rubyOverhang(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_rubyOverhang(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_layoutGridChar(IHTMLStyle2 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_layoutGridChar(IHTMLStyle2 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_layoutGridLine(IHTMLStyle2 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_layoutGridLine(IHTMLStyle2 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_layoutGridMode(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_layoutGridMode(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_layoutGridType(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_layoutGridType(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_layoutGrid(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_layoutGrid(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_wordBreak(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_wordBreak(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_lineBreak(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_lineBreak(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_textJustify(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_textJustify(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_textJustifyTrim(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_textJustifyTrim(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_textKashida(IHTMLStyle2 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_textKashida(IHTMLStyle2 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_textAutospace(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_textAutospace(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_overflowX(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_overflowX(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_overflowY(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_overflowY(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_put_accelerator(IHTMLStyle2 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle2_get_accelerator(IHTMLStyle2 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle2(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static const IHTMLStyle2Vtbl HTMLStyle2Vtbl = { + HTMLCurrentStyle_HTMLStyle2_QueryInterface, + HTMLCurrentStyle_HTMLStyle2_AddRef, + HTMLCurrentStyle_HTMLStyle2_Release, + HTMLCurrentStyle_HTMLStyle2_GetTypeInfoCount, + HTMLCurrentStyle_HTMLStyle2_GetTypeInfo, + HTMLCurrentStyle_HTMLStyle2_GetIDsOfNames, + HTMLCurrentStyle_HTMLStyle2_Invoke, + HTMLCurrentStyle_HTMLStyle2_put_tableLayout, + HTMLCurrentStyle_HTMLStyle2_get_tableLayout, + HTMLCurrentStyle_HTMLStyle2_put_borderCollapse, + HTMLCurrentStyle_HTMLStyle2_get_borderCollapse, + HTMLCurrentStyle_HTMLStyle2_put_direction, + HTMLCurrentStyle_HTMLStyle2_get_direction, + HTMLCurrentStyle_HTMLStyle2_put_behavior, + HTMLCurrentStyle_HTMLStyle2_get_behavior, + HTMLCurrentStyle_HTMLStyle2_setExpression, + HTMLCurrentStyle_HTMLStyle2_getExpression, + HTMLCurrentStyle_HTMLStyle2_removeExpression, + HTMLCurrentStyle_HTMLStyle2_put_position, + HTMLCurrentStyle_HTMLStyle2_get_position, + HTMLCurrentStyle_HTMLStyle2_put_unicodeBidi, + HTMLCurrentStyle_HTMLStyle2_get_unicodeBidi, + HTMLCurrentStyle_HTMLStyle2_put_bottom, + HTMLCurrentStyle_HTMLStyle2_get_bottom, + HTMLCurrentStyle_HTMLStyle2_put_right, + HTMLCurrentStyle_HTMLStyle2_get_right, + HTMLCurrentStyle_HTMLStyle2_put_pixelBottom, + HTMLCurrentStyle_HTMLStyle2_get_pixelBottom, + HTMLCurrentStyle_HTMLStyle2_put_pixelRight, + HTMLCurrentStyle_HTMLStyle2_get_pixelRight, + HTMLCurrentStyle_HTMLStyle2_put_posBottom, + HTMLCurrentStyle_HTMLStyle2_get_posBottom, + HTMLCurrentStyle_HTMLStyle2_put_posRight, + HTMLCurrentStyle_HTMLStyle2_get_posRight, + HTMLCurrentStyle_HTMLStyle2_put_imeMode, + HTMLCurrentStyle_HTMLStyle2_get_imeMode, + HTMLCurrentStyle_HTMLStyle2_put_rubyAlign, + HTMLCurrentStyle_HTMLStyle2_get_rubyAlign, + HTMLCurrentStyle_HTMLStyle2_put_rubyPosition, + HTMLCurrentStyle_HTMLStyle2_get_rubyPosition, + HTMLCurrentStyle_HTMLStyle2_put_rubyOverhang, + HTMLCurrentStyle_HTMLStyle2_get_rubyOverhang, + HTMLCurrentStyle_HTMLStyle2_put_layoutGridChar, + HTMLCurrentStyle_HTMLStyle2_get_layoutGridChar, + HTMLCurrentStyle_HTMLStyle2_put_layoutGridLine, + HTMLCurrentStyle_HTMLStyle2_get_layoutGridLine, + HTMLCurrentStyle_HTMLStyle2_put_layoutGridMode, + HTMLCurrentStyle_HTMLStyle2_get_layoutGridMode, + HTMLCurrentStyle_HTMLStyle2_put_layoutGridType, + HTMLCurrentStyle_HTMLStyle2_get_layoutGridType, + HTMLCurrentStyle_HTMLStyle2_put_layoutGrid, + HTMLCurrentStyle_HTMLStyle2_get_layoutGrid, + HTMLCurrentStyle_HTMLStyle2_put_wordBreak, + HTMLCurrentStyle_HTMLStyle2_get_wordBreak, + HTMLCurrentStyle_HTMLStyle2_put_lineBreak, + HTMLCurrentStyle_HTMLStyle2_get_lineBreak, + HTMLCurrentStyle_HTMLStyle2_put_textJustify, + HTMLCurrentStyle_HTMLStyle2_get_textJustify, + HTMLCurrentStyle_HTMLStyle2_put_textJustifyTrim, + HTMLCurrentStyle_HTMLStyle2_get_textJustifyTrim, + HTMLCurrentStyle_HTMLStyle2_put_textKashida, + HTMLCurrentStyle_HTMLStyle2_get_textKashida, + HTMLCurrentStyle_HTMLStyle2_put_textAutospace, + HTMLCurrentStyle_HTMLStyle2_get_textAutospace, + HTMLCurrentStyle_HTMLStyle2_put_overflowX, + HTMLCurrentStyle_HTMLStyle2_get_overflowX, + HTMLCurrentStyle_HTMLStyle2_put_overflowY, + HTMLCurrentStyle_HTMLStyle2_get_overflowY, + HTMLCurrentStyle_HTMLStyle2_put_accelerator, + HTMLCurrentStyle_HTMLStyle2_get_accelerator +}; + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_QueryInterface(IHTMLStyle3 *iface, REFIID riid, void **ppv) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + return IHTMLCurrentStyle_QueryInterface(&This->IHTMLCurrentStyle_iface, riid, ppv); +} + +static ULONG WINAPI HTMLCurrentStyle_HTMLStyle3_AddRef(IHTMLStyle3 *iface) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + return IHTMLCurrentStyle_AddRef(&This->IHTMLCurrentStyle_iface); +} + +static ULONG WINAPI HTMLCurrentStyle_HTMLStyle3_Release(IHTMLStyle3 *iface) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + return IHTMLCurrentStyle_Release(&This->IHTMLCurrentStyle_iface); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_GetTypeInfoCount(IHTMLStyle3 *iface, UINT *pctinfo) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + return IDispatchEx_GetTypeInfoCount(&This->css_style.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_GetTypeInfo(IHTMLStyle3 *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + return IDispatchEx_GetTypeInfo(&This->css_style.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_GetIDsOfNames(IHTMLStyle3 *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + return IDispatchEx_GetIDsOfNames(&This->css_style.dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_Invoke(IHTMLStyle3 *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + return IDispatchEx_Invoke(&This->css_style.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, + wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_put_layoutFlow(IHTMLStyle3 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_get_layoutFlow(IHTMLStyle3 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_put_zoom(IHTMLStyle3 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_get_zoom(IHTMLStyle3 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + TRACE("(%p)->(%p)\n", This, p); + return IHTMLCSSStyleDeclaration_get_zoom(&This->css_style.IHTMLCSSStyleDeclaration_iface, p); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_put_wordWrap(IHTMLStyle3 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_get_wordWrap(IHTMLStyle3 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_put_textUnderlinePosition(IHTMLStyle3 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_get_textUnderlinePosition(IHTMLStyle3 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_put_scrollbarBaseColor(IHTMLStyle3 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_get_scrollbarBaseColor(IHTMLStyle3 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_put_scrollbarFaceColor(IHTMLStyle3 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_get_scrollbarFaceColor(IHTMLStyle3 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_put_scrollbar3dLightColor(IHTMLStyle3 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_get_scrollbar3dLightColor(IHTMLStyle3 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_put_scrollbarShadowColor(IHTMLStyle3 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_get_scrollbarShadowColor(IHTMLStyle3 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_put_scrollbarHighlightColor(IHTMLStyle3 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_get_scrollbarHighlightColor(IHTMLStyle3 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_put_scrollbarDarkShadowColor(IHTMLStyle3 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_get_scrollbarDarkShadowColor(IHTMLStyle3 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_put_scrollbarArrowColor(IHTMLStyle3 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_get_scrollbarArrowColor(IHTMLStyle3 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_put_scrollbarTrackColor(IHTMLStyle3 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_get_scrollbarTrackColor(IHTMLStyle3 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_put_writingMode(IHTMLStyle3 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_get_writingMode(IHTMLStyle3 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_put_textAlignLast(IHTMLStyle3 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_get_textAlignLast(IHTMLStyle3 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_put_textKashidaSpace(IHTMLStyle3 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle3_get_textKashidaSpace(IHTMLStyle3 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle3(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static const IHTMLStyle3Vtbl HTMLStyle3Vtbl = { + HTMLCurrentStyle_HTMLStyle3_QueryInterface, + HTMLCurrentStyle_HTMLStyle3_AddRef, + HTMLCurrentStyle_HTMLStyle3_Release, + HTMLCurrentStyle_HTMLStyle3_GetTypeInfoCount, + HTMLCurrentStyle_HTMLStyle3_GetTypeInfo, + HTMLCurrentStyle_HTMLStyle3_GetIDsOfNames, + HTMLCurrentStyle_HTMLStyle3_Invoke, + HTMLCurrentStyle_HTMLStyle3_put_layoutFlow, + HTMLCurrentStyle_HTMLStyle3_get_layoutFlow, + HTMLCurrentStyle_HTMLStyle3_put_zoom, + HTMLCurrentStyle_HTMLStyle3_get_zoom, + HTMLCurrentStyle_HTMLStyle3_put_wordWrap, + HTMLCurrentStyle_HTMLStyle3_get_wordWrap, + HTMLCurrentStyle_HTMLStyle3_put_textUnderlinePosition, + HTMLCurrentStyle_HTMLStyle3_get_textUnderlinePosition, + HTMLCurrentStyle_HTMLStyle3_put_scrollbarBaseColor, + HTMLCurrentStyle_HTMLStyle3_get_scrollbarBaseColor, + HTMLCurrentStyle_HTMLStyle3_put_scrollbarFaceColor, + HTMLCurrentStyle_HTMLStyle3_get_scrollbarFaceColor, + HTMLCurrentStyle_HTMLStyle3_put_scrollbar3dLightColor, + HTMLCurrentStyle_HTMLStyle3_get_scrollbar3dLightColor, + HTMLCurrentStyle_HTMLStyle3_put_scrollbarShadowColor, + HTMLCurrentStyle_HTMLStyle3_get_scrollbarShadowColor, + HTMLCurrentStyle_HTMLStyle3_put_scrollbarHighlightColor, + HTMLCurrentStyle_HTMLStyle3_get_scrollbarHighlightColor, + HTMLCurrentStyle_HTMLStyle3_put_scrollbarDarkShadowColor, + HTMLCurrentStyle_HTMLStyle3_get_scrollbarDarkShadowColor, + HTMLCurrentStyle_HTMLStyle3_put_scrollbarArrowColor, + HTMLCurrentStyle_HTMLStyle3_get_scrollbarArrowColor, + HTMLCurrentStyle_HTMLStyle3_put_scrollbarTrackColor, + HTMLCurrentStyle_HTMLStyle3_get_scrollbarTrackColor, + HTMLCurrentStyle_HTMLStyle3_put_writingMode, + HTMLCurrentStyle_HTMLStyle3_get_writingMode, + HTMLCurrentStyle_HTMLStyle3_put_textAlignLast, + HTMLCurrentStyle_HTMLStyle3_get_textAlignLast, + HTMLCurrentStyle_HTMLStyle3_put_textKashidaSpace, + HTMLCurrentStyle_HTMLStyle3_get_textKashidaSpace +}; + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle5_QueryInterface(IHTMLStyle5 *iface, REFIID riid, void **ppv) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle5(iface); + return IHTMLCurrentStyle_QueryInterface(&This->IHTMLCurrentStyle_iface, riid, ppv); +} + +static ULONG WINAPI HTMLCurrentStyle_HTMLStyle5_AddRef(IHTMLStyle5 *iface) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle5(iface); + return IHTMLCurrentStyle_AddRef(&This->IHTMLCurrentStyle_iface); +} + +static ULONG WINAPI HTMLCurrentStyle_HTMLStyle5_Release(IHTMLStyle5 *iface) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle5(iface); + return IHTMLCurrentStyle_Release(&This->IHTMLCurrentStyle_iface); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle5_GetTypeInfoCount(IHTMLStyle5 *iface, UINT *pctinfo) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle5(iface); + return IDispatchEx_GetTypeInfoCount(&This->css_style.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle5_GetTypeInfo(IHTMLStyle5 *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle5(iface); + return IDispatchEx_GetTypeInfo(&This->css_style.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle5_GetIDsOfNames(IHTMLStyle5 *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle5(iface); + return IDispatchEx_GetIDsOfNames(&This->css_style.dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle5_Invoke(IHTMLStyle5 *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle5(iface); + return IDispatchEx_Invoke(&This->css_style.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, + wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle5_put_msInterpolationMode(IHTMLStyle5 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle5(iface); + TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle5_get_msInterpolationMode(IHTMLStyle5 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle5(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle5_put_maxHeight(IHTMLStyle5 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle5(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle5_get_maxHeight(IHTMLStyle5 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle5(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(p)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle5_put_minWidth(IHTMLStyle5 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle5(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle5_get_minWidth(IHTMLStyle5 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle5(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle5_put_maxWidth(IHTMLStyle5 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle5(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle5_get_maxWidth(IHTMLStyle5 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle5(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static const IHTMLStyle5Vtbl HTMLStyle5Vtbl = { + HTMLCurrentStyle_HTMLStyle5_QueryInterface, + HTMLCurrentStyle_HTMLStyle5_AddRef, + HTMLCurrentStyle_HTMLStyle5_Release, + HTMLCurrentStyle_HTMLStyle5_GetTypeInfoCount, + HTMLCurrentStyle_HTMLStyle5_GetTypeInfo, + HTMLCurrentStyle_HTMLStyle5_GetIDsOfNames, + HTMLCurrentStyle_HTMLStyle5_Invoke, + HTMLCurrentStyle_HTMLStyle5_put_msInterpolationMode, + HTMLCurrentStyle_HTMLStyle5_get_msInterpolationMode, + HTMLCurrentStyle_HTMLStyle5_put_maxHeight, + HTMLCurrentStyle_HTMLStyle5_get_maxHeight, + HTMLCurrentStyle_HTMLStyle5_put_minWidth, + HTMLCurrentStyle_HTMLStyle5_get_minWidth, + HTMLCurrentStyle_HTMLStyle5_put_maxWidth, + HTMLCurrentStyle_HTMLStyle5_get_maxWidth +}; + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_QueryInterface(IHTMLStyle6 *iface, REFIID riid, void **ppv) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + return IHTMLCurrentStyle_QueryInterface(&This->IHTMLCurrentStyle_iface, riid, ppv); +} + +static ULONG WINAPI HTMLCurrentStyle_HTMLStyle6_AddRef(IHTMLStyle6 *iface) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + return IHTMLCurrentStyle_AddRef(&This->IHTMLCurrentStyle_iface); +} + +static ULONG WINAPI HTMLCurrentStyle_HTMLStyle6_Release(IHTMLStyle6 *iface) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + return IHTMLCurrentStyle_Release(&This->IHTMLCurrentStyle_iface); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_GetTypeInfoCount(IHTMLStyle6 *iface, UINT *pctinfo) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + return IDispatchEx_GetTypeInfoCount(&This->css_style.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_GetTypeInfo(IHTMLStyle6 *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + return IDispatchEx_GetTypeInfo(&This->css_style.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_GetIDsOfNames(IHTMLStyle6 *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + return IDispatchEx_GetIDsOfNames(&This->css_style.dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_Invoke(IHTMLStyle6 *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + return IDispatchEx_Invoke(&This->css_style.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, + wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_put_content(IHTMLStyle6 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_get_content(IHTMLStyle6 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_put_contentSide(IHTMLStyle6 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_get_contentSide(IHTMLStyle6 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_put_counterIncrement(IHTMLStyle6 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_get_counterIncrement(IHTMLStyle6 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_put_counterReset(IHTMLStyle6 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_get_counterReset(IHTMLStyle6 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_put_outline(IHTMLStyle6 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_get_outline(IHTMLStyle6 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_put_outlineWidth(IHTMLStyle6 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_get_outlineWidth(IHTMLStyle6 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_put_outlineStyle(IHTMLStyle6 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_get_outlineStyle(IHTMLStyle6 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_put_outlineColor(IHTMLStyle6 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_get_outlineColor(IHTMLStyle6 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_put_boxSizing(IHTMLStyle6 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_get_boxSizing(IHTMLStyle6 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_put_borderSpacing(IHTMLStyle6 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_get_borderSpacing(IHTMLStyle6 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_put_orphans(IHTMLStyle6 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_get_orphans(IHTMLStyle6 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_put_windows(IHTMLStyle6 *iface, VARIANT v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%s)\n", This, debugstr_variant(&v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_get_windows(IHTMLStyle6 *iface, VARIANT *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_put_pageBreakInside(IHTMLStyle6 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_get_pageBreakInside(IHTMLStyle6 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_put_emptyCells(IHTMLStyle6 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_get_emptyCells(IHTMLStyle6 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_put_msBlockProgression(IHTMLStyle6 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + return E_FAIL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_get_msBlockProgression(IHTMLStyle6 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_put_quotes(IHTMLStyle6 *iface, BSTR v) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%s)\n", This, debugstr_w(v)); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLCurrentStyle_HTMLStyle6_get_quotes(IHTMLStyle6 *iface, BSTR *p) +{ + HTMLCurrentStyle *This = impl_from_IHTMLStyle6(iface); + WARN("(%p)->(%p)\n", This, p); + return E_UNEXPECTED; +} + +static const IHTMLStyle6Vtbl HTMLStyle6Vtbl = { + HTMLCurrentStyle_HTMLStyle6_QueryInterface, + HTMLCurrentStyle_HTMLStyle6_AddRef, + HTMLCurrentStyle_HTMLStyle6_Release, + HTMLCurrentStyle_HTMLStyle6_GetTypeInfoCount, + HTMLCurrentStyle_HTMLStyle6_GetTypeInfo, + HTMLCurrentStyle_HTMLStyle6_GetIDsOfNames, + HTMLCurrentStyle_HTMLStyle6_Invoke, + HTMLCurrentStyle_HTMLStyle6_put_content, + HTMLCurrentStyle_HTMLStyle6_get_content, + HTMLCurrentStyle_HTMLStyle6_put_contentSide, + HTMLCurrentStyle_HTMLStyle6_get_contentSide, + HTMLCurrentStyle_HTMLStyle6_put_counterIncrement, + HTMLCurrentStyle_HTMLStyle6_get_counterIncrement, + HTMLCurrentStyle_HTMLStyle6_put_counterReset, + HTMLCurrentStyle_HTMLStyle6_get_counterReset, + HTMLCurrentStyle_HTMLStyle6_put_outline, + HTMLCurrentStyle_HTMLStyle6_get_outline, + HTMLCurrentStyle_HTMLStyle6_put_outlineWidth, + HTMLCurrentStyle_HTMLStyle6_get_outlineWidth, + HTMLCurrentStyle_HTMLStyle6_put_outlineStyle, + HTMLCurrentStyle_HTMLStyle6_get_outlineStyle, + HTMLCurrentStyle_HTMLStyle6_put_outlineColor, + HTMLCurrentStyle_HTMLStyle6_get_outlineColor, + HTMLCurrentStyle_HTMLStyle6_put_boxSizing, + HTMLCurrentStyle_HTMLStyle6_get_boxSizing, + HTMLCurrentStyle_HTMLStyle6_put_borderSpacing, + HTMLCurrentStyle_HTMLStyle6_get_borderSpacing, + HTMLCurrentStyle_HTMLStyle6_put_orphans, + HTMLCurrentStyle_HTMLStyle6_get_orphans, + HTMLCurrentStyle_HTMLStyle6_put_windows, + HTMLCurrentStyle_HTMLStyle6_get_windows, + HTMLCurrentStyle_HTMLStyle6_put_pageBreakInside, + HTMLCurrentStyle_HTMLStyle6_get_pageBreakInside, + HTMLCurrentStyle_HTMLStyle6_put_emptyCells, + HTMLCurrentStyle_HTMLStyle6_get_emptyCells, + HTMLCurrentStyle_HTMLStyle6_put_msBlockProgression, + HTMLCurrentStyle_HTMLStyle6_get_msBlockProgression, + HTMLCurrentStyle_HTMLStyle6_put_quotes, + HTMLCurrentStyle_HTMLStyle6_get_quotes +}; + static const tid_t HTMLCurrentStyle_iface_tids[] = { IHTMLCurrentStyle_tid, IHTMLCurrentStyle2_tid, @@ -1356,6 +4190,11 @@ HRESULT HTMLCurrentStyle_Create(HTMLElement *elem, IHTMLCurrentStyle **p) ret->IHTMLCurrentStyle2_iface.lpVtbl = &HTMLCurrentStyle2Vtbl; ret->IHTMLCurrentStyle3_iface.lpVtbl = &HTMLCurrentStyle3Vtbl; ret->IHTMLCurrentStyle4_iface.lpVtbl = &HTMLCurrentStyle4Vtbl; + ret->IHTMLStyle_iface.lpVtbl = &HTMLStyleVtbl; + ret->IHTMLStyle2_iface.lpVtbl = &HTMLStyle2Vtbl; + ret->IHTMLStyle3_iface.lpVtbl = &HTMLStyle3Vtbl; + ret->IHTMLStyle5_iface.lpVtbl = &HTMLStyle5Vtbl; + ret->IHTMLStyle6_iface.lpVtbl = &HTMLStyle6Vtbl; init_css_style(&ret->css_style, nsstyle, HTMLCurrentStyle_QI, &HTMLCurrentStyle_dispex, get_inner_window(elem->node.doc), dispex_compat_mode(&elem->node.event_target.dispex)); From 3035dfa0c92829835358a43a077c042a7d7450cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:06 +0200 Subject: [PATCH 0912/2777] mshtml: Introduce MSCSSPropertiesPrototype and set it as prototype of CurrentStyle and Style prototypes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The interface is abstract, and is only used in prototype chains (and constructor), so we needn't implement any of it. However, MSCSSPropertiesPrototype inherits from CSSStyleDeclarationPrototype. Some of the props are now exposed in MSCSSPropertiesPrototype instead, and none of styles in the style table are exposed in either the HTMLCurrentStyle or HTMLStyle prototypes; they are exposed further up the chain, so get_static_dispid logic has been moved accordingly. Signed-off-by: Gabriel Ivăncescu --- Without all the above fixes, some of the existing tests would fail... --- dlls/mshtml/htmlstyle.c | 172 ++++++++++++++++++++++++++++-- dlls/mshtml/mshtml_private.h | 5 +- dlls/mshtml/tests/documentmode.js | 22 ++++ 3 files changed, 189 insertions(+), 10 deletions(-) diff --git a/dlls/mshtml/htmlstyle.c b/dlls/mshtml/htmlstyle.c index df2b2e6ef27..438c49e2603 100644 --- a/dlls/mshtml/htmlstyle.c +++ b/dlls/mshtml/htmlstyle.c @@ -109,6 +109,7 @@ static const WCHAR *overflow_values[] = { #define ATTR_REMOVE_COMMA 0x0010 #define ATTR_NO_NULL 0x0020 #define ATTR_COMPAT_IE10 0x0040 +#define ATTR_IN_CSSPROPERTIES 0x0080 typedef struct { const WCHAR *name; @@ -167,13 +168,13 @@ static const style_tbl_entry_t style_tbl[] = { L"background-position-x", DISPID_IHTMLCSSSTYLEDECLARATION_BACKGROUNDPOSITIONX, DISPID_A_BACKGROUNDPOSX, - ATTR_FIX_PX + ATTR_FIX_PX | ATTR_IN_CSSPROPERTIES }, { L"background-position-y", DISPID_IHTMLCSSSTYLEDECLARATION_BACKGROUNDPOSITIONY, DISPID_A_BACKGROUNDPOSY, - ATTR_FIX_PX + ATTR_FIX_PX | ATTR_IN_CSSPROPERTIES }, { L"background-repeat", @@ -9985,14 +9986,16 @@ static HRESULT CSSStyle_get_static_dispid(compat_mode_t compat_mode, BSTR name, { const style_tbl_entry_t *style_entry; + /* Found in prototypes */ + if(compat_mode >= COMPAT_MODE_IE9) + return DISP_E_UNKNOWNNAME; + style_entry = lookup_style_tbl_compat_mode(compat_mode, name); if(style_entry) { - DISPID id = compat_mode >= COMPAT_MODE_IE9 - ? style_entry->dispid : style_entry->compat_dispid; - if(id == DISPID_UNKNOWN) + if(style_entry->compat_dispid == DISPID_UNKNOWN) return DISP_E_UNKNOWNNAME; - *dispid = id; + *dispid = style_entry->compat_dispid; return S_OK; } @@ -10120,13 +10123,166 @@ HRESULT HTMLStyle_Create(HTMLElement *elem, HTMLStyle **ret) return S_OK; } +/* dummy dispex used only for MSCSSPropertiesPrototype in prototype chain */ +static HRESULT HTMLCSSProperties_get_static_dispid(compat_mode_t compat_mode, BSTR name, DWORD flags, DISPID *dispid) +{ + const style_tbl_entry_t *style_entry; + + style_entry = lookup_style_tbl_compat_mode(compat_mode, name); + if(style_entry) { + if(style_entry->dispid == DISPID_UNKNOWN || !(style_entry->flags & ATTR_IN_CSSPROPERTIES)) + return DISP_E_UNKNOWNNAME; + + *dispid = style_entry->dispid; + return S_OK; + } + + return DISP_E_UNKNOWNNAME; +} + +static void HTMLCSSProperties_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t style_hooks[] = { + {DISPID_IHTMLSTYLE_TEXTDECORATIONNONE}, + {DISPID_IHTMLSTYLE_TEXTDECORATIONUNDERLINE}, + {DISPID_IHTMLSTYLE_TEXTDECORATIONOVERLINE}, + {DISPID_IHTMLSTYLE_TEXTDECORATIONLINETHROUGH}, + {DISPID_IHTMLSTYLE_TEXTDECORATIONBLINK}, + {DISPID_IHTMLSTYLE_PIXELTOP}, + {DISPID_IHTMLSTYLE_PIXELLEFT}, + {DISPID_IHTMLSTYLE_PIXELWIDTH}, + {DISPID_IHTMLSTYLE_PIXELHEIGHT}, + {DISPID_IHTMLSTYLE_POSTOP}, + {DISPID_IHTMLSTYLE_POSLEFT}, + {DISPID_IHTMLSTYLE_POSWIDTH}, + {DISPID_IHTMLSTYLE_POSHEIGHT}, + {DISPID_IHTMLSTYLE_TOSTRING}, + {DISPID_UNKNOWN} + }; + static const dispex_hook_t style2_hooks[] = { + {DISPID_IHTMLSTYLE2_SETEXPRESSION}, + {DISPID_IHTMLSTYLE2_GETEXPRESSION}, + {DISPID_IHTMLSTYLE2_REMOVEEXPRESSION}, + {DISPID_IHTMLSTYLE2_PIXELBOTTOM}, + {DISPID_IHTMLSTYLE2_PIXELRIGHT}, + {DISPID_IHTMLSTYLE2_POSBOTTOM}, + {DISPID_IHTMLSTYLE2_POSRIGHT}, + {DISPID_UNKNOWN} + }; + + dispex_info_add_interface(info, IHTMLStyle6_tid, NULL); + dispex_info_add_interface(info, IHTMLStyle5_tid, NULL); + dispex_info_add_interface(info, IHTMLStyle3_tid, NULL); + dispex_info_add_interface(info, IHTMLStyle2_tid, style2_hooks); + dispex_info_add_interface(info, IHTMLStyle_tid, style_hooks); +} + +const dispex_static_data_vtbl_t HTMLCSSProperties_dispex_vtbl = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + HTMLCSSProperties_get_static_dispid +}; + +dispex_static_data_t HTMLCSSProperties_dispex = { + L"MSCSSProperties", + &HTMLCSSProperties_dispex_vtbl, + PROTO_ID_HTMLCSSProperties, + NULL_tid, + no_iface_tids, + HTMLCSSProperties_init_dispex_info +}; + +static HRESULT HTMLW3CComputedStyle_get_static_dispid(compat_mode_t compat_mode, BSTR name, DWORD flags, DISPID *dispid) +{ + const style_tbl_entry_t *style_entry; + DISPID id; + + style_entry = lookup_style_tbl_compat_mode(compat_mode, name); + if(style_entry) { + if(compat_mode < COMPAT_MODE_IE9) + id = style_entry->compat_dispid; + else { + if(style_entry->flags & ATTR_IN_CSSPROPERTIES) + return DISP_E_UNKNOWNNAME; + id = style_entry->dispid; + } + if(id == DISPID_UNKNOWN) + return DISP_E_UNKNOWNNAME; + + *dispid = id; + return S_OK; + } + + return DISP_E_UNKNOWNNAME; +} + +void HTMLW3CComputedStyle_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + /* don't expose props shared with children prototypes */ + static const dispex_hook_t styledecl_hooks[] = { + {DISPID_IHTMLCSSSTYLEDECLARATION_BACKGROUNDPOSITIONX}, + {DISPID_IHTMLCSSSTYLEDECLARATION_BACKGROUNDPOSITIONY}, + {DISPID_IHTMLCSSSTYLEDECLARATION_STYLEFLOAT}, + {DISPID_IHTMLCSSSTYLEDECLARATION_IMEMODE}, + {DISPID_IHTMLCSSSTYLEDECLARATION_LAYOUTGRIDCHAR}, + {DISPID_IHTMLCSSSTYLEDECLARATION_LAYOUTGRIDLINE}, + {DISPID_IHTMLCSSSTYLEDECLARATION_LAYOUTGRIDMODE}, + {DISPID_IHTMLCSSSTYLEDECLARATION_LAYOUTGRIDTYPE}, + {DISPID_IHTMLCSSSTYLEDECLARATION_LAYOUTGRID}, + {DISPID_IHTMLCSSSTYLEDECLARATION_TEXTAUTOSPACE}, + {DISPID_IHTMLCSSSTYLEDECLARATION_LINEBREAK}, + {DISPID_IHTMLCSSSTYLEDECLARATION_TEXTJUSTIFYTRIM}, + {DISPID_IHTMLCSSSTYLEDECLARATION_TEXTKASHIDA}, + {DISPID_IHTMLCSSSTYLEDECLARATION_ACCELERATOR}, + {DISPID_IHTMLCSSSTYLEDECLARATION_LAYOUTFLOW}, + {DISPID_IHTMLCSSSTYLEDECLARATION_ZOOM}, + {DISPID_IHTMLCSSSTYLEDECLARATION_SCROLLBARBASECOLOR}, + {DISPID_IHTMLCSSSTYLEDECLARATION_SCROLLBARFACECOLOR}, + {DISPID_IHTMLCSSSTYLEDECLARATION_SCROLLBAR3DLIGHTCOLOR}, + {DISPID_IHTMLCSSSTYLEDECLARATION_SCROLLBARSHADOWCOLOR}, + {DISPID_IHTMLCSSSTYLEDECLARATION_SCROLLBARHIGHLIGHTCOLOR}, + {DISPID_IHTMLCSSSTYLEDECLARATION_SCROLLBARDARKSHADOWCOLOR}, + {DISPID_IHTMLCSSSTYLEDECLARATION_SCROLLBARARROWCOLOR}, + {DISPID_IHTMLCSSSTYLEDECLARATION_SCROLLBARTRACKCOLOR}, + {DISPID_IHTMLCSSSTYLEDECLARATION_WRITINGMODE}, + {DISPID_IHTMLCSSSTYLEDECLARATION_TEXTKASHIDASPACE}, + {DISPID_IHTMLCSSSTYLEDECLARATION_MSINTERPOLATIONMODE}, + {DISPID_IHTMLCSSSTYLEDECLARATION_MSBLOCKPROGRESSION}, + {DISPID_IHTMLCSSSTYLEDECLARATION_CLIPTOP}, + {DISPID_IHTMLCSSSTYLEDECLARATION_CLIPRIGHT}, + {DISPID_IHTMLCSSSTYLEDECLARATION_CLIPBOTTOM}, + {DISPID_IHTMLCSSSTYLEDECLARATION_CLIPLEFT}, + {DISPID_UNKNOWN} + }; + if(mode >= COMPAT_MODE_IE9) + dispex_info_add_interface(info, IHTMLCSSStyleDeclaration_tid, styledecl_hooks); + if(mode >= COMPAT_MODE_IE10) + dispex_info_add_interface(info, IHTMLCSSStyleDeclaration2_tid, NULL); +} + +const dispex_static_data_vtbl_t HTMLW3CComputedStyle_dispex_vtbl = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + HTMLW3CComputedStyle_get_static_dispid +}; + dispex_static_data_t HTMLW3CComputedStyle_dispex = { L"CSSStyleDeclaration", - &CSSStyle_dispex_vtbl, + &HTMLW3CComputedStyle_dispex_vtbl, PROTO_ID_HTMLW3CComputedStyle, DispHTMLW3CComputedStyle_tid, no_iface_tids, - CSSStyle_init_dispex_info + HTMLW3CComputedStyle_init_dispex_info }; HRESULT create_computed_style(nsIDOMCSSStyleDeclaration *nsstyle, HTMLInnerWindow *window, diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 7e4bcac824a..d79b220c5f1 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -424,7 +424,7 @@ PRIVATE_TID_LIST X(HTMLStorage, "Storage", HTMLStorage_dispex, Object) \ X(HTMLTextRange, "TextRange", HTMLTxtRange_dispex, Object) \ X(HTMLXMLHttpRequest, "XMLHttpRequest", HTMLXMLHttpRequest_dispex, Object) \ - X(HTMLCurrentStyle, "MSCurrentStyleCSSProperties", HTMLCurrentStyle_dispex, Object) \ + X(HTMLCurrentStyle, "MSCurrentStyleCSSProperties", HTMLCurrentStyle_dispex, HTMLCSSProperties) \ X(HTMLW3CComputedStyle, "CSSStyleDeclaration", HTMLW3CComputedStyle_dispex, Object) \ X(HTMLStyleSheet, "CSSStyleSheet", HTMLStyleSheet_dispex, Object) \ X(HTMLStyleSheetRule, "CSSStyleRule", HTMLStyleSheetRule_dispex, Object) \ @@ -479,7 +479,8 @@ PRIVATE_TID_LIST X(HTMLPerformance, "Performance", HTMLPerformance_dispex, Object) \ X(HTMLPerformanceNavigation, "PerformanceNavigation", HTMLPerformanceNavigation_dispex, Object) \ X(HTMLPerformanceTiming, "PerformanceTiming", HTMLPerformanceTiming_dispex, Object) \ - X(HTMLStyle, "MSStyleCSSProperties", HTMLStyle_dispex, Object) \ + X(HTMLCSSProperties, "MSCSSProperties", HTMLCSSProperties_dispex, HTMLW3CComputedStyle) \ + X(HTMLStyle, "MSStyleCSSProperties", HTMLStyle_dispex, HTMLCSSProperties) \ X(HTMLTableCellProt, "HTMLTableCellElement", HTMLTableCellProt_dispex, HTMLElement) typedef enum { diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 2b4e24b75cc..a281785b1ef 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1191,12 +1191,15 @@ sync_test("builtin_prototypes", function() { [ "MessageEvent", "Event" ], [ "MimeTypeArray", "Object" ], [ "MouseEvent", "UIEvent" ], + [ "MSCSSProperties", "CSSStyleDeclaration" ], [ "MSCSSRuleList", "Object" ], + [ "MSCurrentStyleCSSProperties", "MSCSSProperties" ], [ "MSEventObj", "Object" ], [ "MSMimeTypesCollection", "Object" ], [ "MSNamespaceInfoCollection", "Object" ], [ "MSPluginsCollection", "Object" ], [ "MSSelection", "Object" ], + [ "MSStyleCSSProperties", "MSCSSProperties" ], [ "NamedNodeMap", "Object" ], [ "Navigator", "Object" ], [ "Node", "Object" ], @@ -1227,6 +1230,11 @@ sync_test("builtin_prototypes", function() { ok(a === b, "getPrototypeOf(" + protos[i][0] + ".prototype) = " + a); } + var CSS_props = [ "accelerator","backgroundPositionX","backgroundPositionY","getAttribute","imeMode","layoutFlow","layoutGrid","layoutGridChar", + "layoutGridLine","layoutGridMode","layoutGridType","lineBreak","msBlockProgression","msInterpolationMode","removeAttribute", + "scrollbar3dLightColor","scrollbarArrowColor","scrollbarBaseColor","scrollbarDarkShadowColor","scrollbarFaceColor", + "scrollbarHighlightColor","scrollbarShadowColor","scrollbarTrackColor","setAttribute","styleFloat","textAutospace", + "textJustifyTrim","textKashida","textKashidaSpace","writingMode","zoom" ]; var Elem_props = [ "clientHeight","clientLeft","clientTop","clientWidth","firstElementChild","getAttribute","getAttributeNode","getAttributeNodeNS", "getAttributeNS","getBoundingClientRect","getClientRects","getElementsByTagName","getElementsByTagNameNS","hasAttribute", "hasAttributeNS","lastElementChild","msMatchesSelector","nextElementSibling","previousElementSibling","querySelector", @@ -1268,6 +1276,9 @@ sync_test("builtin_prototypes", function() { [ "KeyboardEvent", ["altKey","ctrlKey","getModifierState","initKeyboardEvent","key","metaKey"], ["detail","initUIEvent","view"] ], [ "MessageEvent", ["data","initMessageEvent","origin","source"], Event_props ], [ "MouseEvent", ["button","clientX","initMouseEvent","offsetY","pageX","shiftKey","x","y"], ["detail","initUIEvent","view"] ], + [ "MSCSSProperties", CSS_props, ["background","border","clip","fontWeight","listStyle","quotes","setProperty","zIndex"] ], + [ "MSCurrentStyleCSSProperties", ["blockDirection","clipBottom","clipLeft","clipRight","clipTop","hasLayout"], CSS_props ], + [ "MSStyleCSSProperties", ["pixelTop","pixelWidth","posHeight","posLeft","textDecorationBlink","textDecorationNone"], CSS_props ], [ "ProgressEvent", ["initProgressEvent","lengthComputable","loaded","total"], Event_props ], [ "StorageEvent", ["initStorageEvent","key","newValue","oldValue","storageArea"], Event_props ], [ "Text", ["splitText"], ["data","length","appendData","deleteData","insertData","replaceData","substringData"] ], @@ -1545,10 +1556,21 @@ sync_test("style_props", function() { test_exposed("float", true); test_exposed("css-float", false); test_exposed("style-float", false); + test_exposed("styleFloat", true); test_exposed("setProperty", v >= 9); test_exposed("removeProperty", v >= 9); test_exposed("background-clip", v >= 9); test_exposed("transform", v >= 10); + test_exposed("zoom", true); + + try { + style.styleFloat = "left"; + ok(false, "expected exception setting styleFloat"); + }catch(ex) {} + try { + style.zoom = "1.0"; + ok(false, "expected exception setting zoom"); + }catch(ex) {} if(window.getComputedStyle) { style = window.getComputedStyle(document.body); From 95a9002033c693c9ffdd2d14d1f9e23f8272e4ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:06 +0200 Subject: [PATCH 0913/2777] mshtml: Introduce StyleSheetPrototype and set it as CSSStyleSheetPrototype's prototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The interface is abstract, and is only used in prototype chains (and constructor), so we needn't implement any of it. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlstylesheet.c | 38 +++++++++++++++++++++++++++++++ dlls/mshtml/mshtml_private.h | 3 ++- dlls/mshtml/tests/documentmode.js | 3 +++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/htmlstylesheet.c b/dlls/mshtml/htmlstylesheet.c index c13d679d4f6..e19b32d2312 100644 --- a/dlls/mshtml/htmlstylesheet.c +++ b/dlls/mshtml/htmlstylesheet.c @@ -24,6 +24,7 @@ #include "winbase.h" #include "winuser.h" #include "ole2.h" +#include "mshtmdid.h" #include "wine/debug.h" @@ -1524,3 +1525,40 @@ HRESULT create_style_sheet(nsIDOMStyleSheet *nsstylesheet, HTMLDocumentNode *doc *ret = &style_sheet->IHTMLStyleSheet_iface; return S_OK; } + +/* dummy dispex used only for StyleSheet in prototype chain */ +static void StyleSheet_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t stylesheet_hooks[] = { + {DISPID_IHTMLSTYLESHEET_OWNINGELEMENT}, + {DISPID_IHTMLSTYLESHEET_READONLY}, + {DISPID_IHTMLSTYLESHEET_IMPORTS}, + {DISPID_IHTMLSTYLESHEET_ID}, + {DISPID_IHTMLSTYLESHEET_ADDIMPORT}, + {DISPID_IHTMLSTYLESHEET_ADDRULE}, + {DISPID_IHTMLSTYLESHEET_REMOVEIMPORT}, + {DISPID_IHTMLSTYLESHEET_REMOVERULE}, + {DISPID_IHTMLSTYLESHEET_CSSTEXT}, + {DISPID_IHTMLSTYLESHEET_RULES}, + {DISPID_UNKNOWN} + }; + static const dispex_hook_t stylesheet4_hooks[] = { + {DISPID_IHTMLSTYLESHEET4_OWNERRULE}, + {DISPID_IHTMLSTYLESHEET4_CSSRULES}, + {DISPID_IHTMLSTYLESHEET4_INSERTRULE}, + {DISPID_IHTMLSTYLESHEET4_DELETERULE}, + {DISPID_UNKNOWN} + }; + + dispex_info_add_interface(info, IHTMLStyleSheet4_tid, stylesheet4_hooks); + dispex_info_add_interface(info, IHTMLStyleSheet_tid, stylesheet_hooks); +} + +dispex_static_data_t StyleSheet_dispex = { + L"StyleSheet", + NULL, + PROTO_ID_StyleSheet, + NULL_tid, + no_iface_tids, + StyleSheet_init_dispex_info +}; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index d79b220c5f1..7e9649663a0 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -426,7 +426,7 @@ PRIVATE_TID_LIST X(HTMLXMLHttpRequest, "XMLHttpRequest", HTMLXMLHttpRequest_dispex, Object) \ X(HTMLCurrentStyle, "MSCurrentStyleCSSProperties", HTMLCurrentStyle_dispex, HTMLCSSProperties) \ X(HTMLW3CComputedStyle, "CSSStyleDeclaration", HTMLW3CComputedStyle_dispex, Object) \ - X(HTMLStyleSheet, "CSSStyleSheet", HTMLStyleSheet_dispex, Object) \ + X(HTMLStyleSheet, "CSSStyleSheet", HTMLStyleSheet_dispex, StyleSheet) \ X(HTMLStyleSheetRule, "CSSStyleRule", HTMLStyleSheetRule_dispex, Object) \ X(HTMLElement, "HTMLElement", HTMLElement_dispex, DOMElement) \ X(HTMLGenericElement, "HTMLUnknownElement", HTMLGenericElement_dispex, HTMLElement) \ @@ -471,6 +471,7 @@ PRIVATE_TID_LIST X(DOMCharacterData, "CharacterData", DOMCharacterData_dispex, HTMLDOMNode) \ X(DocumentType, "DocumentType", DocumentType_dispex, HTMLDOMNode) \ X(DOMElement, "Element", DOMElement_dispex, HTMLDOMNode) \ + X(StyleSheet, "StyleSheet", StyleSheet_dispex, Object) \ X(MediaQueryList, "MediaQueryList", media_query_list_dispex, Object) \ X(DOMTokenList, "DOMTokenList", DOMTokenList_dispex, Object) \ X(HTMLDOMNode, "Node", HTMLDOMNode_dispex, Object) \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index a281785b1ef..072090f3f5f 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1149,6 +1149,7 @@ sync_test("builtin_prototypes", function() { [ "Comment", "CharacterData" ], [ "Console", "Object" ], [ "CSSStyleDeclaration", "Object" ], + [ "CSSStyleSheet", "StyleSheet" ], [ "CustomEvent", "Event" ], [ "DocumentType", "Node" ], [ "DOMImplementation", "Object" ], @@ -1214,6 +1215,7 @@ sync_test("builtin_prototypes", function() { [ "Screen", "Object" ], [ "Storage", "Object" ], [ "StorageEvent", "Event" ], + [ "StyleSheet", "Object" ], [ "StyleSheetList", "Object" ], [ "Text", "CharacterData" ], [ "TextRange", "Object" ], @@ -1266,6 +1268,7 @@ sync_test("builtin_prototypes", function() { protos = [ [ "CharacterData", ["data","length","appendData"], Node_props ], [ "Comment", ["text"], ["insertData","replaceData","substringData"] ], + [ "CSSStyleSheet", ["addRule","cssRules","ownerRule","rules"], ["disabled","media","ownerNode","parentStyleSheet","title","type"] ], [ "CustomEvent", ["detail","initCustomEvent"], Event_props ], [ "DocumentType", ["entities","internalSubset","name","notations","publicId","systemId"], Node_props ], [ "Element", Elem_props, Node_props ], From 6cb75771ad936dae04281a01c797894944ba7c2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:06 +0200 Subject: [PATCH 0914/2777] mshtml: Introduce CSSRulePrototype and set it as CSSStyleRulePrototype's prototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The interface is abstract, and is only used in prototype chains (and constructor), so we needn't implement any of it. IHTMLCSSRule is added as a stub interface to HTMLStyleSheetRule since it will now inherit from it and have its props exposed. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlstylesheet.c | 128 +++++++++++++++++++++++++++++- dlls/mshtml/mshtml_private.h | 4 +- dlls/mshtml/tests/documentmode.js | 3 + 3 files changed, 133 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/htmlstylesheet.c b/dlls/mshtml/htmlstylesheet.c index e19b32d2312..176204e5129 100644 --- a/dlls/mshtml/htmlstylesheet.c +++ b/dlls/mshtml/htmlstylesheet.c @@ -75,6 +75,7 @@ struct HTMLStyleSheetRulesCollection { struct HTMLStyleSheetRule { DispatchEx dispex; IHTMLStyleSheetRule IHTMLStyleSheetRule_iface; + IHTMLCSSRule IHTMLCSSRule_iface; LONG ref; @@ -210,6 +211,114 @@ static const IHTMLStyleSheetRuleVtbl HTMLStyleSheetRuleVtbl = { HTMLStyleSheetRule_get_readOnly }; +static inline HTMLStyleSheetRule *impl_from_IHTMLCSSRule(IHTMLCSSRule *iface) +{ + return CONTAINING_RECORD(iface, HTMLStyleSheetRule, IHTMLCSSRule_iface); +} + +static HRESULT WINAPI HTMLCSSRule_QueryInterface(IHTMLCSSRule *iface, REFIID riid, void **ppv) +{ + HTMLStyleSheetRule *This = impl_from_IHTMLCSSRule(iface); + return IHTMLStyleSheetRule_QueryInterface(&This->IHTMLStyleSheetRule_iface, riid, ppv); +} + +static ULONG WINAPI HTMLCSSRule_AddRef(IHTMLCSSRule *iface) +{ + HTMLStyleSheetRule *This = impl_from_IHTMLCSSRule(iface); + return IHTMLStyleSheetRule_AddRef(&This->IHTMLStyleSheetRule_iface); +} + +static ULONG WINAPI HTMLCSSRule_Release(IHTMLCSSRule *iface) +{ + HTMLStyleSheetRule *This = impl_from_IHTMLCSSRule(iface); + return IHTMLStyleSheetRule_Release(&This->IHTMLStyleSheetRule_iface); +} + +static HRESULT WINAPI HTMLCSSRule_GetTypeInfoCount( + IHTMLCSSRule *iface, UINT *pctinfo) +{ + HTMLStyleSheetRule *This = impl_from_IHTMLCSSRule(iface); + return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLCSSRule_GetTypeInfo(IHTMLCSSRule *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLStyleSheetRule *This = impl_from_IHTMLCSSRule(iface); + return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLCSSRule_GetIDsOfNames(IHTMLCSSRule *iface, REFIID riid, LPOLESTR *rgszNames, + UINT cNames, LCID lcid, DISPID *rgDispId) +{ + HTMLStyleSheetRule *This = impl_from_IHTMLCSSRule(iface); + return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI HTMLCSSRule_Invoke(IHTMLCSSRule *iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLStyleSheetRule *This = impl_from_IHTMLCSSRule(iface); + return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLCSSRule_get_type(IHTMLCSSRule *iface, USHORT *p) +{ + HTMLStyleSheetRule *This = impl_from_IHTMLCSSRule(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCSSRule_put_cssText(IHTMLCSSRule *iface, BSTR v) +{ + HTMLStyleSheetRule *This = impl_from_IHTMLCSSRule(iface); + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCSSRule_get_cssText(IHTMLCSSRule *iface, BSTR *p) +{ + HTMLStyleSheetRule *This = impl_from_IHTMLCSSRule(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCSSRule_get_parentRule(IHTMLCSSRule *iface, IHTMLCSSRule **p) +{ + HTMLStyleSheetRule *This = impl_from_IHTMLCSSRule(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLCSSRule_get_parentStyleSheet(IHTMLCSSRule *iface, IHTMLStyleSheet **p) +{ + HTMLStyleSheetRule *This = impl_from_IHTMLCSSRule(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static const IHTMLCSSRuleVtbl HTMLCSSRuleVtbl = { + HTMLCSSRule_QueryInterface, + HTMLCSSRule_AddRef, + HTMLCSSRule_Release, + HTMLCSSRule_GetTypeInfoCount, + HTMLCSSRule_GetTypeInfo, + HTMLCSSRule_GetIDsOfNames, + HTMLCSSRule_Invoke, + HTMLCSSRule_get_type, + HTMLCSSRule_put_cssText, + HTMLCSSRule_get_cssText, + HTMLCSSRule_get_parentRule, + HTMLCSSRule_get_parentStyleSheet +}; + +static void HTMLStyleSheetRule_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + if(mode >= COMPAT_MODE_IE9) + dispex_info_add_interface(info, IHTMLCSSRule_tid, NULL); +} + static const tid_t HTMLStyleSheetRule_iface_tids[] = { IHTMLStyleSheetRule_tid, 0 @@ -219,7 +328,8 @@ dispex_static_data_t HTMLStyleSheetRule_dispex = { NULL, PROTO_ID_HTMLStyleSheetRule, DispHTMLStyleSheetRule_tid, - HTMLStyleSheetRule_iface_tids + HTMLStyleSheetRule_iface_tids, + HTMLStyleSheetRule_init_dispex_info }; static HRESULT create_style_sheet_rule(nsIDOMCSSRule *nsstylesheetrule, HTMLInnerWindow *window, @@ -232,6 +342,7 @@ static HRESULT create_style_sheet_rule(nsIDOMCSSRule *nsstylesheetrule, HTMLInne return E_OUTOFMEMORY; rule->IHTMLStyleSheetRule_iface.lpVtbl = &HTMLStyleSheetRuleVtbl; + rule->IHTMLCSSRule_iface.lpVtbl = &HTMLCSSRuleVtbl; rule->ref = 1; rule->nsstylesheetrule = NULL; @@ -250,6 +361,21 @@ static HRESULT create_style_sheet_rule(nsIDOMCSSRule *nsstylesheetrule, HTMLInne return S_OK; } +/* dummy dispex used only for StyleSheet in prototype chain */ +static void CSSRule_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + dispex_info_add_interface(info, IHTMLCSSRule_tid, NULL); +} + +dispex_static_data_t CSSRule_dispex = { + L"CSSRule", + NULL, + PROTO_ID_CSSRule, + NULL_tid, + no_iface_tids, + CSSRule_init_dispex_info +}; + static inline HTMLStyleSheetRulesCollection *impl_from_IHTMLStyleSheetRulesCollection(IHTMLStyleSheetRulesCollection *iface) { return CONTAINING_RECORD(iface, HTMLStyleSheetRulesCollection, IHTMLStyleSheetRulesCollection_iface); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 7e9649663a0..d2007b5524f 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -347,6 +347,7 @@ typedef struct ScriptHost ScriptHost; XIID(IHTMLStyleSheet) \ XIID(IHTMLStyleSheet4) \ XIID(IHTMLStyleSheetRule) \ + XIID(IHTMLCSSRule) \ XIID(IHTMLStyleSheetRulesCollection) \ XIID(IHTMLStyleSheetsCollection) \ XIID(IHTMLTable) \ @@ -427,7 +428,7 @@ PRIVATE_TID_LIST X(HTMLCurrentStyle, "MSCurrentStyleCSSProperties", HTMLCurrentStyle_dispex, HTMLCSSProperties) \ X(HTMLW3CComputedStyle, "CSSStyleDeclaration", HTMLW3CComputedStyle_dispex, Object) \ X(HTMLStyleSheet, "CSSStyleSheet", HTMLStyleSheet_dispex, StyleSheet) \ - X(HTMLStyleSheetRule, "CSSStyleRule", HTMLStyleSheetRule_dispex, Object) \ + X(HTMLStyleSheetRule, "CSSStyleRule", HTMLStyleSheetRule_dispex, CSSRule) \ X(HTMLElement, "HTMLElement", HTMLElement_dispex, DOMElement) \ X(HTMLGenericElement, "HTMLUnknownElement", HTMLGenericElement_dispex, HTMLElement) \ X(HTMLAnchorElement, "HTMLAnchorElement", HTMLAnchorElement_dispex, HTMLElement) \ @@ -471,6 +472,7 @@ PRIVATE_TID_LIST X(DOMCharacterData, "CharacterData", DOMCharacterData_dispex, HTMLDOMNode) \ X(DocumentType, "DocumentType", DocumentType_dispex, HTMLDOMNode) \ X(DOMElement, "Element", DOMElement_dispex, HTMLDOMNode) \ + X(CSSRule, "CSSRule", CSSRule_dispex, Object) \ X(StyleSheet, "StyleSheet", StyleSheet_dispex, Object) \ X(MediaQueryList, "MediaQueryList", media_query_list_dispex, Object) \ X(DOMTokenList, "DOMTokenList", DOMTokenList_dispex, Object) \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 072090f3f5f..ecbf297bcb2 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1148,7 +1148,9 @@ sync_test("builtin_prototypes", function() { [ "ClientRectList", "Object" ], [ "Comment", "CharacterData" ], [ "Console", "Object" ], + [ "CSSRule", "Object" ], [ "CSSStyleDeclaration", "Object" ], + [ "CSSStyleRule", "CSSRule" ], [ "CSSStyleSheet", "StyleSheet" ], [ "CustomEvent", "Event" ], [ "DocumentType", "Node" ], @@ -1268,6 +1270,7 @@ sync_test("builtin_prototypes", function() { protos = [ [ "CharacterData", ["data","length","appendData"], Node_props ], [ "Comment", ["text"], ["insertData","replaceData","substringData"] ], + [ "CSSStyleRule", ["readOnly","selectorText","style"], ["cssText","parentRule","parentStyleSheet","type" ] ], [ "CSSStyleSheet", ["addRule","cssRules","ownerRule","rules"], ["disabled","media","ownerNode","parentStyleSheet","title","type"] ], [ "CustomEvent", ["detail","initCustomEvent"], Event_props ], [ "DocumentType", ["entities","internalSubset","name","notations","publicId","systemId"], Node_props ], From fc0001e9df450e51a0656d48fc1ae82a24d90c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:06 +0200 Subject: [PATCH 0915/2777] mshtml: Introduce DocumentPrototype and set it as HTMLDocumentPrototype's prototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmldoc.c | 9 +++++++++ dlls/mshtml/mshtml_private.h | 3 ++- dlls/mshtml/tests/documentmode.js | 3 +++ dlls/mshtml/tests/es5.js | 1 - 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 94357fae90a..46df65b3c2f 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -6455,6 +6455,15 @@ dispex_static_data_t HTMLDocumentNode_dispex = { HTMLDocumentNode_init_dispex_info }; +dispex_static_data_t DocumentNode_dispex = { + L"Document", + &HTMLDocumentNode_event_target_vtbl.dispex_vtbl, + PROTO_ID_Document, + DispHTMLDocument_tid, + HTMLDocumentNode_iface_tids, + HTMLDocumentNode_init_dispex_info +}; + static HTMLDocumentNode *alloc_doc_node(HTMLDocumentObj *doc_obj, HTMLInnerWindow *window) { HTMLDocumentNode *doc; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index d2007b5524f..4392bdaf864 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -409,7 +409,7 @@ PRIVATE_TID_LIST X(HTMLDOMChildrenCollection, "NodeList", HTMLDOMChildrenCollection_dispex, Object) \ X(HTMLDOMImplementation, "DOMImplementation", HTMLDOMImplementation_dispex, Object) \ X(HTMLDOMTextNode, "Text", HTMLDOMTextNode_dispex, DOMCharacterData) \ - X(HTMLDocument, "HTMLDocument", HTMLDocumentNode_dispex, Object) \ + X(HTMLDocument, "HTMLDocument", HTMLDocumentNode_dispex, Document) \ X(HTMLWindow, "Window", HTMLWindow_dispex, Object) \ X(HTMLAttributeCollection, "NamedNodeMap", HTMLAttributeCollection_dispex, Object) \ X(HTMLElementCollection, "HTMLCollection", HTMLElementCollection_dispex, Object) \ @@ -470,6 +470,7 @@ PRIVATE_TID_LIST X(DOMStorageEvent, "StorageEvent", DOMStorageEvent_dispex, DOMEvent) \ X(DOMUIEvent, "UIEvent", DOMUIEvent_dispex, DOMEvent) \ X(DOMCharacterData, "CharacterData", DOMCharacterData_dispex, HTMLDOMNode) \ + X(Document, "Document", DocumentNode_dispex, HTMLDOMNode) \ X(DocumentType, "DocumentType", DocumentType_dispex, HTMLDOMNode) \ X(DOMElement, "Element", DOMElement_dispex, HTMLDOMNode) \ X(CSSRule, "CSSRule", CSSRule_dispex, Object) \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index ecbf297bcb2..3f4dd1a379a 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1153,6 +1153,7 @@ sync_test("builtin_prototypes", function() { [ "CSSStyleRule", "CSSRule" ], [ "CSSStyleSheet", "StyleSheet" ], [ "CustomEvent", "Event" ], + [ "Document", "Node" ], [ "DocumentType", "Node" ], [ "DOMImplementation", "Object" ], [ "DOMTokenList", "Object" ], @@ -1164,6 +1165,7 @@ sync_test("builtin_prototypes", function() { [ "HTMLBodyElement", "HTMLElement" ], [ "HTMLButtonElement", "HTMLElement" ], [ "HTMLCollection", "Object" ], + [ "HTMLDocument", "Document" ], [ "HTMLElement", "Element" ], [ "HTMLEmbedElement", "HTMLElement" ], [ "HTMLFormElement", "HTMLElement" ], @@ -1273,6 +1275,7 @@ sync_test("builtin_prototypes", function() { [ "CSSStyleRule", ["readOnly","selectorText","style"], ["cssText","parentRule","parentStyleSheet","type" ] ], [ "CSSStyleSheet", ["addRule","cssRules","ownerRule","rules"], ["disabled","media","ownerNode","parentStyleSheet","title","type"] ], [ "CustomEvent", ["detail","initCustomEvent"], Event_props ], + [ "Document", ["body","doctype","documentMode","onactivate","parentWindow","styleSheets","title"], Node_props ], [ "DocumentType", ["entities","internalSubset","name","notations","publicId","systemId"], Node_props ], [ "Element", Elem_props, Node_props ], [ "HTMLElement", HtmlElem_props, Elem_props ], diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index dba924eb8f5..4c3006ab992 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2957,7 +2957,6 @@ sync_test("instanceof", function() { r = (document.createElement("div") instanceof HTMLIFrameElement); ok(r === false, "div element instance of HTMLIFrameElement"); r = (document instanceof Node); - todo_wine. ok(r === true, "document not instance of Node"); }); From 93e14cc49c2694e1370ec6f2c2725c5833b41eaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:07 +0200 Subject: [PATCH 0916/2777] mshtml: Set the document node to DocumentNode in IE9 and IE10 modes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have to delay setting it once the mode is changed. Note that IE8 uses HTMLDocumentNodePrototype as prototype, even though it's a different architecture (without jscript proxies). Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/dispex.c | 45 ++++++++++++++++--------------- dlls/mshtml/htmldoc.c | 10 ++++--- dlls/mshtml/tests/documentmode.js | 2 +- dlls/mshtml/tests/events.c | 1 - 4 files changed, 32 insertions(+), 26 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 39c092b2b1a..006e055e13e 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1983,13 +1983,33 @@ compat_mode_t dispex_compat_mode(DispatchEx *dispex) : dispex->info->desc->vtbl->get_compat_mode(dispex); } +static dispex_data_t *ensure_dispex_info(dispex_static_data_t *desc, compat_mode_t compat_mode) +{ + if(!desc->info_cache[compat_mode]) { + EnterCriticalSection(&cs_dispex_static_data); + if(!desc->info_cache[compat_mode]) + desc->info_cache[compat_mode] = preprocess_dispex_data(desc, compat_mode); + LeaveCriticalSection(&cs_dispex_static_data); + } + return desc->info_cache[compat_mode]; +} + +static BOOL ensure_real_info(DispatchEx *dispex) +{ + if(dispex->info != dispex->info->desc->delayed_init_info) + return TRUE; + + dispex->info->desc->vtbl->finalize_dispex(dispex); + return dispex->info != NULL; +} + HRESULT dispex_to_string(DispatchEx *dispex, BSTR *ret) { static const WCHAR prefix[8] = L"[object "; static const WCHAR suffix[] = L"]"; WCHAR buf[ARRAY_SIZE(prefix) + 36 + ARRAY_SIZE(suffix)], *p = buf; compat_mode_t compat_mode = dispex_compat_mode(dispex); - const WCHAR *name = dispex->info->desc->name; + const WCHAR *name; unsigned len; if(!ret) @@ -2000,6 +2020,9 @@ HRESULT dispex_to_string(DispatchEx *dispex, BSTR *ret) if(compat_mode < COMPAT_MODE_IE9) p--; else { + if(!ensure_real_info(dispex)) + return E_OUTOFMEMORY; + name = dispex->info->desc->name; len = wcslen(name); assert(len <= 36); memcpy(p, name, len * sizeof(WCHAR)); @@ -2011,26 +2034,6 @@ HRESULT dispex_to_string(DispatchEx *dispex, BSTR *ret) return *ret ? S_OK : E_OUTOFMEMORY; } -static dispex_data_t *ensure_dispex_info(dispex_static_data_t *desc, compat_mode_t compat_mode) -{ - if(!desc->info_cache[compat_mode]) { - EnterCriticalSection(&cs_dispex_static_data); - if(!desc->info_cache[compat_mode]) - desc->info_cache[compat_mode] = preprocess_dispex_data(desc, compat_mode); - LeaveCriticalSection(&cs_dispex_static_data); - } - return desc->info_cache[compat_mode]; -} - -static BOOL ensure_real_info(DispatchEx *dispex) -{ - if(dispex->info != dispex->info->desc->delayed_init_info) - return TRUE; - - dispex->info->desc->vtbl->finalize_dispex(dispex); - return dispex->info != NULL; -} - static inline struct legacy_prototype *legacy_prototype_from_IUnknown(IUnknown *iface) { return CONTAINING_RECORD(iface, struct legacy_prototype, IUnknown_iface); diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 46df65b3c2f..6e02acbb4e4 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -6291,11 +6291,15 @@ static compat_mode_t HTMLDocumentNode_get_compat_mode(DispatchEx *dispex) static void HTMLDocumentNode_finalize_dispex(DispatchEx *dispex) { HTMLDocumentNode *This = impl_from_DispatchEx(dispex); + compat_mode_t compat_mode = lock_document_mode(This); + dispex_static_data_t *dispex_data; - lock_document_mode(This); + if(COMPAT_MODE_IE9 <= compat_mode && compat_mode < COMPAT_MODE_IE11) + dispex_data = &DocumentNode_dispex; + else + dispex_data = &HTMLDocumentNode_dispex; - /* FIXME: IE9 and IE10 have different dispex data */ - finalize_delayed_init_dispex(dispex, get_inner_window(This), &HTMLDocumentNode_dispex); + finalize_delayed_init_dispex(dispex, get_inner_window(This), dispex_data); } static nsISupports *HTMLDocumentNode_get_gecko_target(DispatchEx *dispex) diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 3f4dd1a379a..7e7d0eb007e 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -322,7 +322,7 @@ sync_test("builtin_toString", function() { if(clientRects) test("clientRect", clientRects[0], "ClientRect"); if(clientRects) test("clientRects", clientRects, "ClientRectList"); if(currentStyle) test("currentStyle", currentStyle, "MSCurrentStyleCSSProperties"); - if(v >= 11 /* todo_wine */) test("document", document, v < 11 ? "Document" : "HTMLDocument"); + test("document", document, v < 11 ? "Document" : "HTMLDocument"); test("elements", document.getElementsByTagName("body"), "HTMLCollection"); test("history", window.history, "History"); test("implementation", document.implementation, "DOMImplementation"); diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 7170951459e..446a7b4435b 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -4021,7 +4021,6 @@ static void test_doc_obj(IHTMLDocument2 *doc) bstr = NULL; hres = IHTMLDocument2_toString(doc, &bstr); ok(hres == S_OK, "toString failed: %08lx\n", hres); - todo_wine_if(document_mode >= 9) ok(!wcscmp(bstr, (document_mode < 9 ? L"[object]" : L"[object Document]")), "toString returned %s\n", wine_dbgstr_w(bstr)); SysFreeString(bstr); From 840f4541fb8591f02156ed860c08425b4bd9e234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:07 +0200 Subject: [PATCH 0917/2777] mshtml: Use a helper function to find an attribute in the collection's list. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- Helps next patch. --- dlls/mshtml/htmlelem.c | 43 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 09645a1876e..482aa7cf776 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -526,6 +526,24 @@ HRESULT create_element(HTMLDocumentNode *doc, const WCHAR *tag, HTMLElement **re return hres; } +static HTMLDOMAttribute *find_attr_in_list(HTMLAttributeCollection *attrs, DISPID dispid, LONG *pos) +{ + HTMLDOMAttribute *iter, *ret = NULL; + struct list *list = &attrs->attrs; + unsigned i = 0; + + LIST_FOR_EACH_ENTRY(iter, list, HTMLDOMAttribute, entry) { + if(iter->dispid == dispid) { + ret = iter; + break; + } + i++; + } + if(pos) + *pos = i; + return ret; +} + typedef struct { DispatchEx dispex; IHTMLRect IHTMLRect_iface; @@ -4643,7 +4661,7 @@ static HRESULT WINAPI HTMLElement4_setAttributeNode(IHTMLElement4 *iface, IHTMLD IHTMLDOMAttribute **ppretAttribute) { HTMLElement *This = impl_from_IHTMLElement4(iface); - HTMLDOMAttribute *attr, *iter, *replace = NULL; + HTMLDOMAttribute *attr, *replace; HTMLAttributeCollection *attrs; DISPID dispid; HRESULT hres; @@ -4668,13 +4686,7 @@ static HRESULT WINAPI HTMLElement4_setAttributeNode(IHTMLElement4 *iface, IHTMLD if(FAILED(hres)) return hres; - LIST_FOR_EACH_ENTRY(iter, &attrs->attrs, HTMLDOMAttribute, entry) { - if(iter->dispid == dispid) { - replace = iter; - break; - } - } - + replace = find_attr_in_list(attrs, dispid, NULL); if(replace) { hres = get_elem_attr_value_by_dispid(This, dispid, &replace->value); if(FAILED(hres)) { @@ -8290,20 +8302,9 @@ static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, BST static inline HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, LONG *list_pos, HTMLDOMAttribute **attr) { - HTMLDOMAttribute *iter; - LONG pos = 0; HRESULT hres; - *attr = NULL; - LIST_FOR_EACH_ENTRY(iter, &This->attrs, HTMLDOMAttribute, entry) { - if(iter->dispid == id) { - *attr = iter; - break; - } - pos++; - } - - if(!*attr) { + if(!(*attr = find_attr_in_list(This, id, list_pos))) { if(!This->elem) { WARN("NULL elem\n"); return E_UNEXPECTED; @@ -8316,8 +8317,6 @@ static inline HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, LONG } IHTMLDOMAttribute_AddRef(&(*attr)->IHTMLDOMAttribute_iface); - if(list_pos) - *list_pos = pos; return S_OK; } From 150b4fc4a8eb4543066f677cbb9c1541b84d3049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:07 +0200 Subject: [PATCH 0918/2777] mshtml: Implement proper attribute nodes for IE9+ modes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We only use them for IE9+ modes because the legacy node-like attribute props are correct wrt the older compat modes. Signed-off-by: Gabriel Ivăncescu --- Detached attributes will be tested on next patch since they require a small fix to the legacy modes. --- dlls/mshtml/dispex.c | 17 ++ dlls/mshtml/htmlattr.c | 248 +++++++++++++++++++++++++++--- dlls/mshtml/htmldoc.c | 19 ++- dlls/mshtml/htmlelem.c | 200 ++++++++++++++++++------ dlls/mshtml/mshtml_private.h | 9 +- dlls/mshtml/tests/documentmode.js | 70 +++++++++ 6 files changed, 493 insertions(+), 70 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 006e055e13e..5a0e88352eb 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -736,6 +736,23 @@ dispex_prop_type_t get_dispid_type(DISPID id) return DISPEXPROP_BUILTIN; } +BOOL is_custom_attribute(DispatchEx *dispex, const WCHAR *name) +{ + func_info_t **funcs = dispex->info->name_table; + DWORD i, a = 0, b = dispex->info->func_cnt; + int c; + + while(a < b) { + i = (a + b) / 2; + c = wcsicmp(funcs[i]->name, name); + if(!c) + return (funcs[i]->func_disp_idx >= 0); + if(c > 0) b = i; + else a = i + 1; + } + return TRUE; +} + static HRESULT variant_copy(VARIANT *dest, VARIANT *src) { if(V_VT(src) == VT_BSTR && !V_BSTR(src)) { diff --git a/dlls/mshtml/htmlattr.c b/dlls/mshtml/htmlattr.c index 1d3a3f49787..cca3d6b9ca0 100644 --- a/dlls/mshtml/htmlattr.c +++ b/dlls/mshtml/htmlattr.c @@ -42,6 +42,9 @@ static HRESULT WINAPI HTMLDOMAttribute_QueryInterface(IHTMLDOMAttribute *iface, { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface); + if(This->node.nsnode) + return IHTMLDOMNode_QueryInterface(&This->node.IHTMLDOMNode_iface, riid, ppv); + TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); if(IsEqualGUID(&IID_IUnknown, riid)) { @@ -50,7 +53,7 @@ static HRESULT WINAPI HTMLDOMAttribute_QueryInterface(IHTMLDOMAttribute *iface, *ppv = &This->IHTMLDOMAttribute_iface; }else if(IsEqualGUID(&IID_IHTMLDOMAttribute2, riid)) { *ppv = &This->IHTMLDOMAttribute2_iface; - }else if(dispex_query_interface(&This->dispex, riid, ppv)) { + }else if(dispex_query_interface(&This->node.event_target.dispex, riid, ppv)) { return *ppv ? S_OK : E_NOINTERFACE; }else { WARN("%s not supported\n", debugstr_mshtml_guid(riid)); @@ -65,7 +68,11 @@ static HRESULT WINAPI HTMLDOMAttribute_QueryInterface(IHTMLDOMAttribute *iface, static ULONG WINAPI HTMLDOMAttribute_AddRef(IHTMLDOMAttribute *iface) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface); - LONG ref = InterlockedIncrement(&This->ref); + LONG ref; + + if(This->node.nsnode) + return IHTMLDOMNode_AddRef(&This->node.IHTMLDOMNode_iface); + ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); @@ -75,13 +82,17 @@ static ULONG WINAPI HTMLDOMAttribute_AddRef(IHTMLDOMAttribute *iface) static ULONG WINAPI HTMLDOMAttribute_Release(IHTMLDOMAttribute *iface) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface); - LONG ref = InterlockedDecrement(&This->ref); + LONG ref; + + if(This->node.nsnode) + return IHTMLDOMNode_Release(&This->node.IHTMLDOMNode_iface); + ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { assert(!This->elem); - release_dispex(&This->dispex); + release_dispex(&This->node.event_target.dispex); VariantClear(&This->value); free(This->name); free(This); @@ -93,14 +104,14 @@ static ULONG WINAPI HTMLDOMAttribute_Release(IHTMLDOMAttribute *iface) static HRESULT WINAPI HTMLDOMAttribute_GetTypeInfoCount(IHTMLDOMAttribute *iface, UINT *pctinfo) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface); - return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); + return IDispatchEx_GetTypeInfoCount(&This->node.event_target.dispex.IDispatchEx_iface, pctinfo); } static HRESULT WINAPI HTMLDOMAttribute_GetTypeInfo(IHTMLDOMAttribute *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface); - return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); + return IDispatchEx_GetTypeInfo(&This->node.event_target.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); } static HRESULT WINAPI HTMLDOMAttribute_GetIDsOfNames(IHTMLDOMAttribute *iface, REFIID riid, @@ -108,7 +119,7 @@ static HRESULT WINAPI HTMLDOMAttribute_GetIDsOfNames(IHTMLDOMAttribute *iface, R LCID lcid, DISPID *rgDispId) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface); - return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, + return IDispatchEx_GetIDsOfNames(&This->node.event_target.dispex.IDispatchEx_iface, riid, rgszNames, cNames, lcid, rgDispId); } @@ -117,7 +128,7 @@ static HRESULT WINAPI HTMLDOMAttribute_Invoke(IHTMLDOMAttribute *iface, DISPID d VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface); - return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, + return IDispatchEx_Invoke(&This->node.event_target.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); } @@ -125,6 +136,9 @@ static HRESULT WINAPI HTMLDOMAttribute_get_nodeName(IHTMLDOMAttribute *iface, BS { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface); + if(This->node.nsnode) + return IHTMLDOMNode_get_nodeName(&This->node.IHTMLDOMNode_iface, p); + TRACE("(%p)->(%p)\n", This, p); if(!This->elem) { @@ -148,6 +162,9 @@ static HRESULT WINAPI HTMLDOMAttribute_put_nodeValue(IHTMLDOMAttribute *iface, V EXCEPINFO ei; VARIANT ret; + if(This->node.nsnode) + return IHTMLDOMNode_put_nodeValue(&This->node.IHTMLDOMNode_iface, v); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); if(!This->elem) @@ -163,6 +180,9 @@ static HRESULT WINAPI HTMLDOMAttribute_get_nodeValue(IHTMLDOMAttribute *iface, V { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface); + if(This->node.nsnode) + return IHTMLDOMNode_get_nodeValue(&This->node.IHTMLDOMNode_iface, p); + TRACE("(%p)->(%p)\n", This, p); if(!This->elem) @@ -179,9 +199,16 @@ static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, V BSTR name; nsresult nsres; HRESULT hres; + cpp_bool b; TRACE("(%p)->(%p)\n", This, p); + if(This->node.nsnode) { + nsres = nsIDOMAttr_GetSpecified((nsIDOMAttr*)This->node.nsnode, &b); + *p = variant_bool(NS_SUCCEEDED(nsres) && b); + return S_OK; + } + if(!This->elem || !This->elem->dom_element) { FIXME("NULL This->elem\n"); return E_UNEXPECTED; @@ -255,21 +282,21 @@ static ULONG WINAPI HTMLDOMAttribute2_Release(IHTMLDOMAttribute2 *iface) static HRESULT WINAPI HTMLDOMAttribute2_GetTypeInfoCount(IHTMLDOMAttribute2 *iface, UINT *pctinfo) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); - return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); + return IDispatchEx_GetTypeInfoCount(&This->node.event_target.dispex.IDispatchEx_iface, pctinfo); } static HRESULT WINAPI HTMLDOMAttribute2_GetTypeInfo(IHTMLDOMAttribute2 *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); - return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); + return IDispatchEx_GetTypeInfo(&This->node.event_target.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); } static HRESULT WINAPI HTMLDOMAttribute2_GetIDsOfNames(IHTMLDOMAttribute2 *iface, REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); - return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, + return IDispatchEx_GetIDsOfNames(&This->node.event_target.dispex.IDispatchEx_iface, riid, rgszNames, cNames, lcid, rgDispId); } @@ -278,26 +305,43 @@ static HRESULT WINAPI HTMLDOMAttribute2_Invoke(IHTMLDOMAttribute2 *iface, DISPID VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); - return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, + return IDispatchEx_Invoke(&This->node.event_target.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); } static HRESULT WINAPI HTMLDOMAttribute2_get_name(IHTMLDOMAttribute2 *iface, BSTR *p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + nsAString nsstr; + nsresult nsres; TRACE("(%p)->(%p)\n", This, p); + if(This->node.nsnode) { + nsAString_InitDepend(&nsstr, NULL); + nsres = nsIDOMAttr_GetName((nsIDOMAttr*)This->node.nsnode, &nsstr); + return return_nsstr(nsres, &nsstr, p); + } + return IHTMLDOMAttribute_get_nodeName(&This->IHTMLDOMAttribute_iface, p); } static HRESULT WINAPI HTMLDOMAttribute2_put_value(IHTMLDOMAttribute2 *iface, BSTR v) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + nsAString nsstr; + nsresult nsres; VARIANT var; TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + if(This->node.nsnode) { + nsAString_InitDepend(&nsstr, v); + nsres = nsIDOMAttr_SetValue((nsIDOMAttr*)This->node.nsnode, &nsstr); + nsAString_Finish(&nsstr); + return NS_SUCCEEDED(nsres) ? S_OK : E_FAIL; + } + V_VT(&var) = VT_BSTR; V_BSTR(&var) = v; return IHTMLDOMAttribute_put_nodeValue(&This->IHTMLDOMAttribute_iface, var); @@ -306,11 +350,19 @@ static HRESULT WINAPI HTMLDOMAttribute2_put_value(IHTMLDOMAttribute2 *iface, BST static HRESULT WINAPI HTMLDOMAttribute2_get_value(IHTMLDOMAttribute2 *iface, BSTR *p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + nsAString nsstr; + nsresult nsres; VARIANT val; HRESULT hres; TRACE("(%p)->(%p)\n", This, p); + if(This->node.nsnode) { + nsAString_InitDepend(&nsstr, NULL); + nsres = nsIDOMAttr_GetValue((nsIDOMAttr*)This->node.nsnode, &nsstr); + return return_nsstr(nsres, &nsstr, p); + } + V_VT(&val) = VT_EMPTY; if(This->elem) hres = get_elem_attr_value_by_dispid(This->elem, This->dispid, &val); @@ -341,7 +393,12 @@ static HRESULT WINAPI HTMLDOMAttribute2_get_expando(IHTMLDOMAttribute2 *iface, V static HRESULT WINAPI HTMLDOMAttribute2_get_nodeType(IHTMLDOMAttribute2 *iface, LONG *p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_get_nodeType(&This->node.IHTMLDOMNode_iface, p); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; } @@ -349,6 +406,9 @@ static HRESULT WINAPI HTMLDOMAttribute2_get_parentNode(IHTMLDOMAttribute2 *iface { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + if(This->node.nsnode) + return IHTMLDOMNode_get_parentNode(&This->node.IHTMLDOMNode_iface, p); + TRACE("(%p)->(%p)\n", This, p); *p = NULL; @@ -358,49 +418,84 @@ static HRESULT WINAPI HTMLDOMAttribute2_get_parentNode(IHTMLDOMAttribute2 *iface static HRESULT WINAPI HTMLDOMAttribute2_get_childNodes(IHTMLDOMAttribute2 *iface, IDispatch **p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_get_childNodes(&This->node.IHTMLDOMNode_iface, p); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; } static HRESULT WINAPI HTMLDOMAttribute2_get_firstChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_get_firstChild(&This->node.IHTMLDOMNode_iface, p); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; } static HRESULT WINAPI HTMLDOMAttribute2_get_lastChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_get_lastChild(&This->node.IHTMLDOMNode_iface, p); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; } static HRESULT WINAPI HTMLDOMAttribute2_get_previousSibling(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_get_previousSibling(&This->node.IHTMLDOMNode_iface, p); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; } static HRESULT WINAPI HTMLDOMAttribute2_get_nextSibling(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_get_nextSibling(&This->node.IHTMLDOMNode_iface, p); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; } static HRESULT WINAPI HTMLDOMAttribute2_get_attributes(IHTMLDOMAttribute2 *iface, IDispatch **p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_get_attributes(&This->node.IHTMLDOMNode_iface, p); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; } static HRESULT WINAPI HTMLDOMAttribute2_get_ownerDocument(IHTMLDOMAttribute2 *iface, IDispatch **p) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode2_get_ownerDocument(&This->node.IHTMLDOMNode2_iface, p); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; } @@ -408,7 +503,12 @@ static HRESULT WINAPI HTMLDOMAttribute2_insertBefore(IHTMLDOMAttribute2 *iface, VARIANT refChild, IHTMLDOMNode **node) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_insertBefore(&This->node.IHTMLDOMNode_iface, newChild, refChild, node); + FIXME("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), node); + return E_NOTIMPL; } @@ -416,7 +516,12 @@ static HRESULT WINAPI HTMLDOMAttribute2_replaceChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode *oldChild, IHTMLDOMNode **node) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_replaceChild(&This->node.IHTMLDOMNode_iface, newChild, oldChild, node); + FIXME("(%p)->(%p %p %p)\n", This, newChild, oldChild, node); + return E_NOTIMPL; } @@ -424,7 +529,12 @@ static HRESULT WINAPI HTMLDOMAttribute2_removeChild(IHTMLDOMAttribute2 *iface, I IHTMLDOMNode **node) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_removeChild(&This->node.IHTMLDOMNode_iface, oldChild, node); + FIXME("(%p)->(%p %p)\n", This, oldChild, node); + return E_NOTIMPL; } @@ -432,14 +542,24 @@ static HRESULT WINAPI HTMLDOMAttribute2_appendChild(IHTMLDOMAttribute2 *iface, I IHTMLDOMNode **node) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_appendChild(&This->node.IHTMLDOMNode_iface, newChild, node); + FIXME("(%p)->(%p %p)\n", This, newChild, node); + return E_NOTIMPL; } static HRESULT WINAPI HTMLDOMAttribute2_hasChildNodes(IHTMLDOMAttribute2 *iface, VARIANT_BOOL *fChildren) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + + if(This->node.nsnode) + return IHTMLDOMNode_hasChildNodes(&This->node.IHTMLDOMNode_iface, fChildren); + FIXME("(%p)->(%p)\n", This, fChildren); + return E_NOTIMPL; } @@ -447,7 +567,20 @@ static HRESULT WINAPI HTMLDOMAttribute2_cloneNode(IHTMLDOMAttribute2 *iface, VAR IHTMLDOMAttribute **clonedNode) { HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface); + HRESULT hres; + + if(This->node.nsnode) { + IHTMLDOMNode *cloned; + hres = IHTMLDOMNode_cloneNode(&This->node.IHTMLDOMNode_iface, fDeep, &cloned); + if(SUCCEEDED(hres)) { + hres = IHTMLDOMNode_QueryInterface(cloned, &IID_IHTMLDOMAttribute, (void**)clonedNode); + IHTMLDOMNode_Release(cloned); + } + return hres; + } + FIXME("(%p)->(%x %p)\n", This, fDeep, clonedNode); + return E_NOTIMPL; } @@ -480,6 +613,73 @@ static const IHTMLDOMAttribute2Vtbl HTMLDOMAttribute2Vtbl = { HTMLDOMAttribute2_cloneNode }; +static inline HTMLDOMAttribute *impl_from_HTMLDOMNode(HTMLDOMNode *iface) +{ + return CONTAINING_RECORD(iface, HTMLDOMAttribute, node); +} + +static HRESULT HTMLDOMAttribute_QI(HTMLDOMNode *iface, REFIID riid, void **ppv) +{ + HTMLDOMAttribute *This = impl_from_HTMLDOMNode(iface); + + *ppv = NULL; + + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IHTMLDOMAttribute, riid)) { + *ppv = &This->IHTMLDOMAttribute_iface; + }else if(IsEqualGUID(&IID_IHTMLDOMAttribute2, riid)) { + *ppv = &This->IHTMLDOMAttribute2_iface; + }else { + return HTMLDOMNode_QI(&This->node, riid, ppv); + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static HRESULT HTMLDOMAttribute_clone(HTMLDOMNode *iface, nsIDOMNode *nsnode, HTMLDOMNode **ret) +{ + HTMLDOMAttribute *This = impl_from_HTMLDOMNode(iface); + HTMLDOMAttribute *new_attr; + nsIDOMAttr *nsattr; + nsresult nsres; + HRESULT hres; + + nsres = nsIDOMNode_QueryInterface(nsnode, &IID_nsIDOMAttr, (void**)&nsattr); + if(NS_FAILED(nsres)) { + ERR("no nsIDOMAttr iface\n"); + return E_FAIL; + } + + hres = HTMLDOMAttribute_Create(NULL, This->node.doc, This->elem, This->dispid, nsattr, + dispex_compat_mode(&This->node.event_target.dispex), &new_attr); + nsIDOMAttr_Release(nsattr); + if(FAILED(hres)) + return hres; + + *ret = &new_attr->node; + return S_OK; +} + +static const cpc_entry_t HTMLDOMAttribute_cpc[] = {{NULL}}; + +static const NodeImplVtbl HTMLDOMAttributeImplVtbl = { + NULL, + HTMLDOMAttribute_QI, + HTMLDOMNode_destructor, + HTMLDOMAttribute_cpc, + HTMLDOMAttribute_clone +}; + +static void HTMLDOMAttribute_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + HTMLDOMNode_init_dispex_info(info, mode); + + if(mode >= COMPAT_MODE_IE9) { + dispex_info_add_interface(info, IHTMLDOMNode_tid, NULL); + dispex_info_add_interface(info, IHTMLDOMNode2_tid, NULL); + } +} + static const tid_t HTMLDOMAttribute_iface_tids[] = { IHTMLDOMAttribute_tid, IHTMLDOMAttribute2_tid, @@ -490,7 +690,8 @@ dispex_static_data_t HTMLDOMAttribute_dispex = { NULL, PROTO_ID_HTMLDOMAttribute, DispHTMLDOMAttribute_tid, - HTMLDOMAttribute_iface_tids + HTMLDOMAttribute_iface_tids, + HTMLDOMAttribute_init_dispex_info }; HTMLDOMAttribute *unsafe_impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute *iface) @@ -499,7 +700,7 @@ HTMLDOMAttribute *unsafe_impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute *iface) } HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLDocumentNode *doc, HTMLElement *elem, DISPID dispid, - compat_mode_t compat_mode, HTMLDOMAttribute **attr) + nsIDOMAttr *nsattr, compat_mode_t compat_mode, HTMLDOMAttribute **attr) { HTMLAttributeCollection *col; HTMLDOMAttribute *ret; @@ -515,14 +716,12 @@ HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLDocumentNode *doc, HTMLEl ret->dispid = dispid; ret->elem = elem; - init_dispatch(&ret->dispex, (IUnknown*)&ret->IHTMLDOMAttribute_iface, - &HTMLDOMAttribute_dispex, get_inner_window(doc), compat_mode); - - /* For attributes attached to an element, (elem,dispid) pair should be valid used for its operation. */ + /* For attributes attached to an element, (elem,dispid) pair should + be valid used for its operation if we don't have a proper node. */ if(elem) { hres = HTMLElement_get_attr_col(&elem->node, &col); if(FAILED(hres)) { - IHTMLDOMAttribute_Release(&ret->IHTMLDOMAttribute_iface); + free(ret); return hres; } IHTMLAttributeCollection_Release(&col->IHTMLAttributeCollection_iface); @@ -530,6 +729,17 @@ HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLDocumentNode *doc, HTMLEl list_add_tail(&elem->attrs->attrs, &ret->entry); } + /* If we have a nsattr, use proper node */ + if(nsattr) { + ret->node.vtbl = &HTMLDOMAttributeImplVtbl; + HTMLDOMNode_Init(doc, &ret->node, (nsIDOMNode*)nsattr, &HTMLDOMAttribute_dispex); + *attr = ret; + return S_OK; + } + + init_dispatch(&ret->node.event_target.dispex, (IUnknown*)&ret->IHTMLDOMAttribute_iface, + &HTMLDOMAttribute_dispex, get_inner_window(doc), compat_mode); + /* For detached attributes we may still do most operations if we have its name available. */ if(name) { ret->name = wcsdup(name); diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 6e02acbb4e4..0c5a8db1f33 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -3241,13 +3241,28 @@ static HRESULT WINAPI HTMLDocument5_createAttribute(IHTMLDocument5 *iface, BSTR IHTMLDOMAttribute **ppattribute) { HTMLDocumentNode *This = impl_from_IHTMLDocument5(iface); + compat_mode_t compat_mode = dispex_compat_mode(&This->node.event_target.dispex); + nsIDOMAttr *nsattr = NULL; HTMLDOMAttribute *attr; + nsresult nsres; + nsAString str; HRESULT hres; TRACE("(%p)->(%s %p)\n", This, debugstr_w(bstrattrName), ppattribute); - hres = HTMLDOMAttribute_Create(bstrattrName, This, NULL, 0, - dispex_compat_mode(&This->node.event_target.dispex), &attr); + if(compat_mode >= COMPAT_MODE_IE9) { + nsAString_InitDepend(&str, bstrattrName); + nsres = nsIDOMDocument_CreateAttribute(This->dom_document, &str, &nsattr); + nsAString_Finish(&str); + if(NS_FAILED(nsres)) { + ERR("CreateAttribute failed: %08lx\n", nsres); + return E_FAIL; + } + } + + hres = HTMLDOMAttribute_Create(bstrattrName, This, NULL, 0, nsattr, compat_mode, &attr); + if(nsattr) + nsIDOMAttr_Release(nsattr); if(FAILED(hres)) return hres; diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 482aa7cf776..63256946941 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -526,24 +526,52 @@ HRESULT create_element(HTMLDocumentNode *doc, const WCHAR *tag, HTMLElement **re return hres; } -static HTMLDOMAttribute *find_attr_in_list(HTMLAttributeCollection *attrs, DISPID dispid, LONG *pos) +static HTMLDOMAttribute *find_attr_in_list(HTMLAttributeCollection *attrs, DISPID dispid, nsIDOMAttr *nsattr, LONG *pos) { HTMLDOMAttribute *iter, *ret = NULL; struct list *list = &attrs->attrs; unsigned i = 0; - LIST_FOR_EACH_ENTRY(iter, list, HTMLDOMAttribute, entry) { - if(iter->dispid == dispid) { - ret = iter; - break; + if(nsattr) { + LIST_FOR_EACH_ENTRY(iter, list, HTMLDOMAttribute, entry) { + if(iter->node.nsnode == (nsIDOMNode*)nsattr) { + ret = iter; + break; + } + i++; + } + }else { + LIST_FOR_EACH_ENTRY(iter, list, HTMLDOMAttribute, entry) { + if(iter->dispid == dispid) { + ret = iter; + break; + } + i++; } - i++; } if(pos) *pos = i; return ret; } +static DISPID get_dispid_for_nsattr(HTMLElement *elem, nsIDOMAttr *nsattr) +{ + DISPID dispid = 0; + nsAString nsstr; + + nsAString_InitDepend(&nsstr, NULL); + if(SUCCEEDED(nsIDOMAttr_GetName(nsattr, &nsstr))) { + const PRUnichar *name; + nsAString_GetData(&nsstr, &name); + + /* Supply a dummy non-builtin dispid so it can be checked for expando */ + if(is_custom_attribute(&elem->node.event_target.dispex, name)) + dispid = MSHTML_DISPID_CUSTOM_MIN; + nsAString_Finish(&nsstr); + } + return dispid; +} + typedef struct { DispatchEx dispex; IHTMLRect IHTMLRect_iface; @@ -4661,6 +4689,7 @@ static HRESULT WINAPI HTMLElement4_setAttributeNode(IHTMLElement4 *iface, IHTMLD IHTMLDOMAttribute **ppretAttribute) { HTMLElement *This = impl_from_IHTMLElement4(iface); + nsIDOMAttr *nsattr, *oldnsattr = NULL; HTMLDOMAttribute *attr, *replace; HTMLAttributeCollection *attrs; DISPID dispid; @@ -4677,25 +4706,49 @@ static HRESULT WINAPI HTMLElement4_setAttributeNode(IHTMLElement4 *iface, IHTMLD return E_INVALIDARG; } - hres = IDispatchEx_GetDispID(&This->node.event_target.dispex.IDispatchEx_iface, - attr->name, fdexNameCaseInsensitive|fdexNameEnsure, &dispid); - if(FAILED(hres)) - return hres; - hres = HTMLElement_get_attr_col(&This->node, &attrs); if(FAILED(hres)) return hres; - replace = find_attr_in_list(attrs, dispid, NULL); - if(replace) { - hres = get_elem_attr_value_by_dispid(This, dispid, &replace->value); + nsattr = (nsIDOMAttr*)attr->node.nsnode; + if(nsattr && !attrs->nsattrs) { + FIXME("Attribute has proper node but no NS collection for it.\n"); + IHTMLAttributeCollection_Release(&attrs->IHTMLAttributeCollection_iface); + return E_NOTIMPL; + } + + if(nsattr) { + if(NS_FAILED(nsIDOMMozNamedAttrMap_SetNamedItem(attrs->nsattrs, nsattr, &oldnsattr))) { + IHTMLAttributeCollection_Release(&attrs->IHTMLAttributeCollection_iface); + return E_FAIL; + } + dispid = get_dispid_for_nsattr(This, nsattr); + replace = NULL; + if(oldnsattr) { + replace = find_attr_in_list(attrs, 0, oldnsattr, NULL); + nsIDOMAttr_Release(oldnsattr); + } + }else { + hres = IDispatchEx_GetDispID(&This->node.event_target.dispex.IDispatchEx_iface, + attr->name, fdexNameCaseInsensitive|fdexNameEnsure, &dispid); if(FAILED(hres)) { - WARN("could not get attr value: %08lx\n", hres); - V_VT(&replace->value) = VT_EMPTY; + IHTMLAttributeCollection_Release(&attrs->IHTMLAttributeCollection_iface); + return hres; } - if(!replace->name) { - replace->name = attr->name; - attr->name = NULL; + replace = find_attr_in_list(attrs, dispid, NULL, NULL); + } + + if(replace) { + if(!nsattr) { + hres = get_elem_attr_value_by_dispid(This, dispid, &replace->value); + if(FAILED(hres)) { + WARN("could not get attr value: %08lx\n", hres); + V_VT(&replace->value) = VT_EMPTY; + } + if(!replace->name) { + replace->name = attr->name; + attr->name = NULL; + } } list_add_head(&replace->entry, &attr->entry); list_remove(&replace->entry); @@ -4710,10 +4763,12 @@ static HRESULT WINAPI HTMLElement4_setAttributeNode(IHTMLElement4 *iface, IHTMLD IHTMLAttributeCollection_Release(&attrs->IHTMLAttributeCollection_iface); - hres = set_elem_attr_value_by_dispid(This, dispid, &attr->value); - if(FAILED(hres)) - WARN("Could not set attribute value: %08lx\n", hres); - VariantClear(&attr->value); + if(!nsattr) { + hres = set_elem_attr_value_by_dispid(This, dispid, &attr->value); + if(FAILED(hres)) + WARN("Could not set attribute value: %08lx\n", hres); + VariantClear(&attr->value); + } *ppretAttribute = replace ? &replace->IHTMLDOMAttribute_iface : NULL; return S_OK; @@ -8239,13 +8294,30 @@ static HRESULT create_filters_collection(HTMLElement *elem, IHTMLFiltersCollecti return S_OK; } -static HRESULT get_attr_dispid_by_relative_idx(HTMLAttributeCollection *This, LONG *idx, DISPID start, DISPID *dispid) +static HRESULT get_attr_dispid_by_relative_idx(HTMLAttributeCollection *This, LONG *idx, DISPID start, + DISPID *dispid, nsIDOMAttr **nsattr) { IDispatchEx *dispex = &This->elem->node.event_target.dispex.IDispatchEx_iface; DISPID id = start; + UINT32 length; LONG len = -1; HRESULT hres; + if(This->nsattrs) { + id++; + if(dispid) { + *dispid = id + *idx; + if(!nsattr) + return S_OK; + if(NS_FAILED(nsIDOMMozNamedAttrMap_Item(This->nsattrs, *dispid, nsattr))) + return E_FAIL; + return *nsattr ? S_OK : DISP_E_UNKNOWNNAME; + } + nsIDOMMozNamedAttrMap_GetLength(This->nsattrs, &length); + *idx = (length > id) ? length - id : 0; + return S_OK; + } + FIXME("filter non-enumerable attributes out\n"); while(1) { @@ -8269,13 +8341,15 @@ static HRESULT get_attr_dispid_by_relative_idx(HTMLAttributeCollection *This, LO return S_OK; } -static HRESULT get_attr_dispid_by_idx(HTMLAttributeCollection *This, LONG *idx, DISPID *dispid) +static HRESULT get_attr_dispid_by_idx(HTMLAttributeCollection *This, LONG *idx, DISPID *dispid, nsIDOMAttr **nsattr) { - return get_attr_dispid_by_relative_idx(This, idx, DISPID_STARTENUM, dispid); + return get_attr_dispid_by_relative_idx(This, idx, DISPID_STARTENUM, dispid, nsattr); } -static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, BSTR name, DISPID *id) +static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, BSTR name, DISPID *id, nsIDOMAttr **nsattr) { + nsAString nsstr; + nsresult nsres; HRESULT hres; if(name[0]>='0' && name[0]<='9') { @@ -8284,12 +8358,22 @@ static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, BST idx = wcstoul(name, &end_ptr, 10); if(!*end_ptr) { - hres = get_attr_dispid_by_idx(This, &idx, id); + hres = get_attr_dispid_by_idx(This, &idx, id, nsattr); if(SUCCEEDED(hres)) return hres; } } + if(This->nsattrs) { + nsAString_InitDepend(&nsstr, name); + *nsattr = NULL; + nsres = nsIDOMMozNamedAttrMap_GetNamedItem(This->nsattrs, &nsstr, nsattr); + nsAString_Finish(&nsstr); + if(NS_FAILED(nsres)) + return E_FAIL; + return *nsattr ? S_OK : DISP_E_UNKNOWNNAME; + } + if(!This->elem) { WARN("NULL elem\n"); return E_UNEXPECTED; @@ -8300,17 +8384,20 @@ static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, BST return hres; } -static inline HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, LONG *list_pos, HTMLDOMAttribute **attr) +static inline HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, nsIDOMAttr *nsattr, + LONG *list_pos, HTMLDOMAttribute **attr) { HRESULT hres; - if(!(*attr = find_attr_in_list(This, id, list_pos))) { + if(!(*attr = find_attr_in_list(This, id, nsattr, list_pos))) { if(!This->elem) { WARN("NULL elem\n"); return E_UNEXPECTED; } - hres = HTMLDOMAttribute_Create(NULL, This->elem->node.doc, This->elem, id, + if(nsattr) + id = get_dispid_for_nsattr(This->elem, nsattr); + hres = HTMLDOMAttribute_Create(NULL, This->elem->node.doc, This->elem, id, nsattr, dispex_compat_mode(&This->elem->node.event_target.dispex), attr); if(FAILED(hres)) return hres; @@ -8385,6 +8472,7 @@ static HRESULT WINAPI HTMLAttributeCollectionEnum_Next(IEnumVARIANT *iface, ULON HTMLAttributeCollectionEnum *This = HTMLAttributeCollectionEnum_from_IEnumVARIANT(iface); DISPID tmp, dispid = This->iter_dispid; HTMLDOMAttribute *attr; + nsIDOMAttr *nsattr; LONG rel_index = 0; HRESULT hres; ULONG i; @@ -8392,10 +8480,13 @@ static HRESULT WINAPI HTMLAttributeCollectionEnum_Next(IEnumVARIANT *iface, ULON TRACE("(%p)->(%lu %p %p)\n", This, celt, rgVar, pCeltFetched); for(i = 0; i < celt; i++) { - hres = get_attr_dispid_by_relative_idx(This->col, &rel_index, dispid, &tmp); + nsattr = NULL; + hres = get_attr_dispid_by_relative_idx(This->col, &rel_index, dispid, &tmp, &nsattr); if(SUCCEEDED(hres)) { dispid = tmp; - hres = get_domattr(This->col, dispid, NULL, &attr); + hres = get_domattr(This->col, dispid, nsattr, NULL, &attr); + if(nsattr) + nsIDOMAttr_Release(nsattr); } else if(hres == DISP_E_UNKNOWNNAME) break; @@ -8430,14 +8521,14 @@ static HRESULT WINAPI HTMLAttributeCollectionEnum_Skip(IEnumVARIANT *iface, ULON return S_OK; rel_index = -1; - hres = get_attr_dispid_by_relative_idx(This->col, &rel_index, This->iter_dispid, NULL); + hres = get_attr_dispid_by_relative_idx(This->col, &rel_index, This->iter_dispid, NULL, NULL); if(FAILED(hres)) return hres; remaining = min(celt, rel_index); if(remaining) { rel_index = remaining - 1; - hres = get_attr_dispid_by_relative_idx(This->col, &rel_index, This->iter_dispid, &dispid); + hres = get_attr_dispid_by_relative_idx(This->col, &rel_index, This->iter_dispid, &dispid, NULL); if(FAILED(hres)) return hres; This->iter += remaining; @@ -8576,7 +8667,7 @@ static HRESULT WINAPI HTMLAttributeCollection_get_length(IHTMLAttributeCollectio TRACE("(%p)->(%p)\n", This, p); *p = -1; - hres = get_attr_dispid_by_idx(This, p, NULL); + hres = get_attr_dispid_by_idx(This, p, NULL, NULL); return hres; } @@ -8606,6 +8697,7 @@ static HRESULT WINAPI HTMLAttributeCollection__newEnum(IHTMLAttributeCollection static HRESULT WINAPI HTMLAttributeCollection_item(IHTMLAttributeCollection *iface, VARIANT *name, IDispatch **ppItem) { HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection(iface); + nsIDOMAttr *nsattr = NULL; HTMLDOMAttribute *attr; DISPID id; HRESULT hres; @@ -8614,10 +8706,10 @@ static HRESULT WINAPI HTMLAttributeCollection_item(IHTMLAttributeCollection *ifa switch(V_VT(name)) { case VT_I4: - hres = get_attr_dispid_by_idx(This, &V_I4(name), &id); + hres = get_attr_dispid_by_idx(This, &V_I4(name), &id, &nsattr); break; case VT_BSTR: - hres = get_attr_dispid_by_name(This, V_BSTR(name), &id); + hres = get_attr_dispid_by_name(This, V_BSTR(name), &id, &nsattr); break; default: FIXME("unsupported name %s\n", debugstr_variant(name)); @@ -8628,7 +8720,9 @@ static HRESULT WINAPI HTMLAttributeCollection_item(IHTMLAttributeCollection *ifa if(FAILED(hres)) return hres; - hres = get_domattr(This, id, NULL, &attr); + hres = get_domattr(This, id, nsattr, NULL, &attr); + if(nsattr) + nsIDOMAttr_Release(nsattr); if(FAILED(hres)) return hres; @@ -8706,13 +8800,14 @@ static HRESULT WINAPI HTMLAttributeCollection2_getNamedItem(IHTMLAttributeCollec IHTMLDOMAttribute **newretNode) { HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection2(iface); + nsIDOMAttr *nsattr = NULL; HTMLDOMAttribute *attr; DISPID id; HRESULT hres; TRACE("(%p)->(%s %p)\n", This, debugstr_w(bstrName), newretNode); - hres = get_attr_dispid_by_name(This, bstrName, &id); + hres = get_attr_dispid_by_name(This, bstrName, &id, &nsattr); if(hres == DISP_E_UNKNOWNNAME) { *newretNode = NULL; return S_OK; @@ -8720,7 +8815,9 @@ static HRESULT WINAPI HTMLAttributeCollection2_getNamedItem(IHTMLAttributeCollec return hres; } - hres = get_domattr(This, id, NULL, &attr); + hres = get_domattr(This, id, nsattr, NULL, &attr); + if(nsattr) + nsIDOMAttr_Release(nsattr); if(FAILED(hres)) return hres; @@ -8836,19 +8933,22 @@ static HRESULT WINAPI HTMLAttributeCollection3_removeNamedItem(IHTMLAttributeCol static HRESULT WINAPI HTMLAttributeCollection3_item(IHTMLAttributeCollection3 *iface, LONG index, IHTMLDOMAttribute **ppNodeOut) { HTMLAttributeCollection *This = impl_from_IHTMLAttributeCollection3(iface); + nsIDOMAttr *nsattr = NULL; HTMLDOMAttribute *attr; DISPID id; HRESULT hres; TRACE("(%p)->(%ld %p)\n", This, index, ppNodeOut); - hres = get_attr_dispid_by_idx(This, &index, &id); + hres = get_attr_dispid_by_idx(This, &index, &id, &nsattr); if(hres == DISP_E_UNKNOWNNAME) return E_INVALIDARG; if(FAILED(hres)) return hres; - hres = get_domattr(This, id, NULL, &attr); + hres = get_domattr(This, id, nsattr, NULL, &attr); + if(nsattr) + nsIDOMAttr_Release(nsattr); if(FAILED(hres)) return hres; @@ -8885,17 +8985,20 @@ static inline HTMLAttributeCollection *HTMLAttributeCollection_from_DispatchEx(D static HRESULT HTMLAttributeCollection_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid) { HTMLAttributeCollection *This = HTMLAttributeCollection_from_DispatchEx(dispex); + nsIDOMAttr *nsattr = NULL; HTMLDOMAttribute *attr; LONG pos; HRESULT hres; TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(name), flags, dispid); - hres = get_attr_dispid_by_name(This, name, dispid); + hres = get_attr_dispid_by_name(This, name, dispid, &nsattr); if(FAILED(hres)) return hres; - hres = get_domattr(This, *dispid, &pos, &attr); + hres = get_domattr(This, *dispid, nsattr, &pos, &attr); + if(nsattr) + nsIDOMAttr_Release(nsattr); if(FAILED(hres)) return hres; IHTMLDOMAttribute_Release(&attr->IHTMLDOMAttribute_iface); @@ -8973,6 +9076,7 @@ dispex_static_data_t HTMLAttributeCollection_dispex = { HRESULT HTMLElement_get_attr_col(HTMLDOMNode *iface, HTMLAttributeCollection **ac) { HTMLElement *This = impl_from_HTMLDOMNode(iface); + compat_mode_t compat_mode = dispex_compat_mode(&iface->event_target.dispex); if(This->attrs) { IHTMLAttributeCollection_AddRef(&This->attrs->IHTMLAttributeCollection_iface); @@ -8992,8 +9096,10 @@ HRESULT HTMLElement_get_attr_col(HTMLDOMNode *iface, HTMLAttributeCollection **a This->attrs->elem = This; list_init(&This->attrs->attrs); init_dispatch(&This->attrs->dispex, (IUnknown*)&This->attrs->IHTMLAttributeCollection_iface, - &HTMLAttributeCollection_dispex, get_inner_window(This->node.doc), - dispex_compat_mode(&iface->event_target.dispex)); + &HTMLAttributeCollection_dispex, get_inner_window(This->node.doc), compat_mode); + + if(compat_mode >= COMPAT_MODE_IE9 && This->dom_element) + nsIDOMElement_GetAttributes(This->dom_element, &This->attrs->nsattrs); *ac = This->attrs; return S_OK; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 4392bdaf864..ca14c13bc93 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -631,6 +631,7 @@ HRESULT change_type(VARIANT*,VARIANT*,VARTYPE,IServiceProvider*) DECLSPEC_HIDDEN HRESULT dispex_get_builtin_id(DispatchEx*,BSTR,DWORD,DISPID*) DECLSPEC_HIDDEN; HRESULT dispex_get_dprop_ref(DispatchEx*,const WCHAR*,BOOL,VARIANT**) DECLSPEC_HIDDEN; HRESULT get_dispids(tid_t,DWORD*,DISPID**) DECLSPEC_HIDDEN; +BOOL is_custom_attribute(DispatchEx*,const WCHAR*) DECLSPEC_HIDDEN; HRESULT remove_attribute(DispatchEx*,DISPID,VARIANT_BOOL*) DECLSPEC_HIDDEN; HRESULT dispex_get_dynid(DispatchEx*,const WCHAR*,BOOL,DISPID*) DECLSPEC_HIDDEN; HRESULT dispex_invoke(DispatchEx*,IDispatch*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*) DECLSPEC_HIDDEN; @@ -1353,12 +1354,15 @@ struct HTMLAttributeCollection { LONG ref; + nsIDOMMozNamedAttrMap *nsattrs; HTMLElement *elem; struct list attrs; }; typedef struct { - DispatchEx dispex; + /* valid only when attribute nodes are used (node.nsnode) */ + HTMLDOMNode node; + IHTMLDOMAttribute IHTMLDOMAttribute_iface; IHTMLDOMAttribute2 IHTMLDOMAttribute2_iface; @@ -1376,7 +1380,8 @@ typedef struct { HTMLDOMAttribute *unsafe_impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute*) DECLSPEC_HIDDEN; -HRESULT HTMLDOMAttribute_Create(const WCHAR*,HTMLDocumentNode*,HTMLElement*,DISPID,compat_mode_t,HTMLDOMAttribute**) DECLSPEC_HIDDEN; +HRESULT HTMLDOMAttribute_Create(const WCHAR*,HTMLDocumentNode*,HTMLElement*,DISPID,nsIDOMAttr*, + compat_mode_t,HTMLDOMAttribute**) DECLSPEC_HIDDEN; HRESULT HTMLElement_Create(HTMLDocumentNode*,nsIDOMNode*,BOOL,HTMLElement**) DECLSPEC_HIDDEN; HRESULT HTMLCommentElement_Create(HTMLDocumentNode*,nsIDOMNode*,HTMLElement**) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 7e7d0eb007e..603688b861a 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1355,6 +1355,76 @@ sync_test("elem_props", function() { test_exposed("fileSize", v < 11); }); +sync_test("attr_props", function() { + var elem = document.createElement("style"), attr; + var v = document.documentMode; + elem.setAttribute("id", "test"); + elem.setAttribute("test", "wine"); + elem.setAttribute("z-index", "foobar"); + + function test_exposed(prop, expect) { + if(expect) + ok(prop in attr, prop + " not found in attribute."); + else + ok(!(prop in attr), prop + " found in attribute."); + } + + function test_attr(expando, specified) { + var r = attr.expando; + ok(r === expando, attr.name + " attr.expando = " + r); + r = attr.specified; + ok(r === specified, attr.name + " attr.specified = " + r); + } + + attr = elem.getAttributeNode("id"); + test_exposed("appendChild", true); + test_exposed("attributes", true); + test_exposed("childNodes", true); + test_exposed("cloneNode", true); + test_exposed("compareDocumentPosition", v >= 9); + test_exposed("expando", true); + test_exposed("firstChild", true); + test_exposed("hasChildNodes", true); + test_exposed("insertBefore", true); + test_exposed("isDefaultNamespace", v >= 9); + test_exposed("isEqualNode", v >= 9); + test_exposed("isSameNode", v >= 9); + test_exposed("isSupported", v >= 9); + test_exposed("lastChild", true); + test_exposed("localName", v >= 9); + test_exposed("lookupNamespaceURI", v >= 9); + test_exposed("lookupPrefix", v >= 9); + test_exposed("name", true); + test_exposed("namespaceURI", v >= 9); + test_exposed("nextSibling", true); + test_exposed("nodeName", true); + test_exposed("nodeType", true); + test_exposed("nodeValue", true); + test_exposed("ownerDocument", true); + test_exposed("parentNode", true); + test_exposed("prefix", v >= 9); + test_exposed("previousSibling", true); + test_exposed("removeChild", true); + test_exposed("replaceChild", true); + test_exposed("specified", true); + test_exposed("textContent", v >= 9); + test_exposed("value", true); + test_attr(false, true); + + attr = elem.getAttributeNode("test"); + test_attr(true, true); + + attr = elem.getAttributeNode("z-index"); + test_attr(true, true); + + attr = elem.getAttributeNode("tabIndex"); + if(v < 8) + test_attr(false, false); + else + todo_wine_if(v === 8). + ok(attr === null, "tabIndex attr not null."); +}); + sync_test("doc_props", function() { function test_exposed(prop, expect, is_todo) { var ok_ = is_todo ? todo_wine.ok : ok; From d9f95d4e39cdcce4f9c1ff039e6f5119a57f88ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:07 +0200 Subject: [PATCH 0919/2777] mshtml: Return FALSE from a detached attribute's `specified` prop in old compat modes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlattr.c | 4 ++-- dlls/mshtml/tests/documentmode.js | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/htmlattr.c b/dlls/mshtml/htmlattr.c index cca3d6b9ca0..49c89b4a59e 100644 --- a/dlls/mshtml/htmlattr.c +++ b/dlls/mshtml/htmlattr.c @@ -210,8 +210,8 @@ static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, V } if(!This->elem || !This->elem->dom_element) { - FIXME("NULL This->elem\n"); - return E_UNEXPECTED; + *p = VARIANT_FALSE; + return S_OK; } if(get_dispid_type(This->dispid) != DISPEXPROP_BUILTIN) { diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 603688b861a..1aaeddad018 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1423,6 +1423,9 @@ sync_test("attr_props", function() { else todo_wine_if(v === 8). ok(attr === null, "tabIndex attr not null."); + + attr = document.createAttribute("winetest"); + test_attr(false, v >= 9); }); sync_test("doc_props", function() { From 5694cdd1e8815bbf202dcd4f007ae52cfbc604db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:07 +0200 Subject: [PATCH 0920/2777] mshtml: Do not treat builtin methods as attributes in old compat modes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- Helps with next patch, and it makes no sense to treat them as attributes anyway (they aren't on native either). Note that methods whose slot has been replaced are not treated as builtin methods (that is implicitly tested in next patch). --- dlls/mshtml/dispex.c | 21 +++++++++++++++++++++ dlls/mshtml/htmlelem.c | 4 +++- dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/documentmode.js | 2 +- 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 5a0e88352eb..bc266308d8f 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1915,6 +1915,27 @@ HRESULT dispex_call_builtin(DispatchEx *dispex, DISPID id, DISPPARAMS *dp, return invoke_builtin_function((IDispatch*)&dispex->IDispatchEx_iface, func, dp, res, ei, caller); } +BOOL dispex_is_builtin_method(DispatchEx *dispex, DISPID id) +{ + func_info_t *func; + + if(get_dispid_type(id) != DISPEXPROP_BUILTIN) + return FALSE; + + if(FAILED(get_builtin_func(dispex->info, id, &func)) || func->func_disp_idx < 0) + return FALSE; + + if(dispex->dynamic_data && dispex->dynamic_data->func_disps) { + func_obj_entry_t *entry = dispex->dynamic_data->func_disps + func->func_disp_idx; + + if(entry->func_obj && (V_VT(&entry->val) != VT_DISPATCH || + V_DISPATCH(&entry->val) != (IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface)) + return FALSE; + } + + return TRUE; +} + static VARIANT_BOOL reset_builtin_func(DispatchEx *dispex, func_info_t *func) { func_obj_entry_t *entry; diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 63256946941..e7dd5195b0e 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -8381,7 +8381,9 @@ static inline HRESULT get_attr_dispid_by_name(HTMLAttributeCollection *This, BST hres = IDispatchEx_GetDispID(&This->elem->node.event_target.dispex.IDispatchEx_iface, name, fdexNameCaseInsensitive, id); - return hres; + if(FAILED(hres)) + return hres; + return dispex_is_builtin_method(&This->elem->node.event_target.dispex, *id) ? DISP_E_UNKNOWNNAME : S_OK; } static inline HRESULT get_domattr(HTMLAttributeCollection *This, DISPID id, nsIDOMAttr *nsattr, diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index ca14c13bc93..0af62f970ed 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -646,6 +646,7 @@ compat_mode_t dispex_compat_mode(DispatchEx*) DECLSPEC_HIDDEN; HRESULT dispex_to_string(DispatchEx*,BSTR*) DECLSPEC_HIDDEN; HRESULT dispex_call_builtin(DispatchEx *dispex, DISPID id, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) DECLSPEC_HIDDEN; +BOOL dispex_is_builtin_method(DispatchEx*,DISPID) DECLSPEC_HIDDEN; typedef enum { DISPEXPROP_CUSTOM, diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 1aaeddad018..8a51f87062c 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -317,7 +317,7 @@ sync_test("builtin_toString", function() { if(!localStorage) win_skip("localStorage is buggy and not available, skipping"); test("attribute", document.createAttribute("class"), "Attr"); - if(false /* todo_wine */) test("attributes", e.attributes, "NamedNodeMap"); + test("attributes", e.attributes, "NamedNodeMap"); test("childNodes", document.body.childNodes, "NodeList"); if(clientRects) test("clientRect", clientRects[0], "ClientRect"); if(clientRects) test("clientRects", clientRects, "ClientRectList"); From c09d7d884e55da9fd1cda2322bf4a9d144ad8812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:07 +0200 Subject: [PATCH 0921/2777] mshtml: Fix `expando` and `specified` for attributes in old compat modes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `expando` returns TRUE on non-builtin attributes (builtin attributes are only the builtin accessors, not methods), while `specified` always returns TRUE on any non-builtin attribute as long as it has a user-defined value (e.g. for builtin methods, their slot must be non-default), which is an extension to just checking the dynamic props. Signed-off-by: Gabriel Ivăncescu --- These are tested together in the new test. We have other existing tests dealing with other cases that must still pass, of course. --- dlls/mshtml/dispex.c | 40 +++++++++++++++++++++++++++++++ dlls/mshtml/htmlattr.c | 4 ++-- dlls/mshtml/mshtml_private.h | 2 ++ dlls/mshtml/tests/documentmode.js | 4 ++++ 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index bc266308d8f..503d8a00379 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -1915,6 +1915,22 @@ HRESULT dispex_call_builtin(DispatchEx *dispex, DISPID id, DISPPARAMS *dp, return invoke_builtin_function((IDispatch*)&dispex->IDispatchEx_iface, func, dp, res, ei, caller); } +BOOL dispex_is_builtin_attribute(DispatchEx *dispex, DISPID id) +{ + func_info_t *func; + + if(id == DISPID_VALUE) + return TRUE; + + if(get_dispid_type(id) != DISPEXPROP_BUILTIN) + return FALSE; + + if(FAILED(get_builtin_func(dispex->info, id, &func))) + return FALSE; + + return func->func_disp_idx < 0; +} + BOOL dispex_is_builtin_method(DispatchEx *dispex, DISPID id) { func_info_t *func; @@ -1936,6 +1952,30 @@ BOOL dispex_is_builtin_method(DispatchEx *dispex, DISPID id) return TRUE; } +BOOL dispex_is_builtin_value(DispatchEx *dispex, DISPID id) +{ + func_info_t *func; + + if(get_dispid_type(id) != DISPEXPROP_BUILTIN) + return FALSE; + + if(FAILED(get_builtin_func(dispex->info, id, &func))) + return FALSE; + + if(func->func_disp_idx < 0) + return TRUE; + + if(dispex->dynamic_data && dispex->dynamic_data->func_disps) { + func_obj_entry_t *entry = dispex->dynamic_data->func_disps + func->func_disp_idx; + + if(entry->func_obj && (V_VT(&entry->val) != VT_DISPATCH || + V_DISPATCH(&entry->val) != (IDispatch*)&entry->func_obj->dispex.IDispatchEx_iface)) + return FALSE; + } + + return TRUE; +} + static VARIANT_BOOL reset_builtin_func(DispatchEx *dispex, func_info_t *func) { func_obj_entry_t *entry; diff --git a/dlls/mshtml/htmlattr.c b/dlls/mshtml/htmlattr.c index 49c89b4a59e..1e512fb7c21 100644 --- a/dlls/mshtml/htmlattr.c +++ b/dlls/mshtml/htmlattr.c @@ -214,7 +214,7 @@ static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, V return S_OK; } - if(get_dispid_type(This->dispid) != DISPEXPROP_BUILTIN) { + if(!dispex_is_builtin_value(&This->elem->node.event_target.dispex, This->dispid)) { *p = VARIANT_TRUE; return S_OK; } @@ -386,7 +386,7 @@ static HRESULT WINAPI HTMLDOMAttribute2_get_expando(IHTMLDOMAttribute2 *iface, V TRACE("(%p)->(%p)\n", This, p); - *p = variant_bool(This->elem && get_dispid_type(This->dispid) != DISPEXPROP_BUILTIN); + *p = variant_bool(This->elem && !dispex_is_builtin_attribute(&This->elem->node.event_target.dispex, This->dispid)); return S_OK; } diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 0af62f970ed..1ac6e52c823 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -646,7 +646,9 @@ compat_mode_t dispex_compat_mode(DispatchEx*) DECLSPEC_HIDDEN; HRESULT dispex_to_string(DispatchEx*,BSTR*) DECLSPEC_HIDDEN; HRESULT dispex_call_builtin(DispatchEx *dispex, DISPID id, DISPPARAMS *dp, VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) DECLSPEC_HIDDEN; +BOOL dispex_is_builtin_attribute(DispatchEx*,DISPID); DECLSPEC_HIDDEN; BOOL dispex_is_builtin_method(DispatchEx*,DISPID) DECLSPEC_HIDDEN; +BOOL dispex_is_builtin_value(DispatchEx*,DISPID) DECLSPEC_HIDDEN; typedef enum { DISPEXPROP_CUSTOM, diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 8a51f87062c..a86e1a58d49 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1361,6 +1361,7 @@ sync_test("attr_props", function() { elem.setAttribute("id", "test"); elem.setAttribute("test", "wine"); elem.setAttribute("z-index", "foobar"); + elem.setAttribute("removeAttribute", "funcattr"); function test_exposed(prop, expect) { if(expect) @@ -1417,6 +1418,9 @@ sync_test("attr_props", function() { attr = elem.getAttributeNode("z-index"); test_attr(true, true); + attr = elem.getAttributeNode("removeAttribute"); + test_attr(true, true); + attr = elem.getAttributeNode("tabIndex"); if(v < 8) test_attr(false, false); From 856de3b426bff7d8ee9ca799294eb65021d94379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:07 +0200 Subject: [PATCH 0922/2777] mshtml: Set prototype of AttrPrototype to NodePrototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/mshtml_private.h | 2 +- dlls/mshtml/tests/documentmode.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 1ac6e52c823..c07dc1d13b5 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -405,7 +405,7 @@ PRIVATE_TID_LIST #define COMMON_PROTOTYPE_LIST \ X(History, "History", OmHistory_dispex, Object) \ X(Navigator, "Navigator", OmNavigator_dispex, Object) \ - X(HTMLDOMAttribute, "Attr", HTMLDOMAttribute_dispex, Object) \ + X(HTMLDOMAttribute, "Attr", HTMLDOMAttribute_dispex, HTMLDOMNode) \ X(HTMLDOMChildrenCollection, "NodeList", HTMLDOMChildrenCollection_dispex, Object) \ X(HTMLDOMImplementation, "DOMImplementation", HTMLDOMImplementation_dispex, Object) \ X(HTMLDOMTextNode, "Text", HTMLDOMTextNode_dispex, DOMCharacterData) \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index a86e1a58d49..051574ead74 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1143,6 +1143,7 @@ sync_test("builtin_prototypes", function() { } }else { var protos = [ + [ "Attr", "Node" ], [ "CharacterData", "Node" ], [ "ClientRect", "Object" ], [ "ClientRectList", "Object" ], @@ -1270,6 +1271,7 @@ sync_test("builtin_prototypes", function() { "rowSpan","vAlign","width" ]; protos = [ + [ "Attr", ["expando","name","specified","value"], Node_props ], [ "CharacterData", ["data","length","appendData"], Node_props ], [ "Comment", ["text"], ["insertData","replaceData","substringData"] ], [ "CSSStyleRule", ["readOnly","selectorText","style"], ["cssText","parentRule","parentStyleSheet","type" ] ], From 7831571c3f22fed8e4e54c6abed3e409be04dd18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:07 +0200 Subject: [PATCH 0923/2777] jscript: Allow objects that expose "length" prop for Function.apply under certain conditions. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Behavior depends on mode. Javascript used inside mshtml allows non-JS objects that expose "length" to be used in apply(). For ES5 and above, even JS objects that expose "length" are allowed. Javascript not in HTML mode does not, however. Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/function.c | 126 ++++++++++++++++++++++++++++-- dlls/jscript/tests/api.js | 2 + dlls/mshtml/tests/documentmode.js | 66 ++++++++++++++++ 3 files changed, 187 insertions(+), 7 deletions(-) diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 2023ce27720..69b7973fe04 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -374,6 +374,109 @@ static HRESULT array_to_args(script_ctx_t *ctx, jsdisp_t *arg_array, unsigned *a return S_OK; } +static HRESULT disp_to_args(script_ctx_t *ctx, IDispatch *disp, unsigned *argc, jsval_t **ret) +{ + IDispatchEx *dispex; + DWORD length, i; + jsval_t *argv; + DISPID dispid; + EXCEPINFO ei; + UINT err = 0; + HRESULT hres; + VARIANT var; + BSTR name; + + if(!(name = SysAllocString(L"length"))) + return E_OUTOFMEMORY; + hres = IDispatch_QueryInterface(disp, &IID_IDispatchEx, (void**)&dispex); + if(SUCCEEDED(hres) && dispex) + hres = IDispatchEx_GetDispID(dispex, name, fdexNameCaseSensitive, &dispid); + else { + hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, &dispid); + dispex = NULL; + } + SysFreeString(name); + if(SUCCEEDED(hres) && dispid == DISPID_UNKNOWN) + hres = DISP_E_UNKNOWNNAME; + if(FAILED(hres)) { + if(hres == DISP_E_UNKNOWNNAME) + hres = JS_E_JSCRIPT_EXPECTED; + goto fail; + } + + if(dispex) + hres = IDispatchEx_InvokeEx(dispex, dispid, ctx->lcid, DISPATCH_PROPERTYGET, NULL, + &var, &ei, &ctx->jscaller->IServiceProvider_iface); + else + hres = IDispatch_Invoke(disp, dispid, &IID_NULL, ctx->lcid, DISPATCH_PROPERTYGET, NULL, &var, &ei, &err); + if(FAILED(hres)) { + if(hres == DISP_E_EXCEPTION) + disp_fill_exception(ctx, &ei); + if(hres == DISP_E_MEMBERNOTFOUND) + hres = JS_E_JSCRIPT_EXPECTED; + goto fail; + } + + if(FAILED(VariantChangeType(&var, &var, 0, VT_UI4))) { + VariantClear(&var); + hres = JS_E_JSCRIPT_EXPECTED; + goto fail; + } + length = V_UI4(&var); + + argv = malloc(length * sizeof(*argv)); + if(!argv) { + hres = E_OUTOFMEMORY; + goto fail; + } + + for(i = 0; i < length; i++) { + WCHAR buf[12]; + + swprintf(buf, ARRAY_SIZE(buf), L"%u", i); + if(!(name = SysAllocString(buf))) + hres = E_OUTOFMEMORY; + else { + if(dispex) + hres = IDispatchEx_GetDispID(dispex, name, fdexNameCaseSensitive, &dispid); + else + hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &name, 1, 0, &dispid); + SysFreeString(name); + } + if(SUCCEEDED(hres)) { + if(dispex) + hres = IDispatchEx_InvokeEx(dispex, dispid, ctx->lcid, DISPATCH_PROPERTYGET, NULL, + &var, &ei, &ctx->jscaller->IServiceProvider_iface); + else + hres = IDispatch_Invoke(disp, dispid, &IID_NULL, ctx->lcid, DISPATCH_PROPERTYGET, NULL, &var, &ei, &err); + if(SUCCEEDED(hres)) { + hres = variant_to_jsval(ctx, &var, &argv[i]); + VariantClear(&var); + }else if(hres == DISP_E_EXCEPTION) { + disp_fill_exception(ctx, &ei); + } + } + if(FAILED(hres)) { + if(hres == DISP_E_UNKNOWNNAME || hres == DISP_E_MEMBERNOTFOUND) { + argv[i] = jsval_undefined(); + continue; + } + while(i--) + jsval_release(argv[i]); + free(argv); + goto fail; + } + } + + *argc = length; + *ret = argv; + hres = S_OK; +fail: + if(dispex) + IDispatchEx_Release(dispex); + return hres; +} + static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsval_t this_val = jsval_undefined(); @@ -405,22 +508,31 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi if(argc >= 2) { jsdisp_t *arg_array = NULL; + IDispatch *obj = NULL; if(is_object_instance(argv[1])) { - arg_array = iface_to_jsdisp(get_object(argv[1])); - if(arg_array && - (!is_class(arg_array, JSCLASS_ARRAY) && !is_class(arg_array, JSCLASS_ARGUMENTS) )) { - jsdisp_release(arg_array); - arg_array = NULL; + obj = get_object(argv[1]); + arg_array = iface_to_jsdisp(obj); + + if(ctx->version < SCRIPTLANGUAGEVERSION_ES5) { + if(!arg_array) { + if(!ctx->html_mode) + obj = NULL; + }else if(!is_class(arg_array, JSCLASS_ARRAY) && !is_class(arg_array, JSCLASS_ARGUMENTS)) { + jsdisp_release(arg_array); + arg_array = NULL; + obj = NULL; + } } } if(arg_array) { hres = array_to_args(ctx, arg_array, &cnt, &args); jsdisp_release(arg_array); + }else if(obj) { + hres = disp_to_args(ctx, obj, &cnt, &args); }else { - FIXME("throw TypeError\n"); - hres = E_FAIL; + hres = JS_E_JSCRIPT_EXPECTED; } } diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index a3f81da6f60..1aabcd0edf2 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -2865,6 +2865,8 @@ testFunctionThis("toString"); testFunctionThis("call"); testFunctionThis("apply"); +testException(function() {(function (a, b) {}).apply(null, testObj)}, "E_JSCRIPT_EXPECTED"); + function testArrayHostThis(func) { testException(function() { Array.prototype[func].call(testObj); }, "E_JSCRIPT_EXPECTED"); } diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 051574ead74..a6db1219fbb 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -518,6 +518,72 @@ sync_test("builtin_obj", function() { f.call = function() { }; ok(f.apply === 0, "changed f.apply = ", f.apply); ok(f.call instanceof Function, "changed f.call not instance of Function"); + + e = Array.isArray(document.body.childNodes); + ok(e === false, "isArray(childNodes) returned " + e); + } + + (function(a, b, c) { + ok(a === document.body.childNodes[0], "a = " + a); + ok(b === document.body.childNodes[1], "b = " + b); + ok(c === document.body.childNodes[2], "c = " + c); + }).apply(null, document.body.childNodes); + + elem[0] = "a"; + elem[1] = "b"; + if(v < 9) { + try { + (function(a, b) {}).apply(null, elem); + }catch(ex) { + e = ex.number; + } + todo_wine. + ok(e === 0xa13a4 - 0x80000000, "[function.apply with elem without length] e = " + e); + }else { + (function(a, b) { + ok(a === undefined, "a = " + a); + ok(b === undefined, "b = " + b); + }).apply(null, elem); + } + + elem.length = 2; + (function(a, b) { + ok(a === "a", "a = " + a); + ok(b === "b", "b = " + b); + }).apply(null, elem); + + elem = new Object; + elem[0] = "c"; + elem[1] = "d"; + if(v < 9) { + try { + (function(c, d) {}).apply(null, elem); + }catch(ex) { + e = ex.number; + } + todo_wine. + ok(e === 0xa13a4 - 0x80000000, "[function.apply with Object without length] e = " + e); + }else { + (function(c, d) { + ok(c === undefined, "c = " + c); + ok(d === undefined, "d = " + d); + }).apply(null, elem); + } + + elem.length = 2; + if(v < 9) { + try { + (function(c, d) {}).apply(null, elem); + }catch(ex) { + e = ex.number; + } + todo_wine. + ok(e === 0xa13a4 - 0x80000000, "[function.apply with Object with length] e = " + e); + }else { + (function(c, d) { + ok(c === "c", "c = " + c); + ok(d === "d", "d = " + d); + }).apply(null, elem); } }); From c6bd80ba47f27d9a7afc6244da851de56628b4d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:07 +0200 Subject: [PATCH 0924/2777] jscript: Return proper error when passing wrong type to Function.apply. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/error.c | 1 + dlls/jscript/function.c | 8 ++++---- dlls/jscript/jscript.h | 1 + dlls/jscript/jscript.rc | 1 + dlls/jscript/resource.h | 1 + dlls/mshtml/tests/documentmode.js | 3 --- 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index 2823acefba4..82caef59bb6 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -477,6 +477,7 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_JSCRIPT_EXPECTED: case JS_E_ENUMERATOR_EXPECTED: case JS_E_REGEXP_EXPECTED: + case JS_E_ARRAY_OR_ARGS_EXPECTED: case JS_E_ARRAY_EXPECTED: case JS_E_CYCLIC_PROTO_VALUE: case JS_E_CANNOT_CREATE_FOR_NONEXTENSIBLE: diff --git a/dlls/jscript/function.c b/dlls/jscript/function.c index 69b7973fe04..f7f8d6bf6cd 100644 --- a/dlls/jscript/function.c +++ b/dlls/jscript/function.c @@ -400,7 +400,7 @@ static HRESULT disp_to_args(script_ctx_t *ctx, IDispatch *disp, unsigned *argc, hres = DISP_E_UNKNOWNNAME; if(FAILED(hres)) { if(hres == DISP_E_UNKNOWNNAME) - hres = JS_E_JSCRIPT_EXPECTED; + hres = JS_E_ARRAY_OR_ARGS_EXPECTED; goto fail; } @@ -413,13 +413,13 @@ static HRESULT disp_to_args(script_ctx_t *ctx, IDispatch *disp, unsigned *argc, if(hres == DISP_E_EXCEPTION) disp_fill_exception(ctx, &ei); if(hres == DISP_E_MEMBERNOTFOUND) - hres = JS_E_JSCRIPT_EXPECTED; + hres = JS_E_ARRAY_OR_ARGS_EXPECTED; goto fail; } if(FAILED(VariantChangeType(&var, &var, 0, VT_UI4))) { VariantClear(&var); - hres = JS_E_JSCRIPT_EXPECTED; + hres = JS_E_ARRAY_OR_ARGS_EXPECTED; goto fail; } length = V_UI4(&var); @@ -532,7 +532,7 @@ static HRESULT Function_apply(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi }else if(obj) { hres = disp_to_args(ctx, obj, &cnt, &args); }else { - hres = JS_E_JSCRIPT_EXPECTED; + hres = ctx->html_mode ? JS_E_ARRAY_OR_ARGS_EXPECTED : JS_E_JSCRIPT_EXPECTED; } } diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 6da6e6e153c..3299152056a 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -639,6 +639,7 @@ static inline DWORD make_grfdex(script_ctx_t *ctx, DWORD flags) #define JS_E_INVALID_URI_CHAR MAKE_JSERROR(IDS_URI_INVALID_CHAR) #define JS_E_FRACTION_DIGITS_OUT_OF_RANGE MAKE_JSERROR(IDS_FRACTION_DIGITS_OUT_OF_RANGE) #define JS_E_PRECISION_OUT_OF_RANGE MAKE_JSERROR(IDS_PRECISION_OUT_OF_RANGE) +#define JS_E_ARRAY_OR_ARGS_EXPECTED MAKE_JSERROR(IDS_ARRAY_OR_ARGS_EXPECTED) #define JS_E_INVALID_LENGTH MAKE_JSERROR(IDS_INVALID_LENGTH) #define JS_E_ARRAY_EXPECTED MAKE_JSERROR(IDS_ARRAY_EXPECTED) #define JS_E_CYCLIC_PROTO_VALUE MAKE_JSERROR(IDS_CYCLIC_PROTO_VALUE) diff --git a/dlls/jscript/jscript.rc b/dlls/jscript/jscript.rc index 5a9f88f5689..f2476528259 100644 --- a/dlls/jscript/jscript.rc +++ b/dlls/jscript/jscript.rc @@ -68,6 +68,7 @@ STRINGTABLE IDS_URI_INVALID_CHAR "URI to be encoded contains invalid characters" IDS_FRACTION_DIGITS_OUT_OF_RANGE "Number of fraction digits is out of range" IDS_PRECISION_OUT_OF_RANGE "Precision is out of range" + IDS_ARRAY_OR_ARGS_EXPECTED "Array or arguments object expected" IDS_INVALID_LENGTH "Array length must be a finite positive integer" IDS_ARRAY_EXPECTED "Array object expected" IDS_INVALID_WRITABLE_PROP_DESC "'writable' attribute on the property descriptor cannot be set to 'true' on this object" diff --git a/dlls/jscript/resource.h b/dlls/jscript/resource.h index 396346e2fbc..bb33a407de9 100644 --- a/dlls/jscript/resource.h +++ b/dlls/jscript/resource.h @@ -66,6 +66,7 @@ #define IDS_URI_INVALID_CODING 0x13A1 #define IDS_FRACTION_DIGITS_OUT_OF_RANGE 0x13A2 #define IDS_PRECISION_OUT_OF_RANGE 0x13A3 +#define IDS_ARRAY_OR_ARGS_EXPECTED 0x13A4 #define IDS_INVALID_LENGTH 0x13A5 #define IDS_ARRAY_EXPECTED 0x13A7 #define IDS_INVALID_WRITABLE_PROP_DESC 0x13AC diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index a6db1219fbb..f59a5e6ea3e 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -537,7 +537,6 @@ sync_test("builtin_obj", function() { }catch(ex) { e = ex.number; } - todo_wine. ok(e === 0xa13a4 - 0x80000000, "[function.apply with elem without length] e = " + e); }else { (function(a, b) { @@ -561,7 +560,6 @@ sync_test("builtin_obj", function() { }catch(ex) { e = ex.number; } - todo_wine. ok(e === 0xa13a4 - 0x80000000, "[function.apply with Object without length] e = " + e); }else { (function(c, d) { @@ -577,7 +575,6 @@ sync_test("builtin_obj", function() { }catch(ex) { e = ex.number; } - todo_wine. ok(e === 0xa13a4 - 0x80000000, "[function.apply with Object with length] e = " + e); }else { (function(c, d) { From ea52be00662783b4b82c57b4cf5eca4603992276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:07 +0200 Subject: [PATCH 0925/2777] jscript: Fallback to Object's toString for Arrays when 'this' isn't an array in ES5 mode. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/array.c | 8 +++++- dlls/jscript/jscript.h | 1 + dlls/jscript/object.c | 2 +- dlls/jscript/tests/api.js | 1 + dlls/mshtml/tests/documentmode.js | 46 +++++++++++++++++++++++++++++++ 5 files changed, 56 insertions(+), 2 deletions(-) diff --git a/dlls/jscript/array.c b/dlls/jscript/array.c index 12a09e020df..e7d9feea823 100644 --- a/dlls/jscript/array.c +++ b/dlls/jscript/array.c @@ -944,8 +944,14 @@ static HRESULT Array_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsi TRACE("\n"); array = array_this(vthis); - if(!array) + if(!array) { + if(ctx->version >= SCRIPTLANGUAGEVERSION_ES5) { + if(is_undefined(vthis) || is_null(vthis)) + return JS_E_OBJECT_EXPECTED; + return Object_toString(ctx, vthis, flags, argc, argv, r); + } return JS_E_ARRAY_EXPECTED; + } return array_join(ctx, &array->dispex, array->length, L",", 1, to_string, r); } diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 3299152056a..f77905aca0d 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -573,6 +573,7 @@ unsigned array_get_length(jsdisp_t*) DECLSPEC_HIDDEN; HRESULT localize_number(script_ctx_t*,DOUBLE,BOOL,jsstr_t**) DECLSPEC_HIDDEN; HRESULT JSGlobal_eval(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; +HRESULT Object_toString(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; HRESULT Object_get_proto_(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; HRESULT Object_set_proto_(script_ctx_t*,jsval_t,WORD,unsigned,jsval_t*,jsval_t*) DECLSPEC_HIDDEN; diff --git a/dlls/jscript/object.c b/dlls/jscript/object.c index 8a2399d7ab3..9ad30138229 100644 --- a/dlls/jscript/object.c +++ b/dlls/jscript/object.c @@ -24,7 +24,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(jscript); -static HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, +HRESULT Object_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r) { jsdisp_t *jsdisp; diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index 1aabcd0edf2..5f078153319 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -2654,6 +2654,7 @@ testException(function() {date.setTime();}, "E_ARG_NOT_OPT"); testException(function() {date.setYear();}, "E_ARG_NOT_OPT"); testException(function() {arr.test();}, "E_NO_PROPERTY"); testException(function() {[1,2,3].sort(nullDisp);}, "E_JSCRIPT_EXPECTED"); +testException(function() {var o = new Object(); o.length = 1; o[0] = "a"; Array.prototype.toString.call(o);}, "E_NOT_ARRAY"); testException(function() {var o = new Object(); o.length = 1; o[0] = "a"; Array.prototype.toLocaleString.call(o);}, "E_NOT_ARRAY"); testException(function() {Number.prototype.toString.call(arr);}, "E_NOT_NUM"); testException(function() {Number.prototype.toFixed.call(arr);}, "E_NOT_NUM"); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index f59a5e6ea3e..d5f995484f0 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -521,6 +521,52 @@ sync_test("builtin_obj", function() { e = Array.isArray(document.body.childNodes); ok(e === false, "isArray(childNodes) returned " + e); + e = Array.prototype.toString.call(Number); + ok(e === "[object Function]", "Array.toString(Number) = " + e); + } + + function test_toString(msg, constr, err) { + var e = 0; + if(typeof err == "string") { + e = constr.prototype.toString.call(document.body); + ok(e === err, msg + ".toString(body) = " + e); + return; + } + try { + constr.prototype.toString.call(document.body); + }catch(ex) { + e = ex.number; + } + ok(e === err - 0x80000000, "[" + msg + ".toString(body)] e = " + e); + } + + test_toString("Array", Array, v < 9 ? 0xa13a7 : "[object HTMLBodyElement]"); + test_toString("Boolean", Boolean, 0xa1392); + test_toString("Date", Date, 0xa138e); + test_toString("RegExp", RegExp, 0xa1398); + test_toString("Number", Number, 0xa1389); + + if(v >= 9) { + var obj = { length: 2 }; + obj[0] = "foo"; + obj[1] = "bar"; + e = Array.prototype.toString.call(obj); + ok(e === "[object Object]", "Array.toString(array-like object) = " + e); + + obj = Object.create(null); + obj.length = 2; + obj[0] = "foo"; + obj[1] = "bar"; + e = Array.prototype.toString.call(obj); + ok(e === "[object Object]", "Array.toString(array-like object with no prototype) = " + e); + + e = 0; + try { + Array.prototype.toString.call(null); + }catch(ex) { + e = ex.number; + } + ok(e === 0xa138f - 0x80000000, "Array.toString(null) e = " + e); } (function(a, b, c) { From 8f0561553bd85ed9942db937fa5518478d7abe97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:08 +0200 Subject: [PATCH 0926/2777] jscript: Fix error value when passing non-string 'this' to String's toString. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/error.c | 1 + dlls/jscript/jscript.h | 1 + dlls/jscript/jscript.rc | 1 + dlls/jscript/resource.h | 1 + dlls/jscript/string.c | 2 +- dlls/jscript/tests/api.js | 3 +++ dlls/mshtml/tests/documentmode.js | 1 + 7 files changed, 9 insertions(+), 1 deletion(-) diff --git a/dlls/jscript/error.c b/dlls/jscript/error.c index 82caef59bb6..d4c80a03755 100644 --- a/dlls/jscript/error.c +++ b/dlls/jscript/error.c @@ -467,6 +467,7 @@ jsdisp_t *create_builtin_error(script_ctx_t *ctx) case JS_E_MISSING_ARG: case JS_E_OBJECT_NOT_COLLECTION: case JS_E_FUNCTION_EXPECTED: + case JS_E_STRING_EXPECTED: case JS_E_DATE_EXPECTED: case JS_E_NUMBER_EXPECTED: case JS_E_OBJECT_EXPECTED: diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index f77905aca0d..22cc3773eb6 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -623,6 +623,7 @@ static inline DWORD make_grfdex(script_ctx_t *ctx, DWORD flags) #define JS_E_DISABLED_CC MAKE_JSERROR(IDS_DISABLED_CC) #define JS_E_EXPECTED_AT MAKE_JSERROR(IDS_EXPECTED_AT) #define JS_E_FUNCTION_EXPECTED MAKE_JSERROR(IDS_NOT_FUNC) +#define JS_E_STRING_EXPECTED MAKE_JSERROR(IDS_NOT_STRING) #define JS_E_DATE_EXPECTED MAKE_JSERROR(IDS_NOT_DATE) #define JS_E_NUMBER_EXPECTED MAKE_JSERROR(IDS_NOT_NUM) #define JS_E_OBJECT_EXPECTED MAKE_JSERROR(IDS_OBJECT_EXPECTED) diff --git a/dlls/jscript/jscript.rc b/dlls/jscript/jscript.rc index f2476528259..7e4927eba0c 100644 --- a/dlls/jscript/jscript.rc +++ b/dlls/jscript/jscript.rc @@ -51,6 +51,7 @@ STRINGTABLE IDS_DISABLED_CC "Conditional compilation is turned off" IDS_EXPECTED_AT "Expected '@'" IDS_NOT_FUNC "Function expected" + IDS_NOT_STRING "'[object]' is not a string object" IDS_NOT_DATE "'[object]' is not a date object" IDS_NOT_NUM "Number expected" IDS_OBJECT_EXPECTED "Object expected" diff --git a/dlls/jscript/resource.h b/dlls/jscript/resource.h index bb33a407de9..31822bffaea 100644 --- a/dlls/jscript/resource.h +++ b/dlls/jscript/resource.h @@ -49,6 +49,7 @@ #define IDS_DISABLED_CC 0x0406 #define IDS_EXPECTED_AT 0x0408 #define IDS_NOT_FUNC 0x138A +#define IDS_NOT_STRING 0x138D #define IDS_NOT_DATE 0x138E #define IDS_NOT_NUM 0x1389 #define IDS_OBJECT_EXPECTED 0x138F diff --git a/dlls/jscript/string.c b/dlls/jscript/string.c index 4faf8ea56c9..da7ee1aad1e 100644 --- a/dlls/jscript/string.c +++ b/dlls/jscript/string.c @@ -89,7 +89,7 @@ static HRESULT stringobj_to_string(jsval_t vthis, jsval_t *r) if(!(string = string_this(vthis))) { WARN("this is not a string object\n"); - return E_FAIL; + return JS_E_STRING_EXPECTED; } if(r) diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js index 5f078153319..84fd14302c1 100644 --- a/dlls/jscript/tests/api.js +++ b/dlls/jscript/tests/api.js @@ -2584,6 +2584,7 @@ var exception_array = { E_INVALID_LENGTH: { type: "RangeError", number: -2146823259 }, E_NOT_DATE: { type: "TypeError", number: -2146823282 }, + E_NOT_STRING: { type: "TypeError", number: -2146823283 }, E_NOT_BOOL: { type: "TypeError", number: -2146823278 }, E_ARG_NOT_OPT: { type: "TypeError", number: -2146827839 }, E_NO_PROPERTY: { type: "TypeError", number: -2146827850 }, @@ -2675,6 +2676,8 @@ testException(function() {(new Object()) instanceof nullDisp;}, "E_NOT_FUNC"); testException(function() {nullDisp instanceof Object;}, "E_OBJECT_EXPECTED"); testException(function() {Function.prototype.apply.call(nullDisp, Object, []);}, "E_OBJECT_REQUIRED"); testException(function() {Function.prototype.call.call(nullDisp, Object);}, "E_OBJECT_REQUIRED"); +testException(function() {String.prototype.toString.call(null);}, "E_NOT_STRING"); +testException(function() {String.prototype.toString.call([]);}, "E_NOT_STRING"); testException(function() {"test" in 3;}, "E_OBJECT_EXPECTED"); testException(function() {"test" in null;}, "E_OBJECT_EXPECTED"); testException(function() {"test" in nullDisp;}, "E_OBJECT_EXPECTED"); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index d5f995484f0..f9c8d708b4b 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -545,6 +545,7 @@ sync_test("builtin_obj", function() { test_toString("Date", Date, 0xa138e); test_toString("RegExp", RegExp, 0xa1398); test_toString("Number", Number, 0xa1389); + test_toString("String", String, 0xa138d); if(v >= 9) { var obj = { length: 2 }; From f9a87834726ded24c5eab39cceefb8d5b1c9183a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:08 +0200 Subject: [PATCH 0927/2777] mshtml: Implement DOMParser constructor and instance object. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/dispex.c | 16 ++- dlls/mshtml/htmlwindow.c | 5 +- dlls/mshtml/mshtml_private.h | 5 + dlls/mshtml/omnavigator.c | 171 ++++++++++++++++++++++++++++++ dlls/mshtml/tests/documentmode.js | 12 +++ dlls/mshtml/tests/es5.js | 11 ++ 6 files changed, 216 insertions(+), 4 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 503d8a00379..5567f13bc01 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -2603,6 +2603,7 @@ static IDispatch *get_proxy_constructor_disp(HTMLInnerWindow *window, prototype_ dispex_static_data_t *dispex; const void *vtbl; } ctors[] = { + { PROTO_ID_DOMParser, &DOMParserCtor_dispex, &legacy_ctor_vtbl }, { PROTO_ID_HTMLImgElement, &HTMLImageCtor_dispex, &HTMLImageElementFactoryVtbl }, { PROTO_ID_HTMLOptionElement, &HTMLOptionCtor_dispex, &HTMLOptionElementFactoryVtbl }, { PROTO_ID_HTMLXMLHttpRequest, &HTMLXMLHttpRequestFactory_dispex, &HTMLXMLHttpRequestFactoryVtbl } @@ -3145,11 +3146,16 @@ static IDispatch* WINAPI WineDispatchProxyPrivate_GetDefaultPrototype(IWineDispa static IDispatch* WINAPI WineDispatchProxyPrivate_GetDefaultConstructor(IWineDispatchProxyPrivate *iface, IWineDispatchProxyPrivate *window, struct proxy_prototypes *prots) { + static const prototype_id_t special_ctors[] = { + PROTO_ID_DOMParser, + PROTO_ID_HTMLXMLHttpRequest + }; DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); struct proxy_prototype *prot = proxy_prototype_from_IUnknown(This->outer); struct proxy_ctor *ctor; prototype_id_t prot_id; IDispatch **entry; + unsigned i; prot_id = CONTAINING_RECORD(prot->dispex.info->desc, struct prototype_static_data, dispex) - prototype_static_data; @@ -3159,9 +3165,12 @@ static IDispatch* WINAPI WineDispatchProxyPrivate_GetDefaultConstructor(IWineDis return *entry; } - /* XMLHttpRequest is a special case */ - if(prot_id == PROTO_ID_HTMLXMLHttpRequest) { - IDispatch *disp = get_proxy_constructor_disp(CONTAINING_RECORD((IDispatchEx*)window, HTMLWindow, IDispatchEx_iface)->inner_window, prot_id); + for(i = 0; i < ARRAY_SIZE(special_ctors); i++) { + IDispatch *disp; + if(prot_id != special_ctors[i]) + continue; + + disp = get_proxy_constructor_disp(CONTAINING_RECORD((IDispatchEx*)window, HTMLWindow, IDispatchEx_iface)->inner_window, prot_id); if(disp) { *entry = This->proxy->lpVtbl->CreateConstructor(This->proxy, disp, proxy_ctor_dispex[prot_id - LEGACY_PROTOTYPE_COUNT].name); IDispatch_Release(disp); @@ -3170,6 +3179,7 @@ static IDispatch* WINAPI WineDispatchProxyPrivate_GetDefaultConstructor(IWineDis return *entry; } } + break; } if(!(ctor = malloc(sizeof(*ctor)))) diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 55b741b2bc8..dd0f382ebb6 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -223,13 +223,16 @@ static ULONG WINAPI legacy_ctor_Release(IUnknown *iface) TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { + /* Proxy constructor disps hold ref to window, others are always detached first */ + if(This->window) + IHTMLWindow2_Release(&This->window->base.IHTMLWindow2_iface); release_dispex(&This->dispex); free(This); } return ref; } -static const IUnknownVtbl legacy_ctor_vtbl = { +const IUnknownVtbl legacy_ctor_vtbl = { legacy_ctor_QueryInterface, legacy_ctor_AddRef, legacy_ctor_Release diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index c07dc1d13b5..5cf88477f0b 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -183,6 +183,7 @@ typedef struct ScriptHost ScriptHost; XDIID(DispDOMStorageEvent) \ XDIID(DispDOMUIEvent) \ XDIID(DispDOMDocumentType) \ + XDIID(DispDOMParser) \ XDIID(DispHTMLAnchorElement) \ XDIID(DispHTMLAreaElement) \ XDIID(DispHTMLAttributeCollection) \ @@ -247,6 +248,7 @@ typedef struct ScriptHost ScriptHost; XIID(IDOMStorageEvent) \ XIID(IDOMUIEvent) \ XIID(IDOMDocumentType) \ + XIID(IDOMParser) \ XIID(IDocumentEvent) \ XIID(IDocumentRange) \ XIID(IDocumentSelector) \ @@ -460,6 +462,7 @@ PRIVATE_TID_LIST #define PROXY_PROTOTYPE_LIST \ X(Console, "Console", console_dispex, Object) \ + X(DOMParser, "DOMParser", DOMParser_dispex, Object) \ X(DOMEvent, "Event", DOMEvent_dispex, Object) \ X(DOMCustomEvent, "CustomEvent", DOMCustomEvent_dispex, DOMEvent) \ X(DOMKeyboardEvent, "KeyboardEvent", DOMKeyboardEvent_dispex, DOMUIEvent) \ @@ -1686,6 +1689,7 @@ extern HINSTANCE hInst DECLSPEC_HIDDEN; void create_console(HTMLInnerWindow *window, IWineMSHTMLConsole **ret) DECLSPEC_HIDDEN; HRESULT create_media_query_list(HTMLWindow *window, BSTR media_query, IDispatch **ret) DECLSPEC_HIDDEN; +extern const IUnknownVtbl legacy_ctor_vtbl DECLSPEC_HIDDEN; extern const IHTMLImageElementFactoryVtbl HTMLImageElementFactoryVtbl DECLSPEC_HIDDEN; extern const IHTMLOptionElementFactoryVtbl HTMLOptionElementFactoryVtbl DECLSPEC_HIDDEN; extern const IHTMLXMLHttpRequestFactoryVtbl HTMLXMLHttpRequestFactoryVtbl DECLSPEC_HIDDEN; @@ -1695,6 +1699,7 @@ extern dispex_static_data_t HTMLXMLHttpRequestFactory_dispex DECLSPEC_HIDDEN; extern dispex_static_data_t HTMLImageCtor_dispex DECLSPEC_HIDDEN; extern dispex_static_data_t HTMLOptionCtor_dispex DECLSPEC_HIDDEN; extern dispex_static_data_t HTMLXMLHttpRequestCtor_dispex DECLSPEC_HIDDEN; +extern dispex_static_data_t DOMParserCtor_dispex DECLSPEC_HIDDEN; #define X(id, name, dispex, proto_id) extern dispex_static_data_t dispex DECLSPEC_HIDDEN; LEGACY_PROTOTYPE_LIST diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 036192aefdf..bf1b01dc93b 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -351,6 +351,177 @@ void detach_dom_implementation(IHTMLDOMImplementation *iface) dom_implementation->browser = NULL; } +struct dom_parser { + IDOMParser IDOMParser_iface; + DispatchEx dispex; + LONG ref; +}; + +static inline struct dom_parser *impl_from_IDOMParser(IDOMParser *iface) +{ + return CONTAINING_RECORD(iface, struct dom_parser, IDOMParser_iface); +} + +static HRESULT WINAPI DOMParser_QueryInterface(IDOMParser *iface, REFIID riid, void **ppv) +{ + struct dom_parser *This = impl_from_IDOMParser(iface); + + TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); + + if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IDOMParser, riid)) { + *ppv = &This->IDOMParser_iface; + }else if(dispex_query_interface(&This->dispex, riid, ppv)) { + return *ppv ? S_OK : E_NOINTERFACE; + }else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI DOMParser_AddRef(IDOMParser *iface) +{ + struct dom_parser *This = impl_from_IDOMParser(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI DOMParser_Release(IDOMParser *iface) +{ + struct dom_parser *This = impl_from_IDOMParser(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if(!ref) { + release_dispex(&This->dispex); + free(This); + } + + return ref; +} + +static HRESULT WINAPI DOMParser_GetTypeInfoCount(IDOMParser *iface, UINT *pctinfo) +{ + struct dom_parser *This = impl_from_IDOMParser(iface); + + return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI DOMParser_GetTypeInfo(IDOMParser *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + struct dom_parser *This = impl_from_IDOMParser(iface); + + return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI DOMParser_GetIDsOfNames(IDOMParser *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + struct dom_parser *This = impl_from_IDOMParser(iface); + + return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI DOMParser_Invoke(IDOMParser *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + struct dom_parser *This = impl_from_IDOMParser(iface); + + return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI DOMParser_parseFromString(IDOMParser *iface, BSTR string, BSTR mimeType, IHTMLDocument2 **ppNode) +{ + struct dom_parser *This = impl_from_IDOMParser(iface); + + FIXME("(%p)->(%s %s %p)\n", This, debugstr_w(string), debugstr_w(mimeType), ppNode); + + return E_NOTIMPL; +} + +static const IDOMParserVtbl DOMParserVtbl = { + DOMParser_QueryInterface, + DOMParser_AddRef, + DOMParser_Release, + DOMParser_GetTypeInfoCount, + DOMParser_GetTypeInfo, + DOMParser_GetIDsOfNames, + DOMParser_Invoke, + DOMParser_parseFromString +}; + +static const tid_t DOMParser_iface_tids[] = { + IDOMParser_tid, + 0 +}; + +dispex_static_data_t DOMParser_dispex = { + L"DOMParser", + NULL, + PROTO_ID_DOMParser, + DispDOMParser_tid, + DOMParser_iface_tids +}; + +static HRESULT DOMParserCtor_value(DispatchEx *iface, LCID lcid, WORD flags, DISPPARAMS *params, + VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + struct legacy_ctor *This = CONTAINING_RECORD(iface, struct legacy_ctor, dispex); + struct dom_parser *ret; + + TRACE("\n"); + + switch(flags) { + case DISPATCH_METHOD|DISPATCH_PROPERTYGET: + if(!res) + return E_INVALIDARG; + /* fall through */ + case DISPATCH_METHOD: + case DISPATCH_CONSTRUCT: + break; + default: + return legacy_ctor_value(iface, lcid, flags, params, res, ei, caller); + } + + if(!(ret = calloc(1, sizeof(*ret)))) + return E_OUTOFMEMORY; + + ret->IDOMParser_iface.lpVtbl = &DOMParserVtbl; + ret->ref = 1; + init_dispatch(&ret->dispex, (IUnknown*)&ret->IDOMParser_iface, &DOMParser_dispex, + This->window, dispex_compat_mode(&This->dispex)); + + V_VT(res) = VT_DISPATCH; + V_DISPATCH(res) = (IDispatch*)&ret->IDOMParser_iface; + return S_OK; +} + +static const dispex_static_data_vtbl_t DOMParserCtor_dispex_vtbl = { + DOMParserCtor_value, + legacy_ctor_get_dispid, + legacy_ctor_get_name, + legacy_ctor_invoke, + legacy_ctor_delete +}; + +dispex_static_data_t DOMParserCtor_dispex = { + L"DOMParser", + &DOMParserCtor_dispex_vtbl, + PROTO_ID_NULL, + NULL_tid, + no_iface_tids +}; + typedef struct { DispatchEx dispex; IHTMLScreen IHTMLScreen_iface; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index f9c8d708b4b..16208a58add 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -355,6 +355,7 @@ sync_test("builtin_toString", function() { if(v >= 9) { test("computedStyle", window.getComputedStyle(e), "CSSStyleDeclaration"); test("doctype", document.doctype, "DocumentType"); + test("domParser", new DOMParser(), "DOMParser", null, "Function"); test("Event", document.createEvent("Event"), "Event"); test("CustomEvent", document.createEvent("CustomEvent"), "CustomEvent"); @@ -635,11 +636,14 @@ sync_test("builtin_prototypes", function() { var v = document.documentMode, r, obj, name, proto; var special_ctors = [ + [ "DOMParser", [ "prototype", "arguments" ], [ "create", "length" ], 9 ], [ "Image", [ "prototype", "arguments" ], [ "create", "length" ] ], [ "Option", [ "prototype", "arguments" ], [ "create", "length" ] ], [ "XMLHttpRequest", [ "prototype", "arguments", "create" ], [ "length" ] ] ]; for(var i = 0; i < special_ctors.length; i++) { + if(special_ctors[i].length > 3 && v < special_ctors[i][3]) + continue; name = special_ctors[i][0]; ok(Object.prototype.hasOwnProperty.call(window, name), name + " not a property of window."); eval("obj = window." + name + ";"); @@ -864,6 +868,12 @@ sync_test("builtin_prototypes", function() { }else ok(proto.constructor === window.HTMLOptionElement, "Option.prototype.constructor = " + proto.constructor); + if(v >= 9) { + set_obj("DOMParser", true); + test_prop("parseFromString"); + ok(proto.constructor === window.DOMParser, "DOMParser.prototype.constructor = " + proto.constructor); + } + // other constructors don't support construction set_obj("ClientRect"); set_obj("ClientRectList"); @@ -1267,6 +1277,7 @@ sync_test("builtin_prototypes", function() { [ "Document", "Node" ], [ "DocumentType", "Node" ], [ "DOMImplementation", "Object" ], + [ "DOMParser", "Object" ], [ "DOMTokenList", "Object" ], [ "Element", "Node" ], [ "Event", "Object" ], @@ -1620,6 +1631,7 @@ sync_test("window_props", function() { test_exposed("Set", v >= 11); test_exposed("performance", true); test_exposed("console", v >= 10); + test_exposed("DOMParser", v >= 9); test_exposed("matchMedia", v >= 10); }); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 4c3006ab992..9ef653cc932 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -3048,3 +3048,14 @@ sync_test("matchMedia", function() { mql = window.matchMedia("(max-width: 1000px)"); ok(mql.matches === true, "(max-width: 1000px) does not match"); }); + +sync_test("DOMParser", function() { + var p, r = DOMParser.length; + ok(r === 0, "length = " + r); + + p = DOMParser(); + r = Object.getPrototypeOf(p); + ok(r === DOMParser.prototype, "prototype of instance created without new = " + r); + ok(p !== new DOMParser(), "DOMParser() == new DOMParser()"); + ok(new DOMParser() !== new DOMParser(), "new DOMParser() == new DOMParser()"); +}); From 39fb27a207495510bfd41b9fef3b30f7efbe6e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:08 +0200 Subject: [PATCH 0928/2777] mshtml: Implement DOMParser's parseFromString for HTML documents. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/mshtml_private.h | 8 ++++ dlls/mshtml/omnavigator.c | 74 +++++++++++++++++++++++++++++++++++- dlls/mshtml/tests/es5.js | 50 +++++++++++++++++++++++- 3 files changed, 130 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 5cf88477f0b..6fda50386a7 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -1115,6 +1115,14 @@ struct HTMLFrameBase { typedef struct nsDocumentEventListener nsDocumentEventListener; +typedef enum { + DOCTYPE_INVALID = -1, + DOCTYPE_HTML, + DOCTYPE_XHTML, + DOCTYPE_XML, + DOCTYPE_SVG, +} document_type_t; + struct HTMLDocumentNode { HTMLDOMNode node; diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index bf1b01dc93b..6dbf3f42048 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -31,6 +31,31 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); +static document_type_t document_type_from_content_type(const WCHAR *content_type) +{ + static const struct { + const WCHAR *content_type; + document_type_t doc_type; + } table[] = { + { L"application/xhtml+xml", DOCTYPE_XHTML }, + { L"application/xml", DOCTYPE_XML }, + { L"image/svg+xml", DOCTYPE_SVG }, + { L"text/html", DOCTYPE_HTML }, + { L"text/xml", DOCTYPE_XML }, + }; + unsigned int i, a = 0, b = ARRAY_SIZE(table); + int c; + + while(a < b) { + i = (a + b) / 2; + c = wcsicmp(table[i].content_type, content_type); + if(!c) return table[i].doc_type; + if(c > 0) b = i; + else a = i + 1; + } + return DOCTYPE_INVALID; +} + typedef struct HTMLPluginsCollection HTMLPluginsCollection; typedef struct HTMLMimeTypesCollection HTMLMimeTypesCollection; @@ -355,6 +380,8 @@ struct dom_parser { IDOMParser IDOMParser_iface; DispatchEx dispex; LONG ref; + + HTMLDocumentNode *doc; }; static inline struct dom_parser *impl_from_IDOMParser(IDOMParser *iface) @@ -399,6 +426,7 @@ static ULONG WINAPI DOMParser_Release(IDOMParser *iface) TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { + IHTMLDOMNode_Release(&This->doc->node.IHTMLDOMNode_iface); release_dispex(&This->dispex); free(This); } @@ -443,9 +471,50 @@ static HRESULT WINAPI DOMParser_Invoke(IDOMParser *iface, DISPID dispIdMember, static HRESULT WINAPI DOMParser_parseFromString(IDOMParser *iface, BSTR string, BSTR mimeType, IHTMLDocument2 **ppNode) { struct dom_parser *This = impl_from_IDOMParser(iface); + document_type_t doc_type; + HRESULT hres; + + TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(string), debugstr_w(mimeType), ppNode); + + if(!string || !mimeType || (doc_type = document_type_from_content_type(mimeType)) == DOCTYPE_INVALID) + return E_INVALIDARG; + + if(doc_type == DOCTYPE_HTML) { + IHTMLDOMImplementation *impl_iface; + HTMLDOMImplementation *impl; + IHTMLDocument7 *html_doc; + IHTMLElement *html_elem; + HTMLDocumentNode *doc; + + hres = IHTMLDocument5_get_implementation(&This->doc->IHTMLDocument5_iface, &impl_iface); + if(FAILED(hres)) + return hres; + + impl = impl_from_IHTMLDOMImplementation(impl_iface); + hres = HTMLDOMImplementation2_createHTMLDocument(&impl->IHTMLDOMImplementation2_iface, NULL, &html_doc); + HTMLDOMImplementation_Release(impl_iface); + if(FAILED(hres)) + return hres; + doc = CONTAINING_RECORD(html_doc, HTMLDocumentNode, IHTMLDocument7_iface); - FIXME("(%p)->(%s %s %p)\n", This, debugstr_w(string), debugstr_w(mimeType), ppNode); + hres = IHTMLDocument3_get_documentElement(&doc->IHTMLDocument3_iface, &html_elem); + if(FAILED(hres)) { + IHTMLDocument7_Release(html_doc); + return hres; + } + hres = IHTMLElement_put_innerHTML(html_elem, string); + IHTMLElement_Release(html_elem); + if(FAILED(hres)) { + IHTMLDocument7_Release(html_doc); + return hres; + } + + *ppNode = &doc->IHTMLDocument2_iface; + return hres; + } + + FIXME("Not implemented for XML Document\n"); return E_NOTIMPL; } @@ -498,6 +567,9 @@ static HRESULT DOMParserCtor_value(DispatchEx *iface, LCID lcid, WORD flags, DIS ret->IDOMParser_iface.lpVtbl = &DOMParserVtbl; ret->ref = 1; + ret->doc = This->window->doc; + IHTMLDOMNode_AddRef(&ret->doc->node.IHTMLDOMNode_iface); + init_dispatch(&ret->dispex, (IUnknown*)&ret->IDOMParser_iface, &DOMParser_dispex, This->window, dispex_compat_mode(&This->dispex)); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 9ef653cc932..488a2dfae5c 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -3050,7 +3050,7 @@ sync_test("matchMedia", function() { }); sync_test("DOMParser", function() { - var p, r = DOMParser.length; + var p, r = DOMParser.length, mimeType; ok(r === 0, "length = " + r); p = DOMParser(); @@ -3058,4 +3058,52 @@ sync_test("DOMParser", function() { ok(r === DOMParser.prototype, "prototype of instance created without new = " + r); ok(p !== new DOMParser(), "DOMParser() == new DOMParser()"); ok(new DOMParser() !== new DOMParser(), "new DOMParser() == new DOMParser()"); + + var teststr = { toString: function() { return "wine"; } }; + + // HTML mime types + mimeType = [ + "text/hTml" + ]; + for(var i = 0; i < mimeType.length; i++) { + var m = mimeType[i], html = p.parseFromString(teststr, m), e = external.getExpectedMimeType(m.toLowerCase()); + r = html.mimeType; + ok(r === e, "mimeType of HTML document with mime type " + m + " = " + r + ", expected " + e); + r = html.childNodes; + ok(r.length === 1 || r.length === 2, "childNodes.length of HTML document with mime type " + m + " = " + r.length); + var html_elem = r[r.length - 1]; + ok(html_elem.nodeName === "HTML", "child nodeName of HTML document with mime type " + m + " = " + r.nodeName); + ok(html_elem.nodeValue === null, "child nodeValue of HTML document with mime type " + m + " = " + r.nodeValue); + r = html.anchors; + ok(r.length === 1, "anchors.length of HTML document with mime type " + m + " = " + r.length); + r = r[0]; + ok(r.nodeName === "A", "anchor nodeName of HTML document with mime type " + m + " = " + r.nodeName); + ok(r.nodeValue === null, "anchor nodeValue of HTML document with mime type " + m + " = " + r.nodeValue); + r = r.parentNode; + ok(r.nodeName === "BODY", "anchor parent nodeName of HTML document with mime type " + m + " = " + r.nodeName); + ok(r.nodeValue === null, "anchor parent nodeValue of HTML document with mime type " + m + " = " + r.nodeValue); + r = r.parentNode; + ok(r === html_elem, "body parent of HTML document with mime type " + m + " = " + r); + } + + // Invalid mime types + mimeType = [ + "application/html", + "wine/test+xml", + "image/jpeg", + "text/plain", + "html", + "+xml", + "xml", + 42 + ]; + for(var i = 0; i < mimeType.length; i++) { + try { + p.parseFromString(teststr, mimeType[i]); + ok(false, "expected exception calling parseFromString with mime type " + mimeType[i]); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === E_INVALIDARG, "parseFromString with mime type " + mimeType[i] + " threw " + n); + } + } }); From e4ed133a18ea3425e49236f7233dc66d585babe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:08 +0200 Subject: [PATCH 0929/2777] mshtml: Use Gecko's responseXML to create the XML document in IE10 and up. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Native modes IE10 and up implement XML documents as children of the DocumentPrototype, which have standard IHTMLDocument interfaces. But previous modes do not, but instead have the IXMLDOMDocument interface (which suggests it uses msxml like now). Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmldoc.c | 25 +++++++++++++++++++++---- dlls/mshtml/htmlwindow.c | 4 ++-- dlls/mshtml/mshtml_private.h | 5 ++++- dlls/mshtml/omnavigator.c | 2 +- dlls/mshtml/tests/documentmode.js | 1 + dlls/mshtml/tests/xhr.js | 22 ++++++++++++++++++++++ dlls/mshtml/tests/xmlhttprequest.c | 15 +++++++++++++++ dlls/mshtml/xmlhttprequest.c | 9 +++++++++ 8 files changed, 75 insertions(+), 8 deletions(-) diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 0c5a8db1f33..3e9b29227ff 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -39,6 +39,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); +static dispex_static_data_t *const dispex_from_document_type[] = { + [DOCTYPE_HTML] = &HTMLDocumentNode_dispex, + [DOCTYPE_XHTML] = &XMLDocumentNode_dispex, + [DOCTYPE_XML] = &XMLDocumentNode_dispex, + [DOCTYPE_SVG] = &XMLDocumentNode_dispex, +}; + static HRESULT create_document_fragment(nsIDOMNode *nsnode, HTMLDocumentNode *doc_node, HTMLDocumentNode **ret); HRESULT get_doc_elem_by_id(HTMLDocumentNode *doc, const WCHAR *id, HTMLElement **ret) @@ -6312,7 +6319,7 @@ static void HTMLDocumentNode_finalize_dispex(DispatchEx *dispex) if(COMPAT_MODE_IE9 <= compat_mode && compat_mode < COMPAT_MODE_IE11) dispex_data = &DocumentNode_dispex; else - dispex_data = &HTMLDocumentNode_dispex; + dispex_data = dispex_from_document_type[This->doc_type]; finalize_delayed_init_dispex(dispex, get_inner_window(This), dispex_data); } @@ -6474,6 +6481,15 @@ dispex_static_data_t HTMLDocumentNode_dispex = { HTMLDocumentNode_init_dispex_info }; +dispex_static_data_t XMLDocumentNode_dispex = { + L"XMLDocument", + &HTMLDocumentNode_event_target_vtbl.dispex_vtbl, + PROTO_ID_XMLDocument, + DispHTMLDocument_tid, + HTMLDocumentNode_iface_tids, + HTMLDocumentNode_init_dispex_info +}; + dispex_static_data_t DocumentNode_dispex = { L"Document", &HTMLDocumentNode_event_target_vtbl.dispex_vtbl, @@ -6527,7 +6543,7 @@ static HTMLDocumentNode *alloc_doc_node(HTMLDocumentObj *doc_obj, HTMLInnerWindo } HRESULT create_document_node(nsIDOMDocument *nsdoc, GeckoBrowser *browser, HTMLInnerWindow *window, - compat_mode_t parent_mode, HTMLDocumentNode **ret) + document_type_t doc_type, compat_mode_t parent_mode, HTMLDocumentNode **ret) { HTMLDocumentObj *doc_obj = browser->doc; HTMLDocumentNode *doc; @@ -6535,6 +6551,7 @@ HRESULT create_document_node(nsIDOMDocument *nsdoc, GeckoBrowser *browser, HTMLI doc = alloc_doc_node(doc_obj, window); if(!doc) return E_OUTOFMEMORY; + doc->doc_type = doc_type; if(!doc_obj->window || (window && is_main_content_window(window->base.outer_window))) doc->cp_container.forward_container = &doc_obj->cp_container; @@ -6548,7 +6565,7 @@ HRESULT create_document_node(nsIDOMDocument *nsdoc, GeckoBrowser *browser, HTMLI } doc->node.vtbl = &HTMLDocumentNodeImplVtbl; - HTMLDOMNode_Init(doc, &doc->node, (nsIDOMNode*)doc->dom_document, &HTMLDocumentNode_dispex); + HTMLDOMNode_Init(doc, &doc->node, (nsIDOMNode*)doc->dom_document, dispex_from_document_type[doc_type]); if(parent_mode >= COMPAT_MODE_IE9) { TRACE("using parent mode %u\n", parent_mode); @@ -6588,7 +6605,7 @@ static HRESULT create_document_fragment(nsIDOMNode *nsnode, HTMLDocumentNode *do IHTMLWindow2_AddRef(&doc_frag->window->base.IHTMLWindow2_iface); doc_frag->node.vtbl = &HTMLDocumentFragmentImplVtbl; - HTMLDOMNode_Init(doc_node, &doc_frag->node, nsnode, &HTMLDocumentNode_dispex); + HTMLDOMNode_Init(doc_node, &doc_frag->node, nsnode, dispex_from_document_type[doc_node->doc_type]); doc_frag->document_mode = lock_document_mode(doc_node); *ret = doc_frag; diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index dd0f382ebb6..157ca111334 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -5046,7 +5046,7 @@ void set_window_uninitialized(HTMLOuterWindow *window, HTMLDocumentNode *doc_nod if(NS_FAILED(nsres)) return; - hres = create_document_node(nsdoc, window->browser, window->pending_window, COMPAT_MODE_QUIRKS, &window->pending_window->doc); + hres = create_document_node(nsdoc, window->browser, window->pending_window, DOCTYPE_HTML, COMPAT_MODE_QUIRKS, &window->pending_window->doc); nsIDOMDocument_Release(nsdoc); if(FAILED(hres)) return; @@ -5081,7 +5081,7 @@ HRESULT update_window_doc(HTMLInnerWindow *window) if(outer_window->parent) parent_mode = outer_window->parent->base.inner_window->doc->document_mode; - hres = create_document_node(nsdoc, outer_window->browser, window, parent_mode, &window->doc); + hres = create_document_node(nsdoc, outer_window->browser, window, DOCTYPE_HTML, parent_mode, &window->doc); nsIDOMDocument_Release(nsdoc); if(FAILED(hres)) return hres; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 6fda50386a7..81e8c8bdfc9 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -474,6 +474,7 @@ PRIVATE_TID_LIST X(DOMUIEvent, "UIEvent", DOMUIEvent_dispex, DOMEvent) \ X(DOMCharacterData, "CharacterData", DOMCharacterData_dispex, HTMLDOMNode) \ X(Document, "Document", DocumentNode_dispex, HTMLDOMNode) \ + X(XMLDocument, "XMLDocument", XMLDocumentNode_dispex, Document) \ X(DocumentType, "DocumentType", DocumentType_dispex, HTMLDOMNode) \ X(DOMElement, "Element", DOMElement_dispex, HTMLDOMNode) \ X(CSSRule, "CSSRule", CSSRule_dispex, Object) \ @@ -1115,6 +1116,7 @@ struct HTMLFrameBase { typedef struct nsDocumentEventListener nsDocumentEventListener; +/* NOTE: Update arrays at top of htmldoc.c if you change this */ typedef enum { DOCTYPE_INVALID = -1, DOCTYPE_HTML, @@ -1163,6 +1165,7 @@ struct HTMLDocumentNode { LONG ref; + document_type_t doc_type; ConnectionPointContainer cp_container; HTMLOuterWindow *outer_window; HTMLInnerWindow *window; @@ -1205,7 +1208,7 @@ HRESULT HTMLDocument_Create(IUnknown*,REFIID,void**) DECLSPEC_HIDDEN; HRESULT MHTMLDocument_Create(IUnknown*,REFIID,void**) DECLSPEC_HIDDEN; HRESULT HTMLLoadOptions_Create(IUnknown*,REFIID,void**) DECLSPEC_HIDDEN; HRESULT create_document_node(nsIDOMDocument*,GeckoBrowser*,HTMLInnerWindow*, - compat_mode_t,HTMLDocumentNode**) DECLSPEC_HIDDEN; + document_type_t,compat_mode_t,HTMLDocumentNode**) DECLSPEC_HIDDEN; HRESULT create_doctype_node(HTMLDocumentNode*,nsIDOMNode*,HTMLDOMNode**) DECLSPEC_HIDDEN; HRESULT create_outer_window(GeckoBrowser*,mozIDOMWindowProxy*,HTMLOuterWindow*,HTMLOuterWindow**) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 6dbf3f42048..31206adda10 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -286,7 +286,7 @@ static HRESULT WINAPI HTMLDOMImplementation2_createHTMLDocument(IHTMLDOMImplemen return E_FAIL; } - hres = create_document_node(doc, This->browser, NULL, dispex_compat_mode(&This->dispex), &new_document_node); + hres = create_document_node(doc, This->browser, NULL, DOCTYPE_HTML, dispex_compat_mode(&This->dispex), &new_document_node); nsIDOMDocument_Release(doc); if(FAILED(hres)) return hres; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 16208a58add..4f2ec3d3dc0 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1347,6 +1347,7 @@ sync_test("builtin_prototypes", function() { [ "TextRange", "Object" ], [ "UIEvent", "Event" ], [ "Window", "Object" ], + [ "XMLDocument", "Document" ], [ "XMLHttpRequest", "Object" ] ]; diff --git a/dlls/mshtml/tests/xhr.js b/dlls/mshtml/tests/xhr.js index 5e7fa96158e..2e233795981 100644 --- a/dlls/mshtml/tests/xhr.js +++ b/dlls/mshtml/tests/xhr.js @@ -21,6 +21,7 @@ var xml = "\nwine function test_xhr() { var xhr = new XMLHttpRequest(); var complete_cnt = 0, loadstart = false; + var v = document.documentMode; xhr.onreadystatechange = function() { if(xhr.readyState != 4) @@ -29,6 +30,26 @@ function test_xhr() { ok(xhr.responseText === xml, "unexpected responseText " + xhr.responseText); ok(xhr.responseXML !== null, "unexpected null responseXML"); + var x = xhr.responseXML, r = Object.prototype.toString.call(x); + ok(r === (v < 10 ? "[object Object]" : (v < 11 ? "[object Document]" : "[object XMLDocument]")), + "XML document Object.toString = " + r); + + r = Object.getPrototypeOf(x); + if(v < 10) + ok(r === null, "prototype of returned XML document = " + r); + else if(v < 11) + ok(r === window.Document.prototype, "prototype of returned XML document = " + r); + else + ok(r === window.XMLDocument.prototype, "prototype of returned XML document" + r); + + if(v < 10) { + ok(!("anchors" in x), "anchors is in returned XML document"); + ok(Object.prototype.hasOwnProperty.call(x, "createElement"), "createElement not a prop of returned XML document"); + }else { + ok("anchors" in x, "anchors not in returned XML document"); + ok(!x.hasOwnProperty("createElement"), "createElement is a prop of returned XML document"); + } + if(complete_cnt++ && !("onloadend" in xhr)) next_test(); } @@ -90,6 +111,7 @@ function test_content_types() { var xml_types = [ "text/xmL", "apPliCation/xml", + "application/xHtml+xml", "image/SvG+xml", "Wine/Test+xml", "++Xml", diff --git a/dlls/mshtml/tests/xmlhttprequest.c b/dlls/mshtml/tests/xmlhttprequest.c index a3ec54ffef6..4316a25f595 100644 --- a/dlls/mshtml/tests/xmlhttprequest.c +++ b/dlls/mshtml/tests/xmlhttprequest.c @@ -519,10 +519,14 @@ static void _set_request_header(unsigned line, IHTMLXMLHttpRequest *xhr, const W static void test_responseXML(const WCHAR *expect_text) { IDispatch *disp; + IHTMLDocument2 *html_doc; IXMLDOMDocument *xmldom; IObjectSafety *safety; + IHTMLDOMNode *node; DWORD enabled = 0, supported = 0; + DISPID dispid; HRESULT hres; + BSTR str; disp = NULL; hres = IHTMLXMLHttpRequest_get_responseXML(xhr, &disp); @@ -545,6 +549,17 @@ static void test_responseXML(const WCHAR *expect_text) "Expected enabled: (INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA | INTERFACE_USES_SECURITY_MANAGER), got 0x%08lx\n", enabled); IObjectSafety_Release(safety); + hres = IXMLDOMDocument_QueryInterface(xmldom, &IID_IHTMLDOMNode, (void**)&node); + ok(hres == E_NOINTERFACE, "QueryInterface(IHTMLDOMNode) returned: %08lx\n", hres); + + hres = IXMLDOMDocument_QueryInterface(xmldom, &IID_IHTMLDocument2, (void**)&html_doc); + ok(hres == E_NOINTERFACE, "QueryInterface(IHTMLDocument2) returned: %08lx\n", hres); + + str = SysAllocString(L"anchors"); + hres = IDispatch_GetIDsOfNames(disp, &IID_NULL, &str, 1, LOCALE_USER_DEFAULT, &dispid); + ok(hres == DISP_E_UNKNOWNNAME, "GetIDsOfNames(\"anchors\") returned: %08lx\n", hres); + SysFreeString(str); + if(!expect_text) test_illegal_xml(xmldom); diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 535e261af1a..04adc813381 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -397,6 +397,7 @@ static HRESULT WINAPI HTMLXMLHttpRequest_get_responseXML(IHTMLXMLHttpRequest *if TRACE("(%p)->(%p)\n", This, p); if(dispex_compat_mode(&This->event_target.dispex) >= COMPAT_MODE_IE10) { + HTMLDocumentNode *doc; nsIDOMDocument *nsdoc; nsresult nsres; @@ -407,7 +408,15 @@ static HRESULT WINAPI HTMLXMLHttpRequest_get_responseXML(IHTMLXMLHttpRequest *if *p = NULL; return S_OK; } + + hres = create_document_node(nsdoc, This->window->base.outer_window->browser, NULL, DOCTYPE_XML, + dispex_compat_mode(&This->window->event_target.dispex), &doc); nsIDOMDocument_Release(nsdoc); + if(FAILED(hres)) + return hres; + + *p = (IDispatch*)&doc->IHTMLDocument2_iface; + return S_OK; } hres = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void**)&xmldoc); From f6edfa0c3ac21c6534c8ae0cf2dbc189fe9e17d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:08 +0200 Subject: [PATCH 0930/2777] mshtml: Use the proper XML document type in responseXML. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmldoc.c | 12 +++++++++++- dlls/mshtml/tests/xhr.js | 11 +++++++++-- dlls/mshtml/xmlhttprequest.c | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 3e9b29227ff..6126ff1c6d3 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -39,6 +39,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); +static const WCHAR *const content_type_from_document_type[] = { + [DOCTYPE_HTML] = L"text/html", + [DOCTYPE_XHTML] = L"application/xhtml+xml", + [DOCTYPE_XML] = L"text/xml", + [DOCTYPE_SVG] = L"image/svg+xml", +}; + static dispex_static_data_t *const dispex_from_document_type[] = { [DOCTYPE_HTML] = &HTMLDocumentNode_dispex, [DOCTYPE_XHTML] = &XMLDocumentNode_dispex, @@ -1328,7 +1335,10 @@ static HRESULT WINAPI HTMLDocument_get_mimeType(IHTMLDocument2 *iface, BSTR *p) *p = NULL; - if(This->window && This->window->base.outer_window->readystate == READYSTATE_UNINITIALIZED) + if(!This->window) + return get_mime_type_display_name(content_type_from_document_type[This->doc_type], p); + + if(This->window->base.outer_window->readystate == READYSTATE_UNINITIALIZED) return (*p = SysAllocString(L"")) ? S_OK : E_FAIL; nsAString_InitDepend(&nsstr, NULL); diff --git a/dlls/mshtml/tests/xhr.js b/dlls/mshtml/tests/xhr.js index 2e233795981..82182d1eb1e 100644 --- a/dlls/mshtml/tests/xhr.js +++ b/dlls/mshtml/tests/xhr.js @@ -120,9 +120,16 @@ function test_content_types() { function onload() { ok(xhr.responseText === xml, "unexpected responseText " + xhr.responseText); - if(v < 10 || types === xml_types) + if(v < 10 || types === xml_types) { ok(xhr.responseXML !== null, "unexpected null responseXML for " + types[i]); - else + if(v >= 10) { + var r = xhr.responseXML.mimeType, e = "text/xml"; + if(types[i] === "application/xHtml+xml" || types[i] === "image/SvG+xml") + e = types[i].toLowerCase(); + e = external.getExpectedMimeType(e); + ok(r === e, "XML document mimeType for " + types[i] + " = " + r + ", expected " + e); + } + }else ok(xhr.responseXML === null, "unexpected non-null responseXML for " + (override ? "overridden " : "") + types[i]); if(("overrideMimeType" in xhr) && !override) { diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 04adc813381..97edc4a0e16 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -138,6 +138,7 @@ struct HTMLXMLHttpRequest { IWineXMLHttpRequestPrivate IWineXMLHttpRequestPrivate_iface; IProvideClassInfo2 IProvideClassInfo2_iface; LONG ref; + document_type_t doctype_override; response_type_t response_type; HTMLInnerWindow *window; nsIXMLHttpRequest *nsxhr; @@ -397,8 +398,11 @@ static HRESULT WINAPI HTMLXMLHttpRequest_get_responseXML(IHTMLXMLHttpRequest *if TRACE("(%p)->(%p)\n", This, p); if(dispex_compat_mode(&This->event_target.dispex) >= COMPAT_MODE_IE10) { + nsACString header, nscstr; + document_type_t doctype; HTMLDocumentNode *doc; nsIDOMDocument *nsdoc; + const char *type; nsresult nsres; nsres = nsIXMLHttpRequest_GetResponseXML(This->nsxhr, &nsdoc); @@ -409,7 +413,25 @@ static HRESULT WINAPI HTMLXMLHttpRequest_get_responseXML(IHTMLXMLHttpRequest *if return S_OK; } - hres = create_document_node(nsdoc, This->window->base.outer_window->browser, NULL, DOCTYPE_XML, + if(This->doctype_override != DOCTYPE_INVALID) + doctype = This->doctype_override; + else { + doctype = DOCTYPE_XML; + nsACString_InitDepend(&header, "Content-Type"); + nsACString_InitDepend(&nscstr, NULL); + nsres = nsIXMLHttpRequest_GetResponseHeader(This->nsxhr, &header, &nscstr); + nsACString_Finish(&header); + if(NS_SUCCEEDED(nsres)) { + nsACString_GetData(&nscstr, &type); + if(!stricmp(type, "application/xhtml+xml")) + doctype = DOCTYPE_XHTML; + else if(!stricmp(type, "image/svg+xml")) + doctype = DOCTYPE_SVG; + } + nsACString_Finish(&nscstr); + } + + hres = create_document_node(nsdoc, This->window->base.outer_window->browser, NULL, doctype, dispex_compat_mode(&This->window->event_target.dispex), &doc); nsIDOMDocument_Release(nsdoc); if(FAILED(hres)) @@ -1075,6 +1097,7 @@ static HRESULT WINAPI HTMLXMLHttpRequest_private_overrideMimeType(IWineXMLHttpRe { HTMLXMLHttpRequest *This = impl_from_IWineXMLHttpRequestPrivate(iface); static const WCHAR generic_type[] = L"application/octet-stream"; + document_type_t doctype = DOCTYPE_XML; const WCHAR *type = NULL; WCHAR *lowercase = NULL; nsAString nsstr; @@ -1088,6 +1111,11 @@ static HRESULT WINAPI HTMLXMLHttpRequest_private_overrideMimeType(IWineXMLHttpRe return E_OUTOFMEMORY; _wcslwr(lowercase); type = lowercase; + + if(!wcscmp(type, L"application/xhtml+xml")) + doctype = DOCTYPE_XHTML; + else if(!wcscmp(type, L"image/svg+xml")) + doctype = DOCTYPE_SVG; }else type = generic_type; } @@ -1096,6 +1124,8 @@ static HRESULT WINAPI HTMLXMLHttpRequest_private_overrideMimeType(IWineXMLHttpRe nsres = nsIXMLHttpRequest_SlowOverrideMimeType(This->nsxhr, &nsstr); nsAString_Finish(&nsstr); free(lowercase); + if(NS_SUCCEEDED(nsres)) + This->doctype_override = doctype; return map_nsresult(nsres); } @@ -1495,6 +1525,7 @@ static HRESULT WINAPI HTMLXMLHttpRequestFactory_create(IHTMLXMLHttpRequestFactor nsIXMLHttpRequest_Release(nsxhr); return E_OUTOFMEMORY; } + ret->doctype_override = DOCTYPE_INVALID; ret->nsxhr = nsxhr; ret->window = This->window; IHTMLWindow2_AddRef(&This->window->base.IHTMLWindow2_iface); From 158cbb801399d5f00de5d8be5babbca4a1664cbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:08 +0200 Subject: [PATCH 0931/2777] mshtml: Implement anchors prop for XML documents. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmldoc.c | 21 ++++++++++----------- dlls/mshtml/tests/xhr.js | 2 ++ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 6126ff1c6d3..8cbf3066267 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -780,21 +780,20 @@ static HRESULT WINAPI HTMLDocument_get_anchors(IHTMLDocument2 *iface, IHTMLEleme return E_UNEXPECTED; } - if(!This->html_document) { - FIXME("Not implemented for XML document\n"); - return E_NOTIMPL; - } + if(This->doc_type == DOCTYPE_XHTML) + FIXME("Not implemented for XHTML Document, returning empty list\n"); - nsres = nsIDOMHTMLDocument_GetAnchors(This->html_document, &nscoll); - if(NS_FAILED(nsres)) { - ERR("GetAnchors failed: %08lx\n", nsres); - return E_FAIL; + if(This->html_document) { + nsres = nsIDOMHTMLDocument_GetAnchors(This->html_document, &nscoll); + if(NS_FAILED(nsres)) { + ERR("GetAnchors failed: %08lx\n", nsres); + return E_FAIL; + } } - if(nscoll) { - *p = create_collection_from_htmlcol(nscoll, This, This->document_mode); + *p = create_collection_from_htmlcol(nscoll, This, This->document_mode); + if(nscoll) nsIDOMHTMLCollection_Release(nscoll); - } return S_OK; } diff --git a/dlls/mshtml/tests/xhr.js b/dlls/mshtml/tests/xhr.js index 82182d1eb1e..8b78db7243a 100644 --- a/dlls/mshtml/tests/xhr.js +++ b/dlls/mshtml/tests/xhr.js @@ -48,6 +48,8 @@ function test_xhr() { }else { ok("anchors" in x, "anchors not in returned XML document"); ok(!x.hasOwnProperty("createElement"), "createElement is a prop of returned XML document"); + r = x.anchors; + ok(r.length === 0, "anchors.length of returned XML document = " + r.length); } if(complete_cnt++ && !("onloadend" in xhr)) From 88c0cf94a51f264ce6060a22abd99bb2fe764eb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:08 +0200 Subject: [PATCH 0932/2777] mshtml: Implement DOMParser's parseFromString for XML documents. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/mshtml_private.h | 2 ++ dlls/mshtml/nsembed.c | 48 +++++++++++++++++++++++++++++++ dlls/mshtml/nsiface.idl | 13 +++++++++ dlls/mshtml/omnavigator.c | 42 +++++++++++++++++++++++++-- dlls/mshtml/tests/documentmode.js | 3 ++ dlls/mshtml/tests/es5.js | 46 +++++++++++++++++++++++++++++ 6 files changed, 152 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 81e8c8bdfc9..e6bff647ebb 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -153,6 +153,7 @@ struct _IWineDispatchProxyCbPrivate { #define MSHTML_E_INVALID_PROPERTY 0x800a01b6 #define MSHTML_E_INVALID_ACTION 0x800a01bd #define MSHTML_E_NODOC 0x800a025c +#define MSHTML_E_SYNTAX 0x800a03ea typedef struct HTMLWindow HTMLWindow; typedef struct HTMLInnerWindow HTMLInnerWindow; @@ -1321,6 +1322,7 @@ HRESULT nsnode_to_nsstring(nsIDOMNode*,nsAString*) DECLSPEC_HIDDEN; void setup_editor_controller(GeckoBrowser*) DECLSPEC_HIDDEN; nsresult get_nsinterface(nsISupports*,REFIID,void**) DECLSPEC_HIDDEN; nsIWritableVariant *create_nsvariant(void) DECLSPEC_HIDDEN; +nsIDOMParser *create_nsdomparser(HTMLDocumentNode*) DECLSPEC_HIDDEN; nsIXMLHttpRequest *create_nsxhr(nsIDOMWindow *nswindow) DECLSPEC_HIDDEN; nsresult create_nsfile(const PRUnichar*,nsIFile**) DECLSPEC_HIDDEN; char *get_nscategory_entry(const char*,const char*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/nsembed.c b/dlls/mshtml/nsembed.c index 3244dca127c..8f504a7cac9 100644 --- a/dlls/mshtml/nsembed.c +++ b/dlls/mshtml/nsembed.c @@ -42,6 +42,7 @@ WINE_DECLARE_DEBUG_CHANNEL(gecko); #define NS_WEBBROWSER_CONTRACTID "@mozilla.org/embedding/browser/nsWebBrowser;1" #define NS_COMMANDPARAMS_CONTRACTID "@mozilla.org/embedcomp/command-params;1" #define NS_HTMLSERIALIZER_CONTRACTID "@mozilla.org/layout/contentserializer;1?mimetype=text/html" +#define NS_DOMPARSER_CONTRACTID "@mozilla.org/xmlextras/domparser;1" #define NS_EDITORCONTROLLER_CONTRACTID "@mozilla.org/editor/editorcontroller;1" #define NS_PREFERENCES_CONTRACTID "@mozilla.org/preferences;1" #define NS_VARIANT_CONTRACTID "@mozilla.org/variant;1" @@ -2418,6 +2419,53 @@ __ASM_GLOBAL_FUNC(call_thiscall_func, #define nsIScriptObjectPrincipal_GetPrincipal(this) ((void* (WINAPI*)(void*,void*))&call_thiscall_func)((this)->lpVtbl->GetPrincipal,this) #endif +nsIDOMParser *create_nsdomparser(HTMLDocumentNode *doc_node) +{ + nsIScriptObjectPrincipal *sop; + HTMLOuterWindow *outer_window; + mozIDOMWindow *inner_window; + nsIGlobalObject *nsglo; + nsIDOMParser *nsparser; + nsIPrincipal *nspri; + nsresult nsres; + + outer_window = doc_node->outer_window; + if(!outer_window) + outer_window = doc_node->doc_obj->window; + + nsres = nsIDOMWindow_GetInnerWindow(outer_window->nswindow, &inner_window); + if(NS_FAILED(nsres)) { + ERR("Could not get inner window: %08lx\n", nsres); + return NULL; + } + + nsres = mozIDOMWindow_QueryInterface(inner_window, &IID_nsIGlobalObject, (void**)&nsglo); + mozIDOMWindow_Release(inner_window); + assert(nsres == NS_OK); + + nsres = nsIGlobalObject_QueryInterface(nsglo, &IID_nsIScriptObjectPrincipal, (void**)&sop); + assert(nsres == NS_OK); + + nspri = nsIScriptObjectPrincipal_GetPrincipal(sop); + nsIScriptObjectPrincipal_Release(sop); + + nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, + NS_DOMPARSER_CONTRACTID, NULL, &IID_nsIDOMParser, (void**)&nsparser); + if(NS_SUCCEEDED(nsres)) { + nsres = nsIDOMParser_Init(nsparser, nspri, NULL, NULL, nsglo); + if(NS_FAILED(nsres)) + nsIDOMParser_Release(nsparser); + } + nsISupports_Release(nspri); + nsIGlobalObject_Release(nsglo); + if(NS_FAILED(nsres)) { + ERR("nsIDOMParser_Init failed: %08lx\n", nsres); + return NULL; + } + + return nsparser; +} + nsIXMLHttpRequest *create_nsxhr(nsIDOMWindow *nswindow) { nsIScriptObjectPrincipal *sop; diff --git a/dlls/mshtml/nsiface.idl b/dlls/mshtml/nsiface.idl index 1e97f1fc63b..9c50b3a7599 100644 --- a/dlls/mshtml/nsiface.idl +++ b/dlls/mshtml/nsiface.idl @@ -4303,6 +4303,19 @@ interface nsIScriptObjectPrincipal : nsISupports nsIPrincipal* /* thiscall */ GetPrincipal(); } +[ + object, + uuid(70b9600e-8622-4c93-9ad8-22c28058dc44), + local +] +interface nsIDOMParser : nsISupports +{ + nsresult ParseFromString(const char16_t *str, const char *contentType, nsIDOMDocument **_retval); + nsresult ParseFromBuffer(const uint8_t *buf, uint32_t bufLen, const char *aContentType, nsIDOMDocument **_retval); + nsresult ParseFromStream(nsIInputStream *stream, const char *charset, int32_t contentLength, const char *contentType, nsIDOMDocument **_retval); + nsresult Init(nsIPrincipal *principal, nsIURI *documentURI, nsIURI *baseURI, nsIGlobalObject *scriptObject); +} + [ object, uuid(6f54214c-7175-498d-9d2d-0429e38c2869), diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 31206adda10..2866e677b5c 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -471,7 +471,13 @@ static HRESULT WINAPI DOMParser_Invoke(IDOMParser *iface, DISPID dispIdMember, static HRESULT WINAPI DOMParser_parseFromString(IDOMParser *iface, BSTR string, BSTR mimeType, IHTMLDocument2 **ppNode) { struct dom_parser *This = impl_from_IDOMParser(iface); + nsIDOMDocument *nsdoc = NULL; + HTMLDocumentNode *xml_doc; document_type_t doc_type; + nsAString errns, errtag; + nsIDOMNodeList *nodes; + nsIDOMParser *parser; + nsresult nsres; HRESULT hres; TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(string), debugstr_w(mimeType), ppNode); @@ -514,8 +520,40 @@ static HRESULT WINAPI DOMParser_parseFromString(IDOMParser *iface, BSTR string, return hres; } - FIXME("Not implemented for XML Document\n"); - return E_NOTIMPL; + if(!(parser = create_nsdomparser(This->doc))) + return E_FAIL; + nsres = nsIDOMParser_ParseFromString(parser, string ? string : L"", + doc_type == DOCTYPE_SVG ? "image/svg+xml" : + doc_type == DOCTYPE_XHTML ? "application/xhtml+xml" : + "text/xml", &nsdoc); + nsIDOMParser_Release(parser); + if(NS_FAILED(nsres) || !nsdoc) { + ERR("ParseFromString failed: 0x%08lx\n", nsres); + return NS_FAILED(nsres) ? map_nsresult(nsres) : E_FAIL; + } + + nsAString_InitDepend(&errns, L"http://www.mozilla.org/newlayout/xml/parsererror.xml"); + nsAString_InitDepend(&errtag, L"parsererror"); + nsres = nsIDOMDocument_GetElementsByTagNameNS(nsdoc, &errns, &errtag, &nodes); + nsAString_Finish(&errtag); + nsAString_Finish(&errns); + if(NS_SUCCEEDED(nsres)) { + UINT32 length; + nsres = nsIDOMNodeList_GetLength(nodes, &length); + nsIDOMNodeList_Release(nodes); + if(NS_SUCCEEDED(nsres) && length) { + nsIDOMDocument_Release(nsdoc); + return MSHTML_E_SYNTAX; + } + } + + hres = create_document_node(nsdoc, This->doc->browser, NULL, doc_type, This->doc->document_mode, &xml_doc); + nsIDOMDocument_Release(nsdoc); + if(FAILED(hres)) + return hres; + + *ppNode = &xml_doc->IHTMLDocument2_iface; + return hres; } static const IDOMParserVtbl DOMParserVtbl = { diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 4f2ec3d3dc0..c6799b482af 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -356,6 +356,9 @@ sync_test("builtin_toString", function() { test("computedStyle", window.getComputedStyle(e), "CSSStyleDeclaration"); test("doctype", document.doctype, "DocumentType"); test("domParser", new DOMParser(), "DOMParser", null, "Function"); + test("svgDocument", new DOMParser().parseFromString("foobar", "image/svg+xml"), v < 11 ? "Document" : "XMLDocument"); + test("xhtmlDocument", new DOMParser().parseFromString("foobar", "application/xhtml+xml"), v < 11 ? "Document" : "XMLDocument"); + test("xmlDocument", new DOMParser().parseFromString("foobar", "text/xml"), v < 11 ? "Document" : "XMLDocument"); test("Event", document.createEvent("Event"), "Event"); test("CustomEvent", document.createEvent("CustomEvent"), "CustomEvent"); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 488a2dfae5c..68c5be5c102 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -3086,6 +3086,44 @@ sync_test("DOMParser", function() { ok(r === html_elem, "body parent of HTML document with mime type " + m + " = " + r); } + // XML mime types + mimeType = [ + "text/xmL", + "aPPlication/xml", + "application/xhtml+xml", + "image/svg+xml" + ]; + for(var i = 0; i < mimeType.length; i++) { + var m = mimeType[i], xml = p.parseFromString(teststr, m), e; + e = external.getExpectedMimeType(m === "aPPlication/xml" ? "text/xml" : m.toLowerCase()); + r = xml.mimeType; + ok(r === e, "mimeType of XML document with mime type " + m + " = " + r + ", expected " + e); + r = xml.childNodes; + ok(r.length === 1, "childNodes.length of XML document with mime type " + m + " = " + r.length); + r = r[0]; + ok(r.nodeName === "a", "child nodeName of XML document with mime type " + m + " = " + r.nodeName); + ok(r.nodeValue === null, "child nodeValue of XML document with mime type " + m + " = " + r.nodeValue); + r = r.childNodes; + ok(r.length === 1, "childNodes of child.length of XML document with mime type " + m + " = " + r.length); + r = r[0]; + ok(r.nodeName === "#text", "child of child nodeName of XML document with mime type " + m + " = " + r.nodeName); + ok(r.nodeValue === "wine", "child of child nodeValue of XML document with mime type " + m + " = " + r.nodeValue); + ok(!("test" in xml), "'test' in XML document with mime type " + m); + + // test HTMLDocument specific props, which are available in DocumentPrototype, + // so they are shared in XMLDocument since they both have the same prototype + r = xml.anchors; + if(m === "application/xhtml+xml") { + todo_wine. + ok(r.length === 1, "anchors.length of XML document with mime type " + m + " = " + r.length); + r = r[0]; + todo_wine. + ok(r === xml.childNodes[0], "anchor of XML document with mime type " + m + " = " + r); + }else { + ok(r.length === 0, "anchors.length of XML document with mime type " + m + " = " + r.length); + } + } + // Invalid mime types mimeType = [ "application/html", @@ -3106,4 +3144,12 @@ sync_test("DOMParser", function() { ok(n === E_INVALIDARG, "parseFromString with mime type " + mimeType[i] + " threw " + n); } } + + try { + r = p.parseFromString("xml", "text/xml"); + ok(false, "expected exception calling parseFromString with invalid xml"); + }catch(ex) { + ok(ex.name === "SyntaxError", "parseFromString with invalid xml threw " + ex.name); + } + p.parseFromString("", "text/xml"); }); From 5a3f21224c45488ce6fb6bfee5843be9d4fa145a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:08 +0200 Subject: [PATCH 0933/2777] mshtml: Set non-HTML elements' prototype to ElementPrototype. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlelem.c | 32 ++++++++++++++++++++++++------- dlls/mshtml/tests/documentmode.js | 4 +++- dlls/mshtml/tests/es5.js | 10 ++++++++++ 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index e7dd5195b0e..cee37d4ce02 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -8015,6 +8015,8 @@ void HTMLElement_Init(HTMLElement *This, HTMLDocumentNode *doc, nsIDOMElement *n HRESULT HTMLElement_Create(HTMLDocumentNode *doc, nsIDOMNode *nsnode, BOOL use_generic, HTMLElement **ret) { + nsIDOMHTMLElement *nshtmlelem; + nsIDOMSVGElement *svg_element; nsIDOMElement *nselem; nsAString tag_name_str; const PRUnichar *tag_name; @@ -8034,17 +8036,32 @@ HRESULT HTMLElement_Create(HTMLDocumentNode *doc, nsIDOMNode *nsnode, BOOL use_g nsAString_GetData(&tag_name_str, &tag_name); + /* Check this first, as Gecko treats svg elements as non-HTML */ + nsres = nsIDOMElement_QueryInterface(nselem, &IID_nsIDOMSVGElement, (void**)&svg_element); + if(NS_SUCCEEDED(nsres)) { + hres = create_svg_element(doc, svg_element, tag_name, &elem); + nsIDOMSVGElement_Release(svg_element); + goto done; + } + + nsres = nsIDOMElement_QueryInterface(nselem, &IID_nsIDOMHTMLElement, (void**)&nshtmlelem); + if(NS_FAILED(nsres)) { + if(!(elem = calloc(1, sizeof(HTMLElement)))) + hres = E_OUTOFMEMORY; + else { + elem->node.vtbl = &HTMLElementImplVtbl; + HTMLElement_Init(elem, doc, nselem, &DOMElement_dispex); + hres = S_OK; + } + goto done; + } + nsIDOMHTMLElement_Release(nshtmlelem); + tag = get_tag_desc(tag_name); if(tag) { hres = tag->constructor(doc, nselem, &elem); }else { - nsIDOMSVGElement *svg_element; - - nsres = nsIDOMElement_QueryInterface(nselem, &IID_nsIDOMSVGElement, (void**)&svg_element); - if(NS_SUCCEEDED(nsres)) { - hres = create_svg_element(doc, svg_element, tag_name, &elem); - nsIDOMSVGElement_Release(svg_element); - }else if(use_generic || doc->document_mode >= COMPAT_MODE_IE9) { + if(use_generic || doc->document_mode >= COMPAT_MODE_IE9) { hres = HTMLGenericElement_Create(doc, nselem, &elem); }else { elem = calloc(1, sizeof(HTMLElement)); @@ -8058,6 +8075,7 @@ HRESULT HTMLElement_Create(HTMLDocumentNode *doc, nsIDOMNode *nsnode, BOOL use_g } } +done: TRACE("%s ret %p\n", debugstr_w(tag_name), elem); nsIDOMElement_Release(nselem); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index c6799b482af..0d9305e2ee5 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -353,12 +353,14 @@ sync_test("builtin_toString", function() { test("selection", document.selection, "MSSelection"); } if(v >= 9) { + var xml = new DOMParser().parseFromString("foobar", "text/xml"); test("computedStyle", window.getComputedStyle(e), "CSSStyleDeclaration"); test("doctype", document.doctype, "DocumentType"); test("domParser", new DOMParser(), "DOMParser", null, "Function"); test("svgDocument", new DOMParser().parseFromString("foobar", "image/svg+xml"), v < 11 ? "Document" : "XMLDocument"); test("xhtmlDocument", new DOMParser().parseFromString("foobar", "application/xhtml+xml"), v < 11 ? "Document" : "XMLDocument"); - test("xmlDocument", new DOMParser().parseFromString("foobar", "text/xml"), v < 11 ? "Document" : "XMLDocument"); + test("xmlDocument", xml, v < 11 ? "Document" : "XMLDocument"); + test("xmlElement", xml.getElementsByTagName("tag")[0], "Element"); test("Event", document.createEvent("Event"), "Event"); test("CustomEvent", document.createEvent("CustomEvent"), "CustomEvent"); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 68c5be5c102..b868f8d62b9 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -3119,8 +3119,18 @@ sync_test("DOMParser", function() { r = r[0]; todo_wine. ok(r === xml.childNodes[0], "anchor of XML document with mime type " + m + " = " + r); + r = Object.prototype.toString.call(xml.getElementsByTagName("a")[0]); + todo_wine. + ok(r === "[object HTMLAnchorElement]", "element's Object.toString of XML document with mime type " + m + " = " + r); }else { ok(r.length === 0, "anchors.length of XML document with mime type " + m + " = " + r.length); + r = Object.getPrototypeOf(xml.getElementsByTagName("a")[0]); + ok(r === Element.prototype, "element's prototype of XML document with mime type " + m + " = " + r); + r = document.importNode(xml.childNodes[0], true); + ok(r.nodeName === "a", "imported node name of XML document with mime type " + m + " = " + r.nodeName); + ok(r.nodeValue === null, "imported node value of XML document with mime type " + m + " = " + r.nodeValue); + r = Object.getPrototypeOf(r); + ok(r === Element.prototype, "imported node's prototype of XML document with mime type " + m + " = " + r); } } From a0164b0e48d68d6d25897aa54a6bd03ed05d8ab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:08 +0200 Subject: [PATCH 0934/2777] mshtml: Add window.msCrypto stub. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlwindow.c | 26 ++++- dlls/mshtml/mshtml_private.h | 4 + dlls/mshtml/mshtml_private_iface.idl | 24 ++++- dlls/mshtml/omnavigator.c | 153 +++++++++++++++++++++++++++ dlls/mshtml/tests/documentmode.js | 8 ++ dlls/mshtml/tests/es5.js | 11 ++ 6 files changed, 221 insertions(+), 5 deletions(-) diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 157ca111334..996f80f4e74 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -559,6 +559,8 @@ static void release_inner_window(HTMLInnerWindow *This) detach_html_storage(This->local_storage); IHTMLStorage_Release(This->local_storage); } + if(This->crypto) + IWineMSHTMLCrypto_Release(This->crypto); IHTMLPerformanceTiming_Release(&This->performance_timing->IHTMLPerformanceTiming_iface); VariantClear(&This->performance); @@ -3628,6 +3630,21 @@ static HRESULT WINAPI window_private_get_console(IWineHTMLWindowPrivate *iface, return S_OK; } +static HRESULT WINAPI window_private_get_msCrypto(IWineHTMLWindowPrivate *iface, IDispatch **crypto) +{ + HTMLInnerWindow *This = impl_from_IWineHTMLWindowPrivateVtbl(iface)->inner_window; + + TRACE("iface %p, crypto %p.\n", iface, crypto); + + if(!This->crypto) + create_crypto(This, &This->crypto); + + *crypto = (IDispatch*)This->crypto; + if(This->crypto) + IWineMSHTMLCrypto_AddRef(This->crypto); + return S_OK; +} + static const IWineHTMLWindowPrivateVtbl WineHTMLWindowPrivateVtbl = { window_private_QueryInterface, window_private_AddRef, @@ -3638,8 +3655,9 @@ static const IWineHTMLWindowPrivateVtbl WineHTMLWindowPrivateVtbl = { window_private_Invoke, window_private_requestAnimationFrame, window_private_cancelAnimationFrame, - window_private_get_console, window_private_matchMedia, + window_private_get_console, + window_private_get_msCrypto }; static inline HTMLWindow *impl_from_IWineHTMLWindowCompatPrivateVtbl(IWineHTMLWindowCompatPrivate *iface) @@ -4822,13 +4840,17 @@ static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compa {DISPID_IHTMLWINDOW6_POSTMESSAGE, IHTMLWindow6_postMessage_hook}, {DISPID_UNKNOWN} }; + static const dispex_hook_t private_ie10_hooks[] = { + {DISPID_IWINEHTMLWINDOWPRIVATE_MSCRYPTO}, + {DISPID_UNKNOWN} + }; if(compat_mode >= COMPAT_MODE_IE9) dispex_info_add_interface(info, IHTMLWindow7_tid, NULL); else dispex_info_add_interface(info, IWineHTMLWindowCompatPrivate_tid, NULL); if(compat_mode >= COMPAT_MODE_IE10) - dispex_info_add_interface(info, IWineHTMLWindowPrivate_tid, NULL); + dispex_info_add_interface(info, IWineHTMLWindowPrivate_tid, compat_mode <= COMPAT_MODE_IE10 ? private_ie10_hooks : NULL); dispex_info_add_interface(info, IHTMLWindow6_tid, window6_hooks); dispex_info_add_interface(info, IHTMLWindow5_tid, NULL); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index e6bff647ebb..9a3da55c802 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -388,6 +388,7 @@ typedef struct ScriptHost ScriptHost; XIID(IWinePageTransitionEvent) \ XIID(IWineXMLHttpRequestPrivate) \ XIID(IWineMSHTMLConsole) \ + XIID(IWineMSHTMLCrypto) \ XIID(IWineMSHTMLMediaQueryList) typedef enum { @@ -463,6 +464,7 @@ PRIVATE_TID_LIST #define PROXY_PROTOTYPE_LIST \ X(Console, "Console", console_dispex, Object) \ + X(Crypto, "Crypto", crypto_dispex, Object) \ X(DOMParser, "DOMParser", DOMParser_dispex, Object) \ X(DOMEvent, "Event", DOMEvent_dispex, Object) \ X(DOMCustomEvent, "CustomEvent", DOMCustomEvent_dispex, DOMEvent) \ @@ -819,6 +821,7 @@ struct HTMLInnerWindow { IOmNavigator *navigator; IHTMLStorage *session_storage; IHTMLStorage *local_storage; + IWineMSHTMLCrypto *crypto; BOOL performance_initialized; VARIANT performance; @@ -1700,6 +1703,7 @@ IInternetSecurityManager *get_security_manager(void) DECLSPEC_HIDDEN; extern HINSTANCE hInst DECLSPEC_HIDDEN; void create_console(HTMLInnerWindow *window, IWineMSHTMLConsole **ret) DECLSPEC_HIDDEN; +void create_crypto(HTMLInnerWindow *window, IWineMSHTMLCrypto **ret) DECLSPEC_HIDDEN; HRESULT create_media_query_list(HTMLWindow *window, BSTR media_query, IDispatch **ret) DECLSPEC_HIDDEN; extern const IUnknownVtbl legacy_ctor_vtbl DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl index 512942d7809..1bad302f840 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -95,6 +95,22 @@ interface IWineMSHTMLMediaQueryList : IDispatch HRESULT removeListener([in] VARIANT *listener); } +[ + odl, + oleautomation, + dual, + hidden, + uuid(fd55b4b6-2813-4fb4-829d-380099474ab2) +] +interface IWineMSHTMLCrypto : IDispatch +{ + [propget, id(1)] + HRESULT subtle([retval, out] IDispatch **subtle); + [id(2)] + HRESULT getRandomValues([in] VARIANT *typedArray, [retval, out] IDispatch **ret); +} + +const long DISPID_IWINEHTMLWINDOWPRIVATE_MSCRYPTO = 54; [ odl, oleautomation, @@ -108,10 +124,12 @@ interface IWineHTMLWindowPrivate : IDispatch HRESULT requestAnimationFrame([in] VARIANT *expr, [retval, out] VARIANT *timer_id); [id(51)] HRESULT cancelAnimationFrame([in] VARIANT timer_id); - [propget, id(52)] - HRESULT console([retval, out] IDispatch **console); - [id(53)] + [id(52)] HRESULT matchMedia([in] BSTR media_query, [retval, out] IDispatch **media_query_list); + [propget, id(53)] + HRESULT console([retval, out] IDispatch **console); + [propget, id(DISPID_IWINEHTMLWINDOWPRIVATE_MSCRYPTO)] + HRESULT msCrypto([retval, out] IDispatch **crypto); } [ diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 2866e677b5c..4c1f2f50160 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -3169,3 +3169,156 @@ HRESULT create_media_query_list(HTMLWindow *window, BSTR media_query, IDispatch *ret = (IDispatch*)&media_query_list->IWineMSHTMLMediaQueryList_iface; return S_OK; } + +struct crypto { + DispatchEx dispex; + IWineMSHTMLCrypto IWineMSHTMLCrypto_iface; + LONG ref; +}; + +static inline struct crypto *impl_from_IWineMSHTMLCrypto(IWineMSHTMLCrypto *iface) +{ + return CONTAINING_RECORD(iface, struct crypto, IWineMSHTMLCrypto_iface); +} + +static HRESULT WINAPI crypto_QueryInterface(IWineMSHTMLCrypto *iface, REFIID riid, void **ppv) +{ + struct crypto *crypto = impl_from_IWineMSHTMLCrypto(iface); + + TRACE("(%p)->(%s %p)\n", crypto, debugstr_mshtml_guid(riid), ppv); + + if(IsEqualGUID(&IID_IUnknown, riid)) { + *ppv = &crypto->IWineMSHTMLCrypto_iface; + }else if(IsEqualGUID(&IID_IWineMSHTMLCrypto, riid)) { + *ppv = &crypto->IWineMSHTMLCrypto_iface; + }else if(dispex_query_interface(&crypto->dispex, riid, ppv)) { + return *ppv ? S_OK : E_NOINTERFACE; + }else { + WARN("(%p)->(%s %p)\n", crypto, debugstr_mshtml_guid(riid), ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI crypto_AddRef(IWineMSHTMLCrypto *iface) +{ + struct crypto *crypto = impl_from_IWineMSHTMLCrypto(iface); + LONG ref = InterlockedIncrement(&crypto->ref); + + TRACE("(%p) ref=%ld\n", crypto, ref); + + return ref; +} + +static ULONG WINAPI crypto_Release(IWineMSHTMLCrypto *iface) +{ + struct crypto *crypto = impl_from_IWineMSHTMLCrypto(iface); + LONG ref = InterlockedDecrement(&crypto->ref); + + TRACE("(%p) ref=%ld\n", crypto, ref); + + if(!ref) { + release_dispex(&crypto->dispex); + free(crypto); + } + + return ref; +} + +static HRESULT WINAPI crypto_GetTypeInfoCount(IWineMSHTMLCrypto *iface, UINT *pctinfo) +{ + struct crypto *crypto = impl_from_IWineMSHTMLCrypto(iface); + + TRACE("(%p)->(%p)\n", crypto, pctinfo); + + return IDispatchEx_GetTypeInfoCount(&crypto->dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI crypto_GetTypeInfo(IWineMSHTMLCrypto *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + struct crypto *crypto = impl_from_IWineMSHTMLCrypto(iface); + + return IDispatchEx_GetTypeInfo(&crypto->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI crypto_GetIDsOfNames(IWineMSHTMLCrypto *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + struct crypto *crypto = impl_from_IWineMSHTMLCrypto(iface); + + return IDispatchEx_GetIDsOfNames(&crypto->dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI crypto_Invoke(IWineMSHTMLCrypto *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + struct crypto *crypto = impl_from_IWineMSHTMLCrypto(iface); + + return IDispatchEx_Invoke(&crypto->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI crypto_get_subtle(IWineMSHTMLCrypto *iface, IDispatch **subtle) +{ + struct crypto *crypto = impl_from_IWineMSHTMLCrypto(iface); + + FIXME("(%p)->(%p)\n", crypto, subtle); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_getRandomValues(IWineMSHTMLCrypto *iface, VARIANT *typedArray, IDispatch **ret) +{ + struct crypto *crypto = impl_from_IWineMSHTMLCrypto(iface); + + FIXME("(%p)->(%p %p)\n", crypto, typedArray, ret); + + return E_NOTIMPL; +} + +static const IWineMSHTMLCryptoVtbl WineMSHTMLCryptoVtbl = { + crypto_QueryInterface, + crypto_AddRef, + crypto_Release, + crypto_GetTypeInfoCount, + crypto_GetTypeInfo, + crypto_GetIDsOfNames, + crypto_Invoke, + crypto_get_subtle, + crypto_getRandomValues +}; + +static const tid_t crypto_iface_tids[] = { + IWineMSHTMLCrypto_tid, + 0 +}; +dispex_static_data_t crypto_dispex = { + L"Crypto", + NULL, + PROTO_ID_Crypto, + IWineMSHTMLCrypto_tid, + crypto_iface_tids +}; + +void create_crypto(HTMLInnerWindow *window, IWineMSHTMLCrypto **ret) +{ + struct crypto *obj; + + if(!(obj = calloc(1, sizeof(*obj)))) { + ERR("No memory.\n"); + return; + } + + obj->IWineMSHTMLCrypto_iface.lpVtbl = &WineMSHTMLCryptoVtbl; + obj->ref = 1; + init_dispatch(&obj->dispex, (IUnknown*)&obj->IWineMSHTMLCrypto_iface, &crypto_dispex, + window, dispex_compat_mode(&window->event_target.dispex)); + + *ret = &obj->IWineMSHTMLCrypto_iface; +} diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 0d9305e2ee5..4d39368a322 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -373,6 +373,9 @@ sync_test("builtin_toString", function() { test("console", window.console, "Console"); test("mediaQueryList", window.matchMedia("(hover:hover)"), "MediaQueryList"); } + if(v >= 11) { + test("crypto", window.msCrypto, "Crypto"); + } if(v >= 9) { document.body.innerHTML = ""; test("comment", document.body.firstChild, "Comment"); @@ -917,6 +920,9 @@ sync_test("builtin_prototypes", function() { set_obj("TextRange"); set_obj("Window"); } + if(v >= 11) { + set_obj("Crypto"); + } if(v >= 8 && v < 11) { set_obj(v < 9 ? "Event" : "MSEventObj", document.createEventObject()); @@ -1274,6 +1280,7 @@ sync_test("builtin_prototypes", function() { [ "ClientRectList", "Object" ], [ "Comment", "CharacterData" ], [ "Console", "Object" ], + [ "Crypto", "Object" ], [ "CSSRule", "Object" ], [ "CSSStyleDeclaration", "Object" ], [ "CSSStyleRule", "CSSRule" ], @@ -1639,6 +1646,7 @@ sync_test("window_props", function() { test_exposed("console", v >= 10); test_exposed("DOMParser", v >= 9); test_exposed("matchMedia", v >= 10); + test_exposed("msCrypto", v >= 11); }); sync_test("domimpl_props", function() { diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index b868f8d62b9..cbcdee066f4 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -3049,6 +3049,17 @@ sync_test("matchMedia", function() { ok(mql.matches === true, "(max-width: 1000px) does not match"); }); +sync_test("Crypto", function() { + var crypto = window.msCrypto, r; + ok(Object.prototype.hasOwnProperty.call(Object.getPrototypeOf(window), "msCrypto"), "msCrypto not a property of window's prototype."); + r = Object.getPrototypeOf(crypto); + ok(r === window.Crypto.prototype, "getPrototypeOf(crypto) = " + r); + + ok("subtle" in crypto, "subtle not in crypto"); + ok("getRandomValues" in crypto, "getRandomValues not in crypto"); + ok(!("randomUUID" in crypto), "randomUUID is in crypto"); +}); + sync_test("DOMParser", function() { var p, r = DOMParser.length, mimeType; ok(r === 0, "length = " + r); From 1c549ea463f2f8f2722a8ea6efffdc1aad9e803f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:09 +0200 Subject: [PATCH 0935/2777] mshtml: Add window.msCrypto.subtle stub. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/mshtml_private.h | 2 + dlls/mshtml/mshtml_private_iface.idl | 40 ++++ dlls/mshtml/omnavigator.c | 264 ++++++++++++++++++++++++++- dlls/mshtml/tests/documentmode.js | 3 + dlls/mshtml/tests/es5.js | 5 + 5 files changed, 309 insertions(+), 5 deletions(-) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 9a3da55c802..352b838a03d 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -389,6 +389,7 @@ typedef struct ScriptHost ScriptHost; XIID(IWineXMLHttpRequestPrivate) \ XIID(IWineMSHTMLConsole) \ XIID(IWineMSHTMLCrypto) \ + XIID(IWineMSHTMLSubtleCrypto) \ XIID(IWineMSHTMLMediaQueryList) typedef enum { @@ -465,6 +466,7 @@ PRIVATE_TID_LIST #define PROXY_PROTOTYPE_LIST \ X(Console, "Console", console_dispex, Object) \ X(Crypto, "Crypto", crypto_dispex, Object) \ + X(SubtleCrypto, "SubtleCrypto", crypto_subtle_dispex, Object) \ X(DOMParser, "DOMParser", DOMParser_dispex, Object) \ X(DOMEvent, "Event", DOMEvent_dispex, Object) \ X(DOMCustomEvent, "CustomEvent", DOMCustomEvent_dispex, DOMEvent) \ diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl index 1bad302f840..d53feeaf71c 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -110,6 +110,46 @@ interface IWineMSHTMLCrypto : IDispatch HRESULT getRandomValues([in] VARIANT *typedArray, [retval, out] IDispatch **ret); } +[ + odl, + oleautomation, + dual, + hidden, + uuid(fd55b4b6-2813-4fb4-829d-380099474ab3) +] +interface IWineMSHTMLSubtleCrypto : IDispatch +{ + [id(1)] + HRESULT encrypt([in] VARIANT *algorithm, [in] VARIANT *key, [in] VARIANT *data, [retval, out] IDispatch **result); + [id(2)] + HRESULT decrypt([in] VARIANT *algorithm, [in] VARIANT *key, [in] VARIANT *data, [retval, out] IDispatch **result); + [id(3)] + HRESULT sign([in] VARIANT *algorithm, [in] VARIANT *key, [in] VARIANT *data, [retval, out] IDispatch **signature); + [id(4)] + HRESULT verify([in] VARIANT *algorithm, [in] VARIANT *key, [in] VARIANT *signature, [in] VARIANT *data, + [retval, out] IDispatch **result); + [id(5)] + HRESULT digest([in] VARIANT *algorithm, [in] VARIANT *data, [retval, out] IDispatch **digest); + [id(6)] + HRESULT generateKey([in] VARIANT *algorithm, VARIANT_BOOL extractable, [in] VARIANT *keyUsages, + [retval, out] IDispatch **result); + [id(7)] + HRESULT deriveKey([in] VARIANT *algorithm, [in] VARIANT *baseKey, [in] VARIANT *derivedKeyAlgorithm, + VARIANT_BOOL extractable, [in] VARIANT *keyUsages, [retval, out] IDispatch **result); + [id(8)] + HRESULT importKey([in] BSTR format, [in] VARIANT *keyData, [in] VARIANT *algorithm, VARIANT_BOOL extractable, + [in] VARIANT *keyUsages, [retval, out] IDispatch **result); + [id(9)] + HRESULT exportKey([in] BSTR format, [in] VARIANT *key, [retval, out] IDispatch **result); + [id(10)] + HRESULT wrapKey([in] BSTR format, [in] VARIANT *key, [in] VARIANT *wrappingKey, [in] VARIANT *wrapAlgo, + [retval, out] IDispatch **result); + [id(11)] + HRESULT unwrapKey([in] BSTR format, [in] VARIANT *wrappedKey, [in] VARIANT *unwrappingKey, + [in] VARIANT *unwrapAlgo, [in] VARIANT *unwrappedKeyAlgo, VARIANT_BOOL extractable, + [in] VARIANT *keyUsages, [retval, out] IDispatch **result); +} + const long DISPID_IWINEHTMLWINDOWPRIVATE_MSCRYPTO = 54; [ odl, diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 4c1f2f50160..7278ef0d280 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -3170,9 +3170,251 @@ HRESULT create_media_query_list(HTMLWindow *window, BSTR media_query, IDispatch return S_OK; } +struct crypto_subtle { + DispatchEx dispex; + IWineMSHTMLSubtleCrypto IWineMSHTMLSubtleCrypto_iface; + LONG ref; +}; + +static inline struct crypto_subtle *impl_from_IWineMSHTMLSubtleCrypto(IWineMSHTMLSubtleCrypto *iface) +{ + return CONTAINING_RECORD(iface, struct crypto_subtle, IWineMSHTMLSubtleCrypto_iface); +} + +static HRESULT WINAPI crypto_subtle_QueryInterface(IWineMSHTMLSubtleCrypto *iface, REFIID riid, void **ppv) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + TRACE("(%p)->(%s %p)\n", subtle, debugstr_mshtml_guid(riid), ppv); + + if(IsEqualGUID(&IID_IUnknown, riid)) { + *ppv = &subtle->IWineMSHTMLSubtleCrypto_iface; + }else if(IsEqualGUID(&IID_IWineMSHTMLSubtleCrypto, riid)) { + *ppv = &subtle->IWineMSHTMLSubtleCrypto_iface; + }else if(dispex_query_interface(&subtle->dispex, riid, ppv)) { + return *ppv ? S_OK : E_NOINTERFACE; + }else { + WARN("(%p)->(%s %p)\n", subtle, debugstr_mshtml_guid(riid), ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI crypto_subtle_AddRef(IWineMSHTMLSubtleCrypto *iface) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + LONG ref = InterlockedIncrement(&subtle->ref); + + TRACE("(%p) ref=%ld\n", subtle, ref); + + return ref; +} + +static ULONG WINAPI crypto_subtle_Release(IWineMSHTMLSubtleCrypto *iface) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + LONG ref = InterlockedDecrement(&subtle->ref); + + TRACE("(%p) ref=%ld\n", subtle, ref); + + if(!ref) { + release_dispex(&subtle->dispex); + free(subtle); + } + + return ref; +} + +static HRESULT WINAPI crypto_subtle_GetTypeInfoCount(IWineMSHTMLSubtleCrypto *iface, UINT *pctinfo) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + TRACE("(%p)->(%p)\n", subtle, pctinfo); + + return IDispatchEx_GetTypeInfoCount(&subtle->dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI crypto_subtle_GetTypeInfo(IWineMSHTMLSubtleCrypto *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + return IDispatchEx_GetTypeInfo(&subtle->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI crypto_subtle_GetIDsOfNames(IWineMSHTMLSubtleCrypto *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + return IDispatchEx_GetIDsOfNames(&subtle->dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI crypto_subtle_Invoke(IWineMSHTMLSubtleCrypto *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + return IDispatchEx_Invoke(&subtle->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI crypto_subtle_encrypt(IWineMSHTMLSubtleCrypto *iface, VARIANT *algorithm, VARIANT *key, + VARIANT *data, IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%p %p %p %p)\n", subtle, algorithm, key, data, result); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_decrypt(IWineMSHTMLSubtleCrypto *iface, VARIANT *algorithm, VARIANT *key, + VARIANT *data, IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%p %p %p %p)\n", subtle, algorithm, key, data, result); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_sign(IWineMSHTMLSubtleCrypto *iface, VARIANT *algorithm, VARIANT *key, + VARIANT *data, IDispatch **signature) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%p %p %p %p)\n", subtle, algorithm, key, data, signature); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_verify(IWineMSHTMLSubtleCrypto *iface, VARIANT *algorithm, VARIANT *key, + VARIANT *signature, VARIANT *data, IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%p %p %p %p %p)\n", subtle, algorithm, key, signature, data, result); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_digest(IWineMSHTMLSubtleCrypto *iface, VARIANT *algorithm, VARIANT *data, + IDispatch **digest) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%p %p %p)\n", subtle, algorithm, data, digest); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_generateKey(IWineMSHTMLSubtleCrypto *iface, VARIANT *algorithm, + VARIANT_BOOL extractable, VARIANT *keyUsages, IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%p %x %p %p)\n", subtle, algorithm, extractable, keyUsages, result); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_deriveKey(IWineMSHTMLSubtleCrypto *iface, VARIANT *algorithm, VARIANT *baseKey, + VARIANT *derivedKeyAlgorithm, VARIANT_BOOL extractable, VARIANT *keyUsages, IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%p %p %p %x %p %p)\n", subtle, algorithm, baseKey, derivedKeyAlgorithm, extractable, + keyUsages, result); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_importKey(IWineMSHTMLSubtleCrypto *iface, BSTR format, VARIANT *keyData, + VARIANT *algorithm, VARIANT_BOOL extractable, VARIANT *keyUsages, IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%s %p %p %x %p %p)\n", subtle, debugstr_w(format), keyData, algorithm, extractable, + keyUsages, result); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_exportKey(IWineMSHTMLSubtleCrypto *iface, BSTR format, VARIANT *key, + IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%s %p %p)\n", subtle, debugstr_w(format), key, result); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_wrapKey(IWineMSHTMLSubtleCrypto *iface, BSTR format, VARIANT *key, + VARIANT *wrappingKey, VARIANT *wrapAlgo, IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%s %p %p %p %p)\n", subtle, debugstr_w(format), key, wrappingKey, wrapAlgo, result); + + return E_NOTIMPL; +} + +static HRESULT WINAPI crypto_subtle_unwrapKey(IWineMSHTMLSubtleCrypto *iface, BSTR format, VARIANT *wrappedKey, + VARIANT *unwrappingKey, VARIANT *unwrapAlgo, VARIANT *unwrappedKeyAlgo, VARIANT_BOOL extractable, + VARIANT *keyUsages, IDispatch **result) +{ + struct crypto_subtle *subtle = impl_from_IWineMSHTMLSubtleCrypto(iface); + + FIXME("(%p)->(%s %p %p %p %p %x %p %p)\n", subtle, debugstr_w(format), wrappedKey, unwrappingKey, unwrapAlgo, + unwrappedKeyAlgo, extractable, keyUsages, result); + + return E_NOTIMPL; +} + +static const IWineMSHTMLSubtleCryptoVtbl WineMSHTMLSubtleCryptoVtbl = { + crypto_subtle_QueryInterface, + crypto_subtle_AddRef, + crypto_subtle_Release, + crypto_subtle_GetTypeInfoCount, + crypto_subtle_GetTypeInfo, + crypto_subtle_GetIDsOfNames, + crypto_subtle_Invoke, + crypto_subtle_encrypt, + crypto_subtle_decrypt, + crypto_subtle_sign, + crypto_subtle_verify, + crypto_subtle_digest, + crypto_subtle_generateKey, + crypto_subtle_deriveKey, + crypto_subtle_importKey, + crypto_subtle_exportKey, + crypto_subtle_wrapKey, + crypto_subtle_unwrapKey +}; + +static const tid_t crypto_subtle_iface_tids[] = { + IWineMSHTMLSubtleCrypto_tid, + 0 +}; +dispex_static_data_t crypto_subtle_dispex = { + L"SubtleCrypto", + NULL, + PROTO_ID_SubtleCrypto, + IWineMSHTMLSubtleCrypto_tid, + crypto_subtle_iface_tids +}; + struct crypto { DispatchEx dispex; IWineMSHTMLCrypto IWineMSHTMLCrypto_iface; + struct crypto_subtle *subtle; LONG ref; }; @@ -3221,6 +3463,7 @@ static ULONG WINAPI crypto_Release(IWineMSHTMLCrypto *iface) TRACE("(%p) ref=%ld\n", crypto, ref); if(!ref) { + IWineMSHTMLSubtleCrypto_Release(&crypto->subtle->IWineMSHTMLSubtleCrypto_iface); release_dispex(&crypto->dispex); free(crypto); } @@ -3268,9 +3511,11 @@ static HRESULT WINAPI crypto_get_subtle(IWineMSHTMLCrypto *iface, IDispatch **su { struct crypto *crypto = impl_from_IWineMSHTMLCrypto(iface); - FIXME("(%p)->(%p)\n", crypto, subtle); + TRACE("(%p)->(%p)\n", crypto, subtle); - return E_NOTIMPL; + *subtle = (IDispatch*)&crypto->subtle->dispex.IDispatchEx_iface; + IWineMSHTMLSubtleCrypto_AddRef(&crypto->subtle->IWineMSHTMLSubtleCrypto_iface); + return S_OK; } static HRESULT WINAPI crypto_getRandomValues(IWineMSHTMLCrypto *iface, VARIANT *typedArray, IDispatch **ret) @@ -3308,17 +3553,26 @@ dispex_static_data_t crypto_dispex = { void create_crypto(HTMLInnerWindow *window, IWineMSHTMLCrypto **ret) { + compat_mode_t compat_mode = dispex_compat_mode(&window->event_target.dispex); + struct crypto_subtle *subtle; struct crypto *obj; - if(!(obj = calloc(1, sizeof(*obj)))) { + if(!(obj = calloc(1, sizeof(*obj))) || !(subtle = calloc(1, sizeof(*subtle)))) { ERR("No memory.\n"); + free(obj); return; } obj->IWineMSHTMLCrypto_iface.lpVtbl = &WineMSHTMLCryptoVtbl; obj->ref = 1; - init_dispatch(&obj->dispex, (IUnknown*)&obj->IWineMSHTMLCrypto_iface, &crypto_dispex, - window, dispex_compat_mode(&window->event_target.dispex)); + obj->subtle = subtle; + + init_dispatch(&obj->dispex, (IUnknown*)&obj->IWineMSHTMLCrypto_iface, &crypto_dispex, window, compat_mode); + + subtle->IWineMSHTMLSubtleCrypto_iface.lpVtbl = &WineMSHTMLSubtleCryptoVtbl; + subtle->ref = 1; + init_dispatch(&subtle->dispex, (IUnknown*)&subtle->IWineMSHTMLSubtleCrypto_iface, &crypto_subtle_dispex, + window, compat_mode); *ret = &obj->IWineMSHTMLCrypto_iface; } diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 4d39368a322..0e7751f204d 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -375,6 +375,7 @@ sync_test("builtin_toString", function() { } if(v >= 11) { test("crypto", window.msCrypto, "Crypto"); + test("crypto.subtle", window.msCrypto.subtle, "SubtleCrypto"); } if(v >= 9) { document.body.innerHTML = ""; @@ -922,6 +923,7 @@ sync_test("builtin_prototypes", function() { } if(v >= 11) { set_obj("Crypto"); + set_obj("SubtleCrypto"); } if(v >= 8 && v < 11) { @@ -1355,6 +1357,7 @@ sync_test("builtin_prototypes", function() { [ "StorageEvent", "Event" ], [ "StyleSheet", "Object" ], [ "StyleSheetList", "Object" ], + [ "SubtleCrypto", "Object" ], [ "Text", "CharacterData" ], [ "TextRange", "Object" ], [ "UIEvent", "Event" ], diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index cbcdee066f4..273675b03b3 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -3058,6 +3058,11 @@ sync_test("Crypto", function() { ok("subtle" in crypto, "subtle not in crypto"); ok("getRandomValues" in crypto, "getRandomValues not in crypto"); ok(!("randomUUID" in crypto), "randomUUID is in crypto"); + + var list = [ "decrypt", "deriveKey", "digest", "encrypt", "exportKey", "generateKey", "importKey", "sign", "unwrapKey", "verify", "wrapKey" ]; + for(var i = 0; i < list.length; i++) + ok(list[i] in crypto.subtle, list[i] + " not in crypto.subtle"); + ok(!("deriveBits" in crypto.subtle), "deriveBits is in crypto.subtle"); }); sync_test("DOMParser", function() { From dee1f4d084ac1e5946c006b12fc73caa4e0c993e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:09 +0200 Subject: [PATCH 0936/2777] mshtml: Implement window.msCrypto.getRandomValues. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/arraybuf.c | 36 ++++++++++++++++- dlls/jscript/dispex.c | 1 + dlls/jscript/jscript.h | 3 ++ dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/omnavigator.c | 19 ++++++++- dlls/mshtml/tests/es5.js | 77 +++++++++++++++++++++++++++++++++++- 6 files changed, 133 insertions(+), 4 deletions(-) diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index e5c22df53c4..01d226fe675 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -20,7 +20,14 @@ #include #include #include - +#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "ntsecapi.h" #include "jscript.h" #include "wine/debug.h" @@ -1270,6 +1277,33 @@ static const builtin_info_t TypedArrayConstr_info = { NULL }; +HRESULT WINAPI WineDispatchProxyCbPrivate_GetRandomValues(IDispatch *disp) +{ + jsdisp_t *obj = to_jsdisp(disp); + TypedArrayInstance *typedarr; + DWORD size; + + if(!obj || obj->builtin_info->class < FIRST_TYPEDARRAY_JSCLASS || obj->builtin_info->class > LAST_TYPEDARRAY_JSCLASS) + return E_INVALIDARG; + + if(obj->builtin_info->class == JSCLASS_FLOAT32ARRAY || obj->builtin_info->class == JSCLASS_FLOAT64ARRAY) { + /* FIXME: Return TypeMismatchError */ + return E_FAIL; + } + + typedarr = typedarr_from_jsdisp(obj); + size = typedarr->length * TypedArray_elem_size[TYPEDARRAY_INDEX(obj->builtin_info->class)]; + if(size > 65536) { + /* FIXME: Return QuotaExceededError */ + return E_FAIL; + } + + if(!RtlGenRandom(&arraybuf_from_jsdisp(typedarr->buffer)->buf[typedarr->offset], size)) + return HRESULT_FROM_WIN32(GetLastError()); + + return S_OK; +} + HRESULT init_arraybuf_constructors(script_ctx_t *ctx) { static const struct { diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 904e12a1960..b87a68cfc1e 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2746,6 +2746,7 @@ static IWineDispatchProxyCbPrivateVtbl WineDispatchProxyCbPrivateVtbl = { WineDispatchProxyCbPrivate_HostUpdated, WineDispatchProxyCbPrivate_CreateConstructor, WineDispatchProxyCbPrivate_DefineConstructor, + WineDispatchProxyCbPrivate_GetRandomValues, WineDispatchProxyCbPrivate_PropEnum }; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 22cc3773eb6..a08b1509e11 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -106,6 +106,7 @@ typedef struct { HRESULT (STDMETHODCALLTYPE *HostUpdated)(IWineDispatchProxyCbPrivate *This, IActiveScript *script); IDispatch* (STDMETHODCALLTYPE *CreateConstructor)(IWineDispatchProxyCbPrivate *This, IDispatch *disp, const WCHAR *name); HRESULT (STDMETHODCALLTYPE *DefineConstructor)(IWineDispatchProxyCbPrivate *This, const WCHAR *name, IDispatch *prot, IDispatch *ctor); + HRESULT (STDMETHODCALLTYPE *GetRandomValues)(IDispatch *typedarr); HRESULT (STDMETHODCALLTYPE *PropEnum)(IWineDispatchProxyCbPrivate *This, const WCHAR *name); } IWineDispatchProxyCbPrivateVtbl; @@ -684,3 +685,5 @@ static inline void unlock_module(void) { InterlockedDecrement(&module_ref); } + +HRESULT WINAPI WineDispatchProxyCbPrivate_GetRandomValues(IDispatch*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 352b838a03d..72fb575a17c 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -99,6 +99,7 @@ typedef struct { HRESULT (STDMETHODCALLTYPE *HostUpdated)(IWineDispatchProxyCbPrivate *This, IActiveScript *script); IDispatch* (STDMETHODCALLTYPE *CreateConstructor)(IWineDispatchProxyCbPrivate *This, IDispatch *disp, const WCHAR *name); HRESULT (STDMETHODCALLTYPE *DefineConstructor)(IWineDispatchProxyCbPrivate *This, const WCHAR *name, IDispatch *prot, IDispatch *ctor); + HRESULT (STDMETHODCALLTYPE *GetRandomValues)(IDispatch *typedarr); HRESULT (STDMETHODCALLTYPE *PropEnum)(IWineDispatchProxyCbPrivate *This, const WCHAR *name); } IWineDispatchProxyCbPrivateVtbl; diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 7278ef0d280..888cdaec248 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -3521,10 +3521,25 @@ static HRESULT WINAPI crypto_get_subtle(IWineMSHTMLCrypto *iface, IDispatch **su static HRESULT WINAPI crypto_getRandomValues(IWineMSHTMLCrypto *iface, VARIANT *typedArray, IDispatch **ret) { struct crypto *crypto = impl_from_IWineMSHTMLCrypto(iface); + IWineDispatchProxyCbPrivate *proxy; + HRESULT hres; - FIXME("(%p)->(%p %p)\n", crypto, typedArray, ret); + TRACE("(%p)->(%p %p)\n", crypto, typedArray, ret); - return E_NOTIMPL; + if(V_VT(typedArray) != VT_DISPATCH || !V_DISPATCH(typedArray)) + return E_INVALIDARG; + + if(!(proxy = crypto->dispex.proxy)) { + FIXME("No proxy\n"); + return E_NOTIMPL; + } + + hres = proxy->lpVtbl->GetRandomValues(V_DISPATCH(typedArray)); + if(SUCCEEDED(hres) && ret) { + *ret = V_DISPATCH(typedArray); + IDispatch_AddRef(*ret); + } + return hres; } static const IWineMSHTMLCryptoVtbl WineMSHTMLCryptoVtbl = { diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 273675b03b3..e14e948e710 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -3050,7 +3050,7 @@ sync_test("matchMedia", function() { }); sync_test("Crypto", function() { - var crypto = window.msCrypto, r; + var crypto = window.msCrypto, arr, r; ok(Object.prototype.hasOwnProperty.call(Object.getPrototypeOf(window), "msCrypto"), "msCrypto not a property of window's prototype."); r = Object.getPrototypeOf(crypto); ok(r === window.Crypto.prototype, "getPrototypeOf(crypto) = " + r); @@ -3063,6 +3063,81 @@ sync_test("Crypto", function() { for(var i = 0; i < list.length; i++) ok(list[i] in crypto.subtle, list[i] + " not in crypto.subtle"); ok(!("deriveBits" in crypto.subtle), "deriveBits is in crypto.subtle"); + + list = [ + [ "Int8Array", 65536 ], + [ "Uint8Array", 65536 ], + [ "Int16Array", 32768 ], + [ "Uint16Array", 32768 ], + [ "Int32Array", 16384 ], + [ "Uint32Array", 16384 ] + ]; + for(var i = 0; i < list.length; i++) { + var arrType = list[i][0]; + arr = eval(arrType + "(" + list[i][1] + ")"); + + ok(arr[0] === 0, arrType + "[0] = " + arr[0]); + ok(arr[1] === 0, arrType + "[1] = " + arr[1]); + r = crypto.getRandomValues(arr); + ok(r === arr, "getRandomValues returned " + r); + + arr = eval(arrType + "(" + (list[i][1]+1) + ")"); + try { + crypto.getRandomValues(arr); + }catch(ex) { + var n = ex.number >>> 0; + todo_wine. + ok(ex.name === "QuotaExceededError", "getRandomValues(oversized " + arrType + ") threw " + ex.name); + todo_wine. + ok(n === 0, "getRandomValues(oversized " + arrType + ") threw code " + n); + todo_wine. + ok(ex.message === "QuotaExceededError", "getRandomValues(oversized " + arrType + ") threw message " + ex.message); + } + } + + try { + crypto.getRandomValues(null); + ok(false, "getRandomValues(null) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === E_INVALIDARG, "getRandomValues(null) threw " + n); + } + try { + crypto.getRandomValues(external.nullDisp); + ok(false, "getRandomValues(nullDisp) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === E_INVALIDARG, "getRandomValues(nullDisp) threw " + n); + } + try { + crypto.getRandomValues([1,2,3]); + ok(false, "getRandomValues([1,2,3]) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === E_INVALIDARG, "getRandomValues([1,2,3]) threw " + n); + } + arr = Float32Array(2); + try { + crypto.getRandomValues(arr); + ok(false, "getRandomValues(Float32Array) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + todo_wine. + ok(ex.name === "TypeMismatchError", "getRandomValues(Float32Array) threw " + ex.name); + todo_wine. + ok(n === 0, "getRandomValues(Float32Array) threw code " + n); + } + arr = Float64Array(2); + try { + crypto.getRandomValues(arr); + ok(false, "getRandomValues(Float64Array) did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + todo_wine. + ok(ex.name === "TypeMismatchError", "getRandomValues(Float64Array) threw " + ex.name); + todo_wine. + ok(n === 0, "getRandomValues(Float64Array) threw code " + n); + } }); sync_test("DOMParser", function() { From e01df0b55ca54c7bc12d6f55f1fe0b13f30dcca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:09 +0200 Subject: [PATCH 0937/2777] mshtml: Add private stub interfaces for validating form/input elements. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- And some others related to them. Some of them are shared, but not always (form elements are a bit weirder). This matches native exactly. --- dlls/mshtml/htmlform.c | 129 +++++- dlls/mshtml/htmlinput.c | 586 ++++++++++++++++++++++++++- dlls/mshtml/htmlobject.c | 140 ++++++- dlls/mshtml/htmlselect.c | 137 ++++++- dlls/mshtml/htmltextarea.c | 137 ++++++- dlls/mshtml/mshtml_private.h | 3 + dlls/mshtml/mshtml_private_iface.idl | 80 ++++ dlls/mshtml/tests/documentmode.js | 80 ++++ 8 files changed, 1286 insertions(+), 6 deletions(-) diff --git a/dlls/mshtml/htmlform.c b/dlls/mshtml/htmlform.c index c7439827ec3..403c288d009 100644 --- a/dlls/mshtml/htmlform.c +++ b/dlls/mshtml/htmlform.c @@ -37,6 +37,7 @@ struct HTMLFormElement { HTMLElement element; IHTMLFormElement IHTMLFormElement_iface; + IWineHTMLFormPrivate IWineHTMLFormPrivate_iface; nsIDOMHTMLFormElement *nsform; }; @@ -769,6 +770,115 @@ static const IHTMLFormElementVtbl HTMLFormElementVtbl = { HTMLFormElement_tags }; +static inline HTMLFormElement *impl_from_IWineHTMLFormPrivateVtbl(IWineHTMLFormPrivate *iface) +{ + return CONTAINING_RECORD(iface, HTMLFormElement, IWineHTMLFormPrivate_iface); +} + +static HRESULT WINAPI HTMLFormElement_private_QueryInterface(IWineHTMLFormPrivate *iface, + REFIID riid, void **ppv) +{ + HTMLFormElement *This = impl_from_IWineHTMLFormPrivateVtbl(iface); + + return IHTMLDOMNode_QueryInterface(&This->element.node.IHTMLDOMNode_iface, riid, ppv); +} + +static ULONG WINAPI HTMLFormElement_private_AddRef(IWineHTMLFormPrivate *iface) +{ + HTMLFormElement *This = impl_from_IWineHTMLFormPrivateVtbl(iface); + + return IHTMLDOMNode_AddRef(&This->element.node.IHTMLDOMNode_iface); +} + +static ULONG WINAPI HTMLFormElement_private_Release(IWineHTMLFormPrivate *iface) +{ + HTMLFormElement *This = impl_from_IWineHTMLFormPrivateVtbl(iface); + + return IHTMLDOMNode_Release(&This->element.node.IHTMLDOMNode_iface); +} + +static HRESULT WINAPI HTMLFormElement_private_GetTypeInfoCount(IWineHTMLFormPrivate *iface, UINT *pctinfo) +{ + HTMLFormElement *This = impl_from_IWineHTMLFormPrivateVtbl(iface); + return IDispatchEx_GetTypeInfoCount(&This->element.node.event_target.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLFormElement_private_GetTypeInfo(IWineHTMLFormPrivate *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLFormElement *This = impl_from_IWineHTMLFormPrivateVtbl(iface); + return IDispatchEx_GetTypeInfo(&This->element.node.event_target.dispex.IDispatchEx_iface, iTInfo, lcid, + ppTInfo); +} + +static HRESULT WINAPI HTMLFormElement_private_GetIDsOfNames(IWineHTMLFormPrivate *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + HTMLFormElement *This = impl_from_IWineHTMLFormPrivateVtbl(iface); + return IDispatchEx_GetIDsOfNames(&This->element.node.event_target.dispex.IDispatchEx_iface, riid, rgszNames, + cNames, lcid, rgDispId); +} + +static HRESULT WINAPI HTMLFormElement_private_Invoke(IWineHTMLFormPrivate *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLFormElement *This = impl_from_IWineHTMLFormPrivateVtbl(iface); + return IDispatchEx_Invoke(&This->element.node.event_target.dispex.IDispatchEx_iface, dispIdMember, riid, + lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLFormElement_private_put_enctype(IWineHTMLFormPrivate *iface, BSTR v) +{ + HTMLFormElement *This = impl_from_IWineHTMLFormPrivateVtbl(iface); + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLFormElement_private_get_enctype(IWineHTMLFormPrivate *iface, BSTR *ret) +{ + HTMLFormElement *This = impl_from_IWineHTMLFormPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLFormElement_private_put_noValidate(IWineHTMLFormPrivate *iface, VARIANT_BOOL v) +{ + HTMLFormElement *This = impl_from_IWineHTMLFormPrivateVtbl(iface); + FIXME("(%p)->(%x)\n", This, v); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLFormElement_private_get_noValidate(IWineHTMLFormPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLFormElement *This = impl_from_IWineHTMLFormPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLFormElement_private_checkValidity(IWineHTMLFormPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLFormElement *This = impl_from_IWineHTMLFormPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static const IWineHTMLFormPrivateVtbl WineHTMLFormPrivateVtbl = { + HTMLFormElement_private_QueryInterface, + HTMLFormElement_private_AddRef, + HTMLFormElement_private_Release, + HTMLFormElement_private_GetTypeInfoCount, + HTMLFormElement_private_GetTypeInfo, + HTMLFormElement_private_GetIDsOfNames, + HTMLFormElement_private_Invoke, + HTMLFormElement_private_put_enctype, + HTMLFormElement_private_get_enctype, + HTMLFormElement_private_put_noValidate, + HTMLFormElement_private_get_noValidate, + HTMLFormElement_private_checkValidity, +}; + static inline HTMLFormElement *impl_from_HTMLDOMNode(HTMLDOMNode *iface) { return CONTAINING_RECORD(iface, HTMLFormElement, element.node); @@ -789,6 +899,9 @@ static HRESULT HTMLFormElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv) }else if(IsEqualGUID(&IID_IHTMLFormElement, riid)) { TRACE("(%p)->(IID_IHTMLFormElement %p)\n", This, ppv); *ppv = &This->IHTMLFormElement_iface; + }else if(IsEqualGUID(&IID_IWineHTMLFormPrivate, riid)) { + TRACE("(%p)->(IID_IWineHTMLFormPrivate %p)\n", This, ppv); + *ppv = &This->IWineHTMLFormPrivate_iface; }else if(IsEqualGUID(&DIID_DispHTMLFormElement, riid)) { TRACE("(%p)->(DIID_DispHTMLFormElement %p)\n", This, ppv); *ppv = &This->IHTMLFormElement_iface; @@ -1001,6 +1114,19 @@ static const NodeImplVtbl HTMLFormElementImplVtbl = { HTMLFormElement_unlink }; +static void HTMLFormElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t form_private_ie9_hooks[] = { + {DISPID_IWINEHTMLFORMPRIVATE_NOVALIDATE}, + {DISPID_IWINEHTMLFORMPRIVATE_CHECKVALIDITY}, + {DISPID_UNKNOWN} + }; + HTMLElement_init_dispex_info(info, mode); + + if(mode >= COMPAT_MODE_IE9) + dispex_info_add_interface(info, IWineHTMLFormPrivate_tid, mode < COMPAT_MODE_IE10 ? form_private_ie9_hooks : NULL); +} + static const tid_t HTMLFormElement_iface_tids[] = { HTMLELEMENT_TIDS, IHTMLFormElement_tid, @@ -1013,7 +1139,7 @@ dispex_static_data_t HTMLFormElement_dispex = { PROTO_ID_HTMLFormElement, DispHTMLFormElement_tid, HTMLFormElement_iface_tids, - HTMLElement_init_dispex_info + HTMLFormElement_init_dispex_info }; HRESULT HTMLFormElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) @@ -1026,6 +1152,7 @@ HRESULT HTMLFormElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTM return E_OUTOFMEMORY; ret->IHTMLFormElement_iface.lpVtbl = &HTMLFormElementVtbl; + ret->IWineHTMLFormPrivate_iface.lpVtbl = &WineHTMLFormPrivateVtbl; ret->element.node.vtbl = &HTMLFormElementImplVtbl; HTMLElement_Init(&ret->element, doc, nselem, &HTMLFormElement_dispex); diff --git a/dlls/mshtml/htmlinput.c b/dlls/mshtml/htmlinput.c index e182b4eb3d6..b4c097ca87c 100644 --- a/dlls/mshtml/htmlinput.c +++ b/dlls/mshtml/htmlinput.c @@ -39,6 +39,8 @@ struct HTMLInputElement { IHTMLInputElement IHTMLInputElement_iface; IHTMLInputTextElement IHTMLInputTextElement_iface; IHTMLInputTextElement2 IHTMLInputTextElement2_iface; + IWineHTMLInputPrivate IWineHTMLInputPrivate_iface; + IWineHTMLParentFormPrivate IWineHTMLParentFormPrivate_iface; nsIDOMHTMLInputElement *nsinput; }; @@ -1330,6 +1332,277 @@ static const IHTMLInputTextElement2Vtbl HTMLInputTextElement2Vtbl = { HTMLInputTextElement2_setSelectionRange }; +static inline HTMLInputElement *impl_from_IWineHTMLInputPrivateVtbl(IWineHTMLInputPrivate *iface) +{ + return CONTAINING_RECORD(iface, HTMLInputElement, IWineHTMLInputPrivate_iface); +} + +static HRESULT WINAPI HTMLInputElement_private_QueryInterface(IWineHTMLInputPrivate *iface, + REFIID riid, void **ppv) +{ + HTMLInputElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IHTMLDOMNode_QueryInterface(&This->element.node.IHTMLDOMNode_iface, riid, ppv); +} + +static ULONG WINAPI HTMLInputElement_private_AddRef(IWineHTMLInputPrivate *iface) +{ + HTMLInputElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IHTMLDOMNode_AddRef(&This->element.node.IHTMLDOMNode_iface); +} + +static ULONG WINAPI HTMLInputElement_private_Release(IWineHTMLInputPrivate *iface) +{ + HTMLInputElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IHTMLDOMNode_Release(&This->element.node.IHTMLDOMNode_iface); +} + +static HRESULT WINAPI HTMLInputElement_private_GetTypeInfoCount(IWineHTMLInputPrivate *iface, UINT *pctinfo) +{ + HTMLInputElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_GetTypeInfoCount(&This->element.node.event_target.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLInputElement_private_GetTypeInfo(IWineHTMLInputPrivate *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLInputElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_GetTypeInfo(&This->element.node.event_target.dispex.IDispatchEx_iface, iTInfo, lcid, + ppTInfo); +} + +static HRESULT WINAPI HTMLInputElement_private_GetIDsOfNames(IWineHTMLInputPrivate *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + HTMLInputElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_GetIDsOfNames(&This->element.node.event_target.dispex.IDispatchEx_iface, riid, rgszNames, + cNames, lcid, rgDispId); +} + +static HRESULT WINAPI HTMLInputElement_private_Invoke(IWineHTMLInputPrivate *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLInputElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_Invoke(&This->element.node.event_target.dispex.IDispatchEx_iface, dispIdMember, riid, + lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLInputElement_private_put_autofocus(IWineHTMLInputPrivate *iface, VARIANT_BOOL v) +{ + HTMLInputElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%x)\n", This, v); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLInputElement_private_get_autofocus(IWineHTMLInputPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLInputElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLInputElement_private_get_validationMessage(IWineHTMLInputPrivate *iface, BSTR *ret) +{ + HTMLInputElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLInputElement_private_get_validity(IWineHTMLInputPrivate *iface, IDispatch **ret) +{ + HTMLInputElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLInputElement_private_get_willValidate(IWineHTMLInputPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLInputElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLInputElement_private_setCustomValidity(IWineHTMLInputPrivate *iface, VARIANT *message) +{ + HTMLInputElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%s)\n", This, debugstr_variant(message)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLInputElement_private_checkValidity(IWineHTMLInputPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLInputElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static const IWineHTMLInputPrivateVtbl WineHTMLInputPrivateVtbl = { + HTMLInputElement_private_QueryInterface, + HTMLInputElement_private_AddRef, + HTMLInputElement_private_Release, + HTMLInputElement_private_GetTypeInfoCount, + HTMLInputElement_private_GetTypeInfo, + HTMLInputElement_private_GetIDsOfNames, + HTMLInputElement_private_Invoke, + HTMLInputElement_private_put_autofocus, + HTMLInputElement_private_get_autofocus, + HTMLInputElement_private_get_validationMessage, + HTMLInputElement_private_get_validity, + HTMLInputElement_private_get_willValidate, + HTMLInputElement_private_setCustomValidity, + HTMLInputElement_private_checkValidity +}; + +static inline HTMLInputElement *impl_from_IWineHTMLParentFormPrivateVtbl(IWineHTMLParentFormPrivate *iface) +{ + return CONTAINING_RECORD(iface, HTMLInputElement, IWineHTMLParentFormPrivate_iface); +} + +static HRESULT WINAPI HTMLInputElement_form_private_QueryInterface(IWineHTMLParentFormPrivate *iface, + REFIID riid, void **ppv) +{ + HTMLInputElement *This = impl_from_IWineHTMLParentFormPrivateVtbl(iface); + + return IHTMLDOMNode_QueryInterface(&This->element.node.IHTMLDOMNode_iface, riid, ppv); +} + +static ULONG WINAPI HTMLInputElement_form_private_AddRef(IWineHTMLParentFormPrivate *iface) +{ + HTMLInputElement *This = impl_from_IWineHTMLParentFormPrivateVtbl(iface); + + return IHTMLDOMNode_AddRef(&This->element.node.IHTMLDOMNode_iface); +} + +static ULONG WINAPI HTMLInputElement_form_private_Release(IWineHTMLParentFormPrivate *iface) +{ + HTMLInputElement *This = impl_from_IWineHTMLParentFormPrivateVtbl(iface); + + return IHTMLDOMNode_Release(&This->element.node.IHTMLDOMNode_iface); +} + +static HRESULT WINAPI HTMLInputElement_form_private_GetTypeInfoCount(IWineHTMLParentFormPrivate *iface, UINT *pctinfo) +{ + HTMLInputElement *This = impl_from_IWineHTMLParentFormPrivateVtbl(iface); + return IDispatchEx_GetTypeInfoCount(&This->element.node.event_target.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLInputElement_form_private_GetTypeInfo(IWineHTMLParentFormPrivate *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLInputElement *This = impl_from_IWineHTMLParentFormPrivateVtbl(iface); + return IDispatchEx_GetTypeInfo(&This->element.node.event_target.dispex.IDispatchEx_iface, iTInfo, lcid, + ppTInfo); +} + +static HRESULT WINAPI HTMLInputElement_form_private_GetIDsOfNames(IWineHTMLParentFormPrivate *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + HTMLInputElement *This = impl_from_IWineHTMLParentFormPrivateVtbl(iface); + return IDispatchEx_GetIDsOfNames(&This->element.node.event_target.dispex.IDispatchEx_iface, riid, rgszNames, + cNames, lcid, rgDispId); +} + +static HRESULT WINAPI HTMLInputElement_form_private_Invoke(IWineHTMLParentFormPrivate *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLInputElement *This = impl_from_IWineHTMLParentFormPrivateVtbl(iface); + return IDispatchEx_Invoke(&This->element.node.event_target.dispex.IDispatchEx_iface, dispIdMember, riid, + lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLInputElement_form_private_put_formAction(IWineHTMLParentFormPrivate *iface, BSTR v) +{ + HTMLInputElement *This = impl_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLInputElement_form_private_get_formAction(IWineHTMLParentFormPrivate *iface, BSTR *ret) +{ + HTMLInputElement *This = impl_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLInputElement_form_private_put_formEnctype(IWineHTMLParentFormPrivate *iface, BSTR v) +{ + HTMLInputElement *This = impl_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLInputElement_form_private_get_formEnctype(IWineHTMLParentFormPrivate *iface, BSTR *ret) +{ + HTMLInputElement *This = impl_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLInputElement_form_private_put_formMethod(IWineHTMLParentFormPrivate *iface, BSTR v) +{ + HTMLInputElement *This = impl_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLInputElement_form_private_get_formMethod(IWineHTMLParentFormPrivate *iface, BSTR *ret) +{ + HTMLInputElement *This = impl_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLInputElement_form_private_put_formNoValidate(IWineHTMLParentFormPrivate *iface, VARIANT_BOOL v) +{ + HTMLInputElement *This = impl_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%x)\n", This, v); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLInputElement_form_private_get_formNoValidate(IWineHTMLParentFormPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLInputElement *This = impl_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLInputElement_form_private_put_formTarget(IWineHTMLParentFormPrivate *iface, BSTR v) +{ + HTMLInputElement *This = impl_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLInputElement_form_private_get_formTarget(IWineHTMLParentFormPrivate *iface, BSTR *ret) +{ + HTMLInputElement *This = impl_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static const IWineHTMLParentFormPrivateVtbl WineHTMLParentFormPrivateVtbl = { + HTMLInputElement_form_private_QueryInterface, + HTMLInputElement_form_private_AddRef, + HTMLInputElement_form_private_Release, + HTMLInputElement_form_private_GetTypeInfoCount, + HTMLInputElement_form_private_GetTypeInfo, + HTMLInputElement_form_private_GetIDsOfNames, + HTMLInputElement_form_private_Invoke, + HTMLInputElement_form_private_put_formAction, + HTMLInputElement_form_private_get_formAction, + HTMLInputElement_form_private_put_formEnctype, + HTMLInputElement_form_private_get_formEnctype, + HTMLInputElement_form_private_put_formMethod, + HTMLInputElement_form_private_get_formMethod, + HTMLInputElement_form_private_put_formNoValidate, + HTMLInputElement_form_private_get_formNoValidate, + HTMLInputElement_form_private_put_formTarget, + HTMLInputElement_form_private_get_formTarget +}; + static inline HTMLInputElement *impl_from_HTMLDOMNode(HTMLDOMNode *iface) { return CONTAINING_RECORD(iface, HTMLInputElement, element.node); @@ -1356,6 +1629,12 @@ static HRESULT HTMLInputElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv) }else if(IsEqualGUID(&IID_IHTMLInputTextElement2, riid)) { TRACE("(%p)->(IID_IHTMLInputTextElement2 %p)\n", This, ppv); *ppv = &This->IHTMLInputTextElement2_iface; + }else if(IsEqualGUID(&IID_IWineHTMLInputPrivate, riid)) { + TRACE("(%p)->(IID_IWineHTMLInputPrivate %p)\n", This, ppv); + *ppv = &This->IWineHTMLInputPrivate_iface; + }else if(IsEqualGUID(&IID_IWineHTMLParentFormPrivate, riid)) { + TRACE("(%p)->(IID_IWineHTMLParentFormPrivate %p)\n", This, ppv); + *ppv = &This->IWineHTMLParentFormPrivate_iface; } if(*ppv) { @@ -1440,6 +1719,16 @@ static const NodeImplVtbl HTMLInputElementImplVtbl = { HTMLInputElement_is_text_edit }; +static void HTMLInputElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + HTMLElement_init_dispex_info(info, mode); + + if(mode >= COMPAT_MODE_IE10) { + dispex_info_add_interface(info, IWineHTMLInputPrivate_tid, NULL); + dispex_info_add_interface(info, IWineHTMLParentFormPrivate_tid, NULL); + } +} + static const tid_t HTMLInputElement_iface_tids[] = { HTMLELEMENT_TIDS, IHTMLInputElement_tid, @@ -1452,7 +1741,7 @@ dispex_static_data_t HTMLInputElement_dispex = { PROTO_ID_HTMLInputElement, DispHTMLInputElement_tid, HTMLInputElement_iface_tids, - HTMLElement_init_dispex_info + HTMLInputElement_init_dispex_info }; HRESULT HTMLInputElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) @@ -1467,6 +1756,8 @@ HRESULT HTMLInputElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HT ret->IHTMLInputElement_iface.lpVtbl = &HTMLInputElementVtbl; ret->IHTMLInputTextElement_iface.lpVtbl = &HTMLInputTextElementVtbl; ret->IHTMLInputTextElement2_iface.lpVtbl = &HTMLInputTextElement2Vtbl; + ret->IWineHTMLInputPrivate_iface.lpVtbl = &WineHTMLInputPrivateVtbl; + ret->IWineHTMLParentFormPrivate_iface.lpVtbl = &WineHTMLParentFormPrivateVtbl; ret->element.node.vtbl = &HTMLInputElementImplVtbl; HTMLElement_Init(&ret->element, doc, nselem, &HTMLInputElement_dispex); @@ -1674,6 +1965,8 @@ struct HTMLButtonElement { HTMLElement element; IHTMLButtonElement IHTMLButtonElement_iface; + IWineHTMLInputPrivate IWineHTMLInputPrivate_iface; + IWineHTMLParentFormPrivate IWineHTMLParentFormPrivate_iface; nsIDOMHTMLButtonElement *nsbutton; }; @@ -1904,6 +2197,277 @@ static const IHTMLButtonElementVtbl HTMLButtonElementVtbl = { HTMLButtonElement_createTextRange }; +static inline HTMLButtonElement *button_from_IWineHTMLInputPrivateVtbl(IWineHTMLInputPrivate *iface) +{ + return CONTAINING_RECORD(iface, HTMLButtonElement, IWineHTMLInputPrivate_iface); +} + +static HRESULT WINAPI HTMLButtonElement_private_QueryInterface(IWineHTMLInputPrivate *iface, + REFIID riid, void **ppv) +{ + HTMLButtonElement *This = button_from_IWineHTMLInputPrivateVtbl(iface); + return IHTMLDOMNode_QueryInterface(&This->element.node.IHTMLDOMNode_iface, riid, ppv); +} + +static ULONG WINAPI HTMLButtonElement_private_AddRef(IWineHTMLInputPrivate *iface) +{ + HTMLButtonElement *This = button_from_IWineHTMLInputPrivateVtbl(iface); + return IHTMLDOMNode_AddRef(&This->element.node.IHTMLDOMNode_iface); +} + +static ULONG WINAPI HTMLButtonElement_private_Release(IWineHTMLInputPrivate *iface) +{ + HTMLButtonElement *This = button_from_IWineHTMLInputPrivateVtbl(iface); + return IHTMLDOMNode_Release(&This->element.node.IHTMLDOMNode_iface); +} + +static HRESULT WINAPI HTMLButtonElement_private_GetTypeInfoCount(IWineHTMLInputPrivate *iface, UINT *pctinfo) +{ + HTMLButtonElement *This = button_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_GetTypeInfoCount(&This->element.node.event_target.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLButtonElement_private_GetTypeInfo(IWineHTMLInputPrivate *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLButtonElement *This = button_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_GetTypeInfo(&This->element.node.event_target.dispex.IDispatchEx_iface, iTInfo, lcid, + ppTInfo); +} + +static HRESULT WINAPI HTMLButtonElement_private_GetIDsOfNames(IWineHTMLInputPrivate *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + HTMLButtonElement *This = button_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_GetIDsOfNames(&This->element.node.event_target.dispex.IDispatchEx_iface, riid, rgszNames, + cNames, lcid, rgDispId); +} + +static HRESULT WINAPI HTMLButtonElement_private_Invoke(IWineHTMLInputPrivate *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLButtonElement *This = button_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_Invoke(&This->element.node.event_target.dispex.IDispatchEx_iface, dispIdMember, riid, + lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLButtonElement_private_put_autofocus(IWineHTMLInputPrivate *iface, VARIANT_BOOL v) +{ + HTMLButtonElement *This = button_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%x)\n", This, v); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLButtonElement_private_get_autofocus(IWineHTMLInputPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLButtonElement *This = button_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLButtonElement_private_get_validationMessage(IWineHTMLInputPrivate *iface, BSTR *ret) +{ + HTMLButtonElement *This = button_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLButtonElement_private_get_validity(IWineHTMLInputPrivate *iface, IDispatch **ret) +{ + HTMLButtonElement *This = button_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLButtonElement_private_get_willValidate(IWineHTMLInputPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLButtonElement *This = button_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLButtonElement_private_setCustomValidity(IWineHTMLInputPrivate *iface, VARIANT *message) +{ + HTMLButtonElement *This = button_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%s)\n", This, debugstr_variant(message)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLButtonElement_private_checkValidity(IWineHTMLInputPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLButtonElement *This = button_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static const IWineHTMLInputPrivateVtbl WineHTMLButtonInputPrivateVtbl = { + HTMLButtonElement_private_QueryInterface, + HTMLButtonElement_private_AddRef, + HTMLButtonElement_private_Release, + HTMLButtonElement_private_GetTypeInfoCount, + HTMLButtonElement_private_GetTypeInfo, + HTMLButtonElement_private_GetIDsOfNames, + HTMLButtonElement_private_Invoke, + HTMLButtonElement_private_put_autofocus, + HTMLButtonElement_private_get_autofocus, + HTMLButtonElement_private_get_validationMessage, + HTMLButtonElement_private_get_validity, + HTMLButtonElement_private_get_willValidate, + HTMLButtonElement_private_setCustomValidity, + HTMLButtonElement_private_checkValidity +}; + +static inline HTMLButtonElement *button_from_IWineHTMLParentFormPrivateVtbl(IWineHTMLParentFormPrivate *iface) +{ + return CONTAINING_RECORD(iface, HTMLButtonElement, IWineHTMLParentFormPrivate_iface); +} + +static HRESULT WINAPI HTMLButtonElement_form_private_QueryInterface(IWineHTMLParentFormPrivate *iface, + REFIID riid, void **ppv) +{ + HTMLButtonElement *This = button_from_IWineHTMLParentFormPrivateVtbl(iface); + + return IHTMLDOMNode_QueryInterface(&This->element.node.IHTMLDOMNode_iface, riid, ppv); +} + +static ULONG WINAPI HTMLButtonElement_form_private_AddRef(IWineHTMLParentFormPrivate *iface) +{ + HTMLButtonElement *This = button_from_IWineHTMLParentFormPrivateVtbl(iface); + + return IHTMLDOMNode_AddRef(&This->element.node.IHTMLDOMNode_iface); +} + +static ULONG WINAPI HTMLButtonElement_form_private_Release(IWineHTMLParentFormPrivate *iface) +{ + HTMLButtonElement *This = button_from_IWineHTMLParentFormPrivateVtbl(iface); + + return IHTMLDOMNode_Release(&This->element.node.IHTMLDOMNode_iface); +} + +static HRESULT WINAPI HTMLButtonElement_form_private_GetTypeInfoCount(IWineHTMLParentFormPrivate *iface, UINT *pctinfo) +{ + HTMLButtonElement *This = button_from_IWineHTMLParentFormPrivateVtbl(iface); + return IDispatchEx_GetTypeInfoCount(&This->element.node.event_target.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLButtonElement_form_private_GetTypeInfo(IWineHTMLParentFormPrivate *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLButtonElement *This = button_from_IWineHTMLParentFormPrivateVtbl(iface); + return IDispatchEx_GetTypeInfo(&This->element.node.event_target.dispex.IDispatchEx_iface, iTInfo, lcid, + ppTInfo); +} + +static HRESULT WINAPI HTMLButtonElement_form_private_GetIDsOfNames(IWineHTMLParentFormPrivate *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + HTMLButtonElement *This = button_from_IWineHTMLParentFormPrivateVtbl(iface); + return IDispatchEx_GetIDsOfNames(&This->element.node.event_target.dispex.IDispatchEx_iface, riid, rgszNames, + cNames, lcid, rgDispId); +} + +static HRESULT WINAPI HTMLButtonElement_form_private_Invoke(IWineHTMLParentFormPrivate *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLButtonElement *This = button_from_IWineHTMLParentFormPrivateVtbl(iface); + return IDispatchEx_Invoke(&This->element.node.event_target.dispex.IDispatchEx_iface, dispIdMember, riid, + lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLButtonElement_form_private_put_formAction(IWineHTMLParentFormPrivate *iface, BSTR v) +{ + HTMLButtonElement *This = button_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLButtonElement_form_private_get_formAction(IWineHTMLParentFormPrivate *iface, BSTR *ret) +{ + HTMLButtonElement *This = button_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLButtonElement_form_private_put_formEnctype(IWineHTMLParentFormPrivate *iface, BSTR v) +{ + HTMLButtonElement *This = button_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLButtonElement_form_private_get_formEnctype(IWineHTMLParentFormPrivate *iface, BSTR *ret) +{ + HTMLButtonElement *This = button_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLButtonElement_form_private_put_formMethod(IWineHTMLParentFormPrivate *iface, BSTR v) +{ + HTMLButtonElement *This = button_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLButtonElement_form_private_get_formMethod(IWineHTMLParentFormPrivate *iface, BSTR *ret) +{ + HTMLButtonElement *This = button_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLButtonElement_form_private_put_formNoValidate(IWineHTMLParentFormPrivate *iface, VARIANT_BOOL v) +{ + HTMLButtonElement *This = button_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%x)\n", This, v); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLButtonElement_form_private_get_formNoValidate(IWineHTMLParentFormPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLButtonElement *This = button_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLButtonElement_form_private_put_formTarget(IWineHTMLParentFormPrivate *iface, BSTR v) +{ + HTMLButtonElement *This = button_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%s)\n", This, debugstr_w(v)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLButtonElement_form_private_get_formTarget(IWineHTMLParentFormPrivate *iface, BSTR *ret) +{ + HTMLButtonElement *This = button_from_IWineHTMLParentFormPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static const IWineHTMLParentFormPrivateVtbl WineHTMLButtonParentFormPrivateVtbl = { + HTMLButtonElement_form_private_QueryInterface, + HTMLButtonElement_form_private_AddRef, + HTMLButtonElement_form_private_Release, + HTMLButtonElement_form_private_GetTypeInfoCount, + HTMLButtonElement_form_private_GetTypeInfo, + HTMLButtonElement_form_private_GetIDsOfNames, + HTMLButtonElement_form_private_Invoke, + HTMLButtonElement_form_private_put_formAction, + HTMLButtonElement_form_private_get_formAction, + HTMLButtonElement_form_private_put_formEnctype, + HTMLButtonElement_form_private_get_formEnctype, + HTMLButtonElement_form_private_put_formMethod, + HTMLButtonElement_form_private_get_formMethod, + HTMLButtonElement_form_private_put_formNoValidate, + HTMLButtonElement_form_private_get_formNoValidate, + HTMLButtonElement_form_private_put_formTarget, + HTMLButtonElement_form_private_get_formTarget +}; + static inline HTMLButtonElement *button_from_HTMLDOMNode(HTMLDOMNode *iface) { return CONTAINING_RECORD(iface, HTMLButtonElement, element.node); @@ -1921,6 +2485,12 @@ static HRESULT HTMLButtonElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv) }else if(IsEqualGUID(&IID_IHTMLButtonElement, riid)) { TRACE("(%p)->(IID_IHTMLButtonElement %p)\n", This, ppv); *ppv = &This->IHTMLButtonElement_iface; + }else if(IsEqualGUID(&IID_IWineHTMLInputPrivate, riid)) { + TRACE("(%p)->(IID_IWineHTMLInputPrivate %p)\n", This, ppv); + *ppv = &This->IWineHTMLInputPrivate_iface; + }else if(IsEqualGUID(&IID_IWineHTMLParentFormPrivate, riid)) { + TRACE("(%p)->(IID_IWineHTMLParentFormPrivate %p)\n", This, ppv); + *ppv = &This->IWineHTMLParentFormPrivate_iface; }else { return HTMLElement_QI(&This->element.node, riid, ppv); } @@ -1989,6 +2559,16 @@ static const NodeImplVtbl HTMLButtonElementImplVtbl = { HTMLButtonElement_is_text_edit }; +static void HTMLButtonElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + HTMLElement_init_dispex_info(info, mode); + + if(mode >= COMPAT_MODE_IE10) { + dispex_info_add_interface(info, IWineHTMLInputPrivate_tid, NULL); + dispex_info_add_interface(info, IWineHTMLParentFormPrivate_tid, NULL); + } +} + static const tid_t HTMLButtonElement_iface_tids[] = { HTMLELEMENT_TIDS, IHTMLButtonElement_tid, @@ -2001,7 +2581,7 @@ dispex_static_data_t HTMLButtonElement_dispex = { PROTO_ID_HTMLButtonElement, DispHTMLButtonElement_tid, HTMLButtonElement_iface_tids, - HTMLElement_init_dispex_info + HTMLButtonElement_init_dispex_info }; HRESULT HTMLButtonElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) @@ -2014,6 +2594,8 @@ HRESULT HTMLButtonElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, H return E_OUTOFMEMORY; ret->IHTMLButtonElement_iface.lpVtbl = &HTMLButtonElementVtbl; + ret->IWineHTMLInputPrivate_iface.lpVtbl = &WineHTMLButtonInputPrivateVtbl; + ret->IWineHTMLParentFormPrivate_iface.lpVtbl = &WineHTMLButtonParentFormPrivateVtbl; ret->element.node.vtbl = &HTMLButtonElementImplVtbl; HTMLElement_Init(&ret->element, doc, nselem, &HTMLButtonElement_dispex); diff --git a/dlls/mshtml/htmlobject.c b/dlls/mshtml/htmlobject.c index 11379b49abe..c989a54044a 100644 --- a/dlls/mshtml/htmlobject.c +++ b/dlls/mshtml/htmlobject.c @@ -38,6 +38,7 @@ struct HTMLObjectElement { IHTMLObjectElement IHTMLObjectElement_iface; IHTMLObjectElement2 IHTMLObjectElement2_iface; + IWineHTMLInputPrivate IWineHTMLInputPrivate_iface; nsIDOMHTMLObjectElement *nsobject; }; @@ -631,6 +632,128 @@ static const IHTMLObjectElement2Vtbl HTMLObjectElement2Vtbl = { HTMLObjectElement2_get_data }; +static inline HTMLObjectElement *impl_from_IWineHTMLInputPrivateVtbl(IWineHTMLInputPrivate *iface) +{ + return CONTAINING_RECORD(iface, HTMLObjectElement, IWineHTMLInputPrivate_iface); +} + +static HRESULT WINAPI HTMLObjectElement_input_private_QueryInterface(IWineHTMLInputPrivate *iface, + REFIID riid, void **ppv) +{ + HTMLObjectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IHTMLDOMNode_QueryInterface(&This->plugin_container.element.node.IHTMLDOMNode_iface, riid, ppv); +} + +static ULONG WINAPI HTMLObjectElement_input_private_AddRef(IWineHTMLInputPrivate *iface) +{ + HTMLObjectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IHTMLDOMNode_AddRef(&This->plugin_container.element.node.IHTMLDOMNode_iface); +} + +static ULONG WINAPI HTMLObjectElement_input_private_Release(IWineHTMLInputPrivate *iface) +{ + HTMLObjectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IHTMLDOMNode_Release(&This->plugin_container.element.node.IHTMLDOMNode_iface); +} + +static HRESULT WINAPI HTMLObjectElement_input_private_GetTypeInfoCount(IWineHTMLInputPrivate *iface, UINT *pctinfo) +{ + HTMLObjectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_GetTypeInfoCount(&This->plugin_container.element.node.event_target.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLObjectElement_input_private_GetTypeInfo(IWineHTMLInputPrivate *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLObjectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_GetTypeInfo(&This->plugin_container.element.node.event_target.dispex.IDispatchEx_iface, iTInfo, lcid, + ppTInfo); +} + +static HRESULT WINAPI HTMLObjectElement_input_private_GetIDsOfNames(IWineHTMLInputPrivate *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + HTMLObjectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_GetIDsOfNames(&This->plugin_container.element.node.event_target.dispex.IDispatchEx_iface, riid, + rgszNames, cNames, lcid, rgDispId); +} + +static HRESULT WINAPI HTMLObjectElement_input_private_Invoke(IWineHTMLInputPrivate *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLObjectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_Invoke(&This->plugin_container.element.node.event_target.dispex.IDispatchEx_iface, dispIdMember, + riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLObjectElement_input_private_put_autofocus(IWineHTMLInputPrivate *iface, VARIANT_BOOL v) +{ + HTMLObjectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + WARN("(%p)->(%x)\n", This, v); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLObjectElement_input_private_get_autofocus(IWineHTMLInputPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLObjectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + WARN("(%p)->(%p)\n", This, ret); + return E_UNEXPECTED; +} + +static HRESULT WINAPI HTMLObjectElement_input_private_get_validationMessage(IWineHTMLInputPrivate *iface, BSTR *ret) +{ + HTMLObjectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLObjectElement_input_private_get_validity(IWineHTMLInputPrivate *iface, IDispatch **ret) +{ + HTMLObjectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLObjectElement_input_private_get_willValidate(IWineHTMLInputPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLObjectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLObjectElement_input_private_setCustomValidity(IWineHTMLInputPrivate *iface, VARIANT *message) +{ + HTMLObjectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%s)\n", This, debugstr_variant(message)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLObjectElement_input_private_checkValidity(IWineHTMLInputPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLObjectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static const IWineHTMLInputPrivateVtbl WineHTMLInputPrivateVtbl = { + HTMLObjectElement_input_private_QueryInterface, + HTMLObjectElement_input_private_AddRef, + HTMLObjectElement_input_private_Release, + HTMLObjectElement_input_private_GetTypeInfoCount, + HTMLObjectElement_input_private_GetTypeInfo, + HTMLObjectElement_input_private_GetIDsOfNames, + HTMLObjectElement_input_private_Invoke, + HTMLObjectElement_input_private_put_autofocus, + HTMLObjectElement_input_private_get_autofocus, + HTMLObjectElement_input_private_get_validationMessage, + HTMLObjectElement_input_private_get_validity, + HTMLObjectElement_input_private_get_willValidate, + HTMLObjectElement_input_private_setCustomValidity, + HTMLObjectElement_input_private_checkValidity +}; + static inline HTMLObjectElement *impl_from_HTMLDOMNode(HTMLDOMNode *iface) { return CONTAINING_RECORD(iface, HTMLObjectElement, plugin_container.element.node); @@ -650,6 +773,8 @@ static HRESULT HTMLObjectElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv) *ppv = &This->IHTMLObjectElement_iface; }else if(IsEqualGUID(&IID_IHTMLObjectElement2, riid)) { *ppv = &This->IHTMLObjectElement2_iface; + }else if(IsEqualGUID(&IID_IWineHTMLInputPrivate, riid)) { + *ppv = &This->IWineHTMLInputPrivate_iface; }else if(IsEqualGUID(&IID_HTMLPluginContainer, riid)) { /* Special pseudo-interface returning HTMLPluginContainse struct. */ *ppv = &This->plugin_container; @@ -770,6 +895,18 @@ static const NodeImplVtbl HTMLObjectElementImplVtbl = { HTMLObjectElement_unlink }; +static void HTMLObjectElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t input_private_hooks[] = { + {DISPID_IWINEHTMLINPUTPRIVATE_AUTOFOCUS}, + {DISPID_UNKNOWN} + }; + HTMLElement_init_dispex_info(info, mode); + + if(mode >= COMPAT_MODE_IE10) + dispex_info_add_interface(info, IWineHTMLInputPrivate_tid, input_private_hooks); +} + static const tid_t HTMLObjectElement_iface_tids[] = { IHTMLObjectElement2_tid, IHTMLObjectElement_tid, @@ -782,7 +919,7 @@ dispex_static_data_t HTMLObjectElement_dispex = { PROTO_ID_HTMLObjectElement, DispHTMLObjectElement_tid, HTMLObjectElement_iface_tids, - HTMLElement_init_dispex_info + HTMLObjectElement_init_dispex_info }; HRESULT HTMLObjectElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) @@ -796,6 +933,7 @@ HRESULT HTMLObjectElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, H ret->IHTMLObjectElement_iface.lpVtbl = &HTMLObjectElementVtbl; ret->IHTMLObjectElement2_iface.lpVtbl = &HTMLObjectElement2Vtbl; + ret->IWineHTMLInputPrivate_iface.lpVtbl = &WineHTMLInputPrivateVtbl; ret->plugin_container.element.node.vtbl = &HTMLObjectElementImplVtbl; HTMLElement_Init(&ret->plugin_container.element, doc, nselem, &HTMLObjectElement_dispex); diff --git a/dlls/mshtml/htmlselect.c b/dlls/mshtml/htmlselect.c index c617b1fc605..9776f4b7f9d 100644 --- a/dlls/mshtml/htmlselect.c +++ b/dlls/mshtml/htmlselect.c @@ -688,6 +688,7 @@ struct HTMLSelectElement { HTMLElement element; IHTMLSelectElement IHTMLSelectElement_iface; + IWineHTMLInputPrivate IWineHTMLInputPrivate_iface; nsIDOMHTMLSelectElement *nsselect; }; @@ -1355,6 +1356,128 @@ static const IHTMLSelectElementVtbl HTMLSelectElementVtbl = { HTMLSelectElement_tags }; +static inline HTMLSelectElement *impl_from_IWineHTMLInputPrivateVtbl(IWineHTMLInputPrivate *iface) +{ + return CONTAINING_RECORD(iface, HTMLSelectElement, IWineHTMLInputPrivate_iface); +} + +static HRESULT WINAPI HTMLSelectElement_input_private_QueryInterface(IWineHTMLInputPrivate *iface, + REFIID riid, void **ppv) +{ + HTMLSelectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IHTMLDOMNode_QueryInterface(&This->element.node.IHTMLDOMNode_iface, riid, ppv); +} + +static ULONG WINAPI HTMLSelectElement_input_private_AddRef(IWineHTMLInputPrivate *iface) +{ + HTMLSelectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IHTMLDOMNode_AddRef(&This->element.node.IHTMLDOMNode_iface); +} + +static ULONG WINAPI HTMLSelectElement_input_private_Release(IWineHTMLInputPrivate *iface) +{ + HTMLSelectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IHTMLDOMNode_Release(&This->element.node.IHTMLDOMNode_iface); +} + +static HRESULT WINAPI HTMLSelectElement_input_private_GetTypeInfoCount(IWineHTMLInputPrivate *iface, UINT *pctinfo) +{ + HTMLSelectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_GetTypeInfoCount(&This->element.node.event_target.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLSelectElement_input_private_GetTypeInfo(IWineHTMLInputPrivate *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLSelectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_GetTypeInfo(&This->element.node.event_target.dispex.IDispatchEx_iface, iTInfo, lcid, + ppTInfo); +} + +static HRESULT WINAPI HTMLSelectElement_input_private_GetIDsOfNames(IWineHTMLInputPrivate *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + HTMLSelectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_GetIDsOfNames(&This->element.node.event_target.dispex.IDispatchEx_iface, riid, rgszNames, + cNames, lcid, rgDispId); +} + +static HRESULT WINAPI HTMLSelectElement_input_private_Invoke(IWineHTMLInputPrivate *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLSelectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_Invoke(&This->element.node.event_target.dispex.IDispatchEx_iface, dispIdMember, riid, + lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLSelectElement_input_private_put_autofocus(IWineHTMLInputPrivate *iface, VARIANT_BOOL v) +{ + HTMLSelectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%x)\n", This, v); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLSelectElement_input_private_get_autofocus(IWineHTMLInputPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLSelectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLSelectElement_input_private_get_validationMessage(IWineHTMLInputPrivate *iface, BSTR *ret) +{ + HTMLSelectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLSelectElement_input_private_get_validity(IWineHTMLInputPrivate *iface, IDispatch **ret) +{ + HTMLSelectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLSelectElement_input_private_get_willValidate(IWineHTMLInputPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLSelectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLSelectElement_input_private_setCustomValidity(IWineHTMLInputPrivate *iface, VARIANT *message) +{ + HTMLSelectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%s)\n", This, debugstr_variant(message)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLSelectElement_input_private_checkValidity(IWineHTMLInputPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLSelectElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static const IWineHTMLInputPrivateVtbl WineHTMLInputPrivateVtbl = { + HTMLSelectElement_input_private_QueryInterface, + HTMLSelectElement_input_private_AddRef, + HTMLSelectElement_input_private_Release, + HTMLSelectElement_input_private_GetTypeInfoCount, + HTMLSelectElement_input_private_GetTypeInfo, + HTMLSelectElement_input_private_GetIDsOfNames, + HTMLSelectElement_input_private_Invoke, + HTMLSelectElement_input_private_put_autofocus, + HTMLSelectElement_input_private_get_autofocus, + HTMLSelectElement_input_private_get_validationMessage, + HTMLSelectElement_input_private_get_validity, + HTMLSelectElement_input_private_get_willValidate, + HTMLSelectElement_input_private_setCustomValidity, + HTMLSelectElement_input_private_checkValidity +}; + static inline HTMLSelectElement *impl_from_HTMLDOMNode(HTMLDOMNode *iface) { return CONTAINING_RECORD(iface, HTMLSelectElement, element.node); @@ -1375,6 +1498,9 @@ static HRESULT HTMLSelectElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv) }else if(IsEqualGUID(&IID_IHTMLSelectElement, riid)) { TRACE("(%p)->(IID_IHTMLSelectElement %p)\n", This, ppv); *ppv = &This->IHTMLSelectElement_iface; + }else if(IsEqualGUID(&IID_IWineHTMLInputPrivate, riid)) { + TRACE("(%p)->(IID_IWineHTMLInputPrivate_iface %p)\n", This, ppv); + *ppv = &This->IWineHTMLInputPrivate_iface; } if(*ppv) { @@ -1506,6 +1632,14 @@ static const NodeImplVtbl HTMLSelectElementImplVtbl = { HTMLSelectElement_unlink }; +static void HTMLSelectElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + HTMLElement_init_dispex_info(info, mode); + + if(mode >= COMPAT_MODE_IE10) + dispex_info_add_interface(info, IWineHTMLInputPrivate_tid, NULL); +} + static const tid_t HTMLSelectElement_tids[] = { HTMLELEMENT_TIDS, IHTMLSelectElement_tid, @@ -1518,7 +1652,7 @@ dispex_static_data_t HTMLSelectElement_dispex = { PROTO_ID_HTMLSelectElement, DispHTMLSelectElement_tid, HTMLSelectElement_tids, - HTMLElement_init_dispex_info + HTMLSelectElement_init_dispex_info }; HRESULT HTMLSelectElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) @@ -1531,6 +1665,7 @@ HRESULT HTMLSelectElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, H return E_OUTOFMEMORY; ret->IHTMLSelectElement_iface.lpVtbl = &HTMLSelectElementVtbl; + ret->IWineHTMLInputPrivate_iface.lpVtbl = &WineHTMLInputPrivateVtbl; ret->element.node.vtbl = &HTMLSelectElementImplVtbl; HTMLElement_Init(&ret->element, doc, nselem, &HTMLSelectElement_dispex); diff --git a/dlls/mshtml/htmltextarea.c b/dlls/mshtml/htmltextarea.c index 2fd11c343e0..1ef8daeae5a 100644 --- a/dlls/mshtml/htmltextarea.c +++ b/dlls/mshtml/htmltextarea.c @@ -35,6 +35,7 @@ struct HTMLTextAreaElement { HTMLElement element; IHTMLTextAreaElement IHTMLTextAreaElement_iface; + IWineHTMLInputPrivate IWineHTMLInputPrivate_iface; nsIDOMHTMLTextAreaElement *nstextarea; }; @@ -384,6 +385,128 @@ static const IHTMLTextAreaElementVtbl HTMLTextAreaElementVtbl = { HTMLTextAreaElement_createTextRange }; +static inline HTMLTextAreaElement *impl_from_IWineHTMLInputPrivateVtbl(IWineHTMLInputPrivate *iface) +{ + return CONTAINING_RECORD(iface, HTMLTextAreaElement, IWineHTMLInputPrivate_iface); +} + +static HRESULT WINAPI HTMLTextAreaElement_input_private_QueryInterface(IWineHTMLInputPrivate *iface, + REFIID riid, void **ppv) +{ + HTMLTextAreaElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IHTMLDOMNode_QueryInterface(&This->element.node.IHTMLDOMNode_iface, riid, ppv); +} + +static ULONG WINAPI HTMLTextAreaElement_input_private_AddRef(IWineHTMLInputPrivate *iface) +{ + HTMLTextAreaElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IHTMLDOMNode_AddRef(&This->element.node.IHTMLDOMNode_iface); +} + +static ULONG WINAPI HTMLTextAreaElement_input_private_Release(IWineHTMLInputPrivate *iface) +{ + HTMLTextAreaElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IHTMLDOMNode_Release(&This->element.node.IHTMLDOMNode_iface); +} + +static HRESULT WINAPI HTMLTextAreaElement_input_private_GetTypeInfoCount(IWineHTMLInputPrivate *iface, UINT *pctinfo) +{ + HTMLTextAreaElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_GetTypeInfoCount(&This->element.node.event_target.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLTextAreaElement_input_private_GetTypeInfo(IWineHTMLInputPrivate *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLTextAreaElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_GetTypeInfo(&This->element.node.event_target.dispex.IDispatchEx_iface, iTInfo, lcid, + ppTInfo); +} + +static HRESULT WINAPI HTMLTextAreaElement_input_private_GetIDsOfNames(IWineHTMLInputPrivate *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + HTMLTextAreaElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_GetIDsOfNames(&This->element.node.event_target.dispex.IDispatchEx_iface, riid, rgszNames, + cNames, lcid, rgDispId); +} + +static HRESULT WINAPI HTMLTextAreaElement_input_private_Invoke(IWineHTMLInputPrivate *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLTextAreaElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + return IDispatchEx_Invoke(&This->element.node.event_target.dispex.IDispatchEx_iface, dispIdMember, riid, + lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLTextAreaElement_input_private_put_autofocus(IWineHTMLInputPrivate *iface, VARIANT_BOOL v) +{ + HTMLTextAreaElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%x)\n", This, v); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLTextAreaElement_input_private_get_autofocus(IWineHTMLInputPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLTextAreaElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLTextAreaElement_input_private_get_validationMessage(IWineHTMLInputPrivate *iface, BSTR *ret) +{ + HTMLTextAreaElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLTextAreaElement_input_private_get_validity(IWineHTMLInputPrivate *iface, IDispatch **ret) +{ + HTMLTextAreaElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLTextAreaElement_input_private_get_willValidate(IWineHTMLInputPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLTextAreaElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLTextAreaElement_input_private_setCustomValidity(IWineHTMLInputPrivate *iface, VARIANT *message) +{ + HTMLTextAreaElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%s)\n", This, debugstr_variant(message)); + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLTextAreaElement_input_private_checkValidity(IWineHTMLInputPrivate *iface, VARIANT_BOOL *ret) +{ + HTMLTextAreaElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); + FIXME("(%p)->(%p)\n", This, ret); + return E_NOTIMPL; +} + +static const IWineHTMLInputPrivateVtbl WineHTMLInputPrivateVtbl = { + HTMLTextAreaElement_input_private_QueryInterface, + HTMLTextAreaElement_input_private_AddRef, + HTMLTextAreaElement_input_private_Release, + HTMLTextAreaElement_input_private_GetTypeInfoCount, + HTMLTextAreaElement_input_private_GetTypeInfo, + HTMLTextAreaElement_input_private_GetIDsOfNames, + HTMLTextAreaElement_input_private_Invoke, + HTMLTextAreaElement_input_private_put_autofocus, + HTMLTextAreaElement_input_private_get_autofocus, + HTMLTextAreaElement_input_private_get_validationMessage, + HTMLTextAreaElement_input_private_get_validity, + HTMLTextAreaElement_input_private_get_willValidate, + HTMLTextAreaElement_input_private_setCustomValidity, + HTMLTextAreaElement_input_private_checkValidity +}; + static inline HTMLTextAreaElement *impl_from_HTMLDOMNode(HTMLDOMNode *iface) { return CONTAINING_RECORD(iface, HTMLTextAreaElement, element.node); @@ -404,6 +527,9 @@ static HRESULT HTMLTextAreaElement_QI(HTMLDOMNode *iface, REFIID riid, void **pp }else if(IsEqualGUID(&IID_IHTMLTextAreaElement, riid)) { TRACE("(%p)->(IID_IHTMLTextAreaElement %p)\n", This, ppv); *ppv = &This->IHTMLTextAreaElement_iface; + }else if(IsEqualGUID(&IID_IWineHTMLInputPrivate, riid)) { + TRACE("(%p)->(IID_IWineHTMLInputPrivate_iface %p)\n", This, ppv); + *ppv = &This->IWineHTMLInputPrivate_iface; } if(*ppv) { @@ -474,6 +600,14 @@ static const NodeImplVtbl HTMLTextAreaElementImplVtbl = { HTMLTextAreaElement_is_text_edit }; +static void HTMLTextAreaElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + HTMLElement_init_dispex_info(info, mode); + + if(mode >= COMPAT_MODE_IE10) + dispex_info_add_interface(info, IWineHTMLInputPrivate_tid, NULL); +} + static const tid_t HTMLTextAreaElement_iface_tids[] = { HTMLELEMENT_TIDS, IHTMLTextAreaElement_tid, @@ -486,7 +620,7 @@ dispex_static_data_t HTMLTextAreaElement_dispex = { PROTO_ID_HTMLTextAreaElement, DispHTMLTextAreaElement_tid, HTMLTextAreaElement_iface_tids, - HTMLElement_init_dispex_info + HTMLTextAreaElement_init_dispex_info }; HRESULT HTMLTextAreaElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, HTMLElement **elem) @@ -499,6 +633,7 @@ HRESULT HTMLTextAreaElement_Create(HTMLDocumentNode *doc, nsIDOMElement *nselem, return E_OUTOFMEMORY; ret->IHTMLTextAreaElement_iface.lpVtbl = &HTMLTextAreaElementVtbl; + ret->IWineHTMLInputPrivate_iface.lpVtbl = &WineHTMLInputPrivateVtbl; ret->element.node.vtbl = &HTMLTextAreaElementImplVtbl; HTMLElement_Init(&ret->element, doc, nselem, &HTMLTextAreaElement_dispex); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 72fb575a17c..9f7e68b8696 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -384,6 +384,9 @@ typedef struct ScriptHost ScriptHost; #define PRIVATE_TID_LIST \ XIID(IWineDOMTokenList) \ XIID(IWineHTMLElementPrivate) \ + XIID(IWineHTMLInputPrivate) \ + XIID(IWineHTMLFormPrivate) \ + XIID(IWineHTMLParentFormPrivate) \ XIID(IWineHTMLWindowPrivate) \ XIID(IWineHTMLWindowCompatPrivate) \ XIID(IWinePageTransitionEvent) \ diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl index d53feeaf71c..48c391e5f07 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -201,6 +201,86 @@ interface IWineHTMLElementPrivate : IDispatch HRESULT classList([retval, out] IDispatch **class_list); } +const long DISPID_IWINEHTMLFORMPRIVATE_NOVALIDATE = 51; +const long DISPID_IWINEHTMLFORMPRIVATE_CHECKVALIDITY = 52; +[ + odl, + oleautomation, + dual, + hidden, + uuid(465908fd-f394-489f-b7a3-4c00fbbe9eed) +] +interface IWineHTMLFormPrivate : IDispatch +{ + [propput, id(50)] + HRESULT enctype([in] BSTR v); + [propget, id(50)] + HRESULT enctype([retval, out] BSTR *ret); + [propput, id(DISPID_IWINEHTMLFORMPRIVATE_NOVALIDATE)] + HRESULT noValidate([in] VARIANT_BOOL v); + [propget, id(DISPID_IWINEHTMLFORMPRIVATE_NOVALIDATE)] + HRESULT noValidate([retval, out] VARIANT_BOOL *ret); + [id(DISPID_IWINEHTMLFORMPRIVATE_CHECKVALIDITY)] + HRESULT checkValidity([retval, out] VARIANT_BOOL *ret); +} + +[ + odl, + oleautomation, + dual, + hidden, + uuid(465908fd-f394-489f-b7a3-4c00fbbe9eee) +] +interface IWineHTMLParentFormPrivate : IDispatch +{ + [propput, id(60)] + HRESULT formAction([in] BSTR v); + [propget, id(60)] + HRESULT formAction([retval, out] BSTR *ret); + [propput, id(61)] + HRESULT formEnctype([in] BSTR v); + [propget, id(61)] + HRESULT formEnctype([retval, out] BSTR *ret); + [propput, id(62)] + HRESULT formMethod([in] BSTR v); + [propget, id(62)] + HRESULT formMethod([retval, out] BSTR *ret); + [propput, id(63)] + HRESULT formNoValidate([in] VARIANT_BOOL v); + [propget, id(63)] + HRESULT formNoValidate([retval, out] VARIANT_BOOL *ret); + [propput, id(64)] + HRESULT formTarget([in] BSTR v); + [propget, id(64)] + HRESULT formTarget([retval, out] BSTR *ret); +} + +const long DISPID_IWINEHTMLINPUTPRIVATE_AUTOFOCUS = 50; +[ + odl, + oleautomation, + dual, + hidden, + uuid(465908fd-f394-489f-b7a3-4c00fbbe9eef) +] +interface IWineHTMLInputPrivate : IDispatch +{ + [propput, id(DISPID_IWINEHTMLINPUTPRIVATE_AUTOFOCUS)] + HRESULT autofocus([in] VARIANT_BOOL v); + [propget, id(DISPID_IWINEHTMLINPUTPRIVATE_AUTOFOCUS)] + HRESULT autofocus([retval, out] VARIANT_BOOL *ret); + [propget, id(51)] + HRESULT validationMessage([retval, out] BSTR *ret); + [propget, id(52)] + HRESULT validity([retval, out] IDispatch **ret); + [propget, id(53)] + HRESULT willValidate([retval, out] VARIANT_BOOL *ret); + [id(54)] + HRESULT setCustomValidity([in] VARIANT *message); + [id(55)] + HRESULT checkValidity([retval, out] VARIANT_BOOL *ret); +} + [ odl, oleautomation, diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 0e7751f204d..fd48adcdc8f 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1816,6 +1816,86 @@ sync_test("style_props", function() { } }); +sync_test("input_validation_props", function() { + var obj, v = document.documentMode; + if(v < 9) return; + + function test_exposed(prop, expect) { + if(expect) + ok(Object.prototype.hasOwnProperty.call(obj, prop), prop + " not a property of " + obj); + else + ok(!Object.prototype.hasOwnProperty.call(obj, prop), prop + " is a property of " + obj); + } + + obj = window.HTMLFormElement.prototype; + test_exposed("action", true); + test_exposed("autofocus", false); + test_exposed("checkValidity", v >= 10); + test_exposed("enctype", true); + test_exposed("formAction", false); + test_exposed("formEnctype", false); + test_exposed("formMethod", false); + test_exposed("formNoValidate", false); + test_exposed("formTarget", false); + test_exposed("method", true); + test_exposed("noValidate", v >= 10); + test_exposed("setCustomValidity", false); + test_exposed("target", true); + test_exposed("validationMessage", false); + test_exposed("validity", false); + test_exposed("willValidate", false); + + obj = window.HTMLInputElement.prototype; + test_exposed("autofocus", v >= 10); + test_exposed("checkValidity", v >= 10); + test_exposed("formAction", v >= 10); + test_exposed("formEnctype", v >= 10); + test_exposed("formMethod", v >= 10); + test_exposed("formNoValidate", v >= 10); + test_exposed("formTarget", v >= 10); + test_exposed("setCustomValidity", v >= 10); + test_exposed("validationMessage", v >= 10); + test_exposed("validity", v >= 10); + test_exposed("willValidate", v >= 10); + + obj = window.HTMLButtonElement.prototype; + test_exposed("autofocus", v >= 10); + test_exposed("checkValidity", v >= 10); + test_exposed("formAction", v >= 10); + test_exposed("formEnctype", v >= 10); + test_exposed("formMethod", v >= 10); + test_exposed("formNoValidate", v >= 10); + test_exposed("formTarget", v >= 10); + test_exposed("setCustomValidity", v >= 10); + test_exposed("validationMessage", v >= 10); + test_exposed("validity", v >= 10); + test_exposed("willValidate", v >= 10); + + obj = window.HTMLObjectElement.prototype; + test_exposed("autofocus", false); + test_exposed("checkValidity", v >= 10); + test_exposed("setCustomValidity", v >= 10); + test_exposed("validationMessage", v >= 10); + test_exposed("validity", v >= 10); + test_exposed("willValidate", v >= 10); + + obj = window.HTMLSelectElement.prototype; + test_exposed("autofocus", v >= 10); + test_exposed("checkValidity", v >= 10); + test_exposed("setCustomValidity", v >= 10); + test_exposed("validationMessage", v >= 10); + test_exposed("validity", v >= 10); + test_exposed("willValidate", v >= 10); + + obj = window.HTMLTextAreaElement.prototype; + test_exposed("autofocus", v >= 10); + test_exposed("checkValidity", v >= 10); + test_exposed("setCustomValidity", v >= 10); + test_exposed("validationMessage", v >= 10); + test_exposed("validity", v >= 10); + test_exposed("willValidate", v >= 10); +}); + sync_test("createElement_inline_attr", function() { var v = document.documentMode, e, s; From 1848749942cf9abfdf431b634fad973263a5469f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:09 +0200 Subject: [PATCH 0938/2777] mshtml: Implement checkValidity for HTMLInputElement. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlevent.c | 2 ++ dlls/mshtml/htmlevent.h | 1 + dlls/mshtml/htmlinput.c | 24 ++++++++++++++++++++++-- dlls/mshtml/nsiface.idl | 20 +++++++++++++++++++- dlls/mshtml/tests/es5.js | 23 +++++++++++++++++++++++ 5 files changed, 67 insertions(+), 3 deletions(-) diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index c5990a2918a..7f66ef9c452 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -160,6 +160,8 @@ static const event_info_t event_info[] = { EVENT_BUBBLES | EVENT_CANCELABLE}, {L"input", EVENT_TYPE_EVENT, DISPID_UNKNOWN, EVENT_DEFAULTLISTENER | EVENT_BUBBLES}, + {L"invalid", EVENT_TYPE_EVENT, DISPID_EVPROP_INVALID, + EVENT_BIND_TO_TARGET | EVENT_CANCELABLE}, {L"keydown", EVENT_TYPE_KEYBOARD, DISPID_EVMETH_ONKEYDOWN, EVENT_DEFAULTLISTENER | EVENT_HASDEFAULTHANDLERS | EVENT_BUBBLES | EVENT_CANCELABLE }, {L"keypress", EVENT_TYPE_KEYBOARD, DISPID_EVMETH_ONKEYPRESS, diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index d6bf65edc38..eaf1607b7de 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -40,6 +40,7 @@ typedef enum { EVENTID_FOCUSOUT, EVENTID_HELP, EVENTID_INPUT, + EVENTID_INVALID, EVENTID_KEYDOWN, EVENTID_KEYPRESS, EVENTID_KEYUP, diff --git a/dlls/mshtml/htmlinput.c b/dlls/mshtml/htmlinput.c index b4c097ca87c..e6cb61eece6 100644 --- a/dlls/mshtml/htmlinput.c +++ b/dlls/mshtml/htmlinput.c @@ -1433,8 +1433,28 @@ static HRESULT WINAPI HTMLInputElement_private_setCustomValidity(IWineHTMLInputP static HRESULT WINAPI HTMLInputElement_private_checkValidity(IWineHTMLInputPrivate *iface, VARIANT_BOOL *ret) { HTMLInputElement *This = impl_from_IWineHTMLInputPrivateVtbl(iface); - FIXME("(%p)->(%p)\n", This, ret); - return E_NOTIMPL; + nsIDOMValidityState *nsvalidity; + DOMEvent *event; + nsresult nsres; + HRESULT hres; + cpp_bool b; + + TRACE("(%p)->(%p)\n", This, ret); + + nsres = nsIDOMHTMLInputElement_GetValidity(This->nsinput, &nsvalidity); + if(NS_FAILED(nsres)) + return map_nsresult(nsres); + nsres = nsIDOMValidityState_GetValid(nsvalidity, &b); + nsIDOMValidityState_Release(nsvalidity); + + if(!(*ret = variant_bool(NS_SUCCEEDED(nsres) && b))) { + hres = create_document_event(This->element.node.doc, EVENTID_INVALID, &event); + if(FAILED(hres)) + return hres; + dispatch_event(&This->element.node.event_target, event); + IDOMEvent_Release(&event->IDOMEvent_iface); + } + return S_OK; } static const IWineHTMLInputPrivateVtbl WineHTMLInputPrivateVtbl = { diff --git a/dlls/mshtml/nsiface.idl b/dlls/mshtml/nsiface.idl index 9c50b3a7599..0073c192990 100644 --- a/dlls/mshtml/nsiface.idl +++ b/dlls/mshtml/nsiface.idl @@ -160,7 +160,6 @@ typedef nsISupports nsITransferable; typedef nsISupports nsIDOMFileList; typedef nsISupports nsIDOMFile; typedef nsISupports nsIControllers; -typedef nsISupports nsIDOMValidityState; typedef nsISupports nsIPluginInstanceOwner; typedef nsISupports nsIPluginStreamListener; typedef nsISupports nsIContentSink; @@ -961,6 +960,25 @@ interface nsIDOMMozNamedAttrMap : nsISupports nsresult RemoveNamedItemNS(const nsAString *namespaceURI, const nsAString *localName, nsIDOMAttr **_retval); } +[ + object, + uuid(00bed276-f1f7-492f-a039-dbd9b9efc10b), + local +] +interface nsIDOMValidityState : nsISupports +{ + nsresult GetValueMissing(bool *_retval); + nsresult GetTypeMismatch(bool *_retval); + nsresult GetPatternMismatch(bool *_retval); + nsresult GetTooLong(bool *_retval); + nsresult GetRangeUnderflow(bool *_retval); + nsresult GetRangeOverflow(bool *_retval); + nsresult GetStepMismatch(bool *_retval); + nsresult GetBadInput(bool *_retval); + nsresult GetCustomError(bool *_retval); + nsresult GetValid(bool *_retval); +} + [ object, uuid(cc35b412-009b-46a3-9be0-76448f12548d), diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index e14e948e710..8eb75c693a2 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2942,6 +2942,29 @@ sync_test("functions scope", function() { })(); }); +sync_test("input validation", function() { + var fired, elem = document.createElement("input"); + elem.type = "number"; + elem.setAttribute("min", "1"); + elem.setAttribute("max", "4"); + elem.addEventListener("invalid", function(e) { + ok(e.target === elem, "unexpected target " + e.target); + fired = true; + }); + fired = false; + elem.value = 1; + ok(elem.checkValidity() === true, "input number (1-4) with value 1: invalid"); + ok(fired === false, "input number (1-4) with value 1 fired invalid event"); + fired = false; + elem.value = 0; + ok(elem.checkValidity() === false, "input number (1-4) with value 0: valid"); + ok(fired === true, "input number (1-4) with value 0 did not fire invalid event"); + fired = false; + elem.value = 5; + ok(elem.checkValidity() === false, "input number (1-4) with value 5: valid"); + ok(fired === true, "input number (1-4) with value 5 did not fire invalid event"); +}); + sync_test("instanceof", function() { var r; From b1b61300831c9cde761ffeb89c1230462807af8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:09 +0200 Subject: [PATCH 0939/2777] mshtml: Implement enctype for HTMLFormElement. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's an alternative name for `encoding`. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/htmlform.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/dlls/mshtml/htmlform.c b/dlls/mshtml/htmlform.c index 403c288d009..14fabdb7ee5 100644 --- a/dlls/mshtml/htmlform.c +++ b/dlls/mshtml/htmlform.c @@ -832,15 +832,19 @@ static HRESULT WINAPI HTMLFormElement_private_Invoke(IWineHTMLFormPrivate *iface static HRESULT WINAPI HTMLFormElement_private_put_enctype(IWineHTMLFormPrivate *iface, BSTR v) { HTMLFormElement *This = impl_from_IWineHTMLFormPrivateVtbl(iface); - FIXME("(%p)->(%s)\n", This, debugstr_w(v)); - return E_NOTIMPL; + + TRACE("(%p)->(%s)\n", This, debugstr_w(v)); + + return IHTMLFormElement_put_encoding(&This->IHTMLFormElement_iface, v); } static HRESULT WINAPI HTMLFormElement_private_get_enctype(IWineHTMLFormPrivate *iface, BSTR *ret) { HTMLFormElement *This = impl_from_IWineHTMLFormPrivateVtbl(iface); - FIXME("(%p)->(%p)\n", This, ret); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, ret); + + return IHTMLFormElement_get_encoding(&This->IHTMLFormElement_iface, ret); } static HRESULT WINAPI HTMLFormElement_private_put_noValidate(IWineHTMLFormPrivate *iface, VARIANT_BOOL v) From 09b45e3d41f0b05a2de8e7a3d06a4e2aac2c1445 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:09 +0200 Subject: [PATCH 0940/2777] mshtml: Expose toJSON only in IE9+ modes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/omnavigator.c | 49 ++++++++++++++++++++---------- dlls/mshtml/tests/documentmode.js | 50 +++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 15 deletions(-) diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 888cdaec248..1d2c30eb2e0 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -24,6 +24,7 @@ #include "winbase.h" #include "winuser.h" #include "ole2.h" +#include "mshtmdid.h" #include "wine/debug.h" @@ -2167,16 +2168,22 @@ static const IHTMLPerformanceTimingVtbl HTMLPerformanceTimingVtbl = { HTMLPerformanceTiming_toJSON }; -static const tid_t HTMLPerformanceTiming_iface_tids[] = { - IHTMLPerformanceTiming_tid, - 0 -}; +static void HTMLPerformanceTiming_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLPERFORMANCETIMING_TOJSON}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLPerformanceTiming_tid, mode < COMPAT_MODE_IE9 ? hooks : NULL); +} + dispex_static_data_t HTMLPerformanceTiming_dispex = { L"PerformanceTiming", NULL, PROTO_ID_HTMLPerformanceTiming, IHTMLPerformanceTiming_tid, - HTMLPerformanceTiming_iface_tids + no_iface_tids, + HTMLPerformanceTiming_init_dispex_info }; HRESULT create_performance_timing(HTMLPerformanceTiming **ret) @@ -2341,16 +2348,22 @@ static const IHTMLPerformanceNavigationVtbl HTMLPerformanceNavigationVtbl = { HTMLPerformanceNavigation_toJSON }; -static const tid_t HTMLPerformanceNavigation_iface_tids[] = { - IHTMLPerformanceNavigation_tid, - 0 -}; +static void HTMLPerformanceNavigation_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLPERFORMANCENAVIGATION_TOJSON}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLPerformanceNavigation_tid, mode < COMPAT_MODE_IE9 ? hooks : NULL); +} + dispex_static_data_t HTMLPerformanceNavigation_dispex = { L"PerformanceNavigation", NULL, PROTO_ID_HTMLPerformanceNavigation, IHTMLPerformanceNavigation_tid, - HTMLPerformanceNavigation_iface_tids + no_iface_tids, + HTMLPerformanceNavigation_init_dispex_info }; typedef struct { @@ -2503,16 +2516,22 @@ static const IHTMLPerformanceVtbl HTMLPerformanceVtbl = { HTMLPerformance_toJSON }; -static const tid_t HTMLPerformance_iface_tids[] = { - IHTMLPerformance_tid, - 0 -}; +static void HTMLPerformance_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + static const dispex_hook_t hooks[] = { + {DISPID_IHTMLPERFORMANCE_TOJSON}, + {DISPID_UNKNOWN} + }; + dispex_info_add_interface(info, IHTMLPerformance_tid, mode < COMPAT_MODE_IE9 ? hooks : NULL); +} + dispex_static_data_t HTMLPerformance_dispex = { L"Performance", NULL, PROTO_ID_HTMLPerformance, IHTMLPerformance_tid, - HTMLPerformance_iface_tids + no_iface_tids, + HTMLPerformance_init_dispex_info }; HRESULT create_performance(HTMLInnerWindow *window, IHTMLPerformance **ret) diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index fd48adcdc8f..ef26149d5c0 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1669,6 +1669,56 @@ sync_test("domimpl_props", function() { test_exposed("createHTMLDocument", v >= 9); }); +sync_test("perf_props", function() { + var obj = window.performance, name = "Performance"; + var v = document.documentMode; + + function test_exposed(prop, expect) { + if(expect) + ok(prop in obj, prop + " not found in " + name + "."); + else + ok(!(prop in obj), prop + " found in " + name + "."); + } + + test_exposed("navigation", true); + test_exposed("timing", true); + test_exposed("toJSON", v >= 9); + test_exposed("toString", true); + + obj = window.performance.navigation, name = "PerformanceNavigation"; + + test_exposed("redirectCount", true); + test_exposed("type", true); + test_exposed("toJSON", v >= 9); + test_exposed("toString", true); + + obj = window.performance.timing, name = "PerformanceTiming"; + + test_exposed("connectEnd", true); + test_exposed("connectStart", true); + test_exposed("domComplete", true); + test_exposed("domContentLoadedEventEnd", true); + test_exposed("domContentLoadedEventStart", true); + test_exposed("domInteractive", true); + test_exposed("domLoading", true); + test_exposed("domainLookupEnd", true); + test_exposed("domainLookupStart", true); + test_exposed("fetchStart", true); + test_exposed("loadEventEnd", true); + test_exposed("loadEventStart", true); + test_exposed("msFirstPaint", true); + test_exposed("navigationStart", true); + test_exposed("redirectEnd", true); + test_exposed("redirectStart", true); + test_exposed("requestStart", true); + test_exposed("responseEnd", true); + test_exposed("responseStart", true); + test_exposed("unloadEventEnd", true); + test_exposed("unloadEventStart", true); + test_exposed("toJSON", v >= 9); + test_exposed("toString", true); +}); + sync_test("xhr_props", function() { var xhr = new XMLHttpRequest(); From bc516791dcaf2b26017162ff4f5943c9caa73fc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:09 +0200 Subject: [PATCH 0941/2777] mshtml: Implement toJSON() for PerformanceTiming. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/dispex.c | 13 ++++++++ dlls/jscript/jscript.h | 1 + dlls/mshtml/dispex.c | 45 +++++++++++++++++++++++++++ dlls/mshtml/mshtml_private.h | 2 ++ dlls/mshtml/omnavigator.c | 6 ++-- dlls/mshtml/tests/dom.c | 60 ++++++++++++++++++++++++++++++++++++ dlls/mshtml/tests/es5.js | 39 +++++++++++++++++++++++ 7 files changed, 164 insertions(+), 2 deletions(-) diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index b87a68cfc1e..04b8ae36d2f 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2713,6 +2713,18 @@ static HRESULT WINAPI WineDispatchProxyCbPrivate_DefineConstructor(IWineDispatch return hres; } +static HRESULT WINAPI WineDispatchProxyCbPrivate_CreateObject(IWineDispatchProxyCbPrivate *iface, IDispatchEx **obj) +{ + jsdisp_t *This = impl_from_IWineDispatchProxyCbPrivate(iface); + jsdisp_t *jsdisp; + HRESULT hres; + + hres = create_object(This->ctx, NULL, &jsdisp); + if(SUCCEEDED(hres)) + *obj = &jsdisp->IDispatchEx_iface; + return hres; +} + static HRESULT WINAPI WineDispatchProxyCbPrivate_PropEnum(IWineDispatchProxyCbPrivate *iface, const WCHAR *name) { jsdisp_t *This = impl_from_IWineDispatchProxyCbPrivate(iface); @@ -2746,6 +2758,7 @@ static IWineDispatchProxyCbPrivateVtbl WineDispatchProxyCbPrivateVtbl = { WineDispatchProxyCbPrivate_HostUpdated, WineDispatchProxyCbPrivate_CreateConstructor, WineDispatchProxyCbPrivate_DefineConstructor, + WineDispatchProxyCbPrivate_CreateObject, WineDispatchProxyCbPrivate_GetRandomValues, WineDispatchProxyCbPrivate_PropEnum }; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index a08b1509e11..7da6ba8eeb7 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -106,6 +106,7 @@ typedef struct { HRESULT (STDMETHODCALLTYPE *HostUpdated)(IWineDispatchProxyCbPrivate *This, IActiveScript *script); IDispatch* (STDMETHODCALLTYPE *CreateConstructor)(IWineDispatchProxyCbPrivate *This, IDispatch *disp, const WCHAR *name); HRESULT (STDMETHODCALLTYPE *DefineConstructor)(IWineDispatchProxyCbPrivate *This, const WCHAR *name, IDispatch *prot, IDispatch *ctor); + HRESULT (STDMETHODCALLTYPE *CreateObject)(IWineDispatchProxyCbPrivate *This, IDispatchEx **obj); HRESULT (STDMETHODCALLTYPE *GetRandomValues)(IDispatch *typedarr); HRESULT (STDMETHODCALLTYPE *PropEnum)(IWineDispatchProxyCbPrivate *This, const WCHAR *name); } IWineDispatchProxyCbPrivateVtbl; diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 5567f13bc01..da0572e844e 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -3677,6 +3677,51 @@ HRESULT dispex_delete_prop(DispatchEx *dispex, DISPID id) return S_OK; } +HRESULT dispex_builtin_props_to_json(DispatchEx *dispex, VARIANT *ret) +{ + static DISPID propput_dispid = DISPID_PROPERTYPUT; + IWineDispatchProxyCbPrivate *proxy; + func_info_t *func, *end; + IDispatchEx *json; + HRESULT hres; + VARIANT var; + DISPID id; + DISPPARAMS dp = { 0 }, put_dp = { &var, &propput_dispid, 1, 1 }; + + if(!(proxy = dispex->proxy)) + return E_UNEXPECTED; + + if(!ensure_real_info(dispex)) + return E_OUTOFMEMORY; + + hres = proxy->lpVtbl->CreateObject(proxy, &json); + if(FAILED(hres)) + return hres; + + for(func = dispex->info->funcs, end = func + dispex->info->func_cnt; func < end; func++) { + if(func->func_disp_idx != -1) + continue; + hres = proxy_getter_invoke((IDispatch*)&dispex->IDispatchEx_iface, func, &dp, &var, NULL, NULL); + if(SUCCEEDED(hres)) { + hres = IDispatchEx_GetDispID(json, func->name, fdexNameEnsure | fdexNameCaseSensitive, &id); + if(SUCCEEDED(hres)) { + hres = IDispatchEx_InvokeEx(json, id, 0, DISPATCH_PROPERTYPUT, &put_dp, NULL, NULL, NULL); + } + VariantClear(&var); + } + if(FAILED(hres)) { + IDispatchEx_Release(json); + return hres; + } + } + + if(ret) { + V_VT(ret) = VT_DISPATCH; + V_DISPATCH(ret) = (IDispatch*)json; + } + return hres; +} + void dispex_traverse(DispatchEx *This, nsCycleCollectionTraversalCallback *cb) { dynamic_prop_t *prop; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 9f7e68b8696..d9b22859c7e 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -99,6 +99,7 @@ typedef struct { HRESULT (STDMETHODCALLTYPE *HostUpdated)(IWineDispatchProxyCbPrivate *This, IActiveScript *script); IDispatch* (STDMETHODCALLTYPE *CreateConstructor)(IWineDispatchProxyCbPrivate *This, IDispatch *disp, const WCHAR *name); HRESULT (STDMETHODCALLTYPE *DefineConstructor)(IWineDispatchProxyCbPrivate *This, const WCHAR *name, IDispatch *prot, IDispatch *ctor); + HRESULT (STDMETHODCALLTYPE *CreateObject)(IWineDispatchProxyCbPrivate *This, IDispatchEx **obj); HRESULT (STDMETHODCALLTYPE *GetRandomValues)(IDispatch *typedarr); HRESULT (STDMETHODCALLTYPE *PropEnum)(IWineDispatchProxyCbPrivate *This, const WCHAR *name); } IWineDispatchProxyCbPrivateVtbl; @@ -649,6 +650,7 @@ HRESULT remove_attribute(DispatchEx*,DISPID,VARIANT_BOOL*) DECLSPEC_HIDDEN; HRESULT dispex_get_dynid(DispatchEx*,const WCHAR*,BOOL,DISPID*) DECLSPEC_HIDDEN; HRESULT dispex_invoke(DispatchEx*,IDispatch*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,IServiceProvider*) DECLSPEC_HIDDEN; HRESULT dispex_delete_prop(DispatchEx*,DISPID) DECLSPEC_HIDDEN; +HRESULT dispex_builtin_props_to_json(DispatchEx*,VARIANT*) DECLSPEC_HIDDEN; void dispex_traverse(DispatchEx*,nsCycleCollectionTraversalCallback*) DECLSPEC_HIDDEN; void dispex_unlink(DispatchEx*) DECLSPEC_HIDDEN; void release_typelib(void) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 1d2c30eb2e0..8515438944e 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -2131,8 +2131,10 @@ static HRESULT WINAPI HTMLPerformanceTiming_toString(IHTMLPerformanceTiming *ifa static HRESULT WINAPI HTMLPerformanceTiming_toJSON(IHTMLPerformanceTiming *iface, VARIANT *p) { HTMLPerformanceTiming *This = impl_from_IHTMLPerformanceTiming(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + return dispex_builtin_props_to_json(&This->dispex, p); } static const IHTMLPerformanceTimingVtbl HTMLPerformanceTimingVtbl = { diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 5e5cff26db9..775ae4303bf 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -52,6 +52,16 @@ static enum { static const char doc_blank[] = ""; +static const char doc_blank_ie8[] = + "\n" + "" + " " + " " + " " + " " + " " + ""; + static const char doc_blank_ie9[] = "\n" "" @@ -11170,6 +11180,54 @@ static void test_quirks_mode_offsetHeight(IHTMLDocument2 *doc) IHTMLElement_Release(elem); } +static void test_quirks_mode_perf_toJSON(IHTMLDocument2 *doc) +{ + IHTMLPerformanceTiming *timing; + IHTMLPerformance *perf; + DISPPARAMS dp = { 0 }; + IHTMLWindow2 *window; + IDispatchEx *dispex; + DISPID dispid; + HRESULT hres; + VARIANT var; + BSTR bstr; + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "QueryInterface(IID_IDispatchEx) failed: %08lx\n", hres); + IHTMLWindow2_Release(window); + + bstr = SysAllocString(L"performance"); + hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &dispid); + ok(hres == S_OK, "GetDispID(performance) failed: %08lx\n", hres); + SysFreeString(bstr); + + V_VT(&var) = VT_EMPTY; + hres = IDispatchEx_InvokeEx(dispex, dispid, 0, DISPATCH_PROPERTYGET, &dp, &var, NULL, NULL); + ok(hres == S_OK, "InvokeEx(performance) failed: %08lx\n", hres); + ok(V_VT(&var) == VT_DISPATCH, "V_VT(performance) = %d\n", V_VT(&var)); + ok(V_DISPATCH(&var) != NULL, "V_DISPATCH(performance) = NULL\n"); + IDispatchEx_Release(dispex); + + hres = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IHTMLPerformance, (void**)&perf); + ok(hres == S_OK, "QueryInterface(IID_IHTMLPerformance) failed: %08lx\n", hres); + ok(perf != NULL, "performance is NULL\n"); + VariantClear(&var); + + hres = IHTMLPerformance_get_timing(perf, &timing); + ok(hres == S_OK, "get_timing failed: %08lx\n", hres); + ok(timing != NULL, "performance.timing is NULL\n"); + + hres = IHTMLPerformanceTiming_toJSON(timing, &var); + ok(hres == E_UNEXPECTED, "timing.toJSON() failed: %08lx\n", hres); + ok(V_VT(&var) == VT_EMPTY, "V_VT(timing.toJSON()) = %d\n", V_VT(&var)); + IHTMLPerformanceTiming_Release(timing); + + IHTMLPerformance_Release(perf); +} + static IHTMLDocument2 *notif_doc; static BOOL doc_complete; @@ -12061,6 +12119,8 @@ START_TEST(dom) run_domtest(emptydiv_str, test_docfrag); run_domtest(doc_blank, test_replacechild_elems); run_domtest(doctype_str, test_doctype); + run_domtest(doc_blank, test_quirks_mode_perf_toJSON); + run_domtest(doc_blank_ie8, test_quirks_mode_perf_toJSON); test_quirks_mode(); test_document_mode_lock(); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 8eb75c693a2..fd5b5475d22 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2983,6 +2983,45 @@ sync_test("instanceof", function() { ok(r === true, "document not instance of Node"); }); +sync_test("perf toJSON", function() { + var tests = [ + [ "performance.timing", "connectEnd", "connectStart", "domComplete", "domContentLoadedEventEnd", + "domContentLoadedEventStart", "domInteractive", "domLoading", "domainLookupEnd", "domainLookupStart", + "fetchStart", "loadEventEnd", "loadEventStart", "msFirstPaint", "navigationStart", "redirectEnd", + "redirectStart", "requestStart", "responseEnd", "responseStart", "unloadEventEnd", "unloadEventStart" ] + ]; + + for(var i = 0; i < tests.length; i++) { + var desc, name = tests[i][0], obj = eval("window." + name), json; + + Object.defineProperty(obj, "foobar", {writable: true, enumerable: true, configurable: true, value: 1}); + Object.defineProperty(Object.getPrototypeOf(obj), "barfoo", {writable: true, enumerable: true, configurable: true, value: 3}); + json = obj.toJSON(); + + ok(Object.getPrototypeOf(json) === Object.prototype, "prototype of " + name + ".toJSON() != Object.prototype"); + ok(typeof json === "object", "typeof " + name + ".toJSON() != object"); + for(var j = 1; j < tests[i].length; j++) { + desc = Object.getOwnPropertyDescriptor(json, tests[i][j]); + ok(json.hasOwnProperty(tests[i][j]), name + ".toJSON() does not have " + tests[i][j]); + ok(desc.writable === true, name + ".toJSON()." + tests[i][j] + " not writable"); + ok(desc.enumerable === true, name + ".toJSON()." + tests[i][j] + " not enumerable"); + ok(desc.configurable === true, name + ".toJSON()." + tests[i][j] + " not configurable"); + } + ok(!("foobar" in json), "foobar in " + name + ".toJSON()"); + ok(!("barfoo" in json), "barfoo in " + name + ".toJSON()"); + + delete obj.foobar; + delete Object.getPrototypeOf(obj).barfoo; + + desc = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(obj), tests[i][1]); + delete Object.getPrototypeOf(obj)[tests[i][1]]; + ok(!(tests[i][1] in obj), tests[i][1] + " in " + name + " after delete"); + json = obj.toJSON(); + ok(json.hasOwnProperty(tests[i][1]), name + ".toJSON() does not have " + tests[i][1] + " after delete"); + Object.defineProperty(Object.getPrototypeOf(obj), tests[i][1], desc); + } +}); + sync_test("console", function() { var except From d1c41ab0c7ced3661130749f1aa1b76d531d5739 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:09 +0200 Subject: [PATCH 0942/2777] mshtml: Implement toJSON() for PerformanceNavigation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/omnavigator.c | 6 ++++-- dlls/mshtml/tests/dom.c | 10 ++++++++++ dlls/mshtml/tests/es5.js | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 8515438944e..66f42d8e115 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -2332,8 +2332,10 @@ static HRESULT WINAPI HTMLPerformanceNavigation_toString(IHTMLPerformanceNavigat static HRESULT WINAPI HTMLPerformanceNavigation_toJSON(IHTMLPerformanceNavigation *iface, VARIANT *p) { HTMLPerformanceNavigation *This = impl_from_IHTMLPerformanceNavigation(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + return dispex_builtin_props_to_json(&This->dispex, p); } static const IHTMLPerformanceNavigationVtbl HTMLPerformanceNavigationVtbl = { diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 775ae4303bf..86539c35597 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -11182,6 +11182,7 @@ static void test_quirks_mode_offsetHeight(IHTMLDocument2 *doc) static void test_quirks_mode_perf_toJSON(IHTMLDocument2 *doc) { + IHTMLPerformanceNavigation *nav; IHTMLPerformanceTiming *timing; IHTMLPerformance *perf; DISPPARAMS dp = { 0 }; @@ -11216,6 +11217,15 @@ static void test_quirks_mode_perf_toJSON(IHTMLDocument2 *doc) ok(perf != NULL, "performance is NULL\n"); VariantClear(&var); + hres = IHTMLPerformance_get_navigation(perf, &nav); + ok(hres == S_OK, "get_navigation failed: %08lx\n", hres); + ok(nav != NULL, "performance.navigation is NULL\n"); + + hres = IHTMLPerformanceNavigation_toJSON(nav, &var); + ok(hres == E_UNEXPECTED, "navigation.toJSON() failed: %08lx\n", hres); + ok(V_VT(&var) == VT_EMPTY, "V_VT(navigation.toJSON()) = %d\n", V_VT(&var)); + IHTMLPerformanceNavigation_Release(nav); + hres = IHTMLPerformance_get_timing(perf, &timing); ok(hres == S_OK, "get_timing failed: %08lx\n", hres); ok(timing != NULL, "performance.timing is NULL\n"); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index fd5b5475d22..09d27adc2d7 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2985,6 +2985,7 @@ sync_test("instanceof", function() { sync_test("perf toJSON", function() { var tests = [ + [ "performance.navigation", "redirectCount", "type" ], [ "performance.timing", "connectEnd", "connectStart", "domComplete", "domContentLoadedEventEnd", "domContentLoadedEventStart", "domInteractive", "domLoading", "domainLookupEnd", "domainLookupStart", "fetchStart", "loadEventEnd", "loadEventStart", "msFirstPaint", "navigationStart", "redirectEnd", From 6857c4e5b8d16c588ed732c206ed5e708e00c63b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:09 +0200 Subject: [PATCH 0943/2777] mshtml: Implement toJSON() for Performance. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/dispex.c | 15 ++++++++++++--- dlls/mshtml/omnavigator.c | 6 ++++-- dlls/mshtml/tests/dom.c | 4 ++++ dlls/mshtml/tests/es5.js | 1 + 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index da0572e844e..1d49c8c5a56 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -3680,12 +3680,14 @@ HRESULT dispex_delete_prop(DispatchEx *dispex, DISPID id) HRESULT dispex_builtin_props_to_json(DispatchEx *dispex, VARIANT *ret) { static DISPID propput_dispid = DISPID_PROPERTYPUT; + static WCHAR toJSONW[] = L"toJSON"; IWineDispatchProxyCbPrivate *proxy; func_info_t *func, *end; + DispatchEx *subdispex; + DISPID id, to_json; IDispatchEx *json; HRESULT hres; VARIANT var; - DISPID id; DISPPARAMS dp = { 0 }, put_dp = { &var, &propput_dispid, 1, 1 }; if(!(proxy = dispex->proxy)) @@ -3704,9 +3706,16 @@ HRESULT dispex_builtin_props_to_json(DispatchEx *dispex, VARIANT *ret) hres = proxy_getter_invoke((IDispatch*)&dispex->IDispatchEx_iface, func, &dp, &var, NULL, NULL); if(SUCCEEDED(hres)) { hres = IDispatchEx_GetDispID(json, func->name, fdexNameEnsure | fdexNameCaseSensitive, &id); - if(SUCCEEDED(hres)) { - hres = IDispatchEx_InvokeEx(json, id, 0, DISPATCH_PROPERTYPUT, &put_dp, NULL, NULL, NULL); + + if(SUCCEEDED(hres) && V_VT(&var) == VT_DISPATCH && (subdispex = get_dispex_for_hook((IUnknown*)V_DISPATCH(&var)))) { + if(SUCCEEDED(dispex_get_builtin_id(subdispex, toJSONW, fdexNameCaseSensitive, &to_json))) { + VariantClear(&var); + hres = dispex_call_builtin(subdispex, to_json, &dp, &var, NULL, NULL); + } + IDispatchEx_Release(&subdispex->IDispatchEx_iface); } + if(SUCCEEDED(hres)) + hres = IDispatchEx_InvokeEx(json, id, 0, DISPATCH_PROPERTYPUT, &put_dp, NULL, NULL, NULL); VariantClear(&var); } if(FAILED(hres)) { diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 66f42d8e115..0be8542763b 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -2502,8 +2502,10 @@ static HRESULT WINAPI HTMLPerformance_toString(IHTMLPerformance *iface, BSTR *st static HRESULT WINAPI HTMLPerformance_toJSON(IHTMLPerformance *iface, VARIANT *var) { HTMLPerformance *This = impl_from_IHTMLPerformance(iface); - FIXME("(%p)->(%p)\n", This, var); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, var); + + return dispex_builtin_props_to_json(&This->dispex, var); } static const IHTMLPerformanceVtbl HTMLPerformanceVtbl = { diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 86539c35597..8623cec6a77 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -11217,6 +11217,10 @@ static void test_quirks_mode_perf_toJSON(IHTMLDocument2 *doc) ok(perf != NULL, "performance is NULL\n"); VariantClear(&var); + hres = IHTMLPerformance_toJSON(perf, &var); + ok(hres == E_UNEXPECTED, "toJSON() returned: %08lx\n", hres); + ok(V_VT(&var) == VT_EMPTY, "V_VT(toJSON()) = %d\n", V_VT(&var)); + hres = IHTMLPerformance_get_navigation(perf, &nav); ok(hres == S_OK, "get_navigation failed: %08lx\n", hres); ok(nav != NULL, "performance.navigation is NULL\n"); diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 09d27adc2d7..cdd5f35b901 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -2985,6 +2985,7 @@ sync_test("instanceof", function() { sync_test("perf toJSON", function() { var tests = [ + [ "performance", "navigation", "timing" ], [ "performance.navigation", "redirectCount", "type" ], [ "performance.timing", "connectEnd", "connectStart", "domComplete", "domContentLoadedEventEnd", "domContentLoadedEventStart", "domInteractive", "domLoading", "domainLookupEnd", "domainLookupStart", From 3a4d51f45fc38cd20164a6203c87ecf9543f863f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:10 +0200 Subject: [PATCH 0944/2777] mshtml: Add XDomainRequest factory implementation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/dispex.c | 10 +- dlls/mshtml/htmlwindow.c | 28 +- dlls/mshtml/mshtml_private.h | 9 + dlls/mshtml/tests/documentmode.js | 31 +- dlls/mshtml/tests/dom.c | 77 +++++ dlls/mshtml/tests/events.c | 19 ++ dlls/mshtml/xmlhttprequest.c | 493 ++++++++++++++++++++++++++++++ 7 files changed, 656 insertions(+), 11 deletions(-) diff --git a/dlls/mshtml/dispex.c b/dlls/mshtml/dispex.c index 1d49c8c5a56..4a62a4b9995 100644 --- a/dlls/mshtml/dispex.c +++ b/dlls/mshtml/dispex.c @@ -2293,6 +2293,7 @@ static void legacy_prototype_init_dispex_info(dispex_data_t *info, compat_mode_t DISPID_IHTMLWINDOW2_IMAGE, DISPID_IHTMLWINDOW2_OPTION, DISPID_IHTMLWINDOW5_XMLHTTPREQUEST, + DISPID_IHTMLWINDOW6_XDOMAINREQUEST, DISPID_UNKNOWN }; prototype_id_t prot_id = info->desc - legacy_prototype_dispex; @@ -2606,7 +2607,8 @@ static IDispatch *get_proxy_constructor_disp(HTMLInnerWindow *window, prototype_ { PROTO_ID_DOMParser, &DOMParserCtor_dispex, &legacy_ctor_vtbl }, { PROTO_ID_HTMLImgElement, &HTMLImageCtor_dispex, &HTMLImageElementFactoryVtbl }, { PROTO_ID_HTMLOptionElement, &HTMLOptionCtor_dispex, &HTMLOptionElementFactoryVtbl }, - { PROTO_ID_HTMLXMLHttpRequest, &HTMLXMLHttpRequestFactory_dispex, &HTMLXMLHttpRequestFactoryVtbl } + { PROTO_ID_HTMLXMLHttpRequest, &HTMLXMLHttpRequestFactory_dispex, &HTMLXMLHttpRequestFactoryVtbl }, + { PROTO_ID_HTMLXDomainRequest, &HTMLXDomainRequestFactory_dispex, &HTMLXDomainRequestFactoryVtbl } }; struct legacy_ctor *ctor; unsigned i; @@ -3148,7 +3150,8 @@ static IDispatch* WINAPI WineDispatchProxyPrivate_GetDefaultConstructor(IWineDis { static const prototype_id_t special_ctors[] = { PROTO_ID_DOMParser, - PROTO_ID_HTMLXMLHttpRequest + PROTO_ID_HTMLXMLHttpRequest, + PROTO_ID_HTMLXDomainRequest }; DispatchEx *This = impl_from_IWineDispatchProxyPrivate(iface); struct proxy_prototype *prot = proxy_prototype_from_IUnknown(This->outer); @@ -3217,6 +3220,9 @@ static HRESULT WINAPI WineDispatchProxyPrivate_DefineConstructors(IWineDispatchP compat_mode = dispex_compat_mode(This); for(i = 0; i < ARRAY_SIZE(proxy_ctor_dispex); i++) { + if(PROTO_ID_HTMLXDomainRequest == i + LEGACY_PROTOTYPE_COUNT && compat_mode >= COMPAT_MODE_IE11) + continue; + if(!(prot = get_default_prototype(i + LEGACY_PROTOTYPE_COUNT, compat_mode, prots_ref))) return E_OUTOFMEMORY; diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 996f80f4e74..67a3359185a 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -255,7 +255,7 @@ static const struct { } special_ctor_static_data[] = { { L"Image", PROTO_ID_HTMLImgElement, LEGACY_CTOR_ID_Image, &HTMLImageCtor_dispex, &HTMLImageElementFactoryVtbl }, { L"Option", PROTO_ID_HTMLOptionElement, LEGACY_CTOR_ID_Option, &HTMLOptionCtor_dispex, &HTMLOptionElementFactoryVtbl }, - /* { L"XDomainRequest", PROTO_ID_?, LEGACY_CTOR_ID_?, ?, ? } */ + { L"XDomainRequest", PROTO_ID_HTMLXDomainRequest, LEGACY_CTOR_ID_HTMLXDomainRequest, &HTMLXDomainRequestCtor_dispex, &HTMLXDomainRequestFactoryVtbl }, { L"XMLHttpRequest", PROTO_ID_HTMLXMLHttpRequest, LEGACY_CTOR_ID_HTMLXMLHttpRequest, &HTMLXMLHttpRequestCtor_dispex, &HTMLXMLHttpRequestFactoryVtbl } }; @@ -2384,8 +2384,24 @@ static HRESULT WINAPI HTMLWindow6_put_XDomainRequest(IHTMLWindow6 *iface, VARIAN static HRESULT WINAPI HTMLWindow6_get_XDomainRequest(IHTMLWindow6 *iface, VARIANT *p) { HTMLWindow *This = impl_from_IHTMLWindow6(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + HTMLInnerWindow *window = This->inner_window; + IDispatch *disp; + HRESULT hres; + + TRACE("(%p)->(%p)\n", This, p); + + if(This->outer_window->readystate == READYSTATE_UNINITIALIZED) { + V_VT(p) = VT_EMPTY; + return S_OK; + } + + hres = get_legacy_ctor(window, LEGACY_CTOR_ID_HTMLXDomainRequest_builtin, PROTO_ID_HTMLXDomainRequest, + &HTMLXDomainRequestFactory_dispex, &HTMLXDomainRequestFactoryVtbl, &disp); + if(SUCCEEDED(hres)) { + V_VT(p) = VT_DISPATCH; + V_DISPATCH(p) = (IDispatch*)&legacy_ctor_from_IDispatch(disp)->IHTMLXDomainRequestFactory_iface; + } + return hres; } static HRESULT WINAPI HTMLWindow6_get_sessionStorage(IHTMLWindow6 *iface, IHTMLStorage **p) @@ -4836,10 +4852,12 @@ static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compa {DISPID_IHTMLWINDOW4_CREATEPOPUP, NULL}, {DISPID_UNKNOWN} }; - static const dispex_hook_t window6_hooks[] = { + static const dispex_hook_t window6_ie11_hooks[] = { + {DISPID_IHTMLWINDOW6_XDOMAINREQUEST}, /* IE11 only */ {DISPID_IHTMLWINDOW6_POSTMESSAGE, IHTMLWindow6_postMessage_hook}, {DISPID_UNKNOWN} }; + const dispex_hook_t *const window6_hooks = window6_ie11_hooks + 1; static const dispex_hook_t private_ie10_hooks[] = { {DISPID_IWINEHTMLWINDOWPRIVATE_MSCRYPTO}, {DISPID_UNKNOWN} @@ -4852,7 +4870,7 @@ static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compa if(compat_mode >= COMPAT_MODE_IE10) dispex_info_add_interface(info, IWineHTMLWindowPrivate_tid, compat_mode <= COMPAT_MODE_IE10 ? private_ie10_hooks : NULL); - dispex_info_add_interface(info, IHTMLWindow6_tid, window6_hooks); + dispex_info_add_interface(info, IHTMLWindow6_tid, compat_mode >= COMPAT_MODE_IE11 ? window6_ie11_hooks : window6_hooks); dispex_info_add_interface(info, IHTMLWindow5_tid, NULL); dispex_info_add_interface(info, IHTMLWindow4_tid, compat_mode >= COMPAT_MODE_IE11 ? window4_ie11_hooks : NULL); dispex_info_add_interface(info, IHTMLWindow3_tid, compat_mode >= COMPAT_MODE_IE11 ? window3_ie11_hooks : window3_hooks); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index d9b22859c7e..62f3d52532c 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -236,6 +236,7 @@ typedef struct ScriptHost ScriptHost; XDIID(DispHTMLW3CComputedStyle) \ XDIID(DispHTMLWindow2) \ XDIID(DispHTMLXMLHttpRequest) \ + XDIID(DispXDomainRequest) \ XDIID(DispSVGCircleElement) \ XDIID(DispSVGSVGElement) \ XDIID(DispSVGTSpanElement) \ @@ -374,6 +375,8 @@ typedef struct ScriptHost ScriptHost; XIID(IHTMLXMLHttpRequest) \ XIID(IHTMLXMLHttpRequest2) \ XIID(IHTMLXMLHttpRequestFactory) \ + XIID(IHTMLXDomainRequest) \ + XIID(IHTMLXDomainRequestFactory) \ XIID(IOmHistory) \ XIID(IOmNavigator) \ XIID(ISVGCircleElement) \ @@ -435,6 +438,7 @@ PRIVATE_TID_LIST X(HTMLStorage, "Storage", HTMLStorage_dispex, Object) \ X(HTMLTextRange, "TextRange", HTMLTxtRange_dispex, Object) \ X(HTMLXMLHttpRequest, "XMLHttpRequest", HTMLXMLHttpRequest_dispex, Object) \ + X(HTMLXDomainRequest, "XDomainRequest", HTMLXDomainRequest_dispex, Object) \ X(HTMLCurrentStyle, "MSCurrentStyleCSSProperties", HTMLCurrentStyle_dispex, HTMLCSSProperties) \ X(HTMLW3CComputedStyle, "CSSStyleDeclaration", HTMLW3CComputedStyle_dispex, Object) \ X(HTMLStyleSheet, "CSSStyleSheet", HTMLStyleSheet_dispex, StyleSheet) \ @@ -527,6 +531,7 @@ COMMON_PROTOTYPE_LIST LEGACY_CTOR_ID_Image_builtin, LEGACY_CTOR_ID_Option_builtin, LEGACY_CTOR_ID_HTMLXMLHttpRequest_builtin, + LEGACY_CTOR_ID_HTMLXDomainRequest_builtin, LEGACY_CTOR_COUNT } legacy_ctor_id_t; @@ -680,6 +685,7 @@ struct legacy_ctor { IHTMLOptionElementFactory IHTMLOptionElementFactory_iface; IHTMLImageElementFactory IHTMLImageElementFactory_iface; IHTMLXMLHttpRequestFactory IHTMLXMLHttpRequestFactory_iface; + IHTMLXDomainRequestFactory IHTMLXDomainRequestFactory_iface; }; LONG ref; @@ -1718,12 +1724,15 @@ extern const IUnknownVtbl legacy_ctor_vtbl DECLSPEC_HIDDEN; extern const IHTMLImageElementFactoryVtbl HTMLImageElementFactoryVtbl DECLSPEC_HIDDEN; extern const IHTMLOptionElementFactoryVtbl HTMLOptionElementFactoryVtbl DECLSPEC_HIDDEN; extern const IHTMLXMLHttpRequestFactoryVtbl HTMLXMLHttpRequestFactoryVtbl DECLSPEC_HIDDEN; +extern const IHTMLXDomainRequestFactoryVtbl HTMLXDomainRequestFactoryVtbl DECLSPEC_HIDDEN; extern dispex_static_data_t HTMLImageElementFactory_dispex DECLSPEC_HIDDEN; extern dispex_static_data_t HTMLOptionElementFactory_dispex DECLSPEC_HIDDEN; extern dispex_static_data_t HTMLXMLHttpRequestFactory_dispex DECLSPEC_HIDDEN; +extern dispex_static_data_t HTMLXDomainRequestFactory_dispex DECLSPEC_HIDDEN; extern dispex_static_data_t HTMLImageCtor_dispex DECLSPEC_HIDDEN; extern dispex_static_data_t HTMLOptionCtor_dispex DECLSPEC_HIDDEN; extern dispex_static_data_t HTMLXMLHttpRequestCtor_dispex DECLSPEC_HIDDEN; +extern dispex_static_data_t HTMLXDomainRequestCtor_dispex DECLSPEC_HIDDEN; extern dispex_static_data_t DOMParserCtor_dispex DECLSPEC_HIDDEN; #define X(id, name, dispex, proto_id) extern dispex_static_data_t dispex DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index ef26149d5c0..51149b63213 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -351,6 +351,7 @@ sync_test("builtin_toString", function() { if(v < 11) { test("eventObject", document.createEventObject(), "MSEventObj"); test("selection", document.selection, "MSSelection"); + test("XDomainRequest", new XDomainRequest(), "XDomainRequest", null, "Function"); } if(v >= 9) { var xml = new DOMParser().parseFromString("foobar", "text/xml"); @@ -648,10 +649,12 @@ sync_test("builtin_prototypes", function() { [ "DOMParser", [ "prototype", "arguments" ], [ "create", "length" ], 9 ], [ "Image", [ "prototype", "arguments" ], [ "create", "length" ] ], [ "Option", [ "prototype", "arguments" ], [ "create", "length" ] ], + [ "XDomainRequest", [ "prototype", "arguments", "create" ], [ "length" ], 0, 10 ], [ "XMLHttpRequest", [ "prototype", "arguments", "create" ], [ "length" ] ] ]; for(var i = 0; i < special_ctors.length; i++) { - if(special_ctors[i].length > 3 && v < special_ctors[i][3]) + if((special_ctors[i].length > 3 && v < special_ctors[i][3]) || + (special_ctors[i].length > 4 && v > special_ctors[i][4])) continue; name = special_ctors[i][0]; ok(Object.prototype.hasOwnProperty.call(window, name), name + " not a property of window."); @@ -813,6 +816,26 @@ sync_test("builtin_prototypes", function() { }else ok(proto.constructor === window.XMLHttpRequest, "XMLHttpRequest.prototype.constructor = " + proto.constructor); + if(v < 11) { + set_obj("XDomainRequest", true); + test_prop("open"); + test_prop("send"); + test_prop("timeout"); + test_legacy_ctor(["abort"], ["contentType", "responseText"], ["status", "onreadystatechange"], "onerror", function(){}); + if(v < 9) { + r = obj.abort(); + ok(r === "foobar", "(new XDomainRequest).abort() returned " + r); + r = obj.winetestprop; + ok(r === "test", "(new XDomainRequest).winetestprop = " + r); + obj.winetestprop = "prop"; + r = obj.winetestprop; + ok(r === "prop", "(new XDomainRequest).winetestprop after set = " + r); + r = XDomainRequest.prototype.winetestprop; + ok(r === "test", "XDomainRequest.prototype.winetestprop after obj = " + r); + }else + ok(proto.constructor === window.XDomainRequest, "XDomainRequest.prototype.constructor = " + proto.constructor); + } + set_obj("Image", true); test_prop("src"); test_prop("border"); @@ -1223,7 +1246,7 @@ sync_test("builtin_prototypes", function() { [ "XMLHttpRequest", 0 ] ]; for(var i = 0; i < ctors.length; i++) { - if(!(ctors[i][0] in window) && (v >= 8 || ctors[i][0] === "XDomainRequest")) { + if(!(ctors[i][0] in window) && v >= 8) { todo_wine.ok(false, ctors[i][0] + " not implemented"); continue; } @@ -1234,8 +1257,6 @@ sync_test("builtin_prototypes", function() { }catch(ex) { r = ex.number; } - if(r === 0x4001 - 0x80000000) /* todo_wine XDomainRequest */ - continue; if(v < 8 && (ctors[i].length < 2 || v < ctors[i][1])) ok(r === 0xa1391 - 0x80000000, ctors[i][0] + " not undefined: " + r); else { @@ -1362,6 +1383,7 @@ sync_test("builtin_prototypes", function() { [ "TextRange", "Object" ], [ "UIEvent", "Event" ], [ "Window", "Object" ], + [ "XDomainRequest", "Object" ], [ "XMLDocument", "Document" ], [ "XMLHttpRequest", "Object" ] ]; @@ -1650,6 +1672,7 @@ sync_test("window_props", function() { test_exposed("DOMParser", v >= 9); test_exposed("matchMedia", v >= 10); test_exposed("msCrypto", v >= 11); + test_exposed("XDomainRequest", v < 11); }); sync_test("domimpl_props", function() { diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index 8623cec6a77..f99f95e745e 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -7291,6 +7291,41 @@ static void test_xmlhttprequest(IHTMLWindow5 *window) VariantClear(&var); } +static void test_xdomainrequest(IHTMLWindow6 *window) +{ + IHTMLXDomainRequestFactory *factory; + IHTMLXDomainRequest *xdr; + HRESULT hres; + VARIANT var; + + hres = IHTMLWindow6_get_XDomainRequest(window, &var); + ok(hres == S_OK, "get_XDomainRequest failed: %08lx\n", hres); + ok(V_VT(&var) == VT_DISPATCH || broken(V_VT(&var) == VT_EMPTY), "expect VT_DISPATCH, got %s\n", debugstr_variant(&var)); + + if(V_VT(&var) == VT_EMPTY) { + win_skip("Native XDomainRequest support is missing or disabled.\n"); + return; + } + + factory = NULL; + hres = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IHTMLXDomainRequestFactory, (void**)&factory); + ok(hres == S_OK, "QueryInterface(&IID_IHTMLXDomainRequestFactory) failed: %08lx\n", hres); + ok(factory != NULL, "factory == NULL\n"); + + test_factory(window, factory, L"XDomainRequest", L"[object XDomainRequest]"); + + xdr = NULL; + hres = IHTMLXDomainRequestFactory_create(factory, &xdr); + ok(hres == S_OK, "create failed: %08lx\n", hres); + ok(xdr != NULL, "xdr == NULL\n"); + if(is_ie9plus) + test_disp((IUnknown*)xdr, &DIID_DispXDomainRequest, NULL, L"[object]"); + + IHTMLXDomainRequest_Release(xdr); + IHTMLXDomainRequestFactory_Release(factory); + VariantClear(&var); +} + static void test_read_only_style(IHTMLCSSStyleDeclaration *style) { BSTR none = SysAllocString(L"none"), display = SysAllocString(L"display"), str; @@ -7316,6 +7351,7 @@ static void test_window(IHTMLDocument2 *doc) { IHTMLWindow2 *window, *window2, *self, *parent; IHTMLWindow5 *window5; + IHTMLWindow6 *window6; IHTMLWindow7 *window7; IHTMLDOMConstructorCollection *ctor_col; IHTMLDocument2 *doc2 = NULL; @@ -7420,6 +7456,15 @@ static void test_window(IHTMLDocument2 *doc) win_skip("IHTMLWindow5 not supported!\n"); } + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow6, (void**)&window6); + if(SUCCEEDED(hres)) { + ok(window6 != NULL, "window6 == NULL\n"); + test_xdomainrequest(window6); + IHTMLWindow6_Release(window6); + }else { + win_skip("IHTMLWindow6 not supported!\n"); + } + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLDOMConstructorCollection, (void**)&ctor_col); ok(hres == E_NOINTERFACE, "QueryInterface for IHTMLDOMConstructorCollection returned %08lx\n", hres); @@ -7648,6 +7693,28 @@ static void test_xhr(IHTMLDocument2 *doc) IDispatchEx_Release(dispex); } +static void test_xdr(IHTMLDocument2 *doc) +{ + IHTMLWindow2 *window; + IDispatchEx *dispex; + DISPID id; + BSTR str; + HRESULT hres; + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx iface: %08lx\n", hres); + + str = SysAllocString(L"XDomainRequest"); + hres = IDispatchEx_GetDispID(dispex, str, 0, &id); + ok(hres == S_OK, "GetDispID failed: %08lx\n", hres); + SysFreeString(str); + + IHTMLWindow2_Release(window); +} + static void test_defaults(IHTMLDocument2 *doc) { IHTMLStyleSheetsCollection *stylesheetcol; @@ -7721,6 +7788,7 @@ static void test_defaults(IHTMLDocument2 *doc) } test_xhr(doc); + test_xdr(doc); hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLBodyElement, (void**)&body); ok(hres == S_OK, "Could not get IHTMBodyElement: %08lx\n", hres); @@ -11888,6 +11956,7 @@ static void test_document_mode_lock(void) IEventTarget *event_target; IPersistStreamInit *init; IHTMLWindow7 *window7; + IHTMLWindow6 *window6; IHTMLWindow5 *window5; IHTMLWindow2 *window; IStream *stream; @@ -11938,6 +12007,14 @@ static void test_document_mode_lock(void) ok(V_VT(&var) == VT_EMPTY, "V_VT(XMLHttpRequest) = %d\n", V_VT(&var)); IHTMLWindow5_Release(window5); + V_VT(&var) = VT_NULL; + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow6, (void**)&window6); + ok(hres == S_OK, "Could not get IHTMLWindow6: %08lx\n", hres); + hres = IHTMLWindow6_get_XDomainRequest(window6, &var); + ok(hres == S_OK, "get_XDomainRequest failed: %08lx\n", hres); + ok(V_VT(&var) == VT_EMPTY, "V_VT(XDomainRequest) = %d\n", V_VT(&var)); + IHTMLWindow6_Release(window6); + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow7, (void**)&window7); ok(hres == S_OK, "Could not get IHTMLWindow7: %08lx\n", hres); hres = IHTMLWindow7_get_performance(window7, &var); diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 446a7b4435b..5c9700c5823 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -3963,6 +3963,7 @@ static void test_doc_obj(IHTMLDocument2 *doc) IHTMLOptionElementFactory *option, *option2; IHTMLImageElementFactory *image, *image2; IHTMLXMLHttpRequestFactory *xhr, *xhr2; + IHTMLXDomainRequestFactory *xdr, *xdr2; IHTMLDocument2 *doc_node, *doc_node2; IOmNavigator *navigator, *navigator2; IHTMLLocation *location, *location2; @@ -4137,7 +4138,14 @@ static void test_doc_obj(IHTMLDocument2 *doc) ok(hres == S_OK, "Could not get IHTMLWindow6: %08lx\n", hres); hres = IHTMLWindow6_get_sessionStorage(window6, &storage); ok(hres == S_OK, "get_sessionStorage failed: %08lx\n", hres); + + hres = IHTMLWindow6_get_XDomainRequest(window6, &res); + ok(hres == S_OK, "get_XDomainRequest failed: %08lx\n", hres); + ok(V_VT(&res) == VT_DISPATCH, "V_VT(XDomainRequest) = %d\n", V_VT(&res)); + hres = IDispatch_QueryInterface(V_DISPATCH(&res), &IID_IHTMLXDomainRequestFactory, (void**)&xdr); + ok(hres == S_OK, "Could not get IHTMLXDomainRequestFactory: %08lx\n", hres); IHTMLWindow6_Release(window6); + VariantClear(&res); hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow7, (void**)&window7); ok(hres == S_OK, "Could not get IHTMLWindow7: %08lx\n", hres); @@ -4274,7 +4282,18 @@ static void test_doc_obj(IHTMLDocument2 *doc) ok(storage != storage2, "storage == storage2\n"); IHTMLStorage_Release(storage2); IHTMLStorage_Release(storage); + + ok(hres == S_OK, "Could not get IHTMLWindow6: %08lx\n", hres); + hres = IHTMLWindow6_get_XDomainRequest(window6, &res); + ok(hres == S_OK, "get_XDomainRequest failed: %08lx\n", hres); + ok(V_VT(&res) == VT_DISPATCH, "V_VT(XDomainRequest) = %d\n", V_VT(&res)); + hres = IDispatch_QueryInterface(V_DISPATCH(&res), &IID_IHTMLXDomainRequestFactory, (void**)&xdr2); + ok(hres == S_OK, "Could not get IHTMLXDomainRequestFactory: %08lx\n", hres); + ok(xdr != xdr2, "xdr == xdr2\n"); + IHTMLXDomainRequestFactory_Release(xdr2); + IHTMLXDomainRequestFactory_Release(xdr); IHTMLWindow6_Release(window6); + VariantClear(&res); hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow7, (void**)&window7); ok(hres == S_OK, "Could not get IHTMLWindow7: %08lx\n", hres); diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 97edc4a0e16..a6c7af65385 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -145,6 +145,13 @@ struct HTMLXMLHttpRequest { XMLHttpReqEventListener *event_listener; }; +typedef struct { + EventTarget event_target; + IHTMLXDomainRequest IHTMLXDomainRequest_iface; + LONG ref; + nsIXMLHttpRequest *nsxhr; +} HTMLXDomainRequest; + static void detach_xhr_event_listener(XMLHttpReqEventListener *event_listener) { nsIDOMEventTarget *event_target; @@ -1623,3 +1630,489 @@ dispex_static_data_t HTMLXMLHttpRequestCtor_dispex = { IHTMLXMLHttpRequestFactory_tid, HTMLXMLHttpRequestFactory_iface_tids }; + + +/* IHTMLXDomainRequest */ +static inline HTMLXDomainRequest *impl_from_IHTMLXDomainRequest(IHTMLXDomainRequest *iface) +{ + return CONTAINING_RECORD(iface, HTMLXDomainRequest, IHTMLXDomainRequest_iface); +} + +static HRESULT WINAPI HTMLXDomainRequest_QueryInterface(IHTMLXDomainRequest *iface, REFIID riid, void **ppv) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + + TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); + + if(IsEqualGUID(&IID_IUnknown, riid)) { + *ppv = &This->IHTMLXDomainRequest_iface; + }else if(IsEqualGUID(&IID_IDispatch, riid)) { + *ppv = &This->IHTMLXDomainRequest_iface; + }else if(IsEqualGUID(&IID_IHTMLXDomainRequest, riid)) { + *ppv = &This->IHTMLXDomainRequest_iface; + }else if(dispex_query_interface(&This->event_target.dispex, riid, ppv)) { + return *ppv ? S_OK : E_NOINTERFACE; + }else { + *ppv = NULL; + WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI HTMLXDomainRequest_AddRef(IHTMLXDomainRequest *iface) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI HTMLXDomainRequest_Release(IHTMLXDomainRequest *iface) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if(!ref) { + release_event_target(&This->event_target); + release_dispex(&This->event_target.dispex); + nsIXMLHttpRequest_Release(This->nsxhr); + free(This); + } + + return ref; +} + +static HRESULT WINAPI HTMLXDomainRequest_GetTypeInfoCount(IHTMLXDomainRequest *iface, UINT *pctinfo) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + return IDispatchEx_GetTypeInfoCount(&This->event_target.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLXDomainRequest_GetTypeInfo(IHTMLXDomainRequest *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + return IDispatchEx_GetTypeInfo(&This->event_target.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLXDomainRequest_GetIDsOfNames(IHTMLXDomainRequest *iface, REFIID riid, LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + return IDispatchEx_GetIDsOfNames(&This->event_target.dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI HTMLXDomainRequest_Invoke(IHTMLXDomainRequest *iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + return IDispatchEx_Invoke(&This->event_target.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLXDomainRequest_get_responseText(IHTMLXDomainRequest *iface, BSTR *p) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + nsAString nsstr; + nsresult nsres; + + TRACE("(%p)->(%p)\n", This, p); + + if(!p) + return E_POINTER; + + nsAString_InitDepend(&nsstr, NULL); + nsres = nsIXMLHttpRequest_GetResponseText(This->nsxhr, &nsstr); + return return_nsstr(nsres, &nsstr, p); +} + +static HRESULT WINAPI HTMLXDomainRequest_put_timeout(IHTMLXDomainRequest *iface, LONG v) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + + FIXME("(%p)->(%ld)\n", This, v); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLXDomainRequest_get_timeout(IHTMLXDomainRequest *iface, LONG *p) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLXDomainRequest_get_contentType(IHTMLXDomainRequest *iface, BSTR *p) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + + FIXME("(%p)->(%p)\n", This, p); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLXDomainRequest_put_onprogress(IHTMLXDomainRequest *iface, VARIANT v) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + + return set_event_handler(&This->event_target, EVENTID_PROGRESS, &v); +} + +static HRESULT WINAPI HTMLXDomainRequest_get_onprogress(IHTMLXDomainRequest *iface, VARIANT *p) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + + TRACE("(%p)->(%p)\n", This, p); + + return get_event_handler(&This->event_target, EVENTID_PROGRESS, p); +} + +static HRESULT WINAPI HTMLXDomainRequest_put_onerror(IHTMLXDomainRequest *iface, VARIANT v) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + + return set_event_handler(&This->event_target, EVENTID_ERROR, &v); +} + +static HRESULT WINAPI HTMLXDomainRequest_get_onerror(IHTMLXDomainRequest *iface, VARIANT *p) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + + TRACE("(%p)->(%p)\n", This, p); + + return get_event_handler(&This->event_target, EVENTID_ERROR, p); +} + +static HRESULT WINAPI HTMLXDomainRequest_put_ontimeout(IHTMLXDomainRequest *iface, VARIANT v) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + + return set_event_handler(&This->event_target, EVENTID_TIMEOUT, &v); +} + +static HRESULT WINAPI HTMLXDomainRequest_get_ontimeout(IHTMLXDomainRequest *iface, VARIANT *p) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + + TRACE("(%p)->(%p)\n", This, p); + + return get_event_handler(&This->event_target, EVENTID_TIMEOUT, p); +} + +static HRESULT WINAPI HTMLXDomainRequest_put_onload(IHTMLXDomainRequest *iface, VARIANT v) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + + return set_event_handler(&This->event_target, EVENTID_LOAD, &v); +} + +static HRESULT WINAPI HTMLXDomainRequest_get_onload(IHTMLXDomainRequest *iface, VARIANT *p) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + + TRACE("(%p)->(%p)\n", This, p); + + return get_event_handler(&This->event_target, EVENTID_LOAD, p); +} + +static HRESULT WINAPI HTMLXDomainRequest_abort(IHTMLXDomainRequest *iface) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + + FIXME("(%p)->()\n", This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLXDomainRequest_open(IHTMLXDomainRequest *iface, BSTR bstrMethod, BSTR bstrUrl) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + + FIXME("(%p)->(%s %s)\n", This, debugstr_w(bstrMethod), debugstr_w(bstrUrl)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI HTMLXDomainRequest_send(IHTMLXDomainRequest *iface, VARIANT varBody) +{ + HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + + FIXME("(%p)->(%s)\n", This, debugstr_variant(&varBody)); + + return E_NOTIMPL; +} + +static const IHTMLXDomainRequestVtbl HTMLXDomainRequestVtbl = { + HTMLXDomainRequest_QueryInterface, + HTMLXDomainRequest_AddRef, + HTMLXDomainRequest_Release, + HTMLXDomainRequest_GetTypeInfoCount, + HTMLXDomainRequest_GetTypeInfo, + HTMLXDomainRequest_GetIDsOfNames, + HTMLXDomainRequest_Invoke, + HTMLXDomainRequest_get_responseText, + HTMLXDomainRequest_put_timeout, + HTMLXDomainRequest_get_timeout, + HTMLXDomainRequest_get_contentType, + HTMLXDomainRequest_put_onprogress, + HTMLXDomainRequest_get_onprogress, + HTMLXDomainRequest_put_onerror, + HTMLXDomainRequest_get_onerror, + HTMLXDomainRequest_put_ontimeout, + HTMLXDomainRequest_get_ontimeout, + HTMLXDomainRequest_put_onload, + HTMLXDomainRequest_get_onload, + HTMLXDomainRequest_abort, + HTMLXDomainRequest_open, + HTMLXDomainRequest_send +}; + +static inline HTMLXDomainRequest *XDomainRequest_from_DispatchEx(DispatchEx *iface) +{ + return CONTAINING_RECORD(iface, HTMLXDomainRequest, event_target.dispex); +} + +static nsISupports *HTMLXDomainRequest_get_gecko_target(DispatchEx *dispex) +{ + HTMLXDomainRequest *This = XDomainRequest_from_DispatchEx(dispex); + return (nsISupports*)This->nsxhr; +} + +static void HTMLXDomainRequest_bind_event(DispatchEx *dispex, eventid_t eid) +{ + HTMLXDomainRequest *This = XDomainRequest_from_DispatchEx(dispex); + + FIXME("(%p)\n", This); +} + +static void HTMLXDomainRequest_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) +{ + dispex_info_add_interface(info, IHTMLXDomainRequest_tid, NULL); +} + +static event_target_vtbl_t HTMLXDomainRequest_event_target_vtbl = { + { + NULL + }, + NULL, + HTMLXDomainRequest_get_gecko_target, + HTMLXDomainRequest_bind_event +}; + +dispex_static_data_t HTMLXDomainRequest_dispex = { + L"XDomainRequest", + &HTMLXDomainRequest_event_target_vtbl.dispex_vtbl, + PROTO_ID_HTMLXDomainRequest, + DispXDomainRequest_tid, + no_iface_tids, + HTMLXDomainRequest_init_dispex_info +}; + + +/* IHTMLXDomainRequestFactory */ +static inline struct legacy_ctor *impl_from_IHTMLXDomainRequestFactory(IHTMLXDomainRequestFactory *iface) +{ + return CONTAINING_RECORD(iface, struct legacy_ctor, IHTMLXDomainRequestFactory_iface); +} + +static HRESULT WINAPI HTMLXDomainRequestFactory_QueryInterface(IHTMLXDomainRequestFactory *iface, REFIID riid, void **ppv) +{ + struct legacy_ctor *This = impl_from_IHTMLXDomainRequestFactory(iface); + + TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); + + if(IsEqualGUID(&IID_IUnknown, riid)) { + *ppv = &This->IHTMLXDomainRequestFactory_iface; + }else if(IsEqualGUID(&IID_IDispatch, riid) || IsEqualGUID(&IID_IHTMLXDomainRequestFactory, riid)) { + *ppv = &This->IHTMLXDomainRequestFactory_iface; + }else if(dispex_query_interface(&This->dispex, riid, ppv)) { + return *ppv ? S_OK : E_NOINTERFACE; + }else { + *ppv = NULL; + WARN("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI HTMLXDomainRequestFactory_AddRef(IHTMLXDomainRequestFactory *iface) +{ + struct legacy_ctor *This = impl_from_IHTMLXDomainRequestFactory(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI HTMLXDomainRequestFactory_Release(IHTMLXDomainRequestFactory *iface) +{ + struct legacy_ctor *This = impl_from_IHTMLXDomainRequestFactory(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if(!ref) { + /* Proxy constructor disps hold ref to window, others are always detached first */ + if(This->window) + IHTMLWindow2_Release(&This->window->base.IHTMLWindow2_iface); + release_dispex(&This->dispex); + free(This); + } + + return ref; +} + +static HRESULT WINAPI HTMLXDomainRequestFactory_GetTypeInfoCount(IHTMLXDomainRequestFactory *iface, UINT *pctinfo) +{ + struct legacy_ctor *This = impl_from_IHTMLXDomainRequestFactory(iface); + return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLXDomainRequestFactory_GetTypeInfo(IHTMLXDomainRequestFactory *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + struct legacy_ctor *This = impl_from_IHTMLXDomainRequestFactory(iface); + return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLXDomainRequestFactory_GetIDsOfNames(IHTMLXDomainRequestFactory *iface, REFIID riid, LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + struct legacy_ctor *This = impl_from_IHTMLXDomainRequestFactory(iface); + return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI HTMLXDomainRequestFactory_Invoke(IHTMLXDomainRequestFactory *iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + struct legacy_ctor *This = impl_from_IHTMLXDomainRequestFactory(iface); + return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLXDomainRequestFactory_create(IHTMLXDomainRequestFactory *iface, IHTMLXDomainRequest **p) +{ + struct legacy_ctor *This = impl_from_IHTMLXDomainRequestFactory(iface); + nsIXMLHttpRequest *nsxhr; + HTMLXDomainRequest *ret; + + TRACE("(%p)->(%p)\n", This, p); + + nsxhr = create_nsxhr(This->window->base.outer_window->nswindow); + if(!nsxhr) + return E_FAIL; + + ret = calloc(1, sizeof(*ret)); + if(!ret) { + nsIXMLHttpRequest_Release(nsxhr); + return E_OUTOFMEMORY; + } + ret->nsxhr = nsxhr; + + ret->IHTMLXDomainRequest_iface.lpVtbl = &HTMLXDomainRequestVtbl; + ret->ref = 1; + EventTarget_Init(&ret->event_target, (IUnknown*)&ret->IHTMLXDomainRequest_iface, + &HTMLXDomainRequest_dispex, This->window); + + *p = &ret->IHTMLXDomainRequest_iface; + return S_OK; +} + +const IHTMLXDomainRequestFactoryVtbl HTMLXDomainRequestFactoryVtbl = { + HTMLXDomainRequestFactory_QueryInterface, + HTMLXDomainRequestFactory_AddRef, + HTMLXDomainRequestFactory_Release, + HTMLXDomainRequestFactory_GetTypeInfoCount, + HTMLXDomainRequestFactory_GetTypeInfo, + HTMLXDomainRequestFactory_GetIDsOfNames, + HTMLXDomainRequestFactory_Invoke, + HTMLXDomainRequestFactory_create +}; + +static HRESULT HTMLXDomainRequestFactory_value(DispatchEx *iface, LCID lcid, WORD flags, DISPPARAMS *params, + VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + struct legacy_ctor *This = ctor_from_DispatchEx(iface); + IHTMLXDomainRequest *xdr; + HRESULT hres; + + TRACE("\n"); + + if(flags != DISPATCH_CONSTRUCT) + return S_FALSE; + + hres = IHTMLXDomainRequestFactory_create(&This->IHTMLXDomainRequestFactory_iface, &xdr); + if(FAILED(hres)) + return hres; + + V_VT(res) = VT_DISPATCH; + V_DISPATCH(res) = (IDispatch*)xdr; + return S_OK; +} + +static const dispex_static_data_vtbl_t HTMLXDomainRequestFactory_dispex_vtbl = { + HTMLXDomainRequestFactory_value, + legacy_ctor_get_dispid, + legacy_ctor_get_name, + legacy_ctor_invoke, + legacy_ctor_delete +}; + +static const tid_t HTMLXDomainRequestFactory_iface_tids[] = { + IHTMLXDomainRequestFactory_tid, + 0 +}; +dispex_static_data_t HTMLXDomainRequestFactory_dispex = { + L"XDomainRequest", + &HTMLXDomainRequestFactory_dispex_vtbl, + PROTO_ID_NULL, + IHTMLXDomainRequestFactory_tid, + HTMLXDomainRequestFactory_iface_tids +}; + +static HRESULT HTMLXDomainRequestCtor_value(DispatchEx *iface, LCID lcid, WORD flags, DISPPARAMS *params, + VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller) +{ + if(flags == DISPATCH_CONSTRUCT) + return HTMLXDomainRequestFactory_value(iface, lcid, flags, params, res, ei, caller); + + return legacy_ctor_value(iface, lcid, flags, params, res, ei, caller); +} + +static const dispex_static_data_vtbl_t HTMLXDomainRequestCtor_dispex_vtbl = { + HTMLXDomainRequestCtor_value, + legacy_ctor_get_dispid, + legacy_ctor_get_name, + legacy_ctor_invoke, + legacy_ctor_delete +}; + +dispex_static_data_t HTMLXDomainRequestCtor_dispex = { + L"XDomainRequest", + &HTMLXDomainRequestCtor_dispex_vtbl, + PROTO_ID_NULL, + IHTMLXDomainRequestFactory_tid, + HTMLXDomainRequestFactory_iface_tids +}; From 051db10bf0a7d5f139cd7c0c4ca17e4e6749b111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:10 +0200 Subject: [PATCH 0945/2777] mshtml: Implement XDomainRequest.open(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/tests/xhr.js | 24 +++++++++++++ dlls/mshtml/xmlhttprequest.c | 70 ++++++++++++++++++++++++++++++++++-- 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/tests/xhr.js b/dlls/mshtml/tests/xhr.js index 8b78db7243a..9ea202f28dd 100644 --- a/dlls/mshtml/tests/xhr.js +++ b/dlls/mshtml/tests/xhr.js @@ -167,6 +167,29 @@ function test_content_types() { xhr.send(xml); } +function test_xdr() { + if(!window.XDomainRequest) { next_test(); return; } + + var xdr = new XDomainRequest(); + xdr.open("POST", "echo.php"); + // send on native aborts with custom pluggable protocol handler even with the right + // response headers (`XDomainRequestAllowed: 1` and `Access-Control-Allow-Origin: *`). + + // Only http/https schemes are allowed, and it must match with the origin's scheme + xdr = new XDomainRequest(); + xdr.open("GET", "http://www.winehq.org/"); + + xdr = new XDomainRequest(); + try { + xdr.open("GET", "https://www.winehq.org/"); + ok(false, "xdr scheme mismatch did not throw exception"); + }catch(ex) { + var n = ex.number >>> 0; + ok(n === 0x80070005, "xdr scheme mismatch threw " + n); + } + next_test(); +} + function test_abort() { var xhr = new XMLHttpRequest(); if(!("onabort" in xhr)) { next_test(); return; } @@ -321,6 +344,7 @@ function test_response() { var tests = [ test_xhr, + test_xdr, test_content_types, test_abort, test_timeout, diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index a6c7af65385..89583eb3527 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -149,6 +149,7 @@ typedef struct { EventTarget event_target; IHTMLXDomainRequest IHTMLXDomainRequest_iface; LONG ref; + HTMLInnerWindow *window; nsIXMLHttpRequest *nsxhr; } HTMLXDomainRequest; @@ -1680,6 +1681,7 @@ static ULONG WINAPI HTMLXDomainRequest_Release(IHTMLXDomainRequest *iface) TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { + IHTMLWindow2_Release(&This->window->base.IHTMLWindow2_iface); release_event_target(&This->event_target); release_dispex(&This->event_target.dispex); nsIXMLHttpRequest_Release(This->nsxhr); @@ -1845,10 +1847,72 @@ static HRESULT WINAPI HTMLXDomainRequest_abort(IHTMLXDomainRequest *iface) static HRESULT WINAPI HTMLXDomainRequest_open(IHTMLXDomainRequest *iface, BSTR bstrMethod, BSTR bstrUrl) { HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + nsAString nsstr, password; + nsACString str1, str2; + nsresult nsres; + HRESULT hres; + WCHAR *p; - FIXME("(%p)->(%s %s)\n", This, debugstr_w(bstrMethod), debugstr_w(bstrUrl)); + TRACE("(%p)->(%s %s)\n", This, debugstr_w(bstrMethod), debugstr_w(bstrUrl)); - return E_NOTIMPL; + if((p = wcschr(bstrUrl, ':')) && p[1] == '/' && p[2] == '/') { + size_t len = p - bstrUrl; + BSTR bstr; + + /* Native only allows http and https, and the scheme must match */ + if(len < 4 || len > 5 || wcsnicmp(bstrUrl, L"https", len) || !This->window->base.outer_window->uri) + return E_ACCESSDENIED; + + hres = IUri_GetSchemeName(This->window->base.outer_window->uri, &bstr); + if(FAILED(hres)) + return hres; + if(SysStringLen(bstr) != len || wcsnicmp(bstr, bstrUrl, len)) + hres = E_ACCESSDENIED; + SysFreeString(bstr); + if(FAILED(hres)) + return hres; + } + + hres = bstr_to_nsacstr(bstrMethod, &str1); + if(FAILED(hres)) + return hres; + + hres = bstr_to_nsacstr(bstrUrl, &str2); + if(FAILED(hres)) { + nsACString_Finish(&str1); + return hres; + } + + nsAString_Init(&nsstr, NULL); + nsAString_Init(&password, NULL); + nsres = nsIXMLHttpRequest_Open(This->nsxhr, &str1, &str2, TRUE, &nsstr, &password, 0); + nsAString_Finish(&nsstr); + nsAString_Finish(&password); + nsACString_Finish(&str1); + nsACString_Finish(&str2); + if(NS_FAILED(nsres)) { + ERR("nsIXMLHttpRequest_Open failed: %08lx\n", nsres); + return map_nsresult(nsres); + } + + /* Prevent Gecko from parsing responseXML for no reason */ + nsAString_InitDepend(&nsstr, L"text/plain"); + nsIXMLHttpRequest_SlowOverrideMimeType(This->nsxhr, &nsstr); + nsAString_Finish(&nsstr); + + /* XDomainRequest only accepts text/plain */ + nsACString_InitDepend(&str1, "Accept"); + nsACString_InitDepend(&str2, "text/plain"); + nsres = nsIXMLHttpRequest_SetRequestHeader(This->nsxhr, &str1, &str2); + nsACString_Finish(&str1); + nsACString_Finish(&str2); + if(NS_FAILED(nsres)) { + ERR("nsIXMLHttpRequest_SetRequestHeader failed: %08lx\n", nsres); + return map_nsresult(nsres); + } + + /* IE always adds Origin header, even from same origin, but Gecko doesn't allow us to alter it. */ + return S_OK; } static HRESULT WINAPI HTMLXDomainRequest_send(IHTMLXDomainRequest *iface, VARIANT varBody) @@ -2030,6 +2094,8 @@ static HRESULT WINAPI HTMLXDomainRequestFactory_create(IHTMLXDomainRequestFactor return E_OUTOFMEMORY; } ret->nsxhr = nsxhr; + ret->window = This->window; + IHTMLWindow2_AddRef(&This->window->base.IHTMLWindow2_iface); ret->IHTMLXDomainRequest_iface.lpVtbl = &HTMLXDomainRequestVtbl; ret->ref = 1; From 6dff903e1c5f431f1560ced4d7f1fac88c086aac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:10 +0200 Subject: [PATCH 0946/2777] mshtml: Move XMLHttpRequest.send() implementation to a helper. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/xmlhttprequest.c | 74 +++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 89583eb3527..c4d2cfa3967 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -179,6 +179,45 @@ static void detach_xhr_event_listener(XMLHttpReqEventListener *event_listener) nsIDOMEventListener_Release(&event_listener->nsIDOMEventListener_iface); } +static HRESULT WINAPI nsxhr_send(nsIXMLHttpRequest *nsxhr, VARIANT body) +{ + nsIWritableVariant *nsbody = NULL; + nsresult nsres = NS_OK; + + switch(V_VT(&body)) { + case VT_NULL: + case VT_EMPTY: + case VT_ERROR: + break; + case VT_BSTR: { + nsAString nsstr; + + nsbody = create_nsvariant(); + if(!nsbody) + return E_OUTOFMEMORY; + + nsAString_InitDepend(&nsstr, V_BSTR(&body)); + nsres = nsIWritableVariant_SetAsAString(nsbody, &nsstr); + nsAString_Finish(&nsstr); + break; + } + default: + FIXME("unsupported body type %s\n", debugstr_variant(&body)); + return E_NOTIMPL; + } + + if(NS_SUCCEEDED(nsres)) + nsres = nsIXMLHttpRequest_Send(nsxhr, (nsIVariant*)nsbody); + if(nsbody) + nsIWritableVariant_Release(nsbody); + if(NS_FAILED(nsres)) { + ERR("nsIXMLHttpRequest_Send failed: %08lx\n", nsres); + return map_nsresult(nsres); + } + + return S_OK; +} + static inline XMLHttpReqEventListener *impl_from_nsIDOMEventListener(nsIDOMEventListener *iface) { @@ -654,43 +693,10 @@ static HRESULT WINAPI HTMLXMLHttpRequest_open(IHTMLXMLHttpRequest *iface, BSTR b static HRESULT WINAPI HTMLXMLHttpRequest_send(IHTMLXMLHttpRequest *iface, VARIANT varBody) { HTMLXMLHttpRequest *This = impl_from_IHTMLXMLHttpRequest(iface); - nsIWritableVariant *nsbody = NULL; - nsresult nsres = NS_OK; TRACE("(%p)->(%s)\n", This, debugstr_variant(&varBody)); - switch(V_VT(&varBody)) { - case VT_NULL: - case VT_EMPTY: - case VT_ERROR: - break; - case VT_BSTR: { - nsAString nsstr; - - nsbody = create_nsvariant(); - if(!nsbody) - return E_OUTOFMEMORY; - - nsAString_InitDepend(&nsstr, V_BSTR(&varBody)); - nsres = nsIWritableVariant_SetAsAString(nsbody, &nsstr); - nsAString_Finish(&nsstr); - break; - } - default: - FIXME("unsupported body type %s\n", debugstr_variant(&varBody)); - return E_NOTIMPL; - } - - if(NS_SUCCEEDED(nsres)) - nsres = nsIXMLHttpRequest_Send(This->nsxhr, (nsIVariant*)nsbody); - if(nsbody) - nsIWritableVariant_Release(nsbody); - if(NS_FAILED(nsres)) { - ERR("nsIXMLHttpRequest_Send failed: %08lx\n", nsres); - return E_FAIL; - } - - return S_OK; + return nsxhr_send(This->nsxhr, varBody); } static HRESULT WINAPI HTMLXMLHttpRequest_getAllResponseHeaders(IHTMLXMLHttpRequest *iface, BSTR *p) From 579e6308caeedd110d7170de6868028a777ea4be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:10 +0200 Subject: [PATCH 0947/2777] mshtml: Implement XDomainRequest.send(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/xmlhttprequest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index c4d2cfa3967..2d774f80dd9 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1925,9 +1925,9 @@ static HRESULT WINAPI HTMLXDomainRequest_send(IHTMLXDomainRequest *iface, VARIAN { HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); - FIXME("(%p)->(%s)\n", This, debugstr_variant(&varBody)); + TRACE("(%p)->(%s)\n", This, debugstr_variant(&varBody)); - return E_NOTIMPL; + return nsxhr_send(This->nsxhr, varBody); } static const IHTMLXDomainRequestVtbl HTMLXDomainRequestVtbl = { From 6ec89ef7d60094c1e6c78b79b0732d5492eeb5fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:10 +0200 Subject: [PATCH 0948/2777] mshtml: Implement XDomainRequest.abort(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/xmlhttprequest.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 2d774f80dd9..c73d8dec9ff 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1844,10 +1844,17 @@ static HRESULT WINAPI HTMLXDomainRequest_get_onload(IHTMLXDomainRequest *iface, static HRESULT WINAPI HTMLXDomainRequest_abort(IHTMLXDomainRequest *iface) { HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + nsresult nsres; - FIXME("(%p)->()\n", This); + TRACE("(%p)->()\n", This); - return E_NOTIMPL; + nsres = nsIXMLHttpRequest_SlowAbort(This->nsxhr); + if(NS_FAILED(nsres)) { + ERR("nsIXMLHttpRequest_SlowAbort failed: %08lx\n", nsres); + return map_nsresult(nsres); + } + + return S_OK; } static HRESULT WINAPI HTMLXDomainRequest_open(IHTMLXDomainRequest *iface, BSTR bstrMethod, BSTR bstrUrl) From 1ca2f9bd851fb238bc91fc68b73c13bfbb4f4380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:10 +0200 Subject: [PATCH 0949/2777] mshtml: Don't go through HTMLXMLHttpRequest in XMLHttpReqEventListener. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Store (non-refcounted) pointer copies of the elements we need, instead of going through HTMLXMLHttpRequest, so it can be shared by XDomainRequest. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/xmlhttprequest.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index c73d8dec9ff..f8cd68b3f66 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -127,7 +127,9 @@ static const struct { typedef struct { nsIDOMEventListener nsIDOMEventListener_iface; LONG ref; - HTMLXMLHttpRequest *xhr; + EventTarget *event_target; + HTMLInnerWindow *window; + nsIXMLHttpRequest *nsxhr; DWORD events_mask; } XMLHttpReqEventListener; @@ -160,7 +162,7 @@ static void detach_xhr_event_listener(XMLHttpReqEventListener *event_listener) nsAString str; nsresult nsres; - nsres = nsIXMLHttpRequest_QueryInterface(event_listener->xhr->nsxhr, &IID_nsIDOMEventTarget, (void**)&event_target); + nsres = nsIXMLHttpRequest_QueryInterface(event_listener->nsxhr, &IID_nsIDOMEventTarget, (void**)&event_target); assert(nsres == NS_OK); for(events_mask = event_listener->events_mask, i = 0; events_mask; events_mask >>= 1, i++) { @@ -174,8 +176,7 @@ static void detach_xhr_event_listener(XMLHttpReqEventListener *event_listener) nsIDOMEventTarget_Release(event_target); - event_listener->xhr->event_listener = NULL; - event_listener->xhr = NULL; + event_listener->event_target = NULL; nsIDOMEventListener_Release(&event_listener->nsIDOMEventListener_iface); } @@ -263,7 +264,7 @@ static nsrefcnt NSAPI XMLHttpReqEventListener_Release(nsIDOMEventListener *iface TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { - assert(!This->xhr); + assert(!This->event_target); free(This); } @@ -278,12 +279,12 @@ static nsresult NSAPI XMLHttpReqEventListener_HandleEvent(nsIDOMEventListener *i TRACE("(%p)\n", This); - if(!This->xhr) + if(!This->event_target) return NS_OK; - hres = create_event_from_nsevent(nsevent, This->xhr->window, dispex_compat_mode(&This->xhr->event_target.dispex), &event); + hres = create_event_from_nsevent(nsevent, This->window, dispex_compat_mode(&This->event_target->dispex), &event); if(SUCCEEDED(hres) ){ - dispatch_event(&This->xhr->event_target, event); + dispatch_event(This->event_target, event); IDOMEvent_Release(&event->IDOMEvent_iface); } return NS_OK; @@ -1360,7 +1361,9 @@ static void HTMLXMLHttpRequest_bind_event(DispatchEx *dispex, eventid_t eid) This->event_listener->nsIDOMEventListener_iface.lpVtbl = &XMLHttpReqEventListenerVtbl; This->event_listener->ref = 1; - This->event_listener->xhr = This; + This->event_listener->event_target = &This->event_target; + This->event_listener->window = This->window; + This->event_listener->nsxhr = This->nsxhr; This->event_listener->events_mask = 0; } From e68593adc85f4dcd5fcf2ee16d14b115c6c42f52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:10 +0200 Subject: [PATCH 0950/2777] mshtml: Implement events handling for XDomainRequest. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/tests/xmlhttprequest.c | 137 +++++++++++++++++++++++++++++ dlls/mshtml/xmlhttprequest.c | 43 ++++++++- 2 files changed, 179 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/tests/xmlhttprequest.c b/dlls/mshtml/tests/xmlhttprequest.c index 4316a25f595..7d3ffa9e42c 100644 --- a/dlls/mshtml/tests/xmlhttprequest.c +++ b/dlls/mshtml/tests/xmlhttprequest.c @@ -63,6 +63,7 @@ DEFINE_EXPECT(xmlhttprequest_onreadystatechange_opened); DEFINE_EXPECT(xmlhttprequest_onreadystatechange_headers_received); DEFINE_EXPECT(xmlhttprequest_onreadystatechange_loading); DEFINE_EXPECT(xmlhttprequest_onreadystatechange_done); +DEFINE_EXPECT(xdomainrequest_onload); #define test_disp(u,id) _test_disp(__LINE__,u,id) static void _test_disp(unsigned line, IUnknown *unk, const IID *diid, const IID *broken_diid) @@ -266,6 +267,58 @@ static IDispatchExVtbl xmlhttprequest_onreadystatechangeFuncVtbl = { }; static IDispatchEx xmlhttprequest_onreadystatechange_obj = { &xmlhttprequest_onreadystatechangeFuncVtbl }; +static HRESULT WINAPI xdomainrequest_onload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + test_event_args(&DIID_DispXDomainRequest, &IID_IHTMLXDomainRequest, id, wFlags, pdp, pvarRes, pei, pspCaller); + CHECK_EXPECT(xdomainrequest_onload); + return S_OK; +} + +static IDispatchExVtbl xdomainrequest_onloadFuncVtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + xdomainrequest_onload, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; +static IDispatchEx xdomainrequest_onload_obj = { &xdomainrequest_onloadFuncVtbl }; + +static HRESULT WINAPI xdomainrequest_ignore(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + return S_OK; +} + +static IDispatchExVtbl xdomainrequest_ignoreFuncVtbl = { + DispatchEx_QueryInterface, + DispatchEx_AddRef, + DispatchEx_Release, + DispatchEx_GetTypeInfoCount, + DispatchEx_GetTypeInfo, + DispatchEx_GetIDsOfNames, + DispatchEx_Invoke, + DispatchEx_GetDispID, + xdomainrequest_ignore, + DispatchEx_DeleteMemberByName, + DispatchEx_DeleteMemberByDispID, + DispatchEx_GetMemberProperties, + DispatchEx_GetMemberName, + DispatchEx_GetNextDispID, + DispatchEx_GetNameSpaceParent +}; +static IDispatchEx xdomainrequest_ignore_obj = { &xdomainrequest_ignoreFuncVtbl }; + static BOOL doc_complete; static IHTMLDocument2 *notif_doc; @@ -1087,6 +1140,89 @@ static void test_timeout(IHTMLDocument2 *doc) IHTMLXMLHttpRequest2_Release(xhr2); } +static void test_xdr(IHTMLDocument2 *doc) +{ + IHTMLXDomainRequestFactory *factory; + IHTMLXDomainRequest *xdr; + IHTMLWindow6 *window6; + IHTMLWindow2 *window; + BSTR bstr, url; + HRESULT hres; + VARIANT v; + + hres = IHTMLDocument2_get_parentWindow(doc, &window); + ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); + ok(window != NULL, "window == NULL\n"); + + hres = IHTMLWindow2_QueryInterface(window, &IID_IHTMLWindow6, (void**)&window6); + IHTMLWindow2_Release(window); + if(FAILED(hres)) { + win_skip("IHTMLWindow6 not supported\n"); + return; + } + + VariantInit(&v); + hres = IHTMLWindow6_get_XDomainRequest(window6, &v); + IHTMLWindow6_Release(window6); + ok(hres == S_OK, "get_XDomainRequest failed: %08lx\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(&v) is %08x, expected VT_DISPATCH\n", V_VT(&v)); + + hres = IDispatch_QueryInterface(V_DISPATCH(&v), &IID_IHTMLXDomainRequestFactory, (void**)&factory); + VariantClear(&v); + ok(hres == S_OK, "QueryInterface(IID_IXDomainRequestFactory) failed: %08lx\n", hres); + ok(factory != NULL, "factory == NULL\n"); + + hres = IHTMLXDomainRequestFactory_create(factory, &xdr); + IHTMLXDomainRequestFactory_Release(factory); + ok(hres == S_OK, "create failed: %08lx\n", hres); + ok(xdr != NULL, "xdr == NULL\n"); + + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)&xdomainrequest_onload_obj; + hres = IHTMLXDomainRequest_put_onload(xdr, v); + ok(hres == S_OK, "put_onload failed: %08lx\n", hres); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLXDomainRequest_get_onload(xdr, &v); + ok(hres == S_OK, "get_onload failed: %08lx\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(onload) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) == (IDispatch*)&xdomainrequest_onload_obj, "unexpected onload value\n"); + VariantClear(&v); + + /* Native IE9 sometimes (rarely) aborts if the other handlers are not set */ + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)&xdomainrequest_ignore_obj; + hres = IHTMLXDomainRequest_put_onerror(xdr, v); + ok(hres == S_OK, "put_onerror failed: %08lx\n", hres); + hres = IHTMLXDomainRequest_put_onprogress(xdr, v); + ok(hres == S_OK, "put_onprogress failed: %08lx\n", hres); + hres = IHTMLXDomainRequest_put_ontimeout(xdr, v); + ok(hres == S_OK, "put_ontimeout failed: %08lx\n", hres); + + bstr = SysAllocString(L"GET"); + url = SysAllocString(L"http://test.winehq.org/tests/cors.html"); + hres = IHTMLXDomainRequest_open(xdr, bstr, url); + ok(hres == S_OK, "open failed: %08lx\n", hres); + SysFreeString(bstr); + SysFreeString(url); + + V_VT(&v) = VT_BSTR; + V_BSTR(&v) = SysAllocString(L"test"); + SET_EXPECT(xdomainrequest_onload); + hres = IHTMLXDomainRequest_send(xdr, v); + ok(hres == S_OK, "send failed: %08lx\n", hres); + if(SUCCEEDED(hres)) + pump_msgs(&called_xdomainrequest_onload); + CHECK_CALLED(xdomainrequest_onload); + + hres = IHTMLXDomainRequest_get_responseText(xdr, &bstr); + ok(hres == S_OK, "get_contentType returned %08lx\n", hres); + ok(!lstrcmpW(bstr, L"test\n"), "responseText = %s\n", debugstr_w(bstr)); + SysFreeString(bstr); + + IHTMLXDomainRequest_Release(xdr); +} + static IHTMLDocument2 *create_doc_from_url(const WCHAR *start_url) { BSTR url; @@ -1153,6 +1289,7 @@ START_TEST(xmlhttprequest) test_async_xhr_abort(doc, large_page_url); test_xhr_post(doc); test_timeout(doc); + test_xdr(doc); IHTMLDocument2_Release(doc); } SysFreeString(content_type); diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index f8cd68b3f66..78be87e1dff 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -153,6 +153,7 @@ typedef struct { LONG ref; HTMLInnerWindow *window; nsIXMLHttpRequest *nsxhr; + XMLHttpReqEventListener *event_listener; } HTMLXDomainRequest; static void detach_xhr_event_listener(XMLHttpReqEventListener *event_listener) @@ -1690,6 +1691,8 @@ static ULONG WINAPI HTMLXDomainRequest_Release(IHTMLXDomainRequest *iface) TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { + if(This->event_listener) + detach_xhr_event_listener(This->event_listener); IHTMLWindow2_Release(&This->window->base.IHTMLWindow2_iface); release_event_target(&This->event_target); release_dispex(&This->event_target.dispex); @@ -1979,8 +1982,46 @@ static nsISupports *HTMLXDomainRequest_get_gecko_target(DispatchEx *dispex) static void HTMLXDomainRequest_bind_event(DispatchEx *dispex, eventid_t eid) { HTMLXDomainRequest *This = XDomainRequest_from_DispatchEx(dispex); + nsIDOMEventTarget *nstarget; + nsAString type_str; + const WCHAR *name; + nsresult nsres; + unsigned i; + + TRACE("(%p)\n", This); + + for(i = 0; i < ARRAY_SIZE(events); i++) + if(eid == events[i]) + break; + if(i >= ARRAY_SIZE(events)) + return; + + if(!This->event_listener) { + This->event_listener = malloc(sizeof(*This->event_listener)); + if(!This->event_listener) + return; - FIXME("(%p)\n", This); + This->event_listener->nsIDOMEventListener_iface.lpVtbl = &XMLHttpReqEventListenerVtbl; + This->event_listener->ref = 1; + This->event_listener->event_target = &This->event_target; + This->event_listener->window = This->window; + This->event_listener->nsxhr = This->nsxhr; + This->event_listener->events_mask = 0; + } + + nsres = nsIXMLHttpRequest_QueryInterface(This->nsxhr, &IID_nsIDOMEventTarget, (void**)&nstarget); + assert(nsres == NS_OK); + + name = get_event_name(events[i]); + nsAString_InitDepend(&type_str, name); + nsres = nsIDOMEventTarget_AddEventListener(nstarget, &type_str, &This->event_listener->nsIDOMEventListener_iface, FALSE, TRUE, 2); + nsAString_Finish(&type_str); + if(NS_FAILED(nsres)) + ERR("AddEventListener(%s) failed: %08lx\n", debugstr_w(name), nsres); + + nsIDOMEventTarget_Release(nstarget); + + This->event_listener->events_mask |= 1 << i; } static void HTMLXDomainRequest_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode) From d5be26bcf49dafc029035f55d3f0c198b9f0a05c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:10 +0200 Subject: [PATCH 0951/2777] mshtml: Implement timeout for XDomainRequest. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/tests/xmlhttprequest.c | 15 +++++++++++++++ dlls/mshtml/xmlhttprequest.c | 17 +++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/dlls/mshtml/tests/xmlhttprequest.c b/dlls/mshtml/tests/xmlhttprequest.c index 7d3ffa9e42c..bd4194889ae 100644 --- a/dlls/mshtml/tests/xmlhttprequest.c +++ b/dlls/mshtml/tests/xmlhttprequest.c @@ -1148,6 +1148,7 @@ static void test_xdr(IHTMLDocument2 *doc) IHTMLWindow2 *window; BSTR bstr, url; HRESULT hres; + LONG timeout; VARIANT v; hres = IHTMLDocument2_get_parentWindow(doc, &window); @@ -1206,6 +1207,20 @@ static void test_xdr(IHTMLDocument2 *doc) SysFreeString(bstr); SysFreeString(url); + hres = IHTMLXDomainRequest_get_timeout(xdr, NULL); + ok(hres == E_INVALIDARG, "get_timeout returned %08lx\n", hres); + hres = IHTMLXDomainRequest_get_timeout(xdr, &timeout); + ok(hres == S_OK, "get_timeout returned %08lx\n", hres); + ok(timeout == -1, "timeout = %ld\n", timeout); + + hres = IHTMLXDomainRequest_put_timeout(xdr, -1); + ok(hres == E_INVALIDARG || broken(hres == E_FAIL), "put_timeout returned %08lx\n", hres); + hres = IHTMLXDomainRequest_put_timeout(xdr, 1337); + ok(hres == S_OK, "put_timeout returned %08lx\n", hres); + hres = IHTMLXDomainRequest_get_timeout(xdr, &timeout); + ok(hres == S_OK, "get_timeout returned %08lx\n", hres); + ok(timeout == 1337, "timeout = %ld\n", timeout); + V_VT(&v) = VT_BSTR; V_BSTR(&v) = SysAllocString(L"test"); SET_EXPECT(xdomainrequest_onload); diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 78be87e1dff..9ecbd2aa62a 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1752,18 +1752,27 @@ static HRESULT WINAPI HTMLXDomainRequest_put_timeout(IHTMLXDomainRequest *iface, { HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); - FIXME("(%p)->(%ld)\n", This, v); + TRACE("(%p)->(%ld)\n", This, v); - return E_NOTIMPL; + if(v < 0) + return E_INVALIDARG; + return map_nsresult(nsIXMLHttpRequest_SetTimeout(This->nsxhr, v)); } static HRESULT WINAPI HTMLXDomainRequest_get_timeout(IHTMLXDomainRequest *iface, LONG *p) { HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + nsresult nsres; + UINT32 timeout; - FIXME("(%p)->(%p)\n", This, p); + TRACE("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + if(!p) + return E_INVALIDARG; + + nsres = nsIXMLHttpRequest_GetTimeout(This->nsxhr, &timeout); + *p = timeout ? timeout : -1; + return map_nsresult(nsres); } static HRESULT WINAPI HTMLXDomainRequest_get_contentType(IHTMLXDomainRequest *iface, BSTR *p) From 44751d51fa510b88727adcb506864e500bd7dd5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:10 +0200 Subject: [PATCH 0952/2777] mshtml: Implement contentType for XDomainRequest. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/tests/dom.c | 5 ++++ dlls/mshtml/tests/xmlhttprequest.c | 13 ++++++++++ dlls/mshtml/xmlhttprequest.c | 41 ++++++++++++++++++++++++++++-- 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c index f99f95e745e..4d3f6a6fb53 100644 --- a/dlls/mshtml/tests/dom.c +++ b/dlls/mshtml/tests/dom.c @@ -7297,6 +7297,7 @@ static void test_xdomainrequest(IHTMLWindow6 *window) IHTMLXDomainRequest *xdr; HRESULT hres; VARIANT var; + BSTR bstr; hres = IHTMLWindow6_get_XDomainRequest(window, &var); ok(hres == S_OK, "get_XDomainRequest failed: %08lx\n", hres); @@ -7321,6 +7322,10 @@ static void test_xdomainrequest(IHTMLWindow6 *window) if(is_ie9plus) test_disp((IUnknown*)xdr, &DIID_DispXDomainRequest, NULL, L"[object]"); + hres = IHTMLXDomainRequest_get_contentType(xdr, &bstr); + ok(hres == S_OK, "get_contentType returned %08lx\n", hres); + ok(bstr == NULL, "contentType = %s\n", debugstr_w(bstr)); + IHTMLXDomainRequest_Release(xdr); IHTMLXDomainRequestFactory_Release(factory); VariantClear(&var); diff --git a/dlls/mshtml/tests/xmlhttprequest.c b/dlls/mshtml/tests/xmlhttprequest.c index bd4194889ae..375a711f8db 100644 --- a/dlls/mshtml/tests/xmlhttprequest.c +++ b/dlls/mshtml/tests/xmlhttprequest.c @@ -1200,6 +1200,10 @@ static void test_xdr(IHTMLDocument2 *doc) hres = IHTMLXDomainRequest_put_ontimeout(xdr, v); ok(hres == S_OK, "put_ontimeout failed: %08lx\n", hres); + hres = IHTMLXDomainRequest_get_contentType(xdr, &bstr); + ok(hres == S_OK, "get_contentType returned %08lx\n", hres); + ok(bstr == NULL, "contentType = %s\n", debugstr_w(bstr)); + bstr = SysAllocString(L"GET"); url = SysAllocString(L"http://test.winehq.org/tests/cors.html"); hres = IHTMLXDomainRequest_open(xdr, bstr, url); @@ -1207,6 +1211,10 @@ static void test_xdr(IHTMLDocument2 *doc) SysFreeString(bstr); SysFreeString(url); + hres = IHTMLXDomainRequest_get_contentType(xdr, &bstr); + ok(hres == S_OK, "get_contentType returned %08lx\n", hres); + ok(bstr == NULL, "contentType = %s\n", debugstr_w(bstr)); + hres = IHTMLXDomainRequest_get_timeout(xdr, NULL); ok(hres == E_INVALIDARG, "get_timeout returned %08lx\n", hres); hres = IHTMLXDomainRequest_get_timeout(xdr, &timeout); @@ -1235,6 +1243,11 @@ static void test_xdr(IHTMLDocument2 *doc) ok(!lstrcmpW(bstr, L"test\n"), "responseText = %s\n", debugstr_w(bstr)); SysFreeString(bstr); + hres = IHTMLXDomainRequest_get_contentType(xdr, &bstr); + ok(hres == S_OK, "get_contentType returned %08lx\n", hres); + ok(!lstrcmpW(bstr, L"text/html"), "contentType = %s\n", debugstr_w(bstr)); + SysFreeString(bstr); + IHTMLXDomainRequest_Release(xdr); } diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 9ecbd2aa62a..8a1d88c183d 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -1778,10 +1778,47 @@ static HRESULT WINAPI HTMLXDomainRequest_get_timeout(IHTMLXDomainRequest *iface, static HRESULT WINAPI HTMLXDomainRequest_get_contentType(IHTMLXDomainRequest *iface, BSTR *p) { HTMLXDomainRequest *This = impl_from_IHTMLXDomainRequest(iface); + nsAString nsstr; + nsresult nsres; + HRESULT hres; + UINT16 state; - FIXME("(%p)->(%p)\n", This, p); + TRACE("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + if(!p) + return E_POINTER; + + nsres = nsIXMLHttpRequest_GetReadyState(This->nsxhr, &state); + if(NS_FAILED(nsres) || state < 2) { + *p = NULL; + return S_OK; + } + + nsAString_InitDepend(&nsstr, NULL); + nsres = nsIXMLHttpRequest_GetResponseText(This->nsxhr, &nsstr); + if(NS_SUCCEEDED(nsres)) { + const PRUnichar *data; + char text[256 * 3]; + WCHAR *mime; + size_t len; + + nsAString_GetData(&nsstr, &data); + len = wcslen(data); + len = WideCharToMultiByte(CP_ACP, 0, data, min(len, 256), text, ARRAY_SIZE(text), NULL, NULL); + nsAString_Finish(&nsstr); + + if(len) { + hres = FindMimeFromData(NULL, NULL, text, len, NULL, 0, &mime, 0); + if(SUCCEEDED(hres)) { + *p = SysAllocString(mime); + CoTaskMemFree(mime); + return *p ? S_OK : E_OUTOFMEMORY; + } + } + } + + *p = SysAllocString(L"text/plain"); + return *p ? S_OK : E_OUTOFMEMORY; } static HRESULT WINAPI HTMLXDomainRequest_put_onprogress(IHTMLXDomainRequest *iface, VARIANT v) From e90358b5fee9583c487cdc1d6e8533c6c2bab340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:10 +0200 Subject: [PATCH 0953/2777] mshtml: Implement "arraybuffer" type response for XMLHttpRequest. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gabriel Ivăncescu --- dlls/jscript/arraybuf.c | 20 ++++++++++++++++++++ dlls/jscript/dispex.c | 1 + dlls/jscript/jscript.h | 2 ++ dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/xhr.js | 14 ++++++++++++++ dlls/mshtml/xmlhttprequest.c | 34 ++++++++++++++++++++++++++++++++-- 6 files changed, 70 insertions(+), 2 deletions(-) diff --git a/dlls/jscript/arraybuf.c b/dlls/jscript/arraybuf.c index 01d226fe675..2716359a1c4 100644 --- a/dlls/jscript/arraybuf.c +++ b/dlls/jscript/arraybuf.c @@ -1277,6 +1277,26 @@ static const builtin_info_t TypedArrayConstr_info = { NULL }; +static inline jsdisp_t *impl_from_IWineDispatchProxyCbPrivate(IWineDispatchProxyCbPrivate *iface) +{ + return CONTAINING_RECORD((IDispatchEx*)iface, jsdisp_t, IDispatchEx_iface); +} + +HRESULT WINAPI WineDispatchProxyCbPrivate_CreateArrayBuffer(IWineDispatchProxyCbPrivate *iface, DWORD size, IDispatch **arraybuf, void **data) +{ + jsdisp_t *This = impl_from_IWineDispatchProxyCbPrivate(iface); + jsdisp_t *obj; + HRESULT hres; + + hres = create_arraybuf(This->ctx, size, &obj); + if(FAILED(hres)) + return hres; + + *arraybuf = (IDispatch*)&obj->IDispatchEx_iface; + *data = arraybuf_from_jsdisp(obj)->buf; + return S_OK; +} + HRESULT WINAPI WineDispatchProxyCbPrivate_GetRandomValues(IDispatch *disp) { jsdisp_t *obj = to_jsdisp(disp); diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index 04b8ae36d2f..b7c03501240 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2759,6 +2759,7 @@ static IWineDispatchProxyCbPrivateVtbl WineDispatchProxyCbPrivateVtbl = { WineDispatchProxyCbPrivate_CreateConstructor, WineDispatchProxyCbPrivate_DefineConstructor, WineDispatchProxyCbPrivate_CreateObject, + WineDispatchProxyCbPrivate_CreateArrayBuffer, WineDispatchProxyCbPrivate_GetRandomValues, WineDispatchProxyCbPrivate_PropEnum }; diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h index 7da6ba8eeb7..0653f8d0968 100644 --- a/dlls/jscript/jscript.h +++ b/dlls/jscript/jscript.h @@ -107,6 +107,7 @@ typedef struct { IDispatch* (STDMETHODCALLTYPE *CreateConstructor)(IWineDispatchProxyCbPrivate *This, IDispatch *disp, const WCHAR *name); HRESULT (STDMETHODCALLTYPE *DefineConstructor)(IWineDispatchProxyCbPrivate *This, const WCHAR *name, IDispatch *prot, IDispatch *ctor); HRESULT (STDMETHODCALLTYPE *CreateObject)(IWineDispatchProxyCbPrivate *This, IDispatchEx **obj); + HRESULT (STDMETHODCALLTYPE *CreateArrayBuffer)(IWineDispatchProxyCbPrivate *This, DWORD size, IDispatch **arraybuf, void **data); HRESULT (STDMETHODCALLTYPE *GetRandomValues)(IDispatch *typedarr); HRESULT (STDMETHODCALLTYPE *PropEnum)(IWineDispatchProxyCbPrivate *This, const WCHAR *name); } IWineDispatchProxyCbPrivateVtbl; @@ -687,4 +688,5 @@ static inline void unlock_module(void) InterlockedDecrement(&module_ref); } +HRESULT WINAPI WineDispatchProxyCbPrivate_CreateArrayBuffer(IWineDispatchProxyCbPrivate*,DWORD,IDispatch**,void**) DECLSPEC_HIDDEN; HRESULT WINAPI WineDispatchProxyCbPrivate_GetRandomValues(IDispatch*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 62f3d52532c..ac99cb93dc6 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -100,6 +100,7 @@ typedef struct { IDispatch* (STDMETHODCALLTYPE *CreateConstructor)(IWineDispatchProxyCbPrivate *This, IDispatch *disp, const WCHAR *name); HRESULT (STDMETHODCALLTYPE *DefineConstructor)(IWineDispatchProxyCbPrivate *This, const WCHAR *name, IDispatch *prot, IDispatch *ctor); HRESULT (STDMETHODCALLTYPE *CreateObject)(IWineDispatchProxyCbPrivate *This, IDispatchEx **obj); + HRESULT (STDMETHODCALLTYPE *CreateArrayBuffer)(IWineDispatchProxyCbPrivate *This, DWORD size, IDispatch **arraybuf, void **data); HRESULT (STDMETHODCALLTYPE *GetRandomValues)(IDispatch *typedarr); HRESULT (STDMETHODCALLTYPE *PropEnum)(IWineDispatchProxyCbPrivate *This, const WCHAR *name); } IWineDispatchProxyCbPrivateVtbl; diff --git a/dlls/mshtml/tests/xhr.js b/dlls/mshtml/tests/xhr.js index 9ea202f28dd..2f00579d600 100644 --- a/dlls/mshtml/tests/xhr.js +++ b/dlls/mshtml/tests/xhr.js @@ -312,6 +312,20 @@ function test_response() { [ "arraybuffer", "image/png", function() { if(xhr.readyState < 4) ok(xhr.response === undefined, "response for arraybuffer with state " + state + " = " + xhr.response); + else { + var buf = xhr.response; + ok(buf instanceof ArrayBuffer, "response for arraybuffer not instanceof ArrayBuffer"); + ok(buf.byteLength === xml.length, "response for arraybuffer byteLength = " + buf.byteLength); + buf = new Uint8Array(buf); + for(var i = 0; i < buf.length; i++) { + if(buf[i] !== xml.charCodeAt(i)) { + var a = new Array(buf.length); + for(var j = 0; j < a.length; j++) a[j] = buf[j]; + ok(false, "response for arraybuffer is wrong (first bad char at pos " + i + "): " + a); + break; + } + } + } }], [ "blob", "wine/test", function() { if(xhr.readyState < 4) diff --git a/dlls/mshtml/xmlhttprequest.c b/dlls/mshtml/xmlhttprequest.c index 8a1d88c183d..24ff716b71c 100644 --- a/dlls/mshtml/xmlhttprequest.c +++ b/dlls/mshtml/xmlhttprequest.c @@ -142,6 +142,7 @@ struct HTMLXMLHttpRequest { LONG ref; document_type_t doctype_override; response_type_t response_type; + IDispatch *response_obj; HTMLInnerWindow *window; nsIXMLHttpRequest *nsxhr; XMLHttpReqEventListener *event_listener; @@ -349,6 +350,8 @@ static ULONG WINAPI HTMLXMLHttpRequest_Release(IHTMLXMLHttpRequest *iface) TRACE("(%p) ref=%ld\n", This, ref); if(!ref) { + if(This->response_obj) + IDispatch_Release(This->response_obj); if(This->event_listener) detach_xhr_event_listener(This->event_listener); IHTMLWindow2_Release(&This->window->base.IHTMLWindow2_iface); @@ -987,12 +990,22 @@ static HRESULT WINAPI HTMLXMLHttpRequest_private_Invoke(IWineXMLHttpRequestPriva static HRESULT WINAPI HTMLXMLHttpRequest_private_get_response(IWineXMLHttpRequestPrivate *iface, VARIANT *p) { HTMLXMLHttpRequest *This = impl_from_IWineXMLHttpRequestPrivate(iface); + IWineDispatchProxyCbPrivate *proxy; HRESULT hres = S_OK; + UINT32 buf_size; nsresult nsres; UINT16 state; + void *buf; TRACE("(%p)->(%p)\n", This, p); + if(This->response_obj) { + V_VT(p) = VT_DISPATCH; + V_DISPATCH(p) = This->response_obj; + IDispatch_AddRef(This->response_obj); + return S_OK; + } + switch(This->response_type) { case response_type_empty: case response_type_text: @@ -1012,10 +1025,22 @@ static HRESULT WINAPI HTMLXMLHttpRequest_private_get_response(IWineXMLHttpReques V_VT(p) = VT_EMPTY; break; } - if(This->response_type == response_type_arraybuf) { - FIXME("response_type_arraybuf\n"); + if(!(proxy = This->event_target.dispex.proxy)) { + FIXME("No proxy\n"); return E_NOTIMPL; } + nsres = nsIXMLHttpRequest_GetResponseBuffer(This->nsxhr, NULL, 0, &buf_size); + assert(nsres == NS_OK); + + if(This->response_type == response_type_arraybuf) { + hres = proxy->lpVtbl->CreateArrayBuffer(proxy, buf_size, &This->response_obj, &buf); + if(SUCCEEDED(hres)) { + nsres = nsIXMLHttpRequest_GetResponseBuffer(This->nsxhr, buf, buf_size, &buf_size); + assert(nsres == NS_OK); + } + break; + } + FIXME("response_type_blob\n"); return E_NOTIMPL; @@ -1027,6 +1052,11 @@ static HRESULT WINAPI HTMLXMLHttpRequest_private_get_response(IWineXMLHttpReques assert(0); } + if(SUCCEEDED(hres) && This->response_obj) { + V_VT(p) = VT_DISPATCH; + V_DISPATCH(p) = This->response_obj; + IDispatch_AddRef(This->response_obj); + } return hres; } From b11966c4c60656cff21a3b1104b294fd793141bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Wed, 4 Jan 2023 22:13:11 +0200 Subject: [PATCH 0954/2777] mshtml HACK: Fix refcount crash for XML documents. --- dlls/mshtml/omnavigator.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/omnavigator.c b/dlls/mshtml/omnavigator.c index 0be8542763b..5c59af572b8 100644 --- a/dlls/mshtml/omnavigator.c +++ b/dlls/mshtml/omnavigator.c @@ -549,7 +549,8 @@ static HRESULT WINAPI DOMParser_parseFromString(IDOMParser *iface, BSTR string, } hres = create_document_node(nsdoc, This->doc->browser, NULL, doc_type, This->doc->document_mode, &xml_doc); - nsIDOMDocument_Release(nsdoc); + /* FIXME HACK: in FFXIV launcher, cycle collector crashes due to some bad refcount somewhere (gecko bug?) */ + /* nsIDOMDocument_Release(nsdoc); */ if(FAILED(hres)) return hres; From 0f7c85d419c550e839650fe992e51c671b6676f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= Date: Mon, 9 Jan 2023 17:15:18 +0200 Subject: [PATCH 0955/2777] mshtml: Use Scrollbar_Auto as default for vertical scrollbars. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While Internet Explorer 6 used to default to "always", this hasn't been the case for a long while now. Signed-off-by: Gabriel Ivăncescu --- dlls/mshtml/nsembed.c | 2 +- dlls/mshtml/oleobj.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/mshtml/nsembed.c b/dlls/mshtml/nsembed.c index 8f504a7cac9..af4b42000e3 100644 --- a/dlls/mshtml/nsembed.c +++ b/dlls/mshtml/nsembed.c @@ -2270,7 +2270,7 @@ static HRESULT init_browser(GeckoBrowser *browser) nsres = nsIWebBrowser_QueryInterface(browser->webbrowser, &IID_nsIScrollable, (void**)&scrollable); if(NS_SUCCEEDED(nsres)) { nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable, - ScrollOrientation_Y, Scrollbar_Always); + ScrollOrientation_Y, Scrollbar_Auto); if(NS_FAILED(nsres)) ERR("Could not set default Y scrollbar prefs: %08lx\n", nsres); diff --git a/dlls/mshtml/oleobj.c b/dlls/mshtml/oleobj.c index 6167dbdde74..d0595e93fe2 100644 --- a/dlls/mshtml/oleobj.c +++ b/dlls/mshtml/oleobj.c @@ -363,7 +363,7 @@ static void update_hostinfo(HTMLDocumentObj *This, DOCHOSTUIINFO *hostinfo) nsres = nsIWebBrowser_QueryInterface(This->nscontainer->webbrowser, &IID_nsIScrollable, (void**)&scrollable); if(NS_SUCCEEDED(nsres)) { nsres = nsIScrollable_SetDefaultScrollbarPreferences(scrollable, ScrollOrientation_Y, - (hostinfo->dwFlags & DOCHOSTUIFLAG_SCROLL_NO) ? Scrollbar_Never : Scrollbar_Always); + (hostinfo->dwFlags & DOCHOSTUIFLAG_SCROLL_NO) ? Scrollbar_Never : Scrollbar_Auto); if(NS_FAILED(nsres)) ERR("Could not set default Y scrollbar prefs: %08lx\n", nsres); From 10979c67b73c3f7e479f57f4e59a2a0101046976 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 7 Jan 2022 23:54:20 +0300 Subject: [PATCH 0956/2777] mshtml: Also call before_async_open() for iframe in nsChannel_AsyncOpen(). CW-Bug-Id: #19930 --- dlls/ieframe/tests/webbrowser.c | 144 +++++++++++++++++++++++++++----- dlls/mshtml/nsio.c | 65 ++++++++++++++ 2 files changed, 188 insertions(+), 21 deletions(-) diff --git a/dlls/ieframe/tests/webbrowser.c b/dlls/ieframe/tests/webbrowser.c index 584da6e9022..45df603e003 100644 --- a/dlls/ieframe/tests/webbrowser.c +++ b/dlls/ieframe/tests/webbrowser.c @@ -172,6 +172,7 @@ static HRESULT hr_site_TranslateAccelerator = E_NOTIMPL; static const WCHAR *current_url; static int wb_version, expect_update_commands_enable, set_update_commands_enable; static BOOL nav_back_todo, nav_forward_todo; /* FIXME */ +static BOOL navigation_cancelled; enum SessionOp { @@ -191,6 +192,8 @@ static LONG (WINAPI *pSetQueryNetSessionCount)(DWORD); #define DWL_HTTP 0x10 #define DWL_REFRESH 0x20 #define DWL_BACK_ENABLE 0x40 +#define DWL_IFRAME_NAV_CANCEL 0x80 +#define DWL_FROM_IFRAME_NAV_CANCEL 0x100 static DWORD dwl_flags; @@ -290,6 +293,8 @@ static void _test_ready_state(unsigned line, READYSTATE exstate, VARIANT_BOOL ex hres = IWebBrowser2_get_Busy(wb, &busy); if(expect_busy != BUSY_FAIL) { ok_(__FILE__,line)(hres == S_OK, "get_ReadyState failed: %08lx\n", hres); + todo_wine_if(dwl_flags & DWL_FROM_IFRAME_NAV_CANCEL && state == READYSTATE_LOADING + && busy != expect_busy) ok_(__FILE__,line)(busy == expect_busy, "Busy = %x, expected %x for ready state %d\n", busy, expect_busy, state); }else { @@ -415,13 +420,13 @@ static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID ok(nCmdexecopt == OLECMDEXECOPT_DONTPROMPTUSER || !nCmdexecopt, "nCmdexecopts=%08lx\n", nCmdexecopt); else - ok(!nCmdexecopt, "nCmdexecopts=%08lx\n", nCmdexecopt); + todo_wine_if(dwl_flags & DWL_IFRAME_NAV_CANCEL) ok(!nCmdexecopt, "nCmdexecopts=%08lx\n", nCmdexecopt); ok(pvaOut == NULL, "pvaOut=%p\n", pvaOut); ok(pvaIn != NULL, "pvaIn == NULL\n"); ok(V_VT(pvaIn) == VT_I4, "V_VT(pvaIn)=%d\n", V_VT(pvaIn)); switch(V_I4(pvaIn)) { case 0: - CHECK_EXPECT2(Exec_SETDOWNLOADSTATE_0); + todo_wine_if(dwl_flags & DWL_IFRAME_NAV_CANCEL) CHECK_EXPECT2(Exec_SETDOWNLOADSTATE_0); break; case 1: CHECK_EXPECT2(Exec_SETDOWNLOADSTATE_1); @@ -480,6 +485,7 @@ static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID }else if(IsEqualGUID(&CGID_ShellDocView, pguidCmdGroup)) { switch(nCmdID) { case 63: /* win10 */ + case 65: case 105: /* TODO */ case 132: /* win10 */ case 133: /* IE11 */ @@ -719,11 +725,11 @@ static void _test_invoke_bool(unsigned line, const DISPPARAMS *params, BOOL stri static void test_OnBeforeNavigate(const VARIANT *disp, const VARIANT *url, const VARIANT *flags, const VARIANT *frame, const VARIANT *post_data, const VARIANT *headers, const VARIANT *cancel) { + BOOL cancel_nav = FALSE; BSTR str; ok(V_VT(disp) == VT_DISPATCH, "V_VT(disp)=%d, expected VT_DISPATCH\n", V_VT(disp)); ok(V_DISPATCH(disp) != NULL, "V_DISPATCH(disp) == NULL\n"); - ok(V_DISPATCH(disp) == (IDispatch*)wb, "V_DISPATCH(disp)=%p, wb=%p\n", V_DISPATCH(disp), wb); ok(V_VT(url) == (VT_BYREF|VT_VARIANT), "V_VT(url)=%x, expected VT_BYREF|VT_VARIANT\n", V_VT(url)); ok(V_VARIANTREF(url) != NULL, "V_VARIANTREF(url) == NULL)\n"); @@ -731,10 +737,21 @@ static void test_OnBeforeNavigate(const VARIANT *disp, const VARIANT *url, const ok(V_VT(V_VARIANTREF(url)) == VT_BSTR, "V_VT(V_VARIANTREF(url))=%d, expected VT_BSTR\n", V_VT(V_VARIANTREF(url))); ok(V_BSTR(V_VARIANTREF(url)) != NULL, "V_BSTR(V_VARIANTREF(url)) == NULL\n"); - ok(!lstrcmpW(V_BSTR(V_VARIANTREF(url)), current_url), "unexpected url %s, expected %s\n", - wine_dbgstr_w(V_BSTR(V_VARIANTREF(url))), wine_dbgstr_w(current_url)); + if (!wcscmp(V_BSTR(V_VARIANTREF(url)), L"invalid:///")) + cancel_nav = TRUE; + if (!(dwl_flags & DWL_IFRAME_NAV_CANCEL && cancel_nav)) + ok(!lstrcmpW(V_BSTR(V_VARIANTREF(url)), current_url), "unexpected url %s, expected %s\n", + wine_dbgstr_w(V_BSTR(V_VARIANTREF(url))), wine_dbgstr_w(current_url)); } + if (dwl_flags & DWL_IFRAME_NAV_CANCEL && cancel_nav) + { + ok(!!V_DISPATCH(disp), "Got NULL disp.\n"); + todo_wine ok(V_DISPATCH(disp) != (IDispatch*)wb, "Got the same browser.\n"); + } + else + ok(V_DISPATCH(disp) == (IDispatch*)wb, "V_DISPATCH(disp)=%p, wb=%p\n", V_DISPATCH(disp), wb); + ok(V_VT(flags) == (VT_BYREF|VT_VARIANT), "V_VT(flags)=%x, expected VT_BYREF|VT_VARIANT\n", V_VT(flags)); ok(V_VT(flags) == (VT_BYREF|VT_VARIANT), "V_VT(flags)=%x, expected VT_BYREF|VT_VARIANT\n", @@ -805,8 +822,15 @@ static void test_OnBeforeNavigate(const VARIANT *disp, const VARIANT *url, const V_VT(cancel)); ok(V_BOOLREF(cancel) != NULL, "V_BOOLREF(pDispParams->rgvarg[0] == NULL)\n"); if(V_BOOLREF(cancel)) + { ok(*V_BOOLREF(cancel) == VARIANT_FALSE, "*V_BOOLREF(cancel) = %x, expected VARIANT_FALSE\n", *V_BOOLREF(cancel)); + if (cancel_nav) + { + *V_BOOLREF(cancel) = TRUE; + navigation_cancelled = TRUE; + } + } } static void test_navigatecomplete2(DISPPARAMS *dp) @@ -821,6 +845,7 @@ static void test_navigatecomplete2(DISPPARAMS *dp) ok(V_VT(dp->rgvarg) == (VT_BYREF|VT_VARIANT), "V_VT(dp->rgvarg) = %d\n", V_VT(dp->rgvarg)); v = V_VARIANTREF(dp->rgvarg); ok(V_VT(v) == VT_BSTR, "V_VT(url) = %d\n", V_VT(v)); + todo_wine_if(!memcmp(V_BSTR(v), L"file:", 10)) ok(!lstrcmpW(V_BSTR(v), current_url), "url=%s, expected %s\n", wine_dbgstr_w(V_BSTR(v)), wine_dbgstr_w(current_url)); @@ -845,6 +870,8 @@ static void test_documentcomplete(DISPPARAMS *dp) ok(V_VT(dp->rgvarg) == (VT_BYREF|VT_VARIANT), "V_VT(dp->rgvarg) = %d\n", V_VT(dp->rgvarg)); v = V_VARIANTREF(dp->rgvarg); ok(V_VT(v) == VT_BSTR, "V_VT(url) = %d\n", V_VT(v)); + + todo_wine_if(!memcmp(V_BSTR(v), L"file:", 10)) ok(!lstrcmpW(V_BSTR(v), current_url), "url=%s, expected %s\n", wine_dbgstr_w(V_BSTR(v)), wine_dbgstr_w(current_url)); @@ -907,9 +934,19 @@ static HRESULT WINAPI WebBrowserEvents2_Invoke(IDispatch *iface, DISPID dispIdMe pDispParams->rgvarg+3, pDispParams->rgvarg+2, pDispParams->rgvarg+1, pDispParams->rgvarg); if(dwl_flags & (DWL_FROM_PUT_HREF|DWL_FROM_GOFORWARD)) + { test_ready_state(READYSTATE_COMPLETE, VARIANT_FALSE); + } + else if (dwl_flags & DWL_IFRAME_NAV_CANCEL) + { + test_ready_state(READYSTATE_LOADING, navigation_cancelled ? VARIANT_TRUE : VARIANT_FALSE); + if (!navigation_cancelled) + SET_EXPECT(Invoke_BEFORENAVIGATE2); + } else - test_ready_state(READYSTATE_LOADING, VARIANT_FALSE); + { + test_ready_state(READYSTATE_LOADING, dwl_flags & DWL_FROM_IFRAME_NAV_CANCEL ? VARIANT_TRUE : VARIANT_FALSE); + } break; case DISPID_SETSECURELOCKICON: @@ -948,7 +985,7 @@ static HRESULT WINAPI WebBrowserEvents2_Invoke(IDispatch *iface, DISPID dispIdMe CHECK_EXPECT2(Invoke_COMMANDSTATECHANGE_NAVIGATEFORWARD_FALSE); } } - else if (V_I4(pDispParams->rgvarg+1) == CSC_NAVIGATEBACK) + else if (V_I4(pDispParams->rgvarg+1) == CSC_NAVIGATEBACK && !(dwl_flags & DWL_FROM_IFRAME_NAV_CANCEL)) { todo_wine_if(nav_back_todo) { if(V_BOOL(pDispParams->rgvarg)) @@ -1681,6 +1718,8 @@ static HRESULT WINAPI DocHostUIHandler_TranslateUrl(IDocHostUIHandler2 *iface, D { todo_wine_if(is_downloading && !(dwl_flags & DWL_EXPECT_BEFORE_NAVIGATE)) CHECK_EXPECT(TranslateUrl); + if (dwl_flags & DWL_IFRAME_NAV_CANCEL && wcscmp(pchURLIn, L"invalid:///")) + SET_EXPECT(TranslateUrl); return E_NOTIMPL; } @@ -2814,12 +2853,16 @@ static void test_ConnectionPoint(IWebBrowser2 *unk, BOOL init) static void test_Navigate2(IWebBrowser2 *webbrowser, const WCHAR *nav_url) { const WCHAR *title = L"WineHQ - Run Windows applications on Linux, BSD, Solaris and Mac OS X"; + const WCHAR *file_title = L"wine_test"; VARIANT url; BOOL is_file; HRESULT hres; test_LocationURL(webbrowser, is_first_load ? L"" : current_url); - test_LocationName(webbrowser, is_first_load ? L"" : (is_http ? title : current_url)); + if (current_url && !memcmp(current_url, L"file:", 10)) + test_LocationName(webbrowser, file_title); + else + test_LocationName(webbrowser, is_first_load ? L"" : (is_http ? title : current_url)); test_ready_state(is_first_load ? READYSTATE_UNINITIALIZED : READYSTATE_COMPLETE, VARIANT_FALSE); is_http = !memcmp(nav_url, "http:", 5); @@ -2990,6 +3033,8 @@ static void test_download(DWORD flags) BOOL *b = &called_Invoke_DOCUMENTCOMPLETE; MSG msg; + navigation_cancelled = FALSE; + if(flags & DWL_REFRESH) b = use_container_olecmd ? &called_Exec_SETDOWNLOADSTATE_0 : &called_Invoke_DOWNLOADCOMPLETE; else if((flags & DWL_FROM_PUT_HREF) && !use_container_olecmd && 0) @@ -3001,8 +3046,9 @@ static void test_download(DWORD flags) if(flags & (DWL_FROM_PUT_HREF|DWL_FROM_GOBACK|DWL_FROM_GOFORWARD|DWL_REFRESH)) test_ready_state(READYSTATE_COMPLETE, VARIANT_FALSE); else - test_ready_state(READYSTATE_LOADING, VARIANT_FALSE); - + { + test_ready_state(READYSTATE_LOADING, flags & DWL_FROM_IFRAME_NAV_CANCEL ? VARIANT_TRUE : VARIANT_FALSE); + } if(flags & (DWL_EXPECT_BEFORE_NAVIGATE|(is_http ? DWL_FROM_PUT_HREF : 0)|DWL_FROM_GOFORWARD|DWL_REFRESH)) SET_EXPECT(Invoke_PROPERTYCHANGE); @@ -3065,7 +3111,7 @@ static void test_download(DWORD flags) SET_EXPECT(GetOverridesKeyPath); /* Called randomly on some VMs. */ trace("Downloading...\n"); - while(!*b && GetMessageW(&msg, NULL, 0, 0)) { + while(!navigation_cancelled && !*b && GetMessageW(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessageW(&msg); } @@ -3096,11 +3142,14 @@ static void test_download(DWORD flags) CLEAR_CALLED(EnableModeless_FALSE); /* IE 8 */ if(!(flags & DWL_REFRESH)) { - todo_wine_if(nav_back_todo) { - if(flags & (DWL_FROM_GOFORWARD|DWL_BACK_ENABLE)) - CHECK_CALLED(Invoke_COMMANDSTATECHANGE_NAVIGATEBACK_TRUE); - else - CHECK_CALLED(Invoke_COMMANDSTATECHANGE_NAVIGATEBACK_FALSE); + if (!(flags & DWL_FROM_IFRAME_NAV_CANCEL)) + { + todo_wine_if(nav_back_todo) { + if(flags & (DWL_FROM_GOFORWARD|DWL_BACK_ENABLE)) + CHECK_CALLED(Invoke_COMMANDSTATECHANGE_NAVIGATEBACK_TRUE); + else + CHECK_CALLED(Invoke_COMMANDSTATECHANGE_NAVIGATEBACK_FALSE); + } } if(flags & DWL_FROM_GOBACK) CHECK_CALLED(Invoke_COMMANDSTATECHANGE_NAVIGATEFORWARD_TRUE); @@ -3117,20 +3166,26 @@ static void test_download(DWORD flags) if(!is_first_load) todo_wine CHECK_CALLED(GetHostInfo); if(use_container_olecmd) - CHECK_CALLED(Exec_SETDOWNLOADSTATE_0); + todo_wine_if(flags & DWL_IFRAME_NAV_CANCEL) CHECK_CALLED(Exec_SETDOWNLOADSTATE_0); else - CHECK_CALLED(Invoke_DOWNLOADCOMPLETE); + todo_wine_if(flags & DWL_IFRAME_NAV_CANCEL) CHECK_CALLED(Invoke_DOWNLOADCOMPLETE); todo_wine CHECK_CALLED(Invoke_TITLECHANGE); if(!(flags & DWL_REFRESH)) CHECK_CALLED(Invoke_NAVIGATECOMPLETE2); if(is_first_load) todo_wine CHECK_CALLED(GetDropTarget); - if(!(flags & DWL_REFRESH)) + if(!(flags & (DWL_REFRESH | DWL_IFRAME_NAV_CANCEL))) CHECK_CALLED(Invoke_DOCUMENTCOMPLETE); is_downloading = FALSE; - test_ready_state(READYSTATE_COMPLETE, VARIANT_FALSE); + if (flags & DWL_IFRAME_NAV_CANCEL) + { + test_ready_state(READYSTATE_INTERACTIVE, VARIANT_TRUE); + SET_EXPECT(Invoke_TITLECHANGE); + } + else + test_ready_state(READYSTATE_COMPLETE, VARIANT_FALSE); while(use_container_olecmd && !called_Exec_UPDATECOMMANDS && GetMessageA(&msg, NULL, 0, 0)) { TranslateMessage(&msg); @@ -3840,6 +3895,51 @@ static void init_test(IWebBrowser2 *webbrowser, DWORD flags) use_container_dochostui = !(flags & TEST_NODOCHOST); } +static const char iframe_doc_str[] = + ""; + +static void test_iframe_load(IWebBrowser2 *webbrowser) +{ + WCHAR file_path[MAX_PATH]; + WCHAR file_url[MAX_PATH]; + HRESULT hres; + HANDLE file; + VARIANT url; + DWORD size; + BOOL bret; + + GetTempPathW(MAX_PATH, file_path); + lstrcatW(file_path, L"wine_ifr_test.html"); + + file = CreateFileW(file_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed, error %u.\n", GetLastError()); + if(file == INVALID_HANDLE_VALUE && GetLastError() != ERROR_FILE_EXISTS){ + ok(0, "CreateFile failed\n"); + return; + } + WriteFile(file, iframe_doc_str, strlen(iframe_doc_str), &size, NULL); + CloseHandle(file); + + GetLongPathNameW(file_path, file_path, ARRAY_SIZE(file_path)); + lstrcpyW(file_url, L"file://"); + lstrcatW(file_url, file_path); + + trace("iframe load...\n"); + test_Navigate2(webbrowser, file_url); + test_download(DWL_EXPECT_BEFORE_NAVIGATE|DWL_IFRAME_NAV_CANCEL|DWL_BACK_ENABLE); + + V_VT(&url) = VT_BSTR; + V_BSTR(&url) = SysAllocString(current_url = L"about:blank"); + hres = IWebBrowser2_Navigate2(webbrowser, &url, NULL, NULL, NULL, NULL); + ok(hres == S_OK, "Navigate2 failed: %08x\n", hres); + VariantClear(&url); + + test_download(DWL_EXPECT_BEFORE_NAVIGATE|DWL_FROM_IFRAME_NAV_CANCEL); + + bret = DeleteFileW(file_path); + ok(bret, "DeleteFileW failed, err %u.\n", GetLastError()); +} + static void test_WebBrowser(DWORD flags, BOOL do_close) { IWebBrowser2 *webbrowser; @@ -3868,6 +3968,7 @@ static void test_WebBrowser(DWORD flags, BOOL do_close) test_LocationURL(webbrowser, L""); test_ConnectionPoint(webbrowser, TRUE); + test_ClientSite(webbrowser, &ClientSite, !do_download); test_Extent(webbrowser); test_wb_funcs(webbrowser, TRUE); @@ -3934,6 +4035,8 @@ static void test_WebBrowser(DWORD flags, BOOL do_close) trace("GoForward...\n"); test_go_forward(webbrowser, L"http://test.winehq.org/tests/winehq_snapshot/", -1, 0); test_download(DWL_FROM_GOFORWARD|DWL_HTTP); + if (!(flags & TEST_NOOLECMD)) + test_iframe_load(webbrowser); }else { trace("Navigate2 repeated with the same URL...\n"); test_Navigate2(webbrowser, L"about:blank"); @@ -3942,7 +4045,6 @@ static void test_WebBrowser(DWORD flags, BOOL do_close) test_EnumVerbs(webbrowser); test_TranslateAccelerator(webbrowser); - test_dochost_qs(webbrowser); }else { test_ExecWB(webbrowser, TRUE); diff --git a/dlls/mshtml/nsio.c b/dlls/mshtml/nsio.c index 612d91ed386..8b730995763 100644 --- a/dlls/mshtml/nsio.c +++ b/dlls/mshtml/nsio.c @@ -280,6 +280,50 @@ static nsresult before_async_open(nsChannel *channel, GeckoBrowser *container, B return NS_OK; } +static nsresult fire_before_navigate(nsChannel *channel, HTMLOuterWindow *window, BOOL *cancel) +{ + BSTR frame_name = NULL; + OLECHAR *new_url; + BSTR uri_str; + HRESULT hres; + + hres = IUri_GetDisplayUri(channel->uri->uri, &uri_str); + if(FAILED(hres)) + { + ERR("IUri_GetDisplayUri failed, hres %#lx.\n", hres); + return NS_ERROR_FAILURE; + } + if(window->browser->doc->hostui) + { + hres = IDocHostUIHandler_TranslateUrl(window->browser->doc->hostui, 0, uri_str, &new_url); + if(hres == S_OK && new_url) + { + if(wcscmp(uri_str, new_url)) + { + FIXME("TranslateUrl returned new URL %s -> %s.\n", debugstr_w(uri_str), debugstr_w(new_url)); + CoTaskMemFree(new_url); + *cancel = TRUE; + SysFreeString(uri_str); + return NS_OK; + } + CoTaskMemFree(new_url); + } + } + + hres = IHTMLWindow2_get_name(&window->base.IHTMLWindow2_iface, &frame_name); + if (FAILED(hres)) + { + SysFreeString(uri_str); + return NS_ERROR_FAILURE; + } + + hres = IDocObjectService_FireBeforeNavigate2(window->browser->doc->doc_object_service, NULL, uri_str, 0x40, + frame_name, NULL, 0, NULL, TRUE, cancel); + SysFreeString(frame_name); + SysFreeString(uri_str); + return SUCCEEDED(hres) ? NS_OK : NS_ERROR_FAILURE; +} + HRESULT load_nsuri(HTMLOuterWindow *window, nsWineURI *uri, nsIInputStream *post_stream, nsChannelBSC *channelbsc, DWORD flags) { @@ -1093,6 +1137,27 @@ static nsresult NSAPI nsChannel_AsyncOpen(nsIHttpChannel *iface, nsIStreamListen This->content_type = strdupWtoA(window->browser->doc->mime); } } + else if (window->browser && window->frame_element && window->browser->doc + && window->browser->doc->doc_object_service) + { + IUnknown *unk; + if (SUCCEEDED(IHTMLFrameBase_QueryInterface(&window->frame_element->IHTMLFrameBase_iface, + &IID_IHTMLIFrameElement, (void **)&unk))) + { + IUnknown_Release(unk); + nsres = fire_before_navigate(This, window, &cancel); + if(NS_SUCCEEDED(nsres) && cancel) + { + TRACE("canceled.\n"); + nsres = NS_BINDING_ABORTED; + } + else + { + FIXME("fire_before_navigate returned error %#lx.\n", nsres); + nsres = NS_OK; + } + } + } } if(!cancel) From 08735384c85c13856e8379a98904ef701acca335 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Thu, 13 Dec 2012 14:05:03 +0100 Subject: [PATCH 0957/2777] HACK: Create HTMLDocument in dedicated thread to work around Gecko threading limitation. CW-Bug-Id: 18848 --- dlls/actxprxy/Makefile.in | 1 + dlls/actxprxy/actxprxy_mshtml.idl | 35 ++++++++++++ dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/oleobj.c | 89 +++++++++++++++++++++++++++++++ dlls/mshtml/task.c | 51 ++++++++++++++++++ include/docobjectservice.idl | 14 ++--- include/mshtmhst.idl | 6 +-- include/mshtml.idl | 18 +++++-- include/shdeprecated.idl | 4 +- 9 files changed, 203 insertions(+), 16 deletions(-) create mode 100644 dlls/actxprxy/actxprxy_mshtml.idl diff --git a/dlls/actxprxy/Makefile.in b/dlls/actxprxy/Makefile.in index a4618bd560f..8967862350e 100644 --- a/dlls/actxprxy/Makefile.in +++ b/dlls/actxprxy/Makefile.in @@ -11,6 +11,7 @@ IDL_SRCS = \ actxprxy_hlink.idl \ actxprxy_htiface.idl \ actxprxy_htiframe.idl \ + actxprxy_mshtml.idl \ actxprxy_objsafe.idl \ actxprxy_ocmm.idl \ actxprxy_servprov.idl \ diff --git a/dlls/actxprxy/actxprxy_mshtml.idl b/dlls/actxprxy/actxprxy_mshtml.idl new file mode 100644 index 00000000000..6f4a7ca9fd0 --- /dev/null +++ b/dlls/actxprxy/actxprxy_mshtml.idl @@ -0,0 +1,35 @@ +/* + * Copyright 2009 Alexandre Julliard + * + * 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 + */ + +/* just a wrapper for mshtmhst.idl */ + +#pragma makedep proxy +#pragma makedep register + +#define NO_MSHTML_IMPORT + +#include "mshtml.idl" +#include "mshtmhst.idl" +#include "shdeprecated.idl" +#include "docobjectservice.idl" + +[ + threading(both), + uuid(b8da6310-e19b-11d0-933c-00a0c90dcaa9) /* IActiveScriptStats */ +] +coclass PSFactoryBuffer { interface IFactoryBuffer; } diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index ac99cb93dc6..4984353eaf3 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -1229,6 +1229,7 @@ HRESULT HTMLLoadOptions_Create(IUnknown*,REFIID,void**) DECLSPEC_HIDDEN; HRESULT create_document_node(nsIDOMDocument*,GeckoBrowser*,HTMLInnerWindow*, document_type_t,compat_mode_t,HTMLDocumentNode**) DECLSPEC_HIDDEN; HRESULT create_doctype_node(HTMLDocumentNode*,nsIDOMNode*,HTMLDOMNode**) DECLSPEC_HIDDEN; +HRESULT create_marshaled_doc(HWND,REFIID,void**) DECLSPEC_HIDDEN; HRESULT create_outer_window(GeckoBrowser*,mozIDOMWindowProxy*,HTMLOuterWindow*,HTMLOuterWindow**) DECLSPEC_HIDDEN; void set_window_uninitialized(HTMLOuterWindow*,HTMLDocumentNode*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/oleobj.c b/dlls/mshtml/oleobj.c index d0595e93fe2..44d6748c73b 100644 --- a/dlls/mshtml/oleobj.c +++ b/dlls/mshtml/oleobj.c @@ -3644,16 +3644,105 @@ static const cpc_entry_t HTMLDocumentObj_cpc[] = { {NULL} }; + + +/* TRUE if we create a dedicated thread for all HTML documents */ +static BOOL gecko_main_thread_config; + +static LONG gecko_main_thread; +static HWND gecko_main_thread_hwnd; +static HANDLE gecko_main_thread_event; + +static DWORD WINAPI gecko_main_thread_proc(void *arg) +{ + MSG msg; + + TRACE("\n"); + + CoInitialize(NULL); + + gecko_main_thread_hwnd = get_thread_hwnd(); + if(!gecko_main_thread_hwnd) { + ERR("Could not create thread window\n"); + SetEvent(gecko_main_thread_event); + CoUninitialize(); + return 0; + } + + gecko_main_thread = GetCurrentThreadId(); + SetEvent(gecko_main_thread_event); + + while(GetMessageW(&msg, NULL, 0, 0)) { + DispatchMessageW(&msg); + TranslateMessage(&msg); + } + + CoUninitialize(); + return 0; +} + +static BOOL WINAPI read_thread_config(INIT_ONCE *once, void *param, void **context) +{ + HKEY key; + DWORD res; + static const WCHAR enable_keyW[] = + {'S','o','f','t','w','a','r','e', + '\\','W','i','n','e', + '\\','M','S','H','T','M','L', + '\\','M','a','i','n','T','h','r','e','a','d','H','a','c','k',0}; + + res = RegOpenKeyW(HKEY_CURRENT_USER, enable_keyW, &key); + if(res == ERROR_SUCCESS) { + RegCloseKey(key); + FIXME("CXHACK: Using separated main thread.\n"); + gecko_main_thread_config = TRUE; + } + + return TRUE; +} + static HRESULT create_document_object(BOOL is_mhtml, IUnknown *outer, REFIID riid, void **ppv) { HTMLDocumentObj *doc; HRESULT hres; + static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; + if(outer && !IsEqualGUID(&IID_IUnknown, riid)) { *ppv = NULL; return E_INVALIDARG; } + /* CXHACK 15579 */ + InitOnceExecuteOnce(&init_once, read_thread_config, NULL, NULL); + if(gecko_main_thread_config && !gecko_main_thread) { + HANDLE thread, event; + + event = CreateEventW(NULL, TRUE, FALSE, NULL); + if(InterlockedCompareExchangePointer(&gecko_main_thread_event, event, NULL)) + CloseHandle(event); + + thread = CreateThread(NULL, 0, gecko_main_thread_proc, NULL, 0, NULL); + if(thread) { + WaitForSingleObject(gecko_main_thread_event, INFINITE); + CloseHandle(thread); + }else { + ERR("Could not create a thread\n"); + } + } + + if(!gecko_main_thread) { + gecko_main_thread = GetCurrentThreadId(); + gecko_main_thread_hwnd = get_thread_hwnd(); + }else if(GetCurrentThreadId() != gecko_main_thread) { + FIXME("CXHACK: Creating HTMLDocument outside Gecko main thread\n"); + if(!gecko_main_thread_config) { + FIXME("CXHACK: Dedicated main thread not configured\n"); + FIXME("CXHACK: Create HKCU\\Software\\Wine\\MSHTML\\MainThreadHack key\n"); + } + return create_marshaled_doc(gecko_main_thread_hwnd, riid, ppv); + } + /* ensure that security manager is initialized */ if(!get_security_manager()) return E_OUTOFMEMORY; diff --git a/dlls/mshtml/task.c b/dlls/mshtml/task.c index 2987b4bf19d..7d7af09a385 100644 --- a/dlls/mshtml/task.c +++ b/dlls/mshtml/task.c @@ -33,6 +33,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); #define WM_PROCESSTASK 0x8008 +#define WM_CREATEDOC 0x8018 #define TIMER_ID 0x3000 typedef struct { @@ -330,6 +331,13 @@ static LRESULT process_timer(void) return 0; } +typedef struct { + IUnknown *unk; + IID iid; + IStream *stream; + HRESULT hres; +} create_doc_params_t; + static LRESULT WINAPI hidden_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { @@ -346,6 +354,20 @@ static LRESULT WINAPI hidden_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPa return 0; case WM_TIMER: return process_timer(); + case WM_CREATEDOC: { + create_doc_params_t *params = (create_doc_params_t*)lParam; + IUnknown *unk; + + TRACE("WM_CREATEDOC %p\n", params); + + params->hres = HTMLDocument_Create(NULL, ¶ms->iid, (void**)&unk); + if(FAILED(params->hres)) + return 0; + + params->hres = CoMarshalInterface(params->stream, ¶ms->iid, unk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + IUnknown_Release(unk); + return 0; + } } if(msg > WM_USER) @@ -388,6 +410,35 @@ HWND get_thread_hwnd(void) return thread_data->thread_hwnd; } +HRESULT create_marshaled_doc(HWND main_thread_hwnd, REFIID riid, void **ppv) +{ + create_doc_params_t params = {NULL, *riid, NULL, E_FAIL}; + LARGE_INTEGER zero; + BOOL res; + HRESULT hres; + + hres = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream); + if(FAILED(hres)) + return hres; + + res = SendMessageW(main_thread_hwnd, WM_CREATEDOC, 0, (LPARAM)¶ms); + TRACE("SendMessage ret %x\n", res); + if(FAILED(params.hres)) { + WARN("EM_CREATEDOC failed: %08lx\n", params.hres); + IStream_Release(params.stream); + return hres; + } + + zero.QuadPart = 0; + hres = IStream_Seek(params.stream, zero, STREAM_SEEK_SET, NULL); + if(SUCCEEDED(hres)) + hres = CoUnmarshalInterface(params.stream, riid, ppv); + IStream_Release(params.stream); + if(FAILED(hres)) + WARN("CoUnmarshalInterface failed: %08lx\n", hres); + return hres; +} + thread_data_t *get_thread_data(BOOL create) { thread_data_t *thread_data; diff --git a/include/docobjectservice.idl b/include/docobjectservice.idl index 4e931351b49..cfa007c75eb 100644 --- a/include/docobjectservice.idl +++ b/include/docobjectservice.idl @@ -17,23 +17,25 @@ */ import "objidl.idl"; +#ifndef NO_MSHTML_IMPORT import "mshtml.idl"; +#endif [ - local, + /* local, CXHACK 15579 */ object, uuid(3050f801-98b5-11cf-bb82-00aa00bdce0b) ] interface IDocObjectService : IUnknown { HRESULT FireBeforeNavigate2( - [in] IDispatch *pDispatch, - [in] LPCWSTR lpszUrl, + [in, optional] IDispatch *pDispatch, + [in, string, unique] LPCWSTR lpszUrl, [in] DWORD dwFlags, - [in] LPCWSTR lpszFrameName, - [in] BYTE *pPostData, + [in, string, unique] LPCWSTR lpszFrameName, + [in, unique, size_is(cbPostData)] BYTE *pPostData, [in] DWORD cbPostData, - [in] LPCWSTR lpszHeaders, + [in, string, unique] LPCWSTR lpszHeaders, [in] BOOL fPlayNavSound, [out] BOOL *pfCancel); diff --git a/include/mshtmhst.idl b/include/mshtmhst.idl index 6cc500ed7a9..efc51c6a5da 100644 --- a/include/mshtmhst.idl +++ b/include/mshtmhst.idl @@ -163,7 +163,7 @@ typedef enum tagDOCHOSTUIFLAG object, uuid(BD3F23C0-D43E-11CF-893B-00AA00BDCE1A), pointer_default(unique), - local + /* local, CXHACK 15579 */ ] interface IDocHostUIHandler : IUnknown { @@ -237,7 +237,7 @@ cpp_quote("DEFINE_GUID(CGID_DocHostCommandHandler,0xf38bc242,0xb950,0x11d1,0x89, object, uuid(3050F6D0-98b5-11CF-BB82-00AA00BDCE0B), pointer_default(unique), - local + /* local, CXHACK 15579 */ ] interface IDocHostUIHandler2 : IDocHostUIHandler { @@ -253,7 +253,7 @@ interface IDocHostUIHandler2 : IDocHostUIHandler object, uuid(3050f3f0-98b5-11cf-bb82-00aa00bdce0b), pointer_default(unique), - local + /* local, CXHACK 15579 */ ] interface ICustomDoc : IUnknown { diff --git a/include/mshtml.idl b/include/mshtml.idl index f3c675e012d..0f9a55a4a44 100644 --- a/include/mshtml.idl +++ b/include/mshtml.idl @@ -30335,7 +30335,11 @@ interface IElementBehaviorFactory : IUnknown } /* library MSHTML */ +#ifdef MSHTML_MARSHALING_HACK +#define IOleCommandTarget IUnknown +#else interface IOleCommandTarget; +#endif /***************************************************************************** * IHTMLPrivateWindow interface @@ -30343,7 +30347,7 @@ interface IOleCommandTarget; [ object, uuid(3050f6dc-98b5-11cf-bb82-00aa00bdce0b), - local + /* local, CXHACK 15579 */ ] interface IHTMLPrivateWindow : IUnknown { @@ -30352,7 +30356,7 @@ interface IHTMLPrivateWindow : IUnknown HRESULT SetPICSTarget(IOleCommandTarget *cmdtrg); HRESULT PICSComplete(int arg); HRESULT FindWindowByName(LPCWSTR name, IHTMLWindow2 **ret); - HRESULT GetAddressBarUrl(BSTR *url); + HRESULT GetAddressBarUrl([out, retval] BSTR *url); } /***************************************************************************** @@ -30361,7 +30365,7 @@ interface IHTMLPrivateWindow : IUnknown [ object, uuid(3050f804-98b5-11cf-bb82-00aa00bdce0b), - local + /* local, CXHACK 15579 */ ] interface IWebBrowserPriv : IUnknown { @@ -30376,7 +30380,7 @@ interface IWebBrowserPriv : IUnknown [ object, uuid(3ed72303-6ffc-4214-ba90-faf1862dec8a), - local + /* local, CXHACK 15579 */ ] interface IWebBrowserPriv2IE8 : IUnknown { @@ -30398,7 +30402,7 @@ interface IWebBrowserPriv2IE8 : IUnknown [ object, uuid(3ed72303-6ffc-4214-ba90-faf1862dec8a), - local + /* local, CXHACK 15579 */ ] interface IWebBrowserPriv2IE9 : IUnknown { @@ -30406,3 +30410,7 @@ interface IWebBrowserPriv2IE9 : IUnknown VARIANT *headers, IBindCtx *bind_ctx, LPOLESTR url_fragment, DWORD unused); /* Probably more */ } + +#ifdef MSHTML_MARSHALING_HACK +#undef IOleCommandTarget +#endif diff --git a/include/shdeprecated.idl b/include/shdeprecated.idl index c8bb3fd9bf0..bb0559578e9 100644 --- a/include/shdeprecated.idl +++ b/include/shdeprecated.idl @@ -186,7 +186,7 @@ cpp_quote("#define HLNF_ALLOW_AUTONAVIGATE 0x20000000") cpp_quote("#define HLNF_NEWWINDOWSMANAGED 0x80000000") [ - local, + /* local, CXHACK 15579 */ object, uuid(02ba3b52-0547-11d1-b833-00c04fc9b31f) ] @@ -220,7 +220,7 @@ interface IBrowserService : IUnknown HRESULT IEGetDisplayName( [in] PCIDLIST_ABSOLUTE pidl, - [out, size_is(INTERNET_MAX_URL_LENGTH)] LPWSTR pwszName, + [out, size_is(300)] LPWSTR pwszName, [in] UINT uFlags); HRESULT IEParseDisplayName( From ac5082a631d1c3bb16884e1c6a092bd2fb546485 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 16 Apr 2021 01:54:11 +0300 Subject: [PATCH 0958/2777] mshtml: Use environment variable instead of registry for dedicated thread hack. And auto enable it for The Bus. CW-Bug-Id: 18848 --- dlls/mshtml/oleobj.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/dlls/mshtml/oleobj.c b/dlls/mshtml/oleobj.c index 44d6748c73b..0a099c920c9 100644 --- a/dlls/mshtml/oleobj.c +++ b/dlls/mshtml/oleobj.c @@ -3683,18 +3683,12 @@ static DWORD WINAPI gecko_main_thread_proc(void *arg) static BOOL WINAPI read_thread_config(INIT_ONCE *once, void *param, void **context) { - HKEY key; - DWORD res; - static const WCHAR enable_keyW[] = - {'S','o','f','t','w','a','r','e', - '\\','W','i','n','e', - '\\','M','S','H','T','M','L', - '\\','M','a','i','n','T','h','r','e','a','d','H','a','c','k',0}; - - res = RegOpenKeyW(HKEY_CURRENT_USER, enable_keyW, &key); - if(res == ERROR_SUCCESS) { - RegCloseKey(key); - FIXME("CXHACK: Using separated main thread.\n"); + char str[64]; + + if((GetEnvironmentVariableA("SteamGameId", str, sizeof(str)) && !strcmp(str, "491540")) + || (GetEnvironmentVariableA("WINE_GECKO_MAIN_THREAD", str, sizeof(str)) && *str != '0')) + { + FIXME("HACK: Using separated main thread.\n"); gecko_main_thread_config = TRUE; } @@ -3735,10 +3729,10 @@ static HRESULT create_document_object(BOOL is_mhtml, IUnknown *outer, REFIID rii gecko_main_thread = GetCurrentThreadId(); gecko_main_thread_hwnd = get_thread_hwnd(); }else if(GetCurrentThreadId() != gecko_main_thread) { - FIXME("CXHACK: Creating HTMLDocument outside Gecko main thread\n"); + FIXME("HACK: Creating HTMLDocument outside Gecko main thread\n"); if(!gecko_main_thread_config) { - FIXME("CXHACK: Dedicated main thread not configured\n"); - FIXME("CXHACK: Create HKCU\\Software\\Wine\\MSHTML\\MainThreadHack key\n"); + FIXME("HACK: Dedicated main thread not configured\n"); + FIXME("HACK: Create HKCU\\Software\\Wine\\MSHTML\\MainThreadHack key\n"); } return create_marshaled_doc(gecko_main_thread_hwnd, riid, ppv); } From 01fadb60cf46cd269ab2d19af91baada842b7d31 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 26 Jul 2021 21:18:36 +0300 Subject: [PATCH 0959/2777] mshtml: Also enable dedicated thread hack for The Sims 3. For The Sims 3 launcher crash. CW-Bug-Id: #19151 --- dlls/mshtml/oleobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/mshtml/oleobj.c b/dlls/mshtml/oleobj.c index 0a099c920c9..ea6060a761c 100644 --- a/dlls/mshtml/oleobj.c +++ b/dlls/mshtml/oleobj.c @@ -3685,7 +3685,7 @@ static BOOL WINAPI read_thread_config(INIT_ONCE *once, void *param, void **conte { char str[64]; - if((GetEnvironmentVariableA("SteamGameId", str, sizeof(str)) && !strcmp(str, "491540")) + if((GetEnvironmentVariableA("SteamGameId", str, sizeof(str)) && (!strcmp(str, "491540") || !strcmp(str,"47890"))) || (GetEnvironmentVariableA("WINE_GECKO_MAIN_THREAD", str, sizeof(str)) && *str != '0')) { FIXME("HACK: Using separated main thread.\n"); From 3d652ac707993dd16e73c0a9d99766c616c9d079 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 25 May 2021 20:48:17 +0300 Subject: [PATCH 0960/2777] mshtml: HACK: Split rules in HTMLStyleSheet_put_cssText(). For Open Swords of Legends Online: Beta launcher. CW-Bug-Id: #18963 --- dlls/mshtml/htmlstylesheet.c | 49 +++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/dlls/mshtml/htmlstylesheet.c b/dlls/mshtml/htmlstylesheet.c index 176204e5129..b0ded7534b2 100644 --- a/dlls/mshtml/htmlstylesheet.c +++ b/dlls/mshtml/htmlstylesheet.c @@ -1342,17 +1342,48 @@ static HRESULT WINAPI HTMLStyleSheet_put_cssText(IHTMLStyleSheet *iface, BSTR v) }while(NS_SUCCEEDED(nsres)); if(v && *v) { + UINT32 i, depth, idx; nsAString nsstr; - UINT32 idx; - - /* FIXME: This won't work for multiple rules in the string. */ - nsAString_InitDepend(&nsstr, v); - nsres = nsIDOMCSSStyleSheet_InsertRule(This->nsstylesheet, &nsstr, 0, &idx); - nsAString_Finish(&nsstr); - if(NS_FAILED(nsres)) { - FIXME("InsertRule failed for string %s. Probably multiple rules passed.\n", debugstr_w(v)); - return E_FAIL; + WCHAR *ws; + + depth = 0; + ws = malloc(sizeof(*ws) * (lstrlenW(v) + 1)); + do + { + for (i = 0; v[i]; ++i) + { + ws[i] = v[i]; + if (ws[i] == '{') + ++depth; + else if (ws[i] == '}' && !--depth) + break; + } + if (ws[i]) + ws[++i] = 0; + + v += i; + + for (i = 0; ws[i]; ++i) + if (!iswspace(ws[i])) + break; + + if (!ws[i]) + { + TRACE("Skipping empty part.\n"); + continue; + } + + nsAString_InitDepend(&nsstr, ws); + nsres = nsIDOMCSSStyleSheet_InsertRule(This->nsstylesheet, &nsstr, 0, &idx); + nsAString_Finish(&nsstr); + + if(NS_FAILED(nsres)) + FIXME("InsertRule failed for string %s.\n", debugstr_w(ws)); + else + TRACE("Added rule %s.\n", debugstr_w(ws)); } + while (*v); + free(ws); } return S_OK; From 1fe24c9d04274d2451fd48d5fc4c5ac886260218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 13 Jan 2023 13:07:25 +0100 Subject: [PATCH 0961/2777] jscript: Silence a false positive maybe-uninitialized warning in convert_to_proxy. --- dlls/jscript/dispex.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/jscript/dispex.c b/dlls/jscript/dispex.c index b7c03501240..8cbbf1110f4 100644 --- a/dlls/jscript/dispex.c +++ b/dlls/jscript/dispex.c @@ -2824,6 +2824,7 @@ HRESULT create_dispex(script_ctx_t *ctx, const builtin_info_t *builtin_info, jsd jsdisp_t *ret; HRESULT hres; + *dispex = NULL; ret = calloc(1, sizeof(jsdisp_t)); if(!ret) return E_OUTOFMEMORY; From c67c0e18365ac88fd2441ac25e8facd846e86e9d Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Tue, 23 Oct 2018 16:18:20 +0300 Subject: [PATCH 0962/2777] wine.inf: Add font registry entries. --- loader/wine.inf.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index a16ad974592..ebe5d9d0047 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -266,6 +266,7 @@ CurrentVersionNT="Software\Microsoft\Windows NT\CurrentVersion" FontSubStr="Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes" Control="System\CurrentControlSet\Control" Packages="Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\PackageRepository\Packages" +FontsNT="Software\Microsoft\Windows NT\CurrentVersion\Fonts" [Classes] HKCR,.chm,,2,"chm.file" @@ -499,6 +500,10 @@ HKLM,%FontSubStr%,"Times New Roman CYR,204",,"Times New Roman,204" HKLM,%FontSubStr%,"Times New Roman Greek,161",,"Times New Roman,161" HKLM,%FontSubStr%,"Times New Roman TUR,162",,"Times New Roman,162" HKLM,System\CurrentControlSet\Hardware Profiles\Current\Software\Fonts,"LogPixels",0x10003,0x00000060 +HKLM,%FontsNT%,"Arial (TrueType)",,"arial.ttf" +HKLM,%FontsNT%,"Arial Bold (TrueType)",,"arialbd.ttf" +HKLM,%FontsNT%,"Times New Roman (TrueType)",,"times.ttf" +HKLM,%FontsNT%,"Courier New (TrueType)",,"cour.ttf" [MCI] HKLM,%Mci32Str%,"AVIVideo",,"mciavi32.dll" From 4e3daedef09a18911e86ad986cf95b54f998c023 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 30 Oct 2018 13:04:06 -0500 Subject: [PATCH 0963/2777] wine.inf: Substitute Times New Roman for Palatino Linotype For AOE2HD launcher. CW-Bug-Id: #16410 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index ebe5d9d0047..995e412c0c3 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -504,6 +504,7 @@ HKLM,%FontsNT%,"Arial (TrueType)",,"arial.ttf" HKLM,%FontsNT%,"Arial Bold (TrueType)",,"arialbd.ttf" HKLM,%FontsNT%,"Times New Roman (TrueType)",,"times.ttf" HKLM,%FontsNT%,"Courier New (TrueType)",,"cour.ttf" +HKCU,Software\Wine\Fonts\Replacements,"Palatino Linotype",,"Times New Roman" [MCI] HKLM,%Mci32Str%,"AVIVideo",,"mciavi32.dll" From 72508b7d4110b76f90320ff009df1141f6e07901 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Tue, 10 Aug 2021 11:56:55 +0200 Subject: [PATCH 0964/2777] HACK: loader/wine.inf: Add registry entries for the new fonts. They are required for DWrite to enumerate the fonts. For Cyberpunk 2077 launcher font support. CW-Bug-Id: #19125 --- loader/wine.inf.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 995e412c0c3..9c593606ffa 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -504,6 +504,10 @@ HKLM,%FontsNT%,"Arial (TrueType)",,"arial.ttf" HKLM,%FontsNT%,"Arial Bold (TrueType)",,"arialbd.ttf" HKLM,%FontsNT%,"Times New Roman (TrueType)",,"times.ttf" HKLM,%FontsNT%,"Courier New (TrueType)",,"cour.ttf" +HKLM,%FontsNT%,"Malgun Gothic (TrueType)",,"malgun.ttf" +HKLM,%FontsNT%,"Microsoft YaHei (TrueType)",,"msyh.ttf" +HKLM,%FontsNT%,"MS Gothic (TrueType)",,"msgothic.ttc" +HKLM,%FontsNT%,"SimSun (TrueType)",,"simsun.ttc" HKCU,Software\Wine\Fonts\Replacements,"Palatino Linotype",,"Times New Roman" [MCI] From a4848695e67e2ee1d0a3f932cf46718e96ddeaa4 Mon Sep 17 00:00:00 2001 From: Matteo Bruni Date: Sat, 24 Aug 2019 00:58:42 +0200 Subject: [PATCH 0965/2777] wined3d: Avoid NaNs in RCP and RSQ in <= SM3. CW-Bug-Id: #21762 Fixes sporadic white screen in Chapter 1 Act 3 in A Hat in Time. FWIW the NaNs end up in a RGBA16F render target, another option that might work is to fixup NaNs when writing them into the pixel shader output. --- dlls/wined3d/glsl_shader.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 594fdf73f46..5317e64a9d3 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -2562,6 +2562,7 @@ static void shader_generate_glsl_declarations(const struct wined3d_context_gl *c shader_addline(buffer, ";\n"); } } + shader_addline(buffer, "const float FLT_MAX = 1e38;\n"); } /* Prototypes */ @@ -4215,9 +4216,10 @@ static void shader_glsl_scalar_op(const struct wined3d_shader_instruction *ins) { DWORD shader_version = WINED3D_SHADER_VERSION(ins->ctx->reg_maps->shader_version.major, ins->ctx->reg_maps->shader_version.minor); + struct shader_glsl_ctx_priv *priv = ins->ctx->backend_data; struct wined3d_string_buffer *buffer = ins->ctx->buffer; + struct wined3d_string_buffer *prefix, *suffix; struct glsl_src_param src0_param; - const char *prefix, *suffix; unsigned int dst_size; DWORD dst_write_mask; @@ -4229,41 +4231,50 @@ static void shader_glsl_scalar_op(const struct wined3d_shader_instruction *ins) shader_glsl_add_src_param(ins, &ins->src[0], dst_write_mask, &src0_param); + prefix = string_buffer_get(priv->string_buffers); + suffix = string_buffer_get(priv->string_buffers); + switch (ins->handler_idx) { case WINED3DSIH_EXP: case WINED3DSIH_EXPP: - prefix = "exp2("; - suffix = ")"; + string_buffer_sprintf(prefix, "exp2("); + string_buffer_sprintf(suffix, ")"); break; case WINED3DSIH_LOG: case WINED3DSIH_LOGP: - prefix = "log2(abs("; - suffix = "))"; + string_buffer_sprintf(prefix, "log2(abs("); + string_buffer_sprintf(suffix, "))"); break; case WINED3DSIH_RCP: - prefix = "1.0 / "; - suffix = ""; + if (shader_version <= WINED3D_SHADER_VERSION(3, 0)) + string_buffer_sprintf(prefix, "%s == 0.0 ? FLT_MAX : 1.0 / ", src0_param.param_str); + else + string_buffer_sprintf(prefix, "1.0 / "); break; case WINED3DSIH_RSQ: - prefix = "inversesqrt(abs("; - suffix = "))"; + if (shader_version <= WINED3D_SHADER_VERSION(3, 0)) + string_buffer_sprintf(prefix, "%s == 0.0 ? FLT_MAX : inversesqrt(abs(", src0_param.param_str); + else + string_buffer_sprintf(prefix, "inversesqrt(abs("); + string_buffer_sprintf(suffix, "))"); break; default: - prefix = ""; - suffix = ""; FIXME("Unhandled instruction %#x.\n", ins->handler_idx); break; } if (dst_size > 1 && shader_version < WINED3D_SHADER_VERSION(4, 0)) - shader_addline(buffer, "vec%u(%s%s%s));\n", dst_size, prefix, src0_param.param_str, suffix); + shader_addline(buffer, "vec%u(%s%s%s));\n", dst_size, prefix->buffer, src0_param.param_str, suffix->buffer); else - shader_addline(buffer, "%s%s%s);\n", prefix, src0_param.param_str, suffix); + shader_addline(buffer, "%s%s%s);\n", prefix->buffer, src0_param.param_str, suffix->buffer); + + string_buffer_release(priv->string_buffers, prefix); + string_buffer_release(priv->string_buffers, suffix); } /** Process the WINED3DSIO_EXPP instruction in GLSL: From e9624576c87ae5fb51f5d6f53b6400538c36f16d Mon Sep 17 00:00:00 2001 From: Matteo Bruni Date: Tue, 27 Aug 2019 02:55:16 +0200 Subject: [PATCH 0966/2777] wined3d: Avoid NaNs in LOG and LOGP. CW-Bug-Id: #21762 Fixes some white artifacts in A Hat in Time Chapter 2 Act 1. --- dlls/wined3d/glsl_shader.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 5317e64a9d3..41023b6325f 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -4244,7 +4244,10 @@ static void shader_glsl_scalar_op(const struct wined3d_shader_instruction *ins) case WINED3DSIH_LOG: case WINED3DSIH_LOGP: - string_buffer_sprintf(prefix, "log2(abs("); + if (shader_version <= WINED3D_SHADER_VERSION(3, 0)) + string_buffer_sprintf(prefix, "%s == 0.0 ? -FLT_MAX : log2(abs(", src0_param.param_str); + else + string_buffer_sprintf(prefix, "log2(abs("); string_buffer_sprintf(suffix, "))"); break; From ba3c43eb34cd10b7cf1c8e76319a2eef86f31f8b Mon Sep 17 00:00:00 2001 From: Jactry Zeng Date: Sun, 26 Sep 2021 14:58:45 +0800 Subject: [PATCH 0967/2777] loader/wine.inf: Add registry entries for Microsoft Sans Serif (micross.ttf) and Nirmala UI (nirmala.ttf). CW-Bug-Id: #17132 --- loader/wine.inf.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 9c593606ffa..39f86ba7493 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -505,8 +505,10 @@ HKLM,%FontsNT%,"Arial Bold (TrueType)",,"arialbd.ttf" HKLM,%FontsNT%,"Times New Roman (TrueType)",,"times.ttf" HKLM,%FontsNT%,"Courier New (TrueType)",,"cour.ttf" HKLM,%FontsNT%,"Malgun Gothic (TrueType)",,"malgun.ttf" +HKLM,%FontsNT%,"Microsoft Sans Serif (TrueType)",,"micross.ttf" HKLM,%FontsNT%,"Microsoft YaHei (TrueType)",,"msyh.ttf" HKLM,%FontsNT%,"MS Gothic (TrueType)",,"msgothic.ttc" +HKLM,%FontsNT%,"Nirmala UI (TrueType)",,"nirmala.ttf" HKLM,%FontsNT%,"SimSun (TrueType)",,"simsun.ttc" HKCU,Software\Wine\Fonts\Replacements,"Palatino Linotype",,"Times New Roman" From deb9b261c45adf2b44de7c19237d9c2fe758620d Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Thu, 12 Jan 2023 16:57:40 +0100 Subject: [PATCH 0968/2777] dwrite: Use fonts distributed with Proton as fallback. --- dlls/dwrite/analyzer.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 5489efa93b8..ca247639403 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -248,7 +248,7 @@ system_fallback_config[] = { "0D00-0D7F", L"Noto Sans Malayalam" }, { "0D80-0DFF", L"Noto Sans Sinhala" }, - { "0E00-0E7F", L"Noto Sans Thai" }, + { "0E00-0E7F", L"Microsoft Sans Serif" }, { "0E80-0EFF", L"Noto Sans Lao" }, { "0F00-0FFF", L"Noto Serif Tibetan" }, @@ -268,7 +268,7 @@ system_fallback_config[] = { "1100-11FF, 3130-318F, " "3200-321F, 3260-327F, " "A960-A97F, AC00-D7FF, " - "D7B0-D7FF", L"Noto Sans CJK KR" }, + "D7B0-D7FF", L"Malgun Gothic" }, { "1680-169F", L"Noto Sans Ogham" }, @@ -297,27 +297,27 @@ system_fallback_config[] = /* CJK Radicals Supplement - 2E80-2EFF */ - { "2E80-2EFF", L"Noto Sans CJK SC", L"zh-Hans" }, + { "2E80-2EFF", L"Microsoft YaHei", L"zh-Hans" }, { "2E80-2EFF", L"Noto Sans CJK TC", L"zh-Hant" }, - { "2E80-2EFF", L"Noto Sans CJK KR", L"ko" }, + { "2E80-2EFF", L"Malgun Gothic", L"ko" }, /* CJK Symbols and Punctuation - 3000-303F Hiragana - 3040-309F Katakana - 30A0-30FF Katakana Phonetic Ext. - 31F0-31FF */ - { "3000-30FF, 31F0-31FF", L"Noto Sans CJK SC", L"zh-Hans" }, + { "3000-30FF, 31F0-31FF", L"Microsoft YaHei", L"zh-Hans" }, { "3000-30FF, 31F0-31FF", L"Noto Sans CJK TC", L"zh-Hant" }, - { "3000-30FF, 31F0-31FF", L"Noto Sans CJK KR", L"ko" }, - { "3000-30FF, 31F0-31FF", L"Noto Sans CJK JP" }, + { "3000-30FF, 31F0-31FF", L"Malgun Gothic", L"ko" }, + { "3000-30FF, 31F0-31FF", L"MS Gothic" }, /* CJK Unified Ext A - 3400-4DBF CJK Unified - 4E00-9FFF */ - { "3400-4DBF, 4E00-9FFF", L"Noto Sans CJK SC", L"zh-Hans" }, + { "3400-4DBF, 4E00-9FFF", L"Microsoft YaHei", L"zh-Hans" }, { "3400-4DBF, 4E00-9FFF", L"Noto Sans CJK TC", L"zh-Hant" }, - { "3400-4DBF, 4E00-9FFF", L"Noto Sans CJK KR", L"ko" }, - { "3400-4DBF, 4E00-9FFF", L"Noto Sans CJK JP" }, + { "3400-4DBF, 4E00-9FFF", L"Malgun Gothic", L"ko" }, + { "3400-4DBF, 4E00-9FFF", L"MS Gothic" }, { "A000-A4CF", L"Noto Sans Yi" }, { "A4D0-A4FF", L"Noto Sans Lisu" }, @@ -333,30 +333,30 @@ system_fallback_config[] = /* CJK Compatibility Ideographs - F900-FAFF */ - { "F900-FAFF", L"Noto Sans CJK SC", L"zh-Hans" }, + { "F900-FAFF", L"Microsoft YaHei", L"zh-Hans" }, { "F900-FAFF", L"Noto Sans CJK TC", L"zh-Hant" }, - { "F900-FAFF", L"Noto Sans CJK KR", L"ko" }, - { "F900-FAFF", L"Noto Sans CJK JP" }, + { "F900-FAFF", L"Malgun Gothic", L"ko" }, + { "F900-FAFF", L"MS Gothic" }, /* Vertical Forms - FE10-FE1F */ - { "FE10-FE1F", L"Noto Sans CJK SC", L"zh-Hans" }, - { "FE10-FE1F", L"Noto Sans CJK KR", L"ko" }, + { "FE10-FE1F", L"Microsoft YaHei", L"zh-Hans" }, + { "FE10-FE1F", L"Malgun Gothic", L"ko" }, { "FE10-FE1F", L"Noto Sans CJK TC" }, /* CJK Compatibility Forms - FE30-FE4F Small Form Variants - FE50-FE6F */ - { "FE30-FE6F", L"Noto Sans CJK SC", L"zh-Hans" }, - { "FE30-FE6F", L"Noto Sans CJK KR", L"ko" }, - { "FE30-FE6F", L"Noto Sans CJK JP", L"ja" }, + { "FE30-FE6F", L"Microsoft YaHei", L"zh-Hans" }, + { "FE30-FE6F", L"Malgun Gothic", L"ko" }, + { "FE30-FE6F", L"MS Gothic", L"ja" }, { "FE30-FE6F", L"Noto Sans CJK TC" }, /* Halfwidth and Fullwidth Forms */ - { "FF00-FFEF", L"Noto Sans CJK SC", L"zh-Hans" }, + { "FF00-FFEF", L"Microsoft YaHei", L"zh-Hans" }, { "FF00-FFEF", L"Noto Sans CJK TC", L"zh-Hant" }, - { "FF00-FFEF", L"Noto Sans CJK KR", L"ko" }, - { "FF00-FFEF", L"Noto Sans CJK JP" }, + { "FF00-FFEF", L"Malgun Gothic", L"ko" }, + { "FF00-FFEF", L"MS Gothic" }, }; struct text_source_context From 646158c820a31f853b96a13e05dce21983a92b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 3 Dec 2022 07:48:29 +0100 Subject: [PATCH 0969/2777] ntdll: Add .cfi_signal_frame to __wine_syscall_dispatcher. To make sure gdb will unwind through it, and ignore that the syscall frame is inner its caller frame on the thread stack. --- dlls/ntdll/unix/signal_i386.c | 2 ++ dlls/ntdll/unix/signal_x86_64.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index b2dfe82beb5..abbfe7e11bd 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -2578,6 +2578,7 @@ __ASM_GLOBAL_FUNC( signal_exit_thread, * __wine_syscall_dispatcher */ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, + __ASM_CFI(".cfi_signal_frame\n\t") "movl %fs:0x1f8,%ecx\n\t" /* x86_thread_data()->syscall_frame */ "movw $0,0x02(%ecx)\n\t" /* frame->restore_flags */ "popl 0x08(%ecx)\n\t" /* frame->eip */ @@ -2770,6 +2771,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, * __wine_unix_call_dispatcher */ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher, + __ASM_CFI(".cfi_signal_frame\n\t") "movl %fs:0x1f8,%ecx\n\t" /* x86_thread_data()->syscall_frame */ "movw $0,0x02(%ecx)\n\t" /* frame->restore_flags */ "popl 0x08(%ecx)\n\t" /* frame->eip */ diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 51b9b79d931..7685ca7852b 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2979,6 +2979,7 @@ __ASM_GLOBAL_FUNC( signal_exit_thread, * __wine_syscall_dispatcher */ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, + __ASM_CFI(".cfi_signal_frame\n\t") #ifdef __APPLE__ "movq %gs:0x30,%rcx\n\t" "movq 0x328(%rcx),%rcx\n\t" @@ -3203,6 +3204,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, * __wine_unix_call_dispatcher */ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher, + __ASM_CFI(".cfi_signal_frame\n\t") "movq %rcx,%r10\n\t" #ifdef __APPLE__ "movq %gs:0x30,%rcx\n\t" From 0a273e2a86338a94365469238fb73e348ed16338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 16 Oct 2022 22:45:59 +0200 Subject: [PATCH 0970/2777] loader: Expose a shadow copy of ld.so link map to GDB. Effectively supporting dynamically loaded libraries when running Wine under GDB without WINELOADERNOEXEC=1. Credits to Jinoh Kang for the idea. --- loader/main.c | 88 +++++++++++++++++++++++++++++++++++++++++++++- loader/preloader.c | 15 ++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/loader/main.c b/loader/main.c index 242ff15accd..b7805473da8 100644 --- a/loader/main.c +++ b/loader/main.c @@ -33,13 +33,99 @@ #ifdef HAVE_SYS_SYSCTL_H # include #endif +#ifdef HAVE_LINK_H +# include +#endif +#ifdef HAVE_SYS_LINK_H +# include +#endif #include "main.h" extern char **environ; -/* the preloader will set this variable */ +/* the preloader will set these variables */ const struct wine_preload_info *wine_main_preload_info = NULL; +void (*wine_dl_debug_state)(void) = NULL; +struct r_debug *wine_r_debug = NULL; + +#ifdef __linux__ + +static struct link_map so_link_map = {.l_name = (char *)""}; +static pthread_mutex_t link_map_lock = PTHREAD_MUTEX_INITIALIZER; + +static void sync_wine_link_map(void) +{ + static struct r_debug *_r_debug; + struct link_map *next = &so_link_map, *prev = NULL, **rtld_map, **wine_map; + + if (!_r_debug) _r_debug = dlsym( RTLD_NEXT, "_r_debug" ); + rtld_map = &_r_debug->r_map; + wine_map = &next; + + pthread_mutex_lock( &link_map_lock ); + + while (*rtld_map) + { + if (!*wine_map) + { + if (!(*wine_map = calloc( 1, sizeof(struct link_map) ))) break; + (*wine_map)->l_prev = prev; + } + + prev = *wine_map; + (*wine_map)->l_addr = (*rtld_map)->l_addr; + (*wine_map)->l_name = strdup( (*rtld_map)->l_name ); + (*wine_map)->l_ld = (*rtld_map)->l_ld; + rtld_map = &(*rtld_map)->l_next; + wine_map = &(*wine_map)->l_next; + } + + /* remove the remaining wine entries */ + next = *wine_map; + *wine_map = NULL; + + while (next) + { + struct link_map *prev = next; + wine_map = &next->l_next; + next = *wine_map; + *wine_map = NULL; + free( prev->l_name ); + free( prev ); + } + + pthread_mutex_unlock( &link_map_lock ); + + if (wine_r_debug) wine_r_debug->r_map = &so_link_map; + if (wine_dl_debug_state) wine_dl_debug_state(); +} + +void *dlopen( const char *file, int mode ) +{ + static typeof(dlopen) *rtld_dlopen; + void *ret; + + if (!rtld_dlopen) rtld_dlopen = dlsym( RTLD_NEXT, "dlopen" ); + ret = rtld_dlopen( file, mode ); + + sync_wine_link_map(); + return ret; +} + +int dlclose( void *handle ) +{ + static typeof(dlclose) *rtld_dlclose; + int ret; + + if (!rtld_dlclose) rtld_dlclose = dlsym( RTLD_NEXT, "dlclose" ); + ret = rtld_dlclose( handle ); + + sync_wine_link_map(); + return ret; +} + +#endif /* __linux__ */ /* canonicalize path and return its directory name */ static char *realpath_dirname( const char *name ) diff --git a/loader/preloader.c b/loader/preloader.c index 72556f09720..9fa00786281 100644 --- a/loader/preloader.c +++ b/loader/preloader.c @@ -1362,6 +1362,9 @@ static void set_process_name( int argc, char *argv[] ) for (i = 1; i < argc; i++) argv[i] -= off; } +/* GDB hooks integration */ +struct r_debug _r_debug = {0}; +void _dl_debug_state(void) {} /* * wld_start @@ -1378,6 +1381,8 @@ void* wld_start( void **stack ) struct wld_auxv new_av[8], delete_av[3], *av; struct wld_link_map main_binary_map, ld_so_map; struct wine_preload_info **wine_main_preload_info; + void (**wine_dl_debug_state)(void); + struct r_debug **wine_r_debug; pargc = *stack; argv = (char **)pargc + 1; @@ -1450,6 +1455,16 @@ void* wld_start( void **stack ) if (wine_main_preload_info) *wine_main_preload_info = preload_info; else wld_printf( "wine_main_preload_info not found\n" ); + /* provide r_debug to inform GDB of loaded modules */ + wine_r_debug = find_symbol( &main_binary_map, "wine_r_debug", STT_OBJECT ); + if (wine_r_debug) *wine_r_debug = &_r_debug; + else wld_printf( "wine_r_debug not found\n" ); + + /* provide _dl_debug_state callback to trigger GDB hooks */ + wine_dl_debug_state = find_symbol( &main_binary_map, "wine_dl_debug_state", STT_OBJECT ); + if (wine_dl_debug_state) *wine_dl_debug_state = _dl_debug_state; + else wld_printf( "wine_dl_debug_state not found\n" ); + #define SET_NEW_AV(n,type,val) new_av[n].a_type = (type); new_av[n].a_un.a_val = (val); SET_NEW_AV( 0, AT_PHDR, (unsigned long)main_binary_map.l_phdr ); SET_NEW_AV( 1, AT_PHENT, sizeof(ElfW(Phdr)) ); From 6a3ff7a3980329e53ced560c7a211050cf7d7cde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 5 Dec 2022 20:10:49 +0100 Subject: [PATCH 0971/2777] ntdll: Pass a UNICODE_STRING to load_builtin and virtual_map_image. --- dlls/ntdll/unix/loader.c | 12 +++++----- dlls/ntdll/unix/unix_private.h | 2 +- dlls/ntdll/unix/virtual.c | 40 +++++++++++++++++----------------- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index cdbdecd520c..d4cb5266b64 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -1715,17 +1715,15 @@ static NTSTATUS find_builtin_dll( UNICODE_STRING *nt_name, void **module, SIZE_T * Load the builtin dll if specified by load order configuration. * Return STATUS_IMAGE_ALREADY_LOADED if we should keep the native one that we have found. */ -NTSTATUS load_builtin( const pe_image_info_t *image_info, WCHAR *filename, +NTSTATUS load_builtin( const pe_image_info_t *image_info, UNICODE_STRING *nt_name, void **module, SIZE_T *size, ULONG_PTR zero_bits ) { WORD machine = image_info->machine; /* request same machine as the native one */ NTSTATUS status; - UNICODE_STRING nt_name; SECTION_IMAGE_INFORMATION info; enum loadorder loadorder; - init_unicode_string( &nt_name, filename ); - loadorder = get_load_order( &nt_name ); + loadorder = get_load_order( nt_name ); if (loadorder == LO_DISABLED) return STATUS_DLL_NOT_FOUND; @@ -1736,7 +1734,7 @@ NTSTATUS load_builtin( const pe_image_info_t *image_info, WCHAR *filename, } else if (image_info->image_flags & IMAGE_FLAGS_WineFakeDll) { - TRACE( "%s is a fake Wine dll\n", debugstr_w(filename) ); + TRACE( "%s is a fake Wine dll\n", debugstr_us(nt_name) ); if (loadorder == LO_NATIVE) return STATUS_DLL_NOT_FOUND; loadorder = LO_BUILTIN; /* builtin with no fallback since mapping a fake dll is not useful */ } @@ -1747,9 +1745,9 @@ NTSTATUS load_builtin( const pe_image_info_t *image_info, WCHAR *filename, case LO_NATIVE_BUILTIN: return STATUS_IMAGE_ALREADY_LOADED; case LO_BUILTIN: - return find_builtin_dll( &nt_name, module, size, &info, zero_bits, machine, FALSE ); + return find_builtin_dll( nt_name, module, size, &info, zero_bits, machine, FALSE ); default: - status = find_builtin_dll( &nt_name, module, size, &info, zero_bits, machine, (loadorder == LO_DEFAULT) ); + status = find_builtin_dll( nt_name, module, size, &info, zero_bits, machine, (loadorder == LO_DEFAULT) ); if (status == STATUS_DLL_NOT_FOUND || status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) return STATUS_IMAGE_ALREADY_LOADED; return status; diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 9a97a1ed3c3..dcc4c64c508 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -162,7 +162,7 @@ extern void *create_startup_info( const UNICODE_STRING *nt_image, const RTL_USER DWORD *info_size ) DECLSPEC_HIDDEN; extern char **build_envp( const WCHAR *envW ) DECLSPEC_HIDDEN; extern NTSTATUS exec_wineloader( char **argv, int socketfd, const pe_image_info_t *pe_info ) DECLSPEC_HIDDEN; -extern NTSTATUS load_builtin( const pe_image_info_t *image_info, WCHAR *filename, +extern NTSTATUS load_builtin( const pe_image_info_t *image_info, UNICODE_STRING *nt_name, void **addr_ptr, SIZE_T *size_ptr, ULONG_PTR zero_bits ) DECLSPEC_HIDDEN; extern BOOL is_builtin_path( const UNICODE_STRING *path, WORD *machine ) DECLSPEC_HIDDEN; extern NTSTATUS load_main_exe( const WCHAR *name, const char *unix_name, const WCHAR *curdir, WCHAR **image, diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 837ecd878dd..c3e6c7548d5 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -2403,7 +2403,7 @@ static NTSTATUS map_pe_header( void *ptr, size_t size, int fd, BOOL *removable ) * Map an executable (PE format) image into an existing view. * virtual_mutex must be held by caller. */ -static NTSTATUS map_image_into_view( struct file_view *view, const WCHAR *filename, int fd, void *orig_base, +static NTSTATUS map_image_into_view( struct file_view *view, UNICODE_STRING *nt_name, int fd, void *orig_base, SIZE_T header_size, ULONG image_flags, int shared_fd, BOOL removable ) { IMAGE_DOS_HEADER *dos; @@ -2419,7 +2419,7 @@ static NTSTATUS map_image_into_view( struct file_view *view, const WCHAR *filena char *ptr = view->base; SIZE_T total_size = view->size; - TRACE_(module)( "mapping PE file %s at %p-%p\n", debugstr_w(filename), ptr, ptr + total_size ); + TRACE_(module)( "mapping PE file %s at %p-%p\n", debugstr_us(nt_name), ptr, ptr + total_size ); /* map the header */ @@ -2493,7 +2493,7 @@ static NTSTATUS map_image_into_view( struct file_view *view, const WCHAR *filena if (sec->VirtualAddress > total_size || end > total_size || end < sec->VirtualAddress) { WARN_(module)( "%s section %.8s too large (%x+%lx/%lx)\n", - debugstr_w(filename), sec->Name, (int)sec->VirtualAddress, map_size, total_size ); + debugstr_us(nt_name), sec->Name, (int)sec->VirtualAddress, map_size, total_size ); return status; } @@ -2501,13 +2501,13 @@ static NTSTATUS map_image_into_view( struct file_view *view, const WCHAR *filena (sec->Characteristics & IMAGE_SCN_MEM_WRITE)) { TRACE_(module)( "%s mapping shared section %.8s at %p off %x (%x) size %lx (%lx) flags %x\n", - debugstr_w(filename), sec->Name, ptr + sec->VirtualAddress, + debugstr_us(nt_name), sec->Name, ptr + sec->VirtualAddress, (int)sec->PointerToRawData, (int)pos, file_size, map_size, (int)sec->Characteristics ); if (map_file_into_view( view, shared_fd, sec->VirtualAddress, map_size, pos, VPROT_COMMITTED | VPROT_READ | VPROT_WRITE, FALSE ) != STATUS_SUCCESS) { - ERR_(module)( "Could not map %s shared section %.8s\n", debugstr_w(filename), sec->Name ); + ERR_(module)( "Could not map %s shared section %.8s\n", debugstr_us(nt_name), sec->Name ); return status; } @@ -2528,7 +2528,7 @@ static NTSTATUS map_image_into_view( struct file_view *view, const WCHAR *filena } TRACE_(module)( "mapping %s section %.8s at %p off %x size %x virt %x flags %x\n", - debugstr_w(filename), sec->Name, ptr + sec->VirtualAddress, + debugstr_us(nt_name), sec->Name, ptr + sec->VirtualAddress, (int)sec->PointerToRawData, (int)sec->SizeOfRawData, (int)sec->Misc.VirtualSize, (int)sec->Characteristics ); @@ -2546,7 +2546,7 @@ static NTSTATUS map_image_into_view( struct file_view *view, const WCHAR *filena removable ) != STATUS_SUCCESS) { ERR_(module)( "Could not map %s section %.8s, file probably truncated\n", - debugstr_w(filename), sec->Name ); + debugstr_us(nt_name), sec->Name ); return status; } @@ -2582,7 +2582,7 @@ static NTSTATUS map_image_into_view( struct file_view *view, const WCHAR *filena if (!set_vprot( view, ptr + sec->VirtualAddress, size, vprot ) && (vprot & VPROT_EXEC)) ERR( "failed to set %08x protection on %s section %.8s, noexec filesystem?\n", - (int)sec->Characteristics, debugstr_w(filename), sec->Name ); + (int)sec->Characteristics, debugstr_us(nt_name), sec->Name ); } #ifdef VALGRIND_LOAD_PDB_DEBUGINFO @@ -2647,7 +2647,7 @@ static unsigned int get_mapping_info( HANDLE handle, ACCESS_MASK access, unsigne */ static NTSTATUS virtual_map_image( HANDLE mapping, ACCESS_MASK access, void **addr_ptr, SIZE_T *size_ptr, ULONG_PTR zero_bits, HANDLE shared_file, ULONG alloc_type, - pe_image_info_t *image_info, WCHAR *filename, BOOL is_builtin ) + pe_image_info_t *image_info, UNICODE_STRING *nt_name, BOOL is_builtin ) { unsigned int vprot = SEC_IMAGE | SEC_FILE | VPROT_COMMITTED | VPROT_READ | VPROT_EXEC | VPROT_WRITECOPY; int unix_fd = -1, needs_close; @@ -2680,7 +2680,7 @@ static NTSTATUS virtual_map_image( HANDLE mapping, ACCESS_MASK access, void **ad if (status) status = map_view( &view, NULL, size, alloc_type & MEM_TOP_DOWN, vprot, get_zero_bits_mask( zero_bits ), 0 ); if (status) goto done; - status = map_image_into_view( view, filename, unix_fd, base, image_info->header_size, + status = map_image_into_view( view, nt_name, unix_fd, base, image_info->header_size, image_info->image_flags, shared_fd, needs_close ); if (status == STATUS_SUCCESS) { @@ -2725,7 +2725,6 @@ static unsigned int virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG_P ACCESS_MASK access; SIZE_T size; pe_image_info_t *image_info = NULL; - WCHAR *filename; void *base; int unix_handle = -1, needs_close; unsigned int vprot, sec_flags; @@ -2761,12 +2760,13 @@ static unsigned int virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG_P if (image_info) { - filename = (WCHAR *)(image_info + 1); + UNICODE_STRING nt_name; + init_unicode_string( &nt_name, (WCHAR *)(image_info + 1) ); /* check if we can replace that mapping with the builtin */ - res = load_builtin( image_info, filename, addr_ptr, size_ptr, zero_bits ); + res = load_builtin( image_info, &nt_name, addr_ptr, size_ptr, zero_bits ); if (res == STATUS_IMAGE_ALREADY_LOADED) res = virtual_map_image( handle, access, addr_ptr, size_ptr, zero_bits, shared_file, - alloc_type, image_info, filename, FALSE ); + alloc_type, image_info, &nt_name, FALSE ); if (shared_file) NtClose( shared_file ); free( image_info ); return res; @@ -3010,8 +3010,8 @@ NTSTATUS virtual_map_builtin_module( HANDLE mapping, void **module, SIZE_T *size HANDLE shared_file; pe_image_info_t *image_info = NULL; ACCESS_MASK access = SECTION_MAP_READ | SECTION_MAP_EXECUTE; + UNICODE_STRING nt_name; NTSTATUS status; - WCHAR *filename; if ((status = get_mapping_info( mapping, access, &sec_flags, &full_size, &shared_file, &image_info ))) return status; @@ -3020,27 +3020,27 @@ NTSTATUS virtual_map_builtin_module( HANDLE mapping, void **module, SIZE_T *size *module = NULL; *size = 0; - filename = (WCHAR *)(image_info + 1); + init_unicode_string( &nt_name, (WCHAR *)(image_info + 1) ); if (!(image_info->image_flags & IMAGE_FLAGS_WineBuiltin)) /* ignore non-builtins */ { - WARN( "%s found in WINEDLLPATH but not a builtin, ignoring\n", debugstr_w(filename) ); + WARN( "%s found in WINEDLLPATH but not a builtin, ignoring\n", debugstr_us(&nt_name) ); status = STATUS_DLL_NOT_FOUND; } else if (machine && image_info->machine != machine) { - TRACE( "%s is for arch %04x, continuing search\n", debugstr_w(filename), image_info->machine ); + TRACE( "%s is for arch %04x, continuing search\n", debugstr_us(&nt_name), image_info->machine ); status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH; } else if (prefer_native && (image_info->dll_charact & IMAGE_DLLCHARACTERISTICS_PREFER_NATIVE)) { - TRACE( "%s has prefer-native flag, ignoring builtin\n", debugstr_w(filename) ); + TRACE( "%s has prefer-native flag, ignoring builtin\n", debugstr_us(&nt_name) ); status = STATUS_IMAGE_ALREADY_LOADED; } else { status = virtual_map_image( mapping, SECTION_MAP_READ | SECTION_MAP_EXECUTE, - module, size, zero_bits, shared_file, 0, image_info, filename, TRUE ); + module, size, zero_bits, shared_file, 0, image_info, &nt_name, TRUE ); virtual_fill_image_information( image_info, info ); } From 5573f048e2f8a3dd7d2999fb801cb19e8bd5f3d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 5 Dec 2022 11:25:10 +0100 Subject: [PATCH 0972/2777] ntdll: Maintain a PE module link map and expose it to GDB. --- dlls/ntdll/unix/loader.c | 26 +++++++ dlls/ntdll/unix/unix_private.h | 1 + dlls/ntdll/unix/virtual.c | 5 ++ loader/main.c | 123 +++++++++++++++++++++++++++++++-- 4 files changed, 151 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index d4cb5266b64..f869a3acc24 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -1518,6 +1518,30 @@ static inline char *prepend_build_dir_path( char *ptr, const char *ext, const ch } +static void notify_gdb_dll_loaded( void *module, const char *unix_path ) +{ + static void (*wine_gdb_dll_loaded)( const void *module, const char *unix_path ); + if (!wine_gdb_dll_loaded) wine_gdb_dll_loaded = dlsym( RTLD_DEFAULT, "wine_gdb_dll_loaded" ); + if (wine_gdb_dll_loaded) wine_gdb_dll_loaded( module, unix_path ); +} + +void notify_gdb_native_dll_loaded( void *module, UNICODE_STRING *nt_name ) +{ + OBJECT_ATTRIBUTES attr; + UNICODE_STRING redir; + char *unix_path = NULL; + + InitializeObjectAttributes( &attr, nt_name, OBJ_CASE_INSENSITIVE, 0, 0 ); + get_redirect( &attr, &redir ); + + if (!nt_to_unix_file_name( &attr, &unix_path, FILE_OPEN )) + notify_gdb_dll_loaded( module, unix_path ); + + free( redir.Buffer ); + free( unix_path ); +} + + /*********************************************************************** * open_dll_file * @@ -1568,6 +1592,7 @@ static NTSTATUS open_builtin_pe_file( const char *name, OBJECT_ATTRIBUTES *attr, { status = virtual_map_builtin_module( mapping, module, size, image_info, zero_bits, machine, prefer_native ); NtClose( mapping ); + if (!status) notify_gdb_dll_loaded( *module, name ); } return status; } @@ -1698,6 +1723,7 @@ static NTSTATUS find_builtin_dll( UNICODE_STRING *nt_name, void **module, SIZE_T if (found_image) status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH; WARN( "cannot find builtin library for %s\n", debugstr_us(nt_name) ); + if (!status) notify_gdb_native_dll_loaded( *module, nt_name ); done: if (status >= 0 && ext) { diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index dcc4c64c508..d186d29d735 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -168,6 +168,7 @@ extern BOOL is_builtin_path( const UNICODE_STRING *path, WORD *machine ) DECLSPE extern NTSTATUS load_main_exe( const WCHAR *name, const char *unix_name, const WCHAR *curdir, WCHAR **image, void **module ) DECLSPEC_HIDDEN; extern NTSTATUS load_start_exe( WCHAR **image, void **module ) DECLSPEC_HIDDEN; +extern void notify_gdb_native_dll_loaded( void *module, UNICODE_STRING *nt_name ) DECLSPEC_HIDDEN; extern void start_server( BOOL debug ) DECLSPEC_HIDDEN; extern unsigned int server_call_unlocked( void *req_ptr ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index c3e6c7548d5..148d1a47855 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -2767,6 +2767,7 @@ static unsigned int virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG_P if (res == STATUS_IMAGE_ALREADY_LOADED) res = virtual_map_image( handle, access, addr_ptr, size_ptr, zero_bits, shared_file, alloc_type, image_info, &nt_name, FALSE ); + if (!res || res == STATUS_IMAGE_NOT_AT_BASE) notify_gdb_native_dll_loaded( *addr_ptr, &nt_name ); if (shared_file) NtClose( shared_file ); free( image_info ); return res; @@ -5294,6 +5295,10 @@ static NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr, ULONG flags ) SERVER_END_REQ; if (!status) { + static void (*wine_gdb_dll_unload)( const void *module ); + if (!wine_gdb_dll_unload) wine_gdb_dll_unload = dlsym( RTLD_DEFAULT, "wine_gdb_dll_unload" ); + if (wine_gdb_dll_unload) wine_gdb_dll_unload( view->base ); + if (view->protect & SEC_IMAGE) release_builtin_module( view->base ); if (flags & MEM_PRESERVE_PLACEHOLDER) { diff --git a/loader/main.c b/loader/main.c index b7805473da8..074fb153a94 100644 --- a/loader/main.c +++ b/loader/main.c @@ -20,6 +20,13 @@ #include "config.h" +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winnt.h" + #include #include #include @@ -40,6 +47,8 @@ # include #endif +#include "wine/list.h" + #include "main.h" extern char **environ; @@ -51,13 +60,31 @@ struct r_debug *wine_r_debug = NULL; #ifdef __linux__ +struct link_map_entry +{ + struct link_map map; + const void *module; + struct list entry; +}; + +static struct list pe_link_map_entries = LIST_INIT( pe_link_map_entries ); +static struct link_map so_link_map; +static struct link_map pe_link_map = {.l_prev = &so_link_map, .l_name = (char *)""}; static struct link_map so_link_map = {.l_name = (char *)""}; static pthread_mutex_t link_map_lock = PTHREAD_MUTEX_INITIALIZER; +static char *strdup_link_name( const char *path ) +{ + char *real; + if (!path || !(real = realpath( path, NULL ))) return NULL; + if (!strncmp( real, "/run/host", 9 )) memmove( real, real + 9, strlen( real ) - 8 ); + return real; +} + static void sync_wine_link_map(void) { static struct r_debug *_r_debug; - struct link_map *next = &so_link_map, *prev = NULL, **rtld_map, **wine_map; + struct link_map *next = &so_link_map, **rtld_map, **wine_map; if (!_r_debug) _r_debug = dlsym( RTLD_NEXT, "_r_debug" ); rtld_map = &_r_debug->r_map; @@ -65,17 +92,20 @@ static void sync_wine_link_map(void) pthread_mutex_lock( &link_map_lock ); + /* unlink PE link map */ + pe_link_map.l_prev->l_next = NULL; + while (*rtld_map) { if (!*wine_map) { if (!(*wine_map = calloc( 1, sizeof(struct link_map) ))) break; - (*wine_map)->l_prev = prev; + (*wine_map)->l_prev = pe_link_map.l_prev; } - prev = *wine_map; + pe_link_map.l_prev = *wine_map; (*wine_map)->l_addr = (*rtld_map)->l_addr; - (*wine_map)->l_name = strdup( (*rtld_map)->l_name ); + (*wine_map)->l_name = strdup_link_name( (*rtld_map)->l_name ); (*wine_map)->l_ld = (*rtld_map)->l_ld; rtld_map = &(*rtld_map)->l_next; wine_map = &(*wine_map)->l_next; @@ -95,12 +125,97 @@ static void sync_wine_link_map(void) free( prev ); } + /* link PE link map back */ + pe_link_map.l_prev->l_next = &pe_link_map; + pthread_mutex_unlock( &link_map_lock ); if (wine_r_debug) wine_r_debug->r_map = &so_link_map; if (wine_dl_debug_state) wine_dl_debug_state(); } +static void add_dll_to_pe_link_map( const void *module, const char *unix_path ) +{ + const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)module; + const IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)((const BYTE *)dos + dos->e_lfanew); + struct link_map_entry *entry; + struct link_map *map_end; + struct list *tail; + + if (!(entry = calloc( 1, sizeof(*entry) ))) return; + + entry->module = module; + entry->map.l_addr = (char *)module - (char *)nt->OptionalHeader.ImageBase; + entry->map.l_name = strdup_link_name( unix_path ); + + if ((tail = list_tail( &pe_link_map_entries ))) + { + entry->map.l_prev = &LIST_ENTRY( tail, struct link_map_entry, entry )->map; + entry->map.l_prev->l_next = &entry->map; + } + else + { + map_end = &pe_link_map; + while (map_end->l_next) map_end = map_end->l_next; + + map_end->l_next = &entry->map; + map_end->l_next->l_prev = map_end; + } + + list_add_tail( &pe_link_map_entries, &entry->entry ); +} + +void wine_gdb_dll_loaded( const void *module, const char *unix_path ) +{ + struct link_map_entry *entry; + + pthread_mutex_lock( &link_map_lock ); + + LIST_FOR_EACH_ENTRY( entry, &pe_link_map_entries, struct link_map_entry, entry ) + if (entry->module == module) break; + + if (&entry->entry == &pe_link_map_entries) + add_dll_to_pe_link_map( module, unix_path ); + else + { + const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)module; + const IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)((const BYTE *)dos + dos->e_lfanew); + entry->map.l_addr = (char *)module - (char *)nt->OptionalHeader.ImageBase; + } + + pthread_mutex_unlock( &link_map_lock ); + + sync_wine_link_map(); +} + +void wine_gdb_dll_unload( const void *module ) +{ + struct link_map_entry *entry; + + pthread_mutex_lock( &link_map_lock ); + + LIST_FOR_EACH_ENTRY( entry, &pe_link_map_entries, struct link_map_entry, entry ) + if (entry->module == module) break; + + if (&entry->entry == &pe_link_map_entries) + { + pthread_mutex_unlock( &link_map_lock ); + return; + } + + list_remove( &entry->entry ); + + if (entry->map.l_prev) entry->map.l_prev->l_next = entry->map.l_next; + if (entry->map.l_next) entry->map.l_next->l_prev = entry->map.l_prev; + + pthread_mutex_unlock( &link_map_lock ); + + sync_wine_link_map(); + + free( entry->map.l_name ); + free( entry ); +} + void *dlopen( const char *file, int mode ) { static typeof(dlopen) *rtld_dlopen; From 16bcefd1a48999fd97b5cdb4e69d70839102d194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 3 Dec 2022 08:03:58 +0100 Subject: [PATCH 0973/2777] HACK: winebus.sys: Introduce a new PROTON_ENABLE_HIDRAW environment variable. To easily enable hidraw for new devices. --- dlls/winebus.sys/bus_udev.c | 3 +-- dlls/winebus.sys/unix_private.h | 5 +--- dlls/winebus.sys/unixlib.c | 45 ++++++++++++++------------------- 3 files changed, 21 insertions(+), 32 deletions(-) diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 3f7eaba3790..d3c4b705968 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -1697,8 +1697,7 @@ static void udev_add_device(struct udev_device *dev, int fd) memcpy(desc.serialnumber, zeros, sizeof(zeros)); } - if (!is_dualshock4_gamepad(desc.vid, desc.pid) && !is_dualsense_gamepad(desc.vid, desc.pid) && !is_thrustmaster_hotas(desc.vid, desc.pid) && - !is_simucube_wheel(desc.vid, desc.pid) && !is_fanatec_pedals(desc.vid, desc.pid)) + if (!is_hidraw_enabled(desc.vid, desc.pid)) { TRACE("hidraw %s: deferring %s to a different backend\n", debugstr_a(devnode), debugstr_device_desc(&desc)); close(fd); diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index 64161f9e236..87c3d4ad626 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -268,12 +268,9 @@ extern void hid_device_set_effect_state(struct unix_device *iface, BYTE index, B BOOL is_sdl_blacklisted(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_wine_blacklisted(WORD vid, WORD pid) DECLSPEC_HIDDEN; -BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_dualshock4_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_dualsense_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_logitech_g920(WORD vid, WORD pid) DECLSPEC_HIDDEN; -BOOL is_thrustmaster_hotas(WORD vid, WORD pid) DECLSPEC_HIDDEN; -BOOL is_simucube_wheel(WORD vid, WORD pid) DECLSPEC_HIDDEN; -BOOL is_fanatec_pedals(WORD vid, WORD pid) DECLSPEC_HIDDEN; +BOOL is_hidraw_enabled(WORD vid, WORD pid) DECLSPEC_HIDDEN; #endif /* __WINEBUS_UNIX_PRIVATE_H */ diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c index 588ba7c2b93..d4adc78f6ec 100644 --- a/dlls/winebus.sys/unixlib.c +++ b/dlls/winebus.sys/unixlib.c @@ -62,29 +62,6 @@ BOOL is_sdl_blacklisted(WORD vid, WORD pid) return FALSE; } -BOOL is_xbox_gamepad(WORD vid, WORD pid) -{ - if (vid != 0x045e) return FALSE; - if (pid == 0x0202) return TRUE; /* Xbox Controller */ - if (pid == 0x0285) return TRUE; /* Xbox Controller S */ - if (pid == 0x0289) return TRUE; /* Xbox Controller S */ - if (pid == 0x028e) return TRUE; /* Xbox360 Controller */ - if (pid == 0x028f) return TRUE; /* Xbox360 Wireless Controller */ - if (pid == 0x02d1) return TRUE; /* Xbox One Controller */ - if (pid == 0x02dd) return TRUE; /* Xbox One Controller (Covert Forces/Firmware 2015) */ - if (pid == 0x02e0) return TRUE; /* Xbox One X Controller */ - if (pid == 0x02e3) return TRUE; /* Xbox One Elite Controller */ - if (pid == 0x02e6) return TRUE; /* Wireless XBox Controller Dongle */ - if (pid == 0x02ea) return TRUE; /* Xbox One S Controller */ - if (pid == 0x02fd) return TRUE; /* Xbox One S Controller (Firmware 2017) */ - if (pid == 0x0b00) return TRUE; /* Xbox Elite 2 */ - if (pid == 0x0b05) return TRUE; /* Xbox Elite 2 Wireless */ - if (pid == 0x0b12) return TRUE; /* Xbox Series */ - if (pid == 0x0b13) return TRUE; /* Xbox Series Wireless */ - if (pid == 0x0719) return TRUE; /* Xbox 360 Wireless Adapter */ - return FALSE; -} - BOOL is_dualshock4_gamepad(WORD vid, WORD pid) { if (vid != 0x054c) return FALSE; @@ -105,12 +82,12 @@ BOOL is_logitech_g920(WORD vid, WORD pid) return vid == 0x046D && pid == 0xC262; } -BOOL is_thrustmaster_hotas(WORD vid, WORD pid) +static BOOL is_thrustmaster_hotas(WORD vid, WORD pid) { return vid == 0x044F && (pid == 0xB679 || pid == 0xB687 || pid == 0xB10A); } -BOOL is_simucube_wheel(WORD vid, WORD pid) +static BOOL is_simucube_wheel(WORD vid, WORD pid) { if (vid != 0x16D0) return FALSE; if (pid == 0x0D61) return TRUE; /* Simucube 2 Sport */ @@ -120,7 +97,7 @@ BOOL is_simucube_wheel(WORD vid, WORD pid) return FALSE; } -BOOL is_fanatec_pedals(WORD vid, WORD pid) +static BOOL is_fanatec_pedals(WORD vid, WORD pid) { if (vid != 0x0EB7) return FALSE; if (pid == 0x183B) return TRUE; /* Fanatec ClubSport Pedals v3 */ @@ -128,6 +105,22 @@ BOOL is_fanatec_pedals(WORD vid, WORD pid) return FALSE; } +BOOL is_hidraw_enabled(WORD vid, WORD pid) +{ + const char *enabled = getenv("PROTON_ENABLE_HIDRAW"); + char needle[16]; + + if (is_dualshock4_gamepad(vid, pid)) return TRUE; + if (is_dualsense_gamepad(vid, pid)) return TRUE; + if (is_thrustmaster_hotas(vid, pid)) return TRUE; + if (is_simucube_wheel(vid, pid)) return TRUE; + if (is_fanatec_pedals(vid, pid)) return TRUE; + + sprintf(needle, "0x%04x/0x%04x", vid, pid); + if (enabled) return strcasestr(enabled, needle) != NULL; + return FALSE; +} + struct mouse_device { struct unix_device unix_device; From 0808ffee151e81662eec89280354d5650a5e2b78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 21 Dec 2022 12:31:49 +0100 Subject: [PATCH 0974/2777] dinput: Avoid sending envelope report if it has been removed. (cherry picked from commit 42082d4d3946a3911fe7b6f811b5001a5cb15f01) --- dlls/dinput/joystick_hid.c | 11 +++++++- dlls/dinput/tests/force_feedback.c | 40 ------------------------------ 2 files changed, 10 insertions(+), 41 deletions(-) diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index ab4a799ff9f..247e298b088 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -2708,7 +2708,9 @@ static HRESULT WINAPI hid_joystick_effect_SetParameters( IDirectInputEffect *ifa impl->params.cbTypeSpecificParams = params->cbTypeSpecificParams; } - if ((flags & DIEP_ENVELOPE) && params->lpEnvelope) + if (!(flags & DIEP_ENVELOPE)) + TRACE( "Keeping previous effect envelope\n" ); + else if (params->lpEnvelope) { if (params->lpEnvelope->dwSize != sizeof(DIENVELOPE)) return DIERR_INVALIDPARAM; impl->params.lpEnvelope = &impl->envelope; @@ -2716,6 +2718,13 @@ static HRESULT WINAPI hid_joystick_effect_SetParameters( IDirectInputEffect *ifa impl->modified |= DIEP_ENVELOPE; memcpy( impl->params.lpEnvelope, params->lpEnvelope, sizeof(DIENVELOPE) ); } + else + { + flags &= ~DIEP_ENVELOPE; + impl->flags &= ~DIEP_ENVELOPE; + impl->modified &= ~DIEP_ENVELOPE; + impl->params.lpEnvelope = NULL; + } if (flags & DIEP_DURATION) { diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c index 1e68748a07d..f6157a84df7 100644 --- a/dlls/dinput/tests/force_feedback.c +++ b/dlls/dinput/tests/force_feedback.c @@ -458,14 +458,6 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO .report_len = 2, .report_buf = {0x05,0x19}, }, - /* set envelope (wine) */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 6, - .report_len = 7, - .report_buf = {0x06,0x19,0x4c,0x01,0x00,0x04,0x00}, - .todo = TRUE, .wine_only = TRUE, - }, /* update effect */ { .code = IOCTL_HID_WRITE_REPORT, @@ -5683,14 +5675,6 @@ static void test_windows_gaming_input(void) .report_len = 10, .report_buf = {7,0x01,0x10,0x27,0x00,0x00,0x70,0xff,0xe8,0x03}, }, - /* set envelope (wine) */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 8, - .report_len = 8, - .report_buf = {8,0x01,0x00,0x00,0x00,0x00,0x00,0x00}, - .todo = TRUE, .wine_only = TRUE, - }, /* update effect */ { .code = IOCTL_HID_WRITE_REPORT, @@ -5822,14 +5806,6 @@ static void test_windows_gaming_input(void) .report_len = 4, .report_buf = {9,0x01,0x18,0xfc}, }, - /* set envelope (wine) */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 8, - .report_len = 8, - .report_buf = {8,0x01,0x00,0x00,0x00,0x00,0x00,0x00}, - .todo = TRUE, .wine_only = TRUE, - }, /* update effect (wine) */ { .code = IOCTL_HID_WRITE_REPORT, @@ -5908,14 +5884,6 @@ static void test_windows_gaming_input(void) .report_len = 6, .report_buf = {10,0x01,0xe8,0x03,0xa0,0x0f}, }, - /* set envelope (wine) */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 8, - .report_len = 8, - .report_buf = {8,0x01,0x00,0x00,0x00,0x00,0x00,0x00}, - .todo = TRUE, .wine_only = TRUE, - }, /* update effect (wine) */ { .code = IOCTL_HID_WRITE_REPORT, @@ -5956,14 +5924,6 @@ static void test_windows_gaming_input(void) .report_len = 6, .report_buf = {10,0x01,0x18,0xfc,0x60,0xf0}, }, - /* set envelope (wine) */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 8, - .report_len = 8, - .report_buf = {8,0x01,0x00,0x00,0x00,0x00,0x00,0x00}, - .todo = TRUE, .wine_only = TRUE, - }, /* update effect (wine) */ { .code = IOCTL_HID_WRITE_REPORT, From 377622d9b9cb94ec48ea07360046702ee2020ea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 21 Dec 2022 12:32:07 +0100 Subject: [PATCH 0975/2777] windows.gaming.input: Fix infinite effect duration scaling. (cherry picked from commit d79075eb0702ad9e7812704071bb88044eb8a35b) --- dlls/dinput/tests/force_feedback.c | 9 --------- dlls/windows.gaming.input/force_feedback.c | 16 ++++++++-------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c index f6157a84df7..6fdfa20c130 100644 --- a/dlls/dinput/tests/force_feedback.c +++ b/dlls/dinput/tests/force_feedback.c @@ -5884,21 +5884,12 @@ static void test_windows_gaming_input(void) .report_len = 6, .report_buf = {10,0x01,0xe8,0x03,0xa0,0x0f}, }, - /* update effect (wine) */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 3, - .report_len = 18, - .report_buf = {3,0x01,0x05,0x04,0x8f,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x01,0x00,0x00}, - .todo = TRUE, .wine_only = TRUE, - }, /* update effect */ { .code = IOCTL_HID_WRITE_REPORT, .report_id = 3, .report_len = 18, .report_buf = {3,0x01,0x05,0x04,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x01,0x00,0x00}, - .todo = TRUE, }, }; struct hid_expect expect_create_ramp_neg[] = diff --git a/dlls/windows.gaming.input/force_feedback.c b/dlls/windows.gaming.input/force_feedback.c index f7a233b46d4..d404934c3a7 100644 --- a/dlls/windows.gaming.input/force_feedback.c +++ b/dlls/windows.gaming.input/force_feedback.c @@ -124,8 +124,8 @@ static HRESULT WINAPI effect_impl_put_Parameters( IWineForceFeedbackEffectImpl * case WineForceFeedbackEffectType_Constant: impl->repeat_count = params.constant.repeat_count; impl->constant_force.lMagnitude = round( params.constant.gain * params.constant.direction.X * 10000 ); - impl->params.dwDuration = params.constant.duration.Duration / 10; - impl->params.dwStartDelay = params.constant.start_delay.Duration / 10; + impl->params.dwDuration = min( max( params.constant.duration.Duration / 10, 0 ), INFINITE ); + impl->params.dwStartDelay = min( max( params.constant.start_delay.Duration / 10, 0 ), INFINITE ); if (impl->axes[count] == DIJOFS_X) impl->directions[count++] = round( -params.constant.direction.X * 10000 ); if (impl->axes[count] == DIJOFS_Y) impl->directions[count++] = round( -params.constant.direction.Y * 10000 ); if (impl->axes[count] == DIJOFS_Z) impl->directions[count++] = round( -params.constant.direction.Z * 10000 ); @@ -135,8 +135,8 @@ static HRESULT WINAPI effect_impl_put_Parameters( IWineForceFeedbackEffectImpl * impl->repeat_count = params.ramp.repeat_count; impl->ramp_force.lStart = round( params.ramp.gain * params.ramp.start_vector.X * 10000 ); impl->ramp_force.lEnd = round( params.ramp.gain * params.ramp.end_vector.X * 10000 ); - impl->params.dwDuration = params.ramp.duration.Duration / 10; - impl->params.dwStartDelay = params.ramp.start_delay.Duration / 10; + impl->params.dwDuration = min( max( params.ramp.duration.Duration / 10, 0 ), INFINITE ); + impl->params.dwStartDelay = min( max( params.ramp.start_delay.Duration / 10, 0 ), INFINITE ); if (impl->axes[count] == DIJOFS_X) impl->directions[count++] = round( -params.ramp.start_vector.X * 10000 ); if (impl->axes[count] == DIJOFS_Y) impl->directions[count++] = round( -params.ramp.start_vector.Y * 10000 ); if (impl->axes[count] == DIJOFS_Z) impl->directions[count++] = round( -params.ramp.start_vector.Z * 10000 ); @@ -152,8 +152,8 @@ static HRESULT WINAPI effect_impl_put_Parameters( IWineForceFeedbackEffectImpl * impl->periodic.dwPeriod = 1000000 / params.periodic.frequency; impl->periodic.dwPhase = round( params.periodic.phase * 36000 ); impl->periodic.lOffset = round( params.periodic.bias * 10000 ); - impl->params.dwDuration = params.periodic.duration.Duration / 10; - impl->params.dwStartDelay = params.periodic.start_delay.Duration / 10; + impl->params.dwDuration = min( max( params.periodic.duration.Duration / 10, 0 ), INFINITE ); + impl->params.dwStartDelay = min( max( params.periodic.start_delay.Duration / 10, 0 ), INFINITE ); if (impl->axes[count] == DIJOFS_X) impl->directions[count++] = round( -params.periodic.direction.X * 10000 ); if (impl->axes[count] == DIJOFS_Y) impl->directions[count++] = round( -params.periodic.direction.Y * 10000 ); if (impl->axes[count] == DIJOFS_Z) impl->directions[count++] = round( -params.periodic.direction.Z * 10000 ); @@ -181,9 +181,9 @@ static HRESULT WINAPI effect_impl_put_Parameters( IWineForceFeedbackEffectImpl * if (!envelope) impl->params.lpEnvelope = NULL; else { - impl->envelope.dwAttackTime = envelope->attack_duration.Duration / 10; + impl->envelope.dwAttackTime = min( max( envelope->attack_duration.Duration / 10, 0 ), INFINITE ); impl->envelope.dwAttackLevel = round( envelope->attack_gain * 10000 ); - impl->envelope.dwFadeTime = impl->params.dwDuration - envelope->release_duration.Duration / 10; + impl->envelope.dwFadeTime = impl->params.dwDuration - min( max( envelope->release_duration.Duration / 10, 0 ), INFINITE ); impl->envelope.dwFadeLevel = round( envelope->release_gain * 10000 ); impl->params.lpEnvelope = &impl->envelope; } From 8ca0f42e5681dd0f31026b9cee31cadfc2516e1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 2 Jan 2023 13:48:20 +0100 Subject: [PATCH 0976/2777] windows.gaming.input: Introduce new effect_reorient_direction helper. (cherry picked from commit 9d06d700e85bde3e45001688b8299abc192cb1a7) --- dlls/windows.gaming.input/force_feedback.c | 63 +++++++++++++++++----- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/dlls/windows.gaming.input/force_feedback.c b/dlls/windows.gaming.input/force_feedback.c index d404934c3a7..20b022ff317 100644 --- a/dlls/windows.gaming.input/force_feedback.c +++ b/dlls/windows.gaming.input/force_feedback.c @@ -109,37 +109,74 @@ static ULONG WINAPI effect_impl_Release( IWineForceFeedbackEffectImpl *iface ) return ref; } +static int effect_reorient_direction( const WineForceFeedbackEffectParameters *params, Vector3 *direction ) +{ + int sign = +1; + + switch (params->type) + { + case WineForceFeedbackEffectType_Constant: + *direction = params->constant.direction; + break; + + case WineForceFeedbackEffectType_Ramp: + *direction = params->ramp.start_vector; + break; + + case WineForceFeedbackEffectType_Periodic_SineWave: + case WineForceFeedbackEffectType_Periodic_TriangleWave: + case WineForceFeedbackEffectType_Periodic_SquareWave: + case WineForceFeedbackEffectType_Periodic_SawtoothWaveDown: + case WineForceFeedbackEffectType_Periodic_SawtoothWaveUp: + *direction = params->periodic.direction; + break; + + case WineForceFeedbackEffectType_Condition_Spring: + case WineForceFeedbackEffectType_Condition_Damper: + case WineForceFeedbackEffectType_Condition_Inertia: + case WineForceFeedbackEffectType_Condition_Friction: + *direction = params->condition.direction; + sign = -1; + break; + } + + direction->X *= -sign; + direction->Y *= -sign; + direction->Z *= -sign; + + return sign; +} + static HRESULT WINAPI effect_impl_put_Parameters( IWineForceFeedbackEffectImpl *iface, WineForceFeedbackEffectParameters params, WineForceFeedbackEffectEnvelope *envelope ) { struct effect *impl = impl_from_IWineForceFeedbackEffectImpl( iface ); + Vector3 direction = {0}; DWORD count = 0; HRESULT hr; + int sign; TRACE( "iface %p, params %p, envelope %p.\n", iface, ¶ms, envelope ); EnterCriticalSection( &impl->cs ); + + sign = effect_reorient_direction( ¶ms, &direction ); + switch (params.type) { case WineForceFeedbackEffectType_Constant: impl->repeat_count = params.constant.repeat_count; - impl->constant_force.lMagnitude = round( params.constant.gain * params.constant.direction.X * 10000 ); + impl->constant_force.lMagnitude = -sign * round( params.constant.gain * direction.X * 10000 ); impl->params.dwDuration = min( max( params.constant.duration.Duration / 10, 0 ), INFINITE ); impl->params.dwStartDelay = min( max( params.constant.start_delay.Duration / 10, 0 ), INFINITE ); - if (impl->axes[count] == DIJOFS_X) impl->directions[count++] = round( -params.constant.direction.X * 10000 ); - if (impl->axes[count] == DIJOFS_Y) impl->directions[count++] = round( -params.constant.direction.Y * 10000 ); - if (impl->axes[count] == DIJOFS_Z) impl->directions[count++] = round( -params.constant.direction.Z * 10000 ); break; case WineForceFeedbackEffectType_Ramp: impl->repeat_count = params.ramp.repeat_count; - impl->ramp_force.lStart = round( params.ramp.gain * params.ramp.start_vector.X * 10000 ); + impl->ramp_force.lStart = -sign * round( params.ramp.gain * direction.X * 10000 ); impl->ramp_force.lEnd = round( params.ramp.gain * params.ramp.end_vector.X * 10000 ); impl->params.dwDuration = min( max( params.ramp.duration.Duration / 10, 0 ), INFINITE ); impl->params.dwStartDelay = min( max( params.ramp.start_delay.Duration / 10, 0 ), INFINITE ); - if (impl->axes[count] == DIJOFS_X) impl->directions[count++] = round( -params.ramp.start_vector.X * 10000 ); - if (impl->axes[count] == DIJOFS_Y) impl->directions[count++] = round( -params.ramp.start_vector.Y * 10000 ); - if (impl->axes[count] == DIJOFS_Z) impl->directions[count++] = round( -params.ramp.start_vector.Z * 10000 ); break; case WineForceFeedbackEffectType_Periodic_SineWave: @@ -154,9 +191,6 @@ static HRESULT WINAPI effect_impl_put_Parameters( IWineForceFeedbackEffectImpl * impl->periodic.lOffset = round( params.periodic.bias * 10000 ); impl->params.dwDuration = min( max( params.periodic.duration.Duration / 10, 0 ), INFINITE ); impl->params.dwStartDelay = min( max( params.periodic.start_delay.Duration / 10, 0 ), INFINITE ); - if (impl->axes[count] == DIJOFS_X) impl->directions[count++] = round( -params.periodic.direction.X * 10000 ); - if (impl->axes[count] == DIJOFS_Y) impl->directions[count++] = round( -params.periodic.direction.Y * 10000 ); - if (impl->axes[count] == DIJOFS_Z) impl->directions[count++] = round( -params.periodic.direction.Z * 10000 ); break; case WineForceFeedbackEffectType_Condition_Spring: @@ -172,12 +206,13 @@ static HRESULT WINAPI effect_impl_put_Parameters( IWineForceFeedbackEffectImpl * impl->condition.lOffset = round( params.condition.bias * 10000 ); impl->params.dwDuration = -1; impl->params.dwStartDelay = 0; - if (impl->axes[count] == DIJOFS_X) impl->directions[count++] = round( params.condition.direction.X * 10000 ); - if (impl->axes[count] == DIJOFS_Y) impl->directions[count++] = round( params.condition.direction.Y * 10000 ); - if (impl->axes[count] == DIJOFS_Z) impl->directions[count++] = round( params.condition.direction.Z * 10000 ); break; } + if (impl->axes[count] == DIJOFS_X) impl->directions[count++] = round( direction.X * 10000 ); + if (impl->axes[count] == DIJOFS_Y) impl->directions[count++] = round( direction.Y * 10000 ); + if (impl->axes[count] == DIJOFS_Z) impl->directions[count++] = round( direction.Z * 10000 ); + if (!envelope) impl->params.lpEnvelope = NULL; else { From 731be6cb5625b963852f613c1ac95d6c07fff799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 2 Jan 2023 13:48:20 +0100 Subject: [PATCH 0977/2777] windows.gaming.input: Fix magnitude sign for constant and ramp effects. The magnitude already carries the sign of X direction. Having a signed direction will inverse the effective direction. The Y and Z direction sign and magnitude seem to be ignored. (cherry picked from commit 4466e2c24c45ad483201562ebe37d1ffc0eb966d) --- dlls/dinput/tests/force_feedback.c | 18 ------------------ dlls/windows.gaming.input/force_feedback.c | 9 +++++++-- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c index 6fdfa20c130..5ffc6a43471 100644 --- a/dlls/dinput/tests/force_feedback.c +++ b/dlls/dinput/tests/force_feedback.c @@ -5806,21 +5806,12 @@ static void test_windows_gaming_input(void) .report_len = 4, .report_buf = {9,0x01,0x18,0xfc}, }, - /* update effect (wine) */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 3, - .report_len = 18, - .report_buf = {3,0x01,0x04,0x04,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x7f,0x99,0x00,0x00,0x00}, - .wine_only = TRUE, .todo = TRUE, - }, /* update effect */ { .code = IOCTL_HID_WRITE_REPORT, .report_id = 3, .report_len = 18, .report_buf = {3,0x01,0x04,0x04,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x7f,0x4e,0x01,0x00,0x00}, - .todo = TRUE, }, }; struct hid_expect expect_create_ramp[] = @@ -5915,21 +5906,12 @@ static void test_windows_gaming_input(void) .report_len = 6, .report_buf = {10,0x01,0x18,0xfc,0x60,0xf0}, }, - /* update effect (wine) */ - { - .code = IOCTL_HID_WRITE_REPORT, - .report_id = 3, - .report_len = 18, - .report_buf = {3,0x01,0x05,0x04,0x8f,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x99,0x00,0x00,0x00}, - .wine_only = TRUE, .todo = TRUE, - }, /* update effect */ { .code = IOCTL_HID_WRITE_REPORT, .report_id = 3, .report_len = 18, .report_buf = {3,0x01,0x05,0x04,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x01,0x00,0x00}, - .todo = TRUE, }, }; struct hid_expect expect_effect_start = diff --git a/dlls/windows.gaming.input/force_feedback.c b/dlls/windows.gaming.input/force_feedback.c index 20b022ff317..cff3c184bf9 100644 --- a/dlls/windows.gaming.input/force_feedback.c +++ b/dlls/windows.gaming.input/force_feedback.c @@ -117,10 +117,12 @@ static int effect_reorient_direction( const WineForceFeedbackEffectParameters *p { case WineForceFeedbackEffectType_Constant: *direction = params->constant.direction; + sign = params->constant.direction.X < 0 ? -1 : +1; break; case WineForceFeedbackEffectType_Ramp: *direction = params->ramp.start_vector; + sign = params->ramp.start_vector.X < 0 ? -1 : +1; break; case WineForceFeedbackEffectType_Periodic_SineWave: @@ -152,6 +154,7 @@ static HRESULT WINAPI effect_impl_put_Parameters( IWineForceFeedbackEffectImpl * { struct effect *impl = impl_from_IWineForceFeedbackEffectImpl( iface ); Vector3 direction = {0}; + double magnitude = 0; DWORD count = 0; HRESULT hr; int sign; @@ -161,19 +164,21 @@ static HRESULT WINAPI effect_impl_put_Parameters( IWineForceFeedbackEffectImpl * EnterCriticalSection( &impl->cs ); sign = effect_reorient_direction( ¶ms, &direction ); + /* Y and Z axes seems to be always ignored, is it really the case? */ + magnitude += direction.X * direction.X; switch (params.type) { case WineForceFeedbackEffectType_Constant: impl->repeat_count = params.constant.repeat_count; - impl->constant_force.lMagnitude = -sign * round( params.constant.gain * direction.X * 10000 ); + impl->constant_force.lMagnitude = sign * round( params.constant.gain * sqrt( magnitude ) * 10000 ); impl->params.dwDuration = min( max( params.constant.duration.Duration / 10, 0 ), INFINITE ); impl->params.dwStartDelay = min( max( params.constant.start_delay.Duration / 10, 0 ), INFINITE ); break; case WineForceFeedbackEffectType_Ramp: impl->repeat_count = params.ramp.repeat_count; - impl->ramp_force.lStart = -sign * round( params.ramp.gain * direction.X * 10000 ); + impl->ramp_force.lStart = sign * round( params.ramp.gain * sqrt( magnitude ) * 10000 ); impl->ramp_force.lEnd = round( params.ramp.gain * params.ramp.end_vector.X * 10000 ); impl->params.dwDuration = min( max( params.ramp.duration.Duration / 10, 0 ), INFINITE ); impl->params.dwStartDelay = min( max( params.ramp.start_delay.Duration / 10, 0 ), INFINITE ); From c733f5550fdd0bbb58e88ed87472a9d9d614e63d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 6 Sep 2022 22:01:26 +0200 Subject: [PATCH 0978/2777] mf: Discard end of presentation on IMFMediaSession_Stop. MR !607 was trying to fix an issue with Life Is Strange Remastered, but although it fixed some race conditions with presentation end, the issue it was trying to fix is still there. The game calls IMFMediaSession_Stop while the presentation is ending, expects that command to quickly execute, interrupting the presentation end and emitting a MESessionStopped event instead of the MESessionEnded. Delaying the Stop command and emitting the MESessionEnded event breaks the game assumptions and it crashes. CW-Bug-Id: #20916 --- dlls/mf/session.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 9c746c9f5ef..1edd380e983 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -2526,6 +2526,13 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, EnterCriticalSection(&session->cs); + if ((session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION) && op->command != SESSION_CMD_STOP) + { + WARN("session %p command is ending, waiting for it to complete.\n", session); + LeaveCriticalSection(&session->cs); + return S_OK; + } + if (session->presentation.flags & SESSION_FLAG_PENDING_COMMAND) { WARN("session %p command is in progress, waiting for it to complete.\n", session); @@ -2552,6 +2559,9 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, session_pause(session); break; case SESSION_CMD_STOP: + if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION) + session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED); + session_clear_end_of_presentation(session); session_stop(session); break; case SESSION_CMD_CLOSE: @@ -3523,7 +3533,7 @@ static void session_raise_end_of_presentation(struct media_session *session) { if (session_nodes_is_mask_set(session, MF_TOPOLOGY_MAX, SOURCE_FLAG_END_OF_PRESENTATION)) { - session->presentation.flags |= SESSION_FLAG_END_OF_PRESENTATION | SESSION_FLAG_PENDING_COMMAND; + session->presentation.flags |= SESSION_FLAG_END_OF_PRESENTATION; IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, NULL); } } From 46514a4cea16cb2031c71705a911cf13d64ad15d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 11 Jan 2023 18:42:15 +0100 Subject: [PATCH 0979/2777] ntdll: Ignore unsupported Unix locales and initialize regardless. We shouldn't rely very much on Unix locale anymore, and not having the Unix locale configured shouldn't prevent us from running applications in a localized Windows environment if they need it. CW-Bug-Id: #21346 --- dlls/ntdll/unix/env.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c index a388aa7168c..9e5abc3c4fe 100644 --- a/dlls/ntdll/unix/env.c +++ b/dlls/ntdll/unix/env.c @@ -59,6 +59,7 @@ #include "error.h" WINE_DEFAULT_DEBUG_CHANNEL(environ); +WINE_DECLARE_DEBUG_CHANNEL(nls); PEB *peb = NULL; WOW_PEB *wow_peb = NULL; @@ -277,13 +278,14 @@ static const struct { const char *name; UINT cp; } charset_names[] = static void init_unix_codepage(void) { + const char *name, *ctype; char charset_name[16]; - const char *name; size_t i, j; int min = 0, max = ARRAY_SIZE(charset_names) - 1; - setlocale( LC_CTYPE, "" ); - if (!(name = nl_langinfo( CODESET ))) return; + if (!(ctype = setlocale( LC_CTYPE, "" ))) name = "UTF-8"; + else if (!(name = nl_langinfo( CODESET ))) return; + TRACE_(nls)( "Unix LC_CTYPE %s, using %s codeset\n", debugstr_a(ctype), debugstr_a(name) ); /* remove punctuation characters from charset name */ for (i = j = 0; name[i] && j < sizeof(charset_name)-1; i++) @@ -800,12 +802,21 @@ static const NLS_LOCALE_DATA *get_win_locale( const NLS_LOCALE_HEADER *header, c static void init_locale(void) { struct locale_nls_header *header; + const char *all, *ctype, *messages; const NLS_LOCALE_HEADER *locale_table; const NLS_LOCALE_DATA *locale; - setlocale( LC_ALL, "" ); - if (!unix_to_win_locale( setlocale( LC_CTYPE, NULL ), system_locale )) system_locale[0] = 0; - if (!unix_to_win_locale( setlocale( LC_MESSAGES, NULL ), user_locale )) user_locale[0] = 0; + if (!(all = setlocale( LC_ALL, "" )) && (all = getenv( "LC_ALL" ))) + FIXME_(nls)( "Failed to set LC_ALL to %s, is the locale supported?\n", debugstr_a(all) ); + if (!(ctype = setlocale( LC_CTYPE, "" )) && (ctype = getenv( "LC_CTYPE" ))) + FIXME_(nls)( "Failed to set LC_CTYPE to %s, is the locale supported?\n", debugstr_a(ctype) ); + if (!(messages = setlocale( LC_MESSAGES, "" )) && (messages = getenv( "LC_MESSAGES" ))) + FIXME_(nls)( "Failed to set LC_MESSAGES to %s, is the locale supported?\n", debugstr_a(messages) ); + + if (!unix_to_win_locale( ctype, system_locale )) system_locale[0] = 0; + TRACE_(nls)( "Unix LC_CTYPE is %s, setting system locale to %s\n", debugstr_a(ctype), debugstr_a(user_locale) ); + if (!unix_to_win_locale( messages, user_locale )) user_locale[0] = 0; + TRACE_(nls)( "Unix LC_MESSAGES is %s, user system locale to %s\n", debugstr_a(messages), debugstr_a(user_locale) ); #ifdef __APPLE__ if (!system_locale[0]) From 671e9f996519cc6bbfecc7fafee9eb759ad2d2a2 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 12 Jan 2023 14:54:20 -0600 Subject: [PATCH 0980/2777] winex11.drv: Cache clip window. CW-Bug-Id: #21761 --- dlls/winex11.drv/mouse.c | 41 ++++++++++++++++++++++++++++++--------- dlls/winex11.drv/x11drv.h | 1 + 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 4142536b96f..739960b083e 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -152,6 +152,34 @@ MAKE_FUNCPTR(XGetDeviceButtonMapping); #undef MAKE_FUNCPTR #endif +static HWND get_clip_hwnd(void) +{ + static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0}; + struct x11drv_thread_data *data = x11drv_thread_data(); + UNICODE_STRING class_name; + HWND ret; + + if (data->cached_clip_hwnd) + { + ret = data->cached_clip_hwnd; + data->cached_clip_hwnd = NULL; + return ret; + } + RtlInitUnicodeString( &class_name, messageW ); + return NtUserCreateWindowEx( 0, &class_name, &class_name, NULL, 0, 0, 0, 0, 0, + HWND_MESSAGE, 0, NtCurrentTeb()->Peb->ImageBaseAddress, + NULL, 0, NULL, 0, FALSE ); +} + +static void release_clip_hwnd( HWND hwnd ) +{ + struct x11drv_thread_data *data = x11drv_thread_data(); + + if (data->cached_clip_hwnd) + NtUserDestroyWindow( data->cached_clip_hwnd ); + data->cached_clip_hwnd = hwnd; +} + /*********************************************************************** * X11DRV_Xcursor_Init * @@ -436,9 +464,7 @@ void X11DRV_XInput2_Enable( Display *display, Window window, long event_mask ) static BOOL grab_clipping_window( const RECT *clip ) { #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0}; struct x11drv_thread_data *data = x11drv_thread_data(); - UNICODE_STRING class_name; Window clip_window; HWND msg_hwnd = 0; POINT pos; @@ -450,10 +476,7 @@ static BOOL grab_clipping_window( const RECT *clip ) if (!data) return FALSE; if (!(clip_window = init_clip_window())) return TRUE; - RtlInitUnicodeString( &class_name, messageW ); - if (!(msg_hwnd = NtUserCreateWindowEx( 0, &class_name, &class_name, NULL, 0, 0, 0, 0, 0, - HWND_MESSAGE, 0, NtCurrentTeb()->Peb->ImageBaseAddress, - NULL, 0, NULL, 0, FALSE ))) + if (!(msg_hwnd = get_clip_hwnd())) return TRUE; /* enable XInput2 unless we are already clipping */ @@ -492,7 +515,7 @@ static BOOL grab_clipping_window( const RECT *clip ) if (!clipping_cursor) { X11DRV_XInput2_Enable( data->display, None, 0 ); - NtUserDestroyWindow( msg_hwnd ); + release_clip_hwnd( msg_hwnd ); return FALSE; } clip_rect = *clip; @@ -565,7 +588,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) data->clip_hwnd = 0; data->clip_reset = NtGetTickCount(); X11DRV_XInput2_Enable( data->display, None, 0 ); - NtUserDestroyWindow( hwnd ); + release_clip_hwnd( hwnd ); } else if (prev_clip_hwnd) { @@ -573,7 +596,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) * dangling clip window. */ TRACE( "destroying old clip hwnd %p\n", prev_clip_hwnd ); - NtUserDestroyWindow( prev_clip_hwnd ); + release_clip_hwnd( prev_clip_hwnd ); } return 0; } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 20aeebcab94..ca500c3d96d 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -399,6 +399,7 @@ struct x11drv_thread_data int xi2_active_touches; int xi2_primary_touchid; #endif /* HAVE_X11_EXTENSIONS_XINPUT2_H */ + HWND cached_clip_hwnd; }; extern struct x11drv_thread_data *x11drv_init_thread_data(void) DECLSPEC_HIDDEN; From 549d7fedb4d2c342aa1680feaf1dde342de5545e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 12 Jan 2023 16:56:13 -0600 Subject: [PATCH 0981/2777] win32u: Limit the frequency of update_display_cache() calls. CW-Bug-Id: #21761 --- dlls/win32u/ntuser_private.h | 6 +++++ dlls/win32u/sysparams.c | 27 ++++++++++++++++++++- dlls/win32u/winstation.c | 47 ++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index c86b5010383..7cbdbc91f42 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -252,6 +252,12 @@ void release_user_handle_ptr( void *ptr ) DECLSPEC_HIDDEN; UINT win_set_flags( HWND hwnd, UINT set_mask, UINT clear_mask ) DECLSPEC_HIDDEN; /* winstation.c */ +struct global_shared_memory +{ + ULONG display_settings_serial; +}; + +extern volatile struct global_shared_memory *get_global_shared_memory( void ) DECLSPEC_HIDDEN; extern volatile struct desktop_shared_memory *get_desktop_shared_memory( void ) DECLSPEC_HIDDEN; extern volatile struct queue_shared_memory *get_queue_shared_memory( void ) DECLSPEC_HIDDEN; extern volatile struct input_shared_memory *get_input_shared_memory( void ) DECLSPEC_HIDDEN; diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 94d5f73ce90..dd9059a0dd4 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -856,6 +856,7 @@ static void reg_empty_key( HKEY root, const char *key_name ) static void prepare_devices(void) { + volatile struct global_shared_memory *global_shared = get_global_shared_memory(); char buffer[4096]; KEY_NODE_INFORMATION *key = (void *)buffer; KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer; @@ -865,6 +866,8 @@ static void prepare_devices(void) DWORD size; HKEY hkey, subkey, device_key, prop_key; + if (global_shared) InterlockedIncrement( (LONG *)&global_shared->display_settings_serial ); + if (!enum_key) enum_key = reg_create_key( NULL, enum_keyW, sizeof(enum_keyW), 0, NULL ); if (!control_key) control_key = reg_create_key( NULL, control_keyW, sizeof(control_keyW), 0, NULL ); if (!video_key) video_key = reg_create_key( NULL, devicemap_video_keyW, sizeof(devicemap_video_keyW), @@ -1559,11 +1562,24 @@ static BOOL update_display_cache_from_registry(void) static BOOL update_display_cache( BOOL force ) { - HWINSTA winstation = NtUserGetProcessWindowStation(); + static ULONG last_update_serial; + + volatile struct global_shared_memory *global_shared = get_global_shared_memory(); + ULONG current_serial, global_serial; + HWINSTA winstation; struct device_manager_ctx ctx = {0}; USEROBJECTFLAGS flags; + __WINE_ATOMIC_LOAD_RELAXED( &last_update_serial, ¤t_serial ); + if (global_shared) + { + __WINE_ATOMIC_LOAD_RELAXED( &global_shared->display_settings_serial, &global_serial ); + if (!force && current_serial && current_serial == global_serial) return TRUE; + } + else global_serial = 0; + /* services do not have any adapters, only a virtual monitor */ + winstation = NtUserGetProcessWindowStation(); if (NtUserGetObjectInformation( winstation, UOI_FLAGS, &flags, sizeof(flags), NULL ) && !(flags.dwFlags & WSF_VISIBLE)) { @@ -1571,6 +1587,7 @@ static BOOL update_display_cache( BOOL force ) clear_display_devices(); list_add_tail( &monitors, &virtual_monitor.entry ); pthread_mutex_unlock( &display_lock ); + InterlockedCompareExchange( (LONG *)&last_update_serial, global_serial, current_serial ); return TRUE; } @@ -1642,6 +1659,7 @@ static BOOL update_display_cache( BOOL force ) return update_display_cache( TRUE ); } + InterlockedCompareExchange( (LONG *)&last_update_serial, global_serial, current_serial ); return TRUE; } @@ -1956,6 +1974,7 @@ RECT get_primary_monitor_rect( UINT dpi ) LONG WINAPI NtUserGetDisplayConfigBufferSizes( UINT32 flags, UINT32 *num_path_info, UINT32 *num_mode_info ) { + volatile struct global_shared_memory *global_shared; struct monitor *monitor; UINT32 count = 0; @@ -1980,6 +1999,10 @@ LONG WINAPI NtUserGetDisplayConfigBufferSizes( UINT32 flags, UINT32 *num_path_in if (flags != QDC_ONLY_ACTIVE_PATHS) FIXME( "only returning active paths\n" ); + /* NtUserGetDisplayConfigBufferSizes() is called by display drivers to trigger display settings update. */ + if ((global_shared = get_global_shared_memory())) + InterlockedIncrement( (LONG *)&global_shared->display_settings_serial ); + if (lock_display_devices()) { LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry ) @@ -2481,6 +2504,7 @@ static BOOL all_detached_settings( const DEVMODEW *displays ) static LONG apply_display_settings( const WCHAR *devname, const DEVMODEW *devmode, HWND hwnd, DWORD flags, void *lparam ) { + volatile struct global_shared_memory *global_shared = get_global_shared_memory(); WCHAR primary_name[CCHDEVICENAME]; struct display_device *primary; DEVMODEW *mode, *displays; @@ -2524,6 +2548,7 @@ static LONG apply_display_settings( const WCHAR *devname, const DEVMODEW *devmod free( displays ); if (ret) return ret; + if (global_shared) InterlockedIncrement( (LONG *)&global_shared->display_settings_serial ); if (!update_display_cache( TRUE )) WARN( "Failed to update display cache after mode change.\n" ); diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index a695365b8f1..3996b4fcf73 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -600,6 +600,53 @@ static void map_shared_memory_section( const WCHAR *name, SIZE_T size, HANDLE ro } } +volatile struct global_shared_memory *get_global_shared_memory( void ) +{ + static const WCHAR global_mappingW[] = + { + '\\','?','?','\\','_','_','w','i','n','e','_','w','i','n','3','2','u','_','m','a','p','p','i','n','g',0 + }; + static struct global_shared_memory *global_shared; + struct global_shared_memory *ret; + UNICODE_STRING section_str; + OBJECT_ATTRIBUTES attr; + LARGE_INTEGER size_l; + unsigned int status; + HANDLE handle; + SIZE_T size; + + __WINE_ATOMIC_LOAD_RELAXED( &global_shared, &ret ); + if (ret) return ret; + + RtlInitUnicodeString( §ion_str, global_mappingW ); + InitializeObjectAttributes( &attr, §ion_str, OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT, NULL, NULL ); + size_l.QuadPart = sizeof(struct global_shared_memory); + status = NtCreateSection( &handle, SECTION_ALL_ACCESS, &attr, &size_l, PAGE_READWRITE, SEC_COMMIT, NULL ); + if (status && status != STATUS_OBJECT_NAME_EXISTS) + { + static int once; + if (!once++) + ERR( "Failed to get global shared memory, status %#x.\n", status ); + } + size = sizeof(struct global_shared_memory); + status = NtMapViewOfSection( handle, GetCurrentProcess(), (void **)&ret, 0, 0, NULL, + &size, ViewUnmap, 0, PAGE_READWRITE ); + NtClose( handle ); + if (status) + { + ERR( "failed to map view of section, status %#x\n", status ); + return NULL; + } + if (InterlockedCompareExchangePointer( (void **)&global_shared, ret, NULL )) + { + if (NtUnmapViewOfSection( GetCurrentProcess(), ret )) + ERR( "NtUnmapViewOfSection failed.\n" ); + ret = global_shared; + } + + return ret; +} + volatile struct desktop_shared_memory *get_desktop_shared_memory( void ) { static const WCHAR dir_desktop_maps[] = From 51a1db2755be4edf30c6ba523f79c7d890fd9246 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 12 Jan 2023 19:02:11 -0600 Subject: [PATCH 0982/2777] win32u: Avoid calling server in NtUserGetKeyState() when input keystate is in sync. CW-Bug-Id: #21761 --- dlls/win32u/input.c | 16 ++++++++++++++-- server/protocol.def | 2 ++ server/queue.c | 4 ++++ server/winstation.c | 6 +++++- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 4267a590bfc..77f81248c6d 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -401,6 +401,7 @@ HKL WINAPI NtUserGetKeyboardLayout( DWORD thread_id ) SHORT WINAPI NtUserGetKeyState( INT vkey ) { volatile struct input_shared_memory *shared = get_input_shared_memory(); + volatile struct desktop_shared_memory *desktop_shared; SHORT retval = 0; BOOL skip = TRUE; @@ -408,8 +409,19 @@ SHORT WINAPI NtUserGetKeyState( INT vkey ) else SHARED_READ_BEGIN( &shared->seq ) { if (!shared->created) skip = FALSE; /* server needs to create the queue */ - else if (!shared->keystate_lock) skip = FALSE; /* server needs to call sync_input_keystate */ - else retval = (signed char)(shared->keystate[vkey & 0xff] & 0x81); + else if (!shared->keystate_lock) + { + desktop_shared = get_desktop_shared_memory(); + if (!desktop_shared) skip = FALSE; + else SHARED_READ_BEGIN( &desktop_shared->seq ) + { + if (shared->sync_serial != desktop_shared->update_serial) + skip = FALSE; /* server needs to call sync_input_keystate */ + } + SHARED_READ_END( &desktop_shared->seq ); + } + if (skip) + retval = (signed char)(shared->keystate[vkey & 0xff] & 0x81); } SHARED_READ_END( &shared->seq ); diff --git a/server/protocol.def b/server/protocol.def index deb246584e4..c21f86d3d49 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -886,6 +886,7 @@ struct desktop_shared_memory struct shared_cursor cursor; /* global cursor information */ unsigned char keystate[256]; /* asynchronous key state */ thread_id_t foreground_tid; /* tid of the foreground thread */ + __int64 update_serial; }; struct queue_shared_memory @@ -915,6 +916,7 @@ struct input_shared_memory int cursor_count; /* cursor show count */ unsigned char keystate[256]; /* key state */ int keystate_lock; /* keystate is locked */ + __int64 sync_serial; }; /* Bits that must be clear for client to read */ diff --git a/server/queue.c b/server/queue.c index 72abbc080d0..5ed75964e0f 100644 --- a/server/queue.c +++ b/server/queue.c @@ -409,6 +409,7 @@ static void sync_input_keystate( struct thread_input *input ) if (input->desktop_keystate[i] == input->desktop->shared->keystate[i]) continue; input->shared->keystate[i] = input->desktop_keystate[i] = input->desktop->shared->keystate[i]; } + input->shared->sync_serial = input->desktop->shared->update_serial; SHARED_WRITE_END( &input->shared->seq ); } @@ -1623,6 +1624,7 @@ static void update_input_key_state( struct thread_input *input, unsigned int msg static void update_desktop_key_state( struct desktop *desktop, unsigned int msg, lparam_t wparam ) { SHARED_WRITE_BEGIN( &desktop->shared->seq ); + ++desktop->shared->update_serial; update_key_state( desktop->shared->keystate, msg, wparam, 1 ); SHARED_WRITE_END( &desktop->shared->seq ); } @@ -3441,6 +3443,7 @@ DECL_HANDLER(get_key_state) { reply->state = desktop->shared->keystate[req->key & 0xff]; SHARED_WRITE_BEGIN( &desktop->shared->seq ); + ++desktop->shared->update_serial; desktop->shared->keystate[req->key & 0xff] &= ~0x40; SHARED_WRITE_END( &desktop->shared->seq ); } @@ -3476,6 +3479,7 @@ DECL_HANDLER(set_key_state) if (req->async && (desktop = get_thread_desktop( current, 0 ))) { SHARED_WRITE_BEGIN( &desktop->shared->seq ); + ++desktop->shared->update_serial; memcpy( (void *)desktop->shared->keystate, get_req_data(), size ); SHARED_WRITE_END( &desktop->shared->seq ); release_object( desktop ); diff --git a/server/winstation.c b/server/winstation.c index 2f009d5ea15..52da03c3718 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -232,7 +232,11 @@ static volatile void *init_desktop_mapping( struct desktop *desktop, const struc desktop->shared_mapping = create_shared_mapping( dir, name, sizeof(struct desktop_shared_memory), NULL, (void **)&desktop->shared ); release_object( dir ); - if (desktop->shared_mapping) memset( (void *)desktop->shared, 0, sizeof(*desktop->shared) ); + if (desktop->shared_mapping) + { + memset( (void *)desktop->shared, 0, sizeof(*desktop->shared) ); + desktop->shared->update_serial = 1; + } return desktop->shared; } From 0de7c50ed48d341b4df13d1895ef7603f926da4c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 13 Jan 2023 18:36:25 -0600 Subject: [PATCH 0983/2777] win32u: Stop leaking shared data memory. And close section handles right away. CW-Bug-Id: #21761 --- dlls/win32u/ntuser_private.h | 4 ---- dlls/win32u/sysparams.c | 18 +++++++----------- dlls/win32u/winstation.c | 33 ++++++++++++++------------------- 3 files changed, 21 insertions(+), 34 deletions(-) diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 7cbdbc91f42..4c92480b476 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -137,13 +137,9 @@ struct user_thread_info UINT kbd_layout_id; /* Current keyboard layout ID */ struct rawinput_thread_data *rawinput; /* RawInput thread local data / buffer */ UINT spy_indent; /* Current spy indent */ - HANDLE desktop_shared_map; /* HANDLE to server's desktop shared memory */ struct desktop_shared_memory *desktop_shared_memory; /* Ptr to server's desktop shared memory */ - HANDLE queue_shared_map; /* HANDLE to server's thread queue shared memory */ struct queue_shared_memory *queue_shared_memory; /* Ptr to server's thread queue shared memory */ - HANDLE input_shared_map; /* HANDLE to server's thread input shared memory */ struct input_shared_memory *input_shared_memory; /* Ptr to server's thread input shared memory */ - HANDLE foreground_shared_map; /* HANDLE to server's thread input shared memory */ struct input_shared_memory *foreground_shared_memory; /* Ptr to server's thread input shared memory */ }; diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index dd9059a0dd4..cba0052577d 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -5460,31 +5460,27 @@ static void thread_detach(void) cleanup_imm_thread(); NtClose( thread_info->server_queue ); - if (thread_info->desktop_shared_map) + if (thread_info->desktop_shared_memory) { - NtClose( thread_info->desktop_shared_map ); - thread_info->desktop_shared_map = NULL; + NtUnmapViewOfSection( GetCurrentProcess(), thread_info->desktop_shared_memory ); thread_info->desktop_shared_memory = NULL; } - if (thread_info->queue_shared_map) + if (thread_info->queue_shared_memory) { - NtClose( thread_info->queue_shared_map ); - thread_info->queue_shared_map = NULL; + NtUnmapViewOfSection( GetCurrentProcess(), thread_info->queue_shared_memory ); thread_info->queue_shared_memory = NULL; } - if (thread_info->input_shared_map) + if (thread_info->input_shared_memory) { - NtClose( thread_info->input_shared_map ); - thread_info->input_shared_map = NULL; + NtUnmapViewOfSection( GetCurrentProcess(), thread_info->input_shared_memory ); thread_info->input_shared_memory = NULL; } if (thread_info->foreground_shared_memory) { - NtClose( thread_info->foreground_shared_map ); - thread_info->foreground_shared_map = NULL; + NtUnmapViewOfSection( GetCurrentProcess(), thread_info->foreground_shared_memory ); thread_info->foreground_shared_memory = NULL; } diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 3996b4fcf73..61d1e8edee8 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -240,10 +240,9 @@ BOOL WINAPI NtUserSetThreadDesktop( HDESK handle ) struct user_thread_info *thread_info = get_user_thread_info(); thread_info->client_info.top_window = 0; thread_info->client_info.msg_window = 0; - if (thread_info->desktop_shared_map) + if (thread_info->desktop_shared_memory) { - NtClose( thread_info->desktop_shared_map ); - thread_info->desktop_shared_map = NULL; + NtUnmapViewOfSection( GetCurrentProcess(), thread_info->desktop_shared_memory ); thread_info->desktop_shared_memory = NULL; } } @@ -571,32 +570,31 @@ static const WCHAR *get_default_desktop( void *buf, size_t buf_size ) return defaultW; } -static void map_shared_memory_section( const WCHAR *name, SIZE_T size, HANDLE root, HANDLE *handle, void **ptr ) +static void map_shared_memory_section( const WCHAR *name, SIZE_T size, HANDLE root, void **ptr ) { OBJECT_ATTRIBUTES attr; UNICODE_STRING section_str; unsigned int status; + HANDLE handle; RtlInitUnicodeString( §ion_str, name ); InitializeObjectAttributes( &attr, §ion_str, 0, root, NULL ); - status = NtOpenSection( handle, SECTION_ALL_ACCESS, &attr ); + status = NtOpenSection( &handle, SECTION_ALL_ACCESS, &attr ); if (status) { ERR( "failed to open section %s: %08x\n", debugstr_w(name), status ); *ptr = NULL; - *handle = NULL; return; } *ptr = NULL; - status = NtMapViewOfSection( *handle, GetCurrentProcess(), ptr, 0, 0, NULL, + status = NtMapViewOfSection( handle, GetCurrentProcess(), ptr, 0, 0, NULL, &size, ViewUnmap, 0, PAGE_READONLY ); + NtClose( handle ); if (status) { ERR( "failed to map view of section %s: %08x\n", debugstr_w(name), status ); - NtClose( *handle ); *ptr = NULL; - *handle = NULL; } } @@ -675,7 +673,7 @@ volatile struct desktop_shared_memory *get_desktop_shared_memory( void ) root = get_winstations_dir_handle(); map_shared_memory_section( buf, sizeof(struct desktop_shared_memory), root, - &thread_info->desktop_shared_map, (void **)&thread_info->desktop_shared_memory ); + (void **)&thread_info->desktop_shared_memory ); NtClose( root ); return thread_info->desktop_shared_memory; @@ -693,23 +691,22 @@ volatile struct queue_shared_memory *get_queue_shared_memory( void ) snprintf( buffer, ARRAY_SIZE(buffer), "\\KernelObjects\\__wine_thread_mappings\\%08x-queue", tid ); asciiz_to_unicode( bufferW, buffer ); map_shared_memory_section( bufferW, sizeof(struct queue_shared_memory), NULL, - &thread_info->queue_shared_map, (void **)&thread_info->queue_shared_memory ); + (void **)&thread_info->queue_shared_memory ); return thread_info->queue_shared_memory; } -static volatile struct input_shared_memory *get_thread_input_shared_memory( UINT tid, HANDLE *handle, - struct input_shared_memory **ptr ) +static volatile struct input_shared_memory *get_thread_input_shared_memory( UINT tid, struct input_shared_memory **ptr ) { WCHAR bufferW[MAX_PATH]; char buffer[MAX_PATH]; if (*ptr && (*ptr)->tid == tid) return *ptr; - if (*ptr) NtClose( *handle ); + if (*ptr) NtUnmapViewOfSection( GetCurrentProcess(), *ptr ); snprintf( buffer, ARRAY_SIZE(buffer), "\\KernelObjects\\__wine_thread_mappings\\%08x-input", tid ); asciiz_to_unicode( bufferW, buffer ); map_shared_memory_section( bufferW, sizeof(struct input_shared_memory), NULL, - handle, (void **)ptr ); + (void **)ptr ); return *ptr; } @@ -726,8 +723,7 @@ volatile struct input_shared_memory *get_input_shared_memory( void ) } SHARED_READ_END( &queue->seq ); - return get_thread_input_shared_memory( tid, &thread_info->input_shared_map, - &thread_info->input_shared_memory ); + return get_thread_input_shared_memory( tid, &thread_info->input_shared_memory ); } volatile struct input_shared_memory *get_foreground_shared_memory( void ) @@ -744,8 +740,7 @@ volatile struct input_shared_memory *get_foreground_shared_memory( void ) SHARED_READ_END( &desktop->seq ); if (!tid) return NULL; - return get_thread_input_shared_memory( tid, &thread_info->foreground_shared_map, - &thread_info->foreground_shared_memory ); + return get_thread_input_shared_memory( tid, &thread_info->foreground_shared_memory ); } /*********************************************************************** From fa28d88d4ffe78448fbdd27b37633628a37f7bf5 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 18 Jan 2023 15:03:17 -0600 Subject: [PATCH 0984/2777] winegstreamer: Implement MFT_MESSAGE_COMMAND_DRAIN for h264 transform. CW-Bug-Id: #21804 --- dlls/mf/tests/transform.c | 7 +++-- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/h264_decoder.c | 13 +++++++- dlls/winegstreamer/main.c | 12 ++++++++ dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 6 ++++ dlls/winegstreamer/wg_parser.c | 1 + dlls/winegstreamer/wg_transform.c | 49 +++++++++++++++++++++++++++++++ 8 files changed, 86 insertions(+), 4 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 3c068aae743..972212ba1e6 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -3641,10 +3641,10 @@ static void test_h264_decoder(void) hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0); ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr); + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0); + ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr); } - todo_wine ok(i == 2, "got %lu iterations\n", i); - todo_wine ok(h264_encoded_data_len == 1180, "got h264_encoded_data_len %lu\n", h264_encoded_data_len); ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "ProcessOutput returned %#lx\n", hr); ok(output_status == MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE, "got output[0].dwStatus %#lx\n", output_status); @@ -3705,7 +3705,7 @@ static void test_h264_decoder(void) output_sample = create_sample(NULL, actual_width * actual_height * 2); hr = check_mft_process_output(transform, output_sample, &output_status); - todo_wine + todo_wine /* due to wg_transform_set_output_format() currently drops already processed samples */ ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "ProcessOutput returned %#lx\n", hr); todo_wine ok(output_status == MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE, "got output[0].dwStatus %#lx\n", output_status); @@ -3743,6 +3743,7 @@ static void test_h264_decoder(void) ok(ref == 1, "Release returned %ld\n", ref); ret = check_mf_sample_collection(output_samples, &expect_output_sample_i420, L"i420frame.bmp"); + todo_wine /* wg_transform_set_output_format() should convert already processed samples instead of dropping */ ok(ret == 0, "got %lu%% diff\n", ret); IMFCollection_Release(output_samples); diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index caa754125b8..337b94e8a32 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -104,6 +104,7 @@ struct wg_transform *wg_transform_create(const struct wg_format *input_format, const struct wg_format *output_format); void wg_transform_destroy(struct wg_transform *transform); bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_format *format); +HRESULT wg_transform_drain(struct wg_transform *transform); unsigned int wg_format_get_max_size(const struct wg_format *format); diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 5e58dd4dc83..f6aba970e91 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -575,7 +575,18 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - FIXME("iface %p, message %#x, param %Ix stub!\n", iface, message, param); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, message %#x, param %Ix.\n", iface, message, param); + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (message == MFT_MESSAGE_COMMAND_DRAIN) + return wg_transform_drain(decoder->wg_transform); + + FIXME("Ignoring message %#x.\n", message); + return S_OK; } diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index de3bde867dc..0e2dd64fd07 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -399,6 +399,18 @@ bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_fo return !WINE_UNIX_CALL(unix_wg_transform_set_output_format, ¶ms); } +HRESULT wg_transform_drain(struct wg_transform *transform) +{ + struct wg_transform_drain_params params = + { + .transform = transform, + }; + + TRACE("transform %p.\n", transform); + + return WINE_UNIX_CALL(unix_wg_transform_drain, ¶ms); +} + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { if (reason == DLL_PROCESS_ATTACH) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 6c66ec4711b..bb69c084770 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -43,6 +43,7 @@ extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_set_output_format(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_transform_drain(void *args) DECLSPEC_HIDDEN; /* wg_allocator_release_sample can be used to release any sample that was requested. */ typedef struct wg_sample *(*wg_allocator_request_sample_cb)(gsize size, void *context); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 968359b7454..5fe27fdf4c4 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -317,6 +317,11 @@ struct wg_transform_set_output_format_params const struct wg_format *format; }; +struct wg_transform_drain_params +{ + struct wg_transform *transform; +}; + enum unix_funcs { unix_wg_parser_create, @@ -350,6 +355,7 @@ enum unix_funcs unix_wg_transform_push_data, unix_wg_transform_read_data, + unix_wg_transform_drain, }; #endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 4f07cbe8de7..0bc1fcc2686 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -2043,4 +2043,5 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_transform_push_data), X(wg_transform_read_data), + X(wg_transform_drain), }; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 823a82e4793..881015f878c 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -97,6 +97,11 @@ static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, Gst GST_LOG("transform %p, buffer %p.", transform, buffer); + if (GST_BUFFER_PTS_IS_VALID(buffer)) + transform->segment.start = GST_BUFFER_PTS(buffer); + else if (GST_BUFFER_DURATION_IS_VALID(buffer)) + transform->segment.start += GST_BUFFER_DURATION(buffer); + if (!(sample = gst_sample_new(buffer, transform->output_caps, NULL, NULL))) { GST_ERROR("Failed to allocate transform %p output sample.", transform); @@ -620,6 +625,50 @@ NTSTATUS wg_transform_set_output_format(void *args) return STATUS_SUCCESS; } +NTSTATUS wg_transform_drain(void *args) +{ + struct wg_transform_drain_params *params = args; + struct wg_transform *transform = params->transform; + GstBuffer *input_buffer; + GstFlowReturn ret; + GstEvent *event; + + + while ((input_buffer = gst_atomic_queue_pop(transform->input_queue))) + { + if ((ret = gst_pad_push(transform->my_src, input_buffer))) + { + GST_ERROR("Failed to push transform input, error %d", ret); + return S_OK; + } + } + + if (!gst_pad_peer_query(transform->my_src, transform->drain_query)) + { + GST_ERROR("Drain query failed, transform %p.", transform); + return MF_E_STREAM_ERROR; + } + if (!(event = gst_event_new_segment_done(GST_FORMAT_TIME, transform->segment.start)) + || !gst_pad_push_event(transform->my_src, event)) + { + GST_ERROR("Sending segment done event failed, transform %p.", transform); + return MF_E_STREAM_ERROR; + } + if (!gst_pad_peer_query(transform->my_src, transform->drain_query)) + { + GST_ERROR("Drain query failed, transform %p.", transform); + return MF_E_STREAM_ERROR; + } + if (!(event = gst_event_new_segment(&transform->segment)) + || !gst_pad_push_event(transform->my_src, event)) + { + GST_ERROR("Sending new segment event failed, transform %p.", transform); + return MF_E_STREAM_ERROR; + } + + return S_OK; +} + static void wg_sample_free_notify(void *arg) { struct wg_sample *sample = arg; From 37e94ecce5752e10842601d8a30dd971ad1348a7 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 20 Jan 2023 14:18:25 -0600 Subject: [PATCH 0985/2777] winegstreamer: Implement MFT_MESSAGE_COMMAND_DRAIN for aac decoder. CW-Bug-Id: #21804 --- dlls/mf/tests/transform.c | 9 +++++++-- dlls/winegstreamer/aac_decoder.c | 13 ++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 972212ba1e6..2830cfc6346 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -2465,8 +2465,13 @@ static void test_aac_decoder(void) hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0); ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr); - hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); - ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr); + if (0) + { + /* This is fine on Windows but currently MFT_MESSAGE_COMMAND_DRAIN removes input sample from the queue + * and makes next _ProcessInput succeed on Wine breaking the tests below. */ + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr); + } hr = MFCreateCollection(&output_samples); ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr); diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index a2a6984dd18..920385abd3d 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -524,7 +524,18 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); + struct aac_decoder *decoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, message %#x, param %p.\n", iface, message, (void *)param); + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (message == MFT_MESSAGE_COMMAND_DRAIN) + return wg_transform_drain(decoder->wg_transform); + + FIXME("Ignoring message %#x.\n", message); + return S_OK; } From 0799ee446e37cbc69c0078f952b3b89552f39465 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 20 Jan 2023 14:47:47 -0600 Subject: [PATCH 0986/2777] winegstreamer: Implement MFT_MESSAGE_COMMAND_DRAIN for resampler. CW-Bug-Id: #21804 --- dlls/mf/tests/transform.c | 9 +++++++-- dlls/winegstreamer/resampler.c | 13 ++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 2830cfc6346..f5cbf12f4c0 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -4052,8 +4052,13 @@ static void test_audio_convert(void) ok(hr == S_OK, "ProcessInput returned %#lx\n", hr); hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0); ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr); - hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); - ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr); + if (0) + { + /* This is fine on Windows but currently MFT_MESSAGE_COMMAND_DRAIN removes input sample from the queue + * and makes next _ProcessInput succeed on Wine breaking the tests below. */ + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr); + } ret = IMFSample_Release(input_sample); ok(ret <= 1, "Release returned %ld\n", ret); diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c index 88e9727ff21..c4efd5fb82c 100644 --- a/dlls/winegstreamer/resampler.c +++ b/dlls/winegstreamer/resampler.c @@ -505,7 +505,18 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); + struct resampler *impl = impl_from_IMFTransform(iface); + + TRACE("iface %p, message %#x, param %p.\n", iface, message, (void *)param); + + if (!impl->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (message == MFT_MESSAGE_COMMAND_DRAIN) + return wg_transform_drain(impl->wg_transform); + + FIXME("Ignoring message %#x.\n", message); + return S_OK; } From 6b04b251a08801467ffc36da2afd4f02c1ac5ea4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 20 Jan 2023 14:48:48 -0600 Subject: [PATCH 0987/2777] winegstreamer: Implement MFT_MESSAGE_COMMAND_DRAIN for video processor. CW-Bug-Id: #21804 --- dlls/winegstreamer/video_processor.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index 21bc46b0bb3..d8ef51b7bf2 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -505,7 +505,18 @@ static HRESULT WINAPI video_processor_ProcessEvent(IMFTransform *iface, DWORD id static HRESULT WINAPI video_processor_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - FIXME("iface %p, message %#x, param %#Ix stub!\n", iface, message, param); + struct video_processor *impl = impl_from_IMFTransform(iface); + + TRACE("iface %p, message %#x, param %p.\n", iface, message, (void *)param); + + if (!impl->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (message == MFT_MESSAGE_COMMAND_DRAIN) + return wg_transform_drain(impl->wg_transform); + + FIXME("Ignoring message %#x.\n", message); + return S_OK; } From 051fd7938d4e0a59872ab18cae9fbe957c889a62 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 20 Jan 2023 14:50:38 -0600 Subject: [PATCH 0988/2777] winegstreamer: Implement MFT_MESSAGE_COMMAND_DRAIN for wma decoder. CW-Bug-Id: #21804 --- dlls/winegstreamer/wma_decoder.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 10a41a0c92f..9354822e45c 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -522,7 +522,18 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); + struct wma_decoder *decoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, message %#x, param %p.\n", iface, message, (void *)param); + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (message == MFT_MESSAGE_COMMAND_DRAIN) + return wg_transform_drain(decoder->wg_transform); + + FIXME("Ignoring message %#x.\n", message); + return S_OK; } From d4a8af017a2fa8bb976b9b93e3c1abb4d3b57c56 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 17 Jan 2023 15:12:38 -0600 Subject: [PATCH 0989/2777] mfplat: Implement mediatype_GetRepresentation() for FORMAT_MFVideoFormat. CW-Bug-Id: #21660 --- dlls/mfplat/mediatype.c | 89 +++++++++++++++++++++++++++++++++----- dlls/mfplat/tests/mfplat.c | 63 +++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 12 deletions(-) diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index eca397ef067..2e16de96849 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -72,6 +72,71 @@ struct presentation_desc static HRESULT presentation_descriptor_init(struct presentation_desc *object, DWORD count); +static HRESULT WINAPI mediatype_get_representation(struct media_type *media_type, const GUID *guid, + void **representation) +{ + if (IsEqualIID(guid, &FORMAT_MFVideoFormat)) + { + IMFMediaType *iface = &media_type->IMFMediaType_iface; + AM_MEDIA_TYPE *amt; + UINT32 value; + HRESULT hr; + + *representation = NULL; + if (!(amt = CoTaskMemAlloc(sizeof(*amt)))) + return E_OUTOFMEMORY; + + memset(amt, 0, sizeof(*amt)); + + if (IMFMediaType_GetMajorType(iface, &amt->majortype) || !IsEqualGUID(&amt->majortype, &MFMediaType_Video) + || IMFMediaType_GetGUID(iface, &MF_MT_SUBTYPE, &amt->subtype)) + { + CoTaskMemFree(amt); + return MF_E_ATTRIBUTENOTFOUND; + } + + if (FAILED(hr = MFCreateMFVideoFormatFromMFMediaType(iface, (MFVIDEOFORMAT **)&amt->pbFormat, + (UINT32 *)&amt->cbFormat ))) + { + WARN("Failed to create format description, hr %#lx.\n", hr); + CoTaskMemFree(amt); + return hr; + } + memcpy(&amt->formattype, guid, sizeof(*guid)); + if (IMFMediaType_GetUINT32(iface, &MF_MT_FIXED_SIZE_SAMPLES, (UINT32 *)&value)) + value = 0; + amt->bFixedSizeSamples = !!value; + + if ((hr = IMFMediaType_GetUINT32(iface, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value))) + value = 0; + amt->bTemporalCompression = !value; + + if (IMFMediaType_GetUINT32(iface, &MF_MT_SAMPLE_SIZE, (UINT32 *)&amt->lSampleSize)) + amt->lSampleSize = 0; + + *representation = amt; + return S_OK; + } + + FIXME("Not implemented for %s.\n", debugstr_guid(guid)); + return E_NOTIMPL; +} + +static HRESULT mediatype_free_representation(const GUID *guid, void *representation) +{ + if (IsEqualIID(guid, &FORMAT_MFVideoFormat)) + { + AM_MEDIA_TYPE *amt = representation; + + CoTaskMemFree(amt->pbFormat); + CoTaskMemFree(amt); + return S_OK; + } + + FIXME("Not implemented for %s.\n", debugstr_guid(guid)); + return E_NOTIMPL; +} + static struct media_type *impl_from_IMFMediaType(IMFMediaType *iface) { return CONTAINING_RECORD(iface, struct media_type, IMFMediaType_iface); @@ -583,16 +648,16 @@ static HRESULT WINAPI mediatype_IsEqual(IMFMediaType *iface, IMFMediaType *type, static HRESULT WINAPI mediatype_GetRepresentation(IMFMediaType *iface, GUID guid, void **representation) { - FIXME("%p, %s, %p.\n", iface, debugstr_guid(&guid), representation); + TRACE("%p, %s, %p.\n", iface, debugstr_guid(&guid), representation); - return E_NOTIMPL; + return mediatype_get_representation(impl_from_IMFMediaType(iface), &guid, representation); } static HRESULT WINAPI mediatype_FreeRepresentation(IMFMediaType *iface, GUID guid, void *representation) { - FIXME("%p, %s, %p.\n", iface, debugstr_guid(&guid), representation); + TRACE("%p, %s, %p.\n", iface, debugstr_guid(&guid), representation); - return E_NOTIMPL; + return mediatype_free_representation(&guid, representation); } static const IMFMediaTypeVtbl mediatypevtbl = @@ -958,16 +1023,16 @@ static HRESULT WINAPI video_mediatype_IsEqual(IMFVideoMediaType *iface, IMFMedia static HRESULT WINAPI video_mediatype_GetRepresentation(IMFVideoMediaType *iface, GUID guid, void **representation) { - FIXME("%p, %s, %p.\n", iface, debugstr_guid(&guid), representation); + TRACE("%p, %s, %p.\n", iface, debugstr_guid(&guid), representation); - return E_NOTIMPL; + return mediatype_get_representation(impl_from_IMFVideoMediaType(iface), &guid, representation);; } static HRESULT WINAPI video_mediatype_FreeRepresentation(IMFVideoMediaType *iface, GUID guid, void *representation) { - FIXME("%p, %s, %p.\n", iface, debugstr_guid(&guid), representation); + TRACE("%p, %s, %p.\n", iface, debugstr_guid(&guid), representation); - return E_NOTIMPL; + return mediatype_free_representation(&guid, representation); } static const MFVIDEOFORMAT * WINAPI video_mediatype_GetVideoFormat(IMFVideoMediaType *iface) @@ -1359,16 +1424,16 @@ static HRESULT WINAPI audio_mediatype_IsEqual(IMFAudioMediaType *iface, IMFMedia static HRESULT WINAPI audio_mediatype_GetRepresentation(IMFAudioMediaType *iface, GUID guid, void **representation) { - FIXME("%p, %s, %p.\n", iface, debugstr_guid(&guid), representation); + TRACE("%p, %s, %p.\n", iface, debugstr_guid(&guid), representation); - return E_NOTIMPL; + return mediatype_get_representation(impl_from_IMFAudioMediaType(iface), &guid, representation);; } static HRESULT WINAPI audio_mediatype_FreeRepresentation(IMFAudioMediaType *iface, GUID guid, void *representation) { - FIXME("%p, %s, %p.\n", iface, debugstr_guid(&guid), representation); + TRACE("%p, %s, %p.\n", iface, debugstr_guid(&guid), representation); - return E_NOTIMPL; + return mediatype_free_representation(&guid, representation); } static const WAVEFORMATEX * WINAPI audio_mediatype_GetAudioFormat(IMFAudioMediaType *iface) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index f1f61e25d00..2dd3e834a0e 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -1163,6 +1163,54 @@ static void init_functions(void) is_win8_plus = pMFPutWaitingWorkItem != NULL; } +#define check_format_representation(a) check_format_representation_(__LINE__, a) +static void check_format_representation_(unsigned int line, IMFMediaType *mediatype) +{ + AM_MEDIA_TYPE *amt; + GUID guid, subtype; + UINT32 value, size; + MFVIDEOFORMAT *mvf; + HRESULT hr; + + amt = (void *)0xdeadbeef; + hr = IMFMediaType_GetRepresentation(mediatype, FORMAT_MFVideoFormat, (void **)&amt); + + if (IMFMediaType_GetMajorType(mediatype, &guid) || !IsEqualGUID(&guid, &MFMediaType_Video) + || IMFMediaType_GetGUID(mediatype, &MF_MT_SUBTYPE, &subtype)) + { + ok_(__FILE__, line)(hr == MF_E_ATTRIBUTENOTFOUND, "hr %#lx.\n", hr); + ok_(__FILE__, line)(!amt, "got %p.\n", amt); + return; + } + + ok_(__FILE__, line)(hr == S_OK, "hr %#lx.\n", hr); + ok_(__FILE__, line)(IsEqualIID(&amt->majortype, &MEDIATYPE_Video), "major_type %s.\n", debugstr_guid(&amt->majortype)); + ok_(__FILE__, line)(IsEqualIID(&amt->subtype, &subtype), "subtype %s.\n", debugstr_guid(&amt->subtype)); + if (IMFMediaType_GetUINT32(mediatype, &MF_MT_FIXED_SIZE_SAMPLES, &value)) + value = 0; + ok_(__FILE__, line)(amt->bFixedSizeSamples == value, "bFixedSizeSamples %d.\n", amt->bFixedSizeSamples); + + if ((hr = IMFMediaType_GetUINT32(mediatype, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value))) + value = FALSE; + ok_(__FILE__, line)(amt->bTemporalCompression == !value, "bTemporalCompression %d.\n", amt->bTemporalCompression); + + if (IMFMediaType_GetUINT32(mediatype, &MF_MT_SAMPLE_SIZE, &value)) + value = 0; + ok_(__FILE__, line)(amt->lSampleSize == value, "lSampleSize %lu.\n", amt->lSampleSize); + + ok_(__FILE__, line)(IsEqualIID(&amt->formattype, &FORMAT_MFVideoFormat), "formattype %s.\n", debugstr_guid(&amt->formattype)); + ok_(__FILE__, line)(!amt->pUnk, "pUnk %p.\n", amt->pUnk); + ok_(__FILE__, line)(amt->cbFormat == sizeof(MFVIDEOFORMAT), "cbFormat %lu.\n", amt->cbFormat); + + hr = MFCreateMFVideoFormatFromMFMediaType(mediatype, &mvf, &size); + ok_(__FILE__, line)(hr == S_OK, "hr %#lx.\n", hr); + ok_(__FILE__, line)(!memcmp(mvf, amt->pbFormat, sizeof(*mvf)), "video format does not match.\n"); + CoTaskMemFree(mvf); + + hr = IMFMediaType_FreeRepresentation(mediatype, FORMAT_MFVideoFormat, amt); + ok_(__FILE__, line)(hr == S_OK, "hr %#lx.\n", hr); +} + static void test_media_type(void) { IMFMediaType *mediatype, *mediatype2; @@ -1184,6 +1232,8 @@ if(0) hr = MFCreateMediaType(&mediatype); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_format_representation(mediatype); + hr = IMFMediaType_GetMajorType(mediatype, &guid); ok(hr == MF_E_ATTRIBUTENOTFOUND, "Unexpected hr %#lx.\n", hr); @@ -1225,6 +1275,8 @@ if(0) hr = IMFMediaType_SetGUID(mediatype, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); ok(hr == S_OK, "Failed to set GUID value, hr %#lx.\n", hr); + check_format_representation(mediatype); + hr = IMFMediaType_GetMajorType(mediatype, &guid); ok(hr == S_OK, "Failed to get major type, hr %#lx.\n", hr); ok(IsEqualGUID(&guid, &MFMediaType_Video), "Unexpected major type.\n"); @@ -1238,6 +1290,8 @@ if(0) ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); ok(flags == 0, "Unexpected flags %#lx.\n", flags); + check_format_representation(mediatype); + /* Different major types. */ hr = IMFMediaType_SetGUID(mediatype2, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio); ok(hr == S_OK, "Failed to set major type, hr %#lx.\n", hr); @@ -1252,6 +1306,7 @@ if(0) hr = IMFMediaType_SetGUID(mediatype2, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); ok(hr == S_OK, "Failed to set major type, hr %#lx.\n", hr); + flags = 0; hr = IMFMediaType_IsEqual(mediatype, mediatype2, &flags); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -1271,9 +1326,13 @@ if(0) hr = IMFMediaType_DeleteItem(mediatype, &MF_MT_USER_DATA); ok(hr == S_OK, "Failed to delete item, hr %#lx.\n", hr); + check_format_representation(mediatype); + hr = IMFMediaType_SetGUID(mediatype, &MF_MT_SUBTYPE, &MFVideoFormat_RGB32); ok(hr == S_OK, "Failed to set subtype, hr %#lx.\n", hr); + check_format_representation(mediatype); + flags = 0; hr = IMFMediaType_IsEqual(mediatype, mediatype2, &flags); ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr); @@ -1323,6 +1382,8 @@ if(0) hr = pMFCreateVideoMediaTypeFromSubtype(&MFVideoFormat_RGB555, &video_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_format_representation((IMFMediaType *)video_type); + check_interface(video_type, &IID_IMFMediaType, TRUE); check_interface(video_type, &IID_IMFVideoMediaType, TRUE); @@ -1377,6 +1438,8 @@ if(0) IUnknown_Release(unk); + check_format_representation(mediatype); + IMFMediaType_Release(mediatype); } From 100550d6950740bb22eeffc6e0e35c67a748d871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 13 Jan 2023 09:08:33 +0100 Subject: [PATCH 0990/2777] mf: Drop late samples in audio renderer. CW-Bug-Id: #21159 --- dlls/mf/sar.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/dlls/mf/sar.c b/dlls/mf/sar.c index 84824f954dd..86af2a34f11 100644 --- a/dlls/mf/sar.c +++ b/dlls/mf/sar.c @@ -1339,6 +1339,7 @@ static HRESULT stream_queue_sample(struct audio_renderer *renderer, IMFSample *s { struct queued_object *object; DWORD sample_len, sample_frames; + MFTIME time, clocktime, systime; HRESULT hr; if (FAILED(hr = IMFSample_GetTotalLength(sample, &sample_len))) @@ -1353,8 +1354,27 @@ static HRESULT stream_queue_sample(struct audio_renderer *renderer, IMFSample *s object->u.sample.sample = sample; IMFSample_AddRef(object->u.sample.sample); - list_add_tail(&renderer->queue, &object->entry); - renderer->queued_frames += sample_frames; + if (FAILED(hr = IMFSample_GetSampleTime(sample, &time))) + { + WARN("Failed to get sample time, hr %#lx.\n", hr); + return hr; + } + + if (!renderer->clock) + clocktime = time; + else if (FAILED(hr = IMFPresentationClock_GetCorrelatedTime(renderer->clock, 0, &clocktime, &systime))) + { + WARN("Failed to get clock time, hr %#lx.\n", hr); + return hr; + } + + if (time < clocktime) + FIXME("Dropping sample %p, time %I64u, clocktime %I64u, systime %I64u.\n", sample, time, clocktime, systime); + else + { + list_add_tail(&renderer->queue, &object->entry); + renderer->queued_frames += sample_frames; + } return S_OK; } From a5b8d22399462951e50f555f5d17f31928c49936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 13 Jan 2023 09:08:34 +0100 Subject: [PATCH 0991/2777] mfplat: Use QueryPerformanceCounter in MFGetSystemTime. CW-Bug-Id: #21159 --- dlls/mfplat/main.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 96e6b1d5094..ed69d501f2a 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -974,11 +974,14 @@ HRESULT WINAPI MFTUnregisterLocal(IClassFactory *factory) MFTIME WINAPI MFGetSystemTime(void) { - MFTIME mf; + static LARGE_INTEGER frequency; + LARGE_INTEGER counter; - GetSystemTimeAsFileTime( (FILETIME*)&mf ); + if (!frequency.QuadPart) + QueryPerformanceFrequency(&frequency); + QueryPerformanceCounter(&counter); - return mf; + return (counter.QuadPart * 1000) / frequency.QuadPart * 10000; } static BOOL mft_is_type_info_match(struct mft_registration *mft, const GUID *category, UINT32 flags, From fe7901be6de96a7572fff977dd34584d96b5ec29 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Tue, 24 Jan 2023 12:12:01 +0100 Subject: [PATCH 0992/2777] loader: Install all fonts provided by Proton in the registry. --- loader/wine.inf.in | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 39f86ba7493..70751891f7d 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -502,14 +502,24 @@ HKLM,%FontSubStr%,"Times New Roman TUR,162",,"Times New Roman,162" HKLM,System\CurrentControlSet\Hardware Profiles\Current\Software\Fonts,"LogPixels",0x10003,0x00000060 HKLM,%FontsNT%,"Arial (TrueType)",,"arial.ttf" HKLM,%FontsNT%,"Arial Bold (TrueType)",,"arialbd.ttf" -HKLM,%FontsNT%,"Times New Roman (TrueType)",,"times.ttf" HKLM,%FontsNT%,"Courier New (TrueType)",,"cour.ttf" +HKLM,%FontsNT%,"Courier New Bold (TrueType)",,"courbd.ttf" HKLM,%FontsNT%,"Malgun Gothic (TrueType)",,"malgun.ttf" +HKLM,%FontsNT%,"Marlett (TrueType)",,"marlett.ttf" HKLM,%FontsNT%,"Microsoft Sans Serif (TrueType)",,"micross.ttf" -HKLM,%FontsNT%,"Microsoft YaHei (TrueType)",,"msyh.ttf" HKLM,%FontsNT%,"MS Gothic (TrueType)",,"msgothic.ttc" +HKLM,%FontsNT%,"MS PGothic (TrueType)",,"msgothic.ttc" +HKLM,%FontsNT%,"MS UI Gothic (TrueType)",,"msgothic.ttc" +HKLM,%FontsNT%,"Microsoft YaHei (TrueType)",,"msyh.ttf" HKLM,%FontsNT%,"Nirmala UI (TrueType)",,"nirmala.ttf" HKLM,%FontsNT%,"SimSun (TrueType)",,"simsun.ttc" +HKLM,%FontsNT%,"NSimSun (TrueType)",,"simsun.ttc" +HKLM,%FontsNT%,"Symbol (TrueType)",,"symbol.ttf" +HKLM,%FontsNT%,"Tahoma (TrueType)",,"tahoma.ttf" +HKLM,%FontsNT%,"Tahoma Bold (TrueType)",,"tahomabd.ttf" +HKLM,%FontsNT%,"Times New Roman (TrueType)",,"times.ttf" +HKLM,%FontsNT%,"Webdings (TrueType)",,"webdings.ttf" +HKLM,%FontsNT%,"Wingdings (TrueType)",,"wingdings.ttf" HKCU,Software\Wine\Fonts\Replacements,"Palatino Linotype",,"Times New Roman" [MCI] From 60875817c5e59d7256982ccb141e77338c86eb5f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 24 Jan 2023 17:52:14 -0600 Subject: [PATCH 0993/2777] mf: Increment requests before session_request_sample_from_node() in session_request_sample(). CW-Bug-Id: #21804 --- dlls/mf/session.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 1edd380e983..95632fae5fb 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -3400,8 +3400,9 @@ static void session_request_sample(struct media_session *session, IMFStreamSink return; } - if (SUCCEEDED(session_request_sample_from_node(session, upstream_node, upstream_output))) - sink_node->u.sink.requests++; + sink_node->u.sink.requests++; + if (FAILED(session_request_sample_from_node(session, upstream_node, upstream_output))) + sink_node->u.sink.requests--; IMFTopologyNode_Release(upstream_node); } From 86b980e5cbd5def5cc8268e0f2d8eca531ca8f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 23 Jan 2023 15:35:05 +0100 Subject: [PATCH 0994/2777] hidp: Allow match all usages on specific functions only. (cherry picked from commit 36b2f6be52466fce3d495e280f392522529d2745) --- dlls/dinput/tests/hid.c | 5 +++++ dlls/hid/hidp.c | 31 +++++++++++++++++-------------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c index 5200892e95b..a5ede6ee29b 100644 --- a/dlls/dinput/tests/hid.c +++ b/dlls/dinput/tests/hid.c @@ -1841,6 +1841,11 @@ static void test_hidp( HANDLE file, HANDLE async_file, int report_id, BOOL polle ok( buffer[0] == (char)0xcd, "got report value %#x\n", buffer[0] ); ok( buffer[1] == (char)0xcd, "got report value %#x\n", buffer[1] ); + status = HidP_GetUsageValue( HidP_Input, HID_USAGE_PAGE_GENERIC, 0, 0, &value, preparsed_data, report, caps.InputReportByteLength ); + ok( status == HIDP_STATUS_USAGE_NOT_FOUND, "HidP_GetUsageValue returned %#lx\n", status ); + status = HidP_GetUsageValue( HidP_Input, 0, 0, HID_USAGE_GENERIC_X, &value, preparsed_data, report, caps.InputReportByteLength ); + ok( status == HIDP_STATUS_USAGE_NOT_FOUND, "HidP_GetUsageValue returned %#lx\n", status ); + report[16] = 0xff; report[17] = 0xff; status = HidP_GetUsageValue( HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_HATSWITCH, diff --git a/dlls/hid/hidp.c b/dlls/hid/hidp.c index 83a4638b6ad..c24a98155b0 100644 --- a/dlls/hid/hidp.c +++ b/dlls/hid/hidp.c @@ -68,14 +68,17 @@ static NTSTATUS get_value_caps_range( struct hid_preparsed_data *preparsed, HIDP return HIDP_STATUS_SUCCESS; } +#define USAGE_MASK 0xffff +#define USAGE_ANY 0x10000 + struct caps_filter { BOOLEAN buttons; BOOLEAN values; BOOLEAN array; - USAGE usage_page; + DWORD usage_page; USHORT collection; - USAGE usage; + DWORD usage; UCHAR report_id; }; @@ -84,10 +87,10 @@ static BOOL match_value_caps( const struct hid_value_caps *caps, const struct ca if (!caps->usage_min && !caps->usage_max) return FALSE; if (filter->buttons && !(caps->flags & HID_VALUE_CAPS_IS_BUTTON)) return FALSE; if (filter->values && (caps->flags & HID_VALUE_CAPS_IS_BUTTON)) return FALSE; - if (filter->usage_page && filter->usage_page != caps->usage_page) return FALSE; + if (filter->usage_page != USAGE_ANY && (filter->usage_page & USAGE_MASK) != caps->usage_page) return FALSE; if (filter->collection && filter->collection != caps->link_collection) return FALSE; - if (!filter->usage) return TRUE; - return caps->usage_min <= filter->usage && caps->usage_max >= filter->usage; + if (filter->usage == USAGE_ANY) return TRUE; + return caps->usage_min <= (filter->usage & USAGE_MASK) && caps->usage_max >= (filter->usage & USAGE_MASK); } typedef NTSTATUS (*enum_value_caps_callback)( const struct hid_value_caps *caps, void *user ); @@ -384,7 +387,7 @@ NTSTATUS WINAPI HidP_GetUsages( HIDP_REPORT_TYPE report_type, USAGE usage_page, { struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)preparsed_data; struct get_usage_params params = {.usages = usages, .usages_end = usages + *usages_len, .report_buf = report_buf}; - struct caps_filter filter = {.buttons = TRUE, .usage_page = usage_page, .collection = collection}; + struct caps_filter filter = {.buttons = TRUE, .usage_page = usage_page, .collection = collection, .usage = USAGE_ANY}; NTSTATUS status; USHORT limit = -1; @@ -441,7 +444,7 @@ static NTSTATUS get_usage_list_length( const struct hid_value_caps *caps, void * ULONG WINAPI HidP_MaxUsageListLength( HIDP_REPORT_TYPE report_type, USAGE usage_page, PHIDP_PREPARSED_DATA preparsed_data ) { struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)preparsed_data; - struct caps_filter filter = {.buttons = TRUE, .usage_page = usage_page}; + struct caps_filter filter = {.buttons = TRUE, .usage_page = usage_page | USAGE_ANY, .usage = USAGE_ANY}; USHORT limit = -1; ULONG count = 0; @@ -590,7 +593,7 @@ NTSTATUS WINAPI HidP_SetUsages( HIDP_REPORT_TYPE report_type, USAGE usage_page, { struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)preparsed_data; struct set_usage_params params = {.report_buf = report_buf}; - struct caps_filter filter = {.buttons = TRUE, .usage_page = usage_page, .collection = collection}; + struct caps_filter filter = {.buttons = TRUE, .usage_page = usage_page, .collection = collection, .usage = USAGE_ANY}; NTSTATUS status; USHORT limit = 1; ULONG i, count = *usage_count; @@ -656,7 +659,7 @@ NTSTATUS WINAPI HidP_UnsetUsages( HIDP_REPORT_TYPE report_type, USAGE usage_page { struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)preparsed_data; struct unset_usage_params params = {.report_buf = report_buf, .found = FALSE}; - struct caps_filter filter = {.buttons = TRUE, .usage_page = usage_page, .collection = collection}; + struct caps_filter filter = {.buttons = TRUE, .usage_page = usage_page, .collection = collection, .usage = USAGE_ANY}; NTSTATUS status; USHORT limit = 1; ULONG i, count = *usage_count; @@ -739,7 +742,7 @@ NTSTATUS WINAPI HidP_GetSpecificButtonCaps( HIDP_REPORT_TYPE report_type, USAGE PHIDP_PREPARSED_DATA preparsed_data ) { struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)preparsed_data; - const struct caps_filter filter = {.buttons = TRUE, .usage_page = usage_page, .collection = collection, .usage = usage}; + const struct caps_filter filter = {.buttons = TRUE, .usage_page = usage_page | USAGE_ANY, .collection = collection, .usage = usage | USAGE_ANY}; TRACE( "report_type %d, usage_page %u, collection %u, usage %u, caps %p, caps_count %p, preparsed_data %p.\n", report_type, usage_page, collection, usage, caps, caps_count, preparsed_data ); @@ -806,7 +809,7 @@ NTSTATUS WINAPI HidP_GetSpecificValueCaps( HIDP_REPORT_TYPE report_type, USAGE u PHIDP_PREPARSED_DATA preparsed_data ) { struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)preparsed_data; - const struct caps_filter filter = {.values = TRUE, .usage_page = usage_page, .collection = collection, .usage = usage}; + const struct caps_filter filter = {.values = TRUE, .usage_page = usage_page | USAGE_ANY, .collection = collection, .usage = usage | USAGE_ANY}; TRACE( "report_type %d, usage_page %u, collection %u, usage %u, caps %p, caps_count %p, preparsed_data %p.\n", report_type, usage_page, collection, usage, caps, caps_count, preparsed_data ); @@ -869,7 +872,7 @@ NTSTATUS WINAPI HidP_GetUsagesEx( HIDP_REPORT_TYPE report_type, USHORT collectio { struct get_usage_and_page_params params = {.usages = usages, .usages_end = usages + *usages_len, .report_buf = report_buf}; struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)preparsed_data; - struct caps_filter filter = {.buttons = TRUE, .collection = collection}; + struct caps_filter filter = {.buttons = TRUE, .usage_page = USAGE_ANY, .collection = collection, .usage = USAGE_ANY}; NTSTATUS status; USHORT limit = -1; @@ -899,7 +902,7 @@ static NTSTATUS count_data( const struct hid_value_caps *caps, void *user ) ULONG WINAPI HidP_MaxDataListLength( HIDP_REPORT_TYPE report_type, PHIDP_PREPARSED_DATA preparsed_data ) { struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)preparsed_data; - struct caps_filter filter = {}; + struct caps_filter filter = {.usage_page = USAGE_ANY, .usage = USAGE_ANY}; USHORT limit = -1; ULONG count = 0; @@ -981,7 +984,7 @@ NTSTATUS WINAPI HidP_GetData( HIDP_REPORT_TYPE report_type, HIDP_DATA *data, ULO { struct find_all_data_params params = {.data = data, .data_end = data + *data_len, .report_buf = report_buf}; struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)preparsed_data; - struct caps_filter filter = {}; + struct caps_filter filter = {.usage_page = USAGE_ANY, .usage = USAGE_ANY}; NTSTATUS status; USHORT limit = -1; From 4f395e6ef4d1aa2876a8832b2035a4a84d3e18b6 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 30 Dec 2022 21:11:51 -0600 Subject: [PATCH 0995/2777] msmpeg2vdec: Add stub dll. CW-Bug-Id: #21714 --- configure.ac | 1 + dlls/msmpeg2vdec/Makefile.in | 1 + dlls/msmpeg2vdec/msmpeg2vdec.spec | 0 3 files changed, 2 insertions(+) create mode 100644 dlls/msmpeg2vdec/Makefile.in create mode 100644 dlls/msmpeg2vdec/msmpeg2vdec.spec diff --git a/configure.ac b/configure.ac index 03806f6189e..d8dd5a9dac1 100644 --- a/configure.ac +++ b/configure.ac @@ -2821,6 +2821,7 @@ WINE_CONFIG_MAKEFILE(dlls/msimtf) WINE_CONFIG_MAKEFILE(dlls/msisip) WINE_CONFIG_MAKEFILE(dlls/msisys.ocx) WINE_CONFIG_MAKEFILE(dlls/msls31) +WINE_CONFIG_MAKEFILE(dlls/msmpeg2vdec) WINE_CONFIG_MAKEFILE(dlls/msnet32) WINE_CONFIG_MAKEFILE(dlls/mspatcha) WINE_CONFIG_MAKEFILE(dlls/mspatcha/tests) diff --git a/dlls/msmpeg2vdec/Makefile.in b/dlls/msmpeg2vdec/Makefile.in new file mode 100644 index 00000000000..d2dbf5adda0 --- /dev/null +++ b/dlls/msmpeg2vdec/Makefile.in @@ -0,0 +1 @@ +MODULE = msmpeg2vdec.dll diff --git a/dlls/msmpeg2vdec/msmpeg2vdec.spec b/dlls/msmpeg2vdec/msmpeg2vdec.spec new file mode 100644 index 00000000000..e69de29bb2d From 3d54fde4889a7b37049efc1e0bcd954a4778ecd4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 30 Dec 2022 21:19:12 -0600 Subject: [PATCH 0996/2777] msauddecmft: Add stub dll. CW-Bug-Id: #21714 --- configure.ac | 1 + dlls/msauddecmft/Makefile.in | 1 + dlls/msauddecmft/msauddecmft.spec | 0 3 files changed, 2 insertions(+) create mode 100644 dlls/msauddecmft/Makefile.in create mode 100644 dlls/msauddecmft/msauddecmft.spec diff --git a/configure.ac b/configure.ac index d8dd5a9dac1..867bfe92897 100644 --- a/configure.ac +++ b/configure.ac @@ -2788,6 +2788,7 @@ WINE_CONFIG_MAKEFILE(dlls/msado15/tests) WINE_CONFIG_MAKEFILE(dlls/msadp32.acm) WINE_CONFIG_MAKEFILE(dlls/msasn1) WINE_CONFIG_MAKEFILE(dlls/msasn1/tests) +WINE_CONFIG_MAKEFILE(dlls/msauddecmft) WINE_CONFIG_MAKEFILE(dlls/mscat32) WINE_CONFIG_MAKEFILE(dlls/mscms) WINE_CONFIG_MAKEFILE(dlls/mscms/tests) diff --git a/dlls/msauddecmft/Makefile.in b/dlls/msauddecmft/Makefile.in new file mode 100644 index 00000000000..abce4d1cfe4 --- /dev/null +++ b/dlls/msauddecmft/Makefile.in @@ -0,0 +1 @@ +MODULE = msauddecmft.dll diff --git a/dlls/msauddecmft/msauddecmft.spec b/dlls/msauddecmft/msauddecmft.spec new file mode 100644 index 00000000000..e69de29bb2d From 78206723b83cd1d0729d56c731e8f8f21701e542 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 23 Jan 2023 21:23:28 -0600 Subject: [PATCH 0997/2777] esync, fsync: Support wait on completion ports. CW-Bug-Id: #21831 --- server/completion.c | 88 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 7 deletions(-) diff --git a/server/completion.c b/server/completion.c index cbafe811796..3ed7b2ff2a3 100644 --- a/server/completion.c +++ b/server/completion.c @@ -30,7 +30,7 @@ #include #include - +#include #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" @@ -40,7 +40,8 @@ #include "file.h" #include "handle.h" #include "request.h" - +#include "esync.h" +#include "fsync.h" static const WCHAR completion_name[] = {'I','o','C','o','m','p','l','e','t','i','o','n'}; @@ -64,6 +65,8 @@ struct completion_wait struct completion *completion; struct list queue; unsigned int depth; + int esync_fd; + unsigned int fsync_idx; }; struct completion @@ -75,6 +78,8 @@ struct completion static void completion_wait_dump( struct object*, int ); static int completion_wait_signaled( struct object *obj, struct wait_queue_entry *entry ); static void completion_wait_satisfied( struct object *obj, struct wait_queue_entry *entry ); +static int completion_wait_get_esync_fd( struct object *obj, enum esync_type *type ); +static unsigned int completion_wait_get_fsync_idx( struct object *obj, enum fsync_type *type ); static void completion_wait_destroy( struct object * ); static const struct object_ops completion_wait_ops = @@ -85,8 +90,8 @@ static const struct object_ops completion_wait_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ completion_wait_signaled, /* signaled */ - NULL, /* get_esync_fd */ - NULL, /* get_fsync_idx */ + completion_wait_get_esync_fd, /* get_esync_fd */ + completion_wait_get_fsync_idx, /* get_fsync_idx */ completion_wait_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -106,6 +111,8 @@ static const struct object_ops completion_wait_ops = static void completion_dump( struct object*, int ); static int completion_add_queue( struct object *obj, struct wait_queue_entry *entry ); static void completion_remove_queue( struct object *obj, struct wait_queue_entry *entry ); +static int completion_get_esync_fd( struct object *obj, enum esync_type *type ); +static unsigned int completion_get_fsync_idx( struct object *obj, enum fsync_type *type ); static void completion_destroy( struct object * ); static const struct object_ops completion_ops = @@ -116,8 +123,8 @@ static const struct object_ops completion_ops = completion_add_queue, /* add_queue */ completion_remove_queue, /* remove_queue */ NULL, /* signaled */ - NULL, /* get_esync_fd */ - NULL, /* get_fsync_idx */ + completion_get_esync_fd, /* get_esync_fd */ + completion_get_fsync_idx, /* get_fsync_idx */ no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ @@ -152,6 +159,11 @@ static void completion_wait_destroy( struct object *obj) { free( tmp ); } + + if (do_esync()) + close( wait->esync_fd ); + + if (wait->fsync_idx) fsync_free_shm_idx( wait->fsync_idx ); } static void completion_wait_dump( struct object *obj, int verbose ) @@ -170,6 +182,23 @@ static int completion_wait_signaled( struct object *obj, struct wait_queue_entry return !wait->completion || !list_empty( &wait->queue ); } +static int completion_wait_get_esync_fd( struct object *obj, enum esync_type *type ) +{ + struct completion_wait *wait = (struct completion_wait *)obj; + + *type = ESYNC_MANUAL_SERVER; + return wait->esync_fd; +} + +static unsigned int completion_wait_get_fsync_idx( struct object *obj, enum fsync_type *type ) +{ + struct completion_wait *wait = (struct completion_wait *)obj; + + assert( obj->ops == &completion_wait_ops ); + *type = FSYNC_MANUAL_SERVER; + return wait->fsync_idx; +} + static void completion_wait_satisfied( struct object *obj, struct wait_queue_entry *entry ) { struct completion_wait *wait = (struct completion_wait *)obj; @@ -209,6 +238,22 @@ static void completion_remove_queue( struct object *obj, struct wait_queue_entry completion->wait->obj.ops->remove_queue( &completion->wait->obj, entry ); } +static int completion_get_esync_fd( struct object *obj, enum esync_type *type ) +{ + struct completion *completion = (struct completion *)obj; + + assert( obj->ops == &completion_ops ); + return completion->wait->obj.ops->get_esync_fd( &completion->wait->obj, type ); +} + +static unsigned int completion_get_fsync_idx( struct object *obj, enum fsync_type *type ) +{ + struct completion *completion = (struct completion *)obj; + + assert( obj->ops == &completion_ops ); + return completion->wait->obj.ops->get_fsync_idx( &completion->wait->obj, type ); +} + static void completion_destroy( struct object *obj ) { struct completion *completion = (struct completion *)obj; @@ -237,6 +282,14 @@ static struct completion *create_completion( struct object *root, const struct u completion->wait->completion = completion; list_init( &completion->wait->queue ); completion->wait->depth = 0; + completion->wait->fsync_idx = 0; + + if (do_fsync()) + completion->wait->fsync_idx = fsync_alloc_shm( 0, 0 ); + + if (do_esync()) + completion->wait->esync_fd = esync_create_fd( 0, 0 ); + return completion; } @@ -260,6 +313,7 @@ void add_completion( struct completion *completion, apc_param_t ckey, apc_param_ list_add_tail( &completion->wait->queue, &msg->queue_entry ); completion->wait->depth++; + wake_up( &completion->wait->obj, 1 ); } @@ -333,7 +387,18 @@ DECL_HANDLER(remove_completion) entry = list_head( &wait->queue ); if (!entry) - set_error( STATUS_PENDING ); + { + if (wait->completion) + { + if (do_fsync() || do_esync()) + { + /* completion_wait_satisfied is not called, so lock completion here. */ + current->locked_completion = grab_object( wait ); + } + set_error( STATUS_PENDING ); + } + else set_error( STATUS_ABANDONED_WAIT_0 ); + } else { list_remove( entry ); @@ -344,6 +409,15 @@ DECL_HANDLER(remove_completion) reply->status = msg->status; reply->information = msg->information; free( msg ); + + if (!completion_wait_signaled( &wait->obj, NULL )) + { + if (do_fsync()) + fsync_clear( &wait->obj ); + + if (do_esync()) + esync_clear( wait->esync_fd ); + } } release_object( wait ); From 5d458e3c3048e994a15e762090bc35897f2bfb80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Jan 2023 14:09:56 +0100 Subject: [PATCH 0998/2777] sechost: Use heap_strdup_multi_AtoW for dependencies in CreateServiceA. (cherry picked from commit bea9ef83cc062372a1b6acfb31381a9ab86915ed) --- dlls/sechost/service.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/sechost/service.c b/dlls/sechost/service.c index dfa1634db07..1062893b263 100644 --- a/dlls/sechost/service.c +++ b/dlls/sechost/service.c @@ -366,7 +366,7 @@ SC_HANDLE WINAPI DECLSPEC_HOTPATCH CreateServiceA( SC_HANDLE manager, const char display_nameW = heap_strdupAtoW( display_name ); pathW = heap_strdupAtoW( path ); groupW = heap_strdupAtoW( group ); - dependenciesW = heap_strdupAtoW( dependencies ); + dependenciesW = heap_strdup_multi_AtoW( dependencies ); usernameW = heap_strdupAtoW( username ); passwordW = heap_strdupAtoW( password ); From 09a89988d093fab3b0c74a34894bc50ee248bd1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Jan 2023 15:13:41 +0100 Subject: [PATCH 0999/2777] services: Use a separate allocation for NotifyParamsArray[0].params. The pointer might be freed by RPC NdrPointerFree, which will try to use a dedicated free call for the array elements, and fail. (cherry picked from commit 03aa9e13e70e0f4c8087a93c7435eff75fc7cddd) --- programs/services/rpc.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/programs/services/rpc.c b/programs/services/rpc.c index de918d33b1f..e56d25ea1af 100644 --- a/programs/services/rpc.c +++ b/programs/services/rpc.c @@ -102,6 +102,8 @@ static void sc_notify_release(struct sc_notify_handle *notify) if (r == 0) { CloseHandle(notify->event); + if (notify->params_list) + free(notify->params_list->NotifyParamsArray[0].params); free(notify->params_list); free(notify); } @@ -841,11 +843,14 @@ static void fill_notify(struct sc_notify_handle *notify, struct service_entry *s SC_RPC_NOTIFY_PARAMS_LIST *list; SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 *cparams; - list = calloc(1, sizeof(SC_RPC_NOTIFY_PARAMS_LIST) + sizeof(SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2)); + list = calloc(1, sizeof(SC_RPC_NOTIFY_PARAMS_LIST)); if (!list) return; - - cparams = (SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 *)(list + 1); + if (!(cparams = calloc(1, sizeof(SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2)))) + { + free(list); + return; + } cparams->dwNotifyMask = notify->notify_mask; fill_status_process(&cparams->ServiceStatus, service); From e11e59a3dcbe45a8ee7748712e0dc3cb1b2f5906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Jan 2023 15:34:59 +0100 Subject: [PATCH 1000/2777] dwrite: Statically init the system_fallback locale list. To avoid a crash on DLL unload if it wasn't initialized. (cherry picked from commit 17ac4059a586cdfaa7cabf734396905f04ce80af) --- dlls/dwrite/analyzer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index ca247639403..256e354d2fd 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -551,7 +551,10 @@ struct dwrite_fontfallback_builder size_t mappings_size; }; -static struct fallback_data system_fallback; +static struct fallback_data system_fallback = +{ + .locales = LIST_INIT(system_fallback.locales), +}; static void release_fallback_mapping(struct fallback_mapping *mapping) { From feb92a451d008271a569b36d8153ee1dd5ee2812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 13 Jan 2023 08:19:27 +0100 Subject: [PATCH 1001/2777] schedsvc: Avoid mismatching heap in SchRpcEnumFolders. (cherry picked from commit d59e89dab1301ea5a0178f84d4592d574d0141e7) --- dlls/schedsvc/schedsvc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/schedsvc/schedsvc.c b/dlls/schedsvc/schedsvc.c index c670c8b1cbb..671614a1bcf 100644 --- a/dlls/schedsvc/schedsvc.c +++ b/dlls/schedsvc/schedsvc.c @@ -660,7 +660,7 @@ HRESULT __cdecl SchRpcEnumFolders(const WCHAR *path, DWORD flags, DWORD *start_i { TASK_NAMES new_list; allocated *= 2; - new_list = heap_realloc(list, allocated * sizeof(list[0])); + new_list = realloc(list, allocated * sizeof(list[0])); if (!new_list) { hr = E_OUTOFMEMORY; From 61a5e957a9ac9dabfb699188221aec353cdbe3d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 13 Jan 2023 08:19:27 +0100 Subject: [PATCH 1002/2777] schedsvc: Avoid mismatching heap in SchRpcEnumTasks. (cherry picked from commit 381e756a9b8c60a9010bbaf4579bb16c65ed3fe5) --- dlls/schedsvc/schedsvc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/schedsvc/schedsvc.c b/dlls/schedsvc/schedsvc.c index 671614a1bcf..784fc5d944d 100644 --- a/dlls/schedsvc/schedsvc.c +++ b/dlls/schedsvc/schedsvc.c @@ -768,7 +768,7 @@ HRESULT __cdecl SchRpcEnumTasks(const WCHAR *path, DWORD flags, DWORD *start_ind { TASK_NAMES new_list; allocated *= 2; - new_list = heap_realloc(list, allocated * sizeof(list[0])); + new_list = realloc(list, allocated * sizeof(list[0])); if (!new_list) { hr = E_OUTOFMEMORY; From efca62caa5225d15fddd6cf49117464e12942b6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 13 Jan 2023 08:19:27 +0100 Subject: [PATCH 1003/2777] schedsvc: Avoid mismatching heap in RPC allocations. SchRpcEnumFolders names are allocated with malloc, and later freed in __finally_ITaskSchedulerService_SchRpcEnumFolders using MIDL_user_free. (cherry picked from commit 554cfb1984c903e358d5ad25dd625d3764535ec5) --- dlls/schedsvc/schedsvc_private.h | 2 -- dlls/schedsvc/svc_main.c | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/dlls/schedsvc/schedsvc_private.h b/dlls/schedsvc/schedsvc_private.h index 62b25f97794..224b4c1b398 100644 --- a/dlls/schedsvc/schedsvc_private.h +++ b/dlls/schedsvc/schedsvc_private.h @@ -19,8 +19,6 @@ #ifndef __WINE_SCHEDSVC_PRIVATE_H__ #define __WINE_SCHEDSVC_PRIVATE_H__ -#include "wine/heap.h" - void schedsvc_auto_start(void) DECLSPEC_HIDDEN; void add_job(const WCHAR *name) DECLSPEC_HIDDEN; void remove_job(const WCHAR *name) DECLSPEC_HIDDEN; diff --git a/dlls/schedsvc/svc_main.c b/dlls/schedsvc/svc_main.c index 7681a220592..e3e1fcb5ffd 100644 --- a/dlls/schedsvc/svc_main.c +++ b/dlls/schedsvc/svc_main.c @@ -418,10 +418,10 @@ void WINAPI ServiceMain(DWORD argc, LPWSTR *argv) void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len) { - return heap_alloc(len); + return malloc(len); } void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr) { - heap_free(ptr); + free(ptr); } From dbbafbb63dbbfa25af830aec09566324c35c16f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 13 Jan 2023 08:17:46 +0100 Subject: [PATCH 1004/2777] schedsvc: Use CRT allocation functions in remaining calls. (cherry picked from commit d418cb75515588dc7612579e3f14a442de8fe0be) --- dlls/schedsvc/svc_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/schedsvc/svc_main.c b/dlls/schedsvc/svc_main.c index e3e1fcb5ffd..349dae756fc 100644 --- a/dlls/schedsvc/svc_main.c +++ b/dlls/schedsvc/svc_main.c @@ -244,7 +244,7 @@ void schedsvc_auto_start(void) { if (!QueryServiceConfigW(service, NULL, 0, &cfg_size) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - cfg = HeapAlloc(GetProcessHeap(), 0, cfg_size); + cfg = malloc(cfg_size); if (cfg) { if (QueryServiceConfigW(service, cfg, cfg_size, &cfg_size)) @@ -257,7 +257,7 @@ void schedsvc_auto_start(void) start_type = SERVICE_AUTO_START; } } - HeapFree(GetProcessHeap(), 0, cfg); + free(cfg); } } else From f0b89d09538b27fb0d70e3c3697861e68be69701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 25 Jan 2023 01:02:15 +0100 Subject: [PATCH 1005/2777] oledb32: Fix error info cleanup dispparams rgvarg index. (cherry picked from commit e7fbdd1eb2f7e60e3ce3829c8468e39fdcb2ac3a) --- dlls/oledb32/errorinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/oledb32/errorinfo.c b/dlls/oledb32/errorinfo.c index b6e0d10e8e0..6857caeb368 100644 --- a/dlls/oledb32/errorinfo.c +++ b/dlls/oledb32/errorinfo.c @@ -120,7 +120,7 @@ static ULONG WINAPI errorrecords_Release(IErrorInfo* iface) IUnknown_Release(This->records[i].custom_error); for (j = 0; j < dispparams->cArgs && dispparams->rgvarg; j++) - VariantClear(&dispparams->rgvarg[i]); + VariantClear(&dispparams->rgvarg[j]); CoTaskMemFree(dispparams->rgvarg); CoTaskMemFree(dispparams->rgdispidNamedArgs); } From 1e7da189ba589b9c58520817ad85f223548b99e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 25 Jan 2023 02:10:29 +0100 Subject: [PATCH 1006/2777] oledb32/tests: Avoid use-after-free and unused assignment. (cherry picked from commit e091a7b8178cf515864b82ae8239f4e977f39179) --- dlls/oledb32/tests/database.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dlls/oledb32/tests/database.c b/dlls/oledb32/tests/database.c index 5d99aef7a89..26e3ebf2186 100644 --- a/dlls/oledb32/tests/database.c +++ b/dlls/oledb32/tests/database.c @@ -1043,13 +1043,9 @@ static void test_odbc_provider(void) ok(propidlist.cPropertyIDs == 14, "got %ld\n", propinfoset->cPropertyInfos); for (i = 0; i < propidlist.cPropertyIDs; i++) - { ok(properties[i] == propidlist.rgPropertyIDs[i], "%ld, got %ld\n", i, propidlist.rgPropertyIDs[i]); - propidlist.rgPropertyIDs[i] = propinfoset->rgPropertyInfos[i].dwPropertyID; - } - CoTaskMemFree(propidlist.rgPropertyIDs); CoTaskMemFree(propset); } From 5a9814357e87872529bab3f874dbcf90086e98f0 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 30 Jan 2023 17:14:33 -0600 Subject: [PATCH 1007/2777] ntdll: Add stub for NtQueryInformationProcess( ProcessHandleTable ). CW-Bug-Id: #21856 --- dlls/ntdll/unix/process.c | 6 ++++++ include/winternl.h | 1 + 2 files changed, 7 insertions(+) diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c index ca153a30bf2..4b9c42467e7 100644 --- a/dlls/ntdll/unix/process.c +++ b/dlls/ntdll/unix/process.c @@ -1343,6 +1343,7 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class else if (!handle) ret = STATUS_INVALID_HANDLE; else { + FIXME( "ProcessHandleCount (%p,%p,0x%08x,%p) stub\n", handle, info, (int)size, ret_len ); memset(info, 0, 4); len = 4; } @@ -1355,6 +1356,11 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class } break; + case ProcessHandleTable: + FIXME( "ProcessHandleTable (%p,%p,0x%08x,%p) stub\n", handle, info, (int)size, ret_len ); + len = 0; + break; + case ProcessAffinityMask: len = sizeof(ULONG_PTR); if (size == len) diff --git a/include/winternl.h b/include/winternl.h index c720d962933..8e736e604d3 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -1574,6 +1574,7 @@ typedef enum _PROCESSINFOCLASS { ProcessConsoleHostProcess = 49, ProcessWindowInformation = 50, ProcessHandleInformation = 51, + ProcessHandleTable = 58, ProcessPowerThrottlingState = 77, ProcessLeapSecondInformation = 97, MaxProcessInfoClass, From 66d3f24be48962e65ecf9ea97f28251dddde1e98 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 27 Jan 2023 14:53:13 -0600 Subject: [PATCH 1008/2777] ntdll: Add an option to load dlls to high addresses on 64 bit. CW-Bug-Id: #21841 --- dlls/ntdll/unix/loader.c | 9 +++++++++ dlls/ntdll/unix/unix_private.h | 1 + dlls/ntdll/unix/virtual.c | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index f869a3acc24..0a9e16afbbc 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2304,6 +2304,7 @@ BOOL fsync_simulate_sched_quantum; BOOL alert_simulate_sched_quantum; BOOL no_priv_elevation; BOOL localsystem_sid; +BOOL high_dll_addresses; static void hacks_init(void) { @@ -2351,6 +2352,14 @@ static void hacks_init(void) if (env_str) report_native_pc_as_ntdll = atoi(env_str); else if (sgi) report_native_pc_as_ntdll = !strcmp(sgi, "700330"); +#ifdef _WIN64 + env_str = getenv("WINE_HIGH_DLL_ADDRESSES"); + if (env_str) high_dll_addresses = atoi(env_str); + else if (sgi) high_dll_addresses = !strcmp(sgi, "1938010"); + if (high_dll_addresses) + ERR("HACK: moving dlls to high addresses.\n"); +#endif + if (main_argc > 1 && strstr(main_argv[1], "MicrosoftEdgeUpdate.exe")) { ERR("HACK: reporting LocalSystem account SID.\n"); diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index d186d29d735..0cfa149e163 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -155,6 +155,7 @@ extern BOOL fsync_simulate_sched_quantum DECLSPEC_HIDDEN; extern BOOL alert_simulate_sched_quantum DECLSPEC_HIDDEN; extern BOOL no_priv_elevation DECLSPEC_HIDDEN; extern BOOL localsystem_sid DECLSPEC_HIDDEN; +extern BOOL high_dll_addresses DECLSPEC_HIDDEN; extern void init_environment( int argc, char *argv[], char *envp[] ) DECLSPEC_HIDDEN; extern void init_startup_info(void) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 148d1a47855..22a66f4116d 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -2674,6 +2674,12 @@ static NTSTATUS virtual_map_image( HANDLE mapping, ACCESS_MASK access, void **ad base = wine_server_get_ptr( image_info->base ); if ((ULONG_PTR)base != image_info->base) base = NULL; +#ifdef _WIN64 + if (high_dll_addresses && base && (ULONG_PTR)base > 0x100000000 && image_info->image_charact & IMAGE_FILE_DLL + && !(image_info->image_charact & IMAGE_FILE_RELOCS_STRIPPED)) + base = (char *)base + 0x800000000; +#endif + if ((char *)base >= (char *)address_space_start) /* make sure the DOS area remains free */ status = map_view( &view, base, size, alloc_type & MEM_TOP_DOWN, vprot, get_zero_bits_mask( zero_bits ), 0 ); From c1be0f3f08cb777a9ff6bf8fd0d963dadda09f86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 11 Jan 2023 14:42:32 +0100 Subject: [PATCH 1009/2777] comctl32/tests: Test unicode nature of window subclasses. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43073 (cherry picked from commit 711f05c4327091504030b8d6570eeeadac5ae03e) --- dlls/comctl32/tests/subclass.c | 70 ++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/dlls/comctl32/tests/subclass.c b/dlls/comctl32/tests/subclass.c index e2e8573f4c0..684593e6ed7 100644 --- a/dlls/comctl32/tests/subclass.c +++ b/dlls/comctl32/tests/subclass.c @@ -34,9 +34,14 @@ static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR static BOOL (WINAPI *pRemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR); static LRESULT (WINAPI *pDefSubclassProc)(HWND, UINT, WPARAM, LPARAM); +#define IS_WNDPROC_HANDLE(x) (((ULONG_PTR)(x) >> 16) == (~0u >> 16)) + #define SEND_NEST 0x01 #define DELETE_SELF 0x02 #define DELETE_PREV 0x04 +#define EXPECT_UNICODE 0x10 +#define EXPECT_WNDPROC_1 0x20 +#define EXPECT_WNDPROC_3 0x40 struct message { int procnum; /* WndProc id message is expected from */ @@ -166,15 +171,47 @@ static void ok_sequence(const struct message *expected, const char *context) flush_sequence(); } +static LRESULT WINAPI wnd_proc_1(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +static LRESULT WINAPI wnd_proc_3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + +#define check_unicode(a, b) check_unicode_(__LINE__, a, b) +static void check_unicode_(int line, HWND hwnd, DWORD flags) +{ + WNDPROC proc; + BOOL ret; + + ret = IsWindowUnicode(hwnd); + ok_(__FILE__, line)(ret == !!(flags & EXPECT_UNICODE), "IsWindowUnicode returned %u\n", ret); + + proc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC); + ok_(__FILE__, line)(IS_WNDPROC_HANDLE(proc) == !(flags & EXPECT_UNICODE), "got proc %p\n", proc); + + proc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC); + if (flags & EXPECT_UNICODE) + ok_(__FILE__, line)(IS_WNDPROC_HANDLE(proc), "got proc %p\n", proc); + else if (flags & EXPECT_WNDPROC_1) + ok_(__FILE__, line)(proc == wnd_proc_1, "got proc %p\n", proc); + else if (flags & EXPECT_WNDPROC_3) + todo_wine_if(proc == wnd_proc_1) ok_(__FILE__, line)(proc == wnd_proc_3, "got proc %p\n", proc); + else + ok_(__FILE__, line)(!IS_WNDPROC_HANDLE(proc), "got proc %p\n", proc); +} + static LRESULT WINAPI wnd_proc_1(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { + DWORD flags = GetWindowLongA(hwnd, GWLP_USERDATA); struct message msg; + + todo_wine_if(flags & EXPECT_UNICODE) check_unicode(hwnd, flags); if(message == WM_USER) { msg.wParam = wParam; msg.procnum = 1; add_message(&msg); } + if (message == WM_CHAR) { + ok(!(wParam & ~0xff), "got wParam %#Ix\n", wParam); + } return DefWindowProcA(hwnd, message, wParam, lParam); } @@ -194,7 +231,10 @@ static LRESULT WINAPI wnd_proc_3(HWND hwnd, UINT message, WPARAM wParam, LPARAM static LRESULT WINAPI wnd_proc_sub(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uldSubclass, DWORD_PTR dwRefData) { + DWORD flags = GetWindowLongA(hwnd, GWLP_USERDATA); struct message msg; + + todo_wine_if(flags & EXPECT_UNICODE) check_unicode(hwnd, flags); if(message == WM_USER) { msg.wParam = wParam; @@ -205,13 +245,24 @@ static LRESULT WINAPI wnd_proc_sub(HWND hwnd, UINT message, WPARAM wParam, LPARA if(dwRefData & DELETE_SELF) { pRemoveWindowSubclass(hwnd, wnd_proc_sub, uldSubclass); pRemoveWindowSubclass(hwnd, wnd_proc_sub, uldSubclass); + todo_wine_if(flags & EXPECT_UNICODE) check_unicode(hwnd, flags); } if(dwRefData & DELETE_PREV) + { pRemoveWindowSubclass(hwnd, wnd_proc_sub, uldSubclass-1); + todo_wine_if(flags & EXPECT_UNICODE) check_unicode(hwnd, flags); + } if(dwRefData & SEND_NEST) + { SendMessageA(hwnd, WM_USER, wParam+1, 0); + todo_wine_if(flags & EXPECT_UNICODE) check_unicode(hwnd, flags); + } } } + if (message == WM_CHAR) { + todo_wine + ok(wParam == 0x30c2, "got wParam %#Ix\n", wParam); + } return pDefSubclassProc(hwnd, message, wParam, lParam); } @@ -221,17 +272,27 @@ static void test_subclass(void) HWND hwnd = CreateWindowExA(0, "TestSubclass", "Test subclass", WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL); ok(hwnd != NULL, "failed to create test subclass wnd\n"); + check_unicode(hwnd, EXPECT_WNDPROC_1); + SetWindowLongA(hwnd, GWLP_USERDATA, EXPECT_WNDPROC_1); ret = pSetWindowSubclass(hwnd, wnd_proc_sub, 2, 0); ok(ret == TRUE, "Expected TRUE\n"); + todo_wine check_unicode(hwnd, EXPECT_UNICODE); + SetWindowLongA(hwnd, GWLP_USERDATA, EXPECT_UNICODE); + SendMessageA(hwnd, WM_USER, 1, 0); SendMessageA(hwnd, WM_USER, 2, 0); ok_sequence(Sub_BasicTest, "Basic"); + SendMessageW(hwnd, WM_CHAR, 0x30c2, 1); ret = pSetWindowSubclass(hwnd, wnd_proc_sub, 2, DELETE_SELF); ok(ret == TRUE, "Expected TRUE\n"); + todo_wine check_unicode(hwnd, EXPECT_UNICODE); + SendMessageA(hwnd, WM_USER, 1, 1); ok_sequence(Sub_DeletedTest, "Deleted"); + check_unicode(hwnd, EXPECT_WNDPROC_1); + SetWindowLongA(hwnd, GWLP_USERDATA, EXPECT_WNDPROC_1); SendMessageA(hwnd, WM_USER, 1, 0); ok_sequence(Sub_AfterDeletedTest, "After Deleted"); @@ -239,15 +300,22 @@ static void test_subclass(void) ret = pSetWindowSubclass(hwnd, wnd_proc_sub, 2, 0); ok(ret == TRUE, "Expected TRUE\n"); orig_proc_3 = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)wnd_proc_3); + check_unicode(hwnd, EXPECT_WNDPROC_3); + SetWindowLongA(hwnd, GWLP_USERDATA, EXPECT_WNDPROC_3); + SendMessageA(hwnd, WM_USER, 1, 0); SendMessageA(hwnd, WM_USER, 2, 0); ok_sequence(Sub_OldAfterNewTest, "Old after New"); ret = pSetWindowSubclass(hwnd, wnd_proc_sub, 4, 0); ok(ret == TRUE, "Expected TRUE\n"); + check_unicode(hwnd, EXPECT_WNDPROC_3); + SendMessageA(hwnd, WM_USER, 1, 0); ok_sequence(Sub_MixTest, "Mix"); + check_unicode(hwnd, EXPECT_WNDPROC_3); + /* Now the fun starts */ ret = pSetWindowSubclass(hwnd, wnd_proc_sub, 4, SEND_NEST); ok(ret == TRUE, "Expected TRUE\n"); @@ -275,6 +343,8 @@ static void test_subclass(void) pRemoveWindowSubclass(hwnd, wnd_proc_sub, 2); pRemoveWindowSubclass(hwnd, wnd_proc_sub, 5); + check_unicode(hwnd, EXPECT_WNDPROC_3); + DestroyWindow(hwnd); } From 3594c6abf91a8800a742a8a8ec7d4d4adf1ea306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 10 Jan 2023 17:39:17 +0100 Subject: [PATCH 1010/2777] comctl32: Save unicode window nature on SetWindowSubclass call. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43073 (cherry picked from commit 591f585a55034ef68cfba150c12eef107a0e8120) --- dlls/comctl32/comctl32.h | 1 + dlls/comctl32/commctrl.c | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/dlls/comctl32/comctl32.h b/dlls/comctl32/comctl32.h index 7dfdf089eb1..faff3f30717 100644 --- a/dlls/comctl32/comctl32.h +++ b/dlls/comctl32/comctl32.h @@ -209,6 +209,7 @@ typedef struct SUBCLASSPROCS *SubclassProcs; SUBCLASSPROCS *stackpos; WNDPROC origproc; + int is_unicode; int running; } SUBCLASS_INFO, *LPSUBCLASS_INFO; diff --git a/dlls/comctl32/commctrl.c b/dlls/comctl32/commctrl.c index c5910b40869..37cb66b9bbb 100644 --- a/dlls/comctl32/commctrl.c +++ b/dlls/comctl32/commctrl.c @@ -1103,7 +1103,8 @@ BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass, SetPropW (hWnd, COMCTL32_wSubclass, stack); /* set window procedure to our own and save the current one */ - if (IsWindowUnicode (hWnd)) + stack->is_unicode = IsWindowUnicode (hWnd); + if (stack->is_unicode) stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)COMCTL32_SubclassProc); else @@ -1127,7 +1128,7 @@ BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass, proc = Alloc(sizeof(SUBCLASSPROCS)); if (!proc) { ERR ("Failed to allocate subclass entry in stack\n"); - if (IsWindowUnicode (hWnd)) + if (stack->is_unicode) SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); else SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); @@ -1246,7 +1247,7 @@ BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR u if (!stack->SubclassProcs && !stack->running) { TRACE("Last Subclass removed, cleaning up\n"); /* clean up our heap and reset the original window procedure */ - if (IsWindowUnicode (hWnd)) + if (stack->is_unicode) SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); else SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); @@ -1288,7 +1289,7 @@ static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam if (!stack->SubclassProcs && !stack->running) { TRACE("Last Subclass removed, cleaning up\n"); /* clean up our heap and reset the original window procedure */ - if (IsWindowUnicode (hWnd)) + if (stack->is_unicode) SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); else SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); @@ -1331,7 +1332,7 @@ LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar /* If we are at the end of stack then we have to call the original * window procedure */ if (!stack->stackpos) { - if (IsWindowUnicode (hWnd)) + if (stack->is_unicode) ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam); else ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam); From 0204628e21145fa3dd14ea5cdb577a51e4ba977a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 10 Jan 2023 17:39:17 +0100 Subject: [PATCH 1011/2777] comctl32: Always use unicode messages for subclass procedures. Final Fantasy XIV Online depends on this for its text input. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43073 (cherry picked from commit 8387d2fefff6886235a0ba46042e96ff2c6e89cc) --- dlls/comctl32/commctrl.c | 13 +++---------- dlls/comctl32/tests/subclass.c | 15 +++++++-------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/dlls/comctl32/commctrl.c b/dlls/comctl32/commctrl.c index 37cb66b9bbb..eae64022d65 100644 --- a/dlls/comctl32/commctrl.c +++ b/dlls/comctl32/commctrl.c @@ -1104,12 +1104,8 @@ BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass, /* set window procedure to our own and save the current one */ stack->is_unicode = IsWindowUnicode (hWnd); - if (stack->is_unicode) - stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC, - (DWORD_PTR)COMCTL32_SubclassProc); - else - stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC, - (DWORD_PTR)COMCTL32_SubclassProc); + stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC, + (DWORD_PTR)COMCTL32_SubclassProc); } else { /* Check to see if we have called this function with the same uIDSubClass @@ -1332,10 +1328,7 @@ LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar /* If we are at the end of stack then we have to call the original * window procedure */ if (!stack->stackpos) { - if (stack->is_unicode) - ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam); - else - ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam); + ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam); } else { const SUBCLASSPROCS *proc = stack->stackpos; stack->stackpos = stack->stackpos->next; diff --git a/dlls/comctl32/tests/subclass.c b/dlls/comctl32/tests/subclass.c index 684593e6ed7..3c07a9d221c 100644 --- a/dlls/comctl32/tests/subclass.c +++ b/dlls/comctl32/tests/subclass.c @@ -202,7 +202,7 @@ static LRESULT WINAPI wnd_proc_1(HWND hwnd, UINT message, WPARAM wParam, LPARAM DWORD flags = GetWindowLongA(hwnd, GWLP_USERDATA); struct message msg; - todo_wine_if(flags & EXPECT_UNICODE) check_unicode(hwnd, flags); + check_unicode(hwnd, flags); if(message == WM_USER) { msg.wParam = wParam; @@ -234,7 +234,7 @@ static LRESULT WINAPI wnd_proc_sub(HWND hwnd, UINT message, WPARAM wParam, LPARA DWORD flags = GetWindowLongA(hwnd, GWLP_USERDATA); struct message msg; - todo_wine_if(flags & EXPECT_UNICODE) check_unicode(hwnd, flags); + check_unicode(hwnd, flags); if(message == WM_USER) { msg.wParam = wParam; @@ -245,22 +245,21 @@ static LRESULT WINAPI wnd_proc_sub(HWND hwnd, UINT message, WPARAM wParam, LPARA if(dwRefData & DELETE_SELF) { pRemoveWindowSubclass(hwnd, wnd_proc_sub, uldSubclass); pRemoveWindowSubclass(hwnd, wnd_proc_sub, uldSubclass); - todo_wine_if(flags & EXPECT_UNICODE) check_unicode(hwnd, flags); + check_unicode(hwnd, flags); } if(dwRefData & DELETE_PREV) { pRemoveWindowSubclass(hwnd, wnd_proc_sub, uldSubclass-1); - todo_wine_if(flags & EXPECT_UNICODE) check_unicode(hwnd, flags); + check_unicode(hwnd, flags); } if(dwRefData & SEND_NEST) { SendMessageA(hwnd, WM_USER, wParam+1, 0); - todo_wine_if(flags & EXPECT_UNICODE) check_unicode(hwnd, flags); + check_unicode(hwnd, flags); } } } if (message == WM_CHAR) { - todo_wine ok(wParam == 0x30c2, "got wParam %#Ix\n", wParam); } return pDefSubclassProc(hwnd, message, wParam, lParam); @@ -277,7 +276,7 @@ static void test_subclass(void) ret = pSetWindowSubclass(hwnd, wnd_proc_sub, 2, 0); ok(ret == TRUE, "Expected TRUE\n"); - todo_wine check_unicode(hwnd, EXPECT_UNICODE); + check_unicode(hwnd, EXPECT_UNICODE); SetWindowLongA(hwnd, GWLP_USERDATA, EXPECT_UNICODE); SendMessageA(hwnd, WM_USER, 1, 0); @@ -287,7 +286,7 @@ static void test_subclass(void) ret = pSetWindowSubclass(hwnd, wnd_proc_sub, 2, DELETE_SELF); ok(ret == TRUE, "Expected TRUE\n"); - todo_wine check_unicode(hwnd, EXPECT_UNICODE); + check_unicode(hwnd, EXPECT_UNICODE); SendMessageA(hwnd, WM_USER, 1, 1); ok_sequence(Sub_DeletedTest, "Deleted"); From 351dc5979d4175c24cc00728cb0c3d9e287c6539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Jan 2023 15:40:43 +0100 Subject: [PATCH 1012/2777] comctl32: Skip restoring window proc if it has been modified. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43073 (cherry picked from commit 078c6e5ab2acd70b448838189c81c7ff484a4ee9) --- dlls/comctl32/commctrl.c | 4 +++- dlls/comctl32/tests/subclass.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dlls/comctl32/commctrl.c b/dlls/comctl32/commctrl.c index eae64022d65..4c5900bc37f 100644 --- a/dlls/comctl32/commctrl.c +++ b/dlls/comctl32/commctrl.c @@ -1243,7 +1243,9 @@ BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR u if (!stack->SubclassProcs && !stack->running) { TRACE("Last Subclass removed, cleaning up\n"); /* clean up our heap and reset the original window procedure */ - if (stack->is_unicode) + if ((WNDPROC)GetWindowLongPtrW (hWnd, GWLP_WNDPROC) != COMCTL32_SubclassProc) + WARN("Window procedure has been modified, skipping restore\n"); + else if (stack->is_unicode) SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); else SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); diff --git a/dlls/comctl32/tests/subclass.c b/dlls/comctl32/tests/subclass.c index 3c07a9d221c..bc3fc6f1d91 100644 --- a/dlls/comctl32/tests/subclass.c +++ b/dlls/comctl32/tests/subclass.c @@ -192,7 +192,7 @@ static void check_unicode_(int line, HWND hwnd, DWORD flags) else if (flags & EXPECT_WNDPROC_1) ok_(__FILE__, line)(proc == wnd_proc_1, "got proc %p\n", proc); else if (flags & EXPECT_WNDPROC_3) - todo_wine_if(proc == wnd_proc_1) ok_(__FILE__, line)(proc == wnd_proc_3, "got proc %p\n", proc); + ok_(__FILE__, line)(proc == wnd_proc_3, "got proc %p\n", proc); else ok_(__FILE__, line)(!IS_WNDPROC_HANDLE(proc), "got proc %p\n", proc); } From 4e6665b601b7e4b430332180842ed90df101e332 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Thu, 19 Jan 2023 21:22:36 +0300 Subject: [PATCH 1013/2777] windows.globalization: Implement ILanguage::get_LanguageTag(). Signed-off-by: Nikolay Sivov (cherry picked from commit fbbc2c7c10d107a1dc6f02abc87692e3698cfb93) --- dlls/windows.globalization/classes.idl | 12 + dlls/windows.globalization/main.c | 291 +++++++++++++++++- .../tests/globalization.c | 87 ++++++ include/windows.globalization.idl | 2 + include/windows.system.userprofile.idl | 2 + 5 files changed, 390 insertions(+), 4 deletions(-) diff --git a/dlls/windows.globalization/classes.idl b/dlls/windows.globalization/classes.idl index 94fc53c0dd5..ded6b7572e8 100644 --- a/dlls/windows.globalization/classes.idl +++ b/dlls/windows.globalization/classes.idl @@ -20,4 +20,16 @@ #pragma makedep register +#ifdef __WIDL__ +#pragma winrt ns_prefix +#endif + +import "inspectable.idl"; +import "asyncinfo.idl"; +import "eventtoken.idl"; +import "windowscontracts.idl"; +import "windows.foundation.idl"; + +#define DO_NO_IMPORTS +#include "windows.globalization.idl" #include "windows.system.userprofile.idl" diff --git a/dlls/windows.globalization/main.c b/dlls/windows.globalization/main.c index 21ea2908679..d5a5895938f 100644 --- a/dlls/windows.globalization/main.c +++ b/dlls/windows.globalization/main.c @@ -234,16 +234,156 @@ struct windows_globalization LONG ref; }; +struct language_factory +{ + IActivationFactory IActivationFactory_iface; + ILanguageFactory ILanguageFactory_iface; + LONG ref; +}; + +struct language +{ + ILanguage ILanguage_iface; + LONG ref; + WCHAR name[LOCALE_NAME_MAX_LENGTH]; +}; + static inline struct windows_globalization *impl_from_IActivationFactory(IActivationFactory *iface) { return CONTAINING_RECORD(iface, struct windows_globalization, IActivationFactory_iface); } +static inline struct language_factory *impl_language_factory_from_IActivationFactory(IActivationFactory *iface) +{ + return CONTAINING_RECORD(iface, struct language_factory, IActivationFactory_iface); +} + static inline struct windows_globalization *impl_from_IGlobalizationPreferencesStatics(IGlobalizationPreferencesStatics *iface) { return CONTAINING_RECORD(iface, struct windows_globalization, IGlobalizationPreferencesStatics_iface); } +static inline struct language_factory *impl_from_ILanguageFactory(ILanguageFactory *iface) +{ + return CONTAINING_RECORD(iface, struct language_factory, ILanguageFactory_iface); +} + +static inline struct language *impl_from_ILanguage(ILanguage *iface) +{ + return CONTAINING_RECORD(iface, struct language, ILanguage_iface); +} + +static HRESULT STDMETHODCALLTYPE language_QueryInterface( + ILanguage *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_IAgileObject) || + IsEqualGUID(iid, &IID_ILanguage)) + { + IUnknown_AddRef(iface); + *out = iface; + return S_OK; + } + + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG STDMETHODCALLTYPE language_AddRef( + ILanguage *iface) +{ + struct language *language = impl_from_ILanguage(iface); + ULONG ref = InterlockedIncrement(&language->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + return ref; +} + +static ULONG STDMETHODCALLTYPE language_Release( + ILanguage *iface) +{ + struct language *language = impl_from_ILanguage(iface); + ULONG ref = InterlockedDecrement(&language->ref); + + TRACE("iface %p, ref %lu.\n", iface, ref); + + if (!ref) + free(language); + + return ref; +} + +static HRESULT STDMETHODCALLTYPE language_GetIids( + ILanguage *iface, ULONG *iid_count, IID **iids) +{ + FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE language_GetRuntimeClassName( + ILanguage *iface, HSTRING *class_name) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE language_GetTrustLevel( + ILanguage *iface, TrustLevel *trust_level) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE language_get_LanguageTag( + ILanguage *iface, HSTRING *value) +{ + struct language *language = impl_from_ILanguage(iface); + + TRACE("iface %p, value %p.\n", iface, value); + + return WindowsCreateString(language->name, wcslen(language->name), value); +} + +static HRESULT STDMETHODCALLTYPE language_get_DisplayName( + ILanguage *iface, HSTRING *value) +{ + FIXME("iface %p, value %p stub!\n", iface, value); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE language_get_NativeName( + ILanguage *iface, HSTRING *value) +{ + FIXME("iface %p, value %p stub!\n", iface, value); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE language_get_Script( + ILanguage *iface, HSTRING *value) +{ + FIXME("iface %p, value %p stub!\n", iface, value); + return E_NOTIMPL; +} + +static const struct ILanguageVtbl language_vtbl = +{ + language_QueryInterface, + language_AddRef, + language_Release, + /* IInspectable methods */ + language_GetIids, + language_GetRuntimeClassName, + language_GetTrustLevel, + /* ILanguage methods */ + language_get_LanguageTag, + language_get_DisplayName, + language_get_NativeName, + language_get_Script, +}; + static HRESULT STDMETHODCALLTYPE windows_globalization_QueryInterface( IActivationFactory *iface, REFIID iid, void **out) { @@ -454,13 +594,141 @@ static const struct IGlobalizationPreferencesStaticsVtbl globalization_preferenc globalization_preferences_get_WeekStartsOn, }; -static struct windows_globalization windows_globalization = +static struct windows_globalization userprofile_preferences = { {&activation_factory_vtbl}, {&globalization_preferences_vtbl}, 0 }; +static HRESULT STDMETHODCALLTYPE windows_globalization_language_factory_QueryInterface( + IActivationFactory *iface, REFIID iid, void **out) +{ + struct language_factory *factory = impl_language_factory_from_IActivationFactory(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_IAgileObject) || + IsEqualGUID(iid, &IID_IActivationFactory)) + { + IUnknown_AddRef(iface); + *out = iface; + return S_OK; + } + + if (IsEqualGUID(iid, &IID_ILanguageFactory)) + { + IUnknown_AddRef(iface); + *out = &factory->ILanguageFactory_iface; + return S_OK; + } + + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static const struct IActivationFactoryVtbl activation_factory_language_vtbl = +{ + windows_globalization_language_factory_QueryInterface, + windows_globalization_AddRef, + windows_globalization_Release, + /* IInspectable methods */ + windows_globalization_GetIids, + windows_globalization_GetRuntimeClassName, + windows_globalization_GetTrustLevel, + /* IActivationFactory methods */ + windows_globalization_ActivateInstance, +}; + +static HRESULT STDMETHODCALLTYPE language_factory_QueryInterface( + ILanguageFactory *iface, REFIID iid, void **object) +{ + struct language_factory *factory = impl_from_ILanguageFactory(iface); + return IActivationFactory_QueryInterface(&factory->IActivationFactory_iface, iid, object); +} + +static ULONG STDMETHODCALLTYPE language_factory_AddRef( + ILanguageFactory *iface) +{ + struct language_factory *factory = impl_from_ILanguageFactory(iface); + return IActivationFactory_AddRef(&factory->IActivationFactory_iface); +} + +static ULONG STDMETHODCALLTYPE language_factory_Release( + ILanguageFactory *iface) +{ + struct language_factory *factory = impl_from_ILanguageFactory(iface); + return IActivationFactory_Release(&factory->IActivationFactory_iface); +} + +static HRESULT STDMETHODCALLTYPE language_factory_GetIids( + ILanguageFactory *iface, ULONG *iid_count, IID **iids) +{ + FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE language_factory_GetRuntimeClassName( + ILanguageFactory *iface, HSTRING *class_name) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE language_factory_GetTrustLevel( + ILanguageFactory *iface, TrustLevel *trust_level) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT STDMETHODCALLTYPE language_factory_CreateLanguage( + ILanguageFactory *iface, HSTRING tag, ILanguage **value) +{ + const WCHAR *name = WindowsGetStringRawBuffer(tag, NULL); + WCHAR buffer[LOCALE_NAME_MAX_LENGTH]; + struct language *language; + + TRACE("iface %p, tag %p, value %p.\n", iface, tag, value); + + if (!GetLocaleInfoEx(name, LOCALE_SNAME, buffer, ARRAY_SIZE(buffer))) + return E_INVALIDARG; + + if (!(language = calloc(1, sizeof(*language)))) + return E_OUTOFMEMORY; + + language->ILanguage_iface.lpVtbl = &language_vtbl; + language->ref = 1; + wcscpy(language->name, buffer); + + *value = &language->ILanguage_iface; + + return S_OK; +} + +static const struct ILanguageFactoryVtbl language_factory_vtbl = +{ + language_factory_QueryInterface, + language_factory_AddRef, + language_factory_Release, + /* IInspectable methods */ + language_factory_GetIids, + language_factory_GetRuntimeClassName, + language_factory_GetTrustLevel, + /* ILanguageFactory methods */ + language_factory_CreateLanguage, +}; + +static struct language_factory language_factory = +{ + {&activation_factory_language_vtbl}, + {&language_factory_vtbl}, + 0 +}; + HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out) { FIXME("clsid %s, riid %s, out %p stub!\n", debugstr_guid(clsid), debugstr_guid(riid), out); @@ -469,8 +737,23 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out) HRESULT WINAPI DllGetActivationFactory(HSTRING classid, IActivationFactory **factory) { + const WCHAR *name = WindowsGetStringRawBuffer(classid, NULL); + TRACE("classid %s, factory %p.\n", debugstr_hstring(classid), factory); - *factory = &windows_globalization.IActivationFactory_iface; - IUnknown_AddRef(*factory); - return S_OK; + + *factory = NULL; + + if (!wcscmp(name, RuntimeClass_Windows_System_UserProfile_GlobalizationPreferences)) + { + *factory = &userprofile_preferences.IActivationFactory_iface; + IUnknown_AddRef(*factory); + } + else if (!wcscmp(name, RuntimeClass_Windows_Globalization_Language)) + { + *factory = &language_factory.IActivationFactory_iface; + IUnknown_AddRef(*factory); + } + + if (*factory) return S_OK; + return CLASS_E_CLASSNOTAVAILABLE; } diff --git a/dlls/windows.globalization/tests/globalization.c b/dlls/windows.globalization/tests/globalization.c index c42cb67496e..3c12818b743 100644 --- a/dlls/windows.globalization/tests/globalization.c +++ b/dlls/windows.globalization/tests/globalization.c @@ -29,6 +29,8 @@ #define WIDL_using_Windows_Foundation #define WIDL_using_Windows_Foundation_Collections #include "windows.foundation.h" +#define WIDL_using_Windows_Globalization +#include "windows.globalization.h" #define WIDL_using_Windows_System_UserProfile #include "windows.system.userprofile.h" @@ -227,6 +229,90 @@ static void test_GlobalizationPreferences(void) RoUninitialize(); } +static void test_Language(void) +{ + static const WCHAR *class_name = L"Windows.Globalization.Language"; + + IAgileObject *agile_object, *tmp_agile_object; + IInspectable *inspectable, *tmp_inspectable; + WCHAR buffer[LOCALE_NAME_MAX_LENGTH]; + ILanguageFactory *language_factory; + IActivationFactory *factory; + ILanguage *language; + HSTRING tag, str; + const WCHAR *buf; + HRESULT hr; + + hr = RoInitialize(RO_INIT_MULTITHREADED); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = WindowsCreateString(class_name, wcslen(class_name), &str); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory); + ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG), "Unexpected hr %#lx.\n", hr); + WindowsDeleteString(str); + if (hr == REGDB_E_CLASSNOTREG) + { + win_skip("%s runtimeclass not registered, skipping tests.\n", wine_dbgstr_w(class_name)); + RoUninitialize(); + return; + } + + hr = IActivationFactory_QueryInterface(factory, &IID_IInspectable, (void **)&inspectable); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IActivationFactory_QueryInterface(factory, &IID_IAgileObject, (void **)&agile_object); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IActivationFactory_QueryInterface(factory, &IID_ILanguageFactory, (void **)&language_factory); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = ILanguageFactory_QueryInterface(language_factory, &IID_IInspectable, (void **)&tmp_inspectable); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(tmp_inspectable == inspectable, "Unexpected interface pointer %p, expected %p.\n", tmp_inspectable, inspectable); + IInspectable_Release(tmp_inspectable); + + hr = ILanguageFactory_QueryInterface(language_factory, &IID_IAgileObject, (void **)&tmp_agile_object); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(tmp_agile_object == agile_object, "Unexpected interface pointer %p, expected %p.\n", tmp_agile_object, agile_object); + IAgileObject_Release(tmp_agile_object); + + /* Invalid language tag */ + hr = WindowsCreateString(L"test-tag", 8, &str); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = ILanguageFactory_CreateLanguage(language_factory, str, &language); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) + ILanguage_Release(language); + WindowsDeleteString(str); + + hr = WindowsCreateString(L"en-us", 5, &str); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = ILanguageFactory_CreateLanguage(language_factory, str, &language); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + WindowsDeleteString(str); + + hr = ILanguage_get_LanguageTag(language, &tag); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + buf = WindowsGetStringRawBuffer(tag, NULL); + ok(!wcscmp(buf, L"en-US"), "Unexpected tag %s.\n", debugstr_w(buf)); + GetLocaleInfoEx(L"en-us", LOCALE_SNAME, buffer, ARRAY_SIZE(buffer)); + ok(!wcscmp(buf, buffer), "Unexpected tag %s, locale name %s.\n", debugstr_w(buf), debugstr_w(buffer)); + + WindowsDeleteString(tag); + + ILanguage_Release(language); + + ILanguageFactory_Release(language_factory); + + IAgileObject_Release(agile_object); + IInspectable_Release(inspectable); + IActivationFactory_Release(factory); + + RoUninitialize(); +} + START_TEST(globalization) { HMODULE kernel32; @@ -235,4 +321,5 @@ START_TEST(globalization) pGetUserDefaultGeoName = (void*)GetProcAddress(kernel32, "GetUserDefaultGeoName"); test_GlobalizationPreferences(); + test_Language(); } diff --git a/include/windows.globalization.idl b/include/windows.globalization.idl index 03c44703b7e..639d0d24411 100644 --- a/include/windows.globalization.idl +++ b/include/windows.globalization.idl @@ -20,11 +20,13 @@ #pragma winrt ns_prefix #endif +#ifndef DO_NO_IMPORTS import "inspectable.idl"; import "asyncinfo.idl"; import "eventtoken.idl"; import "windowscontracts.idl"; import "windows.foundation.idl"; +#endif namespace Windows { namespace Globalization { diff --git a/include/windows.system.userprofile.idl b/include/windows.system.userprofile.idl index 4a066c9ae8b..65a334b97f8 100644 --- a/include/windows.system.userprofile.idl +++ b/include/windows.system.userprofile.idl @@ -20,12 +20,14 @@ #pragma winrt ns_prefix #endif +#ifndef DO_NO_IMPORTS import "inspectable.idl"; import "asyncinfo.idl"; import "eventtoken.idl"; import "windowscontracts.idl"; import "windows.foundation.idl"; import "windows.globalization.idl"; +#endif namespace Windows { namespace System { From 71145cb256bd4b90e0e66d25ec61fbc6114621ce Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 1 Feb 2023 13:01:38 -0600 Subject: [PATCH 1014/2777] kernelbase: HACK: Force Angle GL instead of Swiftshader for UplayWebCore. CW-Bug-Id: #21862 --- dlls/kernelbase/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index a332bce17e7..2fe9d93e76e 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -599,7 +599,7 @@ static const WCHAR *hack_append_command_line( const WCHAR *cmd ) } options[] = { - {L"UplayWebCore.exe", L" --use-gl=swiftshader"}, + {L"UplayWebCore.exe", L" --use-angle=gl"}, {L"Paradox Launcher.exe", L" --use-gl=swiftshader --in-process-gpu"}, {L"Montaro\\nw.exe", L" --use-gl=swiftshader"}, {L"EOSOverlayRenderer-Win64-Shipping.exe", L" --use-gl=swiftshader --in-process-gpu"}, From fbc160da0e2271a21fecd73059edd10d6978f764 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 2 Feb 2023 17:06:35 -0600 Subject: [PATCH 1015/2777] kernel32/tests: Add tests for known dlls load specifics. CW-Bug-Id: #21866 --- dlls/kernel32/tests/module.c | 90 ++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/dlls/kernel32/tests/module.c b/dlls/kernel32/tests/module.c index 9efbdba336d..678bb43fe74 100644 --- a/dlls/kernel32/tests/module.c +++ b/dlls/kernel32/tests/module.c @@ -1609,6 +1609,95 @@ static void test_ddag_node(void) ok( se == node->Dependencies.Tail, "Expected end of the list.\n" ); } +#define check_dll_path(a, b) check_dll_path_( __LINE__, a, b ) +static void check_dll_path_( unsigned int line, HMODULE h, const char *expected ) +{ + char path[MAX_PATH]; + DWORD ret; + + *path = 0; + ret = GetModuleFileNameA( h, path, MAX_PATH); + ok_(__FILE__, line)( ret && ret < MAX_PATH, "Got %lu.\n", ret ); + ok_(__FILE__, line)( !stricmp( path, expected ), "Got %s.\n", debugstr_a(path) ); +} + +static void test_known_dlls_load(void) +{ + static const char apiset_dll[] = "ext-ms-win-base-psapi-l1-1-0.dll"; + char system_path[MAX_PATH], local_path[MAX_PATH]; + static const char dll[] = "psapi.dll"; + HMODULE hlocal, hsystem, hapiset, h; + BOOL ret; + + if (GetModuleHandleA( dll ) || GetModuleHandleA( apiset_dll )) + { + skip( "%s is already loaded, skipping test.\n", dll ); + return; + } + + hapiset = LoadLibraryA( apiset_dll ); + if (!hapiset) + { + win_skip( "%s is not available.\n", apiset_dll ); + return; + } + FreeLibrary( hapiset ); + + GetSystemDirectoryA( system_path, sizeof(system_path) ); + strcat( system_path, "\\" ); + strcat( system_path, dll ); + + GetCurrentDirectoryA( sizeof(local_path), local_path ); + strcat( local_path, "\\" ); + strcat( local_path, dll ); + + /* Known dll is always found in system dir, regardless of its presence in the application dir. */ + ret = pSetDefaultDllDirectories( LOAD_LIBRARY_SEARCH_USER_DIRS ); + ok( ret, "SetDefaultDllDirectories failed err %lu\n", GetLastError() ); + h = LoadLibraryA( dll ); + ret = pSetDefaultDllDirectories( LOAD_LIBRARY_SEARCH_DEFAULT_DIRS ); + ok( ret, "SetDefaultDllDirectories failed err %lu\n", GetLastError() ); + todo_wine ok( !!h, "Got NULL.\n" ); + hapiset = GetModuleHandleA( apiset_dll ); + ok( hapiset == h, "Got %p, %p.\n", hapiset, h ); + FreeLibrary( h ); + + h = LoadLibraryExA( dll, 0, LOAD_LIBRARY_SEARCH_APPLICATION_DIR ); + todo_wine ok( !!h, "Got NULL.\n" ); + hapiset = GetModuleHandleA( apiset_dll ); + ok( hapiset == h, "Got %p, %p.\n", hapiset, h ); + FreeLibrary( h ); + + /* Put dll to the current directory. */ + create_test_dll( dll ); + + h = LoadLibraryExA( dll, 0, LOAD_LIBRARY_SEARCH_APPLICATION_DIR ); + ok( !!h, "Got NULL.\n" ); + hapiset = GetModuleHandleA( apiset_dll ); + todo_wine ok( hapiset == h, "Got %p, %p.\n", hapiset, h ); + FreeLibrary( h ); + + /* Local version can still be loaded if dll name contains path. */ + hlocal = LoadLibraryA( local_path ); + ok( !!hlocal, "Got NULL.\n" ); + check_dll_path( hlocal, local_path ); + + /* dll without path will match the loaded one. */ + hsystem = LoadLibraryA( dll ); + ok( hsystem == hlocal, "Got %p, %p.\n", hsystem, hlocal ); + h = GetModuleHandleA( dll ); + ok( h == hlocal, "Got %p, %p.\n", h, hlocal ); + + /* apiset dll won't match the one loaded not from system dir. */ + hapiset = GetModuleHandleA( apiset_dll ); + ok( !hapiset, "Got %p.\n", hapiset ); + + FreeLibrary( hsystem ); + FreeLibrary( hlocal ); + + DeleteFileA( dll ); +} + START_TEST(module) { WCHAR filenameW[MAX_PATH]; @@ -1645,4 +1734,5 @@ START_TEST(module) test_LdrGetDllFullName(); test_apisets(); test_ddag_node(); + test_known_dlls_load(); } From cc76f964ec06e662d96d3cbf6d4e7b06bd7f2ce9 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 2 Feb 2023 14:48:37 -0600 Subject: [PATCH 1016/2777] ntdll: Factor out prepend_system_dir() function. CW-Bug-Id: #21866 --- dlls/ntdll/loader.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index a93ff3048b3..1f037ada806 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -2871,6 +2871,23 @@ static NTSTATUS find_actctx_dll( LPCWSTR libname, LPWSTR *fullname ) } +/****************************************************************************** + * prepend_system_dir + */ +static NTSTATUS prepend_system_dir( const WCHAR *name, ULONG name_length, WCHAR **fullname ) +{ + ULONG len; + + len = wcslen( system_dir ) + name_length; + if (!(*fullname = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) + return STATUS_NO_MEMORY; + wcscpy( *fullname, system_dir ); + memcpy( *fullname + wcslen( system_dir ), name, name_length * sizeof(WCHAR) ); + (*fullname)[len] = 0; + + return STATUS_SUCCESS; +} + /****************************************************************************** * find_apiset_dll @@ -2880,18 +2897,11 @@ static NTSTATUS find_apiset_dll( const WCHAR *name, WCHAR **fullname ) const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap; const API_SET_NAMESPACE_ENTRY *entry; UNICODE_STRING str; - ULONG len; if (get_apiset_entry( map, name, wcslen(name), &entry )) return STATUS_APISET_NOT_PRESENT; if (get_apiset_target( map, entry, NULL, &str )) return STATUS_DLL_NOT_FOUND; - len = wcslen( system_dir ) + str.Length / sizeof(WCHAR); - if (!(*fullname = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) - return STATUS_NO_MEMORY; - wcscpy( *fullname, system_dir ); - memcpy( *fullname + wcslen( system_dir ), str.Buffer, str.Length ); - (*fullname)[len] = 0; - return STATUS_SUCCESS; + return prepend_system_dir( str.Buffer, str.Length / sizeof(WCHAR), fullname ); } From cc6d503b8eb2aa9d44f92b322534e4a892664e0d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 7 Feb 2023 10:16:36 -0600 Subject: [PATCH 1017/2777] loader/wine.inf: Add known dlls key. CW-Bug-Id: #21866 --- loader/wine.inf.in | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 70751891f7d..40dcd9eb0d2 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -478,6 +478,51 @@ HKLM,%Control%\Session Manager\Environment,"windir",0x00020000,"%SystemRoot%" HKLM,%Control%\Session Manager\Environment,"winsysdir",,"%11%" HKLM,%Control%\Session Manager\Memory Management,PagingFiles,,"%24%\pagefile.sys 27 77" HKLM,%Control%\Session Manager\Memory Management,WriteWatch,0x00040002,1 +;;KnownDLLs +HKLM,%Control%\Session Manager\KnownDLLs,"_wow64cpu",,"wow64cpu.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"_wowarmhw",,"wowarmhw.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"_xtajit",,"_xtajit.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"advapi32",,"advapi32.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"clbcatq",,"clbcatq.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"combase",,"combase.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"COMDLG32",,"COMDLG32.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"coml2",,"coml2.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"DifxApi",,"difxapi.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"gdi32",,"gdi32.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"gdiplus",,"gdiplus.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"IMAGEHLP",,"IMAGEHLP.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"IMM32",,"IMM32.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"kernel32",,"kernel32.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"MSCTF",,"MSCTF.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"MSVCRT",,"MSVCRT.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"NORMALIZ",,"NORMALIZ.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"NSI",,"NSI.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"ole32",,"ole32.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"OLEAUT32",,"OLEAUT32.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"PSAPI",,"PSAPI.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"rpcrt4",,"rpcrt4.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"sechost",,"sechost.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"Setupapi",,"Setupapi.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"SHCORE",,"SHCORE.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"SHELL32",,"SHELL32.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"SHLWAPI",,"SHLWAPI.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"user32",,"user32.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"wow64",,"wow64.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"wow64win",,"wow64win.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"WS2_32",,"WS2_32.dll" +;;KnownDLLs not present in registry on Windows but present in \\KnownDLLs directory +HKLM,%Control%\Session Manager\KnownDLLs,"ucrtbase",,"ucrtbase.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"msvcp_win",,"msvcp_win.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"bcrypt",,"bcrypt.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"COMCTL32",,"COMCTL32.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"cfgmgr32",,"cfgmgr32.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"ntdll",,"ntdll.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"bcryptPrimitives",,"bcryptPrimitives.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"win32u",,"win32u.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"gdi32full",,"gdi32full.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"WINTRUST",,"WINTRUST.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"CRYPT32",,"CRYPT32.dll" +HKLM,%Control%\Session Manager\KnownDLLs,"WLDAP32",,"WLDAP32.dll" [Fonts] HKLM,%FontSubStr%,"Arial Baltic,186",,"Arial,186" From 49d5cbd7deb3297dd534f75b059e9baaacd417ee Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 2 Feb 2023 17:14:54 -0600 Subject: [PATCH 1018/2777] ntdll: Load known dlls from system directory. CW-Bug-Id: #21866 --- dlls/kernel32/tests/module.c | 9 ++++--- dlls/ntdll/loader.c | 52 ++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/dlls/kernel32/tests/module.c b/dlls/kernel32/tests/module.c index 678bb43fe74..d7eb4a5f525 100644 --- a/dlls/kernel32/tests/module.c +++ b/dlls/kernel32/tests/module.c @@ -1657,13 +1657,15 @@ static void test_known_dlls_load(void) h = LoadLibraryA( dll ); ret = pSetDefaultDllDirectories( LOAD_LIBRARY_SEARCH_DEFAULT_DIRS ); ok( ret, "SetDefaultDllDirectories failed err %lu\n", GetLastError() ); - todo_wine ok( !!h, "Got NULL.\n" ); + ok( !!h, "Got NULL.\n" ); + check_dll_path( h, system_path ); hapiset = GetModuleHandleA( apiset_dll ); ok( hapiset == h, "Got %p, %p.\n", hapiset, h ); FreeLibrary( h ); h = LoadLibraryExA( dll, 0, LOAD_LIBRARY_SEARCH_APPLICATION_DIR ); - todo_wine ok( !!h, "Got NULL.\n" ); + ok( !!h, "Got NULL.\n" ); + check_dll_path( h, system_path ); hapiset = GetModuleHandleA( apiset_dll ); ok( hapiset == h, "Got %p, %p.\n", hapiset, h ); FreeLibrary( h ); @@ -1673,8 +1675,9 @@ static void test_known_dlls_load(void) h = LoadLibraryExA( dll, 0, LOAD_LIBRARY_SEARCH_APPLICATION_DIR ); ok( !!h, "Got NULL.\n" ); + check_dll_path( h, system_path ); hapiset = GetModuleHandleA( apiset_dll ); - todo_wine ok( hapiset == h, "Got %p, %p.\n", hapiset, h ); + ok( hapiset == h, "Got %p, %p.\n", hapiset, h ); FreeLibrary( h ); /* Local version can still be loaded if dll name contains path. */ diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 1f037ada806..e800f40d787 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -36,6 +36,7 @@ #include "wine/exception.h" #include "wine/debug.h" #include "wine/list.h" +#include "wine/rbtree.h" #include "ntdll_misc.h" #include "ddk/wdm.h" @@ -185,6 +186,13 @@ static WINE_MODREF *last_failed_modref; static LDR_DDAG_NODE *node_ntdll, *node_kernel32; +struct known_dll +{ + struct rb_entry entry; + WCHAR name[1]; +}; +static struct rb_tree known_dlls; + static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, DWORD flags, WINE_MODREF** pwm, BOOL system ); static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved ); static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports, @@ -3105,6 +3113,7 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, UNI WINE_MODREF **pwm, HANDLE *mapping, SECTION_IMAGE_INFORMATION *image_info, struct file_id *id ) { + const WCHAR *known_dll_name = NULL; WCHAR *fullname = NULL; NTSTATUS status; ULONG wow64_old_value = 0; @@ -3137,6 +3146,12 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, UNI goto done; } } + if (!fullname && rb_get( &known_dlls, libname )) + { + prepend_system_dir( libname, wcslen(libname), &fullname ); + known_dll_name = libname; + libname = fullname; + } } if (RtlDetermineDosPathNameType_U( libname ) == RELATIVE_PATH) @@ -3146,7 +3161,11 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, UNI status = find_builtin_without_file( libname, nt_name, pwm, mapping, image_info, id ); } else if (!(status = RtlDosPathNameToNtPathName_U_WithStatus( libname, nt_name, NULL, NULL ))) + { status = open_dll_file( nt_name, pwm, mapping, image_info, id ); + if (status == STATUS_DLL_NOT_FOUND && known_dll_name) + status = find_builtin_without_file( known_dll_name, nt_name, pwm, mapping, image_info, id ); + } if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) status = STATUS_INVALID_IMAGE_FORMAT; @@ -4020,14 +4039,28 @@ static void process_breakpoint(void) __ENDTRY } +/************************************************************************* + * compare_known_dlls + */ +static int compare_known_dlls( const void *name, const struct wine_rb_entry *entry ) +{ + struct known_dll *known_dll = WINE_RB_ENTRY_VALUE( entry, struct known_dll, entry ); + + return wcsicmp( name, known_dll->name ); +} /*********************************************************************** * load_global_options */ static void load_global_options(void) { + char buffer[256]; + KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; OBJECT_ATTRIBUTES attr; UNICODE_STRING name_str, val_str; + struct known_dll *known_dll; + ULONG idx = 0, size; + NTSTATUS status; HANDLE hkey; RtlInitUnicodeString( &name_str, L"WINEBOOTSTRAPMODE" ); @@ -4048,6 +4081,25 @@ static void load_global_options(void) query_dword_option( hkey, L"SafeDllSearchMode", &dll_safe_mode ); NtClose( hkey ); } + + rb_init( &known_dlls, compare_known_dlls ); + + RtlInitUnicodeString( &name_str, + L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\KnownDLLs" ); + if (NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr )) return; + while (1) + { + status = NtEnumerateValueKey( hkey, idx++, KeyValuePartialInformation, buffer, sizeof(buffer), &size ); + if (status == STATUS_BUFFER_OVERFLOW) continue; + if (status) break; + if (info->Type != REG_SZ) continue; + + known_dll = RtlAllocateHeap( GetProcessHeap(), 0, offsetof(struct known_dll, name[0]) + info->DataLength ); + if (!known_dll) break; + memcpy( known_dll->name, info->Data, info->DataLength ); + rb_put( &known_dlls, known_dll->name, &known_dll->entry ); + } + NtClose( hkey ); } From c3009233c973a9d7b80181a1c6a53e9fb5ea7388 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Sun, 22 Jan 2023 17:36:44 -0600 Subject: [PATCH 1019/2777] ntdll: Use MemAvailable field for free RAM estimation if available. (cherry picked from commit e41135a4a532524684a6c85141ac2c08d7fe17a5) CW-Bug-Id: #21822 --- dlls/ntdll/unix/system.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index 79d2a7bab9b..16fde91ea7c 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -2021,7 +2021,7 @@ static void get_performance_info( SYSTEM_PERFORMANCE_INFORMATION *info ) if ((fp = fopen("/proc/meminfo", "r"))) { - unsigned long long value; + unsigned long long value, mem_available = 0; char line[64]; while (fgets(line, sizeof(line), fp)) @@ -2038,8 +2038,11 @@ static void get_performance_info( SYSTEM_PERFORMANCE_INFORMATION *info ) freeram += value * 1024; else if (sscanf(line, "Cached: %llu", &value)) freeram += value * 1024; + else if (sscanf(line, "MemAvailable: %llu", &value)) + mem_available = value * 1024; } fclose(fp); + if (mem_available) freeram = mem_available; } } #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || \ From 40996c60eb52553c5893e6bcc991f6a987e1bacd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 8 Feb 2023 18:47:24 +0100 Subject: [PATCH 1020/2777] Revert "mfmediaengine: Pass volume changes to media session." This reverts commit 12c28aa22f793de1ffa62dc269afb288fdf0526d. CW-Bug-Id: #21816 --- dlls/mfmediaengine/main.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 63e9a8f07d5..4f99513e938 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -835,23 +835,6 @@ static void media_engine_get_frame_size(struct media_engine *engine, IMFTopology IMFMediaType_Release(media_type); } -static void media_engine_apply_volume(const struct media_engine *engine) -{ - IMFSimpleAudioVolume *sa_volume; - HRESULT hr; - - if (!engine->session) - return; - - if (FAILED(MFGetService((IUnknown *)engine->session, &MR_POLICY_VOLUME_SERVICE, &IID_IMFSimpleAudioVolume, (void **)&sa_volume))) - return; - - if (FAILED(hr = IMFSimpleAudioVolume_SetMasterVolume(sa_volume, engine->volume))) - WARN("Failed to set master volume, hr %#lx.\n", hr); - - IMFSimpleAudioVolume_Release(sa_volume); -} - static HRESULT WINAPI media_engine_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IMFAsyncCallback) || @@ -935,8 +918,6 @@ static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface EnterCriticalSection(&engine->cs); - media_engine_apply_volume(engine); - engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_METADATA; media_engine_get_frame_size(engine, topology); @@ -2031,7 +2012,6 @@ static HRESULT WINAPI media_engine_SetVolume(IMFMediaEngineEx *iface, double vol else if (volume != engine->volume) { engine->volume = volume; - media_engine_apply_volume(engine); IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, 0, 0); } LeaveCriticalSection(&engine->cs); From 00d9388d1c438f9848a1337bd0e5b7ba5f447a6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 31 Oct 2022 10:34:38 +0100 Subject: [PATCH 1021/2777] HACK: mf: Return E_NOTIMPL from media session SetRate if rate is 0 (scrubbing). CW-Bug-Id: #21498 --- dlls/mf/session.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 95632fae5fb..004dcc88b98 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -4101,6 +4101,13 @@ static HRESULT WINAPI session_rate_control_SetRate(IMFRateControl *iface, BOOL t TRACE("%p, %d, %f.\n", iface, thin, rate); + if (!rate) + { + /* The Anacrusis fails to play its video if we succeed here */ + ERR("Scrubbing not implemented!\n"); + return E_NOTIMPL; + } + if (FAILED(hr = create_session_op(SESSION_CMD_SET_RATE, &op))) return hr; From 7196f51540b67c9d9d450c58c4102902482aa6fd Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Thu, 9 Feb 2023 21:24:57 +0200 Subject: [PATCH 1022/2777] HACK: kernelbase: Do not flash the winedbg console window. Depending on what the crashing software does with the handles / own console we may end up creating a new console window for windbg. Since Proton defaults to starting windbg in a non-interactive mode without displaying the crash dialog and redirects the log to unix's stderr we want to avoid confusing users. CW-Bug-Id: #21872 --- dlls/kernelbase/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/kernelbase/debug.c b/dlls/kernelbase/debug.c index 378531acc62..fe28d524a8c 100644 --- a/dlls/kernelbase/debug.c +++ b/dlls/kernelbase/debug.c @@ -520,7 +520,7 @@ static BOOL start_debugger( EXCEPTION_POINTERS *epointers, HANDLE event ) startup.cb = sizeof(startup); startup.dwFlags = STARTF_USESHOWWINDOW; startup.wShowWindow = SW_SHOWNORMAL; - ret = CreateProcessW( NULL, cmdline, NULL, NULL, TRUE, 0, env, NULL, &startup, &info ); + ret = CreateProcessW( NULL, cmdline, NULL, NULL, TRUE, CREATE_NO_WINDOW, env, NULL, &startup, &info ); FreeEnvironmentStringsW( env ); if (ret) From 28c9d5ce1b23e23ae1f096cd3d98019febc5a300 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 3 Feb 2023 20:15:48 -0600 Subject: [PATCH 1023/2777] imm32: Disable cross thread access in ImmSetCompositionString(). CW-Bug-Id: #21872 --- dlls/imm32/imm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index fa2e0705db1..17061ae0034 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2377,6 +2377,9 @@ BOOL WINAPI ImmSetCompositionStringA( if (!data) return FALSE; + if (IMM_IsCrossThreadAccess(NULL, hIMC)) + return FALSE; + if (!(dwIndex == SCS_SETSTR || dwIndex == SCS_CHANGEATTR || dwIndex == SCS_CHANGECLAUSE || @@ -2432,6 +2435,9 @@ BOOL WINAPI ImmSetCompositionStringW( if (!data) return FALSE; + if (IMM_IsCrossThreadAccess(NULL, hIMC)) + return FALSE; + if (!(dwIndex == SCS_SETSTR || dwIndex == SCS_CHANGEATTR || dwIndex == SCS_CHANGECLAUSE || From 6c79e9c21f553a7db9ee6b8f828d16b2e5312bcc Mon Sep 17 00:00:00 2001 From: Esme Povirk Date: Wed, 1 Feb 2023 15:07:05 -0600 Subject: [PATCH 1024/2777] Update Wine Mono to 7.4.1. --- dlls/appwiz.cpl/addons.c | 6 +++--- dlls/mscoree/mscoree_private.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/appwiz.cpl/addons.c b/dlls/appwiz.cpl/addons.c index c63106de95b..762c0b31f73 100644 --- a/dlls/appwiz.cpl/addons.c +++ b/dlls/appwiz.cpl/addons.c @@ -58,10 +58,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl); #define GECKO_SHA "???" #endif -#define MONO_VERSION "7.4.0" +#define MONO_VERSION "7.4.1" #if defined(__i386__) || defined(__x86_64__) #define MONO_ARCH "x86" -#define MONO_SHA "6413ff328ebbf7ec7689c648feb3546d8102ded865079d1fbf0331b14b3ab0ec" +#define MONO_SHA "4721de007ecd0019cc18e144a882c290da3314d7e1bc77f57c404675e644b9fe" #else #define MONO_ARCH "" #define MONO_SHA "???" @@ -97,7 +97,7 @@ static const addon_info_t addons_info[] = { L"wine-mono-" MONO_VERSION "-" MONO_ARCH ".msi", L"mono", MONO_SHA, - "http://source.winehq.org/winemono.php", + "https://github.com/madewokherd/wine-mono/releases/download/wine-mono-" MONO_VERSION "/wine-mono-" MONO_VERSION "-" MONO_ARCH ".msi", "Dotnet", "MonoUrl", "MonoCabDir", MAKEINTRESOURCEW(ID_DWL_MONO_DIALOG) } diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h index 71e943d34c3..64a5efe8d10 100644 --- a/dlls/mscoree/mscoree_private.h +++ b/dlls/mscoree/mscoree_private.h @@ -45,7 +45,7 @@ extern HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version) extern HRESULT assembly_get_vtable_fixups(ASSEMBLY *assembly, VTableFixup **fixups, DWORD *count) DECLSPEC_HIDDEN; extern HRESULT assembly_get_native_entrypoint(ASSEMBLY *assembly, NativeEntryPointFunc *func) DECLSPEC_HIDDEN; -#define WINE_MONO_VERSION "7.4.0" +#define WINE_MONO_VERSION "7.4.1" /* Mono embedding */ typedef struct _MonoDomain MonoDomain; From 9cb0f0259c7d94312b1c82b72e2e49de0b906c87 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 10 Feb 2023 19:14:02 -0600 Subject: [PATCH 1025/2777] bcrypt/tests: Add more tests for AES initialization vectors. (cherry picked from commit 8e305d811a753d1de5a5a4c2c481e3f31c312e1c) CW-Bug-Id: #21898 --- dlls/bcrypt/tests/bcrypt.c | 108 +++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index bc355c6d821..a139b31b393 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -739,6 +739,10 @@ static void test_BCryptGenerateSymmetricKey(void) {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}; static UCHAR expected[] = {0xc6,0xa1,0x3b,0x37,0x87,0x8f,0x5b,0x82,0x6f,0x4f,0x81,0x62,0xa1,0xc8,0xd8,0x79}; + static UCHAR expected2[] = + {0xb5,0x8a,0x10,0x64,0xd8,0xac,0xa9,0x9b,0xd9,0xb0,0x40,0x5b,0x85,0x45,0xf5,0xbb}; + static UCHAR expected3[] = + {0xe3,0x7c,0xd3,0x63,0xdd,0x7c,0x87,0xa0,0x9a,0xff,0x0e,0x3e,0x60,0xe0,0x9c,0x82}; BCRYPT_ALG_HANDLE aes; BCRYPT_KEY_HANDLE key, key2; UCHAR *buf, ciphertext[16], plaintext[16], ivbuf[16], mode[64]; @@ -821,6 +825,7 @@ static void test_BCryptGenerateSymmetricKey(void) ret = BCryptEncrypt(key, data, 16, NULL, ivbuf, 16, NULL, 0, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n"); size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -831,6 +836,26 @@ static void test_BCryptGenerateSymmetricKey(void) ok(!memcmp(ciphertext, expected, sizeof(expected)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + + size = 0; + memset(ciphertext, 0, sizeof(ciphertext)); + ret = BCryptEncrypt(key, data, 16, NULL, NULL, 0, ciphertext, 16, &size, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(size == 16, "got %lu\n", size); + todo_wine ok(!memcmp(ciphertext, expected2, sizeof(expected2)), "wrong data\n"); + + size = 0; + memcpy(ivbuf, iv, sizeof(iv)); + ++ivbuf[0]; + memset(ciphertext, 0, sizeof(ciphertext)); + ret = BCryptEncrypt(key, data, 16, NULL, ivbuf, 16, ciphertext, 16, &size, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(size == 16, "got %lu\n", size); + ok(!memcmp(ciphertext, expected3, sizeof(expected3)), "wrong data\n"); + for (i = 0; i < 16; i++) + ok(ciphertext[i] == expected3[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected3[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); key2 = (void *)0xdeadbeef; ret = BCryptDuplicateKey(NULL, &key2, NULL, 0, 0); @@ -858,6 +883,7 @@ static void test_BCryptGenerateSymmetricKey(void) ok(!memcmp(ciphertext, expected, sizeof(expected)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); ret = BCryptDestroyKey(key2); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); @@ -881,6 +907,7 @@ static void test_BCryptGenerateSymmetricKey(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); ok(!memcmp(plaintext, data, sizeof(data)), "wrong data\n"); + todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); memset(mode, 0, sizeof(mode)); ret = BCryptGetProperty(key, BCRYPT_CHAINING_MODE, mode, sizeof(mode), &size, 0); @@ -1083,6 +1110,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data, 16, NULL, ivbuf, 16, NULL, 0, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n"); size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1093,6 +1121,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected, sizeof(expected)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); /* NULL initialization vector */ size = 0; @@ -1112,6 +1141,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected9, sizeof(expected9)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected9[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected9[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); /* input size is not a multiple of block size */ size = 0; @@ -1126,6 +1156,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data, 17, NULL, ivbuf, 16, NULL, 0, &size, BCRYPT_BLOCK_PADDING); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n"); size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1136,6 +1167,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected2, sizeof(expected2)), "wrong data\n"); for (i = 0; i < 32; i++) ok(ciphertext[i] == expected2[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected2[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n"); /* input size is a multiple of block size, block padding set */ size = 0; @@ -1143,6 +1175,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data2, 32, NULL, ivbuf, 16, NULL, 0, &size, BCRYPT_BLOCK_PADDING); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 48, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n"); size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1153,6 +1186,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected3, sizeof(expected3)), "wrong data\n"); for (i = 0; i < 48; i++) ok(ciphertext[i] == expected3[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected3[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n"); /* output size too small */ size = 0; @@ -1191,6 +1225,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data2, 32, NULL, ivbuf, 16, NULL, 0, &size, BCRYPT_BLOCK_PADDING); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 48, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n"); size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1201,6 +1236,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected10, sizeof(expected10)), "wrong data\n"); for (i = 0; i < 48; i++) ok(ciphertext[i] == expected10[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected10[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n"); ret = BCryptDestroyKey(key); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); @@ -1267,6 +1303,7 @@ static void test_BCryptEncrypt(void) ok(ciphertext[i] == expected4[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected4[i]); for (i = 0; i < 16; i++) ok(tag[i] == expected_tag[i], "%lu: %02x != %02x\n", i, tag[i], expected_tag[i]); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n"); /* NULL initialization vector */ size = 0; @@ -1296,6 +1333,8 @@ static void test_BCryptEncrypt(void) ok(ciphertext[i] == expected4[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected4[i]); for (i = 0; i < 16; i++) ok(tag[i] == expected_tag[i], "%lu: %02x != %02x\n", i, tag[i], expected_tag[i]); + memset(ciphertext, 0, sizeof(iv)); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); /* input size is not multiple of block size */ size = 0; @@ -1311,6 +1350,7 @@ static void test_BCryptEncrypt(void) ok(ciphertext[i] == expected4[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected4[i]); for (i = 0; i < 16; i++) ok(tag[i] == expected_tag2[i], "%lu: %02x != %02x\n", i, tag[i], expected_tag2[i]); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n"); /* test with auth data */ auth_info.pbAuthData = auth_data; @@ -1329,6 +1369,7 @@ static void test_BCryptEncrypt(void) ok(ciphertext[i] == expected4[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected4[i]); for (i = 0; i < 16; i++) ok(tag[i] == expected_tag3[i], "%lu: %02x != %02x\n", i, tag[i], expected_tag3[i]); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n"); memset(tag, 0xff, sizeof(tag)); ret = BCryptEncrypt(key, data2, 0, &auth_info, ivbuf, 16, NULL, 0, &size, 0); @@ -1496,6 +1537,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data, 16, NULL, ivbuf, 16, NULL, 0, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n"); size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1506,6 +1548,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected11, sizeof(expected11)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected11[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected11[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); /* NULL initialization vector */ size = 0; @@ -1525,6 +1568,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected13, sizeof(expected13)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected13[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected13[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); /* input size is not a multiple of block size */ size = 0; @@ -1539,6 +1583,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data, 17, NULL, ivbuf, 16, NULL, 0, &size, BCRYPT_BLOCK_PADDING); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n"); size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1549,6 +1594,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected14, sizeof(expected14)), "wrong data\n"); for (i = 0; i < 32; i++) ok(ciphertext[i] == expected14[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected14[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n"); /* input size is a multiple of block size, block padding set */ size = 0; @@ -1566,6 +1612,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected15, sizeof(expected15)), "wrong data\n"); for (i = 0; i < 48; i++) ok(ciphertext[i] == expected15[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected15[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n"); /* output size too small */ size = 0; @@ -1574,6 +1621,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data, 17, NULL, ivbuf, 16, ciphertext, 31, &size, BCRYPT_BLOCK_PADDING); ok(ret == STATUS_BUFFER_TOO_SMALL, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n"); size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1581,6 +1629,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data2, 32, NULL, ivbuf, 16, ciphertext, 32, &size, BCRYPT_BLOCK_PADDING); ok(ret == STATUS_BUFFER_TOO_SMALL, "got %#lx\n", ret); ok(size == 48, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n"); ret = BCryptDestroyKey(key); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); @@ -1604,6 +1653,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data2, 32, NULL, ivbuf, 16, NULL, 0, &size, BCRYPT_BLOCK_PADDING); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 48, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n"); size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1614,6 +1664,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected16, sizeof(expected16)), "wrong data\n"); for (i = 0; i < 48; i++) ok(ciphertext[i] == expected16[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected16[i]); + todo_wine ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n"); ret = BCryptCloseAlgorithmProvider(aes, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); @@ -1636,6 +1687,12 @@ static void test_BCryptDecrypt(void) static UCHAR expected3[] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10}; + static UCHAR expected4[] = + {0x28,0x73,0x3d,0xef,0x84,0x8f,0xb0,0xa6,0x5d,0x1a,0x51,0xb7,0xec,0x8f,0xea,0xe9, + 0x10,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f}; + static UCHAR expected5[] = + {0x29,0x73,0x3d,0xef,0x84,0x8f,0xb0,0xa6,0x5d,0x1a,0x51,0xb7,0xec,0x8f,0xea,0xe9, + 0x10,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f}; static UCHAR ciphertext[32] = {0xc6,0xa1,0x3b,0x37,0x87,0x8f,0x5b,0x82,0x6f,0x4f,0x81,0x62,0xa1,0xc8,0xd8,0x79, 0x28,0x73,0x3d,0xef,0x84,0x8f,0xb0,0xa6,0x5d,0x1a,0x51,0xb7,0xec,0x8f,0xea,0xe9}; @@ -1702,6 +1759,7 @@ static void test_BCryptDecrypt(void) ret = BCryptDecrypt(key, ciphertext, 32, NULL, ivbuf, 16, NULL, 0, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n"); size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1710,6 +1768,23 @@ static void test_BCryptDecrypt(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); ok(!memcmp(plaintext, expected, sizeof(expected)), "wrong data\n"); + todo_wine ok(!memcmp(ivbuf, ciphertext + size - sizeof(iv), sizeof(iv)), "wrong iv data.\n"); + + size = 0; + ++ivbuf[0]; + memset(plaintext, 0, sizeof(plaintext)); + ret = BCryptDecrypt(key, ciphertext, 32, NULL, ivbuf, 16, plaintext, 32, &size, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(size == 32, "got %lu\n", size); + todo_wine ok(!memcmp(plaintext, expected5, sizeof(expected)), "wrong data\n"); + todo_wine ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n"); + + size = 0; + memset(plaintext, 0, sizeof(plaintext)); + ret = BCryptDecrypt(key, ciphertext, 32, NULL, NULL, 0, plaintext, 32, &size, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(size == 32, "got %lu\n", size); + todo_wine ok(!memcmp(plaintext, expected4, sizeof(expected4)), "wrong data\n"); /* test with padding smaller than block size */ size = 0; @@ -1717,6 +1792,7 @@ static void test_BCryptDecrypt(void) ret = BCryptDecrypt(key, ciphertext2, 32, NULL, ivbuf, 16, NULL, 0, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n"); size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1725,6 +1801,15 @@ static void test_BCryptDecrypt(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 17, "got %lu\n", size); ok(!memcmp(plaintext, expected2, sizeof(expected2)), "wrong data\n"); + todo_wine ok(!memcmp(ivbuf, ciphertext2 + 32 - sizeof(iv), sizeof(iv)), "wrong iv data.\n"); + + size = 0; + memset(plaintext, 0, sizeof(plaintext)); + ret = BCryptDecrypt(key, ciphertext2, 32, NULL, ivbuf, 16, plaintext, 17, &size, BCRYPT_BLOCK_PADDING); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(size == 17, "got %lu\n", size); + todo_wine ok(!memcmp(plaintext, expected4, size), "wrong data\n"); + todo_wine ok(!memcmp(ivbuf, ciphertext2 + 32 - 16, sizeof(iv)), "wrong iv data.\n"); /* test with padding of block size */ size = 0; @@ -1732,6 +1817,7 @@ static void test_BCryptDecrypt(void) ret = BCryptDecrypt(key, ciphertext3, 48, NULL, ivbuf, 16, NULL, 0, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 48, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n"); size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1740,6 +1826,7 @@ static void test_BCryptDecrypt(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); ok(!memcmp(plaintext, expected3, sizeof(expected3)), "wrong data\n"); + todo_wine ok(!memcmp(ivbuf, ciphertext3 + 48 - 16, sizeof(iv)), "wrong iv data.\n"); /* output size too small */ size = 0; @@ -1816,6 +1903,25 @@ static void test_BCryptDecrypt(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); ok(!memcmp(plaintext, expected3, sizeof(expected3)), "wrong data\n"); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv.\n"); + + size = 0; + memset(plaintext, 0, sizeof(plaintext)); + ret = BCryptDecrypt(key, ciphertext4, 32, &auth_info, NULL, 0, plaintext, 32, &size, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(size == 32, "got %lu\n", size); + ok(!memcmp(plaintext, expected3, sizeof(expected3)), "wrong data\n"); + + size = 0; + memcpy(ivbuf, iv, sizeof(iv)); + ++ivbuf[0]; + memset(plaintext, 0, sizeof(plaintext)); + ret = BCryptDecrypt(key, ciphertext4, 32, &auth_info, ivbuf, 16, plaintext, 32, &size, 0); + ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); + ok(size == 32, "got %lu\n", size); + ok(!memcmp(plaintext, expected3, sizeof(expected3)), "wrong data\n"); + ok(!memcmp(ivbuf + 1, iv + 1, sizeof(iv) - 1), "wrong iv data.\n"); + ok(ivbuf[0] == iv[0] + 1, "wrong iv data.\n"); /* test with auth data */ auth_info.pbAuthData = auth_data; @@ -1830,6 +1936,7 @@ static void test_BCryptDecrypt(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); ok(!memcmp(plaintext, expected3, sizeof(expected3)), "wrong data\n"); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv.\n"); /* test with wrong tag */ memcpy(ivbuf, iv, sizeof(iv)); @@ -1837,6 +1944,7 @@ static void test_BCryptDecrypt(void) ret = BCryptDecrypt(key, ciphertext4, 32, &auth_info, ivbuf, 16, plaintext, 32, &size, 0); ok(ret == STATUS_AUTH_TAG_MISMATCH, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); + ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n"); ret = BCryptDestroyKey(key); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); From c41566c1778626b2a5c7d159b3d8b9b818ec3c08 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 10 Feb 2023 19:18:04 -0600 Subject: [PATCH 1026/2777] bcrypt: Update init vector after encrypt or decrypt. (cherry picked from commit 7d31f39487e701d3378b51a6e32d3bc2b9094ce7) CW-Bug-Id: #21898 --- dlls/bcrypt/bcrypt_main.c | 20 +++++++++++++++++ dlls/bcrypt/tests/bcrypt.c | 44 +++++++++++++++++++------------------- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index af4b5321701..e3bdc8d6a88 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -1448,6 +1448,16 @@ static NTSTATUS key_symmetric_encrypt( struct key *key, UCHAR *input, ULONG inp free( buf ); } + if (!status) + { + if (key->u.s.vector && *ret_len >= key->u.s.vector_len) + { + memcpy( key->u.s.vector, output + *ret_len - key->u.s.vector_len, key->u.s.vector_len ); + if (iv) memcpy( iv, key->u.s.vector, min( iv_len, key->u.s.vector_len )); + } + else FIXME( "Unexpected vector len %lu, *ret_len %lu.\n", key->u.s.vector_len, *ret_len ); + } + return status; } @@ -1545,6 +1555,16 @@ static NTSTATUS key_symmetric_decrypt( struct key *key, UCHAR *input, ULONG inpu free( buf ); } + if (!status) + { + if (key->u.s.vector && input_len >= key->u.s.vector_len) + { + memcpy( key->u.s.vector, input + input_len - key->u.s.vector_len, key->u.s.vector_len ); + if (iv) memcpy( iv, key->u.s.vector, min( iv_len, key->u.s.vector_len )); + } + else FIXME( "Unexpected vector len %lu, *ret_len %lu.\n", key->u.s.vector_len, *ret_len ); + } + return status; } diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index a139b31b393..c64ecb365a3 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -836,7 +836,7 @@ static void test_BCryptGenerateSymmetricKey(void) ok(!memcmp(ciphertext, expected, sizeof(expected)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); size = 0; memset(ciphertext, 0, sizeof(ciphertext)); @@ -855,7 +855,7 @@ static void test_BCryptGenerateSymmetricKey(void) ok(!memcmp(ciphertext, expected3, sizeof(expected3)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected3[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected3[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); key2 = (void *)0xdeadbeef; ret = BCryptDuplicateKey(NULL, &key2, NULL, 0, 0); @@ -883,7 +883,7 @@ static void test_BCryptGenerateSymmetricKey(void) ok(!memcmp(ciphertext, expected, sizeof(expected)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); ret = BCryptDestroyKey(key2); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); @@ -907,7 +907,7 @@ static void test_BCryptGenerateSymmetricKey(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); ok(!memcmp(plaintext, data, sizeof(data)), "wrong data\n"); - todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); memset(mode, 0, sizeof(mode)); ret = BCryptGetProperty(key, BCRYPT_CHAINING_MODE, mode, sizeof(mode), &size, 0); @@ -1121,7 +1121,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected, sizeof(expected)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); /* NULL initialization vector */ size = 0; @@ -1141,7 +1141,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected9, sizeof(expected9)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected9[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected9[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); /* input size is not a multiple of block size */ size = 0; @@ -1167,7 +1167,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected2, sizeof(expected2)), "wrong data\n"); for (i = 0; i < 32; i++) ok(ciphertext[i] == expected2[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected2[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n"); /* input size is a multiple of block size, block padding set */ size = 0; @@ -1186,7 +1186,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected3, sizeof(expected3)), "wrong data\n"); for (i = 0; i < 48; i++) ok(ciphertext[i] == expected3[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected3[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n"); /* output size too small */ size = 0; @@ -1236,7 +1236,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected10, sizeof(expected10)), "wrong data\n"); for (i = 0; i < 48; i++) ok(ciphertext[i] == expected10[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected10[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n"); ret = BCryptDestroyKey(key); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); @@ -1548,7 +1548,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected11, sizeof(expected11)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected11[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected11[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); /* NULL initialization vector */ size = 0; @@ -1568,7 +1568,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected13, sizeof(expected13)), "wrong data\n"); for (i = 0; i < 16; i++) ok(ciphertext[i] == expected13[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected13[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext, sizeof(iv)), "wrong iv data.\n"); /* input size is not a multiple of block size */ size = 0; @@ -1594,7 +1594,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected14, sizeof(expected14)), "wrong data\n"); for (i = 0; i < 32; i++) ok(ciphertext[i] == expected14[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected14[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n"); /* input size is a multiple of block size, block padding set */ size = 0; @@ -1612,7 +1612,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected15, sizeof(expected15)), "wrong data\n"); for (i = 0; i < 48; i++) ok(ciphertext[i] == expected15[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected15[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n"); /* output size too small */ size = 0; @@ -1664,7 +1664,7 @@ static void test_BCryptEncrypt(void) ok(!memcmp(ciphertext, expected16, sizeof(expected16)), "wrong data\n"); for (i = 0; i < 48; i++) ok(ciphertext[i] == expected16[i], "%lu: %02x != %02x\n", i, ciphertext[i], expected16[i]); - todo_wine ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext + 48 - 16, sizeof(iv)), "wrong iv data.\n"); ret = BCryptCloseAlgorithmProvider(aes, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); @@ -1768,7 +1768,7 @@ static void test_BCryptDecrypt(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); ok(!memcmp(plaintext, expected, sizeof(expected)), "wrong data\n"); - todo_wine ok(!memcmp(ivbuf, ciphertext + size - sizeof(iv), sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext + size - sizeof(iv), sizeof(iv)), "wrong iv data.\n"); size = 0; ++ivbuf[0]; @@ -1776,8 +1776,8 @@ static void test_BCryptDecrypt(void) ret = BCryptDecrypt(key, ciphertext, 32, NULL, ivbuf, 16, plaintext, 32, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); - todo_wine ok(!memcmp(plaintext, expected5, sizeof(expected)), "wrong data\n"); - todo_wine ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(plaintext, expected5, sizeof(expected)), "wrong data\n"); + ok(!memcmp(ivbuf, ciphertext + 32 - 16, sizeof(iv)), "wrong iv data.\n"); size = 0; memset(plaintext, 0, sizeof(plaintext)); @@ -1801,15 +1801,15 @@ static void test_BCryptDecrypt(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 17, "got %lu\n", size); ok(!memcmp(plaintext, expected2, sizeof(expected2)), "wrong data\n"); - todo_wine ok(!memcmp(ivbuf, ciphertext2 + 32 - sizeof(iv), sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext2 + 32 - sizeof(iv), sizeof(iv)), "wrong iv data.\n"); size = 0; memset(plaintext, 0, sizeof(plaintext)); ret = BCryptDecrypt(key, ciphertext2, 32, NULL, ivbuf, 16, plaintext, 17, &size, BCRYPT_BLOCK_PADDING); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 17, "got %lu\n", size); - todo_wine ok(!memcmp(plaintext, expected4, size), "wrong data\n"); - todo_wine ok(!memcmp(ivbuf, ciphertext2 + 32 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(plaintext, expected4, size), "wrong data\n"); + ok(!memcmp(ivbuf, ciphertext2 + 32 - 16, sizeof(iv)), "wrong iv data.\n"); /* test with padding of block size */ size = 0; @@ -1826,7 +1826,7 @@ static void test_BCryptDecrypt(void) ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); ok(!memcmp(plaintext, expected3, sizeof(expected3)), "wrong data\n"); - todo_wine ok(!memcmp(ivbuf, ciphertext3 + 48 - 16, sizeof(iv)), "wrong iv data.\n"); + ok(!memcmp(ivbuf, ciphertext3 + 48 - 16, sizeof(iv)), "wrong iv data.\n"); /* output size too small */ size = 0; @@ -3256,7 +3256,7 @@ static void test_aes_vector(void) ret = BCryptEncrypt(key, input, sizeof(input), NULL, iv, sizeof(iv), output, sizeof(output), &size, 0); ok(!ret, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); - todo_wine ok(!memcmp(output, expect3, sizeof(expect3)), "wrong cipher text\n"); + ok(!memcmp(output, expect3, sizeof(expect3)), "wrong cipher text\n"); ret = BCryptDestroyKey(key); ok(!ret, "got %#lx\n", ret); From f8ff2cde4127c33d6c08082be489ea4a3bdda87f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 10 Feb 2023 19:19:15 -0600 Subject: [PATCH 1027/2777] bcrypt: Only reset init vector if the new vector is non-NULL. (cherry picked from commit 39dc9d09f3af3c08fda2070e4bf0c862c232ca17) CW-Bug-Id: #21898 --- dlls/bcrypt/bcrypt_main.c | 8 ++++---- dlls/bcrypt/tests/bcrypt.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c index e3bdc8d6a88..249b8c78c21 100644 --- a/dlls/bcrypt/bcrypt_main.c +++ b/dlls/bcrypt/bcrypt_main.c @@ -1169,12 +1169,12 @@ static BOOL is_equal_vector( const UCHAR *vector, ULONG len, const UCHAR *vector static NTSTATUS key_symmetric_set_vector( struct key *key, UCHAR *vector, ULONG vector_len, BOOL force_reset ) { BOOL needs_reset = force_reset || !is_equal_vector( key->u.s.vector, key->u.s.vector_len, vector, vector_len ); - - free( key->u.s.vector ); - key->u.s.vector = NULL; - key->u.s.vector_len = 0; if (vector) { + free( key->u.s.vector ); + key->u.s.vector = NULL; + key->u.s.vector_len = 0; + if (!(key->u.s.vector = malloc( vector_len ))) return STATUS_NO_MEMORY; memcpy( key->u.s.vector, vector, vector_len ); key->u.s.vector_len = vector_len; diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c index c64ecb365a3..6f83f447f39 100644 --- a/dlls/bcrypt/tests/bcrypt.c +++ b/dlls/bcrypt/tests/bcrypt.c @@ -843,7 +843,7 @@ static void test_BCryptGenerateSymmetricKey(void) ret = BCryptEncrypt(key, data, 16, NULL, NULL, 0, ciphertext, 16, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); - todo_wine ok(!memcmp(ciphertext, expected2, sizeof(expected2)), "wrong data\n"); + ok(!memcmp(ciphertext, expected2, sizeof(expected2)), "wrong data\n"); size = 0; memcpy(ivbuf, iv, sizeof(iv)); @@ -1129,7 +1129,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data, 16, NULL, NULL, 0, ciphertext, 16, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); - todo_wine ok(!memcmp(ciphertext, expected8, sizeof(expected8)), "wrong data\n"); + ok(!memcmp(ciphertext, expected8, sizeof(expected8)), "wrong data\n"); /* all zero initialization vector */ size = 0; @@ -1556,7 +1556,7 @@ static void test_BCryptEncrypt(void) ret = BCryptEncrypt(key, data, 16, NULL, NULL, 0, ciphertext, 16, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 16, "got %lu\n", size); - todo_wine ok(!memcmp(ciphertext, expected12, sizeof(expected12)), "wrong data\n"); + ok(!memcmp(ciphertext, expected12, sizeof(expected12)), "wrong data\n"); /* all zero initialization vector */ size = 0; @@ -1784,7 +1784,7 @@ static void test_BCryptDecrypt(void) ret = BCryptDecrypt(key, ciphertext, 32, NULL, NULL, 0, plaintext, 32, &size, 0); ok(ret == STATUS_SUCCESS, "got %#lx\n", ret); ok(size == 32, "got %lu\n", size); - todo_wine ok(!memcmp(plaintext, expected4, sizeof(expected4)), "wrong data\n"); + ok(!memcmp(plaintext, expected4, sizeof(expected4)), "wrong data\n"); /* test with padding smaller than block size */ size = 0; From adb3eea83c0a814f6b889e4c23470d4b179b6837 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 31 Jan 2023 19:25:40 -0600 Subject: [PATCH 1028/2777] winegstreamer: Implement _GetInputStatus() for h264 decoder transform. (cherry picked from commit 1e3d4a1dc10f99062dd93f617d111931ba8e9765) CW-Bug-Id: #21714 --- dlls/mf/tests/transform.c | 31 +++++++++++++++++++++++++++++++ dlls/winegstreamer/h264_decoder.c | 11 +++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index f5cbf12f4c0..af207292167 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -3507,6 +3507,7 @@ static void test_h264_decoder(void) IMFMediaType *media_type; IMFTransform *transform; ULONG i, ret, ref; + DWORD flags; HRESULT hr; hr = CoInitialize(NULL); @@ -3543,6 +3544,11 @@ static void test_h264_decoder(void) hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type); ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "GetOutputAvailableType returned %#lx\n", hr); + flags = 0xdeadbeef; + hr = IMFTransform_GetInputStatus(transform, 0, &flags); + ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Got %#lx\n", hr); + ok(flags == 0xdeadbeef, "Got flags %#lx.\n", flags); + /* setting output media type first doesn't work */ check_mft_set_output_type(transform, output_type_desc, MF_E_TRANSFORM_TYPE_NOT_SET); check_mft_get_output_current_type(transform, NULL); @@ -3631,12 +3637,20 @@ static void test_h264_decoder(void) ret = IMFSample_Release(output_sample); ok(ret == 0, "Release returned %lu\n", ret); + flags = 0; + hr = IMFTransform_GetInputStatus(transform, 0, &flags); + ok(hr == S_OK, "Got %#lx\n", hr); + ok(flags == MFT_INPUT_STATUS_ACCEPT_DATA, "Got flags %#lx.\n", flags); hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); ok(hr == S_OK, "ProcessInput returned %#lx\n", hr); ret = IMFSample_Release(input_sample); ok(ret <= 1, "Release returned %lu\n", ret); input_sample = next_h264_sample(&h264_encoded_data, &h264_encoded_data_len); + flags = 0; + hr = IMFTransform_GetInputStatus(transform, 0, &flags); + ok(hr == S_OK, "Got %#lx\n", hr); + ok(flags == MFT_INPUT_STATUS_ACCEPT_DATA, "Got flags %#lx.\n", flags); hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); ok(hr == S_OK, "ProcessInput returned %#lx\n", hr); ret = IMFSample_Release(input_sample); @@ -3760,6 +3774,23 @@ static void test_h264_decoder(void) ret = IMFSample_Release(output_sample); ok(ret == 0, "Release returned %lu\n", ret); + do + { + flags = 0; + hr = IMFTransform_GetInputStatus(transform, 0, &flags); + ok(hr == S_OK, "Got %#lx\n", hr); + ok(flags == MFT_INPUT_STATUS_ACCEPT_DATA, "Got flags %#lx.\n", flags); + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK || hr == MF_E_NOTACCEPTING, "Got %#lx\n", hr); + input_sample = next_h264_sample(&h264_encoded_data, &h264_encoded_data_len); + } while (hr == S_OK); + + ok(hr == MF_E_NOTACCEPTING, "Got %#lx\n", hr); + flags = 0; + hr = IMFTransform_GetInputStatus(transform, 0, &flags); + ok(hr == S_OK, "Got %#lx\n", hr); + ok(flags == MFT_INPUT_STATUS_ACCEPT_DATA, "Got flags %#lx.\n", flags); + ret = IMFTransform_Release(transform); ok(ret == 0, "Release returned %lu\n", ret); ret = IMFSample_Release(input_sample); diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index f6aba970e91..32936145b24 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -551,8 +551,15 @@ static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) { - FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags); - return E_NOTIMPL; + struct h264_decoder *decoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, id %#lx, flags %p.\n", iface, id, flags); + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + *flags = MFT_INPUT_STATUS_ACCEPT_DATA; + return S_OK; } static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) From 9f3f8d4090ed52fab4518094228d7e7360518f8f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 31 Jan 2023 19:50:27 -0600 Subject: [PATCH 1029/2777] winegstreamer: Implement _GetInputStatus() for aac decoder transform. (cherry picked from commit 62068a4dff79ee640e2bf9d51fe4a6ad5226cf9e) CW-Bug-Id: #21714 --- dlls/mf/tests/transform.c | 28 ++++++++++++++++++++++++++++ dlls/winegstreamer/aac_decoder.c | 16 ++++++++++++++-- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/main.c | 16 ++++++++++++++++ dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 7 +++++++ dlls/winegstreamer/wg_parser.c | 1 + dlls/winegstreamer/wg_transform.c | 9 +++++++++ 8 files changed, 77 insertions(+), 2 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index af207292167..69139771532 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -2370,6 +2370,7 @@ static void test_aac_decoder(void) IMFMediaType *media_type; IMFTransform *transform; const BYTE *aacenc_data; + DWORD flags; HRESULT hr; hr = CoInitialize(NULL); @@ -2449,10 +2450,23 @@ static void test_aac_decoder(void) ok(aacenc_data_len == 24861, "got length %lu\n", aacenc_data_len); input_sample = create_sample(aacenc_data + sizeof(DWORD), *(DWORD *)aacenc_data); + + flags = 0; + hr = IMFTransform_GetInputStatus(transform, 0, &flags); + ok(hr == S_OK, "Got %#lx\n", hr); + ok(flags == MFT_INPUT_STATUS_ACCEPT_DATA, "Got flags %#lx.\n", flags); hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); ok(hr == S_OK, "ProcessInput returned %#lx\n", hr); + flags = 0xdeadbeef; + hr = IMFTransform_GetInputStatus(transform, 0, &flags); + ok(hr == S_OK, "Got %#lx\n", hr); + ok(!flags, "Got flags %#lx.\n", flags); hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr); + flags = 0xdeadbeef; + hr = IMFTransform_GetInputStatus(transform, 0, &flags); + ok(hr == S_OK, "Got %#lx\n", hr); + ok(!flags, "Got flags %#lx.\n", flags); /* As output_info.dwFlags doesn't have MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES * IMFTransform_ProcessOutput needs a sample or returns MF_E_TRANSFORM_NEED_MORE_INPUT */ @@ -2460,11 +2474,19 @@ static void test_aac_decoder(void) hr = check_mft_process_output(transform, NULL, &output_status); ok(hr == E_INVALIDARG, "ProcessOutput returned %#lx\n", hr); ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status); + flags = 0xdeadbeef; + hr = IMFTransform_GetInputStatus(transform, 0, &flags); + ok(hr == S_OK, "Got %#lx\n", hr); + ok(!flags, "Got flags %#lx.\n", flags); hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr); hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0); ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr); + flags = 0xdeadbeef; + hr = IMFTransform_GetInputStatus(transform, 0, &flags); + ok(hr == S_OK, "Got %#lx\n", hr); + ok(!flags, "Got flags %#lx.\n", flags); if (0) { /* This is fine on Windows but currently MFT_MESSAGE_COMMAND_DRAIN removes input sample from the queue @@ -2489,6 +2511,12 @@ static void test_aac_decoder(void) winetest_pop_context(); } ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr); + + flags = 0; + hr = IMFTransform_GetInputStatus(transform, 0, &flags); + ok(hr == S_OK, "Got %#lx\n", hr); + ok(flags == MFT_INPUT_STATUS_ACCEPT_DATA, "Got flags %#lx.\n", flags); + ok(output_status == MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE, "got output[0].dwStatus %#lx\n", output_status); ret = IMFSample_Release(output_sample); ok(ret == 0, "Release returned %lu\n", ret); diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index 920385abd3d..fbe57ffee36 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -500,8 +500,20 @@ static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) { - FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags); - return E_NOTIMPL; + struct aac_decoder *decoder = impl_from_IMFTransform(iface); + bool accepts_input; + HRESULT hr; + + TRACE("iface %p, id %#lx, flags %p.\n", iface, id, flags); + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (FAILED(hr = wg_transform_get_status(decoder->wg_transform, &accepts_input))) + return hr; + + *flags = accepts_input ? MFT_INPUT_STATUS_ACCEPT_DATA : 0; + return S_OK; } static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 337b94e8a32..daf0818c3fa 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -104,6 +104,7 @@ struct wg_transform *wg_transform_create(const struct wg_format *input_format, const struct wg_format *output_format); void wg_transform_destroy(struct wg_transform *transform); bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_format *format); +bool wg_transform_get_status(struct wg_transform *transform, bool *accepts_input); HRESULT wg_transform_drain(struct wg_transform *transform); unsigned int wg_format_get_max_size(const struct wg_format *format); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 0e2dd64fd07..2a2d5c55d7d 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -386,6 +386,22 @@ HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample return params.result; } +bool wg_transform_get_status(struct wg_transform *transform, bool *accepts_input) +{ + struct wg_transform_get_status_params params = + { + .transform = transform, + }; + + TRACE("transform %p, accepts_input %p.\n", transform, accepts_input); + + if (WINE_UNIX_CALL(unix_wg_transform_get_status, ¶ms)) + return false; + + *accepts_input = params.accepts_input; + return true; +} + bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_format *format) { struct wg_transform_set_output_format_params params = diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index bb69c084770..9f23b52f1c4 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -43,6 +43,7 @@ extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_set_output_format(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_transform_get_status(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_drain(void *args) DECLSPEC_HIDDEN; /* wg_allocator_release_sample can be used to release any sample that was requested. */ diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 5fe27fdf4c4..f098ff1fec3 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -317,6 +317,12 @@ struct wg_transform_set_output_format_params const struct wg_format *format; }; +struct wg_transform_get_status_params +{ + struct wg_transform *transform; + UINT32 accepts_input; +}; + struct wg_transform_drain_params { struct wg_transform *transform; @@ -355,6 +361,7 @@ enum unix_funcs unix_wg_transform_push_data, unix_wg_transform_read_data, + unix_wg_transform_get_status, unix_wg_transform_drain, }; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 0bc1fcc2686..d1ad9ec0e69 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -2043,5 +2043,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_transform_push_data), X(wg_transform_read_data), + X(wg_transform_get_status), X(wg_transform_drain), }; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 881015f878c..a31dacc9e79 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -994,3 +994,12 @@ NTSTATUS wg_transform_read_data(void *args) wg_allocator_release_sample(transform->allocator, sample, discard_data); return STATUS_SUCCESS; } + +NTSTATUS wg_transform_get_status(void *args) +{ + struct wg_transform_get_status_params *params = args; + struct wg_transform *transform = params->transform; + + params->accepts_input = gst_atomic_queue_length(transform->input_queue) < transform->input_max_length; + return STATUS_SUCCESS; +} From c8283ea22df8d49e4fade808ced5def2298b5397 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 3 Jan 2023 18:45:54 -0600 Subject: [PATCH 1030/2777] winegstreamer: Set MF_SA_D3D11_AWARE attribute for h264 transform. (cherry picked from commit 2cfcce835081fc3cadbfc3629fab8e713546d230) CW-Bug-Id: #21714 --- dlls/mf/tests/transform.c | 2 +- dlls/winegstreamer/h264_decoder.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 69139771532..9baa72ade5b 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -3257,7 +3257,7 @@ static void test_h264_decoder(void) { ATTR_UINT32(MF_LOW_LATENCY, 0), ATTR_UINT32(MF_SA_D3D_AWARE, 1, .todo = TRUE), - ATTR_UINT32(MF_SA_D3D11_AWARE, 1, .todo = TRUE), + ATTR_UINT32(MF_SA_D3D11_AWARE, 1), ATTR_UINT32(MFT_DECODER_EXPOSE_OUTPUT_TYPES_IN_NATIVE_ORDER, 0, .todo = TRUE), /* more H264 decoder specific attributes from CODECAPI */ {0}, diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 32936145b24..a1d70eb5733 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -752,6 +752,8 @@ HRESULT h264_decoder_create(REFIID riid, void **ret) goto failed; if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_LOW_LATENCY, 0))) goto failed; + if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, TRUE))) + goto failed; if (FAILED(hr = MFCreateAttributes(&decoder->output_attributes, 0))) goto failed; if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue))) From c3d4b7e188568633fbbe5452f02db3efd3fcd5af Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 3 Jan 2023 18:48:03 -0600 Subject: [PATCH 1031/2777] winegstreamer: Route MFAudioFormat_RAW_AAC to mf_media_type_to_wg_format_audio_mpeg4(). CW-Bug-Id: #21714 --- dlls/winegstreamer/aac_decoder.c | 2 -- dlls/winegstreamer/gst_private.h | 2 ++ dlls/winegstreamer/mfplat.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index fbe57ffee36..3be7e91147f 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -30,8 +30,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); WINE_DECLARE_DEBUG_CHANNEL(winediag); -extern const GUID MFAudioFormat_RAW_AAC; - static struct { const GUID *const guid; diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index daf0818c3fa..2f0681a18bd 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -156,4 +156,6 @@ HRESULT h264_decoder_create(REFIID riid, void **ret); HRESULT video_processor_create(REFIID riid, void **ret); HRESULT gstreamer_scheme_handler_construct(REFIID riid, void **ret) DECLSPEC_HIDDEN; +extern const GUID MFAudioFormat_RAW_AAC; + #endif /* __GST_PRIVATE_INCLUDED__ */ diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index d8c5292e2d4..e6af8569ea9 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -885,7 +885,7 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless) || IsEqualGUID(&subtype, &MFAudioFormat_XMAudio2)) mf_media_type_to_wg_format_audio_wma(type, &subtype, format); - else if (IsEqualGUID(&subtype, &MFAudioFormat_AAC)) + else if (IsEqualGUID(&subtype, &MFAudioFormat_AAC) || IsEqualGUID(&subtype, &MFAudioFormat_RAW_AAC)) mf_media_type_to_wg_format_audio_mpeg4(type, format); else mf_media_type_to_wg_format_audio(type, &subtype, format); From 059d74efc230d63ec193ef7327a834c3b7b4e75d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 14 Feb 2023 14:05:00 -0600 Subject: [PATCH 1032/2777] winegstreamer: Fix getting codec data for raw aac. CW-Bug-Id: #21714 --- dlls/winegstreamer/mfplat.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index e6af8569ea9..7dfc8631ba0 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -628,7 +628,7 @@ static void mf_media_type_to_wg_format_audio(IMFMediaType *type, const GUID *sub FIXME("Unrecognized audio subtype %s, depth %u.\n", debugstr_guid(subtype), depth); } -static void mf_media_type_to_wg_format_audio_mpeg4(IMFMediaType *type, struct wg_format *format) +static void mf_media_type_to_wg_format_audio_mpeg4(IMFMediaType *type, const GUID *subtype, struct wg_format *format) { /* Audio specific config is stored at after HEAACWAVEINFO in MF_MT_USER_DATA * https://docs.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-heaacwaveformat @@ -650,6 +650,7 @@ static void mf_media_type_to_wg_format_audio_mpeg4(IMFMediaType *type, struct wg BYTE buffer[64]; HEAACWAVEFORMAT *user_data = (HEAACWAVEFORMAT *)buffer; UINT32 codec_data_size; + BOOL raw_aac; if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_USER_DATA, buffer, sizeof(buffer), &codec_data_size))) { @@ -657,12 +658,18 @@ static void mf_media_type_to_wg_format_audio_mpeg4(IMFMediaType *type, struct wg return; } - codec_data_size -= min(codec_data_size, offsetof(HEAACWAVEFORMAT, pbAudioSpecificConfig)); + raw_aac = IsEqualGUID(subtype, &MFAudioFormat_RAW_AAC); + if (!raw_aac) + codec_data_size -= min(codec_data_size, offsetof(HEAACWAVEFORMAT, pbAudioSpecificConfig)); if (codec_data_size > sizeof(format->u.audio_mpeg4.codec_data)) { FIXME("Codec data needs %u bytes.\n", codec_data_size); return; } + if (raw_aac) + memcpy(format->u.audio_mpeg4.codec_data, buffer, codec_data_size); + else + memcpy(format->u.audio_mpeg4.codec_data, user_data->pbAudioSpecificConfig, codec_data_size); format->major_type = WG_MAJOR_TYPE_AUDIO_MPEG4; @@ -670,7 +677,6 @@ static void mf_media_type_to_wg_format_audio_mpeg4(IMFMediaType *type, struct wg format->u.audio_mpeg4.payload_type = -1; format->u.audio_mpeg4.codec_data_len = codec_data_size; - memcpy(format->u.audio_mpeg4.codec_data, user_data->pbAudioSpecificConfig, codec_data_size); } static void mf_media_type_to_wg_format_video(IMFMediaType *type, const GUID *subtype, struct wg_format *format) @@ -886,7 +892,7 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) IsEqualGUID(&subtype, &MFAudioFormat_XMAudio2)) mf_media_type_to_wg_format_audio_wma(type, &subtype, format); else if (IsEqualGUID(&subtype, &MFAudioFormat_AAC) || IsEqualGUID(&subtype, &MFAudioFormat_RAW_AAC)) - mf_media_type_to_wg_format_audio_mpeg4(type, format); + mf_media_type_to_wg_format_audio_mpeg4(type, &subtype, format); else mf_media_type_to_wg_format_audio(type, &subtype, format); } From 6c3a4f88e59eeab615932d93c2e0e2c5475659d6 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 14 Feb 2023 14:08:31 -0600 Subject: [PATCH 1033/2777] winegstreamer: Use default 0 for _AAC_PAYLOAD_TYPE if not set. CW-Bug-Id: #21714 --- dlls/winegstreamer/mfplat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 7dfc8631ba0..c560ff31a4a 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -674,7 +674,7 @@ static void mf_media_type_to_wg_format_audio_mpeg4(IMFMediaType *type, const GUI format->major_type = WG_MAJOR_TYPE_AUDIO_MPEG4; if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_PAYLOAD_TYPE, &format->u.audio_mpeg4.payload_type))) - format->u.audio_mpeg4.payload_type = -1; + format->u.audio_mpeg4.payload_type = 0; format->u.audio_mpeg4.codec_data_len = codec_data_size; } From 454450eb3779a4d43bbfd12838bf33a1389e3964 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 14 Feb 2023 14:09:50 -0600 Subject: [PATCH 1034/2777] mf/tests: Add basic tests for raw aac decode. CW-Bug-Id: #21714 --- dlls/mf/tests/transform.c | 45 +++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 9baa72ade5b..476d385f862 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -2220,7 +2220,7 @@ static void test_aac_encoder(void) CoUninitialize(); } -static void test_aac_decoder(void) +static void test_aac_decoder_subtype(const struct attribute_desc *input_type_desc) { const GUID *const class_id = &CLSID_MSAACDecMFT; const struct transform_info expect_mft_info = @@ -2310,19 +2310,6 @@ static void test_aac_decoder(void) /* more AAC decoder specific attributes from CODECAPI */ {0}, }; - const struct attribute_desc input_type_desc[] = - { - ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE), - ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_AAC, .required = TRUE), - ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100, .required = TRUE), - ATTR_BLOB(MF_MT_USER_DATA, aac_codec_data, sizeof(aac_codec_data), .required = TRUE), - ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16), - ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), - ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 12000), - ATTR_UINT32(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 41), - ATTR_UINT32(MF_MT_AAC_PAYLOAD_TYPE, 0), - {0}, - }; static const struct attribute_desc output_type_desc[] = { ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE), @@ -2547,6 +2534,36 @@ static void test_aac_decoder(void) CoUninitialize(); } +static void test_aac_decoder(void) +{ + static const BYTE aac_raw_codec_data[] = {0x12, 0x08}; + static const struct attribute_desc raw_aac_input_type_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_RAW_AAC1, .required = TRUE), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100, .required = TRUE), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), + ATTR_BLOB(MF_MT_USER_DATA, aac_raw_codec_data, sizeof(aac_raw_codec_data), .required = TRUE), + {0}, + }; + static const struct attribute_desc aac_input_type_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio, .required = TRUE), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_AAC, .required = TRUE), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100, .required = TRUE), + ATTR_BLOB(MF_MT_USER_DATA, aac_codec_data, sizeof(aac_codec_data), .required = TRUE), + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16), + ATTR_UINT32(MF_MT_AUDIO_NUM_CHANNELS, 1), + ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 12000), + ATTR_UINT32(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 41), + ATTR_UINT32(MF_MT_AAC_PAYLOAD_TYPE, 0), + {0}, + }; + + test_aac_decoder_subtype(aac_input_type_desc); + test_aac_decoder_subtype(raw_aac_input_type_desc); +} + static const BYTE wma_codec_data[10] = {0, 0x44, 0, 0, 0x17, 0, 0, 0, 0, 0}; static const ULONG wmaenc_block_size = 1487; static const ULONG wmadec_block_size = 0x2000; From d6e917c1aad9fe23fe50c206f8bde063da6c91fa Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 20 Feb 2023 18:34:23 -0600 Subject: [PATCH 1035/2777] win32u: Do not set last error in wait_message() for zero count. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54405 CW-Bug-Id: #21938 --- dlls/win32u/message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 8cc6c13bd52..8748d5acfc5 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2281,7 +2281,7 @@ static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DW mask, flags ); if (HIWORD(ret)) /* is it an error code? */ { - RtlSetLastWin32Error( RtlNtStatusToDosError(ret) ); + if (count) RtlSetLastWin32Error( RtlNtStatusToDosError(ret) ); ret = WAIT_FAILED; } if (ret == WAIT_TIMEOUT && !count && !timeout) NtYieldExecution(); From 7dc421bb36630330700f64dc5843a5cb010f8321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 23 Feb 2023 12:20:30 +0100 Subject: [PATCH 1036/2777] msvcrt: Fix _dupenv_s behavior with missing env var. CW-Bug-Id: #21952 --- dlls/msvcrt/environ.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dlls/msvcrt/environ.c b/dlls/msvcrt/environ.c index e541bd5bff0..4f8d54e3a07 100644 --- a/dlls/msvcrt/environ.c +++ b/dlls/msvcrt/environ.c @@ -229,7 +229,12 @@ int CDECL _dupenv_s(char **buffer, size_t *numberOfElements, const char *varname if (!MSVCRT_CHECK_PMT(buffer != NULL)) return EINVAL; if (!MSVCRT_CHECK_PMT(varname != NULL)) return EINVAL; - if (!(e = getenv(varname))) return *_errno() = EINVAL; + if (!(e = getenv(varname))) + { + *buffer = NULL; + if (numberOfElements) *numberOfElements = 0; + return 0; + } sz = strlen(e) + 1; if (!(*buffer = malloc(sz))) From a87acee59eeb31b9285c6b3c7e91577fc33ad2c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 23 Feb 2023 12:21:03 +0100 Subject: [PATCH 1037/2777] msvcrt: Fix _wdupenv_s behavior with missing env var. CW-Bug-Id: #21952 --- dlls/msvcrt/environ.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dlls/msvcrt/environ.c b/dlls/msvcrt/environ.c index 4f8d54e3a07..b23f1196319 100644 --- a/dlls/msvcrt/environ.c +++ b/dlls/msvcrt/environ.c @@ -259,7 +259,12 @@ int CDECL _wdupenv_s(wchar_t **buffer, size_t *numberOfElements, if (!MSVCRT_CHECK_PMT(buffer != NULL)) return EINVAL; if (!MSVCRT_CHECK_PMT(varname != NULL)) return EINVAL; - if (!(e = _wgetenv(varname))) return *_errno() = EINVAL; + if (!(e = _wgetenv(varname))) + { + *buffer = NULL; + if (numberOfElements) *numberOfElements = 0; + return 0; + } sz = wcslen(e) + 1; if (!(*buffer = malloc(sz * sizeof(wchar_t)))) From efd6149fbcf5096d1f6f06ca455bec49c5f8aa24 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 7 Dec 2022 12:08:43 -0600 Subject: [PATCH 1038/2777] win32u, server: Support setting desktop close timeout. And use zero timeout by default. CW-Bug-Id: #19584 CW-Bug-Id: #21645 --- dlls/win32u/winstation.c | 27 ++++++++++++++++++++++++--- server/protocol.def | 3 +++ server/user.h | 1 + server/winstation.c | 4 +++- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 61d1e8edee8..28771584712 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -367,6 +367,8 @@ BOOL WINAPI NtUserGetObjectInformation( HANDLE handle, INT index, void *info, } } +#define TICKSPERSEC 10000000 + /*********************************************************************** * NtUserSetObjectInformation (win32u.@) */ @@ -374,8 +376,19 @@ BOOL WINAPI NtUserSetObjectInformation( HANDLE handle, INT index, void *info, DW { BOOL ret; const USEROBJECTFLAGS *obj_flags = info; + LONG64 close_timeout = 0; - if (index != UOI_FLAGS || !info || len < sizeof(*obj_flags)) + if (index == 1000) + { + /* Wine specific: set desktop close timeout. */ + if (!info || len < sizeof(DWORD)) + { + RtlSetLastWin32Error( ERROR_INVALID_PARAMETER ); + return FALSE; + } + close_timeout = -(*(DWORD *)info * (ULONG64)TICKSPERSEC / 1000); + } + else if (index != UOI_FLAGS || !info || len < sizeof(*obj_flags)) { RtlSetLastWin32Error( ERROR_INVALID_PARAMETER ); return FALSE; @@ -384,8 +397,16 @@ BOOL WINAPI NtUserSetObjectInformation( HANDLE handle, INT index, void *info, DW SERVER_START_REQ( set_user_object_info ) { req->handle = wine_server_obj_handle( handle ); - req->flags = SET_USER_OBJECT_SET_FLAGS; - req->obj_flags = obj_flags->dwFlags; + if (index == 1000) + { + req->flags = SET_USER_OBJECT_SET_CLOSE_TIMEOUT; + req->close_timeout = close_timeout; + } + else + { + req->flags = SET_USER_OBJECT_SET_FLAGS; + req->obj_flags = obj_flags->dwFlags; + } ret = !wine_server_call_err( req ); } SERVER_END_REQ; diff --git a/server/protocol.def b/server/protocol.def index c21f86d3d49..3f8e8118aca 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2802,6 +2802,7 @@ enum coords_relative obj_handle_t handle; /* handle to the object */ unsigned int flags; /* information to set/get */ unsigned int obj_flags; /* new object flags */ + timeout_t close_timeout; /* desktop close timeout */ @REPLY int is_desktop; /* is object a desktop? */ unsigned int old_obj_flags; /* old object flags */ @@ -2809,6 +2810,7 @@ enum coords_relative @END #define SET_USER_OBJECT_SET_FLAGS 1 #define SET_USER_OBJECT_GET_FULL_NAME 2 +#define SET_USER_OBJECT_SET_CLOSE_TIMEOUT 4 /* Register a hotkey */ @@ -3556,6 +3558,7 @@ struct handle_info /* Make the current process a system process */ @REQ(make_process_system) obj_handle_t handle; /* handle to the process */ + timeout_t desktop_close_timeout; /* set timeout for desktop close */ @REPLY obj_handle_t event; /* event signaled when all user processes have exited */ @END diff --git a/server/user.h b/server/user.h index 345db9225d4..1a7980e6f61 100644 --- a/server/user.h +++ b/server/user.h @@ -63,6 +63,7 @@ struct desktop struct hook_table *global_hooks; /* table of global hooks on this desktop */ struct list hotkeys; /* list of registered hotkeys */ struct timeout_user *close_timeout; /* timeout before closing the desktop */ + timeout_t close_timeout_val;/* timeout duration before closing desktop */ struct list touches; /* list of active touches */ struct thread_input *foreground_input; /* thread input of foreground thread */ unsigned int users; /* processes and threads using this desktop */ diff --git a/server/winstation.c b/server/winstation.c index 52da03c3718..53613592a82 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -257,6 +257,7 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned desktop->msg_window = NULL; desktop->global_hooks = NULL; desktop->close_timeout = NULL; + desktop->close_timeout_val = 0; desktop->foreground_input = NULL; desktop->users = 0; desktop->cursor_clip_msg = 0; @@ -364,7 +365,7 @@ static void remove_desktop_user( struct desktop *desktop ) /* if we have one remaining user, it has to be the manager of the desktop window */ if ((process = get_top_window_owner( desktop )) && desktop->users == process->running_threads && !desktop->close_timeout) - desktop->close_timeout = add_timeout_user( -TICKS_PER_SEC, close_desktop_timeout, desktop ); + desktop->close_timeout = add_timeout_user( desktop->close_timeout_val, close_desktop_timeout, desktop ); } /* set the thread default desktop handle */ @@ -703,6 +704,7 @@ DECL_HANDLER(set_user_object_info) reply->is_desktop = 1; reply->old_obj_flags = desktop->flags; if (req->flags & SET_USER_OBJECT_SET_FLAGS) desktop->flags = req->obj_flags; + if (req->flags & SET_USER_OBJECT_SET_CLOSE_TIMEOUT) desktop->close_timeout_val = req->close_timeout; } else if (obj->ops == &winstation_ops) { From 0f1683aeb0bb318f1a236a06446df9386c06c439 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 7 Mar 2023 15:54:01 -0600 Subject: [PATCH 1039/2777] fsync: Retry grabbing semaphore if count has changed. CW-Bug-Id: #21996 --- dlls/ntdll/unix/fsync.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index fab1be35adc..a520de13e41 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -976,15 +976,18 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, case FSYNC_SEMAPHORE: { struct semaphore *semaphore = obj->shm; - int current; + int current, new; - if ((current = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST )) - && __sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) == current) + new = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST ); + while ((current = new)) { - TRACE("Woken up by handle %p [%d].\n", handles[i], i); - if (waited) simulate_sched_quantum(); - put_objects( objs, count ); - return i; + if ((new = __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(); + put_objects( objs, count ); + return i; + } } futex_vector_set( &futexes[i], &semaphore->count, 0 ); break; @@ -1230,10 +1233,15 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, case FSYNC_SEMAPHORE: { struct semaphore *semaphore = obj->shm; - int current; + int current, new; - if (!(current = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST )) - || __sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) != current) + new = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST ); + while ((current = new)) + { + if ((new = __sync_val_compare_and_swap( &semaphore->count, current, current - 1 )) == current) + break; + } + if (!current) goto tooslow; break; } From 25af2062b760f01a11ef65ffb0b554b3f17f8f9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 16 Mar 2023 10:43:14 +0100 Subject: [PATCH 1040/2777] ntoskrnl.exe: Enumerate devices in their invalidation order. This fixes a regression from 9fbdf2b43435caf62742d997bf8b3fb8752f606c, which broke XInput-compatible controller hotplug in some games. They register for HID device PnP notification and expect that XInput already has the controller device available on some slot, or they will later ignore that controller device. In Wine, we use HID-like internal interface for XInput, and register for PnP notifications on this internal interface class. In winexinput.sys, the internal interface is created and invalidated before the matching public HID interface, and we expect XInput to be notified before the application is. CW-Bug-Id: #22037 --- dlls/ntoskrnl.exe/pnp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c index 7c77a9a7145..3a2826a8f0a 100644 --- a/dlls/ntoskrnl.exe/pnp.c +++ b/dlls/ntoskrnl.exe/pnp.c @@ -1126,7 +1126,9 @@ static DWORD CALLBACK device_enum_thread_proc(void *arg) while (!invalidated_devices_count) SleepConditionVariableCS( &invalidated_devices_cv, &invalidated_devices_cs, INFINITE ); - device = invalidated_devices[--invalidated_devices_count]; + invalidated_devices_count--; + device = invalidated_devices[0]; + memmove( invalidated_devices, invalidated_devices + 1, invalidated_devices_count * sizeof(*invalidated_devices) ); /* Don't hold the CS while enumerating the device. Tests show that * calling IoInvalidateDeviceRelations() from another thread shouldn't From 18b28a85957c3999cbb2ec555807d6ffd15aac06 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 20 Mar 2023 10:03:16 -0600 Subject: [PATCH 1041/2777] ntdll: HACK: Search for ucrtbase using common rules. CW-Bug-Id: #22048 --- dlls/ntdll/loader.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index e800f40d787..1e6858437e0 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -2884,8 +2884,18 @@ static NTSTATUS find_actctx_dll( LPCWSTR libname, LPWSTR *fullname ) */ static NTSTATUS prepend_system_dir( const WCHAR *name, ULONG name_length, WCHAR **fullname ) { + static const WCHAR ucrtbase[] = L"ucrtbase.dll"; ULONG len; + if (name_length == sizeof(ucrtbase) / sizeof(*ucrtbase) - 1 && !_wcsnicmp( name, ucrtbase, name_length )) + { + if (!(*fullname = RtlAllocateHeap( GetProcessHeap(), 0, (name_length + 1) * sizeof(WCHAR) ))) + return STATUS_NO_MEMORY; + memcpy( *fullname, name, name_length * sizeof(WCHAR) ); + (*fullname)[name_length] = 0; + return STATUS_SUCCESS; + } + len = wcslen( system_dir ) + name_length; if (!(*fullname = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return STATUS_NO_MEMORY; From 4b6dc565790923bb26fe66016bdcbf4e36bb8fd0 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 21 Mar 2023 20:31:35 -0600 Subject: [PATCH 1042/2777] dwmapi: Sleep in DwmFlush(). CW-Bug-Id: #22046 --- dlls/dwmapi/dwmapi_main.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/dlls/dwmapi/dwmapi_main.c b/dlls/dwmapi/dwmapi_main.c index 973af052a4a..d83b437b80e 100644 --- a/dlls/dwmapi/dwmapi_main.c +++ b/dlls/dwmapi/dwmapi_main.c @@ -83,18 +83,6 @@ HRESULT WINAPI DwmGetColorizationColor(DWORD *colorization, BOOL *opaque_blend) return E_NOTIMPL; } -/********************************************************************** - * DwmFlush (DWMAPI.@) - */ -HRESULT WINAPI DwmFlush(void) -{ - static BOOL once; - - if (!once++) FIXME("() stub\n"); - - return S_OK; -} - /********************************************************************** * DwmInvalidateIconicBitmaps (DWMAPI.@) */ @@ -295,6 +283,31 @@ HRESULT WINAPI DwmGetCompositionTimingInfo(HWND hwnd, DWM_TIMING_INFO *info) return S_OK; } +/********************************************************************** + * DwmFlush (DWMAPI.@) + */ +HRESULT WINAPI DwmFlush(void) +{ + LARGE_INTEGER qpf, qpc, delay; + LONG64 qpc_refresh_period; + int display_frequency; + static BOOL once; + + if (!once++) + FIXME("() stub\n"); + else + TRACE(".\n"); + + display_frequency = get_display_frequency(); + NtQueryPerformanceCounter(&qpc, &qpf); + qpc_refresh_period = qpf.QuadPart / display_frequency; + delay.QuadPart = (qpc.QuadPart - ((qpc.QuadPart + qpc_refresh_period - 1) / qpc_refresh_period) * qpc_refresh_period) + * 10000000 / qpf.QuadPart; + NtDelayExecution(FALSE, &delay); + + return S_OK; +} + /********************************************************************** * DwmAttachMilContent (DWMAPI.@) */ From 7267a0e38eee69af7042292bff435b98a8e1898b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 29 Mar 2023 18:58:25 +0200 Subject: [PATCH 1043/2777] HACK: msmpeg2vdec: Refuse to load DLL for some games. THE KING OF FIGHTERS XV will try to use MF DXGI device manager as soon as msmpeg2vdec.dll and msauddecmft.dll are succesfully loaded. CW-Bug-Id: #22084 --- dlls/msmpeg2vdec/Makefile.in | 3 +++ dlls/msmpeg2vdec/main.c | 48 ++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 dlls/msmpeg2vdec/main.c diff --git a/dlls/msmpeg2vdec/Makefile.in b/dlls/msmpeg2vdec/Makefile.in index d2dbf5adda0..609c6a34f9a 100644 --- a/dlls/msmpeg2vdec/Makefile.in +++ b/dlls/msmpeg2vdec/Makefile.in @@ -1 +1,4 @@ MODULE = msmpeg2vdec.dll + +C_SRCS = \ + main.c diff --git a/dlls/msmpeg2vdec/main.c b/dlls/msmpeg2vdec/main.c new file mode 100644 index 00000000000..348d3d405b4 --- /dev/null +++ b/dlls/msmpeg2vdec/main.c @@ -0,0 +1,48 @@ +/* + * Copyright 2023 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 + */ + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved ) +{ + TRACE( "instance %p, reason %#lx, reserved %p\n", instance, reason, reserved ); + + switch (reason) + { + case DLL_PROCESS_ATTACH: + { + const char *sgi; + if ((sgi = getenv( "SteamGameId" )) && !strcmp( sgi, "1498570" )) return FALSE; + DisableThreadLibraryCalls( instance ); + break; + } + case DLL_PROCESS_DETACH: + break; + } + + return TRUE; +} From 11f4b00f52a22a31570aa8178e68050e9e82bc30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 5 Apr 2023 12:38:11 +0200 Subject: [PATCH 1044/2777] ddraw: Remove topmost from the previous window when releasing exclusive cooperative level. Fixes The Binding of Isaac staying topmost, regression after upstream commit e44afcd8bf17eb628fcb1ea0b012970b6e611da4. Note: this is possibly a hack and maybe we should use exclusive_window instead, but it is cleared when focus is lost in device_parent_activate, and removing topmost there as well is a bigger, riskier change. CW-Bug-Id: #22108 --- dlls/ddraw/ddraw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c index fd4c5bd4862..7a8c4fe8719 100644 --- a/dlls/ddraw/ddraw.c +++ b/dlls/ddraw/ddraw.c @@ -978,7 +978,7 @@ static HRESULT ddraw_set_cooperative_level(struct ddraw *ddraw, HWND window, topmost bit unless the DDSCL_NOWINDOWCHANGES flag is set in this call that sets it to normal, not in the old coop level. */ if (!(cooplevel & DDSCL_NOWINDOWCHANGES)) - SetWindowPos(window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + SetWindowPos(ddraw->dest_window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); if (restore_mode_on_normal && FAILED(ddraw7_RestoreDisplayMode(&ddraw->IDirectDraw7_iface))) ERR("RestoreDisplayMode failed\n"); From bde47fedd341f412045e1a7321299f1465ce6ef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 5 Apr 2023 16:20:15 +0200 Subject: [PATCH 1045/2777] winex11: Avoid updating fullscreen monitor info when minimized. CW-Bug-Id: #22105 --- dlls/winex11.drv/window.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index e6cae0684d9..58417f37506 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1322,7 +1322,9 @@ void update_net_wm_states( struct x11drv_win_data *data ) } } data->net_wm_state = new_state; - update_net_wm_fullscreen_monitors( data ); + + if (!(style & WS_MINIMIZE)) + update_net_wm_fullscreen_monitors( data ); XChangeProperty( data->display, data->whole_window, x11drv_atom(_NET_WM_BYPASS_COMPOSITOR), XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&net_wm_bypass_compositor, 1 ); From 01dad2c92a56e141225a992ba09599c444e4a586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 5 Apr 2023 16:20:42 +0200 Subject: [PATCH 1046/2777] fshack: winex11: Implement _NET_FULLSCREEN_MONITOR support. CW-Bug-Id: #22105 --- dlls/winex11.drv/fs.c | 6 +++++- dlls/winex11.drv/window.c | 23 ++++++++++++++++++++++- dlls/winex11.drv/xinerama.c | 10 ++++------ 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/dlls/winex11.drv/fs.c b/dlls/winex11.drv/fs.c index bf1766cfb15..d43ab716e56 100644 --- a/dlls/winex11.drv/fs.c +++ b/dlls/winex11.drv/fs.c @@ -913,10 +913,14 @@ void fs_hack_init(void) { struct x11drv_display_device_handler device_handler; struct x11drv_settings_handler settings_handler; + RECT rect; real_device_handler = X11DRV_DisplayDevices_GetHandler(); real_settings_handler = X11DRV_Settings_GetHandler(); + rect = get_host_primary_monitor_rect(); + xinerama_init( rect.right - rect.left, rect.bottom - rect.top ); + settings_handler.name = "Fullscreen Hack"; settings_handler.priority = 500; settings_handler.get_id = real_settings_handler.get_id; @@ -934,7 +938,7 @@ void fs_hack_init(void) device_handler.free_gpus = real_device_handler.free_gpus; device_handler.free_adapters = real_device_handler.free_adapters; device_handler.free_monitors = real_device_handler.free_monitors; - device_handler.register_event_handlers = NULL; + device_handler.register_event_handlers = real_device_handler.register_event_handlers; X11DRV_DisplayDevices_SetHandler( &device_handler ); initialized = TRUE; diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 58417f37506..a265aae59dd 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1180,6 +1180,8 @@ void update_user_time( Time time ) * windows spanning multiple monitors */ static void update_net_wm_fullscreen_monitors( struct x11drv_win_data *data ) { + RECT window_rect = data->whole_rect, monitor_rect; + HMONITOR hmonitor; long monitors[4]; XEvent xev; @@ -1192,8 +1194,27 @@ static void update_net_wm_fullscreen_monitors( struct x11drv_win_data *data ) if (!X11DRV_DisplayDevices_SupportEventHandlers()) return; - if (!xinerama_get_fullscreen_monitors( &data->whole_rect, monitors )) + if (!(hmonitor = fs_hack_monitor_from_hwnd( data->hwnd ))) + { + ERR( "Failed to find monitor for %p at %s\n", data->hwnd, wine_dbgstr_rect(&data->whole_rect) ); + return; + } + + monitor_rect = fs_hack_current_mode( hmonitor ); + intersect_rect( &window_rect, &monitor_rect, &window_rect ); + if (!EqualRect( &window_rect, &data->whole_rect )) + { + ERR( "hwnd %p at %s is outside of monitor %p at %s, ignoring\n", data->hwnd, + wine_dbgstr_rect(&data->whole_rect), hmonitor, wine_dbgstr_rect(&monitor_rect) ); return; + } + + monitor_rect = fs_hack_real_mode( hmonitor ); + if (!xinerama_get_fullscreen_monitors( &monitor_rect, monitors )) + { + ERR( "Failed to find xinerama monitors for %p at %s\n", hmonitor, wine_dbgstr_rect(&monitor_rect) ); + return; + } if (!data->mapped) { diff --git a/dlls/winex11.drv/xinerama.c b/dlls/winex11.drv/xinerama.c index 6835aa4a331..588cd4e8dde 100644 --- a/dlls/winex11.drv/xinerama.c +++ b/dlls/winex11.drv/xinerama.c @@ -126,7 +126,7 @@ static inline int query_screens(void) /* Get xinerama monitor indices required for _NET_WM_FULLSCREEN_MONITORS */ BOOL xinerama_get_fullscreen_monitors( const RECT *rect, long *indices ) { - RECT window_rect, intersected_rect, monitor_rect; + RECT window_rect, intersected_rect, monitor_rect, virtual; BOOL ret = FALSE; POINT offset; INT i; @@ -140,11 +140,9 @@ BOOL xinerama_get_fullscreen_monitors( const RECT *rect, long *indices ) } /* Convert window rectangle to root coordinates */ - offset = virtual_screen_to_root( rect->left, rect->top ); - window_rect.left = offset.x; - window_rect.top = offset.y; - window_rect.right = window_rect.left + rect->right - rect->left; - window_rect.bottom = window_rect.top + rect->bottom - rect->top; + window_rect = *rect; + virtual = fs_hack_get_real_virtual_screen(); + OffsetRect( &window_rect, -virtual.left, -virtual.top ); /* Compare to xinerama monitor rectangles in root coordinates */ offset.x = INT_MAX; From 9c515fa06aad5553e09cdabf0828f3dacf8873e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 7 Apr 2023 10:47:36 +0200 Subject: [PATCH 1047/2777] fshack: winex11: Pass the current HMONITOR to window_update_fshack. As fs_hack_monitor_from_hwnd may use a stale window position, different from the one we get in X11DRV_WindowPosChanging. CW-Bug-Id: #22116 --- dlls/winex11.drv/window.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index a265aae59dd..697203dd499 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2945,10 +2945,10 @@ static inline BOOL get_surface_rect( const RECT *visible_rect, RECT *surface_rec return TRUE; } -static BOOL CALLBACK update_child_window_fshack( HWND hwnd, LPARAM enable ); +static BOOL CALLBACK update_child_window_fshack( HWND hwnd, LPARAM lparam ); static void window_update_fshack( struct x11drv_win_data *data, const RECT *window_rect_virt, - const RECT *client_rect_virt, BOOL enable ) + const RECT *client_rect_virt, HMONITOR hmonitor, BOOL enable ) { BOOL set_hints = window_rect_virt == NULL; /* don't change hints yet in X11DRV_WindowPosChanging */ RECT window_rect_host, client_rect_host; @@ -2968,8 +2968,7 @@ static void window_update_fshack( struct x11drv_win_data *data, const RECT *wind } else { - HMONITOR monitor = fs_hack_monitor_from_hwnd( data->hwnd ); - window_rect_host = fs_hack_real_mode( monitor ); + window_rect_host = fs_hack_real_mode( hmonitor ); if (data->whole_window) /* HACK: top-level window, pretend client rect covers it fully */ client_rect_host = window_rect_host; @@ -3014,14 +3013,14 @@ static void window_update_fshack( struct x11drv_win_data *data, const RECT *wind invalidate_vk_surfaces( data->hwnd ); } - NtUserEnumChildWindows( data->hwnd, update_child_window_fshack, enable ); + NtUserEnumChildWindows( data->hwnd, update_child_window_fshack, MAKELONG(hmonitor, enable) ); } -static BOOL CALLBACK update_child_window_fshack( HWND hwnd, LPARAM enable ) +static BOOL CALLBACK update_child_window_fshack( HWND hwnd, LPARAM lparam ) { struct x11drv_win_data *data; if (!(data = get_win_data( hwnd ))) return TRUE; - if (data->client_window) window_update_fshack( data, NULL, NULL, enable ); + if (data->client_window) window_update_fshack( data, NULL, NULL, UlongToPtr(LOWORD(lparam)), HIWORD(lparam) ); release_win_data( data ); return TRUE; } @@ -3045,9 +3044,9 @@ BOOL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags, monitor = fs_hack_monitor_from_rect( window_rect ); if (fs_hack_enabled( monitor ) && fs_hack_matches_current_mode( monitor, window_rect->right - window_rect->left, window_rect->bottom - window_rect->top )) - window_update_fshack( data, window_rect, client_rect, TRUE ); + window_update_fshack( data, window_rect, client_rect, monitor, TRUE ); else - window_update_fshack( data, window_rect, client_rect, FALSE ); + window_update_fshack( data, window_rect, client_rect, monitor, FALSE ); /* check if we need to switch the window to managed */ if (!data->managed && data->whole_window && is_window_managed( hwnd, swp_flags, window_rect )) @@ -3644,7 +3643,7 @@ static void handle_window_desktop_resize( struct x11drv_win_data *data, UINT old fs_hack_matches_current_mode( monitor, data->whole_rect.right - data->whole_rect.left, data->whole_rect.bottom - data->whole_rect.top )) { - window_update_fshack( data, NULL, NULL, TRUE ); + window_update_fshack( data, NULL, NULL, monitor, TRUE ); return; } @@ -3669,7 +3668,7 @@ static void handle_window_desktop_resize( struct x11drv_win_data *data, UINT old if (!fs_hack_mapping_required( monitor ) || !fs_hack_matches_current_mode( monitor, data->whole_rect.right - data->whole_rect.left, data->whole_rect.bottom - data->whole_rect.top )) - window_update_fshack( data, NULL, NULL, FALSE ); + window_update_fshack( data, NULL, NULL, monitor, FALSE ); } /********************************************************************** From 90adee1fc56af86c93bb3878aaed1a07e47fab20 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 7 Apr 2023 19:59:49 -0600 Subject: [PATCH 1048/2777] wined3d: Set window state from the calling thread. This effectively reverts commit 1765c4594f6a11fe0df1aed7261cfafdb7514c43. CW-Bug-Id: #22121 --- dlls/wined3d/swapchain.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index 337c0410d39..0b4a33ca054 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -2147,26 +2147,12 @@ static DWORD WINAPI set_window_state_thread(void *ctx) static void set_window_state(struct wined3d_window_state *s) { DWORD window_tid = GetWindowThreadProcessId(s->window, NULL); - DWORD tid = GetCurrentThreadId(); - HANDLE thread; TRACE("Window %p belongs to thread %#lx.\n", s->window, window_tid); /* If the window belongs to a different thread, modifying the style and/or * position can potentially deadlock if that thread isn't processing * messages. */ - if (window_tid == tid) - { - set_window_state_thread(s); - } - else if ((thread = CreateThread(NULL, 0, set_window_state_thread, s, 0, NULL))) - { - SetThreadDescription(thread, L"wined3d_set_window_state"); - CloseHandle(thread); - } - else - { - ERR("Failed to create thread.\n"); - } + set_window_state_thread(s); } HRESULT wined3d_swapchain_state_setup_fullscreen(struct wined3d_swapchain_state *state, From 3b28570f60280896d034707a89e4480032899670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 13 Apr 2023 20:13:05 +0200 Subject: [PATCH 1049/2777] ntdll: Guard gdb integration behind WINEDEBUG=+gdb. --- dlls/ntdll/unix/loader.c | 5 ++++- dlls/ntdll/unix/virtual.c | 10 +++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 0a9e16afbbc..8833e959283 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -95,6 +95,7 @@ #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(module); +WINE_DECLARE_DEBUG_CHANNEL(gdb); #ifdef __i386__ static const char so_dir[] = "/i386-unix"; @@ -1531,6 +1532,8 @@ void notify_gdb_native_dll_loaded( void *module, UNICODE_STRING *nt_name ) UNICODE_STRING redir; char *unix_path = NULL; + if (!TRACE_ON(gdb)) return; + InitializeObjectAttributes( &attr, nt_name, OBJ_CASE_INSENSITIVE, 0, 0 ); get_redirect( &attr, &redir ); @@ -1592,7 +1595,7 @@ static NTSTATUS open_builtin_pe_file( const char *name, OBJECT_ATTRIBUTES *attr, { status = virtual_map_builtin_module( mapping, module, size, image_info, zero_bits, machine, prefer_native ); NtClose( mapping ); - if (!status) notify_gdb_dll_loaded( *module, name ); + if (!status && TRACE_ON(gdb)) notify_gdb_dll_loaded( *module, name ); } return status; } diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 22a66f4116d..c1604b20eb7 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -80,6 +80,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(virtual); WINE_DECLARE_DEBUG_CHANNEL(module); WINE_DECLARE_DEBUG_CHANNEL(virtual_ranges); +WINE_DECLARE_DEBUG_CHANNEL(gdb); struct preload_info { @@ -5301,9 +5302,12 @@ static NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr, ULONG flags ) SERVER_END_REQ; if (!status) { - static void (*wine_gdb_dll_unload)( const void *module ); - if (!wine_gdb_dll_unload) wine_gdb_dll_unload = dlsym( RTLD_DEFAULT, "wine_gdb_dll_unload" ); - if (wine_gdb_dll_unload) wine_gdb_dll_unload( view->base ); + if (TRACE_ON(gdb)) + { + static void (*wine_gdb_dll_unload)( const void *module ); + if (!wine_gdb_dll_unload) wine_gdb_dll_unload = dlsym( RTLD_DEFAULT, "wine_gdb_dll_unload" ); + if (wine_gdb_dll_unload) wine_gdb_dll_unload( view->base ); + } if (view->protect & SEC_IMAGE) release_builtin_module( view->base ); if (flags & MEM_PRESERVE_PLACEHOLDER) From bd85c4a0f66f5fb4930368ca522dfc068e8b619b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 22 Feb 2023 22:11:51 +0100 Subject: [PATCH 1050/2777] Revert "ntdll: Enable LFH in RtlCreateHeap()." This reverts commit d33871eb7ff35c69f74c88a3834d518696f377e5. --- dlls/ntdll/heap.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 9dc0f0e8908..dbb578cceff 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -1402,13 +1402,6 @@ HANDLE WINAPI RtlCreateHeap( ULONG flags, void *addr, SIZE_T total_size, SIZE_T list_init( &process_heap->entry ); } - if (!(flags & HEAP_CREATE_ENABLE_EXECUTE)) - { - ULONG hci = 2; - - RtlSetHeapInformation(heap, HeapCompatibilityInformation, &hci, sizeof(hci)); - } - return heap; } From 24f4f05dd2ba0ccbac996951dce04c9578b72332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 22 Feb 2023 22:12:34 +0100 Subject: [PATCH 1051/2777] Revert "ntdll: Implement Low Fragmentation Heap." This reverts commit 88de62d83e13ae2146c36b86496c3336b3d660ea. --- dlls/kernel32/tests/heap.c | 6 - dlls/ntdll/Makefile.in | 1 - dlls/ntdll/heap.c | 39 +- dlls/ntdll/heap_lfh.c | 1228 -------------------------------- dlls/ntdll/ntdll_misc.h | 25 - dlls/ntdll/unix/unix_private.h | 1 - 6 files changed, 13 insertions(+), 1287 deletions(-) delete mode 100644 dlls/ntdll/heap_lfh.c diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index 494bccd36a1..29faf8c902e 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -1618,8 +1618,6 @@ static void test_GlobalAlloc(void) } /* invalid pointers are caught */ -if (0) -{ SetLastError( 0xdeadbeef ); tmp_mem = pGlobalFree( invalid_ptr ); ok( tmp_mem == invalid_ptr, "GlobalFree succeeded\n" ); @@ -1660,7 +1658,6 @@ if (0) ok( ret, "RtlGetUserInfoHeap failed, error %lu\n", GetLastError() ); ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); } -} /* GMEM_FIXED block doesn't allow resize, though it succeeds with GMEM_MODIFY */ mem = GlobalAlloc( GMEM_FIXED, small_size ); @@ -2366,8 +2363,6 @@ static void test_LocalAlloc(void) } /* invalid pointers are caught */ -if (0) -{ SetLastError( 0xdeadbeef ); tmp_mem = pLocalFree( invalid_ptr ); ok( tmp_mem == invalid_ptr, "LocalFree succeeded\n" ); @@ -2401,7 +2396,6 @@ if (0) ok( !tmp_mem, "LocalHandle succeeded\n" ); todo_wine ok( GetLastError() == ERROR_NOACCESS, "got error %lu\n", GetLastError() ); -} /* LMEM_FIXED block doesn't allow resize, though it succeeds with LMEM_MODIFY */ mem = LocalAlloc( LMEM_FIXED, small_size ); diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index 17f16adff1e..4f51cdc460b 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -20,7 +20,6 @@ C_SRCS = \ exception.c \ handletable.c \ heap.c \ - heap_lfh.c \ large_int.c \ loader.c \ locale.c \ diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index dbb578cceff..3d364d89040 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -225,6 +225,16 @@ C_ASSERT( offsetof(struct heap, subheap) <= REGION_ALIGN - 1 ); #define HEAP_DEF_SIZE (0x40000 * BLOCK_ALIGN) #define MAX_FREE_PENDING 1024 /* max number of free requests to delay */ +/* some undocumented flags (names are made up) */ +#define HEAP_PRIVATE 0x00001000 +#define HEAP_ADD_USER_INFO 0x00000100 +#define HEAP_USER_FLAGS_MASK 0x00000f00 +#define HEAP_PAGE_ALLOCS 0x01000000 +#define HEAP_VALIDATE 0x10000000 +#define HEAP_VALIDATE_ALL 0x20000000 +#define HEAP_VALIDATE_PARAMS 0x40000000 +#define HEAP_CHECKING_ENABLED 0x80000000 + BOOL delay_heap_free = FALSE; static struct heap *process_heap; /* main process heap */ @@ -1295,8 +1305,6 @@ static void heap_set_debug_flags( HANDLE handle ) MAX_FREE_PENDING * sizeof(*heap->pending_free) ); heap->pending_pos = 0; } - - HEAP_lfh_set_debug_flags( flags ); } @@ -1544,8 +1552,6 @@ void *WINAPI DECLSPEC_HOTPATCH RtlAllocateHeap( HANDLE handle, ULONG flags, SIZE if (!(heap = unsafe_heap_from_handle( handle, flags, &heap_flags ))) status = STATUS_INVALID_HANDLE; - else if (heap->compat_info == HEAP_LFH && !HEAP_lfh_allocate( heap, heap_flags, size, &ptr )) - status = STATUS_SUCCESS; else if ((block_size = heap_get_block_size( heap, heap_flags, size )) == ~0U) status = STATUS_NO_MEMORY; else if (block_size >= HEAP_MIN_LARGE_BLOCK_SIZE) @@ -1581,8 +1587,6 @@ BOOLEAN WINAPI DECLSPEC_HOTPATCH RtlFreeHeap( HANDLE handle, ULONG flags, void * if (!(heap = unsafe_heap_from_handle( handle, flags, &heap_flags ))) status = STATUS_INVALID_PARAMETER; - else if (heap->compat_info == HEAP_LFH && !HEAP_lfh_free( heap, heap_flags, ptr )) - status = STATUS_SUCCESS; else if (!(block = unsafe_block_from_ptr( heap, heap_flags, ptr ))) status = STATUS_INVALID_PARAMETER; else if (block_get_flags( block ) & BLOCK_FLAG_LARGE) @@ -1691,8 +1695,6 @@ void *WINAPI RtlReAllocateHeap( HANDLE handle, ULONG flags, void *ptr, SIZE_T si if (!(heap = unsafe_heap_from_handle( handle, flags, &heap_flags ))) status = STATUS_INVALID_HANDLE; - else if (heap->compat_info == HEAP_LFH && !HEAP_lfh_reallocate( heap, heap_flags, ptr, size, &ret )) - status = STATUS_SUCCESS; else if ((block_size = heap_get_block_size( heap, heap_flags, size )) == ~0U) status = STATUS_NO_MEMORY; else if (!(block = unsafe_block_from_ptr( heap, heap_flags, ptr ))) @@ -1810,8 +1812,6 @@ SIZE_T WINAPI RtlSizeHeap( HANDLE handle, ULONG flags, const void *ptr ) if (!(heap = unsafe_heap_from_handle( handle, flags, &heap_flags ))) status = STATUS_INVALID_PARAMETER; - else if (heap->compat_info == HEAP_LFH && !HEAP_lfh_get_allocated_size( heap, heap_flags, ptr, &size )) - status = STATUS_SUCCESS; else if (!(block = unsafe_block_from_ptr( heap, heap_flags, ptr ))) status = STATUS_INVALID_PARAMETER; else @@ -1838,8 +1838,6 @@ BOOLEAN WINAPI RtlValidateHeap( HANDLE handle, ULONG flags, const void *ptr ) if (!(heap = unsafe_heap_from_handle( handle, flags, &heap_flags ))) ret = FALSE; - else if (heap->compat_info == HEAP_LFH && !HEAP_lfh_validate( heap, heap_flags, ptr )) - ret = TRUE; else { heap_lock( heap, heap_flags ); @@ -2059,13 +2057,9 @@ NTSTATUS WINAPI RtlSetHeapInformation( HANDLE handle, HEAP_INFORMATION_CLASS inf if (!(heap = unsafe_heap_from_handle( handle, 0, &heap_flags ))) return STATUS_INVALID_HANDLE; compat_info = *(ULONG *)info; - if (compat_info != HEAP_STD && compat_info != HEAP_LFH) - { - FIXME( "HeapCompatibilityInformation %lu not implemented!\n", compat_info ); - return STATUS_UNSUCCESSFUL; - } - if (!delay_heap_free) - InterlockedCompareExchange( &heap->compat_info, compat_info, HEAP_STD ); + if (compat_info) FIXME( "HeapCompatibilityInformation %lu not implemented!\n", compat_info ); + if (compat_info != HEAP_STD && compat_info != HEAP_LFH) return STATUS_UNSUCCESSFUL; + if (InterlockedCompareExchange( &heap->compat_info, compat_info, HEAP_STD )) return STATUS_UNSUCCESSFUL; return STATUS_SUCCESS; } @@ -2093,8 +2087,6 @@ BOOLEAN WINAPI RtlGetUserInfoHeap( HANDLE handle, ULONG flags, void *ptr, void * if (!(heap = unsafe_heap_from_handle( handle, flags, &heap_flags ))) status = STATUS_SUCCESS; - else if (heap->compat_info == HEAP_LFH && !HEAP_lfh_get_user_info( heap, heap_flags, ptr, user_value, user_flags )) - status = STATUS_SUCCESS; else if (!(block = unsafe_block_from_ptr( heap, heap_flags, ptr ))) { status = STATUS_INVALID_PARAMETER; @@ -2139,8 +2131,6 @@ BOOLEAN WINAPI RtlSetUserValueHeap( HANDLE handle, ULONG flags, void *ptr, void if (!(heap = unsafe_heap_from_handle( handle, flags, &heap_flags ))) ret = TRUE; - else if (heap->compat_info == HEAP_LFH && !HEAP_lfh_set_user_value( heap, heap_flags, ptr, user_value )) - ret = TRUE; else if (!(block = unsafe_block_from_ptr( heap, heap_flags, ptr ))) ret = FALSE; else if (!(block_get_flags( block ) & BLOCK_FLAG_USER_INFO)) @@ -2186,8 +2176,6 @@ BOOLEAN WINAPI RtlSetUserFlagsHeap( HANDLE handle, ULONG flags, void *ptr, ULONG if (!(heap = unsafe_heap_from_handle( handle, flags, &heap_flags ))) ret = TRUE; - else if (heap->compat_info == HEAP_LFH && !HEAP_lfh_set_user_flags( heap, heap_flags, ptr, clear, set )) - ret = TRUE; else if (!(block = unsafe_block_from_ptr( heap, heap_flags, ptr ))) ret = FALSE; else if (!(block_get_flags( block ) & BLOCK_FLAG_USER_INFO)) @@ -2203,5 +2191,4 @@ BOOLEAN WINAPI RtlSetUserFlagsHeap( HANDLE handle, ULONG flags, void *ptr, ULONG void HEAP_notify_thread_destroy( BOOLEAN last ) { - HEAP_lfh_notify_thread_destroy( last ); } diff --git a/dlls/ntdll/heap_lfh.c b/dlls/ntdll/heap_lfh.c deleted file mode 100644 index 41980f491a6..00000000000 --- a/dlls/ntdll/heap_lfh.c +++ /dev/null @@ -1,1228 +0,0 @@ -/* - * Wine Low Fragmentation Heap - * - * Copyright 2020 Remi 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 - */ - -#include "ntstatus.h" -#define WIN32_NO_STATUS - -#include "wine/list.h" -#include "wine/debug.h" - -#include "ntdll_misc.h" - -WINE_DEFAULT_DEBUG_CHANNEL(heap); - -#define ROUND_SIZE(size, mask) ((((SIZE_T)(size) + (mask)) & ~(SIZE_T)(mask))) -#define ALIGNMENT (2 * sizeof(void *)) - -#define BLOCK_FLAG_USER_INFO 0x00000010 /* user flags up to 0xf0 */ -#define BLOCK_FLAG_USER_MASK 0x000000f0 - -#define BLOCK_USER_FLAGS( heap_flags ) (((heap_flags) >> 4) & BLOCK_FLAG_USER_MASK) -#define HEAP_USER_FLAGS( block_flags ) (((block_flags) & BLOCK_FLAG_USER_MASK) << 4) - -typedef struct LFH_ptr LFH_ptr; -typedef struct LFH_block LFH_block; -typedef enum LFH_block_type LFH_block_type; -typedef struct LFH_arena LFH_arena; -typedef struct LFH_class LFH_class; -typedef struct LFH_heap LFH_heap; -typedef struct LFH_slist LFH_slist; - -#define ARENA_HEADER_SIZE (sizeof(LFH_arena)) - -#define LARGE_ARENA_SIZE 0x400000 /* 4MiB */ -#define LARGE_ARENA_MASK (LARGE_ARENA_SIZE - 1) - -#define BLOCK_ARENA_SIZE 0x10000 /* 64kiB */ -#define BLOCK_ARENA_MASK (BLOCK_ARENA_SIZE - 1) - -#define SMALL_CLASS_STEP 0x20 -#define SMALL_CLASS_MASK (SMALL_CLASS_STEP - 1) -#define SMALL_CLASS_MIN_SIZE SMALL_CLASS_STEP -#define SMALL_CLASS_MAX_SIZE 0x800 -#define SMALL_CLASS_COUNT ((SMALL_CLASS_MAX_SIZE - SMALL_CLASS_MIN_SIZE) / SMALL_CLASS_STEP + 1) -#define SMALL_CLASS_FIRST 0 -#define SMALL_CLASS_LAST (SMALL_CLASS_FIRST + SMALL_CLASS_COUNT - 1) - -#define MEDIUM_CLASS_STEP (16 * SMALL_CLASS_STEP) -#define MEDIUM_CLASS_MASK (MEDIUM_CLASS_STEP - 1) -#define MEDIUM_CLASS_MIN_SIZE SMALL_CLASS_MAX_SIZE -#define MEDIUM_CLASS_MAX_SIZE ((BLOCK_ARENA_SIZE - ARENA_HEADER_SIZE - ARENA_HEADER_SIZE) / 2) -#define MEDIUM_CLASS_COUNT ((MEDIUM_CLASS_MAX_SIZE - MEDIUM_CLASS_MIN_SIZE + MEDIUM_CLASS_MASK) / MEDIUM_CLASS_STEP + 1) -#define MEDIUM_CLASS_FIRST (SMALL_CLASS_LAST + 1) -#define MEDIUM_CLASS_LAST (MEDIUM_CLASS_FIRST + MEDIUM_CLASS_COUNT - 1) - -#define LARGE_CLASS_STEP BLOCK_ARENA_SIZE -#define LARGE_CLASS_MASK (LARGE_CLASS_STEP - 1) -#define LARGE_CLASS_MIN_SIZE (BLOCK_ARENA_SIZE - ARENA_HEADER_SIZE) -#define LARGE_CLASS_MAX_SIZE (LARGE_ARENA_SIZE / 2 - ARENA_HEADER_SIZE) /* we need an arena header for every large block */ -#define LARGE_CLASS_COUNT ((LARGE_CLASS_MAX_SIZE - LARGE_CLASS_MIN_SIZE) / LARGE_CLASS_STEP + 1) -#define LARGE_CLASS_FIRST 0 -#define LARGE_CLASS_LAST (LARGE_CLASS_FIRST + LARGE_CLASS_COUNT - 1) - -#define TOTAL_BLOCK_CLASS_COUNT (MEDIUM_CLASS_LAST + 1) -#define TOTAL_LARGE_CLASS_COUNT (LARGE_CLASS_LAST + 1) - -struct LFH_slist -{ - LFH_slist *next; -}; - -static inline void LFH_slist_push(LFH_slist **list, LFH_slist *entry) -{ - /* There will be no ABA issue here, other threads can only replace - * list->next with a different entry, or NULL. */ - entry->next = __atomic_load_n(list, __ATOMIC_RELAXED); - while (!__atomic_compare_exchange_n(list, &entry->next, entry, 0, __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)); -} - -static inline LFH_slist *LFH_slist_flush(LFH_slist **list) -{ - if (!__atomic_load_n(list, __ATOMIC_RELAXED)) return NULL; - return __atomic_exchange_n(list, NULL, __ATOMIC_ACQUIRE); -} - -/* be sure to keep these different from ARENA_INUSE magic */ -enum LFH_block_type -{ - LFH_block_type_used = 0xa55a5aa5, - LFH_block_type_free = 0xc33c3cc3, -}; - -struct DECLSPEC_ALIGN(16) LFH_block -{ - union - { - ssize_t next_free; - LFH_slist entry_defer; - size_t alloc_size; - }; - - UINT32 flags; - LFH_block_type type; -}; - -C_ASSERT(sizeof(LFH_block) == 0x10); -C_ASSERT(offsetof(LFH_block, entry_defer) == 0); - -struct DECLSPEC_ALIGN(16) LFH_arena -{ - ssize_t next_free; - LFH_arena *class_entry; - - union - { - LFH_arena *parent; - LFH_class *class; - }; - - union - { - size_t huge_size; - size_t used_count; - }; -}; - -#ifdef _WIN64 -C_ASSERT(sizeof(LFH_arena) == 0x20); -#else -C_ASSERT(sizeof(LFH_arena) == 0x10); -#endif - -struct LFH_class -{ - LFH_arena *next; - size_t size; -}; - -struct LFH_heap -{ - LFH_slist *list_defer; - LFH_arena *cached_large_arena; - - LFH_class block_class[TOTAL_BLOCK_CLASS_COUNT]; - LFH_class large_class[TOTAL_LARGE_CLASS_COUNT]; - - SLIST_ENTRY entry_orphan; -#ifdef _WIN64 - void *pad[0xc2]; -#else - void *pad[0xc3]; -#endif -}; - -C_ASSERT(TOTAL_BLOCK_CLASS_COUNT == 0x7d); -C_ASSERT(TOTAL_LARGE_CLASS_COUNT == 0x20); - -/* arena->class/arena->parent pointer low bits are used to discriminate between the two */ -C_ASSERT(offsetof(LFH_heap, block_class[0]) > 0); -C_ASSERT(offsetof(LFH_heap, large_class[TOTAL_LARGE_CLASS_COUNT]) < BLOCK_ARENA_SIZE); - -/* helpers to retrieve parent arena from a child, or class pointer from a large or block arena */ -static inline LFH_arena *LFH_parent_from_arena(const LFH_arena *arena) -{ - if (!arena->parent) return (LFH_arena *)arena; - if (!((UINT_PTR)(arena)->parent & BLOCK_ARENA_MASK)) return arena->parent; - return (LFH_arena *)arena; -} - -static inline LFH_class *LFH_class_from_arena(const LFH_arena *arena) -{ - const LFH_arena *parent = LFH_parent_from_arena(arena); - if ((UINT_PTR)parent->class & BLOCK_ARENA_MASK) return parent->class; - return NULL; -} - -/* make sure its aligns to power of two so we can mask class pointers in LFH_heap_from_arena */ -#ifdef _WIN64 -C_ASSERT(sizeof(LFH_heap) == 0x1000); -#else -C_ASSERT(sizeof(LFH_heap) == 0x800); -#endif - -/* helper to retrieve the heap from an arena, using its class pointer */ -static inline LFH_heap *LFH_heap_from_arena(const LFH_arena *arena) -{ - LFH_class *class = LFH_class_from_arena(arena); - return (LFH_heap *)((UINT_PTR)class & ~(sizeof(LFH_heap) - 1)); -} - -/* helpers to retrieve block pointers to the containing block or large (maybe child) arena */ -static inline LFH_arena *LFH_large_arena_from_block(const LFH_block *block) -{ - return (LFH_arena *)((UINT_PTR)block & ~BLOCK_ARENA_MASK); -} - -static inline LFH_arena *LFH_block_arena_from_block(const LFH_block *block) -{ - return LFH_large_arena_from_block(block) + 1; -} - -static inline LFH_arena *LFH_arena_from_block(const LFH_block *block) -{ - LFH_arena *block_arena = LFH_block_arena_from_block(block); - if (block_arena == (LFH_arena *)block) return LFH_large_arena_from_block(block); - return block_arena; -} - -/* helpers to translate between data pointer and LFH_block header */ -static inline LFH_block *LFH_block_from_ptr(const LFH_ptr *ptr) -{ - return ((LFH_block *)ptr) - 1; -} - -static inline void *LFH_ptr_from_block(const LFH_block *block) -{ - return (LFH_ptr *)(block + 1); -} - -static inline size_t LFH_block_get_class_size(const LFH_block *block) -{ - const LFH_arena *arena = LFH_arena_from_block(block); - const LFH_class *class = LFH_class_from_arena(arena); - if (class) return class->size; - return arena->huge_size; -} - -static inline size_t LFH_block_get_alloc_size(const LFH_block *block, ULONG flags) -{ - return block->alloc_size; -} - -static inline size_t LFH_get_class_size(ULONG flags, size_t size) -{ - static const ULONG padd_flags = HEAP_VALIDATE | HEAP_VALIDATE_ALL | HEAP_VALIDATE_PARAMS | HEAP_ADD_USER_INFO; - static const ULONG check_flags = HEAP_TAIL_CHECKING_ENABLED | HEAP_FREE_CHECKING_ENABLED | HEAP_CHECKING_ENABLED; - SIZE_T overhead; - - if ((flags & check_flags)) overhead = ALIGNMENT; - else overhead = sizeof(LFH_block); - - if (flags & HEAP_TAIL_CHECKING_ENABLED) overhead += ALIGNMENT; - if (flags & padd_flags) overhead += ALIGNMENT; - - if (size < ALIGNMENT) size = ALIGNMENT; - return ROUND_SIZE( size + overhead, ALIGNMENT - 1 ); -} - -static inline void *LFH_memory_allocate(size_t size) -{ - void *addr = NULL; - SIZE_T alloc_size = size; - - if (NtAllocateVirtualMemory(NtCurrentProcess(), (void **)&addr, 0, &alloc_size, - MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)) - return NULL; - - return addr; -} - -static inline BOOLEAN LFH_memory_deallocate(void *addr, size_t size) -{ - SIZE_T release_size = 0; - - if (NtFreeVirtualMemory(NtCurrentProcess(), &addr, &release_size, MEM_RELEASE)) - return FALSE; - - return TRUE; -} - -static inline LFH_block *LFH_arena_get_block(const LFH_arena *arena, size_t offset) -{ - return (LFH_block *)((UINT_PTR)arena + offset); -} - -static inline void LFH_arena_push_block(LFH_arena *arena, LFH_block *block) -{ - block->flags = 0; - block->type = LFH_block_type_free; - block->next_free = arena->next_free; - arena->next_free = (UINT_PTR)block - (UINT_PTR)arena; - arena->used_count--; -} - -static inline LFH_block *LFH_arena_pop_block(LFH_arena *arena) -{ - if (arena->next_free > 0) - { - LFH_block *block = LFH_arena_get_block(arena, arena->next_free); - arena->next_free = block->next_free; - arena->used_count++; - return block; - } - else - { - LFH_arena *child, *large_arena = LFH_large_arena_from_block((LFH_block *)arena); - LFH_class *class = LFH_class_from_arena(arena); - LFH_block *block = LFH_arena_get_block(arena, -arena->next_free); - ssize_t extra = 0, limit; - - if (arena == large_arena) - { - extra = ARENA_HEADER_SIZE; - limit = LARGE_ARENA_SIZE; - child = LFH_large_arena_from_block(block); - if (arena != child) child->parent = arena; - } - else limit = LFH_class_from_arena(large_arena)->size; - - arena->next_free -= class->size + extra; - if (-arena->next_free > limit - class->size) - arena->next_free = 0; - - arena->used_count++; - return block; - } -} - -static inline int LFH_arena_is_empty(LFH_arena *arena) -{ - return arena->next_free == 0; -} - -static inline int LFH_arena_is_used(LFH_arena *arena) -{ - return arena->used_count > 0; -} - -static inline int LFH_class_is_block(LFH_heap *heap, LFH_class *class) -{ - return class >= heap->block_class && class < (heap->block_class + TOTAL_BLOCK_CLASS_COUNT); -} - -static void LFH_class_initialize(LFH_heap *heap, LFH_class *class, size_t index) -{ - class->next = NULL; - - if (LFH_class_is_block(heap, class)) - { - if (index <= SMALL_CLASS_LAST) - class->size = min(SMALL_CLASS_MIN_SIZE + SMALL_CLASS_STEP * (index - SMALL_CLASS_FIRST), SMALL_CLASS_MAX_SIZE); - else - class->size = min(MEDIUM_CLASS_MIN_SIZE + MEDIUM_CLASS_STEP * (index - MEDIUM_CLASS_FIRST), MEDIUM_CLASS_MAX_SIZE); - } - else - { - class->size = min(LARGE_CLASS_MIN_SIZE + LARGE_CLASS_STEP * (index - LARGE_CLASS_FIRST), LARGE_CLASS_MAX_SIZE); - } -} - -static inline LFH_arena *LFH_class_pop_arena(LFH_class *class) -{ - LFH_arena *arena = class->next; - if (!arena) return NULL; - class->next = arena->class_entry; - return arena; -} - -static inline void LFH_class_remove_arena(LFH_class *class, LFH_arena *arena) -{ - LFH_arena **next = &class->next; - while (*next != arena) next = &(*next)->class_entry; - *next = arena->class_entry; -} - -static inline LFH_arena *LFH_class_peek_arena(LFH_class *class) -{ - return class->next; -} - -static inline void LFH_class_push_arena(LFH_class *class, LFH_arena *arena) -{ - arena->class_entry = class->next; - class->next = arena; -} - -static inline LFH_class *LFH_heap_get_class(LFH_heap *heap, size_t size) -{ - if (size == 0) - return &heap->block_class[0]; - else if (size <= SMALL_CLASS_MAX_SIZE) - return &heap->block_class[SMALL_CLASS_FIRST + (size + SMALL_CLASS_MASK - SMALL_CLASS_MIN_SIZE) / SMALL_CLASS_STEP]; - else if (size <= MEDIUM_CLASS_MAX_SIZE) - return &heap->block_class[MEDIUM_CLASS_FIRST + (size + MEDIUM_CLASS_MASK - MEDIUM_CLASS_MIN_SIZE) / MEDIUM_CLASS_STEP]; - else if (size <= LARGE_CLASS_MAX_SIZE) - return &heap->large_class[LARGE_CLASS_FIRST + (size + LARGE_CLASS_MASK - LARGE_CLASS_MIN_SIZE) / LARGE_CLASS_STEP]; - else - return NULL; -} - -static void LFH_arena_initialize(LFH_heap *heap, LFH_class *class, LFH_arena *arena, size_t huge_size) -{ - arena->class = class; - arena->next_free = -ARENA_HEADER_SIZE; - - if (class == NULL) - arena->huge_size = huge_size; - else - arena->used_count = 0; -} - -static LFH_arena *LFH_acquire_arena(LFH_heap *heap, LFH_class *class); -static BOOLEAN LFH_release_arena(LFH_heap *heap, LFH_arena *arena); - -static inline LFH_block *LFH_allocate_block(LFH_heap *heap, LFH_class *class, LFH_arena *arena); -static inline BOOLEAN LFH_deallocate_block(LFH_heap *heap, LFH_arena *arena, LFH_block *block); - -static inline BOOLEAN LFH_deallocate_deferred_blocks(LFH_heap *heap) -{ - LFH_slist *entry = LFH_slist_flush(&heap->list_defer); - - while (entry) - { - LFH_block *block = LIST_ENTRY(entry, LFH_block, entry_defer); - entry = entry->next; - - if (!LFH_deallocate_block(heap, LFH_arena_from_block(block), block)) - return FALSE; - } - - return TRUE; -} - -static inline void LFH_deallocated_cached_arenas(LFH_heap *heap) -{ - if (!heap->cached_large_arena) return; - LFH_memory_deallocate(heap->cached_large_arena, LARGE_ARENA_SIZE); - heap->cached_large_arena = NULL; -} - -static inline size_t LFH_huge_alloc_size(size_t size) -{ - return (ARENA_HEADER_SIZE + size + BLOCK_ARENA_MASK) & ~BLOCK_ARENA_MASK; -} - -static inline LFH_arena *LFH_allocate_huge_arena(LFH_heap *heap, size_t size) -{ - LFH_arena *arena; - size_t alloc_size = LFH_huge_alloc_size(size); - if (alloc_size < size) return NULL; - - if ((arena = LFH_memory_allocate(alloc_size))) - LFH_arena_initialize(heap, NULL, arena, size); - - return arena; -} - -static inline LFH_arena *LFH_allocate_large_arena(LFH_heap *heap, LFH_class *class) -{ - LFH_arena *arena; - - if ((arena = heap->cached_large_arena) || - (arena = LFH_memory_allocate(LARGE_ARENA_SIZE))) - { - heap->cached_large_arena = NULL; - LFH_arena_initialize(heap, class, arena, 0); - LFH_class_push_arena(class, arena); - } - - return arena; -} - -static inline LFH_arena *LFH_allocate_block_arena(LFH_heap *heap, LFH_class *large_class, LFH_class *block_class) -{ - LFH_arena *large_arena; - LFH_arena *arena = NULL; - - if ((large_arena = LFH_acquire_arena(heap, large_class))) - { - arena = (LFH_arena *)LFH_allocate_block(heap, large_class, large_arena); - LFH_arena_initialize(heap, block_class, arena, 0); - LFH_class_push_arena(block_class, arena); - } - - return arena; -} - -static inline LFH_arena *LFH_acquire_arena(LFH_heap *heap, LFH_class *class) -{ - LFH_arena *arena; - - if (!(arena = LFH_class_peek_arena(class))) - { - if (LFH_class_is_block(heap, class)) - arena = LFH_allocate_block_arena(heap, &heap->large_class[0], class); - else - arena = LFH_allocate_large_arena(heap, class); - } - - return arena; -} - -static inline BOOLEAN LFH_release_arena(LFH_heap *heap, LFH_arena *arena) -{ - LFH_arena *large_arena = LFH_large_arena_from_block((LFH_block *)arena); - if (arena == large_arena && !heap->cached_large_arena) - { - heap->cached_large_arena = arena; - return TRUE; - } - else if (arena == large_arena) - return LFH_memory_deallocate(arena, LARGE_ARENA_SIZE); - else - return LFH_deallocate_block(heap, large_arena, (LFH_block *)arena); -}; - -static inline LFH_block *LFH_allocate_block(LFH_heap *heap, LFH_class *class, LFH_arena *arena) -{ - LFH_block *block = LFH_arena_pop_block(arena); - if (LFH_arena_is_empty(arena)) - LFH_class_pop_arena(class); - return block; -} - -static inline BOOLEAN LFH_deallocate_block(LFH_heap *heap, LFH_arena *arena, LFH_block *block) -{ - LFH_class *class = LFH_class_from_arena(arena); - - arena = LFH_parent_from_arena(arena); - if (LFH_arena_is_empty(arena)) - LFH_class_push_arena(class, arena); - - LFH_arena_push_block(arena, block); - if (LFH_arena_is_used(arena)) - return TRUE; - - LFH_class_remove_arena(class, arena); - return LFH_release_arena(heap, arena); -} - -static void LFH_heap_initialize(LFH_heap *heap) -{ - size_t i; - - for (i = 0; i < TOTAL_LARGE_CLASS_COUNT; ++i) - LFH_class_initialize(heap, &heap->large_class[i], i); - for (i = 0; i < TOTAL_BLOCK_CLASS_COUNT; ++i) - LFH_class_initialize(heap, &heap->block_class[i], i); - - heap->list_defer = NULL; - heap->cached_large_arena = NULL; -} - -static SLIST_HEADER *LFH_orphan_list(void) -{ - static SLIST_HEADER *header; - SLIST_HEADER *ptr, *expected = NULL; - LFH_heap *tmp; - - C_ASSERT(sizeof(LFH_heap) >= sizeof(SLIST_HEADER)); - - if ((ptr = __atomic_load_n(&header, __ATOMIC_RELAXED))) - return ptr; - - if (!(ptr = LFH_memory_allocate(BLOCK_ARENA_SIZE))) - return NULL; - - RtlInitializeSListHead(ptr); - for (tmp = (LFH_heap *)ptr + 1; tmp < (LFH_heap *)ptr + BLOCK_ARENA_SIZE / sizeof(*tmp); tmp++) - { - LFH_heap_initialize(tmp); - RtlInterlockedPushEntrySList(ptr, &tmp->entry_orphan); - } - - if (__atomic_compare_exchange_n(&header, &expected, ptr, 0, __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) - return ptr; - - LFH_memory_deallocate(ptr, BLOCK_ARENA_SIZE); - return expected; -} - -static void LFH_heap_finalize(LFH_heap *heap) -{ - LFH_arena *arena; - - LFH_deallocate_deferred_blocks(heap); - - for (size_t i = 0; i < TOTAL_BLOCK_CLASS_COUNT; ++i) - { - while ((arena = LFH_class_pop_arena(&heap->block_class[i]))) - { - WARN("block arena %p still has used blocks\n", arena); - LFH_release_arena(heap, arena); - } - } - - for (size_t i = 0; i < TOTAL_LARGE_CLASS_COUNT; ++i) - { - while ((arena = LFH_class_pop_arena(&heap->large_class[i]))) - { - WARN("large arena %p still has used blocks\n", arena); - LFH_memory_deallocate(arena, LARGE_ARENA_SIZE); - } - } - - LFH_deallocated_cached_arenas(heap); -} - -static LFH_heap *LFH_heap_allocate(void) -{ - SLIST_HEADER *list_orphan = LFH_orphan_list(); - LFH_heap *heap, *tmp; - - heap = LFH_memory_allocate(BLOCK_ARENA_SIZE); - if (!heap) - return NULL; - - for (tmp = heap + 1; tmp < heap + BLOCK_ARENA_SIZE / sizeof(*tmp); tmp++) - { - LFH_heap_initialize(tmp); - RtlInterlockedPushEntrySList(list_orphan, &tmp->entry_orphan); - } - - LFH_heap_initialize(heap); - return heap; -} - -static LFH_heap *LFH_create_thread_heap(void) -{ - SLIST_ENTRY *entry; - LFH_heap *heap; - - if ((entry = RtlInterlockedPopEntrySList(LFH_orphan_list()))) - heap = LIST_ENTRY(entry, LFH_heap, entry_orphan); - else - heap = LFH_heap_allocate(); - - return (NtCurrentTeb()->Reserved5[2] = heap); -} - -static inline LFH_heap *LFH_thread_heap(BOOL create) -{ - LFH_heap *heap = (LFH_heap *)NtCurrentTeb()->Reserved5[2]; - if (!heap && create) return LFH_create_thread_heap(); - return heap; -} - -static void LFH_dump_arena(LFH_heap *heap, LFH_class *class, LFH_arena *arena) -{ - LFH_arena *large_arena = LFH_large_arena_from_block((LFH_block *)arena); - LFH_arena *block_arena = LFH_block_arena_from_block((LFH_block *)arena); - - if (arena == block_arena) - WARN(" block arena: %p-%p", arena, (void *)((UINT_PTR)large_arena + BLOCK_ARENA_SIZE - 1)); - else if (arena == large_arena) - WARN(" large arena: %p-%p", arena, (void *)((UINT_PTR)large_arena + LARGE_ARENA_SIZE - 1)); - - WARN(" heap: %p class: %p parent: %p free: %Id used: %Id\n", - LFH_heap_from_arena(arena), LFH_class_from_arena(arena), LFH_parent_from_arena(arena), arena->next_free, arena->used_count); -} - -static void LFH_dump_class(LFH_heap *heap, LFH_class *class) -{ - LFH_arena *arena = class->next; - if (!arena) return; - - if (LFH_class_is_block(heap, class)) - WARN(" block class: %p size: %Ix\n", class, class->size); - else - WARN(" large class: %p size: %Ix\n", class, class->size); - - while (arena) - { - LFH_dump_arena(heap, class, arena); - arena = arena->class_entry; - } -} - -static void LFH_dump_heap(LFH_heap *heap) -{ - size_t i; - - WARN("heap: %p\n", heap); - - for (i = 0; i < TOTAL_BLOCK_CLASS_COUNT; ++i) - LFH_dump_class(heap, &heap->block_class[i]); - - for (i = 0; i < TOTAL_LARGE_CLASS_COUNT; ++i) - LFH_dump_class(heap, &heap->large_class[i]); -} - -static BOOLEAN LFH_validate_arena(ULONG flags, const LFH_arena *arena); -static BOOLEAN LFH_validate_heap(ULONG flags, const LFH_heap *heap); - -static inline BOOLEAN LFH_validate_block(ULONG flags, const LFH_block *block) -{ - const LFH_arena *arena = LFH_arena_from_block(block); - const LFH_arena *large_arena = LFH_large_arena_from_block(block); - const LFH_arena *block_arena = LFH_block_arena_from_block(block); - const LFH_arena *arena_arena = LFH_large_arena_from_block((LFH_block *)arena); - const char *err = NULL; - - if (flags & HEAP_VALIDATE) - return LFH_validate_arena(flags, arena); - - if (!arena) - err = "invalid arena"; - else if (arena != arena_arena && arena != (arena_arena + 1)) - err = "invalid arena alignment"; - else if (arena == block_arena) - { - if ((UINT_PTR)block < (UINT_PTR)block_arena + ARENA_HEADER_SIZE) - err = "invalid block alignment"; - if (((UINT_PTR)block & (sizeof(*block) - 1))) - err = "invalid block alignment"; - } - else if (arena != large_arena) - err = "large/huge arena mismatch"; - else if ((UINT_PTR)block != (UINT_PTR)block_arena) - err = "invalid block for large/huge arena"; - - if (err) WARN("%08lx %p: %s\n", flags, block, err); - return err == NULL; -} - -static BOOLEAN LFH_validate_free_block(ULONG flags, const LFH_block *block) -{ - const char *err = NULL; - - if (!LFH_validate_block(flags, block)) - return FALSE; - if (block->type != LFH_block_type_free) - err = "invalid free block type"; - - if (err) WARN("%08lx %p: %s\n", flags, block, err); - return err == NULL; -} - -static BOOLEAN LFH_validate_defer_block(ULONG flags, const LFH_block *block) -{ - const char *err = NULL; - - if (!LFH_validate_block(flags, block)) - return FALSE; - if (block->type != LFH_block_type_free) - err = "invalid defer block type"; - else if (flags & HEAP_FREE_CHECKING_ENABLED) - { - const unsigned int *data = (const unsigned int *)LFH_ptr_from_block(block); - size_t class_size = LFH_block_get_class_size(block); - for (size_t i = 0; i < class_size / 4 - (data - (const unsigned int *)block) && !err; ++i) - if (data[i] != 0xfeeefeee) err = "invalid free filler"; - } - - if (err) WARN("%08lx %p: %s\n", flags, block, err); - return err == NULL; -} - -static inline BOOLEAN LFH_validate_used_block(ULONG flags, const LFH_block *block) -{ - const char *err = NULL; - - if (!LFH_validate_block(flags, block)) - return FALSE; - if (block->type != LFH_block_type_used) - err = "invalid used block type"; - else if (flags & HEAP_TAIL_CHECKING_ENABLED) - { - const unsigned char *data = (const unsigned char *)LFH_ptr_from_block(block); - size_t alloc_size = LFH_block_get_alloc_size(block, flags); - for (size_t i = alloc_size; i < alloc_size + ALIGNMENT && !err; ++i) - if (data[i] != 0xab) err = "invalid tail filler"; - } - - if (err) WARN("%08lx %p: %s\n", flags, block, err); - return err == NULL; -} - -static BOOLEAN LFH_validate_arena_free_blocks(ULONG flags, const LFH_arena *arena) -{ - ssize_t offset = arena->next_free; - while (offset > 0) - { - LFH_block *block = LFH_arena_get_block(arena, offset); - if (!LFH_validate_free_block(flags, block)) - return FALSE; - offset = block->next_free; - } - - return TRUE; -} - -static BOOLEAN LFH_validate_arena(ULONG flags, const LFH_arena *arena) -{ - const char *err = NULL; - const LFH_arena *parent; - const LFH_arena *block_arena = LFH_block_arena_from_block((LFH_block *)arena); - const LFH_arena *large_arena = LFH_large_arena_from_block((LFH_block *)arena); - - if (flags & HEAP_VALIDATE) - return LFH_validate_heap(flags, LFH_heap_from_arena(arena)); - - if (arena != large_arena && arena != block_arena) - err = "invalid arena alignment"; - else if (arena == block_arena) - { - if (!LFH_validate_block(flags, (LFH_block *)arena)) - err = "invalid block arena"; - else if (!LFH_validate_arena_free_blocks(flags, arena)) - err = "invalid block arena free list"; - } - else if (arena == large_arena && !LFH_class_from_arena(arena)) - { - if (arena->huge_size <= LARGE_CLASS_MAX_SIZE) - err = "invalid huge arena size"; - } - else if (arena == large_arena && (parent = LFH_parent_from_arena(arena)) != arena) - { - if (arena > parent || LFH_large_arena_from_block((LFH_block *)parent) != parent) - err = "invalid child arena parent"; - } - else - { - if (!LFH_validate_arena_free_blocks(flags, arena)) - err = "invalid large arena free list"; - } - - if (err) WARN("%08lx %p: %s\n", flags, arena, err); - return err == NULL; -} - -static BOOLEAN LFH_validate_class_arenas(ULONG flags, const LFH_class *class) -{ - LFH_arena *arena = class->next; - while (arena) - { - if (!LFH_validate_arena(flags, arena)) - return FALSE; - - arena = arena->class_entry; - } - - return TRUE; -} - -static BOOLEAN LFH_validate_heap_defer_blocks(ULONG flags, const LFH_heap *heap) -{ - const LFH_slist *entry = heap->list_defer; - - while (entry) - { - const LFH_block *block = LIST_ENTRY(entry, LFH_block, entry_defer); - if (!LFH_validate_defer_block(flags, block)) - return FALSE; - entry = entry->next; - } - - return TRUE; -} - -static BOOLEAN LFH_validate_heap(ULONG flags, const LFH_heap *heap) -{ - const char *err = NULL; - UINT i; - - flags &= ~HEAP_VALIDATE; - - if (heap != LFH_thread_heap(FALSE)) - err = "unable to validate foreign heap"; - else if (!LFH_validate_heap_defer_blocks(flags, heap)) - err = "invalid heap defer blocks"; - else - { - for (i = 0; err == NULL && i < TOTAL_BLOCK_CLASS_COUNT; ++i) - { - if (!LFH_validate_class_arenas(flags, &heap->block_class[i])) - return FALSE; - } - - for (i = 0; err == NULL && i < TOTAL_LARGE_CLASS_COUNT; ++i) - { - if (!LFH_validate_class_arenas(flags, &heap->large_class[i])) - return FALSE; - } - } - - if (err) WARN("%08lx %p: %s\n", flags, heap, err); - return err == NULL; -} - -static inline void LFH_block_initialize(LFH_block *block, ULONG flags, size_t old_size, size_t new_size, size_t class_size) -{ - char *ptr = (char *)LFH_ptr_from_block(block); - - TRACE("block %p, flags %08lx, old_size %Ix, new_size %Ix, class_size %Ix, ptr %p\n", block, flags, old_size, new_size, class_size, ptr); - - if ((flags & HEAP_ZERO_MEMORY) && new_size > old_size) - memset(ptr + old_size, 0, new_size - old_size); - else if ((flags & HEAP_FREE_CHECKING_ENABLED) && new_size > old_size && class_size < BLOCK_ARENA_SIZE) - memset(ptr + old_size, 0x55, new_size - old_size); - - if ((flags & HEAP_TAIL_CHECKING_ENABLED)) - memset(ptr + new_size, 0xab, class_size - new_size - (ptr - (char *)block)); - - block->flags = BLOCK_USER_FLAGS( flags ); - block->type = LFH_block_type_used; - block->alloc_size = new_size; -} - -static FORCEINLINE LFH_ptr *LFH_allocate(ULONG flags, size_t size) -{ - LFH_block *block = NULL; - LFH_class *class; - LFH_arena *arena; - LFH_heap *heap = LFH_thread_heap(TRUE); - size_t class_size = LFH_get_class_size(flags, size); - - if (class_size == ~(size_t)0) - return NULL; - - if (!LFH_deallocate_deferred_blocks(heap)) - return NULL; - - if ((class = LFH_heap_get_class(heap, class_size))) - { - arena = LFH_acquire_arena(heap, class); - if (arena) block = LFH_allocate_block(heap, class, arena); - if (block) LFH_block_initialize(block, flags, 0, size, LFH_block_get_class_size(block)); - } - else - { - arena = LFH_allocate_huge_arena(heap, class_size); - if (arena) block = LFH_arena_get_block(arena, ARENA_HEADER_SIZE); - if (block) LFH_block_initialize(block, flags & ~HEAP_ZERO_MEMORY, 0, size, LFH_block_get_class_size(block)); - } - - LFH_deallocated_cached_arenas(heap); - - if (!block) return NULL; - return LFH_ptr_from_block(block); -} - -static FORCEINLINE BOOLEAN LFH_free(ULONG flags, LFH_ptr *ptr) -{ - LFH_block *block = LFH_block_from_ptr(ptr); - LFH_arena *arena = LFH_arena_from_block(block); - LFH_heap *heap = LFH_heap_from_arena(arena); - - if (!LFH_class_from_arena(arena)) - return LFH_memory_deallocate(arena, LFH_block_get_class_size(block)); - - if (flags & HEAP_FREE_CHECKING_ENABLED) - { - unsigned int *data = (unsigned int *)LFH_ptr_from_block(block); - size_t class_size = LFH_block_get_class_size(block); - for (size_t i = 0; i < class_size / 4 - (data - (const unsigned int *)block); ++i) - data[i] = 0xfeeefeee; - } - - block->flags = 0; - block->type = LFH_block_type_free; - - if (heap == LFH_thread_heap(FALSE) && !(flags & HEAP_FREE_CHECKING_ENABLED)) - LFH_deallocate_block(heap, LFH_arena_from_block(block), block); - else - LFH_slist_push(&heap->list_defer, &block->entry_defer); - - return TRUE; -} - -static FORCEINLINE LFH_ptr *LFH_reallocate(ULONG flags, LFH_ptr *old_ptr, size_t new_size) -{ - LFH_block *block = LFH_block_from_ptr(old_ptr); - LFH_arena *arena = LFH_arena_from_block(block); - LFH_heap *heap = LFH_heap_from_arena(arena); - size_t old_size = LFH_block_get_alloc_size(block, flags); - size_t old_class_size = LFH_block_get_class_size(block); - size_t new_class_size = LFH_get_class_size(flags, new_size); - LFH_class *new_class, *old_class = LFH_class_from_arena(arena); - LFH_ptr *new_ptr = NULL; - - if (new_class_size == ~(size_t)0) - return NULL; - - if (new_class_size <= old_class_size) - goto in_place; - - if ((new_class = LFH_heap_get_class(heap, new_class_size)) && new_class == old_class) - goto in_place; - - old_class_size = LFH_huge_alloc_size(old_class_size); - new_class_size = LFH_huge_alloc_size(new_class_size); - if (!new_class && !old_class && old_class_size == new_class_size) - goto in_place; - - if (flags & HEAP_REALLOC_IN_PLACE_ONLY) - return NULL; - - if (!(new_ptr = LFH_allocate(flags, new_size))) - return NULL; - - memcpy(new_ptr, old_ptr, old_size); - - if (LFH_free(flags, old_ptr)) - return new_ptr; - - LFH_free(flags, new_ptr); - return NULL; - -in_place: - LFH_block_initialize(block, flags, old_size, new_size, old_class_size); - return old_ptr; -} - -static inline size_t LFH_get_allocated_size(ULONG flags, const LFH_ptr *ptr) -{ - const LFH_block *block = LFH_block_from_ptr(ptr); - return LFH_block_get_alloc_size(block, flags); -} - -static inline BOOLEAN LFH_validate(ULONG flags, const LFH_ptr *ptr) -{ - const LFH_block *block = LFH_block_from_ptr(ptr); - const LFH_heap *heap; - - /* clear HEAP_VALIDATE so we only validate block */ - if (ptr) - return LFH_validate_used_block(flags & ~HEAP_VALIDATE, block); - - if (!(heap = LFH_thread_heap(FALSE))) - return TRUE; - - return LFH_validate_heap(flags, heap); -} - -static inline void LFH_get_user_info( ULONG flags, void *ptr, void **user_value, ULONG *user_flags ) -{ - LFH_block *block = LFH_block_from_ptr(ptr); - void **tmp; - - if (!(*user_flags = HEAP_USER_FLAGS( block->flags ))) return; - - tmp = (void **)((char *)block + LFH_block_get_class_size( block ) - ALIGNMENT); - *user_flags = *user_flags & ~HEAP_ADD_USER_INFO; - *user_value = tmp[1]; -} - -static inline void LFH_set_user_value( ULONG flags, void *ptr, void *user_value ) -{ - LFH_block *block = LFH_block_from_ptr(ptr); - void **tmp; - - if (!(block->flags & BLOCK_FLAG_USER_INFO)) return; - - tmp = (void **)((char *)block + LFH_block_get_class_size( block ) - ALIGNMENT); - tmp[1] = user_value; -} - -static inline void LFH_set_user_flags( ULONG flags, void *ptr, ULONG clear, ULONG set ) -{ - LFH_block *block = LFH_block_from_ptr(ptr); - - if (!(block->flags & BLOCK_FLAG_USER_INFO)) return; - - block->flags &= ~BLOCK_USER_FLAGS( clear ); - block->flags |= BLOCK_USER_FLAGS( set ); -} - -static inline BOOLEAN LFH_try_validate_all(ULONG flags) -{ - if (!(flags & HEAP_VALIDATE_ALL)) - return TRUE; - - if (LFH_validate(flags, NULL)) - return TRUE; - - LFH_dump_heap(LFH_thread_heap(FALSE)); - return FALSE; -} - -NTSTATUS HEAP_lfh_allocate(HANDLE heap, ULONG flags, SIZE_T size, void **out) -{ - TRACE("heap %p, flags %08lx, size %Ix, out %p.\n", heap, flags, size, out); - - if (!LFH_try_validate_all(flags)) - return STATUS_INVALID_PARAMETER; - - if (!(*out = LFH_allocate(flags, size))) - return STATUS_NO_MEMORY; - - return STATUS_SUCCESS; -} - -NTSTATUS HEAP_lfh_free(HANDLE heap, ULONG flags, void *ptr) -{ - TRACE("heap %p, flags %08lx, ptr %p.\n", heap, flags, ptr); - - if (!LFH_try_validate_all(flags)) - return STATUS_INVALID_PARAMETER; - - if (!LFH_validate(flags, ptr)) - return STATUS_INVALID_PARAMETER; - - if (!LFH_free(flags, ptr)) - return STATUS_INVALID_PARAMETER; - - return STATUS_SUCCESS; -} - -NTSTATUS HEAP_lfh_reallocate(HANDLE heap, ULONG flags, void *ptr, SIZE_T size, void **out) -{ - TRACE("heap %p, flags %08lx, ptr %p, size %Ix, out %p.\n", heap, flags, ptr, size, out); - - if (!LFH_try_validate_all(flags)) - return STATUS_INVALID_PARAMETER; - - if (!LFH_validate(flags, ptr)) - return STATUS_INVALID_PARAMETER; - - if (!(*out = LFH_reallocate(flags, ptr, size))) - return STATUS_NO_MEMORY; - - return STATUS_SUCCESS; -} - -NTSTATUS HEAP_lfh_get_allocated_size(HANDLE heap, ULONG flags, const void *ptr, SIZE_T* out) -{ - TRACE("heap %p, flags %08lx, ptr %p, out %p.\n", heap, flags, ptr, out); - - if (!LFH_try_validate_all(flags)) - return STATUS_INVALID_PARAMETER; - - if (!LFH_validate(flags, ptr)) - return STATUS_INVALID_PARAMETER; - - *out = LFH_get_allocated_size(flags, ptr); - return STATUS_SUCCESS; -} - -NTSTATUS HEAP_lfh_validate(HANDLE heap, ULONG flags, const void *ptr) -{ - TRACE("heap %p, flags %08lx, ptr %p.\n", heap, flags, ptr); - - if (!LFH_try_validate_all(flags)) - return STATUS_INVALID_PARAMETER; - - if (!LFH_validate(flags, ptr)) - return STATUS_INVALID_PARAMETER; - - return STATUS_SUCCESS; -} - -NTSTATUS HEAP_lfh_get_user_info( HANDLE heap, ULONG flags, void *ptr, void **user_value, ULONG *user_flags ) -{ - TRACE("heap %p, flags %08lx, ptr %p, user_value %p, user_flags %p.\n", heap, flags, ptr, user_value, user_flags); - - if (!LFH_try_validate_all(flags)) - return STATUS_INVALID_PARAMETER; - - if (!LFH_validate(flags, ptr)) - return STATUS_INVALID_PARAMETER; - - LFH_get_user_info(flags, ptr, user_value, user_flags); - return STATUS_SUCCESS; -} - -NTSTATUS HEAP_lfh_set_user_value( HANDLE heap, ULONG flags, void *ptr, void *user_value ) -{ - TRACE("heap %p, flags %08lx, ptr %p, user_value %p.\n", heap, flags, ptr, user_value); - - if (!LFH_try_validate_all(flags)) - return STATUS_INVALID_PARAMETER; - - if (!LFH_validate(flags, ptr)) - return STATUS_INVALID_PARAMETER; - - LFH_set_user_value(flags, ptr, user_value); - return STATUS_SUCCESS; -} - -NTSTATUS HEAP_lfh_set_user_flags( HANDLE heap, ULONG flags, void *ptr, ULONG clear, ULONG set ) -{ - TRACE("heap %p, flags %08lx, ptr %p, clear %08lx, set %08lx.\n", heap, flags, ptr, clear, set); - - if (!LFH_try_validate_all(flags)) - return STATUS_INVALID_PARAMETER; - - if (!LFH_validate(flags, ptr)) - return STATUS_INVALID_PARAMETER; - - LFH_set_user_flags(flags, ptr, clear, set); - return STATUS_SUCCESS; -} - -void HEAP_lfh_notify_thread_destroy(BOOLEAN last) -{ - SLIST_HEADER *list_orphan = LFH_orphan_list(); - SLIST_ENTRY *entry_orphan = NULL; - LFH_heap *heap; - - if (last) - { - while ((entry_orphan || (entry_orphan = RtlInterlockedFlushSList(list_orphan)))) - { - LFH_heap *orphan = LIST_ENTRY(entry_orphan, LFH_heap, entry_orphan); - entry_orphan = entry_orphan->Next; - LFH_heap_finalize(orphan); - } - LFH_memory_deallocate(list_orphan, BLOCK_ARENA_SIZE); - } - else if ((heap = LFH_thread_heap(FALSE)) && LFH_validate_heap(0, heap)) - RtlInterlockedPushEntrySList(list_orphan, &heap->entry_orphan); -} - -void HEAP_lfh_set_debug_flags(ULONG flags) -{ - LFH_heap *heap = LFH_thread_heap(FALSE); - if (!heap) return; - - LFH_deallocate_deferred_blocks(heap); - LFH_deallocated_cached_arenas(heap); -} diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 28519099e27..a9c8c62bc2d 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -115,32 +115,7 @@ static inline TEB64 *NtCurrentTeb64(void) { return NULL; } static inline TEB64 *NtCurrentTeb64(void) { return (TEB64 *)NtCurrentTeb()->GdiBatchCount; } #endif -#define HEAP_STD 0 -#define HEAP_LAL 1 -#define HEAP_LFH 2 - -/* some undocumented flags (names are made up) */ -#define HEAP_PRIVATE 0x00001000 -#define HEAP_ADD_USER_INFO 0x00000100 -#define HEAP_USER_FLAGS_MASK 0x00000f00 -#define HEAP_PAGE_ALLOCS 0x01000000 -#define HEAP_VALIDATE 0x10000000 -#define HEAP_VALIDATE_ALL 0x20000000 -#define HEAP_VALIDATE_PARAMS 0x40000000 -#define HEAP_CHECKING_ENABLED 0x80000000 - -NTSTATUS HEAP_lfh_allocate( HANDLE std_heap, ULONG flags, SIZE_T size, void **out ); -NTSTATUS HEAP_lfh_free( HANDLE std_heap, ULONG flags, void *ptr ); -NTSTATUS HEAP_lfh_reallocate( HANDLE std_heap, ULONG flags, void *ptr, SIZE_T size, void **out ); -NTSTATUS HEAP_lfh_get_allocated_size( HANDLE std_heap, ULONG flags, const void *ptr, SIZE_T *out ); -NTSTATUS HEAP_lfh_validate( HANDLE std_heap, ULONG flags, const void *ptr ); -NTSTATUS HEAP_lfh_get_user_info( HANDLE std_handle, ULONG flags, void *ptr, void **user_value, ULONG *user_flags ); -NTSTATUS HEAP_lfh_set_user_value( HANDLE std_handle, ULONG flags, void *ptr, void *user_value ); -NTSTATUS HEAP_lfh_set_user_flags( HANDLE std_handle, ULONG flags, void *ptr, ULONG clear, ULONG set ); - void HEAP_notify_thread_destroy( BOOLEAN last ); -void HEAP_lfh_notify_thread_destroy( BOOLEAN last ); -void HEAP_lfh_set_debug_flags( ULONG flags ); #define HASH_STRING_ALGORITHM_DEFAULT 0 #define HASH_STRING_ALGORITHM_X65599 1 diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 0cfa149e163..2fb1594acf6 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -68,7 +68,6 @@ struct ntdll_thread_data PRTL_THREAD_START_ROUTINE start; /* thread entry point */ void *param; /* thread entry point parameter */ void *jmp_buf; /* setjmp buffer for exception handling */ - void *heap; /* thread local heap data */ }; C_ASSERT( sizeof(struct ntdll_thread_data) <= sizeof(((TEB *)0)->GdiTebBatch) ); From e9a4c139689a974962d64aaef039586f42513250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 22 Feb 2023 22:12:42 +0100 Subject: [PATCH 1052/2777] Revert "ntdll: Add thread destroy notification function." This reverts commit f65391c9ae9b80dbbe4cb73842ea3ab458e4d8ee. --- dlls/ntdll/heap.c | 4 ---- dlls/ntdll/loader.c | 1 - dlls/ntdll/ntdll_misc.h | 2 -- dlls/ntdll/thread.c | 1 - 4 files changed, 8 deletions(-) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 3d364d89040..a73613e254f 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -2188,7 +2188,3 @@ BOOLEAN WINAPI RtlSetUserFlagsHeap( HANDLE handle, ULONG flags, void *ptr, ULONG return ret; } - -void HEAP_notify_thread_destroy( BOOLEAN last ) -{ -} diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 1e6858437e0..4a0d62433ac 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -3783,7 +3783,6 @@ void WINAPI RtlExitUserProcess( DWORD status ) RtlAcquirePebLock(); NtTerminateProcess( 0, status ); LdrShutdownProcess(); - HEAP_notify_thread_destroy(TRUE); for (;;) NtTerminateProcess( GetCurrentProcess(), status ); } diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index a9c8c62bc2d..d31358bab58 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -115,8 +115,6 @@ static inline TEB64 *NtCurrentTeb64(void) { return NULL; } static inline TEB64 *NtCurrentTeb64(void) { return (TEB64 *)NtCurrentTeb()->GdiBatchCount; } #endif -void HEAP_notify_thread_destroy( BOOLEAN last ); - #define HASH_STRING_ALGORITHM_DEFAULT 0 #define HASH_STRING_ALGORITHM_X65599 1 #define HASH_STRING_ALGORITHM_INVALID 0xffffffff diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 3cfeddbeeab..dbf0225419b 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -241,7 +241,6 @@ void WINAPI RtlExitUserThread( ULONG status ) NtQueryInformationThread( GetCurrentThread(), ThreadAmILastThread, &last, sizeof(last), NULL ); if (last) RtlExitUserProcess( status ); LdrShutdownThread(); - HEAP_notify_thread_destroy(FALSE); for (;;) NtTerminateThread( GetCurrentThread(), status ); } From a9c72bddc4842cee9eb19af937822d750fe9ad99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 22 Feb 2023 22:12:44 +0100 Subject: [PATCH 1053/2777] Revert "ntdll: Implement HeapCompatibilityInformation for Rtl(Query|Set)HeapInformation." This reverts commit dbf48814e16b943bdeda245d23f7737dae4b1729. --- dlls/kernel32/tests/heap.c | 10 +++++++ dlls/ntdll/heap.c | 53 +++++++------------------------------- 2 files changed, 19 insertions(+), 44 deletions(-) diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index 29faf8c902e..a81cb1b7a15 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -827,8 +827,11 @@ static void test_HeapCreate(void) size = 0; SetLastError( 0xdeadbeef ); ret = pHeapQueryInformation( 0, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); + todo_wine ok( !ret, "HeapQueryInformation succeeded\n" ); + todo_wine ok( GetLastError() == ERROR_NOACCESS, "got error %lu\n", GetLastError() ); + todo_wine ok( size == 0, "got size %Iu\n", size ); size = 0; @@ -868,6 +871,7 @@ static void test_HeapCreate(void) ok( ret, "HeapSetInformation failed, error %lu\n", GetLastError() ); ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); + todo_wine ok( compat_info == 2, "got HeapCompatibilityInformation %lu\n", compat_info ); /* cannot be undone */ @@ -875,15 +879,20 @@ static void test_HeapCreate(void) compat_info = 0; SetLastError( 0xdeadbeef ); ret = pHeapSetInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info) ); + todo_wine ok( !ret, "HeapSetInformation succeeded\n" ); + todo_wine ok( GetLastError() == ERROR_GEN_FAILURE, "got error %lu\n", GetLastError() ); compat_info = 1; SetLastError( 0xdeadbeef ); ret = pHeapSetInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info) ); + todo_wine ok( !ret, "HeapSetInformation succeeded\n" ); + todo_wine ok( GetLastError() == ERROR_GEN_FAILURE, "got error %lu\n", GetLastError() ); ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); + todo_wine ok( compat_info == 2, "got HeapCompatibilityInformation %lu\n", compat_info ); ret = HeapDestroy( heap ); @@ -922,6 +931,7 @@ static void test_HeapCreate(void) ok( ret, "HeapSetInformation failed, error %lu\n", GetLastError() ); ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); + todo_wine ok( compat_info == 2, "got HeapCompatibilityInformation %lu\n", compat_info ); for (i = 0; i < 0x11; i++) ptrs[i] = pHeapAlloc( heap, 0, 24 + 2 * sizeof(void *) ); diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index a73613e254f..e55d06369c0 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -39,13 +39,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(heap); -/* HeapCompatibilityInformation values */ - -#define HEAP_STD 0 -#define HEAP_LAL 1 -#define HEAP_LFH 2 - - /* undocumented RtlWalkHeap structure */ struct rtl_heap_entry @@ -201,7 +194,6 @@ struct heap DWORD force_flags; /* 0044/0074 */ /* end of the Windows 10 compatible struct layout */ - volatile LONG compat_info; /* HeapCompatibilityInformation / heap frontend type */ struct list entry; /* Entry in process heap list */ struct list subheap_list; /* Sub-heap list */ struct list large_list; /* Large blocks list */ @@ -1353,7 +1345,6 @@ HANDLE WINAPI RtlCreateHeap( ULONG flags, void *addr, SIZE_T total_size, SIZE_T heap->ffeeffee = 0xffeeffee; heap->auto_flags = (flags & HEAP_GROWABLE); heap->flags = (flags & ~HEAP_SHARED); - heap->compat_info = HEAP_STD; heap->magic = HEAP_MAGIC; heap->grow_size = max( HEAP_DEF_SIZE, total_size ); heap->min_size = commit_size; @@ -2015,24 +2006,21 @@ ULONG WINAPI RtlGetProcessHeaps( ULONG count, HANDLE *heaps ) * RtlQueryHeapInformation (NTDLL.@) */ NTSTATUS WINAPI RtlQueryHeapInformation( HANDLE handle, HEAP_INFORMATION_CLASS info_class, - void *info, SIZE_T size_in, SIZE_T *size_out ) + void *info, SIZE_T size_in, PSIZE_T size_out ) { - struct heap *heap; - ULONG heap_flags; - - TRACE( "handle %p, info_class %u, info %p, size_in %Iu, size_out %p.\n", handle, info_class, info, size_in, size_out ); - switch (info_class) { case HeapCompatibilityInformation: - if (!(heap = unsafe_heap_from_handle( handle, 0, &heap_flags ))) return STATUS_ACCESS_VIOLATION; if (size_out) *size_out = sizeof(ULONG); - if (size_in < sizeof(ULONG)) return STATUS_BUFFER_TOO_SMALL; - *(ULONG *)info = heap->compat_info; + + if (size_in < sizeof(ULONG)) + return STATUS_BUFFER_TOO_SMALL; + + *(ULONG *)info = 0; /* standard heap */ return STATUS_SUCCESS; default: - FIXME( "HEAP_INFORMATION_CLASS %u not implemented!\n", info_class ); + FIXME("Unknown heap information class %u\n", info_class); return STATUS_INVALID_INFO_CLASS; } } @@ -2042,31 +2030,8 @@ NTSTATUS WINAPI RtlQueryHeapInformation( HANDLE handle, HEAP_INFORMATION_CLASS i */ NTSTATUS WINAPI RtlSetHeapInformation( HANDLE handle, HEAP_INFORMATION_CLASS info_class, void *info, SIZE_T size ) { - struct heap *heap; - ULONG heap_flags; - - TRACE( "handle %p, info_class %u, info %p, size %Iu.\n", handle, info_class, info, size ); - - switch (info_class) - { - case HeapCompatibilityInformation: - { - ULONG compat_info; - - if (size < sizeof(ULONG)) return STATUS_BUFFER_TOO_SMALL; - if (!(heap = unsafe_heap_from_handle( handle, 0, &heap_flags ))) return STATUS_INVALID_HANDLE; - - compat_info = *(ULONG *)info; - if (compat_info) FIXME( "HeapCompatibilityInformation %lu not implemented!\n", compat_info ); - if (compat_info != HEAP_STD && compat_info != HEAP_LFH) return STATUS_UNSUCCESSFUL; - if (InterlockedCompareExchange( &heap->compat_info, compat_info, HEAP_STD )) return STATUS_UNSUCCESSFUL; - return STATUS_SUCCESS; - } - - default: - FIXME( "HEAP_INFORMATION_CLASS %u not implemented!\n", info_class ); - return STATUS_SUCCESS; - } + FIXME( "handle %p, info_class %d, info %p, size %Id stub!\n", handle, info_class, info, size ); + return STATUS_SUCCESS; } /*********************************************************************** From 949d5da696f29d53b6d16b88eee5d56ff81ea41d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 27 Jan 2023 16:51:41 +0100 Subject: [PATCH 1054/2777] ntdll: Fix HeapWalk with empty uncommitted consecutive subheaps. (cherry picked from commit 805247ace3a3abc0f496834342482fba2a6631bc) --- dlls/ntdll/heap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index e55d06369c0..d2d1fa1fef9 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -653,7 +653,7 @@ static SUBHEAP *find_subheap( const struct heap *heap, const struct block *block if (!check_subheap( subheap )) return NULL; if (contains( first_block( subheap ), blocks_size, block, sizeof(*block) )) return subheap; /* outside of blocks region, possible corruption or heap_walk */ - if (contains( subheap_base( subheap ), subheap_size( subheap ), block, 0 )) return heap_walk ? subheap : NULL; + if (contains( subheap_base( subheap ), subheap_size( subheap ), block, 1 )) return heap_walk ? subheap : NULL; } return NULL; From 3c05ebc3f6d1e528b0cbcc08d5ea141fe55e295e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 1 Dec 2022 11:18:27 +0100 Subject: [PATCH 1055/2777] ntdll: Implement HeapCompatibilityInformation. (cherry picked from commit 7314029c907a5760fcf7502d37784e079078adf5) --- dlls/kernel32/tests/heap.c | 34 +++++++++++++++------- dlls/ntdll/heap.c | 58 ++++++++++++++++++++++++++++++++------ 2 files changed, 73 insertions(+), 19 deletions(-) diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index a81cb1b7a15..307b11771b3 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -827,11 +827,8 @@ static void test_HeapCreate(void) size = 0; SetLastError( 0xdeadbeef ); ret = pHeapQueryInformation( 0, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); - todo_wine ok( !ret, "HeapQueryInformation succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_NOACCESS, "got error %lu\n", GetLastError() ); - todo_wine ok( size == 0, "got size %Iu\n", size ); size = 0; @@ -871,7 +868,6 @@ static void test_HeapCreate(void) ok( ret, "HeapSetInformation failed, error %lu\n", GetLastError() ); ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); - todo_wine ok( compat_info == 2, "got HeapCompatibilityInformation %lu\n", compat_info ); /* cannot be undone */ @@ -879,25 +875,44 @@ static void test_HeapCreate(void) compat_info = 0; SetLastError( 0xdeadbeef ); ret = pHeapSetInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info) ); - todo_wine ok( !ret, "HeapSetInformation succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_GEN_FAILURE, "got error %lu\n", GetLastError() ); compat_info = 1; SetLastError( 0xdeadbeef ); ret = pHeapSetInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info) ); - todo_wine ok( !ret, "HeapSetInformation succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_GEN_FAILURE, "got error %lu\n", GetLastError() ); ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); - todo_wine ok( compat_info == 2, "got HeapCompatibilityInformation %lu\n", compat_info ); ret = HeapDestroy( heap ); ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + + /* cannot set LFH with HEAP_NO_SERIALIZE */ + + heap = HeapCreate( HEAP_NO_SERIALIZE, 0, 0 ); + ok( !!heap, "HeapCreate failed, error %lu\n", GetLastError() ); + ok( !((ULONG_PTR)heap & 0xffff), "wrong heap alignment\n" ); + + ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); + ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); + ok( compat_info == 0, "got HeapCompatibilityInformation %lu\n", compat_info ); + + compat_info = 2; + SetLastError( 0xdeadbeef ); + ret = pHeapSetInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info) ); + ok( !ret, "HeapSetInformation succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); + ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); + ok( compat_info == 0, "got HeapCompatibilityInformation %lu\n", compat_info ); + + ret = HeapDestroy( heap ); + ok( ret, "HeapDestroy failed, error %lu\n", GetLastError() ); + + /* some allocation pattern automatically enables LFH */ heap = HeapCreate( 0, 0, 0 ); @@ -931,7 +946,6 @@ static void test_HeapCreate(void) ok( ret, "HeapSetInformation failed, error %lu\n", GetLastError() ); ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); - todo_wine ok( compat_info == 2, "got HeapCompatibilityInformation %lu\n", compat_info ); for (i = 0; i < 0x11; i++) ptrs[i] = pHeapAlloc( heap, 0, 24 + 2 * sizeof(void *) ); diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index d2d1fa1fef9..7604abd35a2 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -39,6 +39,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(heap); +/* HeapCompatibilityInformation values */ + +#define HEAP_STD 0 +#define HEAP_LAL 1 +#define HEAP_LFH 2 + + /* undocumented RtlWalkHeap structure */ struct rtl_heap_entry @@ -194,6 +201,7 @@ struct heap DWORD force_flags; /* 0044/0074 */ /* end of the Windows 10 compatible struct layout */ + LONG compat_info; /* HeapCompatibilityInformation / heap frontend type */ struct list entry; /* Entry in process heap list */ struct list subheap_list; /* Sub-heap list */ struct list large_list; /* Large blocks list */ @@ -1345,6 +1353,7 @@ HANDLE WINAPI RtlCreateHeap( ULONG flags, void *addr, SIZE_T total_size, SIZE_T heap->ffeeffee = 0xffeeffee; heap->auto_flags = (flags & HEAP_GROWABLE); heap->flags = (flags & ~HEAP_SHARED); + heap->compat_info = HEAP_STD; heap->magic = HEAP_MAGIC; heap->grow_size = max( HEAP_DEF_SIZE, total_size ); heap->min_size = commit_size; @@ -2006,21 +2015,24 @@ ULONG WINAPI RtlGetProcessHeaps( ULONG count, HANDLE *heaps ) * RtlQueryHeapInformation (NTDLL.@) */ NTSTATUS WINAPI RtlQueryHeapInformation( HANDLE handle, HEAP_INFORMATION_CLASS info_class, - void *info, SIZE_T size_in, PSIZE_T size_out ) + void *info, SIZE_T size_in, SIZE_T *size_out ) { + struct heap *heap; + ULONG flags; + + TRACE( "handle %p, info_class %u, info %p, size_in %Iu, size_out %p.\n", handle, info_class, info, size_in, size_out ); + switch (info_class) { case HeapCompatibilityInformation: + if (!(heap = unsafe_heap_from_handle( handle, 0, &flags ))) return STATUS_ACCESS_VIOLATION; if (size_out) *size_out = sizeof(ULONG); - - if (size_in < sizeof(ULONG)) - return STATUS_BUFFER_TOO_SMALL; - - *(ULONG *)info = 0; /* standard heap */ + if (size_in < sizeof(ULONG)) return STATUS_BUFFER_TOO_SMALL; + *(ULONG *)info = ReadNoFence( &heap->compat_info ); return STATUS_SUCCESS; default: - FIXME("Unknown heap information class %u\n", info_class); + FIXME( "HEAP_INFORMATION_CLASS %u not implemented!\n", info_class ); return STATUS_INVALID_INFO_CLASS; } } @@ -2030,8 +2042,36 @@ NTSTATUS WINAPI RtlQueryHeapInformation( HANDLE handle, HEAP_INFORMATION_CLASS i */ NTSTATUS WINAPI RtlSetHeapInformation( HANDLE handle, HEAP_INFORMATION_CLASS info_class, void *info, SIZE_T size ) { - FIXME( "handle %p, info_class %d, info %p, size %Id stub!\n", handle, info_class, info, size ); - return STATUS_SUCCESS; + struct heap *heap; + ULONG flags; + + TRACE( "handle %p, info_class %u, info %p, size %Iu.\n", handle, info_class, info, size ); + + switch (info_class) + { + case HeapCompatibilityInformation: + { + ULONG compat_info; + + if (size < sizeof(ULONG)) return STATUS_BUFFER_TOO_SMALL; + if (!(heap = unsafe_heap_from_handle( handle, 0, &flags ))) return STATUS_INVALID_HANDLE; + if (heap->flags & HEAP_NO_SERIALIZE) return STATUS_INVALID_PARAMETER; + + compat_info = *(ULONG *)info; + if (compat_info != HEAP_STD && compat_info != HEAP_LFH) + { + FIXME( "HeapCompatibilityInformation %lu not implemented!\n", compat_info ); + return STATUS_UNSUCCESSFUL; + } + if (InterlockedCompareExchange( &heap->compat_info, compat_info, HEAP_STD ) != HEAP_STD) + return STATUS_UNSUCCESSFUL; + return STATUS_SUCCESS; + } + + default: + FIXME( "HEAP_INFORMATION_CLASS %u not implemented!\n", info_class ); + return STATUS_SUCCESS; + } } /*********************************************************************** From d21d7f962ee635084983b2d0d7c84a4109503dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 2 Feb 2023 23:27:17 +0100 Subject: [PATCH 1056/2777] ntdll: Increase heap block tail_size capacity to 16 bits. We need this for larger LFH block bin steps. Use smaller block types to get more space, they are somewhat redundant with the block flags. (cherry picked from commit 0f6ebd0152f1217e7d9271cff9afb2e35b130995) --- dlls/ntdll/heap.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 7604abd35a2..e5968635481 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -86,11 +86,14 @@ struct rtl_heap_entry struct block { - WORD block_size; /* block size in multiple of BLOCK_ALIGN */ + /* block size in multiple of BLOCK_ALIGN */ + WORD block_size; + /* unused size (used block) / high size bits (free block) */ + WORD tail_size; + /* offset to region base */ + WORD base_offset; + BYTE block_type; BYTE block_flags; - BYTE tail_size; /* unused size (used block) / high size bits (free block) */ - WORD base_offset; /* offset to the region base in multiple of REGION_ALIGN */ - WORD block_type; }; C_ASSERT( sizeof(struct block) == 8 ); @@ -131,10 +134,10 @@ typedef struct C_ASSERT( sizeof(ARENA_LARGE) == offsetof(ARENA_LARGE, block) + sizeof(struct block) ); C_ASSERT( sizeof(ARENA_LARGE) == 4 * BLOCK_ALIGN ); -#define BLOCK_TYPE_USED 0x5355 -#define BLOCK_TYPE_DEAD 0xdead -#define BLOCK_TYPE_FREE 0x5246 -#define BLOCK_TYPE_LARGE 0x614c +#define BLOCK_TYPE_USED 'u' +#define BLOCK_TYPE_DEAD 'D' +#define BLOCK_TYPE_FREE 'F' +#define BLOCK_TYPE_LARGE 'L' #define BLOCK_FILL_USED 0x55 #define BLOCK_FILL_TAIL 0xab @@ -157,8 +160,9 @@ C_ASSERT( sizeof(struct entry) <= HEAP_MIN_BLOCK_SIZE ); #define HEAP_MAX_BLOCK_REGION_SIZE (FIELD_MAX( struct block, base_offset ) * REGION_ALIGN) C_ASSERT( HEAP_MAX_USED_BLOCK_SIZE == 512 * 1024 * (sizeof(void *) / 4) - BLOCK_ALIGN ); -C_ASSERT( HEAP_MAX_FREE_BLOCK_SIZE == 128 * 1024 * 1024 * (sizeof(void *) / 4) - BLOCK_ALIGN ); -C_ASSERT( HEAP_MAX_BLOCK_REGION_SIZE >= HEAP_MAX_FREE_BLOCK_SIZE ); +C_ASSERT( HEAP_MAX_FREE_BLOCK_SIZE >= 128 * 1024 * 1024 * (sizeof(void *) / 4) - BLOCK_ALIGN ); +C_ASSERT( HEAP_MAX_BLOCK_REGION_SIZE >= 128 * 1024 * 1024 * (sizeof(void *) / 4) - BLOCK_ALIGN ); +C_ASSERT( HEAP_MAX_FREE_BLOCK_SIZE >= HEAP_MAX_BLOCK_REGION_SIZE ); /* minimum size to start allocating large blocks */ #define HEAP_MIN_LARGE_BLOCK_SIZE (HEAP_MAX_USED_BLOCK_SIZE - 0x1000) From 518357322f52aff0c11da2b351b2e2ca1781ace3 Mon Sep 17 00:00:00 2001 From: Jinoh Kang Date: Sat, 31 Dec 2022 22:55:12 +0900 Subject: [PATCH 1057/2777] ntdll: Check for delayed free block in heap_validate_ptr. Today, the heap does not catch double free when both HEAP_VALIDATE and HEAP_FREE_CHECKING_ENABLED are on, since validate_used_block() accepts BLOCK_TYPE_DEAD as a valid (allocated) block type. Fix this by adding an explicit check that rejects BLOCK_TYPE_DEAD in heap_validate_ptr. (cherry picked from commit b887e31d151be53324bc0670f01ebc5ee6349dac) --- dlls/ntdll/heap.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index e5968635481..c6ab99b1a2b 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -1081,7 +1081,8 @@ static BOOL validate_free_block( const struct heap *heap, const SUBHEAP *subheap } -static BOOL validate_used_block( const struct heap *heap, const SUBHEAP *subheap, const struct block *block ) +static BOOL validate_used_block( const struct heap *heap, const SUBHEAP *subheap, const struct block *block, + unsigned int expected_block_type ) { const char *err = NULL, *base = subheap_base( subheap ), *commit_end = subheap_commit_end( subheap ); DWORD flags = heap->flags; @@ -1092,6 +1093,8 @@ static BOOL validate_used_block( const struct heap *heap, const SUBHEAP *subheap err = "invalid block BLOCK_ALIGN"; else if (block_get_type( block ) != BLOCK_TYPE_USED && block_get_type( block ) != BLOCK_TYPE_DEAD) err = "invalid block header"; + else if (expected_block_type && block_get_type( block ) != expected_block_type) + err = "invalid block type"; else if (block_get_flags( block ) & BLOCK_FLAG_FREE) err = "invalid block flags"; else if (!contains( base, commit_end - base, block, block_get_size( block ) )) @@ -1152,7 +1155,7 @@ static BOOL heap_validate_ptr( const struct heap *heap, const void *ptr ) return validate_large_block( heap, block ); } - return validate_used_block( heap, subheap, block ); + return validate_used_block( heap, subheap, block, BLOCK_TYPE_USED ); } static BOOL heap_validate( const struct heap *heap ) @@ -1178,7 +1181,7 @@ static BOOL heap_validate( const struct heap *heap ) } else { - if (!validate_used_block( heap, subheap, block )) return FALSE; + if (!validate_used_block( heap, subheap, block, 0 )) return FALSE; } } } From 658e5f704ed8d4131bd4b638d21d53440c4f16ce Mon Sep 17 00:00:00 2001 From: Jinoh Kang Date: Sat, 31 Dec 2022 22:56:53 +0900 Subject: [PATCH 1058/2777] ntdll: Validate subheap's owner heap when validating heap. (cherry picked from commit 8cc5e89267163dbdff89b8a84b6d92c756904305) --- dlls/ntdll/heap.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index c6ab99b1a2b..9f50e485fdc 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -352,8 +352,10 @@ static inline struct block *next_block( const SUBHEAP *subheap, const struct blo return (struct block *)next; } -static inline BOOL check_subheap( const SUBHEAP *subheap ) +static inline BOOL check_subheap( const SUBHEAP *subheap, const struct heap *heap ) { + if (subheap->user_value != heap) return FALSE; + return contains( &subheap->block, subheap->block_size, subheap + 1, subheap->data_size ); } @@ -461,13 +463,13 @@ static inline void valgrind_notify_resize( void const *ptr, SIZE_T size_old, SIZ #endif } -static void valgrind_notify_free_all( SUBHEAP *subheap ) +static void valgrind_notify_free_all( SUBHEAP *subheap, const struct heap *heap ) { #ifdef VALGRIND_FREELIKE_BLOCK struct block *block; if (!RUNNING_ON_VALGRIND) return; - if (!check_subheap( subheap )) return; + if (!check_subheap( subheap, heap )) return; for (block = first_block( subheap ); block; block = next_block( subheap, block )) { @@ -563,7 +565,7 @@ static void heap_dump( const struct heap *heap ) TRACE( " %p: base %p first %p last %p end %p\n", subheap, base, first_block( subheap ), last_block( subheap ), base + subheap_size( subheap ) ); - if (!check_subheap( subheap )) return; + if (!check_subheap( subheap, heap )) return; overhead += subheap_overhead( subheap ); for (block = first_block( subheap ); block; block = next_block( subheap, block )) @@ -662,7 +664,7 @@ static SUBHEAP *find_subheap( const struct heap *heap, const struct block *block LIST_FOR_EACH_ENTRY( subheap, &heap->subheap_list, SUBHEAP, entry ) { SIZE_T blocks_size = (char *)last_block( subheap ) - (char *)first_block( subheap ); - if (!check_subheap( subheap )) return NULL; + if (!check_subheap( subheap, heap )) return NULL; if (contains( first_block( subheap ), blocks_size, block, sizeof(*block) )) return subheap; /* outside of blocks region, possible corruption or heap_walk */ if (contains( subheap_base( subheap ), subheap_size( subheap ), block, 1 )) return heap_walk ? subheap : NULL; @@ -1166,9 +1168,9 @@ static BOOL heap_validate( const struct heap *heap ) LIST_FOR_EACH_ENTRY( subheap, &heap->subheap_list, SUBHEAP, entry ) { - if (!check_subheap( subheap )) + if (!check_subheap( subheap, heap )) { - ERR( "heap %p, subheap %p corrupted sizes\n", heap, subheap ); + ERR( "heap %p, subheap %p corrupted sizes or user_value\n", heap, subheap ); if (TRACE_ON(heap)) heap_dump( heap ); return FALSE; } @@ -1285,7 +1287,7 @@ static void heap_set_debug_flags( HANDLE handle ) { const char *commit_end = subheap_commit_end( subheap ); - if (!check_subheap( subheap )) break; + if (!check_subheap( subheap, heap )) break; for (block = first_block( subheap ); block; block = next_block( subheap, block )) { @@ -1482,13 +1484,13 @@ HANDLE WINAPI RtlDestroyHeap( HANDLE handle ) LIST_FOR_EACH_ENTRY_SAFE( subheap, next, &heap->subheap_list, SUBHEAP, entry ) { if (subheap == &heap->subheap) continue; /* do this one last */ - valgrind_notify_free_all( subheap ); + valgrind_notify_free_all( subheap, heap ); list_remove( &subheap->entry ); size = 0; addr = ROUND_ADDR( subheap, REGION_ALIGN - 1 ); NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE ); } - valgrind_notify_free_all( &heap->subheap ); + valgrind_notify_free_all( &heap->subheap, heap ); size = 0; addr = heap; NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE ); From a565aa1298987e6a5374b24d3d4f4d57069cae94 Mon Sep 17 00:00:00 2001 From: Jinoh Kang Date: Sat, 31 Dec 2022 22:57:17 +0900 Subject: [PATCH 1059/2777] ntdll: Validate blocks in the heap pending free request list. (cherry picked from commit af557f0cbc644e5a46af0b13acef8eae59e1cbea) --- dlls/ntdll/heap.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 9f50e485fdc..9e497d3221b 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -1188,6 +1188,36 @@ static BOOL heap_validate( const struct heap *heap ) } } + if (heap->pending_free) + { + unsigned int i; + + for (i = 0; i < MAX_FREE_PENDING; i++) + { + if (!(block = heap->pending_free[i])) break; + + subheap = find_subheap( heap, block, FALSE ); + if (!subheap) + { + ERR( "heap %p: cannot find valid subheap for delayed freed block %p\n", heap, block ); + if (TRACE_ON(heap)) heap_dump( heap ); + return FALSE; + } + + if (!validate_used_block( heap, subheap, block, BLOCK_TYPE_DEAD )) return FALSE; + } + + for (; i < MAX_FREE_PENDING; i++) + { + if ((block = heap->pending_free[i])) + { + ERR( "heap %p: unexpected delayed freed block %p at slot %u\n", heap, block, i ); + if (TRACE_ON(heap)) heap_dump( heap ); + return FALSE; + } + } + } + LIST_FOR_EACH_ENTRY( large_arena, &heap->large_list, ARENA_LARGE, entry ) if (!validate_large_block( heap, &large_arena->block )) return FALSE; From a6fe2a291f97b0327a049ec760822596f2a64525 Mon Sep 17 00:00:00 2001 From: Jinoh Kang Date: Mon, 2 Jan 2023 20:07:13 +0900 Subject: [PATCH 1060/2777] ntdll: Remove redundant WARN_ON(heap) check. (cherry picked from commit f9ab9292e7e23674c32a3af7a292732698058c68) --- dlls/ntdll/heap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 9e497d3221b..874b4dd6633 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -1150,7 +1150,7 @@ static BOOL heap_validate_ptr( const struct heap *heap, const void *ptr ) { if (!find_large_block( heap, block )) { - if (WARN_ON(heap)) WARN("heap %p, ptr %p: block region not found\n", heap, ptr ); + WARN("heap %p, ptr %p: block region not found\n", heap, ptr ); return FALSE; } From cb573c8289bdc7c8a10d072dc2962dcea95cf394 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 15 Nov 2022 00:11:12 +0100 Subject: [PATCH 1061/2777] ntdll: Count allocations and automatically enable LFH. (cherry picked from commit 632b08aa5bfa71c666f0b2560503c12e2e080b3e) --- dlls/kernel32/tests/heap.c | 2 - dlls/ntdll/heap.c | 138 ++++++++++++++++++++++++++++++++++++- 2 files changed, 136 insertions(+), 4 deletions(-) diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index 307b11771b3..cf4b4fa7058 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -928,7 +928,6 @@ static void test_HeapCreate(void) ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); - todo_wine ok( compat_info == 2, "got HeapCompatibilityInformation %lu\n", compat_info ); ret = HeapDestroy( heap ); @@ -1219,7 +1218,6 @@ static void test_HeapCreate(void) ret = pHeapQueryInformation( heap, HeapCompatibilityInformation, &compat_info, sizeof(compat_info), &size ); ok( ret, "HeapQueryInformation failed, error %lu\n", GetLastError() ); - todo_wine ok( compat_info == 2, "got HeapCompatibilityInformation %lu\n", compat_info ); /* locking is serialized */ diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 874b4dd6633..a9033deb7c8 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -90,7 +90,7 @@ struct block WORD block_size; /* unused size (used block) / high size bits (free block) */ WORD tail_size; - /* offset to region base */ + /* offset to region base / first group block (LFH block) */ WORD base_offset; BYTE block_type; BYTE block_flags; @@ -193,6 +193,76 @@ typedef struct DECLSPEC_ALIGN(BLOCK_ALIGN) tagSUBHEAP C_ASSERT( sizeof(SUBHEAP) == offsetof(SUBHEAP, block) + sizeof(struct block) ); C_ASSERT( sizeof(SUBHEAP) == 4 * BLOCK_ALIGN ); + +/* LFH block size bins */ + +#define BIN_SIZE_MIN_0 0 +#define BIN_SIZE_MIN_1 0x100 +#define BIN_SIZE_MIN_2 0x200 +#define BIN_SIZE_MIN_3 0x400 +#define BIN_SIZE_MIN_4 0x800 +#define BIN_SIZE_MIN_5 0x1000 +#define BIN_SIZE_MIN_6 0x2000 +#define BIN_SIZE_MIN_7 0x4000 +#define BIN_SIZE_MAX 0x8000 + +#define BIN_SIZE_STEP_0 (16) +#define BIN_SIZE_STEP_1 (BIN_SIZE_MIN_1 >> 4) +#define BIN_SIZE_STEP_2 (BIN_SIZE_MIN_2 >> 4) +#define BIN_SIZE_STEP_3 (BIN_SIZE_MIN_3 >> 4) +#define BIN_SIZE_STEP_4 (BIN_SIZE_MIN_4 >> 4) +#define BIN_SIZE_STEP_5 (BIN_SIZE_MIN_5 >> 4) +#define BIN_SIZE_STEP_6 (BIN_SIZE_MIN_6 >> 4) +#define BIN_SIZE_STEP_7 (BIN_SIZE_MIN_7 >> 4) + +#define BLOCK_BIN_SIZE_N( n, bin ) (BIN_SIZE_MIN_##n + (bin + 1) * BIN_SIZE_STEP_##n) +#define BLOCK_SIZE_BIN_N( n, size ) (((size) - 1 - BIN_SIZE_MIN_##n) / BIN_SIZE_STEP_##n) + +#define BLOCK_BIN_SIZE( bin ) ((bin) >= 0x80 ? ~(SIZE_T)0 : \ + (bin) >= 0x70 ? BLOCK_BIN_SIZE_N( 7, bin - 0x70 ) : \ + (bin) >= 0x60 ? BLOCK_BIN_SIZE_N( 6, bin - 0x60 ) : \ + (bin) >= 0x50 ? BLOCK_BIN_SIZE_N( 5, bin - 0x50 ) : \ + (bin) >= 0x40 ? BLOCK_BIN_SIZE_N( 4, bin - 0x40 ) : \ + (bin) >= 0x30 ? BLOCK_BIN_SIZE_N( 3, bin - 0x30 ) : \ + (bin) >= 0x20 ? BLOCK_BIN_SIZE_N( 2, bin - 0x20 ) : \ + (bin) >= 0x10 ? BLOCK_BIN_SIZE_N( 1, bin - 0x10 ) : \ + BLOCK_BIN_SIZE_N( 0, bin )) + +#define BLOCK_SIZE_BIN( size ) ((size) > BIN_SIZE_MAX ? 0x80 : \ + (size) > BIN_SIZE_MIN_7 ? 0x70 + BLOCK_SIZE_BIN_N( 7, size ) : \ + (size) > BIN_SIZE_MIN_6 ? 0x60 + BLOCK_SIZE_BIN_N( 6, size ) : \ + (size) > BIN_SIZE_MIN_5 ? 0x50 + BLOCK_SIZE_BIN_N( 5, size ) : \ + (size) > BIN_SIZE_MIN_4 ? 0x40 + BLOCK_SIZE_BIN_N( 4, size ) : \ + (size) > BIN_SIZE_MIN_3 ? 0x30 + BLOCK_SIZE_BIN_N( 3, size ) : \ + (size) > BIN_SIZE_MIN_2 ? 0x20 + BLOCK_SIZE_BIN_N( 2, size ) : \ + (size) > BIN_SIZE_MIN_1 ? 0x10 + BLOCK_SIZE_BIN_N( 1, size ) : \ + (size) <= BIN_SIZE_MIN_0 ? 0 : BLOCK_SIZE_BIN_N( 0, size )) + +#define BLOCK_SIZE_BIN_COUNT (BLOCK_SIZE_BIN( BIN_SIZE_MAX + 1 ) + 1) + +/* macros sanity checks */ +C_ASSERT( BLOCK_SIZE_BIN( 0 ) == 0 ); +C_ASSERT( BLOCK_SIZE_BIN( 0x10 ) == 0 ); +C_ASSERT( BLOCK_BIN_SIZE( 0 ) == BIN_SIZE_MIN_0 + 1 * BIN_SIZE_STEP_0 ); +C_ASSERT( BLOCK_SIZE_BIN( 0x11 ) == 1 ); +C_ASSERT( BLOCK_BIN_SIZE( 1 ) == BIN_SIZE_MIN_0 + 2 * BIN_SIZE_STEP_0 ); +C_ASSERT( BLOCK_SIZE_BIN( BIN_SIZE_MAX ) == 0x7f ); +C_ASSERT( BLOCK_BIN_SIZE( 0x7f ) == BIN_SIZE_MAX ); +C_ASSERT( BLOCK_SIZE_BIN( BIN_SIZE_MAX + 1 ) == 0x80 ); +C_ASSERT( BLOCK_BIN_SIZE( 0x80 ) == ~(SIZE_T)0 ); + +/* difference between block classes and all possible validation overhead must fit into block tail_size */ +C_ASSERT( BIN_SIZE_STEP_7 + 3 * BLOCK_ALIGN <= FIELD_MAX( struct block, tail_size ) ); + +/* a bin, tracking heap blocks of a certain size */ +struct bin +{ + /* counters for LFH activation */ + LONG count_alloc; + LONG count_freed; + LONG enabled; +}; + struct heap { /* win32/win64 */ DWORD_PTR unknown1[2]; /* 0000/0000 */ @@ -216,6 +286,7 @@ struct heap struct block **pending_free; /* Ring buffer for pending free requests */ RTL_CRITICAL_SECTION cs; struct entry free_lists[HEAP_NB_FREE_LISTS]; + struct bin *bins; SUBHEAP subheap; }; @@ -550,6 +621,16 @@ static void heap_dump( const struct heap *heap ) TRACE( "heap: %p\n", heap ); TRACE( " next %p\n", LIST_ENTRY( heap->entry.next, struct heap, entry ) ); + TRACE( " bins:\n" ); + for (i = 0; heap->bins && i < BLOCK_SIZE_BIN_COUNT; i++) + { + const struct bin *bin = heap->bins + i; + ULONG alloc = ReadNoFence( &bin->count_alloc ), freed = ReadNoFence( &bin->count_freed ); + if (!alloc && !freed) continue; + TRACE( " %3u: size %#4Ix, alloc %ld, freed %ld, enabled %lu\n", i, BLOCK_BIN_SIZE( i ), + alloc, freed, ReadNoFence( &bin->enabled ) ); + } + TRACE( " free_lists: %p\n", heap->free_lists ); for (i = 0; i < HEAP_NB_FREE_LISTS; i++) TRACE( " %p: size %#8Ix, prev %p, next %p\n", heap->free_lists + i, get_free_list_block_size( i ), @@ -1436,6 +1517,13 @@ HANDLE WINAPI RtlCreateHeap( ULONG flags, void *addr, SIZE_T total_size, SIZE_T heap_set_debug_flags( heap ); + if (heap->flags & HEAP_GROWABLE) + { + SIZE_T size = sizeof(struct bin) * BLOCK_SIZE_BIN_COUNT; + NtAllocateVirtualMemory( NtCurrentProcess(), (void *)&heap->bins, + 0, &size, MEM_COMMIT, PAGE_READWRITE ); + } + /* link it into the per-process heap list */ if (process_heap) { @@ -1521,6 +1609,11 @@ HANDLE WINAPI RtlDestroyHeap( HANDLE handle ) NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE ); } valgrind_notify_free_all( &heap->subheap, heap ); + if ((addr = heap->bins)) + { + size = 0; + NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE ); + } size = 0; addr = heap; NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE ); @@ -1578,6 +1671,27 @@ static NTSTATUS heap_allocate_block( struct heap *heap, ULONG flags, SIZE_T bloc return STATUS_SUCCESS; } +static void bin_try_enable( struct heap *heap, struct bin *bin ) +{ + ULONG alloc = ReadNoFence( &bin->count_alloc ), freed = ReadNoFence( &bin->count_freed ); + SIZE_T block_size = BLOCK_BIN_SIZE( bin - heap->bins ); + BOOL enable = FALSE; + + if (bin == heap->bins && alloc > 0x10) enable = TRUE; + else if (bin - heap->bins < 0x30 && alloc > 0x800) enable = TRUE; + else if (bin - heap->bins < 0x30 && alloc - freed > 0x10) enable = TRUE; + else if (alloc - freed > 0x400000 / block_size) enable = TRUE; + if (!enable) return; + + if (ReadNoFence( &heap->compat_info ) != HEAP_LFH) + { + ULONG info = HEAP_LFH; + RtlSetHeapInformation( heap, HeapCompatibilityInformation, &info, sizeof(info) ); + } + + WriteNoFence( &bin->enabled, TRUE ); +} + /*********************************************************************** * RtlAllocateHeap (NTDLL.@) */ @@ -1600,6 +1714,13 @@ void *WINAPI DECLSPEC_HOTPATCH RtlAllocateHeap( HANDLE handle, ULONG flags, SIZE heap_lock( heap, heap_flags ); status = heap_allocate_block( heap, heap_flags, block_size, size, &ptr ); heap_unlock( heap, heap_flags ); + + if (!status && heap->bins) + { + SIZE_T bin = BLOCK_SIZE_BIN( block_get_size( (struct block *)ptr - 1 ) ); + InterlockedIncrement( &heap->bins[bin].count_alloc ); + if (!ReadNoFence( &heap->bins[bin].enabled )) bin_try_enable( heap, &heap->bins[bin] ); + } } if (!status) valgrind_notify_alloc( ptr, size, flags & HEAP_ZERO_MEMORY ); @@ -1634,9 +1755,13 @@ BOOLEAN WINAPI DECLSPEC_HOTPATCH RtlFreeHeap( HANDLE handle, ULONG flags, void * status = STATUS_SUCCESS; else { + SIZE_T block_size = block_get_size( block ), bin = BLOCK_SIZE_BIN( block_size ); + heap_lock( heap, heap_flags ); status = heap_free_block( heap, heap_flags, block ); heap_unlock( heap, heap_flags ); + + if (!status && heap->bins) InterlockedIncrement( &heap->bins[bin].count_freed ); } TRACE( "handle %p, flags %#lx, ptr %p, return %u, status %#lx.\n", handle, flags, ptr, !status, status ); @@ -1648,7 +1773,7 @@ static NTSTATUS heap_resize_block( struct heap *heap, ULONG flags, struct block SIZE_T size, SIZE_T *old_size, void **ret ) { SUBHEAP *subheap = block_get_subheap( heap, block ); - SIZE_T old_block_size; + SIZE_T old_bin, old_block_size; struct entry *entry; struct block *next; @@ -1675,6 +1800,7 @@ static NTSTATUS heap_resize_block( struct heap *heap, ULONG flags, struct block old_block_size = block_get_size( block ); *old_size = old_block_size - block_get_overhead( block ); + old_bin = BLOCK_SIZE_BIN( old_block_size ); if (block_size >= HEAP_MIN_LARGE_BLOCK_SIZE) return STATUS_NO_MEMORY; /* growing small block to large block */ @@ -1714,6 +1840,14 @@ static NTSTATUS heap_resize_block( struct heap *heap, ULONG flags, struct block heap_unlock( heap, flags ); + if (heap->bins) + { + SIZE_T new_bin = BLOCK_SIZE_BIN( block_size ); + InterlockedIncrement( &heap->bins[old_bin].count_freed ); + InterlockedIncrement( &heap->bins[new_bin].count_alloc ); + if (!ReadNoFence( &heap->bins[new_bin].enabled )) bin_try_enable( heap, &heap->bins[new_bin] ); + } + *ret = block + 1; return STATUS_SUCCESS; } From 95497e84fd60bbd785737252682799ae718ccc2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 Feb 2023 17:54:32 +0100 Subject: [PATCH 1062/2777] ntdll: Split heap_resize_block into heap_resize_(block|large) helpers. (cherry picked from commit b4e5aa8dfc7261504f734ce34b092eec32673362) --- dlls/ntdll/heap.c | 92 ++++++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index a9033deb7c8..0358ec2748a 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -1769,57 +1769,47 @@ BOOLEAN WINAPI DECLSPEC_HOTPATCH RtlFreeHeap( HANDLE handle, ULONG flags, void * return !status; } -static NTSTATUS heap_resize_block( struct heap *heap, ULONG flags, struct block *block, SIZE_T block_size, +static NTSTATUS heap_resize_large( struct heap *heap, ULONG flags, struct block *block, SIZE_T block_size, SIZE_T size, SIZE_T *old_size, void **ret ) { - SUBHEAP *subheap = block_get_subheap( heap, block ); - SIZE_T old_bin, old_block_size; - struct entry *entry; - struct block *next; + ARENA_LARGE *large = CONTAINING_RECORD( block, ARENA_LARGE, block ); + SIZE_T old_block_size = large->block_size; + *old_size = large->data_size; - if (block_get_flags( block ) & BLOCK_FLAG_LARGE) - { - ARENA_LARGE *large = CONTAINING_RECORD( block, ARENA_LARGE, block ); - old_block_size = large->block_size; - *old_size = large->data_size; - - if (block_size < HEAP_MIN_LARGE_BLOCK_SIZE / 4) return STATUS_NO_MEMORY; /* shrinking large block to small block */ - if (old_block_size < block_size) return STATUS_NO_MEMORY; - - /* FIXME: we could remap zero-pages instead */ - valgrind_notify_resize( block + 1, *old_size, size ); - initialize_block( block, *old_size, size, flags ); + if (block_size < HEAP_MIN_LARGE_BLOCK_SIZE / 4) return STATUS_NO_MEMORY; /* shrinking large block to small block */ + if (old_block_size < block_size) return STATUS_NO_MEMORY; - large->data_size = size; - valgrind_make_noaccess( (char *)block + sizeof(*block) + large->data_size, - old_block_size - sizeof(*block) - large->data_size ); - - *ret = block + 1; - return STATUS_SUCCESS; - } + /* FIXME: we could remap zero-pages instead */ + valgrind_notify_resize( block + 1, *old_size, size ); + initialize_block( block, *old_size, size, flags ); - old_block_size = block_get_size( block ); - *old_size = old_block_size - block_get_overhead( block ); - old_bin = BLOCK_SIZE_BIN( old_block_size ); + large->data_size = size; + valgrind_make_noaccess( (char *)block + sizeof(*block) + large->data_size, + old_block_size - sizeof(*block) - large->data_size ); - if (block_size >= HEAP_MIN_LARGE_BLOCK_SIZE) return STATUS_NO_MEMORY; /* growing small block to large block */ + *ret = block + 1; + return STATUS_SUCCESS; +} - heap_lock( heap, flags ); +static NTSTATUS heap_resize_block( struct heap *heap, ULONG flags, struct block *block, SIZE_T block_size, + SIZE_T size, SIZE_T old_block_size, SIZE_T *old_size, void **ret ) +{ + SUBHEAP *subheap = block_get_subheap( heap, block ); + struct block *next; if (block_size > old_block_size) { - if (!(next = next_block( subheap, block )) || !(block_get_flags( next ) & BLOCK_FLAG_FREE) || - block_size > old_block_size + block_get_size( next ) || !subheap_commit( heap, subheap, block, block_size )) - { - heap_unlock( heap, flags ); - return STATUS_NO_MEMORY; - } + /* need to grow block, make sure it's followed by large enough free block */ + if (!(next = next_block( subheap, block ))) return STATUS_NO_MEMORY; + if (!(block_get_flags( next ) & BLOCK_FLAG_FREE)) return STATUS_NO_MEMORY; + if (block_size > old_block_size + block_get_size( next )) return STATUS_NO_MEMORY; + if (!subheap_commit( heap, subheap, block, block_size )) return STATUS_NO_MEMORY; } if ((next = next_block( subheap, block )) && (block_get_flags( next ) & BLOCK_FLAG_FREE)) { /* merge with next block if it is free */ - entry = (struct entry *)next; + struct entry *entry = (struct entry *)next; list_remove( &entry->entry ); old_block_size += block_get_size( next ); } @@ -1838,9 +1828,30 @@ static NTSTATUS heap_resize_block( struct heap *heap, ULONG flags, struct block if ((next = next_block( subheap, block ))) block_set_flags( next, BLOCK_FLAG_PREV_FREE, 0 ); + *ret = block + 1; + return STATUS_SUCCESS; +} + +static NTSTATUS heap_resize_in_place( struct heap *heap, ULONG flags, struct block *block, SIZE_T block_size, + SIZE_T size, SIZE_T *old_size, void **ret ) +{ + SIZE_T old_bin, old_block_size; + NTSTATUS status; + + if (block_get_flags( block ) & BLOCK_FLAG_LARGE) + return heap_resize_large( heap, flags, block, block_size, size, old_size, ret ); + + old_block_size = block_get_size( block ); + *old_size = old_block_size - block_get_overhead( block ); + old_bin = BLOCK_SIZE_BIN( old_block_size ); + + if (block_size >= HEAP_MIN_LARGE_BLOCK_SIZE) return STATUS_NO_MEMORY; /* growing small block to large block */ + + heap_lock( heap, flags ); + status = heap_resize_block( heap, flags, block, block_size, size, old_block_size, old_size, ret ); heap_unlock( heap, flags ); - if (heap->bins) + if (!status && heap->bins) { SIZE_T new_bin = BLOCK_SIZE_BIN( block_size ); InterlockedIncrement( &heap->bins[old_bin].count_freed ); @@ -1848,8 +1859,7 @@ static NTSTATUS heap_resize_block( struct heap *heap, ULONG flags, struct block if (!ReadNoFence( &heap->bins[new_bin].enabled )) bin_try_enable( heap, &heap->bins[new_bin] ); } - *ret = block + 1; - return STATUS_SUCCESS; + return status; } /*********************************************************************** @@ -1872,8 +1882,8 @@ void *WINAPI RtlReAllocateHeap( HANDLE handle, ULONG flags, void *ptr, SIZE_T si status = STATUS_NO_MEMORY; else if (!(block = unsafe_block_from_ptr( heap, heap_flags, ptr ))) status = STATUS_INVALID_PARAMETER; - else if ((status = heap_resize_block( heap, heap_flags, block, block_size, size, - &old_size, &ret ))) + else if ((status = heap_resize_in_place( heap, heap_flags, block, block_size, size, + &old_size, &ret ))) { if (flags & HEAP_REALLOC_IN_PLACE_ONLY) status = STATUS_NO_MEMORY; From f71b8c073b84ce0e90169d76a3d360285d30f2fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 11 Feb 2023 09:43:30 +0100 Subject: [PATCH 1063/2777] ntdll: Implement Low Fragmentation Heap frontend. This implements the reduced fragmentation from the heap frontend, by carving smaller blocks out of larger allocated blocks. The super block and each sub-block are all flagged with BLOCK_FLAG_LFH. The super-block (struct group) uses a standard struct block header, as well as a list entry to be linked in free list, and a free bit map to track free sub-blocks. Sub-blocks reference their super block through the base_offset, instead of the subheap, using the block size as radix. (cherry picked from commit 27665f35e4da13bac1e4dd8948a65f484c9dadfa) --- dlls/kernel32/tests/heap.c | 20 ++- dlls/ntdll/heap.c | 276 ++++++++++++++++++++++++++++++++++++- 2 files changed, 277 insertions(+), 19 deletions(-) diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index cf4b4fa7058..8c06e9d5f53 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -986,6 +986,7 @@ static void test_HeapCreate(void) ok( entries[0].cbData <= 0x1000 /* sizeof(*heap) */, "got cbData %#lx\n", entries[0].cbData ); ok( entries[0].cbOverhead == 0, "got cbOverhead %#x\n", entries[0].cbOverhead ); ok( entries[0].iRegionIndex == 0, "got iRegionIndex %d\n", entries[0].iRegionIndex ); + todo_wine /* Wine currently reports the LFH group as a single block here */ ok( entries[1].wFlags == 0, "got wFlags %#x\n", entries[1].wFlags ); for (i = 0; i < 0x12; i++) @@ -1066,6 +1067,7 @@ static void test_HeapCreate(void) for (i = 1; i < count - 2; i++) { if (entries[i].wFlags != PROCESS_HEAP_ENTRY_BUSY) continue; + todo_wine /* Wine currently reports the LFH group as a single block */ ok( entries[i].cbData == 0x18 + 2 * sizeof(void *), "got cbData %#lx\n", entries[i].cbData ); ok( entries[i].cbOverhead == 0x8, "got cbOverhead %#x\n", entries[i].cbOverhead ); } @@ -1691,9 +1693,7 @@ static void test_GlobalAlloc(void) ok( size == small_size, "GlobalSize returned %Iu\n", size ); SetLastError( 0xdeadbeef ); tmp_mem = GlobalReAlloc( mem, small_size, 0 ); - todo_wine ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got error %lu\n", GetLastError() ); if (tmp_mem) mem = tmp_mem; tmp_mem = GlobalReAlloc( mem, 1024 * 1024, GMEM_MODIFY ); @@ -1709,7 +1709,6 @@ static void test_GlobalAlloc(void) ok( !!mem, "GlobalAlloc failed, error %lu\n", GetLastError() ); tmp_mem = GlobalReAlloc( mem, small_size + 1, GMEM_MOVEABLE ); ok( !!tmp_mem, "GlobalReAlloc failed, error %lu\n", GetLastError() ); - todo_wine ok( tmp_mem != mem, "GlobalReAlloc didn't relocate memory\n" ); ptr = GlobalLock( tmp_mem ); ok( !!ptr, "GlobalLock failed, error %lu\n", GetLastError() ); @@ -1856,8 +1855,8 @@ static void test_GlobalAlloc(void) { ok( !is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); if (flags == GMEM_MODIFY) ok( tmp_mem == mem, "GlobalReAlloc returned %p\n", tmp_mem ); - else if (flags != GMEM_MOVEABLE) todo_wine_if(!flags) ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); - else todo_wine ok( tmp_mem != mem, "GlobalReAlloc returned %p\n", tmp_mem ); + else if (flags != GMEM_MOVEABLE) ok( !tmp_mem, "GlobalReAlloc succeeded\n" ); + else ok( tmp_mem != mem, "GlobalReAlloc returned %p\n", tmp_mem ); } else { @@ -1871,7 +1870,7 @@ static void test_GlobalAlloc(void) size = GlobalSize( mem ); if (flags == GMEM_MOVEABLE) ok( size == 0 || broken( size == 1 ) /* w7 */, "GlobalSize returned %Iu\n", size ); - else todo_wine_if(!flags) ok( size == small_size, "GlobalSize returned %Iu\n", size ); + else ok( size == small_size, "GlobalSize returned %Iu\n", size ); mem = GlobalFree( mem ); ok( !mem, "GlobalFree failed, error %lu\n", GetLastError() ); @@ -2429,9 +2428,7 @@ static void test_LocalAlloc(void) ok( size == small_size, "LocalSize returned %Iu\n", size ); SetLastError( 0xdeadbeef ); tmp_mem = LocalReAlloc( mem, small_size, 0 ); - todo_wine ok( !tmp_mem, "LocalReAlloc succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got error %lu\n", GetLastError() ); if (tmp_mem) mem = tmp_mem; tmp_mem = LocalReAlloc( mem, 1024 * 1024, LMEM_MODIFY ); @@ -2447,7 +2444,6 @@ static void test_LocalAlloc(void) ok( !!mem, "LocalAlloc failed, error %lu\n", GetLastError() ); tmp_mem = LocalReAlloc( mem, small_size + 1, LMEM_MOVEABLE ); ok( !!tmp_mem, "LocalReAlloc failed, error %lu\n", GetLastError() ); - todo_wine ok( tmp_mem != mem, "LocalReAlloc didn't relocate memory\n" ); ptr = LocalLock( tmp_mem ); ok( !!ptr, "LocalLock failed, error %lu\n", GetLastError() ); @@ -2540,13 +2536,13 @@ static void test_LocalAlloc(void) tmp_mem = LocalReAlloc( mem, 0, flags ); ok( !is_mem_entry( tmp_mem ), "unexpected moveable %p\n", tmp_mem ); if (flags & LMEM_MODIFY) ok( tmp_mem == mem, "LocalReAlloc returned %p\n", tmp_mem ); - else if (flags != LMEM_MOVEABLE) todo_wine_if(!flags) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); - else todo_wine ok( tmp_mem != mem, "LocalReAlloc returned %p\n", tmp_mem ); + else if (flags != LMEM_MOVEABLE) ok( !tmp_mem, "LocalReAlloc succeeded\n" ); + else ok( tmp_mem != mem, "LocalReAlloc returned %p\n", tmp_mem ); if (tmp_mem) mem = tmp_mem; size = LocalSize( mem ); if (flags == LMEM_MOVEABLE) ok( size == 0 || broken( size == 1 ) /* w7 */, "LocalSize returned %Iu\n", size ); - else todo_wine_if(!flags) ok( size == small_size, "LocalSize returned %Iu\n", size ); + else ok( size == small_size, "LocalSize returned %Iu\n", size ); mem = LocalFree( mem ); ok( !mem, "LocalFree failed, error %lu\n", GetLastError() ); diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 0358ec2748a..636e9d13e3a 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -84,7 +84,7 @@ struct rtl_heap_entry #define REGION_ALIGN 0x10000 #define BLOCK_ALIGN (2 * sizeof(void *)) -struct block +struct DECLSPEC_ALIGN(8) block { /* block size in multiple of BLOCK_ALIGN */ WORD block_size; @@ -104,6 +104,7 @@ C_ASSERT( sizeof(struct block) == 8 ); #define BLOCK_FLAG_PREV_FREE 0x02 #define BLOCK_FLAG_FREE_LINK 0x03 #define BLOCK_FLAG_LARGE 0x04 +#define BLOCK_FLAG_LFH 0x08 /* block is handled by the LFH frontend */ #define BLOCK_FLAG_USER_INFO 0x10 /* user flags up to 0xf0 */ #define BLOCK_FLAG_USER_MASK 0xf0 @@ -261,6 +262,9 @@ struct bin LONG count_alloc; LONG count_freed; LONG enabled; + + /* list of groups with free blocks */ + struct list groups; }; struct heap @@ -1184,7 +1188,9 @@ static BOOL validate_used_block( const struct heap *heap, const SUBHEAP *subheap err = "invalid block size"; else if (block->tail_size > block_get_size( block ) - sizeof(*block)) err = "invalid block unused size"; - else if ((next = next_block( subheap, block )) && (block_get_flags( next ) & BLOCK_FLAG_PREV_FREE)) + else if ((next = next_block( subheap, block )) && (block_get_flags( next ) & BLOCK_FLAG_PREV_FREE) && + /* LFH blocks do not use BLOCK_FLAG_PREV_FREE or back pointer */ + !(block_get_flags( block ) & BLOCK_FLAG_LFH)) err = "invalid next block flags"; else if (block_get_flags( block ) & BLOCK_FLAG_PREV_FREE) { @@ -1321,6 +1327,16 @@ static inline struct block *unsafe_block_from_ptr( struct heap *heap, ULONG flag if ((ULONG_PTR)ptr % BLOCK_ALIGN) err = "invalid ptr alignment"; + else if (block_get_type( block ) == BLOCK_TYPE_DEAD) + err = "delayed freed block"; + else if (block_get_type( block ) == BLOCK_TYPE_FREE) + err = "already freed block"; + else if (block_get_flags( block ) & BLOCK_FLAG_LFH) + { + /* LFH block base_offset points to the group, not the subheap */ + if (block_get_type( block ) != BLOCK_TYPE_USED) + err = "invalid block type"; + } else if ((subheap = block_get_subheap( heap, block )) >= (SUBHEAP *)block) err = "invalid base offset"; else if (block_get_type( block ) == BLOCK_TYPE_USED) @@ -1334,12 +1350,10 @@ static inline struct block *unsafe_block_from_ptr( struct heap *heap, ULONG flag ARENA_LARGE *large = subheap_base( subheap ); if (block != &large->block) err = "invalid large block"; } - else if (block_get_type( block ) == BLOCK_TYPE_DEAD) - err = "delayed freed block"; - else if (block_get_type( block ) == BLOCK_TYPE_FREE) - err = "already freed block"; else + { err = "invalid block type"; + } if (err) WARN( "heap %p, block %p: %s\n", heap, block, err ); return err ? NULL : block; @@ -1522,6 +1536,8 @@ HANDLE WINAPI RtlCreateHeap( ULONG flags, void *addr, SIZE_T total_size, SIZE_T SIZE_T size = sizeof(struct bin) * BLOCK_SIZE_BIN_COUNT; NtAllocateVirtualMemory( NtCurrentProcess(), (void *)&heap->bins, 0, &size, MEM_COMMIT, PAGE_READWRITE ); + for (i = 0; i < BLOCK_SIZE_BIN_COUNT; ++i) + list_init( &heap->bins[i].groups ); } /* link it into the per-process heap list */ @@ -1671,6 +1687,222 @@ static NTSTATUS heap_allocate_block( struct heap *heap, ULONG flags, SIZE_T bloc return STATUS_SUCCESS; } +/* Low Fragmentation Heap frontend */ + +/* header for every LFH block group */ +struct DECLSPEC_ALIGN(BLOCK_ALIGN) group +{ + struct list entry; + /* one bit for each free block and the highest bit for GROUP_FLAG_FREE */ + LONG free_bits; + /* first block of a group, required for alignment */ + struct block first_block; +}; + +#define GROUP_BLOCK_COUNT (sizeof(((struct group *)0)->free_bits) * 8 - 1) +#define GROUP_FLAG_FREE (1u << GROUP_BLOCK_COUNT) +#define GROUP_FREE_BITS_MASK (GROUP_FLAG_FREE - 1) + +static inline UINT block_get_group_index( const struct block *block ) +{ + return block->base_offset; +} + +static inline struct group *block_get_group( const struct block *block ) +{ + SIZE_T block_size = block_get_size( block ); + void *first_block = (char *)block - block_get_group_index( block ) * block_size; + return CONTAINING_RECORD( first_block, struct group, first_block ); +} + +static inline void block_set_group( struct block *block, SIZE_T block_size, const struct group *group ) +{ + SIZE_T offset = (char *)block - (char *)&group->first_block; + block->base_offset = offset / block_size; +} + +static inline struct block *group_get_block( struct group *group, SIZE_T block_size, UINT index ) +{ + char *first_block = (char *)&group->first_block; + return (struct block *)(first_block + index * block_size); +} + +/* lookup a free block using the group free_bits, the current thread must own the group */ +static inline struct block *group_find_free_block( struct group *group, SIZE_T block_size ) +{ + ULONG i, free_bits = group->free_bits; + /* free_bits will never be 0 as the group is unlinked when it's fully used */ + BitScanForward( &i, free_bits ); + group->free_bits &= ~(1 << i); + return group_get_block( group, block_size, i ); +} + +/* allocate a new group block using non-LFH allocation, returns a group owned by current thread */ +static struct group *group_allocate( struct heap *heap, ULONG flags, SIZE_T block_size ) +{ + SIZE_T i, group_size, group_block_size; + struct group *group; + NTSTATUS status; + + group_size = offsetof( struct group, first_block ) + GROUP_BLOCK_COUNT * block_size; + group_block_size = heap_get_block_size( heap, flags, group_size ); + + if (group_block_size >= HEAP_MIN_LARGE_BLOCK_SIZE) + status = heap_allocate_large( heap, flags & ~HEAP_ZERO_MEMORY, group_block_size, group_size, (void **)&group ); + else + status = heap_allocate_block( heap, flags & ~HEAP_ZERO_MEMORY, group_block_size, group_size, (void **)&group ); + + if (status) return NULL; + + block_set_flags( (struct block *)group - 1, 0, BLOCK_FLAG_LFH ); + group->free_bits = ~GROUP_FLAG_FREE; + + for (i = 0; i < GROUP_BLOCK_COUNT; ++i) + { + struct block *block = group_get_block( group, block_size, i ); + valgrind_make_writable( block, sizeof(*block) ); + block_set_type( block, BLOCK_TYPE_FREE ); + block_set_flags( block, ~0, BLOCK_FLAG_FREE | BLOCK_FLAG_LFH ); + block_set_group( block, block_size, group ); + block_set_size( block, block_size ); + mark_block_free( block + 1, (char *)block + block_size - (char *)(block + 1), flags ); + } + + return group; +} + +/* release a fully freed group to the non-LFH subheap, group must be owned by current thread */ +static NTSTATUS group_release( struct heap *heap, ULONG flags, struct bin *bin, struct group *group ) +{ + struct block *block = (struct block *)group - 1; + NTSTATUS status; + + block_set_flags( block, BLOCK_FLAG_LFH, 0 ); + + if (block_get_flags( block ) & BLOCK_FLAG_LARGE) + status = heap_free_large( heap, flags, block ); + else + status = heap_free_block( heap, flags, block ); + + return status; +} + +/* acquire a group from the bin, thread takes ownership of a shared group or allocates a new one */ +static struct group *heap_acquire_bin_group( struct heap *heap, ULONG flags, SIZE_T block_size, struct bin *bin ) +{ + struct group *group; + struct list *entry; + + if ((entry = list_head( &bin->groups ))) + { + group = LIST_ENTRY( entry, struct group, entry ); + list_remove( &group->entry ); + return group; + } + + return group_allocate( heap, flags, block_size ); +} + +/* release a thread owned and fully freed group to the bin shared group, or free its memory */ +static NTSTATUS heap_release_bin_group( struct heap *heap, ULONG flags, struct bin *bin, struct group *group ) +{ + /* try re-using the block group instead of releasing it */ + if (list_empty( &bin->groups )) + { + list_add_tail( &bin->groups, &group->entry ); + return STATUS_SUCCESS; + } + + return group_release( heap, flags, bin, group ); +} + +static struct block *find_free_bin_block( struct heap *heap, ULONG flags, SIZE_T block_size, struct bin *bin ) +{ + struct block *block; + struct group *group; + + /* acquire a group, the thread will own it and no other thread can clear free bits. + * some other thread might still set the free bits if they are freeing blocks. + */ + if (!(group = heap_acquire_bin_group( heap, flags, block_size, bin ))) return NULL; + block = group_find_free_block( group, block_size ); + + /* serialize with heap_free_block_lfh: atomically set GROUP_FLAG_FREE when the free bits are all 0. */ + if (!group->free_bits) + group->free_bits = GROUP_FLAG_FREE; + else + { + /* if GROUP_FLAG_FREE isn't set, thread is responsible for putting it back into group list. */ + list_add_tail( &bin->groups, &group->entry ); + } + + return block; +} + +static NTSTATUS heap_allocate_block_lfh( struct heap *heap, ULONG flags, SIZE_T block_size, + SIZE_T size, void **ret ) +{ + struct bin *bin, *last = heap->bins + BLOCK_SIZE_BIN_COUNT - 1; + struct block *block; + + bin = heap->bins + BLOCK_SIZE_BIN( block_size ); + if (bin == last) return STATUS_UNSUCCESSFUL; + + /* paired with WriteRelease in bin_try_enable. */ + if (!ReadAcquire( &bin->enabled )) return STATUS_UNSUCCESSFUL; + + block_size = BLOCK_BIN_SIZE( BLOCK_SIZE_BIN( block_size ) ); + + heap_lock( heap, flags ); + if ((block = find_free_bin_block( heap, flags, block_size, bin ))) + { + block_set_type( block, BLOCK_TYPE_USED ); + block_set_flags( block, ~BLOCK_FLAG_LFH, BLOCK_USER_FLAGS( flags ) ); + block->tail_size = block_size - sizeof(*block) - size; + initialize_block( block, 0, size, flags ); + mark_block_tail( block, flags ); + *ret = block + 1; + } + heap_unlock( heap, flags ); + + return block ? STATUS_SUCCESS : STATUS_NO_MEMORY; +} + +static NTSTATUS heap_free_block_lfh( struct heap *heap, ULONG flags, struct block *block ) +{ + struct bin *bin, *last = heap->bins + BLOCK_SIZE_BIN_COUNT - 1; + SIZE_T i, block_size = block_get_size( block ); + struct group *group = block_get_group( block ); + NTSTATUS status = STATUS_SUCCESS; + + if (!(block_get_flags( block ) & BLOCK_FLAG_LFH)) return STATUS_UNSUCCESSFUL; + + bin = heap->bins + BLOCK_SIZE_BIN( block_size ); + if (bin == last) return STATUS_UNSUCCESSFUL; + + i = block_get_group_index( block ); + valgrind_make_writable( block, sizeof(*block) ); + block_set_type( block, BLOCK_TYPE_FREE ); + block_set_flags( block, ~BLOCK_FLAG_LFH, BLOCK_FLAG_FREE ); + mark_block_free( block + 1, (char *)block + block_size - (char *)(block + 1), flags ); + + heap_lock( heap, flags ); + + group->free_bits |= (1 << i); + + /* if this was the last used block in a group and GROUP_FLAG_FREE was set */ + if (group->free_bits == (GROUP_FREE_BITS_MASK | GROUP_FLAG_FREE)) + { + /* thread now owns the group, and can release it to its bin */ + group->free_bits = ~GROUP_FLAG_FREE; + status = heap_release_bin_group( heap, flags, bin, group ); + } + + heap_unlock( heap, flags ); + + return status; +} + static void bin_try_enable( struct heap *heap, struct bin *bin ) { ULONG alloc = ReadNoFence( &bin->count_alloc ), freed = ReadNoFence( &bin->count_freed ); @@ -1689,7 +1921,15 @@ static void bin_try_enable( struct heap *heap, struct bin *bin ) RtlSetHeapInformation( heap, HeapCompatibilityInformation, &info, sizeof(info) ); } - WriteNoFence( &bin->enabled, TRUE ); + /* paired with ReadAcquire in heap_allocate_block_lfh. + * + * The acq/rel barrier on the enabled flag is protecting compat_info + * (i.e. compat_info := LFH happens-before enabled := TRUE), so that + * a caller that observes LFH block allocation (alloc request + * succeeds without heap lock) will never observe HEAP_STD when it + * queries the heap. + */ + WriteRelease( &bin->enabled, TRUE ); } /*********************************************************************** @@ -1709,6 +1949,8 @@ void *WINAPI DECLSPEC_HOTPATCH RtlAllocateHeap( HANDLE handle, ULONG flags, SIZE status = STATUS_NO_MEMORY; else if (block_size >= HEAP_MIN_LARGE_BLOCK_SIZE) status = heap_allocate_large( heap, heap_flags, block_size, size, &ptr ); + else if (heap->bins && !heap_allocate_block_lfh( heap, heap_flags, block_size, size, &ptr )) + status = STATUS_SUCCESS; else { heap_lock( heap, heap_flags ); @@ -1753,6 +1995,8 @@ BOOLEAN WINAPI DECLSPEC_HOTPATCH RtlFreeHeap( HANDLE handle, ULONG flags, void * status = heap_free_large( heap, heap_flags, block ); else if (!(block = heap_delay_free( heap, heap_flags, block ))) status = STATUS_SUCCESS; + else if (!heap_free_block_lfh( heap, heap_flags, block )) + status = STATUS_SUCCESS; else { SIZE_T block_size = block_get_size( block ), bin = BLOCK_SIZE_BIN( block_size ); @@ -1832,6 +2076,21 @@ static NTSTATUS heap_resize_block( struct heap *heap, ULONG flags, struct block return STATUS_SUCCESS; } +static NTSTATUS heap_resize_block_lfh( struct block *block, ULONG flags, SIZE_T block_size, SIZE_T size, SIZE_T *old_size, void **ret ) +{ + /* as native LFH does it with different block size: refuse to resize even though we could */ + if (ROUND_SIZE( *old_size, BLOCK_ALIGN - 1) != ROUND_SIZE( size, BLOCK_ALIGN - 1)) return STATUS_NO_MEMORY; + if (size >= *old_size) return STATUS_NO_MEMORY; + + block_set_flags( block, BLOCK_FLAG_USER_MASK & ~BLOCK_FLAG_USER_INFO, BLOCK_USER_FLAGS( flags ) ); + block->tail_size = block_size - sizeof(*block) - size; + initialize_block( block, *old_size, size, flags ); + mark_block_tail( block, flags ); + + *ret = block + 1; + return STATUS_SUCCESS; +} + static NTSTATUS heap_resize_in_place( struct heap *heap, ULONG flags, struct block *block, SIZE_T block_size, SIZE_T size, SIZE_T *old_size, void **ret ) { @@ -1847,6 +2106,9 @@ static NTSTATUS heap_resize_in_place( struct heap *heap, ULONG flags, struct blo if (block_size >= HEAP_MIN_LARGE_BLOCK_SIZE) return STATUS_NO_MEMORY; /* growing small block to large block */ + if (block_get_flags( block ) & BLOCK_FLAG_LFH) + return heap_resize_block_lfh( block, flags, block_size, size, old_size, ret ); + heap_lock( heap, flags ); status = heap_resize_block( heap, flags, block, block_size, size, old_block_size, old_size, ret ); heap_unlock( heap, flags ); From b9ec2df4b821610bfe837426103d063e3417a00b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 10 Feb 2023 08:28:06 +0100 Subject: [PATCH 1064/2777] ntdll: Use atomics and lock-free list for bin groups. (cherry picked from commit 889743154e63766de17bd82489cac5940e81000f) --- dlls/kernel32/tests/heap.c | 1 - dlls/ntdll/heap.c | 50 ++++++++++++++++---------------------- 2 files changed, 21 insertions(+), 30 deletions(-) diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index 8c06e9d5f53..b0b56132393 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -1246,7 +1246,6 @@ static void test_HeapCreate(void) thread_params.flags = 0; SetEvent( thread_params.start_event ); res = WaitForSingleObject( thread_params.ready_event, 100 ); - todo_wine ok( !res, "WaitForSingleObject returned %#lx, error %lu\n", res, GetLastError() ); ret = HeapUnlock( heap ); ok( ret, "HeapUnlock failed, error %lu\n", GetLastError() ); diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 636e9d13e3a..50742a2a51e 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -264,7 +264,7 @@ struct bin LONG enabled; /* list of groups with free blocks */ - struct list groups; + SLIST_HEADER groups; }; struct heap @@ -1537,7 +1537,7 @@ HANDLE WINAPI RtlCreateHeap( ULONG flags, void *addr, SIZE_T total_size, SIZE_T NtAllocateVirtualMemory( NtCurrentProcess(), (void *)&heap->bins, 0, &size, MEM_COMMIT, PAGE_READWRITE ); for (i = 0; i < BLOCK_SIZE_BIN_COUNT; ++i) - list_init( &heap->bins[i].groups ); + RtlInitializeSListHead( &heap->bins[i].groups ); } /* link it into the per-process heap list */ @@ -1692,7 +1692,7 @@ static NTSTATUS heap_allocate_block( struct heap *heap, ULONG flags, SIZE_T bloc /* header for every LFH block group */ struct DECLSPEC_ALIGN(BLOCK_ALIGN) group { - struct list entry; + SLIST_ENTRY entry; /* one bit for each free block and the highest bit for GROUP_FLAG_FREE */ LONG free_bits; /* first block of a group, required for alignment */ @@ -1701,7 +1701,6 @@ struct DECLSPEC_ALIGN(BLOCK_ALIGN) group #define GROUP_BLOCK_COUNT (sizeof(((struct group *)0)->free_bits) * 8 - 1) #define GROUP_FLAG_FREE (1u << GROUP_BLOCK_COUNT) -#define GROUP_FREE_BITS_MASK (GROUP_FLAG_FREE - 1) static inline UINT block_get_group_index( const struct block *block ) { @@ -1730,10 +1729,10 @@ static inline struct block *group_get_block( struct group *group, SIZE_T block_s /* lookup a free block using the group free_bits, the current thread must own the group */ static inline struct block *group_find_free_block( struct group *group, SIZE_T block_size ) { - ULONG i, free_bits = group->free_bits; + ULONG i, free_bits = ReadNoFence( &group->free_bits ); /* free_bits will never be 0 as the group is unlinked when it's fully used */ BitScanForward( &i, free_bits ); - group->free_bits &= ~(1 << i); + InterlockedAnd( &group->free_bits, ~(1 << i) ); return group_get_block( group, block_size, i ); } @@ -1747,11 +1746,15 @@ static struct group *group_allocate( struct heap *heap, ULONG flags, SIZE_T bloc group_size = offsetof( struct group, first_block ) + GROUP_BLOCK_COUNT * block_size; group_block_size = heap_get_block_size( heap, flags, group_size ); + heap_lock( heap, flags ); + if (group_block_size >= HEAP_MIN_LARGE_BLOCK_SIZE) status = heap_allocate_large( heap, flags & ~HEAP_ZERO_MEMORY, group_block_size, group_size, (void **)&group ); else status = heap_allocate_block( heap, flags & ~HEAP_ZERO_MEMORY, group_block_size, group_size, (void **)&group ); + heap_unlock( heap, flags ); + if (status) return NULL; block_set_flags( (struct block *)group - 1, 0, BLOCK_FLAG_LFH ); @@ -1777,6 +1780,8 @@ static NTSTATUS group_release( struct heap *heap, ULONG flags, struct bin *bin, struct block *block = (struct block *)group - 1; NTSTATUS status; + heap_lock( heap, flags ); + block_set_flags( block, BLOCK_FLAG_LFH, 0 ); if (block_get_flags( block ) & BLOCK_FLAG_LARGE) @@ -1784,21 +1789,18 @@ static NTSTATUS group_release( struct heap *heap, ULONG flags, struct bin *bin, else status = heap_free_block( heap, flags, block ); + heap_unlock( heap, flags ); + return status; } /* acquire a group from the bin, thread takes ownership of a shared group or allocates a new one */ static struct group *heap_acquire_bin_group( struct heap *heap, ULONG flags, SIZE_T block_size, struct bin *bin ) { - struct group *group; - struct list *entry; + SLIST_ENTRY *entry; - if ((entry = list_head( &bin->groups ))) - { - group = LIST_ENTRY( entry, struct group, entry ); - list_remove( &group->entry ); - return group; - } + if ((entry = RtlInterlockedPopEntrySList( &bin->groups ))) + return CONTAINING_RECORD( entry, struct group, entry ); return group_allocate( heap, flags, block_size ); } @@ -1807,9 +1809,9 @@ static struct group *heap_acquire_bin_group( struct heap *heap, ULONG flags, SIZ static NTSTATUS heap_release_bin_group( struct heap *heap, ULONG flags, struct bin *bin, struct group *group ) { /* try re-using the block group instead of releasing it */ - if (list_empty( &bin->groups )) + if (!RtlQueryDepthSList( &bin->groups )) { - list_add_tail( &bin->groups, &group->entry ); + RtlInterlockedPushEntrySList( &bin->groups, &group->entry ); return STATUS_SUCCESS; } @@ -1828,12 +1830,10 @@ static struct block *find_free_bin_block( struct heap *heap, ULONG flags, SIZE_T block = group_find_free_block( group, block_size ); /* serialize with heap_free_block_lfh: atomically set GROUP_FLAG_FREE when the free bits are all 0. */ - if (!group->free_bits) - group->free_bits = GROUP_FLAG_FREE; - else + if (ReadNoFence( &group->free_bits ) || InterlockedCompareExchange( &group->free_bits, GROUP_FLAG_FREE, 0 )) { /* if GROUP_FLAG_FREE isn't set, thread is responsible for putting it back into group list. */ - list_add_tail( &bin->groups, &group->entry ); + RtlInterlockedPushEntrySList( &bin->groups, &group->entry ); } return block; @@ -1853,7 +1853,6 @@ static NTSTATUS heap_allocate_block_lfh( struct heap *heap, ULONG flags, SIZE_T block_size = BLOCK_BIN_SIZE( BLOCK_SIZE_BIN( block_size ) ); - heap_lock( heap, flags ); if ((block = find_free_bin_block( heap, flags, block_size, bin ))) { block_set_type( block, BLOCK_TYPE_USED ); @@ -1863,7 +1862,6 @@ static NTSTATUS heap_allocate_block_lfh( struct heap *heap, ULONG flags, SIZE_T mark_block_tail( block, flags ); *ret = block + 1; } - heap_unlock( heap, flags ); return block ? STATUS_SUCCESS : STATUS_NO_MEMORY; } @@ -1886,20 +1884,14 @@ static NTSTATUS heap_free_block_lfh( struct heap *heap, ULONG flags, struct bloc block_set_flags( block, ~BLOCK_FLAG_LFH, BLOCK_FLAG_FREE ); mark_block_free( block + 1, (char *)block + block_size - (char *)(block + 1), flags ); - heap_lock( heap, flags ); - - group->free_bits |= (1 << i); - /* if this was the last used block in a group and GROUP_FLAG_FREE was set */ - if (group->free_bits == (GROUP_FREE_BITS_MASK | GROUP_FLAG_FREE)) + if (InterlockedOr( &group->free_bits, 1 << i ) == ~(1 << i)) { /* thread now owns the group, and can release it to its bin */ group->free_bits = ~GROUP_FLAG_FREE; status = heap_release_bin_group( heap, flags, bin, group ); } - heap_unlock( heap, flags ); - return status; } From b1cec9dc321b6af03ab44fcba04a2231badb485c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 10 Feb 2023 08:10:01 +0100 Subject: [PATCH 1065/2777] ntdll: Add a heap thread affinity and per-affinity bin group cache. (cherry picked from commit 40b7c3e89a95d6ccb190b234d4ad13b3a8304495) --- dlls/ntdll/heap.c | 90 +++++++++++++++++++++++++++++++++++++++-- dlls/ntdll/loader.c | 2 + dlls/ntdll/ntdll_misc.h | 1 + 3 files changed, 89 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 50742a2a51e..a8ee2524c03 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -255,6 +255,9 @@ C_ASSERT( BLOCK_BIN_SIZE( 0x80 ) == ~(SIZE_T)0 ); /* difference between block classes and all possible validation overhead must fit into block tail_size */ C_ASSERT( BIN_SIZE_STEP_7 + 3 * BLOCK_ALIGN <= FIELD_MAX( struct block, tail_size ) ); +static BYTE affinity_mapping[] = {20,6,31,15,14,29,27,4,18,24,26,13,0,9,2,30,17,7,23,25,10,19,12,3,22,21,5,16,1,28,11,8}; +static LONG next_thread_affinity; + /* a bin, tracking heap blocks of a certain size */ struct bin { @@ -265,8 +268,20 @@ struct bin /* list of groups with free blocks */ SLIST_HEADER groups; + + /* array of affinity reserved groups, interleaved with other bins to keep + * all pointers of the same affinity and different bin grouped together, + * and pointers of the same bin and different affinity away from each other, + * hopefully in separate cache lines. + */ + struct group **affinity_group_base; }; +static inline struct group **bin_get_affinity_group( struct bin *bin, BYTE affinity ) +{ + return bin->affinity_group_base + affinity * BLOCK_SIZE_BIN_COUNT; +} + struct heap { /* win32/win64 */ DWORD_PTR unknown1[2]; /* 0000/0000 */ @@ -1533,11 +1548,16 @@ HANDLE WINAPI RtlCreateHeap( ULONG flags, void *addr, SIZE_T total_size, SIZE_T if (heap->flags & HEAP_GROWABLE) { - SIZE_T size = sizeof(struct bin) * BLOCK_SIZE_BIN_COUNT; + SIZE_T size = (sizeof(struct bin) + sizeof(struct group *) * ARRAY_SIZE(affinity_mapping)) * BLOCK_SIZE_BIN_COUNT; NtAllocateVirtualMemory( NtCurrentProcess(), (void *)&heap->bins, 0, &size, MEM_COMMIT, PAGE_READWRITE ); - for (i = 0; i < BLOCK_SIZE_BIN_COUNT; ++i) + + for (i = 0; heap->bins && i < BLOCK_SIZE_BIN_COUNT; ++i) + { RtlInitializeSListHead( &heap->bins[i].groups ); + /* offset affinity_group_base to interleave the bin affinity group pointers */ + heap->bins[i].affinity_group_base = (struct group **)(heap->bins + BLOCK_SIZE_BIN_COUNT) + i; + } } /* link it into the per-process heap list */ @@ -1695,6 +1715,8 @@ struct DECLSPEC_ALIGN(BLOCK_ALIGN) group SLIST_ENTRY entry; /* one bit for each free block and the highest bit for GROUP_FLAG_FREE */ LONG free_bits; + /* affinity of the thread which last allocated from this group */ + LONG affinity; /* first block of a group, required for alignment */ struct block first_block; }; @@ -1794,11 +1816,30 @@ static NTSTATUS group_release( struct heap *heap, ULONG flags, struct bin *bin, return status; } +static inline ULONG heap_current_thread_affinity(void) +{ + ULONG affinity; + + if (!(affinity = NtCurrentTeb()->HeapVirtualAffinity)) + { + affinity = InterlockedIncrement( &next_thread_affinity ); + affinity = affinity_mapping[affinity % ARRAY_SIZE(affinity_mapping)]; + NtCurrentTeb()->HeapVirtualAffinity = affinity; + } + + return affinity; +} + /* acquire a group from the bin, thread takes ownership of a shared group or allocates a new one */ static struct group *heap_acquire_bin_group( struct heap *heap, ULONG flags, SIZE_T block_size, struct bin *bin ) { + ULONG affinity = NtCurrentTeb()->HeapVirtualAffinity; + struct group *group; SLIST_ENTRY *entry; + if ((group = InterlockedExchangePointer( (void *)bin_get_affinity_group( bin, affinity ), NULL ))) + return group; + if ((entry = RtlInterlockedPopEntrySList( &bin->groups ))) return CONTAINING_RECORD( entry, struct group, entry ); @@ -1808,8 +1849,16 @@ static struct group *heap_acquire_bin_group( struct heap *heap, ULONG flags, SIZ /* release a thread owned and fully freed group to the bin shared group, or free its memory */ static NTSTATUS heap_release_bin_group( struct heap *heap, ULONG flags, struct bin *bin, struct group *group ) { + ULONG affinity = group->affinity; + + /* using InterlockedExchangePointer here would possibly return a group that has used blocks, + * we prefer keeping our fully freed group instead for reduced memory consumption. + */ + if (!InterlockedCompareExchangePointer( (void *)bin_get_affinity_group( bin, affinity ), group, NULL )) + return STATUS_SUCCESS; + /* try re-using the block group instead of releasing it */ - if (!RtlQueryDepthSList( &bin->groups )) + if (RtlQueryDepthSList( &bin->groups ) <= ARRAY_SIZE(affinity_mapping)) { RtlInterlockedPushEntrySList( &bin->groups, &group->entry ); return STATUS_SUCCESS; @@ -1820,6 +1869,7 @@ static NTSTATUS heap_release_bin_group( struct heap *heap, ULONG flags, struct b static struct block *find_free_bin_block( struct heap *heap, ULONG flags, SIZE_T block_size, struct bin *bin ) { + ULONG affinity = heap_current_thread_affinity(); struct block *block; struct group *group; @@ -1827,13 +1877,16 @@ static struct block *find_free_bin_block( struct heap *heap, ULONG flags, SIZE_T * some other thread might still set the free bits if they are freeing blocks. */ if (!(group = heap_acquire_bin_group( heap, flags, block_size, bin ))) return NULL; + group->affinity = affinity; + block = group_find_free_block( group, block_size ); /* serialize with heap_free_block_lfh: atomically set GROUP_FLAG_FREE when the free bits are all 0. */ if (ReadNoFence( &group->free_bits ) || InterlockedCompareExchange( &group->free_bits, GROUP_FLAG_FREE, 0 )) { /* if GROUP_FLAG_FREE isn't set, thread is responsible for putting it back into group list. */ - RtlInterlockedPushEntrySList( &bin->groups, &group->entry ); + if ((group = InterlockedExchangePointer( (void *)bin_get_affinity_group( bin, affinity ), group ))) + RtlInterlockedPushEntrySList( &bin->groups, &group->entry ); } return block; @@ -1924,6 +1977,35 @@ static void bin_try_enable( struct heap *heap, struct bin *bin ) WriteRelease( &bin->enabled, TRUE ); } +static void heap_thread_detach_bin_groups( struct heap *heap ) +{ + ULONG i, affinity = NtCurrentTeb()->HeapVirtualAffinity; + + if (!heap->bins) return; + + for (i = 0; i < BLOCK_SIZE_BIN_COUNT; ++i) + { + struct bin *bin = heap->bins + i; + struct group *group; + if (!(group = InterlockedExchangePointer( (void *)bin_get_affinity_group( bin, affinity ), NULL ))) continue; + RtlInterlockedPushEntrySList( &bin->groups, &group->entry ); + } +} + +void heap_thread_detach(void) +{ + struct heap *heap; + + RtlEnterCriticalSection( &process_heap->cs ); + + LIST_FOR_EACH_ENTRY( heap, &process_heap->entry, struct heap, entry ) + heap_thread_detach_bin_groups( heap ); + + heap_thread_detach_bin_groups( process_heap ); + + RtlLeaveCriticalSection( &process_heap->cs ); +} + /*********************************************************************** * RtlAllocateHeap (NTDLL.@) */ diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 4a0d62433ac..14fc568f0d2 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -3841,6 +3841,8 @@ void WINAPI LdrShutdownThread(void) /* don't call DbgUiGetThreadDebugObject as some apps hook it and terminate if called */ if (NtCurrentTeb()->DbgSsReserved[1]) NtClose( NtCurrentTeb()->DbgSsReserved[1] ); RtlFreeThreadActivationContextStack(); + + heap_thread_detach(); } diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index d31358bab58..6b1aaffc167 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -129,5 +129,6 @@ static inline void ascii_to_unicode( WCHAR *dst, const char *src, size_t len ) /* FLS data */ extern TEB_FLS_DATA *fls_alloc_data(void) DECLSPEC_HIDDEN; +extern void heap_thread_detach(void) DECLSPEC_HIDDEN; #endif From 0913f492ebf4fefca70e6cab3b01f442c599732e Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Mon, 10 Apr 2023 17:43:28 +0900 Subject: [PATCH 1066/2777] ntdll: Use log-linear bucketing for free lists. Currently, the free list consists of a "small list" for sizes below 256, which are linearly spaced, and a "large list" which is manually split into a few chunks. This patch replaces it with a single log-linear policy, while expanding the range the large list covers. The old implementation had issues when a lot of large allocations happened. In this case, all the allocations went in the last catch-all bucket in the "large list", and what happens is: 1. The linked list grew in size over time, causing searching cost to skyrocket. 2. With the first-fit allocation policy, fragmentation was also making the problem worse. The new bucketing covers the entire range up until we start allocating large blocks, which will not enter the free list. It also makes the allocation policy closer to best-fit (although not exactly), reducing fragmentation. The increase in number of free lists does incur some cost when it needs to be skipped over, but the improvement in allocation performance outweighs it. For future work, these ideas (mostly from glibc) might or might not benefit performance: - Use an exact best-fit allocation policy. - Add a bitmap for freelist, allowing empty lists to be skipped with a single bit scan. Signed-off-by: Tatsuyuki Ishi (cherry picked from commit a612ab6f2a45bc08f5b39e22edc58bb541b26ae1) --- dlls/kernel32/tests/heap.c | 2 - dlls/ntdll/heap.c | 100 ++++++++++++++++++++++++------------- 2 files changed, 64 insertions(+), 38 deletions(-) diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index b0b56132393..d2742b55495 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -452,9 +452,7 @@ static void test_HeapCreate(void) SetLastError( 0xdeadbeef ); ptr1 = HeapAlloc( heap, 0, alloc_size - (0x200 + 0x80 * sizeof(void *)) ); - todo_wine ok( !ptr1, "HeapAlloc succeeded\n" ); - todo_wine ok( GetLastError() == ERROR_NOT_ENOUGH_MEMORY, "got error %lu\n", GetLastError() ); ret = HeapFree( heap, 0, ptr1 ); ok( ret, "HeapFree failed, error %lu\n", GetLastError() ); diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index a8ee2524c03..0d6ef047ecd 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -146,7 +146,8 @@ C_ASSERT( sizeof(ARENA_LARGE) == 4 * BLOCK_ALIGN ); #define ROUND_ADDR(addr, mask) ((void *)((UINT_PTR)(addr) & ~(UINT_PTR)(mask))) #define ROUND_SIZE(size, mask) ((((SIZE_T)(size) + (mask)) & ~(SIZE_T)(mask))) -#define FIELD_MAX(type, field) (((SIZE_T)1 << (sizeof(((type *)0)->field) * 8)) - 1) +#define FIELD_BITS(type, field) (sizeof(((type *)0)->field) * 8) +#define FIELD_MAX(type, field) (((SIZE_T)1 << FIELD_BITS(type, field)) - 1) #define HEAP_MIN_BLOCK_SIZE ROUND_SIZE(sizeof(struct entry) + BLOCK_ALIGN, BLOCK_ALIGN - 1) @@ -168,17 +169,11 @@ C_ASSERT( HEAP_MAX_FREE_BLOCK_SIZE >= HEAP_MAX_BLOCK_REGION_SIZE ); /* minimum size to start allocating large blocks */ #define HEAP_MIN_LARGE_BLOCK_SIZE (HEAP_MAX_USED_BLOCK_SIZE - 0x1000) -/* There will be a free list bucket for every arena size up to and including this value */ -#define HEAP_MAX_SMALL_FREE_LIST 0x100 -C_ASSERT( HEAP_MAX_SMALL_FREE_LIST % BLOCK_ALIGN == 0 ); -#define HEAP_NB_SMALL_FREE_LISTS (((HEAP_MAX_SMALL_FREE_LIST - HEAP_MIN_BLOCK_SIZE) / BLOCK_ALIGN) + 1) - -/* Max size of the blocks on the free lists above HEAP_MAX_SMALL_FREE_LIST */ -static const SIZE_T free_list_sizes[] = -{ - 0x200, 0x400, 0x1000, ~(SIZE_T)0 -}; -#define HEAP_NB_FREE_LISTS (ARRAY_SIZE(free_list_sizes) + HEAP_NB_SMALL_FREE_LISTS) +#define FREE_LIST_LINEAR_BITS 2 +#define FREE_LIST_LINEAR_MASK ((1 << FREE_LIST_LINEAR_BITS) - 1) +#define FREE_LIST_COUNT ((FIELD_BITS( struct block, block_size ) - FREE_LIST_LINEAR_BITS + 1) * (1 << FREE_LIST_LINEAR_BITS) + 1) +/* for reference, update this when changing parameters */ +C_ASSERT( FREE_LIST_COUNT == 0x3d ); typedef struct DECLSPEC_ALIGN(BLOCK_ALIGN) tagSUBHEAP { @@ -304,7 +299,7 @@ struct heap DWORD pending_pos; /* Position in pending free requests ring */ struct block **pending_free; /* Ring buffer for pending free requests */ RTL_CRITICAL_SECTION cs; - struct entry free_lists[HEAP_NB_FREE_LISTS]; + struct entry free_lists[FREE_LIST_COUNT]; struct bin *bins; SUBHEAP subheap; }; @@ -569,23 +564,6 @@ static void valgrind_notify_free_all( SUBHEAP *subheap, const struct heap *heap #endif } -/* locate a free list entry of the appropriate size */ -/* size is the size of the whole block including the arena header */ -static inline struct entry *find_free_list( struct heap *heap, SIZE_T block_size, BOOL last ) -{ - struct entry *list, *end = heap->free_lists + ARRAY_SIZE(heap->free_lists); - unsigned int i; - - if (block_size <= HEAP_MAX_SMALL_FREE_LIST) - i = (block_size - HEAP_MIN_BLOCK_SIZE) / BLOCK_ALIGN; - else for (i = HEAP_NB_SMALL_FREE_LISTS; i < HEAP_NB_FREE_LISTS - 1; i++) - if (block_size <= free_list_sizes[i - HEAP_NB_SMALL_FREE_LISTS]) break; - - list = heap->free_lists + i; - if (last && ++list == end) list = heap->free_lists; - return list; -} - /* get the memory protection type to use for a given heap */ static inline ULONG get_protection_type( DWORD flags ) { @@ -624,10 +602,60 @@ static void heap_set_status( const struct heap *heap, ULONG flags, NTSTATUS stat if (status) RtlSetLastWin32ErrorAndNtStatusFromNtStatus( status ); } -static size_t get_free_list_block_size( unsigned int index ) +static SIZE_T get_free_list_block_size( unsigned int index ) +{ + DWORD log = index >> FREE_LIST_LINEAR_BITS; + DWORD linear = index & FREE_LIST_LINEAR_MASK; + + if (log == 0) return index * BLOCK_ALIGN; + + return (((1 << FREE_LIST_LINEAR_BITS) + linear) << (log - 1)) * BLOCK_ALIGN; +} + +/* + * Given a size, return its index in the block size list for freelists. + * + * With FREE_LIST_LINEAR_BITS=2, the list looks like this + * (with respect to size / BLOCK_ALIGN): + * 0, + * 1, 2, 3, 4, 5, 6, 7, 8, + * 10, 12, 14, 16, 20, 24, 28, 32, + * 40, 48, 56, 64, 80, 96, 112, 128, + * 160, 192, 224, 256, 320, 384, 448, 512, + * ... + */ +static unsigned int get_free_list_index( SIZE_T block_size ) +{ + DWORD bit, log, linear; + + if (block_size > get_free_list_block_size( FREE_LIST_COUNT - 1 )) + return FREE_LIST_COUNT - 1; + + block_size /= BLOCK_ALIGN; + /* find the highest bit */ + if (!BitScanReverse( &bit, block_size ) || bit < FREE_LIST_LINEAR_BITS) + { + /* for small values, the index is same as block_size. */ + log = 0; + linear = block_size; + } + else + { + /* the highest bit is always set, ignore it and encode the next FREE_LIST_LINEAR_BITS bits + * as a linear scale, combined with the shift as a log scale, in the free list index. */ + log = bit - FREE_LIST_LINEAR_BITS + 1; + linear = (block_size >> (bit - FREE_LIST_LINEAR_BITS)) & FREE_LIST_LINEAR_MASK; + } + + return (log << FREE_LIST_LINEAR_BITS) + linear; +} + +/* locate a free list entry of the appropriate size */ +static inline struct entry *find_free_list( struct heap *heap, SIZE_T block_size, BOOL last ) { - if (index < HEAP_NB_SMALL_FREE_LISTS) return HEAP_MIN_BLOCK_SIZE + index * BLOCK_ALIGN; - return free_list_sizes[index - HEAP_NB_SMALL_FREE_LISTS]; + unsigned int index = get_free_list_index( block_size ); + if (last && ++index == FREE_LIST_COUNT) index = 0; + return &heap->free_lists[index]; } static void heap_dump( const struct heap *heap ) @@ -651,7 +679,7 @@ static void heap_dump( const struct heap *heap ) } TRACE( " free_lists: %p\n", heap->free_lists ); - for (i = 0; i < HEAP_NB_FREE_LISTS; i++) + for (i = 0; i < FREE_LIST_COUNT; i++) TRACE( " %p: size %#8Ix, prev %p, next %p\n", heap->free_lists + i, get_free_list_block_size( i ), LIST_ENTRY( heap->free_lists[i].entry.prev, struct entry, entry ), LIST_ENTRY( heap->free_lists[i].entry.next, struct entry, entry ) ); @@ -1126,7 +1154,7 @@ static BOOL is_valid_free_block( const struct heap *heap, const struct block *bl unsigned int i; if ((subheap = find_subheap( heap, block, FALSE ))) return TRUE; - for (i = 0; i < HEAP_NB_FREE_LISTS; i++) if (block == &heap->free_lists[i].block) return TRUE; + for (i = 0; i < FREE_LIST_COUNT; i++) if (block == &heap->free_lists[i].block) return TRUE; return FALSE; } @@ -1510,7 +1538,7 @@ HANDLE WINAPI RtlCreateHeap( ULONG flags, void *addr, SIZE_T total_size, SIZE_T list_init( &heap->large_list ); list_init( &heap->free_lists[0].entry ); - for (i = 0, entry = heap->free_lists; i < HEAP_NB_FREE_LISTS; i++, entry++) + for (i = 0, entry = heap->free_lists; i < FREE_LIST_COUNT; i++, entry++) { block_set_flags( &entry->block, ~0, BLOCK_FLAG_FREE_LINK ); block_set_size( &entry->block, 0 ); From 53b3b958fff93703e83d35540205add2e5474991 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Wed, 26 Apr 2023 12:18:26 -0400 Subject: [PATCH 1067/2777] uiautomationcore: HACK: Return FALSE from UiaClientsAreListening() when called from EA Launcher. CW-Bug-Id: #22180 --- dlls/uiautomationcore/uia_main.c | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 6818e39951d..9f9b63c2a7b 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -259,12 +259,61 @@ static const IRawElementProviderSimpleVtbl hwnd_host_provider_vtbl = { hwnd_host_provider_get_HostRawElementProvider, }; +static BOOL is_ea_launcher_check(void) +{ + static const WCHAR *names[] = + { + L"\\EADesktop.exe", + L"\\Link2EA.exe", + L"\\EAConnect_microsoft.exe", + L"\\EALaunchHelper.exe", + L"\\EACrashReporter.exe", + L"EA Desktop\\ErrorReporter.exe", + }; + unsigned int i, len; + WCHAR module[256]; + DWORD size; + + if ((size = GetModuleFileNameW( NULL, module, ARRAY_SIZE(module) )) && size < ARRAY_SIZE(module)) + { + for (i = 0; i < ARRAY_SIZE(names); ++i) + { + len = lstrlenW(names[i]); + if (size > len && !memcmp( module + size - len, names[i], len * sizeof(*module) )) + { + FIXME("HACK: Returning FALSE from UiaClientsAreListening for EA launcher.\n"); + return TRUE; + } + } + } + + return FALSE; +} + /*********************************************************************** * UiaClientsAreListening (uiautomationcore.@) */ BOOL WINAPI UiaClientsAreListening(void) { + static BOOL ea_launcher_check_ran; + static BOOL is_ea_launcher; + FIXME("()\n"); + + /* + * HACK: Tell EA Launcher no clients are listening so it doesn't attempt + * to raise an event. Temporarily disabling until the cause of the access + * violation is found. + */ + if (!ea_launcher_check_ran) + { + is_ea_launcher = is_ea_launcher_check(); + ea_launcher_check_ran = TRUE; + } + + if (is_ea_launcher) + return FALSE; + return TRUE; } From 64da7c4c4b7b460f2178f7889762786377abd52b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20=C3=9Cbelacker?= Date: Tue, 11 Jan 2022 22:15:26 +0100 Subject: [PATCH 1068/2777] ntoskrnl: Do not leak memory by setting input buffer to NULL. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52322 (cherry picked from commit 07c0cd6ba5f4b1d6ef738ad7f3cad9992947dd3d) --- dlls/ntoskrnl.exe/ntoskrnl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 945f590c6a4..c841ae67c55 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -842,7 +842,6 @@ static NTSTATUS dispatch_volume( struct dispatch_context *context ) irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread(); irp->Tail.Overlay.OriginalFileObject = file; irp->RequestorMode = UserMode; - context->in_buff = NULL; irp->Flags |= IRP_DEALLOCATE_BUFFER; /* deallocate out_buff */ return dispatch_irp( device, irp, context ); From db9d4549dd4fc28c157b8b8bb17a118ccab03dcd Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 20 Apr 2023 11:43:53 -0600 Subject: [PATCH 1069/2777] fixup! winevulkan: Add support for signalling VkFence from virtualized VkQueues. CW-Bug-Id: #22163 --- dlls/winevulkan/vulkan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 13e6b2fe40e..260f196b81b 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -5328,7 +5328,7 @@ void wine_vkDestroyFence(VkDevice device_handle, VkFence fence_handle, const VkA if (fence->eventfd != -1) close(fence->eventfd); - device->funcs.p_vkDestroyFence(device->device, fence->fence, allocator); + device->funcs.p_vkDestroyFence(device->device, fence->fence, NULL); free(fence); } From 6f11c7e32dc78fc25491695b51eed9a231af2665 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Thu, 27 Apr 2023 17:26:27 +0300 Subject: [PATCH 1070/2777] Revert "ntdll: Guard gdb integration behind WINEDEBUG=+gdb." This reverts commit 3b28570f60280896d034707a89e4480032899670. --- dlls/ntdll/unix/loader.c | 5 +---- dlls/ntdll/unix/virtual.c | 10 +++------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 8833e959283..0a9e16afbbc 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -95,7 +95,6 @@ #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(module); -WINE_DECLARE_DEBUG_CHANNEL(gdb); #ifdef __i386__ static const char so_dir[] = "/i386-unix"; @@ -1532,8 +1531,6 @@ void notify_gdb_native_dll_loaded( void *module, UNICODE_STRING *nt_name ) UNICODE_STRING redir; char *unix_path = NULL; - if (!TRACE_ON(gdb)) return; - InitializeObjectAttributes( &attr, nt_name, OBJ_CASE_INSENSITIVE, 0, 0 ); get_redirect( &attr, &redir ); @@ -1595,7 +1592,7 @@ static NTSTATUS open_builtin_pe_file( const char *name, OBJECT_ATTRIBUTES *attr, { status = virtual_map_builtin_module( mapping, module, size, image_info, zero_bits, machine, prefer_native ); NtClose( mapping ); - if (!status && TRACE_ON(gdb)) notify_gdb_dll_loaded( *module, name ); + if (!status) notify_gdb_dll_loaded( *module, name ); } return status; } diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index c1604b20eb7..22a66f4116d 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -80,7 +80,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(virtual); WINE_DECLARE_DEBUG_CHANNEL(module); WINE_DECLARE_DEBUG_CHANNEL(virtual_ranges); -WINE_DECLARE_DEBUG_CHANNEL(gdb); struct preload_info { @@ -5302,12 +5301,9 @@ static NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr, ULONG flags ) SERVER_END_REQ; if (!status) { - if (TRACE_ON(gdb)) - { - static void (*wine_gdb_dll_unload)( const void *module ); - if (!wine_gdb_dll_unload) wine_gdb_dll_unload = dlsym( RTLD_DEFAULT, "wine_gdb_dll_unload" ); - if (wine_gdb_dll_unload) wine_gdb_dll_unload( view->base ); - } + static void (*wine_gdb_dll_unload)( const void *module ); + if (!wine_gdb_dll_unload) wine_gdb_dll_unload = dlsym( RTLD_DEFAULT, "wine_gdb_dll_unload" ); + if (wine_gdb_dll_unload) wine_gdb_dll_unload( view->base ); if (view->protect & SEC_IMAGE) release_builtin_module( view->base ); if (flags & MEM_PRESERVE_PLACEHOLDER) From 717a16b9604e0d983db9101410e1caac57ce86b8 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Thu, 27 Apr 2023 17:27:20 +0300 Subject: [PATCH 1071/2777] Revert "ntdll: Maintain a PE module link map and expose it to GDB." This reverts commit 5573f048e2f8a3dd7d2999fb801cb19e8bd5f3d0. --- dlls/ntdll/unix/loader.c | 26 ------- dlls/ntdll/unix/unix_private.h | 1 - dlls/ntdll/unix/virtual.c | 5 -- loader/main.c | 123 ++------------------------------- 4 files changed, 4 insertions(+), 151 deletions(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 0a9e16afbbc..845ce39eda0 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -1518,30 +1518,6 @@ static inline char *prepend_build_dir_path( char *ptr, const char *ext, const ch } -static void notify_gdb_dll_loaded( void *module, const char *unix_path ) -{ - static void (*wine_gdb_dll_loaded)( const void *module, const char *unix_path ); - if (!wine_gdb_dll_loaded) wine_gdb_dll_loaded = dlsym( RTLD_DEFAULT, "wine_gdb_dll_loaded" ); - if (wine_gdb_dll_loaded) wine_gdb_dll_loaded( module, unix_path ); -} - -void notify_gdb_native_dll_loaded( void *module, UNICODE_STRING *nt_name ) -{ - OBJECT_ATTRIBUTES attr; - UNICODE_STRING redir; - char *unix_path = NULL; - - InitializeObjectAttributes( &attr, nt_name, OBJ_CASE_INSENSITIVE, 0, 0 ); - get_redirect( &attr, &redir ); - - if (!nt_to_unix_file_name( &attr, &unix_path, FILE_OPEN )) - notify_gdb_dll_loaded( module, unix_path ); - - free( redir.Buffer ); - free( unix_path ); -} - - /*********************************************************************** * open_dll_file * @@ -1592,7 +1568,6 @@ static NTSTATUS open_builtin_pe_file( const char *name, OBJECT_ATTRIBUTES *attr, { status = virtual_map_builtin_module( mapping, module, size, image_info, zero_bits, machine, prefer_native ); NtClose( mapping ); - if (!status) notify_gdb_dll_loaded( *module, name ); } return status; } @@ -1723,7 +1698,6 @@ static NTSTATUS find_builtin_dll( UNICODE_STRING *nt_name, void **module, SIZE_T if (found_image) status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH; WARN( "cannot find builtin library for %s\n", debugstr_us(nt_name) ); - if (!status) notify_gdb_native_dll_loaded( *module, nt_name ); done: if (status >= 0 && ext) { diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 2fb1594acf6..cc5d2d96560 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -168,7 +168,6 @@ extern BOOL is_builtin_path( const UNICODE_STRING *path, WORD *machine ) DECLSPE extern NTSTATUS load_main_exe( const WCHAR *name, const char *unix_name, const WCHAR *curdir, WCHAR **image, void **module ) DECLSPEC_HIDDEN; extern NTSTATUS load_start_exe( WCHAR **image, void **module ) DECLSPEC_HIDDEN; -extern void notify_gdb_native_dll_loaded( void *module, UNICODE_STRING *nt_name ) DECLSPEC_HIDDEN; extern void start_server( BOOL debug ) DECLSPEC_HIDDEN; extern unsigned int server_call_unlocked( void *req_ptr ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 22a66f4116d..4287874b77a 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -2773,7 +2773,6 @@ static unsigned int virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG_P if (res == STATUS_IMAGE_ALREADY_LOADED) res = virtual_map_image( handle, access, addr_ptr, size_ptr, zero_bits, shared_file, alloc_type, image_info, &nt_name, FALSE ); - if (!res || res == STATUS_IMAGE_NOT_AT_BASE) notify_gdb_native_dll_loaded( *addr_ptr, &nt_name ); if (shared_file) NtClose( shared_file ); free( image_info ); return res; @@ -5301,10 +5300,6 @@ static NTSTATUS unmap_view_of_section( HANDLE process, PVOID addr, ULONG flags ) SERVER_END_REQ; if (!status) { - static void (*wine_gdb_dll_unload)( const void *module ); - if (!wine_gdb_dll_unload) wine_gdb_dll_unload = dlsym( RTLD_DEFAULT, "wine_gdb_dll_unload" ); - if (wine_gdb_dll_unload) wine_gdb_dll_unload( view->base ); - if (view->protect & SEC_IMAGE) release_builtin_module( view->base ); if (flags & MEM_PRESERVE_PLACEHOLDER) { diff --git a/loader/main.c b/loader/main.c index 074fb153a94..b7805473da8 100644 --- a/loader/main.c +++ b/loader/main.c @@ -20,13 +20,6 @@ #include "config.h" -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "winnt.h" - #include #include #include @@ -47,8 +40,6 @@ # include #endif -#include "wine/list.h" - #include "main.h" extern char **environ; @@ -60,31 +51,13 @@ struct r_debug *wine_r_debug = NULL; #ifdef __linux__ -struct link_map_entry -{ - struct link_map map; - const void *module; - struct list entry; -}; - -static struct list pe_link_map_entries = LIST_INIT( pe_link_map_entries ); -static struct link_map so_link_map; -static struct link_map pe_link_map = {.l_prev = &so_link_map, .l_name = (char *)""}; static struct link_map so_link_map = {.l_name = (char *)""}; static pthread_mutex_t link_map_lock = PTHREAD_MUTEX_INITIALIZER; -static char *strdup_link_name( const char *path ) -{ - char *real; - if (!path || !(real = realpath( path, NULL ))) return NULL; - if (!strncmp( real, "/run/host", 9 )) memmove( real, real + 9, strlen( real ) - 8 ); - return real; -} - static void sync_wine_link_map(void) { static struct r_debug *_r_debug; - struct link_map *next = &so_link_map, **rtld_map, **wine_map; + struct link_map *next = &so_link_map, *prev = NULL, **rtld_map, **wine_map; if (!_r_debug) _r_debug = dlsym( RTLD_NEXT, "_r_debug" ); rtld_map = &_r_debug->r_map; @@ -92,20 +65,17 @@ static void sync_wine_link_map(void) pthread_mutex_lock( &link_map_lock ); - /* unlink PE link map */ - pe_link_map.l_prev->l_next = NULL; - while (*rtld_map) { if (!*wine_map) { if (!(*wine_map = calloc( 1, sizeof(struct link_map) ))) break; - (*wine_map)->l_prev = pe_link_map.l_prev; + (*wine_map)->l_prev = prev; } - pe_link_map.l_prev = *wine_map; + prev = *wine_map; (*wine_map)->l_addr = (*rtld_map)->l_addr; - (*wine_map)->l_name = strdup_link_name( (*rtld_map)->l_name ); + (*wine_map)->l_name = strdup( (*rtld_map)->l_name ); (*wine_map)->l_ld = (*rtld_map)->l_ld; rtld_map = &(*rtld_map)->l_next; wine_map = &(*wine_map)->l_next; @@ -125,97 +95,12 @@ static void sync_wine_link_map(void) free( prev ); } - /* link PE link map back */ - pe_link_map.l_prev->l_next = &pe_link_map; - pthread_mutex_unlock( &link_map_lock ); if (wine_r_debug) wine_r_debug->r_map = &so_link_map; if (wine_dl_debug_state) wine_dl_debug_state(); } -static void add_dll_to_pe_link_map( const void *module, const char *unix_path ) -{ - const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)module; - const IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)((const BYTE *)dos + dos->e_lfanew); - struct link_map_entry *entry; - struct link_map *map_end; - struct list *tail; - - if (!(entry = calloc( 1, sizeof(*entry) ))) return; - - entry->module = module; - entry->map.l_addr = (char *)module - (char *)nt->OptionalHeader.ImageBase; - entry->map.l_name = strdup_link_name( unix_path ); - - if ((tail = list_tail( &pe_link_map_entries ))) - { - entry->map.l_prev = &LIST_ENTRY( tail, struct link_map_entry, entry )->map; - entry->map.l_prev->l_next = &entry->map; - } - else - { - map_end = &pe_link_map; - while (map_end->l_next) map_end = map_end->l_next; - - map_end->l_next = &entry->map; - map_end->l_next->l_prev = map_end; - } - - list_add_tail( &pe_link_map_entries, &entry->entry ); -} - -void wine_gdb_dll_loaded( const void *module, const char *unix_path ) -{ - struct link_map_entry *entry; - - pthread_mutex_lock( &link_map_lock ); - - LIST_FOR_EACH_ENTRY( entry, &pe_link_map_entries, struct link_map_entry, entry ) - if (entry->module == module) break; - - if (&entry->entry == &pe_link_map_entries) - add_dll_to_pe_link_map( module, unix_path ); - else - { - const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)module; - const IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)((const BYTE *)dos + dos->e_lfanew); - entry->map.l_addr = (char *)module - (char *)nt->OptionalHeader.ImageBase; - } - - pthread_mutex_unlock( &link_map_lock ); - - sync_wine_link_map(); -} - -void wine_gdb_dll_unload( const void *module ) -{ - struct link_map_entry *entry; - - pthread_mutex_lock( &link_map_lock ); - - LIST_FOR_EACH_ENTRY( entry, &pe_link_map_entries, struct link_map_entry, entry ) - if (entry->module == module) break; - - if (&entry->entry == &pe_link_map_entries) - { - pthread_mutex_unlock( &link_map_lock ); - return; - } - - list_remove( &entry->entry ); - - if (entry->map.l_prev) entry->map.l_prev->l_next = entry->map.l_next; - if (entry->map.l_next) entry->map.l_next->l_prev = entry->map.l_prev; - - pthread_mutex_unlock( &link_map_lock ); - - sync_wine_link_map(); - - free( entry->map.l_name ); - free( entry ); -} - void *dlopen( const char *file, int mode ) { static typeof(dlopen) *rtld_dlopen; From fb4ceb17bed733cbabf331402bc3816bd9376f12 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Thu, 27 Apr 2023 17:27:26 +0300 Subject: [PATCH 1072/2777] Revert "ntdll: Pass a UNICODE_STRING to load_builtin and virtual_map_image." This reverts commit 6a3ff7a3980329e53ced560c7a211050cf7d7cde. --- dlls/ntdll/unix/loader.c | 12 +++++----- dlls/ntdll/unix/unix_private.h | 2 +- dlls/ntdll/unix/virtual.c | 40 +++++++++++++++++----------------- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 845ce39eda0..ef38691b15a 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -1715,15 +1715,17 @@ static NTSTATUS find_builtin_dll( UNICODE_STRING *nt_name, void **module, SIZE_T * Load the builtin dll if specified by load order configuration. * Return STATUS_IMAGE_ALREADY_LOADED if we should keep the native one that we have found. */ -NTSTATUS load_builtin( const pe_image_info_t *image_info, UNICODE_STRING *nt_name, +NTSTATUS load_builtin( const pe_image_info_t *image_info, WCHAR *filename, void **module, SIZE_T *size, ULONG_PTR zero_bits ) { WORD machine = image_info->machine; /* request same machine as the native one */ NTSTATUS status; + UNICODE_STRING nt_name; SECTION_IMAGE_INFORMATION info; enum loadorder loadorder; - loadorder = get_load_order( nt_name ); + init_unicode_string( &nt_name, filename ); + loadorder = get_load_order( &nt_name ); if (loadorder == LO_DISABLED) return STATUS_DLL_NOT_FOUND; @@ -1734,7 +1736,7 @@ NTSTATUS load_builtin( const pe_image_info_t *image_info, UNICODE_STRING *nt_nam } else if (image_info->image_flags & IMAGE_FLAGS_WineFakeDll) { - TRACE( "%s is a fake Wine dll\n", debugstr_us(nt_name) ); + TRACE( "%s is a fake Wine dll\n", debugstr_w(filename) ); if (loadorder == LO_NATIVE) return STATUS_DLL_NOT_FOUND; loadorder = LO_BUILTIN; /* builtin with no fallback since mapping a fake dll is not useful */ } @@ -1745,9 +1747,9 @@ NTSTATUS load_builtin( const pe_image_info_t *image_info, UNICODE_STRING *nt_nam case LO_NATIVE_BUILTIN: return STATUS_IMAGE_ALREADY_LOADED; case LO_BUILTIN: - return find_builtin_dll( nt_name, module, size, &info, zero_bits, machine, FALSE ); + return find_builtin_dll( &nt_name, module, size, &info, zero_bits, machine, FALSE ); default: - status = find_builtin_dll( nt_name, module, size, &info, zero_bits, machine, (loadorder == LO_DEFAULT) ); + status = find_builtin_dll( &nt_name, module, size, &info, zero_bits, machine, (loadorder == LO_DEFAULT) ); if (status == STATUS_DLL_NOT_FOUND || status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) return STATUS_IMAGE_ALREADY_LOADED; return status; diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index cc5d2d96560..6df7f9071de 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -162,7 +162,7 @@ extern void *create_startup_info( const UNICODE_STRING *nt_image, const RTL_USER DWORD *info_size ) DECLSPEC_HIDDEN; extern char **build_envp( const WCHAR *envW ) DECLSPEC_HIDDEN; extern NTSTATUS exec_wineloader( char **argv, int socketfd, const pe_image_info_t *pe_info ) DECLSPEC_HIDDEN; -extern NTSTATUS load_builtin( const pe_image_info_t *image_info, UNICODE_STRING *nt_name, +extern NTSTATUS load_builtin( const pe_image_info_t *image_info, WCHAR *filename, void **addr_ptr, SIZE_T *size_ptr, ULONG_PTR zero_bits ) DECLSPEC_HIDDEN; extern BOOL is_builtin_path( const UNICODE_STRING *path, WORD *machine ) DECLSPEC_HIDDEN; extern NTSTATUS load_main_exe( const WCHAR *name, const char *unix_name, const WCHAR *curdir, WCHAR **image, diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 4287874b77a..ddaf643c797 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -2403,7 +2403,7 @@ static NTSTATUS map_pe_header( void *ptr, size_t size, int fd, BOOL *removable ) * Map an executable (PE format) image into an existing view. * virtual_mutex must be held by caller. */ -static NTSTATUS map_image_into_view( struct file_view *view, UNICODE_STRING *nt_name, int fd, void *orig_base, +static NTSTATUS map_image_into_view( struct file_view *view, const WCHAR *filename, int fd, void *orig_base, SIZE_T header_size, ULONG image_flags, int shared_fd, BOOL removable ) { IMAGE_DOS_HEADER *dos; @@ -2419,7 +2419,7 @@ static NTSTATUS map_image_into_view( struct file_view *view, UNICODE_STRING *nt_ char *ptr = view->base; SIZE_T total_size = view->size; - TRACE_(module)( "mapping PE file %s at %p-%p\n", debugstr_us(nt_name), ptr, ptr + total_size ); + TRACE_(module)( "mapping PE file %s at %p-%p\n", debugstr_w(filename), ptr, ptr + total_size ); /* map the header */ @@ -2493,7 +2493,7 @@ static NTSTATUS map_image_into_view( struct file_view *view, UNICODE_STRING *nt_ if (sec->VirtualAddress > total_size || end > total_size || end < sec->VirtualAddress) { WARN_(module)( "%s section %.8s too large (%x+%lx/%lx)\n", - debugstr_us(nt_name), sec->Name, (int)sec->VirtualAddress, map_size, total_size ); + debugstr_w(filename), sec->Name, (int)sec->VirtualAddress, map_size, total_size ); return status; } @@ -2501,13 +2501,13 @@ static NTSTATUS map_image_into_view( struct file_view *view, UNICODE_STRING *nt_ (sec->Characteristics & IMAGE_SCN_MEM_WRITE)) { TRACE_(module)( "%s mapping shared section %.8s at %p off %x (%x) size %lx (%lx) flags %x\n", - debugstr_us(nt_name), sec->Name, ptr + sec->VirtualAddress, + debugstr_w(filename), sec->Name, ptr + sec->VirtualAddress, (int)sec->PointerToRawData, (int)pos, file_size, map_size, (int)sec->Characteristics ); if (map_file_into_view( view, shared_fd, sec->VirtualAddress, map_size, pos, VPROT_COMMITTED | VPROT_READ | VPROT_WRITE, FALSE ) != STATUS_SUCCESS) { - ERR_(module)( "Could not map %s shared section %.8s\n", debugstr_us(nt_name), sec->Name ); + ERR_(module)( "Could not map %s shared section %.8s\n", debugstr_w(filename), sec->Name ); return status; } @@ -2528,7 +2528,7 @@ static NTSTATUS map_image_into_view( struct file_view *view, UNICODE_STRING *nt_ } TRACE_(module)( "mapping %s section %.8s at %p off %x size %x virt %x flags %x\n", - debugstr_us(nt_name), sec->Name, ptr + sec->VirtualAddress, + debugstr_w(filename), sec->Name, ptr + sec->VirtualAddress, (int)sec->PointerToRawData, (int)sec->SizeOfRawData, (int)sec->Misc.VirtualSize, (int)sec->Characteristics ); @@ -2546,7 +2546,7 @@ static NTSTATUS map_image_into_view( struct file_view *view, UNICODE_STRING *nt_ removable ) != STATUS_SUCCESS) { ERR_(module)( "Could not map %s section %.8s, file probably truncated\n", - debugstr_us(nt_name), sec->Name ); + debugstr_w(filename), sec->Name ); return status; } @@ -2582,7 +2582,7 @@ static NTSTATUS map_image_into_view( struct file_view *view, UNICODE_STRING *nt_ if (!set_vprot( view, ptr + sec->VirtualAddress, size, vprot ) && (vprot & VPROT_EXEC)) ERR( "failed to set %08x protection on %s section %.8s, noexec filesystem?\n", - (int)sec->Characteristics, debugstr_us(nt_name), sec->Name ); + (int)sec->Characteristics, debugstr_w(filename), sec->Name ); } #ifdef VALGRIND_LOAD_PDB_DEBUGINFO @@ -2647,7 +2647,7 @@ static unsigned int get_mapping_info( HANDLE handle, ACCESS_MASK access, unsigne */ static NTSTATUS virtual_map_image( HANDLE mapping, ACCESS_MASK access, void **addr_ptr, SIZE_T *size_ptr, ULONG_PTR zero_bits, HANDLE shared_file, ULONG alloc_type, - pe_image_info_t *image_info, UNICODE_STRING *nt_name, BOOL is_builtin ) + pe_image_info_t *image_info, WCHAR *filename, BOOL is_builtin ) { unsigned int vprot = SEC_IMAGE | SEC_FILE | VPROT_COMMITTED | VPROT_READ | VPROT_EXEC | VPROT_WRITECOPY; int unix_fd = -1, needs_close; @@ -2686,7 +2686,7 @@ static NTSTATUS virtual_map_image( HANDLE mapping, ACCESS_MASK access, void **ad if (status) status = map_view( &view, NULL, size, alloc_type & MEM_TOP_DOWN, vprot, get_zero_bits_mask( zero_bits ), 0 ); if (status) goto done; - status = map_image_into_view( view, nt_name, unix_fd, base, image_info->header_size, + status = map_image_into_view( view, filename, unix_fd, base, image_info->header_size, image_info->image_flags, shared_fd, needs_close ); if (status == STATUS_SUCCESS) { @@ -2731,6 +2731,7 @@ static unsigned int virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG_P ACCESS_MASK access; SIZE_T size; pe_image_info_t *image_info = NULL; + WCHAR *filename; void *base; int unix_handle = -1, needs_close; unsigned int vprot, sec_flags; @@ -2766,13 +2767,12 @@ static unsigned int virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG_P if (image_info) { - UNICODE_STRING nt_name; - init_unicode_string( &nt_name, (WCHAR *)(image_info + 1) ); + filename = (WCHAR *)(image_info + 1); /* check if we can replace that mapping with the builtin */ - res = load_builtin( image_info, &nt_name, addr_ptr, size_ptr, zero_bits ); + res = load_builtin( image_info, filename, addr_ptr, size_ptr, zero_bits ); if (res == STATUS_IMAGE_ALREADY_LOADED) res = virtual_map_image( handle, access, addr_ptr, size_ptr, zero_bits, shared_file, - alloc_type, image_info, &nt_name, FALSE ); + alloc_type, image_info, filename, FALSE ); if (shared_file) NtClose( shared_file ); free( image_info ); return res; @@ -3016,8 +3016,8 @@ NTSTATUS virtual_map_builtin_module( HANDLE mapping, void **module, SIZE_T *size HANDLE shared_file; pe_image_info_t *image_info = NULL; ACCESS_MASK access = SECTION_MAP_READ | SECTION_MAP_EXECUTE; - UNICODE_STRING nt_name; NTSTATUS status; + WCHAR *filename; if ((status = get_mapping_info( mapping, access, &sec_flags, &full_size, &shared_file, &image_info ))) return status; @@ -3026,27 +3026,27 @@ NTSTATUS virtual_map_builtin_module( HANDLE mapping, void **module, SIZE_T *size *module = NULL; *size = 0; - init_unicode_string( &nt_name, (WCHAR *)(image_info + 1) ); + filename = (WCHAR *)(image_info + 1); if (!(image_info->image_flags & IMAGE_FLAGS_WineBuiltin)) /* ignore non-builtins */ { - WARN( "%s found in WINEDLLPATH but not a builtin, ignoring\n", debugstr_us(&nt_name) ); + WARN( "%s found in WINEDLLPATH but not a builtin, ignoring\n", debugstr_w(filename) ); status = STATUS_DLL_NOT_FOUND; } else if (machine && image_info->machine != machine) { - TRACE( "%s is for arch %04x, continuing search\n", debugstr_us(&nt_name), image_info->machine ); + TRACE( "%s is for arch %04x, continuing search\n", debugstr_w(filename), image_info->machine ); status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH; } else if (prefer_native && (image_info->dll_charact & IMAGE_DLLCHARACTERISTICS_PREFER_NATIVE)) { - TRACE( "%s has prefer-native flag, ignoring builtin\n", debugstr_us(&nt_name) ); + TRACE( "%s has prefer-native flag, ignoring builtin\n", debugstr_w(filename) ); status = STATUS_IMAGE_ALREADY_LOADED; } else { status = virtual_map_image( mapping, SECTION_MAP_READ | SECTION_MAP_EXECUTE, - module, size, zero_bits, shared_file, 0, image_info, &nt_name, TRUE ); + module, size, zero_bits, shared_file, 0, image_info, filename, TRUE ); virtual_fill_image_information( image_info, info ); } From 6ae3049c0b7b14ccdb0f4947a07cf6add5854446 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Thu, 27 Apr 2023 17:27:33 +0300 Subject: [PATCH 1073/2777] Revert "loader: Expose a shadow copy of ld.so link map to GDB." This reverts commit 0a273e2a86338a94365469238fb73e348ed16338. --- loader/main.c | 88 +--------------------------------------------- loader/preloader.c | 15 -------- 2 files changed, 1 insertion(+), 102 deletions(-) diff --git a/loader/main.c b/loader/main.c index b7805473da8..242ff15accd 100644 --- a/loader/main.c +++ b/loader/main.c @@ -33,99 +33,13 @@ #ifdef HAVE_SYS_SYSCTL_H # include #endif -#ifdef HAVE_LINK_H -# include -#endif -#ifdef HAVE_SYS_LINK_H -# include -#endif #include "main.h" extern char **environ; -/* the preloader will set these variables */ +/* the preloader will set this variable */ const struct wine_preload_info *wine_main_preload_info = NULL; -void (*wine_dl_debug_state)(void) = NULL; -struct r_debug *wine_r_debug = NULL; - -#ifdef __linux__ - -static struct link_map so_link_map = {.l_name = (char *)""}; -static pthread_mutex_t link_map_lock = PTHREAD_MUTEX_INITIALIZER; - -static void sync_wine_link_map(void) -{ - static struct r_debug *_r_debug; - struct link_map *next = &so_link_map, *prev = NULL, **rtld_map, **wine_map; - - if (!_r_debug) _r_debug = dlsym( RTLD_NEXT, "_r_debug" ); - rtld_map = &_r_debug->r_map; - wine_map = &next; - - pthread_mutex_lock( &link_map_lock ); - - while (*rtld_map) - { - if (!*wine_map) - { - if (!(*wine_map = calloc( 1, sizeof(struct link_map) ))) break; - (*wine_map)->l_prev = prev; - } - - prev = *wine_map; - (*wine_map)->l_addr = (*rtld_map)->l_addr; - (*wine_map)->l_name = strdup( (*rtld_map)->l_name ); - (*wine_map)->l_ld = (*rtld_map)->l_ld; - rtld_map = &(*rtld_map)->l_next; - wine_map = &(*wine_map)->l_next; - } - - /* remove the remaining wine entries */ - next = *wine_map; - *wine_map = NULL; - - while (next) - { - struct link_map *prev = next; - wine_map = &next->l_next; - next = *wine_map; - *wine_map = NULL; - free( prev->l_name ); - free( prev ); - } - - pthread_mutex_unlock( &link_map_lock ); - - if (wine_r_debug) wine_r_debug->r_map = &so_link_map; - if (wine_dl_debug_state) wine_dl_debug_state(); -} - -void *dlopen( const char *file, int mode ) -{ - static typeof(dlopen) *rtld_dlopen; - void *ret; - - if (!rtld_dlopen) rtld_dlopen = dlsym( RTLD_NEXT, "dlopen" ); - ret = rtld_dlopen( file, mode ); - - sync_wine_link_map(); - return ret; -} - -int dlclose( void *handle ) -{ - static typeof(dlclose) *rtld_dlclose; - int ret; - - if (!rtld_dlclose) rtld_dlclose = dlsym( RTLD_NEXT, "dlclose" ); - ret = rtld_dlclose( handle ); - - sync_wine_link_map(); - return ret; -} - -#endif /* __linux__ */ /* canonicalize path and return its directory name */ static char *realpath_dirname( const char *name ) diff --git a/loader/preloader.c b/loader/preloader.c index 9fa00786281..72556f09720 100644 --- a/loader/preloader.c +++ b/loader/preloader.c @@ -1362,9 +1362,6 @@ static void set_process_name( int argc, char *argv[] ) for (i = 1; i < argc; i++) argv[i] -= off; } -/* GDB hooks integration */ -struct r_debug _r_debug = {0}; -void _dl_debug_state(void) {} /* * wld_start @@ -1381,8 +1378,6 @@ void* wld_start( void **stack ) struct wld_auxv new_av[8], delete_av[3], *av; struct wld_link_map main_binary_map, ld_so_map; struct wine_preload_info **wine_main_preload_info; - void (**wine_dl_debug_state)(void); - struct r_debug **wine_r_debug; pargc = *stack; argv = (char **)pargc + 1; @@ -1455,16 +1450,6 @@ void* wld_start( void **stack ) if (wine_main_preload_info) *wine_main_preload_info = preload_info; else wld_printf( "wine_main_preload_info not found\n" ); - /* provide r_debug to inform GDB of loaded modules */ - wine_r_debug = find_symbol( &main_binary_map, "wine_r_debug", STT_OBJECT ); - if (wine_r_debug) *wine_r_debug = &_r_debug; - else wld_printf( "wine_r_debug not found\n" ); - - /* provide _dl_debug_state callback to trigger GDB hooks */ - wine_dl_debug_state = find_symbol( &main_binary_map, "wine_dl_debug_state", STT_OBJECT ); - if (wine_dl_debug_state) *wine_dl_debug_state = _dl_debug_state; - else wld_printf( "wine_dl_debug_state not found\n" ); - #define SET_NEW_AV(n,type,val) new_av[n].a_type = (type); new_av[n].a_un.a_val = (val); SET_NEW_AV( 0, AT_PHDR, (unsigned long)main_binary_map.l_phdr ); SET_NEW_AV( 1, AT_PHENT, sizeof(ElfW(Phdr)) ); From c3dea8541bb021d4aae8274f2d602f0aa43c5a45 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 20 Apr 2023 17:58:51 -0600 Subject: [PATCH 1074/2777] ntdll: Mind LFH pending blocks in RtlDestroyHeap(). (cherry picked from commit 74e0c4ce6b8216610f28df6db9bc38014ac871c2) --- dlls/ntdll/heap.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 0d6ef047ecd..c2f5841fe72 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -328,6 +328,8 @@ BOOL delay_heap_free = FALSE; static struct heap *process_heap; /* main process heap */ +static NTSTATUS heap_free_block_lfh( struct heap *heap, ULONG flags, struct block *block ); + /* check if memory range a contains memory range b */ static inline BOOL contains( const void *a, SIZE_T a_size, const void *b, SIZE_T b_size ) { @@ -1642,7 +1644,10 @@ HANDLE WINAPI RtlDestroyHeap( HANDLE handle ) { heap->pending_free = NULL; for (tmp = pending; *tmp && tmp != pending + MAX_FREE_PENDING; ++tmp) + { + if (!heap_free_block_lfh( heap, heap->flags, *tmp )) continue; heap_free_block( heap, heap->flags, *tmp ); + } RtlFreeHeap( handle, 0, pending ); } From cd165953c8b379a78418711f07417022e503c81b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 21 Apr 2023 19:19:20 -0600 Subject: [PATCH 1075/2777] ntdll: Avoid integer overflow in block_get_subheap(). (cherry picked from commit 27c4c64c367f47fe7914c5c87596e6cf3501dbd6) --- dlls/ntdll/heap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index c2f5841fe72..2c3402dd110 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -361,7 +361,7 @@ static inline void block_set_type( struct block *block, UINT type ) static inline SUBHEAP *block_get_subheap( const struct heap *heap, const struct block *block ) { char *offset = ROUND_ADDR( block, REGION_ALIGN - 1 ); - void *base = offset - block->base_offset * REGION_ALIGN; + void *base = offset - (SIZE_T)block->base_offset * REGION_ALIGN; if (base != (void *)heap) return base; else return (SUBHEAP *)&heap->subheap; } From 6927714cd5fcfb521cd5f9db39951ce934a9bddd Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Fri, 27 Jan 2023 13:08:04 +0100 Subject: [PATCH 1076/2777] makedep: Don't output rules for disabled modules. (cherry picked from commit a3932d7deb2d5e489c6195d566b98ee7f8b54af2) --- tools/makedep.c | 63 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/tools/makedep.c b/tools/makedep.c index 6379b5b69d9..76644c84e02 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -2745,7 +2745,8 @@ static void output_source_rc( struct makefile *make, struct incl_file *source, c if (source->file->flags & FLAG_RC_HEADER) return; if (source->file->flags & FLAG_GENERATED) strarray_add( &make->clean_files, source->name ); if (linguas.count && (source->file->flags & FLAG_RC_PO)) po_dir = "po"; - for (arch = 0; arch < archs.count; arch++) strarray_add( &make->res_files[arch], res_file ); + for (arch = 0; arch < archs.count; arch++) + if (!make->disabled[arch]) strarray_add( &make->res_files[arch], res_file ); if (source->file->flags & FLAG_RC_PO) { strarray_add( &make->pot_files, strmake( "%s.pot", obj )); @@ -2782,7 +2783,8 @@ static void output_source_mc( struct makefile *make, struct incl_file *source, c char *obj_path = obj_dir_path( make, obj ); char *res_file = strmake( "%s.res", obj ); - for (arch = 0; arch < archs.count; arch++) strarray_add( &make->res_files[arch], res_file ); + for (arch = 0; arch < archs.count; arch++) + if (!make->disabled[arch]) strarray_add( &make->res_files[arch], res_file ); strarray_add( &make->pot_files, strmake( "%s.pot", obj )); output( "%s.pot %s.res: %s", obj_path, obj_path, source->filename ); output_filename( tools_path( make, "wmc" )); @@ -2807,6 +2809,7 @@ static void output_source_mc( struct makefile *make, struct incl_file *source, c */ static void output_source_res( struct makefile *make, struct incl_file *source, const char *obj ) { + if (make->disabled[source->arch]) return; strarray_add( &make->res_files[source->arch], source->name ); } @@ -2818,6 +2821,7 @@ static void output_source_idl( struct makefile *make, struct incl_file *source, { struct strarray defines = get_source_defines( make, source, obj ); struct strarray headers = empty_strarray; + struct strarray deps = empty_strarray; struct strarray multiarch_targets[MAX_ARCHS] = { empty_strarray }; const char *dest; unsigned int i, arch; @@ -2847,6 +2851,7 @@ static void output_source_idl( struct makefile *make, struct incl_file *source, for (arch = 0; arch < archs.count; arch++) { if (!is_multiarch( arch )) continue; + if (make->disabled[arch]) continue; dest = strmake( "%s%s%s", arch_dirs[arch], obj, idl_outputs[i].ext ); if (!find_src_file( make, dest )) strarray_add( &make->clean_files, dest ); strarray_add( &multiarch_targets[arch], dest ); @@ -2855,9 +2860,12 @@ static void output_source_idl( struct makefile *make, struct incl_file *source, for (arch = 0; arch < archs.count; arch++) { - if (multiarch_targets[arch].count + (arch ? 0 : headers.count) == 0) continue; - if (!arch) output_filenames_obj_dir( make, headers ); - output_filenames_obj_dir( make, multiarch_targets[arch] ); + struct strarray arch_deps = empty_strarray; + + if (!arch) strarray_addall( &arch_deps, headers ); + strarray_addall( &arch_deps, multiarch_targets[arch] ); + if (!arch_deps.count) continue; + output_filenames_obj_dir( make, arch_deps ); output( ":\n" ); output( "\t%s%s -o $@", cmd_prefix( "WIDL" ), tools_path( make, "widl" ) ); output_filenames( target_flags[arch] ); @@ -2868,15 +2876,18 @@ static void output_source_idl( struct makefile *make, struct incl_file *source, output_filenames( get_expanded_file_local_var( make, obj, "EXTRAIDLFLAGS" )); output_filename( source->filename ); output( "\n" ); + strarray_addall( &deps, arch_deps ); } - output_filenames_obj_dir( make, headers ); - for (arch = 0; arch < archs.count; arch++) output_filenames_obj_dir( make, multiarch_targets[arch] ); - output( ":" ); - output_filename( tools_path( make, "widl" )); - output_filename( source->filename ); - output_filenames( source->dependencies ); - output( "\n" ); + if (deps.count) + { + output_filenames_obj_dir( make, deps ); + output( ":" ); + output_filename( tools_path( make, "widl" )); + output_filename( source->filename ); + output_filenames( source->dependencies ); + output( "\n" ); + } if (source->importlibdeps.count) { @@ -3125,6 +3136,8 @@ static void output_source_one_arch( struct makefile *make, struct incl_file *sou { const char *obj_name; + if (make->disabled[arch] && !(source->file->flags & FLAG_C_IMPLIB)) return; + if (arch) { if (source->file->flags & FLAG_C_UNIX) return; @@ -3264,6 +3277,8 @@ static void output_fake_module( struct makefile *make ) unsigned int arch = 0; /* fake modules are always native */ const char *spec_file = NULL, *name = strmake( "%s%s", arch_pe_dirs[arch], make->module ); + if (make->disabled[arch]) return; + if (!make->is_exe) spec_file = src_dir_path( make, replace_extension( make->module, ".dll", ".spec" )); strarray_add( &make->all_targets[arch], name ); @@ -3302,6 +3317,8 @@ static void output_module( struct makefile *make, unsigned int arch ) char *spec_file = NULL; unsigned int i; + if (make->disabled[arch]) return; + if (!make->is_exe) spec_file = src_dir_path( make, replace_extension( make->module, ".dll", ".spec" )); if (!make->data_only) @@ -3407,6 +3424,8 @@ static void output_unix_lib( struct makefile *make ) struct strarray unix_libs = add_unix_libraries( make, &unix_deps ); unsigned int arch = 0; /* unix libs are always native */ + if (make->disabled[arch]) return; + strarray_add( &make->all_targets[arch], make->unixlib ); add_install_rule( make, make->module, arch, make->unixlib, strmake( "p%s%s", arch_install_dirs[arch], make->unixlib )); @@ -4041,16 +4060,6 @@ static void output_stub_makefile( struct makefile *make ) const char *make_var = strarray_get_value( &top_makefile->vars, "MAKE" ); unsigned int i, arch; - if (make->obj_dir) create_dir( make->obj_dir ); - - output_file_name = obj_dir_path( make, "Makefile" ); - output_file = create_temp_file( output_file_name ); - - output( "# Auto-generated stub makefile; all rules forward to the top-level makefile\n\n" ); - - if (make_var) output( "MAKE = %s\n\n", make_var ); - output( "all:\n" ); - for (arch = 0; arch < archs.count; arch++) if (make->all_targets[arch].count) strarray_add_uniq( &targets, "all" ); @@ -4068,6 +4077,16 @@ static void output_stub_makefile( struct makefile *make ) strarray_add( &targets, "testclean" ); } + if (!targets.count && !make->clean_files.count) return; + + output_file_name = obj_dir_path( make, "Makefile" ); + output_file = create_temp_file( output_file_name ); + + output( "# Auto-generated stub makefile; all rules forward to the top-level makefile\n\n" ); + + if (make_var) output( "MAKE = %s\n\n", make_var ); + + output( "all:\n" ); output_filenames( targets ); output_filenames( make->clean_files ); output( ":\n" ); From 7daa5ec867d9684ae5ab496a354369a3103385c8 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 22 Feb 2023 21:04:35 +0100 Subject: [PATCH 1077/2777] makedep: Don't add dependencies for tests of disabled dlls. (cherry picked from commit 8670876db9b7b918cb7893a16d7edde6b40a607a) --- tools/makedep.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/makedep.c b/tools/makedep.c index 76644c84e02..3dd58428c99 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -3559,6 +3559,11 @@ static void output_test_module( struct makefile *make, unsigned int arch ) output( "\t%secho \"%s_test.exe TESTRES \\\"%s\\\"\" | %s -u -o $@\n", cmd_prefix( "WRC" ), basemodule, obj_dir_path( make, stripped ), tools_path( make, "wrc" )); + if (make->disabled[arch] || (parent && parent->disabled[arch])) + { + make->ok_files = empty_strarray; + return; + } output_filenames_obj_dir( make, make->ok_files ); output( ": %s", obj_dir_path( make, testmodule )); if (parent) @@ -3569,8 +3574,7 @@ static void output_test_module( struct makefile *make, unsigned int arch ) } output( "\n" ); output( "%s %s:", obj_dir_path( make, "check" ), obj_dir_path( make, "test" )); - if (!make->disabled[arch] && parent && !parent->disabled[arch]) - output_filenames_obj_dir( make, make->ok_files ); + output_filenames_obj_dir( make, make->ok_files ); output( "\n" ); strarray_add_uniq( &make->phony_targets, obj_dir_path( make, "check" )); strarray_add_uniq( &make->phony_targets, obj_dir_path( make, "test" )); From d042e6540686c257a95dda3051a6f1c3cce6c6fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 21 Jan 2023 21:42:10 +0100 Subject: [PATCH 1078/2777] dinput: Remove outdated and superfluous comments. (cherry picked from commit 1b3fab9bd4995c40b471748d006611d6eee4fc47) --- dlls/dinput/device.c | 42 ------------------------------------ dlls/dinput/device_private.h | 3 --- dlls/dinput/dinput_main.c | 39 --------------------------------- dlls/dinput/dinput_private.h | 1 - dlls/dinput/mouse.c | 6 ++---- 5 files changed, 2 insertions(+), 89 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 590151483c9..e53940a2e3b 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -19,12 +19,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -/* This file contains all the Device specific functions that can be used as stubs - by real device implementations. - - It also contains all the helper functions. -*/ - #include #include #include @@ -87,9 +81,6 @@ static inline BOOL is_exclusively_acquired( struct dinput_device *device ) return device->status == STATUS_ACQUIRED && (device->dwCoopLevel & DISCL_EXCLUSIVE); } -/****************************************************************************** - * Various debugging tools - */ static void _dump_cooperativelevel_DI(DWORD dwFlags) { if (TRACE_ON(dinput)) { unsigned int i; @@ -113,9 +104,6 @@ static void _dump_cooperativelevel_DI(DWORD dwFlags) { } } -/****************************************************************************** - * Get the default and the app-specific config keys. - */ BOOL get_app_key(HKEY *defkey, HKEY *appkey) { char buffer[MAX_PATH+16]; @@ -148,9 +136,6 @@ BOOL get_app_key(HKEY *defkey, HKEY *appkey) return *defkey || *appkey; } -/****************************************************************************** - * Get a config key from either the app-specific or the default config - */ DWORD get_config_key( HKEY defkey, HKEY appkey, const WCHAR *name, WCHAR *buffer, DWORD size ) { if (appkey && !RegQueryValueExW( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0; @@ -507,10 +492,6 @@ static BOOL set_app_data( struct dinput_device *dev, int offset, UINT_PTR app_da return TRUE; } -/****************************************************************************** - * queue_event - add new event to the ring queue - */ - void queue_event( IDirectInputDevice8W *iface, int inst_id, DWORD data, DWORD time, DWORD seq ) { static ULONGLONG notify_ms = 0; @@ -561,10 +542,6 @@ void queue_event( IDirectInputDevice8W *iface, int inst_id, DWORD data, DWORD ti /* Send event if asked */ } -/****************************************************************************** - * Acquire - */ - static HRESULT WINAPI dinput_device_Acquire( IDirectInputDevice8W *iface ) { struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); @@ -593,10 +570,6 @@ static HRESULT WINAPI dinput_device_Acquire( IDirectInputDevice8W *iface ) return hr; } -/****************************************************************************** - * Unacquire - */ - static HRESULT WINAPI dinput_device_Unacquire( IDirectInputDevice8W *iface ) { struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); @@ -617,10 +590,6 @@ static HRESULT WINAPI dinput_device_Unacquire( IDirectInputDevice8W *iface ) return hr; } -/****************************************************************************** - * IDirectInputDeviceA - */ - static HRESULT WINAPI dinput_device_SetDataFormat( IDirectInputDevice8W *iface, const DIDATAFORMAT *format ) { struct dinput_device *This = impl_from_IDirectInputDevice8W( iface ); @@ -653,11 +622,6 @@ static HRESULT WINAPI dinput_device_SetDataFormat( IDirectInputDevice8W *iface, return res; } -/****************************************************************************** - * SetCooperativeLevel - * - * Set cooperative level and the source window for the events. - */ static HRESULT WINAPI dinput_device_SetCooperativeLevel( IDirectInputDevice8W *iface, HWND hwnd, DWORD flags ) { struct dinput_device *This = impl_from_IDirectInputDevice8W( iface ); @@ -685,7 +649,6 @@ static HRESULT WINAPI dinput_device_SetCooperativeLevel( IDirectInputDevice8W *i (IsEqualGUID( &This->guid, &GUID_SysMouse ) || IsEqualGUID( &This->guid, &GUID_SysKeyboard ))) return DIERR_UNSUPPORTED; - /* Store the window which asks for the mouse */ EnterCriticalSection(&This->crit); if (This->status == STATUS_ACQUIRED) hr = DIERR_ACQUIRED; else @@ -718,9 +681,6 @@ static HRESULT WINAPI dinput_device_GetDeviceInfo( IDirectInputDevice8W *iface, return S_OK; } -/****************************************************************************** - * SetEventNotification : specifies event to be sent on state change - */ static HRESULT WINAPI dinput_device_SetEventNotification( IDirectInputDevice8W *iface, HANDLE event ) { struct dinput_device *This = impl_from_IDirectInputDevice8W( iface ); @@ -742,11 +702,9 @@ void dinput_device_destroy( IDirectInputDevice8W *iface ) free( This->object_properties ); free( This->data_queue ); - /* Free data format */ free( This->device_format.rgodf ); dinput_device_release_user_format( This ); - /* Free action mapping */ free( This->action_map ); IDirectInput_Release(&This->dinput->IDirectInput7A_iface); diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h index be5d7861fd1..45250ed082b 100644 --- a/dlls/dinput/device_private.h +++ b/dlls/dinput/device_private.h @@ -77,7 +77,6 @@ enum device_status STATUS_UNPLUGGED, }; -/* Device implementation */ struct dinput_device { IDirectInputDevice8W IDirectInputDevice8W_iface; @@ -132,8 +131,6 @@ extern void dinput_device_destroy( IDirectInputDevice8W *iface ); extern BOOL get_app_key(HKEY*, HKEY*) DECLSPEC_HIDDEN; extern DWORD get_config_key( HKEY, HKEY, const WCHAR *, WCHAR *, DWORD ) DECLSPEC_HIDDEN; extern BOOL device_instance_is_disabled( DIDEVICEINSTANCEW *instance, BOOL *override ) DECLSPEC_HIDDEN; - -/* Routines to do DataFormat / WineFormat conversions */ extern void queue_event( IDirectInputDevice8W *iface, int inst_id, DWORD data, DWORD time, DWORD seq ) DECLSPEC_HIDDEN; extern const GUID dinput_pidvid_guid DECLSPEC_HIDDEN; diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 8fc593f37e2..c149156bf23 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -20,15 +20,6 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -/* Status: - * - * - Tomb Raider 2 Demo: - * Playable using keyboard only. - * - WingCommander Prophecy Demo: - * Doesn't get Input Focus. - * - * - Fallout : works great in X and DGA mode - */ #include #include @@ -157,9 +148,6 @@ static HRESULT dinput_create( IUnknown **out ) return DI_OK; } -/****************************************************************************** - * DirectInputCreateEx (DINPUT.@) - */ HRESULT WINAPI DirectInputCreateEx( HINSTANCE hinst, DWORD version, REFIID iid, void **out, IUnknown *outer ) { IUnknown *unknown; @@ -190,9 +178,6 @@ HRESULT WINAPI DirectInputCreateEx( HINSTANCE hinst, DWORD version, REFIID iid, return DI_OK; } -/****************************************************************************** - * DirectInput8Create (DINPUT8.@) - */ HRESULT WINAPI DECLSPEC_HOTPATCH DirectInput8Create( HINSTANCE hinst, DWORD version, REFIID iid, void **out, IUnknown *outer ) { IUnknown *unknown; @@ -225,17 +210,11 @@ HRESULT WINAPI DECLSPEC_HOTPATCH DirectInput8Create( HINSTANCE hinst, DWORD vers return S_OK; } -/****************************************************************************** - * DirectInputCreateA (DINPUT.@) - */ HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateA( HINSTANCE hinst, DWORD version, IDirectInputA **out, IUnknown *outer ) { return DirectInputCreateEx( hinst, version, &IID_IDirectInput7A, (void **)out, outer ); } -/****************************************************************************** - * DirectInputCreateW (DINPUT.@) - */ HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateW( HINSTANCE hinst, DWORD version, IDirectInputW **out, IUnknown *outer ) { return DirectInputCreateEx( hinst, version, &IID_IDirectInput7W, (void **)out, outer ); @@ -287,9 +266,6 @@ __ASM_GLOBAL_FUNC( enum_callback_wrapper, #define enum_callback_wrapper(callback, instance, ref) (callback)((instance), (ref)) #endif -/****************************************************************************** - * IDirectInputW_EnumDevices - */ static HRESULT WINAPI dinput7_EnumDevices( IDirectInput7W *iface, DWORD type, LPDIENUMDEVICESCALLBACKW callback, void *context, DWORD flags ) { @@ -563,10 +539,6 @@ static HRESULT WINAPI dinput7_CreateDevice( IDirectInput7W *iface, const GUID *g return IDirectInput7_CreateDeviceEx( iface, guid, &IID_IDirectInputDeviceW, (void **)out, outer ); } -/******************************************************************************* - * DirectInput8 - */ - static ULONG WINAPI dinput8_AddRef( IDirectInput8W *iface ) { struct dinput *impl = impl_from_IDirectInput8W( iface ); @@ -842,10 +814,6 @@ static HRESULT WINAPI dinput8_ConfigureDevices( IDirectInput8W *iface, LPDICONFI return _configure_devices( iface, callback, params, flags, context ); } -/***************************************************************************** - * IDirectInputJoyConfig8 interface - */ - static inline struct dinput *impl_from_IDirectInputJoyConfig8( IDirectInputJoyConfig8 *iface ) { return CONTAINING_RECORD( iface, struct dinput, IDirectInputJoyConfig8_iface ); @@ -1124,9 +1092,6 @@ static const IClassFactoryVtbl class_factory_vtbl = static struct class_factory class_factory = {{&class_factory_vtbl}}; -/*********************************************************************** - * DllGetClassObject (DINPUT.@) - */ HRESULT WINAPI DllGetClassObject( REFCLSID clsid, REFIID iid, void **out ) { TRACE( "clsid %s, iid %s, out %p.\n", debugstr_guid( clsid ), debugstr_guid( iid ), out ); @@ -1143,10 +1108,6 @@ HRESULT WINAPI DllGetClassObject( REFCLSID clsid, REFIID iid, void **out ) return CLASS_E_CLASSNOTAVAILABLE; } -/****************************************************************************** - * DInput hook thread - */ - static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam ) { struct dinput_device *impl; diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h index 3e61d940005..ae5c3e6ceef 100644 --- a/dlls/dinput/dinput_private.h +++ b/dlls/dinput/dinput_private.h @@ -29,7 +29,6 @@ extern HINSTANCE DINPUT_instance; -/* Implementation specification */ struct dinput { IDirectInput7A IDirectInput7A_iface; diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c index ee172547a30..6aab20a631c 100644 --- a/dlls/dinput/mouse.c +++ b/dlls/dinput/mouse.c @@ -256,7 +256,6 @@ void dinput_mouse_rawinput_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPA LeaveCriticalSection( &impl->base.crit ); } -/* low-level mouse hook */ int dinput_mouse_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lparam ) { MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam; @@ -416,7 +415,6 @@ static HRESULT mouse_acquire( IDirectInputDevice8W *iface ) DIMOUSESTATE2 *state = (DIMOUSESTATE2 *)impl->base.device_state; POINT point; - /* Init the mouse state */ GetCursorPos( &point ); if (impl->base.user_format.dwFlags & DIDF_ABSAXIS) { @@ -436,7 +434,7 @@ static HRESULT mouse_acquire( IDirectInputDevice8W *iface ) if (impl->base.dwCoopLevel & DISCL_EXCLUSIVE) { - ShowCursor( FALSE ); /* hide cursor */ + ShowCursor( FALSE ); warp_check( impl, TRUE ); } else if (impl->warp_override == WARP_FORCE_ON) @@ -461,7 +459,7 @@ static HRESULT mouse_unacquire( IDirectInputDevice8W *iface ) if (impl->base.dwCoopLevel & DISCL_EXCLUSIVE) { ClipCursor( NULL ); - ShowCursor( TRUE ); /* show cursor */ + ShowCursor( TRUE ); impl->clipped = FALSE; } From 173c8b430059b37174745b1c6e6cbf133f25471c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 21 Jan 2023 21:46:22 +0100 Subject: [PATCH 1079/2777] dinput: Add traces to the ANSI wrappers. (cherry picked from commit 21fa1be53b7309db85eb5993736da3e687fd4552) --- dlls/dinput/ansi.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/dlls/dinput/ansi.c b/dlls/dinput/ansi.c index 99ec3c73327..a9e948c97a4 100644 --- a/dlls/dinput/ansi.c +++ b/dlls/dinput/ansi.c @@ -33,6 +33,8 @@ #include "wine/debug.h" +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + static struct dinput_device *impl_from_IDirectInputDevice8A( IDirectInputDevice8A *iface ) { return CONTAINING_RECORD( iface, struct dinput_device, IDirectInputDevice8A_iface ); @@ -270,6 +272,7 @@ static HRESULT WINAPI dinput_device_a_QueryInterface( IDirectInputDevice8A *ifac { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, iid %s, out %p.\n", impl, debugstr_guid( iid ), out ); return IDirectInputDevice8_QueryInterface( iface_w, iid, out ); } @@ -277,6 +280,7 @@ static ULONG WINAPI dinput_device_a_AddRef( IDirectInputDevice8A *iface_a ) { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p.\n", impl ); return IDirectInputDevice8_AddRef( iface_w ); } @@ -284,6 +288,7 @@ static ULONG WINAPI dinput_device_a_Release( IDirectInputDevice8A *iface_a ) { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p.\n", impl ); return IDirectInputDevice8_Release( iface_w ); } @@ -291,6 +296,7 @@ static HRESULT WINAPI dinput_device_a_GetCapabilities( IDirectInputDevice8A *ifa { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, caps %p.\n", impl, caps ); return IDirectInputDevice8_GetCapabilities( iface_w, caps ); } @@ -316,6 +322,8 @@ static HRESULT WINAPI dinput_device_a_EnumObjects( IDirectInputDevice8A *iface_a struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, callback %p, ref %p, flags %#lx.\n", impl, callback, ref, flags ); + if (!callback) return DIERR_INVALIDPARAM; return IDirectInputDevice8_EnumObjects( iface_w, enum_objects_wtoa_callback, ¶ms, flags ); @@ -325,6 +333,7 @@ static HRESULT WINAPI dinput_device_a_GetProperty( IDirectInputDevice8A *iface_a { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, guid %s, header %p.\n", impl, debugstr_guid( guid ), header ); return IDirectInputDevice8_GetProperty( iface_w, guid, header ); } @@ -332,6 +341,7 @@ static HRESULT WINAPI dinput_device_a_SetProperty( IDirectInputDevice8A *iface_a { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, guid %s, header %p.\n", impl, debugstr_guid( guid ), header ); return IDirectInputDevice8_SetProperty( iface_w, guid, header ); } @@ -339,6 +349,7 @@ static HRESULT WINAPI dinput_device_a_Acquire( IDirectInputDevice8A *iface_a ) { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p.\n", impl ); return IDirectInputDevice8_Acquire( iface_w ); } @@ -346,6 +357,7 @@ static HRESULT WINAPI dinput_device_a_Unacquire( IDirectInputDevice8A *iface_a ) { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p.\n", impl ); return IDirectInputDevice8_Unacquire( iface_w ); } @@ -353,6 +365,7 @@ static HRESULT WINAPI dinput_device_a_GetDeviceState( IDirectInputDevice8A *ifac { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, count %#lx, data %p.\n", impl, count, data ); return IDirectInputDevice8_GetDeviceState( iface_w, count, data ); } @@ -361,6 +374,7 @@ static HRESULT WINAPI dinput_device_a_GetDeviceData( IDirectInputDevice8A *iface { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, data_size %#lx, data %p, entries %p, flags %#lx.\n", impl, data_size, data, entries, flags ); return IDirectInputDevice8_GetDeviceData( iface_w, data_size, data, entries, flags ); } @@ -368,6 +382,7 @@ static HRESULT WINAPI dinput_device_a_SetDataFormat( IDirectInputDevice8A *iface { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, format %p.\n", impl, format ); return IDirectInputDevice8_SetDataFormat( iface_w, format ); } @@ -375,6 +390,7 @@ static HRESULT WINAPI dinput_device_a_SetEventNotification( IDirectInputDevice8A { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, event %p.\n", impl, event ); return IDirectInputDevice8_SetEventNotification( iface_w, event ); } @@ -382,6 +398,7 @@ static HRESULT WINAPI dinput_device_a_SetCooperativeLevel( IDirectInputDevice8A { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, window %p, flags %#lx.\n", impl, window, flags ); return IDirectInputDevice8_SetCooperativeLevel( iface_w, window, flags ); } @@ -393,6 +410,8 @@ static HRESULT WINAPI dinput_device_a_GetObjectInfo( IDirectInputDevice8A *iface DIDEVICEOBJECTINSTANCEW instance_w = {sizeof(instance_w)}; HRESULT hr; + TRACE( "impl %p, instance_a %p, obj %#lx, how %#lx.\n", impl, instance_a, obj, how ); + if (!instance_a) return E_POINTER; if (instance_a->dwSize != sizeof(DIDEVICEOBJECTINSTANCEA) && instance_a->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3A)) @@ -411,6 +430,8 @@ static HRESULT WINAPI dinput_device_a_GetDeviceInfo( IDirectInputDevice8A *iface DIDEVICEINSTANCEW instance_w = {sizeof(instance_w)}; HRESULT hr; + TRACE( "impl %p, instance_a %p.\n", impl, instance_a ); + if (!instance_a) return E_POINTER; if (instance_a->dwSize != sizeof(DIDEVICEINSTANCEA) && instance_a->dwSize != sizeof(DIDEVICEINSTANCE_DX3A)) return DIERR_INVALIDPARAM; @@ -425,6 +446,7 @@ static HRESULT WINAPI dinput_device_a_RunControlPanel( IDirectInputDevice8A *ifa { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, owner %p, flags %#lx.\n", impl, owner, flags ); return IDirectInputDevice8_RunControlPanel( iface_w, owner, flags ); } @@ -432,6 +454,7 @@ static HRESULT WINAPI dinput_device_a_Initialize( IDirectInputDevice8A *iface_a, { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, instance %p, version %#lx, guid %s.\n", impl, instance, version, debugstr_guid( guid ) ); return IDirectInputDevice8_Initialize( iface_w, instance, version, guid ); } @@ -440,6 +463,7 @@ static HRESULT WINAPI dinput_device_a_CreateEffect( IDirectInputDevice8A *iface_ { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, guid %s, effect %p, out %p, outer %p.\n", impl, debugstr_guid( guid ), effect, out, outer ); return IDirectInputDevice8_CreateEffect( iface_w, guid, effect, out, outer ); } @@ -465,6 +489,8 @@ static HRESULT WINAPI dinput_device_a_EnumEffects( IDirectInputDevice8A *iface_a struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, callback %p, ref %p, type %#lx.\n", impl, callback, ref, type ); + if (!callback) return DIERR_INVALIDPARAM; return IDirectInputDevice8_EnumEffects( iface_w, enum_effects_wtoa_callback, ¶ms, type ); @@ -477,6 +503,8 @@ static HRESULT WINAPI dinput_device_a_GetEffectInfo( IDirectInputDevice8A *iface DIEFFECTINFOW info_w = {sizeof(info_w)}; HRESULT hr; + TRACE( "impl %p, info_a %p, guid %s.\n", impl, info_a, debugstr_guid( guid ) ); + if (!info_a) return E_POINTER; if (info_a->dwSize != sizeof(DIEFFECTINFOA)) return DIERR_INVALIDPARAM; @@ -490,6 +518,7 @@ static HRESULT WINAPI dinput_device_a_GetForceFeedbackState( IDirectInputDevice8 { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, state %p.\n", impl, state ); return IDirectInputDevice8_GetForceFeedbackState( iface_w, state ); } @@ -497,6 +526,7 @@ static HRESULT WINAPI dinput_device_a_SendForceFeedbackCommand( IDirectInputDevi { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, flags %#lx.\n", impl, flags ); return IDirectInputDevice8_SendForceFeedbackCommand( iface_w, flags ); } @@ -505,6 +535,7 @@ static HRESULT WINAPI dinput_device_a_EnumCreatedEffectObjects( IDirectInputDevi { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, callback %p, ref %p, flags %#lx.\n", impl, callback, ref, flags ); return IDirectInputDevice8_EnumCreatedEffectObjects( iface_w, callback, ref, flags ); } @@ -512,6 +543,7 @@ static HRESULT WINAPI dinput_device_a_Escape( IDirectInputDevice8A *iface_a, DIE { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, escape %p.\n", impl, escape ); return IDirectInputDevice8_Escape( iface_w, escape ); } @@ -519,6 +551,7 @@ static HRESULT WINAPI dinput_device_a_Poll( IDirectInputDevice8A *iface_a ) { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p.\n", impl ); return IDirectInputDevice8_Poll( iface_w ); } @@ -527,6 +560,7 @@ static HRESULT WINAPI dinput_device_a_SendDeviceData( IDirectInputDevice8A *ifac { struct dinput_device *impl = impl_from_IDirectInputDevice8A( iface_a ); IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); + TRACE( "impl %p, count %#lx, data %p, inout %p, flags %#lx.\n", impl, count, data, inout, flags ); return IDirectInputDevice8_SendDeviceData( iface_w, count, data, inout, flags ); } @@ -537,6 +571,9 @@ static HRESULT WINAPI dinput_device_a_EnumEffectsInFile( IDirectInputDevice8A *i IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); WCHAR buffer[MAX_PATH], *filename_w = buffer; + TRACE( "impl %p, filename_a %s, callback %p, ref %p, flags %#lx.\n", impl, + debugstr_a(filename_a), callback, ref, flags ); + if (!filename_a) filename_w = NULL; else MultiByteToWideChar( CP_ACP, 0, filename_a, -1, buffer, MAX_PATH ); @@ -550,6 +587,9 @@ static HRESULT WINAPI dinput_device_a_WriteEffectToFile( IDirectInputDevice8A *i IDirectInputDevice8W *iface_w = IDirectInputDevice8W_from_impl( impl ); WCHAR buffer[MAX_PATH], *filename_w = buffer; + TRACE( "impl %p, filename_a %s, entries %#lx, file_effect %p, flags %#lx.\n", impl, + debugstr_a(filename_a), entries, file_effect, flags ); + if (!filename_a) filename_w = NULL; else MultiByteToWideChar( CP_ACP, 0, filename_a, -1, buffer, MAX_PATH ); @@ -565,6 +605,8 @@ static HRESULT WINAPI dinput_device_a_BuildActionMap( IDirectInputDevice8A *ifac HRESULT hr; WCHAR *username_w; + TRACE( "impl %p, format_a %p, username_a %s, flags %#lx.\n", impl, format_a, debugstr_a(username_a), flags ); + if (!format_a) return E_POINTER; if (format_a->dwSize != sizeof(DIACTIONFORMATA)) return DIERR_INVALIDPARAM; if (format_a->dwActionSize != sizeof(DIACTIONA)) return DIERR_INVALIDPARAM; @@ -594,6 +636,8 @@ static HRESULT WINAPI dinput_device_a_SetActionMap( IDirectInputDevice8A *iface_ HRESULT hr; WCHAR *username_w; + TRACE( "impl %p, format_a %p, username_a %s, flags %#lx.\n", impl, format_a, debugstr_a(username_a), flags ); + if (!format_a) return E_POINTER; if (format_a->dwSize != sizeof(DIACTIONFORMATA)) return DIERR_INVALIDPARAM; if (format_a->dwActionSize != sizeof(DIACTIONA)) return DIERR_INVALIDPARAM; @@ -621,6 +665,8 @@ static HRESULT WINAPI dinput_device_a_GetImageInfo( IDirectInputDevice8A *iface_ DIDEVICEIMAGEINFOHEADERW header_w = {sizeof(header_w), sizeof(DIDEVICEIMAGEINFOW)}; HRESULT hr; + TRACE( "impl %p, header_a %p.\n", impl, header_a ); + if (!header_a) return E_POINTER; if (header_a->dwSize != sizeof(DIDEVICEIMAGEINFOHEADERA)) return DIERR_INVALIDPARAM; if (header_a->dwSizeImageInfo != sizeof(DIDEVICEIMAGEINFOA)) return DIERR_INVALIDPARAM; @@ -680,6 +726,7 @@ static HRESULT WINAPI dinput8_a_QueryInterface( IDirectInput8A *iface_a, REFIID { struct dinput *impl = impl_from_IDirectInput8A( iface_a ); IDirectInput8W *iface_w = IDirectInput8W_from_impl( impl ); + TRACE( "impl %p, iid %s, out %p.\n", impl, debugstr_guid( iid ), out ); return IDirectInput8_QueryInterface( iface_w, iid, out ); } @@ -687,6 +734,7 @@ static ULONG WINAPI dinput8_a_AddRef( IDirectInput8A *iface_a ) { struct dinput *impl = impl_from_IDirectInput8A( iface_a ); IDirectInput8W *iface_w = IDirectInput8W_from_impl( impl ); + TRACE( "impl %p.\n", impl ); return IDirectInput8_AddRef( iface_w ); } @@ -694,6 +742,7 @@ static ULONG WINAPI dinput8_a_Release( IDirectInput8A *iface_a ) { struct dinput *impl = impl_from_IDirectInput8A( iface_a ); IDirectInput8W *iface_w = IDirectInput8W_from_impl( impl ); + TRACE( "impl %p.\n", impl ); return IDirectInput8_Release( iface_w ); } @@ -704,6 +753,8 @@ static HRESULT WINAPI dinput8_a_CreateDevice( IDirectInput8A *iface_a, REFGUID g IDirectInputDevice8W *outw; HRESULT hr; + TRACE( "impl %p, guid %s, out %p, outer %p.\n", impl, debugstr_guid( guid ), out, outer ); + if (!out) return E_POINTER; hr = IDirectInput8_CreateDevice( iface_w, guid, &outw, outer ); @@ -733,6 +784,8 @@ static HRESULT WINAPI dinput8_a_EnumDevices( IDirectInput8A *iface_a, DWORD type struct dinput *impl = impl_from_IDirectInput8A( iface_a ); IDirectInput8W *iface_w = IDirectInput8W_from_impl( impl ); + TRACE( "impl %p, type %#lx, callback %p, ref %p, flags %#lx.\n", impl, type, callback, ref, flags ); + if (!callback) return DIERR_INVALIDPARAM; return IDirectInput8_EnumDevices( iface_w, type, enum_devices_wtoa_callback, ¶ms, flags ); @@ -742,6 +795,7 @@ static HRESULT WINAPI dinput8_a_GetDeviceStatus( IDirectInput8A *iface_a, REFGUI { struct dinput *impl = impl_from_IDirectInput8A( iface_a ); IDirectInput8W *iface_w = IDirectInput8W_from_impl( impl ); + TRACE( "impl %p, instance_guid %s.\n", impl, debugstr_guid( instance_guid ) ); return IDirectInput8_GetDeviceStatus( iface_w, instance_guid ); } @@ -749,6 +803,7 @@ static HRESULT WINAPI dinput8_a_RunControlPanel( IDirectInput8A *iface_a, HWND o { struct dinput *impl = impl_from_IDirectInput8A( iface_a ); IDirectInput8W *iface_w = IDirectInput8W_from_impl( impl ); + TRACE( "impl %p, owner %p, flags %#lx.\n", impl, owner, flags ); return IDirectInput8_RunControlPanel( iface_w, owner, flags ); } @@ -756,6 +811,7 @@ static HRESULT WINAPI dinput8_a_Initialize( IDirectInput8A *iface_a, HINSTANCE i { struct dinput *impl = impl_from_IDirectInput8A( iface_a ); IDirectInput8W *iface_w = IDirectInput8W_from_impl( impl ); + TRACE( "impl %p, instance %p, version %#lx.\n", impl, instance, version ); return IDirectInput8_Initialize( iface_w, instance, version ); } @@ -766,6 +822,9 @@ static HRESULT WINAPI dinput8_a_FindDevice( IDirectInput8A *iface_a, REFGUID gui HRESULT hr; WCHAR *name_w; + TRACE( "impl %p, guid %s, name_a %s, instance_guid %s.\n", impl, debugstr_guid( guid ), + debugstr_a(name_a), debugstr_guid( instance_guid ) ); + if (FAILED(hr = string_atow( name_a, &name_w ))) return hr; hr = IDirectInput8_FindDevice( iface_w, guid, name_w, instance_guid ); @@ -800,6 +859,9 @@ static HRESULT WINAPI dinput8_a_EnumDevicesBySemantics( IDirectInput8A *iface_a, HRESULT hr; WCHAR *username_w; + TRACE( "impl %p, username_a %s, format_a %p, callback %p, ref %p, flags %#lx.\n", impl, + debugstr_a(username_a), format_a, callback, ref, flags ); + if (!callback) return DIERR_INVALIDPARAM; if (FAILED(hr = string_atow( username_a, &username_w ))) return hr; @@ -829,6 +891,8 @@ static HRESULT WINAPI dinput8_a_ConfigureDevices( IDirectInput8A *iface_a, LPDIC HRESULT hr; DWORD i; + TRACE( "impl %p, callback %p, params_a %p, flags %#lx, ref %p.\n", impl, callback, params_a, flags, ref ); + if (FAILED(hr = diconfiguredevicesparams_atow( params_a, ¶ms_w ))) return hr; format_w.dwNumActions = format_a->dwNumActions; @@ -875,6 +939,7 @@ static HRESULT WINAPI dinput7_a_QueryInterface( IDirectInput7A *iface_a, REFIID { struct dinput *impl = impl_from_IDirectInput7A( iface_a ); IDirectInput7W *iface_w = IDirectInput7W_from_impl( impl ); + TRACE( "impl %p, iid %s, out %p.\n", impl, debugstr_guid( iid ), out ); return IDirectInput7_QueryInterface( iface_w, iid, out ); } @@ -882,6 +947,7 @@ static ULONG WINAPI dinput7_a_AddRef( IDirectInput7A *iface_a ) { struct dinput *impl = impl_from_IDirectInput7A( iface_a ); IDirectInput7W *iface_w = IDirectInput7W_from_impl( impl ); + TRACE( "impl %p.\n", impl ); return IDirectInput7_AddRef( iface_w ); } @@ -889,6 +955,7 @@ static ULONG WINAPI dinput7_a_Release( IDirectInput7A *iface_a ) { struct dinput *impl = impl_from_IDirectInput7A( iface_a ); IDirectInput7W *iface_w = IDirectInput7W_from_impl( impl ); + TRACE( "impl %p.\n", impl ); return IDirectInput7_Release( iface_w ); } @@ -899,6 +966,8 @@ static HRESULT WINAPI dinput7_a_CreateDevice( IDirectInput7A *iface_a, REFGUID g IDirectInputDeviceW *out_w; HRESULT hr; + TRACE( "impl %p, guid %s, out_a %p, outer %p.\n", impl, debugstr_guid( guid ), out_a, outer ); + if (!out_a) return E_POINTER; hr = IDirectInput7_CreateDevice( iface_w, guid, &out_w, outer ); @@ -913,6 +982,8 @@ static HRESULT WINAPI dinput7_a_EnumDevices( IDirectInput7A *iface_a, DWORD type struct dinput *impl = impl_from_IDirectInput7A( iface_a ); IDirectInput7W *iface_w = IDirectInput7W_from_impl( impl ); + TRACE( "impl %p, type %#lx, callback %p, ref %p, flags %#lx.\n", impl, type, callback, ref, flags ); + if (!callback) return DIERR_INVALIDPARAM; return IDirectInput7_EnumDevices( iface_w, type, enum_devices_wtoa_callback, ¶ms, flags ); @@ -922,6 +993,7 @@ static HRESULT WINAPI dinput7_a_GetDeviceStatus( IDirectInput7A *iface_a, REFGUI { struct dinput *impl = impl_from_IDirectInput7A( iface_a ); IDirectInput7W *iface_w = IDirectInput7W_from_impl( impl ); + TRACE( "impl %p, instance_guid %s.\n", impl, debugstr_guid( instance_guid ) ); return IDirectInput7_GetDeviceStatus( iface_w, instance_guid ); } @@ -929,6 +1001,7 @@ static HRESULT WINAPI dinput7_a_RunControlPanel( IDirectInput7A *iface_a, HWND o { struct dinput *impl = impl_from_IDirectInput7A( iface_a ); IDirectInput7W *iface_w = IDirectInput7W_from_impl( impl ); + TRACE( "impl %p, owner %p, flags %#lx.\n", impl, owner, flags ); return IDirectInput7_RunControlPanel( iface_w, owner, flags ); } @@ -936,6 +1009,7 @@ static HRESULT WINAPI dinput7_a_Initialize( IDirectInput7A *iface_a, HINSTANCE i { struct dinput *impl = impl_from_IDirectInput7A( iface_a ); IDirectInput7W *iface_w = IDirectInput7W_from_impl( impl ); + TRACE( "impl %p, instance %p, version %#lx.\n", impl, instance, version ); return IDirectInput7_Initialize( iface_w, instance, version ); } @@ -946,6 +1020,9 @@ static HRESULT WINAPI dinput7_a_FindDevice( IDirectInput7A *iface_a, REFGUID gui HRESULT hr; WCHAR *name_w; + TRACE( "impl %p, guid %s, name_a %s, instance_guid %s.\n", impl, debugstr_guid( guid ), + debugstr_a(name_a), debugstr_guid( instance_guid ) ); + if (FAILED(hr = string_atow( name_a, &name_w ))) return hr; hr = IDirectInput7_FindDevice( iface_w, guid, name_w, instance_guid ); @@ -957,6 +1034,8 @@ static HRESULT WINAPI dinput7_a_CreateDeviceEx( IDirectInput7A *iface_a, REFGUID { struct dinput *impl = impl_from_IDirectInput7A( iface_a ); IDirectInput7W *iface_w = IDirectInput7W_from_impl( impl ); + TRACE( "impl %p, guid %s, iid %s, out %p, outer %p.\n", impl, debugstr_guid( guid ), + debugstr_guid( iid ), out, outer ); return IDirectInput7_CreateDeviceEx( iface_w, guid, iid, out, outer ); } From 81d590f82f2a423b02d59c85d1f89c6025687c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 21 Jan 2023 22:09:51 +0100 Subject: [PATCH 1080/2777] dinput: Remove unnecessary initialization helpers. (cherry picked from commit 070e1f5ea8ae6d306bdcf73870950c856978e24a) --- dlls/dinput/dinput_main.c | 63 ++++++++++++++---------------------- dlls/dinput/dinput_private.h | 1 - 2 files changed, 25 insertions(+), 39 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index c149156bf23..2c77407eedc 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -86,9 +86,6 @@ static struct list acquired_rawmouse_list = LIST_INIT( acquired_rawmouse_list ); static struct list acquired_keyboard_list = LIST_INIT( acquired_keyboard_list ); static struct list acquired_device_list = LIST_INIT( acquired_device_list ); -static HRESULT initialize_directinput_instance( struct dinput *impl, DWORD version ); -static void uninitialize_directinput_instance( struct dinput *impl ); - void dinput_hooks_acquire_device( IDirectInputDevice8W *iface ) { struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); @@ -140,6 +137,8 @@ static HRESULT dinput_create( IUnknown **out ) impl->IDirectInputJoyConfig8_iface.lpVtbl = &joy_config_vtbl; impl->ref = 1; + list_init( &impl->device_players ); + #if DIRECTINPUT_VERSION == 0x0700 *out = (IUnknown *)&impl->IDirectInput7W_iface; #else @@ -299,7 +298,11 @@ static ULONG WINAPI dinput7_Release( IDirectInput7W *iface ) if (ref == 0) { - uninitialize_directinput_instance( impl ); + struct DevicePlayer *device_player, *device_player2; + + LIST_FOR_EACH_ENTRY_SAFE( device_player, device_player2, &impl->device_players, struct DevicePlayer, entry ) + free( device_player ); + free( impl ); } @@ -395,34 +398,6 @@ static void unregister_di_em_win_class(void) WARN( "Unable to unregister message window class\n" ); } -static HRESULT initialize_directinput_instance( struct dinput *impl, DWORD version ) -{ - if (!impl->initialized) - { - impl->dwVersion = version; - impl->evsequence = 1; - - list_init( &impl->device_players ); - - impl->initialized = TRUE; - } - - return DI_OK; -} - -static void uninitialize_directinput_instance( struct dinput *impl ) -{ - if (impl->initialized) - { - struct DevicePlayer *device_player, *device_player2; - - LIST_FOR_EACH_ENTRY_SAFE ( device_player, device_player2, &impl->device_players, struct DevicePlayer, entry ) - free( device_player ); - - impl->initialized = FALSE; - } -} - enum directinput_versions { DIRECTINPUT_VERSION_300 = 0x0300, @@ -452,7 +427,13 @@ static HRESULT WINAPI dinput7_Initialize( IDirectInput7W *iface, HINSTANCE hinst version != DIRECTINPUT_VERSION_700 && version != DIRECTINPUT_VERSION) return DIERR_BETADIRECTINPUTVERSION; - return initialize_directinput_instance( impl, version ); + if (!impl->dwVersion) + { + impl->dwVersion = version; + impl->evsequence = 1; + } + + return DI_OK; } static HRESULT WINAPI dinput7_GetDeviceStatus( IDirectInput7W *iface, const GUID *guid ) @@ -464,7 +445,7 @@ static HRESULT WINAPI dinput7_GetDeviceStatus( IDirectInput7W *iface, const GUID TRACE( "iface %p, guid %s.\n", iface, debugstr_guid( guid ) ); if (!guid) return E_POINTER; - if (!impl->initialized) return DIERR_NOTINITIALIZED; + if (!impl->dwVersion) return DIERR_NOTINITIALIZED; hr = IDirectInput_CreateDevice( iface, guid, &device, NULL ); if (hr != DI_OK) return DI_NOTATTACHED; @@ -485,7 +466,7 @@ static HRESULT WINAPI dinput7_RunControlPanel( IDirectInput7W *iface, HWND owner if (owner && !IsWindow( owner )) return E_HANDLE; if (flags) return DIERR_INVALIDPARAM; - if (!impl->initialized) return DIERR_NOTINITIALIZED; + if (!impl->dwVersion) return DIERR_NOTINITIALIZED; if (!CreateProcessW( NULL, control_exe, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi )) return HRESULT_FROM_WIN32(GetLastError()); @@ -514,7 +495,7 @@ static HRESULT WINAPI dinput7_CreateDeviceEx( IDirectInput7W *iface, const GUID *out = NULL; if (!guid) return E_POINTER; - if (!impl->initialized) return DIERR_NOTINITIALIZED; + if (!impl->dwVersion) return DIERR_NOTINITIALIZED; if (IsEqualGUID( &GUID_SysKeyboard, guid )) hr = keyboard_create_device( impl, guid, &device ); else if (IsEqualGUID( &GUID_SysMouse, guid )) hr = mouse_create_device( impl, guid, &device ); @@ -593,7 +574,7 @@ static HRESULT WINAPI dinput8_EnumDevices( IDirectInput8W *iface, DWORD type, LP DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN)) return DIERR_INVALIDPARAM; - if (!impl->initialized) return DIERR_NOTINITIALIZED; + if (!impl->dwVersion) return DIERR_NOTINITIALIZED; if (type <= DI8DEVCLASS_GAMECTRL) device_class = type; else device_type = type; @@ -652,7 +633,13 @@ static HRESULT WINAPI dinput8_Initialize( IDirectInput8W *iface, HINSTANCE hinst else if (version > DIRECTINPUT_VERSION) return DIERR_OLDDIRECTINPUTVERSION; - return initialize_directinput_instance( impl, version ); + if (!impl->dwVersion) + { + impl->dwVersion = version; + impl->evsequence = 1; + } + + return DI_OK; } static HRESULT WINAPI dinput8_FindDevice( IDirectInput8W *iface, const GUID *guid, const WCHAR *name, GUID *instance_guid ) diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h index ae5c3e6ceef..2ce486c9540 100644 --- a/dlls/dinput/dinput_private.h +++ b/dlls/dinput/dinput_private.h @@ -38,7 +38,6 @@ struct dinput IDirectInputJoyConfig8 IDirectInputJoyConfig8_iface; LONG ref; - BOOL initialized; DWORD dwVersion; /* direct input version number */ DWORD evsequence; /* unique sequence number for events */ struct list device_players; /* device instance guid to player name */ From b94881a70a29172c2c9c05c03ea79a67d0679baf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 21 Jan 2023 22:14:58 +0100 Subject: [PATCH 1081/2777] dinput: Move dinput class implementation to dinput.c. (cherry picked from commit 1b7750e4489c33520f68f3d0f6a401c7425de80c) --- dlls/dinput/Makefile.in | 1 + dlls/dinput/dinput.c | 966 ++++++++++++++++++++++++++++++++++++++ dlls/dinput/dinput_main.c | 938 ------------------------------------ dlls/dinput8/Makefile.in | 1 + 4 files changed, 968 insertions(+), 938 deletions(-) create mode 100644 dlls/dinput/dinput.c diff --git a/dlls/dinput/Makefile.in b/dlls/dinput/Makefile.in index e1dd52cf67d..280ac49f9aa 100644 --- a/dlls/dinput/Makefile.in +++ b/dlls/dinput/Makefile.in @@ -8,6 +8,7 @@ C_SRCS = \ config.c \ data_formats.c \ device.c \ + dinput.c \ dinput_main.c \ joystick_hid.c \ keyboard.c \ diff --git a/dlls/dinput/dinput.c b/dlls/dinput/dinput.c new file mode 100644 index 00000000000..2b1ce6d2e33 --- /dev/null +++ b/dlls/dinput/dinput.c @@ -0,0 +1,966 @@ +/* + * Copyright 1998 Marcus Meissner + * Copyright 1998,1999 Lionel Ulmer + * Copyright 2000-2002 TransGaming Technologies Inc. + * Copyright 2007 Vitaliy Margolen + * + * + * 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 + */ + +#include +#include + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" + +#include "dinput_private.h" +#include "device_private.h" + +#include "wine/asm.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +static inline struct dinput *impl_from_IDirectInput7W( IDirectInput7W *iface ) +{ + return CONTAINING_RECORD( iface, struct dinput, IDirectInput7W_iface ); +} + +static inline struct dinput *impl_from_IDirectInput8W( IDirectInput8W *iface ) +{ + return CONTAINING_RECORD( iface, struct dinput, IDirectInput8W_iface ); +} + +static DWORD diactionformat_priorityW( DIACTIONFORMATW *action_format, DWORD genre ) +{ + int i; + DWORD priorityFlags = 0; + + /* If there's at least one action for the device it's priority 1 */ + for (i = 0; i < action_format->dwNumActions; i++) + if ((action_format->rgoAction[i].dwSemantic & genre) == genre) + priorityFlags |= DIEDBS_MAPPEDPRI1; + + return priorityFlags; +} + +#if defined __i386__ && defined _MSC_VER +__declspec(naked) BOOL enum_callback_wrapper(void *callback, const void *instance, void *ref) +{ + __asm + { + push ebp + mov ebp, esp + push [ebp+16] + push [ebp+12] + call [ebp+8] + leave + ret + } +} +#elif defined __i386__ && defined __GNUC__ +extern BOOL enum_callback_wrapper(void *callback, const void *instance, void *ref); +__ASM_GLOBAL_FUNC( enum_callback_wrapper, + "pushl %ebp\n\t" + __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") + __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") + "movl %esp,%ebp\n\t" + __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") + "pushl 16(%ebp)\n\t" + "pushl 12(%ebp)\n\t" + "call *8(%ebp)\n\t" + "leave\n\t" + __ASM_CFI(".cfi_def_cfa %esp,4\n\t") + __ASM_CFI(".cfi_same_value %ebp\n\t") + "ret" ) +#else +#define enum_callback_wrapper(callback, instance, ref) (callback)((instance), (ref)) +#endif + +static HRESULT WINAPI dinput7_EnumDevices( IDirectInput7W *iface, DWORD type, LPDIENUMDEVICESCALLBACKW callback, + void *context, DWORD flags ) +{ + struct dinput *impl = impl_from_IDirectInput7W( iface ); + + TRACE( "iface %p, type %#lx, callback %p, context %p, flags %#lx.\n", iface, type, callback, context, flags ); + + if (!callback) return DIERR_INVALIDPARAM; + + if (type > DIDEVTYPE_JOYSTICK) return DIERR_INVALIDPARAM; + if (flags & ~(DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK | DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS)) + return DIERR_INVALIDPARAM; + + return IDirectInput8_EnumDevices( &impl->IDirectInput8W_iface, type, callback, context, flags ); +} + +static ULONG WINAPI dinput7_AddRef( IDirectInput7W *iface ) +{ + struct dinput *impl = impl_from_IDirectInput7W( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI dinput7_Release( IDirectInput7W *iface ) +{ + struct dinput *impl = impl_from_IDirectInput7W( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + + if (!ref) + { + struct DevicePlayer *device_player, *device_player2; + + LIST_FOR_EACH_ENTRY_SAFE( device_player, device_player2, &impl->device_players, struct DevicePlayer, entry ) + free( device_player ); + + free( impl ); + } + + return ref; +} + +static HRESULT WINAPI dinput7_QueryInterface( IDirectInput7W *iface, REFIID iid, void **out ) +{ + struct dinput *impl = impl_from_IDirectInput7W( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (!iid || !out) return E_POINTER; + + *out = NULL; + +#if DIRECTINPUT_VERSION == 0x0700 + if (IsEqualGUID( &IID_IDirectInputA, iid ) || + IsEqualGUID( &IID_IDirectInput2A, iid ) || + IsEqualGUID( &IID_IDirectInput7A, iid )) + *out = &impl->IDirectInput7A_iface; + else if (IsEqualGUID( &IID_IUnknown, iid ) || + IsEqualGUID( &IID_IDirectInputW, iid ) || + IsEqualGUID( &IID_IDirectInput2W, iid ) || + IsEqualGUID( &IID_IDirectInput7W, iid )) + *out = &impl->IDirectInput7W_iface; +#else + if (IsEqualGUID( &IID_IDirectInput8A, iid )) + *out = &impl->IDirectInput8A_iface; + else if (IsEqualGUID( &IID_IUnknown, iid ) || + IsEqualGUID( &IID_IDirectInput8W, iid )) + *out = &impl->IDirectInput8W_iface; +#endif + + if (IsEqualGUID( &IID_IDirectInputJoyConfig8, iid )) + *out = &impl->IDirectInputJoyConfig8_iface; + + if (*out) + { + IUnknown_AddRef( (IUnknown *)*out ); + return DI_OK; + } + + WARN( "Unsupported interface: %s\n", debugstr_guid( iid ) ); + return E_NOINTERFACE; +} + +enum directinput_versions +{ + DIRECTINPUT_VERSION_300 = 0x0300, + DIRECTINPUT_VERSION_500 = 0x0500, + DIRECTINPUT_VERSION_50A = 0x050A, + DIRECTINPUT_VERSION_5B2 = 0x05B2, + DIRECTINPUT_VERSION_602 = 0x0602, + DIRECTINPUT_VERSION_61A = 0x061A, + DIRECTINPUT_VERSION_700 = 0x0700, +}; + +static HRESULT WINAPI dinput7_Initialize( IDirectInput7W *iface, HINSTANCE hinst, DWORD version ) +{ + struct dinput *impl = impl_from_IDirectInput7W( iface ); + + TRACE( "iface %p, hinst %p, version %#lx.\n", iface, hinst, version ); + + if (!hinst) + return DIERR_INVALIDPARAM; + else if (version == 0) + return DIERR_NOTINITIALIZED; + else if (version > DIRECTINPUT_VERSION_700) + return DIERR_OLDDIRECTINPUTVERSION; + else if (version != DIRECTINPUT_VERSION_300 && version != DIRECTINPUT_VERSION_500 && + version != DIRECTINPUT_VERSION_50A && version != DIRECTINPUT_VERSION_5B2 && + version != DIRECTINPUT_VERSION_602 && version != DIRECTINPUT_VERSION_61A && + version != DIRECTINPUT_VERSION_700 && version != DIRECTINPUT_VERSION) + return DIERR_BETADIRECTINPUTVERSION; + + if (!impl->dwVersion) + { + impl->dwVersion = version; + impl->evsequence = 1; + } + + return DI_OK; +} + +static HRESULT WINAPI dinput7_GetDeviceStatus( IDirectInput7W *iface, const GUID *guid ) +{ + struct dinput *impl = impl_from_IDirectInput7W( iface ); + HRESULT hr; + IDirectInputDeviceW *device; + + TRACE( "iface %p, guid %s.\n", iface, debugstr_guid( guid ) ); + + if (!guid) return E_POINTER; + if (!impl->dwVersion) return DIERR_NOTINITIALIZED; + + hr = IDirectInput_CreateDevice( iface, guid, &device, NULL ); + if (hr != DI_OK) return DI_NOTATTACHED; + + IUnknown_Release( device ); + + return DI_OK; +} + +static HRESULT WINAPI dinput7_RunControlPanel( IDirectInput7W *iface, HWND owner, DWORD flags ) +{ + struct dinput *impl = impl_from_IDirectInput7W( iface ); + WCHAR control_exe[] = {L"control.exe"}; + STARTUPINFOW si = {0}; + PROCESS_INFORMATION pi; + + TRACE( "iface %p, owner %p, flags %#lx.\n", iface, owner, flags ); + + if (owner && !IsWindow( owner )) return E_HANDLE; + if (flags) return DIERR_INVALIDPARAM; + if (!impl->dwVersion) return DIERR_NOTINITIALIZED; + + if (!CreateProcessW( NULL, control_exe, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi )) + return HRESULT_FROM_WIN32(GetLastError()); + + return DI_OK; +} + +static HRESULT WINAPI dinput7_FindDevice( IDirectInput7W *iface, const GUID *guid, const WCHAR *name, GUID *instance_guid ) +{ + FIXME( "iface %p, guid %s, name %s, instance_guid %s stub!\n", iface, debugstr_guid( guid ), + debugstr_w(name), debugstr_guid( instance_guid ) ); + return DI_OK; +} + +static HRESULT WINAPI dinput7_CreateDeviceEx( IDirectInput7W *iface, const GUID *guid, + REFIID iid, void **out, IUnknown *outer ) +{ + struct dinput *impl = impl_from_IDirectInput7W( iface ); + IDirectInputDevice8W *device; + HRESULT hr; + + TRACE( "iface %p, guid %s, iid %s, out %p, outer %p.\n", iface, debugstr_guid( guid ), + debugstr_guid( iid ), out, outer ); + + if (!out) return E_POINTER; + *out = NULL; + + if (!guid) return E_POINTER; + if (!impl->dwVersion) return DIERR_NOTINITIALIZED; + + if (IsEqualGUID( &GUID_SysKeyboard, guid )) hr = keyboard_create_device( impl, guid, &device ); + else if (IsEqualGUID( &GUID_SysMouse, guid )) hr = mouse_create_device( impl, guid, &device ); + else hr = hid_joystick_create_device( impl, guid, &device ); + + if (FAILED(hr)) return hr; + + if (FAILED(hr = dinput_device_init_device_format( device ))) + { + IDirectInputDevice8_Release( device ); + return hr; + } + + hr = IDirectInputDevice8_QueryInterface( device, iid, out ); + IDirectInputDevice8_Release( device ); + return hr; +} + +static HRESULT WINAPI dinput7_CreateDevice( IDirectInput7W *iface, const GUID *guid, + IDirectInputDeviceW **out, IUnknown *outer ) +{ + return IDirectInput7_CreateDeviceEx( iface, guid, &IID_IDirectInputDeviceW, (void **)out, outer ); +} + +static ULONG WINAPI dinput8_AddRef( IDirectInput8W *iface ) +{ + struct dinput *impl = impl_from_IDirectInput8W( iface ); + return IDirectInput7_AddRef( &impl->IDirectInput7W_iface ); +} + +static HRESULT WINAPI dinput8_QueryInterface( IDirectInput8W *iface, REFIID iid, void **out ) +{ + struct dinput *impl = impl_from_IDirectInput8W( iface ); + return IDirectInput7_QueryInterface( &impl->IDirectInput7W_iface, iid, out ); +} + +static ULONG WINAPI dinput8_Release( IDirectInput8W *iface ) +{ + struct dinput *impl = impl_from_IDirectInput8W( iface ); + return IDirectInput7_Release( &impl->IDirectInput7W_iface ); +} + +static HRESULT WINAPI dinput8_CreateDevice( IDirectInput8W *iface, const GUID *guid, + IDirectInputDevice8W **out, IUnknown *outer ) +{ + struct dinput *impl = impl_from_IDirectInput8W( iface ); + return IDirectInput7_CreateDeviceEx( &impl->IDirectInput7W_iface, guid, + &IID_IDirectInputDevice8W, (void **)out, outer ); +} + +static BOOL try_enum_device( DWORD type, LPDIENUMDEVICESCALLBACKW callback, + DIDEVICEINSTANCEW *instance, void *context, DWORD flags ) +{ + if (type && (instance->dwDevType & 0xff) != type) return DIENUM_CONTINUE; + if ((flags & DIEDFL_FORCEFEEDBACK) && IsEqualGUID( &instance->guidFFDriver, &GUID_NULL )) + return DIENUM_CONTINUE; + return enum_callback_wrapper( callback, instance, context ); +} + +static HRESULT WINAPI dinput8_EnumDevices( IDirectInput8W *iface, DWORD type, LPDIENUMDEVICESCALLBACKW callback, void *context, + DWORD flags ) +{ + DIDEVICEINSTANCEW instance = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; + struct dinput *impl = impl_from_IDirectInput8W( iface ); + DWORD device_class = 0, device_type = 0; + unsigned int i = 0; + HRESULT hr; + + TRACE( "iface %p, type %#lx, callback %p, context %p, flags %#lx.\n", iface, type, callback, context, flags ); + + if (!callback) return DIERR_INVALIDPARAM; + + if ((type > DI8DEVCLASS_GAMECTRL && type < DI8DEVTYPE_DEVICE) || type > DI8DEVTYPE_SUPPLEMENTAL) + return DIERR_INVALIDPARAM; + if (flags & ~(DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK | DIEDFL_INCLUDEALIASES | + DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN)) + return DIERR_INVALIDPARAM; + + if (!impl->dwVersion) return DIERR_NOTINITIALIZED; + + if (type <= DI8DEVCLASS_GAMECTRL) device_class = type; + else device_type = type; + + if (device_class == DI8DEVCLASS_ALL || device_class == DI8DEVCLASS_POINTER) + { + hr = mouse_enum_device( type, flags, &instance, impl->dwVersion ); + if (hr == DI_OK && try_enum_device( device_type, callback, &instance, context, flags ) == DIENUM_STOP) + return DI_OK; + } + + if (device_class == DI8DEVCLASS_ALL || device_class == DI8DEVCLASS_KEYBOARD) + { + hr = keyboard_enum_device( type, flags, &instance, impl->dwVersion ); + if (hr == DI_OK && try_enum_device( device_type, callback, &instance, context, flags ) == DIENUM_STOP) + return DI_OK; + } + + if (device_class == DI8DEVCLASS_ALL || device_class == DI8DEVCLASS_GAMECTRL) + { + do + { + hr = hid_joystick_enum_device( type, flags, &instance, impl->dwVersion, i++ ); + if (hr == DI_OK && try_enum_device( device_type, callback, &instance, context, flags ) == DIENUM_STOP) + return DI_OK; + } while (SUCCEEDED(hr)); + } + + return DI_OK; +} + +static HRESULT WINAPI dinput8_GetDeviceStatus( IDirectInput8W *iface, const GUID *guid ) +{ + struct dinput *impl = impl_from_IDirectInput8W( iface ); + return IDirectInput7_GetDeviceStatus( &impl->IDirectInput7W_iface, guid ); +} + +static HRESULT WINAPI dinput8_RunControlPanel( IDirectInput8W *iface, HWND owner, DWORD flags ) +{ + struct dinput *impl = impl_from_IDirectInput8W( iface ); + return IDirectInput7_RunControlPanel( &impl->IDirectInput7W_iface, owner, flags ); +} + +static HRESULT WINAPI dinput8_Initialize( IDirectInput8W *iface, HINSTANCE hinst, DWORD version ) +{ + struct dinput *impl = impl_from_IDirectInput8W( iface ); + + TRACE( "iface %p, hinst %p, version %#lx.\n", iface, hinst, version ); + + if (!hinst) + return DIERR_INVALIDPARAM; + else if (version == 0) + return DIERR_NOTINITIALIZED; + else if (version < DIRECTINPUT_VERSION) + return DIERR_BETADIRECTINPUTVERSION; + else if (version > DIRECTINPUT_VERSION) + return DIERR_OLDDIRECTINPUTVERSION; + + if (!impl->dwVersion) + { + impl->dwVersion = version; + impl->evsequence = 1; + } + + return DI_OK; +} + +static HRESULT WINAPI dinput8_FindDevice( IDirectInput8W *iface, const GUID *guid, const WCHAR *name, GUID *instance_guid ) +{ + struct dinput *impl = impl_from_IDirectInput8W( iface ); + return IDirectInput7_FindDevice( &impl->IDirectInput7W_iface, guid, name, instance_guid ); +} + +static BOOL should_enumerate_device( const WCHAR *username, DWORD flags, struct list *device_players, const GUID *guid ) +{ + BOOL should_enumerate = TRUE; + struct DevicePlayer *device_player; + + /* Check if user owns impl device */ + if (flags & DIEDBSFL_THISUSER && username && *username) + { + should_enumerate = FALSE; + LIST_FOR_EACH_ENTRY( device_player, device_players, struct DevicePlayer, entry ) + { + if (IsEqualGUID( &device_player->instance_guid, guid )) + { + if (*device_player->username && !wcscmp( username, device_player->username )) + return TRUE; /* Device username matches */ + break; + } + } + } + + /* Check if impl device is not owned by anyone */ + if (flags & DIEDBSFL_AVAILABLEDEVICES) + { + BOOL found = FALSE; + should_enumerate = FALSE; + LIST_FOR_EACH_ENTRY( device_player, device_players, struct DevicePlayer, entry ) + { + if (IsEqualGUID( &device_player->instance_guid, guid )) + { + if (*device_player->username) found = TRUE; + break; + } + } + if (!found) return TRUE; /* Device does not have a username */ + } + + return should_enumerate; +} + +struct enum_device_by_semantics_params +{ + IDirectInput8W *iface; + const WCHAR *username; + DWORD flags; + + DIDEVICEINSTANCEW *instances; + DWORD instance_count; +}; + +static BOOL CALLBACK enum_device_by_semantics( const DIDEVICEINSTANCEW *instance, void *context ) +{ + struct enum_device_by_semantics_params *params = context; + struct dinput *impl = impl_from_IDirectInput8W( params->iface ); + + if (should_enumerate_device( params->username, params->flags, &impl->device_players, &instance->guidInstance )) + { + params->instance_count++; + params->instances = realloc( params->instances, sizeof(DIDEVICEINSTANCEW) * params->instance_count ); + params->instances[params->instance_count - 1] = *instance; + } + + return DIENUM_CONTINUE; +} + +static HRESULT WINAPI dinput8_EnumDevicesBySemantics( IDirectInput8W *iface, const WCHAR *username, DIACTIONFORMATW *action_format, + LPDIENUMDEVICESBYSEMANTICSCBW callback, void *context, DWORD flags ) +{ + struct enum_device_by_semantics_params params = {.iface = iface, .username = username, .flags = flags}; + DWORD callbackFlags, enum_flags = DIEDFL_ATTACHEDONLY | (flags & DIEDFL_FORCEFEEDBACK); + static const GUID *guids[2] = {&GUID_SysKeyboard, &GUID_SysMouse}; + static const DWORD actionMasks[] = {DIKEYBOARD_MASK, DIMOUSE_MASK}; + struct dinput *impl = impl_from_IDirectInput8W( iface ); + DIDEVICEINSTANCEW didevi; + IDirectInputDevice8W *lpdid; + unsigned int i = 0; + HRESULT hr; + int remain; + + FIXME( "iface %p, username %s, action_format %p, callback %p, context %p, flags %#lx stub!\n", + iface, debugstr_w(username), action_format, callback, context, flags ); + + didevi.dwSize = sizeof(didevi); + + hr = IDirectInput8_EnumDevices( &impl->IDirectInput8W_iface, DI8DEVCLASS_GAMECTRL, + enum_device_by_semantics, ¶ms, enum_flags ); + if (FAILED(hr)) + { + free( params.instances ); + return hr; + } + + remain = params.instance_count; + /* Add keyboard and mouse to remaining device count */ + if (!(flags & DIEDBSFL_FORCEFEEDBACK)) + { + for (i = 0; i < ARRAY_SIZE(guids); i++) + { + if (should_enumerate_device( username, flags, &impl->device_players, guids[i] )) remain++; + } + } + + for (i = 0; i < params.instance_count; i++) + { + callbackFlags = diactionformat_priorityW( action_format, action_format->dwGenre ); + IDirectInput_CreateDevice( iface, ¶ms.instances[i].guidInstance, &lpdid, NULL ); + + if (callback( ¶ms.instances[i], lpdid, callbackFlags, --remain, context ) == DIENUM_STOP) + { + free( params.instances ); + IDirectInputDevice_Release( lpdid ); + return DI_OK; + } + IDirectInputDevice_Release( lpdid ); + } + + free( params.instances ); + + if (flags & DIEDBSFL_FORCEFEEDBACK) return DI_OK; + + /* Enumerate keyboard and mouse */ + for (i = 0; i < ARRAY_SIZE(guids); i++) + { + if (should_enumerate_device( username, flags, &impl->device_players, guids[i] )) + { + callbackFlags = diactionformat_priorityW( action_format, actionMasks[i] ); + + IDirectInput_CreateDevice( iface, guids[i], &lpdid, NULL ); + IDirectInputDevice_GetDeviceInfo( lpdid, &didevi ); + + if (callback( &didevi, lpdid, callbackFlags, --remain, context ) == DIENUM_STOP) + { + IDirectInputDevice_Release( lpdid ); + return DI_OK; + } + IDirectInputDevice_Release( lpdid ); + } + } + + return DI_OK; +} + +static HRESULT WINAPI dinput8_ConfigureDevices( IDirectInput8W *iface, LPDICONFIGUREDEVICESCALLBACK callback, + DICONFIGUREDEVICESPARAMSW *params, DWORD flags, void *context ) +{ + FIXME( "iface %p, callback %p, params %p, flags %#lx, context %p stub!\n", iface, callback, + params, flags, context ); + + /* Call helper function in config.c to do the real work */ + return _configure_devices( iface, callback, params, flags, context ); +} + +static inline struct dinput *impl_from_IDirectInputJoyConfig8( IDirectInputJoyConfig8 *iface ) +{ + return CONTAINING_RECORD( iface, struct dinput, IDirectInputJoyConfig8_iface ); +} + +static HRESULT WINAPI joy_config_QueryInterface( IDirectInputJoyConfig8 *iface, REFIID iid, void **out ) +{ + struct dinput *impl = impl_from_IDirectInputJoyConfig8( iface ); + return IDirectInput7_QueryInterface( &impl->IDirectInput7W_iface, iid, out ); +} + +static ULONG WINAPI joy_config_AddRef( IDirectInputJoyConfig8 *iface ) +{ + struct dinput *impl = impl_from_IDirectInputJoyConfig8( iface ); + return IDirectInput7_AddRef( &impl->IDirectInput7W_iface ); +} + +static ULONG WINAPI joy_config_Release( IDirectInputJoyConfig8 *iface ) +{ + struct dinput *impl = impl_from_IDirectInputJoyConfig8( iface ); + return IDirectInput7_Release( &impl->IDirectInput7W_iface ); +} + +static HRESULT WINAPI joy_config_Acquire( IDirectInputJoyConfig8 *iface ) +{ + FIXME( "iface %p stub!\n", iface ); + return E_NOTIMPL; +} + +static HRESULT WINAPI joy_config_Unacquire( IDirectInputJoyConfig8 *iface ) +{ + FIXME( "iface %p stub!\n", iface ); + return E_NOTIMPL; +} + +static HRESULT WINAPI joy_config_SetCooperativeLevel( IDirectInputJoyConfig8 *iface, HWND hwnd, DWORD flags ) +{ + FIXME( "iface %p, hwnd %p, flags %#lx stub!\n", iface, hwnd, flags ); + return E_NOTIMPL; +} + +static HRESULT WINAPI joy_config_SendNotify( IDirectInputJoyConfig8 *iface ) +{ + FIXME( "iface %p stub!\n", iface ); + return E_NOTIMPL; +} + +static HRESULT WINAPI joy_config_EnumTypes( IDirectInputJoyConfig8 *iface, LPDIJOYTYPECALLBACK callback, void *context ) +{ + FIXME( "iface %p, callback %p, context %p stub!\n", iface, callback, context ); + return E_NOTIMPL; +} + +static HRESULT WINAPI joy_config_GetTypeInfo( IDirectInputJoyConfig8 *iface, const WCHAR *name, + DIJOYTYPEINFO *info, DWORD flags ) +{ + FIXME( "iface %p, name %s, info %p, flags %#lx stub!\n", iface, debugstr_w(name), info, flags ); + return E_NOTIMPL; +} + +static HRESULT WINAPI joy_config_SetTypeInfo( IDirectInputJoyConfig8 *iface, const WCHAR *name, + const DIJOYTYPEINFO *info, DWORD flags, WCHAR *new_name ) +{ + FIXME( "iface %p, name %s, info %p, flags %#lx, new_name %s stub!\n", iface, debugstr_w(name), + info, flags, debugstr_w(new_name) ); + return E_NOTIMPL; +} + +static HRESULT WINAPI joy_config_DeleteType( IDirectInputJoyConfig8 *iface, const WCHAR *name ) +{ + FIXME( "iface %p, name %s stub!\n", iface, debugstr_w(name) ); + return E_NOTIMPL; +} + +struct find_device_from_index_params +{ + UINT index; + DIDEVICEINSTANCEW instance; +}; + +static BOOL CALLBACK find_device_from_index( const DIDEVICEINSTANCEW *instance, void *context ) +{ + struct find_device_from_index_params *params = context; + params->instance = *instance; + if (!params->index--) return DIENUM_STOP; + return DIENUM_CONTINUE; +} + +static HRESULT WINAPI joy_config_GetConfig( IDirectInputJoyConfig8 *iface, UINT id, DIJOYCONFIG *info, DWORD flags ) +{ + struct dinput *impl = impl_from_IDirectInputJoyConfig8( iface ); + struct find_device_from_index_params params = {.index = id}; + HRESULT hr; + + FIXME( "iface %p, id %u, info %p, flags %#lx stub!\n", iface, id, info, flags ); + +#define X(x) if (flags & x) FIXME("\tflags |= "#x"\n"); + X(DIJC_GUIDINSTANCE) + X(DIJC_REGHWCONFIGTYPE) + X(DIJC_GAIN) + X(DIJC_CALLOUT) +#undef X + + hr = IDirectInput8_EnumDevices( &impl->IDirectInput8W_iface, DI8DEVCLASS_GAMECTRL, + find_device_from_index, ¶ms, 0 ); + if (FAILED(hr)) return hr; + if (params.index != ~0) return DIERR_NOMOREITEMS; + if (flags & DIJC_GUIDINSTANCE) info->guidInstance = params.instance.guidInstance; + return DI_OK; +} + +static HRESULT WINAPI joy_config_SetConfig( IDirectInputJoyConfig8 *iface, UINT id, const DIJOYCONFIG *info, DWORD flags ) +{ + FIXME( "iface %p, id %u, info %p, flags %#lx stub!\n", iface, id, info, flags ); + return E_NOTIMPL; +} + +static HRESULT WINAPI joy_config_DeleteConfig( IDirectInputJoyConfig8 *iface, UINT id ) +{ + FIXME( "iface %p, id %u stub!\n", iface, id ); + return E_NOTIMPL; +} + +static HRESULT WINAPI joy_config_GetUserValues( IDirectInputJoyConfig8 *iface, DIJOYUSERVALUES *info, DWORD flags ) +{ + FIXME( "iface %p, info %p, flags %#lx stub!\n", iface, info, flags ); + return E_NOTIMPL; +} + +static HRESULT WINAPI joy_config_SetUserValues( IDirectInputJoyConfig8 *iface, const DIJOYUSERVALUES *info, DWORD flags ) +{ + FIXME( "iface %p, info %p, flags %#lx stub!\n", iface, info, flags ); + return E_NOTIMPL; +} + +static HRESULT WINAPI joy_config_AddNewHardware( IDirectInputJoyConfig8 *iface, HWND hwnd, const GUID *guid ) +{ + FIXME( "iface %p, hwnd %p, guid %s stub!\n", iface, hwnd, debugstr_guid( guid ) ); + return E_NOTIMPL; +} + +static HRESULT WINAPI joy_config_OpenTypeKey( IDirectInputJoyConfig8 *iface, const WCHAR *name, DWORD security, HKEY *key ) +{ + FIXME( "iface %p, name %s, security %lu, key %p stub!\n", iface, debugstr_w(name), security, key ); + return E_NOTIMPL; +} + +static HRESULT WINAPI joy_config_OpenAppStatusKey( IDirectInputJoyConfig8 *iface, HKEY *key ) +{ + FIXME( "iface %p, key %p stub!\n", iface, key ); + return E_NOTIMPL; +} + +static const IDirectInput7WVtbl dinput7_vtbl = +{ + dinput7_QueryInterface, + dinput7_AddRef, + dinput7_Release, + dinput7_CreateDevice, + dinput7_EnumDevices, + dinput7_GetDeviceStatus, + dinput7_RunControlPanel, + dinput7_Initialize, + dinput7_FindDevice, + dinput7_CreateDeviceEx, +}; + +static const IDirectInput8WVtbl dinput8_vtbl = +{ + dinput8_QueryInterface, + dinput8_AddRef, + dinput8_Release, + dinput8_CreateDevice, + dinput8_EnumDevices, + dinput8_GetDeviceStatus, + dinput8_RunControlPanel, + dinput8_Initialize, + dinput8_FindDevice, + dinput8_EnumDevicesBySemantics, + dinput8_ConfigureDevices, +}; + +static const IDirectInputJoyConfig8Vtbl joy_config_vtbl = +{ + joy_config_QueryInterface, + joy_config_AddRef, + joy_config_Release, + joy_config_Acquire, + joy_config_Unacquire, + joy_config_SetCooperativeLevel, + joy_config_SendNotify, + joy_config_EnumTypes, + joy_config_GetTypeInfo, + joy_config_SetTypeInfo, + joy_config_DeleteType, + joy_config_GetConfig, + joy_config_SetConfig, + joy_config_DeleteConfig, + joy_config_GetUserValues, + joy_config_SetUserValues, + joy_config_AddNewHardware, + joy_config_OpenTypeKey, + joy_config_OpenAppStatusKey, +}; + +static HRESULT dinput_create( IUnknown **out ) +{ + struct dinput *impl; + + if (!(impl = calloc( 1, sizeof(struct dinput) ))) return E_OUTOFMEMORY; + impl->IDirectInput7A_iface.lpVtbl = &dinput7_a_vtbl; + impl->IDirectInput7W_iface.lpVtbl = &dinput7_vtbl; + impl->IDirectInput8A_iface.lpVtbl = &dinput8_a_vtbl; + impl->IDirectInput8W_iface.lpVtbl = &dinput8_vtbl; + impl->IDirectInputJoyConfig8_iface.lpVtbl = &joy_config_vtbl; + impl->ref = 1; + + list_init( &impl->device_players ); + +#if DIRECTINPUT_VERSION == 0x0700 + *out = (IUnknown *)&impl->IDirectInput7W_iface; +#else + *out = (IUnknown *)&impl->IDirectInput8W_iface; +#endif + return DI_OK; +} + +struct class_factory +{ + IClassFactory IClassFactory_iface; +}; + +static inline struct class_factory *impl_from_IClassFactory( IClassFactory *iface ) +{ + return CONTAINING_RECORD( iface, struct class_factory, IClassFactory_iface ); +} + +static HRESULT WINAPI class_factory_QueryInterface( IClassFactory *iface, REFIID iid, void **out ) +{ + struct class_factory *impl = impl_from_IClassFactory( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IClassFactory )) + *out = &impl->IClassFactory_iface; + else + { + *out = NULL; + WARN( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + return E_NOINTERFACE; + } + + IUnknown_AddRef( (IUnknown *)*out ); + return S_OK; +} + +static ULONG WINAPI class_factory_AddRef( IClassFactory *iface ) +{ + return 2; +} + +static ULONG WINAPI class_factory_Release( IClassFactory *iface ) +{ + return 1; +} + +static HRESULT WINAPI class_factory_CreateInstance( IClassFactory *iface, IUnknown *outer, REFIID iid, void **out ) +{ + IUnknown *unknown; + HRESULT hr; + + TRACE( "iface %p, outer %p, iid %s, out %p.\n", iface, outer, debugstr_guid( iid ), out ); + + if (outer) return CLASS_E_NOAGGREGATION; + + if (FAILED(hr = dinput_create( &unknown ))) return hr; + hr = IUnknown_QueryInterface( unknown, iid, out ); + IUnknown_Release( unknown ); + + return hr; +} + +static HRESULT WINAPI class_factory_LockServer( IClassFactory *iface, BOOL lock ) +{ + FIXME( "iface %p, lock %d stub!\n", iface, lock ); + return S_OK; +} + +static const IClassFactoryVtbl class_factory_vtbl = +{ + class_factory_QueryInterface, + class_factory_AddRef, + class_factory_Release, + class_factory_CreateInstance, + class_factory_LockServer, +}; + +static struct class_factory class_factory = {{&class_factory_vtbl}}; + +HRESULT WINAPI DllGetClassObject( REFCLSID clsid, REFIID iid, void **out ) +{ + TRACE( "clsid %s, iid %s, out %p.\n", debugstr_guid( clsid ), debugstr_guid( iid ), out ); + +#if DIRECTINPUT_VERSION == 0x0700 + if (IsEqualCLSID( &CLSID_DirectInput, clsid )) + return IClassFactory_QueryInterface( &class_factory.IClassFactory_iface, iid, out ); +#else + if (IsEqualCLSID( &CLSID_DirectInput8, clsid )) + return IClassFactory_QueryInterface( &class_factory.IClassFactory_iface, iid, out ); +#endif + + WARN( "%s not implemented, returning CLASS_E_CLASSNOTAVAILABLE.\n", debugstr_guid( clsid ) ); + return CLASS_E_CLASSNOTAVAILABLE; +} + +HRESULT WINAPI DirectInputCreateEx( HINSTANCE hinst, DWORD version, REFIID iid, void **out, IUnknown *outer ) +{ + IUnknown *unknown; + HRESULT hr; + + TRACE( "hinst %p, version %#lx, iid %s, out %p, outer %p.\n", hinst, version, debugstr_guid( iid ), out, outer ); + + if (!IsEqualGUID( &IID_IDirectInputA, iid ) && + !IsEqualGUID( &IID_IDirectInputW, iid ) && + !IsEqualGUID( &IID_IDirectInput2A, iid ) && + !IsEqualGUID( &IID_IDirectInput2W, iid ) && + !IsEqualGUID( &IID_IDirectInput7A, iid ) && + !IsEqualGUID( &IID_IDirectInput7W, iid )) + return DIERR_NOINTERFACE; + + if (FAILED(hr = dinput_create( &unknown ))) return hr; + hr = IUnknown_QueryInterface( unknown, iid, out ); + IUnknown_Release( unknown ); + if (FAILED(hr)) return hr; + + if (outer || FAILED(hr = IDirectInput7_Initialize( (IDirectInput7W *)unknown, hinst, version ))) + { + IUnknown_Release( unknown ); + *out = NULL; + return hr; + } + + return DI_OK; +} + +HRESULT WINAPI DECLSPEC_HOTPATCH DirectInput8Create( HINSTANCE hinst, DWORD version, REFIID iid, void **out, IUnknown *outer ) +{ + IUnknown *unknown; + HRESULT hr; + + TRACE( "hinst %p, version %#lx, iid %s, out %p, outer %p.\n", hinst, version, debugstr_guid( iid ), out, outer ); + + if (!out) return E_POINTER; + + if (!IsEqualGUID( &IID_IDirectInput8A, iid ) && + !IsEqualGUID( &IID_IDirectInput8W, iid ) && + !IsEqualGUID( &IID_IUnknown, iid )) + { + *out = NULL; + return DIERR_NOINTERFACE; + } + + if (FAILED(hr = dinput_create( &unknown ))) return hr; + hr = IUnknown_QueryInterface( unknown, iid, out ); + IUnknown_Release( unknown ); + if (FAILED(hr)) return hr; + + if (outer || FAILED(hr = IDirectInput8_Initialize( (IDirectInput8W *)unknown, hinst, version ))) + { + IUnknown_Release( (IUnknown *)unknown ); + *out = NULL; + return hr; + } + + return S_OK; +} + +HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateA( HINSTANCE hinst, DWORD version, IDirectInputA **out, IUnknown *outer ) +{ + return DirectInputCreateEx( hinst, version, &IID_IDirectInput7A, (void **)out, outer ); +} + +HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateW( HINSTANCE hinst, DWORD version, IDirectInputW **out, IUnknown *outer ) +{ + return DirectInputCreateEx( hinst, version, &IID_IDirectInput7W, (void **)out, outer ); +} diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 2c77407eedc..8ac94761387 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -46,20 +46,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); -static const IDirectInput7WVtbl dinput7_vtbl; -static const IDirectInput8WVtbl dinput8_vtbl; -static const IDirectInputJoyConfig8Vtbl joy_config_vtbl; - -static inline struct dinput *impl_from_IDirectInput7W( IDirectInput7W *iface ) -{ - return CONTAINING_RECORD( iface, struct dinput, IDirectInput7W_iface ); -} - -static inline struct dinput *impl_from_IDirectInput8W( IDirectInput8W *iface ) -{ - return CONTAINING_RECORD( iface, struct dinput, IDirectInput8W_iface ); -} - static inline struct dinput_device *impl_from_IDirectInputDevice8W( IDirectInputDevice8W *iface ) { return CONTAINING_RECORD( iface, struct dinput_device, IDirectInputDevice8W_iface ); @@ -125,233 +111,6 @@ static void dinput_device_internal_unacquire( IDirectInputDevice8W *iface ) LeaveCriticalSection( &impl->crit ); } -static HRESULT dinput_create( IUnknown **out ) -{ - struct dinput *impl; - - if (!(impl = calloc( 1, sizeof(struct dinput) ))) return E_OUTOFMEMORY; - impl->IDirectInput7A_iface.lpVtbl = &dinput7_a_vtbl; - impl->IDirectInput7W_iface.lpVtbl = &dinput7_vtbl; - impl->IDirectInput8A_iface.lpVtbl = &dinput8_a_vtbl; - impl->IDirectInput8W_iface.lpVtbl = &dinput8_vtbl; - impl->IDirectInputJoyConfig8_iface.lpVtbl = &joy_config_vtbl; - impl->ref = 1; - - list_init( &impl->device_players ); - -#if DIRECTINPUT_VERSION == 0x0700 - *out = (IUnknown *)&impl->IDirectInput7W_iface; -#else - *out = (IUnknown *)&impl->IDirectInput8W_iface; -#endif - return DI_OK; -} - -HRESULT WINAPI DirectInputCreateEx( HINSTANCE hinst, DWORD version, REFIID iid, void **out, IUnknown *outer ) -{ - IUnknown *unknown; - HRESULT hr; - - TRACE( "hinst %p, version %#lx, iid %s, out %p, outer %p.\n", hinst, version, debugstr_guid( iid ), out, outer ); - - if (!IsEqualGUID( &IID_IDirectInputA, iid ) && - !IsEqualGUID( &IID_IDirectInputW, iid ) && - !IsEqualGUID( &IID_IDirectInput2A, iid ) && - !IsEqualGUID( &IID_IDirectInput2W, iid ) && - !IsEqualGUID( &IID_IDirectInput7A, iid ) && - !IsEqualGUID( &IID_IDirectInput7W, iid )) - return DIERR_NOINTERFACE; - - if (FAILED(hr = dinput_create( &unknown ))) return hr; - hr = IUnknown_QueryInterface( unknown, iid, out ); - IUnknown_Release( unknown ); - if (FAILED(hr)) return hr; - - if (outer || FAILED(hr = IDirectInput7_Initialize( (IDirectInput7W *)unknown, hinst, version ))) - { - IUnknown_Release( unknown ); - *out = NULL; - return hr; - } - - return DI_OK; -} - -HRESULT WINAPI DECLSPEC_HOTPATCH DirectInput8Create( HINSTANCE hinst, DWORD version, REFIID iid, void **out, IUnknown *outer ) -{ - IUnknown *unknown; - HRESULT hr; - - TRACE( "hinst %p, version %#lx, iid %s, out %p, outer %p.\n", hinst, version, debugstr_guid( iid ), out, outer ); - - if (!out) return E_POINTER; - - if (!IsEqualGUID( &IID_IDirectInput8A, iid ) && - !IsEqualGUID( &IID_IDirectInput8W, iid ) && - !IsEqualGUID( &IID_IUnknown, iid )) - { - *out = NULL; - return DIERR_NOINTERFACE; - } - - if (FAILED(hr = dinput_create( &unknown ))) return hr; - hr = IUnknown_QueryInterface( unknown, iid, out ); - IUnknown_Release( unknown ); - if (FAILED(hr)) return hr; - - if (outer || FAILED(hr = IDirectInput8_Initialize( (IDirectInput8W *)unknown, hinst, version ))) - { - IUnknown_Release( (IUnknown *)unknown ); - *out = NULL; - return hr; - } - - return S_OK; -} - -HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateA( HINSTANCE hinst, DWORD version, IDirectInputA **out, IUnknown *outer ) -{ - return DirectInputCreateEx( hinst, version, &IID_IDirectInput7A, (void **)out, outer ); -} - -HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateW( HINSTANCE hinst, DWORD version, IDirectInputW **out, IUnknown *outer ) -{ - return DirectInputCreateEx( hinst, version, &IID_IDirectInput7W, (void **)out, outer ); -} - -static DWORD diactionformat_priorityW( DIACTIONFORMATW *action_format, DWORD genre ) -{ - int i; - DWORD priorityFlags = 0; - - /* If there's at least one action for the device it's priority 1 */ - for (i = 0; i < action_format->dwNumActions; i++) - if ((action_format->rgoAction[i].dwSemantic & genre) == genre) - priorityFlags |= DIEDBS_MAPPEDPRI1; - - return priorityFlags; -} - -#if defined __i386__ && defined _MSC_VER -__declspec(naked) BOOL enum_callback_wrapper(void *callback, const void *instance, void *ref) -{ - __asm - { - push ebp - mov ebp, esp - push [ebp+16] - push [ebp+12] - call [ebp+8] - leave - ret - } -} -#elif defined __i386__ && defined __GNUC__ -extern BOOL enum_callback_wrapper(void *callback, const void *instance, void *ref); -__ASM_GLOBAL_FUNC( enum_callback_wrapper, - "pushl %ebp\n\t" - __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") - __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") - "movl %esp,%ebp\n\t" - __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") - "pushl 16(%ebp)\n\t" - "pushl 12(%ebp)\n\t" - "call *8(%ebp)\n\t" - "leave\n\t" - __ASM_CFI(".cfi_def_cfa %esp,4\n\t") - __ASM_CFI(".cfi_same_value %ebp\n\t") - "ret" ) -#else -#define enum_callback_wrapper(callback, instance, ref) (callback)((instance), (ref)) -#endif - -static HRESULT WINAPI dinput7_EnumDevices( IDirectInput7W *iface, DWORD type, LPDIENUMDEVICESCALLBACKW callback, - void *context, DWORD flags ) -{ - struct dinput *impl = impl_from_IDirectInput7W( iface ); - - TRACE( "iface %p, type %#lx, callback %p, context %p, flags %#lx.\n", iface, type, callback, context, flags ); - - if (!callback) return DIERR_INVALIDPARAM; - - if (type > DIDEVTYPE_JOYSTICK) return DIERR_INVALIDPARAM; - if (flags & ~(DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK | DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS)) - return DIERR_INVALIDPARAM; - - return IDirectInput8_EnumDevices( &impl->IDirectInput8W_iface, type, callback, context, flags ); -} - -static ULONG WINAPI dinput7_AddRef( IDirectInput7W *iface ) -{ - struct dinput *impl = impl_from_IDirectInput7W( iface ); - ULONG ref = InterlockedIncrement( &impl->ref ); - TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); - return ref; -} - -static ULONG WINAPI dinput7_Release( IDirectInput7W *iface ) -{ - struct dinput *impl = impl_from_IDirectInput7W( iface ); - ULONG ref = InterlockedDecrement( &impl->ref ); - - TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); - - if (ref == 0) - { - struct DevicePlayer *device_player, *device_player2; - - LIST_FOR_EACH_ENTRY_SAFE( device_player, device_player2, &impl->device_players, struct DevicePlayer, entry ) - free( device_player ); - - free( impl ); - } - - return ref; -} - -static HRESULT WINAPI dinput7_QueryInterface( IDirectInput7W *iface, REFIID iid, void **out ) -{ - struct dinput *impl = impl_from_IDirectInput7W( iface ); - - TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); - - if (!iid || !out) return E_POINTER; - - *out = NULL; - -#if DIRECTINPUT_VERSION == 0x0700 - if (IsEqualGUID( &IID_IDirectInputA, iid ) || - IsEqualGUID( &IID_IDirectInput2A, iid ) || - IsEqualGUID( &IID_IDirectInput7A, iid )) - *out = &impl->IDirectInput7A_iface; - else if (IsEqualGUID( &IID_IUnknown, iid ) || - IsEqualGUID( &IID_IDirectInputW, iid ) || - IsEqualGUID( &IID_IDirectInput2W, iid ) || - IsEqualGUID( &IID_IDirectInput7W, iid )) - *out = &impl->IDirectInput7W_iface; - -#else - if (IsEqualGUID( &IID_IDirectInput8A, iid )) - *out = &impl->IDirectInput8A_iface; - else if (IsEqualGUID( &IID_IUnknown, iid ) || - IsEqualGUID( &IID_IDirectInput8W, iid )) - *out = &impl->IDirectInput8W_iface; - -#endif - - if (IsEqualGUID( &IID_IDirectInputJoyConfig8, iid )) - *out = &impl->IDirectInputJoyConfig8_iface; - - if (*out) - { - IUnknown_AddRef( (IUnknown *)*out ); - return DI_OK; - } - - WARN( "Unsupported interface: %s\n", debugstr_guid( iid ) ); - return E_NOINTERFACE; -} - static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { struct dinput_device *impl; @@ -398,703 +157,6 @@ static void unregister_di_em_win_class(void) WARN( "Unable to unregister message window class\n" ); } -enum directinput_versions -{ - DIRECTINPUT_VERSION_300 = 0x0300, - DIRECTINPUT_VERSION_500 = 0x0500, - DIRECTINPUT_VERSION_50A = 0x050A, - DIRECTINPUT_VERSION_5B2 = 0x05B2, - DIRECTINPUT_VERSION_602 = 0x0602, - DIRECTINPUT_VERSION_61A = 0x061A, - DIRECTINPUT_VERSION_700 = 0x0700, -}; - -static HRESULT WINAPI dinput7_Initialize( IDirectInput7W *iface, HINSTANCE hinst, DWORD version ) -{ - struct dinput *impl = impl_from_IDirectInput7W( iface ); - - TRACE( "iface %p, hinst %p, version %#lx.\n", iface, hinst, version ); - - if (!hinst) - return DIERR_INVALIDPARAM; - else if (version == 0) - return DIERR_NOTINITIALIZED; - else if (version > DIRECTINPUT_VERSION_700) - return DIERR_OLDDIRECTINPUTVERSION; - else if (version != DIRECTINPUT_VERSION_300 && version != DIRECTINPUT_VERSION_500 && - version != DIRECTINPUT_VERSION_50A && version != DIRECTINPUT_VERSION_5B2 && - version != DIRECTINPUT_VERSION_602 && version != DIRECTINPUT_VERSION_61A && - version != DIRECTINPUT_VERSION_700 && version != DIRECTINPUT_VERSION) - return DIERR_BETADIRECTINPUTVERSION; - - if (!impl->dwVersion) - { - impl->dwVersion = version; - impl->evsequence = 1; - } - - return DI_OK; -} - -static HRESULT WINAPI dinput7_GetDeviceStatus( IDirectInput7W *iface, const GUID *guid ) -{ - struct dinput *impl = impl_from_IDirectInput7W( iface ); - HRESULT hr; - IDirectInputDeviceW *device; - - TRACE( "iface %p, guid %s.\n", iface, debugstr_guid( guid ) ); - - if (!guid) return E_POINTER; - if (!impl->dwVersion) return DIERR_NOTINITIALIZED; - - hr = IDirectInput_CreateDevice( iface, guid, &device, NULL ); - if (hr != DI_OK) return DI_NOTATTACHED; - - IUnknown_Release( device ); - - return DI_OK; -} - -static HRESULT WINAPI dinput7_RunControlPanel( IDirectInput7W *iface, HWND owner, DWORD flags ) -{ - struct dinput *impl = impl_from_IDirectInput7W( iface ); - WCHAR control_exe[] = {L"control.exe"}; - STARTUPINFOW si = {0}; - PROCESS_INFORMATION pi; - - TRACE( "iface %p, owner %p, flags %#lx.\n", iface, owner, flags ); - - if (owner && !IsWindow( owner )) return E_HANDLE; - if (flags) return DIERR_INVALIDPARAM; - if (!impl->dwVersion) return DIERR_NOTINITIALIZED; - - if (!CreateProcessW( NULL, control_exe, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi )) - return HRESULT_FROM_WIN32(GetLastError()); - - return DI_OK; -} - -static HRESULT WINAPI dinput7_FindDevice( IDirectInput7W *iface, const GUID *guid, const WCHAR *name, GUID *instance_guid ) -{ - FIXME( "iface %p, guid %s, name %s, instance_guid %s stub!\n", iface, debugstr_guid( guid ), - debugstr_w(name), debugstr_guid( instance_guid ) ); - return DI_OK; -} - -static HRESULT WINAPI dinput7_CreateDeviceEx( IDirectInput7W *iface, const GUID *guid, - REFIID iid, void **out, IUnknown *outer ) -{ - struct dinput *impl = impl_from_IDirectInput7W( iface ); - IDirectInputDevice8W *device; - HRESULT hr; - - TRACE( "iface %p, guid %s, iid %s, out %p, outer %p.\n", iface, debugstr_guid( guid ), - debugstr_guid( iid ), out, outer ); - - if (!out) return E_POINTER; - *out = NULL; - - if (!guid) return E_POINTER; - if (!impl->dwVersion) return DIERR_NOTINITIALIZED; - - if (IsEqualGUID( &GUID_SysKeyboard, guid )) hr = keyboard_create_device( impl, guid, &device ); - else if (IsEqualGUID( &GUID_SysMouse, guid )) hr = mouse_create_device( impl, guid, &device ); - else hr = hid_joystick_create_device( impl, guid, &device ); - - if (FAILED(hr)) return hr; - - if (FAILED(hr = dinput_device_init_device_format( device ))) - { - IDirectInputDevice8_Release( device ); - return hr; - } - - hr = IDirectInputDevice8_QueryInterface( device, iid, out ); - IDirectInputDevice8_Release( device ); - return hr; -} - -static HRESULT WINAPI dinput7_CreateDevice( IDirectInput7W *iface, const GUID *guid, - IDirectInputDeviceW **out, IUnknown *outer ) -{ - return IDirectInput7_CreateDeviceEx( iface, guid, &IID_IDirectInputDeviceW, (void **)out, outer ); -} - -static ULONG WINAPI dinput8_AddRef( IDirectInput8W *iface ) -{ - struct dinput *impl = impl_from_IDirectInput8W( iface ); - return IDirectInput7_AddRef( &impl->IDirectInput7W_iface ); -} - -static HRESULT WINAPI dinput8_QueryInterface( IDirectInput8W *iface, REFIID iid, void **out ) -{ - struct dinput *impl = impl_from_IDirectInput8W( iface ); - return IDirectInput7_QueryInterface( &impl->IDirectInput7W_iface, iid, out ); -} - -static ULONG WINAPI dinput8_Release( IDirectInput8W *iface ) -{ - struct dinput *impl = impl_from_IDirectInput8W( iface ); - return IDirectInput7_Release( &impl->IDirectInput7W_iface ); -} - -static HRESULT WINAPI dinput8_CreateDevice( IDirectInput8W *iface, const GUID *guid, - IDirectInputDevice8W **out, IUnknown *outer ) -{ - struct dinput *impl = impl_from_IDirectInput8W( iface ); - return IDirectInput7_CreateDeviceEx( &impl->IDirectInput7W_iface, guid, - &IID_IDirectInputDevice8W, (void **)out, outer ); -} - -static BOOL try_enum_device( DWORD type, LPDIENUMDEVICESCALLBACKW callback, - DIDEVICEINSTANCEW *instance, void *context, DWORD flags ) -{ - if (type && (instance->dwDevType & 0xff) != type) return DIENUM_CONTINUE; - if ((flags & DIEDFL_FORCEFEEDBACK) && IsEqualGUID( &instance->guidFFDriver, &GUID_NULL )) - return DIENUM_CONTINUE; - return enum_callback_wrapper( callback, instance, context ); -} - -static HRESULT WINAPI dinput8_EnumDevices( IDirectInput8W *iface, DWORD type, LPDIENUMDEVICESCALLBACKW callback, void *context, - DWORD flags ) -{ - DIDEVICEINSTANCEW instance = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; - struct dinput *impl = impl_from_IDirectInput8W( iface ); - DWORD device_class = 0, device_type = 0; - unsigned int i = 0; - HRESULT hr; - - TRACE( "iface %p, type %#lx, callback %p, context %p, flags %#lx.\n", iface, type, callback, context, flags ); - - if (!callback) return DIERR_INVALIDPARAM; - - if ((type > DI8DEVCLASS_GAMECTRL && type < DI8DEVTYPE_DEVICE) || type > DI8DEVTYPE_SUPPLEMENTAL) - return DIERR_INVALIDPARAM; - if (flags & ~(DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK | DIEDFL_INCLUDEALIASES | - DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN)) - return DIERR_INVALIDPARAM; - - if (!impl->dwVersion) return DIERR_NOTINITIALIZED; - - if (type <= DI8DEVCLASS_GAMECTRL) device_class = type; - else device_type = type; - - if (device_class == DI8DEVCLASS_ALL || device_class == DI8DEVCLASS_POINTER) - { - hr = mouse_enum_device( type, flags, &instance, impl->dwVersion ); - if (hr == DI_OK && try_enum_device( device_type, callback, &instance, context, flags ) == DIENUM_STOP) - return DI_OK; - } - - if (device_class == DI8DEVCLASS_ALL || device_class == DI8DEVCLASS_KEYBOARD) - { - hr = keyboard_enum_device( type, flags, &instance, impl->dwVersion ); - if (hr == DI_OK && try_enum_device( device_type, callback, &instance, context, flags ) == DIENUM_STOP) - return DI_OK; - } - - if (device_class == DI8DEVCLASS_ALL || device_class == DI8DEVCLASS_GAMECTRL) - { - do - { - hr = hid_joystick_enum_device( type, flags, &instance, impl->dwVersion, i++ ); - if (hr == DI_OK && try_enum_device( device_type, callback, &instance, context, flags ) == DIENUM_STOP) - return DI_OK; - } while (SUCCEEDED(hr)); - } - - return DI_OK; -} - -static HRESULT WINAPI dinput8_GetDeviceStatus( IDirectInput8W *iface, const GUID *guid ) -{ - struct dinput *impl = impl_from_IDirectInput8W( iface ); - return IDirectInput7_GetDeviceStatus( &impl->IDirectInput7W_iface, guid ); -} - -static HRESULT WINAPI dinput8_RunControlPanel( IDirectInput8W *iface, HWND owner, DWORD flags ) -{ - struct dinput *impl = impl_from_IDirectInput8W( iface ); - return IDirectInput7_RunControlPanel( &impl->IDirectInput7W_iface, owner, flags ); -} - -static HRESULT WINAPI dinput8_Initialize( IDirectInput8W *iface, HINSTANCE hinst, DWORD version ) -{ - struct dinput *impl = impl_from_IDirectInput8W( iface ); - - TRACE( "iface %p, hinst %p, version %#lx.\n", iface, hinst, version ); - - if (!hinst) - return DIERR_INVALIDPARAM; - else if (version == 0) - return DIERR_NOTINITIALIZED; - else if (version < DIRECTINPUT_VERSION) - return DIERR_BETADIRECTINPUTVERSION; - else if (version > DIRECTINPUT_VERSION) - return DIERR_OLDDIRECTINPUTVERSION; - - if (!impl->dwVersion) - { - impl->dwVersion = version; - impl->evsequence = 1; - } - - return DI_OK; -} - -static HRESULT WINAPI dinput8_FindDevice( IDirectInput8W *iface, const GUID *guid, const WCHAR *name, GUID *instance_guid ) -{ - struct dinput *impl = impl_from_IDirectInput8W( iface ); - return IDirectInput7_FindDevice( &impl->IDirectInput7W_iface, guid, name, instance_guid ); -} - -static BOOL should_enumerate_device( const WCHAR *username, DWORD flags, struct list *device_players, const GUID *guid ) -{ - BOOL should_enumerate = TRUE; - struct DevicePlayer *device_player; - - /* Check if user owns impl device */ - if (flags & DIEDBSFL_THISUSER && username && *username) - { - should_enumerate = FALSE; - LIST_FOR_EACH_ENTRY(device_player, device_players, struct DevicePlayer, entry) - { - if (IsEqualGUID(&device_player->instance_guid, guid)) - { - if (*device_player->username && !wcscmp( username, device_player->username )) - return TRUE; /* Device username matches */ - break; - } - } - } - - /* Check if impl device is not owned by anyone */ - if (flags & DIEDBSFL_AVAILABLEDEVICES) - { - BOOL found = FALSE; - should_enumerate = FALSE; - LIST_FOR_EACH_ENTRY(device_player, device_players, struct DevicePlayer, entry) - { - if (IsEqualGUID(&device_player->instance_guid, guid)) - { - if (*device_player->username) - found = TRUE; - break; - } - } - if (!found) - return TRUE; /* Device does not have a username */ - } - - return should_enumerate; -} - -struct enum_device_by_semantics_params -{ - IDirectInput8W *iface; - const WCHAR *username; - DWORD flags; - - DIDEVICEINSTANCEW *instances; - DWORD instance_count; -}; - -static BOOL CALLBACK enum_device_by_semantics( const DIDEVICEINSTANCEW *instance, void *context ) -{ - struct enum_device_by_semantics_params *params = context; - struct dinput *impl = impl_from_IDirectInput8W( params->iface ); - - if (should_enumerate_device( params->username, params->flags, &impl->device_players, &instance->guidInstance )) - { - params->instance_count++; - params->instances = realloc( params->instances, sizeof(DIDEVICEINSTANCEW) * params->instance_count ); - params->instances[params->instance_count - 1] = *instance; - } - - return DIENUM_CONTINUE; -} - -static HRESULT WINAPI dinput8_EnumDevicesBySemantics( IDirectInput8W *iface, const WCHAR *username, DIACTIONFORMATW *action_format, - LPDIENUMDEVICESBYSEMANTICSCBW callback, void *context, DWORD flags ) -{ - struct enum_device_by_semantics_params params = {.iface = iface, .username = username, .flags = flags}; - DWORD callbackFlags, enum_flags = DIEDFL_ATTACHEDONLY | (flags & DIEDFL_FORCEFEEDBACK); - static const GUID *guids[2] = {&GUID_SysKeyboard, &GUID_SysMouse}; - static const DWORD actionMasks[] = { DIKEYBOARD_MASK, DIMOUSE_MASK }; - struct dinput *impl = impl_from_IDirectInput8W( iface ); - DIDEVICEINSTANCEW didevi; - IDirectInputDevice8W *lpdid; - unsigned int i = 0; - HRESULT hr; - int remain; - - FIXME( "iface %p, username %s, action_format %p, callback %p, context %p, flags %#lx stub!\n", - iface, debugstr_w(username), action_format, callback, context, flags ); - - didevi.dwSize = sizeof(didevi); - - hr = IDirectInput8_EnumDevices( &impl->IDirectInput8W_iface, DI8DEVCLASS_GAMECTRL, - enum_device_by_semantics, ¶ms, enum_flags ); - if (FAILED(hr)) - { - free( params.instances ); - return hr; - } - - remain = params.instance_count; - /* Add keyboard and mouse to remaining device count */ - if (!(flags & DIEDBSFL_FORCEFEEDBACK)) - { - for (i = 0; i < ARRAY_SIZE(guids); i++) - { - if (should_enumerate_device( username, flags, &impl->device_players, guids[i] )) remain++; - } - } - - for (i = 0; i < params.instance_count; i++) - { - callbackFlags = diactionformat_priorityW( action_format, action_format->dwGenre ); - IDirectInput_CreateDevice( iface, ¶ms.instances[i].guidInstance, &lpdid, NULL ); - - if (callback( ¶ms.instances[i], lpdid, callbackFlags, --remain, context ) == DIENUM_STOP) - { - free( params.instances ); - IDirectInputDevice_Release(lpdid); - return DI_OK; - } - IDirectInputDevice_Release(lpdid); - } - - free( params.instances ); - - if (flags & DIEDBSFL_FORCEFEEDBACK) return DI_OK; - - /* Enumerate keyboard and mouse */ - for (i = 0; i < ARRAY_SIZE(guids); i++) - { - if (should_enumerate_device( username, flags, &impl->device_players, guids[i] )) - { - callbackFlags = diactionformat_priorityW( action_format, actionMasks[i] ); - - IDirectInput_CreateDevice(iface, guids[i], &lpdid, NULL); - IDirectInputDevice_GetDeviceInfo(lpdid, &didevi); - - if (callback( &didevi, lpdid, callbackFlags, --remain, context ) == DIENUM_STOP) - { - IDirectInputDevice_Release(lpdid); - return DI_OK; - } - IDirectInputDevice_Release(lpdid); - } - } - - return DI_OK; -} - -static HRESULT WINAPI dinput8_ConfigureDevices( IDirectInput8W *iface, LPDICONFIGUREDEVICESCALLBACK callback, - DICONFIGUREDEVICESPARAMSW *params, DWORD flags, void *context ) -{ - FIXME( "iface %p, callback %p, params %p, flags %#lx, context %p stub!\n", iface, callback, - params, flags, context ); - - /* Call helper function in config.c to do the real work */ - return _configure_devices( iface, callback, params, flags, context ); -} - -static inline struct dinput *impl_from_IDirectInputJoyConfig8( IDirectInputJoyConfig8 *iface ) -{ - return CONTAINING_RECORD( iface, struct dinput, IDirectInputJoyConfig8_iface ); -} - -static HRESULT WINAPI joy_config_QueryInterface( IDirectInputJoyConfig8 *iface, REFIID iid, void **out ) -{ - struct dinput *impl = impl_from_IDirectInputJoyConfig8( iface ); - return IDirectInput7_QueryInterface( &impl->IDirectInput7W_iface, iid, out ); -} - -static ULONG WINAPI joy_config_AddRef( IDirectInputJoyConfig8 *iface ) -{ - struct dinput *impl = impl_from_IDirectInputJoyConfig8( iface ); - return IDirectInput7_AddRef( &impl->IDirectInput7W_iface ); -} - -static ULONG WINAPI joy_config_Release( IDirectInputJoyConfig8 *iface ) -{ - struct dinput *impl = impl_from_IDirectInputJoyConfig8( iface ); - return IDirectInput7_Release( &impl->IDirectInput7W_iface ); -} - -static HRESULT WINAPI joy_config_Acquire( IDirectInputJoyConfig8 *iface ) -{ - FIXME( "iface %p stub!\n", iface ); - return E_NOTIMPL; -} - -static HRESULT WINAPI joy_config_Unacquire( IDirectInputJoyConfig8 *iface ) -{ - FIXME( "iface %p stub!\n", iface ); - return E_NOTIMPL; -} - -static HRESULT WINAPI joy_config_SetCooperativeLevel( IDirectInputJoyConfig8 *iface, HWND hwnd, DWORD flags ) -{ - FIXME( "iface %p, hwnd %p, flags %#lx stub!\n", iface, hwnd, flags ); - return E_NOTIMPL; -} - -static HRESULT WINAPI joy_config_SendNotify( IDirectInputJoyConfig8 *iface ) -{ - FIXME( "iface %p stub!\n", iface ); - return E_NOTIMPL; -} - -static HRESULT WINAPI joy_config_EnumTypes( IDirectInputJoyConfig8 *iface, LPDIJOYTYPECALLBACK callback, void *context ) -{ - FIXME( "iface %p, callback %p, context %p stub!\n", iface, callback, context ); - return E_NOTIMPL; -} - -static HRESULT WINAPI joy_config_GetTypeInfo( IDirectInputJoyConfig8 *iface, const WCHAR *name, - DIJOYTYPEINFO *info, DWORD flags ) -{ - FIXME( "iface %p, name %s, info %p, flags %#lx stub!\n", iface, debugstr_w(name), info, flags ); - return E_NOTIMPL; -} - -static HRESULT WINAPI joy_config_SetTypeInfo( IDirectInputJoyConfig8 *iface, const WCHAR *name, - const DIJOYTYPEINFO *info, DWORD flags, WCHAR *new_name ) -{ - FIXME( "iface %p, name %s, info %p, flags %#lx, new_name %s stub!\n", - iface, debugstr_w(name), info, flags, debugstr_w(new_name) ); - return E_NOTIMPL; -} - -static HRESULT WINAPI joy_config_DeleteType( IDirectInputJoyConfig8 *iface, const WCHAR *name ) -{ - FIXME( "iface %p, name %s stub!\n", iface, debugstr_w(name) ); - return E_NOTIMPL; -} - -struct find_device_from_index_params -{ - UINT index; - DIDEVICEINSTANCEW instance; -}; - -static BOOL CALLBACK find_device_from_index( const DIDEVICEINSTANCEW *instance, void *context ) -{ - struct find_device_from_index_params *params = context; - params->instance = *instance; - if (!params->index--) return DIENUM_STOP; - return DIENUM_CONTINUE; -} - -static HRESULT WINAPI joy_config_GetConfig( IDirectInputJoyConfig8 *iface, UINT id, DIJOYCONFIG *info, DWORD flags ) -{ - struct dinput *impl = impl_from_IDirectInputJoyConfig8( iface ); - struct find_device_from_index_params params = {.index = id}; - HRESULT hr; - - FIXME( "iface %p, id %u, info %p, flags %#lx stub!\n", iface, id, info, flags ); - -#define X(x) if (flags & x) FIXME("\tflags |= "#x"\n"); - X(DIJC_GUIDINSTANCE) - X(DIJC_REGHWCONFIGTYPE) - X(DIJC_GAIN) - X(DIJC_CALLOUT) -#undef X - - hr = IDirectInput8_EnumDevices( &impl->IDirectInput8W_iface, DI8DEVCLASS_GAMECTRL, - find_device_from_index, ¶ms, 0 ); - if (FAILED(hr)) return hr; - if (params.index != ~0) return DIERR_NOMOREITEMS; - if (flags & DIJC_GUIDINSTANCE) info->guidInstance = params.instance.guidInstance; - return DI_OK; -} - -static HRESULT WINAPI joy_config_SetConfig( IDirectInputJoyConfig8 *iface, UINT id, const DIJOYCONFIG *info, DWORD flags ) -{ - FIXME( "iface %p, id %u, info %p, flags %#lx stub!\n", iface, id, info, flags ); - return E_NOTIMPL; -} - -static HRESULT WINAPI joy_config_DeleteConfig( IDirectInputJoyConfig8 *iface, UINT id ) -{ - FIXME( "iface %p, id %u stub!\n", iface, id ); - return E_NOTIMPL; -} - -static HRESULT WINAPI joy_config_GetUserValues( IDirectInputJoyConfig8 *iface, DIJOYUSERVALUES *info, DWORD flags ) -{ - FIXME( "iface %p, info %p, flags %#lx stub!\n", iface, info, flags ); - return E_NOTIMPL; -} - -static HRESULT WINAPI joy_config_SetUserValues( IDirectInputJoyConfig8 *iface, const DIJOYUSERVALUES *info, DWORD flags ) -{ - FIXME( "iface %p, info %p, flags %#lx stub!\n", iface, info, flags ); - return E_NOTIMPL; -} - -static HRESULT WINAPI joy_config_AddNewHardware( IDirectInputJoyConfig8 *iface, HWND hwnd, const GUID *guid ) -{ - FIXME( "iface %p, hwnd %p, guid %s stub!\n", iface, hwnd, debugstr_guid( guid ) ); - return E_NOTIMPL; -} - -static HRESULT WINAPI joy_config_OpenTypeKey( IDirectInputJoyConfig8 *iface, const WCHAR *name, DWORD security, HKEY *key ) -{ - FIXME( "iface %p, name %s, security %lu, key %p stub!\n", iface, debugstr_w(name), security, key ); - return E_NOTIMPL; -} - -static HRESULT WINAPI joy_config_OpenAppStatusKey( IDirectInputJoyConfig8 *iface, HKEY *key ) -{ - FIXME( "iface %p, key %p stub!\n", iface, key ); - return E_NOTIMPL; -} - -static const IDirectInput7WVtbl dinput7_vtbl = -{ - dinput7_QueryInterface, - dinput7_AddRef, - dinput7_Release, - dinput7_CreateDevice, - dinput7_EnumDevices, - dinput7_GetDeviceStatus, - dinput7_RunControlPanel, - dinput7_Initialize, - dinput7_FindDevice, - dinput7_CreateDeviceEx, -}; - -static const IDirectInput8WVtbl dinput8_vtbl = -{ - dinput8_QueryInterface, - dinput8_AddRef, - dinput8_Release, - dinput8_CreateDevice, - dinput8_EnumDevices, - dinput8_GetDeviceStatus, - dinput8_RunControlPanel, - dinput8_Initialize, - dinput8_FindDevice, - dinput8_EnumDevicesBySemantics, - dinput8_ConfigureDevices, -}; - -static const IDirectInputJoyConfig8Vtbl joy_config_vtbl = -{ - joy_config_QueryInterface, - joy_config_AddRef, - joy_config_Release, - joy_config_Acquire, - joy_config_Unacquire, - joy_config_SetCooperativeLevel, - joy_config_SendNotify, - joy_config_EnumTypes, - joy_config_GetTypeInfo, - joy_config_SetTypeInfo, - joy_config_DeleteType, - joy_config_GetConfig, - joy_config_SetConfig, - joy_config_DeleteConfig, - joy_config_GetUserValues, - joy_config_SetUserValues, - joy_config_AddNewHardware, - joy_config_OpenTypeKey, - joy_config_OpenAppStatusKey, -}; - -struct class_factory -{ - IClassFactory IClassFactory_iface; -}; - -static inline struct class_factory *impl_from_IClassFactory( IClassFactory *iface ) -{ - return CONTAINING_RECORD( iface, struct class_factory, IClassFactory_iface ); -} - -static HRESULT WINAPI class_factory_QueryInterface( IClassFactory *iface, REFIID iid, void **out ) -{ - struct class_factory *impl = impl_from_IClassFactory(iface); - - TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); - - if (IsEqualGUID(iid, &IID_IUnknown) || - IsEqualGUID(iid, &IID_IClassFactory)) - *out = &impl->IClassFactory_iface; - else - { - *out = NULL; - WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown *)*out); - return S_OK; -} - -static ULONG WINAPI class_factory_AddRef( IClassFactory *iface ) -{ - return 2; -} - -static ULONG WINAPI class_factory_Release( IClassFactory *iface ) -{ - return 1; -} - -static HRESULT WINAPI class_factory_CreateInstance( IClassFactory *iface, IUnknown *outer, REFIID iid, void **out ) -{ - IUnknown *unknown; - HRESULT hr; - - TRACE( "iface %p, outer %p, iid %s, out %p.\n", iface, outer, debugstr_guid( iid ), out ); - - if (outer) return CLASS_E_NOAGGREGATION; - - if (FAILED(hr = dinput_create( &unknown ))) return hr; - hr = IUnknown_QueryInterface( unknown, iid, out ); - IUnknown_Release( unknown ); - - return hr; -} - -static HRESULT WINAPI class_factory_LockServer( IClassFactory *iface, BOOL lock ) -{ - FIXME( "iface %p, lock %d stub!\n", iface, lock ); - return S_OK; -} - -static const IClassFactoryVtbl class_factory_vtbl = -{ - class_factory_QueryInterface, - class_factory_AddRef, - class_factory_Release, - class_factory_CreateInstance, - class_factory_LockServer, -}; - -static struct class_factory class_factory = {{&class_factory_vtbl}}; - -HRESULT WINAPI DllGetClassObject( REFCLSID clsid, REFIID iid, void **out ) -{ - TRACE( "clsid %s, iid %s, out %p.\n", debugstr_guid( clsid ), debugstr_guid( iid ), out ); - -#if DIRECTINPUT_VERSION == 0x0700 - if (IsEqualCLSID( &CLSID_DirectInput, clsid )) - return IClassFactory_QueryInterface( &class_factory.IClassFactory_iface, iid, out ); -#else - if (IsEqualCLSID( &CLSID_DirectInput8, clsid )) - return IClassFactory_QueryInterface( &class_factory.IClassFactory_iface, iid, out ); -#endif - - WARN( "%s not implemented, returning CLASS_E_CLASSNOTAVAILABLE.\n", debugstr_guid( clsid ) ); - return CLASS_E_CLASSNOTAVAILABLE; -} - static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam ) { struct dinput_device *impl; diff --git a/dlls/dinput8/Makefile.in b/dlls/dinput8/Makefile.in index 164f2458da7..1d1b52c00ac 100644 --- a/dlls/dinput8/Makefile.in +++ b/dlls/dinput8/Makefile.in @@ -9,6 +9,7 @@ C_SRCS = \ config.c \ data_formats.c \ device.c \ + dinput.c \ dinput_main.c \ joystick_hid.c \ keyboard.c \ From f1cc0dec9ae70b140daf588a39970f10f691f602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 21 Jan 2023 22:18:59 +0100 Subject: [PATCH 1082/2777] dinput: Rename lpdid local variable to device. (cherry picked from commit adbc9ae185e166c4411cb493fb34bb0d146afd36) --- dlls/dinput/dinput.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dlls/dinput/dinput.c b/dlls/dinput/dinput.c index 2b1ce6d2e33..08d36246071 100644 --- a/dlls/dinput/dinput.c +++ b/dlls/dinput/dinput.c @@ -498,8 +498,8 @@ static HRESULT WINAPI dinput8_EnumDevicesBySemantics( IDirectInput8W *iface, con static const GUID *guids[2] = {&GUID_SysKeyboard, &GUID_SysMouse}; static const DWORD actionMasks[] = {DIKEYBOARD_MASK, DIMOUSE_MASK}; struct dinput *impl = impl_from_IDirectInput8W( iface ); + IDirectInputDevice8W *device; DIDEVICEINSTANCEW didevi; - IDirectInputDevice8W *lpdid; unsigned int i = 0; HRESULT hr; int remain; @@ -530,15 +530,15 @@ static HRESULT WINAPI dinput8_EnumDevicesBySemantics( IDirectInput8W *iface, con for (i = 0; i < params.instance_count; i++) { callbackFlags = diactionformat_priorityW( action_format, action_format->dwGenre ); - IDirectInput_CreateDevice( iface, ¶ms.instances[i].guidInstance, &lpdid, NULL ); + IDirectInput_CreateDevice( iface, ¶ms.instances[i].guidInstance, &device, NULL ); - if (callback( ¶ms.instances[i], lpdid, callbackFlags, --remain, context ) == DIENUM_STOP) + if (callback( ¶ms.instances[i], device, callbackFlags, --remain, context ) == DIENUM_STOP) { free( params.instances ); - IDirectInputDevice_Release( lpdid ); + IDirectInputDevice_Release( device ); return DI_OK; } - IDirectInputDevice_Release( lpdid ); + IDirectInputDevice_Release( device ); } free( params.instances ); @@ -552,15 +552,15 @@ static HRESULT WINAPI dinput8_EnumDevicesBySemantics( IDirectInput8W *iface, con { callbackFlags = diactionformat_priorityW( action_format, actionMasks[i] ); - IDirectInput_CreateDevice( iface, guids[i], &lpdid, NULL ); - IDirectInputDevice_GetDeviceInfo( lpdid, &didevi ); + IDirectInput_CreateDevice( iface, guids[i], &device, NULL ); + IDirectInputDevice_GetDeviceInfo( device, &didevi ); - if (callback( &didevi, lpdid, callbackFlags, --remain, context ) == DIENUM_STOP) + if (callback( &didevi, device, callbackFlags, --remain, context ) == DIENUM_STOP) { - IDirectInputDevice_Release( lpdid ); + IDirectInputDevice_Release( device ); return DI_OK; } - IDirectInputDevice_Release( lpdid ); + IDirectInputDevice_Release( device ); } } From 52e8d012ace5c17c395449d5b93937277931ec77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 27 Jan 2023 07:18:00 +0100 Subject: [PATCH 1083/2777] dinput: Use an internal refcount on all dinput devices. (cherry picked from commit 15c12fd75d73e59236b024270939f85c0e67fd63) --- dlls/dinput/device.c | 38 +++++++++++++++++++++++------------- dlls/dinput/device_private.h | 8 ++++++-- dlls/dinput/joystick_hid.c | 38 ++++++++++++------------------------ 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index e53940a2e3b..afb3a1512bb 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -693,25 +693,35 @@ static HRESULT WINAPI dinput_device_SetEventNotification( IDirectInputDevice8W * return DI_OK; } -void dinput_device_destroy( IDirectInputDevice8W *iface ) +void dinput_device_internal_addref( struct dinput_device *impl ) { - struct dinput_device *This = impl_from_IDirectInputDevice8W( iface ); + ULONG ref = InterlockedIncrement( &impl->internal_ref ); + TRACE( "impl %p, internal ref %lu.\n", impl, ref ); +} - TRACE( "iface %p.\n", iface ); +void dinput_device_internal_release( struct dinput_device *impl ) +{ + ULONG ref = InterlockedDecrement( &impl->internal_ref ); + TRACE( "impl %p, internal ref %lu.\n", impl, ref ); - free( This->object_properties ); - free( This->data_queue ); + if (!ref) + { + if (impl->vtbl->destroy) impl->vtbl->destroy( &impl->IDirectInputDevice8W_iface ); - free( This->device_format.rgodf ); - dinput_device_release_user_format( This ); + free( impl->object_properties ); + free( impl->data_queue ); - free( This->action_map ); + free( impl->device_format.rgodf ); + dinput_device_release_user_format( impl ); - IDirectInput_Release(&This->dinput->IDirectInput7A_iface); - This->crit.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&This->crit); + free( impl->action_map ); - free( This ); + IDirectInput_Release( &impl->dinput->IDirectInput7A_iface ); + impl->crit.DebugInfo->Spare[0] = 0; + DeleteCriticalSection( &impl->crit ); + + free( impl ); + } } static ULONG WINAPI dinput_device_Release( IDirectInputDevice8W *iface ) @@ -724,8 +734,7 @@ static ULONG WINAPI dinput_device_Release( IDirectInputDevice8W *iface ) if (!ref) { IDirectInputDevice_Unacquire( iface ); - if (impl->vtbl->release) impl->vtbl->release( iface ); - else dinput_device_destroy( iface ); + dinput_device_internal_release( impl ); } return ref; @@ -2107,6 +2116,7 @@ void dinput_device_init( struct dinput_device *device, const struct dinput_devic { device->IDirectInputDevice8A_iface.lpVtbl = &dinput_device_a_vtbl; device->IDirectInputDevice8W_iface.lpVtbl = &dinput_device_w_vtbl; + device->internal_ref = 1; device->ref = 1; device->guid = *guid; device->instance.dwSize = sizeof(DIDEVICEINSTANCEW); diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h index 45250ed082b..fd48a602b97 100644 --- a/dlls/dinput/device_private.h +++ b/dlls/dinput/device_private.h @@ -36,7 +36,7 @@ typedef struct struct dinput_device_vtbl { - void (*release)( IDirectInputDevice8W *iface ); + void (*destroy)( IDirectInputDevice8W *iface ); HRESULT (*poll)( IDirectInputDevice8W *iface ); HRESULT (*read)( IDirectInputDevice8W *iface ); HRESULT (*acquire)( IDirectInputDevice8W *iface ); @@ -81,7 +81,9 @@ struct dinput_device { IDirectInputDevice8W IDirectInputDevice8W_iface; IDirectInputDevice8A IDirectInputDevice8A_iface; + LONG internal_ref; LONG ref; + GUID guid; CRITICAL_SECTION crit; struct dinput *dinput; @@ -125,8 +127,10 @@ struct dinput_device extern void dinput_device_init( struct dinput_device *device, const struct dinput_device_vtbl *vtbl, const GUID *guid, struct dinput *dinput ); +extern void dinput_device_internal_addref( struct dinput_device *device ); +extern void dinput_device_internal_release( struct dinput_device *device ); + extern HRESULT dinput_device_init_device_format( IDirectInputDevice8W *iface ); -extern void dinput_device_destroy( IDirectInputDevice8W *iface ); extern BOOL get_app_key(HKEY*, HKEY*) DECLSPEC_HIDDEN; extern DWORD get_config_key( HKEY, HKEY, const WCHAR *, WCHAR *, DWORD ) DECLSPEC_HIDDEN; diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 247e298b088..e4fe64c0e81 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -175,7 +175,6 @@ struct pid_effect_state struct hid_joystick { struct dinput_device base; - LONG internal_ref; BOOL wgi_device; HANDLE device; @@ -818,30 +817,18 @@ static void set_report_value( struct hid_joystick *impl, char *report_buf, caps->usage_page, caps->usage_min, status ); } -static void hid_joystick_addref( IDirectInputDevice8W *iface ) +static void hid_joystick_destroy( IDirectInputDevice8W *iface ) { struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface ); - ULONG ref = InterlockedIncrement( &impl->internal_ref ); - TRACE( "iface %p, internal ref %lu.\n", iface, ref ); -} - -static void hid_joystick_release( IDirectInputDevice8W *iface ) -{ - struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface ); - ULONG ref = InterlockedDecrement( &impl->internal_ref ); - TRACE( "iface %p, internal ref %lu.\n", iface, ref ); + TRACE( "iface %p.\n", iface ); - if (!ref) - { - free( impl->usages_buf ); - free( impl->feature_report_buf ); - free( impl->output_report_buf ); - free( impl->input_report_buf ); - HidD_FreePreparsedData( impl->preparsed ); - CloseHandle( impl->base.read_event ); - CloseHandle( impl->device ); - dinput_device_destroy( iface ); - } + free( impl->usages_buf ); + free( impl->feature_report_buf ); + free( impl->output_report_buf ); + free( impl->input_report_buf ); + HidD_FreePreparsedData( impl->preparsed ); + CloseHandle( impl->base.read_event ); + CloseHandle( impl->device ); } static HRESULT hid_joystick_get_property( IDirectInputDevice8W *iface, DWORD property, @@ -1430,7 +1417,7 @@ static HRESULT hid_joystick_enum_objects( IDirectInputDevice8W *iface, const DIP static const struct dinput_device_vtbl hid_joystick_vtbl = { - hid_joystick_release, + hid_joystick_destroy, NULL, hid_joystick_read, hid_joystick_acquire, @@ -2102,7 +2089,6 @@ HRESULT hid_joystick_create_device( struct dinput *dinput, const GUID *guid, IDi impl->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": hid_joystick.base.crit"); impl->base.dwCoopLevel = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND; impl->base.read_event = CreateEventW( NULL, TRUE, FALSE, NULL ); - impl->internal_ref = 1; if (memcmp( device_path_guid.Data4, guid->Data4, sizeof(device_path_guid.Data4) )) hr = hid_joystick_device_open( -1, guid, &impl->base.instance, impl->device_path, &impl->device, &impl->preparsed, @@ -2230,7 +2216,7 @@ static ULONG WINAPI hid_joystick_effect_Release( IDirectInputEffect *iface ) EnterCriticalSection( &impl->joystick->base.crit ); list_remove( &impl->entry ); LeaveCriticalSection( &impl->joystick->base.crit ); - hid_joystick_release( &impl->joystick->base.IDirectInputDevice8W_iface ); + dinput_device_internal_release( &impl->joystick->base ); free( impl->set_envelope_buf ); free( impl->type_specific_buf ); free( impl->effect_update_buf ); @@ -3222,7 +3208,7 @@ static HRESULT hid_joystick_create_effect( IDirectInputDevice8W *iface, IDirectI impl->IDirectInputEffect_iface.lpVtbl = &hid_joystick_effect_vtbl; impl->ref = 1; impl->joystick = joystick; - hid_joystick_addref( &joystick->base.IDirectInputDevice8W_iface ); + dinput_device_internal_addref( &joystick->base ); EnterCriticalSection( &joystick->base.crit ); list_add_tail( &joystick->effect_list, &impl->entry ); From 4152d6e7bacd69df7314b23478e3facd624492c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 22 Jan 2023 14:40:39 +0100 Subject: [PATCH 1084/2777] dinput: Introduce a new struct to keep input thread state. (cherry picked from commit 35e4a577f062bf8b48b2644ce055fbe4ae11369e) --- dlls/dinput/dinput_main.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 8ac94761387..223a9b5cd02 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -46,6 +46,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); +struct input_thread_state +{ + UINT events_count; + HANDLE events[128]; +}; + static inline struct dinput_device *impl_from_IDirectInputDevice8W( IDirectInputDevice8W *iface ) { return CONTAINING_RECORD( iface, struct dinput_device, IDirectInputDevice8W_iface ); @@ -233,11 +239,10 @@ static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam static DWORD WINAPI dinput_thread_proc( void *params ) { - HANDLE events[128], start_event = params; + HANDLE finished_event, start_event = params; + struct input_thread_state state = {0}; static HHOOK kbd_hook, mouse_hook; struct dinput_device *impl, *next; - SIZE_T events_count = 0; - HANDLE finished_event; DWORD ret; MSG msg; @@ -247,16 +252,16 @@ static DWORD WINAPI dinput_thread_proc( void *params ) PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ); SetEvent( start_event ); - while ((ret = MsgWaitForMultipleObjectsEx( events_count, events, INFINITE, QS_ALLINPUT, 0 )) <= events_count) + while ((ret = MsgWaitForMultipleObjectsEx( state.events_count, state.events, INFINITE, QS_ALLINPUT, 0 )) <= state.events_count) { UINT kbd_cnt = 0, mice_cnt = 0; - if (ret < events_count) + if (ret < state.events_count) { EnterCriticalSection( &dinput_hook_crit ); LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_device_list, struct dinput_device, entry ) { - if (impl->read_event == events[ret]) + if (impl->read_event == state.events[ret]) { if (FAILED( impl->vtbl->read( &impl->IDirectInputDevice8W_iface ) )) { @@ -314,18 +319,18 @@ static DWORD WINAPI dinput_thread_proc( void *params ) SetEvent(finished_event); } - events_count = 0; + state.events_count = 0; EnterCriticalSection( &dinput_hook_crit ); LIST_FOR_EACH_ENTRY( impl, &acquired_device_list, struct dinput_device, entry ) { if (!impl->read_event || !impl->vtbl->read) continue; - if (events_count >= ARRAY_SIZE(events)) break; - events[events_count++] = impl->read_event; + if (state.events_count >= ARRAY_SIZE(state.events)) break; + state.events[state.events_count++] = impl->read_event; } LeaveCriticalSection( &dinput_hook_crit ); } - if (ret != events_count) ERR("Unexpected termination, ret %#lx\n", ret); + if (ret != state.events_count) ERR("Unexpected termination, ret %#lx\n", ret); done: DestroyWindow( di_em_win ); From 5dbabb7ff708b6d9902ce52edf49908a1d9f4ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 22 Jan 2023 14:42:11 +0100 Subject: [PATCH 1085/2777] dinput: Introduce new input_thread_update_device_list helper. (cherry picked from commit 27e89c5c32bbd717932a55d91fc287819e950646) --- dlls/dinput/dinput_main.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 223a9b5cd02..4ce114f3824 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -237,6 +237,22 @@ static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam return CallNextHookEx( 0, code, wparam, lparam ); } +static void input_thread_update_device_list( struct input_thread_state *state ) +{ + struct dinput_device *device; + UINT count = 0; + + EnterCriticalSection( &dinput_hook_crit ); + LIST_FOR_EACH_ENTRY( device, &acquired_device_list, struct dinput_device, entry ) + { + if (!device->read_event || !device->vtbl->read) continue; + state->events[count] = device->read_event; + if (++count >= ARRAY_SIZE(state->events)) break; + } + state->events_count = count; + LeaveCriticalSection( &dinput_hook_crit ); +} + static DWORD WINAPI dinput_thread_proc( void *params ) { HANDLE finished_event, start_event = params; @@ -319,15 +335,7 @@ static DWORD WINAPI dinput_thread_proc( void *params ) SetEvent(finished_event); } - state.events_count = 0; - EnterCriticalSection( &dinput_hook_crit ); - LIST_FOR_EACH_ENTRY( impl, &acquired_device_list, struct dinput_device, entry ) - { - if (!impl->read_event || !impl->vtbl->read) continue; - if (state.events_count >= ARRAY_SIZE(state.events)) break; - state.events[state.events_count++] = impl->read_event; - } - LeaveCriticalSection( &dinput_hook_crit ); + input_thread_update_device_list( &state ); } if (ret != state.events_count) ERR("Unexpected termination, ret %#lx\n", ret); From 2469461214663641111096c6519db67b4e4bcc34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 22 Jan 2023 12:19:12 +0100 Subject: [PATCH 1086/2777] dinput: Keep an internal refcount for dinput devices references. (cherry picked from commit 5fa11f5fb6e0b630d1aa8d978a8377753817cce7) --- dlls/dinput/device.c | 5 ++--- dlls/dinput/dinput.c | 30 ++++++++++++++++++++++++------ dlls/dinput/dinput_private.h | 4 ++++ dlls/dinput/tests/device8.c | 1 - dlls/dinput/tests/hid.c | 2 -- 5 files changed, 30 insertions(+), 12 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index afb3a1512bb..7f97067bd81 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -716,7 +716,7 @@ void dinput_device_internal_release( struct dinput_device *impl ) free( impl->action_map ); - IDirectInput_Release( &impl->dinput->IDirectInput7A_iface ); + dinput_internal_release( impl->dinput ); impl->crit.DebugInfo->Spare[0] = 0; DeleteCriticalSection( &impl->crit ); @@ -2125,8 +2125,7 @@ void dinput_device_init( struct dinput_device *device, const struct dinput_devic device->device_gain = 10000; device->force_feedback_state = DIGFFS_STOPPED | DIGFFS_EMPTY; InitializeCriticalSection( &device->crit ); - device->dinput = dinput; - IDirectInput_AddRef( &dinput->IDirectInput7A_iface ); + dinput_internal_addref( (device->dinput = dinput) ); device->vtbl = vtbl; } diff --git a/dlls/dinput/dinput.c b/dlls/dinput/dinput.c index 08d36246071..7cf06364dc3 100644 --- a/dlls/dinput/dinput.c +++ b/dlls/dinput/dinput.c @@ -107,6 +107,28 @@ static HRESULT WINAPI dinput7_EnumDevices( IDirectInput7W *iface, DWORD type, LP return IDirectInput8_EnumDevices( &impl->IDirectInput8W_iface, type, callback, context, flags ); } +void dinput_internal_addref( struct dinput *impl ) +{ + ULONG ref = InterlockedIncrement( &impl->internal_ref ); + TRACE( "impl %p, internal ref %lu.\n", impl, ref ); +} + +void dinput_internal_release( struct dinput *impl ) +{ + ULONG ref = InterlockedDecrement( &impl->internal_ref ); + TRACE( "impl %p, internal ref %lu.\n", impl, ref ); + + if (!ref) + { + struct DevicePlayer *device_player, *device_player2; + + LIST_FOR_EACH_ENTRY_SAFE( device_player, device_player2, &impl->device_players, struct DevicePlayer, entry ) + free( device_player ); + + free( impl ); + } +} + static ULONG WINAPI dinput7_AddRef( IDirectInput7W *iface ) { struct dinput *impl = impl_from_IDirectInput7W( iface ); @@ -124,12 +146,7 @@ static ULONG WINAPI dinput7_Release( IDirectInput7W *iface ) if (!ref) { - struct DevicePlayer *device_player, *device_player2; - - LIST_FOR_EACH_ENTRY_SAFE( device_player, device_player2, &impl->device_players, struct DevicePlayer, entry ) - free( device_player ); - - free( impl ); + dinput_internal_release( impl ); } return ref; @@ -792,6 +809,7 @@ static HRESULT dinput_create( IUnknown **out ) impl->IDirectInput8A_iface.lpVtbl = &dinput8_a_vtbl; impl->IDirectInput8W_iface.lpVtbl = &dinput8_vtbl; impl->IDirectInputJoyConfig8_iface.lpVtbl = &joy_config_vtbl; + impl->internal_ref = 1; impl->ref = 1; list_init( &impl->device_players ); diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h index 2ce486c9540..e2609ee43a2 100644 --- a/dlls/dinput/dinput_private.h +++ b/dlls/dinput/dinput_private.h @@ -36,6 +36,7 @@ struct dinput IDirectInput8A IDirectInput8A_iface; IDirectInput8W IDirectInput8W_iface; IDirectInputJoyConfig8 IDirectInputJoyConfig8_iface; + LONG internal_ref; LONG ref; DWORD dwVersion; /* direct input version number */ @@ -48,6 +49,9 @@ extern const IDirectInput8AVtbl dinput8_a_vtbl DECLSPEC_HIDDEN; extern HANDLE steam_overlay_event DECLSPEC_HIDDEN; extern HANDLE steam_keyboard_event DECLSPEC_HIDDEN; +extern void dinput_internal_addref( struct dinput *dinput ); +extern void dinput_internal_release( struct dinput *dinput ); + extern HRESULT mouse_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance, DWORD version ); extern HRESULT mouse_create_device( struct dinput *dinput, const GUID *guid, IDirectInputDevice8W **out ); extern HRESULT keyboard_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance, DWORD version ); diff --git a/dlls/dinput/tests/device8.c b/dlls/dinput/tests/device8.c index 86f0360c0f1..449402621a7 100644 --- a/dlls/dinput/tests/device8.c +++ b/dlls/dinput/tests/device8.c @@ -116,7 +116,6 @@ static HRESULT create_dinput_device( DWORD version, const GUID *guid, IDirectInp ok( hr == DI_OK, "CreateDevice returned %#lx\n", hr ); ref = IDirectInput_Release( dinput ); - todo_wine ok( ref == 0, "Release returned %ld\n", ref ); return DI_OK; diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c index a5ede6ee29b..facbf69fcec 100644 --- a/dlls/dinput/tests/hid.c +++ b/dlls/dinput/tests/hid.c @@ -3689,7 +3689,6 @@ HRESULT dinput_test_create_device( DWORD version, DIDEVICEINSTANCEW *devinst, ID ok( hr == DI_OK, "CreateDevice returned %#lx\n", hr ); ref = IDirectInput8_Release( di8 ); - todo_wine ok( ref == 0, "Release returned %ld\n", ref ); } else @@ -3716,7 +3715,6 @@ HRESULT dinput_test_create_device( DWORD version, DIDEVICEINSTANCEW *devinst, ID ok( hr == DI_OK, "CreateDevice returned %#lx\n", hr ); ref = IDirectInput_Release( di ); - todo_wine ok( ref == 0, "Release returned %ld\n", ref ); } From 72097df6c88ccc16a2f931fed1dda8a9f6a40a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 22 Jan 2023 14:45:43 +0100 Subject: [PATCH 1087/2777] dinput: Keep a reference on acquired devices while waiting. (cherry picked from commit d58055dd7d79cdb7466d4183ec4326f95a23cdd1) --- dlls/dinput/dinput_main.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 4ce114f3824..58bb97c4761 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -46,10 +46,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); +#define INPUT_THREAD_MAX_DEVICES 128 + struct input_thread_state { UINT events_count; - HANDLE events[128]; + UINT devices_count; + struct dinput_device *devices[INPUT_THREAD_MAX_DEVICES]; + HANDLE events[INPUT_THREAD_MAX_DEVICES]; }; static inline struct dinput_device *impl_from_IDirectInputDevice8W( IDirectInputDevice8W *iface ) @@ -247,9 +251,11 @@ static void input_thread_update_device_list( struct input_thread_state *state ) { if (!device->read_event || !device->vtbl->read) continue; state->events[count] = device->read_event; - if (++count >= ARRAY_SIZE(state->events)) break; + dinput_device_internal_addref( (state->devices[count] = device) ); + if (++count >= INPUT_THREAD_MAX_DEVICES) break; } state->events_count = count; + state->devices_count = count; LeaveCriticalSection( &dinput_hook_crit ); } @@ -258,7 +264,7 @@ static DWORD WINAPI dinput_thread_proc( void *params ) HANDLE finished_event, start_event = params; struct input_thread_state state = {0}; static HHOOK kbd_hook, mouse_hook; - struct dinput_device *impl, *next; + struct dinput_device *device; DWORD ret; MSG msg; @@ -274,20 +280,13 @@ static DWORD WINAPI dinput_thread_proc( void *params ) if (ret < state.events_count) { - EnterCriticalSection( &dinput_hook_crit ); - LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_device_list, struct dinput_device, entry ) + if ((device = state.devices[ret]) && FAILED( device->vtbl->read( &device->IDirectInputDevice8W_iface ) )) { - if (impl->read_event == state.events[ret]) - { - if (FAILED( impl->vtbl->read( &impl->IDirectInputDevice8W_iface ) )) - { - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface ); - impl->status = STATUS_UNPLUGGED; - } - break; - } + EnterCriticalSection( &dinput_hook_crit ); + dinput_device_internal_unacquire( &device->IDirectInputDevice8W_iface ); + LeaveCriticalSection( &dinput_hook_crit ); + device->status = STATUS_UNPLUGGED; } - LeaveCriticalSection( &dinput_hook_crit ); } while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) @@ -335,12 +334,14 @@ static DWORD WINAPI dinput_thread_proc( void *params ) SetEvent(finished_event); } + while (state.devices_count--) dinput_device_internal_release( state.devices[state.devices_count] ); input_thread_update_device_list( &state ); } if (ret != state.events_count) ERR("Unexpected termination, ret %#lx\n", ret); done: + while (state.devices_count--) dinput_device_internal_release( state.devices[state.devices_count] ); DestroyWindow( di_em_win ); di_em_win = NULL; return 0; From 65ba311381e63805755ce8630855f1cbcc94ce39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 22 Jan 2023 12:23:53 +0100 Subject: [PATCH 1088/2777] dinput: Update the input thread device list when notified only. (cherry picked from commit 6122dddf4ffe006127f69052414a5068a8c08aec) --- dlls/dinput/dinput_main.c | 64 ++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 58bb97c4761..2a01567b83d 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -52,6 +52,8 @@ struct input_thread_state { UINT events_count; UINT devices_count; + HHOOK mouse_ll_hook; + HHOOK keyboard_ll_hook; struct dinput_device *devices[INPUT_THREAD_MAX_DEVICES]; HANDLE events[INPUT_THREAD_MAX_DEVICES]; }; @@ -167,7 +169,7 @@ static void unregister_di_em_win_class(void) WARN( "Unable to unregister message window class\n" ); } -static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam ) +static LRESULT CALLBACK input_thread_ll_hook_proc( int code, WPARAM wparam, LPARAM lparam ) { struct dinput_device *impl; int skip = 0; @@ -243,8 +245,8 @@ static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam static void input_thread_update_device_list( struct input_thread_state *state ) { + UINT count = 0, keyboard_count, mouse_count; struct dinput_device *device; - UINT count = 0; EnterCriticalSection( &dinput_hook_crit ); LIST_FOR_EACH_ENTRY( device, &acquired_device_list, struct dinput_device, entry ) @@ -256,14 +258,32 @@ static void input_thread_update_device_list( struct input_thread_state *state ) } state->events_count = count; state->devices_count = count; + + keyboard_count = list_count( &acquired_keyboard_list ); + mouse_count = list_count( &acquired_mouse_list ); LeaveCriticalSection( &dinput_hook_crit ); + + if (keyboard_count && !state->keyboard_ll_hook) + state->keyboard_ll_hook = SetWindowsHookExW( WH_KEYBOARD_LL, input_thread_ll_hook_proc, DINPUT_instance, 0 ); + else if (!keyboard_count && state->keyboard_ll_hook) + { + UnhookWindowsHookEx( state->keyboard_ll_hook ); + state->keyboard_ll_hook = NULL; + } + + if (mouse_count && !state->mouse_ll_hook) + state->mouse_ll_hook = SetWindowsHookExW( WH_MOUSE_LL, input_thread_ll_hook_proc, DINPUT_instance, 0 ); + else if (!mouse_count && state->mouse_ll_hook) + { + UnhookWindowsHookEx( state->mouse_ll_hook ); + state->mouse_ll_hook = NULL; + } } static DWORD WINAPI dinput_thread_proc( void *params ) { HANDLE finished_event, start_event = params; struct input_thread_state state = {0}; - static HHOOK kbd_hook, mouse_hook; struct dinput_device *device; DWORD ret; MSG msg; @@ -276,8 +296,6 @@ static DWORD WINAPI dinput_thread_proc( void *params ) while ((ret = MsgWaitForMultipleObjectsEx( state.events_count, state.events, INFINITE, QS_ALLINPUT, 0 )) <= state.events_count) { - UINT kbd_cnt = 0, mice_cnt = 0; - if (ret < state.events_count) { if ((device = state.devices[ret]) && FAILED( device->vtbl->read( &device->IDirectInputDevice8W_iface ) )) @@ -286,6 +304,11 @@ static DWORD WINAPI dinput_thread_proc( void *params ) dinput_device_internal_unacquire( &device->IDirectInputDevice8W_iface ); LeaveCriticalSection( &dinput_hook_crit ); device->status = STATUS_UNPLUGGED; + + state.events[ret] = state.events[--state.events_count]; + state.devices[ret] = state.devices[state.events_count]; + state.devices[state.events_count] = state.devices[--state.devices_count]; + dinput_device_internal_release( device ); } } @@ -304,38 +327,17 @@ static DWORD WINAPI dinput_thread_proc( void *params ) if (!msg.wParam) { - if (kbd_hook) UnhookWindowsHookEx( kbd_hook ); - if (mouse_hook) UnhookWindowsHookEx( mouse_hook ); - kbd_hook = mouse_hook = NULL; + if (state.keyboard_ll_hook) UnhookWindowsHookEx( state.keyboard_ll_hook ); + if (state.mouse_ll_hook) UnhookWindowsHookEx( state.mouse_ll_hook ); + state.keyboard_ll_hook = state.mouse_ll_hook = NULL; goto done; } - EnterCriticalSection( &dinput_hook_crit ); - kbd_cnt = list_count( &acquired_keyboard_list ); - mice_cnt = list_count( &acquired_mouse_list ); - LeaveCriticalSection( &dinput_hook_crit ); - - if (kbd_cnt && !kbd_hook) - kbd_hook = SetWindowsHookExW( WH_KEYBOARD_LL, LL_hook_proc, DINPUT_instance, 0 ); - else if (!kbd_cnt && kbd_hook) - { - UnhookWindowsHookEx( kbd_hook ); - kbd_hook = NULL; - } - - if (mice_cnt && !mouse_hook) - mouse_hook = SetWindowsHookExW( WH_MOUSE_LL, LL_hook_proc, DINPUT_instance, 0 ); - else if (!mice_cnt && mouse_hook) - { - UnhookWindowsHookEx( mouse_hook ); - mouse_hook = NULL; - } + while (state.devices_count--) dinput_device_internal_release( state.devices[state.devices_count] ); + input_thread_update_device_list( &state ); SetEvent(finished_event); } - - while (state.devices_count--) dinput_device_internal_release( state.devices[state.devices_count] ); - input_thread_update_device_list( &state ); } if (ret != state.events_count) ERR("Unexpected termination, ret %#lx\n", ret); From f3b57cabd4ab194d46f8768e2409eaae0fbca0dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 22 Jan 2023 12:26:51 +0100 Subject: [PATCH 1089/2777] dinput: Update the device status while holding its CS. (cherry picked from commit 721437b43618db9ba9e0d4384014e0bbc7895a15) --- dlls/dinput/dinput_main.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 2a01567b83d..ab74d02c5fb 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -107,7 +107,7 @@ void dinput_hooks_unacquire_device( IDirectInputDevice8W *iface ) LeaveCriticalSection( &dinput_hook_crit ); } -static void dinput_device_internal_unacquire( IDirectInputDevice8W *iface ) +static void dinput_device_internal_unacquire( IDirectInputDevice8W *iface, DWORD status ) { struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); @@ -117,7 +117,7 @@ static void dinput_device_internal_unacquire( IDirectInputDevice8W *iface ) if (impl->status == STATUS_ACQUIRED) { impl->vtbl->unacquire( iface ); - impl->status = STATUS_UNACQUIRED; + impl->status = status; list_remove( &impl->entry ); } LeaveCriticalSection( &impl->crit ); @@ -211,7 +211,7 @@ static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam if (msg->hwnd == impl->win && msg->hwnd != foreground) { TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface ); + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); } } LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_mouse_list, struct dinput_device, entry ) @@ -219,7 +219,7 @@ static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam if (msg->hwnd == impl->win && msg->hwnd != foreground) { TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface ); + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); } } LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_rawmouse_list, struct dinput_device, entry ) @@ -227,7 +227,7 @@ static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam if (msg->hwnd == impl->win && msg->hwnd != foreground) { TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface ); + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); } } LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_keyboard_list, struct dinput_device, entry ) @@ -235,7 +235,7 @@ static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam if (msg->hwnd == impl->win && msg->hwnd != foreground) { TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface ); + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); } } LeaveCriticalSection( &dinput_hook_crit ); @@ -301,9 +301,8 @@ static DWORD WINAPI dinput_thread_proc( void *params ) if ((device = state.devices[ret]) && FAILED( device->vtbl->read( &device->IDirectInputDevice8W_iface ) )) { EnterCriticalSection( &dinput_hook_crit ); - dinput_device_internal_unacquire( &device->IDirectInputDevice8W_iface ); + dinput_device_internal_unacquire( &device->IDirectInputDevice8W_iface, STATUS_UNPLUGGED ); LeaveCriticalSection( &dinput_hook_crit ); - device->status = STATUS_UNPLUGGED; state.events[ret] = state.events[--state.events_count]; state.devices[ret] = state.devices[state.events_count]; From cf3bc5289b91397ba446a1a0e47cb4a1d0066161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 22 Jan 2023 12:27:40 +0100 Subject: [PATCH 1090/2777] dinput: Cleanup low-level hooks on input thread exit. (cherry picked from commit 0a355d8a54864b9c7de4ab10d48bfe027ef9cc22) --- dlls/dinput/dinput_main.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index ab74d02c5fb..104eee5c109 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -282,9 +282,9 @@ static void input_thread_update_device_list( struct input_thread_state *state ) static DWORD WINAPI dinput_thread_proc( void *params ) { - HANDLE finished_event, start_event = params; struct input_thread_state state = {0}; struct dinput_device *device; + HANDLE start_event = params; DWORD ret; MSG msg; @@ -320,22 +320,13 @@ static DWORD WINAPI dinput_thread_proc( void *params ) continue; } - finished_event = (HANDLE)msg.lParam; - TRACE( "Processing hook change notification wparam %#Ix, lparam %#Ix.\n", msg.wParam, msg.lParam ); - if (!msg.wParam) - { - if (state.keyboard_ll_hook) UnhookWindowsHookEx( state.keyboard_ll_hook ); - if (state.mouse_ll_hook) UnhookWindowsHookEx( state.mouse_ll_hook ); - state.keyboard_ll_hook = state.mouse_ll_hook = NULL; - goto done; - } + if (!msg.wParam) goto done; while (state.devices_count--) dinput_device_internal_release( state.devices[state.devices_count] ); input_thread_update_device_list( &state ); - - SetEvent(finished_event); + SetEvent( (HANDLE)msg.lParam ); } } @@ -343,6 +334,8 @@ static DWORD WINAPI dinput_thread_proc( void *params ) done: while (state.devices_count--) dinput_device_internal_release( state.devices[state.devices_count] ); + if (state.keyboard_ll_hook) UnhookWindowsHookEx( state.keyboard_ll_hook ); + if (state.mouse_ll_hook) UnhookWindowsHookEx( state.mouse_ll_hook ); DestroyWindow( di_em_win ); di_em_win = NULL; return 0; From df66e8b5f2da09fe830152cbb8ca631bddc6bf4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 5 Jan 2022 14:25:57 +0100 Subject: [PATCH 1091/2777] dinput: Introduce new dinput_unacquire_window_devices helper. (cherry picked from commit 7c88cf0f26f34e57ab582c2e8b397608cc8c1b52) --- dlls/dinput/dinput_main.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 104eee5c109..e60cce979fa 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -193,22 +193,15 @@ static LRESULT CALLBACK input_thread_ll_hook_proc( int code, WPARAM wparam, LPAR return skip ? 1 : CallNextHookEx( 0, code, wparam, lparam ); } -static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam ) +static void dinput_unacquire_window_devices( HWND window ) { struct dinput_device *impl, *next; - CWPSTRUCT *msg = (CWPSTRUCT *)lparam; - HWND foreground; - - if (code != HC_ACTION || (msg->message != WM_KILLFOCUS && - msg->message != WM_ACTIVATEAPP && msg->message != WM_ACTIVATE)) - return CallNextHookEx( 0, code, wparam, lparam ); - - foreground = GetForegroundWindow(); EnterCriticalSection( &dinput_hook_crit ); + LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_device_list, struct dinput_device, entry ) { - if (msg->hwnd == impl->win && msg->hwnd != foreground) + if (window == impl->win) { TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); @@ -216,7 +209,7 @@ static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam } LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_mouse_list, struct dinput_device, entry ) { - if (msg->hwnd == impl->win && msg->hwnd != foreground) + if (window == impl->win) { TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); @@ -224,7 +217,7 @@ static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam } LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_rawmouse_list, struct dinput_device, entry ) { - if (msg->hwnd == impl->win && msg->hwnd != foreground) + if (window == impl->win) { TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); @@ -232,13 +225,25 @@ static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam } LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_keyboard_list, struct dinput_device, entry ) { - if (msg->hwnd == impl->win && msg->hwnd != foreground) + if (window == impl->win) { TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); } } + LeaveCriticalSection( &dinput_hook_crit ); +} + +static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam ) +{ + CWPSTRUCT *msg = (CWPSTRUCT *)lparam; + + if (code != HC_ACTION || (msg->message != WM_KILLFOCUS && + msg->message != WM_ACTIVATEAPP && msg->message != WM_ACTIVATE)) + return CallNextHookEx( 0, code, wparam, lparam ); + + if (msg->hwnd != GetForegroundWindow()) dinput_unacquire_window_devices( msg->hwnd ); return CallNextHookEx( 0, code, wparam, lparam ); } From 2dfadd39c2277bff5d14094311fcb628017c4731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 22 Jan 2023 12:28:14 +0100 Subject: [PATCH 1092/2777] dinput: Unacquire all devices on internal thread error. (cherry picked from commit 5119753a33e3b0bed98186b574eb1a82cb18664e) --- dlls/dinput/dinput_main.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index e60cce979fa..cc9e2f23fca 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -201,7 +201,7 @@ static void dinput_unacquire_window_devices( HWND window ) LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_device_list, struct dinput_device, entry ) { - if (window == impl->win) + if (!window || window == impl->win) { TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); @@ -209,7 +209,7 @@ static void dinput_unacquire_window_devices( HWND window ) } LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_mouse_list, struct dinput_device, entry ) { - if (window == impl->win) + if (!window || window == impl->win) { TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); @@ -217,7 +217,7 @@ static void dinput_unacquire_window_devices( HWND window ) } LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_rawmouse_list, struct dinput_device, entry ) { - if (window == impl->win) + if (!window || window == impl->win) { TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); @@ -225,7 +225,7 @@ static void dinput_unacquire_window_devices( HWND window ) } LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_keyboard_list, struct dinput_device, entry ) { - if (window == impl->win) + if (!window || window == impl->win) { TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); @@ -335,7 +335,8 @@ static DWORD WINAPI dinput_thread_proc( void *params ) } } - if (ret != state.events_count) ERR("Unexpected termination, ret %#lx\n", ret); + ERR( "Unexpected termination, ret %#lx\n", ret ); + dinput_unacquire_window_devices( 0 ); done: while (state.devices_count--) dinput_device_internal_release( state.devices[state.devices_count] ); From 3d09f846fac81c3e1a985263658443c5961376de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 22 Jan 2023 12:30:44 +0100 Subject: [PATCH 1093/2777] dinput: Keep track of input thread users using public refcounts. And start the input thread when first user is created, then stop it when last user is destroyed. The thread will not need to enter the hook critical section on stop, as no public reference are held and devices are already unacquired. (cherry picked from commit 80d1d087877cb2012203927795596fca8da3945b) --- dlls/dinput/device.c | 3 +++ dlls/dinput/dinput.c | 3 +++ dlls/dinput/dinput_main.c | 49 +++++++++++++++++++----------------- dlls/dinput/dinput_private.h | 3 +++ 4 files changed, 35 insertions(+), 23 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 7f97067bd81..04788b22f9a 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -734,6 +734,7 @@ static ULONG WINAPI dinput_device_Release( IDirectInputDevice8W *iface ) if (!ref) { IDirectInputDevice_Unacquire( iface ); + input_thread_remove_user(); dinput_device_internal_release( impl ); } @@ -2127,6 +2128,8 @@ void dinput_device_init( struct dinput_device *device, const struct dinput_devic InitializeCriticalSection( &device->crit ); dinput_internal_addref( (device->dinput = dinput) ); device->vtbl = vtbl; + + input_thread_add_user(); } static const GUID *object_instance_guid( const DIDEVICEOBJECTINSTANCEW *instance ) diff --git a/dlls/dinput/dinput.c b/dlls/dinput/dinput.c index 7cf06364dc3..db367e1f1ba 100644 --- a/dlls/dinput/dinput.c +++ b/dlls/dinput/dinput.c @@ -146,6 +146,7 @@ static ULONG WINAPI dinput7_Release( IDirectInput7W *iface ) if (!ref) { + input_thread_remove_user(); dinput_internal_release( impl ); } @@ -819,6 +820,8 @@ static HRESULT dinput_create( IUnknown **out ) #else *out = (IUnknown *)&impl->IDirectInput8W_iface; #endif + + input_thread_add_user(); return DI_OK; } diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index cc9e2f23fca..e18d065a364 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -69,6 +69,7 @@ static HWND di_em_win; static HANDLE dinput_thread; static DWORD dinput_thread_id; +static UINT input_thread_user_count; static CRITICAL_SECTION dinput_hook_crit; static CRITICAL_SECTION_DEBUG dinput_critsect_debug = @@ -347,34 +348,39 @@ static DWORD WINAPI dinput_thread_proc( void *params ) return 0; } -static BOOL WINAPI dinput_thread_start_once( INIT_ONCE *once, void *param, void **context ) +void input_thread_add_user(void) { - HANDLE start_event; - - start_event = CreateEventW( NULL, FALSE, FALSE, NULL ); - if (!start_event) ERR( "failed to create start event, error %lu\n", GetLastError() ); + EnterCriticalSection( &dinput_hook_crit ); + if (!input_thread_user_count++) + { + HANDLE start_event; - dinput_thread = CreateThread( NULL, 0, dinput_thread_proc, start_event, 0, &dinput_thread_id ); - if (!dinput_thread) ERR( "failed to create internal thread, error %lu\n", GetLastError() ); + TRACE( "Starting input thread.\n" ); - WaitForSingleObject( start_event, INFINITE ); - CloseHandle( start_event ); + if (!(start_event = CreateEventW( NULL, FALSE, FALSE, NULL ))) + ERR( "Failed to create start event, error %lu\n", GetLastError() ); + else if (!(dinput_thread = CreateThread( NULL, 0, dinput_thread_proc, start_event, 0, &dinput_thread_id ))) + ERR( "Failed to create internal thread, error %lu\n", GetLastError() ); + else + WaitForSingleObject( start_event, INFINITE ); - return TRUE; + CloseHandle( start_event ); + } + LeaveCriticalSection( &dinput_hook_crit ); } -static void dinput_thread_start(void) +void input_thread_remove_user(void) { - static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; - InitOnceExecuteOnce( &init_once, dinput_thread_start_once, NULL, NULL ); -} + EnterCriticalSection( &dinput_hook_crit ); + if (!--input_thread_user_count) + { + TRACE( "Stopping input thread.\n" ); -static void dinput_thread_stop(void) -{ - PostThreadMessageW( dinput_thread_id, WM_USER + 0x10, 0, 0 ); - if (WaitForSingleObject( dinput_thread, 500 ) == WAIT_TIMEOUT) - WARN("Timeout while waiting for internal thread\n"); - CloseHandle( dinput_thread ); + PostThreadMessageW( dinput_thread_id, WM_USER + 0x10, 0, 0 ); + WaitForSingleObject( dinput_thread, INFINITE ); + CloseHandle( dinput_thread ); + } + LeaveCriticalSection( &dinput_hook_crit ); } void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired ) @@ -384,8 +390,6 @@ void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired ) struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); HANDLE hook_change_finished_event = NULL; - dinput_thread_start(); - EnterCriticalSection(&dinput_hook_crit); if (impl->dwCoopLevel & DISCL_FOREGROUND) @@ -473,7 +477,6 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved ) break; case DLL_PROCESS_DETACH: if (reserved) break; - dinput_thread_stop(); unregister_di_em_win_class(); CloseHandle(steam_overlay_event); CloseHandle(steam_keyboard_event); diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h index e2609ee43a2..7d167619cae 100644 --- a/dlls/dinput/dinput_private.h +++ b/dlls/dinput/dinput_private.h @@ -65,6 +65,9 @@ struct DevicePlayer { struct list entry; }; +extern void input_thread_add_user(void); +extern void input_thread_remove_user(void); + extern void dinput_hooks_acquire_device( IDirectInputDevice8W *iface ); extern void dinput_hooks_unacquire_device( IDirectInputDevice8W *iface ); extern int dinput_mouse_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lparam ); From b7948a457bd34ad1aa29117156061789e8e73cb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 22 Jan 2023 14:55:55 +0100 Subject: [PATCH 1094/2777] dinput: Move window hook checks to input_thread_update_device_list. (cherry picked from commit ca2a44bd76a0e20e3443b9ba3237a0b5a99ce020) --- dlls/dinput/dinput_main.c | 50 +++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index e18d065a364..37ce6782a3a 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -54,6 +54,7 @@ struct input_thread_state UINT devices_count; HHOOK mouse_ll_hook; HHOOK keyboard_ll_hook; + HHOOK callwndproc_hook; struct dinput_device *devices[INPUT_THREAD_MAX_DEVICES]; HANDLE events[INPUT_THREAD_MAX_DEVICES]; }; @@ -251,24 +252,45 @@ static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam static void input_thread_update_device_list( struct input_thread_state *state ) { - UINT count = 0, keyboard_count, mouse_count; + UINT count = 0, keyboard_count = 0, mouse_count = 0, foreground_count = 0; struct dinput_device *device; EnterCriticalSection( &dinput_hook_crit ); LIST_FOR_EACH_ENTRY( device, &acquired_device_list, struct dinput_device, entry ) { + if (device->dwCoopLevel & DISCL_FOREGROUND) foreground_count++; if (!device->read_event || !device->vtbl->read) continue; state->events[count] = device->read_event; dinput_device_internal_addref( (state->devices[count] = device) ); if (++count >= INPUT_THREAD_MAX_DEVICES) break; } state->events_count = count; - state->devices_count = count; - keyboard_count = list_count( &acquired_keyboard_list ); - mouse_count = list_count( &acquired_mouse_list ); + LIST_FOR_EACH_ENTRY( device, &acquired_rawmouse_list, struct dinput_device, entry ) + { + if (device->dwCoopLevel & DISCL_FOREGROUND) foreground_count++; + } + LIST_FOR_EACH_ENTRY( device, &acquired_mouse_list, struct dinput_device, entry ) + { + if (device->dwCoopLevel & DISCL_FOREGROUND) foreground_count++; + mouse_count++; + } + LIST_FOR_EACH_ENTRY( device, &acquired_keyboard_list, struct dinput_device, entry ) + { + if (device->dwCoopLevel & DISCL_FOREGROUND) foreground_count++; + keyboard_count++; + } + state->devices_count = count; LeaveCriticalSection( &dinput_hook_crit ); + if (foreground_count && !state->callwndproc_hook) + state->callwndproc_hook = SetWindowsHookExW( WH_CALLWNDPROC, callwndproc_proc, DINPUT_instance, GetCurrentThreadId() ); + else if (!foreground_count && state->callwndproc_hook) + { + UnhookWindowsHookEx( state->callwndproc_hook ); + state->callwndproc_hook = NULL; + } + if (keyboard_count && !state->keyboard_ll_hook) state->keyboard_ll_hook = SetWindowsHookExW( WH_KEYBOARD_LL, input_thread_ll_hook_proc, DINPUT_instance, 0 ); else if (!keyboard_count && state->keyboard_ll_hook) @@ -341,6 +363,7 @@ static DWORD WINAPI dinput_thread_proc( void *params ) done: while (state.devices_count--) dinput_device_internal_release( state.devices[state.devices_count] ); + if (state.callwndproc_hook) UnhookWindowsHookEx( state.callwndproc_hook ); if (state.keyboard_ll_hook) UnhookWindowsHookEx( state.keyboard_ll_hook ); if (state.mouse_ll_hook) UnhookWindowsHookEx( state.mouse_ll_hook ); DestroyWindow( di_em_win ); @@ -385,30 +408,11 @@ void input_thread_remove_user(void) void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired ) { - static HHOOK callwndproc_hook; - static ULONG foreground_cnt; struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); HANDLE hook_change_finished_event = NULL; EnterCriticalSection(&dinput_hook_crit); - if (impl->dwCoopLevel & DISCL_FOREGROUND) - { - if (acquired) - foreground_cnt++; - else - foreground_cnt--; - } - - if (foreground_cnt && !callwndproc_hook) - callwndproc_hook = SetWindowsHookExW( WH_CALLWNDPROC, callwndproc_proc, - DINPUT_instance, GetCurrentThreadId() ); - else if (!foreground_cnt && callwndproc_hook) - { - UnhookWindowsHookEx( callwndproc_hook ); - callwndproc_hook = NULL; - } - if (impl->use_raw_input) { if (acquired) From e22ddee7dfe6cfbbf7cf610da6a678e025cfa645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 22 Jan 2023 13:52:06 +0100 Subject: [PATCH 1095/2777] dinput: Move rawinput registration to input_thread_update_device_list. (cherry picked from commit bf8274edd210f4bebe3c29a3e06138254363d080) --- dlls/dinput/device_private.h | 2 -- dlls/dinput/dinput_main.c | 39 ++++++++++++------------------------ dlls/dinput/mouse.c | 4 ---- 3 files changed, 13 insertions(+), 32 deletions(-) diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h index fd48a602b97..f6030c5d088 100644 --- a/dlls/dinput/device_private.h +++ b/dlls/dinput/device_private.h @@ -94,9 +94,7 @@ struct dinput_device DWORD dwCoopLevel; HWND win; enum device_status status; - BOOL use_raw_input; /* use raw input instead of low-level messages */ - RAWINPUTDEVICE raw_device; /* raw device to (un)register */ LPDIDEVICEOBJECTDATA data_queue; /* buffer for 'GetDeviceData'. */ int queue_len; /* valid size of the queue */ diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 37ce6782a3a..a9fa5974086 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -35,6 +35,7 @@ #include "objbase.h" #include "rpcproxy.h" #include "devguid.h" +#include "hidusage.h" #include "initguid.h" #include "dinputd.h" @@ -55,6 +56,7 @@ struct input_thread_state HHOOK mouse_ll_hook; HHOOK keyboard_ll_hook; HHOOK callwndproc_hook; + RAWINPUTDEVICE rawinput_devices[2]; struct dinput_device *devices[INPUT_THREAD_MAX_DEVICES]; HANDLE events[INPUT_THREAD_MAX_DEVICES]; }; @@ -252,6 +254,7 @@ static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam static void input_thread_update_device_list( struct input_thread_state *state ) { + RAWINPUTDEVICE rawinput_mouse = {.usUsagePage = HID_USAGE_PAGE_GENERIC, .usUsage = HID_USAGE_GENERIC_MOUSE, .dwFlags = RIDEV_REMOVE}; UINT count = 0, keyboard_count = 0, mouse_count = 0, foreground_count = 0; struct dinput_device *device; @@ -269,6 +272,10 @@ static void input_thread_update_device_list( struct input_thread_state *state ) LIST_FOR_EACH_ENTRY( device, &acquired_rawmouse_list, struct dinput_device, entry ) { if (device->dwCoopLevel & DISCL_FOREGROUND) foreground_count++; + if (device->dwCoopLevel & DISCL_BACKGROUND) rawinput_mouse.dwFlags |= RIDEV_INPUTSINK; + if (device->dwCoopLevel & DISCL_EXCLUSIVE) rawinput_mouse.dwFlags |= RIDEV_NOLEGACY | RIDEV_CAPTUREMOUSE; + rawinput_mouse.dwFlags &= ~RIDEV_REMOVE; + rawinput_mouse.hwndTarget = di_em_win; } LIST_FOR_EACH_ENTRY( device, &acquired_mouse_list, struct dinput_device, entry ) { @@ -306,6 +313,12 @@ static void input_thread_update_device_list( struct input_thread_state *state ) UnhookWindowsHookEx( state->mouse_ll_hook ); state->mouse_ll_hook = NULL; } + + if (!rawinput_mouse.hwndTarget != !state->rawinput_devices[0].hwndTarget && + !RegisterRawInputDevices( &rawinput_mouse, 1, sizeof(RAWINPUTDEVICE) )) + WARN( "Failed to (un)register rawinput mouse device.\n" ); + + state->rawinput_devices[0] = rawinput_mouse; } static DWORD WINAPI dinput_thread_proc( void *params ) @@ -408,36 +421,10 @@ void input_thread_remove_user(void) void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired ) { - struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); HANDLE hook_change_finished_event = NULL; EnterCriticalSection(&dinput_hook_crit); - if (impl->use_raw_input) - { - if (acquired) - { - impl->raw_device.dwFlags = 0; - if (impl->dwCoopLevel & DISCL_BACKGROUND) - impl->raw_device.dwFlags |= RIDEV_INPUTSINK; - if (impl->dwCoopLevel & DISCL_EXCLUSIVE) - impl->raw_device.dwFlags |= RIDEV_NOLEGACY; - if ((impl->dwCoopLevel & DISCL_EXCLUSIVE) && impl->raw_device.usUsage == 2) - impl->raw_device.dwFlags |= RIDEV_CAPTUREMOUSE; - if ((impl->dwCoopLevel & DISCL_EXCLUSIVE) && impl->raw_device.usUsage == 6) - impl->raw_device.dwFlags |= RIDEV_NOHOTKEYS; - impl->raw_device.hwndTarget = di_em_win; - } - else - { - impl->raw_device.dwFlags = RIDEV_REMOVE; - impl->raw_device.hwndTarget = NULL; - } - - if (!RegisterRawInputDevices( &impl->raw_device, 1, sizeof(RAWINPUTDEVICE) )) - WARN( "Unable to (un)register raw device %x:%x\n", impl->raw_device.usUsagePage, impl->raw_device.usUsage ); - } - hook_change_finished_event = CreateEventW( NULL, FALSE, FALSE, NULL ); PostThreadMessageW( dinput_thread_id, WM_USER + 0x10, 1, (LPARAM)hook_change_finished_event ); diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c index 6aab20a631c..502ee797716 100644 --- a/dlls/dinput/mouse.c +++ b/dlls/dinput/mouse.c @@ -148,11 +148,7 @@ HRESULT mouse_create_device( struct dinput *dinput, const GUID *guid, IDirectInp if (hkey) RegCloseKey(hkey); if (dinput->dwVersion >= 0x0800) - { impl->base.use_raw_input = TRUE; - impl->base.raw_device.usUsagePage = 1; /* HID generic device page */ - impl->base.raw_device.usUsage = 2; /* HID generic mouse */ - } *out = &impl->base.IDirectInputDevice8W_iface; return DI_OK; From e2ef5baf28b7b80ab4e05786e35447defdb18f3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 22 Jan 2023 14:00:45 +0100 Subject: [PATCH 1096/2777] dinput: Move di_em_win_wndproc function around. (cherry picked from commit f3952a3e21aa73585fab40cc40ace54333117c76) --- dlls/dinput/dinput_main.c | 92 +++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index a9fa5974086..9b93e1b3640 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -127,52 +127,6 @@ static void dinput_device_internal_unacquire( IDirectInputDevice8W *iface, DWORD LeaveCriticalSection( &impl->crit ); } -static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - struct dinput_device *impl; - RAWINPUT ri; - UINT size = sizeof(ri); - int rim = GET_RAWINPUT_CODE_WPARAM( wparam ); - - TRACE( "%p %d %Ix %Ix\n", hwnd, msg, wparam, lparam ); - - if (msg == WM_INPUT && (rim == RIM_INPUT || rim == RIM_INPUTSINK)) - { - size = GetRawInputData( (HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER) ); - if (size == (UINT)-1 || size < sizeof(RAWINPUTHEADER)) - WARN( "Unable to read raw input data\n" ); - else if (ri.header.dwType == RIM_TYPEMOUSE) - { - EnterCriticalSection( &dinput_hook_crit ); - LIST_FOR_EACH_ENTRY( impl, &acquired_rawmouse_list, struct dinput_device, entry ) - dinput_mouse_rawinput_hook( &impl->IDirectInputDevice8W_iface, wparam, lparam, &ri ); - LeaveCriticalSection( &dinput_hook_crit ); - } - } - - return DefWindowProcW( hwnd, msg, wparam, lparam ); -} - -static void register_di_em_win_class(void) -{ - WNDCLASSEXW class; - - memset(&class, 0, sizeof(class)); - class.cbSize = sizeof(class); - class.lpfnWndProc = di_em_win_wndproc; - class.hInstance = DINPUT_instance; - class.lpszClassName = L"DIEmWin"; - - if (!RegisterClassExW( &class ) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) - WARN( "Unable to register message window class\n" ); -} - -static void unregister_di_em_win_class(void) -{ - if (!UnregisterClassW( L"DIEmWin", NULL ) && GetLastError() != ERROR_CLASS_DOES_NOT_EXIST) - WARN( "Unable to unregister message window class\n" ); -} - static LRESULT CALLBACK input_thread_ll_hook_proc( int code, WPARAM wparam, LPARAM lparam ) { struct dinput_device *impl; @@ -321,6 +275,52 @@ static void input_thread_update_device_list( struct input_thread_state *state ) state->rawinput_devices[0] = rawinput_mouse; } +static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + struct dinput_device *impl; + RAWINPUT ri; + UINT size = sizeof(ri); + int rim = GET_RAWINPUT_CODE_WPARAM( wparam ); + + TRACE( "%p %d %Ix %Ix\n", hwnd, msg, wparam, lparam ); + + if (msg == WM_INPUT && (rim == RIM_INPUT || rim == RIM_INPUTSINK)) + { + size = GetRawInputData( (HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER) ); + if (size == (UINT)-1 || size < sizeof(RAWINPUTHEADER)) + WARN( "Unable to read raw input data\n" ); + else if (ri.header.dwType == RIM_TYPEMOUSE) + { + EnterCriticalSection( &dinput_hook_crit ); + LIST_FOR_EACH_ENTRY( impl, &acquired_rawmouse_list, struct dinput_device, entry ) + dinput_mouse_rawinput_hook( &impl->IDirectInputDevice8W_iface, wparam, lparam, &ri ); + LeaveCriticalSection( &dinput_hook_crit ); + } + } + + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +static void register_di_em_win_class(void) +{ + WNDCLASSEXW class; + + memset(&class, 0, sizeof(class)); + class.cbSize = sizeof(class); + class.lpfnWndProc = di_em_win_wndproc; + class.hInstance = DINPUT_instance; + class.lpszClassName = L"DIEmWin"; + + if (!RegisterClassExW( &class ) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) + WARN( "Unable to register message window class\n" ); +} + +static void unregister_di_em_win_class(void) +{ + if (!UnregisterClassW( L"DIEmWin", NULL ) && GetLastError() != ERROR_CLASS_DOES_NOT_EXIST) + WARN( "Unable to unregister message window class\n" ); +} + static DWORD WINAPI dinput_thread_proc( void *params ) { struct input_thread_state state = {0}; From e51c57fe142cd0d1b41bcffd98822a7da77cea90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 22 Jan 2023 14:08:02 +0100 Subject: [PATCH 1097/2777] dinput: Use SendMessageW to notify and stop input thread. (cherry picked from commit 76a138c996da55c0f7c97d37b26fd4ae637f9f29) --- dlls/dinput/device.c | 2 - dlls/dinput/dinput_main.c | 74 +++++++++++++++++------------------- dlls/dinput/dinput_private.h | 1 - 3 files changed, 34 insertions(+), 43 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 04788b22f9a..c7b29da9271 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -565,7 +565,6 @@ static HRESULT WINAPI dinput_device_Acquire( IDirectInputDevice8W *iface ) if (hr != DI_OK) return hr; dinput_hooks_acquire_device( iface ); - check_dinput_hooks( iface, TRUE ); return hr; } @@ -585,7 +584,6 @@ static HRESULT WINAPI dinput_device_Unacquire( IDirectInputDevice8W *iface ) if (hr != DI_OK) return hr; dinput_hooks_unacquire_device( iface ); - check_dinput_hooks( iface, FALSE ); return hr; } diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 9b93e1b3640..a667969aeb5 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -51,6 +51,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); struct input_thread_state { + BOOL running; UINT events_count; UINT devices_count; HHOOK mouse_ll_hook; @@ -69,10 +70,9 @@ static inline struct dinput_device *impl_from_IDirectInputDevice8W( IDirectInput HINSTANCE DINPUT_instance; static HWND di_em_win; - static HANDLE dinput_thread; -static DWORD dinput_thread_id; static UINT input_thread_user_count; +static struct input_thread_state *input_thread_state; static CRITICAL_SECTION dinput_hook_crit; static CRITICAL_SECTION_DEBUG dinput_critsect_debug = @@ -100,6 +100,8 @@ void dinput_hooks_acquire_device( IDirectInputDevice8W *iface ) else list_add_tail( &acquired_device_list, &impl->entry ); LeaveCriticalSection( &dinput_hook_crit ); + + SendMessageW( di_em_win, WM_USER + 0x10, 1, 0 ); } void dinput_hooks_unacquire_device( IDirectInputDevice8W *iface ) @@ -109,6 +111,8 @@ void dinput_hooks_unacquire_device( IDirectInputDevice8W *iface ) EnterCriticalSection( &dinput_hook_crit ); list_remove( &impl->entry ); LeaveCriticalSection( &dinput_hook_crit ); + + SendMessageW( di_em_win, WM_USER + 0x10, 1, 0 ); } static void dinput_device_internal_unacquire( IDirectInputDevice8W *iface, DWORD status ) @@ -298,6 +302,22 @@ static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPAR } } + if (msg == WM_USER + 0x10) + { + struct input_thread_state *state = input_thread_state; + + TRACE( "Processing hook change notification wparam %#Ix, lparam %#Ix.\n", wparam, lparam ); + + if (!wparam) state->running = FALSE; + else + { + while (state->devices_count--) dinput_device_internal_release( state->devices[state->devices_count] ); + input_thread_update_device_list( state ); + } + + return 0; + } + return DefWindowProcW( hwnd, msg, wparam, lparam ); } @@ -323,19 +343,18 @@ static void unregister_di_em_win_class(void) static DWORD WINAPI dinput_thread_proc( void *params ) { - struct input_thread_state state = {0}; + struct input_thread_state state = {.running = TRUE}; struct dinput_device *device; HANDLE start_event = params; DWORD ret; MSG msg; + input_thread_state = &state; di_em_win = CreateWindowW( L"DIEmWin", L"DIEmWin", 0, 0, 0, 0, 0, HWND_MESSAGE, 0, DINPUT_instance, NULL ); - - /* Force creation of the message queue */ PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ); SetEvent( start_event ); - while ((ret = MsgWaitForMultipleObjectsEx( state.events_count, state.events, INFINITE, QS_ALLINPUT, 0 )) <= state.events_count) + while (state.running && (ret = MsgWaitForMultipleObjectsEx( state.events_count, state.events, INFINITE, QS_ALLINPUT, 0 )) <= state.events_count) { if (ret < state.events_count) { @@ -354,27 +373,17 @@ static DWORD WINAPI dinput_thread_proc( void *params ) while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) { - if (msg.message != WM_USER+0x10) - { - TranslateMessage(&msg); - DispatchMessageW(&msg); - continue; - } - - TRACE( "Processing hook change notification wparam %#Ix, lparam %#Ix.\n", msg.wParam, msg.lParam ); - - if (!msg.wParam) goto done; - - while (state.devices_count--) dinput_device_internal_release( state.devices[state.devices_count] ); - input_thread_update_device_list( &state ); - SetEvent( (HANDLE)msg.lParam ); + TranslateMessage(&msg); + DispatchMessageW(&msg); } } - ERR( "Unexpected termination, ret %#lx\n", ret ); - dinput_unacquire_window_devices( 0 ); + if (state.running) + { + ERR( "Unexpected termination, ret %#lx\n", ret ); + dinput_unacquire_window_devices( 0 ); + } -done: while (state.devices_count--) dinput_device_internal_release( state.devices[state.devices_count] ); if (state.callwndproc_hook) UnhookWindowsHookEx( state.callwndproc_hook ); if (state.keyboard_ll_hook) UnhookWindowsHookEx( state.keyboard_ll_hook ); @@ -395,7 +404,7 @@ void input_thread_add_user(void) if (!(start_event = CreateEventW( NULL, FALSE, FALSE, NULL ))) ERR( "Failed to create start event, error %lu\n", GetLastError() ); - else if (!(dinput_thread = CreateThread( NULL, 0, dinput_thread_proc, start_event, 0, &dinput_thread_id ))) + else if (!(dinput_thread = CreateThread( NULL, 0, dinput_thread_proc, start_event, 0, NULL ))) ERR( "Failed to create internal thread, error %lu\n", GetLastError() ); else WaitForSingleObject( start_event, INFINITE ); @@ -412,28 +421,13 @@ void input_thread_remove_user(void) { TRACE( "Stopping input thread.\n" ); - PostThreadMessageW( dinput_thread_id, WM_USER + 0x10, 0, 0 ); + SendMessageW( di_em_win, WM_USER + 0x10, 0, 0 ); WaitForSingleObject( dinput_thread, INFINITE ); CloseHandle( dinput_thread ); } LeaveCriticalSection( &dinput_hook_crit ); } -void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired ) -{ - HANDLE hook_change_finished_event = NULL; - - EnterCriticalSection(&dinput_hook_crit); - - hook_change_finished_event = CreateEventW( NULL, FALSE, FALSE, NULL ); - PostThreadMessageW( dinput_thread_id, WM_USER + 0x10, 1, (LPARAM)hook_change_finished_event ); - - LeaveCriticalSection(&dinput_hook_crit); - - WaitForSingleObject(hook_change_finished_event, INFINITE); - CloseHandle(hook_change_finished_event); -} - void check_dinput_events(void) { /* Windows does not do that, but our current implementation of winex11 diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h index 7d167619cae..4a54fb57df8 100644 --- a/dlls/dinput/dinput_private.h +++ b/dlls/dinput/dinput_private.h @@ -75,7 +75,6 @@ extern int dinput_keyboard_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPA extern void dinput_mouse_rawinput_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lparam, RAWINPUT *raw ); -extern void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired ) DECLSPEC_HIDDEN; extern void check_dinput_events(void) DECLSPEC_HIDDEN; extern HRESULT _configure_devices(IDirectInput8W *iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback, LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData) DECLSPEC_HIDDEN; From d4731b38f0729ef54459be7062a8e39bfbf7995c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 22 Jan 2023 15:11:13 +0100 Subject: [PATCH 1098/2777] dinput: Avoid entering hook CS for rawinput messages. (cherry picked from commit e5eeca384384b1edf20ce2ec9716c93b89f16ea6) --- dlls/dinput/dinput_main.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index a667969aeb5..746b2c0b68e 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -234,6 +234,8 @@ static void input_thread_update_device_list( struct input_thread_state *state ) if (device->dwCoopLevel & DISCL_EXCLUSIVE) rawinput_mouse.dwFlags |= RIDEV_NOLEGACY | RIDEV_CAPTUREMOUSE; rawinput_mouse.dwFlags &= ~RIDEV_REMOVE; rawinput_mouse.hwndTarget = di_em_win; + dinput_device_internal_addref( (state->devices[count] = device) ); + if (++count >= INPUT_THREAD_MAX_DEVICES) break; } LIST_FOR_EACH_ENTRY( device, &acquired_mouse_list, struct dinput_device, entry ) { @@ -281,10 +283,10 @@ static void input_thread_update_device_list( struct input_thread_state *state ) static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - struct dinput_device *impl; - RAWINPUT ri; - UINT size = sizeof(ri); + struct input_thread_state *state = input_thread_state; int rim = GET_RAWINPUT_CODE_WPARAM( wparam ); + UINT i, size = sizeof(RAWINPUT); + RAWINPUT ri; TRACE( "%p %d %Ix %Ix\n", hwnd, msg, wparam, lparam ); @@ -295,17 +297,25 @@ static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPAR WARN( "Unable to read raw input data\n" ); else if (ri.header.dwType == RIM_TYPEMOUSE) { - EnterCriticalSection( &dinput_hook_crit ); - LIST_FOR_EACH_ENTRY( impl, &acquired_rawmouse_list, struct dinput_device, entry ) - dinput_mouse_rawinput_hook( &impl->IDirectInputDevice8W_iface, wparam, lparam, &ri ); - LeaveCriticalSection( &dinput_hook_crit ); + for (i = state->events_count; i < state->devices_count; ++i) + { + struct dinput_device *device = state->devices[i]; + if (!device->use_raw_input) continue; + if (device->instance.dwDevType & DIDEVTYPE_HID) continue; + switch (GET_DIDEVICE_TYPE( device->instance.dwDevType )) + { + case DIDEVTYPE_MOUSE: + case DI8DEVTYPE_MOUSE: + dinput_mouse_rawinput_hook( &device->IDirectInputDevice8W_iface, wparam, lparam, &ri ); + break; + default: break; + } + } } } if (msg == WM_USER + 0x10) { - struct input_thread_state *state = input_thread_state; - TRACE( "Processing hook change notification wparam %#Ix, lparam %#Ix.\n", wparam, lparam ); if (!wparam) state->running = FALSE; @@ -349,9 +359,8 @@ static DWORD WINAPI dinput_thread_proc( void *params ) DWORD ret; MSG msg; - input_thread_state = &state; di_em_win = CreateWindowW( L"DIEmWin", L"DIEmWin", 0, 0, 0, 0, 0, HWND_MESSAGE, 0, DINPUT_instance, NULL ); - PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ); + input_thread_state = &state; SetEvent( start_event ); while (state.running && (ret = MsgWaitForMultipleObjectsEx( state.events_count, state.events, INFINITE, QS_ALLINPUT, 0 )) <= state.events_count) From fbe2eeec6b5934df20935f284813ea29e79421c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Jan 2023 22:19:45 +0100 Subject: [PATCH 1099/2777] include: Add Windows.Foundation.Collections.IVectorChangedEventArgs definition. (cherry picked from commit a483e9928b4787d93f3bbe417f0a2fcbbaf7c564) --- include/Makefile.in | 1 + include/ivectorchangedeventargs.idl | 49 +++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 include/ivectorchangedeventargs.idl diff --git a/include/Makefile.in b/include/Makefile.in index 8ea42337ba3..f37e0098ed1 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -378,6 +378,7 @@ SOURCES = \ iprtrmib.h \ iptypes.h \ isguids.h \ + ivectorchangedeventargs.idl \ knownfolders.h \ ks.h \ ksguid.h \ diff --git a/include/ivectorchangedeventargs.idl b/include/ivectorchangedeventargs.idl new file mode 100644 index 00000000000..45720b595f2 --- /dev/null +++ b/include/ivectorchangedeventargs.idl @@ -0,0 +1,49 @@ +/* + * Copyright 2022 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 + */ + +#ifdef __WIDL__ +#pragma winrt ns_prefix +#endif + +import "inspectable.idl"; +import "windowscontracts.idl"; + +namespace Windows.Foundation.Collections { + [contract(Windows.Foundation.FoundationContract, 1.0)] + enum CollectionChange + { + Reset = 0, + ItemInserted = 1, + ItemRemoved = 2, + ItemChanged = 3, + }; + typedef enum CollectionChange CollectionChange; + + [ + contract(Windows.Foundation.FoundationContract, 1.0), + uuid(575933df-34fe-4480-af15-07691f3d5d9b), + pointer_default(unique), + version(0x06020000 /* NTDDI_WIN8 */), + object, + ] + interface IVectorChangedEventArgs : IInspectable + { + [propget] HRESULT CollectionChange([out, retval] CollectionChange *value); + [propget] HRESULT Index([out, retval] unsigned *value); + }; +} From b98a836d423b4f1cfb42d4089450c445480ef913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Jan 2023 22:19:45 +0100 Subject: [PATCH 1100/2777] include: Add Windows.Foundation.Collections.IMapChangedEventArgs definition. (cherry picked from commit f122309f356571505d7cd6ec940bcede8781fb30) --- include/windows.foundation.collections.idl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/windows.foundation.collections.idl b/include/windows.foundation.collections.idl index 395adad27aa..567c411e129 100644 --- a/include/windows.foundation.collections.idl +++ b/include/windows.foundation.collections.idl @@ -24,6 +24,7 @@ import "inspectable.idl"; import "asyncinfo.idl"; import "windowscontracts.idl"; /* import "eventtoken.idl"; */ +import "ivectorchangedeventargs.idl"; namespace Windows { namespace Foundation { @@ -105,6 +106,16 @@ cpp_quote("#endif") HRESULT First([out, retval] Windows.Foundation.Collections.IIterator **value); } + [ + contract(Windows.Foundation.FoundationContract, 1.0), + uuid(9939f4df-050a-4c0f-aa60-77075f9c4777) + ] + interface IMapChangedEventArgs : IInspectable + { + [propget] HRESULT CollectionChanged([out, retval] Windows.Foundation.Collections.CollectionChange *value); + [propget] HRESULT Key([out, retval] T *key); + } + [ contract(Windows.Foundation.FoundationContract, 1.0), uuid(02b51929-c1c4-4a7e-8940-0312b5c18500) From 965d4d7aeb328e4c2f4d99c3b00138a3f7344ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Jan 2023 22:19:45 +0100 Subject: [PATCH 1101/2777] include: Add Windows.Foundation.Collections.MapChangedEventHandler definition. (cherry picked from commit 634b163407dab08406b014157991c3e69909a483) --- include/windows.foundation.collections.idl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/windows.foundation.collections.idl b/include/windows.foundation.collections.idl index 567c411e129..31da63d5f5d 100644 --- a/include/windows.foundation.collections.idl +++ b/include/windows.foundation.collections.idl @@ -116,6 +116,15 @@ cpp_quote("#endif") [propget] HRESULT Key([out, retval] T *key); } + interface IObservableMap; + + [ + contract(Windows.Foundation.FoundationContract, 1.0), + uuid(179517f3-94ee-41f8-bddc-768a895544f3) + ] + delegate HRESULT MapChangedEventHandler([in] Windows.Foundation.Collections.IObservableMap *sender, + [in] Windows.Foundation.Collections.IMapChangedEventArgs *args); + [ contract(Windows.Foundation.FoundationContract, 1.0), uuid(02b51929-c1c4-4a7e-8940-0312b5c18500) From 0048f96a948ed96bebf60918c18b9d824d14da83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Jan 2023 22:19:45 +0100 Subject: [PATCH 1102/2777] include: Add Windows.Foundation.Collections.IMap definition. (cherry picked from commit 44906b6051c216a021f0449f5e1b627e14f24948) --- include/windows.foundation.collections.idl | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/windows.foundation.collections.idl b/include/windows.foundation.collections.idl index 31da63d5f5d..8156a833a96 100644 --- a/include/windows.foundation.collections.idl +++ b/include/windows.foundation.collections.idl @@ -149,6 +149,22 @@ cpp_quote("#endif") [out] Windows.Foundation.Collections.IMapView **second); } + [ + contract(Windows.Foundation.FoundationContract, 1.0), + uuid(3c2925fe-8519-45c1-aa79-197b6718c1c1) + ] + interface IMap : IInspectable + requires Windows.Foundation.Collections.IIterable *> + { + HRESULT Lookup([in] K key, [out, retval] V *value); + [propget] HRESULT Size([out, retval] unsigned int *size); + HRESULT HasKey([in] K key, [out, retval] boolean *found); + HRESULT GetView([out, retval] Windows.Foundation.Collections.IMapView **view); + HRESULT Insert([in] K key, [in] V value, [out, retval] boolean *replaced); + HRESULT Remove([in] K key); + HRESULT Clear(); + } + [ contract(Windows.Foundation.FoundationContract, 1.0), uuid(bbe1fa4c-b0e3-4583-baef-1f1b2e483e56) From 72938bc2f741306437c20fe336e3379960acb3c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Jan 2023 22:19:45 +0100 Subject: [PATCH 1103/2777] include: Add Windows.Foundation.Collections.IObservableMap definition. (cherry picked from commit 1aadd3fc6da0b975c58dc13efb9215e3efce9aa3) --- include/windows.foundation.collections.idl | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/include/windows.foundation.collections.idl b/include/windows.foundation.collections.idl index 8156a833a96..36fb9bf4161 100644 --- a/include/windows.foundation.collections.idl +++ b/include/windows.foundation.collections.idl @@ -23,7 +23,7 @@ import "inspectable.idl"; import "asyncinfo.idl"; import "windowscontracts.idl"; -/* import "eventtoken.idl"; */ +import "eventtoken.idl"; import "ivectorchangedeventargs.idl"; namespace Windows { @@ -165,6 +165,18 @@ cpp_quote("#endif") HRESULT Clear(); } + [ + contract(Windows.Foundation.FoundationContract, 1.0), + uuid(65df2bf5-bf39-41b5-aebc-5a9d865e472b) + ] + interface IObservableMap : IInspectable + requires Windows.Foundation.Collections.IMap + { + [eventadd] HRESULT MapChanged([in] Windows.Foundation.Collections.MapChangedEventHandler *handler, + [out, retval] EventRegistrationToken *token); + [eventremove] HRESULT MapChanged([in] EventRegistrationToken token); + } + [ contract(Windows.Foundation.FoundationContract, 1.0), uuid(bbe1fa4c-b0e3-4583-baef-1f1b2e483e56) From 64c2af21fb45cced9bae99b7d9f0aabc6ea5b2d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Jan 2023 22:19:45 +0100 Subject: [PATCH 1104/2777] include: Add Windows.Foundation.Collections.IPropertySet definition. (cherry picked from commit 5050ae668dc291b04f25bd15cd04c5e09a3bcb16) --- include/windows.foundation.idl | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/include/windows.foundation.idl b/include/windows.foundation.idl index cdc603f8e84..96bdd1167e6 100644 --- a/include/windows.foundation.idl +++ b/include/windows.foundation.idl @@ -27,6 +27,32 @@ import "eventtoken.idl"; /* import "ivectorchangedeventargs.idl"; */ import "windows.foundation.collections.idl"; +namespace Windows.Foundation.Collections { + interface IPropertySet; + + declare { + interface Windows.Foundation.Collections.IKeyValuePair; + interface Windows.Foundation.Collections.IIterable *>; + interface Windows.Foundation.Collections.IIterator *>; + interface Windows.Foundation.Collections.IMapChangedEventArgs; + interface Windows.Foundation.Collections.MapChangedEventHandler; + interface Windows.Foundation.Collections.IMap; + interface Windows.Foundation.Collections.IMapView; + interface Windows.Foundation.Collections.IObservableMap; + } + + [ + contract(Windows.Foundation.FoundationContract, 1.0), + uuid(8a43ed9f-f4e6-4421-acf9-1dab2986820c) + ] + interface IPropertySet : IInspectable + requires Windows.Foundation.Collections.IObservableMap, + Windows.Foundation.Collections.IMap, + Windows.Foundation.Collections.IIterable *> + { + } +} + namespace Windows.Foundation { typedef enum PropertyType PropertyType; typedef struct Point Point; From c9fe50d57a9b03bda5ce14a9a9c91766e6783513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Jan 2023 22:19:45 +0100 Subject: [PATCH 1105/2777] include: Add Windows.Foundation.Collections.IObservableVector definition. (cherry picked from commit fe11aa6ad155c35bef1fa129163dc1ffd6a6faab) --- include/windows.foundation.collections.idl | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/windows.foundation.collections.idl b/include/windows.foundation.collections.idl index 36fb9bf4161..4b72c63882c 100644 --- a/include/windows.foundation.collections.idl +++ b/include/windows.foundation.collections.idl @@ -177,6 +177,15 @@ cpp_quote("#endif") [eventremove] HRESULT MapChanged([in] EventRegistrationToken token); } + interface IObservableVector; + + [ + contract(Windows.Foundation.FoundationContract, 1.0), + uuid(0c051752-9fbf-4c70-aa0c-0e4c82d9a761) + ] + delegate HRESULT VectorChangedEventHandler([in] Windows.Foundation.Collections.IObservableVector *sender, + [in] Windows.Foundation.Collections.IVectorChangedEventArgs *args); + [ contract(Windows.Foundation.FoundationContract, 1.0), uuid(bbe1fa4c-b0e3-4583-baef-1f1b2e483e56) @@ -210,6 +219,18 @@ cpp_quote("#endif") HRESULT GetMany([in] UINT32 start_index, [in] UINT32 items_size, [out] T *items, [out, retval] UINT32 *value); HRESULT ReplaceAll([in] UINT32 count, [in] T *items); } + + [ + contract(Windows.Foundation.FoundationContract, 1.0), + uuid(5917eb53-50b4-4a0d-b309-65862b3f1dbc) + ] + interface IObservableVector : IInspectable + requires Windows.Foundation.Collections.IVector + { + [eventadd] HRESULT VectorChanged([in] Windows.Foundation.Collections.VectorChangedEventHandler *handler, + [out, retval] EventRegistrationToken *token); + [eventremove] HRESULT VectorChanged([in] EventRegistrationToken token); + } } #endif } From dbc481ff93f2791b4470747134f237e7f3f3e9df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Jan 2023 22:19:45 +0100 Subject: [PATCH 1106/2777] include: Add Windows.Foundation.IAsyncActionWithProgress definition. (cherry picked from commit f0f83180c674153ff79b597009fd54a3b0bd8155) --- include/windows.foundation.collections.idl | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/include/windows.foundation.collections.idl b/include/windows.foundation.collections.idl index 4b72c63882c..0f10f4dbc00 100644 --- a/include/windows.foundation.collections.idl +++ b/include/windows.foundation.collections.idl @@ -68,6 +68,34 @@ cpp_quote("#endif") HRESULT GetResults([out, retval] TResult *results); } + interface IAsyncActionWithProgress; + + [ + contract(Windows.Foundation.FoundationContract, 1.0), + uuid(6d844858-0cff-4590-ae89-95a5a5c8b4b8) + ] + delegate HRESULT AsyncActionProgressHandler([in] Windows.Foundation.IAsyncActionWithProgress *info, + [in] TProgress progress); + [ + contract(Windows.Foundation.FoundationContract, 1.0), + uuid(9c029f91-cc84-44fd-ac26-0a6c4e555281) + ] + delegate HRESULT AsyncActionWithProgressCompletedHandler([in] Windows.Foundation.IAsyncActionWithProgress *info, + [in] AsyncStatus status); + + [ + contract(Windows.Foundation.FoundationContract, 1.0), + uuid(1f6db258-e803-48a1-9546-eb7353398884) + ] + interface IAsyncActionWithProgress : IInspectable + { + [propput] HRESULT Progress([in] Windows.Foundation.AsyncActionProgressHandler *handler); + [propget] HRESULT Progress([out, retval] Windows.Foundation.AsyncActionProgressHandler **handler); + [propput] HRESULT Completed([in] Windows.Foundation.AsyncActionWithProgressCompletedHandler *handler); + [propget] HRESULT Completed([out, retval] Windows.Foundation.AsyncActionWithProgressCompletedHandler **handler); + HRESULT GetResults(); + } + [ contract(Windows.Foundation.FoundationContract, 1.0), uuid(9de1c534-6ae1-11e0-84e1-18a905bcc53f) From 78906e558c301b84d35f7f50dfbb32f5d1b11ea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Jan 2023 22:19:45 +0100 Subject: [PATCH 1107/2777] include: Add Windows.Foundation.IAsyncOperationWithProgress definition. (cherry picked from commit c5c9108d8c67e55720c121ffd7e6ae09b8aad80a) --- include/windows.foundation.collections.idl | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/include/windows.foundation.collections.idl b/include/windows.foundation.collections.idl index 0f10f4dbc00..680d7803cc8 100644 --- a/include/windows.foundation.collections.idl +++ b/include/windows.foundation.collections.idl @@ -96,6 +96,34 @@ cpp_quote("#endif") HRESULT GetResults(); } + interface IAsyncOperationWithProgress; + + [ + contract(Windows.Foundation.FoundationContract, 1.0), + uuid(55690902-0aab-421a-8778-f8ce5026d758) + ] + delegate HRESULT AsyncOperationProgressHandler([in] Windows.Foundation.IAsyncOperationWithProgress *info, + [in] TProgress progress); + [ + contract(Windows.Foundation.FoundationContract, 1.0), + uuid(e85df41d-6aa7-46e3-a8e2-f009d840c627) + ] + delegate HRESULT AsyncOperationWithProgressCompletedHandler([in] Windows.Foundation.IAsyncOperationWithProgress *info, + [in] AsyncStatus status); + + [ + contract(Windows.Foundation.FoundationContract, 1.0), + uuid(b5d036d7-e297-498f-ba60-0289e76e23dd) + ] + interface IAsyncOperationWithProgress : IInspectable + { + [propput] HRESULT Progress([in] Windows.Foundation.AsyncOperationProgressHandler *handler); + [propget] HRESULT Progress([out, retval] Windows.Foundation.AsyncOperationProgressHandler **handler); + [propput] HRESULT Completed([in] Windows.Foundation.AsyncOperationWithProgressCompletedHandler *handler); + [propget] HRESULT Completed([out, retval] Windows.Foundation.AsyncOperationWithProgressCompletedHandler **handler); + HRESULT GetResults([out, retval] TResult *results); + } + [ contract(Windows.Foundation.FoundationContract, 1.0), uuid(9de1c534-6ae1-11e0-84e1-18a905bcc53f) From c95b39a046f4f51a93783bc7b107dd2ecb5eecb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 3 Feb 2023 22:17:33 +0100 Subject: [PATCH 1108/2777] Revert "user32: Implement rudimentary EnableMouseInPointer support." This reverts commit 8da1fcd1be94ed2b7db77697d24ecbee6bca4885. --- dlls/user32/input.c | 11 +++++++++ dlls/user32/user32.spec | 2 +- dlls/win32u/input.c | 15 ------------ dlls/win32u/message.c | 45 ------------------------------------ dlls/win32u/syscall.c | 1 - dlls/win32u/win32u.spec | 2 +- dlls/win32u/win32u_private.h | 1 - include/ntuser.h | 1 - 8 files changed, 13 insertions(+), 65 deletions(-) diff --git a/dlls/user32/input.c b/dlls/user32/input.c index e81fda9513e..440737328e5 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -495,6 +495,17 @@ BOOL WINAPI UnloadKeyboardLayout( HKL layout ) } +/*********************************************************************** + * EnableMouseInPointer (USER32.@) + */ +BOOL WINAPI EnableMouseInPointer(BOOL enable) +{ + FIXME("(%#x) stub\n", enable); + + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + static DWORD CALLBACK devnotify_window_callback(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header) { SendMessageTimeoutW(handle, WM_DEVICECHANGE, flags, (LPARAM)header, SMTO_ABORTIFHUNG, 2000, NULL); diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 18c371ac2fe..133cb31a449 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -205,7 +205,7 @@ @ stdcall EditWndProc(long long long long) EditWndProcA @ stdcall EmptyClipboard() NtUserEmptyClipboard @ stdcall EnableMenuItem(long long long) NtUserEnableMenuItem -@ stdcall EnableMouseInPointer(long) NtUserEnableMouseInPointer +@ stdcall EnableMouseInPointer(long) @ stdcall EnableNonClientDpiScaling(long) @ stdcall -import EnableScrollBar(long long long) NtUserEnableScrollBar @ stdcall EnableWindow(long long) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 77f81248c6d..2cc17bdfc2d 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -50,10 +50,6 @@ static const WCHAR keyboard_layouts_keyW[] = '\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s' }; - -BOOL enable_mouse_in_pointer = FALSE; - - /********************************************************************** * NtUserAttachThreadInput (win32u.@) */ @@ -2201,17 +2197,6 @@ BOOL unregister_touch_window( HWND hwnd ) } -/********************************************************************** - * NtUserEnableMouseInPointer (win32u.@) - */ -BOOL WINAPI NtUserEnableMouseInPointer( BOOL enable ) -{ - FIXME( "enable %u semi-stub!\n", enable ); - enable_mouse_in_pointer = TRUE; - return TRUE; -} - - HWND get_shell_window(void) { HWND hwnd = 0; diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 8748d5acfc5..655d10695d9 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1639,51 +1639,6 @@ static BOOL process_mouse_message( MSG *msg, UINT hw_id, ULONG_PTR extra_info, H msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt ); SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( msg->hwnd )); - if ((extra_info & 0xffffff00) != 0xff515700 && enable_mouse_in_pointer) - { - WORD flags = POINTER_MESSAGE_FLAG_PRIMARY; - DWORD message = 0; - - switch (msg->message) - { - case WM_MOUSEMOVE: - message = WM_POINTERUPDATE; - flags |= POINTER_MESSAGE_FLAG_INRANGE; - break; - case WM_LBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_XBUTTONDOWN: - message = WM_POINTERDOWN; - flags |= POINTER_MESSAGE_FLAG_INRANGE|POINTER_MESSAGE_FLAG_INCONTACT; - if (msg->message == WM_LBUTTONDOWN) flags |= POINTER_MESSAGE_FLAG_FIRSTBUTTON; - if (msg->message == WM_RBUTTONDOWN) flags |= POINTER_MESSAGE_FLAG_SECONDBUTTON; - if (msg->message == WM_MBUTTONDOWN) flags |= POINTER_MESSAGE_FLAG_THIRDBUTTON; - if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_LBUTTON) flags |= POINTER_MESSAGE_FLAG_FIRSTBUTTON; - if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_RBUTTON) flags |= POINTER_MESSAGE_FLAG_SECONDBUTTON; - if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_MBUTTON) flags |= POINTER_MESSAGE_FLAG_THIRDBUTTON; - if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_XBUTTON1) flags |= POINTER_MESSAGE_FLAG_FOURTHBUTTON; - if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_XBUTTON2) flags |= POINTER_MESSAGE_FLAG_FIFTHBUTTON; - break; - case WM_LBUTTONUP: - case WM_RBUTTONUP: - case WM_MBUTTONUP: - case WM_XBUTTONUP: - message = WM_POINTERUP; - break; - case WM_MOUSEWHEEL: - message = WM_POINTERWHEEL; - flags = HIWORD( msg->wParam ); - break; - case WM_MOUSEHWHEEL: - message = WM_POINTERHWHEEL; - flags = HIWORD( msg->wParam ); - break; - } - - if (message) send_message( msg->hwnd, message, MAKELONG( 1, flags ), MAKELONG( msg->pt.x, msg->pt.y ) ); - } - /* FIXME: is this really the right place for this hook? */ event.message = msg->message; event.time = msg->time; diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index 6fbbedd628f..1735b0c8133 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -145,7 +145,6 @@ static void * const syscalls[] = NtUserDrawIconEx, NtUserEmptyClipboard, NtUserEnableMenuItem, - NtUserEnableMouseInPointer, NtUserEnableScrollBar, NtUserEndDeferWindowPosEx, NtUserEndMenu, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index def27cc05f2..f800f7408ae 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -861,7 +861,7 @@ @ stub NtUserEnableChildWindowDpiMessage @ stub NtUserEnableIAMAccess @ stdcall -syscall NtUserEnableMenuItem(long long long) -@ stdcall -syscall NtUserEnableMouseInPointer(long) +@ stub NtUserEnableMouseInPointer @ stub NtUserEnableMouseInPointerForWindow @ stub NtUserEnableMouseInputForCursorSuppression @ stub NtUserEnableNonClientDpiScaling diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 87c76e7422c..489750bdc3c 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -265,7 +265,6 @@ extern void unregister_imm_window( HWND hwnd ) DECLSPEC_HIDDEN; /* input.c */ extern BOOL destroy_caret(void) DECLSPEC_HIDDEN; -extern BOOL enable_mouse_in_pointer DECLSPEC_HIDDEN; extern HWND get_active_window(void) DECLSPEC_HIDDEN; extern HWND get_capture(void) DECLSPEC_HIDDEN; extern BOOL get_cursor_pos( POINT *pt ) DECLSPEC_HIDDEN; diff --git a/include/ntuser.h b/include/ntuser.h index 97659711310..b9e19699e73 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -701,7 +701,6 @@ BOOL WINAPI NtUserDrawIconEx( HDC hdc, INT x0, INT y0, HICON icon, INT width, DWORD WINAPI NtUserDrawMenuBarTemp( HWND hwnd, HDC hdc, RECT *rect, HMENU handle, HFONT font ); BOOL WINAPI NtUserEmptyClipboard(void); BOOL WINAPI NtUserEnableMenuItem( HMENU handle, UINT id, UINT flags ); -BOOL WINAPI NtUserEnableMouseInPointer( BOOL enable ); BOOL WINAPI NtUserEnableScrollBar( HWND hwnd, UINT bar, UINT flags ); BOOL WINAPI NtUserEndDeferWindowPosEx( HDWP hdwp, BOOL async ); BOOL WINAPI NtUserEndMenu(void); From 87827e153902709d05c045efe9b1c947772292a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 3 Feb 2023 22:17:45 +0100 Subject: [PATCH 1109/2777] Revert "user32: Implement semi-stub touch input support." This reverts commit 72a60e472c88469d69f9273148abd9620263d4a3. --- dlls/user32/input.c | 21 ++++++++++++--------- dlls/win32u/input.c | 21 ++------------------- dlls/win32u/ntuser_private.h | 1 - dlls/win32u/sysparams.c | 6 ------ dlls/win32u/win32u_private.h | 2 -- include/ntuser.h | 2 -- 6 files changed, 14 insertions(+), 39 deletions(-) diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 440737328e5..66a66b8f0d3 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -659,8 +659,9 @@ LRESULT WINAPI DefRawInputProc( RAWINPUT **data, INT data_count, UINT header_siz */ BOOL WINAPI CloseTouchInputHandle( HTOUCHINPUT handle ) { - TRACE( "handle %p.\n", handle ); - return TRUE; + FIXME( "handle %p stub!\n", handle ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; } /***************************************************************************** @@ -668,9 +669,9 @@ BOOL WINAPI CloseTouchInputHandle( HTOUCHINPUT handle ) */ BOOL WINAPI GetTouchInputInfo( HTOUCHINPUT handle, UINT count, TOUCHINPUT *ptr, int size ) { - TRACE( "handle %p, count %u, ptr %p, size %u.\n", handle, count, ptr, size ); - *ptr = *(TOUCHINPUT *)handle; - return TRUE; + FIXME( "handle %p, count %u, ptr %p, size %u stub!\n", handle, count, ptr, size ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; } /***************************************************************************** @@ -678,8 +679,9 @@ BOOL WINAPI GetTouchInputInfo( HTOUCHINPUT handle, UINT count, TOUCHINPUT *ptr, */ BOOL WINAPI RegisterTouchWindow( HWND hwnd, ULONG flags ) { - TRACE( "hwnd %p, flags %#lx.\n", hwnd, flags ); - return NtUserCallTwoParam( (ULONG_PTR)hwnd, flags, NtUserCallTwoParam_RegisterTouchWindow ); + FIXME( "hwnd %p, flags %#lx stub!\n", hwnd, flags ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; } /***************************************************************************** @@ -687,8 +689,9 @@ BOOL WINAPI RegisterTouchWindow( HWND hwnd, ULONG flags ) */ BOOL WINAPI UnregisterTouchWindow( HWND hwnd ) { - TRACE( "hwnd %p.\n", hwnd ); - return NtUserCallOneParam( (ULONG_PTR)hwnd, NtUserCallOneParam_UnregisterTouchWindow ); + FIXME( "hwnd %p stub!\n", hwnd ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; } /***************************************************************************** diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 2cc17bdfc2d..2ef215e94ab 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2175,25 +2175,8 @@ void toggle_caret( HWND hwnd ) */ BOOL WINAPI NtUserIsTouchWindow( HWND hwnd, ULONG *flags ) { - DWORD win_flags = win_set_flags( hwnd, 0, 0 ); - TRACE( "hwnd %p, flags %p.\n", hwnd, flags ); - return (win_flags & WIN_IS_TOUCH) != 0; -} - - -BOOL register_touch_window( HWND hwnd, UINT flags ) -{ - DWORD win_flags = win_set_flags( hwnd, WIN_IS_TOUCH, 0 ); - TRACE( "hwnd %p, flags %#x.\n", hwnd, flags ); - return (win_flags & WIN_IS_TOUCH) == 0; -} - - -BOOL unregister_touch_window( HWND hwnd ) -{ - DWORD win_flags = win_set_flags( hwnd, 0, WIN_IS_TOUCH ); - TRACE( "hwnd %p.\n", hwnd ); - return (win_flags & WIN_IS_TOUCH) != 0; + FIXME( "hwnd %p, flags %p stub!\n", hwnd, flags ); + return FALSE; } diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 4c92480b476..6eb182e5979 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -104,7 +104,6 @@ typedef struct tagWND #define WIN_NEEDS_SHOW_OWNEDPOPUP 0x0020 /* WM_SHOWWINDOW:SC_SHOW must be sent in the next ShowOwnedPopup call */ #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 */ #define WND_OTHER_PROCESS ((WND *)1) /* returned by get_win_ptr on unknown window handles */ diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index cba0052577d..36aed0ad43b 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -5613,9 +5613,6 @@ ULONG_PTR WINAPI NtUserCallOneParam( ULONG_PTR arg, ULONG code ) process_layout = arg; return TRUE; - case NtUserCallOneParam_UnregisterTouchWindow: - return unregister_touch_window( (HWND)arg ); - /* temporary exports */ case NtUserGetDeskPattern: return get_entry( &entry_DESKPATTERN, 256, (WCHAR *)arg ); @@ -5648,9 +5645,6 @@ ULONG_PTR WINAPI NtUserCallTwoParam( ULONG_PTR arg1, ULONG_PTR arg2, ULONG code case NtUserCallTwoParam_MonitorFromRect: return HandleToUlong( monitor_from_rect( (const RECT *)arg1, arg2, get_thread_dpi() )); - case NtUserCallTwoParam_RegisterTouchWindow: - return register_touch_window( (HWND)arg1, arg2 ); - case NtUserCallTwoParam_SetCaretPos: return set_caret_pos( arg1, arg2 ); diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 489750bdc3c..98af7c73c9c 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -273,7 +273,6 @@ extern DWORD get_input_state(void) DECLSPEC_HIDDEN; extern HWND get_progman_window(void) DECLSPEC_HIDDEN; extern HWND get_shell_window(void) DECLSPEC_HIDDEN; extern HWND get_taskman_window(void) DECLSPEC_HIDDEN; -extern BOOL register_touch_window( HWND hwnd, UINT flags ) DECLSPEC_HIDDEN; extern BOOL WINAPI release_capture(void) DECLSPEC_HIDDEN; extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) DECLSPEC_HIDDEN; extern BOOL set_caret_blink_time( unsigned int time ) DECLSPEC_HIDDEN; @@ -282,7 +281,6 @@ extern BOOL set_foreground_window( HWND hwnd, BOOL mouse ) DECLSPEC_HIDDEN; extern HWND set_progman_window( HWND hwnd ) DECLSPEC_HIDDEN; extern HWND set_taskman_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void toggle_caret( HWND hwnd ) DECLSPEC_HIDDEN; -extern BOOL unregister_touch_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void update_mouse_tracking_info( HWND hwnd ) DECLSPEC_HIDDEN; /* menu.c */ diff --git a/include/ntuser.h b/include/ntuser.h index b9e19699e73..15fc6b3bc4e 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -991,7 +991,6 @@ enum NtUserCallOneParam_ReplyMessage, NtUserCallOneParam_SetCaretBlinkTime, NtUserCallOneParam_SetProcessDefaultLayout, - NtUserCallOneParam_UnregisterTouchWindow, /* temporary exports */ NtUserGetDeskPattern, }; @@ -1118,7 +1117,6 @@ enum NtUserCallTwoParam_GetMonitorInfo, NtUserCallTwoParam_GetSystemMetricsForDpi, NtUserCallTwoParam_MonitorFromRect, - NtUserCallTwoParam_RegisterTouchWindow, NtUserCallTwoParam_SetCaretPos, NtUserCallTwoParam_SetIconParam, NtUserCallTwoParam_UnhookWindowsHook, From 9a9144256c9f03d204765d082199cb77b0cf80f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 3 Feb 2023 22:18:02 +0100 Subject: [PATCH 1110/2777] Revert "user32: Translate WM_POINTER* messages to WM_TOUCH in DefWindowProc." This reverts commit 785173112d5ea563362143ae4c373da92e02fe24. --- dlls/user32/input.c | 9 +++++++++ dlls/user32/user32.spec | 2 +- dlls/win32u/defwnd.c | 32 -------------------------------- dlls/win32u/input.c | 11 ----------- dlls/win32u/syscall.c | 1 - dlls/win32u/win32u.spec | 2 +- include/ntuser.h | 1 - 7 files changed, 11 insertions(+), 47 deletions(-) diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 66a66b8f0d3..c5387cf9212 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -674,6 +674,15 @@ BOOL WINAPI GetTouchInputInfo( HTOUCHINPUT handle, UINT count, TOUCHINPUT *ptr, return FALSE; } +/********************************************************************** + * IsTouchWindow (USER32.@) + */ +BOOL WINAPI IsTouchWindow( HWND hwnd, ULONG *flags ) +{ + FIXME( "hwnd %p, flags %p stub!\n", hwnd, flags ); + return FALSE; +} + /***************************************************************************** * RegisterTouchWindow (USER32.@) */ diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 133cb31a449..1628c7ca74a 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -478,7 +478,7 @@ @ stdcall IsProcessDPIAware() @ stdcall IsRectEmpty(ptr) # @ stub IsServerSideWindow -@ stdcall IsTouchWindow(long ptr) NtUserIsTouchWindow +@ stdcall IsTouchWindow(long ptr) @ stdcall IsValidDpiAwarenessContext(long) @ stdcall IsWinEventHookInstalled(long) @ stdcall IsWindow(long) diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c index 76779974cfb..85cdc61be1c 100644 --- a/dlls/win32u/defwnd.c +++ b/dlls/win32u/defwnd.c @@ -30,8 +30,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); -#define WINE_MOUSE_HANDLE ((HANDLE)1) -#define WINE_KEYBOARD_HANDLE ((HANDLE)2) #define DRAG_FILE 0x454c4946 @@ -2945,36 +2943,6 @@ LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, 0, NtUserSendMessage, ansi ); } break; - - case WM_POINTERDOWN: - case WM_POINTERUP: - case WM_POINTERUPDATE: - { - TOUCHINPUT touchinput; - - if (!NtUserIsTouchWindow( hwnd, NULL )) return 0; - touchinput.x = LOWORD( lparam ) * 100; - touchinput.y = HIWORD( lparam ) * 100; - touchinput.hSource = WINE_MOUSE_HANDLE; - touchinput.dwID = GET_POINTERID_WPARAM( wparam ); - touchinput.dwFlags = TOUCHEVENTF_NOCOALESCE | TOUCHEVENTF_PALM; - if (msg == WM_POINTERDOWN) touchinput.dwFlags |= TOUCHEVENTF_DOWN; - if (msg == WM_POINTERUP) touchinput.dwFlags |= TOUCHEVENTF_UP; - if (msg == WM_POINTERUPDATE) touchinput.dwFlags |= TOUCHEVENTF_MOVE; - if (IS_POINTER_PRIMARY_WPARAM( wparam )) touchinput.dwFlags |= TOUCHEVENTF_PRIMARY; - touchinput.dwMask = 0; - touchinput.dwTime = NtGetTickCount(); - touchinput.dwExtraInfo = 0; - touchinput.cxContact = 0; - touchinput.cyContact = 0; - - send_message( hwnd, WM_TOUCH, MAKELONG( 1, 0 ), (LPARAM)&touchinput ); - break; - } - - case WM_TOUCH: - /* FIXME: CloseTouchInputHandle( (HTOUCHINPUT)lparam ); */ - return 0; } return result; diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 2ef215e94ab..6a8814e0422 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2169,17 +2169,6 @@ void toggle_caret( HWND hwnd ) if (ret && !hidden) display_caret( hwnd, &r ); } - -/********************************************************************** - * NtUserIsTouchWindow (win32u.@) - */ -BOOL WINAPI NtUserIsTouchWindow( HWND hwnd, ULONG *flags ) -{ - FIXME( "hwnd %p, flags %p stub!\n", hwnd, flags ); - return FALSE; -} - - HWND get_shell_window(void) { HWND hwnd = 0; diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index 1735b0c8133..32812a3d881 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -221,7 +221,6 @@ static void * const syscalls[] = NtUserInvalidateRect, NtUserInvalidateRgn, NtUserIsClipboardFormatAvailable, - NtUserIsTouchWindow, NtUserKillTimer, NtUserLockWindowUpdate, NtUserLogicalToPerMonitorDPIPhysicalPoint, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index f800f7408ae..c3ed3c0559a 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1056,7 +1056,7 @@ @ stub NtUserIsNonClientDpiScalingEnabled @ stub NtUserIsResizeLayoutSynchronizationEnabled @ stub NtUserIsTopLevelWindow -@ stdcall -syscall NtUserIsTouchWindow(long ptr) +@ stub NtUserIsTouchWindow @ stub NtUserIsWindowBroadcastingDpiToChildren @ stub NtUserIsWindowGDIScaledDpiMessageEnabled @ stdcall -syscall NtUserKillTimer(long long) diff --git a/include/ntuser.h b/include/ntuser.h index 15fc6b3bc4e..a0a6edbc0e5 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -791,7 +791,6 @@ INT WINAPI NtUserInternalGetWindowText( HWND hwnd, WCHAR *text, INT count ); BOOL WINAPI NtUserIsClipboardFormatAvailable( UINT format ); BOOL WINAPI NtUserInvalidateRect( HWND hwnd, const RECT *rect, BOOL erase ); BOOL WINAPI NtUserInvalidateRgn( HWND hwnd, HRGN hrgn, BOOL erase ); -BOOL WINAPI NtUserIsTouchWindow( HWND hwnd, ULONG *flags ); BOOL WINAPI NtUserKillTimer( HWND hwnd, UINT_PTR id ); BOOL WINAPI NtUserLockWindowUpdate( HWND hwnd ); BOOL WINAPI NtUserLogicalToPerMonitorDPIPhysicalPoint( HWND hwnd, POINT *pt ); From 440398714ab2a0e86694f09f8b917781ccc302b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 19 Dec 2022 12:19:33 +0100 Subject: [PATCH 1111/2777] include: Declare some NtUser pointer related syscalls. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53847 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51537 (cherry picked from commit 3cf7b6b41ae759ddf7e991e12542dfb94feee889) --- include/ntuser.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/ntuser.h b/include/ntuser.h index a0a6edbc0e5..b383e97e726 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -701,6 +701,7 @@ BOOL WINAPI NtUserDrawIconEx( HDC hdc, INT x0, INT y0, HICON icon, INT width, DWORD WINAPI NtUserDrawMenuBarTemp( HWND hwnd, HDC hdc, RECT *rect, HMENU handle, HFONT font ); BOOL WINAPI NtUserEmptyClipboard(void); BOOL WINAPI NtUserEnableMenuItem( HMENU handle, UINT id, UINT flags ); +BOOL WINAPI NtUserEnableMouseInPointer( BOOL ); BOOL WINAPI NtUserEnableScrollBar( HWND hwnd, UINT bar, UINT flags ); BOOL WINAPI NtUserEndDeferWindowPosEx( HDWP hdwp, BOOL async ); BOOL WINAPI NtUserEndMenu(void); @@ -760,6 +761,8 @@ int WINAPI NtUserGetMouseMovePointsEx( UINT size, MOUSEMOVEPOINT *ptin, MOUS BOOL WINAPI NtUserGetObjectInformation( HANDLE handle, INT index, void *info, DWORD len, DWORD *needed ); HWND WINAPI NtUserGetOpenClipboardWindow(void); +BOOL WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, UINT_PTR, UINT_PTR, SIZE_T size, + UINT32 *entry_count, UINT32 *pointer_count, void *pointer_info ); INT WINAPI NtUserGetPriorityClipboardFormat( UINT *list, INT count ); HWINSTA WINAPI NtUserGetProcessWindowStation(void); HANDLE WINAPI NtUserGetProp( HWND hwnd, const WCHAR *str ); @@ -789,6 +792,7 @@ NTSTATUS WINAPI NtUserInitializeClientPfnArrays( const struct user_client_procs HICON WINAPI NtUserInternalGetWindowIcon( HWND hwnd, UINT type ); INT WINAPI NtUserInternalGetWindowText( HWND hwnd, WCHAR *text, INT count ); BOOL WINAPI NtUserIsClipboardFormatAvailable( UINT format ); +BOOL WINAPI NtUserIsMouseInPointerEnabled(void); BOOL WINAPI NtUserInvalidateRect( HWND hwnd, const RECT *rect, BOOL erase ); BOOL WINAPI NtUserInvalidateRgn( HWND hwnd, HRGN hrgn, BOOL erase ); BOOL WINAPI NtUserKillTimer( HWND hwnd, UINT_PTR id ); From 92fbd035e54906dbd3ac67fc04e42e73dba1f917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 19 Dec 2022 11:39:38 +0100 Subject: [PATCH 1112/2777] win32u: Move NtUserEnableMouseInPointer from user32. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53847 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51537 (cherry picked from commit 738425185f3901d192249f18950c6a7a51cd2ad5) --- dlls/user32/input.c | 11 ----------- dlls/user32/user32.spec | 2 +- dlls/win32u/input.c | 12 ++++++++++++ dlls/win32u/syscall.c | 1 + dlls/win32u/win32u.spec | 2 +- dlls/wow64win/syscall.h | 1 + dlls/wow64win/user.c | 7 +++++++ 7 files changed, 23 insertions(+), 13 deletions(-) diff --git a/dlls/user32/input.c b/dlls/user32/input.c index c5387cf9212..3b0a13842c8 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -495,17 +495,6 @@ BOOL WINAPI UnloadKeyboardLayout( HKL layout ) } -/*********************************************************************** - * EnableMouseInPointer (USER32.@) - */ -BOOL WINAPI EnableMouseInPointer(BOOL enable) -{ - FIXME("(%#x) stub\n", enable); - - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - static DWORD CALLBACK devnotify_window_callback(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header) { SendMessageTimeoutW(handle, WM_DEVICECHANGE, flags, (LPARAM)header, SMTO_ABORTIFHUNG, 2000, NULL); diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 1628c7ca74a..f0e32c633d8 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -205,7 +205,7 @@ @ stdcall EditWndProc(long long long long) EditWndProcA @ stdcall EmptyClipboard() NtUserEmptyClipboard @ stdcall EnableMenuItem(long long long) NtUserEnableMenuItem -@ stdcall EnableMouseInPointer(long) +@ stdcall EnableMouseInPointer(long) NtUserEnableMouseInPointer @ stdcall EnableNonClientDpiScaling(long) @ stdcall -import EnableScrollBar(long long long) NtUserEnableScrollBar @ stdcall EnableWindow(long long) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 6a8814e0422..2ca1ed4119d 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2169,6 +2169,18 @@ void toggle_caret( HWND hwnd ) if (ret && !hidden) display_caret( hwnd, &r ); } + +/********************************************************************** + * NtUserEnableMouseInPointer (win32u.@) + */ +BOOL WINAPI NtUserEnableMouseInPointer( BOOL enable ) +{ + FIXME( "enable %u stub!\n", enable ); + RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + + HWND get_shell_window(void) { HWND hwnd = 0; diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index 32812a3d881..a0fba9f8045 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -145,6 +145,7 @@ static void * const syscalls[] = NtUserDrawIconEx, NtUserEmptyClipboard, NtUserEnableMenuItem, + NtUserEnableMouseInPointer, NtUserEnableScrollBar, NtUserEndDeferWindowPosEx, NtUserEndMenu, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index c3ed3c0559a..6f3b2c31577 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -861,7 +861,7 @@ @ stub NtUserEnableChildWindowDpiMessage @ stub NtUserEnableIAMAccess @ stdcall -syscall NtUserEnableMenuItem(long long long) -@ stub NtUserEnableMouseInPointer +@ stdcall -syscall NtUserEnableMouseInPointer(long) @ stub NtUserEnableMouseInPointerForWindow @ stub NtUserEnableMouseInputForCursorSuppression @ stub NtUserEnableNonClientDpiScaling diff --git a/dlls/wow64win/syscall.h b/dlls/wow64win/syscall.h index ecf79f69cce..5c5de66cd3c 100644 --- a/dlls/wow64win/syscall.h +++ b/dlls/wow64win/syscall.h @@ -131,6 +131,7 @@ SYSCALL_ENTRY( NtUserDrawIconEx ) \ SYSCALL_ENTRY( NtUserEmptyClipboard ) \ SYSCALL_ENTRY( NtUserEnableMenuItem ) \ + SYSCALL_ENTRY( NtUserEnableMouseInPointer ) \ SYSCALL_ENTRY( NtUserEnableScrollBar ) \ SYSCALL_ENTRY( NtUserEndDeferWindowPosEx ) \ SYSCALL_ENTRY( NtUserEndMenu ) \ diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index 4ce8c94c1af..5520a28a018 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -1629,6 +1629,13 @@ NTSTATUS WINAPI wow64_NtUserEnableMenuItem( UINT *args ) return NtUserEnableMenuItem( handle, id, flags ); } +NTSTATUS WINAPI wow64_NtUserEnableMouseInPointer( UINT *args ) +{ + UINT enable = get_ulong( &args ); + + return NtUserEnableMouseInPointer( enable ); +} + NTSTATUS WINAPI wow64_NtUserEnableScrollBar( UINT *args ) { HWND hwnd = get_handle( &args ); From 5bd2d48615068b40c263ef2a6acc7fa39daa045b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 19 Dec 2022 17:22:00 +0100 Subject: [PATCH 1113/2777] win32u: Stub NtUserIsMouseInPointerEnabled syscall. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53847 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51537 (cherry picked from commit 1f2e722877423dfe71694647d2bb3b822235b797) --- dlls/user32/tests/input.c | 10 ++++------ dlls/user32/user32.spec | 1 + dlls/win32u/input.c | 10 ++++++++++ dlls/win32u/syscall.c | 1 + dlls/win32u/win32u.spec | 2 +- dlls/wow64win/syscall.h | 1 + dlls/wow64win/user.c | 5 +++++ 7 files changed, 23 insertions(+), 7 deletions(-) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 95abdbb601b..f8b40099091 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -4844,17 +4844,15 @@ static void test_EnableMouseInPointer_process( const char *arg ) ok( !ret, "EnableMouseInPointer succeeded\n" ); todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "got error %lu\n", GetLastError() ); - if (!pIsMouseInPointerEnabled) ret = !enable; - else ret = pIsMouseInPointerEnabled(); - todo_wine_if(!pIsMouseInPointerEnabled) + ret = pIsMouseInPointerEnabled(); + todo_wine_if(enable) ok( ret == enable, "IsMouseInPointerEnabled returned %u, error %lu\n", ret, GetLastError() ); ret = pEnableMouseInPointer( enable ); todo_wine ok( ret, "EnableMouseInPointer failed, error %lu\n", GetLastError() ); - if (!pIsMouseInPointerEnabled) ret = !enable; - else ret = pIsMouseInPointerEnabled(); - todo_wine_if(!pIsMouseInPointerEnabled) + ret = pIsMouseInPointerEnabled(); + todo_wine_if(enable) ok( ret == enable, "IsMouseInPointerEnabled returned %u, error %lu\n", ret, GetLastError() ); test_GetPointerInfo( enable ); diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index f0e32c633d8..38462607ccd 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -475,6 +475,7 @@ # @ stub IsHungThread @ stdcall IsIconic(long) @ stdcall IsMenu(long) +@ stdcall IsMouseInPointerEnabled() NtUserIsMouseInPointerEnabled @ stdcall IsProcessDPIAware() @ stdcall IsRectEmpty(ptr) # @ stub IsServerSideWindow diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 2ca1ed4119d..6e36d514c6a 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2180,6 +2180,16 @@ BOOL WINAPI NtUserEnableMouseInPointer( BOOL enable ) return FALSE; } +/********************************************************************** + * NtUserIsMouseInPointerEnabled (win32u.@) + */ +BOOL WINAPI NtUserIsMouseInPointerEnabled(void) +{ + FIXME( "stub!\n" ); + RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + HWND get_shell_window(void) { diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index a0fba9f8045..3e3c5aba58c 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -222,6 +222,7 @@ static void * const syscalls[] = NtUserInvalidateRect, NtUserInvalidateRgn, NtUserIsClipboardFormatAvailable, + NtUserIsMouseInPointerEnabled, NtUserKillTimer, NtUserLockWindowUpdate, NtUserLogicalToPerMonitorDPIPhysicalPoint, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 6f3b2c31577..0c4d4a3971d 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1051,7 +1051,7 @@ @ stdcall -syscall NtUserInvalidateRgn(long long long) @ stub NtUserIsChildWindowDpiMessageEnabled @ stdcall -syscall NtUserIsClipboardFormatAvailable(long) -@ stub NtUserIsMouseInPointerEnabled +@ stdcall -syscall NtUserIsMouseInPointerEnabled() @ stub NtUserIsMouseInputEnabled @ stub NtUserIsNonClientDpiScalingEnabled @ stub NtUserIsResizeLayoutSynchronizationEnabled diff --git a/dlls/wow64win/syscall.h b/dlls/wow64win/syscall.h index 5c5de66cd3c..ca491f2a6b1 100644 --- a/dlls/wow64win/syscall.h +++ b/dlls/wow64win/syscall.h @@ -208,6 +208,7 @@ SYSCALL_ENTRY( NtUserInvalidateRect ) \ SYSCALL_ENTRY( NtUserInvalidateRgn ) \ SYSCALL_ENTRY( NtUserIsClipboardFormatAvailable ) \ + SYSCALL_ENTRY( NtUserIsMouseInPointerEnabled ) \ SYSCALL_ENTRY( NtUserKillTimer ) \ SYSCALL_ENTRY( NtUserLockWindowUpdate ) \ SYSCALL_ENTRY( NtUserLogicalToPerMonitorDPIPhysicalPoint ) \ diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index 5520a28a018..7afd0ca0ffe 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -2731,6 +2731,11 @@ NTSTATUS WINAPI wow64_NtUserIsClipboardFormatAvailable( UINT *args ) return NtUserIsClipboardFormatAvailable( format ); } +NTSTATUS WINAPI wow64_NtUserIsMouseInPointerEnabled( UINT *args ) +{ + return NtUserIsMouseInPointerEnabled(); +} + NTSTATUS WINAPI wow64_NtUserKillTimer( UINT *args ) { HWND hwnd = get_handle( &args ); From fedded4d1643dd52a1ef93ed5fbf6ae00b0348cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Jan 2023 12:38:35 +0100 Subject: [PATCH 1114/2777] win32u: Stub NtUserGetPointerInfoList syscall. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53847 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51537 (cherry picked from commit 45e6dfc19249ceb506c4610d8abd206a11943bc7) --- dlls/win32u/input.c | 11 +++++++++++ dlls/win32u/syscall.c | 1 + dlls/win32u/win32u.spec | 2 +- dlls/wow64win/syscall.h | 1 + dlls/wow64win/user.c | 14 ++++++++++++++ 5 files changed, 28 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 6e36d514c6a..34b1fa4393a 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2190,6 +2190,17 @@ BOOL WINAPI NtUserIsMouseInPointerEnabled(void) return FALSE; } +/********************************************************************** + * NtUserGetPointerInfoList (win32u.@) + */ +BOOL WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, UINT_PTR unk0, UINT_PTR unk1, SIZE_T size, + UINT32 *entry_count, UINT32 *pointer_count, void *pointer_info ) +{ + FIXME( "id %#x, type %#x, unk0 %#zx, unk1 %#zx, size %#zx, entry_count %p, pointer_count %p, pointer_info %p stub!\n", + id, (int)type, unk0, unk1, (size_t)size, entry_count, pointer_count, pointer_info ); + RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} HWND get_shell_window(void) { diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index 3e3c5aba58c..9020aa01126 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -193,6 +193,7 @@ static void * const syscalls[] = NtUserGetMouseMovePointsEx, NtUserGetObjectInformation, NtUserGetOpenClipboardWindow, + NtUserGetPointerInfoList, NtUserGetPriorityClipboardFormat, NtUserGetProcessDpiAwarenessContext, NtUserGetProcessWindowStation, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 0c4d4a3971d..6e1a0a51175 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -971,7 +971,7 @@ @ stub NtUserGetPointerDeviceRects @ stub NtUserGetPointerDevices @ stub NtUserGetPointerFrameTimes -@ stub NtUserGetPointerInfoList +@ stdcall -syscall NtUserGetPointerInfoList(long long long long long ptr ptr ptr) @ stub NtUserGetPointerInputTransform @ stub NtUserGetPointerProprietaryId @ stub NtUserGetPointerType diff --git a/dlls/wow64win/syscall.h b/dlls/wow64win/syscall.h index ca491f2a6b1..4977013c595 100644 --- a/dlls/wow64win/syscall.h +++ b/dlls/wow64win/syscall.h @@ -179,6 +179,7 @@ SYSCALL_ENTRY( NtUserGetMouseMovePointsEx ) \ SYSCALL_ENTRY( NtUserGetObjectInformation ) \ SYSCALL_ENTRY( NtUserGetOpenClipboardWindow ) \ + SYSCALL_ENTRY( NtUserGetPointerInfoList ) \ SYSCALL_ENTRY( NtUserGetPriorityClipboardFormat ) \ SYSCALL_ENTRY( NtUserGetProcessDpiAwarenessContext ) \ SYSCALL_ENTRY( NtUserGetProcessWindowStation ) \ diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index 7afd0ca0ffe..2ce82907a88 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -2246,6 +2246,20 @@ NTSTATUS WINAPI wow64_NtUserGetOpenClipboardWindow( UINT *args ) return HandleToUlong( NtUserGetOpenClipboardWindow() ); } +NTSTATUS WINAPI wow64_NtUserGetPointerInfoList( UINT *args ) +{ + UINT id = get_ulong( &args ); + UINT type = get_ulong( &args ); + UINT unk0 = get_ulong( &args ); + UINT unk1 = get_ulong( &args ); + UINT size = get_ulong( &args ); + void *entry_count = get_ptr( &args ); + void *pointer_count = get_ptr( &args ); + void *pointer_info = get_ptr( &args ); + + return NtUserGetPointerInfoList( id, type, unk0, unk1, size, entry_count, pointer_count, pointer_info ); +} + NTSTATUS WINAPI wow64_NtUserGetPriorityClipboardFormat( UINT *args ) { UINT *list = get_ptr( &args ); From 736b57592e4b386d9a5f2f8395e400cff508e5dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 19 Dec 2022 11:39:38 +0100 Subject: [PATCH 1115/2777] win32u/tests: Test NtUserEnableMouseInPointer syscall. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53847 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51537 (cherry picked from commit 9443bde57d6a75f4f3fde05cf9252e7fdd9a136f) --- dlls/win32u/tests/win32u.c | 49 +++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/tests/win32u.c b/dlls/win32u/tests/win32u.c index 87419f6fadb..0187d52ea9d 100644 --- a/dlls/win32u/tests/win32u.c +++ b/dlls/win32u/tests/win32u.c @@ -24,7 +24,6 @@ #include "winbase.h" #include "ntuser.h" - static void test_NtUserEnumDisplayDevices(void) { NTSTATUS ret; @@ -822,6 +821,43 @@ static void test_inter_process_child( HWND hwnd ) PostMessageA( hwnd, WM_USER, 0, 0 ); } +static void test_NtUserEnableMouseInPointer_process( const char *arg ) +{ + DWORD enable = strtoul( arg, 0, 10 ); + BOOL ret; + + ret = NtUserEnableMouseInPointer( enable ); + todo_wine + ok( ret, "NtUserEnableMouseInPointer failed, error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = NtUserEnableMouseInPointer( !enable ); + ok( !ret, "NtUserEnableMouseInPointer succeeded\n" ); + todo_wine + ok( GetLastError() == ERROR_ACCESS_DENIED, "got error %lu\n", GetLastError() ); + + ret = NtUserEnableMouseInPointer( enable ); + todo_wine + ok( ret, "NtUserEnableMouseInPointer failed, error %lu\n", GetLastError() ); +} + +static void test_NtUserEnableMouseInPointer( char **argv, BOOL enable ) +{ + STARTUPINFOA startup = {.cb = sizeof(STARTUPINFOA)}; + PROCESS_INFORMATION info = {0}; + char cmdline[MAX_PATH * 2]; + BOOL ret; + + sprintf( cmdline, "%s %s NtUserEnableMouseInPointer %u", argv[0], argv[1], enable ); + ret = CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ); + ok( ret, "CreateProcessA failed, error %lu\n", GetLastError() ); + if (!ret) return; + + wait_child_process( info.hProcess ); + CloseHandle( info.hThread ); + CloseHandle( info.hProcess ); +} + START_TEST(win32u) { char **argv; @@ -837,6 +873,14 @@ START_TEST(win32u) return; } + if (argc > 3 && !strcmp( argv[2], "NtUserEnableMouseInPointer" )) + { + winetest_push_context( "enable %s", argv[3] ); + test_NtUserEnableMouseInPointer_process( argv[3] ); + winetest_pop_context(); + return; + } + test_NtUserEnumDisplayDevices(); test_window_props(); test_class(); @@ -851,4 +895,7 @@ START_TEST(win32u) test_NtUserCloseWindowStation(); test_NtUserDisplayConfigGetDeviceInfo(); + + test_NtUserEnableMouseInPointer( argv, FALSE ); + test_NtUserEnableMouseInPointer( argv, TRUE ); } From 23cd5a2ef895bd90b06ad8acea23bde74a5675e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 28 Jan 2023 10:35:31 +0100 Subject: [PATCH 1116/2777] win32u/tests: Test NtUserIsMouseInPointerEnabled syscall. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53847 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51537 (cherry picked from commit 87839a41ca17b2c62cbc7ab038e7a03284155feb) --- dlls/win32u/tests/win32u.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dlls/win32u/tests/win32u.c b/dlls/win32u/tests/win32u.c index 0187d52ea9d..f7778e9ef41 100644 --- a/dlls/win32u/tests/win32u.c +++ b/dlls/win32u/tests/win32u.c @@ -826,19 +826,31 @@ static void test_NtUserEnableMouseInPointer_process( const char *arg ) DWORD enable = strtoul( arg, 0, 10 ); BOOL ret; + ret = NtUserIsMouseInPointerEnabled(); + ok( !ret, "NtUserIsMouseInPointerEnabled returned %u, error %lu\n", ret, GetLastError() ); + ret = NtUserEnableMouseInPointer( enable ); todo_wine ok( ret, "NtUserEnableMouseInPointer failed, error %lu\n", GetLastError() ); + ret = NtUserIsMouseInPointerEnabled(); + todo_wine_if(enable) + ok( ret == enable, "NtUserIsMouseInPointerEnabled returned %u, error %lu\n", ret, GetLastError() ); SetLastError( 0xdeadbeef ); ret = NtUserEnableMouseInPointer( !enable ); ok( !ret, "NtUserEnableMouseInPointer succeeded\n" ); todo_wine ok( GetLastError() == ERROR_ACCESS_DENIED, "got error %lu\n", GetLastError() ); + ret = NtUserIsMouseInPointerEnabled(); + todo_wine_if(enable) + ok( ret == enable, "NtUserIsMouseInPointerEnabled returned %u, error %lu\n", ret, GetLastError() ); ret = NtUserEnableMouseInPointer( enable ); todo_wine ok( ret, "NtUserEnableMouseInPointer failed, error %lu\n", GetLastError() ); + ret = NtUserIsMouseInPointerEnabled(); + todo_wine_if(enable) + ok( ret == enable, "NtUserIsMouseInPointerEnabled returned %u, error %lu\n", ret, GetLastError() ); } static void test_NtUserEnableMouseInPointer( char **argv, BOOL enable ) From df08a558577b2d2a3c9387d43d3efe35e7e84616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 28 Jan 2023 10:35:54 +0100 Subject: [PATCH 1117/2777] win32u/tests: Test NtUserGetPointerInfoList syscall signature. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53847 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51537 (cherry picked from commit d970584b6240e73e2568471939235ae79850b540) --- dlls/win32u/tests/win32u.c | 252 +++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) diff --git a/dlls/win32u/tests/win32u.c b/dlls/win32u/tests/win32u.c index f7778e9ef41..60ef2d38b5f 100644 --- a/dlls/win32u/tests/win32u.c +++ b/dlls/win32u/tests/win32u.c @@ -24,6 +24,29 @@ #include "winbase.h" #include "ntuser.h" +#define check_member_( file, line, val, exp, fmt, member ) \ + ok_(file, line)( (val).member == (exp).member, "got " #member " " fmt "\n", (val).member ) +#define check_member( val, exp, fmt, member ) \ + check_member_( __FILE__, __LINE__, val, exp, fmt, member ) + +static void flush_events(void) +{ + int min_timeout = 100, diff = 200; + DWORD time = GetTickCount() + diff; + MSG msg; + + while (diff > 0) + { + if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break; + while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageA( &msg ); + } + diff = time - GetTickCount(); + } +} + static void test_NtUserEnumDisplayDevices(void) { NTSTATUS ret; @@ -821,6 +844,233 @@ static void test_inter_process_child( HWND hwnd ) PostMessageA( hwnd, WM_USER, 0, 0 ); } +static DWORD CALLBACK test_NtUserGetPointerInfoList_thread( void *arg ) +{ + POINTER_INFO pointer_info[4] = {0}; + UINT32 entry_count, pointer_count; + HWND hwnd; + BOOL ret; + + hwnd = CreateWindowW( L"test", L"test name", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, NULL, 0 ); + flush_events(); + + memset( &pointer_info, 0xcd, sizeof(pointer_info) ); + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_POINTER, 0, 0, sizeof(POINTER_INFO), &entry_count, &pointer_count, pointer_info ); + ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + ok( pointer_count == 2, "got pointer_count %u\n", pointer_count ); + ok( entry_count == 2, "got entry_count %u\n", entry_count ); + + DestroyWindow( hwnd ); + + return 0; +} + +#define check_pointer_info( a, b ) check_pointer_info_( __LINE__, a, b ) +static void check_pointer_info_( int line, const POINTER_INFO *actual, const POINTER_INFO *expected ) +{ + check_member( *actual, *expected, "%#lx", pointerType ); + check_member( *actual, *expected, "%#x", pointerId ); + check_member( *actual, *expected, "%#x", frameId ); + check_member( *actual, *expected, "%#x", pointerFlags ); + check_member( *actual, *expected, "%p", sourceDevice ); + check_member( *actual, *expected, "%p", hwndTarget ); + check_member( *actual, *expected, "%+ld", ptPixelLocation.x ); + check_member( *actual, *expected, "%+ld", ptPixelLocation.y ); + check_member( *actual, *expected, "%+ld", ptHimetricLocation.x ); + check_member( *actual, *expected, "%+ld", ptHimetricLocation.y ); + check_member( *actual, *expected, "%+ld", ptPixelLocationRaw.x ); + check_member( *actual, *expected, "%+ld", ptPixelLocationRaw.y ); + check_member( *actual, *expected, "%+ld", ptHimetricLocationRaw.x ); + check_member( *actual, *expected, "%+ld", ptHimetricLocationRaw.y ); + check_member( *actual, *expected, "%lu", dwTime ); + check_member( *actual, *expected, "%u", historyCount ); + check_member( *actual, *expected, "%#x", InputData ); + check_member( *actual, *expected, "%#lx", dwKeyStates ); + check_member( *actual, *expected, "%I64u", PerformanceCount ); + check_member( *actual, *expected, "%#x", ButtonChangeType ); +} + +static void test_NtUserGetPointerInfoList( BOOL mouse_in_pointer_enabled ) +{ + void *invalid_ptr = (void *)0xdeadbeef; + POINTER_TOUCH_INFO touch_info[4] = {0}; + POINTER_PEN_INFO pen_info[4] = {0}; + POINTER_INFO pointer_info[4] = {0}; + UINT32 entry_count, pointer_count; + WNDCLASSW cls = + { + .lpfnWndProc = DefWindowProcW, + .hInstance = GetModuleHandleW( NULL ), + .hbrBackground = GetStockObject( WHITE_BRUSH ), + .lpszClassName = L"test", + }; + HANDLE thread; + SIZE_T size; + ATOM class; + DWORD res; + HWND hwnd; + BOOL ret; + + class = RegisterClassW( &cls ); + ok( class, "RegisterClassW failed: %lu\n", GetLastError() ); + + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_POINTER, 0, 0, sizeof(POINTER_INFO), invalid_ptr, &pointer_count, pointer_info ); + ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); + todo_wine + ok( GetLastError() == ERROR_NOACCESS, "got error %lu\n", GetLastError() ); + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_POINTER, 0, 0, sizeof(POINTER_INFO), &entry_count, invalid_ptr, pointer_info ); + ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); + todo_wine + ok( GetLastError() == ERROR_NOACCESS, "got error %lu\n", GetLastError() ); + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_POINTER, 0, 0, sizeof(POINTER_INFO), &entry_count, &pointer_count, invalid_ptr ); + ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); + todo_wine + ok( GetLastError() == ERROR_NOACCESS || broken(GetLastError() == ERROR_INVALID_PARAMETER) /* w10 32bit */, "got error %lu\n", GetLastError() ); + + memset( pointer_info, 0xcd, sizeof(pointer_info) ); + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_POINTER, 0, 0, sizeof(POINTER_INFO), &entry_count, &pointer_count, pointer_info ); + ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); + todo_wine + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + ok( pointer_count == 2, "got pointer_count %u\n", pointer_count ); + ok( entry_count == 2, "got entry_count %u\n", entry_count ); + + SetCursorPos( 500, 500 ); /* avoid generating mouse message on window creation */ + + hwnd = CreateWindowW( L"test", L"test name", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 200, 200, 0, 0, NULL, 0 ); + flush_events(); + + memset( pointer_info, 0xcd, sizeof(pointer_info) ); + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_POINTER, 0, 0, sizeof(POINTER_INFO), &entry_count, &pointer_count, pointer_info ); + ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); + todo_wine + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + ok( pointer_count == 2, "got pointer_count %u\n", pointer_count ); + ok( entry_count == 2, "got entry_count %u\n", entry_count ); + + SetCursorPos( 200, 200 ); + flush_events(); + mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); + flush_events(); + mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); + flush_events(); + mouse_event( MOUSEEVENTF_MOVE, 10, 10, 0, 0 ); + flush_events(); + + memset( pointer_info, 0xcd, sizeof(pointer_info) ); + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_POINTER, 0, 0, sizeof(POINTER_INFO), &entry_count, &pointer_count, pointer_info ); + todo_wine_if(mouse_in_pointer_enabled) + ok( ret == mouse_in_pointer_enabled, "NtUserGetPointerInfoList failed, error %lu\n", GetLastError() ); + if (!ret) + { + todo_wine + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + goto done; + } + + ok( pointer_count == 1, "got pointer_count %u\n", pointer_count ); + ok( entry_count == 1, "got entry_count %u\n", entry_count ); + ok( pointer_info[0].pointerType == PT_MOUSE, "got pointerType %lu\n", pointer_info[0].pointerType ); + ok( pointer_info[0].pointerId == 1, "got pointerId %u\n", pointer_info[0].pointerId ); + ok( !!pointer_info[0].frameId, "got frameId %u\n", pointer_info[0].frameId ); + ok( pointer_info[0].pointerFlags == (0x20000 | POINTER_MESSAGE_FLAG_INRANGE | POINTER_MESSAGE_FLAG_PRIMARY), + "got pointerFlags %#x\n", pointer_info[0].pointerFlags ); + ok( pointer_info[0].sourceDevice == INVALID_HANDLE_VALUE || broken(!!pointer_info[0].sourceDevice) /* w1064v1809 32bit */, + "got sourceDevice %p\n", pointer_info[0].sourceDevice ); + ok( pointer_info[0].hwndTarget == hwnd, "got hwndTarget %p\n", pointer_info[0].hwndTarget ); + ok( !!pointer_info[0].ptPixelLocation.x, "got ptPixelLocation %s\n", wine_dbgstr_point( &pointer_info[0].ptPixelLocation ) ); + ok( !!pointer_info[0].ptPixelLocation.y, "got ptPixelLocation %s\n", wine_dbgstr_point( &pointer_info[0].ptPixelLocation ) ); + ok( !!pointer_info[0].ptHimetricLocation.x, "got ptHimetricLocation %s\n", wine_dbgstr_point( &pointer_info[0].ptHimetricLocation ) ); + ok( !!pointer_info[0].ptHimetricLocation.y, "got ptHimetricLocation %s\n", wine_dbgstr_point( &pointer_info[0].ptHimetricLocation ) ); + ok( !!pointer_info[0].ptPixelLocationRaw.x, "got ptPixelLocationRaw %s\n", wine_dbgstr_point( &pointer_info[0].ptPixelLocationRaw ) ); + ok( !!pointer_info[0].ptPixelLocationRaw.y, "got ptPixelLocationRaw %s\n", wine_dbgstr_point( &pointer_info[0].ptPixelLocationRaw ) ); + ok( !!pointer_info[0].ptHimetricLocationRaw.x, "got ptHimetricLocationRaw %s\n", wine_dbgstr_point( &pointer_info[0].ptHimetricLocationRaw ) ); + ok( !!pointer_info[0].ptHimetricLocationRaw.y, "got ptHimetricLocationRaw %s\n", wine_dbgstr_point( &pointer_info[0].ptHimetricLocationRaw ) ); + ok( !!pointer_info[0].dwTime, "got dwTime %lu\n", pointer_info[0].dwTime ); + ok( pointer_info[0].historyCount == 1, "got historyCount %u\n", pointer_info[0].historyCount ); + ok( pointer_info[0].InputData == 0, "got InputData %u\n", pointer_info[0].InputData ); + ok( pointer_info[0].dwKeyStates == 0, "got dwKeyStates %lu\n", pointer_info[0].dwKeyStates ); + ok( !!pointer_info[0].PerformanceCount, "got PerformanceCount %I64u\n", pointer_info[0].PerformanceCount ); + ok( pointer_info[0].ButtonChangeType == 0, "got ButtonChangeType %u\n", pointer_info[0].ButtonChangeType ); + + thread = CreateThread( NULL, 0, test_NtUserGetPointerInfoList_thread, NULL, 0, NULL ); + res = WaitForSingleObject( thread, 5000 ); + ok( !res, "WaitForSingleObject returned %#lx, error %lu\n", res, GetLastError() ); + + memset( pen_info, 0xa5, sizeof(pen_info) ); + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_PEN, 0, 0, sizeof(POINTER_PEN_INFO), &entry_count, &pointer_count, pen_info ); + ok( ret, "NtUserGetPointerInfoList failed, error %lu\n", GetLastError() ); + ok( pointer_count == 1, "got pointer_count %u\n", pointer_count ); + ok( entry_count == 1, "got entry_count %u\n", entry_count ); + check_pointer_info( &pen_info[0].pointerInfo, &pointer_info[0] ); + memset( touch_info, 0xa5, sizeof(touch_info) ); + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_TOUCH, 0, 0, sizeof(POINTER_TOUCH_INFO), &entry_count, &pointer_count, touch_info ); + ok( ret, "NtUserGetPointerInfoList failed, error %lu\n", GetLastError() ); + ok( pointer_count == 1, "got pointer_count %u\n", pointer_count ); + ok( entry_count == 1, "got entry_count %u\n", entry_count ); + check_pointer_info( &touch_info[0].pointerInfo, &pointer_info[0] ); + + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_POINTER, 0, 0, sizeof(POINTER_INFO) - 1, &entry_count, &pointer_count, pointer_info ); + ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_PEN, 0, 0, sizeof(POINTER_PEN_INFO) - 1, &entry_count, &pointer_count, pointer_info ); + ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_TOUCH, 0, 0, sizeof(POINTER_TOUCH_INFO) - 1, &entry_count, &pointer_count, pointer_info ); + ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_TOUCHPAD, 0, 0, sizeof(POINTER_TOUCH_INFO) - 1, &entry_count, &pointer_count, pointer_info ); + ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_POINTER, 0, 0, sizeof(POINTER_INFO) + 1, &entry_count, &pointer_count, pointer_info ); + ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_PEN, 0, 0, sizeof(POINTER_PEN_INFO) + 1, &entry_count, &pointer_count, pointer_info ); + ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_TOUCH, 0, 0, sizeof(POINTER_TOUCH_INFO) + 1, &entry_count, &pointer_count, pointer_info ); + ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_TOUCHPAD, 0, 0, sizeof(POINTER_TOUCH_INFO) + 1, &entry_count, &pointer_count, pointer_info ); + ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + + for (size = 0; size < 0xfff; ++size) + { + char buffer[0x1000]; + entry_count = pointer_count = 2; + ret = NtUserGetPointerInfoList( 1, PT_MOUSE, 0, 0, size, &entry_count, &pointer_count, buffer ); + ok( !ret, "NtUserGetPointerInfoList succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + } + +done: + DestroyWindow( hwnd ); + + ret = UnregisterClassW( L"test", GetModuleHandleW(NULL) ); + ok( ret, "UnregisterClassW failed: %lu\n", GetLastError() ); +} + static void test_NtUserEnableMouseInPointer_process( const char *arg ) { DWORD enable = strtoul( arg, 0, 10 ); @@ -851,6 +1101,8 @@ static void test_NtUserEnableMouseInPointer_process( const char *arg ) ret = NtUserIsMouseInPointerEnabled(); todo_wine_if(enable) ok( ret == enable, "NtUserIsMouseInPointerEnabled returned %u, error %lu\n", ret, GetLastError() ); + + test_NtUserGetPointerInfoList( enable ); } static void test_NtUserEnableMouseInPointer( char **argv, BOOL enable ) From 9297e703def6acb884ffe37f12deec0f518a4026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 30 Nov 2022 20:16:09 +0100 Subject: [PATCH 1118/2777] include: Add new kbd.h header with KBDTABLES definition. (cherry picked from commit f0ac3b218d3e2239955443cf065ea9de47c1ed30) --- include/Makefile.in | 1 + include/kbd.h | 116 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 include/kbd.h diff --git a/include/Makefile.in b/include/Makefile.in index f37e0098ed1..ff21e9b4d70 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -379,6 +379,7 @@ SOURCES = \ iptypes.h \ isguids.h \ ivectorchangedeventargs.idl \ + kbd.h \ knownfolders.h \ ks.h \ ksguid.h \ diff --git a/include/kbd.h b/include/kbd.h new file mode 100644 index 00000000000..3cf0b35ac8e --- /dev/null +++ b/include/kbd.h @@ -0,0 +1,116 @@ +/* + * Copyright 2022 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 + */ + +#ifndef __WINE_KBD_H +#define __WINE_KBD_H + +#include "windef.h" + +typedef struct +{ + BYTE Vk; + BYTE ModBits; +} VK_TO_BIT, *PVK_TO_BIT; + +typedef struct +{ + VK_TO_BIT *pVkToBit; + WORD wMaxModBits; + BYTE ModNumber[]; +} MODIFIERS, *PMODIFIERS; + +#define TYPEDEF_VK_TO_WCHARS(n) \ + typedef struct _VK_TO_WCHARS##n \ + { \ + BYTE VirtualKey; \ + BYTE Attributes; \ + WCHAR wch[n]; \ + } VK_TO_WCHARS##n, *PVK_TO_WCHARS##n + +TYPEDEF_VK_TO_WCHARS(1); +TYPEDEF_VK_TO_WCHARS(2); +TYPEDEF_VK_TO_WCHARS(3); +TYPEDEF_VK_TO_WCHARS(4); +TYPEDEF_VK_TO_WCHARS(5); +TYPEDEF_VK_TO_WCHARS(6); +TYPEDEF_VK_TO_WCHARS(7); +TYPEDEF_VK_TO_WCHARS(8); +TYPEDEF_VK_TO_WCHARS(9); +TYPEDEF_VK_TO_WCHARS(10); + +typedef struct _VK_TO_WCHAR_TABLE +{ + VK_TO_WCHARS1 *pVkToWchars; + BYTE nModifications; + BYTE cbSize; +} VK_TO_WCHAR_TABLE, *PVK_TO_WCHAR_TABLE; + +typedef struct +{ + DWORD dwBoth; + WCHAR wchComposed; + USHORT uFlags; +} DEADKEY, *PDEADKEY; + +typedef struct +{ + BYTE vsc; + WCHAR *pwsz; +} VSC_LPWSTR, *PVSC_LPWSTR; + +typedef struct _VSC_VK +{ + BYTE Vsc; + USHORT Vk; +} VSC_VK, *PVSC_VK; + +#define TYPEDEF_LIGATURE(n) \ + typedef struct _LIGATURE##n \ + { \ + BYTE VirtualKey; \ + WORD ModificationNumber; \ + WCHAR wch[n]; \ + } LIGATURE##n, *PLIGATURE##n; + +TYPEDEF_LIGATURE(1) +TYPEDEF_LIGATURE(2) +TYPEDEF_LIGATURE(3) +TYPEDEF_LIGATURE(4) +TYPEDEF_LIGATURE(5) + +typedef struct tagKbdLayer +{ + MODIFIERS *pCharModifiers; + VK_TO_WCHAR_TABLE *pVkToWcharTable; + DEADKEY *pDeadKey; + VSC_LPWSTR *pKeyNames; + VSC_LPWSTR *pKeyNamesExt; + WCHAR **pKeyNamesDead; + USHORT *pusVSCtoVK; + BYTE bMaxVSCtoVK; + VSC_VK *pVSCtoVK_E0; + VSC_VK *pVSCtoVK_E1; + DWORD fLocaleFlags; + BYTE nLgMax; + BYTE cbLgEntry; + LIGATURE1 *pLigature; + DWORD dwType; + DWORD dwSubType; +} KBDTABLES, *PKBDTABLES; + +#endif /* __WINE_KBD_H */ From fa097afe7bc8ec1830740988d22c47cb2d4281c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 7 Jan 2023 17:25:20 +0100 Subject: [PATCH 1119/2777] win32u: Use KBDTABLES for default NtUserGetKeyNameText. (cherry picked from commit 1cd690a33678a9348b5df0c26d02973d77cd5e16) --- dlls/win32u/input.c | 236 +++++++++++++++++++++++++++++++++----------- 1 file changed, 181 insertions(+), 55 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 34b1fa4393a..e3db35bb4e8 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -36,6 +36,7 @@ #include "ntuser_private.h" #include "wine/server.h" #include "wine/debug.h" +#include "kbd.h" WINE_DEFAULT_DEBUG_CHANNEL(win); WINE_DECLARE_DEBUG_CHANNEL(keyboard); @@ -49,6 +50,168 @@ static const WCHAR keyboard_layouts_keyW[] = '\\','C','o','n','t','r','o','l', '\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s' }; +static const WCHAR escW[] = {'E','s','c',0}; +static const WCHAR backspaceW[] = {'B','a','c','k','s','p','a','c','e',0}; +static const WCHAR tabW[] = {'T','a','b',0}; +static const WCHAR enterW[] = {'E','n','t','e','r',0}; +static const WCHAR ctrlW[] = {'C','t','r','l',0}; +static const WCHAR shiftW[] = {'S','h','i','f','t',0}; +static const WCHAR right_shiftW[] = {'R','i','g','h','t',' ','S','h','i','f','t',0}; +static const WCHAR num_mulW[] = {'N','u','m',' ','*',0}; +static const WCHAR altW[] = {'A','l','t',0}; +static const WCHAR spaceW[] = {'S','p','a','c','e',0}; +static const WCHAR caps_lockW[] = {'C','a','p','s',' ','L','o','c','k',0}; +static const WCHAR f1W[] = {'F','1',0}; +static const WCHAR f2W[] = {'F','2',0}; +static const WCHAR f3W[] = {'F','3',0}; +static const WCHAR f4W[] = {'F','4',0}; +static const WCHAR f5W[] = {'F','5',0}; +static const WCHAR f6W[] = {'F','6',0}; +static const WCHAR f7W[] = {'F','7',0}; +static const WCHAR f8W[] = {'F','8',0}; +static const WCHAR f9W[] = {'F','9',0}; +static const WCHAR f10W[] = {'F','1','0',0}; +static const WCHAR pauseW[] = {'P','a','u','s','e',0}; +static const WCHAR scroll_lockW[] = {'S','c','r','o','l','l',' ','L','o','c','k',0}; +static const WCHAR num_7W[] = {'N','u','m',' ','7',0}; +static const WCHAR num_8W[] = {'N','u','m',' ','8',0}; +static const WCHAR num_9W[] = {'N','u','m',' ','9',0}; +static const WCHAR num_minusW[] = {'N','u','m',' ','-',0}; +static const WCHAR num_4W[] = {'N','u','m',' ','4',0}; +static const WCHAR num_5W[] = {'N','u','m',' ','5',0}; +static const WCHAR num_6W[] = {'N','u','m',' ','6',0}; +static const WCHAR num_plusW[] = {'N','u','m',' ','+',0}; +static const WCHAR num_1W[] = {'N','u','m',' ','1',0}; +static const WCHAR num_2W[] = {'N','u','m',' ','2',0}; +static const WCHAR num_3W[] = {'N','u','m',' ','3',0}; +static const WCHAR num_0W[] = {'N','u','m',' ','0',0}; +static const WCHAR num_delW[] = {'N','u','m',' ','D','e','l',0}; +static const WCHAR sys_reqW[] = {'S','y','s',' ','R','e','q',0}; +static const WCHAR f11W[] = {'F','1','1',0}; +static const WCHAR f12W[] = {'F','1','2',0}; +static const WCHAR f13W[] = {'F','1','3',0}; +static const WCHAR f14W[] = {'F','1','4',0}; +static const WCHAR f15W[] = {'F','1','5',0}; +static const WCHAR f16W[] = {'F','1','6',0}; +static const WCHAR f17W[] = {'F','1','7',0}; +static const WCHAR f18W[] = {'F','1','8',0}; +static const WCHAR f19W[] = {'F','1','9',0}; +static const WCHAR f20W[] = {'F','2','0',0}; +static const WCHAR f21W[] = {'F','2','1',0}; +static const WCHAR f22W[] = {'F','2','2',0}; +static const WCHAR f23W[] = {'F','2','3',0}; +static const WCHAR f24W[] = {'F','2','4',0}; +static const WCHAR num_enterW[] = {'N','u','m',' ','E','n','t','e','r',0}; +static const WCHAR right_ctrlW[] = {'R','i','g','h','t',' ','C','t','r','l',0}; +static const WCHAR num_divW[] = {'N','u','m',' ','/',0}; +static const WCHAR prnt_scrnW[] = {'P','r','n','t',' ','S','c','r','n',0}; +static const WCHAR right_altW[] = {'R','i','g','h','t',' ','A','l','t',0}; +static const WCHAR num_lockW[] = {'N','u','m',' ','L','o','c','k',0}; +static const WCHAR breakW[] = {'B','r','e','a','k',0}; +static const WCHAR homeW[] = {'H','o','m','e',0}; +static const WCHAR upW[] = {'U','p',0}; +static const WCHAR page_upW[] = {'P','a','g','e',' ','U','p',0}; +static const WCHAR leftW[] = {'L','e','f','t',0}; +static const WCHAR rightW[] = {'R','i','g','h','t',0}; +static const WCHAR endW[] = {'E','n','d',0}; +static const WCHAR downW[] = {'D','o','w','n',0}; +static const WCHAR page_downW[] = {'P','a','g','e',' ','D','o','w','n',0}; +static const WCHAR insertW[] = {'I','n','s','e','r','t',0}; +static const WCHAR deleteW[] = {'D','e','l','e','t','e',0}; +static const WCHAR zerozeroW[] = {'<','0','0','>',0}; +static const WCHAR helpW[] = {'H','e','l','p',0}; +static const WCHAR left_windowsW[] = {'L','e','f','t',' ','W','i','n','d','o','w','s',0}; +static const WCHAR right_windowsW[] = {'R','i','g','h','t',' ','W','i','n','d','o','w','s',0}; +static const WCHAR applicationW[] = {'A','p','p','l','i','c','a','t','i','o','n',0}; + +static const VSC_LPWSTR key_names[] = +{ + {.vsc = 0x01, .pwsz = (WCHAR *)escW}, + {.vsc = 0x0e, .pwsz = (WCHAR *)backspaceW}, + {.vsc = 0x0f, .pwsz = (WCHAR *)tabW}, + {.vsc = 0x1c, .pwsz = (WCHAR *)enterW}, + {.vsc = 0x1d, .pwsz = (WCHAR *)ctrlW}, + {.vsc = 0x2a, .pwsz = (WCHAR *)shiftW}, + {.vsc = 0x36, .pwsz = (WCHAR *)right_shiftW}, + {.vsc = 0x37, .pwsz = (WCHAR *)num_mulW}, + {.vsc = 0x38, .pwsz = (WCHAR *)altW}, + {.vsc = 0x39, .pwsz = (WCHAR *)spaceW}, + {.vsc = 0x3a, .pwsz = (WCHAR *)caps_lockW}, + {.vsc = 0x3b, .pwsz = (WCHAR *)f1W}, + {.vsc = 0x3c, .pwsz = (WCHAR *)f2W}, + {.vsc = 0x3d, .pwsz = (WCHAR *)f3W}, + {.vsc = 0x3e, .pwsz = (WCHAR *)f4W}, + {.vsc = 0x3f, .pwsz = (WCHAR *)f5W}, + {.vsc = 0x40, .pwsz = (WCHAR *)f6W}, + {.vsc = 0x41, .pwsz = (WCHAR *)f7W}, + {.vsc = 0x42, .pwsz = (WCHAR *)f8W}, + {.vsc = 0x43, .pwsz = (WCHAR *)f9W}, + {.vsc = 0x44, .pwsz = (WCHAR *)f10W}, + {.vsc = 0x45, .pwsz = (WCHAR *)pauseW}, + {.vsc = 0x46, .pwsz = (WCHAR *)scroll_lockW}, + {.vsc = 0x47, .pwsz = (WCHAR *)num_7W}, + {.vsc = 0x48, .pwsz = (WCHAR *)num_8W}, + {.vsc = 0x49, .pwsz = (WCHAR *)num_9W}, + {.vsc = 0x4a, .pwsz = (WCHAR *)num_minusW}, + {.vsc = 0x4b, .pwsz = (WCHAR *)num_4W}, + {.vsc = 0x4c, .pwsz = (WCHAR *)num_5W}, + {.vsc = 0x4d, .pwsz = (WCHAR *)num_6W}, + {.vsc = 0x4e, .pwsz = (WCHAR *)num_plusW}, + {.vsc = 0x4f, .pwsz = (WCHAR *)num_1W}, + {.vsc = 0x50, .pwsz = (WCHAR *)num_2W}, + {.vsc = 0x51, .pwsz = (WCHAR *)num_3W}, + {.vsc = 0x52, .pwsz = (WCHAR *)num_0W}, + {.vsc = 0x53, .pwsz = (WCHAR *)num_delW}, + {.vsc = 0x54, .pwsz = (WCHAR *)sys_reqW}, + {.vsc = 0x57, .pwsz = (WCHAR *)f11W}, + {.vsc = 0x58, .pwsz = (WCHAR *)f12W}, + {.vsc = 0x7c, .pwsz = (WCHAR *)f13W}, + {.vsc = 0x7d, .pwsz = (WCHAR *)f14W}, + {.vsc = 0x7e, .pwsz = (WCHAR *)f15W}, + {.vsc = 0x7f, .pwsz = (WCHAR *)f16W}, + {.vsc = 0x80, .pwsz = (WCHAR *)f17W}, + {.vsc = 0x81, .pwsz = (WCHAR *)f18W}, + {.vsc = 0x82, .pwsz = (WCHAR *)f19W}, + {.vsc = 0x83, .pwsz = (WCHAR *)f20W}, + {.vsc = 0x84, .pwsz = (WCHAR *)f21W}, + {.vsc = 0x85, .pwsz = (WCHAR *)f22W}, + {.vsc = 0x86, .pwsz = (WCHAR *)f23W}, + {.vsc = 0x87, .pwsz = (WCHAR *)f24W}, + {0}, +}; + +static const VSC_LPWSTR key_names_ext[] = +{ + {.vsc = 0x1c, .pwsz = (WCHAR *)num_enterW}, + {.vsc = 0x1d, .pwsz = (WCHAR *)right_ctrlW}, + {.vsc = 0x35, .pwsz = (WCHAR *)num_divW}, + {.vsc = 0x37, .pwsz = (WCHAR *)prnt_scrnW}, + {.vsc = 0x38, .pwsz = (WCHAR *)right_altW}, + {.vsc = 0x45, .pwsz = (WCHAR *)num_lockW}, + {.vsc = 0x46, .pwsz = (WCHAR *)breakW}, + {.vsc = 0x47, .pwsz = (WCHAR *)homeW}, + {.vsc = 0x48, .pwsz = (WCHAR *)upW}, + {.vsc = 0x49, .pwsz = (WCHAR *)page_upW}, + {.vsc = 0x4b, .pwsz = (WCHAR *)leftW}, + {.vsc = 0x4d, .pwsz = (WCHAR *)rightW}, + {.vsc = 0x4f, .pwsz = (WCHAR *)endW}, + {.vsc = 0x50, .pwsz = (WCHAR *)downW}, + {.vsc = 0x51, .pwsz = (WCHAR *)page_downW}, + {.vsc = 0x52, .pwsz = (WCHAR *)insertW}, + {.vsc = 0x53, .pwsz = (WCHAR *)deleteW}, + {.vsc = 0x54, .pwsz = (WCHAR *)zerozeroW}, + {.vsc = 0x56, .pwsz = (WCHAR *)helpW}, + {.vsc = 0x5b, .pwsz = (WCHAR *)left_windowsW}, + {.vsc = 0x5c, .pwsz = (WCHAR *)right_windowsW}, + {.vsc = 0x5d, .pwsz = (WCHAR *)applicationW}, + {0}, +}; + +static const KBDTABLES kbdus_tables = +{ + .pKeyNames = (VSC_LPWSTR *)key_names, + .pKeyNamesExt = (VSC_LPWSTR *)key_names_ext, +}; /********************************************************************** * NtUserAttachThreadInput (win32u.@) @@ -625,43 +788,6 @@ static const UINT kbd_en_vk2char[] = 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -static const char *kbd_en_vscname[] = -{ - 0, "Esc", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Backspace", "Tab", - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Enter", "Ctrl", 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Shift", 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, "Right Shift", "Num *", "Alt", "Space", "Caps Lock", "F1", "F2", "F3", "F4", "F5", - "F6", "F7", "F8", "F9", "F10", "Pause", "Scroll Lock", "Num 7", "Num 8", "Num 9", "Num -", "Num 4", "Num 5", "Num 6", "Num +", "Num 1", - "Num 2", "Num 3", "Num 0", "Num Del", "Sys Req", 0, 0, "F11", "F12", 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "F13", "F14", "F15", "F16", - "F17", "F18", "F19", "F20", "F21", "F22", "F23", "F24", 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* extended */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Num Enter", "Right Ctrl", 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, "Num /", 0, "Prnt Scrn", "Right Alt", 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, "Num Lock", "Break", "Home", "Up", "Page Up", 0, "Left", 0, "Right", 0, "End", - "Down", "Page Down", "Insert", "Delete", "<00>", 0, "Help", 0, 0, 0, 0, "Left Windows", "Right Windows", "Application", 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - /****************************************************************************** * NtUserMapVirtualKeyEx (win32u.@) */ @@ -749,11 +875,12 @@ UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout ) INT WINAPI NtUserGetKeyNameText( LONG lparam, WCHAR *buffer, INT size ) { INT code = ((lparam >> 16) & 0x1ff), vkey, len; - UINT vsc2vk_size, vscname_size; - const char *const *vscname; + const KBDTABLES *kbd_tables = &kbdus_tables; + VSC_LPWSTR *key_name; const UINT *vsc2vk; + UINT vsc2vk_size; - TRACE_(keyboard)( "lparam %d, buffer %p, size %d.\n", (int)lparam, buffer, size ); + TRACE_(keyboard)( "lparam %#x, buffer %p, size %d.\n", (int)lparam, buffer, size ); if (!buffer || !size) return 0; if ((len = user_driver->pGetKeyNameText( lparam, buffer, size )) >= 0) return len; @@ -762,8 +889,6 @@ INT WINAPI NtUserGetKeyNameText( LONG lparam, WCHAR *buffer, INT size ) vsc2vk = kbd_en_vsc2vk; vsc2vk_size = ARRAYSIZE(kbd_en_vsc2vk); - vscname = kbd_en_vscname; - vscname_size = ARRAYSIZE(kbd_en_vscname); if (lparam & 0x2000000) { @@ -778,20 +903,21 @@ INT WINAPI NtUserGetKeyNameText( LONG lparam, WCHAR *buffer, INT size ) } } - if (code < vscname_size) + if (code < 0x100) key_name = kbd_tables->pKeyNames; + else key_name = kbd_tables->pKeyNamesExt; + while (key_name->vsc && key_name->vsc != (BYTE)code) key_name++; + + if (key_name->vsc == (BYTE)code) { - if (vscname[code]) - { - len = min( size - 1, strlen(vscname[code]) ); - ascii_to_unicode( buffer, vscname[code], len ); - } - else if (size > 1) - { - HKL hkl = NtUserGetKeyboardLayout( 0 ); - vkey = NtUserMapVirtualKeyEx( code & 0xff, MAPVK_VSC_TO_VK, hkl ); - buffer[0] = NtUserMapVirtualKeyEx( vkey, MAPVK_VK_TO_CHAR, hkl ); - len = 1; - } + len = min( size - 1, wcslen( key_name->pwsz ) ); + memcpy( buffer, key_name->pwsz, len * sizeof(WCHAR) ); + } + else if (size > 1) + { + HKL hkl = NtUserGetKeyboardLayout( 0 ); + vkey = NtUserMapVirtualKeyEx( code & 0xff, MAPVK_VSC_TO_VK, hkl ); + buffer[0] = NtUserMapVirtualKeyEx( vkey, MAPVK_VK_TO_CHAR, hkl ); + len = 1; } buffer[len] = 0; From 1f317c9f0867d932b8a65cf3894a443a3abc970f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 30 Nov 2022 20:16:09 +0100 Subject: [PATCH 1120/2777] include: Add VSC_VK constants definitions to kbd.h. (cherry picked from commit 48c71b31f5aeb0d71563303438ff63e07156e869) --- include/kbd.h | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) diff --git a/include/kbd.h b/include/kbd.h index 3cf0b35ac8e..de1d2c784d2 100644 --- a/include/kbd.h +++ b/include/kbd.h @@ -113,4 +113,211 @@ typedef struct tagKbdLayer DWORD dwSubType; } KBDTABLES, *PKBDTABLES; +#define KBD_VERSION 1 +#define GET_KBD_VERSION(table) (HIWORD((table)->fLocaleFlags)) + +#ifndef KBD_TYPE +#define KBD_TYPE 4 +#endif + +#define KBDEXT (USHORT)0x0100 +#define KBDMULTIVK (USHORT)0x0200 +#define KBDSPECIAL (USHORT)0x0400 +#define KBDNUMPAD (USHORT)0x0800 +#define KBDUNICODE (USHORT)0x1000 +#define KBDINJECTEDVK (USHORT)0x2000 +#define KBDMAPPEDVK (USHORT)0x4000 +#define KBDBREAK (USHORT)0x8000 + +#define VK__none_ 0xff +#define VK_ABNT_C1 0xc1 +#define VK_ABNT_C2 0xc2 + +#if (KBD_TYPE <= 6) +#define _EQ(v4) (VK_##v4) +#if (KBD_TYPE == 1) +#define _NE(v1, v2, v3, v4, v5, v6) (VK_##v1) +#elif (KBD_TYPE == 2) +#define _NE(v1, v2, v3, v4, v5, v6) (VK_##v2) +#elif (KBD_TYPE == 3) +#define _NE(v1, v2, v3, v4, v5, v6) (VK_##v3) +#elif (KBD_TYPE == 4) +#define _NE(v1, v2, v3, v4, v5, v6) (VK_##v4) +#elif (KBD_TYPE == 5) +#define _NE(v1, v2, v3, v4, v5, v6) (VK_##v5) +#elif (KBD_TYPE == 6) +#define _NE(v1, v2, v3, v4, v5, v6) (VK_##v6) +#endif +#define T00 _EQ(_none_) +#define T01 _EQ(ESCAPE) +#define T02 '1' +#define T03 '2' +#define T04 '3' +#define T05 '4' +#define T06 '5' +#define T07 '6' +#define T08 '7' +#define T09 '8' +#define T0A '9' +#define T0B '0' +#define T0C _EQ(OEM_MINUS) +#define T0D _NE(OEM_PLUS,OEM_4, OEM_PLUS, OEM_PLUS, OEM_PLUS, OEM_PLUS) +#define T0E _EQ(BACK) +#define T0F _EQ(TAB) +#define T10 'Q' +#define T11 'W' +#define T12 'E' +#define T13 'R' +#define T14 'T' +#define T15 'Y' +#define T16 'U' +#define T17 'I' +#define T18 'O' +#define T19 'P' +#define T1A _NE(OEM_4, OEM_6, OEM_4, OEM_4, OEM_4, OEM_4) +#define T1B _NE(OEM_6, OEM_1, OEM_6, OEM_6, OEM_6, OEM_6) +#define T1C _EQ(RETURN) +#define T1D _EQ(LCONTROL) +#define T1E 'A' +#define T1F 'S' +#define T20 'D' +#define T21 'F' +#define T22 'G' +#define T23 'H' +#define T24 'J' +#define T25 'K' +#define T26 'L' +#define T27 _NE(OEM_1, OEM_PLUS, OEM_1, OEM_1, OEM_1, OEM_1) +#define T28 _NE(OEM_7, OEM_3, OEM_7, OEM_7, OEM_3, OEM_3) +#define T29 _NE(OEM_3, OEM_7, OEM_3, OEM_3, OEM_7, OEM_7) +#define T2A _EQ(LSHIFT) +#define T2B _EQ(OEM_5) +#define T2C 'Z' +#define T2D 'X' +#define T2E 'C' +#define T2F 'V' +#define T30 'B' +#define T31 'N' +#define T32 'M' +#define T33 _EQ(OEM_COMMA) +#define T34 _EQ(OEM_PERIOD) +#define T35 _EQ(OEM_2) +#define T36 _EQ(RSHIFT) +#define T37 _EQ(MULTIPLY) +#define T38 _EQ(LMENU) +#define T39 ' ' +#define T3A _EQ(CAPITAL) +#define T3B _EQ(F1) +#define T3C _EQ(F2) +#define T3D _EQ(F3) +#define T3E _EQ(F4) +#define T3F _EQ(F5) +#define T40 _EQ(F6) +#define T41 _EQ(F7) +#define T42 _EQ(F8) +#define T43 _EQ(F9) +#define T44 _EQ(F10) +#define T45 _EQ(NUMLOCK) +#define T46 _EQ(SCROLL) +#define T47 _EQ(HOME) +#define T48 _EQ(UP) +#define T49 _EQ(PRIOR) +#define T4A _EQ(SUBTRACT) +#define T4B _EQ(LEFT) +#define T4C _EQ(CLEAR) +#define T4D _EQ(RIGHT) +#define T4E _EQ(ADD) +#define T4F _EQ(END) +#define T50 _EQ(DOWN) +#define T51 _EQ(NEXT) +#define T52 _EQ(INSERT) +#define T53 _EQ(DELETE) +#define T54 _EQ(SNAPSHOT) +#define T55 _EQ(_none_) +#define T56 _NE(OEM_102, HELP, OEM_102, OEM_102, _none_, OEM_PA2) +#define T57 _NE(F11, RETURN, F11, F11, _none_, HELP) +#define T58 _NE(F12, LEFT, F12, F12, _none_, OEM_102) +#define T59 _EQ(CLEAR) +#define T5A _EQ(OEM_WSCTRL) +#define T5B _EQ(OEM_FINISH) +#define T5C _EQ(OEM_JUMP) +#define T5D _EQ(EREOF) +#define T5E _EQ(OEM_BACKTAB) +#define T5F _EQ(OEM_AUTO) +#define T60 _EQ(_none_) +#define T61 _EQ(_none_) +#define T62 _EQ(ZOOM) +#define T63 _EQ(HELP) +#define T64 _EQ(F13) +#define T65 _EQ(F14) +#define T66 _EQ(F15) +#define T67 _EQ(F16) +#define T68 _EQ(F17) +#define T69 _EQ(F18) +#define T6A _EQ(F19) +#define T6B _EQ(F20) +#define T6C _EQ(F21) +#define T6D _EQ(F22) +#define T6E _EQ(F23) +#define T6F _EQ(OEM_PA3) +#define T70 _EQ(_none_) +#define T71 _EQ(OEM_RESET) +#define T72 _EQ(_none_) +#define T73 _EQ(ABNT_C1) +#define T74 _EQ(_none_) +#define T75 _EQ(_none_) +#define T76 _EQ(F24) +#define T77 _EQ(_none_) +#define T78 _EQ(_none_) +#define T79 _EQ(_none_) +#define T7A _EQ(_none_) +#define T7B _EQ(OEM_PA1) +#define T7C _EQ(TAB) +#define T7D _EQ(_none_) +#define T7E _EQ(ABNT_C2) +#define T7F _EQ(OEM_PA2) +#define X10 _EQ(MEDIA_PREV_TRACK) +#define X19 _EQ(MEDIA_NEXT_TRACK) +#define X1C _EQ(RETURN) +#define X1D _EQ(RCONTROL) +#define X20 _EQ(VOLUME_MUTE) +#define X21 _EQ(LAUNCH_APP2) +#define X22 _EQ(MEDIA_PLAY_PAUSE) +#define X24 _EQ(MEDIA_STOP) +#define X2E _EQ(VOLUME_DOWN) +#define X30 _EQ(VOLUME_UP) +#define X32 _EQ(BROWSER_HOME) +#define X35 _EQ(DIVIDE) +#define X37 _EQ(SNAPSHOT) +#define X38 _EQ(RMENU) +#define X46 _EQ(CANCEL) +#define X47 _EQ(HOME) +#define X48 _EQ(UP) +#define X49 _EQ(PRIOR) +#define X4B _EQ(LEFT) +#define X4D _EQ(RIGHT) +#define X4F _EQ(END) +#define X50 _EQ(DOWN) +#define X51 _NE(NEXT, F1, NEXT, NEXT, _none_, OEM_PA2) +#define X52 _EQ(INSERT) +#define X53 _EQ(DELETE) +#define X5B _EQ(LWIN) +#define X5C _EQ(RWIN) +#define X5D _EQ(APPS) +#define X5E _EQ(POWER) +#define X5F _EQ(SLEEP) +#define X65 _EQ(BROWSER_SEARCH) +#define X66 _EQ(BROWSER_FAVORITES) +#define X67 _EQ(BROWSER_REFRESH) +#define X68 _EQ(BROWSER_STOP) +#define X69 _EQ(BROWSER_FORWARD) +#define X6A _EQ(BROWSER_BACK) +#define X6B _EQ(LAUNCH_APP1) +#define X6C _EQ(LAUNCH_MAIL) +#define X6D _EQ(LAUNCH_MEDIA_SELECT) +#define Y1D _EQ(PAUSE) +#else +#error "Unsupported KBD_TYPE" +#endif + #endif /* __WINE_KBD_H */ From bb8ef1fabd3d7d6ac76e080423b3350fe6bb0760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 8 Feb 2023 00:13:33 +0100 Subject: [PATCH 1121/2777] win32u: Use KBDTABLES for NtUserMapVirtualKeyEx VSC / VK mapping. (cherry picked from commit 37de2cb434dcce61e8ae07ce4b81213ef97b5d45) --- dlls/win32u/input.c | 181 +++++++++++++++++++++++++++----------------- 1 file changed, 111 insertions(+), 70 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index e3db35bb4e8..34f2463d78e 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -207,12 +207,112 @@ static const VSC_LPWSTR key_names_ext[] = {0}, }; +static const USHORT vsc_to_vk[] = +{ + T00, T01, T02, T03, T04, T05, T06, T07, + T08, T09, T0A, T0B, T0C, T0D, T0E, T0F, + T10, T11, T12, T13, T14, T15, T16, T17, + T18, T19, T1A, T1B, T1C, T1D, T1E, T1F, + T20, T21, T22, T23, T24, T25, T26, T27, + T28, T29, T2A, T2B, T2C, T2D, T2E, T2F, + T30, T31, T32, T33, T34, T35, T36 | KBDEXT, T37 | KBDMULTIVK, + T38, T39, T3A, T3B, T3C, T3D, T3E, T3F, + T40, T41, T42, T43, T44, T45 | KBDEXT | KBDMULTIVK, T46 | KBDMULTIVK, T47 | KBDNUMPAD | KBDSPECIAL, + T48 | KBDNUMPAD | KBDSPECIAL, T49 | KBDNUMPAD | KBDSPECIAL, T4A, T4B | KBDNUMPAD | KBDSPECIAL, + T4C | KBDNUMPAD | KBDSPECIAL, T4D | KBDNUMPAD | KBDSPECIAL, T4E, T4F | KBDNUMPAD | KBDSPECIAL, + T50 | KBDNUMPAD | KBDSPECIAL, T51 | KBDNUMPAD | KBDSPECIAL, T52 | KBDNUMPAD | KBDSPECIAL, + T53 | KBDNUMPAD | KBDSPECIAL, T54, T55, T56, T57, + T58, T59, T5A, T5B, T5C, T5D, T5E, T5F, + T60, T61, T62, T63, T64, T65, T66, T67, + T68, T69, T6A, T6B, T6C, T6D, T6E, T6F, + T70, T71, T72, T73, T74, T75, T76, T77, + T78, T79, T7A, T7B, T7C, T7D, T7E +}; + +static const VSC_VK vsc_to_vk_e0[] = +{ + {0x10, X10 | KBDEXT}, + {0x19, X19 | KBDEXT}, + {0x1d, X1D | KBDEXT}, + {0x20, X20 | KBDEXT}, + {0x21, X21 | KBDEXT}, + {0x22, X22 | KBDEXT}, + {0x24, X24 | KBDEXT}, + {0x2e, X2E | KBDEXT}, + {0x30, X30 | KBDEXT}, + {0x32, X32 | KBDEXT}, + {0x35, X35 | KBDEXT}, + {0x37, X37 | KBDEXT}, + {0x38, X38 | KBDEXT}, + {0x47, X47 | KBDEXT}, + {0x48, X48 | KBDEXT}, + {0x49, X49 | KBDEXT}, + {0x4b, X4B | KBDEXT}, + {0x4d, X4D | KBDEXT}, + {0x4f, X4F | KBDEXT}, + {0x50, X50 | KBDEXT}, + {0x51, X51 | KBDEXT}, + {0x52, X52 | KBDEXT}, + {0x53, X53 | KBDEXT}, + {0x5b, X5B | KBDEXT}, + {0x5c, X5C | KBDEXT}, + {0x5d, X5D | KBDEXT}, + {0x5f, X5F | KBDEXT}, + {0x65, X65 | KBDEXT}, + {0x66, X66 | KBDEXT}, + {0x67, X67 | KBDEXT}, + {0x68, X68 | KBDEXT}, + {0x69, X69 | KBDEXT}, + {0x6a, X6A | KBDEXT}, + {0x6b, X6B | KBDEXT}, + {0x6c, X6C | KBDEXT}, + {0x6d, X6D | KBDEXT}, + {0x1c, X1C | KBDEXT}, + {0x46, X46 | KBDEXT}, + {0}, +}; + +static const VSC_VK vsc_to_vk_e1[] = +{ + {0x1d, Y1D}, + {0}, +}; + static const KBDTABLES kbdus_tables = { .pKeyNames = (VSC_LPWSTR *)key_names, .pKeyNamesExt = (VSC_LPWSTR *)key_names_ext, + .pusVSCtoVK = (USHORT *)vsc_to_vk, + .bMaxVSCtoVK = sizeof(vsc_to_vk) / sizeof(vsc_to_vk[0]), + .pVSCtoVK_E0 = (VSC_VK *)vsc_to_vk_e0, + .pVSCtoVK_E1 = (VSC_VK *)vsc_to_vk_e1, }; + +static void kbd_tables_init_vsc2vk( const KBDTABLES *tables, BYTE vsc2vk[0x300] ) +{ + const VSC_VK *entry; + WORD vsc; + + memset( vsc2vk, 0, 0x300 ); + + for (vsc = 0; tables->pusVSCtoVK && vsc <= tables->bMaxVSCtoVK; ++vsc) + { + if (tables->pusVSCtoVK[vsc] == VK__none_) continue; + vsc2vk[vsc] = (BYTE)tables->pusVSCtoVK[vsc]; + } + for (entry = tables->pVSCtoVK_E0; entry && entry->Vsc; entry++) + { + if (entry->Vk == VK__none_) continue; + vsc2vk[entry->Vsc + 0x100] = (BYTE)entry->Vk; + } + for (entry = tables->pVSCtoVK_E1; entry && entry->Vsc; entry++) + { + if (entry->Vk == VK__none_) continue; + vsc2vk[entry->Vsc + 0x200] = (BYTE)entry->Vk; + } +} + /********************************************************************** * NtUserAttachThreadInput (win32u.@) */ @@ -713,61 +813,6 @@ WORD WINAPI NtUserVkKeyScanEx( WCHAR chr, HKL layout ) return ret; } -/* English keyboard layout (0x0409) */ -static const UINT kbd_en_vsc2vk[] = -{ - 0x00, 0x1b, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0xbd, 0xbb, 0x08, 0x09, - 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4f, 0x50, 0xdb, 0xdd, 0x0d, 0xa2, 0x41, 0x53, - 0x44, 0x46, 0x47, 0x48, 0x4a, 0x4b, 0x4c, 0xba, 0xde, 0xc0, 0xa0, 0xdc, 0x5a, 0x58, 0x43, 0x56, - 0x42, 0x4e, 0x4d, 0xbc, 0xbe, 0xbf, 0xa1, 0x6a, 0xa4, 0x20, 0x14, 0x70, 0x71, 0x72, 0x73, 0x74, - 0x75, 0x76, 0x77, 0x78, 0x79, 0x90, 0x91, 0x24, 0x26, 0x21, 0x6d, 0x25, 0x0c, 0x27, 0x6b, 0x23, - 0x28, 0x22, 0x2d, 0x2e, 0x2c, 0x00, 0xe2, 0x7a, 0x7b, 0x0c, 0xee, 0xf1, 0xea, 0xf9, 0xf5, 0xf3, - 0x00, 0x00, 0xfb, 0x2f, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xed, - 0x00, 0xe9, 0x00, 0xc1, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x00, 0xeb, 0x09, 0x00, 0xc2, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0xe000 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x0d, 0xa3, 0x00, 0x00, - 0xad, 0xb7, 0xb3, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0x00, - 0xaf, 0x00, 0xac, 0x00, 0x00, 0x6f, 0x00, 0x2c, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x24, 0x26, 0x21, 0x00, 0x25, 0x00, 0x27, 0x00, 0x23, - 0x28, 0x22, 0x2d, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x5c, 0x5d, 0x00, 0x5f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xab, 0xa8, 0xa9, 0xa7, 0xa6, 0xb6, 0xb4, 0xb5, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0xe100 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - static const UINT kbd_en_vk2char[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, @@ -793,18 +838,18 @@ static const UINT kbd_en_vk2char[] = */ UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout ) { - const UINT *vsc2vk, *vk2char; - UINT vsc2vk_size, vk2char_size; + const KBDTABLES *kbd_tables = &kbdus_tables; + const UINT *vk2char; + BYTE vsc2vk[0x300]; + UINT vk2char_size; UINT ret; TRACE_(keyboard)( "code %u, type %u, layout %p.\n", code, type, layout ); if ((ret = user_driver->pMapVirtualKeyEx( code, type, layout )) != -1) return ret; - /* FIXME: English keyboard layout specific */ + kbd_tables_init_vsc2vk( kbd_tables, vsc2vk ); - vsc2vk = kbd_en_vsc2vk; - vsc2vk_size = ARRAYSIZE(kbd_en_vsc2vk); vk2char = kbd_en_vk2char; vk2char_size = ARRAYSIZE(kbd_en_vk2char); @@ -830,8 +875,8 @@ UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout ) case VK_DECIMAL: code = VK_DELETE; break; } - for (ret = 0; ret < vsc2vk_size; ++ret) if (vsc2vk[ret] == code) break; - if (ret >= vsc2vk_size) ret = 0; + for (ret = 0; ret < ARRAY_SIZE(vsc2vk); ++ret) if (vsc2vk[ret] == code) break; + if (ret >= ARRAY_SIZE(vsc2vk)) ret = 0; if (type == MAPVK_VK_TO_VSC) { @@ -843,7 +888,7 @@ UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout ) case MAPVK_VSC_TO_VK: case MAPVK_VSC_TO_VK_EX: if (code & 0xe000) code -= 0xdf00; - if (code >= vsc2vk_size) ret = 0; + if (code >= ARRAY_SIZE(vsc2vk)) ret = 0; else ret = vsc2vk[code]; if (type == MAPVK_VSC_TO_VK) @@ -877,18 +922,14 @@ INT WINAPI NtUserGetKeyNameText( LONG lparam, WCHAR *buffer, INT size ) INT code = ((lparam >> 16) & 0x1ff), vkey, len; const KBDTABLES *kbd_tables = &kbdus_tables; VSC_LPWSTR *key_name; - const UINT *vsc2vk; - UINT vsc2vk_size; + BYTE vsc2vk[0x300]; TRACE_(keyboard)( "lparam %#x, buffer %p, size %d.\n", (int)lparam, buffer, size ); if (!buffer || !size) return 0; if ((len = user_driver->pGetKeyNameText( lparam, buffer, size )) >= 0) return len; - /* FIXME: English keyboard layout specific */ - - vsc2vk = kbd_en_vsc2vk; - vsc2vk_size = ARRAYSIZE(kbd_en_vsc2vk); + kbd_tables_init_vsc2vk( kbd_tables, vsc2vk ); if (lparam & 0x2000000) { @@ -897,7 +938,7 @@ INT WINAPI NtUserGetKeyNameText( LONG lparam, WCHAR *buffer, INT size ) case VK_RSHIFT: case VK_RCONTROL: case VK_RMENU: - for (code = 0; code < vsc2vk_size; ++code) + for (code = 0; code < ARRAY_SIZE(vsc2vk); ++code) if (vsc2vk[code] == (vkey - 1)) break; break; } From a7209978f0bbdc138e20e3c8e0da1dce8d70bb40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 30 Nov 2022 20:16:09 +0100 Subject: [PATCH 1122/2777] include: Add VK_TO_WCHARS constants definitions to kbd.h. (cherry picked from commit c04f351db26c71c9f69f4cb8dd586233e3db53af) --- include/kbd.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/kbd.h b/include/kbd.h index de1d2c784d2..9bbcd886b1c 100644 --- a/include/kbd.h +++ b/include/kbd.h @@ -21,6 +21,25 @@ #include "windef.h" +#define KBDBASE 0 +#define KBDSHIFT 1 +#define KBDCTRL 2 +#define KBDALT 4 +#define KBDKANA 8 +#define KBDROYA 0x10 +#define KBDLOYA 0x20 +#define KBDGRPSELTAP 0x80 + +#define WCH_NONE 0xf000 +#define WCH_DEAD 0xf001 +#define WCH_LGTR 0xf002 + +#define CAPLOK 0x01 +#define SGCAPS 0x02 +#define CAPLOKALTGR 0x04 +#define KANALOK 0x08 +#define GRPSELTAP 0x80 + typedef struct { BYTE Vk; From ff90280d2fd3f3126e86828ecf9e085a94af2760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 7 Jan 2023 17:25:20 +0100 Subject: [PATCH 1123/2777] win32u: Use KBDTABLES for NtUserMapVirtualKeyEx MAP_VK_TO_CHAR. (cherry picked from commit 70dc48e3f0a3472bf8ad6d34bf473d2a1ea0e329) --- dlls/win32u/input.c | 167 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 141 insertions(+), 26 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 34f2463d78e..518ce3fc32e 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -124,6 +124,119 @@ static const WCHAR left_windowsW[] = {'L','e','f','t',' ','W','i','n','d','o','w static const WCHAR right_windowsW[] = {'R','i','g','h','t',' ','W','i','n','d','o','w','s',0}; static const WCHAR applicationW[] = {'A','p','p','l','i','c','a','t','i','o','n',0}; +static const VK_TO_BIT vk_to_bit[] = +{ + {.Vk = VK_SHIFT, .ModBits = KBDSHIFT}, + {.Vk = VK_CONTROL, .ModBits = KBDCTRL}, + {.Vk = VK_MENU, .ModBits = KBDALT}, + {0}, +}; + +static const MODIFIERS modifiers = +{ + .pVkToBit = (VK_TO_BIT *)vk_to_bit, + .wMaxModBits = 3, + .ModNumber = {0, 1, 2, 3}, +}; + +static const VK_TO_WCHARS2 vk_to_wchars2[] = +{ + {.VirtualKey = VK_OEM_3, .wch = {'`', '~'}}, + {.VirtualKey = '1', .wch = {'1', '!'}}, + {.VirtualKey = '3', .wch = {'3', '#'}}, + {.VirtualKey = '4', .wch = {'4', '$'}}, + {.VirtualKey = '5', .wch = {'5', '%'}}, + {.VirtualKey = '7', .wch = {'7', '&'}}, + {.VirtualKey = '8', .wch = {'8', '*'}}, + {.VirtualKey = '9', .wch = {'9', '('}}, + {.VirtualKey = '0', .wch = {'0', ')'}}, + {.VirtualKey = VK_OEM_PLUS, .wch = {'=', '+'}}, + {.VirtualKey = 'Q', .wch = {'q', 'Q'}, .Attributes = CAPLOK}, + {.VirtualKey = 'W', .wch = {'w', 'W'}, .Attributes = CAPLOK}, + {.VirtualKey = 'E', .wch = {'e', 'E'}, .Attributes = CAPLOK}, + {.VirtualKey = 'R', .wch = {'r', 'R'}, .Attributes = CAPLOK}, + {.VirtualKey = 'T', .wch = {'t', 'T'}, .Attributes = CAPLOK}, + {.VirtualKey = 'Y', .wch = {'y', 'Y'}, .Attributes = CAPLOK}, + {.VirtualKey = 'U', .wch = {'u', 'U'}, .Attributes = CAPLOK}, + {.VirtualKey = 'I', .wch = {'i', 'I'}, .Attributes = CAPLOK}, + {.VirtualKey = 'O', .wch = {'o', 'O'}, .Attributes = CAPLOK}, + {.VirtualKey = 'P', .wch = {'p', 'P'}, .Attributes = CAPLOK}, + {.VirtualKey = 'A', .wch = {'a', 'A'}, .Attributes = CAPLOK}, + {.VirtualKey = 'S', .wch = {'s', 'S'}, .Attributes = CAPLOK}, + {.VirtualKey = 'D', .wch = {'d', 'D'}, .Attributes = CAPLOK}, + {.VirtualKey = 'F', .wch = {'f', 'F'}, .Attributes = CAPLOK}, + {.VirtualKey = 'G', .wch = {'g', 'G'}, .Attributes = CAPLOK}, + {.VirtualKey = 'H', .wch = {'h', 'H'}, .Attributes = CAPLOK}, + {.VirtualKey = 'J', .wch = {'j', 'J'}, .Attributes = CAPLOK}, + {.VirtualKey = 'K', .wch = {'k', 'K'}, .Attributes = CAPLOK}, + {.VirtualKey = 'L', .wch = {'l', 'L'}, .Attributes = CAPLOK}, + {.VirtualKey = VK_OEM_1, .wch = {';', ':'}}, + {.VirtualKey = VK_OEM_7, .wch = {'\'', '\"'}}, + {.VirtualKey = 'Z', .wch = {'z', 'Z'}, .Attributes = CAPLOK}, + {.VirtualKey = 'X', .wch = {'x', 'X'}, .Attributes = CAPLOK}, + {.VirtualKey = 'C', .wch = {'c', 'C'}, .Attributes = CAPLOK}, + {.VirtualKey = 'V', .wch = {'v', 'V'}, .Attributes = CAPLOK}, + {.VirtualKey = 'B', .wch = {'b', 'B'}, .Attributes = CAPLOK}, + {.VirtualKey = 'N', .wch = {'n', 'N'}, .Attributes = CAPLOK}, + {.VirtualKey = 'M', .wch = {'m', 'M'}, .Attributes = CAPLOK}, + {.VirtualKey = VK_OEM_COMMA, .wch = {',', '<'}}, + {.VirtualKey = VK_OEM_PERIOD, .wch = {'.', '>'}}, + {.VirtualKey = VK_OEM_2, .wch = {'/', '?'}}, + {.VirtualKey = VK_DECIMAL, .wch = {'.', '.'}}, + {.VirtualKey = VK_TAB, .wch = {'\t', '\t'}}, + {.VirtualKey = VK_ADD, .wch = {'+', '+'}}, + {.VirtualKey = VK_DIVIDE, .wch = {'/', '/'}}, + {.VirtualKey = VK_MULTIPLY, .wch = {'*', '*'}}, + {.VirtualKey = VK_SUBTRACT, .wch = {'-', '-'}}, + {0}, +}; + +static const VK_TO_WCHARS3 vk_to_wchars3[] = +{ + {.VirtualKey = VK_OEM_4, .wch = {'[', '{', '\x001b'}}, + {.VirtualKey = VK_OEM_6, .wch = {']', '}', '\x001d'}}, + {.VirtualKey = VK_OEM_5, .wch = {'\\', '|', '\x001c'}}, + {.VirtualKey = VK_OEM_102, .wch = {'\\', '|', '\x001c'}}, + {.VirtualKey = VK_BACK, .wch = {'\b', '\b', '\x007f'}}, + {.VirtualKey = VK_ESCAPE, .wch = {'\x001b', '\x001b', '\x001b'}}, + {.VirtualKey = VK_RETURN, .wch = {'\r', '\r', '\n'}}, + {.VirtualKey = VK_SPACE, .wch = {' ', ' ', ' '}}, + {.VirtualKey = VK_CANCEL, .wch = {'\x0003', '\x0003', '\x0003'}}, + {0}, +}; + +static const VK_TO_WCHARS4 vk_to_wchars4[] = +{ + {.VirtualKey = '2', .wch = {'2', '@', WCH_NONE, '\x0000'}}, + {.VirtualKey = '6', .wch = {'6', '^', WCH_NONE, '\x001e'}}, + {.VirtualKey = VK_OEM_MINUS, .wch = {'-', '_', WCH_NONE, '\x001f'}}, + {0}, +}; + +static const VK_TO_WCHARS1 vk_to_wchars1[] = +{ + {.VirtualKey = VK_NUMPAD0, .wch = {'0'}}, + {.VirtualKey = VK_NUMPAD1, .wch = {'1'}}, + {.VirtualKey = VK_NUMPAD2, .wch = {'2'}}, + {.VirtualKey = VK_NUMPAD3, .wch = {'3'}}, + {.VirtualKey = VK_NUMPAD4, .wch = {'4'}}, + {.VirtualKey = VK_NUMPAD5, .wch = {'5'}}, + {.VirtualKey = VK_NUMPAD6, .wch = {'6'}}, + {.VirtualKey = VK_NUMPAD7, .wch = {'7'}}, + {.VirtualKey = VK_NUMPAD8, .wch = {'8'}}, + {.VirtualKey = VK_NUMPAD9, .wch = {'9'}}, + {0}, +}; + +static const VK_TO_WCHAR_TABLE vk_to_wchar_table[] = +{ + {.pVkToWchars = (VK_TO_WCHARS1 *)vk_to_wchars3, .nModifications = 3, .cbSize = sizeof(vk_to_wchars3[0])}, + {.pVkToWchars = (VK_TO_WCHARS1 *)vk_to_wchars4, .nModifications = 4, .cbSize = sizeof(vk_to_wchars4[0])}, + {.pVkToWchars = (VK_TO_WCHARS1 *)vk_to_wchars2, .nModifications = 2, .cbSize = sizeof(vk_to_wchars2[0])}, + {.pVkToWchars = (VK_TO_WCHARS1 *)vk_to_wchars1, .nModifications = 1, .cbSize = sizeof(vk_to_wchars1[0])}, + {0}, +}; + static const VSC_LPWSTR key_names[] = { {.vsc = 0x01, .pwsz = (WCHAR *)escW}, @@ -280,12 +393,15 @@ static const VSC_VK vsc_to_vk_e1[] = static const KBDTABLES kbdus_tables = { + .pCharModifiers = (MODIFIERS *)&modifiers, + .pVkToWcharTable = (VK_TO_WCHAR_TABLE *)vk_to_wchar_table, .pKeyNames = (VSC_LPWSTR *)key_names, .pKeyNamesExt = (VSC_LPWSTR *)key_names_ext, .pusVSCtoVK = (USHORT *)vsc_to_vk, .bMaxVSCtoVK = sizeof(vsc_to_vk) / sizeof(vsc_to_vk[0]), .pVSCtoVK_E0 = (VSC_VK *)vsc_to_vk_e0, .pVSCtoVK_E1 = (VSC_VK *)vsc_to_vk_e1, + .fLocaleFlags = MAKELONG(0, KBD_VERSION), }; @@ -313,6 +429,27 @@ static void kbd_tables_init_vsc2vk( const KBDTABLES *tables, BYTE vsc2vk[0x300] } } +#define NEXT_ENTRY(t, e) ((void *)&(e)->wch[(t)->nModifications]) + +static void kbd_tables_init_vk2char( const KBDTABLES *tables, BYTE vk2char[0x100] ) +{ + const VK_TO_WCHAR_TABLE *table; + const VK_TO_WCHARS1 *entry; + + memset( vk2char, 0, 0x100 ); + + for (table = tables->pVkToWcharTable; table->pVkToWchars; table++) + { + for (entry = table->pVkToWchars; entry->VirtualKey; entry = NEXT_ENTRY(table, entry)) + { + if (entry->VirtualKey & ~0xff) continue; + vk2char[entry->VirtualKey] = entry->wch[0]; + } + } +} + +#undef NEXT_ENTRY + /********************************************************************** * NtUserAttachThreadInput (win32u.@) */ @@ -813,25 +950,6 @@ WORD WINAPI NtUserVkKeyScanEx( WCHAR chr, HKL layout ) return ret; } -static const UINT kbd_en_vk2char[] = -{ - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, - ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0x00, 0x00, 0x00, 0x00, 0x00, - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '+', 0x00, '-', '.', '/', - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ';', '=', ',', '-', '.', '/', - '`', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, '[', '\\', ']', '\'', 0x00, - 0x00, 0x00, '\\', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; /****************************************************************************** * NtUserMapVirtualKeyEx (win32u.@) @@ -839,9 +957,7 @@ static const UINT kbd_en_vk2char[] = UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout ) { const KBDTABLES *kbd_tables = &kbdus_tables; - const UINT *vk2char; - BYTE vsc2vk[0x300]; - UINT vk2char_size; + BYTE vsc2vk[0x300], vk2char[0x100]; UINT ret; TRACE_(keyboard)( "code %u, type %u, layout %p.\n", code, type, layout ); @@ -849,9 +965,7 @@ UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout ) if ((ret = user_driver->pMapVirtualKeyEx( code, type, layout )) != -1) return ret; kbd_tables_init_vsc2vk( kbd_tables, vsc2vk ); - - vk2char = kbd_en_vk2char; - vk2char_size = ARRAYSIZE(kbd_en_vk2char); + kbd_tables_init_vk2char( kbd_tables, vk2char ); switch (type) { @@ -902,7 +1016,8 @@ UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout ) } break; case MAPVK_VK_TO_CHAR: - if (code >= vk2char_size) ret = 0; + if (code >= ARRAY_SIZE(vk2char)) ret = 0; + else if (code >= 'A' && code <= 'Z') ret = code; else ret = vk2char[code]; break; default: From 810174a796a7e3df076ce006405b9cfb179664b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 8 Jan 2023 10:26:59 +0100 Subject: [PATCH 1124/2777] win32u: Use KBDTABLES for NtUserVkKeyScanEx. (cherry picked from commit 2e13fc3542bb4dcbb230105732332a8e55209517) --- dlls/win32u/input.c | 89 ++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 50 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 518ce3fc32e..b1ee4c8ba63 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -448,6 +448,43 @@ static void kbd_tables_init_vk2char( const KBDTABLES *tables, BYTE vk2char[0x100 } } +static UINT kbd_tables_get_mod_bits( const KBDTABLES *tables, UINT mod ) +{ + const MODIFIERS *mods = tables->pCharModifiers; + WORD bits; + + for (bits = 0; bits <= mods->wMaxModBits; ++bits) + if (mods->ModNumber[bits] == mod) return bits; + + return -1; +} + +static WORD kbd_tables_wchar_to_vkey( const KBDTABLES *tables, WCHAR wch ) +{ + const VK_TO_WCHAR_TABLE *table; + const VK_TO_WCHARS1 *entry; + WORD bits; + BYTE mod; + + if (wch == '\x001b') return VK_ESCAPE; + + for (table = tables->pVkToWcharTable; table->pVkToWchars; table++) + { + for (entry = table->pVkToWchars; entry->VirtualKey; entry = NEXT_ENTRY(table, entry)) + { + for (mod = 0; mod < table->nModifications; ++mod) + { + if (entry->wch[mod] == WCH_NONE || entry->wch[mod] != wch) continue; + bits = kbd_tables_get_mod_bits( tables, mod ); + return (bits << 8) | entry->VirtualKey; + } + } + } + + if (wch >= 0x0001 && wch <= 0x001a) return (0x200) | ('A' + wch - 1); /* CTRL + A-Z */ + return wch >= 0x0080 ? -1 : 0; +} + #undef NEXT_ENTRY /********************************************************************** @@ -890,61 +927,13 @@ BOOL WINAPI NtUserSetKeyboardState( BYTE *state ) */ WORD WINAPI NtUserVkKeyScanEx( WCHAR chr, HKL layout ) { - WORD shift = 0x100, ctrl = 0x200; + const KBDTABLES *kbd_tables = &kbdus_tables; SHORT ret; TRACE_(keyboard)( "chr %s, layout %p\n", debugstr_wn(&chr, 1), layout ); if ((ret = user_driver->pVkKeyScanEx( chr, layout )) != -256) return ret; - - /* FIXME: English keyboard layout specific */ - - if (chr == VK_CANCEL || chr == VK_BACK || chr == VK_TAB || chr == VK_RETURN || - chr == VK_ESCAPE || chr == VK_SPACE) ret = chr; - else if (chr >= '0' && chr <= '9') ret = chr; - else if (chr == ')') ret = shift + '0'; - else if (chr == '!') ret = shift + '1'; - else if (chr == '@') ret = shift + '2'; - else if (chr == '#') ret = shift + '3'; - else if (chr == '$') ret = shift + '4'; - else if (chr == '%') ret = shift + '5'; - else if (chr == '^') ret = shift + '6'; - else if (chr == '&') ret = shift + '7'; - else if (chr == '*') ret = shift + '8'; - else if (chr == '(') ret = shift + '9'; - else if (chr >= 'a' && chr <= 'z') ret = chr - 'a' + 'A'; - else if (chr >= 'A' && chr <= 'Z') ret = shift + chr; - else if (chr == ';') ret = VK_OEM_1; - else if (chr == '=') ret = VK_OEM_PLUS; - else if (chr == ',') ret = VK_OEM_COMMA; - else if (chr == '-') ret = VK_OEM_MINUS; - else if (chr == '.') ret = VK_OEM_PERIOD; - else if (chr == '/') ret = VK_OEM_2; - else if (chr == '`') ret = VK_OEM_3; - else if (chr == '[') ret = VK_OEM_4; - else if (chr == '\\') ret = VK_OEM_5; - else if (chr == ']') ret = VK_OEM_6; - else if (chr == '\'') ret = VK_OEM_7; - else if (chr == ':') ret = shift + VK_OEM_1; - else if (chr == '+') ret = shift + VK_OEM_PLUS; - else if (chr == '<') ret = shift + VK_OEM_COMMA; - else if (chr == '_') ret = shift + VK_OEM_MINUS; - else if (chr == '>') ret = shift + VK_OEM_PERIOD; - else if (chr == '?') ret = shift + VK_OEM_2; - else if (chr == '~') ret = shift + VK_OEM_3; - else if (chr == '{') ret = shift + VK_OEM_4; - else if (chr == '|') ret = shift + VK_OEM_5; - else if (chr == '}') ret = shift + VK_OEM_6; - else if (chr == '\"') ret = shift + VK_OEM_7; - else if (chr == 0x7f) ret = ctrl + VK_BACK; - else if (chr == '\n') ret = ctrl + VK_RETURN; - else if (chr == 0xf000) ret = ctrl + '2'; - else if (chr == 0x0000) ret = ctrl + shift + '2'; - else if (chr >= 0x0001 && chr <= 0x001a) ret = ctrl + 'A' + chr - 1; - else if (chr >= 0x001c && chr <= 0x001d) ret = ctrl + VK_OEM_3 + chr; - else if (chr == 0x001e) ret = ctrl + shift + '6'; - else if (chr == 0x001f) ret = ctrl + shift + VK_OEM_MINUS; - else ret = -1; + ret = kbd_tables_wchar_to_vkey( kbd_tables, chr ); TRACE_(keyboard)( "ret %04x\n", ret ); return ret; From 315a76ca2df8854ff4797fb534f503ea751927e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 7 Jan 2023 21:41:11 +0100 Subject: [PATCH 1125/2777] win32u: Use KBDTABLES for NtUserToUnicodeEx. (cherry picked from commit 2d3516cde91f4e574d0970a7609c98ba72986272) --- dlls/win32u/input.c | 122 +++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 70 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index b1ee4c8ba63..3803870bfba 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -459,6 +459,20 @@ static UINT kbd_tables_get_mod_bits( const KBDTABLES *tables, UINT mod ) return -1; } +static UINT kbd_tables_get_mod_num( const KBDTABLES *tables, const BYTE *state, BOOL caps ) +{ + const MODIFIERS *mods = tables->pCharModifiers; + const VK_TO_BIT *entry; + WORD bits = 0; + + for (entry = mods->pVkToBit; entry->Vk; ++entry) + if (state[entry->Vk] & 0x80) bits |= entry->ModBits; + if (caps) bits |= KBDSHIFT; + + if (bits > mods->wMaxModBits) return -1; + return mods->ModNumber[bits]; +} + static WORD kbd_tables_wchar_to_vkey( const KBDTABLES *tables, WCHAR wch ) { const VK_TO_WCHAR_TABLE *table; @@ -485,6 +499,37 @@ static WORD kbd_tables_wchar_to_vkey( const KBDTABLES *tables, WCHAR wch ) return wch >= 0x0080 ? -1 : 0; } +static WCHAR kbd_tables_vkey_to_wchar( const KBDTABLES *tables, UINT vkey, const BYTE *state ) +{ + UINT mod, caps_mod, alt, ctrl, caps; + const VK_TO_WCHAR_TABLE *table; + const VK_TO_WCHARS1 *entry; + + alt = state[VK_MENU] & 0x80; + ctrl = state[VK_CONTROL] & 0x80; + caps = state[VK_CAPITAL] & 1; + + if (ctrl && alt) return WCH_NONE; + if (!ctrl && vkey == VK_ESCAPE) return VK_ESCAPE; + + mod = caps_mod = kbd_tables_get_mod_num( tables, state, FALSE ); + if (caps) caps_mod = kbd_tables_get_mod_num( tables, state, TRUE ); + + for (table = tables->pVkToWcharTable; table->pVkToWchars; table++) + { + if (table->nModifications <= mod) continue; + for (entry = table->pVkToWchars; entry->VirtualKey; entry = NEXT_ENTRY(table, entry)) + { + if (entry->VirtualKey != vkey) continue; + if ((entry->Attributes & CAPLOK) && table->nModifications > caps_mod) return entry->wch[caps_mod]; + return entry->wch[mod]; + } + } + + if (ctrl && vkey >= 'A' && vkey <= 'Z') return vkey - 'A' + 1; + return WCH_NONE; +} + #undef NEXT_ENTRY /********************************************************************** @@ -1076,86 +1121,23 @@ INT WINAPI NtUserGetKeyNameText( LONG lparam, WCHAR *buffer, INT size ) INT WINAPI NtUserToUnicodeEx( UINT virt, UINT scan, const BYTE *state, WCHAR *str, int size, UINT flags, HKL layout ) { - BOOL shift, ctrl, alt, numlock; - WCHAR buffer[2]; + const KBDTABLES *kbd_tables = &kbdus_tables; + WCHAR buffer[2] = {0}; INT len; - TRACE_(keyboard)( "virt %u, scan %u, state %p, str %p, size %d, flags %x, layout %p.\n", + TRACE_(keyboard)( "virt %#x, scan %#x, state %p, str %p, size %d, flags %#x, layout %p.\n", virt, scan, state, str, size, flags, layout ); if (!state) return 0; if ((len = user_driver->pToUnicodeEx( virt, scan, state, str, size, flags, layout )) >= -1) return len; - alt = state[VK_MENU] & 0x80; - shift = state[VK_SHIFT] & 0x80; - ctrl = state[VK_CONTROL] & 0x80; - numlock = state[VK_NUMLOCK] & 0x01; + if (scan & 0x8000) buffer[0] = 0; /* key up */ + else buffer[0] = kbd_tables_vkey_to_wchar( kbd_tables, virt, state ); - /* FIXME: English keyboard layout specific */ + if (buffer[0] != WCH_NONE) len = 1; + else buffer[0] = len = 0; - if (scan & 0x8000) buffer[0] = 0; /* key up */ - else if (virt == VK_ESCAPE) buffer[0] = VK_ESCAPE; - else if (!ctrl) - { - switch (virt) - { - case VK_BACK: buffer[0] = '\b'; break; - case VK_OEM_1: buffer[0] = shift ? ':' : ';'; break; - case VK_OEM_2: buffer[0] = shift ? '?' : '/'; break; - case VK_OEM_3: buffer[0] = shift ? '~' : '`'; break; - case VK_OEM_4: buffer[0] = shift ? '{' : '['; break; - case VK_OEM_5: buffer[0] = shift ? '|' : '\\'; break; - case VK_OEM_6: buffer[0] = shift ? '}' : ']'; break; - case VK_OEM_7: buffer[0] = shift ? '"' : '\''; break; - case VK_OEM_COMMA: buffer[0] = shift ? '<' : ','; break; - case VK_OEM_MINUS: buffer[0] = shift ? '_' : '-'; break; - case VK_OEM_PERIOD: buffer[0] = shift ? '>' : '.'; break; - case VK_OEM_PLUS: buffer[0] = shift ? '+' : '='; break; - case VK_RETURN: buffer[0] = '\r'; break; - case VK_SPACE: buffer[0] = ' '; break; - case VK_TAB: buffer[0] = '\t'; break; - case VK_MULTIPLY: buffer[0] = '*'; break; - case VK_ADD: buffer[0] = '+'; break; - case VK_SUBTRACT: buffer[0] = '-'; break; - case VK_DIVIDE: buffer[0] = '/'; break; - default: - if (virt >= '0' && virt <= '9') - buffer[0] = shift ? ")!@#$%^&*("[virt - '0'] : virt; - else if (virt >= 'A' && virt <= 'Z') - buffer[0] = shift || (state[VK_CAPITAL] & 0x01) ? virt : virt + 'a' - 'A'; - else if (virt >= VK_NUMPAD0 && virt <= VK_NUMPAD9 && numlock && !shift) - buffer[0] = '0' + virt - VK_NUMPAD0; - else if (virt == VK_DECIMAL && numlock && !shift) - buffer[0] = '.'; - else - buffer[0] = 0; - break; - } - } - else if (!alt) /* Control codes */ - { - switch (virt) - { - case VK_OEM_4: buffer[0] = 0x1b; break; - case VK_OEM_5: buffer[0] = 0x1c; break; - case VK_OEM_6: buffer[0] = 0x1d; break; - case '6': buffer[0] = shift ? 0x1e : 0; break; - case VK_OEM_MINUS: buffer[0] = shift ? 0x1f : 0; break; - case VK_BACK: buffer[0] = 0x7f; break; - case VK_RETURN: buffer[0] = shift ? 0 : '\n'; break; - case '2': buffer[0] = shift ? 0xffff : 0xf000; break; - case VK_SPACE: buffer[0] = ' '; break; - default: - if (virt >= 'A' && virt <= 'Z') buffer[0] = virt - 'A' + 1; - else buffer[0] = 0; - break; - } - } - else buffer[0] = 0; - buffer[1] = 0; - len = lstrlenW( buffer ); - if (buffer[0] == 0xffff) buffer[0] = 0; lstrcpynW( str, buffer, size ); TRACE_(keyboard)( "ret %d, str %s.\n", len, debugstr_w(str) ); From 166e326324afb41828056ba04079d1f958047178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 11 Feb 2023 16:26:57 +0100 Subject: [PATCH 1126/2777] joy.cpl: Process messages while waiting for the input threads. Instead of interrupting the wait on any message. (cherry picked from commit 37025bdabd4ed771d0e9a5092c421e067b3b623e) --- dlls/joy.cpl/dinput.c | 11 ++++++++++- dlls/joy.cpl/xinput.c | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/dlls/joy.cpl/dinput.c b/dlls/joy.cpl/dinput.c index 521634ff7da..9a6359834ea 100644 --- a/dlls/joy.cpl/dinput.c +++ b/dlls/joy.cpl/dinput.c @@ -792,7 +792,16 @@ INT_PTR CALLBACK test_di_dialog_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM case PSN_RESET: case PSN_KILLACTIVE: SetEvent( thread_stop ); - MsgWaitForMultipleObjects( 1, &thread, FALSE, INFINITE, 0 ); + /* wait for the input thread to stop, processing any WM_USER message from it */ + while (MsgWaitForMultipleObjects( 1, &thread, FALSE, INFINITE, QS_ALLINPUT ) == 1) + { + MSG msg; + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } + } CloseHandle( state_event ); CloseHandle( thread_stop ); CloseHandle( thread ); diff --git a/dlls/joy.cpl/xinput.c b/dlls/joy.cpl/xinput.c index 757b99fa333..f652c9ad171 100644 --- a/dlls/joy.cpl/xinput.c +++ b/dlls/joy.cpl/xinput.c @@ -428,7 +428,16 @@ extern INT_PTR CALLBACK test_xi_dialog_proc( HWND hwnd, UINT msg, WPARAM wparam, case PSN_RESET: case PSN_KILLACTIVE: SetEvent( thread_stop ); - MsgWaitForMultipleObjects( 1, &thread, FALSE, INFINITE, 0 ); + /* wait for the input thread to stop, processing any WM_USER message from it */ + while (MsgWaitForMultipleObjects( 1, &thread, FALSE, INFINITE, QS_ALLINPUT ) == 1) + { + MSG msg; + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } + } CloseHandle( thread_stop ); CloseHandle( thread ); dialog_hwnd = 0; From 7a03cf6bed93fe82e4513546aee8b23c35e748ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 Feb 2023 11:54:13 +0100 Subject: [PATCH 1127/2777] joy.cpl: Refresh the DInput button display on device change. (cherry picked from commit 91f7201d421cc655bfa66fe89248055875a26358) --- dlls/joy.cpl/dinput.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/joy.cpl/dinput.c b/dlls/joy.cpl/dinput.c index 9a6359834ea..188c430618d 100644 --- a/dlls/joy.cpl/dinput.c +++ b/dlls/joy.cpl/dinput.c @@ -564,6 +564,7 @@ LRESULT CALLBACK test_di_buttons_window_proc( HWND hwnd, UINT msg, WPARAM wparam hdc = BeginPaint( hwnd, &paint ); GetClientRect( hwnd, &rect ); + FillRect( hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1) ); size = (rect.right - rect.left - space) / step; offs = (rect.right - rect.left - step * size - space) / 2; @@ -762,6 +763,8 @@ INT_PTR CALLBACK test_di_dialog_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM SendDlgItemMessageW( hwnd, IDC_DI_EFFECTS, LB_SETCURSEL, 0, 0 ); handle_di_effects_change( hwnd ); + + update_device_views( hwnd ); break; case MAKEWPARAM( IDC_DI_EFFECTS, LBN_SELCHANGE ): From e5bcb0ee21cce86881a42e4c6607343d55682cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 Feb 2023 11:54:38 +0100 Subject: [PATCH 1128/2777] joy.cpl: Improve the DInput button display with many buttons. (cherry picked from commit bb9ee1e94a3e3e8423df2f5a0613c5d7b4d8cdae) --- dlls/joy.cpl/dinput.c | 10 ++++++---- dlls/joy.cpl/joy.rc | 6 +++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/dlls/joy.cpl/dinput.c b/dlls/joy.cpl/dinput.c index 188c430618d..a4aef66e04d 100644 --- a/dlls/joy.cpl/dinput.c +++ b/dlls/joy.cpl/dinput.c @@ -417,7 +417,8 @@ static void draw_button_view( HDC hdc, RECT rect, BOOL set, const WCHAR *name ) SelectObject( hdc, GetStockObject( DC_BRUSH ) ); SelectObject( hdc, GetStockObject( DC_PEN ) ); - Ellipse( hdc, rect.left, rect.top, rect.right, rect.bottom ); + if (rect.right - rect.left < 16) Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom ); + else Ellipse( hdc, rect.left, rect.top, rect.right, rect.bottom ); color = SetTextColor( hdc, GetSysColor( set ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT ) ); font = SelectObject( hdc, GetStockObject( ANSI_VAR_FONT ) ); @@ -559,7 +560,7 @@ LRESULT CALLBACK test_di_buttons_window_proc( HWND hwnd, UINT msg, WPARAM wparam } if (caps.dwButtons <= 48) step = 16; - else step = 32; + else step = 24; hdc = BeginPaint( hwnd, &paint ); @@ -579,7 +580,8 @@ LRESULT CALLBACK test_di_buttons_window_proc( HWND hwnd, UINT msg, WPARAM wparam for (j = 0; j < step && i < caps.dwButtons; j++, i++) { WCHAR buffer[3]; - swprintf( buffer, ARRAY_SIZE(buffer), L"%d", i ); + if (step == 24) swprintf( buffer, ARRAY_SIZE(buffer), L"%02x", i ); + else swprintf( buffer, ARRAY_SIZE(buffer), L"%d", i ); draw_button_view( hdc, rect, state.rgbButtons[i], buffer ); OffsetRect( &rect, size, 0 ); } @@ -675,7 +677,7 @@ static void create_device_views( HWND hwnd ) GetClientRect( parent, &rect ); rect.top += 10; - margin = (rect.bottom - rect.top) * 10 / 100; + margin = (rect.bottom - rect.top) * 5 / 100; InflateRect( &rect, -margin, -margin ); CreateWindowW( L"JoyCplDInputButtons", NULL, WS_CHILD | WS_VISIBLE, rect.left, rect.top, diff --git a/dlls/joy.cpl/joy.rc b/dlls/joy.cpl/joy.rc index 08f6fa12e0c..76d8bb401e4 100644 --- a/dlls/joy.cpl/joy.rc +++ b/dlls/joy.cpl/joy.rc @@ -57,9 +57,9 @@ FONT 8, "Ms Shell Dlg" COMBOBOX IDC_DI_DEVICES, 15, 10, 291, 60, CBS_DROPDOWNLIST | CBS_HASSTRINGS GROUPBOX "Axes", IDC_DI_AXES, 15, 30, 214, 60 GROUPBOX "POVs", IDC_DI_POVS, 246, 30, 60, 60 - GROUPBOX "Buttons", IDC_DI_BUTTONS, 15, 100, 291, 70 - LTEXT "Force Feedback Effect", IDC_STATIC, 15, 180, 291, 10 - LISTBOX IDC_DI_EFFECTS, 15, 190, 291, 70, WS_TABSTOP | WS_VSCROLL | LBS_NOTIFY + GROUPBOX "Buttons", IDC_DI_BUTTONS, 15, 100, 291, 86 + LTEXT "Force Feedback Effect", IDC_STATIC, 15, 196, 291, 10 + LISTBOX IDC_DI_EFFECTS, 15, 206, 291, 54, WS_TABSTOP | WS_VSCROLL | LBS_NOTIFY LTEXT "Press any button in the controller to activate the chosen effect. The effect direction can be changed with the controller axis.", IDC_STATIC, 15, 260, 291, 25 } From 09298d0e36b4a7653ed428e79006f39c7a8ecd02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 Feb 2023 11:55:00 +0100 Subject: [PATCH 1129/2777] joy.cpl: Use the DIJOYSTATE2 user data format to support more buttons. (cherry picked from commit b4b6c3af7534e0503b147613badf5de9c093c1cd) --- dlls/joy.cpl/dinput.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dlls/joy.cpl/dinput.c b/dlls/joy.cpl/dinput.c index a4aef66e04d..f624e650147 100644 --- a/dlls/joy.cpl/dinput.c +++ b/dlls/joy.cpl/dinput.c @@ -236,7 +236,7 @@ static BOOL CALLBACK enum_devices( const DIDEVICEINSTANCEW *instance, void *cont if (!(entry = calloc( 1, sizeof(*entry) ))) return DIENUM_STOP; IDirectInput8_CreateDevice( dinput, &instance->guidInstance, &entry->device, NULL ); - IDirectInputDevice8_SetDataFormat( entry->device, &c_dfDIJoystick ); + IDirectInputDevice8_SetDataFormat( entry->device, &c_dfDIJoystick2 ); IDirectInputDevice8_GetCapabilities( entry->device, &caps ); list_add_tail( &devices, &entry->entry ); @@ -266,7 +266,7 @@ static DWORD WINAPI input_thread( void *param ) while (WaitForMultipleObjects( 2, events, FALSE, INFINITE ) != 0) { IDirectInputEffect *effect; - DIJOYSTATE state = {0}; + DIJOYSTATE2 state = {0}; unsigned int i; SendMessageW( dialog_hwnd, WM_USER, 0, 0 ); @@ -437,7 +437,7 @@ LRESULT CALLBACK test_di_axes_window_proc( HWND hwnd, UINT msg, WPARAM wparam, L { DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; IDirectInputDevice8W *device; - DIJOYSTATE state = {0}; + DIJOYSTATE2 state = {0}; RECT rect, tmp_rect; PAINTSTRUCT paint; HDC hdc; @@ -503,7 +503,7 @@ LRESULT CALLBACK test_di_povs_window_proc( HWND hwnd, UINT msg, WPARAM wparam, L { DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; IDirectInputDevice8W *device; - DIJOYSTATE state = {0}; + DIJOYSTATE2 state = {0}; PAINTSTRUCT paint; RECT rect; HDC hdc; @@ -547,7 +547,7 @@ LRESULT CALLBACK test_di_buttons_window_proc( HWND hwnd, UINT msg, WPARAM wparam DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; UINT i, j, offs, size, step, space = 2; IDirectInputDevice8W *device; - DIJOYSTATE state = {0}; + DIJOYSTATE2 state = {0}; PAINTSTRUCT paint; RECT rect; HDC hdc; From 25420efb04b29acc28981624f3874b29718747f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 11 Feb 2023 11:05:22 +0100 Subject: [PATCH 1130/2777] winebuild: Use .incbin instead of printf for resource data. (cherry picked from commit 0b3f90ab1485d5bd32bd72d41c7fd8213b3b95b9) --- tools/winebuild/res32.c | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/tools/winebuild/res32.c b/tools/winebuild/res32.c index 80890f55458..6c007da2e1c 100644 --- a/tools/winebuild/res32.c +++ b/tools/winebuild/res32.c @@ -44,6 +44,8 @@ struct resource { struct string_id type; struct string_id name; + const char *input_name; + unsigned int input_offset; const void *data; unsigned int data_size; unsigned int data_offset; @@ -156,28 +158,6 @@ static void put_string( const struct string_id *str ) } } -static void dump_res_data( const struct resource *res ) -{ - unsigned int i = 0; - unsigned int size = (res->data_size + 3) & ~3; - - if (!size) return; - - input_buffer = res->data; - input_buffer_pos = 0; - input_buffer_size = size; - - output( "\t.long " ); - while (size > 4) - { - if ((i++ % 16) == 15) output( "0x%08x\n\t.long ", get_dword() ); - else output( "0x%08x,", get_dword() ); - size -= 4; - } - output( "0x%08x\n", get_dword() ); - assert( input_buffer_pos == input_buffer_size ); -} - /* check the file header */ /* all values must be zero except header size */ static int check_header(void) @@ -199,7 +179,7 @@ static int check_header(void) } /* load the next resource from the current file */ -static void load_next_resource( DLLSPEC *spec ) +static void load_next_resource( DLLSPEC *spec, const char *name ) { unsigned int hdr_size; struct resource *res = add_resource( spec ); @@ -209,6 +189,9 @@ static void load_next_resource( DLLSPEC *spec ) if (hdr_size & 3) fatal_error( "%s header size not aligned\n", input_buffer_filename ); if (hdr_size < 32) fatal_error( "%s invalid header size %u\n", input_buffer_filename, hdr_size ); + res->input_name = xstrdup( name ); + res->input_offset = input_buffer_pos - 2*sizeof(unsigned int) + hdr_size; + res->data = input_buffer + input_buffer_pos - 2*sizeof(unsigned int) + hdr_size; if ((const unsigned char *)res->data < input_buffer || (const unsigned char *)res->data >= input_buffer + input_buffer_size) @@ -237,7 +220,7 @@ int load_res32_file( const char *name, DLLSPEC *spec ) if ((ret = check_header())) { - while (input_buffer_pos < input_buffer_size) load_next_resource( spec ); + while (input_buffer_pos < input_buffer_size) load_next_resource( spec, name ); } return ret; } @@ -490,7 +473,7 @@ void output_resources( DLLSPEC *spec ) { output( "\n\t.align %d\n", get_alignment(4) ); output( ".L__wine_spec_res_%d:\n", i ); - dump_res_data( res ); + output( "\t.incbin \"%s\",%d,%d\n", res->input_name, res->input_offset, res->data_size ); } if (!is_pe()) From 9da67b7330b677700d589a2fba88f6a406a9dadc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 12 Feb 2023 00:25:29 +0100 Subject: [PATCH 1131/2777] dinput: Split dinput_unacquire_window_devices helper. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54431 (cherry picked from commit 7f9fb63aec7f00e73b3c0756d48947059c2b1797) --- dlls/dinput/dinput_main.c | 52 +++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 746b2c0b68e..4da4bc96bdb 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -163,40 +163,50 @@ static void dinput_unacquire_window_devices( HWND window ) LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_device_list, struct dinput_device, entry ) { - if (!window || window == impl->win) - { - TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); - } + if (window != impl->win) continue; + TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); } LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_mouse_list, struct dinput_device, entry ) { - if (!window || window == impl->win) - { - TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); - } + if (window != impl->win) continue; + TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); } LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_rawmouse_list, struct dinput_device, entry ) { - if (!window || window == impl->win) - { - TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); - } + if (window != impl->win) continue; + TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); } LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_keyboard_list, struct dinput_device, entry ) { - if (!window || window == impl->win) - { - TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); - } + if (window != impl->win) continue; + TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); } LeaveCriticalSection( &dinput_hook_crit ); } +static void dinput_unacquire_devices(void) +{ + struct dinput_device *impl, *next; + + EnterCriticalSection( &dinput_hook_crit ); + + LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_device_list, struct dinput_device, entry ) + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); + LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_mouse_list, struct dinput_device, entry ) + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); + LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_rawmouse_list, struct dinput_device, entry ) + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); + LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_keyboard_list, struct dinput_device, entry ) + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); + + LeaveCriticalSection( &dinput_hook_crit ); +} + static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam ) { CWPSTRUCT *msg = (CWPSTRUCT *)lparam; @@ -390,7 +400,7 @@ static DWORD WINAPI dinput_thread_proc( void *params ) if (state.running) { ERR( "Unexpected termination, ret %#lx\n", ret ); - dinput_unacquire_window_devices( 0 ); + dinput_unacquire_devices(); } while (state.devices_count--) dinput_device_internal_release( state.devices[state.devices_count] ); From 4a27f24f461c1ee6fcf340e030102ee561670667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 13 Feb 2023 23:42:45 +0100 Subject: [PATCH 1132/2777] dinput: Name input thread message and wparam values. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54431 (cherry picked from commit 20a835a20beb9baa3d09e8123ca4f715f16265aa) --- dlls/dinput/dinput_main.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 4da4bc96bdb..baf377a9394 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -49,6 +49,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); #define INPUT_THREAD_MAX_DEVICES 128 +#define INPUT_THREAD_NOTIFY (WM_USER + 0x10) +#define NOTIFY_THREAD_STOP 0 +#define NOTIFY_REFRESH_DEVICES 1 + struct input_thread_state { BOOL running; @@ -101,7 +105,7 @@ void dinput_hooks_acquire_device( IDirectInputDevice8W *iface ) list_add_tail( &acquired_device_list, &impl->entry ); LeaveCriticalSection( &dinput_hook_crit ); - SendMessageW( di_em_win, WM_USER + 0x10, 1, 0 ); + SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_REFRESH_DEVICES, 0 ); } void dinput_hooks_unacquire_device( IDirectInputDevice8W *iface ) @@ -112,7 +116,7 @@ void dinput_hooks_unacquire_device( IDirectInputDevice8W *iface ) list_remove( &impl->entry ); LeaveCriticalSection( &dinput_hook_crit ); - SendMessageW( di_em_win, WM_USER + 0x10, 1, 0 ); + SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_REFRESH_DEVICES, 0 ); } static void dinput_device_internal_unacquire( IDirectInputDevice8W *iface, DWORD status ) @@ -324,15 +328,19 @@ static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPAR } } - if (msg == WM_USER + 0x10) + if (msg == INPUT_THREAD_NOTIFY) { TRACE( "Processing hook change notification wparam %#Ix, lparam %#Ix.\n", wparam, lparam ); - if (!wparam) state->running = FALSE; - else + switch (wparam) { + case NOTIFY_THREAD_STOP: + state->running = FALSE; + break; + case NOTIFY_REFRESH_DEVICES: while (state->devices_count--) dinput_device_internal_release( state->devices[state->devices_count] ); input_thread_update_device_list( state ); + break; } return 0; @@ -440,7 +448,7 @@ void input_thread_remove_user(void) { TRACE( "Stopping input thread.\n" ); - SendMessageW( di_em_win, WM_USER + 0x10, 0, 0 ); + SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_THREAD_STOP, 0 ); WaitForSingleObject( dinput_thread, INFINITE ); CloseHandle( dinput_thread ); } From 9240d98ff4476770c24ac8174a6e945789e68df2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 13 Feb 2023 23:43:09 +0100 Subject: [PATCH 1133/2777] dinput: Use a WH_CBT hook instead of WH_CALLWNDPROC. WH_CALLWNDPROC hooks are called on every message, but we only need it for the activation messages. WH_CBT hooks are called for a few events only, which is much lighter, as we need to use a global hook to track windows which belong to any other thread. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54431 (cherry picked from commit b3aea08c319f4b52afba141d10a0dfac92880c15) --- dlls/dinput/dinput_main.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index baf377a9394..ac50e1bd429 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -52,6 +52,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); #define INPUT_THREAD_NOTIFY (WM_USER + 0x10) #define NOTIFY_THREAD_STOP 0 #define NOTIFY_REFRESH_DEVICES 1 +#define NOTIFY_FOREGROUND_LOST 2 struct input_thread_state { @@ -211,15 +212,14 @@ static void dinput_unacquire_devices(void) LeaveCriticalSection( &dinput_hook_crit ); } -static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam ) +static LRESULT CALLBACK cbt_hook_proc( int code, WPARAM wparam, LPARAM lparam ) { - CWPSTRUCT *msg = (CWPSTRUCT *)lparam; - - if (code != HC_ACTION || (msg->message != WM_KILLFOCUS && - msg->message != WM_ACTIVATEAPP && msg->message != WM_ACTIVATE)) - return CallNextHookEx( 0, code, wparam, lparam ); - - if (msg->hwnd != GetForegroundWindow()) dinput_unacquire_window_devices( msg->hwnd ); + if (code == HCBT_ACTIVATE && di_em_win) + { + CBTACTIVATESTRUCT *data = (CBTACTIVATESTRUCT *)lparam; + SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_FOREGROUND_LOST, + (LPARAM)data->hWndActive ); + } return CallNextHookEx( 0, code, wparam, lparam ); } @@ -265,7 +265,7 @@ static void input_thread_update_device_list( struct input_thread_state *state ) LeaveCriticalSection( &dinput_hook_crit ); if (foreground_count && !state->callwndproc_hook) - state->callwndproc_hook = SetWindowsHookExW( WH_CALLWNDPROC, callwndproc_proc, DINPUT_instance, GetCurrentThreadId() ); + state->callwndproc_hook = SetWindowsHookExW( WH_CBT, cbt_hook_proc, DINPUT_instance, 0 ); else if (!foreground_count && state->callwndproc_hook) { UnhookWindowsHookEx( state->callwndproc_hook ); @@ -341,6 +341,9 @@ static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPAR while (state->devices_count--) dinput_device_internal_release( state->devices[state->devices_count] ); input_thread_update_device_list( state ); break; + case NOTIFY_FOREGROUND_LOST: + dinput_unacquire_window_devices( (HWND)lparam ); + break; } return 0; From efce8e09e1d5406a0aee659330adc34f65069e40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 5 Feb 2022 14:00:00 +0100 Subject: [PATCH 1134/2777] dinput: Introduce keyboard_handle_key_event helper. (cherry picked from commit 2d6776e82e3597a87cd41074e7bea79f17492a9d) --- dlls/dinput/keyboard.c | 47 ++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/dlls/dinput/keyboard.c b/dlls/dinput/keyboard.c index 873a2d98434..6c24ddcf24b 100644 --- a/dlls/dinput/keyboard.c +++ b/dlls/dinput/keyboard.c @@ -83,22 +83,13 @@ static BYTE map_dik_code(DWORD scanCode, DWORD vkCode, DWORD subType, DWORD vers return (BYTE)scanCode; } -int dinput_keyboard_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lparam ) +static void keyboard_handle_event( struct keyboard *impl, DWORD vkey, DWORD scan_code, BOOL up ) { - struct keyboard *impl = impl_from_IDirectInputDevice8W( iface ); BYTE new_diks, subtype = GET_DIDEVICE_SUBTYPE( impl->base.instance.dwDevType ); - int dik_code, ret = impl->base.dwCoopLevel & DISCL_EXCLUSIVE; - KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam; - DWORD scan_code; - - if (wparam != WM_KEYDOWN && wparam != WM_KEYUP && - wparam != WM_SYSKEYDOWN && wparam != WM_SYSKEYUP) - return 0; + IDirectInputDevice8W *iface = &impl->base.IDirectInputDevice8W_iface; + int dik_code; - TRACE( "iface %p, wparam %#Ix, lparam %#Ix, vkCode %#lx, scanCode %#lx.\n", iface, wparam, - lparam, hook->vkCode, hook->scanCode ); - - switch (hook->vkCode) + switch (vkey) { /* R-Shift is special - it is an extended key with separate scan code */ case VK_RSHIFT : dik_code = DIK_RSHIFT; break; @@ -106,25 +97,41 @@ int dinput_keyboard_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lpa case VK_NUMLOCK : dik_code = DIK_NUMLOCK; break; case VK_SUBTRACT: dik_code = DIK_SUBTRACT; break; default: - scan_code = hook->scanCode & 0xff; - if (hook->flags & LLKHF_EXTENDED) scan_code |= 0x100; - dik_code = map_dik_code( scan_code, hook->vkCode, subtype, impl->base.dinput->dwVersion ); + dik_code = map_dik_code( scan_code, vkey, subtype, impl->base.dinput->dwVersion ); + break; } - new_diks = hook->flags & LLKHF_UP ? 0 : 0x80; + new_diks = (up ? 0 : 0x80); /* returns now if key event already known */ - if (new_diks == impl->base.device_state[dik_code]) return ret; + if (new_diks == impl->base.device_state[dik_code]) return; impl->base.device_state[dik_code] = new_diks; - TRACE( " setting key %02x to %02x\n", dik_code, impl->base.device_state[dik_code] ); + TRACE( "setting key %02x to %02x\n", dik_code, impl->base.device_state[dik_code] ); EnterCriticalSection( &impl->base.crit ); queue_event( iface, DIDFT_MAKEINSTANCE( dik_code ) | DIDFT_PSHBUTTON, new_diks, GetCurrentTime(), impl->base.dinput->evsequence++ ); if (impl->base.hEvent) SetEvent( impl->base.hEvent ); LeaveCriticalSection( &impl->base.crit ); +} + +int dinput_keyboard_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lparam ) +{ + struct keyboard *impl = impl_from_IDirectInputDevice8W( iface ); + KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam; + DWORD scan_code; + + TRACE( "iface %p, wparam %#Ix, lparam %#Ix, vkCode %#lx, scanCode %#lx.\n", iface, wparam, + lparam, hook->vkCode, hook->scanCode ); + + if (wparam != WM_KEYDOWN && wparam != WM_KEYUP && wparam != WM_SYSKEYDOWN && wparam != WM_SYSKEYUP) + return 0; + + scan_code = hook->scanCode & 0xff; + if (hook->flags & LLKHF_EXTENDED) scan_code |= 0x100; + keyboard_handle_event( impl, hook->vkCode, scan_code, hook->flags & LLKHF_UP ); - return ret; + return impl->base.dwCoopLevel & DISCL_EXCLUSIVE; } static DWORD get_keyboard_subtype(void) From a42f0bfb0b2d6f83bff12dbe435324eb4dcb419b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 11 Feb 2023 12:33:58 +0100 Subject: [PATCH 1135/2777] dinput: Avoid entering the hook CS in input_thread_ll_hook_proc. (cherry picked from commit 5c16cda656e1e486f2767acd2d30114abf820820) --- dlls/dinput/dinput_main.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index ac50e1bd429..090e4233876 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -138,24 +138,30 @@ static void dinput_device_internal_unacquire( IDirectInputDevice8W *iface, DWORD static LRESULT CALLBACK input_thread_ll_hook_proc( int code, WPARAM wparam, LPARAM lparam ) { - struct dinput_device *impl; - int skip = 0; + struct input_thread_state *state = input_thread_state; + int i, skip = 0; if (code != HC_ACTION) return CallNextHookEx( 0, code, wparam, lparam ); - EnterCriticalSection( &dinput_hook_crit ); - LIST_FOR_EACH_ENTRY( impl, &acquired_mouse_list, struct dinput_device, entry ) - { - TRACE( "calling dinput_mouse_hook (%p %Ix %Ix)\n", impl, wparam, lparam ); - skip |= dinput_mouse_hook( &impl->IDirectInputDevice8W_iface, wparam, lparam ); - } - LIST_FOR_EACH_ENTRY( impl, &acquired_keyboard_list, struct dinput_device, entry ) + for (i = state->events_count; i < state->devices_count; ++i) { - if (impl->use_raw_input) continue; - TRACE( "calling dinput_keyboard_hook (%p %Ix %Ix)\n", impl, wparam, lparam ); - skip |= dinput_keyboard_hook( &impl->IDirectInputDevice8W_iface, wparam, lparam ); + struct dinput_device *device = state->devices[i]; + if (device->use_raw_input) continue; + if (device->instance.dwDevType & DIDEVTYPE_HID) continue; + switch (GET_DIDEVICE_TYPE( device->instance.dwDevType )) + { + case DIDEVTYPE_MOUSE: + case DI8DEVTYPE_MOUSE: + TRACE( "calling dinput_mouse_hook (%p %Ix %Ix)\n", device, wparam, lparam ); + skip |= dinput_mouse_hook( &device->IDirectInputDevice8W_iface, wparam, lparam ); + break; + case DIDEVTYPE_KEYBOARD: + case DI8DEVTYPE_KEYBOARD: + TRACE( "calling dinput_keyboard_hook (%p %Ix %Ix)\n", device, wparam, lparam ); + skip |= dinput_keyboard_hook( &device->IDirectInputDevice8W_iface, wparam, lparam ); + break; + } } - LeaveCriticalSection( &dinput_hook_crit ); return skip ? 1 : CallNextHookEx( 0, code, wparam, lparam ); } @@ -248,18 +254,19 @@ static void input_thread_update_device_list( struct input_thread_state *state ) if (device->dwCoopLevel & DISCL_EXCLUSIVE) rawinput_mouse.dwFlags |= RIDEV_NOLEGACY | RIDEV_CAPTUREMOUSE; rawinput_mouse.dwFlags &= ~RIDEV_REMOVE; rawinput_mouse.hwndTarget = di_em_win; - dinput_device_internal_addref( (state->devices[count] = device) ); - if (++count >= INPUT_THREAD_MAX_DEVICES) break; + if (count < INPUT_THREAD_MAX_DEVICES) dinput_device_internal_addref( (state->devices[count++] = device) ); } LIST_FOR_EACH_ENTRY( device, &acquired_mouse_list, struct dinput_device, entry ) { if (device->dwCoopLevel & DISCL_FOREGROUND) foreground_count++; mouse_count++; + if (count < INPUT_THREAD_MAX_DEVICES) dinput_device_internal_addref( (state->devices[count++] = device) ); } LIST_FOR_EACH_ENTRY( device, &acquired_keyboard_list, struct dinput_device, entry ) { if (device->dwCoopLevel & DISCL_FOREGROUND) foreground_count++; keyboard_count++; + if (count < INPUT_THREAD_MAX_DEVICES) dinput_device_internal_addref( (state->devices[count++] = device) ); } state->devices_count = count; LeaveCriticalSection( &dinput_hook_crit ); From e7a409b311fdf9d08fd45f11ab382da00f0b6aad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 11 Feb 2023 12:36:26 +0100 Subject: [PATCH 1136/2777] dinput: Merge mouse and rawmouse acquired lists. (cherry picked from commit 6e0dd0d8b11be3acfaf36416e191cb2c4c53652a) --- dlls/dinput/dinput_main.c | 47 ++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 090e4233876..91565f3da60 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -89,7 +89,6 @@ static CRITICAL_SECTION_DEBUG dinput_critsect_debug = static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0, 0 }; static struct list acquired_mouse_list = LIST_INIT( acquired_mouse_list ); -static struct list acquired_rawmouse_list = LIST_INIT( acquired_rawmouse_list ); static struct list acquired_keyboard_list = LIST_INIT( acquired_keyboard_list ); static struct list acquired_device_list = LIST_INIT( acquired_device_list ); @@ -99,7 +98,7 @@ void dinput_hooks_acquire_device( IDirectInputDevice8W *iface ) EnterCriticalSection( &dinput_hook_crit ); if (IsEqualGUID( &impl->guid, &GUID_SysMouse )) - list_add_tail( impl->use_raw_input ? &acquired_rawmouse_list : &acquired_mouse_list, &impl->entry ); + list_add_tail( &acquired_mouse_list, &impl->entry ); else if (IsEqualGUID( &impl->guid, &GUID_SysKeyboard )) list_add_tail( &acquired_keyboard_list, &impl->entry ); else @@ -184,12 +183,6 @@ static void dinput_unacquire_window_devices( HWND window ) TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); } - LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_rawmouse_list, struct dinput_device, entry ) - { - if (window != impl->win) continue; - TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); - } LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_keyboard_list, struct dinput_device, entry ) { if (window != impl->win) continue; @@ -210,8 +203,6 @@ static void dinput_unacquire_devices(void) dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_mouse_list, struct dinput_device, entry ) dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); - LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_rawmouse_list, struct dinput_device, entry ) - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_keyboard_list, struct dinput_device, entry ) dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); @@ -233,7 +224,7 @@ static LRESULT CALLBACK cbt_hook_proc( int code, WPARAM wparam, LPARAM lparam ) static void input_thread_update_device_list( struct input_thread_state *state ) { RAWINPUTDEVICE rawinput_mouse = {.usUsagePage = HID_USAGE_PAGE_GENERIC, .usUsage = HID_USAGE_GENERIC_MOUSE, .dwFlags = RIDEV_REMOVE}; - UINT count = 0, keyboard_count = 0, mouse_count = 0, foreground_count = 0; + UINT count = 0, keyboard_count = 0, mouse_ll_count = 0, foreground_count = 0; struct dinput_device *device; EnterCriticalSection( &dinput_hook_crit ); @@ -247,19 +238,29 @@ static void input_thread_update_device_list( struct input_thread_state *state ) } state->events_count = count; - LIST_FOR_EACH_ENTRY( device, &acquired_rawmouse_list, struct dinput_device, entry ) - { - if (device->dwCoopLevel & DISCL_FOREGROUND) foreground_count++; - if (device->dwCoopLevel & DISCL_BACKGROUND) rawinput_mouse.dwFlags |= RIDEV_INPUTSINK; - if (device->dwCoopLevel & DISCL_EXCLUSIVE) rawinput_mouse.dwFlags |= RIDEV_NOLEGACY | RIDEV_CAPTUREMOUSE; - rawinput_mouse.dwFlags &= ~RIDEV_REMOVE; - rawinput_mouse.hwndTarget = di_em_win; - if (count < INPUT_THREAD_MAX_DEVICES) dinput_device_internal_addref( (state->devices[count++] = device) ); - } LIST_FOR_EACH_ENTRY( device, &acquired_mouse_list, struct dinput_device, entry ) { + RAWINPUTDEVICE *rawinput_device = NULL; if (device->dwCoopLevel & DISCL_FOREGROUND) foreground_count++; - mouse_count++; + + switch (GET_DIDEVICE_TYPE( device->instance.dwDevType )) + { + case DIDEVTYPE_MOUSE: + case DI8DEVTYPE_MOUSE: + if (device->dwCoopLevel & DISCL_EXCLUSIVE) rawinput_mouse.dwFlags |= RIDEV_CAPTUREMOUSE; + if (!device->use_raw_input) mouse_ll_count++; + else rawinput_device = &rawinput_mouse; + break; + } + + if (rawinput_device) + { + if (device->dwCoopLevel & DISCL_BACKGROUND) rawinput_device->dwFlags |= RIDEV_INPUTSINK; + if (device->dwCoopLevel & DISCL_EXCLUSIVE) rawinput_device->dwFlags |= RIDEV_NOLEGACY; + rawinput_device->dwFlags &= ~RIDEV_REMOVE; + rawinput_device->hwndTarget = di_em_win; + } + if (count < INPUT_THREAD_MAX_DEVICES) dinput_device_internal_addref( (state->devices[count++] = device) ); } LIST_FOR_EACH_ENTRY( device, &acquired_keyboard_list, struct dinput_device, entry ) @@ -287,9 +288,9 @@ static void input_thread_update_device_list( struct input_thread_state *state ) state->keyboard_ll_hook = NULL; } - if (mouse_count && !state->mouse_ll_hook) + if (mouse_ll_count && !state->mouse_ll_hook) state->mouse_ll_hook = SetWindowsHookExW( WH_MOUSE_LL, input_thread_ll_hook_proc, DINPUT_instance, 0 ); - else if (!mouse_count && state->mouse_ll_hook) + else if (!mouse_ll_count && state->mouse_ll_hook) { UnhookWindowsHookEx( state->mouse_ll_hook ); state->mouse_ll_hook = NULL; From 3c875c25444392751141bf0ca4af87506d1ed537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 12 Feb 2023 00:38:54 +0100 Subject: [PATCH 1137/2777] dinput: Merge all acquired device lists together. This is no longer needed as an optimization. (cherry picked from commit a75e0d062236db2dafad44f3de3f0d3ac2120834) --- dlls/dinput/dinput_main.c | 45 +++++++++------------------------------ 1 file changed, 10 insertions(+), 35 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 91565f3da60..f6d93840329 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -88,8 +88,6 @@ static CRITICAL_SECTION_DEBUG dinput_critsect_debug = }; static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0, 0 }; -static struct list acquired_mouse_list = LIST_INIT( acquired_mouse_list ); -static struct list acquired_keyboard_list = LIST_INIT( acquired_keyboard_list ); static struct list acquired_device_list = LIST_INIT( acquired_device_list ); void dinput_hooks_acquire_device( IDirectInputDevice8W *iface ) @@ -97,12 +95,7 @@ void dinput_hooks_acquire_device( IDirectInputDevice8W *iface ) struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); EnterCriticalSection( &dinput_hook_crit ); - if (IsEqualGUID( &impl->guid, &GUID_SysMouse )) - list_add_tail( &acquired_mouse_list, &impl->entry ); - else if (IsEqualGUID( &impl->guid, &GUID_SysKeyboard )) - list_add_tail( &acquired_keyboard_list, &impl->entry ); - else - list_add_tail( &acquired_device_list, &impl->entry ); + list_add_tail( &acquired_device_list, &impl->entry ); LeaveCriticalSection( &dinput_hook_crit ); SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_REFRESH_DEVICES, 0 ); @@ -177,18 +170,6 @@ static void dinput_unacquire_window_devices( HWND window ) TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); } - LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_mouse_list, struct dinput_device, entry ) - { - if (window != impl->win) continue; - TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); - } - LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_keyboard_list, struct dinput_device, entry ) - { - if (window != impl->win) continue; - TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); - } LeaveCriticalSection( &dinput_hook_crit ); } @@ -201,10 +182,6 @@ static void dinput_unacquire_devices(void) LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_device_list, struct dinput_device, entry ) dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); - LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_mouse_list, struct dinput_device, entry ) - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); - LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_keyboard_list, struct dinput_device, entry ) - dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); LeaveCriticalSection( &dinput_hook_crit ); } @@ -224,7 +201,7 @@ static LRESULT CALLBACK cbt_hook_proc( int code, WPARAM wparam, LPARAM lparam ) static void input_thread_update_device_list( struct input_thread_state *state ) { RAWINPUTDEVICE rawinput_mouse = {.usUsagePage = HID_USAGE_PAGE_GENERIC, .usUsage = HID_USAGE_GENERIC_MOUSE, .dwFlags = RIDEV_REMOVE}; - UINT count = 0, keyboard_count = 0, mouse_ll_count = 0, foreground_count = 0; + UINT count = 0, keyboard_ll_count = 0, mouse_ll_count = 0, foreground_count = 0; struct dinput_device *device; EnterCriticalSection( &dinput_hook_crit ); @@ -238,11 +215,11 @@ static void input_thread_update_device_list( struct input_thread_state *state ) } state->events_count = count; - LIST_FOR_EACH_ENTRY( device, &acquired_mouse_list, struct dinput_device, entry ) + LIST_FOR_EACH_ENTRY( device, &acquired_device_list, struct dinput_device, entry ) { RAWINPUTDEVICE *rawinput_device = NULL; - if (device->dwCoopLevel & DISCL_FOREGROUND) foreground_count++; + if (device->read_event && device->vtbl->read) continue; switch (GET_DIDEVICE_TYPE( device->instance.dwDevType )) { case DIDEVTYPE_MOUSE: @@ -251,6 +228,10 @@ static void input_thread_update_device_list( struct input_thread_state *state ) if (!device->use_raw_input) mouse_ll_count++; else rawinput_device = &rawinput_mouse; break; + case DIDEVTYPE_KEYBOARD: + case DI8DEVTYPE_KEYBOARD: + if (!device->use_raw_input) keyboard_ll_count++; + break; } if (rawinput_device) @@ -263,12 +244,6 @@ static void input_thread_update_device_list( struct input_thread_state *state ) if (count < INPUT_THREAD_MAX_DEVICES) dinput_device_internal_addref( (state->devices[count++] = device) ); } - LIST_FOR_EACH_ENTRY( device, &acquired_keyboard_list, struct dinput_device, entry ) - { - if (device->dwCoopLevel & DISCL_FOREGROUND) foreground_count++; - keyboard_count++; - if (count < INPUT_THREAD_MAX_DEVICES) dinput_device_internal_addref( (state->devices[count++] = device) ); - } state->devices_count = count; LeaveCriticalSection( &dinput_hook_crit ); @@ -280,9 +255,9 @@ static void input_thread_update_device_list( struct input_thread_state *state ) state->callwndproc_hook = NULL; } - if (keyboard_count && !state->keyboard_ll_hook) + if (keyboard_ll_count && !state->keyboard_ll_hook) state->keyboard_ll_hook = SetWindowsHookExW( WH_KEYBOARD_LL, input_thread_ll_hook_proc, DINPUT_instance, 0 ); - else if (!keyboard_count && state->keyboard_ll_hook) + else if (!keyboard_ll_count && state->keyboard_ll_hook) { UnhookWindowsHookEx( state->keyboard_ll_hook ); state->keyboard_ll_hook = NULL; From 0ac7482e9dff8877f6dc55469285021f74e916ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 11 Feb 2023 12:41:55 +0100 Subject: [PATCH 1138/2777] dinput: Use rawinput interface for keyboard device. (cherry picked from commit aa7a6b8f4284bb654c657828271a0383f652801c) --- dlls/dinput/dinput_main.c | 17 ++++++++++++++++- dlls/dinput/dinput_private.h | 2 ++ dlls/dinput/keyboard.c | 15 +++++++++++++++ dlls/dinput/tests/device8.c | 11 ----------- 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index f6d93840329..49ae59e76a5 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -200,6 +200,7 @@ static LRESULT CALLBACK cbt_hook_proc( int code, WPARAM wparam, LPARAM lparam ) static void input_thread_update_device_list( struct input_thread_state *state ) { + RAWINPUTDEVICE rawinput_keyboard = {.usUsagePage = HID_USAGE_PAGE_GENERIC, .usUsage = HID_USAGE_GENERIC_KEYBOARD, .dwFlags = RIDEV_REMOVE}; RAWINPUTDEVICE rawinput_mouse = {.usUsagePage = HID_USAGE_PAGE_GENERIC, .usUsage = HID_USAGE_GENERIC_MOUSE, .dwFlags = RIDEV_REMOVE}; UINT count = 0, keyboard_ll_count = 0, mouse_ll_count = 0, foreground_count = 0; struct dinput_device *device; @@ -230,7 +231,9 @@ static void input_thread_update_device_list( struct input_thread_state *state ) break; case DIDEVTYPE_KEYBOARD: case DI8DEVTYPE_KEYBOARD: + if (device->dwCoopLevel & DISCL_EXCLUSIVE) rawinput_keyboard.dwFlags |= RIDEV_NOHOTKEYS; if (!device->use_raw_input) keyboard_ll_count++; + else rawinput_device = &rawinput_keyboard; break; } @@ -274,8 +277,12 @@ static void input_thread_update_device_list( struct input_thread_state *state ) if (!rawinput_mouse.hwndTarget != !state->rawinput_devices[0].hwndTarget && !RegisterRawInputDevices( &rawinput_mouse, 1, sizeof(RAWINPUTDEVICE) )) WARN( "Failed to (un)register rawinput mouse device.\n" ); + if (!rawinput_keyboard.hwndTarget != !state->rawinput_devices[1].hwndTarget && + !RegisterRawInputDevices( &rawinput_keyboard, 1, sizeof(RAWINPUTDEVICE) )) + WARN( "Failed to (un)register rawinput mouse device.\n" ); state->rawinput_devices[0] = rawinput_mouse; + state->rawinput_devices[1] = rawinput_keyboard; } static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) @@ -292,7 +299,9 @@ static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPAR size = GetRawInputData( (HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER) ); if (size == (UINT)-1 || size < sizeof(RAWINPUTHEADER)) WARN( "Unable to read raw input data\n" ); - else if (ri.header.dwType == RIM_TYPEMOUSE) + else if (ri.header.dwType == RIM_TYPEHID) + WARN( "Unexpected HID rawinput message\n" ); + else { for (i = state->events_count; i < state->devices_count; ++i) { @@ -303,8 +312,14 @@ static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPAR { case DIDEVTYPE_MOUSE: case DI8DEVTYPE_MOUSE: + if (ri.header.dwType != RIM_TYPEMOUSE) break; dinput_mouse_rawinput_hook( &device->IDirectInputDevice8W_iface, wparam, lparam, &ri ); break; + case DIDEVTYPE_KEYBOARD: + case DI8DEVTYPE_KEYBOARD: + if (ri.header.dwType != RIM_TYPEKEYBOARD) break; + dinput_keyboard_rawinput_hook( &device->IDirectInputDevice8W_iface, wparam, lparam, &ri ); + break; default: break; } } diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h index 4a54fb57df8..b12936e750f 100644 --- a/dlls/dinput/dinput_private.h +++ b/dlls/dinput/dinput_private.h @@ -74,6 +74,8 @@ extern int dinput_mouse_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM extern int dinput_keyboard_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lparam ); extern void dinput_mouse_rawinput_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lparam, RAWINPUT *raw ); +extern void dinput_keyboard_rawinput_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lparam, + RAWINPUT *raw ); extern void check_dinput_events(void) DECLSPEC_HIDDEN; diff --git a/dlls/dinput/keyboard.c b/dlls/dinput/keyboard.c index 6c24ddcf24b..c49796cfa2d 100644 --- a/dlls/dinput/keyboard.c +++ b/dlls/dinput/keyboard.c @@ -115,6 +115,18 @@ static void keyboard_handle_event( struct keyboard *impl, DWORD vkey, DWORD scan LeaveCriticalSection( &impl->base.crit ); } +void dinput_keyboard_rawinput_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lparam, RAWINPUT *ri ) +{ + struct keyboard *impl = impl_from_IDirectInputDevice8W( iface ); + DWORD scan_code; + + TRACE("(%p) wparam %Ix, lparam %Ix\n", iface, wparam, lparam); + + scan_code = ri->data.keyboard.MakeCode & 0xff; + if (ri->data.keyboard.Flags & RI_KEY_E0) scan_code |= 0x100; + keyboard_handle_event( impl, ri->data.keyboard.VKey, scan_code, ri->data.keyboard.Flags & RI_KEY_BREAK ); +} + int dinput_keyboard_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lparam ) { struct keyboard *impl = impl_from_IDirectInputDevice8W( iface ); @@ -189,6 +201,9 @@ HRESULT keyboard_create_device( struct dinput *dinput, const GUID *guid, IDirect impl->base.caps.dwFirmwareRevision = 100; impl->base.caps.dwHardwareRevision = 100; + if (dinput->dwVersion >= 0x0800) + impl->base.use_raw_input = TRUE; + *out = &impl->base.IDirectInputDevice8W_iface; return DI_OK; } diff --git a/dlls/dinput/tests/device8.c b/dlls/dinput/tests/device8.c index 449402621a7..1f29c9af519 100644 --- a/dlls/dinput/tests/device8.c +++ b/dlls/dinput/tests/device8.c @@ -1099,15 +1099,11 @@ static void test_mouse_keyboard(void) raw_devices_count = ARRAY_SIZE(raw_devices); memset(raw_devices, 0, sizeof(raw_devices)); hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); - todo_wine ok(hr == 1, "GetRegisteredRawInputDevices returned %ld, raw_devices_count: %d\n", hr, raw_devices_count); - todo_wine ok(raw_devices[0].usUsagePage == HID_USAGE_PAGE_GENERIC, "got usUsagePage: %x\n", raw_devices[0].usUsagePage); - todo_wine ok(raw_devices[0].usUsage == HID_USAGE_GENERIC_KEYBOARD, "got usUsage: %x\n", raw_devices[0].usUsage); todo_wine ok(raw_devices[0].dwFlags == RIDEV_INPUTSINK, "Unexpected raw device flags: %#lx\n", raw_devices[0].dwFlags); - todo_wine ok(raw_devices[0].hwndTarget != NULL, "Unexpected raw device target: %p\n", raw_devices[0].hwndTarget); hr = IDirectInputDevice8_Unacquire(di_keyboard); ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %#lx\n", hr); @@ -1139,7 +1135,6 @@ static void test_mouse_keyboard(void) ok(raw_devices[0].usUsagePage == HID_USAGE_PAGE_GENERIC, "got usUsagePage: %x\n", raw_devices[0].usUsagePage); ok(raw_devices[0].usUsage == HID_USAGE_GENERIC_MOUSE, "got usUsage: %x\n", raw_devices[0].usUsage); ok(raw_devices[0].dwFlags == RIDEV_INPUTSINK, "Unexpected raw device flags: %#lx\n", raw_devices[0].dwFlags); - todo_wine ok(raw_devices[0].hwndTarget == di_hwnd, "Unexpected raw device target: %p\n", raw_devices[0].hwndTarget); hr = IDirectInputDevice8_Unacquire(di_mouse); ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %#lx\n", hr); @@ -1185,9 +1180,6 @@ static void test_mouse_keyboard(void) ok(raw_devices[1].hwndTarget == hwnd, "Unexpected raw device target: %p\n", raw_devices[1].hwndTarget); ok(raw_devices[2].usUsagePage == HID_USAGE_PAGE_GENERIC, "got usUsagePage: %x\n", raw_devices[1].usUsagePage); ok(raw_devices[2].usUsage == HID_USAGE_GENERIC_KEYBOARD, "got usUsage: %x\n", raw_devices[1].usUsage); - todo_wine - ok(raw_devices[2].dwFlags == RIDEV_INPUTSINK, "Unexpected raw device flags: %#lx\n", raw_devices[1].dwFlags); - todo_wine ok(raw_devices[2].hwndTarget == di_hwnd, "Unexpected raw device target: %p\n", raw_devices[1].hwndTarget); hr = IDirectInputDevice8_Unacquire(di_keyboard); ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %#lx\n", hr); @@ -1195,7 +1187,6 @@ static void test_mouse_keyboard(void) ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %#lx\n", hr); raw_devices_count = ARRAY_SIZE(raw_devices); GetRegisteredRawInputDevices(NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE)); - todo_wine ok(raw_devices_count == 1, "Unexpected raw devices registered: %d\n", raw_devices_count); IDirectInputDevice8_SetCooperativeLevel(di_mouse, hwnd, DISCL_FOREGROUND|DISCL_EXCLUSIVE); @@ -1210,7 +1201,6 @@ static void test_mouse_keyboard(void) hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); ok(hr == 3, "GetRegisteredRawInputDevices returned %ld, raw_devices_count: %d\n", hr, raw_devices_count); ok(raw_devices[0].dwFlags == (RIDEV_CAPTUREMOUSE|RIDEV_NOLEGACY), "Unexpected raw device flags: %#lx\n", raw_devices[0].dwFlags); - todo_wine ok(raw_devices[2].dwFlags == (RIDEV_NOHOTKEYS|RIDEV_NOLEGACY), "Unexpected raw device flags: %#lx\n", raw_devices[1].dwFlags); hr = IDirectInputDevice8_Unacquire(di_keyboard); ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %#lx\n", hr); @@ -1219,7 +1209,6 @@ static void test_mouse_keyboard(void) raw_devices_count = ARRAY_SIZE(raw_devices); hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); - todo_wine ok(hr == 1, "GetRegisteredRawInputDevices returned %ld, raw_devices_count: %d\n", hr, raw_devices_count); ok(raw_devices[0].usUsagePage == HID_USAGE_PAGE_GENERIC, "got usUsagePage: %x\n", raw_devices[0].usUsagePage); ok(raw_devices[0].usUsage == HID_USAGE_GENERIC_GAMEPAD, "got usUsage: %x\n", raw_devices[0].usUsage); From 9397ad5e642ebc0c47019d21ce2183c6e390c0ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 22 Feb 2023 13:21:32 +0100 Subject: [PATCH 1139/2777] include: Move ddk/imm.h to immdev.h. (cherry picked from commit 68ff9a942e899750238c6653fbc38966c7469781) --- dlls/imm32/imm.c | 2 +- dlls/imm32/tests/imm32.c | 2 +- dlls/user32/user_main.c | 2 +- dlls/win32u/imm.c | 2 +- dlls/win32u/message.c | 2 +- dlls/winemac.drv/ime.c | 2 +- dlls/winex11.drv/ime.c | 2 +- include/Makefile.in | 2 +- include/{ddk/imm.h => immdev.h} | 21 +++++++++++++-------- 9 files changed, 21 insertions(+), 16 deletions(-) rename include/{ddk/imm.h => immdev.h} (95%) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 17061ae0034..d7af6d79736 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -33,7 +33,7 @@ #include "winerror.h" #include "wine/debug.h" #include "imm.h" -#include "ddk/imm.h" +#include "immdev.h" #include "winnls.h" #include "winreg.h" #include "wine/list.h" diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 75b5cde6c7b..7042e32fc04 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -25,7 +25,7 @@ #include "winuser.h" #include "wingdi.h" #include "imm.h" -#include "ddk/imm.h" +#include "immdev.h" BOOL WINAPI ImmSetActiveContext(HWND, HIMC, BOOL); diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index 0ddbd710b6b..56d5849f469 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -21,7 +21,7 @@ #include "user_private.h" #include "controls.h" #include "imm.h" -#include "ddk/imm.h" +#include "immdev.h" #include "wine/debug.h" diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index e9d7c699130..db077dbbef0 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -27,7 +27,7 @@ #include #include "win32u_private.h" #include "ntuser_private.h" -#include "ddk/imm.h" +#include "immdev.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(imm); diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 655d10695d9..beaa5bf21bf 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -33,7 +33,7 @@ #include "hidusage.h" #include "dbt.h" #include "dde.h" -#include "ddk/imm.h" +#include "immdev.h" #include "wine/server.h" #include "wine/debug.h" diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index 163980dd691..d52e1fc1a76 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -36,7 +36,7 @@ #include "macdrv_dll.h" #include "imm.h" -#include "ddk/imm.h" +#include "immdev.h" #include "wine/server.h" #include "wine/debug.h" diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 0599159646f..7fe1e0a0b1e 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -43,7 +43,7 @@ #include "x11drv_dll.h" #include "wine/debug.h" #include "imm.h" -#include "ddk/imm.h" +#include "immdev.h" WINE_DEFAULT_DEBUG_CHANNEL(imm); diff --git a/include/Makefile.in b/include/Makefile.in index ff21e9b4d70..44c95a7f47c 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -195,7 +195,6 @@ SOURCES = \ ddk/hidport.h \ ddk/hidsdi.h \ ddk/hidtypes.h \ - ddk/imm.h \ ddk/mountmgr.h \ ddk/ndis.h \ ddk/ntddcdvd.h \ @@ -359,6 +358,7 @@ SOURCES = \ imagehlp.h \ ime.h \ imm.h \ + immdev.h \ imnact.idl \ imnxport.idl \ in6addr.h \ diff --git a/include/ddk/imm.h b/include/immdev.h similarity index 95% rename from include/ddk/imm.h rename to include/immdev.h index bbbd70a596f..994bb44d74f 100644 --- a/include/ddk/imm.h +++ b/include/immdev.h @@ -16,14 +16,15 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#ifndef _DDKIMM_H_ -#define _DDKIMM_H_ +#ifndef __WINE_IMMDEV_H +#define __WINE_IMMDEV_H #ifdef __cplusplus extern "C" { #endif -typedef struct _tagINPUTCONTEXT { +typedef struct tagINPUTCONTEXT +{ HWND hWnd; BOOL fOpen; POINT ptStatusWndPos; @@ -46,7 +47,8 @@ typedef struct _tagINPUTCONTEXT { DWORD dwReserve[3]; } INPUTCONTEXT, *LPINPUTCONTEXT; -typedef struct _tagIMEINFO { +typedef struct tagIMEINFO +{ DWORD dwPrivateDataSize; DWORD fdwProperty; DWORD fdwConversionCaps; @@ -56,7 +58,8 @@ typedef struct _tagIMEINFO { DWORD fdwSelectCaps; } IMEINFO, *LPIMEINFO; -typedef struct tagCOMPOSITIONSTRING { +typedef struct tagCOMPOSITIONSTRING +{ DWORD dwSize; DWORD dwCompReadAttrLen; DWORD dwCompReadAttrOffset; @@ -84,7 +87,8 @@ typedef struct tagCOMPOSITIONSTRING { DWORD dwPrivateOffset; } COMPOSITIONSTRING, *LPCOMPOSITIONSTRING; -typedef struct tagGUIDELINE { +typedef struct tagGUIDELINE +{ DWORD dwSize; DWORD dwLevel; DWORD dwIndex; @@ -94,7 +98,8 @@ typedef struct tagGUIDELINE { DWORD dwPrivateOffset; } GUIDELINE, *LPGUIDELINE; -typedef struct tagCANDIDATEINFO { +typedef struct tagCANDIDATEINFO +{ DWORD dwSize; DWORD dwCount; DWORD dwOffset[32]; @@ -170,4 +175,4 @@ DWORD WINAPI ImeGetImeMenuItems(HIMC, DWORD, DWORD, LPIMEMENUITEMINFOW, LPIMEMEN } /* extern "C" */ #endif -#endif /* _DDKIMM_H_ */ +#endif /* __WINE_IMMDEV_H */ From d0357fd2c24dd495485fcc36518e720d32dc4292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 4 Dec 2022 18:59:10 +0100 Subject: [PATCH 1140/2777] include: Fix ImeInquire declaration. (cherry picked from commit 2fdfe16c2d5a92b1204f929ba8074a7c6574c7cf) --- dlls/imm32/imm.c | 4 ++-- dlls/winemac.drv/ime.c | 2 +- dlls/winex11.drv/ime.c | 3 +-- include/immdev.h | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index d7af6d79736..c4c495e86a5 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -62,7 +62,7 @@ typedef struct _tagImmHkl{ HWND UIWnd; /* Function Pointers */ - BOOL (WINAPI *pImeInquire)(IMEINFO *, WCHAR *, const WCHAR *); + BOOL (WINAPI *pImeInquire)(IMEINFO *, WCHAR *, DWORD); BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *); BOOL (WINAPI *pImeDestroy)(UINT); LRESULT (WINAPI *pImeEscape)(HIMC, UINT, void *); @@ -508,7 +508,7 @@ static ImmHkl *IMM_GetImmHkl(HKL hkl) if (ptr->hIME) { LOAD_FUNCPTR(ImeInquire); - if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, NULL)) + if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, 0)) { FreeLibrary(ptr->hIME); ptr->hIME = NULL; diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index d52e1fc1a76..d8ca684d674 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -1368,7 +1368,7 @@ static BOOL WINAPI register_classes( INIT_ONCE *once, void *param, void **contex return TRUE; } -BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass, LPCWSTR lpszOption) +BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass, DWORD flags) { static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 7fe1e0a0b1e..ef498760a60 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -511,8 +511,7 @@ static void IME_AddToSelected(HIMC hIMC) hSelectedFrom[hSelectedCount-1] = hIMC; } -BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass, - LPCWSTR lpszOption) +BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass, DWORD flags) { static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; diff --git a/include/immdev.h b/include/immdev.h index 994bb44d74f..eb6591d1e74 100644 --- a/include/immdev.h +++ b/include/immdev.h @@ -154,7 +154,7 @@ HWND WINAPI ImmCreateSoftKeyboard(UINT, UINT, int, int); BOOL WINAPI ImmDestroySoftKeyboard(HWND); BOOL WINAPI ImmShowSoftKeyboard(HWND, int); -BOOL WINAPI ImeInquire(LPIMEINFO, LPWSTR, LPCWSTR lpszOptions); +BOOL WINAPI ImeInquire(LPIMEINFO, LPWSTR, DWORD); BOOL WINAPI ImeConfigure (HKL, HWND, DWORD, LPVOID); DWORD WINAPI ImeConversionList(HIMC, LPCWSTR, LPCANDIDATELIST,DWORD,UINT); BOOL WINAPI ImeDestroy(UINT); From e8cc433ba3916775b5da0346a1b833c711a4b5a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 4 Dec 2022 18:59:10 +0100 Subject: [PATCH 1141/2777] include: Fix ImeToAsciiEx declaration. (cherry picked from commit f371309f6d12273c889ebb9d6be1c8bcb613450a) --- dlls/imm32/imm.c | 14 ++++---------- dlls/imm32/tests/imm32.c | 6 ------ dlls/winemac.drv/ime.c | 14 ++++---------- dlls/winex11.drv/ime.c | 8 +------- include/immdev.h | 15 ++++++++++++++- 5 files changed, 23 insertions(+), 34 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index c4c495e86a5..57d00dd4984 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -68,7 +68,7 @@ typedef struct _tagImmHkl{ LRESULT (WINAPI *pImeEscape)(HIMC, UINT, void *); BOOL (WINAPI *pImeSelect)(HIMC, BOOL); BOOL (WINAPI *pImeSetActiveContext)(HIMC, BOOL); - UINT (WINAPI *pImeToAsciiEx)(UINT, UINT, const BYTE *, DWORD *, UINT, HIMC); + UINT (WINAPI *pImeToAsciiEx)(UINT, UINT, const BYTE *, TRANSMSGLIST *, UINT, HIMC); BOOL (WINAPI *pNotifyIME)(HIMC, DWORD, DWORD, DWORD); BOOL (WINAPI *pImeRegisterWord)(const WCHAR *, DWORD, const WCHAR *); BOOL (WINAPI *pImeUnregisterWord)(const WCHAR *, DWORD, const WCHAR *); @@ -97,12 +97,6 @@ typedef struct tagInputContextData #define WINE_IMC_VALID_MAGIC 0x56434D49 -typedef struct _tagTRANSMSG { - UINT message; - WPARAM wParam; - LPARAM lParam; -} TRANSMSG, *LPTRANSMSG; - struct coinit_spy { IInitializeSpy IInitializeSpy_iface; @@ -3004,7 +2998,7 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD HIMC imc = ImmGetContext(hwnd); BYTE state[256]; UINT scancode; - LPVOID list = 0; + TRANSMSGLIST *list = NULL; UINT msg_count; UINT uVirtKey; static const DWORD list_count = 10; @@ -3020,7 +3014,7 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD scancode = lKeyData >> 0x10 & 0xff; list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list_count * sizeof(TRANSMSG) + sizeof(DWORD)); - ((DWORD*)list)[0] = list_count; + list->uMsgCount = list_count; if (data->immKbd->imeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST) { @@ -3040,7 +3034,7 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD if (msg_count && msg_count <= list_count) { UINT i; - LPTRANSMSG msgs = (LPTRANSMSG)((LPBYTE)list + sizeof(DWORD)); + LPTRANSMSG msgs = list->TransMsg; for (i = 0; i < msg_count; i++) ImmInternalPostIMEMessage(data, msgs[i].message, msgs[i].wParam, msgs[i].lParam); diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 7042e32fc04..98af84383ba 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -93,12 +93,6 @@ typedef struct } u; } TEST_INPUT; -typedef struct _tagTRANSMSG { - UINT message; - WPARAM wParam; - LPARAM lParam; -} TRANSMSG, *LPTRANSMSG; - static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t); static LRESULT CALLBACK get_msg_filter(int nCode, WPARAM wParam, LPARAM lParam) diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index d8ca684d674..4bdfcbc6730 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -53,12 +53,6 @@ typedef struct _IMEPRIVATE { UINT repeat; } IMEPRIVATE, *LPIMEPRIVATE; -typedef struct _tagTRANSMSG { - UINT message; - WPARAM wParam; - LPARAM lParam; -} TRANSMSG, *LPTRANSMSG; - static const WCHAR UI_CLASS_NAME[] = {'W','i','n','e',' ','M','a','c',' ','I','M','E',0}; static HIMC *hSelectedFrom = NULL; @@ -455,15 +449,15 @@ static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam, LPARAM lParam UnlockRealIMC(hIMC); } -static BOOL GenerateMessageToTransKey(LPDWORD lpTransBuf, UINT *uNumTranMsgs, +static BOOL GenerateMessageToTransKey(TRANSMSGLIST *lpTransBuf, UINT *uNumTranMsgs, UINT msg, WPARAM wParam, LPARAM lParam) { LPTRANSMSG ptr; - if (*uNumTranMsgs + 1 >= (UINT)*lpTransBuf) + if (*uNumTranMsgs + 1 >= lpTransBuf->uMsgCount) return FALSE; - ptr = (LPTRANSMSG)(lpTransBuf + 1 + *uNumTranMsgs * 3); + ptr = lpTransBuf->TransMsg + *uNumTranMsgs; ptr->message = msg; ptr->wParam = wParam; ptr->lParam = lParam; @@ -653,7 +647,7 @@ BOOL WINAPI ImeSetActiveContext(HIMC hIMC, BOOL fFlag) } UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, - LPDWORD lpdwTransKey, UINT fuState, HIMC hIMC) + TRANSMSGLIST *lpdwTransKey, UINT fuState, HIMC hIMC) { struct process_text_input_params params; UINT vkey; diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index ef498760a60..a293daa6ad9 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -56,12 +56,6 @@ typedef struct _IMEPRIVATE { HWND hwndDefault; } IMEPRIVATE, *LPIMEPRIVATE; -typedef struct _tagTRANSMSG { - UINT message; - WPARAM wParam; - LPARAM lParam; -} TRANSMSG, *LPTRANSMSG; - static const WCHAR UI_CLASS_NAME[] = {'W','i','n','e','X','1','1','I','M','E',0}; static HIMC *hSelectedFrom = NULL; @@ -618,7 +612,7 @@ BOOL WINAPI ImeSetActiveContext(HIMC hIMC,BOOL fFlag) } UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, - LPDWORD lpdwTransKey, UINT fuState, HIMC hIMC) + TRANSMSGLIST *lpdwTransKey, UINT fuState, HIMC hIMC) { /* See the comment at the head of this file */ TRACE("We do no processing via this route\n"); diff --git a/include/immdev.h b/include/immdev.h index eb6591d1e74..350adf00a8b 100644 --- a/include/immdev.h +++ b/include/immdev.h @@ -107,6 +107,19 @@ typedef struct tagCANDIDATEINFO DWORD dwPrivateOffset; } CANDIDATEINFO, *LPCANDIDATEINFO; +typedef struct tagTRANSMSG +{ + UINT message; + WPARAM wParam; + LPARAM lParam; +} TRANSMSG, *LPTRANSMSG; + +typedef struct tagTRANSMSGLIST +{ + UINT uMsgCount; + TRANSMSG TransMsg[1]; +} TRANSMSGLIST, *LPTRANSMSGLIST; + LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC); BOOL WINAPI ImmUnlockIMC(HIMC); DWORD WINAPI ImmGetIMCLockCount(HIMC); @@ -162,7 +175,7 @@ LRESULT WINAPI ImeEscape(HIMC, UINT, LPVOID); BOOL WINAPI ImeProcessKey(HIMC, UINT, LPARAM, const LPBYTE); BOOL WINAPI ImeSelect(HIMC, BOOL); BOOL WINAPI ImeSetActiveContext(HIMC, BOOL); -UINT WINAPI ImeToAsciiEx(UINT, UINT, const LPBYTE, LPDWORD, UINT, HIMC); +UINT WINAPI ImeToAsciiEx(UINT, UINT, const LPBYTE, LPTRANSMSGLIST, UINT, HIMC); BOOL WINAPI NotifyIME(HIMC, DWORD, DWORD, DWORD); BOOL WINAPI ImeRegisterWord(LPCWSTR, DWORD, LPCWSTR); BOOL WINAPI ImeUnregisterWord(LPCWSTR, DWORD, LPCWSTR); From 131363054d3a6e0aadee666f4e044f0334632bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 4 Dec 2022 20:28:15 +0100 Subject: [PATCH 1142/2777] include: Add Imm(Get|Set)HotKey declarations. (cherry picked from commit 333ab2b4d683e253cf0040954794d942d03a57ef) --- dlls/imm32/imm.c | 2 +- include/immdev.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 57d00dd4984..3d9cbf7e198 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3116,7 +3116,7 @@ BOOL WINAPI ImmEnumInputContext(DWORD idThread, IMCENUMPROC lpfn, LPARAM lParam) * ImmGetHotKey(IMM32.@) */ -BOOL WINAPI ImmGetHotKey(DWORD hotkey, UINT *modifiers, UINT *key, HKL hkl) +BOOL WINAPI ImmGetHotKey(DWORD hotkey, UINT *modifiers, UINT *key, HKL *hkl) { FIXME("%lx, %p, %p, %p: stub\n", hotkey, modifiers, key, hkl); return FALSE; diff --git a/include/immdev.h b/include/immdev.h index 350adf00a8b..92f2a47c167 100644 --- a/include/immdev.h +++ b/include/immdev.h @@ -158,6 +158,8 @@ DWORD WINAPI ImmGetIMCCSize(HIMCC); #define NI_SETCANDIDATE_PAGESIZE 0x0017 #define NI_IMEMENUSELECTED 0x0018 +BOOL WINAPI ImmGetHotKey(DWORD,UINT*,UINT*,HKL*); +BOOL WINAPI ImmSetHotKey(DWORD,UINT,UINT,HKL); BOOL WINAPI ImmGenerateMessage(HIMC); LRESULT WINAPI ImmRequestMessageA(HIMC, WPARAM, LPARAM); LRESULT WINAPI ImmRequestMessageW(HIMC, WPARAM, LPARAM); From 5eb16171b0f01ed5f6b18c933834bc4933a18c69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 15 Feb 2023 13:43:26 +0100 Subject: [PATCH 1143/2777] dinput: Forbid acquiring for other process windows. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54431 (cherry picked from commit 7a2d59fb24ae6c6458339f1e8be1a7d160fc5d3c) --- dlls/dinput/device.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index c7b29da9271..c001d1ef29a 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -546,6 +546,7 @@ static HRESULT WINAPI dinput_device_Acquire( IDirectInputDevice8W *iface ) { struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); HRESULT hr = DI_OK; + DWORD pid; TRACE( "iface %p.\n", iface ); @@ -556,6 +557,8 @@ static HRESULT WINAPI dinput_device_Acquire( IDirectInputDevice8W *iface ) hr = DIERR_INVALIDPARAM; else if ((impl->dwCoopLevel & DISCL_FOREGROUND) && impl->win != GetForegroundWindow()) hr = DIERR_OTHERAPPHASPRIO; + else if ((impl->dwCoopLevel & DISCL_FOREGROUND) && (!GetWindowThreadProcessId( impl->win, &pid ) || pid != GetCurrentProcessId())) + hr = DIERR_INVALIDPARAM; else { impl->status = STATUS_ACQUIRED; From 52d2c30b4b0ac9e53dab0e55407cc577632483c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 15 Feb 2023 13:46:49 +0100 Subject: [PATCH 1144/2777] dinput: Hook window threads instead of the entire prefix. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54431 (cherry picked from commit e5c540c59b5642254b6e5731a93d3eeba543be7b) --- dlls/dinput/device_private.h | 1 + dlls/dinput/dinput_main.c | 32 ++++++++++++++++++++------------ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h index f6030c5d088..ebe1b49da2f 100644 --- a/dlls/dinput/device_private.h +++ b/dlls/dinput/device_private.h @@ -95,6 +95,7 @@ struct dinput_device HWND win; enum device_status status; BOOL use_raw_input; /* use raw input instead of low-level messages */ + HHOOK cbt_hook; /* CBT hook to track foreground changes */ LPDIDEVICEOBJECTDATA data_queue; /* buffer for 'GetDeviceData'. */ int queue_len; /* valid size of the queue */ diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 49ae59e76a5..33f98eda120 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -61,7 +61,6 @@ struct input_thread_state UINT devices_count; HHOOK mouse_ll_hook; HHOOK keyboard_ll_hook; - HHOOK callwndproc_hook; RAWINPUTDEVICE rawinput_devices[2]; struct dinput_device *devices[INPUT_THREAD_MAX_DEVICES]; HANDLE events[INPUT_THREAD_MAX_DEVICES]; @@ -112,12 +111,21 @@ void dinput_hooks_unacquire_device( IDirectInputDevice8W *iface ) SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_REFRESH_DEVICES, 0 ); } +static void unhook_device_window_foreground_changes( struct dinput_device *device ) +{ + if (!device->cbt_hook) return; + UnhookWindowsHookEx( device->cbt_hook ); + device->cbt_hook = NULL; +} + static void dinput_device_internal_unacquire( IDirectInputDevice8W *iface, DWORD status ) { struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); TRACE( "iface %p.\n", iface ); + unhook_device_window_foreground_changes( impl ); + EnterCriticalSection( &impl->crit ); if (impl->status == STATUS_ACQUIRED) { @@ -198,17 +206,26 @@ static LRESULT CALLBACK cbt_hook_proc( int code, WPARAM wparam, LPARAM lparam ) return CallNextHookEx( 0, code, wparam, lparam ); } +static void hook_device_window_foreground_changes( struct dinput_device *device ) +{ + DWORD tid, pid; + if (!(tid = GetWindowThreadProcessId( device->win, &pid ))) return; + device->cbt_hook = SetWindowsHookExW( WH_CBT, cbt_hook_proc, DINPUT_instance, tid ); +} + static void input_thread_update_device_list( struct input_thread_state *state ) { RAWINPUTDEVICE rawinput_keyboard = {.usUsagePage = HID_USAGE_PAGE_GENERIC, .usUsage = HID_USAGE_GENERIC_KEYBOARD, .dwFlags = RIDEV_REMOVE}; RAWINPUTDEVICE rawinput_mouse = {.usUsagePage = HID_USAGE_PAGE_GENERIC, .usUsage = HID_USAGE_GENERIC_MOUSE, .dwFlags = RIDEV_REMOVE}; - UINT count = 0, keyboard_ll_count = 0, mouse_ll_count = 0, foreground_count = 0; + UINT count = 0, keyboard_ll_count = 0, mouse_ll_count = 0; struct dinput_device *device; EnterCriticalSection( &dinput_hook_crit ); LIST_FOR_EACH_ENTRY( device, &acquired_device_list, struct dinput_device, entry ) { - if (device->dwCoopLevel & DISCL_FOREGROUND) foreground_count++; + unhook_device_window_foreground_changes( device ); + if (device->dwCoopLevel & DISCL_FOREGROUND) hook_device_window_foreground_changes( device ); + if (!device->read_event || !device->vtbl->read) continue; state->events[count] = device->read_event; dinput_device_internal_addref( (state->devices[count] = device) ); @@ -250,14 +267,6 @@ static void input_thread_update_device_list( struct input_thread_state *state ) state->devices_count = count; LeaveCriticalSection( &dinput_hook_crit ); - if (foreground_count && !state->callwndproc_hook) - state->callwndproc_hook = SetWindowsHookExW( WH_CBT, cbt_hook_proc, DINPUT_instance, 0 ); - else if (!foreground_count && state->callwndproc_hook) - { - UnhookWindowsHookEx( state->callwndproc_hook ); - state->callwndproc_hook = NULL; - } - if (keyboard_ll_count && !state->keyboard_ll_hook) state->keyboard_ll_hook = SetWindowsHookExW( WH_KEYBOARD_LL, input_thread_ll_hook_proc, DINPUT_instance, 0 ); else if (!keyboard_ll_count && state->keyboard_ll_hook) @@ -413,7 +422,6 @@ static DWORD WINAPI dinput_thread_proc( void *params ) } while (state.devices_count--) dinput_device_internal_release( state.devices[state.devices_count] ); - if (state.callwndproc_hook) UnhookWindowsHookEx( state.callwndproc_hook ); if (state.keyboard_ll_hook) UnhookWindowsHookEx( state.keyboard_ll_hook ); if (state.mouse_ll_hook) UnhookWindowsHookEx( state.mouse_ll_hook ); DestroyWindow( di_em_win ); From 2b12908fc9d9dddf1c47fb83889483ab66f849ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Oct 2021 14:47:24 +0200 Subject: [PATCH 1145/2777] user32: Translate WM_POINTER* messages to WM_TOUCH in DefWindowProc. CW-Bug-Id: #18214 --- dlls/user32/input.c | 9 --------- dlls/user32/user32.spec | 2 +- dlls/win32u/defwnd.c | 32 ++++++++++++++++++++++++++++++++ dlls/win32u/input.c | 9 +++++++++ dlls/win32u/syscall.c | 1 + dlls/win32u/win32u.spec | 2 +- include/ntuser.h | 1 + 7 files changed, 45 insertions(+), 11 deletions(-) diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 3b0a13842c8..883377c1279 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -663,15 +663,6 @@ BOOL WINAPI GetTouchInputInfo( HTOUCHINPUT handle, UINT count, TOUCHINPUT *ptr, return FALSE; } -/********************************************************************** - * IsTouchWindow (USER32.@) - */ -BOOL WINAPI IsTouchWindow( HWND hwnd, ULONG *flags ) -{ - FIXME( "hwnd %p, flags %p stub!\n", hwnd, flags ); - return FALSE; -} - /***************************************************************************** * RegisterTouchWindow (USER32.@) */ diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 38462607ccd..a3c950da87d 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -479,7 +479,7 @@ @ stdcall IsProcessDPIAware() @ stdcall IsRectEmpty(ptr) # @ stub IsServerSideWindow -@ stdcall IsTouchWindow(long ptr) +@ stdcall IsTouchWindow(long ptr) NtUserIsTouchWindow @ stdcall IsValidDpiAwarenessContext(long) @ stdcall IsWinEventHookInstalled(long) @ stdcall IsWindow(long) diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c index 85cdc61be1c..76779974cfb 100644 --- a/dlls/win32u/defwnd.c +++ b/dlls/win32u/defwnd.c @@ -30,6 +30,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); +#define WINE_MOUSE_HANDLE ((HANDLE)1) +#define WINE_KEYBOARD_HANDLE ((HANDLE)2) #define DRAG_FILE 0x454c4946 @@ -2943,6 +2945,36 @@ LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, 0, NtUserSendMessage, ansi ); } break; + + case WM_POINTERDOWN: + case WM_POINTERUP: + case WM_POINTERUPDATE: + { + TOUCHINPUT touchinput; + + if (!NtUserIsTouchWindow( hwnd, NULL )) return 0; + touchinput.x = LOWORD( lparam ) * 100; + touchinput.y = HIWORD( lparam ) * 100; + touchinput.hSource = WINE_MOUSE_HANDLE; + touchinput.dwID = GET_POINTERID_WPARAM( wparam ); + touchinput.dwFlags = TOUCHEVENTF_NOCOALESCE | TOUCHEVENTF_PALM; + if (msg == WM_POINTERDOWN) touchinput.dwFlags |= TOUCHEVENTF_DOWN; + if (msg == WM_POINTERUP) touchinput.dwFlags |= TOUCHEVENTF_UP; + if (msg == WM_POINTERUPDATE) touchinput.dwFlags |= TOUCHEVENTF_MOVE; + if (IS_POINTER_PRIMARY_WPARAM( wparam )) touchinput.dwFlags |= TOUCHEVENTF_PRIMARY; + touchinput.dwMask = 0; + touchinput.dwTime = NtGetTickCount(); + touchinput.dwExtraInfo = 0; + touchinput.cxContact = 0; + touchinput.cyContact = 0; + + send_message( hwnd, WM_TOUCH, MAKELONG( 1, 0 ), (LPARAM)&touchinput ); + break; + } + + case WM_TOUCH: + /* FIXME: CloseTouchInputHandle( (HTOUCHINPUT)lparam ); */ + return 0; } return result; diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 3803870bfba..1ffad046cbf 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2443,6 +2443,15 @@ BOOL WINAPI NtUserIsMouseInPointerEnabled(void) return FALSE; } +/********************************************************************** + * NtUserIsTouchWindow (win32u.@) + */ +BOOL WINAPI NtUserIsTouchWindow( HWND hwnd, ULONG *flags ) +{ + FIXME( "hwnd %p, flags %p stub!\n", hwnd, flags ); + return FALSE; +} + /********************************************************************** * NtUserGetPointerInfoList (win32u.@) */ diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index 9020aa01126..49ce3943444 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -224,6 +224,7 @@ static void * const syscalls[] = NtUserInvalidateRgn, NtUserIsClipboardFormatAvailable, NtUserIsMouseInPointerEnabled, + NtUserIsTouchWindow, NtUserKillTimer, NtUserLockWindowUpdate, NtUserLogicalToPerMonitorDPIPhysicalPoint, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 6e1a0a51175..b7311009ffa 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1056,7 +1056,7 @@ @ stub NtUserIsNonClientDpiScalingEnabled @ stub NtUserIsResizeLayoutSynchronizationEnabled @ stub NtUserIsTopLevelWindow -@ stub NtUserIsTouchWindow +@ stdcall -syscall NtUserIsTouchWindow(long ptr) @ stub NtUserIsWindowBroadcastingDpiToChildren @ stub NtUserIsWindowGDIScaledDpiMessageEnabled @ stdcall -syscall NtUserKillTimer(long long) diff --git a/include/ntuser.h b/include/ntuser.h index b383e97e726..daa52d3cb57 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -795,6 +795,7 @@ BOOL WINAPI NtUserIsClipboardFormatAvailable( UINT format ); BOOL WINAPI NtUserIsMouseInPointerEnabled(void); BOOL WINAPI NtUserInvalidateRect( HWND hwnd, const RECT *rect, BOOL erase ); BOOL WINAPI NtUserInvalidateRgn( HWND hwnd, HRGN hrgn, BOOL erase ); +BOOL WINAPI NtUserIsTouchWindow( HWND hwnd, ULONG *flags ); BOOL WINAPI NtUserKillTimer( HWND hwnd, UINT_PTR id ); BOOL WINAPI NtUserLockWindowUpdate( HWND hwnd ); BOOL WINAPI NtUserLogicalToPerMonitorDPIPhysicalPoint( HWND hwnd, POINT *pt ); From cafe7a0c15fcbe65a6cb6175be6c1363c1198c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Nov 2022 08:45:36 +0100 Subject: [PATCH 1146/2777] user32: Implement semi-stub touch input support. CW-Bug-Id: #18214 --- dlls/user32/input.c | 21 +++++++++------------ dlls/win32u/input.c | 21 +++++++++++++++++++-- dlls/win32u/ntuser_private.h | 1 + dlls/win32u/sysparams.c | 6 ++++++ dlls/win32u/win32u_private.h | 2 ++ include/ntuser.h | 2 ++ 6 files changed, 39 insertions(+), 14 deletions(-) diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 883377c1279..e81fda9513e 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -648,9 +648,8 @@ LRESULT WINAPI DefRawInputProc( RAWINPUT **data, INT data_count, UINT header_siz */ BOOL WINAPI CloseTouchInputHandle( HTOUCHINPUT handle ) { - FIXME( "handle %p stub!\n", handle ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + TRACE( "handle %p.\n", handle ); + return TRUE; } /***************************************************************************** @@ -658,9 +657,9 @@ BOOL WINAPI CloseTouchInputHandle( HTOUCHINPUT handle ) */ BOOL WINAPI GetTouchInputInfo( HTOUCHINPUT handle, UINT count, TOUCHINPUT *ptr, int size ) { - FIXME( "handle %p, count %u, ptr %p, size %u stub!\n", handle, count, ptr, size ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + TRACE( "handle %p, count %u, ptr %p, size %u.\n", handle, count, ptr, size ); + *ptr = *(TOUCHINPUT *)handle; + return TRUE; } /***************************************************************************** @@ -668,9 +667,8 @@ BOOL WINAPI GetTouchInputInfo( HTOUCHINPUT handle, UINT count, TOUCHINPUT *ptr, */ BOOL WINAPI RegisterTouchWindow( HWND hwnd, ULONG flags ) { - FIXME( "hwnd %p, flags %#lx stub!\n", hwnd, flags ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + TRACE( "hwnd %p, flags %#lx.\n", hwnd, flags ); + return NtUserCallTwoParam( (ULONG_PTR)hwnd, flags, NtUserCallTwoParam_RegisterTouchWindow ); } /***************************************************************************** @@ -678,9 +676,8 @@ BOOL WINAPI RegisterTouchWindow( HWND hwnd, ULONG flags ) */ BOOL WINAPI UnregisterTouchWindow( HWND hwnd ) { - FIXME( "hwnd %p stub!\n", hwnd ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + TRACE( "hwnd %p.\n", hwnd ); + return NtUserCallOneParam( (ULONG_PTR)hwnd, NtUserCallOneParam_UnregisterTouchWindow ); } /***************************************************************************** diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 1ffad046cbf..52b9d95580b 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2448,8 +2448,25 @@ BOOL WINAPI NtUserIsMouseInPointerEnabled(void) */ BOOL WINAPI NtUserIsTouchWindow( HWND hwnd, ULONG *flags ) { - FIXME( "hwnd %p, flags %p stub!\n", hwnd, flags ); - return FALSE; + DWORD win_flags = win_set_flags( hwnd, 0, 0 ); + TRACE( "hwnd %p, flags %p.\n", hwnd, flags ); + return (win_flags & WIN_IS_TOUCH) != 0; +} + + +BOOL register_touch_window( HWND hwnd, UINT flags ) +{ + DWORD win_flags = win_set_flags( hwnd, WIN_IS_TOUCH, 0 ); + TRACE( "hwnd %p, flags %#x.\n", hwnd, flags ); + return (win_flags & WIN_IS_TOUCH) == 0; +} + + +BOOL unregister_touch_window( HWND hwnd ) +{ + DWORD win_flags = win_set_flags( hwnd, 0, WIN_IS_TOUCH ); + TRACE( "hwnd %p.\n", hwnd ); + return (win_flags & WIN_IS_TOUCH) != 0; } /********************************************************************** diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 6eb182e5979..4c92480b476 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -104,6 +104,7 @@ typedef struct tagWND #define WIN_NEEDS_SHOW_OWNEDPOPUP 0x0020 /* WM_SHOWWINDOW:SC_SHOW must be sent in the next ShowOwnedPopup call */ #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 */ #define WND_OTHER_PROCESS ((WND *)1) /* returned by get_win_ptr on unknown window handles */ diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 36aed0ad43b..cba0052577d 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -5613,6 +5613,9 @@ ULONG_PTR WINAPI NtUserCallOneParam( ULONG_PTR arg, ULONG code ) process_layout = arg; return TRUE; + case NtUserCallOneParam_UnregisterTouchWindow: + return unregister_touch_window( (HWND)arg ); + /* temporary exports */ case NtUserGetDeskPattern: return get_entry( &entry_DESKPATTERN, 256, (WCHAR *)arg ); @@ -5645,6 +5648,9 @@ ULONG_PTR WINAPI NtUserCallTwoParam( ULONG_PTR arg1, ULONG_PTR arg2, ULONG code case NtUserCallTwoParam_MonitorFromRect: return HandleToUlong( monitor_from_rect( (const RECT *)arg1, arg2, get_thread_dpi() )); + case NtUserCallTwoParam_RegisterTouchWindow: + return register_touch_window( (HWND)arg1, arg2 ); + case NtUserCallTwoParam_SetCaretPos: return set_caret_pos( arg1, arg2 ); diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 98af7c73c9c..489750bdc3c 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -273,6 +273,7 @@ extern DWORD get_input_state(void) DECLSPEC_HIDDEN; extern HWND get_progman_window(void) DECLSPEC_HIDDEN; extern HWND get_shell_window(void) DECLSPEC_HIDDEN; extern HWND get_taskman_window(void) DECLSPEC_HIDDEN; +extern BOOL register_touch_window( HWND hwnd, UINT flags ) DECLSPEC_HIDDEN; extern BOOL WINAPI release_capture(void) DECLSPEC_HIDDEN; extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) DECLSPEC_HIDDEN; extern BOOL set_caret_blink_time( unsigned int time ) DECLSPEC_HIDDEN; @@ -281,6 +282,7 @@ extern BOOL set_foreground_window( HWND hwnd, BOOL mouse ) DECLSPEC_HIDDEN; extern HWND set_progman_window( HWND hwnd ) DECLSPEC_HIDDEN; extern HWND set_taskman_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void toggle_caret( HWND hwnd ) DECLSPEC_HIDDEN; +extern BOOL unregister_touch_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void update_mouse_tracking_info( HWND hwnd ) DECLSPEC_HIDDEN; /* menu.c */ diff --git a/include/ntuser.h b/include/ntuser.h index daa52d3cb57..7e8e5b56371 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -995,6 +995,7 @@ enum NtUserCallOneParam_ReplyMessage, NtUserCallOneParam_SetCaretBlinkTime, NtUserCallOneParam_SetProcessDefaultLayout, + NtUserCallOneParam_UnregisterTouchWindow, /* temporary exports */ NtUserGetDeskPattern, }; @@ -1121,6 +1122,7 @@ enum NtUserCallTwoParam_GetMonitorInfo, NtUserCallTwoParam_GetSystemMetricsForDpi, NtUserCallTwoParam_MonitorFromRect, + NtUserCallTwoParam_RegisterTouchWindow, NtUserCallTwoParam_SetCaretPos, NtUserCallTwoParam_SetIconParam, NtUserCallTwoParam_UnhookWindowsHook, From 16eeea9d07e10d4198f5046736d9f073bafa792a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 21 May 2021 14:57:46 +0200 Subject: [PATCH 1147/2777] user32: Implement rudimentary EnableMouseInPointer support. CW-Bug-Id: 18943 Squashed with: user32: Send EnableMouseInPointer emulated messages earlier. Emulating these messages should probably be done elsewhere. CW-Bug-Id: #21331 winex11.drv: Send legacy and rawinput mouse messages on touch input. CW-Bug-Id: #18214 user32: Better emulate EnableMouseInPointer messages. This is still not very good, but it better matches what Windows does, and it fixes mouse input with Return to Monkey Island. CW-Bug-Id: #21331 --- dlls/win32u/input.c | 8 ++++--- dlls/win32u/message.c | 45 ++++++++++++++++++++++++++++++++++++ dlls/win32u/win32u_private.h | 1 + 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 52b9d95580b..79382e55c42 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -532,6 +532,8 @@ static WCHAR kbd_tables_vkey_to_wchar( const KBDTABLES *tables, UINT vkey, const #undef NEXT_ENTRY +BOOL enable_mouse_in_pointer = FALSE; + /********************************************************************** * NtUserAttachThreadInput (win32u.@) */ @@ -2428,9 +2430,9 @@ void toggle_caret( HWND hwnd ) */ BOOL WINAPI NtUserEnableMouseInPointer( BOOL enable ) { - FIXME( "enable %u stub!\n", enable ); - RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + FIXME( "enable %u semi-stub!\n", enable ); + enable_mouse_in_pointer = TRUE; + return TRUE; } /********************************************************************** diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index beaa5bf21bf..ea7b9db522b 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1639,6 +1639,51 @@ static BOOL process_mouse_message( MSG *msg, UINT hw_id, ULONG_PTR extra_info, H msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt ); SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( msg->hwnd )); + if ((extra_info & 0xffffff00) != 0xff515700 && enable_mouse_in_pointer) + { + WORD flags = POINTER_MESSAGE_FLAG_PRIMARY; + DWORD message = 0; + + switch (msg->message) + { + case WM_MOUSEMOVE: + message = WM_POINTERUPDATE; + flags |= POINTER_MESSAGE_FLAG_INRANGE; + break; + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_XBUTTONDOWN: + message = WM_POINTERDOWN; + flags |= POINTER_MESSAGE_FLAG_INRANGE|POINTER_MESSAGE_FLAG_INCONTACT; + if (msg->message == WM_LBUTTONDOWN) flags |= POINTER_MESSAGE_FLAG_FIRSTBUTTON; + if (msg->message == WM_RBUTTONDOWN) flags |= POINTER_MESSAGE_FLAG_SECONDBUTTON; + if (msg->message == WM_MBUTTONDOWN) flags |= POINTER_MESSAGE_FLAG_THIRDBUTTON; + if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_LBUTTON) flags |= POINTER_MESSAGE_FLAG_FIRSTBUTTON; + if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_RBUTTON) flags |= POINTER_MESSAGE_FLAG_SECONDBUTTON; + if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_MBUTTON) flags |= POINTER_MESSAGE_FLAG_THIRDBUTTON; + if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_XBUTTON1) flags |= POINTER_MESSAGE_FLAG_FOURTHBUTTON; + if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_XBUTTON2) flags |= POINTER_MESSAGE_FLAG_FIFTHBUTTON; + break; + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case WM_XBUTTONUP: + message = WM_POINTERUP; + break; + case WM_MOUSEWHEEL: + message = WM_POINTERWHEEL; + flags = HIWORD( msg->wParam ); + break; + case WM_MOUSEHWHEEL: + message = WM_POINTERHWHEEL; + flags = HIWORD( msg->wParam ); + break; + } + + if (message) send_message( msg->hwnd, message, MAKELONG( 1, flags ), MAKELONG( msg->pt.x, msg->pt.y ) ); + } + /* FIXME: is this really the right place for this hook? */ event.message = msg->message; event.time = msg->time; diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 489750bdc3c..87c76e7422c 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -265,6 +265,7 @@ extern void unregister_imm_window( HWND hwnd ) DECLSPEC_HIDDEN; /* input.c */ extern BOOL destroy_caret(void) DECLSPEC_HIDDEN; +extern BOOL enable_mouse_in_pointer DECLSPEC_HIDDEN; extern HWND get_active_window(void) DECLSPEC_HIDDEN; extern HWND get_capture(void) DECLSPEC_HIDDEN; extern BOOL get_cursor_pos( POINT *pt ) DECLSPEC_HIDDEN; From 4dec4a9862ea1fb3bf7480e8a75504e9d0951482 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 11 Jan 2023 19:19:17 -0600 Subject: [PATCH 1148/2777] ws2_32: Provide same address order from gethostbyname() on consequent calls. (cherry picked from commit 9c5e380cfe7b9d44d86dac539398c04cd22b8282) CW-Bug-Id: #21772 --- dlls/ws2_32/Makefile.in | 1 + dlls/ws2_32/unixlib.c | 89 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/dlls/ws2_32/Makefile.in b/dlls/ws2_32/Makefile.in index 13937dc6ee7..fc13323b930 100644 --- a/dlls/ws2_32/Makefile.in +++ b/dlls/ws2_32/Makefile.in @@ -3,6 +3,7 @@ MODULE = ws2_32.dll UNIXLIB = ws2_32.so IMPORTLIB = ws2_32 DELAYIMPORTS = dnsapi advapi32 iphlpapi user32 +UNIX_LIBS = $(PTHREAD_LIBS) C_SRCS = \ async.c \ diff --git a/dlls/ws2_32/unixlib.c b/dlls/ws2_32/unixlib.c index 0625c5c72ce..f013e1ac3d0 100644 --- a/dlls/ws2_32/unixlib.c +++ b/dlls/ws2_32/unixlib.c @@ -167,6 +167,51 @@ static const int ip_protocol_map[][2] = #undef MAP +static pthread_once_t hash_init_once = PTHREAD_ONCE_INIT; +static BYTE byte_hash[256]; + +static void init_hash(void) +{ + unsigned i, index; + NTSTATUS status; + BYTE *buf, tmp; + ULONG buf_len; + + for (i = 0; i < sizeof(byte_hash); ++i) + byte_hash[i] = i; + + buf_len = sizeof(SYSTEM_INTERRUPT_INFORMATION) * NtCurrentTeb()->Peb->NumberOfProcessors; + if (!(buf = malloc( buf_len ))) + { + ERR( "No memory.\n" ); + return; + } + + for (i = 0; i < sizeof(byte_hash) - 1; ++i) + { + if (!(i % buf_len) && (status = NtQuerySystemInformation( SystemInterruptInformation, buf, + buf_len, &buf_len ))) + { + ERR( "Failed to get random bytes.\n" ); + free( buf ); + return; + } + index = i + buf[i % buf_len] % (sizeof(byte_hash) - i); + tmp = byte_hash[index]; + byte_hash[index] = byte_hash[i]; + byte_hash[i] = tmp; + } + free( buf ); +} + +static void hash_random( BYTE *d, const BYTE *s, unsigned int len ) +{ + unsigned int i; + + for (i = 0; i < len; ++i) + d[i] = byte_hash[s[i]]; +} + static int addrinfo_flags_from_unix( int flags ) { int ws_flags = 0; @@ -889,6 +934,44 @@ static NTSTATUS unix_gethostbyaddr( void *args ) #endif } +static int compare_addrs_hashed( const void *a1, const void *a2, int addr_len ) +{ + char a1_hashed[16], a2_hashed[16]; + + assert( addr_len <= sizeof(a1_hashed) ); + hash_random( (BYTE *)a1_hashed, a1, addr_len ); + hash_random( (BYTE *)a2_hashed, a2, addr_len ); + return memcmp( a1_hashed, a2_hashed, addr_len ); +} + +static void sort_addrs_hashed( struct hostent *host ) +{ + /* On Unix gethostbyname() may return IP addresses in random order on each call. On Windows the order of + * IP addresses is not determined as well but it is the same on consequent calls (changes after network + * resets and probably DNS timeout expiration). + * Life is Strange Remastered depends on gethostbyname() returning IP addresses in the same order to reuse + * the established TLS connection and avoid timeouts that happen in game when establishing multiple extra TLS + * connections. + * Just sorting the addresses would break server load balancing provided by gethostbyname(), so randomize the + * sort once per process. */ + unsigned int i, j; + char *tmp; + + pthread_once( &hash_init_once, init_hash ); + + for (i = 0; host->h_addr_list[i]; ++i) + { + for (j = i + 1; host->h_addr_list[j]; ++j) + { + if (compare_addrs_hashed( host->h_addr_list[j], host->h_addr_list[i], host->h_length ) < 0) + { + tmp = host->h_addr_list[j]; + host->h_addr_list[j] = host->h_addr_list[i]; + host->h_addr_list[i] = tmp; + } + } + } +} #ifdef HAVE_LINUX_GETHOSTBYNAME_R_6 static NTSTATUS unix_gethostbyname( void *args ) @@ -915,9 +998,14 @@ static NTSTATUS unix_gethostbyname( void *args ) } if (!unix_host) + { ret = (locerr < 0 ? errno_from_unix( errno ) : host_errno_from_unix( locerr )); + } else + { + sort_addrs_hashed( unix_host ); ret = hostent_from_unix( unix_host, params->host, params->size ); + } free( unix_buffer ); return ret; @@ -938,6 +1026,7 @@ static NTSTATUS unix_gethostbyname( void *args ) return ret; } + sort_addrs_hashed( unix_host ); ret = hostent_from_unix( unix_host, params->host, params->size ); pthread_mutex_unlock( &host_mutex ); From c001cf4df874fa8013e7e123ae487d2d3e1b0195 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 27 Feb 2023 10:23:17 -0600 Subject: [PATCH 1149/2777] Revert "cryptnet: Also cache revocation status when using OCSP." This reverts commit ca40454f47ee18f769dee2261eeac0182b205726. --- dlls/cryptnet/cryptnet_main.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/dlls/cryptnet/cryptnet_main.c b/dlls/cryptnet/cryptnet_main.c index 516bbad9ca4..01ded96d88f 100644 --- a/dlls/cryptnet/cryptnet_main.c +++ b/dlls/cryptnet/cryptnet_main.c @@ -1895,12 +1895,11 @@ static BOOL match_cert_id(const OCSP_CERT_ID *id, const CERT_INFO *cert, const C } static DWORD check_ocsp_response_info(const CERT_INFO *cert, const CERT_INFO *issuer, - const CRYPT_OBJID_BLOB *blob, DWORD *status, FILETIME *next_update) + const CRYPT_OBJID_BLOB *blob, DWORD *status) { OCSP_BASIC_RESPONSE_INFO *info; DWORD size, i; - memset(next_update, 0, sizeof(*next_update)); if (!CryptDecodeObjectEx(X509_ASN_ENCODING, OCSP_BASIC_RESPONSE, blob->pbData, blob->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)) return GetLastError(); @@ -1908,11 +1907,7 @@ static DWORD check_ocsp_response_info(const CERT_INFO *cert, const CERT_INFO *is for (i = 0; i < info->cResponseEntry; i++) { OCSP_BASIC_RESPONSE_ENTRY *entry = &info->rgResponseEntry[i]; - if (match_cert_id(&entry->CertId, cert, issuer)) - { - *status = map_ocsp_status(entry->dwCertStatus); - *next_update = entry->NextUpdate; - } + if (match_cert_id(&entry->CertId, cert, issuer)) *status = map_ocsp_status(entry->dwCertStatus); } LocalFree(info); @@ -1925,7 +1920,6 @@ static DWORD verify_signed_ocsp_response_info(const CERT_INFO *cert, const CERT_ OCSP_BASIC_SIGNED_RESPONSE_INFO *info; DWORD size, error, status = CRYPT_E_REVOCATION_OFFLINE; CRYPT_ALGORITHM_IDENTIFIER *alg; - FILETIME next_update; CRYPT_BIT_BLOB *sig; HCRYPTPROV prov = 0; HCRYPTHASH hash = 0; @@ -1935,7 +1929,7 @@ static DWORD verify_signed_ocsp_response_info(const CERT_INFO *cert, const CERT_ if (!CryptDecodeObjectEx(X509_ASN_ENCODING, OCSP_BASIC_SIGNED_RESPONSE, blob->pbData, blob->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)) return GetLastError(); - if ((error = check_ocsp_response_info(cert, issuer, &info->ToBeSigned, &status, &next_update))) goto done; + if ((error = check_ocsp_response_info(cert, issuer, &info->ToBeSigned, &status))) goto done; alg = &info->SignatureInfo.SignatureAlgorithm; if (!alg->pszObjId || !(algid = CertOIDToAlgId(alg->pszObjId))) @@ -1964,16 +1958,6 @@ static DWORD verify_signed_ocsp_response_info(const CERT_INFO *cert, const CERT_ else error = ERROR_SUCCESS; done: - if (next_update.dwLowDateTime || next_update.dwHighDateTime) - { - CERT_REVOCATION_STATUS rev_status; - - memset(&rev_status, 0, sizeof(rev_status)); - rev_status.cbSize = sizeof(rev_status); - rev_status.dwError = status; - cache_revocation_status(&cert->SerialNumber, &next_update, &rev_status); - } - CryptDestroyKey(key); CryptDestroyHash(hash); CryptReleaseContext(prov, 0); From 78eb3d5f9aa7f3626d6c6f788d2a8cd577c1fa72 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 27 Feb 2023 10:23:18 -0600 Subject: [PATCH 1150/2777] Revert "cryptnet: Check cached revocation status in verify_cert_revocation()." This reverts commit 67de946ca9bdc8f39adffca57a336165936e62e2. --- dlls/cryptnet/cryptnet_main.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/dlls/cryptnet/cryptnet_main.c b/dlls/cryptnet/cryptnet_main.c index 01ded96d88f..19de1ed2d8e 100644 --- a/dlls/cryptnet/cryptnet_main.c +++ b/dlls/cryptnet/cryptnet_main.c @@ -1696,6 +1696,9 @@ static DWORD verify_cert_revocation_from_dist_points_ext(const CRYPT_DATA_BLOB * return CRYPT_E_REVOCATION_OFFLINE; } + if (find_cached_revocation_status(&cert->pCertInfo->SerialNumber, time, status)) + return status->dwError; + if (!CRYPT_GetUrlFromCRLDistPointsExt(value, NULL, &url_array_size, NULL, NULL)) return GetLastError(); @@ -2143,12 +2146,6 @@ static DWORD verify_cert_revocation(const CERT_CONTEXT *cert, FILETIME *pTime, DWORD error = ERROR_SUCCESS; PCERT_EXTENSION ext; - if (find_cached_revocation_status(&cert->pCertInfo->SerialNumber, pTime, pRevStatus)) - { - if (pRevStatus->dwError == ERROR_SUCCESS || pRevStatus->dwError == CRYPT_E_REVOKED) - return pRevStatus->dwError; - } - if ((ext = CertFindExtension(szOID_AUTHORITY_INFO_ACCESS, cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) { error = verify_cert_revocation_from_aia_ext(&ext->Value, cert, pTime, dwFlags, pRevPara, pRevStatus); From 5f1454298c641a804fd6838e4712e9b48f598b52 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 11 Jan 2023 14:00:48 -0600 Subject: [PATCH 1151/2777] cryptnet: Check cached revocation status in verify_cert_revocation(). (cherry picked from commit 67de946ca9bdc8f39adffca57a336165936e62e2) --- dlls/cryptnet/cryptnet_main.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dlls/cryptnet/cryptnet_main.c b/dlls/cryptnet/cryptnet_main.c index 19de1ed2d8e..01ded96d88f 100644 --- a/dlls/cryptnet/cryptnet_main.c +++ b/dlls/cryptnet/cryptnet_main.c @@ -1696,9 +1696,6 @@ static DWORD verify_cert_revocation_from_dist_points_ext(const CRYPT_DATA_BLOB * return CRYPT_E_REVOCATION_OFFLINE; } - if (find_cached_revocation_status(&cert->pCertInfo->SerialNumber, time, status)) - return status->dwError; - if (!CRYPT_GetUrlFromCRLDistPointsExt(value, NULL, &url_array_size, NULL, NULL)) return GetLastError(); @@ -2146,6 +2143,12 @@ static DWORD verify_cert_revocation(const CERT_CONTEXT *cert, FILETIME *pTime, DWORD error = ERROR_SUCCESS; PCERT_EXTENSION ext; + if (find_cached_revocation_status(&cert->pCertInfo->SerialNumber, pTime, pRevStatus)) + { + if (pRevStatus->dwError == ERROR_SUCCESS || pRevStatus->dwError == CRYPT_E_REVOKED) + return pRevStatus->dwError; + } + if ((ext = CertFindExtension(szOID_AUTHORITY_INFO_ACCESS, cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) { error = verify_cert_revocation_from_aia_ext(&ext->Value, cert, pTime, dwFlags, pRevPara, pRevStatus); From 7f2725826b83d23a5c5b2fc41a7400b102110ba8 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 11 Jan 2023 14:17:47 -0600 Subject: [PATCH 1152/2777] cryptnet: Also cache revocation status when using OCSP. (cherry picked from commit ca40454f47ee18f769dee2261eeac0182b205726) --- dlls/cryptnet/cryptnet_main.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/dlls/cryptnet/cryptnet_main.c b/dlls/cryptnet/cryptnet_main.c index 01ded96d88f..516bbad9ca4 100644 --- a/dlls/cryptnet/cryptnet_main.c +++ b/dlls/cryptnet/cryptnet_main.c @@ -1895,11 +1895,12 @@ static BOOL match_cert_id(const OCSP_CERT_ID *id, const CERT_INFO *cert, const C } static DWORD check_ocsp_response_info(const CERT_INFO *cert, const CERT_INFO *issuer, - const CRYPT_OBJID_BLOB *blob, DWORD *status) + const CRYPT_OBJID_BLOB *blob, DWORD *status, FILETIME *next_update) { OCSP_BASIC_RESPONSE_INFO *info; DWORD size, i; + memset(next_update, 0, sizeof(*next_update)); if (!CryptDecodeObjectEx(X509_ASN_ENCODING, OCSP_BASIC_RESPONSE, blob->pbData, blob->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)) return GetLastError(); @@ -1907,7 +1908,11 @@ static DWORD check_ocsp_response_info(const CERT_INFO *cert, const CERT_INFO *is for (i = 0; i < info->cResponseEntry; i++) { OCSP_BASIC_RESPONSE_ENTRY *entry = &info->rgResponseEntry[i]; - if (match_cert_id(&entry->CertId, cert, issuer)) *status = map_ocsp_status(entry->dwCertStatus); + if (match_cert_id(&entry->CertId, cert, issuer)) + { + *status = map_ocsp_status(entry->dwCertStatus); + *next_update = entry->NextUpdate; + } } LocalFree(info); @@ -1920,6 +1925,7 @@ static DWORD verify_signed_ocsp_response_info(const CERT_INFO *cert, const CERT_ OCSP_BASIC_SIGNED_RESPONSE_INFO *info; DWORD size, error, status = CRYPT_E_REVOCATION_OFFLINE; CRYPT_ALGORITHM_IDENTIFIER *alg; + FILETIME next_update; CRYPT_BIT_BLOB *sig; HCRYPTPROV prov = 0; HCRYPTHASH hash = 0; @@ -1929,7 +1935,7 @@ static DWORD verify_signed_ocsp_response_info(const CERT_INFO *cert, const CERT_ if (!CryptDecodeObjectEx(X509_ASN_ENCODING, OCSP_BASIC_SIGNED_RESPONSE, blob->pbData, blob->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)) return GetLastError(); - if ((error = check_ocsp_response_info(cert, issuer, &info->ToBeSigned, &status))) goto done; + if ((error = check_ocsp_response_info(cert, issuer, &info->ToBeSigned, &status, &next_update))) goto done; alg = &info->SignatureInfo.SignatureAlgorithm; if (!alg->pszObjId || !(algid = CertOIDToAlgId(alg->pszObjId))) @@ -1958,6 +1964,16 @@ static DWORD verify_signed_ocsp_response_info(const CERT_INFO *cert, const CERT_ else error = ERROR_SUCCESS; done: + if (next_update.dwLowDateTime || next_update.dwHighDateTime) + { + CERT_REVOCATION_STATUS rev_status; + + memset(&rev_status, 0, sizeof(rev_status)); + rev_status.cbSize = sizeof(rev_status); + rev_status.dwError = status; + cache_revocation_status(&cert->SerialNumber, &next_update, &rev_status); + } + CryptDestroyKey(key); CryptDestroyHash(hash); CryptReleaseContext(prov, 0); From 6c0a8522954976c18598160c304bb69b310d70d9 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 24 Jan 2023 11:51:08 -0600 Subject: [PATCH 1153/2777] cryptnet: Cache revocation status in verify_cert_revocation(). (cherry picked from commit 6e782449ab72cc5d20877934c580a45e8df46a04) --- dlls/cryptnet/cryptnet_main.c | 56 +++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/dlls/cryptnet/cryptnet_main.c b/dlls/cryptnet/cryptnet_main.c index 516bbad9ca4..211b5c3cf8c 100644 --- a/dlls/cryptnet/cryptnet_main.c +++ b/dlls/cryptnet/cryptnet_main.c @@ -1683,7 +1683,8 @@ static const CRL_CONTEXT *retrieve_crl_from_dist_points(const CRYPT_URL_ARRAY *a } static DWORD verify_cert_revocation_from_dist_points_ext(const CRYPT_DATA_BLOB *value, const CERT_CONTEXT *cert, - FILETIME *time, DWORD flags, const CERT_REVOCATION_PARA *params, CERT_REVOCATION_STATUS *status) + FILETIME *time, DWORD flags, const CERT_REVOCATION_PARA *params, CERT_REVOCATION_STATUS *status, + FILETIME *next_update) { DWORD url_array_size, error; CRYPT_URL_ARRAY *url_array; @@ -1719,7 +1720,7 @@ static DWORD verify_cert_revocation_from_dist_points_ext(const CRYPT_DATA_BLOB * error = verify_cert_revocation_with_crl_online(cert, crl, time, status); - cache_revocation_status(&cert->pCertInfo->SerialNumber, &crl->pCrlInfo->NextUpdate, status); + *next_update = crl->pCrlInfo->NextUpdate; CertFreeCRLContext(crl); CryptMemFree(url_array); @@ -1920,12 +1921,11 @@ static DWORD check_ocsp_response_info(const CERT_INFO *cert, const CERT_INFO *is } static DWORD verify_signed_ocsp_response_info(const CERT_INFO *cert, const CERT_INFO *issuer, - const CRYPT_OBJID_BLOB *blob) + const CRYPT_OBJID_BLOB *blob, FILETIME *next_update) { OCSP_BASIC_SIGNED_RESPONSE_INFO *info; DWORD size, error, status = CRYPT_E_REVOCATION_OFFLINE; CRYPT_ALGORITHM_IDENTIFIER *alg; - FILETIME next_update; CRYPT_BIT_BLOB *sig; HCRYPTPROV prov = 0; HCRYPTHASH hash = 0; @@ -1935,7 +1935,7 @@ static DWORD verify_signed_ocsp_response_info(const CERT_INFO *cert, const CERT_ if (!CryptDecodeObjectEx(X509_ASN_ENCODING, OCSP_BASIC_SIGNED_RESPONSE, blob->pbData, blob->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)) return GetLastError(); - if ((error = check_ocsp_response_info(cert, issuer, &info->ToBeSigned, &status, &next_update))) goto done; + if ((error = check_ocsp_response_info(cert, issuer, &info->ToBeSigned, &status, next_update))) goto done; alg = &info->SignatureInfo.SignatureAlgorithm; if (!alg->pszObjId || !(algid = CertOIDToAlgId(alg->pszObjId))) @@ -1964,16 +1964,6 @@ static DWORD verify_signed_ocsp_response_info(const CERT_INFO *cert, const CERT_ else error = ERROR_SUCCESS; done: - if (next_update.dwLowDateTime || next_update.dwHighDateTime) - { - CERT_REVOCATION_STATUS rev_status; - - memset(&rev_status, 0, sizeof(rev_status)); - rev_status.cbSize = sizeof(rev_status); - rev_status.dwError = status; - cache_revocation_status(&cert->SerialNumber, &next_update, &rev_status); - } - CryptDestroyKey(key); CryptDestroyHash(hash); CryptReleaseContext(prov, 0); @@ -1983,7 +1973,7 @@ static DWORD verify_signed_ocsp_response_info(const CERT_INFO *cert, const CERT_ } static DWORD handle_ocsp_response(const CERT_INFO *cert, const CERT_INFO *issuer, const BYTE *encoded, - DWORD encoded_size) + DWORD encoded_size, FILETIME *next_update) { OCSP_RESPONSE_INFO *info; DWORD size, error = CRYPT_E_NO_REVOCATION_CHECK; @@ -1999,7 +1989,7 @@ static DWORD handle_ocsp_response(const CERT_INFO *cert, const CERT_INFO *issuer FIXME("unhandled response type %s\n", debugstr_a(info->pszObjId)); break; } - error = verify_signed_ocsp_response_info(cert, issuer, &info->Value); + error = verify_signed_ocsp_response_info(cert, issuer, &info->Value, next_update); break; default: @@ -2012,7 +2002,7 @@ static DWORD handle_ocsp_response(const CERT_INFO *cert, const CERT_INFO *issuer } static DWORD verify_cert_revocation_with_ocsp(const CERT_CONTEXT *cert, const WCHAR *base_url, - const CERT_REVOCATION_PARA *revpara) + const CERT_REVOCATION_PARA *revpara, FILETIME *next_update) { HINTERNET ses, con, req = NULL; BYTE *request_data = NULL, *response_data = NULL; @@ -2081,7 +2071,8 @@ static DWORD verify_cert_revocation_with_ocsp(const CERT_CONTEXT *cert, const WC !response_len || !(response_data = malloc(response_len)) || !InternetReadFile(req, response_data, response_len, &count) || count != response_len) goto done; - ret = handle_ocsp_response(cert->pCertInfo, revpara->pIssuerCert->pCertInfo, response_data, response_len); + ret = handle_ocsp_response(cert->pCertInfo, revpara->pIssuerCert->pCertInfo, response_data, response_len, + next_update); done: free(url); @@ -2093,7 +2084,8 @@ static DWORD verify_cert_revocation_with_ocsp(const CERT_CONTEXT *cert, const WC } static DWORD verify_cert_revocation_from_aia_ext(const CRYPT_DATA_BLOB *value, const CERT_CONTEXT *cert, - FILETIME *pTime, DWORD dwFlags, CERT_REVOCATION_PARA *pRevPara, CERT_REVOCATION_STATUS *pRevStatus) + FILETIME *pTime, DWORD dwFlags, CERT_REVOCATION_PARA *pRevPara, CERT_REVOCATION_STATUS *pRevStatus, + FILETIME *next_update) { BOOL ret; DWORD size, i, error = CRYPT_E_NO_REVOCATION_CHECK; @@ -2111,7 +2103,7 @@ static DWORD verify_cert_revocation_from_aia_ext(const CRYPT_DATA_BLOB *value, c { const WCHAR *url = aia->rgAccDescr[i].AccessLocation.u.pwszURL; TRACE("OCSP URL = %s\n", debugstr_w(url)); - error = verify_cert_revocation_with_ocsp(cert, url, pRevPara); + error = verify_cert_revocation_with_ocsp(cert, url, pRevPara, next_update); } else { @@ -2157,6 +2149,7 @@ static DWORD verify_cert_revocation(const CERT_CONTEXT *cert, FILETIME *pTime, DWORD dwFlags, CERT_REVOCATION_PARA *pRevPara, CERT_REVOCATION_STATUS *pRevStatus) { DWORD error = ERROR_SUCCESS; + FILETIME next_update = {0}; PCERT_EXTENSION ext; if (find_cached_revocation_status(&cert->pCertInfo->SerialNumber, pTime, pRevStatus)) @@ -2167,15 +2160,17 @@ static DWORD verify_cert_revocation(const CERT_CONTEXT *cert, FILETIME *pTime, if ((ext = CertFindExtension(szOID_AUTHORITY_INFO_ACCESS, cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) { - error = verify_cert_revocation_from_aia_ext(&ext->Value, cert, pTime, dwFlags, pRevPara, pRevStatus); + error = verify_cert_revocation_from_aia_ext(&ext->Value, cert, pTime, dwFlags, pRevPara, pRevStatus, + &next_update); TRACE("verify_cert_revocation_from_aia_ext() returned %08lx\n", error); - if (error == ERROR_SUCCESS || error == CRYPT_E_REVOKED) return error; + if (error == ERROR_SUCCESS || error == CRYPT_E_REVOKED) goto done; } if ((ext = CertFindExtension(szOID_CRL_DIST_POINTS, cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) { - error = verify_cert_revocation_from_dist_points_ext(&ext->Value, cert, pTime, dwFlags, pRevPara, pRevStatus); + error = verify_cert_revocation_from_dist_points_ext(&ext->Value, cert, pTime, dwFlags, pRevPara, pRevStatus, + &next_update); TRACE("verify_cert_revocation_from_dist_points_ext() returned %08lx\n", error); - if (error == ERROR_SUCCESS || error == CRYPT_E_REVOKED) return error; + if (error == ERROR_SUCCESS || error == CRYPT_E_REVOKED) goto done; } if (!ext) { @@ -2247,6 +2242,17 @@ static DWORD verify_cert_revocation(const CERT_CONTEXT *cert, FILETIME *pTime, error = CRYPT_E_NO_REVOCATION_CHECK; } } +done: + if ((next_update.dwLowDateTime || next_update.dwHighDateTime) + && (error == ERROR_SUCCESS || error == CRYPT_E_REVOKED)) + { + CERT_REVOCATION_STATUS rev_status; + + memset(&rev_status, 0, sizeof(rev_status)); + rev_status.cbSize = sizeof(rev_status); + rev_status.dwError = error; + cache_revocation_status(&cert->pCertInfo->SerialNumber, &next_update, &rev_status); + } return error; } From 7edae125b7498860690dae337625ef98b37739c7 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 24 Jan 2023 11:54:23 -0600 Subject: [PATCH 1154/2777] cryptnet: Use cert data hash as cache id instead of serial number. (cherry picked from commit f114ab57d268bfc7803bbba82e9877cc6178fd0d) --- dlls/cryptnet/cryptnet_main.c | 37 +++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/dlls/cryptnet/cryptnet_main.c b/dlls/cryptnet/cryptnet_main.c index 211b5c3cf8c..7d1c01363c0 100644 --- a/dlls/cryptnet/cryptnet_main.c +++ b/dlls/cryptnet/cryptnet_main.c @@ -1537,11 +1537,16 @@ BOOL WINAPI CryptRetrieveObjectByUrlW(LPCWSTR pszURL, LPCSTR pszObjectOid, static const char revocation_cache_signature[] = "Wine cached revocation"; -static FILE *open_cached_revocation_file(const CRYPT_INTEGER_BLOB *serial, const WCHAR *mode, int sharing) +#define CACHED_CERT_HASH_SIZE 20 + +static FILE *open_cached_revocation_file(const CERT_CONTEXT *cert, const WCHAR *mode, int sharing) { + BYTE hash_data[CACHED_CERT_HASH_SIZE]; WCHAR path[MAX_PATH]; WCHAR *appdata_path; - DWORD len, i; + DWORD len, i, size; + HCRYPTPROV prov; + HCRYPTHASH hash; HRESULT hr; if (FAILED(hr = SHGetKnownFolderPath(&FOLDERID_LocalAppDataLow, 0, NULL, &appdata_path))) @@ -1553,24 +1558,32 @@ static FILE *open_cached_revocation_file(const CRYPT_INTEGER_BLOB *serial, const len = swprintf(path, ARRAY_SIZE(path), L"%s\\Microsoft\\CryptnetUrlCache\\Content\\", appdata_path); CoTaskMemFree(appdata_path); - if (len + serial->cbData * 2 * sizeof(WCHAR) > ARRAY_SIZE(path) - 1) + if (len + CACHED_CERT_HASH_SIZE * 2 * sizeof(WCHAR) > ARRAY_SIZE(path) - 1) { - WARN("Serial length exceeds static buffer; not caching.\n"); + WARN("Hash length exceeds static buffer; not caching.\n"); return INVALID_HANDLE_VALUE; } + CryptAcquireContextW(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + CryptCreateHash(prov, CALG_SHA1, 0, 0, &hash); + CryptHashData(hash, cert->pbCertEncoded, cert->cbCertEncoded, 0); + size = sizeof(hash_data); + CryptGetHashParam(hash, HP_HASHVAL, hash_data, &size, 0); + CryptDestroyHash(hash); + CryptReleaseContext(prov, 0); + SHCreateDirectoryExW(NULL, path, NULL); - for (i = 0; i < serial->cbData; ++i) + for (i = 0; i < CACHED_CERT_HASH_SIZE; ++i) { - swprintf(path + len, 3, L"%02x", serial->pbData[i]); + swprintf(path + len, 3, L"%02x", hash_data[i]); len += 2; } return _wfsopen(path, mode, sharing); } -static BOOL find_cached_revocation_status(const CRYPT_INTEGER_BLOB *serial, +static BOOL find_cached_revocation_status(const CERT_CONTEXT *cert, const FILETIME *time, CERT_REVOCATION_STATUS *status) { char buffer[sizeof(revocation_cache_signature)]; @@ -1578,7 +1591,7 @@ static BOOL find_cached_revocation_status(const CRYPT_INTEGER_BLOB *serial, FILE *file; int len; - if (!(file = open_cached_revocation_file(serial, L"rb", _SH_DENYWR))) + if (!(file = open_cached_revocation_file(cert, L"rb", _SH_DENYWR))) return FALSE; if ((len = fread(buffer, 1, sizeof(buffer), file)) != sizeof(buffer) @@ -1621,12 +1634,12 @@ static BOOL find_cached_revocation_status(const CRYPT_INTEGER_BLOB *serial, return TRUE; } -static void cache_revocation_status(const CRYPT_INTEGER_BLOB *serial, +static void cache_revocation_status(const CERT_CONTEXT *cert, const FILETIME *time, const CERT_REVOCATION_STATUS *status) { FILE *file; - if (!(file = open_cached_revocation_file(serial, L"wb", _SH_DENYRW))) + if (!(file = open_cached_revocation_file(cert, L"wb", _SH_DENYRW))) return; fwrite(revocation_cache_signature, 1, sizeof(revocation_cache_signature), file); fwrite(time, sizeof(*time), 1, file); @@ -2152,7 +2165,7 @@ static DWORD verify_cert_revocation(const CERT_CONTEXT *cert, FILETIME *pTime, FILETIME next_update = {0}; PCERT_EXTENSION ext; - if (find_cached_revocation_status(&cert->pCertInfo->SerialNumber, pTime, pRevStatus)) + if (find_cached_revocation_status(cert, pTime, pRevStatus)) { if (pRevStatus->dwError == ERROR_SUCCESS || pRevStatus->dwError == CRYPT_E_REVOKED) return pRevStatus->dwError; @@ -2251,7 +2264,7 @@ static DWORD verify_cert_revocation(const CERT_CONTEXT *cert, FILETIME *pTime, memset(&rev_status, 0, sizeof(rev_status)); rev_status.cbSize = sizeof(rev_status); rev_status.dwError = error; - cache_revocation_status(&cert->pCertInfo->SerialNumber, &next_update, &rev_status); + cache_revocation_status(cert, &next_update, &rev_status); } return error; } From 61292e466ed1153918bbf83b24999fe06da1af0a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 24 Jan 2023 12:07:31 -0600 Subject: [PATCH 1155/2777] cryptnet: Also hash issuer cert for cache id. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54353 (cherry picked from commit 66b1a4f333e0687922062cb859bd73e5545608bd) --- dlls/cryptnet/cryptnet_main.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/dlls/cryptnet/cryptnet_main.c b/dlls/cryptnet/cryptnet_main.c index 7d1c01363c0..75fa4028d12 100644 --- a/dlls/cryptnet/cryptnet_main.c +++ b/dlls/cryptnet/cryptnet_main.c @@ -1539,7 +1539,8 @@ static const char revocation_cache_signature[] = "Wine cached revocation"; #define CACHED_CERT_HASH_SIZE 20 -static FILE *open_cached_revocation_file(const CERT_CONTEXT *cert, const WCHAR *mode, int sharing) +static FILE *open_cached_revocation_file(const CERT_CONTEXT *cert, const CERT_REVOCATION_PARA *params, + const WCHAR *mode, int sharing) { BYTE hash_data[CACHED_CERT_HASH_SIZE]; WCHAR path[MAX_PATH]; @@ -1567,6 +1568,16 @@ static FILE *open_cached_revocation_file(const CERT_CONTEXT *cert, const WCHAR * CryptAcquireContextW(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); CryptCreateHash(prov, CALG_SHA1, 0, 0, &hash); CryptHashData(hash, cert->pbCertEncoded, cert->cbCertEncoded, 0); + if (params && params->pIssuerCert) + { + CryptHashData(hash, (BYTE *)¶ms->pIssuerCert->cbCertEncoded, sizeof(params->pIssuerCert->cbCertEncoded), 0); + CryptHashData(hash, params->pIssuerCert->pbCertEncoded, params->pIssuerCert->cbCertEncoded, 0); + } + else + { + size = 0; + CryptHashData(hash, (BYTE *)&size, sizeof(size), 0); + } size = sizeof(hash_data); CryptGetHashParam(hash, HP_HASHVAL, hash_data, &size, 0); CryptDestroyHash(hash); @@ -1583,7 +1594,7 @@ static FILE *open_cached_revocation_file(const CERT_CONTEXT *cert, const WCHAR * return _wfsopen(path, mode, sharing); } -static BOOL find_cached_revocation_status(const CERT_CONTEXT *cert, +static BOOL find_cached_revocation_status(const CERT_CONTEXT *cert, const CERT_REVOCATION_PARA *params, const FILETIME *time, CERT_REVOCATION_STATUS *status) { char buffer[sizeof(revocation_cache_signature)]; @@ -1591,7 +1602,7 @@ static BOOL find_cached_revocation_status(const CERT_CONTEXT *cert, FILE *file; int len; - if (!(file = open_cached_revocation_file(cert, L"rb", _SH_DENYWR))) + if (!(file = open_cached_revocation_file(cert, params, L"rb", _SH_DENYWR))) return FALSE; if ((len = fread(buffer, 1, sizeof(buffer), file)) != sizeof(buffer) @@ -1634,12 +1645,12 @@ static BOOL find_cached_revocation_status(const CERT_CONTEXT *cert, return TRUE; } -static void cache_revocation_status(const CERT_CONTEXT *cert, +static void cache_revocation_status(const CERT_CONTEXT *cert, const CERT_REVOCATION_PARA *params, const FILETIME *time, const CERT_REVOCATION_STATUS *status) { FILE *file; - if (!(file = open_cached_revocation_file(cert, L"wb", _SH_DENYRW))) + if (!(file = open_cached_revocation_file(cert, params, L"wb", _SH_DENYRW))) return; fwrite(revocation_cache_signature, 1, sizeof(revocation_cache_signature), file); fwrite(time, sizeof(*time), 1, file); @@ -2165,10 +2176,13 @@ static DWORD verify_cert_revocation(const CERT_CONTEXT *cert, FILETIME *pTime, FILETIME next_update = {0}; PCERT_EXTENSION ext; - if (find_cached_revocation_status(cert, pTime, pRevStatus)) + if (find_cached_revocation_status(cert, pRevPara, pTime, pRevStatus)) { if (pRevStatus->dwError == ERROR_SUCCESS || pRevStatus->dwError == CRYPT_E_REVOKED) + { + TRACE("Returning cached status.\n"); return pRevStatus->dwError; + } } if ((ext = CertFindExtension(szOID_AUTHORITY_INFO_ACCESS, cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension))) @@ -2264,7 +2278,7 @@ static DWORD verify_cert_revocation(const CERT_CONTEXT *cert, FILETIME *pTime, memset(&rev_status, 0, sizeof(rev_status)); rev_status.cbSize = sizeof(rev_status); rev_status.dwError = error; - cache_revocation_status(cert, &next_update, &rev_status); + cache_revocation_status(cert, pRevPara, &next_update, &rev_status); } return error; } From 93ba794c9bc90ea8aeab581aa3d936bdcb7ff3c8 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 16 Jan 2023 18:33:30 -0600 Subject: [PATCH 1156/2777] ddraw: Do not report D3DDEVCAPS_HWRASTERIZATION for RGB emulation device. (cherry picked from commit be57ebe01581f709b0e52a29304668eaaf6f0634) CW-Bug-Id: #18113 --- dlls/ddraw/ddraw.c | 6 +++--- dlls/ddraw/tests/ddraw1.c | 4 ++++ dlls/ddraw/tests/ddraw2.c | 4 ++++ dlls/ddraw/tests/ddraw4.c | 4 ++++ dlls/ddraw/tests/ddraw7.c | 2 ++ 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c index 7a8c4fe8719..8c5c6180505 100644 --- a/dlls/ddraw/ddraw.c +++ b/dlls/ddraw/ddraw.c @@ -73,7 +73,7 @@ static struct enum_device_entry "WINE Direct3D7 RGB Software Emulation using WineD3D", "Wine D3D7 RGB", &IID_IDirect3DRGBDevice, - D3DDEVCAPS_HWTRANSFORMANDLIGHT | D3DDEVCAPS_DRAWPRIMITIVES2EX, + D3DDEVCAPS_HWTRANSFORMANDLIGHT | D3DDEVCAPS_DRAWPRIMITIVES2EX | D3DDEVCAPS_HWRASTERIZATION, }, }; @@ -3883,8 +3883,8 @@ static HRESULT WINAPI d3d3_EnumDevices(IDirect3D3 *iface, LPD3DENUMDEVICESCALLBA /* RGB, RAMP and MMX devices cannot report HAL hardware flags */ hal_desc.dwFlags = 0; /* RGB, REF, RAMP and MMX devices don't report hardware transform and lighting capability */ - hal_desc.dwDevCaps &= ~(D3DDEVCAPS_HWTRANSFORMANDLIGHT | D3DDEVCAPS_DRAWPRIMITIVES2EX); - hel_desc.dwDevCaps &= ~(D3DDEVCAPS_HWTRANSFORMANDLIGHT | D3DDEVCAPS_DRAWPRIMITIVES2EX); + hal_desc.dwDevCaps &= ~(D3DDEVCAPS_HWTRANSFORMANDLIGHT | D3DDEVCAPS_DRAWPRIMITIVES2EX | D3DDEVCAPS_HWRASTERIZATION); + hel_desc.dwDevCaps &= ~(D3DDEVCAPS_HWTRANSFORMANDLIGHT | D3DDEVCAPS_DRAWPRIMITIVES2EX | D3DDEVCAPS_HWRASTERIZATION); hr = callback((GUID *)&IID_IDirect3DRGBDevice, reference_description, device_name, &hal_desc, &hel_desc, context); diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index 3d81c590a3a..5e10db15860 100644 --- a/dlls/ddraw/tests/ddraw1.c +++ b/dlls/ddraw/tests/ddraw1.c @@ -15215,6 +15215,10 @@ static HRESULT WINAPI test_enum_devices_caps_callback(GUID *guid, char *device_d "RGB Device hal device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n"); ok((hel->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0, "RGB Device hel device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n"); + ok((hal->dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) == 0, + "RGB Device hal device caps has D3DDEVCAPS_HWRASTERIZATION set\n"); + ok((hel->dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) == 0, + "RGB Device hel device caps has D3DDEVCAPS_HWRASTERIZATION set\n"); } else if(IsEqualGUID(&IID_IDirect3DHALDevice, guid)) { diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c index f4079b1e5e5..84f0b82bb96 100644 --- a/dlls/ddraw/tests/ddraw2.c +++ b/dlls/ddraw/tests/ddraw2.c @@ -16161,6 +16161,10 @@ static HRESULT WINAPI test_enum_devices_caps_callback(GUID *guid, char *device_d "RGB Device hal device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n"); ok((hel->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0, "RGB Device hel device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n"); + ok((hal->dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) == 0, + "RGB Device hal device caps has D3DDEVCAPS_HWRASTERIZATION set\n"); + ok((hel->dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) == 0, + "RGB Device hel device caps has D3DDEVCAPS_HWRASTERIZATION set\n"); } else if(IsEqualGUID(&IID_IDirect3DHALDevice, guid)) { diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c index ff38483faf9..02591afc079 100644 --- a/dlls/ddraw/tests/ddraw4.c +++ b/dlls/ddraw/tests/ddraw4.c @@ -19230,6 +19230,10 @@ static HRESULT WINAPI test_enum_devices_caps_callback(GUID *guid, char *device_d "RGB Device hal device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n"); ok((hel->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0, "RGB Device hel device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n"); + ok((hal->dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) == 0, + "RGB Device hal device caps has D3DDEVCAPS_HWRASTERIZATION set\n"); + ok((hel->dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) == 0, + "RGB Device hel device caps has D3DDEVCAPS_HWRASTERIZATION set\n"); } else if(IsEqualGUID(&IID_IDirect3DHALDevice, guid)) { diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c index 8631f824edd..75bc08b0437 100644 --- a/dlls/ddraw/tests/ddraw7.c +++ b/dlls/ddraw/tests/ddraw7.c @@ -19446,6 +19446,8 @@ static HRESULT WINAPI test_enum_devices_caps_callback(char *device_desc, char *d "RGB Device device caps has D3DDEVCAPS_HWTRANSFORMANDLIGHT set\n"); ok((device_desc7->dwDevCaps & D3DDEVCAPS_DRAWPRIMITIVES2EX) == 0, "RGB Device device caps has D3DDEVCAPS_DRAWPRIMITIVES2EX set\n"); + ok((device_desc7->dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) == 0, + "RGB Device device caps has D3DDEVCAPS_HWRASTERIZATION set\n"); } else { From 636759854bce032b45d5a35b426347c2ca0e4421 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 15 Feb 2023 16:29:32 -0600 Subject: [PATCH 1157/2777] server: Retry socket connection on ECONNABORTED error. (cherry picked from commit 4e6a5d62ad2bbccafa751812ca31eb9ffa25727e) CW-Bug-Id: #20812 --- dlls/ws2_32/tests/afd.c | 8 +------- dlls/ws2_32/tests/sock.c | 41 +++++++++++++++++++++++++--------------- server/sock.c | 11 +++++++++++ 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index 3215ddaef62..b07fb40fe3f 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -569,13 +569,7 @@ static void test_poll(void) ret = connect(client, (struct sockaddr *)&addr, sizeof(addr)); ok(ret == -1, "got %d\n", ret); - todo_wine ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); - if (WSAGetLastError() == WSAECONNABORTED) - { - ret = connect(client, (struct sockaddr *)&addr, sizeof(addr)); - ok(ret == -1, "got %d\n", ret); - ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); - } + ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); /* A subsequent poll call returns no events, or times out. However, this * can't be reliably tested, as e.g. Linux will fail the connection diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 6f2bcb73a06..ba4d7514c5e 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -4349,13 +4349,7 @@ static void test_select(void) ret = connect(fdWrite, (const struct sockaddr *)&invalid_addr, sizeof(invalid_addr)); ok(ret == -1, "got %d\n", ret); - todo_wine ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); - if (WSAGetLastError() == WSAECONNABORTED) - { - ret = connect(fdWrite, (const struct sockaddr *)&invalid_addr, sizeof(invalid_addr)); - ok(ret == -1, "got %d\n", ret); - ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); - } + ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); len = sizeof(id); id = 0xdeadbeef; @@ -4377,13 +4371,7 @@ static void test_select(void) ok(!ret, "got error %u\n", WSAGetLastError()); ret = connect(fdWrite, (const struct sockaddr *)&address, sizeof(address)); ok(ret == -1, "got %d\n", ret); - todo_wine ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); - if (WSAGetLastError() == WSAECONNABORTED) - { - ret = connect(fdWrite, (const struct sockaddr *)&address, sizeof(address)); - ok(ret == -1, "got %d\n", ret); - ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); - } + ok(WSAGetLastError() == WSAEWOULDBLOCK, "got error %u\n", WSAGetLastError()); FD_ZERO_ALL(); FD_SET(fdWrite, &readfds); @@ -8317,7 +8305,6 @@ static void test_connect(void) closesocket(connector); closesocket(acceptor); - closesocket(listener); tcp_socketpair(&connector, &acceptor); @@ -8377,6 +8364,30 @@ static void test_connect(void) WSACloseEvent(overlapped.hEvent); closesocket(connector); + + /* Test connect after previous connect attempt failure. */ + connector = socket(AF_INET, SOCK_STREAM, 0); + ok(connector != INVALID_SOCKET, "failed to create socket, error %u\n", WSAGetLastError()); + + conaddress.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + conaddress.sin_port = htons(255); + iret = connect(connector, (struct sockaddr *)&conaddress, sizeof(conaddress)); + ok(iret == -1, "connection succeeded.\n"); + + ok(WSAGetLastError() == WSAECONNREFUSED, "got error %u\n", WSAGetLastError()); + set_blocking( connector, FALSE ); + iret = getsockname(listener, (struct sockaddr*)&address, &addrlen); + ok(!iret, "failed to get address, error %u\n", WSAGetLastError()); + + iret = connect(connector, (struct sockaddr *)&address, sizeof(address)); + ok(iret == -1 && WSAGetLastError() == WSAEWOULDBLOCK, "unexpected iret %d, error %d.\n", + iret, WSAGetLastError()); + acceptor = accept(listener, NULL, NULL); + ok(acceptor != INVALID_SOCKET, "could not accept socket error %d\n", WSAGetLastError()); + + closesocket(acceptor); + closesocket(connector); + closesocket(listener); } static void test_AcceptEx(void) diff --git a/server/sock.c b/server/sock.c index eba045c88a7..c06f0f94f6e 100644 --- a/server/sock.c +++ b/server/sock.c @@ -2604,6 +2604,17 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) unix_addr.in.sin_addr.s_addr = htonl( INADDR_LOOPBACK ); ret = connect( unix_fd, &unix_addr.addr, unix_len ); + if (ret < 0 && errno == ECONNABORTED) + { + /* On Linux with nonblocking socket if the previous connect() failed for any reason (including + * timeout), next connect will fail. If the error code was queried by getsockopt( SO_ERROR ) + * the error code returned now is ECONNABORTED (otherwise that is the actual connect() failure + * error code). If we got here after previous connect attempt on the socket that means + * we already queried SO_ERROR in sock_error(), so retrying on ECONNABORTED only is + * sufficient. */ + ret = connect( unix_fd, &unix_addr.addr, unix_len ); + } + if (ret < 0 && errno != EINPROGRESS) { set_error( sock_get_ntstatus( errno ) ); From 8874da6828e1014d3a0d4b3c33cb8932920c6a6b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 15 Feb 2023 16:30:37 -0600 Subject: [PATCH 1158/2777] server: Set TCP SYN count on sockets. (cherry picked from commit 74240a354558ce8dd3c98b4a190005de471b4c95) CW-Bug-Id: #20812 --- server/sock.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/server/sock.c b/server/sock.c index c06f0f94f6e..b02b1c75b5e 100644 --- a/server/sock.c +++ b/server/sock.c @@ -39,6 +39,9 @@ #ifdef HAVE_NETINET_IN_H # include #endif +#ifdef HAVE_NETINET_TCP_H +# include +#endif #include #include #include @@ -1923,9 +1926,12 @@ static int init_socket( struct sock *sock, int family, int type, int protocol ) if (is_tcp_socket( sock )) { - int reuse = 1; - - setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse) ); + value = 1; + setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value) ); +#ifdef TCP_SYNCNT + value = 4; + setsockopt( sockfd, IPPROTO_TCP, TCP_SYNCNT, &value, sizeof(value) ); +#endif } if (sock->fd) From 035dea703a8cbd097762ba653c0c6ef4e5ec45be Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 15 Feb 2023 21:00:47 -0600 Subject: [PATCH 1159/2777] kernelbase: Do not attempt to start winedbg if logging is disabled. CW-Bug-Id: #20812 --- dlls/kernelbase/debug.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/kernelbase/debug.c b/dlls/kernelbase/debug.c index fe28d524a8c..6973a74ad5e 100644 --- a/dlls/kernelbase/debug.c +++ b/dlls/kernelbase/debug.c @@ -555,6 +555,8 @@ static BOOL start_debugger_atomic( EXCEPTION_POINTERS *epointers ) { static HANDLE once; + if (!ERR_ON(seh)) return FALSE; + if (once == 0) { OBJECT_ATTRIBUTES attr; From 62bf8c85658ad56d788d177f53008a1f3b2e0da8 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 17 Feb 2023 16:46:24 -0600 Subject: [PATCH 1160/2777] winex11.drv: Sync parent's GL drawable when child window is destroyed. CW-Bug-Id: #21769 --- dlls/winex11.drv/opengl.c | 1 + dlls/winex11.drv/window.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index a96ef3bec1a..0cd9218fce1 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1664,6 +1664,7 @@ void sync_gl_drawable( HWND hwnd, BOOL known_child ) new_layered_type = get_gl_layered_type( hwnd ); if (old->type == DC_GL_PIXMAP_WIN || (known_child && old->type == DC_GL_WINDOW) + || (!known_child && old->type != DC_GL_WINDOW) || old->layered_type != new_layered_type) { if ((new = create_gl_drawable( hwnd, old->format, known_child, old->mutable_pf ))) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 697203dd499..47abd189860 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2228,7 +2228,10 @@ void X11DRV_DestroyWindow( HWND hwnd ) HWND parent = NtUserGetAncestor( hwnd, GA_PARENT ); if (!NtUserGetWindowRelative( parent, GW_CHILD ) && NtUserGetAncestor( parent, GA_PARENT ) == NtUserGetDesktopWindow()) + { + sync_gl_drawable( parent, FALSE ); sync_vk_surface( parent, FALSE ); + } if (!(data = get_win_data( hwnd ))) return; From 8fc9368228d1550b5357f6fe587d3e1996bcda66 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 13 Feb 2023 15:11:25 -0600 Subject: [PATCH 1161/2777] win32u: Remove monitor name from gdi driver monitor info. (cherry picked from commit 6bc1eea7182acdcdfc74c04bbfbd8710818e5b9a) --- dlls/win32u/sysparams.c | 8 +++----- dlls/winemac.drv/cocoa_display.m | 1 - dlls/winemac.drv/display.c | 3 --- dlls/winemac.drv/macdrv_cocoa.h | 2 -- dlls/winex11.drv/desktop.c | 4 ---- dlls/winex11.drv/display.c | 3 --- dlls/winex11.drv/xinerama.c | 4 ---- dlls/winex11.drv/xrandr.c | 7 ------- include/wine/gdi_driver.h | 1 - 9 files changed, 3 insertions(+), 30 deletions(-) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index cba0052577d..fc2cbd8ea9c 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -1314,12 +1314,11 @@ static void add_monitor( const struct gdi_monitor *monitor, void *param ) static const WCHAR default_monitorW[] = {'M','O','N','I','T','O','R','\\','D','e','f','a','u','l','t','_','M','o','n','i','t','o','r',0,0}; - TRACE( "%s %s %s\n", debugstr_w(monitor->name), wine_dbgstr_rect(&monitor->rc_monitor), - wine_dbgstr_rect(&monitor->rc_work) ); - monitor_index = ctx->monitor_count++; output_index = ctx->output_count++; + TRACE( "%u %s %s\n", monitor_index, wine_dbgstr_rect(&monitor->rc_monitor), wine_dbgstr_rect(&monitor->rc_work) ); + sprintf( buffer, "MonitorID%u", monitor_index ); sprintf( instance, "DISPLAY\\Default_Monitor\\%04X&%04X", ctx->video_count - 1, monitor_index ); set_reg_ascii_value( ctx->adapter_key, buffer, instance ); @@ -1330,8 +1329,7 @@ static void add_monitor( const struct gdi_monitor *monitor, void *param ) link_device( bufferW, guid_devinterface_monitorW ); - lstrcpyW( bufferW, monitor->name ); - if (!bufferW[0]) asciiz_to_unicode( bufferW, "Generic Non-PnP Monitor" ); + asciiz_to_unicode( bufferW, "Generic Non-PnP Monitor" ); set_reg_value( hkey, device_descW, REG_SZ, bufferW, (lstrlenW( bufferW ) + 1) * sizeof(WCHAR) ); set_reg_value( hkey, classW, REG_SZ, monitorW, sizeof(monitorW) ); diff --git a/dlls/winemac.drv/cocoa_display.m b/dlls/winemac.drv/cocoa_display.m index 04f6dda4481..b5096a39ca4 100644 --- a/dlls/winemac.drv/cocoa_display.m +++ b/dlls/winemac.drv/cocoa_display.m @@ -675,7 +675,6 @@ int macdrv_get_monitors(uint32_t adapter_id, struct macdrv_monitor** new_monitor if (j == 0) primary_index = monitor_count; - strcpy(monitors[monitor_count].name, "Generic Non-PnP Monitor"); monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED | DISPLAY_DEVICE_ACTIVE; monitors[monitor_count].rc_monitor = displays[j].frame; monitors[monitor_count].rc_work = displays[j].work_frame; diff --git a/dlls/winemac.drv/display.c b/dlls/winemac.drv/display.c index dab81cc8ffb..19ff72a7130 100644 --- a/dlls/winemac.drv/display.c +++ b/dlls/winemac.drv/display.c @@ -1192,9 +1192,6 @@ BOOL macdrv_UpdateDisplayDevices( const struct gdi_device_manager *device_manage .rc_work = rect_from_cgrect(monitor->rc_work), .state_flags = monitor->state_flags, }; - RtlUTF8ToUnicodeN(gdi_monitor.name, sizeof(gdi_monitor.name), &len, - monitor->name, strlen(monitor->name)); - TRACE("monitor: %s\n", debugstr_a(monitor->name)); device_manager->add_monitor( &gdi_monitor, param ); } diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index 6196032c08d..a82dd319330 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -291,8 +291,6 @@ struct macdrv_adapter /* Represent a monitor in EnumDisplayDevices context */ struct macdrv_monitor { - /* Name, in UTF-8 encoding */ - char name[128]; /* as RcMonitor in MONITORINFO struct after conversion by rect_from_cgrect */ CGRect rc_monitor; /* as RcWork in MONITORINFO struct after conversion by rect_from_cgrect */ diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c index f46fe0f5fa2..f7f49f6ca4e 100644 --- a/dlls/winex11.drv/desktop.c +++ b/dlls/winex11.drv/desktop.c @@ -287,15 +287,11 @@ static void X11DRV_desktop_free_adapters( struct gdi_adapter *adapters ) static BOOL X11DRV_desktop_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **new_monitors, int *count ) { - static const WCHAR generic_nonpnp_monitorW[] = { - 'G','e','n','e','r','i','c',' ', - 'N','o','n','-','P','n','P',' ','M','o','n','i','t','o','r',0}; struct gdi_monitor *monitor; monitor = calloc( 1, sizeof(*monitor) ); if (!monitor) return FALSE; - lstrcpyW( monitor->name, generic_nonpnp_monitorW ); SetRect( &monitor->rc_monitor, 0, 0, desktop_width, desktop_height ); SetRect( &monitor->rc_work, 0, 0, desktop_width, desktop_height ); query_desktop_work_area( &monitor->rc_work ); diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c index 25b7070a315..fe6a5b873f1 100644 --- a/dlls/winex11.drv/display.c +++ b/dlls/winex11.drv/display.c @@ -618,10 +618,7 @@ BOOL X11DRV_UpdateDisplayDevices( const struct gdi_device_manager *device_manage /* Initialize monitors */ for (monitor = 0; monitor < monitor_count; monitor++) - { - TRACE("monitor: %#x %s\n", monitor, wine_dbgstr_w(monitors[monitor].name)); device_manager->add_monitor( &monitors[monitor], param ); - } handler->free_monitors(monitors, monitor_count); diff --git a/dlls/winex11.drv/xinerama.c b/dlls/winex11.drv/xinerama.c index 588cd4e8dde..bdc611d4323 100644 --- a/dlls/winex11.drv/xinerama.c +++ b/dlls/winex11.drv/xinerama.c @@ -285,9 +285,6 @@ static void xinerama_free_adapters( struct gdi_adapter *adapters ) static BOOL xinerama_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **new_monitors, int *count ) { - static const WCHAR generic_nonpnp_monitorW[] = { - 'G','e','n','e','r','i','c',' ', - 'N','o','n','-','P','n','P',' ','M','o','n','i','t','o','r',0}; struct gdi_monitor *monitor; INT first = (INT)adapter_id; INT monitor_count = 0; @@ -317,7 +314,6 @@ static BOOL xinerama_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **ne || (EqualRect( &monitors[i].rcMonitor, &monitors[first].rcMonitor ) && !IsRectEmpty( &monitors[first].rcMonitor ))) { - lstrcpyW( monitor[index].name, generic_nonpnp_monitorW ); monitor[index].rc_monitor = monitors[i].rcMonitor; monitor[index].rc_work = monitors[i].rcWork; /* Xinerama only reports monitors already attached */ diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c index fd2b759e822..c4b3be8b40c 100644 --- a/dlls/winex11.drv/xrandr.c +++ b/dlls/winex11.drv/xrandr.c @@ -1231,9 +1231,6 @@ static void xrandr14_free_adapters( struct gdi_adapter *adapters ) static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **new_monitors, int *count ) { - static const WCHAR generic_nonpnp_monitorW[] = { - 'G','e','n','e','r','i','c',' ', - 'N','o','n','-','P','n','P',' ','M','o','n','i','t','o','r',0}; struct gdi_monitor *realloc_monitors, *monitors = NULL; XRRScreenResources *screen_resources = NULL; XRROutputInfo *output_info = NULL, *enum_output_info = NULL; @@ -1267,7 +1264,6 @@ static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **ne /* Inactive but attached monitor, no need to check for mirrored/replica monitors */ if (!output_info->crtc || !crtc_info->mode) { - lstrcpyW( monitors[monitor_count].name, generic_nonpnp_monitorW ); monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED; monitors[monitor_count].edid_len = get_edid( adapter_id, &monitors[monitor_count].edid, output_info, screen_resources ); @@ -1313,9 +1309,6 @@ static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct gdi_monitor **ne enum_crtc_info->width == crtc_info->width && enum_crtc_info->height == crtc_info->height) { - /* FIXME: Read output EDID property and parse the data to get the correct name */ - lstrcpyW( monitors[monitor_count].name, generic_nonpnp_monitorW ); - SetRect( &monitors[monitor_count].rc_monitor, crtc_info->x, crtc_info->y, crtc_info->x + crtc_info->width, crtc_info->y + crtc_info->height ); monitors[monitor_count].rc_work = get_work_area( &monitors[monitor_count].rc_monitor ); diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 1b1ebf85f1a..f87e1ceefb0 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -253,7 +253,6 @@ struct gdi_adapter struct gdi_monitor { - WCHAR name[128]; /* name */ RECT rc_monitor; /* RcMonitor in MONITORINFO struct */ RECT rc_work; /* RcWork in MONITORINFO struct */ DWORD state_flags; /* StateFlags in DISPLAY_DEVICE struct */ From 2ebc23558304ee27d9328ade8ffaa6a2ae1be896 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 13 Feb 2023 11:37:01 -0600 Subject: [PATCH 1162/2777] win32u: Use monitor ID from EDID when available. (cherry picked from commit 480a6088765694e02ea6c69cc6833031419dcde7) --- dlls/win32u/sysparams.c | 54 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index fc2cbd8ea9c..e02b9fd473d 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -218,6 +218,14 @@ struct adapter DEVMODEW *modes; }; +#define MONITOR_INFO_HAS_MONITOR_ID 0x00000001 +struct edid_monitor_info +{ + unsigned int flags; + /* MONITOR_INFO_HAS_MONITOR_ID */ + char monitor_id_string[8]; +}; + struct monitor { struct list entry; @@ -438,6 +446,30 @@ static void adapter_release( struct adapter *adapter ) C_ASSERT(sizeof(DEVMODEW) - offsetof(DEVMODEW, dmFields) == 0x94); +static void get_monitor_info_from_edid( struct edid_monitor_info *info, const unsigned char *edid, unsigned int edid_len ) +{ + unsigned short w; + unsigned char d; + unsigned int i; + + info->flags = 0; + if (!edid || edid_len < 128) return; + + w = (edid[8] << 8) | edid[9]; /* Manufacturer ID, big endian. */ + for (i = 0; i < 3; ++i) + { + d = w & 0x1f; + if (!d || d - 1 > 'Z' - 'A') return; + info->monitor_id_string[2 - i] = 'A' + d - 1; + w >>= 5; + } + if (w) return; + w = edid[10] | (edid[11] << 8); /* Product code, little endian. */ + sprintf( info->monitor_id_string + 3, "%04X", w ); + info->flags = MONITOR_INFO_HAS_MONITOR_ID; + TRACE( "Monitor id %s.\n", info->monitor_id_string ); +} + static BOOL write_adapter_mode( HKEY adapter_key, UINT index, const DEVMODEW *mode ) { WCHAR bufferW[MAX_PATH] = {0}; @@ -874,7 +906,7 @@ static void prepare_devices(void) REG_OPTION_VOLATILE, NULL ); /* delete monitors */ - reg_empty_key( enum_key, "DISPLAY\\DEFAULT_MONITOR" ); + reg_empty_key( enum_key, "DISPLAY" ); sprintf( buffer, "Class\\%s", guid_devclass_monitorA ); hkey = reg_create_key( control_key, bufferW, asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR), 0, NULL ); @@ -1308,19 +1340,25 @@ static void add_monitor( const struct gdi_monitor *monitor, void *param ) struct device_manager_ctx *ctx = param; char buffer[MAX_PATH], instance[64]; unsigned int monitor_index, output_index; + struct edid_monitor_info monitor_info; + char monitor_id_string[16]; WCHAR bufferW[MAX_PATH]; HKEY hkey, subkey; - - static const WCHAR default_monitorW[] = - {'M','O','N','I','T','O','R','\\','D','e','f','a','u','l','t','_','M','o','n','i','t','o','r',0,0}; + unsigned int len; monitor_index = ctx->monitor_count++; output_index = ctx->output_count++; TRACE( "%u %s %s\n", monitor_index, wine_dbgstr_rect(&monitor->rc_monitor), wine_dbgstr_rect(&monitor->rc_work) ); + get_monitor_info_from_edid( &monitor_info, monitor->edid, monitor->edid_len ); + if (monitor_info.flags & MONITOR_INFO_HAS_MONITOR_ID) + strcpy( monitor_id_string, monitor_info.monitor_id_string ); + else + strcpy( monitor_id_string, "Default_Monitor" ); + sprintf( buffer, "MonitorID%u", monitor_index ); - sprintf( instance, "DISPLAY\\Default_Monitor\\%04X&%04X", ctx->video_count - 1, monitor_index ); + sprintf( instance, "DISPLAY\\%s\\%04X&%04X", monitor_id_string, ctx->video_count - 1, monitor_index ); set_reg_ascii_value( ctx->adapter_key, buffer, instance ); hkey = reg_create_key( enum_key, bufferW, asciiz_to_unicode( bufferW, instance ) - sizeof(WCHAR), @@ -1336,7 +1374,11 @@ static void add_monitor( const struct gdi_monitor *monitor, void *param ) sprintf( buffer, "%s\\%04X", guid_devclass_monitorA, output_index ); set_reg_ascii_value( hkey, "Driver", buffer ); set_reg_value( hkey, class_guidW, REG_SZ, guid_devclass_monitorW, sizeof(guid_devclass_monitorW) ); - set_reg_value( hkey, hardware_idW, REG_MULTI_SZ, default_monitorW, sizeof(default_monitorW) ); + + sprintf( buffer, "MONITOR\\%s", monitor_id_string ); + len = asciiz_to_unicode( bufferW, buffer ); + bufferW[len / sizeof(WCHAR)] = 0; + set_reg_value( hkey, hardware_idW, REG_MULTI_SZ, bufferW, len + sizeof(WCHAR) ); if ((subkey = reg_create_key( hkey, device_parametersW, sizeof(device_parametersW), 0, NULL ))) { From c8be8fa67cee5fe006e3bcdab9468301aafaa46f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 13 Feb 2023 14:32:09 -0600 Subject: [PATCH 1163/2777] win32u: Store EDID info in monitors cache. (cherry picked from commit 76713da1e013e939c91077c6b36cc3ff31357f85) --- dlls/win32u/sysparams.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index e02b9fd473d..f4c4108bbbb 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -170,6 +170,7 @@ static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0}; static const WCHAR yesW[] = {'Y','e','s',0}; static const WCHAR noW[] = {'N','o',0}; static const WCHAR mode_countW[] = {'M','o','d','e','C','o','u','n','t',0}; +static const WCHAR edidW[] = {'E','D','I','D',0}; static const char guid_devclass_displayA[] = "{4D36E968-E325-11CE-BFC1-08002BE10318}"; static const WCHAR guid_devclass_displayW[] = @@ -238,6 +239,7 @@ struct monitor RECT rc_monitor; RECT rc_work; BOOL is_clone; + struct edid_monitor_info edid_info; }; static struct list adapters = LIST_INIT(adapters); @@ -749,7 +751,7 @@ static BOOL read_monitor_settings( struct adapter *adapter, UINT index, struct m char buffer[4096]; KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer; WCHAR *device_name, *value_str = (WCHAR *)value->Data, *ptr; - HKEY hkey; + HKEY hkey, subkey; DWORD size, len; monitor->flags = adapter->id ? 0 : MONITORINFOF_PRIMARY; @@ -856,6 +858,14 @@ static BOOL read_monitor_settings( struct adapter *adapter, UINT index, struct m monitor->dev.device_id[size++] = '\\'; lstrcpyW( monitor->dev.device_id + size, device_name ); + /* EDID */ + if ((subkey = reg_open_key( hkey, device_parametersW, sizeof(device_parametersW) ))) + { + if (query_reg_value( subkey, edidW, value, sizeof(buffer) )) + get_monitor_info_from_edid( &monitor->edid_info, value->Data, value->DataLength ); + NtClose( subkey ); + } + NtClose( hkey ); return TRUE; } @@ -1383,7 +1393,6 @@ static void add_monitor( const struct gdi_monitor *monitor, void *param ) if ((subkey = reg_create_key( hkey, device_parametersW, sizeof(device_parametersW), 0, NULL ))) { static const WCHAR bad_edidW[] = {'B','A','D','_','E','D','I','D',0}; - static const WCHAR edidW[] = {'E','D','I','D',0}; if (monitor->edid_len) set_reg_value( subkey, edidW, REG_BINARY, monitor->edid, monitor->edid_len ); From 46f0d0921a73795bbd15982a2246084426411c90 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 13 Feb 2023 14:56:10 -0600 Subject: [PATCH 1164/2777] win32u: Return edidManufactureId and edidProductCodeId from NtUserDisplayConfigGetDeviceInfo(). (cherry picked from commit f00dcb4bd54ea0d39956692d34b67d7a35eee2bd) CW-Bug-Id: #21894 --- dlls/win32u/sysparams.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index f4c4108bbbb..996cc14b58a 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -224,6 +224,7 @@ struct edid_monitor_info { unsigned int flags; /* MONITOR_INFO_HAS_MONITOR_ID */ + unsigned short manufacturer, product_code; char monitor_id_string[8]; }; @@ -467,6 +468,8 @@ static void get_monitor_info_from_edid( struct edid_monitor_info *info, const un } if (w) return; w = edid[10] | (edid[11] << 8); /* Product code, little endian. */ + info->manufacturer = *(unsigned short *)(edid + 8); + info->product_code = w; sprintf( info->monitor_id_string + 3, "%04X", w ); info->flags = MONITOR_INFO_HAS_MONITOR_ID; TRACE( "Monitor id %s.\n", info->monitor_id_string ); @@ -5785,6 +5788,12 @@ NTSTATUS WINAPI NtUserDisplayConfigGetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEAD snprintf( buffer, ARRAY_SIZE(buffer), "Display%u", monitor->output_id + 1 ); asciiz_to_unicode( target_name->monitorFriendlyDeviceName, buffer ); lstrcpyW( target_name->monitorDevicePath, monitor->dev.interface_name ); + if (monitor->edid_info.flags & MONITOR_INFO_HAS_MONITOR_ID) + { + target_name->edidManufactureId = monitor->edid_info.manufacturer; + target_name->edidProductCodeId = monitor->edid_info.product_code; + target_name->flags.edidIdsValid = 1; + } ret = STATUS_SUCCESS; break; } From 71d4f8121c9dcf14d6f0ceb4bb4409a58244cb44 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 13 Feb 2023 15:55:31 -0600 Subject: [PATCH 1165/2777] win32u: Get friendly monitor name from EDID in NtUserDisplayConfigGetDeviceInfo(). (cherry picked from commit 1f31fda00a7126c5ba3defa55f7cba2c550c1686) CW-Bug-Id: #21894 --- dlls/win32u/sysparams.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 996cc14b58a..bfff39e8767 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -220,12 +220,15 @@ struct adapter }; #define MONITOR_INFO_HAS_MONITOR_ID 0x00000001 +#define MONITOR_INFO_HAS_MONITOR_NAME 0x00000002 struct edid_monitor_info { unsigned int flags; /* MONITOR_INFO_HAS_MONITOR_ID */ unsigned short manufacturer, product_code; char monitor_id_string[8]; + /* MONITOR_INFO_HAS_MONITOR_NAME */ + WCHAR monitor_name[14]; }; struct monitor @@ -451,9 +454,10 @@ C_ASSERT(sizeof(DEVMODEW) - offsetof(DEVMODEW, dmFields) == 0x94); static void get_monitor_info_from_edid( struct edid_monitor_info *info, const unsigned char *edid, unsigned int edid_len ) { + unsigned int i, j; unsigned short w; unsigned char d; - unsigned int i; + const char *s; info->flags = 0; if (!edid || edid_len < 128) return; @@ -473,6 +477,19 @@ static void get_monitor_info_from_edid( struct edid_monitor_info *info, const un sprintf( info->monitor_id_string + 3, "%04X", w ); info->flags = MONITOR_INFO_HAS_MONITOR_ID; TRACE( "Monitor id %s.\n", info->monitor_id_string ); + + for (i = 0; i < 4; ++i) + { + if (edid[54 + i * 18 + 3] != 0xfc) continue; + /* "Display name" ASCII descriptor. */ + s = (const char *)&edid[54 + i * 18 + 5]; + for (j = 0; s[j] && j < 13; ++j) + info->monitor_name[j] = s[j]; + while (j && isspace(s[j - 1])) --j; + info->monitor_name[j] = 0; + info->flags |= MONITOR_INFO_HAS_MONITOR_NAME; + break; + } } static BOOL write_adapter_mode( HKEY adapter_key, UINT index, const DEVMODEW *mode ) @@ -5784,7 +5801,6 @@ NTSTATUS WINAPI NtUserDisplayConfigGetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEAD continue; target_name->outputTechnology = DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL; - /* FIXME: get real monitor name. */ snprintf( buffer, ARRAY_SIZE(buffer), "Display%u", monitor->output_id + 1 ); asciiz_to_unicode( target_name->monitorFriendlyDeviceName, buffer ); lstrcpyW( target_name->monitorDevicePath, monitor->dev.interface_name ); @@ -5794,6 +5810,11 @@ NTSTATUS WINAPI NtUserDisplayConfigGetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEAD target_name->edidProductCodeId = monitor->edid_info.product_code; target_name->flags.edidIdsValid = 1; } + if (monitor->edid_info.flags & MONITOR_INFO_HAS_MONITOR_NAME) + { + wcscpy( target_name->monitorFriendlyDeviceName, monitor->edid_info.monitor_name ); + target_name->flags.friendlyNameFromEdid = 1; + } ret = STATUS_SUCCESS; break; } From 1c595e51bfc6ff0c299dcaf8d4bb9013b1625fc1 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 13 Feb 2023 17:06:08 -0600 Subject: [PATCH 1166/2777] winex11.drv: Use EDID suggested by Gamescope. CW-Bug-Id: #21894 --- dlls/winex11.drv/x11drv.h | 1 + dlls/winex11.drv/x11drv_main.c | 3 ++- dlls/winex11.drv/xrandr.c | 26 ++++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index ca500c3d96d..5413f82f54a 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -565,6 +565,7 @@ enum x11drv_atoms XATOM_text_richtext, XATOM_text_uri_list, XATOM_GAMESCOPE_FOCUSED_APP, + XATOM_GAMESCOPE_DISPLAY_EDID_PATH, NB_XATOMS }; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index fefe8ddcec0..9d534c1bcf7 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -235,7 +235,8 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = "text/rtf", "text/richtext", "text/uri-list", - "GAMESCOPE_FOCUSED_APP" + "GAMESCOPE_FOCUSED_APP", + "GAMESCOPE_DISPLAY_EDID_PATH", }; /*********************************************************************** diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c index c4b3be8b40c..35998877520 100644 --- a/dlls/winex11.drv/xrandr.c +++ b/dlls/winex11.drv/xrandr.c @@ -456,6 +456,7 @@ static unsigned int get_edid( RROutput output, unsigned char **prop, int result, actual_format; XRRModeInfo *mode; Atom actual_type; + char *edid_path; *prop = NULL; result = pXRRGetOutputProperty( gdi_display, output, x11drv_atom(EDID), 0, 128, FALSE, FALSE, @@ -472,6 +473,31 @@ static unsigned int get_edid( RROutput output, unsigned char **prop, return len; } + edid_path = NULL; + if ((result = XGetWindowProperty( gdi_display, DefaultRootWindow(gdi_display), x11drv_atom(GAMESCOPE_DISPLAY_EDID_PATH), 0, + PATH_MAX, False, x11drv_atom(UTF8_STRING), &actual_type, &actual_format, + &len, &bytes_after, (unsigned char **)&edid_path )) == Success + && actual_type == x11drv_atom(UTF8_STRING)) + { + char buffer[4096]; + FILE *f; + + f = fopen( edid_path, "rb" ); + if (f) + { + len = fread( buffer, 1, sizeof(buffer), f ); + fclose( f ); + if (len) + { + XFree( edid_path ); + if (!(*prop = malloc( len ))) return 0; + memcpy( *prop, buffer, len ); + return len; + } + } + } + if (edid_path) XFree( edid_path ); + WARN( "Could not retrieve EDID property for output %#lx.\n", output ); if (!output_info->npreferred) { From 2286eca2103bc2b4d05eab6cbb8199883aaa0c01 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Fri, 25 Nov 2022 18:32:11 -0500 Subject: [PATCH 1167/2777] HACK: winegstreamer: Expose S16LE as the first native media type in MFSourceReader. Metal Gear Solid V: The Phantom Pain expects the bps of first native media type returned by MFSourceReader, of a WMA Pro audio stream, to be 16. Here, we ensure that S16LE is exposed first before the preferred format of the gstreamer pipeline. CW-Bug-Id: #21407 --- dlls/winegstreamer/media_source.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index da65785b54a..97c00bb4d35 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -918,26 +918,32 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) else if (format.major_type == WG_MAJOR_TYPE_AUDIO) { /* Expose at least one PCM and one floating point type for the - consumer to pick from. */ + consumer to pick from. Moreover, ensure that we expose S16LE first, + as games such as MGSV expect the native media type to be 16 bps. */ static const enum wg_audio_format audio_types[] = { WG_AUDIO_FORMAT_S16LE, WG_AUDIO_FORMAT_F32LE, }; - if ((stream_types[0] = mf_media_type_from_wg_format(&format))) - type_count = 1; + BOOL has_native_format = FALSE; for (i = 0; i < ARRAY_SIZE(audio_types); i++) { struct wg_format new_format; - if (format.u.audio.format == audio_types[i]) - continue; + new_format = format; new_format.u.audio.format = audio_types[i]; if ((stream_types[type_count] = mf_media_type_from_wg_format(&new_format))) + { + if (format.u.audio.format == audio_types[i]) + has_native_format = TRUE; type_count++; + } } + + if (!has_native_format && (stream_types[type_count] = mf_media_type_from_wg_format(&format))) + type_count++; } else { From dd05e127829720f2ecf4180d58de1e937020d400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 24 Feb 2023 13:05:06 +0100 Subject: [PATCH 1168/2777] include: Add Windows.Globalization.GeographicRegion runtimeclass. CW-Bug-Id: #21875 --- include/windows.globalization.idl | 53 +++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/include/windows.globalization.idl b/include/windows.globalization.idl index 639d0d24411..49b484f6467 100644 --- a/include/windows.globalization.idl +++ b/include/windows.globalization.idl @@ -40,7 +40,11 @@ namespace Windows { interface ILanguageStatics; interface ILanguageStatics2; interface ILanguageStatics3; + interface IGeographicRegion; + interface IGeographicRegionFactory; + interface IGeographicRegionStatics; runtimeclass Language; + runtimeclass GeographicRegion; } } @@ -163,6 +167,42 @@ namespace Windows { HRESULT GetMuiCompatibleLanguageListFromLanguageTags([in] Windows.Foundation.Collections.IIterable *tags, [out, retval] Windows.Foundation.Collections.IVector **result); } + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Globalization.GeographicRegion), + uuid(01e9a621-4a64-4ed9-954f-9edeb07bd903) + ] + interface IGeographicRegion : IInspectable + { + [propget] HRESULT Code([out, retval] HSTRING *value); + [propget] HRESULT CodeTwoLetter([out, retval] HSTRING *value); + [propget] HRESULT CodeThreeLetter([out, retval] HSTRING *value); + [propget] HRESULT CodeThreeDigit([out, retval] HSTRING *value); + [propget] HRESULT DisplayName([out, retval] HSTRING *value); + [propget] HRESULT NativeName([out, retval] HSTRING *value); + [propget] HRESULT CurrenciesInUse([out, retval] Windows.Foundation.Collections.IVectorView **value); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Globalization.GeographicRegion), + uuid(53425270-77b4-426b-859f-81e19d512546) + ] + interface IGeographicRegionFactory : IInspectable + { + HRESULT CreateGeographicRegion([in] HSTRING region_code, [out, retval] Windows.Globalization.GeographicRegion **result); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.Globalization.GeographicRegion), + uuid(29e28974-7ad9-4ef4-8799-b3b44fadec08) + ] + interface IGeographicRegionStatics : IInspectable + { + HRESULT IsSupported([in] HSTRING region_code, [out, retval] boolean *result); + } + [ activatable(Windows.Globalization.ILanguageFactory, Windows.Foundation.UniversalApiContract, 1.0), contract(Windows.Foundation.UniversalApiContract, 1.0), @@ -179,5 +219,18 @@ namespace Windows { [contract(Windows.Foundation.UniversalApiContract, 6.0)] interface Windows.Globalization.ILanguage2; [contract(Windows.Foundation.UniversalApiContract, 10.0)] interface Windows.Globalization.ILanguage3; } + + [ + activatable(Windows.Foundation.UniversalApiContract, 1.0), + activatable(Windows.Globalization.IGeographicRegionFactory, Windows.Foundation.UniversalApiContract, 1.0), + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile), + static(Windows.Globalization.IGeographicRegionStatics, Windows.Foundation.UniversalApiContract, 1.0), + threading(both) + ] + runtimeclass GeographicRegion + { + [contract(Windows.Foundation.UniversalApiContract, 1.0), default] interface Windows.Globalization.IGeographicRegion; + } } } From f5f9634d5664a786f4a1ea5b98e9feded05f42b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 24 Feb 2023 13:16:36 +0100 Subject: [PATCH 1169/2777] include: Add Windows.System.Profile.AnalyticsInfo runtimeclass. CW-Bug-Id: #21875 --- include/Makefile.in | 1 + include/windows.system.profile.idl | 86 ++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 include/windows.system.profile.idl diff --git a/include/Makefile.in b/include/Makefile.in index 44c95a7f47c..3a06dbcabe4 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -821,6 +821,7 @@ SOURCES = \ windows.storage.streams.idl \ windows.system.idl \ windows.system.power.idl \ + windows.system.profile.idl \ windows.system.threading.idl \ windows.system.userprofile.idl \ windows.ui.idl \ diff --git a/include/windows.system.profile.idl b/include/windows.system.profile.idl new file mode 100644 index 00000000000..90a561ced07 --- /dev/null +++ b/include/windows.system.profile.idl @@ -0,0 +1,86 @@ +/* + * Copyright 2023 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 + */ + +#ifdef __WIDL__ +#pragma winrt ns_prefix +#endif + +#ifndef DO_NO_IMPORTS +import "inspectable.idl"; +import "asyncinfo.idl"; +import "eventtoken.idl"; +import "windowscontracts.idl"; +import "windows.foundation.idl"; +import "windows.storage.streams.idl"; +import "windows.system.idl"; +#endif + +namespace Windows.System.Profile { + + interface IAnalyticsInfoStatics; + interface IAnalyticsInfoStatics2; + interface IAnalyticsVersionInfo; + interface IAnalyticsVersionInfo2; + runtimeclass AnalyticsVersionInfo; + runtimeclass AnalyticsInfo; + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.System.Profile.AnalyticsInfo), + uuid(1d5ee066-188d-5ba9-4387-acaeb0e7e305) + ] + interface IAnalyticsInfoStatics : IInspectable + { + [propget] HRESULT VersionInfo([out, retval] Windows.System.Profile.AnalyticsVersionInfo **value); + [propget] HRESULT DeviceForm([out, retval] HSTRING *value); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.System.Profile.AnalyticsVersionInfo), + uuid(926130b8-9955-4c74-bdc1-7cd0decf9b03) + ] + interface IAnalyticsVersionInfo : IInspectable + { + [propget] HRESULT DeviceFamily([out, retval] HSTRING *value); + [propget] HRESULT DeviceFamilyVersion([out, retval] HSTRING *value); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile), + threading(both) + ] + runtimeclass AnalyticsVersionInfo + { + [default] interface Windows.System.Profile.IAnalyticsVersionInfo; + [contract(Windows.Foundation.UniversalApiContract, 11.0)] interface Windows.System.Profile.IAnalyticsVersionInfo2; + } + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile), + static(Windows.System.Profile.IAnalyticsInfoStatics, Windows.Foundation.UniversalApiContract, 1.0), + static(Windows.System.Profile.IAnalyticsInfoStatics2, Windows.Foundation.UniversalApiContract, 6.0), + threading(both) + ] + runtimeclass AnalyticsInfo + { + } + +} From 38bf4812da3c655dcba0b540d50e6301fb813518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Feb 2023 22:35:47 +0100 Subject: [PATCH 1170/2777] windows.globalization: Stub Windows.Globalization.GeographicRegion. CW-Bug-Id: #21875 --- dlls/windows.globalization/Makefile.in | 1 + .../windows.globalization/geographic_region.c | 286 ++++++++++++++++++ dlls/windows.globalization/main.c | 33 +- .../windows.globalization/winewinrt_classes.h | 91 ++++++ 4 files changed, 384 insertions(+), 27 deletions(-) create mode 100644 dlls/windows.globalization/geographic_region.c create mode 100644 dlls/windows.globalization/winewinrt_classes.h diff --git a/dlls/windows.globalization/Makefile.in b/dlls/windows.globalization/Makefile.in index d29c44ea746..a4d2d501e0f 100644 --- a/dlls/windows.globalization/Makefile.in +++ b/dlls/windows.globalization/Makefile.in @@ -2,6 +2,7 @@ MODULE = windows.globalization.dll IMPORTS = combase uuid C_SRCS = \ + geographic_region.c \ main.c IDL_SRCS = classes.idl diff --git a/dlls/windows.globalization/geographic_region.c b/dlls/windows.globalization/geographic_region.c new file mode 100644 index 00000000000..a1a3d9e837e --- /dev/null +++ b/dlls/windows.globalization/geographic_region.c @@ -0,0 +1,286 @@ +/* WinRT Windows.Globalization implementation + * + * 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 + */ + +#include "winewinrt_classes.h" + +WINE_DEFAULT_DEBUG_CHANNEL(locale); + +struct geographic_region +{ + IGeographicRegion IGeographicRegion_iface; + LONG ref; +}; + +static inline struct geographic_region *impl_from_IGeographicRegion( IGeographicRegion *iface ) +{ + return CONTAINING_RECORD( iface, struct geographic_region, IGeographicRegion_iface ); +} + +static HRESULT WINAPI geographic_region_QueryInterface( IGeographicRegion *iface, REFIID iid, void **out ) +{ + struct geographic_region *impl = impl_from_IGeographicRegion( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IGeographicRegion )) + { + IInspectable_AddRef( (*out = &impl->IGeographicRegion_iface) ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI geographic_region_AddRef( IGeographicRegion *iface ) +{ + struct geographic_region *impl = impl_from_IGeographicRegion( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI geographic_region_Release( IGeographicRegion *iface ) +{ + struct geographic_region *impl = impl_from_IGeographicRegion( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + if (!ref) free( impl ); + return ref; +} + +static HRESULT WINAPI geographic_region_GetIids( IGeographicRegion *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI geographic_region_GetRuntimeClassName( IGeographicRegion *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI geographic_region_GetTrustLevel( IGeographicRegion *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI geographic_region_get_Code( IGeographicRegion *iface, HSTRING *value ) +{ + FIXME( "iface %p stub!\n", iface ); + return E_NOTIMPL; +} + +static HRESULT WINAPI geographic_region_get_CodeTwoLetter( IGeographicRegion *iface, HSTRING *value ) +{ + WCHAR buffer[LOCALE_NAME_MAX_LENGTH]; + + FIXME( "iface %p semi-stub!\n", iface ); + + if (!GetLocaleInfoEx( LOCALE_NAME_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, buffer, ARRAY_SIZE(buffer) )) return E_INVALIDARG; + return WindowsCreateString( buffer, wcslen( buffer ), value ); +} + +static HRESULT WINAPI geographic_region_get_CodeThreeLetter( IGeographicRegion *iface, HSTRING *value ) +{ + FIXME( "iface %p stub!\n", iface ); + return E_NOTIMPL; +} + +static HRESULT WINAPI geographic_region_get_CodeThreeDigit( IGeographicRegion *iface, HSTRING *value ) +{ + FIXME( "iface %p stub!\n", iface ); + return E_NOTIMPL; +} + +static HRESULT WINAPI geographic_region_get_DisplayName( IGeographicRegion *iface, HSTRING *value ) +{ + FIXME( "iface %p stub!\n", iface ); + return E_NOTIMPL; +} + +static HRESULT WINAPI geographic_region_get_NativeName( IGeographicRegion *iface, HSTRING *value ) +{ + FIXME( "iface %p stub!\n", iface ); + return E_NOTIMPL; +} + +static HRESULT WINAPI geographic_region_get_CurrenciesInUse( IGeographicRegion *iface, IVectorView_HSTRING **value ) +{ + FIXME( "iface %p stub!\n", iface ); + return E_NOTIMPL; +} + +static const struct IGeographicRegionVtbl geographic_region_vtbl = +{ + geographic_region_QueryInterface, + geographic_region_AddRef, + geographic_region_Release, + /* IInspectable methods */ + geographic_region_GetIids, + geographic_region_GetRuntimeClassName, + geographic_region_GetTrustLevel, + /* IGeographicRegion methods */ + geographic_region_get_Code, + geographic_region_get_CodeTwoLetter, + geographic_region_get_CodeThreeLetter, + geographic_region_get_CodeThreeDigit, + geographic_region_get_DisplayName, + geographic_region_get_NativeName, + geographic_region_get_CurrenciesInUse, +}; + +struct geographic_region_factory +{ + IActivationFactory IActivationFactory_iface; + IGeographicRegionFactory IGeographicRegionFactory_iface; + LONG ref; +}; + +static inline struct geographic_region_factory *impl_from_IActivationFactory( IActivationFactory *iface ) +{ + return CONTAINING_RECORD( iface, struct geographic_region_factory, IActivationFactory_iface ); +} + +static HRESULT WINAPI activation_factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out ) +{ + struct geographic_region_factory *factory = impl_from_IActivationFactory( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IActivationFactory )) + { + IUnknown_AddRef( iface ); + *out = iface; + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IGeographicRegionFactory )) + { + IUnknown_AddRef( iface ); + *out = &factory->IGeographicRegionFactory_iface; + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI activation_factory_AddRef( IActivationFactory *iface ) +{ + struct geographic_region_factory *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI activation_factory_Release( IActivationFactory *iface ) +{ + struct geographic_region_factory *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static HRESULT WINAPI activation_factory_GetIids( IActivationFactory *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI activation_factory_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI activation_factory_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI activation_factory_ActivateInstance( IActivationFactory *iface, IInspectable **out ) +{ + struct geographic_region *region; + + TRACE( "iface %p, out %p.\n", iface, out ); + + if (!(region = calloc( 1, sizeof(*region) ))) return E_OUTOFMEMORY; + + region->IGeographicRegion_iface.lpVtbl = &geographic_region_vtbl; + region->ref = 1; + + *out = (IInspectable *)®ion->IGeographicRegion_iface; + return S_OK; +} + +static const struct IActivationFactoryVtbl activation_factory_vtbl = +{ + activation_factory_QueryInterface, + activation_factory_AddRef, + activation_factory_Release, + /* IInspectable methods */ + activation_factory_GetIids, + activation_factory_GetRuntimeClassName, + activation_factory_GetTrustLevel, + /* IActivationFactory methods */ + activation_factory_ActivateInstance, +}; + +DEFINE_IINSPECTABLE( geographic_region_factory, IGeographicRegionFactory, struct geographic_region_factory, IActivationFactory_iface ) + +static HRESULT WINAPI geographic_region_factory_CreateGeographicRegion( IGeographicRegionFactory *iface, HSTRING code, + IGeographicRegion **value ) +{ + FIXME( "iface %p, code %p, value %p stub!\n", iface, code, value ); + return E_NOTIMPL; +} + +static const struct IGeographicRegionFactoryVtbl geographic_region_factory_vtbl = +{ + geographic_region_factory_QueryInterface, + geographic_region_factory_AddRef, + geographic_region_factory_Release, + /* IInspectable methods */ + geographic_region_factory_GetIids, + geographic_region_factory_GetRuntimeClassName, + geographic_region_factory_GetTrustLevel, + /* IGeographicRegionFactory methods */ + geographic_region_factory_CreateGeographicRegion, +}; + +static struct geographic_region_factory factory = +{ + {&activation_factory_vtbl}, + {&geographic_region_factory_vtbl}, + 0, +}; + +IInspectable *globalization_geographic_region_factory = (IInspectable *)&factory.IActivationFactory_iface; diff --git a/dlls/windows.globalization/main.c b/dlls/windows.globalization/main.c index d5a5895938f..b7bc2d72eeb 100644 --- a/dlls/windows.globalization/main.c +++ b/dlls/windows.globalization/main.c @@ -17,37 +17,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include - -#define COBJMACROS -#include "windef.h" -#include "winbase.h" -#include "winstring.h" -#include "wine/debug.h" -#include "objbase.h" - #include "initguid.h" -#include "activation.h" - -#define WIDL_using_Windows_Foundation -#define WIDL_using_Windows_Foundation_Collections -#include "windows.foundation.h" -#define WIDL_using_Windows_Globalization -#include "windows.globalization.h" -#define WIDL_using_Windows_System_UserProfile -#include "windows.system.userprofile.h" +#include "winewinrt_classes.h" WINE_DEFAULT_DEBUG_CHANNEL(locale); -static const char *debugstr_hstring(HSTRING hstr) -{ - const WCHAR *str; - UINT32 len; - if (hstr && !((ULONG_PTR)hstr >> 16)) return "(invalid)"; - str = WindowsGetStringRawBuffer(hstr, &len); - return wine_dbgstr_wn(str, len); -} - struct hstring_vector { IVectorView_HSTRING IVectorView_HSTRING_iface; @@ -753,6 +727,11 @@ HRESULT WINAPI DllGetActivationFactory(HSTRING classid, IActivationFactory **fac *factory = &language_factory.IActivationFactory_iface; IUnknown_AddRef(*factory); } + else if (!wcscmp(name, RuntimeClass_Windows_Globalization_GeographicRegion)) + { + *factory = (IActivationFactory *)globalization_geographic_region_factory; + IUnknown_AddRef(*factory); + } if (*factory) return S_OK; return CLASS_E_CLASSNOTAVAILABLE; diff --git a/dlls/windows.globalization/winewinrt_classes.h b/dlls/windows.globalization/winewinrt_classes.h new file mode 100644 index 00000000000..4d64dc6d6cd --- /dev/null +++ b/dlls/windows.globalization/winewinrt_classes.h @@ -0,0 +1,91 @@ +/* WinRT Windows.Globalization implementation + * + * 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 + */ + +#include +#include + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" +#include "winstring.h" +#include "activation.h" + +#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections +#define WIDL_using_Windows_Foundation_Numerics +#include "windows.foundation.h" + +#define WIDL_using_Windows_Globalization +#define WIDL_using_Windows_System_UserProfile +#include "windows.globalization.h" +#include "windows.system.userprofile.h" + +extern IInspectable *globalization_geographic_region_factory; + +#include "wine/debug.h" +#include "wine/list.h" + +#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr ) \ + static inline impl_type *impl_from( iface_type *iface ) \ + { \ + return CONTAINING_RECORD( iface, impl_type, iface_mem ); \ + } \ + static HRESULT WINAPI pfx##_QueryInterface( iface_type *iface, REFIID iid, void **out ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_QueryInterface( (IInspectable *)(expr), iid, out ); \ + } \ + static ULONG WINAPI pfx##_AddRef( iface_type *iface ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_AddRef( (IInspectable *)(expr) ); \ + } \ + static ULONG WINAPI pfx##_Release( iface_type *iface ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_Release( (IInspectable *)(expr) ); \ + } \ + static HRESULT WINAPI pfx##_GetIids( iface_type *iface, ULONG *iid_count, IID **iids ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetIids( (IInspectable *)(expr), iid_count, iids ); \ + } \ + static HRESULT WINAPI pfx##_GetRuntimeClassName( iface_type *iface, HSTRING *class_name ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetRuntimeClassName( (IInspectable *)(expr), class_name ); \ + } \ + static HRESULT WINAPI pfx##_GetTrustLevel( iface_type *iface, TrustLevel *trust_level ) \ + { \ + impl_type *impl = impl_from( iface ); \ + return IInspectable_GetTrustLevel( (IInspectable *)(expr), trust_level ); \ + } +#define DEFINE_IINSPECTABLE( pfx, iface_type, impl_type, base_iface ) \ + DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, &impl->base_iface ) +#define DEFINE_IINSPECTABLE_OUTER( pfx, iface_type, impl_type, outer_iface ) \ + DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, impl->outer_iface ) + +static inline const char *debugstr_hstring( HSTRING hstr ) +{ + const WCHAR *str; + UINT32 len; + if (hstr && !((ULONG_PTR)hstr >> 16)) return "(invalid)"; + str = WindowsGetStringRawBuffer( hstr, &len ); + return wine_dbgstr_wn( str, len ); +} From 609ae9d72f75dec976697e26553ea7856f975a46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 24 Feb 2023 13:05:06 +0100 Subject: [PATCH 1171/2777] windows.globalization: Stub Windows.System.Profile.AnalyticsInfo class. CW-Bug-Id: #21875 --- dlls/windows.globalization/Makefile.in | 1 + dlls/windows.globalization/analytics_info.c | 254 ++++++++++++++++++ dlls/windows.globalization/classes.idl | 1 + dlls/windows.globalization/main.c | 5 + .../windows.globalization/winewinrt_classes.h | 3 + 5 files changed, 264 insertions(+) create mode 100644 dlls/windows.globalization/analytics_info.c diff --git a/dlls/windows.globalization/Makefile.in b/dlls/windows.globalization/Makefile.in index a4d2d501e0f..c8db5674405 100644 --- a/dlls/windows.globalization/Makefile.in +++ b/dlls/windows.globalization/Makefile.in @@ -2,6 +2,7 @@ MODULE = windows.globalization.dll IMPORTS = combase uuid C_SRCS = \ + analytics_info.c \ geographic_region.c \ main.c diff --git a/dlls/windows.globalization/analytics_info.c b/dlls/windows.globalization/analytics_info.c new file mode 100644 index 00000000000..273b6be94e9 --- /dev/null +++ b/dlls/windows.globalization/analytics_info.c @@ -0,0 +1,254 @@ +/* WinRT Windows.Globalization implementation + * + * 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 + */ + +#include "winewinrt_classes.h" + +WINE_DEFAULT_DEBUG_CHANNEL(locale); + +struct analytics_version_info +{ + IAnalyticsVersionInfo IAnalyticsVersionInfo_iface; + LONG ref; +}; + +static inline struct analytics_version_info *impl_from_IAnalyticsVersionInfo( IAnalyticsVersionInfo *iface ) +{ + return CONTAINING_RECORD( iface, struct analytics_version_info, IAnalyticsVersionInfo_iface ); +} + +static HRESULT WINAPI analytics_version_info_QueryInterface( IAnalyticsVersionInfo *iface, REFIID iid, void **out ) +{ + struct analytics_version_info *impl = impl_from_IAnalyticsVersionInfo( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IAnalyticsVersionInfo )) + { + IUnknown_AddRef( &impl->IAnalyticsVersionInfo_iface ); + *out = iface; + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI analytics_version_info_AddRef( IAnalyticsVersionInfo *iface ) +{ + struct analytics_version_info *impl = impl_from_IAnalyticsVersionInfo( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI analytics_version_info_Release( IAnalyticsVersionInfo *iface ) +{ + struct analytics_version_info *impl = impl_from_IAnalyticsVersionInfo( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + if (!ref) free( impl ); + return ref; +} + +static HRESULT WINAPI analytics_version_info_GetIids( IAnalyticsVersionInfo *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI analytics_version_info_GetRuntimeClassName( IAnalyticsVersionInfo *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI analytics_version_info_GetTrustLevel( IAnalyticsVersionInfo *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI analytics_version_info_DeviceFamily( IAnalyticsVersionInfo *iface, HSTRING *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return WindowsCreateString( L"Windows.Desktop", 4, value ); +} + +static HRESULT WINAPI analytics_version_info_DeviceFamilyVersion( IAnalyticsVersionInfo *iface, HSTRING *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return WindowsCreateString( L"2814751015176748", 4, value ); +} + +static IAnalyticsVersionInfoVtbl analytics_version_info_vtbl = +{ + analytics_version_info_QueryInterface, + analytics_version_info_AddRef, + analytics_version_info_Release, + /* IInspectable methods */ + analytics_version_info_GetIids, + analytics_version_info_GetRuntimeClassName, + analytics_version_info_GetTrustLevel, + /* IAnalyticsVersionInfo methods */ + analytics_version_info_DeviceFamily, + analytics_version_info_DeviceFamilyVersion, +}; + +struct analytics_info_factory +{ + IActivationFactory IActivationFactory_iface; + IAnalyticsInfoStatics IAnalyticsInfoStatics_iface; + LONG ref; +}; + +static inline struct analytics_info_factory *impl_from_IActivationFactory( IActivationFactory *iface ) +{ + return CONTAINING_RECORD( iface, struct analytics_info_factory, IActivationFactory_iface ); +} + +static HRESULT WINAPI activation_factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out ) +{ + struct analytics_info_factory *impl = impl_from_IActivationFactory( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IActivationFactory )) + { + IUnknown_AddRef( iface ); + *out = iface; + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IAnalyticsInfoStatics )) + { + IUnknown_AddRef( iface ); + *out = &impl->IAnalyticsInfoStatics_iface; + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI activation_factory_AddRef( IActivationFactory *iface ) +{ + struct analytics_info_factory *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI activation_factory_Release( IActivationFactory *iface ) +{ + struct analytics_info_factory *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; +} + +static HRESULT WINAPI activation_factory_GetIids( IActivationFactory *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI activation_factory_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI activation_factory_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI activation_factory_ActivateInstance( IActivationFactory *iface, IInspectable **out ) +{ + FIXME( "iface %p, out %p stub!\n", iface, out ); + return E_NOTIMPL; +} + +static const struct IActivationFactoryVtbl activation_factory_vtbl = +{ + activation_factory_QueryInterface, + activation_factory_AddRef, + activation_factory_Release, + /* IInspectable methods */ + activation_factory_GetIids, + activation_factory_GetRuntimeClassName, + activation_factory_GetTrustLevel, + /* IActivationFactory methods */ + activation_factory_ActivateInstance, +}; + +DEFINE_IINSPECTABLE( statics, IAnalyticsInfoStatics, struct analytics_info_factory, IActivationFactory_iface ); + +static HRESULT WINAPI statics_get_VersionInfo( IAnalyticsInfoStatics *iface, IAnalyticsVersionInfo **value ) +{ + struct analytics_version_info *info; + + TRACE( "iface %p, out %p.\n", iface, value ); + + if (!(info = calloc( 1, sizeof(*info) ))) return E_OUTOFMEMORY; + + info->IAnalyticsVersionInfo_iface.lpVtbl = &analytics_version_info_vtbl; + info->ref = 1; + + *value = &info->IAnalyticsVersionInfo_iface; + return S_OK; +} + +static HRESULT WINAPI statics_get_DeviceForm( IAnalyticsInfoStatics *iface, HSTRING *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + +static const struct IAnalyticsInfoStaticsVtbl statics_vtbl = +{ + statics_QueryInterface, + statics_AddRef, + statics_Release, + /* IInspectable methods */ + statics_GetIids, + statics_GetRuntimeClassName, + statics_GetTrustLevel, + /* IAnalyticsInfoStatics methods */ + statics_get_VersionInfo, + statics_get_DeviceForm, +}; + +static struct analytics_info_factory factory = +{ + {&activation_factory_vtbl}, + {&statics_vtbl}, + 0, +}; + +IInspectable *system_profile_analytics_info_factory = (IInspectable *)&factory.IActivationFactory_iface; diff --git a/dlls/windows.globalization/classes.idl b/dlls/windows.globalization/classes.idl index ded6b7572e8..7847b068cfb 100644 --- a/dlls/windows.globalization/classes.idl +++ b/dlls/windows.globalization/classes.idl @@ -32,4 +32,5 @@ import "windows.foundation.idl"; #define DO_NO_IMPORTS #include "windows.globalization.idl" +#include "windows.system.profile.idl" #include "windows.system.userprofile.idl" diff --git a/dlls/windows.globalization/main.c b/dlls/windows.globalization/main.c index b7bc2d72eeb..d2b6a88a957 100644 --- a/dlls/windows.globalization/main.c +++ b/dlls/windows.globalization/main.c @@ -732,6 +732,11 @@ HRESULT WINAPI DllGetActivationFactory(HSTRING classid, IActivationFactory **fac *factory = (IActivationFactory *)globalization_geographic_region_factory; IUnknown_AddRef(*factory); } + else if (!wcscmp(name, RuntimeClass_Windows_System_Profile_AnalyticsInfo)) + { + *factory = (IActivationFactory *)system_profile_analytics_info_factory; + IUnknown_AddRef(*factory); + } if (*factory) return S_OK; return CLASS_E_CLASSNOTAVAILABLE; diff --git a/dlls/windows.globalization/winewinrt_classes.h b/dlls/windows.globalization/winewinrt_classes.h index 4d64dc6d6cd..6ccd9be1bbe 100644 --- a/dlls/windows.globalization/winewinrt_classes.h +++ b/dlls/windows.globalization/winewinrt_classes.h @@ -32,11 +32,14 @@ #include "windows.foundation.h" #define WIDL_using_Windows_Globalization +#define WIDL_using_Windows_System_Profile #define WIDL_using_Windows_System_UserProfile #include "windows.globalization.h" +#include "windows.system.profile.h" #include "windows.system.userprofile.h" extern IInspectable *globalization_geographic_region_factory; +extern IInspectable *system_profile_analytics_info_factory; #include "wine/debug.h" #include "wine/list.h" From c00cb087d4d1f2a39eb2c269ef085e5348862f53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 28 Feb 2023 12:10:33 +0100 Subject: [PATCH 1172/2777] twinapi.appcore: Succeed IEasClientDeviceInformation stub calls. CW-Bug-Id: #21875 --- dlls/twinapi.appcore.dll/main.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/dlls/twinapi.appcore.dll/main.c b/dlls/twinapi.appcore.dll/main.c index 3842e36153c..7a85e476e65 100644 --- a/dlls/twinapi.appcore.dll/main.c +++ b/dlls/twinapi.appcore.dll/main.c @@ -206,9 +206,7 @@ static HRESULT WINAPI eas_client_devinfo_get_OperatingSystem(IEasClientDeviceInf { FIXME("iface %p, value %p stub.\n", iface, value); - WindowsCreateString(NULL, 0, value); - - return E_NOTIMPL; + return WindowsCreateString(NULL, 0, value); } static HRESULT WINAPI eas_client_devinfo_get_FriendlyName(IEasClientDeviceInformation *iface, @@ -216,9 +214,7 @@ static HRESULT WINAPI eas_client_devinfo_get_FriendlyName(IEasClientDeviceInform { FIXME("iface %p, value %p stub.\n", iface, value); - WindowsCreateString(NULL, 0, value); - - return E_NOTIMPL; + return WindowsCreateString(NULL, 0, value); } static HRESULT WINAPI eas_client_devinfo_get_SystemManufacturer(IEasClientDeviceInformation *iface, @@ -226,9 +222,7 @@ static HRESULT WINAPI eas_client_devinfo_get_SystemManufacturer(IEasClientDevice { FIXME("iface %p, value %p stub.\n", iface, value); - WindowsCreateString(NULL, 0, value); - - return E_NOTIMPL; + return WindowsCreateString(NULL, 0, value); } static HRESULT WINAPI eas_client_devinfo_get_SystemProductName(IEasClientDeviceInformation *iface, @@ -236,9 +230,7 @@ static HRESULT WINAPI eas_client_devinfo_get_SystemProductName(IEasClientDeviceI { FIXME("iface %p, value %p stub.\n", iface, value); - WindowsCreateString(NULL, 0, value); - - return E_NOTIMPL; + return WindowsCreateString(NULL, 0, value); } static HRESULT WINAPI eas_client_devinfo_get_SystemSku(IEasClientDeviceInformation *iface, @@ -246,9 +238,7 @@ static HRESULT WINAPI eas_client_devinfo_get_SystemSku(IEasClientDeviceInformati { FIXME("iface %p, value %p stub.\n", iface, value); - WindowsCreateString(NULL, 0, value); - - return E_NOTIMPL; + return WindowsCreateString(NULL, 0, value); } static IEasClientDeviceInformationVtbl eas_client_devinfo_vtbl = { From 1a45e4353f6dccbb5f10494dbf098b7b2a57308b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 28 Feb 2023 13:43:56 +0100 Subject: [PATCH 1173/2777] include: Use nested namespaces in windows.system.userprofile.idl. CW-Bug-Id: #21875 --- include/windows.system.userprofile.idl | 65 ++++++++++++-------------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/include/windows.system.userprofile.idl b/include/windows.system.userprofile.idl index 65a334b97f8..255ea7dcf6d 100644 --- a/include/windows.system.userprofile.idl +++ b/include/windows.system.userprofile.idl @@ -29,44 +29,37 @@ import "windows.foundation.idl"; import "windows.globalization.idl"; #endif -namespace Windows { - namespace System { - namespace UserProfile { - interface IGlobalizationPreferencesStatics; - interface IGlobalizationPreferencesStatics2; - interface IGlobalizationPreferencesStatics3; - runtimeclass GlobalizationPreferences; - } - } -} +namespace Windows.System.UserProfile { -namespace Windows { - namespace System { - namespace UserProfile { + interface IGlobalizationPreferencesStatics; + interface IGlobalizationPreferencesStatics2; + interface IGlobalizationPreferencesStatics3; + runtimeclass GlobalizationPreferences; - [ - contract(Windows.Foundation.UniversalApiContract, 1.0), - exclusiveto(Windows.System.UserProfile.GlobalizationPreferences), - uuid(01bf4326-ed37-4e96-b0e9-c1340d1ea158) - ] - interface IGlobalizationPreferencesStatics : IInspectable - { - [propget] HRESULT Calendars([out, retval] Windows.Foundation.Collections.IVectorView** value); - [propget] HRESULT Clocks([out, retval] Windows.Foundation.Collections.IVectorView** value); - [propget] HRESULT Currencies([out, retval] Windows.Foundation.Collections.IVectorView** value); - [propget] HRESULT Languages([out, retval] Windows.Foundation.Collections.IVectorView** value); - [propget] HRESULT HomeGeographicRegion([out, retval] HSTRING* value); - [propget] HRESULT WeekStartsOn([out, retval] Windows.Globalization.DayOfWeek* value); - } + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.System.UserProfile.GlobalizationPreferences), + uuid(01bf4326-ed37-4e96-b0e9-c1340d1ea158) + ] + interface IGlobalizationPreferencesStatics : IInspectable + { + [propget] HRESULT Calendars([out, retval] Windows.Foundation.Collections.IVectorView **value); + [propget] HRESULT Clocks([out, retval] Windows.Foundation.Collections.IVectorView **value); + [propget] HRESULT Currencies([out, retval] Windows.Foundation.Collections.IVectorView **value); + [propget] HRESULT Languages([out, retval] Windows.Foundation.Collections.IVectorView **value); + [propget] HRESULT HomeGeographicRegion([out, retval] HSTRING *value); + [propget] HRESULT WeekStartsOn([out, retval] Windows.Globalization.DayOfWeek *value); + } - [contract(Windows.Foundation.UniversalApiContract, 1.0)] - [marshaling_behavior(agile)] - [static(Windows.System.UserProfile.IGlobalizationPreferencesStatics, Windows.Foundation.UniversalApiContract, 1.0)] - [static(Windows.System.UserProfile.IGlobalizationPreferencesStatics2, Windows.Foundation.UniversalApiContract, 5.0)] - [static(Windows.System.UserProfile.IGlobalizationPreferencesStatics3, Windows.Foundation.UniversalApiContract, 6.0)] - runtimeclass GlobalizationPreferences - { - } - } + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile), + static(Windows.System.UserProfile.IGlobalizationPreferencesStatics, Windows.Foundation.UniversalApiContract, 1.0), + static(Windows.System.UserProfile.IGlobalizationPreferencesStatics2, Windows.Foundation.UniversalApiContract, 5.0), + static(Windows.System.UserProfile.IGlobalizationPreferencesStatics3, Windows.Foundation.UniversalApiContract, 6.0), + ] + runtimeclass GlobalizationPreferences + { } + } From 886b6ab85dcec579816570e861f81956feedc1dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 28 Feb 2023 13:46:13 +0100 Subject: [PATCH 1174/2777] include: Add Windows.System.UserProfile.AdvertisingManager runtimeclass. CW-Bug-Id: #21875 --- include/windows.system.userprofile.idl | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/include/windows.system.userprofile.idl b/include/windows.system.userprofile.idl index 255ea7dcf6d..672f520c37a 100644 --- a/include/windows.system.userprofile.idl +++ b/include/windows.system.userprofile.idl @@ -31,9 +31,12 @@ import "windows.globalization.idl"; namespace Windows.System.UserProfile { + interface IAdvertisingManagerStatics; + interface IAdvertisingManagerStatics2; interface IGlobalizationPreferencesStatics; interface IGlobalizationPreferencesStatics2; interface IGlobalizationPreferencesStatics3; + runtimeclass AdvertisingManager; runtimeclass GlobalizationPreferences; [ @@ -51,6 +54,16 @@ namespace Windows.System.UserProfile { [propget] HRESULT WeekStartsOn([out, retval] Windows.Globalization.DayOfWeek *value); } + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + exclusiveto(Windows.System.UserProfile.AdvertisingManager), + uuid(add3468c-a273-48cb-b346-3544522d5581), + ] + interface IAdvertisingManagerStatics : IInspectable + { + [propget] HRESULT AdvertisingId([out, retval] HSTRING *value); + } + [ contract(Windows.Foundation.UniversalApiContract, 1.0), marshaling_behavior(agile), @@ -62,4 +75,14 @@ namespace Windows.System.UserProfile { { } + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(standard), + static(Windows.System.UserProfile.IAdvertisingManagerStatics, Windows.Foundation.UniversalApiContract, 1.0), + static(Windows.System.UserProfile.IAdvertisingManagerStatics2, Windows.Foundation.UniversalApiContract, 3.0), + ] + runtimeclass AdvertisingManager + { + } + } From 2d49075113fe38ca73721ee69b677fe2dfa1b010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 28 Feb 2023 14:01:28 +0100 Subject: [PATCH 1175/2777] windows.globalization: Stub Windows.System.UserProfile.AdvertisingManager factory. CW-Bug-Id: #21875 --- dlls/windows.globalization/Makefile.in | 1 + .../advertising_manager.c | 144 ++++++++++++++++++ dlls/windows.globalization/main.c | 5 + .../windows.globalization/winewinrt_classes.h | 1 + 4 files changed, 151 insertions(+) create mode 100644 dlls/windows.globalization/advertising_manager.c diff --git a/dlls/windows.globalization/Makefile.in b/dlls/windows.globalization/Makefile.in index c8db5674405..baea4c27677 100644 --- a/dlls/windows.globalization/Makefile.in +++ b/dlls/windows.globalization/Makefile.in @@ -3,6 +3,7 @@ IMPORTS = combase uuid C_SRCS = \ analytics_info.c \ + advertising_manager.c \ geographic_region.c \ main.c diff --git a/dlls/windows.globalization/advertising_manager.c b/dlls/windows.globalization/advertising_manager.c new file mode 100644 index 00000000000..2e0ca6ceba0 --- /dev/null +++ b/dlls/windows.globalization/advertising_manager.c @@ -0,0 +1,144 @@ +/* WinRT Windows.Globalization implementation + * + * 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 + */ + +#include "winewinrt_classes.h" + +WINE_DEFAULT_DEBUG_CHANNEL(locale); + +struct advertising_manager_factory +{ + IActivationFactory IActivationFactory_iface; + IAdvertisingManagerStatics IAdvertisingManagerStatics_iface; + LONG ref; +}; + +static inline struct advertising_manager_factory *impl_from_IActivationFactory( IActivationFactory *iface ) +{ + return CONTAINING_RECORD( iface, struct advertising_manager_factory, IActivationFactory_iface ); +} + +static HRESULT WINAPI activation_factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out ) +{ + struct advertising_manager_factory *impl = impl_from_IActivationFactory( iface ); + TRACE("iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_IAgileObject) || + IsEqualGUID(iid, &IID_IActivationFactory)) + { + IUnknown_AddRef(iface); + *out = &impl->IActivationFactory_iface; + return S_OK; + } + + if (IsEqualGUID(iid, &IID_IAdvertisingManagerStatics)) + { + IUnknown_AddRef(iface); + *out = &impl->IAdvertisingManagerStatics_iface; + return S_OK; + } + + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI activation_factory_AddRef( IActivationFactory *iface ) +{ + struct advertising_manager_factory *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedIncrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + return ref; +} + +static ULONG WINAPI activation_factory_Release( IActivationFactory *iface ) +{ + struct advertising_manager_factory *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + return ref; +} + +static HRESULT WINAPI activation_factory_GetIids( IActivationFactory *iface, ULONG *iid_count, IID **iids ) +{ + FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids); + return E_NOTIMPL; +} + +static HRESULT WINAPI activation_factory_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name ) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT WINAPI activation_factory_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level ) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT WINAPI activation_factory_ActivateInstance( IActivationFactory *iface, IInspectable **instance ) +{ + FIXME("iface %p, instance %p stub!\n", iface, instance); + return E_NOTIMPL; +} + +static const struct IActivationFactoryVtbl activation_factory_vtbl = +{ + activation_factory_QueryInterface, + activation_factory_AddRef, + activation_factory_Release, + /* IInspectable methods */ + activation_factory_GetIids, + activation_factory_GetRuntimeClassName, + activation_factory_GetTrustLevel, + /* IActivationFactory methods */ + activation_factory_ActivateInstance, +}; + +DEFINE_IINSPECTABLE( statics, IAdvertisingManagerStatics, struct advertising_manager_factory, IActivationFactory_iface ) + +static HRESULT WINAPI statics_get_AdvertisingId( IAdvertisingManagerStatics *iface, HSTRING *out ) +{ + FIXME( "iface %p, out %p stub!\n", iface, out ); + return WindowsCreateString( NULL, 0, out ); +} + +static const struct IAdvertisingManagerStaticsVtbl statics_vtbl = +{ + statics_QueryInterface, + statics_AddRef, + statics_Release, + /* IInspectable methods */ + statics_GetIids, + statics_GetRuntimeClassName, + statics_GetTrustLevel, + /* IAdvertisingManagerStatics methods */ + statics_get_AdvertisingId, +}; + +static struct advertising_manager_factory advertising_manager_factory = +{ + {&activation_factory_vtbl}, + {&statics_vtbl}, + 0, +}; + +IInspectable *system_user_profile_advertising_manager_factory = (IInspectable *)&advertising_manager_factory.IActivationFactory_iface; diff --git a/dlls/windows.globalization/main.c b/dlls/windows.globalization/main.c index d2b6a88a957..e51e1b3ab26 100644 --- a/dlls/windows.globalization/main.c +++ b/dlls/windows.globalization/main.c @@ -737,6 +737,11 @@ HRESULT WINAPI DllGetActivationFactory(HSTRING classid, IActivationFactory **fac *factory = (IActivationFactory *)system_profile_analytics_info_factory; IUnknown_AddRef(*factory); } + else if (!wcscmp(name, RuntimeClass_Windows_System_UserProfile_AdvertisingManager)) + { + *factory = (IActivationFactory *)system_user_profile_advertising_manager_factory; + IUnknown_AddRef(*factory); + } if (*factory) return S_OK; return CLASS_E_CLASSNOTAVAILABLE; diff --git a/dlls/windows.globalization/winewinrt_classes.h b/dlls/windows.globalization/winewinrt_classes.h index 6ccd9be1bbe..ae168206c3f 100644 --- a/dlls/windows.globalization/winewinrt_classes.h +++ b/dlls/windows.globalization/winewinrt_classes.h @@ -40,6 +40,7 @@ extern IInspectable *globalization_geographic_region_factory; extern IInspectable *system_profile_analytics_info_factory; +extern IInspectable *system_user_profile_advertising_manager_factory; #include "wine/debug.h" #include "wine/list.h" From 6af55bf56157767b8c8d6c8a4415aa45589be6f2 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 28 Feb 2023 12:07:55 -0600 Subject: [PATCH 1176/2777] winegstreamer: Don't pre-check sample size in wg_transform_read_mf(). CW-Bug-Id: #21813 --- dlls/winegstreamer/wg_sample.c | 5 ---- dlls/winegstreamer/wg_transform.c | 48 ++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/dlls/winegstreamer/wg_sample.c b/dlls/winegstreamer/wg_sample.c index e8e3dca72ba..1f9eb85bcfb 100644 --- a/dlls/winegstreamer/wg_sample.c +++ b/dlls/winegstreamer/wg_sample.c @@ -353,11 +353,6 @@ HRESULT wg_transform_read_mf(struct wg_transform *transform, IMFSample *sample, return hr; wg_sample->size = 0; - if (wg_sample->max_size < sample_size) - { - wg_sample_release(wg_sample); - return MF_E_BUFFERTOOSMALL; - } if (FAILED(hr = wg_transform_read_data(transform, wg_sample, format))) { diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index a31dacc9e79..f53b165cd8b 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -718,19 +718,19 @@ NTSTATUS wg_transform_push_data(void *args) return STATUS_SUCCESS; } -static bool copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_align, +static NTSTATUS copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_align, struct wg_sample *sample, gsize *total_size) { + NTSTATUS status = STATUS_UNSUCCESSFUL; GstVideoFrame src_frame, dst_frame; GstVideoInfo src_info, dst_info; GstVideoAlignment align; GstBuffer *dst_buffer; - bool ret = false; if (!gst_video_info_from_caps(&src_info, caps)) { GST_ERROR("Failed to get video info from caps."); - return false; + return STATUS_UNSUCCESSFUL; } dst_info = src_info; @@ -739,14 +739,14 @@ static bool copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_alig if (sample->max_size < dst_info.size) { GST_ERROR("Output buffer is too small."); - return false; + return STATUS_BUFFER_TOO_SMALL; } if (!(dst_buffer = gst_buffer_new_wrapped_full(0, sample->data, sample->max_size, 0, sample->max_size, 0, NULL))) { GST_ERROR("Failed to wrap wg_sample into GstBuffer"); - return false; + return STATUS_UNSUCCESSFUL; } gst_buffer_set_size(dst_buffer, dst_info.size); *total_size = sample->size = dst_info.size; @@ -759,7 +759,9 @@ static bool copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_alig GST_ERROR("Failed to map destination frame."); else { - if (!(ret = gst_video_frame_copy(&dst_frame, &src_frame))) + if (gst_video_frame_copy(&dst_frame, &src_frame)) + status = STATUS_SUCCESS; + else GST_ERROR("Failed to copy video frame."); gst_video_frame_unmap(&dst_frame); } @@ -767,16 +769,16 @@ static bool copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_alig } gst_buffer_unref(dst_buffer); - return ret; + return status; } -static bool copy_buffer(GstBuffer *buffer, GstCaps *caps, struct wg_sample *sample, +static NTSTATUS copy_buffer(GstBuffer *buffer, GstCaps *caps, struct wg_sample *sample, gsize *total_size) { GstMapInfo info; if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) - return false; + return STATUS_UNSUCCESSFUL; if (sample->max_size >= info.size) sample->size = info.size; @@ -793,15 +795,16 @@ static bool copy_buffer(GstBuffer *buffer, GstCaps *caps, struct wg_sample *samp gst_buffer_resize(buffer, sample->size, -1); *total_size = info.size; - return true; + return STATUS_SUCCESS; } static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsize plane_align, struct wg_sample *sample) { - bool ret, needs_copy; gsize total_size; + bool needs_copy; GstMapInfo info; + NTSTATUS status; if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) { @@ -812,18 +815,24 @@ static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsi needs_copy = info.data != sample->data; gst_buffer_unmap(buffer, &info); - if ((ret = !needs_copy)) + if (!needs_copy) + { total_size = sample->size = info.size; - else if (is_caps_video(caps)) - ret = copy_video_buffer(buffer, caps, plane_align, sample, &total_size); + status = STATUS_SUCCESS; + } else - ret = copy_buffer(buffer, caps, sample, &total_size); + { + if (is_caps_video(caps)) + status = copy_video_buffer(buffer, caps, plane_align, sample, &total_size); + else + status = copy_buffer(buffer, caps, sample, &total_size); + } - if (!ret) + if (status) { GST_ERROR("Failed to copy buffer %p", buffer); sample->size = 0; - return STATUS_UNSUCCESSFUL; + return status; } if (GST_BUFFER_PTS_IS_VALID(buffer)) @@ -960,6 +969,11 @@ NTSTATUS wg_transform_read_data(void *args) if ((status = read_transform_output_data(output_buffer, output_caps, transform->output_plane_align, sample))) { + if (status == STATUS_BUFFER_TOO_SMALL) + { + status = 0; + params->result = E_FAIL; + } wg_allocator_release_sample(transform->allocator, sample, false); return status; } From a76a0c4b0ca3cbf892b3f377ed2923a70b510b1f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 28 Feb 2023 20:20:11 -0600 Subject: [PATCH 1177/2777] winegstreamer: Return gst_pad_query_default() when processing GST_QUERY_CAPS for input stream format change. CW-Bug-Id: #21813 --- dlls/mf/tests/resource.rc | 19 ++++ dlls/mf/tests/stream1.bin | Bin 0 -> 7174 bytes dlls/mf/tests/stream2.bin | Bin 0 -> 4416 bytes dlls/mf/tests/transform.c | 168 ++++++++++++++++++++++++++++++ dlls/winegstreamer/wg_transform.c | 7 ++ 5 files changed, 194 insertions(+) create mode 100644 dlls/mf/tests/stream1.bin create mode 100644 dlls/mf/tests/stream2.bin diff --git a/dlls/mf/tests/resource.rc b/dlls/mf/tests/resource.rc index 25768d21983..58654b93c33 100644 --- a/dlls/mf/tests/resource.rc +++ b/dlls/mf/tests/resource.rc @@ -63,6 +63,25 @@ mp3decdata.bin RCDATA mp3decdata.bin /* @makedep: h264data.bin */ h264data.bin RCDATA h264data.bin + +/* Generated with: + * gst-launch-1.0 videotestsrc num-buffers=60 pattern=smpte100 ! \ + * video/x-raw,format=I420,width=1920,height=1080,framerate=30000/1001 ! \ + * videoflip method=clockwise ! videoconvert ! \ + * x264enc ! filesink location=dlls/mf/tests/h264data.bin + */ +/* @makedep: stream1.bin */ +stream1.bin RCDATA stream1.bin + +/* Generated with: + * gst-launch-1.0 videotestsrc num-buffers=60 pattern=smpte100 ! \ + * video/x-raw,format=I420,width=1280,height=720,framerate=30000/1001 ! \ + * videoflip method=clockwise ! videoconvert ! \ + * x264enc ! filesink location=dlls/mf/tests/h264data.bin + */ +/* @makedep: stream2.bin */ +stream2.bin RCDATA stream2.bin + /* Generated from running the tests on Windows */ /* @makedep: nv12frame.bmp */ nv12frame.bmp RCDATA nv12frame.bmp diff --git a/dlls/mf/tests/stream1.bin b/dlls/mf/tests/stream1.bin new file mode 100644 index 0000000000000000000000000000000000000000..f16bdaec31cd097310c31af70e15e30f9175b3e1 GIT binary patch literal 7174 zcmb_f4LDS38$L4#vC66}#hw)vi}~@hewvsSDTJ_V+n?#oILt7AW(LFdGb`z5w^F_= zkx8{hY>{k~jnc-pwQ7@AQmIW}M7Ba@@x5opOvCE>Fs{or-uFGvdq2-}KhHVu{X!6g z)13){->3*^QBjlUQjOa0t5-`TlKl|04u;J94IfM+S7QdujwdHLY>IBmf6m=vL!2@4=U_b~6@?K`=2va}t z0+tad13d8J@e|o-qzEPxi4JyTBAE;pnIaM2jX+39NU)D*MW8%3!nNlKq6nB5d!~rP z1~xpth{fXy-CzbnM;H_mEI=bE4sZlYXY&{_6p|a!jR+%LgqL<$fNDg z5htQJ60tA^2*#-Z6*9qg0fVMY7ke&XP#AOp%%KBfv9#zcU=I=`6CGV(Y$W2bu@b?t zSaKAiy)zi{F-Nlhh?wH+3KoPSluvPlmz@Rl~Oi*<$ zC>0#ZVzW_s8*~=%1Y$yBK_g*p0ZBmTqgzrSlcB-B>mHX+bo9BFJ;?7nkh_59 z6=#LZ&bZL&25dAGfBJ?iM2;z5A&%W?*b>eF(wYakRBIBUP)O$`ZZ@<)qLqf52N5KC z)p!`%f*H+%{~k11p95KJr@idmHFR&Kw5Td4_n+$}by2x91)UIskBZNR z9I%HMbyVrTI$^vykd(7c^UR|?Gn4*gi`g=0lZK&r)?G$NPSUSD_p`k#z7|A$;}Wl# z?2FBGCm6=)m~~Rx?N9wW*!W9>gEv9P`j-LI(3~X0mfCM;-ysxHb_JQGi^_kKyT!-x z0>UgJZkEkdiDNY0IG7l*Mel5JN==&kxvhUDmGWH9r@!a!{$eJr>Vrl5@J{Y8);em3 zT)JL*kaww9ymw`R!+tChoRPM;=TiMQe2f5{Xb`|&msVW9Gvm`A6H1E~|J4sWfUPL0Z`c=J=%7PM?b>7>8Z-^8`_2m1w z@5b7wwMU7L%SA*~!dOOQg{9(8wnZ~X1&9%?2GBkkkep)X@_Z^Y%U{QCXdFb34oML< zu22~oH8<7U(AH>ZvRP{2XDG37xj(4Gmpo0Zthn4G>hL8eUd~q$;EO$_d|mRMJ!O17 zR);Uu{_2=2zPg9`A`A^Sepfu%uHaCWO+l3!OdVlTJ9P+CX)q~aiU`YgoEpMBRR~)( zg@nbbLzqg3Nrh8In0S~lr=h`Hhr=h^Va|Cfgk=E2=1l$*25pxp!En+t5jAkKQEA|e zRgg|aQ+bm{g0_DngOYv5vMa|!nqI}>mU!4i+Og(ln3EN=>(12aqHbz|0*i9SrR;-xx^r(PX9oZeeV@?UH2RVudj2RUmeibUFvRR zTf3p(CbGD5Q|IsI)@HY^Whj8xR4cinN^gM@nyOJk-3lcbPWnnj-Kp@RIP>0i7XEwP z@}3G*e>7D(d8qdcWl-`O-W#iic+Y3GLy!?6sV1nfZU3c5Ek7B4VO(uNxw~}d<&ODU zb?+B^Sz920{LE7LEt`6DG+^jR-<5#d{XZ2bc~oS$a&1u6Kx2LN%JrQso7u@{0(5<% zPxoBbDYg8|Jo%wn@M)LKz{D>}+oCP}HgyOrjZHTP8*j|k8~Alg>$0q_;7_}zYu4(2 z_(L*j^&aEnRS^sIPg-q+O{zTNZIinLw_WyG9Mw!4uzr7zcOrdL{es3z&*E+`xyaXg zn9x$@Up$SwuIT&BljiALPo#dX-B`CeRF{1+diYLxFqjZSFy)1eQjGSi8N)<35vEL3h z3j5#F5kZGbF3xMWV2TG+^m8ySStl{z>Mt5u1q^B>v=wHRyu`uuGjf(Tzev2Rv zBK<4H^q!A@_VJA@yJ{OO;vIHG6XR2KSPkPa)EsWj}0$);VXE97n$GYSuZXchAuL>49Z! zal4ZLn$d9VK|=*(wd1@C_x$S=TpAS8-*&ibU2~}7B*W<*>FJo|mbU3e+Q5QToy9(Z zP;#H$;gWYgvR&(O@sH?7sUJSx?GfM5Eg3GA$=@oa!7e8gD9!Yu0jll6#dXn8-#!vS2c(X)@8T*=9`&Oi%nD*5+MeLy2R;cDazo@p% zXD{YA;%m+-rHpEj-%jLJ1{a<2J643Q>}u7cH~Y+3M=##<`Ne0ZlErow{8o^#3Ie`y z^F7o$(O}_w{+|{4E_+uiyt3q-odJetkm`5cgc?l_#!b#AY&^PGe93SxU0Y)+>hn(+ zL;c}gU%2(RIbFjpf*O$C`oVva>+AifZseQ(GIz56q(5?4D; N35S!uR*$^${{cQ_{{#R4 literal 0 HcmV?d00001 diff --git a/dlls/mf/tests/stream2.bin b/dlls/mf/tests/stream2.bin new file mode 100644 index 0000000000000000000000000000000000000000..265878cced89f3a465b72e123c8e93a7f49ef1e2 GIT binary patch literal 4416 zcmeHJdsGzH9iHVSqM+u~AezFMLXgN~_Q7jqPFM*MkEDmFh)L9Oc6OE>o!uE`2H4do zV0>1>X*D3?aTl!-BocC{#2O#qqX`;nTQv&!2qtMNQNWa(ps}*O!?Md_VOjoa|L8fK z+26hQyWjnO-+lamAV@NCDg?gS8YtvwTk465wpx2{rFNeFt}X3&S!65R_N(q5qbyDVN5KTck+2kmoE%Avh1EDoDi8z=q(uWj z%2X#Ta-cOyFvqK&3E8YEe0?A=NZPtVN|tM2Wz-0jEtoi6Tb15;01p za#&BII?@R9xoQx_!z^zCQ^6PGG^jKh0h7Q7)>B4OgNck%FazUoLpF&@<6uI^F?t*W zQ>C!Lku**5AWASMXb1rWM2;RsfCOB#jxms^Od2Vb!djdcFqU6Su_D4oki%k(R?CwD z8YP1T9S3Frq6C;`n6K^dY*fW=5)XmN|+95Fc*iH-vyD=swfiyP6n zM9{$tB#SEGJarzX$Bjb_Vuw0c%TwzBxlEP-gQJ1zz^)s>R>4||rb*FPiUqq3P8L`R zXu@;AK@yJzR0vK!xqUM<)7sy6?RZOl*AnKFN!5J^%`agoxnYuhWf!`X0OL9M*ST~P z@lH4Nx8h@B$C4($^1!K!&b~S!ZSL8v{?L^^=7-X*M|M1hKmA>E$K>;7m52X?o78`u}n;^*l;hdsl zzo;BqcJ9{LttWj`o-{vs{obiPmZUfDz^Yj5%I^!#b(k7X9P&n_U2^m4WNbx2R_1T` z+6#BtCUUtb+Y`;Z``$Na|CzpGh|H19V9-odrC%?T^<4h?`nKjTk8xiu&YI_S{^gsQ z{bAQ7uXOJ`vhrzAFe-=yQx;9@yL55=E_KJqbdnv4NjG*EAhM0Z;u{ZmdgVM0?mn3C z!WNIK$!~h0-+d^jI9RfG{~=4={vpzoE33{Vg@pbIWN!EQnPAK21KX>Z){;eh{E3#O zDc&=(wE62>GS87O_E$aXd3^C+z~v6p=G(F^;zqJa(tBz9z0cqMw)~GHGfG|z_tfmk zzYtKIShS#Svhv8TLqB;ZdfoAr7MD&;4wn)ZVODly}N$}&1M zveF4ktZ@lFFaWj5)h(=6>Gr1k##&vAKI@=YnYX4+i=1g4UCS`pAGnrn(;}K7F;}^k zZOhOm`zVl2yCJ*DN%p1G>F&$!bS>Ma#U}f{`?4RpDci|yOTai}TcQM2oqHQ&iCNvvnyszs_MKMU>92woT`!qk-$3_RF8?{QBctIE=F&E(V5?KA!J^S+dU<1t*0q~D3=iTe(9JnN8W#Kq$s zQSbZwef8)6iVyqZeAkvAm%TlEPw$j={(NA~^zUUUu^$x?nayuMy8TVHPgg|z?S}M^ zA!v4c=hwY489Ti0CflVce)6aIMpdiW_S@@_r!of*nNB!;o%|%H*wf24~mnkcgN|{m_c!J1$DX!6=HF6=aqN5z@Rvd z2VS_TuCUYReD-P*sJC;w0%U-uCO~(m&Ar_5S+laktL3VyR?(PyzC^DoMKT zz^dPe%HO*8eC&!Xjqlx278> 32; + width = frame_size & 0xffffffff; + ok(width == 1920, "got %u.\n", width); + ok(height == 1088, "got %u.\n", height); + IMFMediaType_Release(type); + + output_sample = create_sample(NULL, 0x1000); + hr = check_mft_process_output(transform, output_sample, &output_status); + ok(hr == E_FAIL, "got %#lx\n", hr); + IMFSample_Release(output_sample); + + output_sample = create_sample(NULL, width * height * 3 / 2); + hr = check_mft_process_output(transform, output_sample, &output_status); + ok(hr == S_OK, "got %#lx\n", hr); + IMFSample_Release(output_sample); + + IMFSample_Release(input_sample); + + load_resource(L"stream2.bin", &data1, &data1_len); + i = 0; + input_sample = next_h264_sample(&data1, &data1_len); + while (1) + { + output_sample = create_sample(NULL, width * height * 3 / 2); + hr = check_mft_process_output(transform, output_sample, &output_status); + if (hr != MF_E_TRANSFORM_NEED_MORE_INPUT) break; + + ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status); + hr = IMFSample_GetTotalLength(output_sample, &length); + ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr); + ok(length == 0, "got length %lu\n", length); + IMFSample_Release(output_sample); + + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "got %#lx\n", hr); + IMFSample_Release(input_sample); + input_sample = next_h264_sample(&data1, &data1_len); + + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "got %#lx\n", hr); + IMFSample_Release(input_sample); + input_sample = next_h264_sample(&data1, &data1_len); + + i++; + } + trace("i %d.\n", i); + ok(hr == S_OK, "got %#lx\n", hr); + while (hr == S_OK) + { + IMFSample_Release(output_sample); + output_sample = create_sample(NULL, width * height * 3 / 2); + hr = check_mft_process_output(transform, output_sample, &output_status); + } + while (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) + { + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "got %#lx\n", hr); + IMFSample_Release(input_sample); + input_sample = next_h264_sample(&data1, &data1_len); + + hr = check_mft_process_output(transform, output_sample, &output_status); + } + + ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "got %#lx\n", hr); + + hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &type); + ok(hr == S_OK, "got %#lx\n", hr); + IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size); + ok(hr == S_OK, "got %#lx\n", hr); + height = frame_size >> 32; + width = frame_size & 0xffffffff; + ok(width == 1280, "got %u.\n", width); + ok(height == 720, "got %u.\n", height); + IMFMediaType_Release(type); + + IMFSample_Release(output_sample); + IMFSample_Release(input_sample); + + IMFTransform_Release(transform); +failed: + CoUninitialize(); +} + START_TEST(transform) { init_functions(); @@ -6485,4 +6652,5 @@ START_TEST(transform) test_color_convert(); test_video_processor(); test_mp3_decoder(); + test_h264_reuse(); } diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index f53b165cd8b..e955d734656 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -63,6 +63,7 @@ struct wg_transform bool output_caps_changed; GstCaps *output_caps; bool broken_timestamps; + bool setting_output_format; }; static bool is_caps_video(GstCaps *caps) @@ -188,6 +189,9 @@ static gboolean transform_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery GstCaps *caps, *filter, *temp; gchar *str; + if (!transform->setting_output_format) + return gst_pad_query_default(pad, parent, query); + gst_query_parse_caps(query, &filter); caps = gst_caps_ref(transform->output_caps); @@ -227,6 +231,7 @@ static gboolean transform_sink_event_cb(GstPad *pad, GstObject *parent, GstEvent { GstCaps *caps; + transform->setting_output_format = false; gst_event_parse_caps(event, &caps); transform->output_caps_changed = transform->output_caps_changed @@ -602,6 +607,8 @@ NTSTATUS wg_transform_set_output_format(void *args) gst_caps_unref(transform->output_caps); transform->output_caps = caps; + transform->setting_output_format = true; + if (!gst_pad_push_event(transform->my_sink, gst_event_new_reconfigure())) { GST_ERROR("Failed to reconfigure transform %p.", transform); From 6fc8c46aab46ad5e3ccc1019a44288f3143279e9 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 28 Feb 2023 09:16:44 -0600 Subject: [PATCH 1178/2777] winegstreamer: Implement MFT_MESSAGE_COMMAND_FLUSH for h264 decoder. CW-Bug-Id: #21813 --- dlls/mf/tests/transform.c | 19 +++---------------- dlls/winegstreamer/aac_decoder.c | 2 +- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/h264_decoder.c | 4 +++- dlls/winegstreamer/main.c | 3 ++- dlls/winegstreamer/resampler.c | 2 +- dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/video_processor.c | 2 +- dlls/winegstreamer/wg_transform.c | 14 +++++++++++++- dlls/winegstreamer/wma_decoder.c | 2 +- 10 files changed, 27 insertions(+), 24 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 05504cac9b3..2cf36bf4b38 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -6567,6 +6567,9 @@ static void test_h264_reuse(void) ok(hr == S_OK, "got %#lx\n", hr); IMFSample_Release(output_sample); + hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_FLUSH, 0); + ok(hr == S_OK, "got %#lx\n", hr); + IMFSample_Release(input_sample); load_resource(L"stream2.bin", &data1, &data1_len); @@ -6597,22 +6600,6 @@ static void test_h264_reuse(void) i++; } trace("i %d.\n", i); - ok(hr == S_OK, "got %#lx\n", hr); - while (hr == S_OK) - { - IMFSample_Release(output_sample); - output_sample = create_sample(NULL, width * height * 3 / 2); - hr = check_mft_process_output(transform, output_sample, &output_status); - } - while (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) - { - hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); - ok(hr == S_OK, "got %#lx\n", hr); - IMFSample_Release(input_sample); - input_sample = next_h264_sample(&data1, &data1_len); - - hr = check_mft_process_output(transform, output_sample, &output_status); - } ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "got %#lx\n", hr); diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index 3be7e91147f..01f07e6b713 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -542,7 +542,7 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ return MF_E_TRANSFORM_TYPE_NOT_SET; if (message == MFT_MESSAGE_COMMAND_DRAIN) - return wg_transform_drain(decoder->wg_transform); + return wg_transform_drain(decoder->wg_transform, FALSE); FIXME("Ignoring message %#x.\n", message); diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 2f0681a18bd..e4d0af8af44 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -105,7 +105,7 @@ struct wg_transform *wg_transform_create(const struct wg_format *input_format, void wg_transform_destroy(struct wg_transform *transform); bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_format *format); bool wg_transform_get_status(struct wg_transform *transform, bool *accepts_input); -HRESULT wg_transform_drain(struct wg_transform *transform); +HRESULT wg_transform_drain(struct wg_transform *transform, BOOL flush); unsigned int wg_format_get_max_size(const struct wg_format *format); diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index a1d70eb5733..c5600389be7 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -590,7 +590,9 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ return MF_E_TRANSFORM_TYPE_NOT_SET; if (message == MFT_MESSAGE_COMMAND_DRAIN) - return wg_transform_drain(decoder->wg_transform); + return wg_transform_drain(decoder->wg_transform, FALSE); + if (message == MFT_MESSAGE_COMMAND_FLUSH) + return wg_transform_drain(decoder->wg_transform, TRUE); FIXME("Ignoring message %#x.\n", message); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 2a2d5c55d7d..304b390c8fe 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -415,11 +415,12 @@ bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_fo return !WINE_UNIX_CALL(unix_wg_transform_set_output_format, ¶ms); } -HRESULT wg_transform_drain(struct wg_transform *transform) +HRESULT wg_transform_drain(struct wg_transform *transform, BOOL flush) { struct wg_transform_drain_params params = { .transform = transform, + .flush = flush, }; TRACE("transform %p.\n", transform); diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c index c4efd5fb82c..4c8d27856f9 100644 --- a/dlls/winegstreamer/resampler.c +++ b/dlls/winegstreamer/resampler.c @@ -513,7 +513,7 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ return MF_E_TRANSFORM_TYPE_NOT_SET; if (message == MFT_MESSAGE_COMMAND_DRAIN) - return wg_transform_drain(impl->wg_transform); + return wg_transform_drain(impl->wg_transform, FALSE); FIXME("Ignoring message %#x.\n", message); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index f098ff1fec3..f0e176b2085 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -326,6 +326,7 @@ struct wg_transform_get_status_params struct wg_transform_drain_params { struct wg_transform *transform; + BOOL flush; }; enum unix_funcs diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index d8ef51b7bf2..03186b36d9d 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -513,7 +513,7 @@ static HRESULT WINAPI video_processor_ProcessMessage(IMFTransform *iface, MFT_ME return MF_E_TRANSFORM_TYPE_NOT_SET; if (message == MFT_MESSAGE_COMMAND_DRAIN) - return wg_transform_drain(impl->wg_transform); + return wg_transform_drain(impl->wg_transform, FALSE); FIXME("Ignoring message %#x.\n", message); diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index e955d734656..fe045f822ac 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -637,13 +637,16 @@ NTSTATUS wg_transform_drain(void *args) struct wg_transform_drain_params *params = args; struct wg_transform *transform = params->transform; GstBuffer *input_buffer; + GstSample *sample; GstFlowReturn ret; GstEvent *event; while ((input_buffer = gst_atomic_queue_pop(transform->input_queue))) { - if ((ret = gst_pad_push(transform->my_src, input_buffer))) + if (params->flush) + gst_buffer_unref(input_buffer); + else if ((ret = gst_pad_push(transform->my_src, input_buffer))) { GST_ERROR("Failed to push transform input, error %d", ret); return S_OK; @@ -673,6 +676,15 @@ NTSTATUS wg_transform_drain(void *args) return MF_E_STREAM_ERROR; } + if (params->flush) + { + if (transform->output_sample) + gst_sample_unref(transform->output_sample); + while ((sample = gst_atomic_queue_pop(transform->output_queue))) + gst_sample_unref(sample); + transform->output_sample = NULL; + } + return S_OK; } diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 9354822e45c..fa649fea63b 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -530,7 +530,7 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ return MF_E_TRANSFORM_TYPE_NOT_SET; if (message == MFT_MESSAGE_COMMAND_DRAIN) - return wg_transform_drain(decoder->wg_transform); + return wg_transform_drain(decoder->wg_transform, FALSE); FIXME("Ignoring message %#x.\n", message); From 02d89f04149a8b28ecba978ddf84e73b18daec1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 10 Mar 2023 20:51:53 +0100 Subject: [PATCH 1179/2777] user32: Add more devnotify traces on +rawinput. CW-Bug-Id: #22037 --- dlls/user32/input.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/user32/input.c b/dlls/user32/input.c index e81fda9513e..7f7eb18476a 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -31,6 +31,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); WINE_DECLARE_DEBUG_CHANNEL(keyboard); +WINE_DECLARE_DEBUG_CHANNEL(rawinput); /*********************************************************************** * get_locale_kbd_layout @@ -497,6 +498,7 @@ BOOL WINAPI UnloadKeyboardLayout( HKL layout ) static DWORD CALLBACK devnotify_window_callback(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header) { + TRACE_(rawinput)("handle %p, flags %#lx, header %p\n", handle, flags, header); SendMessageTimeoutW(handle, WM_DEVICECHANGE, flags, (LPARAM)header, SMTO_ABORTIFHUNG, 2000, NULL); return 0; } @@ -540,7 +542,7 @@ HDEVNOTIFY WINAPI RegisterDeviceNotificationW( HANDLE handle, void *filter, DWOR struct device_notification_details details; DEV_BROADCAST_HDR *header = filter; - TRACE("handle %p, filter %p, flags %#lx\n", handle, filter, flags); + TRACE_(rawinput)("handle %p, filter %p, flags %#lx\n", handle, filter, flags); if (flags & ~(DEVICE_NOTIFY_SERVICE_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES)) { From c6259602077f618afc6193eedc0286c2d9d74d4a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 13 Mar 2023 21:39:04 -0600 Subject: [PATCH 1180/2777] fsync: Avoid race between NtClose() and get_object(). CW-Bug-Id: #22029 --- dlls/ntdll/unix/fsync.c | 19 ++++++++++++++++--- dlls/ntdll/unix/fsync.h | 5 +++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index a520de13e41..ba85862fcc2 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -373,8 +373,9 @@ static BOOL get_cached_object( HANDLE handle, struct fsync *obj ) { /* This check does not strictly guarantee that we avoid the potential race but is supposed to greatly * reduce the probability of that. */ + FIXME( "Cache changed while getting object, handle %p, shm_idx %d, refcount %d.\n", + handle, cache.shm_idx, ((int *)obj->shm)[2] ); put_object( obj ); - FIXME( "Cache changed while getting object.\n" ); goto again; } return TRUE; @@ -389,6 +390,7 @@ static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) NTSTATUS ret = STATUS_SUCCESS; unsigned int shm_idx = 0; enum fsync_type type; + sigset_t sigset; if (get_cached_object( handle, obj )) return STATUS_SUCCESS; @@ -398,7 +400,17 @@ static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) return STATUS_NOT_IMPLEMENTED; } - /* We need to try grabbing it from the server. */ + + /* We need to try grabbing it from the server. Uninterrupted section + * is needed to avoid race with NtClose() which first calls fsync_close() + * and then closes handle on server. Without the section we might cache + * already closed handle back. */ + server_enter_uninterrupted_section( &fd_cache_mutex, &sigset ); + if (get_cached_object( handle, obj )) + { + server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); + return STATUS_SUCCESS; + } SERVER_START_REQ( get_fsync_idx ) { req->handle = wine_server_obj_handle( handle ); @@ -409,6 +421,8 @@ static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) } } SERVER_END_REQ; + if (!ret) add_to_list( handle, type, shm_idx ); + server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); if (ret) { @@ -420,7 +434,6 @@ static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) obj->type = type; obj->shm = get_shm( shm_idx ); - add_to_list( handle, type, shm_idx ); /* get_fsync_idx server request increments shared mem refcount, so not grabbing object here. */ return ret; } diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h index b3604548554..16ae15f8423 100644 --- a/dlls/ntdll/unix/fsync.h +++ b/dlls/ntdll/unix/fsync.h @@ -47,3 +47,8 @@ extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; extern NTSTATUS fsync_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; + +/* We have to synchronize on the fd cache mutex so that fsync_close(), close_handle() sequence + * called from NtClose() doesn't race with get_fsync_idx(), add_to_list() sequence called + * from get_object(). */ +extern pthread_mutex_t fd_cache_mutex; From d2ed33c4553c18ca9aad4c2adea15d9d54d27890 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 27 Mar 2023 10:44:52 -0600 Subject: [PATCH 1181/2777] kernelbase: HACK: Force swiftshader for Olympia Rising. CW-Bug-Id: #22076 --- dlls/kernelbase/process.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 2fe9d93e76e..b98e7557b0e 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -604,6 +604,7 @@ static const WCHAR *hack_append_command_line( const WCHAR *cmd ) {L"Montaro\\nw.exe", L" --use-gl=swiftshader"}, {L"EOSOverlayRenderer-Win64-Shipping.exe", L" --use-gl=swiftshader --in-process-gpu"}, {L"EpicOnlineServicesUIHelper", L" --use-gl=desktop"}, + {L"OlympiaRising.exe", L" --use-gl=swiftshader"}, }; unsigned int i; From 846c106e45633aa701cad5cf536a236c8eacf0ed Mon Sep 17 00:00:00 2001 From: Evan Tang Date: Tue, 6 Dec 2022 11:58:36 -0600 Subject: [PATCH 1182/2777] secur32: Schannel AcceptSecurityContext support. (cherry picked from commit 24e276a92860131749e9f792784bfc6407874576) CW-Bug-ID: 21551 --- dlls/secur32/schannel.c | 103 +++++++++++++++++++++++---------- dlls/secur32/schannel_gnutls.c | 51 +++++++++++----- 2 files changed, 107 insertions(+), 47 deletions(-) diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c index 23917626497..9790c4fa9e0 100644 --- a/dlls/secur32/schannel.c +++ b/dlls/secur32/schannel.c @@ -769,14 +769,11 @@ static BOOL validate_input_buffers(SecBufferDesc *desc) return TRUE; } -/*********************************************************************** - * InitializeSecurityContextW - */ -static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( +static SECURITY_STATUS establish_context( PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName, - ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, - PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext, - PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) + PSecBufferDesc pInput, ULONG fContextReq, ULONG TargetDataRep, + PCtxtHandle phNewContext, PSecBufferDesc pOutput, ULONG *pfContextAttr, + PTimeStamp ptsTimeStamp, BOOL bIsServer) { const ULONG extra_size = 0x10000; struct schan_context *ctx; @@ -791,26 +788,20 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( ULONG input_offset = 0, output_offset = 0; SecBufferDesc input_desc, output_desc; - TRACE("%p %p %s 0x%08lx %ld %ld %p %ld %p %p %p %p\n", phCredential, phContext, - debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput, - Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry); - - dump_buffer_desc(pInput); - dump_buffer_desc(pOutput); - - if (ptsExpiry) + if (ptsTimeStamp) { - ptsExpiry->LowPart = 0; - ptsExpiry->HighPart = 0; + ptsTimeStamp->LowPart = 0; + ptsTimeStamp->HighPart = 0; } if (!pOutput || !pOutput->cBuffers) return SEC_E_INVALID_TOKEN; for (i = 0; i < pOutput->cBuffers; i++) { ULONG type = pOutput->pBuffers[i].BufferType; + ULONG allocate_memory_flag = bIsServer ? ASC_REQ_ALLOCATE_MEMORY : ISC_REQ_ALLOCATE_MEMORY; if (type != SECBUFFER_TOKEN && type != SECBUFFER_ALERT) continue; - if (!pOutput->pBuffers[i].cbBuffer && !(fContextReq & ISC_REQ_ALLOCATE_MEMORY)) + if (!pOutput->pBuffers[i].cbBuffer && !(fContextReq & allocate_memory_flag)) return SEC_E_INSUFFICIENT_MEMORY; } @@ -818,15 +809,16 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( { ULONG_PTR handle; struct create_session_params create_params; + ULONG credential_use = bIsServer ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND; if (!phCredential) return SEC_E_INVALID_HANDLE; cred = schan_get_object(phCredential->dwLower, SCHAN_HANDLE_CRED); if (!cred) return SEC_E_INVALID_HANDLE; - if (!(cred->credential_use & SECPKG_CRED_OUTBOUND)) + if (!(cred->credential_use & credential_use)) { - WARN("Invalid credential use %#lx\n", cred->credential_use); + WARN("Invalid credential use %#lx, expected %#lx\n", cred->credential_use, credential_use); return SEC_E_INVALID_HANDLE; } @@ -848,7 +840,7 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( return SEC_E_INTERNAL_ERROR; } - if (cred->enabled_protocols & (SP_PROT_DTLS1_0_CLIENT | SP_PROT_DTLS1_2_CLIENT)) + if (cred->enabled_protocols & SP_PROT_DTLS1_X) ctx->header_size = HEADER_SIZE_DTLS; else ctx->header_size = HEADER_SIZE_TLS; @@ -894,12 +886,13 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( phNewContext->dwLower = handle; phNewContext->dwUpper = 0; } - else + + if (bIsServer || phContext) { SIZE_T record_size = 0; unsigned char *ptr; - if (!(ctx = schan_get_object(phContext->dwLower, SCHAN_HANDLE_CTX))) return SEC_E_INVALID_HANDLE; + if (phContext && !(ctx = schan_get_object(phContext->dwLower, SCHAN_HANDLE_CTX))) return SEC_E_INVALID_HANDLE; if (!pInput && !ctx->shutdown_requested && !is_dtls_context(ctx)) return SEC_E_INCOMPLETE_MESSAGE; if (!ctx->shutdown_requested && pInput) @@ -938,7 +931,7 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( TRACE("Using expected_size %Iu.\n", expected_size); } - if (phNewContext) *phNewContext = *phContext; + if (phNewContext && phContext) *phNewContext = *phContext; } ctx->req_ctx_attr = fContextReq; @@ -1014,16 +1007,45 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( if (buffer->BufferType == SECBUFFER_ALERT) buffer->cbBuffer = 0; } - *pfContextAttr = ISC_RET_REPLAY_DETECT | ISC_RET_SEQUENCE_DETECT | ISC_RET_CONFIDENTIALITY | ISC_RET_STREAM; - if (ctx->req_ctx_attr & ISC_REQ_EXTENDED_ERROR) *pfContextAttr |= ISC_RET_EXTENDED_ERROR; - if (ctx->req_ctx_attr & ISC_REQ_DATAGRAM) *pfContextAttr |= ISC_RET_DATAGRAM; - if (ctx->req_ctx_attr & ISC_REQ_ALLOCATE_MEMORY) *pfContextAttr |= ISC_RET_ALLOCATED_MEMORY; - if (ctx->req_ctx_attr & ISC_REQ_USE_SUPPLIED_CREDS) *pfContextAttr |= ISC_RET_USED_SUPPLIED_CREDS; - if (ctx->req_ctx_attr & ISC_REQ_MANUAL_CRED_VALIDATION) *pfContextAttr |= ISC_RET_MANUAL_CRED_VALIDATION; + if (bIsServer) + { + *pfContextAttr = ASC_RET_REPLAY_DETECT | ASC_RET_SEQUENCE_DETECT | ASC_RET_CONFIDENTIALITY | ASC_RET_STREAM; + if (ctx->req_ctx_attr & ASC_REQ_EXTENDED_ERROR) *pfContextAttr |= ASC_RET_EXTENDED_ERROR; + if (ctx->req_ctx_attr & ASC_REQ_DATAGRAM) *pfContextAttr |= ASC_RET_DATAGRAM; + if (ctx->req_ctx_attr & ASC_REQ_ALLOCATE_MEMORY) *pfContextAttr |= ASC_RET_ALLOCATED_MEMORY; + } + else + { + *pfContextAttr = ISC_RET_REPLAY_DETECT | ISC_RET_SEQUENCE_DETECT | ISC_RET_CONFIDENTIALITY | ISC_RET_STREAM; + if (ctx->req_ctx_attr & ISC_REQ_EXTENDED_ERROR) *pfContextAttr |= ISC_RET_EXTENDED_ERROR; + if (ctx->req_ctx_attr & ISC_REQ_DATAGRAM) *pfContextAttr |= ISC_RET_DATAGRAM; + if (ctx->req_ctx_attr & ISC_REQ_ALLOCATE_MEMORY) *pfContextAttr |= ISC_RET_ALLOCATED_MEMORY; + if (ctx->req_ctx_attr & ISC_REQ_USE_SUPPLIED_CREDS) *pfContextAttr |= ISC_RET_USED_SUPPLIED_CREDS; + if (ctx->req_ctx_attr & ISC_REQ_MANUAL_CRED_VALIDATION) *pfContextAttr |= ISC_RET_MANUAL_CRED_VALIDATION; + } return ret; } +/*********************************************************************** + * InitializeSecurityContextW + */ +static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( + PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName, + ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, + PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext, + PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) +{ + TRACE("%p %p %s 0x%08lx %ld %ld %p %ld %p %p %p %p\n", phCredential, phContext, + debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput, + Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry); + + dump_buffer_desc(pInput); + dump_buffer_desc(pOutput); + + return establish_context(phCredential, phContext, pszTargetName, pInput, fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr, ptsExpiry, FALSE); +} + /*********************************************************************** * InitializeSecurityContextA */ @@ -1055,6 +1077,23 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextA( return ret; } +/*********************************************************************** + * AcceptSecurityContext + */ +static SECURITY_STATUS SEC_ENTRY schan_AcceptSecurityContext( + PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput, + ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext, + PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsTimeStamp) +{ + TRACE("%p %p %p 0x%08lx %ld %p %p %p %p\n", phCredential, phContext, pInput, + fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr, ptsTimeStamp); + + dump_buffer_desc(pInput); + dump_buffer_desc(pOutput); + + return establish_context(phCredential, phContext, NULL, pInput, fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr, ptsTimeStamp, TRUE); +} + static void *get_alg_name(ALG_ID id, BOOL wide) { static const struct { @@ -1604,7 +1643,7 @@ static const SecurityFunctionTableA schanTableA = { schan_FreeCredentialsHandle, NULL, /* Reserved2 */ schan_InitializeSecurityContextA, - NULL, /* AcceptSecurityContext */ + schan_AcceptSecurityContext, NULL, /* CompleteAuthToken */ schan_DeleteSecurityContext, schan_ApplyControlToken, /* ApplyControlToken */ @@ -1635,7 +1674,7 @@ static const SecurityFunctionTableW schanTableW = { schan_FreeCredentialsHandle, NULL, /* Reserved2 */ schan_InitializeSecurityContextW, - NULL, /* AcceptSecurityContext */ + schan_AcceptSecurityContext, NULL, /* CompleteAuthToken */ schan_DeleteSecurityContext, schan_ApplyControlToken, /* ApplyControlToken */ diff --git a/dlls/secur32/schannel_gnutls.c b/dlls/secur32/schannel_gnutls.c index b26344aa85e..06d56fccee1 100644 --- a/dlls/secur32/schannel_gnutls.c +++ b/dlls/secur32/schannel_gnutls.c @@ -354,10 +354,12 @@ static ssize_t push_adapter(gnutls_transport_ptr_t transport, const void *buff, return len; } -static const struct { +struct protocol_priority_flag { DWORD enable_flag; const char *gnutls_flag; -} protocol_priority_flags[] = { +}; + +static const struct protocol_priority_flag client_protocol_priority_flags[] = { {SP_PROT_DTLS1_2_CLIENT, "VERS-DTLS1.2"}, {SP_PROT_DTLS1_0_CLIENT, "VERS-DTLS1.0"}, {SP_PROT_TLS1_3_CLIENT, "VERS-TLS1.3"}, @@ -368,33 +370,46 @@ static const struct { /* {SP_PROT_SSL2_CLIENT} is not supported by GnuTLS */ }; +static const struct protocol_priority_flag server_protocol_priority_flags[] = { + {SP_PROT_DTLS1_2_SERVER, "VERS-DTLS1.2"}, + {SP_PROT_DTLS1_0_SERVER, "VERS-DTLS1.0"}, + {SP_PROT_TLS1_3_SERVER, "VERS-TLS1.3"}, + {SP_PROT_TLS1_2_SERVER, "VERS-TLS1.2"}, + {SP_PROT_TLS1_1_SERVER, "VERS-TLS1.1"}, + {SP_PROT_TLS1_0_SERVER, "VERS-TLS1.0"}, + {SP_PROT_SSL3_SERVER, "VERS-SSL3.0"} + /* {SP_PROT_SSL2_SERVER} is not supported by GnuTLS */ +}; + static DWORD supported_protocols; -static void check_supported_protocols(void) +static void check_supported_protocols( + const struct protocol_priority_flag *flags, int num_flags, BOOLEAN server) { + const char *type_desc = server ? "server" : "client"; gnutls_session_t session; char priority[64]; unsigned i; int err; - err = pgnutls_init(&session, GNUTLS_CLIENT); + err = pgnutls_init(&session, server ? GNUTLS_SERVER : GNUTLS_CLIENT); if (err != GNUTLS_E_SUCCESS) { pgnutls_perror(err); return; } - for(i = 0; i < ARRAY_SIZE(protocol_priority_flags); i++) + for(i = 0; i < num_flags; i++) { - sprintf(priority, "NORMAL:-%s", protocol_priority_flags[i].gnutls_flag); + sprintf(priority, "NORMAL:-%s", flags[i].gnutls_flag); err = pgnutls_priority_set_direct(session, priority, NULL); if (err == GNUTLS_E_SUCCESS) { - TRACE("%s is supported\n", protocol_priority_flags[i].gnutls_flag); - supported_protocols |= protocol_priority_flags[i].enable_flag; + TRACE("%s %s is supported\n", type_desc, flags[i].gnutls_flag); + supported_protocols |= flags[i].enable_flag; } else - TRACE("%s is not supported\n", protocol_priority_flags[i].gnutls_flag); + TRACE("%s %s is not supported\n", type_desc, flags[i].gnutls_flag); } pgnutls_deinit(session); @@ -420,6 +435,11 @@ static int pull_timeout(gnutls_transport_ptr_t transport, unsigned int timeout) static NTSTATUS set_priority(schan_credentials *cred, gnutls_session_t session) { char priority[128] = "NORMAL:%LATEST_RECORD_VERSION", *p; + BOOL server = !!(cred->credential_use & SECPKG_CRED_INBOUND); + const struct protocol_priority_flag *protocols = + server ? server_protocol_priority_flags : client_protocol_priority_flags; + int num_protocols = server ? ARRAYSIZE(server_protocol_priority_flags) + : ARRAYSIZE(client_protocol_priority_flags); BOOL using_vers_all = FALSE, disabled; int i, err; @@ -447,16 +467,16 @@ static NTSTATUS set_priority(schan_credentials *cred, gnutls_session_t session) using_vers_all = TRUE; } - for (i = 0; i < ARRAY_SIZE(protocol_priority_flags); i++) + for (i = 0; i < num_protocols; i++) { - if (!(supported_protocols & protocol_priority_flags[i].enable_flag)) continue; + if (!(supported_protocols & protocols[i].enable_flag)) continue; - disabled = !(cred->enabled_protocols & protocol_priority_flags[i].enable_flag); + disabled = !(cred->enabled_protocols & protocols[i].enable_flag); if (using_vers_all && disabled) continue; *p++ = ':'; *p++ = disabled ? '-' : '+'; - strcpy(p, protocol_priority_flags[i].gnutls_flag); + strcpy(p, protocols[i].gnutls_flag); p += strlen(p); } @@ -483,7 +503,7 @@ static NTSTATUS schan_create_session( void *args ) *params->session = 0; - if (cred->enabled_protocols & (SP_PROT_DTLS1_0_CLIENT | SP_PROT_DTLS1_2_CLIENT)) + if (cred->enabled_protocols & SP_PROT_DTLS1_X) { flags |= GNUTLS_DATAGRAM | GNUTLS_NONBLOCK; } @@ -1505,7 +1525,8 @@ static NTSTATUS process_attach( void *args ) pgnutls_global_set_log_function(gnutls_log); } - check_supported_protocols(); + check_supported_protocols(client_protocol_priority_flags, ARRAYSIZE(client_protocol_priority_flags), FALSE); + check_supported_protocols(server_protocol_priority_flags, ARRAYSIZE(server_protocol_priority_flags), TRUE); return STATUS_SUCCESS; fail: From e1ce55ff5f6c0563ef4d169abcc23a51b8470b69 Mon Sep 17 00:00:00 2001 From: Evan Tang Date: Wed, 7 Dec 2022 11:30:32 -0600 Subject: [PATCH 1183/2777] secur32: Share code for schannel Acquire and AcceptCredentialsHandle. (cherry picked from commit ee0c01cb3b97d9e3ded414f5f02452923217476b) CW-Bug-ID: 21551 --- dlls/secur32/schannel.c | 161 ++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 96 deletions(-) diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c index 9790c4fa9e0..0d07286cf11 100644 --- a/dlls/secur32/schannel.c +++ b/dlls/secur32/schannel.c @@ -161,23 +161,24 @@ static void read_config(void) DWORD enabled = 0, default_disabled = 0; HKEY protocols_key, key; WCHAR subkey_name[64]; - unsigned i; + unsigned i, server; DWORD res; static BOOL config_read = FALSE; static const struct { WCHAR key_name[20]; DWORD prot_client_flag; + DWORD prot_server_flag; BOOL enabled; /* If no config is present, enable the protocol */ BOOL disabled_by_default; /* Disable if caller asks for default protocol set */ } protocol_config_keys[] = { - { L"SSL 2.0", SP_PROT_SSL2_CLIENT, FALSE, TRUE }, /* NOTE: TRUE, TRUE on Windows */ - { L"SSL 3.0", SP_PROT_SSL3_CLIENT, TRUE, FALSE }, - { L"TLS 1.0", SP_PROT_TLS1_0_CLIENT, TRUE, FALSE }, - { L"TLS 1.1", SP_PROT_TLS1_1_CLIENT, TRUE, FALSE /* NOTE: not enabled by default on Windows */ }, - { L"TLS 1.2", SP_PROT_TLS1_2_CLIENT, TRUE, FALSE /* NOTE: not enabled by default on Windows */ }, - { L"DTLS 1.0", SP_PROT_DTLS1_0_CLIENT, TRUE, TRUE }, - { L"DTLS 1.2", SP_PROT_DTLS1_2_CLIENT, TRUE, TRUE }, + { L"SSL 2.0", SP_PROT_SSL2_CLIENT, SP_PROT_SSL2_SERVER, FALSE, TRUE }, /* NOTE: TRUE, TRUE on Windows */ + { L"SSL 3.0", SP_PROT_SSL3_CLIENT, SP_PROT_SSL3_SERVER, TRUE, FALSE }, + { L"TLS 1.0", SP_PROT_TLS1_0_CLIENT, SP_PROT_TLS1_0_SERVER, TRUE, FALSE }, + { L"TLS 1.1", SP_PROT_TLS1_1_CLIENT, SP_PROT_TLS1_1_SERVER, TRUE, FALSE /* NOTE: not enabled by default on Windows */ }, + { L"TLS 1.2", SP_PROT_TLS1_2_CLIENT, SP_PROT_TLS1_2_SERVER, TRUE, FALSE /* NOTE: not enabled by default on Windows */ }, + { L"DTLS 1.0", SP_PROT_DTLS1_0_CLIENT, SP_PROT_DTLS1_0_SERVER, TRUE, TRUE }, + { L"DTLS 1.2", SP_PROT_DTLS1_2_CLIENT, SP_PROT_DTLS1_2_SERVER, TRUE, TRUE }, }; /* No need for thread safety */ @@ -191,44 +192,49 @@ static void read_config(void) DWORD type, size, value; for(i = 0; i < ARRAY_SIZE(protocol_config_keys); i++) { - wcscpy(subkey_name, protocol_config_keys[i].key_name); - wcscat(subkey_name, L"\\Client"); - res = RegOpenKeyExW(protocols_key, subkey_name, 0, KEY_READ, &key); - if(res != ERROR_SUCCESS) { - if(protocol_config_keys[i].enabled) - enabled |= protocol_config_keys[i].prot_client_flag; - if(protocol_config_keys[i].disabled_by_default) - default_disabled |= protocol_config_keys[i].prot_client_flag; - continue; - } - - size = sizeof(value); - res = RegQueryValueExW(key, L"enabled", NULL, &type, (BYTE *)&value, &size); - if(res == ERROR_SUCCESS) { - if(type == REG_DWORD && value) - enabled |= protocol_config_keys[i].prot_client_flag; - }else if(protocol_config_keys[i].enabled) { - enabled |= protocol_config_keys[i].prot_client_flag; + for (server = 0; server < 2; server++) { + DWORD flag = server ? protocol_config_keys[i].prot_server_flag + : protocol_config_keys[i].prot_client_flag; + wcscpy(subkey_name, protocol_config_keys[i].key_name); + wcscat(subkey_name, server ? L"\\Server" : L"\\Client"); + res = RegOpenKeyExW(protocols_key, subkey_name, 0, KEY_READ, &key); + if(res != ERROR_SUCCESS) { + if(protocol_config_keys[i].enabled) + enabled |= flag; + if(protocol_config_keys[i].disabled_by_default) + default_disabled |= flag; + continue; + } + + size = sizeof(value); + res = RegQueryValueExW(key, L"enabled", NULL, &type, (BYTE *)&value, &size); + if(res == ERROR_SUCCESS) { + if(type == REG_DWORD && value) + enabled |= flag; + }else if(protocol_config_keys[i].enabled) { + enabled |= flag; + } + + size = sizeof(value); + res = RegQueryValueExW(key, L"DisabledByDefault", NULL, &type, (BYTE *)&value, &size); + if(res == ERROR_SUCCESS) { + if(type != REG_DWORD || value) + default_disabled |= flag; + }else if(protocol_config_keys[i].disabled_by_default) { + default_disabled |= flag; + } + + RegCloseKey(key); } - - size = sizeof(value); - res = RegQueryValueExW(key, L"DisabledByDefault", NULL, &type, (BYTE *)&value, &size); - if(res == ERROR_SUCCESS) { - if(type != REG_DWORD || value) - default_disabled |= protocol_config_keys[i].prot_client_flag; - }else if(protocol_config_keys[i].disabled_by_default) { - default_disabled |= protocol_config_keys[i].prot_client_flag; - } - - RegCloseKey(key); } }else { /* No config, enable all known protocols. */ for(i = 0; i < ARRAY_SIZE(protocol_config_keys); i++) { + DWORD flag = protocol_config_keys[i].prot_client_flag | protocol_config_keys[i].prot_server_flag; if(protocol_config_keys[i].enabled) - enabled |= protocol_config_keys[i].prot_client_flag; + enabled |= flag; if(protocol_config_keys[i].disabled_by_default) - default_disabled |= protocol_config_keys[i].prot_client_flag; + default_disabled |= flag; } } @@ -533,8 +539,8 @@ static BYTE *get_key_blob(const CERT_CONTEXT *ctx, DWORD *size) return ret; } -static SECURITY_STATUS schan_AcquireClientCredentials(const void *schanCred, - PCredHandle phCredential, PTimeStamp ptsExpiry) +static SECURITY_STATUS acquire_credentials_handle(ULONG fCredentialUse, + const SCHANNEL_CRED *schanCred, PCredHandle phCredential, PTimeStamp ptsExpiry) { struct schan_credentials *creds; DWORD enabled_protocols, cred_enabled_protocols; @@ -545,7 +551,7 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const void *schanCred, BYTE *key_blob = NULL; ULONG key_size = 0; - TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred, phCredential, ptsExpiry); + TRACE("fCredentialUse %#lx, schanCred %p, phCredential %p, ptsExpiry %p\n", fCredentialUse, schanCred, phCredential, ptsExpiry); if (schanCred) { @@ -563,6 +569,10 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const void *schanCred, status = SEC_E_OK; } + else if (fCredentialUse & SECPKG_CRED_INBOUND) + { + return SEC_E_NO_CREDENTIALS; + } read_config(); if(schanCred && cred_enabled_protocols) @@ -575,7 +585,7 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const void *schanCred, } if (!(creds = malloc(sizeof(*creds)))) return SEC_E_INSUFFICIENT_MEMORY; - creds->credential_use = SECPKG_CRED_OUTBOUND; + creds->credential_use = fCredentialUse; creds->enabled_protocols = enabled_protocols; if (cert && !(key_blob = get_key_blob(cert, &key_size))) goto fail; @@ -598,11 +608,18 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const void *schanCred, phCredential->dwLower = handle; phCredential->dwUpper = 0; - /* Outbound credentials have no expiry */ if (ptsExpiry) { - ptsExpiry->LowPart = 0; - ptsExpiry->HighPart = 0; + if (fCredentialUse & SECPKG_CRED_INBOUND) + { + /* FIXME: get expiry from cert */ + } + else + { + /* Outbound credentials have no expiry */ + ptsExpiry->LowPart = 0; + ptsExpiry->HighPart = 0; + } } return status; @@ -612,54 +629,6 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const void *schanCred, return SEC_E_INTERNAL_ERROR; } -static SECURITY_STATUS schan_AcquireServerCredentials(const SCHANNEL_CRED *schanCred, - PCredHandle phCredential, PTimeStamp ptsExpiry) -{ - SECURITY_STATUS status; - const CERT_CONTEXT *cert = NULL; - - TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred, phCredential, ptsExpiry); - - if (!schanCred) return SEC_E_NO_CREDENTIALS; - - status = get_cert(schanCred, &cert); - if (status == SEC_E_OK) - { - ULONG_PTR handle; - struct schan_credentials *creds; - - if (!(creds = calloc(1, sizeof(*creds)))) return SEC_E_INSUFFICIENT_MEMORY; - creds->credential_use = SECPKG_CRED_INBOUND; - - handle = schan_alloc_handle(creds, SCHAN_HANDLE_CRED); - if (handle == SCHAN_INVALID_HANDLE) - { - free(creds); - return SEC_E_INTERNAL_ERROR; - } - - phCredential->dwLower = handle; - phCredential->dwUpper = 0; - - /* FIXME: get expiry from cert */ - } - return status; -} - -static SECURITY_STATUS schan_AcquireCredentialsHandle(ULONG fCredentialUse, - const SCHANNEL_CRED *schanCred, PCredHandle phCredential, PTimeStamp ptsExpiry) -{ - SECURITY_STATUS ret; - - if (fCredentialUse == SECPKG_CRED_OUTBOUND) - ret = schan_AcquireClientCredentials(schanCred, phCredential, - ptsExpiry); - else - ret = schan_AcquireServerCredentials(schanCred, phCredential, - ptsExpiry); - return ret; -} - static SECURITY_STATUS SEC_ENTRY schan_AcquireCredentialsHandleA( SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse, PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn, @@ -668,7 +637,7 @@ static SECURITY_STATUS SEC_ENTRY schan_AcquireCredentialsHandleA( TRACE("(%s, %s, 0x%08lx, %p, %p, %p, %p, %p, %p)\n", debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse, pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry); - return schan_AcquireCredentialsHandle(fCredentialUse, + return acquire_credentials_handle(fCredentialUse, pAuthData, phCredential, ptsExpiry); } @@ -680,7 +649,7 @@ static SECURITY_STATUS SEC_ENTRY schan_AcquireCredentialsHandleW( TRACE("(%s, %s, 0x%08lx, %p, %p, %p, %p, %p, %p)\n", debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse, pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry); - return schan_AcquireCredentialsHandle(fCredentialUse, + return acquire_credentials_handle(fCredentialUse, pAuthData, phCredential, ptsExpiry); } From 4b4bf80ab720362da347050015b2328cb6997898 Mon Sep 17 00:00:00 2001 From: Evan Tang Date: Wed, 7 Dec 2022 11:32:23 -0600 Subject: [PATCH 1184/2777] secur32: Fix schannel AcquireCredentialsHandle algorithm mismatch error return. (cherry picked from commit 610fd134b71c27e3c09b7345032dfe29c5a31850) --- dlls/secur32/schannel.c | 13 ++++++++----- dlls/secur32/tests/schannel.c | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c index 0d07286cf11..6b5df3520a7 100644 --- a/dlls/secur32/schannel.c +++ b/dlls/secur32/schannel.c @@ -555,16 +555,15 @@ static SECURITY_STATUS acquire_credentials_handle(ULONG fCredentialUse, if (schanCred) { - const unsigned dtls_protocols = SP_PROT_DTLS_CLIENT | SP_PROT_DTLS1_2_CLIENT; - const unsigned tls_protocols = SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_1_CLIENT | - SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_3_CLIENT; + const unsigned dtls_protocols = SP_PROT_DTLS1_X; + const unsigned non_dtls_protocols = (SP_PROT_X_CLIENTS | SP_PROT_X_SERVERS) & ~SP_PROT_DTLS1_X; status = get_cert(schanCred, &cert); if (status != SEC_E_OK && status != SEC_E_NO_CREDENTIALS) return status; cred_enabled_protocols = get_enabled_protocols(schanCred); - if ((cred_enabled_protocols & tls_protocols) && + if ((cred_enabled_protocols & non_dtls_protocols) && (cred_enabled_protocols & dtls_protocols)) return SEC_E_ALGORITHM_MISMATCH; status = SEC_E_OK; @@ -579,9 +578,13 @@ static SECURITY_STATUS acquire_credentials_handle(ULONG fCredentialUse, enabled_protocols = cred_enabled_protocols & config_enabled_protocols; else enabled_protocols = config_enabled_protocols & ~config_default_disabled_protocols; + if (!(fCredentialUse & SECPKG_CRED_OUTBOUND)) + enabled_protocols &= ~SP_PROT_X_CLIENTS; + if (!(fCredentialUse & SECPKG_CRED_INBOUND)) + enabled_protocols &= ~SP_PROT_X_SERVERS; if(!enabled_protocols) { ERR("Could not find matching protocol\n"); - return SEC_E_NO_AUTHENTICATING_AUTHORITY; + return SEC_E_ALGORITHM_MISMATCH; } if (!(creds = malloc(sizeof(*creds)))) return SEC_E_INSUFFICIENT_MEMORY; diff --git a/dlls/secur32/tests/schannel.c b/dlls/secur32/tests/schannel.c index 33915351cb3..455fcb97aa7 100644 --- a/dlls/secur32/tests/schannel.c +++ b/dlls/secur32/tests/schannel.c @@ -351,6 +351,8 @@ static void testAcquireSecurityContext(void) ok(st == SEC_E_OK, "AcquireCredentialsHandleA failed: %08lx\n", st); if(st == SEC_E_OK) FreeCredentialsHandle(&cred); + st = AcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &cred, NULL); + ok(st == SEC_E_NO_CREDENTIALS, "st = %08lx\n", st); memset(&cred, 0, sizeof(cred)); st = AcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, NULL, NULL, NULL, NULL, &cred, &exp); @@ -363,6 +365,22 @@ static void testAcquireSecurityContext(void) FreeCredentialsHandle(&cred); + /* Should fail if no enabled protocols are available */ + init_cred(&schanCred); + schanCred.grbitEnabledProtocols = SP_PROT_TLS1_X_SERVER; + st = AcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, NULL, &schanCred, NULL, NULL, &cred, &exp); + ok(st == SEC_E_ALGORITHM_MISMATCH, "st = %08lx\n", st); + st = AcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND, NULL, &schanCred, NULL, NULL, &cred, &exp); + ok(st == SEC_E_OK, "AcquireCredentialsHandleA failed: %08lx\n", st); + FreeCredentialsHandle(&cred); + + schanCred.grbitEnabledProtocols = SP_PROT_TLS1_X_CLIENT; + st = AcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, NULL, &schanCred, NULL, NULL, &cred, &exp); + ok(st == SEC_E_OK, "AcquireCredentialsHandleA failed: %08lx\n", st); + FreeCredentialsHandle(&cred); + st = AcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND, NULL, &schanCred, NULL, NULL, &cred, &exp); + ok(st == SEC_E_ALGORITHM_MISMATCH, "st = %08lx\n", st); + /* Bad version in SCHANNEL_CRED */ memset(&schanCred, 0, sizeof(schanCred)); st = AcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, @@ -1668,7 +1686,7 @@ static void test_dtls(void) SECURITY_STATUS status; TimeStamp exp; SCHANNEL_CRED cred; - CredHandle cred_handle; + CredHandle cred_handle, cred_handle2; CtxtHandle ctx_handle, ctx_handle2; SecBufferDesc buffers[3]; ULONG flags_req, flags_ret, attr, prev_buf_len; @@ -1687,6 +1705,19 @@ static void test_dtls(void) } ok( status == SEC_E_OK, "got %08lx\n", status ); + /* Should fail if both DTLS and TLS protocols are requested */ + cred.grbitEnabledProtocols |= SP_PROT_TLS1_CLIENT; + status = AcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, NULL, &cred, NULL, NULL, &cred_handle2, &exp); + ok(status == SEC_E_ALGORITHM_MISMATCH, "status = %08lx\n", status); + + cred.grbitEnabledProtocols = SP_PROT_DTLS1_X_CLIENT | SP_PROT_TLS1_SERVER; + status = AcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, NULL, &cred, NULL, NULL, &cred_handle2, &exp); + ok(status == SEC_E_ALGORITHM_MISMATCH, "status = got %08lx\n", status); + + cred.grbitEnabledProtocols = SP_PROT_DTLS1_X_CLIENT | SP_PROT_SSL3_SERVER; + status = AcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND, NULL, &cred, NULL, NULL, &cred_handle2, &exp); + ok(status == SEC_E_ALGORITHM_MISMATCH, "status = got %08lx\n", status); + flags_req = ISC_REQ_MANUAL_CRED_VALIDATION | ISC_REQ_EXTENDED_ERROR | ISC_REQ_DATAGRAM | ISC_REQ_USE_SUPPLIED_CREDS | ISC_REQ_CONFIDENTIALITY | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT; test_context_output_buffer_size(SP_PROT_DTLS_CLIENT | SP_PROT_DTLS1_2_CLIENT, SCH_CRED_NO_DEFAULT_CREDS, flags_req); From c3a24915dcda0edca9815eaf0f1c66cdaac56cf5 Mon Sep 17 00:00:00 2001 From: Evan Tang Date: Mon, 12 Dec 2022 16:39:45 -0600 Subject: [PATCH 1185/2777] secur32: Add test for schannel AcceptSecurityContext. (cherry picked from commit d423d76f10da57255a2d65e950ee796703966959) --- dlls/secur32/tests/schannel.c | 141 ++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/dlls/secur32/tests/schannel.c b/dlls/secur32/tests/schannel.c index 455fcb97aa7..f0b0b20b08a 100644 --- a/dlls/secur32/tests/schannel.c +++ b/dlls/secur32/tests/schannel.c @@ -1671,6 +1671,146 @@ static void test_application_protocol_negotiation(void) closesocket(sock); } +static void test_server_protocol_negotiation(void) { + BOOL ret; + SECURITY_STATUS status; + ULONG attrs; + SCHANNEL_CRED client_cred, server_cred; + CredHandle client_cred_handle, server_cred_handle; + CtxtHandle client_context, server_context, client_context2, server_context2; + SecPkgContext_ApplicationProtocol protocol; + SecBufferDesc buffers[3]; + PCCERT_CONTEXT cert; + HCRYPTPROV csp; + HCRYPTKEY key; + CRYPT_KEY_PROV_INFO keyProvInfo; + WCHAR ms_def_prov_w[MAX_PATH]; + unsigned buf_size = 8192; + unsigned char *alpn_buffer; + unsigned int *extension_len; + unsigned short *list_len; + int list_start_index, offset = 0; + + if (!pQueryContextAttributesA) + { + win_skip("Required secur32 functions not available\n"); + return; + } + + lstrcpyW(ms_def_prov_w, MS_DEF_PROV_W); + keyProvInfo.pwszContainerName = cspNameW; + keyProvInfo.pwszProvName = ms_def_prov_w; + keyProvInfo.dwProvType = PROV_RSA_FULL; + keyProvInfo.dwFlags = 0; + keyProvInfo.cProvParam = 0; + keyProvInfo.rgProvParam = NULL; + keyProvInfo.dwKeySpec = AT_SIGNATURE; + + cert = CertCreateCertificateContext(X509_ASN_ENCODING, selfSignedCert, sizeof(selfSignedCert)); + ret = CertSetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, 0, &keyProvInfo); + ok(ret, "CertSetCertificateContextProperty failed: %08lx", GetLastError()); + ret = CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_NEWKEYSET); + ok(ret, "CryptAcquireContextW failed: %08lx\n", GetLastError()); + ret = CryptImportKey(csp, privKey, sizeof(privKey), 0, 0, &key); + ok(ret, "CryptImportKey failed: %08lx\n", GetLastError()); + if (!ret) return; + + init_cred(&client_cred); + init_cred(&server_cred); + client_cred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT; + client_cred.dwFlags = SCH_CRED_NO_DEFAULT_CREDS|SCH_CRED_MANUAL_CRED_VALIDATION; + server_cred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER; + server_cred.dwFlags = SCH_CRED_NO_DEFAULT_CREDS|SCH_CRED_MANUAL_CRED_VALIDATION; + server_cred.cCreds = 1; + server_cred.paCred = &cert; + + status = AcquireCredentialsHandleA(NULL, (SEC_CHAR *)UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &client_cred, NULL, NULL, &client_cred_handle, NULL); + ok(status == SEC_E_OK, "got %08lx\n", status); + if (status != SEC_E_OK) return; + status = AcquireCredentialsHandleA(NULL, (SEC_CHAR *)UNISP_NAME_A, SECPKG_CRED_INBOUND, NULL, &server_cred, NULL, NULL, &server_cred_handle, NULL); + ok(status == SEC_E_OK, "got %08lx\n", status); + if (status != SEC_E_OK) return; + + init_buffers(&buffers[0], 4, buf_size); + init_buffers(&buffers[1], 4, buf_size); + init_buffers(&buffers[2], 1, 128); + + alpn_buffer = buffers[2].pBuffers[0].pvBuffer; + extension_len = (unsigned int *)&alpn_buffer[offset]; + offset += sizeof(*extension_len); + *(unsigned int *)&alpn_buffer[offset] = SecApplicationProtocolNegotiationExt_ALPN; + offset += sizeof(unsigned int); + list_len = (unsigned short *)&alpn_buffer[offset]; + offset += sizeof(*list_len); + list_start_index = offset; + + alpn_buffer[offset++] = sizeof("http/1.1") - 1; + memcpy(&alpn_buffer[offset], "http/1.1", sizeof("http/1.1") - 1); + offset += sizeof("http/1.1") - 1; + alpn_buffer[offset++] = sizeof("h2") - 1; + memcpy(&alpn_buffer[offset], "h2", sizeof("h2") - 1); + offset += sizeof("h2") - 1; + + *list_len = offset - list_start_index; + *extension_len = *list_len + sizeof(*extension_len) + sizeof(*list_len); + + buffers[2].pBuffers[0].BufferType = SECBUFFER_APPLICATION_PROTOCOLS; + buffers[2].pBuffers[0].cbBuffer = offset; + buffers[0].pBuffers[0].BufferType = SECBUFFER_TOKEN; + status = InitializeSecurityContextA(&client_cred_handle, NULL, (SEC_CHAR *)"localhost", ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM, 0, 0, &buffers[2], 0, &client_context, &buffers[0], &attrs, NULL); + ok(status == SEC_I_CONTINUE_NEEDED, "got %08lx\n", status); + + buffers[1].pBuffers[0].cbBuffer = buf_size; + buffers[1].pBuffers[0].BufferType = SECBUFFER_TOKEN; + buffers[0].pBuffers[1] = buffers[2].pBuffers[0]; + status = AcceptSecurityContext(&server_cred_handle, NULL, &buffers[0], ASC_REQ_CONFIDENTIALITY|ASC_REQ_STREAM, 0, &server_context, &buffers[1], &attrs, NULL); + ok(status == SEC_I_CONTINUE_NEEDED, "got %08lx\n", status); + memset(&buffers[0].pBuffers[1], 0, sizeof(buffers[0].pBuffers[1])); + + client_context2.dwLower = client_context2.dwUpper = 0xdeadbeef; + buffers[0].pBuffers[0].cbBuffer = buf_size; + status = InitializeSecurityContextA(&client_cred_handle, &client_context, (SEC_CHAR *)"localhost", ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM|ISC_REQ_USE_SUPPLIED_CREDS, 0, 0, &buffers[1], 0, &client_context2, &buffers[0], &attrs, NULL); + ok(client_context.dwLower == client_context2.dwLower, "dwLower mismatch, expected %#Ix, got %#Ix\n", client_context.dwLower, client_context2.dwLower); + ok(client_context.dwUpper == client_context2.dwUpper, "dwUpper mismatch, expected %#Ix, got %#Ix\n", client_context.dwUpper, client_context2.dwUpper); + ok(status == SEC_I_CONTINUE_NEEDED, "got %08lx\n", status); + + server_context2.dwLower = server_context2.dwUpper = 0xdeadbeef; + buffers[1].pBuffers[0].cbBuffer = buf_size; + status = AcceptSecurityContext(&server_cred_handle, &server_context, &buffers[0], ASC_REQ_CONFIDENTIALITY|ASC_REQ_STREAM, 0, &server_context2, &buffers[1], &attrs, NULL); + ok(server_context.dwLower == server_context2.dwLower, "dwLower mismatch, expected %#Ix, got %#Ix\n", server_context.dwLower, server_context2.dwLower); + ok(server_context.dwUpper == server_context2.dwUpper, "dwUpper mismatch, expected %#Ix, got %#Ix\n", server_context.dwUpper, server_context2.dwUpper); + ok(status == SEC_E_OK, "got %08lx\n", status); + + buffers[0].pBuffers[0].cbBuffer = buf_size; + status = InitializeSecurityContextA(&client_cred_handle, &client_context, (SEC_CHAR *)"localhost", ISC_REQ_USE_SUPPLIED_CREDS, 0, 0, &buffers[1], 0, NULL, &buffers[0], &attrs, NULL); + ok(status == SEC_E_OK, "got %08lx\n", status); + + memset(&protocol, 0, sizeof(protocol)); + status = pQueryContextAttributesA(&client_context, SECPKG_ATTR_APPLICATION_PROTOCOL, &protocol); + ok(status == SEC_E_OK || broken(status == SEC_E_UNSUPPORTED_FUNCTION) /* win2k8 */, "got %08lx\n", status); + if (status == SEC_E_OK) + { + ok(protocol.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success, "got %u\n", protocol.ProtoNegoStatus); + ok(protocol.ProtoNegoExt == SecApplicationProtocolNegotiationExt_ALPN, "got %u\n", protocol.ProtoNegoExt); + ok(protocol.ProtocolIdSize == 8, "got %u\n", protocol.ProtocolIdSize); + ok(!memcmp(protocol.ProtocolId, "http/1.1", 8), "wrong protocol id\n"); + } + + DeleteSecurityContext(&client_context); + DeleteSecurityContext(&server_context); + FreeCredentialsHandle(&client_cred_handle); + FreeCredentialsHandle(&server_cred_handle); + + free_buffers(&buffers[0]); + free_buffers(&buffers[1]); + free_buffers(&buffers[2]); + + CryptDestroyKey(key); + CryptReleaseContext(csp, 0); + CryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_DELETEKEYSET); + CertFreeCertificateContext(cert); +} + static void init_dtls_output_buffer(SecBufferDesc *buffer) { buffer->pBuffers[0].BufferType = SECBUFFER_TOKEN; @@ -1949,6 +2089,7 @@ START_TEST(schannel) test_InitializeSecurityContext(); test_communication(); test_application_protocol_negotiation(); + test_server_protocol_negotiation(); test_dtls(); test_connection_shutdown(); } From efad2bf6caed4c046f2a80215a05b2c75ca26321 Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Wed, 1 Feb 2023 13:37:11 -0800 Subject: [PATCH 1186/2777] taskkill: Use exit code 1 when terminating processes. (cherry picked from commit fe6294c74346e9956fb839d2a4ca078c624f6bbf) --- programs/taskkill/taskkill.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/taskkill/taskkill.c b/programs/taskkill/taskkill.c index 2904e64f40a..424e87b9a44 100644 --- a/programs/taskkill/taskkill.c +++ b/programs/taskkill/taskkill.c @@ -341,7 +341,7 @@ static int terminate_processes(void) continue; } - if (!TerminateProcess(process, 0)) + if (!TerminateProcess(process, 1)) { taskkill_message_printfW(STRING_TERMINATE_FAILED, task_list[i]); status_code = 1; @@ -381,7 +381,7 @@ static int terminate_processes(void) continue; } - if (!TerminateProcess(process, 0)) + if (!TerminateProcess(process, 1)) { taskkill_message_printfW(STRING_TERMINATE_FAILED, task_list[i]); status_code = 1; From 6bb1f9467030af620e95c9aa22a8c76f6c665935 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 28 Mar 2023 09:34:12 -0600 Subject: [PATCH 1187/2777] taskkill: Use CRT allocation functions. (cherry picked from commit dd3f3f381f9e761325c7c06236de1241c9605ed6) CW-Bug-Id: #22078 --- programs/taskkill/taskkill.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/programs/taskkill/taskkill.c b/programs/taskkill/taskkill.c index 424e87b9a44..44ed4c79119 100644 --- a/programs/taskkill/taskkill.c +++ b/programs/taskkill/taskkill.c @@ -58,13 +58,13 @@ static int taskkill_vprintfW(const WCHAR *msg, va_list va_args) */ len = WideCharToMultiByte(GetOEMCP(), 0, msg_buffer, wlen, NULL, 0, NULL, NULL); - msgA = HeapAlloc(GetProcessHeap(), 0, len); + msgA = malloc(len); if (!msgA) return 0; WideCharToMultiByte(GetOEMCP(), 0, msg_buffer, wlen, msgA, len, NULL, NULL); WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msgA, len, &count, FALSE); - HeapFree(GetProcessHeap(), 0, msgA); + free(msgA); } return count; @@ -127,7 +127,7 @@ static DWORD *enumerate_processes(DWORD *list_count) { DWORD *pid_list, alloc_bytes = 1024 * sizeof(*pid_list), needed_bytes; - pid_list = HeapAlloc(GetProcessHeap(), 0, alloc_bytes); + pid_list = malloc(alloc_bytes); if (!pid_list) return NULL; @@ -137,7 +137,7 @@ static DWORD *enumerate_processes(DWORD *list_count) if (!EnumProcesses(pid_list, alloc_bytes, &needed_bytes)) { - HeapFree(GetProcessHeap(), 0, pid_list); + free(pid_list); return NULL; } @@ -150,10 +150,10 @@ static DWORD *enumerate_processes(DWORD *list_count) break; alloc_bytes *= 2; - realloc_list = HeapReAlloc(GetProcessHeap(), 0, pid_list, alloc_bytes); + realloc_list = realloc(pid_list, alloc_bytes); if (!realloc_list) { - HeapFree(GetProcessHeap(), 0, pid_list); + free(pid_list); return NULL; } pid_list = realloc_list; @@ -288,7 +288,7 @@ static int send_close_messages(void) } } - HeapFree(GetProcessHeap(), 0, pid_list); + free(pid_list); return status_code; } @@ -403,7 +403,7 @@ static int terminate_processes(void) } } - HeapFree(GetProcessHeap(), 0, pid_list); + free(pid_list); return status_code; } @@ -413,8 +413,7 @@ static BOOL add_to_task_list(WCHAR *name) if (!task_list) { - task_list = HeapAlloc(GetProcessHeap(), 0, - list_size * sizeof(*task_list)); + task_list = malloc(list_size * sizeof(*task_list)); if (!task_list) return FALSE; } @@ -423,8 +422,7 @@ static BOOL add_to_task_list(WCHAR *name) void *realloc_list; list_size *= 2; - realloc_list = HeapReAlloc(GetProcessHeap(), 0, task_list, - list_size * sizeof(*task_list)); + realloc_list = realloc(task_list, list_size * sizeof(*task_list)); if (!realloc_list) return FALSE; @@ -521,7 +519,7 @@ int __cdecl wmain(int argc, WCHAR *argv[]) if (!process_arguments(argc, argv)) { - HeapFree(GetProcessHeap(), 0, task_list); + free(task_list); return 1; } @@ -530,6 +528,6 @@ int __cdecl wmain(int argc, WCHAR *argv[]) else status_code = send_close_messages(); - HeapFree(GetProcessHeap(), 0, task_list); + free(task_list); return status_code; } From be72daaf95651ddccd47310d08bf6b2b7b5c2409 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 28 Mar 2023 10:12:29 -0600 Subject: [PATCH 1188/2777] taskkill: Remove unneeded free() before process exit. (cherry picked from commit 20ab5f06d0972440a7df7fb1ba390ab1b32f3b1d) CW-Bug-Id: #22078 --- programs/taskkill/taskkill.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/programs/taskkill/taskkill.c b/programs/taskkill/taskkill.c index 44ed4c79119..ad5f8e389f7 100644 --- a/programs/taskkill/taskkill.c +++ b/programs/taskkill/taskkill.c @@ -136,10 +136,7 @@ static DWORD *enumerate_processes(DWORD *list_count) DWORD *realloc_list; if (!EnumProcesses(pid_list, alloc_bytes, &needed_bytes)) - { - free(pid_list); return NULL; - } /* EnumProcesses can't signal an insufficient buffer condition, so the * only way to possibly determine whether a larger buffer is required @@ -152,10 +149,7 @@ static DWORD *enumerate_processes(DWORD *list_count) alloc_bytes *= 2; realloc_list = realloc(pid_list, alloc_bytes); if (!realloc_list) - { - free(pid_list); return NULL; - } pid_list = realloc_list; } @@ -288,7 +282,6 @@ static int send_close_messages(void) } } - free(pid_list); return status_code; } @@ -403,7 +396,6 @@ static int terminate_processes(void) } } - free(pid_list); return status_code; } @@ -515,19 +507,10 @@ static BOOL process_arguments(int argc, WCHAR *argv[]) int __cdecl wmain(int argc, WCHAR *argv[]) { - int status_code = 0; - if (!process_arguments(argc, argv)) - { - free(task_list); return 1; - } if (force_termination) - status_code = terminate_processes(); - else - status_code = send_close_messages(); - - free(task_list); - return status_code; + return terminate_processes(); + return send_close_messages(); } From 9deb39feb54096fd7d59adf174964623aa13e27e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 28 Mar 2023 10:09:11 -0600 Subject: [PATCH 1189/2777] taskkill: Enumerate processes in main(). (cherry picked from commit cf4a0b7392f33ba3e0b3fe69007a6d1f327f13f2) CW-Bug-Id: #22078 --- programs/taskkill/taskkill.c | 38 ++++++++++++++---------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/programs/taskkill/taskkill.c b/programs/taskkill/taskkill.c index ad5f8e389f7..595bfa659af 100644 --- a/programs/taskkill/taskkill.c +++ b/programs/taskkill/taskkill.c @@ -33,6 +33,8 @@ static BOOL force_termination = FALSE; static WCHAR **task_list; static unsigned int task_count; +static DWORD *pid_list, pid_list_size; + struct pid_close_info { DWORD pid; @@ -123,20 +125,20 @@ static BOOL CALLBACK pid_enum_proc(HWND hwnd, LPARAM lParam) return TRUE; } -static DWORD *enumerate_processes(DWORD *list_count) +static BOOL enumerate_processes(void) { - DWORD *pid_list, alloc_bytes = 1024 * sizeof(*pid_list), needed_bytes; + DWORD alloc_bytes = 1024 * sizeof(*pid_list), needed_bytes; pid_list = malloc(alloc_bytes); if (!pid_list) - return NULL; + return FALSE; for (;;) { DWORD *realloc_list; if (!EnumProcesses(pid_list, alloc_bytes, &needed_bytes)) - return NULL; + return FALSE; /* EnumProcesses can't signal an insufficient buffer condition, so the * only way to possibly determine whether a larger buffer is required @@ -149,12 +151,12 @@ static DWORD *enumerate_processes(DWORD *list_count) alloc_bytes *= 2; realloc_list = realloc(pid_list, alloc_bytes); if (!realloc_list) - return NULL; + return FALSE; pid_list = realloc_list; } - *list_count = needed_bytes / sizeof(*pid_list); - return pid_list; + pid_list_size = needed_bytes / sizeof(*pid_list); + return TRUE; } static BOOL get_process_name_from_pid(DWORD pid, WCHAR *buf, DWORD chars) @@ -199,18 +201,10 @@ static BOOL get_process_name_from_pid(DWORD pid, WCHAR *buf, DWORD chars) * system processes. */ static int send_close_messages(void) { - DWORD *pid_list, pid_list_size; DWORD self_pid = GetCurrentProcessId(); unsigned int i; int status_code = 0; - pid_list = enumerate_processes(&pid_list_size); - if (!pid_list) - { - taskkill_message(STRING_ENUM_FAILED); - return 1; - } - for (i = 0; i < task_count; i++) { WCHAR *p = task_list[i]; @@ -287,18 +281,10 @@ static int send_close_messages(void) static int terminate_processes(void) { - DWORD *pid_list, pid_list_size; DWORD self_pid = GetCurrentProcessId(); unsigned int i; int status_code = 0; - pid_list = enumerate_processes(&pid_list_size); - if (!pid_list) - { - taskkill_message(STRING_ENUM_FAILED); - return 1; - } - for (i = 0; i < task_count; i++) { WCHAR *p = task_list[i]; @@ -510,6 +496,12 @@ int __cdecl wmain(int argc, WCHAR *argv[]) if (!process_arguments(argc, argv)) return 1; + if (!enumerate_processes()) + { + taskkill_message(STRING_ENUM_FAILED); + return 1; + } + if (force_termination) return terminate_processes(); return send_close_messages(); From 45aba93789c3664131f2ecd9caa7fec6fe4fb77a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 28 Mar 2023 13:21:13 -0600 Subject: [PATCH 1190/2777] taskkill: Factor out get_task_pid(). (cherry picked from commit 62ef3c5be1d2c5374399984588a9daa75663d030) CW-Bug-Id: #22078 --- programs/taskkill/taskkill.c | 234 ++++++++++++----------------------- 1 file changed, 82 insertions(+), 152 deletions(-) diff --git a/programs/taskkill/taskkill.c b/programs/taskkill/taskkill.c index 595bfa659af..d2e1dd54209 100644 --- a/programs/taskkill/taskkill.c +++ b/programs/taskkill/taskkill.c @@ -185,6 +185,55 @@ static BOOL get_process_name_from_pid(DWORD pid, WCHAR *buf, DWORD chars) return TRUE; } +static BOOL get_task_pid(const WCHAR *str, BOOL *is_numeric, WCHAR *process_name, int *status_code, DWORD *pid) +{ + DWORD self_pid = GetCurrentProcessId(); + const WCHAR *p = str; + unsigned int i; + + *is_numeric = TRUE; + while (*p) + { + if (!iswdigit(*p++)) + { + *is_numeric = FALSE; + break; + } + } + + if (*is_numeric) + { + *pid = wcstol(str, NULL, 10); + if (*pid == self_pid) + { + taskkill_message(STRING_SELF_TERMINATION); + *status_code = 1; + return FALSE; + } + return TRUE; + } + + for (i = 0; i < pid_list_size; ++i) + { + if (get_process_name_from_pid(pid_list[i], process_name, MAX_PATH) && + !wcsicmp(process_name, str)) + { + if (pid_list[i] == self_pid) + { + taskkill_message(STRING_SELF_TERMINATION); + *status_code = 1; + return FALSE; + } + *pid = pid_list[i]; + return TRUE; + } + } + + taskkill_message_printfW(STRING_SEARCH_FAILED, str); + *status_code = 128; + return FALSE; +} + /* The implemented task enumeration and termination behavior does not * exactly match native behavior. On Windows: * @@ -201,79 +250,29 @@ static BOOL get_process_name_from_pid(DWORD pid, WCHAR *buf, DWORD chars) * system processes. */ static int send_close_messages(void) { - DWORD self_pid = GetCurrentProcessId(); + WCHAR process_name[MAX_PATH]; + struct pid_close_info info; unsigned int i; int status_code = 0; + BOOL is_numeric; for (i = 0; i < task_count; i++) { - WCHAR *p = task_list[i]; - BOOL is_numeric = TRUE; - - /* Determine whether the string is not numeric. */ - while (*p) - { - if (!iswdigit(*p++)) - { - is_numeric = FALSE; - break; - } - } + if (!get_task_pid(task_list[i], &is_numeric, process_name, &status_code, &info.pid)) + continue; - if (is_numeric) + info.found = FALSE; + EnumWindows(pid_enum_proc, (LPARAM)&info); + if (info.found) { - DWORD pid = wcstol(task_list[i], NULL, 10); - struct pid_close_info info = { pid }; - - if (pid == self_pid) - { - taskkill_message(STRING_SELF_TERMINATION); - status_code = 1; - continue; - } - - EnumWindows(pid_enum_proc, (LPARAM)&info); - if (info.found) - taskkill_message_printfW(STRING_CLOSE_PID_SEARCH, pid); + if (is_numeric) + taskkill_message_printfW(STRING_CLOSE_PID_SEARCH, info.pid); else - { - taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); - status_code = 128; - } - } - else - { - DWORD index; - BOOL found_process = FALSE; - - for (index = 0; index < pid_list_size; index++) - { - WCHAR process_name[MAX_PATH]; - - if (get_process_name_from_pid(pid_list[index], process_name, MAX_PATH) && - !wcsicmp(process_name, task_list[i])) - { - struct pid_close_info info = { pid_list[index] }; - - found_process = TRUE; - if (pid_list[index] == self_pid) - { - taskkill_message(STRING_SELF_TERMINATION); - status_code = 1; - continue; - } - - EnumWindows(pid_enum_proc, (LPARAM)&info); - taskkill_message_printfW(STRING_CLOSE_PROC_SRCH, process_name, pid_list[index]); - } - } - - if (!found_process) - { - taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); - status_code = 128; - } + taskkill_message_printfW(STRING_CLOSE_PROC_SRCH, process_name, info.pid); + continue; } + taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); + status_code = 128; } return status_code; @@ -281,107 +280,38 @@ static int send_close_messages(void) static int terminate_processes(void) { - DWORD self_pid = GetCurrentProcessId(); + WCHAR process_name[MAX_PATH]; unsigned int i; int status_code = 0; + BOOL is_numeric; + HANDLE process; + DWORD pid; for (i = 0; i < task_count; i++) { - WCHAR *p = task_list[i]; - BOOL is_numeric = TRUE; + if (!get_task_pid(task_list[i], &is_numeric, process_name, &status_code, &pid)) + continue; - /* Determine whether the string is not numeric. */ - while (*p) + process = OpenProcess(PROCESS_TERMINATE, FALSE, pid); + if (!process) { - if (!iswdigit(*p++)) - { - is_numeric = FALSE; - break; - } + taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); + status_code = 128; + continue; } - - if (is_numeric) + if (!TerminateProcess(process, 1)) { - DWORD pid = wcstol(task_list[i], NULL, 10); - HANDLE process; - - if (pid == self_pid) - { - taskkill_message(STRING_SELF_TERMINATION); - status_code = 1; - continue; - } - - process = OpenProcess(PROCESS_TERMINATE, FALSE, pid); - if (!process) - { - taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); - status_code = 128; - continue; - } - - if (!TerminateProcess(process, 1)) - { - taskkill_message_printfW(STRING_TERMINATE_FAILED, task_list[i]); - status_code = 1; - CloseHandle(process); - continue; - } - - taskkill_message_printfW(STRING_TERM_PID_SEARCH, pid); + taskkill_message_printfW(STRING_TERMINATE_FAILED, task_list[i]); + status_code = 1; CloseHandle(process); + continue; } + if (is_numeric) + taskkill_message_printfW(STRING_TERM_PID_SEARCH, pid); else - { - DWORD index; - BOOL found_process = FALSE; - - for (index = 0; index < pid_list_size; index++) - { - WCHAR process_name[MAX_PATH]; - - if (get_process_name_from_pid(pid_list[index], process_name, MAX_PATH) && - !wcsicmp(process_name, task_list[i])) - { - HANDLE process; - - if (pid_list[index] == self_pid) - { - taskkill_message(STRING_SELF_TERMINATION); - status_code = 1; - continue; - } - - process = OpenProcess(PROCESS_TERMINATE, FALSE, pid_list[index]); - if (!process) - { - taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); - status_code = 128; - continue; - } - - if (!TerminateProcess(process, 1)) - { - taskkill_message_printfW(STRING_TERMINATE_FAILED, task_list[i]); - status_code = 1; - CloseHandle(process); - continue; - } - - found_process = TRUE; - taskkill_message_printfW(STRING_TERM_PROC_SEARCH, task_list[i], pid_list[index]); - CloseHandle(process); - } - } - - if (!found_process) - { - taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); - status_code = 128; - } - } + taskkill_message_printfW(STRING_TERM_PROC_SEARCH, task_list[i], pid); + CloseHandle(process); } - return status_code; } From d6569e6e74407f3a19fa181210f85cead0cf4f95 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 28 Mar 2023 14:32:31 -0600 Subject: [PATCH 1191/2777] taskkill: Use toolhelp snapshot to get process information. (cherry picked from commit 6cca1f5099a8354b67578b42dd34fd010e80b6de) CW-Bug-Id: #22078 --- programs/taskkill/taskkill.c | 99 ++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 54 deletions(-) diff --git a/programs/taskkill/taskkill.c b/programs/taskkill/taskkill.c index d2e1dd54209..b60b5486f87 100644 --- a/programs/taskkill/taskkill.c +++ b/programs/taskkill/taskkill.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include "taskkill.h" @@ -33,7 +33,13 @@ static BOOL force_termination = FALSE; static WCHAR **task_list; static unsigned int task_count; -static DWORD *pid_list, pid_list_size; +static struct +{ + PROCESSENTRY32W p; + BOOL matched; +} +*process_list; +static unsigned int process_count; struct pid_close_info { @@ -127,61 +133,36 @@ static BOOL CALLBACK pid_enum_proc(HWND hwnd, LPARAM lParam) static BOOL enumerate_processes(void) { - DWORD alloc_bytes = 1024 * sizeof(*pid_list), needed_bytes; + unsigned int alloc_count = 128; + void *realloc_list; + HANDLE snapshot; - pid_list = malloc(alloc_bytes); - if (!pid_list) + snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (snapshot == INVALID_HANDLE_VALUE) return FALSE; - for (;;) - { - DWORD *realloc_list; - - if (!EnumProcesses(pid_list, alloc_bytes, &needed_bytes)) - return FALSE; - - /* EnumProcesses can't signal an insufficient buffer condition, so the - * only way to possibly determine whether a larger buffer is required - * is to see whether the written number of bytes is the same as the - * buffer size. If so, the buffer will be reallocated to twice the - * size. */ - if (alloc_bytes != needed_bytes) - break; - - alloc_bytes *= 2; - realloc_list = realloc(pid_list, alloc_bytes); - if (!realloc_list) - return FALSE; - pid_list = realloc_list; - } - - pid_list_size = needed_bytes / sizeof(*pid_list); - return TRUE; -} - -static BOOL get_process_name_from_pid(DWORD pid, WCHAR *buf, DWORD chars) -{ - HANDLE process; - HMODULE module; - DWORD required_size; - - process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); - if (!process) + process_list = malloc(alloc_count * sizeof(*process_list)); + if (!process_list) return FALSE; - if (!EnumProcessModules(process, &module, sizeof(module), &required_size)) - { - CloseHandle(process); + process_list[0].p.dwSize = sizeof(process_list[0].p); + if (!Process32FirstW(snapshot, &process_list[0].p)) return FALSE; - } - if (!GetModuleBaseNameW(process, module, buf, chars)) + do { - CloseHandle(process); - return FALSE; - } - - CloseHandle(process); + process_list[process_count++].matched = FALSE; + if (process_count == alloc_count) + { + alloc_count *= 2; + realloc_list = realloc(process_list, alloc_count * sizeof(*process_list)); + if (!realloc_list) + return FALSE; + process_list = realloc_list; + } + process_list[process_count].p.dwSize = sizeof(process_list[process_count].p); + } while (Process32NextW(snapshot, &process_list[process_count].p)); + CloseHandle(snapshot); return TRUE; } @@ -204,6 +185,14 @@ static BOOL get_task_pid(const WCHAR *str, BOOL *is_numeric, WCHAR *process_name if (*is_numeric) { *pid = wcstol(str, NULL, 10); + for (i = 0; i < process_count; ++i) + { + if (process_list[i].p.th32ProcessID == *pid) + break; + } + if (i == process_count || process_list[i].matched) + goto not_found; + process_list[i].matched = TRUE; if (*pid == self_pid) { taskkill_message(STRING_SELF_TERMINATION); @@ -213,22 +202,24 @@ static BOOL get_task_pid(const WCHAR *str, BOOL *is_numeric, WCHAR *process_name return TRUE; } - for (i = 0; i < pid_list_size; ++i) + for (i = 0; i < process_count; ++i) { - if (get_process_name_from_pid(pid_list[i], process_name, MAX_PATH) && - !wcsicmp(process_name, str)) + if (!wcsicmp(process_list[i].p.szExeFile, str) && !process_list[i].matched) { - if (pid_list[i] == self_pid) + process_list[i].matched = TRUE; + if (process_list[i].p.th32ProcessID == self_pid) { taskkill_message(STRING_SELF_TERMINATION); *status_code = 1; return FALSE; } - *pid = pid_list[i]; + *pid = process_list[i].p.th32ProcessID; + wcscpy(process_name, process_list[i].p.szExeFile); return TRUE; } } +not_found: taskkill_message_printfW(STRING_SEARCH_FAILED, str); *status_code = 128; return FALSE; From 87f083909ffb149f7788aac219151d830da3db4f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 28 Mar 2023 15:14:17 -0600 Subject: [PATCH 1192/2777] taskkill: Mark processes for termination in main(). (cherry picked from commit 5c851451892e05c1747108432a5a2bff3a78ed9e) CW-Bug-Id: #22078 --- programs/taskkill/taskkill.c | 82 +++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/programs/taskkill/taskkill.c b/programs/taskkill/taskkill.c index b60b5486f87..c32c380f001 100644 --- a/programs/taskkill/taskkill.c +++ b/programs/taskkill/taskkill.c @@ -37,6 +37,7 @@ static struct { PROCESSENTRY32W p; BOOL matched; + BOOL is_numeric; } *process_list; static unsigned int process_count; @@ -151,6 +152,7 @@ static BOOL enumerate_processes(void) do { + process_list[process_count].is_numeric = FALSE; process_list[process_count++].matched = FALSE; if (process_count == alloc_count) { @@ -166,40 +168,42 @@ static BOOL enumerate_processes(void) return TRUE; } -static BOOL get_task_pid(const WCHAR *str, BOOL *is_numeric, WCHAR *process_name, int *status_code, DWORD *pid) +static void mark_task_process(const WCHAR *str, int *status_code) { DWORD self_pid = GetCurrentProcessId(); const WCHAR *p = str; + BOOL is_numeric; unsigned int i; + DWORD pid; - *is_numeric = TRUE; + is_numeric = TRUE; while (*p) { if (!iswdigit(*p++)) { - *is_numeric = FALSE; + is_numeric = FALSE; break; } } - if (*is_numeric) + if (is_numeric) { - *pid = wcstol(str, NULL, 10); + pid = wcstol(str, NULL, 10); for (i = 0; i < process_count; ++i) { - if (process_list[i].p.th32ProcessID == *pid) + if (process_list[i].p.th32ProcessID == pid) break; } if (i == process_count || process_list[i].matched) goto not_found; process_list[i].matched = TRUE; - if (*pid == self_pid) + process_list[i].is_numeric = TRUE; + if (pid == self_pid) { taskkill_message(STRING_SELF_TERMINATION); *status_code = 1; - return FALSE; } - return TRUE; + return; } for (i = 0; i < process_count; ++i) @@ -211,18 +215,27 @@ static BOOL get_task_pid(const WCHAR *str, BOOL *is_numeric, WCHAR *process_name { taskkill_message(STRING_SELF_TERMINATION); *status_code = 1; - return FALSE; } - *pid = process_list[i].p.th32ProcessID; - wcscpy(process_name, process_list[i].p.szExeFile); - return TRUE; + return; } } not_found: taskkill_message_printfW(STRING_SEARCH_FAILED, str); *status_code = 128; - return FALSE; +} + +static void taskkill_message_print_process(int msg, unsigned int index) +{ + WCHAR pid_str[16]; + + if (!process_list[index].is_numeric) + { + taskkill_message_printfW(msg, process_list[index].p.szExeFile); + return; + } + wsprintfW(pid_str, L"%lu", process_list[index].p.th32ProcessID); + taskkill_message_printfW(msg, pid_str); } /* The implemented task enumeration and termination behavior does not @@ -241,28 +254,28 @@ static BOOL get_task_pid(const WCHAR *str, BOOL *is_numeric, WCHAR *process_name * system processes. */ static int send_close_messages(void) { - WCHAR process_name[MAX_PATH]; + const WCHAR *process_name; struct pid_close_info info; unsigned int i; int status_code = 0; - BOOL is_numeric; for (i = 0; i < task_count; i++) { - if (!get_task_pid(task_list[i], &is_numeric, process_name, &status_code, &info.pid)) + if (!process_list[i].matched) continue; - + info.pid = process_list[i].p.th32ProcessID; + process_name = process_list[i].p.szExeFile; info.found = FALSE; EnumWindows(pid_enum_proc, (LPARAM)&info); if (info.found) { - if (is_numeric) + if (process_list[i].is_numeric) taskkill_message_printfW(STRING_CLOSE_PID_SEARCH, info.pid); else taskkill_message_printfW(STRING_CLOSE_PROC_SRCH, process_name, info.pid); continue; } - taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); + taskkill_message_print_process(STRING_SEARCH_FAILED, i); status_code = 128; } @@ -271,36 +284,37 @@ static int send_close_messages(void) static int terminate_processes(void) { - WCHAR process_name[MAX_PATH]; + const WCHAR *process_name; unsigned int i; int status_code = 0; - BOOL is_numeric; HANDLE process; DWORD pid; - for (i = 0; i < task_count; i++) + for (i = 0; i < process_count; i++) { - if (!get_task_pid(task_list[i], &is_numeric, process_name, &status_code, &pid)) + if (!process_list[i].matched) continue; + pid = process_list[i].p.th32ProcessID; + process_name = process_list[i].p.szExeFile; process = OpenProcess(PROCESS_TERMINATE, FALSE, pid); if (!process) { - taskkill_message_printfW(STRING_SEARCH_FAILED, task_list[i]); + taskkill_message_print_process(STRING_SEARCH_FAILED, i); status_code = 128; continue; } if (!TerminateProcess(process, 1)) { - taskkill_message_printfW(STRING_TERMINATE_FAILED, task_list[i]); + taskkill_message_print_process(STRING_TERMINATE_FAILED, i); status_code = 1; CloseHandle(process); continue; } - if (is_numeric) + if (process_list[i].is_numeric) taskkill_message_printfW(STRING_TERM_PID_SEARCH, pid); else - taskkill_message_printfW(STRING_TERM_PROC_SEARCH, task_list[i], pid); + taskkill_message_printfW(STRING_TERM_PROC_SEARCH, process_name, pid); CloseHandle(process); } return status_code; @@ -414,6 +428,9 @@ static BOOL process_arguments(int argc, WCHAR *argv[]) int __cdecl wmain(int argc, WCHAR *argv[]) { + int search_status = 0, terminate_status; + unsigned int i; + if (!process_arguments(argc, argv)) return 1; @@ -423,7 +440,12 @@ int __cdecl wmain(int argc, WCHAR *argv[]) return 1; } + for (i = 0; i < task_count; ++i) + mark_task_process(task_list[i], &search_status); + if (force_termination) - return terminate_processes(); - return send_close_messages(); + terminate_status = terminate_processes(); + else + terminate_status = send_close_messages(); + return search_status ? search_status : terminate_status; } From b90ea0b82880c2e76f0ff35fe543e25b75927ce3 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 28 Mar 2023 08:19:45 -0600 Subject: [PATCH 1193/2777] taskkill: Support terminating child processes. (cherry picked from commit fb6b1c91bbf412f5eba260ae52ee38176fd693d4) CW-Bug-Id: #22078 --- po/ar.po | 13 ++++++++ po/ast.po | 11 +++++++ po/bg.po | 11 +++++++ po/ca.po | 13 ++++++++ po/cs.po | 13 ++++++++ po/da.po | 13 ++++++++ po/de.po | 13 ++++++++ po/el.po | 11 +++++++ po/en.po | 14 +++++++++ po/en_US.po | 14 +++++++++ po/eo.po | 11 +++++++ po/es.po | 13 ++++++++ po/fa.po | 11 +++++++ po/fi.po | 13 ++++++++ po/fr.po | 13 ++++++++ po/he.po | 13 ++++++++ po/hi.po | 11 +++++++ po/hr.po | 11 +++++++ po/hu.po | 13 ++++++++ po/it.po | 13 ++++++++ po/ja.po | 13 ++++++++ po/ko.po | 13 ++++++++ po/lt.po | 13 ++++++++ po/ml.po | 11 +++++++ po/nb_NO.po | 13 ++++++++ po/nl.po | 13 ++++++++ po/or.po | 11 +++++++ po/pa.po | 11 +++++++ po/pl.po | 13 ++++++++ po/pt_BR.po | 13 ++++++++ po/pt_PT.po | 13 ++++++++ po/rm.po | 11 +++++++ po/ro.po | 11 +++++++ po/ru.po | 13 ++++++++ po/si.po | 11 +++++++ po/sk.po | 11 +++++++ po/sl.po | 13 ++++++++ po/sr_RS@cyrillic.po | 11 +++++++ po/sr_RS@latin.po | 11 +++++++ po/sv.po | 13 ++++++++ po/ta.po | 11 +++++++ po/te.po | 11 +++++++ po/th.po | 11 +++++++ po/tr.po | 13 ++++++++ po/uk.po | 13 ++++++++ po/wa.po | 11 +++++++ po/wine.pot | 11 +++++++ po/zh_CN.po | 13 ++++++++ po/zh_TW.po | 13 ++++++++ programs/taskkill/taskkill.c | 59 +++++++++++++++++++++++++++++++---- programs/taskkill/taskkill.h | 2 ++ programs/taskkill/taskkill.rc | 2 ++ 52 files changed, 654 insertions(+), 6 deletions(-) diff --git a/po/ar.po b/po/ar.po index 2888fed4538..b87d6151a2f 100644 --- a/po/ar.po +++ b/po/ar.po @@ -18454,6 +18454,19 @@ msgstr "خطأ : غير قادر على إنهاء العملية \"%1\".\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "خطأ : الإنهاء الذاتي للعملية غير مصرح به.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "العملية ذات الرقم %1!u! أغلقت بالإكراه.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "Ù…&همة جديدة (تشغيل)..." diff --git a/po/ast.po b/po/ast.po index 8b505d8f5d9..91d7d256182 100644 --- a/po/ast.po +++ b/po/ast.po @@ -17101,6 +17101,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "" diff --git a/po/bg.po b/po/bg.po index 3bc0e391cdb..47e12a893e8 100644 --- a/po/bg.po +++ b/po/bg.po @@ -17102,6 +17102,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "" diff --git a/po/ca.po b/po/ca.po index 591482a8c64..90ee5673f7a 100644 --- a/po/ca.po +++ b/po/ca.po @@ -17374,6 +17374,19 @@ msgstr "Error: No s'ha pogut terminar el procés \"%1\".\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Error: No es permet l'autoterminació de procés.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "El procés amb PID %1!u! s'ha terminat a la força.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Tasca nova (executa...)" diff --git a/po/cs.po b/po/cs.po index a453ec50c6e..25a4f1b75e3 100644 --- a/po/cs.po +++ b/po/cs.po @@ -17858,6 +17858,19 @@ msgstr "Chyba: proces „%1“ nelze ukonÄit.\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Chyba: samoukonÄení procesu není dovoleno.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "Proces identifikovaný jako %1!u! (PID) byl násilnÄ› ukonÄen.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Nová úloha (Spustit...)" diff --git a/po/da.po b/po/da.po index 970f7df80c3..c7ee34b8ff9 100644 --- a/po/da.po +++ b/po/da.po @@ -18365,6 +18365,19 @@ msgstr "Fejl: Kunne ikke afslutte processen «%1».\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Fejl: Proces selv-afslutning er ikke tilladt.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "Proces med PID %1!u! blev tvunget til at lukke.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Ny opgave (Kør...)" diff --git a/po/de.po b/po/de.po index 235569a0fab..1ed7acd9d05 100644 --- a/po/de.po +++ b/po/de.po @@ -17341,6 +17341,19 @@ msgstr "Fehler: Prozess \"%1\" konnte nicht beendet werden.\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Fehler: Selbstterminierung von Prozessen ist nicht gestattet.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "Prozess mit der PID %1!u! wurde zum Beenden gezwungen.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Neuer Task (Ausführen...)" diff --git a/po/el.po b/po/el.po index 3a5c6aba714..c5c8307e2cb 100644 --- a/po/el.po +++ b/po/el.po @@ -16742,6 +16742,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "" diff --git a/po/en.po b/po/en.po index 1664c52597b..a9ad0a9cb0a 100644 --- a/po/en.po +++ b/po/en.po @@ -17236,6 +17236,20 @@ msgstr "Error: Unable to terminate process \"%1\".\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Error: Process self-termination is not permitted.\n" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&New Task (Run...)" diff --git a/po/en_US.po b/po/en_US.po index c04161fe970..ab15878a97b 100644 --- a/po/en_US.po +++ b/po/en_US.po @@ -17236,6 +17236,20 @@ msgstr "Error: Unable to terminate process \"%1\".\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Error: Process self-termination is not permitted.\n" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&New Task (Run...)" diff --git a/po/eo.po b/po/eo.po index 8776dd68b21..050cd952e48 100644 --- a/po/eo.po +++ b/po/eo.po @@ -17421,6 +17421,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "" diff --git a/po/es.po b/po/es.po index fe577dd60e3..c19a7daabc1 100644 --- a/po/es.po +++ b/po/es.po @@ -17699,6 +17699,19 @@ msgstr "Error: No se pudo terminar el proceso \"%1\".\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Error: La auto-terminación de un proceso no está permitida.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "El proceso con el PID %1!u! ha sido terminado forzosamente.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Nueva Tarea (Ejecutar...)" diff --git a/po/fa.po b/po/fa.po index 5388bf13738..40491717d00 100644 --- a/po/fa.po +++ b/po/fa.po @@ -16934,6 +16934,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "" diff --git a/po/fi.po b/po/fi.po index aa5f747223d..51f6dc4736e 100644 --- a/po/fi.po +++ b/po/fi.po @@ -17198,6 +17198,19 @@ msgstr "Virhe: Prosessia \"%1\" ei voida sulkea.\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Virhe: Prosessin itsensä sulkemista ei sallita.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "Prosessi PID %1!u! suljettiin väkisin.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Uusi tehtävä (Suorita...)" diff --git a/po/fr.po b/po/fr.po index b84024c5fea..b3d2ea080c0 100644 --- a/po/fr.po +++ b/po/fr.po @@ -17940,6 +17940,19 @@ msgstr "Erreur : impossible de terminer le processus « %1 ».\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Erreur : un processus ne peut pas se terminer lui-même.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "Le processus de PID %1!u! a été terminé brutalement.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Nouvelle tâche (Exécuter...)" diff --git a/po/he.po b/po/he.po index fc504572108..2e716c65960 100644 --- a/po/he.po +++ b/po/he.po @@ -17871,6 +17871,19 @@ msgstr "Error: Unable to terminate process \"%1\".\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Error: Process self-termination is not permitted.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "Process with PID %1!u! was forcibly terminated.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "משימה &חדשה (הפעלה...)" diff --git a/po/hi.po b/po/hi.po index 03919a4a1ca..08201ec785b 100644 --- a/po/hi.po +++ b/po/hi.po @@ -16412,6 +16412,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "" diff --git a/po/hr.po b/po/hr.po index f9e965d2a08..cab03b4c47b 100644 --- a/po/hr.po +++ b/po/hr.po @@ -17827,6 +17827,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Novi zadatak (Pokreni...)" diff --git a/po/hu.po b/po/hu.po index aefd8906dfd..6b70faab001 100644 --- a/po/hu.po +++ b/po/hu.po @@ -18356,6 +18356,19 @@ msgstr "Hiba: Nem lehet megszakítani a \"%1\" folyamatot.\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Hiba: A folyamat önmegszakítás nem engedélyezett.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "%1!u! PID azonosítóval rendelkezÅ‘ folyamatok kényszerbÅ‘l leálltak.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "Új feladat (f&uttatás...)" diff --git a/po/it.po b/po/it.po index 7c7e9c26e6a..d2bf050bd81 100644 --- a/po/it.po +++ b/po/it.po @@ -18443,6 +18443,19 @@ msgstr "Errore: impossibile terminare il processo \"%1\".\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Errore: l'auto-terminazione del processo non è permessa.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "Il processo con PID %1!u! è stato terminato forzatamente.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Nuovo processo (Esegui...)" diff --git a/po/ja.po b/po/ja.po index 31e2e57eeb8..ee177c0aaa8 100644 --- a/po/ja.po +++ b/po/ja.po @@ -17235,6 +17235,19 @@ msgstr "エラー: プロセス(%1)を終了ã§ãã¾ã›ã‚“。\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "エラー: ã“ã®ãƒ—ロセス自身を終了ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "プロセス(PID %1!u!)ã¯å¼·åˆ¶çš„ã«çµ‚了ã•ã‚Œã¾ã—ãŸã€‚\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "æ–°ã—ã„タスクã®å®Ÿè¡Œ(&N)..." diff --git a/po/ko.po b/po/ko.po index 30301f559f1..fde0ddc1d3b 100644 --- a/po/ko.po +++ b/po/ko.po @@ -17175,6 +17175,19 @@ msgstr "오류: \"%1\" 프로세스를 중단할 수 없습니다.\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "오류: 프로세스 ìžì²´ 종료는 허용ë˜ì§€ 않습니다.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "PID %1!u! 프로세스를 강제로 종료하였습니다.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "새 ìž‘ì—…(&N) (실행...)" diff --git a/po/lt.po b/po/lt.po index 4ef96a92e99..2fe2909a0d6 100644 --- a/po/lt.po +++ b/po/lt.po @@ -17252,6 +17252,19 @@ msgstr "Klaida: nepavyko nutraukti proceso „%1“.\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Klaida: savo proceso priverstinis nutraukimas negalimas.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "Procesas su PID %1!u! priverstinai nutrauktas.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Nauja užduotis (vykdyti...)" diff --git a/po/ml.po b/po/ml.po index 3b431aec552..29b316c025c 100644 --- a/po/ml.po +++ b/po/ml.po @@ -16411,6 +16411,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "" diff --git a/po/nb_NO.po b/po/nb_NO.po index 01b12008f5c..ec59d534991 100644 --- a/po/nb_NO.po +++ b/po/nb_NO.po @@ -17920,6 +17920,19 @@ msgstr "Feil: Klarte ikke stoppe prosessen \"%1\".\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Feil: Selvterminering av prosesser er ikke tillatt.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "Tvang avslutning av prosessen med PID %1!u!.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Ny oppgave (Kjør...)" diff --git a/po/nl.po b/po/nl.po index bc4e374862c..b571b48a26b 100644 --- a/po/nl.po +++ b/po/nl.po @@ -17320,6 +17320,19 @@ msgstr "Fout: Kon proces \"%1\" niet beëindigen.\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Fout: Zelf-beëindiging van een proces is niet toegestaan.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "Proces met PID %1!u! is geforceerd beëindigd.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Nieuwe taak (uitvoeren...)" diff --git a/po/or.po b/po/or.po index 0082689f58d..4efb1620ccb 100644 --- a/po/or.po +++ b/po/or.po @@ -16397,6 +16397,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "" diff --git a/po/pa.po b/po/pa.po index 4c3f431b746..fb970b7c963 100644 --- a/po/pa.po +++ b/po/pa.po @@ -16397,6 +16397,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "" diff --git a/po/pl.po b/po/pl.po index 583db3af500..723493afaa2 100644 --- a/po/pl.po +++ b/po/pl.po @@ -17455,6 +17455,19 @@ msgstr "BÅ‚Ä…d: Nie można zakoÅ„czyć procesu \"%1\".\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "BÅ‚Ä…d: Samo-zakoÅ„czenie procesu nie jest dozwolone.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "Proces z PID %1!u! zostaÅ‚ zmuszony do zakoÅ„czenia.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Nowe zadanie (Uruchom...)" diff --git a/po/pt_BR.po b/po/pt_BR.po index 2cfd2549ed6..d6821db3689 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -17517,6 +17517,19 @@ msgstr "Erro: Incapaz de finalizar o processo \"%1\".\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Erro: Auto finalização do processo não é permitida.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "Processo com PID %1!u! foi finalizado à força.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Nova Tarefa (Executar...)" diff --git a/po/pt_PT.po b/po/pt_PT.po index 3eb5aaeea63..833b8b23ade 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -18091,6 +18091,19 @@ msgstr "Erro: Incapaz de terminar o processo \"%1\".\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Erro: auto-terminação de processo não é permitida.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "O processo com PID %1!u! foi forçado a terminar.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Nova Tarefa (Executar...)" diff --git a/po/rm.po b/po/rm.po index 33ee55775af..412e3dc6c5e 100644 --- a/po/rm.po +++ b/po/rm.po @@ -16525,6 +16525,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "" diff --git a/po/ro.po b/po/ro.po index 68592b86328..6c82bb5c603 100644 --- a/po/ro.po +++ b/po/ro.po @@ -18122,6 +18122,17 @@ msgstr "Eroare: Procesul „%1†nu a putut fi terminat.\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "Sarcină &nouă (executare...)" diff --git a/po/ru.po b/po/ru.po index d30632b6cef..cb918603b72 100644 --- a/po/ru.po +++ b/po/ru.po @@ -17484,6 +17484,19 @@ msgstr "Ошибка: завершить процеÑÑ Â«%1» не ÑƒÐ´Ð°Ð»Ð¾Ñ msgid "Error: Process self-termination is not permitted.\n" msgstr "Ошибка: Ñамозавершение процеÑÑа запрещено.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "ПроцеÑÑ Ñ PID %1!u! завершён принудительно.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&ÐÐ¾Ð²Ð°Ñ Ð·Ð°Ð´Ð°Ñ‡Ð° (Выполнить...)" diff --git a/po/si.po b/po/si.po index 4e2270c3320..bb39137afd5 100644 --- a/po/si.po +++ b/po/si.po @@ -17150,6 +17150,17 @@ msgstr "දà·à·‚ය: ක්රියà·à·€à¶½à·’ය \"%1\" නතර කරන msgid "Error: Process self-termination is not permitted.\n" msgstr "දà·à·‚ය: ක්රියà·à·€à¶½à·’යක් තමංම නතර කරන්න බà·à·„à·.\n" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "අලුත් කà·à¶»à·Šà¶ºà¶ºà¶šà·Š (ධà·à·€à¶± කරන්න...) (&N)" diff --git a/po/sk.po b/po/sk.po index c2387d413c6..c018db3e215 100644 --- a/po/sk.po +++ b/po/sk.po @@ -17601,6 +17601,17 @@ msgstr "Chyba: Nemožno ukonÄiÅ¥ proces \"%1\".\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Nová úloha (Spusti...)" diff --git a/po/sl.po b/po/sl.po index 2708682753e..02638b23811 100644 --- a/po/sl.po +++ b/po/sl.po @@ -18380,6 +18380,19 @@ msgstr "Napaka: ni mogoÄe konÄati opravila \"%1\".\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Napaka: samo-konÄanje opravila ni dovoljeno.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "Opravilo s PID %1!u! je bilo prisilno konÄano.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Novo opravilo (Zaženi ...)" diff --git a/po/sr_RS@cyrillic.po b/po/sr_RS@cyrillic.po index 34cd34c3246..63e76fa78f5 100644 --- a/po/sr_RS@cyrillic.po +++ b/po/sr_RS@cyrillic.po @@ -17673,6 +17673,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "" diff --git a/po/sr_RS@latin.po b/po/sr_RS@latin.po index ed7e9811776..e0977ce9ac3 100644 --- a/po/sr_RS@latin.po +++ b/po/sr_RS@latin.po @@ -17867,6 +17867,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "" diff --git a/po/sv.po b/po/sv.po index 5e52599bef0..5f4397962bf 100644 --- a/po/sv.po +++ b/po/sv.po @@ -18052,6 +18052,19 @@ msgstr "Fel: Kunde inte avsluta processen \"%1\".\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Fel: Processen fÃ¥r inte avsluta sig själv.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "Tvingade fram nedstängning av processen med PID %1!u!.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Ny aktivitet (Kör...)" diff --git a/po/ta.po b/po/ta.po index 368a3a2a2d4..2d1c803e1ad 100644 --- a/po/ta.po +++ b/po/ta.po @@ -16325,6 +16325,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "" diff --git a/po/te.po b/po/te.po index 25980d922a7..c0c7e8116a0 100644 --- a/po/te.po +++ b/po/te.po @@ -16397,6 +16397,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "" diff --git a/po/th.po b/po/th.po index b8a67e4c1a1..8f563d508b7 100644 --- a/po/th.po +++ b/po/th.po @@ -17044,6 +17044,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "" diff --git a/po/tr.po b/po/tr.po index 4b8b1c096fd..28cee4524cd 100644 --- a/po/tr.po +++ b/po/tr.po @@ -17403,6 +17403,19 @@ msgstr "Hata: \"%1\" iÅŸlemi sonlandırılamıyor.\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "Hata: Ä°ÅŸlemin kendini sonlandırmasına izin verilmiyor.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "PID'i %1!u! olan iÅŸlem zorla sonlandırıldı.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Yeni Görev (Çalıştır...)" diff --git a/po/uk.po b/po/uk.po index fdce4739263..2d941b5248f 100644 --- a/po/uk.po +++ b/po/uk.po @@ -17338,6 +17338,19 @@ msgstr "Помилка: Ðе вдаєтьÑÑ Ð·Ð°Ð²ÐµÑ€ÑˆÐ¸Ñ‚Ð¸ Ð¿Ñ€Ð¾Ñ†ÐµÑ \" msgid "Error: Process self-termination is not permitted.\n" msgstr "Помилка: Ð¡Ð°Ð¼Ð¾Ð¿Ñ€Ð¸Ð¿Ð¸Ð½ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ†ÐµÑу не дозволене.\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "ÐŸÑ€Ð¾Ñ†ÐµÑ Ð· PID %1!u! був завершений примуÑово.\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "&Ðове Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ (Виконати...)" diff --git a/po/wa.po b/po/wa.po index cd0417b2569..13d79d4eeca 100644 --- a/po/wa.po +++ b/po/wa.po @@ -16896,6 +16896,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "" diff --git a/po/wine.pot b/po/wine.pot index 266b26e4acb..881b048e33b 100644 --- a/po/wine.pot +++ b/po/wine.pot @@ -16304,6 +16304,17 @@ msgstr "" msgid "Error: Process self-termination is not permitted.\n" msgstr "" +#: programs/taskkill/taskkill.rc:44 +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "" diff --git a/po/zh_CN.po b/po/zh_CN.po index e72b7053aaa..f226c3b1ced 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -16994,6 +16994,19 @@ msgstr "错误: 无法结æŸè¿›ç¨‹ \"%1\"。\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "错误: ä¸å…许结æŸæœ¬è¿›ç¨‹ã€‚\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "å·²ç»å¼ºè¡Œç»“æŸ PID 为 %1!u! 的进程。\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "新任务(&N)..." diff --git a/po/zh_TW.po b/po/zh_TW.po index 1def9b22a99..2a93c59445a 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -17059,6 +17059,19 @@ msgstr "錯誤: 無法終止處ç†ç¨‹åº %1。\n" msgid "Error: Process self-termination is not permitted.\n" msgstr "錯誤: 處ç†ç¨‹åºä¸å…許自我終止。\n" +#: programs/taskkill/taskkill.rc:44 +#, fuzzy +#| msgid "Process with PID %1!u! was forcibly terminated.\n" +msgid "" +"The process with PID %1!u! (child process of PID %2!u!) has been " +"terminated.\n" +msgstr "處ç†ç¨‹åº PID %1!u! 已被強制終止。\n" + +#: programs/taskkill/taskkill.rc:45 +msgid "" +"Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" +msgstr "" + #: programs/taskmgr/taskmgr.rc:37 programs/taskmgr/taskmgr.rc:108 msgid "&New Task (Run...)" msgstr "執行新工作(&N)..." diff --git a/programs/taskkill/taskkill.c b/programs/taskkill/taskkill.c index c32c380f001..1eff832f0ea 100644 --- a/programs/taskkill/taskkill.c +++ b/programs/taskkill/taskkill.c @@ -29,6 +29,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(taskkill); static BOOL force_termination = FALSE; +static BOOL kill_child_processes; static WCHAR **task_list; static unsigned int task_count; @@ -238,6 +239,46 @@ static void taskkill_message_print_process(int msg, unsigned int index) taskkill_message_printfW(msg, pid_str); } +static BOOL find_parent(unsigned int process_index, unsigned int *parent_index) +{ + DWORD parent_id = process_list[process_index].p.th32ParentProcessID; + unsigned int i; + + if (!parent_id) + return FALSE; + + for (i = 0; i < process_count; ++i) + { + if (process_list[i].p.th32ProcessID == parent_id) + { + *parent_index = i; + return TRUE; + } + } + return FALSE; +} + +static void mark_child_processes(void) +{ + unsigned int i, parent; + + for (i = 0; i < process_count; ++i) + { + if (process_list[i].matched) + continue; + parent = i; + while (find_parent(parent, &parent)) + { + if (process_list[parent].matched) + { + WINE_TRACE("Adding child %04lx.\n", process_list[i].p.th32ProcessID); + process_list[i].matched = TRUE; + break; + } + } + } +} + /* The implemented task enumeration and termination behavior does not * exactly match native behavior. On Windows: * @@ -259,17 +300,20 @@ static int send_close_messages(void) unsigned int i; int status_code = 0; - for (i = 0; i < task_count; i++) + for (i = 0; i < process_count; i++) { if (!process_list[i].matched) continue; info.pid = process_list[i].p.th32ProcessID; process_name = process_list[i].p.szExeFile; info.found = FALSE; + WINE_TRACE("Terminating pid %04lx.\n", info.pid); EnumWindows(pid_enum_proc, (LPARAM)&info); if (info.found) { - if (process_list[i].is_numeric) + if (kill_child_processes) + taskkill_message_printfW(STRING_CLOSE_CHILD, info.pid, process_list[i].p.th32ParentProcessID); + else if (process_list[i].is_numeric) taskkill_message_printfW(STRING_CLOSE_PID_SEARCH, info.pid); else taskkill_message_printfW(STRING_CLOSE_PROC_SRCH, process_name, info.pid); @@ -311,7 +355,9 @@ static int terminate_processes(void) CloseHandle(process); continue; } - if (process_list[i].is_numeric) + if (kill_child_processes) + taskkill_message_printfW(STRING_TERM_CHILD, pid, process_list[i].p.th32ParentProcessID); + else if (process_list[i].is_numeric) taskkill_message_printfW(STRING_TERM_PID_SEARCH, pid); else taskkill_message_printfW(STRING_TERM_PROC_SEARCH, process_name, pid); @@ -378,8 +424,8 @@ static BOOL process_arguments(int argc, WCHAR *argv[]) argdata++; if (!wcsicmp(L"t", argdata)) - WINE_FIXME("argument T not supported\n"); - if (!wcsicmp(L"f", argdata)) + kill_child_processes = TRUE; + else if (!wcsicmp(L"f", argdata)) force_termination = TRUE; /* Options /IM and /PID appear to behave identically, except for * the fact that they cannot be specified at the same time. */ @@ -442,7 +488,8 @@ int __cdecl wmain(int argc, WCHAR *argv[]) for (i = 0; i < task_count; ++i) mark_task_process(task_list[i], &search_status); - + if (kill_child_processes) + mark_child_processes(); if (force_termination) terminate_status = terminate_processes(); else diff --git a/programs/taskkill/taskkill.h b/programs/taskkill/taskkill.h index 7972a156f3c..068f817f546 100644 --- a/programs/taskkill/taskkill.h +++ b/programs/taskkill/taskkill.h @@ -35,3 +35,5 @@ #define STRING_ENUM_FAILED 112 #define STRING_TERMINATE_FAILED 113 #define STRING_SELF_TERMINATION 114 +#define STRING_TERM_CHILD 115 +#define STRING_CLOSE_CHILD 116 diff --git a/programs/taskkill/taskkill.rc b/programs/taskkill/taskkill.rc index e6ad8afac75..fd195f3f8c0 100644 --- a/programs/taskkill/taskkill.rc +++ b/programs/taskkill/taskkill.rc @@ -40,4 +40,6 @@ STRINGTABLE STRING_ENUM_FAILED, "Error: Unable to enumerate the process list.\n" STRING_TERMINATE_FAILED, "Error: Unable to terminate process \"%1\".\n" STRING_SELF_TERMINATION, "Error: Process self-termination is not permitted.\n" + STRING_TERM_CHILD, "The process with PID %1!u! (child process of PID %2!u!) has been terminated.\n" + STRING_CLOSE_CHILD, "Sent termination signal to process with PID %1!u!, child of PID %2!u!.\n" } From 8cd4b03fa340c45934f12bf48f452ef5e0a01365 Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Mon, 12 Dec 2022 22:49:24 -0700 Subject: [PATCH 1194/2777] include: Add RTL_CONSTANT_STRING. (cherry picked from commit 7ada8b96fb1dc305028a29fd3f4d1b0f019da75c) --- include/ntdef.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/ntdef.h b/include/ntdef.h index 92366c3f3bb..8d04f83da5d 100644 --- a/include/ntdef.h +++ b/include/ntdef.h @@ -84,4 +84,6 @@ typedef struct _RTL_BALANCED_NODE #define RTL_BALANCED_NODE_RESERVED_PARENT_MASK 3 +#define RTL_CONSTANT_STRING(s) { sizeof(s) - sizeof(s[0]), sizeof(s), (void*)s } + #endif /* _NTDEF_ */ From 8aa9281e69f16f819b6f31470e91e79bf2ce454e Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Thu, 9 Feb 2023 23:04:17 -0700 Subject: [PATCH 1195/2777] services: Avoid calling RtlInitUnicodeString on a static constant. (cherry picked from commit dccc6a60b67db35c3cdc6333aa0146a5ab4bae2c) --- programs/services/services.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/services/services.c b/programs/services/services.c index 6bda0a4008b..8a3ff754329 100644 --- a/programs/services/services.c +++ b/programs/services/services.c @@ -1074,9 +1074,9 @@ static DWORD service_start_process(struct service_entry *service_entry, struct p CreateEnvironmentBlock(&environment, token, FALSE); if (GetEnvironmentVariableW( L"WINEBOOTSTRAPMODE", val, ARRAY_SIZE(val) )) { - UNICODE_STRING name, value; + UNICODE_STRING name = RTL_CONSTANT_STRING(L"WINEBOOTSTRAPMODE"); + UNICODE_STRING value; - RtlInitUnicodeString( &name, L"WINEBOOTSTRAPMODE" ); RtlInitUnicodeString( &value, val ); RtlSetEnvironmentVariable( (WCHAR **)&environment, &name, &value ); } From fd0147727f1fe98483b6a1be5f964dd62adfa7de Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 29 Mar 2023 18:17:58 -0600 Subject: [PATCH 1196/2777] services: Create service processes in a job. (cherry picked from commit 466a86bc5460a3b1d9c253d3e82da2eb63b0775c) CW-Bug-Id: #22078 --- programs/services/services.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/programs/services/services.c b/programs/services/services.c index 8a3ff754329..9efedab43d2 100644 --- a/programs/services/services.c +++ b/programs/services/services.c @@ -47,6 +47,7 @@ static DWORD default_preshutdown_timeout = 180000; static DWORD autostart_delay = 120000; static void *environment = NULL; static HKEY service_current_key = NULL; +static HANDLE job_object; static const BOOL is_win64 = (sizeof(void *) > sizeof(int)); @@ -1102,6 +1103,8 @@ static DWORD service_start_process(struct service_entry *service_entry, struct p release_process(process); return err; } + if (!AssignProcessToJobObject(job_object, pi.hProcess)) + WINE_ERR("Could not add object to job.\n"); process->process_id = pi.dwProcessId; process->process = pi.hProcess; @@ -1284,9 +1287,18 @@ int __cdecl main(int argc, char *argv[]) 'C','o','n','t','r','o','l','\\', 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0}; static const WCHAR svcctl_started_event[] = SVCCTL_STARTED_EVENT; + JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_limit; HANDLE started_event; DWORD err; + job_object = CreateJobObjectW(NULL, NULL); + job_limit.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; + if (!SetInformationJobObject(job_object, JobObjectExtendedLimitInformation, &job_limit, sizeof(job_limit))) + { + WINE_ERR("Failed to initialized job object, err %lu.\n", GetLastError()); + return GetLastError(); + } + started_event = CreateEventW(NULL, TRUE, FALSE, svcctl_started_event); err = RegCreateKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0, From 56c6f69b0018c087b1172ea1da56a7e519cde5cc Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 29 Mar 2023 19:03:58 -0600 Subject: [PATCH 1197/2777] services: Factor out notify_service_state() function. (cherry picked from commit 3580d466cc122729ed3825fa394cc4b0d4333c20) CW-Bug-Id: #22078 --- programs/services/rpc.c | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/programs/services/rpc.c b/programs/services/rpc.c index e56d25ea1af..863a605ef35 100644 --- a/programs/services/rpc.c +++ b/programs/services/rpc.c @@ -868,11 +868,32 @@ static void fill_notify(struct sc_notify_handle *notify, struct service_entry *s SetEvent(notify->event); } +static void notify_service_state(struct service_entry *service) +{ + struct sc_service_handle *service_handle; + DWORD mask; + + mask = 1 << (service->status.dwCurrentState - SERVICE_STOPPED); + LIST_FOR_EACH_ENTRY(service_handle, &service->handles, struct sc_service_handle, entry) + { + struct sc_notify_handle *notify = service_handle->notify; + if (notify && (notify->notify_mask & mask)) + { + fill_notify(notify, service); + sc_notify_release(notify); + service_handle->notify = NULL; + service_handle->status_notified = TRUE; + } + else + service_handle->status_notified = FALSE; + } +} + DWORD __cdecl svcctl_SetServiceStatus(SC_RPC_HANDLE handle, SERVICE_STATUS *status) { - struct sc_service_handle *service, *service_handle; + struct sc_service_handle *service; struct process_entry *process; - DWORD err, mask; + DWORD err; WINE_TRACE("(%p, %p)\n", handle, status); @@ -902,21 +923,7 @@ DWORD __cdecl svcctl_SetServiceStatus(SC_RPC_HANDLE handle, SERVICE_STATUS *stat release_process(process); } - mask = 1 << (service->service_entry->status.dwCurrentState - SERVICE_STOPPED); - LIST_FOR_EACH_ENTRY(service_handle, &service->service_entry->handles, struct sc_service_handle, entry) - { - struct sc_notify_handle *notify = service_handle->notify; - if (notify && (notify->notify_mask & mask)) - { - fill_notify(notify, service->service_entry); - sc_notify_release(notify); - service_handle->notify = NULL; - service_handle->status_notified = TRUE; - } - else - service_handle->status_notified = FALSE; - } - + notify_service_state(service->service_entry); service_unlock(service->service_entry); return ERROR_SUCCESS; From eb39a306af162a88a337a40fda0f9466ca6810b3 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 29 Mar 2023 18:19:03 -0600 Subject: [PATCH 1198/2777] services: Change running service state once its process dies. (cherry picked from commit c0c68ee83a42eb4fd8af661e55b89b56fb32e149) CW-Bug-Id: #22078 --- programs/services/rpc.c | 2 +- programs/services/services.c | 61 +++++++++++++++- programs/services/services.h | 1 + programs/services/tests/service.c | 117 ++++++++++++++++++++++++++++++ 4 files changed, 178 insertions(+), 3 deletions(-) diff --git a/programs/services/rpc.c b/programs/services/rpc.c index 863a605ef35..b3d5c9403fe 100644 --- a/programs/services/rpc.c +++ b/programs/services/rpc.c @@ -868,7 +868,7 @@ static void fill_notify(struct sc_notify_handle *notify, struct service_entry *s SetEvent(notify->event); } -static void notify_service_state(struct service_entry *service) +void notify_service_state(struct service_entry *service) { struct sc_service_handle *service_handle; DWORD mask; diff --git a/programs/services/services.c b/programs/services/services.c index 9efedab43d2..2db74f99e0f 100644 --- a/programs/services/services.c +++ b/programs/services/services.c @@ -47,7 +47,7 @@ static DWORD default_preshutdown_timeout = 180000; static DWORD autostart_delay = 120000; static void *environment = NULL; static HKEY service_current_key = NULL; -static HANDLE job_object; +static HANDLE job_object, job_completion_port; static const BOOL is_win64 = (sizeof(void *) > sizeof(int)); @@ -1280,6 +1280,50 @@ static void load_registry_parameters(void) RegCloseKey( key ); } +static DWORD WINAPI process_monitor_thread_proc( void *arg ) +{ + struct scmdatabase *db = active_database; + struct service_entry *service; + struct process_entry *process; + OVERLAPPED *overlapped; + ULONG_PTR value; + DWORD key, pid; + + while (GetQueuedCompletionStatus(job_completion_port, &key, &value, &overlapped, INFINITE)) + { + if (!key) + break; + if (key != JOB_OBJECT_MSG_EXIT_PROCESS) + continue; + pid = (ULONG_PTR)overlapped; + WINE_TRACE("pid %04lx exited.\n", pid); + scmdatabase_lock(db); + LIST_FOR_EACH_ENTRY(service, &db->services, struct service_entry, entry) + { + if (service->status.dwCurrentState != SERVICE_RUNNING || !service->process + || service->process->process_id != pid) continue; + + WINE_TRACE("Stopping service %s.\n", debugstr_w(service->config.lpBinaryPathName)); + service->status.dwCurrentState = SERVICE_STOPPED; + service->status.dwControlsAccepted = 0; + service->status.dwWin32ExitCode = ERROR_PROCESS_ABORTED; + service->status.dwServiceSpecificExitCode = 0; + service->status.dwCheckPoint = 0; + service->status.dwWaitHint = 0; + SetEvent(service->status_changed_event); + + process = service->process; + service->process = NULL; + process->use_count--; + release_process(process); + notify_service_state(service); + } + scmdatabase_unlock(db); + } + WINE_TRACE("Terminating.\n"); + return 0; +} + int __cdecl main(int argc, char *argv[]) { static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\', @@ -1288,7 +1332,8 @@ int __cdecl main(int argc, char *argv[]) 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0}; static const WCHAR svcctl_started_event[] = SVCCTL_STARTED_EVENT; JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_limit; - HANDLE started_event; + JOBOBJECT_ASSOCIATE_COMPLETION_PORT port_info; + HANDLE started_event, process_monitor_thread; DWORD err; job_object = CreateJobObjectW(NULL, NULL); @@ -1298,6 +1343,15 @@ int __cdecl main(int argc, char *argv[]) WINE_ERR("Failed to initialized job object, err %lu.\n", GetLastError()); return GetLastError(); } + job_completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); + port_info.CompletionPort = job_completion_port; + port_info.CompletionKey = job_object; + if (!SetInformationJobObject(job_object, JobObjectAssociateCompletionPortInformation, + &port_info, sizeof(port_info))) + { + WINE_ERR("Failed to set completion port for job, err %lu.\n", GetLastError()); + return GetLastError(); + } started_event = CreateEventW(NULL, TRUE, FALSE, svcctl_started_event); @@ -1316,8 +1370,11 @@ int __cdecl main(int argc, char *argv[]) if ((err = RPC_Init()) == ERROR_SUCCESS) { scmdatabase_autostart_services(active_database); + process_monitor_thread = CreateThread(NULL, 0, process_monitor_thread_proc, NULL, 0, NULL); SetEvent(started_event); WaitForSingleObject(exit_event, INFINITE); + PostQueuedCompletionStatus(job_completion_port, 0, 0, NULL); + WaitForSingleObject(process_monitor_thread, INFINITE); scmdatabase_wait_terminate(active_database); if (delayed_autostart_cleanup) { diff --git a/programs/services/services.h b/programs/services/services.h index 908a36e6514..1d9dbfdcbff 100644 --- a/programs/services/services.h +++ b/programs/services/services.h @@ -93,6 +93,7 @@ void release_service(struct service_entry *service); void service_lock(struct service_entry *service); void service_unlock(struct service_entry *service); DWORD service_start(struct service_entry *service, DWORD service_argc, LPCWSTR *service_argv); +void notify_service_state(struct service_entry *service); /* Process functions */ diff --git a/programs/services/tests/service.c b/programs/services/tests/service.c index f069347ff37..99cf0838bf0 100644 --- a/programs/services/tests/service.c +++ b/programs/services/tests/service.c @@ -616,6 +616,122 @@ static void test_runner(void (*p_run_test)(void)) CloseHandle(thread); } +static void CALLBACK notify_cb(void *user) +{ +} + +static inline void test_kill_service_process(void) +{ + static const char *argv[2] = {"param1", "param2"}; + SC_HANDLE service_handle = register_service("simple_service"); + SERVICE_STATUS_PROCESS status2; + SERVICE_NOTIFYW notify; + SERVICE_STATUS status; + DWORD bytes, error; + HANDLE process; + BOOL res; + + if(!service_handle) + return; + + trace("starting...\n"); + res = StartServiceA(service_handle, 2, argv); + ok(res, "StartService failed: %lu\n", GetLastError()); + if(!res) { + DeleteService(service_handle); + CloseServiceHandle(service_handle); + return; + } + expect_event("RUNNING"); + + memset(¬ify, 0, sizeof(notify)); + notify.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE; + notify.dwNotificationStatus = 0xdeadbeef; + notify.pfnNotifyCallback = notify_cb; + notify.pContext = ¬ify; + error = NotifyServiceStatusChangeW(service_handle, SERVICE_NOTIFY_STOPPED | SERVICE_NOTIFY_RUNNING + | SERVICE_NOTIFY_PAUSED | SERVICE_NOTIFY_PAUSE_PENDING | SERVICE_NOTIFY_STOP_PENDING, ¬ify); + ok(error == ERROR_SUCCESS, "got error %lu.\n", error); + + /* This shouldn't wait, we are supposed to get service start notification before. */ + SleepEx(5000, TRUE); + ok(!notify.dwNotificationStatus, "got %#lx.\n", notify.dwNotificationStatus); + ok(notify.dwNotificationTriggered == SERVICE_NOTIFY_RUNNING, "got %#lx.\n", notify.dwNotificationTriggered); + ok(notify.ServiceStatus.dwCurrentState == SERVICE_RUNNING, "got %#lx.\n", notify.ServiceStatus.dwCurrentState); + ok(!notify.ServiceStatus.dwWin32ExitCode, "got %#lx.\n", notify.ServiceStatus.dwWin32ExitCode); + + res = QueryServiceStatus(service_handle, &status); + ok(res, "got error %lu.\n", GetLastError()); + ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "got %lx.\n", status.dwServiceType); + ok(status.dwCurrentState == SERVICE_RUNNING, "got %lx.\n", status.dwCurrentState); + + res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes); + ok(res, "got error %lu.\n", GetLastError()); + ok(status2.dwCurrentState == SERVICE_RUNNING, "got %lx.\n", status2.dwCurrentState); + ok(status2.dwProcessId, "got %ld\n", status2.dwProcessId); + + process = OpenProcess(PROCESS_TERMINATE, FALSE, status2.dwProcessId); + ok(!!process, "got NULL.\n"); + res = TerminateProcess(process, 0xdeadbeef); + ok(res, "got error %lu.\n", GetLastError()); + CloseHandle(process); + + memset(¬ify, 0, sizeof(notify)); + notify.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE; + notify.dwNotificationStatus = 0xdeadbeef; + notify.pfnNotifyCallback = notify_cb; + notify.pContext = ¬ify; + error = NotifyServiceStatusChangeW(service_handle, SERVICE_NOTIFY_STOPPED | SERVICE_NOTIFY_RUNNING + | SERVICE_NOTIFY_PAUSED | SERVICE_NOTIFY_PAUSE_PENDING | SERVICE_NOTIFY_STOP_PENDING, ¬ify); + ok(error == ERROR_SUCCESS, "got error %lu.\n", error); + + SleepEx(3000, TRUE); + ok(!notify.dwNotificationStatus, "got %#lx.\n", notify.dwNotificationStatus); + ok(notify.dwNotificationTriggered == SERVICE_NOTIFY_STOPPED, "got %#lx.\n", notify.dwNotificationTriggered); + ok(notify.ServiceStatus.dwCurrentState == SERVICE_STOPPED, "got %#lx.\n", notify.ServiceStatus.dwCurrentState); + ok(notify.ServiceStatus.dwWin32ExitCode == ERROR_PROCESS_ABORTED, "got %#lx.\n", notify.ServiceStatus.dwWin32ExitCode); + ok(!notify.ServiceStatus.dwServiceSpecificExitCode, "got %#lx.\n", notify.ServiceStatus.dwWin32ExitCode); + + res = QueryServiceStatus(service_handle, &status); + ok(res, "got error %lu.\n", error); + ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "got %lx.\n", status.dwServiceType); + ok(status.dwCurrentState == SERVICE_STOPPED, "got %lx.\n", status.dwCurrentState); + ok(!status.dwControlsAccepted, "got %lx\n", status.dwControlsAccepted); + ok(status.dwWin32ExitCode == ERROR_PROCESS_ABORTED, "got %ld.\n", status.dwWin32ExitCode); + ok(!status.dwServiceSpecificExitCode, "got %ld.\n", + status.dwServiceSpecificExitCode); + ok(!status.dwCheckPoint, "got %ld.\n", status.dwCheckPoint); + ok(!status.dwWaitHint, "got %ld.\n", status.dwWaitHint); + + res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes); + ok(res, "got error %lu.\n", error); + ok(!status2.dwProcessId, "got %ld.\n", status2.dwProcessId); + + res = DeleteService(service_handle); + ok(res, "got error %lu.\n", error); + + res = QueryServiceStatus(service_handle, &status); + ok(res, "got error %lu.\n", error); + ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "got %lx.\n", status.dwServiceType); + ok(status.dwCurrentState == SERVICE_STOPPED, "got %lx.\n", status.dwCurrentState); + ok(status.dwControlsAccepted == 0, "got %lx.\n", status.dwControlsAccepted); + ok(status.dwWin32ExitCode == ERROR_PROCESS_ABORTED, "got %ld.\n", status.dwWin32ExitCode); + ok(status.dwServiceSpecificExitCode == 0, "got %ld.\n", + status.dwServiceSpecificExitCode); + ok(!status.dwCheckPoint, "got %ld.\n", status.dwCheckPoint); + ok(!status.dwWaitHint, "got %ld.\n", status.dwWaitHint); + + res = QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO, (BYTE *)&status2, sizeof(status2), &bytes); + ok(res, "got error %lu.\n", GetLastError()); + ok(!status2.dwProcessId, "got %ld.\n", status2.dwProcessId); + + CloseServiceHandle(service_handle); + + res = QueryServiceStatus(service_handle, &status); + ok(!res, "QueryServiceStatus should have failed.\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "got %ld.\n", GetLastError()); +} + START_TEST(service) { char **argv; @@ -641,6 +757,7 @@ START_TEST(service) if(argc < 3) { test_runner(test_service); test_runner(test_no_stop); + test_runner(test_kill_service_process); }else { strcpy(service_name, argv[3]); sprintf(named_pipe_name, "\\\\.\\pipe\\%s_pipe", service_name); From c4cf6488429cab1d6084d60a39327fee8480734d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 27 Mar 2023 21:18:36 -0600 Subject: [PATCH 1199/2777] wined3d: Rename Deck GPU in description table. CW-Bug-Id: #22080 --- dlls/wined3d/directx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index 9b6901d25c0..9385d05deaf 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -539,7 +539,7 @@ static const struct wined3d_gpu_description gpu_description_table[] = {HW_VENDOR_AMD, CARD_AMD_RADEON_RX_NAVI_21, "Radeon RX 6800/6800 XT / 6900 XT", DRIVER_AMD_RX, 16384}, {HW_VENDOR_AMD, CARD_AMD_RADEON_PRO_V620, "Radeon Pro V620", DRIVER_AMD_RX, 32768}, {HW_VENDOR_AMD, CARD_AMD_RADEON_PRO_V620_VF, "Radeon Pro V620 VF", DRIVER_AMD_RX, 32768}, - {HW_VENDOR_AMD, CARD_AMD_VANGOGH, "AMD VANGOGH", DRIVER_AMD_RX, 4096}, + {HW_VENDOR_AMD, CARD_AMD_VANGOGH, "AMD Radeon VANGOGH", DRIVER_AMD_RX, 4096}, /* Red Hat */ {HW_VENDOR_REDHAT, CARD_REDHAT_VIRGL, "Red Hat VirtIO GPU", DRIVER_REDHAT_VIRGL, 1024}, From 4ac6bcd7144024753996a311718dd492a6e86285 Mon Sep 17 00:00:00 2001 From: Dmitry Timoshkov Date: Sat, 3 Dec 2022 21:11:00 +0300 Subject: [PATCH 1200/2777] win32u: Give full access rights to the process window station. Fix CEF applications crash at start without --no-sandbox option. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53981 Signed-off-by: Dmitry Timoshkov (cherry picked from commit b99c67569f8ca939fba84dc3c8d448570daa753e) CW-Bug-Id: #22034 --- dlls/user32/tests/winstation.c | 5 +++++ dlls/win32u/winstation.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/dlls/user32/tests/winstation.c b/dlls/user32/tests/winstation.c index 9c27b5afd01..d77dd7f3f5a 100644 --- a/dlls/user32/tests/winstation.c +++ b/dlls/user32/tests/winstation.c @@ -133,6 +133,11 @@ static void test_handles(void) ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %ld\n", GetLastError() ); print_object( w1 ); + status = NtQueryObject( w1, ObjectBasicInformation, &info, sizeof(info), NULL ); + ok( !status, "NtQueryObject failed, status %#lx\n", status ); + ok( info.GrantedAccess == (STANDARD_RIGHTS_REQUIRED | WINSTA_ALL_ACCESS), + "Got unexpected access %#lx\n", info.GrantedAccess ); + flags = 0; ok( GetHandleInformation( w1, &flags ), "GetHandleInformation failed\n" ); ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) || diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 28771584712..a3ee69e26ee 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -801,7 +801,7 @@ void winstation_init(void) InitializeObjectAttributes( &attr, &str, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, dir, NULL ); - handle = NtUserCreateWindowStation( &attr, WINSTA_ALL_ACCESS, 0, 0, 0, 0, 0 ); + handle = NtUserCreateWindowStation( &attr, STANDARD_RIGHTS_REQUIRED | WINSTA_ALL_ACCESS, 0, 0, 0, 0, 0 ); if (handle) { NtUserSetProcessWindowStation( handle ); From a0132bb45034cff717e717209e1321f2f949300d Mon Sep 17 00:00:00 2001 From: Dmitry Timoshkov Date: Sat, 3 Dec 2022 21:33:42 +0300 Subject: [PATCH 1201/2777] win32u: Give full access rights to the thread desktop. Fix CEF applications crash at start without --no-sandbox option. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53981 Signed-off-by: Dmitry Timoshkov (cherry picked from commit 02e3e17b4dd62eb71d867d0140d3061de683ba29) CW-Bug-Id: #22034 --- dlls/user32/tests/winstation.c | 5 +++++ dlls/win32u/winstation.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/dlls/user32/tests/winstation.c b/dlls/user32/tests/winstation.c index d77dd7f3f5a..4fece752aad 100644 --- a/dlls/user32/tests/winstation.c +++ b/dlls/user32/tests/winstation.c @@ -275,6 +275,11 @@ static void test_handles(void) ok( GetHandleInformation( d1, &flags ), "GetHandleInformation failed\n" ); ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), "handle %p PROTECT_FROM_CLOSE set\n", d1 ); + status = NtQueryObject( d1, ObjectBasicInformation, &info, sizeof(info), NULL ); + ok( !status, "NtQueryObject failed, status %#lx\n", status ); + ok( info.GrantedAccess == (STANDARD_RIGHTS_REQUIRED | DESKTOP_ALL_ACCESS), + "Got unexpected access %#lx\n", info.GrantedAccess ); + SetLastError( 0xdeadbeef ); ok( !CloseDesktop(d1), "closing thread desktop succeeded\n" ); ok( GetLastError() == ERROR_BUSY || broken(GetLastError() == 0xdeadbeef), /* wow64 */ diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index a3ee69e26ee..79808010598 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -825,7 +825,7 @@ void winstation_init(void) InitializeObjectAttributes( &attr, &str, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, dir, NULL ); - handle = NtUserCreateDesktopEx( &attr, NULL, NULL, 0, DESKTOP_ALL_ACCESS, 0 ); + handle = NtUserCreateDesktopEx( &attr, NULL, NULL, 0, STANDARD_RIGHTS_REQUIRED | DESKTOP_ALL_ACCESS, 0 ); if (handle) NtUserSetThreadDesktop( handle ); } NtClose( dir ); From 2316ab20a39474e5291fedc884df3a40535f4edf Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 23 Mar 2023 12:59:42 -0600 Subject: [PATCH 1202/2777] crypt32: Support user properties for certificates. (cherry picked from commit 3d38e85964386f6066758e088a10f58d35b7b354) CW-Bug-Id: #22034 --- dlls/crypt32/cert.c | 13 +++++++++++++ dlls/crypt32/serialize.c | 6 ++++++ dlls/crypt32/tests/cert.c | 20 ++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/dlls/crypt32/cert.c b/dlls/crypt32/cert.c index a0b5747f2d3..b9645770ce1 100644 --- a/dlls/crypt32/cert.c +++ b/dlls/crypt32/cert.c @@ -714,6 +714,19 @@ static BOOL CertContext_SetProperty(cert_t *cert, DWORD dwPropId, if (!cert->base.properties) ret = FALSE; + else if (dwPropId >= CERT_FIRST_USER_PROP_ID && dwPropId <= CERT_LAST_USER_PROP_ID) + { + if (pvData) + { + const CRYPT_DATA_BLOB *blob = pvData; + ret = ContextPropertyList_SetProperty(cert->base.properties, dwPropId, blob->pbData, blob->cbData); + } + else + { + ContextPropertyList_RemoveProperty(cert->base.properties, dwPropId); + ret = TRUE; + } + } else { switch (dwPropId) diff --git a/dlls/crypt32/serialize.c b/dlls/crypt32/serialize.c index 47ab834bf48..11d39188880 100644 --- a/dlls/crypt32/serialize.c +++ b/dlls/crypt32/serialize.c @@ -405,6 +405,12 @@ static BOOL CRYPT_ReadContextProp( SetLastError(ERROR_FILE_NOT_FOUND); ret = FALSE; } + else if (hdr->propID >= CERT_FIRST_USER_PROP_ID && hdr->propID <= CERT_LAST_USER_PROP_ID) + { + CRYPT_DATA_BLOB blob = { hdr->cb, (LPBYTE)pbElement }; + + ret = contextInterface->setProp(context, hdr->propID, 0, &blob); + } else if (hdr->propID != CERT_CERT_PROP_ID && hdr->propID != CERT_CRL_PROP_ID && hdr->propID != CERT_CTL_PROP_ID) { diff --git a/dlls/crypt32/tests/cert.c b/dlls/crypt32/tests/cert.c index 0de6aa717bf..83594560efa 100644 --- a/dlls/crypt32/tests/cert.c +++ b/dlls/crypt32/tests/cert.c @@ -369,6 +369,7 @@ static void testCertProperties(void) BYTE hash[20] = { 0 }, hashProperty[20]; CRYPT_DATA_BLOB blob; CERT_KEY_CONTEXT keyContext; + unsigned int value; ok(context != NULL, "CertCreateCertificateContext failed: %08lx\n", GetLastError()); @@ -566,6 +567,25 @@ static void testCertProperties(void) free(buf); } } + + ret = CertGetCertificateContextProperty(context, CERT_LAST_USER_PROP_ID, NULL, &size); + ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND, "got ret %d, error %#lx.\n", ret, GetLastError()); + + blob.cbData = sizeof(value); + blob.pbData = (BYTE *)&value; + value = 1; + ret = CertSetCertificateContextProperty(context, CERT_LAST_USER_PROP_ID, 0, &blob); + ok(ret, "got error %#lx.\n", GetLastError()); + value = 0xdeadbeef; + size = 0xdeadbeef; + ret = CertGetCertificateContextProperty(context, CERT_LAST_USER_PROP_ID, NULL, &size); + ok(ret, "got error %#lx.\n", GetLastError()); + ok(size == sizeof(value), "got size %lu.\n", size); + ret = CertGetCertificateContextProperty(context, CERT_LAST_USER_PROP_ID, &value, &size); + ok(ret, "got error %#lx.\n", GetLastError()); + ok(size == sizeof(value), "got size %lu.\n", size); + ok(value == 1, "got value %u.\n", value); + CertFreeCertificateContext(context); context = CertCreateCertificateContext(X509_ASN_ENCODING, From cbbe31dc62ff4e4941b122a9338ec37e9457083f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 23 Mar 2023 13:23:53 -0600 Subject: [PATCH 1203/2777] crypt32: Use CERT_STORE_ADD_ALWAYS when reading certs from registry. (cherry picked from commit 49f0331cefe1dd69d869ce6bce4201b610adaba1) CW-Bug-Id: #22034 --- dlls/crypt32/regstore.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/dlls/crypt32/regstore.c b/dlls/crypt32/regstore.c index 3899c805531..e472da5a773 100644 --- a/dlls/crypt32/regstore.c +++ b/dlls/crypt32/regstore.c @@ -56,8 +56,7 @@ static void CRYPT_HashToStr(const BYTE *hash, LPWSTR asciiHash) wsprintfW(asciiHash + i * 2, L"%02X", hash[i]); } -static void CRYPT_RegReadSerializedFromReg(HKEY key, DWORD contextType, - HCERTSTORE store) +static void CRYPT_RegReadSerializedFromReg(HKEY key, DWORD contextType, HCERTSTORE store, DWORD disposition) { LONG rc; DWORD index = 0; @@ -130,7 +129,7 @@ static void CRYPT_RegReadSerializedFromReg(HKEY key, DWORD contextType, TRACE("hash matches, adding\n"); contextInterface->addContextToStore( store, context, - CERT_STORE_ADD_REPLACE_EXISTING, NULL); + disposition, NULL); } else TRACE("hash doesn't match, ignoring\n"); @@ -149,7 +148,7 @@ static void CRYPT_RegReadSerializedFromReg(HKEY key, DWORD contextType, } while (!rc); } -static void CRYPT_RegReadFromReg(HKEY key, HCERTSTORE store) +static void CRYPT_RegReadFromReg(HKEY key, HCERTSTORE store, DWORD disposition) { static const WCHAR * const subKeys[] = { L"Certificates", L"CRLs", L"CTLs" }; static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG, @@ -165,7 +164,7 @@ static void CRYPT_RegReadFromReg(HKEY key, HCERTSTORE store) &hKey, NULL); if (!rc) { - CRYPT_RegReadSerializedFromReg(hKey, contextFlags[i], store); + CRYPT_RegReadSerializedFromReg(hKey, contextFlags[i], store, disposition); RegCloseKey(hKey); } } @@ -463,7 +462,7 @@ static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags, CERT_STORE_CREATE_NEW_FLAG, NULL); CRYPT_RegFlushStore(store, FALSE); - CRYPT_RegReadFromReg(store->key, memStore); + CRYPT_RegReadFromReg(store->key, memStore, CERT_STORE_ADD_REPLACE_EXISTING); I_CertUpdateStore(store->memStore, memStore, 0, 0); CertCloseStore(memStore, 0); break; @@ -551,7 +550,7 @@ WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags, list_init(®Info->certsToDelete); list_init(®Info->crlsToDelete); list_init(®Info->ctlsToDelete); - CRYPT_RegReadFromReg(regInfo->key, regInfo->memStore); + CRYPT_RegReadFromReg(regInfo->key, regInfo->memStore, CERT_STORE_ADD_ALWAYS); regInfo->dirty = FALSE; provInfo.cbSize = sizeof(provInfo); provInfo.cStoreProvFunc = ARRAY_SIZE(regProvFuncs); From b91d13559da6675710f35b61306a2a22fbd4108a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 22 Mar 2023 15:55:06 -0600 Subject: [PATCH 1204/2777] crypt32: Refactor CRYPT_ImportSystemRootCertsToReg(). (cherry picked from commit 330d6ab88f17672543e9287643f68f6880b93130) CW-Bug-Id: #22034 --- dlls/crypt32/rootstore.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/dlls/crypt32/rootstore.c b/dlls/crypt32/rootstore.c index ab3a396b651..fb90c5bde7c 100644 --- a/dlls/crypt32/rootstore.c +++ b/dlls/crypt32/rootstore.c @@ -657,7 +657,7 @@ static HCERTSTORE create_root_store(void) void CRYPT_ImportSystemRootCertsToReg(void) { HCERTSTORE store = NULL; - HKEY key; + HKEY key = NULL; LONG rc; HANDLE hsem; @@ -674,24 +674,28 @@ void CRYPT_ImportSystemRootCertsToReg(void) } if(GetLastError() == ERROR_ALREADY_EXISTS) + { WaitForSingleObject(hsem, INFINITE); - else + goto done; + } + + rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\SystemCertificates\\Root\\Certificates", 0, NULL, 0, + KEY_ALL_ACCESS, NULL, &key, 0); + if (rc) + goto done; + + if (!(store = create_root_store())) { - if ((store = create_root_store())) - { - rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\SystemCertificates\\Root\\Certificates", 0, NULL, 0, - KEY_ALL_ACCESS, NULL, &key, 0); - if (!rc) - { - if (!CRYPT_SerializeContextsToReg(key, REG_OPTION_VOLATILE, pCertInterface, store)) - ERR("Failed to import system certs into registry, %08lx\n", GetLastError()); - RegCloseKey(key); - } - CertCloseStore(store, 0); - } else - ERR("Failed to create root store\n"); + ERR("Failed to create root store\n"); + goto done; } + if (!CRYPT_SerializeContextsToReg(key, REG_OPTION_VOLATILE, pCertInterface, store)) + ERR("Failed to import system certs into registry, %08lx\n", GetLastError()); + +done: + RegCloseKey(key); + CertCloseStore(store, 0); root_certs_imported = TRUE; ReleaseSemaphore(hsem, 1, NULL); CloseHandle(hsem); From 73891e9aceb7d58a60425355fcd7b975cf4c97c0 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 23 Mar 2023 15:18:28 -0600 Subject: [PATCH 1205/2777] crypt32: Refactor read_trusted_roots_from_known_locations(). (cherry picked from commit 463bd7c3e012c98592e530bb0e16d23d083aac03) CW-Bug-Id: #22034 --- dlls/crypt32/rootstore.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/dlls/crypt32/rootstore.c b/dlls/crypt32/rootstore.c index fb90c5bde7c..85efe5354bd 100644 --- a/dlls/crypt32/rootstore.c +++ b/dlls/crypt32/rootstore.c @@ -614,29 +614,30 @@ static void add_ms_root_certs(HCERTSTORE to) */ static void read_trusted_roots_from_known_locations(HCERTSTORE store) { - HCERTSTORE from = CertOpenStore(CERT_STORE_PROV_MEMORY, - X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); + HCERTSTORE new; DWORD needed; struct enum_root_certs_params params = { NULL, 2048, &needed }; - if (from) + new = CertOpenStore( CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL ); + if (!new) return; + + params.buffer = CryptMemAlloc( params.size ); + while (!CRYPT32_CALL( enum_root_certs, ¶ms )) { - params.buffer = CryptMemAlloc( params.size ); - while (!CRYPT32_CALL( enum_root_certs, ¶ms )) + if (needed > params.size) { - if (needed > params.size) - { - CryptMemFree( params.buffer ); - params.buffer = CryptMemAlloc( needed ); - params.size = needed; - } - else CertAddEncodedCertificateToStore( from, X509_ASN_ENCODING, params.buffer, needed, - CERT_STORE_ADD_NEW, NULL ); + CryptMemFree( params.buffer ); + params.buffer = CryptMemAlloc( needed ); + params.size = needed; + continue; } - CryptMemFree( params.buffer ); - check_and_store_certs(from, store); + CertAddEncodedCertificateToStore( new, X509_ASN_ENCODING, params.buffer, needed, + CERT_STORE_ADD_NEW, NULL ); } - CertCloseStore(from, 0); + CryptMemFree( params.buffer ); + check_and_store_certs( new, store ); + + CertCloseStore( new, 0 ); } static HCERTSTORE create_root_store(void) From 6eb71455552854463a9a18f00c9ec614ee562f33 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 22 Mar 2023 19:07:23 -0600 Subject: [PATCH 1206/2777] crypt32: Keep root certs cached in registry unless some are deleted on host. (cherry picked from commit caf5ae1981840d2541889ba90e055553f52ab69e) CW-Bug-Id: #22034 --- dlls/crypt32/crypt32_private.h | 2 + dlls/crypt32/regstore.c | 2 +- dlls/crypt32/rootstore.c | 124 ++++++++++++++++++++++++++++----- 3 files changed, 110 insertions(+), 18 deletions(-) diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h index 41c5ec523be..e29249b1136 100644 --- a/dlls/crypt32/crypt32_private.h +++ b/dlls/crypt32/crypt32_private.h @@ -349,6 +349,8 @@ WINECRYPT_CERTSTORE *CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv, void CRYPT_ImportSystemRootCertsToReg(void) DECLSPEC_HIDDEN; BOOL CRYPT_SerializeContextsToReg(HKEY key, DWORD flags, const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore) DECLSPEC_HIDDEN; +void CRYPT_RegReadSerializedFromReg(HKEY key, DWORD contextType, + HCERTSTORE store, DWORD disposition) DECLSPEC_HIDDEN; DWORD CRYPT_IsCertificateSelfSigned(const CERT_CONTEXT *cert) DECLSPEC_HIDDEN; diff --git a/dlls/crypt32/regstore.c b/dlls/crypt32/regstore.c index e472da5a773..4f8914798f6 100644 --- a/dlls/crypt32/regstore.c +++ b/dlls/crypt32/regstore.c @@ -56,7 +56,7 @@ static void CRYPT_HashToStr(const BYTE *hash, LPWSTR asciiHash) wsprintfW(asciiHash + i * 2, L"%02X", hash[i]); } -static void CRYPT_RegReadSerializedFromReg(HKEY key, DWORD contextType, HCERTSTORE store, DWORD disposition) +void CRYPT_RegReadSerializedFromReg(HKEY key, DWORD contextType, HCERTSTORE store, DWORD disposition) { LONG rc; DWORD index = 0; diff --git a/dlls/crypt32/rootstore.c b/dlls/crypt32/rootstore.c index 85efe5354bd..cfddcc143ac 100644 --- a/dlls/crypt32/rootstore.c +++ b/dlls/crypt32/rootstore.c @@ -98,7 +98,7 @@ static const char *get_cert_common_name(PCCERT_CONTEXT cert) return name; } -static void check_and_store_certs(HCERTSTORE from, HCERTSTORE to) +static void check_and_store_certs(HCERTSTORE cached, HCERTSTORE new, HCERTSTORE to) { DWORD root_count = 0; CERT_CHAIN_ENGINE_CONFIG chainEngineConfig = @@ -114,14 +114,14 @@ static void check_and_store_certs(HCERTSTORE from, HCERTSTORE to) PCCERT_CONTEXT cert = NULL; do { - cert = CertEnumCertificatesInStore(from, cert); + cert = CertEnumCertificatesInStore(new, cert); if (cert) { CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } }; PCCERT_CHAIN_CONTEXT chain; BOOL ret; - ret = CertGetCertificateChain(engine, cert, NULL, from, + ret = CertGetCertificateChain(engine, cert, NULL, cached, &chainPara, CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL, NULL, &chain); if (!ret) TRACE("rejecting %s: %s\n", get_cert_common_name(cert), @@ -595,16 +595,28 @@ static const struct CONST_BLOB { { rootcertauthority2011, sizeof(rootcertauthority2011) }, }; -static void add_ms_root_certs(HCERTSTORE to) +static void add_ms_root_certs(HCERTSTORE to, HCERTSTORE cached) { + PCCERT_CONTEXT cert, existing; DWORD i; TRACE("\n"); for (i = 0; i < ARRAY_SIZE(msRootCerts); i++) + { if (!CertAddEncodedCertificateToStore(to, X509_ASN_ENCODING, - msRootCerts[i].pb, msRootCerts[i].cb, CERT_STORE_ADD_NEW, NULL)) + msRootCerts[i].pb, msRootCerts[i].cb, CERT_STORE_ADD_NEW, &cert)) + { WARN("adding root cert %ld failed: %08lx\n", i, GetLastError()); + continue; + } + if ((existing = CertFindCertificateInStore(cached, X509_ASN_ENCODING, 0, CERT_FIND_EXISTING, cert, NULL))) + { + CertDeleteCertificateFromStore(existing); + CertFreeCertificateContext(existing); + } + CertFreeCertificateContext(cert); + } } /* Reads certificates from the list of known locations into store. Stops when @@ -612,15 +624,29 @@ static void add_ms_root_certs(HCERTSTORE to) * adding redundant certificates, e.g. when both a certificate bundle and * individual certificates exist in the same directory. */ -static void read_trusted_roots_from_known_locations(HCERTSTORE store) +static void read_trusted_roots_from_known_locations(HCERTSTORE store, HCERTSTORE cached, BOOL *delete) { HCERTSTORE new; - DWORD needed; + DWORD needed, size; struct enum_root_certs_params params = { NULL, 2048, &needed }; + HCRYPTPROV prov; + HCRYPTHASH hash; + BYTE hashval[20]; + DWORD hashlen; + CRYPT_HASH_BLOB hash_blob = { sizeof(hashval), hashval }; + CRYPT_DATA_BLOB exists_blob = { 0, NULL }; + PCCERT_CONTEXT cert, existing; + unsigned int existing_count = 0, new_count = 0; + unsigned int cached_count = 0; new = CertOpenStore( CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL ); if (!new) return; + existing = NULL; + while ((existing = CertEnumCertificatesInStore( cached, existing ))) + ++cached_count; + + CryptAcquireContextW( &prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ); params.buffer = CryptMemAlloc( params.size ); while (!CRYPT32_CALL( enum_root_certs, ¶ms )) { @@ -631,24 +657,78 @@ static void read_trusted_roots_from_known_locations(HCERTSTORE store) params.size = needed; continue; } - CertAddEncodedCertificateToStore( new, X509_ASN_ENCODING, params.buffer, needed, - CERT_STORE_ADD_NEW, NULL ); + CryptCreateHash( prov, CALG_SHA1, 0, 0, &hash ); + CryptHashData( hash, params.buffer, needed, 0 ); + hashlen = sizeof(hashval); + CryptGetHashParam( hash, HP_HASHVAL, hashval, &hashlen, 0 ); + CryptDestroyHash( hash ); + if ((existing = CertFindCertificateInStore( cached, X509_ASN_ENCODING, 0, + CERT_FIND_SHA1_HASH, &hash_blob, NULL ))) + { + /* Skip certificate which is already cached. CERT_FIRST_USER_PROP_ID is set once the cached cert + * is found among host imports. */ + if (!CertGetCertificateContextProperty( existing, CERT_FIRST_USER_PROP_ID, NULL, &size )) + { + if (!CertSetCertificateContextProperty( existing, CERT_FIRST_USER_PROP_ID, 0, &exists_blob )) + ERR( "Failed to set property.\n" ); + ++existing_count; + } + CertFreeCertificateContext( existing ); + continue; + } + CertAddEncodedCertificateToStore( new, X509_ASN_ENCODING, params.buffer, needed, CERT_STORE_ADD_ALWAYS, &cert ); + /* Add to cached so we can catch duplicates and check_and_store_certs() has the full chains. */ + CertAddCertificateContextToStore( cached, cert, CERT_STORE_ADD_ALWAYS, NULL ); + if (!CertSetCertificateContextProperty( cert, CERT_FIRST_USER_PROP_ID, 0, &exists_blob )) + ERR("Failed to set property.\n"); + CertFreeCertificateContext( cert ); + ++new_count; } CryptMemFree( params.buffer ); - check_and_store_certs( new, store ); + CryptReleaseContext( prov, 0 ); + + if (existing_count < cached_count) + { + /* Some certs were removed on host. Clean up the cache and add all the certificates so cert chains + * get revalidated. The certs present on host are now in 'cached' store and are marked with + * CERT_FIRST_USER_PROP_ID property. */ + TRACE( "Some keys were removed, reimporting, cached %u, existing %u, new %u.\n", + cached_count, existing_count, new_count ); + *delete = TRUE; + existing_count = 0; + existing = NULL; + while ((existing = CertEnumCertificatesInStore( cached, existing ))) + { + if (!CertGetCertificateContextProperty( existing, CERT_FIRST_USER_PROP_ID, NULL, &size )) + continue; + CertAddCertificateContextToStore( new, existing, CERT_STORE_ADD_NEW, NULL ); + ++new_count; + } + } + if (new_count) + { + /* Clear custom property so it is not serialized and seen by apps. */ + cert = NULL; + while ((cert = CertEnumCertificatesInStore( new, cert ))) + CertSetCertificateContextProperty( cert, CERT_FIRST_USER_PROP_ID, 0, NULL ); + check_and_store_certs( cached, new, store ); + } CertCloseStore( new, 0 ); + TRACE( "existing %u, new %u.\n", existing_count, new_count ); } -static HCERTSTORE create_root_store(void) +static HCERTSTORE create_root_store(HCERTSTORE cached, BOOL *delete) { HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); + + *delete = FALSE; if (memStore) { - read_trusted_roots_from_known_locations(memStore); - add_ms_root_certs(memStore); + add_ms_root_certs(memStore, cached); + read_trusted_roots_from_known_locations(memStore, cached, delete); } TRACE("returning %p\n", memStore); @@ -657,10 +737,11 @@ static HCERTSTORE create_root_store(void) void CRYPT_ImportSystemRootCertsToReg(void) { - HCERTSTORE store = NULL; + HCERTSTORE store = NULL, reg = NULL; HKEY key = NULL; LONG rc; HANDLE hsem; + BOOL delete; static BOOL root_certs_imported = FALSE; @@ -685,18 +766,27 @@ void CRYPT_ImportSystemRootCertsToReg(void) if (rc) goto done; - if (!(store = create_root_store())) + if (!(reg = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL))) { - ERR("Failed to create root store\n"); + ERR("Failed to create memory store.\n"); goto done; } + CRYPT_RegReadSerializedFromReg(key, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, reg, CERT_STORE_ADD_ALWAYS); - if (!CRYPT_SerializeContextsToReg(key, REG_OPTION_VOLATILE, pCertInterface, store)) + if (!(store = create_root_store(reg, &delete))) + { + ERR("Failed to create root store\n"); + goto done; + } + if (delete && RegDeleteTreeW(key, NULL)) + ERR("Error deleting key.\n"); + if (!CRYPT_SerializeContextsToReg(key, 0, pCertInterface, store)) ERR("Failed to import system certs into registry, %08lx\n", GetLastError()); done: RegCloseKey(key); CertCloseStore(store, 0); + CertCloseStore(reg, 0); root_certs_imported = TRUE; ReleaseSemaphore(hsem, 1, NULL); CloseHandle(hsem); From 6b9c29967a4a30cdabe48a8f88378d559c9c85f0 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 24 Mar 2023 17:32:02 -0600 Subject: [PATCH 1207/2777] wineboot: Load root certificates on prefix update. CW-Bug-Id: #22034 --- programs/wineboot/Makefile.in | 2 +- programs/wineboot/wineboot.c | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/programs/wineboot/Makefile.in b/programs/wineboot/Makefile.in index 667f8f48702..51823d3ebb2 100644 --- a/programs/wineboot/Makefile.in +++ b/programs/wineboot/Makefile.in @@ -1,6 +1,6 @@ MODULE = wineboot.exe IMPORTS = uuid advapi32 ws2_32 kernelbase -DELAYIMPORTS = shell32 shlwapi version user32 setupapi newdev +DELAYIMPORTS = shell32 shlwapi version user32 setupapi newdev crypt32 EXTRADLLFLAGS = -mconsole diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c index ee9660af80b..79e798f28ae 100644 --- a/programs/wineboot/wineboot.c +++ b/programs/wineboot/wineboot.c @@ -79,6 +79,7 @@ #include #include #include +#include #include "resource.h" WINE_DEFAULT_DEBUG_CHANNEL(wineboot); @@ -1623,6 +1624,15 @@ static void update_win_version(void) } } +static void update_root_certs(void) +{ + HCERTSTORE store; + + store = CertOpenStore( CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0, 0, CERT_STORE_OPEN_EXISTING_FLAG + | CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_LOCAL_MACHINE, L"Root"); + CertCloseStore( store, 0 ); +} + /* execute rundll32 on the wine.inf file if necessary */ static void update_wineprefix( BOOL force ) { @@ -1677,6 +1687,7 @@ static void update_wineprefix( BOOL force ) install_root_pnp_devices(); update_user_profile(); update_win_version(); + update_root_certs(); WINE_MESSAGE( "wine: configuration in %s has been updated.\n", debugstr_w(prettyprint_configdir()) ); } From 98bce52ddf46c0c8c6be57c27d4aa9c48303798b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 14 Mar 2023 21:12:22 -0600 Subject: [PATCH 1208/2777] ntdll: HACK: Add WINE_SIMULATE_WRITECOPY option. CW-Bug-Id: #22034 --- dlls/ntdll/unix/loader.c | 5 +++++ dlls/ntdll/unix/unix_private.h | 1 + dlls/ntdll/unix/virtual.c | 13 +++++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index ef38691b15a..f35ec8203fd 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2281,6 +2281,7 @@ BOOL alert_simulate_sched_quantum; BOOL no_priv_elevation; BOOL localsystem_sid; BOOL high_dll_addresses; +BOOL simulate_writecopy; static void hacks_init(void) { @@ -2336,6 +2337,10 @@ static void hacks_init(void) ERR("HACK: moving dlls to high addresses.\n"); #endif + env_str = getenv("WINE_SIMULATE_WRITECOPY"); + if (env_str) simulate_writecopy = atoi(env_str); + else if (sgi) simulate_writecopy = !strcmp(sgi, "1608730"); + if (main_argc > 1 && strstr(main_argv[1], "MicrosoftEdgeUpdate.exe")) { ERR("HACK: reporting LocalSystem account SID.\n"); diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 6df7f9071de..471f7377233 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -155,6 +155,7 @@ extern BOOL alert_simulate_sched_quantum DECLSPEC_HIDDEN; extern BOOL no_priv_elevation DECLSPEC_HIDDEN; extern BOOL localsystem_sid DECLSPEC_HIDDEN; extern BOOL high_dll_addresses DECLSPEC_HIDDEN; +extern BOOL simulate_writecopy DECLSPEC_HIDDEN; extern void init_environment( int argc, char *argv[], char *envp[] ) DECLSPEC_HIDDEN; extern void init_startup_info(void) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index ddaf643c797..2ac3aeba130 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -4571,10 +4571,19 @@ NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T old = get_win32_prot( vprot, view->protect ); status = set_protection( view, base, size, new_prot ); - /* GTA5 HACK: Mark first page as copied. */ - if (status == STATUS_SUCCESS && (view->protect & SEC_IMAGE) && + if (simulate_writecopy && status == STATUS_SUCCESS + && ((old == PAGE_WRITECOPY || old == PAGE_EXECUTE_WRITECOPY))) + { + TRACE("Setting VPROT_COPIED.\n"); + + set_page_vprot_bits(base, size, VPROT_COPIED, 0); + vprot |= VPROT_COPIED; + old = get_win32_prot( vprot, view->protect ); + } + else if (status == STATUS_SUCCESS && (view->protect & SEC_IMAGE) && base == (void*)NtCurrentTeb()->Peb->ImageBaseAddress) { + /* GTA5 HACK: Mark first page as copied. */ const WCHAR gta5W[] = { 'g','t','a','5','.','e','x','e',0 }; WCHAR *name, *p; From e25edcb82707318445de23f210e5e5ea06cfe0cb Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 24 Mar 2023 18:12:29 -0600 Subject: [PATCH 1209/2777] ntdll: HACK: Enable WINE_SIMULATE_WRITECOPY for Purgo box. CW-Bug-Id: #22034 --- dlls/ntdll/unix/loader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index f35ec8203fd..9781e3df094 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2339,7 +2339,7 @@ static void hacks_init(void) env_str = getenv("WINE_SIMULATE_WRITECOPY"); if (env_str) simulate_writecopy = atoi(env_str); - else if (sgi) simulate_writecopy = !strcmp(sgi, "1608730"); + else if (sgi) simulate_writecopy = !strcmp(sgi, "1608730") || !strcmp(sgi, "1680700"); if (main_argc > 1 && strstr(main_argv[1], "MicrosoftEdgeUpdate.exe")) { From b8f1881a1896cdaac78293496833d2aed56c489e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 20 Mar 2023 17:48:40 -0600 Subject: [PATCH 1210/2777] kernelbase: HACK: Add --use-angle=d3d9 command line option for nw.exe.exe. CW-Bug-Id: #22042 --- dlls/kernelbase/process.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index b98e7557b0e..2d42d408012 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -605,6 +605,7 @@ static const WCHAR *hack_append_command_line( const WCHAR *cmd ) {L"EOSOverlayRenderer-Win64-Shipping.exe", L" --use-gl=swiftshader --in-process-gpu"}, {L"EpicOnlineServicesUIHelper", L" --use-gl=desktop"}, {L"OlympiaRising.exe", L" --use-gl=swiftshader"}, + {L"nw.exe.exe", L" --use-angle=d3d9"}, }; unsigned int i; From 1674b049b37aef31da0168abf27dd2e873006c58 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 20 Mar 2023 11:59:14 -0600 Subject: [PATCH 1211/2777] win32u: Set DEVPKEY_Device_MatchingDeviceId for GPUs. (cherry picked from commit 80910517d7470b5eb070c7ea8c8224af860265bc) CW-Bug-Id: #22053 --- dlls/gdi32/tests/driver.c | 50 +++++++++++++++++++++++++++++++++++++++ dlls/win32u/sysparams.c | 19 +++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/dlls/gdi32/tests/driver.c b/dlls/gdi32/tests/driver.c index b2d2a0545ff..77681f9e3cf 100644 --- a/dlls/gdi32/tests/driver.c +++ b/dlls/gdi32/tests/driver.c @@ -32,6 +32,7 @@ #include "initguid.h" #include "setupapi.h" #include "ntddvdeo.h" +#include "devpkey.h" #include "wine/test.h" @@ -993,6 +994,54 @@ static void test_D3DKMTQueryVideoMemoryInfo(void) ok(status == STATUS_SUCCESS, "Got unexpected return code %#lx.\n", status); } +static void test_gpu_device_properties_guid(const GUID *devinterface_guid) +{ + BYTE iface_detail_buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + 256 * sizeof(WCHAR)]; + SP_DEVINFO_DATA device_data = {sizeof(device_data)}; + SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; + SP_DEVICE_INTERFACE_DETAIL_DATA_W *iface_data; + WCHAR device_id[256]; + DEVPROPTYPE type; + unsigned int i; + HDEVINFO set; + BOOL ret; + + /* Make sure display devices are initialized. */ + SendMessageW(GetDesktopWindow(), WM_NULL, 0, 0); + + set = SetupDiGetClassDevsW(devinterface_guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); + ok(set != INVALID_HANDLE_VALUE, "SetupDiGetClassDevs failed, error %lu.\n", GetLastError()); + + iface_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)iface_detail_buffer; + iface_data->cbSize = sizeof(*iface_data); + + i = 0; + while (SetupDiEnumDeviceInterfaces(set, NULL, devinterface_guid, i, &iface)) + { + ret = SetupDiGetDeviceInterfaceDetailW(set, &iface, iface_data, + sizeof(iface_detail_buffer), NULL, &device_data ); + ok(ret, "Got unexpected ret %d, GetLastError() %lu.\n", ret, GetLastError()); + + ret = SetupDiGetDevicePropertyW(set, &device_data, &DEVPKEY_Device_MatchingDeviceId, &type, + (BYTE *)device_id, sizeof(device_id), NULL, 0); + ok(ret, "Got unexpected ret %d, GetLastError() %lu.\n", ret, GetLastError()); + ok(type == DEVPROP_TYPE_STRING, "Got type %ld.\n", type); + + ++i; + } + SetupDiDestroyDeviceInfoList(set); +} + +static void test_gpu_device_properties(void) +{ + winetest_push_context("GUID_DEVINTERFACE_DISPLAY_ADAPTER"); + test_gpu_device_properties_guid(&GUID_DEVINTERFACE_DISPLAY_ADAPTER); + winetest_pop_context(); + winetest_push_context("GUID_DISPLAY_DEVICE_ARRIVAL"); + test_gpu_device_properties_guid(&GUID_DISPLAY_DEVICE_ARRIVAL); + winetest_pop_context(); +} + START_TEST(driver) { HMODULE gdi32 = GetModuleHandleA("gdi32.dll"); @@ -1022,6 +1071,7 @@ START_TEST(driver) test_D3DKMTCheckOcclusion(); test_D3DKMTOpenAdapterFromDeviceName(); test_D3DKMTQueryVideoMemoryInfo(); + test_gpu_device_properties(); FreeLibrary(dwmapi); } diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index bfff39e8767..fd9cb3fb0af 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -93,6 +93,14 @@ static const WCHAR devpropkey_gpu_luidW[] = '\\','0','0','0','2' }; +static const WCHAR devpkey_device_matching_device_id[] = +{ + 'P','r','o','p','e','r','t','i','e','s', + '\\','{','A','8','B','8','6','5','D','D','-','2','E','3','D','-','4','0','9','4', + '-','A','D','9','7','-','E','5','9','3','A','7','0','C','7','5','D','6','}', + '\\','0','0','0','8' +}; + static const WCHAR devpropkey_device_ispresentW[] = { 'P','r','o','p','e','r','t','i','e','s', @@ -1221,6 +1229,17 @@ static void add_gpu( const struct gdi_gpu *gpu, void *param ) bufferW[size / sizeof(WCHAR)] = 0; /* for REG_MULTI_SZ */ set_reg_value( hkey, hardware_idW, REG_MULTI_SZ, bufferW, size + sizeof(WCHAR) ); + if ((subkey = reg_create_key( hkey, devpkey_device_matching_device_id, + sizeof(devpkey_device_matching_device_id), 0, NULL ))) + { + if (gpu->vendor_id && gpu->device_id) + set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_STRING, bufferW, size ); + else + set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_STRING, bufferW, + asciiz_to_unicode( bufferW, "ROOT\\BasicRender" )); + NtClose( subkey ); + } + desc = gpu->name; if (!desc[0]) desc = wine_adapterW; set_reg_value( hkey, device_descW, REG_SZ, desc, (lstrlenW( desc ) + 1) * sizeof(WCHAR) ); From 801358dbde7b4c1d042e1e8a0b5d2e998164591a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 20 Mar 2023 13:02:31 -0600 Subject: [PATCH 1212/2777] win32u: Set DEVPKEY_Device_BusNumber for GPUs. (cherry picked from commit bee387dc8a2c19cc82f2f12973159fcdf738d455) CW-Bug-Id: #22053 --- dlls/gdi32/tests/driver.c | 12 ++++++++++++ dlls/win32u/sysparams.c | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/dlls/gdi32/tests/driver.c b/dlls/gdi32/tests/driver.c index 77681f9e3cf..31902a63321 100644 --- a/dlls/gdi32/tests/driver.c +++ b/dlls/gdi32/tests/driver.c @@ -1003,6 +1003,7 @@ static void test_gpu_device_properties_guid(const GUID *devinterface_guid) WCHAR device_id[256]; DEVPROPTYPE type; unsigned int i; + UINT32 value; HDEVINFO set; BOOL ret; @@ -1027,6 +1028,17 @@ static void test_gpu_device_properties_guid(const GUID *devinterface_guid) ok(ret, "Got unexpected ret %d, GetLastError() %lu.\n", ret, GetLastError()); ok(type == DEVPROP_TYPE_STRING, "Got type %ld.\n", type); + ret = SetupDiGetDevicePropertyW(set, &device_data, &DEVPKEY_Device_BusNumber, &type, + (BYTE *)&value, sizeof(value), NULL, 0); + if (!wcsicmp(device_id, L"root\\basicrender") || !wcsicmp(device_id, L"root\\basicdisplay")) + { + ok(!ret, "Found Bus Id.\n"); + } + else + { + ok(ret, "Got unexpected ret %d, GetLastError() %lu, %s.\n", ret, GetLastError(), debugstr_w(device_id)); + ok(type == DEVPROP_TYPE_UINT32, "Got type %ld.\n", type); + } ++i; } SetupDiDestroyDeviceInfoList(set); diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index fd9cb3fb0af..92058029f52 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -101,6 +101,14 @@ static const WCHAR devpkey_device_matching_device_id[] = '\\','0','0','0','8' }; +static const WCHAR devpkey_device_bus_number[] = +{ + 'P','r','o','p','e','r','t','i','e','s', + '\\','{','A','4','5','C','2','5','4','E','-','D','F','1','C','-','4','E','F','D', + '-','8','0','2','0','-','6','7','D','1','4','6','A','8','5','0','E','0','}', + '\\','0','0','1','7' +}; + static const WCHAR devpropkey_device_ispresentW[] = { 'P','r','o','p','e','r','t','i','e','s', @@ -1240,6 +1248,17 @@ static void add_gpu( const struct gdi_gpu *gpu, void *param ) NtClose( subkey ); } + if (gpu->vendor_id && gpu->device_id) + { + if ((subkey = reg_create_key( hkey, devpkey_device_bus_number, + sizeof(devpkey_device_bus_number), 0, NULL ))) + { + set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_UINT32, + &gpu_index, sizeof(gpu_index) ); + NtClose( subkey ); + } + } + desc = gpu->name; if (!desc[0]) desc = wine_adapterW; set_reg_value( hkey, device_descW, REG_SZ, desc, (lstrlenW( desc ) + 1) * sizeof(WCHAR) ); From 5e29ed20f1db988928d3441975c6208260a0bcee Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 20 Mar 2023 13:18:26 -0600 Subject: [PATCH 1213/2777] win32u: Set DEVPKEY_Device_RemovalPolicy for GPUs. (cherry picked from commit c4073d5abf5fdb069cb8c7ffa633f622fb0da22b) CW-Bug-Id: #22053 --- dlls/gdi32/tests/driver.c | 8 ++++++++ dlls/win32u/sysparams.c | 19 +++++++++++++++++++ include/cfgmgr32.h | 4 ++++ 3 files changed, 31 insertions(+) diff --git a/dlls/gdi32/tests/driver.c b/dlls/gdi32/tests/driver.c index 31902a63321..6e7caddf1f6 100644 --- a/dlls/gdi32/tests/driver.c +++ b/dlls/gdi32/tests/driver.c @@ -33,6 +33,7 @@ #include "setupapi.h" #include "ntddvdeo.h" #include "devpkey.h" +#include "cfgmgr32.h" #include "wine/test.h" @@ -1039,6 +1040,13 @@ static void test_gpu_device_properties_guid(const GUID *devinterface_guid) ok(ret, "Got unexpected ret %d, GetLastError() %lu, %s.\n", ret, GetLastError(), debugstr_w(device_id)); ok(type == DEVPROP_TYPE_UINT32, "Got type %ld.\n", type); } + + ret = SetupDiGetDevicePropertyW(set, &device_data, &DEVPKEY_Device_RemovalPolicy, &type, + (BYTE *)&value, sizeof(value), NULL, 0); + ok(ret, "Got unexpected ret %d, GetLastError() %lu, %s.\n", ret, GetLastError(), debugstr_w(device_id)); + ok(value == CM_REMOVAL_POLICY_EXPECT_NO_REMOVAL || value == CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL + || value == CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL, "Got value %d.\n", value); + ok(type == DEVPROP_TYPE_UINT32, "Got type %ld.\n", type); ++i; } SetupDiDestroyDeviceInfoList(set); diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 92058029f52..dfbfc9009b5 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -32,6 +32,7 @@ #include "ntgdi_private.h" #include "ntuser_private.h" #include "devpropdef.h" +#include "cfgmgr32.h" #include "wine/wingdi16.h" #include "wine/server.h" @@ -109,6 +110,14 @@ static const WCHAR devpkey_device_bus_number[] = '\\','0','0','1','7' }; +static const WCHAR devpkey_device_removal_policy[] = +{ + 'P','r','o','p','e','r','t','i','e','s', + '\\','{','A','4','5','C','2','5','4','E','-','D','F','1','C','-','4','E','F','D', + '-','8','0','2','0','-','6','7','D','1','4','6','A','8','5','0','E','0','}', + '\\','0','0','2','1' +}; + static const WCHAR devpropkey_device_ispresentW[] = { 'P','r','o','p','e','r','t','i','e','s', @@ -1259,6 +1268,16 @@ static void add_gpu( const struct gdi_gpu *gpu, void *param ) } } + if ((subkey = reg_create_key( hkey, devpkey_device_removal_policy, + sizeof(devpkey_device_removal_policy), 0, NULL ))) + { + unsigned int removal_policy = CM_REMOVAL_POLICY_EXPECT_NO_REMOVAL; + + set_reg_value( subkey, NULL, 0xffff0000 | DEVPROP_TYPE_UINT32, + &removal_policy, sizeof(removal_policy) ); + NtClose( subkey ); + } + desc = gpu->name; if (!desc[0]) desc = wine_adapterW; set_reg_value( hkey, device_descW, REG_SZ, desc, (lstrlenW( desc ) + 1) * sizeof(WCHAR) ); diff --git a/include/cfgmgr32.h b/include/cfgmgr32.h index d300c4babaa..bff32fe1c08 100644 --- a/include/cfgmgr32.h +++ b/include/cfgmgr32.h @@ -180,6 +180,10 @@ typedef DWORD CONFIGRET; #define CM_REGISTRY_USER 0x0100 #define CM_REGISTRY_CONFIG 0x0200 +#define CM_REMOVAL_POLICY_EXPECT_NO_REMOVAL 1 +#define CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL 2 +#define CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL 3 + typedef DWORD DEVINST, *PDEVINST; typedef DWORD DEVNODE, *PDEVNODE; typedef HANDLE HMACHINE, *PHMACHINE; From af26aac563b370eeb0f55677781ea6dd895d547d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 22 Mar 2023 14:31:03 -0600 Subject: [PATCH 1214/2777] crypt32: Add WINE_ADDITIONAL_CERTS_DIR option. CW-Bug-Id: #22063 --- dlls/crypt32/unixlib.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/crypt32/unixlib.c b/dlls/crypt32/unixlib.c index e90642fb0d5..843ca70674b 100644 --- a/dlls/crypt32/unixlib.c +++ b/dlls/crypt32/unixlib.c @@ -623,6 +623,7 @@ static const char * const CRYPT_knownLocations[] = { static void load_root_certs(void) { + const char *additional_dir; unsigned int i; #ifdef __APPLE__ @@ -660,6 +661,9 @@ static void load_root_certs(void) for (i = 0; i < ARRAY_SIZE(CRYPT_knownLocations) && list_empty(&root_cert_list); i++) import_certs_from_path( CRYPT_knownLocations[i], TRUE ); + + if ((additional_dir = getenv( "WINE_ADDITIONAL_CERTS_DIR" ))) + import_certs_from_path( additional_dir, TRUE ); } static NTSTATUS enum_root_certs( void *args ) From 568f135a9214509b1968379eef105ec43b3bdbc8 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Thu, 5 Jan 2023 12:58:21 +0100 Subject: [PATCH 1215/2777] winedbg: Pass loaded image's file handle to dbghelp. In some cases (running from build tree, overriding load order...), the path to the module from the load DLL debug event isn't the real path to the loaded module. So pass the handle to loaded module's image from winedbg to dbghelp (to avoid image lookup). Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54250 Signed-off-by: Eric Pouech (cherry picked from commit 3055653c1e79d59a2b5231d9c9b89bd995324061) --- programs/winedbg/winedbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index b2a1706117a..30f77e32783 100644 --- a/programs/winedbg/winedbg.c +++ b/programs/winedbg/winedbg.c @@ -385,7 +385,7 @@ BOOL dbg_init(HANDLE hProc, const WCHAR* in, BOOL invade) BOOL dbg_load_module(HANDLE hProc, HANDLE hFile, const WCHAR* name, DWORD_PTR base, DWORD size) { - BOOL ret = SymLoadModuleExW(hProc, NULL, name, NULL, base, size, NULL, 0); + BOOL ret = SymLoadModuleExW(hProc, hFile, name, NULL, base, size, NULL, 0); if (ret) { IMAGEHLP_MODULEW64 ihm; From ef63efefbd4de88ce4473ceea455570d36cf816b Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Mon, 16 Jan 2023 11:09:46 -0600 Subject: [PATCH 1216/2777] winedbg: Track loaded modules. Co-authored-by: Evan Tang (cherry picked from commit 224b33c2be2ccab7ea5f2926f391717703b5427b) --- programs/winedbg/debugger.h | 12 ++++++- programs/winedbg/tgt_active.c | 3 +- programs/winedbg/types.c | 12 +++---- programs/winedbg/winedbg.c | 61 +++++++++++++++++++++++++++++++---- 4 files changed, 72 insertions(+), 16 deletions(-) diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index 4d2b946162b..f31efe4cd8e 100644 --- a/programs/winedbg/debugger.h +++ b/programs/winedbg/debugger.h @@ -246,6 +246,12 @@ struct dbg_thread BOOL suspended; }; +struct dbg_module +{ + struct list entry; + DWORD_PTR base; +}; + struct dbg_delayed_bp { BOOL is_symbol; @@ -271,6 +277,7 @@ struct dbg_process void* pio_data; const WCHAR* imageName; struct list threads; + struct list modules; struct backend_cpu* be_cpu; HANDLE event_on_first_exception; BOOL active_debuggee; @@ -505,7 +512,7 @@ extern BOOL types_is_integral_type(const struct dbg_lvalue*); extern BOOL types_is_float_type(const struct dbg_lvalue*); extern BOOL types_is_pointer_type(const struct dbg_lvalue*); extern BOOL types_find_basic(const WCHAR*, const char*, struct dbg_type* type); -extern BOOL types_unload_module(DWORD_PTR linear); +extern BOOL types_unload_module(struct dbg_process* pcs, DWORD_PTR linear); /* winedbg.c */ #ifdef __GNUC__ @@ -526,6 +533,9 @@ extern struct dbg_thread* dbg_get_thread(struct dbg_process* p, DWORD tid); extern void dbg_del_thread(struct dbg_thread* t); extern BOOL dbg_init(HANDLE hProc, const WCHAR* in, BOOL invade); extern BOOL dbg_load_module(HANDLE hProc, HANDLE hFile, const WCHAR* name, DWORD_PTR base, DWORD size); +extern struct dbg_module* dbg_get_module(struct dbg_process* pcs, DWORD_PTR base); +extern void dbg_del_module(struct dbg_module* mod); +extern BOOL dbg_unload_module(struct dbg_process* pcs, DWORD_PTR base); extern void dbg_set_option(const char*, const char*); extern void dbg_start_interactive(const char*, HANDLE hFile); extern void dbg_init_console(void); diff --git a/programs/winedbg/tgt_active.c b/programs/winedbg/tgt_active.c index 5d660ab81dd..069d0a39c23 100644 --- a/programs/winedbg/tgt_active.c +++ b/programs/winedbg/tgt_active.c @@ -503,8 +503,7 @@ static unsigned dbg_handle_debug_event(DEBUG_EVENT* de) de->dwProcessId, de->dwThreadId, de->u.UnloadDll.lpBaseOfDll); break_delete_xpoints_from_module((DWORD_PTR)de->u.UnloadDll.lpBaseOfDll); - types_unload_module((DWORD_PTR)de->u.UnloadDll.lpBaseOfDll); - SymUnloadModule64(dbg_curr_process->handle, (DWORD_PTR)de->u.UnloadDll.lpBaseOfDll); + dbg_unload_module(dbg_curr_process, (DWORD_PTR)de->u.UnloadDll.lpBaseOfDll); break; case OUTPUT_DEBUG_STRING_EVENT: diff --git a/programs/winedbg/types.c b/programs/winedbg/types.c index 5f5f1346c67..44872a7edad 100644 --- a/programs/winedbg/types.c +++ b/programs/winedbg/types.c @@ -1205,16 +1205,16 @@ BOOL types_get_info(const struct dbg_type* type, IMAGEHLP_SYMBOL_TYPE_INFO ti, v return TRUE; } -BOOL types_unload_module(DWORD_PTR linear) +BOOL types_unload_module(struct dbg_process* pcs, DWORD_PTR linear) { unsigned i; - if (!dbg_curr_process) return FALSE; - for (i = 0; i < dbg_curr_process->num_synthetized_types; i++) + if (!pcs) return FALSE; + for (i = 0; i < pcs->num_synthetized_types; i++) { - if (dbg_curr_process->synthetized_types[i].module == linear) + if (pcs->synthetized_types[i].module == linear) { - dbg_curr_process->synthetized_types[i].module = 0; - dbg_curr_process->synthetized_types[i].id = dbg_itype_none; + pcs->synthetized_types[i].module = 0; + pcs->synthetized_types[i].id = dbg_itype_none; } } return TRUE; diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index 30f77e32783..d7c16733e5c 100644 --- a/programs/winedbg/winedbg.c +++ b/programs/winedbg/winedbg.c @@ -281,6 +281,7 @@ struct dbg_process* dbg_add_process(const struct be_process_io* pio, DWORD pid, p->pio_data = NULL; p->imageName = NULL; list_init(&p->threads); + list_init(&p->modules); p->event_on_first_exception = NULL; p->active_debuggee = FALSE; p->next_bp = 1; /* breakpoint 0 is reserved for step-over */ @@ -324,11 +325,16 @@ void dbg_del_process(struct dbg_process* p) { struct dbg_thread* t; struct dbg_thread* t2; + struct dbg_module* mod; + struct dbg_module* mod2; int i; LIST_FOR_EACH_ENTRY_SAFE(t, t2, &p->threads, struct dbg_thread, entry) dbg_del_thread(t); + LIST_FOR_EACH_ENTRY_SAFE(mod, mod2, &p->modules, struct dbg_module, entry) + dbg_del_module(mod); + for (i = 0; i < p->num_delayed_bp; i++) if (p->delayed_bp[i].is_symbol) free(p->delayed_bp[i].u.symbol.name); @@ -385,15 +391,56 @@ BOOL dbg_init(HANDLE hProc, const WCHAR* in, BOOL invade) BOOL dbg_load_module(HANDLE hProc, HANDLE hFile, const WCHAR* name, DWORD_PTR base, DWORD size) { - BOOL ret = SymLoadModuleExW(hProc, hFile, name, NULL, base, size, NULL, 0); - if (ret) + struct dbg_process* pcs = dbg_get_process_h(hProc); + struct dbg_module* mod; + IMAGEHLP_MODULEW64 info; + + if (!pcs) return FALSE; + mod = malloc(sizeof(struct dbg_module)); + if (!mod) return FALSE; + if (!SymLoadModuleExW(hProc, hFile, name, NULL, base, size, NULL, 0)) { - IMAGEHLP_MODULEW64 ihm; - ihm.SizeOfStruct = sizeof(ihm); - if (SymGetModuleInfoW64(hProc, base, &ihm) && (ihm.PdbUnmatched || ihm.DbgUnmatched)) - dbg_printf("Loaded unmatched debug information for %s\n", wine_dbgstr_w(name)); + free(mod); + return FALSE; } - return ret; + mod->base = base; + list_add_head(&pcs->modules, &mod->entry); + + info.SizeOfStruct = sizeof(info); + if (SymGetModuleInfoW64(hProc, base, &info)) + if (info.PdbUnmatched || info.DbgUnmatched) + dbg_printf("Loaded unmatched debug information for %s\n", wine_dbgstr_w(name)); + + return TRUE; +} + +void dbg_del_module(struct dbg_module* mod) +{ + list_remove(&mod->entry); + free(mod); +} + +struct dbg_module* dbg_get_module(struct dbg_process* pcs, DWORD_PTR base) +{ + struct dbg_module* mod; + + if (!pcs) + return NULL; + LIST_FOR_EACH_ENTRY(mod, &pcs->modules, struct dbg_module, entry) + if (mod->base == base) + return mod; + return NULL; +} + +BOOL dbg_unload_module(struct dbg_process* pcs, DWORD_PTR base) +{ + struct dbg_module* mod = dbg_get_module(pcs, base); + + types_unload_module(pcs, base); + SymUnloadModule64(pcs->handle, base); + dbg_del_module(mod); + + return !!mod; } struct dbg_thread* dbg_get_thread(struct dbg_process* p, DWORD tid) From 8924323f79e5e3b98f38758f3261312d0fe3d053 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Mon, 16 Jan 2023 11:14:59 -0600 Subject: [PATCH 1217/2777] winedbg: Fix read access to variables with thread local storage. No longer relying on loaded module info (getting index address out of PE image, and caching it in struct dbg_module). Co-authored-by: Evan Tang (cherry picked from commit 433bc1270965c07d440ef676d5593de1ef329918) --- programs/winedbg/debugger.h | 1 + programs/winedbg/symbol.c | 74 +++++++++++++++++++------------------ programs/winedbg/winedbg.c | 29 +++++++++++++++ 3 files changed, 68 insertions(+), 36 deletions(-) diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index f31efe4cd8e..570ed52143f 100644 --- a/programs/winedbg/debugger.h +++ b/programs/winedbg/debugger.h @@ -250,6 +250,7 @@ struct dbg_module { struct list entry; DWORD_PTR base; + DWORD_PTR tls_index_offset; }; struct dbg_delayed_bp diff --git a/programs/winedbg/symbol.c b/programs/winedbg/symbol.c index 961dc95585a..22c34033752 100644 --- a/programs/winedbg/symbol.c +++ b/programs/winedbg/symbol.c @@ -61,6 +61,43 @@ static BOOL symbol_get_debug_start(const struct dbg_type* func, ULONG64* start) return FALSE; } +static BOOL fetch_tls_lvalue(const SYMBOL_INFO* sym, struct dbg_lvalue* lvalue) +{ + struct dbg_module* mod = dbg_get_module(dbg_curr_process, sym->ModBase); + unsigned tlsindex; + struct dbg_lvalue lv_teb_tls, lv_index_addr, lv_module_tls; + dbg_lgint_t teb_tls_addr, index_addr, tls_module_addr; + char* teb_tls_storage; + + if (!mod || !mod->tls_index_offset || !dbg_curr_thread) + return FALSE; + /* get ThreadLocalStoragePointer offset depending on debuggee bitness */ + teb_tls_storage = (char*)dbg_curr_thread->teb; + if (ADDRSIZE == sizeof(void*)) + /* debugger and debuggee have same bitness */ + teb_tls_storage += offsetof(TEB, ThreadLocalStoragePointer); + else + /* debugger is 64bit, while debuggee is 32bit */ + teb_tls_storage += 0x2000 /* TEB64 => TEB32 */ + offsetof(TEB32, ThreadLocalStoragePointer); + init_lvalue(&lv_teb_tls, TRUE, teb_tls_storage); + + if (!memory_fetch_integer(&lv_teb_tls, ADDRSIZE, FALSE, &teb_tls_addr)) + return FALSE; + + init_lvalue(&lv_index_addr, TRUE, (void*)(DWORD_PTR)(sym->ModBase + mod->tls_index_offset)); + if (!memory_fetch_integer(&lv_index_addr, ADDRSIZE, FALSE, &index_addr)) + return FALSE; + + if (!dbg_read_memory((const char*)(DWORD_PTR)index_addr, &tlsindex, sizeof(tlsindex))) + return FALSE; + + init_lvalue(&lv_module_tls, TRUE, (void*)(DWORD_PTR)(teb_tls_addr + tlsindex * ADDRSIZE)); + if (!memory_fetch_integer(&lv_module_tls, ADDRSIZE, FALSE, &tls_module_addr)) + return FALSE; + init_lvalue(lvalue, TRUE, (void*)(DWORD_PTR)(tls_module_addr + sym->Address)); + return TRUE; +} + static BOOL fill_sym_lvalue(const SYMBOL_INFO* sym, ULONG_PTR base, struct dbg_lvalue* lvalue, char* buffer, size_t sz) { @@ -128,46 +165,11 @@ static BOOL fill_sym_lvalue(const SYMBOL_INFO* sym, ULONG_PTR base, } else if (sym->Flags & SYMFLAG_TLSREL) { - PROCESS_BASIC_INFORMATION pbi; - THREAD_BASIC_INFORMATION tbi; - DWORD_PTR addr; - PEB peb; - PEB_LDR_DATA ldr_data; - PLIST_ENTRY head, current; - LDR_DATA_TABLE_ENTRY ldr_module; - unsigned tlsindex = -1; - - if (NtQueryInformationProcess(dbg_curr_process->handle, ProcessBasicInformation, - &pbi, sizeof(pbi), NULL) || - NtQueryInformationThread(dbg_curr_thread->handle, ThreadBasicInformation, - &tbi, sizeof(tbi), NULL)) + if (!fetch_tls_lvalue(sym, lvalue)) { - tls_error: if (buffer) snprintf(buffer, sz, "Cannot read TLS address\n"); return FALSE; } - addr = (DWORD_PTR)&(((TEB*)tbi.TebBaseAddress)->ThreadLocalStoragePointer); - if (!dbg_read_memory((void*)addr, &addr, sizeof(addr)) || - !dbg_read_memory(pbi.PebBaseAddress, &peb, sizeof(peb)) || - !dbg_read_memory(peb.LdrData, &ldr_data, sizeof(ldr_data))) - goto tls_error; - current = ldr_data.InLoadOrderModuleList.Flink; - head = &((PEB_LDR_DATA*)peb.LdrData)->InLoadOrderModuleList; - do - { - if (!dbg_read_memory(CONTAINING_RECORD(current, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks), - &ldr_module, sizeof(ldr_module))) goto tls_error; - if ((DWORD_PTR)ldr_module.DllBase == sym->ModBase) - { - tlsindex = ldr_module.TlsIndex; - break; - } - current = ldr_module.InLoadOrderLinks.Flink; - } while (current != head); - - addr += tlsindex * sizeof(DWORD_PTR); - if (!dbg_read_memory((void*)addr, &addr, sizeof(addr))) goto tls_error; - init_lvalue(lvalue, TRUE, (void*)(DWORD_PTR)(addr + sym->Address)); } else { diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index d7c16733e5c..8cccf30fa09 100644 --- a/programs/winedbg/winedbg.c +++ b/programs/winedbg/winedbg.c @@ -394,6 +394,8 @@ BOOL dbg_load_module(HANDLE hProc, HANDLE hFile, const WCHAR* name, DWORD_PTR ba struct dbg_process* pcs = dbg_get_process_h(hProc); struct dbg_module* mod; IMAGEHLP_MODULEW64 info; + HANDLE hMap; + void* image; if (!pcs) return FALSE; mod = malloc(sizeof(struct dbg_module)); @@ -406,6 +408,33 @@ BOOL dbg_load_module(HANDLE hProc, HANDLE hFile, const WCHAR* name, DWORD_PTR ba mod->base = base; list_add_head(&pcs->modules, &mod->entry); + mod->tls_index_offset = 0; + if ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL))) + { + if ((image = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0))) + { + IMAGE_NT_HEADERS* nth = RtlImageNtHeader(image); + const void* tlsdir; + ULONG sz; + + tlsdir = RtlImageDirectoryEntryToData(image, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &sz); + switch (nth->OptionalHeader.Magic) + { + case IMAGE_NT_OPTIONAL_HDR32_MAGIC: + if (tlsdir && sz >= sizeof(IMAGE_TLS_DIRECTORY32)) + mod->tls_index_offset = (const char*)tlsdir - (const char*)image + + offsetof(IMAGE_TLS_DIRECTORY32, AddressOfIndex); + break; + case IMAGE_NT_OPTIONAL_HDR64_MAGIC: + if (tlsdir && sz >= sizeof(IMAGE_TLS_DIRECTORY64)) + mod->tls_index_offset = (const char*)tlsdir - (const char*)image + + offsetof(IMAGE_TLS_DIRECTORY64, AddressOfIndex); + break; + } + UnmapViewOfFile(image); + } + CloseHandle(hMap); + } info.SizeOfStruct = sizeof(info); if (SymGetModuleInfoW64(hProc, base, &info)) if (info.PdbUnmatched || info.DbgUnmatched) From 9bd5c72eebbbb1f4fe84df5f00176a3357afb6cb Mon Sep 17 00:00:00 2001 From: Evan Tang Date: Mon, 28 Nov 2022 14:54:41 -0600 Subject: [PATCH 1218/2777] ntdll: TlsIndex should not actually contain tls indices. It actually contains a -1 if the module has a tls slot and a 0 if it doesn't. Putting tls indices in it breaks initialization of the D runtime if a D dll is loaded into a tls-free exe and gets assigned tls slot 0, as it makes the D runtime think the OS hasn't initialized a tls slot: https://github.com/dlang/dmd/blob/6bf60ea0eb174631ede0074a77d3898d943e0b30/druntime/src/core/sys/windows/dll.d#L354-L355 (cherry picked from commit a30a5287f06ccf56a1d7184e8c22ea9e79e9efaf) CW-Bug-ID: 21596 --- dlls/ntdll/loader.c | 34 ++++++++++++++++++++-------------- dlls/ntdll/tests/rtl.c | 26 ++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 14fc568f0d2..2ea6487db69 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -1230,7 +1230,7 @@ static BOOL is_dll_native_subsystem( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_NT_H * Allocate a TLS slot for a newly-loaded module. * The loader_section must be locked while calling this function. */ -static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) +static BOOL alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) { const IMAGE_TLS_DIRECTORY *dir; ULONG i, size; @@ -1238,10 +1238,10 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) LIST_ENTRY *entry; if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size ))) - return -1; + return FALSE; size = dir->EndAddressOfRawData - dir->StartAddressOfRawData; - if (!size && !dir->SizeOfZeroFill && !dir->AddressOfCallBacks) return -1; + if (!size && !dir->SizeOfZeroFill && !dir->AddressOfCallBacks) return FALSE; for (i = 0; i < tls_module_count; i++) { @@ -1263,7 +1263,7 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) else new_ptr = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, tls_dirs, new_count * sizeof(*tls_dirs) ); - if (!new_ptr) return -1; + if (!new_ptr) return FALSE; /* resize the pointer block in all running threads */ for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink) @@ -1272,7 +1272,7 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) void **old = teb->ThreadLocalStoragePointer; void **new = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*new)); - if (!new) return -1; + if (!new) return FALSE; if (old) memcpy( new, old, tls_module_count * sizeof(*new) ); teb->ThreadLocalStoragePointer = new; #ifdef __x86_64__ /* macOS-specific hack */ @@ -1304,7 +1304,7 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) *(DWORD *)dir->AddressOfIndex = i; tls_dirs[i] = *dir; - return i; + return TRUE; } @@ -1316,9 +1316,15 @@ static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) */ static void free_tls_slot( LDR_DATA_TABLE_ENTRY *mod ) { - ULONG i = (USHORT)mod->TlsIndex; + const IMAGE_TLS_DIRECTORY *dir; + ULONG i, size; + + if (mod->TlsIndex != -1) + return; + if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size ))) + return; - if (mod->TlsIndex == -1) return; + i = *(ULONG*)dir->AddressOfIndex; assert( i < tls_module_count ); memset( &tls_dirs[i], 0, sizeof(tls_dirs[i]) ); } @@ -1382,7 +1388,7 @@ static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path ) if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS; /* already done */ wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS; - wm->ldr.TlsIndex = alloc_tls_slot( &wm->ldr ); + if (alloc_tls_slot( &wm->ldr )) wm->ldr.TlsIndex = -1; if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size ))) @@ -1439,7 +1445,7 @@ static WINE_MODREF *alloc_module( HMODULE hModule, const UNICODE_STRING *nt_name wm->ldr.DllBase = hModule; wm->ldr.SizeOfImage = nt->OptionalHeader.SizeOfImage; wm->ldr.Flags = LDR_DONT_RESOLVE_REFS | (builtin ? LDR_WINE_INTERNAL : 0); - wm->ldr.TlsIndex = -1; + wm->ldr.TlsIndex = 0; wm->ldr.LoadCount = 1; wm->CheckSum = nt->OptionalHeader.CheckSum; wm->ldr.TimeDateStamp = nt->FileHeader.TimeDateStamp; @@ -1791,7 +1797,7 @@ NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule) RtlEnterCriticalSection( &loader_section ); wm = get_modref( hModule ); - if (!wm || wm->ldr.TlsIndex != -1) + if (!wm || wm->ldr.TlsIndex == -1) ret = STATUS_DLL_NOT_FOUND; else wm->ldr.Flags |= LDR_NO_DLL_CALLS; @@ -3822,7 +3828,7 @@ void WINAPI LdrShutdownThread(void) DLL_THREAD_DETACH, NULL ); } - if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_DETACH ); + if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_DETACH ); RtlAcquirePebLock(); if (NtCurrentTeb()->TlsLinks.Flink) RemoveEntryList( &NtCurrentTeb()->TlsLinks ); @@ -4372,7 +4378,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR NtTerminateProcess( GetCurrentProcess(), status ); } release_address_space(); - if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_PROCESS_ATTACH ); + if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_PROCESS_ATTACH ); if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie ); process_breakpoint(); } @@ -4381,7 +4387,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR if ((status = alloc_thread_tls()) != STATUS_SUCCESS) NtTerminateThread( GetCurrentThread(), status ); thread_attach(); - if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_ATTACH ); + if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_ATTACH ); } RtlLeaveCriticalSection( &loader_section ); diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c index c2ca8ea11a7..a7c43a46e07 100644 --- a/dlls/ntdll/tests/rtl.c +++ b/dlls/ntdll/tests/rtl.c @@ -3788,6 +3788,31 @@ static void test_RtlFirstFreeAce(void) HeapFree(GetProcessHeap(), 0, acl); } +static void test_TlsIndex(void) +{ + LIST_ENTRY *root = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; + for (LIST_ENTRY *entry = root->Flink; entry != root; entry = entry->Flink) + { + LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + if (lstrcmpiW(L"ntdll.dll", mod->BaseDllName.Buffer) == 0) + { + /* Pick ntdll as a dll that definitely won't have TLS */ + ok(mod->TlsIndex == 0, "ntdll.dll TlsIndex: %d instead of 0\n", mod->TlsIndex); + } + else if (mod->DllBase == GetModuleHandleA(NULL)) + { + /* mingw gcc doesn't support MSVC-style TLS */ + /* If we do get a way to add tls to this exe, uncomment the following test: */ + /* ok(mod->TlsIndex == -1, "Test exe TlsIndex: %d instead of -1\n", mod->TlsIndex); */ + } + else + { + ok(mod->TlsIndex == 0 || mod->TlsIndex == -1, "%s TlsIndex: %d\n", + debugstr_w(mod->BaseDllName.Buffer), mod->TlsIndex); + } + } +} + START_TEST(rtl) { InitFunctionPtrs(); @@ -3832,4 +3857,5 @@ START_TEST(rtl) test_DbgPrint(); test_RtlDestroyHeap(); test_RtlFirstFreeAce(); + test_TlsIndex(); } From 6d08056ab07f85cdd13ee00cf5ce9065e763d50f Mon Sep 17 00:00:00 2001 From: Evan Tang Date: Tue, 7 Mar 2023 17:13:33 -0600 Subject: [PATCH 1219/2777] ntdll: Fix inverted TlsIndex check. Fixes: a30a5287f06ccf56a1d7184e8c22ea9e79e9efaf Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54539 (cherry picked from commit 1833887428f7539681ebbc1c893a4ec85cc1ea88) --- dlls/ntdll/loader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 2ea6487db69..1aea4fdcb94 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -1586,7 +1586,7 @@ static NTSTATUS MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved /* Skip calls for modules loaded with special load flags */ if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return STATUS_SUCCESS; - if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, reason ); + if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, reason ); if (!entry) return STATUS_SUCCESS; if (TRACE_ON(relay)) From fe08567e0cb58b729cb788830168656c2a2af998 Mon Sep 17 00:00:00 2001 From: Evan Tang Date: Wed, 8 Mar 2023 16:57:43 -0600 Subject: [PATCH 1220/2777] kernel32/tests: Add test verifying that tls init functions are called. (cherry picked from commit 2203a8564c5faba383a3512f8244dba12d79da16) --- dlls/kernel32/tests/loader.c | 51 +++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index 365f4465fc7..ef9c68a7c3a 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -2134,14 +2134,38 @@ static void test_import_resolution(void) char module[16]; struct { WORD hint; char name[32]; } function; IMAGE_TLS_DIRECTORY tls; + UINT_PTR tls_init_fn_list[2]; char tls_data[16]; SHORT tls_index; + SHORT tls_index_hi; + UCHAR tls_init_fn[64]; /* Note: Uses rip-relative address of tls_index, don't separate */ } data, *ptr; IMAGE_NT_HEADERS nt; IMAGE_SECTION_HEADER section; int test; +#if defined(__i386__) + static const UCHAR tls_init_code[] = { + 0xE8, 0x00, 0x00, 0x00, 0x00, /* call 1f */ + 0x59, /* 1: pop ecx */ + 0x8B, 0x49, 0xF7, /* mov ecx, [ecx - 9] ; mov ecx, [tls_index] */ + 0x64, 0x8B, 0x15, 0x2C, 0x00, 0x00, 0x00, /* mov edx, fs:0x2c */ + 0x8B, 0x14, 0x8A, /* mov edx, [edx + edx * 4] */ + 0xC6, 0x42, 0x05, 0x21, /* mov byte [edx + 5], 0x21 */ + 0xC2, 0x0C, 0x00, /* ret 12 */ + }; +#elif defined(__x86_64__) + static const UCHAR tls_init_code[] = { + 0x8B, 0x0D, 0xF6, 0xFF, 0xFF, 0xFF, /* mov ecx, [rip + tls_index] */ + 0x65, 0x48, 0x8B, 0x14, 0x25, 0x58, 0x00, 0x00, 0x00, /* mov rdx, gs:0x58 */ + 0x48, 0x8B, 0x14, 0xCA, /* mov rdx, [rdx + rcx * 8] */ + 0xC6, 0x42, 0x05, 0x21, /* mov byte [rdx + 5], 0x21 */ + 0xC3, /* ret */ + }; +#else + static const UCHAR tls_init_code[] = { 0x00 }; +#endif - for (test = 0; test < 3; test++) + for (test = 0; test < 4; test++) { #define DATA_RVA(ptr) (page_size + ((char *)(ptr) - (char *)&data)) nt = nt_header_template; @@ -2175,6 +2199,15 @@ static void test_import_resolution(void) data.tls.AddressOfIndex = nt.OptionalHeader.ImageBase + DATA_RVA( &data.tls_index ); strcpy( data.tls_data, "hello world" ); data.tls_index = 9999; + data.tls_index_hi = 9999; + + if (test == 3 && sizeof(tls_init_code) > 1) + { + assert(sizeof(tls_init_code) <= sizeof(data.tls_init_fn)); + memcpy(data.tls_init_fn, tls_init_code, sizeof(tls_init_code)); + data.tls_init_fn_list[0] = nt.OptionalHeader.ImageBase + DATA_RVA(&data.tls_init_fn); + data.tls.AddressOfCallBacks = nt.OptionalHeader.ImageBase + DATA_RVA(&data.tls_init_fn_list); + } GetTempPathA(MAX_PATH, temp_path); GetTempFileNameA(temp_path, "ldr", 0, dll_name); @@ -2189,6 +2222,7 @@ static void test_import_resolution(void) section.Misc.VirtualSize = sizeof(data); section.SizeOfRawData = sizeof(data); section.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; + if (test == 3) section.Characteristics |= IMAGE_SCN_MEM_EXECUTE; WriteFile(hfile, &dos_header, sizeof(dos_header), &dummy, NULL); WriteFile(hfile, &nt, sizeof(nt), &dummy, NULL); @@ -2215,6 +2249,7 @@ static void test_import_resolution(void) { str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index]; ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str ); + ok(ptr->tls_index_hi == 0, "TLS Index written as a short, high half: %d\n", ptr->tls_index_hi); } FreeLibrary( mod ); break; @@ -2245,6 +2280,20 @@ static void test_import_resolution(void) ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index ); FreeLibrary( mod ); break; + case 3: /* load with tls init function */ + mod = LoadLibraryA( dll_name ); + ok( mod != NULL, "failed to load err %lu\n", GetLastError() ); + if (!mod) break; + ptr = (struct imports *)((char *)mod + page_size); + ok( ptr->tls_index < 32 || broken(ptr->tls_index == 9999), /* before vista */ + "wrong tls index %d\n", ptr->tls_index ); + if (ptr->tls_index != 9999 && sizeof(tls_init_code) > 1) + { + /* tls init function will write an '!' over the space in "hello world" */ + str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index]; + ok( !strcmp( str, "hello!world" ), "wrong tls data '%s' at %p\n", str, str ); + } + FreeLibrary( mod ); } DeleteFileA( dll_name ); #undef DATA_RVA From 36c0b2152649f2f12e5f19a2faee7259eebcb94d Mon Sep 17 00:00:00 2001 From: Evan Tang Date: Thu, 9 Mar 2023 11:16:53 -0600 Subject: [PATCH 1221/2777] ntdll/tests: Move TlsIndex test to kernel32:loader. Gets us access to a dll with tls to verify. (cherry picked from commit a8fa80cfb4a1819be12ece459753bc07d4ea8be6) --- dlls/kernel32/tests/loader.c | 31 +++++++++++++++++++++++++++++++ dlls/ntdll/tests/rtl.c | 26 -------------------------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index ef9c68a7c3a..90e6d09740a 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -2117,6 +2117,33 @@ static void test_section_access(void) } } +static void check_tls_index(HANDLE dll, BOOL tls_initialized) +{ + BOOL found_dll = FALSE; + LIST_ENTRY *root = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; + for (LIST_ENTRY *entry = root->Flink; entry != root; entry = entry->Flink) + { + LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + if (wcsicmp(L"ntdll.dll", mod->BaseDllName.Buffer) == 0) + { + /* Pick ntdll as a dll that definitely won't have TLS */ + ok(mod->TlsIndex == 0, "ntdll.dll TlsIndex: %d instead of 0\n", mod->TlsIndex); + } + else if (mod->DllBase == dll) + { + SHORT expected = tls_initialized ? -1 : 0; + ok(mod->TlsIndex == expected, "Test exe TlsIndex: %d instead of %d\n", mod->TlsIndex, expected); + found_dll = TRUE; + } + else + { + ok(mod->TlsIndex == 0 || mod->TlsIndex == -1, "%s TlsIndex: %d\n", + debugstr_w(mod->BaseDllName.Buffer), mod->TlsIndex); + } + } + ok(found_dll, "Couldn't find dll %p in module list\n", dll); +} + static void test_import_resolution(void) { char temp_path[MAX_PATH]; @@ -2251,6 +2278,7 @@ static void test_import_resolution(void) ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str ); ok(ptr->tls_index_hi == 0, "TLS Index written as a short, high half: %d\n", ptr->tls_index_hi); } + check_tls_index(mod, ptr->tls_index != 9999); FreeLibrary( mod ); break; case 1: /* load with DONT_RESOLVE_DLL_REFERENCES doesn't resolve imports */ @@ -2267,6 +2295,7 @@ static void test_import_resolution(void) ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n", (void *)ptr->thunks[0].u1.Function, data.module, data.function.name ); ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index ); + check_tls_index(mod, ptr->tls_index != 9999); FreeLibrary( mod2 ); FreeLibrary( mod ); break; @@ -2278,6 +2307,7 @@ static void test_import_resolution(void) ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n", (void *)ptr->thunks[0].u1.Function, data.module, data.function.name ); ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index ); + check_tls_index(mod, ptr->tls_index != 9999); FreeLibrary( mod ); break; case 3: /* load with tls init function */ @@ -2293,6 +2323,7 @@ static void test_import_resolution(void) str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index]; ok( !strcmp( str, "hello!world" ), "wrong tls data '%s' at %p\n", str, str ); } + check_tls_index(mod, ptr->tls_index != 9999); FreeLibrary( mod ); } DeleteFileA( dll_name ); diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c index a7c43a46e07..c2ca8ea11a7 100644 --- a/dlls/ntdll/tests/rtl.c +++ b/dlls/ntdll/tests/rtl.c @@ -3788,31 +3788,6 @@ static void test_RtlFirstFreeAce(void) HeapFree(GetProcessHeap(), 0, acl); } -static void test_TlsIndex(void) -{ - LIST_ENTRY *root = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; - for (LIST_ENTRY *entry = root->Flink; entry != root; entry = entry->Flink) - { - LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); - if (lstrcmpiW(L"ntdll.dll", mod->BaseDllName.Buffer) == 0) - { - /* Pick ntdll as a dll that definitely won't have TLS */ - ok(mod->TlsIndex == 0, "ntdll.dll TlsIndex: %d instead of 0\n", mod->TlsIndex); - } - else if (mod->DllBase == GetModuleHandleA(NULL)) - { - /* mingw gcc doesn't support MSVC-style TLS */ - /* If we do get a way to add tls to this exe, uncomment the following test: */ - /* ok(mod->TlsIndex == -1, "Test exe TlsIndex: %d instead of -1\n", mod->TlsIndex); */ - } - else - { - ok(mod->TlsIndex == 0 || mod->TlsIndex == -1, "%s TlsIndex: %d\n", - debugstr_w(mod->BaseDllName.Buffer), mod->TlsIndex); - } - } -} - START_TEST(rtl) { InitFunctionPtrs(); @@ -3857,5 +3832,4 @@ START_TEST(rtl) test_DbgPrint(); test_RtlDestroyHeap(); test_RtlFirstFreeAce(); - test_TlsIndex(); } From 39e625a4ac62e942e9704cd4e654c351ddaacaf0 Mon Sep 17 00:00:00 2001 From: Evan Tang Date: Fri, 10 Mar 2023 20:39:38 -0600 Subject: [PATCH 1222/2777] kernel32/tests: Fix tls callback tests on Windows 7. Also add a few more so the full set of callbacks is tested. Fixes: 2203a8564c5faba383a3512f8244dba12d79da16 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54657 (cherry picked from commit a7b49b0e86502125214c3672f56ecda7845dcb0d) --- dlls/kernel32/tests/loader.c | 72 ++++++++++++++++++++++++++++-------- dlls/kernelbase/process.c | 4 +- 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c index 90e6d09740a..19f112efcd8 100644 --- a/dlls/kernel32/tests/loader.c +++ b/dlls/kernel32/tests/loader.c @@ -2144,6 +2144,19 @@ static void check_tls_index(HANDLE dll, BOOL tls_initialized) ok(found_dll, "Couldn't find dll %p in module list\n", dll); } +static int tls_init_fn_output; + +static DWORD WINAPI tls_thread_fn(void* tlsidx_v) +{ + int tls_index = (int)(DWORD_PTR)(tlsidx_v); + const char* str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[tls_index]; + ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str ); + ok( tls_init_fn_output == DLL_THREAD_ATTACH, + "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_THREAD_ATTACH ); + tls_init_fn_output = 9999; + return 0; +} + static void test_import_resolution(void) { char temp_path[MAX_PATH]; @@ -2165,31 +2178,41 @@ static void test_import_resolution(void) char tls_data[16]; SHORT tls_index; SHORT tls_index_hi; - UCHAR tls_init_fn[64]; /* Note: Uses rip-relative address of tls_index, don't separate */ + int* tls_init_fn_output; + UCHAR tls_init_fn[64]; /* Note: Uses rip-relative address of tls_init_fn_output, don't separate */ + UCHAR entry_point_fn[16]; } data, *ptr; IMAGE_NT_HEADERS nt; IMAGE_SECTION_HEADER section; - int test; + int test, tls_index_save; #if defined(__i386__) static const UCHAR tls_init_code[] = { - 0xE8, 0x00, 0x00, 0x00, 0x00, /* call 1f */ - 0x59, /* 1: pop ecx */ - 0x8B, 0x49, 0xF7, /* mov ecx, [ecx - 9] ; mov ecx, [tls_index] */ - 0x64, 0x8B, 0x15, 0x2C, 0x00, 0x00, 0x00, /* mov edx, fs:0x2c */ - 0x8B, 0x14, 0x8A, /* mov edx, [edx + edx * 4] */ - 0xC6, 0x42, 0x05, 0x21, /* mov byte [edx + 5], 0x21 */ - 0xC2, 0x0C, 0x00, /* ret 12 */ + 0xE8, 0x00, 0x00, 0x00, 0x00, /* call 1f */ + 0x59, /* 1: pop ecx */ + 0x8B, 0x49, 0xF7, /* mov ecx, [ecx - 9] ; mov ecx, [tls_init_fn_output] */ + 0x8B, 0x54, 0x24, 0x08, /* mov edx, [esp + 8] */ + 0x89, 0x11, /* mov [ecx], edx */ + 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */ + 0xC2, 0x0C, 0x00, /* ret 12 */ + }; + static const UCHAR entry_point_code[] = { + 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */ + 0xC2, 0x0C, 0x00, /* ret 12 */ }; #elif defined(__x86_64__) static const UCHAR tls_init_code[] = { - 0x8B, 0x0D, 0xF6, 0xFF, 0xFF, 0xFF, /* mov ecx, [rip + tls_index] */ - 0x65, 0x48, 0x8B, 0x14, 0x25, 0x58, 0x00, 0x00, 0x00, /* mov rdx, gs:0x58 */ - 0x48, 0x8B, 0x14, 0xCA, /* mov rdx, [rdx + rcx * 8] */ - 0xC6, 0x42, 0x05, 0x21, /* mov byte [rdx + 5], 0x21 */ - 0xC3, /* ret */ + 0x48, 0x8B, 0x0D, 0xF1, 0xFF, 0xFF, 0xFF, /* mov rcx, [rip + tls_init_fn_output] */ + 0x89, 0x11, /* mov [rcx], edx */ + 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */ + 0xC3, /* ret */ + }; + static const UCHAR entry_point_code[] = { + 0xB8, 0x01, 0x00, 0x00, 0x00, /* mov eax, 1 */ + 0xC3, /* ret */ }; #else static const UCHAR tls_init_code[] = { 0x00 }; + static const UCHAR entry_point_code[] = { 0x00 }; #endif for (test = 0; test < 4; test++) @@ -2230,10 +2253,16 @@ static void test_import_resolution(void) if (test == 3 && sizeof(tls_init_code) > 1) { + /* Windows doesn't consistently call tls init functions on dlls without entry points */ assert(sizeof(tls_init_code) <= sizeof(data.tls_init_fn)); + assert(sizeof(entry_point_code) <= sizeof(data.entry_point_fn)); memcpy(data.tls_init_fn, tls_init_code, sizeof(tls_init_code)); + memcpy(data.entry_point_fn, entry_point_code, sizeof(entry_point_code)); + tls_init_fn_output = 9999; + data.tls_init_fn_output = &tls_init_fn_output; data.tls_init_fn_list[0] = nt.OptionalHeader.ImageBase + DATA_RVA(&data.tls_init_fn); data.tls.AddressOfCallBacks = nt.OptionalHeader.ImageBase + DATA_RVA(&data.tls_init_fn_list); + nt.OptionalHeader.AddressOfEntryPoint = DATA_RVA(&data.entry_point_fn); } GetTempPathA(MAX_PATH, temp_path); @@ -2315,16 +2344,27 @@ static void test_import_resolution(void) ok( mod != NULL, "failed to load err %lu\n", GetLastError() ); if (!mod) break; ptr = (struct imports *)((char *)mod + page_size); + tls_index_save = ptr->tls_index; ok( ptr->tls_index < 32 || broken(ptr->tls_index == 9999), /* before vista */ "wrong tls index %d\n", ptr->tls_index ); if (ptr->tls_index != 9999 && sizeof(tls_init_code) > 1) { - /* tls init function will write an '!' over the space in "hello world" */ str = ((char **)NtCurrentTeb()->ThreadLocalStoragePointer)[ptr->tls_index]; - ok( !strcmp( str, "hello!world" ), "wrong tls data '%s' at %p\n", str, str ); + ok( !strcmp( str, "hello world" ), "wrong tls data '%s' at %p\n", str, str ); + /* tls init function will write the reason to *tls_init_fn_output */ + ok( tls_init_fn_output == DLL_PROCESS_ATTACH, + "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_PROCESS_ATTACH ); + tls_init_fn_output = 9999; + WaitForSingleObject(CreateThread(NULL, 0, tls_thread_fn, (void*)(DWORD_PTR)ptr->tls_index, 0, NULL), INFINITE); + ok( tls_init_fn_output == DLL_THREAD_DETACH, + "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_THREAD_DETACH ); } check_tls_index(mod, ptr->tls_index != 9999); + tls_init_fn_output = 9999; FreeLibrary( mod ); + if (tls_index_save != 9999 && sizeof(tls_init_code) > 1) + ok( tls_init_fn_output == DLL_PROCESS_DETACH, + "tls init function didn't run or got wrong reason: %d instead of %d\n", tls_init_fn_output, DLL_PROCESS_DETACH ); } DeleteFileA( dll_name ); #undef DATA_RVA diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 2d42d408012..bd3a790c062 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -602,8 +602,8 @@ static const WCHAR *hack_append_command_line( const WCHAR *cmd ) {L"UplayWebCore.exe", L" --use-angle=gl"}, {L"Paradox Launcher.exe", L" --use-gl=swiftshader --in-process-gpu"}, {L"Montaro\\nw.exe", L" --use-gl=swiftshader"}, - {L"EOSOverlayRenderer-Win64-Shipping.exe", L" --use-gl=swiftshader --in-process-gpu"}, - {L"EpicOnlineServicesUIHelper", L" --use-gl=desktop"}, + {L"\\EOSOverlayRenderer-Win64-Shipping.exe", L" --use-gl=swiftshader --in-process-gpu"}, + {L"\\EpicOnlineServicesUIHelper", L" --use-gl=desktop"}, {L"OlympiaRising.exe", L" --use-gl=swiftshader"}, {L"nw.exe.exe", L" --use-angle=d3d9"}, }; From ec4be35ffb327df5fb689941cbae9519d0f1f3db Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 11 Apr 2023 14:04:18 -0600 Subject: [PATCH 1223/2777] ntdll: HACK: Enable WINE_SIMULATE_WRITECOPY for Breakout 13. CW-Bug-Id: #22130 --- dlls/ntdll/unix/loader.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 9781e3df094..fad2131c8bc 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2339,7 +2339,8 @@ static void hacks_init(void) env_str = getenv("WINE_SIMULATE_WRITECOPY"); if (env_str) simulate_writecopy = atoi(env_str); - else if (sgi) simulate_writecopy = !strcmp(sgi, "1608730") || !strcmp(sgi, "1680700"); + else if (sgi) simulate_writecopy = !strcmp(sgi, "1608730") || !strcmp(sgi, "1680700") + || !strcmp(sgi, "2095300"); if (main_argc > 1 && strstr(main_argv[1], "MicrosoftEdgeUpdate.exe")) { From 58ceab7abb1390fcb8a80acbee4780e41a536d10 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Tue, 11 Apr 2023 16:34:16 +0800 Subject: [PATCH 1224/2777] HACK: ntdll: Enable WINE_SIMULATE_WRITECOPY for Mr. Hopp's Playhouse 3. CW-Bug-Id: #22127 --- dlls/ntdll/unix/loader.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index fad2131c8bc..00f545f181e 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2339,8 +2339,10 @@ static void hacks_init(void) env_str = getenv("WINE_SIMULATE_WRITECOPY"); if (env_str) simulate_writecopy = atoi(env_str); - else if (sgi) simulate_writecopy = !strcmp(sgi, "1608730") || !strcmp(sgi, "1680700") - || !strcmp(sgi, "2095300"); + else if (sgi) simulate_writecopy = !strcmp(sgi, "1608730") /* Dawn of Corruption */ + || !strcmp(sgi, "1680700") /* Purgo box */ + || !strcmp(sgi, "2095300") /* Breakout 13 */ + || !strcmp(sgi, "2176450"); /* Mr. Hopp's Playhouse 3 */ if (main_argc > 1 && strstr(main_argv[1], "MicrosoftEdgeUpdate.exe")) { From 580750e154512efdf33dc8afc341da83ae883e0a Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Mon, 13 Mar 2023 17:41:14 +0800 Subject: [PATCH 1225/2777] HACK: winex11.drv: Disable Vulkan child window rendering for Tales of Berseria. The game creates a top-level window and use it to create a Vulkan surface. It then creates a child window in the top-level window so Vulkan child window rendering gets enabled, causing the game intro video tearing because the use of XCopyArea(). X11 doesn't seem to have proper vertical blanking support so a hack is used instead. CW-Bug-Id: #21949 --- dlls/winex11.drv/vulkan.c | 17 +++++++++++++++++ dlls/winex11.drv/x11drv.h | 1 + dlls/winex11.drv/x11drv_main.c | 8 ++++++++ 3 files changed, 26 insertions(+) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index cae182fe89a..3e260adcd04 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -289,6 +289,12 @@ static BOOL wine_vk_surface_set_offscreen(struct wine_vk_surface *surface, BOOL #ifdef SONAME_LIBXCOMPOSITE if (usexcomposite) { + if (vulkan_disable_child_window_rendering_hack) + { + FIXME("Vulkan child window rendering is supported, but it's disabled.\n"); + return TRUE; + } + if (!surface->offscreen && offscreen) { FIXME("Redirecting vulkan surface offscreen, expect degraded performance.\n"); @@ -326,6 +332,17 @@ void sync_vk_surface(HWND hwnd, BOOL known_child) struct wine_vk_surface *surface; UINT surface_with_swapchain_count = 0; + if (vulkan_disable_child_window_rendering_hack) + { + static BOOL once = FALSE; + + if (!once++) + FIXME("Vulkan child window rendering is disabled.\n"); + else + WARN("Vulkan child window rendering is disabled.\n"); + return; + } + pthread_mutex_lock(&vulkan_mutex); LIST_FOR_EACH_ENTRY(surface, &surface_list, struct wine_vk_surface, entry) { diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 5413f82f54a..9013ae595fd 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -1019,5 +1019,6 @@ static inline UINT asciiz_to_unicode( WCHAR *dst, const char *src ) extern BOOL layered_window_client_hack; extern BOOL vulkan_gdi_blit_source_hack; +extern BOOL vulkan_disable_child_window_rendering_hack; #endif /* __WINE_X11DRV_H */ diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 9d534c1bcf7..58d7c8eee03 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -99,6 +99,7 @@ HANDLE steam_overlay_event; HANDLE steam_keyboard_event; BOOL layered_window_client_hack = FALSE; BOOL vulkan_gdi_blit_source_hack = FALSE; +BOOL vulkan_disable_child_window_rendering_hack = FALSE; static x11drv_error_callback err_callback; /* current callback for error */ static Display *err_callback_display; /* display callback is set for */ @@ -845,6 +846,13 @@ static NTSTATUS x11drv_init( void *arg ) !strcmp(sgi, "803600") /* Disgaea 5 Complete */ )) || (e && *e != '\0' && *e != '0'); + + e = getenv("WINE_DISABLE_VK_CHILD_WINDOW_RENDERING_HACK"); + vulkan_disable_child_window_rendering_hack = + (sgi && ( + !strcmp(sgi, "429660") /* Bug 21949 : Tales of Berseria video tearing */ + )) || + (e && *e != '\0' && *e != '0'); } init_user_driver(); From 978cdfb67fee41b99fa88942dd467ca4e2eaec73 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Mon, 10 Apr 2023 16:54:38 +0800 Subject: [PATCH 1226/2777] amd_ags_x64: Stub agsSetDisplayMode(). CW-Bug-Id: #22067 --- dlls/amd_ags_x64/amd_ags_x64.spec | 2 +- dlls/amd_ags_x64/amd_ags_x64_main.c | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec index 3d9800469a1..ece559ca9d3 100644 --- a/dlls/amd_ags_x64/amd_ags_x64.spec +++ b/dlls/amd_ags_x64/amd_ags_x64.spec @@ -42,4 +42,4 @@ @ stdcall agsGetVersionNumber() @ stdcall agsInit(ptr ptr ptr) @ stdcall agsInitialize(long ptr ptr ptr) -@ stub agsSetDisplayMode +@ stdcall agsSetDisplayMode(ptr long long ptr) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 97cc6d48afa..32f618c95dc 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -633,6 +633,17 @@ AGSReturnCode WINAPI agsDeInitialize(AGSContext *context) return AGS_SUCCESS; } +AGSReturnCode WINAPI agsSetDisplayMode(AGSContext *context, int device_index, int display_index, const AGSDisplaySettings *settings) +{ + FIXME("context %p device_index %d display_index %d settings %p stub!\n", context, device_index, + display_index, settings); + + if (!context) + return AGS_INVALID_ARGS; + + return AGS_SUCCESS; +} + AGSReturnCode WINAPI agsGetCrossfireGPUCount(AGSContext *context, int *gpu_count) { TRACE("context %p gpu_count %p stub!\n", context, gpu_count); From b6ee91e25a25b30eb4b34e5f3fc9934d5d7f0584 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Mon, 10 Apr 2023 16:57:24 +0800 Subject: [PATCH 1227/2777] wine.inf: Set amd_ags_x64 to built-in for Ghost Recon Breakpoint. CW-Bug-Id: #22067 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 40dcd9eb0d2..cdece7d2b22 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2840,6 +2840,7 @@ HKCU,Software\Wine\AppDefaults\RDR2.exe\DllOverrides,"amd_ags_x64",0x2,"builtin, HKCU,Software\Wine\AppDefaults\ForzaHorizon4.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" HKCU,Software\Wine\AppDefaults\Deathloop.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" HKCU,Software\Wine\AppDefaults\ForzaHorizon5.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" +HKCU,Software\Wine\AppDefaults\GRB.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\MonsterHunterRise.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\Sam4.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\Sam4_Unrestricted.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" From 377d449f6bb75d462c71c27ed77cc4bd4d1d9faf Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 16 Dec 2022 16:21:50 -0600 Subject: [PATCH 1228/2777] ntdll: HACK: Also simulate async file read and IO cancellation for Immortals Fenyx Rising. CW-Bug-Id: #21711 --- dlls/ntdll/unix/loader.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 00f545f181e..c2887f51500 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2286,15 +2286,18 @@ BOOL simulate_writecopy; 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 *env_str, *sgi; - if (main_argc > 1 && strstr(main_argv[1], ac_odyssey_exe)) - { - ERR("HACK: AC Odyssey sync tweak on.\n"); + + env_str = getenv("WINE_SIMULATE_ASYNC_READ"); + if (env_str) + ac_odyssey = !!atoi(env_str); + else if (main_argc > 1 && (strstr(main_argv[1], "ACOdyssey.exe") || strstr(main_argv[1], "ImmortalsFenyxRising.exe"))) ac_odyssey = TRUE; - return; - } + + if (ac_odyssey) + ERR("HACK: AC Odyssey sync tweak on.\n"); + env_str = getenv("WINE_FSYNC_SIMULATE_SCHED_QUANTUM"); if (env_str) fsync_simulate_sched_quantum = !!atoi(env_str); From 23908e917ba5dfd08fb001510b610f19ea439bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 14 Dec 2022 21:57:01 +0100 Subject: [PATCH 1229/2777] ntdll: HACK: Set LIBGL_ALWAYS_SOFTWARE for Witcher 3 (Launcher). CW-Bug-Id: #21699 --- dlls/ntdll/unix/loader.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index c2887f51500..2b6fac37bb1 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2361,6 +2361,11 @@ static void hacks_init(void) ERR("HACK: setting LIBGL_ALWAYS_SOFTWARE.\n"); setenv("LIBGL_ALWAYS_SOFTWARE", "1", 0); } + if (sgi && !strcmp(sgi, "292030")) + { + ERR("HACK: setting LIBGL_ALWAYS_SOFTWARE.\n"); + setenv("LIBGL_ALWAYS_SOFTWARE", "1", 0); + } } #ifdef _WIN64 From b5766a820bae8ab060551309c770b46d2ddf7c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Feb 2023 23:01:03 +0100 Subject: [PATCH 1230/2777] user32: Move GetTouchInputInfo to win32u NtUserGetTouchInputInfo. CW-Bug-Id: #21796 --- dlls/user32/input.c | 10 ---------- dlls/user32/user32.spec | 2 +- dlls/win32u/input.c | 10 ++++++++++ dlls/win32u/ntuser_private.h | 8 ++++++++ dlls/win32u/syscall.c | 1 + dlls/win32u/win32u.spec | 2 +- dlls/wow64win/syscall.h | 1 + dlls/wow64win/user.c | 10 ++++++++++ include/ntuser.h | 1 + 9 files changed, 33 insertions(+), 12 deletions(-) diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 7f7eb18476a..2e08d0e2eda 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -654,16 +654,6 @@ BOOL WINAPI CloseTouchInputHandle( HTOUCHINPUT handle ) return TRUE; } -/***************************************************************************** - * GetTouchInputInfo (USER32.@) - */ -BOOL WINAPI GetTouchInputInfo( HTOUCHINPUT handle, UINT count, TOUCHINPUT *ptr, int size ) -{ - TRACE( "handle %p, count %u, ptr %p, size %u.\n", handle, count, ptr, size ); - *ptr = *(TOUCHINPUT *)handle; - return TRUE; -} - /***************************************************************************** * RegisterTouchWindow (USER32.@) */ diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index a3c950da87d..21962768dcc 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -396,7 +396,7 @@ @ stdcall GetThreadDpiAwarenessContext() @ stdcall GetTitleBarInfo(long ptr) NtUserGetTitleBarInfo @ stdcall GetTopWindow(long) -@ stdcall GetTouchInputInfo(long long ptr long) +@ stdcall GetTouchInputInfo(long long ptr long) NtUserGetTouchInputInfo @ stdcall GetUpdateRect(long ptr long) NtUserGetUpdateRect @ stdcall GetUpdateRgn(long long long) NtUserGetUpdateRgn @ stdcall GetUpdatedClipboardFormats(ptr long ptr) NtUserGetUpdatedClipboardFormats diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 79382e55c42..248dcdc2614 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2594,3 +2594,13 @@ HWND set_taskman_window( HWND hwnd ) SERVER_END_REQ; return hwnd; } + +/***************************************************************************** + * NtUserGetTouchInputInfo (WIN32U.@) + */ +BOOL WINAPI NtUserGetTouchInputInfo( HTOUCHINPUT handle, UINT count, TOUCHINPUT *ptr, int size ) +{ + TRACE( "handle %p, count %u, ptr %p, size %u.\n", handle, count, ptr, size ); + *ptr = *(TOUCHINPUT *)handle; + return TRUE; +} diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 4c92480b476..44af8158c6f 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -116,6 +116,13 @@ static inline BOOL is_broadcast( HWND hwnd ) return hwnd == HWND_BROADCAST || hwnd == HWND_TOPMOST; } +struct touchinput_thread_data +{ + BYTE index; /* history index */ + TOUCHINPUT current[8]; /* current touch state */ + TOUCHINPUT history[128][8]; /* touches history buffer */ +}; + /* this is the structure stored in TEB->Win32ClientInfo */ /* no attempt is made to keep the layout compatible with the Windows one */ struct user_thread_info @@ -136,6 +143,7 @@ struct user_thread_info HKL kbd_layout; /* Current keyboard layout */ UINT kbd_layout_id; /* Current keyboard layout ID */ struct rawinput_thread_data *rawinput; /* RawInput thread local data / buffer */ + struct touchinput_thread_data *touchinput; /* touch input thread local buffer */ UINT spy_indent; /* Current spy indent */ struct desktop_shared_memory *desktop_shared_memory; /* Ptr to server's desktop shared memory */ struct queue_shared_memory *queue_shared_memory; /* Ptr to server's thread queue shared memory */ diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index 49ce3943444..e802b3d2ec0 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -209,6 +209,7 @@ static void * const syscalls[] = NtUserGetSystemMenu, NtUserGetThreadDesktop, NtUserGetTitleBarInfo, + NtUserGetTouchInputInfo, NtUserGetUpdateRect, NtUserGetUpdateRgn, NtUserGetUpdatedClipboardFormats, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index b7311009ffa..d450d07635e 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -999,7 +999,7 @@ @ stub NtUserGetThreadState @ stdcall -syscall NtUserGetTitleBarInfo(long ptr) @ stub NtUserGetTopLevelWindow -@ stub NtUserGetTouchInputInfo +@ stdcall -syscall NtUserGetTouchInputInfo(ptr long ptr long) @ stub NtUserGetTouchValidationStatus @ stub NtUserGetUniformSpaceMapping @ stdcall -syscall NtUserGetUpdateRect(long ptr long) diff --git a/dlls/wow64win/syscall.h b/dlls/wow64win/syscall.h index 4977013c595..8543c877644 100644 --- a/dlls/wow64win/syscall.h +++ b/dlls/wow64win/syscall.h @@ -195,6 +195,7 @@ SYSCALL_ENTRY( NtUserGetSystemMenu ) \ SYSCALL_ENTRY( NtUserGetThreadDesktop ) \ SYSCALL_ENTRY( NtUserGetTitleBarInfo ) \ + SYSCALL_ENTRY( NtUserGetTouchInputInfo ) \ SYSCALL_ENTRY( NtUserGetUpdateRect ) \ SYSCALL_ENTRY( NtUserGetUpdateRgn ) \ SYSCALL_ENTRY( NtUserGetUpdatedClipboardFormats ) \ diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index 2ce82907a88..c8ce23a05ce 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -2582,6 +2582,16 @@ NTSTATUS WINAPI wow64_NtUserGetTitleBarInfo( UINT *args ) return NtUserGetTitleBarInfo( hwnd, info ); } +NTSTATUS WINAPI wow64_NtUserGetTouchInputInfo( UINT *args ) +{ + HTOUCHINPUT handle = get_handle( &args ); + UINT count = get_ulong( &args ); + TOUCHINPUT *ptr = get_ptr( &args ); + int size = get_ulong( &args ); + + return NtUserGetTouchInputInfo( handle, count, ptr, size ); +} + NTSTATUS WINAPI wow64_NtUserGetUpdateRect( UINT *args ) { HWND hwnd = get_handle( &args ); diff --git a/include/ntuser.h b/include/ntuser.h index 7e8e5b56371..5295c2c2108 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -778,6 +778,7 @@ ULONG WINAPI NtUserGetSystemDpiForProcess( HANDLE process ); HMENU WINAPI NtUserGetSystemMenu( HWND hwnd, BOOL revert ); HDESK WINAPI NtUserGetThreadDesktop( DWORD thread ); BOOL WINAPI NtUserGetTitleBarInfo( HWND hwnd, TITLEBARINFO *info ); +BOOL WINAPI NtUserGetTouchInputInfo( HTOUCHINPUT handle, UINT count, TOUCHINPUT *ptr, int size ); INT WINAPI NtUserGetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase ); BOOL WINAPI NtUserGetUpdatedClipboardFormats( UINT *formats, UINT size, UINT *out_size ); BOOL WINAPI NtUserGetUpdateRect( HWND hwnd, RECT *rect, BOOL erase ); From 330a34b848a1a49dc35bab7d200d59615b16a227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 13 Jan 2023 10:59:12 +0100 Subject: [PATCH 1231/2777] win32u: Support multiple touches in WM_TOUCH message. CW-Bug-Id: #21796 --- dlls/win32u/defwnd.c | 70 +++++++++++++++++++++++++++++++++----------- dlls/win32u/input.c | 14 ++++++++- 2 files changed, 66 insertions(+), 18 deletions(-) diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c index 76779974cfb..b28d02a79f4 100644 --- a/dlls/win32u/defwnd.c +++ b/dlls/win32u/defwnd.c @@ -2386,6 +2386,14 @@ static LRESULT handle_nc_mouse_leave( HWND hwnd ) return 0; } +static struct touchinput_thread_data *touch_input_thread_data(void) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + struct touchinput_thread_data *data = thread_info->touchinput; + + if (!data) data = thread_info->touchinput = calloc( 1, sizeof(struct touchinput_thread_data) ); + return data; +} LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL ansi ) { @@ -2950,25 +2958,53 @@ LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, case WM_POINTERUP: case WM_POINTERUPDATE: { - TOUCHINPUT touchinput; + struct touchinput_thread_data *thread_data; + TOUCHINPUT *touches, *end, *touch; + UINT i; if (!NtUserIsTouchWindow( hwnd, NULL )) return 0; - touchinput.x = LOWORD( lparam ) * 100; - touchinput.y = HIWORD( lparam ) * 100; - touchinput.hSource = WINE_MOUSE_HANDLE; - touchinput.dwID = GET_POINTERID_WPARAM( wparam ); - touchinput.dwFlags = TOUCHEVENTF_NOCOALESCE | TOUCHEVENTF_PALM; - if (msg == WM_POINTERDOWN) touchinput.dwFlags |= TOUCHEVENTF_DOWN; - if (msg == WM_POINTERUP) touchinput.dwFlags |= TOUCHEVENTF_UP; - if (msg == WM_POINTERUPDATE) touchinput.dwFlags |= TOUCHEVENTF_MOVE; - if (IS_POINTER_PRIMARY_WPARAM( wparam )) touchinput.dwFlags |= TOUCHEVENTF_PRIMARY; - touchinput.dwMask = 0; - touchinput.dwTime = NtGetTickCount(); - touchinput.dwExtraInfo = 0; - touchinput.cxContact = 0; - touchinput.cyContact = 0; - - send_message( hwnd, WM_TOUCH, MAKELONG( 1, 0 ), (LPARAM)&touchinput ); + if (!(thread_data = touch_input_thread_data())) return 0; + + for (touches = thread_data->current, end = touches + ARRAY_SIZE(thread_data->current), touch = touches; touch < end; touch++) + if (!touch->dwID || touch->dwID == GET_POINTERID_WPARAM( wparam )) break; + + if (touch == end || (msg != WM_POINTERDOWN && !touch->dwID)) + { + if (msg != WM_POINTERDOWN) FIXME("Touch point not found!\n"); + else FIXME("Unsupported number of touch points!\n"); + break; + } + + while (end > touch && !(end - 1)->dwID) end--; + + if (msg == WM_POINTERUP) + { + while (++touch < end) *(touch - 1) = *touch; + memset( touch - 1, 0, sizeof(*touch) ); + end--; + } + else + { + touch->x = LOWORD( lparam ) * 100; + touch->y = HIWORD( lparam ) * 100; + touch->hSource = WINE_MOUSE_HANDLE; + touch->dwID = GET_POINTERID_WPARAM( wparam ); + touch->dwFlags = TOUCHEVENTF_NOCOALESCE | TOUCHEVENTF_PALM; + if (msg == WM_POINTERDOWN) touch->dwFlags |= TOUCHEVENTF_DOWN; + if (msg == WM_POINTERUP) touch->dwFlags |= TOUCHEVENTF_UP; + if (msg == WM_POINTERUPDATE) touch->dwFlags |= TOUCHEVENTF_MOVE; + if (IS_POINTER_PRIMARY_WPARAM( wparam )) touch->dwFlags |= TOUCHEVENTF_PRIMARY; + touch->dwMask = 0; + touch->dwTime = NtGetTickCount(); + touch->dwExtraInfo = 0; + touch->cxContact = 0; + touch->cyContact = 0; + } + + i = thread_data->index++ % ARRAY_SIZE(thread_data->history); + memcpy( thread_data->history + i, thread_data->current, sizeof(thread_data->current) ); + + send_message( hwnd, WM_TOUCH, MAKELONG(end - touches, 0), (LPARAM)i ); break; } diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 248dcdc2614..2e35d3b8d1a 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2600,7 +2600,19 @@ HWND set_taskman_window( HWND hwnd ) */ BOOL WINAPI NtUserGetTouchInputInfo( HTOUCHINPUT handle, UINT count, TOUCHINPUT *ptr, int size ) { + struct user_thread_info *thread_info = get_user_thread_info(); + struct touchinput_thread_data *thread_data; + UINT index = (ULONG_PTR)handle; + TRACE( "handle %p, count %u, ptr %p, size %u.\n", handle, count, ptr, size ); - *ptr = *(TOUCHINPUT *)handle; + + if (!thread_info || !(thread_data = thread_info->touchinput) || size != sizeof(TOUCHINPUT) || + index >= ARRAY_SIZE(thread_data->history)) + { + RtlSetLastWin32Error( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + memcpy( ptr, thread_data->history + index, min( count, ARRAY_SIZE(thread_data->current) ) * size ); return TRUE; } From c15c719f9104eaeb5feaf4800151a89422d4acfe Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 24 Apr 2023 19:58:11 -0600 Subject: [PATCH 1232/2777] HACK: server: Disable hooks that time out. An addition to "HACK: user32: Remove hooks that time out." CW-Bug-Id: #22178 --- server/hook.c | 25 ++++++++++++++++++++++++- server/queue.c | 22 ++++++++++++++++++---- server/user.h | 3 ++- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/server/hook.c b/server/hook.c index 3a89a883c3c..24eb27434db 100644 --- a/server/hook.c +++ b/server/hook.c @@ -374,16 +374,39 @@ static unsigned int get_active_hooks(void) } /* return the thread that owns the first global hook */ -struct thread *get_first_global_hook( int id ) +struct thread *get_first_global_hook( int id, thread_id_t *thread_id, client_ptr_t *proc ) { struct hook *hook; struct hook_table *global_hooks = get_global_hooks( current ); if (!global_hooks) return NULL; if (!(hook = get_first_valid_hook( global_hooks, id - WH_MINHOOK, EVENT_MIN, 0, 0, 0 ))) return NULL; + *thread_id = hook->owner->id; + *proc = hook->proc; return hook->owner; } +void disable_hung_hook( struct desktop *desktop, int id, thread_id_t thread_id, client_ptr_t proc ) +{ + struct hook_table *global_hooks = desktop->global_hooks; + int index = id - WH_MINHOOK; + struct hook *hook; + + if (!global_hooks || !proc) return; + + hook = get_first_hook( global_hooks, index ); + + while (hook) + { + if (hook->proc == proc && hook->owner->id == thread_id) + { + hook->proc = 0; + return; + } + hook = HOOK_ENTRY( list_next( &global_hooks->hooks[index], &hook->chain ) ); + } +} + /* get thread active hooks */ DECL_HANDLER(get_active_hooks) { diff --git a/server/queue.c b/server/queue.c index 5ed75964e0f..f51263ed692 100644 --- a/server/queue.c +++ b/server/queue.c @@ -67,6 +67,8 @@ struct message_result void *data; /* message reply data */ unsigned int data_size; /* size of message reply data */ struct timeout_user *timeout; /* result timeout */ + thread_id_t hook_thread_id;/* Hook owner thread id. */ + client_ptr_t hook_proc; /* Hook proc address. */ }; struct message @@ -872,6 +874,13 @@ static void result_timeout( void *private ) { struct message *msg = result->msg; + if (result->sender && result->hook_thread_id && result->hook_proc) + { + if (debug_level > 1) + fprintf( stderr, "disabling hung hook: tid %04x, proc %#lx\n", + result->hook_thread_id, (unsigned long)result->hook_proc ); + disable_hung_hook( result->sender->input->desktop, msg->msg, result->hook_thread_id, result->hook_proc ); + } result->msg = NULL; msg->result = NULL; remove_queue_message( result->receiver, msg, SEND_MESSAGE ); @@ -883,7 +892,8 @@ static void result_timeout( void *private ) /* allocate and fill a message result structure */ static struct message_result *alloc_message_result( struct msg_queue *send_queue, struct msg_queue *recv_queue, - struct message *msg, timeout_t timeout ) + struct message *msg, timeout_t timeout, + thread_id_t hook_thread_id, client_ptr_t hook_proc) { struct message_result *result = mem_alloc( sizeof(*result) ); if (result) @@ -898,6 +908,8 @@ static struct message_result *alloc_message_result( struct msg_queue *send_queue result->hardware_msg = NULL; result->desktop = NULL; result->callback_msg = NULL; + result->hook_thread_id = hook_thread_id; + result->hook_proc = hook_proc; if (msg->type == MSG_CALLBACK) { @@ -1863,8 +1875,10 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa struct message *msg; timeout_t timeout = 2000 * -10000; /* FIXME: load from registry */ int id = (input->type == INPUT_MOUSE) ? WH_MOUSE_LL : WH_KEYBOARD_LL; + thread_id_t hook_thread_id; + client_ptr_t hook_proc; - if (!(hook_thread = get_first_global_hook( id ))) return 0; + if (!(hook_thread = get_first_global_hook( id, &hook_thread_id, &hook_proc ))) return 0; if (!(queue = hook_thread->queue)) return 0; if (is_queue_hung( queue )) return 0; @@ -1889,7 +1903,7 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa else msg->lparam = input->mouse.data << 16; if (!(msg->data = memdup( hardware_msg->data, hardware_msg->data_size )) || - !(msg->result = alloc_message_result( sender, queue, msg, timeout ))) + !(msg->result = alloc_message_result( sender, queue, msg, timeout, hook_thread_id, hook_proc ))) { free_message( msg ); return 0; @@ -2877,7 +2891,7 @@ DECL_HANDLER(send_message) case MSG_ASCII: case MSG_UNICODE: case MSG_CALLBACK: - if (!(msg->result = alloc_message_result( send_queue, recv_queue, msg, req->timeout ))) + if (!(msg->result = alloc_message_result( send_queue, recv_queue, msg, req->timeout, 0, 0 ))) { free_message( msg ); break; diff --git a/server/user.h b/server/user.h index 1a7980e6f61..deebd92ee6a 100644 --- a/server/user.h +++ b/server/user.h @@ -93,7 +93,8 @@ extern void cleanup_clipboard_thread( struct thread *thread ); /* hook functions */ extern void remove_thread_hooks( struct thread *thread ); -extern struct thread *get_first_global_hook( int id ); +extern struct thread *get_first_global_hook( int id, thread_id_t *thread_id, client_ptr_t *proc ); +extern void disable_hung_hook( struct desktop *desktop, int id, thread_id_t thread_id, client_ptr_t proc ); /* queue functions */ From 44b7f12182d45e4be0083265008a0ade574d6361 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Sat, 11 Mar 2023 14:12:18 -0500 Subject: [PATCH 1233/2777] quartz: Set filter sync source in FilterGraph2_AddFilter. (cherry picked from commit 6992b7623b8f5673c9b5da0fe3b32ef82854dc25) CW-Bug-Id: #21705 --- dlls/quartz/filtergraph.c | 2 ++ dlls/quartz/tests/filtergraph.c | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c index 3e0a34f07ba..ef8d27ff5c8 100644 --- a/dlls/quartz/filtergraph.c +++ b/dlls/quartz/filtergraph.c @@ -675,6 +675,8 @@ static HRESULT WINAPI FilterGraph2_AddFilter(IFilterGraph2 *iface, return hr; } + IBaseFilter_SetSyncSource(filter, graph->refClock); + IBaseFilter_AddRef(entry->filter = filter); list_add_head(&graph->filters, &entry->entry); diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c index d6ce9d31ce2..391f9777175 100644 --- a/dlls/quartz/tests/filtergraph.c +++ b/dlls/quartz/tests/filtergraph.c @@ -3314,7 +3314,7 @@ static void test_connect_direct(void) static void test_sync_source(void) { - struct testfilter filter1, filter2; + struct testfilter filter1, filter2, filter3; IFilterGraph2 *graph = create_graph(); IReferenceClock *systemclock, *clock; @@ -3326,6 +3326,7 @@ static void test_sync_source(void) testfilter_init(&filter1, NULL, 0); testfilter_init(&filter2, NULL, 0); + testfilter_init(&filter3, NULL, 0); IFilterGraph2_AddFilter(graph, &filter1.IBaseFilter_iface, NULL); IFilterGraph2_AddFilter(graph, &filter2.IBaseFilter_iface, NULL); @@ -3346,10 +3347,14 @@ static void test_sync_source(void) ok(clock == systemclock, "Got clock %p.\n", clock); IReferenceClock_Release(clock); + IFilterGraph2_AddFilter(graph, &filter3.IBaseFilter_iface, NULL); + ok(filter3.clock == systemclock, "Got clock %p.\n", filter3.clock); + hr = IMediaFilter_SetSyncSource(filter, NULL); ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(!filter1.clock, "Got clock %p.\n", filter1.clock); ok(!filter2.clock, "Got clock %p.\n", filter2.clock); + ok(!filter3.clock, "Got clock %p.\n", filter3.clock); hr = IMediaFilter_GetSyncSource(filter, &clock); todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); @@ -3361,6 +3366,7 @@ static void test_sync_source(void) ok(!ref, "Got outstanding refcount %ld\n", ref); ok(filter1.ref == 1, "Got outstanding refcount %ld.\n", filter1.ref); ok(filter2.ref == 1, "Got outstanding refcount %ld.\n", filter2.ref); + ok(filter3.ref == 1, "Got outstanding refcount %ld.\n", filter3.ref); } #define check_filter_state(a, b) check_filter_state_(__LINE__, a, b) From 7a1b49c8229d6e3c1026725a9abbf9e7e1b89544 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 10 Apr 2023 16:20:38 -0600 Subject: [PATCH 1234/2777] winex11.drv: Fix bit shifts in pixel format description for RGBA formats. (cherry picked from commit 01c59b3f18dca1f4db42425eda2f95296da61a63) CW-Bug-Id: #22128 --- dlls/opengl32/tests/opengl.c | 15 ++++++++++++++- dlls/winex11.drv/opengl.c | 13 ++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c index 42c2626a2c2..724f21ed3d6 100644 --- a/dlls/opengl32/tests/opengl.c +++ b/dlls/opengl32/tests/opengl.c @@ -288,7 +288,20 @@ static void test_choosepixelformat(void) pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 32; - ok( test_pfd(&pfd, NULL), "Simple pfd failed\n" ); + ok( test_pfd(&pfd, &ret_fmt), "Simple pfd failed\n" ); + ok( ret_fmt.cColorBits == 32, "Got %u.\n", ret_fmt.cColorBits ); + ok( !ret_fmt.cBlueShift, "Got %u.\n", ret_fmt.cBlueShift ); + ok( ret_fmt.cBlueBits == 8, "Got %u.\n", ret_fmt.cBlueBits ); + ok( ret_fmt.cRedBits == 8, "Got %u.\n", ret_fmt.cRedBits ); + ok( ret_fmt.cGreenBits == 8, "Got %u.\n", ret_fmt.cGreenBits ); + ok( ret_fmt.cGreenShift == 8, "Got %u.\n", ret_fmt.cGreenShift ); + ok( ret_fmt.cRedShift == 16, "Got %u.\n", ret_fmt.cRedShift ); + ok( !ret_fmt.cAlphaBits || ret_fmt.cAlphaBits == 8, "Got %u.\n", ret_fmt.cAlphaBits ); + if (ret_fmt.cAlphaBits) + ok( ret_fmt.cAlphaShift == 24, "Got %u.\n", ret_fmt.cAlphaShift ); + else + ok( !ret_fmt.cAlphaShift, "Got %u.\n", ret_fmt.cAlphaShift ); + pfd.dwFlags |= PFD_DOUBLEBUFFER_DONTCARE; ok( test_pfd(&pfd, NULL), "PFD_DOUBLEBUFFER_DONTCARE failed\n" ); pfd.dwFlags |= PFD_STEREO_DONTCARE; diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 0cd9218fce1..83af8a52dd6 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1814,14 +1814,17 @@ static int describe_pixel_format( int iPixelFormat, PIXELFORMATDESCRIPTOR *ppfd, pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_BLUE_SIZE, &bb); pglXGetFBConfigAttrib(gdi_display, fmt->fbconfig, GLX_ALPHA_SIZE, &ab); - ppfd->cRedBits = rb; - ppfd->cRedShift = gb + bb + ab; ppfd->cBlueBits = bb; - ppfd->cBlueShift = ab; + ppfd->cBlueShift = 0; ppfd->cGreenBits = gb; - ppfd->cGreenShift = bb + ab; + ppfd->cGreenShift = bb; + ppfd->cRedBits = rb; + ppfd->cRedShift = gb + bb; ppfd->cAlphaBits = ab; - ppfd->cAlphaShift = 0; + if (ab) + ppfd->cAlphaShift = rb + gb + bb; + else + ppfd->cAlphaShift = 0; } else { ppfd->cRedBits = 0; ppfd->cRedShift = 0; From 583c458a6ada5d3ddb7401e2f46a3d334bdc4b73 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 10 Apr 2023 20:27:49 -0600 Subject: [PATCH 1235/2777] setupapi: Don't use NULL as key value in get_device_property(). CW-Bug-Id: #22126 --- dlls/setupapi/devinst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index fa7b91e3884..93d7c849ee5 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -4452,7 +4452,7 @@ static LSTATUS get_device_property(struct device *device, const DEVPROPKEY *prop if (!ls) { value_size = prop_buff_size; - ls = RegQueryValueExW(hkey, NULL, NULL, &value_type, prop_buff, &value_size); + ls = RegQueryValueExW(hkey, L"", NULL, &value_type, prop_buff, &value_size); RegCloseKey(hkey); } From 0b45b1015c334a72be559fe7b8c678a3c52868d5 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 10 Apr 2023 20:28:51 -0600 Subject: [PATCH 1236/2777] combase: Don't use NULL as key value in get_object_dll_path(). CW-Bug-Id: #22126 --- dlls/combase/apartment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/combase/apartment.c b/dlls/combase/apartment.c index b951486ee82..eb63fea6ef8 100644 --- a/dlls/combase/apartment.c +++ b/dlls/combase/apartment.c @@ -721,7 +721,7 @@ static BOOL get_object_dll_path(const struct class_reg_data *regdata, WCHAR *dst WCHAR src[MAX_PATH]; DWORD dwLength = dstlen * sizeof(WCHAR); - if ((ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS) + if ((ret = RegQueryValueExW(regdata->u.hkey, L"", NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS) { if (keytype == REG_EXPAND_SZ) { From ae5e8d7a7b62e466e3b68816f3cc6026cbb49db9 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 10 Apr 2023 20:30:22 -0600 Subject: [PATCH 1237/2777] shell32: Don't use NULL as key value in ShellExecute_GetClassKey(). CW-Bug-Id: #22126 --- dlls/shell32/shlexec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index da2b5fdc2b0..411d0c691a3 100644 --- a/dlls/shell32/shlexec.c +++ b/dlls/shell32/shlexec.c @@ -1109,13 +1109,13 @@ static HKEY ShellExecute_GetClassKey( const SHELLEXECUTEINFOW *sei ) if (r != ERROR_SUCCESS ) return hkey; - r = RegQueryValueExW( hkey, NULL, 0, &type, NULL, &sz ); + r = RegQueryValueExW( hkey, L"", 0, &type, NULL, &sz ); if ( r == ERROR_SUCCESS && type == REG_SZ ) { sz += sizeof (WCHAR); cls = heap_alloc( sz ); cls[0] = 0; - RegQueryValueExW( hkey, NULL, 0, &type, (LPBYTE) cls, &sz ); + RegQueryValueExW( hkey, L"", 0, &type, (LPBYTE) cls, &sz ); } RegCloseKey( hkey ); From 1a26651dd420609cb90d2939816d339761cb13eb Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 10 Apr 2023 20:35:46 -0600 Subject: [PATCH 1238/2777] fixup! ntdll: HACK: Add WINE_HEAP_DELAY_FREE variable to force the use of pending free buffer. CW-Bug-Id: #22126 --- dlls/ntdll/loader.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 1aea4fdcb94..8012eee2afd 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -212,6 +212,21 @@ static inline BOOL contains_path( LPCWSTR name ) return ((*name && (name[1] == ':')) || wcschr(name, '/') || wcschr(name, '\\')); } +static BOOL get_env( const WCHAR *var, WCHAR *val, unsigned int len ) +{ + UNICODE_STRING name, value; + + name.Length = wcslen( var ) * sizeof(WCHAR); + name.MaximumLength = name.Length + sizeof(WCHAR); + name.Buffer = (WCHAR *)var; + + value.Length = 0; + value.MaximumLength = len; + value.Buffer = val; + + return !RtlQueryEnvironmentVariable_U( NULL, &name, &value ); +} + #define RTL_UNLOAD_EVENT_TRACE_NUMBER 64 typedef struct _RTL_UNLOAD_EVENT_TRACE @@ -3105,21 +3120,6 @@ static WCHAR *strstriW( const WCHAR *str, const WCHAR *sub ) return NULL; } -static BOOL get_env( const WCHAR *var, WCHAR *val, unsigned int len ) -{ - UNICODE_STRING name, value; - - name.Length = wcslen( var ) * sizeof(WCHAR); - name.MaximumLength = name.Length + sizeof(WCHAR); - name.Buffer = (WCHAR *)var; - - value.Length = 0; - value.MaximumLength = len; - value.Buffer = val; - - return !RtlQueryEnvironmentVariable_U( NULL, &name, &value ); -} - /*********************************************************************** * find_dll_file * From 8b4e2280274961cc7f341ee94cb910d8c135e9e3 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 10 Apr 2023 21:07:10 -0600 Subject: [PATCH 1239/2777] ntdll: Add PROTON_DISABLE_LSTEAMCLIENT config option. CW-Bug-Id: #22126 --- dlls/ntdll/loader.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 8012eee2afd..9bd07a9bec7 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -2125,6 +2125,18 @@ static NTSTATUS perform_relocations( void *module, IMAGE_NT_HEADERS *nt, SIZE_T return STATUS_SUCCESS; } +static int use_lsteamclient(void) +{ + WCHAR env[32]; + static int use = -1; + + if (use != -1) return use; + + use = !get_env( L"PROTON_DISABLE_LSTEAMCLIENT", env, sizeof(env) ) || *env == '0'; + if (!use) + ERR("lsteamclient disabled.\n"); + return use; +} /************************************************************************* * build_module @@ -2172,7 +2184,7 @@ static NTSTATUS build_module( LPCWSTR load_path, const UNICODE_STRING *nt_name, basename_len = wcslen(basename); if (basename_len >= 4 && !wcscmp(basename + basename_len - 4, L".dll")) basename_len -= 4; - if ((!RtlCompareUnicodeStrings(basename, basename_len, L"steamclient", 11, TRUE) || + if (use_lsteamclient() && (!RtlCompareUnicodeStrings(basename, basename_len, L"steamclient", 11, TRUE) || !RtlCompareUnicodeStrings(basename, basename_len, L"steamclient64", 13, TRUE) || !RtlCompareUnicodeStrings(basename, basename_len, L"gameoverlayrenderer", 19, TRUE) || !RtlCompareUnicodeStrings(basename, basename_len, L"gameoverlayrenderer64", 21, TRUE)) && From 903e12125f7837e517a2fa70b6513657cd22c733 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Tue, 18 Apr 2023 12:14:07 +0200 Subject: [PATCH 1240/2777] twinapi.appcore: Use a regular directory for DLL. Directory is now dlls/twinapi.appcore/ (instead of dlls/twinapi.appcore.dll/). (cherry picked from commit 54ad442cd13c20ab0fccab2afdf3a3bdd1427d94) --- configure.ac | 2 +- dlls/{twinapi.appcore.dll => twinapi.appcore}/Makefile.in | 0 dlls/{twinapi.appcore.dll => twinapi.appcore}/classes.idl | 0 dlls/{twinapi.appcore.dll => twinapi.appcore}/main.c | 0 .../twinapi.appcore.spec | 0 5 files changed, 1 insertion(+), 1 deletion(-) rename dlls/{twinapi.appcore.dll => twinapi.appcore}/Makefile.in (100%) rename dlls/{twinapi.appcore.dll => twinapi.appcore}/classes.idl (100%) rename dlls/{twinapi.appcore.dll => twinapi.appcore}/main.c (100%) rename dlls/{twinapi.appcore.dll => twinapi.appcore}/twinapi.appcore.spec (100%) diff --git a/configure.ac b/configure.ac index 867bfe92897..91ac8a9485f 100644 --- a/configure.ac +++ b/configure.ac @@ -3092,7 +3092,7 @@ WINE_CONFIG_MAKEFILE(dlls/twain.dll16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/twain_32) WINE_CONFIG_MAKEFILE(dlls/twain_32/tests) WINE_CONFIG_MAKEFILE(dlls/typelib.dll16,enable_win16) -WINE_CONFIG_MAKEFILE(dlls/twinapi.appcore.dll) +WINE_CONFIG_MAKEFILE(dlls/twinapi.appcore) WINE_CONFIG_MAKEFILE(dlls/tzres) WINE_CONFIG_MAKEFILE(dlls/ucrtbase) WINE_CONFIG_MAKEFILE(dlls/ucrtbase/tests) diff --git a/dlls/twinapi.appcore.dll/Makefile.in b/dlls/twinapi.appcore/Makefile.in similarity index 100% rename from dlls/twinapi.appcore.dll/Makefile.in rename to dlls/twinapi.appcore/Makefile.in diff --git a/dlls/twinapi.appcore.dll/classes.idl b/dlls/twinapi.appcore/classes.idl similarity index 100% rename from dlls/twinapi.appcore.dll/classes.idl rename to dlls/twinapi.appcore/classes.idl diff --git a/dlls/twinapi.appcore.dll/main.c b/dlls/twinapi.appcore/main.c similarity index 100% rename from dlls/twinapi.appcore.dll/main.c rename to dlls/twinapi.appcore/main.c diff --git a/dlls/twinapi.appcore.dll/twinapi.appcore.spec b/dlls/twinapi.appcore/twinapi.appcore.spec similarity index 100% rename from dlls/twinapi.appcore.dll/twinapi.appcore.spec rename to dlls/twinapi.appcore/twinapi.appcore.spec From a5d4ec469141925adfcb21f4f2128233772811f0 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Tue, 18 Apr 2023 12:14:07 +0200 Subject: [PATCH 1241/2777] twinapi.appcore: Flesh out the .spec file. (cherry picked from commit 89feff4dbf73415d5da3a7c7149dc9f108414ad6) --- dlls/twinapi.appcore/twinapi.appcore.spec | 138 ++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/dlls/twinapi.appcore/twinapi.appcore.spec b/dlls/twinapi.appcore/twinapi.appcore.spec index 721493229c2..7396410d10e 100644 --- a/dlls/twinapi.appcore/twinapi.appcore.spec +++ b/dlls/twinapi.appcore/twinapi.appcore.spec @@ -1,3 +1,141 @@ 1 stdcall -private DllCanUnloadNow() 2 stdcall -private DllGetActivationFactory(ptr ptr) 3 stdcall -private DllGetClassObject(ptr ptr ptr) +4 stub @ +5 stub @ +6 stub @ +7 stub @ +8 stub @ +9 stub @ +10 stub @ +11 stub @ +12 stub @ +13 stub @ +@ stub ValidateSystemShutdown +@ stub BiActivateWorkItemForUser +@ stub BiChangeApplicationStateForPackageName +@ stub BiChangeApplicationStateForPackageNameForUser +@ stub BiChangeApplicationStateForPsmKey +@ stub BiChangeApplicationStateForPsmKeyForUser +@ stub BiChangeSessionState +@ stub BiChangeUserState +@ stub BiEnumerateWorkItemsForPackageNameAndUser +@ stub BiGetActiveBackgroundTasksEvent +@ stub BiGetActiveBackgroundTasksEventForUser +@ stub BiGetCancellationTimeoutInMs +@ stub BiIsApplicationTerminateSensitive +@ stub BiIsApplicationTerminateSensitiveForUser +@ stub BiNotifyNewSession +@ stub BiNotifyNewSessionComplete +@ stub BiNotifyNewUser +@ stub BiPlmFreeMemory +@ stub BiPtActivateDeferredWorkItem +@ stub BiPtActivateInBackground +@ stub BiPtActivateInBackgroundEx +@ stub BiPtActivateWorkItem +@ stub BiPtAssociateActivationProxy +@ stub BiPtAssociateApplicationEntryPoint +@ stub BiPtAssociateApplicationExtensionClass +@ stub BiPtCancelWorkItem +@ stub BiPtCancelWorkItemEx +@ stub BiPtCreateEvent +@ stub BiPtCreateEventForApp +@ stub BiPtCreateEventForPackageName +@ stub BiPtDeleteEvent +@ stub BiPtDisableWorkItem +@ stub BiPtDisassociateWorkItem +@ stub BiPtDisassociateWorkItemEx +@ stub BiPtEnableWorkItem +@ stub BiPtEnumerateBrokeredEvents +@ stub BiPtEnumerateBrokeredEventsEx +@ stub BiPtEnumerateWorkItemsForPackageName +@ stub BiPtEnumerateWorkItemsForPackageNameEx +@ stub BiPtFreeMemory +@ stub BiPtGetStatusStateNameFromBrokerEventId +@ stub BiPtQueryBrokerEventId +@ stub BiPtQueryBrokeredEvent +@ stub BiPtQuerySystemStateBroadcastChannels +@ stub BiPtQueryWorkItem +@ stub BiPtQueryWorkItemEx +@ stub BiPtQueryWorkItemStatusStateName +@ stub BiPtSignalEvent +@ stub BiPtSignalEventEx +@ stub BiPtSignalMultipleEvents +@ stub BiPtSignalTriggerEvent +@ stub BiPtSignalTriggerEventEx +@ stub BiQueryWorkItemForUser +@ stub BiResetActiveSessionForPackage +@ stub BiResetActiveUserForPackage +@ stub BiSetActiveSessionForPackage +@ stub BiSetActiveUserForPackage +@ stub BiTerminateApplicationHost +@ stub BiTerminateApplicationHost2 +@ stub BiTerminateApplicationHostForUser +@ stub BiUpdateBackgroundAccessApplicationsForUser +@ stub BiUpdateLockScreenApplications +@ stub PsmApplyTaskCompletion +@ stub PsmBlockAppStateChangeCompletion +@ stub PsmDisconnect +@ stub PsmGetSessionInfo +@ stub PsmInitializeExtension +@ stub PsmIsProcessInApplication +@ stub PsmIsProcessInApplication2 +@ stub PsmQueryApplicationInformation +@ stub PsmQueryApplicationInformation2 +@ stub PsmQueryApplicationInterferenceCount +@ stub PsmQueryApplicationInterferenceCount2 +@ stub PsmQueryApplicationList +@ stub PsmQueryApplicationList2 +@ stub PsmQueryApplicationProperties +@ stub PsmQueryApplicationProperties2 +@ stub PsmQueryApplicationProperties3 +@ stub PsmQueryApplicationPropertiesByUser +@ stub PsmQueryApplicationResourceUsage +@ stub PsmQueryApplicationResourceUsage2 +@ stub PsmQueryApplicationResourceUsageForTimer +@ stub PsmQueryCurrentAppState +@ stub PsmQueryMaxMemoryUsage +@ stub PsmQueryMaxMemoryUsage2 +@ stub PsmQueryMemoryUsage +@ stub PsmQueryMemoryUsage2 +@ stub PsmQueryMemoryUsageByUser +@ stub PsmQueryProcessList +@ stub PsmQueryProcessList2 +@ stub PsmQuerySharedCommitByUser +@ stub PsmQueryTaskCompletionInformation +@ stub PsmQueryTaskCompletionInformation2 +@ stub PsmRegisterAppPriorityNotification +@ stub PsmRegisterAppStateChangeNotification +@ stub PsmRegisterApplicationNotification +@ stub PsmRegisterApplicationNotification2 +@ stub PsmRegisterDynamicProcess +@ stub PsmRegisterKeyNotification +@ stub PsmRegisterManagerType +@ stub PsmResetMaxMemoryUsage +@ stub PsmResetMaxMemoryUsage2 +@ stub PsmResetMaxMemoryUsageByUser +@ stub PsmSetApplicationPriority +@ stub PsmSetApplicationPriority2 +@ stub PsmSetApplicationProperties +@ stub PsmSetApplicationProperties2 +@ stub PsmSetApplicationProperties3 +@ stub PsmSetApplicationPropertiesByUser +@ stub PsmSetApplicationState +@ stub PsmSetApplicationState2 +@ stub PsmShutdownApplication +@ stub PsmTimerCleanup +@ stub PsmTimerElapsedResourceTimeGet +@ stub PsmTimerInitialize +@ stub PsmTimerRemainingResourceTimeGet +@ stub PsmTimerStart +@ stub PsmUnblockAppStateChangeCompletion +@ stub PsmUnregisterAppStateChangeNotification +@ stub PsmWaitForAppResume +@ stub RegisterAppConstrainedChangeNotification +@ stub RegisterAppStateChangeNotification +@ stub TryGetTitleBarIslandId +@ stub TryGetTitleBarIslandSelectedHost +@ stub UnregisterAppConstrainedChangeNotification +@ stub UnregisterAppStateChangeNotification +500 stub @ +505 stub @ From 922573f01c622660c86e97540347e5b0fc26fdc5 Mon Sep 17 00:00:00 2001 From: Mohamad Al-Jaf Date: Tue, 18 Apr 2023 14:03:09 -0400 Subject: [PATCH 1242/2777] include: Add appnotify.h file. (cherry picked from commit 4ce24eb9be5c7f2896a91d1d554b20f2b8266d3f) (cherry picked from commit b7fdef03f944c85e66b9d7ccfde4a004bf48dc99) --- include/Makefile.in | 1 + include/appnotify.h | 49 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 include/appnotify.h diff --git a/include/Makefile.in b/include/Makefile.in index 3a06dbcabe4..71b2ad01ab8 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -19,6 +19,7 @@ SOURCES = \ appcompatapi.h \ appmgmt.h \ appmodel.h \ + appnotify.h \ asferr.h \ asptlb.idl \ asyncinfo.idl \ diff --git a/include/appnotify.h b/include/appnotify.h new file mode 100644 index 00000000000..882b0342afb --- /dev/null +++ b/include/appnotify.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 Mohamad Al-Jaf + * + * 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 + */ + +#ifndef _WINE_APISET_PSMAPPNOTIFY_H_ +#define _WINE_APISET_PSMAPPNOTIFY_H_ + +#include + +#ifdef _CONTRACT_GEN +#define PSM_APP_API_HOST +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(PSM_APP_API_HOST) +#define APICONTRACT +#else +#define APICONTRACT DECLSPEC_IMPORT +#endif + +typedef void (__cdecl *PAPPSTATE_CHANGE_ROUTINE)(BOOLEAN quiesced, void *context); + +typedef struct _APPSTATE_REGISTRATION *PAPPSTATE_REGISTRATION; + +APICONTRACT ULONG NTAPI RegisterAppStateChangeNotification(PAPPSTATE_CHANGE_ROUTINE,void *,PAPPSTATE_REGISTRATION *); +APICONTRACT void NTAPI UnregisterAppStateChangeNotification(PAPPSTATE_REGISTRATION); + +#ifdef __cplusplus +} +#endif + +#endif /* _WINE_APISET_PSMAPPNOTIFY_H_ */ From 2a6bf124cd18da33ff3c85e03f96e57af5ddad25 Mon Sep 17 00:00:00 2001 From: Mohamad Al-Jaf Date: Tue, 18 Apr 2023 14:16:51 -0400 Subject: [PATCH 1243/2777] apisetschema: Add api-ms-win-core-psm-appnotify-l1-1-0. Needed for Minecraft Legends. (cherry picked from commit 041a7990a356d22bfb1186b4184f67c04b477df1) (cherry picked from commit a76db6ffc85c4d8ae073d23aaa096b6c9d1c53f2) --- dlls/apisetschema/apisetschema.spec | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/apisetschema/apisetschema.spec b/dlls/apisetschema/apisetschema.spec index cb22c25c054..58ce3e92f57 100644 --- a/dlls/apisetschema/apisetschema.spec +++ b/dlls/apisetschema/apisetschema.spec @@ -99,6 +99,7 @@ apiset api-ms-win-core-psapi-ansi-l1-1-0 = kernelbase.dll apiset api-ms-win-core-psapi-l1-1-0 = kernelbase.dll apiset api-ms-win-core-psapi-obsolete-l1-1-0 = kernelbase.dll apiset api-ms-win-core-psapiansi-l1-1-0 = kernelbase.dll +apiset api-ms-win-core-psm-appnotify-l1-1-0 = twinapi.appcore.dll apiset api-ms-win-core-psm-key-l1-1-1 = kernelbase.dll apiset api-ms-win-core-quirks-l1-1-0 = kernelbase.dll apiset api-ms-win-core-realtime-l1-1-0 = kernelbase.dll From 81ef089b1f5686c15651ad940d47e005a4bfea7a Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Fri, 28 Apr 2023 11:15:34 +0200 Subject: [PATCH 1244/2777] twinapi.appcore: Add stubs for (Un)RegisterAppStateChangeNotification. (cherry picked from commit 1a4b05b9f15e4ca56e13eecc3742fea51cb5097b) --- dlls/twinapi.appcore/Makefile.in | 2 +- dlls/twinapi.appcore/main.c | 18 ++++++++++++++++++ dlls/twinapi.appcore/twinapi.appcore.spec | 4 ++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/dlls/twinapi.appcore/Makefile.in b/dlls/twinapi.appcore/Makefile.in index 1f7b969fe80..b9328fa9753 100644 --- a/dlls/twinapi.appcore/Makefile.in +++ b/dlls/twinapi.appcore/Makefile.in @@ -1,4 +1,4 @@ -EXTRADEFS = -DWINE_NO_LONG_TYPES +EXTRADEFS = -DWINE_NO_LONG_TYPES -D_CONTRACT_GEN MODULE = twinapi.appcore.dll IMPORTS = combase diff --git a/dlls/twinapi.appcore/main.c b/dlls/twinapi.appcore/main.c index 7a85e476e65..ff85d4d5557 100644 --- a/dlls/twinapi.appcore/main.c +++ b/dlls/twinapi.appcore/main.c @@ -27,6 +27,7 @@ #include "objbase.h" #include "activation.h" +#include "appnotify.h" #define WIDL_using_Windows_Foundation #define WIDL_using_Windows_Foundation_Collections @@ -283,3 +284,20 @@ HRESULT WINAPI DllGetActivationFactory(HSTRING classid, IActivationFactory **fac IUnknown_AddRef(*factory); return S_OK; } + +ULONG WINAPI RegisterAppStateChangeNotification(PAPPSTATE_CHANGE_ROUTINE routine, + PVOID context, + PAPPSTATE_REGISTRATION* registration) +{ + FIXME("routine %p, context %p, registration %p: stub.\n", routine, context, registration); + + if (!registration) return E_INVALIDARG; + /* Just pretend success */ + *registration = (void*)(DWORD_PTR)0x0baddad0; + return S_OK; +} + +void WINAPI UnregisterAppStateChangeNotification(PAPPSTATE_REGISTRATION registration) +{ + FIXME("registration %p: stub.\n", registration); +} diff --git a/dlls/twinapi.appcore/twinapi.appcore.spec b/dlls/twinapi.appcore/twinapi.appcore.spec index 7396410d10e..1f81bd82d49 100644 --- a/dlls/twinapi.appcore/twinapi.appcore.spec +++ b/dlls/twinapi.appcore/twinapi.appcore.spec @@ -132,10 +132,10 @@ @ stub PsmUnregisterAppStateChangeNotification @ stub PsmWaitForAppResume @ stub RegisterAppConstrainedChangeNotification -@ stub RegisterAppStateChangeNotification +@ stdcall RegisterAppStateChangeNotification(ptr ptr ptr) @ stub TryGetTitleBarIslandId @ stub TryGetTitleBarIslandSelectedHost @ stub UnregisterAppConstrainedChangeNotification -@ stub UnregisterAppStateChangeNotification +@ stdcall UnregisterAppStateChangeNotification(ptr) 500 stub @ 505 stub @ From 72ace14335ea9d7f2a79254db8e953c871c8f8a9 Mon Sep 17 00:00:00 2001 From: LeonTheo02 <57302337+LeonTheo02@users.noreply.github.com> Date: Thu, 23 Feb 2023 13:32:14 +0100 Subject: [PATCH 1245/2777] dxdiag: Return DirectX 12 values Changed the values DxDiag returns to reflect values taken from a modern DirectX 12 capable system via Windows DxDiag. This will allow games that check these values to detect the DirectX Version correctly. Fixes DX11 Open Beta of RAID : World War II. Link: https://github.com/ValveSoftware/wine/pull/178 --- dlls/dxdiagn/provider.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/dxdiagn/provider.c b/dlls/dxdiagn/provider.c index ed59f84bef2..df53370d97a 100644 --- a/dlls/dxdiagn/provider.c +++ b/dlls/dxdiagn/provider.c @@ -614,7 +614,7 @@ static HRESULT build_systeminfo_tree(IDxDiagContainerImpl_Container *node) WCHAR buffer[MAX_PATH], computer_name[MAX_COMPUTERNAME_LENGTH + 1], print_buf[200], localized_pagefile_fmt[200]; DWORD_PTR args[2]; - hr = add_ui4_property(node, L"dwDirectXVersionMajor", 9); + hr = add_ui4_property(node, L"dwDirectXVersionMajor", 12); if (FAILED(hr)) return hr; @@ -622,15 +622,15 @@ static HRESULT build_systeminfo_tree(IDxDiagContainerImpl_Container *node) if (FAILED(hr)) return hr; - hr = add_bstr_property(node, L"szDirectXVersionLetter", L"c"); + hr = add_bstr_property(node, L"szDirectXVersionLetter", L" "); if (FAILED(hr)) return hr; - hr = add_bstr_property(node, L"szDirectXVersionEnglish", L"4.09.0000.0904"); + hr = add_bstr_property(node, L"szDirectXVersionEnglish", L""); if (FAILED(hr)) return hr; - hr = add_bstr_property(node, L"szDirectXVersionLongEnglish", L"= \"DirectX 9.0c (4.09.0000.0904)"); + hr = add_bstr_property(node, L"szDirectXVersionLongEnglish", L"DirectX 12"); if (FAILED(hr)) return hr; From 5f72d8e7112c4a901f97ae639ee2636bfaf7ff45 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 7 Mar 2023 09:01:39 -0600 Subject: [PATCH 1246/2777] kernelbase: HACK: Force Angle GL instead of Swiftshader for Paradox Launcher. CW-Bug-Id: #21997 --- dlls/kernelbase/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index bd3a790c062..c05157e38cc 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -600,7 +600,7 @@ static const WCHAR *hack_append_command_line( const WCHAR *cmd ) options[] = { {L"UplayWebCore.exe", L" --use-angle=gl"}, - {L"Paradox Launcher.exe", L" --use-gl=swiftshader --in-process-gpu"}, + {L"Paradox Launcher.exe", L" --use-angle=gl"}, {L"Montaro\\nw.exe", L" --use-gl=swiftshader"}, {L"\\EOSOverlayRenderer-Win64-Shipping.exe", L" --use-gl=swiftshader --in-process-gpu"}, {L"\\EpicOnlineServicesUIHelper", L" --use-gl=desktop"}, From 22743b6bd4b7a9af0ce924d2931acf401e8d9564 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 5 Apr 2023 11:31:10 -0600 Subject: [PATCH 1247/2777] kernelbase: HACK: Add --use-gl=swiftshader for DC Universe Online/LaunchPad.exe. CW-Bug-Id: #22083 --- dlls/kernelbase/process.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index c05157e38cc..342f138dcc8 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -606,6 +606,7 @@ static const WCHAR *hack_append_command_line( const WCHAR *cmd ) {L"\\EpicOnlineServicesUIHelper", L" --use-gl=desktop"}, {L"OlympiaRising.exe", L" --use-gl=swiftshader"}, {L"nw.exe.exe", L" --use-angle=d3d9"}, + {L"DC Universe Online\\LaunchPad.exe", L" --use-gl=swiftshader"}, }; unsigned int i; From 39bcc4ca5757796db0e729d0e82df5fad4009845 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 5 Apr 2023 11:33:40 -0600 Subject: [PATCH 1248/2777] kernelbase: HACK: Add --use-gl=swiftshader for Planetside 2/LaunchPad.exe. CW-Bug-Id: #22083 --- dlls/kernelbase/process.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 342f138dcc8..fe3818aed59 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -607,6 +607,7 @@ static const WCHAR *hack_append_command_line( const WCHAR *cmd ) {L"OlympiaRising.exe", L" --use-gl=swiftshader"}, {L"nw.exe.exe", L" --use-angle=d3d9"}, {L"DC Universe Online\\LaunchPad.exe", L" --use-gl=swiftshader"}, + {L"PlanetSide 2\\LaunchPad.exe", L" --use-gl=swiftshader"}, }; unsigned int i; From 4fcf69285710c61207ae1d007cd2130e767b388e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 12 Apr 2023 18:25:03 -0600 Subject: [PATCH 1249/2777] kernelbase: Remove command line fixup code from battleye_launcher_redirect_hack(). CW-Bug-Id: #22133 --- dlls/kernelbase/process.c | 45 ++++++--------------------------------- 1 file changed, 7 insertions(+), 38 deletions(-) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index fe3818aed59..3ada1cfd9d9 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -544,49 +544,23 @@ static BOOL product_name_matches(const WCHAR *app_name, const char *match) return TRUE; } -static int battleye_launcher_redirect_hack(const WCHAR *app_name, WCHAR *new_name, DWORD new_name_len, WCHAR **cmd_line) +static int battleye_launcher_redirect_hack( const WCHAR *app_name, WCHAR *new_name, DWORD new_name_len ) { static const WCHAR belauncherW[] = L"c:\\windows\\system32\\belauncher.exe"; - WCHAR *new_cmd_line; - WCHAR *p; /* We detect the BattlEye launcher executable through the product name property, as the executable name varies */ - if (!product_name_matches(app_name, "BattlEye Launcher")) + if (!product_name_matches( app_name, "BattlEye Launcher" )) return 0; - TRACE("Detected launch of a BattlEye Launcher, redirecting to Proton version.\n"); + TRACE( "Detected launch of a BattlEye Launcher, redirecting to Proton version.\n" ); - if (new_name_len < wcslen(belauncherW) + 1) + if (new_name_len < wcslen( belauncherW ) + 1) { - WARN("Game executable path doesn't fit in buffer.\n"); + ERR( "Game executable path doesn't fit in buffer.\n" ); return 0; } - wcscpy(new_name, belauncherW); - - /* find and replace executable name in command line, and add BE argument */ - p = *cmd_line; - if (p[0] == '\"') - p++; - - if (!wcsncmp(p, app_name, wcslen(app_name))) - { - new_cmd_line = HeapAlloc( GetProcessHeap(), 0, ( wcslen(*cmd_line) + wcslen(belauncherW) + 1 - wcslen(app_name) ) * sizeof(WCHAR) ); - - wcscpy(new_cmd_line, *cmd_line); - p = new_cmd_line; - if (p[0] == '\"') - p++; - - memmove( p + wcslen(belauncherW), p + wcslen(app_name), (wcslen(p) - wcslen(belauncherW)) * sizeof(WCHAR) ); - memcpy( p, belauncherW, wcslen(belauncherW) * sizeof(WCHAR) ); - - 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; - } - + wcscpy( new_name, belauncherW ); return 1; } @@ -694,13 +668,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR app_name = name; } - p = tidy_cmdline; - if (battleye_launcher_redirect_hack( app_name, name, ARRAY_SIZE(name), &tidy_cmdline )) - { + if (battleye_launcher_redirect_hack( app_name, name, ARRAY_SIZE(name) )) app_name = name; - if (p != tidy_cmdline && p != cmd_line) - HeapFree( GetProcessHeap(), 0, p ); - } /* Warn if unsupported features are used */ From 27719fb336e0aa2fbdc5b228b1a2a3a766d9afe3 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 12 Apr 2023 18:51:15 -0600 Subject: [PATCH 1250/2777] kernelbase: Set PROTON_ORIG_LAUNCHER_NAME when starting builtin BattleEye launcher. CW-Bug-Id: #22133 --- dlls/kernelbase/process.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 3ada1cfd9d9..8e1a729a9ab 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -544,9 +544,11 @@ static BOOL product_name_matches(const WCHAR *app_name, const char *match) return TRUE; } -static int battleye_launcher_redirect_hack( const WCHAR *app_name, WCHAR *new_name, DWORD new_name_len ) +static int battleye_launcher_redirect_hack( const WCHAR *app_name, WCHAR *new_name, DWORD new_name_len, + WCHAR **orig_app_name ) { static const WCHAR belauncherW[] = L"c:\\windows\\system32\\belauncher.exe"; + unsigned int len; /* We detect the BattlEye launcher executable through the product name property, as the executable name varies */ if (!product_name_matches( app_name, "BattlEye Launcher" )) @@ -560,6 +562,13 @@ static int battleye_launcher_redirect_hack( const WCHAR *app_name, WCHAR *new_na return 0; } + len = (wcslen( app_name ) + 1) * sizeof(*app_name); + if (!(*orig_app_name = HeapAlloc( GetProcessHeap(), 0, len ))) + { + ERR( "No memory.\n" ); + return 0; + } + memcpy( *orig_app_name, app_name, len ); wcscpy( new_name, belauncherW ); return 1; } @@ -610,7 +619,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR { const struct proc_thread_attr *handle_list = NULL, *job_list = NULL; WCHAR name[MAX_PATH]; - WCHAR *p, *tidy_cmdline = cmd_line; + WCHAR *p, *tidy_cmdline = cmd_line, *orig_app_name = NULL; RTL_USER_PROCESS_PARAMETERS *params = NULL; RTL_USER_PROCESS_INFORMATION rtl_info; HANDLE parent = 0, debug = 0; @@ -668,7 +677,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR app_name = name; } - if (battleye_launcher_redirect_hack( app_name, name, ARRAY_SIZE(name) )) + if (battleye_launcher_redirect_hack( app_name, name, ARRAY_SIZE(name), &orig_app_name )) app_name = name; /* Warn if unsupported features are used */ @@ -692,6 +701,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR if (!(params = create_process_params( app_name, tidy_cmdline, cur_dir, env, flags, startup_info ))) { + HeapFree( GetProcessHeap(), 0, orig_app_name ); status = STATUS_NO_MEMORY; goto done; } @@ -700,18 +710,25 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR - We don't do this check in ntdll itself because it's harder to get the product name there - we don't overwrite WINEDLLOVERRIDES because it's fetched from the unix environment */ { - UNICODE_STRING is_eac_launcher_us; - UNICODE_STRING one_us; + UNICODE_STRING name, value; WCHAR *new_env = RtlAllocateHeap( GetProcessHeap(), 0, params->EnvironmentSize ); memcpy(new_env, params->Environment, params->EnvironmentSize); RtlDestroyProcessParameters( params ); - RtlInitUnicodeString( &is_eac_launcher_us, L"PROTON_EAC_LAUNCHER_PROCESS" ); - RtlInitUnicodeString( &one_us, L"1" ); - RtlSetEnvironmentVariable( &new_env, &is_eac_launcher_us, product_name_matches(app_name, "EasyAntiCheat Launcher") ? &one_us : NULL ); + RtlInitUnicodeString( &name, L"PROTON_EAC_LAUNCHER_PROCESS" ); + RtlInitUnicodeString( &value, L"1" ); + RtlSetEnvironmentVariable( &new_env, &name, product_name_matches(app_name, "EasyAntiCheat Launcher") ? &value : NULL ); + + if (orig_app_name) + { + RtlInitUnicodeString( &name, L"PROTON_ORIG_LAUNCHER_NAME" ); + RtlInitUnicodeString( &value, orig_app_name ); + RtlSetEnvironmentVariable( &new_env, &name, &value ); + } + HeapFree( GetProcessHeap(), 0, orig_app_name ); params = create_process_params( app_name, tidy_cmdline, cur_dir, new_env, flags | CREATE_UNICODE_ENVIRONMENT, startup_info ); RtlFreeHeap(GetProcessHeap(), 0, new_env); From 327a61e8f8a95dd22255bd3d79e589b40681a45f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 12 Apr 2023 19:42:00 -0600 Subject: [PATCH 1251/2777] belauncher: Use original launcher .exe path to find BELauncher.ini and executable. CW-Bug-Id: #22133 --- programs/belauncher/Makefile.in | 2 +- programs/belauncher/main.c | 54 ++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/programs/belauncher/Makefile.in b/programs/belauncher/Makefile.in index f2dc59b07ce..a5f4891ecc2 100644 --- a/programs/belauncher/Makefile.in +++ b/programs/belauncher/Makefile.in @@ -1,5 +1,5 @@ MODULE = belauncher.exe -IMPORTS = +IMPORTS = shlwapi EXTRADLLFLAGS = -mwindows -municode diff --git a/programs/belauncher/main.c b/programs/belauncher/main.c index 004a7d1a711..a40e7cf8853 100644 --- a/programs/belauncher/main.c +++ b/programs/belauncher/main.c @@ -1,6 +1,7 @@ #define WIN32_LEAN_AND_MEAN #include #include +#include #include "wine/debug.h" @@ -9,9 +10,10 @@ 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; + WCHAR path[MAX_PATH], *p, config_path[MAX_PATH]; LARGE_INTEGER launcher_cfg_size; unsigned char battleye_status; - int game_exe_len, arg_len; + int game_exe_len, arg_len, path_len; PROCESS_INFORMATION pi; HANDLE launcher_cfg; LPWSTR launch_cmd; @@ -22,9 +24,31 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cm 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); + *path = 0; + if ((size = GetEnvironmentVariableW(L"PROTON_ORIG_LAUNCHER_NAME", path, ARRAY_SIZE(path))) && size <= ARRAY_SIZE(path)) + { + WINE_TRACE("PROTON_ORIG_LAUNCHER_NAME %s.\n", wine_dbgstr_w(path)); + + for (p = path + wcslen(path); p != path; --p) + if (*p == '\\') break; + if (*p == '\\') + ++p; + *p = 0; + } + + wcscpy(config_path, path); + wcscat(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) + { + *path = 0; + 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) + { + WINE_ERR("BELauncher.ini not found.\n"); goto start_failed; + } if(!GetFileSizeEx(launcher_cfg, &launcher_cfg_size) || launcher_cfg_size.u.HighPart) { @@ -64,7 +88,7 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cm else { HeapFree( GetProcessHeap(), 0, configs ); - WINE_WARN("Failed to find game executable name from BattlEye config.\n"); + WINE_ERR("Failed to find game executable name from BattlEye config.\n"); goto start_failed; } @@ -88,21 +112,28 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cm 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] = ' '; + if (PathIsRelativeA(game_exe)) + path_len = wcslen(path); + else + path_len = 0; + + launch_cmd = HeapAlloc(GetProcessHeap(), 0, (path_len + game_exe_len + 1 + wcslen(cmdline) + 1 + arg_len + 1) * sizeof(WCHAR)); - wcscpy(launch_cmd + game_exe_len + 1, cmdline); - launch_cmd[game_exe_len + 1 + wcslen(cmdline)] = ' '; + memcpy(launch_cmd, path, path_len * sizeof(*path)); - MultiByteToWideChar(CP_ACP, 0, be_arg, -1, launch_cmd + game_exe_len + 1 + wcslen(cmdline) + 1, arg_len + 1); + MultiByteToWideChar(CP_ACP, 0, game_exe, -1, launch_cmd + path_len, game_exe_len + 1); + launch_cmd[path_len + game_exe_len] = ' '; + + wcscpy(launch_cmd + path_len + game_exe_len + 1, cmdline); + launch_cmd[path_len + game_exe_len + 1 + wcslen(cmdline)] = ' '; + + MultiByteToWideChar(CP_ACP, 0, be_arg, -1, launch_cmd + path_len + 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)) { + WINE_ERR("CreateProcessW failed.\n"); battleye_status = 0xA; /* Launch Failed */ _write(1, &battleye_status, 1); - - HeapFree( GetProcessHeap(), 0, launch_cmd ); return GetLastError(); } HeapFree( GetProcessHeap(), 0, launch_cmd ); @@ -112,6 +143,7 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cm return 0; start_failed: + WINE_ERR("Failed.\n"); battleye_status = 0x4; /* Start Failed */ _write(1, &battleye_status, 1); return 0; From 1d7a6f8e7a11bc24e5956fa22cc75b65003cb969 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 19 Apr 2023 15:32:38 -0600 Subject: [PATCH 1252/2777] belauncher: Null terminate launch_cmd if be_arg is empty. CW-Bug-Id: #22146 --- programs/belauncher/main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/programs/belauncher/main.c b/programs/belauncher/main.c index a40e7cf8853..c8b8ccbf532 100644 --- a/programs/belauncher/main.c +++ b/programs/belauncher/main.c @@ -127,7 +127,13 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cm wcscpy(launch_cmd + path_len + game_exe_len + 1, cmdline); launch_cmd[path_len + game_exe_len + 1 + wcslen(cmdline)] = ' '; - MultiByteToWideChar(CP_ACP, 0, be_arg, -1, launch_cmd + path_len + game_exe_len + 1 + wcslen(cmdline) + 1, arg_len + 1); + + if (!MultiByteToWideChar(CP_ACP, 0, be_arg, -1, launch_cmd + path_len + game_exe_len + 1 + wcslen(cmdline) + 1, arg_len + 1)) + launch_cmd[path_len + game_exe_len + 1 + wcslen(cmdline)] = 0; + + WINE_TRACE("game_exe %s, cmdline %s.\n", wine_dbgstr_a(game_exe), wine_dbgstr_w(cmdline)); + WINE_TRACE("path %s, be_arg %s.\n", wine_dbgstr_w(path), wine_dbgstr_a(be_arg)); + WINE_TRACE("launch_cmd %s.\n", wine_dbgstr_w(launch_cmd)); if (!CreateProcessW(NULL, launch_cmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) { From 0324188518470d1b20c3e2fa237440c379eca866 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 19 Apr 2023 17:00:49 -0600 Subject: [PATCH 1253/2777] belauncher: Support --exe command line option. CW-Bug-Id: #22146 --- programs/belauncher/Makefile.in | 2 +- programs/belauncher/main.c | 61 +++++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/programs/belauncher/Makefile.in b/programs/belauncher/Makefile.in index a5f4891ecc2..0537cfe0f3a 100644 --- a/programs/belauncher/Makefile.in +++ b/programs/belauncher/Makefile.in @@ -1,5 +1,5 @@ MODULE = belauncher.exe -IMPORTS = shlwapi +IMPORTS = shlwapi shcore EXTRADLLFLAGS = -mwindows -municode diff --git a/programs/belauncher/main.c b/programs/belauncher/main.c index c8b8ccbf532..75a2d78871b 100644 --- a/programs/belauncher/main.c +++ b/programs/belauncher/main.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "wine/debug.h" @@ -10,7 +11,7 @@ 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; - WCHAR path[MAX_PATH], *p, config_path[MAX_PATH]; + WCHAR path[MAX_PATH], *p, config_path[MAX_PATH], game_exeW[MAX_PATH], **argvW; LARGE_INTEGER launcher_cfg_size; unsigned char battleye_status; int game_exe_len, arg_len, path_len; @@ -18,6 +19,7 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cm HANDLE launcher_cfg; LPWSTR launch_cmd; STARTUPINFOW si = {0}; + int i, argc; DWORD size; BOOL wow64; @@ -81,22 +83,46 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cm } 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 + *game_exeW = 0; + + if ((argvW = CommandLineToArgvW(cmdline, &argc))) { - HeapFree( GetProcessHeap(), 0, configs ); - WINE_ERR("Failed to find game executable name from BattlEye config.\n"); - goto start_failed; + for (i = 0; i < argc; ++i) + { + if (!wcscmp(argvW[i], L"-exe") && i < argc - 1) + { + wcscpy(game_exeW, argvW[i + 1]); + game_exe_len = wcslen(game_exeW); + break; + } + } } - 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 (!*game_exeW) + { + 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_ERR("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, game_exeW, ARRAY_SIZE(game_exeW)); + if (!game_exe_len) + { + WINE_ERR("Failed to convert game_exe %s.\n", wine_dbgstr_a(game_exe)); + goto start_failed; + } + --game_exe_len; + } if (!be_arg) arg_len = 0; else @@ -112,7 +138,7 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cm battleye_status = 0x9; /* Launching Game */ _write(1, &battleye_status, 1); - if (PathIsRelativeA(game_exe)) + if (PathIsRelativeW(game_exeW)) path_len = wcslen(path); else path_len = 0; @@ -121,17 +147,16 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cm memcpy(launch_cmd, path, path_len * sizeof(*path)); - MultiByteToWideChar(CP_ACP, 0, game_exe, -1, launch_cmd + path_len, game_exe_len + 1); + memcpy(launch_cmd + path_len, game_exeW, game_exe_len * sizeof(*launch_cmd)); launch_cmd[path_len + game_exe_len] = ' '; wcscpy(launch_cmd + path_len + game_exe_len + 1, cmdline); launch_cmd[path_len + game_exe_len + 1 + wcslen(cmdline)] = ' '; - if (!MultiByteToWideChar(CP_ACP, 0, be_arg, -1, launch_cmd + path_len + game_exe_len + 1 + wcslen(cmdline) + 1, arg_len + 1)) launch_cmd[path_len + game_exe_len + 1 + wcslen(cmdline)] = 0; - WINE_TRACE("game_exe %s, cmdline %s.\n", wine_dbgstr_a(game_exe), wine_dbgstr_w(cmdline)); + WINE_TRACE("game_exe %s, cmdline %s.\n", wine_dbgstr_w(game_exeW), wine_dbgstr_w(cmdline)); WINE_TRACE("path %s, be_arg %s.\n", wine_dbgstr_w(path), wine_dbgstr_a(be_arg)); WINE_TRACE("launch_cmd %s.\n", wine_dbgstr_w(launch_cmd)); From 1e56a6edb71c4e50e4d6d7c44f5f90e6bd2c8598 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 14 Apr 2023 20:20:21 -0600 Subject: [PATCH 1254/2777] ntdll: HACK: Enable WINESTEAMNOEXEC for Madballs in Babo: Invasion. CW-Bug-Id: #22137 --- dlls/ntdll/unix/loader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 2b6fac37bb1..d1fda7a6e5a 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2321,7 +2321,7 @@ static void hacks_init(void) ERR("HACK: Simulating sched quantum in NtWaitForAlertByThreadId.\n"); sgi = getenv("SteamGameId"); - if (sgi && (!strcmp(sgi, "50130") || !strcmp(sgi, "202990") || !strcmp(sgi, "212910"))) + if (sgi && (!strcmp(sgi, "50130") || !strcmp(sgi, "202990") || !strcmp(sgi, "212910") || !strcmp(sgi, "25700"))) setenv("WINESTEAMNOEXEC", "1", 0); env_str = getenv("WINE_NO_PRIV_ELEVATION"); From e09857dc47be65ce316dd32029668fd2bab91b4b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 19 Apr 2023 13:22:16 -0600 Subject: [PATCH 1255/2777] amd_ags_x64: Add agsDriverExtensionsDX11_BeginUAVOverlap() stub. CW-Bug-Id: #22146 --- dlls/amd_ags_x64/amd_ags_x64.spec | 2 +- dlls/amd_ags_x64/amd_ags_x64_main.c | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec index ece559ca9d3..876ceee1273 100644 --- a/dlls/amd_ags_x64/amd_ags_x64.spec +++ b/dlls/amd_ags_x64/amd_ags_x64.spec @@ -1,7 +1,7 @@ @ stdcall agsDeInit(ptr) @ stdcall agsDeInitialize(ptr) @ stdcall agsCheckDriverVersion(ptr long) -@ stub agsDriverExtensionsDX11_BeginUAVOverlap +@ stdcall -norelay -arch=win64 agsDriverExtensionsDX11_BeginUAVOverlap() DX11_BeginUAVOverlap_impl @ stub agsDriverExtensionsDX11_CreateBuffer @ stdcall agsDriverExtensionsDX11_CreateDevice(ptr ptr ptr ptr) @ stub agsDriverExtensionsDX11_CreateFromDevice diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 32f618c95dc..b6af95bd2b7 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -833,6 +833,32 @@ __ASM_GLOBAL_FUNC( DX11_SetDepthBounds_impl, "jmp " __ASM_NAME("agsDriverExtensionsDX11_SetDepthBounds") "\n\t" "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_SetDepthBounds_530") ) +AGSReturnCode WINAPI agsDriverExtensionsDX11_BeginUAVOverlap_520(AGSContext *context) +{ + static int once; + + if (!once++) + FIXME("context %p stub.\n", context); + return AGS_EXTENSION_NOT_SUPPORTED; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_BeginUAVOverlap(AGSContext *context, ID3D11DeviceContext *dx_context) +{ + static int once; + + if (!once++) + FIXME("context %p, dx_context %p stub.\n", context, dx_context); + + return AGS_EXTENSION_NOT_SUPPORTED; +} + +__ASM_GLOBAL_FUNC( DX11_BeginUAVOverlap_impl, + "mov (%rcx),%eax\n\t" /* version */ + "cmp $3,%eax\n\t" + "jge 1f\n\t" + "jmp " __ASM_NAME("agsDriverExtensionsDX11_BeginUAVOverlap_520") "\n\t" + "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_BeginUAVOverlap") ) + AGSReturnCode WINAPI agsDriverExtensionsDX11_DestroyDevice_520(AGSContext *context, ID3D11Device* device, unsigned int *device_ref, ID3D11DeviceContext *device_context, unsigned int *context_ref) From 822d111b7d158f5cf367a86f52bb841bcdd1e9b5 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 19 Apr 2023 14:41:04 -0600 Subject: [PATCH 1256/2777] amd_ags_x64: Add agsDriverExtensionsDX11_EndUAVOverlap() stub. CW-Bug-Id: #22146 --- dlls/amd_ags_x64/amd_ags_x64.spec | 2 +- dlls/amd_ags_x64/amd_ags_x64_main.c | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec index 876ceee1273..a825a450cfa 100644 --- a/dlls/amd_ags_x64/amd_ags_x64.spec +++ b/dlls/amd_ags_x64/amd_ags_x64.spec @@ -11,7 +11,7 @@ @ stub agsDriverExtensionsDX11_DeInit @ stub agsDriverExtensionsDX11_Destroy @ stdcall -norelay -arch=win64 agsDriverExtensionsDX11_DestroyDevice() -@ stub agsDriverExtensionsDX11_EndUAVOverlap +@ stdcall -norelay -arch=win64 agsDriverExtensionsDX11_EndUAVOverlap() DX11_EndUAVOverlap_impl @ stub agsDriverExtensionsDX11_GetMaxClipRects @ stub agsDriverExtensionsDX11_IASetPrimitiveTopology @ stdcall agsDriverExtensionsDX11_Init(ptr ptr long ptr) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index b6af95bd2b7..43b72d908ee 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -859,6 +859,32 @@ __ASM_GLOBAL_FUNC( DX11_BeginUAVOverlap_impl, "jmp " __ASM_NAME("agsDriverExtensionsDX11_BeginUAVOverlap_520") "\n\t" "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_BeginUAVOverlap") ) +AGSReturnCode WINAPI agsDriverExtensionsDX11_EndUAVOverlap_520(AGSContext *context) +{ + static int once; + + if (!once++) + FIXME("context %p stub.\n", context); + return AGS_EXTENSION_NOT_SUPPORTED; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_EndUAVOverlap(AGSContext *context, ID3D11DeviceContext *dx_context) +{ + static int once; + + if (!once++) + FIXME("context %p, dx_context %p stub.\n", context, dx_context); + + return AGS_EXTENSION_NOT_SUPPORTED; +} + +__ASM_GLOBAL_FUNC( DX11_EndUAVOverlap_impl, + "mov (%rcx),%eax\n\t" /* version */ + "cmp $3,%eax\n\t" + "jge 1f\n\t" + "jmp " __ASM_NAME("agsDriverExtensionsDX11_EndUAVOverlap_520") "\n\t" + "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_EndUAVOverlap") ) + AGSReturnCode WINAPI agsDriverExtensionsDX11_DestroyDevice_520(AGSContext *context, ID3D11Device* device, unsigned int *device_ref, ID3D11DeviceContext *device_context, unsigned int *context_ref) From 748eca3106b27b869810947a6a0d68b194b22324 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 19 Apr 2023 18:57:04 -0600 Subject: [PATCH 1257/2777] win32u: Partially implement NtUserDisplayConfigGetDeviceInfo(DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE). (cherry picked from commit 24019f0d385c653d58be50f7941256e4e1c8b68a) CW-Bug-Id: #22146 --- dlls/user32/tests/monitor.c | 49 ++++++++++++++++++++- dlls/win32u/sysparams.c | 87 ++++++++++++++++++++++++++++++++++++- 2 files changed, 132 insertions(+), 4 deletions(-) diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c index 1dff85b9621..6b7f7b44b15 100644 --- a/dlls/user32/tests/monitor.c +++ b/dlls/user32/tests/monitor.c @@ -1683,6 +1683,52 @@ static void check_device_path(const WCHAR *device_path, const LUID *adapter_id, SetupDiDestroyDeviceInfoList(set); } +static void check_preferred_mode(const DISPLAYCONFIG_TARGET_PREFERRED_MODE *mode, const WCHAR *gdi_device_name) +{ + DISPLAYCONFIG_TARGET_PREFERRED_MODE mode2; + DEVMODEW dm, dm2; + LONG lret; + BOOL bret; + + dm.dmSize = sizeof(dm); + bret = EnumDisplaySettingsW(gdi_device_name, ENUM_CURRENT_SETTINGS, &dm); + ok(bret, "got error %lu.\n", GetLastError()); + + if (dm.dmPelsWidth == 1024 && dm.dmPelsHeight == 768) + { + skip("Current display mode is already 1024x768, skipping test.\n"); + return; + } + if (mode->width == 1024 && mode->height == 768) + { + skip("Preferred display mode is 1024x768, skipping test.\n"); + return; + } + + memset(&dm2, 0, sizeof(dm2)); + dm2.dmSize = sizeof(dm2); + dm2.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; + dm2.dmPelsWidth = 1024; + dm2.dmPelsHeight = 768; + lret = ChangeDisplaySettingsW(&dm2, 0); + if (lret != DISP_CHANGE_SUCCESSFUL) + { + skip("Can't change display settings, skipping test.\n"); + return; + } + + memset(&mode2, 0, sizeof(mode2)); + mode2.header = mode->header; + + lret = pDisplayConfigGetDeviceInfo(&mode2.header); + ok(!lret, "got %ld\n", lret); + ok(mode2.width == mode->width, "got %u, expected %u.\n", mode2.width, mode->width); + ok(mode2.height == mode->height, "got %u, expected %u.\n", mode2.height, mode->height); + + lret = ChangeDisplaySettingsW(&dm, 0); + ok(lret == DISP_CHANGE_SUCCESSFUL, "got %ld.\n", lret); +} + static void test_QueryDisplayConfig_result(UINT32 flags, UINT32 paths, const DISPLAYCONFIG_PATH_INFO *pi, UINT32 modes, const DISPLAYCONFIG_MODE_INFO *mi) { @@ -1722,7 +1768,6 @@ static void test_QueryDisplayConfig_result(UINT32 flags, ok(!ret, "Expected 0, got %ld\n", ret); check_device_path(target_name.monitorDevicePath, &target_name.header.adapterId, target_name.header.id); - todo_wine { preferred_mode.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE; preferred_mode.header.size = sizeof(preferred_mode); preferred_mode.header.adapterId = pi[i].targetInfo.adapterId; @@ -1732,7 +1777,7 @@ static void test_QueryDisplayConfig_result(UINT32 flags, ok(!ret, "Expected 0, got %ld\n", ret); ok(preferred_mode.width > 0 && preferred_mode.height > 0, "Expected non-zero height/width, got %ux%u\n", preferred_mode.width, preferred_mode.height); - } + check_preferred_mode(&preferred_mode, source_name.viewGdiDeviceName); todo_wine { adapter_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME; diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index dfbfc9009b5..826a9927e03 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -33,6 +33,7 @@ #include "ntuser_private.h" #include "devpropdef.h" #include "cfgmgr32.h" +#include "d3dkmdt.h" #include "wine/wingdi16.h" #include "wine/server.h" @@ -246,6 +247,7 @@ struct adapter #define MONITOR_INFO_HAS_MONITOR_ID 0x00000001 #define MONITOR_INFO_HAS_MONITOR_NAME 0x00000002 +#define MONITOR_INFO_HAS_PREFERRED_MODE 0x00000004 struct edid_monitor_info { unsigned int flags; @@ -254,6 +256,8 @@ struct edid_monitor_info char monitor_id_string[8]; /* MONITOR_INFO_HAS_MONITOR_NAME */ WCHAR monitor_name[14]; + /* MONITOR_INFO_HAS_PREFERRED_MODE */ + unsigned int preferred_width, preferred_height; }; struct monitor @@ -505,6 +509,16 @@ static void get_monitor_info_from_edid( struct edid_monitor_info *info, const un for (i = 0; i < 4; ++i) { + if (edid[54 + i * 18] || edid[54 + i * 18 + 1]) + { + /* Detailed timing descriptor. */ + if (info->flags & MONITOR_INFO_HAS_PREFERRED_MODE) continue; + info->preferred_width = edid[54 + i * 18 + 2] | ((UINT32)(edid[54 + i * 18 + 4] & 0xf0) << 4); + info->preferred_height = edid[54 + i * 18 + 5] | ((UINT32)(edid[54 + i * 18 + 7] & 0xf0) << 4); + if (info->preferred_width && info->preferred_height) + info->flags |= MONITOR_INFO_HAS_PREFERRED_MODE; + continue; + } if (edid[54 + i * 18 + 3] != 0xfc) continue; /* "Display name" ASCII descriptor. */ s = (const char *)&edid[54 + i * 18 + 5]; @@ -5882,13 +5896,82 @@ NTSTATUS WINAPI NtUserDisplayConfigGetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEAD case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE: { DISPLAYCONFIG_TARGET_PREFERRED_MODE *preferred_mode = (DISPLAYCONFIG_TARGET_PREFERRED_MODE *)packet; + DISPLAYCONFIG_VIDEO_SIGNAL_INFO *signal_info = &preferred_mode->targetMode.targetVideoSignalInfo; + unsigned int i, display_freq; + DEVMODEW *found_mode = NULL; + BOOL have_edid_mode = FALSE; + struct monitor *monitor; - FIXME( "DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE stub.\n" ); + FIXME( "DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE semi-stub.\n" ); if (packet->size < sizeof(*preferred_mode)) return STATUS_INVALID_PARAMETER; - return STATUS_NOT_SUPPORTED; + if (!lock_display_devices()) return STATUS_UNSUCCESSFUL; + + memset( &preferred_mode->width, 0, sizeof(*preferred_mode) - offsetof(DISPLAYCONFIG_TARGET_PREFERRED_MODE, width) ); + + LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry) + { + if (preferred_mode->header.id != monitor->output_id) continue; + if (memcmp( &preferred_mode->header.adapterId, &monitor->adapter->gpu_luid, + sizeof(monitor->adapter->gpu_luid) )) + continue; + + for (i = 0; i < monitor->adapter->mode_count; ++i) + { + DEVMODEW *mode = &monitor->adapter->modes[i]; + + if (!have_edid_mode && monitor->edid_info.flags & MONITOR_INFO_HAS_PREFERRED_MODE + && mode->dmPelsWidth == monitor->edid_info.preferred_width + && mode->dmPelsHeight == monitor->edid_info.preferred_height) + { + found_mode = mode; + have_edid_mode = TRUE; + } + + if (!have_edid_mode && (!found_mode + || (mode->dmPelsWidth > found_mode->dmPelsWidth && mode->dmPelsHeight >= found_mode->dmPelsHeight) + || (mode->dmPelsHeight > found_mode->dmPelsHeight && mode->dmPelsWidth >= found_mode->dmPelsWidth))) + found_mode = mode; + + if (mode->dmPelsWidth == found_mode->dmPelsWidth + && mode->dmPelsHeight == found_mode->dmPelsHeight + && mode->dmDisplayFrequency > found_mode->dmDisplayFrequency) + found_mode = mode; + } + + if (!found_mode) + { + ERR( "No mode found.\n" ); + break; + } + preferred_mode->width = found_mode->dmPelsWidth; + preferred_mode->height = found_mode->dmPelsHeight; + display_freq = found_mode->dmDisplayFrequency; + + signal_info->pixelRate = display_freq * preferred_mode->width * preferred_mode->height; + signal_info->hSyncFreq.Numerator = display_freq * preferred_mode->width; + signal_info->hSyncFreq.Denominator = 1; + signal_info->vSyncFreq.Numerator = display_freq; + signal_info->vSyncFreq.Denominator = 1; + signal_info->activeSize.cx = preferred_mode->width; + signal_info->activeSize.cy = preferred_mode->height; + signal_info->totalSize.cx = preferred_mode->width; + signal_info->totalSize.cy = preferred_mode->height; + signal_info->videoStandard = D3DKMDT_VSS_OTHER; + if (!(found_mode->dmFields & DM_DISPLAYFLAGS)) + signal_info->scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED; + else if (found_mode->dmDisplayFlags & DM_INTERLACED) + signal_info->scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED; + else + signal_info->scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE; + ret = STATUS_SUCCESS; + break; + } + + unlock_display_devices(); + return ret; } case DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME: { From 3c52a9240ca44335876ef8fcbc9c208d1f24d6bf Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 20 Apr 2023 19:32:18 -0600 Subject: [PATCH 1258/2777] ntdll: Retry send on ECONNREFUSED in try_send(). CW-Bug-Id: #22167 --- dlls/ntdll/unix/socket.c | 12 ++++++++++++ dlls/ws2_32/tests/sock.c | 25 ++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index f4ea5e93ea0..32a40570d14 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -986,6 +986,7 @@ static NTSTATUS try_send( int fd, struct async_send_ioctl *async ) { union unix_sockaddr unix_addr; struct msghdr hdr; + int attempt = 0; ssize_t ret; memset( &hdr, 0, sizeof(hdr) ); @@ -1030,6 +1031,17 @@ static NTSTATUS try_send( int fd, struct async_send_ioctl *async ) else if (errno != EINTR) { if (errno != EWOULDBLOCK) WARN( "sendmsg: %s\n", strerror( errno ) ); + + /* ECONNREFUSED may be returned if this is connected datagram socket and the system received + * ICMP "destination port unreachable" message from the peer. That is ignored + * on Windows. The first sendmsg() will clear the error in this case and the next + * call should succeed. */ + if (!attempt && errno == ECONNREFUSED) + { + ++attempt; + continue; + } + return sock_errno_to_status( errno ); } } diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index ba4d7514c5e..289686fff3b 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -2949,7 +2949,9 @@ static void test_UDP(void) /* peer 0 receives data from all other peers */ struct sock_info peer[NUM_UDP_PEERS]; char buf[16]; - int ss, i, n_recv, n_sent; + int ss, i, n_recv, n_sent, ret; + struct sockaddr_in addr; + int sock; memset (buf,0,sizeof(buf)); for ( i = NUM_UDP_PEERS - 1; i >= 0; i-- ) { @@ -2987,6 +2989,27 @@ static void test_UDP(void) ok ( n_recv == sizeof(buf), "UDP: recvfrom() received wrong amount of data or socket error: %d\n", n_recv ); ok ( memcmp ( &peer[0].peer.sin_port, buf, sizeof(peer[0].addr.sin_port) ) == 0, "UDP: port numbers do not match\n" ); } + + sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP); + ok( sock != INVALID_SOCKET, "got error %u.\n", WSAGetLastError() ); + + memset( &addr, 0, sizeof(addr) ); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + addr.sin_port = htons(23456); + + ret = connect( sock, (struct sockaddr *)&addr, sizeof(addr) ); + ok( !ret, "got error %u.\n", WSAGetLastError() ); + + /* Send to UDP socket succeeds even if the packets are not received and the network is replying with + * "destination port unreachable" ICMP messages. */ + for (i = 0; i < 10; ++i) + { + ret = send( sock, buf, sizeof(buf), 0 ); + ok( ret == sizeof(buf), "got %d, error %u.\n", ret, WSAGetLastError() ); + } + + closesocket(sock); } static void test_WSASocket(void) From da2120602f0d6631903b4b94ad6db0bf3309feaa Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Tue, 7 Mar 2023 18:59:53 +0100 Subject: [PATCH 1259/2777] winegstreamer/media_source: Close bytestream in ::Shutdown. Signed-off-by: Derek Lesho (cherry picked from commit ab80ee17fa050e36511a602b228209a60a8b43b4) --- dlls/winegstreamer/media_source.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 97c00bb4d35..3411e0ffc4c 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1357,6 +1357,7 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) IMFPresentationDescriptor_Release(source->pres_desc); IMFMediaEventQueue_Shutdown(source->event_queue); + IMFByteStream_Close(source->byte_stream); IMFByteStream_Release(source->byte_stream); for (i = 0; i < source->stream_count; i++) From 8392e972e4d7d12672d754606a6a4e89ad733acb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Apr 2023 21:16:10 +0200 Subject: [PATCH 1260/2777] winegstreamer: Query the wg_parser stream in media_stream_create. (cherry picked from commit cd120fa8be35e36f7444b15ad5124eb492bdb074) --- dlls/winegstreamer/media_source.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 3411e0ffc4c..f1f85f60813 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -823,13 +823,16 @@ static const IMFMediaStreamVtbl media_stream_vtbl = media_stream_RequestSample }; -static HRESULT new_media_stream(struct media_source *source, - struct wg_parser_stream *wg_stream, DWORD stream_id, struct media_stream **out_stream) +static HRESULT media_stream_create(struct media_source *source, DWORD id, + struct media_stream **out) { - struct media_stream *object = calloc(1, sizeof(*object)); + struct media_stream *object; HRESULT hr; - TRACE("source %p, wg_stream %p, stream_id %lu.\n", source, wg_stream, stream_id); + TRACE("source %p, id %lu.\n", source, id); + + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl; object->ref = 1; @@ -842,16 +845,15 @@ static HRESULT new_media_stream(struct media_source *source, IMFMediaSource_AddRef(&source->IMFMediaSource_iface); object->parent_source = source; - object->stream_id = stream_id; + object->stream_id = id; object->state = STREAM_INACTIVE; object->eos = FALSE; - object->wg_stream = wg_stream; + object->wg_stream = wg_parser_get_stream(source->wg_parser, id); TRACE("Created stream object %p.\n", object); - *out_stream = object; - + *out = object; return S_OK; } @@ -1470,7 +1472,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, const WCHAR * for (i = 0; i < stream_count; ++i) { - if (FAILED(hr = new_media_stream(object, wg_parser_get_stream(parser, i), i, &object->streams[i]))) + if (FAILED(hr = media_stream_create(object, i, &object->streams[i]))) goto fail; if (FAILED(hr = media_stream_init_desc(object->streams[i]))) From 664b38fe0fb19b02449386fd11900571f7655b32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Apr 2023 21:18:57 +0200 Subject: [PATCH 1261/2777] winegstreamer: Keep a IMFMediaSource pointer in the media stream. (cherry picked from commit 3eb9571d5f902e38a835143be9e5cee0e70a1b48) --- dlls/winegstreamer/media_source.c | 42 +++++++++++++++++-------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index f1f85f60813..e3d9c8456a4 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -33,7 +33,8 @@ struct media_stream { IMFMediaStream IMFMediaStream_iface; LONG ref; - struct media_source *parent_source; + + IMFMediaSource *media_source; IMFMediaEventQueue *event_queue; IMFStreamDescriptor *descriptor; @@ -290,6 +291,7 @@ static BOOL enqueue_token(struct media_stream *stream, IUnknown *token) static void flush_token_queue(struct media_stream *stream, BOOL send) { + struct media_source *source = impl_from_IMFMediaSource(stream->media_source); LONG i; for (i = 0; i < stream->token_queue_count; i++) @@ -303,8 +305,8 @@ static void flush_token_queue(struct media_stream *stream, BOOL send) command->u.request_sample.stream = stream; command->u.request_sample.token = stream->token_queue[i]; - hr = MFPutWorkItem(stream->parent_source->async_commands_queue, - &stream->parent_source->async_commands_callback, &command->IUnknown_iface); + hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, + &command->IUnknown_iface); } if (FAILED(hr)) WARN("Could not enqueue sample request, hr %#lx\n", hr); @@ -530,7 +532,7 @@ static void send_buffer(struct media_stream *stream, const struct wg_parser_buff static void wait_on_sample(struct media_stream *stream, IUnknown *token) { - struct media_source *source = stream->parent_source; + struct media_source *source = impl_from_IMFMediaSource(stream->media_source); PROPVARIANT empty_var = {.vt = VT_EMPTY}; struct wg_parser_buffer buffer; @@ -544,7 +546,7 @@ static void wait_on_sample(struct media_stream *stream, IUnknown *token) { stream->eos = TRUE; IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty_var); - dispatch_end_of_presentation(stream->parent_source); + dispatch_end_of_presentation(source); } } @@ -743,17 +745,18 @@ static HRESULT WINAPI media_stream_QueueEvent(IMFMediaStream *iface, MediaEventT return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value); } -static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **source) +static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **out) { struct media_stream *stream = impl_from_IMFMediaStream(iface); + struct media_source *source = impl_from_IMFMediaSource(stream->media_source); - TRACE("%p, %p.\n", iface, source); + TRACE("%p, %p.\n", iface, out); if (stream->state == STREAM_SHUTDOWN) return MF_E_SHUTDOWN; - IMFMediaSource_AddRef(&stream->parent_source->IMFMediaSource_iface); - *source = &stream->parent_source->IMFMediaSource_iface; + IMFMediaSource_AddRef(&source->IMFMediaSource_iface); + *out = &source->IMFMediaSource_iface; return S_OK; } @@ -776,6 +779,7 @@ static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IM static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token) { struct media_stream *stream = impl_from_IMFMediaStream(iface); + struct media_source *source = impl_from_IMFMediaSource(stream->media_source); struct source_async_command *command; HRESULT hr; @@ -802,8 +806,7 @@ static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown IUnknown_AddRef(token); command->u.request_sample.token = token; - hr = MFPutWorkItem(stream->parent_source->async_commands_queue, - &stream->parent_source->async_commands_callback, &command->IUnknown_iface); + hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface); } return hr; @@ -823,9 +826,10 @@ static const IMFMediaStreamVtbl media_stream_vtbl = media_stream_RequestSample }; -static HRESULT media_stream_create(struct media_source *source, DWORD id, +static HRESULT media_stream_create(IMFMediaSource *source, DWORD id, struct media_stream **out) { + struct wg_parser *wg_parser = impl_from_IMFMediaSource(source)->wg_parser; struct media_stream *object; HRESULT hr; @@ -843,13 +847,13 @@ static HRESULT media_stream_create(struct media_source *source, DWORD id, return hr; } - IMFMediaSource_AddRef(&source->IMFMediaSource_iface); - object->parent_source = source; + IMFMediaSource_AddRef(source); + object->media_source = source; object->stream_id = id; object->state = STREAM_INACTIVE; object->eos = FALSE; - object->wg_stream = wg_parser_get_stream(source->wg_parser, id); + object->wg_stream = wg_parser_get_stream(wg_parser, id); TRACE("Created stream object %p.\n", object); @@ -1370,7 +1374,7 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) IMFMediaEventQueue_Shutdown(stream->event_queue); IMFStreamDescriptor_Release(stream->descriptor); - IMFMediaSource_Release(&stream->parent_source->IMFMediaSource_iface); + IMFMediaSource_Release(stream->media_source); IMFMediaStream_Release(&stream->IMFMediaStream_iface); } @@ -1472,13 +1476,13 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, const WCHAR * for (i = 0; i < stream_count; ++i) { - if (FAILED(hr = media_stream_create(object, i, &object->streams[i]))) + if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, i, &object->streams[i]))) goto fail; if (FAILED(hr = media_stream_init_desc(object->streams[i]))) { ERR("Failed to finish initialization of media stream %p, hr %#lx.\n", object->streams[i], hr); - IMFMediaSource_Release(&object->streams[i]->parent_source->IMFMediaSource_iface); + IMFMediaSource_Release(object->streams[i]->media_source); IMFMediaEventQueue_Release(object->streams[i]->event_queue); free(object->streams[i]); goto fail; @@ -1584,7 +1588,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, const WCHAR * IMFMediaEventQueue_Release(stream->event_queue); IMFStreamDescriptor_Release(stream->descriptor); - IMFMediaSource_Release(&stream->parent_source->IMFMediaSource_iface); + IMFMediaSource_Release(stream->media_source); free(stream); } From 09c85f9151cee681378ca8d3998c1f2f4f6a662f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Apr 2023 20:54:30 +0200 Subject: [PATCH 1262/2777] winegstreamer: Only break cyclic references in IMFMediaSource_Shutdown. (cherry picked from commit be50a7899af860855766286885735dd841584d2d) --- dlls/winegstreamer/media_source.c | 38 ++++++++++++------------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index e3d9c8456a4..5dedc855464 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -699,8 +699,9 @@ static ULONG WINAPI media_stream_Release(IMFMediaStream *iface) if (!ref) { - if (stream->event_queue) - IMFMediaEventQueue_Release(stream->event_queue); + IMFMediaSource_Release(stream->media_source); + IMFStreamDescriptor_Release(stream->descriptor); + IMFMediaEventQueue_Release(stream->event_queue); flush_token_queue(stream, FALSE); free(stream); } @@ -1207,8 +1208,11 @@ static ULONG WINAPI media_source_Release(IMFMediaSource *iface) if (!ref) { - IMFMediaSource_Shutdown(&source->IMFMediaSource_iface); + IMFMediaSource_Shutdown(iface); + IMFPresentationDescriptor_Release(source->pres_desc); IMFMediaEventQueue_Release(source->event_queue); + IMFByteStream_Release(source->byte_stream); + wg_parser_destroy(source->wg_parser); free(source); } @@ -1346,7 +1350,6 @@ static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) { struct media_source *source = impl_from_IMFMediaSource(iface); - unsigned int i; TRACE("%p.\n", iface); @@ -1361,26 +1364,16 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) WaitForSingleObject(source->read_thread, INFINITE); CloseHandle(source->read_thread); - IMFPresentationDescriptor_Release(source->pres_desc); IMFMediaEventQueue_Shutdown(source->event_queue); IMFByteStream_Close(source->byte_stream); - IMFByteStream_Release(source->byte_stream); - for (i = 0; i < source->stream_count; i++) + while (source->stream_count--) { - struct media_stream *stream = source->streams[i]; - + struct media_stream *stream = source->streams[source->stream_count]; stream->state = STREAM_SHUTDOWN; - IMFMediaEventQueue_Shutdown(stream->event_queue); - IMFStreamDescriptor_Release(stream->descriptor); - IMFMediaSource_Release(stream->media_source); - IMFMediaStream_Release(&stream->IMFMediaStream_iface); } - - wg_parser_destroy(source->wg_parser); - free(source->streams); MFUnlockWorkQueue(source->async_commands_queue); @@ -1582,17 +1575,14 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, const WCHAR * IMFStreamDescriptor_Release(descriptors[i]); free(descriptors); } - for (i = 0; i < object->stream_count; i++) - { - struct media_stream *stream = object->streams[i]; - IMFMediaEventQueue_Release(stream->event_queue); - IMFStreamDescriptor_Release(stream->descriptor); - IMFMediaSource_Release(stream->media_source); - - free(stream); + while (object->streams && object->stream_count--) + { + struct media_stream *stream = object->streams[object->stream_count]; + IMFMediaStream_Release(&stream->IMFMediaStream_iface); } free(object->streams); + if (stream_count != UINT_MAX) wg_parser_disconnect(object->wg_parser); if (object->read_thread) From b4a8beb9fa9bea37cc3418292704e0c571dc7867 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Thu, 27 Apr 2023 20:57:46 +0200 Subject: [PATCH 1263/2777] winegstreamer: Synchronize concurrent access to the media source. (cherry picked from commit aed8612c2cbe183b1cc5d0483678020c418a40eb) --- dlls/winegstreamer/media_source.c | 76 +++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 20 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 5dedc855464..812acd4c47d 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -95,6 +95,8 @@ struct media_source IMFMediaEventQueue *event_queue; IMFByteStream *byte_stream; + CRITICAL_SECTION cs; + struct wg_parser *wg_parser; struct media_stream **streams; @@ -1134,7 +1136,9 @@ static HRESULT WINAPI media_source_rate_control_SetRate(IMFRateControl *iface, B if (FAILED(hr = IMFRateSupport_IsRateSupported(&source->IMFRateSupport_iface, thin, rate, NULL))) return hr; + EnterCriticalSection(&source->cs); source->rate = rate; + LeaveCriticalSection(&source->cs); return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceRateChanged, &GUID_NULL, S_OK, NULL); } @@ -1148,7 +1152,9 @@ static HRESULT WINAPI media_source_rate_control_GetRate(IMFRateControl *iface, B if (thin) *thin = FALSE; + EnterCriticalSection(&source->cs); *rate = source->rate; + LeaveCriticalSection(&source->cs); return S_OK; } @@ -1213,6 +1219,8 @@ static ULONG WINAPI media_source_Release(IMFMediaSource *iface) IMFMediaEventQueue_Release(source->event_queue); IMFByteStream_Release(source->byte_stream); wg_parser_destroy(source->wg_parser); + source->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&source->cs); free(source); } @@ -1259,27 +1267,39 @@ static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventT static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics) { struct media_source *source = impl_from_IMFMediaSource(iface); + HRESULT hr = S_OK; TRACE("%p, %p.\n", iface, characteristics); + EnterCriticalSection(&source->cs); + if (source->state == SOURCE_SHUTDOWN) - return MF_E_SHUTDOWN; + hr = MF_E_SHUTDOWN; + else + *characteristics = MFMEDIASOURCE_CAN_SEEK | MFMEDIASOURCE_CAN_PAUSE; - *characteristics = MFMEDIASOURCE_CAN_SEEK | MFMEDIASOURCE_CAN_PAUSE; + LeaveCriticalSection(&source->cs); - return S_OK; + return hr; } static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor) { struct media_source *source = impl_from_IMFMediaSource(iface); + HRESULT hr; TRACE("%p, %p.\n", iface, descriptor); + EnterCriticalSection(&source->cs); + if (source->state == SOURCE_SHUTDOWN) - return MF_E_SHUTDOWN; + hr = MF_E_SHUTDOWN; + else + hr = IMFPresentationDescriptor_Clone(source->pres_desc, descriptor); - return IMFPresentationDescriptor_Clone(source->pres_desc, descriptor); + LeaveCriticalSection(&source->cs); + + return hr; } static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor, @@ -1291,13 +1311,13 @@ static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationD TRACE("%p, %p, %p, %p.\n", iface, descriptor, time_format, position); - if (source->state == SOURCE_SHUTDOWN) - return MF_E_SHUTDOWN; - - if (!(IsEqualIID(time_format, &GUID_NULL))) - return MF_E_UNSUPPORTED_TIME_FORMAT; + EnterCriticalSection(&source->cs); - if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_START, &command))) + if (source->state == SOURCE_SHUTDOWN) + hr = MF_E_SHUTDOWN; + else if (!(IsEqualIID(time_format, &GUID_NULL))) + hr = MF_E_UNSUPPORTED_TIME_FORMAT; + else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_START, &command))) { command->u.start.descriptor = descriptor; command->u.start.format = *time_format; @@ -1306,6 +1326,8 @@ static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationD hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface); } + LeaveCriticalSection(&source->cs); + return hr; } @@ -1317,12 +1339,15 @@ static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface) TRACE("%p.\n", iface); - if (source->state == SOURCE_SHUTDOWN) - return MF_E_SHUTDOWN; + EnterCriticalSection(&source->cs); - if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_STOP, &command))) + if (source->state == SOURCE_SHUTDOWN) + hr = MF_E_SHUTDOWN; + else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_STOP, &command))) hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface); + LeaveCriticalSection(&source->cs); + return hr; } @@ -1334,16 +1359,18 @@ static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) TRACE("%p.\n", iface); - if (source->state == SOURCE_SHUTDOWN) - return MF_E_SHUTDOWN; - - if (source->state != SOURCE_RUNNING) - return MF_E_INVALID_STATE_TRANSITION; + EnterCriticalSection(&source->cs); - if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_PAUSE, &command))) + if (source->state == SOURCE_SHUTDOWN) + hr = MF_E_SHUTDOWN; + else if (source->state != SOURCE_RUNNING) + hr = MF_E_INVALID_STATE_TRANSITION; + else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_PAUSE, &command))) hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface); + LeaveCriticalSection(&source->cs); + return S_OK; } @@ -1353,8 +1380,13 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) TRACE("%p.\n", iface); + EnterCriticalSection(&source->cs); + if (source->state == SOURCE_SHUTDOWN) + { + LeaveCriticalSection(&source->cs); return MF_E_SHUTDOWN; + } source->state = SOURCE_SHUTDOWN; @@ -1378,6 +1410,8 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) MFUnlockWorkQueue(source->async_commands_queue); + LeaveCriticalSection(&source->cs); + return S_OK; } @@ -1438,6 +1472,8 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, const WCHAR * object->byte_stream = bytestream; IMFByteStream_AddRef(bytestream); object->rate = 1.0f; + InitializeCriticalSection(&object->cs); + object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs"); if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) goto fail; From 47d2caa1a1c3f22e18437202fb99a2db47867525 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Thu, 27 Apr 2023 20:00:50 +0200 Subject: [PATCH 1264/2777] winegstreamer: Synchronize concurrent access to the media stream. (cherry picked from commit 49af378e31b4308f1af00f82a11a3f344daba421) --- dlls/winegstreamer/media_source.c | 55 ++++++++++++++++++------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 812acd4c47d..07086619550 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -752,31 +752,46 @@ static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMedi { struct media_stream *stream = impl_from_IMFMediaStream(iface); struct media_source *source = impl_from_IMFMediaSource(stream->media_source); + HRESULT hr = S_OK; TRACE("%p, %p.\n", iface, out); + EnterCriticalSection(&source->cs); + if (stream->state == STREAM_SHUTDOWN) - return MF_E_SHUTDOWN; + hr = MF_E_SHUTDOWN; + else + { + IMFMediaSource_AddRef(&source->IMFMediaSource_iface); + *out = &source->IMFMediaSource_iface; + } - IMFMediaSource_AddRef(&source->IMFMediaSource_iface); - *out = &source->IMFMediaSource_iface; + LeaveCriticalSection(&source->cs); - return S_OK; + return hr; } static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IMFStreamDescriptor **descriptor) { struct media_stream *stream = impl_from_IMFMediaStream(iface); + struct media_source *source = impl_from_IMFMediaSource(stream->media_source); + HRESULT hr = S_OK; TRACE("%p, %p.\n", iface, descriptor); + EnterCriticalSection(&source->cs); + if (stream->state == STREAM_SHUTDOWN) - return MF_E_SHUTDOWN; + hr = MF_E_SHUTDOWN; + else + { + IMFStreamDescriptor_AddRef(stream->descriptor); + *descriptor = stream->descriptor; + } - IMFStreamDescriptor_AddRef(stream->descriptor); - *descriptor = stream->descriptor; + LeaveCriticalSection(&source->cs); - return S_OK; + return hr; } static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token) @@ -788,21 +803,15 @@ static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown TRACE("%p, %p.\n", iface, token); - if (stream->state == STREAM_SHUTDOWN) - return MF_E_SHUTDOWN; - - if (stream->state == STREAM_INACTIVE) - { - WARN("Stream isn't active\n"); - return MF_E_MEDIA_SOURCE_WRONGSTATE; - } - - if (stream->eos) - { - return MF_E_END_OF_STREAM; - } + EnterCriticalSection(&source->cs); - if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &command))) + if (stream->state == STREAM_SHUTDOWN) + hr = MF_E_SHUTDOWN; + else if (stream->state == STREAM_INACTIVE) + hr = MF_E_MEDIA_SOURCE_WRONGSTATE; + else if (stream->eos) + hr = MF_E_END_OF_STREAM; + else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &command))) { command->u.request_sample.stream = stream; if (token) @@ -812,6 +821,8 @@ static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface); } + LeaveCriticalSection(&source->cs); + return hr; } From ea8ffdca0dd388e2342f4b3527eb609a7e83c348 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Thu, 10 Nov 2022 13:10:06 +0100 Subject: [PATCH 1265/2777] winegstreamer: Synchronize access to the media source from callbacks. (cherry picked from commit b7f5d908b5d5699a567ca2931e604060ffdf6f87) --- dlls/winegstreamer/media_source.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 07086619550..84f632230c1 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -559,32 +559,36 @@ static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFA IUnknown *state; HRESULT hr; - if (source->state == SOURCE_SHUTDOWN) - return S_OK; - if (FAILED(hr = IMFAsyncResult_GetState(result, &state))) return hr; + EnterCriticalSection(&source->cs); + command = impl_from_async_command_IUnknown(state); switch (command->op) { case SOURCE_ASYNC_START: - start_pipeline(source, command); + if (source->state != SOURCE_SHUTDOWN) + start_pipeline(source, command); break; case SOURCE_ASYNC_PAUSE: - pause_pipeline(source); + if (source->state != SOURCE_SHUTDOWN) + pause_pipeline(source); break; case SOURCE_ASYNC_STOP: - stop_pipeline(source); + if (source->state != SOURCE_SHUTDOWN) + stop_pipeline(source); break; case SOURCE_ASYNC_REQUEST_SAMPLE: if (source->state == SOURCE_PAUSED) enqueue_token(command->u.request_sample.stream, command->u.request_sample.token); - else + else if (source->state == SOURCE_RUNNING) wait_on_sample(command->u.request_sample.stream, command->u.request_sample.token); break; } + LeaveCriticalSection(&source->cs); + IUnknown_Release(state); return S_OK; From 96ecdded42fdec4d34fdd2f525f5ea8888764a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Apr 2023 21:29:29 +0200 Subject: [PATCH 1266/2777] winegstreamer: Remove unnecessary media source stream states. (cherry picked from commit b4b48e232a54d125181f3fef8ee10764cd85cc75) --- dlls/winegstreamer/media_source.c | 40 +++++++++++++------------------ 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 84f632230c1..e6e78fd4de3 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -44,13 +44,8 @@ struct media_stream LONG token_queue_count; LONG token_queue_cap; - enum - { - STREAM_INACTIVE, - STREAM_SHUTDOWN, - STREAM_RUNNING, - } state; DWORD stream_id; + BOOL active; BOOL eos; }; @@ -352,9 +347,8 @@ static void start_pipeline(struct media_source *source, struct source_async_comm sd = stream_descriptor_from_id(command->u.start.descriptor, stream_id, &selected); IMFStreamDescriptor_Release(sd); - was_active = stream->state != STREAM_INACTIVE; - - stream->state = selected ? STREAM_RUNNING : STREAM_INACTIVE; + was_active = stream->active; + stream->active = selected; if (selected) { @@ -406,14 +400,14 @@ static void start_pipeline(struct media_source *source, struct source_async_comm static void pause_pipeline(struct media_source *source) { unsigned int i; + HRESULT hr; for (i = 0; i < source->stream_count; i++) { struct media_stream *stream = source->streams[i]; - if (stream->state != STREAM_INACTIVE) - { - IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamPaused, &GUID_NULL, S_OK, NULL); - } + if (stream->active && FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamPaused, + &GUID_NULL, S_OK, NULL))) + WARN("Failed to queue MEStreamPaused event, hr %#lx\n", hr); } IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourcePaused, &GUID_NULL, S_OK, NULL); @@ -424,12 +418,14 @@ static void pause_pipeline(struct media_source *source) static void stop_pipeline(struct media_source *source) { unsigned int i; + HRESULT hr; for (i = 0; i < source->stream_count; i++) { struct media_stream *stream = source->streams[i]; - if (stream->state != STREAM_INACTIVE) - IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamStopped, &GUID_NULL, S_OK, NULL); + if (stream->active && FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamStopped, + &GUID_NULL, S_OK, NULL))) + WARN("Failed to queue MEStreamStopped event, hr %#lx\n", hr); } IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceStopped, &GUID_NULL, S_OK, NULL); @@ -449,8 +445,7 @@ static void dispatch_end_of_presentation(struct media_source *source) for (i = 0; i < source->stream_count; i++) { struct media_stream *stream = source->streams[i]; - - if (stream->state != STREAM_INACTIVE && !stream->eos) + if (stream->active && !stream->eos) return; } @@ -762,7 +757,7 @@ static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMedi EnterCriticalSection(&source->cs); - if (stream->state == STREAM_SHUTDOWN) + if (source->state == SOURCE_SHUTDOWN) hr = MF_E_SHUTDOWN; else { @@ -785,7 +780,7 @@ static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IM EnterCriticalSection(&source->cs); - if (stream->state == STREAM_SHUTDOWN) + if (source->state == SOURCE_SHUTDOWN) hr = MF_E_SHUTDOWN; else { @@ -809,9 +804,9 @@ static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown EnterCriticalSection(&source->cs); - if (stream->state == STREAM_SHUTDOWN) + if (source->state == SOURCE_SHUTDOWN) hr = MF_E_SHUTDOWN; - else if (stream->state == STREAM_INACTIVE) + else if (!stream->active) hr = MF_E_MEDIA_SOURCE_WRONGSTATE; else if (stream->eos) hr = MF_E_END_OF_STREAM; @@ -869,7 +864,7 @@ static HRESULT media_stream_create(IMFMediaSource *source, DWORD id, object->media_source = source; object->stream_id = id; - object->state = STREAM_INACTIVE; + object->active = FALSE; object->eos = FALSE; object->wg_stream = wg_parser_get_stream(wg_parser, id); @@ -1417,7 +1412,6 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) while (source->stream_count--) { struct media_stream *stream = source->streams[source->stream_count]; - stream->state = STREAM_SHUTDOWN; IMFMediaEventQueue_Shutdown(stream->event_queue); IMFMediaStream_Release(&stream->IMFMediaStream_iface); } From d83ff3ead71eafd95703bad35944fd5d26533f86 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Fri, 28 Apr 2023 12:52:35 -0400 Subject: [PATCH 1267/2777] uiautomationcore: Make sure to clone UIA node on thread that raised the event. If an event is raised in an STA, we need to clone the node in the STA to create the proper proxy. CW-Bug-Id: #22180 --- dlls/uiautomationcore/uia_client.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 6f3f50e88e6..eb39ec95eca 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -427,7 +427,6 @@ static HRESULT uia_event_thread_process_queue(struct list *event_queue) } else { - HUIANODE node2; LRESULT lr; VARIANT v; @@ -435,12 +434,7 @@ static HRESULT uia_event_thread_process_queue(struct list *event_queue) if (FAILED(hr)) goto next_event; - hr = clone_uia_node(node, &node2); - UiaNodeRelease(node); - if (FAILED(hr)) - goto next_event; - - if ((lr = uia_lresult_from_node(node2))) + if ((lr = uia_lresult_from_node(node))) { V_VT(&v) = VT_I4; V_I4(&v) = lr; @@ -449,7 +443,7 @@ static HRESULT uia_event_thread_process_queue(struct list *event_queue) WARN("IWineUiaEvent_raise_event failed with hr %#lx\n", hr); } else - UiaNodeRelease(node2); + UiaNodeRelease(node); } next_event: @@ -4641,9 +4635,14 @@ static void uia_event_invoke_callback(HUIANODE node, struct uia_event_args *args else { struct uia_queue_event *queue_event; + HUIANODE node2; VARIANT v; - get_variant_for_node(node, &v); + hr = clone_uia_node(node, &node2); + if (FAILED(hr)) + return; + + get_variant_for_node(node2, &v); hr = create_uia_queue_event(event, v, FALSE, args, &queue_event); if (SUCCEEDED(hr)) { @@ -4651,7 +4650,7 @@ static void uia_event_invoke_callback(HUIANODE node, struct uia_event_args *args if (event_thread.event_queue) { InterlockedIncrement(&args->ref); - IWineUiaNode_AddRef((IWineUiaNode *)node); + IWineUiaNode_AddRef((IWineUiaNode *)node2); list_add_tail(event_thread.event_queue, &queue_event->event_queue_entry); PostMessageW(event_thread.hwnd, WM_UIA_EVENT_THREAD_RAISE_EVENT, 0, 0); } @@ -4662,6 +4661,7 @@ static void uia_event_invoke_callback(HUIANODE node, struct uia_event_args *args } LeaveCriticalSection(&event_thread_cs); } + UiaNodeRelease(node2); } } From 8ed56c2f90255326aa0ddd7ed85e22500dda3ae4 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Fri, 5 May 2023 15:31:47 -0400 Subject: [PATCH 1268/2777] Revert "uiautomationcore: HACK: Return FALSE from UiaClientsAreListening() when called from EA Launcher." This reverts commit 53b3b958fff93703e83d35540205add2e5474991. --- dlls/uiautomationcore/uia_main.c | 49 -------------------------------- 1 file changed, 49 deletions(-) diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 9f9b63c2a7b..6818e39951d 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -259,61 +259,12 @@ static const IRawElementProviderSimpleVtbl hwnd_host_provider_vtbl = { hwnd_host_provider_get_HostRawElementProvider, }; -static BOOL is_ea_launcher_check(void) -{ - static const WCHAR *names[] = - { - L"\\EADesktop.exe", - L"\\Link2EA.exe", - L"\\EAConnect_microsoft.exe", - L"\\EALaunchHelper.exe", - L"\\EACrashReporter.exe", - L"EA Desktop\\ErrorReporter.exe", - }; - unsigned int i, len; - WCHAR module[256]; - DWORD size; - - if ((size = GetModuleFileNameW( NULL, module, ARRAY_SIZE(module) )) && size < ARRAY_SIZE(module)) - { - for (i = 0; i < ARRAY_SIZE(names); ++i) - { - len = lstrlenW(names[i]); - if (size > len && !memcmp( module + size - len, names[i], len * sizeof(*module) )) - { - FIXME("HACK: Returning FALSE from UiaClientsAreListening for EA launcher.\n"); - return TRUE; - } - } - } - - return FALSE; -} - /*********************************************************************** * UiaClientsAreListening (uiautomationcore.@) */ BOOL WINAPI UiaClientsAreListening(void) { - static BOOL ea_launcher_check_ran; - static BOOL is_ea_launcher; - FIXME("()\n"); - - /* - * HACK: Tell EA Launcher no clients are listening so it doesn't attempt - * to raise an event. Temporarily disabling until the cause of the access - * violation is found. - */ - if (!ea_launcher_check_ran) - { - is_ea_launcher = is_ea_launcher_check(); - ea_launcher_check_ran = TRUE; - } - - if (is_ea_launcher) - return FALSE; - return TRUE; } From 62230118e33a3de389d04649d25834a81d8b957c Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Fri, 28 Apr 2023 19:43:14 -0400 Subject: [PATCH 1269/2777] fixup! uiautomationcore: Implement UiaRaiseAutomationEvent. --- dlls/uiautomationcore/uia_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index eb39ec95eca..d038d2239a6 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -4814,7 +4814,7 @@ HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *elprov, EVENTI TRACE("(%p, %d)\n", elprov, id); - if (!event_info || event_info->event_arg_type != EventArgsType_Simple) + if (!elprov || !event_info || event_info->event_arg_type != EventArgsType_Simple) return E_INVALIDARG; args = create_uia_event_args(event_info); From 17a73d085aca0d741d59f405cc8c9a9aed2a391d Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Wed, 3 May 2023 09:00:19 +0200 Subject: [PATCH 1270/2777] evr: Fix incorrect integral computation. Note: typeof (int * unsigned) is unsigned. So: - on 64bit CPUs, where sizeof(int) = 4 < sizeof(void*) = 8, - when the result of the multiplication is supposed to be negative - there's no propagation of the negative sign from 32bit to 64 bit integers Fixes a crash in Age of Empire II. CW-Bug-Id: #22161 Signed-off-by: Eric Pouech (cherry picked from commit 0cc4a38aae9ded4493550bbff8d51f49d71c9dd6) --- dlls/evr/evr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/evr/evr.c b/dlls/evr/evr.c index 26a2a3a1eb5..803c1d2dff9 100644 --- a/dlls/evr/evr.c +++ b/dlls/evr/evr.c @@ -382,7 +382,7 @@ static HRESULT evr_copy_sample_buffer(struct evr *filter, IMediaSample *input_sa { if (SUCCEEDED(hr = IDirect3DSurface9_LockRect(surface, &locked_rect, NULL, D3DLOCK_DISCARD))) { - if (src_stride < 0) src -= src_stride * (lines - 1); + if (src_stride < 0) src += (-src_stride) * (lines - 1); MFCopyImage(locked_rect.pBits, locked_rect.Pitch, src, src_stride, width * 4, lines); IDirect3DSurface9_UnlockRect(surface); } From 74e4b69d6997c0cd646c18062842a3e0be9db5b1 Mon Sep 17 00:00:00 2001 From: Tingzhong Luo Date: Thu, 23 Feb 2023 11:56:54 +0800 Subject: [PATCH 1271/2777] evr: Fix crash when clearing input type for the mixer. CW-Bug-Id: #22161 Signed-off-by: Tingzhong Luo (cherry picked from commit c56638278cecc1db682af28b16fbdba6c73bbf42) --- dlls/evr/mixer.c | 9 +++++++-- dlls/evr/tests/evr.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/dlls/evr/mixer.c b/dlls/evr/mixer.c index 668a97da979..222fc538fec 100644 --- a/dlls/evr/mixer.c +++ b/dlls/evr/mixer.c @@ -240,7 +240,7 @@ static void video_mixer_clear_types(struct video_mixer *mixer) free(mixer->output.rt_formats); if (mixer->output.media_type) IMFMediaType_Release(mixer->output.media_type); - mixer->output.media_type = NULL; + memset(&mixer->output, 0, sizeof(mixer->output)); } static HRESULT WINAPI video_mixer_inner_QueryInterface(IUnknown *iface, REFIID riid, void **obj) @@ -855,12 +855,17 @@ static HRESULT WINAPI video_mixer_transform_SetInputType(IMFTransform *iface, DW TRACE("%p, %lu, %p, %#lx.\n", iface, id, media_type, flags); + if (!media_type && (flags & MFT_SET_TYPE_TEST_ONLY)) + return E_INVALIDARG; + EnterCriticalSection(&mixer->cs); if (!(flags & MFT_SET_TYPE_TEST_ONLY)) video_mixer_clear_types(mixer); - if (!mixer->device_manager) + if (!media_type) + hr = S_OK; + else if (!mixer->device_manager) hr = MF_E_NOT_INITIALIZED; else { diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index acfb92f2ea5..4f30dd28570 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -1249,6 +1249,11 @@ static void test_default_mixer_type_negotiation(void) goto done; } + hr = IMFTransform_SetInputType(transform, 0, NULL, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_SetInputType(transform, 0, NULL, MFT_SET_TYPE_TEST_ONLY); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + hr = DXVA2CreateDirect3DDeviceManager9(&token, &manager); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -1469,9 +1474,48 @@ static void test_default_mixer_type_negotiation(void) hr = IMFTransform_GetOutputCurrentType(transform, 0, &media_type2); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(media_type == media_type2, "Unexpected media type instance.\n"); + + IMFMediaType_Release(media_type); + + /* Clear input types */ + hr = IMFTransform_SetInputType(transform, 0, NULL, MFT_SET_TYPE_TEST_ONLY); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = IMFTransform_SetInputType(transform, 0, NULL, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); + ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_GetOutputCurrentType(transform, 0, &media_type); + ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#lx.\n", hr); + + /* Restore types */ + hr = IMFTransform_SetOutputType(transform, 0, media_type2, 0); + ok(hr == MF_E_INVALIDMEDIATYPE, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_GetOutputCurrentType(transform, 0, &media_type); + ok(hr == MF_E_TRANSFORM_TYPE_NOT_SET, "Unexpected hr %#lx.\n", hr); + + hr = IMFTransform_SetInputType(transform, 0, video_type, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(media_type == video_type, "Unexpected media type instance.\n"); + IMFMediaType_Release(media_type); + + hr = IMFTransform_SetOutputType(transform, 0, media_type2, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_GetOutputCurrentType(transform, 0, &media_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(media_type2 == media_type, "Unexpected media type instance.\n"); + IMFMediaType_Release(media_type2); IMFMediaType_Release(media_type); + /* Resetting type twice */ + hr = IMFTransform_SetInputType(transform, 0, NULL, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_SetInputType(transform, 0, NULL, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFVideoProcessor_Release(processor); IMFMediaType_Release(video_type); From 9aad94ebe68a184640a66bc25e978edee500fca4 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Thu, 11 May 2023 10:29:58 +0800 Subject: [PATCH 1272/2777] HACK: winex11.drv: Disable Vulkan child window rendering for SWORD ART ONLINE Alicization Lycoris. CW-Bug-Id: #21949 --- dlls/winex11.drv/x11drv_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 58d7c8eee03..e35ea4052d2 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -850,7 +850,8 @@ static NTSTATUS x11drv_init( void *arg ) e = getenv("WINE_DISABLE_VK_CHILD_WINDOW_RENDERING_HACK"); vulkan_disable_child_window_rendering_hack = (sgi && ( - !strcmp(sgi, "429660") /* Bug 21949 : Tales of Berseria video tearing */ + !strcmp(sgi, "429660") || /* Bug 21949 : Tales of Berseria video tearing */ + !strcmp(sgi, "1009290") /* Bug 21949 : SWORD ART ONLINE Alicization Lycoris video tearing */ )) || (e && *e != '\0' && *e != '0'); } From 7cb87ef917d1eaa0f59ae9f656d3b509beb9084e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 10 May 2023 15:57:00 +0200 Subject: [PATCH 1273/2777] dinput: Delay input thread start until the first device acquire. Some applications create a IDirectInput and IDirectInputDevice instance from their DllMain procedure, and starting the thread on the first user creation and waiting for it to start will deadlock on the loader lock. CW-Bug-Id: #22253 --- dlls/dinput/dinput_main.c | 80 +++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 33f98eda120..f2d75a14d2e 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -89,28 +89,6 @@ static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0 static struct list acquired_device_list = LIST_INIT( acquired_device_list ); -void dinput_hooks_acquire_device( IDirectInputDevice8W *iface ) -{ - struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); - - EnterCriticalSection( &dinput_hook_crit ); - list_add_tail( &acquired_device_list, &impl->entry ); - LeaveCriticalSection( &dinput_hook_crit ); - - SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_REFRESH_DEVICES, 0 ); -} - -void dinput_hooks_unacquire_device( IDirectInputDevice8W *iface ) -{ - struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); - - EnterCriticalSection( &dinput_hook_crit ); - list_remove( &impl->entry ); - LeaveCriticalSection( &dinput_hook_crit ); - - SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_REFRESH_DEVICES, 0 ); -} - static void unhook_device_window_foreground_changes( struct dinput_device *device ) { if (!device->cbt_hook) return; @@ -429,37 +407,67 @@ static DWORD WINAPI dinput_thread_proc( void *params ) return 0; } -void input_thread_add_user(void) +void input_thread_start(void) { + HANDLE start_event; + + TRACE( "Starting input thread.\n" ); + + if (!(start_event = CreateEventW( NULL, FALSE, FALSE, NULL ))) + ERR( "Failed to create start event, error %lu\n", GetLastError() ); + else if (!(dinput_thread = CreateThread( NULL, 0, dinput_thread_proc, start_event, 0, NULL ))) + ERR( "Failed to create internal thread, error %lu\n", GetLastError() ); + else + WaitForSingleObject( start_event, INFINITE ); + + CloseHandle( start_event ); +} + +void dinput_hooks_acquire_device( IDirectInputDevice8W *iface ) +{ + struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); + EnterCriticalSection( &dinput_hook_crit ); - if (!input_thread_user_count++) - { - HANDLE start_event; + /* start the input thread now if it wasn't started already */ + if (!dinput_thread) input_thread_start(); + list_add_tail( &acquired_device_list, &impl->entry ); + LeaveCriticalSection( &dinput_hook_crit ); - TRACE( "Starting input thread.\n" ); + SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_REFRESH_DEVICES, 0 ); +} - if (!(start_event = CreateEventW( NULL, FALSE, FALSE, NULL ))) - ERR( "Failed to create start event, error %lu\n", GetLastError() ); - else if (!(dinput_thread = CreateThread( NULL, 0, dinput_thread_proc, start_event, 0, NULL ))) - ERR( "Failed to create internal thread, error %lu\n", GetLastError() ); - else - WaitForSingleObject( start_event, INFINITE ); +void dinput_hooks_unacquire_device( IDirectInputDevice8W *iface ) +{ + struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); - CloseHandle( start_event ); - } + EnterCriticalSection( &dinput_hook_crit ); + list_remove( &impl->entry ); + LeaveCriticalSection( &dinput_hook_crit ); + + SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_REFRESH_DEVICES, 0 ); +} + +void input_thread_add_user(void) +{ + /* we cannot start the input thread here because some games create dinput objects from their DllMain, and + * starting the thread will wait for it to initialize, which requires the loader lock to be released. + */ + EnterCriticalSection( &dinput_hook_crit ); + input_thread_user_count++; LeaveCriticalSection( &dinput_hook_crit ); } void input_thread_remove_user(void) { EnterCriticalSection( &dinput_hook_crit ); - if (!--input_thread_user_count) + if (!--input_thread_user_count && dinput_thread) { TRACE( "Stopping input thread.\n" ); SendMessageW( di_em_win, INPUT_THREAD_NOTIFY, NOTIFY_THREAD_STOP, 0 ); WaitForSingleObject( dinput_thread, INFINITE ); CloseHandle( dinput_thread ); + dinput_thread = NULL; } LeaveCriticalSection( &dinput_hook_crit ); } From 622bd8089ad4395243643c39820d898233c6a043 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Sun, 14 May 2023 15:34:24 +0800 Subject: [PATCH 1274/2777] gdiplus/tests: Add pen custom line cap record and play back tests. CW-Bug-Id: #22170 --- dlls/gdiplus/tests/metafile.c | 126 ++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c index aa844a62ff9..48da5c648ef 100644 --- a/dlls/gdiplus/tests/metafile.c +++ b/dlls/gdiplus/tests/metafile.c @@ -3874,6 +3874,131 @@ static void test_setclippath(void) expect(Ok, stat); } +static const emfplus_record pen_dc_records[] = +{ + { EMR_HEADER }, + { EmfPlusRecordTypeHeader }, + { EmfPlusRecordTypeObject, ObjectTypePen << 8 }, + { EmfPlusRecordTypeObject, (ObjectTypePath << 8) | 1 }, + { EmfPlusRecordTypeDrawPath, 1 }, + { EMR_SAVEDC, 0, 1 }, + { EMR_SETICMMODE, 0, 1 }, + { EMR_BITBLT, 0, 1 }, + { EMR_RESTOREDC, 0, 1 }, + { EmfPlusRecordTypeEndOfFile }, + { EMR_EOF }, + { 0 } +}; + +static const emfplus_record pen_bitmap_records[] = +{ + { EMR_HEADER }, + { EmfPlusRecordTypeHeader }, + { EmfPlusRecordTypeObject, ObjectTypePen << 8 }, + { EmfPlusRecordTypeObject, (ObjectTypePath << 8) | 1 }, + { EmfPlusRecordTypeDrawPath, 1 }, + { EmfPlusRecordTypeEndOfFile }, + { EMR_EOF }, + { 0 } +}; + +static void test_pen(void) +{ + static const GpPointF dst_points[3] = {{0.0, 0.0}, {100.0, 0.0}, {0.0, 100.0}}; + static const GpRectF frame = {0.0, 0.0, 100.0, 100.0}; + GpMetafile *metafile, *clone_metafile; + GpPath *draw_path, *line_cap_path; + GpCustomLineCap *custom_line_cap; + GpGraphics *graphics; + HENHMETAFILE hemf; + COLORREF color; + GpStatus stat; + GpPen *pen; + HWND hwnd; + BOOL ret; + HDC hdc; + + /* Record */ + hdc = CreateCompatibleDC(0); + stat = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, &frame, MetafileFrameUnitPixel, description, &metafile); + expect(Ok, stat); + DeleteDC(hdc); + + stat = GdipGetImageGraphicsContext((GpImage *)metafile, &graphics); + expect(Ok, stat); + + stat = GdipCreatePath(FillModeAlternate, &draw_path); + expect(Ok, stat); + stat = GdipAddPathLine(draw_path, 25, 25, 25, 75); + expect(Ok, stat); + + stat = GdipCreatePen1((ARGB)0xffff0000, 1.0f, UnitPixel, &pen); + expect(Ok, stat); + stat = GdipCreatePath(FillModeAlternate, &line_cap_path); + expect(Ok, stat); + stat = GdipAddPathRectangle(line_cap_path, 5.0, 5.0, 10.0, 10.0); + expect(Ok, stat); + stat = GdipCreateCustomLineCap(NULL, line_cap_path, LineCapCustom, 0.0, &custom_line_cap); + expect(Ok, stat); + stat = GdipSetPenCustomStartCap(pen, custom_line_cap); + expect(Ok, stat); + stat = GdipSetPenCustomEndCap(pen, custom_line_cap); + expect(Ok, stat); + stat = GdipDeleteCustomLineCap(custom_line_cap); + expect(Ok, stat); + stat = GdipDeletePath(line_cap_path); + expect(Ok, stat); + + stat = GdipDrawPath(graphics, pen, draw_path); + expect(Ok, stat); + + stat = GdipDeletePen(pen); + expect(Ok, stat); + stat = GdipDeletePath(draw_path); + expect(Ok, stat); + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + + GdipCloneImage((GpImage *)metafile, (GpImage **)&clone_metafile); + sync_metafile(&metafile, "pen.emf"); + + stat = GdipGetHemfFromMetafile(metafile, &hemf); + expect(Ok, stat); + + check_emfplus(hemf, pen_dc_records, "pen record"); + + ret = DeleteEnhMetaFile(hemf); + ok(ret != 0, "Failed to delete enhmetafile.\n"); + stat = GdipDisposeImage((GpImage *)metafile); + expect(Ok, stat); + + /* Play back */ + /* Create graphics from a window DC for this test because bitmap DC uses + * SOFTWARE_GdipDrawPath(), which doesn't support drawing line caps */ + hwnd = CreateWindowA("static", NULL, WS_POPUP, 0, 0, 100, 100, NULL, NULL, NULL, 0); + hdc = GetDC(0); + stat = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, stat); + + play_metafile(clone_metafile, graphics, pen_bitmap_records, "pen playback", dst_points, &frame, UnitPixel); + + color = GetPixel(hdc, 10, 10); + todo_wine + expect(RGB(0xff, 0, 0), color); + + color = GetPixel(hdc, 40, 90); + todo_wine + flaky /* Win10 + */ + expect(RGB(0xff, 0, 0), color); + + stat = GdipDisposeImage((GpImage *)clone_metafile); + expect(Ok, stat); + stat = GdipDeleteGraphics(graphics); + expect(Ok, stat); + ReleaseDC(hwnd, hdc); + DestroyWindow(hwnd); +} + START_TEST(metafile) { struct GdiplusStartupInput gdiplusStartupInput; @@ -3934,6 +4059,7 @@ START_TEST(metafile) test_offsetclip(); test_resetclip(); test_setclippath(); + test_pen(); GdiplusShutdown(gdiplusToken); } From 6fc82d9190d8fe1a8e195e9536f6e58a01f2db19 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Fri, 28 Apr 2023 16:44:20 +0800 Subject: [PATCH 1275/2777] gdiplus: Support recording pen custom start line cap. CW-Bug-Id: #22170 --- dlls/gdiplus/metafile.c | 230 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 215 insertions(+), 15 deletions(-) diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index 90ef39e34d6..da1b3241105 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -46,6 +46,12 @@ HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**); typedef ARGB EmfPlusARGB; +typedef struct EmfPlusPointF +{ + float X; + float Y; +} EmfPlusPointF; + typedef struct EmfPlusRecordHeader { WORD Type; @@ -177,6 +183,12 @@ enum PenDataFlags PenDataCustomEndCap = 0x1000 }; +enum CustomLineCapData +{ + CustomLineCapDataFillPath = 0x1, + CustomLineCapDataLinePath = 0x2, +}; + typedef struct EmfPlusTransformMatrix { REAL TransformMatrix[6]; @@ -287,14 +299,20 @@ typedef struct EmfPlusBrush } BrushData; } EmfPlusBrush; -typedef struct EmfPlusPen -{ - DWORD Version; - DWORD Type; - /* EmfPlusPenData */ - /* EmfPlusBrush */ - BYTE data[1]; -} EmfPlusPen; +typedef struct EmfPlusCustomLineCapArrowData +{ + REAL Width; + REAL Height; + REAL MiddleInset; + BOOL FillState; + DWORD LineStartCap; + DWORD LineEndCap; + DWORD LineJoin; + REAL LineMiterLimit; + REAL WidthScale; + EmfPlusPointF FillHotSpot; + EmfPlusPointF LineHotSpot; +} EmfPlusCustomLineCapArrowData; typedef struct EmfPlusPath { @@ -307,6 +325,55 @@ typedef struct EmfPlusPath BYTE data[1]; } EmfPlusPath; +typedef struct EmfPlusCustomLineCapDataFillPath +{ + INT FillPathLength; + /* EmfPlusPath */ + BYTE FillPath[1]; +} EmfPlusCustomLineCapDataFillPath; + +typedef struct EmfPlusCustomLineCapDataLinePath +{ + INT LinePathLength; + /* EmfPlusPath */ + BYTE LinePath[1]; +} EmfPlusCustomLineCapDataLinePath; + +typedef struct EmfPlusCustomLineCapData +{ + DWORD CustomLineCapDataFlags; + DWORD BaseCap; + REAL BaseInset; + DWORD StrokeStartCap; + DWORD StrokeEndCap; + DWORD StrokeJoin; + REAL StrokeMiterLimit; + REAL WidthScale; + EmfPlusPointF FillHotSpot; + EmfPlusPointF LineHotSpot; + /* EmfPlusCustomLineCapDataFillPath */ + /* EmfPlusCustomLineCapDataLinePath */ + BYTE OptionalData[1]; +} EmfPlusCustomLineCapData; + +typedef struct EmfPlusCustomLineCap +{ + DWORD Version; + DWORD Type; + /* EmfPlusCustomLineCapArrowData */ + /* EmfPlusCustomLineCapData */ + BYTE CustomLineCapData[1]; +} EmfPlusCustomLineCap; + +typedef struct EmfPlusPen +{ + DWORD Version; + DWORD Type; + /* EmfPlusPenData */ + /* EmfPlusBrush */ + BYTE data[1]; +} EmfPlusPen; + typedef struct EmfPlusRegionNodePath { DWORD RegionNodePathLength; @@ -416,12 +483,6 @@ typedef struct EmfPlusPoint short Y; } EmfPlusPoint; -typedef struct EmfPlusPointF -{ - float X; - float Y; -} EmfPlusPointF; - typedef struct EmfPlusDrawImage { EmfPlusRecordHeader Header; @@ -1055,6 +1116,134 @@ static void METAFILE_FillBrushData(GDIPCONST GpBrush *brush, EmfPlusBrush *data) } } +static void METAFILE_PrepareCustomLineCapData(GDIPCONST GpCustomLineCap *cap, DWORD *ret_cap_size, + DWORD *ret_cap_data_size, DWORD *ret_path_size) +{ + DWORD cap_size, path_size = 0; + + /* EmfPlusCustomStartCapData */ + cap_size = FIELD_OFFSET(EmfPlusCustomStartCapData, data); + /* -> EmfPlusCustomLineCap */ + cap_size += FIELD_OFFSET(EmfPlusCustomLineCap, CustomLineCapData); + /* -> EmfPlusCustomLineCapArrowData */ + if (cap->type == CustomLineCapTypeAdjustableArrow) + cap_size += sizeof(EmfPlusCustomLineCapArrowData); + /* -> EmfPlusCustomLineCapData */ + else + { + /* -> EmfPlusCustomLineCapOptionalData */ + cap_size += FIELD_OFFSET(EmfPlusCustomLineCapData, OptionalData); + if (cap->fill) + /* -> EmfPlusCustomLineCapDataFillPath */ + cap_size += FIELD_OFFSET(EmfPlusCustomLineCapDataFillPath, FillPath); + else + /* -> EmfPlusCustomLineCapDataLinePath */ + cap_size += FIELD_OFFSET(EmfPlusCustomLineCapDataLinePath, LinePath); + + /* -> EmfPlusPath in EmfPlusCustomLineCapDataFillPath and EmfPlusCustomLineCapDataLinePath */ + path_size = FIELD_OFFSET(EmfPlusPath, data); + path_size += sizeof(PointF) * cap->pathdata.Count; + path_size += sizeof(BYTE) * cap->pathdata.Count; + path_size = (path_size + 3) & ~3; + + cap_size += path_size; + } + + *ret_cap_size = cap_size; + *ret_cap_data_size = cap_size - FIELD_OFFSET(EmfPlusCustomStartCapData, data); + *ret_path_size = path_size; +} + +static void METAFILE_FillCustomLineCapData(GDIPCONST GpCustomLineCap *cap, BYTE *ptr, + REAL line_miter_limit, DWORD data_size, DWORD path_size) +{ + EmfPlusCustomStartCapData *cap_data; + EmfPlusCustomLineCap *line_cap; + DWORD i, j; + + cap_data = (EmfPlusCustomStartCapData *)ptr; + cap_data->CustomStartCapSize = data_size; + i = FIELD_OFFSET(EmfPlusCustomStartCapData, data); + + line_cap = (EmfPlusCustomLineCap *)(ptr + i); + line_cap->Version = VERSION_MAGIC2; + line_cap->Type = cap->type; + i += FIELD_OFFSET(EmfPlusCustomLineCap, CustomLineCapData); + + if (cap->type == CustomLineCapTypeAdjustableArrow) + { + EmfPlusCustomLineCapArrowData *arrow_data; + GpAdjustableArrowCap *arrow_cap; + + arrow_data = (EmfPlusCustomLineCapArrowData *)(ptr + i); + arrow_cap = (GpAdjustableArrowCap *)cap; + arrow_data->Width = arrow_cap->width; + arrow_data->Height = arrow_cap->height; + arrow_data->MiddleInset = arrow_cap->middle_inset; + arrow_data->FillState = arrow_cap->cap.fill; + arrow_data->LineStartCap = arrow_cap->cap.strokeStartCap; + arrow_data->LineEndCap = arrow_cap->cap.strokeEndCap; + arrow_data->LineJoin = arrow_cap->cap.join; + arrow_data->LineMiterLimit = line_miter_limit; + arrow_data->WidthScale = arrow_cap->cap.scale; + arrow_data->FillHotSpot.X = 0; + arrow_data->FillHotSpot.Y = 0; + arrow_data->LineHotSpot.X = 0; + arrow_data->LineHotSpot.Y = 0; + } + else + { + EmfPlusCustomLineCapData *line_cap_data = (EmfPlusCustomLineCapData *)(ptr + i); + EmfPlusPath *path; + + if (cap->fill) + line_cap_data->CustomLineCapDataFlags = CustomLineCapDataFillPath; + else + line_cap_data->CustomLineCapDataFlags = CustomLineCapDataLinePath; + line_cap_data->BaseCap = cap->basecap; + line_cap_data->BaseInset = cap->inset; + line_cap_data->StrokeStartCap = cap->strokeStartCap; + line_cap_data->StrokeEndCap = cap->strokeEndCap; + line_cap_data->StrokeJoin = cap->join; + line_cap_data->StrokeMiterLimit = line_miter_limit; + line_cap_data->WidthScale = cap->scale; + line_cap_data->FillHotSpot.X = 0; + line_cap_data->FillHotSpot.Y = 0; + line_cap_data->LineHotSpot.X = 0; + line_cap_data->LineHotSpot.Y = 0; + i += FIELD_OFFSET(EmfPlusCustomLineCapData, OptionalData); + + if (cap->fill) + { + EmfPlusCustomLineCapDataFillPath *fill_path = (EmfPlusCustomLineCapDataFillPath *)(ptr + i); + fill_path->FillPathLength = path_size; + i += FIELD_OFFSET(EmfPlusCustomLineCapDataFillPath, FillPath); + } + else + { + EmfPlusCustomLineCapDataLinePath *line_path = (EmfPlusCustomLineCapDataLinePath *)(ptr + i); + line_path->LinePathLength = path_size; + i += FIELD_OFFSET(EmfPlusCustomLineCapDataLinePath, LinePath); + } + + path = (EmfPlusPath *)(ptr + i); + path->Version = VERSION_MAGIC2; + path->PathPointCount = cap->pathdata.Count; + path->PathPointFlags = 0; + i += FIELD_OFFSET(EmfPlusPath, data); + for (j = 0; j < cap->pathdata.Count; ++j) + { + *(PointF *)(ptr + i) = cap->pathdata.Points[j]; + i += sizeof(PointF); + } + for (j = 0; j < cap->pathdata.Count; ++j) + { + *(BYTE *)(ptr + i) = cap->pathdata.Types[j]; + i += sizeof(BYTE); + } + } +} + static GpStatus METAFILE_AddBrushObject(GpMetafile *metafile, GDIPCONST GpBrush *brush, DWORD *id) { EmfPlusObject *object_record; @@ -4562,6 +4751,7 @@ static GpStatus METAFILE_AddPathObject(GpMetafile *metafile, GpPath *path, DWORD static GpStatus METAFILE_AddPenObject(GpMetafile *metafile, GpPen *pen, DWORD *id) { + DWORD custom_start_cap_size = 0, custom_start_cap_data_size = 0, custom_start_cap_path_size = 0; DWORD i, data_flags, pen_data_size, brush_size; EmfPlusObject *object_record; EmfPlusPenData *pen_data; @@ -4626,7 +4816,10 @@ static GpStatus METAFILE_AddPenObject(GpMetafile *metafile, GpPen *pen, DWORD *i /* TODO: Add support for PenDataCompoundLine */ if (pen->customstart) { - FIXME("ignoring custom start cup\n"); + data_flags |= PenDataCustomStartCap; + METAFILE_PrepareCustomLineCapData(pen->customstart, &custom_start_cap_size, + &custom_start_cap_data_size, &custom_start_cap_path_size); + pen_data_size += custom_start_cap_size; } if (pen->customend) { @@ -4719,6 +4912,13 @@ static GpStatus METAFILE_AddPenObject(GpMetafile *metafile, GpPen *pen, DWORD *i *(REAL*)(pen_data->OptionalData + i) = pen->align; i += sizeof(DWORD); } + if (data_flags & PenDataCustomStartCap) + { + METAFILE_FillCustomLineCapData(pen->customstart, pen_data->OptionalData + i, + pen->miterlimit, custom_start_cap_data_size, + custom_start_cap_path_size); + i += custom_start_cap_size; + } METAFILE_FillBrushData(pen->brush, (EmfPlusBrush*)(object_record->ObjectData.pen.data + pen_data_size)); From 803480e1b24dba7d0025870cc4fdf81825fc0f47 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Fri, 28 Apr 2023 16:45:51 +0800 Subject: [PATCH 1276/2777] gdiplus: Support recording pen custom end line cap. CW-Bug-Id: #22170 --- dlls/gdiplus/metafile.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index da1b3241105..e51b44e0f0a 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -4752,6 +4752,7 @@ static GpStatus METAFILE_AddPathObject(GpMetafile *metafile, GpPath *path, DWORD static GpStatus METAFILE_AddPenObject(GpMetafile *metafile, GpPen *pen, DWORD *id) { DWORD custom_start_cap_size = 0, custom_start_cap_data_size = 0, custom_start_cap_path_size = 0; + DWORD custom_end_cap_size = 0, custom_end_cap_data_size = 0, custom_end_cap_path_size = 0; DWORD i, data_flags, pen_data_size, brush_size; EmfPlusObject *object_record; EmfPlusPenData *pen_data; @@ -4823,7 +4824,10 @@ static GpStatus METAFILE_AddPenObject(GpMetafile *metafile, GpPen *pen, DWORD *i } if (pen->customend) { - FIXME("ignoring custom end cup\n"); + data_flags |= PenDataCustomEndCap; + METAFILE_PrepareCustomLineCapData(pen->customend, &custom_end_cap_size, + &custom_end_cap_data_size, &custom_end_cap_path_size); + pen_data_size += custom_end_cap_size; } stat = METAFILE_PrepareBrushData(pen->brush, &brush_size); @@ -4919,6 +4923,13 @@ static GpStatus METAFILE_AddPenObject(GpMetafile *metafile, GpPen *pen, DWORD *i custom_start_cap_path_size); i += custom_start_cap_size; } + if (data_flags & PenDataCustomEndCap) + { + METAFILE_FillCustomLineCapData(pen->customend, pen_data->OptionalData + i, + pen->miterlimit, custom_end_cap_data_size, + custom_end_cap_path_size); + i += custom_end_cap_size; + } METAFILE_FillBrushData(pen->brush, (EmfPlusBrush*)(object_record->ObjectData.pen.data + pen_data_size)); From b46ffe0fe94df87abee5f33678221dba00ce7dda Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Wed, 3 May 2023 22:36:13 +0800 Subject: [PATCH 1277/2777] gdiplus: Support playing back pen custom start line cap. CW-Bug-Id: #22170 --- dlls/gdiplus/metafile.c | 124 +++++++++++++++++++++++++++++++++- dlls/gdiplus/tests/metafile.c | 1 - 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index e51b44e0f0a..d30c8c1a738 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -2347,6 +2347,122 @@ static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_si return status; } +static GpStatus metafile_deserialize_custom_line_cap(const BYTE *record_data, UINT data_size, GpCustomLineCap **cap) +{ + EmfPlusCustomStartCapData *custom_cap_data = (EmfPlusCustomStartCapData *)record_data; + EmfPlusCustomLineCap *line_cap; + GpStatus status; + UINT offset; + + *cap = NULL; + + if (data_size < FIELD_OFFSET(EmfPlusCustomStartCapData, data)) + return InvalidParameter; + if (data_size < FIELD_OFFSET(EmfPlusCustomStartCapData, data) + custom_cap_data->CustomStartCapSize) + return InvalidParameter; + offset = FIELD_OFFSET(EmfPlusCustomStartCapData, data); + line_cap = (EmfPlusCustomLineCap *)(record_data + offset); + + if (data_size < offset + FIELD_OFFSET(EmfPlusCustomLineCap, CustomLineCapData)) + return InvalidParameter; + offset += FIELD_OFFSET(EmfPlusCustomLineCap, CustomLineCapData); + + if (line_cap->Type == CustomLineCapTypeAdjustableArrow) + { + EmfPlusCustomLineCapArrowData *arrow_data; + GpAdjustableArrowCap *arrow_cap; + + arrow_data = (EmfPlusCustomLineCapArrowData *)(record_data + offset); + + if (data_size < offset + sizeof(EmfPlusCustomLineCapArrowData)) + return InvalidParameter; + + if ((status = GdipCreateAdjustableArrowCap(arrow_data->Height, arrow_data->Width, + arrow_data->FillState, &arrow_cap))) + return status; + + if ((status = GdipSetAdjustableArrowCapMiddleInset(arrow_cap, arrow_data->MiddleInset))) + goto arrow_cap_failed; + if ((status = GdipSetCustomLineCapStrokeCaps((GpCustomLineCap *)arrow_cap, arrow_data->LineStartCap, arrow_data->LineEndCap))) + goto arrow_cap_failed; + if ((status = GdipSetCustomLineCapStrokeJoin((GpCustomLineCap *)arrow_cap, arrow_data->LineJoin))) + goto arrow_cap_failed; + if ((status = GdipSetCustomLineCapWidthScale((GpCustomLineCap *)arrow_cap, arrow_data->WidthScale))) + goto arrow_cap_failed; + + *cap = (GpCustomLineCap *)arrow_cap; + return Ok; + + arrow_cap_failed: + GdipDeleteCustomLineCap((GpCustomLineCap *)arrow_cap); + return status; + } + else + { + GpPath *path, *fill_path = NULL, *stroke_path = NULL; + EmfPlusCustomLineCapData *line_cap_data; + GpCustomLineCap *line_cap = NULL; + GpStatus status; + + line_cap_data = (EmfPlusCustomLineCapData *)(record_data + offset); + + if (data_size < offset + FIELD_OFFSET(EmfPlusCustomLineCapData, OptionalData)) + return InvalidParameter; + offset += FIELD_OFFSET(EmfPlusCustomLineCapData, OptionalData); + + if (line_cap_data->CustomLineCapDataFlags == CustomLineCapDataFillPath) + { + EmfPlusCustomLineCapDataFillPath *fill_path = (EmfPlusCustomLineCapDataFillPath *)(record_data + offset); + + if (data_size < offset + FIELD_OFFSET(EmfPlusCustomLineCapDataFillPath, FillPath)) + return InvalidParameter; + if (data_size < offset + fill_path->FillPathLength) + return InvalidParameter; + + offset += FIELD_OFFSET(EmfPlusCustomLineCapDataFillPath, FillPath); + } + else + { + EmfPlusCustomLineCapDataLinePath *line_path = (EmfPlusCustomLineCapDataLinePath *)(record_data + offset); + + if (data_size < offset + FIELD_OFFSET(EmfPlusCustomLineCapDataLinePath, LinePath)) + return InvalidParameter; + if (data_size < offset + line_path->LinePathLength) + return InvalidParameter; + + offset += FIELD_OFFSET(EmfPlusCustomLineCapDataLinePath, LinePath); + } + + if ((status = metafile_deserialize_path(record_data + offset, data_size - offset, &path))) + return status; + + if (line_cap_data->CustomLineCapDataFlags == CustomLineCapDataFillPath) + fill_path = path; + else + stroke_path = path; + + if ((status = GdipCreateCustomLineCap(fill_path, stroke_path, line_cap_data->BaseCap, + line_cap_data->BaseInset, &line_cap))) + goto default_cap_failed; + if ((status = GdipSetCustomLineCapStrokeCaps(line_cap, line_cap_data->StrokeStartCap, line_cap_data->StrokeEndCap))) + goto default_cap_failed; + if ((status = GdipSetCustomLineCapStrokeJoin(line_cap, line_cap_data->StrokeJoin))) + goto default_cap_failed; + if ((status = GdipSetCustomLineCapWidthScale(line_cap, line_cap_data->WidthScale))) + goto default_cap_failed; + + GdipDeletePath(path); + *cap = line_cap; + return Ok; + + default_cap_failed: + if (line_cap) + GdipDeleteCustomLineCap(line_cap); + GdipDeletePath(path); + return status; + } +} + static GpStatus metafile_get_pen_brush_data_offset(EmfPlusPen *data, UINT data_size, DWORD *ret) { EmfPlusPenData *pendata = (EmfPlusPenData *)data->data; @@ -2453,6 +2569,7 @@ static GpStatus METAFILE_PlaybackObject(GpMetafile *metafile, UINT flags, UINT d { EmfPlusPen *data = (EmfPlusPen *)record_data; EmfPlusPenData *pendata = (EmfPlusPenData *)data->data; + GpCustomLineCap *custom_line_cap; GpBrush *brush; DWORD offset; GpPen *pen; @@ -2549,7 +2666,12 @@ static GpStatus METAFILE_PlaybackObject(GpMetafile *metafile, UINT flags, UINT d if (pendata->PenDataFlags & PenDataCustomStartCap) { EmfPlusCustomStartCapData *startcap = (EmfPlusCustomStartCapData *)((BYTE *)pendata + offset); - FIXME("PenDataCustomStartCap is not supported.\n"); + if ((status = metafile_deserialize_custom_line_cap((BYTE *)startcap, data_size, &custom_line_cap)) != Ok) + goto penfailed; + status = GdipSetPenCustomStartCap(pen, custom_line_cap); + GdipDeleteCustomLineCap(custom_line_cap); + if (status != Ok) + goto penfailed; offset += FIELD_OFFSET(EmfPlusCustomStartCapData, data) + startcap->CustomStartCapSize; } diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c index 48da5c648ef..909767edbee 100644 --- a/dlls/gdiplus/tests/metafile.c +++ b/dlls/gdiplus/tests/metafile.c @@ -3983,7 +3983,6 @@ static void test_pen(void) play_metafile(clone_metafile, graphics, pen_bitmap_records, "pen playback", dst_points, &frame, UnitPixel); color = GetPixel(hdc, 10, 10); - todo_wine expect(RGB(0xff, 0, 0), color); color = GetPixel(hdc, 40, 90); From b7d446cc252722c9f1b356c2fd2859e2593923b2 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Sun, 14 May 2023 15:23:04 +0800 Subject: [PATCH 1278/2777] gdiplus: Support playing back pen custom end line cap. Fix Cafe Stella (SteamID: 1829980) Flowchart crashes once there are 2 things on it. CW-Bug-Id: #22170 --- dlls/gdiplus/metafile.c | 7 ++++++- dlls/gdiplus/tests/metafile.c | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index d30c8c1a738..c86601c7a0a 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -2678,7 +2678,12 @@ static GpStatus METAFILE_PlaybackObject(GpMetafile *metafile, UINT flags, UINT d if (pendata->PenDataFlags & PenDataCustomEndCap) { EmfPlusCustomEndCapData *endcap = (EmfPlusCustomEndCapData *)((BYTE *)pendata + offset); - FIXME("PenDataCustomEndCap is not supported.\n"); + if ((status = metafile_deserialize_custom_line_cap((BYTE *)endcap, data_size, &custom_line_cap)) != Ok) + goto penfailed; + status = GdipSetPenCustomEndCap(pen, custom_line_cap); + GdipDeleteCustomLineCap(custom_line_cap); + if (status != Ok) + goto penfailed; offset += FIELD_OFFSET(EmfPlusCustomEndCapData, data) + endcap->CustomEndCapSize; } diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c index 909767edbee..ac10746f639 100644 --- a/dlls/gdiplus/tests/metafile.c +++ b/dlls/gdiplus/tests/metafile.c @@ -3986,7 +3986,6 @@ static void test_pen(void) expect(RGB(0xff, 0, 0), color); color = GetPixel(hdc, 40, 90); - todo_wine flaky /* Win10 + */ expect(RGB(0xff, 0, 0), color); From aac5294ee9d48097f6cffb0294fef910ce7ef428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 22 May 2023 10:52:06 +0200 Subject: [PATCH 1279/2777] dinput/tests: Test that FromGameController also works with IRawGameController. CW-Bug-Id: #22198 --- dlls/dinput/tests/joystick8.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 2d00d2e541c..2851c6baa52 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -4027,6 +4027,12 @@ static void test_windows_gaming_input(void) ok( tmp_raw_controller == raw_controller, "got unexpected IGameController interface\n" ); IRawGameController_Release( tmp_raw_controller ); + hr = IRawGameControllerStatics_FromGameController( controller_statics, (IGameController *)raw_controller, &tmp_raw_controller ); + ok( hr == S_OK, "FromGameController returned %#lx\n", hr ); + todo_wine + ok( tmp_raw_controller == raw_controller, "got unexpected IGameController interface\n" ); + if (tmp_raw_controller) IRawGameController_Release( tmp_raw_controller ); + IGameController_Release( game_controller ); IRawGameController_Release( raw_controller ); From 209f97b6c53eddbc664b85842e16ea0b711130ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 22 May 2023 10:56:51 +0200 Subject: [PATCH 1280/2777] windows.gaming.input: Query IGameController interface in TryGetFactoryControllerFromGameController. CW-Bug-Id: #22198 --- dlls/dinput/tests/hotplug.c | 2 +- dlls/dinput/tests/joystick8.c | 3 +-- dlls/windows.gaming.input/manager.c | 9 ++++++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/dlls/dinput/tests/hotplug.c b/dlls/dinput/tests/hotplug.c index cd21363770e..7187cf7dc38 100644 --- a/dlls/dinput/tests/hotplug.c +++ b/dlls/dinput/tests/hotplug.c @@ -1184,13 +1184,13 @@ static void test_windows_gaming_input(void) IGameController_Release( tmp_game_controller ); -next: hr = IRawGameControllerStatics_FromGameController( statics, custom_controller.IGameController_outer, &tmp_raw_controller ); ok( hr == S_OK, "FromGameController returned %#lx\n", hr ); todo_wine ok( tmp_raw_controller == raw_controller, "got controller %p\n", tmp_raw_controller ); if (tmp_raw_controller) IRawGameController_Release( tmp_raw_controller ); +next: IGameController_Release( game_controller ); IRawGameController_Release( raw_controller ); SetEvent( stop_event ); diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 2851c6baa52..847e0d6c195 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -4029,9 +4029,8 @@ static void test_windows_gaming_input(void) hr = IRawGameControllerStatics_FromGameController( controller_statics, (IGameController *)raw_controller, &tmp_raw_controller ); ok( hr == S_OK, "FromGameController returned %#lx\n", hr ); - todo_wine ok( tmp_raw_controller == raw_controller, "got unexpected IGameController interface\n" ); - if (tmp_raw_controller) IRawGameController_Release( tmp_raw_controller ); + IRawGameController_Release( tmp_raw_controller ); IGameController_Release( game_controller ); IRawGameController_Release( raw_controller ); diff --git a/dlls/windows.gaming.input/manager.c b/dlls/windows.gaming.input/manager.c index c2567a2fe3e..d54b01d92e3 100644 --- a/dlls/windows.gaming.input/manager.c +++ b/dlls/windows.gaming.input/manager.c @@ -372,14 +372,18 @@ statics2_TryGetFactoryControllerFromGameController( IGameControllerFactoryManage IGameController *controller, IGameController **value ) { struct controller *entry, *other; + IGameController *tmp_controller; BOOL found = FALSE; TRACE( "iface %p, factory %p, controller %p, value %p.\n", iface, factory, controller, value ); + /* Spider Man Remastered passes a IRawGameController instead of IGameController, query the iface again */ + if (FAILED(IGameController_QueryInterface( controller, &IID_IGameController, (void **)&tmp_controller ))) goto done; + EnterCriticalSection( &manager_cs ); LIST_FOR_EACH_ENTRY( entry, &controller_list, struct controller, entry ) - if ((found = &entry->IGameController_iface == controller)) break; + if ((found = &entry->IGameController_iface == tmp_controller)) break; if (!found) WARN( "Failed to find controller %p\n", controller ); else @@ -392,6 +396,9 @@ statics2_TryGetFactoryControllerFromGameController( IGameControllerFactoryManage LeaveCriticalSection( &manager_cs ); + IGameController_Release( tmp_controller ); + +done: if (!found) *value = NULL; return S_OK; } From 0e9392f150a8300a608c20fff5cf7168fb5b400a Mon Sep 17 00:00:00 2001 From: Michael Stefaniuc Date: Thu, 30 Mar 2023 19:20:44 +0200 Subject: [PATCH 1281/2777] dinput/tests: Drop superfluous TRUE : FALSE conditional expressions. (cherry picked from commit 567e35ceaf4bbf23c91d545d7a15c75dada6a424) CW-Bug-Id: #22257 --- dlls/dinput/tests/force_feedback.c | 2 +- dlls/dinput/tests/joystick8.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c index 5ffc6a43471..0e9d396996c 100644 --- a/dlls/dinput/tests/force_feedback.c +++ b/dlls/dinput/tests/force_feedback.c @@ -2950,7 +2950,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .expect_count = version < 0x700 ? ARRAY_SIZE(expect_objects_5) : ARRAY_SIZE(expect_objects), .expect_objs = version < 0x700 ? expect_objects_5 : expect_objects, .todo_objs = version < 0x700 ? todo_objects_5 : NULL, - .todo_extra = version < 0x700 ? TRUE : FALSE, + .todo_extra = version < 0x700, }; struct check_effects_params check_effects_params = { diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 847e0d6c195..c757a3fe628 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -734,7 +734,7 @@ static void test_simple_joystick( DWORD version ) .expect_count = version < 0x700 ? ARRAY_SIZE(expect_objects_5) : ARRAY_SIZE(expect_objects), .expect_objs = version < 0x700 ? expect_objects_5 : expect_objects, .todo_objs = version < 0x700 ? todo_objects_5 : NULL, - .todo_extra = version < 0x700 ? TRUE : FALSE, + .todo_extra = version < 0x700, }; const DIEFFECTINFOW expect_effects[] = {}; From 5c367698066b1c35a8da2a956f11f646b85c6d47 Mon Sep 17 00:00:00 2001 From: Florian Will Date: Tue, 4 Apr 2023 08:25:53 +0200 Subject: [PATCH 1282/2777] dinput/tests: Add guidType test for collection objects. (cherry picked from commit 4413356d19dadbe7027cdfec1a45020246a51355) CW-Bug-Id: #22257 --- dlls/dinput/tests/joystick8.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index c757a3fe628..7efb0b48376 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -403,6 +403,11 @@ static void test_simple_joystick( DWORD version ) REPORT_COUNT(1, 4), INPUT(1, Data|Var|Abs), END_COLLECTION, + + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_RZ), + COLLECTION(1, Physical), + END_COLLECTION, END_COLLECTION, }; C_ASSERT(sizeof(report_desc) < MAX_HID_DESCRIPTOR_LEN); @@ -632,6 +637,14 @@ static void test_simple_joystick( DWORD version ) .wUsagePage = HID_USAGE_PAGE_GENERIC, .wUsage = HID_USAGE_GENERIC_JOYSTICK, }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(2), + .tszName = L"Collection 2 - Z Rotation", + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_RZ, + }, }; const DIDEVICEOBJECTINSTANCEW expect_objects_5[] = { @@ -717,6 +730,21 @@ static void test_simple_joystick( DWORD version ) .wReportId = 1, }, }; + struct check_object_todo todo_objects[ARRAY_SIZE(expect_objects)] = + { + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + { .guid = TRUE }, + }; struct check_object_todo todo_objects_5[ARRAY_SIZE(expect_objects_5)] = { {.guid = TRUE, .type = TRUE, .flags = TRUE, .usage = TRUE, .usage_page = TRUE, .name = TRUE}, @@ -733,7 +761,7 @@ static void test_simple_joystick( DWORD version ) .version = version, .expect_count = version < 0x700 ? ARRAY_SIZE(expect_objects_5) : ARRAY_SIZE(expect_objects), .expect_objs = version < 0x700 ? expect_objects_5 : expect_objects, - .todo_objs = version < 0x700 ? todo_objects_5 : NULL, + .todo_objs = version < 0x700 ? todo_objects_5 : todo_objects, .todo_extra = version < 0x700, }; From 9df62bb92bde4cc50d87af55fb17ee387a5c276e Mon Sep 17 00:00:00 2001 From: Florian Will Date: Tue, 4 Apr 2023 09:32:16 +0200 Subject: [PATCH 1283/2777] dinput: Set guidType = GUID_Unknown for HID collections. Fixes an issue in Zusi 3 where DIDFT_COLLECTION objects would be passed to SetDataFormat. (cherry picked from commit ba889f2c4c4e17007653bf9a93e58787859358e2) CW-Bug-Id: #22257 --- dlls/dinput/joystick_hid.c | 2 +- dlls/dinput/tests/joystick8.c | 17 +---------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index e4fe64c0e81..349644df633 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -774,7 +774,7 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, instance.dwFlags = 0; instance.wUsagePage = node->usage_page; instance.wUsage = node->usage; - instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage ); + instance.guidType = GUID_Unknown; instance.wReportId = 0; instance.wCollectionNumber = node->parent; instance.dwDimension = 0; diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 7efb0b48376..0496185b006 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -730,21 +730,6 @@ static void test_simple_joystick( DWORD version ) .wReportId = 1, }, }; - struct check_object_todo todo_objects[ARRAY_SIZE(expect_objects)] = - { - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - {0}, - { .guid = TRUE }, - }; struct check_object_todo todo_objects_5[ARRAY_SIZE(expect_objects_5)] = { {.guid = TRUE, .type = TRUE, .flags = TRUE, .usage = TRUE, .usage_page = TRUE, .name = TRUE}, @@ -761,7 +746,7 @@ static void test_simple_joystick( DWORD version ) .version = version, .expect_count = version < 0x700 ? ARRAY_SIZE(expect_objects_5) : ARRAY_SIZE(expect_objects), .expect_objs = version < 0x700 ? expect_objects_5 : expect_objects, - .todo_objs = version < 0x700 ? todo_objects_5 : todo_objects, + .todo_objs = version < 0x700 ? todo_objects_5 : NULL, .todo_extra = version < 0x700, }; From b3b9669d8d7ab5c358544b2c25ac82754a084231 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 22 Mar 2023 11:11:17 -0600 Subject: [PATCH 1284/2777] fixup! winevulkan: HACK: Add WINE_HIDE_VANGOGH_GPU environment variable. --- dlls/winex11.drv/display.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c index fe6a5b873f1..88c96d52c1e 100644 --- a/dlls/winex11.drv/display.c +++ b/dlls/winex11.drv/display.c @@ -601,6 +601,12 @@ BOOL X11DRV_UpdateDisplayDevices( const struct gdi_device_manager *device_manage gpus[gpu].device_id = 0x67df; /* RX 480 */ } } + if (gpus[gpu].vendor_id == 0x1002 && gpus[gpu].device_id == 0x163f + && (sgi = getenv("WINE_HIDE_VANGOGH_GPU")) && *sgi != '0') + { + FIXME("HACK: hiding Vangogh GPU.\n"); + gpus[gpu].device_id = 0x687f; /* Radeon RX Vega 56/64 */ + } } device_manager->add_gpu( &gpus[gpu], param ); From d764f4978e3aa62e8236a9b58acbb540c862627f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 6 Apr 2023 17:50:54 -0600 Subject: [PATCH 1285/2777] wine.inf: Set amd_ags_x64 to built-in for SoPFFO. CW-Bug-Id: #22117 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index cdece7d2b22..31907416078 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2847,6 +2847,7 @@ HKCU,Software\Wine\AppDefaults\Sam4_Unrestricted.exe\DllOverrides,"amd_ags_x64", HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"amd_ags_x64",,"disabled" HKCU,Software\Wine\AppDefaults\u4.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\tll.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" +HKCU,Software\Wine\AppDefaults\SOPFFO.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" ;;App-specific overrides for atiadlxx.dll. HKCU,Software\Wine\AppDefaults\s2_sp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\s2_mp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" From ca7f5b9d64cdab669757f02d2b96843590bb817a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 27 Feb 2023 17:07:58 -0600 Subject: [PATCH 1286/2777] wined3d: Do not switch pixel format on non-private GL contexts. CW-Bug-Id: #21749 --- dlls/wined3d/context_gl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/wined3d/context_gl.c b/dlls/wined3d/context_gl.c index 0217e12d903..97118991821 100644 --- a/dlls/wined3d/context_gl.c +++ b/dlls/wined3d/context_gl.c @@ -1212,6 +1212,9 @@ static BOOL wined3d_context_gl_set_pixel_format(struct wined3d_context_gl *conte current = gl_info->gl_ops.wgl.p_wglGetPixelFormat(dc); if (current == format) goto success; + if (current && !private) + return FALSE; + /* By default WGL doesn't allow pixel format adjustments but we need it * here. For this reason there's a Wine specific wglSetPixelFormat() * which allows us to set the pixel format multiple times. Use it when we From 7ccce68a3c21e7d89f0ba306b08d29f6811a190c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 27 Apr 2023 16:53:17 -0600 Subject: [PATCH 1287/2777] fsync: Cache current process ID. CW-Bug-Id: #22194 --- dlls/ntdll/unix/fsync.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index ba85862fcc2..ed2c334610f 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -60,6 +60,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(fsync); #include "pshpack4.h" #include "poppack.h" +static int current_pid; + /* futex_waitv interface */ #ifndef __NR_futex_waitv @@ -349,7 +351,7 @@ static void put_object_from_wait( struct fsync *obj ) { int *shm = obj->shm; - __sync_val_compare_and_swap( &shm[3], GetCurrentProcessId(), 0 ); + __sync_val_compare_and_swap( &shm[3], current_pid, 0 ); put_object( obj ); } @@ -448,7 +450,7 @@ static NTSTATUS get_object_for_wait( HANDLE handle, struct fsync *obj ) shm = obj->shm; /* Give wineserver a chance to cleanup shm index if the process * is killed while we are waiting on the object. */ - __atomic_store_n( &shm[3], GetCurrentProcessId(), __ATOMIC_SEQ_CST ); + __atomic_store_n( &shm[3], current_pid, __ATOMIC_SEQ_CST ); return STATUS_SUCCESS; } @@ -578,6 +580,9 @@ void fsync_init(void) ERR("Failed to initialize shared memory: %s\n", strerror( errno )); exit(1); } + + current_pid = GetCurrentProcessId(); + assert(current_pid); } NTSTATUS fsync_create_semaphore( HANDLE *handle, ACCESS_MASK access, From d00022a765f54b7d01e5dbc1c3a3a1e0ac82d1f0 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 27 Apr 2023 16:56:26 -0600 Subject: [PATCH 1288/2777] fsync: Cache current TID in __fsync_wait_objects(). CW-Bug-Id: #22194 --- dlls/ntdll/unix/fsync.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index ed2c334610f..479a7a6baf4 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -885,6 +885,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, { static const LARGE_INTEGER zero = {0}; + int current_tid = 0; +#define CURRENT_TID (current_tid ? current_tid : (current_tid = GetCurrentThreadId())) + struct futex_waitv futexes[MAXIMUM_WAIT_OBJECTS + 1]; struct fsync objs[MAXIMUM_WAIT_OBJECTS]; BOOL msgwait = FALSE, waited = FALSE; @@ -1015,7 +1018,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, struct mutex *mutex = obj->shm; int tid; - if (mutex->tid == GetCurrentThreadId()) + if (mutex->tid == CURRENT_TID) { TRACE("Woken up by handle %p [%d].\n", handles[i], i); mutex->count++; @@ -1024,7 +1027,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, return i; } - if (!(tid = __sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() ))) + if (!(tid = __sync_val_compare_and_swap( &mutex->tid, 0, CURRENT_TID ))) { TRACE("Woken up by handle %p [%d].\n", handles[i], i); mutex->count = 1; @@ -1032,7 +1035,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, put_objects( objs, count ); return i; } - else if (tid == ~0 && (tid = __sync_val_compare_and_swap( &mutex->tid, ~0, GetCurrentThreadId() )) == ~0) + else if (tid == ~0 && (tid = __sync_val_compare_and_swap( &mutex->tid, ~0, CURRENT_TID )) == ~0) { TRACE("Woken up by abandoned mutex %p [%d].\n", handles[i], i); mutex->count = 1; @@ -1171,7 +1174,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, { struct mutex *mutex = obj->shm; - if (mutex->tid == GetCurrentThreadId()) + if (mutex->tid == CURRENT_TID) continue; while ((current = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ))) @@ -1215,7 +1218,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, struct mutex *mutex = obj->shm; int tid = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ); - if (tid && tid != ~0 && tid != GetCurrentThreadId()) + if (tid && tid != ~0 && tid != CURRENT_TID) goto tryagain; } else if (obj->type) @@ -1238,11 +1241,11 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, { struct mutex *mutex = obj->shm; int tid = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ); - if (tid == GetCurrentThreadId()) + if (tid == CURRENT_TID) break; if (tid && tid != ~0) goto tooslow; - if (__sync_val_compare_and_swap( &mutex->tid, tid, GetCurrentThreadId() ) != tid) + if (__sync_val_compare_and_swap( &mutex->tid, tid, CURRENT_TID ) != tid) goto tooslow; if (tid == ~0) abandoned = TRUE; @@ -1352,6 +1355,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, * right thing to do seems to be to return STATUS_USER_APC anyway. */ if (ret == STATUS_TIMEOUT) ret = STATUS_USER_APC; return ret; +#undef CURRENT_TID } /* Like esync, we need to let the server know when we are doing a message wait, From e2f18ede64bd44779c87c2908203e150c900eb58 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 27 Apr 2023 17:32:38 -0600 Subject: [PATCH 1289/2777] fsync: Add WINE_FSYNC_YIELD_TO_WAITERS option. CW-Bug-Id: #22194 --- dlls/ntdll/unix/fsync.c | 37 +++++++++++++++++++++++++++++++--- dlls/ntdll/unix/loader.c | 8 ++++++++ dlls/ntdll/unix/unix_private.h | 1 + 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 479a7a6baf4..b4d4b086919 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -440,7 +440,7 @@ static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) return ret; } -static NTSTATUS get_object_for_wait( HANDLE handle, struct fsync *obj ) +static NTSTATUS get_object_for_wait( HANDLE handle, struct fsync *obj, int *prev_pid ) { NTSTATUS ret; int *shm; @@ -450,7 +450,10 @@ static NTSTATUS get_object_for_wait( HANDLE handle, struct fsync *obj ) shm = obj->shm; /* Give wineserver a chance to cleanup shm index if the process * is killed while we are waiting on the object. */ - __atomic_store_n( &shm[3], current_pid, __ATOMIC_SEQ_CST ); + if (fsync_yield_to_waiters) + *prev_pid = __atomic_exchange_n( &shm[3], current_pid, __ATOMIC_SEQ_CST ); + else + __atomic_store_n( &shm[3], current_pid, __ATOMIC_SEQ_CST ); return STATUS_SUCCESS; } @@ -837,6 +840,24 @@ NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) return STATUS_SUCCESS; } +static inline void try_yield_to_waiters( int prev_pid ) +{ + if (!fsync_yield_to_waiters) return; + + /* On Windows singaling an object will wake the threads waiting on the object. With fsync + * it may happen that signaling thread (or other thread) grabs the object before the already waiting + * thread gets a chance. Try to workaround that for the affected apps. Non-zero 'prev_pid' indicates + * that the object is grabbed in __fsync_wait_objects() by some other thread. It is the same for + * a non-current pid, but we may currently have a stale PID on an object from a terminated process + * and it is probably safer to skip this workaround. This won't work great if the object is used in 'wait all' + * and the waiter is blocked on the other object. + * This check is also not entirely reliable as if multiple waiters from the same process enter + * __fsync_wait_objects() the first one leaving will clear 'last_pid' in the object. */ + + if (prev_pid == current_pid) + usleep(0); +} + static NTSTATUS do_single_wait( int *addr, int val, const struct timespec64 *end, clockid_t clock_id, BOOLEAN alertable ) { @@ -891,6 +912,7 @@ 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 prev_pids[MAXIMUM_WAIT_OBJECTS]; int has_fsync = 0, has_server = 0; clockid_t clock_id = 0; struct timespec64 end; @@ -921,7 +943,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, for (i = 0; i < count; i++) { - ret = get_object_for_wait( handles[i], &objs[i] ); + ret = get_object_for_wait( handles[i], &objs[i], &prev_pids[i] ); if (ret == STATUS_SUCCESS) { assert( objs[i].type ); @@ -1000,6 +1022,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, int current, new; new = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST ); + if (!waited && new) + try_yield_to_waiters(prev_pids[i]); + while ((current = new)) { if ((new = __sync_val_compare_and_swap( &semaphore->count, current, current - 1 )) == current) @@ -1027,6 +1052,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, return i; } + if (!waited && !mutex->tid) + try_yield_to_waiters(prev_pids[i]); + if (!(tid = __sync_val_compare_and_swap( &mutex->tid, 0, CURRENT_TID ))) { TRACE("Woken up by handle %p [%d].\n", handles[i], i); @@ -1051,6 +1079,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, { struct event *event = obj->shm; + if (!waited && event->signaled) + try_yield_to_waiters(prev_pids[i]); + if (__sync_val_compare_and_swap( &event->signaled, 1, 0 )) { if (ac_odyssey && alertable) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index d1fda7a6e5a..dd16a630bf2 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2278,6 +2278,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = BOOL ac_odyssey; BOOL fsync_simulate_sched_quantum; BOOL alert_simulate_sched_quantum; +BOOL fsync_yield_to_waiters; BOOL no_priv_elevation; BOOL localsystem_sid; BOOL high_dll_addresses; @@ -2340,6 +2341,13 @@ static void hacks_init(void) ERR("HACK: moving dlls to high addresses.\n"); #endif + env_str = getenv("WINE_FSYNC_YIELD_TO_WAITERS"); + if (env_str) + fsync_yield_to_waiters = !!atoi(env_str); + if (fsync_yield_to_waiters) + ERR("HACK: fsync: yield to waiters.\n"); + + env_str = getenv("WINE_SIMULATE_WRITECOPY"); if (env_str) simulate_writecopy = atoi(env_str); else if (sgi) simulate_writecopy = !strcmp(sgi, "1608730") /* Dawn of Corruption */ diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 471f7377233..63ed982be92 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -152,6 +152,7 @@ extern struct ldt_copy __wine_ldt_copy DECLSPEC_HIDDEN; extern BOOL ac_odyssey DECLSPEC_HIDDEN; extern BOOL fsync_simulate_sched_quantum DECLSPEC_HIDDEN; extern BOOL alert_simulate_sched_quantum DECLSPEC_HIDDEN; +extern BOOL fsync_yield_to_waiters; extern BOOL no_priv_elevation DECLSPEC_HIDDEN; extern BOOL localsystem_sid DECLSPEC_HIDDEN; extern BOOL high_dll_addresses DECLSPEC_HIDDEN; From ebfae0290dd98cae4dc5c15201e027b960774850 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 27 Apr 2023 18:19:01 -0600 Subject: [PATCH 1290/2777] ntdll: HACK: Enable WINE_FSYNC_YIELD_TO_WAITERS for FFXIII. CW-Bug-Id: #22194 --- dlls/ntdll/unix/loader.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index dd16a630bf2..9c5aa5122a3 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2344,6 +2344,7 @@ static void hacks_init(void) env_str = getenv("WINE_FSYNC_YIELD_TO_WAITERS"); if (env_str) fsync_yield_to_waiters = !!atoi(env_str); + else if (sgi) fsync_yield_to_waiters = !strcmp(sgi, "292120"); if (fsync_yield_to_waiters) ERR("HACK: fsync: yield to waiters.\n"); From 10caabc9be58bfdf5358fb8c0f81fe72a04de70b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 28 Apr 2023 14:44:16 -0600 Subject: [PATCH 1291/2777] ntdll: HACK: Abort process on syscall fault when terminating. CW-Bug-Id: #22206 --- dlls/ntdll/unix/process.c | 12 ++++++++++++ dlls/ntdll/unix/signal_x86_64.c | 6 ++++++ dlls/ntdll/unix/unix_private.h | 2 ++ 3 files changed, 20 insertions(+) diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c index 4b9c42467e7..3e3c24c702c 100644 --- a/dlls/ntdll/unix/process.c +++ b/dlls/ntdll/unix/process.c @@ -938,6 +938,8 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_ return status; } +BOOL terminate_process_running; +LONG terminate_process_exit_code; /****************************************************************************** * NtTerminateProcess (NTDLL.@) @@ -947,6 +949,14 @@ NTSTATUS WINAPI NtTerminateProcess( HANDLE handle, LONG exit_code ) unsigned int ret; BOOL self; + TRACE("handle %p, exit_code %d, process_exiting %d.\n", handle, (int)exit_code, process_exiting); + + if (handle == GetCurrentProcess()) + { + terminate_process_running = TRUE; + terminate_process_exit_code = exit_code; + } + SERVER_START_REQ( terminate_process ) { req->handle = wine_server_obj_handle( handle ); @@ -955,6 +965,8 @@ NTSTATUS WINAPI NtTerminateProcess( HANDLE handle, LONG exit_code ) self = reply->self; } SERVER_END_REQ; + + TRACE("handle %p, self %d, process_exiting %d.\n", handle, self, process_exiting); if (self) { if (!handle) process_exiting = TRUE; diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 7685ca7852b..900eedb20e7 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2201,6 +2201,12 @@ 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 (terminate_process_running) + { + FIXME_(seh)( "Process is terminating, aborting.\n" ); + abort_process( terminate_process_exit_code ); + } + if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION && is_inside_syscall_stack_guard( (char *)rec->ExceptionInformation[1] )) ERR_(seh)( "Syscall stack overrun.\n "); diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 63ed982be92..e564b34e14e 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -137,6 +137,8 @@ extern const WCHAR system_dir[] DECLSPEC_HIDDEN; extern unsigned int supported_machines_count DECLSPEC_HIDDEN; extern USHORT supported_machines[8] DECLSPEC_HIDDEN; extern BOOL process_exiting DECLSPEC_HIDDEN; +extern BOOL terminate_process_running; +extern LONG terminate_process_exit_code; extern HANDLE keyed_event DECLSPEC_HIDDEN; extern timeout_t server_start_time DECLSPEC_HIDDEN; extern sigset_t server_block_set DECLSPEC_HIDDEN; From 422a6dbc716c65cead5286add013581983dcaf2a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 1 May 2023 21:19:09 -0600 Subject: [PATCH 1292/2777] ntdll: HACK: Set thread teb earlier in start_main_thread(). CW-Bug-Id: #22218 --- dlls/ntdll/unix/loader.c | 3 +++ dlls/ntdll/unix/signal_i386.c | 6 ++++++ dlls/ntdll/unix/signal_x86_64.c | 4 ++++ dlls/ntdll/unix/unix_private.h | 1 + 4 files changed, 14 insertions(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 9c5aa5122a3..e0e5006f498 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2412,6 +2412,9 @@ static void start_main_thread(void) virtual_map_user_shared_data(); init_cpu_info(); init_files(); + + set_thread_teb( teb ); + load_libwine(); init_startup_info(); if (p___wine_main_argc) *p___wine_main_argc = main_argc; diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index abbfe7e11bd..c7e59702e2b 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -2345,6 +2345,12 @@ void signal_init_threading(void) #endif } +void set_thread_teb( TEB *teb ) +{ + struct x86_thread_data *thread_data = (struct x86_thread_data *)&teb->GdiTebBatch; + + ldt_set_fs( thread_data->fs, teb ); +} /********************************************************************** * signal_alloc_thread diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 900eedb20e7..ec5535c742a 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2830,6 +2830,10 @@ void signal_init_process(void) exit(1); } +void set_thread_teb( TEB *teb ) +{ + arch_prctl( ARCH_SET_GS, teb ); +} /*********************************************************************** * call_init_thunk diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index e564b34e14e..ef2b7ab665e 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -254,6 +254,7 @@ extern BOOL get_thread_times( int unix_pid, int unix_tid, LARGE_INTEGER *kernel_ LARGE_INTEGER *user_time ) DECLSPEC_HIDDEN; extern void signal_init_threading(void) DECLSPEC_HIDDEN; extern NTSTATUS signal_alloc_thread( TEB *teb ) DECLSPEC_HIDDEN; +extern void set_thread_teb( TEB *teb ) DECLSPEC_HIDDEN; extern void signal_free_thread( TEB *teb ) DECLSPEC_HIDDEN; extern void signal_init_process(void) DECLSPEC_HIDDEN; extern void DECLSPEC_NORETURN signal_start_thread( PRTL_THREAD_START_ROUTINE entry, void *arg, From e930e5c0b12355948f38b61611c1d706f15d7917 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 3 May 2023 17:23:40 -0600 Subject: [PATCH 1293/2777] ntdll: Do not inherit Unix std handles for files without a name. CW-Bug-Id: #22237 --- dlls/ntdll/unix/env.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c index 9e5abc3c4fe..196edaa0d06 100644 --- a/dlls/ntdll/unix/env.c +++ b/dlls/ntdll/unix/env.c @@ -1383,6 +1383,27 @@ static void add_registry_environment( WCHAR **env, SIZE_T *pos, SIZE_T *size ) } } +static void get_std_handle( int fd, unsigned int access, unsigned int attributes, HANDLE *handle ) +{ + IO_STATUS_BLOCK io; + FILE_POSITION_INFORMATION pos_info; + FILE_NAME_INFORMATION name_info; + NTSTATUS status; + + wine_server_fd_to_handle( fd, access, attributes, handle ); + if (!*handle) return; + + /* Python checks if a file is seekable and if so expects the file name to be gettable from handle. */ + if (NtQueryInformationFile( *handle, &io, &pos_info, sizeof(pos_info), FilePositionInformation )) + return; + + TRACE("handle for fd %d is seekable.\n", fd); + if (!(status = NtQueryInformationFile( *handle, &io, &name_info, sizeof(name_info), FileNameInformation )) + || status == STATUS_BUFFER_OVERFLOW) return; + TRACE("closing handle for fd %d.\n", fd); + NtClose( *handle ); + *handle = NULL; +} /************************************************************************* * get_initial_console @@ -1393,9 +1414,9 @@ static void get_initial_console( RTL_USER_PROCESS_PARAMETERS *params ) { int output_fd = -1; - wine_server_fd_to_handle( 0, GENERIC_READ|SYNCHRONIZE, OBJ_INHERIT, ¶ms->hStdInput ); - wine_server_fd_to_handle( 1, GENERIC_WRITE|SYNCHRONIZE, OBJ_INHERIT, ¶ms->hStdOutput ); - wine_server_fd_to_handle( 2, GENERIC_WRITE|SYNCHRONIZE, OBJ_INHERIT, ¶ms->hStdError ); + get_std_handle( 0, GENERIC_READ|SYNCHRONIZE, OBJ_INHERIT, ¶ms->hStdInput ); + get_std_handle( 1, GENERIC_WRITE|SYNCHRONIZE, OBJ_INHERIT, ¶ms->hStdOutput ); + get_std_handle( 2, GENERIC_WRITE|SYNCHRONIZE, OBJ_INHERIT, ¶ms->hStdError ); /* mark tty handles for kernelbase, see init_console */ if (params->hStdInput && isatty(0)) From 3cdab6ca4f5bff6020812de5b7551e1d68e46d52 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 21 Feb 2023 10:40:19 -0600 Subject: [PATCH 1294/2777] winex11.drv: Use hwnd from surface in X11DRV_query_fs_hack(). CW-Bug-Id: #21902 --- dlls/winex11.drv/vulkan.c | 7 +++++-- dlls/winex11.drv/window.c | 2 -- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 3e260adcd04..3c67be599f9 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -1137,9 +1137,12 @@ static VkBool32 X11DRV_query_fs_hack( VkSurfaceKHR surface, VkExtent2D *real_sz, if (wm_is_steamcompmgr( gdi_display )) return VK_FALSE; if (x11_surface->other_process) return VK_FALSE; - if (XFindContext( gdi_display, x11_surface->window, winContext, (char **)&hwnd ) != 0) + if (x11_surface->other_process) + return VK_FALSE; + + if (!(hwnd = x11_surface->hwnd)) { - ERR( "Failed to find hwnd context\n" ); + TRACE("No window.\n"); return VK_FALSE; } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 47abd189860..ed348a82dec 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1957,8 +1957,6 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual ) if (data->client_window) { XSaveContext( data->display, data->client_window, winContext, (char *)data->hwnd ); - /* Save to gdi_display as well for fullscreen hack, needed in X11DRV_query_fs_hack() */ - XSaveContext( gdi_display, data->client_window, winContext, (char *)data->hwnd ); XMapWindow( gdi_display, data->client_window ); XSync( gdi_display, False ); if (data->whole_window) XSelectInput( data->display, data->client_window, ExposureMask ); From 836347bb0386146b61b4c61ddf67f1f10659587b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 17 Feb 2023 17:21:34 -0600 Subject: [PATCH 1295/2777] winex11.drv: Do not release Vulkan surface when detaching window. CW-Bug-Id: #16608 CW-Bug-Id: #21902 CW-Bug-Id: #21817 --- dlls/winex11.drv/opengl.c | 2 +- dlls/winex11.drv/vulkan.c | 30 ++++++++++++++++++++++++------ dlls/winex11.drv/window.c | 5 +++-- dlls/winex11.drv/x11drv.h | 2 +- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 83af8a52dd6..1ba33627e10 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1505,7 +1505,7 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel if (gl->layered_type) { - detach_client_window( hwnd ); + detach_client_window( hwnd, 0 ); gl->type = DC_GL_PIXMAP_WIN; gl->pixmap = XCreatePixmap( gdi_display, root_window, width, height, visual->depth ); if (gl->pixmap) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 3c67be599f9..be1cb95afd9 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -223,15 +223,22 @@ static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo static struct wine_vk_surface *wine_vk_surface_grab(struct wine_vk_surface *surface) { - InterlockedIncrement(&surface->ref); + int refcount = InterlockedIncrement(&surface->ref); + TRACE("surface %p, refcount %d.\n", surface, refcount); return surface; } static void wine_vk_surface_release(struct wine_vk_surface *surface) { - if (InterlockedDecrement(&surface->ref)) + int refcount = InterlockedDecrement(&surface->ref); + + TRACE("surface %p, refcount %d.\n", surface, refcount); + + if (refcount) return; + TRACE("Destroying vk surface %p.\n", surface); + if (surface->entry.next) { pthread_mutex_lock(&vulkan_mutex); @@ -242,7 +249,19 @@ static void wine_vk_surface_release(struct wine_vk_surface *surface) if (surface->draw_dc) NtGdiDeleteObjectApp(surface->draw_dc); if (surface->window) + { + struct x11drv_win_data *data; + if (surface->hwnd && (data = get_win_data( surface->hwnd ))) + { + if (data->client_window == surface->window) + { + XDeleteContext( data->display, data->client_window, winContext ); + data->client_window = 0; + } + release_win_data( data ); + } XDestroyWindow(gdi_display, surface->window); + } if (surface->client_colormap) XFreeColormap( gdi_display, surface->client_colormap ); @@ -252,12 +271,11 @@ static void wine_vk_surface_release(struct wine_vk_surface *surface) void wine_vk_surface_destroy(struct wine_vk_surface *surface) { TRACE("Detaching surface %p, hwnd %p.\n", surface, surface->hwnd); - XReparentWindow(gdi_display, surface->window, get_dummy_parent(), 0, 0); - XSync(gdi_display, False); + if (surface->window) + detach_client_window( surface->hwnd, surface->window ); surface->hwnd_thread_id = 0; surface->hwnd = 0; - wine_vk_surface_release(surface); } void destroy_vk_surface(HWND hwnd) @@ -668,7 +686,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, list_add_tail(&surface_list, &x11_surface->entry); pthread_mutex_unlock(&vulkan_mutex); - *surface = (uintptr_t)wine_vk_surface_grab(x11_surface); + *surface = (uintptr_t)x11_surface; if (x11_surface->gdi_blit_source && !x11_surface->other_process) { diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index ed348a82dec..07b7725c63d 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1855,13 +1855,13 @@ void update_client_window( HWND hwnd ) /********************************************************************** * detach_client_window */ -void detach_client_window( HWND hwnd ) +void detach_client_window( HWND hwnd, Window window ) { struct x11drv_win_data *data; if (!(data = get_win_data( hwnd ))) return; - if (!data->client_window) + if (!data->client_window || (window && data->client_window != window)) { release_win_data( data ); return; @@ -1872,6 +1872,7 @@ void detach_client_window( HWND hwnd ) TRACE( "%p reparent xwin %lx/%lx\n", data->hwnd, data->whole_window, data->client_window ); data->client_window = 0; XFlush( data->display ); + XSync( gdi_display, False ); release_win_data( data ); } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 9013ae595fd..54e86b4f6e0 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -691,7 +691,7 @@ extern void make_window_embedded( struct x11drv_win_data *data ) DECLSPEC_HIDDEN extern Window create_dummy_client_window(void) DECLSPEC_HIDDEN; extern Window create_client_window( HWND hwnd, const XVisualInfo *visual ) DECLSPEC_HIDDEN; extern void update_client_window( HWND hwnd ) DECLSPEC_HIDDEN; -extern void detach_client_window( HWND hwnd ) DECLSPEC_HIDDEN; +extern void detach_client_window( HWND hwnd, Window window ) DECLSPEC_HIDDEN; extern void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *vis, BOOL use_alpha ) DECLSPEC_HIDDEN; extern void change_systray_owner( Display *display, Window systray_window ) DECLSPEC_HIDDEN; extern HWND create_foreign_window( Display *display, Window window ) DECLSPEC_HIDDEN; From ad6bc9d37dd981c53cf1b5a065a970900542cc8a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 21 Feb 2023 10:52:52 -0600 Subject: [PATCH 1296/2777] winex11.drv: Do not delete winContext in create_client_window(). When there are multiple Vulkan surfaces for window there are multiple client windows but they still belong to hwnd. CW-Bug-Id: #21902 --- dlls/winex11.drv/opengl.c | 4 +--- dlls/winex11.drv/window.c | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 1ba33627e10..b9cfb845163 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1309,11 +1309,9 @@ static void release_gl_drawable( struct gl_drawable *gl ) TRACE( "destroying %lx drawable %lx\n", gl->window, gl->drawable ); if (data) { + XDeleteContext( data->display, data->client_window, winContext ); if (data->client_window == gl->window) - { - XDeleteContext( data->display, data->client_window, winContext ); data->client_window = 0; - } release_win_data( data ); } pglXDestroyWindow( gdi_display, gl->drawable ); diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 07b7725c63d..1f153677cda 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1918,7 +1918,6 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual ) if (data->client_window) { - XDeleteContext( data->display, data->client_window, winContext ); XReparentWindow( gdi_display, data->client_window, dummy_parent, 0, 0 ); TRACE( "%p reparent xwin %lx/%lx\n", data->hwnd, data->whole_window, data->client_window ); } From 08855dc7aa9a3d26089406ef300d88e23d1e5925 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 17 Feb 2023 16:15:06 -0600 Subject: [PATCH 1297/2777] winex11.drv: Don't use offscreen rendering for multiple Vulkan swapchains. Instead, switch the client window if the last presented swapchain has a different one. CW-Bug-Id: #21902 --- dlls/winex11.drv/vulkan.c | 63 ++++------------------------------ dlls/winex11.drv/window.c | 56 ++++++++++++++++++++---------- dlls/winex11.drv/x11drv.h | 3 +- dlls/winex11.drv/x11drv_main.c | 12 ++++++- 4 files changed, 56 insertions(+), 78 deletions(-) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index be1cb95afd9..bc447f794f0 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -66,7 +66,6 @@ struct wine_vk_surface VkPresentModeKHR present_mode; BOOL known_child; /* hwnd is or has a child */ BOOL offscreen; /* drawable is offscreen */ - LONG swapchain_count; /* surface can have one active an many retired swapchains */ HWND hwnd; DWORD hwnd_thread_id; BOOL gdi_blit_source; /* HACK: gdi blits from the window should work with Vulkan rendered contents. */ @@ -348,7 +347,6 @@ void resize_vk_surfaces(HWND hwnd, Window active, int mask, XWindowChanges *chan void sync_vk_surface(HWND hwnd, BOOL known_child) { struct wine_vk_surface *surface; - UINT surface_with_swapchain_count = 0; if (vulkan_disable_child_window_rendering_hack) { @@ -365,15 +363,7 @@ void sync_vk_surface(HWND hwnd, BOOL known_child) LIST_FOR_EACH_ENTRY(surface, &surface_list, struct wine_vk_surface, entry) { if (surface->hwnd != hwnd) continue; - if (surface->swapchain_count) surface_with_swapchain_count++; - surface->known_child = known_child; - } - TRACE("hwnd %p surface_with_swapchain_count %u known_child %u\n", hwnd, surface_with_swapchain_count, known_child); - LIST_FOR_EACH_ENTRY(surface, &surface_list, struct wine_vk_surface, entry) - { - if (surface->hwnd != hwnd) continue; - if (surface_with_swapchain_count > 1) wine_vk_surface_set_offscreen(surface, TRUE); - else wine_vk_surface_set_offscreen(surface, known_child || surface->gdi_blit_source); + wine_vk_surface_set_offscreen(surface, known_child || surface->gdi_blit_source); } pthread_mutex_unlock(&vulkan_mutex); } @@ -390,33 +380,6 @@ void invalidate_vk_surfaces(HWND hwnd) pthread_mutex_unlock(&vulkan_mutex); } -Window wine_vk_active_surface(HWND hwnd) -{ - struct wine_vk_surface *surface, *active = NULL; - UINT surface_with_swapchain_count = 0; - Window window; - - pthread_mutex_lock(&vulkan_mutex); - LIST_FOR_EACH_ENTRY(surface, &surface_list, struct wine_vk_surface, entry) - { - if (surface->hwnd != hwnd) continue; - if (!surface->swapchain_count || surface->gdi_blit_source) continue; - active = surface; - surface_with_swapchain_count++; - } - if (!active) window = None; - else - { - TRACE("hwnd %p surface_with_swapchain_count %u known_child %u\n", hwnd, surface_with_swapchain_count, active->known_child); - if (surface_with_swapchain_count > 1) wine_vk_surface_set_offscreen(active, TRUE); - else wine_vk_surface_set_offscreen(active, active->known_child); - window = active->window; - } - pthread_mutex_unlock(&vulkan_mutex); - - return window; -} - BOOL wine_vk_direct_window_draw( HWND hwnd ) { struct wine_vk_surface *surface; @@ -496,7 +459,7 @@ static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *create_info, const VkAllocationCallbacks *allocator, VkSwapchainKHR *swapchain) { - struct wine_vk_surface *other, *x11_surface = surface_from_handle(create_info->surface); + struct wine_vk_surface *x11_surface = surface_from_handle(create_info->surface); VkSwapchainCreateInfoKHR create_info_host; VkResult result; @@ -520,20 +483,10 @@ static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device, x11_surface->invalidated = FALSE; pthread_mutex_lock(&vulkan_mutex); - LIST_FOR_EACH_ENTRY(other, &surface_list, struct wine_vk_surface, entry) - { - if (other->hwnd != x11_surface->hwnd) continue; - if (!other->swapchain_count) continue; - TRACE("hwnd %p already has a swapchain, moving surface offscreen\n", x11_surface->hwnd); - wine_vk_surface_set_offscreen(other, TRUE); - wine_vk_surface_set_offscreen(x11_surface, TRUE); - } result = pvkCreateSwapchainKHR(device, &create_info_host, NULL /* allocator */, swapchain); if (result == VK_SUCCESS) - { - x11_surface->swapchain_count++; XSaveContext(gdi_display, (XID)(*swapchain), vulkan_swapchain_context, (char *)wine_vk_surface_grab(x11_surface)); - } + pthread_mutex_unlock(&vulkan_mutex); return result; } @@ -572,7 +525,6 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, x11_surface->ref = 1; x11_surface->hwnd = create_info->hwnd; x11_surface->known_child = FALSE; - x11_surface->swapchain_count = 0; if (x11_surface->hwnd) { x11_surface->hwnd_thread_id = NtUserGetWindowThread(x11_surface->hwnd, &hwnd_pid); @@ -717,7 +669,6 @@ static void X11DRV_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface const VkAllocationCallbacks *allocator) { struct wine_vk_surface *x11_surface = surface_from_handle(surface); - HWND hwnd = x11_surface->hwnd; TRACE("%p 0x%s %p\n", instance, wine_dbgstr_longlong(surface), allocator); @@ -730,7 +681,6 @@ static void X11DRV_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface pvkDestroySurfaceKHR(instance, x11_surface->surface, NULL /* allocator */); wine_vk_surface_release(x11_surface); - update_client_window(hwnd); } } @@ -748,10 +698,8 @@ static void X11DRV_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapcha pthread_mutex_lock(&vulkan_mutex); if (!XFindContext(gdi_display, (XID)swapchain, vulkan_swapchain_context, (char **)&surface)) - { - surface->swapchain_count--; wine_vk_surface_release(surface); - } + XDeleteContext(gdi_display, (XID)swapchain, vulkan_swapchain_context); pthread_mutex_unlock(&vulkan_mutex); } @@ -998,6 +946,9 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, wine_vk_surface_grab(surface); pthread_mutex_unlock(&vulkan_mutex); + if (surface) + update_client_window( surface->hwnd, surface->window, surface->offscreen ); + if (!surface || !surface->offscreen) wait_fence = FALSE; else if (surface->other_process || surface->present_mode == VK_PRESENT_MODE_MAILBOX_KHR || diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 1f153677cda..b7cc69532a7 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -52,6 +52,7 @@ #include "wingdi.h" #include "winuser.h" +#include "xcomposite.h" #include "wine/debug.h" #include "wine/server.h" @@ -1825,28 +1826,49 @@ Window get_dummy_parent(void) return dummy_parent; } +void reparent_client_window( struct x11drv_win_data *data, BOOL attach, BOOL offscreen ) +{ + if (!data->client_window) return; + + TRACE( "%p reparent xwin %lx/%lx\n", data->hwnd, data->whole_window, data->client_window ); + + if (attach) + { + XReparentWindow( gdi_display, data->client_window, data->whole_window, + data->client_rect.left - data->whole_rect.left, + data->client_rect.top - data->whole_rect.top ); +#ifdef SONAME_LIBXCOMPOSITE + if (!offscreen && usexcomposite) + pXCompositeUnredirectWindow( gdi_display, data->client_window, CompositeRedirectManual ); +#endif + } + else + { +#ifdef SONAME_LIBXCOMPOSITE + if (offscreen && usexcomposite) + pXCompositeRedirectWindow( gdi_display, data->client_window, CompositeRedirectManual ); +#endif + XReparentWindow( gdi_display, data->client_window, get_dummy_parent(), 0, 0 ); + } +} /********************************************************************** * update_client_window */ -void update_client_window( HWND hwnd ) +void update_client_window( HWND hwnd, Window new_active, BOOL offscreen ) { struct x11drv_win_data *data; - Window old_active; if ((data = get_win_data( hwnd ))) { - old_active = data->client_window; - data->client_window = wine_vk_active_surface( hwnd ); - if (data->client_window && data->whole_window && old_active != data->client_window) + if (data->whole_window && data->client_window != new_active) { - TRACE( "%p reparent xwin %lx/%lx\n", data->hwnd, data->whole_window, data->client_window ); - XReparentWindow( data->display, data->client_window, data->whole_window, - data->client_rect.left - data->whole_rect.left, - data->client_rect.top - data->whole_rect.top ); + reparent_client_window( data, FALSE, TRUE ); + data->client_window = new_active; + reparent_client_window( data, TRUE, offscreen ); + /* make sure any request that could use old client window has been flushed */ + XSync( gdi_display, False ); } - /* make sure any request that could use old client window has been flushed */ - XFlush( data->display ); release_win_data( data ); } } @@ -1868,8 +1890,7 @@ void detach_client_window( HWND hwnd, Window window ) } XDeleteContext( data->display, data->client_window, winContext ); - XReparentWindow( gdi_display, data->client_window, get_dummy_parent(), 0, 0 ); - TRACE( "%p reparent xwin %lx/%lx\n", data->hwnd, data->whole_window, data->client_window ); + reparent_client_window( data, 0, TRUE ); data->client_window = 0; XFlush( data->display ); XSync( gdi_display, False ); @@ -1916,11 +1937,7 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual ) data->window_rect = data->whole_rect = data->client_rect; } - if (data->client_window) - { - XReparentWindow( gdi_display, data->client_window, dummy_parent, 0, 0 ); - TRACE( "%p reparent xwin %lx/%lx\n", data->hwnd, data->whole_window, data->client_window ); - } + if (data->client_window) reparent_client_window( data, FALSE, TRUE ); if (data->client_colormap) XFreeColormap( gdi_display, data->client_colormap ); data->client_colormap = XCreateColormap( gdi_display, dummy_parent, visual->visual, @@ -2102,8 +2119,9 @@ static void destroy_whole_window( struct x11drv_win_data *data, BOOL already_des if (data->client_window && !already_destroyed) { XSelectInput( data->display, data->client_window, 0 ); - XReparentWindow( data->display, data->client_window, get_dummy_parent(), 0, 0 ); + reparent_client_window( data, FALSE, TRUE ); XSync( data->display, False ); + XSync( gdi_display, False ); } XDeleteContext( data->display, data->whole_window, winContext ); if (!already_destroyed) XDestroyWindow( data->display, data->whole_window ); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 54e86b4f6e0..9edf97da487 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -678,7 +678,6 @@ extern void destroy_vk_surface( HWND hwnd ) DECLSPEC_HIDDEN; extern void sync_vk_surface( HWND hwnd, BOOL known_child ) DECLSPEC_HIDDEN; extern void resize_vk_surfaces( HWND hwnd, Window active, int mask, XWindowChanges *changes ) DECLSPEC_HIDDEN; extern void invalidate_vk_surfaces( HWND hwnd ) DECLSPEC_HIDDEN; -extern Window wine_vk_active_surface( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL wine_vk_direct_window_draw( HWND hwnd ) DECLSPEC_HIDDEN; extern void vulkan_thread_detach(void) DECLSPEC_HIDDEN; @@ -690,7 +689,7 @@ extern void update_net_wm_states( struct x11drv_win_data *data ) DECLSPEC_HIDDEN extern void make_window_embedded( struct x11drv_win_data *data ) DECLSPEC_HIDDEN; extern Window create_dummy_client_window(void) DECLSPEC_HIDDEN; extern Window create_client_window( HWND hwnd, const XVisualInfo *visual ) DECLSPEC_HIDDEN; -extern void update_client_window( HWND hwnd ) DECLSPEC_HIDDEN; +extern void update_client_window( HWND hwnd, Window new_active, BOOL offscreen ) DECLSPEC_HIDDEN; extern void detach_client_window( HWND hwnd, Window window ) DECLSPEC_HIDDEN; extern void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *vis, BOOL use_alpha ) DECLSPEC_HIDDEN; extern void change_systray_owner( Display *display, Window systray_window ) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index e35ea4052d2..2b5c5b9c8e8 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -109,6 +109,7 @@ static unsigned long err_serial; /* serial number of first request * static int (*old_error_handler)( Display *, XErrorEvent * ); static BOOL use_xim = TRUE; static WCHAR input_style[20]; +static int xcomp_opcode; static pthread_mutex_t d3dkmt_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t error_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -268,6 +269,11 @@ static inline BOOL ignore_error( Display *display, XErrorEvent *event ) { if (event->error_code == xrender_error_base + BadPicture) return TRUE; } +#endif +#ifdef SONAME_LIBXCOMPOSITE + if (xcomp_opcode && event->request_code == xcomp_opcode + && (event->minor_code == X_CompositeRedirectWindow || event->minor_code == X_CompositeUnredirectWindow)) + return TRUE; #endif } return FALSE; @@ -611,7 +617,11 @@ static void X11DRV_XComposite_Init(void) usexcomposite = FALSE; return; } - TRACE("XComposite is up and running error_base = %d\n", xcomp_error_base); + if (!XQueryExtension(gdi_display, "Composite", &xcomp_opcode, &xcomp_event_base, &xcomp_error_base)) + ERR("XQueryExtension failed.\n"); + + TRACE("XComposite is up and running opcode = %d, error_base = %d, event_base %d\n", + xcomp_opcode, xcomp_error_base, xcomp_event_base); return; sym_not_found: From 7f6c94f0c79f1cd15bc438f09abc6be7ae164f52 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 2 May 2023 22:06:23 -0600 Subject: [PATCH 1298/2777] winex11.drv: HACK: Cleanup lost Vulkan surfaces for DOOM (2016). CW-Bug-Id: #21902 --- dlls/winex11.drv/vulkan.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index bc447f794f0..0760cf7c46d 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -502,6 +502,30 @@ static BOOL disable_opwr(void) return disable; } +static void cleanup_leaked_surfaces(HWND hwnd) +{ + struct wine_vk_surface *surface, *next; + static int cleanup = -1; + + if (cleanup == -1) + { + const char *e = getenv("SteamGameId"); + cleanup = e && !strcmp(e, "379720"); + if (cleanup) + ERR("HACK.\n"); + } + + if (!cleanup) + return; + + LIST_FOR_EACH_ENTRY_SAFE(surface, next, &surface_list, struct wine_vk_surface, entry) + { + if (surface->hwnd != hwnd) + continue; + wine_vk_surface_release(surface); + } +} + static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *create_info, const VkAllocationCallbacks *allocator, VkSurfaceKHR *surface) @@ -635,6 +659,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, } pthread_mutex_lock(&vulkan_mutex); + cleanup_leaked_surfaces(x11_surface->hwnd); list_add_tail(&surface_list, &x11_surface->entry); pthread_mutex_unlock(&vulkan_mutex); From bdbf560f1f6643c2343f929d5ec416927405137c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 19 Apr 2023 14:50:31 -0600 Subject: [PATCH 1299/2777] amd_ags_x64: Store d3d11 immediate context in AGS context. CW-Bug-Id: #22242 --- dlls/amd_ags_x64/amd_ags_x64_main.c | 65 ++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 43b72d908ee..74d6c8e432c 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -117,6 +117,7 @@ struct AGSContext struct AGSDeviceInfo *devices; VkPhysicalDeviceProperties *properties; VkPhysicalDeviceMemoryProperties *memory_properties; + ID3D11DeviceContext *d3d11_context; }; static HMODULE hd3d11, hd3d12; @@ -451,11 +452,9 @@ static AGSReturnCode init_ags_context(AGSContext *context) unsigned int i, j; BYTE *device; + memset(context, 0, sizeof(*context)); + context->version = determine_ags_version(); - context->device_count = 0; - context->devices = NULL; - context->properties = NULL; - context->memory_properties = NULL; ret = vk_get_physical_device_properties(&context->device_count, &context->properties, &context->memory_properties); if (ret != AGS_SUCCESS || !context->device_count) @@ -616,19 +615,24 @@ AGSReturnCode WINAPI agsDeInitialize(AGSContext *context) TRACE("context %p.\n", context); - if (context) + if (!context) + return AGS_SUCCESS; + + if (context->d3d11_context) { - heap_free(context->memory_properties); - heap_free(context->properties); - device = (BYTE *)context->devices; - for (i = 0; i < context->device_count; ++i) - { - heap_free(*GET_DEVICE_FIELD_ADDR(device, displays, void *, context->version)); - device += amd_ags_info[context->version].device_size; - } - heap_free(context->devices); - heap_free(context); + ID3D11DeviceContext_Release(context->d3d11_context); + context->d3d11_context = NULL; + } + heap_free(context->memory_properties); + heap_free(context->properties); + device = (BYTE *)context->devices; + for (i = 0; i < context->device_count; ++i) + { + heap_free(*GET_DEVICE_FIELD_ADDR(device, displays, void *, context->version)); + device += amd_ags_info[context->version].device_size; } + heap_free(context->devices); + heap_free(context); return AGS_SUCCESS; } @@ -722,6 +726,15 @@ AGSReturnCode WINAPI agsDriverExtensionsDX11_CreateDevice( AGSContext* context, r->featureLevel = feature_level; } + if (context->version < AMD_AGS_VERSION_5_3_0) + { + /* Later versions pass context to functions explicitly, no need to keep it. */ + if (context->d3d11_context) + ID3D11DeviceContext_Release(context->d3d11_context); + ID3D11DeviceContext_AddRef(device_context); + context->d3d11_context = device_context; + } + return AGS_SUCCESS; } @@ -783,11 +796,25 @@ int WINAPI agsGetVersionNumber(void) return AGS_MAKE_VERSION(amd_ags_info[version].major, amd_ags_info[version].minor, amd_ags_info[version].patch); } -AGSReturnCode WINAPI agsDriverExtensionsDX11_Init( AGSContext* context, ID3D11Device* device, unsigned int uavSlot, unsigned int* extensionsSupported ) +AGSReturnCode WINAPI agsDriverExtensionsDX11_Init( AGSContext *context, ID3D11Device *device, unsigned int uavSlot, unsigned int *extensionsSupported ) { FIXME("context %p, device %p, uavSlot %u, extensionsSupported %p stub.\n", context, device, uavSlot, extensionsSupported); *extensionsSupported = 0; + if (device) + { + if (context->version < AMD_AGS_VERSION_5_3_0) + { + /* Later versions pass context to functions explicitly, no need to keep it. */ + if (context->d3d11_context) + { + ID3D11DeviceContext_Release(context->d3d11_context); + context->d3d11_context = NULL; + } + ID3D11Device_GetImmediateContext(device, &context->d3d11_context); + } + } + return AGS_SUCCESS; } @@ -897,6 +924,12 @@ AGSReturnCode WINAPI agsDriverExtensionsDX11_DestroyDevice_520(AGSContext *conte if (!device) return AGS_SUCCESS; + if (context->d3d11_context) + { + ID3D11DeviceContext_Release(context->d3d11_context); + context->d3d11_context = NULL; + } + ref = ID3D11Device_Release(device); if (device_ref) *device_ref = ref; From 8bf0f4d5abd7e59ad58f69385eb4a61bafc84b26 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 19 Apr 2023 18:09:02 -0600 Subject: [PATCH 1300/2777] amd_ags_x64: Implement agsDriverExtensionsDX11_SetDepthBounds(). CW-Bug-Id: #22242 --- dlls/amd_ags_x64/Makefile.in | 3 + dlls/amd_ags_x64/amd_ags_x64_main.c | 78 +++++++++++++++--- dlls/amd_ags_x64/dxvk_interfaces.idl | 116 +++++++++++++++++++++++++++ 3 files changed, 187 insertions(+), 10 deletions(-) create mode 100644 dlls/amd_ags_x64/dxvk_interfaces.idl diff --git a/dlls/amd_ags_x64/Makefile.in b/dlls/amd_ags_x64/Makefile.in index 4e3cd326d2f..5efcc5e0ffc 100644 --- a/dlls/amd_ags_x64/Makefile.in +++ b/dlls/amd_ags_x64/Makefile.in @@ -7,3 +7,6 @@ EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native C_SRCS = \ amd_ags_x64_main.c + +IDL_SRCS = \ + dxvk_interfaces.idl diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 74d6c8e432c..3c5f3043c21 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -14,6 +14,10 @@ #include "d3d11.h" #include "d3d12.h" +#include "initguid.h" + +#include "dxvk_interfaces.h" + #include "amd_ags.h" WINE_DEFAULT_DEBUG_CHANNEL(amd_ags); @@ -118,6 +122,7 @@ struct AGSContext VkPhysicalDeviceProperties *properties; VkPhysicalDeviceMemoryProperties *memory_properties; ID3D11DeviceContext *d3d11_context; + AGSDX11ExtensionsSupported_600 extensions; }; static HMODULE hd3d11, hd3d12; @@ -659,6 +664,23 @@ AGSReturnCode WINAPI agsGetCrossfireGPUCount(AGSContext *context, int *gpu_count return AGS_SUCCESS; } +static void get_dx11_extensions_supported(ID3D11Device *device, AGSDX11ExtensionsSupported_600 *extensions) +{ + ID3D11VkExtDevice *ext_device; + + if (FAILED(ID3D11Device_QueryInterface(device, &IID_ID3D11VkExtDevice, (void **)&ext_device))) + { + TRACE("No ID3D11VkExtDevice.\n"); + return; + } + + extensions->depthBoundsTest = !!ID3D11VkExtDevice_GetExtensionSupport(ext_device, D3D11_VK_EXT_DEPTH_BOUNDS); + + ID3D11VkExtDevice_Release(ext_device); + + TRACE("extensions %#x.\n", *(unsigned int *)extensions); +} + AGSReturnCode WINAPI agsDriverExtensionsDX11_CreateDevice( AGSContext* context, const AGSDX11DeviceCreationParams* creation_params, const AGSDX11ExtensionParams* extension_params, AGSDX11ReturnedParams* returned_params ) @@ -701,6 +723,9 @@ AGSReturnCode WINAPI agsDriverExtensionsDX11_CreateDevice( AGSContext* context, ERR("Device creation failed, hr %#x.\n", hr); return AGS_DX_FAILURE; } + + get_dx11_extensions_supported(device, &context->extensions); + if (context->version < AMD_AGS_VERSION_5_2_0) { AGSDX11ReturnedParams_511 *r = &returned_params->agsDX11ReturnedParams511; @@ -708,6 +733,7 @@ AGSReturnCode WINAPI agsDriverExtensionsDX11_CreateDevice( AGSContext* context, r->pImmediateContext = device_context; r->pSwapChain = swapchain; r->FeatureLevel = feature_level; + r->extensionsSupported = *(unsigned int *)&context->extensions; } else if (context->version < AMD_AGS_VERSION_6_0_0) { @@ -716,6 +742,7 @@ AGSReturnCode WINAPI agsDriverExtensionsDX11_CreateDevice( AGSContext* context, r->pImmediateContext = device_context; r->pSwapChain = swapchain; r->FeatureLevel = feature_level; + r->extensionsSupported = *(unsigned int *)&context->extensions; } else { @@ -724,6 +751,7 @@ AGSReturnCode WINAPI agsDriverExtensionsDX11_CreateDevice( AGSContext* context, r->pImmediateContext = device_context; r->pSwapChain = swapchain; r->featureLevel = feature_level; + r->extensionsSupported = context->extensions; } if (context->version < AMD_AGS_VERSION_5_3_0) @@ -813,6 +841,8 @@ AGSReturnCode WINAPI agsDriverExtensionsDX11_Init( AGSContext *context, ID3D11De } ID3D11Device_GetImmediateContext(device, &context->d3d11_context); } + get_dx11_extensions_supported(device, &context->extensions); + *extensionsSupported = *(unsigned int *)&context->extensions; } return AGS_SUCCESS; @@ -833,24 +863,52 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) } #ifdef __x86_64__ + +static AGSReturnCode set_depth_bounds(AGSContext* context, ID3D11DeviceContext *dx_context, bool enabled, + float min_depth, float max_depth) +{ + ID3D11VkExtContext *ext_context; + + if (!context->extensions.depthBoundsTest) + return AGS_EXTENSION_NOT_SUPPORTED; + + if (FAILED(ID3D11DeviceContext_QueryInterface(dx_context, &IID_ID3D11VkExtContext, (void **)&ext_context))) + { + TRACE("No ID3D11VkExtContext.\n"); + return AGS_EXTENSION_NOT_SUPPORTED; + } + ID3D11VkExtContext_SetDepthBoundsTest(ext_context, enabled, min_depth, max_depth); + ID3D11VkExtContext_Release(ext_context); + return AGS_SUCCESS; +} + AGSReturnCode WINAPI agsDriverExtensionsDX11_SetDepthBounds(AGSContext* context, bool enabled, - float minDepth, float maxDepth ) + float min_depth, float max_depth ) { - static int once; + TRACE("context %p, enabled %d, min_depth %f, max_depth %f.\n", context, enabled, min_depth, max_depth); - if (!once++) - FIXME("context %p, enabled %#x, minDepth %f, maxDepth %f stub.\n", context, enabled, minDepth, maxDepth); - return AGS_EXTENSION_NOT_SUPPORTED; + if (!context || !context->d3d11_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + + return set_depth_bounds(context, context->d3d11_context, enabled, min_depth, max_depth); } AGSReturnCode WINAPI agsDriverExtensionsDX11_SetDepthBounds_530(AGSContext* context, - ID3D11DeviceContext* dxContext, bool enabled, float minDepth, float maxDepth ) + ID3D11DeviceContext* dx_context, bool enabled, float min_depth, float max_depth ) { - static int once; + TRACE("context %p, dx_context %p, enabled %d, min_depth %f, max_depth %f.\n", context, dx_context, enabled, + min_depth, max_depth); - if (!once++) - FIXME("context %p, enabled %#x, minDepth %f, maxDepth %f stub.\n", context, enabled, minDepth, maxDepth); - return AGS_EXTENSION_NOT_SUPPORTED; + if (!context || !dx_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + + return set_depth_bounds(context, dx_context, enabled, min_depth, max_depth); } __ASM_GLOBAL_FUNC( DX11_SetDepthBounds_impl, diff --git a/dlls/amd_ags_x64/dxvk_interfaces.idl b/dlls/amd_ags_x64/dxvk_interfaces.idl new file mode 100644 index 00000000000..c632d926fb2 --- /dev/null +++ b/dlls/amd_ags_x64/dxvk_interfaces.idl @@ -0,0 +1,116 @@ +/* + * Copyright 2023 Paul Gofman 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 + */ + +import "d3d11.idl"; + +typedef enum D3D11_VK_EXTENSION +{ + D3D11_VK_EXT_MULTI_DRAW_INDIRECT, + D3D11_VK_EXT_MULTI_DRAW_INDIRECT_COUNT, + D3D11_VK_EXT_DEPTH_BOUNDS, + D3D11_VK_EXT_BARRIER_CONTROL, + D3D11_VK_NVX_BINARY_IMPORT, + D3D11_VK_NVX_IMAGE_VIEW_HANDLE, +} D3D11_VK_EXTENSION; + +typedef enum D3D11_VK_BARRIER_CONTROL +{ + D3D11_VK_BARRIER_CONTROL_IGNORE_WRITE_AFTER_WRITE = 0x1, + D3D11_VK_BARRIER_CONTROL_IGNORE_GRAPHICS_UAV = 0x2, +} D3D11_VK_BARRIER_CONTROL; + +[ + object, + uuid(bb8a4fb9-3935-4762-b44b-35189a26414a), + local, + pointer_default(unique) +] +interface ID3D11VkExtShader : IUnknown +{ + HRESULT GetSpirvCode([in, out] SIZE_T *code_size, [out] void *code); +} + +[ + object, + uuid(8a6e3c42-f74c-45b7-8265-a231b677ca17), + local, + pointer_default(unique) +] +interface ID3D11VkExtDevice : IUnknown +{ + BOOL GetExtensionSupport([in] D3D11_VK_EXTENSION extension); +} + +[ + object, + uuid(cfcf64ef-9586-46d0-bca4-97cf2ca61b06), + local, + pointer_default(unique) +] +interface ID3D11VkExtDevice1 : ID3D11VkExtDevice +{ + BOOL GetResourceHandleGPUVirtualAddressAndSizeNVX([in] void *object, [out] UINT64 *gpu_va_start, + [out] UINT64 *gpu_va_size); + BOOL CreateUnorderedAccessViewAndGetDriverHandleNVX([in] ID3D11Resource *resource, + [in] const D3D11_UNORDERED_ACCESS_VIEW_DESC *desc, [out] ID3D11UnorderedAccessView **uav, + UINT32 *driver_handle); + BOOL CreateShaderResourceViewAndGetDriverHandleNVX([in] ID3D11Resource *resource, + [in] const D3D11_SHADER_RESOURCE_VIEW_DESC* desc, [out] ID3D11ShaderResourceView **srv, + UINT32 *dirver_handle); + BOOL CreateSamplerStateAndGetDriverHandleNVX([in] const D3D11_SAMPLER_DESC *sample_desc, + [out] ID3D11SamplerState **sample_state, UINT32 *driver_handle); + BOOL CreateCubinComputeShaderWithNameNVX([in] const void *cubin, [in] UINT32 size, [in] UINT32 block_x, + [in] UINT32 block_y, [in] UINT32 block_z, [in] const char *shader_name, [out] IUnknown **shader); + BOOL GetCudaTextureObjectNVX([in] UINT32 srv_driver_hadnle, [in] UINT32 sample_driver_handle, + [out] UINT32 *cuda_texture_handle); +} + +[ + object, + uuid(fd0bca13-5cb6-4c3a-987e-4750de2ca791), + local, + pointer_default(unique) +] +interface ID3D11VkExtContext : IUnknown +{ + void MultiDrawIndirect([in] UINT draw_count, [in] ID3D11Buffer *buffer_for_args, [in] UINT byte_offset_for_args, + [in] UINT byte_stride_for_args); + void MultiDrawIndexedIndirect([in] UINT draw_count, [in] ID3D11Buffer *buffer_for_args, + [in] UINT byte_offset_for_args, [in] UINT byte_stride_for_args); + void MultiDrawIndirectCount([in] UINT max_draw_count, [in] ID3D11Buffer *buffer_for_count, + [in] UINT byte_offset_for_count, [in] ID3D11Buffer *buffer_for_args, + [in] UINT byte_offset_for_args, [in] UINT byte_stride_for_args); + void MultiDrawIndexedIndirectCount([in] UINT max_draw_count, [in] ID3D11Buffer *buffer_for_count, + [in] UINT byte_offset_for_count, [in] ID3D11Buffer *buffer_for_args, + [in] UINT byte_offset_for_args, [in] UINT byte_stride_for_args); + void SetDepthBoundsTest([in] BOOL enable, [in] FLOAT min_depth_bounds, [in] FLOAT max_depth_bounds); + void SetBarrierControl([in] UINT control_flags); +} + +[ + object, + uuid(874b09b2-ae0b-41d8-8476-5f3b7a0e879d), + local, + pointer_default(unique) +] +interface ID3D11VkExtContext1 : ID3D11VkExtContext +{ + BOOL LaunchCubinShaderNVX([in] IUnknown *shader,[in] UINT32 grid_x, [in] UINT32 grid_y, [in] UINT32 grid_z, + [in] const void *params, [in] UINT32 param_size, [in] void * const *read_resources, + [in] UINT32 read_resource_count, [in] void* const *write_resources, [in] UINT32 write_resources_count); +} From 8f9cd2221cd5d2d9fff44be2f81563a4a0f12493 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 4 May 2023 20:15:20 -0600 Subject: [PATCH 1301/2777] amd_ags_x64: Implement UAV overlap. CW-Bug-Id: #22242 --- dlls/amd_ags_x64/amd_ags_x64_main.c | 66 ++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 3c5f3043c21..db1b3294902 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -675,6 +675,8 @@ static void get_dx11_extensions_supported(ID3D11Device *device, AGSDX11Extension } extensions->depthBoundsTest = !!ID3D11VkExtDevice_GetExtensionSupport(ext_device, D3D11_VK_EXT_DEPTH_BOUNDS); + extensions->uavOverlap = !!ID3D11VkExtDevice_GetExtensionSupport(ext_device, D3D11_VK_EXT_BARRIER_CONTROL); + extensions->UAVOverlapDeferredContexts = extensions->uavOverlap; ID3D11VkExtDevice_Release(ext_device); @@ -918,23 +920,48 @@ __ASM_GLOBAL_FUNC( DX11_SetDepthBounds_impl, "jmp " __ASM_NAME("agsDriverExtensionsDX11_SetDepthBounds") "\n\t" "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_SetDepthBounds_530") ) +static AGSReturnCode update_uav_overlap(AGSContext* context, ID3D11DeviceContext *dx_context, BOOL set) +{ + ID3D11VkExtContext *ext_context; + + if (!context->extensions.uavOverlap) + return AGS_EXTENSION_NOT_SUPPORTED; + + if (FAILED(ID3D11DeviceContext_QueryInterface(dx_context, &IID_ID3D11VkExtContext, (void **)&ext_context))) + { + TRACE("No ID3D11VkExtContext.\n"); + return AGS_EXTENSION_NOT_SUPPORTED; + } + + ID3D11VkExtContext_SetBarrierControl(ext_context, set ? D3D11_VK_BARRIER_CONTROL_IGNORE_WRITE_AFTER_WRITE : 0); + ID3D11VkExtContext_Release(ext_context); + return AGS_SUCCESS; +} + AGSReturnCode WINAPI agsDriverExtensionsDX11_BeginUAVOverlap_520(AGSContext *context) { - static int once; + TRACE("context %p.\n", context); - if (!once++) - FIXME("context %p stub.\n", context); - return AGS_EXTENSION_NOT_SUPPORTED; + if (!context || !context->d3d11_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + + return update_uav_overlap(context, context->d3d11_context, TRUE); } AGSReturnCode WINAPI agsDriverExtensionsDX11_BeginUAVOverlap(AGSContext *context, ID3D11DeviceContext *dx_context) { - static int once; + TRACE("context %p, dx_context %p.\n", context, dx_context); - if (!once++) - FIXME("context %p, dx_context %p stub.\n", context, dx_context); + if (!context || !dx_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } - return AGS_EXTENSION_NOT_SUPPORTED; + return update_uav_overlap(context, dx_context, TRUE); } __ASM_GLOBAL_FUNC( DX11_BeginUAVOverlap_impl, @@ -946,21 +973,28 @@ __ASM_GLOBAL_FUNC( DX11_BeginUAVOverlap_impl, AGSReturnCode WINAPI agsDriverExtensionsDX11_EndUAVOverlap_520(AGSContext *context) { - static int once; + TRACE("context %p.\n", context); - if (!once++) - FIXME("context %p stub.\n", context); - return AGS_EXTENSION_NOT_SUPPORTED; + if (!context || !context->d3d11_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } + + return update_uav_overlap(context, context->d3d11_context, FALSE); } AGSReturnCode WINAPI agsDriverExtensionsDX11_EndUAVOverlap(AGSContext *context, ID3D11DeviceContext *dx_context) { - static int once; + TRACE("context %p, dx_context %p.\n", context, dx_context); - if (!once++) - FIXME("context %p, dx_context %p stub.\n", context, dx_context); + if (!context || !dx_context) + { + WARN("Invalid arguments.\n"); + return AGS_INVALID_ARGS; + } - return AGS_EXTENSION_NOT_SUPPORTED; + return update_uav_overlap(context, dx_context, FALSE); } __ASM_GLOBAL_FUNC( DX11_EndUAVOverlap_impl, From f6c842614f575b8d7ac0cf7aa38036b4262007d8 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 28 Apr 2023 21:11:33 -0600 Subject: [PATCH 1302/2777] d3dx9: Fix dst pitch for compressed format in D3DXLoadSurfaceFromMemory(). Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54901 (cherry picked from commit 0b9620266f08d57c2db41b934a77b6ce4a94aeda) --- dlls/d3dx9_36/surface.c | 2 +- dlls/d3dx9_36/tests/surface.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/dlls/d3dx9_36/surface.c b/dlls/d3dx9_36/surface.c index 26809a47e18..ccb5c2ffadb 100644 --- a/dlls/d3dx9_36/surface.c +++ b/dlls/d3dx9_36/surface.c @@ -2148,7 +2148,7 @@ HRESULT WINAPI D3DXLoadSurfaceFromMemory(IDirect3DSurface9 *dst_surface, } tx_compress_dxtn(4, dst_size_aligned.width, dst_size_aligned.height, dst_uncompressed, gl_format, lockrect.pBits, - lockrect.Pitch * destformatdesc->block_width / destformatdesc->block_byte_count); + lockrect.Pitch); heap_free(dst_uncompressed); } } diff --git a/dlls/d3dx9_36/tests/surface.c b/dlls/d3dx9_36/tests/surface.c index c3ac4ba74b3..9395bf41d80 100644 --- a/dlls/d3dx9_36/tests/surface.c +++ b/dlls/d3dx9_36/tests/surface.c @@ -847,6 +847,7 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) static const DWORD pixdata_g16r16[] = { 0x07d23fbe, 0xdc7f44a4, 0xe4d8976b, 0x9a84fe89 }; static const DWORD pixdata_a8b8g8r8[] = { 0xc3394cf0, 0x235ae892, 0x09b197fd, 0x8dc32bf6 }; static const DWORD pixdata_a2r10g10b10[] = { 0x57395aff, 0x5b7668fd, 0xb0d856b5, 0xff2c61d6 }; + BYTE buffer[4 * 8 * 4]; hr = create_file("testdummy.bmp", noimage, sizeof(noimage)); /* invalid image */ testdummy_ok = SUCCEEDED(hr); @@ -1463,6 +1464,29 @@ static void test_D3DXLoadSurface(IDirect3DDevice9 *device) check_release((IUnknown *)newsurf, 1); check_release((IUnknown *)tex, 0); + /* Test updating subarea of compressed texture. */ + hr = IDirect3DDevice9_CreateTexture(device, 32, 16, 1, 0, D3DFMT_DXT5, D3DPOOL_SYSTEMMEM, &tex, NULL); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + hr = IDirect3DTexture9_GetSurfaceLevel(tex, 0, &newsurf); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + SetRect(&destrect, 0, 0, 4, 8); + SetRect(&rect, 0, 0, 4, 8); + memset(buffer, 0x40, sizeof(buffer)); + hr = D3DXLoadSurfaceFromMemory(newsurf, NULL, &destrect, buffer, + D3DFMT_A8B8G8R8, 4 * 4, NULL, &rect, D3DX_FILTER_NONE, 0); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + hr = IDirect3DSurface9_LockRect(newsurf, &lockrect, &destrect, D3DLOCK_READONLY); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + /* 2 identical 16 bytes DXT5 blocks. The exact values in blocks may differ from Windows due to + * different compression algorithms. */ + ok(!memcmp(lockrect.pBits, (char *)lockrect.pBits + lockrect.Pitch, 16), "data mismatch.\n"); + hr = IDirect3DSurface9_UnlockRect(newsurf); + ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); + + check_release((IUnknown *)newsurf, 1); + check_release((IUnknown *)tex, 0); + /* Test a rect larger than but not an integer multiple of the block size. */ hr = IDirect3DDevice9_CreateTexture(device, 4, 8, 1, 0, D3DFMT_DXT5, D3DPOOL_SYSTEMMEM, &tex, NULL); ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr); From 2b8bd70b25a2e45ba326b873d09f2f2c7c75471a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 5 May 2023 17:16:58 -0600 Subject: [PATCH 1303/2777] amd_ags_x64: Update to 6.1.0. --- dlls/amd_ags_x64/amd_ags.h | 5 +++-- dlls/amd_ags_x64/amd_ags_x64_main.c | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h index 9b521de75b8..f0afda73d37 100644 --- a/dlls/amd_ags_x64/amd_ags.h +++ b/dlls/amd_ags_x64/amd_ags.h @@ -417,6 +417,7 @@ typedef enum AsicFamily AsicFamily_Vega, ///< AMD Vega architecture, including Raven Ridge (ie AMD Ryzen CPU + AMD Vega GPU). AsicFamily_RDNA, ///< AMD RDNA architecture AsicFamily_RDNA2, ///< AMD RDNA2 architecture + AsicFamily_RDNA3, ///< AMD RDNA3 architecture AsicFamily_Count ///< Number of enumerated ASIC families } AsicFamily; @@ -1422,11 +1423,11 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_WriteBreadcrumb( AGSContext* c /// @{ /// Additional topologies supported via extensions -typedef enum AGSPrimitiveTopology +typedef enum AGSPrimitiveTopologyDX11 { AGS_PRIMITIVE_TOPOLOGY_QUADLIST = 7, ///< Quad list AGS_PRIMITIVE_TOPOLOGY_SCREENRECTLIST = 9 ///< Screen rect list -} AGSPrimitiveTopology; +} AGSPrimitiveTopologyDX11; /// /// Function used to set the primitive topology. If you are using any of the extended topology types, then this function should diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index db1b3294902..97bdeb2dc87 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -33,6 +33,7 @@ enum amd_ags_version AMD_AGS_VERSION_5_4_2, AMD_AGS_VERSION_6_0_0, AMD_AGS_VERSION_6_0_1, + AMD_AGS_VERSION_6_1_0, AMD_AGS_VERSION_COUNT }; @@ -56,23 +57,24 @@ amd_ags_info[AMD_AGS_VERSION_COUNT] = {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)}, + {6, 1, 0, sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600)}, }; #define DEF_FIELD(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name), \ - offsetof(AGSDeviceInfo_600, name)}} + offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name)}} #define DEF_FIELD_520_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), -1, \ - -1, -1, -1, -1}} + -1, -1, -1, -1, -1}} #define DEF_FIELD_540_UP(name) {DEVICE_FIELD_##name, {-1, -1, \ -1, -1, offsetof(AGSDeviceInfo_540, name), \ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name), \ - offsetof(AGSDeviceInfo_600, name)}} + offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name)}} #define DEF_FIELD_600_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), -1, \ - -1}} + -1, -1}} #define DEVICE_FIELD_adapterString 0 #define DEVICE_FIELD_architectureVersion 1 From 2a64c92a64a014b21e876ca10aaf60ec48a0f660 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 5 May 2023 17:43:41 -0600 Subject: [PATCH 1304/2777] amd_ags_x64: Set isAPU field in device info. --- dlls/amd_ags_x64/amd_ags_x64_main.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 97bdeb2dc87..dcba20458fc 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -71,6 +71,10 @@ amd_ags_info[AMD_AGS_VERSION_COUNT] = -1, -1, offsetof(AGSDeviceInfo_540, name), \ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name), \ offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name)}} +#define DEF_FIELD_540_600(name) {DEVICE_FIELD_##name, {-1, -1, \ + -1, -1, offsetof(AGSDeviceInfo_540, name), \ + offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), \ + -1, -1, -1}} #define DEF_FIELD_600_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), -1, \ @@ -85,6 +89,7 @@ amd_ags_info[AMD_AGS_VERSION_COUNT] = #define DEVICE_FIELD_localMemoryInBytes 6 #define DEVICE_FIELD_numDisplays 7 #define DEVICE_FIELD_displays 8 +#define DEVICE_FIELD_isAPU 9 static const struct { @@ -102,6 +107,7 @@ device_struct_fields[] = DEF_FIELD(localMemoryInBytes), DEF_FIELD(numDisplays), DEF_FIELD(displays), + DEF_FIELD_540_600(isAPU), }; #undef DEF_FIELD @@ -482,6 +488,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) { const VkPhysicalDeviceProperties *vk_properties = &context->properties[i]; const VkPhysicalDeviceMemoryProperties *vk_memory_properties = &context->memory_properties[i]; + struct AGSDeviceInfo_600 *device_600 = (struct AGSDeviceInfo_600 *)device; VkDeviceSize local_memory_size = 0; for (j = 0; j < vk_memory_properties->memoryHeapCount; j++) @@ -492,7 +499,9 @@ static AGSReturnCode init_ags_context(AGSContext *context) break; } } - TRACE("device %s, %04x:%04x, reporting local memory size 0x%s bytes\n", debugstr_a(vk_properties->deviceName), + + TRACE("device %s, type %d, %04x:%04x, reporting local memory size 0x%s bytes\n", + debugstr_a(vk_properties->deviceName), vk_properties->deviceType, vk_properties->vendorID, vk_properties->deviceID, wine_dbgstr_longlong(local_memory_size)); SET_DEVICE_FIELD(device, adapterString, const char *, context->version, vk_properties->deviceName); @@ -502,6 +511,13 @@ static AGSReturnCode init_ags_context(AGSContext *context) { SET_DEVICE_FIELD(device, architectureVersion, ArchitectureVersion, context->version, ArchitectureVersion_GCN); SET_DEVICE_FIELD(device, asicFamily, AsicFamily, context->version, AsicFamily_GCN4); + if (vk_properties->deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) + { + if (context->version >= AMD_AGS_VERSION_6_0_0) + device_600->isAPU = 1; + else + SET_DEVICE_FIELD(device, isAPU, int, context->version, 1); + } } SET_DEVICE_FIELD(device, localMemoryInBytes, ULONG64, context->version, local_memory_size); if (!i) @@ -509,7 +525,6 @@ static AGSReturnCode init_ags_context(AGSContext *context) if (context->version >= AMD_AGS_VERSION_6_0_0) { // This is a bitfield now... Nice... - struct AGSDeviceInfo_600 *device_600 = (struct AGSDeviceInfo_600 *)device; device_600->isPrimaryDevice = 1; } else From 5407fb207442aa3ead8987e2ebfe3bf254fe663c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 5 May 2023 17:55:53 -0600 Subject: [PATCH 1305/2777] amd_ags_x64: Skip non-physical devices. --- dlls/amd_ags_x64/amd_ags_x64_main.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index dcba20458fc..3706e21915c 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -221,10 +221,18 @@ static AGSReturnCode vk_get_physical_device_properties(unsigned int *out_count, } for (i = 0; i < count; ++i) + { vkGetPhysicalDeviceProperties(vk_physical_devices[i], &properties[i]); - - for (i = 0; i < count; ++i) + if (properties[i].deviceType != VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU + && properties[i].deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) + { + TRACE("Skipping device type %d.\n", properties[i].deviceType); + --i; + --count; + continue; + } vkGetPhysicalDeviceMemoryProperties(vk_physical_devices[i], &memory_properties[i]); + } *out_count = count; *out = properties; From 5ff2c451ed3bb62cfd0dbc538e072ed56b0498a3 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 9 May 2023 14:07:18 -0600 Subject: [PATCH 1306/2777] wbemprox: Bump video driver version and date. (cherry picked from commit a6344997831f283e92a7e203534f0e3faf3cdb06) CW-Bug-Id: #22252 --- dlls/wbemprox/builtin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/wbemprox/builtin.c b/dlls/wbemprox/builtin.c index faab5d51af6..c98f1c6c975 100644 --- a/dlls/wbemprox/builtin.c +++ b/dlls/wbemprox/builtin.c @@ -4161,8 +4161,8 @@ static enum fill_status fill_videocontroller( struct table *table, const struct rec->current_verticalres = vres; rec->description = wcsdup( name ); rec->device_id = L"VideoController1"; - rec->driverdate = L"20220118000000.000000-000"; - rec->driverversion = L"30.0.14023.3004"; + rec->driverdate = L"20230420000000.000000-000"; + rec->driverversion = L"31.0.14051.5006"; rec->installeddriver = get_videocontroller_installeddriver( desc.VendorId ); rec->name = wcsdup( name ); rec->pnpdevice_id = get_videocontroller_pnpdeviceid( &desc ); From 593e3018b2b8ba0183d6b2a69a2f482658d65a74 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 11 May 2023 21:57:52 -0600 Subject: [PATCH 1307/2777] ntdll: Fix tail padding in mark_block_tail(). (cherry picked from commit 0fc9a9e426499693c6c91552e20fed40c406e864) CW-Bug-Id: #22247 --- dlls/kernel32/tests/heap.c | 1 - dlls/ntdll/heap.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index d2742b55495..8c101e1c47d 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -3127,7 +3127,6 @@ static void test_block_layout( HANDLE heap, DWORD global_flags, DWORD heap_flags ok( !memcmp( ptr1 + alloc_size, tail_buf, tail_size ), "missing block tail\n" ); ok( !memcmp( ptr2 + alloc_size, tail_buf, tail_size ), "missing block tail\n" ); - todo_wine_if( global_flags & FLG_HEAP_ENABLE_FREE_CHECK ) ok( !memcmp( ptr0 + alloc_size + tail_size, padd_buf, 2 * sizeof(void *) ), "unexpected padding\n" ); tmp_ptr = (void *)0xdeadbeef; diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 2c3402dd110..1cc1a362a92 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -502,8 +502,8 @@ static inline void mark_block_tail( struct block *block, DWORD flags ) if (flags & HEAP_ADD_USER_INFO) { if (flags & HEAP_TAIL_CHECKING_ENABLED || RUNNING_ON_VALGRIND) tail += BLOCK_ALIGN; - valgrind_make_writable( tail + sizeof(void *), sizeof(void *) ); - memset( tail + sizeof(void *), 0, sizeof(void *) ); + valgrind_make_writable( tail, BLOCK_ALIGN ); + memset( tail, 0, BLOCK_ALIGN ); } } From 06475505fc865bcead84167edac316aedb2110e1 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 11 May 2023 22:08:07 -0600 Subject: [PATCH 1308/2777] ntdll: Fix last block detection in heap_walk_blocks(). (cherry picked from commit 74b04b763397dc06620863ea97c8cab2304c7d45) CW-Bug-Id: #22247 --- dlls/ntdll/heap.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 1cc1a362a92..553717a7536 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -2402,7 +2402,6 @@ BOOLEAN WINAPI RtlValidateHeap( HANDLE handle, ULONG flags, const void *ptr ) return ret; } - static NTSTATUS heap_walk_blocks( const struct heap *heap, const SUBHEAP *subheap, const struct block *block, struct rtl_heap_entry *entry ) { @@ -2426,8 +2425,8 @@ static NTSTATUS heap_walk_blocks( const struct heap *heap, const SUBHEAP *subhea entry->lpData = (char *)block + block_get_overhead( block ); entry->cbData = block_get_size( block ) - block_get_overhead( block ); /* FIXME: last free block should not include uncommitted range, which also has its own overhead */ - if (!contains( blocks, commit_end - (char *)blocks, block, block_get_size( block ) )) - entry->cbData = commit_end - (char *)entry->lpData - 4 * BLOCK_ALIGN; + if (!contains( blocks, commit_end - 4 * BLOCK_ALIGN - (char *)blocks, block, block_get_size( block ) )) + entry->cbData = commit_end - 4 * BLOCK_ALIGN - (char *)entry->lpData; entry->cbOverhead = 2 * BLOCK_ALIGN; entry->iRegionIndex = 0; entry->wFlags = 0; From 49ababff0d696651ea364b7747eaaab508f26609 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 11 May 2023 22:27:11 -0600 Subject: [PATCH 1309/2777] kernel32/tests: Add tests for subheap sizes. (cherry picked from commit 76fc73f311f31f068f7d1c75418b98f9d4dd89b4) CW-Bug-Id: #22247 --- dlls/kernel32/tests/heap.c | 85 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index 8c101e1c47d..fead409960c 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -3621,6 +3621,90 @@ static void test_GlobalMemoryStatus(void) #undef IS_WITHIN_RANGE } +static void get_valloc_info( void *mem, char **base, SIZE_T *alloc_size ) +{ + MEMORY_BASIC_INFORMATION info, info2; + SIZE_T size; + char *p; + + size = VirtualQuery( mem, &info, sizeof(info) ); + ok( size == sizeof(info), "got %Iu.\n", size ); + + info2 = info; + p = info.AllocationBase; + while (1) + { + size = VirtualQuery( p, &info2, sizeof(info2) ); + ok( size == sizeof(info), "got %Iu.\n", size ); + if (info2.AllocationBase != info.AllocationBase) + break; + ok( info2.State == MEM_RESERVE || info2.State == MEM_COMMIT, "got %#lx.\n", info2.State ); + p += info2.RegionSize; + } + + *base = info.AllocationBase; + *alloc_size = p - *base; +} + +static void test_heap_size( SIZE_T initial_size ) +{ + static const SIZE_T default_heap_size = 0x10000, init_grow_size = 0x100000, max_grow_size = 0xfd0000; + + BOOL initial_subheap = TRUE, max_size_reached = FALSE; + SIZE_T alloc_size, current_subheap_size; + char *base, *current_base; + unsigned int i; + HANDLE heap; + void *p; + + winetest_push_context( "init size %#Ix", initial_size ); + heap = HeapCreate( HEAP_NO_SERIALIZE, initial_size, 0 ); + get_valloc_info( heap, ¤t_base, &alloc_size ); + + todo_wine + ok( alloc_size == initial_size + default_heap_size || broken( (initial_size && alloc_size == initial_size) + || (!initial_size && (alloc_size == default_heap_size * sizeof(void*))) ) /* Win7 */, + "got %#Ix.\n", alloc_size ); + + current_subheap_size = alloc_size; + for (i = 0; i < 100; ++i) + { + winetest_push_context( "i %u, current_subheap_size %#Ix", i, current_subheap_size ); + p = HeapAlloc( heap, 0, 0x60000 ); + get_valloc_info( p, &base, &alloc_size ); + if (base != current_base) + { + current_base = base; + if (initial_subheap) + { + current_subheap_size = init_grow_size; + initial_subheap = FALSE; + } + else + { + current_subheap_size = min( current_subheap_size * 2, max_grow_size ); + if (current_subheap_size == max_grow_size) + max_size_reached = TRUE; + } + } + todo_wine_if( !initial_subheap ) + ok( alloc_size == current_subheap_size, "got %#Ix.\n", alloc_size ); + winetest_pop_context(); + } + todo_wine_if( sizeof(void *) == 8 ) + ok( max_size_reached, "Did not reach maximum subheap size.\n" ); + + HeapDestroy( heap ); + winetest_pop_context(); +} + +static void test_heap_sizes(void) +{ + test_heap_size( 0 ); + test_heap_size( 0x80000 ); + test_heap_size( 0x150000 ); +} + START_TEST(heap) { int argc; @@ -3657,4 +3741,5 @@ START_TEST(heap) test_debug_heap( argv[0], 0xdeadbeef ); } else win_skip( "RtlGetNtGlobalFlags not found, skipping heap debug tests\n" ); + test_heap_sizes(); } From 24b2d10834b66b9b7e9e7ed54f6893716822577e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 11 May 2023 21:53:02 -0600 Subject: [PATCH 1310/2777] ntdll: Better match Windows subheap sizes. (cherry picked from commit 354a8bb1f4a65bdec052606f2799db9e2907b5b1) CW-Bug-Id: #22247 --- dlls/kernel32/tests/heap.c | 8 ++------ dlls/ntdll/heap.c | 13 +++++++++---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index fead409960c..59a82c0c579 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -578,7 +578,6 @@ static void test_HeapCreate(void) todo_wine ok( entries[0].Region.dwCommittedSize == 0x400 * sizeof(void *), "got Region.dwCommittedSize %#lx\n", entries[0].Region.dwCommittedSize ); - todo_wine ok( entries[0].Region.dwUnCommittedSize == 0x10000 - entries[0].Region.dwCommittedSize || entries[0].Region.dwUnCommittedSize == 0x10000 * sizeof(void *) - entries[0].Region.dwCommittedSize /* win7 */, "got Region.dwUnCommittedSize %#lx\n", entries[0].Region.dwUnCommittedSize ); @@ -3019,9 +3018,9 @@ static void test_block_layout( HANDLE heap, DWORD global_flags, DWORD heap_flags expect_size = max( alloc_size, 2 * sizeof(void *) ); expect_size = ALIGN_BLOCK_SIZE( expect_size + extra_size ); diff = min( llabs( ptr2 - ptr1 ), llabs( ptr1 - ptr0 ) ); - todo_wine_if( (!(global_flags & ~FLG_HEAP_ENABLE_FREE_CHECK) && alloc_size < 2 * sizeof(void *)) ) + todo_wine_if( (!global_flags && alloc_size < 2 * sizeof(void *)) || + ((heap_flags & HEAP_FREE_CHECKING_ENABLED) && diff >= 0x100000) ) ok( diff == expect_size, "got diff %#Ix exp %#Ix\n", diff, expect_size ); - ok( !memcmp( ptr0 + alloc_size, tail_buf, tail_size ), "missing block tail\n" ); ok( !memcmp( ptr1 + alloc_size, tail_buf, tail_size ), "missing block tail\n" ); ok( !memcmp( ptr2 + alloc_size, tail_buf, tail_size ), "missing block tail\n" ); @@ -3661,7 +3660,6 @@ static void test_heap_size( SIZE_T initial_size ) heap = HeapCreate( HEAP_NO_SERIALIZE, initial_size, 0 ); get_valloc_info( heap, ¤t_base, &alloc_size ); - todo_wine ok( alloc_size == initial_size + default_heap_size || broken( (initial_size && alloc_size == initial_size) || (!initial_size && (alloc_size == default_heap_size * sizeof(void*))) ) /* Win7 */, "got %#Ix.\n", alloc_size ); @@ -3687,11 +3685,9 @@ static void test_heap_size( SIZE_T initial_size ) max_size_reached = TRUE; } } - todo_wine_if( !initial_subheap ) ok( alloc_size == current_subheap_size, "got %#Ix.\n", alloc_size ); winetest_pop_context(); } - todo_wine_if( sizeof(void *) == 8 ) ok( max_size_reached, "Did not reach maximum subheap size.\n" ); HeapDestroy( heap ); diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 553717a7536..5a419f6ac98 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -311,7 +311,12 @@ C_ASSERT( offsetof(struct heap, subheap) <= REGION_ALIGN - 1 ); #define HEAP_MAGIC ((DWORD)('H' | ('E'<<8) | ('A'<<16) | ('P'<<24))) -#define HEAP_DEF_SIZE (0x40000 * BLOCK_ALIGN) +#define HEAP_INITIAL_SIZE 0x10000 +#define HEAP_INITIAL_GROW_SIZE 0x100000 +#define HEAP_MAX_GROW_SIZE 0xfd0000 + +C_ASSERT( HEAP_MIN_LARGE_BLOCK_SIZE <= HEAP_INITIAL_GROW_SIZE ); + #define MAX_FREE_PENDING 1024 /* max number of free requests to delay */ /* some undocumented flags (names are made up) */ @@ -1135,7 +1140,7 @@ static struct block *find_free_block( struct heap *heap, ULONG flags, SIZE_T blo if ((subheap = create_subheap( heap, flags, max( heap->grow_size, total_size ), total_size ))) { - if (heap->grow_size <= HEAP_MAX_FREE_BLOCK_SIZE / 2) heap->grow_size *= 2; + heap->grow_size = min( heap->grow_size * 2, HEAP_MAX_GROW_SIZE ); } else while (!subheap) /* shrink the grow size again if we are running out of space */ { @@ -1519,7 +1524,7 @@ HANDLE WINAPI RtlCreateHeap( ULONG flags, void *addr, SIZE_T total_size, SIZE_T flags &= ~(HEAP_TAIL_CHECKING_ENABLED|HEAP_FREE_CHECKING_ENABLED); if (process_heap) flags |= HEAP_PRIVATE; if (!process_heap || !total_size || (flags & HEAP_SHARED)) flags |= HEAP_GROWABLE; - if (!total_size) total_size = HEAP_DEF_SIZE; + if (!total_size) total_size = commit_size + HEAP_INITIAL_SIZE; if (!(heap = addr)) { @@ -1534,7 +1539,7 @@ HANDLE WINAPI RtlCreateHeap( ULONG flags, void *addr, SIZE_T total_size, SIZE_T heap->flags = (flags & ~HEAP_SHARED); heap->compat_info = HEAP_STD; heap->magic = HEAP_MAGIC; - heap->grow_size = max( HEAP_DEF_SIZE, total_size ); + heap->grow_size = HEAP_INITIAL_GROW_SIZE; heap->min_size = commit_size; list_init( &heap->subheap_list ); list_init( &heap->large_list ); From 575b588736a12d75c5d80b4eb52302d44713f7a9 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 12 May 2023 19:19:25 -0600 Subject: [PATCH 1311/2777] fixup! ntdll: Exclude natively mapped areas from free areas list. CW-Bug-Id: #22247 --- dlls/ntdll/unix/virtual.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 2ac3aeba130..ea314dbe1d5 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -182,6 +182,9 @@ static void *user_space_limit = (void *)0x7fff0000; static void *working_set_limit = (void *)0x7fff0000; #endif +static const ptrdiff_t max_try_map_step = 0x40000000; +static BOOL increase_try_map_step = TRUE; + struct _KUSER_SHARED_DATA *user_shared_data = (void *)0x7ffe0000; /* TEB allocation blocks */ @@ -1302,7 +1305,8 @@ static void* try_map_free_area( struct alloc_area *area, void *base, void *end, step == 0) break; start = (char *)start + step; - step *= 2; + if (increase_try_map_step && llabs(step) < max_try_map_step) + step *= 2; } return NULL; @@ -2168,11 +2172,13 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, } else if (!(ptr = alloc_free_area( (void *)limit, size, top_down, get_unix_prot( vprot ), align_mask ))) { - WARN("Allocation failed, clearing native views.\n"); + WARN( "Allocation failed, clearing native views.\n" ); clear_native_views(); - if (!(ptr = alloc_free_area( (void *)limit, size, top_down, get_unix_prot( vprot ), align_mask ))) - return STATUS_NO_MEMORY; + if (!is_win64) increase_try_map_step = FALSE; + ptr = alloc_free_area( (void *)limit, size, top_down, get_unix_prot( vprot ), align_mask ); + if (!is_win64) increase_try_map_step = TRUE; + if (!ptr) return STATUS_NO_MEMORY; } status = create_view( view_ret, ptr, size, vprot ); if (status != STATUS_SUCCESS) unmap_area( ptr, size ); From fed27c2204cdb19c288bba3c46379c55478645f5 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 12 May 2023 19:22:44 -0600 Subject: [PATCH 1312/2777] ntdll: Add WINE_KERNEL_STACK_SIZE option. CW-Bug-Id: #22247 --- dlls/ntdll/unix/loader.c | 8 ++++++++ dlls/ntdll/unix/unix_private.h | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index e0e5006f498..0cdab9e6b91 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2283,6 +2283,7 @@ BOOL no_priv_elevation; BOOL localsystem_sid; BOOL high_dll_addresses; BOOL simulate_writecopy; +SIZE_T kernel_stack_size = 0x100000; static void hacks_init(void) { @@ -2363,6 +2364,13 @@ static void hacks_init(void) return; } + if ((env_str = getenv( "WINE_KERNEL_STACK_SIZE" ))) + kernel_stack_size = atoll( env_str ) * 1024; + else if (sgi && !strcmp( sgi, "702700" )) + kernel_stack_size = 200 * 1024; + if (kernel_stack_size != 0x100000) + ERR( "HACK: setting kernel_stack_size to %luKB.\n", (long)(kernel_stack_size / 1024) ); + if (main_argc > 1 && (strstr(main_argv[1], "\\EADesktop.exe") || strstr(main_argv[1], "\\Link2EA.exe") || strstr(main_argv[1], "EA Desktop\\ErrorReporter.exe") || strstr(main_argv[1], "\\EAConnect_microsoft.exe") || strstr(main_argv[1], "\\EALaunchHelper.exe") || strstr(main_argv[1], "\\EACrashReporter.exe"))) diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index ef2b7ab665e..d54d802e0cb 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -91,7 +91,7 @@ static const SIZE_T page_size = 0x1000; 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 = 0x100000; +extern SIZE_T kernel_stack_size; static const SIZE_T kernel_stack_guard_size = 0x1000; static const SIZE_T min_kernel_stack = 0x3000; static const LONG teb_offset = 0x2000; From 2ca613269f544ff467fa23f7a7b4d6343a02b645 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 16 May 2023 17:43:57 -0600 Subject: [PATCH 1313/2777] ntdll: Handle context overlap in call_user_exception_dispatcher() on x64. (cherry picked from commit 901c8b90a1d2e5e91cd33bed57316e43e607ccbf) CW-Bug-Id: #22275 --- dlls/ntdll/unix/signal_x86_64.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index ec5535c742a..0674ce2a575 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1580,15 +1580,15 @@ NTSTATUS call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context rsp = (rsp - sizeof(XSTATE)) & ~63; stack = (struct stack_layout *)rsp - 1; assert( !((ULONG_PTR)stack->xstate & 63) ); + memmove( &stack->context, context, sizeof(*context) ); context_init_xstate( &stack->context, stack->xstate ); memcpy( stack->xstate, &frame->xstate, sizeof(frame->xstate) ); } - - memmove( &stack->context, context, sizeof(*context) ); + else memmove( &stack->context, context, sizeof(*context) ); stack->rec = *rec; /* fix up instruction pointer in context for EXCEPTION_BREAKPOINT */ if (stack->rec.ExceptionCode == EXCEPTION_BREAKPOINT) stack->context.Rip--; - frame->rbp = context->Rbp; + frame->rbp = stack->context.Rbp; frame->rsp = (ULONG64)stack; frame->rip = (ULONG64)pKiUserExceptionDispatcher; frame->restore_flags |= CONTEXT_CONTROL; From 0c0cf292df2636ae46ac3ec418e715ff33d983ff Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 15 May 2023 19:00:02 -0600 Subject: [PATCH 1314/2777] wined3d: Avoid sysmem pinning streaming buffer. CW-Bug-Id: #22259 Currently that happens on _SOFTWARE_VERTEXPROCESSING devices and prevents _MAP_DISCARD and _MAP_NOOVERWRITE optimization. --- dlls/wined3d/buffer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/wined3d/buffer.c b/dlls/wined3d/buffer.c index fa24f006872..29a6a062520 100644 --- a/dlls/wined3d/buffer.c +++ b/dlls/wined3d/buffer.c @@ -1288,7 +1288,7 @@ static HRESULT wined3d_buffer_init(struct wined3d_buffer *buffer, struct wined3d access |= WINED3D_RESOURCE_ACCESS_MAP_W; if (FAILED(hr = resource_init(resource, device, WINED3D_RTYPE_BUFFER, format, - WINED3D_MULTISAMPLE_NONE, 0, desc->usage, desc->bind_flags, access, + WINED3D_MULTISAMPLE_NONE, 0, desc->usage & ~WINED3DUSAGE_PRIVATE, desc->bind_flags, access, desc->byte_width, 1, 1, desc->byte_width, parent, parent_ops, &buffer_resource_ops))) { WARN("Failed to initialize resource, hr %#lx.\n", hr); @@ -1301,8 +1301,8 @@ static HRESULT wined3d_buffer_init(struct wined3d_buffer *buffer, struct wined3d TRACE("buffer %p, size %#x, usage %#x, memory @ %p.\n", buffer, buffer->resource.size, buffer->resource.usage, buffer->resource.heap_memory); - if (device->create_parms.flags & WINED3DCREATE_SOFTWARE_VERTEXPROCESSING - || (desc->usage & WINED3DUSAGE_MANAGED)) + if (!(desc->usage & WINED3DUSAGE_PRIVATE) && (device->create_parms.flags & WINED3DCREATE_SOFTWARE_VERTEXPROCESSING + || (desc->usage & WINED3DUSAGE_MANAGED))) { /* SWvp and managed buffers always return the same pointer in buffer * maps and retain data in DISCARD maps. Keep a system memory copy of @@ -1675,7 +1675,7 @@ static HRESULT wined3d_streaming_buffer_prepare(struct wined3d_device *device, TRACE("Growing buffer to %u bytes.\n", size); desc.byte_width = size; - desc.usage = WINED3DUSAGE_DYNAMIC; + desc.usage = WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_PRIVATE; desc.bind_flags = buffer->bind_flags; desc.access = WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_MAP_W; desc.misc_flags = 0; From b734efa46c3449942d7e3bb94837c037bfca590e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 16 May 2023 20:17:32 -0600 Subject: [PATCH 1315/2777] wined3d: Only set changed.lights if wined3d_light_state_enable_light() changed state. (cherry picked from commit 45ee728dbb2f343f1e9f68e1c983c8eaf57e1680) CW-Bug-Id: #22259 --- dlls/wined3d/cs.c | 3 +-- dlls/wined3d/device.c | 4 ++-- dlls/wined3d/stateblock.c | 17 ++++++++++------- dlls/wined3d/wined3d_private.h | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 4579cba27fe..3c9fde4874d 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -2024,8 +2024,7 @@ static void wined3d_cs_exec_set_light_enable(struct wined3d_cs *cs, const void * } prev_idx = light_info->glIndex; - wined3d_light_state_enable_light(&cs->state.light_state, &device->adapter->d3d_info, light_info, op->enable); - if (light_info->glIndex != prev_idx) + if (wined3d_light_state_enable_light(&cs->state.light_state, &device->adapter->d3d_info, light_info, op->enable)) { device_invalidate_state(device, STATE_LIGHT_TYPE); device_invalidate_state(device, STATE_ACTIVELIGHT(op->enable ? light_info->glIndex : prev_idx)); diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index e50ef5112b5..230ce7fc132 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -1695,8 +1695,8 @@ static void wined3d_device_set_light_enable(struct wined3d_device *device, UINT } } - wined3d_light_state_enable_light(light_state, &device->adapter->d3d_info, light_info, enable); - wined3d_device_context_emit_set_light_enable(&device->cs->c, light_idx, enable); + if (wined3d_light_state_enable_light(light_state, &device->adapter->d3d_info, light_info, enable)) + wined3d_device_context_emit_set_light_enable(&device->cs->c, light_idx, enable); } static HRESULT wined3d_device_set_clip_plane(struct wined3d_device *device, diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c index 16f58b726d0..7b953fce234 100644 --- a/dlls/wined3d/stateblock.c +++ b/dlls/wined3d/stateblock.c @@ -634,7 +634,7 @@ HRESULT wined3d_light_state_set_light(struct wined3d_light_state *state, DWORD l return WINED3D_OK; } -void wined3d_light_state_enable_light(struct wined3d_light_state *state, const struct wined3d_d3d_info *d3d_info, +bool wined3d_light_state_enable_light(struct wined3d_light_state *state, const struct wined3d_d3d_info *d3d_info, struct wined3d_light_info *light_info, BOOL enable) { unsigned int light_count, i; @@ -644,18 +644,18 @@ void wined3d_light_state_enable_light(struct wined3d_light_state *state, const s if (light_info->glIndex == -1) { TRACE("Light already disabled, nothing to do.\n"); - return; + return false; } state->lights[light_info->glIndex] = NULL; light_info->glIndex = -1; - return; + return true; } if (light_info->glIndex != -1) { TRACE("Light already enabled, nothing to do.\n"); - return; + return false; } /* Find a free light. */ @@ -667,7 +667,7 @@ void wined3d_light_state_enable_light(struct wined3d_light_state *state, const s state->lights[i] = light_info; light_info->glIndex = i; - return; + return true; } /* Our tests show that Windows returns D3D_OK in this situation, even with @@ -677,6 +677,7 @@ void wined3d_light_state_enable_light(struct wined3d_light_state *state, const s * * TODO: Test how this affects rendering. */ WARN("Too many concurrently active lights.\n"); + return false; } static void wined3d_state_record_lights(struct wined3d_light_state *dst_state, @@ -1616,8 +1617,10 @@ HRESULT CDECL wined3d_stateblock_set_light_enable(struct wined3d_stateblock *sta if (FAILED(hr = wined3d_light_state_set_light(light_state, light_idx, &WINED3D_default_light, &light_info))) return hr; } - wined3d_light_state_enable_light(light_state, &stateblock->device->adapter->d3d_info, light_info, enable); - stateblock->changed.lights = 1; + + if (wined3d_light_state_enable_light(light_state, &stateblock->device->adapter->d3d_info, light_info, enable)) + stateblock->changed.lights = 1; + return S_OK; } diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index c2e28a14881..461734c4d2d 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -5023,7 +5023,7 @@ void wined3d_stateblock_state_init(struct wined3d_stateblock_state *state, const struct wined3d_device *device, uint32_t flags) DECLSPEC_HIDDEN; void wined3d_stateblock_state_cleanup(struct wined3d_stateblock_state *state) DECLSPEC_HIDDEN; -void wined3d_light_state_enable_light(struct wined3d_light_state *state, const struct wined3d_d3d_info *d3d_info, +bool wined3d_light_state_enable_light(struct wined3d_light_state *state, const struct wined3d_d3d_info *d3d_info, struct wined3d_light_info *light_info, BOOL enable) DECLSPEC_HIDDEN; struct wined3d_light_info *wined3d_light_state_get_light(const struct wined3d_light_state *state, unsigned int idx) DECLSPEC_HIDDEN; From a3f84d0939666b9c7674784a53028e377f4a3d0b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 15 May 2023 14:12:47 -0600 Subject: [PATCH 1316/2777] wined3d: Track per light state changes in stateblock. (cherry picked from commit debe2bd632cf1f545bca278658b3ba133a013067) CW-Bug-Id: #22259 --- dlls/wined3d/device.c | 17 ++++++------ dlls/wined3d/stateblock.c | 48 ++++++++++++++++++++++------------ dlls/wined3d/wined3d_private.h | 4 +++ 3 files changed, 45 insertions(+), 24 deletions(-) diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 230ce7fc132..3f17c0069ea 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -3964,15 +3964,14 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device, if (changed->lights) { - for (i = 0; i < ARRAY_SIZE(state->light_state->light_map); ++i) - { - const struct wined3d_light_info *light; + struct wined3d_light_info *light, *cursor; - LIST_FOR_EACH_ENTRY(light, &state->light_state->light_map[i], struct wined3d_light_info, entry) - { - wined3d_device_context_set_light(context, light->OriginalIndex, &light->OriginalParms); - wined3d_device_set_light_enable(device, light->OriginalIndex, light->glIndex != -1); - } + LIST_FOR_EACH_ENTRY_SAFE(light, cursor, &changed->changed_lights, struct wined3d_light_info, changed_entry) + { + wined3d_device_context_set_light(context, light->OriginalIndex, &light->OriginalParms); + wined3d_device_set_light_enable(device, light->OriginalIndex, light->glIndex != -1); + list_remove(&light->changed_entry); + light->changed = false; } } @@ -4286,7 +4285,9 @@ void CDECL wined3d_device_apply_stateblock(struct wined3d_device *device, wined3d_device_set_clip_plane(device, i, &state->clip_planes[i]); } + assert(list_empty(&stateblock->changed.changed_lights)); memset(&stateblock->changed, 0, sizeof(stateblock->changed)); + list_init(&stateblock->changed.changed_lights); TRACE("Applied stateblock %p.\n", stateblock); } diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c index 7b953fce234..6688889d6ff 100644 --- a/dlls/wined3d/stateblock.c +++ b/dlls/wined3d/stateblock.c @@ -340,8 +340,9 @@ void CDECL wined3d_stateblock_init_contained_states(struct wined3d_stateblock *s } } -static void stateblock_init_lights(struct list *dst_map, const struct list *src_map) +static void stateblock_init_lights(struct wined3d_stateblock *stateblock, const struct list *src_map) { + struct list *dst_map = stateblock->stateblock_state.light_state->light_map; unsigned int i; for (i = 0; i < LIGHTMAP_SIZE; ++i) @@ -354,6 +355,8 @@ static void stateblock_init_lights(struct list *dst_map, const struct list *src_ *dst_light = *src_light; list_add_tail(&dst_map[i], &dst_light->entry); + dst_light->changed = true; + list_add_tail(&stateblock->changed.changed_lights, &dst_light->changed_entry); } } } @@ -545,6 +548,8 @@ void wined3d_stateblock_state_cleanup(struct wined3d_stateblock_state *state) { LIST_FOR_EACH_ENTRY_SAFE(light, cursor, &state->light_state->light_map[i], struct wined3d_light_info, entry) { + if (light->changed) + list_remove(&light->changed_entry); list_remove(&light->entry); heap_free(light); } @@ -570,6 +575,8 @@ void state_cleanup(struct wined3d_state *state) { struct wined3d_light_info *light = LIST_ENTRY(e1, struct wined3d_light_info, entry); list_remove(&light->entry); + if (light->changed) + list_remove(&light->changed_entry); heap_free(light); } } @@ -607,6 +614,16 @@ struct wined3d_light_info *wined3d_light_state_get_light(const struct wined3d_li return NULL; } +static void set_light_changed(struct wined3d_stateblock *stateblock, struct wined3d_light_info *light_info) +{ + if (!light_info->changed) + { + list_add_tail(&stateblock->changed.changed_lights, &light_info->changed_entry); + light_info->changed = true; + } + stateblock->changed.lights = 1; +} + HRESULT wined3d_light_state_set_light(struct wined3d_light_state *state, DWORD light_idx, const struct wined3d_light *params, struct wined3d_light_info **light_info) { @@ -1060,15 +1077,12 @@ void CDECL wined3d_stateblock_apply(const struct wined3d_stateblock *stateblock, if (stateblock->changed.lights) { - for (i = 0; i < ARRAY_SIZE(state->light_state->light_map); ++i) - { - const struct wined3d_light_info *light; + const struct wined3d_light_info *light; - LIST_FOR_EACH_ENTRY(light, &state->light_state->light_map[i], struct wined3d_light_info, entry) - { - wined3d_stateblock_set_light(device_state, light->OriginalIndex, &light->OriginalParms); - wined3d_stateblock_set_light_enable(device_state, light->OriginalIndex, light->glIndex != -1); - } + LIST_FOR_EACH_ENTRY(light, &stateblock->changed.changed_lights, struct wined3d_light_info, changed_entry) + { + wined3d_stateblock_set_light(device_state, light->OriginalIndex, &light->OriginalParms); + wined3d_stateblock_set_light_enable(device_state, light->OriginalIndex, light->glIndex != -1); } } @@ -1568,6 +1582,7 @@ HRESULT CDECL wined3d_stateblock_set_light(struct wined3d_stateblock *stateblock UINT light_idx, const struct wined3d_light *light) { struct wined3d_light_info *object = NULL; + HRESULT hr; TRACE("stateblock %p, light_idx %u, light %p.\n", stateblock, light_idx, light); @@ -1600,8 +1615,9 @@ HRESULT CDECL wined3d_stateblock_set_light(struct wined3d_stateblock *stateblock return WINED3DERR_INVALIDCALL; } - stateblock->changed.lights = 1; - return wined3d_light_state_set_light(stateblock->stateblock_state.light_state, light_idx, light, &object); + if (SUCCEEDED(hr = wined3d_light_state_set_light(stateblock->stateblock_state.light_state, light_idx, light, &object))) + set_light_changed(stateblock, object); + return hr; } HRESULT CDECL wined3d_stateblock_set_light_enable(struct wined3d_stateblock *stateblock, UINT light_idx, BOOL enable) @@ -1616,10 +1632,11 @@ HRESULT CDECL wined3d_stateblock_set_light_enable(struct wined3d_stateblock *sta { if (FAILED(hr = wined3d_light_state_set_light(light_state, light_idx, &WINED3D_default_light, &light_info))) return hr; + set_light_changed(stateblock, light_info); } if (wined3d_light_state_enable_light(light_state, &stateblock->device->adapter->d3d_info, light_info, enable)) - stateblock->changed.lights = 1; + set_light_changed(stateblock, light_info); return S_OK; } @@ -2008,6 +2025,7 @@ static HRESULT stateblock_init(struct wined3d_stateblock *stateblock, const stru type == WINED3D_SBT_PRIMARY ? WINED3D_STATE_INIT_DEFAULT : 0); stateblock->changed.store_stream_offset = 1; + list_init(&stateblock->changed.changed_lights); if (type == WINED3D_SBT_RECORDED || type == WINED3D_SBT_PRIMARY) return WINED3D_OK; @@ -2017,8 +2035,7 @@ static HRESULT stateblock_init(struct wined3d_stateblock *stateblock, const stru switch (type) { case WINED3D_SBT_ALL: - stateblock_init_lights(stateblock->stateblock_state.light_state->light_map, - device_state->stateblock_state.light_state->light_map); + stateblock_init_lights(stateblock, device_state->stateblock_state.light_state->light_map); stateblock_savedstates_set_all(&stateblock->changed, d3d_info->limits.vs_uniform_count, d3d_info->limits.ps_uniform_count); break; @@ -2029,8 +2046,7 @@ static HRESULT stateblock_init(struct wined3d_stateblock *stateblock, const stru break; case WINED3D_SBT_VERTEX_STATE: - stateblock_init_lights(stateblock->stateblock_state.light_state->light_map, - device_state->stateblock_state.light_state->light_map); + stateblock_init_lights(stateblock, device_state->stateblock_state.light_state->light_map); stateblock_savedstates_set_vertex(&stateblock->changed, d3d_info->limits.vs_uniform_count); break; diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 461734c4d2d..d6a1fc32614 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2966,6 +2966,8 @@ struct wined3d_light_info float cutoff; struct list entry; + struct list changed_entry; + bool changed; }; /* The default light parameters */ @@ -4990,6 +4992,8 @@ struct wined3d_saved_states DWORD lights : 1; DWORD transforms : 1; DWORD padding : 1; + + struct list changed_lights; }; struct StageState { From a817a627579245b34e2c161a310151c48fdd1aad Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 16 May 2023 21:12:24 -0600 Subject: [PATCH 1317/2777] wined3d: Use RB tree for storing lights. (cherry picked from commit 71da110b4689d7fc8ca1439dfb7944146b6d8d9d) CW-Bug-Id: #22259 --- dlls/wined3d/cs.c | 5 +- dlls/wined3d/device.c | 62 ++++++------- dlls/wined3d/stateblock.c | 155 ++++++++++++++------------------- dlls/wined3d/wined3d_private.h | 8 +- 4 files changed, 98 insertions(+), 132 deletions(-) diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 3c9fde4874d..fa1204d67e9 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -1965,7 +1965,7 @@ static void wined3d_cs_exec_set_light(struct wined3d_cs *cs, const void *data) { const struct wined3d_cs_set_light *op = data; struct wined3d_light_info *light_info; - unsigned int light_idx, hash_idx; + unsigned int light_idx; light_idx = op->light.OriginalIndex; @@ -1978,10 +1978,9 @@ static void wined3d_cs_exec_set_light(struct wined3d_cs *cs, const void *data) return; } - hash_idx = LIGHTMAP_HASHFUNC(light_idx); - list_add_head(&cs->state.light_state.light_map[hash_idx], &light_info->entry); light_info->glIndex = -1; light_info->OriginalIndex = light_idx; + rb_put(&cs->state.light_state.lights_tree, (void *)(ULONG_PTR)light_idx, &light_info->entry); } if (light_info->glIndex != -1) diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 3f17c0069ea..6391c603fee 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -1907,7 +1907,7 @@ void CDECL wined3d_device_context_reset_state(struct wined3d_device_context *con void CDECL wined3d_device_context_set_state(struct wined3d_device_context *context, struct wined3d_state *state) { - const struct wined3d_light_info *light; + struct wined3d_light_info *light; unsigned int i, j; TRACE("context %p, state %p.\n", context, state); @@ -1991,13 +1991,10 @@ void CDECL wined3d_device_context_set_state(struct wined3d_device_context *conte wined3d_device_context_emit_set_viewports(context, state->viewport_count, state->viewports); wined3d_device_context_emit_set_scissor_rects(context, state->scissor_rect_count, state->scissor_rects); - for (i = 0; i < LIGHTMAP_SIZE; ++i) + RB_FOR_EACH_ENTRY(light, &state->light_state.lights_tree, struct wined3d_light_info, entry) { - LIST_FOR_EACH_ENTRY(light, &state->light_state.light_map[i], struct wined3d_light_info, entry) - { - wined3d_device_context_set_light(context, light->OriginalIndex, &light->OriginalParms); - wined3d_device_context_emit_set_light_enable(context, light->OriginalIndex, light->glIndex != -1); - } + wined3d_device_context_set_light(context, light->OriginalIndex, &light->OriginalParms); + wined3d_device_context_emit_set_light_enable(context, light->OriginalIndex, light->glIndex != -1); } for (i = 0; i < WINEHIGHEST_RENDER_STATE + 1; ++i) @@ -3074,6 +3071,7 @@ static void init_transformed_lights(struct lights_settings *ls, { const struct wined3d_light_info *lights[WINED3D_MAX_SOFTWARE_ACTIVE_LIGHTS]; const struct wined3d_light_info *light_info; + struct wined3d_light_info *light_iter; struct light_transformed *light; struct wined3d_vec4 vec4; unsigned int light_count; @@ -3105,39 +3103,37 @@ static void init_transformed_lights(struct lights_settings *ls, ls->normalise = !!state->render_states[WINED3D_RS_NORMALIZENORMALS]; ls->localviewer = !!state->render_states[WINED3D_RS_LOCALVIEWER]; - for (i = 0, index = 0; i < LIGHTMAP_SIZE && index < ARRAY_SIZE(lights); ++i) + index = 0; + RB_FOR_EACH_ENTRY(light_iter, &state->light_state.lights_tree, struct wined3d_light_info, entry) { - LIST_FOR_EACH_ENTRY(light_info, &state->light_state.light_map[i], struct wined3d_light_info, entry) - { - if (!light_info->enabled) - continue; - - switch (light_info->OriginalParms.type) - { - case WINED3D_LIGHT_DIRECTIONAL: - ++ls->directional_light_count; - break; + if (!light_iter->enabled) + continue; - case WINED3D_LIGHT_POINT: - ++ls->point_light_count; - break; + switch (light_iter->OriginalParms.type) + { + case WINED3D_LIGHT_DIRECTIONAL: + ++ls->directional_light_count; + break; - case WINED3D_LIGHT_SPOT: - ++ls->spot_light_count; - break; + case WINED3D_LIGHT_POINT: + ++ls->point_light_count; + break; - case WINED3D_LIGHT_PARALLELPOINT: - ++ls->parallel_point_light_count; - break; + case WINED3D_LIGHT_SPOT: + ++ls->spot_light_count; + break; - default: - FIXME("Unhandled light type %#x.\n", light_info->OriginalParms.type); - continue; - } - lights[index++] = light_info; - if (index == WINED3D_MAX_SOFTWARE_ACTIVE_LIGHTS) + case WINED3D_LIGHT_PARALLELPOINT: + ++ls->parallel_point_light_count; break; + + default: + FIXME("Unhandled light type %#x.\n", light_iter->OriginalParms.type); + continue; } + lights[index++] = light_iter; + if (index == WINED3D_MAX_SOFTWARE_ACTIVE_LIGHTS) + break; } light_count = index; diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c index 6688889d6ff..3d6edbfa7f3 100644 --- a/dlls/wined3d/stateblock.c +++ b/dlls/wined3d/stateblock.c @@ -340,24 +340,19 @@ void CDECL wined3d_stateblock_init_contained_states(struct wined3d_stateblock *s } } -static void stateblock_init_lights(struct wined3d_stateblock *stateblock, const struct list *src_map) +static void stateblock_init_lights(struct wined3d_stateblock *stateblock, const struct rb_tree *src_tree) { - struct list *dst_map = stateblock->stateblock_state.light_state->light_map; - unsigned int i; + struct rb_tree *dst_tree = &stateblock->stateblock_state.light_state->lights_tree; + struct wined3d_light_info *src_light; - for (i = 0; i < LIGHTMAP_SIZE; ++i) + RB_FOR_EACH_ENTRY(src_light, src_tree, struct wined3d_light_info, entry) { - const struct wined3d_light_info *src_light; - - LIST_FOR_EACH_ENTRY(src_light, &src_map[i], struct wined3d_light_info, entry) - { - struct wined3d_light_info *dst_light = heap_alloc(sizeof(*dst_light)); + struct wined3d_light_info *dst_light = heap_alloc(sizeof(*dst_light)); - *dst_light = *src_light; - list_add_tail(&dst_map[i], &dst_light->entry); - dst_light->changed = true; - list_add_tail(&stateblock->changed.changed_lights, &dst_light->changed_entry); - } + *dst_light = *src_light; + rb_put(dst_tree, (void *)(ULONG_PTR)dst_light->OriginalIndex, &dst_light->entry); + dst_light->changed = true; + list_add_tail(&stateblock->changed.changed_lights, &dst_light->changed_entry); } } @@ -544,41 +539,34 @@ void wined3d_stateblock_state_cleanup(struct wined3d_stateblock_state *state) } } - for (i = 0; i < LIGHTMAP_SIZE; ++i) + RB_FOR_EACH_ENTRY_DESTRUCTOR(light, cursor, &state->light_state->lights_tree, struct wined3d_light_info, entry) { - LIST_FOR_EACH_ENTRY_SAFE(light, cursor, &state->light_state->light_map[i], struct wined3d_light_info, entry) - { - if (light->changed) - list_remove(&light->changed_entry); - list_remove(&light->entry); - heap_free(light); - } + if (light->changed) + list_remove(&light->changed_entry); + rb_remove(&state->light_state->lights_tree, &light->entry); + heap_free(light); } } void state_cleanup(struct wined3d_state *state) { - unsigned int counter; + struct wined3d_light_info *light, *cursor; + unsigned int i; if (!(state->flags & WINED3D_STATE_NO_REF)) state_unbind_resources(state); - for (counter = 0; counter < WINED3D_MAX_ACTIVE_LIGHTS; ++counter) + for (i = 0; i < WINED3D_MAX_ACTIVE_LIGHTS; ++i) { - state->light_state.lights[counter] = NULL; + state->light_state.lights[i] = NULL; } - for (counter = 0; counter < LIGHTMAP_SIZE; ++counter) + RB_FOR_EACH_ENTRY_DESTRUCTOR(light, cursor, &state->light_state.lights_tree, struct wined3d_light_info, entry) { - struct list *e1, *e2; - LIST_FOR_EACH_SAFE(e1, e2, &state->light_state.light_map[counter]) - { - struct wined3d_light_info *light = LIST_ENTRY(e1, struct wined3d_light_info, entry); - list_remove(&light->entry); - if (light->changed) - list_remove(&light->changed_entry); - heap_free(light); - } + if (light->changed) + list_remove(&light->changed_entry); + rb_remove(&state->light_state.lights_tree, &light->entry); + heap_free(light); } } @@ -601,17 +589,12 @@ ULONG CDECL wined3d_stateblock_decref(struct wined3d_stateblock *stateblock) struct wined3d_light_info *wined3d_light_state_get_light(const struct wined3d_light_state *state, unsigned int idx) { - struct wined3d_light_info *light_info; - unsigned int hash_idx; + struct rb_entry *entry; - hash_idx = LIGHTMAP_HASHFUNC(idx); - LIST_FOR_EACH_ENTRY(light_info, &state->light_map[hash_idx], struct wined3d_light_info, entry) - { - if (light_info->OriginalIndex == idx) - return light_info; - } + if (!(entry = rb_get(&state->lights_tree, (void *)(ULONG_PTR)idx))) + return NULL; - return NULL; + return RB_ENTRY_VALUE(entry, struct wined3d_light_info, entry); } static void set_light_changed(struct wined3d_stateblock *stateblock, struct wined3d_light_info *light_info) @@ -628,7 +611,6 @@ HRESULT wined3d_light_state_set_light(struct wined3d_light_state *state, DWORD l const struct wined3d_light *params, struct wined3d_light_info **light_info) { struct wined3d_light_info *object; - unsigned int hash_idx; if (!(object = wined3d_light_state_get_light(state, light_idx))) { @@ -639,10 +621,9 @@ HRESULT wined3d_light_state_set_light(struct wined3d_light_state *state, DWORD l return E_OUTOFMEMORY; } - hash_idx = LIGHTMAP_HASHFUNC(light_idx); - list_add_head(&state->light_map[hash_idx], &object->entry); object->glIndex = -1; object->OriginalIndex = light_idx; + rb_put(&state->lights_tree, (void *)(ULONG_PTR)light_idx, &object->entry); } object->OriginalParms = *params; @@ -702,44 +683,40 @@ static void wined3d_state_record_lights(struct wined3d_light_state *dst_state, { const struct wined3d_light_info *src; struct wined3d_light_info *dst; - UINT i; /* Lights... For a recorded state block, we just had a chain of actions * to perform, so we need to walk that chain and update any actions which * differ. */ - for (i = 0; i < LIGHTMAP_SIZE; ++i) + RB_FOR_EACH_ENTRY(dst, &dst_state->lights_tree, struct wined3d_light_info, entry) { - LIST_FOR_EACH_ENTRY(dst, &dst_state->light_map[i], struct wined3d_light_info, entry) + if ((src = wined3d_light_state_get_light(src_state, dst->OriginalIndex))) { - if ((src = wined3d_light_state_get_light(src_state, dst->OriginalIndex))) + dst->OriginalParms = src->OriginalParms; + + if (src->glIndex == -1 && dst->glIndex != -1) { - dst->OriginalParms = src->OriginalParms; - - if (src->glIndex == -1 && dst->glIndex != -1) - { - /* Light disabled. */ - dst_state->lights[dst->glIndex] = NULL; - } - else if (src->glIndex != -1 && dst->glIndex == -1) - { - /* Light enabled. */ - dst_state->lights[src->glIndex] = dst; - } - dst->glIndex = src->glIndex; + /* Light disabled. */ + dst_state->lights[dst->glIndex] = NULL; } - else + else if (src->glIndex != -1 && dst->glIndex == -1) { - /* This can happen if the light was originally created as a - * default light for SetLightEnable() while recording. */ - WARN("Light %u in dst_state %p does not exist in src_state %p.\n", - dst->OriginalIndex, dst_state, src_state); - - dst->OriginalParms = WINED3D_default_light; - if (dst->glIndex != -1) - { - dst_state->lights[dst->glIndex] = NULL; - dst->glIndex = -1; - } + /* Light enabled. */ + dst_state->lights[src->glIndex] = dst; + } + dst->glIndex = src->glIndex; + } + else + { + /* This can happen if the light was originally created as a + * default light for SetLightEnable() while recording. */ + WARN("Light %u in dst_state %p does not exist in src_state %p.\n", + dst->OriginalIndex, dst_state, src_state); + + dst->OriginalParms = WINED3D_default_light; + if (dst->glIndex != -1) + { + dst_state->lights[dst->glIndex] = NULL; + dst->glIndex = -1; } } } @@ -1895,18 +1872,21 @@ static void state_init_default(struct wined3d_state *state, const struct wined3d } } +static int lights_compare(const void *key, const struct rb_entry *entry) +{ + const struct wined3d_light_info *light = RB_ENTRY_VALUE(entry, struct wined3d_light_info, entry); + unsigned int original_index = (ULONG_PTR)key; + + return wined3d_uint32_compare(light->OriginalIndex, original_index); +} + void state_init(struct wined3d_state *state, const struct wined3d_d3d_info *d3d_info, uint32_t flags, enum wined3d_feature_level feature_level) { - unsigned int i; - state->feature_level = feature_level; state->flags = flags; - for (i = 0; i < LIGHTMAP_SIZE; i++) - { - list_init(&state->light_state.light_map[i]); - } + rb_init(&state->light_state.lights_tree, lights_compare); if (flags & WINED3D_STATE_INIT_DEFAULT) state_init_default(state, d3d_info); @@ -2001,12 +1981,7 @@ static void stateblock_state_init_default(struct wined3d_stateblock_state *state void wined3d_stateblock_state_init(struct wined3d_stateblock_state *state, const struct wined3d_device *device, uint32_t flags) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(state->light_state->light_map); i++) - { - list_init(&state->light_state->light_map[i]); - } + rb_init(&state->light_state->lights_tree, lights_compare); if (flags & WINED3D_STATE_INIT_DEFAULT) stateblock_state_init_default(state, &device->adapter->d3d_info); @@ -2035,7 +2010,7 @@ static HRESULT stateblock_init(struct wined3d_stateblock *stateblock, const stru switch (type) { case WINED3D_SBT_ALL: - stateblock_init_lights(stateblock, device_state->stateblock_state.light_state->light_map); + stateblock_init_lights(stateblock, &device_state->stateblock_state.light_state->lights_tree); stateblock_savedstates_set_all(&stateblock->changed, d3d_info->limits.vs_uniform_count, d3d_info->limits.ps_uniform_count); break; @@ -2046,7 +2021,7 @@ static HRESULT stateblock_init(struct wined3d_stateblock *stateblock, const stru break; case WINED3D_SBT_VERTEX_STATE: - stateblock_init_lights(stateblock, device_state->stateblock_state.light_state->light_map); + stateblock_init_lights(stateblock, &device_state->stateblock_state.light_state->lights_tree); stateblock_savedstates_set_vertex(&stateblock->changed, d3d_info->limits.vs_uniform_count); break; diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index d6a1fc32614..f7c35f63d9e 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2965,7 +2965,7 @@ struct wined3d_light_info float exponent; float cutoff; - struct list entry; + struct rb_entry entry; struct list changed_entry; bool changed; }; @@ -3858,13 +3858,9 @@ struct wined3d_rasterizer_state struct wine_rb_entry entry; }; -#define LIGHTMAP_SIZE 43 -#define LIGHTMAP_HASHFUNC(x) ((x) % LIGHTMAP_SIZE) - struct wined3d_light_state { - /* Light hashmap. Collisions are handled using linked lists. */ - struct list light_map[LIGHTMAP_SIZE]; + struct rb_tree lights_tree; const struct wined3d_light_info *lights[WINED3D_MAX_ACTIVE_LIGHTS]; }; From 242111fb85e3fa7f7a516c0ec18e0f161e9c6837 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 17 May 2023 15:42:34 -0600 Subject: [PATCH 1318/2777] fshack: winex11: Use linear colour internal format for GL fshack buffer. CW-Bug-Id: #22260 --- dlls/winex11.drv/opengl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index b9cfb845163..b5fd4788291 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2134,7 +2134,7 @@ static void fs_hack_get_attachments_config( struct gl_drawable *gl, struct fs_ha if (attribs->red_size != 8 || attribs->green_size != 8 || attribs->blue_size != 8) FIXME( "Unsupported RGBA color sizes {%u, %u, %u, %u}.\n", attribs->red_size, attribs->green_size, attribs->blue_size, attribs->alpha_size ); - config->color_internalformat = attribs->alpha_size ? GL_SRGB8_ALPHA8 : GL_SRGB8; + config->color_internalformat = attribs->alpha_size ? GL_RGBA8 : GL_RGB8; config->color_format = GL_BGRA; config->color_type = GL_UNSIGNED_INT_8_8_8_8_REV; if (attribs->depth_size || attribs->stencil_size) @@ -2794,7 +2794,7 @@ static void fs_hack_handle_shaders( int mode, struct gl_drawable *gl, struct wgl fs_hack_handle_enable_switch( mode, GL_FRAGMENT_PROGRAM_ARB, &state->arb_frag, FALSE ); if (gl->has_vertex_program) fs_hack_handle_enable_switch( mode, GL_VERTEX_PROGRAM_ARB, &state->arb_vert, FALSE ); - fs_hack_handle_enable_switch( mode, GL_FRAMEBUFFER_SRGB, &state->fb_srgb, TRUE ); + fs_hack_handle_enable_switch( mode, GL_FRAMEBUFFER_SRGB, &state->fb_srgb, FALSE ); if (gl->has_ati_frag_shader) fs_hack_handle_enable_switch( mode, GL_FRAGMENT_SHADER_ATI, &state->ati_frag, FALSE ); From 1218f54de8d29b04a4c4c82315180de2154edccd Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 17 May 2023 21:08:23 -0600 Subject: [PATCH 1319/2777] kernelbase: HACK: Add WINE_SHRINK_ENV option. CW-Bug-Id: #22272 --- dlls/kernelbase/process.c | 56 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 8e1a729a9ab..4e0925c00ee 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -1646,6 +1646,59 @@ LPSTR WINAPI DECLSPEC_HOTPATCH GetEnvironmentStringsA(void) return ret; } +static void hack_shrink_environment( WCHAR *env, SIZE_T len ) +{ + static int enabled = -1; + static const char *skip[] = + { + "SteamGenericControllers=", + "STEAM_RUNTIME_LIBRARY_PATH=", + "SDL_GAMECONTROLLER_IGNORE_DEVICES=", + "SDL_GAMECONTROLLERCONFIG=", + "LD_LIBRARY_PATH=", + "ORIG_LD_LIBRARY_PATH=", + "LS_COLORS=", + "BASH_FUNC_", + "XDG_DATA_DIRS=", + }; + SIZE_T l; + unsigned int i, j; + + if (enabled == -1) + { + WCHAR str[40]; + + *str = 0; + if (GetEnvironmentVariableW( L"WINE_SHRINK_ENV", str, sizeof(str)) ) + enabled = *str != '0'; + else if (GetEnvironmentVariableW( L"SteamGameId", str, sizeof(str)) ) + enabled = !wcscmp( str, L"431590" ); + else + enabled = 0; + + if (enabled) + ERR( "HACK: shrinking environment size.\n" ); + } + + if (!enabled) return; + + while (*env) + { + for (i = 0; i < ARRAY_SIZE(skip); ++i) + { + j = 0; + while (skip[i][j] && skip[i][j] == env[j]) + ++j; + if (!skip[i][j]) break; + } + l = lstrlenW( env ); + len -= (l + 1) * sizeof(WCHAR); + if (i == ARRAY_SIZE(skip)) + env += l + 1; + else + memmove( env, env + l + 1, len ); + } +} /*********************************************************************** * GetEnvironmentStringsW (kernelbase.@) @@ -1658,7 +1711,10 @@ LPWSTR WINAPI DECLSPEC_HOTPATCH GetEnvironmentStringsW(void) RtlAcquirePebLock(); len = get_env_length( NtCurrentTeb()->Peb->ProcessParameters->Environment ) * sizeof(WCHAR); if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) + { memcpy( ret, NtCurrentTeb()->Peb->ProcessParameters->Environment, len ); + hack_shrink_environment( ret, len ); + } RtlReleasePebLock(); return ret; } From d77e084b017e924c7050fe683eee467b6173f997 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 22 Sep 2022 15:48:40 -0500 Subject: [PATCH 1320/2777] msvcrt: HACK: Disable SSE2 support for Indiana Jones and The Emperor Tomb. CW-Bug-Id: #21330 --- dlls/msvcrt/math.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c index 854403a71bf..ec04bd9b411 100644 --- a/dlls/msvcrt/math.c +++ b/dlls/msvcrt/math.c @@ -72,6 +72,15 @@ void msvcrt_init_math( void *module ) sse2_supported = IsProcessorFeaturePresent( PF_XMMI64_INSTRUCTIONS_AVAILABLE ); #if _MSVCR_VER <=71 sse2_enabled = FALSE; + { + char sgi[64]; + + if (GetEnvironmentVariableA("SteamGameId", sgi, sizeof(sgi)) && !strcmp(sgi, "560430")) + { + sse2_supported = FALSE; + FIXME("HACK: disabling sse2 support in msvcrt.\n"); + } + } #else sse2_enabled = sse2_supported; #endif From d9c2ff2303f5ca5af63472b1a72b26037911cc3c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 22 Sep 2022 15:50:33 -0500 Subject: [PATCH 1321/2777] msvcrt: HACK: Disable SSE2 support for DarkStar One. CW-Bug-Id: #21330 --- dlls/msvcrt/math.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c index ec04bd9b411..0a282a0722b 100644 --- a/dlls/msvcrt/math.c +++ b/dlls/msvcrt/math.c @@ -75,7 +75,8 @@ void msvcrt_init_math( void *module ) { char sgi[64]; - if (GetEnvironmentVariableA("SteamGameId", sgi, sizeof(sgi)) && !strcmp(sgi, "560430")) + if (GetEnvironmentVariableA("SteamGameId", sgi, sizeof(sgi)) + && (!strcmp(sgi, "560430") || !strcmp(sgi, "12330"))) { sse2_supported = FALSE; FIXME("HACK: disabling sse2 support in msvcrt.\n"); From f23c5efb61cc7e58dd32e318bd47c6375fb375c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 16 May 2023 15:32:25 +0200 Subject: [PATCH 1322/2777] Revert "win32u: Do not set last error in wait_message() for zero count." This reverts commit d6e917c1aad9fe23fe50c206f8bde063da6c91fa. --- dlls/win32u/message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index ea7b9db522b..203d00dbc57 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2281,7 +2281,7 @@ static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DW mask, flags ); if (HIWORD(ret)) /* is it an error code? */ { - if (count) RtlSetLastWin32Error( RtlNtStatusToDosError(ret) ); + RtlSetLastWin32Error( RtlNtStatusToDosError(ret) ); ret = WAIT_FAILED; } if (ret == WAIT_TIMEOUT && !count && !timeout) NtYieldExecution(); From 89cf83c0b3691687e911bb8fe2f07748593b3323 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 21 Feb 2023 14:43:39 -0600 Subject: [PATCH 1323/2777] win32u: Expose and use ProcessEvents from drivers instead of MsgWaitForMultipleObjectsEx. (cherry picked from commit a97fd9f29e7dbeee2dc06415a34a9f7669ea2e0d) CW-Bug-Id: #21938 --- dlls/win32u/dce.c | 3 +-- dlls/win32u/driver.c | 12 ++++-------- dlls/win32u/input.c | 3 +-- dlls/win32u/message.c | 20 +++++++++++++------- dlls/wineandroid.drv/android.h | 4 +--- dlls/wineandroid.drv/init.c | 2 +- dlls/wineandroid.drv/window.c | 11 ++++------- dlls/winemac.drv/event.c | 27 +++++---------------------- dlls/winemac.drv/gdi.c | 2 +- dlls/winemac.drv/macdrv.h | 4 +--- dlls/winex11.drv/event.c | 25 ++++--------------------- dlls/winex11.drv/init.c | 2 +- dlls/winex11.drv/x11drv.h | 4 +--- include/wine/gdi_driver.h | 2 +- 14 files changed, 39 insertions(+), 82 deletions(-) diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 76a1260ef25..77a7a4ce835 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -1446,7 +1446,6 @@ static void update_now( HWND hwnd, UINT rdw_flags ) */ BOOL WINAPI NtUserRedrawWindow( HWND hwnd, const RECT *rect, HRGN hrgn, UINT flags ) { - LARGE_INTEGER zero = { .QuadPart = 0 }; static const RECT empty; BOOL ret; @@ -1467,7 +1466,7 @@ BOOL WINAPI NtUserRedrawWindow( HWND hwnd, const RECT *rect, HRGN hrgn, UINT fla } /* process pending expose events before painting */ - if (flags & RDW_UPDATENOW) user_driver->pMsgWaitForMultipleObjectsEx( 0, NULL, &zero, QS_PAINT, 0 ); + if (flags & RDW_UPDATENOW) user_driver->pProcessEvents( QS_PAINT ); if (rect && !hrgn) { diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index e2c9ba04efd..1c0708461a1 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -806,13 +806,9 @@ static void nulldrv_GetDC( HDC hdc, HWND hwnd, HWND top_win, const RECT *win_rec { } -static NTSTATUS nulldrv_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, - const LARGE_INTEGER *timeout, - DWORD mask, DWORD flags ) +static BOOL nulldrv_ProcessEvents( DWORD mask ) { - if (!count && timeout && !timeout->QuadPart) return WAIT_TIMEOUT; - return NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL), - !!(flags & MWMO_ALERTABLE), timeout ); + return FALSE; } static void nulldrv_ReleaseDC( HWND hwnd, HDC hdc ) @@ -1193,7 +1189,7 @@ static const struct user_driver_funcs lazy_load_driver = nulldrv_DestroyWindow, loaderdrv_FlashWindowEx, loaderdrv_GetDC, - nulldrv_MsgWaitForMultipleObjectsEx, + nulldrv_ProcessEvents, nulldrv_ReleaseDC, nulldrv_ScrollDC, nulldrv_SetCapture, @@ -1268,7 +1264,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version SET_USER_FUNC(DestroyWindow); SET_USER_FUNC(FlashWindowEx); SET_USER_FUNC(GetDC); - SET_USER_FUNC(MsgWaitForMultipleObjectsEx); + SET_USER_FUNC(ProcessEvents); SET_USER_FUNC(ReleaseDC); SET_USER_FUNC(ScrollDC); SET_USER_FUNC(SetCapture); diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 2e35d3b8d1a..94554fa4c5d 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -747,8 +747,7 @@ BOOL WINAPI NtUserGetCursorInfo( CURSORINFO *info ) static void check_for_events( UINT flags ) { - LARGE_INTEGER zero = { .QuadPart = 0 }; - if (user_driver->pMsgWaitForMultipleObjectsEx( 0, NULL, &zero, flags, 0 ) == WAIT_TIMEOUT) + if (!user_driver->pProcessEvents( flags )) flush_window_surfaces( TRUE ); } diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 203d00dbc57..fc405f39d4c 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2246,9 +2246,8 @@ static inline void check_for_driver_events( UINT msg ) struct user_thread_info *thread_info = get_user_thread_info(); if (thread_info->message_count > 200) { - LARGE_INTEGER zero = { .QuadPart = 0 }; flush_window_surfaces( FALSE ); - user_driver->pMsgWaitForMultipleObjectsEx( 0, NULL, &zero, QS_ALLINPUT, 0 ); + user_driver->pProcessEvents( QS_ALLINPUT ); } else if (msg == WM_TIMER || msg == WM_SYSTIMER) { @@ -2277,13 +2276,20 @@ static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DW if (enable_thunk_lock) lock = KeUserModeCallback( NtUserThunkLock, NULL, 0, &ret_ptr, &ret_len ); - ret = user_driver->pMsgWaitForMultipleObjectsEx( count, handles, get_nt_timeout( &time, timeout ), - mask, flags ); - if (HIWORD(ret)) /* is it an error code? */ + if (user_driver->pProcessEvents( mask )) ret = count ? count - 1 : 0; + else if (count) { - RtlSetLastWin32Error( RtlNtStatusToDosError(ret) ); - ret = WAIT_FAILED; + ret = NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL), + !!(flags & MWMO_ALERTABLE), get_nt_timeout( &time, timeout )); + if (ret == count - 1) user_driver->pProcessEvents( mask ); + else if (HIWORD(ret)) /* is it an error code? */ + { + RtlSetLastWin32Error( RtlNtStatusToDosError(ret) ); + ret = WAIT_FAILED; + } } + else ret = WAIT_TIMEOUT; + if (ret == WAIT_TIMEOUT && !count && !timeout) NtYieldExecution(); if ((mask & QS_INPUT) == QS_INPUT) get_user_thread_info()->message_count = 0; diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h index 22652f11d27..0d073a63bcc 100644 --- a/dlls/wineandroid.drv/android.h +++ b/dlls/wineandroid.drv/android.h @@ -89,9 +89,7 @@ extern SHORT ANDROID_VkKeyScanEx( WCHAR ch, HKL hkl ) DECLSPEC_HIDDEN; extern void ANDROID_SetCursor( HCURSOR handle ) DECLSPEC_HIDDEN; extern BOOL ANDROID_CreateWindow( HWND hwnd ) DECLSPEC_HIDDEN; extern void ANDROID_DestroyWindow( HWND hwnd ) DECLSPEC_HIDDEN; -extern NTSTATUS ANDROID_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, - const LARGE_INTEGER *timeout, - DWORD mask, DWORD flags ) DECLSPEC_HIDDEN; +extern BOOL ANDROID_ProcessEvents( DWORD mask ) DECLSPEC_HIDDEN; extern LRESULT ANDROID_DesktopWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) DECLSPEC_HIDDEN; extern void ANDROID_SetCursor( HCURSOR handle ) DECLSPEC_HIDDEN; extern void ANDROID_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, diff --git a/dlls/wineandroid.drv/init.c b/dlls/wineandroid.drv/init.c index acf6b9abbbe..074aa6c6257 100644 --- a/dlls/wineandroid.drv/init.c +++ b/dlls/wineandroid.drv/init.c @@ -352,7 +352,7 @@ static const struct user_driver_funcs android_drv_funcs = .pCreateWindow = ANDROID_CreateWindow, .pDesktopWindowProc = ANDROID_DesktopWindowProc, .pDestroyWindow = ANDROID_DestroyWindow, - .pMsgWaitForMultipleObjectsEx = ANDROID_MsgWaitForMultipleObjectsEx, + .pProcessEvents = ANDROID_ProcessEvents, .pSetCapture = ANDROID_SetCapture, .pSetLayeredWindowAttributes = ANDROID_SetLayeredWindowAttributes, .pSetParent = ANDROID_SetParent, diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index 222751abc29..eb96300da89 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -1201,20 +1201,17 @@ LRESULT ANDROID_DesktopWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) /*********************************************************************** - * ANDROID_MsgWaitForMultipleObjectsEx + * ANDROID_ProcessEvents */ -NTSTATUS ANDROID_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, - const LARGE_INTEGER *timeout, - DWORD mask, DWORD flags ) +BOOL ANDROID_ProcessEvents( DWORD mask ) { if (GetCurrentThreadId() == desktop_tid) { /* don't process nested events */ if (current_event) mask = 0; - if (process_events( mask )) return count - 1; + return process_events( mask ); } - return NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL), - !!(flags & MWMO_ALERTABLE), timeout ); + return FALSE; } /********************************************************************** diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c index e4f76e2b0e1..5b717b4b730 100644 --- a/dlls/winemac.drv/event.c +++ b/dlls/winemac.drv/event.c @@ -510,24 +510,16 @@ static int process_events(macdrv_event_queue queue, macdrv_event_mask mask) /*********************************************************************** - * MsgWaitForMultipleObjectsEx (MACDRV.@) + * ProcessEvents (MACDRV.@) */ -NTSTATUS macdrv_MsgWaitForMultipleObjectsEx(DWORD count, const HANDLE *handles, - const LARGE_INTEGER *timeout, DWORD mask, DWORD flags) +NTSTATUS macdrv_ProcessEvents(DWORD mask) { - DWORD ret; struct macdrv_thread_data *data = macdrv_thread_data(); macdrv_event_mask event_mask = get_event_mask(mask); - TRACE("count %d, handles %p, timeout %p, mask %x, flags %x\n", (unsigned int)count, - handles, timeout, (unsigned int)mask, (unsigned int)flags); + TRACE("mask %x\n", (unsigned int)mask); - if (!data) - { - if (!count && timeout && !timeout->QuadPart) return WAIT_TIMEOUT; - return NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL), - !!(flags & MWMO_ALERTABLE), timeout ); - } + if (!data) return FALSE; if (data->current_event && data->current_event->type != QUERY_EVENT && data->current_event->type != QUERY_EVENT_NO_PREEMPT_WAIT && @@ -535,14 +527,5 @@ NTSTATUS macdrv_MsgWaitForMultipleObjectsEx(DWORD count, const HANDLE *handles, data->current_event->type != WINDOW_DRAG_BEGIN) event_mask = 0; /* don't process nested events */ - if (process_events(data->queue, event_mask)) ret = count - 1; - else if (count || !timeout || timeout->QuadPart) - { - ret = NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL), - !!(flags & MWMO_ALERTABLE), timeout ); - if (ret == count - 1) process_events(data->queue, event_mask); - } - else ret = WAIT_TIMEOUT; - - return ret; + return process_events(data->queue, event_mask); } diff --git a/dlls/winemac.drv/gdi.c b/dlls/winemac.drv/gdi.c index fd1da722061..d22532fd3b7 100644 --- a/dlls/winemac.drv/gdi.c +++ b/dlls/winemac.drv/gdi.c @@ -282,7 +282,7 @@ static const struct user_driver_funcs macdrv_funcs = .pGetKeyboardLayoutList = macdrv_GetKeyboardLayoutList, .pGetKeyNameText = macdrv_GetKeyNameText, .pMapVirtualKeyEx = macdrv_MapVirtualKeyEx, - .pMsgWaitForMultipleObjectsEx = macdrv_MsgWaitForMultipleObjectsEx, + .pProcessEvents = macdrv_ProcessEvents, .pRegisterHotKey = macdrv_RegisterHotKey, .pSetCapture = macdrv_SetCapture, .pSetCursor = macdrv_SetCursor, diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 40f70e55094..281d49c1e9a 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -169,9 +169,7 @@ extern UINT macdrv_GetKeyboardLayoutList(INT size, HKL *list) DECLSPEC_HIDDEN; extern INT macdrv_GetKeyNameText(LONG lparam, LPWSTR buffer, INT size) DECLSPEC_HIDDEN; extern BOOL macdrv_SystemParametersInfo(UINT action, UINT int_param, void *ptr_param, UINT flags) DECLSPEC_HIDDEN; -extern NTSTATUS macdrv_MsgWaitForMultipleObjectsEx(DWORD count, const HANDLE *handles, - const LARGE_INTEGER *timeout, DWORD mask, - DWORD flags) DECLSPEC_HIDDEN; +extern BOOL macdrv_ProcessEvents(DWORD mask) DECLSPEC_HIDDEN; extern void macdrv_ThreadDetach(void) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index f8ab367acfd..00778ac073b 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -523,33 +523,16 @@ static BOOL process_events( Display *display, Bool (*filter)(Display*, XEvent*,X /*********************************************************************** - * MsgWaitForMultipleObjectsEx (X11DRV.@) + * ProcessEvents (X11DRV.@) */ -NTSTATUS X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, - const LARGE_INTEGER *timeout, DWORD mask, DWORD flags ) +BOOL X11DRV_ProcessEvents( DWORD mask ) { struct x11drv_thread_data *data = x11drv_thread_data(); - NTSTATUS ret; - - if (!data) - { - if (!count && timeout && !timeout->QuadPart) return WAIT_TIMEOUT; - return NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL), - !!(flags & MWMO_ALERTABLE), timeout ); - } + if (!data) return FALSE; if (data->current_event) mask = 0; /* don't process nested events */ - if (process_events( data->display, filter_event, mask )) ret = count - 1; - else if (count || !timeout || timeout->QuadPart) - { - ret = NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL), - !!(flags & MWMO_ALERTABLE), timeout ); - if (ret == count - 1) process_events( data->display, filter_event, mask ); - } - else ret = WAIT_TIMEOUT; - - return ret; + return process_events( data->display, filter_event, mask ); } /*********************************************************************** diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index bd53421dd5b..ef11461ea67 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -415,7 +415,7 @@ static const struct user_driver_funcs x11drv_funcs = .pDestroyWindow = X11DRV_DestroyWindow, .pFlashWindowEx = X11DRV_FlashWindowEx, .pGetDC = X11DRV_GetDC, - .pMsgWaitForMultipleObjectsEx = X11DRV_MsgWaitForMultipleObjectsEx, + .pProcessEvents = X11DRV_ProcessEvents, .pReleaseDC = X11DRV_ReleaseDC, .pScrollDC = X11DRV_ScrollDC, .pSetCapture = X11DRV_SetCapture, diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 9edf97da487..f1ded52c2b8 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -744,9 +744,7 @@ extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN; extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN; extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN; extern void X11DRV_InitMouse( Display *display ) DECLSPEC_HIDDEN; -extern NTSTATUS X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, - const LARGE_INTEGER *timeout, - DWORD mask, DWORD flags ) DECLSPEC_HIDDEN; +extern BOOL X11DRV_ProcessEvents( DWORD mask ) DECLSPEC_HIDDEN; extern HWND *build_hwnd_list(void) DECLSPEC_HIDDEN; typedef int (*x11drv_error_callback)( Display *display, XErrorEvent *event, void *arg ); diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index f87e1ceefb0..96bedd7acab 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -307,7 +307,7 @@ struct user_driver_funcs void (*pDestroyWindow)(HWND); void (*pFlashWindowEx)(FLASHWINFO*); void (*pGetDC)(HDC,HWND,HWND,const RECT *,const RECT *,DWORD); - NTSTATUS (*pMsgWaitForMultipleObjectsEx)(DWORD,const HANDLE*,const LARGE_INTEGER*,DWORD,DWORD); + BOOL (*pProcessEvents)(DWORD); void (*pReleaseDC)(HWND,HDC); BOOL (*pScrollDC)(HDC,INT,INT,HRGN); void (*pSetCapture)(HWND,UINT); From 4803a9dcf4495ba7b8498590856e3c6379aeb44a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 23 May 2023 14:41:14 -0600 Subject: [PATCH 1324/2777] winex11.drv: fshack: Add optional extra display mode. CW-Bug-Id: #22285 --- dlls/winex11.drv/fs.c | 69 ++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/dlls/winex11.drv/fs.c b/dlls/winex11.drv/fs.c index d43ab716e56..74a87007847 100644 --- a/dlls/winex11.drv/fs.c +++ b/dlls/winex11.drv/fs.c @@ -42,29 +42,35 @@ static struct x11drv_settings_handler real_settings_handler; static BOOL initialized; /* A table of resolutions some games expect but host system may not report */ -static SIZE fs_monitor_sizes[] = -{ - {640, 480}, /* 4:3 */ - {800, 600}, /* 4:3 */ - {1024, 768}, /* 4:3 */ - {1600, 1200}, /* 4:3 */ - {960, 540}, /* 16:9 */ - {1280, 720}, /* 16:9 */ - {1600, 900}, /* 16:9 */ - {1920, 1080}, /* 16:9 */ - {2560, 1440}, /* 16:9 */ - {2880, 1620}, /* 16:9 */ - {3200, 1800}, /* 16:9 */ - {1440, 900}, /* 8:5 */ - {1680, 1050}, /* 8:5 */ - {1920, 1200}, /* 8:5 */ - {2560, 1600}, /* 8:5 */ - {1440, 960}, /* 3:2 */ - {1920, 1280}, /* 3:2 */ - {2560, 1080}, /* 21:9 ultra-wide */ - {1920, 800}, /* 12:5 */ - {3840, 1600}, /* 12:5 */ - {1280, 1024}, /* 5:4 */ +static const struct +{ + SIZE size; + BOOL additional; +} +fs_monitor_sizes[] = +{ + {{640, 480}}, /* 4:3 */ + {{800, 600}}, /* 4:3 */ + {{1024, 768}}, /* 4:3 */ + {{1600, 1200}}, /* 4:3 */ + {{960, 540}}, /* 16:9 */ + {{1280, 720}}, /* 16:9 */ + {{1600, 900}}, /* 16:9 */ + {{1920, 1080}}, /* 16:9 */ + {{2560, 1440}}, /* 16:9 */ + {{2880, 1620}}, /* 16:9 */ + {{3200, 1800}}, /* 16:9 */ + {{1440, 900}}, /* 8:5 */ + {{1680, 1050}}, /* 8:5 */ + {{1920, 1200}}, /* 8:5 */ + {{2560, 1600}}, /* 8:5 */ + {{1440, 960}}, /* 3:2 */ + {{1920, 1280}}, /* 3:2 */ + {{2560, 1080}}, /* 21:9 ultra-wide */ + {{1920, 800}}, /* 12:5 */ + {{3840, 1600}}, /* 12:5 */ + {{1280, 1024}}, /* 5:4 */ + {{1280, 768}, TRUE }, }; /* A fake monitor for the fullscreen hack */ @@ -268,6 +274,8 @@ static void monitor_get_modes( struct fs_monitor *monitor, DEVMODEW **modes, UIN { UINT i, j, max_count, real_mode_count, resolutions = 0; DEVMODEW *real_modes, *real_mode, mode_host = {0}; + BOOL additional_modes = FALSE; + const char *env; *mode_count = 0; *modes = NULL; @@ -286,21 +294,28 @@ static void monitor_get_modes( struct fs_monitor *monitor, DEVMODEW **modes, UIN /* Add the current mode early, in case we have to limit */ modes_append( *modes, mode_count, &resolutions, &mode_host ); + if ((env = getenv( "WINE_ADDITIONAL_DISPLAY_MODES" ))) + additional_modes = (env[0] != '0'); + else if ((env = getenv( "SteamAppId" ))) + additional_modes = !strcmp( env, "979400" ); + /* Linux reports far fewer resolutions than Windows. Add modes that some games may expect. */ for (i = 0; i < ARRAY_SIZE(fs_monitor_sizes); ++i) { DEVMODEW mode = mode_host; + if (!additional_modes && fs_monitor_sizes[i].additional) continue; + if (mode_host.dmDisplayOrientation == DMDO_DEFAULT || mode_host.dmDisplayOrientation == DMDO_180) { - mode.dmPelsWidth = fs_monitor_sizes[i].cx; - mode.dmPelsHeight = fs_monitor_sizes[i].cy; + mode.dmPelsWidth = fs_monitor_sizes[i].size.cx; + mode.dmPelsHeight = fs_monitor_sizes[i].size.cy; } else { - mode.dmPelsWidth = fs_monitor_sizes[i].cy; - mode.dmPelsHeight = fs_monitor_sizes[i].cx; + mode.dmPelsWidth = fs_monitor_sizes[i].size.cy; + mode.dmPelsHeight = fs_monitor_sizes[i].size.cx; } /* Don't report modes that are larger than the current mode */ From d1aea5fa46291c25add4624985b8a681fc5b88a2 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 23 May 2023 19:52:45 -0600 Subject: [PATCH 1325/2777] nsiproxy.sys: Detect PPP interface type from flags on Linux. VPN interfaces often have ARPHRD_NONE in ifr_hwaddr.sa_data but IFF_POINTOPOINT flag set. (cherry picked from commit 1ea5d470a21effb90b5a7442a47e7f714ce997dc) CW-Bug-Id: #22287 --- dlls/nsiproxy.sys/ndis.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/nsiproxy.sys/ndis.c b/dlls/nsiproxy.sys/ndis.c index c34630d8aec..1fc66c3611b 100644 --- a/dlls/nsiproxy.sys/ndis.c +++ b/dlls/nsiproxy.sys/ndis.c @@ -170,6 +170,9 @@ static NTSTATUS if_get_physical( const char *name, UINT *type, IF_PHYSICAL_ADDRE break; } + if (*type == MIB_IF_TYPE_OTHER && !ioctl( fd, SIOCGIFFLAGS, &ifr ) && ifr.ifr_flags & IFF_POINTOPOINT) + *type = MIB_IF_TYPE_PPP; + err: close( fd ); return ret; From f6144d82755de1b255a83e4dc859b9620234b7ae Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 26 May 2023 20:33:41 -0600 Subject: [PATCH 1326/2777] ws2_32: Make wait in accept() alertable. CW-Bug-Id: #22289 --- dlls/ws2_32/socket.c | 2 +- dlls/ws2_32/tests/sock.c | 44 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index e8a04e2e714..64180764f7f 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -765,7 +765,7 @@ SOCKET WINAPI accept( SOCKET s, struct sockaddr *addr, int *len ) NULL, 0, &accept_handle, sizeof(accept_handle) ); if (status == STATUS_PENDING) { - if (WaitForSingleObject( sync_event, INFINITE ) == WAIT_FAILED) + if (wait_event_alertable( sync_event ) == WAIT_FAILED) return SOCKET_ERROR; status = io.u.Status; } diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 289686fff3b..9537e0ee63a 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -4632,10 +4632,37 @@ static SOCKET setup_connector_socket(const struct sockaddr_in *addr, int len, BO return connector; } +struct connect_apc_func_param +{ + HANDLE event; + struct sockaddr_in addr; + SOCKET connector; + unsigned int apc_count; +}; + +static DWORD WINAPI test_accept_connect_thread(void *param) +{ + struct connect_apc_func_param *p = (struct connect_apc_func_param *)param; + + WaitForSingleObject(p->event, INFINITE); + p->connector = setup_connector_socket(&p->addr, sizeof(p->addr), FALSE); + ok(p->connector != INVALID_SOCKET, "failed connecting from APC func.\n"); + return 0; +} + +static void WINAPI connect_apc_func(ULONG_PTR param) +{ + struct connect_apc_func_param *p = (struct connect_apc_func_param *)param; + + ++p->apc_count; + SetEvent(p->event); +} + static void test_accept(void) { int ret; SOCKET server_socket, accepted = INVALID_SOCKET, connector; + struct connect_apc_func_param apc_param; struct sockaddr_in address; SOCKADDR_STORAGE ss, ss_empty; int socklen; @@ -4650,6 +4677,23 @@ static void test_accept(void) socklen = sizeof(address); server_socket = setup_server_socket(&address, &socklen); + memset(&apc_param, 0, sizeof(apc_param)); + apc_param.event = CreateEventW(NULL, FALSE, FALSE, NULL); + apc_param.addr = address; + /* Connecting directly from APC function randomly crashes on Windows for some reason, + * so do it from a thread and only signal it from the APC when we are in accept() call. */ + thread_handle = CreateThread(NULL, 0, test_accept_connect_thread, &apc_param, 0, NULL); + ret = QueueUserAPC(connect_apc_func, GetCurrentThread(), (ULONG_PTR)&apc_param); + ok(ret, "QueueUserAPC returned %d\n", ret); + accepted = accept(server_socket, NULL, NULL); + ok(accepted != INVALID_SOCKET, "Failed to accept connection, %d\n", WSAGetLastError()); + ok(apc_param.apc_count == 1, "APC was called %u times\n", apc_param.apc_count); + closesocket(accepted); + closesocket(apc_param.connector); + WaitForSingleObject(thread_handle, INFINITE); + CloseHandle(thread_handle); + CloseHandle(apc_param.event); + connector = setup_connector_socket(&address, socklen, FALSE); if (connector == INVALID_SOCKET) goto done; From 06a2325d393d65b8cd2a9c19b0e4aef283547586 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 26 May 2023 20:35:57 -0600 Subject: [PATCH 1327/2777] ws2_32: Make wait in connect() alertable. CW-Bug-Id: #22289 --- dlls/ws2_32/socket.c | 2 +- dlls/ws2_32/tests/sock.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 64180764f7f..3ac6ed6da5a 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -1240,7 +1240,7 @@ int WINAPI connect( SOCKET s, const struct sockaddr *addr, int len ) free( params ); if (status == STATUS_PENDING) { - if (WaitForSingleObject( sync_event, INFINITE ) == WAIT_FAILED) return -1; + if (wait_event_alertable( sync_event ) == WAIT_FAILED) return -1; status = io.u.Status; } if (status) diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 9537e0ee63a..47306472b57 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -8432,6 +8432,28 @@ static void test_connect(void) WSACloseEvent(overlapped.hEvent); closesocket(connector); + if (0) + { + /* Wait in connect() is alertable. This may take a very long time before connection fails, + * so disable the test. Testing with localhost is unreliable as that may avoid waiting in + * accept(). */ + connector = socket(AF_INET, SOCK_STREAM, 0); + ok(connector != INVALID_SOCKET, "failed to create socket, error %u\n", WSAGetLastError()); + address.sin_addr.s_addr = inet_addr("8.8.8.8"); + address.sin_port = htons(255); + + apc_count = 0; + SleepEx(0, TRUE); + ok(apc_count == 0, "got apc_count %d.\n", apc_count); + bret = QueueUserAPC(apc_func, GetCurrentThread(), (ULONG_PTR)&apc_count); + ok(bret, "QueueUserAPC returned %d\n", bret); + iret = connect(connector, (struct sockaddr *)&address, sizeof(address)); + ok(apc_count == 1, "got apc_count %d.\n", apc_count); + ok(iret == -1 && (WSAGetLastError() == WSAECONNREFUSED || WSAGetLastError() == WSAETIMEDOUT), + "unexpected iret %d, error %d.\n", iret, WSAGetLastError()); + closesocket(connector); + } + /* Test connect after previous connect attempt failure. */ connector = socket(AF_INET, SOCK_STREAM, 0); ok(connector != INVALID_SOCKET, "failed to create socket, error %u\n", WSAGetLastError()); From 51ec40dfdba54828ea932adc4c9c8a83e5e0f869 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 26 May 2023 20:36:53 -0600 Subject: [PATCH 1328/2777] ws2_32: Make wait in WSAPoll() alertable. CW-Bug-Id: #22289 --- dlls/ws2_32/socket.c | 2 +- dlls/ws2_32/tests/sock.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 3ac6ed6da5a..fdaa03ecfb3 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -2994,7 +2994,7 @@ int WINAPI WSAPoll( WSAPOLLFD *fds, ULONG count, int timeout ) params, params_size, params, params_size ); if (status == STATUS_PENDING) { - if (WaitForSingleObject( sync_event, INFINITE ) == WAIT_FAILED) + if (wait_event_alertable( sync_event ) == WAIT_FAILED) { free( params ); return -1; diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 47306472b57..f0ae9e1af7f 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -8111,7 +8111,11 @@ static void test_WSAPoll(void) fds[0].fd = client; fds[0].events = POLLRDNORM | POLLRDBAND; fds[0].revents = 0xdead; + apc_count = 0; + ret = QueueUserAPC(apc_func, GetCurrentThread(), (ULONG_PTR)&apc_count); + ok(ret, "QueueUserAPC returned %d\n", ret); ret = pWSAPoll(fds, 1, 2000); + ok(apc_count == 1, "APC was called %u times\n", apc_count); ok(ret == 1, "got %d\n", ret); ok(fds[0].revents == POLLNVAL, "got events %#x\n", fds[0].revents); ret = WaitForSingleObject(thread_handle, 1000); From 0a8c83509cff193634614203b51527ec95a2cf33 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 26 May 2023 20:37:56 -0600 Subject: [PATCH 1329/2777] ws2_32: Test wait alertability in WSAGetOverlappedResult(). CW-Bug-Id: #22289 --- dlls/ws2_32/tests/sock.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index f0ae9e1af7f..21c6b81028d 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -12644,6 +12644,19 @@ static void test_WSAGetOverlappedResult(void) } } + overlapped.Internal = STATUS_PENDING; + overlapped.hEvent = CreateEventW(NULL, TRUE, TRUE, NULL); + + apc_count = 0; + ret = QueueUserAPC(apc_func, GetCurrentThread(), (ULONG_PTR)&apc_count); + ok(ret, "QueueUserAPC returned %d\n", ret); + ret = WSAGetOverlappedResult(s, &overlapped, &size, TRUE, &flags); + ok(ret && GetLastError() == ERROR_IO_PENDING, "Got ret %d, err %lu.\n", ret, GetLastError()); + ok(!apc_count, "got apc_count %d.\n", apc_count); + SleepEx(0, TRUE); + ok(apc_count == 1, "got apc_count %d.\n", apc_count); + + CloseHandle(overlapped.hEvent); closesocket(s); } From 43c02bf5330a705a6e0a3f2b6fd059cc4725a72e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 30 May 2023 14:40:53 -0600 Subject: [PATCH 1330/2777] kernelbase: Don't modify non-volatile regs in RaiseException() on x64. CW-Bug-Id: #22304 --- dlls/kernelbase/debug.c | 47 +++++++++++++++++ dlls/ntdll/tests/exception.c | 99 ++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) diff --git a/dlls/kernelbase/debug.c b/dlls/kernelbase/debug.c index 6973a74ad5e..652f1cf8809 100644 --- a/dlls/kernelbase/debug.c +++ b/dlls/kernelbase/debug.c @@ -283,6 +283,52 @@ void WINAPI DECLSPEC_HOTPATCH OutputDebugStringW( LPCWSTR str ) /******************************************************************* * RaiseException (kernelbase.@) */ +#if defined(__x86_64__) +/* Some DRMs depend on RaiseException not altering non-volatile registers. */ +__ASM_GLOBAL_FUNC( RaiseException, + "raise_exception_start:\n\t" + ".byte 0x48,0x8d,0xa4,0x24,0x00,0x00,0x00,0x00\n\t" /* hotpatch prolog */ + "sub $0xc8,%rsp\n\t" + __ASM_SEH(".seh_stackalloc 0xc8\n\t") + __ASM_SEH(".seh_endprologue\n\t") + __ASM_CFI(".cfi_adjust_cfa_offset 0xc8\n\t") + "leaq 0x20(%rsp),%rax\n\t" + "movl %ecx,(%rax)\n\t" /* ExceptionCode */ + "and $1,%edx\n\t" + "movl %edx,4(%rax)\n\t" /* ExceptionFlags */ + "movq $0,8(%rax)\n\t" /* ExceptionRecord */ + "leaq raise_exception_start(%rip),%rcx\n\t" + "movq %rcx,0x10(%rax)\n\t" /* ExceptionAddress */ + "movq %rax,%rcx\n\t" + "movl $0,0x18(%rcx)\n\t" /* NumberParameters */ + "testl %r8d,%r8d\n\t" + "jz 2f\n\t" + "testq %r9,%r9\n\t" + "jz 2f\n\t" + "movl $15,%edx\n\t" + "cmp %edx,%r8d\n\t" + "cmovb %r8d,%edx\n\t" + "movl %edx,0x18(%rcx)\n\t" /* NumberParameters */ + "leaq 0x20(%rcx),%rax\n" /* ExceptionInformation */ + "1:\tmovq (%r9),%r8\n\t" + "movq %r8,(%rax)\n\t" + "decl %edx\n\t" + "jz 2f\n\t" + "addq $8,%rax\n\t" + "addq $8,%r9\n\t" + "jmp 1b\n" + "2:\tcall " __ASM_NAME("RtlRaiseException") "\n\t" + "add $0xc8,%rsp\n\t" + __ASM_CFI(".cfi_adjust_cfa_offset -0xc8\n\t") + "ret" ) + +C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionCode) == 0 ); +C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionFlags) == 4 ); +C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionRecord) == 8 ); +C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionAddress) == 0x10 ); +C_ASSERT( offsetof(EXCEPTION_RECORD, NumberParameters) == 0x18 ); +C_ASSERT( offsetof(EXCEPTION_RECORD, ExceptionInformation) == 0x20 ); +#else void WINAPI DECLSPEC_HOTPATCH RaiseException( DWORD code, DWORD flags, DWORD count, const ULONG_PTR *args ) { EXCEPTION_RECORD record; @@ -301,6 +347,7 @@ void WINAPI DECLSPEC_HOTPATCH RaiseException( DWORD code, DWORD flags, DWORD cou RtlRaiseException( &record ); } +#endif __ASM_STDCALL_IMPORT(RaiseException,16) /******************************************************************* diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index dd5cdcafd64..98624d3b7ac 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -5033,6 +5033,104 @@ static void test_syscall_clobbered_regs(void) ok(regs.r11 == regs.eflags, "Expected r11 (%#I64x) to equal EFLAGS (%#x).\n", regs.r11, regs.eflags); } + +static CONTEXT test_raiseexception_regs_context; +static LONG CALLBACK test_raiseexception_regs_handle(EXCEPTION_POINTERS *exception_info) +{ + EXCEPTION_RECORD *rec = exception_info->ExceptionRecord; + unsigned int i; + + test_raiseexception_regs_context = *exception_info->ContextRecord; + ok(rec->NumberParameters == EXCEPTION_MAXIMUM_PARAMETERS, "got %lu.\n", rec->NumberParameters); + ok(rec->ExceptionCode == 0xdeadbeaf, "got %#lx.\n", rec->ExceptionCode); + ok(!rec->ExceptionRecord, "got %p.\n", rec->ExceptionRecord); + ok(!rec->ExceptionFlags, "got %#lx.\n", rec->ExceptionFlags); + for (i = 0; i < rec->NumberParameters; ++i) + ok(rec->ExceptionInformation[i] == i, "got %Iu, i %u.\n", rec->ExceptionInformation[i], i); + return EXCEPTION_CONTINUE_EXECUTION; +} + +static void test_raiseexception_regs(void) +{ + static const BYTE code[] = + { + 0xb8, 0x00, 0xb0, 0xad, 0xde, /* mov $0xdeadb000,%eax */ + 0x53, /* push %rbx */ + 0x48, 0x89, 0xc3, /* mov %rax,%rbx */ + 0x56, /* push %rsi */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x48, 0x89, 0xc6, /* mov %rax,%rsi */ + 0x57, /* push %rdi */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x48, 0x89, 0xc7, /* mov %rax,%rdi */ + 0x55, /* push %rbp */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x48, 0x89, 0xc5, /* mov %rax,%rbp */ + 0x41, 0x54, /* push %r12 */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x49, 0x89, 0xc4, /* mov %rax,%r12 */ + 0x41, 0x55, /* push %r13 */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x49, 0x89, 0xc5, /* mov %rax,%r13 */ + 0x41, 0x56, /* push %r14 */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x49, 0x89, 0xc6, /* mov %rax,%r14 */ + 0x41, 0x57, /* push %r15 */ + 0x48, 0xff, 0xc0, /* inc %rax */ + 0x49, 0x89, 0xc7, /* mov %rax,%r15 */ + + 0x50, /* push %rax */ /* align stack */ + 0x48, 0x89, 0xc8, /* mov %rcx,%rax */ + 0xb9, 0xaf, 0xbe, 0xad, 0xde, /* mov $0xdeadbeaf,%ecx */ + 0xff, 0xd0, /* call *%rax */ + 0x58, /* pop %rax */ + + 0x41, 0x5f, /* pop %r15 */ + 0x41, 0x5e, /* pop %r14 */ + 0x41, 0x5d, /* pop %r13 */ + 0x41, 0x5c, /* pop %r12 */ + 0x5d, /* pop %rbp */ + 0x5f, /* pop %rdi */ + 0x5e, /* pop %rsi */ + 0x5b, /* pop %rbx */ + 0xc3, /* ret */ + }; + void (WINAPI *pRaiseException)( DWORD code, DWORD flags, DWORD count, const ULONG_PTR *args ) = RaiseException; + void (WINAPI *func)(void *raise_exception, DWORD flags, DWORD count, const ULONG_PTR *args); + void *vectored_handler; + ULONG_PTR args[20]; + ULONG64 expected; + unsigned int i; + + vectored_handler = AddVectoredExceptionHandler(TRUE, test_raiseexception_regs_handle); + ok(!!vectored_handler, "failed.\n"); + + memcpy(code_mem, code, sizeof(code)); + func = code_mem; + + for (i = 0; i < ARRAY_SIZE(args); ++i) + args[i] = i; + + func(pRaiseException, 0, ARRAY_SIZE(args), args); + expected = 0xdeadb000; + ok(test_raiseexception_regs_context.Rbx == expected, "got %#I64x.\n", test_raiseexception_regs_context.Rbx); + ++expected; + ok(test_raiseexception_regs_context.Rsi == expected, "got %#I64x.\n", test_raiseexception_regs_context.Rsi); + ++expected; + ok(test_raiseexception_regs_context.Rdi == expected, "got %#I64x.\n", test_raiseexception_regs_context.Rdi); + ++expected; + ok(test_raiseexception_regs_context.Rbp == expected, "got %#I64x.\n", test_raiseexception_regs_context.Rbp); + ++expected; + ok(test_raiseexception_regs_context.R12 == expected, "got %#I64x.\n", test_raiseexception_regs_context.R12); + ++expected; + ok(test_raiseexception_regs_context.R13 == expected, "got %#I64x.\n", test_raiseexception_regs_context.R13); + ++expected; + ok(test_raiseexception_regs_context.R14 == expected, "got %#I64x.\n", test_raiseexception_regs_context.R14); + ++expected; + ok(test_raiseexception_regs_context.R15 == expected, "got %#I64x.\n", test_raiseexception_regs_context.R15); + + RemoveVectoredExceptionHandler(vectored_handler); +} #elif defined(__arm__) #define UNW_FLAG_NHANDLER 0 @@ -10958,6 +11056,7 @@ START_TEST(exception) test_copy_context(); test_unwind_from_apc(); test_syscall_clobbered_regs(); + test_raiseexception_regs(); #elif defined(__aarch64__) From 40e0c5b7eb8041ef2ed10364d8e3415396f1913b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 31 May 2023 14:47:40 -0600 Subject: [PATCH 1331/2777] kernelbase: HACK: Force Angle Vulkan instead of GL for UplayWebCore. CW-Bug-Id: #22307 --- dlls/kernelbase/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 4e0925c00ee..7e7ea051398 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -582,7 +582,7 @@ static const WCHAR *hack_append_command_line( const WCHAR *cmd ) } options[] = { - {L"UplayWebCore.exe", L" --use-angle=gl"}, + {L"UplayWebCore.exe", L" --use-angle=vulkan"}, {L"Paradox Launcher.exe", L" --use-angle=gl"}, {L"Montaro\\nw.exe", L" --use-gl=swiftshader"}, {L"\\EOSOverlayRenderer-Win64-Shipping.exe", L" --use-gl=swiftshader --in-process-gpu"}, From 6755ffef4cbd25c7bdf649023b773af597ac641f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 16 May 2023 15:58:04 +0200 Subject: [PATCH 1332/2777] fixup! user32: Flush driver display in ReleaseDC() for other process window. --- dlls/win32u/dce.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 77a7a4ce835..773d6e0b059 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -1021,7 +1021,7 @@ HDC WINAPI NtUserGetDCEx( HWND hwnd, HRGN clip_rgn, DWORD flags ) INT WINAPI NtUserReleaseDC( HWND hwnd, HDC hdc ) { if (hwnd && !is_current_process_window( hwnd )) - user_driver->pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 ); + user_driver->pProcessEvents( 0 ); return release_dc( hwnd, hdc, FALSE ); } From 45e4f2538f3b3aca278804d2458cf32bd08cf99b Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Fri, 24 Feb 2023 09:30:28 +0000 Subject: [PATCH 1333/2777] winemac: Fix return type of ProcessEvents(). Introduced by commit a97fd9f29e7dbeee2dc06415a34a9f7669ea2e0d (cherry picked from commit 9260e6333b5171959f96564f56642b8a2351dacf) --- dlls/winemac.drv/event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c index 5b717b4b730..5953dc0e0d8 100644 --- a/dlls/winemac.drv/event.c +++ b/dlls/winemac.drv/event.c @@ -512,7 +512,7 @@ static int process_events(macdrv_event_queue queue, macdrv_event_mask mask) /*********************************************************************** * ProcessEvents (MACDRV.@) */ -NTSTATUS macdrv_ProcessEvents(DWORD mask) +BOOL macdrv_ProcessEvents(DWORD mask) { struct macdrv_thread_data *data = macdrv_thread_data(); macdrv_event_mask event_mask = get_event_mask(mask); From ae06cd6f21ee8b65ab867facd3ed21b44853d4a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 16 Mar 2023 16:22:29 +0100 Subject: [PATCH 1334/2777] include: Add some dinput.h action semantics definitions. (cherry picked from commit cefe42dfeb2f1d0aedbfa5e0efef75b5d0661b24) --- include/dinput.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/dinput.h b/include/dinput.h index 71cc55aece5..2ebe1b1e83e 100644 --- a/include/dinput.h +++ b/include/dinput.h @@ -2172,6 +2172,12 @@ extern const DIDATAFORMAT c_dfDIJoystick2; }; #endif +#define DIVIRTUAL_DRIVING_RACE 0x01000000 +#define DIAXIS_DRIVINGR_STEER 0x01008a01 +#define DIAXIS_DRIVINGR_ACCELERATE 0x01039202 + +#define DIVOICE_CHANNEL1 0x83000401 + #define DIAXIS_ANY_X_1 0xFF00C201 #define DIAXIS_ANY_X_2 0xFF00C202 #define DIAXIS_ANY_Y_1 0xFF014201 From c2269247fbd6ff6b2e5e71c8744147e1cbf41f4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 15 Mar 2023 21:04:01 +0100 Subject: [PATCH 1335/2777] dinput/tests: Test BuildActionMap / SaveActionMap with the HID joystick. (cherry picked from commit 88e2b447a228eeef40b9e0bd1fcf2498c60d0194) --- dlls/dinput/tests/joystick8.c | 541 ++++++++++++++++++++++++++++++++++ 1 file changed, 541 insertions(+) diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 0496185b006..112058ffd3d 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -47,6 +47,11 @@ #include "windows.gaming.input.h" #undef Size +#include "initguid.h" + +DEFINE_GUID(GUID_action_mapping_1,0x00000001,0x0002,0x0003,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b); +DEFINE_GUID(GUID_action_mapping_2,0x00010001,0x0002,0x0003,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b); + static HRESULT (WINAPI *pRoGetActivationFactory)( HSTRING, REFIID, void** ); static HRESULT (WINAPI *pRoInitialize)( RO_INIT_TYPE ); static HRESULT (WINAPI *pWindowsCreateString)( const WCHAR*, UINT32, HSTRING* ); @@ -203,6 +208,62 @@ static BOOL CALLBACK check_no_created_effect_objects( IDirectInputEffect *effect return DIENUM_CONTINUE; } +struct diaction_todo +{ + BOOL instance; + BOOL objid; + BOOL how; +}; + +#define check_diactionw( a, b ) check_diactionw_( __LINE__, a, b, NULL ) +static void check_diactionw_( int line, const DIACTIONW *actual, const DIACTIONW *expected, + const struct diaction_todo *todos ) +{ + check_member_( __FILE__, line, *actual, *expected, "%#Ix", uAppData ); + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwSemantic ); + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwFlags ); + if (actual->lptszActionName && expected->lptszActionName) + check_member_wstr_( __FILE__, line, *actual, *expected, lptszActionName ); + else + check_member_( __FILE__, line, *actual, *expected, "%p", lptszActionName ); + todo_wine_if( todos->instance ) + check_member_guid_( __FILE__, line, *actual, *expected, guidInstance ); + todo_wine_if( todos->objid ) + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwObjID ); + todo_wine_if( todos->how ) + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwHow ); +} + +#define check_diactionformatw( a, b ) check_diactionformatw_( __LINE__, a, b, NULL ) +static void check_diactionformatw_( int line, const DIACTIONFORMATW *actual, const DIACTIONFORMATW *expected, + const struct diaction_todo *todos ) +{ + DWORD i; + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwSize ); + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwActionSize ); + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwDataSize ); + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwNumActions ); + for (i = 0; i < min( actual->dwNumActions, expected->dwNumActions ); ++i) + { + winetest_push_context( "action[%lu]", i ); + check_diactionw_( line, actual->rgoAction + i, expected->rgoAction + i, todos ? todos + i : NULL ); + winetest_pop_context(); + if (expected->dwActionSize != sizeof(DIACTIONW)) break; + if (actual->dwActionSize != sizeof(DIACTIONW)) break; + } + check_member_guid_( __FILE__, line, *actual, *expected, guidActionMap ); + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwGenre ); + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwBufferSize ); + check_member_( __FILE__, line, *actual, *expected, "%+ld", lAxisMin ); + check_member_( __FILE__, line, *actual, *expected, "%+ld", lAxisMax ); + check_member_( __FILE__, line, *actual, *expected, "%p", hInstString ); + check_member_( __FILE__, line, *actual, *expected, "%ld", ftTimeStamp.dwLowDateTime ); + check_member_( __FILE__, line, *actual, *expected, "%ld", ftTimeStamp.dwHighDateTime ); + todo_wine + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwCRC ); + check_member_wstr_( __FILE__, line, *actual, *expected, tszActionMap ); +} + static BOOL CALLBACK enum_device_count( const DIDEVICEINSTANCEW *devinst, void *context ) { DWORD *count = context; @@ -356,6 +417,482 @@ static void check_dinput_devices( DWORD version, DIDEVICEINSTANCEW *devinst ) } } +static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE event ) +{ + const DIACTIONW expect_actions[] = + { + { + .dwSemantic = DIBUTTON_ANY( 1 ), + .guidInstance = expect_guid_product, + .dwHow = DIAH_DEFAULT, + .dwObjID = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ), + }, + { + .dwSemantic = DIBUTTON_ANY( 2 ), + .guidInstance = expect_guid_product, + .dwHow = DIAH_DEFAULT, + .dwObjID = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 1 ), + }, + { + .dwSemantic = DIAXIS_ANY_X_1, + }, + { + .dwSemantic = DIPOV_ANY_1, + .guidInstance = expect_guid_product, + .dwHow = DIAH_DEFAULT, + .dwObjID = DIDFT_POV | DIDFT_MAKEINSTANCE( 0 ), + }, + { + .dwSemantic = DIAXIS_DRIVINGR_ACCELERATE, + }, + { + .dwSemantic = DIAXIS_ANY_Z_2, + .guidInstance = expect_guid_product, + .dwHow = DIAH_DEFAULT, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ), + }, + { + .dwSemantic = DIAXIS_ANY_4, + .guidInstance = expect_guid_product, + .dwHow = DIAH_DEFAULT, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 6 ), + }, + { + .dwSemantic = DIAXIS_DRIVINGR_STEER, + .guidInstance = expect_guid_product, + .dwHow = DIAH_DEFAULT, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ), + }, + }; + const DIACTIONW expect_filled_actions[ARRAY_SIZE(expect_actions)] = + { + { + .dwSemantic = DIBUTTON_ANY( 1 ), + .guidInstance = expect_guid_product, + .dwHow = DIAH_APPREQUESTED, + .dwObjID = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 1 ), + .dwFlags = DIA_APPMAPPED, + .lptszActionName = L"Button 1", + .uAppData = 1, + }, + { + .dwSemantic = DIBUTTON_ANY( 2 ), + .guidInstance = expect_guid_product, + .dwObjID = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ), + .dwFlags = DIA_APPNOMAP, + .lptszActionName = L"Button 2", + .uAppData = 2, + }, + { + .dwSemantic = DIAXIS_ANY_X_1, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ), + .dwFlags = DIA_FORCEFEEDBACK, + .lptszActionName = L"Wheel", + .uAppData = 3, + }, + { + .dwSemantic = DIPOV_ANY_1, + .guidInstance = expect_guid_product, + .dwHow = DIAH_APPREQUESTED, + .dwObjID = DIDFT_POV | DIDFT_MAKEINSTANCE( 0 ), + .dwFlags = DIA_APPMAPPED | DIA_APPFIXED, + .lptszActionName = L"POV", + .uAppData = 4, + }, + { + .dwSemantic = DIAXIS_DRIVINGR_ACCELERATE, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ), + .dwFlags = DIA_NORANGE, + .lptszActionName = L"Accelerate", + .uAppData = 5, + }, + { + .dwSemantic = DIAXIS_ANY_Z_2, + .guidInstance = expect_guid_product, + .dwHow = DIAH_DEFAULT, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ), + .dwFlags = DIA_APPFIXED, + .lptszActionName = L"Z", + .uAppData = 6, + }, + { + .dwSemantic = DIAXIS_ANY_4, + .guidInstance = expect_guid_product, + .dwHow = DIAH_DEFAULT, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 6 ), + .dwFlags = DIA_APPFIXED, + .lptszActionName = L"Axis 4", + .uAppData = 7, + }, + { + .dwSemantic = DIAXIS_DRIVINGR_STEER, + .guidInstance = expect_guid_product, + .dwHow = DIAH_DEFAULT, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ), + .lptszActionName = L"Steer", + .uAppData = 8, + }, + }; + const DIACTIONFORMATW expect_action_format_1 = + { + .dwSize = sizeof(DIACTIONFORMATW), + .dwActionSize = sizeof(DIACTIONW), + .dwNumActions = 1, + .dwDataSize = 4, + .rgoAction = (DIACTIONW *)expect_actions, + .dwGenre = DIVIRTUAL_DRIVING_RACE, + .guidActionMap = GUID_action_mapping_1, + .dwCRC = 0x6cd1f698, + }; + const DIACTIONFORMATW expect_action_format_2 = + { + .dwSize = sizeof(DIACTIONFORMATW), + .dwActionSize = sizeof(DIACTIONW), + .dwNumActions = ARRAY_SIZE(expect_actions), + .dwDataSize = 4 * ARRAY_SIZE(expect_actions), + .rgoAction = (DIACTIONW *)expect_actions, + .dwGenre = DIVIRTUAL_DRIVING_RACE, + .guidActionMap = GUID_action_mapping_2, + .dwCRC = 0x9a7bb5e6, + }; + const DIACTIONFORMATW expect_action_format_2_filled = + { + .dwSize = sizeof(DIACTIONFORMATW), + .dwActionSize = sizeof(DIACTIONW), + .dwNumActions = ARRAY_SIZE(expect_actions), + .dwDataSize = 4 * ARRAY_SIZE(expect_actions), + .rgoAction = (DIACTIONW *)expect_filled_actions, + .dwGenre = DIVIRTUAL_DRIVING_RACE, + .guidActionMap = GUID_action_mapping_2, + .dwBufferSize = 32, + .lAxisMin = -128, + .lAxisMax = +128, + .tszActionMap = L"Action Map Filled", + .dwCRC = 0x3d98f717, + }; + DIACTIONW voice_actions[] = + { + {.dwSemantic = DIVOICE_CHANNEL1}, + }; + DIACTIONFORMATW voice_action_format = + { + .dwSize = sizeof(DIACTIONFORMATW), + .dwActionSize = sizeof(*voice_actions), + .dwNumActions = 1, + .dwDataSize = 4, + .rgoAction = voice_actions, + .dwGenre = DIVIRTUAL_DRIVING_RACE, + .guidActionMap = GUID_action_mapping_1, + }; + DIACTIONW default_actions[ARRAY_SIZE(expect_actions)] = + { + {.dwSemantic = DIBUTTON_ANY( 1 )}, + {.dwSemantic = DIBUTTON_ANY( 2 )}, + {.dwSemantic = DIAXIS_ANY_X_1}, + {.dwSemantic = DIPOV_ANY_1}, + {.dwSemantic = DIAXIS_DRIVINGR_ACCELERATE}, + {.dwSemantic = DIAXIS_ANY_Z_2}, + {.dwSemantic = DIAXIS_ANY_4}, + {.dwSemantic = DIAXIS_DRIVINGR_STEER}, + }; + DIACTIONFORMATW action_format_1 = + { + .dwSize = sizeof(DIACTIONFORMATW), + .dwActionSize = sizeof(*default_actions), + .dwNumActions = 1, + .dwDataSize = 4, + .rgoAction = default_actions, + .dwGenre = DIVIRTUAL_DRIVING_RACE, + .guidActionMap = GUID_action_mapping_1, + }; + DIACTIONFORMATW action_format_2 = + { + .dwSize = sizeof(DIACTIONFORMATW), + .dwActionSize = sizeof(*default_actions), + .dwNumActions = ARRAY_SIZE(expect_actions), + .dwDataSize = 4 * ARRAY_SIZE(expect_actions), + .rgoAction = default_actions, + .dwGenre = DIVIRTUAL_DRIVING_RACE, + .guidActionMap = GUID_action_mapping_2, + }; + DIACTIONW filled_actions[ARRAY_SIZE(expect_actions)] = + { + { + .dwSemantic = DIBUTTON_ANY( 1 ), + .guidInstance = expect_guid_product, + .dwHow = DIAH_USERCONFIG, + .dwObjID = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 1 ), + .dwFlags = DIA_APPMAPPED, + .lptszActionName = L"Button 1", + .uAppData = 1, + }, + { + .dwSemantic = DIBUTTON_ANY( 2 ), + .guidInstance = expect_guid_product, + .dwObjID = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ), + .dwFlags = DIA_APPNOMAP, + .lptszActionName = L"Button 2", + .uAppData = 2, + }, + { + .dwSemantic = DIAXIS_ANY_X_1, + .guidInstance = expect_guid_product, + .dwHow = DIAH_HWDEFAULT, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ), + .dwFlags = DIA_FORCEFEEDBACK, + .lptszActionName = L"Wheel", + .uAppData = 3, + }, + { + .dwSemantic = DIPOV_ANY_1, + .guidInstance = expect_guid_product, + .dwHow = DIAH_HWAPP, + .dwObjID = DIDFT_POV | DIDFT_MAKEINSTANCE( 0 ), + .dwFlags = DIA_APPMAPPED | DIA_APPFIXED, + .lptszActionName = L"POV", + .uAppData = 4, + }, + { + .dwSemantic = DIAXIS_DRIVINGR_ACCELERATE, + .guidInstance = expect_guid_product, + .dwHow = DIAH_USERCONFIG, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ), + .dwFlags = DIA_NORANGE, + .lptszActionName = L"Accelerate", + .uAppData = 5, + }, + { + .dwSemantic = DIAXIS_ANY_Z_2, + .guidInstance = expect_guid_product, + .dwHow = DIAH_UNMAPPED, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 3 ), + .dwFlags = DIA_APPFIXED, + .lptszActionName = L"Z", + .uAppData = 6, + }, + { + .dwSemantic = DIAXIS_ANY_4, + .guidInstance = expect_guid_product, + .dwHow = DIAH_DEFAULT, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 5 ), + .dwFlags = DIA_APPFIXED, + .lptszActionName = L"Axis 4", + .uAppData = 7, + }, + { + .dwSemantic = DIAXIS_DRIVINGR_STEER, + .guidInstance = expect_guid_product, + .dwHow = DIAH_USERCONFIG, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 4 ), + .lptszActionName = L"Steer", + .uAppData = 8, + }, + }; + DIACTIONFORMATW action_format_2_filled = + { + .dwSize = sizeof(DIACTIONFORMATW), + .dwActionSize = sizeof(*default_actions), + .dwNumActions = ARRAY_SIZE(expect_actions), + .dwDataSize = 4 * ARRAY_SIZE(expect_actions), + .rgoAction = filled_actions, + .dwGenre = DIVIRTUAL_DRIVING_RACE, + .guidActionMap = GUID_action_mapping_2, + .dwBufferSize = 32, + .lAxisMin = -128, + .lAxisMax = +128, + .tszActionMap = L"Action Map Filled", + }; + struct diaction_todo actions_todos_1 = {.instance = TRUE, .objid = TRUE, .how = TRUE}; + struct diaction_todo actions_todos_2[ARRAY_SIZE(expect_actions)] = + { + {.instance = TRUE, .objid = TRUE, .how = TRUE}, + {.instance = TRUE, .objid = TRUE, .how = TRUE}, + {0}, + {.instance = TRUE, .objid = TRUE, .how = TRUE}, + {.instance = TRUE, .objid = TRUE, .how = TRUE}, + {.instance = TRUE, .objid = TRUE, .how = TRUE}, + {.instance = TRUE, .objid = TRUE, .how = TRUE}, + {.objid = TRUE}, + }; + struct diaction_todo actions_todos_2_filled[ARRAY_SIZE(expect_actions)] = + { + {.how = TRUE}, + {0}, + {.instance = TRUE, .how = TRUE}, + {.how = TRUE}, + {.instance = TRUE, .how = TRUE}, + {.objid = TRUE, .how = TRUE}, + {.objid = TRUE}, + {.objid = TRUE, .how = TRUE}, + }; + DIACTIONW actions[ARRAY_SIZE(expect_actions)]; + DIACTIONFORMATW action_format; + DWORD flags; + HRESULT hr; + + + hr = IDirectInputDevice8_BuildActionMap( device, NULL, L"username", DIDBAM_DEFAULT ); + ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); + hr = IDirectInputDevice8_BuildActionMap( device, &action_format_1, L"username", 0xdeadbeef ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); + flags = DIDBAM_HWDEFAULTS | DIDBAM_INITIALIZE; + hr = IDirectInputDevice8_BuildActionMap( device, &action_format_1, L"username", flags ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); + flags = DIDBAM_HWDEFAULTS | DIDBAM_PRESERVE; + hr = IDirectInputDevice8_BuildActionMap( device, &action_format_1, L"username", flags ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); + flags = DIDBAM_INITIALIZE | DIDBAM_PRESERVE; + hr = IDirectInputDevice8_BuildActionMap( device, &action_format_1, L"username", flags ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); + + hr = IDirectInputDevice8_SetActionMap( device, NULL, NULL, DIDSAM_DEFAULT ); + ok( hr == DIERR_INVALIDPARAM, "SetActionMap returned %#lx\n", hr ); + flags = DIDSAM_FORCESAVE | DIDSAM_NOUSER; + hr = IDirectInputDevice8_SetActionMap( device, &action_format_1, NULL, flags ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "SetActionMap returned %#lx\n", hr ); + + + /* action format with no suitable actions */ + + hr = IDirectInputDevice8_BuildActionMap( device, &voice_action_format, NULL, DIDBAM_DEFAULT ); + ok( hr == DI_NOEFFECT, "BuildActionMap returned %#lx\n", hr ); + + /* first SetActionMap call for a user always return DI_SETTINGSNOTSAVED */ + + hr = IDirectInputDevice8_SetActionMap( device, &voice_action_format, NULL, DIDSAM_FORCESAVE ); + todo_wine + ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); + + hr = IDirectInputDevice8_SetActionMap( device, &voice_action_format, NULL, DIDSAM_DEFAULT ); + ok( hr == DI_NOEFFECT, "SetActionMap returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetActionMap( device, &voice_action_format, NULL, DIDSAM_FORCESAVE ); + todo_wine + ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); + + + action_format = action_format_1; + action_format.rgoAction = actions; + memset( actions, 0, sizeof(actions) ); + actions[0] = default_actions[0]; + hr = IDirectInputDevice8_BuildActionMap( device, &action_format, NULL, DIDBAM_DEFAULT ); + todo_wine + ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); + check_diactionformatw_( __LINE__, &action_format, &expect_action_format_1, &actions_todos_1 ); + hr = IDirectInputDevice8_SetActionMap( device, &action_format, NULL, DIDSAM_DEFAULT ); + todo_wine + ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); + check_diactionformatw_( __LINE__, &action_format, &expect_action_format_1, &actions_todos_1 ); + + + action_format = action_format_1; + action_format.rgoAction = actions; + memset( actions, 0, sizeof(actions) ); + actions[0] = default_actions[0]; + hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); + todo_wine + ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); + check_diactionformatw_( __LINE__, &action_format, &expect_action_format_1, &actions_todos_1 ); + + /* first SetActionMap call for a user always return DI_SETTINGSNOTSAVED */ + + hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_DEFAULT ); + todo_wine + ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_DEFAULT ); + todo_wine + ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); + + /* same SetActionMap call returns DI_OK */ + + hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_DEFAULT ); + todo_wine + ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); + + /* DIDSAM_FORCESAVE always returns DI_SETTINGSNOTSAVED */ + + hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_FORCESAVE ); + todo_wine + ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_FORCESAVE ); + todo_wine + ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); + check_diactionformatw_( __LINE__, &action_format, &expect_action_format_1, &actions_todos_1 ); + + + /* action format dwDataSize and dwNumActions have to match, actions require a dwSemantic */ + + action_format = action_format_2; + action_format.rgoAction = actions; + memset( actions, 0, sizeof(actions) ); + actions[0] = default_actions[0]; + action_format.dwDataSize = 8; + hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); + action_format.dwNumActions = 2; + hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); + todo_wine + ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); + action_format.dwNumActions = 1; + action_format.dwDataSize = 4; + + + action_format = action_format_2; + action_format.rgoAction = actions; + memcpy( actions, default_actions, sizeof(default_actions) ); + hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); + ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); + check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2, actions_todos_2 ); + + hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_DEFAULT ); + ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); + + + /* saving action map actually does nothing */ + + action_format = action_format_2_filled; + action_format.rgoAction = actions; + memcpy( actions, filled_actions, sizeof(filled_actions) ); + hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); + todo_wine + ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); + check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2_filled, actions_todos_2_filled ); + hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_DEFAULT ); + ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); + check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2_filled, actions_todos_2_filled ); + hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_FORCESAVE ); + todo_wine + ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); + check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2_filled, actions_todos_2_filled ); + + + action_format = action_format_2; + action_format.rgoAction = actions; + memcpy( actions, default_actions, sizeof(default_actions) ); + hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_HWDEFAULTS ); + ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); + check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2, actions_todos_2 ); + + action_format = action_format_2; + action_format.rgoAction = actions; + memcpy( actions, default_actions, sizeof(default_actions) ); + hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_INITIALIZE ); + ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); + check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2, actions_todos_2 ); + + action_format = action_format_2; + action_format.rgoAction = actions; + memcpy( actions, default_actions, sizeof(default_actions) ); + hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_PRESERVE ); + ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); + check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2, actions_todos_2 ); +} + static void test_simple_joystick( DWORD version ) { #include "psh_hid_macros.h" @@ -2070,6 +2607,8 @@ static void test_simple_joystick( DWORD version ) todo_wine ok( hr == DIERR_UNSUPPORTED, "Escape returned: %#lx\n", hr ); + if (version == 0x800) test_action_map( device, file, event ); + ref = IDirectInputDevice8_Release( device ); ok( ref == 0, "Release returned %ld\n", ref ); @@ -4422,6 +4961,8 @@ START_TEST( joystick8 ) dinput_test_init(); if (!bus_device_start()) goto done; + winetest_mute_threshold = 3; + if (test_device_types( 0x800 )) { /* This needs to be done before doing anything involving dinput.dll From 01fea2a862956a9cb72db29a43778deb2a3b1c45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 16 Mar 2023 13:27:37 +0100 Subject: [PATCH 1336/2777] dinput/tests: Test SaveActionMap effect on DIPROP_USERNAME property. (cherry picked from commit 2656e418e2de27491f92eae0569b4f4e02c28128) --- dlls/dinput/tests/joystick8.c | 50 ++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 112058ffd3d..6f966e95f7c 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -725,11 +725,29 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e {.objid = TRUE}, {.objid = TRUE, .how = TRUE}, }; + DIPROPSTRING prop_username = + { + .diph = + { + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwSize = sizeof(DIPROPSTRING), + .dwHow = DIPH_DEVICE, + } + }; DIACTIONW actions[ARRAY_SIZE(expect_actions)]; DIACTIONFORMATW action_format; - DWORD flags; + WCHAR username[256]; + DWORD res, flags; HRESULT hr; + res = ARRAY_SIZE(username); + GetUserNameW( username, &res ); + + memset( prop_username.wsz, 0, sizeof(prop_username.wsz) ); + hr = IDirectInputDevice_GetProperty( device, DIPROP_USERNAME, &prop_username.diph ); + ok( hr == DI_NOEFFECT, "GetProperty returned %#lx\n", hr ); + ok( !wcscmp( prop_username.wsz, L"" ), "got username %s\n", debugstr_w(prop_username.wsz) ); + hr = IDirectInputDevice8_BuildActionMap( device, NULL, L"username", DIDBAM_DEFAULT ); ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); @@ -768,12 +786,26 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e todo_wine ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); + memset( prop_username.wsz, 0, sizeof(prop_username.wsz) ); + hr = IDirectInputDevice_GetProperty( device, DIPROP_USERNAME, &prop_username.diph ); + todo_wine + ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); + todo_wine + ok( !wcscmp( prop_username.wsz, username ), "got username %s\n", debugstr_w(prop_username.wsz) ); + hr = IDirectInputDevice8_SetActionMap( device, &voice_action_format, NULL, DIDSAM_DEFAULT ); ok( hr == DI_NOEFFECT, "SetActionMap returned %#lx\n", hr ); hr = IDirectInputDevice8_SetActionMap( device, &voice_action_format, NULL, DIDSAM_FORCESAVE ); todo_wine ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); + memset( prop_username.wsz, 0, sizeof(prop_username.wsz) ); + hr = IDirectInputDevice_GetProperty( device, DIPROP_USERNAME, &prop_username.diph ); + todo_wine + ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); + todo_wine + ok( !wcscmp( prop_username.wsz, username ), "got username %s\n", debugstr_w(prop_username.wsz) ); + action_format = action_format_1; action_format.rgoAction = actions; @@ -891,6 +923,22 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_PRESERVE ); ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2, actions_todos_2 ); + + + /* DIDSAM_NOUSER flag clears the device user property */ + + memset( prop_username.wsz, 0, sizeof(prop_username.wsz) ); + hr = IDirectInputDevice_GetProperty( device, DIPROP_USERNAME, &prop_username.diph ); + ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); + ok( !wcscmp( prop_username.wsz, L"username" ), "got username %s\n", debugstr_w(prop_username.wsz) ); + + hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_NOUSER ); + ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); + + memset( prop_username.wsz, 0, sizeof(prop_username.wsz) ); + hr = IDirectInputDevice_GetProperty( device, DIPROP_USERNAME, &prop_username.diph ); + ok( hr == DI_NOEFFECT, "GetProperty returned %#lx\n", hr ); + ok( !wcscmp( prop_username.wsz, L"" ), "got username %s\n", debugstr_w(prop_username.wsz) ); } static void test_simple_joystick( DWORD version ) From 3768f52c80d7f8f869eb85211b5e965d9aca9881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 16 Mar 2023 13:26:06 +0100 Subject: [PATCH 1337/2777] dinput/tests: Test SaveActionMap effect on DIPROP_APPDATA property. (cherry picked from commit 2750d924db6db1523d9dd5ac2322bf09fa84e9df) --- dlls/dinput/tests/joystick8.c | 66 +++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 6f966e95f7c..425f3af9d75 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -734,6 +734,14 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e .dwHow = DIPH_DEVICE, } }; + DIPROPPOINTER prop_pointer = + { + .diph = + { + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwSize = sizeof(DIPROPPOINTER), + } + }; DIACTIONW actions[ARRAY_SIZE(expect_actions)]; DIACTIONFORMATW action_format; WCHAR username[256]; @@ -885,6 +893,14 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); + prop_pointer.diph.dwHow = DIPH_BYUSAGE; + prop_pointer.diph.dwObj = MAKELONG(HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); + todo_wine + ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); + ok( prop_pointer.uData == 0, "got uData %#Ix\n", prop_pointer.uData ); + + /* saving action map actually does nothing */ action_format = action_format_2_filled; @@ -903,6 +919,34 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2_filled, actions_todos_2_filled ); + prop_pointer.diph.dwHow = DIPH_DEVICE; + prop_pointer.diph.dwObj = 0; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); + ok( hr == DIERR_UNSUPPORTED, "GetProperty returned %#lx\n", hr ); + + prop_pointer.diph.dwHow = DIPH_BYID; + prop_pointer.diph.dwObj = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 3 ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); + todo_wine + ok( hr == DIERR_NOTFOUND, "GetProperty returned %#lx\n", hr ); + + prop_pointer.diph.dwHow = DIPH_BYID; + prop_pointer.diph.dwObj = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); + todo_wine + ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); + todo_wine + ok( prop_pointer.uData == 6, "got uData %#Ix\n", prop_pointer.uData ); + + prop_pointer.diph.dwHow = DIPH_BYUSAGE; + prop_pointer.diph.dwObj = MAKELONG(HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); + todo_wine + ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); + todo_wine + ok( prop_pointer.uData == 8, "got uData %#Ix\n", prop_pointer.uData ); + + action_format = action_format_2; action_format.rgoAction = actions; memcpy( actions, default_actions, sizeof(default_actions) ); @@ -925,6 +969,28 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2, actions_todos_2 ); + /* setting the data format resets action map */ + + prop_pointer.diph.dwHow = DIPH_BYUSAGE; + prop_pointer.diph.dwObj = MAKELONG(HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); + todo_wine + ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); + todo_wine + ok( prop_pointer.uData == 8, "got uData %#Ix\n", prop_pointer.uData ); + + hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); + ok( hr == DI_OK, "SetDataFormat returned %#lx\n", hr ); + + prop_pointer.diph.dwHow = DIPH_BYUSAGE; + prop_pointer.diph.dwObj = MAKELONG(HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); + todo_wine + ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); + todo_wine + ok( prop_pointer.uData == -1, "got uData %#Ix\n", prop_pointer.uData ); + + /* DIDSAM_NOUSER flag clears the device user property */ memset( prop_username.wsz, 0, sizeof(prop_username.wsz) ); From 549aeecabda38e186af34f6494b9cb81762c4975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 16 Mar 2023 14:04:50 +0100 Subject: [PATCH 1338/2777] dinput/tests: Test SaveActionMap effect on DIPROP_BUFFERSIZE property. (cherry picked from commit 4edea8a93ae14820c85f2201907b25ff74d5b936) --- dlls/dinput/tests/joystick8.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 425f3af9d75..17f938c4153 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -725,6 +725,15 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e {.objid = TRUE}, {.objid = TRUE, .how = TRUE}, }; + DIPROPDWORD prop_dword = + { + .diph = + { + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwSize = sizeof(DIPROPDWORD), + .dwHow = DIPH_DEVICE, + } + }; DIPROPSTRING prop_username = { .diph = @@ -900,6 +909,11 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); ok( prop_pointer.uData == 0, "got uData %#Ix\n", prop_pointer.uData ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); + ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); + todo_wine + ok( prop_dword.dwData == 0, "got dwData %#lx\n", prop_dword.dwData ); + /* saving action map actually does nothing */ @@ -946,6 +960,10 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e todo_wine ok( prop_pointer.uData == 8, "got uData %#Ix\n", prop_pointer.uData ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); + ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); + ok( prop_dword.dwData == 32, "got dwData %#lx\n", prop_dword.dwData ); + action_format = action_format_2; action_format.rgoAction = actions; @@ -990,6 +1008,10 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e todo_wine ok( prop_pointer.uData == -1, "got uData %#Ix\n", prop_pointer.uData ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); + ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); + ok( prop_dword.dwData == 32, "got dwData %#lx\n", prop_dword.dwData ); + /* DIDSAM_NOUSER flag clears the device user property */ From de465f4a251cd7c951faa07f17632c20d187c0e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 16 Mar 2023 14:06:52 +0100 Subject: [PATCH 1339/2777] dinput/tests: Test SaveActionMap effect on DIPROP_RANGE property. (cherry picked from commit e7b3e3514c6a12388d7772479777d16a3309575b) --- dlls/dinput/tests/joystick8.c | 55 +++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 17f938c4153..6cea23f9128 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -725,6 +725,15 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e {.objid = TRUE}, {.objid = TRUE, .how = TRUE}, }; + DIPROPRANGE prop_range = + { + .diph = + { + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwSize = sizeof(DIPROPRANGE), + .dwHow = DIPH_DEVICE, + } + }; DIPROPDWORD prop_dword = { .diph = @@ -909,6 +918,24 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); ok( prop_pointer.uData == 0, "got uData %#Ix\n", prop_pointer.uData ); + prop_range.diph.dwHow = DIPH_BYID; + prop_range.diph.dwObj = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); + ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); + todo_wine + ok( prop_range.lMin == +1000, "got lMin %+ld\n", prop_range.lMin ); + todo_wine + ok( prop_range.lMax == +51000, "got lMax %+ld\n", prop_range.lMax ); + + prop_range.diph.dwHow = DIPH_BYUSAGE; + prop_range.diph.dwObj = MAKELONG(HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); + ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); + todo_wine + ok( prop_range.lMin == -14000, "got lMin %+ld\n", prop_range.lMin ); + todo_wine + ok( prop_range.lMax == -4000, "got lMax %+ld\n", prop_range.lMax ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); todo_wine @@ -960,6 +987,20 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e todo_wine ok( prop_pointer.uData == 8, "got uData %#Ix\n", prop_pointer.uData ); + prop_range.diph.dwHow = DIPH_BYID; + prop_range.diph.dwObj = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); + ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); + ok( prop_range.lMin == -128, "got lMin %+ld\n", prop_range.lMin ); + ok( prop_range.lMax == +128, "got lMax %+ld\n", prop_range.lMax ); + + prop_range.diph.dwHow = DIPH_BYUSAGE; + prop_range.diph.dwObj = MAKELONG(HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); + ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); + ok( prop_range.lMin == -128, "got lMin %+ld\n", prop_range.lMin ); + ok( prop_range.lMax == +128, "got lMax %+ld\n", prop_range.lMax ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); ok( prop_dword.dwData == 32, "got dwData %#lx\n", prop_dword.dwData ); @@ -1008,6 +1049,20 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e todo_wine ok( prop_pointer.uData == -1, "got uData %#Ix\n", prop_pointer.uData ); + prop_range.diph.dwHow = DIPH_BYID; + prop_range.diph.dwObj = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); + ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); + ok( prop_range.lMin == -128, "got lMin %+ld\n", prop_range.lMin ); + ok( prop_range.lMax == +128, "got lMax %+ld\n", prop_range.lMax ); + + prop_range.diph.dwHow = DIPH_BYUSAGE; + prop_range.diph.dwObj = MAKELONG(HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); + ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); + ok( prop_range.lMin == -128, "got lMin %+ld\n", prop_range.lMin ); + ok( prop_range.lMax == +128, "got lMax %+ld\n", prop_range.lMax ); + hr = IDirectInputDevice8_GetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); ok( prop_dword.dwData == 32, "got dwData %#lx\n", prop_dword.dwData ); From 263ab4424bda3450b980488d0894fa5eb71d5331 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 16 Mar 2023 16:36:38 +0100 Subject: [PATCH 1340/2777] dinput/tests: Test SaveActionMap effect on HID joystick input. (cherry picked from commit ed3f06b11afada68e0d389e866d45cbd3b708c40) --- dlls/dinput/tests/joystick8.c | 132 +++++++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 1 deletion(-) diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 6cea23f9128..414a586b2ba 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -570,6 +570,53 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e .tszActionMap = L"Action Map Filled", .dwCRC = 0x3d98f717, }; + struct hid_expect injected_input[] = + { + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0}, + }, + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x38,0x38,0x10,0x10,0x10,0xf8}, + }, + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x01,0x01,0x10,0x10,0x10,0x00}, + }, + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x01,0x01,0x10,0x10,0x10,0x00}, + }, + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x80,0x80,0x10,0x10,0x10,0xff}, + }, + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x10,0xee,0x10,0x10,0x10,0x54}, + }, + }; + const DWORD expect_state[ARRAY_SIZE(injected_input)][ARRAY_SIZE(expect_actions)] = + { + { 0, 0, 0, -1, 0, 0, 0, 0}, + { 0, 0, 0, -1, 0, 0, 0, 0}, + {+128, 0, 0, +31500, 0, 0, 0, +128}, + { 0, 0, 0, -1, 0, 0, 0, -43}, + { 0, 0, 0, -1, 0, 0, 0, -43}, + {+128, 0, 0, -1, 0, 0, 0, -128}, + }; + const DIDEVICEOBJECTDATA expect_objdata[8] = + { + {.dwOfs = 0x1c, .dwData = +128, .uAppData = 8}, + {.dwOfs = 0xc, .dwData = +31500, .uAppData = 4}, + {.dwOfs = 0, .dwData = +128, .uAppData = 1}, + {.dwOfs = 0x1c, .dwData = -43, .uAppData = 8}, + {.dwOfs = 0xc, .dwData = -1, .uAppData = 4}, + {.dwOfs = 0, .dwData = 0, .uAppData = 1}, + {.dwOfs = 0x1c, .dwData = -128, .uAppData = 8}, + {.dwOfs = 0, .dwData = +128, .uAppData = 1}, + }; DIACTIONW voice_actions[] = { {.dwSemantic = DIVOICE_CHANNEL1}, @@ -760,10 +807,12 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e .dwSize = sizeof(DIPROPPOINTER), } }; + DIDEVICEOBJECTDATA objdata[ARRAY_SIZE(expect_objdata)]; DIACTIONW actions[ARRAY_SIZE(expect_actions)]; + DWORD state[ARRAY_SIZE(expect_actions)]; DIACTIONFORMATW action_format; WCHAR username[256]; - DWORD res, flags; + DWORD i, res, flags; HRESULT hr; res = ARRAY_SIZE(username); @@ -1028,6 +1077,87 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2, actions_todos_2 ); + hr = IDirectInputDevice8_Acquire( device ); + todo_wine + ok( hr == DI_OK, "Acquire returned: %#lx\n", hr ); + if (hr != DI_OK) goto skip_input; + + hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_DEFAULT ); + ok( hr == DIERR_ACQUIRED, "SetActionMap returned %#lx\n", hr ); + + send_hid_input( file, &injected_input[0], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + if (res == WAIT_TIMEOUT) /* Acquire is asynchronous */ + { + send_hid_input( file, &injected_input[0], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + } + todo_wine + ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + + for (i = 0; i < ARRAY_SIZE(injected_input); ++i) + { + winetest_push_context( "state[%ld]", i ); + + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), state ); + todo_wine + ok( hr == DI_OK, "GetDeviceState returned: %#lx\n", hr ); + todo_wine_if( expect_state[i][0] ) + ok( state[0] == expect_state[i][0], "got state[0] %+ld\n", state[0] ); + todo_wine_if( expect_state[i][1] ) + ok( state[1] == expect_state[i][1], "got state[1] %+ld\n", state[1] ); + todo_wine_if( expect_state[i][2] ) + ok( state[2] == expect_state[i][2], "got state[2] %+ld\n", state[2] ); + todo_wine_if( expect_state[i][3] ) + ok( state[3] == expect_state[i][3], "got state[3] %+ld\n", state[3] ); + todo_wine_if( expect_state[i][4] ) + ok( state[4] == expect_state[i][4], "got state[4] %+ld\n", state[4] ); + todo_wine_if( expect_state[i][5] ) + ok( state[5] == expect_state[i][5], "got state[5] %+ld\n", state[5] ); + todo_wine_if( expect_state[i][6] ) + ok( state[6] == expect_state[i][6], "got state[6] %+ld\n", state[6] ); + todo_wine_if( expect_state[i][7] ) + ok( state[7] == expect_state[i][7] || + broken(state[7] == -45 && expect_state[i][7] == -43) /* 32-bit rounding */, + "got state[7] %+ld\n", state[7] ); + + send_hid_input( file, &injected_input[i], sizeof(*injected_input) ); + + res = WaitForSingleObject( event, 100 ); + if (i == 0 || i == 3) ok( res == WAIT_TIMEOUT, "WaitForSingleObject succeeded\n" ); + else todo_wine ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + ResetEvent( event ); + winetest_pop_context(); + } + + res = ARRAY_SIZE(objdata); + hr = IDirectInputDevice8_GetDeviceData( device, sizeof(*objdata), objdata, &res, DIGDD_PEEK ); + todo_wine + ok( hr == DI_BUFFEROVERFLOW, "GetDeviceData returned %#lx\n", hr ); + ok( res == 8, "got %lu expected %u\n", res, 8 ); + while (res--) + { + winetest_push_context( "%lu", res ); + todo_wine_if( expect_objdata[res].dwOfs ) + check_member( objdata[res], expect_objdata[res], "%#lx", dwOfs ); + todo_wine_if( expect_objdata[res].dwData ) + ok( objdata[res].dwData == expect_objdata[res].dwData || + broken(objdata[res].dwData == -45 && expect_objdata[res].dwData == -43) /* 32-bit rounding */, + "got dwData %+ld\n", objdata[res].dwData ); + todo_wine + check_member( objdata[res], expect_objdata[res], "%#Ix", uAppData ); + winetest_pop_context(); + } + +skip_input: + hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); + ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); + + hr = IDirectInputDevice8_Unacquire( device ); + todo_wine + ok( hr == DI_OK, "Acquire returned: %#lx\n", hr ); + + /* setting the data format resets action map */ prop_pointer.diph.dwHow = DIPH_BYUSAGE; From 8054abf7819403a7864fc0e4b1bf92c53aa534bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 15 Mar 2023 21:04:01 +0100 Subject: [PATCH 1341/2777] dinput/tests: Remove BuildActionMap / SaveActionMap mouse and keyboard tests. (cherry picked from commit 07753da93ce1f78c710f666e193a0434eb99699b) --- dlls/dinput/tests/device8.c | 517 ------------------------------------ 1 file changed, 517 deletions(-) diff --git a/dlls/dinput/tests/device8.c b/dlls/dinput/tests/device8.c index 1f29c9af519..620a31417fa 100644 --- a/dlls/dinput/tests/device8.c +++ b/dlls/dinput/tests/device8.c @@ -42,43 +42,7 @@ struct enum_data IDirectInput8A *dinput8; IDirectInputA *dinput; }; - DIACTIONFORMATA *lpdiaf; - IDirectInputDevice8A *keyboard; - IDirectInputDevice8A *mouse; - const char *username; - int ndevices; - HWND hwnd; -}; - -/* Dummy GUID */ -static const GUID ACTION_MAPPING_GUID = { 0x1, 0x2, 0x3, { 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb } }; - -enum { - DITEST_AXIS, - DITEST_BUTTON, - DITEST_KEYBOARDSPACE, - DITEST_MOUSEBUTTON0, - DITEST_YAXIS -}; - -static DIACTIONA actionMapping[]= -{ - /* axis */ - { 0, 0x01008A01 /* DIAXIS_DRIVINGR_STEER */, 0, { "Steer.\0" } }, - /* button */ - { 1, 0x01000C01 /* DIBUTTON_DRIVINGR_SHIFTUP */, 0, { "Upshift.\0" } }, - /* keyboard key */ - { 2, DIKEYBOARD_SPACE, 0, { "Missile.\0" } }, - /* mouse button */ - { 3, DIMOUSE_BUTTON0, 0, { "Select\0" } }, - /* mouse axis */ - { 4, DIMOUSE_YAXIS, 0, { "Y Axis\0" } } }; -/* By placing the memory pointed to by lptszActionName right before memory with PAGE_NOACCESS - * one can find out that the regular ansi string termination is not respected by EnumDevicesBySemantics. - * Adding a double termination, making it a valid wide string termination, made the test succeed. - * Therefore it looks like ansi version of EnumDevicesBySemantics forwards the string to - * the wide variant without conversation. */ static void flush_events(void) { @@ -571,485 +535,6 @@ static void test_device_input( IDirectInputDevice8A *device, DWORD type, DWORD c CloseHandle( event ); } -static void test_build_action_map(IDirectInputDevice8A *lpdid, DIACTIONFORMATA *lpdiaf, - int action_index, DWORD expected_type, DWORD expected_inst) -{ - HRESULT hr; - DIACTIONA *actions; - DWORD instance, type, how; - GUID assigned_to; - DIDEVICEINSTANCEA ddi; - - ddi.dwSize = sizeof(ddi); - IDirectInputDevice_GetDeviceInfo(lpdid, &ddi); - - hr = IDirectInputDevice8_BuildActionMap(lpdid, lpdiaf, NULL, DIDBAM_HWDEFAULTS); - ok (SUCCEEDED(hr), "BuildActionMap failed hr=%#lx\n", hr); - - actions = lpdiaf->rgoAction; - instance = DIDFT_GETINSTANCE(actions[action_index].dwObjID); - type = DIDFT_GETTYPE(actions[action_index].dwObjID); - how = actions[action_index].dwHow; - assigned_to = actions[action_index].guidInstance; - - ok (how == DIAH_USERCONFIG || how == DIAH_DEFAULT, "Action was not set dwHow=%#lx\n", how); - ok (instance == expected_inst, "Action not mapped correctly instance=%#lx expected=%#lx\n", instance, expected_inst); - ok (type == expected_type, "Action type not mapped correctly type=%#lx expected=%#lx\n", type, expected_type); - ok (IsEqualGUID(&assigned_to, &ddi.guidInstance), "Action and device GUID do not match action=%d\n", action_index); -} - -static BOOL CALLBACK enumeration_callback(const DIDEVICEINSTANCEA *lpddi, IDirectInputDevice8A *lpdid, - DWORD dwFlags, DWORD dwRemaining, LPVOID pvRef) -{ - HRESULT hr; - DIPROPDWORD dp; - DIPROPRANGE dpr; - DIPROPSTRING dps; - WCHAR usernameW[MAX_PATH]; - DWORD username_size = MAX_PATH; - struct enum_data *data = pvRef; - DWORD cnt; - DIDEVICEOBJECTDATA buffer[5]; - IDirectInputDevice8A *lpdid2; - - if (!data) return DIENUM_CONTINUE; - - data->ndevices++; - - /* Convert username to WCHAR */ - if (data->username != NULL) - { - username_size = MultiByteToWideChar(CP_ACP, 0, data->username, -1, usernameW, 0); - MultiByteToWideChar(CP_ACP, 0, data->username, -1, usernameW, username_size); - } - else - GetUserNameW(usernameW, &username_size); - - /* collect the mouse and keyboard */ - if (IsEqualGUID(&lpddi->guidInstance, &GUID_SysKeyboard)) - { - IDirectInputDevice_AddRef(lpdid); - data->keyboard = lpdid; - - ok (dwFlags & DIEDBS_MAPPEDPRI1, "Keyboard should be mapped as pri1 dwFlags=%#lx\n", dwFlags); - } - - if (IsEqualGUID(&lpddi->guidInstance, &GUID_SysMouse)) - { - IDirectInputDevice_AddRef(lpdid); - data->mouse = lpdid; - - ok (dwFlags & DIEDBS_MAPPEDPRI1, "Mouse should be mapped as pri1 dwFlags=%#lx\n", dwFlags); - } - - /* Creating second device object to check if it has the same username */ - hr = IDirectInput_CreateDevice(data->dinput8, &lpddi->guidInstance, &lpdid2, NULL); - ok(SUCCEEDED(hr), "IDirectInput_CreateDevice() failed: %#lx\n", hr); - - /* Building and setting an action map */ - /* It should not use any pre-stored mappings so we use DIDBAM_HWDEFAULTS */ - hr = IDirectInputDevice8_BuildActionMap(lpdid, data->lpdiaf, NULL, DIDBAM_HWDEFAULTS); - ok (SUCCEEDED(hr), "BuildActionMap failed hr=%#lx\n", hr); - - /* Device has no data format and thus can't be acquired */ - hr = IDirectInputDevice8_Acquire(lpdid); - ok (hr == DIERR_INVALIDPARAM, "Device was acquired before SetActionMap hr=%#lx\n", hr); - - hr = IDirectInputDevice8_SetActionMap(lpdid, data->lpdiaf, data->username, 0); - ok (SUCCEEDED(hr), "SetActionMap failed hr=%#lx\n", hr); - - /* Some joysticks may have no suitable actions and thus should not be tested */ - if (hr == DI_NOEFFECT) return DIENUM_CONTINUE; - - /* Test username after SetActionMap */ - dps.diph.dwSize = sizeof(dps); - dps.diph.dwHeaderSize = sizeof(DIPROPHEADER); - dps.diph.dwObj = 0; - dps.diph.dwHow = DIPH_DEVICE; - dps.wsz[0] = '\0'; - - hr = IDirectInputDevice_GetProperty(lpdid, DIPROP_USERNAME, &dps.diph); - ok (SUCCEEDED(hr), "GetProperty failed hr=%#lx\n", hr); - ok (!lstrcmpW(usernameW, dps.wsz), "Username not set correctly expected=%s, got=%s\n", wine_dbgstr_w(usernameW), wine_dbgstr_w(dps.wsz)); - - dps.wsz[0] = '\0'; - hr = IDirectInputDevice_GetProperty(lpdid2, DIPROP_USERNAME, &dps.diph); - ok (SUCCEEDED(hr), "GetProperty failed hr=%#lx\n", hr); - ok (!lstrcmpW(usernameW, dps.wsz), "Username not set correctly expected=%s, got=%s\n", wine_dbgstr_w(usernameW), wine_dbgstr_w(dps.wsz)); - - /* Test buffer size */ - memset(&dp, 0, sizeof(dp)); - dp.diph.dwSize = sizeof(dp); - dp.diph.dwHeaderSize = sizeof(DIPROPHEADER); - dp.diph.dwHow = DIPH_DEVICE; - - hr = IDirectInputDevice_GetProperty(lpdid, DIPROP_BUFFERSIZE, &dp.diph); - ok (SUCCEEDED(hr), "GetProperty failed hr=%#lx\n", hr); - ok (dp.dwData == data->lpdiaf->dwBufferSize, "SetActionMap must set the buffer, buffersize=%lu\n", dp.dwData); - - cnt = 1; - hr = IDirectInputDevice_GetDeviceData(lpdid, sizeof(buffer[0]), buffer, &cnt, 0); - ok(hr == DIERR_NOTACQUIRED, "GetDeviceData() failed hr=%#lx\n", hr); - - /* Test axis range */ - memset(&dpr, 0, sizeof(dpr)); - dpr.diph.dwSize = sizeof(dpr); - dpr.diph.dwHeaderSize = sizeof(DIPROPHEADER); - dpr.diph.dwHow = DIPH_DEVICE; - - hr = IDirectInputDevice_GetProperty(lpdid, DIPROP_RANGE, &dpr.diph); - /* Only test if device supports the range property */ - if (SUCCEEDED(hr)) - { - ok (dpr.lMin == data->lpdiaf->lAxisMin, "SetActionMap must set the min axis range expected=%ld got=%ld\n", data->lpdiaf->lAxisMin, dpr.lMin); - ok (dpr.lMax == data->lpdiaf->lAxisMax, "SetActionMap must set the max axis range expected=%ld got=%ld\n", data->lpdiaf->lAxisMax, dpr.lMax); - } - - /* SetActionMap has set the data format so now it should work */ - hr = IDirectInputDevice8_Acquire(lpdid); - ok (SUCCEEDED(hr), "Acquire failed hr=%#lx\n", hr); - - cnt = 1; - hr = IDirectInputDevice_GetDeviceData(lpdid, sizeof(buffer[0]), buffer, &cnt, 0); - ok(hr == DI_OK, "GetDeviceData() failed hr=%#lx\n", hr); - - /* SetActionMap should not work on an acquired device */ - hr = IDirectInputDevice8_SetActionMap(lpdid, data->lpdiaf, NULL, 0); - ok (hr == DIERR_ACQUIRED, "SetActionMap succeeded with an acquired device hr=%#lx\n", hr); - - IDirectInputDevice_Release(lpdid2); - - return DIENUM_CONTINUE; -} - -static void test_appdata_property_vs_map(struct enum_data *data) -{ - HRESULT hr; - DIPROPPOINTER dp; - - dp.diph.dwSize = sizeof(dp); - dp.diph.dwHeaderSize = sizeof(DIPROPHEADER); - dp.diph.dwHow = DIPH_BYID; - dp.diph.dwObj = DIDFT_MAKEINSTANCE(DIK_SPACE) | DIDFT_PSHBUTTON; - dp.uData = 10; - hr = IDirectInputDevice8_SetProperty(data->keyboard, DIPROP_APPDATA, &(dp.diph)); - ok(SUCCEEDED(hr), "IDirectInputDevice8_SetProperty failed hr=%#lx\n", hr); - - test_device_input(data->keyboard, INPUT_KEYBOARD, DIK_SPACE, 10); - - dp.diph.dwHow = DIPH_BYID; - dp.diph.dwObj = DIDFT_MAKEINSTANCE(DIK_V) | DIDFT_PSHBUTTON; - dp.uData = 11; - hr = IDirectInputDevice8_SetProperty(data->keyboard, DIPROP_APPDATA, &(dp.diph)); - ok(hr == DIERR_OBJECTNOTFOUND, "IDirectInputDevice8_SetProperty should not find key that's not in the action map hr=%#lx\n", hr); - - /* setting format should reset action map */ - hr = IDirectInputDevice8_SetDataFormat(data->keyboard, &c_dfDIKeyboard); - ok(SUCCEEDED(hr), "SetDataFormat failed: %#lx\n", hr); - - test_device_input(data->keyboard, INPUT_KEYBOARD, DIK_SPACE, -1); - - dp.diph.dwHow = DIPH_BYID; - dp.diph.dwObj = DIDFT_MAKEINSTANCE(DIK_V) | DIDFT_PSHBUTTON; - dp.uData = 11; - hr = IDirectInputDevice8_SetProperty(data->keyboard, DIPROP_APPDATA, &(dp.diph)); - ok(SUCCEEDED(hr), "IDirectInputDevice8_SetProperty failed hr=%#lx\n", hr); - - test_device_input(data->keyboard, INPUT_KEYBOARD, DIK_V, 11); - - /* back to action map */ - hr = IDirectInputDevice8_SetActionMap(data->keyboard, data->lpdiaf, NULL, 0); - ok(SUCCEEDED(hr), "SetActionMap failed hr=%#lx\n", hr); - - test_device_input(data->keyboard, INPUT_KEYBOARD, DIK_SPACE, 2); -} - -static void test_action_mapping(void) -{ - HRESULT hr; - IDirectInput8A *pDI = NULL; - DIACTIONFORMATA af; - DIPROPSTRING dps; - struct enum_data data = {.version = 0x800, .lpdiaf = &af}; - HWND hwnd; - - hr = CoCreateInstance(&CLSID_DirectInput8, 0, CLSCTX_INPROC_SERVER, &IID_IDirectInput8A, (LPVOID*)&pDI); - if (hr == DIERR_OLDDIRECTINPUTVERSION || - hr == DIERR_BETADIRECTINPUTVERSION || - hr == REGDB_E_CLASSNOTREG) - { - win_skip("ActionMapping requires dinput8\n"); - return; - } - ok(SUCCEEDED(hr), "DirectInput8 Create failed: hr=%#lx\n", hr); - if (FAILED(hr)) return; - - hr = IDirectInput8_Initialize(pDI, instance, DIRECTINPUT_VERSION); - if (hr == DIERR_OLDDIRECTINPUTVERSION || hr == DIERR_BETADIRECTINPUTVERSION) - { - win_skip("ActionMapping requires dinput8\n"); - return; - } - ok(SUCCEEDED(hr), "DirectInput8 Initialize failed: hr=%#lx\n", hr); - if (FAILED(hr)) return; - - memset (&af, 0, sizeof(af)); - af.dwSize = sizeof(af); - af.dwActionSize = sizeof(DIACTIONA); - af.dwDataSize = 4 * ARRAY_SIZE(actionMapping); - af.dwNumActions = ARRAY_SIZE(actionMapping); - af.rgoAction = actionMapping; - af.guidActionMap = ACTION_MAPPING_GUID; - af.dwGenre = 0x01000000; /* DIVIRTUAL_DRIVING_RACE */ - af.dwBufferSize = 32; - - /* This enumeration builds and sets the action map for all devices */ - data.dinput8 = pDI; - hr = IDirectInput8_EnumDevicesBySemantics(pDI, 0, &af, enumeration_callback, &data, DIEDBSFL_ATTACHEDONLY); - ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed: hr=%#lx\n", hr); - - if (data.keyboard) - IDirectInputDevice_Release(data.keyboard); - - if (data.mouse) - IDirectInputDevice_Release(data.mouse); - - /* Repeat tests with a non NULL user */ - data.username = "Ninja Brian"; - hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &af, enumeration_callback, &data, DIEDBSFL_ATTACHEDONLY); - ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed: hr=%#lx\n", hr); - - hwnd = CreateWindowExA(WS_EX_TOPMOST, "static", "dinput", - WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL); - ok(hwnd != NULL, "failed to create window\n"); - SetCursorPos(50, 50); - - if (data.keyboard != NULL) - { - /* Test keyboard BuildActionMap */ - test_build_action_map(data.keyboard, data.lpdiaf, DITEST_KEYBOARDSPACE, DIDFT_PSHBUTTON, DIK_SPACE); - /* Test keyboard input */ - test_device_input(data.keyboard, INPUT_KEYBOARD, DIK_SPACE, 2); - - /* setting format should reset action map */ - hr = IDirectInputDevice8_SetDataFormat(data.keyboard, &c_dfDIKeyboard); - ok (SUCCEEDED(hr), "IDirectInputDevice8_SetDataFormat failed: %#lx\n", hr); - - test_device_input(data.keyboard, INPUT_KEYBOARD, DIK_SPACE, -1); - - /* back to action map */ - hr = IDirectInputDevice8_SetActionMap(data.keyboard, data.lpdiaf, NULL, 0); - ok (SUCCEEDED(hr), "SetActionMap should succeed hr=%#lx\n", hr); - - test_device_input(data.keyboard, INPUT_KEYBOARD, DIK_SPACE, 2); - - test_appdata_property_vs_map(&data); - - /* Test BuildActionMap with no suitable actions for a device */ - IDirectInputDevice_Unacquire(data.keyboard); - af.dwDataSize = 4 * DITEST_KEYBOARDSPACE; - af.dwNumActions = DITEST_KEYBOARDSPACE; - - hr = IDirectInputDevice8_BuildActionMap(data.keyboard, data.lpdiaf, NULL, DIDBAM_HWDEFAULTS); - ok (hr == DI_NOEFFECT, "BuildActionMap should have no effect with no actions hr=%#lx\n", hr); - - hr = IDirectInputDevice8_SetActionMap(data.keyboard, data.lpdiaf, NULL, 0); - ok (hr == DI_NOEFFECT, "SetActionMap should have no effect with no actions to map hr=%#lx\n", hr); - - af.dwDataSize = 4 * ARRAY_SIZE(actionMapping); - af.dwNumActions = ARRAY_SIZE(actionMapping); - - /* test DIDSAM_NOUSER */ - dps.diph.dwSize = sizeof(dps); - dps.diph.dwHeaderSize = sizeof(DIPROPHEADER); - dps.diph.dwObj = 0; - dps.diph.dwHow = DIPH_DEVICE; - dps.wsz[0] = '\0'; - - hr = IDirectInputDevice_GetProperty(data.keyboard, DIPROP_USERNAME, &dps.diph); - ok (SUCCEEDED(hr), "GetProperty failed hr=%#lx\n", hr); - ok (dps.wsz[0] != 0, "Expected any username, got=%s\n", wine_dbgstr_w(dps.wsz)); - - hr = IDirectInputDevice8_SetActionMap(data.keyboard, data.lpdiaf, NULL, DIDSAM_NOUSER); - ok (SUCCEEDED(hr), "SetActionMap failed hr=%#lx\n", hr); - - dps.diph.dwSize = sizeof(dps); - dps.diph.dwHeaderSize = sizeof(DIPROPHEADER); - dps.diph.dwObj = 0; - dps.diph.dwHow = DIPH_DEVICE; - dps.wsz[0] = '\0'; - - hr = IDirectInputDevice_GetProperty(data.keyboard, DIPROP_USERNAME, &dps.diph); - ok (SUCCEEDED(hr), "GetProperty failed hr=%#lx\n", hr); - ok (dps.wsz[0] == 0, "Expected empty username, got=%s\n", wine_dbgstr_w(dps.wsz)); - - IDirectInputDevice_Release(data.keyboard); - } - - if (data.mouse != NULL) - { - /* Test mouse BuildActionMap */ - test_build_action_map(data.mouse, data.lpdiaf, DITEST_MOUSEBUTTON0, DIDFT_PSHBUTTON, 0x03); - test_build_action_map(data.mouse, data.lpdiaf, DITEST_YAXIS, DIDFT_RELAXIS, 0x01); - - test_device_input(data.mouse, INPUT_MOUSE, MOUSEEVENTF_LEFTDOWN, 3); - - IDirectInputDevice_Release(data.mouse); - } - - DestroyWindow(hwnd); - IDirectInput_Release(pDI); -} - -static void test_save_settings(void) -{ - HRESULT hr; - IDirectInput8A *pDI = NULL; - DIACTIONFORMATA af; - IDirectInputDevice8A *pKey; - - static const GUID mapping_guid = { 0xcafecafe, 0x2, 0x3, { 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb } }; - static const GUID other_guid = { 0xcafe, 0xcafe, 0x3, { 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb } }; - - static DIACTIONA actions[] = { - { 0, DIKEYBOARD_A , 0, { "Blam" } }, - { 1, DIKEYBOARD_B , 0, { "Kapow"} } - }; - static const DWORD results[] = { - DIDFT_MAKEINSTANCE(DIK_A) | DIDFT_PSHBUTTON, - DIDFT_MAKEINSTANCE(DIK_B) | DIDFT_PSHBUTTON - }; - static const DWORD other_results[] = { - DIDFT_MAKEINSTANCE(DIK_C) | DIDFT_PSHBUTTON, - DIDFT_MAKEINSTANCE(DIK_D) | DIDFT_PSHBUTTON - }; - - hr = CoCreateInstance(&CLSID_DirectInput8, 0, CLSCTX_INPROC_SERVER, &IID_IDirectInput8A, (LPVOID*)&pDI); - if (hr == DIERR_OLDDIRECTINPUTVERSION || - hr == DIERR_BETADIRECTINPUTVERSION || - hr == REGDB_E_CLASSNOTREG) - { - win_skip("ActionMapping requires dinput8\n"); - return; - } - ok (SUCCEEDED(hr), "DirectInput8 Create failed: hr=%#lx\n", hr); - if (FAILED(hr)) return; - - hr = IDirectInput8_Initialize(pDI, instance, DIRECTINPUT_VERSION); - if (hr == DIERR_OLDDIRECTINPUTVERSION || hr == DIERR_BETADIRECTINPUTVERSION) - { - win_skip("ActionMapping requires dinput8\n"); - return; - } - ok (SUCCEEDED(hr), "DirectInput8 Initialize failed: hr=%#lx\n", hr); - if (FAILED(hr)) return; - - hr = IDirectInput_CreateDevice(pDI, &GUID_SysKeyboard, &pKey, NULL); - ok (SUCCEEDED(hr), "IDirectInput_Create device failed hr: 0x%#lx\n", hr); - if (FAILED(hr)) return; - - memset (&af, 0, sizeof(af)); - af.dwSize = sizeof(af); - af.dwActionSize = sizeof(DIACTIONA); - af.dwDataSize = 4 * ARRAY_SIZE(actions); - af.dwNumActions = ARRAY_SIZE(actions); - af.rgoAction = actions; - af.guidActionMap = mapping_guid; - af.dwGenre = 0x01000000; /* DIVIRTUAL_DRIVING_RACE */ - af.dwBufferSize = 32; - - /* Easy case. Ask for default mapping, save, ask for previous map and read it back */ - hr = IDirectInputDevice8_BuildActionMap(pKey, &af, NULL, DIDBAM_HWDEFAULTS); - ok (SUCCEEDED(hr), "BuildActionMap failed hr=%#lx\n", hr); - ok (results[0] == af.rgoAction[0].dwObjID, - "Mapped incorrectly expected: 0x%#lx got: 0x%#lx\n", results[0], af.rgoAction[0].dwObjID); - - ok (results[1] == af.rgoAction[1].dwObjID, - "Mapped incorrectly expected: 0x%#lx got: 0x%#lx\n", results[1], af.rgoAction[1].dwObjID); - - hr = IDirectInputDevice8_SetActionMap(pKey, &af, NULL, DIDSAM_FORCESAVE); - ok (SUCCEEDED(hr), "SetActionMap failed hr=%#lx\n", hr); - - if (hr == DI_SETTINGSNOTSAVED) - { - skip ("Can't test saving settings if SetActionMap returns DI_SETTINGSNOTSAVED\n"); - return; - } - - af.rgoAction[0].dwObjID = 0; - af.rgoAction[1].dwObjID = 0; - memset(&af.rgoAction[0].guidInstance, 0, sizeof(GUID)); - memset(&af.rgoAction[1].guidInstance, 0, sizeof(GUID)); - - hr = IDirectInputDevice8_BuildActionMap(pKey, &af, NULL, 0); - ok (SUCCEEDED(hr), "BuildActionMap failed hr=%#lx\n", hr); - - ok (results[0] == af.rgoAction[0].dwObjID, - "Mapped incorrectly expected: 0x%#lx got: 0x%#lx\n", results[0], af.rgoAction[0].dwObjID); - ok (IsEqualGUID(&GUID_SysKeyboard, &af.rgoAction[0].guidInstance), "Action should be mapped to keyboard\n"); - - ok (results[1] == af.rgoAction[1].dwObjID, - "Mapped incorrectly expected: 0x%#lx got: 0x%#lx\n", results[1], af.rgoAction[1].dwObjID); - ok (IsEqualGUID(&GUID_SysKeyboard, &af.rgoAction[1].guidInstance), "Action should be mapped to keyboard\n"); - - /* Test that a different action map with no pre-stored settings, in spite of the flags, - does not try to load mappings and instead applies the default mapping */ - af.guidActionMap = other_guid; - - af.rgoAction[0].dwObjID = 0; - af.rgoAction[1].dwObjID = 0; - memset(&af.rgoAction[0].guidInstance, 0, sizeof(GUID)); - memset(&af.rgoAction[1].guidInstance, 0, sizeof(GUID)); - - hr = IDirectInputDevice8_BuildActionMap(pKey, &af, NULL, 0); - ok (SUCCEEDED(hr), "BuildActionMap failed hr=%#lx\n", hr); - - ok (results[0] == af.rgoAction[0].dwObjID, - "Mapped incorrectly expected: 0x%#lx got: 0x%#lx\n", results[0], af.rgoAction[0].dwObjID); - ok (IsEqualGUID(&GUID_SysKeyboard, &af.rgoAction[0].guidInstance), "Action should be mapped to keyboard\n"); - - ok (results[1] == af.rgoAction[1].dwObjID, - "Mapped incorrectly expected: 0x%#lx got: 0x%#lx\n", results[1], af.rgoAction[1].dwObjID); - ok (IsEqualGUID(&GUID_SysKeyboard, &af.rgoAction[1].guidInstance), "Action should be mapped to keyboard\n"); - - af.guidActionMap = mapping_guid; - /* Hard case. Customized mapping, save, ask for previous map and read it back */ - af.rgoAction[0].dwObjID = other_results[0]; - af.rgoAction[0].dwHow = DIAH_USERCONFIG; - af.rgoAction[0].guidInstance = GUID_SysKeyboard; - af.rgoAction[1].dwObjID = other_results[1]; - af.rgoAction[1].dwHow = DIAH_USERCONFIG; - af.rgoAction[1].guidInstance = GUID_SysKeyboard; - - hr = IDirectInputDevice8_SetActionMap(pKey, &af, NULL, DIDSAM_FORCESAVE); - ok (SUCCEEDED(hr), "SetActionMap failed hr=%#lx\n", hr); - - if (hr == DI_SETTINGSNOTSAVED) - { - skip ("Can't test saving settings if SetActionMap returns DI_SETTINGSNOTSAVED\n"); - return; - } - - af.rgoAction[0].dwObjID = 0; - af.rgoAction[1].dwObjID = 0; - memset(&af.rgoAction[0].guidInstance, 0, sizeof(GUID)); - memset(&af.rgoAction[1].guidInstance, 0, sizeof(GUID)); - - hr = IDirectInputDevice8_BuildActionMap(pKey, &af, NULL, 0); - ok (SUCCEEDED(hr), "BuildActionMap failed hr=%#lx\n", hr); - - ok (other_results[0] == af.rgoAction[0].dwObjID, - "Mapped incorrectly expected: 0x%#lx got: 0x%#lx\n", other_results[0], af.rgoAction[0].dwObjID); - ok (IsEqualGUID(&GUID_SysKeyboard, &af.rgoAction[0].guidInstance), "Action should be mapped to keyboard\n"); - - ok (other_results[1] == af.rgoAction[1].dwObjID, - "Mapped incorrectly expected: 0x%#lx got: 0x%#lx\n", other_results[1], af.rgoAction[1].dwObjID); - ok (IsEqualGUID(&GUID_SysKeyboard, &af.rgoAction[1].guidInstance), "Action should be mapped to keyboard\n"); - - IDirectInputDevice_Release(pKey); - IDirectInput_Release(pDI); -} - static void test_mouse_keyboard(void) { HRESULT hr; @@ -2716,8 +2201,6 @@ START_TEST(device8) test_sys_keyboard( 0x700 ); test_sys_keyboard( 0x800 ); - test_action_mapping(); - test_save_settings(); test_mouse_keyboard(); test_keyboard_events(); test_appdata_property(); From 80cac1ca36d6499a18ad76a05bbc12650f43da0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 15 Mar 2023 19:58:19 +0100 Subject: [PATCH 1342/2777] dinput/tests: Increase timeouts for waits not supposed to fail. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54594 (cherry picked from commit 659525268b5193347ffe98a039906388b61bdd8f) --- dlls/dinput/tests/device8.c | 48 +++++++++++++++--------------- dlls/dinput/tests/force_feedback.c | 8 ++--- dlls/dinput/tests/joystick8.c | 26 ++++++++-------- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/dlls/dinput/tests/device8.c b/dlls/dinput/tests/device8.c index 620a31417fa..e8a61968127 100644 --- a/dlls/dinput/tests/device8.c +++ b/dlls/dinput/tests/device8.c @@ -315,12 +315,12 @@ void test_overlapped_format( DWORD version ) if (res == WAIT_TIMEOUT) /* Acquire is asynchronous */ { keybd_event( 0, DIK_F, KEYEVENTF_SCANCODE, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); } ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); keybd_event( 0, DIK_F, KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); count = 10; @@ -331,7 +331,7 @@ void test_overlapped_format( DWORD version ) /* press D */ keybd_event( 0, DIK_D, KEYEVENTF_SCANCODE, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); count = 10; @@ -351,7 +351,7 @@ void test_overlapped_format( DWORD version ) /* release D */ keybd_event( 0, DIK_D, KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); count = 10; @@ -376,12 +376,12 @@ void test_overlapped_format( DWORD version ) if (res == WAIT_TIMEOUT) /* Acquire is asynchronous */ { keybd_event( 0, DIK_F, KEYEVENTF_SCANCODE, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); } ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); keybd_event( 0, DIK_F, KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); count = 10; @@ -392,7 +392,7 @@ void test_overlapped_format( DWORD version ) /* press D */ keybd_event( 0, DIK_D, KEYEVENTF_SCANCODE, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); count = 10; @@ -412,7 +412,7 @@ void test_overlapped_format( DWORD version ) /* release D */ keybd_event( 0, DIK_D, KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); count = 10; @@ -455,12 +455,12 @@ static void test_device_input( IDirectInputDevice8A *device, DWORD type, DWORD c if (res == WAIT_TIMEOUT) /* Acquire is asynchronous */ { keybd_event( 0, code, KEYEVENTF_SCANCODE, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); } ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); keybd_event( 0, code, KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); } if (type == INPUT_MOUSE) @@ -470,12 +470,12 @@ static void test_device_input( IDirectInputDevice8A *device, DWORD type, DWORD c if (res == WAIT_TIMEOUT) /* Acquire is asynchronous */ { mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); } ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); } @@ -491,21 +491,21 @@ static void test_device_input( IDirectInputDevice8A *device, DWORD type, DWORD c if (type == INPUT_KEYBOARD) { keybd_event( VK_SPACE, DIK_SPACE, 0, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); keybd_event( VK_SPACE, DIK_SPACE, KEYEVENTF_KEYUP, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); } if (type == INPUT_MOUSE) { mouse_event( MOUSEEVENTF_LEFTDOWN, 1, 1, 0, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); mouse_event( MOUSEEVENTF_LEFTUP, 1, 1, 0, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); } } @@ -1463,7 +1463,7 @@ static void test_sys_mouse( DWORD version ) if (res == WAIT_TIMEOUT) /* Acquire is asynchronous */ { mouse_event( MOUSEEVENTF_MOVE, 10, 10, 0, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); } ok( !res, "WaitForSingleObject returned %#lx\n", res ); @@ -1473,7 +1473,7 @@ static void test_sys_mouse( DWORD version ) ok( count == 1, "got count %lu\n", count ); mouse_event( MOUSEEVENTF_MOVE, 10, 10, 0, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( !res, "WaitForSingleObject returned %#lx\n", res ); hr = IDirectInputDevice8_Unacquire( device ); @@ -1491,7 +1491,7 @@ static void test_sys_mouse( DWORD version ) if (res == WAIT_TIMEOUT) /* Acquire is asynchronous */ { mouse_event( MOUSEEVENTF_MOVE, 10, 10, 0, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); } ok( !res, "WaitForSingleObject returned %#lx\n", res ); @@ -1510,14 +1510,14 @@ static void test_sys_mouse( DWORD version ) if (res == WAIT_TIMEOUT) /* Acquire is asynchronous */ { mouse_event( MOUSEEVENTF_MOVE, 10, 10, 0, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); } ok( !res, "WaitForSingleObject returned %#lx\n", res ); for (i = 0; i < 2; i++) { mouse_event( MOUSEEVENTF_MOVE, 10 + i, 10 + i, 0, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( !res, "WaitForSingleObject returned %#lx\n", res ); } @@ -1652,7 +1652,7 @@ static void test_dik_codes( IDirectInputDevice8W *device, HANDLE event, HWND hwn if (i == 0 && j == 0 && res == WAIT_TIMEOUT) /* Acquire is asynchronous */ { keybd_event( vkey, scan, 0, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); } ok( !res, "WaitForSingleObject returned %#lx\n", res ); @@ -1663,7 +1663,7 @@ static void test_dik_codes( IDirectInputDevice8W *device, HANDLE event, HWND hwn ok( key_state[map[j].dik] == 0x80, "got state %#x\n", key_state[map[j].dik] ); keybd_event( vkey, scan, KEYEVENTF_KEYUP, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( !res, "WaitForSingleObject returned %#lx\n", res ); winetest_pop_context(); @@ -2142,7 +2142,7 @@ static void test_sys_keyboard( DWORD version ) if (res == WAIT_TIMEOUT) /* Acquire is asynchronous */ { keybd_event( 'Q', 0, 0, 0 ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); } ok( !res, "WaitForSingleObject returned %#lx\n", res ); diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c index 0e9d396996c..b85aa529896 100644 --- a/dlls/dinput/tests/force_feedback.c +++ b/dlls/dinput/tests/force_feedback.c @@ -4175,7 +4175,7 @@ static void test_device_managed_effect(void) res = WaitForSingleObject( event, 100 ); ok( res == WAIT_TIMEOUT, "WaitForSingleObject returned %#lx\n", res ); send_hid_input( file, device_state_input, sizeof(device_state_input) ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); @@ -4383,7 +4383,7 @@ static void test_device_managed_effect(void) set_hid_expect( file, NULL, 0 ); send_hid_input( file, device_state_input_0, sizeof(device_state_input_0) ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); set_hid_expect( file, expect_pool, sizeof(struct hid_expect) ); res = 0xdeadbeef; @@ -4394,7 +4394,7 @@ static void test_device_managed_effect(void) set_hid_expect( file, NULL, 0 ); send_hid_input( file, device_state_input_1, sizeof(device_state_input_1) ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); res = 0xdeadbeef; hr = IDirectInputEffect_GetEffectStatus( effect, &res ); @@ -4409,7 +4409,7 @@ static void test_device_managed_effect(void) set_hid_expect( file, NULL, 0 ); send_hid_input( file, device_state_input_2, sizeof(device_state_input_2) ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); res = 0xdeadbeef; hr = IDirectInputEffect_GetEffectStatus( effect, &res ); diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 414a586b2ba..362d6cd0066 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -2199,7 +2199,7 @@ static void test_simple_joystick( DWORD version ) if (res == WAIT_TIMEOUT) /* Acquire is asynchronous */ { send_hid_input( file, &injected_input[0], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); } ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); ResetEvent( event ); @@ -2230,7 +2230,7 @@ static void test_simple_joystick( DWORD version ) if (res == WAIT_TIMEOUT) /* Acquire is asynchronous */ { send_hid_input( file, &injected_input[1], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); } ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); ResetEvent( event ); @@ -2257,11 +2257,11 @@ static void test_simple_joystick( DWORD version ) } send_hid_input( file, &injected_input[2], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); ResetEvent( event ); send_hid_input( file, &injected_input[4], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); ResetEvent( event ); @@ -2292,7 +2292,7 @@ static void test_simple_joystick( DWORD version ) } send_hid_input( file, &injected_input[3], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); ResetEvent( event ); @@ -2439,7 +2439,7 @@ static void test_simple_joystick( DWORD version ) ResetEvent( event ); send_hid_input( file, &injected_input[3], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); ResetEvent( event ); @@ -2465,13 +2465,13 @@ static void test_simple_joystick( DWORD version ) if (res == WAIT_TIMEOUT) /* Acquire is asynchronous */ { send_hid_input( file, &injected_input[4], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); } ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); ResetEvent( event ); send_hid_input( file, &injected_input[3], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); ResetEvent( event ); @@ -2735,7 +2735,7 @@ static void test_simple_joystick( DWORD version ) ok( hr == DI_OK, "SetProperty DIPROP_CALIBRATIONMODE returned %#lx\n", hr ); send_hid_input( file, &injected_input[ARRAY_SIZE(injected_input) - 1], sizeof(*injected_input) ); - res = WaitForSingleObject( event, 100 ); + res = WaitForSingleObject( event, 5000 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); hr = IDirectInputDevice8_Unacquire( device ); @@ -4536,8 +4536,8 @@ static BOOL test_winmm_joystick(void) ok( hr == DI_OK, "Acquire returned: %#lx\n", hr ); send_hid_input( file, &injected_input[0], sizeof(struct hid_expect) ); - ret = WaitForSingleObject( event, 100 ); - ok( ret != WAIT_TIMEOUT, "WaitForSingleObject returned %#x\n", ret ); + ret = WaitForSingleObject( event, 5000 ); + ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %#x\n", ret ); Sleep( 50 ); /* leave some time for winmm to keep up */ memset( &infoex, 0xcd, sizeof(infoex) ); @@ -4558,8 +4558,8 @@ static BOOL test_winmm_joystick(void) check_member( infoex, expect_infoex[1], "%#lx", dwPOV ); send_hid_input( file, &injected_input[1], sizeof(struct hid_expect) ); - ret = WaitForSingleObject( event, 100 ); - ok( ret != WAIT_TIMEOUT, "WaitForSingleObject returned %#x\n", ret ); + ret = WaitForSingleObject( event, 5000 ); + ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %#x\n", ret ); Sleep( 50 ); /* leave some time for winmm to keep up */ memset( &infoex, 0xcd, sizeof(infoex) ); From eb6be5108dacc4bf5e250b110fa8b41cc405ec65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 20 Mar 2023 16:07:36 +0100 Subject: [PATCH 1343/2777] dinput: Rewrite IDirectInputDevice8W_BuildActionMap. (cherry picked from commit 7b3f3d60782c63edd621353a635616f4cea029da) --- dlls/dinput/device.c | 139 +++++++++++++++++----------------- dlls/dinput/tests/joystick8.c | 79 ++++--------------- 2 files changed, 84 insertions(+), 134 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index c001d1ef29a..77051eaa620 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -314,31 +314,23 @@ static int id_to_offset( struct dinput_device *impl, int id ) return -1; } -static DWORD semantic_to_obj_id( struct dinput_device *This, DWORD dwSemantic ) +static BOOL object_matches_semantics( const DIOBJECTDATAFORMAT *object, DWORD semantic, BOOL exact ) { - DWORD type = (0x0000ff00 & dwSemantic) >> 8; - BOOL byofs = (dwSemantic & 0x80000000) != 0; - DWORD value = (dwSemantic & 0x000000ff); - BOOL found = FALSE; - DWORD instance; - int i; + DWORD value = semantic & 0xff, axis = (semantic >> 15) & 3, type; - for (i = 0; i < This->device_format.dwNumObjs && !found; i++) + switch (semantic & 0x700) { - LPDIOBJECTDATAFORMAT odf = dataformat_to_odf( &This->device_format, i ); - - if (byofs && value != odf->dwOfs) continue; - if (!byofs && value != DIDFT_GETINSTANCE(odf->dwType)) continue; - instance = DIDFT_GETINSTANCE(odf->dwType); - found = TRUE; + case 0x200: type = DIDFT_ABSAXIS; break; + case 0x300: type = DIDFT_RELAXIS; break; + case 0x400: type = DIDFT_BUTTON; break; + case 0x600: type = DIDFT_POV; break; + default: return FALSE; } - if (!found) return 0; - - if (type & DIDFT_AXIS) type = DIDFT_RELAXIS; - if (type & DIDFT_BUTTON) type = DIDFT_PSHBUTTON; - - return type | (0x0000ff00 & (instance << 8)); + if (!(DIDFT_GETTYPE( object->dwType ) & type)) return FALSE; + if ((semantic & 0xf0000000) == 0x80000000) return object->dwOfs == value; + if (axis && (axis - 1) != DIDFT_GETINSTANCE( object->dwType )) return FALSE; + return !exact || !value || value == DIDFT_GETINSTANCE( object->dwType ) + 1; } /* @@ -1857,34 +1849,34 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, const WCHAR *username, DWORD flags ) { struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); - BOOL load_success = FALSE, has_actions = FALSE; - DWORD genre, username_len = MAX_PATH; + DIOBJECTDATAFORMAT *object, *object_end; + DIACTIONW *action, *action_end; + DWORD i, username_len = MAX_PATH; WCHAR username_buf[MAX_PATH]; - const DIDATAFORMAT *df; - DWORD devMask; - int i; + BOOL load_success = FALSE; + BOOL *mapped; FIXME( "iface %p, format %p, username %s, flags %#lx stub!\n", iface, format, debugstr_w(username), flags ); if (!format) return DIERR_INVALIDPARAM; + if (flags != DIDBAM_DEFAULT && flags != DIDBAM_PRESERVE && + flags != DIDBAM_INITIALIZE && flags != DIDBAM_HWDEFAULTS) + return DIERR_INVALIDPARAM; + if (format->dwNumActions * 4 != format->dwDataSize) + return DIERR_INVALIDPARAM; - switch (GET_DIDEVICE_TYPE( impl->instance.dwDevType )) + action_end = format->rgoAction + format->dwNumActions; + for (action = format->rgoAction; action < action_end; action++) { - case DIDEVTYPE_KEYBOARD: - case DI8DEVTYPE_KEYBOARD: - devMask = DIKEYBOARD_MASK; - df = &c_dfDIKeyboard; - break; - case DIDEVTYPE_MOUSE: - case DI8DEVTYPE_MOUSE: - devMask = DIMOUSE_MASK; - df = &c_dfDIMouse2; - break; - default: - devMask = DIGENRE_ANY; - df = &impl->device_format; - break; + if (!action->dwSemantic) return DIERR_INVALIDPARAM; + if (action->dwFlags & DIA_APPMAPPED) action->dwHow = DIAH_APPREQUESTED; + else if (action->dwFlags & DIA_APPNOMAP) continue; + else + { + action->dwHow = 0; + action->guidInstance = GUID_NULL; + } } /* Unless asked the contrary by these flags, try to load a previous mapping */ @@ -1897,46 +1889,51 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, } if (load_success) return DI_OK; + if (!(mapped = calloc( impl->device_format.dwNumObjs, sizeof(*mapped) ))) return DIERR_OUTOFMEMORY; - for (i = 0; i < format->dwNumActions; i++) + action_end = format->rgoAction + format->dwNumActions; + for (action = format->rgoAction; action < action_end; action++) { - /* Don't touch a user configured action */ - if (format->rgoAction[i].dwHow == DIAH_USERCONFIG) continue; + if (action->dwHow || (action->dwFlags & DIA_APPNOMAP)) continue; /* already mapped */ + if (action->dwSemantic & 0x4000) continue; /* priority 1 */ - genre = format->rgoAction[i].dwSemantic & DIGENRE_ANY; - if (devMask == genre || (devMask == DIGENRE_ANY && genre != DIMOUSE_MASK && genre != DIKEYBOARD_MASK)) + object_end = impl->device_format.rgodf + impl->device_format.dwNumObjs; + for (object = impl->device_format.rgodf; object < object_end; object++) { - DWORD obj_id = semantic_to_obj_id( impl, format->rgoAction[i].dwSemantic ); - DWORD type = DIDFT_GETTYPE( obj_id ); - DWORD inst = DIDFT_GETINSTANCE( obj_id ); - - LPDIOBJECTDATAFORMAT odf; - - if (type == DIDFT_PSHBUTTON) type = DIDFT_BUTTON; - if (type == DIDFT_RELAXIS) type = DIDFT_AXIS; + if (mapped[object - impl->device_format.rgodf]) continue; + if (!object_matches_semantics( object, action->dwSemantic, TRUE )) continue; + if ((action->dwFlags & DIA_FORCEFEEDBACK) && !(object->dwType & DIDFT_FFACTUATOR)) continue; + action->dwObjID = object->dwType; + action->guidInstance = impl->guid; + action->dwHow = DIAH_DEFAULT; + mapped[object - impl->device_format.rgodf] = TRUE; + break; + } + } - /* Make sure the object exists */ - odf = dataformat_to_odf_by_type( df, inst, type ); + for (action = format->rgoAction; action < action_end; action++) + { + if (action->dwHow || (action->dwFlags & DIA_APPNOMAP)) continue; /* already mapped */ + if (!(action->dwSemantic & 0x4000)) continue; /* priority 2 */ - if (odf != NULL) - { - format->rgoAction[i].dwObjID = obj_id; - format->rgoAction[i].guidInstance = impl->guid; - format->rgoAction[i].dwHow = DIAH_DEFAULT; - has_actions = TRUE; - } - } - else if (!(flags & DIDBAM_PRESERVE)) + object_end = impl->device_format.rgodf + impl->device_format.dwNumObjs; + for (object = impl->device_format.rgodf; object < object_end; object++) { - /* We must clear action data belonging to other devices */ - memset( &format->rgoAction[i].guidInstance, 0, sizeof(GUID) ); - format->rgoAction[i].dwHow = DIAH_UNMAPPED; + if (mapped[object - impl->device_format.rgodf]) continue; + if (!object_matches_semantics( object, action->dwSemantic, FALSE )) continue; + if ((action->dwFlags & DIA_FORCEFEEDBACK) && !(object->dwType & DIDFT_FFACTUATOR)) continue; + action->dwObjID = object->dwType; + action->guidInstance = impl->guid; + action->dwHow = DIAH_DEFAULT; + mapped[object - impl->device_format.rgodf] = TRUE; + break; } } - if (!has_actions) return DI_NOEFFECT; - if (flags & (DIDBAM_DEFAULT|DIDBAM_PRESERVE|DIDBAM_INITIALIZE|DIDBAM_HWDEFAULTS)) - FIXME( "Unimplemented flags %#lx\n", flags ); + for (i = 0; i < impl->device_format.dwNumObjs; ++i) if (mapped[i]) break; + free( mapped ); + + if (i == impl->device_format.dwNumObjs) return DI_NOEFFECT; return DI_OK; } @@ -2008,7 +2005,7 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D if (type == DIDFT_PSHBUTTON) type = DIDFT_BUTTON; if (type == DIDFT_RELAXIS) type = DIDFT_AXIS; - obj = dataformat_to_odf_by_type( df, inst, type ); + if (!(obj = dataformat_to_odf_by_type( df, inst, type ))) continue; memcpy( &obj_df[action], obj, df->dwObjSize ); diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 362d6cd0066..93cd3e9f09f 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -208,16 +208,8 @@ static BOOL CALLBACK check_no_created_effect_objects( IDirectInputEffect *effect return DIENUM_CONTINUE; } -struct diaction_todo -{ - BOOL instance; - BOOL objid; - BOOL how; -}; - -#define check_diactionw( a, b ) check_diactionw_( __LINE__, a, b, NULL ) -static void check_diactionw_( int line, const DIACTIONW *actual, const DIACTIONW *expected, - const struct diaction_todo *todos ) +#define check_diactionw( a, b ) check_diactionw_( __LINE__, a, b ) +static void check_diactionw_( int line, const DIACTIONW *actual, const DIACTIONW *expected ) { check_member_( __FILE__, line, *actual, *expected, "%#Ix", uAppData ); check_member_( __FILE__, line, *actual, *expected, "%#lx", dwSemantic ); @@ -226,17 +218,13 @@ static void check_diactionw_( int line, const DIACTIONW *actual, const DIACTIONW check_member_wstr_( __FILE__, line, *actual, *expected, lptszActionName ); else check_member_( __FILE__, line, *actual, *expected, "%p", lptszActionName ); - todo_wine_if( todos->instance ) check_member_guid_( __FILE__, line, *actual, *expected, guidInstance ); - todo_wine_if( todos->objid ) check_member_( __FILE__, line, *actual, *expected, "%#lx", dwObjID ); - todo_wine_if( todos->how ) check_member_( __FILE__, line, *actual, *expected, "%#lx", dwHow ); } -#define check_diactionformatw( a, b ) check_diactionformatw_( __LINE__, a, b, NULL ) -static void check_diactionformatw_( int line, const DIACTIONFORMATW *actual, const DIACTIONFORMATW *expected, - const struct diaction_todo *todos ) +#define check_diactionformatw( a, b ) check_diactionformatw_( __LINE__, a, b ) +static void check_diactionformatw_( int line, const DIACTIONFORMATW *actual, const DIACTIONFORMATW *expected ) { DWORD i; check_member_( __FILE__, line, *actual, *expected, "%#lx", dwSize ); @@ -246,7 +234,7 @@ static void check_diactionformatw_( int line, const DIACTIONFORMATW *actual, con for (i = 0; i < min( actual->dwNumActions, expected->dwNumActions ); ++i) { winetest_push_context( "action[%lu]", i ); - check_diactionw_( line, actual->rgoAction + i, expected->rgoAction + i, todos ? todos + i : NULL ); + check_diactionw_( line, actual->rgoAction + i, expected->rgoAction + i ); winetest_pop_context(); if (expected->dwActionSize != sizeof(DIACTIONW)) break; if (actual->dwActionSize != sizeof(DIACTIONW)) break; @@ -749,29 +737,6 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e .lAxisMax = +128, .tszActionMap = L"Action Map Filled", }; - struct diaction_todo actions_todos_1 = {.instance = TRUE, .objid = TRUE, .how = TRUE}; - struct diaction_todo actions_todos_2[ARRAY_SIZE(expect_actions)] = - { - {.instance = TRUE, .objid = TRUE, .how = TRUE}, - {.instance = TRUE, .objid = TRUE, .how = TRUE}, - {0}, - {.instance = TRUE, .objid = TRUE, .how = TRUE}, - {.instance = TRUE, .objid = TRUE, .how = TRUE}, - {.instance = TRUE, .objid = TRUE, .how = TRUE}, - {.instance = TRUE, .objid = TRUE, .how = TRUE}, - {.objid = TRUE}, - }; - struct diaction_todo actions_todos_2_filled[ARRAY_SIZE(expect_actions)] = - { - {.how = TRUE}, - {0}, - {.instance = TRUE, .how = TRUE}, - {.how = TRUE}, - {.instance = TRUE, .how = TRUE}, - {.objid = TRUE, .how = TRUE}, - {.objid = TRUE}, - {.objid = TRUE, .how = TRUE}, - }; DIPROPRANGE prop_range = { .diph = @@ -827,19 +792,15 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e hr = IDirectInputDevice8_BuildActionMap( device, NULL, L"username", DIDBAM_DEFAULT ); ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); hr = IDirectInputDevice8_BuildActionMap( device, &action_format_1, L"username", 0xdeadbeef ); - todo_wine ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); flags = DIDBAM_HWDEFAULTS | DIDBAM_INITIALIZE; hr = IDirectInputDevice8_BuildActionMap( device, &action_format_1, L"username", flags ); - todo_wine ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); flags = DIDBAM_HWDEFAULTS | DIDBAM_PRESERVE; hr = IDirectInputDevice8_BuildActionMap( device, &action_format_1, L"username", flags ); - todo_wine ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); flags = DIDBAM_INITIALIZE | DIDBAM_PRESERVE; hr = IDirectInputDevice8_BuildActionMap( device, &action_format_1, L"username", flags ); - todo_wine ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); hr = IDirectInputDevice8_SetActionMap( device, NULL, NULL, DIDSAM_DEFAULT ); @@ -887,13 +848,11 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e memset( actions, 0, sizeof(actions) ); actions[0] = default_actions[0]; hr = IDirectInputDevice8_BuildActionMap( device, &action_format, NULL, DIDBAM_DEFAULT ); - todo_wine ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_1, &actions_todos_1 ); + check_diactionformatw( &action_format, &expect_action_format_1 ); hr = IDirectInputDevice8_SetActionMap( device, &action_format, NULL, DIDSAM_DEFAULT ); - todo_wine ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_1, &actions_todos_1 ); + check_diactionformatw( &action_format, &expect_action_format_1 ); action_format = action_format_1; @@ -901,9 +860,8 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e memset( actions, 0, sizeof(actions) ); actions[0] = default_actions[0]; hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); - todo_wine ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_1, &actions_todos_1 ); + check_diactionformatw( &action_format, &expect_action_format_1 ); /* first SetActionMap call for a user always return DI_SETTINGSNOTSAVED */ @@ -911,13 +869,11 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e todo_wine ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_DEFAULT ); - todo_wine ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); /* same SetActionMap call returns DI_OK */ hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_DEFAULT ); - todo_wine ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); /* DIDSAM_FORCESAVE always returns DI_SETTINGSNOTSAVED */ @@ -928,7 +884,7 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_FORCESAVE ); todo_wine ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_1, &actions_todos_1 ); + check_diactionformatw( &action_format, &expect_action_format_1 ); /* action format dwDataSize and dwNumActions have to match, actions require a dwSemantic */ @@ -939,11 +895,9 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e actions[0] = default_actions[0]; action_format.dwDataSize = 8; hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); - todo_wine ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); action_format.dwNumActions = 2; hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); - todo_wine ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); action_format.dwNumActions = 1; action_format.dwDataSize = 4; @@ -954,7 +908,7 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e memcpy( actions, default_actions, sizeof(default_actions) ); hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2, actions_todos_2 ); + check_diactionformatw( &action_format, &expect_action_format_2 ); hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_DEFAULT ); ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); @@ -997,16 +951,15 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e action_format.rgoAction = actions; memcpy( actions, filled_actions, sizeof(filled_actions) ); hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); - todo_wine ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2_filled, actions_todos_2_filled ); + check_diactionformatw( &action_format, &expect_action_format_2_filled ); hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_DEFAULT ); ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2_filled, actions_todos_2_filled ); + check_diactionformatw( &action_format, &expect_action_format_2_filled ); hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_FORCESAVE ); todo_wine ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2_filled, actions_todos_2_filled ); + check_diactionformatw( &action_format, &expect_action_format_2_filled ); prop_pointer.diph.dwHow = DIPH_DEVICE; @@ -1060,21 +1013,21 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e memcpy( actions, default_actions, sizeof(default_actions) ); hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_HWDEFAULTS ); ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2, actions_todos_2 ); + check_diactionformatw( &action_format, &expect_action_format_2 ); action_format = action_format_2; action_format.rgoAction = actions; memcpy( actions, default_actions, sizeof(default_actions) ); hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_INITIALIZE ); ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2, actions_todos_2 ); + check_diactionformatw( &action_format, &expect_action_format_2 ); action_format = action_format_2; action_format.rgoAction = actions; memcpy( actions, default_actions, sizeof(default_actions) ); hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_PRESERVE ); ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2, actions_todos_2 ); + check_diactionformatw( &action_format, &expect_action_format_2 ); hr = IDirectInputDevice8_Acquire( device ); From 442dbd09d5d7dfaecf71dda7872e2f42b631ca17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 20 Mar 2023 15:07:46 +0100 Subject: [PATCH 1344/2777] dinput: Pass device object format index to queue_event. (cherry picked from commit 1e594b1c0fd23c1aedc13b3c2d8c91c1fc00f8ee) --- dlls/dinput/device.c | 61 +++++++++++++++--------- dlls/dinput/device_private.h | 3 +- dlls/dinput/joystick_hid.c | 10 ++-- dlls/dinput/keyboard.c | 8 ++-- dlls/dinput/mouse.c | 91 ++++++++++++++++-------------------- 5 files changed, 92 insertions(+), 81 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 77051eaa620..b2487df529b 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -314,23 +314,22 @@ static int id_to_offset( struct dinput_device *impl, int id ) return -1; } -static BOOL object_matches_semantics( const DIOBJECTDATAFORMAT *object, DWORD semantic, BOOL exact ) +int dinput_device_object_index_from_id( IDirectInputDevice8W *iface, DWORD id ) { - DWORD value = semantic & 0xff, axis = (semantic >> 15) & 3, type; + struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); + const DIDATAFORMAT *format = &impl->device_format; + const DIOBJECTDATAFORMAT *object; - switch (semantic & 0x700) + if (!format->rgodf) return -1; + + object = format->rgodf + impl->device_format.dwNumObjs; + while (object-- > format->rgodf) { - case 0x200: type = DIDFT_ABSAXIS; break; - case 0x300: type = DIDFT_RELAXIS; break; - case 0x400: type = DIDFT_BUTTON; break; - case 0x600: type = DIDFT_POV; break; - default: return FALSE; + if (!object->dwType) continue; + if ((object->dwType & 0x00ffffff) == (id & 0x00ffffff)) return object - format->rgodf; } - if (!(DIDFT_GETTYPE( object->dwType ) & type)) return FALSE; - if ((semantic & 0xf0000000) == 0x80000000) return object->dwOfs == value; - if (axis && (axis - 1) != DIDFT_GETINSTANCE( object->dwType )) return FALSE; - return !exact || !value || value == DIDFT_GETINSTANCE( object->dwType ) + 1; + return -1; } /* @@ -484,12 +483,13 @@ static BOOL set_app_data( struct dinput_device *dev, int offset, UINT_PTR app_da return TRUE; } -void queue_event( IDirectInputDevice8W *iface, int inst_id, DWORD data, DWORD time, DWORD seq ) +void queue_event( IDirectInputDevice8W *iface, int index, DWORD data, DWORD time, DWORD seq ) { static ULONGLONG notify_ms = 0; struct dinput_device *This = impl_from_IDirectInputDevice8W( iface ); - int next_pos, ofs = id_to_offset( This, inst_id ); + const DIOBJECTDATAFORMAT *user_obj = This->user_format.rgodf + index; ULONGLONG time_ms = GetTickCount64(); + int next_pos; if (time_ms - notify_ms > 1000) { @@ -497,7 +497,7 @@ void queue_event( IDirectInputDevice8W *iface, int inst_id, DWORD data, DWORD ti notify_ms = time_ms; } - if (!This->queue_len || This->overflow || ofs < 0) return; + if (!This->queue_len || This->overflow || !user_obj->dwType) return; next_pos = (This->queue_head + 1) % This->queue_len; if (next_pos == This->queue_tail) @@ -507,9 +507,9 @@ void queue_event( IDirectInputDevice8W *iface, int inst_id, DWORD data, DWORD ti return; } - TRACE( " queueing %lu at offset %u (queue head %u / size %u)\n", data, ofs, This->queue_head, This->queue_len ); + TRACE( " queueing %lu at offset %lu (queue head %u / size %u)\n", data, user_obj->dwOfs, This->queue_head, This->queue_len ); - This->data_queue[This->queue_head].dwOfs = ofs; + This->data_queue[This->queue_head].dwOfs = user_obj->dwOfs; This->data_queue[This->queue_head].dwData = data; This->data_queue[This->queue_head].dwTimeStamp = time; This->data_queue[This->queue_head].dwSequence = seq; @@ -521,9 +521,9 @@ void queue_event( IDirectInputDevice8W *iface, int inst_id, DWORD data, DWORD ti int i; for (i=0; i < This->num_actions; i++) { - if (This->action_map[i].offset == ofs) + if (This->action_map[i].offset == user_obj->dwOfs) { - TRACE( "Offset %d mapped to uAppData %#Ix\n", ofs, This->action_map[i].uAppData ); + TRACE( "Offset %lu mapped to uAppData %#Ix\n", user_obj->dwOfs, This->action_map[i].uAppData ); This->data_queue[This->queue_head].uAppData = This->action_map[i].uAppData; break; } @@ -1845,6 +1845,25 @@ static HRESULT WINAPI dinput_device_WriteEffectToFile( IDirectInputDevice8W *ifa return DI_OK; } +static BOOL object_matches_semantic( const DIOBJECTDATAFORMAT *object, DWORD semantic, BOOL exact ) +{ + DWORD value = semantic & 0xff, axis = (semantic >> 15) & 3, type; + + switch (semantic & 0x700) + { + case 0x200: type = DIDFT_ABSAXIS; break; + case 0x300: type = DIDFT_RELAXIS; break; + case 0x400: type = DIDFT_BUTTON; break; + case 0x600: type = DIDFT_POV; break; + default: return FALSE; + } + + if (!(DIDFT_GETTYPE( object->dwType ) & type)) return FALSE; + if ((semantic & 0xf0000000) == 0x80000000) return object->dwOfs == value; + if (axis && (axis - 1) != DIDFT_GETINSTANCE( object->dwType )) return FALSE; + return !exact || !value || value == DIDFT_GETINSTANCE( object->dwType ) + 1; +} + static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, DIACTIONFORMATW *format, const WCHAR *username, DWORD flags ) { @@ -1901,7 +1920,7 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, for (object = impl->device_format.rgodf; object < object_end; object++) { if (mapped[object - impl->device_format.rgodf]) continue; - if (!object_matches_semantics( object, action->dwSemantic, TRUE )) continue; + if (!object_matches_semantic( object, action->dwSemantic, TRUE )) continue; if ((action->dwFlags & DIA_FORCEFEEDBACK) && !(object->dwType & DIDFT_FFACTUATOR)) continue; action->dwObjID = object->dwType; action->guidInstance = impl->guid; @@ -1920,7 +1939,7 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, for (object = impl->device_format.rgodf; object < object_end; object++) { if (mapped[object - impl->device_format.rgodf]) continue; - if (!object_matches_semantics( object, action->dwSemantic, FALSE )) continue; + if (!object_matches_semantic( object, action->dwSemantic, FALSE )) continue; if ((action->dwFlags & DIA_FORCEFEEDBACK) && !(object->dwType & DIDFT_FFACTUATOR)) continue; action->dwObjID = object->dwType; action->guidInstance = impl->guid; diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h index ebe1b49da2f..b044c52ba36 100644 --- a/dlls/dinput/device_private.h +++ b/dlls/dinput/device_private.h @@ -130,11 +130,12 @@ extern void dinput_device_internal_addref( struct dinput_device *device ); extern void dinput_device_internal_release( struct dinput_device *device ); extern HRESULT dinput_device_init_device_format( IDirectInputDevice8W *iface ); +extern int dinput_device_object_index_from_id( IDirectInputDevice8W *iface, DWORD id ); extern BOOL get_app_key(HKEY*, HKEY*) DECLSPEC_HIDDEN; extern DWORD get_config_key( HKEY, HKEY, const WCHAR *, WCHAR *, DWORD ) DECLSPEC_HIDDEN; extern BOOL device_instance_is_disabled( DIDEVICEINSTANCEW *instance, BOOL *override ) DECLSPEC_HIDDEN; -extern void queue_event( IDirectInputDevice8W *iface, int inst_id, DWORD data, DWORD time, DWORD seq ) DECLSPEC_HIDDEN; +extern void queue_event( IDirectInputDevice8W *iface, int index, DWORD data, DWORD time, DWORD seq ) DECLSPEC_HIDDEN; extern const GUID dinput_pidvid_guid DECLSPEC_HIDDEN; diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 349644df633..95e6f8eff86 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -1153,6 +1153,7 @@ static BOOL check_device_state_button( struct hid_joystick *impl, struct hid_val IDirectInputDevice8W *iface = &impl->base.IDirectInputDevice8W_iface; struct parse_device_state_params *params = data; BYTE old_value, value; + int index; if (instance->wReportId != impl->base.device_state_report_id) return DIENUM_CONTINUE; @@ -1162,8 +1163,8 @@ static BOOL check_device_state_button( struct hid_joystick *impl, struct hid_val if (params->reset_state) value = 0; impl->base.device_state[instance->dwOfs] = value; - if (old_value != value) - queue_event( iface, instance->dwType, value, params->time, params->seq ); + if (old_value != value && (index = dinput_device_object_index_from_id( iface, instance->dwType )) >= 0) + queue_event( iface, index, value, params->time, params->seq ); return DIENUM_CONTINUE; } @@ -1233,6 +1234,7 @@ static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_value char *report_buf = impl->input_report_buf; LONG old_value, value; NTSTATUS status; + int index; if (instance->wReportId != impl->base.device_state_report_id) return DIENUM_CONTINUE; @@ -1255,8 +1257,8 @@ static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_value old_value = *(LONG *)(params->old_state + instance->dwOfs); *(LONG *)(impl->base.device_state + instance->dwOfs) = value; - if (old_value != value) - queue_event( iface, instance->dwType, value, params->time, params->seq ); + if (old_value != value && (index = dinput_device_object_index_from_id( iface, instance->dwType )) >= 0) + queue_event( iface, index, value, params->time, params->seq ); return DIENUM_CONTINUE; } diff --git a/dlls/dinput/keyboard.c b/dlls/dinput/keyboard.c index c49796cfa2d..73d369b3b5d 100644 --- a/dlls/dinput/keyboard.c +++ b/dlls/dinput/keyboard.c @@ -87,7 +87,7 @@ static void keyboard_handle_event( struct keyboard *impl, DWORD vkey, DWORD scan { BYTE new_diks, subtype = GET_DIDEVICE_SUBTYPE( impl->base.instance.dwDevType ); IDirectInputDevice8W *iface = &impl->base.IDirectInputDevice8W_iface; - int dik_code; + int dik_code, index; switch (vkey) { @@ -109,8 +109,10 @@ static void keyboard_handle_event( struct keyboard *impl, DWORD vkey, DWORD scan TRACE( "setting key %02x to %02x\n", dik_code, impl->base.device_state[dik_code] ); EnterCriticalSection( &impl->base.crit ); - queue_event( iface, DIDFT_MAKEINSTANCE( dik_code ) | DIDFT_PSHBUTTON, new_diks, - GetCurrentTime(), impl->base.dinput->evsequence++ ); + + if ((index = dinput_device_object_index_from_id( iface, DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( dik_code ) )) >= 0) + queue_event( iface, index, new_diks, GetCurrentTime(), impl->base.dinput->evsequence++ ); + if (impl->base.hEvent) SetEvent( impl->base.hEvent ); LeaveCriticalSection( &impl->base.crit ); } diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c index 502ee797716..8e852907d11 100644 --- a/dlls/dinput/mouse.c +++ b/dlls/dinput/mouse.c @@ -37,12 +37,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); -/* Wine mouse driver object instances */ -#define WINE_MOUSE_X_AXIS_INSTANCE 0 -#define WINE_MOUSE_Y_AXIS_INSTANCE 1 -#define WINE_MOUSE_Z_AXIS_INSTANCE 2 -#define WINE_MOUSE_BUTTONS_INSTANCE 3 - static const struct dinput_device_vtbl mouse_vtbl; typedef enum @@ -160,8 +154,8 @@ void dinput_mouse_rawinput_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPA DIMOUSESTATE2 *state = (DIMOUSESTATE2 *)impl->base.device_state; POINT rel, pt; DWORD seq; - int i, wdata = 0; BOOL notify = FALSE; + int i; static const USHORT mouse_button_flags[] = { @@ -206,15 +200,13 @@ void dinput_mouse_rawinput_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPA if (rel.x) { - queue_event( iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS, - pt.x, GetCurrentTime(), seq ); + queue_event( iface, 0, pt.x, GetCurrentTime(), seq ); notify = TRUE; } if (rel.y) { - queue_event( iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS, - pt.y, GetCurrentTime(), seq ); + queue_event( iface, 1, pt.y, GetCurrentTime(), seq ); notify = TRUE; } @@ -227,9 +219,8 @@ void dinput_mouse_rawinput_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPA if (ri->data.mouse.usButtonFlags & RI_MOUSE_WHEEL) { - state->lZ += (wdata = (SHORT)ri->data.mouse.usButtonData); - queue_event( iface, DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS, - wdata, GetCurrentTime(), seq ); + state->lZ += (SHORT)ri->data.mouse.usButtonData; + queue_event( iface, 2, (SHORT)ri->data.mouse.usButtonData, GetCurrentTime(), seq ); notify = TRUE; } @@ -238,8 +229,7 @@ void dinput_mouse_rawinput_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPA if (ri->data.mouse.usButtonFlags & mouse_button_flags[i]) { state->rgbButtons[i / 2] = 0x80 - (i % 2) * 0x80; - queue_event( iface, DIDFT_MAKEINSTANCE( WINE_MOUSE_BUTTONS_INSTANCE + (i / 2) ) | DIDFT_PSHBUTTON, - state->rgbButtons[i / 2], GetCurrentTime(), seq ); + queue_event( iface, 3 + (i / 2), state->rgbButtons[i / 2], GetCurrentTime(), seq ); notify = TRUE; } } @@ -257,12 +247,14 @@ int dinput_mouse_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lparam MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam; struct mouse *impl = impl_from_IDirectInputDevice8W( iface ); DIMOUSESTATE2 *state = (DIMOUSESTATE2 *)impl->base.device_state; - int wdata = 0, inst_id = -1, ret = 0; BOOL notify = FALSE; + int ret = 0; + DWORD seq; TRACE( "iface %p, msg %#Ix, x %+ld, y %+ld\n", iface, wparam, hook->pt.x, hook->pt.y ); EnterCriticalSection( &impl->base.crit ); + seq = impl->base.dinput->evsequence++; switch(wparam) { case WM_MOUSEMOVE: @@ -282,19 +274,13 @@ int dinput_mouse_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lparam if (pt.x) { - inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS; - wdata = pt1.x; + queue_event( iface, 0, pt1.x, GetCurrentTime(), seq ); + notify = TRUE; } if (pt.y) { - /* Already have X, need to queue it */ - if (inst_id != -1) - { - queue_event( iface, inst_id, wdata, GetCurrentTime(), impl->base.dinput->evsequence ); - notify = TRUE; - } - inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS; - wdata = pt1.y; + queue_event( iface, 1, pt1.y, GetCurrentTime(), seq ); + notify = TRUE; } if (pt.x || pt.y) @@ -306,53 +292,54 @@ int dinput_mouse_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lparam break; } case WM_MOUSEWHEEL: - inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS; - state->lZ += wdata = (short)HIWORD( hook->mouseData ); + state->lZ += (short)HIWORD( hook->mouseData ); + queue_event( iface, 2, state->lZ, GetCurrentTime(), seq ); /* FarCry crashes if it gets a mouse wheel message */ /* FIXME: should probably filter out other messages too */ ret = impl->clipped; break; case WM_LBUTTONDOWN: - inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 0) | DIDFT_PSHBUTTON; - state->rgbButtons[0] = wdata = 0x80; + state->rgbButtons[0] = 0x80; + queue_event( iface, 3, 0x80, GetCurrentTime(), seq ); + notify = TRUE; break; case WM_LBUTTONUP: - inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 0) | DIDFT_PSHBUTTON; - state->rgbButtons[0] = wdata = 0x00; + state->rgbButtons[0] = 0x00; + queue_event( iface, 3, 0x00, GetCurrentTime(), seq ); + notify = TRUE; break; case WM_RBUTTONDOWN: - inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 1) | DIDFT_PSHBUTTON; - state->rgbButtons[1] = wdata = 0x80; + state->rgbButtons[1] = 0x80; + queue_event( iface, 4, 0x80, GetCurrentTime(), seq ); + notify = TRUE; break; case WM_RBUTTONUP: - inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 1) | DIDFT_PSHBUTTON; - state->rgbButtons[1] = wdata = 0x00; + state->rgbButtons[1] = 0x00; + queue_event( iface, 4, 0x00, GetCurrentTime(), seq ); + notify = TRUE; break; case WM_MBUTTONDOWN: - inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2) | DIDFT_PSHBUTTON; - state->rgbButtons[2] = wdata = 0x80; + state->rgbButtons[2] = 0x80; + queue_event( iface, 5, 0x80, GetCurrentTime(), seq ); + notify = TRUE; break; case WM_MBUTTONUP: - inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2) | DIDFT_PSHBUTTON; - state->rgbButtons[2] = wdata = 0x00; + state->rgbButtons[2] = 0x00; + queue_event( iface, 5, 0x00, GetCurrentTime(), seq ); + notify = TRUE; break; case WM_XBUTTONDOWN: - inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2 + HIWORD(hook->mouseData)) | DIDFT_PSHBUTTON; - state->rgbButtons[2 + HIWORD( hook->mouseData )] = wdata = 0x80; + state->rgbButtons[2 + HIWORD( hook->mouseData )] = 0x80; + queue_event( iface, 5 + HIWORD(hook->mouseData), 0x80, GetCurrentTime(), seq ); + notify = TRUE; break; case WM_XBUTTONUP: - inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2 + HIWORD(hook->mouseData)) | DIDFT_PSHBUTTON; - state->rgbButtons[2 + HIWORD( hook->mouseData )] = wdata = 0x00; + state->rgbButtons[2 + HIWORD( hook->mouseData )] = 0x00; + queue_event( iface, 5 + HIWORD(hook->mouseData), 0x00, GetCurrentTime(), seq ); + notify = TRUE; break; } - - if (inst_id != -1) - { - queue_event( iface, inst_id, wdata, GetCurrentTime(), impl->base.dinput->evsequence++ ); - notify = TRUE; - } - TRACE( "buttons %02x %02x %02x %02x %02x, x %+ld, y %+ld, w %+ld\n", state->rgbButtons[0], state->rgbButtons[1], state->rgbButtons[2], state->rgbButtons[3], state->rgbButtons[4], state->lX, state->lY, state->lZ ); From 7cc2dcb6a17d444ac3f0df677a7968c2d0efd887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 23 May 2023 11:32:13 +0200 Subject: [PATCH 1345/2777] dinput: Pass additional information to enum_object callback. (cherry picked from commit 1cda1509731a42b6c0913a3eaa47d584135057cb) --- dlls/dinput/device.c | 51 +++++++++++++------ dlls/dinput/device_private.h | 8 ++- dlls/dinput/joystick_hid.c | 96 ++++++++++++++---------------------- dlls/dinput/keyboard.c | 18 +++---- dlls/dinput/mouse.c | 15 +++--- 5 files changed, 97 insertions(+), 91 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index b2487df529b..7fa2a89cf35 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -792,8 +792,22 @@ static ULONG WINAPI dinput_device_AddRef( IDirectInputDevice8W *iface ) return ref; } -static HRESULT WINAPI dinput_device_EnumObjects( IDirectInputDevice8W *iface, - LPDIENUMDEVICEOBJECTSCALLBACKW callback, +struct enum_objects_params +{ + LPDIENUMDEVICEOBJECTSCALLBACKW callback; + void *context; +}; + +static BOOL enum_objects_callback( struct dinput_device *impl, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ) +{ + struct enum_objects_params *params = data; + if (instance->wUsagePage == HID_USAGE_PAGE_PID && !(instance->dwType & DIDFT_NODATA)) + return DIENUM_CONTINUE; + return params->callback( instance, params->context ); +} + +static HRESULT WINAPI dinput_device_EnumObjects( IDirectInputDevice8W *iface, LPDIENUMDEVICEOBJECTSCALLBACKW callback, void *context, DWORD flags ) { static const DIPROPHEADER filter = @@ -802,6 +816,7 @@ static HRESULT WINAPI dinput_device_EnumObjects( IDirectInputDevice8W *iface, .dwHeaderSize = sizeof(filter), .dwHow = DIPH_DEVICE, }; + struct enum_objects_params params = {.callback = callback, .context = context}; struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); HRESULT hr; @@ -813,25 +828,25 @@ static HRESULT WINAPI dinput_device_EnumObjects( IDirectInputDevice8W *iface, if (flags == DIDFT_ALL || (flags & DIDFT_AXIS)) { - hr = impl->vtbl->enum_objects( iface, &filter, DIDFT_AXIS, callback, context ); + hr = impl->vtbl->enum_objects( iface, &filter, DIDFT_AXIS, enum_objects_callback, ¶ms ); if (FAILED(hr)) return hr; if (hr != DIENUM_CONTINUE) return DI_OK; } if (flags == DIDFT_ALL || (flags & DIDFT_POV)) { - hr = impl->vtbl->enum_objects( iface, &filter, DIDFT_POV, callback, context ); + hr = impl->vtbl->enum_objects( iface, &filter, DIDFT_POV, enum_objects_callback, ¶ms ); if (FAILED(hr)) return hr; if (hr != DIENUM_CONTINUE) return DI_OK; } if (flags == DIDFT_ALL || (flags & DIDFT_BUTTON)) { - hr = impl->vtbl->enum_objects( iface, &filter, DIDFT_BUTTON, callback, context ); + hr = impl->vtbl->enum_objects( iface, &filter, DIDFT_BUTTON, enum_objects_callback, ¶ms ); if (FAILED(hr)) return hr; if (hr != DIENUM_CONTINUE) return DI_OK; } if (flags == DIDFT_ALL || (flags & (DIDFT_NODATA | DIDFT_COLLECTION))) { - hr = impl->vtbl->enum_objects( iface, &filter, DIDFT_NODATA, callback, context ); + hr = impl->vtbl->enum_objects( iface, &filter, DIDFT_NODATA, enum_objects_callback, ¶ms ); if (FAILED(hr)) return hr; if (hr != DIENUM_CONTINUE) return DI_OK; } @@ -1045,9 +1060,10 @@ static HRESULT check_property( struct dinput_device *impl, const GUID *guid, con return DI_OK; } -static BOOL CALLBACK find_object( const DIDEVICEOBJECTINSTANCEW *instance, void *context ) +static BOOL find_object( struct dinput_device *device, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { - *(DIDEVICEOBJECTINSTANCEW *)context = *instance; + *(DIDEVICEOBJECTINSTANCEW *)data = *instance; return DIENUM_STOP; } @@ -1058,7 +1074,8 @@ struct get_object_property_params DWORD property; }; -static BOOL CALLBACK get_object_property( const DIDEVICEOBJECTINSTANCEW *instance, void *context ) +static BOOL get_object_property( struct dinput_device *device, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { static const struct object_properties default_properties = { @@ -1066,7 +1083,7 @@ static BOOL CALLBACK get_object_property( const DIDEVICEOBJECTINSTANCEW *instanc .range_max = DIPROPRANGE_NOMAX, .granularity = 1, }; - struct get_object_property_params *params = context; + struct get_object_property_params *params = data; struct dinput_device *impl = impl_from_IDirectInputDevice8W( params->iface ); const struct object_properties *properties = NULL; @@ -1235,9 +1252,10 @@ struct set_object_property_params DWORD property; }; -static BOOL CALLBACK set_object_property( const DIDEVICEOBJECTINSTANCEW *instance, void *context ) +static BOOL set_object_property( struct dinput_device *device, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { - struct set_object_property_params *params = context; + struct set_object_property_params *params = data; struct dinput_device *impl = impl_from_IDirectInputDevice8W( params->iface ); struct object_properties *properties = NULL; @@ -1276,9 +1294,9 @@ static BOOL CALLBACK set_object_property( const DIDEVICEOBJECTINSTANCEW *instanc return DIENUM_STOP; } -static BOOL CALLBACK reset_object_value( const DIDEVICEOBJECTINSTANCEW *instance, void *context ) +static BOOL reset_object_value( struct dinput_device *impl, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *context ) { - struct dinput_device *impl = context; struct object_properties *properties; LONG tmp = -1; @@ -1445,7 +1463,8 @@ static void dinput_device_set_username( struct dinput_device *impl, const DIPROP lstrcpynW( device_player->username, value->wsz, ARRAY_SIZE(device_player->username) ); } -static BOOL CALLBACK get_object_info( const DIDEVICEOBJECTINSTANCEW *instance, void *data ) +static BOOL get_object_info( struct dinput_device *device, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { DIDEVICEOBJECTINSTANCEW *dest = data; DWORD size = dest->dwSize; @@ -2194,7 +2213,7 @@ static BOOL CALLBACK enum_objects_init( const DIDEVICEOBJECTINSTANCEW *instance, } if (impl->object_properties && (instance->dwType & (DIDFT_AXIS | DIDFT_POV))) - reset_object_value( instance, impl ); + reset_object_value( impl, format->dwNumObjs, NULL, instance, NULL ); format->dwNumObjs++; return DIENUM_CONTINUE; diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h index b044c52ba36..65453f6313d 100644 --- a/dlls/dinput/device_private.h +++ b/dlls/dinput/device_private.h @@ -34,6 +34,12 @@ typedef struct UINT_PTR uAppData; } ActionMap; +struct dinput_device; +struct hid_value_caps; + +typedef BOOL (*enum_object_callback)( struct dinput_device *impl, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ); + struct dinput_device_vtbl { void (*destroy)( IDirectInputDevice8W *iface ); @@ -42,7 +48,7 @@ struct dinput_device_vtbl HRESULT (*acquire)( IDirectInputDevice8W *iface ); HRESULT (*unacquire)( IDirectInputDevice8W *iface ); HRESULT (*enum_objects)( IDirectInputDevice8W *iface, const DIPROPHEADER *filter, DWORD flags, - LPDIENUMDEVICEOBJECTSCALLBACKW callback, void *context ); + enum_object_callback callback, void *context ); HRESULT (*get_property)( IDirectInputDevice8W *iface, DWORD property, DIPROPHEADER *header, const DIDEVICEOBJECTINSTANCEW *instance ); HRESULT (*get_effect_info)( IDirectInputDevice8W *iface, DIEFFECTINFOW *info, const GUID *guid ); diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 95e6f8eff86..6f13d23228c 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -482,11 +482,8 @@ static HRESULT find_next_effect_id( struct hid_joystick *impl, ULONG *index, USA return DI_OK; } -typedef BOOL (*enum_object_callback)( struct hid_joystick *impl, struct hid_value_caps *caps, - DIDEVICEOBJECTINSTANCEW *instance, void *data ); - static BOOL enum_object( struct hid_joystick *impl, const DIPROPHEADER *filter, DWORD flags, - enum_object_callback callback, struct hid_value_caps *caps, + enum_object_callback callback, UINT index, struct hid_value_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data ) { if (flags != DIDFT_ALL && !(flags & DIDFT_GETTYPE( instance->dwType ))) return DIENUM_CONTINUE; @@ -494,17 +491,17 @@ static BOOL enum_object( struct hid_joystick *impl, const DIPROPHEADER *filter, switch (filter->dwHow) { case DIPH_DEVICE: - return callback( impl, caps, instance, data ); + return callback( &impl->base, index, caps, instance, data ); case DIPH_BYOFFSET: if (filter->dwObj != instance->dwOfs) return DIENUM_CONTINUE; - return callback( impl, caps, instance, data ); + return callback( &impl->base, index, caps, instance, data ); case DIPH_BYID: if ((filter->dwObj & 0x00ffffff) != (instance->dwType & 0x00ffffff)) return DIENUM_CONTINUE; - return callback( impl, caps, instance, data ); + return callback( &impl->base, index, caps, instance, data ); case DIPH_BYUSAGE: if (HIWORD( filter->dwObj ) != instance->wUsagePage) return DIENUM_CONTINUE; if (LOWORD( filter->dwObj ) != instance->wUsage) return DIENUM_CONTINUE; - return callback( impl, caps, instance, data ); + return callback( &impl->base, index, caps, instance, data ); default: FIXME( "unimplemented filter dwHow %#lx dwObj %#lx\n", filter->dwHow, filter->dwObj ); break; @@ -659,7 +656,7 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, else if ((tmp = object_usage_to_string( &instance ))) lstrcpynW( instance.tszName, tmp, MAX_PATH ); else swprintf( instance.tszName, MAX_PATH, L"Unknown %u", DIDFT_GETINSTANCE( instance.dwType ) ); check_pid_effect_axis_caps( impl, &instance ); - ret = enum_object( impl, filter, flags, callback, caps, &instance, data ); + ret = enum_object( impl, filter, flags, callback, object, caps, &instance, data ); if (ret != DIENUM_CONTINUE) return ret; value_ofs += sizeof(LONG); object++; @@ -694,7 +691,7 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, instance.dwDimension = caps->units; instance.wExponent = caps->units_exp; swprintf( instance.tszName, MAX_PATH, L"Button %u", DIDFT_GETINSTANCE( instance.dwType ) ); - ret = enum_object( impl, filter, flags, callback, caps, &instance, data ); + ret = enum_object( impl, filter, flags, callback, object, caps, &instance, data ); if (ret != DIENUM_CONTINUE) return ret; button_ofs++; object++; @@ -733,7 +730,7 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, instance.wExponent = caps->units_exp; if ((tmp = object_usage_to_string( &instance ))) lstrcpynW( instance.tszName, tmp, MAX_PATH ); else swprintf( instance.tszName, MAX_PATH, L"Unknown %u", DIDFT_GETINSTANCE( instance.dwType ) ); - ret = enum_object( impl, filter, flags, callback, nary, &instance, data ); + ret = enum_object( impl, filter, flags, callback, -1, nary, &instance, data ); if (ret != DIENUM_CONTINUE) return ret; button_ofs++; } @@ -755,7 +752,7 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, instance.wExponent = caps->units_exp; if ((tmp = object_usage_to_string( &instance ))) lstrcpynW( instance.tszName, tmp, MAX_PATH ); else swprintf( instance.tszName, MAX_PATH, L"Unknown %u", DIDFT_GETINSTANCE( instance.dwType ) ); - ret = enum_object( impl, filter, flags, callback, caps, &instance, data ); + ret = enum_object( impl, filter, flags, callback, -1, caps, &instance, data ); if (ret != DIENUM_CONTINUE) return ret; if (caps->flags & HID_VALUE_CAPS_IS_BUTTON) button_ofs++; @@ -782,7 +779,7 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, len = swprintf( instance.tszName, MAX_PATH, L"Collection %u - ", DIDFT_GETINSTANCE( instance.dwType ) ); if ((tmp = object_usage_to_string( &instance ))) lstrcpynW( instance.tszName + len, tmp, MAX_PATH - len ); else swprintf( instance.tszName + len, MAX_PATH - len, L"Unknown %u", DIDFT_GETINSTANCE( instance.dwType ) ); - ret = enum_object( impl, filter, flags, callback, NULL, &instance, data ); + ret = enum_object( impl, filter, flags, callback, -1, NULL, &instance, data ); if (ret != DIENUM_CONTINUE) return ret; } } @@ -1147,24 +1144,22 @@ struct parse_device_state_params DWORD seq; }; -static BOOL check_device_state_button( struct hid_joystick *impl, struct hid_value_caps *caps, - DIDEVICEOBJECTINSTANCEW *instance, void *data ) +static BOOL check_device_state_button( struct dinput_device *device, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { - IDirectInputDevice8W *iface = &impl->base.IDirectInputDevice8W_iface; + IDirectInputDevice8W *iface = &device->IDirectInputDevice8W_iface; struct parse_device_state_params *params = data; BYTE old_value, value; - int index; - if (instance->wReportId != impl->base.device_state_report_id) return DIENUM_CONTINUE; + if (instance->wReportId != device->device_state_report_id) return DIENUM_CONTINUE; value = params->buttons[instance->wUsage - 1]; old_value = params->old_state[instance->dwOfs]; if (params->reset_state) value = 0; - impl->base.device_state[instance->dwOfs] = value; - if (old_value != value && (index = dinput_device_object_index_from_id( iface, instance->dwType )) >= 0) - queue_event( iface, index, value, params->time, params->seq ); + device->device_state[instance->dwOfs] = value; + if (old_value != value) queue_event( iface, index, value, params->time, params->seq ); return DIENUM_CONTINUE; } @@ -1224,9 +1219,10 @@ static LONG scale_axis_value( ULONG value, struct object_properties *properties return phy_min + MulDiv( tmp - log_min, phy_max - phy_min, log_max - log_min ); } -static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_value_caps *caps, - DIDEVICEOBJECTINSTANCEW *instance, void *data ) +static BOOL read_device_state_value( struct dinput_device *device, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { + struct hid_joystick *impl = CONTAINING_RECORD( device, struct hid_joystick, base ); struct object_properties *properties = impl->base.object_properties + instance->dwOfs / sizeof(LONG); IDirectInputDevice8W *iface = &impl->base.IDirectInputDevice8W_iface; ULONG logical_value, report_len = impl->caps.InputReportByteLength; @@ -1234,7 +1230,6 @@ static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_value char *report_buf = impl->input_report_buf; LONG old_value, value; NTSTATUS status; - int index; if (instance->wReportId != impl->base.device_state_report_id) return DIENUM_CONTINUE; @@ -1257,8 +1252,7 @@ static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_value old_value = *(LONG *)(params->old_state + instance->dwOfs); *(LONG *)(impl->base.device_state + instance->dwOfs) = value; - if (old_value != value && (index = dinput_device_object_index_from_id( iface, instance->dwType )) >= 0) - queue_event( iface, index, value, params->time, params->seq ); + if (old_value != value) queue_event( iface, index, value, params->time, params->seq ); return DIENUM_CONTINUE; } @@ -1394,27 +1388,11 @@ static HRESULT hid_joystick_read( IDirectInputDevice8W *iface ) return hr; } -struct enum_objects_params -{ - LPDIENUMDEVICEOBJECTSCALLBACKW callback; - void *context; -}; - -static BOOL enum_objects_callback( struct hid_joystick *impl, struct hid_value_caps *caps, - DIDEVICEOBJECTINSTANCEW *instance, void *data ) -{ - struct enum_objects_params *params = data; - if (instance->wUsagePage == HID_USAGE_PAGE_PID && !(instance->dwType & DIDFT_NODATA)) - return DIENUM_CONTINUE; - return params->callback( instance, params->context ); -} - static HRESULT hid_joystick_enum_objects( IDirectInputDevice8W *iface, const DIPROPHEADER *filter, - DWORD flags, LPDIENUMDEVICEOBJECTSCALLBACKW callback, void *context ) + DWORD flags, enum_object_callback callback, void *context ) { - struct enum_objects_params params = {.callback = callback, .context = context}; struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface ); - return enum_objects( impl, filter, flags, enum_objects_callback, ¶ms ); + return enum_objects( impl, filter, flags, callback, context ); } static const struct dinput_device_vtbl hid_joystick_vtbl = @@ -1730,10 +1708,10 @@ HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *in return DI_OK; } -static BOOL init_object_properties( struct hid_joystick *impl, struct hid_value_caps *caps, - DIDEVICEOBJECTINSTANCEW *instance, void *data ) +static BOOL init_object_properties( struct dinput_device *device, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { - struct object_properties *properties = impl->base.object_properties + instance->dwOfs / sizeof(LONG); + struct object_properties *properties = device->object_properties + instance->dwOfs / sizeof(LONG); LONG tmp; properties->bit_size = caps->bit_size; @@ -1755,9 +1733,10 @@ static BOOL init_object_properties( struct hid_joystick *impl, struct hid_value_ return DIENUM_CONTINUE; } -static BOOL init_pid_reports( struct hid_joystick *impl, struct hid_value_caps *caps, - DIDEVICEOBJECTINSTANCEW *instance, void *data ) +static BOOL init_pid_reports( struct dinput_device *device, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { + struct hid_joystick *impl = CONTAINING_RECORD( device, struct hid_joystick, base ); struct pid_set_constant_force *set_constant_force = &impl->pid_set_constant_force; struct pid_set_ramp_force *set_ramp_force = &impl->pid_set_ramp_force; struct pid_control_report *device_control = &impl->pid_device_control; @@ -1829,9 +1808,10 @@ static BOOL init_pid_reports( struct hid_joystick *impl, struct hid_value_caps * return DIENUM_CONTINUE; } -static BOOL init_pid_caps( struct hid_joystick *impl, struct hid_value_caps *caps, - DIDEVICEOBJECTINSTANCEW *instance, void *data ) +static BOOL init_pid_caps( struct dinput_device *device, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { + struct hid_joystick *impl = CONTAINING_RECORD( device, struct hid_joystick, base ); struct pid_set_constant_force *set_constant_force = &impl->pid_set_constant_force; struct pid_set_ramp_force *set_ramp_force = &impl->pid_set_ramp_force; struct pid_control_report *device_control = &impl->pid_device_control; @@ -2324,17 +2304,17 @@ static HRESULT WINAPI hid_joystick_effect_GetEffectGuid( IDirectInputEffect *ifa return DI_OK; } -static BOOL get_parameters_object_id( struct hid_joystick *impl, struct hid_value_caps *caps, - DIDEVICEOBJECTINSTANCEW *instance, void *data ) +static BOOL get_parameters_object_id( struct dinput_device *device, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { *(DWORD *)data = instance->dwType; return DIENUM_STOP; } -static BOOL get_parameters_object_ofs( struct hid_joystick *impl, struct hid_value_caps *caps, - DIDEVICEOBJECTINSTANCEW *instance, void *data ) +static BOOL get_parameters_object_ofs( struct dinput_device *device, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { - DIDATAFORMAT *device_format = &impl->base.device_format, *user_format = &impl->base.user_format; + DIDATAFORMAT *device_format = &device->device_format, *user_format = &device->user_format; DIOBJECTDATAFORMAT *device_obj, *user_obj; if (!user_format->rgodf) return DIENUM_CONTINUE; @@ -2585,8 +2565,8 @@ static HRESULT WINAPI hid_joystick_effect_GetParameters( IDirectInputEffect *ifa return DI_OK; } -static BOOL set_parameters_object( struct hid_joystick *impl, struct hid_value_caps *caps, - DIDEVICEOBJECTINSTANCEW *instance, void *data ) +static BOOL set_parameters_object( struct dinput_device *device, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { DWORD usages = MAKELONG( instance->wUsage, instance->wUsagePage ); *(DWORD *)data = usages; diff --git a/dlls/dinput/keyboard.c b/dlls/dinput/keyboard.c index 73d369b3b5d..0dfc909585a 100644 --- a/dlls/dinput/keyboard.c +++ b/dlls/dinput/keyboard.c @@ -228,28 +228,28 @@ static HRESULT keyboard_unacquire( IDirectInputDevice8W *iface ) return DI_OK; } -static BOOL try_enum_object( const DIPROPHEADER *filter, DWORD flags, LPDIENUMDEVICEOBJECTSCALLBACKW callback, - DIDEVICEOBJECTINSTANCEW *instance, void *data ) +static BOOL try_enum_object( struct dinput_device *impl, const DIPROPHEADER *filter, DWORD flags, enum_object_callback callback, + UINT index, DIDEVICEOBJECTINSTANCEW *instance, void *data ) { if (flags != DIDFT_ALL && !(flags & DIDFT_GETTYPE( instance->dwType ))) return DIENUM_CONTINUE; switch (filter->dwHow) { case DIPH_DEVICE: - return callback( instance, data ); + return callback( impl, index, NULL, instance, data ); case DIPH_BYOFFSET: if (filter->dwObj != instance->dwOfs) return DIENUM_CONTINUE; - return callback( instance, data ); + return callback( impl, index, NULL, instance, data ); case DIPH_BYID: if ((filter->dwObj & 0x00ffffff) != (instance->dwType & 0x00ffffff)) return DIENUM_CONTINUE; - return callback( instance, data ); + return callback( impl, index, NULL, instance, data ); } return DIENUM_CONTINUE; } static HRESULT keyboard_enum_objects( IDirectInputDevice8W *iface, const DIPROPHEADER *filter, - DWORD flags, LPDIENUMDEVICEOBJECTSCALLBACKW callback, void *context ) + DWORD flags, enum_object_callback callback, void *context ) { struct keyboard *impl = impl_from_IDirectInputDevice8W( iface ); BYTE subtype = GET_DIDEVICE_SUBTYPE( impl->base.instance.dwDevType ); @@ -260,16 +260,16 @@ static HRESULT keyboard_enum_objects( IDirectInputDevice8W *iface, const DIPROPH .dwOfs = DIK_ESCAPE, .dwType = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( DIK_ESCAPE ), }; - DWORD i, dik; + DWORD index, i, dik; BOOL ret; - for (i = 0; i < 512; ++i) + for (i = 0, index = 0; i < 512; ++i) { if (!GetKeyNameTextW( i << 16, instance.tszName, ARRAY_SIZE(instance.tszName) )) continue; if (!(dik = map_dik_code( i, 0, subtype, impl->base.dinput->dwVersion ))) continue; instance.dwOfs = dik; instance.dwType = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( dik ); - ret = try_enum_object( filter, flags, callback, &instance, context ); + ret = try_enum_object( &impl->base, filter, flags, callback, index++, &instance, context ); if (ret != DIENUM_CONTINUE) return DIENUM_STOP; } diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c index 8e852907d11..9b1bf74b8d5 100644 --- a/dlls/dinput/mouse.c +++ b/dlls/dinput/mouse.c @@ -456,29 +456,30 @@ static HRESULT mouse_unacquire( IDirectInputDevice8W *iface ) return DI_OK; } -static BOOL try_enum_object( const DIPROPHEADER *filter, DWORD flags, LPDIENUMDEVICEOBJECTSCALLBACKW callback, - DIDEVICEOBJECTINSTANCEW *instance, void *data ) +static BOOL try_enum_object( struct dinput_device *impl, const DIPROPHEADER *filter, DWORD flags, enum_object_callback callback, + UINT index, DIDEVICEOBJECTINSTANCEW *instance, void *data ) { if (flags != DIDFT_ALL && !(flags & DIDFT_GETTYPE( instance->dwType ))) return DIENUM_CONTINUE; switch (filter->dwHow) { case DIPH_DEVICE: - return callback( instance, data ); + return callback( impl, index, NULL, instance, data ); case DIPH_BYOFFSET: if (filter->dwObj != instance->dwOfs) return DIENUM_CONTINUE; - return callback( instance, data ); + return callback( impl, index, NULL, instance, data ); case DIPH_BYID: if ((filter->dwObj & 0x00ffffff) != (instance->dwType & 0x00ffffff)) return DIENUM_CONTINUE; - return callback( instance, data ); + return callback( impl, index, NULL, instance, data ); } return DIENUM_CONTINUE; } static HRESULT mouse_enum_objects( IDirectInputDevice8W *iface, const DIPROPHEADER *filter, - DWORD flags, LPDIENUMDEVICEOBJECTSCALLBACKW callback, void *context ) + DWORD flags, enum_object_callback callback, void *context ) { + struct mouse *impl = impl_from_IDirectInputDevice8W( iface ); DIDEVICEOBJECTINSTANCEW instances[] = { { @@ -546,7 +547,7 @@ static HRESULT mouse_enum_objects( IDirectInputDevice8W *iface, const DIPROPHEAD for (i = 0; i < ARRAY_SIZE(instances); ++i) { - ret = try_enum_object( filter, flags, callback, instances + i, context ); + ret = try_enum_object( &impl->base, filter, flags, callback, i, instances + i, context ); if (ret != DIENUM_CONTINUE) return DIENUM_STOP; } From 1c89228dec9d228c255e6ec4ec0627ef35a44966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 19 Mar 2023 14:48:18 +0100 Subject: [PATCH 1346/2777] dinput: Split enum_objects_count helper from enum_objects_init. (cherry picked from commit 570e183b4153db8e701ea1ed1c6ec468b527cb4d) --- dlls/dinput/device.c | 50 ++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 7fa2a89cf35..df19f615a55 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -2183,35 +2183,39 @@ static const GUID *object_instance_guid( const DIDEVICEOBJECTINSTANCEW *instance return &GUID_Unknown; } -static BOOL CALLBACK enum_objects_init( const DIDEVICEOBJECTINSTANCEW *instance, void *data ) +static BOOL CALLBACK enum_objects_count( const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { struct dinput_device *impl = impl_from_IDirectInputDevice8W( data ); DIDATAFORMAT *format = &impl->device_format; - DIOBJECTDATAFORMAT *obj_format; - if (!format->rgodf) + format->dwDataSize = max( format->dwDataSize, instance->dwOfs + sizeof(LONG) ); + if (instance->dwType & DIDFT_BUTTON) impl->caps.dwButtons++; + if (instance->dwType & DIDFT_AXIS) impl->caps.dwAxes++; + if (instance->dwType & DIDFT_POV) impl->caps.dwPOVs++; + if (instance->dwType & (DIDFT_BUTTON|DIDFT_AXIS|DIDFT_POV)) { - format->dwDataSize = max( format->dwDataSize, instance->dwOfs + sizeof(LONG) ); - if (instance->dwType & DIDFT_BUTTON) impl->caps.dwButtons++; - if (instance->dwType & DIDFT_AXIS) impl->caps.dwAxes++; - if (instance->dwType & DIDFT_POV) impl->caps.dwPOVs++; - if (instance->dwType & (DIDFT_BUTTON|DIDFT_AXIS|DIDFT_POV)) - { - if (!impl->device_state_report_id) - impl->device_state_report_id = instance->wReportId; - else if (impl->device_state_report_id != instance->wReportId) - FIXME( "multiple device state reports found!\n" ); - } - } - else - { - obj_format = format->rgodf + format->dwNumObjs; - obj_format->pguid = object_instance_guid( instance ); - obj_format->dwOfs = instance->dwOfs; - obj_format->dwType = instance->dwType; - obj_format->dwFlags = instance->dwFlags; + if (!impl->device_state_report_id) + impl->device_state_report_id = instance->wReportId; + else if (impl->device_state_report_id != instance->wReportId) + FIXME( "multiple device state reports found!\n" ); } + format->dwNumObjs++; + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK enum_objects_init( const DIDEVICEOBJECTINSTANCEW *instance, void *data ) +{ + struct dinput_device *impl = impl_from_IDirectInputDevice8W( data ); + DIDATAFORMAT *format = &impl->device_format; + DIOBJECTDATAFORMAT *object_format; + + object_format = format->rgodf + format->dwNumObjs; + object_format->pguid = object_instance_guid( instance ); + object_format->dwOfs = instance->dwOfs; + object_format->dwType = instance->dwType; + object_format->dwFlags = instance->dwFlags; + if (impl->object_properties && (instance->dwType & (DIDFT_AXIS | DIDFT_POV))) reset_object_value( impl, format->dwNumObjs, NULL, instance, NULL ); @@ -2225,7 +2229,7 @@ HRESULT dinput_device_init_device_format( IDirectInputDevice8W *iface ) DIDATAFORMAT *format = &impl->device_format; ULONG i, size; - IDirectInputDevice8_EnumObjects( iface, enum_objects_init, iface, DIDFT_ALL ); + IDirectInputDevice8_EnumObjects( iface, enum_objects_count, iface, DIDFT_ALL ); if (format->dwDataSize > DEVICE_STATE_MAX_SIZE) { FIXME( "unable to create device, state is too large\n" ); From bcb73853a4f93cb5384f85f757cafff75d1802fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 20 Mar 2023 08:38:53 +0100 Subject: [PATCH 1347/2777] dinput: Call enum_objects to initialize the device object format. (cherry picked from commit 44cb6c8444e8b0030b80c6b7953e9fc9f460461d) --- dlls/dinput/device.c | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index df19f615a55..407e4f52a38 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -2183,11 +2183,15 @@ static const GUID *object_instance_guid( const DIDEVICEOBJECTINSTANCEW *instance return &GUID_Unknown; } -static BOOL CALLBACK enum_objects_count( const DIDEVICEOBJECTINSTANCEW *instance, void *data ) +static BOOL enum_objects_count( struct dinput_device *impl, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { - struct dinput_device *impl = impl_from_IDirectInputDevice8W( data ); DIDATAFORMAT *format = &impl->device_format; + if (index == -1) return DIENUM_STOP; + format->dwNumObjs++; + if (instance->wUsagePage == HID_USAGE_PAGE_PID) return DIENUM_CONTINUE; + format->dwDataSize = max( format->dwDataSize, instance->dwOfs + sizeof(LONG) ); if (instance->dwType & DIDFT_BUTTON) impl->caps.dwButtons++; if (instance->dwType & DIDFT_AXIS) impl->caps.dwAxes++; @@ -2200,36 +2204,46 @@ static BOOL CALLBACK enum_objects_count( const DIDEVICEOBJECTINSTANCEW *instance FIXME( "multiple device state reports found!\n" ); } - format->dwNumObjs++; return DIENUM_CONTINUE; } -static BOOL CALLBACK enum_objects_init( const DIDEVICEOBJECTINSTANCEW *instance, void *data ) +static BOOL enum_objects_init( struct dinput_device *impl, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { - struct dinput_device *impl = impl_from_IDirectInputDevice8W( data ); DIDATAFORMAT *format = &impl->device_format; DIOBJECTDATAFORMAT *object_format; - object_format = format->rgodf + format->dwNumObjs; + if (index == -1) return DIENUM_STOP; + if (instance->wUsagePage == HID_USAGE_PAGE_PID) return DIENUM_CONTINUE; + + object_format = format->rgodf + index; object_format->pguid = object_instance_guid( instance ); object_format->dwOfs = instance->dwOfs; object_format->dwType = instance->dwType; object_format->dwFlags = instance->dwFlags; if (impl->object_properties && (instance->dwType & (DIDFT_AXIS | DIDFT_POV))) - reset_object_value( impl, format->dwNumObjs, NULL, instance, NULL ); + reset_object_value( impl, index, caps, instance, NULL ); - format->dwNumObjs++; return DIENUM_CONTINUE; } HRESULT dinput_device_init_device_format( IDirectInputDevice8W *iface ) { + static const DIPROPHEADER filter = + { + .dwSize = sizeof(filter), + .dwHeaderSize = sizeof(filter), + .dwHow = DIPH_DEVICE, + }; struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); DIDATAFORMAT *format = &impl->device_format; ULONG i, size; + HRESULT hr; + + hr = impl->vtbl->enum_objects( iface, &filter, DIDFT_ALL, enum_objects_count, NULL ); + if (FAILED(hr)) return hr; - IDirectInputDevice8_EnumObjects( iface, enum_objects_count, iface, DIDFT_ALL ); if (format->dwDataSize > DEVICE_STATE_MAX_SIZE) { FIXME( "unable to create device, state is too large\n" ); @@ -2242,8 +2256,15 @@ HRESULT dinput_device_init_device_format( IDirectInputDevice8W *iface ) format->dwSize = sizeof(*format); format->dwObjSize = sizeof(*format->rgodf); format->dwFlags = DIDF_ABSAXIS; - format->dwNumObjs = 0; - IDirectInputDevice8_EnumObjects( iface, enum_objects_init, iface, DIDFT_ALL ); + + hr = impl->vtbl->enum_objects( iface, &filter, DIDFT_AXIS, enum_objects_init, NULL ); + if (FAILED(hr)) return hr; + hr = impl->vtbl->enum_objects( iface, &filter, DIDFT_POV, enum_objects_init, NULL ); + if (FAILED(hr)) return hr; + hr = impl->vtbl->enum_objects( iface, &filter, DIDFT_BUTTON, enum_objects_init, NULL ); + if (FAILED(hr)) return hr; + hr = impl->vtbl->enum_objects( iface, &filter, DIDFT_NODATA, enum_objects_init, NULL ); + if (FAILED(hr)) return hr; if (TRACE_ON( dinput )) { From 2e9b9a40f2563c14a4069bc6f66ee9c8645b2565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Mar 2023 13:29:28 +0100 Subject: [PATCH 1348/2777] dinput/tests: Flush messages after creating the test_mouse_keyboard window. Preventing spurious failures on some Windows 7 VMs. Wine-Bug: https://bugs.winehq.org//show_bug.cgi?id=54713 (cherry picked from commit 01e4c4335a981f420218b5fb68fb405f289e7b67) --- dlls/dinput/tests/device8.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/dinput/tests/device8.c b/dlls/dinput/tests/device8.c index e8a61968127..841473085f6 100644 --- a/dlls/dinput/tests/device8.c +++ b/dlls/dinput/tests/device8.c @@ -546,6 +546,7 @@ static void test_mouse_keyboard(void) hwnd = CreateWindowExA(WS_EX_TOPMOST, "static", "dinput", WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL); ok(hwnd != NULL, "CreateWindowExA failed\n"); + flush_events(); hr = CoCreateInstance(&CLSID_DirectInput8, 0, CLSCTX_INPROC_SERVER, &IID_IDirectInput8A, (LPVOID*)&di); if (hr == DIERR_OLDDIRECTINPUTVERSION || From 524a5af78872031bd4f33902f6c636c22061ec10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Mar 2023 14:26:32 +0100 Subject: [PATCH 1349/2777] dinput: Count the actual number of object formats in SetActionMap. Fixes crash introduced by 7b3f3d60782c63edd621353a635616f4cea029da, as SetActionMap is now called with unsupposed flags from the tests and skips some objects. (cherry picked from commit b75bd86ebd21c00c59ab689d170bd61dc1a30cf4) --- dlls/dinput/device.c | 3 ++- dlls/dinput/tests/joystick8.c | 18 ++++++------------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 407e4f52a38..3b3912ce9d2 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -2028,7 +2028,7 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D /* Construct the dataformat and actionmap */ obj_df = malloc( sizeof(DIOBJECTDATAFORMAT) * num_actions ); data_format.rgodf = (LPDIOBJECTDATAFORMAT)obj_df; - data_format.dwNumObjs = num_actions; + data_format.dwNumObjs = 0; action_map = malloc( sizeof(ActionMap) * num_actions ); @@ -2051,6 +2051,7 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D action_map[action].offset = offset; obj_df[action].dwOfs = offset; offset += (type & DIDFT_BUTTON) ? 1 : 4; + data_format.dwNumObjs++; action++; } diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 93cd3e9f09f..64225bf93a3 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -1031,9 +1031,7 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e hr = IDirectInputDevice8_Acquire( device ); - todo_wine ok( hr == DI_OK, "Acquire returned: %#lx\n", hr ); - if (hr != DI_OK) goto skip_input; hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_DEFAULT ); ok( hr == DIERR_ACQUIRED, "SetActionMap returned %#lx\n", hr ); @@ -1045,7 +1043,6 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e send_hid_input( file, &injected_input[0], sizeof(*injected_input) ); res = WaitForSingleObject( event, 100 ); } - todo_wine ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); for (i = 0; i < ARRAY_SIZE(injected_input); ++i) @@ -1053,11 +1050,10 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e winetest_push_context( "state[%ld]", i ); hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), state ); - todo_wine ok( hr == DI_OK, "GetDeviceState returned: %#lx\n", hr ); - todo_wine_if( expect_state[i][0] ) + todo_wine ok( state[0] == expect_state[i][0], "got state[0] %+ld\n", state[0] ); - todo_wine_if( expect_state[i][1] ) + todo_wine_if( i != 2 ) ok( state[1] == expect_state[i][1], "got state[1] %+ld\n", state[1] ); todo_wine_if( expect_state[i][2] ) ok( state[2] == expect_state[i][2], "got state[2] %+ld\n", state[2] ); @@ -1078,7 +1074,7 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e res = WaitForSingleObject( event, 100 ); if (i == 0 || i == 3) ok( res == WAIT_TIMEOUT, "WaitForSingleObject succeeded\n" ); - else todo_wine ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); + else ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); ResetEvent( event ); winetest_pop_context(); } @@ -1091,23 +1087,21 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e while (res--) { winetest_push_context( "%lu", res ); - todo_wine_if( expect_objdata[res].dwOfs ) + todo_wine check_member( objdata[res], expect_objdata[res], "%#lx", dwOfs ); - todo_wine_if( expect_objdata[res].dwData ) + todo_wine_if( res == 0 || res == 3 || res == 6 ) ok( objdata[res].dwData == expect_objdata[res].dwData || broken(objdata[res].dwData == -45 && expect_objdata[res].dwData == -43) /* 32-bit rounding */, "got dwData %+ld\n", objdata[res].dwData ); - todo_wine + todo_wine_if( res != 1 && res != 4 ) check_member( objdata[res], expect_objdata[res], "%#Ix", uAppData ); winetest_pop_context(); } -skip_input: hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); hr = IDirectInputDevice8_Unacquire( device ); - todo_wine ok( hr == DI_OK, "Acquire returned: %#lx\n", hr ); From f1c76bed397226cb5f4c2b6c82db643dd29e945f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 20 Mar 2023 10:13:15 +0100 Subject: [PATCH 1350/2777] dinput: Initialize device object format when creating devices. (cherry picked from commit 256f35dc42688d983d72ebc636ca0974e64ce0cf) --- dlls/dinput/dinput.c | 6 ------ dlls/dinput/joystick_hid.c | 14 ++++++++------ dlls/dinput/keyboard.c | 9 +++++++-- dlls/dinput/mouse.c | 11 ++++++++--- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/dlls/dinput/dinput.c b/dlls/dinput/dinput.c index db367e1f1ba..998573ad20d 100644 --- a/dlls/dinput/dinput.c +++ b/dlls/dinput/dinput.c @@ -299,12 +299,6 @@ static HRESULT WINAPI dinput7_CreateDeviceEx( IDirectInput7W *iface, const GUID if (FAILED(hr)) return hr; - if (FAILED(hr = dinput_device_init_device_format( device ))) - { - IDirectInputDevice8_Release( device ); - return hr; - } - hr = IDirectInputDevice8_QueryInterface( device, iid, out ); IDirectInputDevice8_Release( device ); return hr; diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 6f13d23228c..ca2d9f67684 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -2089,12 +2089,6 @@ HRESULT hid_joystick_create_device( struct dinput *dinput, const GUID *guid, IDi list_init( &impl->effect_list ); hr = E_OUTOFMEMORY; - preparsed = (struct hid_preparsed_data *)impl->preparsed; - size = preparsed->input_caps_count * sizeof(struct object_properties); - if (!(object_properties = calloc( 1, size ))) goto failed; - impl->base.object_properties = object_properties; - enum_objects( impl, &filter, DIDFT_AXIS | DIDFT_POV, init_object_properties, NULL ); - size = impl->caps.InputReportByteLength; if (!(buffer = malloc( size ))) goto failed; impl->input_report_buf = buffer; @@ -2154,6 +2148,14 @@ HRESULT hid_joystick_create_device( struct dinput *dinput, const GUID *guid, IDi impl->base.caps.dwFFDriverVersion = 1; } + preparsed = (struct hid_preparsed_data *)impl->preparsed; + size = preparsed->input_caps_count * sizeof(struct object_properties); + if (!(object_properties = calloc( 1, size ))) goto failed; + impl->base.object_properties = object_properties; + enum_objects( impl, &filter, DIDFT_AXIS | DIDFT_POV, init_object_properties, NULL ); + + if (FAILED(hr = dinput_device_init_device_format( &impl->base.IDirectInputDevice8W_iface ))) goto failed; + *out = &impl->base.IDirectInputDevice8W_iface; return DI_OK; diff --git a/dlls/dinput/keyboard.c b/dlls/dinput/keyboard.c index 0dfc909585a..cbcbf94f0f6 100644 --- a/dlls/dinput/keyboard.c +++ b/dlls/dinput/keyboard.c @@ -188,6 +188,7 @@ HRESULT keyboard_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instan HRESULT keyboard_create_device( struct dinput *dinput, const GUID *guid, IDirectInputDevice8W **out ) { struct keyboard *impl; + HRESULT hr; TRACE( "dinput %p, guid %s, out %p.\n", dinput, debugstr_guid( guid ), out ); @@ -202,12 +203,16 @@ HRESULT keyboard_create_device( struct dinput *dinput, const GUID *guid, IDirect impl->base.caps.dwDevType = impl->base.instance.dwDevType; impl->base.caps.dwFirmwareRevision = 100; impl->base.caps.dwHardwareRevision = 100; + if (dinput->dwVersion >= 0x0800) impl->base.use_raw_input = TRUE; - if (dinput->dwVersion >= 0x0800) - impl->base.use_raw_input = TRUE; + if (FAILED(hr = dinput_device_init_device_format( &impl->base.IDirectInputDevice8W_iface ))) goto failed; *out = &impl->base.IDirectInputDevice8W_iface; return DI_OK; + +failed: + IDirectInputDevice_Release( &impl->base.IDirectInputDevice8W_iface ); + return hr; } static HRESULT keyboard_poll( IDirectInputDevice8W *iface ) diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c index 9b1bf74b8d5..1c2a66e1bfa 100644 --- a/dlls/dinput/mouse.c +++ b/dlls/dinput/mouse.c @@ -107,6 +107,7 @@ HRESULT mouse_create_device( struct dinput *dinput, const GUID *guid, IDirectInp struct mouse *impl; HKEY hkey, appkey; WCHAR buffer[20]; + HRESULT hr; TRACE( "dinput %p, guid %s, out %p\n", dinput, debugstr_guid( guid ), out ); @@ -122,6 +123,7 @@ HRESULT mouse_create_device( struct dinput *dinput, const GUID *guid, IDirectInp impl->base.caps.dwFirmwareRevision = 100; impl->base.caps.dwHardwareRevision = 100; impl->base.dwCoopLevel = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND; + if (dinput->dwVersion >= 0x0800) impl->base.use_raw_input = TRUE; /* One object_properties per axis */ impl->base.object_properties = calloc( 3, sizeof(struct object_properties) ); @@ -132,6 +134,8 @@ HRESULT mouse_create_device( struct dinput *dinput, const GUID *guid, IDirectInp } IDirectInputDevice8_EnumObjects( &impl->base.IDirectInputDevice8W_iface, init_object_properties, impl, DIDFT_RELAXIS ); + if (FAILED(hr = dinput_device_init_device_format( &impl->base.IDirectInputDevice8W_iface ))) goto failed; + get_app_key(&hkey, &appkey); if (!get_config_key( hkey, appkey, L"MouseWarpOverride", buffer, sizeof(buffer) )) { @@ -141,11 +145,12 @@ HRESULT mouse_create_device( struct dinput *dinput, const GUID *guid, IDirectInp if (appkey) RegCloseKey(appkey); if (hkey) RegCloseKey(hkey); - if (dinput->dwVersion >= 0x0800) - impl->base.use_raw_input = TRUE; - *out = &impl->base.IDirectInputDevice8W_iface; return DI_OK; + +failed: + IDirectInputDevice_Release( &impl->base.IDirectInputDevice8W_iface ); + return hr; } void dinput_mouse_rawinput_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lparam, RAWINPUT *ri ) From f098db38ec49550129b51787179443d07d438a1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 20 Mar 2023 10:28:59 +0100 Subject: [PATCH 1351/2777] dinput: Move mouse_create_device function around. (cherry picked from commit f20940693e41942ffdd3e485419518b8ad8d05b3) --- dlls/dinput/mouse.c | 102 ++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c index 1c2a66e1bfa..cb19f5d1850 100644 --- a/dlls/dinput/mouse.c +++ b/dlls/dinput/mouse.c @@ -102,57 +102,6 @@ static BOOL CALLBACK init_object_properties( const DIDEVICEOBJECTINSTANCEW *inst return DIENUM_CONTINUE; } -HRESULT mouse_create_device( struct dinput *dinput, const GUID *guid, IDirectInputDevice8W **out ) -{ - struct mouse *impl; - HKEY hkey, appkey; - WCHAR buffer[20]; - HRESULT hr; - - TRACE( "dinput %p, guid %s, out %p\n", dinput, debugstr_guid( guid ), out ); - - *out = NULL; - if (!IsEqualGUID( &GUID_SysMouse, guid )) return DIERR_DEVICENOTREG; - - if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; - dinput_device_init( &impl->base, &mouse_vtbl, guid, dinput ); - impl->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": struct mouse*->base.crit"); - - mouse_enum_device( 0, 0, &impl->base.instance, dinput->dwVersion ); - impl->base.caps.dwDevType = impl->base.instance.dwDevType; - impl->base.caps.dwFirmwareRevision = 100; - impl->base.caps.dwHardwareRevision = 100; - impl->base.dwCoopLevel = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND; - if (dinput->dwVersion >= 0x0800) impl->base.use_raw_input = TRUE; - - /* One object_properties per axis */ - impl->base.object_properties = calloc( 3, sizeof(struct object_properties) ); - if (!impl->base.object_properties) - { - IDirectInputDevice_Release( &impl->base.IDirectInputDevice8W_iface ); - return E_OUTOFMEMORY; - } - IDirectInputDevice8_EnumObjects( &impl->base.IDirectInputDevice8W_iface, init_object_properties, impl, DIDFT_RELAXIS ); - - if (FAILED(hr = dinput_device_init_device_format( &impl->base.IDirectInputDevice8W_iface ))) goto failed; - - get_app_key(&hkey, &appkey); - if (!get_config_key( hkey, appkey, L"MouseWarpOverride", buffer, sizeof(buffer) )) - { - if (!wcsnicmp( buffer, L"disable", -1 )) impl->warp_override = WARP_DISABLE; - else if (!wcsnicmp( buffer, L"force", -1 )) impl->warp_override = WARP_FORCE_ON; - } - if (appkey) RegCloseKey(appkey); - if (hkey) RegCloseKey(hkey); - - *out = &impl->base.IDirectInputDevice8W_iface; - return DI_OK; - -failed: - IDirectInputDevice_Release( &impl->base.IDirectInputDevice8W_iface ); - return hr; -} - void dinput_mouse_rawinput_hook( IDirectInputDevice8W *iface, WPARAM wparam, LPARAM lparam, RAWINPUT *ri ) { struct mouse *impl = impl_from_IDirectInputDevice8W( iface ); @@ -559,6 +508,57 @@ static HRESULT mouse_enum_objects( IDirectInputDevice8W *iface, const DIPROPHEAD return DIENUM_CONTINUE; } +HRESULT mouse_create_device( struct dinput *dinput, const GUID *guid, IDirectInputDevice8W **out ) +{ + struct mouse *impl; + HKEY hkey, appkey; + WCHAR buffer[20]; + HRESULT hr; + + TRACE( "dinput %p, guid %s, out %p\n", dinput, debugstr_guid( guid ), out ); + + *out = NULL; + if (!IsEqualGUID( &GUID_SysMouse, guid )) return DIERR_DEVICENOTREG; + + if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; + dinput_device_init( &impl->base, &mouse_vtbl, guid, dinput ); + impl->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": struct mouse*->base.crit"); + + mouse_enum_device( 0, 0, &impl->base.instance, dinput->dwVersion ); + impl->base.caps.dwDevType = impl->base.instance.dwDevType; + impl->base.caps.dwFirmwareRevision = 100; + impl->base.caps.dwHardwareRevision = 100; + impl->base.dwCoopLevel = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND; + if (dinput->dwVersion >= 0x0800) impl->base.use_raw_input = TRUE; + + /* One object_properties per axis */ + impl->base.object_properties = calloc( 3, sizeof(struct object_properties) ); + if (!impl->base.object_properties) + { + IDirectInputDevice_Release( &impl->base.IDirectInputDevice8W_iface ); + return E_OUTOFMEMORY; + } + IDirectInputDevice8_EnumObjects( &impl->base.IDirectInputDevice8W_iface, init_object_properties, impl, DIDFT_RELAXIS ); + + if (FAILED(hr = dinput_device_init_device_format( &impl->base.IDirectInputDevice8W_iface ))) goto failed; + + get_app_key(&hkey, &appkey); + if (!get_config_key( hkey, appkey, L"MouseWarpOverride", buffer, sizeof(buffer) )) + { + if (!wcsnicmp( buffer, L"disable", -1 )) impl->warp_override = WARP_DISABLE; + else if (!wcsnicmp( buffer, L"force", -1 )) impl->warp_override = WARP_FORCE_ON; + } + if (appkey) RegCloseKey(appkey); + if (hkey) RegCloseKey(hkey); + + *out = &impl->base.IDirectInputDevice8W_iface; + return DI_OK; + +failed: + IDirectInputDevice_Release( &impl->base.IDirectInputDevice8W_iface ); + return hr; +} + static const struct dinput_device_vtbl mouse_vtbl = { NULL, From 118a0c882ffd6f9ca3cd3cd5dde6f178b416294b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 20 Mar 2023 10:29:17 +0100 Subject: [PATCH 1352/2777] dinput: Always allocate and initialize the object_properties. (cherry picked from commit 80a35fb4238a151feacb4c15adc718fe3d57c107) --- dlls/dinput/device.c | 44 ++++++++++++++++++++------------------ dlls/dinput/joystick_hid.c | 21 +++++++++--------- dlls/dinput/mouse.c | 32 +++++++++++---------------- 3 files changed, 47 insertions(+), 50 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 3b3912ce9d2..af61075eb70 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -1077,18 +1077,12 @@ struct get_object_property_params static BOOL get_object_property( struct dinput_device *device, UINT index, struct hid_value_caps *caps, const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { - static const struct object_properties default_properties = - { - .range_min = DIPROPRANGE_NOMIN, - .range_max = DIPROPRANGE_NOMAX, - .granularity = 1, - }; struct get_object_property_params *params = data; struct dinput_device *impl = impl_from_IDirectInputDevice8W( params->iface ); - const struct object_properties *properties = NULL; + const struct object_properties *properties; - if (!impl->object_properties) properties = &default_properties; - else properties = impl->object_properties + instance->dwOfs / sizeof(LONG); + if (index == -1) return DIENUM_STOP; + properties = impl->object_properties + index; switch (params->property) { @@ -1257,10 +1251,10 @@ static BOOL set_object_property( struct dinput_device *device, UINT index, struc { struct set_object_property_params *params = data; struct dinput_device *impl = impl_from_IDirectInputDevice8W( params->iface ); - struct object_properties *properties = NULL; + struct object_properties *properties; - if (!impl->object_properties) return DIENUM_STOP; - properties = impl->object_properties + instance->dwOfs / sizeof(LONG); + if (index == -1) return DIENUM_STOP; + properties = impl->object_properties + index; switch (params->property) { @@ -1300,13 +1294,15 @@ static BOOL reset_object_value( struct dinput_device *impl, UINT index, struct h struct object_properties *properties; LONG tmp = -1; - if (!impl->object_properties) return DIENUM_STOP; - properties = impl->object_properties + instance->dwOfs / sizeof(LONG); + if (index == -1) return DIENUM_STOP; + properties = impl->object_properties + index; if (instance->dwType & DIDFT_AXIS) { - if (!properties->range_min) tmp = properties->range_max / 2; - else tmp = round( (properties->range_min + properties->range_max) / 2.0 ); + LONG range_min = 0, range_max = 0xfffe; + if (properties->range_min != DIPROPRANGE_NOMIN) range_min = properties->range_min; + if (properties->range_max != DIPROPRANGE_NOMAX) range_max = properties->range_max; + tmp = round( (range_min + range_max) / 2.0 ); } *(LONG *)(impl->device_state + instance->dwOfs) = tmp; @@ -2211,6 +2207,12 @@ static BOOL enum_objects_count( struct dinput_device *impl, UINT index, struct h static BOOL enum_objects_init( struct dinput_device *impl, UINT index, struct hid_value_caps *caps, const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { + static const struct object_properties default_properties = + { + .range_min = DIPROPRANGE_NOMIN, + .range_max = DIPROPRANGE_NOMAX, + .granularity = 1, + }; DIDATAFORMAT *format = &impl->device_format; DIOBJECTDATAFORMAT *object_format; @@ -2223,8 +2225,8 @@ static BOOL enum_objects_init( struct dinput_device *impl, UINT index, struct hi object_format->dwType = instance->dwType; object_format->dwFlags = instance->dwFlags; - if (impl->object_properties && (instance->dwType & (DIDFT_AXIS | DIDFT_POV))) - reset_object_value( impl, index, caps, instance, NULL ); + impl->object_properties[index] = default_properties; + if (instance->dwType & (DIDFT_AXIS | DIDFT_POV)) reset_object_value( impl, index, caps, instance, NULL ); return DIENUM_CONTINUE; } @@ -2239,8 +2241,8 @@ HRESULT dinput_device_init_device_format( IDirectInputDevice8W *iface ) }; struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); DIDATAFORMAT *format = &impl->device_format; - ULONG i, size; HRESULT hr; + ULONG i; hr = impl->vtbl->enum_objects( iface, &filter, DIDFT_ALL, enum_objects_count, NULL ); if (FAILED(hr)) return hr; @@ -2251,8 +2253,8 @@ HRESULT dinput_device_init_device_format( IDirectInputDevice8W *iface ) return DIERR_OUTOFMEMORY; } - size = format->dwNumObjs * sizeof(*format->rgodf); - if (!(format->rgodf = calloc( 1, size ))) return DIERR_OUTOFMEMORY; + if (!(impl->object_properties = calloc( format->dwNumObjs, sizeof(*impl->object_properties) ))) return DIERR_OUTOFMEMORY; + if (!(format->rgodf = calloc( format->dwNumObjs, sizeof(*format->rgodf) ))) return DIERR_OUTOFMEMORY; format->dwSize = sizeof(*format); format->dwObjSize = sizeof(*format->rgodf); diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index ca2d9f67684..4874e4b1835 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -1223,14 +1223,17 @@ static BOOL read_device_state_value( struct dinput_device *device, UINT index, s const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { struct hid_joystick *impl = CONTAINING_RECORD( device, struct hid_joystick, base ); - struct object_properties *properties = impl->base.object_properties + instance->dwOfs / sizeof(LONG); IDirectInputDevice8W *iface = &impl->base.IDirectInputDevice8W_iface; ULONG logical_value, report_len = impl->caps.InputReportByteLength; struct parse_device_state_params *params = data; char *report_buf = impl->input_report_buf; + struct object_properties *properties; LONG old_value, value; NTSTATUS status; + if (index == -1) return DIENUM_STOP; + properties = device->object_properties + index; + if (instance->wReportId != impl->base.device_state_report_id) return DIENUM_CONTINUE; status = HidP_GetUsageValue( HidP_Input, instance->wUsagePage, 0, instance->wUsage, @@ -1711,14 +1714,19 @@ HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *in static BOOL init_object_properties( struct dinput_device *device, UINT index, struct hid_value_caps *caps, const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { - struct object_properties *properties = device->object_properties + instance->dwOfs / sizeof(LONG); + struct object_properties *properties; LONG tmp; + if (index == -1) return DIENUM_STOP; + properties = device->object_properties + index; + properties->bit_size = caps->bit_size; properties->physical_min = caps->physical_min; properties->physical_max = caps->physical_max; properties->logical_min = caps->logical_min; properties->logical_max = caps->logical_max; + properties->range_min = 0; + properties->range_max = 0; if (instance->dwType & DIDFT_AXIS) properties->range_max = 65535; else @@ -2054,8 +2062,6 @@ HRESULT hid_joystick_create_device( struct dinput *dinput, const GUID *guid, IDi }, }; HIDD_ATTRIBUTES attrs = {.Size = sizeof(attrs)}; - struct object_properties *object_properties; - struct hid_preparsed_data *preparsed; struct hid_joystick *impl = NULL; USAGE_AND_PAGE *usages; char *buffer; @@ -2148,13 +2154,8 @@ HRESULT hid_joystick_create_device( struct dinput *dinput, const GUID *guid, IDi impl->base.caps.dwFFDriverVersion = 1; } - preparsed = (struct hid_preparsed_data *)impl->preparsed; - size = preparsed->input_caps_count * sizeof(struct object_properties); - if (!(object_properties = calloc( 1, size ))) goto failed; - impl->base.object_properties = object_properties; - enum_objects( impl, &filter, DIDFT_AXIS | DIDFT_POV, init_object_properties, NULL ); - if (FAILED(hr = dinput_device_init_device_format( &impl->base.IDirectInputDevice8W_iface ))) goto failed; + enum_objects( impl, &filter, DIDFT_AXIS | DIDFT_POV, init_object_properties, NULL ); *out = &impl->base.IDirectInputDevice8W_iface; return DI_OK; diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c index cb19f5d1850..ec30c825733 100644 --- a/dlls/dinput/mouse.c +++ b/dlls/dinput/mouse.c @@ -85,20 +85,16 @@ HRESULT mouse_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance, return DI_OK; } -static BOOL CALLBACK init_object_properties( const DIDEVICEOBJECTINSTANCEW *instance, void *data ) +static BOOL init_object_properties( struct dinput_device *device, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ) { - struct mouse *impl = (struct mouse *)data; - struct object_properties *properties = impl->base.object_properties + instance->dwOfs / sizeof(LONG); + struct object_properties *properties; - properties->range_min = DIPROPRANGE_NOMIN; - properties->range_max = DIPROPRANGE_NOMAX; + if (index == -1) return DIENUM_STOP; + properties = device->object_properties + index; /* The z-axis (wheel) has a different granularity */ - if (instance->dwOfs == DIMOFS_Z) - properties->granularity = WHEEL_DELTA; - else - properties->granularity = 1; - + if (instance->dwOfs == DIMOFS_Z) properties->granularity = WHEEL_DELTA; return DIENUM_CONTINUE; } @@ -510,6 +506,12 @@ static HRESULT mouse_enum_objects( IDirectInputDevice8W *iface, const DIPROPHEAD HRESULT mouse_create_device( struct dinput *dinput, const GUID *guid, IDirectInputDevice8W **out ) { + static const DIPROPHEADER filter = + { + .dwSize = sizeof(filter), + .dwHeaderSize = sizeof(filter), + .dwHow = DIPH_DEVICE, + }; struct mouse *impl; HKEY hkey, appkey; WCHAR buffer[20]; @@ -531,16 +533,8 @@ HRESULT mouse_create_device( struct dinput *dinput, const GUID *guid, IDirectInp impl->base.dwCoopLevel = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND; if (dinput->dwVersion >= 0x0800) impl->base.use_raw_input = TRUE; - /* One object_properties per axis */ - impl->base.object_properties = calloc( 3, sizeof(struct object_properties) ); - if (!impl->base.object_properties) - { - IDirectInputDevice_Release( &impl->base.IDirectInputDevice8W_iface ); - return E_OUTOFMEMORY; - } - IDirectInputDevice8_EnumObjects( &impl->base.IDirectInputDevice8W_iface, init_object_properties, impl, DIDFT_RELAXIS ); - if (FAILED(hr = dinput_device_init_device_format( &impl->base.IDirectInputDevice8W_iface ))) goto failed; + mouse_enum_objects( &impl->base.IDirectInputDevice8W_iface, &filter, DIDFT_AXIS, init_object_properties, NULL ); get_app_key(&hkey, &appkey); if (!get_config_key( hkey, appkey, L"MouseWarpOverride", buffer, sizeof(buffer) )) From 44a090a51e5b0799bdaf5969f142d806802754b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 18 Mar 2023 18:21:01 +0100 Subject: [PATCH 1353/2777] dinput: Initialize SetActionMap variables in their declarations. (cherry picked from commit 32b43d09e13ec3e71fa144e77b212610d55694bd) --- dlls/dinput/device.c | 78 ++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index af61075eb70..3cf2d868dbe 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -1975,11 +1975,40 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D const WCHAR *username, DWORD flags ) { struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); - DIDATAFORMAT data_format; DIOBJECTDATAFORMAT *obj_df = NULL; - DIPROPDWORD dp; - DIPROPRANGE dpr; - DIPROPSTRING dps; + DIDATAFORMAT data_format = + { + .dwSize = sizeof(DIDATAFORMAT), + .dwObjSize = sizeof(DIOBJECTDATAFORMAT), + .dwFlags = DIDF_RELAXIS, + }; + DIPROPDWORD prop_buffer = + { + .diph = + { + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwSize = sizeof(DIPROPDWORD), + .dwHow = DIPH_DEVICE, + } + }; + DIPROPRANGE prop_range = + { + .diph = + { + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwSize = sizeof(DIPROPRANGE), + .dwHow = DIPH_DEVICE, + } + }; + DIPROPSTRING prop_username = + { + .diph = + { + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwSize = sizeof(DIPROPSTRING), + .dwHow = DIPH_DEVICE, + } + }; WCHAR username_buf[MAX_PATH]; DWORD username_len = MAX_PATH; int i, action = 0, num_actions = 0; @@ -2009,11 +2038,6 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D if (impl->status == STATUS_ACQUIRED) return DIERR_ACQUIRED; - data_format.dwSize = sizeof(data_format); - data_format.dwObjSize = sizeof(DIOBJECTDATAFORMAT); - data_format.dwFlags = DIDF_RELAXIS; - data_format.dwDataSize = format->dwDataSize; - /* Count the actions */ for (i = 0; i < format->dwNumActions; i++) if (IsEqualGUID( &impl->guid, &format->rgoAction[i].guidInstance )) @@ -2024,7 +2048,7 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D /* Construct the dataformat and actionmap */ obj_df = malloc( sizeof(DIOBJECTDATAFORMAT) * num_actions ); data_format.rgodf = (LPDIOBJECTDATAFORMAT)obj_df; - data_format.dwNumObjs = 0; + data_format.dwDataSize = format->dwDataSize; action_map = malloc( sizeof(ActionMap) * num_actions ); @@ -2060,38 +2084,20 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D free( obj_df ); - /* Set the device properties according to the action format */ - dpr.diph.dwSize = sizeof(DIPROPRANGE); - dpr.lMin = format->lAxisMin; - dpr.lMax = format->lAxisMax; - dpr.diph.dwHeaderSize = sizeof(DIPROPHEADER); - dpr.diph.dwObj = 0; - dpr.diph.dwHow = DIPH_DEVICE; - IDirectInputDevice8_SetProperty( iface, DIPROP_RANGE, &dpr.diph ); + prop_range.lMin = format->lAxisMin; + prop_range.lMax = format->lAxisMax; + IDirectInputDevice8_SetProperty( iface, DIPROP_RANGE, &prop_range.diph ); - if (format->dwBufferSize > 0) - { - dp.diph.dwSize = sizeof(DIPROPDWORD); - dp.dwData = format->dwBufferSize; - dp.diph.dwHeaderSize = sizeof(DIPROPHEADER); - dp.diph.dwObj = 0; - dp.diph.dwHow = DIPH_DEVICE; - IDirectInputDevice8_SetProperty( iface, DIPROP_BUFFERSIZE, &dp.diph ); - } + if ((prop_buffer.dwData = format->dwBufferSize)) + IDirectInputDevice8_SetProperty( iface, DIPROP_BUFFERSIZE, &prop_buffer.diph ); - /* Retrieve logged user name if necessary */ if (username == NULL) GetUserNameW( username_buf, &username_len ); else lstrcpynW( username_buf, username, MAX_PATH ); - dps.diph.dwSize = sizeof(dps); - dps.diph.dwHeaderSize = sizeof(DIPROPHEADER); - dps.diph.dwObj = 0; - dps.diph.dwHow = DIPH_DEVICE; - if (flags & DIDSAM_NOUSER) dps.wsz[0] = '\0'; - else lstrcpynW( dps.wsz, username_buf, ARRAY_SIZE(dps.wsz) ); - dinput_device_set_username( impl, &dps ); + if (flags & DIDSAM_NOUSER) prop_username.wsz[0] = '\0'; + else lstrcpynW( prop_username.wsz, username_buf, ARRAY_SIZE(prop_username.wsz) ); + dinput_device_set_username( impl, &prop_username ); - /* Save the settings to disk */ save_mapping_settings( iface, format, username_buf ); return DI_OK; From ddce98cd7f1381710445fa0422361dc52e08e22d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 18 Mar 2023 18:22:09 +0100 Subject: [PATCH 1354/2777] dinput: Always set the DIPROP_BUFFERSIZE property in SetActionMap. (cherry picked from commit be1ef8ed1f70873b20cc889b58da5d5b68df4511) --- dlls/dinput/device.c | 4 ++-- dlls/dinput/tests/joystick8.c | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 3cf2d868dbe..a17df9aa69d 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -2088,8 +2088,8 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D prop_range.lMax = format->lAxisMax; IDirectInputDevice8_SetProperty( iface, DIPROP_RANGE, &prop_range.diph ); - if ((prop_buffer.dwData = format->dwBufferSize)) - IDirectInputDevice8_SetProperty( iface, DIPROP_BUFFERSIZE, &prop_buffer.diph ); + prop_buffer.dwData = format->dwBufferSize; + IDirectInputDevice8_SetProperty( iface, DIPROP_BUFFERSIZE, &prop_buffer.diph ); if (username == NULL) GetUserNameW( username_buf, &username_len ); else lstrcpynW( username_buf, username, MAX_PATH ); diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 64225bf93a3..786ccc7f61c 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -941,7 +941,6 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e hr = IDirectInputDevice8_GetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); - todo_wine ok( prop_dword.dwData == 0, "got dwData %#lx\n", prop_dword.dwData ); From 99aa055d8651b10d1400ea83d6a47429cfd9d5d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 20 Mar 2023 16:18:58 +0100 Subject: [PATCH 1355/2777] dinput: Only set DIPROP_RANGE in SetActionMap if range isn't empty. (cherry picked from commit 8e069f0bf2d9784b66ae863a9894d765e182787f) --- dlls/dinput/device.c | 9 ++++++--- dlls/dinput/tests/joystick8.c | 4 ---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index a17df9aa69d..9dd7a3f478f 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -2084,9 +2084,12 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D free( obj_df ); - prop_range.lMin = format->lAxisMin; - prop_range.lMax = format->lAxisMax; - IDirectInputDevice8_SetProperty( iface, DIPROP_RANGE, &prop_range.diph ); + if (format->lAxisMin != format->lAxisMax) + { + prop_range.lMin = format->lAxisMin; + prop_range.lMax = format->lAxisMax; + IDirectInputDevice8_SetProperty( iface, DIPROP_RANGE, &prop_range.diph ); + } prop_buffer.dwData = format->dwBufferSize; IDirectInputDevice8_SetProperty( iface, DIPROP_BUFFERSIZE, &prop_buffer.diph ); diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 786ccc7f61c..24863330d53 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -925,18 +925,14 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e prop_range.diph.dwObj = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ); hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); - todo_wine ok( prop_range.lMin == +1000, "got lMin %+ld\n", prop_range.lMin ); - todo_wine ok( prop_range.lMax == +51000, "got lMax %+ld\n", prop_range.lMax ); prop_range.diph.dwHow = DIPH_BYUSAGE; prop_range.diph.dwObj = MAKELONG(HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC); hr = IDirectInputDevice8_GetProperty( device, DIPROP_RANGE, &prop_range.diph ); ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); - todo_wine ok( prop_range.lMin == -14000, "got lMin %+ld\n", prop_range.lMin ); - todo_wine ok( prop_range.lMax == -4000, "got lMax %+ld\n", prop_range.lMax ); hr = IDirectInputDevice8_GetProperty( device, DIPROP_BUFFERSIZE, &prop_dword.diph ); From 9b3ad05b898b5c69542eb7508d2a817f186c05b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 20 Mar 2023 09:04:46 +0100 Subject: [PATCH 1356/2777] dinput: Use 4 bytes for every object user state in SetActionMap. (cherry picked from commit df90c379fb91b413d0a652cf20ffaeea963e7207) --- dlls/dinput/device.c | 4 +--- dlls/dinput/tests/joystick8.c | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 9dd7a3f478f..fb7be1e2e6d 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -2052,7 +2052,7 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D action_map = malloc( sizeof(ActionMap) * num_actions ); - for (i = 0; i < format->dwNumActions; i++) + for (i = 0; i < format->dwNumActions; i++, offset += sizeof(ULONG)) { if (IsEqualGUID( &impl->guid, &format->rgoAction[i].guidInstance )) { @@ -2070,9 +2070,7 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D action_map[action].uAppData = format->rgoAction[i].uAppData; action_map[action].offset = offset; obj_df[action].dwOfs = offset; - offset += (type & DIDFT_BUTTON) ? 1 : 4; data_format.dwNumObjs++; - action++; } } diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 24863330d53..2f70efbc69f 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -1046,13 +1046,13 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), state ); ok( hr == DI_OK, "GetDeviceState returned: %#lx\n", hr ); - todo_wine + todo_wine_if( i > 5 ) ok( state[0] == expect_state[i][0], "got state[0] %+ld\n", state[0] ); - todo_wine_if( i != 2 ) + todo_wine_if( i == 2 || i > 4 ) ok( state[1] == expect_state[i][1], "got state[1] %+ld\n", state[1] ); todo_wine_if( expect_state[i][2] ) ok( state[2] == expect_state[i][2], "got state[2] %+ld\n", state[2] ); - todo_wine_if( expect_state[i][3] ) + todo_wine_if( i > 5 ) ok( state[3] == expect_state[i][3], "got state[3] %+ld\n", state[3] ); todo_wine_if( expect_state[i][4] ) ok( state[4] == expect_state[i][4], "got state[4] %+ld\n", state[4] ); @@ -1082,7 +1082,7 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e while (res--) { winetest_push_context( "%lu", res ); - todo_wine + todo_wine_if( res != 1 && res != 4 ) check_member( objdata[res], expect_objdata[res], "%#lx", dwOfs ); todo_wine_if( res == 0 || res == 3 || res == 6 ) ok( objdata[res].dwData == expect_objdata[res].dwData || From 5fb7c2eae84ff3a5fbadaf8956a5c1b1c80ff4d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 22 Mar 2023 09:01:08 +0100 Subject: [PATCH 1357/2777] dinput: Initialize object formats from device objects in SetActionMap. (cherry picked from commit 8ff74b157acc7ec3d4c69c84091421db5584666e) --- dlls/dinput/device.c | 50 +++++++---------------------------- dlls/dinput/tests/joystick8.c | 11 +++----- 2 files changed, 14 insertions(+), 47 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index fb7be1e2e6d..28494c3bec6 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -1975,7 +1975,6 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D const WCHAR *username, DWORD flags ) { struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); - DIOBJECTDATAFORMAT *obj_df = NULL; DIDATAFORMAT data_format = { .dwSize = sizeof(DIDATAFORMAT), @@ -2011,9 +2010,8 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D }; WCHAR username_buf[MAX_PATH]; DWORD username_len = MAX_PATH; - int i, action = 0, num_actions = 0; + int i, index, action = 0, num_actions = 0; unsigned int offset = 0; - const DIDATAFORMAT *df; ActionMap *action_map; FIXME( "iface %p, format %p, username %s, flags %#lx stub!\n", iface, format, @@ -2021,21 +2019,6 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D if (!format) return DIERR_INVALIDPARAM; - switch (GET_DIDEVICE_TYPE( impl->instance.dwDevType )) - { - case DIDEVTYPE_KEYBOARD: - case DI8DEVTYPE_KEYBOARD: - df = &c_dfDIKeyboard; - break; - case DIDEVTYPE_MOUSE: - case DI8DEVTYPE_MOUSE: - df = &c_dfDIMouse2; - break; - default: - df = &impl->device_format; - break; - } - if (impl->status == STATUS_ACQUIRED) return DIERR_ACQUIRED; /* Count the actions */ @@ -2045,34 +2028,21 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D if (num_actions == 0) return DI_NOEFFECT; - /* Construct the dataformat and actionmap */ - obj_df = malloc( sizeof(DIOBJECTDATAFORMAT) * num_actions ); - data_format.rgodf = (LPDIOBJECTDATAFORMAT)obj_df; + data_format.rgodf = malloc( sizeof(DIOBJECTDATAFORMAT) * num_actions ); data_format.dwDataSize = format->dwDataSize; action_map = malloc( sizeof(ActionMap) * num_actions ); for (i = 0; i < format->dwNumActions; i++, offset += sizeof(ULONG)) { - if (IsEqualGUID( &impl->guid, &format->rgoAction[i].guidInstance )) - { - DWORD inst = DIDFT_GETINSTANCE( format->rgoAction[i].dwObjID ); - DWORD type = DIDFT_GETTYPE( format->rgoAction[i].dwObjID ); - LPDIOBJECTDATAFORMAT obj; - - if (type == DIDFT_PSHBUTTON) type = DIDFT_BUTTON; - if (type == DIDFT_RELAXIS) type = DIDFT_AXIS; + if (!IsEqualGUID( &impl->guid, &format->rgoAction[i].guidInstance )) continue; + if ((index = dinput_device_object_index_from_id( iface, format->rgoAction[i].dwObjID )) < 0) continue; - if (!(obj = dataformat_to_odf_by_type( df, inst, type ))) continue; - - memcpy( &obj_df[action], obj, df->dwObjSize ); - - action_map[action].uAppData = format->rgoAction[i].uAppData; - action_map[action].offset = offset; - obj_df[action].dwOfs = offset; - data_format.dwNumObjs++; - action++; - } + action_map[action].uAppData = format->rgoAction[i].uAppData; + action_map[action].offset = offset; + data_format.rgodf[data_format.dwNumObjs] = impl->device_format.rgodf[index]; + data_format.rgodf[data_format.dwNumObjs].dwOfs = offset; + data_format.dwNumObjs++; } IDirectInputDevice8_SetDataFormat( iface, &data_format ); @@ -2080,7 +2050,7 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D impl->action_map = action_map; impl->num_actions = num_actions; - free( obj_df ); + free( data_format.rgodf ); if (format->lAxisMin != format->lAxisMax) { diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 2f70efbc69f..d6a7402d971 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -1046,13 +1046,11 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), state ); ok( hr == DI_OK, "GetDeviceState returned: %#lx\n", hr ); - todo_wine_if( i > 5 ) ok( state[0] == expect_state[i][0], "got state[0] %+ld\n", state[0] ); - todo_wine_if( i == 2 || i > 4 ) + todo_wine_if( i == 2 || i == 5 ) ok( state[1] == expect_state[i][1], "got state[1] %+ld\n", state[1] ); todo_wine_if( expect_state[i][2] ) ok( state[2] == expect_state[i][2], "got state[2] %+ld\n", state[2] ); - todo_wine_if( i > 5 ) ok( state[3] == expect_state[i][3], "got state[3] %+ld\n", state[3] ); todo_wine_if( expect_state[i][4] ) ok( state[4] == expect_state[i][4], "got state[4] %+ld\n", state[4] ); @@ -1060,7 +1058,6 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e ok( state[5] == expect_state[i][5], "got state[5] %+ld\n", state[5] ); todo_wine_if( expect_state[i][6] ) ok( state[6] == expect_state[i][6], "got state[6] %+ld\n", state[6] ); - todo_wine_if( expect_state[i][7] ) ok( state[7] == expect_state[i][7] || broken(state[7] == -45 && expect_state[i][7] == -43) /* 32-bit rounding */, "got state[7] %+ld\n", state[7] ); @@ -1082,13 +1079,13 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e while (res--) { winetest_push_context( "%lu", res ); - todo_wine_if( res != 1 && res != 4 ) + todo_wine check_member( objdata[res], expect_objdata[res], "%#lx", dwOfs ); - todo_wine_if( res == 0 || res == 3 || res == 6 ) + todo_wine ok( objdata[res].dwData == expect_objdata[res].dwData || broken(objdata[res].dwData == -45 && expect_objdata[res].dwData == -43) /* 32-bit rounding */, "got dwData %+ld\n", objdata[res].dwData ); - todo_wine_if( res != 1 && res != 4 ) + todo_wine check_member( objdata[res], expect_objdata[res], "%#Ix", uAppData ); winetest_pop_context(); } From ce89eb5a827d9e198acd437cc71ed48a56e5dc6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 20 Mar 2023 16:57:27 +0100 Subject: [PATCH 1358/2777] dinput: Respect DIA_APPNOMAP in IDirectInputDevice8W_SetActionMap. (cherry picked from commit c6a922c1a1a6f6cf6b04323cc5883873f28183cc) --- dlls/dinput/device.c | 1 + dlls/dinput/tests/joystick8.c | 9 +-------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 28494c3bec6..e493149a474 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -2035,6 +2035,7 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D for (i = 0; i < format->dwNumActions; i++, offset += sizeof(ULONG)) { + if (format->rgoAction[i].dwFlags & DIA_APPNOMAP) continue; if (!IsEqualGUID( &impl->guid, &format->rgoAction[i].guidInstance )) continue; if ((index = dinput_device_object_index_from_id( iface, format->rgoAction[i].dwObjID )) < 0) continue; diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index d6a7402d971..2f1c82c2121 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -1047,16 +1047,11 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), state ); ok( hr == DI_OK, "GetDeviceState returned: %#lx\n", hr ); ok( state[0] == expect_state[i][0], "got state[0] %+ld\n", state[0] ); - todo_wine_if( i == 2 || i == 5 ) ok( state[1] == expect_state[i][1], "got state[1] %+ld\n", state[1] ); - todo_wine_if( expect_state[i][2] ) ok( state[2] == expect_state[i][2], "got state[2] %+ld\n", state[2] ); ok( state[3] == expect_state[i][3], "got state[3] %+ld\n", state[3] ); - todo_wine_if( expect_state[i][4] ) ok( state[4] == expect_state[i][4], "got state[4] %+ld\n", state[4] ); - todo_wine_if( expect_state[i][5] ) ok( state[5] == expect_state[i][5], "got state[5] %+ld\n", state[5] ); - todo_wine_if( expect_state[i][6] ) ok( state[6] == expect_state[i][6], "got state[6] %+ld\n", state[6] ); ok( state[7] == expect_state[i][7] || broken(state[7] == -45 && expect_state[i][7] == -43) /* 32-bit rounding */, @@ -1079,13 +1074,11 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e while (res--) { winetest_push_context( "%lu", res ); - todo_wine check_member( objdata[res], expect_objdata[res], "%#lx", dwOfs ); - todo_wine ok( objdata[res].dwData == expect_objdata[res].dwData || broken(objdata[res].dwData == -45 && expect_objdata[res].dwData == -43) /* 32-bit rounding */, "got dwData %+ld\n", objdata[res].dwData ); - todo_wine + todo_wine_if( res != 0 && res != 3 && res != 6 ) check_member( objdata[res], expect_objdata[res], "%#Ix", uAppData ); winetest_pop_context(); } From 818362f127e9b3ffd12333566f036c9cd2667bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 22 Mar 2023 09:18:46 +0100 Subject: [PATCH 1359/2777] dinput: Return error from SetActionMap if SetDataFormat fails. (cherry picked from commit 63637f240769ae635a4894477d2a511d6cfeccb4) --- dlls/dinput/device.c | 48 +++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index e493149a474..162e4c451fb 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -2013,14 +2013,13 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D int i, index, action = 0, num_actions = 0; unsigned int offset = 0; ActionMap *action_map; + HRESULT hr; FIXME( "iface %p, format %p, username %s, flags %#lx stub!\n", iface, format, debugstr_w(username), flags ); if (!format) return DIERR_INVALIDPARAM; - if (impl->status == STATUS_ACQUIRED) return DIERR_ACQUIRED; - /* Count the actions */ for (i = 0; i < format->dwNumActions; i++) if (IsEqualGUID( &impl->guid, &format->rgoAction[i].guidInstance )) @@ -2046,33 +2045,40 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D data_format.dwNumObjs++; } - IDirectInputDevice8_SetDataFormat( iface, &data_format ); + EnterCriticalSection( &impl->crit ); - impl->action_map = action_map; - impl->num_actions = num_actions; + if (FAILED(hr = IDirectInputDevice8_SetDataFormat( iface, &data_format ))) + WARN( "Failed to set data format from action map, hr %#lx\n", hr ); + else + { + impl->action_map = action_map; + impl->num_actions = num_actions; - free( data_format.rgodf ); + if (format->lAxisMin != format->lAxisMax) + { + prop_range.lMin = format->lAxisMin; + prop_range.lMax = format->lAxisMax; + IDirectInputDevice8_SetProperty( iface, DIPROP_RANGE, &prop_range.diph ); + } - if (format->lAxisMin != format->lAxisMax) - { - prop_range.lMin = format->lAxisMin; - prop_range.lMax = format->lAxisMax; - IDirectInputDevice8_SetProperty( iface, DIPROP_RANGE, &prop_range.diph ); - } + prop_buffer.dwData = format->dwBufferSize; + IDirectInputDevice8_SetProperty( iface, DIPROP_BUFFERSIZE, &prop_buffer.diph ); - prop_buffer.dwData = format->dwBufferSize; - IDirectInputDevice8_SetProperty( iface, DIPROP_BUFFERSIZE, &prop_buffer.diph ); + if (username == NULL) GetUserNameW( username_buf, &username_len ); + else lstrcpynW( username_buf, username, MAX_PATH ); - if (username == NULL) GetUserNameW( username_buf, &username_len ); - else lstrcpynW( username_buf, username, MAX_PATH ); + if (flags & DIDSAM_NOUSER) prop_username.wsz[0] = '\0'; + else lstrcpynW( prop_username.wsz, username_buf, ARRAY_SIZE(prop_username.wsz) ); + dinput_device_set_username( impl, &prop_username ); - if (flags & DIDSAM_NOUSER) prop_username.wsz[0] = '\0'; - else lstrcpynW( prop_username.wsz, username_buf, ARRAY_SIZE(prop_username.wsz) ); - dinput_device_set_username( impl, &prop_username ); + save_mapping_settings( iface, format, username_buf ); + } - save_mapping_settings( iface, format, username_buf ); + LeaveCriticalSection( &impl->crit ); - return DI_OK; + if (FAILED(hr)) free( action_map ); + free( data_format.rgodf ); + return hr; } static HRESULT WINAPI dinput_device_GetImageInfo( IDirectInputDevice8W *iface, DIDEVICEIMAGEINFOHEADERW *header ) From 3562a6d7f72e885aa5ec062f22ce36fb930aa463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 22 Mar 2023 09:19:49 +0100 Subject: [PATCH 1360/2777] dinput: Keep device objects app data in the object properties. (cherry picked from commit b1a95b9671091aad2bf8ed29465c307db39f3447) --- dlls/dinput/device.c | 157 ++++++++++++---------------------- dlls/dinput/device_private.h | 11 +-- dlls/dinput/tests/joystick8.c | 12 --- 3 files changed, 54 insertions(+), 126 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 162e4c451fb..16c4409b9b3 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -273,6 +273,9 @@ static HRESULT dinput_device_init_user_format( struct dinput_device *impl, const user_obj = user_format->rgodf + user_format->dwNumObjs; while (user_obj-- > user_format->rgodf) user_obj->dwType |= DIDFT_OPTIONAL; + for (i = 0; i < device_format->dwNumObjs; i++) + impl->object_properties[i].app_data = -1; + for (i = 0; i < format->dwNumObjs; ++i) { match_obj = format->rgodf + i; @@ -297,23 +300,6 @@ static HRESULT dinput_device_init_user_format( struct dinput_device *impl, const return DIERR_INVALIDPARAM; } -static int id_to_offset( struct dinput_device *impl, int id ) -{ - DIDATAFORMAT *user_format = &impl->user_format; - DIOBJECTDATAFORMAT *user_obj; - - if (!user_format->rgodf) return -1; - - user_obj = user_format->rgodf + impl->device_format.dwNumObjs; - while (user_obj-- > user_format->rgodf) - { - if (!user_obj->dwType) continue; - if ((user_obj->dwType & 0x00ffffff) == (id & 0x00ffffff)) return user_obj->dwOfs; - } - - return -1; -} - int dinput_device_object_index_from_id( IDirectInputDevice8W *iface, DWORD id ) { struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); @@ -443,50 +429,11 @@ static BOOL load_mapping_settings( struct dinput_device *This, LPDIACTIONFORMATW return mapped > 0; } -static BOOL set_app_data( struct dinput_device *dev, int offset, UINT_PTR app_data ) -{ - int num_actions = dev->num_actions; - ActionMap *action_map = dev->action_map, *target_map = NULL; - - if (num_actions == 0) - { - num_actions = 1; - action_map = malloc( sizeof(ActionMap) ); - if (!action_map) return FALSE; - target_map = &action_map[0]; - } - else - { - int i; - for (i = 0; i < num_actions; i++) - { - if (dev->action_map[i].offset != offset) continue; - target_map = &dev->action_map[i]; - break; - } - - if (!target_map) - { - num_actions++; - action_map = realloc( action_map, sizeof(ActionMap) * num_actions ); - if (!action_map) return FALSE; - target_map = &action_map[num_actions-1]; - } - } - - target_map->offset = offset; - target_map->uAppData = app_data; - - dev->action_map = action_map; - dev->num_actions = num_actions; - - return TRUE; -} - void queue_event( IDirectInputDevice8W *iface, int index, DWORD data, DWORD time, DWORD seq ) { static ULONGLONG notify_ms = 0; struct dinput_device *This = impl_from_IDirectInputDevice8W( iface ); + struct object_properties *properties = This->object_properties + index; const DIOBJECTDATAFORMAT *user_obj = This->user_format.rgodf + index; ULONGLONG time_ms = GetTickCount64(); int next_pos; @@ -513,22 +460,7 @@ void queue_event( IDirectInputDevice8W *iface, int index, DWORD data, DWORD time This->data_queue[This->queue_head].dwData = data; This->data_queue[This->queue_head].dwTimeStamp = time; This->data_queue[This->queue_head].dwSequence = seq; - This->data_queue[This->queue_head].uAppData = -1; - - /* Set uAppData by means of action mapping */ - if (This->num_actions > 0) - { - int i; - for (i=0; i < This->num_actions; i++) - { - if (This->action_map[i].offset == user_obj->dwOfs) - { - TRACE( "Offset %lu mapped to uAppData %#Ix\n", user_obj->dwOfs, This->action_map[i].uAppData ); - This->data_queue[This->queue_head].uAppData = This->action_map[i].uAppData; - break; - } - } - } + This->data_queue[This->queue_head].uAppData = properties->app_data; This->queue_head = next_pos; /* Send event if asked */ @@ -604,10 +536,6 @@ static HRESULT WINAPI dinput_device_SetDataFormat( IDirectInputDevice8W *iface, EnterCriticalSection(&This->crit); - free( This->action_map ); - This->action_map = NULL; - This->num_actions = 0; - dinput_device_release_user_format( This ); res = dinput_device_init_user_format( This, format ); @@ -707,8 +635,6 @@ void dinput_device_internal_release( struct dinput_device *impl ) free( impl->device_format.rgodf ); dinput_device_release_user_format( impl ); - free( impl->action_map ); - dinput_internal_release( impl->dinput ); impl->crit.DebugInfo->Spare[0] = 0; DeleteCriticalSection( &impl->crit ); @@ -1060,13 +986,6 @@ static HRESULT check_property( struct dinput_device *impl, const GUID *guid, con return DI_OK; } -static BOOL find_object( struct dinput_device *device, UINT index, struct hid_value_caps *caps, - const DIDEVICEOBJECTINSTANCEW *instance, void *data ) -{ - *(DIDEVICEOBJECTINSTANCEW *)data = *instance; - return DIENUM_STOP; -} - struct get_object_property_params { IDirectInputDevice8W *iface; @@ -1137,6 +1056,12 @@ static BOOL get_object_property( struct dinput_device *device, UINT index, struc lstrcpynW( value->wsz, instance->tszName, ARRAY_SIZE(value->wsz) ); return DIENUM_STOP; } + case (DWORD_PTR)DIPROP_APPDATA: + { + DIPROPPOINTER *value = (DIPROPPOINTER *)params->header; + value->uData = properties->app_data; + return DIENUM_STOP; + } } return DIENUM_STOP; @@ -1172,6 +1097,7 @@ static HRESULT dinput_device_get_property( IDirectInputDevice8W *iface, const GU case (DWORD_PTR)DIPROP_GRANULARITY: case (DWORD_PTR)DIPROP_KEYNAME: case (DWORD_PTR)DIPROP_CALIBRATIONMODE: + case (DWORD_PTR)DIPROP_APPDATA: hr = impl->vtbl->enum_objects( iface, &filter, object_mask, get_object_property, ¶ms ); if (FAILED(hr)) return hr; if (hr == DIENUM_CONTINUE) return DIERR_NOTFOUND; @@ -1283,6 +1209,12 @@ static BOOL set_object_property( struct dinput_device *device, UINT index, struc properties->calibration_mode = value->dwData; return DIENUM_CONTINUE; } + case (DWORD_PTR)DIPROP_APPDATA: + { + DIPROPPOINTER *value = (DIPROPPOINTER *)params->header; + properties->app_data = value->uData; + return DIENUM_CONTINUE; + } } return DIENUM_STOP; @@ -1328,8 +1260,6 @@ static HRESULT dinput_device_set_property( IDirectInputDevice8W *iface, const GU { struct set_object_property_params params = {.iface = iface, .header = header, .property = LOWORD( guid )}; struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); - DWORD object_mask = DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV; - DIDEVICEOBJECTINSTANCEW instance; DIPROPHEADER filter; HRESULT hr; @@ -1401,13 +1331,8 @@ static HRESULT dinput_device_set_property( IDirectInputDevice8W *iface, const GU } case (DWORD_PTR)DIPROP_APPDATA: { - const DIPROPPOINTER *value = (const DIPROPPOINTER *)header; - int user_offset; - hr = impl->vtbl->enum_objects( iface, &filter, object_mask, find_object, &instance ); + hr = impl->vtbl->enum_objects( iface, &filter, DIDFT_ALL, set_object_property, ¶ms ); if (FAILED(hr)) return hr; - if (hr == DIENUM_CONTINUE) return DIERR_OBJECTNOTFOUND; - if ((user_offset = id_to_offset( impl, instance.dwType )) < 0) return DIERR_OBJECTNOTFOUND; - if (!set_app_data( impl, user_offset, value->uData )) return DIERR_OUTOFMEMORY; return DI_OK; } default: @@ -1971,9 +1896,38 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, return DI_OK; } +static BOOL init_object_app_data( struct dinput_device *device, UINT index, struct hid_value_caps *caps, + const DIDEVICEOBJECTINSTANCEW *instance, void *data ) +{ + struct object_properties *properties; + const DIACTIONFORMATW *format = data; + const DIACTIONW *action = format->rgoAction + format->dwNumActions; + + if (index == -1) return DIENUM_STOP; + if (instance->wUsagePage == HID_USAGE_PAGE_PID) return DIENUM_CONTINUE; + + properties = device->object_properties + index; + properties->app_data = 0; + + while (action-- > format->rgoAction) + { + if (action->dwObjID != instance->dwType) continue; + properties->app_data = action->uAppData; + break; + } + + return DIENUM_CONTINUE; +} + static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, DIACTIONFORMATW *format, const WCHAR *username, DWORD flags ) { + static const DIPROPHEADER filter = + { + .dwSize = sizeof(filter), + .dwHeaderSize = sizeof(filter), + .dwHow = DIPH_DEVICE, + }; struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); DIDATAFORMAT data_format = { @@ -2010,9 +1964,8 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D }; WCHAR username_buf[MAX_PATH]; DWORD username_len = MAX_PATH; - int i, index, action = 0, num_actions = 0; + int i, index, num_actions = 0; unsigned int offset = 0; - ActionMap *action_map; HRESULT hr; FIXME( "iface %p, format %p, username %s, flags %#lx stub!\n", iface, format, @@ -2027,19 +1980,15 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D if (num_actions == 0) return DI_NOEFFECT; - data_format.rgodf = malloc( sizeof(DIOBJECTDATAFORMAT) * num_actions ); + if (!(data_format.rgodf = malloc( sizeof(DIOBJECTDATAFORMAT) * num_actions ))) return DIERR_OUTOFMEMORY; data_format.dwDataSize = format->dwDataSize; - action_map = malloc( sizeof(ActionMap) * num_actions ); - for (i = 0; i < format->dwNumActions; i++, offset += sizeof(ULONG)) { if (format->rgoAction[i].dwFlags & DIA_APPNOMAP) continue; if (!IsEqualGUID( &impl->guid, &format->rgoAction[i].guidInstance )) continue; if ((index = dinput_device_object_index_from_id( iface, format->rgoAction[i].dwObjID )) < 0) continue; - action_map[action].uAppData = format->rgoAction[i].uAppData; - action_map[action].offset = offset; data_format.rgodf[data_format.dwNumObjs] = impl->device_format.rgodf[index]; data_format.rgodf[data_format.dwNumObjs].dwOfs = offset; data_format.dwNumObjs++; @@ -2051,8 +2000,8 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D WARN( "Failed to set data format from action map, hr %#lx\n", hr ); else { - impl->action_map = action_map; - impl->num_actions = num_actions; + if (FAILED(impl->vtbl->enum_objects( iface, &filter, DIDFT_ALL, init_object_app_data, format ))) + WARN( "Failed to initialize action map app data\n" ); if (format->lAxisMin != format->lAxisMax) { @@ -2076,7 +2025,6 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D LeaveCriticalSection( &impl->crit ); - if (FAILED(hr)) free( action_map ); free( data_format.rgodf ); return hr; } @@ -2196,6 +2144,7 @@ static BOOL enum_objects_init( struct dinput_device *impl, UINT index, struct hi .range_min = DIPROPRANGE_NOMIN, .range_max = DIPROPRANGE_NOMAX, .granularity = 1, + .app_data = -1, }; DIDATAFORMAT *format = &impl->device_format; DIOBJECTDATAFORMAT *object_format; diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h index 65453f6313d..5563618ff12 100644 --- a/dlls/dinput/device_private.h +++ b/dlls/dinput/device_private.h @@ -28,12 +28,6 @@ #include "wine/list.h" #include "dinput_private.h" -typedef struct -{ - unsigned int offset; - UINT_PTR uAppData; -} ActionMap; - struct dinput_device; struct hid_value_caps; @@ -72,6 +66,7 @@ struct object_properties LONG range_max; LONG deadzone; LONG saturation; + UINT_PTR app_data; DWORD calibration_mode; DWORD granularity; }; @@ -113,10 +108,6 @@ struct dinput_device DIDATAFORMAT device_format; DIDATAFORMAT user_format; - /* Action mapping */ - int num_actions; /* number of actions mapped */ - ActionMap *action_map; /* array of mappings */ - /* internal device callbacks */ HANDLE read_event; const struct dinput_device_vtbl *vtbl; diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 2f1c82c2121..b77e31ad534 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -917,7 +917,6 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e prop_pointer.diph.dwHow = DIPH_BYUSAGE; prop_pointer.diph.dwObj = MAKELONG(HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC); hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); - todo_wine ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); ok( prop_pointer.uData == 0, "got uData %#Ix\n", prop_pointer.uData ); @@ -965,23 +964,18 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e prop_pointer.diph.dwHow = DIPH_BYID; prop_pointer.diph.dwObj = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 3 ); hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); - todo_wine ok( hr == DIERR_NOTFOUND, "GetProperty returned %#lx\n", hr ); prop_pointer.diph.dwHow = DIPH_BYID; prop_pointer.diph.dwObj = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ); hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); - todo_wine ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); - todo_wine ok( prop_pointer.uData == 6, "got uData %#Ix\n", prop_pointer.uData ); prop_pointer.diph.dwHow = DIPH_BYUSAGE; prop_pointer.diph.dwObj = MAKELONG(HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC); hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); - todo_wine ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); - todo_wine ok( prop_pointer.uData == 8, "got uData %#Ix\n", prop_pointer.uData ); prop_range.diph.dwHow = DIPH_BYID; @@ -1078,7 +1072,6 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e ok( objdata[res].dwData == expect_objdata[res].dwData || broken(objdata[res].dwData == -45 && expect_objdata[res].dwData == -43) /* 32-bit rounding */, "got dwData %+ld\n", objdata[res].dwData ); - todo_wine_if( res != 0 && res != 3 && res != 6 ) check_member( objdata[res], expect_objdata[res], "%#Ix", uAppData ); winetest_pop_context(); } @@ -1095,9 +1088,7 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e prop_pointer.diph.dwHow = DIPH_BYUSAGE; prop_pointer.diph.dwObj = MAKELONG(HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC); hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); - todo_wine ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); - todo_wine ok( prop_pointer.uData == 8, "got uData %#Ix\n", prop_pointer.uData ); hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); @@ -1106,9 +1097,7 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e prop_pointer.diph.dwHow = DIPH_BYUSAGE; prop_pointer.diph.dwObj = MAKELONG(HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC); hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); - todo_wine ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); - todo_wine ok( prop_pointer.uData == -1, "got uData %#Ix\n", prop_pointer.uData ); prop_range.diph.dwHow = DIPH_BYID; @@ -2718,7 +2707,6 @@ static void test_simple_joystick( DWORD version ) prop_pointer.diph.dwHow = DIPH_BYUSAGE; prop_pointer.diph.dwObj = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); hr = IDirectInputDevice8_GetProperty( device, DIPROP_APPDATA, &prop_pointer.diph ); - todo_wine_if( version >= 0x0800 ) ok( hr == (version < 0x0800 ? DIERR_UNSUPPORTED : DI_OK), "GetProperty DIPROP_APPDATA returned %#lx\n", hr ); if (hr == DI_OK) ok( prop_pointer.uData == 0xfeedcafe, "got %p\n", (void *)prop_pointer.uData ); From 333ac7b03262dfc7d02d9d93420b3727a7be4dc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 22 Mar 2023 09:21:48 +0100 Subject: [PATCH 1361/2777] dinput: Allow action formats with no matching actions. (cherry picked from commit 0fe8da86e33331e9e4c41a59fb65c63797445530) --- dlls/dinput/device.c | 14 +++++--------- dlls/dinput/tests/joystick8.c | 4 ---- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 16c4409b9b3..2817ca9839b 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -1964,8 +1964,8 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D }; WCHAR username_buf[MAX_PATH]; DWORD username_len = MAX_PATH; - int i, index, num_actions = 0; unsigned int offset = 0; + int i, index; HRESULT hr; FIXME( "iface %p, format %p, username %s, flags %#lx stub!\n", iface, format, @@ -1973,14 +1973,7 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D if (!format) return DIERR_INVALIDPARAM; - /* Count the actions */ - for (i = 0; i < format->dwNumActions; i++) - if (IsEqualGUID( &impl->guid, &format->rgoAction[i].guidInstance )) - num_actions++; - - if (num_actions == 0) return DI_NOEFFECT; - - if (!(data_format.rgodf = malloc( sizeof(DIOBJECTDATAFORMAT) * num_actions ))) return DIERR_OUTOFMEMORY; + if (!(data_format.rgodf = malloc( sizeof(DIOBJECTDATAFORMAT) * format->dwNumActions ))) return DIERR_OUTOFMEMORY; data_format.dwDataSize = format->dwDataSize; for (i = 0; i < format->dwNumActions; i++, offset += sizeof(ULONG)) @@ -2026,6 +2019,9 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D LeaveCriticalSection( &impl->crit ); free( data_format.rgodf ); + + if (FAILED(hr)) return hr; + if (!data_format.dwNumObjs) return DI_NOEFFECT; return hr; } diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index b77e31ad534..09c753593a6 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -824,9 +824,7 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e memset( prop_username.wsz, 0, sizeof(prop_username.wsz) ); hr = IDirectInputDevice_GetProperty( device, DIPROP_USERNAME, &prop_username.diph ); - todo_wine ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); - todo_wine ok( !wcscmp( prop_username.wsz, username ), "got username %s\n", debugstr_w(prop_username.wsz) ); hr = IDirectInputDevice8_SetActionMap( device, &voice_action_format, NULL, DIDSAM_DEFAULT ); @@ -837,9 +835,7 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e memset( prop_username.wsz, 0, sizeof(prop_username.wsz) ); hr = IDirectInputDevice_GetProperty( device, DIPROP_USERNAME, &prop_username.diph ); - todo_wine ok( hr == DI_OK, "GetProperty returned %#lx\n", hr ); - todo_wine ok( !wcscmp( prop_username.wsz, username ), "got username %s\n", debugstr_w(prop_username.wsz) ); From 3f55935909261d1f5927d7c928292b716827a5f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 20 Mar 2023 16:57:27 +0100 Subject: [PATCH 1362/2777] dinput: Check IDirectInputDevice8W_SetActionMap flags. (cherry picked from commit 5d3f2d18ad36993033bb046d5177fc7130894e2f) --- dlls/dinput/device.c | 1 + dlls/dinput/tests/joystick8.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 2817ca9839b..0df0199317b 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -1972,6 +1972,7 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D debugstr_w(username), flags ); if (!format) return DIERR_INVALIDPARAM; + if (flags != DIDSAM_DEFAULT && flags != DIDSAM_FORCESAVE && flags != DIDSAM_NOUSER) return DIERR_INVALIDPARAM; if (!(data_format.rgodf = malloc( sizeof(DIOBJECTDATAFORMAT) * format->dwNumActions ))) return DIERR_OUTOFMEMORY; data_format.dwDataSize = format->dwDataSize; diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 09c753593a6..be97bff3aa3 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -807,7 +807,6 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e ok( hr == DIERR_INVALIDPARAM, "SetActionMap returned %#lx\n", hr ); flags = DIDSAM_FORCESAVE | DIDSAM_NOUSER; hr = IDirectInputDevice8_SetActionMap( device, &action_format_1, NULL, flags ); - todo_wine ok( hr == DIERR_INVALIDPARAM, "SetActionMap returned %#lx\n", hr ); From c20b06978fdb573ca0df7f4ba89f28cf2814b0eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 20 Mar 2023 16:57:27 +0100 Subject: [PATCH 1363/2777] dinput: Return DI_SETTINGSNOTSAVED when DIDSAM_FORCESAVE is used. (cherry picked from commit bf22424e2af276d0e1b9641bcbbfe63f25159824) --- dlls/dinput/device.c | 1 + dlls/dinput/tests/joystick8.c | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 0df0199317b..41baa630989 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -2022,6 +2022,7 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D free( data_format.rgodf ); if (FAILED(hr)) return hr; + if (flags == DIDSAM_FORCESAVE) return DI_SETTINGSNOTSAVED; if (!data_format.dwNumObjs) return DI_NOEFFECT; return hr; } diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index be97bff3aa3..eef2d255595 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -818,7 +818,6 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e /* first SetActionMap call for a user always return DI_SETTINGSNOTSAVED */ hr = IDirectInputDevice8_SetActionMap( device, &voice_action_format, NULL, DIDSAM_FORCESAVE ); - todo_wine ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); memset( prop_username.wsz, 0, sizeof(prop_username.wsz) ); @@ -829,7 +828,6 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e hr = IDirectInputDevice8_SetActionMap( device, &voice_action_format, NULL, DIDSAM_DEFAULT ); ok( hr == DI_NOEFFECT, "SetActionMap returned %#lx\n", hr ); hr = IDirectInputDevice8_SetActionMap( device, &voice_action_format, NULL, DIDSAM_FORCESAVE ); - todo_wine ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); memset( prop_username.wsz, 0, sizeof(prop_username.wsz) ); @@ -874,10 +872,8 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e /* DIDSAM_FORCESAVE always returns DI_SETTINGSNOTSAVED */ hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_FORCESAVE ); - todo_wine ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_FORCESAVE ); - todo_wine ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); check_diactionformatw( &action_format, &expect_action_format_1 ); @@ -946,7 +942,6 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); check_diactionformatw( &action_format, &expect_action_format_2_filled ); hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_FORCESAVE ); - todo_wine ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); check_diactionformatw( &action_format, &expect_action_format_2_filled ); From 814f5deb576800d14825c6234300971168587d23 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 25 Mar 2023 01:08:56 -0700 Subject: [PATCH 1364/2777] hidparse.sys: Include zero-count reports in cap count. Signed-off-by: Vicki Pfau (cherry picked from commit 6a88500af29b82040f0518eb87171ca047fb95aa) --- dlls/dinput/tests/hid.c | 2 -- dlls/hidparse.sys/main.c | 34 +++++++++++++++++++--------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c index facbf69fcec..bd01d1ae868 100644 --- a/dlls/dinput/tests/hid.c +++ b/dlls/dinput/tests/hid.c @@ -3173,11 +3173,9 @@ static void check_preparsed_data( HANDLE file, const struct hidp_kdr *expect_kdr check_member( *kdr, *expect_kdr, "%d", output_caps_end ); check_member( *kdr, *expect_kdr, "%d", output_report_byte_length ); check_member( *kdr, *expect_kdr, "%d", feature_caps_start ); - todo_wine check_member( *kdr, *expect_kdr, "%d", feature_caps_count ); check_member( *kdr, *expect_kdr, "%d", feature_caps_end ); check_member( *kdr, *expect_kdr, "%d", feature_report_byte_length ); - todo_wine check_member( *kdr, *expect_kdr, "%d", caps_size ); check_member( *kdr, *expect_kdr, "%d", number_link_collection_nodes ); diff --git a/dlls/hidparse.sys/main.c b/dlls/hidparse.sys/main.c index 7058093e03c..feb5b3531a4 100644 --- a/dlls/hidparse.sys/main.c +++ b/dlls/hidparse.sys/main.c @@ -130,11 +130,11 @@ static void debug_print_preparsed( struct hid_preparsed_data *data ) data->output_caps_start, data->output_caps_count, data->output_caps_end, data->output_report_byte_length, data->feature_caps_start, data->feature_caps_count, data->feature_caps_end, data->feature_report_byte_length, data->number_link_collection_nodes ); - end = data->input_caps_count; + end = data->input_caps_end - data->input_caps_start; for (i = 0; i < end; i++) TRACE( "input %d: %s\n", i, debugstr_hid_value_caps( HID_INPUT_VALUE_CAPS( data ) + i ) ); - end = data->output_caps_count; + end = data->output_caps_end - data->output_caps_start; for (i = 0; i < end; i++) TRACE( "output %d: %s\n", i, debugstr_hid_value_caps( HID_OUTPUT_VALUE_CAPS( data ) + i ) ); - end = data->feature_caps_count; + end = data->feature_caps_end - data->feature_caps_start; for (i = 0; i < end; i++) TRACE( "feature %d: %s\n", i, debugstr_hid_value_caps( HID_FEATURE_VALUE_CAPS( data ) + i ) ); end = data->number_link_collection_nodes; for (i = 0; i < end; i++) TRACE( "collection %d: %s\n", i, debugstr_hid_collection_node( HID_COLLECTION_NODES( data ) + i ) ); @@ -171,6 +171,7 @@ struct hid_parser_state ULONG bit_size[3][256]; USHORT byte_length[3]; USHORT caps_count[3]; + USHORT empty_caps[3]; USHORT data_count[3]; }; @@ -373,6 +374,7 @@ static BOOL parse_new_value_caps( struct hid_parser_state *state, HIDP_REPORT_TY if (!state->items.report_count) { + state->empty_caps[type] += usages_size; reset_local_items( state ); return TRUE; } @@ -435,6 +437,8 @@ static struct hid_preparsed_data *build_preparsed_data( struct hid_parser_state caps_size = state->caps_count[HidP_Input] + state->caps_count[HidP_Output] + state->caps_count[HidP_Feature]; + caps_size += state->empty_caps[HidP_Input] + state->empty_caps[HidP_Output] + + state->empty_caps[HidP_Feature]; caps_size *= sizeof(struct hid_value_caps); size = caps_size + FIELD_OFFSET(struct hid_preparsed_data, value_caps[0]) + @@ -446,26 +450,26 @@ static struct hid_preparsed_data *build_preparsed_data( struct hid_parser_state data->usage = state->usage; data->usage_page = state->usage_page; data->input_caps_start = 0; - data->input_caps_count = state->caps_count[HidP_Input]; - data->input_caps_end = data->input_caps_start + data->input_caps_count; + data->input_caps_count = state->caps_count[HidP_Input] + state->empty_caps[HidP_Input]; + data->input_caps_end = data->input_caps_start + state->caps_count[HidP_Input]; data->input_report_byte_length = state->byte_length[HidP_Input]; data->output_caps_start = data->input_caps_end; - data->output_caps_count = state->caps_count[HidP_Output]; - data->output_caps_end = data->output_caps_start + data->output_caps_count; + data->output_caps_count = state->caps_count[HidP_Output] + state->empty_caps[HidP_Output]; + data->output_caps_end = data->output_caps_start + state->caps_count[HidP_Output]; data->output_report_byte_length = state->byte_length[HidP_Output]; data->feature_caps_start = data->output_caps_end; - data->feature_caps_count = state->caps_count[HidP_Feature]; - data->feature_caps_end = data->feature_caps_start + data->feature_caps_count; + data->feature_caps_count = state->caps_count[HidP_Feature] + state->empty_caps[HidP_Feature]; + data->feature_caps_end = data->feature_caps_start + state->caps_count[HidP_Feature]; data->feature_report_byte_length = state->byte_length[HidP_Feature]; data->caps_size = caps_size; data->number_link_collection_nodes = state->number_link_collection_nodes; caps = HID_INPUT_VALUE_CAPS( data ); - memcpy( caps, state->values[0], data->input_caps_count * sizeof(*caps) ); + memcpy( caps, state->values[0], state->caps_count[HidP_Input] * sizeof(*caps) ); caps = HID_OUTPUT_VALUE_CAPS( data ); - memcpy( caps, state->values[1], data->output_caps_count * sizeof(*caps) ); + memcpy( caps, state->values[1], state->caps_count[HidP_Output] * sizeof(*caps) ); caps = HID_FEATURE_VALUE_CAPS( data ); - memcpy( caps, state->values[2], data->feature_caps_count * sizeof(*caps) ); + memcpy( caps, state->values[2], state->caps_count[HidP_Feature] * sizeof(*caps) ); nodes = HID_COLLECTION_NODES( data ); for (i = 0; i < data->number_link_collection_nodes; ++i) @@ -675,7 +679,7 @@ NTSTATUS WINAPI HidP_GetCollectionDescription( PHIDP_REPORT_DESCRIPTOR report_de device_desc->CollectionDesc[0].PreparsedData = (PHIDP_PREPARSED_DATA)preparsed; caps = HID_INPUT_VALUE_CAPS( preparsed ); - caps_end = caps + preparsed->input_caps_count; + caps_end = caps + preparsed->input_caps_end - preparsed->input_caps_start; for (; caps != caps_end; ++caps) { len = caps->start_byte * 8 + caps->start_bit + caps->bit_size * caps->report_count; @@ -684,7 +688,7 @@ NTSTATUS WINAPI HidP_GetCollectionDescription( PHIDP_REPORT_DESCRIPTOR report_de } caps = HID_OUTPUT_VALUE_CAPS( preparsed ); - caps_end = caps + preparsed->output_caps_count; + caps_end = caps + preparsed->output_caps_end - preparsed->output_caps_start; for (; caps != caps_end; ++caps) { len = caps->start_byte * 8 + caps->start_bit + caps->bit_size * caps->report_count; @@ -693,7 +697,7 @@ NTSTATUS WINAPI HidP_GetCollectionDescription( PHIDP_REPORT_DESCRIPTOR report_de } caps = HID_FEATURE_VALUE_CAPS( preparsed ); - caps_end = caps + preparsed->feature_caps_count; + caps_end = caps + preparsed->feature_caps_end - preparsed->feature_caps_start; for (; caps != caps_end; ++caps) { len = caps->start_byte * 8 + caps->start_bit + caps->bit_size * caps->report_count; From 35f8ff25f0312715f89578a81409e93cff4f05be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 24 Mar 2023 11:32:58 +0100 Subject: [PATCH 1365/2777] dinput/tests: Test BuildActionMap cases with multiple devices. (cherry picked from commit 83881f579f573123e172a2d40f203c15fa92079f) --- dlls/dinput/tests/joystick8.c | 210 ++++++++++++++++++++++++++++++++-- 1 file changed, 200 insertions(+), 10 deletions(-) diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index eef2d255595..5f3b0ab0fcf 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -51,6 +51,7 @@ DEFINE_GUID(GUID_action_mapping_1,0x00000001,0x0002,0x0003,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b); DEFINE_GUID(GUID_action_mapping_2,0x00010001,0x0002,0x0003,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b); +DEFINE_GUID(GUID_map_other_device,0x00020001,0x0002,0x0003,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b); static HRESULT (WINAPI *pRoGetActivationFactory)( HSTRING, REFIID, void** ); static HRESULT (WINAPI *pRoInitialize)( RO_INIT_TYPE ); @@ -208,8 +209,8 @@ static BOOL CALLBACK check_no_created_effect_objects( IDirectInputEffect *effect return DIENUM_CONTINUE; } -#define check_diactionw( a, b ) check_diactionw_( __LINE__, a, b ) -static void check_diactionw_( int line, const DIACTIONW *actual, const DIACTIONW *expected ) +#define check_diactionw( a, b ) check_diactionw_( __LINE__, a, b, FALSE ) +static void check_diactionw_( int line, const DIACTIONW *actual, const DIACTIONW *expected, BOOL todo ) { check_member_( __FILE__, line, *actual, *expected, "%#Ix", uAppData ); check_member_( __FILE__, line, *actual, *expected, "%#lx", dwSemantic ); @@ -218,13 +219,15 @@ static void check_diactionw_( int line, const DIACTIONW *actual, const DIACTIONW check_member_wstr_( __FILE__, line, *actual, *expected, lptszActionName ); else check_member_( __FILE__, line, *actual, *expected, "%p", lptszActionName ); + todo_wine_if( todo ) check_member_guid_( __FILE__, line, *actual, *expected, guidInstance ); check_member_( __FILE__, line, *actual, *expected, "%#lx", dwObjID ); + todo_wine_if( todo ) check_member_( __FILE__, line, *actual, *expected, "%#lx", dwHow ); } -#define check_diactionformatw( a, b ) check_diactionformatw_( __LINE__, a, b ) -static void check_diactionformatw_( int line, const DIACTIONFORMATW *actual, const DIACTIONFORMATW *expected ) +#define check_diactionformatw( a, b ) check_diactionformatw_( __LINE__, a, b, FALSE ) +static void check_diactionformatw_( int line, const DIACTIONFORMATW *actual, const DIACTIONFORMATW *expected, BOOL todo ) { DWORD i; check_member_( __FILE__, line, *actual, *expected, "%#lx", dwSize ); @@ -234,7 +237,7 @@ static void check_diactionformatw_( int line, const DIACTIONFORMATW *actual, con for (i = 0; i < min( actual->dwNumActions, expected->dwNumActions ); ++i) { winetest_push_context( "action[%lu]", i ); - check_diactionw_( line, actual->rgoAction + i, expected->rgoAction + i ); + check_diactionw_( line, actual->rgoAction + i, expected->rgoAction + i, todo && i >= 2 ); winetest_pop_context(); if (expected->dwActionSize != sizeof(DIACTIONW)) break; if (actual->dwActionSize != sizeof(DIACTIONW)) break; @@ -451,6 +454,68 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e .dwHow = DIAH_DEFAULT, .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ), }, + { + .dwSemantic = DIAXIS_ANY_Y_1, + .guidInstance = expect_guid_product, + .dwHow = DIAH_DEFAULT, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ), + }, + { + .dwSemantic = DIMOUSE_WHEEL, + }, + { + .dwSemantic = 0x81000410, + }, + }; + const DIACTIONW expect_actions_3[] = + { + { + .dwSemantic = DIAXIS_DRIVINGR_STEER, + .guidInstance = expect_guid_product, + .dwHow = DIAH_DEFAULT, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ), + }, + { + .dwSemantic = DIAXIS_ANY_Y_1, + .guidInstance = expect_guid_product, + .dwHow = DIAH_DEFAULT, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ), + }, + { + .dwSemantic = DIMOUSE_WHEEL, + .dwObjID = DIDFT_RELAXIS | DIDFT_MAKEINSTANCE( 2 ), + }, + { + .dwSemantic = 0x81000410, + .dwObjID = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0x10 ), + }, + }; + const DIACTIONW expect_actions_4[] = + { + { + .dwSemantic = DIAXIS_DRIVINGR_STEER, + .guidInstance = expect_guid_product, + .dwHow = DIAH_DEFAULT, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ), + }, + { + .dwSemantic = DIAXIS_ANY_Y_1, + .guidInstance = expect_guid_product, + .dwHow = DIAH_DEFAULT, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ), + }, + { + .dwSemantic = DIMOUSE_WHEEL, + .guidInstance = GUID_SysMouse, + .dwObjID = DIDFT_RELAXIS | DIDFT_MAKEINSTANCE( 2 ), + .dwHow = DIAH_DEFAULT, + }, + { + .dwSemantic = 0x81000410, + .guidInstance = GUID_SysKeyboard, + .dwObjID = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0x10 ), + .dwHow = DIAH_DEFAULT, + }, }; const DIACTIONW expect_filled_actions[ARRAY_SIZE(expect_actions)] = { @@ -520,6 +585,25 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e .lptszActionName = L"Steer", .uAppData = 8, }, + { + .dwSemantic = DIAXIS_ANY_Y_1, + .guidInstance = expect_guid_product, + .dwHow = DIAH_DEFAULT, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ), + .lptszActionName = L"Y Axis", + .uAppData = 9, + }, + { + .dwSemantic = DIMOUSE_WHEEL, + .lptszActionName = L"Wheel", + .uAppData = 10, + }, + { + .dwSemantic = 0x81000410, + .lptszActionName = L"Key", + .dwFlags = DIA_APPFIXED, + .uAppData = 11, + }, }; const DIACTIONFORMATW expect_action_format_1 = { @@ -541,7 +625,29 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e .rgoAction = (DIACTIONW *)expect_actions, .dwGenre = DIVIRTUAL_DRIVING_RACE, .guidActionMap = GUID_action_mapping_2, - .dwCRC = 0x9a7bb5e6, + .dwCRC = 0x6981e1f7, + }; + const DIACTIONFORMATW expect_action_format_3 = + { + .dwSize = sizeof(DIACTIONFORMATW), + .dwActionSize = sizeof(DIACTIONW), + .dwNumActions = ARRAY_SIZE(expect_actions_3), + .dwDataSize = 4 * ARRAY_SIZE(expect_actions_3), + .rgoAction = (DIACTIONW *)expect_actions_3, + .dwGenre = DIVIRTUAL_DRIVING_RACE, + .guidActionMap = GUID_action_mapping_2, + .dwCRC = 0xf8748d65, + }; + const DIACTIONFORMATW expect_action_format_4 = + { + .dwSize = sizeof(DIACTIONFORMATW), + .dwActionSize = sizeof(DIACTIONW), + .dwNumActions = ARRAY_SIZE(expect_actions_4), + .dwDataSize = 4 * ARRAY_SIZE(expect_actions_4), + .rgoAction = (DIACTIONW *)expect_actions_4, + .dwGenre = DIVIRTUAL_DRIVING_RACE, + .guidActionMap = GUID_action_mapping_2, + .dwCRC = 0xf8748d65, }; const DIACTIONFORMATW expect_action_format_2_filled = { @@ -556,7 +662,7 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e .lAxisMin = -128, .lAxisMax = +128, .tszActionMap = L"Action Map Filled", - .dwCRC = 0x3d98f717, + .dwCRC = 0x5ebf86a6, }; struct hid_expect injected_input[] = { @@ -594,14 +700,17 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e { 0, 0, 0, -1, 0, 0, 0, -43}, {+128, 0, 0, -1, 0, 0, 0, -128}, }; - const DIDEVICEOBJECTDATA expect_objdata[8] = + const DIDEVICEOBJECTDATA expect_objdata[11] = { + {.dwOfs = 0x20, .dwData = +128, .uAppData = 9}, {.dwOfs = 0x1c, .dwData = +128, .uAppData = 8}, {.dwOfs = 0xc, .dwData = +31500, .uAppData = 4}, {.dwOfs = 0, .dwData = +128, .uAppData = 1}, + {.dwOfs = 0x20, .dwData = -67, .uAppData = 9}, {.dwOfs = 0x1c, .dwData = -43, .uAppData = 8}, {.dwOfs = 0xc, .dwData = -1, .uAppData = 4}, {.dwOfs = 0, .dwData = 0, .uAppData = 1}, + {.dwOfs = 0x20, .dwData = -128, .uAppData = 9}, {.dwOfs = 0x1c, .dwData = -128, .uAppData = 8}, {.dwOfs = 0, .dwData = +128, .uAppData = 1}, }; @@ -629,6 +738,9 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e {.dwSemantic = DIAXIS_ANY_Z_2}, {.dwSemantic = DIAXIS_ANY_4}, {.dwSemantic = DIAXIS_DRIVINGR_STEER}, + {.dwSemantic = DIAXIS_ANY_Y_1}, + {.dwSemantic = DIMOUSE_WHEEL}, + {.dwSemantic = 0x81000410}, }; DIACTIONFORMATW action_format_1 = { @@ -650,6 +762,16 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e .dwGenre = DIVIRTUAL_DRIVING_RACE, .guidActionMap = GUID_action_mapping_2, }; + DIACTIONFORMATW action_format_3 = + { + .dwSize = sizeof(DIACTIONFORMATW), + .dwActionSize = sizeof(*default_actions), + .dwNumActions = ARRAY_SIZE(expect_actions_3), + .dwDataSize = 4 * ARRAY_SIZE(expect_actions_3), + .rgoAction = default_actions, + .dwGenre = DIVIRTUAL_DRIVING_RACE, + .guidActionMap = GUID_action_mapping_2, + }; DIACTIONW filled_actions[ARRAY_SIZE(expect_actions)] = { { @@ -722,6 +844,26 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e .lptszActionName = L"Steer", .uAppData = 8, }, + { + .dwSemantic = DIAXIS_ANY_Y_1, + .guidInstance = expect_guid_product, + .dwObjID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ), + .lptszActionName = L"Y Axis", + .uAppData = 9, + }, + { + .dwSemantic = DIMOUSE_WHEEL, + .guidInstance = expect_guid_product, + .lptszActionName = L"Wheel", + .uAppData = 10, + }, + { + .dwSemantic = 0x81000410, + .guidInstance = expect_guid_product, + .lptszActionName = L"Key", + .dwFlags = DIA_APPFIXED, + .uAppData = 11, + }, }; DIACTIONFORMATW action_format_2_filled = { @@ -775,7 +917,9 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e DIDEVICEOBJECTDATA objdata[ARRAY_SIZE(expect_objdata)]; DIACTIONW actions[ARRAY_SIZE(expect_actions)]; DWORD state[ARRAY_SIZE(expect_actions)]; + IDirectInputDevice8W *mouse, *keyboard; DIACTIONFORMATW action_format; + IDirectInput8W *dinput; WCHAR username[256]; DWORD i, res, flags; HRESULT hr; @@ -901,6 +1045,13 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); check_diactionformatw( &action_format, &expect_action_format_2 ); + action_format = action_format_2; + action_format.rgoAction = actions; + memcpy( actions, default_actions, sizeof(default_actions) ); + hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_PRESERVE ); + ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); + check_diactionformatw( &action_format, &expect_action_format_2 ); + hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_DEFAULT ); ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); @@ -1054,13 +1205,14 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e hr = IDirectInputDevice8_GetDeviceData( device, sizeof(*objdata), objdata, &res, DIGDD_PEEK ); todo_wine ok( hr == DI_BUFFEROVERFLOW, "GetDeviceData returned %#lx\n", hr ); - ok( res == 8, "got %lu expected %u\n", res, 8 ); + ok( res == ARRAY_SIZE(objdata), "got %lu expected %u\n", res, 8 ); while (res--) { winetest_push_context( "%lu", res ); check_member( objdata[res], expect_objdata[res], "%#lx", dwOfs ); ok( objdata[res].dwData == expect_objdata[res].dwData || - broken(objdata[res].dwData == -45 && expect_objdata[res].dwData == -43) /* 32-bit rounding */, + broken(objdata[res].dwData == -45 && expect_objdata[res].dwData == -43) /* 32-bit rounding */ || + broken(objdata[res].dwData == -71 && expect_objdata[res].dwData == -67) /* 32-bit rounding */, "got dwData %+ld\n", objdata[res].dwData ); check_member( objdata[res], expect_objdata[res], "%#Ix", uAppData ); winetest_pop_context(); @@ -1123,6 +1275,44 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e hr = IDirectInputDevice_GetProperty( device, DIPROP_USERNAME, &prop_username.diph ); ok( hr == DI_NOEFFECT, "GetProperty returned %#lx\n", hr ); ok( !wcscmp( prop_username.wsz, L"" ), "got username %s\n", debugstr_w(prop_username.wsz) ); + + + /* test BuildActionMap with multiple devices */ + + hr = DirectInput8Create( instance, 0x800, &IID_IDirectInput8W, (void **)&dinput, NULL ); + ok( hr == DI_OK, "DirectInput8Create returned %#lx\n", hr ); + + hr = IDirectInput8_CreateDevice( dinput, &GUID_SysMouse, &mouse, NULL ); + ok( hr == DI_OK, "DirectInput8Create returned %#lx\n", hr ); + hr = IDirectInput8_CreateDevice( dinput, &GUID_SysKeyboard, &keyboard, NULL ); + ok( hr == DI_OK, "DirectInput8Create returned %#lx\n", hr ); + + action_format = action_format_3; + action_format.rgoAction = actions; + memcpy( actions, default_actions + 7, sizeof(expect_actions_3) ); + hr = IDirectInputDevice8_BuildActionMap( mouse, &action_format, L"username", DIDBAM_DEFAULT ); + ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); + hr = IDirectInputDevice8_BuildActionMap( keyboard, &action_format, L"username", DIDBAM_DEFAULT ); + ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); + hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); + ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); + check_diactionformatw( &action_format, &expect_action_format_3 ); + + action_format = action_format_3; + action_format.rgoAction = actions; + memcpy( actions, default_actions + 7, sizeof(expect_actions_4) ); + hr = IDirectInputDevice8_BuildActionMap( mouse, &action_format, L"username", DIDBAM_PRESERVE ); + ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); + hr = IDirectInputDevice8_BuildActionMap( keyboard, &action_format, L"username", DIDBAM_PRESERVE ); + ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); + hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_PRESERVE ); + ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); + check_diactionformatw_( __LINE__, &action_format, &expect_action_format_4, TRUE ); + + IDirectInputDevice8_Release( keyboard ); + IDirectInputDevice8_Release( mouse ); + + IDirectInput8_Release( dinput ); } static void test_simple_joystick( DWORD version ) From c716b2c78eb952ec1a5c77e848739ef31d6e9bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Mar 2023 09:13:45 +0200 Subject: [PATCH 1366/2777] dinput/tests: Add more IDirectInput8_EnumDevicesBySemantics tests. (cherry picked from commit 8e63f68fb383b31b7c3f014b9717ff2f02c10688) --- dlls/dinput/tests/joystick8.c | 92 ++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 5f3b0ab0fcf..e0d4dd45d30 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -408,6 +408,76 @@ static void check_dinput_devices( DWORD version, DIDEVICEINSTANCEW *devinst ) } } +static BOOL CALLBACK enum_devices_by_semantic( const DIDEVICEINSTANCEW *instance, IDirectInputDevice8W *device, + DWORD flags, DWORD remaining, void *context ) +{ + const DIDEVICEINSTANCEW expect_joystick = + { + .dwSize = sizeof(DIDEVICEINSTANCEW), + .guidInstance = expect_guid_product, + .guidProduct = expect_guid_product, + .dwDevType = DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK, + .tszInstanceName = L"Wine Test", + .tszProductName = L"Wine Test", + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }; + const DIDEVICEINSTANCEW expect_keyboard = + { + .dwSize = sizeof(DIDEVICEINSTANCEW), + .guidInstance = GUID_SysKeyboard, + .guidProduct = GUID_SysKeyboard, + .dwDevType = (DI8DEVTYPEKEYBOARD_PCENH << 8) | DI8DEVTYPE_KEYBOARD, + .tszInstanceName = L"Keyboard", + .tszProductName = L"Keyboard", + }; + const DIDEVICEINSTANCEW expect_mouse = + { + .dwSize = sizeof(DIDEVICEINSTANCEW), + .guidInstance = GUID_SysMouse, + .guidProduct = GUID_SysMouse, + .dwDevType = (DI8DEVTYPEMOUSE_UNKNOWN << 8) | DI8DEVTYPE_MOUSE, + .tszInstanceName = L"Mouse", + .tszProductName = L"Mouse", + }; + const DIDEVICEINSTANCEW *expect_instance = NULL; + + ok( remaining <= 2, "got remaining %lu\n", remaining ); + + if (remaining == 2) + { + expect_instance = &expect_joystick; + todo_wine ok( flags == (context ? 3 : 0), "got flags %#lx\n", flags ); + } + else if (remaining == 1) + { + expect_instance = &expect_keyboard; + ok( flags == 1, "got flags %#lx\n", flags ); + } + else if (remaining == 0) + { + expect_instance = &expect_mouse; + ok( flags == 1, "got flags %#lx\n", flags ); + } + + check_member( *instance, *expect_instance, "%#lx", dwSize ); + if (expect_instance != &expect_joystick) check_member_guid( *instance, *expect_instance, guidInstance ); + check_member_guid( *instance, *expect_instance, guidProduct ); + todo_wine_if( expect_instance == &expect_mouse ) + check_member( *instance, *expect_instance, "%#lx", dwDevType ); + if (!localized) + { + check_member_wstr( *instance, *expect_instance, tszInstanceName ); + todo_wine_if( expect_instance != &expect_joystick ) + check_member_wstr( *instance, *expect_instance, tszProductName ); + } + check_member_guid( *instance, *expect_instance, guidFFDriver ); + check_member( *instance, *expect_instance, "%#x", wUsagePage ); + check_member( *instance, *expect_instance, "%#x", wUsage ); + + return DIENUM_CONTINUE; +} + static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE event ) { const DIACTIONW expect_actions[] = @@ -1277,7 +1347,7 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e ok( !wcscmp( prop_username.wsz, L"" ), "got username %s\n", debugstr_w(prop_username.wsz) ); - /* test BuildActionMap with multiple devices */ + /* test BuildActionMap with multiple devices and EnumDevicesBySemantics */ hr = DirectInput8Create( instance, 0x800, &IID_IDirectInput8W, (void **)&dinput, NULL ); ok( hr == DI_OK, "DirectInput8Create returned %#lx\n", hr ); @@ -1312,6 +1382,26 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e IDirectInputDevice8_Release( keyboard ); IDirectInputDevice8_Release( mouse ); + action_format = action_format_2; + action_format.rgoAction = actions; + memcpy( actions, default_actions, sizeof(default_actions) ); + hr = IDirectInput8_EnumDevicesBySemantics( dinput, NULL, &action_format, enum_devices_by_semantic, (void *)0xdeadbeef, 0 ); + ok( hr == DI_OK, "EnumDevicesBySemantics returned %#lx\n", hr ); + + action_format = action_format_3; + action_format.rgoAction = actions; + memcpy( actions, default_actions + 7, sizeof(expect_actions_4) ); + hr = IDirectInput8_EnumDevicesBySemantics( dinput, NULL, &action_format, enum_devices_by_semantic, (void *)0xdeadbeef, 0 ); + ok( hr == DI_OK, "EnumDevicesBySemantics returned %#lx\n", hr ); + + action_format = action_format_3; + action_format.rgoAction = actions; + memcpy( actions, default_actions + 9, 2 * sizeof(DIACTIONW) ); + action_format.dwNumActions = 2; + action_format.dwDataSize = 8; + hr = IDirectInput8_EnumDevicesBySemantics( dinput, NULL, &action_format, enum_devices_by_semantic, NULL, 0 ); + ok( hr == DI_OK, "EnumDevicesBySemantics returned %#lx\n", hr ); + IDirectInput8_Release( dinput ); } From 36fa842ee3fc890ae55895bac9c6c66850d1e45f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Mar 2023 10:04:19 +0200 Subject: [PATCH 1367/2777] dinput: Trace formats in (Build|Set)ActionMap and EnumDevicesBySemantics. (cherry picked from commit 2da8f5d2acda0ea56051e8ab9cc7f96f6dd8a537) --- dlls/dinput/device.c | 24 ++++++++++++++++++++++-- dlls/dinput/dinput.c | 12 ++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 41baa630989..b9f38330800 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -1815,7 +1815,7 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, BOOL load_success = FALSE; BOOL *mapped; - FIXME( "iface %p, format %p, username %s, flags %#lx stub!\n", iface, format, + TRACE( "iface %p, format %p, username %s, flags %#lx\n", iface, format, debugstr_w(username), flags ); if (!format) return DIERR_INVALIDPARAM; @@ -1825,6 +1825,16 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, if (format->dwNumActions * 4 != format->dwDataSize) return DIERR_INVALIDPARAM; + TRACE( "format guid %s, genre %#lx, name %s\n", debugstr_guid(&format->guidActionMap), + format->dwGenre, debugstr_w(format->tszActionMap) ); + for (i = 0; i < format->dwNumActions; i++) + { + DIACTIONW *action = format->rgoAction + i; + TRACE( " %lu: app_data %#Ix, semantic %#lx, flags %#lx, instance %s, obj_id %#lx, how %#lx, name %s\n", + i, action->uAppData, action->dwSemantic, action->dwFlags, debugstr_guid(&action->guidInstance), + action->dwObjID, action->dwHow, debugstr_w(action->lptszActionName) ); + } + action_end = format->rgoAction + format->dwNumActions; for (action = format->rgoAction; action < action_end; action++) { @@ -1968,12 +1978,22 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D int i, index; HRESULT hr; - FIXME( "iface %p, format %p, username %s, flags %#lx stub!\n", iface, format, + TRACE( "iface %p, format %p, username %s, flags %#lx\n", iface, format, debugstr_w(username), flags ); if (!format) return DIERR_INVALIDPARAM; if (flags != DIDSAM_DEFAULT && flags != DIDSAM_FORCESAVE && flags != DIDSAM_NOUSER) return DIERR_INVALIDPARAM; + TRACE( "format guid %s, genre %#lx, name %s\n", debugstr_guid(&format->guidActionMap), + format->dwGenre, debugstr_w(format->tszActionMap) ); + for (i = 0; i < format->dwNumActions; i++) + { + DIACTIONW *action = format->rgoAction + i; + TRACE( " %u: app_data %#Ix, semantic %#lx, flags %#lx, instance %s, obj_id %#lx, how %#lx, name %s\n", + i, action->uAppData, action->dwSemantic, action->dwFlags, debugstr_guid(&action->guidInstance), + action->dwObjID, action->dwHow, debugstr_w(action->lptszActionName) ); + } + if (!(data_format.rgodf = malloc( sizeof(DIOBJECTDATAFORMAT) * format->dwNumActions ))) return DIERR_OUTOFMEMORY; data_format.dwDataSize = format->dwDataSize; diff --git a/dlls/dinput/dinput.c b/dlls/dinput/dinput.c index 998573ad20d..cac47de74a4 100644 --- a/dlls/dinput/dinput.c +++ b/dlls/dinput/dinput.c @@ -519,6 +519,18 @@ static HRESULT WINAPI dinput8_EnumDevicesBySemantics( IDirectInput8W *iface, con FIXME( "iface %p, username %s, action_format %p, callback %p, context %p, flags %#lx stub!\n", iface, debugstr_w(username), action_format, callback, context, flags ); + if (!action_format) return DIERR_INVALIDPARAM; + + TRACE( "format guid %s, genre %#lx, name %s\n", debugstr_guid(&action_format->guidActionMap), + action_format->dwGenre, debugstr_w(action_format->tszActionMap) ); + for (i = 0; i < action_format->dwNumActions; i++) + { + DIACTIONW *action = action_format->rgoAction + i; + TRACE( " %u: app_data %#Ix, semantic %#lx, flags %#lx, instance %s, obj_id %#lx, how %#lx, name %s\n", + i, action->uAppData, action->dwSemantic, action->dwFlags, debugstr_guid(&action->guidInstance), + action->dwObjID, action->dwHow, debugstr_w(action->lptszActionName) ); + } + didevi.dwSize = sizeof(didevi); hr = IDirectInput8_EnumDevices( &impl->IDirectInput8W_iface, DI8DEVCLASS_GAMECTRL, From c7e4b854d2b0da43a8c7e42b4d365857db0ce17a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Mar 2023 09:40:50 +0200 Subject: [PATCH 1368/2777] dinput: Load action map from registry before resetting guid. (cherry picked from commit 18b5f7956f5b45540f5ee7e3ae29cf0948ae5ac2) --- dlls/dinput/device.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index b9f38330800..8b5d5a566bf 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -1812,7 +1812,6 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, DIACTIONW *action, *action_end; DWORD i, username_len = MAX_PATH; WCHAR username_buf[MAX_PATH]; - BOOL load_success = FALSE; BOOL *mapped; TRACE( "iface %p, format %p, username %s, flags %#lx\n", iface, format, @@ -1840,12 +1839,7 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, { if (!action->dwSemantic) return DIERR_INVALIDPARAM; if (action->dwFlags & DIA_APPMAPPED) action->dwHow = DIAH_APPREQUESTED; - else if (action->dwFlags & DIA_APPNOMAP) continue; - else - { - action->dwHow = 0; - action->guidInstance = GUID_NULL; - } + else action->dwHow = 0; } /* Unless asked the contrary by these flags, try to load a previous mapping */ @@ -1854,10 +1848,18 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, /* Retrieve logged user name if necessary */ if (username == NULL) GetUserNameW( username_buf, &username_len ); else lstrcpynW( username_buf, username, MAX_PATH ); - load_success = load_mapping_settings( impl, format, username_buf ); + load_mapping_settings( impl, format, username_buf ); + } + + action_end = format->rgoAction + format->dwNumActions; + for (action = format->rgoAction; action < action_end; action++) + { + if (action->dwHow == DIAH_APPREQUESTED || action->dwHow == DIAH_USERCONFIG) continue; + if (action->dwFlags & DIA_APPNOMAP) continue; + action->guidInstance = GUID_NULL; + action->dwHow = 0; } - if (load_success) return DI_OK; if (!(mapped = calloc( impl->device_format.dwNumObjs, sizeof(*mapped) ))) return DIERR_OUTOFMEMORY; action_end = format->rgoAction + format->dwNumActions; From 39967426e355f277069fd83127648bb0c7ed7db5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 24 Mar 2023 11:05:36 +0100 Subject: [PATCH 1369/2777] dinput: Check device type in BuildActionMap for specific semantics. (cherry picked from commit 782ad8f70c60b35c19a4469f322818f3d879933e) --- dlls/dinput/device.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 8b5d5a566bf..a152d552f5d 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -1785,7 +1785,8 @@ static HRESULT WINAPI dinput_device_WriteEffectToFile( IDirectInputDevice8W *ifa return DI_OK; } -static BOOL object_matches_semantic( const DIOBJECTDATAFORMAT *object, DWORD semantic, BOOL exact ) +static BOOL object_matches_semantic( const DIDEVICEINSTANCEW *instance, const DIOBJECTDATAFORMAT *object, + DWORD semantic, BOOL exact ) { DWORD value = semantic & 0xff, axis = (semantic >> 15) & 3, type; @@ -1799,7 +1800,15 @@ static BOOL object_matches_semantic( const DIOBJECTDATAFORMAT *object, DWORD sem } if (!(DIDFT_GETTYPE( object->dwType ) & type)) return FALSE; - if ((semantic & 0xf0000000) == 0x80000000) return object->dwOfs == value; + if ((semantic & 0xf0000000) == 0x80000000) + { + switch (semantic & 0x0f000000) + { + case 0x01000000: return (instance->dwDevType & 0xf) == DIDEVTYPE_KEYBOARD && object->dwOfs == value; + case 0x02000000: return (instance->dwDevType & 0xf) == DIDEVTYPE_MOUSE && object->dwOfs == value; + default: return FALSE; + } + } if (axis && (axis - 1) != DIDFT_GETINSTANCE( object->dwType )) return FALSE; return !exact || !value || value == DIDFT_GETINSTANCE( object->dwType ) + 1; } @@ -1872,7 +1881,7 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, for (object = impl->device_format.rgodf; object < object_end; object++) { if (mapped[object - impl->device_format.rgodf]) continue; - if (!object_matches_semantic( object, action->dwSemantic, TRUE )) continue; + if (!object_matches_semantic( &impl->instance, object, action->dwSemantic, TRUE )) continue; if ((action->dwFlags & DIA_FORCEFEEDBACK) && !(object->dwType & DIDFT_FFACTUATOR)) continue; action->dwObjID = object->dwType; action->guidInstance = impl->guid; @@ -1891,7 +1900,7 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, for (object = impl->device_format.rgodf; object < object_end; object++) { if (mapped[object - impl->device_format.rgodf]) continue; - if (!object_matches_semantic( object, action->dwSemantic, FALSE )) continue; + if (!object_matches_semantic( &impl->instance, object, action->dwSemantic, FALSE )) continue; if ((action->dwFlags & DIA_FORCEFEEDBACK) && !(object->dwType & DIDFT_FFACTUATOR)) continue; action->dwObjID = object->dwType; action->guidInstance = impl->guid; From bf2d62d2b0a4d03c3e42c9b8171bdb33bce98cc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Mar 2023 09:48:35 +0200 Subject: [PATCH 1370/2777] dinput: Implement DIDBAM_PRESERVE BuildActionMap flag. (cherry picked from commit cb987646a4df19e9b9cbc2c5a5a5b411d3835ec1) --- dlls/dinput/device.c | 4 ++++ dlls/dinput/tests/joystick8.c | 14 ++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index a152d552f5d..b4b39f0595e 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -1847,6 +1847,8 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, for (action = format->rgoAction; action < action_end; action++) { if (!action->dwSemantic) return DIERR_INVALIDPARAM; + if (flags == DIDBAM_PRESERVE && !IsEqualCLSID( &action->guidInstance, &GUID_NULL ) && + !IsEqualCLSID( &action->guidInstance, &impl->guid )) continue; if (action->dwFlags & DIA_APPMAPPED) action->dwHow = DIAH_APPREQUESTED; else action->dwHow = 0; } @@ -1864,6 +1866,8 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, for (action = format->rgoAction; action < action_end; action++) { if (action->dwHow == DIAH_APPREQUESTED || action->dwHow == DIAH_USERCONFIG) continue; + if (flags == DIDBAM_PRESERVE && !IsEqualCLSID( &action->guidInstance, &GUID_NULL ) && + !IsEqualCLSID( &action->guidInstance, &impl->guid )) continue; if (action->dwFlags & DIA_APPNOMAP) continue; action->guidInstance = GUID_NULL; action->dwHow = 0; diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index e0d4dd45d30..5b2390aba7b 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -209,8 +209,8 @@ static BOOL CALLBACK check_no_created_effect_objects( IDirectInputEffect *effect return DIENUM_CONTINUE; } -#define check_diactionw( a, b ) check_diactionw_( __LINE__, a, b, FALSE ) -static void check_diactionw_( int line, const DIACTIONW *actual, const DIACTIONW *expected, BOOL todo ) +#define check_diactionw( a, b ) check_diactionw_( __LINE__, a, b ) +static void check_diactionw_( int line, const DIACTIONW *actual, const DIACTIONW *expected ) { check_member_( __FILE__, line, *actual, *expected, "%#Ix", uAppData ); check_member_( __FILE__, line, *actual, *expected, "%#lx", dwSemantic ); @@ -219,15 +219,13 @@ static void check_diactionw_( int line, const DIACTIONW *actual, const DIACTIONW check_member_wstr_( __FILE__, line, *actual, *expected, lptszActionName ); else check_member_( __FILE__, line, *actual, *expected, "%p", lptszActionName ); - todo_wine_if( todo ) check_member_guid_( __FILE__, line, *actual, *expected, guidInstance ); check_member_( __FILE__, line, *actual, *expected, "%#lx", dwObjID ); - todo_wine_if( todo ) check_member_( __FILE__, line, *actual, *expected, "%#lx", dwHow ); } -#define check_diactionformatw( a, b ) check_diactionformatw_( __LINE__, a, b, FALSE ) -static void check_diactionformatw_( int line, const DIACTIONFORMATW *actual, const DIACTIONFORMATW *expected, BOOL todo ) +#define check_diactionformatw( a, b ) check_diactionformatw_( __LINE__, a, b ) +static void check_diactionformatw_( int line, const DIACTIONFORMATW *actual, const DIACTIONFORMATW *expected ) { DWORD i; check_member_( __FILE__, line, *actual, *expected, "%#lx", dwSize ); @@ -237,7 +235,7 @@ static void check_diactionformatw_( int line, const DIACTIONFORMATW *actual, con for (i = 0; i < min( actual->dwNumActions, expected->dwNumActions ); ++i) { winetest_push_context( "action[%lu]", i ); - check_diactionw_( line, actual->rgoAction + i, expected->rgoAction + i, todo && i >= 2 ); + check_diactionw_( line, actual->rgoAction + i, expected->rgoAction + i ); winetest_pop_context(); if (expected->dwActionSize != sizeof(DIACTIONW)) break; if (actual->dwActionSize != sizeof(DIACTIONW)) break; @@ -1377,7 +1375,7 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_PRESERVE ); ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_4, TRUE ); + check_diactionformatw( &action_format, &expect_action_format_4 ); IDirectInputDevice8_Release( keyboard ); IDirectInputDevice8_Release( mouse ); From baa7d07d91ea6a9a7cc58ce1b064708fab050e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Mar 2023 10:07:56 +0200 Subject: [PATCH 1371/2777] dinput: Rewrite IDirectInput8_EnumDevicesBySemantics. Simplifying and fixing it. (cherry picked from commit d62e2268d77c237e8430e158bb337958d88486ba) --- dlls/dinput/device.c | 6 +- dlls/dinput/device_private.h | 2 + dlls/dinput/dinput.c | 198 +++++++++++++++------------------- dlls/dinput/tests/joystick8.c | 2 +- 4 files changed, 90 insertions(+), 118 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index b4b39f0595e..19c3241e51f 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -1785,7 +1785,7 @@ static HRESULT WINAPI dinput_device_WriteEffectToFile( IDirectInputDevice8W *ifa return DI_OK; } -static BOOL object_matches_semantic( const DIDEVICEINSTANCEW *instance, const DIOBJECTDATAFORMAT *object, +BOOL device_object_matches_semantic( const DIDEVICEINSTANCEW *instance, const DIOBJECTDATAFORMAT *object, DWORD semantic, BOOL exact ) { DWORD value = semantic & 0xff, axis = (semantic >> 15) & 3, type; @@ -1885,7 +1885,7 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, for (object = impl->device_format.rgodf; object < object_end; object++) { if (mapped[object - impl->device_format.rgodf]) continue; - if (!object_matches_semantic( &impl->instance, object, action->dwSemantic, TRUE )) continue; + if (!device_object_matches_semantic( &impl->instance, object, action->dwSemantic, TRUE )) continue; if ((action->dwFlags & DIA_FORCEFEEDBACK) && !(object->dwType & DIDFT_FFACTUATOR)) continue; action->dwObjID = object->dwType; action->guidInstance = impl->guid; @@ -1904,7 +1904,7 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, for (object = impl->device_format.rgodf; object < object_end; object++) { if (mapped[object - impl->device_format.rgodf]) continue; - if (!object_matches_semantic( &impl->instance, object, action->dwSemantic, FALSE )) continue; + if (!device_object_matches_semantic( &impl->instance, object, action->dwSemantic, FALSE )) continue; if ((action->dwFlags & DIA_FORCEFEEDBACK) && !(object->dwType & DIDFT_FFACTUATOR)) continue; action->dwObjID = object->dwType; action->guidInstance = impl->guid; diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h index 5563618ff12..13201cc7178 100644 --- a/dlls/dinput/device_private.h +++ b/dlls/dinput/device_private.h @@ -128,6 +128,8 @@ extern void dinput_device_internal_release( struct dinput_device *device ); extern HRESULT dinput_device_init_device_format( IDirectInputDevice8W *iface ); extern int dinput_device_object_index_from_id( IDirectInputDevice8W *iface, DWORD id ); +extern BOOL device_object_matches_semantic( const DIDEVICEINSTANCEW *instance, const DIOBJECTDATAFORMAT *object, + DWORD semantic, BOOL exact ); extern BOOL get_app_key(HKEY*, HKEY*) DECLSPEC_HIDDEN; extern DWORD get_config_key( HKEY, HKEY, const WCHAR *, WCHAR *, DWORD ) DECLSPEC_HIDDEN; diff --git a/dlls/dinput/dinput.c b/dlls/dinput/dinput.c index cac47de74a4..f3003b652d8 100644 --- a/dlls/dinput/dinput.c +++ b/dlls/dinput/dinput.c @@ -45,19 +45,6 @@ static inline struct dinput *impl_from_IDirectInput8W( IDirectInput8W *iface ) return CONTAINING_RECORD( iface, struct dinput, IDirectInput8W_iface ); } -static DWORD diactionformat_priorityW( DIACTIONFORMATW *action_format, DWORD genre ) -{ - int i; - DWORD priorityFlags = 0; - - /* If there's at least one action for the device it's priority 1 */ - for (i = 0; i < action_format->dwNumActions; i++) - if ((action_format->rgoAction[i].dwSemantic & genre) == genre) - priorityFlags |= DIEDBS_MAPPEDPRI1; - - return priorityFlags; -} - #if defined __i386__ && defined _MSC_VER __declspec(naked) BOOL enum_callback_wrapper(void *callback, const void *instance, void *ref) { @@ -438,65 +425,82 @@ static HRESULT WINAPI dinput8_FindDevice( IDirectInput8W *iface, const GUID *gui return IDirectInput7_FindDevice( &impl->IDirectInput7W_iface, guid, name, instance_guid ); } -static BOOL should_enumerate_device( const WCHAR *username, DWORD flags, struct list *device_players, const GUID *guid ) +struct enum_device_by_semantics_params { - BOOL should_enumerate = TRUE; - struct DevicePlayer *device_player; + IDirectInput8W *iface; + const WCHAR *username; + DWORD flags; - /* Check if user owns impl device */ - if (flags & DIEDBSFL_THISUSER && username && *username) + IDirectInputDevice8W *devices[128]; + DWORD device_count; +}; + +static BOOL CALLBACK enum_device_by_semantics( const DIDEVICEINSTANCEW *instance, void *context ) +{ + struct enum_device_by_semantics_params *params = context; + DIDEVCAPS caps = {.dwSize = sizeof(caps)}; + DIPROPSTRING prop_username = { - should_enumerate = FALSE; - LIST_FOR_EACH_ENTRY( device_player, device_players, struct DevicePlayer, entry ) + .diph = { - if (IsEqualGUID( &device_player->instance_guid, guid )) - { - if (*device_player->username && !wcscmp( username, device_player->username )) - return TRUE; /* Device username matches */ - break; - } - } - } + .dwSize = sizeof(DIPROPSTRING), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + IDirectInputDevice8W *device; + BOOL ret = DIENUM_CONTINUE; + HRESULT hr; - /* Check if impl device is not owned by anyone */ - if (flags & DIEDBSFL_AVAILABLEDEVICES) + if (params->device_count >= ARRAY_SIZE(params->devices)) return DIENUM_STOP; + + if (FAILED(hr = IDirectInput8_CreateDevice( params->iface, &instance->guidInstance, &device, NULL ))) { - BOOL found = FALSE; - should_enumerate = FALSE; - LIST_FOR_EACH_ENTRY( device_player, device_players, struct DevicePlayer, entry ) - { - if (IsEqualGUID( &device_player->instance_guid, guid )) - { - if (*device_player->username) found = TRUE; - break; - } - } - if (!found) return TRUE; /* Device does not have a username */ + WARN( "Failed to create device, hr %#lx\n", hr ); + return DIENUM_CONTINUE; } - return should_enumerate; + if (FAILED(hr = IDirectInputDevice8_GetCapabilities( device, &caps ))) + WARN( "Failed to get device capabilities, hr %#lx\n", hr ); + if ((params->flags & DIEDBSFL_FORCEFEEDBACK) && !caps.dwFFDriverVersion) goto done; + + if (FAILED(hr = IDirectInputDevice8_GetProperty( device, DIPROP_USERNAME, &prop_username.diph ))) + WARN( "Failed to get device capabilities, hr %#lx\n", hr ); + else if ((params->flags & DIEDBSFL_THISUSER) && *params->username && wcscmp( params->username, prop_username.wsz )) + goto done; + else if ((params->flags & DIEDBSFL_AVAILABLEDEVICES) && *prop_username.wsz) + goto done; + + IDirectInputDevice_AddRef( device ); + params->devices[params->device_count++] = device; + +done: + IDirectInputDevice8_Release( device ); + return ret; } -struct enum_device_by_semantics_params +struct enum_device_object_semantics_params { - IDirectInput8W *iface; - const WCHAR *username; + DIDEVICEINSTANCEW instance; + DIACTIONFORMATW *format; DWORD flags; - - DIDEVICEINSTANCEW *instances; - DWORD instance_count; }; -static BOOL CALLBACK enum_device_by_semantics( const DIDEVICEINSTANCEW *instance, void *context ) +static BOOL CALLBACK enum_device_object_semantics( const DIDEVICEOBJECTINSTANCEW *obj, void *args ) { - struct enum_device_by_semantics_params *params = context; - struct dinput *impl = impl_from_IDirectInput8W( params->iface ); + struct enum_device_object_semantics_params *params = args; + DIACTIONFORMATW *format = params->format; + UINT i; - if (should_enumerate_device( params->username, params->flags, &impl->device_players, &instance->guidInstance )) + for (i = 0; format && i < format->dwNumActions; i++) { - params->instance_count++; - params->instances = realloc( params->instances, sizeof(DIDEVICEINSTANCEW) * params->instance_count ); - params->instances[params->instance_count - 1] = *instance; + DIOBJECTDATAFORMAT object_format = {.dwType = obj->dwType, .dwOfs = obj->dwOfs}; + BYTE dev_type = params->instance.dwDevType & 0xf; + DIACTIONW *action = format->rgoAction + i; + + if (!device_object_matches_semantic( ¶ms->instance, &object_format, action->dwSemantic, FALSE )) continue; + if (!(action->dwSemantic & 0x4000)) params->flags |= DIEDBS_MAPPEDPRI1; + else if (dev_type != DIDEVTYPE_KEYBOARD && dev_type != DIDEVTYPE_MOUSE) params->flags |= DIEDBS_MAPPEDPRI2; } return DIENUM_CONTINUE; @@ -505,18 +509,13 @@ static BOOL CALLBACK enum_device_by_semantics( const DIDEVICEINSTANCEW *instance static HRESULT WINAPI dinput8_EnumDevicesBySemantics( IDirectInput8W *iface, const WCHAR *username, DIACTIONFORMATW *action_format, LPDIENUMDEVICESBYSEMANTICSCBW callback, void *context, DWORD flags ) { - struct enum_device_by_semantics_params params = {.iface = iface, .username = username, .flags = flags}; - DWORD callbackFlags, enum_flags = DIEDFL_ATTACHEDONLY | (flags & DIEDFL_FORCEFEEDBACK); - static const GUID *guids[2] = {&GUID_SysKeyboard, &GUID_SysMouse}; - static const DWORD actionMasks[] = {DIKEYBOARD_MASK, DIMOUSE_MASK}; + struct enum_device_by_semantics_params params = {.iface = iface, .username = username ? username : L"", .flags = flags}; + DWORD enum_flags = DIEDFL_ATTACHEDONLY | (flags & DIEDFL_FORCEFEEDBACK); struct dinput *impl = impl_from_IDirectInput8W( iface ); - IDirectInputDevice8W *device; - DIDEVICEINSTANCEW didevi; unsigned int i = 0; HRESULT hr; - int remain; - FIXME( "iface %p, username %s, action_format %p, callback %p, context %p, flags %#lx stub!\n", + TRACE( "iface %p, username %s, action_format %p, callback %p, context %p, flags %#lx\n", iface, debugstr_w(username), action_format, callback, context, flags ); if (!action_format) return DIERR_INVALIDPARAM; @@ -531,64 +530,35 @@ static HRESULT WINAPI dinput8_EnumDevicesBySemantics( IDirectInput8W *iface, con action->dwObjID, action->dwHow, debugstr_w(action->lptszActionName) ); } - didevi.dwSize = sizeof(didevi); - - hr = IDirectInput8_EnumDevices( &impl->IDirectInput8W_iface, DI8DEVCLASS_GAMECTRL, - enum_device_by_semantics, ¶ms, enum_flags ); - if (FAILED(hr)) + if (FAILED(hr = IDirectInput8_EnumDevices( &impl->IDirectInput8W_iface, DI8DEVCLASS_ALL, + enum_device_by_semantics, ¶ms, enum_flags ))) { - free( params.instances ); - return hr; + WARN( "Failed to enumerate devices, hr %#lx\n", hr ); + goto cleanup; } - remain = params.instance_count; - /* Add keyboard and mouse to remaining device count */ - if (!(flags & DIEDBSFL_FORCEFEEDBACK)) + while (params.device_count--) { - for (i = 0; i < ARRAY_SIZE(guids); i++) - { - if (should_enumerate_device( username, flags, &impl->device_players, guids[i] )) remain++; - } - } - - for (i = 0; i < params.instance_count; i++) - { - callbackFlags = diactionformat_priorityW( action_format, action_format->dwGenre ); - IDirectInput_CreateDevice( iface, ¶ms.instances[i].guidInstance, &device, NULL ); - - if (callback( ¶ms.instances[i], device, callbackFlags, --remain, context ) == DIENUM_STOP) - { - free( params.instances ); - IDirectInputDevice_Release( device ); - return DI_OK; - } - IDirectInputDevice_Release( device ); - } - - free( params.instances ); - - if (flags & DIEDBSFL_FORCEFEEDBACK) return DI_OK; - - /* Enumerate keyboard and mouse */ - for (i = 0; i < ARRAY_SIZE(guids); i++) - { - if (should_enumerate_device( username, flags, &impl->device_players, guids[i] )) - { - callbackFlags = diactionformat_priorityW( action_format, actionMasks[i] ); - - IDirectInput_CreateDevice( iface, guids[i], &device, NULL ); - IDirectInputDevice_GetDeviceInfo( device, &didevi ); - - if (callback( &didevi, device, callbackFlags, --remain, context ) == DIENUM_STOP) - { - IDirectInputDevice_Release( device ); - return DI_OK; - } - IDirectInputDevice_Release( device ); - } + struct enum_device_object_semantics_params object_params = {.instance = {.dwSize = sizeof(DIDEVICEINSTANCEW)}, .format = action_format}; + IDirectInputDevice8W *device = params.devices[params.device_count]; + BOOL ret = DIENUM_STOP; + + if (FAILED(hr = IDirectInputDevice8_GetDeviceInfo( device, &object_params.instance ))) + WARN( "Failed to get device %p info, hr %#lx\n", device, hr ); + else if (FAILED(hr = IDirectInputDevice8_EnumObjects( device, enum_device_object_semantics, &object_params, DIDFT_ALL ))) + WARN( "Failed to enumerate device %p objects, hr %#lx\n", device, hr ); + else + ret = callback( &object_params.instance, device, object_params.flags, params.device_count, context ); + + IDirectInputDevice8_Release( device ); + if (ret == DIENUM_STOP) goto cleanup; } return DI_OK; + +cleanup: + while (params.device_count--) IDirectInputDevice8_Release( params.devices[params.device_count] ); + return hr; } static HRESULT WINAPI dinput8_ConfigureDevices( IDirectInput8W *iface, LPDICONFIGUREDEVICESCALLBACK callback, diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 5b2390aba7b..1115eef0bae 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -445,7 +445,7 @@ static BOOL CALLBACK enum_devices_by_semantic( const DIDEVICEINSTANCEW *instance if (remaining == 2) { expect_instance = &expect_joystick; - todo_wine ok( flags == (context ? 3 : 0), "got flags %#lx\n", flags ); + ok( flags == (context ? 3 : 0), "got flags %#lx\n", flags ); } else if (remaining == 1) { From 6bc0621f1856ed1ca1abdd207a70f71f0f345bf3 Mon Sep 17 00:00:00 2001 From: Michael Stefaniuc Date: Tue, 28 Mar 2023 19:34:11 +0200 Subject: [PATCH 1372/2777] dinput/tests: Use separate statements instead of the comma operator. (cherry picked from commit 4af8f423822716932e8c015587ea228312f7d317) --- dlls/dinput/tests/force_feedback.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c index b85aa529896..63c964d7631 100644 --- a/dlls/dinput/tests/force_feedback.c +++ b/dlls/dinput/tests/force_feedback.c @@ -1455,7 +1455,7 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO set_hid_expect( file, NULL, 0 ); desc = expect_desc; desc.dwDuration = INFINITE; - desc.dwTriggerButton = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFEFFECTTRIGGER, + desc.dwTriggerButton = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFEFFECTTRIGGER; hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_NODOWNLOAD | DIEP_DURATION | DIEP_TRIGGERBUTTON ); ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#lx\n", hr ); set_hid_expect( file, expect_update, sizeof(expect_update) ); @@ -1464,7 +1464,7 @@ static void test_periodic_effect( IDirectInputDevice8W *device, HANDLE file, DWO wait_hid_expect( file, 100 ); /* these updates are sent asynchronously */ desc = expect_desc; desc.dwDuration = INFINITE; - desc.dwTriggerButton = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFEFFECTTRIGGER, + desc.dwTriggerButton = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFEFFECTTRIGGER; hr = IDirectInputEffect_SetParameters( effect, &desc, DIEP_NODOWNLOAD | DIEP_DURATION | DIEP_TRIGGERBUTTON ); ok( hr == DI_DOWNLOADSKIPPED, "SetParameters returned %#lx\n", hr ); set_hid_expect( file, expect_update, sizeof(expect_update) ); From e536052c10b6b375bc5c8276078959fa157694b6 Mon Sep 17 00:00:00 2001 From: Michael Stefaniuc Date: Thu, 30 Mar 2023 19:35:16 +0200 Subject: [PATCH 1373/2777] dinput: Remove superfluous cast to self. (cherry picked from commit 6acbec19279c25c3751f459053bfad5f18a62245) --- dlls/dinput/dinput.c | 2 +- dlls/dinput/tests/dinput.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/dinput/dinput.c b/dlls/dinput/dinput.c index f3003b652d8..76c60b09db0 100644 --- a/dlls/dinput/dinput.c +++ b/dlls/dinput/dinput.c @@ -944,7 +944,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH DirectInput8Create( HINSTANCE hinst, DWORD vers if (outer || FAILED(hr = IDirectInput8_Initialize( (IDirectInput8W *)unknown, hinst, version ))) { - IUnknown_Release( (IUnknown *)unknown ); + IUnknown_Release( unknown ); *out = NULL; return hr; } diff --git a/dlls/dinput/tests/dinput.c b/dlls/dinput/tests/dinput.c index 682a5cbf97f..88db7be9288 100644 --- a/dlls/dinput/tests/dinput.c +++ b/dlls/dinput/tests/dinput.c @@ -84,7 +84,7 @@ static HRESULT WINAPI outer_QueryInterface( IUnknown *iface, REFIID iid, void ** if (IsEqualGUID( iid, &IID_IUnknown )) { - *obj = (IUnknown *)iface; + *obj = iface; return S_OK; } From 83770a10b3c80e0bb8091b370b8a5dda793bfd31 Mon Sep 17 00:00:00 2001 From: Florian Will Date: Sun, 2 Apr 2023 00:10:34 +0200 Subject: [PATCH 1374/2777] dinput/tests: Add EnumObjects callback return value test. (cherry picked from commit c04319e5a09dc2b2e85beeada1c4bf5bc31b8519) --- dlls/dinput/tests/device8.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dlls/dinput/tests/device8.c b/dlls/dinput/tests/device8.c index 841473085f6..539e4ac739e 100644 --- a/dlls/dinput/tests/device8.c +++ b/dlls/dinput/tests/device8.c @@ -988,6 +988,13 @@ static BOOL CALLBACK check_object_count( const DIDEVICEOBJECTINSTANCEW *obj, voi return DIENUM_CONTINUE; } +static BOOL CALLBACK check_object_count_bad_retval( const DIDEVICEOBJECTINSTANCEW *obj, void *args ) +{ + DWORD *count = args; + *count = *count + 1; + return -1; /* Invalid, but should CONTINUE. Only explicit DIENUM_STOP will stop enumeration. */ +} + static void test_sys_mouse( DWORD version ) { const DIDEVCAPS expect_caps = @@ -1333,6 +1340,11 @@ static void test_sys_mouse( DWORD version ) ok( check_objects_params.index >= check_objects_params.expect_count, "missing %u objects\n", check_objects_params.expect_count - check_objects_params.index ); + res = 0; + hr = IDirectInputDevice8_EnumObjects( device, check_object_count_bad_retval, &res, DIDFT_AXIS ); + ok( hr == DI_OK, "EnumObjects returned %#lx\n", hr ); + todo_wine ok( res == 3, "got %lu expected 3\n", res ); + objinst.dwSize = sizeof(DIDEVICEOBJECTINSTANCEW); res = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); hr = IDirectInputDevice8_GetObjectInfo( device, &objinst, res, DIPH_BYUSAGE ); From 015f02c0c59a7ad458f8929248f99b24afcdd29f Mon Sep 17 00:00:00 2001 From: Florian Will Date: Sun, 2 Apr 2023 00:13:47 +0200 Subject: [PATCH 1375/2777] dinput: Fix EnumObjects callback return value handling. This solves an issue in ZUSI 3 settings for DirectInput devices. Delphi defines the True value of the "C-compatible" LongBool type as -1, which wine interpreted to mean DIENUM_STOP because it is != DIENUM_CONTINUE. Change that logic so only an explicit DIENUM_STOP (= 0) return value stops the enumeration of objects. (cherry picked from commit dcb84a45f69f57efeb547f11ed5a8474ee74de1e) --- dlls/dinput/device.c | 4 +++- dlls/dinput/tests/device8.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 19c3241e51f..4db8bd943cb 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -730,7 +730,9 @@ static BOOL enum_objects_callback( struct dinput_device *impl, UINT index, struc struct enum_objects_params *params = data; if (instance->wUsagePage == HID_USAGE_PAGE_PID && !(instance->dwType & DIDFT_NODATA)) return DIENUM_CONTINUE; - return params->callback( instance, params->context ); + + /* Applications may return non-zero values instead of DIENUM_CONTINUE. */ + return params->callback( instance, params->context ) ? DIENUM_CONTINUE : DIENUM_STOP; } static HRESULT WINAPI dinput_device_EnumObjects( IDirectInputDevice8W *iface, LPDIENUMDEVICEOBJECTSCALLBACKW callback, diff --git a/dlls/dinput/tests/device8.c b/dlls/dinput/tests/device8.c index 539e4ac739e..270c232e320 100644 --- a/dlls/dinput/tests/device8.c +++ b/dlls/dinput/tests/device8.c @@ -1343,7 +1343,7 @@ static void test_sys_mouse( DWORD version ) res = 0; hr = IDirectInputDevice8_EnumObjects( device, check_object_count_bad_retval, &res, DIDFT_AXIS ); ok( hr == DI_OK, "EnumObjects returned %#lx\n", hr ); - todo_wine ok( res == 3, "got %lu expected 3\n", res ); + ok( res == 3, "got %lu expected 3\n", res ); objinst.dwSize = sizeof(DIDEVICEOBJECTINSTANCEW); res = MAKELONG( HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC ); From 572622ef859a45c6481624bb182d1cf090775d06 Mon Sep 17 00:00:00 2001 From: Florian Will Date: Tue, 4 Apr 2023 09:37:15 +0200 Subject: [PATCH 1376/2777] dinput/tests: Remove unmatched winetest_pop_context(). (cherry picked from commit c5a58aed089083bafbfdf153c3ee4553a09897fb) --- dlls/dinput/tests/joystick8.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 1115eef0bae..65bb21fd40e 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -4196,7 +4196,6 @@ static void test_many_axes_joystick(void) done: hid_device_stop( &desc, 1 ); cleanup_registry_keys(); - winetest_pop_context(); } static void test_driving_wheel_axes(void) @@ -4416,7 +4415,6 @@ static void test_driving_wheel_axes(void) done: hid_device_stop( &desc, 1 ); cleanup_registry_keys(); - winetest_pop_context(); } static BOOL test_winmm_joystick(void) From eef5922057ab915810b0b48f533fbf50475e4fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 6 Apr 2023 10:06:45 +0200 Subject: [PATCH 1377/2777] dinput/tests: Mark some tests as flaky to work around fvwm bug. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54594 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54713 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54774 (cherry picked from commit 3fad9cac5bd9ee69e0f1d37881aaf8f4c6fc40ba) --- dlls/dinput/tests/device8.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/dlls/dinput/tests/device8.c b/dlls/dinput/tests/device8.c index 270c232e320..fd422db94f0 100644 --- a/dlls/dinput/tests/device8.c +++ b/dlls/dinput/tests/device8.c @@ -393,11 +393,13 @@ void test_overlapped_format( DWORD version ) /* press D */ keybd_event( 0, DIK_D, KEYEVENTF_SCANCODE, 0 ); res = WaitForSingleObject( event, 5000 ); + flaky_wine_if( GetForegroundWindow() != hwnd && version == 0x800 ) /* FIXME: fvwm sometimes steals input focus */ ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); count = 10; hr = IDirectInputDevice_GetDeviceData( keyboard, data_size, NULL, &count, 0 ); ok( hr == DI_OK, "GetDeviceData returned %#lx\n", hr ); + flaky_wine_if( GetForegroundWindow() != hwnd && version == 0x800 ) /* FIXME: fvwm sometimes steals input focus */ ok( count == 1, "got count %lu\n", count ); memset( &state, 0xFF, sizeof(state) ); @@ -413,11 +415,13 @@ void test_overlapped_format( DWORD version ) /* release D */ keybd_event( 0, DIK_D, KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, 0 ); res = WaitForSingleObject( event, 5000 ); + flaky_wine_if( GetForegroundWindow() != hwnd && version == 0x800 ) /* FIXME: fvwm sometimes steals input focus */ ok( res == WAIT_OBJECT_0, "WaitForSingleObject returned %#lx\n", res ); count = 10; hr = IDirectInputDevice_GetDeviceData( keyboard, data_size, NULL, &count, 0 ); ok( hr == DI_OK, "GetDeviceData returned %#lx\n", hr ); + flaky_wine_if( GetForegroundWindow() != hwnd && version == 0x800 ) /* FIXME: fvwm sometimes steals input focus */ ok( count == 1, "got count %lu\n", count ); @@ -679,14 +683,19 @@ static void test_mouse_keyboard(void) IDirectInputDevice8_SetCooperativeLevel(di_keyboard, hwnd, DISCL_FOREGROUND|DISCL_EXCLUSIVE); hr = IDirectInputDevice8_Acquire(di_keyboard); + flaky_wine_if( GetForegroundWindow() != hwnd ) /* FIXME: fvwm sometimes steals input focus */ ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %#lx\n", hr); hr = IDirectInputDevice8_Acquire(di_mouse); + flaky_wine_if( GetForegroundWindow() != hwnd ) /* FIXME: fvwm sometimes steals input focus */ ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %#lx\n", hr); raw_devices_count = ARRAY_SIZE(raw_devices); memset(raw_devices, 0, sizeof(raw_devices)); hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); + flaky_wine_if( GetForegroundWindow() != hwnd ) /* FIXME: fvwm sometimes steals input focus */ ok(hr == 3, "GetRegisteredRawInputDevices returned %ld, raw_devices_count: %d\n", hr, raw_devices_count); + flaky_wine_if( GetForegroundWindow() != hwnd ) /* FIXME: fvwm sometimes steals input focus */ ok(raw_devices[0].dwFlags == (RIDEV_CAPTUREMOUSE|RIDEV_NOLEGACY), "Unexpected raw device flags: %#lx\n", raw_devices[0].dwFlags); + flaky_wine_if( GetForegroundWindow() != hwnd ) /* FIXME: fvwm sometimes steals input focus */ ok(raw_devices[2].dwFlags == (RIDEV_NOHOTKEYS|RIDEV_NOLEGACY), "Unexpected raw device flags: %#lx\n", raw_devices[1].dwFlags); hr = IDirectInputDevice8_Unacquire(di_keyboard); ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %#lx\n", hr); @@ -1573,7 +1582,7 @@ static void test_sys_mouse( DWORD version ) localized = old_localized; } -static void test_dik_codes( IDirectInputDevice8W *device, HANDLE event, HWND hwnd ) +static void test_dik_codes( IDirectInputDevice8W *device, HANDLE event, HWND hwnd, DWORD version ) { static const struct key2dik { @@ -1677,6 +1686,7 @@ static void test_dik_codes( IDirectInputDevice8W *device, HANDLE event, HWND hwn keybd_event( vkey, scan, KEYEVENTF_KEYUP, 0 ); res = WaitForSingleObject( event, 5000 ); + flaky_wine_if( GetForegroundWindow() != hwnd && version == 0x800 ) /* FIXME: fvwm sometimes steals input focus */ ok( !res, "WaitForSingleObject returned %#lx\n", res ); winetest_pop_context(); @@ -2182,7 +2192,7 @@ static void test_sys_keyboard( DWORD version ) ActivateKeyboardLayout( old_hkl, 0 ); UnloadKeyboardLayout( hkl ); - test_dik_codes( device, event, hwnd ); + test_dik_codes( device, event, hwnd, version ); CloseHandle( event ); DestroyWindow( hwnd ); From 2a4edc2ebb19bb67b97e14913a4f9dd0a4757f28 Mon Sep 17 00:00:00 2001 From: Francois Gouget Date: Wed, 5 Apr 2023 15:30:03 +0200 Subject: [PATCH 1378/2777] dinput/tests: Fix the spelling of an ok() message. (cherry picked from commit 089cfc7953fcfd62b2bbb023f72f78ee0965e595) --- dlls/dinput/tests/device8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/dinput/tests/device8.c b/dlls/dinput/tests/device8.c index fd422db94f0..aa8906ab45c 100644 --- a/dlls/dinput/tests/device8.c +++ b/dlls/dinput/tests/device8.c @@ -2145,7 +2145,7 @@ static void test_sys_keyboard( DWORD version ) hr = IDirectInputDevice8_GetDeviceState( device, sizeof(full_state), full_state ); ok( hr == DI_OK, "GetDeviceState returned %#lx\n", hr ); hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_OK, "Uncquire returned %#lx\n", hr ); + ok( hr == DI_OK, "Unacquire returned %#lx\n", hr ); hr = IDirectInputDevice8_SetDataFormat( device, &data_format ); ok( hr == DI_OK, "SetDataFormat returned %#lx\n", hr ); hr = IDirectInputDevice8_Acquire( device ); From 3f6c7c224470fc8d2369c9c14ea632f5474849e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 13 May 2023 13:21:31 +0200 Subject: [PATCH 1379/2777] dinput/tests: Avoid leaking a IDirectInput reference (Valgrind). (cherry picked from commit fefc1e57d22666867852542d4e70cc535992d84e) --- dlls/dinput/tests/device8.c | 1 + dlls/dinput/tests/force_feedback.c | 8 +++++++- dlls/dinput/tests/joystick8.c | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/dlls/dinput/tests/device8.c b/dlls/dinput/tests/device8.c index aa8906ab45c..a7a635e4a0a 100644 --- a/dlls/dinput/tests/device8.c +++ b/dlls/dinput/tests/device8.c @@ -426,6 +426,7 @@ void test_overlapped_format( DWORD version ) IUnknown_Release( keyboard ); + IDirectInput_Release( dinput ); DestroyWindow( hwnd ); CloseHandle( event ); diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c index 63c964d7631..9858fe0c1e8 100644 --- a/dlls/dinput/tests/force_feedback.c +++ b/dlls/dinput/tests/force_feedback.c @@ -213,7 +213,7 @@ static void check_dinput_devices( DWORD version, DIDEVICEINSTANCEW *devinst ) { IDirectInput8W *di8; IDirectInputW *di; - ULONG count; + ULONG count, ref; HRESULT hr; if (version >= 0x800) @@ -270,6 +270,9 @@ static void check_dinput_devices( DWORD version, DIDEVICEINSTANCEW *devinst ) if ((devinst->dwDevType & 0xff) != DI8DEVTYPE_SUPPLEMENTAL) ok( hr == DI_OK, "EnumDevices returned: %#lx\n", hr ); else ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#lx\n", hr ); ok( count == 0, "got count %lu, expected 0\n", count ); + + ref = IDirectInput8_Release( di8 ); + ok( ref == 0, "Release returned %ld\n", ref ); } else { @@ -324,6 +327,9 @@ static void check_dinput_devices( DWORD version, DIDEVICEINSTANCEW *devinst ) hr = IDirectInput_EnumDevices( di, 0x14, enum_device_count, &count, DIEDFL_ALLDEVICES ); ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#lx\n", hr ); + + ref = IDirectInput_Release( di ); + ok( ref == 0, "Release returned %ld\n", ref ); } } diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 65bb21fd40e..191e5273e1d 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -349,6 +349,8 @@ static void check_dinput_devices( DWORD version, DIDEVICEINSTANCEW *devinst ) ref = IDirectInputDevice8_Release( device ); ok( ref == 0, "Release returned %ld\n", ref ); + ref = IDirectInput8_Release( di8 ); + ok( ref == 0, "Release returned %ld\n", ref ); } else { @@ -403,6 +405,8 @@ static void check_dinput_devices( DWORD version, DIDEVICEINSTANCEW *devinst ) hr = IDirectInput_EnumDevices( di, 0x14, enum_device_count, &count, DIEDFL_ALLDEVICES ); ok( hr == DIERR_INVALIDPARAM, "EnumDevices returned: %#lx\n", hr ); + ref = IDirectInput_Release( di ); + ok( ref == 0, "Release returned %ld\n", ref ); } } From 50774c22ff40cdac22382dc618cda9a6727e6bb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 13 May 2023 13:25:58 +0200 Subject: [PATCH 1380/2777] dinput/tests: Avoid leaking data in add_file_to_catalog (Valgrind). (cherry picked from commit dde9cef0ffde7248c886ab8e2f2227b304e08723) --- dlls/dinput/tests/hid.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c index bd01d1ae868..87df44ac9a2 100644 --- a/dlls/dinput/tests/hid.c +++ b/dlls/dinput/tests/hid.c @@ -442,6 +442,7 @@ static void add_file_to_catalog( HANDLE catalog, const WCHAR *file ) sizeof(L"2:6.0"), (BYTE *)L"2:6.0" ); ok( ret, "Failed to write attr, error %lu\n", GetLastError() ); } + free( indirect_data ); } static void unload_driver( SC_HANDLE service ) From d5fb251111107c6b709094a683d90f3c55ec22b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 16 May 2023 14:12:19 +0200 Subject: [PATCH 1381/2777] dinput/tests: Add a zero-terminator for hardware ids (Valgrind). (cherry picked from commit cbbb88f2b4fd5d75eab9093aad07320b66e9f4a6) --- dlls/dinput/tests/hid.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c index 87df44ac9a2..9a27f8e93ac 100644 --- a/dlls/dinput/tests/hid.c +++ b/dlls/dinput/tests/hid.c @@ -591,7 +591,7 @@ static BOOL find_hid_device_path( WCHAR *device_path ) BOOL bus_device_start(void) { - static const WCHAR bus_hardware_id[] = L"WINETEST\\BUS"; + static const WCHAR bus_hardware_ids[] = L"WINETEST\\BUS\0"; SP_DEVINFO_DATA device = {sizeof(SP_DEVINFO_DATA)}; const WCHAR *service_name = L"winetest_bus"; WCHAR path[MAX_PATH], filename[MAX_PATH]; @@ -666,7 +666,7 @@ BOOL bus_device_start(void) ret = SetupDiCreateDeviceInfoW( set, L"root\\winetest\\0", &GUID_NULL, NULL, NULL, 0, &device ); ok( ret, "failed to create device, error %#lx\n", GetLastError() ); - ret = SetupDiSetDeviceRegistryPropertyW( set, &device, SPDRP_HARDWAREID, (const BYTE *)bus_hardware_id, sizeof(bus_hardware_id) ); + ret = SetupDiSetDeviceRegistryPropertyW( set, &device, SPDRP_HARDWAREID, (const BYTE *)bus_hardware_ids, sizeof(bus_hardware_ids) ); ok( ret, "failed to create set hardware ID, error %lu\n", GetLastError() ); ret = SetupDiCallClassInstaller( DIF_REGISTERDEVICE, set, &device ); @@ -677,7 +677,7 @@ BOOL bus_device_start(void) GetFullPathNameW( L"winetest.inf", ARRAY_SIZE(path), path, NULL ); - ret = UpdateDriverForPlugAndPlayDevicesW( NULL, bus_hardware_id, path, INSTALLFLAG_FORCE, &need_reboot ); + ret = UpdateDriverForPlugAndPlayDevicesW( NULL, bus_hardware_ids, path, INSTALLFLAG_FORCE, &need_reboot ); ok( ret, "failed to install device, error %lu\n", GetLastError() ); ok( !need_reboot, "expected no reboot necessary\n" ); From 872e12037ddc52169dbe737c3375d6b78b9adeb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 19 May 2023 14:19:28 +0200 Subject: [PATCH 1382/2777] dinput/tests: Add some tests with keyboard action mapping. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54917 (cherry picked from commit bed1ecba2fba310916bee84e4b767a11a3f01828) --- dlls/dinput/tests/device8.c | 118 ++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/dlls/dinput/tests/device8.c b/dlls/dinput/tests/device8.c index a7a635e4a0a..3c8cc12ddf2 100644 --- a/dlls/dinput/tests/device8.c +++ b/dlls/dinput/tests/device8.c @@ -34,6 +34,10 @@ #include "dinput_test.h" +#include "initguid.h" + +DEFINE_GUID(GUID_keyboard_action_mapping,0x00000001,0x0002,0x0003,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b); + struct enum_data { DWORD version; @@ -1704,6 +1708,60 @@ static void test_dik_codes( IDirectInputDevice8W *device, HANDLE event, HWND hwn ok( hr == DI_OK, "Unacquire returned %#lx\n", hr ); } +#define check_member_str_( file, line, val, exp, member ) \ + ok_(file, line)( !strcmp( (val).member, (exp).member ), "got " #member " %s\n", \ + debugstr_a((val).member) ) +#define check_member_str( val, exp, member ) \ + check_member_str_( __FILE__, __LINE__, val, exp, member ) + +#define check_diactionA( a, b ) check_diactionA_( __LINE__, a, b ) +static void check_diactionA_( int line, const DIACTIONA *actual, const DIACTIONA *expected ) +{ + check_member_( __FILE__, line, *actual, *expected, "%#Ix", uAppData ); + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwSemantic ); + todo_wine_if( expected->dwSemantic == 0x810004c8 ) + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwFlags ); + if (actual->lptszActionName && expected->lptszActionName) + check_member_str_( __FILE__, line, *actual, *expected, lptszActionName ); + else + check_member_( __FILE__, line, *actual, *expected, "%p", lptszActionName ); + todo_wine_if( expected->dwSemantic == 0x810004c8 ) + check_member_guid_( __FILE__, line, *actual, *expected, guidInstance ); + todo_wine_if( expected->dwSemantic == 0x810004c8 ) + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwObjID ); + todo_wine_if( expected->dwSemantic == 0x810004c8 ) + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwHow ); +} + +#define check_diactionformatA( a, b ) check_diactionformatA_( __LINE__, a, b ) +static void check_diactionformatA_( int line, const DIACTIONFORMATA *actual, const DIACTIONFORMATA *expected ) +{ + DWORD i; + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwSize ); + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwActionSize ); + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwDataSize ); + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwNumActions ); + for (i = 0; i < min( actual->dwNumActions, expected->dwNumActions ); ++i) + { + winetest_push_context( "action[%lu]", i ); + check_diactionA_( line, actual->rgoAction + i, expected->rgoAction + i ); + winetest_pop_context(); + if (expected->dwActionSize != sizeof(DIACTIONA)) break; + if (actual->dwActionSize != sizeof(DIACTIONA)) break; + } + check_member_guid_( __FILE__, line, *actual, *expected, guidActionMap ); + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwGenre ); + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwBufferSize ); + check_member_( __FILE__, line, *actual, *expected, "%+ld", lAxisMin ); + check_member_( __FILE__, line, *actual, *expected, "%+ld", lAxisMax ); + check_member_( __FILE__, line, *actual, *expected, "%p", hInstString ); + check_member_( __FILE__, line, *actual, *expected, "%ld", ftTimeStamp.dwLowDateTime ); + check_member_( __FILE__, line, *actual, *expected, "%ld", ftTimeStamp.dwHighDateTime ); + todo_wine + check_member_( __FILE__, line, *actual, *expected, "%#lx", dwCRC ); + check_member_str_( __FILE__, line, *actual, *expected, tszActionMap ); +} + static void test_sys_keyboard( DWORD version ) { const DIDEVCAPS expect_caps = @@ -2205,6 +2263,64 @@ static void test_sys_keyboard( DWORD version ) localized = old_localized; } +static void test_sys_keyboard_action_format(void) +{ + DIACTIONA actions[] = + { + {.uAppData = 0x1, .dwSemantic = 0x810004c8, .dwFlags = DIA_APPNOMAP}, + {.uAppData = 0x1, .dwSemantic = 0x81000448, .dwFlags = 0}, + }; + const DIACTIONA expect_actions[ARRAY_SIZE(actions)] = + { + {.uAppData = 0x1, .dwSemantic = 0x810004c8, .dwFlags = 0, .guidInstance = GUID_SysKeyboard, .dwObjID = 0xc804, .dwHow = DIAH_DEFAULT}, + {.uAppData = 0x1, .dwSemantic = 0x81000448, .dwFlags = 0, .guidInstance = GUID_SysKeyboard, .dwObjID = 0x4804, .dwHow = DIAH_DEFAULT}, + }; + DIACTIONFORMATA action_format = + { + .dwSize = sizeof(DIACTIONFORMATA), + .dwActionSize = sizeof(DIACTIONA), + .dwNumActions = ARRAY_SIZE(actions), + .dwDataSize = ARRAY_SIZE(actions) * 4, + .rgoAction = actions, + .dwGenre = 0x1000000, + .guidActionMap = GUID_keyboard_action_mapping, + }; + const DIACTIONFORMATA expect_action_format = + { + .dwSize = sizeof(DIACTIONFORMATA), + .dwActionSize = sizeof(DIACTIONA), + .dwNumActions = ARRAY_SIZE(expect_actions), + .dwDataSize = ARRAY_SIZE(expect_actions) * 4, + .rgoAction = (DIACTIONA *)expect_actions, + .dwGenre = 0x1000000, + .guidActionMap = GUID_keyboard_action_mapping, + .dwCRC = 0x68e7e227, + }; + IDirectInputDevice8A *device; + IDirectInput8A *dinput; + HRESULT hr; + LONG ref; + + hr = DirectInput8Create( instance, 0x800, &IID_IDirectInput8A, (void **)&dinput, NULL ); + ok( hr == DI_OK, "CreateDevice returned %#lx\n", hr ); + hr = IDirectInput_CreateDevice( dinput, &GUID_SysKeyboard, &device, NULL ); + ok( hr == DI_OK, "CreateDevice returned %#lx\n", hr ); + ref = IDirectInput_Release( dinput ); + ok( ref == 0, "Release returned %ld\n", ref ); + + hr = IDirectInputDevice8_BuildActionMap( device, &action_format, NULL, 2 ); + ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); + check_diactionformatA(&action_format, &expect_action_format); + + hr = IDirectInputDevice8_SetActionMap( device, &action_format, NULL, 2 ); + ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetActionMap( device, &action_format, NULL, 0 ); + ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); + + ref = IDirectInputDevice8_Release( device ); + ok( ref == 0, "Release returned %ld\n", ref ); +} + START_TEST(device8) { dinput_test_init(); @@ -2225,6 +2341,8 @@ START_TEST(device8) test_sys_keyboard( 0x700 ); test_sys_keyboard( 0x800 ); + test_sys_keyboard_action_format(); + test_mouse_keyboard(); test_keyboard_events(); test_appdata_property(); From 290dd0c1f91f0fb07be003bf03132443a92a2cdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 19 May 2023 17:09:52 +0200 Subject: [PATCH 1383/2777] dinput: Delete the action mapping registry key on SetActionMap. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54917 (cherry picked from commit b95c820557499ad52a386fcc2354a7590573f7c7) --- dlls/dinput/device.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 4db8bd943cb..4f76168a1a3 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -323,19 +323,20 @@ int dinput_device_object_index_from_id( IDirectInputDevice8W *iface, DWORD id ) * Retrieves an open registry key to save the mapping, parametrized for an username, * specific device and specific action mapping guid. */ -static HKEY get_mapping_key(const WCHAR *device, const WCHAR *username, const WCHAR *guid) +static HKEY get_mapping_key( const WCHAR *device, const WCHAR *username, const WCHAR *guid, BOOL delete ) { - static const WCHAR *subkey = L"Software\\Wine\\DirectInput\\Mappings\\%s\\%s\\%s"; - HKEY hkey; + static const WCHAR format[] = L"Software\\Wine\\DirectInput\\Mappings\\%s\\%s\\%s"; + SIZE_T len = wcslen( format ) + wcslen( username ) + wcslen( device ) + wcslen( guid ) + 1; WCHAR *keyname; + HKEY hkey; - SIZE_T len = wcslen( subkey ) + wcslen( username ) + wcslen( device ) + wcslen( guid ) + 1; - keyname = malloc( sizeof(WCHAR) * len ); - swprintf( keyname, len, subkey, username, device, guid ); + if (!(keyname = malloc( sizeof(WCHAR) * len ))) return 0; /* The key used is HKCU\Software\Wine\DirectInput\Mappings\[username]\[device]\[mapping_guid] */ - if (RegCreateKeyW(HKEY_CURRENT_USER, keyname, &hkey)) - hkey = 0; + swprintf( keyname, len, format, username, device, guid ); + + if (delete) RegDeleteTreeW( HKEY_CURRENT_USER, keyname ); + if (RegCreateKeyW( HKEY_CURRENT_USER, keyname, &hkey )) hkey = 0; free( keyname ); @@ -355,9 +356,7 @@ static HRESULT save_mapping_settings(IDirectInputDevice8W *iface, LPDIACTIONFORM if (StringFromCLSID(&lpdiaf->guidActionMap, &guid_str) != S_OK) return DI_SETTINGSNOTSAVED; - hkey = get_mapping_key(didev.tszInstanceName, lpszUsername, guid_str); - - if (!hkey) + if (!(hkey = get_mapping_key( didev.tszInstanceName, lpszUsername, guid_str, TRUE ))) { CoTaskMemFree(guid_str); return DI_SETTINGSNOTSAVED; @@ -398,9 +397,7 @@ static BOOL load_mapping_settings( struct dinput_device *This, LPDIACTIONFORMATW if (StringFromCLSID(&lpdiaf->guidActionMap, &guid_str) != S_OK) return FALSE; - hkey = get_mapping_key(didev.tszInstanceName, username, guid_str); - - if (!hkey) + if (!(hkey = get_mapping_key( didev.tszInstanceName, username, guid_str, FALSE ))) { CoTaskMemFree(guid_str); return FALSE; From 98585da6e014a8ffa5286f23fd2de862d5631109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 19 May 2023 17:28:40 +0200 Subject: [PATCH 1384/2777] dinput: Reset action map mapping before loading the registry mapping. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54917 (cherry picked from commit 5b648e7e5db10dc5e495a912210b988f2b0b1b5f) --- dlls/dinput/device.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 4f76168a1a3..8fc54d8ce32 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -1850,6 +1850,8 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, !IsEqualCLSID( &action->guidInstance, &impl->guid )) continue; if (action->dwFlags & DIA_APPMAPPED) action->dwHow = DIAH_APPREQUESTED; else action->dwHow = 0; + if (action->dwHow == DIAH_APPREQUESTED || action->dwHow == DIAH_USERCONFIG) continue; + if (!(action->dwFlags & DIA_APPNOMAP)) action->guidInstance = GUID_NULL; } /* Unless asked the contrary by these flags, try to load a previous mapping */ @@ -1861,17 +1863,6 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, load_mapping_settings( impl, format, username_buf ); } - action_end = format->rgoAction + format->dwNumActions; - for (action = format->rgoAction; action < action_end; action++) - { - if (action->dwHow == DIAH_APPREQUESTED || action->dwHow == DIAH_USERCONFIG) continue; - if (flags == DIDBAM_PRESERVE && !IsEqualCLSID( &action->guidInstance, &GUID_NULL ) && - !IsEqualCLSID( &action->guidInstance, &impl->guid )) continue; - if (action->dwFlags & DIA_APPNOMAP) continue; - action->guidInstance = GUID_NULL; - action->dwHow = 0; - } - if (!(mapped = calloc( impl->device_format.dwNumObjs, sizeof(*mapped) ))) return DIERR_OUTOFMEMORY; action_end = format->rgoAction + format->dwNumActions; From ff24549d894a1049a36edc65cb716b2a39a55d63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 19 May 2023 17:29:07 +0200 Subject: [PATCH 1385/2777] dinput: Clear DIA_APPNOMAP BuildActionMap flag with specific device semantic. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54917 (cherry picked from commit df6bc20b90b54e3993cedaa79dab0e50abb19604) --- dlls/dinput/device.c | 1 + dlls/dinput/tests/device8.c | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 8fc54d8ce32..b761b3e9d6d 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -1851,6 +1851,7 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, if (action->dwFlags & DIA_APPMAPPED) action->dwHow = DIAH_APPREQUESTED; else action->dwHow = 0; if (action->dwHow == DIAH_APPREQUESTED || action->dwHow == DIAH_USERCONFIG) continue; + if ((action->dwSemantic & 0xf0000000) == 0x80000000) action->dwFlags &= ~DIA_APPNOMAP; if (!(action->dwFlags & DIA_APPNOMAP)) action->guidInstance = GUID_NULL; } diff --git a/dlls/dinput/tests/device8.c b/dlls/dinput/tests/device8.c index 3c8cc12ddf2..601ba750b15 100644 --- a/dlls/dinput/tests/device8.c +++ b/dlls/dinput/tests/device8.c @@ -1719,17 +1719,13 @@ static void check_diactionA_( int line, const DIACTIONA *actual, const DIACTIONA { check_member_( __FILE__, line, *actual, *expected, "%#Ix", uAppData ); check_member_( __FILE__, line, *actual, *expected, "%#lx", dwSemantic ); - todo_wine_if( expected->dwSemantic == 0x810004c8 ) check_member_( __FILE__, line, *actual, *expected, "%#lx", dwFlags ); if (actual->lptszActionName && expected->lptszActionName) check_member_str_( __FILE__, line, *actual, *expected, lptszActionName ); else check_member_( __FILE__, line, *actual, *expected, "%p", lptszActionName ); - todo_wine_if( expected->dwSemantic == 0x810004c8 ) check_member_guid_( __FILE__, line, *actual, *expected, guidInstance ); - todo_wine_if( expected->dwSemantic == 0x810004c8 ) check_member_( __FILE__, line, *actual, *expected, "%#lx", dwObjID ); - todo_wine_if( expected->dwSemantic == 0x810004c8 ) check_member_( __FILE__, line, *actual, *expected, "%#lx", dwHow ); } From aa1982fefe7e41546fbaf3612ec8435c95ae7cdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 19 May 2023 21:38:14 +0200 Subject: [PATCH 1386/2777] dinput: Avoid remapping already mapped objects in BuildActionMap. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54917 (cherry picked from commit cb7bb2284c37d0dbd58bfe72594fabb7ab398e05) --- dlls/dinput/device.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index b761b3e9d6d..427d3895700 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -1866,6 +1866,23 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, if (!(mapped = calloc( impl->device_format.dwNumObjs, sizeof(*mapped) ))) return DIERR_OUTOFMEMORY; + /* check already mapped objects */ + action_end = format->rgoAction + format->dwNumActions; + for (action = format->rgoAction; action < action_end; action++) + { + if (!action->dwHow || !action->dwObjID) continue; + if (!IsEqualGUID(&action->guidInstance, &impl->guid)) continue; + + object_end = impl->device_format.rgodf + impl->device_format.dwNumObjs; + for (object = impl->device_format.rgodf; object < object_end; object++) + { + if (action->dwObjID != object->dwType) continue; + mapped[object - impl->device_format.rgodf] = TRUE; + break; + } + } + + /* map any unmapped priority 1 objects */ action_end = format->rgoAction + format->dwNumActions; for (action = format->rgoAction; action < action_end; action++) { @@ -1886,6 +1903,7 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, } } + /* map any unmapped priority 2 objects */ for (action = format->rgoAction; action < action_end; action++) { if (action->dwHow || (action->dwFlags & DIA_APPNOMAP)) continue; /* already mapped */ From b5d7c8d3b63aed7800a7a75308cf467d61e81576 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 1 Feb 2023 01:34:12 -0500 Subject: [PATCH 1387/2777] ir50_32: Add stub dll. (cherry picked from commit 91c1c05f5b0d224b664ae5fd6c0bc93db4eab872) CW-Bug-Id: #21175 --- configure.ac | 1 + dlls/ir50_32/Makefile.in | 7 ++ dlls/ir50_32/ir50.c | 180 ++++++++++++++++++++++++++++++++++++ dlls/ir50_32/ir50_32.rc | 29 ++++++ dlls/ir50_32/ir50_32.spec | 1 + dlls/ir50_32/ir50_private.h | 34 +++++++ po/ar.po | 12 +++ po/ast.po | 8 ++ po/bg.po | 10 ++ po/ca.po | 12 +++ po/cs.po | 12 +++ po/da.po | 12 +++ po/de.po | 12 +++ po/el.po | 8 ++ po/en.po | 8 ++ po/en_US.po | 8 ++ po/eo.po | 10 ++ po/es.po | 12 +++ po/fa.po | 8 ++ po/fi.po | 12 +++ po/fr.po | 12 +++ po/he.po | 12 +++ po/hi.po | 8 ++ po/hr.po | 12 +++ po/hu.po | 12 +++ po/it.po | 12 +++ po/ja.po | 12 +++ po/ko.po | 12 +++ po/lt.po | 12 +++ po/ml.po | 8 ++ po/nb_NO.po | 12 +++ po/nl.po | 12 +++ po/or.po | 8 ++ po/pa.po | 8 ++ po/pl.po | 12 +++ po/pt_BR.po | 12 +++ po/pt_PT.po | 12 +++ po/rm.po | 9 ++ po/ro.po | 12 +++ po/ru.po | 12 +++ po/si.po | 12 +++ po/sk.po | 10 ++ po/sl.po | 12 +++ po/sr_RS@cyrillic.po | 11 +++ po/sr_RS@latin.po | 12 +++ po/sv.po | 12 +++ po/ta.po | 10 ++ po/te.po | 8 ++ po/th.po | 8 ++ po/tr.po | 12 +++ po/uk.po | 12 +++ po/wa.po | 9 ++ po/wine.pot | 8 ++ po/zh_CN.po | 12 +++ po/zh_TW.po | 12 +++ 55 files changed, 777 insertions(+) create mode 100644 dlls/ir50_32/Makefile.in create mode 100644 dlls/ir50_32/ir50.c create mode 100644 dlls/ir50_32/ir50_32.rc create mode 100644 dlls/ir50_32/ir50_32.spec create mode 100644 dlls/ir50_32/ir50_private.h diff --git a/configure.ac b/configure.ac index 91ac8a9485f..5d3238618ea 100644 --- a/configure.ac +++ b/configure.ac @@ -2709,6 +2709,7 @@ WINE_CONFIG_MAKEFILE(dlls/inseng) WINE_CONFIG_MAKEFILE(dlls/iphlpapi) WINE_CONFIG_MAKEFILE(dlls/iphlpapi/tests) WINE_CONFIG_MAKEFILE(dlls/iprop) +WINE_CONFIG_MAKEFILE(dlls/ir50_32) WINE_CONFIG_MAKEFILE(dlls/irprops.cpl) WINE_CONFIG_MAKEFILE(dlls/itircl) WINE_CONFIG_MAKEFILE(dlls/itss) diff --git a/dlls/ir50_32/Makefile.in b/dlls/ir50_32/Makefile.in new file mode 100644 index 00000000000..7bac0ccc9ca --- /dev/null +++ b/dlls/ir50_32/Makefile.in @@ -0,0 +1,7 @@ +MODULE = ir50_32.dll +IMPORTS = user32 + +C_SRCS = \ + ir50.c + +RC_SRCS = ir50_32.rc diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c new file mode 100644 index 00000000000..3019301742e --- /dev/null +++ b/dlls/ir50_32/ir50.c @@ -0,0 +1,180 @@ +/* + * Intel Indeo 5 Video Decoder + * Copyright 2023 Shaun Ren 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 + * + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "commdlg.h" +#include "vfw.h" +#include "ir50_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ir50_32); + +static HINSTANCE IR50_32_hModule; + +#define IV50_MAGIC mmioFOURCC('I','V','5','0') + + +static LRESULT +IV50_Open( const ICINFO *icinfo ) +{ + FIXME("DRV_OPEN %p\n", icinfo); + return 0; +} + +static LRESULT +IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) +{ + FIXME("ICM_DECOMPRESS_QUERY %p %p\n", in, out); + return ICERR_UNSUPPORTED; +} + +static LRESULT +IV50_DecompressGetFormat( LPBITMAPINFO in, LPBITMAPINFO out ) +{ + FIXME("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out); + return ICERR_UNSUPPORTED; +} + +static LRESULT IV50_DecompressBegin( IMFTransform *decoder, LPBITMAPINFO in, LPBITMAPINFO out ) +{ + FIXME("ICM_DECOMPRESS_BEGIN %p %p %p\n", decoder, in, out); + return ICERR_UNSUPPORTED; +} + +static LRESULT IV50_Decompress( IMFTransform *decoder, ICDECOMPRESS *icd, DWORD size ) +{ + FIXME("ICM_DECOMPRESS %p %p %lu\n", decoder, icd, size); + return ICERR_UNSUPPORTED; +} + +static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize ) +{ + FIXME("ICM_GETINFO %p %lu\n", icinfo, dwSize); + return ICERR_UNSUPPORTED; +} + +/*********************************************************************** + * DriverProc (IR50_32.@) + */ +LRESULT WINAPI IV50_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg, + LPARAM lParam1, LPARAM lParam2 ) +{ + IMFTransform *decoder = (IMFTransform *) dwDriverId; + LRESULT r = ICERR_UNSUPPORTED; + + TRACE("%Id %p %04x %08Ix %08Ix\n", dwDriverId, hdrvr, msg, lParam1, lParam2); + + switch( msg ) + { + case DRV_LOAD: + TRACE("DRV_LOAD\n"); + r = 1; + break; + + case DRV_OPEN: + r = IV50_Open((ICINFO *)lParam2); + break; + + case DRV_CLOSE: + FIXME("DRV_CLOSE\n"); + break; + + case DRV_ENABLE: + case DRV_DISABLE: + case DRV_FREE: + break; + + case ICM_GETINFO: + r = IV50_GetInfo( (ICINFO *) lParam1, (DWORD) lParam2 ); + break; + + case ICM_DECOMPRESS_QUERY: + r = IV50_DecompressQuery( (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 ); + break; + + case ICM_DECOMPRESS_GET_FORMAT: + r = IV50_DecompressGetFormat( (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 ); + break; + + case ICM_DECOMPRESS_GET_PALETTE: + FIXME("ICM_DECOMPRESS_GET_PALETTE\n"); + break; + + case ICM_DECOMPRESS: + r = IV50_Decompress( decoder, (ICDECOMPRESS *) lParam1, (DWORD) lParam2 ); + break; + + case ICM_DECOMPRESS_BEGIN: + r = IV50_DecompressBegin( decoder, (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 ); + break; + + case ICM_DECOMPRESS_END: + r = ICERR_UNSUPPORTED; + break; + + case ICM_DECOMPRESSEX_QUERY: + FIXME("ICM_DECOMPRESSEX_QUERY\n"); + break; + + case ICM_DECOMPRESSEX: + FIXME("ICM_DECOMPRESSEX\n"); + break; + + case ICM_COMPRESS_QUERY: + r = ICERR_BADFORMAT; + /* fall through */ + case ICM_COMPRESS_GET_FORMAT: + case ICM_COMPRESS_END: + case ICM_COMPRESS: + FIXME("compression not implemented\n"); + break; + + case ICM_CONFIGURE: + break; + + default: + FIXME("Unknown message: %04x %Id %Id\n", msg, lParam1, lParam2); + } + + return r; +} + +/*********************************************************************** + * DllMain + */ +BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved) +{ + TRACE("(%p,%lu,%p)\n", hModule, dwReason, lpReserved); + + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hModule); + IR50_32_hModule = hModule; + break; + } + return TRUE; +} diff --git a/dlls/ir50_32/ir50_32.rc b/dlls/ir50_32/ir50_32.rc new file mode 100644 index 00000000000..fd98f76fbf6 --- /dev/null +++ b/dlls/ir50_32/ir50_32.rc @@ -0,0 +1,29 @@ +/* + * Copyright 2023 Shaun Ren 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 + */ + +#include "ir50_private.h" + +#pragma makedep po + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT + +STRINGTABLE +{ + IDS_NAME "Indeo5" + IDS_DESCRIPTION "Indeo Video Interactive version 5 video codec" +} diff --git a/dlls/ir50_32/ir50_32.spec b/dlls/ir50_32/ir50_32.spec new file mode 100644 index 00000000000..e5c54ef9c56 --- /dev/null +++ b/dlls/ir50_32/ir50_32.spec @@ -0,0 +1 @@ +@ stdcall -private DriverProc(long long long long long) IV50_DriverProc diff --git a/dlls/ir50_32/ir50_private.h b/dlls/ir50_32/ir50_private.h new file mode 100644 index 00000000000..c022a8196d2 --- /dev/null +++ b/dlls/ir50_32/ir50_private.h @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Shaun Ren 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 + */ + +#ifndef __IR50_PRIVATE_H +#define __IR50_PRIVATE_H + +#include + +#define COBJMACROS +#include "mfapi.h" +#include "mferror.h" +#include "mfobjects.h" +#include "mfidl.h" +#include "mftransform.h" + +#define IDS_NAME 100 +#define IDS_DESCRIPTION 101 + +#endif /* __IR50_PRIVATE_H */ diff --git a/po/ar.po b/po/ar.po index b87d6151a2f..a17773e2606 100644 --- a/po/ar.po +++ b/po/ar.po @@ -3732,6 +3732,18 @@ msgstr "زائد" msgid "High" msgstr "عالي" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "الÙهرس" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "ترميز واين المرئي الأول" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "مقابض اللعب" diff --git a/po/ast.po b/po/ast.po index 91d7d256182..1e0b2398d23 100644 --- a/po/ast.po +++ b/po/ast.po @@ -3626,6 +3626,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/bg.po b/po/bg.po index 47e12a893e8..45450a3c193 100644 --- a/po/bg.po +++ b/po/bg.po @@ -3744,6 +3744,16 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +msgid "Indeo5" +msgstr "&Съдържание" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine MS-RLE видео кодек" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/ca.po b/po/ca.po index 90ee5673f7a..ee2bcf7b0a0 100644 --- a/po/ca.po +++ b/po/ca.po @@ -3724,6 +3724,18 @@ msgstr "Elevat" msgid "High" msgstr "Alt" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Ãndex" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Còdec de vídeo Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Palanques de control" diff --git a/po/cs.po b/po/cs.po index 25a4f1b75e3..2c4fd0fc2c2 100644 --- a/po/cs.po +++ b/po/cs.po @@ -3681,6 +3681,18 @@ msgstr "Zvýšená" msgid "High" msgstr "Vysoká" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Rejstřík" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Videokodek Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Pákové ovladaÄe" diff --git a/po/da.po b/po/da.po index c7ee34b8ff9..3180d23849d 100644 --- a/po/da.po +++ b/po/da.po @@ -3763,6 +3763,18 @@ msgstr "Øget" msgid "High" msgstr "&Høj" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Indeks" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 videokodeks" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/de.po b/po/de.po index 1ed7acd9d05..5edd48f2dc2 100644 --- a/po/de.po +++ b/po/de.po @@ -3714,6 +3714,18 @@ msgstr "Erhöht" msgid "High" msgstr "Hoch" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Index" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine-Video-1-Videocodec" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/el.po b/po/el.po index c5c8307e2cb..9b5f42cae51 100644 --- a/po/el.po +++ b/po/el.po @@ -3661,6 +3661,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/en.po b/po/en.po index a9ad0a9cb0a..91419affefd 100644 --- a/po/en.po +++ b/po/en.po @@ -3707,6 +3707,14 @@ msgstr "Increased" msgid "High" msgstr "High" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "Indeo5" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Indeo Video Interactive version 5 video codec" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/en_US.po b/po/en_US.po index ab15878a97b..34daca1a1bc 100644 --- a/po/en_US.po +++ b/po/en_US.po @@ -3707,6 +3707,14 @@ msgstr "Increased" msgid "High" msgstr "High" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "Indeo5" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Indeo Video Interactive version 5 video codec" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/eo.po b/po/eo.po index 050cd952e48..17d3c9647e4 100644 --- a/po/eo.po +++ b/po/eo.po @@ -3649,6 +3649,16 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Indekso" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/es.po b/po/es.po index c19a7daabc1..cde1ed48458 100644 --- a/po/es.po +++ b/po/es.po @@ -3727,6 +3727,18 @@ msgstr "Aumentada" msgid "High" msgstr "Alta" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Ãndice" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Códec de vídeo Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Comando de juego" diff --git a/po/fa.po b/po/fa.po index 40491717d00..b9531707e71 100644 --- a/po/fa.po +++ b/po/fa.po @@ -3692,6 +3692,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/fi.po b/po/fi.po index 51f6dc4736e..d22ab0b6029 100644 --- a/po/fi.po +++ b/po/fi.po @@ -3701,6 +3701,18 @@ msgstr "Korotettu" msgid "High" msgstr "Korkea" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Sisällys" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Winen Video 1 -videokoodekki" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joystickit" diff --git a/po/fr.po b/po/fr.po index b3d2ea080c0..8bb0ba73b07 100644 --- a/po/fr.po +++ b/po/fr.po @@ -3732,6 +3732,18 @@ msgstr "Augmentée" msgid "High" msgstr "Haute" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Index" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Codec vidéo Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/he.po b/po/he.po index 2e716c65960..26d5a2dbb7b 100644 --- a/po/he.po +++ b/po/he.po @@ -3727,6 +3727,18 @@ msgstr "מוגברת" msgid "High" msgstr "גבוהה" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "מפתח" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "מקודד הוויד×ו Video 1 של Wine" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/hi.po b/po/hi.po index 08201ec785b..2bd8f692cc7 100644 --- a/po/hi.po +++ b/po/hi.po @@ -3625,6 +3625,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/hr.po b/po/hr.po index cab03b4c47b..a801b3f74d5 100644 --- a/po/hr.po +++ b/po/hr.po @@ -3737,6 +3737,18 @@ msgstr "Povećane" msgid "High" msgstr "Visoke" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Indeks" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 video codec" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joystici" diff --git a/po/hu.po b/po/hu.po index 6b70faab001..88880d8a997 100644 --- a/po/hu.po +++ b/po/hu.po @@ -3779,6 +3779,18 @@ msgstr "Megnövelt" msgid "High" msgstr "Magas" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "&Témakörök" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 video kodek" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/it.po b/po/it.po index d2bf050bd81..ec6b6b19192 100644 --- a/po/it.po +++ b/po/it.po @@ -3787,6 +3787,18 @@ msgstr "Aumentato" msgid "High" msgstr "Alta" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Indice" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Codec Video Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/ja.po b/po/ja.po index ee177c0aaa8..49f30f5718e 100644 --- a/po/ja.po +++ b/po/ja.po @@ -3699,6 +3699,18 @@ msgstr "中高" msgid "High" msgstr "高" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "索引" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine ビデオ 1 ビデオコーデック" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "ジョイスティック" diff --git a/po/ko.po b/po/ko.po index fde0ddc1d3b..e5038887f90 100644 --- a/po/ko.po +++ b/po/ko.po @@ -3689,6 +3689,18 @@ msgstr "ì¦ê°€" msgid "High" msgstr "높ìŒ" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "ì¸ë±ìŠ¤" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine 비디오 1 비디오 ì½”ë±" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "ì¡°ì´ìŠ¤í‹±" diff --git a/po/lt.po b/po/lt.po index 2fe2909a0d6..217ba5c9628 100644 --- a/po/lt.po +++ b/po/lt.po @@ -3710,6 +3710,18 @@ msgstr "Padidintos" msgid "High" msgstr "AukÅ¡tos" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Indeksas" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "„Wine“ Video 1 vaizdo kodekas" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "VairasvirtÄ—s" diff --git a/po/ml.po b/po/ml.po index 29b316c025c..7a8d207ea34 100644 --- a/po/ml.po +++ b/po/ml.po @@ -3627,6 +3627,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/nb_NO.po b/po/nb_NO.po index ec59d534991..818e6058644 100644 --- a/po/nb_NO.po +++ b/po/nb_NO.po @@ -3715,6 +3715,18 @@ msgstr "Økt" msgid "High" msgstr "Høy" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Innhold" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 videokodeks" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Styrespaker" diff --git a/po/nl.po b/po/nl.po index b571b48a26b..b6c00c155c2 100644 --- a/po/nl.po +++ b/po/nl.po @@ -3720,6 +3720,18 @@ msgstr "Verhoogd" msgid "High" msgstr "Hoog" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Index" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 video codec" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/or.po b/po/or.po index 4efb1620ccb..59e24a848ef 100644 --- a/po/or.po +++ b/po/or.po @@ -3625,6 +3625,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/pa.po b/po/pa.po index fb970b7c963..46068d3822f 100644 --- a/po/pa.po +++ b/po/pa.po @@ -3625,6 +3625,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/pl.po b/po/pl.po index 723493afaa2..49346b2194c 100644 --- a/po/pl.po +++ b/po/pl.po @@ -3726,6 +3726,18 @@ msgstr "Wysoki" msgid "High" msgstr "Najwyższy" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Indeks" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Kodek Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticki" diff --git a/po/pt_BR.po b/po/pt_BR.po index d6821db3689..dc6fbe28027 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -3722,6 +3722,18 @@ msgstr "Elevada" msgid "High" msgstr "Alta" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Ãndice" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Codec de vídeo Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Controles" diff --git a/po/pt_PT.po b/po/pt_PT.po index 833b8b23ade..3ec661f62ee 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -3763,6 +3763,18 @@ msgstr "Aumentada" msgid "High" msgstr "Alta" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Ãndice" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "codec video Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/rm.po b/po/rm.po index 412e3dc6c5e..2573d02eab9 100644 --- a/po/rm.po +++ b/po/rm.po @@ -3653,6 +3653,15 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +msgid "Indeo5" +msgstr "&Cuntgn�" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/ro.po b/po/ro.po index 6c82bb5c603..dd8b5357230 100644 --- a/po/ro.po +++ b/po/ro.po @@ -3720,6 +3720,18 @@ msgstr "Mărit" msgid "High" msgstr "ÃŽnalt" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Index" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Codecul video Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joystick-uri" diff --git a/po/ru.po b/po/ru.po index cb918603b72..1d567cabdcb 100644 --- a/po/ru.po +++ b/po/ru.po @@ -3725,6 +3725,18 @@ msgstr "Повышенный" msgid "High" msgstr "Ð’Ñ‹Ñокий" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Указатель" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Видео кодек Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "ДжойÑтики" diff --git a/po/si.po b/po/si.po index bb39137afd5..444e97e402b 100644 --- a/po/si.po +++ b/po/si.po @@ -3652,6 +3652,18 @@ msgstr "" msgid "High" msgstr "à·€à·à¶©à·’" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "දර්à·à¶šà¶º" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine වීඩිය෠1 වීඩිය෠කොඩෙක්" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "නියà·à¶¸à¶š යටි" diff --git a/po/sk.po b/po/sk.po index c018db3e215..35a24b1ac2b 100644 --- a/po/sk.po +++ b/po/sk.po @@ -3694,6 +3694,16 @@ msgstr "Zvýšené" msgid "High" msgstr "Vysoké" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Obsah" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/sl.po b/po/sl.po index 02638b23811..45f5433f134 100644 --- a/po/sl.po +++ b/po/sl.po @@ -3781,6 +3781,18 @@ msgstr "PoveÄano" msgid "High" msgstr "Visoka" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Kazalo" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 video kodek" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/sr_RS@cyrillic.po b/po/sr_RS@cyrillic.po index 63e76fa78f5..a5815e8aab0 100644 --- a/po/sr_RS@cyrillic.po +++ b/po/sr_RS@cyrillic.po @@ -3762,6 +3762,17 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +msgid "Indeo5" +msgstr "&ПопиÑ" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 видео кодек" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/sr_RS@latin.po b/po/sr_RS@latin.po index e0977ce9ac3..e446f271429 100644 --- a/po/sr_RS@latin.po +++ b/po/sr_RS@latin.po @@ -3846,6 +3846,18 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Index" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 video kodek" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/sv.po b/po/sv.po index 5f4397962bf..21883ad555f 100644 --- a/po/sv.po +++ b/po/sv.po @@ -3742,6 +3742,18 @@ msgstr "Ökad" msgid "High" msgstr "Hög" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Index" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 videokodek" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/ta.po b/po/ta.po index 2d1c803e1ad..50289ad45c3 100644 --- a/po/ta.po +++ b/po/ta.po @@ -3589,6 +3589,16 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine வீடியோ 1 வீடியோ கோடெகà¯" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/te.po b/po/te.po index c0c7e8116a0..7dafde4a546 100644 --- a/po/te.po +++ b/po/te.po @@ -3625,6 +3625,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/th.po b/po/th.po index 8f563d508b7..29af5b4a434 100644 --- a/po/th.po +++ b/po/th.po @@ -3680,6 +3680,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/tr.po b/po/tr.po index 28cee4524cd..d2ecc1b0fc2 100644 --- a/po/tr.po +++ b/po/tr.po @@ -3716,6 +3716,18 @@ msgstr "Arttırılmış" msgid "High" msgstr "Yüksek" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "İçindekiler" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 video çözücü" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Oyun Kolları" diff --git a/po/uk.po b/po/uk.po index 2d941b5248f..cf0ceb06649 100644 --- a/po/uk.po +++ b/po/uk.po @@ -3713,6 +3713,18 @@ msgstr "Збільшені" msgid "High" msgstr "ВиÑокі" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Вказівник" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Відео кодек Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "ДжойÑтик" diff --git a/po/wa.po b/po/wa.po index 13d79d4eeca..fcbcf228e00 100644 --- a/po/wa.po +++ b/po/wa.po @@ -3688,6 +3688,15 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +msgid "Indeo5" +msgstr "Ã…&dvins" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/wine.pot b/po/wine.pot index 881b048e33b..21654586e88 100644 --- a/po/wine.pot +++ b/po/wine.pot @@ -3580,6 +3580,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/zh_CN.po b/po/zh_CN.po index f226c3b1ced..6f1772bd3c4 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -3657,6 +3657,18 @@ msgstr "较高" msgid "High" msgstr "高" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "索引" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 视频编解ç å™¨" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "æ“纵æ†" diff --git a/po/zh_TW.po b/po/zh_TW.po index 2a93c59445a..f29c109df08 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -3663,6 +3663,18 @@ msgstr "ç¨é«˜" msgid "High" msgstr "高" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "索引" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine 視訊 1 視訊編碼解碼器" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "æ–æ¡¿" From 8f439301efb3baab451a450bbcec5fb7cfb068ce Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 1 Feb 2023 01:37:09 -0500 Subject: [PATCH 1388/2777] ir50_32: Implement IV50_GetInfo. (cherry picked from commit 05eef506149ca2892b5727d8a5a7eb9e71638b08) CW-Bug-Id: #21175 --- dlls/ir50_32/ir50.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 3019301742e..0e1c9b4d2e4 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -72,8 +72,23 @@ static LRESULT IV50_Decompress( IMFTransform *decoder, ICDECOMPRESS *icd, DWORD static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize ) { - FIXME("ICM_GETINFO %p %lu\n", icinfo, dwSize); - return ICERR_UNSUPPORTED; + TRACE("ICM_GETINFO %p %lu\n", icinfo, dwSize); + + if ( !icinfo ) return sizeof(ICINFO); + if ( dwSize < sizeof(ICINFO) ) return 0; + + icinfo->dwSize = sizeof(ICINFO); + icinfo->fccType = ICTYPE_VIDEO; + icinfo->fccHandler = IV50_MAGIC; + icinfo->dwFlags = 0; + icinfo->dwVersion = ICVERSION; + icinfo->dwVersionICM = ICVERSION; + + LoadStringW( IR50_32_hModule, IDS_NAME, icinfo->szName, ARRAY_SIZE(icinfo->szName) ); + LoadStringW( IR50_32_hModule, IDS_DESCRIPTION, icinfo->szDescription, ARRAY_SIZE(icinfo->szDescription) ); + /* msvfw32 will fill icinfo->szDriver for us */ + + return sizeof(ICINFO); } /*********************************************************************** From 64995a9b048cd7876ba3611b25c7d2c7ec612e5e Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 1 Feb 2023 01:38:30 -0500 Subject: [PATCH 1389/2777] ir50_32: Implement IV50_DecompressQuery. (cherry picked from commit b979f3b8aa9cc395a6dfc314fc4f48af4ef215c4) CW-Bug-Id: #21175 --- dlls/ir50_32/ir50.c | 47 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 0e1c9b4d2e4..92e4c8a49be 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -47,8 +47,51 @@ IV50_Open( const ICINFO *icinfo ) static LRESULT IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) { - FIXME("ICM_DECOMPRESS_QUERY %p %p\n", in, out); - return ICERR_UNSUPPORTED; + TRACE("ICM_DECOMPRESS_QUERY %p %p\n", in, out); + + TRACE("in->planes = %d\n", in->bmiHeader.biPlanes); + TRACE("in->bpp = %d\n", in->bmiHeader.biBitCount); + TRACE("in->height = %ld\n", in->bmiHeader.biHeight); + TRACE("in->width = %ld\n", in->bmiHeader.biWidth); + TRACE("in->compr = %#lx\n", in->bmiHeader.biCompression); + + if ( in->bmiHeader.biCompression != IV50_MAGIC ) + { + TRACE("can't do %#lx compression\n", in->bmiHeader.biCompression); + return ICERR_BADFORMAT; + } + + /* output must be same dimensions as input */ + if ( out ) + { + TRACE("out->planes = %d\n", out->bmiHeader.biPlanes); + TRACE("out->bpp = %d\n", out->bmiHeader.biBitCount); + TRACE("out->height = %ld\n", out->bmiHeader.biHeight); + TRACE("out->width = %ld\n", out->bmiHeader.biWidth); + TRACE("out->compr = %#lx\n", out->bmiHeader.biCompression); + + if ( out->bmiHeader.biCompression != BI_RGB ) + { + TRACE("incompatible compression requested\n"); + return ICERR_BADFORMAT; + } + + if ( out->bmiHeader.biBitCount != 32 && out->bmiHeader.biBitCount != 16 ) + { + TRACE("incompatible depth requested\n"); + return ICERR_BADFORMAT; + } + + if ( in->bmiHeader.biPlanes != out->bmiHeader.biPlanes || + in->bmiHeader.biHeight != abs(out->bmiHeader.biHeight) || + in->bmiHeader.biWidth != out->bmiHeader.biWidth ) + { + TRACE("incompatible output dimensions requested\n"); + return ICERR_BADFORMAT; + } + } + + return ICERR_OK; } static LRESULT From 8c5de958be2e89bdedce9265b8d0007e4c1800ea Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 1 Feb 2023 01:42:13 -0500 Subject: [PATCH 1390/2777] ir50_32: Implement IV50_DecompressGetFormat. (cherry picked from commit e8cfcbb2f4d4cd04e3ea77979214c4fccf503c92) CW-Bug-Id: #21175 --- dlls/ir50_32/ir50.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 92e4c8a49be..7e494d50761 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -97,8 +97,28 @@ IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) static LRESULT IV50_DecompressGetFormat( LPBITMAPINFO in, LPBITMAPINFO out ) { - FIXME("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out); - return ICERR_UNSUPPORTED; + DWORD size; + + TRACE("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out); + + if ( !in ) + return ICERR_BADPARAM; + + if ( in->bmiHeader.biCompression != IV50_MAGIC ) + return ICERR_BADFORMAT; + + size = in->bmiHeader.biSize; + if ( out ) + { + memcpy( out, in, size ); + out->bmiHeader.biHeight = abs(in->bmiHeader.biHeight); + out->bmiHeader.biCompression = BI_RGB; + out->bmiHeader.biBitCount = 32; + out->bmiHeader.biSizeImage = out->bmiHeader.biWidth * out->bmiHeader.biHeight * 4; + return ICERR_OK; + } + + return size; } static LRESULT IV50_DecompressBegin( IMFTransform *decoder, LPBITMAPINFO in, LPBITMAPINFO out ) From d468eb8bc63481dea9c47283e815512937a7f2a6 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 1 Feb 2023 21:53:57 -0500 Subject: [PATCH 1391/2777] winegstreamer: Add video_decoder stub. (cherry picked from commit 70e93833679342c485b9720af61c92efcdcbd191) CW-Bug-Id: #21175 --- MAINTAINERS | 1 + dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/video_decoder.c | 278 ++++++++++++++++++++++++++ dlls/winegstreamer/winegstreamer.spec | 1 + 4 files changed, 281 insertions(+) create mode 100644 dlls/winegstreamer/video_decoder.c diff --git a/MAINTAINERS b/MAINTAINERS index 276471287da..8c30f8c6d1d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -212,6 +212,7 @@ F: dlls/winegstreamer/aac_decoder.c F: dlls/winegstreamer/color_convert.c F: dlls/winegstreamer/h264_decoder.c F: dlls/winegstreamer/resampler.c +F: dlls/winegstreamer/video_decoder.c F: dlls/winegstreamer/video_processor.c F: dlls/winegstreamer/wg_sample.c F: dlls/winegstreamer/wg_transform.c diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 9bdafe83897..a2d4f2a757c 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -17,6 +17,7 @@ C_SRCS = \ quartz_transform.c \ resampler.c \ scheme_handler.c \ + video_decoder.c \ video_processor.c \ wg_allocator.c \ wg_format.c \ diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c new file mode 100644 index 00000000000..c660be9b212 --- /dev/null +++ b/dlls/winegstreamer/video_decoder.c @@ -0,0 +1,278 @@ +/* Generic Video Decoder Transform + * + * Copyright 2022 Rémi Bernon for CodeWeavers + * Copyright 2023 Shaun Ren 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 + */ + +#include "gst_private.h" + +#include "mfapi.h" +#include "mferror.h" +#include "mfobjects.h" +#include "mftransform.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +struct video_decoder +{ + IMFTransform IMFTransform_iface; + LONG refcount; +}; + +static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface) +{ + return CONTAINING_RECORD(iface, struct video_decoder, IMFTransform_iface); +} + +static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) +{ + struct video_decoder *decoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IMFTransform)) + *out = &decoder->IMFTransform_iface; + else + { + *out = NULL; + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static ULONG WINAPI transform_AddRef(IMFTransform *iface) +{ + struct video_decoder *decoder = impl_from_IMFTransform(iface); + ULONG refcount = InterlockedIncrement(&decoder->refcount); + + TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); + + return refcount; +} + +static ULONG WINAPI transform_Release(IMFTransform *iface) +{ + struct video_decoder *decoder = impl_from_IMFTransform(iface); + ULONG refcount = InterlockedDecrement(&decoder->refcount); + + TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); + + if (!refcount) + { + free(decoder); + } + + return refcount; +} + +static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, + DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) +{ + FIXME("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n", + iface, input_minimum, input_maximum, output_minimum, output_maximum); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) +{ + TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, + DWORD output_size, DWORD *outputs) +{ + FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface, + input_size, inputs, output_size, outputs); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) +{ + FIXME("iface %p, id %#lx, info %p.\n", iface, id, info); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) +{ + FIXME("iface %p, id %#lx, info %p.\n", iface, id, info); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +{ + FIXME("iface %p, attributes %p semi-stub!\n", iface, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + FIXME("iface %p, id %#lx, attributes %p.\n", iface, id, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id) +{ + FIXME("iface %p, id %#lx.\n", iface, id); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) +{ + FIXME("iface %p, streams %lu, ids %p.\n", iface, streams, ids); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, + DWORD index, IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + FIXME("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + FIXME("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) +{ + FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) +{ + FIXME("iface %p, flags %p stub!\n", iface, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) +{ + TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) +{ + FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) +{ + FIXME("iface %p, message %#x, param %Ix stub!\n", iface, message, param); + return S_OK; +} + +static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) +{ + FIXME("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, + MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) +{ + FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); + return E_NOTIMPL; +} + +static const IMFTransformVtbl transform_vtbl = +{ + transform_QueryInterface, + transform_AddRef, + transform_Release, + transform_GetStreamLimits, + transform_GetStreamCount, + transform_GetStreamIDs, + transform_GetInputStreamInfo, + transform_GetOutputStreamInfo, + transform_GetAttributes, + transform_GetInputStreamAttributes, + transform_GetOutputStreamAttributes, + transform_DeleteInputStream, + transform_AddInputStreams, + transform_GetInputAvailableType, + transform_GetOutputAvailableType, + transform_SetInputType, + transform_SetOutputType, + transform_GetInputCurrentType, + transform_GetOutputCurrentType, + transform_GetInputStatus, + transform_GetOutputStatus, + transform_SetOutputBounds, + transform_ProcessEvent, + transform_ProcessMessage, + transform_ProcessInput, + transform_ProcessOutput, +}; + +HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out) +{ + struct video_decoder *decoder; + + TRACE("out %p.\n", out); + + if (!(decoder = calloc(1, sizeof(*decoder)))) + return E_OUTOFMEMORY; + + decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; + decoder->refcount = 1; + + *out = &decoder->IMFTransform_iface; + TRACE("created decoder %p.\n", *out); + return S_OK; +} diff --git a/dlls/winegstreamer/winegstreamer.spec b/dlls/winegstreamer/winegstreamer.spec index 9804e324044..095f75a0865 100644 --- a/dlls/winegstreamer/winegstreamer.spec +++ b/dlls/winegstreamer/winegstreamer.spec @@ -3,3 +3,4 @@ @ stdcall -private DllRegisterServer() @ stdcall -private DllUnregisterServer() @ stdcall winegstreamer_create_wm_sync_reader(ptr ptr) +@ stdcall winegstreamer_create_video_decoder(ptr) From f23349f7b19c90ada42133232ff71d6db5050525 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Fri, 3 Feb 2023 02:16:34 -0500 Subject: [PATCH 1392/2777] ir50_32: Implement open and close. (cherry picked from commit 3dd09ed8f9ecf99439a372b6d0be076cef8aaef3) CW-Bug-Id: #21175 --- dlls/ir50_32/Makefile.in | 3 ++- dlls/ir50_32/ir50.c | 19 ++++++++++++++++--- dlls/ir50_32/ir50_private.h | 2 ++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/dlls/ir50_32/Makefile.in b/dlls/ir50_32/Makefile.in index 7bac0ccc9ca..2db9c8076c9 100644 --- a/dlls/ir50_32/Makefile.in +++ b/dlls/ir50_32/Makefile.in @@ -1,5 +1,6 @@ MODULE = ir50_32.dll -IMPORTS = user32 +IMPORTS = user32 mfplat mfuuid +DELAYIMPORTS = winegstreamer C_SRCS = \ ir50.c diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 7e494d50761..428108f09ba 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -35,13 +35,23 @@ WINE_DEFAULT_DEBUG_CHANNEL(ir50_32); static HINSTANCE IR50_32_hModule; #define IV50_MAGIC mmioFOURCC('I','V','5','0') +#define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020) static LRESULT IV50_Open( const ICINFO *icinfo ) { - FIXME("DRV_OPEN %p\n", icinfo); - return 0; + IMFTransform *decoder = NULL; + + TRACE("DRV_OPEN %p\n", icinfo); + + if ( icinfo && compare_fourcc( icinfo->fccType, ICTYPE_VIDEO ) ) + return 0; + + if ( FAILED(winegstreamer_create_video_decoder( &decoder )) ) + return 0; + + return (LRESULT)decoder; } static LRESULT @@ -177,7 +187,10 @@ LRESULT WINAPI IV50_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg, break; case DRV_CLOSE: - FIXME("DRV_CLOSE\n"); + TRACE("DRV_CLOSE\n"); + if ( decoder ) + IMFTransform_Release( decoder ); + r = 1; break; case DRV_ENABLE: diff --git a/dlls/ir50_32/ir50_private.h b/dlls/ir50_32/ir50_private.h index c022a8196d2..c0b96bc17e4 100644 --- a/dlls/ir50_32/ir50_private.h +++ b/dlls/ir50_32/ir50_private.h @@ -31,4 +31,6 @@ #define IDS_NAME 100 #define IDS_DESCRIPTION 101 +HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out); + #endif /* __IR50_PRIVATE_H */ From 2c1dad89a18a8a8ea7ca30b9e6ca481115bded2d Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Fri, 13 Jan 2023 16:33:29 -0500 Subject: [PATCH 1393/2777] winegstreamer: Add WG_MAJOR_TYPE_VIDEO_INDEO video type. (cherry picked from commit 32bb602393ef991fe0e9372612d212e0489ac87c) CW-Bug-Id: #21175 --- dlls/winegstreamer/mfplat.c | 31 ++++++++++++++++++++++++++++++ dlls/winegstreamer/quartz_parser.c | 2 ++ dlls/winegstreamer/unixlib.h | 7 +++++++ dlls/winegstreamer/wg_format.c | 22 +++++++++++++++++++++ dlls/winegstreamer/wg_transform.c | 2 ++ dlls/winegstreamer/wm_reader.c | 4 ++++ 6 files changed, 68 insertions(+) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index c560ff31a4a..c1deffbb1cc 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -40,6 +40,7 @@ DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC,WAVE_FORMAT_RAW_AAC1); DEFINE_MEDIATYPE_GUID(MFAudioFormat_XMAudio2, 0x0166); DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32,D3DFMT_A8B8G8R8); DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50,MAKEFOURCC('I','V','5','0')); extern GUID MEDIASUBTYPE_VC1S; @@ -563,6 +564,7 @@ IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: + case WG_MAJOR_TYPE_VIDEO_INDEO: FIXME("Format %u not implemented!\n", format->major_type); /* fallthrough */ case WG_MAJOR_TYPE_UNKNOWN: @@ -866,6 +868,33 @@ static void mf_media_type_to_wg_format_wmv(IMFMediaType *type, const GUID *subty } } +static void mf_media_type_to_wg_format_video_indeo(IMFMediaType *type, uint32_t version, struct wg_format *format) +{ + UINT64 frame_rate, frame_size; + + memset(format, 0, sizeof(*format)); + format->major_type = WG_MAJOR_TYPE_VIDEO_INDEO; + + if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) + { + format->u.video_indeo.width = frame_size >> 32; + format->u.video_indeo.height = (UINT32)frame_size; + } + + if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) + { + format->u.video_indeo.fps_n = frame_rate >> 32; + format->u.video_indeo.fps_d = (UINT32)frame_rate; + } + else + { + format->u.video_indeo.fps_n = 1; + format->u.video_indeo.fps_d = 1; + } + + format->u.video_indeo.version = version; +} + void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) { GUID major_type, subtype; @@ -910,6 +939,8 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) || IsEqualGUID(&subtype, &MFVideoFormat_WVC1) || IsEqualGUID(&subtype, &MEDIASUBTYPE_VC1S)) mf_media_type_to_wg_format_wmv(type, &subtype, format); + else if (IsEqualGUID(&subtype, &MFVideoFormat_IV50)) + mf_media_type_to_wg_format_video_indeo(type, 5, format); else mf_media_type_to_wg_format_video(type, &subtype, format); } diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index e683f96be37..b4cc6f83a0f 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -435,6 +435,7 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: + case WG_MAJOR_TYPE_VIDEO_INDEO: FIXME("Format %u not implemented!\n", format->major_type); return 0; @@ -608,6 +609,7 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: + case WG_MAJOR_TYPE_VIDEO_INDEO: FIXME("Format %u not implemented!\n", format->major_type); /* fallthrough */ case WG_MAJOR_TYPE_UNKNOWN: diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index f0e176b2085..89a81b0d780 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -43,6 +43,7 @@ struct wg_format WG_MAJOR_TYPE_VIDEO_CINEPAK, WG_MAJOR_TYPE_VIDEO_H264, WG_MAJOR_TYPE_VIDEO_WMV, + WG_MAJOR_TYPE_VIDEO_INDEO, } major_type; union @@ -135,6 +136,12 @@ struct wg_format uint32_t fps_n, fps_d; uint32_t version; } video_wmv; + struct + { + int32_t width, height; + uint32_t fps_n, fps_d; + uint32_t version; + } video_indeo; } u; }; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 6bf613a9342..3acc2d7cc9d 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -588,6 +588,25 @@ static GstCaps *wg_format_to_caps_video_wmv(const struct wg_format *format) return caps; } +static GstCaps *wg_format_to_caps_video_indeo(const struct wg_format *format) +{ + GstCaps *caps; + + if (!(caps = gst_caps_new_empty_simple("video/x-indeo"))) + return NULL; + + if (format->u.video_indeo.width) + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_indeo.width, NULL); + if (format->u.video_indeo.height) + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_indeo.height, NULL); + if (format->u.video_indeo.fps_d || format->u.video_indeo.fps_n) + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_indeo.fps_n, format->u.video_indeo.fps_d, NULL); + if (format->u.video_indeo.version) + gst_caps_set_simple(caps, "indeoversion", G_TYPE_INT, format->u.video_indeo.version, NULL); + + return caps; +} + GstCaps *wg_format_to_caps(const struct wg_format *format) { switch (format->major_type) @@ -610,6 +629,8 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) return wg_format_to_caps_video_h264(format); case WG_MAJOR_TYPE_VIDEO_WMV: return wg_format_to_caps_video_wmv(format); + case WG_MAJOR_TYPE_VIDEO_INDEO: + return wg_format_to_caps_video_indeo(format); } assert(0); return NULL; @@ -627,6 +648,7 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: + case WG_MAJOR_TYPE_VIDEO_INDEO: GST_FIXME("Format %u not implemented!", a->major_type); /* fallthrough */ case WG_MAJOR_TYPE_UNKNOWN: diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index fe045f822ac..4a5f3efab04 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -444,6 +444,7 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_WMV: + case WG_MAJOR_TYPE_VIDEO_INDEO: if (!(element = transform_find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, raw_caps)) || !append_element(GST_BIN(transform->container), element, &first, &last)) { @@ -499,6 +500,7 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_UNKNOWN: case WG_MAJOR_TYPE_VIDEO_WMV: + case WG_MAJOR_TYPE_VIDEO_INDEO: GST_FIXME("Format %u not implemented!", output_format.major_type); goto out; } diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index c72a284c897..98282683283 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1594,6 +1594,8 @@ static const char *get_major_type_string(enum wg_major_type type) return "h264"; case WG_MAJOR_TYPE_VIDEO_WMV: return "wmv"; + case WG_MAJOR_TYPE_VIDEO_INDEO: + return "indeo"; case WG_MAJOR_TYPE_UNKNOWN: return "unknown"; } @@ -1950,6 +1952,7 @@ static HRESULT WINAPI reader_GetOutputFormat(IWMSyncReader2 *iface, case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: + case WG_MAJOR_TYPE_VIDEO_INDEO: FIXME("Format %u not implemented!\n", format.major_type); break; case WG_MAJOR_TYPE_UNKNOWN: @@ -1991,6 +1994,7 @@ static HRESULT WINAPI reader_GetOutputFormatCount(IWMSyncReader2 *iface, DWORD o case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: + case WG_MAJOR_TYPE_VIDEO_INDEO: FIXME("Format %u not implemented!\n", format.major_type); /* fallthrough */ case WG_MAJOR_TYPE_AUDIO: From 416937ab452d4706044c73bf1dc2e06b4de9ce04 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 8 Feb 2023 01:58:39 -0500 Subject: [PATCH 1394/2777] winegstreamer: Implement basic functionality for video_decoder. (cherry picked from commit 6d7b3addc4ca92fa15d5c7f6f0c4414ceba4651f) CW-Bug-Id: #21175 --- dlls/winegstreamer/video_decoder.c | 250 +++++++++++++++++++++++++++-- 1 file changed, 239 insertions(+), 11 deletions(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index c660be9b212..66df8173038 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -29,10 +29,36 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50, MAKEFOURCC('I','V','5','0')); + +static const GUID *const input_types[] = +{ + &MFVideoFormat_IV50, +}; +static const GUID *const output_types[] = +{ + &MFVideoFormat_YV12, + &MFVideoFormat_YUY2, + &MFVideoFormat_NV11, + &MFVideoFormat_NV12, + &MFVideoFormat_RGB32, + &MFVideoFormat_RGB24, + &MFVideoFormat_RGB565, + &MFVideoFormat_RGB555, + &MFVideoFormat_RGB8, +}; + struct video_decoder { IMFTransform IMFTransform_iface; LONG refcount; + + IMFMediaType *input_type; + IMFMediaType *output_type; + + struct wg_format wg_format; + struct wg_transform *wg_transform; + struct wg_sample_queue *wg_sample_queue; }; static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface) @@ -40,6 +66,35 @@ static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface) return CONTAINING_RECORD(iface, struct video_decoder, IMFTransform_iface); } +static HRESULT try_create_wg_transform(struct video_decoder *decoder) +{ + struct wg_format input_format; + struct wg_format output_format; + + if (decoder->wg_transform) + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = NULL; + + mf_media_type_to_wg_format(decoder->input_type, &input_format); + if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return MF_E_INVALIDMEDIATYPE; + + mf_media_type_to_wg_format(decoder->output_type, &output_format); + if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return MF_E_INVALIDMEDIATYPE; + + output_format.u.video.fps_d = 0; + output_format.u.video.fps_n = 0; + + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format))) + { + ERR("Failed to create transform with input major_type %u.\n", input_format.major_type); + return E_FAIL; + } + + return S_OK; +} + static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) { struct video_decoder *decoder = impl_from_IMFTransform(iface); @@ -79,6 +134,14 @@ static ULONG WINAPI transform_Release(IMFTransform *iface) if (!refcount) { + if (decoder->wg_transform) + wg_transform_destroy(decoder->wg_transform); + if (decoder->input_type) + IMFMediaType_Release(decoder->input_type); + if (decoder->output_type) + IMFMediaType_Release(decoder->output_type); + + wg_sample_queue_destroy(decoder->wg_sample_queue); free(decoder); } @@ -95,15 +158,15 @@ static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *inpu static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) { - TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs); + FIXME("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs); return E_NOTIMPL; } static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, DWORD output_size, DWORD *outputs) { - FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface, - input_size, inputs, output_size, outputs); + FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", + iface, input_size, inputs, output_size, outputs); return E_NOTIMPL; } @@ -165,14 +228,112 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { - FIXME("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); - return E_NOTIMPL; + struct video_decoder *decoder = impl_from_IMFTransform(iface); + GUID major, subtype; + UINT64 frame_size; + HRESULT hr; + ULONG i; + + TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + + if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || + FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) + return E_INVALIDARG; + + if (!IsEqualGUID(&major, &MFMediaType_Video)) + return MF_E_INVALIDMEDIATYPE; + + for (i = 0; i < ARRAY_SIZE(input_types); ++i) + if (IsEqualGUID(&subtype, input_types[i])) + break; + if (i == ARRAY_SIZE(input_types)) + return MF_E_INVALIDMEDIATYPE; + + if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)) || + (frame_size >> 32) == 0 || (UINT32)frame_size == 0) + return MF_E_INVALIDMEDIATYPE; + + if (flags & MFT_SET_TYPE_TEST_ONLY) + return S_OK; + + if (decoder->output_type) + { + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + } + + if (decoder->input_type) + IMFMediaType_Release(decoder->input_type); + IMFMediaType_AddRef((decoder->input_type = type)); + + return S_OK; } static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { - FIXME("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); - return E_NOTIMPL; + struct video_decoder *decoder = impl_from_IMFTransform(iface); + GUID major, subtype; + UINT64 frame_size; + struct wg_format output_format; + HRESULT hr; + ULONG i; + + TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + + if (!decoder->input_type) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || + FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) + return hr; + + if (!IsEqualGUID(&major, &MFMediaType_Video)) + return MF_E_INVALIDMEDIATYPE; + + for (i = 0; i < ARRAY_SIZE(output_types); ++i) + if (IsEqualGUID(&subtype, output_types[i])) + break; + if (i == ARRAY_SIZE(output_types)) + return MF_E_INVALIDMEDIATYPE; + + if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) + return hr; + + if (flags & MFT_SET_TYPE_TEST_ONLY) + return S_OK; + + if (decoder->output_type) + IMFMediaType_Release(decoder->output_type); + IMFMediaType_AddRef((decoder->output_type = type)); + + if (decoder->wg_transform) + { + mf_media_type_to_wg_format(decoder->output_type, &output_format); + + output_format.u.video.width = frame_size >> 32; + output_format.u.video.height = (UINT32)frame_size; + output_format.u.video.fps_d = 0; + output_format.u.video.fps_n = 0; + + if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN + || !wg_transform_set_output_format(decoder->wg_transform, &output_format)) + { + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + return MF_E_INVALIDMEDIATYPE; + } + } + else if (FAILED(hr = try_create_wg_transform(decoder))) + { + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + return hr; + } + + decoder->wg_format.u.video.width = frame_size >> 32; + decoder->wg_format.u.video.height = (UINT32)frame_size; + + return hr; } static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) @@ -219,15 +380,71 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) { - FIXME("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); - return E_NOTIMPL; + struct video_decoder *decoder = impl_from_IMFTransform(iface); + HRESULT hr; + + TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + hr = wg_transform_push_mf(decoder->wg_transform, sample, decoder->wg_sample_queue); + + return hr; } static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { - FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); - return E_NOTIMPL; + struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct wg_format wg_format; + UINT32 sample_size; + UINT64 frame_rate; + GUID subtype; + HRESULT hr; + + TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); + + if (count != 1) + return E_INVALIDARG; + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + *status = samples->dwStatus = 0; + if (!samples->pSample) + return E_INVALIDARG; + + if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype))) + return hr; + if (FAILED(hr = MFCalculateImageSize(&subtype, decoder->wg_format.u.video.width, + decoder->wg_format.u.video.height, &sample_size))) + return hr; + + if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample, + sample_size, &wg_format, &samples->dwStatus))) + wg_sample_queue_flush(decoder->wg_sample_queue, false); + + if (hr == MF_E_TRANSFORM_STREAM_CHANGE) + { + decoder->wg_format = wg_format; + + if (FAILED(hr = MFCalculateImageSize(&subtype, decoder->wg_format.u.video.width, + decoder->wg_format.u.video.height, &sample_size))) + return hr; + + /* keep the frame rate that was requested, GStreamer doesn't provide any */ + if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate))) + { + decoder->wg_format.u.video.fps_n = frame_rate >> 32; + decoder->wg_format.u.video.fps_d = (UINT32)frame_rate; + } + + samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; + *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; + } + + return hr; } static const IMFTransformVtbl transform_vtbl = @@ -263,6 +480,7 @@ static const IMFTransformVtbl transform_vtbl = HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out) { struct video_decoder *decoder; + HRESULT hr; TRACE("out %p.\n", out); @@ -272,7 +490,17 @@ HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out) decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; decoder->refcount = 1; + decoder->wg_format.u.video.fps_d = 1; + decoder->wg_format.u.video.fps_n = 1; + + if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue))) + goto failed; + *out = &decoder->IMFTransform_iface; TRACE("created decoder %p.\n", *out); return S_OK; + +failed: + free(decoder); + return hr; } From 106163706fcd4eb93e1ed8a1b6cae37415a5b29c Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 8 Feb 2023 02:04:02 -0500 Subject: [PATCH 1395/2777] ir50_32: Implement decompression. (cherry picked from commit 4eac23121d17e5b5cca61516429398aac1ed8e5a) CW-Bug-Id: #21175 --- dlls/ir50_32/ir50.c | 149 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 145 insertions(+), 4 deletions(-) diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 428108f09ba..87807aba25f 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -26,6 +26,7 @@ #include "winuser.h" #include "commdlg.h" #include "vfw.h" +#include "initguid.h" #include "ir50_private.h" #include "wine/debug.h" @@ -37,6 +38,14 @@ static HINSTANCE IR50_32_hModule; #define IV50_MAGIC mmioFOURCC('I','V','5','0') #define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020) +DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50, MAKEFOURCC('I','V','5','0')); + +static inline UINT64 +make_uint64( UINT32 high, UINT32 low ) +{ + return ((UINT64)high << 32) | low; +} + static LRESULT IV50_Open( const ICINFO *icinfo ) @@ -133,14 +142,146 @@ IV50_DecompressGetFormat( LPBITMAPINFO in, LPBITMAPINFO out ) static LRESULT IV50_DecompressBegin( IMFTransform *decoder, LPBITMAPINFO in, LPBITMAPINFO out ) { - FIXME("ICM_DECOMPRESS_BEGIN %p %p %p\n", decoder, in, out); - return ICERR_UNSUPPORTED; + IMFMediaType *input_type, *output_type; + const GUID *output_subtype; + LRESULT r = ICERR_INTERNAL; + + TRACE("ICM_DECOMPRESS_BEGIN %p %p %p\n", decoder, in, out); + + if ( !decoder ) + return ICERR_BADPARAM; + + if ( out->bmiHeader.biBitCount == 32 ) + output_subtype = &MFVideoFormat_RGB32; + else if ( out->bmiHeader.biBitCount == 16 ) + output_subtype = &MFVideoFormat_RGB555; + else + return ICERR_BADFORMAT; + + if ( FAILED(MFCreateMediaType( &input_type )) ) + return ICERR_INTERNAL; + + if ( FAILED(MFCreateMediaType( &output_type )) ) + { + IMFMediaType_Release( input_type ); + return ICERR_INTERNAL; + } + + if ( FAILED(IMFMediaType_SetGUID( input_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video )) || + FAILED(IMFMediaType_SetGUID( input_type, &MF_MT_SUBTYPE, &MFVideoFormat_IV50 )) ) + goto done; + if ( FAILED(IMFMediaType_SetUINT64( + input_type, &MF_MT_FRAME_SIZE, + make_uint64( in->bmiHeader.biWidth, in->bmiHeader.biHeight ) )) ) + goto done; + + if ( FAILED(IMFMediaType_SetGUID( output_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video )) || + FAILED(IMFMediaType_SetGUID( output_type, &MF_MT_SUBTYPE, output_subtype )) ) + goto done; + if ( FAILED(IMFMediaType_SetUINT64( + output_type, &MF_MT_FRAME_SIZE, + make_uint64( out->bmiHeader.biWidth, abs(out->bmiHeader.biHeight) ) )) ) + goto done; + + if ( FAILED(IMFTransform_SetInputType( decoder, 0, input_type, 0 )) || + FAILED(IMFTransform_SetOutputType( decoder, 0, output_type, 0 )) ) + goto done; + + r = ICERR_OK; + +done: + IMFMediaType_Release( input_type ); + IMFMediaType_Release( output_type ); + return r; } static LRESULT IV50_Decompress( IMFTransform *decoder, ICDECOMPRESS *icd, DWORD size ) { - FIXME("ICM_DECOMPRESS %p %p %lu\n", decoder, icd, size); - return ICERR_UNSUPPORTED; + IMFSample *in_sample = NULL, *out_sample = NULL; + IMFMediaBuffer *in_buf = NULL, *out_buf = NULL; + MFT_OUTPUT_DATA_BUFFER mft_buf; + DWORD mft_status; + BYTE *data; + HRESULT hr; + LRESULT r = ICERR_INTERNAL; + + TRACE("ICM_DECOMPRESS %p %p %lu\n", decoder, icd, size); + + if ( FAILED(MFCreateSample( &in_sample )) ) + return ICERR_INTERNAL; + + if ( FAILED(MFCreateMemoryBuffer( icd->lpbiInput->biSizeImage, &in_buf )) ) + goto done; + + if ( FAILED(IMFSample_AddBuffer( in_sample, in_buf )) ) + goto done; + + if ( FAILED(MFCreateSample( &out_sample )) ) + goto done; + + if ( FAILED(MFCreateMemoryBuffer( icd->lpbiOutput->biSizeImage, &out_buf )) ) + goto done; + + if ( FAILED(IMFSample_AddBuffer( out_sample, out_buf )) ) + goto done; + + if ( FAILED(IMFMediaBuffer_Lock( in_buf, &data, NULL, NULL ))) + goto done; + + memcpy( data, icd->lpInput, icd->lpbiInput->biSizeImage ); + + if ( FAILED(IMFMediaBuffer_Unlock( in_buf )) ) + goto done; + + if ( FAILED(IMFMediaBuffer_SetCurrentLength( in_buf, icd->lpbiInput->biSizeImage )) ) + goto done; + + if ( FAILED(IMFTransform_ProcessInput( decoder, 0, in_sample, 0 )) ) + goto done; + + memset( &mft_buf, 0, sizeof(mft_buf) ); + mft_buf.pSample = out_sample; + + hr = IMFTransform_ProcessOutput( decoder, 0, 1, &mft_buf, &mft_status ); + if ( SUCCEEDED(hr) && (mft_status & MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE) ) + hr = IMFTransform_ProcessOutput( decoder, 0, 1, &mft_buf, &mft_status ); + + if ( SUCCEEDED(hr) ) + { + LONG width = icd->lpbiOutput->biWidth * (icd->lpbiOutput->biBitCount / 8); + LONG height = abs( icd->lpbiOutput->biHeight ); + LONG data_stride = (width + 3) & ~3; + LONG out_stride = icd->lpbiOutput->biHeight >= 0 ? -data_stride : data_stride; + BYTE *output_start = (BYTE *)icd->lpOutput; + + if (out_stride < 0) + output_start += (height - 1) * abs(out_stride); + + if ( FAILED(IMFMediaBuffer_Lock( out_buf, &data, NULL, NULL ))) + goto done; + + MFCopyImage( output_start, out_stride, data, data_stride, width, height ); + + IMFMediaBuffer_Unlock( out_buf ); + r = ICERR_OK; + } + else if ( hr == MF_E_TRANSFORM_NEED_MORE_INPUT ) + { + TRACE("no output received.\n"); + r = ICERR_OK; + } + +done: + if ( in_buf ) + IMFMediaBuffer_Release( in_buf ); + if ( in_sample ) + IMFSample_Release( in_sample ); + if ( out_buf ) + IMFMediaBuffer_Release( out_buf ); + if ( out_sample ) + IMFSample_Release( out_sample ); + + return r; } static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize ) From 555610770ab2708ba0aaeec9dbabbb9ee56111fb Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 8 Feb 2023 02:46:23 -0500 Subject: [PATCH 1396/2777] wine.inf: Enable ir50_32 video codec. (cherry picked from commit d83e03f638094cbac14307b0eabc9b71025dbaae) CW-Bug-Id: #21175 --- loader/wine.inf.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 31907416078..d99383d6296 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2337,7 +2337,7 @@ system.ini, drivers32,,"msacm.msgsm610=msgsm32.acm" system.ini, drivers32,,"vidc.mrle=msrle32.dll" system.ini, drivers32,,"vidc.msvc=msvidc32.dll" system.ini, drivers32,,"vidc.cvid=iccvid.dll" -system.ini, drivers32,,"; vidc.IV50=ir50_32.dll" +system.ini, drivers32,,"vidc.IV50=ir50_32.dll" system.ini, drivers32,,"; vidc.IV31=ir32_32.dll" system.ini, drivers32,,"; vidc.IV32=ir32_32.dll" From ed610e8913e1a587c1778aa6e5e20f3cec424fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 14 Apr 2023 15:24:03 +0200 Subject: [PATCH 1397/2777] Revert "HACK: winegstreamer: Use capssetter to ignore non-default YUV color spaces." This reverts commit 94d91c0531c1bb59181e38c62cff37f514ea218f. --- dlls/winegstreamer/wg_parser.c | 43 ---------------------------------- 1 file changed, 43 deletions(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index d1ad9ec0e69..d7471536a60 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -960,49 +960,6 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) } else if (!strcmp(name, "video/x-raw")) { - /* Hack?: Flatten down the colorimetry to default values, without - * actually modifying the video at all. - * - * We want to do color matrix conversions when converting from YUV to - * RGB or vice versa. We do *not* want to do color matrix conversions - * when converting YUV <-> YUV or RGB <-> RGB, because these are slow - * (it essentially means always using the slow path, never going through - * liborc). However, we have two videoconvert elements, and it's - * basically impossible to know what conversions each is going to do - * until caps are negotiated (without depending on some implementation - * details, and even then it'snot exactly trivial). And setting - * matrix-mode after caps are negotiated has no effect. - * - * Nor can we just retain colorimetry information the way we retain - * other caps values, because videoconvert automatically clears it if - * not doing passthrough. I think that this would only happen if we have - * to do a double conversion, but that is possible. Not likely, but I - * don't want to have to be the one to find out that there's still a - * game broken. - * - * [Note that we'd actually kind of like to retain colorimetry - * information, just in case it does ever become relevant to pass that - * on to the next DirectShow filter. Hence I think the correct solution - * for upstream is to get videoconvert to Not Do That.] - * - * So as a fallback solution, we force an identity transformation of - * the caps to those with a "default" color matrix—i.e. transform the - * caps, but not the data. We do this by *pre*pending a capssetter to - * the front of the chain, and we remove the matrix-mode setting for the - * videoconvert elements. - */ - if (!(element = create_element("capssetter", "good")) - || !append_element(GST_BIN(parser->container), element, &first, &last)) - goto out; - gst_util_set_object_arg(G_OBJECT(element), "join", "true"); - /* Actually, this is invalid, but it causes videoconvert to use default - * colorimetry as a result. Yes, this is depending on undocumented - * implementation details. It's a hack. - * - * Sadly there doesn't seem to be a way to get capssetter to clear - * certain fields while leaving others untouched. */ - gst_util_set_object_arg(G_OBJECT(element), "caps", "video/x-raw,colorimetry=0:0:0:0"); - /* DirectShow can express interlaced video, but downstream filters can't * necessarily consume it. In particular, the video renderer can't. */ if (!(element = create_element("deinterlace", "good")) From 81b3d6608199828412d18d7976c3415845ae6f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 14 Apr 2023 15:24:29 +0200 Subject: [PATCH 1398/2777] Revert "HACK: winegstreamer: Allow videoconvert to parallelize." This reverts commit 7a5472e6f3e2f7338428c21fdea87eaa467cde4b. --- dlls/winegstreamer/wg_parser.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index d7471536a60..36c350cd338 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -973,9 +973,6 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) || !append_element(GST_BIN(parser->container), element, &first, &last)) goto out; - /* Let GStreamer choose a default number of threads. */ - gst_util_set_object_arg(G_OBJECT(element), "n-threads", "0"); - /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */ if (!(element = create_element("videoflip", "base")) || !append_element(GST_BIN(parser->container), element, &first, &last)) From d4ac5d29465b7f37a38e1a7b3156668f9162f64a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 14 Apr 2023 15:25:17 +0200 Subject: [PATCH 1399/2777] Revert "HACK: winegstreamer: Fake H264 timestamps if framerate cannot be trusted." This reverts commit 08c868d9c4667b2b334d71d5230cfec8e79cffd7. --- dlls/winegstreamer/h264_decoder.c | 18 +----------------- dlls/winegstreamer/wg_transform.c | 9 ++------- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index c5600389be7..ae78374f02e 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -58,8 +58,6 @@ struct h264_decoder IMFMediaType *output_type; MFT_OUTPUT_STREAM_INFO output_info; - UINT64 last_pts; - struct wg_format wg_format; struct wg_transform *wg_transform; struct wg_sample_queue *wg_sample_queue; @@ -75,7 +73,6 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) struct wg_format input_format; struct wg_format output_format; - decoder->last_pts = 0; if (decoder->wg_transform) wg_transform_destroy(decoder->wg_transform); decoder->wg_transform = NULL; @@ -615,10 +612,9 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { struct h264_decoder *decoder = impl_from_IMFTransform(iface); - UINT64 frame_rate, duration; struct wg_format wg_format; UINT32 sample_size; - LONGLONG time; + UINT64 frame_rate; GUID subtype; HRESULT hr; @@ -642,20 +638,8 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample, sample_size, &wg_format, &samples->dwStatus))) - { wg_sample_queue_flush(decoder->wg_sample_queue, false); - if (FAILED(IMFSample_GetSampleTime(samples->pSample, &time)) - || FAILED(IMFSample_GetSampleDuration(samples->pSample, &time))) - { - frame_rate = (UINT64)decoder->wg_format.u.video.fps_n << 32 | decoder->wg_format.u.video.fps_d; - duration = (UINT64)10000000 * (UINT32)frame_rate / (frame_rate >> 32); - IMFSample_SetSampleTime(samples->pSample, decoder->last_pts); - IMFSample_SetSampleDuration(samples->pSample, duration); - decoder->last_pts += duration; - } - } - if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { decoder->wg_format = wg_format; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 4a5f3efab04..e2018ce12c4 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -62,7 +62,6 @@ struct wg_transform GstSample *output_sample; bool output_caps_changed; GstCaps *output_caps; - bool broken_timestamps; bool setting_output_format; }; @@ -434,10 +433,9 @@ NTSTATUS wg_transform_create(void *args) */ transform->input_max_length = 16; transform->output_plane_align = 15; - if ((element = create_element("h264parse", "base")) - && !append_element(GST_BIN(transform->container), element, &first, &last)) + if (!(element = create_element("h264parse", "base")) + || !append_element(GST_BIN(transform->container), element, &first, &last)) goto out; - transform->broken_timestamps = !element; /* fallthrough */ case WG_MAJOR_TYPE_AUDIO_MPEG1: case WG_MAJOR_TYPE_AUDIO_MPEG4: @@ -1022,9 +1020,6 @@ NTSTATUS wg_transform_read_data(void *args) transform->output_sample = NULL; } - if (transform->broken_timestamps) - sample->flags &= ~(WG_SAMPLE_FLAG_HAS_PTS|WG_SAMPLE_FLAG_HAS_DURATION); - params->result = S_OK; wg_allocator_release_sample(transform->allocator, sample, discard_data); return STATUS_SUCCESS; From d6778df4b167f93966f27edc865e0eb07940bca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 14 Apr 2023 15:55:53 +0200 Subject: [PATCH 1400/2777] Revert "HACK: winegstreamer: Check if the decoder accepted our caps." This reverts commit 7e612b8820e3082ea7a92c9500cfe843ec99bae3. --- dlls/winegstreamer/wg_transform.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index e2018ce12c4..a798b0d8dd9 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -527,10 +527,6 @@ NTSTATUS wg_transform_create(void *args) || !gst_pad_push_event(transform->my_src, event)) goto out; - /* Check that the caps event have been accepted */ - if (input_format.major_type == WG_MAJOR_TYPE_VIDEO_H264 && !gst_pad_has_current_caps(transform->their_sink)) - goto out; - /* We need to use GST_FORMAT_TIME here because it's the only format * some elements such avdec_wmav2 correctly support. */ gst_segment_init(&transform->segment, GST_FORMAT_TIME); From 05f0d930d552cbd8d718e83f1b79251f510d4643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 14 Apr 2023 15:25:25 +0200 Subject: [PATCH 1401/2777] Revert "winegstreamer: Use append_element helper in wg_parser." This reverts commit 27f2dfc4069bcd2cc874884a2b311fecbfff16ef. --- dlls/winegstreamer/unix_private.h | 1 - dlls/winegstreamer/wg_parser.c | 47 ++++++++++++++++++++----------- dlls/winegstreamer/wg_transform.c | 18 ++++++------ 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 9f23b52f1c4..e0141f62efd 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -32,7 +32,6 @@ extern bool init_gstreamer(void) DECLSPEC_HIDDEN; extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; -extern bool append_element(GstBin *bin, GstElement *element, GstElement **first, GstElement **last) DECLSPEC_HIDDEN; extern void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) DECLSPEC_HIDDEN; extern bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) DECLSPEC_HIDDEN; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 36c350cd338..5e4bbae3683 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -913,7 +913,6 @@ static void free_stream(struct wg_parser_stream *stream) static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) { - GstElement *first = NULL, *last = NULL; struct wg_parser *parser = user; struct wg_parser_stream *stream; const char *name; @@ -960,46 +959,62 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) } else if (!strcmp(name, "video/x-raw")) { + GstElement *deinterlace, *vconv, *flip, *vconv2; + /* DirectShow can express interlaced video, but downstream filters can't * necessarily consume it. In particular, the video renderer can't. */ - if (!(element = create_element("deinterlace", "good")) - || !append_element(GST_BIN(parser->container), element, &first, &last)) + if (!(deinterlace = create_element("deinterlace", "good"))) goto out; /* decodebin considers many YUV formats to be "raw", but some quartz * filters can't handle those. Also, videoflip can't handle all "raw" * formats either. Add a videoconvert to swap color spaces. */ - if (!(element = create_element("videoconvert", "base")) - || !append_element(GST_BIN(parser->container), element, &first, &last)) + if (!(vconv = create_element("videoconvert", "base"))) goto out; /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */ - if (!(element = create_element("videoflip", "base")) - || !append_element(GST_BIN(parser->container), element, &first, &last)) + if (!(flip = create_element("videoflip", "good"))) goto out; - stream->flip = element; /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert * to do the final conversion. */ - if (!(element = create_element("videoconvert", "base")) - || !append_element(GST_BIN(parser->container), element, &first, &last)) + if (!(vconv2 = create_element("videoconvert", "base"))) goto out; - stream->post_sink = gst_element_get_static_pad(first, "sink"); - stream->post_src = gst_element_get_static_pad(last, "src"); + /* The bin takes ownership of these elements. */ + gst_bin_add(GST_BIN(parser->container), deinterlace); + gst_element_sync_state_with_parent(deinterlace); + gst_bin_add(GST_BIN(parser->container), vconv); + gst_element_sync_state_with_parent(vconv); + gst_bin_add(GST_BIN(parser->container), flip); + gst_element_sync_state_with_parent(flip); + gst_bin_add(GST_BIN(parser->container), vconv2); + gst_element_sync_state_with_parent(vconv2); + + gst_element_link(deinterlace, vconv); + gst_element_link(vconv, flip); + gst_element_link(flip, vconv2); + + stream->post_sink = gst_element_get_static_pad(deinterlace, "sink"); + stream->post_src = gst_element_get_static_pad(vconv2, "src"); + stream->flip = flip; } else if (!strcmp(name, "audio/x-raw")) { + GstElement *convert; + /* Currently our dsound can't handle 64-bit formats or all * surround-sound configurations. Native dsound can't always handle * 64-bit formats either. Add an audioconvert to allow changing bit * depth and channel count. */ - if (!(element = create_element("audioconvert", "base")) - || !append_element(GST_BIN(parser->container), element, &first, &last)) + if (!(convert = create_element("audioconvert", "base"))) goto out; - stream->post_sink = gst_element_get_static_pad(first, "sink"); - stream->post_src = gst_element_get_static_pad(last, "src"); + gst_bin_add(GST_BIN(parser->container), convert); + gst_element_sync_state_with_parent(convert); + + stream->post_sink = gst_element_get_static_pad(convert, "sink"); + stream->post_src = gst_element_get_static_pad(convert, "src"); } if (stream->post_sink) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index a798b0d8dd9..8d54e24f5c8 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -324,14 +324,14 @@ static GstElement *transform_find_element(GstElementFactoryListType type, GstCap return element; } -bool append_element(GstBin *bin, GstElement *element, GstElement **first, GstElement **last) +static bool transform_append_element(struct wg_transform *transform, GstElement *element, + GstElement **first, GstElement **last) { gchar *name = gst_element_get_name(element); bool success = false; - if (!gst_bin_add(bin, element) - || !gst_element_sync_state_with_parent(element) - || (*last && !gst_element_link(*last, element))) + if (!gst_bin_add(GST_BIN(transform->container), element) || + (*last && !gst_element_link(*last, element))) { GST_ERROR("Failed to link %s element.", name); } @@ -434,7 +434,7 @@ NTSTATUS wg_transform_create(void *args) transform->input_max_length = 16; transform->output_plane_align = 15; if (!(element = create_element("h264parse", "base")) - || !append_element(GST_BIN(transform->container), element, &first, &last)) + || !transform_append_element(transform, element, &first, &last)) goto out; /* fallthrough */ case WG_MAJOR_TYPE_AUDIO_MPEG1: @@ -444,7 +444,7 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_INDEO: if (!(element = transform_find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, raw_caps)) - || !append_element(GST_BIN(transform->container), element, &first, &last)) + || !transform_append_element(transform, element, &first, &last)) { gst_caps_unref(raw_caps); goto out; @@ -476,16 +476,16 @@ NTSTATUS wg_transform_create(void *args) * non-interleaved format. */ if (!(element = create_element("audioconvert", "base")) - || !append_element(GST_BIN(transform->container), element, &first, &last)) + || !transform_append_element(transform, element, &first, &last)) goto out; if (!(element = create_element("audioresample", "base")) - || !append_element(GST_BIN(transform->container), element, &first, &last)) + || !transform_append_element(transform, element, &first, &last)) goto out; break; case WG_MAJOR_TYPE_VIDEO: if (!(element = create_element("videoconvert", "base")) - || !append_element(GST_BIN(transform->container), element, &first, &last)) + || !transform_append_element(transform, element, &first, &last)) goto out; /* Let GStreamer choose a default number of threads. */ gst_util_set_object_arg(G_OBJECT(element), "n-threads", "0"); From e9f9150d247cfddf0af0a2acd607b79426182d30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 14 Apr 2023 15:19:56 +0200 Subject: [PATCH 1402/2777] Revert "winegstreamer: create media source from uri" This reverts commit 821204068d11c6de6964315503036c7ccd08e662. --- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 3 +-- dlls/winegstreamer/media_source.c | 32 ++++--------------------- dlls/winegstreamer/quartz_parser.c | 2 +- dlls/winegstreamer/unixlib.h | 2 -- dlls/winegstreamer/wg_parser.c | 38 ------------------------------ dlls/winegstreamer/wm_reader.c | 2 +- 7 files changed, 9 insertions(+), 72 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index e4d0af8af44..fe0515abd3c 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -72,7 +72,7 @@ void wg_sample_queue_flush(struct wg_sample_queue *queue, bool all); struct wg_parser *wg_parser_create(enum wg_parser_type type, bool use_opengl); void wg_parser_destroy(struct wg_parser *parser); -HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size, const WCHAR *uri); +HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size); void wg_parser_disconnect(struct wg_parser *parser); bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, uint32_t *size); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 304b390c8fe..3bf4c2fe38e 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -93,13 +93,12 @@ void wg_parser_destroy(struct wg_parser *parser) WINE_UNIX_CALL(unix_wg_parser_destroy, parser); } -HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size, const WCHAR *uri) +HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size) { struct wg_parser_connect_params params = { .parser = parser, .file_size = file_size, - .uri = uri, }; TRACE("parser %p, file_size %I64u.\n", parser, file_size); diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index e6e78fd4de3..3b1db6944f6 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -880,8 +880,8 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) IMFMediaType *stream_types[9]; struct wg_format format; DWORD type_count = 0; - HRESULT hr = S_OK; unsigned int i; + HRESULT hr; wg_parser_stream_get_preferred_format(stream->wg_stream, &format); @@ -1441,7 +1441,7 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = media_source_Shutdown, }; -static HRESULT media_source_constructor(IMFByteStream *bytestream, const WCHAR *uri, struct media_source **out_media_source) +static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source) { BOOL video_selected = FALSE, audio_selected = FALSE; IMFStreamDescriptor **descriptors = NULL; @@ -1490,7 +1490,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, const WCHAR * if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue))) goto fail; - if (!(parser = wg_parser_create(uri ? WG_PARSER_URIDECODEBIN : WG_PARSER_DECODEBIN, false))) + if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, false))) { hr = E_OUTOFMEMORY; goto fail; @@ -1501,7 +1501,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, const WCHAR * object->state = SOURCE_OPENING; - if (FAILED(hr = wg_parser_connect(parser, file_size, uri))) + if (FAILED(hr = wg_parser_connect(parser, file_size))) goto fail; stream_count = wg_parser_get_stream_count(parser); @@ -1647,28 +1647,6 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, const WCHAR * return hr; } -HRESULT winegstreamer_create_media_source_from_uri(const WCHAR *uri, IUnknown **out_object) -{ - struct media_source *object; - IMFByteStream *bytestream; - IStream *stream; - HRESULT hr; - - if (FAILED(hr = CreateStreamOnHGlobal(0, TRUE, &stream))) - return hr; - - hr = MFCreateMFByteStreamOnStream(stream, &bytestream); - IStream_Release(stream); - if (FAILED(hr)) - return hr; - - if (SUCCEEDED(hr = media_source_constructor(bytestream, uri, &object))) - *out_object = (IUnknown*)&object->IMFMediaSource_iface; - - IMFByteStream_Release(bytestream); - return hr; -} - struct winegstreamer_stream_handler_result { struct list entry; @@ -2009,7 +1987,7 @@ static HRESULT winegstreamer_stream_handler_create_object(struct winegstreamer_s HRESULT hr; struct media_source *new_source; - if (FAILED(hr = media_source_constructor(stream, NULL, &new_source))) + if (FAILED(hr = media_source_constructor(stream, &new_source))) return hr; TRACE("->(%p)\n", new_source); diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index b4cc6f83a0f..60abe8abf54 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1358,7 +1358,7 @@ static HRESULT parser_sink_connect(struct strmbase_sink *iface, IPin *peer, cons filter->sink_connected = true; filter->read_thread = CreateThread(NULL, 0, read_thread, filter, 0, NULL); - if (FAILED(hr = wg_parser_connect(filter->wg_parser, file_size, NULL))) + if (FAILED(hr = wg_parser_connect(filter->wg_parser, file_size))) goto err; if (!filter->init_gst(filter)) diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 89a81b0d780..6a3aa2a3648 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -182,7 +182,6 @@ enum wg_parser_type WG_PARSER_AVIDEMUX, WG_PARSER_MPEGAUDIOPARSE, WG_PARSER_WAVPARSE, - WG_PARSER_URIDECODEBIN, }; struct wg_parser_create_params @@ -197,7 +196,6 @@ struct wg_parser_create_params struct wg_parser_connect_params { struct wg_parser *parser; - const WCHAR *uri; UINT64 file_size; }; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 5e4bbae3683..44a56091a61 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -77,7 +77,6 @@ struct wg_parser guint64 file_size, start_offset, next_offset, stop_offset; guint64 next_pull_offset; - gchar *uri; pthread_t push_thread; @@ -1459,22 +1458,12 @@ static NTSTATUS wg_parser_connect(void *args) GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); const struct wg_parser_connect_params *params = args; struct wg_parser *parser = params->parser; - const WCHAR *uri = params->uri; bool use_mediaconv = false; unsigned int i; int ret; parser->file_size = params->file_size; parser->sink_connected = true; - if (uri) - { - parser->uri = malloc(wcslen(uri) * 3 + 1); - ntdll_wcstoumbs(uri, wcslen(uri) + 1, parser->uri, wcslen(uri) * 3 + 1, FALSE); - } - else - { - parser->uri = NULL; - } if (!parser->bus) { @@ -1723,31 +1712,6 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) return TRUE; } -static BOOL uridecodebin_parser_init_gst(struct wg_parser *parser) -{ - GstElement *element; - - if (!(element = create_element("uridecodebin", "base"))) - return FALSE; - - gst_bin_add(GST_BIN(parser->container), element); - parser->decodebin = element; - - g_object_set(parser->decodebin, "uri", parser->uri, NULL); - g_object_set(parser->decodebin, "max-size-bytes", G_MAXUINT, NULL); - g_signal_connect(element, "pad-added", G_CALLBACK(pad_added_cb), parser); - g_signal_connect(element, "pad-removed", G_CALLBACK(pad_removed_cb), parser); - g_signal_connect(element, "autoplug-select", G_CALLBACK(autoplug_select_cb), parser); - g_signal_connect(element, "autoplug-sort", G_CALLBACK(autoplug_sort_cb), parser); - g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads_cb), parser); - - pthread_mutex_lock(&parser->mutex); - parser->no_more_pads = false; - pthread_mutex_unlock(&parser->mutex); - - return TRUE; -} - static BOOL avi_parser_init_gst(struct wg_parser *parser) { GstElement *element; @@ -1921,7 +1885,6 @@ static NTSTATUS wg_parser_create(void *args) [WG_PARSER_AVIDEMUX] = avi_parser_init_gst, [WG_PARSER_MPEGAUDIOPARSE] = mpeg_audio_parser_init_gst, [WG_PARSER_WAVPARSE] = wave_parser_init_gst, - [WG_PARSER_URIDECODEBIN] = uridecodebin_parser_init_gst, }; struct wg_parser_create_params *params = args; @@ -1973,7 +1936,6 @@ static NTSTATUS wg_parser_destroy(void *args) pthread_cond_destroy(&parser->read_cond); pthread_cond_destroy(&parser->read_done_cond); - free(parser->uri); free(parser); return S_OK; } diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 98282683283..09e191c403a 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1469,7 +1469,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) goto out_destroy_parser; } - if (FAILED(hr = wg_parser_connect(reader->wg_parser, file_size, NULL))) + if (FAILED(hr = wg_parser_connect(reader->wg_parser, file_size))) { ERR("Failed to connect parser, hr %#lx.\n", hr); goto out_shutdown_thread; From a23512d26ae0a69f70a319f61e986eb39db394de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 14 Apr 2023 15:20:18 +0200 Subject: [PATCH 1403/2777] Revert "winegstreamer: Use OpenGL video processing pipeline for WMReader." This reverts commit 92d030f3ee5506820a4b369645c1cfad05193b35. --- configure.ac | 2 +- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 5 +- dlls/winegstreamer/media_source.c | 2 +- dlls/winegstreamer/quartz_parser.c | 2 +- dlls/winegstreamer/unixlib.h | 1 - dlls/winegstreamer/wg_parser.c | 74 +----------------------------- dlls/winegstreamer/wm_reader.c | 5 +- 8 files changed, 8 insertions(+), 85 deletions(-) diff --git a/configure.ac b/configure.ac index 5d3238618ea..e9b26d5499c 100644 --- a/configure.ac +++ b/configure.ac @@ -1582,7 +1582,7 @@ WINE_NOTICE_WITH(pulse, [test -z "$PULSE_LIBS"], dnl **** Check for gstreamer **** if test "x$with_gstreamer" != "xno" then - WINE_PACKAGE_FLAGS(GSTREAMER,[gstreamer-1.0 gstreamer-gl-1.0 gstreamer-video-1.0 gstreamer-audio-1.0],,,, + WINE_PACKAGE_FLAGS(GSTREAMER,[gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0],,,, [AC_CHECK_HEADER([gst/gst.h], [AC_MSG_CHECKING([whether gint64 defined by gst/gst.h is indeed 64-bit]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index fe0515abd3c..734023d1bc2 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -69,7 +69,7 @@ HRESULT wg_sample_queue_create(struct wg_sample_queue **out); void wg_sample_queue_destroy(struct wg_sample_queue *queue); void wg_sample_queue_flush(struct wg_sample_queue *queue, bool all); -struct wg_parser *wg_parser_create(enum wg_parser_type type, bool use_opengl); +struct wg_parser *wg_parser_create(enum wg_parser_type type); void wg_parser_destroy(struct wg_parser *parser); HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 3bf4c2fe38e..e8bc0db3c7e 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -66,17 +66,16 @@ 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 use_opengl) +struct wg_parser *wg_parser_create(enum wg_parser_type type) { struct wg_parser_create_params params = { .type = type, - .use_opengl = use_opengl, .err_on = ERR_ON(quartz), .warn_on = WARN_ON(quartz), }; - TRACE("type %#x, use_opengl %u.\n", type, use_opengl); + TRACE("type %#x.\n", type); if (WINE_UNIX_CALL(unix_wg_parser_create, ¶ms)) return NULL; diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 3b1db6944f6..d99fe45d76a 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1490,7 +1490,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue))) goto fail; - if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, false))) + if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN))) { hr = E_OUTOFMEMORY; goto fail; diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 60abe8abf54..a848fdd33d7 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1495,7 +1495,7 @@ static HRESULT parser_create(enum wg_parser_type type, struct parser **parser) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (!(object->wg_parser = wg_parser_create(type, false))) + if (!(object->wg_parser = wg_parser_create(type))) { free(object); return E_OUTOFMEMORY; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 6a3aa2a3648..29a1fc1d88f 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -188,7 +188,6 @@ struct wg_parser_create_params { struct wg_parser *parser; enum wg_parser_type type; - bool use_opengl; bool err_on; bool warn_on; }; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 44a56091a61..74afc44090b 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -35,8 +35,6 @@ #include #include -#include - #include "ntstatus.h" #define WIN32_NO_STATUS #include "winternl.h" @@ -61,9 +59,6 @@ GST_DEBUG_CATEGORY(wine); typedef BOOL (*init_gst_cb)(struct wg_parser *parser); -static GstGLDisplay *gl_display; -static GstGLContext *gl_context; - struct wg_parser { init_gst_cb init_gst; @@ -98,9 +93,6 @@ struct wg_parser bool sink_connected; bool use_mediaconv; - bool use_opengl; - - GstContext *context; bool using_qtdemux; }; @@ -929,34 +921,7 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) if (!(stream = create_stream(parser, gst_pad_get_stream_id(pad)))) goto out; - if (!strcmp(name, "video/x-raw") && parser->use_opengl) - { - GstElement *first = NULL, *last = NULL, *element; - - if (!(element = create_element("glupload", "base")) - || !append_element(GST_BIN(parser->container), element, &first, &last)) - goto out; - if (!(element = create_element("glcolorconvert", "base")) - || !append_element(GST_BIN(parser->container), element, &first, &last)) - goto out; - if (!(element = create_element("glvideoflip", "base")) - || !append_element(GST_BIN(parser->container), element, &first, &last)) - goto out; - stream->flip = element; - if (!(element = create_element("gldeinterlace", "base")) - || !append_element(GST_BIN(parser->container), element, &first, &last)) - goto out; - if (!(element = create_element("glcolorconvert", "base")) - || !append_element(GST_BIN(parser->container), element, &first, &last)) - goto out; - if (!(element = create_element("gldownload", "base")) - || !append_element(GST_BIN(parser->container), element, &first, &last)) - goto out; - - stream->post_sink = gst_element_get_static_pad(first, "sink"); - stream->post_src = gst_element_get_static_pad(last, "src"); - } - else if (!strcmp(name, "video/x-raw")) + if (!strcmp(name, "video/x-raw")) { GstElement *deinterlace, *vconv, *flip, *vconv2; @@ -1473,8 +1438,6 @@ static NTSTATUS wg_parser_connect(void *args) parser->container = gst_bin_new(NULL); gst_element_set_bus(parser->container, parser->bus); - if (parser->context) - gst_element_set_context(parser->container, parser->context); parser->my_src = gst_pad_new_from_static_template(&src_template, "quartz-src"); gst_pad_set_getrange_function(parser->my_src, src_getrange_cb); @@ -1846,28 +1809,6 @@ static void init_gstreamer_once(void) GST_INFO("GStreamer library version %s; wine built with %d.%d.%d.", gst_version_string(), GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO); - - if (!(gl_display = gst_gl_display_new())) - GST_ERROR("Failed to create OpenGL display"); - else - { - GError *error = NULL; - gboolean ret; - - GST_OBJECT_LOCK(gl_display); - ret = gst_gl_display_create_context(gl_display, NULL, &gl_context, &error); - GST_OBJECT_UNLOCK(gl_display); - g_clear_error(&error); - - if (ret) - gst_gl_display_add_context(gl_display, gl_context); - else - { - GST_ERROR("Failed to create OpenGL context"); - gst_object_unref(gl_display); - gl_display = NULL; - } - } } bool init_gstreamer(void) @@ -1895,16 +1836,6 @@ static NTSTATUS wg_parser_create(void *args) if (!(parser = calloc(1, sizeof(*parser)))) return E_OUTOFMEMORY; - if ((parser->use_opengl = params->use_opengl && gl_display)) - { - if ((parser->context = gst_context_new(GST_GL_DISPLAY_CONTEXT_TYPE, false))) - gst_context_set_gl_display(parser->context, gl_display); - else - { - GST_ERROR("Failed to create parser context"); - parser->use_opengl = FALSE; - } - } pthread_mutex_init(&parser->mutex, NULL); pthread_cond_init(&parser->init_cond, NULL); @@ -1928,9 +1859,6 @@ static NTSTATUS wg_parser_destroy(void *args) gst_object_unref(parser->bus); } - if (parser->context) - gst_context_unref(parser->context); - pthread_mutex_destroy(&parser->mutex); pthread_cond_destroy(&parser->init_cond); pthread_cond_destroy(&parser->read_cond); diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 09e191c403a..ba0998fa572 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1455,10 +1455,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) HRESULT hr; WORD i; - /* 32-bit GStreamer ORC cannot efficiently convert I420 to RGBA, use OpenGL converter - * in that case but keep the usual codepath otherwise. - */ - if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, sizeof(void *) == 4))) + if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN))) return E_OUTOFMEMORY; reader->wg_parser = wg_parser; From 62caa86b430dd385c8d8c2176587cb20492942be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 14 Apr 2023 15:17:34 +0200 Subject: [PATCH 1404/2777] Revert "winegstreamer: HACK: Use a different gst registry file per architecture" This reverts commit 6164e6218e33c6622ea33b6674cc4da52a7ec987. --- dlls/winegstreamer/wg_parser.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 74afc44090b..55244bf659c 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1781,22 +1781,6 @@ static void init_gstreamer_once(void) int argc = ARRAY_SIZE(args) - 1; char **argv = args; GError *err; - const char *e; - - if ((e = getenv("WINE_GST_REGISTRY_DIR"))) - { - char gst_reg[PATH_MAX]; -#if defined(__x86_64__) - const char *arch = "/registry.x86_64.bin"; -#elif defined(__i386__) - const char *arch = "/registry.i386.bin"; -#else -#error Bad arch -#endif - strcpy(gst_reg, e); - strcat(gst_reg, arch); - setenv("GST_REGISTRY_1_0", gst_reg, 1); - } if (!gst_init_check(&argc, &argv, &err)) { From 9fe75e61096248f69707b5d7ba91175277815cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 1 Jun 2023 12:43:26 +0200 Subject: [PATCH 1405/2777] winegstreamer: Introduce a new wg_init_gstreamer unixlib entry. (cherry picked from commit 2df0b96008edded542b60dbeb3803d16c3a1ca30) --- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/main.c | 3 ++ dlls/winegstreamer/quartz_parser.c | 3 -- dlls/winegstreamer/unix_private.h | 16 ++++++- dlls/winegstreamer/unixlib.c | 71 ++++++++++++++++++++++++++++++ dlls/winegstreamer/unixlib.h | 2 + dlls/winegstreamer/wg_allocator.c | 3 -- dlls/winegstreamer/wg_format.c | 3 -- dlls/winegstreamer/wg_parser.c | 42 +----------------- dlls/winegstreamer/wg_transform.c | 6 --- dlls/winegstreamer/wm_reader.c | 3 ++ 11 files changed, 97 insertions(+), 56 deletions(-) create mode 100644 dlls/winegstreamer/unixlib.c diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index a2d4f2a757c..ea232db3ff1 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -17,6 +17,7 @@ C_SRCS = \ quartz_transform.c \ resampler.c \ scheme_handler.c \ + unixlib.c \ video_decoder.c \ video_processor.c \ wg_allocator.c \ diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index e8bc0db3c7e..041ff3cc0d4 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -565,6 +565,9 @@ static BOOL CALLBACK init_gstreamer_proc(INIT_ONCE *once, void *param, void **ct { HINSTANCE handle; + if (WINE_UNIX_CALL(unix_wg_init_gstreamer, NULL)) + return FALSE; + /* Unloading glib is a bad idea.. it installs atexit handlers, * so never unload the dll after loading */ GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index a848fdd33d7..4cd070cd5f9 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1489,9 +1489,6 @@ static HRESULT parser_create(enum wg_parser_type type, struct parser **parser) { struct parser *object; - if (!init_gstreamer()) - return E_FAIL; - if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index e0141f62efd..b7767005ca3 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -30,13 +30,25 @@ #include #include -extern bool init_gstreamer(void) DECLSPEC_HIDDEN; +/* unixlib.c */ + +GST_DEBUG_CATEGORY_EXTERN(wine) DECLSPEC_HIDDEN; +#define GST_CAT_DEFAULT wine + +extern NTSTATUS wg_init_gstreamer(void *args) DECLSPEC_HIDDEN; + +/* wg_parser.c */ + extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; +/* wg_format.c */ + extern void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) DECLSPEC_HIDDEN; extern bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) DECLSPEC_HIDDEN; extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN; +/* wg_transform.c */ + extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_set_output_format(void *args) DECLSPEC_HIDDEN; @@ -45,6 +57,8 @@ extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_get_status(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_drain(void *args) DECLSPEC_HIDDEN; +/* wg_allocator.c */ + /* wg_allocator_release_sample can be used to release any sample that was requested. */ typedef struct wg_sample *(*wg_allocator_request_sample_cb)(gsize size, void *context); extern GstAllocator *wg_allocator_create(wg_allocator_request_sample_cb request_sample, diff --git a/dlls/winegstreamer/unixlib.c b/dlls/winegstreamer/unixlib.c new file mode 100644 index 00000000000..a1799f8043d --- /dev/null +++ b/dlls/winegstreamer/unixlib.c @@ -0,0 +1,71 @@ +/* + * winegstreamer Unix library interface + * + * Copyright 2020-2021 Zebediah Figura 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 + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "winternl.h" +#include "dshow.h" + +#include "unix_private.h" + +/* GStreamer callbacks may be called on threads not created by Wine, and + * therefore cannot access the Wine TEB. This means that we must use GStreamer + * debug logging instead of Wine debug logging. In order to be safe we forbid + * any use of Wine debug logging in this entire file. */ + +GST_DEBUG_CATEGORY(wine); + +NTSTATUS wg_init_gstreamer(void *arg) +{ + char arg0[] = "wine"; + char arg1[] = "--gst-disable-registry-fork"; + char *args[] = {arg0, arg1, NULL}; + int argc = ARRAY_SIZE(args) - 1; + char **argv = args; + GError *err; + + if (!gst_init_check(&argc, &argv, &err)) + { + fprintf(stderr, "winegstreamer: failed to initialize GStreamer: %s\n", err->message); + g_error_free(err); + return STATUS_UNSUCCESSFUL; + } + + GST_DEBUG_CATEGORY_INIT(wine, "WINE", GST_DEBUG_FG_RED, "Wine GStreamer support"); + + GST_INFO("GStreamer library version %s; wine built with %d.%d.%d.", + gst_version_string(), GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO); + return STATUS_SUCCESS; +} diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 29a1fc1d88f..40bab17be39 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -335,6 +335,8 @@ struct wg_transform_drain_params enum unix_funcs { + unix_wg_init_gstreamer, + unix_wg_parser_create, unix_wg_parser_destroy, diff --git a/dlls/winegstreamer/wg_allocator.c b/dlls/winegstreamer/wg_allocator.c index 784677e2b2d..14550ad8bcc 100644 --- a/dlls/winegstreamer/wg_allocator.c +++ b/dlls/winegstreamer/wg_allocator.c @@ -35,9 +35,6 @@ #include "wine/list.h" -GST_DEBUG_CATEGORY_EXTERN(wine); -#define GST_CAT_DEFAULT wine - typedef struct { GstMemory parent; diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 3acc2d7cc9d..9507d6475b0 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -40,9 +40,6 @@ #include "unix_private.h" -GST_DEBUG_CATEGORY_EXTERN(wine); -#define GST_CAT_DEFAULT wine - static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format) { switch (format) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 55244bf659c..840f002c68e 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -49,14 +49,6 @@ typedef enum GST_AUTOPLUG_SELECT_SKIP, } GstAutoplugSelectResult; -/* GStreamer callbacks may be called on threads not created by Wine, and - * therefore cannot access the Wine TEB. This means that we must use GStreamer - * debug logging instead of Wine debug logging. In order to be safe we forbid - * any use of Wine debug logging in this entire file. */ - -GST_DEBUG_CATEGORY(wine); -#define GST_CAT_DEFAULT wine - typedef BOOL (*init_gst_cb)(struct wg_parser *parser); struct wg_parser @@ -1773,35 +1765,6 @@ static BOOL wave_parser_init_gst(struct wg_parser *parser) return TRUE; } -static void init_gstreamer_once(void) -{ - char arg0[] = "wine"; - char arg1[] = "--gst-disable-registry-fork"; - char *args[] = {arg0, arg1, NULL}; - int argc = ARRAY_SIZE(args) - 1; - char **argv = args; - GError *err; - - if (!gst_init_check(&argc, &argv, &err)) - { - fprintf(stderr, "winegstreamer: failed to initialize GStreamer: %s\n", err->message); - g_error_free(err); - return; - } - - GST_DEBUG_CATEGORY_INIT(wine, "WINE", GST_DEBUG_FG_RED, "Wine GStreamer support"); - - GST_INFO("GStreamer library version %s; wine built with %d.%d.%d.", - gst_version_string(), GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO); -} - -bool init_gstreamer(void) -{ - static pthread_once_t init_once = PTHREAD_ONCE_INIT; - - return !pthread_once(&init_once, init_gstreamer_once); -} - static NTSTATUS wg_parser_create(void *args) { static const init_gst_cb init_funcs[] = @@ -1815,9 +1778,6 @@ static NTSTATUS wg_parser_create(void *args) struct wg_parser_create_params *params = args; struct wg_parser *parser; - if (!init_gstreamer()) - return E_FAIL; - if (!(parser = calloc(1, sizeof(*parser)))) return E_OUTOFMEMORY; @@ -1855,6 +1815,8 @@ static NTSTATUS wg_parser_destroy(void *args) const unixlib_entry_t __wine_unix_call_funcs[] = { #define X(name) [unix_ ## name] = name + X(wg_init_gstreamer), + X(wg_parser_create), X(wg_parser_destroy), diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 8d54e24f5c8..ee43f9c41d3 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -39,9 +39,6 @@ #include "unix_private.h" -GST_DEBUG_CATEGORY_EXTERN(wine); -#define GST_CAT_DEFAULT wine - #define GST_SAMPLE_FLAG_WG_CAPS_CHANGED (GST_MINI_OBJECT_FLAG_LAST << 0) struct wg_transform @@ -374,9 +371,6 @@ NTSTATUS wg_transform_create(void *args) if (input_format.major_type == WG_MAJOR_TYPE_VIDEO_H264) touch_h264_used_tag(); - if (!init_gstreamer()) - return STATUS_UNSUCCESSFUL; - if (!(transform = calloc(1, sizeof(*transform)))) return STATUS_NO_MEMORY; if (!(transform->container = gst_bin_new("wg_transform"))) diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index ba0998fa572..e4bab21d453 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -2547,6 +2547,9 @@ HRESULT WINAPI winegstreamer_create_wm_sync_reader(IUnknown *outer, void **out) TRACE("out %p.\n", out); + if (!init_gstreamer()) + return E_FAIL; + if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; From b48737b8d434f4feae4b70f79a4d34be4bde4364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 1 Jun 2023 12:43:42 +0200 Subject: [PATCH 1406/2777] winegstreamer: Move some wg_parser / wg_transform helpers to unixlib.c. (cherry picked from commit c23f6650bfbd02bc1e0f1029a04ff47b973f7ee4) --- dlls/winegstreamer/unix_private.h | 3 +- dlls/winegstreamer/unixlib.c | 54 +++++++++++++++++++++++++++++++ dlls/winegstreamer/wg_parser.c | 10 ------ dlls/winegstreamer/wg_transform.c | 46 +------------------------- 4 files changed, 56 insertions(+), 57 deletions(-) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index b7767005ca3..c8c07f0543f 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -37,9 +37,8 @@ GST_DEBUG_CATEGORY_EXTERN(wine) DECLSPEC_HIDDEN; extern NTSTATUS wg_init_gstreamer(void *args) DECLSPEC_HIDDEN; -/* wg_parser.c */ - extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; +extern GstElement *find_element(GstElementFactoryListType type, GstCaps *src_caps, GstCaps *sink_caps) DECLSPEC_HIDDEN; /* wg_format.c */ diff --git a/dlls/winegstreamer/unixlib.c b/dlls/winegstreamer/unixlib.c index a1799f8043d..cba6d4adf00 100644 --- a/dlls/winegstreamer/unixlib.c +++ b/dlls/winegstreamer/unixlib.c @@ -47,6 +47,60 @@ GST_DEBUG_CATEGORY(wine); +GstElement *create_element(const char *name, const char *plugin_set) +{ + GstElement *element; + + if (!(element = gst_element_factory_make(name, NULL))) + fprintf(stderr, "winegstreamer: failed to create %s, are %u-bit GStreamer \"%s\" plugins installed?\n", + name, 8 * (unsigned int)sizeof(void *), plugin_set); + return element; +} + +GstElement *find_element(GstElementFactoryListType type, GstCaps *src_caps, GstCaps *sink_caps) +{ + GstElement *element = NULL; + GList *tmp, *transforms; + const gchar *name; + + if (!(transforms = gst_element_factory_list_get_elements(type, GST_RANK_MARGINAL))) + goto done; + + tmp = gst_element_factory_list_filter(transforms, src_caps, GST_PAD_SINK, FALSE); + gst_plugin_feature_list_free(transforms); + if (!(transforms = tmp)) + goto done; + + tmp = gst_element_factory_list_filter(transforms, sink_caps, GST_PAD_SRC, FALSE); + gst_plugin_feature_list_free(transforms); + if (!(transforms = tmp)) + goto done; + + transforms = g_list_sort(transforms, gst_plugin_feature_rank_compare_func); + for (tmp = transforms; tmp != NULL && element == NULL; tmp = tmp->next) + { + name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(tmp->data)); + if (!(element = gst_element_factory_create(GST_ELEMENT_FACTORY(tmp->data), NULL))) + GST_WARNING("Failed to create %s element.", name); + } + gst_plugin_feature_list_free(transforms); + +done: + if (element) + { + GST_DEBUG("Created %s element %p.", name, element); + } + else + { + gchar *src_str = gst_caps_to_string(src_caps), *sink_str = gst_caps_to_string(sink_caps); + GST_WARNING("Failed to create element matching caps %s / %s.", src_str, sink_str); + g_free(sink_str); + g_free(src_str); + } + + return element; +} + NTSTATUS wg_init_gstreamer(void *arg) { char arg0[] = "wine"; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 840f002c68e..b0e1f8f94c5 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -820,16 +820,6 @@ static gboolean sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) } } -GstElement *create_element(const char *name, const char *plugin_set) -{ - GstElement *element; - - if (!(element = gst_element_factory_make(name, NULL))) - fprintf(stderr, "winegstreamer: failed to create %s, are %u-bit GStreamer \"%s\" plugins installed?\n", - name, 8 * (unsigned int)sizeof(void *), plugin_set); - return element; -} - static struct wg_parser_stream *create_stream(struct wg_parser *parser, gchar *id) { struct wg_parser_stream *stream, **new_array; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index ee43f9c41d3..331be4aef17 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -277,50 +277,6 @@ NTSTATUS wg_transform_destroy(void *args) return STATUS_SUCCESS; } -static GstElement *transform_find_element(GstElementFactoryListType type, GstCaps *src_caps, GstCaps *sink_caps) -{ - GstElement *element = NULL; - GList *tmp, *transforms; - const gchar *name; - - if (!(transforms = gst_element_factory_list_get_elements(type, GST_RANK_MARGINAL))) - goto done; - - tmp = gst_element_factory_list_filter(transforms, src_caps, GST_PAD_SINK, FALSE); - gst_plugin_feature_list_free(transforms); - if (!(transforms = tmp)) - goto done; - - tmp = gst_element_factory_list_filter(transforms, sink_caps, GST_PAD_SRC, FALSE); - gst_plugin_feature_list_free(transforms); - if (!(transforms = tmp)) - goto done; - - transforms = g_list_sort(transforms, gst_plugin_feature_rank_compare_func); - for (tmp = transforms; tmp != NULL && element == NULL; tmp = tmp->next) - { - name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(tmp->data)); - if (!(element = gst_element_factory_create(GST_ELEMENT_FACTORY(tmp->data), NULL))) - GST_WARNING("Failed to create %s element.", name); - } - gst_plugin_feature_list_free(transforms); - -done: - if (element) - { - GST_DEBUG("Created %s element %p.", name, element); - } - else - { - gchar *src_str = gst_caps_to_string(src_caps), *sink_str = gst_caps_to_string(sink_caps); - GST_WARNING("Failed to create transform matching caps %s / %s.", src_str, sink_str); - g_free(sink_str); - g_free(src_str); - } - - return element; -} - static bool transform_append_element(struct wg_transform *transform, GstElement *element, GstElement **first, GstElement **last) { @@ -437,7 +393,7 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_INDEO: - if (!(element = transform_find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, raw_caps)) + if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, raw_caps)) || !transform_append_element(transform, element, &first, &last)) { gst_caps_unref(raw_caps); From 41554fc6de94c4165327c7971f86c0b2953e935f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 15 Mar 2023 10:38:02 +0100 Subject: [PATCH 1407/2777] winegstreamer: Sync element state with parent in append_element. (cherry picked from commit 5ed0abf3490428ea28de5c6640e6a6e48520bf06) --- dlls/winegstreamer/wg_transform.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 331be4aef17..67768945d38 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -277,13 +277,13 @@ NTSTATUS wg_transform_destroy(void *args) return STATUS_SUCCESS; } -static bool transform_append_element(struct wg_transform *transform, GstElement *element, - GstElement **first, GstElement **last) +static bool append_element(GstElement *container, GstElement *element, GstElement **first, GstElement **last) { gchar *name = gst_element_get_name(element); bool success = false; - if (!gst_bin_add(GST_BIN(transform->container), element) || + if (!gst_bin_add(GST_BIN(container), element) || + !gst_element_sync_state_with_parent(element) || (*last && !gst_element_link(*last, element))) { GST_ERROR("Failed to link %s element.", name); @@ -384,7 +384,7 @@ NTSTATUS wg_transform_create(void *args) transform->input_max_length = 16; transform->output_plane_align = 15; if (!(element = create_element("h264parse", "base")) - || !transform_append_element(transform, element, &first, &last)) + || !append_element(transform->container, element, &first, &last)) goto out; /* fallthrough */ case WG_MAJOR_TYPE_AUDIO_MPEG1: @@ -394,7 +394,7 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_VIDEO_WMV: case WG_MAJOR_TYPE_VIDEO_INDEO: if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, raw_caps)) - || !transform_append_element(transform, element, &first, &last)) + || !append_element(transform->container, element, &first, &last)) { gst_caps_unref(raw_caps); goto out; @@ -426,16 +426,16 @@ NTSTATUS wg_transform_create(void *args) * non-interleaved format. */ if (!(element = create_element("audioconvert", "base")) - || !transform_append_element(transform, element, &first, &last)) + || !append_element(transform->container, element, &first, &last)) goto out; if (!(element = create_element("audioresample", "base")) - || !transform_append_element(transform, element, &first, &last)) + || !append_element(transform->container, element, &first, &last)) goto out; break; case WG_MAJOR_TYPE_VIDEO: if (!(element = create_element("videoconvert", "base")) - || !transform_append_element(transform, element, &first, &last)) + || !append_element(transform->container, element, &first, &last)) goto out; /* Let GStreamer choose a default number of threads. */ gst_util_set_object_arg(G_OBJECT(element), "n-threads", "0"); From 31dfcbdc59388bae236c6184b587b41d329bd1a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 15 Mar 2023 10:40:11 +0100 Subject: [PATCH 1408/2777] winegstreamer: Use append_element to build wg_parser pipeline. (cherry picked from commit 49b0e6c22de7b9c42d7c42a5c5ff76611d75308e) --- dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.c | 24 ++++++++++++++++ dlls/winegstreamer/wg_parser.c | 47 +++++++++++-------------------- dlls/winegstreamer/wg_transform.c | 24 ---------------- 4 files changed, 41 insertions(+), 55 deletions(-) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index c8c07f0543f..8e14704efa2 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -39,6 +39,7 @@ extern NTSTATUS wg_init_gstreamer(void *args) DECLSPEC_HIDDEN; extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; extern GstElement *find_element(GstElementFactoryListType type, GstCaps *src_caps, GstCaps *sink_caps) DECLSPEC_HIDDEN; +extern bool append_element(GstElement *container, GstElement *element, GstElement **first, GstElement **last) DECLSPEC_HIDDEN; /* wg_format.c */ diff --git a/dlls/winegstreamer/unixlib.c b/dlls/winegstreamer/unixlib.c index cba6d4adf00..8869b092eaa 100644 --- a/dlls/winegstreamer/unixlib.c +++ b/dlls/winegstreamer/unixlib.c @@ -101,6 +101,30 @@ GstElement *find_element(GstElementFactoryListType type, GstCaps *src_caps, GstC return element; } +bool append_element(GstElement *container, GstElement *element, GstElement **first, GstElement **last) +{ + gchar *name = gst_element_get_name(element); + bool success = false; + + if (!gst_bin_add(GST_BIN(container), element) || + !gst_element_sync_state_with_parent(element) || + (*last && !gst_element_link(*last, element))) + { + GST_ERROR("Failed to link %s element.", name); + } + else + { + GST_DEBUG("Linked %s element %p.", name, element); + if (!*first) + *first = element; + *last = element; + success = true; + } + + g_free(name); + return success; +} + NTSTATUS wg_init_gstreamer(void *arg) { char arg0[] = "wine"; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index b0e1f8f94c5..fee9655e71d 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -886,6 +886,7 @@ static void free_stream(struct wg_parser_stream *stream) static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) { + GstElement *first = NULL, *last = NULL; struct wg_parser *parser = user; struct wg_parser_stream *stream; const char *name; @@ -905,62 +906,46 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) if (!strcmp(name, "video/x-raw")) { - GstElement *deinterlace, *vconv, *flip, *vconv2; - /* DirectShow can express interlaced video, but downstream filters can't * necessarily consume it. In particular, the video renderer can't. */ - if (!(deinterlace = create_element("deinterlace", "good"))) + if (!(element = create_element("deinterlace", "good")) + || !append_element(parser->container, element, &first, &last)) goto out; /* decodebin considers many YUV formats to be "raw", but some quartz * filters can't handle those. Also, videoflip can't handle all "raw" * formats either. Add a videoconvert to swap color spaces. */ - if (!(vconv = create_element("videoconvert", "base"))) + if (!(element = create_element("videoconvert", "base")) + || !append_element(parser->container, element, &first, &last)) goto out; /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */ - if (!(flip = create_element("videoflip", "good"))) + if (!(element = create_element("videoflip", "good")) + || !append_element(parser->container, element, &first, &last)) goto out; + stream->flip = element; /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert * to do the final conversion. */ - if (!(vconv2 = create_element("videoconvert", "base"))) + if (!(element = create_element("videoconvert", "base")) + || !append_element(parser->container, element, &first, &last)) goto out; - /* The bin takes ownership of these elements. */ - gst_bin_add(GST_BIN(parser->container), deinterlace); - gst_element_sync_state_with_parent(deinterlace); - gst_bin_add(GST_BIN(parser->container), vconv); - gst_element_sync_state_with_parent(vconv); - gst_bin_add(GST_BIN(parser->container), flip); - gst_element_sync_state_with_parent(flip); - gst_bin_add(GST_BIN(parser->container), vconv2); - gst_element_sync_state_with_parent(vconv2); - - gst_element_link(deinterlace, vconv); - gst_element_link(vconv, flip); - gst_element_link(flip, vconv2); - - stream->post_sink = gst_element_get_static_pad(deinterlace, "sink"); - stream->post_src = gst_element_get_static_pad(vconv2, "src"); - stream->flip = flip; + stream->post_sink = gst_element_get_static_pad(first, "sink"); + stream->post_src = gst_element_get_static_pad(last, "src"); } else if (!strcmp(name, "audio/x-raw")) { - GstElement *convert; - /* Currently our dsound can't handle 64-bit formats or all * surround-sound configurations. Native dsound can't always handle * 64-bit formats either. Add an audioconvert to allow changing bit * depth and channel count. */ - if (!(convert = create_element("audioconvert", "base"))) + if (!(element = create_element("audioconvert", "base")) + || !append_element(parser->container, element, &first, &last)) goto out; - gst_bin_add(GST_BIN(parser->container), convert); - gst_element_sync_state_with_parent(convert); - - stream->post_sink = gst_element_get_static_pad(convert, "sink"); - stream->post_src = gst_element_get_static_pad(convert, "src"); + stream->post_sink = gst_element_get_static_pad(first, "sink"); + stream->post_src = gst_element_get_static_pad(last, "src"); } if (stream->post_sink) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 67768945d38..45a33cc27d8 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -277,30 +277,6 @@ NTSTATUS wg_transform_destroy(void *args) return STATUS_SUCCESS; } -static bool append_element(GstElement *container, GstElement *element, GstElement **first, GstElement **last) -{ - gchar *name = gst_element_get_name(element); - bool success = false; - - if (!gst_bin_add(GST_BIN(container), element) || - !gst_element_sync_state_with_parent(element) || - (*last && !gst_element_link(*last, element))) - { - GST_ERROR("Failed to link %s element.", name); - } - else - { - GST_DEBUG("Linked %s element %p.", name, element); - if (!*first) - *first = element; - *last = element; - success = true; - } - - g_free(name); - return success; -} - static struct wg_sample *transform_request_sample(gsize size, void *context) { struct wg_transform *transform = context; From 7fb7a815f125092b6a4faa5ab8912c4c2816045a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 15 Mar 2023 10:56:46 +0100 Subject: [PATCH 1409/2777] winegstreamer: Remove unnecessary unlink in pad-removed callback. (cherry picked from commit 8f7616f360f20543cbcfb44cc307e537afefb4fd) --- dlls/winegstreamer/wg_parser.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index fee9655e71d..cb6caa9265f 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -997,10 +997,6 @@ static void pad_removed_cb(GstElement *element, GstPad *pad, gpointer user) if (stream->their_src == pad) { - if (stream->post_sink) - gst_pad_unlink(stream->their_src, stream->post_sink); - else - gst_pad_unlink(stream->their_src, stream->my_sink); gst_object_unref(stream->their_src); stream->their_src = NULL; return; From 3f4ea920ecfe06e12874a0b79f0e9612602c030e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 15 Mar 2023 10:59:49 +0100 Subject: [PATCH 1410/2777] winegstreamer: Introduce new link_src_to_element / link_element_to_sink helpers. (cherry picked from commit 6d37b673b4063a172be590f431fe5b69320dceca) --- dlls/winegstreamer/unix_private.h | 2 ++ dlls/winegstreamer/unixlib.c | 46 +++++++++++++++++++++++++++++++ dlls/winegstreamer/wg_parser.c | 39 +++----------------------- dlls/winegstreamer/wg_transform.c | 15 ++-------- 4 files changed, 54 insertions(+), 48 deletions(-) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 8e14704efa2..696a5c0f8a4 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -40,6 +40,8 @@ extern NTSTATUS wg_init_gstreamer(void *args) DECLSPEC_HIDDEN; extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; extern GstElement *find_element(GstElementFactoryListType type, GstCaps *src_caps, GstCaps *sink_caps) DECLSPEC_HIDDEN; extern bool append_element(GstElement *container, GstElement *element, GstElement **first, GstElement **last) DECLSPEC_HIDDEN; +extern bool link_src_to_element(GstPad *src_pad, GstElement *element) DECLSPEC_HIDDEN; +extern bool link_element_to_sink(GstElement *element, GstPad *sink_pad) DECLSPEC_HIDDEN; /* wg_format.c */ diff --git a/dlls/winegstreamer/unixlib.c b/dlls/winegstreamer/unixlib.c index 8869b092eaa..7111402bf0a 100644 --- a/dlls/winegstreamer/unixlib.c +++ b/dlls/winegstreamer/unixlib.c @@ -125,6 +125,52 @@ bool append_element(GstElement *container, GstElement *element, GstElement **fir return success; } +bool link_src_to_element(GstPad *src_pad, GstElement *element) +{ + GstPadLinkReturn ret; + GstPad *sink_pad; + + if (!(sink_pad = gst_element_get_static_pad(element, "sink"))) + { + gchar *name = gst_element_get_name(element); + GST_ERROR("Failed to find sink pad on %s", name); + g_free(name); + return false; + } + if ((ret = gst_pad_link(src_pad, sink_pad))) + { + gchar *src_name = gst_pad_get_name(src_pad), *sink_name = gst_pad_get_name(sink_pad); + GST_ERROR("Failed to link element pad %s with pad %s", src_name, sink_name); + g_free(sink_name); + g_free(src_name); + } + gst_object_unref(sink_pad); + return !ret; +} + +bool link_element_to_sink(GstElement *element, GstPad *sink_pad) +{ + GstPadLinkReturn ret; + GstPad *src_pad; + + if (!(src_pad = gst_element_get_static_pad(element, "src"))) + { + gchar *name = gst_element_get_name(element); + GST_ERROR("Failed to find src pad on %s", name); + g_free(name); + return false; + } + if ((ret = gst_pad_link(src_pad, sink_pad))) + { + gchar *src_name = gst_pad_get_name(src_pad), *sink_name = gst_pad_get_name(sink_pad); + GST_ERROR("Failed to link pad %s with element pad %s", src_name, sink_name); + g_free(sink_name); + g_free(src_name); + } + gst_object_unref(src_pad); + return !ret; +} + NTSTATUS wg_init_gstreamer(void *arg) { char arg0[] = "wine"; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index cb6caa9265f..ca07704c44c 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -93,7 +93,7 @@ struct wg_parser_stream struct wg_parser *parser; uint32_t number; - GstPad *their_src, *post_sink, *post_src, *my_sink; + GstPad *their_src, *my_sink; GstElement *flip; GstSegment segment; struct wg_format preferred_format, current_format; @@ -858,15 +858,7 @@ static void free_stream(struct wg_parser_stream *stream) unsigned int i; if (stream->their_src) - { - if (stream->post_sink) - { - gst_object_unref(stream->post_src); - gst_object_unref(stream->post_sink); - stream->post_src = stream->post_sink = NULL; - } gst_object_unref(stream->their_src); - } gst_object_unref(stream->my_sink); pthread_cond_destroy(&stream->event_cond); @@ -931,8 +923,8 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) || !append_element(parser->container, element, &first, &last)) goto out; - stream->post_sink = gst_element_get_static_pad(first, "sink"); - stream->post_src = gst_element_get_static_pad(last, "src"); + if (!link_src_to_element(pad, first) || !link_element_to_sink(last, stream->my_sink)) + goto out; } else if (!strcmp(name, "audio/x-raw")) { @@ -944,31 +936,8 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) || !append_element(parser->container, element, &first, &last)) goto out; - stream->post_sink = gst_element_get_static_pad(first, "sink"); - stream->post_src = gst_element_get_static_pad(last, "src"); - } - - if (stream->post_sink) - { - if ((ret = gst_pad_link(pad, stream->post_sink)) < 0) - { - GST_ERROR("Failed to link decodebin source pad to post-processing elements, error %s.", - gst_pad_link_get_name(ret)); - gst_object_unref(stream->post_sink); - stream->post_sink = NULL; - goto out; - } - - if ((ret = gst_pad_link(stream->post_src, stream->my_sink)) < 0) - { - GST_ERROR("Failed to link post-processing elements to our sink pad, error %s.", - gst_pad_link_get_name(ret)); - gst_object_unref(stream->post_src); - stream->post_src = NULL; - gst_object_unref(stream->post_sink); - stream->post_sink = NULL; + if (!link_src_to_element(pad, first) || !link_element_to_sink(last, stream->my_sink)) goto out; - } } else if ((ret = gst_pad_link(pad, stream->my_sink)) < 0) { diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 45a33cc27d8..f0ee9fed962 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -46,7 +46,6 @@ struct wg_transform GstElement *container; GstAllocator *allocator; GstPad *my_src, *my_sink; - GstPad *their_sink, *their_src; GstSegment segment; GstQuery *drain_query; @@ -264,8 +263,6 @@ NTSTATUS wg_transform_destroy(void *args) gst_sample_unref(sample); wg_allocator_destroy(transform->allocator); - g_object_unref(transform->their_sink); - g_object_unref(transform->their_src); g_object_unref(transform->container); g_object_unref(transform->my_sink); g_object_unref(transform->my_src); @@ -429,13 +426,9 @@ NTSTATUS wg_transform_create(void *args) goto out; } - if (!(transform->their_sink = gst_element_get_static_pad(first, "sink"))) + if (!link_src_to_element(transform->my_src, first)) goto out; - if (!(transform->their_src = gst_element_get_static_pad(last, "src"))) - goto out; - if (gst_pad_link(transform->my_src, transform->their_sink) < 0) - goto out; - if (gst_pad_link(transform->their_src, transform->my_sink) < 0) + if (!link_element_to_sink(last, transform->my_sink)) goto out; if (!gst_pad_set_active(transform->my_sink, 1)) goto out; @@ -469,10 +462,6 @@ NTSTATUS wg_transform_create(void *args) return STATUS_SUCCESS; out: - if (transform->their_sink) - gst_object_unref(transform->their_sink); - if (transform->their_src) - gst_object_unref(transform->their_src); if (transform->my_sink) gst_object_unref(transform->my_sink); if (transform->output_caps) From 2aaca2a5868934f242cecf4e1342f9bff2f51f94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 15 Apr 2023 08:33:22 +0200 Subject: [PATCH 1411/2777] winegstreamer: Introduce new stream_type_from_caps helper. (cherry picked from commit 223d279205420d37c32f8af3d9883f84a7e0da67) --- dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.c | 21 +++++++++++++++++++++ dlls/winegstreamer/wg_transform.c | 17 +++-------------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 696a5c0f8a4..1b892cb0a98 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -37,6 +37,7 @@ GST_DEBUG_CATEGORY_EXTERN(wine) DECLSPEC_HIDDEN; extern NTSTATUS wg_init_gstreamer(void *args) DECLSPEC_HIDDEN; +extern GstStreamType stream_type_from_caps(GstCaps *caps) DECLSPEC_HIDDEN; extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; extern GstElement *find_element(GstElementFactoryListType type, GstCaps *src_caps, GstCaps *sink_caps) DECLSPEC_HIDDEN; extern bool append_element(GstElement *container, GstElement *element, GstElement **first, GstElement **last) DECLSPEC_HIDDEN; diff --git a/dlls/winegstreamer/unixlib.c b/dlls/winegstreamer/unixlib.c index 7111402bf0a..6ffd41e9712 100644 --- a/dlls/winegstreamer/unixlib.c +++ b/dlls/winegstreamer/unixlib.c @@ -47,6 +47,27 @@ GST_DEBUG_CATEGORY(wine); +GstStreamType stream_type_from_caps(GstCaps *caps) +{ + const gchar *media_type; + + if (!caps || !gst_caps_get_size(caps)) + return GST_STREAM_TYPE_UNKNOWN; + + media_type = gst_structure_get_name(gst_caps_get_structure(caps, 0)); + if (g_str_has_prefix(media_type, "video/") + || g_str_has_prefix(media_type, "image/")) + return GST_STREAM_TYPE_VIDEO; + if (g_str_has_prefix(media_type, "audio/")) + return GST_STREAM_TYPE_AUDIO; + if (g_str_has_prefix(media_type, "text/") + || g_str_has_prefix(media_type, "subpicture/") + || g_str_has_prefix(media_type, "closedcaption/")) + return GST_STREAM_TYPE_TEXT; + + return GST_STREAM_TYPE_UNKNOWN; +} + GstElement *create_element(const char *name, const char *plugin_set) { GstElement *element; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index f0ee9fed962..e6429a04622 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -61,17 +61,6 @@ struct wg_transform bool setting_output_format; }; -static bool is_caps_video(GstCaps *caps) -{ - const gchar *media_type; - - if (!caps || !gst_caps_get_size(caps)) - return false; - - media_type = gst_structure_get_name(gst_caps_get_structure(caps, 0)); - return g_str_has_prefix(media_type, "video/"); -} - static void align_video_info_planes(gsize plane_align, GstVideoInfo *info, GstVideoAlignment *align) { gst_video_alignment_reset(align); @@ -133,7 +122,7 @@ static gboolean transform_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery GstCaps *caps; gst_query_parse_allocation(query, &caps, &needs_pool); - if (!is_caps_video(caps) || !needs_pool) + if (stream_type_from_caps(caps) != GST_STREAM_TYPE_VIDEO || !needs_pool) break; if (!gst_video_info_from_caps(&info, caps) @@ -752,7 +741,7 @@ static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsi } else { - if (is_caps_video(caps)) + if (stream_type_from_caps(caps) == GST_STREAM_TYPE_VIDEO) status = copy_video_buffer(buffer, caps, plane_align, sample, &total_size); else status = copy_buffer(buffer, caps, sample, &total_size); @@ -789,7 +778,7 @@ static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsi if (needs_copy) { - if (is_caps_video(caps)) + if (stream_type_from_caps(caps) == GST_STREAM_TYPE_VIDEO) GST_WARNING("Copied %u bytes, sample %p, flags %#x", sample->size, sample, sample->flags); else GST_INFO("Copied %u bytes, sample %p, flags %#x", sample->size, sample, sample->flags); From e1341813e338a787ec7978c3ac9fda4d6dcecf8a Mon Sep 17 00:00:00 2001 From: Anton Baskanov Date: Sat, 15 Apr 2023 13:53:33 +0700 Subject: [PATCH 1412/2777] winegstreamer: Call init_gstreamer() in winegstreamer_create_video_decoder(). (cherry picked from commit 5ae89b0c8b5465f9a8465b1fc53612f70cbb13e6) --- dlls/winegstreamer/video_decoder.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 66df8173038..1fdabd46b96 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -484,6 +484,9 @@ HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out) TRACE("out %p.\n", out); + if (!init_gstreamer()) + return E_FAIL; + if (!(decoder = calloc(1, sizeof(*decoder)))) return E_OUTOFMEMORY; From 7d1f4d912bb5ebb0419fe253dbd9d441da3cfe26 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Thu, 30 Jan 2020 10:16:19 -0600 Subject: [PATCH 1413/2777] winegstreamer: HACK: Use a different gst registry file per architecture --- dlls/winegstreamer/unixlib.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dlls/winegstreamer/unixlib.c b/dlls/winegstreamer/unixlib.c index 6ffd41e9712..e6029168982 100644 --- a/dlls/winegstreamer/unixlib.c +++ b/dlls/winegstreamer/unixlib.c @@ -201,6 +201,23 @@ NTSTATUS wg_init_gstreamer(void *arg) char **argv = args; GError *err; + const char *e; + + if ((e = getenv("WINE_GST_REGISTRY_DIR"))) + { + char gst_reg[PATH_MAX]; +#if defined(__x86_64__) + const char *arch = "/registry.x86_64.bin"; +#elif defined(__i386__) + const char *arch = "/registry.i386.bin"; +#else +#error Bad arch +#endif + strcpy(gst_reg, e); + strcat(gst_reg, arch); + setenv("GST_REGISTRY_1_0", gst_reg, 1); + } + if (!gst_init_check(&argc, &argv, &err)) { fprintf(stderr, "winegstreamer: failed to initialize GStreamer: %s\n", err->message); From a4eb2896193314ad2d6123660c7a5e1da7e60e08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 Aug 2022 16:06:34 +0200 Subject: [PATCH 1414/2777] winegstreamer: Use OpenGL video processing pipeline for WMReader. There's many 32-bit games using either the WM reader or the ASF reader filter, and which require conversion from I420 to RGBA. However, ORC fails to create an optimized routine as it doesn't support spilling vector registers and it needs more than what's available in 32-bit x86. The WM reader (and the ASF reader filter) currently reads audio and video samples synchronously, and having a high video decoding latency causes trouble on the audio stream. Using OpenGL to post-process the video, and more specifically for the color conversion makes it generally faster, enough to solve the problem in most cases. CW-Bug-Id: #18799 CW-Bug-Id: #18994 CW-Bug-Id: #20182 CW-Bug-Id: #20363 CW-Bug-Id: #20905 CW-Bug-Id: #20980 --- configure.ac | 2 +- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 5 +-- dlls/winegstreamer/media_source.c | 2 +- dlls/winegstreamer/quartz_parser.c | 2 +- dlls/winegstreamer/unixlib.c | 32 +++++++++++++++++-- dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_parser.c | 49 +++++++++++++++++++++++++++++- dlls/winegstreamer/wm_reader.c | 5 ++- 9 files changed, 89 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index e9b26d5499c..5d3238618ea 100644 --- a/configure.ac +++ b/configure.ac @@ -1582,7 +1582,7 @@ WINE_NOTICE_WITH(pulse, [test -z "$PULSE_LIBS"], dnl **** Check for gstreamer **** if test "x$with_gstreamer" != "xno" then - WINE_PACKAGE_FLAGS(GSTREAMER,[gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0],,,, + WINE_PACKAGE_FLAGS(GSTREAMER,[gstreamer-1.0 gstreamer-gl-1.0 gstreamer-video-1.0 gstreamer-audio-1.0],,,, [AC_CHECK_HEADER([gst/gst.h], [AC_MSG_CHECKING([whether gint64 defined by gst/gst.h is indeed 64-bit]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 734023d1bc2..fe0515abd3c 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -69,7 +69,7 @@ HRESULT wg_sample_queue_create(struct wg_sample_queue **out); void wg_sample_queue_destroy(struct wg_sample_queue *queue); void wg_sample_queue_flush(struct wg_sample_queue *queue, bool all); -struct wg_parser *wg_parser_create(enum wg_parser_type type); +struct wg_parser *wg_parser_create(enum wg_parser_type type, bool use_opengl); void wg_parser_destroy(struct wg_parser *parser); HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 041ff3cc0d4..753f9cc48b1 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -66,16 +66,17 @@ 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) +struct wg_parser *wg_parser_create(enum wg_parser_type type, bool use_opengl) { struct wg_parser_create_params params = { .type = type, + .use_opengl = use_opengl, .err_on = ERR_ON(quartz), .warn_on = WARN_ON(quartz), }; - TRACE("type %#x.\n", type); + TRACE("type %#x, use_opengl %u.\n", type, use_opengl); if (WINE_UNIX_CALL(unix_wg_parser_create, ¶ms)) return NULL; diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index d99fe45d76a..3b1db6944f6 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1490,7 +1490,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue))) goto fail; - if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN))) + if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, false))) { hr = E_OUTOFMEMORY; goto fail; diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 4cd070cd5f9..b9330d90e44 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1492,7 +1492,7 @@ static HRESULT parser_create(enum wg_parser_type type, struct parser **parser) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (!(object->wg_parser = wg_parser_create(type))) + if (!(object->wg_parser = wg_parser_create(type, false))) { free(object); return E_OUTOFMEMORY; diff --git a/dlls/winegstreamer/unixlib.c b/dlls/winegstreamer/unixlib.c index e6029168982..a185000654d 100644 --- a/dlls/winegstreamer/unixlib.c +++ b/dlls/winegstreamer/unixlib.c @@ -28,10 +28,9 @@ #include #include +#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_30 #include -#include -#include -#include +#include #include "ntstatus.h" #define WIN32_NO_STATUS @@ -47,6 +46,8 @@ GST_DEBUG_CATEGORY(wine); +GstGLDisplay *gl_display; + GstStreamType stream_type_from_caps(GstCaps *caps) { const gchar *media_type; @@ -194,6 +195,8 @@ bool link_element_to_sink(GstElement *element, GstPad *sink_pad) NTSTATUS wg_init_gstreamer(void *arg) { + static GstGLContext *gl_context; + char arg0[] = "wine"; char arg1[] = "--gst-disable-registry-fork"; char *args[] = {arg0, arg1, NULL}; @@ -229,5 +232,28 @@ NTSTATUS wg_init_gstreamer(void *arg) GST_INFO("GStreamer library version %s; wine built with %d.%d.%d.", gst_version_string(), GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO); + + if (!(gl_display = gst_gl_display_new())) + GST_ERROR("Failed to create OpenGL display"); + else + { + GError *error = NULL; + gboolean ret; + + GST_OBJECT_LOCK(gl_display); + ret = gst_gl_display_create_context(gl_display, NULL, &gl_context, &error); + GST_OBJECT_UNLOCK(gl_display); + g_clear_error(&error); + + if (ret) + gst_gl_display_add_context(gl_display, gl_context); + else + { + GST_ERROR("Failed to create OpenGL context"); + gst_object_unref(gl_display); + gl_display = NULL; + } + } + return STATUS_SUCCESS; } diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 40bab17be39..926128f04c3 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -188,6 +188,7 @@ struct wg_parser_create_params { struct wg_parser *parser; enum wg_parser_type type; + bool use_opengl; bool err_on; bool warn_on; }; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index ca07704c44c..da312e825f5 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -35,6 +35,8 @@ #include #include +#include + #include "ntstatus.h" #define WIN32_NO_STATUS #include "winternl.h" @@ -51,6 +53,8 @@ typedef enum typedef BOOL (*init_gst_cb)(struct wg_parser *parser); +extern GstGLDisplay *gl_display; + struct wg_parser { init_gst_cb init_gst; @@ -85,6 +89,9 @@ struct wg_parser bool sink_connected; bool use_mediaconv; + bool use_opengl; + + GstContext *context; bool using_qtdemux; }; @@ -896,7 +903,32 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) if (!(stream = create_stream(parser, gst_pad_get_stream_id(pad)))) goto out; - if (!strcmp(name, "video/x-raw")) + if (!strcmp(name, "video/x-raw") && parser->use_opengl) + { + if (!(element = create_element("glupload", "base")) + || !append_element(parser->container, element, &first, &last)) + goto out; + if (!(element = create_element("glcolorconvert", "base")) + || !append_element(parser->container, element, &first, &last)) + goto out; + if (!(element = create_element("glvideoflip", "base")) + || !append_element(parser->container, element, &first, &last)) + goto out; + stream->flip = element; + if (!(element = create_element("gldeinterlace", "base")) + || !append_element(parser->container, element, &first, &last)) + goto out; + if (!(element = create_element("glcolorconvert", "base")) + || !append_element(parser->container, element, &first, &last)) + goto out; + if (!(element = create_element("gldownload", "base")) + || !append_element(parser->container, element, &first, &last)) + goto out; + + if (!link_src_to_element(pad, first) || !link_element_to_sink(last, stream->my_sink)) + goto out; + } + else if (!strcmp(name, "video/x-raw")) { /* DirectShow can express interlaced video, but downstream filters can't * necessarily consume it. In particular, the video renderer can't. */ @@ -1370,6 +1402,8 @@ static NTSTATUS wg_parser_connect(void *args) parser->container = gst_bin_new(NULL); gst_element_set_bus(parser->container, parser->bus); + if (parser->context) + gst_element_set_context(parser->container, parser->context); parser->my_src = gst_pad_new_from_static_template(&src_template, "quartz-src"); gst_pad_set_getrange_function(parser->my_src, src_getrange_cb); @@ -1720,6 +1754,16 @@ static NTSTATUS wg_parser_create(void *args) if (!(parser = calloc(1, sizeof(*parser)))) return E_OUTOFMEMORY; + if ((parser->use_opengl = params->use_opengl && gl_display)) + { + if ((parser->context = gst_context_new(GST_GL_DISPLAY_CONTEXT_TYPE, false))) + gst_context_set_gl_display(parser->context, gl_display); + else + { + GST_ERROR("Failed to create parser context"); + parser->use_opengl = FALSE; + } + } pthread_mutex_init(&parser->mutex, NULL); pthread_cond_init(&parser->init_cond, NULL); @@ -1743,6 +1787,9 @@ static NTSTATUS wg_parser_destroy(void *args) gst_object_unref(parser->bus); } + if (parser->context) + gst_context_unref(parser->context); + pthread_mutex_destroy(&parser->mutex); pthread_cond_destroy(&parser->init_cond); pthread_cond_destroy(&parser->read_cond); diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index e4bab21d453..0cd7497e985 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1455,7 +1455,10 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) HRESULT hr; WORD i; - if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN))) + /* 32-bit GStreamer ORC cannot efficiently convert I420 to RGBA, use OpenGL converter + * in that case but keep the usual codepath otherwise. + */ + if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, sizeof(void *) == 4))) return E_OUTOFMEMORY; reader->wg_parser = wg_parser; From 24df3affb687caeb0db8cba7e8f69bd94654bf1f Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Fri, 24 Jun 2022 19:46:42 +0200 Subject: [PATCH 1415/2777] winegstreamer: create media source from uri Supported by gstreamer's uridecodebin. Link: https://github.com/ValveSoftware/wine/pull/142 CW-Bug-Id: #20485 --- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 3 ++- dlls/winegstreamer/media_source.c | 32 +++++++++++++++++++++---- dlls/winegstreamer/quartz_parser.c | 2 +- dlls/winegstreamer/unixlib.h | 2 ++ dlls/winegstreamer/wg_parser.c | 38 ++++++++++++++++++++++++++++++ dlls/winegstreamer/wm_reader.c | 2 +- 7 files changed, 72 insertions(+), 9 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index fe0515abd3c..e4d0af8af44 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -72,7 +72,7 @@ void wg_sample_queue_flush(struct wg_sample_queue *queue, bool all); struct wg_parser *wg_parser_create(enum wg_parser_type type, bool use_opengl); void wg_parser_destroy(struct wg_parser *parser); -HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size); +HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size, const WCHAR *uri); void wg_parser_disconnect(struct wg_parser *parser); bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, uint32_t *size); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 753f9cc48b1..232e81a6f27 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -93,12 +93,13 @@ void wg_parser_destroy(struct wg_parser *parser) WINE_UNIX_CALL(unix_wg_parser_destroy, parser); } -HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size) +HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size, const WCHAR *uri) { struct wg_parser_connect_params params = { .parser = parser, .file_size = file_size, + .uri = uri, }; TRACE("parser %p, file_size %I64u.\n", parser, file_size); diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 3b1db6944f6..e6e78fd4de3 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -880,8 +880,8 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) IMFMediaType *stream_types[9]; struct wg_format format; DWORD type_count = 0; + HRESULT hr = S_OK; unsigned int i; - HRESULT hr; wg_parser_stream_get_preferred_format(stream->wg_stream, &format); @@ -1441,7 +1441,7 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = media_source_Shutdown, }; -static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source) +static HRESULT media_source_constructor(IMFByteStream *bytestream, const WCHAR *uri, struct media_source **out_media_source) { BOOL video_selected = FALSE, audio_selected = FALSE; IMFStreamDescriptor **descriptors = NULL; @@ -1490,7 +1490,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue))) goto fail; - if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, false))) + if (!(parser = wg_parser_create(uri ? WG_PARSER_URIDECODEBIN : WG_PARSER_DECODEBIN, false))) { hr = E_OUTOFMEMORY; goto fail; @@ -1501,7 +1501,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ object->state = SOURCE_OPENING; - if (FAILED(hr = wg_parser_connect(parser, file_size))) + if (FAILED(hr = wg_parser_connect(parser, file_size, uri))) goto fail; stream_count = wg_parser_get_stream_count(parser); @@ -1647,6 +1647,28 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ return hr; } +HRESULT winegstreamer_create_media_source_from_uri(const WCHAR *uri, IUnknown **out_object) +{ + struct media_source *object; + IMFByteStream *bytestream; + IStream *stream; + HRESULT hr; + + if (FAILED(hr = CreateStreamOnHGlobal(0, TRUE, &stream))) + return hr; + + hr = MFCreateMFByteStreamOnStream(stream, &bytestream); + IStream_Release(stream); + if (FAILED(hr)) + return hr; + + if (SUCCEEDED(hr = media_source_constructor(bytestream, uri, &object))) + *out_object = (IUnknown*)&object->IMFMediaSource_iface; + + IMFByteStream_Release(bytestream); + return hr; +} + struct winegstreamer_stream_handler_result { struct list entry; @@ -1987,7 +2009,7 @@ static HRESULT winegstreamer_stream_handler_create_object(struct winegstreamer_s HRESULT hr; struct media_source *new_source; - if (FAILED(hr = media_source_constructor(stream, &new_source))) + if (FAILED(hr = media_source_constructor(stream, NULL, &new_source))) return hr; TRACE("->(%p)\n", new_source); diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index b9330d90e44..4f91b2584e2 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1358,7 +1358,7 @@ static HRESULT parser_sink_connect(struct strmbase_sink *iface, IPin *peer, cons filter->sink_connected = true; filter->read_thread = CreateThread(NULL, 0, read_thread, filter, 0, NULL); - if (FAILED(hr = wg_parser_connect(filter->wg_parser, file_size))) + if (FAILED(hr = wg_parser_connect(filter->wg_parser, file_size, NULL))) goto err; if (!filter->init_gst(filter)) diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 926128f04c3..9134cc47413 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -182,6 +182,7 @@ enum wg_parser_type WG_PARSER_AVIDEMUX, WG_PARSER_MPEGAUDIOPARSE, WG_PARSER_WAVPARSE, + WG_PARSER_URIDECODEBIN, }; struct wg_parser_create_params @@ -196,6 +197,7 @@ struct wg_parser_create_params struct wg_parser_connect_params { struct wg_parser *parser; + const WCHAR *uri; UINT64 file_size; }; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index da312e825f5..c5ff3a1d513 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -68,6 +68,7 @@ struct wg_parser guint64 file_size, start_offset, next_offset, stop_offset; guint64 next_pull_offset; + gchar *uri; pthread_t push_thread; @@ -1387,12 +1388,22 @@ static NTSTATUS wg_parser_connect(void *args) GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); const struct wg_parser_connect_params *params = args; struct wg_parser *parser = params->parser; + const WCHAR *uri = params->uri; bool use_mediaconv = false; unsigned int i; int ret; parser->file_size = params->file_size; parser->sink_connected = true; + if (uri) + { + parser->uri = malloc(wcslen(uri) * 3 + 1); + ntdll_wcstoumbs(uri, wcslen(uri) + 1, parser->uri, wcslen(uri) * 3 + 1, FALSE); + } + else + { + parser->uri = NULL; + } if (!parser->bus) { @@ -1641,6 +1652,31 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) return TRUE; } +static BOOL uridecodebin_parser_init_gst(struct wg_parser *parser) +{ + GstElement *element; + + if (!(element = create_element("uridecodebin", "base"))) + return FALSE; + + gst_bin_add(GST_BIN(parser->container), element); + parser->decodebin = element; + + g_object_set(parser->decodebin, "uri", parser->uri, NULL); + g_object_set(parser->decodebin, "max-size-bytes", G_MAXUINT, NULL); + g_signal_connect(element, "pad-added", G_CALLBACK(pad_added_cb), parser); + g_signal_connect(element, "pad-removed", G_CALLBACK(pad_removed_cb), parser); + g_signal_connect(element, "autoplug-select", G_CALLBACK(autoplug_select_cb), parser); + g_signal_connect(element, "autoplug-sort", G_CALLBACK(autoplug_sort_cb), parser); + g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads_cb), parser); + + pthread_mutex_lock(&parser->mutex); + parser->no_more_pads = false; + pthread_mutex_unlock(&parser->mutex); + + return TRUE; +} + static BOOL avi_parser_init_gst(struct wg_parser *parser) { GstElement *element; @@ -1747,6 +1783,7 @@ static NTSTATUS wg_parser_create(void *args) [WG_PARSER_AVIDEMUX] = avi_parser_init_gst, [WG_PARSER_MPEGAUDIOPARSE] = mpeg_audio_parser_init_gst, [WG_PARSER_WAVPARSE] = wave_parser_init_gst, + [WG_PARSER_URIDECODEBIN] = uridecodebin_parser_init_gst, }; struct wg_parser_create_params *params = args; @@ -1795,6 +1832,7 @@ static NTSTATUS wg_parser_destroy(void *args) pthread_cond_destroy(&parser->read_cond); pthread_cond_destroy(&parser->read_done_cond); + free(parser->uri); free(parser); return S_OK; } diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 0cd7497e985..5e86b4f2b33 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1469,7 +1469,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) goto out_destroy_parser; } - if (FAILED(hr = wg_parser_connect(reader->wg_parser, file_size))) + if (FAILED(hr = wg_parser_connect(reader->wg_parser, file_size, NULL))) { ERR("Failed to connect parser, hr %#lx.\n", hr); goto out_shutdown_thread; From 4af94d64b39c33de08f4d678af62b5e4627f674d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Feb 2022 21:31:55 +0100 Subject: [PATCH 1416/2777] HACK: winegstreamer: Check if the decoder accepted our caps. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 CW-Bug-Id: #19854 CW-Bug-Id: #20966 --- dlls/winegstreamer/wg_transform.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index e6429a04622..3b40e0183fb 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -435,6 +435,20 @@ NTSTATUS wg_transform_create(void *args) || !gst_pad_push_event(transform->my_src, event)) goto out; + /* Check that the caps event have been accepted */ + if (input_format.major_type == WG_MAJOR_TYPE_VIDEO_H264) + { + GstPad *peer; + if (!(peer = gst_pad_get_peer(transform->my_src))) + goto out; + else if (!gst_pad_has_current_caps(peer)) + { + gst_object_unref(peer); + goto out; + } + gst_object_unref(peer); + } + /* We need to use GST_FORMAT_TIME here because it's the only format * some elements such avdec_wmav2 correctly support. */ gst_segment_init(&transform->segment, GST_FORMAT_TIME); From 03f96a950ed45afd29d29cd97b8b0091461b060b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 26 Feb 2022 18:05:48 +0100 Subject: [PATCH 1417/2777] HACK: winegstreamer: Fake H264 timestamps if framerate cannot be trusted. Fixes MK11 video framerate. 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 | 18 +++++++++++++++++- dlls/winegstreamer/wg_transform.c | 9 +++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index ae78374f02e..c5600389be7 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -58,6 +58,8 @@ struct h264_decoder IMFMediaType *output_type; MFT_OUTPUT_STREAM_INFO output_info; + UINT64 last_pts; + struct wg_format wg_format; struct wg_transform *wg_transform; struct wg_sample_queue *wg_sample_queue; @@ -73,6 +75,7 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) struct wg_format input_format; struct wg_format output_format; + decoder->last_pts = 0; if (decoder->wg_transform) wg_transform_destroy(decoder->wg_transform); decoder->wg_transform = NULL; @@ -612,9 +615,10 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { struct h264_decoder *decoder = impl_from_IMFTransform(iface); + UINT64 frame_rate, duration; struct wg_format wg_format; UINT32 sample_size; - UINT64 frame_rate; + LONGLONG time; GUID subtype; HRESULT hr; @@ -638,8 +642,20 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample, sample_size, &wg_format, &samples->dwStatus))) + { wg_sample_queue_flush(decoder->wg_sample_queue, false); + if (FAILED(IMFSample_GetSampleTime(samples->pSample, &time)) + || FAILED(IMFSample_GetSampleDuration(samples->pSample, &time))) + { + frame_rate = (UINT64)decoder->wg_format.u.video.fps_n << 32 | decoder->wg_format.u.video.fps_d; + duration = (UINT64)10000000 * (UINT32)frame_rate / (frame_rate >> 32); + IMFSample_SetSampleTime(samples->pSample, decoder->last_pts); + IMFSample_SetSampleDuration(samples->pSample, duration); + decoder->last_pts += duration; + } + } + if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { decoder->wg_format = wg_format; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 3b40e0183fb..7f8f98a9a43 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -58,6 +58,7 @@ struct wg_transform GstSample *output_sample; bool output_caps_changed; GstCaps *output_caps; + bool broken_timestamps; bool setting_output_format; }; @@ -345,9 +346,10 @@ NTSTATUS wg_transform_create(void *args) */ transform->input_max_length = 16; transform->output_plane_align = 15; - if (!(element = create_element("h264parse", "base")) - || !append_element(transform->container, element, &first, &last)) + if ((element = create_element("h264parse", "base")) + && !append_element(transform->container, element, &first, &last)) goto out; + transform->broken_timestamps = !element; /* fallthrough */ case WG_MAJOR_TYPE_AUDIO_MPEG1: case WG_MAJOR_TYPE_AUDIO_MPEG4: @@ -934,6 +936,9 @@ NTSTATUS wg_transform_read_data(void *args) transform->output_sample = NULL; } + if (transform->broken_timestamps) + sample->flags &= ~(WG_SAMPLE_FLAG_HAS_PTS|WG_SAMPLE_FLAG_HAS_DURATION); + params->result = S_OK; wg_allocator_release_sample(transform->allocator, sample, discard_data); return STATUS_SUCCESS; From c82a0b6ba0018950ba6f56aa22dd9bbfe5d2277d Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 21 Oct 2020 16:03:21 -0500 Subject: [PATCH 1418/2777] HACK: winegstreamer: Allow videoconvert to parallelize. Not sure if this should be called a hack. It's not the *best* solution to the problem, but it's not a wrong one either. Signed-off-by: Zebediah Figura Wine-Staging: mfplat-streaming-support --- dlls/winegstreamer/wg_parser.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index c5ff3a1d513..721e6cbee3a 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -944,6 +944,9 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) || !append_element(parser->container, element, &first, &last)) goto out; + /* Let GStreamer choose a default number of threads. */ + gst_util_set_object_arg(G_OBJECT(element), "n-threads", "0"); + /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */ if (!(element = create_element("videoflip", "good")) || !append_element(parser->container, element, &first, &last)) From bf47b4c9d09d22947ba0355af58881b1435d5352 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 10 Aug 2022 19:11:51 +0200 Subject: [PATCH 1419/2777] HACK: winegstreamer: Use capssetter to ignore non-default YUV color spaces. --- dlls/winegstreamer/wg_parser.c | 43 ++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 721e6cbee3a..5216c6f645a 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -931,6 +931,49 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) } else if (!strcmp(name, "video/x-raw")) { + /* Hack?: Flatten down the colorimetry to default values, without + * actually modifying the video at all. + * + * We want to do color matrix conversions when converting from YUV to + * RGB or vice versa. We do *not* want to do color matrix conversions + * when converting YUV <-> YUV or RGB <-> RGB, because these are slow + * (it essentially means always using the slow path, never going through + * liborc). However, we have two videoconvert elements, and it's + * basically impossible to know what conversions each is going to do + * until caps are negotiated (without depending on some implementation + * details, and even then it'snot exactly trivial). And setting + * matrix-mode after caps are negotiated has no effect. + * + * Nor can we just retain colorimetry information the way we retain + * other caps values, because videoconvert automatically clears it if + * not doing passthrough. I think that this would only happen if we have + * to do a double conversion, but that is possible. Not likely, but I + * don't want to have to be the one to find out that there's still a + * game broken. + * + * [Note that we'd actually kind of like to retain colorimetry + * information, just in case it does ever become relevant to pass that + * on to the next DirectShow filter. Hence I think the correct solution + * for upstream is to get videoconvert to Not Do That.] + * + * So as a fallback solution, we force an identity transformation of + * the caps to those with a "default" color matrix—i.e. transform the + * caps, but not the data. We do this by *pre*pending a capssetter to + * the front of the chain, and we remove the matrix-mode setting for the + * videoconvert elements. + */ + if (!(element = create_element("capssetter", "good")) + || !append_element(parser->container, element, &first, &last)) + goto out; + gst_util_set_object_arg(G_OBJECT(element), "join", "true"); + /* Actually, this is invalid, but it causes videoconvert to use default + * colorimetry as a result. Yes, this is depending on undocumented + * implementation details. It's a hack. + * + * Sadly there doesn't seem to be a way to get capssetter to clear + * certain fields while leaving others untouched. */ + gst_util_set_object_arg(G_OBJECT(element), "caps", "video/x-raw,colorimetry=0:0:0:0"); + /* DirectShow can express interlaced video, but downstream filters can't * necessarily consume it. In particular, the video renderer can't. */ if (!(element = create_element("deinterlace", "good")) From d4e4221e8bc7303727e31fbd9be9a36474ba3dc6 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Thu, 10 Nov 2022 14:42:53 +0100 Subject: [PATCH 1420/2777] winegstreamer: Free the GStreamer buffer when freeing a WG parser stream. (cherry picked from commit 059f79be5dcf0ab55627cfd9a0a9f07bebc55790) CW-Bug-Id: #22045 --- dlls/winegstreamer/wg_parser.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 5216c6f645a..cbfc4575561 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -869,6 +869,13 @@ static void free_stream(struct wg_parser_stream *stream) gst_object_unref(stream->their_src); gst_object_unref(stream->my_sink); + if (stream->buffer) + { + gst_buffer_unmap(stream->buffer, &stream->map_info); + gst_buffer_unref(stream->buffer); + stream->buffer = NULL; + } + pthread_cond_destroy(&stream->event_cond); pthread_cond_destroy(&stream->event_empty_cond); From 4ca4f9c0a7127a1ef2f8c72d45505b26c51d3bee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 11 May 2023 21:02:30 +0200 Subject: [PATCH 1421/2777] winegstreamer: Fix the CS cleanup in wg_sample_queue_destroy (Valgrind). (cherry picked from commit 25cb216546d6bcf6cee7b1c89eafab826d89fdb5) CW-Bug-Id: #22045 --- dlls/winegstreamer/wg_sample.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wg_sample.c b/dlls/winegstreamer/wg_sample.c index 1f9eb85bcfb..1278ccf7347 100644 --- a/dlls/winegstreamer/wg_sample.c +++ b/dlls/winegstreamer/wg_sample.c @@ -293,7 +293,7 @@ void wg_sample_queue_destroy(struct wg_sample_queue *queue) wg_sample_queue_flush(queue, true); queue->cs.DebugInfo->Spare[0] = 0; - InitializeCriticalSection(&queue->cs); + DeleteCriticalSection(&queue->cs); free(queue); } From 6e305ee1f278226b0df52d785f12579826cd6323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 11 May 2023 21:02:52 +0200 Subject: [PATCH 1422/2777] winegstreamer: Free the params structure after setting the pool meta (Valgrind). (cherry picked from commit f3b9ea7aefee4f91c82091e36f01bc7fe21fe213) CW-Bug-Id: #22045 --- dlls/winegstreamer/wg_transform.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 7f8f98a9a43..f5fd96ba674 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -138,7 +138,10 @@ static gboolean transform_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery "padding-left", G_TYPE_UINT, align.padding_left, "padding-right", G_TYPE_UINT, align.padding_right, NULL))) + { gst_query_add_allocation_meta(query, GST_VIDEO_META_API_TYPE, params); + gst_structure_free(params); + } if (!(config = gst_buffer_pool_get_config(pool))) GST_ERROR("Failed to get pool %p config.", pool); From 6fa42206900ae79dd108d2bd09c3f672d14450f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 12 May 2023 09:38:47 +0200 Subject: [PATCH 1423/2777] rtworkq: Release thread pool work object when work_item is destroyed (Valgrind). (cherry picked from commit cfff3306049af5f29a168489cf8fe791b1d493d7) CW-Bug-Id: #22045 --- dlls/rtworkq/queue.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dlls/rtworkq/queue.c b/dlls/rtworkq/queue.c index d6c28ca4566..baf648bf771 100644 --- a/dlls/rtworkq/queue.c +++ b/dlls/rtworkq/queue.c @@ -131,6 +131,7 @@ struct work_item RTWQWORKITEM_KEY key; LONG priority; DWORD flags; + TP_WORK *work_object; PTP_SIMPLE_CALLBACK finalization_callback; union { @@ -374,7 +375,6 @@ static void pool_queue_submit(struct queue *queue, struct work_item *item) { TP_CALLBACK_PRIORITY callback_priority; TP_CALLBACK_ENVIRON_V3 env; - TP_WORK *work_object; if (item->priority == 0) callback_priority = TP_CALLBACK_PRIORITY_NORMAL; @@ -389,8 +389,8 @@ static void pool_queue_submit(struct queue *queue, struct work_item *item) we need finalization callback. */ if (item->finalization_callback) IUnknown_AddRef(&item->IUnknown_iface); - work_object = CreateThreadpoolWork(standard_queue_worker, item, (TP_CALLBACK_ENVIRON *)&env); - SubmitThreadpoolWork(work_object); + item->work_object = CreateThreadpoolWork(standard_queue_worker, item, (TP_CALLBACK_ENVIRON *)&env); + SubmitThreadpoolWork(item->work_object); TRACE("dispatched %p.\n", item->result); } @@ -551,6 +551,8 @@ static ULONG WINAPI work_item_Release(IUnknown *iface) if (!refcount) { + if (item->work_object) + CloseThreadpoolWork(item->work_object); if (item->reply_result) IRtwqAsyncResult_Release(item->reply_result); IRtwqAsyncResult_Release(item->result); From ad5ae4d80bc2e042809eb2451c80cb36cdcbea28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 12 May 2023 12:10:39 +0200 Subject: [PATCH 1424/2777] winegstreamer: Remove unnecessary wg_parser their_sink pad. (cherry picked from commit f595a3f904dd3f86ff07d1428bac50b3b0d5879b) CW-Bug-Id: #22045 --- dlls/winegstreamer/wg_parser.c | 40 +++++++--------------------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index cbfc4575561..b72427a3815 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -64,7 +64,7 @@ struct wg_parser GstElement *container, *decodebin; GstBus *bus; - GstPad *my_src, *their_sink; + GstPad *my_src; guint64 file_size, start_offset, next_offset, stop_offset; guint64 next_pull_offset; @@ -1598,11 +1598,8 @@ static NTSTATUS wg_parser_connect(void *args) out: if (parser->container) gst_element_set_state(parser->container, GST_STATE_NULL); - if (parser->their_sink) - { - gst_object_unref(parser->their_sink); - parser->my_src = parser->their_sink = NULL; - } + if (parser->my_src) + gst_object_unref(parser->my_src); for (i = 0; i < parser->stream_count; ++i) free_stream(parser->streams[i]); @@ -1650,8 +1647,7 @@ static NTSTATUS wg_parser_disconnect(void *args) gst_element_set_state(parser->container, GST_STATE_NULL); gst_object_unref(parser->my_src); - gst_object_unref(parser->their_sink); - parser->my_src = parser->their_sink = NULL; + parser->my_src = NULL; pthread_mutex_lock(&parser->mutex); parser->sink_connected = false; @@ -1675,7 +1671,6 @@ static NTSTATUS wg_parser_disconnect(void *args) static BOOL decodebin_parser_init_gst(struct wg_parser *parser) { GstElement *element; - int ret; if (!(element = create_element("decodebin", "base"))) return FALSE; @@ -1690,17 +1685,12 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) g_signal_connect(element, "autoplug-sort", G_CALLBACK(autoplug_sort_cb), parser); g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads_cb), parser); - parser->their_sink = gst_element_get_static_pad(element, "sink"); - pthread_mutex_lock(&parser->mutex); parser->no_more_pads = false; pthread_mutex_unlock(&parser->mutex); - if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) - { - GST_ERROR("Failed to link pads, error %d.", ret); + if (!link_src_to_element(parser->my_src, element)) return FALSE; - } return TRUE; } @@ -1733,7 +1723,6 @@ static BOOL uridecodebin_parser_init_gst(struct wg_parser *parser) static BOOL avi_parser_init_gst(struct wg_parser *parser) { GstElement *element; - int ret; if (!(element = create_element("avidemux", "good"))) return FALSE; @@ -1744,17 +1733,12 @@ static BOOL avi_parser_init_gst(struct wg_parser *parser) g_signal_connect(element, "pad-removed", G_CALLBACK(pad_removed_cb), parser); g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads_cb), parser); - parser->their_sink = gst_element_get_static_pad(element, "sink"); - pthread_mutex_lock(&parser->mutex); parser->no_more_pads = false; pthread_mutex_unlock(&parser->mutex); - if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) - { - GST_ERROR("Failed to link pads, error %d.", ret); + if (!link_src_to_element(parser->my_src, element)) return FALSE; - } return TRUE; } @@ -1770,12 +1754,8 @@ static BOOL mpeg_audio_parser_init_gst(struct wg_parser *parser) gst_bin_add(GST_BIN(parser->container), element); - parser->their_sink = gst_element_get_static_pad(element, "sink"); - if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) - { - GST_ERROR("Failed to link sink pads, error %d.", ret); + if (!link_src_to_element(parser->my_src, element)) return FALSE; - } if (!(stream = create_stream(parser, NULL))) return FALSE; @@ -1804,12 +1784,8 @@ static BOOL wave_parser_init_gst(struct wg_parser *parser) gst_bin_add(GST_BIN(parser->container), element); - parser->their_sink = gst_element_get_static_pad(element, "sink"); - if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) - { - GST_ERROR("Failed to link sink pads, error %d.", ret); + if (!link_src_to_element(parser->my_src, element)) return FALSE; - } if (!(stream = create_stream(parser, NULL))) return FALSE; From 1646893bd48df2b7f15f6e11302adba36b8c5ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 12 May 2023 14:59:38 +0200 Subject: [PATCH 1425/2777] winegstreamer: Remove unnecessary wg_parser_stream their_src pad. (cherry picked from commit ff60152ff05c6fa688078c0782efff9dddda62ca) CW-Bug-Id: #22045 --- dlls/winegstreamer/wg_parser.c | 41 ++++++++-------------------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index b72427a3815..b92114b904b 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -101,7 +101,7 @@ struct wg_parser_stream struct wg_parser *parser; uint32_t number; - GstPad *their_src, *my_sink; + GstPad *my_sink; GstElement *flip; GstSegment segment; struct wg_format preferred_format, current_format; @@ -865,8 +865,6 @@ static void free_stream(struct wg_parser_stream *stream) { unsigned int i; - if (stream->their_src) - gst_object_unref(stream->their_src); gst_object_unref(stream->my_sink); if (stream->buffer) @@ -1033,7 +1031,6 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) } gst_pad_set_active(stream->my_sink, 1); - gst_object_ref(stream->their_src = pad); out: gst_caps_unref(caps); } @@ -1041,23 +1038,10 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) static void pad_removed_cb(GstElement *element, GstPad *pad, gpointer user) { struct wg_parser *parser = user; - unsigned int i; char *name; GST_LOG("parser %p, element %p, pad %p.", parser, element, pad); - for (i = 0; i < parser->stream_count; ++i) - { - struct wg_parser_stream *stream = parser->streams[i]; - - if (stream->their_src == pad) - { - gst_object_unref(stream->their_src); - stream->their_src = NULL; - return; - } - } - name = gst_pad_get_name(pad); GST_WARNING("No pin matching pad \"%s\" found.", name); g_free(name); @@ -1391,6 +1375,7 @@ static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) static void query_tags(struct wg_parser_stream *stream) { + GstPad *peer = gst_pad_get_peer(stream->my_sink); const gchar *struct_name; GstTagList *tag_list; GstEvent *tag_event; @@ -1400,8 +1385,10 @@ static void query_tags(struct wg_parser_stream *stream) GstBuffer *buf; gsize size; - if (!(tag_event = gst_pad_get_sticky_event(stream->their_src, GST_EVENT_TAG, 0))) + if (!(tag_event = gst_pad_get_sticky_event(peer, GST_EVENT_TAG, 0))) { + gst_object_unref(peer); return; + } gst_event_parse_tag(tag_event, &tag_list); gst_tag_list_get_string(tag_list, "language-code", &stream->tags[WG_PARSER_TAG_LANGUAGE]); @@ -1433,6 +1420,7 @@ static void query_tags(struct wg_parser_stream *stream) stream->tags[WG_PARSER_TAG_NAME][size] = 0; } gst_event_unref(tag_event); + gst_object_unref(peer); } static NTSTATUS wg_parser_connect(void *args) @@ -1550,7 +1538,7 @@ static NTSTATUS wg_parser_connect(void *args) pthread_mutex_unlock(&parser->mutex); goto out; } - if (gst_pad_query_duration(stream->their_src, GST_FORMAT_TIME, &duration)) + if (gst_pad_peer_query_duration(stream->my_sink, GST_FORMAT_TIME, &duration)) { stream->duration = duration / 100; break; @@ -1747,7 +1735,6 @@ static BOOL mpeg_audio_parser_init_gst(struct wg_parser *parser) { struct wg_parser_stream *stream; GstElement *element; - int ret; if (!(element = create_element("mpegaudioparse", "good"))) return FALSE; @@ -1760,12 +1747,8 @@ static BOOL mpeg_audio_parser_init_gst(struct wg_parser *parser) if (!(stream = create_stream(parser, NULL))) return FALSE; - gst_object_ref(stream->their_src = gst_element_get_static_pad(element, "src")); - if ((ret = gst_pad_link(stream->their_src, stream->my_sink)) < 0) - { - GST_ERROR("Failed to link source pads, error %d.", ret); + if (!link_element_to_sink(element, stream->my_sink)) return FALSE; - } gst_pad_set_active(stream->my_sink, 1); parser->no_more_pads = true; @@ -1777,7 +1760,6 @@ static BOOL wave_parser_init_gst(struct wg_parser *parser) { struct wg_parser_stream *stream; GstElement *element; - int ret; if (!(element = create_element("wavparse", "good"))) return FALSE; @@ -1790,13 +1772,8 @@ static BOOL wave_parser_init_gst(struct wg_parser *parser) if (!(stream = create_stream(parser, NULL))) return FALSE; - stream->their_src = gst_element_get_static_pad(element, "src"); - gst_object_ref(stream->their_src); - if ((ret = gst_pad_link(stream->their_src, stream->my_sink)) < 0) - { - GST_ERROR("Failed to link source pads, error %d.", ret); + if (!link_element_to_sink(element, stream->my_sink)) return FALSE; - } gst_pad_set_active(stream->my_sink, 1); parser->no_more_pads = true; From 4585bf4807fdb703d248e3dfe1be7886b2d3453d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 12 May 2023 12:20:17 +0200 Subject: [PATCH 1426/2777] HACK: winegstreamer: Unlink sink pad when freeing streams. As a hack as it is should not be necessary, but, sometimes it looks like the reference leaks. CW-Bug-Id: #22045 --- dlls/winegstreamer/wg_parser.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index b92114b904b..adfacf90a04 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -863,8 +863,14 @@ static struct wg_parser_stream *create_stream(struct wg_parser *parser, gchar *i static void free_stream(struct wg_parser_stream *stream) { + GstPad *peer; unsigned int i; + if ((peer = gst_pad_get_peer(stream->my_sink))) + { + gst_pad_unlink(peer, stream->my_sink); + gst_object_unref(peer); + } gst_object_unref(stream->my_sink); if (stream->buffer) From 092ba4c7a0c212cd31883c0c7ad32dbb135e25ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 16 May 2023 12:41:04 +0200 Subject: [PATCH 1427/2777] winegstreamer: Request live latency with WINE_ENABLE_GST_LIVE_LATENCY=1. Effectively greatly reducing the memory overhead from avdec_h264, which otherwise starts one decoding thread per frame. CW-Bug-Id: #22045 --- dlls/winegstreamer/wg_parser.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index adfacf90a04..789f81a8a75 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1142,6 +1142,13 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) gst_query_add_scheduling_mode(query, GST_PAD_MODE_PULL); return TRUE; + case GST_QUERY_LATENCY: + { + const char *live = getenv("WINE_ENABLE_GST_LIVE_LATENCY"); + gst_query_set_latency(query, live && !strcmp(live, "1"), 0, 0); + return TRUE; + } + default: GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query)); return FALSE; From 6220bdde2a29a69ac89661eabc501e932d68f38e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 16 May 2023 12:53:46 +0200 Subject: [PATCH 1428/2777] HACK: ntdll: Set WINE_ENABLE_GST_LIVE_LATENCY=1 for a few appids. CW-Bug-Id: #22045 --- dlls/ntdll/unix/loader.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 0cdab9e6b91..c30e62222c8 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2383,6 +2383,12 @@ static void hacks_init(void) ERR("HACK: setting LIBGL_ALWAYS_SOFTWARE.\n"); setenv("LIBGL_ALWAYS_SOFTWARE", "1", 0); } + + if (sgi && (!strcmp(sgi, "1364780") || !strcmp(sgi, "1952120") || !strcmp(sgi, "2154900"))) + { + ERR("HACK: setting WINE_ENABLE_GST_LIVE_LATENCY.\n"); + setenv("WINE_ENABLE_GST_LIVE_LATENCY", "1", 0); + } } #ifdef _WIN64 From e5e6c482b2b9f0622b8eb01c15e3d0edae8d0869 Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Thu, 1 Jun 2023 10:58:51 -0400 Subject: [PATCH 1429/2777] Revert "uiautomationcore: Use SendMessageCallback in node_from_lresult() to prevent a deadlock." This reverts commit c8a6810692123705783e1d2aa2c36d103e29467d. --- dlls/uiautomationcore/tests/uiautomation.c | 30 ------------------ dlls/uiautomationcore/uia_provider.c | 36 +--------------------- 2 files changed, 1 insertion(+), 65 deletions(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 134c5c7b005..ff05e3d79eb 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -5804,14 +5804,6 @@ static const struct prov_method_sequence node_from_hwnd9[] = { { 0 } }; -static const struct prov_method_sequence node_from_hwnd10[] = { - NODE_CREATE_SEQ(&Provider), - /* Next two only done on Windows 8+. */ - { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, - { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, - { &Provider, PROV_GET_PROVIDER_OPTIONS }, - { 0 } -}; static const struct prov_method_sequence disconnect_prov1[] = { { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, /* Win10v1507 and below call this. */ @@ -6093,28 +6085,6 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param) Sleep(50); ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref); - /* ProviderOptions_UseComThreading test from a separate thread. */ - SET_EXPECT(winproc_GETOBJECT_UiaRoot); - /* Only sent on Win7. */ - SET_EXPECT(winproc_GETOBJECT_CLIENT); - prov_root = &Provider.IRawElementProviderSimple_iface; - initialize_provider(&Provider, ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading, NULL, FALSE); - Provider.frag_root = NULL; - Provider.runtime_id[0] = Provider.runtime_id[1] = 0xdeadbeef; - hr = UiaNodeFromHandle(hwnd, &node); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); - CHECK_CALLED(winproc_GETOBJECT_UiaRoot); - called_winproc_GETOBJECT_CLIENT = expect_winproc_GETOBJECT_CLIENT = 0; - - ok_method_sequence(node_from_hwnd10, "node_from_hwnd10"); - - ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); - /* Win10v1809 can be slow to call Release on Provider. */ - if (Provider.ref != 1) - Sleep(50); - ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref); - if (!pUiaDisconnectProvider) { win_skip("UiaDisconnectProvider not exported by uiautomationcore.dll\n"); diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index a89ab965846..f9977d615e5 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -2312,19 +2312,6 @@ void uia_stop_provider_thread(void) LeaveCriticalSection(&provider_thread_cs); } -struct uia_lresult_from_node_data { - LRESULT lr; - BOOL returned; -}; - -static void CALLBACK uia_lresult_from_node_callback(HWND hwnd, UINT msg, ULONG_PTR data, LRESULT lresult) -{ - struct uia_lresult_from_node_data *cb_data = (struct uia_lresult_from_node_data *)data; - - cb_data->lr = lresult; - cb_data->returned = TRUE; -} - /* * Pass our IWineUiaNode interface to the provider thread for marshaling. UI * Automation has to work regardless of whether or not COM is initialized on @@ -2332,34 +2319,13 @@ static void CALLBACK uia_lresult_from_node_callback(HWND hwnd, UINT msg, ULONG_P */ LRESULT uia_lresult_from_node(HUIANODE huianode) { - struct uia_lresult_from_node_data cb_data = { 0 }; - if (!uia_start_provider_thread()) { UiaNodeRelease(huianode); return 0; } - if (!SendMessageCallbackW(provider_thread.hwnd, WM_GET_OBJECT_UIA_NODE, 0, (LPARAM)huianode, - uia_lresult_from_node_callback, (ULONG_PTR)&cb_data)) - { - WARN("SendMessageCallback failed, error %ld\n", GetLastError()); - UiaNodeRelease(huianode); - return 0; - } - - while (!cb_data.returned) - { - MSG msg; - - if (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - } - - return cb_data.lr; + return SendMessageW(provider_thread.hwnd, WM_GET_OBJECT_UIA_NODE, 0, (LPARAM)huianode); } /*********************************************************************** From cf2c881ff6ba43d512c27e282fd8013238683bca Mon Sep 17 00:00:00 2001 From: Connor McAdams Date: Thu, 16 Feb 2023 13:21:20 -0500 Subject: [PATCH 1430/2777] uiautomationcore: Retrieve runtime ID on UiaReturnRawElementProvider thread to prevent a deadlock. If we pass a node to the provider thread that contains a provider that was created in an STA with the ProviderOptions_UseComThreading flag set, we can deadlock when attempting to get a runtime ID from the proxy due to the message queue not being pumped. To avoid this, retrieve the runtime ID before passing the node to the provider thread. Signed-off-by: Connor McAdams (cherry picked from commit b04acc81d0ae7b354b37025ddb98a3394d5a54d7) CW-Bug-Id: #22312 --- dlls/uiautomationcore/tests/uiautomation.c | 32 +++++++++++ dlls/uiautomationcore/uia_provider.c | 64 ++++++++++++---------- 2 files changed, 66 insertions(+), 30 deletions(-) diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index ff05e3d79eb..3c62face6e0 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -5804,6 +5804,16 @@ static const struct prov_method_sequence node_from_hwnd9[] = { { 0 } }; +static const struct prov_method_sequence node_from_hwnd10[] = { + NODE_CREATE_SEQ(&Provider), + /* Next two only done on Windows 8+. */ + { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, + { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win11+. */ + { 0 } +}; + static const struct prov_method_sequence disconnect_prov1[] = { { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, /* Win10v1507 and below call this. */ @@ -6085,6 +6095,28 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param) Sleep(50); ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref); + /* ProviderOptions_UseComThreading test from a separate thread. */ + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + /* Only sent on Win7. */ + SET_EXPECT(winproc_GETOBJECT_CLIENT); + prov_root = &Provider.IRawElementProviderSimple_iface; + initialize_provider(&Provider, ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading, NULL, FALSE); + Provider.frag_root = NULL; + Provider.runtime_id[0] = Provider.runtime_id[1] = 0xdeadbeef; + hr = UiaNodeFromHandle(hwnd, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + called_winproc_GETOBJECT_CLIENT = expect_winproc_GETOBJECT_CLIENT = 0; + + ok_method_sequence(node_from_hwnd10, "node_from_hwnd10"); + + ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); + /* Win10v1809 can be slow to call Release on Provider. */ + if (Provider.ref != 1) + Sleep(50); + ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref); + if (!pUiaDisconnectProvider) { win_skip("UiaDisconnectProvider not exported by uiautomationcore.dll\n"); diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index f9977d615e5..b90db7f1719 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -2115,19 +2115,15 @@ static void uia_provider_thread_disconnect_node(SAFEARRAY *sa) LeaveCriticalSection(&provider_thread_cs); } -static HRESULT uia_provider_thread_add_node(HUIANODE node) +static HRESULT uia_provider_thread_add_node(HUIANODE node, SAFEARRAY *rt_id) { struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)node); int prov_type = get_node_provider_type_at_idx(node_data, 0); struct uia_provider *prov_data; - SAFEARRAY *sa; - HRESULT hr; + HRESULT hr = S_OK; prov_data = impl_from_IWineUiaProvider(node_data->prov[prov_type]); node_data->nested_node = prov_data->return_nested_node = TRUE; - hr = UiaGetRuntimeId(node, &sa); - if (FAILED(hr)) - return hr; TRACE("Adding node %p\n", node); @@ -2135,38 +2131,40 @@ static HRESULT uia_provider_thread_add_node(HUIANODE node) list_add_tail(&provider_thread.nodes_list, &node_data->prov_thread_list_entry); /* If we have a runtime ID, create an entry in the rb tree. */ - if (sa) + if (rt_id) { struct uia_provider_thread_map_entry *prov_map; struct rb_entry *rb_entry; - if ((rb_entry = rb_get(&provider_thread.node_map, sa))) - { + if ((rb_entry = rb_get(&provider_thread.node_map, rt_id))) prov_map = RB_ENTRY_VALUE(rb_entry, struct uia_provider_thread_map_entry, entry); - SafeArrayDestroy(sa); - } else { prov_map = heap_alloc_zero(sizeof(*prov_map)); if (!prov_map) { - SafeArrayDestroy(sa); - LeaveCriticalSection(&provider_thread_cs); - return E_OUTOFMEMORY; + hr = E_OUTOFMEMORY; + goto exit; } - prov_map->runtime_id = sa; + hr = SafeArrayCopy(rt_id, &prov_map->runtime_id); + if (FAILED(hr)) + { + heap_free(prov_map); + goto exit; + } list_init(&prov_map->nodes_list); - rb_put(&provider_thread.node_map, sa, &prov_map->entry); + rb_put(&provider_thread.node_map, prov_map->runtime_id, &prov_map->entry); } list_add_tail(&prov_map->nodes_list, &node_data->node_map_list_entry); node_data->map = prov_map; } +exit: LeaveCriticalSection(&provider_thread_cs); - return S_OK; + return hr; } #define WM_GET_OBJECT_UIA_NODE (WM_USER + 1) @@ -2178,13 +2176,13 @@ static LRESULT CALLBACK uia_provider_thread_msg_proc(HWND hwnd, UINT msg, WPARAM { case WM_GET_OBJECT_UIA_NODE: { + SAFEARRAY *rt_id = (SAFEARRAY *)wparam; HUIANODE node = (HUIANODE)lparam; LRESULT lr; - if (FAILED(uia_provider_thread_add_node(node))) + if (FAILED(uia_provider_thread_add_node(node, rt_id))) { WARN("Failed to add node %p to provider thread list.\n", node); - UiaNodeRelease(node); return 0; } @@ -2199,11 +2197,6 @@ static LRESULT CALLBACK uia_provider_thread_msg_proc(HWND hwnd, UINT msg, WPARAM lr = 0; } - /* - * LresultFromObject increases refcnt by 1. If LresultFromObject - * failed, this is expected to release the node. - */ - UiaNodeRelease(node); return lr; } @@ -2319,13 +2312,24 @@ void uia_stop_provider_thread(void) */ LRESULT uia_lresult_from_node(HUIANODE huianode) { - if (!uia_start_provider_thread()) - { - UiaNodeRelease(huianode); - return 0; - } + SAFEARRAY *rt_id; + LRESULT lr = 0; + HRESULT hr; + + hr = UiaGetRuntimeId(huianode, &rt_id); + if (SUCCEEDED(hr) && uia_start_provider_thread()) + lr = SendMessageW(provider_thread.hwnd, WM_GET_OBJECT_UIA_NODE, (WPARAM)rt_id, (LPARAM)huianode); + + if (FAILED(hr)) + WARN("UiaGetRuntimeId failed with hr %#lx\n", hr); - return SendMessageW(provider_thread.hwnd, WM_GET_OBJECT_UIA_NODE, 0, (LPARAM)huianode); + /* + * LresultFromObject increases refcnt by 1. If LresultFromObject + * failed or wasn't called, this is expected to release the node. + */ + UiaNodeRelease(huianode); + SafeArrayDestroy(rt_id); + return lr; } /*********************************************************************** From ead92af7c58912d74cf3314009d1a44dd431899e Mon Sep 17 00:00:00 2001 From: Evan Tang Date: Wed, 18 Jan 2023 16:14:19 -0600 Subject: [PATCH 1431/2777] mshtml: Implement IHTMLRect2 for HTMLRect. (cherry picked from commit 8b0868c1760121c8ae5cf5466d16e4d5f7faba3e) CW-Bug-ID: 20738 --- dlls/mshtml/htmlelem.c | 110 +++++++++++++++++++++++++++++- dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/tests/documentmode.js | 17 +++++ dlls/mshtml/tests/dom.js | 2 + include/mshtmdid.h | 4 ++ include/mshtml.idl | 18 +++++ 6 files changed, 151 insertions(+), 1 deletion(-) diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index cee37d4ce02..42660eb5165 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -575,6 +575,7 @@ static DISPID get_dispid_for_nsattr(HTMLElement *elem, nsIDOMAttr *nsattr) typedef struct { DispatchEx dispex; IHTMLRect IHTMLRect_iface; + IHTMLRect2 IHTMLRect2_iface; LONG ref; @@ -596,6 +597,8 @@ static HRESULT WINAPI HTMLRect_QueryInterface(IHTMLRect *iface, REFIID riid, voi *ppv = &This->IHTMLRect_iface; }else if(IsEqualGUID(&IID_IHTMLRect, riid)) { *ppv = &This->IHTMLRect_iface; + }else if (IsEqualGUID(&IID_IHTMLRect2, riid)) { + *ppv = &This->IHTMLRect2_iface; }else if(dispex_query_interface(&This->dispex, riid, ppv)) { return *ppv ? S_OK : E_NOINTERFACE; }else { @@ -769,6 +772,91 @@ static HRESULT WINAPI HTMLRect_get_bottom(IHTMLRect *iface, LONG *p) return S_OK; } +static inline HTMLRect *impl_from_IHTMLRect2(IHTMLRect2 *iface) +{ + return CONTAINING_RECORD(iface, HTMLRect, IHTMLRect2_iface); +} + +static HRESULT WINAPI HTMLRect2_QueryInterface(IHTMLRect2 *iface, REFIID riid, void **ppv) +{ + HTMLRect *This = impl_from_IHTMLRect2(iface); + return IHTMLRect_QueryInterface(&This->IHTMLRect_iface, riid, ppv); +} + +static ULONG WINAPI HTMLRect2_AddRef(IHTMLRect2 *iface) +{ + HTMLRect *This = impl_from_IHTMLRect2(iface); + return IHTMLRect_AddRef(&This->IHTMLRect_iface); +} + +static ULONG WINAPI HTMLRect2_Release(IHTMLRect2 *iface) +{ + HTMLRect *This = impl_from_IHTMLRect2(iface); + return IHTMLRect_Release(&This->IHTMLRect_iface); +} + +static HRESULT WINAPI HTMLRect2_GetTypeInfoCount(IHTMLRect2 *iface, UINT *pctinfo) +{ + HTMLRect *This = impl_from_IHTMLRect2(iface); + return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI HTMLRect2_GetTypeInfo(IHTMLRect2 *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLRect *This = impl_from_IHTMLRect2(iface); + return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI HTMLRect2_GetIDsOfNames(IHTMLRect2 *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + HTMLRect *This = impl_from_IHTMLRect2(iface); + return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI HTMLRect2_Invoke(IHTMLRect2 *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLRect *This = impl_from_IHTMLRect2(iface); + return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI HTMLRect2_get_width(IHTMLRect2 *iface, FLOAT *p) +{ + HTMLRect *This = impl_from_IHTMLRect2(iface); + nsresult nsres; + + TRACE("(%p)->(%p)\n", This, p); + + nsres = nsIDOMClientRect_GetWidth(This->nsrect, p); + if (NS_FAILED(nsres)) { + ERR("GetWidth failed: %08lx\n", nsres); + return E_FAIL; + } + + return S_OK; +} + +static HRESULT WINAPI HTMLRect2_get_height(IHTMLRect2 *iface, FLOAT *p) +{ + HTMLRect *This = impl_from_IHTMLRect2(iface); + nsresult nsres; + + TRACE("(%p)->(%p)\n", This, p); + + nsres = nsIDOMClientRect_GetHeight(This->nsrect, p); + if (NS_FAILED(nsres)) { + ERR("GetHeight failed: %08lx\n", nsres); + return E_FAIL; + } + + return S_OK; +} + static const IHTMLRectVtbl HTMLRectVtbl = { HTMLRect_QueryInterface, HTMLRect_AddRef, @@ -787,6 +875,24 @@ static const IHTMLRectVtbl HTMLRectVtbl = { HTMLRect_get_bottom }; +static const IHTMLRect2Vtbl HTMLRect2Vtbl = { + HTMLRect2_QueryInterface, + HTMLRect2_AddRef, + HTMLRect2_Release, + HTMLRect2_GetTypeInfoCount, + HTMLRect2_GetTypeInfo, + HTMLRect2_GetIDsOfNames, + HTMLRect2_Invoke, + HTMLRect2_get_width, + HTMLRect2_get_height, +}; + +void HTMLRect_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + if (mode >= COMPAT_MODE_IE9) + dispex_info_add_interface(info, IHTMLRect2_tid, NULL); +} + static const tid_t HTMLRect_iface_tids[] = { IHTMLRect_tid, 0 @@ -796,7 +902,8 @@ dispex_static_data_t HTMLRect_dispex = { NULL, PROTO_ID_HTMLRect, IHTMLRect_tid, - HTMLRect_iface_tids + HTMLRect_iface_tids, + HTMLRect_init_dispex_info }; static HRESULT create_html_rect(nsIDOMClientRect *nsrect, HTMLInnerWindow *window, compat_mode_t compat_mode, @@ -809,6 +916,7 @@ static HRESULT create_html_rect(nsIDOMClientRect *nsrect, HTMLInnerWindow *windo return E_OUTOFMEMORY; rect->IHTMLRect_iface.lpVtbl = &HTMLRectVtbl; + rect->IHTMLRect2_iface.lpVtbl = &HTMLRect2Vtbl; rect->ref = 1; init_dispatch(&rect->dispex, (IUnknown*)&rect->IHTMLRect_iface, &HTMLRect_dispex, window, compat_mode); diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 4984353eaf3..441ba6d836e 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -336,6 +336,7 @@ typedef struct ScriptHost ScriptHost; XIID(IHTMLPerformanceTiming) \ XIID(IHTMLPluginsCollection) \ XIID(IHTMLRect) \ + XIID(IHTMLRect2) \ XIID(IHTMLRectCollection) \ XIID(IHTMLScreen) \ XIID(IHTMLScriptElement) \ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 51149b63213..881e340aaee 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -1807,6 +1807,23 @@ sync_test("stylesheet_props", function() { test_exposed("rules", true); }); +sync_test("rect_props", function() { + document.body.innerHTML = '
test
'; + var elem = document.body.firstChild; + var rect = elem.getBoundingClientRect(); + function test_exposed(prop, expect) { + if(expect) + ok(prop in rect, prop + " not found in rect object."); + else + ok(!(prop in rect), prop + " found in rect object."); + } + + var v = document.documentMode; + + test_exposed("width", v >= 9); + test_exposed("height", v >= 9); +}); + sync_test("xhr open", function() { var e = false; try { diff --git a/dlls/mshtml/tests/dom.js b/dlls/mshtml/tests/dom.js index b3d30d44025..2cce40f2588 100644 --- a/dlls/mshtml/tests/dom.js +++ b/dlls/mshtml/tests/dom.js @@ -302,6 +302,8 @@ sync_test("rects", function() { ok(rects.length === 1, "rect.length = " + rects.length); ok(rects[0].top === rect.top, "rects[0].top = " + rects[0].top + " rect.top = " + rect.top); ok(rects[0].bottom === rect.bottom, "rects[0].bottom = " + rects[0].bottom + " rect.bottom = " + rect.bottom); + ok(rect.height === rect.bottom - rect.top, "rect.height = " + rect.height + " rect.bottom = " + rect.bottom + " rect.top = " + rect.top); + ok(rect.width === rect.right - rect.left, "rect.width = " + rect.width + " rect.right = " + rect.right + " rect.left = " + rect.left); elem = document.createElement("style"); rects = elem.getClientRects(); diff --git a/include/mshtmdid.h b/include/mshtmdid.h index 5aca030bd10..a28d706903f 100644 --- a/include/mshtmdid.h +++ b/include/mshtmdid.h @@ -4146,6 +4146,10 @@ #define DISPID_IHTMLRECT_RIGHT DISPID_OMRECT+3 #define DISPID_IHTMLRECT_BOTTOM DISPID_OMRECT+4 +/* IHTMLRect2 */ +#define DISPID_IHTMLRECT2_WIDTH DISPID_OMRECT+5 +#define DISPID_IHTMLRECT2_HEIGHT DISPID_OMRECT+6 + /* IHTMLRectCollection */ #define DISPID_IHTMLRECTCOLLECTION_LENGTH DISPID_COLLECTION #define DISPID_IHTMLRECTCOLLECTION__NEWENUM DISPID_NEWENUM diff --git a/include/mshtml.idl b/include/mshtml.idl index 0f9a55a4a44..7fb245f5d5c 100644 --- a/include/mshtml.idl +++ b/include/mshtml.idl @@ -7937,6 +7937,24 @@ interface IHTMLRect : IDispatch HRESULT bottom([retval, out] LONG *p); } +/***************************************************************************** + * IHTMLRect2 interface + */ +[ + odl, + oleautomation, + dual, + uuid(3051076c-98b5-11cf-bb82-00aa00bdce0b) +] +interface IHTMLRect2 : IDispatch +{ + [propget, id(DISPID_IHTMLRECT2_WIDTH)] + HRESULT width([retval, out] FLOAT *p); + + [propget, id(DISPID_IHTMLRECT2_HEIGHT)] + HRESULT height([retval, out] FLOAT *p); +} + /***************************************************************************** * IHTMLRectCollection interface */ From 29f7b49d42d1db82ec6b09468da78ff427308cdc Mon Sep 17 00:00:00 2001 From: Timo Gurr Date: Fri, 17 Feb 2023 14:29:25 +0100 Subject: [PATCH 1432/2777] wine.inf: HACK: Disable SpeechSynthesisWrapper.dll for Pentiment. The game crashes when utilizing it and works without it, like seen already on the Steam Deck with its specific depot. https://steamdb.info/depot/1205522/ https://github.com/ValveSoftware/Proton/issues/6415#issuecomment-1379357568 Link: https://github.com/ValveSoftware/Proton/pull/6479 Link: https://github.com/ValveSoftware/wine/pull/176 --- loader/wine.inf.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index d99383d6296..7e21f7b0fad 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2873,3 +2873,5 @@ HKCU,Software\Wine\AppDefaults\DarkSoulsIII.exe\X11 Driver,"LimitNumberOfResolut HKCU,Software\Wine\AppDefaults\sekiro.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"32" HKCU,Software\Wine\AppDefaults\NieRAutomata.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"32" HKCU,Software\Wine\AppDefaults\SpellForce.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"16" +;;Other app-specific overrides +HKCU,Software\Wine\AppDefaults\Pentiment.exe\DllOverrides,"SpeechSynthesisWrapper",,"disabled" From fe9eeceeff91c81ee4867525418124a509d4f3d3 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Thu, 5 Jan 2023 08:57:27 +0000 Subject: [PATCH 1433/2777] winevulkan: Enable VK_EXT_hdr_metadata This works fine with the new struct conversions, and is needed for HDR with native Vulkan games such as Doom Eternal and games using HDR with DXVK and VKD3D-Proton. Link: https://github.com/ValveSoftware/wine/pull/174 --- dlls/winevulkan/make_vulkan | 1 - 1 file changed, 1 deletion(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index c2eb72f374a..9ac1f5875f2 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -97,7 +97,6 @@ UNSUPPORTED_EXTENSIONS = [ # Device extensions "VK_AMD_display_native_hdr", "VK_EXT_full_screen_exclusive", - "VK_EXT_hdr_metadata", # Needs WSI work. "VK_GOOGLE_display_timing", "VK_KHR_external_fence_win32", # Relates to external_semaphore and needs type conversions in bitflags. From 78652a777b68cb847f13cc17fe9fb037949e5cec Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Wed, 22 Mar 2023 15:41:00 +0800 Subject: [PATCH 1434/2777] kernelbase: HACK: Force desktop GL for PaladinLias. CW-Bug-Id: #20816 --- dlls/kernelbase/process.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 7e7ea051398..69230d244f2 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -591,6 +591,7 @@ static const WCHAR *hack_append_command_line( const WCHAR *cmd ) {L"nw.exe.exe", L" --use-angle=d3d9"}, {L"DC Universe Online\\LaunchPad.exe", L" --use-gl=swiftshader"}, {L"PlanetSide 2\\LaunchPad.exe", L" --use-gl=swiftshader"}, + {L"PaladinLias\\Game.exe", L" --use-gl=desktop"}, }; unsigned int i; From ce1cef1d41900e08246c433a7f825f3bb813432c Mon Sep 17 00:00:00 2001 From: Bitwolf <65789901+Bitwolfies@users.noreply.github.com> Date: Thu, 23 Feb 2023 13:05:59 -0800 Subject: [PATCH 1435/2777] wine.inf: Use included d3d8.dll with Bloodrayne Terminal Cut 1/2. Proton defaults to use the built-in DirectX 8 implementation but the game ships with it's own d3d8.dll which uses DirectX 9 internally. This helps with massive slowdowns and a few other misc bugs. LinK: https://github.com/ValveSoftware/wine/pull/179 --- loader/wine.inf.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 7e21f7b0fad..c61e81ac645 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2875,3 +2875,5 @@ HKCU,Software\Wine\AppDefaults\NieRAutomata.exe\X11 Driver,"LimitNumberOfResolut HKCU,Software\Wine\AppDefaults\SpellForce.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"16" ;;Other app-specific overrides HKCU,Software\Wine\AppDefaults\Pentiment.exe\DllOverrides,"SpeechSynthesisWrapper",,"disabled" +HKCU,Software\Wine\AppDefaults\rayne1.exe\DllOverrides,"d3d8",,"native" +HKCU,Software\Wine\AppDefaults\rayne2.exe\DllOverrides,"d3d8",,"native" From b140155c457410afb24a1c054df3ed1836cd2568 Mon Sep 17 00:00:00 2001 From: Adrian Thiele Date: Wed, 1 Mar 2023 16:54:15 +0100 Subject: [PATCH 1436/2777] mfreadwrite/tests: Check refcount of device manager after release. (cherry picked from commit eeb25932c7544497b93b3096e79944a9732eeb97) --- dlls/mfreadwrite/tests/mfplat.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 14e92cceab2..e27fad456ce 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -1251,6 +1251,7 @@ static void test_reader_d3d9(void) HWND window; HRESULT hr; UINT token; + ULONG refcount; window = create_window(); d3d9 = Direct3DCreate9(D3D_SDK_VERSION); @@ -1283,7 +1284,9 @@ static void test_reader_d3d9(void) IMFSourceReader_Release(reader); - IDirect3DDeviceManager9_Release(d3d9_manager); + refcount = IDirect3DDeviceManager9_Release(d3d9_manager); + todo_wine ok(!refcount, "Unexpected refcount %lu.\n", refcount); + IDirect3DDevice9_Release(d3d9_device); done: From 386617980801a21e06543bdb646a545fab3c4b80 Mon Sep 17 00:00:00 2001 From: Adrian Thiele Date: Wed, 1 Mar 2023 16:59:50 +0100 Subject: [PATCH 1437/2777] mfreadwrite/reader: Release device manager in source_reader_release. (cherry picked from commit 0d4f63b34cd6f2f8c544714d67d31d93092d210f) --- dlls/mfreadwrite/reader.c | 2 ++ dlls/mfreadwrite/tests/mfplat.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 1384616da64..ecf20cba207 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -211,6 +211,8 @@ static ULONG source_reader_release(struct source_reader *reader) if (!refcount) { + if (reader->device_manager) + IUnknown_Release(reader->device_manager); if (reader->async_callback) IMFSourceReaderCallback_Release(reader->async_callback); if (reader->descriptor) diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index e27fad456ce..0999a8b253f 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -1285,7 +1285,7 @@ static void test_reader_d3d9(void) IMFSourceReader_Release(reader); refcount = IDirect3DDeviceManager9_Release(d3d9_manager); - todo_wine ok(!refcount, "Unexpected refcount %lu.\n", refcount); + ok(!refcount, "Unexpected refcount %lu.\n", refcount); IDirect3DDevice9_Release(d3d9_device); From 83a6404e6a0456e1a90ae5280ff9c5245426e9c2 Mon Sep 17 00:00:00 2001 From: Torge Matthies Date: Wed, 12 Apr 2023 13:35:10 +0200 Subject: [PATCH 1438/2777] ntdll/tests: Add test for file attributes of files with names beginning with a dot. CW-Bug-Id: #22217 --- dlls/ntdll/tests/file.c | 92 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 60916bc777b..891786b8c43 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -4094,6 +4094,97 @@ static void test_file_attribute_tag_information(void) CloseHandle( h ); } +static void rename_file( HANDLE h, const WCHAR *filename ) +{ + FILE_RENAME_INFORMATION *fri; + UNICODE_STRING ntpath; + IO_STATUS_BLOCK io; + NTSTATUS status; + BOOLEAN ret; + ULONG size; + + ret = pRtlDosPathNameToNtPathName_U( filename, &ntpath, NULL, NULL ); + ok( ret, "RtlDosPathNameToNtPathName_U failed\n" ); + + size = offsetof( FILE_RENAME_INFORMATION, FileName ) + ntpath.Length; + fri = HeapAlloc( GetProcessHeap(), 0, size ); + ok( fri != NULL, "HeapAlloc failed\n" ); + fri->ReplaceIfExists = TRUE; + fri->RootDirectory = NULL; + fri->FileNameLength = ntpath.Length; + memcpy( fri->FileName, ntpath.Buffer, ntpath.Length ); + pRtlFreeUnicodeString( &ntpath ); + + status = pNtSetInformationFile( h, &io, fri, size, FileRenameInformation ); + HeapFree( GetProcessHeap(), 0, fri ); + ok( status == STATUS_SUCCESS, "got %#lx\n", status ); +} + +static void test_dotfile_file_attributes(void) +{ + char temppath[MAX_PATH], filename[MAX_PATH]; + WCHAR temppathW[MAX_PATH], filenameW[MAX_PATH]; + FILE_BASIC_INFORMATION info = {}; + IO_STATUS_BLOCK io; + NTSTATUS status; + DWORD attrs; + HANDLE h; + + GetTempPathA( MAX_PATH, temppath ); + GetTempFileNameA( temppath, ".foo", 0, filename ); + h = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0 ); + ok( h != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); + + status = nt_get_file_attrs(filename, &attrs); + ok( status == STATUS_SUCCESS, "got %#lx\n", status ); + todo_wine ok( !(attrs & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", attrs ); + + status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); + ok( status == STATUS_SUCCESS, "got %#lx\n", status ); + ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes ); + + info.FileAttributes = FILE_ATTRIBUTE_SYSTEM; + status = pNtSetInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); + ok( status == STATUS_SUCCESS, "got %#lx\n", status ); + + status = nt_get_file_attrs(filename, &attrs); + ok( status == STATUS_SUCCESS, "got %#lx\n", status ); + ok( attrs & FILE_ATTRIBUTE_SYSTEM, "got attributes %#lx\n", attrs ); + todo_wine ok( !(attrs & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", attrs ); + + status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); + ok( status == STATUS_SUCCESS, "got %#lx\n", status ); + ok( info.FileAttributes & FILE_ATTRIBUTE_SYSTEM, "got attributes %#lx\n", info.FileAttributes ); + ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes ); + + CloseHandle( h ); + + GetTempPathW( MAX_PATH, temppathW ); + GetTempFileNameW( temppathW, L"foo", 0, filenameW ); + h = CreateFileW( filenameW, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0 ); + ok( h != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); + + GetTempFileNameW( temppathW, L".foo", 0, filenameW ); + winetest_push_context("foo -> .foo"); + rename_file( h, filenameW ); + winetest_pop_context(); + + status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); + ok( status == STATUS_SUCCESS, "got %#lx\n", status ); + ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes ); + + GetTempFileNameW( temppathW, L"foo", 0, filenameW ); + winetest_push_context(".foo -> foo"); + rename_file( h, filenameW ); + winetest_pop_context(); + + status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); + ok( status == STATUS_SUCCESS, "got %#lx\n", status ); + ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes ); + + CloseHandle( h ); +} + static void test_file_mode(void) { UNICODE_STRING file_name, pipe_dev_name, mountmgr_dev_name, mailslot_dev_name; @@ -5620,6 +5711,7 @@ START_TEST(file) test_file_id_information(); test_file_access_information(); test_file_attribute_tag_information(); + test_dotfile_file_attributes(); test_file_mode(); test_file_readonly_access(); test_query_volume_information_file(); From ca072fa61e06290579b9e9bfada37f3b24c3f41b Mon Sep 17 00:00:00 2001 From: Torge Matthies Date: Wed, 12 Apr 2023 13:35:10 +0200 Subject: [PATCH 1439/2777] ntdll: Handle hidden file names inside get_file_info instead of after it. Signed-off-by: Torge Matthies CW-Bug-Id: #22217 --- dlls/ntdll/unix/file.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 9de7e536304..26ad99e7a55 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1292,18 +1292,30 @@ static BOOLEAN get_dir_case_sensitivity( const char *dir ) /*********************************************************************** * is_hidden_file * - * Check if the specified file should be hidden based on its name and the show dot files option. + * Check if the specified file should be hidden based on its unix path and the show dot files option. */ -static BOOL is_hidden_file( const UNICODE_STRING *name ) +static BOOL is_hidden_file( const char *name ) { - WCHAR *p, *end; + const char *p, *end; if (show_dot_files) return FALSE; - end = p = name->Buffer + name->Length/sizeof(WCHAR); - while (p > name->Buffer && p[-1] == '\\') p--; - while (p > name->Buffer && p[-1] != '\\') p--; - return (p < end && *p == '.'); + end = p = name + strlen( name ); + while (p > name && p[-1] == '/') p--; + while (p > name && p[-1] != '/') p--; + if (p >= end || *p != '.') + return FALSE; + /* . and .. must not be hidden */ + p++; + if (p >= end || *p == '/') + return FALSE; + else if (*p == '.') + { + p++; + if (p >= end || *p == '/') + return FALSE; + } + return TRUE; } @@ -1700,6 +1712,9 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) } *attr |= get_file_attributes( st ); + if (is_hidden_file( path )) + *attr |= FILE_ATTRIBUTE_HIDDEN; + attr_len = xattr_get( path, SAMBA_XATTR_DOS_ATTRIB, attr_data, sizeof(attr_data)-1 ); if (attr_len != -1) *attr |= parse_samba_dos_attrib_data( attr_data, attr_len ); @@ -2275,11 +2290,6 @@ static NTSTATUS get_dir_data_entry( struct dir_data *dir_data, void *info_ptr, I if (class != FileNamesInformation) { if (st.st_dev != dir_data->id.dev) st.st_ino = 0; /* ignore inode if on a different device */ - - if (!show_dot_files && names->long_name[0] == '.' && names->long_name[1] && - (names->long_name[1] != '.' || names->long_name[2])) - attributes |= FILE_ATTRIBUTE_HIDDEN; - fill_file_info( &st, attributes, info, class ); } @@ -4384,7 +4394,6 @@ NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr, info->AllocationSize = std.AllocationSize; info->EndOfFile = std.EndOfFile; info->FileAttributes = basic.FileAttributes; - if (is_hidden_file( attr->ObjectName )) info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; } free( unix_name ); } @@ -4415,10 +4424,7 @@ NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) status = STATUS_INVALID_INFO_CLASS; else - { status = fill_file_info( &st, attributes, info, FileBasicInformation ); - if (is_hidden_file( attr->ObjectName )) info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; - } free( unix_name ); } else WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), status ); From 78308bfa3293348fc4d0cf92535f268ca9a9dc32 Mon Sep 17 00:00:00 2001 From: Torge Matthies Date: Wed, 12 Apr 2023 13:35:10 +0200 Subject: [PATCH 1440/2777] ntdll: Only infer hidden attribute from file name if xattr is not present. Signed-off-by: Torge Matthies CW-Bug-Id: #22217 --- dlls/ntdll/tests/file.c | 2 +- dlls/ntdll/unix/file.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 891786b8c43..705c25b3b88 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -4150,7 +4150,7 @@ static void test_dotfile_file_attributes(void) status = nt_get_file_attrs(filename, &attrs); ok( status == STATUS_SUCCESS, "got %#lx\n", status ); ok( attrs & FILE_ATTRIBUTE_SYSTEM, "got attributes %#lx\n", attrs ); - todo_wine ok( !(attrs & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", attrs ); + ok( !(attrs & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", attrs ); status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); ok( status == STATUS_SUCCESS, "got %#lx\n", status ); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 26ad99e7a55..f4ad4b41319 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1712,14 +1712,13 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) } *attr |= get_file_attributes( st ); - if (is_hidden_file( path )) - *attr |= FILE_ATTRIBUTE_HIDDEN; - attr_len = xattr_get( path, SAMBA_XATTR_DOS_ATTRIB, attr_data, sizeof(attr_data)-1 ); if (attr_len != -1) *attr |= parse_samba_dos_attrib_data( attr_data, attr_len ); else { + if (is_hidden_file( path )) + *attr |= FILE_ATTRIBUTE_HIDDEN; if (errno == ENOTSUP) return ret; #ifdef ENODATA if (errno == ENODATA) return ret; From c847ac9febbf79ade2d9fd3c2c7165140ec4e6cf Mon Sep 17 00:00:00 2001 From: Torge Matthies Date: Wed, 12 Apr 2023 13:35:10 +0200 Subject: [PATCH 1441/2777] ntdll: Set xattr in NtCreateFile if inferred and requested attributes don't match. And make sure it doesn't get deleted. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53826 Signed-off-by: Torge Matthies CW-Bug-Id: #22217 --- dlls/ntdll/tests/file.c | 2 +- dlls/ntdll/unix/file.c | 29 ++++++++++++++++++++++------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 705c25b3b88..94aff091adf 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -4137,7 +4137,7 @@ static void test_dotfile_file_attributes(void) status = nt_get_file_attrs(filename, &attrs); ok( status == STATUS_SUCCESS, "got %#lx\n", status ); - todo_wine ok( !(attrs & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", attrs ); + ok( !(attrs & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", attrs ); status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); ok( status == STATUS_SUCCESS, "got %#lx\n", status ); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index f4ad4b41319..7955a88b622 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1612,11 +1612,11 @@ static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULON } -static int fd_set_dos_attrib( int fd, UINT attr ) +static int fd_set_dos_attrib( int fd, UINT attr, BOOL force_set ) { /* we only store the HIDDEN and SYSTEM attributes */ attr &= XATTR_ATTRIBS_MASK; - if (attr != 0) + if (force_set || attr != 0) { /* encode the attributes in Samba 3 ASCII format. Samba 4 has extended * this format with more features, but retains compatibility with the @@ -1645,7 +1645,7 @@ static BOOL is_wine_file( HANDLE handle ) /* set the stat info and file attributes for a file (by file descriptor) */ -NTSTATUS fd_set_file_info( int fd, UINT attr, HANDLE handle ) +NTSTATUS fd_set_file_info( int fd, UINT attr, HANDLE handle, BOOL force_set_xattr ) { struct stat st; @@ -1672,7 +1672,11 @@ NTSTATUS fd_set_file_info( int fd, UINT attr, HANDLE handle ) } if (fchmod( fd, st.st_mode ) == -1) return errno_to_status( errno ); - if (fd_set_dos_attrib( fd, attr ) == -1 && errno != ENOTSUP) + /* if the file has multiple names, we can't be sure that it is safe to not + set the extended attribute, since any of the names could start with a dot */ + force_set_xattr = force_set_xattr || st.st_nlink > 1; + + if (fd_set_dos_attrib( fd, attr, force_set_xattr ) == -1 && errno != ENOTSUP) WARN( "Failed to set extended attribute " SAMBA_XATTR_DOS_ATTRIB ". errno %d (%s)\n", errno, strerror( errno ) ); @@ -4146,6 +4150,7 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU OBJECT_ATTRIBUTES new_attr; UNICODE_STRING nt_name; char *unix_name; + BOOL name_hidden = FALSE; BOOL created = FALSE; unsigned int status; @@ -4188,6 +4193,7 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU if (status == STATUS_SUCCESS) { + name_hidden = is_hidden_file( unix_name ); status = open_unix_file( handle, unix_name, access, &new_attr, attributes, sharing, disposition, options, ea_buffer, ea_length ); free( unix_name ); @@ -4215,14 +4221,15 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU break; } - if (io->Information == FILE_CREATED && (attributes & XATTR_ATTRIBS_MASK)) + if (io->Information == FILE_CREATED && + ((attributes & XATTR_ATTRIBS_MASK) || name_hidden)) { int fd, needs_close; /* set any DOS extended attributes */ if (!server_get_unix_fd( *handle, 0, &fd, &needs_close, NULL, NULL )) { - if (fd_set_dos_attrib( fd, attributes ) == -1 && errno != ENOTSUP) + if (fd_set_dos_attrib( fd, attributes, TRUE ) == -1 && errno != ENOTSUP) WARN( "Failed to set extended attribute " SAMBA_XATTR_DOS_ATTRIB ". errno %d (%s)", errno, strerror( errno ) ); if (needs_close) close( fd ); @@ -4739,10 +4746,14 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, { const FILE_BASIC_INFORMATION *info = ptr; LARGE_INTEGER mtime, atime; + char *unix_name; if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))) return io->u.Status = status; + if ((status = server_get_unix_name( handle, &unix_name ))) + unix_name = NULL; + mtime.QuadPart = info->LastWriteTime.QuadPart == -1 ? 0 : info->LastWriteTime.QuadPart; atime.QuadPart = info->LastAccessTime.QuadPart == -1 ? 0 : info->LastAccessTime.QuadPart; @@ -4750,9 +4761,13 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, status = set_file_times( fd, &mtime, &atime ); if (status == STATUS_SUCCESS && info->FileAttributes) - status = fd_set_file_info( fd, info->FileAttributes, handle ); + { + BOOL force_xattr = unix_name && is_hidden_file( unix_name ); + status = fd_set_file_info( fd, info->FileAttributes, handle, force_xattr ); + } if (needs_close) close( fd ); + free( unix_name ); } else status = STATUS_INVALID_PARAMETER_3; break; From 76d15b0b3390c7e5476408488d3091692a0e4e60 Mon Sep 17 00:00:00 2001 From: Tim Clem Date: Mon, 24 Apr 2023 11:51:31 -0700 Subject: [PATCH 1442/2777] ntdll: Decrement thread count from exit_thread and exit the process if needed. (cherry picked from commit fac1aabbef3753afc53a4ea4f933b3d0516fd302) --- dlls/ntdll/unix/thread.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 71247118cb3..4c9101d9faa 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -1425,6 +1425,8 @@ static DECLSPEC_NORETURN void exit_thread( int status ) pthread_sigmask( SIG_BLOCK, &server_block_set, NULL ); + if (InterlockedDecrement( &nb_threads ) <= 0) exit_process( status ); + if ((teb = InterlockedExchangePointer( &prev_teb, NtCurrentTeb() ))) { struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; From d9a81a1d3d832e0656900dd43501ee9b15ffe408 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Tue, 6 Jun 2023 11:30:37 +0300 Subject: [PATCH 1443/2777] wine.inf: HACK: Disable SpeechSynthWrapper.dll for Grounded. The game crashes when utilizing it and works without it, like seen already on the Steam Deck with its specific depot. CW-Bug-Id: #20918 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index c61e81ac645..6916d23f178 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2875,5 +2875,6 @@ HKCU,Software\Wine\AppDefaults\NieRAutomata.exe\X11 Driver,"LimitNumberOfResolut HKCU,Software\Wine\AppDefaults\SpellForce.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"16" ;;Other app-specific overrides HKCU,Software\Wine\AppDefaults\Pentiment.exe\DllOverrides,"SpeechSynthesisWrapper",,"disabled" +HKCU,Software\Wine\AppDefaults\Maine-Win64-Shipping.exe\DllOverrides,"SpeechSynthWrapper",0x2,"disabled" HKCU,Software\Wine\AppDefaults\rayne1.exe\DllOverrides,"d3d8",,"native" HKCU,Software\Wine\AppDefaults\rayne2.exe\DllOverrides,"d3d8",,"native" From a1c2b5f410f415a22c2f165dd6e25abfadc376a5 Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Fri, 3 Mar 2023 10:49:18 -0800 Subject: [PATCH 1444/2777] kernelbase: Implement DiscardVirtualMemory(). (cherry picked from commit d7d94ed0df6931907d1c89d7d7551dd40f5214c5) --- dlls/kernel32/kernel32.spec | 1 + dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/memory.c | 13 +++++++++++++ include/memoryapi.h | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index caa2f42d07c..f0fc51e7ab6 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -373,6 +373,7 @@ @ stdcall -import DeleteProcThreadAttributeList(ptr) # @ stub DisableThreadProfiling @ stdcall DisassociateCurrentThreadFromCallback(ptr) NTDLL.TpDisassociateCallback +@ stdcall DiscardVirtualMemory(ptr long) kernelbase.DiscardVirtualMemory @ stdcall DeleteTimerQueue(long) @ stdcall -import DeleteTimerQueueEx(long long) @ stdcall -import DeleteTimerQueueTimer(long long long) diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index 92421ec4ceb..fc687efb913 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -269,7 +269,7 @@ @ stdcall DisablePredefinedHandleTableInternal(long) @ stdcall DisableThreadLibraryCalls(long) @ stdcall DisassociateCurrentThreadFromCallback(ptr) ntdll.TpDisassociateCallback -# @ stub DiscardVirtualMemory +@ stdcall DiscardVirtualMemory(ptr long) @ stdcall DisconnectNamedPipe(long) @ stdcall DnsHostnameToComputerNameExW(wstr ptr ptr) # @ stub DsBindWithSpnExW diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c index 47a2127452f..cc22a433359 100644 --- a/dlls/kernelbase/memory.c +++ b/dlls/kernelbase/memory.c @@ -52,6 +52,19 @@ BOOLEAN WINAPI RtlSetUserValueHeap( HANDLE handle, ULONG flags, void *ptr, void ***********************************************************************/ +/*********************************************************************** + * DiscardVirtualMemory (kernelbase.@) + */ +DWORD WINAPI DECLSPEC_HOTPATCH DiscardVirtualMemory( void *addr, SIZE_T size ) +{ + NTSTATUS status; + LPVOID ret = addr; + + status = NtAllocateVirtualMemory( GetCurrentProcess(), &ret, 0, &size, MEM_RESET, PAGE_NOACCESS ); + return RtlNtStatusToDosError( status ); +} + + /*********************************************************************** * FlushViewOfFile (kernelbase.@) */ diff --git a/include/memoryapi.h b/include/memoryapi.h index 8743e67927c..6728b832fa7 100644 --- a/include/memoryapi.h +++ b/include/memoryapi.h @@ -41,5 +41,6 @@ typedef struct WIN32_MEMORY_REGION_INFORMATION SIZE_T CommitSize; } WIN32_MEMORY_REGION_INFORMATION; +DWORD WINAPI DiscardVirtualMemory(void *addr, SIZE_T size); BOOL WINAPI QueryVirtualMemoryInformation(HANDLE process,const void *addr, WIN32_MEMORY_INFORMATION_CLASS info_class, void *info, SIZE_T size, SIZE_T *ret_size); From 8a628e8e407da63089cb87b8e239079b53c78e94 Mon Sep 17 00:00:00 2001 From: Brendan Shanks Date: Fri, 3 Mar 2023 11:37:31 -0800 Subject: [PATCH 1445/2777] kernel32: Implement GetFirmwareType(). (cherry picked from commit ac031bff9efb47ac883c062bc44bf60f68b44a1f) CW-Bug-Id: #22316 --- dlls/kernel32/kernel32.spec | 1 + dlls/kernel32/process.c | 12 ++++++++++++ include/winbase.h | 1 + include/winnt.h | 7 +++++++ 4 files changed, 21 insertions(+) diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index f0fc51e7ab6..1d6dcc11f77 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -695,6 +695,7 @@ @ stdcall -import GetFinalPathNameByHandleW(long ptr long long) @ stdcall GetFirmwareEnvironmentVariableA(str str ptr long) @ stdcall GetFirmwareEnvironmentVariableW(wstr wstr ptr long) +@ stdcall GetFirmwareType(ptr) @ stdcall -import GetFullPathNameA(str long ptr ptr) # @ stub GetFullPathNameTransactedA # @ stub GetFullPathNameTransactedW diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c index 4630043645c..e9e18925911 100644 --- a/dlls/kernel32/process.c +++ b/dlls/kernel32/process.c @@ -740,6 +740,18 @@ BOOL WINAPI SetFirmwareEnvironmentVariableW(const WCHAR *name, const WCHAR *guid return FALSE; } +/*********************************************************************** + * GetFirmwareType (KERNEL32.@) + */ +BOOL WINAPI GetFirmwareType(FIRMWARE_TYPE *type) +{ + if (!type) + return FALSE; + + *type = FirmwareTypeUnknown; + return TRUE; +} + /********************************************************************** * GetNumaNodeProcessorMask (KERNEL32.@) */ diff --git a/include/winbase.h b/include/winbase.h index 45492782cd5..9859e22598d 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -2202,6 +2202,7 @@ WINBASEAPI DWORD WINAPI GetFileSize(HANDLE,LPDWORD); WINBASEAPI BOOL WINAPI GetFileSizeEx(HANDLE,PLARGE_INTEGER); WINBASEAPI BOOL WINAPI GetFileTime(HANDLE,LPFILETIME,LPFILETIME,LPFILETIME); WINBASEAPI DWORD WINAPI GetFileType(HANDLE); +WINBASEAPI BOOL WINAPI GetFirmwareType(PFIRMWARE_TYPE); #define GetFreeSpace(w) (__MSABI_LONG(0x100000)) WINBASEAPI DWORD WINAPI GetFullPathNameA(LPCSTR,DWORD,LPSTR,LPSTR*); WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR,DWORD,LPWSTR,LPWSTR*); diff --git a/include/winnt.h b/include/winnt.h index f40136a2003..b414054c807 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -6362,6 +6362,13 @@ typedef enum _PROCESS_MITIGATION_POLICY MaxProcessMitigationPolicy } PROCESS_MITIGATION_POLICY, *PPROCESS_MITIGATION_POLICY; +typedef enum _FIRMWARE_TYPE +{ + FirmwareTypeUnknown, + FirmwareTypeBios, + FirmwareTypeUefi, + FirmwareTypeMax +} FIRMWARE_TYPE, *PFIRMWARE_TYPE; /* Intrinsic functions */ From 9af0cb07fd4c55aafb4f349b6d2c6047b8c81e37 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 16 Jun 2023 13:41:39 -0600 Subject: [PATCH 1446/2777] winex11.drv: HACK: Ignore ConfigureNotify events for fullscreen window for Hitman 2. --- dlls/winex11.drv/event.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 00778ac073b..760177d0622 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1242,6 +1242,18 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) rect.bottom = rect.top + (data->whole_rect.bottom - data->whole_rect.top); } } + else if (steamgameid && !strcmp( steamgameid, "863550" )) + { + /* When going fullscreen WMs may set intermediate window sizes (e. g., excluding taskbar) before finally + * settle with the correct fullscreen window size. Hitman 2 is quick to react on window size change + * and trigger window resize again which randomly triggers the process to repeat. */ + if (data->net_wm_state & (1 << NET_WM_STATE_FULLSCREEN) && NtUserIsWindowRectFullScreen( &data->whole_rect ) + && !NtUserIsWindowRectFullScreen( &rect )) + { + TRACE( "Window is fullscreen, ignoring.\n" ); + goto done; + } + } } x = rect.left; From 498641e6a61392aaceb6dc7580fe169aa6a00072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 29 Jun 2023 11:48:55 +0200 Subject: [PATCH 1447/2777] winegstreamer: Allow concurrent wait_on_sample in the media source. Fixes deadlock in Disaster Report 4: Summer Memories. CW-Bug-Id: #22377 --- dlls/winegstreamer/media_source.c | 37 +++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index e6e78fd4de3..6c00f103662 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -44,6 +44,8 @@ struct media_stream LONG token_queue_count; LONG token_queue_cap; + CRITICAL_SECTION cs; + DWORD stream_id; BOOL active; BOOL eos; @@ -532,19 +534,34 @@ static void wait_on_sample(struct media_stream *stream, IUnknown *token) struct media_source *source = impl_from_IMFMediaSource(stream->media_source); PROPVARIANT empty_var = {.vt = VT_EMPTY}; struct wg_parser_buffer buffer; + BOOL ret; TRACE("%p, %p\n", stream, token); - if (wg_parser_stream_get_buffer(source->wg_parser, stream->wg_stream, &buffer)) + EnterCriticalSection(&stream->cs); + + if (!stream->wg_stream) { - send_buffer(stream, &buffer, token); + LeaveCriticalSection(&stream->cs); + return; } + + LeaveCriticalSection(&source->cs); + ret = wg_parser_stream_get_buffer(source->wg_parser, stream->wg_stream, &buffer); + EnterCriticalSection(&source->cs); + + if (source->state == SOURCE_SHUTDOWN) + WARN("media source has been shutdown, returning\n"); + else if (ret) + send_buffer(stream, &buffer, token); else { stream->eos = TRUE; IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty_var); dispatch_end_of_presentation(source); } + + LeaveCriticalSection(&stream->cs); } static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) @@ -704,6 +721,8 @@ static ULONG WINAPI media_stream_Release(IMFMediaStream *iface) IMFStreamDescriptor_Release(stream->descriptor); IMFMediaEventQueue_Release(stream->event_queue); flush_token_queue(stream, FALSE); + stream->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&stream->cs); free(stream); } @@ -868,6 +887,9 @@ static HRESULT media_stream_create(IMFMediaSource *source, DWORD id, object->eos = FALSE; object->wg_stream = wg_parser_get_stream(wg_parser, id); + InitializeCriticalSection(&object->cs); + object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs"); + TRACE("Created stream object %p.\n", object); *out = object; @@ -1387,6 +1409,7 @@ static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) { struct media_source *source = impl_from_IMFMediaSource(iface); + UINT i; TRACE("%p.\n", iface); @@ -1400,6 +1423,16 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) source->state = SOURCE_SHUTDOWN; + for (i = 0; i < source->stream_count; i++) + { + struct media_stream *stream = source->streams[i]; + wg_parser_stream_disable(stream->wg_stream); + + EnterCriticalSection(&stream->cs); + stream->wg_stream = NULL; + LeaveCriticalSection(&stream->cs); + } + wg_parser_disconnect(source->wg_parser); source->read_thread_shutdown = true; From 3d00d76c1c3ba3af7409b808c8c4b472333463de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 29 Jun 2023 14:36:32 +0200 Subject: [PATCH 1448/2777] winhttp: Move connect end checks out of the loop. This is only done when InitializeSecurityContextW returns SEC_E_OK, which will break out of the loop, and the checks forcefully break out of the loop if any failed. CW-Bug-Id: #18449 CW-Bug-Id: #22371 --- dlls/winhttp/net.c | 80 ++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/dlls/winhttp/net.c b/dlls/winhttp/net.c index 1be78d126d4..2e655bed5a5 100644 --- a/dlls/winhttp/net.c +++ b/dlls/winhttp/net.c @@ -384,60 +384,58 @@ DWORD netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD secur status = InitializeSecurityContextW(cred_handle, &ctx, hostname, isc_req_flags, 0, 0, &in_desc, 0, NULL, &out_desc, &attrs, NULL); TRACE( "InitializeSecurityContext ret %#lx\n", status ); + if(status == SEC_E_OK && in_bufs[1].BufferType == SECBUFFER_EXTRA) + FIXME("SECBUFFER_EXTRA not supported\n"); + } - if(status == SEC_E_OK) { - if(in_bufs[1].BufferType == SECBUFFER_EXTRA) - FIXME("SECBUFFER_EXTRA not supported\n"); - - status = QueryContextAttributesW(&ctx, SECPKG_ATTR_STREAM_SIZES, &conn->ssl_sizes); - if(status != SEC_E_OK) { - WARN("Could not get sizes\n"); - break; - } + free(read_buf); - status = QueryContextAttributesW(&ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert); - if(status == SEC_E_OK) { - res = netconn_verify_cert(cert, hostname, security_flags, check_revocation); - CertFreeCertificateContext(cert); - if(res != ERROR_SUCCESS) { - WARN( "cert verify failed: %lu\n", res ); - break; - } - }else { - WARN("Could not get cert\n"); - break; - } + if(status != SEC_E_OK || res != ERROR_SUCCESS) + goto failed; - conn->ssl_read_buf = malloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer); - if(!conn->ssl_read_buf) { - res = ERROR_OUTOFMEMORY; - break; - } - conn->ssl_write_buf = malloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer); - if(!conn->ssl_write_buf) { - res = ERROR_OUTOFMEMORY; - break; - } - } + status = QueryContextAttributesW(&ctx, SECPKG_ATTR_STREAM_SIZES, &conn->ssl_sizes); + if(status != SEC_E_OK) { + WARN("Could not get sizes\n"); + goto failed; } - free(read_buf); + status = QueryContextAttributesW(&ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert); + if(status != SEC_E_OK) { + WARN("Could not get cert\n"); + goto failed; + } - if(status != SEC_E_OK || res != ERROR_SUCCESS) { - WARN( "Failed to initialize security context: %#lx\n", status ); - free(conn->ssl_read_buf); - conn->ssl_read_buf = NULL; - free(conn->ssl_write_buf); - conn->ssl_write_buf = NULL; - DeleteSecurityContext(&ctx); - return ERROR_WINHTTP_SECURE_CHANNEL_ERROR; + res = netconn_verify_cert(cert, hostname, security_flags, check_revocation); + CertFreeCertificateContext(cert); + if(res != ERROR_SUCCESS) { + WARN( "cert verify failed: %lu\n", res ); + goto failed; } + conn->ssl_read_buf = malloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer); + if(!conn->ssl_read_buf) { + res = ERROR_OUTOFMEMORY; + goto failed; + } + conn->ssl_write_buf = malloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer); + if(!conn->ssl_write_buf) { + res = ERROR_OUTOFMEMORY; + goto failed; + } TRACE("established SSL connection\n"); conn->secure = TRUE; conn->ssl_ctx = ctx; return ERROR_SUCCESS; + +failed: + WARN( "Failed to initialize security context: %#lx\n", status ); + free(conn->ssl_read_buf); + conn->ssl_read_buf = NULL; + free(conn->ssl_write_buf); + conn->ssl_write_buf = NULL; + DeleteSecurityContext(&ctx); + return ERROR_WINHTTP_SECURE_CHANNEL_ERROR; } static DWORD send_ssl_chunk( struct netconn *conn, const void *msg, size_t size, WSAOVERLAPPED *ovr ) From 7c6e45f0f7433bb83842cff93815929d1ec9ba71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 29 Jun 2023 14:39:06 +0200 Subject: [PATCH 1449/2777] winhttp: Introduce new netconn_negotiate helper. CW-Bug-Id: #18449 CW-Bug-Id: #22371 --- dlls/winhttp/net.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/dlls/winhttp/net.c b/dlls/winhttp/net.c index 2e655bed5a5..4eb7b601d0e 100644 --- a/dlls/winhttp/net.c +++ b/dlls/winhttp/net.c @@ -303,28 +303,24 @@ void netconn_release( struct netconn *conn ) free(conn); } -DWORD netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD security_flags, CredHandle *cred_handle, - BOOL check_revocation ) +static DWORD netconn_negotiate( struct netconn *conn, WCHAR *hostname, CredHandle *cred_handle, + CtxtHandle *ctx ) { SecBuffer out_buf = {0, SECBUFFER_TOKEN, NULL}, in_bufs[2] = {{0, SECBUFFER_TOKEN}, {0, SECBUFFER_EMPTY}}; SecBufferDesc out_desc = {SECBUFFER_VERSION, 1, &out_buf}, in_desc = {SECBUFFER_VERSION, 2, in_bufs}; BYTE *read_buf; SIZE_T read_buf_size = 2048; ULONG attrs = 0; - CtxtHandle ctx; SSIZE_T size; - const CERT_CONTEXT *cert; SECURITY_STATUS status; - DWORD res = ERROR_SUCCESS; const DWORD isc_req_flags = ISC_REQ_ALLOCATE_MEMORY|ISC_REQ_USE_SESSION_KEY|ISC_REQ_CONFIDENTIALITY |ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_MANUAL_CRED_VALIDATION; if (!(read_buf = malloc( read_buf_size ))) return ERROR_OUTOFMEMORY; - memset( &ctx, 0, sizeof(ctx) ); status = InitializeSecurityContextW(cred_handle, NULL, hostname, isc_req_flags, 0, 0, NULL, 0, - &ctx, &out_desc, &attrs, NULL); + ctx, &out_desc, &attrs, NULL); assert(status != SEC_E_OK); @@ -337,7 +333,7 @@ DWORD netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD secur size = sock_send(conn->socket, out_buf.pvBuffer, out_buf.cbBuffer, NULL); if(size != out_buf.cbBuffer) { ERR("send failed\n"); - res = ERROR_WINHTTP_SECURE_CHANNEL_ERROR; + status = ERROR_WINHTTP_SECURE_CHANNEL_ERROR; break; } @@ -381,7 +377,7 @@ DWORD netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD secur in_bufs[0].cbBuffer += size; in_bufs[0].pvBuffer = read_buf; - status = InitializeSecurityContextW(cred_handle, &ctx, hostname, isc_req_flags, 0, 0, &in_desc, + status = InitializeSecurityContextW(cred_handle, ctx, hostname, isc_req_flags, 0, 0, &in_desc, 0, NULL, &out_desc, &attrs, NULL); TRACE( "InitializeSecurityContext ret %#lx\n", status ); if(status == SEC_E_OK && in_bufs[1].BufferType == SECBUFFER_EXTRA) @@ -390,6 +386,18 @@ DWORD netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD secur free(read_buf); + return status; +} + +DWORD netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD security_flags, CredHandle *cred_handle, + BOOL check_revocation ) +{ + CtxtHandle ctx = {0}; + const CERT_CONTEXT *cert; + SECURITY_STATUS status; + DWORD res = ERROR_SUCCESS; + + status = netconn_negotiate(conn, hostname, cred_handle, &ctx); if(status != SEC_E_OK || res != ERROR_SUCCESS) goto failed; From 265b92d16e5a1ab9f405e5e09ca078cf4916c189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 29 Jun 2023 16:01:39 +0200 Subject: [PATCH 1450/2777] winhttp: Handle SEC_I_RENEGOTIATE after DecryptMessage. By performing renegotiation as we should, instead of incorrectly returning ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED. MSDN says we should pass returned SECBUFFER_EXTRA as SECBUFFER_TOKEN, so we also do that, although it's usually empty. CW-Bug-Id: #18449 CW-Bug-Id: #22371 --- dlls/winhttp/net.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/dlls/winhttp/net.c b/dlls/winhttp/net.c index 4eb7b601d0e..c10438df624 100644 --- a/dlls/winhttp/net.c +++ b/dlls/winhttp/net.c @@ -304,7 +304,7 @@ void netconn_release( struct netconn *conn ) } static DWORD netconn_negotiate( struct netconn *conn, WCHAR *hostname, CredHandle *cred_handle, - CtxtHandle *ctx ) + CtxtHandle *prev_ctx, SecBufferDesc *prev_buf, CtxtHandle *ctx ) { SecBuffer out_buf = {0, SECBUFFER_TOKEN, NULL}, in_bufs[2] = {{0, SECBUFFER_TOKEN}, {0, SECBUFFER_EMPTY}}; SecBufferDesc out_desc = {SECBUFFER_VERSION, 1, &out_buf}, in_desc = {SECBUFFER_VERSION, 2, in_bufs}; @@ -319,8 +319,9 @@ static DWORD netconn_negotiate( struct netconn *conn, WCHAR *hostname, CredHandl if (!(read_buf = malloc( read_buf_size ))) return ERROR_OUTOFMEMORY; - status = InitializeSecurityContextW(cred_handle, NULL, hostname, isc_req_flags, 0, 0, NULL, 0, + status = InitializeSecurityContextW(cred_handle, prev_ctx, hostname, isc_req_flags, 0, 0, prev_buf, 0, ctx, &out_desc, &attrs, NULL); + if (!ctx) ctx = prev_ctx; assert(status != SEC_E_OK); @@ -397,7 +398,7 @@ DWORD netconn_secure_connect( struct netconn *conn, WCHAR *hostname, DWORD secur SECURITY_STATUS status; DWORD res = ERROR_SUCCESS; - status = netconn_negotiate(conn, hostname, cred_handle, &ctx); + status = netconn_negotiate(conn, hostname, cred_handle, NULL, NULL, &ctx); if(status != SEC_E_OK || res != ERROR_SUCCESS) goto failed; @@ -558,8 +559,23 @@ static DWORD read_ssl_chunk( struct netconn *conn, void *buf, SIZE_T buf_size, S break; case SEC_I_RENEGOTIATE: + { + SecBuffer out_buf = {0, SECBUFFER_TOKEN, NULL}; + SecBufferDesc out_desc = {SECBUFFER_VERSION, 1, &out_buf}; + TRACE("renegotiate\n"); - return ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED; + + for(i = 0; i < ARRAY_SIZE(bufs); i++) { + if(bufs[i].BufferType == SECBUFFER_EXTRA) { + out_buf.cbBuffer = bufs[i].cbBuffer; + out_buf.pvBuffer = bufs[i].pvBuffer; + } + } + + res = netconn_negotiate(conn, conn->host->hostname, NULL, &conn->ssl_ctx, &out_desc, NULL); + if (res != SEC_E_OK) return res; + continue; + } case SEC_I_CONTEXT_EXPIRED: TRACE("context expired\n"); From 5c988cdf33f5c86cfff2dcff5e4b1f65252caa62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 3 Dec 2020 11:26:56 +0100 Subject: [PATCH 1451/2777] secur32: Perform TLS re-handshake after SEC_I_RENEGOTIATE was returned. Even if input buffer is empty, as this is often the case. CW-Bug-Id: #18449 CW-Bug-Id: #22371 --- dlls/secur32/schannel.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c index 6b5df3520a7..d4aab2b4c2a 100644 --- a/dlls/secur32/schannel.c +++ b/dlls/secur32/schannel.c @@ -64,6 +64,7 @@ struct schan_context const CERT_CONTEXT *cert; SIZE_T header_size; BOOL shutdown_requested; + BOOL rehandshake_requested; }; static struct schan_handle *schan_handle_table; @@ -875,7 +876,7 @@ static SECURITY_STATUS establish_context( buffer = &pInput->pBuffers[idx]; ptr = buffer->pvBuffer; - if (buffer->cbBuffer < ctx->header_size) + if (buffer->cbBuffer < ctx->header_size && !ctx->rehandshake_requested) { TRACE("Expected at least %Iu bytes, but buffer only contains %lu bytes.\n", ctx->header_size, buffer->cbBuffer); @@ -892,7 +893,7 @@ static SECURITY_STATUS establish_context( ptr += record_size; } - if (!expected_size) + if (!expected_size && !ctx->rehandshake_requested) { TRACE("Expected at least %Iu bytes, but buffer only contains %lu bytes.\n", max(ctx->header_size, record_size), buffer->cbBuffer); @@ -942,6 +943,7 @@ static SECURITY_STATUS establish_context( params.output_offset = &output_offset; params.control_token = ctx->shutdown_requested ? control_token_shutdown : control_token_none; ctx->shutdown_requested = FALSE; + ctx->rehandshake_requested = FALSE; ret = GNUTLS_CALL( handshake, ¶ms ); if (output_buffer_idx != -1) @@ -1563,6 +1565,7 @@ static SECURITY_STATUS SEC_ENTRY schan_DecryptMessage(PCtxtHandle context_handle buffer->BufferType = SECBUFFER_STREAM_HEADER; buffer->cbBuffer = ctx->header_size; + if (status == SEC_I_RENEGOTIATE) ctx->rehandshake_requested = TRUE; return status; } From 12535412d6bcf5d072c8faf9d8c0e32bb2cf094a Mon Sep 17 00:00:00 2001 From: Georg Lehmann Date: Wed, 28 Jun 2023 17:51:02 +0200 Subject: [PATCH 1452/2777] winevulkan: Keep deferred operation function params alive. The Vulkan spec says: Parameters to the command requesting a deferred operation may be accessed by the implementation at any time until the deferred operation enters the complete state. Pointer parameters must not be modified (e.g. reallocated/freed). This fixes a regression in Doom Eternal with ray tracing enabled with drivers that actually support deferred operations (e.g. nvidia, amdvlk). Link: https://gitlab.winehq.org/wine/wine/-/merge_requests/3188 --- dlls/winevulkan/make_vulkan | 31 ++++++++++++++++---- dlls/winevulkan/vulkan.c | 50 ++++++++++++++++++++++++++++++++ dlls/winevulkan/vulkan_private.h | 21 ++++++++++++++ 3 files changed, 96 insertions(+), 6 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 9ac1f5875f2..fc3aefbe43d 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -266,6 +266,10 @@ FUNCTION_OVERRIDES = { "vkGetDeviceGroupSurfacePresentModesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, "vkGetPhysicalDevicePresentRectanglesKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, + # VK_KHR_deferred_host_operations + "vkCreateDeferredOperationKHR" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, + "vkDestroyDeferredOperationKHR" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, + # VK_EXT_calibrated_timestamps "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, "vkGetCalibratedTimestampsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, @@ -816,6 +820,7 @@ class VkFunction(object): def body(self, conv, unwrap, params_prefix=""): body = "" needs_alloc = False + deferred_op = None # Declare any tmp parameters for conversion. for p in self.params: @@ -830,9 +835,12 @@ class VkFunction(object): body += " {0} {1}_host;\n".format(p.type, p.name) if p.needs_alloc(conv, unwrap): needs_alloc = True + if p.type == "VkDeferredOperationKHR" and not p.is_pointer(): + deferred_op = p.name if needs_alloc: - body += " struct conversion_context ctx;\n" + body += " struct conversion_context local_ctx;\n" + body += " struct conversion_context *ctx = &local_ctx;\n" body += "\n" if not self.is_perf_critical(): @@ -845,7 +853,13 @@ class VkFunction(object): body += " return STATUS_SUCCESS;\n\n" if needs_alloc: - body += " init_conversion_context(&ctx);\n" + if deferred_op is not None: + body += " if (params->{} == VK_NULL_HANDLE)\n".format(deferred_op) + body += " " + body += " init_conversion_context(ctx);\n" + if deferred_op is not None: + body += " else\n" + body += " ctx = &wine_deferred_operation_from_handle(params->{})->ctx;\n".format(deferred_op) # Call any win_to_host conversion calls. unwrap = self.thunk_type == ThunkType.PUBLIC @@ -853,7 +867,7 @@ class VkFunction(object): if p.needs_conversion(conv, unwrap, Direction.INPUT): body += p.copy(Direction.INPUT, conv, unwrap, prefix=params_prefix) elif p.is_dynamic_array() and p.needs_conversion(conv, unwrap, Direction.OUTPUT): - body += " {0}_host = ({2}{0} && {1}) ? conversion_context_alloc(&ctx, sizeof(*{0}_host) * {1}) : NULL;\n".format( + body += " {0}_host = ({2}{0} && {1}) ? conversion_context_alloc(ctx, sizeof(*{0}_host) * {1}) : NULL;\n".format( p.name, p.get_dyn_array_len(params_prefix, conv), params_prefix) # Build list of parameters containing converted and non-converted parameters. @@ -882,7 +896,10 @@ class VkFunction(object): body += p.copy(Direction.OUTPUT, conv, unwrap, prefix=params_prefix) if needs_alloc: - body += " free_conversion_context(&ctx);\n" + if deferred_op is not None: + body += " if (params->{} == VK_NULL_HANDLE)\n".format(deferred_op) + body += " " + body += " free_conversion_context(ctx);\n" # Finally return the result. Performance critical functions return void to allow tail calls. if not self.is_perf_critical(): @@ -1145,6 +1162,8 @@ class VkHandle(object): return "wine_debug_utils_messenger_from_handle({0})->debug_messenger".format(name) if self.name == "VkDebugReportCallbackEXT": return "wine_debug_report_callback_from_handle({0})->debug_callback".format(name) + if self.name == "VkDeferredOperationKHR": + return "wine_deferred_operation_from_handle({0})->deferred_operation".format(name) if self.name == "VkDevice": return "wine_device_from_handle({0})->device".format(name) if self.name == "VkInstance": @@ -1765,7 +1784,7 @@ class VkParam(VkVariable): win_type = "win32" if conv else "win64" wrap_part = "" if unwrap or not self.needs_unwrapping() else "unwrapped_" if direction == Direction.INPUT: - ctx_param = "&ctx, " if self.needs_alloc(conv, unwrap) else "" + ctx_param = "ctx, " if self.needs_alloc(conv, unwrap) else "" if self.is_dynamic_array(): return " {0}_host = convert_{2}_array_{4}_to_{6}host({5}{1}, {3});\n".format( self.name, self.value(prefix, conv), self.type, self.get_dyn_array_len(prefix, conv), @@ -1773,7 +1792,7 @@ class VkParam(VkVariable): elif self.optional: ret = " if ({0}{1})\n".format(prefix, self.name) ret += " {\n" - ret += " {0}_host = conversion_context_alloc(&ctx, sizeof(*{0}_host));\n".format(self.name) + ret += " {0}_host = conversion_context_alloc(ctx, sizeof(*{0}_host));\n".format(self.name) ret += " convert_{0}_{3}_to_{5}host({4}{1}, {2}_host);\n".format( self.type, self.value(prefix, conv), self.name, win_type, ctx_param, wrap_part) ret += " }\n" diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 260f196b81b..6c73ddd2d39 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -3152,6 +3152,56 @@ void wine_vkDestroyDebugReportCallbackEXT(VkInstance handle, VkDebugReportCallba free(object); } +VkResult wine_vkCreateDeferredOperationKHR(VkDevice handle, + const VkAllocationCallbacks* allocator, + VkDeferredOperationKHR* deferredOperation) +{ + struct wine_device *device = wine_device_from_handle(handle); + struct wine_deferred_operation *object; + VkResult res; + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + if (!(object = calloc(1, sizeof(*object)))) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + res = device->funcs.p_vkCreateDeferredOperationKHR(device->device, NULL, &object->deferred_operation); + + if (res != VK_SUCCESS) + { + free(object); + return res; + } + + init_conversion_context(&object->ctx); + + WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance, object, object->deferred_operation, object); + *deferredOperation = wine_deferred_operation_to_handle(object); + + return VK_SUCCESS; +} + +void wine_vkDestroyDeferredOperationKHR(VkDevice handle, + VkDeferredOperationKHR operation, + const VkAllocationCallbacks* allocator) +{ + struct wine_device *device = wine_device_from_handle(handle); + struct wine_deferred_operation *object; + + object = wine_deferred_operation_from_handle(operation); + + if (!object) + return; + + device->funcs.p_vkDestroyDeferredOperationKHR(device->device, object->deferred_operation, NULL); + + WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, object); + + free_conversion_context(&object->ctx); + free(object); +} + void wine_vkDestroySwapchainKHR(VkDevice device_handle, VkSwapchainKHR handle, const VkAllocationCallbacks *allocator) { struct wine_device *device = wine_device_from_handle(device_handle); diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 245c81419a0..864fc392c2c 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -431,6 +431,27 @@ static inline void *conversion_context_alloc(struct conversion_context *pool, si } } +struct wine_deferred_operation +{ + VkDeferredOperationKHR deferred_operation; /* native handle */ + + struct conversion_context ctx; /* to keep params alive. */ + + struct wine_vk_mapping mapping; +}; + +static inline struct wine_deferred_operation *wine_deferred_operation_from_handle( + VkDeferredOperationKHR handle) +{ + return (struct wine_deferred_operation *)(uintptr_t)handle; +} + +static inline VkDeferredOperationKHR wine_deferred_operation_to_handle( + struct wine_deferred_operation *deferred_operation) +{ + return (VkDeferredOperationKHR)(uintptr_t)deferred_operation; +} + typedef UINT32 PTR32; typedef struct From 2babdba48c76616f2e0909bd95382454751bb910 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 3 Jul 2023 13:30:33 -0600 Subject: [PATCH 1453/2777] fsync: Check for NULL handle in get_object(). CW-Bug-Id: #22395 --- dlls/ntdll/unix/fsync.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index b4d4b086919..ac280a81fe6 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -402,6 +402,7 @@ static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) return STATUS_NOT_IMPLEMENTED; } + if (!handle) return STATUS_INVALID_HANDLE; /* We need to try grabbing it from the server. Uninterrupted section * is needed to avoid race with NtClose() which first calls fsync_close() From cbe1cfe06683da5dbc6ff7fb67c0d4703e5e5060 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 17 Jul 2023 16:01:22 +0300 Subject: [PATCH 1454/2777] Revert "wine.inf: Enable ir50_32 video codec." This reverts commit 555610770ab2708ba0aaeec9dbabbb9ee56111fb. --- loader/wine.inf.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 6916d23f178..40179fba301 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2337,7 +2337,7 @@ system.ini, drivers32,,"msacm.msgsm610=msgsm32.acm" system.ini, drivers32,,"vidc.mrle=msrle32.dll" system.ini, drivers32,,"vidc.msvc=msvidc32.dll" system.ini, drivers32,,"vidc.cvid=iccvid.dll" -system.ini, drivers32,,"vidc.IV50=ir50_32.dll" +system.ini, drivers32,,"; vidc.IV50=ir50_32.dll" system.ini, drivers32,,"; vidc.IV31=ir32_32.dll" system.ini, drivers32,,"; vidc.IV32=ir32_32.dll" From 5ac5bccf1c3fa963bfcf856b6dd8ef87e403537f Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 17 Jul 2023 16:01:25 +0300 Subject: [PATCH 1455/2777] Revert "ir50_32: Implement decompression." This reverts commit 106163706fcd4eb93e1ed8a1b6cae37415a5b29c. --- dlls/ir50_32/ir50.c | 149 ++------------------------------------------ 1 file changed, 4 insertions(+), 145 deletions(-) diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 87807aba25f..428108f09ba 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -26,7 +26,6 @@ #include "winuser.h" #include "commdlg.h" #include "vfw.h" -#include "initguid.h" #include "ir50_private.h" #include "wine/debug.h" @@ -38,14 +37,6 @@ static HINSTANCE IR50_32_hModule; #define IV50_MAGIC mmioFOURCC('I','V','5','0') #define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020) -DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50, MAKEFOURCC('I','V','5','0')); - -static inline UINT64 -make_uint64( UINT32 high, UINT32 low ) -{ - return ((UINT64)high << 32) | low; -} - static LRESULT IV50_Open( const ICINFO *icinfo ) @@ -142,146 +133,14 @@ IV50_DecompressGetFormat( LPBITMAPINFO in, LPBITMAPINFO out ) static LRESULT IV50_DecompressBegin( IMFTransform *decoder, LPBITMAPINFO in, LPBITMAPINFO out ) { - IMFMediaType *input_type, *output_type; - const GUID *output_subtype; - LRESULT r = ICERR_INTERNAL; - - TRACE("ICM_DECOMPRESS_BEGIN %p %p %p\n", decoder, in, out); - - if ( !decoder ) - return ICERR_BADPARAM; - - if ( out->bmiHeader.biBitCount == 32 ) - output_subtype = &MFVideoFormat_RGB32; - else if ( out->bmiHeader.biBitCount == 16 ) - output_subtype = &MFVideoFormat_RGB555; - else - return ICERR_BADFORMAT; - - if ( FAILED(MFCreateMediaType( &input_type )) ) - return ICERR_INTERNAL; - - if ( FAILED(MFCreateMediaType( &output_type )) ) - { - IMFMediaType_Release( input_type ); - return ICERR_INTERNAL; - } - - if ( FAILED(IMFMediaType_SetGUID( input_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video )) || - FAILED(IMFMediaType_SetGUID( input_type, &MF_MT_SUBTYPE, &MFVideoFormat_IV50 )) ) - goto done; - if ( FAILED(IMFMediaType_SetUINT64( - input_type, &MF_MT_FRAME_SIZE, - make_uint64( in->bmiHeader.biWidth, in->bmiHeader.biHeight ) )) ) - goto done; - - if ( FAILED(IMFMediaType_SetGUID( output_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video )) || - FAILED(IMFMediaType_SetGUID( output_type, &MF_MT_SUBTYPE, output_subtype )) ) - goto done; - if ( FAILED(IMFMediaType_SetUINT64( - output_type, &MF_MT_FRAME_SIZE, - make_uint64( out->bmiHeader.biWidth, abs(out->bmiHeader.biHeight) ) )) ) - goto done; - - if ( FAILED(IMFTransform_SetInputType( decoder, 0, input_type, 0 )) || - FAILED(IMFTransform_SetOutputType( decoder, 0, output_type, 0 )) ) - goto done; - - r = ICERR_OK; - -done: - IMFMediaType_Release( input_type ); - IMFMediaType_Release( output_type ); - return r; + FIXME("ICM_DECOMPRESS_BEGIN %p %p %p\n", decoder, in, out); + return ICERR_UNSUPPORTED; } static LRESULT IV50_Decompress( IMFTransform *decoder, ICDECOMPRESS *icd, DWORD size ) { - IMFSample *in_sample = NULL, *out_sample = NULL; - IMFMediaBuffer *in_buf = NULL, *out_buf = NULL; - MFT_OUTPUT_DATA_BUFFER mft_buf; - DWORD mft_status; - BYTE *data; - HRESULT hr; - LRESULT r = ICERR_INTERNAL; - - TRACE("ICM_DECOMPRESS %p %p %lu\n", decoder, icd, size); - - if ( FAILED(MFCreateSample( &in_sample )) ) - return ICERR_INTERNAL; - - if ( FAILED(MFCreateMemoryBuffer( icd->lpbiInput->biSizeImage, &in_buf )) ) - goto done; - - if ( FAILED(IMFSample_AddBuffer( in_sample, in_buf )) ) - goto done; - - if ( FAILED(MFCreateSample( &out_sample )) ) - goto done; - - if ( FAILED(MFCreateMemoryBuffer( icd->lpbiOutput->biSizeImage, &out_buf )) ) - goto done; - - if ( FAILED(IMFSample_AddBuffer( out_sample, out_buf )) ) - goto done; - - if ( FAILED(IMFMediaBuffer_Lock( in_buf, &data, NULL, NULL ))) - goto done; - - memcpy( data, icd->lpInput, icd->lpbiInput->biSizeImage ); - - if ( FAILED(IMFMediaBuffer_Unlock( in_buf )) ) - goto done; - - if ( FAILED(IMFMediaBuffer_SetCurrentLength( in_buf, icd->lpbiInput->biSizeImage )) ) - goto done; - - if ( FAILED(IMFTransform_ProcessInput( decoder, 0, in_sample, 0 )) ) - goto done; - - memset( &mft_buf, 0, sizeof(mft_buf) ); - mft_buf.pSample = out_sample; - - hr = IMFTransform_ProcessOutput( decoder, 0, 1, &mft_buf, &mft_status ); - if ( SUCCEEDED(hr) && (mft_status & MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE) ) - hr = IMFTransform_ProcessOutput( decoder, 0, 1, &mft_buf, &mft_status ); - - if ( SUCCEEDED(hr) ) - { - LONG width = icd->lpbiOutput->biWidth * (icd->lpbiOutput->biBitCount / 8); - LONG height = abs( icd->lpbiOutput->biHeight ); - LONG data_stride = (width + 3) & ~3; - LONG out_stride = icd->lpbiOutput->biHeight >= 0 ? -data_stride : data_stride; - BYTE *output_start = (BYTE *)icd->lpOutput; - - if (out_stride < 0) - output_start += (height - 1) * abs(out_stride); - - if ( FAILED(IMFMediaBuffer_Lock( out_buf, &data, NULL, NULL ))) - goto done; - - MFCopyImage( output_start, out_stride, data, data_stride, width, height ); - - IMFMediaBuffer_Unlock( out_buf ); - r = ICERR_OK; - } - else if ( hr == MF_E_TRANSFORM_NEED_MORE_INPUT ) - { - TRACE("no output received.\n"); - r = ICERR_OK; - } - -done: - if ( in_buf ) - IMFMediaBuffer_Release( in_buf ); - if ( in_sample ) - IMFSample_Release( in_sample ); - if ( out_buf ) - IMFMediaBuffer_Release( out_buf ); - if ( out_sample ) - IMFSample_Release( out_sample ); - - return r; + FIXME("ICM_DECOMPRESS %p %p %lu\n", decoder, icd, size); + return ICERR_UNSUPPORTED; } static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize ) From b15e9620074941a62f33087911f30dc70647d4f9 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 17 Jul 2023 16:01:41 +0300 Subject: [PATCH 1456/2777] Revert "ir50_32: Implement open and close." This reverts commit f23349f7b19c90ada42133232ff71d6db5050525. --- dlls/ir50_32/Makefile.in | 3 +-- dlls/ir50_32/ir50.c | 19 +++---------------- dlls/ir50_32/ir50_private.h | 2 -- 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/dlls/ir50_32/Makefile.in b/dlls/ir50_32/Makefile.in index 2db9c8076c9..7bac0ccc9ca 100644 --- a/dlls/ir50_32/Makefile.in +++ b/dlls/ir50_32/Makefile.in @@ -1,6 +1,5 @@ MODULE = ir50_32.dll -IMPORTS = user32 mfplat mfuuid -DELAYIMPORTS = winegstreamer +IMPORTS = user32 C_SRCS = \ ir50.c diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 428108f09ba..7e494d50761 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -35,23 +35,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(ir50_32); static HINSTANCE IR50_32_hModule; #define IV50_MAGIC mmioFOURCC('I','V','5','0') -#define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020) static LRESULT IV50_Open( const ICINFO *icinfo ) { - IMFTransform *decoder = NULL; - - TRACE("DRV_OPEN %p\n", icinfo); - - if ( icinfo && compare_fourcc( icinfo->fccType, ICTYPE_VIDEO ) ) - return 0; - - if ( FAILED(winegstreamer_create_video_decoder( &decoder )) ) - return 0; - - return (LRESULT)decoder; + FIXME("DRV_OPEN %p\n", icinfo); + return 0; } static LRESULT @@ -187,10 +177,7 @@ LRESULT WINAPI IV50_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg, break; case DRV_CLOSE: - TRACE("DRV_CLOSE\n"); - if ( decoder ) - IMFTransform_Release( decoder ); - r = 1; + FIXME("DRV_CLOSE\n"); break; case DRV_ENABLE: diff --git a/dlls/ir50_32/ir50_private.h b/dlls/ir50_32/ir50_private.h index c0b96bc17e4..c022a8196d2 100644 --- a/dlls/ir50_32/ir50_private.h +++ b/dlls/ir50_32/ir50_private.h @@ -31,6 +31,4 @@ #define IDS_NAME 100 #define IDS_DESCRIPTION 101 -HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out); - #endif /* __IR50_PRIVATE_H */ From c499437ab7bfc0d63bcc8880d786a43d7c0e58b0 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 17 Jul 2023 16:01:51 +0300 Subject: [PATCH 1457/2777] Revert "ir50_32: Implement IV50_DecompressGetFormat." This reverts commit 8c5de958be2e89bdedce9265b8d0007e4c1800ea. --- dlls/ir50_32/ir50.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 7e494d50761..92e4c8a49be 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -97,28 +97,8 @@ IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) static LRESULT IV50_DecompressGetFormat( LPBITMAPINFO in, LPBITMAPINFO out ) { - DWORD size; - - TRACE("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out); - - if ( !in ) - return ICERR_BADPARAM; - - if ( in->bmiHeader.biCompression != IV50_MAGIC ) - return ICERR_BADFORMAT; - - size = in->bmiHeader.biSize; - if ( out ) - { - memcpy( out, in, size ); - out->bmiHeader.biHeight = abs(in->bmiHeader.biHeight); - out->bmiHeader.biCompression = BI_RGB; - out->bmiHeader.biBitCount = 32; - out->bmiHeader.biSizeImage = out->bmiHeader.biWidth * out->bmiHeader.biHeight * 4; - return ICERR_OK; - } - - return size; + FIXME("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out); + return ICERR_UNSUPPORTED; } static LRESULT IV50_DecompressBegin( IMFTransform *decoder, LPBITMAPINFO in, LPBITMAPINFO out ) From df17b2caf66d41bf19490a4ab042a0011a3dadff Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 17 Jul 2023 16:02:03 +0300 Subject: [PATCH 1458/2777] Revert "ir50_32: Implement IV50_DecompressQuery." This reverts commit 64995a9b048cd7876ba3611b25c7d2c7ec612e5e. --- dlls/ir50_32/ir50.c | 47 ++------------------------------------------- 1 file changed, 2 insertions(+), 45 deletions(-) diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 92e4c8a49be..0e1c9b4d2e4 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -47,51 +47,8 @@ IV50_Open( const ICINFO *icinfo ) static LRESULT IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) { - TRACE("ICM_DECOMPRESS_QUERY %p %p\n", in, out); - - TRACE("in->planes = %d\n", in->bmiHeader.biPlanes); - TRACE("in->bpp = %d\n", in->bmiHeader.biBitCount); - TRACE("in->height = %ld\n", in->bmiHeader.biHeight); - TRACE("in->width = %ld\n", in->bmiHeader.biWidth); - TRACE("in->compr = %#lx\n", in->bmiHeader.biCompression); - - if ( in->bmiHeader.biCompression != IV50_MAGIC ) - { - TRACE("can't do %#lx compression\n", in->bmiHeader.biCompression); - return ICERR_BADFORMAT; - } - - /* output must be same dimensions as input */ - if ( out ) - { - TRACE("out->planes = %d\n", out->bmiHeader.biPlanes); - TRACE("out->bpp = %d\n", out->bmiHeader.biBitCount); - TRACE("out->height = %ld\n", out->bmiHeader.biHeight); - TRACE("out->width = %ld\n", out->bmiHeader.biWidth); - TRACE("out->compr = %#lx\n", out->bmiHeader.biCompression); - - if ( out->bmiHeader.biCompression != BI_RGB ) - { - TRACE("incompatible compression requested\n"); - return ICERR_BADFORMAT; - } - - if ( out->bmiHeader.biBitCount != 32 && out->bmiHeader.biBitCount != 16 ) - { - TRACE("incompatible depth requested\n"); - return ICERR_BADFORMAT; - } - - if ( in->bmiHeader.biPlanes != out->bmiHeader.biPlanes || - in->bmiHeader.biHeight != abs(out->bmiHeader.biHeight) || - in->bmiHeader.biWidth != out->bmiHeader.biWidth ) - { - TRACE("incompatible output dimensions requested\n"); - return ICERR_BADFORMAT; - } - } - - return ICERR_OK; + FIXME("ICM_DECOMPRESS_QUERY %p %p\n", in, out); + return ICERR_UNSUPPORTED; } static LRESULT From 427139f358705f9351d2288e470abe7e6aedba80 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 17 Jul 2023 16:02:15 +0300 Subject: [PATCH 1459/2777] Revert "ir50_32: Implement IV50_GetInfo." This reverts commit 8f439301efb3baab451a450bbcec5fb7cfb068ce. --- dlls/ir50_32/ir50.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 0e1c9b4d2e4..3019301742e 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -72,23 +72,8 @@ static LRESULT IV50_Decompress( IMFTransform *decoder, ICDECOMPRESS *icd, DWORD static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize ) { - TRACE("ICM_GETINFO %p %lu\n", icinfo, dwSize); - - if ( !icinfo ) return sizeof(ICINFO); - if ( dwSize < sizeof(ICINFO) ) return 0; - - icinfo->dwSize = sizeof(ICINFO); - icinfo->fccType = ICTYPE_VIDEO; - icinfo->fccHandler = IV50_MAGIC; - icinfo->dwFlags = 0; - icinfo->dwVersion = ICVERSION; - icinfo->dwVersionICM = ICVERSION; - - LoadStringW( IR50_32_hModule, IDS_NAME, icinfo->szName, ARRAY_SIZE(icinfo->szName) ); - LoadStringW( IR50_32_hModule, IDS_DESCRIPTION, icinfo->szDescription, ARRAY_SIZE(icinfo->szDescription) ); - /* msvfw32 will fill icinfo->szDriver for us */ - - return sizeof(ICINFO); + FIXME("ICM_GETINFO %p %lu\n", icinfo, dwSize); + return ICERR_UNSUPPORTED; } /*********************************************************************** From 9b953b2963595a0deddd513ea6b5df866d7546a4 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 17 Jul 2023 16:02:23 +0300 Subject: [PATCH 1460/2777] Revert "ir50_32: Add stub dll." This reverts commit b5d7c8d3b63aed7800a7a75308cf467d61e81576. --- configure.ac | 1 - dlls/ir50_32/Makefile.in | 7 -- dlls/ir50_32/ir50.c | 180 ------------------------------------ dlls/ir50_32/ir50_32.rc | 29 ------ dlls/ir50_32/ir50_32.spec | 1 - dlls/ir50_32/ir50_private.h | 34 ------- po/ar.po | 12 --- po/ast.po | 8 -- po/bg.po | 10 -- po/ca.po | 12 --- po/cs.po | 12 --- po/da.po | 12 --- po/de.po | 12 --- po/el.po | 8 -- po/en.po | 8 -- po/en_US.po | 8 -- po/eo.po | 10 -- po/es.po | 12 --- po/fa.po | 8 -- po/fi.po | 12 --- po/fr.po | 12 --- po/he.po | 12 --- po/hi.po | 8 -- po/hr.po | 12 --- po/hu.po | 12 --- po/it.po | 12 --- po/ja.po | 12 --- po/ko.po | 12 --- po/lt.po | 12 --- po/ml.po | 8 -- po/nb_NO.po | 12 --- po/nl.po | 12 --- po/or.po | 8 -- po/pa.po | 8 -- po/pl.po | 12 --- po/pt_BR.po | 12 --- po/pt_PT.po | 12 --- po/rm.po | 9 -- po/ro.po | 12 --- po/ru.po | 12 --- po/si.po | 12 --- po/sk.po | 10 -- po/sl.po | 12 --- po/sr_RS@cyrillic.po | 11 --- po/sr_RS@latin.po | 12 --- po/sv.po | 12 --- po/ta.po | 10 -- po/te.po | 8 -- po/th.po | 8 -- po/tr.po | 12 --- po/uk.po | 12 --- po/wa.po | 9 -- po/wine.pot | 8 -- po/zh_CN.po | 12 --- po/zh_TW.po | 12 --- 55 files changed, 777 deletions(-) delete mode 100644 dlls/ir50_32/Makefile.in delete mode 100644 dlls/ir50_32/ir50.c delete mode 100644 dlls/ir50_32/ir50_32.rc delete mode 100644 dlls/ir50_32/ir50_32.spec delete mode 100644 dlls/ir50_32/ir50_private.h diff --git a/configure.ac b/configure.ac index 5d3238618ea..91ac8a9485f 100644 --- a/configure.ac +++ b/configure.ac @@ -2709,7 +2709,6 @@ WINE_CONFIG_MAKEFILE(dlls/inseng) WINE_CONFIG_MAKEFILE(dlls/iphlpapi) WINE_CONFIG_MAKEFILE(dlls/iphlpapi/tests) WINE_CONFIG_MAKEFILE(dlls/iprop) -WINE_CONFIG_MAKEFILE(dlls/ir50_32) WINE_CONFIG_MAKEFILE(dlls/irprops.cpl) WINE_CONFIG_MAKEFILE(dlls/itircl) WINE_CONFIG_MAKEFILE(dlls/itss) diff --git a/dlls/ir50_32/Makefile.in b/dlls/ir50_32/Makefile.in deleted file mode 100644 index 7bac0ccc9ca..00000000000 --- a/dlls/ir50_32/Makefile.in +++ /dev/null @@ -1,7 +0,0 @@ -MODULE = ir50_32.dll -IMPORTS = user32 - -C_SRCS = \ - ir50.c - -RC_SRCS = ir50_32.rc diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c deleted file mode 100644 index 3019301742e..00000000000 --- a/dlls/ir50_32/ir50.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Intel Indeo 5 Video Decoder - * Copyright 2023 Shaun Ren 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 - * - */ - -#include -#include -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "commdlg.h" -#include "vfw.h" -#include "ir50_private.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ir50_32); - -static HINSTANCE IR50_32_hModule; - -#define IV50_MAGIC mmioFOURCC('I','V','5','0') - - -static LRESULT -IV50_Open( const ICINFO *icinfo ) -{ - FIXME("DRV_OPEN %p\n", icinfo); - return 0; -} - -static LRESULT -IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) -{ - FIXME("ICM_DECOMPRESS_QUERY %p %p\n", in, out); - return ICERR_UNSUPPORTED; -} - -static LRESULT -IV50_DecompressGetFormat( LPBITMAPINFO in, LPBITMAPINFO out ) -{ - FIXME("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out); - return ICERR_UNSUPPORTED; -} - -static LRESULT IV50_DecompressBegin( IMFTransform *decoder, LPBITMAPINFO in, LPBITMAPINFO out ) -{ - FIXME("ICM_DECOMPRESS_BEGIN %p %p %p\n", decoder, in, out); - return ICERR_UNSUPPORTED; -} - -static LRESULT IV50_Decompress( IMFTransform *decoder, ICDECOMPRESS *icd, DWORD size ) -{ - FIXME("ICM_DECOMPRESS %p %p %lu\n", decoder, icd, size); - return ICERR_UNSUPPORTED; -} - -static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize ) -{ - FIXME("ICM_GETINFO %p %lu\n", icinfo, dwSize); - return ICERR_UNSUPPORTED; -} - -/*********************************************************************** - * DriverProc (IR50_32.@) - */ -LRESULT WINAPI IV50_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg, - LPARAM lParam1, LPARAM lParam2 ) -{ - IMFTransform *decoder = (IMFTransform *) dwDriverId; - LRESULT r = ICERR_UNSUPPORTED; - - TRACE("%Id %p %04x %08Ix %08Ix\n", dwDriverId, hdrvr, msg, lParam1, lParam2); - - switch( msg ) - { - case DRV_LOAD: - TRACE("DRV_LOAD\n"); - r = 1; - break; - - case DRV_OPEN: - r = IV50_Open((ICINFO *)lParam2); - break; - - case DRV_CLOSE: - FIXME("DRV_CLOSE\n"); - break; - - case DRV_ENABLE: - case DRV_DISABLE: - case DRV_FREE: - break; - - case ICM_GETINFO: - r = IV50_GetInfo( (ICINFO *) lParam1, (DWORD) lParam2 ); - break; - - case ICM_DECOMPRESS_QUERY: - r = IV50_DecompressQuery( (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 ); - break; - - case ICM_DECOMPRESS_GET_FORMAT: - r = IV50_DecompressGetFormat( (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 ); - break; - - case ICM_DECOMPRESS_GET_PALETTE: - FIXME("ICM_DECOMPRESS_GET_PALETTE\n"); - break; - - case ICM_DECOMPRESS: - r = IV50_Decompress( decoder, (ICDECOMPRESS *) lParam1, (DWORD) lParam2 ); - break; - - case ICM_DECOMPRESS_BEGIN: - r = IV50_DecompressBegin( decoder, (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 ); - break; - - case ICM_DECOMPRESS_END: - r = ICERR_UNSUPPORTED; - break; - - case ICM_DECOMPRESSEX_QUERY: - FIXME("ICM_DECOMPRESSEX_QUERY\n"); - break; - - case ICM_DECOMPRESSEX: - FIXME("ICM_DECOMPRESSEX\n"); - break; - - case ICM_COMPRESS_QUERY: - r = ICERR_BADFORMAT; - /* fall through */ - case ICM_COMPRESS_GET_FORMAT: - case ICM_COMPRESS_END: - case ICM_COMPRESS: - FIXME("compression not implemented\n"); - break; - - case ICM_CONFIGURE: - break; - - default: - FIXME("Unknown message: %04x %Id %Id\n", msg, lParam1, lParam2); - } - - return r; -} - -/*********************************************************************** - * DllMain - */ -BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved) -{ - TRACE("(%p,%lu,%p)\n", hModule, dwReason, lpReserved); - - switch (dwReason) - { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hModule); - IR50_32_hModule = hModule; - break; - } - return TRUE; -} diff --git a/dlls/ir50_32/ir50_32.rc b/dlls/ir50_32/ir50_32.rc deleted file mode 100644 index fd98f76fbf6..00000000000 --- a/dlls/ir50_32/ir50_32.rc +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2023 Shaun Ren 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 - */ - -#include "ir50_private.h" - -#pragma makedep po - -LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT - -STRINGTABLE -{ - IDS_NAME "Indeo5" - IDS_DESCRIPTION "Indeo Video Interactive version 5 video codec" -} diff --git a/dlls/ir50_32/ir50_32.spec b/dlls/ir50_32/ir50_32.spec deleted file mode 100644 index e5c54ef9c56..00000000000 --- a/dlls/ir50_32/ir50_32.spec +++ /dev/null @@ -1 +0,0 @@ -@ stdcall -private DriverProc(long long long long long) IV50_DriverProc diff --git a/dlls/ir50_32/ir50_private.h b/dlls/ir50_32/ir50_private.h deleted file mode 100644 index c022a8196d2..00000000000 --- a/dlls/ir50_32/ir50_private.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2023 Shaun Ren 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 - */ - -#ifndef __IR50_PRIVATE_H -#define __IR50_PRIVATE_H - -#include - -#define COBJMACROS -#include "mfapi.h" -#include "mferror.h" -#include "mfobjects.h" -#include "mfidl.h" -#include "mftransform.h" - -#define IDS_NAME 100 -#define IDS_DESCRIPTION 101 - -#endif /* __IR50_PRIVATE_H */ diff --git a/po/ar.po b/po/ar.po index a17773e2606..b87d6151a2f 100644 --- a/po/ar.po +++ b/po/ar.po @@ -3732,18 +3732,6 @@ msgstr "زائد" msgid "High" msgstr "عالي" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "الÙهرس" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "ترميز واين المرئي الأول" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "مقابض اللعب" diff --git a/po/ast.po b/po/ast.po index 1e0b2398d23..91d7d256182 100644 --- a/po/ast.po +++ b/po/ast.po @@ -3626,14 +3626,6 @@ msgstr "" msgid "High" msgstr "" -#: dlls/ir50_32/ir50_32.rc:28 -msgid "Indeo5" -msgstr "" - -#: dlls/ir50_32/ir50_32.rc:29 -msgid "Indeo Video Interactive version 5 video codec" -msgstr "" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/bg.po b/po/bg.po index 45450a3c193..47e12a893e8 100644 --- a/po/bg.po +++ b/po/bg.po @@ -3744,16 +3744,6 @@ msgstr "" msgid "High" msgstr "" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -msgid "Indeo5" -msgstr "&Съдържание" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine MS-RLE видео кодек" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/ca.po b/po/ca.po index ee2bcf7b0a0..90ee5673f7a 100644 --- a/po/ca.po +++ b/po/ca.po @@ -3724,18 +3724,6 @@ msgstr "Elevat" msgid "High" msgstr "Alt" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Ãndex" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Còdec de vídeo Wine Video 1" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Palanques de control" diff --git a/po/cs.po b/po/cs.po index 2c4fd0fc2c2..25a4f1b75e3 100644 --- a/po/cs.po +++ b/po/cs.po @@ -3681,18 +3681,6 @@ msgstr "Zvýšená" msgid "High" msgstr "Vysoká" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Rejstřík" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Videokodek Wine Video 1" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Pákové ovladaÄe" diff --git a/po/da.po b/po/da.po index 3180d23849d..c7ee34b8ff9 100644 --- a/po/da.po +++ b/po/da.po @@ -3763,18 +3763,6 @@ msgstr "Øget" msgid "High" msgstr "&Høj" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Indeks" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine Video 1 videokodeks" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/de.po b/po/de.po index 5edd48f2dc2..1ed7acd9d05 100644 --- a/po/de.po +++ b/po/de.po @@ -3714,18 +3714,6 @@ msgstr "Erhöht" msgid "High" msgstr "Hoch" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Index" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine-Video-1-Videocodec" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/el.po b/po/el.po index 9b5f42cae51..c5c8307e2cb 100644 --- a/po/el.po +++ b/po/el.po @@ -3661,14 +3661,6 @@ msgstr "" msgid "High" msgstr "" -#: dlls/ir50_32/ir50_32.rc:28 -msgid "Indeo5" -msgstr "" - -#: dlls/ir50_32/ir50_32.rc:29 -msgid "Indeo Video Interactive version 5 video codec" -msgstr "" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/en.po b/po/en.po index 91419affefd..a9ad0a9cb0a 100644 --- a/po/en.po +++ b/po/en.po @@ -3707,14 +3707,6 @@ msgstr "Increased" msgid "High" msgstr "High" -#: dlls/ir50_32/ir50_32.rc:28 -msgid "Indeo5" -msgstr "Indeo5" - -#: dlls/ir50_32/ir50_32.rc:29 -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Indeo Video Interactive version 5 video codec" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/en_US.po b/po/en_US.po index 34daca1a1bc..ab15878a97b 100644 --- a/po/en_US.po +++ b/po/en_US.po @@ -3707,14 +3707,6 @@ msgstr "Increased" msgid "High" msgstr "High" -#: dlls/ir50_32/ir50_32.rc:28 -msgid "Indeo5" -msgstr "Indeo5" - -#: dlls/ir50_32/ir50_32.rc:29 -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Indeo Video Interactive version 5 video codec" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/eo.po b/po/eo.po index 17d3c9647e4..050cd952e48 100644 --- a/po/eo.po +++ b/po/eo.po @@ -3649,16 +3649,6 @@ msgstr "" msgid "High" msgstr "" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Indekso" - -#: dlls/ir50_32/ir50_32.rc:29 -msgid "Indeo Video Interactive version 5 video codec" -msgstr "" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/es.po b/po/es.po index cde1ed48458..c19a7daabc1 100644 --- a/po/es.po +++ b/po/es.po @@ -3727,18 +3727,6 @@ msgstr "Aumentada" msgid "High" msgstr "Alta" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Ãndice" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Códec de vídeo Wine Video 1" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Comando de juego" diff --git a/po/fa.po b/po/fa.po index b9531707e71..40491717d00 100644 --- a/po/fa.po +++ b/po/fa.po @@ -3692,14 +3692,6 @@ msgstr "" msgid "High" msgstr "" -#: dlls/ir50_32/ir50_32.rc:28 -msgid "Indeo5" -msgstr "" - -#: dlls/ir50_32/ir50_32.rc:29 -msgid "Indeo Video Interactive version 5 video codec" -msgstr "" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/fi.po b/po/fi.po index d22ab0b6029..51f6dc4736e 100644 --- a/po/fi.po +++ b/po/fi.po @@ -3701,18 +3701,6 @@ msgstr "Korotettu" msgid "High" msgstr "Korkea" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Sisällys" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Winen Video 1 -videokoodekki" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joystickit" diff --git a/po/fr.po b/po/fr.po index 8bb0ba73b07..b3d2ea080c0 100644 --- a/po/fr.po +++ b/po/fr.po @@ -3732,18 +3732,6 @@ msgstr "Augmentée" msgid "High" msgstr "Haute" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Index" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Codec vidéo Wine Video 1" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/he.po b/po/he.po index 26d5a2dbb7b..2e716c65960 100644 --- a/po/he.po +++ b/po/he.po @@ -3727,18 +3727,6 @@ msgstr "מוגברת" msgid "High" msgstr "גבוהה" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "מפתח" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "מקודד הוויד×ו Video 1 של Wine" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/hi.po b/po/hi.po index 2bd8f692cc7..08201ec785b 100644 --- a/po/hi.po +++ b/po/hi.po @@ -3625,14 +3625,6 @@ msgstr "" msgid "High" msgstr "" -#: dlls/ir50_32/ir50_32.rc:28 -msgid "Indeo5" -msgstr "" - -#: dlls/ir50_32/ir50_32.rc:29 -msgid "Indeo Video Interactive version 5 video codec" -msgstr "" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/hr.po b/po/hr.po index a801b3f74d5..cab03b4c47b 100644 --- a/po/hr.po +++ b/po/hr.po @@ -3737,18 +3737,6 @@ msgstr "Povećane" msgid "High" msgstr "Visoke" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Indeks" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine Video 1 video codec" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joystici" diff --git a/po/hu.po b/po/hu.po index 88880d8a997..6b70faab001 100644 --- a/po/hu.po +++ b/po/hu.po @@ -3779,18 +3779,6 @@ msgstr "Megnövelt" msgid "High" msgstr "Magas" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "&Témakörök" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine Video 1 video kodek" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/it.po b/po/it.po index ec6b6b19192..d2bf050bd81 100644 --- a/po/it.po +++ b/po/it.po @@ -3787,18 +3787,6 @@ msgstr "Aumentato" msgid "High" msgstr "Alta" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Indice" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Codec Video Wine Video 1" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/ja.po b/po/ja.po index 49f30f5718e..ee177c0aaa8 100644 --- a/po/ja.po +++ b/po/ja.po @@ -3699,18 +3699,6 @@ msgstr "中高" msgid "High" msgstr "高" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "索引" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine ビデオ 1 ビデオコーデック" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "ジョイスティック" diff --git a/po/ko.po b/po/ko.po index e5038887f90..fde0ddc1d3b 100644 --- a/po/ko.po +++ b/po/ko.po @@ -3689,18 +3689,6 @@ msgstr "ì¦ê°€" msgid "High" msgstr "높ìŒ" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "ì¸ë±ìŠ¤" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine 비디오 1 비디오 ì½”ë±" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "ì¡°ì´ìŠ¤í‹±" diff --git a/po/lt.po b/po/lt.po index 217ba5c9628..2fe2909a0d6 100644 --- a/po/lt.po +++ b/po/lt.po @@ -3710,18 +3710,6 @@ msgstr "Padidintos" msgid "High" msgstr "AukÅ¡tos" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Indeksas" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "„Wine“ Video 1 vaizdo kodekas" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "VairasvirtÄ—s" diff --git a/po/ml.po b/po/ml.po index 7a8d207ea34..29b316c025c 100644 --- a/po/ml.po +++ b/po/ml.po @@ -3627,14 +3627,6 @@ msgstr "" msgid "High" msgstr "" -#: dlls/ir50_32/ir50_32.rc:28 -msgid "Indeo5" -msgstr "" - -#: dlls/ir50_32/ir50_32.rc:29 -msgid "Indeo Video Interactive version 5 video codec" -msgstr "" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/nb_NO.po b/po/nb_NO.po index 818e6058644..ec59d534991 100644 --- a/po/nb_NO.po +++ b/po/nb_NO.po @@ -3715,18 +3715,6 @@ msgstr "Økt" msgid "High" msgstr "Høy" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Innhold" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine Video 1 videokodeks" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Styrespaker" diff --git a/po/nl.po b/po/nl.po index b6c00c155c2..b571b48a26b 100644 --- a/po/nl.po +++ b/po/nl.po @@ -3720,18 +3720,6 @@ msgstr "Verhoogd" msgid "High" msgstr "Hoog" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Index" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine Video 1 video codec" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/or.po b/po/or.po index 59e24a848ef..4efb1620ccb 100644 --- a/po/or.po +++ b/po/or.po @@ -3625,14 +3625,6 @@ msgstr "" msgid "High" msgstr "" -#: dlls/ir50_32/ir50_32.rc:28 -msgid "Indeo5" -msgstr "" - -#: dlls/ir50_32/ir50_32.rc:29 -msgid "Indeo Video Interactive version 5 video codec" -msgstr "" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/pa.po b/po/pa.po index 46068d3822f..fb970b7c963 100644 --- a/po/pa.po +++ b/po/pa.po @@ -3625,14 +3625,6 @@ msgstr "" msgid "High" msgstr "" -#: dlls/ir50_32/ir50_32.rc:28 -msgid "Indeo5" -msgstr "" - -#: dlls/ir50_32/ir50_32.rc:29 -msgid "Indeo Video Interactive version 5 video codec" -msgstr "" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/pl.po b/po/pl.po index 49346b2194c..723493afaa2 100644 --- a/po/pl.po +++ b/po/pl.po @@ -3726,18 +3726,6 @@ msgstr "Wysoki" msgid "High" msgstr "Najwyższy" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Indeks" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Kodek Wine Video 1" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticki" diff --git a/po/pt_BR.po b/po/pt_BR.po index dc6fbe28027..d6821db3689 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -3722,18 +3722,6 @@ msgstr "Elevada" msgid "High" msgstr "Alta" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Ãndice" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Codec de vídeo Wine Video 1" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Controles" diff --git a/po/pt_PT.po b/po/pt_PT.po index 3ec661f62ee..833b8b23ade 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -3763,18 +3763,6 @@ msgstr "Aumentada" msgid "High" msgstr "Alta" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Ãndice" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "codec video Wine Video 1" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/rm.po b/po/rm.po index 2573d02eab9..412e3dc6c5e 100644 --- a/po/rm.po +++ b/po/rm.po @@ -3653,15 +3653,6 @@ msgstr "" msgid "High" msgstr "" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -msgid "Indeo5" -msgstr "&Cuntgn�" - -#: dlls/ir50_32/ir50_32.rc:29 -msgid "Indeo Video Interactive version 5 video codec" -msgstr "" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/ro.po b/po/ro.po index dd8b5357230..6c82bb5c603 100644 --- a/po/ro.po +++ b/po/ro.po @@ -3720,18 +3720,6 @@ msgstr "Mărit" msgid "High" msgstr "ÃŽnalt" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Index" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Codecul video Wine Video 1" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joystick-uri" diff --git a/po/ru.po b/po/ru.po index 1d567cabdcb..cb918603b72 100644 --- a/po/ru.po +++ b/po/ru.po @@ -3725,18 +3725,6 @@ msgstr "Повышенный" msgid "High" msgstr "Ð’Ñ‹Ñокий" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Указатель" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Видео кодек Wine Video 1" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "ДжойÑтики" diff --git a/po/si.po b/po/si.po index 444e97e402b..bb39137afd5 100644 --- a/po/si.po +++ b/po/si.po @@ -3652,18 +3652,6 @@ msgstr "" msgid "High" msgstr "à·€à·à¶©à·’" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "දර්à·à¶šà¶º" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine වීඩිය෠1 වීඩිය෠කොඩෙක්" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "නියà·à¶¸à¶š යටි" diff --git a/po/sk.po b/po/sk.po index 35a24b1ac2b..c018db3e215 100644 --- a/po/sk.po +++ b/po/sk.po @@ -3694,16 +3694,6 @@ msgstr "Zvýšené" msgid "High" msgstr "Vysoké" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Obsah" - -#: dlls/ir50_32/ir50_32.rc:29 -msgid "Indeo Video Interactive version 5 video codec" -msgstr "" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/sl.po b/po/sl.po index 45f5433f134..02638b23811 100644 --- a/po/sl.po +++ b/po/sl.po @@ -3781,18 +3781,6 @@ msgstr "PoveÄano" msgid "High" msgstr "Visoka" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Kazalo" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine Video 1 video kodek" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/sr_RS@cyrillic.po b/po/sr_RS@cyrillic.po index a5815e8aab0..63e76fa78f5 100644 --- a/po/sr_RS@cyrillic.po +++ b/po/sr_RS@cyrillic.po @@ -3762,17 +3762,6 @@ msgstr "" msgid "High" msgstr "" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -msgid "Indeo5" -msgstr "&ПопиÑ" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine Video 1 видео кодек" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/sr_RS@latin.po b/po/sr_RS@latin.po index e446f271429..e0977ce9ac3 100644 --- a/po/sr_RS@latin.po +++ b/po/sr_RS@latin.po @@ -3846,18 +3846,6 @@ msgstr "" msgid "High" msgstr "" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Index" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine Video 1 video kodek" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/sv.po b/po/sv.po index 21883ad555f..5f4397962bf 100644 --- a/po/sv.po +++ b/po/sv.po @@ -3742,18 +3742,6 @@ msgstr "Ökad" msgid "High" msgstr "Hög" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Index" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine Video 1 videokodek" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/ta.po b/po/ta.po index 50289ad45c3..2d1c803e1ad 100644 --- a/po/ta.po +++ b/po/ta.po @@ -3589,16 +3589,6 @@ msgstr "" msgid "High" msgstr "" -#: dlls/ir50_32/ir50_32.rc:28 -msgid "Indeo5" -msgstr "" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine வீடியோ 1 வீடியோ கோடெகà¯" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/te.po b/po/te.po index 7dafde4a546..c0c7e8116a0 100644 --- a/po/te.po +++ b/po/te.po @@ -3625,14 +3625,6 @@ msgstr "" msgid "High" msgstr "" -#: dlls/ir50_32/ir50_32.rc:28 -msgid "Indeo5" -msgstr "" - -#: dlls/ir50_32/ir50_32.rc:29 -msgid "Indeo Video Interactive version 5 video codec" -msgstr "" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/th.po b/po/th.po index 29af5b4a434..8f563d508b7 100644 --- a/po/th.po +++ b/po/th.po @@ -3680,14 +3680,6 @@ msgstr "" msgid "High" msgstr "" -#: dlls/ir50_32/ir50_32.rc:28 -msgid "Indeo5" -msgstr "" - -#: dlls/ir50_32/ir50_32.rc:29 -msgid "Indeo Video Interactive version 5 video codec" -msgstr "" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/tr.po b/po/tr.po index d2ecc1b0fc2..28cee4524cd 100644 --- a/po/tr.po +++ b/po/tr.po @@ -3716,18 +3716,6 @@ msgstr "Arttırılmış" msgid "High" msgstr "Yüksek" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "İçindekiler" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine Video 1 video çözücü" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Oyun Kolları" diff --git a/po/uk.po b/po/uk.po index cf0ceb06649..2d941b5248f 100644 --- a/po/uk.po +++ b/po/uk.po @@ -3713,18 +3713,6 @@ msgstr "Збільшені" msgid "High" msgstr "ВиÑокі" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "Вказівник" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Відео кодек Wine Video 1" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "ДжойÑтик" diff --git a/po/wa.po b/po/wa.po index fcbcf228e00..13d79d4eeca 100644 --- a/po/wa.po +++ b/po/wa.po @@ -3688,15 +3688,6 @@ msgstr "" msgid "High" msgstr "" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -msgid "Indeo5" -msgstr "Ã…&dvins" - -#: dlls/ir50_32/ir50_32.rc:29 -msgid "Indeo Video Interactive version 5 video codec" -msgstr "" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/wine.pot b/po/wine.pot index 21654586e88..881b048e33b 100644 --- a/po/wine.pot +++ b/po/wine.pot @@ -3580,14 +3580,6 @@ msgstr "" msgid "High" msgstr "" -#: dlls/ir50_32/ir50_32.rc:28 -msgid "Indeo5" -msgstr "" - -#: dlls/ir50_32/ir50_32.rc:29 -msgid "Indeo Video Interactive version 5 video codec" -msgstr "" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/zh_CN.po b/po/zh_CN.po index 6f1772bd3c4..f226c3b1ced 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -3657,18 +3657,6 @@ msgstr "较高" msgid "High" msgstr "高" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "索引" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine Video 1 视频编解ç å™¨" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "æ“纵æ†" diff --git a/po/zh_TW.po b/po/zh_TW.po index f29c109df08..2a93c59445a 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -3663,18 +3663,6 @@ msgstr "ç¨é«˜" msgid "High" msgstr "高" -#: dlls/ir50_32/ir50_32.rc:28 -#, fuzzy -#| msgid "Index" -msgid "Indeo5" -msgstr "索引" - -#: dlls/ir50_32/ir50_32.rc:29 -#, fuzzy -#| msgid "Wine Video 1 video codec" -msgid "Indeo Video Interactive version 5 video codec" -msgstr "Wine 視訊 1 視訊編碼解碼器" - #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "æ–æ¡¿" From 04e12e326b1585adef047d3c3f23d2e1d3a49e71 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 10 Jul 2023 14:09:22 -0600 Subject: [PATCH 1461/2777] include: Add initial ioring definitions. (cherry picked from commit 27fc318161cad21d08c3ee71dc8248d3dae1eae8) CW-Bug-Id: #22414 --- include/Makefile.in | 2 ++ include/ioringapi.h | 42 ++++++++++++++++++++++++++++++++++++++++++ include/ntioring_x.h | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 include/ioringapi.h create mode 100644 include/ntioring_x.h diff --git a/include/Makefile.in b/include/Makefile.in index 71b2ad01ab8..e9498404086 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -371,6 +371,7 @@ SOURCES = \ inspectable.idl \ interactioncontext.h \ intshcut.h \ + ioringapi.h \ ip2string.h \ ipexport.h \ iphlpapi.h \ @@ -570,6 +571,7 @@ SOURCES = \ ntdef.h \ ntdsapi.h \ ntgdi.h \ + ntioring_x.h \ ntlsa.h \ ntquery.h \ ntsecapi.h \ diff --git a/include/ioringapi.h b/include/ioringapi.h new file mode 100644 index 00000000000..3ccbfc80654 --- /dev/null +++ b/include/ioringapi.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2023 Paul Gofman 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 + */ + +#ifndef __IORINGAPI_H_ +#define __IORINGAPI_H_ + +#include + +struct IORING_CAPABILITIES +{ + IORING_VERSION MaxVersion; + UINT32 MaxSubmissionQueueSize; + UINT32 MaxCompletionQueueSize; + IORING_FEATURE_FLAGS FeatureFlags; +}; +typedef struct IORING_CAPABILITIES IORING_CAPABILITIES; + +#ifdef __cplusplus +extern "C" { +#endif + +HRESULT WINAPI QueryIoRingCapabilities(IORING_CAPABILITIES *caps); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/ntioring_x.h b/include/ntioring_x.h new file mode 100644 index 00000000000..bf16d9368d4 --- /dev/null +++ b/include/ntioring_x.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2023 Paul Gofman 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 + */ + +#ifndef __NTIORING_X_H_ +#define __NTIORING_X_H_ + +enum IORING_VERSION +{ + IORING_VERSION_INVALID = 0, + IORING_VERSION_1 = 1, + IORING_VERSION_2 = 2, + IORING_VERSION_3 = 300, +}; +typedef enum IORING_VERSION IORING_VERSION; + +enum IORING_FEATURE_FLAGS +{ + IORING_FEATURE_FLAGS_NONE = 0, + IORING_FEATURE_UM_EMULATION = 0x00000001, + IORING_FEATURE_SET_COMPLETION_EVENT = 0x00000002, +}; +typedef enum IORING_FEATURE_FLAGS IORING_FEATURE_FLAGS; + +#endif From 8a8ec5f86d8ab1e1d4c6bc88dda016b5e8cf479e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 10 Jul 2023 14:20:40 -0600 Subject: [PATCH 1462/2777] kernelbase: Add stub for QueryIoRingCapabilities(). (cherry picked from commit 4021dde40d6ac7fa80074039906b54ebdd509550) CW-Bug-Id: #22414 --- dlls/kernelbase/file.c | 12 +++++++ dlls/kernelbase/kernelbase.spec | 1 + dlls/kernelbase/tests/Makefile.in | 1 + dlls/kernelbase/tests/file.c | 57 +++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 dlls/kernelbase/tests/file.c diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c index ac04388acde..0088bc8747b 100644 --- a/dlls/kernelbase/file.c +++ b/dlls/kernelbase/file.c @@ -38,6 +38,7 @@ #include "shlwapi.h" #include "ddk/ntddk.h" #include "ddk/ntddser.h" +#include "ioringapi.h" #include "kernelbase.h" #include "wine/exception.h" @@ -4475,3 +4476,14 @@ BOOL WINAPI DECLSPEC_HOTPATCH WaitCommEvent( HANDLE handle, DWORD *events, OVERL return DeviceIoControl( handle, IOCTL_SERIAL_WAIT_ON_MASK, NULL, 0, events, sizeof(*events), NULL, overlapped ); } + + +/*********************************************************************** + * QueryIoRingCapabilities (kernelbase.@) + */ +HRESULT WINAPI QueryIoRingCapabilities(IORING_CAPABILITIES *caps) +{ + FIXME( "caps %p stub.\n", caps ); + + return E_NOTIMPL; +} diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index fc687efb913..c14f2a87472 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -1233,6 +1233,7 @@ @ stdcall QueryDosDeviceW(wstr ptr long) @ stdcall QueryFullProcessImageNameA(ptr long ptr ptr) @ stdcall QueryFullProcessImageNameW(ptr long ptr ptr) +@ stdcall QueryIoRingCapabilities(ptr) # @ stub QueryIdleProcessorCycleTime # @ stub QueryIdleProcessorCycleTimeEx # @ stub QueryInterruptTime diff --git a/dlls/kernelbase/tests/Makefile.in b/dlls/kernelbase/tests/Makefile.in index 675054c753d..b51eaefcd13 100644 --- a/dlls/kernelbase/tests/Makefile.in +++ b/dlls/kernelbase/tests/Makefile.in @@ -1,6 +1,7 @@ TESTDLL = kernelbase.dll C_SRCS = \ + file.c \ path.c \ process.c \ sync.c diff --git a/dlls/kernelbase/tests/file.c b/dlls/kernelbase/tests/file.c new file mode 100644 index 00000000000..18dff0a32ab --- /dev/null +++ b/dlls/kernelbase/tests/file.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2023 Paul Gofman 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 + */ + +#include +#include + +#include +#define WIN32_NO_STATUS +#include +#include +#include +#include + +#include "wine/test.h" + +static HRESULT (WINAPI *pQueryIoRingCapabilities)(IORING_CAPABILITIES *); + +static void test_ioring_caps(void) +{ + IORING_CAPABILITIES caps; + HRESULT hr; + + if (!pQueryIoRingCapabilities) + { + win_skip("QueryIoRingCapabilities is not available, skipping tests.\n"); + return; + } + + memset(&caps, 0xcc, sizeof(caps)); + hr = pQueryIoRingCapabilities(&caps); + todo_wine ok(hr == S_OK, "got %#lx.\n", hr); +} + +START_TEST(file) +{ + HMODULE hmod; + + hmod = LoadLibraryA("kernelbase.dll"); + pQueryIoRingCapabilities = (void *)GetProcAddress(hmod, "QueryIoRingCapabilities"); + + test_ioring_caps(); +} From d41736dd4ed3a5e46d9963f961d50e4b294782da Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Sun, 28 May 2023 21:14:47 +0800 Subject: [PATCH 1463/2777] fixup! HACK: winex11.drv: Workaround focusing out of exclusive fullscreen windows. XFCE doesn't make fullscreen (without above) windows appear above their panels. However, 21636959 disables NET_WM_STATE_ABOVE for all window managers when NET_WM_STATE_FULLSCREEN is set. CW-Bug-Id: #22269 --- dlls/winex11.drv/window.c | 12 +++++++++++- include/wine/gdi_driver.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index b7cc69532a7..36bc1d58302 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -170,6 +170,8 @@ static int detect_wm(Display *dpy) cached = WINE_WM_X11_STEAMCOMPMGR; else if(strcmp(wm_name, "KWin") == 0) cached = WINE_WM_X11_KDE; + else if(strcmp(wm_name, "Xfwm4") == 0 || strcmp(wm_name, "xfwm4") == 0) + cached = WINE_WM_X11_XFCE4; else cached = WINE_WM_UNKNOWN; @@ -206,6 +208,11 @@ BOOL wm_is_kde(Display *display) return detect_wm(display) == WINE_WM_X11_KDE; } +BOOL wm_is_xfce4(Display *display) +{ + return detect_wm(display) == WINE_WM_X11_XFCE4; +} + BOOL wm_is_steamcompmgr(Display *display) { return detect_wm(display) == WINE_WM_X11_STEAMCOMPMGR; @@ -1280,9 +1287,12 @@ void update_net_wm_states( struct x11drv_win_data *data ) * Many games do not have any specific logic to get out of exclusive fullscreen * mode, and we have currently no way to tell exclusive fullscreen from a window * with topmost + fullscreen styles, so we cannot properly implement it either. + * + * XFCE doesn't make fullscreen (without above) windows appear above their panels. */ - !(new_state & (1 << NET_WM_STATE_FULLSCREEN))) + (wm_is_xfce4(data->display) || !(new_state & (1 << NET_WM_STATE_FULLSCREEN)))) new_state |= (1 << NET_WM_STATE_ABOVE); + if (!data->add_taskbar) { if (data->skip_taskbar || (ex_style & WS_EX_NOACTIVATE) diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 96bedd7acab..f556da495e9 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -347,6 +347,7 @@ extern void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT #define WINE_WM_X11_MUTTER 1 #define WINE_WM_X11_STEAMCOMPMGR 2 #define WINE_WM_X11_KDE 3 +#define WINE_WM_X11_XFCE4 4 static inline LONG_PTR __wine_get_window_manager(void) { From d1bc7147a0487044ac3082cb99db9f57e3ec80d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 25 May 2023 23:49:31 +0200 Subject: [PATCH 1464/2777] evr/tests: Test IMFVideoDisplayControl_GetCurrentImage orientation. (cherry picked from commit df91b31428ab22fe26c82729d80ef064b5bc8dfc) CW-Bug-Id: #21316 --- dlls/evr/tests/Makefile.in | 2 + dlls/evr/tests/evr.c | 269 ++++++++++++++++++++++++++++- dlls/evr/tests/nv12frame.bmp | Bin 0 -> 50742 bytes dlls/evr/tests/resource.rc | 33 ++++ dlls/evr/tests/rgb32frame-flip.bmp | Bin 0 -> 36918 bytes dlls/evr/tests/rgb32frame.bmp | Bin 0 -> 36918 bytes 6 files changed, 299 insertions(+), 5 deletions(-) create mode 100644 dlls/evr/tests/nv12frame.bmp create mode 100644 dlls/evr/tests/resource.rc create mode 100644 dlls/evr/tests/rgb32frame-flip.bmp create mode 100644 dlls/evr/tests/rgb32frame.bmp diff --git a/dlls/evr/tests/Makefile.in b/dlls/evr/tests/Makefile.in index c5db2226ebc..6b89635225a 100644 --- a/dlls/evr/tests/Makefile.in +++ b/dlls/evr/tests/Makefile.in @@ -3,3 +3,5 @@ IMPORTS = dxva2 mfplat mfuuid mf strmiids uuid dxguid ole32 oleaut32 evr d3d9 C_SRCS = \ evr.c + +RC_SRCS = resource.rc diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index 4f30dd28570..5147896a9b6 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -31,6 +31,95 @@ static const WCHAR sink_id[] = L"EVR Input0"; +static void load_resource(const WCHAR *filename, const BYTE **data, DWORD *length) +{ + HRSRC resource = FindResourceW(NULL, filename, (const WCHAR *)RT_RCDATA); + ok(resource != 0, "FindResourceW failed, error %lu\n", GetLastError()); + *data = LockResource(LoadResource(GetModuleHandleW(NULL), resource)); + *length = SizeofResource(GetModuleHandleW(NULL), resource); +} + +static DWORD compare_rgb32(const BYTE *data, DWORD *length, const RECT *rect, const BYTE *expect) +{ + DWORD x, y, size, diff = 0, width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf; + + /* skip BMP header from the dump */ + size = *(DWORD *)(expect + 2 + 2 * sizeof(DWORD)); + *length = *length + size; + expect = expect + size; + + for (y = 0; y < height; y++, data += width * 4, expect += width * 4) + { + if (y < rect->top || y >= rect->bottom) continue; + for (x = 0; x < width; x++) + { + if (x < rect->left || x >= rect->right) continue; + diff += abs((int)expect[4 * x + 0] - (int)data[4 * x + 0]); + diff += abs((int)expect[4 * x + 1] - (int)data[4 * x + 1]); + diff += abs((int)expect[4 * x + 2] - (int)data[4 * x + 2]); + } + } + + size = (rect->right - rect->left) * (rect->bottom - rect->top) * 3; + return diff * 100 / 256 / size; +} + +static void dump_rgb32(const BYTE *data, DWORD length, const RECT *rect, HANDLE output) +{ + DWORD width = (rect->right + 0xf) & ~0xf, height = (rect->bottom + 0xf) & ~0xf; + static const char magic[2] = "BM"; + struct + { + DWORD length; + DWORD reserved; + DWORD offset; + BITMAPINFOHEADER biHeader; + } header = + { + .length = length + sizeof(header) + 2, .offset = sizeof(header) + 2, + .biHeader = + { + .biSize = sizeof(BITMAPINFOHEADER), .biWidth = width, .biHeight = height, .biPlanes = 1, + .biBitCount = 32, .biCompression = BI_RGB, .biSizeImage = width * height * 4, + }, + }; + DWORD written; + BOOL ret; + + ret = WriteFile(output, magic, sizeof(magic), &written, NULL); + ok(ret, "WriteFile failed, error %lu\n", GetLastError()); + ok(written == sizeof(magic), "written %lu bytes\n", written); + ret = WriteFile(output, &header, sizeof(header), &written, NULL); + ok(ret, "WriteFile failed, error %lu\n", GetLastError()); + ok(written == sizeof(header), "written %lu bytes\n", written); + ret = WriteFile(output, data, length, &written, NULL); + ok(ret, "WriteFile failed, error %lu\n", GetLastError()); + ok(written == length, "written %lu bytes\n", written); +} + +#define check_rgb32_data(a, b, c, d) check_rgb32_data_(__LINE__, a, b, c, d) +static DWORD check_rgb32_data_(int line, const WCHAR *filename, const BYTE *data, DWORD length, const RECT *rect) +{ + WCHAR output_path[MAX_PATH]; + const BYTE *expect_data; + HRSRC resource; + HANDLE output; + + GetTempPathW(ARRAY_SIZE(output_path), output_path); + lstrcatW(output_path, filename); + output = CreateFileW(output_path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(output != INVALID_HANDLE_VALUE, "CreateFileW failed, error %lu\n", GetLastError()); + dump_rgb32(data, length, rect, output); + trace("created %s\n", debugstr_w(output_path)); + CloseHandle(output); + + resource = FindResourceW(NULL, filename, (const WCHAR *)RT_RCDATA); + ok(resource != 0, "FindResourceW failed, error %lu\n", GetLastError()); + expect_data = LockResource(LoadResource(GetModuleHandleW(NULL), resource)); + + return compare_rgb32(data, &length, rect, expect_data); +} + static void set_rect(MFVideoNormalizedRect *rect, float left, float top, float right, float bottom) { rect->left = left; @@ -2913,8 +3002,8 @@ static void test_mixer_zorder(void) IMFTransform_Release(mixer); } -static IDirect3DSurface9 * create_surface(IDirect3DDeviceManager9 *manager, unsigned int width, - unsigned int height) +static IDirect3DSurface9 * create_surface(IDirect3DDeviceManager9 *manager, UINT fourcc, + unsigned int width, unsigned int height) { IDirectXVideoAccelerationService *service; IDirect3DSurface9 *surface = NULL; @@ -2932,7 +3021,7 @@ static IDirect3DSurface9 * create_surface(IDirect3DDeviceManager9 *manager, unsi (void **)&service); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IDirectXVideoAccelerationService_CreateSurface(service, width, height, 0, D3DFMT_A8R8G8B8, + hr = IDirectXVideoAccelerationService_CreateSurface(service, width, height, 0, fourcc, D3DPOOL_DEFAULT, 0, DXVA2_VideoProcessorRenderTarget, &surface, NULL); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -3081,7 +3170,7 @@ static void test_mixer_samples(void) IMFSample_Release(sample); - surface = create_surface(manager, 64, 64); + surface = create_surface(manager, D3DFMT_A8R8G8B8, 64, 64); hr = MFCreateVideoSampleFromSurface((IUnknown *)surface, &sample); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -3230,6 +3319,174 @@ static void test_mixer_samples(void) DestroyWindow(window); } +static void test_presenter_orientation(const GUID *subtype) +{ + IMFTopologyServiceLookupClient *lookup_client; + static const BITMAPINFOHEADER expect_header = + { + .biSize = sizeof(BITMAPINFOHEADER), + .biWidth = 96, .biHeight = 96, + .biPlanes = 1, .biBitCount = 32, + .biCompression = BI_RGB, + .biSizeImage = 96 * 96 * 4, + }; + BITMAPINFOHEADER header = {.biSize = sizeof(BITMAPINFOHEADER)}; + IMFVideoDisplayControl *display_control; + DWORD diff, data_size, frame_data_len; + IDirect3DDeviceManager9 *manager; + D3DLOCKED_RECT d3d_rect = {0}; + IMFVideoPresenter *presenter; + IDirect3DSurface9 *surface; + IMFMediaType *video_type; + const BYTE *frame_data; + struct test_host host; + IMFTransform *mixer; + LONGLONG timestamp; + IMFSample *sample; + LONG stride; + HWND window; + BYTE *data; + HRESULT hr; + RECT rect; + + window = create_window(); + + hr = MFCreateVideoMixer(NULL, &IID_IDirect3DDevice9, &IID_IMFTransform, (void **)&mixer); + ok(hr == S_OK, "Failed to create a mixer, hr %#lx.\n", hr); + hr = MFCreateVideoPresenter(NULL, &IID_IDirect3DDevice9, &IID_IMFVideoPresenter, (void **)&presenter); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + init_test_host(&host, mixer, presenter); + hr = IMFVideoPresenter_QueryInterface(presenter, &IID_IMFTopologyServiceLookupClient, (void **)&lookup_client); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyServiceLookupClient_InitServicePointers(lookup_client, &host.IMFTopologyServiceLookup_iface); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFTopologyServiceLookupClient_Release(lookup_client); + + /* Configure device and media types. */ + + hr = MFGetService((IUnknown *)presenter, &MR_VIDEO_ACCELERATION_SERVICE, &IID_IDirect3DDeviceManager9, (void **)&manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_ProcessMessage(mixer, MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR)manager); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IDirect3DDeviceManager9_Release(manager); + + video_type = create_video_type(subtype); + hr = IMFMediaType_SetUINT64(video_type, &MF_MT_FRAME_SIZE, (UINT64)expect_header.biWidth << 32 | expect_header.biHeight); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFMediaType_SetUINT32(video_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFTransform_SetInputType(mixer, 0, video_type, 0); + if (broken(IsEqualGUID(subtype, &MFVideoFormat_NV12) && hr == E_FAIL)) + { + win_skip("Skipping unsupported NV12 format\n"); + IMFMediaType_Release(video_type); + goto skip_tests; + } + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTransform_SetOutputType(mixer, 0, video_type, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFMediaType_Release(video_type); + + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_INVALIDATEMEDIATYPE, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_BEGINSTREAMING, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + if (IsEqualGUID(subtype, &MFVideoFormat_NV12)) + { + load_resource(L"nv12frame.bmp", &frame_data, &frame_data_len); + /* skip BMP header and RGB data from the dump */ + data_size = *(DWORD *)(frame_data + 2); + frame_data_len = frame_data_len - data_size; + frame_data = frame_data + data_size; + ok(frame_data_len == 13824, "got length %lu\n", frame_data_len); + } + else + { + load_resource(L"rgb32frame.bmp", &frame_data, &frame_data_len); + /* skip BMP header from the dump */ + data_size = *(DWORD *)(frame_data + 2 + 2 * sizeof(DWORD)); + frame_data_len -= data_size; + frame_data += data_size; + ok(frame_data_len == 36864, "got length %lu\n", frame_data_len); + } + + surface = create_surface(manager, subtype->Data1, expect_header.biWidth, expect_header.biHeight); + ok(!!surface, "Failed to create input surface.\n"); + hr = IDirect3DSurface9_LockRect(surface, &d3d_rect, NULL, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (IsEqualGUID(subtype, &MFVideoFormat_RGB32)) + memcpy(d3d_rect.pBits, frame_data, frame_data_len); + else if (IsEqualGUID(subtype, &MFVideoFormat_NV12)) + { + hr = MFGetStrideForBitmapInfoHeader(subtype->Data1, expect_header.biWidth, &stride); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFCopyImage(d3d_rect.pBits, d3d_rect.Pitch, frame_data, stride, expect_header.biWidth, expect_header.biHeight); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + frame_data += stride * expect_header.biHeight; + d3d_rect.pBits = (BYTE *)d3d_rect.pBits + d3d_rect.Pitch * expect_header.biHeight; + hr = MFCopyImage(d3d_rect.pBits, d3d_rect.Pitch, frame_data, stride, expect_header.biWidth, expect_header.biHeight / 2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } + hr = IDirect3DSurface9_UnlockRect(surface); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFCreateVideoSampleFromSurface((IUnknown *)surface, &sample); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IDirect3DSurface9_Release(surface); + + hr = IMFTransform_ProcessInput(mixer, 0, sample, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_PROCESSINPUTNOTIFY, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFSample_Release(sample); + + hr = IMFVideoPresenter_QueryInterface(presenter, &IID_IMFVideoDisplayControl, (void **)&display_control); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFVideoDisplayControl_GetCurrentImage(display_control, &header, &data, &data_size, ×tamp); + if (hr == MF_E_INVALIDREQUEST) + { + Sleep(500); + hr = IMFVideoDisplayControl_GetCurrentImage(display_control, &header, &data, &data_size, ×tamp); + } + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFVideoDisplayControl_Release(display_control); + + ok(header.biSize == expect_header.biSize, "Unexpected biSize %#lx\n", header.biSize); + ok(header.biWidth == expect_header.biWidth, "Unexpected biWidth %#lx\n", header.biWidth); + ok(header.biHeight == expect_header.biHeight, "Unexpected biHeight %#lx\n", header.biHeight); + ok(header.biPlanes == expect_header.biPlanes, "Unexpected biPlanes %#x\n", header.biPlanes); + ok(header.biBitCount == expect_header.biBitCount, "Unexpected biBitCount %#x\n", header.biBitCount); + ok(header.biCompression == expect_header.biCompression, "Unexpected biCompression %#lx\n", header.biCompression); + ok(header.biSizeImage == expect_header.biSizeImage, "Unexpected biSizeImage %#lx\n", header.biSizeImage); + ok(header.biXPelsPerMeter == expect_header.biXPelsPerMeter, "Unexpected biXPelsPerMeter %#lx\n", header.biXPelsPerMeter); + ok(header.biYPelsPerMeter == expect_header.biYPelsPerMeter, "Unexpected biYPelsPerMeter %#lx\n", header.biYPelsPerMeter); + ok(header.biClrUsed == expect_header.biClrUsed, "Unexpected biClrUsed %#lx\n", header.biClrUsed); + ok(header.biClrImportant == expect_header.biClrImportant, "Unexpected biClrImportant %#lx\n", header.biClrImportant); + + SetRect(&rect, 0, 0, header.biWidth, header.biHeight); + diff = check_rgb32_data(L"rgb32frame-flip.bmp", data, header.biSizeImage, &rect); + todo_wine + ok(diff <= 3, "Unexpected %lu%% diff\n", diff); + CoTaskMemFree(data); + + hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_ENDSTREAMING, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + +skip_tests: + hr = IMFVideoPresenter_QueryInterface(presenter, &IID_IMFTopologyServiceLookupClient, (void **)&lookup_client); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMFTopologyServiceLookupClient_ReleaseServicePointers(lookup_client); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFTopologyServiceLookupClient_Release(lookup_client); + + IMFTransform_Release(mixer); + IMFVideoPresenter_Release(presenter); + + DestroyWindow(window); +} + static void test_MFIsFormatYUV(void) { static const DWORD formats[] = @@ -3333,7 +3590,7 @@ static void test_mixer_render(void) IMFMediaType_Release(output_type); IMFMediaType_Release(video_type); - surface = create_surface(manager, 64, 64); + surface = create_surface(manager, D3DFMT_A8R8G8B8, 64, 64); ok(!!surface, "Failed to create input surface.\n"); hr = MFCreateVideoSampleFromSurface((IUnknown *)surface, &sample); @@ -3422,6 +3679,8 @@ START_TEST(evr) test_presenter_video_window(); test_presenter_quality_control(); test_presenter_media_type(); + test_presenter_orientation(&MFVideoFormat_NV12); + test_presenter_orientation(&MFVideoFormat_RGB32); test_presenter_shutdown(); test_mixer_output_rectangle(); test_mixer_zorder(); diff --git a/dlls/evr/tests/nv12frame.bmp b/dlls/evr/tests/nv12frame.bmp new file mode 100644 index 0000000000000000000000000000000000000000..f37bdfc4062ef20d0f017e43147767708c51c09b GIT binary patch literal 50742 zcmeI5v5g`@5JmSgm=IQ2M*f+qAykKQEu3&%9U(Vggsb`@2 z5BqxdGeh`$II2FvAO5O48S3yK|1)^3&Vc{;uey_=4*&5#gU9L&_`gj5kNs-o)H6{1 zhkZT!nIZf=9919T4}aC240ZUA{~0`1XTX2_SKY}_hyVDW!DDp>{9mU3yX#}*)H6{1 zhkZT!nIZf=9919T4}aC240ZUA{~0`1XTX2_SKY}_hyVDW!DDp>{9mU3o9!@i>KUm1 z!@i#V%n<$_j;fFFhrjAhhC2Mm{|p|hGvGh|tL|i|!+-qG;ITRb{x8%2^{^i~^$b-1 zVPDUFW(a=|N7YC8!(VkLLmmF(e+G}$8So$fRd+Jf;XnRo@K~Jz|Ci~%`gfyF`+x6n zgBuRu01n^)4&VR|-~bNb01n^)4&Xp*2cGsdP4I2m?< zEuXu6mHpe}@8ri!;RBzTK>XU)pNoB!{oCU&XU)pS69J{oCW$ zr=RSz(f)5W68H|H{$I2s@Et_`AFfXYzJsX$%dLsP zcM$b2eb)=&z;%HCZX3cs{@u@T=6U+3|IGcmYo~wucN@w)AMJmvPl4|s>VH>rf$t#d z|81=Zd3Zqp8n}S zbHDD|qy4MY%OAjYfd6hg!ax4|ypPd8{nP*Qzt_=cXKfxk`w#n1n>}TFE&9*d|M^S; z-$Ath{d(CR_zt4}-^-f7cM$deTs8&1gQ)*f&wWA*4z8E~?)Ceg;lG{!@ZXNdXpi{E zf3%%dn4^FCUxkjN$3Xun`@j1b34909?_aNr9f9v4>i?)r1-^r*|En?)_zt4}Rq6?7 zupQvP+m7&$|32?y^iTivzx@AT`s}RDV`u-#x&Ms6>TlnG?I7C!-eNBB9Yp=V)r%j% zcM$deRQ-eRAnLzq8iDTs|Gq<~L;U04=_mUv{nLN;hMo1(Km9xXWS^yf`p@35v;JuR EKX0Xo-v9sr literal 0 HcmV?d00001 diff --git a/dlls/evr/tests/rgb32frame.bmp b/dlls/evr/tests/rgb32frame.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9f2ea1e5d1b2b808f3671b09c19ed6fcd090de85 GIT binary patch literal 36918 zcmeI*u}Yg^9EI^Cp-Y{_DXoJ;gGccke(i!PP-=^b)K~Zl@ik*$ag_DEVIB zs5js_AC!Oc1db^3!j~V9MuH??za3ub`F7Ype(pPd-In(IXZ`m2{g*FZJ`TemmK(IQ zCTG~^_A5ijesu(H@#ALzek|36w2%MINA@47$B z4P5_^j}KzGf$Kl}_g5@8aQ)SmVz~kSxna^F{`e>TR6k4q^k2Q<*nvxc=YoC6*hw{_2lG zEH}VEH%vOjAOEDE>SyVn{;M~fTtEHOf6`C&v-D5@)f-N(-|c^?K`b}GKQ~M|#2^2p zpXz7npZ=>ioLoQs(|^)W^|SO(|J55#uHWtd=6w^(4P5`bNq_Ad78|(!AM_xW8@T>6 z_1C^(v4QKa{_H2q4e-wmlMeC6Kk29XS^B5{>J2B?Pyh6v^i%z;+yBYVTr4+m{Xe~1 zh~);Z|4&WDas$`@LPuh`f$KkPNh~+OKQ~M|#2^2ppXz7npZ=>ioLoQs(|^)W^|NmO z3w;sG4P5_w?TY0Fu75l4?_17tgEQ~_-`jOR$8rPLpL1`2%|gsDqX8PA0UDqI8lV9h MpaB}7fpQHz0TpqG-v9sr literal 0 HcmV?d00001 From 75558a83dd320d124dcbb0b5ac1489b85fafa2c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 26 May 2023 11:13:49 +0200 Subject: [PATCH 1465/2777] evr: Respect RGB format stride in GetCurrentImage. (cherry picked from commit 486531ca8a8d0dc3aff2804c574928a37c96664c) CW-Bug-Id: #21316 --- dlls/evr/presenter.c | 3 ++- dlls/evr/tests/evr.c | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index d8bdbee3915..06592f8766e 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -1531,7 +1531,8 @@ static HRESULT WINAPI video_presenter_control_GetCurrentImage(IMFVideoDisplayCon { if (SUCCEEDED(hr = IDirect3DSurface9_LockRect(readback, &mapped_rect, NULL, D3DLOCK_READONLY))) { - memcpy(*dib, mapped_rect.pBits, *dib_size); + hr = MFCopyImage(stride < 0 ? *dib + *dib_size + stride : *dib, stride, + mapped_rect.pBits, mapped_rect.Pitch, abs(stride), surface_desc.Height); IDirect3DSurface9_UnlockRect(readback); } } diff --git a/dlls/evr/tests/evr.c b/dlls/evr/tests/evr.c index 5147896a9b6..c01257e0d34 100644 --- a/dlls/evr/tests/evr.c +++ b/dlls/evr/tests/evr.c @@ -3467,8 +3467,7 @@ static void test_presenter_orientation(const GUID *subtype) SetRect(&rect, 0, 0, header.biWidth, header.biHeight); diff = check_rgb32_data(L"rgb32frame-flip.bmp", data, header.biSizeImage, &rect); - todo_wine - ok(diff <= 3, "Unexpected %lu%% diff\n", diff); + ok(diff <= 5, "Unexpected %lu%% diff\n", diff); CoTaskMemFree(data); hr = IMFVideoPresenter_ProcessMessage(presenter, MFVP_MESSAGE_ENDSTREAMING, 0); From 818634e8bf41ac05cb30f8c8f1644643295a2252 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Fri, 9 Jun 2023 15:12:31 +0800 Subject: [PATCH 1466/2777] fsync: Type-check HANDLE in fsync_reset_event(). Oddworld: Stranger's Wrath HD (15750) calls ResetEvent() on a file handle and then waits for the handle with an infinite timeout. Without esync/fsync, NtResetEvent() should return STATUS_OBJECT_TYPE_MISMATCH because the handle is not an event handle. With esync/fsync, the file handle is set to non-signaled successfully and causes the game to hang at start-up. The same check should also apply to fsync_pulse_event(), esync_reset_event(), and esync_pulse_event(). CW-Bug-Id: #22326 --- dlls/ntdll/unix/fsync.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index ac280a81fe6..73b7fd9bda1 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -715,6 +715,12 @@ NTSTATUS fsync_reset_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) + { + put_object( &obj ); + return STATUS_OBJECT_TYPE_MISMATCH; + } + current = __atomic_exchange_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); if (prev) *prev = current; From 6147ae76c6bea229940bec016f9a7a48d74f6c8e Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Fri, 9 Jun 2023 15:13:12 +0800 Subject: [PATCH 1467/2777] fsync: Type-check HANDLE in fsync_pulse_event(). CW-Bug-Id: #22326 --- dlls/ntdll/unix/fsync.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 73b7fd9bda1..c265d6c02e0 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -741,6 +741,12 @@ NTSTATUS fsync_pulse_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) + { + put_object( &obj ); + return STATUS_OBJECT_TYPE_MISMATCH; + } + /* This isn't really correct; an application could miss the write. * Unfortunately we can't really do much better. Fortunately this is rarely * used (and publicly deprecated). */ From b409cbfbe5433e1a5730adf5591e550efee642d7 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Fri, 9 Jun 2023 15:14:59 +0800 Subject: [PATCH 1468/2777] esync: Type-check HANDLE in esync_reset_event(). CW-Bug-Id: #22326 --- 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 40cf4a07056..948602ef35a 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -572,6 +572,9 @@ NTSTATUS esync_reset_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 d757c31fa83b4cf1f3045f25feac546e67d27ac6 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Fri, 9 Jun 2023 15:15:55 +0800 Subject: [PATCH 1469/2777] esync: Type-check HANDLE in esync_pulse_event(). CW-Bug-Id: #22326 --- 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 948602ef35a..56fdd150175 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -615,6 +615,9 @@ NTSTATUS esync_pulse_event( HANDLE handle ) if ((ret = get_object( handle, &obj ))) return ret; + if (obj->type != ESYNC_MANUAL_EVENT && obj->type != ESYNC_AUTO_EVENT) + return STATUS_OBJECT_TYPE_MISMATCH; + /* This isn't really correct; an application could miss the write. * Unfortunately we can't really do much better. Fortunately this is rarely * used (and publicly deprecated). */ From f1a9bd2ef9443367086a72b274372617f064f7b0 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Tue, 27 Jun 2023 23:01:34 +0300 Subject: [PATCH 1470/2777] win32u: Don't affect nonclient area unless requested. The state of the caption / nonclient area should be only changed when FLASHW_CAPTION or FLASHW_STOP are used. (cherry picked from commit d4b2865eb7f2612e52b3fee6ae121e59c2d28296) CW-Bug-Id: #22348 --- dlls/win32u/window.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 726ac15fc34..a07be55e883 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -4528,11 +4528,11 @@ BOOL WINAPI NtUserFlashWindowEx( FLASHWINFO *info ) win = get_win_ptr( info->hwnd ); if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP) return FALSE; - if (info->dwFlags && !(win->flags & WIN_NCACTIVATED)) + if (info->dwFlags & FLASHW_CAPTION && !(win->flags & WIN_NCACTIVATED)) { win->flags |= WIN_NCACTIVATED; } - else + else if (!info->dwFlags) { win->flags &= ~WIN_NCACTIVATED; } @@ -4553,7 +4553,10 @@ BOOL WINAPI NtUserFlashWindowEx( FLASHWINFO *info ) else wparam = (hwnd == NtUserGetForegroundWindow()); release_win_ptr( win ); - send_notify_message( hwnd, WM_NCACTIVATE, wparam, 0, 0 ); + + if (!info->dwFlags || info->dwFlags & FLASHW_CAPTION) + send_notify_message( hwnd, WM_NCACTIVATE, wparam, 0, 0 ); + user_driver->pFlashWindowEx( info ); return wparam; } From eb40bdcbfb6f26ba2ef9ccf322763c4fdfdac260 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 14 Jul 2023 19:15:52 -0600 Subject: [PATCH 1471/2777] ntdll/tests: Add test for async cancel on pipe's last process handle close. (cherry picked from commit f311bb5fba84c7574ab32c82aee345cccf310223) CW-Bug-Id: #22436 --- dlls/ntdll/tests/pipe.c | 143 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/dlls/ntdll/tests/pipe.c b/dlls/ntdll/tests/pipe.c index 11192d6e471..70aa1ebda95 100644 --- a/dlls/ntdll/tests/pipe.c +++ b/dlls/ntdll/tests/pipe.c @@ -131,6 +131,24 @@ static BOOL init_func_ptrs(void) return TRUE; } +static HANDLE create_process(const char *arg) +{ + STARTUPINFOA si = { 0 }; + PROCESS_INFORMATION pi; + char cmdline[MAX_PATH]; + char **argv; + BOOL ret; + + si.cb = sizeof(si); + winetest_get_mainargs(&argv); + sprintf(cmdline, "%s %s %s", argv[0], argv[1], arg); + ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(ret, "got %lu.\n", GetLastError()); + ret = CloseHandle(pi.hThread); + ok(ret, "got %lu.\n", GetLastError()); + return pi.hProcess; +} + static inline BOOL is_signaled( HANDLE obj ) { return WaitForSingleObject( obj, 0 ) == WAIT_OBJECT_0; @@ -2971,13 +2989,137 @@ static void test_pipe_names(void) } } +static void test_async_cancel_on_handle_close(void) +{ + static const struct + { + BOOL event; + PIO_APC_ROUTINE apc; + BOOL apc_context; + } + tests[] = + { + {TRUE, NULL}, + {FALSE, NULL}, + {TRUE, ioapc}, + {FALSE, ioapc}, + {TRUE, NULL, TRUE}, + {FALSE, NULL, TRUE}, + {TRUE, ioapc, TRUE}, + {FALSE, ioapc, TRUE}, + }; + + FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info; + char read_buf[16]; + HANDLE port, write, read, event, handle2, process_handle; + IO_STATUS_BLOCK io; + NTSTATUS status; + unsigned int i, other_process; + DWORD ret; + BOOL bret; + + create_pipe_pair(&read, &write, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 4096); + + status = pNtQueryInformationFile(read, &io, &info, sizeof(info), + FileIoCompletionNotificationInformation); + ok(status == STATUS_SUCCESS || broken(status == STATUS_INVALID_INFO_CLASS), + "status = %lx\n", status); + CloseHandle(read); + CloseHandle(write); + if (status) + { + win_skip("FileIoCompletionNotificationInformation is not supported.\n"); + return; + } + + process_handle = create_process("sleep"); + event = CreateEventW(NULL, FALSE, FALSE, NULL); + + for (other_process = 0; other_process < 2; ++other_process) + { + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("other_process %u, i %u", other_process, i); + create_pipe_pair(&read, &write, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 4096); + port = CreateIoCompletionPort(read, NULL, 0, 0); + ok(!!port, "got %p.\n", port); + + memset(&io, 0xcc, sizeof(io)); + ResetEvent(event); + status = NtReadFile(read, tests[i].event ? event : NULL, tests[i].apc, tests[i].apc_context ? &io : NULL, &io, + read_buf, 16, NULL, NULL); + if (tests[i].apc) + { + ok(status == STATUS_INVALID_PARAMETER, "got %#lx.\n", status); + CloseHandle(read); + CloseHandle(write); + CloseHandle(port); + winetest_pop_context(); + continue; + } + ok(status == STATUS_PENDING, "got %#lx.\n", status); + ok(io.Status == 0xcccccccc, "got %#lx.\n", io.Status); + + bret = DuplicateHandle(GetCurrentProcess(), read, other_process ? process_handle : GetCurrentProcess(), + &handle2, 0, FALSE, DUPLICATE_SAME_ACCESS); + ok(bret, "failed, error %lu.\n", GetLastError()); + + CloseHandle(read); + ok(io.Status == 0xcccccccc, "got %#lx.\n", io.Status); + if (other_process && tests[i].apc_context && !tests[i].event) + todo_wine test_queued_completion(port, &io, STATUS_CANCELLED, 0); + else + test_no_queued_completion(port); + + ret = WaitForSingleObject(event, 0); + ok(ret == WAIT_TIMEOUT, "got %#lx.\n", ret); + + if (other_process) + { + bret = DuplicateHandle(process_handle, handle2, GetCurrentProcess(), &read, 0, FALSE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + ok(bret, "failed, error %lu.\n", GetLastError()); + } + else + { + read = handle2; + } + CloseHandle(read); + CloseHandle(write); + CloseHandle(port); + winetest_pop_context(); + } + } + + CloseHandle(event); + TerminateProcess(process_handle, 0); + WaitForSingleObject(process_handle, INFINITE); + CloseHandle(process_handle); +} + START_TEST(pipe) { + char **argv; + int argc; + if (!init_func_ptrs()) return; if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE; + argc = winetest_get_mainargs(&argv); + if (argc >= 3) + { + if (!strcmp(argv[2], "sleep")) + { + Sleep(5000); + return; + } + return; + } + trace("starting invalid create tests\n"); test_create_invalid(); @@ -3031,6 +3173,7 @@ START_TEST(pipe) test_security_info(); test_empty_name(); test_pipe_names(); + test_async_cancel_on_handle_close(); pipe_for_each_state(create_pipe_server, connect_pipe, test_pipe_state); pipe_for_each_state(create_pipe_server, connect_and_write_pipe, test_pipe_with_data_state); From 099687dd9fe653f86b4d5b42962f689a92502e26 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 14 Jul 2023 19:57:51 -0600 Subject: [PATCH 1472/2777] ws2_32/tests: Add test for async cancel on socket's last process handle close. (cherry picked from commit 6360f56931bad30dd6381d317570ccee98393e66) CW-Bug-Id: #22436 --- dlls/ws2_32/tests/afd.c | 184 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 172 insertions(+), 12 deletions(-) diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index b07fb40fe3f..73d6769ff8b 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -33,6 +33,24 @@ #define TIMEOUT_INFINITE _I64_MAX +static HANDLE create_process(const char *arg) +{ + STARTUPINFOA si = { 0 }; + PROCESS_INFORMATION pi; + char cmdline[MAX_PATH]; + char **argv; + BOOL ret; + + si.cb = sizeof(si); + winetest_get_mainargs(&argv); + sprintf(cmdline, "%s %s %s", argv[0], argv[1], arg); + ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(ret, "got %lu.\n", GetLastError()); + ret = CloseHandle(pi.hThread); + ok(ret, "got %lu.\n", GetLastError()); + return pi.hProcess; +} + static void tcp_socketpair_flags(SOCKET *src, SOCKET *dst, DWORD flags) { SOCKET server = INVALID_SOCKET; @@ -2457,11 +2475,11 @@ static NTSTATUS WINAPI thread_NtDeviceIoControlFile(BOOL kill_thread, HANDLE han return p.ret; } -static unsigned int test_async_thread_termination_apc_count; +static unsigned int test_apc_count; -static void WINAPI test_async_thread_termination_apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved ) +static void WINAPI test_apc_proc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved ) { - ++test_async_thread_termination_apc_count; + ++test_apc_count; } static void test_async_thread_termination(void) @@ -2479,18 +2497,18 @@ static void test_async_thread_termination(void) {TRUE, TRUE, NULL, NULL}, {FALSE, FALSE, NULL, NULL}, {TRUE, FALSE, NULL, NULL}, - {FALSE, TRUE, test_async_thread_termination_apc, NULL}, - {TRUE, TRUE, test_async_thread_termination_apc, NULL}, - {FALSE, FALSE, test_async_thread_termination_apc, NULL}, - {TRUE, FALSE, test_async_thread_termination_apc, NULL}, + {FALSE, TRUE, test_apc_proc, NULL}, + {TRUE, TRUE, test_apc_proc, NULL}, + {FALSE, FALSE, test_apc_proc, NULL}, + {TRUE, FALSE, test_apc_proc, NULL}, {FALSE, TRUE, NULL, (void *)0xdeadbeef}, {TRUE, TRUE, NULL, (void *)0xdeadbeef}, {FALSE, FALSE, NULL, (void *)0xdeadbeef}, {TRUE, FALSE, NULL, (void *)0xdeadbeef}, - {FALSE, TRUE, test_async_thread_termination_apc, (void *)0xdeadbeef}, - {TRUE, TRUE, test_async_thread_termination_apc, (void *)0xdeadbeef}, - {FALSE, FALSE, test_async_thread_termination_apc, (void *)0xdeadbeef}, - {TRUE, FALSE, test_async_thread_termination_apc, (void *)0xdeadbeef}, + {FALSE, TRUE, test_apc_proc, (void *)0xdeadbeef}, + {TRUE, TRUE, test_apc_proc, (void *)0xdeadbeef}, + {FALSE, FALSE, test_apc_proc, (void *)0xdeadbeef}, + {TRUE, FALSE, test_apc_proc, (void *)0xdeadbeef}, }; const struct sockaddr_in bind_addr = {.sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK)}; @@ -2543,7 +2561,7 @@ static void test_async_thread_termination(void) } SleepEx(0, TRUE); - ok(!test_async_thread_termination_apc_count, "got APC.\n"); + ok(!test_apc_count, "got APC.\n"); port = CreateIoCompletionPort((HANDLE)listener, NULL, 0, 0); @@ -2747,12 +2765,153 @@ static void test_read_write(void) CloseHandle(event); } +static void test_async_cancel_on_handle_close(void) +{ + static const struct + { + BOOL event; + PIO_APC_ROUTINE apc; + void *apc_context; + } + tests[] = + { + {TRUE, NULL, NULL}, + {FALSE, NULL, NULL}, + {TRUE, test_apc_proc, NULL}, + {FALSE, test_apc_proc, NULL}, + {TRUE, NULL, (void *)0xdeadbeef}, + {FALSE, NULL, (void *)0xdeadbeef}, + {TRUE, test_apc_proc, (void *)0xdeadbeef}, + {FALSE, test_apc_proc, (void *)0xdeadbeef}, + }; + + const struct sockaddr_in bind_addr = {.sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK)}; + char in_buffer[offsetof(struct afd_poll_params, sockets[3])]; + char out_buffer[offsetof(struct afd_poll_params, sockets[3])]; + struct afd_poll_params *in_params = (struct afd_poll_params *)in_buffer; + struct afd_poll_params *out_params = (struct afd_poll_params *)out_buffer; + unsigned int i, other_process; + LARGE_INTEGER zero = {{0}}; + HANDLE process_handle; + ULONG_PTR key, value; + IO_STATUS_BLOCK io; + HANDLE event, port; + ULONG params_size; + SOCKET listener; + HANDLE handle2; + DWORD ret; + BOOL bret; + + process_handle = create_process("sleep"); + + event = CreateEventW(NULL, FALSE, FALSE, NULL); + + in_params->count = 1; + in_params->exclusive = FALSE; + in_params->sockets[0].flags = ~0; + in_params->sockets[0].status = 0xdeadbeef; + params_size = offsetof(struct afd_poll_params, sockets[1]); + in_params->timeout = -10 * 1000 * 1000 * 5; + + for (other_process = 0; other_process < 2; ++other_process) + { + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("other_process %u, i %u", other_process, i); + + listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ret = bind(listener, (const struct sockaddr *)&bind_addr, sizeof(bind_addr)); + ok(!ret, "got error %u\n", WSAGetLastError()); + ret = listen(listener, 1); + ok(!ret, "got error %u\n", WSAGetLastError()); + + port = CreateIoCompletionPort((HANDLE)listener, NULL, 0, 0); + ok(!!port, "got %p.\n", port); + + in_params->sockets[0].socket = listener; + + memset(&io, 0xcc, sizeof(io)); + ResetEvent(event); + ret = NtDeviceIoControlFile((HANDLE)listener, tests[i].event ? event : NULL, + tests[i].apc, tests[i].apc_context, &io, IOCTL_AFD_POLL, in_params, params_size, + out_params, params_size); + if (tests[i].apc) + { + ok(ret == STATUS_INVALID_PARAMETER, "got %#lx\n", ret); + winetest_pop_context(); + continue; + } + ok(ret == STATUS_PENDING, "got %#lx.\n", ret); + ok(io.Status == 0xcccccccc, "got %#lx.\n", io.Status); + + bret = DuplicateHandle(GetCurrentProcess(), (HANDLE)listener, + other_process ? process_handle : GetCurrentProcess(), + &handle2, 0, FALSE, DUPLICATE_SAME_ACCESS); + ok(bret, "failed, error %lu.\n", GetLastError()); + + closesocket(listener); + + ok(io.Status == 0xcccccccc, "got %#lx\n", io.Status); + memset(&io, 0xcc, sizeof(io)); + key = 0xcc; + value = 0; + ret = NtRemoveIoCompletion(port, &key, &value, &io, &zero); + if (other_process && tests[i].apc_context && !tests[i].event) + { + todo_wine ok(!ret, "got %#lx\n", ret); + todo_wine ok(!key, "got key %#Ix\n", key); + todo_wine ok(value == 0xdeadbeef, "got value %#Ix\n", value); + todo_wine ok(io.Status == STATUS_CANCELLED, "got %#lx\n", io.Status); + } + else + { + ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); + } + + ret = WaitForSingleObject(event, 0); + ok(ret == WAIT_TIMEOUT, "got %#lx.\n", ret); + + if (other_process) + { + bret = DuplicateHandle(process_handle, handle2, GetCurrentProcess(), (HANDLE *)&listener, 0, FALSE, + DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); + ok(bret, "failed, error %lu.\n", GetLastError()); + } + else + { + listener = (SOCKET)handle2; + } + + CloseHandle((HANDLE)listener); + CloseHandle(port); + winetest_pop_context(); + } + } + CloseHandle(event); + TerminateProcess(process_handle, 0); + WaitForSingleObject(process_handle, INFINITE); + CloseHandle(process_handle); +} + START_TEST(afd) { WSADATA data; + char **argv; + int argc; WSAStartup(MAKEWORD(2, 2), &data); + argc = winetest_get_mainargs(&argv); + if (argc >= 3) + { + if (!strcmp(argv[2], "sleep")) + { + Sleep(5000); + return; + } + return; + } + test_open_device(); test_poll(); test_poll_exclusive(); @@ -2766,6 +2925,7 @@ START_TEST(afd) test_getsockname(); test_async_thread_termination(); test_read_write(); + test_async_cancel_on_handle_close(); WSACleanup(); } From 3d61b33f604f378ec23fad37e7e3cc228dcb001b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 19 Jul 2023 10:02:06 -0600 Subject: [PATCH 1473/2777] server: Cancel socket asyncs when the last handle in process is closed. (cherry picked from commit 57095a91b053a5570bd797782b51b84fdd42173c) CW-Bug-Id: #22436 --- dlls/ws2_32/tests/afd.c | 11 +++++++---- server/async.c | 22 ++++++++++++++++++++++ server/file.h | 1 + server/handle.c | 15 +++++++++++++++ server/handle.h | 1 + server/sock.c | 3 +-- 6 files changed, 47 insertions(+), 6 deletions(-) diff --git a/dlls/ws2_32/tests/afd.c b/dlls/ws2_32/tests/afd.c index 73d6769ff8b..4fabf478f03 100644 --- a/dlls/ws2_32/tests/afd.c +++ b/dlls/ws2_32/tests/afd.c @@ -2851,17 +2851,20 @@ static void test_async_cancel_on_handle_close(void) closesocket(listener); + /* Canceled asyncs with completion port and no event do not update IOSB before removing completion. */ + todo_wine_if(other_process && tests[i].apc_context && !tests[i].event) ok(io.Status == 0xcccccccc, "got %#lx\n", io.Status); + memset(&io, 0xcc, sizeof(io)); key = 0xcc; value = 0; ret = NtRemoveIoCompletion(port, &key, &value, &io, &zero); if (other_process && tests[i].apc_context && !tests[i].event) { - todo_wine ok(!ret, "got %#lx\n", ret); - todo_wine ok(!key, "got key %#Ix\n", key); - todo_wine ok(value == 0xdeadbeef, "got value %#Ix\n", value); - todo_wine ok(io.Status == STATUS_CANCELLED, "got %#lx\n", io.Status); + ok(!ret, "got %#lx\n", ret); + ok(!key, "got key %#Ix\n", key); + ok(value == 0xdeadbeef, "got value %#Ix\n", value); + ok(io.Status == STATUS_CANCELLED, "got %#lx\n", io.Status); } else { diff --git a/server/async.c b/server/async.c index e246650ff3f..91f0d87f9df 100644 --- a/server/async.c +++ b/server/async.c @@ -616,6 +616,28 @@ void cancel_process_asyncs( struct process *process ) cancel_async( process, NULL, NULL, 0 ); } +int async_close_obj_handle( struct object *obj, struct process *process, obj_handle_t handle ) +{ + /* Handle a special case when the last object handle in the given process is closed. + * If this is the last object handle overall that is handled in object's close_handle and + * destruction. */ + struct async *async; + + if (obj->handle_count == 1 || get_obj_handle_count( process, obj ) != 1) return 1; + +restart: + LIST_FOR_EACH_ENTRY( async, &process->asyncs, struct async, process_entry ) + { + if (async->terminated || async->canceled || get_fd_user( async->fd ) != obj) continue; + if (!async->completion || !async->data.apc_context || async->event) continue; + + async->canceled = 1; + fd_cancel_async( async->fd, async ); + goto restart; + } + return 1; +} + void cancel_terminating_thread_asyncs( struct thread *thread ) { struct async *async; diff --git a/server/file.h b/server/file.h index df3b3b3ae4a..1965626dc0e 100644 --- a/server/file.h +++ b/server/file.h @@ -257,6 +257,7 @@ extern struct thread *async_get_thread( struct async *async ); extern struct async *find_pending_async( struct async_queue *queue ); extern void cancel_process_asyncs( struct process *process ); extern void cancel_terminating_thread_asyncs( struct thread *thread ); +extern int async_close_obj_handle( struct object *obj, struct process *process, obj_handle_t handle ); static inline void init_async_queue( struct async_queue *queue ) { diff --git a/server/handle.c b/server/handle.c index 71b23093f62..48b5d8101bb 100644 --- a/server/handle.c +++ b/server/handle.c @@ -522,6 +522,21 @@ obj_handle_t find_inherited_handle( struct process *process, const struct object return 0; } +/* return number of open handles to the object in the process */ +unsigned int get_obj_handle_count( struct process *process, const struct object *obj ) +{ + struct handle_table *table = process->handles; + struct handle_entry *ptr; + unsigned int count = 0; + int i; + + if (!table) return 0; + + for (i = 0, ptr = table->entries; i <= table->last; i++, ptr++) + if (ptr->ptr == obj) ++count; + return count; +} + /* get/set the handle reserved flags */ /* return the old flags (or -1 on error) */ static int set_handle_flags( struct process *process, obj_handle_t handle, int mask, int flags ) diff --git a/server/handle.h b/server/handle.h index ac3104dc003..1d02e040258 100644 --- a/server/handle.h +++ b/server/handle.h @@ -48,6 +48,7 @@ extern obj_handle_t open_object( struct process *process, obj_handle_t parent, u const struct object_ops *ops, const struct unicode_str *name, unsigned int attr ); extern obj_handle_t find_inherited_handle( struct process *process, const struct object_ops *ops ); +extern unsigned int get_obj_handle_count( struct process *process, const struct object *obj ); extern void close_process_handles( struct process *process ); extern struct handle_table *alloc_handle_table( struct process *process, int count ); extern struct handle_table *copy_handle_table( struct process *process, struct process *parent, diff --git a/server/sock.c b/server/sock.c index b02b1c75b5e..16769fc2b4b 100644 --- a/server/sock.c +++ b/server/sock.c @@ -1658,8 +1658,7 @@ static int sock_close_handle( struct object *obj, struct process *process, obj_h if (signaled) complete_async_poll( poll_req, STATUS_SUCCESS ); } } - - return 1; + return async_close_obj_handle( obj, process, handle ); } static void sock_destroy( struct object *obj ) From d2445b4e5aee3d17f55ec3b04e975ccd4a17653f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 14 Jul 2023 20:21:50 -0600 Subject: [PATCH 1474/2777] server: Cancel pipe asyncs when the last handle in process is closed. (cherry picked from commit 03c1930b74e9a41da84fd712a3ebdbb4f7fcbcb5) CW-Bug-Id: #22436 --- dlls/ntdll/tests/pipe.c | 5 ++++- server/named_pipe.c | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/tests/pipe.c b/dlls/ntdll/tests/pipe.c index 70aa1ebda95..30f4b6f1405 100644 --- a/dlls/ntdll/tests/pipe.c +++ b/dlls/ntdll/tests/pipe.c @@ -3067,9 +3067,12 @@ static void test_async_cancel_on_handle_close(void) ok(bret, "failed, error %lu.\n", GetLastError()); CloseHandle(read); + /* Canceled asyncs with completion port and no event do not update IOSB before removing completion. */ + todo_wine_if(other_process && tests[i].apc_context && !tests[i].event) ok(io.Status == 0xcccccccc, "got %#lx.\n", io.Status); + if (other_process && tests[i].apc_context && !tests[i].event) - todo_wine test_queued_completion(port, &io, STATUS_CANCELLED, 0); + test_queued_completion(port, &io, STATUS_CANCELLED, 0); else test_no_queued_completion(port); diff --git a/server/named_pipe.c b/server/named_pipe.c index 6679f4cc3a0..5c486093c76 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -183,7 +183,7 @@ static const struct object_ops pipe_server_ops = NULL, /* unlink_name */ pipe_server_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ - no_close_handle, /* close_handle */ + async_close_obj_handle, /* close_handle */ pipe_server_destroy /* destroy */ }; @@ -229,7 +229,7 @@ static const struct object_ops pipe_client_ops = NULL, /* unlink_name */ no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ - no_close_handle, /* close_handle */ + async_close_obj_handle, /* close_handle */ pipe_end_destroy /* destroy */ }; From 029ed25df6c981d116125775d1cc48901df7d92a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 20 Jul 2023 20:45:34 -0600 Subject: [PATCH 1475/2777] amd_ags_x64, atiadlxx: Bump driver version. --- dlls/amd_ags_x64/amd_ags_x64_main.c | 11 +++++++---- dlls/atiadlxx/atiadlxx_main.c | 6 +++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 3706e21915c..facea4ff622 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -22,6 +22,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(amd_ags); +static const char driver_version[] = "23.10.01.45-230626a-393367C-AMD-Software-Adrenalin-Edition"; +static const char radeon_version[] = "23.7.1"; + enum amd_ags_version { AMD_AGS_VERSION_5_1_1, @@ -586,8 +589,8 @@ AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *confi gpu_info->agsVersionMajor = amd_ags_info[object->version].major; gpu_info->agsVersionMinor = amd_ags_info[object->version].minor; gpu_info->agsVersionPatch = amd_ags_info[object->version].patch; - gpu_info->driverVersion = "21.30.25.05-211005a-372402E-RadeonSoftware"; - gpu_info->radeonSoftwareVersion = "21.10.2"; + gpu_info->driverVersion = driver_version; + gpu_info->radeonSoftwareVersion = radeon_version; gpu_info->numDevices = object->device_count; gpu_info->devices = object->devices; @@ -621,8 +624,8 @@ AGSReturnCode WINAPI agsInitialize(int ags_version, const AGSConfiguration *conf } memset(gpu_info, 0, sizeof(*gpu_info)); - gpu_info->driverVersion = "21.30.25.05-211005a-372402E-RadeonSoftware"; - gpu_info->radeonSoftwareVersion = "21.10.2"; + gpu_info->driverVersion = driver_version; + gpu_info->radeonSoftwareVersion = radeon_version; gpu_info->numDevices = object->device_count; gpu_info->devices = object->devices; diff --git a/dlls/atiadlxx/atiadlxx_main.c b/dlls/atiadlxx/atiadlxx_main.c index 21dfbe71096..7104bcfa723 100644 --- a/dlls/atiadlxx/atiadlxx_main.c +++ b/dlls/atiadlxx/atiadlxx_main.c @@ -172,15 +172,15 @@ typedef struct ADLDisplayMap } ADLDisplayMap, *LPADLDisplayMap; static const ADLVersionsInfo version = { - "22.20.19.16-221003a-384125E-AMD-Software-Adrenalin-Edition", + "23.10.01.45-230626a-393367C-AMD-Software-Adrenalin-Edition", "", "http://support.amd.com/drivers/xml/driver_09_us.xml", }; static const ADLVersionsInfoX2 version2 = { - "22.20.19.16-221003a-384125E-AMD-Software-Adrenalin-Edition", + "23.10.01.45-230626a-393367C-AMD-Software-Adrenalin-Edition", "", - "22.10.1", + "23.7.1", "http://support.amd.com/drivers/xml/driver_09_us.xml", }; From 6eeafbb658fe2bc73c02a3e71a078a56f6ba4a23 Mon Sep 17 00:00:00 2001 From: Victor Chiletto Date: Fri, 14 Jul 2023 18:02:31 -0300 Subject: [PATCH 1476/2777] user32: Add hotpatch prologue to RegisterRawInputDevices. re4_tweaks relies on this function being hotpatchable [1]. [1]: https://github.com/nipkownix/re4_tweaks/blob/7cfcf5c4272f7d68d177661ffe84e9d1e0d2f383/dllmain/input.cpp#L903 (cherry picked from commit fb296929f98e93e5ba08ff4585c09886076da5a9) CW-Bug-Id: #22401 --- dlls/user32/user32.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 21962768dcc..aa96251e4da 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -611,7 +611,7 @@ @ stub RegisterNetworkCapabilities @ stdcall RegisterPointerDeviceNotifications(long long) @ stdcall RegisterPowerSettingNotification(long ptr long) -@ stdcall RegisterRawInputDevices(ptr long long) NtUserRegisterRawInputDevices +@ stdcall -import RegisterRawInputDevices(ptr long long) NtUserRegisterRawInputDevices @ stdcall RegisterServicesProcess(long) @ stdcall RegisterShellHookWindow (long) @ stdcall RegisterSuspendResumeNotification(long long) From 43ef90dedfaee707ed4288c947ed07548c8d9ee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 26 Jul 2023 10:22:33 +0200 Subject: [PATCH 1477/2777] dinput: Unacquire only DISCL_FOREGROUND devices on foreground changes. Fixes broken input in Final Fantasy XIII after main window focus loss. (cherry picked from commit 4151acb4e8f04240c2dfceb8830ba7c34f5bf251) CW-Bug-Id: #22203 --- dlls/dinput/dinput_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index f2d75a14d2e..c99729a3770 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -144,7 +144,7 @@ static LRESULT CALLBACK input_thread_ll_hook_proc( int code, WPARAM wparam, LPAR return skip ? 1 : CallNextHookEx( 0, code, wparam, lparam ); } -static void dinput_unacquire_window_devices( HWND window ) +static void handle_foreground_lost( HWND window ) { struct dinput_device *impl, *next; @@ -152,7 +152,7 @@ static void dinput_unacquire_window_devices( HWND window ) LIST_FOR_EACH_ENTRY_SAFE( impl, next, &acquired_device_list, struct dinput_device, entry ) { - if (window != impl->win) continue; + if (!(impl->dwCoopLevel & DISCL_FOREGROUND) || window != impl->win) continue; TRACE( "%p window is not foreground - unacquiring %p\n", impl->win, impl ); dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface, STATUS_UNACQUIRED ); } @@ -327,7 +327,7 @@ static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPAR input_thread_update_device_list( state ); break; case NOTIFY_FOREGROUND_LOST: - dinput_unacquire_window_devices( (HWND)lparam ); + handle_foreground_lost( (HWND)lparam ); break; } From 01e5ae94986029793029382e8c5169bf696da172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 7 Jul 2023 20:53:07 +0200 Subject: [PATCH 1478/2777] winegstreamer: Free the media source work queue outside of the CS. Possibly fixing some rare deadlock with MSFS. CW-Bug-Id: #22377 --- dlls/winegstreamer/media_source.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 6c00f103662..172e775efc9 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1247,6 +1247,7 @@ static ULONG WINAPI media_source_Release(IMFMediaSource *iface) if (!ref) { IMFMediaSource_Shutdown(iface); + MFUnlockWorkQueue(source->async_commands_queue); IMFPresentationDescriptor_Release(source->pres_desc); IMFMediaEventQueue_Release(source->event_queue); IMFByteStream_Release(source->byte_stream); @@ -1450,8 +1451,6 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) } free(source->streams); - MFUnlockWorkQueue(source->async_commands_queue); - LeaveCriticalSection(&source->cs); return S_OK; From c0219158c2b2732b31035bcb7ac5e7d466690cc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 7 Jul 2023 21:56:32 +0200 Subject: [PATCH 1479/2777] fixup! winegstreamer: Allow concurrent wait_on_sample in the media source. CW-Bug-Id: #22377 --- dlls/winegstreamer/media_source.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 172e775efc9..c9ee6f227e6 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -44,11 +44,12 @@ struct media_stream LONG token_queue_count; LONG token_queue_cap; - CRITICAL_SECTION cs; - DWORD stream_id; BOOL active; BOOL eos; + + DWORD busy; + CONDITION_VARIABLE cond; }; enum source_async_op @@ -538,17 +539,12 @@ static void wait_on_sample(struct media_stream *stream, IUnknown *token) TRACE("%p, %p\n", stream, token); - EnterCriticalSection(&stream->cs); - - if (!stream->wg_stream) - { - LeaveCriticalSection(&stream->cs); - return; - } - + stream->busy = TRUE; LeaveCriticalSection(&source->cs); ret = wg_parser_stream_get_buffer(source->wg_parser, stream->wg_stream, &buffer); EnterCriticalSection(&source->cs); + stream->busy = FALSE; + WakeConditionVariable(&stream->cond); if (source->state == SOURCE_SHUTDOWN) WARN("media source has been shutdown, returning\n"); @@ -560,8 +556,6 @@ static void wait_on_sample(struct media_stream *stream, IUnknown *token) IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty_var); dispatch_end_of_presentation(source); } - - LeaveCriticalSection(&stream->cs); } static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) @@ -721,8 +715,6 @@ static ULONG WINAPI media_stream_Release(IMFMediaStream *iface) IMFStreamDescriptor_Release(stream->descriptor); IMFMediaEventQueue_Release(stream->event_queue); flush_token_queue(stream, FALSE); - stream->cs.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&stream->cs); free(stream); } @@ -887,9 +879,6 @@ static HRESULT media_stream_create(IMFMediaSource *source, DWORD id, object->eos = FALSE; object->wg_stream = wg_parser_get_stream(wg_parser, id); - InitializeCriticalSection(&object->cs); - object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs"); - TRACE("Created stream object %p.\n", object); *out = object; @@ -1428,10 +1417,8 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) { struct media_stream *stream = source->streams[i]; wg_parser_stream_disable(stream->wg_stream); - - EnterCriticalSection(&stream->cs); - stream->wg_stream = NULL; - LeaveCriticalSection(&stream->cs); + while (stream->busy) + SleepConditionVariableCS(&stream->cond, &source->cs, INFINITE); } wg_parser_disconnect(source->wg_parser); From 53c7c5efeb8a9ee76504b3d587c39edc50546e85 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 28 Jul 2023 15:22:42 -0600 Subject: [PATCH 1480/2777] winhttp: Set FILE_SKIP_COMPLETION_PORT_ON_SUCCESS on sockets. (cherry picked from commit 96b6bf6111e841c2a0791c5d99045a1ef7062f48) CW-Bug-Id: #22517 --- dlls/winhttp/net.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/winhttp/net.c b/dlls/winhttp/net.c index c10438df624..251ac389e60 100644 --- a/dlls/winhttp/net.c +++ b/dlls/winhttp/net.c @@ -26,6 +26,7 @@ #include "ws2tcpip.h" #include "winhttp.h" #include "schannel.h" +#include "winternl.h" #include "wine/debug.h" #include "winhttp_private.h" @@ -224,6 +225,8 @@ DWORD netconn_create( struct hostdata *host, const struct sockaddr_storage *sock free( conn ); return ret; } + if (!SetFileCompletionNotificationModes( (HANDLE)(UINT_PTR)conn->socket, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS )) + ERR( "SetFileCompletionNotificationModes failed.\n" ); switch (conn->sockaddr.ss_family) { From 7ff9bad5e2a8ba5e5b831dcc8e28ddedce25542d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 28 Jul 2023 15:35:02 -0600 Subject: [PATCH 1481/2777] winhttp: Skip unexpected completions in netconn_wait_overlapped_result(). (cherry picked from commit 3b69baaee85a99d3091b6fffdad0d8b8a95df6ec) CW-Bug-Id: #22517 --- dlls/winhttp/net.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/dlls/winhttp/net.c b/dlls/winhttp/net.c index 251ac389e60..134227da31b 100644 --- a/dlls/winhttp/net.c +++ b/dlls/winhttp/net.c @@ -57,15 +57,16 @@ BOOL netconn_wait_overlapped_result( struct netconn *conn, WSAOVERLAPPED *ovr, D OVERLAPPED *completion_ovr; ULONG_PTR key; - if (!GetQueuedCompletionStatus( conn->port, len, &key, &completion_ovr, INFINITE )) + while (1) { - WARN( "GetQueuedCompletionStatus failed, err %lu.\n", GetLastError() ); - return FALSE; - } - if ((key != conn->socket && conn->socket != -1) || completion_ovr != (OVERLAPPED *)ovr) - { - ERR( "Unexpected completion key %Ix, overlapped %p.\n", key, completion_ovr ); - return FALSE; + if (!GetQueuedCompletionStatus( conn->port, len, &key, &completion_ovr, INFINITE )) + { + WARN( "GetQueuedCompletionStatus failed, err %lu.\n", GetLastError() ); + return FALSE; + } + if (completion_ovr == (OVERLAPPED *)ovr && (key == conn->socket || conn->socket == -1)) + break; + ERR( "Unexpected completion key %Ix, completion ovr %p, ovr %p.\n", key, completion_ovr, ovr ); } return TRUE; } From d3aa6725a489e9b850ba1a563bdf30b3a75847ea Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Fri, 9 Jun 2023 18:40:56 +0800 Subject: [PATCH 1482/2777] fshack: winex11.drv: Use width and height to check if the current mode is a landscape mode. Check the ratio of dmPelsWidth to dmPelsHeight to determine whether the host is currently in portrait or landscape orientation. DMDO_DEFAULT is the natural orientation of the device, which isn't necessarily a landscape mode. CW-Bug-Id: #21774 --- dlls/winex11.drv/fs.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dlls/winex11.drv/fs.c b/dlls/winex11.drv/fs.c index 74a87007847..1c135fbebed 100644 --- a/dlls/winex11.drv/fs.c +++ b/dlls/winex11.drv/fs.c @@ -274,7 +274,7 @@ static void monitor_get_modes( struct fs_monitor *monitor, DEVMODEW **modes, UIN { UINT i, j, max_count, real_mode_count, resolutions = 0; DEVMODEW *real_modes, *real_mode, mode_host = {0}; - BOOL additional_modes = FALSE; + BOOL additional_modes = FALSE, landscape; const char *env; *mode_count = 0; @@ -291,6 +291,11 @@ static void monitor_get_modes( struct fs_monitor *monitor, DEVMODEW **modes, UIN return; } + /* Check the ratio of dmPelsWidth to dmPelsHeight to determine whether the host is currently in + * portrait or landscape orientation. DMDO_DEFAULT is the natural orientation of the device, + * which isn't necessarily a landscape mode */ + landscape = mode_host.dmPelsWidth >= mode_host.dmPelsHeight; + /* Add the current mode early, in case we have to limit */ modes_append( *modes, mode_count, &resolutions, &mode_host ); @@ -306,8 +311,7 @@ static void monitor_get_modes( struct fs_monitor *monitor, DEVMODEW **modes, UIN if (!additional_modes && fs_monitor_sizes[i].additional) continue; - if (mode_host.dmDisplayOrientation == DMDO_DEFAULT || - mode_host.dmDisplayOrientation == DMDO_180) + if (landscape) { mode.dmPelsWidth = fs_monitor_sizes[i].size.cx; mode.dmPelsHeight = fs_monitor_sizes[i].size.cy; From b2dc0ead305372ec3da7a0f1b4caba67d5793ab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 31 Jul 2023 14:43:21 +0200 Subject: [PATCH 1483/2777] HACK: ntdll: Enable WINE_ENABLE_GST_LIVE_LATENCY for more games. CW-Bug-Id: #22090 --- dlls/ntdll/unix/loader.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index c30e62222c8..99c9fea9661 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2384,7 +2384,10 @@ static void hacks_init(void) setenv("LIBGL_ALWAYS_SOFTWARE", "1", 0); } - if (sgi && (!strcmp(sgi, "1364780") || !strcmp(sgi, "1952120") || !strcmp(sgi, "2154900"))) + if (sgi && (0 + || !strcmp(sgi, "1364780") || !strcmp(sgi, "1952120") || !strcmp(sgi, "2154900") /* Street Fighter 6 */ + || !strcmp(sgi, "1740720") /* Have a Nice Death */ + )) { ERR("HACK: setting WINE_ENABLE_GST_LIVE_LATENCY.\n"); setenv("WINE_ENABLE_GST_LIVE_LATENCY", "1", 0); From 8b8781a80bf177c344f880f0f4fa16d6f0a9cea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Jul 2023 09:22:31 +0200 Subject: [PATCH 1484/2777] Revert "ntoskrnl.exe: Enumerate devices in their invalidation order." This reverts commit 25af2062b760f01a11ef65ffb0b554b3f17f8f9c. CW-Bug-Id: #22500 --- dlls/ntoskrnl.exe/pnp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c index 3a2826a8f0a..7c77a9a7145 100644 --- a/dlls/ntoskrnl.exe/pnp.c +++ b/dlls/ntoskrnl.exe/pnp.c @@ -1126,9 +1126,7 @@ static DWORD CALLBACK device_enum_thread_proc(void *arg) while (!invalidated_devices_count) SleepConditionVariableCS( &invalidated_devices_cv, &invalidated_devices_cs, INFINITE ); - invalidated_devices_count--; - device = invalidated_devices[0]; - memmove( invalidated_devices, invalidated_devices + 1, invalidated_devices_count * sizeof(*invalidated_devices) ); + device = invalidated_devices[--invalidated_devices_count]; /* Don't hold the CS while enumerating the device. Tests show that * calling IoInvalidateDeviceRelations() from another thread shouldn't From 9eca0be74d72587c700c9ddfaff7500140de24f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Jul 2023 09:23:05 +0200 Subject: [PATCH 1485/2777] Revert "ntoskrnl/tests: Fix a test failure." This reverts commit 03034f2c0ef23964891d60e5995d167a113f2d3e. CW-Bug-Id: #22500 --- dlls/ntoskrnl.exe/tests/driver_pnp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dlls/ntoskrnl.exe/tests/driver_pnp.c b/dlls/ntoskrnl.exe/tests/driver_pnp.c index 9a965f584cd..824c6554693 100644 --- a/dlls/ntoskrnl.exe/tests/driver_pnp.c +++ b/dlls/ntoskrnl.exe/tests/driver_pnp.c @@ -703,8 +703,7 @@ static NTSTATUS fdo_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG code) * handles to the device are closed (and the user-space thread is * currently blocked in this ioctl and won't close its handle * yet.) */ - todo_wine_if (remove_device_count) - ok(!remove_device_count, "Got %u remove events.\n", remove_device_count); + ok(!remove_device_count, "Got %u remove events.\n", remove_device_count); return STATUS_SUCCESS; } From a6134348547d0f77187f9fe3609823ea70740140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Jul 2023 09:23:11 +0200 Subject: [PATCH 1486/2777] Revert "ntoskrnl: Enumerate child devices on a separate thread." This reverts commit 9fbdf2b43435caf62742d997bf8b3fb8752f606c. CW-Bug-Id: #22500 --- dlls/ntoskrnl.exe/ntoskrnl_private.h | 1 - dlls/ntoskrnl.exe/pnp.c | 40 +--------------------------- dlls/ntoskrnl.exe/tests/driver_pnp.c | 10 +++---- 3 files changed, 6 insertions(+), 45 deletions(-) diff --git a/dlls/ntoskrnl.exe/ntoskrnl_private.h b/dlls/ntoskrnl.exe/ntoskrnl_private.h index ef1fa99057c..c736a9805a0 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl_private.h +++ b/dlls/ntoskrnl.exe/ntoskrnl_private.h @@ -22,7 +22,6 @@ #define __WINE_NTOSKRNL_PRIVATE_H #include -#include #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c index 7c77a9a7145..3c3353b311f 100644 --- a/dlls/ntoskrnl.exe/pnp.c +++ b/dlls/ntoskrnl.exe/pnp.c @@ -38,12 +38,6 @@ DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); WINE_DEFAULT_DEBUG_CHANNEL(plugplay); -DECLARE_CRITICAL_SECTION(invalidated_devices_cs); -static CONDITION_VARIABLE invalidated_devices_cv = CONDITION_VARIABLE_INIT; - -static DEVICE_OBJECT **invalidated_devices; -static size_t invalidated_devices_count; - static inline const char *debugstr_propkey( const DEVPROPKEY *id ) { if (!id) return "(null)"; @@ -491,14 +485,8 @@ void WINAPI IoInvalidateDeviceRelations( DEVICE_OBJECT *device_object, DEVICE_RE switch (type) { case BusRelations: - EnterCriticalSection( &invalidated_devices_cs ); - invalidated_devices = realloc( invalidated_devices, - (invalidated_devices_count + 1) * sizeof(*invalidated_devices) ); - invalidated_devices[invalidated_devices_count++] = device_object; - LeaveCriticalSection( &invalidated_devices_cs ); - WakeConditionVariable( &invalidated_devices_cv ); + handle_bus_relations( device_object ); break; - default: FIXME("Unhandled relation %#x.\n", type); break; @@ -1115,30 +1103,6 @@ static NTSTATUS WINAPI pnp_manager_driver_entry( DRIVER_OBJECT *driver, UNICODE_ return STATUS_SUCCESS; } -static DWORD CALLBACK device_enum_thread_proc(void *arg) -{ - for (;;) - { - DEVICE_OBJECT *device; - - EnterCriticalSection( &invalidated_devices_cs ); - - while (!invalidated_devices_count) - SleepConditionVariableCS( &invalidated_devices_cv, &invalidated_devices_cs, INFINITE ); - - device = invalidated_devices[--invalidated_devices_count]; - - /* Don't hold the CS while enumerating the device. Tests show that - * calling IoInvalidateDeviceRelations() from another thread shouldn't - * block, even if this thread is blocked in an IRP handler. */ - LeaveCriticalSection( &invalidated_devices_cs ); - - handle_bus_relations( device ); - } - - return 0; -} - void pnp_manager_start(void) { static const WCHAR driver_nameW[] = {'\\','D','r','i','v','e','r','\\','P','n','p','M','a','n','a','g','e','r',0}; @@ -1162,8 +1126,6 @@ void pnp_manager_start(void) RpcStringFreeW( &binding_str ); if (err) ERR("RpcBindingFromStringBinding() failed, error %#lx\n", err); - - CreateThread( NULL, 0, device_enum_thread_proc, NULL, 0, NULL ); } void pnp_manager_stop_driver( struct wine_driver *driver ) diff --git a/dlls/ntoskrnl.exe/tests/driver_pnp.c b/dlls/ntoskrnl.exe/tests/driver_pnp.c index 824c6554693..f17781e3d13 100644 --- a/dlls/ntoskrnl.exe/tests/driver_pnp.c +++ b/dlls/ntoskrnl.exe/tests/driver_pnp.c @@ -275,11 +275,11 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp) device->power_state = PowerDeviceD0; status = ZwWaitForSingleObject(device->plug_event, TRUE, &wait_time); - ok(!status, "Failed to wait for child plug event, status %#lx.\n", status); + todo_wine ok(!status, "Failed to wait for child plug event, status %#lx.\n", status); status = ZwSetEvent(device->plug_event2, NULL); ok(!status, "Failed to set event, status %#lx.\n", status); status = ZwWaitForSingleObject(device->plug_event, TRUE, &wait_time); - ok(!status, "Failed to wait for child plug event, status %#lx.\n", status); + todo_wine ok(!status, "Failed to wait for child plug event, status %#lx.\n", status); ret = STATUS_SUCCESS; break; @@ -695,15 +695,15 @@ static NTSTATUS fdo_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG code) * for the other. */ status = ZwSetEvent(plug_event, NULL); - ok(!status, "Failed to set event, status %#lx.\n", status); + todo_wine ok(!status, "Failed to set event, status %#lx.\n", status); status = ZwWaitForSingleObject(plug_event2, TRUE, &wait_time); - ok(!status, "Failed to wait for child plug event, status %#lx.\n", status); + todo_wine ok(!status, "Failed to wait for child plug event, status %#lx.\n", status); ok(surprise_removal_count == 1, "Got %u surprise removal events.\n", surprise_removal_count); /* We shouldn't get IRP_MN_REMOVE_DEVICE until all user-space * handles to the device are closed (and the user-space thread is * currently blocked in this ioctl and won't close its handle * yet.) */ - ok(!remove_device_count, "Got %u remove events.\n", remove_device_count); + todo_wine ok(!remove_device_count, "Got %u remove events.\n", remove_device_count); return STATUS_SUCCESS; } From 221e3f857c8bd78779d49b77c322fcfb49d9a580 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 14 Aug 2023 16:41:03 -0600 Subject: [PATCH 1487/2777] amd_ags_x64, atiadlxx: Bump driver version. --- dlls/amd_ags_x64/amd_ags_x64_main.c | 4 ++-- dlls/atiadlxx/atiadlxx_main.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index facea4ff622..6a8167d0a59 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -22,8 +22,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(amd_ags); -static const char driver_version[] = "23.10.01.45-230626a-393367C-AMD-Software-Adrenalin-Edition"; -static const char radeon_version[] = "23.7.1"; +static const char driver_version[] = "23.10.23.02-230720a-394204C-AMD-Software-Adrenalin-Edition"; +static const char radeon_version[] = "23.8.1"; enum amd_ags_version { diff --git a/dlls/atiadlxx/atiadlxx_main.c b/dlls/atiadlxx/atiadlxx_main.c index 7104bcfa723..8c52dbdc601 100644 --- a/dlls/atiadlxx/atiadlxx_main.c +++ b/dlls/atiadlxx/atiadlxx_main.c @@ -172,15 +172,15 @@ typedef struct ADLDisplayMap } ADLDisplayMap, *LPADLDisplayMap; static const ADLVersionsInfo version = { - "23.10.01.45-230626a-393367C-AMD-Software-Adrenalin-Edition", + "23.10.23.02-230720a-394204C-AMD-Software-Adrenalin-Edition", "", "http://support.amd.com/drivers/xml/driver_09_us.xml", }; static const ADLVersionsInfoX2 version2 = { - "23.10.01.45-230626a-393367C-AMD-Software-Adrenalin-Edition", + "23.10.23.02-230720a-394204C-AMD-Software-Adrenalin-Edition", "", - "23.7.1", + "23.8.1", "http://support.amd.com/drivers/xml/driver_09_us.xml", }; From d8f0b84480b22836106995de6c46bd00c01bdf63 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 25 Aug 2023 14:40:35 -0600 Subject: [PATCH 1488/2777] amd_ags_x64: Support version 5.0.5. Elden Ring is using this version. --- dlls/amd_ags_x64/amd_ags_x64_main.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 6a8167d0a59..7cc3c2476d2 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -27,6 +27,7 @@ static const char radeon_version[] = "23.8.1"; enum amd_ags_version { + AMD_AGS_VERSION_5_0_5, AMD_AGS_VERSION_5_1_1, AMD_AGS_VERSION_5_2_0, AMD_AGS_VERSION_5_2_1, @@ -51,6 +52,7 @@ static const struct } amd_ags_info[AMD_AGS_VERSION_COUNT] = { + {5, 0, 5, sizeof(AGSDeviceInfo_511), sizeof(AGSDX11ReturnedParams_511)}, {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)}, @@ -63,22 +65,22 @@ amd_ags_info[AMD_AGS_VERSION_COUNT] = {6, 1, 0, sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600)}, }; -#define DEF_FIELD(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ +#define DEF_FIELD(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name), \ offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name)}} -#define DEF_FIELD_520_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ +#define DEF_FIELD_520_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), -1, \ -1, -1, -1, -1, -1}} -#define DEF_FIELD_540_UP(name) {DEVICE_FIELD_##name, {-1, -1, \ +#define DEF_FIELD_540_UP(name) {DEVICE_FIELD_##name, {-1, -1, -1, \ -1, -1, offsetof(AGSDeviceInfo_540, name), \ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name), \ offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name)}} -#define DEF_FIELD_540_600(name) {DEVICE_FIELD_##name, {-1, -1, \ +#define DEF_FIELD_540_600(name) {DEVICE_FIELD_##name, {-1, -1, -1, \ -1, -1, offsetof(AGSDeviceInfo_540, name), \ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), \ -1, -1, -1}} -#define DEF_FIELD_600_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ +#define DEF_FIELD_600_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), -1, \ -1, -1}} @@ -941,9 +943,10 @@ AGSReturnCode WINAPI agsDriverExtensionsDX11_SetDepthBounds_530(AGSContext* cont return set_depth_bounds(context, dx_context, enabled, min_depth, max_depth); } +C_ASSERT(AMD_AGS_VERSION_5_3_0 == 4); __ASM_GLOBAL_FUNC( DX11_SetDepthBounds_impl, "mov (%rcx),%eax\n\t" /* version */ - "cmp $3,%eax\n\t" + "cmp $4,%eax\n\t" "jge 1f\n\t" "jmp " __ASM_NAME("agsDriverExtensionsDX11_SetDepthBounds") "\n\t" "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_SetDepthBounds_530") ) @@ -992,9 +995,10 @@ AGSReturnCode WINAPI agsDriverExtensionsDX11_BeginUAVOverlap(AGSContext *context return update_uav_overlap(context, dx_context, TRUE); } +C_ASSERT(AMD_AGS_VERSION_5_3_0 == 4); __ASM_GLOBAL_FUNC( DX11_BeginUAVOverlap_impl, "mov (%rcx),%eax\n\t" /* version */ - "cmp $3,%eax\n\t" + "cmp $4,%eax\n\t" "jge 1f\n\t" "jmp " __ASM_NAME("agsDriverExtensionsDX11_BeginUAVOverlap_520") "\n\t" "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_BeginUAVOverlap") ) @@ -1025,9 +1029,10 @@ AGSReturnCode WINAPI agsDriverExtensionsDX11_EndUAVOverlap(AGSContext *context, return update_uav_overlap(context, dx_context, FALSE); } +C_ASSERT(AMD_AGS_VERSION_5_3_0 == 4); __ASM_GLOBAL_FUNC( DX11_EndUAVOverlap_impl, "mov (%rcx),%eax\n\t" /* version */ - "cmp $3,%eax\n\t" + "cmp $4,%eax\n\t" "jge 1f\n\t" "jmp " __ASM_NAME("agsDriverExtensionsDX11_EndUAVOverlap_520") "\n\t" "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_EndUAVOverlap") ) @@ -1070,9 +1075,11 @@ AGSReturnCode WINAPI agsDriverExtensionsDX11_DestroyDevice_511(AGSContext *conte return agsDriverExtensionsDX11_DestroyDevice_520(context, device, references, NULL, NULL); } + +C_ASSERT(AMD_AGS_VERSION_5_2_0 == 2); __ASM_GLOBAL_FUNC( agsDriverExtensionsDX11_DestroyDevice, "mov (%rcx),%eax\n\t" /* version */ - "cmp $1,%eax\n\t" + "cmp $2,%eax\n\t" "jge 1f\n\t" "jmp " __ASM_NAME("agsDriverExtensionsDX11_DestroyDevice_511") "\n\t" "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_DestroyDevice_520") ) From d178c4948798be9ee4b11a012ac249df788f9a07 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 28 Aug 2023 11:46:57 -0600 Subject: [PATCH 1489/2777] amd_ags_x64: Fill chroma info in AGSDisplayInfo. Based on a patch by Joshua Ashton. CW-Bug-Id: #22677 --- dlls/amd_ags_x64/amd_ags_x64_main.c | 107 +++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 7cc3c2476d2..1b55df5d798 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -11,10 +11,11 @@ #include "wine/asm.h" #define COBJMACROS +#include "initguid.h" #include "d3d11.h" #include "d3d12.h" -#include "initguid.h" +#include "dxgi1_6.h" #include "dxvk_interfaces.h" @@ -344,8 +345,103 @@ struct monitor_enum_context_600 const char *adapter_name; AGSDisplayInfo_600 **ret_displays; int *ret_display_count; + IDXGIFactory1 *dxgi_factory; }; +static void create_dxgi_factory(HMODULE *hdxgi, IDXGIFactory1 **factory) +{ + typeof(CreateDXGIFactory1) *pCreateDXGIFactory1; + + *factory = NULL; + + if (!(*hdxgi = LoadLibraryW(L"dxgi.dll"))) + { + ERR("Could not load dxgi.dll.\n"); + return; + } + + if (!(pCreateDXGIFactory1 = (void *)GetProcAddress(*hdxgi, "CreateDXGIFactory1"))) + { + ERR("Could not find CreateDXGIFactory1.\n"); + return; + } + + if (FAILED(pCreateDXGIFactory1(&IID_IDXGIFactory1, (void**)factory))) + return; +} + +static void release_dxgi_factory(HMODULE hdxgi, IDXGIFactory1 *factory) +{ + if (factory) + IDXGIFactory1_Release(factory); + if (hdxgi) + FreeLibrary(hdxgi); +} + +static void fill_chroma_info(AGSDisplayInfo_600 *info, struct monitor_enum_context_600 *c, HMONITOR monitor) +{ + DXGI_OUTPUT_DESC1 output_desc; + IDXGIAdapter1 *adapter; + IDXGIOutput6 *output6; + IDXGIOutput *output; + BOOL found = FALSE; + unsigned int i, j; + HRESULT hr; + + i = 0; + while (!found && (SUCCEEDED(IDXGIFactory1_EnumAdapters1(c->dxgi_factory, i++, &adapter)))) + { + j = 0; + while (SUCCEEDED(IDXGIAdapter1_EnumOutputs(adapter, j++, &output))) + { + hr = IDXGIOutput_QueryInterface(output, &IID_IDXGIOutput6, (void**)&output6); + IDXGIOutput_Release(output); + if (FAILED(hr)) + { + WARN("Failed to query IDXGIOutput6.\n"); + continue; + } + hr = IDXGIOutput6_GetDesc1(output6, &output_desc); + IDXGIOutput6_Release(output6); + + if (FAILED(hr) || output_desc.Monitor != monitor) + continue; + found = TRUE; + + TRACE("output_desc.ColorSpace %#x.\n", output_desc.ColorSpace); + if (output_desc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) + { + TRACE("Reporting monitor %s as HDR10 supported.\n", debugstr_a(info->displayDeviceName)); + info->HDR10 = 1; + } + + info->chromaticityRedX = output_desc.RedPrimary[0]; + info->chromaticityRedY = output_desc.RedPrimary[1]; + info->chromaticityGreenX = output_desc.GreenPrimary[0]; + info->chromaticityGreenY = output_desc.GreenPrimary[1]; + info->chromaticityBlueX = output_desc.BluePrimary[0]; + info->chromaticityBlueY = output_desc.BluePrimary[1]; + info->chromaticityWhitePointX = output_desc.WhitePoint[0]; + info->chromaticityWhitePointY = output_desc.WhitePoint[1]; + + TRACE("chromacity: (%.6lf, %.6lf) (%.6lf, %.6lf) (%.6lf, %.6lf).\n", info->chromaticityRedX, + info->chromaticityRedY, info->chromaticityGreenX, info->chromaticityGreenY, info->chromaticityBlueX, + info->chromaticityBlueY); + + info->screenDiffuseReflectance = 0; + info->screenSpecularReflectance = 0; + + info->minLuminance = output_desc.MinLuminance; + info->maxLuminance = output_desc.MaxLuminance; + info->avgLuminance = output_desc.MaxFullFrameLuminance; + } + IDXGIAdapter1_Release(adapter); + } + + if (!found) + WARN("dxgi output not found.\n"); +} + static BOOL WINAPI monitor_enum_proc_600(HMONITOR hmonitor, HDC hdc, RECT *rect, LPARAM context) { struct monitor_enum_context_600 *c = (struct monitor_enum_context_600 *)context; @@ -415,6 +511,9 @@ static BOOL WINAPI monitor_enum_proc_600(HMONITOR hmonitor, HDC hdc, RECT *rect, dev_mode.dmSize = sizeof(dev_mode); } + info->eyefinityGridCoordX = -1; + info->eyefinityGridCoordY = -1; + info->currentResolution.offsetX = monitor_info.rcMonitor.left; info->currentResolution.offsetY = monitor_info.rcMonitor.top; info->currentResolution.width = monitor_info.rcMonitor.right - monitor_info.rcMonitor.left; @@ -428,6 +527,9 @@ static BOOL WINAPI monitor_enum_proc_600(HMONITOR hmonitor, HDC hdc, RECT *rect, info->currentRefreshRate = dev_mode.dmDisplayFrequency; else ERR("Could not get current display settings.\n"); + + fill_chroma_info(info, c, hmonitor); + ++*c->ret_display_count; TRACE("Added display %s for %s.\n", debugstr_a(monitor_info.szDevice), debugstr_a(c->adapter_name)); @@ -439,14 +541,17 @@ static BOOL WINAPI monitor_enum_proc_600(HMONITOR hmonitor, HDC hdc, RECT *rect, static void init_device_displays_600(const char *adapter_name, AGSDisplayInfo_600 **ret_displays, int *ret_display_count) { struct monitor_enum_context_600 context; + HMODULE hdxgi; TRACE("adapter_name %s.\n", debugstr_a(adapter_name)); context.adapter_name = adapter_name; context.ret_displays = ret_displays; context.ret_display_count = ret_display_count; + create_dxgi_factory(&hdxgi, &context.dxgi_factory); EnumDisplayMonitors(NULL, NULL, monitor_enum_proc_600, (LPARAM)&context); + release_dxgi_factory(hdxgi, context.dxgi_factory); } static void init_device_displays_511(const char *adapter_name, AGSDisplayInfo_511 **ret_displays, int *ret_display_count) From ef66cba69d1abbe58b3f6a22ffdc6c375bee06be Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 26 Aug 2023 15:01:32 +0100 Subject: [PATCH 1490/2777] amd_ags_x64: Add definitions for AGSDisplaySettings_506 The enum stuff is slightly different here. Signed-off-by: Joshua Ashton CW-Bug-Id: #22677 --- dlls/amd_ags_x64/amd_ags.h | 55 ++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h index f0afda73d37..52276cc1935 100644 --- a/dlls/amd_ags_x64/amd_ags.h +++ b/dlls/amd_ags_x64/amd_ags.h @@ -689,22 +689,54 @@ typedef struct AGSGPUInfo_600 } AGSGPUInfo_600; /// The display mode -typedef enum AGSDisplaySettings_Mode +typedef enum AGSDisplaySettings_Mode_506 { - Mode_SDR, ///< SDR mode - Mode_HDR10_PQ, ///< HDR10 PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. - Mode_HDR10_scRGB, ///< HDR10 scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. - Mode_FreesyncHDR_scRGB, ///< Freesync HDR scRGB, requiring an FP16 swapchain. A value of 1.0 == 80 nits. - Mode_FreesyncHDR_Gamma22, ///< Freesync HDR Gamma 2.2, requiring a 1010102 UNORM swapchain. The output needs to be encoded to gamma 2.2. - Mode_DolbyVision, ///< Dolby Vision, requiring an 8888 UNORM swapchain + Mode_506_SDR, ///< SDR mode + Mode_506_scRGB, ///< scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. Uses REC709 primaries. + Mode_506_PQ, ///< PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. Uses BT2020 primaries. + Mode_506_DolbyVision ///< Dolby Vision, requiring an 8888 UNORM swapchain +} AGSDisplaySettings_Mode_506; - Mode_Count ///< Number of enumerated display modes -} AGSDisplaySettings_Mode; +typedef enum AGSDisplaySettings_Mode_600 +{ + Mode_600_SDR, ///< SDR mode + Mode_600_HDR10_PQ, ///< HDR10 PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. + Mode_600_HDR10_scRGB, ///< HDR10 scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. + Mode_600_FreesyncHDR_scRGB, ///< Freesync HDR scRGB, requiring an FP16 swapchain. A value of 1.0 == 80 nits. + Mode_600_FreesyncHDR_Gamma22, ///< Freesync HDR Gamma 2.2, requiring a 1010102 UNORM swapchain. The output needs to be encoded to gamma 2.2. + Mode_600_DolbyVision, ///< Dolby Vision, requiring an 8888 UNORM swapchain + + Mode_600_Count ///< Number of enumerated display modes +} AGSDisplaySettings_Mode_600; + +/// The struct to specify the display settings to the driver. +typedef struct AGSDisplaySettings_506 +{ + AGSDisplaySettings_Mode_506 mode; ///< The display mode to set the display into + + double chromaticityRedX; ///< Red display primary X coord + double chromaticityRedY; ///< Red display primary Y coord + + double chromaticityGreenX; ///< Green display primary X coord + double chromaticityGreenY; ///< Green display primary Y coord + + double chromaticityBlueX; ///< Blue display primary X coord + double chromaticityBlueY; ///< Blue display primary Y coord + + double chromaticityWhitePointX; ///< White point X coord + double chromaticityWhitePointY; ///< White point Y coord + + double minLuminance; ///< The minimum scene luminance in nits + double maxLuminance; ///< The maximum scene luminance in nits + + double maxContentLightLevel; ///< The maximum content light level in nits (MaxCLL) + double maxFrameAverageLightLevel; ///< The maximum frame average light level in nits (MaxFALL) +} AGSDisplaySettings_506; /// The struct to specify the display settings to the driver. typedef struct AGSDisplaySettings_511 { - AGSDisplaySettings_Mode mode; ///< The display mode to set the display into + AGSDisplaySettings_Mode_600 mode; ///< The display mode to set the display into double chromaticityRedX; ///< Red display primary X coord double chromaticityRedY; ///< Red display primary Y coord @@ -731,7 +763,7 @@ typedef struct AGSDisplaySettings_511 /// The struct to specify the display settings to the driver. typedef struct AGSDisplaySettings_600 { - AGSDisplaySettings_Mode mode; ///< The display mode to set the display into + AGSDisplaySettings_Mode_600 mode; ///< The display mode to set the display into double chromaticityRedX; ///< Red display primary X coord double chromaticityRedY; ///< Red display primary Y coord @@ -757,6 +789,7 @@ typedef struct AGSDisplaySettings_600 typedef union AGSDisplaySettings { + AGSDisplaySettings_506 agsDisplaySettings506; AGSDisplaySettings_511 agsDisplaySettings511; AGSDisplaySettings_600 agsDisplaySettings600; } AGSDisplaySettings; From e1a11f62425e65e4ea33ce60f5292384ee9ef34e Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 26 Aug 2023 15:02:15 +0100 Subject: [PATCH 1491/2777] amd_ags_x64: Implement agsSetDisplayMode Gets HDR working with Elden Ring. With minor changes by Paul Gofman: - update for prior changes (create dxgi factory when needed); - still return success if anything goes wrong with getting dxgi custom interface; - add a trace with chromacity; - remove '!' in trace messages. CW-Bug-Id: #22677 --- dlls/amd_ags_x64/amd_ags_x64_main.c | 97 +++++++++++++++++++++++++++- dlls/amd_ags_x64/dxvk_interfaces.idl | 35 ++++++++++ 2 files changed, 130 insertions(+), 2 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 1b55df5d798..ca0fb573e3e 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -777,15 +777,108 @@ AGSReturnCode WINAPI agsDeInitialize(AGSContext *context) return AGS_SUCCESS; } +static DXGI_COLOR_SPACE_TYPE convert_ags_colorspace_506(AGSDisplaySettings_Mode_506 mode) +{ + switch (mode) + { + default: + ERR("Unknown color space in AGS: %d.\n", mode); + /* fallthrough */ + case Mode_506_SDR: + TRACE("Setting Mode_506_SDR.\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; + case Mode_506_PQ: + TRACE("Setting Mode_506_PQ.\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; + case Mode_506_scRGB: + TRACE("Setting Mode_506_scRGB.\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709; + } +} + +static DXGI_COLOR_SPACE_TYPE convert_ags_colorspace_600(AGSDisplaySettings_Mode_600 mode) +{ + switch (mode) + { + default: + ERR("Unknown color space in AGS: %d\n", mode); + /* fallthrough */ + case Mode_600_SDR: + TRACE("Setting Mode_600_SDR.\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; + case Mode_600_HDR10_PQ: + TRACE("Setting Mode_600_HDR10_PQ.\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; + case Mode_600_HDR10_scRGB: + TRACE("Setting Mode_600_HDR10_scRGB.\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709; + } +} + +static DXGI_HDR_METADATA_HDR10 convert_ags_metadata(const AGSDisplaySettings_600 *settings) +{ + DXGI_HDR_METADATA_HDR10 metadata; + metadata.RedPrimary[0] = settings->chromaticityRedX * 50000; + metadata.RedPrimary[1] = settings->chromaticityRedY * 50000; + metadata.GreenPrimary[0] = settings->chromaticityGreenX * 50000; + metadata.GreenPrimary[1] = settings->chromaticityGreenY * 50000; + metadata.BluePrimary[0] = settings->chromaticityBlueX * 50000; + metadata.BluePrimary[1] = settings->chromaticityBlueY * 50000; + metadata.WhitePoint[0] = settings->chromaticityWhitePointX * 50000; + metadata.WhitePoint[1] = settings->chromaticityWhitePointY * 50000; + metadata.MaxMasteringLuminance = settings->maxLuminance; + metadata.MinMasteringLuminance = settings->minLuminance / 0.0001f; + metadata.MaxContentLightLevel = settings->maxContentLightLevel; + metadata.MaxFrameAverageLightLevel = settings->maxFrameAverageLightLevel; + return metadata; +} + AGSReturnCode WINAPI agsSetDisplayMode(AGSContext *context, int device_index, int display_index, const AGSDisplaySettings *settings) { - FIXME("context %p device_index %d display_index %d settings %p stub!\n", context, device_index, + const AGSDisplaySettings_506 *settings506 = &settings->agsDisplaySettings506; + const AGSDisplaySettings_600 *settings600 = &settings->agsDisplaySettings600; + IDXGIVkInteropFactory1 *dxgi_interop = NULL; + DXGI_COLOR_SPACE_TYPE colorspace; + DXGI_HDR_METADATA_HDR10 metadata; + AGSReturnCode ret = AGS_SUCCESS; + IDXGIFactory1 *dxgi_factory; + HMODULE hdxgi; + + TRACE("context %p device_index %d display_index %d settings %p\n", context, device_index, display_index, settings); if (!context) return AGS_INVALID_ARGS; - return AGS_SUCCESS; + create_dxgi_factory(&hdxgi, &dxgi_factory); + if (!dxgi_factory) + goto done; + + if (FAILED(IDXGIFactory1_QueryInterface(dxgi_factory, &IID_IDXGIVkInteropFactory1, (void**)&dxgi_interop))) + { + WARN("Failed to get IDXGIVkInteropFactory1.\n"); + goto done; + } + + colorspace = context->version < AMD_AGS_VERSION_5_1_1 + ? convert_ags_colorspace_506(settings506->mode) + : convert_ags_colorspace_600(settings600->mode); + /* Settings 506, 511 and 600 are identical aside from enum order + use + * of bitfield flags we do not use. */ + metadata = convert_ags_metadata(settings600); + + TRACE("chromacity: (%.6lf, %.6lf) (%.6lf, %.6lf) (%.6lf, %.6lf).\n", settings600->chromaticityRedX, + settings600->chromaticityRedY, settings600->chromaticityGreenX, settings600->chromaticityGreenY, + settings600->chromaticityBlueX, settings600->chromaticityBlueY); + + if (FAILED(IDXGIVkInteropFactory1_SetGlobalHDRState(dxgi_interop, colorspace, &metadata))) + ret = AGS_DX_FAILURE; + +done: + if (dxgi_interop) + IDXGIVkInteropFactory1_Release(dxgi_interop); + release_dxgi_factory(hdxgi, dxgi_factory); + return ret; } AGSReturnCode WINAPI agsGetCrossfireGPUCount(AGSContext *context, int *gpu_count) diff --git a/dlls/amd_ags_x64/dxvk_interfaces.idl b/dlls/amd_ags_x64/dxvk_interfaces.idl index c632d926fb2..110cdb94896 100644 --- a/dlls/amd_ags_x64/dxvk_interfaces.idl +++ b/dlls/amd_ags_x64/dxvk_interfaces.idl @@ -17,6 +17,11 @@ */ import "d3d11.idl"; +import "dxgi1_6.idl"; + +typedef struct VkInstance_T *VkInstance; +typedef void (__stdcall *PFN_vkVoidFunction)(void); +typedef PFN_vkVoidFunction (__stdcall *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char* pName); typedef enum D3D11_VK_EXTENSION { @@ -114,3 +119,33 @@ interface ID3D11VkExtContext1 : ID3D11VkExtContext [in] const void *params, [in] UINT32 param_size, [in] void * const *read_resources, [in] UINT32 read_resource_count, [in] void* const *write_resources, [in] UINT32 write_resources_count); } + +[ + object, + uuid(4c5e1b0d-b0c8-4131-bfd8-9b2476f7f408), + local, + pointer_default(unique) +] +interface IDXGIVkInteropFactory : IUnknown +{ + void GetVulkanInstance( + [out] VkInstance *pInstance, + [out] PFN_vkGetInstanceProcAddr *ppfnVkGetInstanceProcAddr); +} + +[ + object, + uuid(2a289dbd-2d0a-4a51-89f7-f2adce465cd6), + local, + pointer_default(unique) +] +interface IDXGIVkInteropFactory1 : IDXGIVkInteropFactory +{ + HRESULT GetGlobalHDRState( + [out] DXGI_COLOR_SPACE_TYPE *pOutColorSpace, + [out] DXGI_HDR_METADATA_HDR10 *ppOutMetadata) = 0; + + HRESULT SetGlobalHDRState( + [in] DXGI_COLOR_SPACE_TYPE ColorSpace, + [in] const DXGI_HDR_METADATA_HDR10 *pMetadata) = 0; +} From 4ffde38fa76b8e558a9aa2b548a7a06a389e2673 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 14 Aug 2023 20:04:14 -0600 Subject: [PATCH 1492/2777] wine.inf: Enable builtin amd_ags_x64, atiadlxx for Ratchet & Clank: Rift Apart. CW-Bug-Id: #22607 --- loader/wine.inf.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 40179fba301..e99e27332ca 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2848,6 +2848,7 @@ HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"amd_ags_x64",,"disa HKCU,Software\Wine\AppDefaults\u4.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\tll.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\SOPFFO.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" +HKCU,Software\Wine\AppDefaults\RiftApart.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" ;;App-specific overrides for atiadlxx.dll. HKCU,Software\Wine\AppDefaults\s2_sp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\s2_mp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" @@ -2868,6 +2869,7 @@ HKCU,Software\Wine\AppDefaults\GW2.Main_Win64_Retail.exe\DllOverrides,"atiadlxx" HKCU,Software\Wine\AppDefaults\Spider-Man.exe\DllOverrides,"atiadlxx",,"builtin" HKLM,Software\Wow6432Node\lucasarts entertainment company llc\Star Wars: Episode I Racer\v1.0,"Display Height",0x10001,480 HKLM,Software\Wow6432Node\lucasarts entertainment company llc\Star Wars: Episode I Racer\v1.0,"Display Width",0x10001,640 +HKCU,Software\Wine\AppDefaults\RiftApart.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 2df26a952a34bdc7fada52c98bbf1c9ca917c2f0 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 18 Aug 2023 18:44:58 -0600 Subject: [PATCH 1493/2777] ntdll: HACK: Enable vk_x11_override_min_image_count, vk_x11_strict_image_count for Rainbow Six Extraction. CW-Bug-Id: #22634 --- dlls/ntdll/unix/loader.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 99c9fea9661..663486554e0 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2392,6 +2392,13 @@ static void hacks_init(void) ERR("HACK: setting WINE_ENABLE_GST_LIVE_LATENCY.\n"); setenv("WINE_ENABLE_GST_LIVE_LATENCY", "1", 0); } + + if (sgi && !strcmp(sgi, "2379390")) + { + ERR("HACK: setting vk_x11_override_min_image_count, vk_x11_strict_image_count.\n"); + setenv("vk_x11_override_min_image_count", "2", 0); + setenv("vk_x11_strict_image_count", "true", 0); + } } #ifdef _WIN64 From 80061cf61dd78709e08cd82d5ac77f7c161c0276 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 11 Jul 2023 14:29:15 -0600 Subject: [PATCH 1494/2777] ntdll: HACK: Enable WINE_SIMULATE_WRITECOPY for Idol Hands 2. CW-Bug-Id: #22425 --- dlls/ntdll/unix/loader.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 663486554e0..d2bff4ab2fc 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2355,6 +2355,7 @@ static void hacks_init(void) else if (sgi) simulate_writecopy = !strcmp(sgi, "1608730") /* Dawn of Corruption */ || !strcmp(sgi, "1680700") /* Purgo box */ || !strcmp(sgi, "2095300") /* Breakout 13 */ + || !strcmp(sgi, "2053940") /* Idol Hands 2 */ || !strcmp(sgi, "2176450"); /* Mr. Hopp's Playhouse 3 */ if (main_argc > 1 && strstr(main_argv[1], "MicrosoftEdgeUpdate.exe")) From 643c3f856e3e8b3db7f3a4cd87209476dccc3c01 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 21 Jul 2023 19:24:45 -0600 Subject: [PATCH 1495/2777] ntdll: Match Windows used block filling. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test rewritten by Rémi Bernon. (cherry picked from commit c77642ec52080a9385362c417505b6d15826a5f7) CW-Bug-Id: #21739 --- dlls/kernel32/tests/heap.c | 29 +++++++++++++++++++++++++++++ dlls/ntdll/heap.c | 6 ++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c index 59a82c0c579..24ce6b792da 100644 --- a/dlls/kernel32/tests/heap.c +++ b/dlls/kernel32/tests/heap.c @@ -3270,6 +3270,35 @@ static void test_heap_checks( DWORD flags ) ret = HeapFree( GetProcessHeap(), 0, p ); ok( ret, "HeapFree failed\n" ); + if (flags & HEAP_FREE_CHECKING_ENABLED) + { + UINT *p32, tmp = 0; + + size = 4 + 3; + p = pHeapAlloc( GetProcessHeap(), 0, size ); + ok( !!p, "HeapAlloc failed\n" ); + p32 = (UINT *)p; + + ok( p32[0] == 0xbaadf00d, "got %#x\n", p32[0] ); + memcpy( &tmp, p + size - 3, 3 ); + ok( tmp != 0xadf00d, "got %#x\n", tmp ); + memset( p, 0xcc, size ); + + size += 2 * 4; + p = pHeapReAlloc( GetProcessHeap(), 0, p, size ); + ok( !!p, "HeapReAlloc failed\n" ); + p32 = (UINT *)p; + + ok( p32[0] == 0xcccccccc, "got %#x\n", p32[0] ); + ok( p32[1] << 8 == 0xcccccc00, "got %#x\n", p32[1] ); + ok( p32[2] == 0xbaadf00d, "got %#x\n", p32[2] ); + memcpy( &tmp, p + size - 3, 3 ); + ok( tmp != 0xadf00d, "got %#x\n", tmp ); + + ret = pHeapFree( GetProcessHeap(), 0, p ); + ok( ret, "failed.\n" ); + } + p = HeapAlloc( GetProcessHeap(), 0, 37 ); ok( p != NULL, "HeapAlloc failed\n" ); memset( p, 0xcc, 37 ); diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 5a419f6ac98..9c1ccb559c0 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -140,7 +140,7 @@ C_ASSERT( sizeof(ARENA_LARGE) == 4 * BLOCK_ALIGN ); #define BLOCK_TYPE_FREE 'F' #define BLOCK_TYPE_LARGE 'L' -#define BLOCK_FILL_USED 0x55 +#define BLOCK_FILL_USED 0xbaadf00d #define BLOCK_FILL_TAIL 0xab #define BLOCK_FILL_FREE 0xfeeefeee @@ -516,6 +516,7 @@ static inline void mark_block_tail( struct block *block, DWORD flags ) static inline void initialize_block( struct block *block, SIZE_T old_size, SIZE_T size, DWORD flags ) { char *data = (char *)(block + 1); + SIZE_T i; if (size <= old_size) return; @@ -527,7 +528,8 @@ static inline void initialize_block( struct block *block, SIZE_T old_size, SIZE_ else if (flags & HEAP_FREE_CHECKING_ENABLED) { valgrind_make_writable( data + old_size, size - old_size ); - memset( data + old_size, BLOCK_FILL_USED, size - old_size ); + i = ROUND_SIZE( old_size, sizeof(DWORD) - 1 ) / sizeof(DWORD); + for (; i < size / sizeof(DWORD); ++i) ((DWORD *)data)[i] = BLOCK_FILL_USED; } } From c9c21755ca4caa04e9dc752a93e3bc55fc3a3dc6 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 21 Jul 2023 21:09:41 -0600 Subject: [PATCH 1496/2777] wine.inf: Set FLG_HEAP_ENABLE_FREE_CHECK for Chaos Code. CW-Bug-Id: #21739 --- loader/wine.inf.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index e99e27332ca..5440db87f19 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -418,6 +418,8 @@ HKLM,%CurrentVersionNT%\Ports,,16 HKLM,%CurrentVersionNT%\Print,,16 HKLM,%CurrentVersionNT%\ProfileList,,16 HKLM,%CurrentVersionNT%\Winlogon,"Shell",,"explorer.exe" +;; App specific heap debug flags +HKLM,%CurrentVersionNT%\Image File Execution Options\ChaosCode.exe,GlobalFlag,0x00040002,0x00000020 [CurrentVersionWow64] HKLM,%CurrentVersion%,"ProgramFilesDir (x86)",,"%16426%" From 9fd6d804116fe9a7288bca8d015f4cf46193627f Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Mon, 5 Jun 2023 23:49:53 +0100 Subject: [PATCH 1497/2777] winevulkan: Include function name in asserts. It is really useful to see at a glance what function is segfaulting/crashing here when debugging games/apps. This code is generated, and when generating WineVulkan against different Vulkan spec versions, etc it may be misleading that the Line: referred to by the assert dialog does not match what is generated locally on a different machine for the same Wine version/commit. Signed-off-by: Joshua Ashton (cherry picked from commit fc7e2041134505f9c122a34c2662490f025a574e) --- dlls/winevulkan/make_vulkan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index fc3aefbe43d..a7171b84129 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -811,7 +811,7 @@ class VkFunction(object): body += " UNIX_CALL({0}, ¶ms);\n".format(self.name) else: body += " status = UNIX_CALL({0}, ¶ms);\n".format(self.name) - body += " assert(!status);\n" + body += " assert(!status && \"{0}\");\n".format(self.name) if self.type != "void": body += " return params.result;\n" From c8b231de85050d074eeeedf11abd360d59a1a6ef Mon Sep 17 00:00:00 2001 From: Georg Lehmann Date: Thu, 26 Jan 2023 11:15:36 +0100 Subject: [PATCH 1498/2777] winevulkan: Update to VK spec version 1.3.240. (cherry picked from commit 83199991ed9df2e3869e60d98b7ead78019caaf2) --- dlls/winevulkan/make_vulkan | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index a7171b84129..1f3d272f65f 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -65,7 +65,7 @@ from enum import Enum LOGGER = logging.Logger("vulkan") LOGGER.addHandler(logging.StreamHandler()) -VK_XML_VERSION = "1.3.237" +VK_XML_VERSION = "1.3.240" WINE_VK_VERSION = (1, 3) # Filenames to create. @@ -101,6 +101,7 @@ UNSUPPORTED_EXTENSIONS = [ "VK_KHR_external_fence_win32", # Relates to external_semaphore and needs type conversions in bitflags. "VK_KHR_shared_presentable_image", # Needs WSI work. + "VK_KHR_video_queue", # TODO Video extensions use separate headers + xml "VK_KHR_win32_keyed_mutex", "VK_NV_external_memory_rdma", # Needs shared resources work. From ea2552752db7b402f6cf0113e8ec6a8112b38673 Mon Sep 17 00:00:00 2001 From: Francois Gouget Date: Mon, 13 Feb 2023 18:34:22 +0100 Subject: [PATCH 1499/2777] winevulkan: Fix a typo in a comment. (cherry picked from commit 96c8d383603d508468bd574f58a05a66395e4e80) --- dlls/winevulkan/make_vulkan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 1f3d272f65f..7dcda2cad1e 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -1248,7 +1248,7 @@ class VkVariable(object): parent = self.parent len = prefix - # check if lenght is a member of another struct (for example pAllocateInfo->commandBufferCount) + # check if length is a member of another struct (for example pAllocateInfo->commandBufferCount) i = len_str.find("->") if i != -1: var = parent[parent.index(len_str[0:i])] From 0b88b4d911a7bf026a88cef51ad969fcf1d7293f Mon Sep 17 00:00:00 2001 From: Georg Lehmann Date: Fri, 3 Mar 2023 20:47:43 +0100 Subject: [PATCH 1500/2777] winevulkan: Deal with per api xml entries. Otherwise we will have duplicate members/params with the new 242 xml. (cherry picked from commit 53c7ccec44e2cac1f3d117b6fc81193e8c8388d2) --- dlls/winevulkan/make_vulkan | 80 ++++++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 15 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 7dcda2cad1e..bb6a8a21c49 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -349,6 +349,8 @@ class Direction(Enum): INPUT = 1 OUTPUT = 2 +def api_is_vulkan(obj): + return "vulkan" in obj.get("api", "vulkan").split(",") class VkBaseType(object): def __init__(self, name, _type, alias=None, requires=None): @@ -399,6 +401,9 @@ class VkDefine(object): @staticmethod def from_xml(define): + if not api_is_vulkan(define): + return None + name_elem = define.find("name") if name_elem is None: @@ -475,6 +480,9 @@ class VkEnum(object): @staticmethod def from_xml(enum): + if not api_is_vulkan(enum): + return None + name = enum.attrib.get("name") bitwidth = int(enum.attrib.get("bitwidth", "32")) result = VkEnum(name, bitwidth) @@ -638,6 +646,9 @@ class VkFunction(object): Returns: VkFunction """ + if not api_is_vulkan(command): + return None + func_name = command.attrib.get("name") func_type = alias.type params = alias.params @@ -646,6 +657,9 @@ class VkFunction(object): @staticmethod def from_xml(command, types): + if not api_is_vulkan(command): + return None + proto = command.find("proto") func_name = proto.find("name").text func_type = proto.find("type").text @@ -653,7 +667,8 @@ class VkFunction(object): params = [] for param in command.findall("param"): vk_param = VkParam.from_xml(param, types, params) - params.append(vk_param) + if vk_param: + params.append(vk_param) return VkFunction(_type=func_type, name=func_name, params=params) @@ -1022,6 +1037,9 @@ class VkFunctionPointer(object): @staticmethod def from_xml(funcpointer): + if not api_is_vulkan(funcpointer): + return None + members = [] begin = None @@ -1102,6 +1120,9 @@ class VkHandle(object): @staticmethod def from_xml(handle): + if not api_is_vulkan(handle): + return None + name = handle.find("name").text _type = handle.find("type").text parent = handle.attrib.get("parent") # Most objects have a parent e.g. VkQueue has VkDevice. @@ -1453,6 +1474,9 @@ class VkMember(VkVariable): def from_xml(member, returnedonly, parent): """ Helper function for parsing a member tag within a struct or union. """ + if not api_is_vulkan(member): + return None + name_elem = member.find("name") type_elem = member.find("type") @@ -1697,6 +1721,9 @@ class VkParam(VkVariable): def from_xml(param, types, parent): """ Helper function to create VkParam from xml. """ + if not api_is_vulkan(param): + return None + # Parameter parsing is slightly tricky. All the data is contained within # a param tag, but some data is within subtags while others are text # before or after the type tag. @@ -2005,6 +2032,9 @@ class VkStruct(Sequence): @staticmethod def from_xml(struct): + if not api_is_vulkan(struct): + return None + # Unions and structs are the same parsing wise, but we need to # know which one we are dealing with later on for code generation. union = True if struct.attrib["category"] == "union" else False @@ -2033,7 +2063,8 @@ class VkStruct(Sequence): s = VkStruct(name, [], returnedonly, structextends, union=union) for member in struct.findall("member"): vk_member = VkMember.from_xml(member, returnedonly, s) - s.members.append(vk_member) + if vk_member: + s.members.append(vk_member) return s @@ -3445,13 +3476,15 @@ class VkRegistry(object): continue func = VkFunction.from_xml(command, self.types) - funcs[func.name] = func + if func: + funcs[func.name] = func for command in alias_commands: alias_name = command.attrib.get("alias") alias = funcs[alias_name] func = VkFunction.from_alias(command, alias) - funcs[func.name] = func + if func: + funcs[func.name] = func # To make life easy for the code generation, separate all function # calls out in the 4 types of Vulkan functions: @@ -3489,7 +3522,9 @@ class VkRegistry(object): _type = enum.attrib.get("type") if _type in ("enum", "bitmask"): - enums[name] = VkEnum.from_xml(enum) + enum_obj = VkEnum.from_xml(enum) + if enum_obj: + enums[name] = enum_obj else: # If no type is set, we are dealing with API constants. for value in enum.findall("enum"): @@ -3749,8 +3784,11 @@ class VkRegistry(object): if tail is not None: _type += tail.strip() basetype = VkBaseType(name, _type) - base_types.append(basetype) - type_info["data"] = basetype + if basetype: + base_types.append(basetype) + type_info["data"] = basetype + else: + continue # Basic C types don't need us to define them, but we do need data for them if type_info["requires"] == "vk_platform": @@ -3771,8 +3809,11 @@ class VkRegistry(object): if type_info["category"] == "define": define = VkDefine.from_xml(t) - defines.append(define) - type_info["data"] = define + if define: + defines.append(define) + type_info["data"] = define + else: + continue if type_info["category"] == "enum": name = t.attrib.get("name") @@ -3788,13 +3829,19 @@ class VkRegistry(object): if type_info["category"] == "funcpointer": funcpointer = VkFunctionPointer.from_xml(t) - funcpointers.append(funcpointer) - type_info["data"] = funcpointer + if funcpointer: + funcpointers.append(funcpointer) + type_info["data"] = funcpointer + else: + continue if type_info["category"] == "handle": handle = VkHandle.from_xml(t) - handles.append(handle) - type_info["data"] = handle + if handle: + handles.append(handle) + type_info["data"] = handle + else: + continue if type_info["category"] in ["struct", "union"]: # We store unions among structs as some structs depend @@ -3802,8 +3849,11 @@ class VkRegistry(object): # generation anyway. The official Vulkan scripts use # a similar kind of hack. struct = VkStruct.from_xml(t) - structs.append(struct) - type_info["data"] = struct + if struct: + structs.append(struct) + type_info["data"] = struct + else: + continue # Name is in general within a name tag else it is an optional # attribute on the type tag. From aa5f174a6bb86255841fd5523c9e0dda2654be46 Mon Sep 17 00:00:00 2001 From: Georg Lehmann Date: Fri, 3 Mar 2023 20:53:07 +0100 Subject: [PATCH 1501/2777] winevulkan: Only parse extensions for Vulkan. 242 adds VulkanSC only extensions (cherry picked from commit e500ca7648438067778d7a33955cfc1da10f7a3d) --- dlls/winevulkan/make_vulkan | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index bb6a8a21c49..bce58027dd3 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -3632,8 +3632,9 @@ class VkRegistry(object): if cmd_name in self.funcs: self.funcs[cmd_name].extensions.add(ext_name) - # Some extensions are not ready or have numbers reserved as a place holder. - if ext.attrib["supported"] == "disabled": + # Some extensions are not ready or have numbers reserved as a place holder + # or are only supported for VulkanSC. + if not "vulkan" in ext.attrib["supported"].split(","): LOGGER.debug("Skipping disabled extension: {0}".format(ext_name)) skipped_exts.append(ext_name) return From ca965700d9f98dce6944ed589db35e327db35335 Mon Sep 17 00:00:00 2001 From: Georg Lehmann Date: Fri, 3 Mar 2023 20:54:40 +0100 Subject: [PATCH 1502/2777] winevulkan: Skip features that are not part of Vulkan. (cherry picked from commit 8fc724927a739dcd62a298d4f93e59184575cf3c) --- dlls/winevulkan/make_vulkan | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index bce58027dd3..0ec95d1fb1d 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -3726,6 +3726,8 @@ class VkRegistry(object): """ Parse the feature section, which describes Core commands and types needed. """ for feature in root.findall("./feature"): + if not api_is_vulkan(feature): + continue feature_name = feature.attrib["name"] for require in feature.findall("require"): LOGGER.info("Including features for {0}".format(require.attrib.get("comment"))) From dbf9b305e3f8a00ba98844c4474d4a1ee6eabb83 Mon Sep 17 00:00:00 2001 From: Georg Lehmann Date: Fri, 3 Mar 2023 21:26:31 +0100 Subject: [PATCH 1503/2777] winevulkan: Add basic support for extension dependencies. (cherry picked from commit 421140b6246a5efd3352a21345f1b7b69b3cc980) --- dlls/winevulkan/make_vulkan | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 0ec95d1fb1d..87d3e7356ec 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -3675,6 +3675,11 @@ class VkRegistry(object): if len(set(requires).intersection(skipped_exts)) > 0: skipped_exts.append(ext_name) return + elif "depends" in ext.attrib: + # The syntax for this is more complex, but this is good enough for now. + if any([sext in ext.attrib["depends"] for sext in skipped_exts]): + skipped_exts.append(ext_name) + return LOGGER.debug("Loading extension: {0}".format(ext_name)) From a588218db38a6a080d360b3cc96a0c7591fdf85d Mon Sep 17 00:00:00 2001 From: Georg Lehmann Date: Fri, 3 Mar 2023 21:34:37 +0100 Subject: [PATCH 1504/2777] winevulkan: Update to VK spec version 1.3.242. (cherry picked from commit 1eed39fffe86ec60dee0678ba2303fee7ad78aec) --- dlls/winevulkan/make_vulkan | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 87d3e7356ec..4d9bb0a0d74 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -65,7 +65,7 @@ from enum import Enum LOGGER = logging.Logger("vulkan") LOGGER.addHandler(logging.StreamHandler()) -VK_XML_VERSION = "1.3.240" +VK_XML_VERSION = "1.3.242" WINE_VK_VERSION = (1, 3) # Filenames to create. @@ -1802,7 +1802,7 @@ class VkParam(VkVariable): self.format_conv = "wine_dbgstr_longlong({0})" elif self.type == "HANDLE": self.format_str = "%p" - elif self.type in ["VisualID", "xcb_visualid_t", "RROutput", "zx_handle_t"]: + elif self.type in ["VisualID", "xcb_visualid_t", "RROutput", "zx_handle_t", "NvSciBufObj", "NvSciBufAttrList", "NvSciSyncAttrList"]: # Don't care about specific types for non-Windows platforms. self.format_str = "" else: From da2d52839369cf8d58633c58848dbcee9c4ea159 Mon Sep 17 00:00:00 2001 From: Georg Lehmann Date: Fri, 31 Mar 2023 15:50:26 +0200 Subject: [PATCH 1505/2777] winevulkan: Update to VK spec version 1.3.246. (cherry picked from commit 36f5da51d0f6205ad8f03010e7fc9fe9eaf4e8d2) Modified to accomodate downstream support for VK_KHR_external_semaphore_win32. --- dlls/winevulkan/make_vulkan | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 4d9bb0a0d74..c573198e68e 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -65,7 +65,7 @@ from enum import Enum LOGGER = logging.Logger("vulkan") LOGGER.addHandler(logging.StreamHandler()) -VK_XML_VERSION = "1.3.242" +VK_XML_VERSION = "1.3.246" WINE_VK_VERSION = (1, 3) # Filenames to create. @@ -99,6 +99,7 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_full_screen_exclusive", "VK_GOOGLE_display_timing", "VK_KHR_external_fence_win32", + "VK_KHR_map_memory2", # Needs wow64 handling and is useless for now. # Relates to external_semaphore and needs type conversions in bitflags. "VK_KHR_shared_presentable_image", # Needs WSI work. "VK_KHR_video_queue", # TODO Video extensions use separate headers + xml From 89366157ed8c16c2df53a1cf28182ab64af21935 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Fri, 7 Apr 2023 18:25:05 +0200 Subject: [PATCH 1506/2777] winevulkan: Add support for VK_KHR_map_memory2. (cherry picked from commit 0a56a4ada251cd1071acfbbf64a28ec4afdd28c3) --- dlls/winevulkan/make_vulkan | 3 +- dlls/winevulkan/vulkan.c | 62 ++++++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index c573198e68e..239ed457e37 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -99,7 +99,6 @@ UNSUPPORTED_EXTENSIONS = [ "VK_EXT_full_screen_exclusive", "VK_GOOGLE_display_timing", "VK_KHR_external_fence_win32", - "VK_KHR_map_memory2", # Needs wow64 handling and is useless for now. # Relates to external_semaphore and needs type conversions in bitflags. "VK_KHR_shared_presentable_image", # Needs WSI work. "VK_KHR_video_queue", # TODO Video extensions use separate headers + xml @@ -214,7 +213,9 @@ FUNCTION_OVERRIDES = { "vkAllocateMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE, "extra_param" : "pAllocateInfo"}, "vkFreeMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkMapMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, + "vkMapMemory2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkUnmapMemory" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, + "vkUnmapMemory2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkCreateBuffer" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkCreateImage" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkGetSemaphoreCounterValue" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 6c73ddd2d39..845646e8343 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -2882,21 +2882,46 @@ void wine_vkFreeMemory(VkDevice handle, VkDeviceMemory memory_handle, const VkAl free(memory); } -VkResult wine_vkMapMemory(VkDevice handle, VkDeviceMemory memory_handle, VkDeviceSize offset, +VkResult wine_vkMapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void **data) +{ + const VkMemoryMapInfoKHR info = + { + .sType = VK_STRUCTURE_TYPE_MEMORY_MAP_INFO_KHR, + .flags = flags, + .memory = memory, + .offset = offset, + .size = size, + }; + + return wine_vkMapMemory2KHR(device, &info, data); +} + +VkResult wine_vkMapMemory2KHR(VkDevice handle, const VkMemoryMapInfoKHR *map_info, void **data) { struct wine_device *device = wine_device_from_handle(handle); - struct wine_device_memory *memory = wine_device_memory_from_handle(memory_handle); + struct wine_device_memory *memory = wine_device_memory_from_handle(map_info->memory); + VkMemoryMapInfoKHR info = *map_info; VkResult result; + info.memory = memory->memory; if (memory->mapping) { - *data = (char *)memory->mapping + offset; + *data = (char *)memory->mapping + info.offset; TRACE("returning %p\n", *data); return VK_SUCCESS; } - result = device->funcs.p_vkMapMemory(device->device, memory->memory, offset, size, flags, data); + if (device->funcs.p_vkMapMemory2KHR) + { + result = device->funcs.p_vkMapMemory2KHR(device->device, &info, data); + } + else + { + assert(!info.pNext); + result = device->funcs.p_vkMapMemory(device->device, info.memory, info.offset, + info.size, info.flags, data); + } #ifdef _WIN64 if (NtCurrentTeb()->WowTebOffset && result == VK_SUCCESS && (UINT_PTR)*data >> 32) @@ -2911,13 +2936,36 @@ VkResult wine_vkMapMemory(VkDevice handle, VkDeviceMemory memory_handle, VkDevic return result; } -void wine_vkUnmapMemory(VkDevice handle, VkDeviceMemory memory_handle) +void wine_vkUnmapMemory(VkDevice device, VkDeviceMemory memory) +{ + const VkMemoryUnmapInfoKHR info = + { + .sType = VK_STRUCTURE_TYPE_MEMORY_UNMAP_INFO_KHR, + .memory = memory, + }; + + wine_vkUnmapMemory2KHR(device, &info); +} + +VkResult wine_vkUnmapMemory2KHR(VkDevice handle, const VkMemoryUnmapInfoKHR *unmap_info) { struct wine_device *device = wine_device_from_handle(handle); - struct wine_device_memory *memory = wine_device_memory_from_handle(memory_handle); + struct wine_device_memory *memory = wine_device_memory_from_handle(unmap_info->memory); + VkMemoryUnmapInfoKHR info; - if (!memory->mapping) + if (memory->mapping) + return VK_SUCCESS; + + if (!device->funcs.p_vkUnmapMemory2KHR) + { + assert(!unmap_info->pNext); device->funcs.p_vkUnmapMemory(device->device, memory->memory); + return VK_SUCCESS; + } + + info = *unmap_info; + info.memory = memory->memory; + return device->funcs.p_vkUnmapMemory2KHR(device->device, &info); } VkResult wine_vkCreateBuffer(VkDevice handle, const VkBufferCreateInfo *create_info, From f2562e1f70690b17dba0ec42b10cbbb699415ef5 Mon Sep 17 00:00:00 2001 From: Georg Lehmann Date: Thu, 4 May 2023 12:14:05 +0200 Subject: [PATCH 1507/2777] winevulkan: Update to VK spec version 1.3.250. (cherry picked from commit e32711dd2fee94cba3ccd145397fd1904e6a397f) --- dlls/winevulkan/make_vulkan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 239ed457e37..374009b89ea 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -65,7 +65,7 @@ from enum import Enum LOGGER = logging.Logger("vulkan") LOGGER.addHandler(logging.StreamHandler()) -VK_XML_VERSION = "1.3.246" +VK_XML_VERSION = "1.3.250" WINE_VK_VERSION = (1, 3) # Filenames to create. From 12ffa4d9716b1c77e9e7195257496e5985fd263f Mon Sep 17 00:00:00 2001 From: Georg Lehmann Date: Tue, 30 May 2023 08:50:05 +0200 Subject: [PATCH 1508/2777] winevulkan: Update to VK spec version 1.3.251. (cherry picked from commit 8190aa25a00e91372090b1ba722b95defbcbed06) --- dlls/winevulkan/make_vulkan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 374009b89ea..f6c16c225d5 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -65,7 +65,7 @@ from enum import Enum LOGGER = logging.Logger("vulkan") LOGGER.addHandler(logging.StreamHandler()) -VK_XML_VERSION = "1.3.250" +VK_XML_VERSION = "1.3.251" WINE_VK_VERSION = (1, 3) # Filenames to create. From 50c173782900fdfb8764cd6d25f0f3a3641dab93 Mon Sep 17 00:00:00 2001 From: Georg Lehmann Date: Fri, 16 Jun 2023 17:48:29 +0200 Subject: [PATCH 1509/2777] winevulkan: Update to VK spec version 1.3.254. Link: https://gitlab.winehq.org/wine/wine/-/merge_requests/3078 --- dlls/winevulkan/make_vulkan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index f6c16c225d5..f680c130955 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -65,7 +65,7 @@ from enum import Enum LOGGER = logging.Logger("vulkan") LOGGER.addHandler(logging.StreamHandler()) -VK_XML_VERSION = "1.3.251" +VK_XML_VERSION = "1.3.254" WINE_VK_VERSION = (1, 3) # Filenames to create. From 21569f69194899080c2df2844082942c4072bd10 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Fri, 16 Jun 2023 22:01:19 +0300 Subject: [PATCH 1510/2777] winevulkan: Update vk.xml to 1.3.254. --- dlls/winevulkan/vk.xml | 3904 ++++++++++++++++++++++++++++++---------- 1 file changed, 2995 insertions(+), 909 deletions(-) diff --git a/dlls/winevulkan/vk.xml b/dlls/winevulkan/vk.xml index f116cbff9a5..0c4bb61609f 100644 --- a/dlls/winevulkan/vk.xml +++ b/dlls/winevulkan/vk.xml @@ -1,7 +1,7 @@ -Copyright 2015-2022 The Khronos Group Inc. +Copyright 2015-2023 The Khronos Group Inc. SPDX-License-Identifier: Apache-2.0 OR MIT @@ -32,12 +32,13 @@ branch of the member gitlab server. + - + @@ -66,14 +67,15 @@ branch of the member gitlab server. - + - + - + + @@ -90,6 +92,8 @@ branch of the member gitlab server. + + In the current header structure, each platform's interfaces are confined to a platform-specific header (vulkan_xlib.h, @@ -130,41 +134,59 @@ branch of the member gitlab server. + + + + + + - // DEPRECATED: This define is deprecated. VK_MAKE_API_VERSION should be used instead. + // DEPRECATED: This define is deprecated. VK_MAKE_API_VERSION should be used instead. #define VK_MAKE_VERSION(major, minor, patch) \ - ((((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch))) - // DEPRECATED: This define is deprecated. VK_API_VERSION_MAJOR should be used instead. -#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) - // DEPRECATED: This define is deprecated. VK_API_VERSION_MINOR should be used instead. -#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3FFU) - // DEPRECATED: This define is deprecated. VK_API_VERSION_PATCH should be used instead. + ((((uint32_t)(major)) << 22U) | (((uint32_t)(minor)) << 12U) | ((uint32_t)(patch))) + // DEPRECATED: This define is deprecated. VK_API_VERSION_MAJOR should be used instead. +#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22U) + // DEPRECATED: This define is deprecated. VK_API_VERSION_MINOR should be used instead. +#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12U) & 0x3FFU) + // DEPRECATED: This define is deprecated. VK_API_VERSION_PATCH should be used instead. #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) #define VK_MAKE_API_VERSION(variant, major, minor, patch) \ - ((((uint32_t)(variant)) << 29) | (((uint32_t)(major)) << 22) | (((uint32_t)(minor)) << 12) | ((uint32_t)(patch))) - #define VK_API_VERSION_VARIANT(version) ((uint32_t)(version) >> 29) - #define VK_API_VERSION_MAJOR(version) (((uint32_t)(version) >> 22) & 0x7FU) - #define VK_API_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3FFU) + ((((uint32_t)(variant)) << 29U) | (((uint32_t)(major)) << 22U) | (((uint32_t)(minor)) << 12U) | ((uint32_t)(patch))) + #define VK_API_VERSION_VARIANT(version) ((uint32_t)(version) >> 29U) + #define VK_API_VERSION_MAJOR(version) (((uint32_t)(version) >> 22U) & 0x7FU) + #define VK_API_VERSION_MINOR(version) (((uint32_t)(version) >> 12U) & 0x3FFU) #define VK_API_VERSION_PATCH(version) ((uint32_t)(version) & 0xFFFU) + // Vulkan SC variant number +#define VKSC_API_VARIANT 1 + // DEPRECATED: This define has been removed. Specific version defines (e.g. VK_API_VERSION_1_0), or the VK_MAKE_VERSION macro, should be used instead. -//#define VK_API_VERSION VK_MAKE_VERSION(1, 0, 0) // Patch version should always be set to 0 - // Vulkan 1.0 version number +//#define VK_API_VERSION VK_MAKE_API_VERSION(0, 1, 0, 0) // Patch version should always be set to 0 + // Vulkan 1.0 version number #define VK_API_VERSION_1_0 VK_MAKE_API_VERSION(0, 1, 0, 0)// Patch version should always be set to 0 - // Vulkan 1.1 version number + // Vulkan 1.1 version number #define VK_API_VERSION_1_1 VK_MAKE_API_VERSION(0, 1, 1, 0)// Patch version should always be set to 0 - // Vulkan 1.2 version number + // Vulkan 1.2 version number #define VK_API_VERSION_1_2 VK_MAKE_API_VERSION(0, 1, 2, 0)// Patch version should always be set to 0 // Vulkan 1.3 version number #define VK_API_VERSION_1_3 VK_MAKE_API_VERSION(0, 1, 3, 0)// Patch version should always be set to 0 - // Version of this file -#define VK_HEADER_VERSION 235 - // Complete version of this file + // Vulkan SC 1.0 version number +#define VKSC_API_VERSION_1_0 VK_MAKE_API_VERSION(VKSC_API_VARIANT, 1, 0, 0)// Patch version should always be set to 0 + + // Version of this file +#define VK_HEADER_VERSION 254 + // Complete version of this file #define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(0, 1, 3, VK_HEADER_VERSION) + // Version of this file +#define VK_HEADER_VERSION 12 + // Complete version of this file +#define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(VKSC_API_VARIANT, 1, 0, VK_HEADER_VERSION) - + #define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; + +#define VK_DEFINE_HANDLE(object) typedef struct object##_T* (object); #ifndef VK_USE_64_BIT_PTR_DEFINES @@ -189,7 +211,7 @@ branch of the member gitlab server. #ifndef VK_NULL_HANDLE #define VK_NULL_HANDLE 0 #endif - + #ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE #if (VK_USE_64_BIT_PTR_DEFINES==1) #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; @@ -197,6 +219,14 @@ branch of the member gitlab server. #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; #endif #endif + +#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE + #if (VK_USE_64_BIT_PTR_DEFINES==1) + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *(object); + #else + #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t (object); + #endif +#endif struct ANativeWindow; struct AHardwareBuffer; @@ -267,9 +297,11 @@ typedef void* MTLSharedEvent_id; typedef VkFlags VkSamplerCreateFlags; typedef VkFlags VkPipelineLayoutCreateFlags; typedef VkFlags VkPipelineCacheCreateFlags; - typedef VkFlags VkPipelineDepthStencilStateCreateFlags; + typedef VkFlags VkPipelineDepthStencilStateCreateFlags; + typedef VkFlags VkPipelineDepthStencilStateCreateFlags; typedef VkFlags VkPipelineDynamicStateCreateFlags; - typedef VkFlags VkPipelineColorBlendStateCreateFlags; + typedef VkFlags VkPipelineColorBlendStateCreateFlags; + typedef VkFlags VkPipelineColorBlendStateCreateFlags; typedef VkFlags VkPipelineMultisampleStateCreateFlags; typedef VkFlags VkPipelineRasterizationStateCreateFlags; typedef VkFlags VkPipelineViewportStateCreateFlags; @@ -307,6 +339,7 @@ typedef void* MTLSharedEvent_id; typedef VkFlags VkCommandBufferUsageFlags; typedef VkFlags VkQueryPipelineStatisticFlags; typedef VkFlags VkMemoryMapFlags; + typedef VkFlags VkMemoryUnmapFlagsKHR; typedef VkFlags VkImageAspectFlags; typedef VkFlags VkSparseMemoryBindFlags; typedef VkFlags VkSparseImageFormatFlags; @@ -342,6 +375,7 @@ typedef void* MTLSharedEvent_id; typedef VkFlags VkPipelineCompilerControlFlagsAMD; typedef VkFlags VkShaderCorePropertiesFlagsAMD; typedef VkFlags VkDeviceDiagnosticsConfigFlagsNV; + typedef VkFlags VkRefreshObjectFlagsKHR; typedef VkFlags64 VkAccessFlags2; typedef VkFlags64 VkPipelineStageFlags2; @@ -355,7 +389,7 @@ typedef void* MTLSharedEvent_id; typedef VkFlags VkBuildMicromapFlagsEXT; typedef VkFlags VkMicromapCreateFlagsEXT; - + typedef VkFlags VkDirectDriverLoadingFlagsLUNARG; WSI extensions typedef VkFlags VkCompositeAlphaFlagsKHR; @@ -441,6 +475,9 @@ typedef void* MTLSharedEvent_id; typedef VkFlags VkOpticalFlowUsageFlagsNV; typedef VkFlags VkOpticalFlowSessionCreateFlagsNV; typedef VkFlags VkOpticalFlowExecuteFlagsNV; + typedef VkFlags VkPresentScalingFlagsEXT; + typedef VkFlags VkPresentGravityFlagsEXT; + typedef VkFlags VkShaderCreateFlagsEXT; Video Core extension typedef VkFlags VkVideoCodecOperationFlagsKHR; @@ -457,29 +494,30 @@ typedef void* MTLSharedEvent_id; typedef VkFlags VkVideoDecodeFlagsKHR; Video Decode H.264 extension - typedef VkFlags VkVideoDecodeH264PictureLayoutFlagsEXT; + typedef VkFlags VkVideoDecodeH264PictureLayoutFlagsKHR; Video Encode Core extension typedef VkFlags VkVideoEncodeFlagsKHR; typedef VkFlags VkVideoEncodeUsageFlagsKHR; typedef VkFlags VkVideoEncodeContentFlagsKHR; typedef VkFlags VkVideoEncodeCapabilityFlagsKHR; + typedef VkFlags VkVideoEncodeFeedbackFlagsKHR; typedef VkFlags VkVideoEncodeRateControlFlagsKHR; typedef VkFlags VkVideoEncodeRateControlModeFlagsKHR; typedef VkFlags VkVideoChromaSubsamplingFlagsKHR; typedef VkFlags VkVideoComponentBitDepthFlagsKHR; Video Encode H.264 extension - typedef VkFlags VkVideoEncodeH264CapabilityFlagsEXT; - typedef VkFlags VkVideoEncodeH264InputModeFlagsEXT; - typedef VkFlags VkVideoEncodeH264OutputModeFlagsEXT; + typedef VkFlags VkVideoEncodeH264CapabilityFlagsEXT; + typedef VkFlags VkVideoEncodeH264StdFlagsEXT; + typedef VkFlags VkVideoEncodeH264RateControlFlagsEXT; Video Encode H.265 extension - typedef VkFlags VkVideoEncodeH265CapabilityFlagsEXT; - typedef VkFlags VkVideoEncodeH265InputModeFlagsEXT; - typedef VkFlags VkVideoEncodeH265OutputModeFlagsEXT; - typedef VkFlags VkVideoEncodeH265CtbSizeFlagsEXT; - typedef VkFlags VkVideoEncodeH265TransformBlockSizeFlagsEXT; + typedef VkFlags VkVideoEncodeH265CapabilityFlagsEXT; + typedef VkFlags VkVideoEncodeH265StdFlagsEXT; + typedef VkFlags VkVideoEncodeH265RateControlFlagsEXT; + typedef VkFlags VkVideoEncodeH265CtbSizeFlagsEXT; + typedef VkFlags VkVideoEncodeH265TransformBlockSizeFlagsEXT; Types which can be void pointers or class pointers, selected at compile time VK_DEFINE_HANDLE(VkInstance) @@ -524,12 +562,13 @@ typedef void* MTLSharedEvent_id; VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCuFunctionNVX) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkOpticalFlowSessionNV) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkMicromapEXT) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderEXT) WSI extensions VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayModeKHR) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugUtilsMessengerEXT) @@ -537,6 +576,9 @@ typedef void* MTLSharedEvent_id; VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkVideoSessionKHR) VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkVideoSessionParametersKHR) + VK_NV_external_sci_sync2 + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphoreSciSyncPoolNV) + Types generated from corresponding enums tags below @@ -690,6 +732,13 @@ typedef void* MTLSharedEvent_id; + + + + + + + @@ -700,6 +749,7 @@ typedef void* MTLSharedEvent_id; + @@ -724,6 +774,11 @@ typedef void* MTLSharedEvent_id; + + + + + WSI extensions @@ -795,6 +850,8 @@ typedef void* MTLSharedEvent_id; + + Enumerated types in the header, but not used by the API @@ -818,7 +875,7 @@ typedef void* MTLSharedEvent_id; Video H.264 Decode extensions - + Video H.265 Decode extensions @@ -827,21 +884,20 @@ typedef void* MTLSharedEvent_id; + Video H.264 Encode extensions - - - - + + + Video H.265 Encode extensions - - - - - - + + + + + The PFN_vk*Function types are used by VkAllocationCallbacks below typedef void (VKAPI_PTR *PFN_vkInternalAllocationNotification)( @@ -890,11 +946,26 @@ typedef void* MTLSharedEvent_id; const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData); + The PFN_vkFaultCallbackFunction type is used by VKSC_VERSION_1_0 + typedef void (VKAPI_PTR *PFN_vkFaultCallbackFunction)( + VkBool32 unrecordedFaults, + uint32_t faultCount, + const VkFaultData* pFaults); + The PFN_vkDeviceMemoryReportCallbackEXT type is used by the VK_EXT_device_memory_report extension typedef void (VKAPI_PTR *PFN_vkDeviceMemoryReportCallbackEXT)( const VkDeviceMemoryReportCallbackDataEXT* pCallbackData, void* pUserData); + The PFN_vkGetInstanceProcAddrLUNARG type is used by the + VkDirectDriverLoadingInfoLUNARG structure. + We cannot introduce an explicit dependency on the + equivalent PFN_vkGetInstanceProcAddr type, even though + it is implicitly generated in the C header, because + that results in multiple definitions. + typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddrLUNARG)( + VkInstance instance, const char* pName); + Struct types VkStructureType sType @@ -997,8 +1068,8 @@ typedef void* MTLSharedEvent_id; VkDeviceCreateFlags flags uint32_t queueCreateInfoCount const VkDeviceQueueCreateInfo* pQueueCreateInfos - uint32_t enabledLayerCount - const char* const* ppEnabledLayerNamesOrdered list of layer names to be enabled + uint32_t enabledLayerCount + const char* const* ppEnabledLayerNamesOrdered list of layer names to be enabled uint32_t enabledExtensionCount const char* const* ppEnabledExtensionNames const VkPhysicalDeviceFeatures* pEnabledFeatures @@ -1191,7 +1262,7 @@ typedef void* MTLSharedEvent_id; const uint32_t* pQueueFamilyIndicesArray of queue family indices to share across VkImageLayout initialLayoutInitial image layout for all subresources - + VkDeviceSize offsetSpecified in bytes VkDeviceSize sizeSpecified in bytes VkDeviceSize rowPitchSpecified in bytes @@ -1354,8 +1425,9 @@ typedef void* MTLSharedEvent_id; const void* pNext VkPipelineShaderStageCreateFlags flags VkShaderStageFlagBits stageShader stage - VkShaderModule moduleModule containing entry point - const char* pNameNull-terminated entry point name + VkShaderModule moduleModule containing entry point + const char* pNameNull-terminated entry point name + const char* pNameNull-terminated entry point name const VkSpecializationInfo* pSpecializationInfo @@ -1489,8 +1561,9 @@ typedef void* MTLSharedEvent_id; VkStructureType sType const void* pNext VkPipelineCreateFlags flagsPipeline creation flags - uint32_t stageCount - const VkPipelineShaderStageCreateInfo* pStagesOne entry for each active shader stage + uint32_t stageCount + const VkPipelineShaderStageCreateInfo* pStagesOne entry for each active shader stage + const VkPipelineShaderStageCreateInfo* pStagesOne entry for each active shader stage const VkPipelineVertexInputStateCreateInfo* pVertexInputState const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState const VkPipelineTessellationStateCreateInfo* pTessellationState @@ -1510,7 +1583,8 @@ typedef void* MTLSharedEvent_id; VkStructureType sType const void* pNext VkPipelineCacheCreateFlags flags - size_t initialDataSizeSize of initial data to populate cache, in bytes + size_t initialDataSizeSize of initial data to populate cache, in bytes + size_t initialDataSizeSize of initial data to populate cache, in bytes const void* pInitialDataInitial data to populate cache @@ -1521,6 +1595,30 @@ typedef void* MTLSharedEvent_id; uint32_t deviceID uint8_t pipelineCacheUUID[VK_UUID_SIZE] + + The fields in this structure are non-normative since structure packing is implementation-defined in C. The specification defines the normative layout. + uint64_t codeSize + uint64_t codeOffset + + + The fields in this structure are non-normative since structure packing is implementation-defined in C. The specification defines the normative layout. + uint8_t pipelineIdentifier[VK_UUID_SIZE] + uint64_t pipelineMemorySize + uint64_t jsonSize + uint64_t jsonOffset + uint32_t stageIndexCount + uint32_t stageIndexStride + uint64_t stageIndexOffset + + + The fields in this structure are non-normative since structure packing is implementation-defined in C. The specification defines the normative layout. + VkPipelineCacheHeaderVersionOne headerVersionOne + VkPipelineCacheValidationVersion validationVersion + uint32_t implementationData + uint32_t pipelineIndexCount + uint32_t pipelineIndexStride + uint64_t pipelineIndexOffset + VkShaderStageFlags stageFlagsWhich stages use the range uint32_t offsetStart of the range, in bytes @@ -2069,7 +2167,8 @@ typedef void* MTLSharedEvent_id; VkCompositeAlphaFlagBitsKHR compositeAlphaThe alpha blending mode used when compositing this surface with other surfaces in the window system VkPresentModeKHR presentModeWhich presentation mode to use for presents on this swap chain VkBool32 clippedSpecifies whether presentable images may be affected by window clip regions - VkSwapchainKHR oldSwapchainExisting swap chain to replace, if any + VkSwapchainKHR oldSwapchainExisting swap chain to replace, if any + VkSwapchainKHR oldSwapchainExisting swap chain to replace, if any VkStructureType sType @@ -2102,6 +2201,14 @@ typedef void* MTLSharedEvent_id; uint32_t disabledValidationFeatureCountNumber of validation features to disable const VkValidationFeatureDisableEXT* pDisabledValidationFeaturesValidation features to disable + + VkStructureType sType + const void* pNext + uint32_t vendorID + uint32_t deviceID + uint32_t key + uint64_t value + VkStructureType sType const void* pNext @@ -2173,6 +2280,35 @@ typedef void* MTLSharedEvent_id; const SECURITY_ATTRIBUTES* pAttributes DWORD dwAccess + + VkStructureType sType + const void* pNext + NvSciBufAttrList pAttributes + + + VkStructureType sType + const void* pNext + VkExternalMemoryHandleTypeFlagBits handleType + NvSciBufObj handle + + + VkStructureType sType + const void* pNext + VkDeviceMemory memory + VkExternalMemoryHandleTypeFlagBits handleType + + + VkStructureType sType + const void* pNext + uint32_t memoryTypeBits + + + VkStructureType sType + void* pNext + VkBool32 sciBufImport + VkBool32 sciBufExport + + VkStructureType sType const void* pNext @@ -2684,6 +2820,80 @@ typedef void* MTLSharedEvent_id; VkFence fence VkExternalFenceHandleTypeFlagBits handleType + + VkStructureType sType + const void* pNext + NvSciSyncAttrList pAttributes + + + VkStructureType sType + const void* pNext + VkFence fence + VkExternalFenceHandleTypeFlagBits handleType + void* handle + + + VkStructureType sType + const void* pNext + VkFence fence + VkExternalFenceHandleTypeFlagBits handleType + + + VkStructureType sType + const void* pNext + NvSciSyncAttrList pAttributes + + + VkStructureType sType + const void* pNext + VkSemaphore semaphore + VkExternalSemaphoreHandleTypeFlagBits handleType + void* handle + + + VkStructureType sType + const void* pNext + VkSemaphore semaphore + VkExternalSemaphoreHandleTypeFlagBits handleType + + + VkStructureType sType + const void* pNext + VkSciSyncClientTypeNV clientType + VkSciSyncPrimitiveTypeNV primitiveType + + + VkStructureType sType + void* pNext + VkBool32 sciSyncFence + VkBool32 sciSyncSemaphore + VkBool32 sciSyncImport + VkBool32 sciSyncExport + + + VkStructureType sType + void* pNext + VkBool32 sciSyncFence + VkBool32 sciSyncSemaphore2 + VkBool32 sciSyncImport + VkBool32 sciSyncExport + + + VkStructureType sType + const void* pNext + NvSciSyncObj handle + + + VkStructureType sType + const void* pNext + VkSemaphoreSciSyncPoolNV semaphorePool + const NvSciSyncFence* pFence + + + VkStructureType sType + const void* pNext + uint32_t semaphoreSciSyncPoolRequestCount + VkStructureType sType void* pNext @@ -3166,6 +3376,12 @@ typedef void* MTLSharedEvent_id; const void* pNext VkImageUsageFlags usage + + VkStructureType sType + const void* pNext + uint32_t sliceOffset + uint32_t sliceCount + VkStructureType sType @@ -4820,6 +5036,11 @@ typedef void* MTLSharedEvent_id; const void* pNext uint32_t counterPassIndexIndex for which counter pass to submit + + VkStructureType sType + const void* pNext + uint32_t maxPerformanceQueriesPerPoolMaximum number of VK_QUERY_TYPE_PERFORMANCE_QUERY_KHR queries in a query pool + VkStructureType sType const void* pNext @@ -5031,12 +5252,13 @@ typedef void* MTLSharedEvent_id; VkShaderStageFlags requiredSubgroupSizeStagesThe shader stages that support specifying a subgroup size - + VkStructureType sType void* pNext uint32_t requiredSubgroupSize + VkStructureType sType void* pNext @@ -5048,6 +5270,14 @@ typedef void* MTLSharedEvent_id; void* pNext uint32_t maxSubpassShadingWorkgroupSizeAspectRatio + + VkStructureType sType + void* pNext + uint32_t maxWorkGroupCount[3] + uint32_t maxWorkGroupSize[3] + uint32_t maxOutputClusterCount + VkDeviceSize indirectBufferOffsetAlignment + VkStructureType sType const void* pNext @@ -5309,6 +5539,19 @@ typedef void* MTLSharedEvent_id; void* pNext VkBool32 deviceCoherentMemory + + VkStructureType sType + void* pNext + VkFaultLevel faultLevel + VkFaultType faultType + + + VkStructureType sType + const void* pNext + uint32_t faultCount + VkFaultData*pFaults + PFN_vkFaultCallbackFunction pfnFaultCallback + VkStructureType sType void* pNext @@ -5486,6 +5729,17 @@ typedef void* MTLSharedEvent_id; uint32_t libraryCount const VkPipeline* pLibraries + + VkObjectType objectType + uint64_t objectHandle + VkRefreshObjectFlagsKHR flags + + + VkStructureType sType + const void* pNext + uint32_t objectCount + const VkRefreshObjectKHR* pObjects + VkStructureType sType void* pNext @@ -5579,6 +5833,13 @@ typedef void* MTLSharedEvent_id; const void* pNext VkDeviceDiagnosticsConfigFlagsNV flags + + VkStructureType sType + const void* pNext + uint8_t pipelineIdentifier[VK_UUID_SIZE] + VkPipelineMatchControl matchControl + VkDeviceSize poolEntrySize + VkStructureType sType void* pNext @@ -5652,6 +5913,12 @@ typedef void* MTLSharedEvent_id; void* pNext VkBool32 subpassShading + + VkStructureType sType + void*pNext + VkBool32 clustercullingShader + VkBool32 multiviewClusterCullingShader + VkStructureType sType const void* pNext @@ -5853,6 +6120,16 @@ typedef void* MTLSharedEvent_id; VkBool32 image2DViewOf3D VkBool32 sampler2DViewOf3D + + VkStructureType sType + void* pNext + VkBool32 imageSlicedViewOf3D + + + VkStructureType sType + void* pNext + VkBool32 attachmentFeedbackLoopDynamicState + VkStructureType sType void* pNext @@ -6013,6 +6290,97 @@ typedef void* MTLSharedEvent_id; VkBool32 synchronization2 + + VkStructureType sType + void* pNext + VkBool32 deviceNoDynamicHostAllocations + VkBool32 deviceDestroyFreesMemory + VkBool32 commandPoolMultipleCommandBuffersRecording + VkBool32 commandPoolResetCommandBuffer + VkBool32 commandBufferSimultaneousUse + VkBool32 secondaryCommandBufferNullOrImagelessFramebuffer + VkBool32 recycleDescriptorSetMemory + VkBool32 recyclePipelineMemory + uint32_t maxRenderPassSubpasses + uint32_t maxRenderPassDependencies + uint32_t maxSubpassInputAttachments + uint32_t maxSubpassPreserveAttachments + uint32_t maxFramebufferAttachments + uint32_t maxDescriptorSetLayoutBindings + uint32_t maxQueryFaultCount + uint32_t maxCallbackFaultCount + uint32_t maxCommandPoolCommandBuffers + VkDeviceSize maxCommandBufferSize + + + VkStructureType sType + const void* pNext + VkDeviceSize poolEntrySize + uint32_t poolEntryCount + + + VkStructureType sType + const void* pNext + uint32_t pipelineCacheCreateInfoCount + const VkPipelineCacheCreateInfo* pPipelineCacheCreateInfos + uint32_t pipelinePoolSizeCount + const VkPipelinePoolSize* pPipelinePoolSizes + uint32_t semaphoreRequestCount + uint32_t commandBufferRequestCount + uint32_t fenceRequestCount + uint32_t deviceMemoryRequestCount + uint32_t bufferRequestCount + uint32_t imageRequestCount + uint32_t eventRequestCount + uint32_t queryPoolRequestCount + uint32_t bufferViewRequestCount + uint32_t imageViewRequestCount + uint32_t layeredImageViewRequestCount + uint32_t pipelineCacheRequestCount + uint32_t pipelineLayoutRequestCount + uint32_t renderPassRequestCount + uint32_t graphicsPipelineRequestCount + uint32_t computePipelineRequestCount + uint32_t descriptorSetLayoutRequestCount + uint32_t samplerRequestCount + uint32_t descriptorPoolRequestCount + uint32_t descriptorSetRequestCount + uint32_t framebufferRequestCount + uint32_t commandPoolRequestCount + uint32_t samplerYcbcrConversionRequestCount + uint32_t surfaceRequestCount + uint32_t swapchainRequestCount + uint32_t displayModeRequestCount + uint32_t subpassDescriptionRequestCount + uint32_t attachmentDescriptionRequestCount + uint32_t descriptorSetLayoutBindingRequestCount + uint32_t descriptorSetLayoutBindingLimit + uint32_t maxImageViewMipLevels + uint32_t maxImageViewArrayLayers + uint32_t maxLayeredImageViewMipLevels + uint32_t maxOcclusionQueriesPerPool + uint32_t maxPipelineStatisticsQueriesPerPool + uint32_t maxTimestampQueriesPerPool + uint32_t maxImmutableSamplersPerDescriptorSetLayout + + + VkStructureType sType + const void* pNext + VkDeviceSize commandPoolReservedSize + uint32_t commandPoolMaxCommandBuffers + + + VkStructureType sType + void* pNext + VkDeviceSize commandPoolAllocated + VkDeviceSize commandPoolReservedSize + VkDeviceSize commandBufferAllocated + + + VkStructureType sType + void* pNext + VkBool32 shaderAtomicInstructions + VkStructureType sType void* pNext @@ -6063,7 +6431,7 @@ typedef void* MTLSharedEvent_id; const VkVideoProfileInfoKHR* pProfiles - VkStructureType sType + VkStructureType sType const void* pNext VkImageUsageFlags imageUsage @@ -6173,44 +6541,44 @@ typedef void* MTLSharedEvent_id; - - VkStructureType sType + + VkStructureType sType const void* pNext StdVideoH264ProfileIdc stdProfileIdc - VkVideoDecodeH264PictureLayoutFlagBitsEXT pictureLayout + VkVideoDecodeH264PictureLayoutFlagBitsKHR pictureLayout - - VkStructureType sType + + VkStructureType sType void* pNext StdVideoH264LevelIdc maxLevelIdc VkOffset2D fieldOffsetGranularity - - VkStructureType sType + + VkStructureType sType const void* pNext uint32_t stdSPSCount const StdVideoH264SequenceParameterSet* pStdSPSs uint32_t stdPPSCount const StdVideoH264PictureParameterSet* pStdPPSsList of Picture Parameters associated with the spsStd, above - - VkStructureType sType + + VkStructureType sType const void* pNext uint32_t maxStdSPSCount uint32_t maxStdPPSCount - const VkVideoDecodeH264SessionParametersAddInfoEXT* pParametersAddInfo + const VkVideoDecodeH264SessionParametersAddInfoKHR* pParametersAddInfo - - VkStructureType sType + + VkStructureType sType const void* pNext const StdVideoDecodeH264PictureInfo* pStdPictureInfo uint32_t sliceCount const uint32_t* pSliceOffsets - - VkStructureType sType + + VkStructureType sType const void* pNext const StdVideoDecodeH264ReferenceInfo* pStdReferenceInfo @@ -6238,18 +6606,18 @@ typedef void* MTLSharedEvent_id; - - VkStructureType sType + + VkStructureType sType const void* pNext StdVideoH265ProfileIdc stdProfileIdc - - VkStructureType sType + + VkStructureType sType void* pNext StdVideoH265LevelIdc maxLevelIdc - - VkStructureType sType + + VkStructureType sType const void* pNext uint32_t stdVPSCount const StdVideoH265VideoParameterSet* pStdVPSs @@ -6258,23 +6626,23 @@ typedef void* MTLSharedEvent_id; uint32_t stdPPSCount const StdVideoH265PictureParameterSet* pStdPPSsList of Picture Parameters associated with the spsStd, above - - VkStructureType sType + + VkStructureType sType const void* pNext uint32_t maxStdVPSCount uint32_t maxStdSPSCount uint32_t maxStdPPSCount - const VkVideoDecodeH265SessionParametersAddInfoEXT* pParametersAddInfo + const VkVideoDecodeH265SessionParametersAddInfoKHR* pParametersAddInfo - - VkStructureType sType - const void* pNext - StdVideoDecodeH265PictureInfo* pStdPictureInfo - uint32_t sliceCount - const uint32_t* pSliceOffsets + + VkStructureType sType + const void* pNext + const StdVideoDecodeH265PictureInfo* pStdPictureInfo + uint32_t sliceSegmentCount + const uint32_t* pSliceSegmentOffsets - - VkStructureType sType + + VkStructureType sType const void* pNext const StdVideoDecodeH265ReferenceInfo* pStdReferenceInfo @@ -6303,6 +6671,16 @@ typedef void* MTLSharedEvent_id; const void* pNext uint32_t updateSequenceCount + + VkStructureType sType + const void* pNext + VkVideoSessionParametersKHR videoSessionParameters + + + VkStructureType sType + void* pNext + VkBool32 hasOverrides + VkStructureType sType const void* pNext @@ -6333,69 +6711,113 @@ typedef void* MTLSharedEvent_id; VkStructureType sType const void* pNext VkVideoEncodeFlagsKHR flags - uint32_t qualityLevel - VkBuffer dstBitstreamBuffer - VkDeviceSize dstBitstreamBufferOffset - VkDeviceSize dstBitstreamBufferMaxRange + VkBuffer dstBuffer + VkDeviceSize dstBufferOffset + VkDeviceSize dstBufferRange VkVideoPictureResourceInfoKHR srcPictureResource const VkVideoReferenceSlotInfoKHR* pSetupReferenceSlot uint32_t referenceSlotCount const VkVideoReferenceSlotInfoKHR* pReferenceSlots uint32_t precedingExternallyEncodedBytes - + + VkStructureType sType + const void* pNext + VkVideoEncodeFeedbackFlagsKHR encodeFeedbackFlags + + + VkStructureType sType + const void* pNext + uint32_t qualityLevel + + + VkStructureType sType + const void* pNext + const VkVideoProfileInfoKHR* pVideoProfile + uint32_t qualityLevel + + + VkStructureType sType + void* pNext + VkVideoEncodeRateControlModeFlagBitsKHR preferredRateControlMode + uint32_t preferredRateControlLayerCount + + VkStructureType sType - const void* pNext + const void* pNext VkVideoEncodeRateControlFlagsKHR flags - VkVideoEncodeRateControlModeFlagBitsKHR rateControlMode - uint8_t layerCount - const VkVideoEncodeRateControlLayerInfoKHR* pLayerConfigs + VkVideoEncodeRateControlModeFlagBitsKHR rateControlMode + uint32_t layerCount + const VkVideoEncodeRateControlLayerInfoKHR* pLayers + uint32_t virtualBufferSizeInMs + uint32_t initialVirtualBufferSizeInMs - + VkStructureType sType - const void* pNext - uint32_t averageBitrate - uint32_t maxBitrate - uint32_t frameRateNumerator - uint32_t frameRateDenominator - uint32_t virtualBufferSizeInMs - uint32_t initialVirtualBufferSizeInMs + const void* pNext + uint64_t averageBitrate + uint64_t maxBitrate + uint32_t frameRateNumerator + uint32_t frameRateDenominator VkStructureType sType void* pNext VkVideoEncodeCapabilityFlagsKHR flags VkVideoEncodeRateControlModeFlagsKHR rateControlModes - uint8_t rateControlLayerCount - uint8_t qualityLevelCount - VkExtent2D inputImageDataFillAlignment + uint32_t maxRateControlLayers + uint64_t maxBitrate + uint32_t maxQualityLevels + VkExtent2D encodeInputPictureGranularity + VkVideoEncodeFeedbackFlagsKHR supportedEncodeFeedbackFlags VkStructureType sType void* pNext - VkVideoEncodeH264CapabilityFlagsEXT flags - VkVideoEncodeH264InputModeFlagsEXT inputModeFlags - VkVideoEncodeH264OutputModeFlagsEXT outputModeFlags - uint8_t maxPPictureL0ReferenceCount - uint8_t maxBPictureL0ReferenceCount - uint8_t maxL1ReferenceCount - VkBool32 motionVectorsOverPicBoundariesFlag - uint32_t maxBytesPerPicDenom - uint32_t maxBitsPerMbDenom - uint32_t log2MaxMvLengthHorizontal - uint32_t log2MaxMvLengthVertical + VkVideoEncodeH264CapabilityFlagsEXT flags + StdVideoH264LevelIdc maxLevelIdc + uint32_t maxSliceCount + uint32_t maxPPictureL0ReferenceCount + uint32_t maxBPictureL0ReferenceCount + uint32_t maxL1ReferenceCount + uint32_t maxTemporalLayerCount + VkBool32 expectDyadicTemporalLayerPattern + int32_t minQp + int32_t maxQp + VkBool32 prefersGopRemainingFrames + VkBool32 requiresGopRemainingFrames + VkVideoEncodeH264StdFlagsEXT stdSyntaxFlags + + + VkStructureType sType + void* pNext + VkVideoEncodeH264RateControlFlagsEXT preferredRateControlFlags + uint32_t preferredGopFrameCount + uint32_t preferredIdrPeriod + uint32_t preferredConsecutiveBFrameCount + uint32_t preferredTemporalLayerCount + VkVideoEncodeH264QpEXT preferredConstantQp + uint32_t preferredMaxL0ReferenceCount + uint32_t preferredMaxL1ReferenceCount + VkBool32 preferredStdEntropyCodingModeFlag #include "vk_video/vulkan_video_codec_h264std_encode.h" - + + + VkStructureType sType + const void* pNext + VkBool32 useMaxLevelIdc + StdVideoH264LevelIdc maxLevelIdc + VkStructureType sType const void* pNext @@ -6406,41 +6828,37 @@ typedef void* MTLSharedEvent_id; VkStructureType sType - const void* pNext + const void* pNext uint32_t maxStdSPSCount uint32_t maxStdPPSCount const VkVideoEncodeH264SessionParametersAddInfoEXT* pParametersAddInfo - + + VkStructureType sType + const void* pNext + VkBool32 writeStdSPS + VkBool32 writeStdPPS + uint32_t stdSPSId + uint32_t stdPPSId + + + VkStructureType sType + void* pNext + VkBool32 hasStdSPSOverrides + VkBool32 hasStdPPSOverrides + + VkStructureType sType - const void* pNext - int8_t slotIndex + const void* pNext const StdVideoEncodeH264ReferenceInfo* pStdReferenceInfo - - VkStructureType sType + + VkStructureType sType const void* pNext - const VkVideoEncodeH264ReferenceListsInfoEXT* pReferenceFinalLists uint32_t naluSliceEntryCount const VkVideoEncodeH264NaluSliceInfoEXT* pNaluSliceEntries - const StdVideoEncodeH264PictureInfo* pCurrentPictureInfo - - - VkStructureType sType - const void* pNext - uint8_t referenceList0EntryCount - const VkVideoEncodeH264DpbSlotInfoEXT* pReferenceList0Entries - uint8_t referenceList1EntryCount - const VkVideoEncodeH264DpbSlotInfoEXT* pReferenceList1Entries - const StdVideoEncodeH264RefMemMgmtCtrlOperations* pMemMgmtCtrlOperations - - - VkStructureType sType - const void* pNext - uint8_t spsId - VkBool32 emitSpsEnable - uint32_t ppsIdEntryCount - const uint8_t* ppsIdEntries + const StdVideoEncodeH264PictureInfo* pStdPictureInfo + VkBool32 generatePrefixNalu VkStructureType sType @@ -6450,18 +6868,17 @@ typedef void* MTLSharedEvent_id; VkStructureType sType const void* pNext - uint32_t mbCount - const VkVideoEncodeH264ReferenceListsInfoEXT* pReferenceFinalLists - const StdVideoEncodeH264SliceHeader* pSliceHeaderStd + int32_t constantQp + const StdVideoEncodeH264SliceHeader* pStdSliceHeader - + VkStructureType sType const void* pNext + VkVideoEncodeH264RateControlFlagsEXT flags uint32_t gopFrameCount uint32_t idrPeriod uint32_t consecutiveBFrameCount - VkVideoEncodeH264RateControlStructureEXT rateControlStructure - uint8_t temporalLayerCount + uint32_t temporalLayerCount int32_t qpI @@ -6473,12 +6890,17 @@ typedef void* MTLSharedEvent_id; uint32_t framePSize uint32_t frameBSize - + + VkStructureType sType + const void* pNext + VkBool32 useGopRemainingFrames + uint32_t gopRemainingI + uint32_t gopRemainingP + uint32_t gopRemainingB + + VkStructureType sType const void* pNext - uint8_t temporalLayerId - VkBool32 useInitialRcQp - VkVideoEncodeH264QpEXT initialRcQp VkBool32 useMinQp VkVideoEncodeH264QpEXT minQp VkBool32 useMaxQp @@ -6489,36 +6911,50 @@ typedef void* MTLSharedEvent_id; VkStructureType sType void* pNext - VkVideoEncodeH265CapabilityFlagsEXT flags - VkVideoEncodeH265InputModeFlagsEXT inputModeFlags - VkVideoEncodeH265OutputModeFlagsEXT outputModeFlags + VkVideoEncodeH265CapabilityFlagsEXT flags + StdVideoH265LevelIdc maxLevelIdc + uint32_t maxSliceSegmentCount + VkExtent2D maxTiles VkVideoEncodeH265CtbSizeFlagsEXT ctbSizes VkVideoEncodeH265TransformBlockSizeFlagsEXT transformBlockSizes - uint8_t maxPPictureL0ReferenceCount - uint8_t maxBPictureL0ReferenceCount - uint8_t maxL1ReferenceCount - uint8_t maxSubLayersCount - uint8_t minLog2MinLumaCodingBlockSizeMinus3 - uint8_t maxLog2MinLumaCodingBlockSizeMinus3 - uint8_t minLog2MinLumaTransformBlockSizeMinus2 - uint8_t maxLog2MinLumaTransformBlockSizeMinus2 - uint8_t minMaxTransformHierarchyDepthInter - uint8_t maxMaxTransformHierarchyDepthInter - uint8_t minMaxTransformHierarchyDepthIntra - uint8_t maxMaxTransformHierarchyDepthIntra - uint8_t maxDiffCuQpDeltaDepth - uint8_t minMaxNumMergeCand - uint8_t maxMaxNumMergeCand + uint32_t maxPPictureL0ReferenceCount + uint32_t maxBPictureL0ReferenceCount + uint32_t maxL1ReferenceCount + uint32_t maxSubLayerCount + VkBool32 expectDyadicTemporalSubLayerPattern + int32_t minQp + int32_t maxQp + VkBool32 prefersGopRemainingFrames + VkBool32 requiresGopRemainingFrames + VkVideoEncodeH265StdFlagsEXT stdSyntaxFlags + + + VkStructureType sType + void* pNext + VkVideoEncodeH265RateControlFlagsEXT preferredRateControlFlags + uint32_t preferredGopFrameCount + uint32_t preferredIdrPeriod + uint32_t preferredConsecutiveBFrameCount + uint32_t preferredSubLayerCount + VkVideoEncodeH265QpEXT preferredConstantQp + uint32_t preferredMaxL0ReferenceCount + uint32_t preferredMaxL1ReferenceCount #include "vk_video/vulkan_video_codec_h265std_encode.h" - + + + VkStructureType sType + const void* pNext + VkBool32 useMaxLevelIdc + StdVideoH265LevelIdc maxLevelIdc + VkStructureType sType const void* pNext @@ -6537,39 +6973,44 @@ typedef void* MTLSharedEvent_id; uint32_t maxStdPPSCount const VkVideoEncodeH265SessionParametersAddInfoEXT* pParametersAddInfo - - VkStructureType sType + + VkStructureType sType + const void* pNext + VkBool32 writeStdVPS + VkBool32 writeStdSPS + VkBool32 writeStdPPS + uint32_t stdVPSId + uint32_t stdSPSId + uint32_t stdPPSId + + + VkStructureType sType + void* pNext + VkBool32 hasStdVPSOverrides + VkBool32 hasStdSPSOverrides + VkBool32 hasStdPPSOverrides + + + VkStructureType sType const void* pNext - const VkVideoEncodeH265ReferenceListsInfoEXT* pReferenceFinalLists uint32_t naluSliceSegmentEntryCount const VkVideoEncodeH265NaluSliceSegmentInfoEXT* pNaluSliceSegmentEntries - const StdVideoEncodeH265PictureInfo* pCurrentPictureInfo - - - VkStructureType sType - const void* pNext - uint8_t vpsId - uint8_t spsId - VkBool32 emitVpsEnable - VkBool32 emitSpsEnable - uint32_t ppsIdEntryCount - const uint8_t* ppsIdEntries + const StdVideoEncodeH265PictureInfo* pStdPictureInfo VkStructureType sType const void* pNext - uint32_t ctbCount - const VkVideoEncodeH265ReferenceListsInfoEXT* pReferenceFinalLists - const StdVideoEncodeH265SliceSegmentHeader* pSliceSegmentHeaderStd + int32_t constantQp + const StdVideoEncodeH265SliceSegmentHeader* pStdSliceSegmentHeader - + VkStructureType sType const void* pNext + VkVideoEncodeH265RateControlFlagsEXT flags uint32_t gopFrameCount uint32_t idrPeriod uint32_t consecutiveBFrameCount - VkVideoEncodeH265RateControlStructureEXT rateControlStructure - uint8_t subLayerCount + uint32_t subLayerCount int32_t qpI @@ -6581,12 +7022,17 @@ typedef void* MTLSharedEvent_id; uint32_t framePSize uint32_t frameBSize - + + VkStructureType sType + const void* pNext + VkBool32 useGopRemainingFrames + uint32_t gopRemainingI + uint32_t gopRemainingP + uint32_t gopRemainingB + + VkStructureType sType const void* pNext - uint8_t temporalId - VkBool32 useInitialRcQp - VkVideoEncodeH265QpEXT initialRcQp VkBool32 useMinQp VkVideoEncodeH265QpEXT minQp VkBool32 useMaxQp @@ -6599,21 +7045,11 @@ typedef void* MTLSharedEvent_id; const void* pNext StdVideoH265ProfileIdc stdProfileIdc - + VkStructureType sType const void* pNext - int8_t slotIndex const StdVideoEncodeH265ReferenceInfo* pStdReferenceInfo - - VkStructureType sType - const void* pNext - uint8_t referenceList0EntryCount - const VkVideoEncodeH265DpbSlotInfoEXT* pReferenceList0Entries - uint8_t referenceList1EntryCount - const VkVideoEncodeH265DpbSlotInfoEXT* pReferenceList1Entries - const StdVideoEncodeH265ReferenceModifications* pReferenceModifications - VkStructureType sType void* pNext @@ -6754,7 +7190,7 @@ typedef void* MTLSharedEvent_id; const VkDescriptorAddressInfoEXT* pStorageTexelBuffer const VkDescriptorAddressInfoEXT* pUniformBuffer const VkDescriptorAddressInfoEXT* pStorageBuffer - VkDeviceAddress accelerationStructure + VkDeviceAddress accelerationStructure VkStructureType sType @@ -7100,7 +7536,8 @@ typedef void* MTLSharedEvent_id; const void* pNext VkRenderingFlags flags uint32_t viewMask - uint32_t colorAttachmentCount + uint32_t colorAttachmentCount + uint32_t colorAttachmentCount const VkFormat* pColorAttachmentFormats VkFormat depthAttachmentFormat VkFormat stencilAttachmentFormat @@ -7351,7 +7788,42 @@ typedef void* MTLSharedEvent_id; uint32_t usageCountsCount const VkMicromapUsageEXT* pUsageCounts const VkMicromapUsageEXT* const* ppUsageCounts - VkMicromapEXT micromap + VkMicromapEXT micromap + + + VkStructureType sType + void* pNext + VkBool32 displacementMicromap + + + VkStructureType sType + void* pNext + uint32_t maxDisplacementMicromapSubdivisionLevel + + + VkStructureType sType + void* pNext + + VkFormat displacementBiasAndScaleFormat + VkFormat displacementVectorFormat + + VkDeviceOrHostAddressConstKHR displacementBiasAndScaleBuffer + VkDeviceSize displacementBiasAndScaleStride + VkDeviceOrHostAddressConstKHR displacementVectorBuffer + VkDeviceSize displacementVectorStride + VkDeviceOrHostAddressConstKHR displacedMicromapPrimitiveFlags + VkDeviceSize displacedMicromapPrimitiveFlagsStride + VkIndexType indexType + VkDeviceOrHostAddressConstKHR indexBuffer + VkDeviceSize indexStride + + uint32_t baseTriangle + + uint32_t usageCountsCount + const VkMicromapUsageEXT* pUsageCounts + const VkMicromapUsageEXT* const* ppUsageCounts + + VkMicromapEXT micromap VkStructureType sType @@ -7368,6 +7840,11 @@ typedef void* MTLSharedEvent_id; void* pNext VkBool32 shaderEarlyAndLateFragmentTests + + VkStructureType sType + const void* pNext + VkBool32 acquireUnmodifiedMemory + VkStructureType sType const void* pNext @@ -7630,6 +8107,26 @@ typedef void* MTLSharedEvent_id; uint32_t applicationNameOffset uint32_t applicationVersion uint32_t engineNameOffset + uint32_t engineVersion + uint32_t apiVersion + + + VkStructureType sType + void* pNext + VkBool32 pipelineLibraryGroupHandles + + + VkStructureType sType + const void* pNext + float depthBiasConstantFactor + float depthBiasClamp + float depthBiasSlopeFactor + + + VkStructureType sType + const void* pNext + VkDepthBiasRepresentationEXT depthBiasRepresentation + VkBool32 depthBiasExact VkDeviceAddress srcAddress @@ -7650,7 +8147,77 @@ typedef void* MTLSharedEvent_id; void* pNext VkBool32 shaderCoreBuiltins - + + VkStructureType sType + void* pNext + VkBool32 dynamicRenderingUnusedAttachments + + + VkStructureType sType + void* pNext + VkPresentModeKHR presentMode + + + VkStructureType sType + void* pNext + VkPresentScalingFlagsEXT supportedPresentScaling + VkPresentGravityFlagsEXT supportedPresentGravityX + VkPresentGravityFlagsEXT supportedPresentGravityY + VkExtent2D minScaledImageExtentSupported minimum image width and height for the surface when scaling is used + VkExtent2D maxScaledImageExtentSupported maximum image width and height for the surface when scaling is used + + + VkStructureType sType + void* pNext + uint32_t presentModeCount + VkPresentModeKHR* pPresentModesOutput list of present modes compatible with the one specified in VkSurfacePresentModeEXT + + + VkStructureType sType + void* pNext + VkBool32 swapchainMaintenance1 + + + VkStructureType sType + const void* pNext + uint32_t swapchainCountCopy of VkPresentInfoKHR::swapchainCount + const VkFence* pFencesFence to signal for each swapchain + + + VkStructureType sType + const void* pNext + uint32_t presentModeCountLength of the pPresentModes array + const VkPresentModeKHR* pPresentModesPresentation modes which will be usable with this swapchain + + + VkStructureType sType + const void* pNext + uint32_t swapchainCountCopy of VkPresentInfoKHR::swapchainCount + const VkPresentModeKHR* pPresentModesPresentation mode for each swapchain + + + VkStructureType sType + const void* pNext + VkPresentScalingFlagsEXT scalingBehavior + VkPresentGravityFlagsEXT presentGravityX + VkPresentGravityFlagsEXT presentGravityY + + + VkStructureType sType + const void* pNext + VkSwapchainKHR swapchainSwapchain for which images are being released + uint32_t imageIndexCountNumber of indices to release + const uint32_t* pImageIndicesIndices of which presentable images to release + + + VkStructureType sType + void* pNext + VkBool32 depthBiasControl + VkBool32 leastRepresentableValueForceUnormRepresentation + VkBool32 floatRepresentation + VkBool32 depthBiasExact + + VkStructureType sType void* pNext VkBool32 rayTracingInvocationReorder @@ -7660,6 +8227,141 @@ typedef void* MTLSharedEvent_id; void* pNext VkRayTracingInvocationReorderModeNV rayTracingInvocationReorderReorderingHint + + VkStructureType sType + void* pNext + VkDirectDriverLoadingFlagsLUNARG flags + PFN_vkGetInstanceProcAddrLUNARG pfnGetInstanceProcAddr + + + VkStructureType sType + void* pNext + VkDirectDriverLoadingModeLUNARG mode + uint32_t driverCount + const VkDirectDriverLoadingInfoLUNARG* pDrivers + + + VkStructureType sType + void* pNext + VkBool32 multiviewPerViewViewports + + + VkStructureType sType + void* pNext + VkBool32 rayTracingPositionFetch + + + VkStructureType sType + void* pNext + uint32_t pixelRate + uint32_t texelRate + uint32_t fmaRate + + + VkStructureType sType + void* pNext + VkBool32 multiviewPerViewRenderAreas + + + VkStructureType sType + const void* pNext + uint32_t perViewRenderAreaCount + const VkRect2D* pPerViewRenderAreas + + + VkStructureType sType + const void* pNext + void* pQueriedLowLatencyData + + + VkStructureType sType + const void* pNext + VkMemoryMapFlags flags + VkDeviceMemory memory + VkDeviceSize offset + VkDeviceSize size + + + VkStructureType sType + const void* pNext + VkMemoryUnmapFlagsKHR flags + VkDeviceMemory memory + + + VkStructureType sType + void* pNext + VkBool32 shaderObject + + + VkStructureType sType + void* pNext + uint8_t shaderBinaryUUID[VK_UUID_SIZE] + uint32_t shaderBinaryVersion + + + VkStructureType sType + const void* pNext + VkShaderCreateFlagsEXT flags + VkShaderStageFlagBits stage + VkShaderStageFlags nextStage + VkShaderCodeTypeEXT codeType + size_t codeSize + const void* pCode + const char* pName + uint32_t setLayoutCount + const VkDescriptorSetLayout* pSetLayouts + uint32_t pushConstantRangeCount + const VkPushConstantRange* pPushConstantRanges + const VkSpecializationInfo* pSpecializationInfo + + + VkStructureType sType + void* pNext + VkBool32 shaderTileImageColorReadAccess + VkBool32 shaderTileImageDepthReadAccess + VkBool32 shaderTileImageStencilReadAccess + + + VkStructureType sType + void* pNext + VkBool32 shaderTileImageCoherentReadAccelerated + VkBool32 shaderTileImageReadSampleFromPixelRateInvocation + VkBool32 shaderTileImageReadFromHelperInvocation + + + VkStructureType sType + const void* pNext + struct _screen_buffer* buffer + + + VkStructureType sType + void* pNext + VkDeviceSize allocationSize + uint32_t memoryTypeBits + + + VkStructureType sType + void* pNext + VkFormat format + uint64_t externalFormat + uint64_t screenUsage + VkFormatFeatureFlags formatFeatures + VkComponentMapping samplerYcbcrConversionComponents + VkSamplerYcbcrModelConversion suggestedYcbcrModel + VkSamplerYcbcrRange suggestedYcbcrRange + VkChromaLocation suggestedXChromaOffset + VkChromaLocation suggestedYChromaOffset + + + VkStructureType sType + void* pNext + uint64_t externalFormat + + + VkStructureType sType + void* pNext + VkBool32 screenBufferImport + @@ -7677,6 +8379,7 @@ typedef void* MTLSharedEvent_id; + @@ -8242,6 +8945,10 @@ typedef void* MTLSharedEvent_id; + + + + Flags @@ -8455,7 +9162,7 @@ typedef void* MTLSharedEvent_id; - + @@ -8480,7 +9187,7 @@ typedef void* MTLSharedEvent_id; - + @@ -8551,7 +9258,7 @@ typedef void* MTLSharedEvent_id; - + NVX_device_generated_commands formerly used these enum values, but that extension has been removed @@ -8559,7 +9266,7 @@ typedef void* MTLSharedEvent_id; value 32 / name VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT - + @@ -8680,7 +9387,7 @@ typedef void* MTLSharedEvent_id; - + @@ -8819,7 +9526,8 @@ typedef void* MTLSharedEvent_id; - + + Driver IDs are now represented as enums instead of the old @@ -8848,6 +9556,8 @@ typedef void* MTLSharedEvent_id; + + @@ -8995,9 +9705,9 @@ typedef void* MTLSharedEvent_id; - - - + + + @@ -9025,14 +9735,16 @@ typedef void* MTLSharedEvent_id; - + - + + + @@ -9075,6 +9787,24 @@ typedef void* MTLSharedEvent_id; + + + + + + + + + + + + + + + + + + @@ -9087,6 +9817,9 @@ typedef void* MTLSharedEvent_id; + + + @@ -9236,10 +9969,22 @@ typedef void* MTLSharedEvent_id; + + + + + + + + + + + + @@ -9262,6 +10007,16 @@ typedef void* MTLSharedEvent_id; + + + + + + + + + + @@ -9286,10 +10041,10 @@ typedef void* MTLSharedEvent_id; - - - - + + + + @@ -9332,52 +10087,54 @@ typedef void* MTLSharedEvent_id; + + + + + - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -9453,47 +10210,44 @@ typedef void* MTLSharedEvent_id; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -9633,6 +10387,11 @@ typedef void* MTLSharedEvent_id; + + + + + @@ -9645,6 +10404,19 @@ typedef void* MTLSharedEvent_id; + + + + + + + + + + + + + VkResult vkCreateInstance @@ -9713,7 +10485,14 @@ typedef void* MTLSharedEvent_id; VkImageCreateFlags flags VkImageFormatProperties* pImageFormatProperties - + + VkResult vkCreateDevice + VkPhysicalDevice physicalDevice + const VkDeviceCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkDevice* pDevice + + VkResult vkCreateDevice VkPhysicalDevice physicalDevice const VkDeviceCreateInfo* pCreateInfo @@ -9743,12 +10522,19 @@ typedef void* MTLSharedEvent_id; uint32_t* pPropertyCount VkExtensionProperties* pProperties - + + VkResult vkEnumerateDeviceLayerProperties + VkPhysicalDevice physicalDevice + uint32_t* pPropertyCount + VkLayerProperties* pProperties + + VkResult vkEnumerateDeviceLayerProperties VkPhysicalDevice physicalDevice uint32_t* pPropertyCount VkLayerProperties* pProperties + VkResult vkEnumerateDeviceExtensionProperties VkPhysicalDevice physicalDevice @@ -10054,7 +10840,14 @@ typedef void* MTLSharedEvent_id; VkShaderModule shaderModule const VkAllocationCallbacks* pAllocator - + + VkResult vkCreatePipelineCache + VkDevice device + const VkPipelineCacheCreateInfo* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkPipelineCache* pPipelineCache + + VkResult vkCreatePipelineCache VkDevice device const VkPipelineCacheCreateInfo* pCreateInfo @@ -10081,7 +10874,7 @@ typedef void* MTLSharedEvent_id; uint32_t srcCacheCount const VkPipelineCache* pSrcCaches - + VkResult vkCreateGraphicsPipelines VkDevice device VkPipelineCache pipelineCache @@ -10090,12 +10883,30 @@ typedef void* MTLSharedEvent_id; const VkAllocationCallbacks* pAllocator VkPipeline* pPipelines - - VkResult vkCreateComputePipelines + + VkResult vkCreateGraphicsPipelines VkDevice device - VkPipelineCache pipelineCache + VkPipelineCache pipelineCache uint32_t createInfoCount - const VkComputePipelineCreateInfo* pCreateInfos + const VkGraphicsPipelineCreateInfo* pCreateInfos + const VkAllocationCallbacks* pAllocator + VkPipeline* pPipelines + + + VkResult vkCreateComputePipelines + VkDevice device + VkPipelineCache pipelineCache + uint32_t createInfoCount + const VkComputePipelineCreateInfo* pCreateInfos + const VkAllocationCallbacks* pAllocator + VkPipeline* pPipelines + + + VkResult vkCreateComputePipelines + VkDevice device + VkPipelineCache pipelineCache + uint32_t createInfoCount + const VkComputePipelineCreateInfo* pCreateInfos const VkAllocationCallbacks* pAllocator VkPipeline* pPipelines @@ -10265,7 +11076,7 @@ typedef void* MTLSharedEvent_id; the sname:VkCommandPool that pname:commandBuffer was allocated from - + VkResult vkEndCommandBuffer VkCommandBuffer commandBuffer @@ -10286,6 +11097,11 @@ typedef void* MTLSharedEvent_id; VkPipelineBindPoint pipelineBindPoint VkPipeline pipeline + + void vkCmdSetAttachmentFeedbackLoopEnableEXT + VkCommandBuffer commandBuffer + VkImageAspectFlags aspectMask + void vkCmdSetViewport VkCommandBuffer commandBuffer @@ -10436,6 +11252,19 @@ typedef void* MTLSharedEvent_id; void vkCmdSubpassShadingHUAWEI VkCommandBuffer commandBuffer + + void vkCmdDrawClusterHUAWEI + VkCommandBuffer commandBuffer + uint32_t groupCountX + uint32_t groupCountY + uint32_t groupCountZ + + + void vkCmdDrawClusterIndirectHUAWEI + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + void vkCmdCopyBuffer VkCommandBuffer commandBuffer @@ -10613,14 +11442,14 @@ typedef void* MTLSharedEvent_id; void vkCmdEndConditionalRenderingEXT VkCommandBuffer commandBuffer - + void vkCmdResetQueryPool VkCommandBuffer commandBuffer VkQueryPool queryPool uint32_t firstQuery uint32_t queryCount - + void vkCmdWriteTimestamp VkCommandBuffer commandBuffer VkPipelineStageFlagBits pipelineStage @@ -10727,7 +11556,8 @@ typedef void* MTLSharedEvent_id; VkResult vkCreateSharedSwapchainsKHR VkDevice device uint32_t swapchainCount - const VkSwapchainCreateInfoKHR* pCreateInfos + const VkSwapchainCreateInfoKHR* pCreateInfos + const VkSwapchainCreateInfoKHR* pCreateInfos const VkAllocationCallbacks* pAllocator VkSwapchainKHR* pSwapchains @@ -10767,7 +11597,8 @@ typedef void* MTLSharedEvent_id; VkResult vkCreateSwapchainKHR VkDevice device - const VkSwapchainCreateInfoKHR* pCreateInfo + const VkSwapchainCreateInfoKHR* pCreateInfo + const VkSwapchainCreateInfoKHR* pCreateInfo const VkAllocationCallbacks* pAllocator VkSwapchainKHR* pSwapchain @@ -11116,6 +11947,24 @@ typedef void* MTLSharedEvent_id; const VkMemoryGetRemoteAddressInfoNV* pMemoryGetRemoteAddressInfo VkRemoteAddressNV* pAddress + + VkResult vkGetMemorySciBufNV + VkDevice device + const VkMemoryGetSciBufInfoNV* pGetSciBufInfo + NvSciBufObj* pHandle + + + VkResult vkGetPhysicalDeviceExternalMemorySciBufPropertiesNV + VkPhysicalDevice physicalDevice + VkExternalMemoryHandleTypeFlagBits handleType + NvSciBufObj handle + VkMemorySciBufPropertiesNV* pMemorySciBufProperties + + + VkResult vkGetPhysicalDeviceSciBufAttributesNV + VkPhysicalDevice physicalDevice + NvSciBufAttrList pAttributes + void vkGetPhysicalDeviceExternalSemaphoreProperties VkPhysicalDevice physicalDevice @@ -11185,6 +12034,58 @@ typedef void* MTLSharedEvent_id; VkDevice device const VkImportFenceFdInfoKHR* pImportFenceFdInfo + + VkResult vkGetFenceSciSyncFenceNV + VkDevice device + const VkFenceGetSciSyncInfoNV* pGetSciSyncHandleInfo + void* pHandle + + + VkResult vkGetFenceSciSyncObjNV + VkDevice device + const VkFenceGetSciSyncInfoNV* pGetSciSyncHandleInfo + void* pHandle + + + VkResult vkImportFenceSciSyncFenceNV + VkDevice device + const VkImportFenceSciSyncInfoNV* pImportFenceSciSyncInfo + + + VkResult vkImportFenceSciSyncObjNV + VkDevice device + const VkImportFenceSciSyncInfoNV* pImportFenceSciSyncInfo + + + VkResult vkGetSemaphoreSciSyncObjNV + VkDevice device + const VkSemaphoreGetSciSyncInfoNV* pGetSciSyncInfo + void* pHandle + + + VkResult vkImportSemaphoreSciSyncObjNV + VkDevice device + const VkImportSemaphoreSciSyncInfoNV* pImportSemaphoreSciSyncInfo + + + VkResult vkGetPhysicalDeviceSciSyncAttributesNV + VkPhysicalDevice physicalDevice + const VkSciSyncAttributesInfoNV* pSciSyncAttributesInfo + NvSciSyncAttrList pAttributes + + + VkResult vkCreateSemaphoreSciSyncPoolNV + VkDevice device + const VkSemaphoreSciSyncPoolCreateInfoNV* pCreateInfo + const VkAllocationCallbacks* pAllocator + VkSemaphoreSciSyncPoolNV* pSemaphorePool + + + void vkDestroySemaphoreSciSyncPoolNV + VkDevice device + VkSemaphoreSciSyncPoolNV semaphorePool + const VkAllocationCallbacks* pAllocator + VkResult vkReleaseDisplayEXT VkPhysicalDevice physicalDevice @@ -11410,6 +12311,16 @@ typedef void* MTLSharedEvent_id; uint32_t discardRectangleCount const VkRect2D* pDiscardRectangles + + void vkCmdSetDiscardRectangleEnableEXT + VkCommandBuffer commandBuffer + VkBool32 discardRectangleEnable + + + void vkCmdSetDiscardRectangleModeEXT + VkCommandBuffer commandBuffer + VkDiscardRectangleModeEXT discardRectangleMode + void vkCmdSetSampleLocationsEXT VkCommandBuffer commandBuffer @@ -11844,6 +12755,13 @@ typedef void* MTLSharedEvent_id; uint32_t exclusiveScissorCount const VkRect2D* pExclusiveScissors + + void vkCmdSetExclusiveScissorEnableNV + VkCommandBuffer commandBuffer + uint32_t firstExclusiveScissor + uint32_t exclusiveScissorCount + const VkBool32* pExclusiveScissorEnables + void vkCmdBindShadingRateImageNV VkCommandBuffer commandBuffer @@ -12091,7 +13009,7 @@ typedef void* MTLSharedEvent_id; size_t dataSize void* pData - + VkResult vkCreateRayTracingPipelinesNV VkDevice device VkPipelineCache pipelineCache @@ -12100,7 +13018,16 @@ typedef void* MTLSharedEvent_id; const VkAllocationCallbacks* pAllocator VkPipeline* pPipelines - + + VkResult vkCreateRayTracingPipelinesNV + VkDevice device + VkPipelineCache pipelineCache + uint32_t createInfoCount + const VkRayTracingPipelineCreateInfoNV* pCreateInfos + const VkAllocationCallbacks* pAllocator + VkPipeline* pPipelines + + VkResult vkCreateRayTracingPipelinesKHR VkDevice device VkDeferredOperationKHR deferredOperation @@ -12110,6 +13037,16 @@ typedef void* MTLSharedEvent_id; const VkAllocationCallbacks* pAllocator VkPipeline* pPipelines + + VkResult vkCreateRayTracingPipelinesKHR + VkDevice device + VkDeferredOperationKHR deferredOperation + VkPipelineCache pipelineCache + uint32_t createInfoCount + const VkRayTracingPipelineCreateInfoKHR* pCreateInfos + const VkAllocationCallbacks* pAllocator + VkPipeline* pPipelines + VkResult vkGetPhysicalDeviceCooperativeMatrixPropertiesNV VkPhysicalDevice physicalDevice @@ -12316,6 +13253,14 @@ typedef void* MTLSharedEvent_id; uint32_t lineStippleFactor uint16_t lineStipplePattern + + VkResult vkGetFaultData + VkDevice device + VkFaultQueryBehavior faultQueryBehavior + VkBool32* pUnrecordedFaults + uint32_t* pFaultCount + VkFaultData* pFaults + VkResult vkGetPhysicalDeviceToolProperties VkPhysicalDevice physicalDevice @@ -12733,6 +13678,17 @@ typedef void* MTLSharedEvent_id; const VkResolveImageInfo2* pResolveImageInfo + + void vkCmdRefreshObjectsKHR + VkCommandBuffer commandBuffer + const VkRefreshObjectListKHR* pRefreshObjects + + + VkResult vkGetPhysicalDeviceRefreshableObjectTypesKHR + VkPhysicalDevice physicalDevice + uint32_t* pRefreshableObjectTypeCount + VkObjectType* pRefreshableObjectTypes + void vkCmdSetFragmentShadingRateKHR VkCommandBuffer commandBuffer @@ -12831,6 +13787,13 @@ typedef void* MTLSharedEvent_id; uint32_t* pCheckpointDataCount VkCheckpointData2NV* pCheckpointData + + void vkGetCommandPoolMemoryConsumption + VkDevice device + VkCommandPool commandPool + VkCommandBuffer commandBuffer + VkCommandPoolMemoryConsumption* pConsumption + VkResult vkGetPhysicalDeviceVideoCapabilitiesKHR VkPhysicalDevice physicalDevice @@ -12844,7 +13807,13 @@ typedef void* MTLSharedEvent_id; uint32_t* pVideoFormatPropertyCount VkVideoFormatPropertiesKHR* pVideoFormatProperties - + + VkResult vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR + VkPhysicalDevice physicalDevice + const VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR* pQualityLevelInfo + VkVideoEncodeQualityLevelPropertiesKHR* pQualityLevelProperties + + VkResult vkCreateVideoSessionKHR VkDevice device const VkVideoSessionCreateInfoKHR* pCreateInfo @@ -12857,33 +13826,41 @@ typedef void* MTLSharedEvent_id; VkVideoSessionKHR videoSession const VkAllocationCallbacks* pAllocator - + VkResult vkCreateVideoSessionParametersKHR VkDevice device const VkVideoSessionParametersCreateInfoKHR* pCreateInfo const VkAllocationCallbacks* pAllocator VkVideoSessionParametersKHR* pVideoSessionParameters - + VkResult vkUpdateVideoSessionParametersKHR VkDevice device VkVideoSessionParametersKHR videoSessionParameters const VkVideoSessionParametersUpdateInfoKHR* pUpdateInfo + + VkResult vkGetEncodedVideoSessionParametersKHR + VkDevice device + const VkVideoEncodeSessionParametersGetInfoKHR* pVideoSessionParametersInfo + VkVideoEncodeSessionParametersFeedbackInfoKHR* pFeedbackInfo + size_t* pDataSize + void* pData + void vkDestroyVideoSessionParametersKHR VkDevice device VkVideoSessionParametersKHR videoSessionParameters const VkAllocationCallbacks* pAllocator - + VkResult vkGetVideoSessionMemoryRequirementsKHR VkDevice device VkVideoSessionKHR videoSession uint32_t* pMemoryRequirementsCount VkVideoSessionMemoryRequirementsKHR* pMemoryRequirements - + VkResult vkBindVideoSessionMemoryKHR VkDevice device VkVideoSessionKHR videoSession @@ -13287,9 +14264,64 @@ typedef void* MTLSharedEvent_id; VkDeviceFaultCountsEXT* pFaultCounts VkDeviceFaultInfoEXT* pFaultInfo + + void vkCmdSetDepthBias2EXT + VkCommandBuffer commandBuffer + const VkDepthBiasInfoEXT* pDepthBiasInfo + + + VkResult vkReleaseSwapchainImagesEXT + VkDevice device + const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo + + + VkResult vkMapMemory2KHR + VkDevice device + const VkMemoryMapInfoKHR* pMemoryMapInfo + void** ppData + + + VkResult vkUnmapMemory2KHR + VkDevice device + const VkMemoryUnmapInfoKHR* pMemoryUnmapInfo + + + VkResult vkCreateShadersEXT + VkDevice device + uint32_t createInfoCount + const VkShaderCreateInfoEXT* pCreateInfos + const VkAllocationCallbacks* pAllocator + VkShaderEXT* pShaders + + + void vkDestroyShaderEXT + VkDevice device + VkShaderEXT shader + const VkAllocationCallbacks* pAllocator + + + VkResult vkGetShaderBinaryDataEXT + VkDevice device + VkShaderEXT shader + size_t* pDataSize + void* pData + + + void vkCmdBindShadersEXT + VkCommandBuffer commandBuffer + uint32_t stageCount + const VkShaderStageFlagBits* pStages + const VkShaderEXT* pShaders + + + VkResult vkGetScreenBufferPropertiesQNX + VkDevice device + const struct _screen_buffer* buffer + VkScreenBufferPropertiesQNX* pProperties + - + @@ -13803,7 +14835,7 @@ typedef void* MTLSharedEvent_id; - + @@ -13957,7 +14989,7 @@ typedef void* MTLSharedEvent_id; - + @@ -14130,12 +15162,12 @@ typedef void* MTLSharedEvent_id; - + - + @@ -14330,7 +15362,7 @@ typedef void* MTLSharedEvent_id; - + @@ -14595,8 +15627,142 @@ typedef void* MTLSharedEvent_id; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -14618,7 +15784,7 @@ typedef void* MTLSharedEvent_id; - + @@ -14639,7 +15805,7 @@ typedef void* MTLSharedEvent_id; - + This duplicates definitions in VK_KHR_device_group below @@ -14663,7 +15829,7 @@ typedef void* MTLSharedEvent_id; - + @@ -14694,7 +15860,7 @@ typedef void* MTLSharedEvent_id; - + @@ -14704,7 +15870,7 @@ typedef void* MTLSharedEvent_id; - + @@ -14715,7 +15881,7 @@ typedef void* MTLSharedEvent_id; - + @@ -14726,7 +15892,7 @@ typedef void* MTLSharedEvent_id; - + @@ -14737,13 +15903,13 @@ typedef void* MTLSharedEvent_id; - + - + @@ -14754,7 +15920,7 @@ typedef void* MTLSharedEvent_id; - + @@ -14792,8 +15958,9 @@ typedef void* MTLSharedEvent_id; - - + + + @@ -14805,7 +15972,7 @@ typedef void* MTLSharedEvent_id; - + This duplicates definitions in other extensions, below @@ -14818,18 +15985,18 @@ typedef void* MTLSharedEvent_id; - + - + - + @@ -14879,7 +16046,7 @@ typedef void* MTLSharedEvent_id; - + @@ -14897,40 +16064,40 @@ typedef void* MTLSharedEvent_id; - + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - + + - - + + - - - - - - + + + + + + @@ -14986,28 +16153,28 @@ typedef void* MTLSharedEvent_id; - + - + - - - - + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + @@ -15022,9 +16189,9 @@ typedef void* MTLSharedEvent_id; - - - + + + @@ -15051,7 +16218,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15163,111 +16330,120 @@ typedef void* MTLSharedEvent_id; - + - + - + - + - + + + + - - - - + + + + - - - + + + - + + + - + - + - + - + - + + + + - - - - - + + + + - - + + + - - + + + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - + @@ -15291,7 +16467,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15311,27 +16487,27 @@ typedef void* MTLSharedEvent_id; - + - + - + - + - + - + - + @@ -15360,7 +16536,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15370,7 +16546,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15379,10 +16555,11 @@ typedef void* MTLSharedEvent_id; - + - - + + + @@ -15391,7 +16568,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15430,7 +16607,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15440,7 +16617,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15451,7 +16628,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15459,7 +16636,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15490,7 +16667,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15520,14 +16697,14 @@ typedef void* MTLSharedEvent_id; - + - + @@ -15536,7 +16713,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15560,7 +16737,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15570,7 +16747,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15588,7 +16765,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15610,7 +16787,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15620,7 +16797,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15634,12 +16811,12 @@ typedef void* MTLSharedEvent_id; - + - - + + @@ -15648,7 +16825,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15661,7 +16838,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15694,7 +16871,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15708,7 +16885,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15724,7 +16901,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15738,7 +16915,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15746,7 +16923,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15771,7 +16948,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15782,7 +16959,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15798,7 +16975,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15810,7 +16987,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15819,16 +16996,16 @@ typedef void* MTLSharedEvent_id; - + - + - + @@ -15847,7 +17024,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15857,7 +17034,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15865,7 +17042,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15875,7 +17052,7 @@ typedef void* MTLSharedEvent_id; - + @@ -15891,11 +17068,11 @@ typedef void* MTLSharedEvent_id; - + - + @@ -15916,14 +17093,14 @@ typedef void* MTLSharedEvent_id; - + - + @@ -15931,19 +17108,19 @@ typedef void* MTLSharedEvent_id; - + - + - + @@ -15964,7 +17141,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16004,11 +17181,11 @@ typedef void* MTLSharedEvent_id; - - + + - + @@ -16029,18 +17206,22 @@ typedef void* MTLSharedEvent_id; - + - + + + + + @@ -16049,7 +17230,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16061,7 +17242,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16076,9 +17257,10 @@ typedef void* MTLSharedEvent_id; + - + @@ -16096,10 +17278,10 @@ typedef void* MTLSharedEvent_id; - + - + @@ -16121,7 +17303,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16136,7 +17318,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16166,7 +17348,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16178,7 +17360,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16202,7 +17384,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16213,7 +17395,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16227,7 +17409,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16239,7 +17421,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16271,13 +17453,17 @@ typedef void* MTLSharedEvent_id; + + + + - + - - + + @@ -16305,7 +17491,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16319,7 +17505,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16329,7 +17515,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16349,7 +17535,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16359,7 +17545,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16375,21 +17561,21 @@ typedef void* MTLSharedEvent_id; - + - + - + @@ -16399,7 +17585,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16435,7 +17621,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16456,12 +17642,12 @@ typedef void* MTLSharedEvent_id; - + - + @@ -16476,7 +17662,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16519,7 +17705,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16540,7 +17726,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16558,7 +17744,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16581,7 +17767,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16593,7 +17779,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16612,7 +17798,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16620,7 +17806,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16689,7 +17875,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16774,11 +17960,11 @@ typedef void* MTLSharedEvent_id; - + - + @@ -16823,7 +18009,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16854,7 +18040,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16864,13 +18050,13 @@ typedef void* MTLSharedEvent_id; - + - + @@ -16949,11 +18135,11 @@ typedef void* MTLSharedEvent_id; - + - + @@ -16966,7 +18152,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16989,7 +18175,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17019,7 +18205,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17050,7 +18236,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17060,7 +18246,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17088,7 +18274,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17184,7 +18370,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17200,12 +18386,12 @@ typedef void* MTLSharedEvent_id; - + - - + + @@ -17213,7 +18399,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17221,7 +18407,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17256,17 +18442,17 @@ typedef void* MTLSharedEvent_id; - + - - + + - + @@ -17280,7 +18466,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17288,7 +18474,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17310,7 +18496,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17318,7 +18504,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17342,7 +18528,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17353,7 +18539,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17367,28 +18553,28 @@ typedef void* MTLSharedEvent_id; - + - - - - - - - - - + + + + + + + + + - - + + - - - - + + + + - + @@ -17412,7 +18598,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17425,7 +18611,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17460,11 +18646,10 @@ typedef void* MTLSharedEvent_id; - + - + @@ -17488,7 +18673,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17500,14 +18685,14 @@ typedef void* MTLSharedEvent_id; - + - + @@ -17524,14 +18709,14 @@ typedef void* MTLSharedEvent_id; - + - + @@ -17539,7 +18724,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17557,7 +18742,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17565,7 +18750,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17573,19 +18758,21 @@ typedef void* MTLSharedEvent_id; - + - + - + + + - + @@ -17597,7 +18784,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17630,7 +18817,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17643,7 +18830,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17677,7 +18864,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17685,7 +18872,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17693,7 +18880,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17705,7 +18892,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17715,7 +18902,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17729,7 +18916,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17740,7 +18927,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17760,7 +18947,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17777,7 +18964,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17795,8 +18982,8 @@ typedef void* MTLSharedEvent_id; - - + + @@ -17805,7 +18992,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17819,7 +19006,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17843,11 +19030,11 @@ typedef void* MTLSharedEvent_id; - + - + @@ -17863,7 +19050,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17897,7 +19084,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17911,13 +19098,13 @@ typedef void* MTLSharedEvent_id; - + - + @@ -17925,7 +19112,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17935,7 +19122,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17943,7 +19130,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17951,7 +19138,7 @@ typedef void* MTLSharedEvent_id; - + @@ -17980,7 +19167,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18008,13 +19195,13 @@ typedef void* MTLSharedEvent_id; - + - + - + @@ -18027,7 +19214,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18037,7 +19224,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18046,7 +19233,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18061,7 +19248,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18076,7 +19263,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18084,7 +19271,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18092,7 +19279,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18100,7 +19287,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18113,7 +19300,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18127,18 +19314,18 @@ typedef void* MTLSharedEvent_id; - + - + - + - + @@ -18148,7 +19335,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18182,7 +19369,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18197,7 +19384,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18205,7 +19392,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18232,7 +19419,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18247,7 +19434,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18279,7 +19466,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18296,7 +19483,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18321,26 +19508,34 @@ typedef void* MTLSharedEvent_id; - + + - + - - + + + + + + + + + - + - + @@ -18348,19 +19543,43 @@ typedef void* MTLSharedEvent_id; - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -18368,7 +19587,7 @@ typedef void* MTLSharedEvent_id; - + This extension requires buffer_device_address functionality. @@ -18416,7 +19635,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18432,7 +19651,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18442,7 +19661,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18452,7 +19671,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18463,13 +19682,21 @@ typedef void* MTLSharedEvent_id; - + - - + + + + + + + + + + - + @@ -18484,7 +19711,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18492,7 +19719,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18502,7 +19729,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18563,7 +19790,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18578,7 +19805,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18590,13 +19817,13 @@ typedef void* MTLSharedEvent_id; - + - + @@ -18606,7 +19833,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18632,7 +19859,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18646,18 +19873,15 @@ typedef void* MTLSharedEvent_id; - - - - - - - + + + + - + - + @@ -18668,9 +19892,15 @@ typedef void* MTLSharedEvent_id; + + + + + + - + @@ -18678,10 +19908,13 @@ typedef void* MTLSharedEvent_id; + - + + + @@ -18690,6 +19923,10 @@ typedef void* MTLSharedEvent_id; + + + + @@ -18703,14 +19940,23 @@ typedef void* MTLSharedEvent_id; + + + + + + + + + - + - + @@ -18765,10 +20011,17 @@ typedef void* MTLSharedEvent_id; - + - - + + + + + + + + + @@ -18778,10 +20031,12 @@ typedef void* MTLSharedEvent_id; - + - - + + + + @@ -18835,7 +20090,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18874,65 +20129,65 @@ typedef void* MTLSharedEvent_id; - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -18943,7 +20198,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18995,7 +20250,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19021,7 +20276,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19039,7 +20294,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19047,7 +20302,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19057,7 +20312,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19071,7 +20326,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19079,7 +20334,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19094,7 +20349,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19117,7 +20372,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19137,7 +20392,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19147,7 +20402,7 @@ typedef void* MTLSharedEvent_id; - + VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT and @@ -19170,7 +20425,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19181,7 +20436,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19189,13 +20444,13 @@ typedef void* MTLSharedEvent_id; - + - + @@ -19203,7 +20458,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19211,7 +20466,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19245,7 +20500,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19267,7 +20522,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19280,7 +20535,7 @@ typedef void* MTLSharedEvent_id; - + VkPhysicalDevice4444FormatsFeaturesEXT and @@ -19295,9 +20550,9 @@ typedef void* MTLSharedEvent_id; - + - + @@ -19313,7 +20568,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19333,7 +20588,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19341,7 +20596,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19349,7 +20604,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19360,7 +20615,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19372,7 +20627,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19386,7 +20641,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19400,7 +20655,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19410,7 +20665,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19424,7 +20679,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19434,7 +20689,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19460,7 +20715,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19488,7 +20743,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19503,7 +20758,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19516,7 +20771,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19566,7 +20821,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19583,7 +20838,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19595,7 +20850,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19609,7 +20864,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19622,20 +20877,60 @@ typedef void* MTLSharedEvent_id; - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -19644,7 +20939,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19657,7 +20952,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19675,7 +20970,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19698,7 +20993,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19710,7 +21005,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19737,7 +21032,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19746,14 +21041,14 @@ typedef void* MTLSharedEvent_id; - + - + - + @@ -19764,12 +21059,12 @@ typedef void* MTLSharedEvent_id; - + - - + + @@ -19787,7 +21082,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19797,7 +21092,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19811,7 +21106,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19820,20 +21115,24 @@ typedef void* MTLSharedEvent_id; - + - + - - + + + + + + - + @@ -19899,13 +21198,20 @@ typedef void* MTLSharedEvent_id; - + - - - - - + + + + + + + + + + + + @@ -19946,12 +21252,19 @@ typedef void* MTLSharedEvent_id; - + - - - - + + + + + + + + + + + @@ -19990,7 +21303,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20000,7 +21313,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20009,7 +21322,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20033,10 +21346,12 @@ typedef void* MTLSharedEvent_id; - + - - + + + + @@ -20051,11 +21366,15 @@ typedef void* MTLSharedEvent_id; - + - - - + + + + + + + @@ -20065,7 +21384,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20079,7 +21398,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20087,7 +21406,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20108,7 +21427,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20121,7 +21440,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20135,7 +21454,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20162,14 +21481,14 @@ typedef void* MTLSharedEvent_id; - + - + @@ -20185,7 +21504,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20197,10 +21516,12 @@ typedef void* MTLSharedEvent_id; - + - - + + + + @@ -20209,7 +21530,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20231,7 +21552,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20247,7 +21568,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20295,7 +21616,6 @@ typedef void* MTLSharedEvent_id; - @@ -20326,21 +21646,27 @@ typedef void* MTLSharedEvent_id; + + + + - + - - + + + + - + - + @@ -20414,19 +21740,19 @@ typedef void* MTLSharedEvent_id; - + - + - + @@ -20443,10 +21769,17 @@ typedef void* MTLSharedEvent_id; - + - - + + + + + + + + + @@ -20454,6 +21787,7 @@ typedef void* MTLSharedEvent_id; + @@ -20462,7 +21796,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20479,7 +21813,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20495,7 +21829,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20540,7 +21874,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20548,14 +21882,14 @@ typedef void* MTLSharedEvent_id; - + - + - + @@ -20575,6 +21909,7 @@ typedef void* MTLSharedEvent_id; + @@ -20649,19 +21984,108 @@ typedef void* MTLSharedEvent_id; - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + + @@ -20670,7 +22094,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20683,7 +22107,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20705,19 +22129,54 @@ typedef void* MTLSharedEvent_id; - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -20746,7 +22205,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20772,7 +22231,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20782,16 +22241,20 @@ typedef void* MTLSharedEvent_id; - + - - + + + + - + - - + + + + @@ -20818,6 +22281,267 @@ typedef void* MTLSharedEvent_id; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -22387,11 +24111,14 @@ typedef void* MTLSharedEvent_id; + + + - + @@ -22404,6 +24131,15 @@ typedef void* MTLSharedEvent_id; + + + + + + + + + @@ -22777,7 +24513,7 @@ typedef void* MTLSharedEvent_id; - + @@ -22875,5 +24611,355 @@ typedef void* MTLSharedEvent_id; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Fragment shader stage is added by the VK_EXT_shader_tile_image extension + + + + + + + Fragment shader stage is added by the VK_EXT_shader_tile_image extension + + + + + + + + + + + + + + + + + + + TODO/Suggestion. Introduce 'synclist' (could be a different name) element + that specifies the list of stages, accesses, etc. This list can be used by + 'syncaccess' or 'syncstage' elements. For example, 'syncsupport' in addition to the + 'stage' attribute can support 'list' attribute to reference 'synclist'. + We can have the lists defined for ALL stages and it can be shared between MEMORY_READ + and MEMORY_WRITE accesses. Similarly, ALL shader stages list is often used. This proposal + is a way to fix duplication problem. When new stage is added multiple places needs to be + updated. It is potential source of bugs. The expectation such setup will produce more + robust system and also more simple structure to review and validate. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT + VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT + VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT + VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT + VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT + VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT + VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT + VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT + VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR + VK_PIPELINE_STAGE_2_FRAGMENT_DENSITY_PROCESS_BIT_EXT + VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT + VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT + VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT + VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT + VK_PIPELINE_STAGE_2_CONDITIONAL_RENDERING_BIT_EXT + + + VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT + VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_EXT + VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT + VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR + VK_PIPELINE_STAGE_2_FRAGMENT_DENSITY_PROCESS_BIT_EXT + VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT + VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT + VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT + VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT + VK_PIPELINE_STAGE_2_CONDITIONAL_RENDERING_BIT_EXT + + + VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT + VK_PIPELINE_STAGE_2_CONDITIONAL_RENDERING_BIT_EXT + + + VK_PIPELINE_STAGE_2_TRANSFER_BIT + + + VK_PIPELINE_STAGE_2_HOST_BIT + + + VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI + + + VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_NV + + + VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR + + + VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_COPY_BIT_KHR + + + VK_PIPELINE_STAGE_2_MICROMAP_BUILD_BIT_EXT + + + VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT + VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR + + + VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR + + + VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR + + + VK_PIPELINE_STAGE_2_OPTICAL_FLOW_BIT_NV + + From 214515b20f8c98a5cd340ecfd9e50292b96fbd32 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Aug 2023 18:45:24 -0600 Subject: [PATCH 1511/2777] Revert "fixup! winevulkan: Add support for signalling VkFence from virtualized VkQueues." This reverts commit db9d4549dd4fc28c157b8b8bb17a118ccab03dcd. CW-Bug-Id: #22526 --- dlls/winevulkan/vulkan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 845646e8343..e08ba2857cf 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -5426,7 +5426,7 @@ void wine_vkDestroyFence(VkDevice device_handle, VkFence fence_handle, const VkA if (fence->eventfd != -1) close(fence->eventfd); - device->funcs.p_vkDestroyFence(device->device, fence->fence, NULL); + device->funcs.p_vkDestroyFence(device->device, fence->fence, allocator); free(fence); } From 662706aa041cf02cb3639cc6a09f940e93556720 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Aug 2023 18:45:26 -0600 Subject: [PATCH 1512/2777] Revert "winevulkan: Only append VK_KHR_timeline_semaphore for Vk API version < 1.2." This reverts commit 145f580cf412cf6d875f0e2d16a014805e6d43ab. CW-Bug-Id: #22526 --- dlls/winevulkan/vulkan.c | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index e08ba2857cf..7b134c1f60e 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -522,8 +522,6 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de else if (!strcmp(extension_name, "VK_KHR_timeline_semaphore")) append_timeline = 0; } - if (append_timeline) - append_timeline = phys_dev->api_version < VK_API_VERSION_1_2 || phys_dev->instance->api_version < VK_API_VERSION_1_2; if (append_timeline) { append_timeline = 0; @@ -1750,25 +1748,6 @@ static void wine_vk_get_physical_device_external_semaphore_properties(struct win break; case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT: { - unsigned int i; - - if (phys_dev->api_version < VK_API_VERSION_1_2 || - phys_dev->instance->api_version < VK_API_VERSION_1_2) - { - for (i = 0; i < phys_dev->extension_count; i++) - { - if (!strcmp(phys_dev->extensions[i].extensionName, "VK_KHR_timeline_semaphore")) - break; - } - if (i == phys_dev->extension_count) - { - properties->exportFromImportedHandleTypes = 0; - properties->compatibleHandleTypes = 0; - properties->externalSemaphoreFeatures = 0; - return; - } - } - if ((p_semaphore_type_info = wine_vk_find_struct(&semaphore_info_dup, SEMAPHORE_TYPE_CREATE_INFO))) { p_semaphore_type_info->semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE; From 1f33db84ce31e238f73e1d97d3ed243cb9841906 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Aug 2023 18:45:27 -0600 Subject: [PATCH 1513/2777] Revert "winevulkan: Rename for_each_d3d12_semaphore() into get_semaphore_by_index()." This reverts commit 4deb9cac53fbce0bac375d485aba6791d7037c7f. CW-Bug-Id: #22526 --- dlls/winevulkan/vulkan.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 7b134c1f60e..fe8af265b75 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -4714,7 +4714,7 @@ struct queue_submit_unit }; /* Abstracts away the differences between VkSubmitInfo and VkSubmitInfo2. */ -static bool get_semaphore_by_index(struct queue_submit_unit *unit, bool signal, +static bool for_each_d3d12_semaphore(struct queue_submit_unit *unit, bool signal, struct wine_semaphore **semaphore_out, uint64_t **value_out, uint32_t counter) { VkTimelineSemaphoreSubmitInfo *timeline_values; @@ -4825,7 +4825,7 @@ static void *virtual_queue_worker(void *arg) goto free_submit_unit; /* Wait for all fences to have a pending signal */ - for (i = 0; get_semaphore_by_index(submit_unit, false, &sem, &timeline_value, i); i++) + for (i = 0; for_each_d3d12_semaphore(submit_unit, false, &sem, &timeline_value, i); i++) { if ((wait = submit_unit->waits[i])) { @@ -4840,7 +4840,7 @@ static void *virtual_queue_worker(void *arg) } } - for (i = 0; get_semaphore_by_index(submit_unit, true, &sem, &timeline_value, i); i++) + for (i = 0; for_each_d3d12_semaphore(submit_unit, true, &sem, &timeline_value, i); i++) { d3d12_semaphore_lock(sem); @@ -4855,7 +4855,7 @@ static void *virtual_queue_worker(void *arg) pthread_mutex_lock(&queue->signaller_mutex); - for (i = 0; get_semaphore_by_index(submit_unit, true, &sem, &timeline_value, i); i++) + for (i = 0; for_each_d3d12_semaphore(submit_unit, true, &sem, &timeline_value, i); i++) { if (vr == VK_SUCCESS) { From 050a1fc8545d135ba28bc51c857210eef4f5f8f4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Aug 2023 18:45:28 -0600 Subject: [PATCH 1514/2777] Revert "winevulkan: Remove extra index increment in virtual_queue_worker()." This reverts commit 27baf0f5af8793d108de8f8615b7a7a752db32a7. CW-Bug-Id: #22526 --- dlls/winevulkan/vulkan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index fe8af265b75..851085da048 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -4827,8 +4827,9 @@ static void *virtual_queue_worker(void *arg) /* Wait for all fences to have a pending signal */ for (i = 0; for_each_d3d12_semaphore(submit_unit, false, &sem, &timeline_value, i); i++) { - if ((wait = submit_unit->waits[i])) + if ((wait = submit_unit->waits[i++])) { + assert(wait); d3d12_semaphore_lock(sem); while (!wait->satisfied) From 1ef1a7bf129643534230b3ff2bfeee83899a85cc Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Aug 2023 18:45:30 -0600 Subject: [PATCH 1515/2777] Revert "winevulkan: Fix vkWaitSemaphores implementation with 32-bit time_t value." This reverts commit 99ec6833def7e0f8290c0062351c50431de36742. CW-Bug-Id: #22526 --- dlls/winevulkan/vulkan.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 851085da048..82fb2051f9a 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -4394,7 +4393,6 @@ static VkResult wine_vk_wait_semaphores(VkDevice device_handle, const VkSemaphor unsigned int i, remaining_waits; VkSemaphore* semaphores_dup; uint64_t *values_dup; - int64_t tv_sec_wide; uint64_t phys_val; int wait_stat; VkResult res; @@ -4405,18 +4403,13 @@ static VkResult wine_vk_wait_semaphores(VkDevice device_handle, const VkSemaphor { clock_gettime(CLOCK_REALTIME, &start_time); - abs_timeout.tv_sec = tv_sec_wide = start_time.tv_sec + (timeout / NANOSECONDS_IN_A_SECOND); + abs_timeout.tv_sec = start_time.tv_sec + (timeout / NANOSECONDS_IN_A_SECOND); abs_timeout.tv_nsec = start_time.tv_nsec + (timeout % NANOSECONDS_IN_A_SECOND); if (abs_timeout.tv_nsec >= NANOSECONDS_IN_A_SECOND) { abs_timeout.tv_sec++; - tv_sec_wide++; abs_timeout.tv_nsec-=NANOSECONDS_IN_A_SECOND; } - - /* tv_sec is still! 32-bit on x86 */ - if (tv_sec_wide > abs_timeout.tv_sec) - abs_timeout.tv_sec = INT_MAX; } wait_info_dup.pSemaphores = semaphores_dup = calloc(wait_info->semaphoreCount, sizeof(VkSemaphore)); From 1e8cda4347c184ac21d04764a67d820c04face77 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Aug 2023 18:45:31 -0600 Subject: [PATCH 1516/2777] Revert "winevulkan: Flush virtual queue before providing native handle." This reverts commit 5152033a65b8f7e98d825973a849153c68c0d4cc. CW-Bug-Id: #22526 --- dlls/winevulkan/vulkan.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 82fb2051f9a..148cb5918a3 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -3639,15 +3639,6 @@ VkQueue WINAPI __wine_get_native_VkQueue(VkQueue handle) { struct wine_queue *queue = wine_queue_from_handle(handle); - if (is_virtual_queue(queue)) - { - FIXME("VR is using native handle of virtualized queue, this is untested.\n"); - pthread_mutex_lock(&queue->submissions_mutex); - while (queue->processing) - pthread_cond_wait(&queue->submissions_cond, &queue->submissions_mutex); - pthread_mutex_unlock(&queue->submissions_mutex); - } - return queue->queue; } From eacb9738c06fd15c6a507571b963eb7f9baa95a9 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Aug 2023 18:45:32 -0600 Subject: [PATCH 1517/2777] Revert "winevulkan: Add support for signalling VkFence from virtualized VkQueues." This reverts commit 221912a31286735ba9d281fb66bf919d95e68d4d. CW-Bug-Id: #22526 --- dlls/winevulkan/make_vulkan | 6 - dlls/winevulkan/vulkan.c | 285 +++---------------------------- dlls/winevulkan/vulkan_private.h | 20 --- 3 files changed, 19 insertions(+), 292 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index f680c130955..6d0d61937ec 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -202,10 +202,8 @@ FUNCTION_OVERRIDES = { # Device functions "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE}, "vkCreateCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE, "extra_param" : "client_ptr"}, - "vkCreateFence" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkDestroyCommandPool" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE}, "vkDestroyDevice" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE}, - "vkDestroyFence" : {"dispatch" : True, "driver" : False, "thunk": ThunkType.NONE}, "vkFreeCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE}, "vkGetDeviceProcAddr" : {"dispatch" : False, "driver" : True, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.NONE}, "vkGetDeviceQueue" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, @@ -219,9 +217,7 @@ FUNCTION_OVERRIDES = { "vkCreateBuffer" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkCreateImage" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, "vkGetSemaphoreCounterValue" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, - "vkResetFences" : {"dispatch" : True, "driver": False, "thunk" : ThunkType.PRIVATE}, "vkSignalSemaphore" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, - "vkWaitForFences" : {"dispatch": True, "driver": False, "thunk": ThunkType.PRIVATE}, "vkWaitSemaphores" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, "vkQueueBindSparse" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, "vkQueueSubmit" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE, "extra_param" : "pSubmits"}, @@ -1196,8 +1192,6 @@ class VkHandle(object): return "wine_device_memory_from_handle({0})->memory".format(name) if self.name == "VkSemaphore": return "wine_semaphore_host_handle( wine_semaphore_from_handle({0}) )".format(name) - if self.name == "VkFence": - return "wine_fence_from_handle({0})->fence".format(name) if self.name == "VkPhysicalDevice": return "wine_phys_dev_from_handle({0})->phys_dev".format(name) if self.name == "VkQueue": diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 148cb5918a3..6ace73ea48e 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -29,8 +29,6 @@ #include #include #include -#include -#include #include "ntstatus.h" #define WIN32_NO_STATUS @@ -4526,9 +4524,8 @@ VkResult wine_vkWaitSemaphoresKHR(VkDevice device, const VkSemaphoreWaitInfo *wa return wine_vk_wait_semaphores(device, wait_info, timeout, true); } -VkResult vk_queue_submit_unwrap(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo *submits_orig, VkFence fence_handle) +VkResult vk_queue_submit_unwrap(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo *submits_orig, VkFence fence) { - struct wine_fence *fence = fence_handle ? wine_fence_from_handle(fence_handle) : NULL; struct conversion_context ctx; VkSubmitInfo *submits; unsigned int i, j; @@ -4550,12 +4547,7 @@ VkResult vk_queue_submit_unwrap(struct wine_queue *queue, uint32_t submit_count, submits[i].pCommandBuffers = out; } } - - - if (fence) - fence->queue = queue; - - ret = queue->device->funcs.p_vkQueueSubmit(queue->queue, submit_count, submits, fence ? fence->fence : VK_NULL_HANDLE); + ret = queue->device->funcs.p_vkQueueSubmit(queue->queue, submit_count, submits, fence); free_conversion_context(&ctx); return ret; } @@ -4565,7 +4557,6 @@ struct signal_op enum { SIGNAL_TYPE_SEMAPHORE, - SIGNAL_TYPE_FENCE, } signal_type; union @@ -4577,8 +4568,6 @@ struct signal_op bool khr; } semaphore; - - struct wine_fence *fence; }; struct list entry; @@ -4591,7 +4580,6 @@ static void *queue_signaller_worker(void *arg) struct signal_op *signal_op; VkSemaphore sem_handle; bool device_lost; - uint64_t buf; VkResult vr; for (;;) @@ -4635,19 +4623,6 @@ static void *queue_signaller_worker(void *arg) d3d12_semaphore_update_phys_val_locked(signal_op->semaphore.obj, signal_op->semaphore.phys_val); d3d12_semaphore_unlock(signal_op->semaphore.obj); } - else - { - if (!device_lost && (vr = queue->device->funcs.p_vkWaitForFences - (queue->device->device, 1, &signal_op->fence->fence, VK_TRUE, -1)) < 0) - { - /* likely GPU hang */ - fprintf(stderr, "winevulkan/queue_signaller_worker: Fence wait failed, vr %d.\n", vr); - continue; - } - - buf = 1; - assert( write(signal_op->fence->eventfd, &buf, sizeof(buf)) != -1 ); - } free(signal_op); } @@ -4780,7 +4755,6 @@ static void *virtual_queue_worker(void *arg) struct signal_op *signal_op; struct wine_semaphore *sem; struct pending_wait *wait; - struct wine_fence *fence; bool device_lost = false; uint64_t *timeline_value; unsigned int i; @@ -4833,10 +4807,10 @@ static void *virtual_queue_worker(void *arg) } if (submit_unit->submits) - vr = vk_queue_submit_unwrap(queue, submit_unit->submit_count, submit_unit->submits, submit_unit->fence); + vr = vk_queue_submit_unwrap(queue, submit_unit->submit_count, submit_unit->submits, VK_NULL_HANDLE); else vr = vk_queue_submit_2_unwrap(queue, submit_unit->submit_count, submit_unit->submits2, - submit_unit->fence, submit_unit->khr); + VK_NULL_HANDLE, submit_unit->khr); pthread_mutex_lock(&queue->signaller_mutex); @@ -4863,15 +4837,6 @@ static void *virtual_queue_worker(void *arg) d3d12_semaphore_unlock(sem); } - if (vr == VK_SUCCESS && (fence = wine_fence_from_handle(submit_unit->fence))) - { - signal_op = malloc(sizeof(*signal_op)); - signal_op->signal_type = SIGNAL_TYPE_FENCE; - signal_op->fence = fence; - - list_add_tail(&queue->signal_ops, &signal_op->entry); - } - pthread_cond_signal(&queue->signaller_cond); pthread_mutex_unlock(&queue->signaller_mutex); @@ -4881,12 +4846,6 @@ static void *virtual_queue_worker(void *arg) pthread_mutex_lock(&queue->submissions_mutex); queue->device_lost = device_lost = true; pthread_mutex_unlock(&queue->submissions_mutex); - - if ((fence = wine_fence_from_handle(submit_unit->fence))) - { - uint64_t buf = 1; - assert( write(fence->eventfd, &buf, sizeof(buf)) != -1 ); - } } free_submit_unit: @@ -4941,6 +4900,12 @@ static NTSTATUS virtual_queue_submit(struct wine_queue *queue, uint32_t submit_c uint64_t wait_value; bool device_lost; + if (fence != VK_NULL_HANDLE) + { + FIXME("Signalling fences in queue submissions involving D3D12-Fence compatible timeline semaphores not supported.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + init_virtual_queue(queue); pthread_mutex_lock(&queue->submissions_mutex); @@ -4954,7 +4919,6 @@ static NTSTATUS virtual_queue_submit(struct wine_queue *queue, uint32_t submit_c submit_unit->submit_count = submit_count; submit_unit->submits = copy_VkSubmitInfo_array(&submit_unit->ctx, submits, submit_count); submit_unit->submits2 = NULL; - submit_unit->fence = fence; submit_unit->waits = NULL; submit_unit->khr = queue->device->phys_dev->api_version < VK_API_VERSION_1_2 || queue->device->phys_dev->instance->api_version < VK_API_VERSION_1_2; @@ -5010,11 +4974,6 @@ static NTSTATUS virtual_queue_submit(struct wine_queue *queue, uint32_t submit_c pthread_mutex_lock(&queue->submissions_mutex); queue->processing = true; - if (fence) - { - wine_fence_from_handle(fence)->queue = queue; - wine_fence_from_handle(fence)->wait_assist = true; - } list_add_tail(&queue->submissions, &submit_unit->entry); pthread_cond_signal(&queue->submissions_cond); pthread_mutex_unlock(&queue->submissions_mutex); @@ -5136,9 +5095,8 @@ static NTSTATUS virtual_queue_submit2(struct wine_queue *queue, uint32_t submit_ } VkResult vk_queue_submit_2_unwrap(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo2 *submits_orig, - VkFence fence_handle, bool khr) + VkFence fence, bool khr) { - struct wine_fence *fence = fence_handle ? wine_fence_from_handle(fence_handle) : NULL; struct conversion_context ctx; VkSubmitInfo2 *submits; unsigned int i, j; @@ -5171,27 +5129,23 @@ VkResult vk_queue_submit_2_unwrap(struct wine_queue *queue, uint32_t submit_coun = wine_cmd_buffer_from_handle(submits[i].pCommandBufferInfos[j].commandBuffer)->command_buffer; } } - if (fence) - fence->queue = queue; - if (khr) - ret = queue->device->funcs.p_vkQueueSubmit2KHR(queue->queue, submit_count, submits, fence ? fence->fence : VK_NULL_HANDLE); + ret = queue->device->funcs.p_vkQueueSubmit2KHR(queue->queue, submit_count, submits, fence); else - ret = queue->device->funcs.p_vkQueueSubmit2(queue->queue, submit_count, submits, fence ? fence->fence : VK_NULL_HANDLE); - + ret = queue->device->funcs.p_vkQueueSubmit2(queue->queue, submit_count, submits, fence); free_conversion_context(&ctx); return ret; } -static VkResult vk_queue_submit_2(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence_handle, bool khr) +static VkResult vk_queue_submit_2(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence, bool khr) { struct wine_queue *queue = wine_queue_from_handle(queue_handle); unsigned int i, k; - TRACE("(%p, %u, %p, %s)\n", queue_handle, submit_count, submits, wine_dbgstr_longlong(fence_handle)); + TRACE("(%p, %u, %p, %s)\n", queue_handle, submit_count, submits, wine_dbgstr_longlong(fence)); if (is_virtual_queue(queue)) - return virtual_queue_submit2(queue, submit_count, submits, fence_handle, khr); + return virtual_queue_submit2(queue, submit_count, submits, fence, khr); for (i = 0; i < submit_count; i++) { @@ -5199,18 +5153,18 @@ static VkResult vk_queue_submit_2(VkQueue queue_handle, uint32_t submit_count, c { if (wine_semaphore_from_handle(submits[i].pWaitSemaphoreInfos[k].semaphore)->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - return virtual_queue_submit2(queue, submit_count, submits, fence_handle, khr); + return virtual_queue_submit2(queue, submit_count, submits, fence, khr); } for (k = 0; k < submits[i].signalSemaphoreInfoCount; k++) { if (wine_semaphore_from_handle(submits[i].pSignalSemaphoreInfos[k].semaphore)->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - return virtual_queue_submit2(queue, submit_count, submits, fence_handle, khr); + return virtual_queue_submit2(queue, submit_count, submits, fence, khr); } } - return vk_queue_submit_2_unwrap(queue, submit_count, submits, fence_handle, khr); + return vk_queue_submit_2_unwrap(queue, submit_count, submits, fence, khr); } VkResult wine_vkQueueSubmit2(VkQueue queue, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence) @@ -5349,207 +5303,6 @@ VkResult wine_vkQueueBindSparse(VkQueue queue_handle, uint32_t bind_info_count, return ret; } -VkResult wine_vkCreateFence(VkDevice device_handle, const VkFenceCreateInfo *create_info, const VkAllocationCallbacks *allocator, VkFence *fence) -{ - struct wine_device *device = wine_device_from_handle(device_handle); - struct wine_fence *object; - VkResult vr; - - TRACE("(%p, %p, %p, %p)\n", device, create_info, allocator, fence); - - if (allocator) - FIXME("Support for allocation callbacks not implemented yet\n"); - - if (!(object = calloc(1, sizeof(*object)))) - return VK_ERROR_OUT_OF_HOST_MEMORY; - - if ((object->eventfd = eventfd(0, EFD_CLOEXEC)) == -1) - ERR("Failed to create eventfd for fence.\n"); - - if ((vr = device->funcs.p_vkCreateFence(device->device, create_info, NULL, &object->fence)) == VK_SUCCESS) - *fence = wine_fence_to_handle(object); - else - free(object); - - return vr; -} - -void wine_vkDestroyFence(VkDevice device_handle, VkFence fence_handle, const VkAllocationCallbacks *allocator) -{ - struct wine_device *device = wine_device_from_handle(device_handle); - struct wine_fence *fence = wine_fence_from_handle(fence_handle); - - TRACE("(%p, %p, %p)\n", device, fence, allocator); - - if (allocator) - FIXME("Support for allocation callbacks not implemented yet\n"); - - if (!fence_handle) - return; - - if (fence->eventfd != -1) - close(fence->eventfd); - - device->funcs.p_vkDestroyFence(device->device, fence->fence, allocator); - free(fence); -} - -static VkFence *unwrap_fence_array(const VkFence *in, uint32_t count, struct conversion_context *ctx) -{ - VkFence *out; - unsigned int i; - - if (!in || !count) return NULL; - - out = conversion_context_alloc(ctx, count * sizeof(*out)); - for (i = 0; i < count; ++i) - out[i] = in[i] ? wine_fence_from_handle(in[i])->fence : VK_NULL_HANDLE; - - return out; -} - -VkResult wine_vkResetFences(VkDevice device_handle, uint32_t fence_count, const VkFence *fences) -{ - struct wine_device *device = wine_device_from_handle(device_handle); - struct conversion_context ctx; - struct wine_fence *fence; - VkFence *fences_unwrap; - unsigned int i; - uint64_t buf; - VkResult vr; - - TRACE("(%p, %u, %p)\n", device, fence_count, fences); - - init_conversion_context(&ctx); - fences_unwrap = unwrap_fence_array(fences, fence_count, &ctx); - vr = device->funcs.p_vkResetFences(device->device, fence_count, fences_unwrap); - free_conversion_context(&ctx); - if (vr) - return vr; - - for (i = 0; i < fence_count; i++) - { - fence = wine_fence_from_handle(fences[i]); - - fence->queue = NULL; - fence->swapchain = NULL; - if (fence->wait_assist) - { - fence->wait_assist = false; - if (read(fence->eventfd, &buf, sizeof(buf)) == -1) - ERR("Failed to reset event fd.\n"); - } - } - - return VK_SUCCESS; -} - -VkResult wine_vkWaitForFences(VkDevice device_handle, uint32_t fence_count, const VkFence *fences, - VkBool32 wait_all, uint64_t timeout) -{ - struct wine_device *device = wine_device_from_handle(device_handle); - struct signal_op *signal_op; - bool assisted_wait = false; - struct wine_fence *fence; - struct pollfd *wait_fds; - struct pollfd wait_fd; - unsigned int i; - VkResult vr; - int ret; - - TRACE("(%p, %u, %p, %u, 0x%s)\n", device, fence_count, fences, wait_all, wine_dbgstr_longlong(timeout)); - - for (i = 0; i < fence_count; i++) - { - fence = wine_fence_from_handle(fences[i]); - if (!fence->wait_assist) - continue; - - if (!wait_all && fence_count > 1) - { - assisted_wait = true; - break; - } - - wait_fd.fd = fence->eventfd; - wait_fd.events = POLLIN; - ret = poll(&wait_fd, 1, timeout / 1000000); - if (ret == -1) - { - ERR("Failed to poll wait assisted fence.\n"); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } - if (!ret) - return VK_TIMEOUT; - - if (wait_fd.revents & (POLLERR | POLLHUP | POLLNVAL)) - ERR("Polling on fd %d returned %#x.", fence->eventfd, wait_fd.revents); - return VK_SUCCESS; - } - - if (assisted_wait) - { - /* Turn all non assisted waits into assisted waits, then poll on all */ - wait_fds = malloc( sizeof(wait_fds[0]) * fence_count ); - - for (i = 0; i < fence_count; i++) - { - if (!fence->wait_assist) - { - assert(fence->queue || fence->swapchain); - - if (fence->queue) - { - fence->wait_assist = true; - - /* If virtual-queue requiring work was submitted after the work signalling this mutex, - * we will end up unnecessarily waiting on that work first, - * but this will only happen once per queue */ - init_virtual_queue(fence->queue); - - signal_op = malloc(sizeof(*signal_op)); - signal_op->signal_type = SIGNAL_TYPE_FENCE; - signal_op->fence = fence; - - pthread_mutex_lock(&fence->queue->signaller_mutex); - list_add_tail(&fence->queue->signal_ops, &signal_op->entry); - pthread_cond_signal(&fence->queue->signaller_cond); - pthread_mutex_unlock(&fence->queue->signaller_mutex); - } - else - { - FIXME("Wait assist for swapchain signaled fences not supported.\n"); - free(wait_fds); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } - } - - wait_fds[i].fd = fence->eventfd; - wait_fds[i].events = POLLIN; - } - - if (poll(wait_fds, fence_count, timeout / 1000000) == -1) - { - ERR("Failed to poll wait assisted fences.\n"); - vr = VK_ERROR_OUT_OF_HOST_MEMORY; - } - - free(wait_fds); - } - else - { - struct conversion_context ctx; - VkFence *fences_unwrap; - - init_conversion_context(&ctx); - fences_unwrap = unwrap_fence_array(fences, fence_count, &ctx); - vr = device->funcs.p_vkWaitForFences(device->device, fence_count, fences_unwrap, wait_all, timeout); - free_conversion_context(&ctx); - } - - return vr; -} - VkResult wine_vkQueueWaitIdle(VkQueue queue_handle) { struct wine_queue *queue = wine_queue_from_handle(queue_handle); diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 864fc392c2c..218c2be9efe 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -393,26 +393,6 @@ static inline VkSemaphore wine_semaphore_host_handle(struct wine_semaphore *sema return semaphore->semaphore; } -struct wine_fence -{ - VkFence fence; - - struct wine_queue *queue; - struct wine_swapchain *swapchain; - bool wait_assist; - int eventfd; -}; - -static inline struct wine_fence *wine_fence_from_handle(VkFence handle) -{ - return (struct wine_fence *)(uintptr_t)handle; -} - -static inline VkFence wine_fence_to_handle(struct wine_fence *fence) -{ - return (VkFence)(uintptr_t)fence; -} - static inline void *conversion_context_alloc(struct conversion_context *pool, size_t size) { if (pool->used + size <= sizeof(pool->buffer)) From ed857f9fdccc72e5642e45126a86822e7bbbca9d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Aug 2023 18:45:33 -0600 Subject: [PATCH 1518/2777] Revert "winevulkan: Support waiting for and signalling D3D12-Fence style timeline semaphores in Vulkan Queues." This reverts commit ac20bc2ef828f9347d0308ac7ae19cf8e884c59a. CW-Bug-Id: #22526 --- dlls/winevulkan/make_vulkan | 52 +-- dlls/winevulkan/vulkan.c | 691 ++----------------------------- dlls/winevulkan/vulkan_private.h | 18 - 3 files changed, 50 insertions(+), 711 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 6d0d61937ec..b7d57f2964e 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -220,9 +220,8 @@ FUNCTION_OVERRIDES = { "vkSignalSemaphore" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, "vkWaitSemaphores" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, "vkQueueBindSparse" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, - "vkQueueSubmit" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE, "extra_param" : "pSubmits"}, + "vkQueueSubmit" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, "vkQueueSubmit2" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, - "vkQueueWaitIdle" : {"dispatch": True, "driver": False, "thunk" : ThunkType.NONE}, # VK_KHR_surface "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE}, @@ -312,16 +311,11 @@ STRUCT_CHAIN_CONVERSIONS = { "VkPhysicalDeviceImageFormatInfo2": [], "VkPhysicalDeviceExternalSemaphoreInfo": [], "VkSemaphoreCreateInfo": ["VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR"], - "VkSubmitInfo": ["VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR"], + "VkSubmitInfo": [], "VkSubmitInfo2": [], "VkBindSparseInfo" : [], } -STRUCT_COPY = { - "VkSubmitInfo", - "VkSubmitInfo2", -}; - # Some struct members are conditionally ignored and callers are free to leave them uninitialized. # We can't deduce that from XML, so we allow expressing it here. MEMBER_LENGTH_EXPRESSIONS = { @@ -1409,9 +1403,6 @@ class VkVariable(object): if struct.needs_conversion(conv, unwrap, Direction.OUTPUT, is_const): conversions.append(StructConversionFunction(struct, Direction.OUTPUT, conv, unwrap, is_const)) - if struct.name in STRUCT_COPY: - conversions.append(StructConversionFunction(struct, Direction.INPUT, False, unwrap, is_const, True)) - if self.is_static_array() or self.is_dynamic_array(): for conv in [False, True]: if self.needs_conversion(conv, unwrap, Direction.INPUT, parent_const): @@ -1541,7 +1532,7 @@ class VkMember(VkVariable): values=values, object_type=object_type, bit_width=bit_width, returnedonly=returnedonly, parent=parent, selection=selection, selector=selector) - def copy(self, input, output, direction, conv, unwrap, copy): + def copy(self, input, output, direction, conv, unwrap): """ Helper method for use by conversion logic to generate a C-code statement to copy this member. - `conv` indicates whether the statement is in a struct alignment conversion path. """ @@ -1599,8 +1590,6 @@ class VkMember(VkVariable): elif self.is_static_array(): bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type) return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count) - elif self.is_dynamic_array() and copy: - return "MEMDUP(ctx, {0}{1}, {2}{1}, {3});\n".format(output, self.name, input, self.get_dyn_array_len(input, conv)) elif direction == Direction.INPUT: return "{0}{1} = {2};\n".format(output, self.name, self.value(input, conv)) elif conv and direction == Direction.OUTPUT and self.is_pointer(): @@ -2323,25 +2312,21 @@ class VkStruct(Sequence): class StructConversionFunction(object): - def __init__(self, struct, direction, conv, unwrap, const, copy=False): + def __init__(self, struct, direction, conv, unwrap, const): self.direction = direction self.operand = struct self.type = struct.name self.conv = conv self.unwrap = unwrap or not self.operand.needs_unwrapping() self.const = const - self.copy = copy - if copy: - name = "copy_{0}".format(self.type) - else: - name = "convert_{0}_".format(self.type) - win_type = "win32" if self.conv else "win64" - host_part = "host" if self.unwrap else "unwrapped_host" - if self.direction == Direction.INPUT: - name += "{0}_to_{1}".format(win_type, host_part) - else: # Direction.OUTPUT - name += "{0}_to_{1}".format(host_part, win_type) + name = "convert_{0}_".format(self.type) + win_type = "win32" if self.conv else "win64" + host_part = "host" if self.unwrap else "unwrapped_host" + if self.direction == Direction.INPUT: + name += "{0}_to_{1}".format(win_type, host_part) + else: # Direction.OUTPUT + name += "{0}_to_{1}".format(host_part, win_type) self.name = name def __eq__(self, other): @@ -2373,7 +2358,7 @@ class StructConversionFunction(object): body = "" - if not self.conv and not self.copy: + if not self.conv: body += "#ifdef _WIN64\n" needs_alloc = self.direction != Direction.OUTPUT and self.operand.needs_alloc(self.conv, self.unwrap) @@ -2383,11 +2368,8 @@ class StructConversionFunction(object): if self.direction == Direction.OUTPUT and self.const: win_type = "const " + win_type - if self.copy: - body += "void {0}(".format(self.name) - else: - body += "static inline void {0}(".format(self.name) if self.conv: + body += "static inline void {0}(".format(self.name) if self.direction == Direction.OUTPUT: params = ["const {0} *in".format(self.type), "{0} *out".format(win_type)] @@ -2404,6 +2386,8 @@ class StructConversionFunction(object): body += ")\n" else: + body += "static inline void {0}(".format(self.name) + params = ["const {0} *in".format(self.type), "{0} *out".format(self.type)] # Generate parameter list @@ -2443,7 +2427,7 @@ class StructConversionFunction(object): body += " || ".join("selector == {}".format(s) for s in m.selection) body += ")\n " - body += " " + m.copy("in->", "out->", self.direction, self.conv, self.unwrap, self.copy) + body += " " + m.copy("in->", "out->", self.direction, self.conv, self.unwrap) if needs_extensions: if self.conv and self.direction == Direction.INPUT: @@ -2503,7 +2487,7 @@ class StructConversionFunction(object): copy_body += ident + "out_ext->pNext = NULL;\n" continue - copy_body += ident + m.copy("in_ext->", "out_ext->", self.direction, self.conv, True, self.copy) + copy_body += ident + m.copy("in_ext->", "out_ext->", self.direction, self.conv, True) # Generate the definition of "in_ext" if we need it if "in_ext->" in copy_body: @@ -2538,7 +2522,7 @@ class StructConversionFunction(object): body += " FIXME(\"Unexpected pNext\\n\");\n" body += "}\n" - if not self.conv and not self.copy: + if not self.conv: body += "#endif /* _WIN64 */\n" body += "\n" diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 6ace73ea48e..d0b90293344 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -36,7 +36,6 @@ #include "winnt.h" #include "winioctl.h" #include "wine/server.h" -#include "wine/list.h" #include "vulkan_private.h" #include "wine/vulkan_driver.h" @@ -243,7 +242,6 @@ static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance struct wine_phys_dev *object; uint32_t num_host_properties, num_properties = 0; VkExtensionProperties *host_properties = NULL; - VkPhysicalDeviceProperties physdev_properties; BOOL have_external_memory_host = FALSE; VkResult res; unsigned int i, j; @@ -255,9 +253,6 @@ static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance object->handle = handle; object->phys_dev = phys_dev; - instance->funcs.p_vkGetPhysicalDeviceProperties(phys_dev, &physdev_properties); - object->api_version = physdev_properties.apiVersion; - handle->base.unix_handle = (uintptr_t)object; WINE_VK_ADD_DISPATCHABLE_MAPPING(instance, handle, phys_dev, object); @@ -402,14 +397,6 @@ static void wine_vk_device_get_queues(struct wine_device *device, queue->queue_index = i; queue->flags = flags; - pthread_mutex_init(&queue->submissions_mutex, NULL); - pthread_cond_init(&queue->submissions_cond, NULL); - list_init(&queue->submissions); - - pthread_mutex_init(&queue->signaller_mutex, NULL); - pthread_cond_init(&queue->signaller_cond, NULL); - list_init(&queue->signal_ops); - /* The Vulkan spec says: * * "vkGetDeviceQueue must only be used to get queues that were created @@ -579,11 +566,6 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de return VK_SUCCESS; } -static bool is_virtual_queue(struct wine_queue *queue) -{ - return __atomic_load_n(&queue->virtual_queue, __ATOMIC_ACQUIRE); -} - /* Helper function used for freeing a device structure. This function supports full * and partial object cleanups and can thus be used for vkCreateDevice failures. */ @@ -600,28 +582,6 @@ static void wine_vk_device_free(struct wine_device *device) for (i = 0; i < device->queue_count; i++) { queue = &device->queues[i]; - - if (is_virtual_queue(queue)) - { - pthread_mutex_lock(&queue->submissions_mutex); - pthread_mutex_lock(&queue->signaller_mutex); - queue->stop = 1; - pthread_mutex_unlock(&queue->submissions_mutex); - pthread_mutex_unlock(&queue->signaller_mutex); - - pthread_cond_signal(&queue->submissions_cond); - pthread_cond_signal(&queue->signaller_cond); - - pthread_join(queue->virtual_queue_thread, NULL); - pthread_join(queue->signal_thread, NULL); - } - - pthread_mutex_destroy(&queue->submissions_mutex); - pthread_mutex_destroy(&queue->signaller_mutex); - - pthread_cond_destroy(&queue->submissions_cond); - pthread_cond_destroy(&queue->signaller_cond); - if (queue && queue->queue) WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, queue); } @@ -1097,8 +1057,6 @@ VkResult wine_vkCreateInstance(const VkInstanceCreateInfo *create_info, app_info->engineVersion); TRACE("API version %#x.\n", app_info->apiVersion); - object->api_version = app_info->apiVersion; - if (app_info->pEngineName && !strcmp(app_info->pEngineName, "idTech")) object->quirks |= WINEVULKAN_QUIRK_GET_DEVICE_PROC_ADDR; } @@ -3741,7 +3699,7 @@ static void d3d12_semaphore_unlock(struct wine_semaphore *semaphore) /* returns -1 when there is no queued update that would satisfy the wait */ static uint64_t d3d12_semaphore_try_get_wait_value_locked(struct wine_semaphore *semaphore, uint64_t virtual_value, - struct wine_queue *waiting_queue) + struct VkQueue_T *waiting_queue) { struct pending_update *update; uint64_t ret = -1; @@ -3750,19 +3708,6 @@ static uint64_t d3d12_semaphore_try_get_wait_value_locked(struct wine_semaphore if (semaphore->d3d12_fence_shm->virtual_value >= virtual_value) return 0; - for (i = 0; i < semaphore->d3d12_fence_shm->pending_updates_count; i++) - { - update = &semaphore->d3d12_fence_shm->pending_updates[i]; - - if (update->virtual_value < virtual_value) - continue; - - if (update->signalling_pid == getpid() && waiting_queue && update->signalling_queue == waiting_queue) - return 0; - - ret = min(ret, update->physical_value); - } - return ret; } @@ -3819,34 +3764,6 @@ static void d3d12_semaphore_satisfy_waits_locked(struct wine_semaphore *semaphor } } -static uint64_t d3d12_semaphore_add_pending_signal_locked(struct wine_semaphore *semaphore, uint64_t virtual_value, - struct wine_queue *signalling_queue) -{ - struct pending_update *update; - - if (semaphore->d3d12_fence_shm->pending_updates_count == ARRAY_SIZE(semaphore->d3d12_fence_shm->pending_updates)) - { - /* Called from Unix thread, can't use Wine traces. */ - fprintf(stderr, "winevulkan/d3d12_semaphore_add_pending_signal_locked: maximum concurrent signals exceeded.\n"); - return 0; - } - - update = &semaphore->d3d12_fence_shm->pending_updates[ - semaphore->d3d12_fence_shm->pending_updates_count++]; - - update->virtual_value = virtual_value; - update->physical_value = ++semaphore->d3d12_fence_shm->counter; - update->signalling_pid = getpid(); - update->signalling_queue = signalling_queue; - - return update->physical_value; -} - -static struct pending_update d3d12_semaphore_peek_added_signal_locked(struct wine_semaphore *semaphore) -{ - return semaphore->d3d12_fence_shm->pending_updates[semaphore->d3d12_fence_shm->pending_updates_count - 1]; -} - static bool d3d12_semaphore_pop_pending_signal_locked(struct wine_semaphore *semaphore, uint64_t phys_val, struct pending_update *ret) { struct pending_update *update; @@ -4288,41 +4205,27 @@ static NTSTATUS wine_vk_signal_semaphore(VkDevice device, const VkSemaphoreSigna if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) { - d3d12_semaphore_lock(semaphore); + VkSemaphoreSignalInfo step_signal_info; - /* vkWaitSemaphore w/ WAIT_ANY wakes on every physical value increment to check if the wait is satisfied, so - if there are no scheduled signals, step the physical value */ - if ((vr = vk_get_semaphore_counter_value(device, signal_info->semaphore, &phys_val, khr)) != VK_SUCCESS) - { - d3d12_semaphore_unlock(semaphore); - return vr; - } - - d3d12_semaphore_update_phys_val_locked(semaphore, phys_val); - - if (!semaphore->d3d12_fence_shm->pending_updates_count) - { - VkSemaphoreSignalInfo step_signal_info; + d3d12_semaphore_lock(semaphore); - assert(semaphore->d3d12_fence_shm->counter == phys_val); - phys_val++; + assert(semaphore->d3d12_fence_shm->counter == phys_val); + phys_val++; - semaphore->d3d12_fence_shm->counter = semaphore->d3d12_fence_shm->physical_value = phys_val; + semaphore->d3d12_fence_shm->counter = semaphore->d3d12_fence_shm->physical_value = phys_val; - step_signal_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO; - step_signal_info.pNext = NULL; - step_signal_info.semaphore = signal_info->semaphore; - step_signal_info.value = phys_val; + step_signal_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO; + step_signal_info.pNext = NULL; + step_signal_info.semaphore = signal_info->semaphore; + step_signal_info.value = phys_val; - vr = vk_signal_semaphore(device, &step_signal_info, khr); - if (vr != VK_SUCCESS) - { - d3d12_semaphore_unlock(semaphore); - return vr; - } + vr = vk_signal_semaphore(device, &step_signal_info, khr); + if (vr != VK_SUCCESS) + { + d3d12_semaphore_unlock(semaphore); + return vr; } - /* If a queue is already waiting on the pending physical value of a previous submit, this won't wake it up. */ d3d12_semaphore_satisfy_waits_locked(semaphore, signal_info->value, 0); semaphore->d3d12_fence_shm->virtual_value = signal_info->value; @@ -4552,460 +4455,33 @@ VkResult vk_queue_submit_unwrap(struct wine_queue *queue, uint32_t submit_count, return ret; } -struct signal_op -{ - enum - { - SIGNAL_TYPE_SEMAPHORE, - } signal_type; - - union - { - struct - { - struct wine_semaphore *obj; - uint64_t phys_val; - - bool khr; - } semaphore; - }; - - struct list entry; -}; - -static void *queue_signaller_worker(void *arg) -{ - struct wine_queue *queue = arg; - VkSemaphoreWaitInfo wait_info; - struct signal_op *signal_op; - VkSemaphore sem_handle; - bool device_lost; - VkResult vr; - - for (;;) - { - pthread_mutex_lock(&queue->signaller_mutex); - - while (!queue->stop && list_empty(&queue->signal_ops)) - pthread_cond_wait(&queue->signaller_cond, &queue->signaller_mutex); - - if (queue->stop) - { - assert( list_empty(&queue->signal_ops) ); - pthread_mutex_unlock(&queue->signaller_mutex); - return NULL; - } - - signal_op = LIST_ENTRY(list_head(&queue->signal_ops), struct signal_op, entry); - list_remove(&signal_op->entry); - - device_lost = queue->device_lost; - - pthread_mutex_unlock(&queue->signaller_mutex); - - if (signal_op->signal_type == SIGNAL_TYPE_SEMAPHORE) - { - wait_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO; - wait_info.pNext = NULL; - wait_info.flags = 0; - wait_info.semaphoreCount = 1; - sem_handle = wine_semaphore_to_handle(signal_op->semaphore.obj); - wait_info.pSemaphores = &sem_handle; - wait_info.pValues = &signal_op->semaphore.phys_val; - if (!device_lost && (vr = vk_wait_semaphores(queue->device, &wait_info, -1, signal_op->semaphore.khr)) < 0) - { - /* likely GPU hang */ - fprintf(stderr, "winevulkan/queue_signaller_worker: Semaphore wait failed, vr %d.\n", vr); - continue; - } - - d3d12_semaphore_lock(signal_op->semaphore.obj); - d3d12_semaphore_update_phys_val_locked(signal_op->semaphore.obj, signal_op->semaphore.phys_val); - d3d12_semaphore_unlock(signal_op->semaphore.obj); - } - - free(signal_op); - } - - return NULL; -} - -struct struct_chain_def -{ - VkStructureType sType; - unsigned int size; -}; - -void copy_VkSubmitInfo(struct conversion_context *ctx, const VkSubmitInfo *in, VkSubmitInfo *out); -static VkSubmitInfo *copy_VkSubmitInfo_array(struct conversion_context *ctx, const VkSubmitInfo *in, uint32_t submit_count) -{ - VkSubmitInfo *out = conversion_context_alloc(ctx, sizeof(*out) * submit_count); - unsigned int i; - - for (i = 0; i < submit_count; i++) - copy_VkSubmitInfo(ctx, &in[i], &out[i]); - return out; -} - -void copy_VkSubmitInfo2(struct conversion_context *ctx, const VkSubmitInfo2 *in, VkSubmitInfo2 *out); -static VkSubmitInfo2 *copy_VkSubmitInfo2_array(struct conversion_context *ctx, const VkSubmitInfo2 *in, uint32_t submit_count) -{ - VkSubmitInfo2 *out = conversion_context_alloc(ctx, sizeof(*out) * submit_count); - unsigned int i; - - for (i = 0; i < submit_count; i++) - copy_VkSubmitInfo2(ctx, &in[i], &out[i]); - return out; -} - -struct queue_submit_unit -{ - uint32_t submit_count; - VkSubmitInfo *submits; - VkSubmitInfo2 *submits2; - VkFence fence; - bool khr; - - struct pending_wait **waits; - - struct list entry; - struct conversion_context ctx; -}; - -/* Abstracts away the differences between VkSubmitInfo and VkSubmitInfo2. */ -static bool for_each_d3d12_semaphore(struct queue_submit_unit *unit, bool signal, - struct wine_semaphore **semaphore_out, uint64_t **value_out, uint32_t counter) -{ - VkTimelineSemaphoreSubmitInfo *timeline_values; - struct wine_semaphore *semaphore; - unsigned int i, j, k; - uint32_t sem_count; - - for (i = 0, k = 0; i < unit->submit_count; i++) - { - if (unit->submits) - { - timeline_values = wine_vk_find_struct(&unit->submits[i], TIMELINE_SEMAPHORE_SUBMIT_INFO); - - if (signal) - sem_count = unit->submits[i].signalSemaphoreCount; - else - sem_count = unit->submits[i].waitSemaphoreCount; - - for (j = 0; j < sem_count; j++) - { - if (signal) - semaphore = wine_semaphore_from_handle(unit->submits[i].pSignalSemaphores[j]); - else - semaphore = wine_semaphore_from_handle(unit->submits[i].pWaitSemaphores[j]); - - if (semaphore->handle_type != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - continue; - - if (k++ == counter) - { - *semaphore_out = semaphore; - if (signal) - *value_out = (uint64_t *) &timeline_values->pSignalSemaphoreValues[j]; - else - *value_out = (uint64_t *) &timeline_values->pWaitSemaphoreValues[j]; - return true; - } - } - } - else - { - if (signal) - sem_count = unit->submits2[i].signalSemaphoreInfoCount; - else - sem_count = unit->submits2[i].waitSemaphoreInfoCount; - - for (j = 0; j < sem_count; j++) - { - if (signal) - semaphore = wine_semaphore_from_handle(unit->submits2[i].pSignalSemaphoreInfos[j].semaphore); - else - semaphore = wine_semaphore_from_handle(unit->submits2[i].pWaitSemaphoreInfos[j].semaphore); - - if (semaphore->handle_type != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - continue; - - if (k++ == counter) - { - *semaphore_out = semaphore; - if (signal) - *value_out = (uint64_t *) &unit->submits2[i].pSignalSemaphoreInfos[j].value; - else - *value_out = (uint64_t *) &unit->submits2[i].pWaitSemaphoreInfos[j].value; - return true; - } - } - } - } - - return false; -} - -VkResult vk_queue_submit_2_unwrap(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence, bool khr); - -static void *virtual_queue_worker(void *arg) -{ - struct wine_queue *queue = (struct wine_queue *)arg; - struct queue_submit_unit *submit_unit; - struct signal_op *signal_op; - struct wine_semaphore *sem; - struct pending_wait *wait; - bool device_lost = false; - uint64_t *timeline_value; - unsigned int i; - VkResult vr; - - for (;;) - { - pthread_mutex_lock(&queue->submissions_mutex); - - while (!queue->stop && list_empty(&queue->submissions)) - pthread_cond_wait(&queue->submissions_cond, &queue->submissions_mutex); - - if (queue->stop) - { - assert( list_empty(&queue->submissions) ); - pthread_mutex_unlock(&queue->submissions_mutex); - return NULL; - } - - submit_unit = LIST_ENTRY(list_head(&queue->submissions), struct queue_submit_unit, entry); - list_remove(&submit_unit->entry); - - pthread_mutex_unlock(&queue->submissions_mutex); - - if (device_lost) - goto free_submit_unit; - - /* Wait for all fences to have a pending signal */ - for (i = 0; for_each_d3d12_semaphore(submit_unit, false, &sem, &timeline_value, i); i++) - { - if ((wait = submit_unit->waits[i++])) - { - assert(wait); - d3d12_semaphore_lock(sem); - - while (!wait->satisfied) - pthread_cond_wait(&wait->cond, &sem->d3d12_fence_shm->mutex); - - *timeline_value = d3d12_semaphore_pop_wait_locked(sem, wait); - - d3d12_semaphore_unlock(sem); - } - } - - for (i = 0; for_each_d3d12_semaphore(submit_unit, true, &sem, &timeline_value, i); i++) - { - d3d12_semaphore_lock(sem); - - *timeline_value = d3d12_semaphore_add_pending_signal_locked(sem, *timeline_value, queue); - } - - if (submit_unit->submits) - vr = vk_queue_submit_unwrap(queue, submit_unit->submit_count, submit_unit->submits, VK_NULL_HANDLE); - else - vr = vk_queue_submit_2_unwrap(queue, submit_unit->submit_count, submit_unit->submits2, - VK_NULL_HANDLE, submit_unit->khr); - - pthread_mutex_lock(&queue->signaller_mutex); - - for (i = 0; for_each_d3d12_semaphore(submit_unit, true, &sem, &timeline_value, i); i++) - { - if (vr == VK_SUCCESS) - { - struct pending_update added_signal = d3d12_semaphore_peek_added_signal_locked(sem); - d3d12_semaphore_satisfy_waits_locked(sem, added_signal.virtual_value, added_signal.physical_value); - - signal_op = malloc(sizeof(*signal_op)); - signal_op->signal_type = SIGNAL_TYPE_SEMAPHORE; - signal_op->semaphore.obj = sem; - signal_op->semaphore.phys_val = added_signal.physical_value; - signal_op->semaphore.khr = submit_unit->khr; - - list_add_tail(&queue->signal_ops, &signal_op->entry); - } - else - { - d3d12_semaphore_pop_pending_signal_locked(sem, *timeline_value, NULL); - } - - d3d12_semaphore_unlock(sem); - } - - pthread_cond_signal(&queue->signaller_cond); - pthread_mutex_unlock(&queue->signaller_mutex); - - if (vr != VK_SUCCESS) - { - fprintf(stderr, "winevulkan/virtual_queue_worker: queue submission failed with %d, treating as DEVICE_LOST.\n", vr); - pthread_mutex_lock(&queue->submissions_mutex); - queue->device_lost = device_lost = true; - pthread_mutex_unlock(&queue->submissions_mutex); - } - -free_submit_unit: - free_conversion_context(&submit_unit->ctx); - free(submit_unit->waits); - free(submit_unit); - - pthread_mutex_lock(&queue->submissions_mutex); - if (list_empty(&queue->submissions)) - { - queue->processing = false; - } - pthread_cond_signal(&queue->submissions_cond); - pthread_mutex_unlock(&queue->submissions_mutex); - } - - return NULL; -} - -static void init_virtual_queue(struct wine_queue *queue) -{ - if (is_virtual_queue(queue)) - return; - - pthread_mutex_lock(&queue->submissions_mutex); - - if (queue->virtual_queue) - { - pthread_mutex_unlock(&queue->submissions_mutex); - return; - } - - __atomic_store_n(&queue->virtual_queue, 1, __ATOMIC_RELEASE); - - pthread_create(&queue->virtual_queue_thread, NULL, virtual_queue_worker, queue); - pthread_create(&queue->signal_thread, NULL, queue_signaller_worker, queue); - - queue->virtual_queue = true; - - pthread_mutex_unlock(&queue->submissions_mutex); -} - -static NTSTATUS virtual_queue_submit(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo *submits, - VkFence fence, void *submits_win_ptr) -{ - VkTimelineSemaphoreSubmitInfo *timeline_submit_info, *host_timeline_values; - const VkSubmitInfo *submits_win = submits_win_ptr; - VkD3D12FenceSubmitInfoKHR *d3d12_submit_info; - struct queue_submit_unit *submit_unit; - struct wine_semaphore *sem; - unsigned int i, j, k; - uint64_t wait_value; - bool device_lost; - - if (fence != VK_NULL_HANDLE) - { - FIXME("Signalling fences in queue submissions involving D3D12-Fence compatible timeline semaphores not supported.\n"); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } - - init_virtual_queue(queue); - - pthread_mutex_lock(&queue->submissions_mutex); - device_lost = queue->device_lost; - pthread_mutex_unlock(&queue->submissions_mutex); - if (device_lost) - return VK_ERROR_DEVICE_LOST; - - submit_unit = malloc(sizeof(*submit_unit)); - init_conversion_context(&submit_unit->ctx); - submit_unit->submit_count = submit_count; - submit_unit->submits = copy_VkSubmitInfo_array(&submit_unit->ctx, submits, submit_count); - submit_unit->submits2 = NULL; - submit_unit->waits = NULL; - submit_unit->khr = queue->device->phys_dev->api_version < VK_API_VERSION_1_2 || - queue->device->phys_dev->instance->api_version < VK_API_VERSION_1_2; - - /* As D3D12 fences are rewindable, we add the wait synchronously as not to miss a temporarily signalled value - between vkQueueSubmit and processing the submit unit*/ - for (i = 0, k = 0; i < submit_count; i++) - { - timeline_submit_info = wine_vk_find_struct(&submits[i], TIMELINE_SEMAPHORE_SUBMIT_INFO); - d3d12_submit_info = wine_vk_find_struct(&submits_win[i], D3D12_FENCE_SUBMIT_INFO_KHR); - - host_timeline_values = wine_vk_find_struct(&submit_unit->submits[i], TIMELINE_SEMAPHORE_SUBMIT_INFO); - - if (d3d12_submit_info && !host_timeline_values) - { - host_timeline_values = conversion_context_alloc(&submit_unit->ctx, sizeof(*host_timeline_values)); - host_timeline_values->sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; - host_timeline_values->pNext = submit_unit->submits[i].pNext; - host_timeline_values->waitSemaphoreValueCount = d3d12_submit_info->waitSemaphoreValuesCount; - MEMDUP(&submit_unit->ctx, host_timeline_values->pWaitSemaphoreValues, d3d12_submit_info->pWaitSemaphoreValues, - d3d12_submit_info->waitSemaphoreValuesCount); - host_timeline_values->signalSemaphoreValueCount = d3d12_submit_info->signalSemaphoreValuesCount; - MEMDUP(&submit_unit->ctx, host_timeline_values->pSignalSemaphoreValues, d3d12_submit_info->pSignalSemaphoreValues, - d3d12_submit_info->signalSemaphoreValuesCount); - submit_unit->submits[i].pNext = host_timeline_values; - } - - for (j = 0; j < submits[i].waitSemaphoreCount; j++) - { - sem = wine_semaphore_from_handle(submits[i].pWaitSemaphores[j]); - - if (sem->handle_type != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - continue; - - if (timeline_submit_info) - wait_value = timeline_submit_info->pWaitSemaphoreValues[j]; - else - wait_value = d3d12_submit_info->pWaitSemaphoreValues[j]; - - submit_unit->waits = realloc(submit_unit->waits, (k + 1) * sizeof(*submit_unit->waits)); - submit_unit->waits[k] = NULL; - - d3d12_semaphore_lock(sem); - - if ((((uint64_t*)host_timeline_values->pWaitSemaphoreValues)[j] = - d3d12_semaphore_try_get_wait_value_locked(sem, wait_value, queue)) == -1) - submit_unit->waits[k] = d3d12_semaphore_push_wait_locked(sem, wait_value); - - d3d12_semaphore_unlock(sem); - k++; - } - } - - pthread_mutex_lock(&queue->submissions_mutex); - queue->processing = true; - list_add_tail(&queue->submissions, &submit_unit->entry); - pthread_cond_signal(&queue->submissions_cond); - pthread_mutex_unlock(&queue->submissions_mutex); - - return VK_SUCCESS; -} - -VkResult wine_vkQueueSubmit(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo *submits, VkFence fence, - void *submits_win) +VkResult wine_vkQueueSubmit(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo *submits, VkFence fence) { struct wine_queue *queue = wine_queue_from_handle(queue_handle); unsigned int i, k; TRACE("(%p %u %p 0x%s)\n", queue_handle, submit_count, submits, wine_dbgstr_longlong(fence)); - if (is_virtual_queue(queue)) - return virtual_queue_submit(queue, submit_count, submits, fence, submits_win); - for (i = 0; i < submit_count; i++) { for (k = 0; k < submits[i].waitSemaphoreCount; k++) { if (wine_semaphore_from_handle(submits[i].pWaitSemaphores[k])->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - return virtual_queue_submit(queue, submit_count, submits, fence, submits_win); + { + FIXME("Queue submissions with waits on D3D12-Fence compatible timeline semaphores not supported.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } } for (k = 0; k < submits[i].signalSemaphoreCount; k++) { if (wine_semaphore_from_handle(submits[i].pSignalSemaphores[k])->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - return virtual_queue_submit(queue, submit_count, submits, fence, submits_win); + { + FIXME("Queue submissions with signalling D3D12-Fence compatible timeline semaphores not supported.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } } } return vk_queue_submit_unwrap(queue, submit_count, submits, fence); @@ -5023,77 +4499,6 @@ static void duplicate_array_for_unwrapping(struct conversion_context *ctx, void *ptr = out; } -static NTSTATUS virtual_queue_submit2(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence, bool khr) -{ - VkSemaphoreSubmitInfo *sem_submit_info; - struct queue_submit_unit *submit_unit; - VkSubmitInfo2 *queue_submit; - struct wine_semaphore *sem; - unsigned int i, j, k; - uint64_t wait_value; - bool device_lost; - - init_virtual_queue(queue); - - pthread_mutex_lock(&queue->submissions_mutex); - device_lost = queue->device_lost; - pthread_mutex_unlock(&queue->submissions_mutex); - if (device_lost) - return VK_ERROR_DEVICE_LOST; - - submit_unit = malloc(sizeof(*submit_unit)); - init_conversion_context(&submit_unit->ctx); - submit_unit->submit_count = submit_count; - submit_unit->submits = NULL; - submit_unit->submits2 = copy_VkSubmitInfo2_array(&submit_unit->ctx, submits, submit_count); - submit_unit->fence = fence; - submit_unit->waits = NULL; - submit_unit->khr = khr; - - /* As D3D12 fences are rewindable, we add the wait synchronously as not to miss a temporarily signalled value - between vkQueueSubmit and processing the submit unit */ - for (i = 0, k = 0; i < submit_count; i++) - { - queue_submit = &submit_unit->submits2[i]; - - for (j = 0; j < queue_submit->waitSemaphoreInfoCount; j++) - { - sem_submit_info = (VkSemaphoreSubmitInfo *) &queue_submit->pWaitSemaphoreInfos[j]; - sem = wine_semaphore_from_handle(sem_submit_info->semaphore); - - if (sem->handle_type != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - continue; - - wait_value = sem_submit_info->value; - - submit_unit->waits = realloc(submit_unit->waits, (k + 1) * sizeof(*submit_unit->waits)); - submit_unit->waits[k] = NULL; - - d3d12_semaphore_lock(sem); - - if ((sem_submit_info->value = - d3d12_semaphore_try_get_wait_value_locked(sem, wait_value, queue)) == -1) - submit_unit->waits[k] = d3d12_semaphore_push_wait_locked(sem, wait_value); - - d3d12_semaphore_unlock(sem); - k++; - } - } - - pthread_mutex_lock(&queue->submissions_mutex); - queue->processing = true; - if (fence) - { - wine_fence_from_handle(fence)->queue = queue; - wine_fence_from_handle(fence)->wait_assist = true; - } - list_add_tail(&queue->submissions, &submit_unit->entry); - pthread_cond_signal(&queue->submissions_cond); - pthread_mutex_unlock(&queue->submissions_mutex); - - return VK_SUCCESS; -} - VkResult vk_queue_submit_2_unwrap(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo2 *submits_orig, VkFence fence, bool khr) { @@ -5144,23 +4549,26 @@ static VkResult vk_queue_submit_2(VkQueue queue_handle, uint32_t submit_count, c TRACE("(%p, %u, %p, %s)\n", queue_handle, submit_count, submits, wine_dbgstr_longlong(fence)); - if (is_virtual_queue(queue)) - return virtual_queue_submit2(queue, submit_count, submits, fence, khr); - for (i = 0; i < submit_count; i++) { for (k = 0; k < submits[i].waitSemaphoreInfoCount; k++) { if (wine_semaphore_from_handle(submits[i].pWaitSemaphoreInfos[k].semaphore)->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - return virtual_queue_submit2(queue, submit_count, submits, fence, khr); + { + FIXME("Queue submissions with waits on D3D12-Fence compatible timeline semaphores not supported.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } } for (k = 0; k < submits[i].signalSemaphoreInfoCount; k++) { if (wine_semaphore_from_handle(submits[i].pSignalSemaphoreInfos[k].semaphore)->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - return virtual_queue_submit2(queue, submit_count, submits, fence, khr); + { + FIXME("Queue submissions signalling D3D12-Fence compatible timeline semaphores not supported.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } } } @@ -5179,7 +4587,6 @@ VkResult wine_vkQueueSubmit2KHR(VkQueue queue, uint32_t submit_count, const VkSu VkResult wine_vkQueuePresentKHR(VkQueue queue_handle, const VkPresentInfoKHR *present_info) { - struct wine_queue *queue = wine_queue_from_handle(queue_handle); VkPresentInfoKHR host_present_info = *present_info; struct wine_semaphore *semaphore; struct conversion_context ctx; @@ -5199,14 +4606,6 @@ VkResult wine_vkQueuePresentKHR(VkQueue queue_handle, const VkPresentInfoKHR *pr } } - if (is_virtual_queue(queue)) - { - pthread_mutex_lock(&queue->submissions_mutex); - while (queue->processing) - pthread_cond_wait(&queue->submissions_cond, &queue->submissions_mutex); - pthread_mutex_unlock(&queue->submissions_mutex); - } - init_conversion_context(&ctx); host_present_info.pWaitSemaphores = unwrap_semaphore_array(present_info->pWaitSemaphores, present_info->waitSemaphoreCount, &ctx); ret = fshack_vk_queue_present(queue_handle, &host_present_info); @@ -5225,15 +4624,6 @@ VkResult wine_vkQueueBindSparse(VkQueue queue_handle, uint32_t bind_info_count, TRACE("(%p, %u, %p, 0x%s)\n", queue, bind_info_count, bind_info, wine_dbgstr_longlong(fence)); - if (is_virtual_queue(queue)) - { - FIXME("Can't process sparse bind calls on virtual queue, flushing.\n"); - pthread_mutex_lock(&queue->submissions_mutex); - while (queue->processing) - pthread_cond_wait(&queue->submissions_cond, &queue->submissions_mutex); - pthread_mutex_unlock(&queue->submissions_mutex); - } - for (i = 0; i < bind_info_count; i++) { batch = (VkBindSparseInfo *)&bind_info[i]; @@ -5302,20 +4692,3 @@ VkResult wine_vkQueueBindSparse(VkQueue queue_handle, uint32_t bind_info_count, free_conversion_context(&ctx); return ret; } - -VkResult wine_vkQueueWaitIdle(VkQueue queue_handle) -{ - struct wine_queue *queue = wine_queue_from_handle(queue_handle); - - TRACE("(%p)\n", queue); - - if (is_virtual_queue(queue)) - { - pthread_mutex_lock(&queue->submissions_mutex); - while (queue->processing) - pthread_cond_wait(&queue->submissions_cond, &queue->submissions_mutex); - pthread_mutex_unlock(&queue->submissions_mutex); - } - - return queue->device->funcs.p_vkQueueWaitIdle(queue->queue); -} diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 218c2be9efe..aac1c65050d 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -142,7 +142,6 @@ struct wine_instance */ struct wine_phys_dev **phys_devs; uint32_t phys_dev_count; - uint32_t api_version; VkBool32 enable_wrapper_list; struct list wrappers; @@ -173,7 +172,6 @@ struct wine_phys_dev VkPhysicalDeviceMemoryProperties memory_properties; VkExtensionProperties *extensions; uint32_t extension_count; - uint32_t api_version; uint32_t external_memory_align; @@ -196,22 +194,6 @@ struct wine_queue uint32_t queue_index; VkDeviceQueueCreateFlags flags; - bool virtual_queue; - bool processing; - bool device_lost; - - pthread_t virtual_queue_thread; - pthread_mutex_t submissions_mutex; - pthread_cond_t submissions_cond; - struct list submissions; - - pthread_t signal_thread; - pthread_mutex_t signaller_mutex; - pthread_cond_t signaller_cond; - struct list signal_ops; - - bool stop; - struct wine_vk_mapping mapping; }; From 15f490e47b550d10810ebd2fa83d10066c7e407e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Aug 2023 18:45:34 -0600 Subject: [PATCH 1519/2777] Revert "winevulkan: Implement vkWaitForFences and vkSignalSemaphore for D3D12-Fence compatible timeline semaphores." This reverts commit 6d2a0863d60e67825a30c7e735b68e5c01f48fb3. CW-Bug-Id: #22526 --- dlls/winevulkan/vulkan.c | 276 +------------------------------ dlls/winevulkan/vulkan_private.h | 20 +-- 2 files changed, 7 insertions(+), 289 deletions(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index d0b90293344..ac683720673 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -26,9 +26,6 @@ #include #include #include -#include -#include -#include #include "ntstatus.h" #define WIN32_NO_STATUS @@ -3697,108 +3694,6 @@ static void d3d12_semaphore_unlock(struct wine_semaphore *semaphore) pthread_mutex_unlock(&semaphore->d3d12_fence_shm->mutex); } -/* returns -1 when there is no queued update that would satisfy the wait */ -static uint64_t d3d12_semaphore_try_get_wait_value_locked(struct wine_semaphore *semaphore, uint64_t virtual_value, - struct VkQueue_T *waiting_queue) -{ - struct pending_update *update; - uint64_t ret = -1; - unsigned int i; - - if (semaphore->d3d12_fence_shm->virtual_value >= virtual_value) - return 0; - - return ret; -} - -static struct pending_wait *d3d12_semaphore_push_wait_locked(struct wine_semaphore *semaphore, uint64_t virtual_value) -{ - struct pending_wait *wait; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(semaphore->d3d12_fence_shm->pending_waits); i++) - { - wait = &semaphore->d3d12_fence_shm->pending_waits[i]; - if (!wait->present) - break; - } - - if (i == ARRAY_SIZE(semaphore->d3d12_fence_shm->pending_waits)) - { - FIXME("Failed to wait on semaphore %p, maximum waits exceeded.\n", semaphore); - return NULL; - } - - wait->present = true; - wait->satisfied = false; - wait->virtual_value = virtual_value; - wait->physical_value = 0; - - return wait; -} - -static uint64_t d3d12_semaphore_pop_wait_locked(struct wine_semaphore *semaphore, struct pending_wait *wait) -{ - wait->satisfied = false; - wait->present = false; - - return wait->physical_value; -} - -static void d3d12_semaphore_satisfy_waits_locked(struct wine_semaphore *semaphore, uint64_t virtual_value, - uint64_t physical_value) -{ - struct pending_wait *wait; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(semaphore->d3d12_fence_shm->pending_waits); i++) - { - wait = &semaphore->d3d12_fence_shm->pending_waits[i]; - - if (wait->present && !wait->satisfied && wait->virtual_value <= virtual_value) - { - wait->satisfied = true; - wait->physical_value = physical_value; - pthread_cond_signal(&wait->cond); - } - } -} - -static bool d3d12_semaphore_pop_pending_signal_locked(struct wine_semaphore *semaphore, uint64_t phys_val, struct pending_update *ret) -{ - struct pending_update *update; - unsigned int i; - - for (i = 0; i < semaphore->d3d12_fence_shm->pending_updates_count; i++) - { - if (semaphore->d3d12_fence_shm->pending_updates[i].physical_value == phys_val) - { - update = &semaphore->d3d12_fence_shm->pending_updates[i]; - if (ret) - *ret = *update; - *update = semaphore->d3d12_fence_shm->pending_updates[--semaphore->d3d12_fence_shm->pending_updates_count]; - return true; - } - } - - return false; -} - -static void d3d12_semaphore_update_phys_val_locked(struct wine_semaphore *sem, uint64_t phys_val) -{ - struct pending_update pending; - - /* Based off linked VKD3D-Proton implementation, but we don't signal CPU waits here. - * https://github.com/HansKristian-Work/vkd3d-proton/blob/829ac72e3d381006a843c183e613e8ee77e0b292/libs/vkd3d/command.c#L758 */ - while (sem->d3d12_fence_shm->physical_value < phys_val) - { - sem->d3d12_fence_shm->physical_value++; - - if (d3d12_semaphore_pop_pending_signal_locked(sem, sem->d3d12_fence_shm->physical_value, &pending)) - sem->d3d12_fence_shm->virtual_value = pending.virtual_value; - } -} - VkResult wine_vkCreateSemaphore(VkDevice device_handle, const VkSemaphoreCreateInfo *create_info, const VkAllocationCallbacks *allocator, VkSemaphore *semaphore, void *win_create_info) { @@ -3811,11 +3706,9 @@ VkResult wine_vkCreateSemaphore(VkDevice device_handle, const VkSemaphoreCreateI VkSemaphoreGetFdInfoKHR fd_info; pthread_mutexattr_t mutex_attr; struct wine_semaphore *object; - pthread_condattr_t cond_attr; OBJECT_ATTRIBUTES attr; HANDLE section_handle; LARGE_INTEGER li; - unsigned int i; VkResult res; SIZE_T size; int fd; @@ -3937,14 +3830,6 @@ VkResult wine_vkCreateSemaphore(VkDevice device_handle, const VkSemaphoreCreateI } pthread_mutexattr_destroy(&mutex_attr); - for (i = 0; i < ARRAY_SIZE(object->d3d12_fence_shm->pending_waits); i++) - { - pthread_condattr_init(&cond_attr); - pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED); - pthread_cond_init(&object->d3d12_fence_shm->pending_waits[i].cond, &cond_attr); - pthread_condattr_destroy(&cond_attr); - } - WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance, object, object->fence_timeline_semaphore, object); } if (object->fence_timeline_semaphore == VK_NULL_HANDLE) @@ -4196,41 +4081,14 @@ static VkResult vk_signal_semaphore(VkDevice device_handle, const VkSemaphoreSig static NTSTATUS wine_vk_signal_semaphore(VkDevice device, const VkSemaphoreSignalInfo *signal_info, bool khr) { - uint64_t phys_val; - VkResult vr; - struct wine_semaphore *semaphore = wine_semaphore_from_handle(signal_info->semaphore); TRACE("(%p, %p)\n", device, signal_info); if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) { - VkSemaphoreSignalInfo step_signal_info; - - d3d12_semaphore_lock(semaphore); - - assert(semaphore->d3d12_fence_shm->counter == phys_val); - phys_val++; - - semaphore->d3d12_fence_shm->counter = semaphore->d3d12_fence_shm->physical_value = phys_val; - - step_signal_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO; - step_signal_info.pNext = NULL; - step_signal_info.semaphore = signal_info->semaphore; - step_signal_info.value = phys_val; - - vr = vk_signal_semaphore(device, &step_signal_info, khr); - if (vr != VK_SUCCESS) - { - d3d12_semaphore_unlock(semaphore); - return vr; - } - - d3d12_semaphore_satisfy_waits_locked(semaphore, signal_info->value, 0); - semaphore->d3d12_fence_shm->virtual_value = signal_info->value; - - d3d12_semaphore_unlock(semaphore); - return VK_SUCCESS; + FIXME("Signalling D3D12-Fence compatible timeline semaphore not supported.\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; } return vk_signal_semaphore(device, signal_info, khr); @@ -4278,143 +4136,21 @@ static VkResult vk_wait_semaphores(struct wine_device *device, const VkSemaphore static VkResult wine_vk_wait_semaphores(VkDevice device_handle, const VkSemaphoreWaitInfo *wait_info, uint64_t timeout, bool khr) { - VkSemaphoreWaitInfo wait_info_dup = *wait_info; - struct timespec abs_timeout, start_time; - struct pending_wait **pending_waits; - struct pending_wait *pending_wait; - unsigned int i, remaining_waits; - VkSemaphore* semaphores_dup; - uint64_t *values_dup; - uint64_t phys_val; - int wait_stat; - VkResult res; + unsigned int i; TRACE("(%p, %p, 0x%s)\n", device_handle, wait_info, wine_dbgstr_longlong(timeout)); - if (timeout) - { - clock_gettime(CLOCK_REALTIME, &start_time); - - abs_timeout.tv_sec = start_time.tv_sec + (timeout / NANOSECONDS_IN_A_SECOND); - abs_timeout.tv_nsec = start_time.tv_nsec + (timeout % NANOSECONDS_IN_A_SECOND); - if (abs_timeout.tv_nsec >= NANOSECONDS_IN_A_SECOND) - { - abs_timeout.tv_sec++; - abs_timeout.tv_nsec-=NANOSECONDS_IN_A_SECOND; - } - } - - wait_info_dup.pSemaphores = semaphores_dup = calloc(wait_info->semaphoreCount, sizeof(VkSemaphore)); - wait_info_dup.pValues = values_dup = calloc(wait_info->semaphoreCount, sizeof(uint64_t)); - pending_waits = calloc(wait_info->semaphoreCount, sizeof(struct pending_wait *)); - for (i = 0; i < wait_info->semaphoreCount; i++) { struct wine_semaphore *semaphore = wine_semaphore_from_handle(wait_info->pSemaphores[i]); - semaphores_dup[i] = wait_info->pSemaphores[i]; - values_dup[i] = wait_info->pValues[i]; - if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) { - d3d12_semaphore_lock(semaphore); - if ((values_dup[i] = d3d12_semaphore_try_get_wait_value_locked(semaphore, wait_info->pValues[i], NULL)) == -1) - { - if (!timeout) - { - d3d12_semaphore_unlock(semaphore); - continue; - } - - pending_wait = d3d12_semaphore_push_wait_locked(semaphore, wait_info->pValues[i]); - - if (wait_info->flags & VK_SEMAPHORE_WAIT_ANY_BIT) - { - /* Keep scheduling a wait of current physical_value+1 until the desired virtual value is signaled */ - values_dup[i] = semaphore->d3d12_fence_shm->physical_value + 1; - pending_waits[i] = pending_wait; - } - else - { - while (!pending_wait->satisfied && wait_stat != ETIMEDOUT) - wait_stat = pthread_cond_timedwait(&pending_wait->cond, &semaphore->d3d12_fence_shm->mutex, &abs_timeout); - - values_dup[i] = d3d12_semaphore_pop_wait_locked(semaphore, pending_wait); - - if (wait_stat == ETIMEDOUT) - { - d3d12_semaphore_unlock(semaphore); - free(semaphores_dup); - free(values_dup); - free(pending_waits); - return VK_TIMEOUT; - } - } - } - d3d12_semaphore_unlock(semaphore); - } - } - do - { - if (timeout) - { - clock_gettime(CLOCK_REALTIME, &start_time); - - if (start_time.tv_sec > abs_timeout.tv_sec || - (start_time.tv_sec == abs_timeout.tv_sec && start_time.tv_nsec >= abs_timeout.tv_nsec)) - timeout = 0; - else - timeout = ((abs_timeout.tv_sec - start_time.tv_sec) * NANOSECONDS_IN_A_SECOND) + - (abs_timeout.tv_nsec - start_time.tv_nsec); - } - - remaining_waits = 0; - res = vk_wait_semaphores(wine_device_from_handle(device_handle), &wait_info_dup, timeout, khr); - - for (i = 0; i < wait_info->semaphoreCount; i++) - { - struct wine_semaphore * semaphore = wine_semaphore_from_handle(wait_info->pSemaphores[i]); - - if (pending_waits[i]) - { - remaining_waits++; - - d3d12_semaphore_lock(semaphore); - if (res != VK_SUCCESS || pending_waits[i]->satisfied) - { - values_dup[i] = pending_waits[i]->physical_value; - d3d12_semaphore_pop_wait_locked(semaphore, pending_waits[i]); - pending_waits[i] = NULL; - } - d3d12_semaphore_unlock(semaphore); - } - } - } - while (res == VK_SUCCESS && remaining_waits); - - /* Make sure the physical value we waited on is processed before returning */ - for (i = 0; i < wait_info_dup.semaphoreCount; i++) - { - struct wine_semaphore *semaphore = wine_semaphore_from_handle(wait_info_dup.pSemaphores[i]); - - if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - { - d3d12_semaphore_lock(semaphore); - if (wait_info->flags & VK_SEMAPHORE_WAIT_ANY_BIT) - { - if (!vk_get_semaphore_counter_value(device_handle, semaphores_dup[i], &phys_val, khr)) - d3d12_semaphore_update_phys_val_locked(semaphore, phys_val); - } - else - d3d12_semaphore_update_phys_val_locked(semaphore, values_dup[i]); - d3d12_semaphore_unlock(semaphore); + FIXME("Waiting on D3D12-Fence compatible timeline semaphores not supported."); + return VK_ERROR_OUT_OF_HOST_MEMORY; } } - - free(semaphores_dup); - free(values_dup); - free(pending_waits); - return res; + return vk_wait_semaphores(wine_device_from_handle(device_handle), wait_info, timeout, khr); } VkResult wine_vkWaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo *wait_info, uint64_t timeout) diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index aac1c65050d..d5b86388263 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -24,7 +24,6 @@ #define VK_NO_PROTOTYPES #include -#include #include "vulkan_loader.h" #include "vulkan_thunks.h" @@ -337,24 +336,7 @@ struct wine_semaphore struct { pthread_mutex_t mutex; - uint64_t virtual_value, physical_value, counter; - - struct pending_wait - { - bool present, satisfied; - uint64_t virtual_value; - uint64_t physical_value; - pthread_cond_t cond; - } pending_waits[100]; - - struct pending_update - { - uint64_t virtual_value; - uint64_t physical_value; - pid_t signalling_pid; - struct wine_queue *signalling_queue; - } pending_updates[100]; - uint32_t pending_updates_count; + uint64_t virtual_value; } *d3d12_fence_shm; }; From 4c5a112aa3c2060c67fad36b7929c3ba5d64482b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 27 Dec 2022 17:59:06 -0600 Subject: [PATCH 1520/2777] winevulkan: Only append VK_KHR_timeline_semaphore for Vk API version < 1.2. CW-Bug-Id: #22526 --- dlls/winevulkan/vulkan.c | 27 +++++++++++++++++++++++++++ dlls/winevulkan/vulkan_private.h | 2 ++ 2 files changed, 29 insertions(+) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index ac683720673..faf6c39d888 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -239,6 +239,7 @@ static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance struct wine_phys_dev *object; uint32_t num_host_properties, num_properties = 0; VkExtensionProperties *host_properties = NULL; + VkPhysicalDeviceProperties physdev_properties; BOOL have_external_memory_host = FALSE; VkResult res; unsigned int i, j; @@ -250,6 +251,9 @@ static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance object->handle = handle; object->phys_dev = phys_dev; + instance->funcs.p_vkGetPhysicalDeviceProperties(phys_dev, &physdev_properties); + object->api_version = physdev_properties.apiVersion; + handle->base.unix_handle = (uintptr_t)object; WINE_VK_ADD_DISPATCHABLE_MAPPING(instance, handle, phys_dev, object); @@ -503,6 +507,8 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de else if (!strcmp(extension_name, "VK_KHR_timeline_semaphore")) append_timeline = 0; } + if (append_timeline) + append_timeline = phys_dev->api_version < VK_API_VERSION_1_2 || phys_dev->instance->api_version < VK_API_VERSION_1_2; if (append_timeline) { append_timeline = 0; @@ -1054,6 +1060,8 @@ VkResult wine_vkCreateInstance(const VkInstanceCreateInfo *create_info, app_info->engineVersion); TRACE("API version %#x.\n", app_info->apiVersion); + object->api_version = app_info->apiVersion; + if (app_info->pEngineName && !strcmp(app_info->pEngineName, "idTech")) object->quirks |= WINEVULKAN_QUIRK_GET_DEVICE_PROC_ADDR; } @@ -1700,6 +1708,25 @@ static void wine_vk_get_physical_device_external_semaphore_properties(struct win break; case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT: { + unsigned int i; + + if (phys_dev->api_version < VK_API_VERSION_1_2 || + phys_dev->instance->api_version < VK_API_VERSION_1_2) + { + for (i = 0; i < phys_dev->extension_count; i++) + { + if (!strcmp(phys_dev->extensions[i].extensionName, "VK_KHR_timeline_semaphore")) + break; + } + if (i == phys_dev->extension_count) + { + properties->exportFromImportedHandleTypes = 0; + properties->compatibleHandleTypes = 0; + properties->externalSemaphoreFeatures = 0; + return; + } + } + if ((p_semaphore_type_info = wine_vk_find_struct(&semaphore_info_dup, SEMAPHORE_TYPE_CREATE_INFO))) { p_semaphore_type_info->semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE; diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index d5b86388263..f89787eb67c 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -141,6 +141,7 @@ struct wine_instance */ struct wine_phys_dev **phys_devs; uint32_t phys_dev_count; + uint32_t api_version; VkBool32 enable_wrapper_list; struct list wrappers; @@ -171,6 +172,7 @@ struct wine_phys_dev VkPhysicalDeviceMemoryProperties memory_properties; VkExtensionProperties *extensions; uint32_t extension_count; + uint32_t api_version; uint32_t external_memory_align; From ed15e98fd668d3fd4013023d4759de8ecb80f79f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Aug 2023 19:34:16 -0600 Subject: [PATCH 1521/2777] winevulkan: Force copying VkSubmitInfo[2] structures. Based on patches by Derek Lesho. CW-Bug-Id: #22526 --- dlls/winevulkan/make_vulkan | 51 ++++++++++++++++++++++++------------- dlls/winevulkan/vulkan.c | 2 +- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index b7d57f2964e..1332875e3ef 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -220,7 +220,7 @@ FUNCTION_OVERRIDES = { "vkSignalSemaphore" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, "vkWaitSemaphores" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, "vkQueueBindSparse" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, - "vkQueueSubmit" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, + "vkQueueSubmit" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE, "extra_param" : "pSubmits"}, "vkQueueSubmit2" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, # VK_KHR_surface @@ -311,11 +311,16 @@ STRUCT_CHAIN_CONVERSIONS = { "VkPhysicalDeviceImageFormatInfo2": [], "VkPhysicalDeviceExternalSemaphoreInfo": [], "VkSemaphoreCreateInfo": ["VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR"], - "VkSubmitInfo": [], + "VkSubmitInfo": ["VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR"], "VkSubmitInfo2": [], "VkBindSparseInfo" : [], } +STRUCT_COPY = { + "VkSubmitInfo", + "VkSubmitInfo2", +}; + # Some struct members are conditionally ignored and callers are free to leave them uninitialized. # We can't deduce that from XML, so we allow expressing it here. MEMBER_LENGTH_EXPRESSIONS = { @@ -1403,6 +1408,9 @@ class VkVariable(object): if struct.needs_conversion(conv, unwrap, Direction.OUTPUT, is_const): conversions.append(StructConversionFunction(struct, Direction.OUTPUT, conv, unwrap, is_const)) + if struct.name in STRUCT_COPY: + conversions.append(StructConversionFunction(struct, Direction.INPUT, False, unwrap, is_const, True)) + if self.is_static_array() or self.is_dynamic_array(): for conv in [False, True]: if self.needs_conversion(conv, unwrap, Direction.INPUT, parent_const): @@ -1532,7 +1540,7 @@ class VkMember(VkVariable): values=values, object_type=object_type, bit_width=bit_width, returnedonly=returnedonly, parent=parent, selection=selection, selector=selector) - def copy(self, input, output, direction, conv, unwrap): + def copy(self, input, output, direction, conv, unwrap, copy): """ Helper method for use by conversion logic to generate a C-code statement to copy this member. - `conv` indicates whether the statement is in a struct alignment conversion path. """ @@ -1590,6 +1598,8 @@ class VkMember(VkVariable): elif self.is_static_array(): bytes_count = "{0} * sizeof({1})".format(self.array_len, self.type) return "memcpy({0}{1}, {2}{1}, {3});\n".format(output, self.name, input, bytes_count) + elif self.is_dynamic_array() and copy: + return "MEMDUP(ctx, {0}{1}, {2}{1}, {3});\n".format(output, self.name, input, self.get_dyn_array_len(input, conv)) elif direction == Direction.INPUT: return "{0}{1} = {2};\n".format(output, self.name, self.value(input, conv)) elif conv and direction == Direction.OUTPUT and self.is_pointer(): @@ -2312,21 +2322,25 @@ class VkStruct(Sequence): class StructConversionFunction(object): - def __init__(self, struct, direction, conv, unwrap, const): + def __init__(self, struct, direction, conv, unwrap, const, copy=False): self.direction = direction self.operand = struct self.type = struct.name self.conv = conv self.unwrap = unwrap or not self.operand.needs_unwrapping() self.const = const + self.copy = copy - name = "convert_{0}_".format(self.type) - win_type = "win32" if self.conv else "win64" - host_part = "host" if self.unwrap else "unwrapped_host" - if self.direction == Direction.INPUT: - name += "{0}_to_{1}".format(win_type, host_part) - else: # Direction.OUTPUT - name += "{0}_to_{1}".format(host_part, win_type) + if copy: + name = "copy_{0}".format(self.type) + else: + name = "convert_{0}_".format(self.type) + win_type = "win32" if self.conv else "win64" + host_part = "host" if self.unwrap else "unwrapped_host" + if self.direction == Direction.INPUT: + name += "{0}_to_{1}".format(win_type, host_part) + else: # Direction.OUTPUT + name += "{0}_to_{1}".format(host_part, win_type) self.name = name def __eq__(self, other): @@ -2358,7 +2372,7 @@ class StructConversionFunction(object): body = "" - if not self.conv: + if not self.conv and not self.copy: body += "#ifdef _WIN64\n" needs_alloc = self.direction != Direction.OUTPUT and self.operand.needs_alloc(self.conv, self.unwrap) @@ -2368,8 +2382,11 @@ class StructConversionFunction(object): if self.direction == Direction.OUTPUT and self.const: win_type = "const " + win_type - if self.conv: + if self.copy: + body += "void {0}(".format(self.name) + else: body += "static inline void {0}(".format(self.name) + if self.conv: if self.direction == Direction.OUTPUT: params = ["const {0} *in".format(self.type), "{0} *out".format(win_type)] @@ -2386,8 +2403,6 @@ class StructConversionFunction(object): body += ")\n" else: - body += "static inline void {0}(".format(self.name) - params = ["const {0} *in".format(self.type), "{0} *out".format(self.type)] # Generate parameter list @@ -2427,7 +2442,7 @@ class StructConversionFunction(object): body += " || ".join("selector == {}".format(s) for s in m.selection) body += ")\n " - body += " " + m.copy("in->", "out->", self.direction, self.conv, self.unwrap) + body += " " + m.copy("in->", "out->", self.direction, self.conv, self.unwrap, self.copy) if needs_extensions: if self.conv and self.direction == Direction.INPUT: @@ -2487,7 +2502,7 @@ class StructConversionFunction(object): copy_body += ident + "out_ext->pNext = NULL;\n" continue - copy_body += ident + m.copy("in_ext->", "out_ext->", self.direction, self.conv, True) + copy_body += ident + m.copy("in_ext->", "out_ext->", self.direction, self.conv, True, self.copy) # Generate the definition of "in_ext" if we need it if "in_ext->" in copy_body: @@ -2522,7 +2537,7 @@ class StructConversionFunction(object): body += " FIXME(\"Unexpected pNext\\n\");\n" body += "}\n" - if not self.conv: + if not self.conv and not self.copy: body += "#endif /* _WIN64 */\n" body += "\n" diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index faf6c39d888..a755600813e 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -4218,7 +4218,7 @@ VkResult vk_queue_submit_unwrap(struct wine_queue *queue, uint32_t submit_count, return ret; } -VkResult wine_vkQueueSubmit(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo *submits, VkFence fence) +VkResult wine_vkQueueSubmit(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo *submits, VkFence fence, void *submits_win_ptr) { struct wine_queue *queue = wine_queue_from_handle(queue_handle); unsigned int i, k; From 057793e30adf8fde642d5698bd35f6d50b472c8e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 31 Jul 2023 11:12:21 -0600 Subject: [PATCH 1522/2777] winevulkan: Support waiting for and signalling d3d12 shared fences. CW-Bug-Id: #22526 --- dlls/winevulkan/vulkan.c | 708 +++++++++++++++++++++++++------ dlls/winevulkan/vulkan_private.h | 39 +- 2 files changed, 610 insertions(+), 137 deletions(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index a755600813e..ff5cca60b28 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -26,6 +26,13 @@ #include #include #include +#include +#include +#include +#include +#ifdef HAVE_SYS_SYSCALL_H +# include +#endif #include "ntstatus.h" #define WIN32_NO_STATUS @@ -33,6 +40,7 @@ #include "winnt.h" #include "winioctl.h" #include "wine/server.h" +#include "wine/list.h" #include "vulkan_private.h" #include "wine/vulkan_driver.h" @@ -40,6 +48,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(vulkan); +static int debug_level; static BOOL is_wow64(void) { @@ -120,6 +129,38 @@ static uint64_t wine_vk_get_wrapper(struct wine_instance *instance, uint64_t nat return result; } +static void signal_timeline_sem(struct wine_device *device, VkSemaphore sem, uint64_t *value) +{ + /* May be called from native thread. */ + struct VkSemaphoreSignalInfo info = { 0 }; + VkResult res; + + info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO; + info.semaphore = sem; + ++*value; + info.value = *value; + if (device->phys_dev->api_version < VK_API_VERSION_1_2 || device->phys_dev->instance->api_version < VK_API_VERSION_1_2) + res = device->funcs.p_vkSignalSemaphoreKHR(device->device, &info); + else + res = device->funcs.p_vkSignalSemaphore(device->device, &info); + if (res != VK_SUCCESS) + fprintf(stderr, "err:winevulkan:signal_timeline_sem vkSignalSemaphore failed, res=%d.\n", res); +} + +static VkResult wait_semaphores(struct wine_device *device, const VkSemaphoreWaitInfo *wait_info, uint64_t timeout) +{ + if (device->phys_dev->api_version < VK_API_VERSION_1_2 || device->phys_dev->instance->api_version < VK_API_VERSION_1_2) + return device->funcs.p_vkWaitSemaphoresKHR(device->device, wait_info, timeout); + return device->funcs.p_vkWaitSemaphores(device->device, wait_info, timeout); +} + +static VkResult get_semaphore_value(struct wine_device *device, VkSemaphore sem, uint64_t *value) +{ + if (device->phys_dev->api_version < VK_API_VERSION_1_2 || device->phys_dev->instance->api_version < VK_API_VERSION_1_2) + return device->funcs.p_vkGetSemaphoreCounterValueKHR(device->device, sem, value); + return device->funcs.p_vkGetSemaphoreCounterValue(device->device, sem, value); +} + static VkBool32 debug_utils_callback_conversion(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT message_types, const VkDebugUtilsMessengerCallbackDataEXT *callback_data, @@ -574,11 +615,32 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de */ static void wine_vk_device_free(struct wine_device *device) { + struct pending_d3d12_fence_op *op; struct wine_queue *queue; if (!device) return; + if (device->signaller_thread) + { + TRACE("Shutting down signaller thread.\n"); + pthread_mutex_lock(&device->signaller_mutex); + device->stop = 1; + signal_timeline_sem(device, device->sem_poll_update.sem, &device->sem_poll_update.value); + pthread_mutex_unlock(&device->signaller_mutex); + pthread_join(device->signaller_thread, NULL); + device->funcs.p_vkDestroySemaphore(device->device, device->sem_poll_update.sem, NULL); + pthread_cond_destroy(&device->sem_poll_updated_cond); + TRACE("Signaller thread shut down.\n"); + } + pthread_mutex_destroy(&device->signaller_mutex); + + LIST_FOR_EACH_ENTRY(op, &device->free_fence_ops_list, struct pending_d3d12_fence_op, entry) + { + device->funcs.p_vkDestroySemaphore(device->device, op->local_sem.sem, NULL); + free(op); + } + if (device->queues) { unsigned int i; @@ -892,6 +954,9 @@ VkResult wine_vkCreateDevice(VkPhysicalDevice phys_dev_handle, const VkDeviceCre if (!(object = calloc(1, sizeof(*object)))) return VK_ERROR_OUT_OF_HOST_MEMORY; + pthread_mutex_init(&object->signaller_mutex, NULL); + list_init(&object->sem_poll_list); + list_init(&object->free_fence_ops_list); object->phys_dev = phys_dev; if ((callback = (VkCreateInfoWineDeviceCallback *)create_info->pNext) @@ -3721,6 +3786,352 @@ static void d3d12_semaphore_unlock(struct wine_semaphore *semaphore) pthread_mutex_unlock(&semaphore->d3d12_fence_shm->mutex); } +static VkSemaphore create_timeline_semaphore(struct wine_device *device) +{ + VkSemaphoreTypeCreateInfo timeline_info = { 0 }; + VkSemaphoreCreateInfo create_info = { 0 }; + VkSemaphore sem = 0; + VkResult res; + + timeline_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO; + timeline_info.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE; + create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + create_info.pNext = &timeline_info; + + res = device->funcs.p_vkCreateSemaphore(device->device, &create_info, NULL, &sem); + if (res != VK_SUCCESS) + ERR("vkCreateSemaphore failed, res=%d\n", res); + return sem; +} + +static void release_fence_op(struct wine_device *device, struct pending_d3d12_fence_op *op) +{ + list_remove(&op->entry); + WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, op); + list_add_head(&device->free_fence_ops_list, &op->entry); +} + +static int wait_info_realloc(VkSemaphoreWaitInfo *wait_info, uint32_t *wait_alloc_count) +{ + VkSemaphore *new_sem; + uint64_t *new_values; + + if (wait_info->semaphoreCount + 1 <= *wait_alloc_count) + return 1; + new_sem = realloc((void *)wait_info->pSemaphores, *wait_alloc_count * 2 * sizeof(*new_sem)); + if (!new_sem) + { + fprintf(stderr, "err:winevulkan:wait_info_realloc no memory.\n"); + return 0; + } + new_values = realloc((void *)wait_info->pValues, *wait_alloc_count * 2 * sizeof(*new_values)); + if (!new_values) + { + fprintf(stderr, "err:winevulkan:wait_info_realloc no memory.\n"); + return 0; + } + *wait_alloc_count *= 2; + wait_info->pSemaphores = new_sem; + wait_info->pValues = new_values; + return 1; +} + +static int add_sem_wait(VkSemaphoreWaitInfo *wait_info, uint32_t *wait_alloc_count, VkSemaphore sem, uint64_t value) +{ + if (!wait_info_realloc(wait_info, wait_alloc_count)) + return 0; + ((VkSemaphore *)wait_info->pSemaphores)[wait_info->semaphoreCount] = sem; + ((uint64_t *)wait_info->pValues)[wait_info->semaphoreCount] = value; + ++wait_info->semaphoreCount; + return 1; +} + +static int semaphore_process(struct wine_device *device, struct wine_semaphore *sem, + VkSemaphoreWaitInfo *wait_info, uint32_t *wait_alloc_count) +{ + /* Called from native thread. */ + struct pending_d3d12_fence_op *op, *op2; + uint64_t global_sem_wait_value; + int virtual_value_updated = 0; + uint64_t value, virtual_value; + VkResult res; + + /* Check local pending signal ops completion, update shared semaphore. */ + d3d12_semaphore_lock( sem ); + LIST_FOR_EACH_ENTRY_SAFE(op, op2, &sem->pending_signals, struct pending_d3d12_fence_op, entry) + { + if (op->virtual_value <= sem->d3d12_fence_shm->virtual_value) + goto signal_op_complete; + + res = get_semaphore_value(device, op->local_sem.sem, &value); + if (res != VK_SUCCESS) + { + fprintf(stderr, "err:winevulkan:semaphore_process vkGetSemaphoreCounterValue failed, res=%d.\n", res); + goto signal_op_complete; + } + if (value <= op->local_sem.value) + { + if (!add_sem_wait(wait_info, wait_alloc_count, op->local_sem.sem, op->local_sem.value + 1)) + { + d3d12_semaphore_unlock(sem); + return 0; + } + continue; + } + + sem->d3d12_fence_shm->virtual_value = op->virtual_value; + virtual_value_updated = 1; +signal_op_complete: + ++op->local_sem.value; + release_fence_op(device, op); + } + + if (virtual_value_updated) + signal_timeline_sem(device, sem->fence_timeline_semaphore, &sem->d3d12_fence_shm->physical_value); + global_sem_wait_value = sem->d3d12_fence_shm->physical_value + 1; + virtual_value = sem->d3d12_fence_shm->virtual_value; + d3d12_semaphore_unlock(sem); + + /* Complete satisfied local waits. */ + LIST_FOR_EACH_ENTRY_SAFE(op, op2, &sem->pending_waits, struct pending_d3d12_fence_op, entry) + { + if (op->virtual_value > virtual_value) + continue; + + signal_timeline_sem(device, op->local_sem.sem, &op->local_sem.value); + release_fence_op(device, op); + } + + /* Only poll shared semaphore if there are waits pending. */ + if (list_empty(&sem->pending_waits)) + return 1; + return add_sem_wait(wait_info, wait_alloc_count, sem->fence_timeline_semaphore, global_sem_wait_value); +} + +#define SIGNALLER_INITIAL_WAIT_COUNT 256 + +void *signaller_worker(void *arg) +{ +#ifdef HAVE_SYS_SYSCALL_H + int unix_tid = syscall( __NR_gettid ); +#else + int unix_tid = -1; +#endif + struct wine_device *device = arg; + struct wine_semaphore *sem; + VkSemaphoreWaitInfo wait_info = { 0 }; + uint32_t wait_alloc_count = 0; + VkResult res; + + if (debug_level) + fprintf(stderr, "[%d] msg:winevulkan:signaller_worker started.\n", unix_tid); + + wait_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO; + wait_info.flags = VK_SEMAPHORE_WAIT_ANY_BIT; + wait_alloc_count = SIGNALLER_INITIAL_WAIT_COUNT; + if (!(wait_info.pSemaphores = malloc(sizeof(*wait_info.pSemaphores) * wait_alloc_count))) + { + fprintf(stderr, "err:winevulkan:signaller_worker no memory.\n"); + return NULL; + } + if (!(wait_info.pValues = malloc(sizeof(*wait_info.pValues) * wait_alloc_count))) + { + fprintf(stderr, "err:winevulkan:signaller_worker no memory.\n"); + free((void *)wait_info.pSemaphores); + return NULL; + } + + for (;;) + { + pthread_mutex_lock(&device->signaller_mutex); + if (device->stop) + { + pthread_mutex_unlock(&device->signaller_mutex); + break; + } + wait_info.semaphoreCount = 1; + *(VkSemaphore *)wait_info.pSemaphores = device->sem_poll_update.sem; + *(uint64_t *)wait_info.pValues = device->sem_poll_update.value + 1; + LIST_FOR_EACH_ENTRY(sem, &device->sem_poll_list, struct wine_semaphore, poll_entry) + { + if (!semaphore_process(device, sem, &wait_info, &wait_alloc_count)) + { + pthread_mutex_unlock(&device->signaller_mutex); + break; + } + } + device->sem_poll_update_value = device->sem_poll_update.value; + pthread_cond_signal(&device->sem_poll_updated_cond); + pthread_mutex_unlock(&device->signaller_mutex); + while ((res = wait_semaphores(device, &wait_info, 3000000000ull)) == VK_TIMEOUT) + { + if (wait_info.semaphoreCount > 1) + fprintf(stderr, "err:winevulkan:signaller_worker wait timed out with non-empty poll list.\n"); + } + if (res != VK_SUCCESS) + { + fprintf(stderr, "err:winevulkan:signaller_worker error waiting for semaphores, vr %d.\n", res); + break; + } + } + + free((void *)wait_info.pSemaphores); + free((void *)wait_info.pValues); + if (debug_level) + fprintf(stderr, "[%d] msg:winevulkan:signaller_worker exiting.\n", unix_tid); + + return NULL; +} + +static void register_sem_poll(struct wine_device *device, struct wine_semaphore *semaphore) +{ + pthread_mutex_lock(&device->signaller_mutex); + if (!device->signaller_thread) + { + device->sem_poll_update.sem = create_timeline_semaphore(device); + device->sem_poll_update.value = 0; + pthread_cond_init(&device->sem_poll_updated_cond, NULL); + if (TRACE_ON(vulkan)) + debug_level = 4; + else if (WARN_ON(vulkan)) + debug_level = 3; + else if (FIXME_ON(vulkan)) + debug_level = 2; + else if (ERR_ON(vulkan)) + debug_level = 1; + else + debug_level = 0; + if (pthread_create(&device->signaller_thread, NULL, signaller_worker, device)) + ERR("Failed to create signaller_worker.\n"); + WARN("d3d12 fence used, created signaller worker.\n"); + } + assert(!semaphore->poll_entry.next); + list_add_head(&device->sem_poll_list, &semaphore->poll_entry); + signal_timeline_sem(device, device->sem_poll_update.sem, &device->sem_poll_update.value); + pthread_mutex_unlock(&device->signaller_mutex); +} + +static void update_sem_poll_wait_processed(struct wine_device *device) +{ + uint64_t update_value; + + signal_timeline_sem(device, device->sem_poll_update.sem, &device->sem_poll_update.value); + update_value = device->sem_poll_update.value; + while (device->sem_poll_update_value < update_value) + pthread_cond_wait(&device->sem_poll_updated_cond, &device->signaller_mutex); +} + +static void unregister_sem_poll(struct wine_device *device, struct wine_semaphore *semaphore) +{ + struct list *entry; + + pthread_mutex_lock(&device->signaller_mutex); + list_remove(&semaphore->poll_entry); + semaphore->poll_entry.next = semaphore->poll_entry.prev = NULL; + update_sem_poll_wait_processed(device); + pthread_mutex_unlock(&device->signaller_mutex); + + while ((entry = list_head(&semaphore->pending_waits))) + release_fence_op(device, CONTAINING_RECORD(entry, struct pending_d3d12_fence_op, entry)); + while ((entry = list_head(&semaphore->pending_signals))) + release_fence_op(device, CONTAINING_RECORD(entry, struct pending_d3d12_fence_op, entry)); +} + +static struct pending_d3d12_fence_op *get_free_fence_op(struct wine_device *device) +{ + struct pending_d3d12_fence_op *op; + struct list *entry; + + if ((entry = list_head(&device->free_fence_ops_list))) + { + list_remove(entry); + return CONTAINING_RECORD(entry, struct pending_d3d12_fence_op, entry); + } + + if (!(op = malloc(sizeof(*op)))) + { + ERR("No memory.\n"); + return NULL; + } + op->local_sem.sem = create_timeline_semaphore(device); + op->local_sem.value = 0; + ++device->allocated_fence_ops_count; + TRACE("Total allocated fence ops %u.\n", device->allocated_fence_ops_count); + return op; +} + +static void add_sem_wait_op(struct wine_device *device, struct wine_semaphore *semaphore, uint64_t virtual_value, + VkSemaphore *phys_semaphore, uint64_t *phys_wait_value) +{ + struct pending_d3d12_fence_op *op; + + pthread_mutex_lock(&device->signaller_mutex); + LIST_FOR_EACH_ENTRY(op, &semaphore->pending_waits, struct pending_d3d12_fence_op, entry) + { + if (op->virtual_value == virtual_value) + { + *phys_semaphore = op->local_sem.sem; + *phys_wait_value = op->local_sem.value + 1; + pthread_mutex_unlock(&device->signaller_mutex); + return; + } + } + if ((op = get_free_fence_op(device))) + { + op->virtual_value = virtual_value; + *phys_semaphore = op->local_sem.sem; + *phys_wait_value = op->local_sem.value + 1; + list_add_tail(&semaphore->pending_waits, &op->entry); + WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance, semaphore, op->local_sem.sem, op); + signal_timeline_sem(device, device->sem_poll_update.sem, &device->sem_poll_update.value); + TRACE("added wait op, semaphore %p, %s, temp sem %s, %s.\n", semaphore, wine_dbgstr_longlong(virtual_value), + wine_dbgstr_longlong(op->local_sem.sem), wine_dbgstr_longlong(op->local_sem.value)); + } + else + { + *phys_semaphore = 0; + *phys_wait_value = 0; + } + pthread_mutex_unlock(&device->signaller_mutex); +} + +static void add_sem_signal_op(struct wine_device *device, struct wine_semaphore *semaphore, uint64_t virtual_value, + VkSemaphore *phys_semaphore, uint64_t *phys_signal_value, BOOL signal_immediate) +{ + struct pending_d3d12_fence_op *op; + uint64_t value; + + pthread_mutex_lock(&device->signaller_mutex); + if ((op = get_free_fence_op(device))) + { + op->virtual_value = virtual_value; + *phys_semaphore = op->local_sem.sem; + *phys_signal_value = op->local_sem.value + 1; + list_add_tail(&semaphore->pending_signals, &op->entry); + WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance, semaphore, op->local_sem.sem, op); + if (signal_immediate) + { + value = op->local_sem.value; + signal_timeline_sem(device, op->local_sem.sem, &value); + update_sem_poll_wait_processed(device); + TRACE("signal op %p, semaphore %p, %s, temp sem %s, %s.\n", op, semaphore, wine_dbgstr_longlong(virtual_value), + wine_dbgstr_longlong(op->local_sem.sem), wine_dbgstr_longlong(op->local_sem.value)); + } + else + { + signal_timeline_sem(device, device->sem_poll_update.sem, &device->sem_poll_update.value); + TRACE("added signal op, semaphore %p, %s, temp sem %s, %s.\n", semaphore, wine_dbgstr_longlong(virtual_value), + wine_dbgstr_longlong(op->local_sem.sem), wine_dbgstr_longlong(op->local_sem.value)); + } + } + else + { + *phys_semaphore = 0; + *phys_signal_value = 0; + } + pthread_mutex_unlock(&device->signaller_mutex); +} + VkResult wine_vkCreateSemaphore(VkDevice device_handle, const VkSemaphoreCreateInfo *create_info, const VkAllocationCallbacks *allocator, VkSemaphore *semaphore, void *win_create_info) { @@ -3748,6 +4159,9 @@ VkResult wine_vkCreateSemaphore(VkDevice device_handle, const VkSemaphoreCreateI if (!(object = calloc(1, sizeof(*object)))) return VK_ERROR_OUT_OF_HOST_MEMORY; + list_init(&object->pending_signals); + list_init(&object->pending_waits); + object->handle = INVALID_HANDLE_VALUE; if ((export_semaphore_info = wine_vk_find_struct(&create_info_dup, EXPORT_SEMAPHORE_CREATE_INFO))) @@ -3880,6 +4294,12 @@ VkResult wine_vkCreateSemaphore(VkDevice device_handle, const VkSemaphoreCreateI device->funcs.p_vkDestroySemaphore(device->device, object->fence_timeline_semaphore, NULL); free(object); } + else if (object->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + register_sem_poll(device, object); + if (res == VK_SUCCESS) + { + TRACE("-> %p (native %#llx, shared %#llx).\n", object, (long long)object->semaphore, (long long)object->fence_timeline_semaphore); + } return res; } @@ -3911,6 +4331,9 @@ void wine_vkDestroySemaphore(VkDevice device_handle, VkSemaphore semaphore_handl if (!semaphore) return; + if (semaphore->poll_entry.next) + unregister_sem_poll(device, semaphore); + if (semaphore->handle != INVALID_HANDLE_VALUE) NtClose(semaphore->handle); @@ -3942,6 +4365,9 @@ VkResult wine_vkImportSemaphoreWin32HandleKHR(VkDevice device_handle, TRACE("(%p, %p). semaphore = %p handle = %p\n", device, handle_info, semaphore, handle_info->handle); + if (semaphore->poll_entry.next) + unregister_sem_poll(device, semaphore); + if (handle_info->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT && !semaphore->fence_timeline_semaphore) { type_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO; @@ -4042,6 +4468,9 @@ VkResult wine_vkImportSemaphoreWin32HandleKHR(VkDevice device_handle, NtUnmapViewOfSection(GetCurrentProcess(), semaphore->d3d12_fence_shm); *semaphore = output_semaphore; + assert(!semaphore->poll_entry.next); + if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + register_sem_poll(device, semaphore); } else { @@ -4057,20 +4486,10 @@ VkResult wine_vkImportSemaphoreWin32HandleKHR(VkDevice device_handle, return res; } -static VkResult vk_get_semaphore_counter_value(VkDevice device_handle, VkSemaphore semaphore_handle, uint64_t *value, bool khr) -{ - struct wine_semaphore *semaphore = wine_semaphore_from_handle(semaphore_handle); - struct wine_device *device = wine_device_from_handle(device_handle); - - if (khr) - return device->funcs.p_vkGetSemaphoreCounterValueKHR(device->device, wine_semaphore_host_handle(semaphore), value); - else - return device->funcs.p_vkGetSemaphoreCounterValue(device->device, wine_semaphore_host_handle(semaphore), value); -} - static VkResult wine_vk_get_semaphore_counter_value(VkDevice device_handle, VkSemaphore semaphore_handle, uint64_t *value, bool khr) { struct wine_semaphore *semaphore = wine_semaphore_from_handle(semaphore_handle); + struct wine_device *device = wine_device_from_handle(device_handle); if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) { @@ -4080,7 +4499,10 @@ static VkResult wine_vk_get_semaphore_counter_value(VkDevice device_handle, VkSe return VK_SUCCESS; } - return vk_get_semaphore_counter_value(device_handle, semaphore_handle, value, khr); + if (khr) + return device->funcs.p_vkGetSemaphoreCounterValueKHR(device->device, wine_semaphore_host_handle(semaphore), value); + else + return device->funcs.p_vkGetSemaphoreCounterValue(device->device, wine_semaphore_host_handle(semaphore), value); } VkResult wine_vkGetSemaphoreCounterValue(VkDevice device_handle, VkSemaphore semaphore_handle, uint64_t *value) @@ -4093,116 +4515,194 @@ VkResult wine_vkGetSemaphoreCounterValueKHR(VkDevice device_handle, VkSemaphore return wine_vk_get_semaphore_counter_value(device_handle, semaphore_handle, value, true); } -static VkResult vk_signal_semaphore(VkDevice device_handle, const VkSemaphoreSignalInfo *signal_info, bool khr) +static NTSTATUS wine_vk_signal_semaphore(VkDevice device_handle, const VkSemaphoreSignalInfo *signal_info, bool khr) { struct wine_semaphore *semaphore = wine_semaphore_from_handle(signal_info->semaphore); struct wine_device *device = wine_device_from_handle(device_handle); VkSemaphoreSignalInfo dup_signal_info = *signal_info; - dup_signal_info.semaphore = wine_semaphore_host_handle(semaphore); + TRACE("(%p, %p)\n", device, signal_info); + + if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + { + add_sem_signal_op(device, semaphore, signal_info->value, &dup_signal_info.semaphore, &dup_signal_info.value, TRUE); + return VK_SUCCESS; + } + else + dup_signal_info.semaphore = wine_semaphore_host_handle(semaphore); + if (khr) return device->funcs.p_vkSignalSemaphoreKHR(device->device, &dup_signal_info); else return device->funcs.p_vkSignalSemaphore(device->device, &dup_signal_info); } -static NTSTATUS wine_vk_signal_semaphore(VkDevice device, const VkSemaphoreSignalInfo *signal_info, bool khr) +VkResult wine_vkSignalSemaphore(VkDevice device_handle, const VkSemaphoreSignalInfo *signal_info) { - struct wine_semaphore *semaphore = wine_semaphore_from_handle(signal_info->semaphore); - - TRACE("(%p, %p)\n", device, signal_info); - - if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - { - FIXME("Signalling D3D12-Fence compatible timeline semaphore not supported.\n"); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } - - return vk_signal_semaphore(device, signal_info, khr); + return wine_vk_signal_semaphore(device_handle, signal_info, false); } -VkResult wine_vkSignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo *signal_info) +VkResult wine_vkSignalSemaphoreKHR(VkDevice device_handle, const VkSemaphoreSignalInfo *signal_info) { - return wine_vk_signal_semaphore(device, signal_info, false); + return wine_vk_signal_semaphore(device_handle, signal_info, true); } -VkResult wine_vkSignalSemaphoreKHR(VkDevice device, const VkSemaphoreSignalInfo *signal_info) +static void unwrap_semaphore(struct wine_device *device, VkSemaphore *sem_handle, uint64_t *value, BOOL signal) { - return wine_vk_signal_semaphore(device, signal_info, true); + struct wine_semaphore *sem = wine_semaphore_from_handle(*sem_handle); + + if (!sem) + return; + + if (sem->handle_type != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + { + *sem_handle = wine_semaphore_host_handle(sem); + return; + } + if (signal) + add_sem_signal_op(device, sem, *value, sem_handle, value, FALSE); + else + add_sem_wait_op(device, sem, *value, sem_handle, value); } -static VkSemaphore *unwrap_semaphore_array(const VkSemaphore *in, uint32_t count, struct conversion_context *ctx) +static VkResult unwrap_semaphore_array(const VkSemaphore **sems, const uint64_t **values_out, + uint32_t count, struct conversion_context *ctx, BOOL signal, struct wine_device *device) { + const uint64_t *values = NULL; + const VkSemaphore *in; VkSemaphore *out; unsigned int i; - if (!in || !count) return NULL; + in = *sems; + *sems = NULL; + + if (!in || !count) + return VK_SUCCESS; out = conversion_context_alloc(ctx, count * sizeof(*out)); for (i = 0; i < count; ++i) - out[i] = in[i] ? wine_semaphore_host_handle(wine_semaphore_from_handle(in[i])) : VK_NULL_HANDLE; - - return out; + { + struct wine_semaphore *sem; + if (!in[i]) + { + out[i] = VK_NULL_HANDLE; + continue; + } + sem = wine_semaphore_from_handle(in[i]); + if (sem->handle_type != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) + { + out[i] = wine_semaphore_host_handle(sem); + continue; + } + if (!values_out) + { + ERR("D3D12 fence without values specified.\n"); + return VK_ERROR_UNKNOWN; + } + if (!values) + { + values = *values_out; + *values_out = conversion_context_alloc(ctx, count * sizeof(*values_out)); + memcpy((void *)*values_out, values, count * sizeof(*values)); + } + if (signal) + add_sem_signal_op(device, sem, values[i], &out[i], (uint64_t *)&(*values_out)[i], FALSE); + else + add_sem_wait_op(device, sem, values[i], &out[i], (uint64_t *)&(*values_out)[i]); + } + *sems = out; + return VK_SUCCESS; } -static VkResult vk_wait_semaphores(struct wine_device *device, const VkSemaphoreWaitInfo *wait_info, uint64_t timeout, bool khr) +static VkResult wine_vk_wait_semaphores(VkDevice device_handle, const VkSemaphoreWaitInfo *wait_info, uint64_t timeout, bool khr) { + struct wine_device *device = wine_device_from_handle(device_handle); VkSemaphoreWaitInfo wait_info_dup = *wait_info; struct conversion_context ctx; VkResult ret; init_conversion_context(&ctx); - wait_info_dup.pSemaphores = unwrap_semaphore_array(wait_info->pSemaphores, wait_info->semaphoreCount, &ctx); + if ((ret = unwrap_semaphore_array(&wait_info_dup.pSemaphores, &wait_info_dup.pValues, + wait_info->semaphoreCount, &ctx, FALSE, device))) + goto done; + if (khr) ret = device->funcs.p_vkWaitSemaphoresKHR(device->device, &wait_info_dup, timeout); else ret = device->funcs.p_vkWaitSemaphores(device->device, &wait_info_dup, timeout); +done: free_conversion_context(&ctx); return ret; } -static VkResult wine_vk_wait_semaphores(VkDevice device_handle, const VkSemaphoreWaitInfo *wait_info, uint64_t timeout, bool khr) -{ - unsigned int i; - - TRACE("(%p, %p, 0x%s)\n", device_handle, wait_info, wine_dbgstr_longlong(timeout)); - - for (i = 0; i < wait_info->semaphoreCount; i++) - { - struct wine_semaphore *semaphore = wine_semaphore_from_handle(wait_info->pSemaphores[i]); - - if (semaphore->handle_type == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - { - FIXME("Waiting on D3D12-Fence compatible timeline semaphores not supported."); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } - } - return vk_wait_semaphores(wine_device_from_handle(device_handle), wait_info, timeout, khr); -} - VkResult wine_vkWaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo *wait_info, uint64_t timeout) { + TRACE("%p %p %s.\n", device, wait_info, wine_dbgstr_longlong(timeout)); + return wine_vk_wait_semaphores(device, wait_info, timeout, false); } VkResult wine_vkWaitSemaphoresKHR(VkDevice device, const VkSemaphoreWaitInfo *wait_info, uint64_t timeout) { + TRACE("%p %p %s.\n", device, wait_info, wine_dbgstr_longlong(timeout)); + return wine_vk_wait_semaphores(device, wait_info, timeout, true); } -VkResult vk_queue_submit_unwrap(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo *submits_orig, VkFence fence) +struct struct_chain_def { + VkStructureType sType; + unsigned int size; +}; + +VkResult wine_vkQueueSubmit(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo *submits_orig, VkFence fence, + void *submits_win_ptr) +{ + struct wine_queue *queue = wine_queue_from_handle(queue_handle); + struct wine_device *device = queue->device; + VkTimelineSemaphoreSubmitInfo *timeline_submit_info; + const VkSubmitInfo *submits_win = submits_win_ptr; + VkD3D12FenceSubmitInfoKHR *d3d12_submit_info; + const uint64_t **values; struct conversion_context ctx; VkSubmitInfo *submits; unsigned int i, j; VkResult ret; + TRACE("(%p %u %p 0x%s)\n", queue_handle, submit_count, submits_orig, wine_dbgstr_longlong(fence)); + init_conversion_context(&ctx); MEMDUP(&ctx, submits, submits_orig, submit_count); for (i = 0; i < submit_count; ++i) { - submits[i].pWaitSemaphores = unwrap_semaphore_array(submits[i].pWaitSemaphores, submits[i].waitSemaphoreCount, &ctx); - submits[i].pSignalSemaphores = unwrap_semaphore_array(submits[i].pSignalSemaphores, submits[i].signalSemaphoreCount, &ctx); + timeline_submit_info = wine_vk_find_struct(&submits[i], TIMELINE_SEMAPHORE_SUBMIT_INFO); + d3d12_submit_info = wine_vk_find_struct(&submits_win[i], D3D12_FENCE_SUBMIT_INFO_KHR); + if (d3d12_submit_info && timeline_submit_info) + WARN("Both TIMELINE_SEMAPHORE_SUBMIT_INFO and D3D12_FENCE_SUBMIT_INFO_KHR specified.\n"); + if (d3d12_submit_info && !timeline_submit_info) + { + timeline_submit_info = conversion_context_alloc(&ctx, sizeof(*timeline_submit_info)); + timeline_submit_info->sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; + timeline_submit_info->pNext = submits[i].pNext; + timeline_submit_info->waitSemaphoreValueCount = d3d12_submit_info->waitSemaphoreValuesCount; + MEMDUP(&ctx, timeline_submit_info->pWaitSemaphoreValues, d3d12_submit_info->pWaitSemaphoreValues, d3d12_submit_info->waitSemaphoreValuesCount); + timeline_submit_info->signalSemaphoreValueCount = d3d12_submit_info->signalSemaphoreValuesCount; + MEMDUP(&ctx, timeline_submit_info->pSignalSemaphoreValues, d3d12_submit_info->pSignalSemaphoreValues, d3d12_submit_info->signalSemaphoreValuesCount); + submits[i].pNext = timeline_submit_info; + } + + if (timeline_submit_info) + values = &timeline_submit_info->pWaitSemaphoreValues; + else + values = NULL; + unwrap_semaphore_array(&submits[i].pWaitSemaphores, values, submits[i].waitSemaphoreCount, &ctx, FALSE, device); + + if (timeline_submit_info) + values = &timeline_submit_info->pSignalSemaphoreValues; + else + values = NULL; + unwrap_semaphore_array(&submits[i].pSignalSemaphores, values, submits[i].signalSemaphoreCount, &ctx, TRUE, device); + if (submits[i].pCommandBuffers && submits[i].commandBufferCount) { VkCommandBuffer *out; @@ -4218,38 +4718,6 @@ VkResult vk_queue_submit_unwrap(struct wine_queue *queue, uint32_t submit_count, return ret; } -VkResult wine_vkQueueSubmit(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo *submits, VkFence fence, void *submits_win_ptr) -{ - struct wine_queue *queue = wine_queue_from_handle(queue_handle); - unsigned int i, k; - - TRACE("(%p %u %p 0x%s)\n", queue_handle, submit_count, submits, wine_dbgstr_longlong(fence)); - - for (i = 0; i < submit_count; i++) - { - for (k = 0; k < submits[i].waitSemaphoreCount; k++) - { - if (wine_semaphore_from_handle(submits[i].pWaitSemaphores[k])->handle_type == - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - { - FIXME("Queue submissions with waits on D3D12-Fence compatible timeline semaphores not supported.\n"); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } - } - - for (k = 0; k < submits[i].signalSemaphoreCount; k++) - { - if (wine_semaphore_from_handle(submits[i].pSignalSemaphores[k])->handle_type == - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - { - FIXME("Queue submissions with signalling D3D12-Fence compatible timeline semaphores not supported.\n"); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } - } - } - return vk_queue_submit_unwrap(queue, submit_count, submits, fence); -} - static void duplicate_array_for_unwrapping(struct conversion_context *ctx, void **ptr, unsigned int size) { void *out; @@ -4262,14 +4730,16 @@ static void duplicate_array_for_unwrapping(struct conversion_context *ctx, void *ptr = out; } -VkResult vk_queue_submit_2_unwrap(struct wine_queue *queue, uint32_t submit_count, const VkSubmitInfo2 *submits_orig, - VkFence fence, bool khr) +static VkResult vk_queue_submit_2(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo2 *submits_orig, VkFence fence, bool khr) { + struct wine_queue *queue = wine_queue_from_handle(queue_handle); struct conversion_context ctx; VkSubmitInfo2 *submits; unsigned int i, j; VkResult ret; + TRACE("(%p, %u, %p, %s)\n", queue_handle, submit_count, submits_orig, wine_dbgstr_longlong(fence)); + init_conversion_context(&ctx); MEMDUP(&ctx, submits, submits_orig, submit_count); for (i = 0; i < submit_count; ++i) @@ -4277,16 +4747,14 @@ VkResult vk_queue_submit_2_unwrap(struct wine_queue *queue, uint32_t submit_coun duplicate_array_for_unwrapping(&ctx, (void **)&submits[i].pWaitSemaphoreInfos, submits[i].waitSemaphoreInfoCount * sizeof(*submits[i].pWaitSemaphoreInfos)); for (j = 0; j < submits[i].waitSemaphoreInfoCount; ++j) - if (submits[i].pWaitSemaphoreInfos[j].semaphore) - ((VkSemaphoreSubmitInfo *)submits[i].pWaitSemaphoreInfos)[j].semaphore - = wine_semaphore_host_handle(wine_semaphore_from_handle(submits[i].pWaitSemaphoreInfos[j].semaphore)); + unwrap_semaphore(queue->device, &((VkSemaphoreSubmitInfo *)submits[i].pWaitSemaphoreInfos)[j].semaphore, + &((VkSemaphoreSubmitInfo *)submits[i].pWaitSemaphoreInfos)[j].value, FALSE); duplicate_array_for_unwrapping(&ctx, (void **)&submits[i].pSignalSemaphoreInfos, submits[i].signalSemaphoreInfoCount * sizeof(*submits[i].pSignalSemaphoreInfos)); for (j = 0; j < submits[i].signalSemaphoreInfoCount; ++j) - if (submits[i].pSignalSemaphoreInfos[j].semaphore) - ((VkSemaphoreSubmitInfo *)submits[i].pSignalSemaphoreInfos)[j].semaphore - = wine_semaphore_host_handle(wine_semaphore_from_handle(submits[i].pSignalSemaphoreInfos[j].semaphore)); + unwrap_semaphore(queue->device, &((VkSemaphoreSubmitInfo *)submits[i].pSignalSemaphoreInfos)[j].semaphore, + &((VkSemaphoreSubmitInfo *)submits[i].pSignalSemaphoreInfos)[j].value, TRUE); if (submits[i].pCommandBufferInfos && submits[i].commandBufferInfoCount) { @@ -4297,6 +4765,7 @@ VkResult vk_queue_submit_2_unwrap(struct wine_queue *queue, uint32_t submit_coun = wine_cmd_buffer_from_handle(submits[i].pCommandBufferInfos[j].commandBuffer)->command_buffer; } } + if (khr) ret = queue->device->funcs.p_vkQueueSubmit2KHR(queue->queue, submit_count, submits, fence); else @@ -4305,39 +4774,6 @@ VkResult vk_queue_submit_2_unwrap(struct wine_queue *queue, uint32_t submit_coun return ret; } -static VkResult vk_queue_submit_2(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence, bool khr) -{ - struct wine_queue *queue = wine_queue_from_handle(queue_handle); - unsigned int i, k; - - TRACE("(%p, %u, %p, %s)\n", queue_handle, submit_count, submits, wine_dbgstr_longlong(fence)); - - for (i = 0; i < submit_count; i++) - { - for (k = 0; k < submits[i].waitSemaphoreInfoCount; k++) - { - if (wine_semaphore_from_handle(submits[i].pWaitSemaphoreInfos[k].semaphore)->handle_type == - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - { - FIXME("Queue submissions with waits on D3D12-Fence compatible timeline semaphores not supported.\n"); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } - } - - for (k = 0; k < submits[i].signalSemaphoreInfoCount; k++) - { - if (wine_semaphore_from_handle(submits[i].pSignalSemaphoreInfos[k].semaphore)->handle_type == - VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT) - { - FIXME("Queue submissions signalling D3D12-Fence compatible timeline semaphores not supported.\n"); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } - } - } - - return vk_queue_submit_2_unwrap(queue, submit_count, submits, fence, khr); -} - VkResult wine_vkQueueSubmit2(VkQueue queue, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence) { return vk_queue_submit_2(queue, submit_count, submits, fence, false); @@ -4350,6 +4786,7 @@ VkResult wine_vkQueueSubmit2KHR(VkQueue queue, uint32_t submit_count, const VkSu VkResult wine_vkQueuePresentKHR(VkQueue queue_handle, const VkPresentInfoKHR *present_info) { + struct wine_queue *queue = wine_queue_from_handle(queue_handle); VkPresentInfoKHR host_present_info = *present_info; struct wine_semaphore *semaphore; struct conversion_context ctx; @@ -4370,7 +4807,8 @@ VkResult wine_vkQueuePresentKHR(VkQueue queue_handle, const VkPresentInfoKHR *pr } init_conversion_context(&ctx); - host_present_info.pWaitSemaphores = unwrap_semaphore_array(present_info->pWaitSemaphores, present_info->waitSemaphoreCount, &ctx); + unwrap_semaphore_array(&host_present_info.pWaitSemaphores, NULL, present_info->waitSemaphoreCount, &ctx, + FALSE, queue->device); ret = fshack_vk_queue_present(queue_handle, &host_present_info); free_conversion_context(&ctx); return ret; @@ -4418,8 +4856,8 @@ VkResult wine_vkQueueBindSparse(VkQueue queue_handle, uint32_t bind_info_count, for (i = 0; i < bind_info_count; ++i) { batch = (VkBindSparseInfo *)&bind_info[i]; - batch->pWaitSemaphores = unwrap_semaphore_array(batch->pWaitSemaphores, batch->waitSemaphoreCount, &ctx); - batch->pSignalSemaphores = unwrap_semaphore_array(batch->pSignalSemaphores, batch->signalSemaphoreCount, &ctx); + unwrap_semaphore_array(&batch->pWaitSemaphores, NULL, batch->waitSemaphoreCount, &ctx, FALSE, queue->device); + unwrap_semaphore_array(&batch->pSignalSemaphores, NULL, batch->signalSemaphoreCount, &ctx, TRUE, queue->device); duplicate_array_for_unwrapping(&ctx, (void **)&batch->pBufferBinds, batch->bufferBindCount * sizeof(*batch->pBufferBinds)); for (j = 0; j < batch->bufferBindCount; ++j) diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index f89787eb67c..5855201ac36 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -24,6 +24,7 @@ #define VK_NO_PROTOTYPES #include +#include #include "vulkan_loader.h" #include "vulkan_thunks.h" @@ -53,6 +54,25 @@ static inline struct wine_cmd_buffer *wine_cmd_buffer_from_handle(VkCommandBuffe return (struct wine_cmd_buffer *)(uintptr_t)handle->base.unix_handle; } +struct wine_semaphore; + +struct local_timeline_semaphore +{ + VkSemaphore sem; + uint64_t value; +}; + +struct pending_d3d12_fence_op +{ + /* Vulkan native local semaphore. */ + struct local_timeline_semaphore local_sem; + + /* Operation values. */ + struct wine_vk_mapping mapping; + struct list entry; + uint64_t virtual_value; +}; + struct wine_device { struct vulkan_device_funcs funcs; @@ -67,6 +87,16 @@ struct wine_device VkQueueFamilyProperties *queue_props; struct wine_vk_mapping mapping; + + pthread_t signaller_thread; + pthread_mutex_t signaller_mutex; + bool stop; + struct list free_fence_ops_list; + struct list sem_poll_list; + struct local_timeline_semaphore sem_poll_update; + pthread_cond_t sem_poll_updated_cond; + uint64_t sem_poll_update_value; /* set to sem_poll_update.value by signaller thread once update is processed. */ + unsigned int allocated_fence_ops_count; }; static inline struct wine_device *wine_device_from_handle(VkDevice handle) @@ -326,7 +356,6 @@ static inline void free_conversion_context(struct conversion_context *pool) struct wine_semaphore { VkSemaphore semaphore; - VkSemaphore fence_timeline_semaphore; VkExternalSemaphoreHandleTypeFlagBits export_types; @@ -334,12 +363,18 @@ struct wine_semaphore /* mutable members */ VkExternalSemaphoreHandleTypeFlagBits handle_type; + struct list poll_entry; + struct list pending_waits; + struct list pending_signals; HANDLE handle; struct { + /* Shared mem access mutex. The non-shared parts access is guarded with device global signaller_mutex. */ pthread_mutex_t mutex; - uint64_t virtual_value; + uint64_t virtual_value, physical_value; } *d3d12_fence_shm; + /* The Vulkan shared semaphore is only waited or signaled in signaller_worker(). */ + VkSemaphore fence_timeline_semaphore; }; static inline struct wine_semaphore *wine_semaphore_from_handle(VkSemaphore handle) From d6f03f31717abcdfff23bfb2dd4a00bf1a960941 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 7 Aug 2023 17:49:30 -0600 Subject: [PATCH 1523/2777] winevulkan: Support resetting shared fence value. CW-Bug-Id: #22526 --- dlls/winevulkan/vulkan.c | 54 ++++++++++++++++++++++++++------ dlls/winevulkan/vulkan_private.h | 10 ++++++ 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index ff5cca60b28..61d9afc45b2 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -137,8 +137,8 @@ static void signal_timeline_sem(struct wine_device *device, VkSemaphore sem, uin info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO; info.semaphore = sem; - ++*value; - info.value = *value; + info.value = *value + 1; + __atomic_store_n(value, info.value, __ATOMIC_RELEASE); if (device->phys_dev->api_version < VK_API_VERSION_1_2 || device->phys_dev->instance->api_version < VK_API_VERSION_1_2) res = device->funcs.p_vkSignalSemaphoreKHR(device->device, &info); else @@ -3855,14 +3855,13 @@ static int semaphore_process(struct wine_device *device, struct wine_semaphore * int virtual_value_updated = 0; uint64_t value, virtual_value; VkResult res; + uint32_t i; /* Check local pending signal ops completion, update shared semaphore. */ d3d12_semaphore_lock( sem ); + virtual_value = sem->d3d12_fence_shm->virtual_value; LIST_FOR_EACH_ENTRY_SAFE(op, op2, &sem->pending_signals, struct pending_d3d12_fence_op, entry) { - if (op->virtual_value <= sem->d3d12_fence_shm->virtual_value) - goto signal_op_complete; - res = get_semaphore_value(device, op->local_sem.sem, &value); if (res != VK_SUCCESS) { @@ -3879,28 +3878,64 @@ static int semaphore_process(struct wine_device *device, struct wine_semaphore * continue; } + virtual_value = max( sem->d3d12_fence_shm->virtual_value, op->virtual_value ); sem->d3d12_fence_shm->virtual_value = op->virtual_value; virtual_value_updated = 1; signal_op_complete: - ++op->local_sem.value; + op->local_sem.value = value; release_fence_op(device, op); } + if (sem->d3d12_fence_shm->virtual_value < virtual_value) + { + uint32_t idx = sem->d3d12_fence_shm->reset_backlog_count; + + if (debug_level >= 3) + fprintf(stderr, "warn:winevulkan:semaphore_process resetting semaphore %p virtual value.\n", sem); + if (idx == ARRAY_SIZE(sem->d3d12_fence_shm->reset_backlog)) + { + sem->d3d12_fence_shm->last_dropped_reset_physical = sem->d3d12_fence_shm->reset_backlog[0].physical_at_reset; + --idx; + memmove(&sem->d3d12_fence_shm->reset_backlog[0], &sem->d3d12_fence_shm->reset_backlog[1], + sizeof(*sem->d3d12_fence_shm->reset_backlog) * sem->d3d12_fence_shm->reset_backlog_count); + } + else + { + ++sem->d3d12_fence_shm->reset_backlog_count; + } + sem->d3d12_fence_shm->last_reset_physical = sem->d3d12_fence_shm->physical_value + 1; + sem->d3d12_fence_shm->reset_backlog[idx].physical_at_reset = sem->d3d12_fence_shm->last_reset_physical; + sem->d3d12_fence_shm->reset_backlog[idx].virtual_before_reset = virtual_value; + } if (virtual_value_updated) signal_timeline_sem(device, sem->fence_timeline_semaphore, &sem->d3d12_fence_shm->physical_value); global_sem_wait_value = sem->d3d12_fence_shm->physical_value + 1; - virtual_value = sem->d3d12_fence_shm->virtual_value; - d3d12_semaphore_unlock(sem); /* Complete satisfied local waits. */ LIST_FOR_EACH_ENTRY_SAFE(op, op2, &sem->pending_waits, struct pending_d3d12_fence_op, entry) { if (op->virtual_value > virtual_value) - continue; + { + if (op->shared_physical_value > sem->d3d12_fence_shm->last_reset_physical) + continue; + for (i = 0; i < sem->d3d12_fence_shm->reset_backlog_count; ++i) + { + if (sem->d3d12_fence_shm->reset_backlog[i].physical_at_reset >= op->shared_physical_value + && sem->d3d12_fence_shm->reset_backlog[i].virtual_before_reset >= op->virtual_value) + break; + } + if (i == sem->d3d12_fence_shm->reset_backlog_count) + { + if (sem->d3d12_fence_shm->last_dropped_reset_physical < op->shared_physical_value) + continue; + fprintf(stderr, "err:winevulkan:semaphore_process wait needs reset backlog beyond cut off.\n"); + } + } signal_timeline_sem(device, op->local_sem.sem, &op->local_sem.value); release_fence_op(device, op); } + d3d12_semaphore_unlock(sem); /* Only poll shared semaphore if there are waits pending. */ if (list_empty(&sem->pending_waits)) @@ -4079,6 +4114,7 @@ static void add_sem_wait_op(struct wine_device *device, struct wine_semaphore *s if ((op = get_free_fence_op(device))) { op->virtual_value = virtual_value; + op->shared_physical_value = __atomic_load_n(&semaphore->d3d12_fence_shm->physical_value, __ATOMIC_ACQUIRE) + 1; *phys_semaphore = op->local_sem.sem; *phys_wait_value = op->local_sem.value + 1; list_add_tail(&semaphore->pending_waits, &op->entry); diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 5855201ac36..beae80cd929 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -71,6 +71,7 @@ struct pending_d3d12_fence_op struct wine_vk_mapping mapping; struct list entry; uint64_t virtual_value; + uint64_t shared_physical_value; }; struct wine_device @@ -372,6 +373,15 @@ struct wine_semaphore /* Shared mem access mutex. The non-shared parts access is guarded with device global signaller_mutex. */ pthread_mutex_t mutex; uint64_t virtual_value, physical_value; + uint64_t last_reset_physical; + uint64_t last_dropped_reset_physical; + struct + { + uint64_t physical_at_reset; + uint64_t virtual_before_reset; + } + reset_backlog[16]; + uint32_t reset_backlog_count; } *d3d12_fence_shm; /* The Vulkan shared semaphore is only waited or signaled in signaller_worker(). */ VkSemaphore fence_timeline_semaphore; From f680b5921f352ee5ad28361546f8b9e958300380 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 4 Aug 2023 13:14:43 -0600 Subject: [PATCH 1524/2777] winevulkan: Also remap Win32 functions in vk_is_available_instance_function(). CW-Bug-Id: #22526 --- dlls/winevulkan/vulkan.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 61d9afc45b2..dc68f76b66c 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -3606,12 +3606,23 @@ VkResult fshack_vk_queue_present(VkQueue queue_handle, const VkPresentInfoKHR *p return res; } +static void substitute_function_name(const char **name) +{ + if (!strcmp(*name, "vkGetMemoryWin32HandleKHR") || !strcmp(*name, "vkGetMemoryWin32HandlePropertiesKHR")) + *name = "vkGetMemoryFdKHR"; + else if (!strcmp(*name, "vkGetSemaphoreWin32HandleKHR")) + *name = "vkGetSemaphoreFdKHR"; + else if (!strcmp(*name, "vkImportSemaphoreWin32HandleKHR")) + *name = "vkImportSemaphoreFdKHR"; +} + #ifdef _WIN64 NTSTATUS vk_is_available_instance_function(void *arg) { struct is_available_instance_function_params *params = arg; struct wine_instance *instance = wine_instance_from_handle(params->instance); + substitute_function_name(¶ms->name); return !!vk_funcs->p_vkGetInstanceProcAddr(instance->instance, params->name); } @@ -3619,12 +3630,7 @@ NTSTATUS vk_is_available_device_function(void *arg) { struct is_available_device_function_params *params = arg; struct wine_device *device = wine_device_from_handle(params->device); - if (!strcmp(params->name, "vkGetMemoryWin32HandleKHR") || !strcmp(params->name, "vkGetMemoryWin32HandlePropertiesKHR")) - params->name = "vkGetMemoryFdKHR"; - else if (!strcmp(params->name, "vkGetSemaphoreWin32HandleKHR")) - params->name = "vkGetSemaphoreFdKHR"; - else if (!strcmp(params->name, "vkImportSemaphoreWin32HandleKHR")) - params->name = "vkImportSemaphoreFdKHR"; + substitute_function_name(¶ms->name); return !!vk_funcs->p_vkGetDeviceProcAddr(device->device, params->name); } @@ -3638,7 +3644,9 @@ NTSTATUS vk_is_available_instance_function32(void *arg) UINT32 name; } *params = arg; struct wine_instance *instance = wine_instance_from_handle(UlongToPtr(params->instance)); - return !!vk_funcs->p_vkGetInstanceProcAddr(instance->instance, UlongToPtr(params->name)); + const char *name = UlongToPtr(params->name); + substitute_function_name(&name); + return !!vk_funcs->p_vkGetInstanceProcAddr(instance->instance, name); } NTSTATUS vk_is_available_device_function32(void *arg) @@ -3649,14 +3657,9 @@ NTSTATUS vk_is_available_device_function32(void *arg) UINT32 name; } *params = arg; struct wine_device *device = wine_device_from_handle(UlongToPtr(params->device)); - char *name = UlongToPtr(params->name); - if (!strcmp(name, "vkGetMemoryWin32HandleKHR") || !strcmp(name, "vkGetMemoryWin32HandlePropertiesKHR")) - return !!vk_funcs->p_vkGetDeviceProcAddr(device->device, "vkGetMemoryFdKHR"); - if (!strcmp(name, "vkGetSemaphoreWin32HandleKHR")) - return !!vk_funcs->p_vkGetDeviceProcAddr(device->device, "vkGetSemaphoreFdKHR"); - if (!strcmp(name, "vkImportSemaphoreWin32HandleKHR")) - return !!vk_funcs->p_vkGetDeviceProcAddr(device->device, "vkImportSemaphoreFdKHR"); - return !!vk_funcs->p_vkGetDeviceProcAddr(device->device, UlongToPtr(params->name)); + const char *name = UlongToPtr(params->name); + substitute_function_name(&name); + return !!vk_funcs->p_vkGetDeviceProcAddr(device->device, name); } VkDevice WINAPI __wine_get_native_VkDevice(VkDevice handle) From 950b079dc433900cfe63774a10105a6d27771764 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 4 Aug 2023 19:38:36 -0600 Subject: [PATCH 1525/2777] fixup! winevulkan: Implement support for KMT handles and named objects. CW-Bug-Id: #22372 --- dlls/sharedgpures.sys/shared_resource.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dlls/sharedgpures.sys/shared_resource.c b/dlls/sharedgpures.sys/shared_resource.c index d8eaea26348..c6ab013ea0d 100644 --- a/dlls/sharedgpures.sys/shared_resource.c +++ b/dlls/sharedgpures.sys/shared_resource.c @@ -168,13 +168,12 @@ static NTSTATUS shared_resource_open(struct shared_resource **res, void *buff, S /* name lookup */ for (i = 0; i < resource_pool_size; i++) { - if (!wcscmp(resource_pool[i].name, &input->name[0])) + if (resource_pool[i].name && !wcscmp(resource_pool[i].name, input->name)) { *res = &resource_pool[i]; break; } } - if (i == resource_pool_size) return STATUS_OBJECT_NAME_NOT_FOUND; } From 59f6e6677dd54bc5779f48d330ae78d7ca0c59f5 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 4 Aug 2023 14:30:26 -0600 Subject: [PATCH 1526/2777] winevulkan: Expose VK_KHR_win32_keyed_mutex extension. CW-Bug-Id: #22372 --- dlls/winevulkan/make_vulkan | 5 ++--- dlls/winevulkan/vulkan.c | 44 +++++++++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 1332875e3ef..98b861b8eb3 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -102,7 +102,6 @@ UNSUPPORTED_EXTENSIONS = [ # Relates to external_semaphore and needs type conversions in bitflags. "VK_KHR_shared_presentable_image", # Needs WSI work. "VK_KHR_video_queue", # TODO Video extensions use separate headers + xml - "VK_KHR_win32_keyed_mutex", "VK_NV_external_memory_rdma", # Needs shared resources work. # Extensions for other platforms @@ -311,8 +310,8 @@ STRUCT_CHAIN_CONVERSIONS = { "VkPhysicalDeviceImageFormatInfo2": [], "VkPhysicalDeviceExternalSemaphoreInfo": [], "VkSemaphoreCreateInfo": ["VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR"], - "VkSubmitInfo": ["VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR"], - "VkSubmitInfo2": [], + "VkSubmitInfo": ["VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR", "VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR"], + "VkSubmitInfo2": ["VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR"], "VkBindSparseInfo" : [], } diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index dc68f76b66c..f2498851e04 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -281,7 +281,7 @@ static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance uint32_t num_host_properties, num_properties = 0; VkExtensionProperties *host_properties = NULL; VkPhysicalDeviceProperties physdev_properties; - BOOL have_external_memory_host = FALSE; + BOOL have_external_memory_host = FALSE, have_external_memory_fd = FALSE, have_external_semaphore_fd = FALSE; VkResult res; unsigned int i, j; @@ -335,6 +335,7 @@ static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance snprintf(host_properties[i].extensionName, sizeof(host_properties[i].extensionName), VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME); host_properties[i].specVersion = VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION; + have_external_memory_fd = TRUE; } if (!strcmp(host_properties[i].extensionName, "VK_KHR_external_semaphore_fd")) { @@ -343,6 +344,7 @@ static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance snprintf(host_properties[i].extensionName, sizeof(host_properties[i].extensionName), VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME); host_properties[i].specVersion = VK_KHR_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION; + have_external_semaphore_fd = TRUE; } if (wine_vk_device_extension_supported(host_properties[i].extensionName)) @@ -358,7 +360,8 @@ static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance have_external_memory_host = TRUE; } - TRACE("Host supported extensions %u, Wine supported extensions %u\n", num_host_properties, num_properties); + if (have_external_memory_fd && have_external_semaphore_fd) + ++num_properties; /* VK_KHR_win32_keyed_mutex */ if (!(object->extensions = calloc(num_properties, sizeof(*object->extensions)))) { @@ -374,7 +377,15 @@ static struct wine_phys_dev *wine_vk_physical_device_alloc(struct wine_instance j++; } } + if (have_external_memory_fd && have_external_semaphore_fd) + { + strcpy(object->extensions[j].extensionName, VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME); + object->extensions[j].specVersion = VK_KHR_WIN32_KEYED_MUTEX_SPEC_VERSION; + TRACE("Enabling extension '%s' for physical device %p\n", object->extensions[j].extensionName, object); + ++j; + } object->extension_count = num_properties; + TRACE("Host supported extensions %u, Wine supported extensions %u\n", num_host_properties, num_properties); if (use_external_memory() && have_external_memory_host) { @@ -523,7 +534,7 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de struct conversion_context *ctx, const VkDeviceCreateInfo *src, VkDeviceCreateInfo *dst) { static const char *wine_xr_extension_name = "VK_WINE_openxr_device_extensions"; - unsigned int i, append_xr = 0, replace_win32 = 0, append_timeline = 1; + unsigned int i, append_xr = 0, have_ext_mem32 = 0, have_ext_sem32 = 0, have_keyed_mutex = 0, append_timeline = 1; VkBaseOutStructure *header; char **xr_extensions_list; @@ -543,8 +554,12 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de if (!strcmp(extension_name, wine_xr_extension_name)) append_xr = 1; - else if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_memory_win32") || !strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_semaphore_win32")) - replace_win32 = 1; + else if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_memory_win32")) + have_ext_mem32 = 1; + else if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_semaphore_win32")) + have_ext_sem32 = 1; + else if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_win32_keyed_mutex")) + have_keyed_mutex = 1; else if (!strcmp(extension_name, "VK_KHR_timeline_semaphore")) append_timeline = 0; } @@ -566,7 +581,7 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de if (append_xr) xr_extensions_list = parse_xr_extensions(&append_xr); - if (phys_dev->external_memory_align || append_xr || replace_win32 || append_timeline) + if (phys_dev->external_memory_align || append_xr || have_ext_mem32 || have_ext_sem32 || have_keyed_mutex || append_timeline) { const char **new_extensions; unsigned int o = 0, count; @@ -578,19 +593,30 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de count += append_xr - 1; if (append_timeline) ++count; + if (have_keyed_mutex) + count += !have_ext_mem32 + !have_ext_sem32; new_extensions = conversion_context_alloc(ctx, count * sizeof(*dst->ppEnabledExtensionNames)); for (i = 0; i < dst->enabledExtensionCount; ++i) { if (append_xr && !strcmp(src->ppEnabledExtensionNames[i], wine_xr_extension_name)) continue; - if (replace_win32 && !strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_memory_win32")) + if (have_ext_mem32 && !strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_memory_win32")) new_extensions[o++] = "VK_KHR_external_memory_fd"; - else if (replace_win32 && !strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_semaphore_win32")) + else if (have_ext_sem32 && !strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_external_semaphore_win32")) new_extensions[o++] = "VK_KHR_external_semaphore_fd"; + else if (have_keyed_mutex && !strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_win32_keyed_mutex")) + continue; else new_extensions[o++] = src->ppEnabledExtensionNames[i]; } + if (have_keyed_mutex) + { + if (!have_ext_mem32) + new_extensions[o++] = "VK_KHR_external_memory_fd"; + if (!have_ext_sem32) + new_extensions[o++] = "VK_KHR_external_semaphore_fd"; + } if (phys_dev->external_memory_align) { new_extensions[o++] = "VK_KHR_external_memory"; @@ -603,7 +629,7 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de } if (append_timeline) new_extensions[o++] = "VK_KHR_timeline_semaphore"; - dst->enabledExtensionCount = count; + dst->enabledExtensionCount = o; dst->ppEnabledExtensionNames = new_extensions; } From a13f16cdf4a2418780edb3fc9ad946a6d3bfc34b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 4 Aug 2023 17:52:14 -0600 Subject: [PATCH 1527/2777] winevulkan: Implement vkGetMemoryWin32HandlePropertiesKHR(). CW-Bug-Id: #22372 --- dlls/winevulkan/vulkan.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index f2498851e04..4872f971c1d 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -3762,13 +3762,25 @@ VkResult wine_vkGetMemoryWin32HandleKHR(VkDevice device, const VkMemoryGetWin32H } } -VkResult wine_vkGetMemoryWin32HandlePropertiesKHR(VkDevice device, VkExternalMemoryHandleTypeFlagBits type, HANDLE handle, VkMemoryWin32HandlePropertiesKHR *properties) +VkResult wine_vkGetMemoryWin32HandlePropertiesKHR(VkDevice device_handle, VkExternalMemoryHandleTypeFlagBits type, HANDLE handle, VkMemoryWin32HandlePropertiesKHR *properties) { + struct wine_device *device = wine_device_from_handle(device_handle); + unsigned int i; + TRACE("%p %u %p %p\n", device, type, handle, properties); - /* VUID-vkGetMemoryWin32HandlePropertiesKHR-handleType-00666 - handleType must not be one of the handle types defined as opaque */ - return VK_ERROR_INVALID_EXTERNAL_HANDLE; + if (!(type & wine_vk_handle_over_fd_types)) + { + FIXME("type %#x.\n", type); + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + } + + properties->memoryTypeBits = 0; + for (i = 0; i < device->phys_dev->memory_properties.memoryTypeCount; ++i) + if (device->phys_dev->memory_properties.memoryTypes[i].propertyFlags == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) + properties->memoryTypeBits |= 1u << i; + + return VK_SUCCESS; } #define IOCTL_SHARED_GPU_RESOURCE_SET_OBJECT CTL_CODE(FILE_DEVICE_VIDEO, 6, METHOD_BUFFERED, FILE_WRITE_ACCESS) From 1a5a2300d91e0805c68fd5c592a97225e279f257 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 4 Aug 2023 19:13:05 -0600 Subject: [PATCH 1528/2777] winevulkan: Use resource allocated size when importing shared textures. CW-Bug-Id: #22372 --- dlls/sharedgpures.sys/shared_resource.c | 28 +++++++++++++ dlls/winevulkan/vulkan.c | 54 +++++++++++++++++++++++-- 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/dlls/sharedgpures.sys/shared_resource.c b/dlls/sharedgpures.sys/shared_resource.c index c6ab013ea0d..ad836662af0 100644 --- a/dlls/sharedgpures.sys/shared_resource.c +++ b/dlls/sharedgpures.sys/shared_resource.c @@ -27,6 +27,7 @@ struct shared_resource SIZE_T metadata_size; void **object_pool; unsigned int object_pool_count; + UINT64 resource_size; }; static struct shared_resource *resource_pool; @@ -72,6 +73,7 @@ static void *reference_client_handle(obj_handle_t handle) struct shared_resource_create { + UINT64 resource_size; obj_handle_t unix_handle; WCHAR name[1]; }; @@ -125,6 +127,7 @@ static NTSTATUS shared_resource_create(struct shared_resource **res, void *buff, (*res)->ref_count = 1; (*res)->unix_resource = unix_resource; (*res)->name = name; + (*res)->resource_size = input->resource_size; iosb->Information = 0; return STATUS_SUCCESS; @@ -138,6 +141,11 @@ struct shared_resource_open WCHAR name[1]; }; +struct shared_resource_info +{ + UINT64 resource_size; +}; + static unsigned int kmt_to_index(obj_handle_t kmt) { if (!(kmt & 0x40000000) || (kmt - 2) % 4) @@ -340,6 +348,20 @@ static NTSTATUS shared_resource_get_object(struct shared_resource *res, void *bu return STATUS_SUCCESS; } +#define IOCTL_SHARED_GPU_RESOURCE_GET_INFO CTL_CODE(FILE_DEVICE_VIDEO, 7, METHOD_BUFFERED, FILE_READ_ACCESS) +static NTSTATUS shared_resource_get_info(struct shared_resource *res, void *buff, SIZE_T outsize, IO_STATUS_BLOCK *iosb) +{ + struct shared_resource_info *info = buff; + + if (sizeof(*info) > outsize) + return STATUS_BUFFER_TOO_SMALL; + + info->resource_size = res->resource_size; + iosb->Information = sizeof(*info); + return STATUS_SUCCESS; +} + + static NTSTATUS WINAPI dispatch_create(DEVICE_OBJECT *device, IRP *irp) { irp->IoStatus.u.Status = STATUS_SUCCESS; @@ -452,6 +474,12 @@ static NTSTATUS WINAPI dispatch_ioctl(DEVICE_OBJECT *device, IRP *irp) stack->Parameters.DeviceIoControl.OutputBufferLength, &irp->IoStatus); break; + case IOCTL_SHARED_GPU_RESOURCE_GET_INFO: + status = shared_resource_get_info( res, + irp->AssociatedIrp.SystemBuffer, + stack->Parameters.DeviceIoControl.OutputBufferLength, + &irp->IoStatus ); + break; default: FIXME( "ioctl %#lx not supported\n", stack->Parameters.DeviceIoControl.IoControlCode ); status = STATUS_NOT_SUPPORTED; diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 4872f971c1d..f6ef96b55d2 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -2564,11 +2564,12 @@ void wine_vkDestroySurfaceKHR(VkInstance handle, VkSurfaceKHR surface, struct shared_resource_create { + UINT64 resource_size; obj_handle_t unix_handle; WCHAR name[1]; }; -static HANDLE create_gpu_resource(int fd, LPCWSTR name) +static HANDLE create_gpu_resource(int fd, LPCWSTR name, UINT64 resource_size) { static const WCHAR shared_gpu_resourceW[] = {'\\','?','?','\\','S','h','a','r','e','d','G','p','u','R','e','s','o','u','r','c','e',0}; HANDLE unix_resource = INVALID_HANDLE_VALUE; @@ -2604,6 +2605,7 @@ static HANDLE create_gpu_resource(int fd, LPCWSTR name) in_size = sizeof(*inbuff) + (name ? lstrlenW(name) * sizeof(WCHAR) : 0); inbuff = calloc(1, in_size); inbuff->unix_handle = wine_server_obj_handle(unix_resource); + inbuff->resource_size = resource_size; if (name) lstrcpyW(&inbuff->name[0], name); @@ -2631,6 +2633,11 @@ struct shared_resource_open WCHAR name[1]; }; +struct shared_resource_info +{ + UINT64 resource_size; +}; + static HANDLE open_shared_resource(HANDLE kmt_handle, LPCWSTR name) { static const WCHAR shared_gpu_resourceW[] = {'\\','?','?','\\','S','h','a','r','e','d','G','p','u','R','e','s','o','u','r','c','e',0}; @@ -2678,6 +2685,21 @@ static HANDLE open_shared_resource(HANDLE kmt_handle, LPCWSTR name) return shared_resource; } +#define IOCTL_SHARED_GPU_RESOURCE_GET_INFO CTL_CODE(FILE_DEVICE_VIDEO, 7, METHOD_BUFFERED, FILE_READ_ACCESS) + +static BOOL shared_resource_get_info(HANDLE handle, struct shared_resource_info *info) +{ + IO_STATUS_BLOCK iosb; + unsigned int status; + + status = NtDeviceIoControlFile(handle, NULL, NULL, NULL, &iosb, IOCTL_SHARED_GPU_RESOURCE_GET_INFO, + NULL, 0, info, sizeof(*info)); + if (status) + ERR("Failed to get shared resource info, status %#x.\n", status); + + return !status; +} + #define IOCTL_SHARED_GPU_RESOURCE_GET_UNIX_RESOURCE CTL_CODE(FILE_DEVICE_VIDEO, 3, METHOD_BUFFERED, FILE_READ_ACCESS) static int get_shared_resource_fd(HANDLE shared_resource) @@ -2756,11 +2778,15 @@ VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *allo /* Vulkan consumes imported FDs, but not imported HANDLEs */ if (handle_import_info) { + struct shared_resource_info res_info; + fd_import_info.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; fd_import_info.pNext = info.pNext; fd_import_info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; info.pNext = &fd_import_info; + TRACE("import handle type %#x.\n", handle_import_info->handleType); + switch (handle_import_info->handleType) { case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT: @@ -2796,6 +2822,26 @@ VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *allo result = VK_ERROR_INVALID_EXTERNAL_HANDLE; goto done; } + + /* From VkMemoryAllocateInfo spec: "if the parameters define an import operation and the external handle type is + * VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT, + * or VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT, allocationSize is ignored.". Although test suggests + * that it is also true for opaque Win32 handles. */ + if (shared_resource_get_info(memory->handle, &res_info)) + { + if (res_info.resource_size) + { + TRACE("Shared resource size %llu.\n", (long long)res_info.resource_size); + if (info.allocationSize && info.allocationSize != res_info.resource_size) + FIXME("Shared resource allocationSize %llu, resource_size %llu.\n", + (long long)info.allocationSize, (long long)res_info.resource_size); + info.allocationSize = res_info.resource_size; + } + else + { + ERR("Zero shared resource size.\n"); + } + } } else if (device->phys_dev->external_memory_align && (mem_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && !find_next_struct(alloc_info->pNext, VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT)) @@ -2876,7 +2922,7 @@ VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *allo if (device->funcs.p_vkGetMemoryFdKHR(device->device, &get_fd_info, &fd) == VK_SUCCESS) { - memory->handle = create_gpu_resource(fd, handle_export_info ? handle_export_info->name : NULL); + memory->handle = create_gpu_resource(fd, handle_export_info ? handle_export_info->name : NULL, alloc_info->allocationSize); memory->access = handle_export_info ? handle_export_info->dwAccess : GENERIC_ALL; if (handle_export_info && handle_export_info->pAttributes) memory->inherit = handle_export_info->pAttributes->bInheritHandle; @@ -4261,7 +4307,7 @@ VkResult wine_vkCreateSemaphore(VkDevice device_handle, const VkSemaphoreCreateI if ((res = device->funcs.p_vkGetSemaphoreFdKHR(device->device, &fd_info, &fd)) == VK_SUCCESS) { - object->handle = create_gpu_resource(fd, export_handle_info ? export_handle_info->name : NULL); + object->handle = create_gpu_resource(fd, export_handle_info ? export_handle_info->name : NULL, 0); close(fd); } @@ -4300,7 +4346,7 @@ VkResult wine_vkCreateSemaphore(VkDevice device_handle, const VkSemaphoreCreateI if ((res = device->funcs.p_vkGetSemaphoreFdKHR(device->device, &fd_info, &fd)) == VK_SUCCESS) { - object->handle = create_gpu_resource(fd, export_handle_info ? export_handle_info->name : NULL); + object->handle = create_gpu_resource(fd, export_handle_info ? export_handle_info->name : NULL, 0); close(fd); } From 9eac724ae46eb8b417ef10f4e3daa7413a5d5058 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 10 Aug 2023 20:09:33 -0600 Subject: [PATCH 1529/2777] winevulkan: Share keyed mutex data. CW-Bug-Id: #22372 --- dlls/winevulkan/vulkan.c | 195 ++++++++++++++++++++++++++++++- dlls/winevulkan/vulkan_private.h | 14 +++ 2 files changed, 207 insertions(+), 2 deletions(-) diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index f6ef96b55d2..26caf7b792a 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -531,7 +531,8 @@ static char **parse_xr_extensions(unsigned int *len) } static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_dev, - struct conversion_context *ctx, const VkDeviceCreateInfo *src, VkDeviceCreateInfo *dst) + struct conversion_context *ctx, const VkDeviceCreateInfo *src, VkDeviceCreateInfo *dst, + struct wine_device *device) { static const char *wine_xr_extension_name = "VK_WINE_openxr_device_extensions"; unsigned int i, append_xr = 0, have_ext_mem32 = 0, have_ext_sem32 = 0, have_keyed_mutex = 0, append_timeline = 1; @@ -616,6 +617,7 @@ static VkResult wine_vk_device_convert_create_info(struct wine_phys_dev *phys_de new_extensions[o++] = "VK_KHR_external_memory_fd"; if (!have_ext_sem32) new_extensions[o++] = "VK_KHR_external_semaphore_fd"; + device->keyed_mutexes_enabled = TRUE; } if (phys_dev->external_memory_align) { @@ -993,7 +995,7 @@ VkResult wine_vkCreateDevice(VkPhysicalDevice phys_dev_handle, const VkDeviceCre } init_conversion_context(&ctx); - res = wine_vk_device_convert_create_info(phys_dev, &ctx, create_info, &create_info_host); + res = wine_vk_device_convert_create_info(phys_dev, &ctx, create_info, &create_info_host, object); if (res == VK_SUCCESS) { VkPhysicalDeviceFeatures features = {0}; @@ -2732,6 +2734,190 @@ static HANDLE get_shared_resource_kmt_handle(HANDLE shared_resource) return wine_server_ptr_handle(kmt_handle); } +static bool set_shared_resource_object(HANDLE shared_resource, unsigned int index, HANDLE handle); +static HANDLE get_shared_resource_object(HANDLE shared_resource, unsigned int index); + +static void destroy_keyed_mutex(struct wine_device *device, struct wine_device_memory *memory) +{ + if (memory->keyed_mutex_shm) + { + NtUnmapViewOfSection(GetCurrentProcess(), memory->keyed_mutex_shm); + memory->keyed_mutex_shm = NULL; + } + if (memory->keyed_mutex_sem) + { + device->funcs.p_vkDestroySemaphore(device->device, memory->keyed_mutex_sem, NULL); + memory->keyed_mutex_sem = VK_NULL_HANDLE; + } +} + +static void create_keyed_mutex(struct wine_device *device, struct wine_device_memory *memory) +{ + VkExportSemaphoreCreateInfo timeline_export_info; + VkSemaphoreTypeCreateInfo type_info; + VkSemaphoreCreateInfo create_info; + VkSemaphoreGetFdInfoKHR fd_info; + pthread_mutexattr_t mutex_attr; + OBJECT_ATTRIBUTES attr; + HANDLE section_handle; + LARGE_INTEGER li; + HANDLE handle; + SIZE_T size; + VkResult vr; + int fd; + + InitializeObjectAttributes(&attr, NULL, 0, NULL, NULL); + size = li.QuadPart = sizeof(*memory->keyed_mutex_shm); + if (NtCreateSection(§ion_handle, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE, &attr, &li, PAGE_READWRITE, SEC_COMMIT, NULL)) + { + ERR("NtCreateSection failed.\n"); + return; + } + + if (!set_shared_resource_object(memory->handle, 0, section_handle)) + { + NtClose(section_handle); + ERR("set_shared_resource_object failed.\n"); + return; + } + + if (NtMapViewOfSection(section_handle, GetCurrentProcess(), (void**) &memory->keyed_mutex_shm, 0, 0, NULL, &size, ViewShare, 0, PAGE_READWRITE)) + { + NtClose(section_handle); + ERR("NtMapViewOfSection failed.\n"); + return; + } + + NtClose(section_handle); + + timeline_export_info.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO; + timeline_export_info.pNext = NULL; + timeline_export_info.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; + + type_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO; + type_info.pNext = &timeline_export_info; + type_info.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE; + type_info.initialValue = 0; + + create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + create_info.pNext = &type_info; + create_info.flags = 0; + + if ((vr = device->funcs.p_vkCreateSemaphore(device->device, &create_info, NULL, &memory->keyed_mutex_sem)) != VK_SUCCESS) + { + ERR("Failed to create semaphore, vr %d.\n", vr); + goto error; + } + fd_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR; + fd_info.pNext = NULL; + fd_info.semaphore = memory->keyed_mutex_sem; + fd_info.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; + + if ((vr = device->funcs.p_vkGetSemaphoreFdKHR(device->device, &fd_info, &fd)) != VK_SUCCESS) + { + ERR("Failed to export semaphore fd, vr %d.\n", vr); + goto error; + } + if (wine_server_fd_to_handle(fd, GENERIC_ALL, 0, &handle) != STATUS_SUCCESS) + { + ERR("wine_server_fd_to_handle failed.\n"); + close(fd); + goto error; + } + close(fd); + if (!set_shared_resource_object(memory->handle, 1, handle)) + { + ERR("set_shared_resource_object failed.\n"); + NtClose(handle); + goto error; + } + NtClose(handle); + + pthread_mutexattr_init(&mutex_attr); + pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED); + if (pthread_mutex_init(&memory->keyed_mutex_shm->mutex, &mutex_attr)) + memory->keyed_mutex_shm->instance_id_counter = 1; + memory->keyed_mutex_instance_id = ++memory->keyed_mutex_shm->instance_id_counter; + TRACE("memory %p, created keyed mutex.\n", memory); + return; + +error: + destroy_keyed_mutex(device, memory); +} + +static void import_keyed_mutex(struct wine_device *device, struct wine_device_memory *memory) +{ + VkSemaphoreTypeCreateInfo type_info; + VkImportSemaphoreFdInfoKHR fd_info; + VkSemaphoreCreateInfo create_info; + HANDLE section_handle, sem_handle; + SIZE_T size; + + VkResult vr; + + if (!(section_handle = get_shared_resource_object(memory->handle, 0))) + { + TRACE("No section handle.\n"); + return; + } + if (!(sem_handle = get_shared_resource_object(memory->handle, 1))) + { + ERR("No smeaphore handle.\n"); + NtClose(section_handle); + return; + } + + size = sizeof(*memory->keyed_mutex_shm); + if (NtMapViewOfSection(section_handle, GetCurrentProcess(), (void**) &memory->keyed_mutex_shm, 0, 0, NULL, &size, ViewShare, 0, PAGE_READWRITE)) + { + ERR("NtMapViewOfSection failed.\n"); + goto error; + } + + type_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO; + type_info.pNext = NULL; + type_info.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE; + type_info.initialValue = 0; + + create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + create_info.pNext = &type_info; + create_info.flags = 0; + + if ((vr = device->funcs.p_vkCreateSemaphore(device->device, &create_info, NULL, &memory->keyed_mutex_sem)) != VK_SUCCESS) + { + ERR("Failed to create semaphore, vr %d.\n", vr); + goto error; + } + + fd_info.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR; + fd_info.pNext = NULL; + fd_info.semaphore = memory->keyed_mutex_sem; + fd_info.flags = 0; + fd_info.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; + + if (wine_server_handle_to_fd(sem_handle, FILE_READ_DATA, &fd_info.fd, NULL)) + { + ERR("wine_server_handle_to_fd failed.\n"); + goto error; + } + + vr = device->funcs.p_vkImportSemaphoreFdKHR(device->device, &fd_info); + close(fd_info.fd); + if (vr != VK_SUCCESS) + { + ERR("vkImportSemaphoreFdKHR failed, vr %d.\n", vr); + goto error; + } + + memory->keyed_mutex_instance_id = InterlockedIncrement64((LONGLONG *)&memory->keyed_mutex_shm->instance_id_counter); + TRACE("memory %p, imported keyed mutex.\n", memory); + return; +error: + NtClose(section_handle); + NtClose(sem_handle); + destroy_keyed_mutex(device, memory); +} + VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *alloc_info, const VkAllocationCallbacks *allocator, VkDeviceMemory *ret, void *win_pAllocateInfo) @@ -2842,6 +3028,8 @@ VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *allo ERR("Zero shared resource size.\n"); } } + if (device->keyed_mutexes_enabled) + import_keyed_mutex(device, memory); } else if (device->phys_dev->external_memory_align && (mem_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && !find_next_struct(alloc_info->pNext, VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT)) @@ -2929,6 +3117,8 @@ VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *allo else memory->inherit = FALSE; close(fd); + if (device->keyed_mutexes_enabled) + create_keyed_mutex(device, memory); } if (memory->handle == INVALID_HANDLE_VALUE) @@ -2963,6 +3153,7 @@ void wine_vkFreeMemory(VkDevice handle, VkDeviceMemory memory_handle, const VkAl return; memory = wine_device_memory_from_handle(memory_handle); + destroy_keyed_mutex(device, memory); device->funcs.p_vkFreeMemory(device->device, memory->memory, NULL); if (memory->mapping) diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index beae80cd929..c9548e944d2 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -98,6 +98,7 @@ struct wine_device pthread_cond_t sem_poll_updated_cond; uint64_t sem_poll_update_value; /* set to sem_poll_update.value by signaller thread once update is processed. */ unsigned int allocated_fence_ops_count; + BOOL keyed_mutexes_enabled; }; static inline struct wine_device *wine_device_from_handle(VkDevice handle) @@ -248,6 +249,16 @@ static inline struct wine_cmd_pool *wine_cmd_pool_from_handle(VkCommandPool hand return (struct wine_cmd_pool *)(uintptr_t)client_ptr->unix_handle; } +struct keyed_mutex_shm +{ + pthread_mutex_t mutex; + uint64_t instance_id_counter; + uint64_t acquired_to_instance; + uint64_t key; + uint64_t timeline_value; + uint64_t timeline_queued_release; +}; + struct wine_device_memory { VkDeviceMemory memory; @@ -256,6 +267,9 @@ struct wine_device_memory DWORD access; HANDLE handle; void *mapping; + struct keyed_mutex_shm *keyed_mutex_shm; + VkSemaphore keyed_mutex_sem; + uint64_t keyed_mutex_instance_id; }; static inline VkDeviceMemory wine_device_memory_to_handle(struct wine_device_memory *device_memory) From f8085807958df7261c41089bf2daaf6b318ce85c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 4 Aug 2023 20:46:30 -0600 Subject: [PATCH 1530/2777] winevulkan: Support keyed mutex waits and signals in submits. CW-Bug-Id: #22372 --- dlls/winevulkan/make_vulkan | 4 +- dlls/winevulkan/vulkan.c | 284 ++++++++++++++++++++++++++++++++++-- 2 files changed, 271 insertions(+), 17 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 98b861b8eb3..f10bcf12a59 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -220,7 +220,7 @@ FUNCTION_OVERRIDES = { "vkWaitSemaphores" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, "vkQueueBindSparse" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, "vkQueueSubmit" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE, "extra_param" : "pSubmits"}, - "vkQueueSubmit2" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, + "vkQueueSubmit2" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE, "extra_param" : "pSubmits"}, # VK_KHR_surface "vkDestroySurfaceKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE}, @@ -295,7 +295,7 @@ FUNCTION_OVERRIDES = { "vkWaitSemaphoresKHR" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, # VK_KHR_synchronization2 - "vkQueueSubmit2KHR" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, + "vkQueueSubmit2KHR" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE, "extra_param" : "pSubmits"}, } STRUCT_CHAIN_CONVERSIONS = { diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 26caf7b792a..910c8be3776 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -2918,6 +2918,111 @@ static void import_keyed_mutex(struct wine_device *device, struct wine_device_me destroy_keyed_mutex(device, memory); } +static VkResult acquire_keyed_mutex(struct wine_device *device, struct wine_device_memory *memory, uint64_t key, + uint32_t timeout_ms) +{ + ULONG end_wait, curr_tick, remaining_wait; + VkSemaphoreWaitInfo wait_info = { 0 }; + uint64_t timeline; + VkResult vr; + + if (!memory->keyed_mutex_shm) + return VK_ERROR_UNKNOWN; + + wait_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO; + wait_info.semaphoreCount = 1; + wait_info.pSemaphores = &memory->keyed_mutex_sem; + wait_info.pValues = &timeline; + + end_wait = NtGetTickCount() + timeout_ms; + + while (1) + { + pthread_mutex_lock(&memory->keyed_mutex_shm->mutex); + + if (memory->keyed_mutex_shm->acquired_to_instance) + { + if ((vr = get_semaphore_value(device, memory->keyed_mutex_sem, &timeline)) != VK_SUCCESS) + { + pthread_mutex_unlock(&memory->keyed_mutex_shm->mutex); + return VK_ERROR_UNKNOWN; + } + assert(timeline == memory->keyed_mutex_shm->timeline_value + || timeline == memory->keyed_mutex_shm->timeline_value + 1); + if (timeline == memory->keyed_mutex_shm->timeline_value + 1) + { + /* released from queue. */ + assert(memory->keyed_mutex_shm->timeline_queued_release == timeline); + memory->keyed_mutex_shm->timeline_queued_release = 0; + ++memory->keyed_mutex_shm->timeline_value; + memory->keyed_mutex_shm->acquired_to_instance = 0; + } + } + + if (memory->keyed_mutex_shm->acquired_to_instance == memory->keyed_mutex_instance_id + && !memory->keyed_mutex_shm->timeline_queued_release) + { + /* Already acquired to this device. */ + pthread_mutex_unlock(&memory->keyed_mutex_shm->mutex); + return VK_ERROR_UNKNOWN; + } + if (!memory->keyed_mutex_shm->acquired_to_instance && memory->keyed_mutex_shm->key == key) + { + /* Can acquire. */ + memory->keyed_mutex_shm->acquired_to_instance = memory->keyed_mutex_instance_id; + pthread_mutex_unlock(&memory->keyed_mutex_shm->mutex); + return VK_SUCCESS; + } + curr_tick = NtGetTickCount(); + if (!timeout_ms || curr_tick >= end_wait) + { + pthread_mutex_unlock(&memory->keyed_mutex_shm->mutex); + return VK_TIMEOUT; + } + remaining_wait = timeout_ms == INFINITE ? INFINITE : end_wait - curr_tick; + timeline = memory->keyed_mutex_shm->timeline_value + 1; + pthread_mutex_unlock(&memory->keyed_mutex_shm->mutex); + + vr = wait_semaphores(device, &wait_info, remaining_wait * 1000000ull); + if (vr != VK_SUCCESS && vr != VK_TIMEOUT) + { + ERR("vkWaitSemaphores failed, vr %d.\n", vr); + return VK_ERROR_UNKNOWN; + } + } +} + +static VkResult release_keyed_mutex(struct wine_device *device, struct wine_device_memory *memory, uint64_t key, + uint64_t *timeline_value) +{ + if (!memory->keyed_mutex_shm) + return VK_ERROR_UNKNOWN; + + pthread_mutex_lock(&memory->keyed_mutex_shm->mutex); + if (memory->keyed_mutex_shm->acquired_to_instance != memory->keyed_mutex_instance_id + || memory->keyed_mutex_shm->timeline_queued_release) + { + pthread_mutex_unlock(&memory->keyed_mutex_shm->mutex); + return VK_ERROR_UNKNOWN; + } + memory->keyed_mutex_shm->key = key; + if (timeline_value) + { + /* Return timeline value to signal from queue. */ + *timeline_value = memory->keyed_mutex_shm->timeline_value + 1; + memory->keyed_mutex_shm->timeline_queued_release = *timeline_value; + } + else + { + /* Release immediately. */ + memory->keyed_mutex_shm->acquired_to_instance = 0; + signal_timeline_sem(device, memory->keyed_mutex_sem, &memory->keyed_mutex_shm->timeline_value); + } + pthread_mutex_unlock(&memory->keyed_mutex_shm->mutex); + + return VK_SUCCESS; +} + VkResult wine_vkAllocateMemory(VkDevice handle, const VkMemoryAllocateInfo *alloc_info, const VkAllocationCallbacks *allocator, VkDeviceMemory *ret, void *win_pAllocateInfo) @@ -4969,17 +5074,127 @@ struct struct_chain_def unsigned int size; }; +static VkResult process_keyed_mutexes(struct conversion_context *ctx, struct wine_device *device, + uint32_t submit_count, const void *submits_win, size_t submit_size, uint32_t **signal_counts, + VkSemaphoreSubmitInfo ***signal_infos) +{ + VkWin32KeyedMutexAcquireReleaseInfoKHR *keyed_mutex_info; + struct wine_device_memory *memory; + VkResult ret = VK_ERROR_UNKNOWN; + uint32_t i, j, signal_count = 0; + void *ptr; + + for (i = 0; i < submit_count; ++i) + { + ptr = (char *)submits_win + i * submit_size; + if (!(keyed_mutex_info = wine_vk_find_struct(ptr, WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR))) + continue; + for (j = 0; j < keyed_mutex_info->acquireCount; ++j) + { + memory = wine_device_memory_from_handle(keyed_mutex_info->pAcquireSyncs[j]); + if ((ret = acquire_keyed_mutex(device, memory, keyed_mutex_info->pAcquireKeys[j], + keyed_mutex_info->pAcquireTimeouts[j])) == VK_SUCCESS) + continue; + while (j) + { + --j; + memory = wine_device_memory_from_handle(keyed_mutex_info->pAcquireSyncs[j]); + release_keyed_mutex(device, memory, keyed_mutex_info->pAcquireKeys[j], NULL); + } + goto error; + } + /* Pre-check release error conditions. */ + for (j = 0; j < keyed_mutex_info->releaseCount; ++j) + { + memory = wine_device_memory_from_handle(keyed_mutex_info->pReleaseSyncs[j]); + if (!memory->keyed_mutex_shm) + goto error; + if (memory->keyed_mutex_shm->acquired_to_instance != memory->keyed_mutex_instance_id) + goto error; + } + signal_count += keyed_mutex_info->releaseCount; + } + + if (!signal_count) + { + *signal_counts = NULL; + return VK_SUCCESS; + } + *signal_counts = conversion_context_alloc(ctx, sizeof(**signal_counts) * submit_count); + *signal_infos = conversion_context_alloc(ctx, sizeof(**signal_infos) * submit_count); + for (i = 0; i < submit_count; ++i) + { + ptr = (char *)submits_win + i * submit_size; + if (!(keyed_mutex_info = wine_vk_find_struct(ptr, WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR))) + { + (*signal_counts)[i] = 0; + continue; + } + (*signal_counts)[i] = keyed_mutex_info->releaseCount; + (*signal_infos)[i] = conversion_context_alloc(ctx, sizeof(***signal_infos) * keyed_mutex_info->releaseCount); + for (j = 0; j < keyed_mutex_info->releaseCount; ++j) + { + memory = wine_device_memory_from_handle(keyed_mutex_info->pReleaseSyncs[j]); + (*signal_infos)[i][j].sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO; + (*signal_infos)[i][j].pNext = NULL; + (*signal_infos)[i][j].semaphore = memory->keyed_mutex_sem; + (*signal_infos)[i][j].stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + (*signal_infos)[i][j].deviceIndex = 0; + ret = release_keyed_mutex(device, memory, keyed_mutex_info->pReleaseKeys[j], &(*signal_infos)[i][j].value); + if (ret != VK_SUCCESS) + { + /* This should only be possible if a racing submit queued release before us, currently not handled. */ + ERR("release_keyed_mutex failed, ret %d.\n", ret); + (*signal_infos)[i][j].value = 0; + } + } + } + + return VK_SUCCESS; + +error: + while (i) + { + --i; + ptr = (char *)submits_win + i * submit_size; + if (!(keyed_mutex_info = wine_vk_find_struct(ptr, WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR))) + continue; + for (j = 0; j < keyed_mutex_info->acquireCount; ++j) + { + memory = wine_device_memory_from_handle(keyed_mutex_info->pAcquireSyncs[j]); + release_keyed_mutex(device, memory, keyed_mutex_info->pAcquireKeys[j], NULL); + } + } + return ret; +} + +static void duplicate_array_for_unwrapping_copy_size(struct conversion_context *ctx, void **ptr, unsigned int size, + unsigned int copy_size) +{ + void *out; + + if (!size) + return; + + out = conversion_context_alloc(ctx, size); + if (*ptr) + memcpy(out, *ptr, copy_size); + *ptr = out; +} + VkResult wine_vkQueueSubmit(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo *submits_orig, VkFence fence, void *submits_win_ptr) { struct wine_queue *queue = wine_queue_from_handle(queue_handle); struct wine_device *device = queue->device; - VkTimelineSemaphoreSubmitInfo *timeline_submit_info; + VkTimelineSemaphoreSubmitInfo *timeline_submit_info, ts_info_copy; const VkSubmitInfo *submits_win = submits_win_ptr; VkD3D12FenceSubmitInfoKHR *d3d12_submit_info; const uint64_t **values; struct conversion_context ctx; VkSubmitInfo *submits; + VkSemaphoreSubmitInfo **km_infos; + uint32_t *km_counts; unsigned int i, j; VkResult ret; @@ -4987,6 +5202,9 @@ VkResult wine_vkQueueSubmit(VkQueue queue_handle, uint32_t submit_count, const V init_conversion_context(&ctx); MEMDUP(&ctx, submits, submits_orig, submit_count); + if ((ret = process_keyed_mutexes(&ctx, device, submit_count, submits_win_ptr, sizeof(*submits), &km_counts, &km_infos))) + return ret; + for (i = 0; i < submit_count; ++i) { timeline_submit_info = wine_vk_find_struct(&submits[i], TIMELINE_SEMAPHORE_SUBMIT_INFO); @@ -5016,6 +5234,36 @@ VkResult wine_vkQueueSubmit(VkQueue queue_handle, uint32_t submit_count, const V else values = NULL; unwrap_semaphore_array(&submits[i].pSignalSemaphores, values, submits[i].signalSemaphoreCount, &ctx, TRUE, device); + if (km_counts && km_counts[i]) + { + if (timeline_submit_info) + { + ts_info_copy = *timeline_submit_info; + timeline_submit_info = &ts_info_copy; + duplicate_array_for_unwrapping_copy_size(&ctx, (void **)&timeline_submit_info->pSignalSemaphoreValues, + (timeline_submit_info->signalSemaphoreValueCount + km_counts[i]) * sizeof(*timeline_submit_info->pSignalSemaphoreValues), + timeline_submit_info->signalSemaphoreValueCount * sizeof(*timeline_submit_info->pSignalSemaphoreValues)); + } + else + { + timeline_submit_info = &ts_info_copy; + timeline_submit_info->sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO; + timeline_submit_info->pNext = submits[i].pNext; + timeline_submit_info->waitSemaphoreValueCount = 0; + timeline_submit_info->signalSemaphoreValueCount = 0; + timeline_submit_info->pSignalSemaphoreValues = conversion_context_alloc(&ctx, km_counts[i] * sizeof(*timeline_submit_info->pSignalSemaphoreValues)); + submits[i].pNext = timeline_submit_info; + } + duplicate_array_for_unwrapping_copy_size(&ctx, (void **)&submits[i].pSignalSemaphores, + (submits[i].signalSemaphoreCount + km_counts[i]) * sizeof(*submits[i].pSignalSemaphores), + submits[i].signalSemaphoreCount * sizeof(*submits[i].pSignalSemaphores)); + for (j = 0; j < km_counts[i]; ++j) + { + ((uint64_t *)timeline_submit_info->pSignalSemaphoreValues)[j + timeline_submit_info->signalSemaphoreValueCount++] + = km_infos[i][j].value; + ((VkSemaphore *)submits[i].pSignalSemaphores)[j + submits[i].signalSemaphoreCount++] = km_infos[i][j].semaphore; + } + } if (submits[i].pCommandBuffers && submits[i].commandBufferCount) { @@ -5034,20 +5282,17 @@ VkResult wine_vkQueueSubmit(VkQueue queue_handle, uint32_t submit_count, const V static void duplicate_array_for_unwrapping(struct conversion_context *ctx, void **ptr, unsigned int size) { - void *out; - - if (!*ptr || !size) - return; - - out = conversion_context_alloc(ctx, size); - memcpy(out, *ptr, size); - *ptr = out; + duplicate_array_for_unwrapping_copy_size(ctx, ptr, size, size); } -static VkResult vk_queue_submit_2(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo2 *submits_orig, VkFence fence, bool khr) +static VkResult vk_queue_submit_2(VkQueue queue_handle, uint32_t submit_count, const VkSubmitInfo2 *submits_orig, + VkFence fence, bool khr, void *submits_win_ptr) { struct wine_queue *queue = wine_queue_from_handle(queue_handle); + struct wine_device *device = queue->device; struct conversion_context ctx; + VkSemaphoreSubmitInfo **km_infos; + uint32_t *km_counts, count; VkSubmitInfo2 *submits; unsigned int i, j; VkResult ret; @@ -5056,6 +5301,8 @@ static VkResult vk_queue_submit_2(VkQueue queue_handle, uint32_t submit_count, c init_conversion_context(&ctx); MEMDUP(&ctx, submits, submits_orig, submit_count); + if ((ret = process_keyed_mutexes(&ctx, device, submit_count, submits_win_ptr, sizeof(*submits), &km_counts, &km_infos))) + return ret; for (i = 0; i < submit_count; ++i) { duplicate_array_for_unwrapping(&ctx, (void **)&submits[i].pWaitSemaphoreInfos, @@ -5064,11 +5311,16 @@ static VkResult vk_queue_submit_2(VkQueue queue_handle, uint32_t submit_count, c unwrap_semaphore(queue->device, &((VkSemaphoreSubmitInfo *)submits[i].pWaitSemaphoreInfos)[j].semaphore, &((VkSemaphoreSubmitInfo *)submits[i].pWaitSemaphoreInfos)[j].value, FALSE); - duplicate_array_for_unwrapping(&ctx, (void **)&submits[i].pSignalSemaphoreInfos, + count = submits[i].signalSemaphoreInfoCount + (km_counts ? km_counts[i] : 0); + duplicate_array_for_unwrapping_copy_size(&ctx, (void **)&submits[i].pSignalSemaphoreInfos, + count * sizeof(*submits[i].pSignalSemaphoreInfos), submits[i].signalSemaphoreInfoCount * sizeof(*submits[i].pSignalSemaphoreInfos)); for (j = 0; j < submits[i].signalSemaphoreInfoCount; ++j) unwrap_semaphore(queue->device, &((VkSemaphoreSubmitInfo *)submits[i].pSignalSemaphoreInfos)[j].semaphore, &((VkSemaphoreSubmitInfo *)submits[i].pSignalSemaphoreInfos)[j].value, TRUE); + for (; j < count; ++j) + ((VkSemaphoreSubmitInfo *)submits[i].pSignalSemaphoreInfos)[j] = km_infos[i][j - submits[i].signalSemaphoreInfoCount]; + submits[i].signalSemaphoreInfoCount = count; if (submits[i].pCommandBufferInfos && submits[i].commandBufferInfoCount) { @@ -5088,14 +5340,16 @@ static VkResult vk_queue_submit_2(VkQueue queue_handle, uint32_t submit_count, c return ret; } -VkResult wine_vkQueueSubmit2(VkQueue queue, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence) +VkResult wine_vkQueueSubmit2(VkQueue queue, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence, + void *submits_win) { - return vk_queue_submit_2(queue, submit_count, submits, fence, false); + return vk_queue_submit_2(queue, submit_count, submits, fence, false, submits_win); } -VkResult wine_vkQueueSubmit2KHR(VkQueue queue, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence) +VkResult wine_vkQueueSubmit2KHR(VkQueue queue, uint32_t submit_count, const VkSubmitInfo2 *submits, VkFence fence, + void *submits_win) { - return vk_queue_submit_2(queue, submit_count, submits, fence, true); + return vk_queue_submit_2(queue, submit_count, submits, fence, true, submits_win); } VkResult wine_vkQueuePresentKHR(VkQueue queue_handle, const VkPresentInfoKHR *present_info) From 0dab18164e40f52b5852e3591d809e1034b48eee Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 10 Aug 2023 12:23:26 -0600 Subject: [PATCH 1531/2777] winevulkan: Export custom functions for acquiring and releasing keyed mutexes. CW-Bug-Id: #22372 --- dlls/winevulkan/make_vulkan | 21 +++++++++++++++------ dlls/winevulkan/vk_custom.xml | 24 ++++++++++++++++++++++++ dlls/winevulkan/vulkan.c | 12 ++++++++++++ 3 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 dlls/winevulkan/vk_custom.xml diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index f10bcf12a59..ae00d208318 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -296,6 +296,10 @@ FUNCTION_OVERRIDES = { # VK_KHR_synchronization2 "vkQueueSubmit2KHR" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE, "extra_param" : "pSubmits"}, + + # Custom functions + "wine_vkAcquireKeyedMutex" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, + "wine_vkReleaseKeyedMutex" : {"dispatch": True, "driver": False, "thunk" : ThunkType.PRIVATE}, } STRUCT_CHAIN_CONVERSIONS = { @@ -3353,12 +3357,16 @@ class VkRegistry(object): # function call we want we set a member 'required' to True. tree = ET.parse(reg_filename) root = tree.getroot() + + tree_custom = ET.parse("vk_custom.xml") + root_custom = tree_custom.getroot() + self._parse_enums(root) self._parse_types(root) - self._parse_commands(root) + self._parse_commands(root, root_custom) # Pull in any required types and functions. - self._parse_features(root) + self._parse_features(root, root_custom) self._parse_extensions(root) for enum in self.enums.values(): @@ -3451,10 +3459,10 @@ class VkRegistry(object): if not handle.object_type: LOGGER.warning("No object type found for {}".format(handle.name)) - def _parse_commands(self, root): + def _parse_commands(self, root, root_custom): """ Parse command section containing the Vulkan function calls. """ funcs = {} - commands = root.findall("./commands/") + commands = root.findall("./commands/") + root_custom.findall("./commands/") # As of Vulkan 1.1, various extensions got promoted to Core. # The old commands (e.g. KHR) are available for backwards compatibility @@ -3470,6 +3478,7 @@ class VkRegistry(object): continue func = VkFunction.from_xml(command, self.types) + if func: funcs[func.name] = func @@ -3721,10 +3730,10 @@ class VkRegistry(object): # Sort in alphabetical order. self.extensions = sorted(extensions, key=lambda ext: ext["name"]) - def _parse_features(self, root): + def _parse_features(self, root, root_custom): """ Parse the feature section, which describes Core commands and types needed. """ - for feature in root.findall("./feature"): + for feature in (root.findall("./feature") + root_custom.findall("./feature")): if not api_is_vulkan(feature): continue feature_name = feature.attrib["name"] diff --git a/dlls/winevulkan/vk_custom.xml b/dlls/winevulkan/vk_custom.xml new file mode 100644 index 00000000000..a9fd68548c4 --- /dev/null +++ b/dlls/winevulkan/vk_custom.xml @@ -0,0 +1,24 @@ + + + + + VkResult wine_vkAcquireKeyedMutex + VkDevice device + VkDeviceMemory memory + uint64_t key + uint32_t timeout_ms + + + VkResult wine_vkReleaseKeyedMutex + VkDevice device + VkDeviceMemory memory + uint64_t key + + + + + + + + + diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 910c8be3776..a20ec837e2a 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -3982,6 +3982,8 @@ static void substitute_function_name(const char **name) *name = "vkGetSemaphoreFdKHR"; else if (!strcmp(*name, "vkImportSemaphoreWin32HandleKHR")) *name = "vkImportSemaphoreFdKHR"; + else if (!strcmp(*name, "wine_vkAcquireKeyedMutex") || !strcmp(*name, "wine_vkReleaseKeyedMutex")) + *name = "vkImportSemaphoreFdKHR"; } #ifdef _WIN64 @@ -5461,3 +5463,13 @@ VkResult wine_vkQueueBindSparse(VkQueue queue_handle, uint32_t bind_info_count, free_conversion_context(&ctx); return ret; } + +VkResult wine_wine_vkAcquireKeyedMutex(VkDevice device, VkDeviceMemory memory, uint64_t key, uint32_t timeout_ms) +{ + return acquire_keyed_mutex(wine_device_from_handle(device), wine_device_memory_from_handle(memory), key, timeout_ms); +} + +VkResult wine_wine_vkReleaseKeyedMutex(VkDevice device, VkDeviceMemory memory, uint64_t key) +{ + return release_keyed_mutex(wine_device_from_handle(device), wine_device_memory_from_handle(memory), key, NULL); +} From 69e2852d373df1c0c075e1be3adf59452c0270a3 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 28 Jun 2023 20:42:36 -0600 Subject: [PATCH 1532/2777] crypt32/tests: Add test for CryptVerifyCertificateSignature() with ECC public key. (cherry picked from commit e6f7e3a0cbd306fc6295ab01ae373854b670dfc0) CW-Bug-Id: #22376 --- dlls/crypt32/tests/cert.c | 45 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/dlls/crypt32/tests/cert.c b/dlls/crypt32/tests/cert.c index 83594560efa..370ed064a94 100644 --- a/dlls/crypt32/tests/cert.c +++ b/dlls/crypt32/tests/cert.c @@ -2042,6 +2042,43 @@ static void testVerifyCertSigEx(HCRYPTPROV csp, const CRYPT_DATA_BLOB *toBeSigne static BYTE emptyCert[] = { 0x30, 0x00 }; + +/* Generated with: + * openssl ecparam -name prime256v1 -genkey -out private-key.pem + * openssl req -new -x509 -key private-key.pem -out certificate.der -outform der -days 900000 -subj "/C=US/ST=T/L=T/O=T/CN=T" + */ +static const BYTE self_signed_ecc_prime256v1[] = { +0x30,0x82,0x01,0xd1,0x30,0x82,0x01,0x77,0xa0,0x03,0x02,0x01,0x02,0x02,0x14,0x32, +0xc2,0xbe,0x7b,0xa2,0x85,0x78,0x89,0x82,0xf8,0x10,0x66,0xd4,0x1d,0xd4,0x97,0x61, +0x83,0x02,0xc8,0x30,0x0a,0x06,0x08,0x2a,0x86,0x48,0xce,0x3d,0x04,0x03,0x02,0x30, +0x3d,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0a, +0x30,0x08,0x06,0x03,0x55,0x04,0x08,0x0c,0x01,0x54,0x31,0x0a,0x30,0x08,0x06,0x03, +0x55,0x04,0x07,0x0c,0x01,0x54,0x31,0x0a,0x30,0x08,0x06,0x03,0x55,0x04,0x0a,0x0c, +0x01,0x54,0x31,0x0a,0x30,0x08,0x06,0x03,0x55,0x04,0x03,0x0c,0x01,0x54,0x30,0x20, +0x17,0x0d,0x32,0x33,0x30,0x36,0x32,0x39,0x30,0x32,0x32,0x34,0x30,0x33,0x5a,0x18, +0x0f,0x34,0x34,0x38,0x37,0x30,0x38,0x31,0x30,0x30,0x32,0x32,0x34,0x30,0x33,0x5a, +0x30,0x3d,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31, +0x0a,0x30,0x08,0x06,0x03,0x55,0x04,0x08,0x0c,0x01,0x54,0x31,0x0a,0x30,0x08,0x06, +0x03,0x55,0x04,0x07,0x0c,0x01,0x54,0x31,0x0a,0x30,0x08,0x06,0x03,0x55,0x04,0x0a, +0x0c,0x01,0x54,0x31,0x0a,0x30,0x08,0x06,0x03,0x55,0x04,0x03,0x0c,0x01,0x54,0x30, +0x59,0x30,0x13,0x06,0x07,0x2a,0x86,0x48,0xce,0x3d,0x02,0x01,0x06,0x08,0x2a,0x86, +0x48,0xce,0x3d,0x03,0x01,0x07,0x03,0x42,0x00,0x04,0xfe,0xdb,0x26,0x60,0xf6,0x89, +0x3d,0xa4,0x50,0x1f,0x06,0x91,0x4e,0x07,0x86,0x70,0x2b,0xc0,0x7c,0x5e,0xb3,0xca, +0xdc,0x1a,0x8b,0x82,0xdd,0x41,0x8a,0x62,0x0f,0xba,0xd1,0xd7,0x80,0xc8,0x20,0x77, +0xba,0xe7,0xe1,0x36,0xf8,0x76,0x9a,0x54,0x6a,0x1b,0x67,0x45,0x3b,0xd7,0x85,0x84, +0xbe,0x11,0xe6,0x6c,0x70,0xd8,0x18,0x68,0xd8,0xa7,0xa3,0x53,0x30,0x51,0x30,0x1d, +0x06,0x03,0x55,0x1d,0x0e,0x04,0x16,0x04,0x14,0x94,0x15,0x14,0xad,0x7e,0xaf,0x63, +0xa4,0x12,0x29,0xaa,0xe4,0x26,0x54,0x7b,0x4e,0x2c,0xb9,0xdb,0xc8,0x30,0x1f,0x06, +0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x94,0x15,0x14,0xad,0x7e,0xaf, +0x63,0xa4,0x12,0x29,0xaa,0xe4,0x26,0x54,0x7b,0x4e,0x2c,0xb9,0xdb,0xc8,0x30,0x0f, +0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30, +0x0a,0x06,0x08,0x2a,0x86,0x48,0xce,0x3d,0x04,0x03,0x02,0x03,0x48,0x00,0x30,0x45, +0x02,0x21,0x00,0x83,0xae,0xa2,0x23,0x95,0x1a,0x65,0x09,0x48,0x40,0x10,0xeb,0x94, +0x90,0x02,0xde,0xe3,0x0f,0x4b,0xd1,0x23,0x73,0xc6,0xd5,0x49,0xa8,0x9c,0x06,0x9c, +0xd3,0xfb,0xc1,0x02,0x20,0x0c,0xf3,0x92,0xec,0xc8,0xb5,0x7e,0x9c,0x14,0x5d,0xb0, +0x26,0xfd,0x2a,0x3c,0x4e,0x08,0x55,0x09,0x35,0x40,0x7c,0xf8,0xf9,0x1b,0x22,0x55, +0x08,0x9b,0x3f,0x37,0x29, }; + static void testCertSigs(void) { HCRYPTPROV csp; @@ -2049,6 +2086,7 @@ static void testCertSigs(void) BOOL ret; BYTE sig[64]; DWORD sigSize = sizeof(sig); + PCCERT_CONTEXT cert; /* Just in case a previous run failed, delete this thing */ CryptAcquireContextA(&csp, cspNameA, MS_DEF_PROV_A, PROV_RSA_FULL, @@ -2065,6 +2103,13 @@ static void testCertSigs(void) ret = CryptAcquireContextA(&csp, cspNameA, MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_DELETEKEYSET); ok(ret, "CryptAcquireContext failed: %08lx\n", GetLastError()); + + cert = CertCreateCertificateContext(X509_ASN_ENCODING, self_signed_ecc_prime256v1, sizeof(self_signed_ecc_prime256v1)); + ok(!!cert, "failed, error %#lx.\n", GetLastError()); + ret = CryptVerifyCertificateSignature(0, X509_ASN_ENCODING, self_signed_ecc_prime256v1, + sizeof(self_signed_ecc_prime256v1), &cert->pCertInfo->SubjectPublicKeyInfo); + ok(ret, "failed, error %#lx.\n", GetLastError()); + CertFreeCertificateContext(cert); } static const BYTE md5SignedEmptyCert[] = { From 276344952f2d5cc854e39e507b957a4ea85ae8fc Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 29 Jun 2023 10:55:58 -0600 Subject: [PATCH 1533/2777] crypt32/tests: Test ECC message signature verification. (cherry picked from commit 073c23940bfafa792c2e364744eeea63632faf41) CW-Bug-Id: #22376 --- dlls/crypt32/tests/msg.c | 140 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/dlls/crypt32/tests/msg.c b/dlls/crypt32/tests/msg.c index 16f7402c613..c663909ed7c 100644 --- a/dlls/crypt32/tests/msg.c +++ b/dlls/crypt32/tests/msg.c @@ -3483,6 +3483,145 @@ static void test_msg_get_and_verify_signer(void) CryptMsgClose(msg); } +/* Generated with: + * openssl ecparam -name prime256v1 -genkey -out private-key.pem + * openssl req -new -x509 -key private-key.pem -out certificate.der -outform der -days 10000 -subj "/C=US/ST=T/L=T/O=T/CN=T" + * openssl pkcs12 -export -out certificate.pfx -inkey private-key.pem -in certificate.der + * - import certificate.pfx on Windows + * signtool /sign /v /fd SHA256 certificate.pfx a.exe + * - extract signed message from a.exe + */ +static const BYTE msg_signed_ecc_prime256v1[] = { +0x30,0x82,0x03,0x85,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07,0x02,0xa0, +0x82,0x03,0x76,0x30,0x82,0x03,0x72,0x02,0x01,0x01,0x31,0x0f,0x30,0x0d,0x06,0x09, +0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x30,0x5c,0x06,0x0a,0x2b, +0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x04,0xa0,0x4e,0x30,0x4c,0x30,0x17,0x06, +0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x02,0x01,0x0f,0x30,0x09,0x03,0x01,0x00, +0xa0,0x04,0xa2,0x02,0x80,0x00,0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01, +0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20,0x32,0x54,0x6a,0x85,0xd7,0xe6,0x83, +0x46,0x6c,0x94,0x58,0x3b,0x17,0xa4,0xa8,0x8b,0xea,0xea,0x11,0xe0,0x6e,0xc4,0x3c, +0xea,0xde,0xbb,0x2e,0x7d,0xa3,0xb6,0xbe,0x69,0xa0,0x82,0x01,0xd5,0x30,0x82,0x01, +0xd1,0x30,0x82,0x01,0x77,0xa0,0x03,0x02,0x01,0x02,0x02,0x14,0x13,0x09,0x38,0x76, +0x3a,0x38,0xef,0x36,0xac,0xc3,0xa5,0x7e,0xa5,0xad,0x56,0x50,0x8d,0x77,0x55,0x2c, +0x30,0x0a,0x06,0x08,0x2a,0x86,0x48,0xce,0x3d,0x04,0x03,0x02,0x30,0x3d,0x31,0x0b, +0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0a,0x30,0x08,0x06, +0x03,0x55,0x04,0x08,0x0c,0x01,0x54,0x31,0x0a,0x30,0x08,0x06,0x03,0x55,0x04,0x07, +0x0c,0x01,0x54,0x31,0x0a,0x30,0x08,0x06,0x03,0x55,0x04,0x0a,0x0c,0x01,0x54,0x31, +0x0a,0x30,0x08,0x06,0x03,0x55,0x04,0x03,0x0c,0x01,0x54,0x30,0x20,0x17,0x0d,0x32, +0x33,0x30,0x36,0x32,0x39,0x30,0x33,0x31,0x38,0x35,0x35,0x5a,0x18,0x0f,0x32,0x30, +0x35,0x30,0x31,0x31,0x31,0x34,0x30,0x33,0x31,0x38,0x35,0x35,0x5a,0x30,0x3d,0x31, +0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0a,0x30,0x08, +0x06,0x03,0x55,0x04,0x08,0x0c,0x01,0x54,0x31,0x0a,0x30,0x08,0x06,0x03,0x55,0x04, +0x07,0x0c,0x01,0x54,0x31,0x0a,0x30,0x08,0x06,0x03,0x55,0x04,0x0a,0x0c,0x01,0x54, +0x31,0x0a,0x30,0x08,0x06,0x03,0x55,0x04,0x03,0x0c,0x01,0x54,0x30,0x59,0x30,0x13, +0x06,0x07,0x2a,0x86,0x48,0xce,0x3d,0x02,0x01,0x06,0x08,0x2a,0x86,0x48,0xce,0x3d, +0x03,0x01,0x07,0x03,0x42,0x00,0x04,0xfe,0xdb,0x26,0x60,0xf6,0x89,0x3d,0xa4,0x50, +0x1f,0x06,0x91,0x4e,0x07,0x86,0x70,0x2b,0xc0,0x7c,0x5e,0xb3,0xca,0xdc,0x1a,0x8b, +0x82,0xdd,0x41,0x8a,0x62,0x0f,0xba,0xd1,0xd7,0x80,0xc8,0x20,0x77,0xba,0xe7,0xe1, +0x36,0xf8,0x76,0x9a,0x54,0x6a,0x1b,0x67,0x45,0x3b,0xd7,0x85,0x84,0xbe,0x11,0xe6, +0x6c,0x70,0xd8,0x18,0x68,0xd8,0xa7,0xa3,0x53,0x30,0x51,0x30,0x1d,0x06,0x03,0x55, +0x1d,0x0e,0x04,0x16,0x04,0x14,0x94,0x15,0x14,0xad,0x7e,0xaf,0x63,0xa4,0x12,0x29, +0xaa,0xe4,0x26,0x54,0x7b,0x4e,0x2c,0xb9,0xdb,0xc8,0x30,0x1f,0x06,0x03,0x55,0x1d, +0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x94,0x15,0x14,0xad,0x7e,0xaf,0x63,0xa4,0x12, +0x29,0xaa,0xe4,0x26,0x54,0x7b,0x4e,0x2c,0xb9,0xdb,0xc8,0x30,0x0f,0x06,0x03,0x55, +0x1d,0x13,0x01,0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x0a,0x06,0x08, +0x2a,0x86,0x48,0xce,0x3d,0x04,0x03,0x02,0x03,0x48,0x00,0x30,0x45,0x02,0x21,0x00, +0xe6,0xb6,0x11,0x8d,0x75,0x3a,0x62,0xf3,0x08,0x17,0xce,0xa5,0x5a,0xcb,0x61,0xc7, +0x0a,0x33,0xdb,0x30,0x29,0x6b,0x5e,0xac,0xfc,0xaa,0xed,0x14,0xd1,0xd7,0xae,0x24, +0x02,0x20,0x2e,0x4d,0x70,0xc7,0x26,0xf7,0xea,0xa3,0x07,0x8a,0x6f,0x98,0x07,0xe1, +0xbc,0x38,0x13,0x88,0x17,0xdd,0x01,0x21,0x1e,0xb0,0xbb,0x32,0xfc,0x7a,0xc0,0xd5, +0x80,0x45,0x31,0x82,0x01,0x23,0x30,0x82,0x01,0x1f,0x02,0x01,0x01,0x30,0x55,0x30, +0x3d,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0a, +0x30,0x08,0x06,0x03,0x55,0x04,0x08,0x0c,0x01,0x54,0x31,0x0a,0x30,0x08,0x06,0x03, +0x55,0x04,0x07,0x0c,0x01,0x54,0x31,0x0a,0x30,0x08,0x06,0x03,0x55,0x04,0x0a,0x0c, +0x01,0x54,0x31,0x0a,0x30,0x08,0x06,0x03,0x55,0x04,0x03,0x0c,0x01,0x54,0x02,0x14, +0x13,0x09,0x38,0x76,0x3a,0x38,0xef,0x36,0xac,0xc3,0xa5,0x7e,0xa5,0xad,0x56,0x50, +0x8d,0x77,0x55,0x2c,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02, +0x01,0x05,0x00,0xa0,0x5e,0x30,0x10,0x06,0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,0x37, +0x02,0x01,0x0c,0x31,0x02,0x30,0x00,0x30,0x19,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7, +0x0d,0x01,0x09,0x03,0x31,0x0c,0x06,0x0a,0x2b,0x06,0x01,0x04,0x01,0x82,0x37,0x02, +0x01,0x04,0x30,0x2f,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x04,0x31, +0x22,0x04,0x20,0x25,0xc1,0x32,0xc0,0x4f,0x1a,0xae,0x84,0xd2,0x6a,0xff,0x0e,0xc9, +0xe8,0x85,0xbc,0x38,0x63,0x7b,0x22,0x89,0x1c,0x97,0x29,0xc2,0x8f,0x70,0x40,0xc2, +0xdf,0x42,0x9a,0x30,0x0b,0x06,0x07,0x2a,0x86,0x48,0xce,0x3d,0x02,0x01,0x05,0x00, +0x04,0x47,0x30,0x45,0x02,0x20,0x07,0x66,0x32,0x9a,0x15,0x8f,0x39,0x0a,0xb0,0xe1, +0x80,0xc9,0x82,0x23,0xb8,0x99,0x54,0x4c,0xa7,0x65,0xf2,0x99,0x11,0x70,0x1e,0xdf, +0xf5,0x40,0x73,0x7a,0x8d,0xd1,0x02,0x21,0x00,0x84,0xe0,0xec,0x38,0x33,0x01,0x28, +0x2b,0x4b,0x72,0xed,0x6a,0x64,0xb7,0xaf,0x7a,0x34,0x4b,0x6b,0x69,0xf6,0x55,0x9a, +0x8e,0x0d,0xe9,0xc1,0x85,0x80,0x4d,0xef,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00, }; + +static void test_verify_ecc_signature(void) +{ + HCERTSTORE store; + HCRYPTKEY key; + BCRYPT_KEY_HANDLE bkey; + HCRYPTMSG msg; + BOOL bret; + CERT_INFO *cert_info; + PCCERT_CONTEXT cert; + DWORD size; + CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA verify_para = { sizeof(verify_para) }; + HCRYPTOIDFUNCSET set; + void *import_func; + HCRYPTOIDFUNCADDR hfunc = NULL; + CMSG_CMS_SIGNER_INFO *signer_info; + + msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, NULL); + ok(!!msg, "failed, error %#lx.\n", GetLastError()); + bret = CryptMsgUpdate(msg, msg_signed_ecc_prime256v1, sizeof(msg_signed_ecc_prime256v1), TRUE); + ok(bret, "failed, error %#lx.\n", GetLastError()); + store = CertOpenStore(CERT_STORE_PROV_MSG, X509_ASN_ENCODING, 0, 0, msg); + ok(!!store, "failed, error %#lx.\n", GetLastError()); + size = 0; + bret = CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM, 0, NULL, &size); + ok(bret, "failed, error %#lx.\n", GetLastError()); + cert_info = malloc(size); + bret = CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM, 0, cert_info, &size); + ok(bret, "failed, error %#lx.\n", GetLastError()); + cert = CertGetSubjectCertificateFromStore(store, X509_ASN_ENCODING, cert_info); + ok(!!cert, "failed, error %#lx.\n", GetLastError()); + + ok(!strcmp(cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, szOID_ECC_PUBLIC_KEY), + "got OID %s.\n", cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId); + size = 0; + bret = CryptMsgGetParam(msg, CMSG_CMS_SIGNER_INFO_PARAM, 0, NULL, &size); + ok(bret, "failed, error %#lx.\n", GetLastError()); + signer_info = malloc(size); + bret = CryptMsgGetParam(msg, CMSG_CMS_SIGNER_INFO_PARAM, 0, signer_info, &size); + ok(bret, "failed, error %#lx.\n", GetLastError()); + ok(!strcmp(signer_info->HashAlgorithm.pszObjId, szOID_NIST_sha256), "got %s.\n", + signer_info->HashAlgorithm.pszObjId); + ok(!strcmp(signer_info->HashEncryptionAlgorithm.pszObjId, szOID_ECC_PUBLIC_KEY), "got %s.\n", + signer_info->HashEncryptionAlgorithm.pszObjId); + + set = CryptInitOIDFunctionSet(CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, 0); + ok(!!set, "failed, error %#lx.\n", GetLastError()); + bret = CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, cert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, + 0, (void **)&import_func, &hfunc); + ok(!bret, "succeeded.\n"); + + bret = CryptImportPublicKeyInfo(0, X509_ASN_ENCODING, &cert->pCertInfo->SubjectPublicKeyInfo, &key); + ok(!bret && GetLastError() == CRYPT_E_ASN1_BADTAG, "got ret %d, error %#lx.\n", bret, GetLastError()); + + bret = CryptImportPublicKeyInfoEx2(X509_ASN_ENCODING, &cert->pCertInfo->SubjectPublicKeyInfo, 0, NULL, &bkey); + ok(bret, "failed, error %#lx.\n", GetLastError()); + BCryptDestroyKey(bkey); + + bret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, cert->pCertInfo); + todo_wine ok(bret, "failed, error %#lx.\n", GetLastError()); + + verify_para.dwSignerType = CMSG_VERIFY_SIGNER_CERT; + verify_para.pvSigner = (void *)cert; + bret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE_EX, &verify_para); + todo_wine ok(bret, "failed, error %#lx.\n", GetLastError()); + + free(signer_info); + free(cert_info); + CertFreeCertificateContext(cert); + CertCloseStore(store, 0); + CryptMsgClose(msg); +} + START_TEST(msg) { /* Basic parameter checking tests */ @@ -3500,4 +3639,5 @@ START_TEST(msg) test_decode_msg(); test_msg_get_and_verify_signer(); + test_verify_ecc_signature(); } From 11444a1f85562ae94eb2af836eff7a80c4e7576d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 29 Jun 2023 11:12:28 -0600 Subject: [PATCH 1534/2777] crypt32: Add OID info for szOID_ECC_PUBLIC_KEY. (cherry picked from commit cbfcfc231360362771352c133906e7d879184319) CW-Bug-Id: #22376 --- dlls/crypt32/oid.c | 2 ++ dlls/crypt32/tests/oid.c | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/dlls/crypt32/oid.c b/dlls/crypt32/oid.c index a4dcc3997f0..70b9e638ab7 100644 --- a/dlls/crypt32/oid.c +++ b/dlls/crypt32/oid.c @@ -1271,6 +1271,8 @@ static const struct OIDInfoConstructor { { 3, szOID_INFOSEC_mosaicKMandUpdSig, CALG_DSS_SIGN, L"mosaicKMandUpdSig", &mosaicFlagsBlob }, { 3, szOID_RSA_SMIMEalgESDH, CALG_DH_EPHEM, L"ESDH", &noNullBlob }, { 3, szOID_PKIX_NO_SIGNATURE, CALG_NO_SIGN, L"NOSIGN", NULL }, + { 3, szOID_ECC_PUBLIC_KEY, CALG_OID_INFO_PARAMETERS, L"ECC", NULL, + CRYPT_OID_INFO_ECC_PARAMETERS_ALGORITHM, L"" }, { 4, szOID_RSA_SHA1RSA, CALG_SHA1, L"sha1RSA", &rsaSignBlob }, { 4, szOID_RSA_SHA256RSA, CALG_SHA_256, L"sha256RSA", &rsaSignBlob }, diff --git a/dlls/crypt32/tests/oid.c b/dlls/crypt32/tests/oid.c index 715d76b9c31..2423c819229 100644 --- a/dlls/crypt32/tests/oid.c +++ b/dlls/crypt32/tests/oid.c @@ -72,7 +72,8 @@ static const struct OIDToAlgID oidToAlgID[] = { { szOID_INFOSEC_mosaicKMandUpdSig, CALG_DSS_SIGN }, { szOID_NIST_sha256, CALG_SHA_256, -1 }, { szOID_NIST_sha384, CALG_SHA_384, -1 }, - { szOID_NIST_sha512, CALG_SHA_512, -1 } + { szOID_NIST_sha512, CALG_SHA_512, -1 }, + { szOID_ECC_PUBLIC_KEY, CALG_OID_INFO_PARAMETERS }, }; static const struct OIDToAlgID algIDToOID[] = { @@ -509,6 +510,7 @@ static void test_findOIDInfo(void) { static CHAR oid_rsa_md5[] = szOID_RSA_MD5, oid_sha256[] = szOID_NIST_sha256; static CHAR oid_ecdsa_sha256[] = szOID_ECDSA_SHA256; + static CHAR oid_ecc_public_key[] = szOID_ECC_PUBLIC_KEY; ALG_ID alg = CALG_SHA1; ALG_ID algs[2] = { CALG_MD5, CALG_RSA_SIGN }; const struct oid_info @@ -573,6 +575,17 @@ static void test_findOIDInfo(void) } else win_skip("Host does not support ECDSA_SHA256, skipping test\n"); + + info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, oid_ecc_public_key, 0); + ok(!!info, "got error %#lx.\n", GetLastError()); + ok(!strcmp(info->pszOID, oid_ecc_public_key), "got %s.\n", info->pszOID); + ok(!wcscmp(info->pwszName, L"ECC"), "got %s.\n", wine_dbgstr_w(info->pwszName)); + ok(info->dwGroupId == CRYPT_PUBKEY_ALG_OID_GROUP_ID, "got %lu.\n", info->dwGroupId); + ok(U(*info).Algid == CALG_OID_INFO_PARAMETERS, "got %d.\n", U(*info).Algid); + ok(!info->ExtraInfo.cbData, "got %ld.\n", info->ExtraInfo.cbData); + ok(!wcscmp(info->pwszCNGAlgid, CRYPT_OID_INFO_ECC_PARAMETERS_ALGORITHM), "got %s.\n", wine_dbgstr_w(info->pwszCNGAlgid)); + ok(info->pwszCNGExtraAlgid && !wcscmp(info->pwszCNGExtraAlgid, L""), "got %s.\n", + wine_dbgstr_w(info->pwszCNGExtraAlgid)); } static void test_registerOIDInfo(void) From 4f7d25944fb44e8470f4042d054a1a144dff9789 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 29 Jun 2023 11:45:00 -0600 Subject: [PATCH 1535/2777] crypt32: Factor out extract_hash() helper. (cherry picked from commit 6b8cf4dcd355487e39b0cb6d985136b460439f8e) CW-Bug-Id: #22376 --- dlls/crypt32/msg.c | 63 +++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/dlls/crypt32/msg.c b/dlls/crypt32/msg.c index 63884d0c275..de5730bc064 100644 --- a/dlls/crypt32/msg.c +++ b/dlls/crypt32/msg.c @@ -43,6 +43,24 @@ typedef BOOL (*CryptMsgUpdateFunc)(HCRYPTMSG hCryptMsg, const BYTE *pbData, typedef BOOL (*CryptMsgControlFunc)(HCRYPTMSG hCryptMsg, DWORD dwFlags, DWORD dwCtrlType, const void *pvCtrlPara); +static BOOL extract_hash(HCRYPTHASH hash, BYTE **data, DWORD *size) +{ + DWORD sz; + + *data = NULL; + sz = sizeof(*size); + if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *)size, &sz, 0)) return FALSE; + if (!(*data = CryptMemAlloc(*size))) + { + ERR("No memory.\n"); + return FALSE; + } + if (CryptGetHashParam(hash, HP_HASHVAL, *data, size, 0)) return TRUE; + CryptMemFree(*data); + *data = NULL; + return FALSE; +} + static BOOL CRYPT_DefaultMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags, DWORD dwCtrlType, const void *pvCtrlPara) { @@ -412,18 +430,7 @@ static BOOL CRYPT_EncodePKCSDigestedData(CHashEncodeMsg *msg, void *pvData, &digestedData.ContentInfo.Content.cbData); } if (msg->base.state == MsgStateFinalized) - { - size = sizeof(DWORD); - ret = CryptGetHashParam(msg->hash, HP_HASHSIZE, - (LPBYTE)&digestedData.hash.cbData, &size, 0); - if (ret) - { - digestedData.hash.pbData = CryptMemAlloc( - digestedData.hash.cbData); - ret = CryptGetHashParam(msg->hash, HP_HASHVAL, - digestedData.hash.pbData, &digestedData.hash.cbData, 0); - } - } + ret = extract_hash(msg->hash, &digestedData.hash.pbData, &digestedData.hash.cbData); if (ret) ret = CRYPT_AsnEncodePKCSDigestedData(&digestedData, pvData, pcbData); @@ -1025,35 +1032,23 @@ static BOOL CSignedMsgData_AppendMessageDigestAttribute( CSignedMsgData *msg_data, DWORD signerIndex) { BOOL ret; - DWORD size; CRYPT_HASH_BLOB hash = { 0, NULL }, encodedHash = { 0, NULL }; char messageDigest[] = szOID_RSA_messageDigest; CRYPT_ATTRIBUTE messageDigestAttr = { messageDigest, 1, &encodedHash }; - size = sizeof(DWORD); - ret = CryptGetHashParam( - msg_data->signerHandles[signerIndex].contentHash, HP_HASHSIZE, - (LPBYTE)&hash.cbData, &size, 0); + if (!(ret = extract_hash(msg_data->signerHandles[signerIndex].contentHash, &hash.pbData, &hash.cbData))) + return FALSE; + + ret = CRYPT_AsnEncodeOctets(0, NULL, &hash, CRYPT_ENCODE_ALLOC_FLAG, NULL, (LPBYTE)&encodedHash.pbData, + &encodedHash.cbData); if (ret) { - hash.pbData = CryptMemAlloc(hash.cbData); - ret = CryptGetHashParam( - msg_data->signerHandles[signerIndex].contentHash, HP_HASHVAL, - hash.pbData, &hash.cbData, 0); - if (ret) - { - ret = CRYPT_AsnEncodeOctets(0, NULL, &hash, CRYPT_ENCODE_ALLOC_FLAG, - NULL, (LPBYTE)&encodedHash.pbData, &encodedHash.cbData); - if (ret) - { - ret = CRYPT_AppendAttribute( - &msg_data->info->rgSignerInfo[signerIndex].AuthAttrs, - &messageDigestAttr); - LocalFree(encodedHash.pbData); - } - } - CryptMemFree(hash.pbData); + ret = CRYPT_AppendAttribute( + &msg_data->info->rgSignerInfo[signerIndex].AuthAttrs, + &messageDigestAttr); + LocalFree(encodedHash.pbData); } + CryptMemFree(hash.pbData); return ret; } From c92f7533bf4ed39377c05c9d226293bd274287a3 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 29 Jun 2023 11:53:28 -0600 Subject: [PATCH 1536/2777] crypt32: Factor out cng_prepare_signature(). (cherry picked from commit 8436f038621b70778330600c725ba8da08218e9b) CW-Bug-Id: #22376 --- dlls/crypt32/cert.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/dlls/crypt32/cert.c b/dlls/crypt32/cert.c index b9645770ce1..0005d5db14a 100644 --- a/dlls/crypt32/cert.c +++ b/dlls/crypt32/cert.c @@ -2810,7 +2810,18 @@ static BOOL CNG_PrepareSignatureECC(BYTE *encoded_sig, DWORD encoded_size, BYTE return TRUE; } -static BOOL CNG_PrepareSignature(CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert, +static BOOL cng_prepare_signature(const char *alg_oid, BYTE *encoded_sig, DWORD encoded_sig_len, + BYTE **sig_value, DWORD *sig_len) +{ + if (!strcmp(alg_oid, szOID_ECC_PUBLIC_KEY)) + return CNG_PrepareSignatureECC(encoded_sig, encoded_sig_len, sig_value, sig_len); + + FIXME("Unsupported public key type: %s\n", debugstr_a(alg_oid)); + SetLastError(NTE_BAD_ALGID); + return FALSE; +} + +static BOOL CNG_PrepareCertSignature(CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert, BYTE **sig_value, DWORD *sig_len) { BYTE *encoded_sig; @@ -2832,14 +2843,8 @@ static BOOL CNG_PrepareSignature(CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SI for (i = 0; i < signedCert->Signature.cbData; i++) encoded_sig[i] = signedCert->Signature.pbData[signedCert->Signature.cbData - i - 1]; - if (!strcmp(pubKeyInfo->Algorithm.pszObjId, szOID_ECC_PUBLIC_KEY)) - ret = CNG_PrepareSignatureECC(encoded_sig, signedCert->Signature.cbData, sig_value, sig_len); - else - { - FIXME("Unsupported public key type: %s\n", debugstr_a(pubKeyInfo->Algorithm.pszObjId)); - SetLastError(NTE_BAD_ALGID); - } - + ret = cng_prepare_signature(pubKeyInfo->Algorithm.pszObjId, encoded_sig, signedCert->Signature.cbData, + sig_value, sig_len); CryptMemFree(encoded_sig); return ret; } @@ -2859,7 +2864,7 @@ static BOOL CNG_VerifySignature(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodi ret = CNG_CalcHash(info->pwszCNGAlgid, signedCert, &hash_value, &hash_len); if (ret) { - ret = CNG_PrepareSignature(pubKeyInfo, signedCert, &sig_value, &sig_len); + ret = CNG_PrepareCertSignature(pubKeyInfo, signedCert, &sig_value, &sig_len); if (ret) { status = BCryptVerifySignature(key, NULL, hash_value, hash_len, sig_value, sig_len, 0); From 0d0d1f2bc8f9f84154eba09051da40a2a143e1af Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 29 Jun 2023 12:39:33 -0600 Subject: [PATCH 1537/2777] crypt32: Support CNG keys in CDecodeSignedMsg_VerifySignatureWithKey(). (cherry picked from commit 650fe1fd789fd6b72b14eaf9c08a30d6c40f8def) CW-Bug-Id: #22376 --- dlls/crypt32/cert.c | 2 +- dlls/crypt32/crypt32_private.h | 2 ++ dlls/crypt32/msg.c | 42 ++++++++++++++++++++++++++++++---- dlls/crypt32/tests/msg.c | 4 ++-- 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/dlls/crypt32/cert.c b/dlls/crypt32/cert.c index 0005d5db14a..a6fefb30b05 100644 --- a/dlls/crypt32/cert.c +++ b/dlls/crypt32/cert.c @@ -2810,7 +2810,7 @@ static BOOL CNG_PrepareSignatureECC(BYTE *encoded_sig, DWORD encoded_size, BYTE return TRUE; } -static BOOL cng_prepare_signature(const char *alg_oid, BYTE *encoded_sig, DWORD encoded_sig_len, +BOOL cng_prepare_signature(const char *alg_oid, BYTE *encoded_sig, DWORD encoded_sig_len, BYTE **sig_value, DWORD *sig_len) { if (!strcmp(alg_oid, szOID_ECC_PUBLIC_KEY)) diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h index e29249b1136..7d0172f6a29 100644 --- a/dlls/crypt32/crypt32_private.h +++ b/dlls/crypt32/crypt32_private.h @@ -23,6 +23,8 @@ #include "wine/unixlib.h" BOOL CNG_ImportPubKey(CERT_PUBLIC_KEY_INFO *pubKeyInfo, BCRYPT_KEY_HANDLE *key) DECLSPEC_HIDDEN; +BOOL cng_prepare_signature(const char *alg_oid, BYTE *encoded_sig, DWORD encoded_sig_len, + BYTE **sig_value, DWORD *sig_len) DECLSPEC_HIDDEN; /* a few asn.1 tags we need */ #define ASN_BOOL (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01) diff --git a/dlls/crypt32/msg.c b/dlls/crypt32/msg.c index de5730bc064..94642ecfce2 100644 --- a/dlls/crypt32/msg.c +++ b/dlls/crypt32/msg.c @@ -3316,24 +3316,56 @@ static BOOL CDecodeHashMsg_VerifyHash(CDecodeMsg *msg) return ret; } +static BOOL cng_verify_msg_signature(CMSG_CMS_SIGNER_INFO *signer, HCRYPTHASH hash, CERT_PUBLIC_KEY_INFO *key_info) +{ + BYTE *hash_value, *sig_value = NULL; + DWORD hash_len, sig_len; + BCRYPT_KEY_HANDLE key; + BOOL ret = FALSE; + NTSTATUS status; + + if (!CryptImportPublicKeyInfoEx2(X509_ASN_ENCODING, key_info, 0, NULL, &key)) return FALSE; + if (!extract_hash(hash, &hash_value, &hash_len)) goto done; + if (!cng_prepare_signature(key_info->Algorithm.pszObjId, signer->EncryptedHash.pbData, + signer->EncryptedHash.cbData, &sig_value, &sig_len)) goto done; + status = BCryptVerifySignature(key, NULL, hash_value, hash_len, sig_value, sig_len, 0); + if (status) + { + FIXME("Failed to verify signature: %08lx.\n", status); + SetLastError(RtlNtStatusToDosError(status)); + } + ret = !status; +done: + CryptMemFree(sig_value); + CryptMemFree(hash_value); + BCryptDestroyKey(key); + return ret; +} + static BOOL CDecodeSignedMsg_VerifySignatureWithKey(CDecodeMsg *msg, HCRYPTPROV prov, DWORD signerIndex, PCERT_PUBLIC_KEY_INFO keyInfo) { + HCRYPTHASH hash; HCRYPTKEY key; BOOL ret; + ALG_ID alg_id = 0; + + if (msg->u.signed_data.info->rgSignerInfo[signerIndex].AuthAttrs.cAttr) + hash = msg->u.signed_data.signerHandles[signerIndex].authAttrHash; + else + hash = msg->u.signed_data.signerHandles[signerIndex].contentHash; + + if (keyInfo->Algorithm.pszObjId) alg_id = CertOIDToAlgId(keyInfo->Algorithm.pszObjId); + if (alg_id == CALG_OID_INFO_PARAMETERS || alg_id == CALG_OID_INFO_CNG_ONLY) + return cng_verify_msg_signature(&msg->u.signed_data.info->rgSignerInfo[signerIndex], hash, keyInfo); if (!prov) prov = msg->crypt_prov; ret = CryptImportPublicKeyInfo(prov, X509_ASN_ENCODING, keyInfo, &key); if (ret) { - HCRYPTHASH hash; CRYPT_HASH_BLOB reversedHash; - if (msg->u.signed_data.info->rgSignerInfo[signerIndex].AuthAttrs.cAttr) - hash = msg->u.signed_data.signerHandles[signerIndex].authAttrHash; - else - hash = msg->u.signed_data.signerHandles[signerIndex].contentHash; ret = CRYPT_ConstructBlob(&reversedHash, &msg->u.signed_data.info->rgSignerInfo[signerIndex].EncryptedHash); if (ret) diff --git a/dlls/crypt32/tests/msg.c b/dlls/crypt32/tests/msg.c index c663909ed7c..d8ac7f75d78 100644 --- a/dlls/crypt32/tests/msg.c +++ b/dlls/crypt32/tests/msg.c @@ -3608,12 +3608,12 @@ static void test_verify_ecc_signature(void) BCryptDestroyKey(bkey); bret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE, cert->pCertInfo); - todo_wine ok(bret, "failed, error %#lx.\n", GetLastError()); + ok(bret, "failed, error %#lx.\n", GetLastError()); verify_para.dwSignerType = CMSG_VERIFY_SIGNER_CERT; verify_para.pvSigner = (void *)cert; bret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_SIGNATURE_EX, &verify_para); - todo_wine ok(bret, "failed, error %#lx.\n", GetLastError()); + ok(bret, "failed, error %#lx.\n", GetLastError()); free(signer_info); free(cert_info); From c8a1164869334f971084eed3a1e240f9c88ebb37 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 3 Aug 2023 13:38:37 -0600 Subject: [PATCH 1538/2777] winex11.drv: Override GL vendor for Paradox Launcher. CW-Bug-Id: #22492 --- dlls/winex11.drv/opengl.c | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index b5fd4788291..4ec0529c75a 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -37,6 +37,8 @@ #ifdef HAVE_SYS_UN_H #include #endif +#include +#include #include "x11drv.h" #include "xcomposite.h" @@ -3348,6 +3350,52 @@ static void wglFlush(void) static const GLubyte *wglGetString(GLenum name) { + static int override_vendor = -1; + if (override_vendor == -1) + { + int fd; + char buffer[4096], *env; + int sz; + + override_vendor = 0; + if ((env = getenv("WINE_GL_HIDE_NVIDIA"))) + { + override_vendor = env[0] != '0'; + } + else + { + fd = open("/proc/self/cmdline", O_RDONLY); + if (fd != -1) + { + if ((sz = read(fd, buffer, sizeof(buffer) - 1)) > 0) + { + buffer[sz] = 0; + if (strstr(buffer, "\\Paradox Launcher.exe")) + { + FIXME("HACK: overriding GL vendor and renderer.\n"); + override_vendor = 1; + } + } + close(fd); + } + } + } + if (override_vendor) + { + const GLubyte *s; + if (name == GL_RENDERER) + { + s = pglGetString(name); + if (s && strstr((const char *)s, "NVIDIA")) return (const GLubyte *)"AMD Radeon Graphics"; + return s; + } + else if (name == GL_VENDOR) + { + s = pglGetString(name); + if (s && strstr((const char *)s, "NVIDIA")) return (const GLubyte *)"AMD"; + return s; + } + } if (name == GL_EXTENSIONS && glExtensions) return (const GLubyte *)glExtensions; return pglGetString(name); } From 7a8eb2cd72f2db7a5e669c765401c785549aa12c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 14 Aug 2023 15:38:49 -0600 Subject: [PATCH 1539/2777] winex11.drv: Fix buffer allocation size in import_xdnd_selection(). Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55443 (cherry picked from commit af3014b3e1a7684c7934b807906baf93d7562bc4) CW-Bug-Id: #22600 --- dlls/winex11.drv/clipboard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/clipboard.c b/dlls/winex11.drv/clipboard.c index 327e74d73dd..5b426f52df5 100644 --- a/dlls/winex11.drv/clipboard.c +++ b/dlls/winex11.drv/clipboard.c @@ -1308,7 +1308,7 @@ struct format_entry *import_xdnd_selection( Display *display, Window win, Atom s if (!(data = import_selection( display, win, selection, format, &size ))) continue; entry_size = (FIELD_OFFSET( struct format_entry, data[size] ) + 7) & ~7; - if (buf_size < size + entry_size) + if (buf_size < *ret_size + entry_size) { if (!(ret = realloc( ret, *ret_size + entry_size + 1024 ))) continue; buf_size = *ret_size + entry_size + 1024; /* extra space for following entries */ From 031a0306292b5caa460da42b0fa921edc2c316b4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 16 Aug 2023 20:22:01 -0600 Subject: [PATCH 1540/2777] winex11.drv: Release old drawables after setting new ones in sync_context(). (cherry picked from commit a743f085df51120a6baa0543d48ca5d1f915afcc) CW-Bug-Id: #22608 --- dlls/winex11.drv/opengl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 4ec0529c75a..d75128f6e27 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1361,18 +1361,19 @@ static void mark_drawable_dirty( struct gl_drawable *old, struct gl_drawable *ne static inline void sync_context(struct wgl_context *context) { BOOL refresh = FALSE; + struct gl_drawable *old[2] = { NULL }; pthread_mutex_lock( &context_mutex ); if (context->new_drawables[0]) { - release_gl_drawable( context->drawables[0] ); + old[0] = context->drawables[0]; context->drawables[0] = context->new_drawables[0]; context->new_drawables[0] = NULL; refresh = TRUE; } if (context->new_drawables[1]) { - release_gl_drawable( context->drawables[1] ); + old[1] = context->drawables[1]; context->drawables[1] = context->new_drawables[1]; context->new_drawables[1] = NULL; refresh = TRUE; @@ -1384,6 +1385,8 @@ static inline void sync_context(struct wgl_context *context) context->drawables[1]->drawable, context->ctx); else pglXMakeCurrent(gdi_display, context->drawables[0]->drawable, context->ctx); + release_gl_drawable( old[0] ); + release_gl_drawable( old[1] ); } pthread_mutex_unlock( &context_mutex ); } From baf7b445cadb21fdac2a4c221a795838d18abe28 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 17 Aug 2023 19:28:17 -0600 Subject: [PATCH 1541/2777] winex11.drv: fshack: Sync GL drawable outside of win data lock in X11DRV_WindowPosChanged(). CW-Bug-Id: #22608 --- dlls/winex11.drv/window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 36bc1d58302..8c55367e4ad 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -3256,7 +3256,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, set_hwnd_style_props( data->display, data->whole_window, data->hwnd ); - if (data->fs_hack) sync_gl_drawable( hwnd, FALSE ); + if (data->fs_hack) needs_resize = TRUE; /* check if we are currently processing an event relevant to this window */ event_type = 0; From 66e33d1b2cc361770dd70ea233a0e570c4a4bb63 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 17 Aug 2023 17:32:41 -0600 Subject: [PATCH 1542/2777] fixup! winex11.drv: Sync parent's GL drawable when child window is destroyed. CW-Bug-Id: #22608 --- dlls/winex11.drv/opengl.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index d75128f6e27..97f3d66db95 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1476,6 +1476,11 @@ static enum dc_gl_layered_type get_gl_layered_type( HWND hwnd ) return ret; } +static BOOL drawable_needs_clipping( HWND hwnd, BOOL known_child ) +{ + if (known_child) return TRUE; + return NtUserGetWindowRelative( hwnd, GW_CHILD ) || NtUserGetAncestor( hwnd, GA_PARENT ) != NtUserGetDesktopWindow(); +} /*********************************************************************** * create_gl_drawable @@ -1520,8 +1525,7 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel } TRACE( "%p created pixmap drawable %lx for layered window, type %u.\n", hwnd, gl->drawable, gl->layered_type ); } - else if (!known_child && !NtUserGetWindowRelative( hwnd, GW_CHILD ) && - NtUserGetAncestor( hwnd, GA_PARENT ) == NtUserGetDesktopWindow()) /* childless top-level window */ + else if (!drawable_needs_clipping( hwnd, known_child )) /* childless top-level window */ { struct x11drv_win_data *data; @@ -1666,6 +1670,9 @@ void sync_gl_drawable( HWND hwnd, BOOL known_child ) if (!(old = get_gl_drawable( hwnd, 0 ))) return; new_layered_type = get_gl_layered_type( hwnd ); + + known_child = drawable_needs_clipping( hwnd, known_child ); + if (old->type == DC_GL_PIXMAP_WIN || (known_child && old->type == DC_GL_WINDOW) || (!known_child && old->type != DC_GL_WINDOW) || old->layered_type != new_layered_type) From 475809142da7bfcc6e71eb55295ccff0e1ec4ff7 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 17 Aug 2023 19:57:51 -0600 Subject: [PATCH 1543/2777] fixup! fshack: winex11: Use window dimensions in GL if fshack is enabled for gamma only. CW-Bug-Id: #22608 --- dlls/winex11.drv/opengl.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 97f3d66db95..bf15a3ab37f 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2999,6 +2999,8 @@ static void fs_hack_blit_framebuffer( struct gl_drawable *gl, GLenum draw_buffer POINT scaled_origin; HMONITOR monitor; struct fs_hack_gl_state state; + struct x11drv_win_data *data; + BOOL window_fs_hack = FALSE; const float *gamma_ramp; LONG gamma_serial; unsigned int i; @@ -3007,7 +3009,13 @@ static void fs_hack_blit_framebuffer( struct gl_drawable *gl, GLenum draw_buffer hwnd = NtUserWindowFromDC( ctx->hdc ); monitor = fs_hack_monitor_from_hwnd( hwnd ); - if (fs_hack_enabled( monitor )) + if ((data = get_win_data( hwnd ))) + { + window_fs_hack = data->fs_hack; + release_win_data( data ); + } + + if (window_fs_hack) { user_rect = fs_hack_current_mode( monitor ); real_rect = fs_hack_real_mode( monitor ); From 8f21a825471aff53027345143b171d6ab336cb48 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 17 Aug 2023 19:22:27 -0600 Subject: [PATCH 1544/2777] winex11.drv: fshack/GL: Support fshack on offscreen drawables. CW-Bug-Id: #22608 --- dlls/winex11.drv/opengl.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index bf15a3ab37f..c29792b62ad 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1542,6 +1542,8 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel #ifdef SONAME_LIBXCOMPOSITE else if(usexcomposite) { + struct x11drv_win_data *data; + gl->type = DC_GL_CHILD_WIN; gl->window = create_client_window( hwnd, visual ); if (gl->window) @@ -1549,6 +1551,10 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel gl->drawable = pglXCreateWindow( gdi_display, gl->format->fbconfig, gl->window, NULL ); pXCompositeRedirectWindow( gdi_display, gl->window, CompositeRedirectManual ); } + data = get_win_data( hwnd ); + gl->fs_hack = data->fs_hack || fs_hack_get_gamma_ramp( NULL ); + if (gl->fs_hack) TRACE( "Window %p has the fullscreen hack enabled\n", hwnd ); + release_win_data( data ); TRACE( "%p created child %lx drawable %lx\n", hwnd, gl->window, gl->drawable ); } #endif @@ -3033,11 +3039,20 @@ static void fs_hack_blit_framebuffer( struct gl_drawable *gl, GLenum draw_buffer src.cy = user_rect.bottom - user_rect.top; real.cx = real_rect.right - real_rect.left; real.cy = real_rect.bottom - real_rect.top; - scaled_origin.x = user_rect.left; - scaled_origin.y = user_rect.top; - fs_hack_point_user_to_real( &scaled_origin ); - scaled_origin.x -= real_rect.left; - scaled_origin.y -= real_rect.top; + if (gl->type != DC_GL_CHILD_WIN) + { + scaled_origin.x = user_rect.left; + scaled_origin.y = user_rect.top; + fs_hack_point_user_to_real( &scaled_origin ); + scaled_origin.x -= real_rect.left; + scaled_origin.y -= real_rect.top; + } + else + { + /* ExtEscape performs the fshack offset. */ + scaled_origin.x = 0; + scaled_origin.y = 0; + } gamma_ramp = fs_hack_get_gamma_ramp( &gamma_serial ); @@ -4798,12 +4813,6 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) if (gl->type == DC_GL_CHILD_WIN) escape.drawable = gl->window; /* fall through */ default: - if (escape.drawable && pglXSwapBuffersMscOML) - { - pglFlush(); - target_sbc = pglXSwapBuffersMscOML( gdi_display, gl->drawable, 0, 0, 0 ); - break; - } if (gl->fs_hack) { ctx->fs_hack = gl->fs_hack; @@ -4816,6 +4825,12 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) ctx->fs_hack = FALSE; fs_hack_setup_context( ctx, gl ); } + if (escape.drawable && pglXSwapBuffersMscOML) + { + pglFlush(); + target_sbc = pglXSwapBuffersMscOML( gdi_display, gl->drawable, 0, 0, 0 ); + break; + } pglXSwapBuffers(gdi_display, gl->drawable); break; } From e576e22c069fa7896a663fba79bce742451040ef Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 17 Aug 2023 14:36:39 -0600 Subject: [PATCH 1545/2777] winex11.drv: fshack/GL: Always blit fs_hack in wglFlush and wglFinish when drawing to front buffer. CW-Bug-Id: #22608 --- dlls/winex11.drv/opengl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index c29792b62ad..5ea90beefdd 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -221,6 +221,7 @@ struct wgl_context GLuint fs_hack_gamma_pgm, ramp_ubo; POINT setup_for; GLuint current_draw_fbo, current_read_fbo; + BOOL drawing_to_front; struct list entry; }; @@ -2710,6 +2711,9 @@ static void wglDrawBuffer( GLenum buffer ) { struct wgl_context *ctx = NtCurrentTeb()->glContext; + TRACE( "buffer %#x.\n", buffer ); + + ctx->drawing_to_front = (buffer == GL_FRONT); if (ctx->fs_hack && ctx->current_draw_fbo == ctx->fs_hack_fbo) { TRACE( "Overriding %#x with GL_COLOR_ATTACHMENT0\n", buffer ); @@ -3324,7 +3328,7 @@ static void wglFinish(void) { ctx->fs_hack = gl->fs_hack; if (!gl->fs_hack_context_set_up) fs_hack_setup_context( ctx, gl ); - if (!gl->fs_hack_did_swapbuf) fs_hack_blit_framebuffer( gl, GL_FRONT ); + if (!gl->fs_hack_did_swapbuf || ctx->drawing_to_front) fs_hack_blit_framebuffer( gl, GL_FRONT ); } else if (gl->fs_hack_context_set_up) { @@ -3365,7 +3369,7 @@ static void wglFlush(void) { ctx->fs_hack = gl->fs_hack; if (!gl->fs_hack_context_set_up) fs_hack_setup_context( ctx, gl ); - if (!gl->fs_hack_did_swapbuf) fs_hack_blit_framebuffer( gl, GL_FRONT ); + if (!gl->fs_hack_did_swapbuf || ctx->drawing_to_front) fs_hack_blit_framebuffer( gl, GL_FRONT ); } else if (gl->fs_hack_context_set_up) { From 9694fe66017c31cf12e6cd286be694b2168dd9df Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 3 May 2023 23:02:58 +0300 Subject: [PATCH 1546/2777] fshack: Resolve fbo for glCopyTexSubImage2D. Based on a patch by Illia Polishchuk from https://github.com/ValveSoftware/wine/pull/189 GL_INVALID_OPERATION is generated if: the effective value of GL_SAMPLE_BUFFERS for the read framebuffer is one. CW-Bug-Id: #22662 --- dlls/winex11.drv/opengl.c | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 5ea90beefdd..2ec985c279e 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -222,6 +222,7 @@ struct wgl_context POINT setup_for; GLuint current_draw_fbo, current_read_fbo; BOOL drawing_to_front; + BOOL fs_hack_needs_resolve; struct list entry; }; @@ -478,11 +479,13 @@ static void (*pglUseProgram)( GLuint program ); static void (*pglViewportIndexedf)( GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h ); static void (*pglViewportIndexedfv)( GLuint index, const GLfloat *v ); static void (*pglGetFramebufferAttachmentParameteriv)( GLenum target, GLenum attachment, GLenum pname, GLint *params ); +static void (*pglCopyTexSubImage2D)( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ); static void wglBindFramebuffer( GLenum target, GLuint framebuffer ); static void wglBindFramebufferEXT( GLenum target, GLuint framebuffer ); static void wglDrawBuffer( GLenum buffer ); static void wglReadBuffer( GLenum src ); static void wglFramebufferTexture2D( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ); +static void wglCopyTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ); /* check if the extension is present in the list */ static BOOL has_extension( const char *list, const char *ext ) @@ -664,6 +667,7 @@ static void init_opengl(void) REDIRECT( glFlush ); REDIRECT( glGetString ); REDIRECT( glReadBuffer ); + REDIRECT( glCopyTexSubImage2D ); #undef REDIRECT pglXGetProcAddressARB = dlsym(opengl_handle, "glXGetProcAddressARB"); @@ -2580,6 +2584,7 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * gl->has_vertex_program = !ctx->is_core && has_extension( glExtensions, "GL_ARB_vertex_program" ); ctx->fs_hack_integer = fs_hack_is_integer(); + ctx->fs_hack_needs_resolve = gl->fs_hack_needs_resolve; gl->fs_hack_context_set_up = TRUE; } else @@ -2734,6 +2739,49 @@ static void wglReadBuffer( GLenum buffer ) pglReadBuffer( buffer ); } +static BOOL resolve_fs_hack_fbo( GLuint *old_read_fbo ) +{ + struct wgl_context *ctx = NtCurrentTeb()->glContext; + GLuint old_draw_fbo; + unsigned int cx, cy; + RECT user_rect; + HWND hwnd; + + if (!ctx || !ctx->fs_hack || !ctx->fs_hack_needs_resolve) return FALSE; + if (!ctx->fs_hack_needs_resolve) return FALSE; + if (ctx->current_read_fbo != ctx->fs_hack_fbo) return FALSE; + if (!(hwnd = NtUserWindowFromDC( ctx->hdc ))) return FALSE; + + NtUserGetClientRect( hwnd, &user_rect ); + cx = user_rect.right - user_rect.left; + cy = user_rect.bottom - user_rect.top; + + TRACE( "resolving fbo, %ux%u.\n", cx, cy ); + + opengl_funcs.gl.p_glGetIntegerv( GL_READ_FRAMEBUFFER_BINDING, (GLint *)old_read_fbo ); + opengl_funcs.gl.p_glGetIntegerv( GL_READ_FRAMEBUFFER_BINDING, (GLint *)&old_draw_fbo ); + + pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_resolve_fbo ); + pglBlitFramebuffer( 0, 0, cx, cy, 0, 0, cx, cy, GL_COLOR_BUFFER_BIT, GL_NEAREST ); + pglBindFramebuffer( GL_READ_FRAMEBUFFER, ctx->fs_hack_resolve_fbo ); + pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, old_draw_fbo ); + + return TRUE; +} + +static void wglCopyTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ) +{ + GLuint old_read_fbo; + BOOL restore; + + TRACE( "target %#x, level %d, offset %dx%d, origin %dx%d, size %dx%d.\n", + target, level, xoffset, yoffset, x, y, width, height ); + + restore = resolve_fs_hack_fbo( &old_read_fbo ); + pglCopyTexSubImage2D( target, level, xoffset, yoffset, x, y, width, height ); + if (restore) pglBindFramebuffer( GL_READ_FRAMEBUFFER, old_read_fbo ); +} + struct fs_hack_gl_state { GLuint draw_fbo; From 07d164ab296702c09181af5f810be809fc0d5dee Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 28 Aug 2023 18:10:10 -0600 Subject: [PATCH 1547/2777] fshack: Resolve fbo for glCopyTexImage2D. CW-Bug-Id: #22662 --- dlls/winex11.drv/opengl.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 2ec985c279e..d15661a36ec 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -479,12 +479,14 @@ static void (*pglUseProgram)( GLuint program ); static void (*pglViewportIndexedf)( GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h ); static void (*pglViewportIndexedfv)( GLuint index, const GLfloat *v ); static void (*pglGetFramebufferAttachmentParameteriv)( GLenum target, GLenum attachment, GLenum pname, GLint *params ); +static void (*pglCopyTexImage2D)( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ); static void (*pglCopyTexSubImage2D)( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ); static void wglBindFramebuffer( GLenum target, GLuint framebuffer ); static void wglBindFramebufferEXT( GLenum target, GLuint framebuffer ); static void wglDrawBuffer( GLenum buffer ); static void wglReadBuffer( GLenum src ); static void wglFramebufferTexture2D( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ); +static void wglCopyTexImage2D( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ); static void wglCopyTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ); /* check if the extension is present in the list */ @@ -668,6 +670,7 @@ static void init_opengl(void) REDIRECT( glGetString ); REDIRECT( glReadBuffer ); REDIRECT( glCopyTexSubImage2D ); + REDIRECT( glCopyTexImage2D ); #undef REDIRECT pglXGetProcAddressARB = dlsym(opengl_handle, "glXGetProcAddressARB"); @@ -2782,6 +2785,19 @@ static void wglCopyTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLi if (restore) pglBindFramebuffer( GL_READ_FRAMEBUFFER, old_read_fbo ); } +static void wglCopyTexImage2D( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ) +{ + GLuint old_read_fbo; + BOOL restore; + + TRACE( "target %#x, level %d, internalformat %#x, origin %dx%d, size %dx%d, border %d.\n", + target, level, internalformat, x, y, width, height, border ); + + restore = resolve_fs_hack_fbo( &old_read_fbo ); + pglCopyTexImage2D( target, level, internalformat, x, y, width, height, border ); + if (restore) pglBindFramebuffer( GL_READ_FRAMEBUFFER, old_read_fbo ); +} + struct fs_hack_gl_state { GLuint draw_fbo; From 226012d02b9d8bdd40692c0bf1f7548da67f86e9 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 28 Aug 2023 18:19:47 -0600 Subject: [PATCH 1548/2777] fshack: Resolve fbo for glReadPixels. CW-Bug-Id: #22662 --- 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 d15661a36ec..3cf88a7d4bc 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -481,6 +481,7 @@ static void (*pglViewportIndexedfv)( GLuint index, const GLfloat *v ); static void (*pglGetFramebufferAttachmentParameteriv)( GLenum target, GLenum attachment, GLenum pname, GLint *params ); static void (*pglCopyTexImage2D)( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ); static void (*pglCopyTexSubImage2D)( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ); +static void (*pglReadPixels)( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * data); static void wglBindFramebuffer( GLenum target, GLuint framebuffer ); static void wglBindFramebufferEXT( GLenum target, GLuint framebuffer ); static void wglDrawBuffer( GLenum buffer ); @@ -488,6 +489,7 @@ static void wglReadBuffer( GLenum src ); static void wglFramebufferTexture2D( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ); static void wglCopyTexImage2D( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border ); static void wglCopyTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height ); +static void wglReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * data); /* check if the extension is present in the list */ static BOOL has_extension( const char *list, const char *ext ) @@ -671,6 +673,7 @@ static void init_opengl(void) REDIRECT( glReadBuffer ); REDIRECT( glCopyTexSubImage2D ); REDIRECT( glCopyTexImage2D ); + REDIRECT( glReadPixels ); #undef REDIRECT pglXGetProcAddressARB = dlsym(opengl_handle, "glXGetProcAddressARB"); @@ -2798,6 +2801,18 @@ static void wglCopyTexImage2D( GLenum target, GLint level, GLenum internalformat if (restore) pglBindFramebuffer( GL_READ_FRAMEBUFFER, old_read_fbo ); } +static void wglReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * data) +{ + GLuint old_read_fbo; + BOOL restore; + + TRACE( "origin %dx%d, size %dx%d, format %#x, type %#x, data %p.\n", x, y, width, height, format, type, data ); + + restore = resolve_fs_hack_fbo( &old_read_fbo ); + pglReadPixels( x, y, width, height, format, type, data ); + if (restore) pglBindFramebuffer( GL_READ_FRAMEBUFFER, old_read_fbo ); +} + struct fs_hack_gl_state { GLuint draw_fbo; From 2a405df65496ccc02684f48af60cb0c16bb839a7 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 24 Jul 2023 19:38:56 -0600 Subject: [PATCH 1549/2777] nsiproxy.sys: Detect wireless interface type on Linux. (cherry picked from commit 7b243afc6322fa82ac42cec6de247a642e16b5a5) CW-Bug-Id: #22496 --- configure.ac | 1 + dlls/nsiproxy.sys/ndis.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/configure.ac b/configure.ac index 91ac8a9485f..5f6138f68e0 100644 --- a/configure.ac +++ b/configure.ac @@ -431,6 +431,7 @@ AC_CHECK_HEADERS(\ linux/serial.h \ linux/types.h \ linux/ucdrom.h \ + linux/wireless.h \ lwp.h \ mach-o/loader.h \ mach/mach.h \ diff --git a/dlls/nsiproxy.sys/ndis.c b/dlls/nsiproxy.sys/ndis.c index 1fc66c3611b..9d53c1591f6 100644 --- a/dlls/nsiproxy.sys/ndis.c +++ b/dlls/nsiproxy.sys/ndis.c @@ -62,6 +62,10 @@ #include #endif +#ifdef HAVE_LINUX_WIRELESS_H +#include +#endif + #include #define NONAMELESSUNION @@ -173,6 +177,21 @@ static NTSTATUS if_get_physical( const char *name, UINT *type, IF_PHYSICAL_ADDRE if (*type == MIB_IF_TYPE_OTHER && !ioctl( fd, SIOCGIFFLAGS, &ifr ) && ifr.ifr_flags & IFF_POINTOPOINT) *type = MIB_IF_TYPE_PPP; +#ifdef HAVE_LINUX_WIRELESS_H + if (*type == MIB_IF_TYPE_ETHERNET) + { + struct iwreq pwrq; + + memset( &pwrq, 0, sizeof(pwrq) ); + memcpy( pwrq.ifr_name, name, size ); + if (ioctl( fd, SIOCGIWNAME, &pwrq ) != -1) + { + TRACE( "iface %s, wireless protocol %s.\n", debugstr_a(name), debugstr_a(pwrq.u.name) ); + *type = IF_TYPE_IEEE80211; + } + } +#endif + err: close( fd ); return ret; From cb0f2df7c31892a008f1d6af19f5539b9a94938f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 9 Aug 2023 16:05:55 -0600 Subject: [PATCH 1550/2777] nsiproxy.sys: HACK: Add an option to fake eth adapter presence. CW-Bug-Id: #22580 --- dlls/nsiproxy.sys/ndis.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/dlls/nsiproxy.sys/ndis.c b/dlls/nsiproxy.sys/ndis.c index 9d53c1591f6..73c047586a9 100644 --- a/dlls/nsiproxy.sys/ndis.c +++ b/dlls/nsiproxy.sys/ndis.c @@ -106,6 +106,8 @@ struct if_entry static struct list if_list = LIST_INIT( if_list ); static pthread_mutex_t if_list_lock = PTHREAD_MUTEX_INITIALIZER; +static BOOL have_ethernet_iface; + static struct if_entry *find_entry_from_index( UINT index ) { struct if_entry *entry; @@ -276,7 +278,22 @@ static WCHAR *strdupAtoW( const char *str ) return ret; } -static struct if_entry *add_entry( UINT index, char *name ) +static int fake_ethernet_adapter(void) +{ + static int cached = -1; + + if (cached == -1) + { + const char *s; + if ((s = getenv( "WINE_FAKE_ETH_PRESENCE" ))) + cached = atoi( s ); + else + cached = (s = getenv( "SteamGameId" )) && !strcmp( s, "1293830" ); + } + return cached; +} + +static struct if_entry *add_entry( UINT index, const char *name ) { struct if_entry *entry; int name_len = strlen( name ); @@ -305,6 +322,10 @@ static struct if_entry *add_entry( UINT index, char *name ) memcpy( entry->if_guid.Data4 + 2, "NetDev", 6 ); list_add_tail( &if_list, &entry->entry ); + + if (entry->if_luid.Info.IfType == MIB_IF_TYPE_ETHERNET) + have_ethernet_iface = TRUE; + return entry; } @@ -312,6 +333,7 @@ static unsigned int update_if_table( void ) { struct if_nameindex *indices = if_nameindex(), *entry; unsigned int append_count = 0; + struct if_entry *if_entry; for (entry = indices; entry->if_index; entry++) { @@ -320,6 +342,14 @@ static unsigned int update_if_table( void ) } if_freenameindex( indices ); + + if (!have_ethernet_iface && fake_ethernet_adapter() && (if_entry = add_entry( 0xdeadbeef, "eth0faked" ))) + { + if_entry->if_type = if_entry->if_luid.Info.IfType = MIB_IF_TYPE_ETHERNET; + have_ethernet_iface = TRUE; + ++append_count; + } + return append_count; } From 10c378b04089eaa6c4230f19aab1c2e9af4f47e2 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 25 Jul 2023 17:37:12 -0600 Subject: [PATCH 1551/2777] nsi: Add stubs for NsiRequestChangeNotification[Ex]. (cherry picked from commit 671412d3bb45f0fa639aefc031b523aa2edac3e8) CW-Bug-Id: #22496 --- dlls/nsi/nsi.c | 22 ++++++++++++++++++++++ dlls/nsi/nsi.spec | 4 ++-- include/wine/nsi.h | 12 ++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/dlls/nsi/nsi.c b/dlls/nsi/nsi.c index 3f324ef555b..e20aa6ef21a 100644 --- a/dlls/nsi/nsi.c +++ b/dlls/nsi/nsi.c @@ -307,3 +307,25 @@ DWORD WINAPI NsiGetParameterEx( struct nsi_get_parameter_ex *params ) CloseHandle( device ); return err; } + +DWORD WINAPI NsiRequestChangeNotification( DWORD unk, const NPI_MODULEID *module, DWORD table, OVERLAPPED *ovr, + HANDLE *handle ) +{ + struct nsi_request_change_notification_ex params; + + TRACE( "%lu %p %lu %p %p stub.\n", unk, module, table, ovr, handle ); + + params.unk = unk; + params.module = module; + params.table = table; + params.ovr = ovr; + params.handle = handle; + return NsiRequestChangeNotificationEx( ¶ms ); +} + +DWORD WINAPI NsiRequestChangeNotificationEx( struct nsi_request_change_notification_ex *params ) +{ + FIXME( "%p stub.\n", params ); + + return ERROR_NOT_SUPPORTED; +} diff --git a/dlls/nsi/nsi.spec b/dlls/nsi/nsi.spec index ba326572fb8..b343b228b9c 100644 --- a/dlls/nsi/nsi.spec +++ b/dlls/nsi/nsi.spec @@ -16,8 +16,8 @@ @ stdcall NsiGetParameterEx(ptr) @ stub NsiRegisterChangeNotification @ stub NsiRegisterChangeNotificationEx -@ stub NsiRequestChangeNotification -@ stub NsiRequestChangeNotificationEx +@ stdcall NsiRequestChangeNotification(long ptr long ptr ptr) +@ stdcall NsiRequestChangeNotificationEx(ptr) @ stub NsiSetAllParameters @ stub NsiSetAllParametersEx @ stub NsiSetAllPersistentParametersWithMask diff --git a/include/wine/nsi.h b/include/wine/nsi.h index af35593b29c..2f9fb0cb6e3 100644 --- a/include/wine/nsi.h +++ b/include/wine/nsi.h @@ -492,6 +492,15 @@ struct nsi_get_parameter_ex UINT data_offset; }; +struct nsi_request_change_notification_ex +{ + DWORD unk; + const NPI_MODULEID *module; + UINT_PTR table; + OVERLAPPED *ovr; + HANDLE *handle; +}; + DWORD WINAPI NsiAllocateAndGetTable( DWORD unk, const NPI_MODULEID *module, DWORD table, void **key_data, DWORD key_size, void **rw_data, DWORD rw_size, void **dynamic_data, DWORD dynamic_size, void **static_data, DWORD static_size, DWORD *count, DWORD unk2 ); @@ -508,5 +517,8 @@ DWORD WINAPI NsiGetAllParametersEx( struct nsi_get_all_parameters_ex *params ); DWORD WINAPI NsiGetParameter( DWORD unk, const NPI_MODULEID *module, DWORD table, const void *key, DWORD key_size, DWORD param_type, void *data, DWORD data_size, DWORD data_offset ); DWORD WINAPI NsiGetParameterEx( struct nsi_get_parameter_ex *params ); +DWORD WINAPI NsiRequestChangeNotification( DWORD unk, const NPI_MODULEID *module, DWORD table, OVERLAPPED *ovr, + HANDLE *handle ); +DWORD WINAPI NsiRequestChangeNotificationEx( struct nsi_request_change_notification_ex *params ); #endif /* __WINE_NSI_H */ From 9b842f50780f4318ec30cfaac1fc4fcceb23d712 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 25 Jul 2023 17:39:41 -0600 Subject: [PATCH 1552/2777] nsi: Add stub for NsiCancelChangeNotification. (cherry picked from commit e06093cbae775e165e53f4ea243ad8b9fdf90f5c) CW-Bug-Id: #22496 --- dlls/nsi/nsi.c | 7 +++++++ dlls/nsi/nsi.spec | 2 +- include/wine/nsi.h | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/dlls/nsi/nsi.c b/dlls/nsi/nsi.c index e20aa6ef21a..c00ec4f8684 100644 --- a/dlls/nsi/nsi.c +++ b/dlls/nsi/nsi.c @@ -88,6 +88,13 @@ DWORD WINAPI NsiAllocateAndGetTable( DWORD unk, const NPI_MODULEID *module, DWOR return err; } +DWORD WINAPI NsiCancelChangeNotification( OVERLAPPED *ovr ) +{ + FIXME( "%p stub.\n", ovr ); + + return ERROR_NOT_SUPPORTED; +} + DWORD WINAPI NsiEnumerateObjectsAllParameters( DWORD unk, DWORD unk2, const NPI_MODULEID *module, DWORD table, void *key_data, DWORD key_size, void *rw_data, DWORD rw_size, void *dynamic_data, DWORD dynamic_size, void *static_data, DWORD static_size, diff --git a/dlls/nsi/nsi.spec b/dlls/nsi/nsi.spec index b343b228b9c..9f1a2472362 100644 --- a/dlls/nsi/nsi.spec +++ b/dlls/nsi/nsi.spec @@ -1,6 +1,6 @@ @ stub NsiAllocateAndGetPersistentDataWithMaskTable @ stdcall NsiAllocateAndGetTable(long ptr long ptr long ptr long ptr long ptr long ptr long) -@ stub NsiCancelChangeNotification +@ stdcall NsiCancelChangeNotification(ptr) @ stub NsiDeregisterChangeNotification @ stub NsiDeregisterChangeNotificationEx @ stdcall NsiEnumerateObjectsAllParameters(long long ptr long ptr long ptr long ptr long ptr long ptr) diff --git a/include/wine/nsi.h b/include/wine/nsi.h index 2f9fb0cb6e3..1a562c3c36d 100644 --- a/include/wine/nsi.h +++ b/include/wine/nsi.h @@ -504,6 +504,7 @@ struct nsi_request_change_notification_ex DWORD WINAPI NsiAllocateAndGetTable( DWORD unk, const NPI_MODULEID *module, DWORD table, void **key_data, DWORD key_size, void **rw_data, DWORD rw_size, void **dynamic_data, DWORD dynamic_size, void **static_data, DWORD static_size, DWORD *count, DWORD unk2 ); +DWORD WINAPI NsiCancelChangeNotification( OVERLAPPED *ovr ); DWORD WINAPI NsiEnumerateObjectsAllParameters( DWORD unk, DWORD unk2, const NPI_MODULEID *module, DWORD table, void *key_data, DWORD key_size, void *rw_data, DWORD rw_size, void *dynamic_data, DWORD dynamic_size, void *static_data, DWORD static_size, From a4e26c9553c2345f6879604ead396d67f5046c87 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 25 Jul 2023 17:35:08 -0600 Subject: [PATCH 1553/2777] nsi/tests: Add test for change notifications. (cherry picked from commit 64c6819553b0bdb3f0a415558b833a07915999e0) CW-Bug-Id: #22496 --- dlls/nsi/tests/nsi.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/dlls/nsi/tests/nsi.c b/dlls/nsi/tests/nsi.c index 4cf49993ea1..5b3a6775992 100644 --- a/dlls/nsi/tests/nsi.c +++ b/dlls/nsi/tests/nsi.c @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "winsock2.h" #include "winternl.h" #include "ws2ipdef.h" @@ -1023,6 +1025,66 @@ static void test_udp_tables( int family ) winetest_pop_context(); } +void test_change_notifications(void) +{ + struct nsi_request_change_notification_ex params; + HANDLE handle, handle2; + OVERLAPPED ovr, ovr2; + DWORD bytes; + DWORD ret; + BOOL bret; + + memset( &ovr, 0, sizeof(ovr) ); + ovr.hEvent = CreateEventW( NULL, FALSE, FALSE, NULL ); + + handle = (HANDLE)0xdeadbeef; + ret = NsiRequestChangeNotification( 0, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, &ovr, &handle ); + todo_wine ok( ret == ERROR_IO_PENDING, "got %lu.\n", ret ); + + memset( ¶ms, 0, sizeof(params) ); + handle2 = (HANDLE)0xdeadbeef; + memset( &ovr2, 0, sizeof(ovr2) ); + params.module = &NPI_MS_NDIS_MODULEID; + params.table = NSI_NDIS_IFINFO_TABLE; + params.ovr = &ovr2; + params.handle = &handle2; + ret = NsiRequestChangeNotificationEx( ¶ms ); + todo_wine ok( ret == ERROR_IO_PENDING, "got %lu.\n", ret ); + + ok( handle2 == handle, "got %p, %p.\n", handle, handle2 ); + bret = GetOverlappedResult( handle, &ovr, &bytes, FALSE ); + todo_wine ok( !bret && GetLastError() == ERROR_IO_INCOMPLETE, "got bret %d, err %lu.\n", bret, GetLastError() ); + + ret = NsiCancelChangeNotification( NULL ); + todo_wine ok( ret == ERROR_NOT_FOUND, "got %lu.\n", ret ); + + ret = NsiCancelChangeNotification( &ovr ); + todo_wine ok( !ret, "got %lu.\n", ret ); + + bytes = 0xdeadbeef; + bret = GetOverlappedResult( handle, &ovr, &bytes, FALSE ); + todo_wine ok( !bret && GetLastError() == ERROR_OPERATION_ABORTED, "got bret %d, err %lu.\n", bret, GetLastError() ); + todo_wine ok( ovr.Internal == (ULONG)STATUS_CANCELLED, "got %Ix.\n", ovr.Internal ); + ok( !bytes, "got %lu.\n", bytes ); + + bret = GetOverlappedResult( handle2, &ovr2, &bytes, FALSE ); + todo_wine ok( !bret && GetLastError() == ERROR_IO_INCOMPLETE, "got bret %d, err %lu.\n", bret, GetLastError() ); + ret = NsiCancelChangeNotification( &ovr2 ); + todo_wine ok( !ret, "got %lu.\n", ret ); + bret = GetOverlappedResult( handle, &ovr, &bytes, FALSE ); + todo_wine ok( !bret && GetLastError() == ERROR_OPERATION_ABORTED, "got bret %d, err %lu.\n", bret, GetLastError() ); + + ret = NsiRequestChangeNotification( 0, &NPI_MS_NDIS_MODULEID, NSI_NDIS_INDEX_LUID_TABLE, &ovr, &handle ); + todo_wine ok( ret == ERROR_INVALID_PARAMETER, "got %lu.\n", ret ); + + ret = NsiRequestChangeNotification( 0, &NPI_MS_IPV4_MODULEID, NSI_IP_FORWARD_TABLE, &ovr, &handle ); + todo_wine ok( ret == ERROR_IO_PENDING, "got %lu.\n", ret ); + ret = NsiCancelChangeNotification( &ovr ); + todo_wine ok( !ret, "got %lu.\n", ret ); + bret = GetOverlappedResult( handle, &ovr, &bytes, FALSE ); + todo_wine ok( !bret && GetLastError() == ERROR_OPERATION_ABORTED, "got bret %d, err %lu.\n", bret, GetLastError() ); +} + START_TEST( nsi ) { test_nsi_api(); @@ -1056,4 +1118,6 @@ START_TEST( nsi ) test_udp_stats( AF_INET6 ); test_udp_tables( AF_INET ); test_udp_tables( AF_INET6 ); + + test_change_notifications(); } From 498252dd1c3e7e041857330f40617f16bfb433b5 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 25 Jul 2023 17:49:07 -0600 Subject: [PATCH 1554/2777] nsi: Cache nsi device handle. (cherry picked from commit b8fa6de2c2df3526993673002c2a2453943c61a2) CW-Bug-Id: #22496 --- dlls/nsi/nsi.c | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/dlls/nsi/nsi.c b/dlls/nsi/nsi.c index c00ec4f8684..c219d59ccf3 100644 --- a/dlls/nsi/nsi.c +++ b/dlls/nsi/nsi.c @@ -30,9 +30,34 @@ WINE_DEFAULT_DEBUG_CHANNEL(nsi); +static HANDLE nsi_device = INVALID_HANDLE_VALUE; + +BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *reserved) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls( hinst ); + break; + case DLL_PROCESS_DETACH: + if (nsi_device != INVALID_HANDLE_VALUE) CloseHandle( nsi_device ); + break; + } + return TRUE; +} + static inline HANDLE get_nsi_device( void ) { - return CreateFileW( L"\\\\.\\Nsi", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); + HANDLE device; + + if (nsi_device == INVALID_HANDLE_VALUE) + { + device = CreateFileW( L"\\\\.\\Nsi", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); + if (device != INVALID_HANDLE_VALUE + && InterlockedCompareExchangePointer( &nsi_device, device, INVALID_HANDLE_VALUE ) != INVALID_HANDLE_VALUE) + CloseHandle( device ); + } + return nsi_device; } DWORD WINAPI NsiAllocateAndGetTable( DWORD unk, const NPI_MODULEID *module, DWORD table, void **key_data, DWORD key_size, @@ -140,11 +165,7 @@ DWORD WINAPI NsiEnumerateObjectsAllParametersEx( struct nsi_enumerate_all_ex *pa (params->key_size + params->rw_size + params->dynamic_size + params->static_size) * params->count; out = heap_alloc( out_size ); - if (!out) - { - CloseHandle( device ); - return ERROR_OUTOFMEMORY; - } + if (!out) return ERROR_OUTOFMEMORY; in.module = *params->module; in.first_arg = params->first_arg; @@ -172,7 +193,6 @@ DWORD WINAPI NsiEnumerateObjectsAllParametersEx( struct nsi_enumerate_all_ex *pa } heap_free( out ); - CloseHandle( device ); return err; } @@ -256,7 +276,6 @@ DWORD WINAPI NsiGetAllParametersEx( struct nsi_get_all_parameters_ex *params ) err: heap_free( out ); heap_free( in ); - CloseHandle( device ); return err; } @@ -293,11 +312,7 @@ DWORD WINAPI NsiGetParameterEx( struct nsi_get_parameter_ex *params ) if (device == INVALID_HANDLE_VALUE) return GetLastError(); in = heap_alloc( in_size ); - if (!in) - { - err = ERROR_OUTOFMEMORY; - goto err; - } + if (!in) return ERROR_OUTOFMEMORY; in->module = *params->module; in->first_arg = params->first_arg; in->table = params->table; @@ -309,9 +324,7 @@ DWORD WINAPI NsiGetParameterEx( struct nsi_get_parameter_ex *params ) if (!DeviceIoControl( device, IOCTL_NSIPROXY_WINE_GET_PARAMETER, in, in_size, params->data, params->data_size, &received, NULL )) err = GetLastError(); -err: heap_free( in ); - CloseHandle( device ); return err; } From 00f1db5254667caa5def1256151299a55fadbb27 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 25 Jul 2023 19:26:18 -0600 Subject: [PATCH 1555/2777] nsi: Forward request to nsiproxy from NsiRequestChangeNotification(). (cherry picked from commit a72f91f5f5bad7ebb00997e8d5a3e5979d74e527) CW-Bug-Id: #22496 --- dlls/nsi/nsi.c | 57 +++++++++++++++++++++++++++++++------- dlls/nsi/tests/nsi.c | 13 +++++---- dlls/nsiproxy.sys/device.c | 46 ++++++++++++++++++++++++++++++ include/wine/nsi.h | 8 ++++++ 4 files changed, 108 insertions(+), 16 deletions(-) diff --git a/dlls/nsi/nsi.c b/dlls/nsi/nsi.c index c219d59ccf3..a44339fc3af 100644 --- a/dlls/nsi/nsi.c +++ b/dlls/nsi/nsi.c @@ -31,6 +31,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(nsi); static HANDLE nsi_device = INVALID_HANDLE_VALUE; +static HANDLE nsi_device_async = INVALID_HANDLE_VALUE; BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *reserved) { @@ -41,23 +42,26 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *reserved) break; case DLL_PROCESS_DETACH: if (nsi_device != INVALID_HANDLE_VALUE) CloseHandle( nsi_device ); + if (nsi_device_async != INVALID_HANDLE_VALUE) CloseHandle( nsi_device_async ); break; } return TRUE; } -static inline HANDLE get_nsi_device( void ) +static inline HANDLE get_nsi_device( BOOL async ) { + HANDLE *cached_device = async ? &nsi_device_async : &nsi_device; HANDLE device; - if (nsi_device == INVALID_HANDLE_VALUE) + if (*cached_device == INVALID_HANDLE_VALUE) { - device = CreateFileW( L"\\\\.\\Nsi", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); + device = CreateFileW( L"\\\\.\\Nsi", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + async ? FILE_FLAG_OVERLAPPED : 0, NULL ); if (device != INVALID_HANDLE_VALUE - && InterlockedCompareExchangePointer( &nsi_device, device, INVALID_HANDLE_VALUE ) != INVALID_HANDLE_VALUE) + && InterlockedCompareExchangePointer( cached_device, device, INVALID_HANDLE_VALUE ) != INVALID_HANDLE_VALUE) CloseHandle( device ); } - return nsi_device; + return *cached_device; } DWORD WINAPI NsiAllocateAndGetTable( DWORD unk, const NPI_MODULEID *module, DWORD table, void **key_data, DWORD key_size, @@ -155,7 +159,7 @@ DWORD WINAPI NsiEnumerateObjectsAllParameters( DWORD unk, DWORD unk2, const NPI_ DWORD WINAPI NsiEnumerateObjectsAllParametersEx( struct nsi_enumerate_all_ex *params ) { DWORD out_size, received, err = ERROR_SUCCESS; - HANDLE device = get_nsi_device(); + HANDLE device = get_nsi_device( FALSE ); struct nsiproxy_enumerate_all in; BYTE *out, *ptr; @@ -235,7 +239,7 @@ DWORD WINAPI NsiGetAllParameters( DWORD unk, const NPI_MODULEID *module, DWORD t DWORD WINAPI NsiGetAllParametersEx( struct nsi_get_all_parameters_ex *params ) { - HANDLE device = get_nsi_device(); + HANDLE device = get_nsi_device( FALSE ); struct nsiproxy_get_all_parameters *in; ULONG in_size = FIELD_OFFSET( struct nsiproxy_get_all_parameters, key[params->key_size] ), received; ULONG out_size = params->rw_size + params->dynamic_size + params->static_size; @@ -304,7 +308,7 @@ DWORD WINAPI NsiGetParameter( DWORD unk, const NPI_MODULEID *module, DWORD table DWORD WINAPI NsiGetParameterEx( struct nsi_get_parameter_ex *params ) { - HANDLE device = get_nsi_device(); + HANDLE device = get_nsi_device( FALSE ); struct nsiproxy_get_parameter *in; ULONG in_size = FIELD_OFFSET( struct nsiproxy_get_parameter, key[params->key_size] ), received; DWORD err = ERROR_SUCCESS; @@ -345,7 +349,40 @@ DWORD WINAPI NsiRequestChangeNotification( DWORD unk, const NPI_MODULEID *module DWORD WINAPI NsiRequestChangeNotificationEx( struct nsi_request_change_notification_ex *params ) { - FIXME( "%p stub.\n", params ); + HANDLE device = get_nsi_device( TRUE ); + struct nsiproxy_request_notification *in; + ULONG in_size = sizeof(struct nsiproxy_get_parameter), received; + OVERLAPPED overlapped, *ovr; + DWORD err = ERROR_SUCCESS; + DWORD len; - return ERROR_NOT_SUPPORTED; + TRACE( "%p.\n", params ); + + if (params->unk) FIXME( "unknown parameter %#lx.\n", params->unk ); + + if (device == INVALID_HANDLE_VALUE) return GetLastError(); + + in = malloc( in_size ); + if (!in) return ERROR_OUTOFMEMORY; + in->module = *params->module; + in->table = params->table; + + if (!(ovr = params->ovr)) + { + overlapped.hEvent = CreateEventW( NULL, FALSE, FALSE, NULL ); + ovr = &overlapped; + } + if (!DeviceIoControl( device, IOCTL_NSIPROXY_WINE_CHANGE_NOTIFICATION, in, in_size, NULL, 0, &received, ovr )) + err = GetLastError(); + if (ovr == &overlapped) + { + if (err == ERROR_IO_PENDING) + err = GetOverlappedResult( device, ovr, &len, TRUE ) ? 0 : GetLastError(); + CloseHandle( overlapped.hEvent ); + } + else if (params->handle && ovr && err == ERROR_IO_PENDING) + *params->handle = device; + + free( in ); + return err; } diff --git a/dlls/nsi/tests/nsi.c b/dlls/nsi/tests/nsi.c index 5b3a6775992..6d759debfd6 100644 --- a/dlls/nsi/tests/nsi.c +++ b/dlls/nsi/tests/nsi.c @@ -1039,7 +1039,7 @@ void test_change_notifications(void) handle = (HANDLE)0xdeadbeef; ret = NsiRequestChangeNotification( 0, &NPI_MS_NDIS_MODULEID, NSI_NDIS_IFINFO_TABLE, &ovr, &handle ); - todo_wine ok( ret == ERROR_IO_PENDING, "got %lu.\n", ret ); + ok( ret == ERROR_IO_PENDING, "got %lu.\n", ret ); memset( ¶ms, 0, sizeof(params) ); handle2 = (HANDLE)0xdeadbeef; @@ -1049,11 +1049,11 @@ void test_change_notifications(void) params.ovr = &ovr2; params.handle = &handle2; ret = NsiRequestChangeNotificationEx( ¶ms ); - todo_wine ok( ret == ERROR_IO_PENDING, "got %lu.\n", ret ); + ok( ret == ERROR_IO_PENDING, "got %lu.\n", ret ); ok( handle2 == handle, "got %p, %p.\n", handle, handle2 ); bret = GetOverlappedResult( handle, &ovr, &bytes, FALSE ); - todo_wine ok( !bret && GetLastError() == ERROR_IO_INCOMPLETE, "got bret %d, err %lu.\n", bret, GetLastError() ); + ok( !bret && GetLastError() == ERROR_IO_INCOMPLETE, "got bret %d, err %lu.\n", bret, GetLastError() ); ret = NsiCancelChangeNotification( NULL ); todo_wine ok( ret == ERROR_NOT_FOUND, "got %lu.\n", ret ); @@ -1063,12 +1063,13 @@ void test_change_notifications(void) bytes = 0xdeadbeef; bret = GetOverlappedResult( handle, &ovr, &bytes, FALSE ); + todo_wine ok( !bret && GetLastError() == ERROR_OPERATION_ABORTED, "got bret %d, err %lu.\n", bret, GetLastError() ); todo_wine ok( ovr.Internal == (ULONG)STATUS_CANCELLED, "got %Ix.\n", ovr.Internal ); - ok( !bytes, "got %lu.\n", bytes ); + todo_wine ok( !bytes, "got %lu.\n", bytes ); bret = GetOverlappedResult( handle2, &ovr2, &bytes, FALSE ); - todo_wine ok( !bret && GetLastError() == ERROR_IO_INCOMPLETE, "got bret %d, err %lu.\n", bret, GetLastError() ); + ok( !bret && GetLastError() == ERROR_IO_INCOMPLETE, "got bret %d, err %lu.\n", bret, GetLastError() ); ret = NsiCancelChangeNotification( &ovr2 ); todo_wine ok( !ret, "got %lu.\n", ret ); bret = GetOverlappedResult( handle, &ovr, &bytes, FALSE ); @@ -1078,7 +1079,7 @@ void test_change_notifications(void) todo_wine ok( ret == ERROR_INVALID_PARAMETER, "got %lu.\n", ret ); ret = NsiRequestChangeNotification( 0, &NPI_MS_IPV4_MODULEID, NSI_IP_FORWARD_TABLE, &ovr, &handle ); - todo_wine ok( ret == ERROR_IO_PENDING, "got %lu.\n", ret ); + ok( ret == ERROR_IO_PENDING, "got %lu.\n", ret ); ret = NsiCancelChangeNotification( &ovr ); todo_wine ok( !ret, "got %lu.\n", ret ); bret = GetOverlappedResult( handle, &ovr, &bytes, FALSE ); diff --git a/dlls/nsiproxy.sys/device.c b/dlls/nsiproxy.sys/device.c index 4528e934991..f0472b3fe7f 100644 --- a/dlls/nsiproxy.sys/device.c +++ b/dlls/nsiproxy.sys/device.c @@ -49,6 +49,7 @@ DECLARE_CRITICAL_SECTION( nsiproxy_cs ); #define LIST_ENTRY_INIT( list ) { .Flink = &(list), .Blink = &(list) } static LIST_ENTRY request_queue = LIST_ENTRY_INIT( request_queue ); +static LIST_ENTRY notification_queue = LIST_ENTRY_INIT( notification_queue ); static NTSTATUS nsiproxy_call( unsigned int code, void *args ) { @@ -261,6 +262,47 @@ static NTSTATUS nsiproxy_icmp_echo( IRP *irp ) return STATUS_PENDING; } +static void WINAPI change_notification_cancel( DEVICE_OBJECT *device, IRP *irp ) +{ + TRACE( "device %p, irp %p.\n", device, irp ); + + IoReleaseCancelSpinLock( irp->CancelIrql ); + + EnterCriticalSection( &nsiproxy_cs ); + RemoveEntryList( &irp->Tail.Overlay.ListEntry ); + LeaveCriticalSection( &nsiproxy_cs ); + + irp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest( irp, IO_NO_INCREMENT ); +} + +static NTSTATUS nsiproxy_change_notification( IRP *irp ) +{ + IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); + struct nsiproxy_request_notification *in = (struct nsiproxy_request_notification *)irp->AssociatedIrp.SystemBuffer; + DWORD in_len = irpsp->Parameters.DeviceIoControl.InputBufferLength; + + FIXME( "\n" ); + + if (in_len < sizeof(*in)) return STATUS_INVALID_PARAMETER; + /* FIXME: validate module and table. */ + + EnterCriticalSection( &nsiproxy_cs ); + IoSetCancelRoutine( irp, change_notification_cancel ); + if (irp->Cancel && !IoSetCancelRoutine( irp, NULL )) + { + /* IRP was canceled before we set cancel routine */ + InitializeListHead( &irp->Tail.Overlay.ListEntry ); + LeaveCriticalSection( &nsiproxy_cs ); + return STATUS_CANCELLED; + } + InsertTailList( ¬ification_queue, &irp->Tail.Overlay.ListEntry ); + IoMarkIrpPending( irp ); + LeaveCriticalSection( &nsiproxy_cs ); + + return STATUS_PENDING; +} + static NTSTATUS WINAPI nsi_ioctl( DEVICE_OBJECT *device, IRP *irp ) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); @@ -289,6 +331,10 @@ static NTSTATUS WINAPI nsi_ioctl( DEVICE_OBJECT *device, IRP *irp ) status = nsiproxy_icmp_echo( irp ); break; + case IOCTL_NSIPROXY_WINE_CHANGE_NOTIFICATION: + status = nsiproxy_change_notification( irp ); + break; + default: FIXME( "ioctl %lx not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode ); status = STATUS_NOT_SUPPORTED; diff --git a/include/wine/nsi.h b/include/wine/nsi.h index 1a562c3c36d..6bf3ce5bd5d 100644 --- a/include/wine/nsi.h +++ b/include/wine/nsi.h @@ -380,6 +380,7 @@ struct nsi_udp_endpoint_static #define IOCTL_NSIPROXY_WINE_GET_ALL_PARAMETERS CTL_CODE(FILE_DEVICE_NETWORK, 0x401, METHOD_BUFFERED, 0) #define IOCTL_NSIPROXY_WINE_GET_PARAMETER CTL_CODE(FILE_DEVICE_NETWORK, 0x402, METHOD_BUFFERED, 0) #define IOCTL_NSIPROXY_WINE_ICMP_ECHO CTL_CODE(FILE_DEVICE_NETWORK, 0x403, METHOD_BUFFERED, 0) +#define IOCTL_NSIPROXY_WINE_CHANGE_NOTIFICATION CTL_CODE(FILE_DEVICE_NETWORK, 0x404, METHOD_BUFFERED, 0) /* input for IOCTL_NSIPROXY_WINE_ENUMERATE_ALL */ struct nsiproxy_enumerate_all @@ -436,6 +437,13 @@ struct nsiproxy_icmp_echo BYTE data[1]; /* ((opt_size + 3) & ~3) + req_size */ }; +/* input for IOCTL_NSIPROXY_WINE_CHANGE_NOTIFICATION */ +struct nsiproxy_request_notification +{ + NPI_MODULEID module; + UINT table; +}; + /* Undocumented Nsi api */ #define NSI_PARAM_TYPE_RW 0 From cd16ef5d18ac2446114ec64bd1b111feab4806d6 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 25 Jul 2023 19:28:25 -0600 Subject: [PATCH 1556/2777] nsi: Implement NsiCancelChangeNotification(). (cherry picked from commit 79165b162492f7b1a0ece97825f2d1ba735b5db0) CW-Bug-Id: #22496 --- dlls/nsi/nsi.c | 10 ++++++++-- dlls/nsi/tests/nsi.c | 24 ++++++++++++------------ 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/dlls/nsi/nsi.c b/dlls/nsi/nsi.c index a44339fc3af..5dc54d0035f 100644 --- a/dlls/nsi/nsi.c +++ b/dlls/nsi/nsi.c @@ -119,9 +119,15 @@ DWORD WINAPI NsiAllocateAndGetTable( DWORD unk, const NPI_MODULEID *module, DWOR DWORD WINAPI NsiCancelChangeNotification( OVERLAPPED *ovr ) { - FIXME( "%p stub.\n", ovr ); + DWORD err = ERROR_SUCCESS; + + TRACE( "%p.\n", ovr ); - return ERROR_NOT_SUPPORTED; + if (!ovr) return ERROR_NOT_FOUND; + if (!CancelIoEx( get_nsi_device( TRUE ), ovr )) + err = GetLastError(); + + return err; } DWORD WINAPI NsiEnumerateObjectsAllParameters( DWORD unk, DWORD unk2, const NPI_MODULEID *module, DWORD table, diff --git a/dlls/nsi/tests/nsi.c b/dlls/nsi/tests/nsi.c index 6d759debfd6..1bae78d2563 100644 --- a/dlls/nsi/tests/nsi.c +++ b/dlls/nsi/tests/nsi.c @@ -1056,24 +1056,24 @@ void test_change_notifications(void) ok( !bret && GetLastError() == ERROR_IO_INCOMPLETE, "got bret %d, err %lu.\n", bret, GetLastError() ); ret = NsiCancelChangeNotification( NULL ); - todo_wine ok( ret == ERROR_NOT_FOUND, "got %lu.\n", ret ); + ok( ret == ERROR_NOT_FOUND, "got %lu.\n", ret ); ret = NsiCancelChangeNotification( &ovr ); - todo_wine ok( !ret, "got %lu.\n", ret ); + ok( !ret, "got %lu.\n", ret ); bytes = 0xdeadbeef; - bret = GetOverlappedResult( handle, &ovr, &bytes, FALSE ); + bret = GetOverlappedResult( handle, &ovr, &bytes, TRUE ); - todo_wine ok( !bret && GetLastError() == ERROR_OPERATION_ABORTED, "got bret %d, err %lu.\n", bret, GetLastError() ); - todo_wine ok( ovr.Internal == (ULONG)STATUS_CANCELLED, "got %Ix.\n", ovr.Internal ); - todo_wine ok( !bytes, "got %lu.\n", bytes ); + ok( !bret && GetLastError() == ERROR_OPERATION_ABORTED, "got bret %d, err %lu.\n", bret, GetLastError() ); + ok( ovr.Internal == (ULONG)STATUS_CANCELLED, "got %Ix.\n", ovr.Internal ); + ok( !bytes, "got %lu.\n", bytes ); bret = GetOverlappedResult( handle2, &ovr2, &bytes, FALSE ); ok( !bret && GetLastError() == ERROR_IO_INCOMPLETE, "got bret %d, err %lu.\n", bret, GetLastError() ); ret = NsiCancelChangeNotification( &ovr2 ); - todo_wine ok( !ret, "got %lu.\n", ret ); - bret = GetOverlappedResult( handle, &ovr, &bytes, FALSE ); - todo_wine ok( !bret && GetLastError() == ERROR_OPERATION_ABORTED, "got bret %d, err %lu.\n", bret, GetLastError() ); + ok( !ret, "got %lu.\n", ret ); + bret = GetOverlappedResult( handle, &ovr, &bytes, TRUE ); + ok( !bret && GetLastError() == ERROR_OPERATION_ABORTED, "got bret %d, err %lu.\n", bret, GetLastError() ); ret = NsiRequestChangeNotification( 0, &NPI_MS_NDIS_MODULEID, NSI_NDIS_INDEX_LUID_TABLE, &ovr, &handle ); todo_wine ok( ret == ERROR_INVALID_PARAMETER, "got %lu.\n", ret ); @@ -1081,9 +1081,9 @@ void test_change_notifications(void) ret = NsiRequestChangeNotification( 0, &NPI_MS_IPV4_MODULEID, NSI_IP_FORWARD_TABLE, &ovr, &handle ); ok( ret == ERROR_IO_PENDING, "got %lu.\n", ret ); ret = NsiCancelChangeNotification( &ovr ); - todo_wine ok( !ret, "got %lu.\n", ret ); - bret = GetOverlappedResult( handle, &ovr, &bytes, FALSE ); - todo_wine ok( !bret && GetLastError() == ERROR_OPERATION_ABORTED, "got bret %d, err %lu.\n", bret, GetLastError() ); + ok( !ret, "got %lu.\n", ret ); + bret = GetOverlappedResult( handle, &ovr, &bytes, TRUE ); + ok( !bret && GetLastError() == ERROR_OPERATION_ABORTED, "got bret %d, err %lu.\n", bret, GetLastError() ); } START_TEST( nsi ) From 4b2a2143aeba7b6a3db99ab9fe781dba11719b58 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 26 Jul 2023 09:06:29 -0600 Subject: [PATCH 1557/2777] nsiproxy.sys: Implement change notifications for NSI_IP_UNICAST_TABLE. (cherry picked from commit a58f3e04013965aec11d328128e5f893d6b9e329) CW-Bug-Id: #22496 --- dlls/nsiproxy.sys/device.c | 56 +++++++++++- dlls/nsiproxy.sys/nsi.c | 122 ++++++++++++++++++++++++++- dlls/nsiproxy.sys/nsiproxy_private.h | 7 ++ 3 files changed, 183 insertions(+), 2 deletions(-) diff --git a/dlls/nsiproxy.sys/device.c b/dlls/nsiproxy.sys/device.c index f0472b3fe7f..8acdecdb735 100644 --- a/dlls/nsiproxy.sys/device.c +++ b/dlls/nsiproxy.sys/device.c @@ -51,6 +51,12 @@ DECLARE_CRITICAL_SECTION( nsiproxy_cs ); static LIST_ENTRY request_queue = LIST_ENTRY_INIT( request_queue ); static LIST_ENTRY notification_queue = LIST_ENTRY_INIT( notification_queue ); +struct notification_data +{ + NPI_MODULEID module; + UINT table; +}; + static NTSTATUS nsiproxy_call( unsigned int code, void *args ) { return WINE_UNIX_CALL( code, args ); @@ -65,6 +71,7 @@ enum unix_calls nsi_enumerate_all_ex, nsi_get_all_parameters_ex, nsi_get_parameter_ex, + nsi_get_notification, }; static NTSTATUS nsiproxy_enumerate_all( IRP *irp ) @@ -270,6 +277,7 @@ static void WINAPI change_notification_cancel( DEVICE_OBJECT *device, IRP *irp ) EnterCriticalSection( &nsiproxy_cs ); RemoveEntryList( &irp->Tail.Overlay.ListEntry ); + free( irp->Tail.Overlay.DriverContext[0] ); LeaveCriticalSection( &nsiproxy_cs ); irp->IoStatus.Status = STATUS_CANCELLED; @@ -281,10 +289,12 @@ static NTSTATUS nsiproxy_change_notification( IRP *irp ) IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); struct nsiproxy_request_notification *in = (struct nsiproxy_request_notification *)irp->AssociatedIrp.SystemBuffer; DWORD in_len = irpsp->Parameters.DeviceIoControl.InputBufferLength; + struct notification_data *data; - FIXME( "\n" ); + TRACE( "irp %p.\n", irp ); if (in_len < sizeof(*in)) return STATUS_INVALID_PARAMETER; + if (!(data = calloc( 1, sizeof(*data) ))) return STATUS_NO_MEMORY; /* FIXME: validate module and table. */ EnterCriticalSection( &nsiproxy_cs ); @@ -294,10 +304,14 @@ static NTSTATUS nsiproxy_change_notification( IRP *irp ) /* IRP was canceled before we set cancel routine */ InitializeListHead( &irp->Tail.Overlay.ListEntry ); LeaveCriticalSection( &nsiproxy_cs ); + free( data ); return STATUS_CANCELLED; } InsertTailList( ¬ification_queue, &irp->Tail.Overlay.ListEntry ); IoMarkIrpPending( irp ); + data->module = in->module; + data->table = in->table; + irp->Tail.Overlay.DriverContext[0] = data; LeaveCriticalSection( &nsiproxy_cs ); return STATUS_PENDING; @@ -468,6 +482,44 @@ static DWORD WINAPI request_thread_proc( void *arg ) return 0; } +static DWORD WINAPI notification_thread_proc( void *arg ) +{ + struct nsi_get_notification_params params; + LIST_ENTRY *entry, *next; + NTSTATUS status; + + while (!(status = nsiproxy_call( nsi_get_notification, ¶ms ))) + { + EnterCriticalSection( &nsiproxy_cs ); + for (entry = notification_queue.Flink; entry != ¬ification_queue; entry = next) + { + IRP *irp = CONTAINING_RECORD( entry, IRP, Tail.Overlay.ListEntry ); + struct notification_data *data = irp->Tail.Overlay.DriverContext[0]; + + next = entry->Flink; + if(irp->Cancel) + { + /* Cancel routine should care of freeing data and completing IRP. */ + TRACE( "irp %p canceled.\n", irp ); + continue; + } + if (!NmrIsEqualNpiModuleId( &data->module, ¶ms.module ) || data->table != params.table) + continue; + + irp->IoStatus.Status = 0; + RemoveEntryList( entry ); + irp->Tail.Overlay.DriverContext[0] = NULL; + free( data ); + TRACE("completing irp %p.\n", irp); + IoCompleteRequest( irp, IO_NO_INCREMENT ); + } + LeaveCriticalSection( &nsiproxy_cs ); + } + + WARN( "nsi_get_notification failed, status %#lx.\n", status ); + return 0; +} + NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) { NTSTATUS status; @@ -485,6 +537,8 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) request_event = CreateEventW( NULL, FALSE, FALSE, NULL ); thread = CreateThread( NULL, 0, request_thread_proc, NULL, 0, NULL ); CloseHandle( thread ); + thread = CreateThread( NULL, 0, notification_thread_proc, NULL, 0, NULL ); + CloseHandle( thread ); return STATUS_SUCCESS; } diff --git a/dlls/nsiproxy.sys/nsi.c b/dlls/nsiproxy.sys/nsi.c index b9b04e63545..2f6d2d59573 100644 --- a/dlls/nsiproxy.sys/nsi.c +++ b/dlls/nsiproxy.sys/nsi.c @@ -21,7 +21,16 @@ #pragma makedep unix #endif +#include "config.h" #include +#include +#include +#include +#include +#include +#ifdef HAVE_LINUX_RTNETLINK_H +#include +#endif #include "ntstatus.h" #define WIN32_NO_STATUS @@ -32,11 +41,13 @@ #include "ddk/wdm.h" #include "ifdef.h" #define __WINE_INIT_NPI_MODULEID +#define USE_WS_PREFIX #include "netiodef.h" #include "wine/nsi.h" #include "wine/debug.h" #include "wine/unixlib.h" #include "unix_private.h" +#include "nsiproxy_private.h" WINE_DEFAULT_DEBUG_CHANNEL(nsi); @@ -145,6 +156,114 @@ static NTSTATUS unix_nsi_get_parameter_ex( void *args ) return nsi_get_parameter_ex( params ); } +#ifdef HAVE_LINUX_RTNETLINK_H +static struct +{ + const NPI_MODULEID *module; + UINT32 table; +} +queued_notifications[256]; +static unsigned int queued_notification_count; + +static NTSTATUS add_notification( const NPI_MODULEID *module, UINT32 table ) +{ + unsigned int i; + + for (i = 0; i < queued_notification_count; ++i) + if (queued_notifications[i].module == module && queued_notifications[i].table == table) return STATUS_SUCCESS; + if (queued_notification_count == ARRAY_SIZE(queued_notifications)) + { + ERR( "Notification queue full.\n" ); + return STATUS_NO_MEMORY; + } + queued_notifications[i].module = module; + queued_notifications[i].table = table; + ++queued_notification_count; + return STATUS_SUCCESS; +} + +static NTSTATUS poll_netlink(void) +{ + static int netlink_fd = -1; + char buffer[PIPE_BUF]; + struct nlmsghdr *nlh; + NTSTATUS status; + int len; + + if (netlink_fd == -1) + { + struct sockaddr_nl addr; + + if ((netlink_fd = socket( PF_NETLINK, SOCK_RAW, NETLINK_ROUTE )) == -1) + { + ERR( "netlink socket creation failed, errno %d.\n", errno ); + return STATUS_NOT_IMPLEMENTED; + } + + memset( &addr, 0, sizeof(addr) ); + addr.nl_family = AF_NETLINK; + addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR; + if (bind( netlink_fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1) + { + close( netlink_fd ); + netlink_fd = -1; + ERR( "bind failed, errno %d.\n", errno ); + return STATUS_NOT_IMPLEMENTED; + } + } + + while (1) + { + len = recv( netlink_fd, buffer, sizeof(buffer), 0 ); + if (len <= 0) + { + if (errno == EINTR) continue; + ERR( "error receivng, len %d, errno %d.\n", len, errno ); + return STATUS_UNSUCCESSFUL; + } + for (nlh = (struct nlmsghdr *)buffer; NLMSG_OK(nlh, len); nlh = NLMSG_NEXT(nlh, len)) + { + if (nlh->nlmsg_type == NLMSG_DONE) break; + if (nlh->nlmsg_type == RTM_NEWADDR || nlh->nlmsg_type == RTM_DELADDR) + { + struct ifaddrmsg *addrmsg = (struct ifaddrmsg *)(nlh + 1); + const NPI_MODULEID *module; + + if (addrmsg->ifa_family == AF_INET) module = &NPI_MS_IPV4_MODULEID; + else if (addrmsg->ifa_family == AF_INET6) module = &NPI_MS_IPV6_MODULEID; + else + { + WARN( "Unknown addrmsg->ifa_family %d.\n", addrmsg->ifa_family ); + continue; + } + if ((status = add_notification( module, NSI_IP_UNICAST_TABLE))) return status; + } + } + if (queued_notification_count) break; + } + return STATUS_SUCCESS; +} + +static NTSTATUS unix_nsi_get_notification( void *args ) +{ + struct nsi_get_notification_params *params = (struct nsi_get_notification_params *)args; + NTSTATUS status; + + if (!queued_notification_count && (status = poll_netlink())) return status; + assert( queued_notification_count ); + params->module = *queued_notifications[0].module; + params->table = queued_notifications[0].table; + --queued_notification_count; + memmove( queued_notifications, queued_notifications + 1, sizeof(*queued_notifications) * queued_notification_count ); + return STATUS_SUCCESS; +} +#else +static NTSTATUS unix_nsi_get_notification( void *args ) +{ + return STATUS_NOT_IMPLEMENTED; +} +#endif + const unixlib_entry_t __wine_unix_call_funcs[] = { icmp_cancel_listen, @@ -153,5 +272,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = icmp_send_echo, unix_nsi_enumerate_all_ex, unix_nsi_get_all_parameters_ex, - unix_nsi_get_parameter_ex + unix_nsi_get_parameter_ex, + unix_nsi_get_notification, }; diff --git a/dlls/nsiproxy.sys/nsiproxy_private.h b/dlls/nsiproxy.sys/nsiproxy_private.h index 241106fe228..1b6eacf7d08 100644 --- a/dlls/nsiproxy.sys/nsiproxy_private.h +++ b/dlls/nsiproxy.sys/nsiproxy_private.h @@ -84,3 +84,10 @@ struct icmp_echo_reply_64 ULONGLONG options_ptr; } opts; }; + +struct nsi_get_notification_params +{ + /* output parameters */ + NPI_MODULEID module; + UINT32 table; +}; From b1b26522b427ab5f2c9d9984681232c696af6074 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 26 Jul 2023 19:19:30 -0600 Subject: [PATCH 1558/2777] iphlpapi: Link NotifyAddrChange and CancelIPChangeNotify to nsi implementation. (cherry picked from commit 4098a05ea84ca8587690f8d0b124b3e07c3c4a9f) CW-Bug-Id: #22496 --- dlls/iphlpapi/iphlpapi_main.c | 21 +++++++++------------ dlls/iphlpapi/tests/iphlpapi.c | 14 +++++++++----- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c index 6286c168277..9b0c125b425 100644 --- a/dlls/iphlpapi/iphlpapi_main.c +++ b/dlls/iphlpapi/iphlpapi_main.c @@ -128,14 +128,15 @@ DWORD WINAPI AddIPAddress(IPAddr Address, IPMask IpMask, DWORD IfIndex, PULONG N * RETURNS * Success: TRUE * Failure: FALSE - * - * FIXME - * Stub, returns FALSE. */ BOOL WINAPI CancelIPChangeNotify(LPOVERLAPPED overlapped) { - FIXME("(overlapped %p): stub\n", overlapped); - return FALSE; + DWORD err; + + TRACE("overlapped %p.\n", overlapped); + + if ((err = NsiCancelChangeNotification( overlapped ))) SetLastError( err ); + return !err; } @@ -3787,16 +3788,12 @@ DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo) * RETURNS * Success: NO_ERROR * Failure: error code from winerror.h - * - * FIXME - * Stub, returns ERROR_NOT_SUPPORTED. */ DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped) { - FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped); - if (Handle) *Handle = INVALID_HANDLE_VALUE; - if (overlapped) ((IO_STATUS_BLOCK *) overlapped)->Status = STATUS_PENDING; - return ERROR_IO_PENDING; + TRACE("Handle %p, overlapped %p.\n", Handle, overlapped); + + return NsiRequestChangeNotification(0, &NPI_MS_IPV4_MODULEID, NSI_IP_UNICAST_TABLE, overlapped, Handle); } diff --git a/dlls/iphlpapi/tests/iphlpapi.c b/dlls/iphlpapi/tests/iphlpapi.c index b8fa82d2a56..4dd2db9e1ee 100644 --- a/dlls/iphlpapi/tests/iphlpapi.c +++ b/dlls/iphlpapi/tests/iphlpapi.c @@ -1670,9 +1670,11 @@ static void testNotifyAddrChange(void) ret = NotifyAddrChange(&handle, &overlapped); ok(ret == ERROR_IO_PENDING, "NotifyAddrChange returned %ld, expected ERROR_IO_PENDING\n", ret); ret = GetLastError(); - todo_wine ok(ret == ERROR_IO_PENDING, "GetLastError returned %ld, expected ERROR_IO_PENDING\n", ret); + ok(ret == ERROR_IO_PENDING, "GetLastError returned %ld, expected ERROR_IO_PENDING\n", ret); success = CancelIPChangeNotify(&overlapped); - todo_wine ok(success == TRUE, "CancelIPChangeNotify returned FALSE, expected TRUE\n"); + ok(success == TRUE, "CancelIPChangeNotify returned FALSE, expected TRUE\n"); + success = GetOverlappedResult( handle, &overlapped, &bytes, TRUE ); + ok( !success && GetLastError() == ERROR_OPERATION_ABORTED, "got bret %d, err %lu.\n", success, GetLastError() ); ZeroMemory(&overlapped, sizeof(overlapped)); success = CancelIPChangeNotify(&overlapped); @@ -1683,13 +1685,15 @@ static void testNotifyAddrChange(void) overlapped.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); ret = NotifyAddrChange(&handle, &overlapped); ok(ret == ERROR_IO_PENDING, "NotifyAddrChange returned %ld, expected ERROR_IO_PENDING\n", ret); - todo_wine ok(handle != INVALID_HANDLE_VALUE, "NotifyAddrChange returned invalid file handle\n"); + ok(handle != INVALID_HANDLE_VALUE, "NotifyAddrChange returned invalid file handle\n"); success = GetOverlappedResult(handle, &overlapped, &bytes, FALSE); ok(success == FALSE, "GetOverlappedResult returned TRUE, expected FALSE\n"); ret = GetLastError(); ok(ret == ERROR_IO_INCOMPLETE, "GetLastError returned %ld, expected ERROR_IO_INCOMPLETE\n", ret); success = CancelIPChangeNotify(&overlapped); - todo_wine ok(success == TRUE, "CancelIPChangeNotify returned FALSE, expected TRUE\n"); + ok(success == TRUE, "CancelIPChangeNotify returned FALSE, expected TRUE\n"); + success = GetOverlappedResult( handle, &overlapped, &bytes, TRUE ); + ok( !success && GetLastError() == ERROR_OPERATION_ABORTED, "got bret %d, err %lu.\n", success, GetLastError() ); if (winetest_interactive) { @@ -1710,7 +1714,7 @@ static void testNotifyAddrChange(void) trace("Testing synchronous ipv4 address change notification. Please " "change the ipv4 address of one of your network interfaces\n"); ret = NotifyAddrChange(NULL, NULL); - todo_wine ok(ret == NO_ERROR, "NotifyAddrChange returned %ld, expected NO_ERROR\n", ret); + ok(ret == NO_ERROR, "NotifyAddrChange returned %ld, expected NO_ERROR\n", ret); } } From ec6c0759728590d77679849a7e67c3698cf146f6 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 11 Aug 2023 17:57:29 -0600 Subject: [PATCH 1559/2777] opengl32: Skip debug callback messages called from native thread. (cherry picked from commit 51b671532715bd2a0486a2c7ddf23134d81ba688) CW-Bug-Id: #22593 --- dlls/opengl32/unix_wgl.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index 24bd904b068..888bd92e205 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -823,8 +823,15 @@ static void gl_debug_message_callback( GLenum source, GLenum type, GLuint id, GL }; void *ret_ptr; ULONG ret_len; - struct wgl_handle *ptr = (struct wgl_handle *)userParam; + + if (!NtCurrentTeb()) + { + fprintf( stderr, "msg:gl_debug_message_callback called from native thread, severity %#x, message \"%.*s\".\n", + severity, length, message ); + return; + } + if (!(params.user_callback = ptr->u.context->debug_callback)) return; params.user_data = ptr->u.context->debug_user; From 2af0eea747516b7af726de692a7aac18109e9deb Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 21 Aug 2023 20:26:03 -0600 Subject: [PATCH 1560/2777] kernelbase: HACK: Try harder to force GL QtWebEngine rendering for EADesktop. CW-Bug-Id: #22640 --- dlls/kernelbase/process.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 69230d244f2..46b22897712 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -1925,6 +1925,16 @@ BOOL WINAPI DECLSPEC_HOTPATCH SetEnvironmentVariableW( LPCWSTR name, LPCWSTR val len = lstrlenW(names[i]); if (size > len && !memcmp( module + size - len, names[i], len * sizeof(*module) )) { + HMODULE h = GetModuleHandleW(L"Qt5Core.dll"); + void (WINAPI *QCoreApplication_setAttribute)(int attr, BOOL set); + + QCoreApplication_setAttribute = (void *)GetProcAddress(h, "?setAttribute@QCoreApplication@@SAXW4ApplicationAttribute@Qt@@_N@Z"); + if (QCoreApplication_setAttribute) + { + QCoreApplication_setAttribute(16 /* AA_UseOpenGLES */, 0); + QCoreApplication_setAttribute(15 /* AA_UseDesktopOpenGL */, 1); + } + else ERR("QCoreApplication_setAttribute not found, h %p.\n", h); value = L"desktop"; FIXME( "HACK: setting QT_OPENGL=desktop.\n" ); break; From a04eceaec04bf37d9570e5850c5164f05fff2479 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 1 Aug 2023 09:09:37 -0600 Subject: [PATCH 1561/2777] ntdll: HACK: Enable WINE_SIMULATE_WRITECOPY for UplayWebCore. CW-Bug-Id: #22534 --- dlls/ntdll/unix/loader.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index d2bff4ab2fc..9dc11f74fb2 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2352,6 +2352,7 @@ static void hacks_init(void) env_str = getenv("WINE_SIMULATE_WRITECOPY"); if (env_str) simulate_writecopy = atoi(env_str); + else if (main_argc > 1 && strstr(main_argv[1], "UplayWebCore.exe")) simulate_writecopy = TRUE; else if (sgi) simulate_writecopy = !strcmp(sgi, "1608730") /* Dawn of Corruption */ || !strcmp(sgi, "1680700") /* Purgo box */ || !strcmp(sgi, "2095300") /* Breakout 13 */ From dcea6ae4343efb1f4b50fdc242bcfffc86d1506f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 19 Jun 2023 17:50:33 -0600 Subject: [PATCH 1562/2777] ntdll: Reimplement NtSaveKey() on the client side. CW-Bug-Id: #22347 --- dlls/ntdll/unix/registry.c | 290 ++++++++++++++++++++++++++++++++++++- server/protocol.def | 14 +- server/registry.c | 124 +++++++++++++--- 3 files changed, 399 insertions(+), 29 deletions(-) diff --git a/dlls/ntdll/unix/registry.c b/dlls/ntdll/unix/registry.c index d183474b53f..595d4f7892d 100644 --- a/dlls/ntdll/unix/registry.c +++ b/dlls/ntdll/unix/registry.c @@ -27,6 +27,8 @@ #include #include +#include +#include #include "ntstatus.h" #define WIN32_NO_STATUS @@ -68,6 +70,248 @@ NTSTATUS open_hkcu_key( const char *path, HANDLE *key ) return NtCreateKey( key, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ); } +/* dump a Unicode string with proper escaping */ +int dump_strW( const WCHAR *str, data_size_t len, FILE *f, const char escape[2] ) +{ + static const char escapes[32] = ".......abtnvfr.............e...."; + char buffer[256]; + char *pos = buffer; + int count = 0; + + for (len /= sizeof(WCHAR); len; str++, len--) + { + if (pos > buffer + sizeof(buffer) - 8) + { + fwrite( buffer, pos - buffer, 1, f ); + count += pos - buffer; + pos = buffer; + } + if (*str > 127) /* hex escape */ + { + if (len > 1 && str[1] < 128 && isxdigit( (char)str[1] )) + pos += sprintf( pos, "\\x%04x", *str ); + else + pos += sprintf( pos, "\\x%x", *str ); + continue; + } + if (*str < 32) /* octal or C escape */ + { + if (!*str && len == 1) continue; /* do not output terminating NULL */ + if (escapes[*str] != '.') + pos += sprintf( pos, "\\%c", escapes[*str] ); + else if (len > 1 && str[1] >= '0' && str[1] <= '7') + pos += sprintf( pos, "\\%03o", *str ); + else + pos += sprintf( pos, "\\%o", *str ); + continue; + } + if (*str == '\\' || *str == escape[0] || *str == escape[1]) *pos++ = '\\'; + *pos++ = *str; + } + fwrite( buffer, pos - buffer, 1, f ); + count += pos - buffer; + return count; +} + +struct saved_key +{ + data_size_t namelen; + WCHAR *name; + data_size_t classlen; + WCHAR *class; + int value_count; + int subkey_count; + unsigned int is_symlink; + timeout_t modif; + struct saved_key *parent; +}; + +/* read serialized key data */ +static char *fill_saved_key( struct saved_key *key, struct saved_key *parent, char *data ) +{ + key->parent = parent; + key->namelen = *(data_size_t *)data; + data += sizeof(data_size_t); + key->name = (WCHAR *)data; + data += key->namelen; + key->classlen = *(data_size_t *)data; + data += sizeof(data_size_t); + key->class = (WCHAR *)data; + data += key->classlen; + key->value_count = *(int *)data; + data += sizeof(int); + key->subkey_count = *(int *)data; + data += sizeof(int); + key->is_symlink = *(unsigned int *)data; + data += sizeof(unsigned int); + key->modif = *(timeout_t *)data; + data += sizeof(timeout_t); + + return data; +} + +/* dump serialized key full path */ +static char *dump_parents( char *data, FILE *f, int count ) +{ + data_size_t len; + WCHAR *name; + + len = *(data_size_t *)data; + data += sizeof(data_size_t); + name = (WCHAR *)data; + data += len; + + if (count > 1) + { + data = dump_parents( data, f, count - 1); + fprintf( f, "\\\\" ); + } + dump_strW( name, len, f, "[]" ); + return data; +} + +/* dump the full path of a key */ +static void dump_path( const struct saved_key *key, const struct saved_key *base, FILE *f ) +{ + if (key->parent && key->parent != base) + { + dump_path( key->parent, base, f ); + fprintf( f, "\\\\" ); + } + dump_strW( key->name, key->namelen, f, "[]" ); +} + +/* dump a value to a text file */ +static char *dump_value( char *data, FILE *f ) +{ + unsigned int i, dw; + int count; + data_size_t namelen, valuelen; + char *valuedata; + WCHAR *name; + unsigned int type; + + namelen = *(data_size_t *)data; + data += sizeof(data_size_t); + name = (WCHAR *)data; + data += namelen; + type = *(unsigned int *)data; + data += sizeof(unsigned int); + valuelen = *(data_size_t *)data; + data += sizeof(data_size_t); + valuedata = data; + data += valuelen; + + if (namelen) + { + fputc( '\"', f ); + count = 1 + dump_strW( name, namelen, f, "\"\"" ); + count += fprintf( f, "\"=" ); + } + else count = fprintf( f, "@=" ); + + switch(type) + { + case REG_SZ: + case REG_EXPAND_SZ: + case REG_MULTI_SZ: + /* only output properly terminated strings in string format */ + if (valuelen < sizeof(WCHAR)) break; + if (valuelen % sizeof(WCHAR)) break; + if (((WCHAR *)valuedata)[valuelen / sizeof(WCHAR) - 1]) break; + if (type != REG_SZ) fprintf( f, "str(%x):", type ); + fputc( '\"', f ); + dump_strW( (WCHAR *)valuedata, valuelen, f, "\"\"" ); + fprintf( f, "\"\n" ); + return data; + + case REG_DWORD: + if (valuelen != sizeof(dw)) break; + memcpy( &dw, valuedata, sizeof(dw) ); + fprintf( f, "dword:%08x\n", dw ); + return data; + } + + if (type == REG_BINARY) count += fprintf( f, "hex:" ); + else count += fprintf( f, "hex(%x):", type ); + for (i = 0; i < valuelen; i++) + { + count += fprintf( f, "%02x", *((unsigned char *)valuedata + i) ); + if (i < valuelen-1) + { + fputc( ',', f ); + if (++count > 76) + { + fprintf( f, "\\\n " ); + count = 2; + } + } + } + fputc( '\n', f ); + return data; +} + +/* save a registry key and all its subkeys to a text file */ +static char *save_subkeys( char *data, struct saved_key *parent, struct saved_key *base, FILE *f ) +{ + struct saved_key key; + int i; + + if (!base) base = &key; + data = fill_saved_key( &key, parent, data ); + + /* save key if it has either some values or no subkeys, or needs special options */ + /* keys with no values but subkeys are saved implicitly by saving the subkeys */ + if ((key.value_count > 0) || !key.subkey_count || key.classlen || key.is_symlink) + { + fprintf( f, "\n[" ); + if (parent) dump_path( &key, base, f ); + fprintf( f, "] %u\n", (unsigned int)((key.modif - SECS_1601_TO_1970 * TICKSPERSEC) / TICKSPERSEC) ); + fprintf( f, "#time=%x%08x\n", (unsigned int)(key.modif >> 32), (unsigned int)key.modif ); + if (key.classlen) + { + fprintf( f, "#class=\"" ); + dump_strW( key.class, key.classlen, f, "\"\"" ); + fprintf( f, "\"\n" ); + } + if (key.is_symlink) fputs( "#link\n", f ); + for (i = 0; i < key.value_count; i++) data = dump_value( data, f ); + } + for (i = 0; i < key.subkey_count; i++) data = save_subkeys( data, &key, base, f ); + return data; +} + +/* save a registry branch to a file */ +static void save_all_subkeys( char *data, FILE *f ) +{ + enum prefix_type prefix_type; + int parent_count; + + prefix_type = *(int *)data; + data += sizeof(int); + + parent_count = *(int *)data; + data += sizeof(int); + + fprintf( f, "WINE REGISTRY Version 2\n" ); + fprintf( f, ";; All keys relative to " ); + data = dump_parents( data, f, parent_count ); + fprintf( f, "\n" ); + + switch (prefix_type) + { + case PREFIX_32BIT: + fprintf( f, "\n#arch=win32\n" ); + break; + case PREFIX_64BIT: + fprintf( f, "\n#arch=win64\n" ); + break; + default: + break; + } + save_subkeys( data, NULL, NULL, f ); +} + /****************************************************************************** * NtCreateKey (NTDLL.@) @@ -776,17 +1020,53 @@ NTSTATUS WINAPI NtUnloadKey( OBJECT_ATTRIBUTES *attr ) */ NTSTATUS WINAPI NtSaveKey( HANDLE key, HANDLE file ) { + data_size_t size = 0; unsigned int ret; + char *data = NULL; + int fd, fd2, needs_close = 0; + FILE *f; TRACE( "(%p,%p)\n", key, file ); - SERVER_START_REQ( save_registry ) + while (1) { - req->hkey = wine_server_obj_handle( key ); - req->file = wine_server_obj_handle( file ); - ret = wine_server_call( req ); + SERVER_START_REQ( save_registry ) + { + req->hkey = wine_server_obj_handle( key ); + if (size) wine_server_set_reply( req, data, size ); + ret = wine_server_call( req ); + size = reply->total; + } + SERVER_END_REQ; + + if (!ret) break; + free( data ); + if (ret != STATUS_BUFFER_TOO_SMALL) return ret; + if (!(data = malloc( size ))) + { + ERR( "No memory.\n" ); + return STATUS_NO_MEMORY; + } } - SERVER_END_REQ; + + if ((ret = server_get_unix_fd( file, FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL ))) goto done; + if ((fd2 = dup( fd )) == -1) + { + ret = errno_to_status( errno ); + goto done; + } + if (!(f = fdopen( fd2, "w" ))) + { + close( fd2 ); + ret = errno_to_status( errno ); + goto done; + } + save_all_subkeys( data, f ); + if (fclose(f)) ret = errno_to_status( errno ); + +done: + if (needs_close) close( fd ); + free( data ); return ret; } diff --git a/server/protocol.def b/server/protocol.def index 3f8e8118aca..8e9fd62c64e 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1917,11 +1917,19 @@ struct process_info @END -/* Save a registry branch to a file */ +/* Return full registry branch non-volatile data for saving */ @REQ(save_registry) - obj_handle_t hkey; /* key to save */ - obj_handle_t file; /* file to save to */ + obj_handle_t hkey; /* key to save */ +@REPLY + data_size_t total; /* total length needed for data */ + VARARG(data,bytes); /* registry data */ @END +enum prefix_type +{ + PREFIX_UNKNOWN, + PREFIX_32BIT, + PREFIX_64BIT, +}; /* Add a registry key change notification */ diff --git a/server/registry.c b/server/registry.c index b7761802f46..f2d2b64d4d9 100644 --- a/server/registry.c +++ b/server/registry.c @@ -124,7 +124,7 @@ static struct key *root_key; static const timeout_t ticks_1601_to_1970 = (timeout_t)86400 * (369 * 365 + 89) * TICKS_PER_SEC; static const timeout_t save_period = 30 * -TICKS_PER_SEC; /* delay between periodic saves */ static struct timeout_user *save_timeout_user; /* saving timer */ -static enum prefix_type { PREFIX_UNKNOWN, PREFIX_32BIT, PREFIX_64BIT } prefix_type; +static enum prefix_type prefix_type; static const WCHAR wow6432node[] = {'W','o','w','6','4','3','2','N','o','d','e'}; static const WCHAR symlink_value[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e'}; @@ -2022,29 +2022,104 @@ static void save_all_subkeys( struct key *key, FILE *f ) save_subkeys( key, key, f ); } -/* save a registry branch to a file handle */ -static void save_registry( struct key *key, obj_handle_t handle ) +static data_size_t serialize_value( const struct key_value *value, char *buf ) { - struct file *file; - int fd; + data_size_t size; - if (!(file = get_file_obj( current->process, handle, FILE_WRITE_DATA ))) return; - fd = dup( get_file_unix_fd( file ) ); - release_object( file ); - if (fd != -1) + size = sizeof(data_size_t) + value->namelen + sizeof(unsigned int) + sizeof(data_size_t) + value->len; + if (!buf) return size; + + *(data_size_t *)buf = value->namelen; + buf += sizeof(data_size_t); + memcpy( buf, value->name, value->namelen ); + buf += value->namelen; + + *(unsigned int *)buf = value->type; + buf += sizeof(unsigned int); + + *(data_size_t *)buf = value->len; + buf += sizeof(data_size_t); + memcpy( buf, value->data, value->len ); + + return size; +} + +/* save a registry key with subkeys to a buffer */ +static data_size_t serialize_key( const struct key *key, char *buf ) +{ + data_size_t size; + int subkey_count, i; + + if (key->flags & KEY_VOLATILE) return 0; + + size = sizeof(data_size_t) + key->obj.name->len + sizeof(data_size_t) + key->classlen + sizeof(int) + sizeof(int) + + sizeof(unsigned int) + sizeof(timeout_t); + for (i = 0; i <= key->last_value; i++) + size += serialize_value( &key->values[i], buf ? buf + size : NULL ); + subkey_count = 0; + for (i = 0; i <= key->last_subkey; i++) { - FILE *f = fdopen( fd, "w" ); - if (f) - { - save_all_subkeys( key, f ); - if (fclose( f )) file_set_error(); - } - else - { - file_set_error(); - close( fd ); - } + if (key->subkeys[i]->flags & KEY_VOLATILE) continue; + size += serialize_key( key->subkeys[i], buf ? buf + size : NULL ); + ++subkey_count; + } + if (!buf) return size; + + *(data_size_t *)buf = key->obj.name->len; + buf += sizeof(data_size_t); + memcpy( buf, key->obj.name->name, key->obj.name->len ); + buf += key->obj.name->len; + + *(data_size_t *)buf = key->classlen; + buf += sizeof(data_size_t); + memcpy( buf, key->class, key->classlen ); + buf += key->classlen; + + *(int *)buf = key->last_value + 1; + buf += sizeof(int); + + *(int *)buf = subkey_count; + buf += sizeof(int); + + *(unsigned int *)buf = key->flags & KEY_SYMLINK; + buf += sizeof(unsigned int); + + *(timeout_t *)buf = key->modif; + + return size; +} + +/* save registry branch to buffer */ +static data_size_t save_registry( const struct key *key, char *buf ) +{ + int *parent_count = NULL; + const struct key *parent; + data_size_t size; + + size = sizeof(int) + sizeof(int); + if (buf) + { + *(int *)buf = prefix_type; + buf += sizeof(int); + parent_count = (int *)buf; + buf += sizeof(int); + *parent_count = 0; } + + parent = key; + do + { + size += sizeof(data_size_t) + parent->obj.name->len; + if (!buf) continue; + ++*parent_count; + *(data_size_t *)buf = parent->obj.name->len; + buf += sizeof(data_size_t); + memcpy( buf, parent->obj.name->name, parent->obj.name->len ); + buf += parent->obj.name->len; + } while ((parent = get_parent( parent ))); + + size += serialize_key( key, buf ); + return size; } /* save a registry branch to a file */ @@ -2371,6 +2446,7 @@ DECL_HANDLER(unload_registry) DECL_HANDLER(save_registry) { struct key *key; + char *data; if (!thread_single_check_privilege( current, SeBackupPrivilege )) { @@ -2380,7 +2456,13 @@ DECL_HANDLER(save_registry) if ((key = get_hkey_obj( req->hkey, 0 ))) { - save_registry( key, req->file ); + reply->total = save_registry( key, NULL ); + if (reply->total <= get_reply_max_size()) + { + if ((data = set_reply_data_size( reply->total ))) + save_registry( key, data ); + } + else set_error( STATUS_BUFFER_TOO_SMALL ); release_object( key ); } } From f0b0daa3d477f505a16a7b790cd64de542b4a9be Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 20 Jun 2023 11:54:06 -0600 Subject: [PATCH 1563/2777] ntdll: Implement NtFlushKey(). CW-Bug-Id: #22347 --- dlls/ntdll/unix/registry.c | 155 +++++++++++++++++++++++++++++++++++-- server/protocol.def | 12 +++ server/registry.c | 94 ++++++++++++++++++++-- 3 files changed, 247 insertions(+), 14 deletions(-) diff --git a/dlls/ntdll/unix/registry.c b/dlls/ntdll/unix/registry.c index 595d4f7892d..d61c9f21732 100644 --- a/dlls/ntdll/unix/registry.c +++ b/dlls/ntdll/unix/registry.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include "ntstatus.h" #define WIN32_NO_STATUS @@ -282,8 +284,9 @@ static char *save_subkeys( char *data, struct saved_key *parent, struct saved_ke } /* save a registry branch to a file */ -static void save_all_subkeys( char *data, FILE *f ) +static char *save_all_subkeys( char *data, FILE *f ) { + /* Output registry format should match server/registry.c:save_all_subkeys(). */ enum prefix_type prefix_type; int parent_count; @@ -309,7 +312,7 @@ static void save_all_subkeys( char *data, FILE *f ) default: break; } - save_subkeys( data, NULL, NULL, f ); + return save_subkeys( data, NULL, NULL, f ); } @@ -901,22 +904,162 @@ NTSTATUS WINAPI NtNotifyChangeKey( HANDLE key, HANDLE event, PIO_APC_ROUTINE apc io, filter, subtree, buffer, length, async ); } +/* acquire mutex for registry flush operation */ +static HANDLE get_key_flush_mutex(void) +{ + WCHAR bufferW[256]; + UNICODE_STRING name = {.Buffer = bufferW}; + OBJECT_ATTRIBUTES attr; + char buffer[256]; + HANDLE mutex; + + snprintf( buffer, ARRAY_SIZE(buffer), "\\Sessions\\%u\\BaseNamedObjects\\__wine_regkey_flush", + (int)NtCurrentTeb()->Peb->SessionId ); + name.Length = name.MaximumLength = (strlen(buffer) + 1) * sizeof(WCHAR); + ascii_to_unicode( bufferW, buffer, name.Length / sizeof(WCHAR) ); + + InitializeObjectAttributes( &attr, &name, OBJ_OPENIF, NULL, NULL ); + if (NtCreateMutant( &mutex, MUTEX_ALL_ACCESS, &attr, FALSE ) < 0) return NULL; + NtWaitForSingleObject( mutex, FALSE, NULL ); + return mutex; +} + +/* release registry flush mutex */ +static void release_key_flush_mutex( HANDLE mutex ) +{ + NtReleaseMutant( mutex, NULL ); + NtClose( mutex ); +} + +/* save registry branch to Wine regsitry storage file */ +static NTSTATUS save_registry_branch( char **data ) +{ + static const char temp_fn[] = "savereg.tmp"; + char *file_name, *path = NULL, *tmp = NULL; + int file_name_len, path_len, fd; + struct stat st; + NTSTATUS ret; + FILE *f; + + file_name_len = *(int *)*data; + *data += sizeof(int); + file_name = *data; + *data += file_name_len; + + path_len = strlen( config_dir ) + 1 + file_name_len + 1; + if (!(path = malloc( path_len ))) return STATUS_NO_MEMORY; + sprintf( path, "%s/%s", config_dir, file_name ); + + if ((fd = open( path, O_WRONLY )) != -1) + { + /* if file is not a regular file or has multiple links or is accessed + * via symbolic links, write directly into it; otherwise use a temp file */ + if (!lstat( path, &st ) && (!S_ISREG(st.st_mode) || st.st_nlink > 1)) + { + ftruncate( fd, 0 ); + goto save; + } + close( fd ); + } + + /* create a temp file in the same directory */ + if (!(tmp = malloc( strlen( config_dir ) + 1 + strlen( temp_fn ) + 1 ))) + { + ret = STATUS_NO_MEMORY; + goto done; + } + sprintf( tmp, "%s/%s", config_dir, temp_fn ); + + if ((fd = open( tmp, O_CREAT | O_EXCL | O_WRONLY, 0666 )) == -1) + { + ret = errno_to_status( errno ); + goto done; + } + +save: + if (!(f = fdopen( fd, "w" ))) + { + ret = errno_to_status( errno ); + if (tmp) unlink( tmp ); + close( fd ); + goto done; + } + + *data = save_all_subkeys( *data, f ); + + ret = fclose( f ) ? errno_to_status( errno ) : STATUS_SUCCESS; + if (tmp) + { + if (!ret && rename( tmp, path )) ret = errno_to_status( errno ); + if (ret) unlink( tmp ); + } + +done: + free( tmp ); + free( path ); + return ret; +} /****************************************************************************** * NtFlushKey (NTDLL.@) */ NTSTATUS WINAPI NtFlushKey( HANDLE key ) { + abstime_t timestamp_counter; + data_size_t size = 0; unsigned int ret; + char *data = NULL, *curr_data; + HANDLE mutex; + int i, branch_count, branch; TRACE( "key=%p\n", key ); - SERVER_START_REQ( flush_key ) + mutex = get_key_flush_mutex(); + + while (1) { - req->hkey = wine_server_obj_handle( key ); - ret = wine_server_call( req ); + SERVER_START_REQ( flush_key ) + { + req->hkey = wine_server_obj_handle( key ); + if (size) wine_server_set_reply( req, data, size ); + ret = wine_server_call( req ); + size = reply->total; + branch_count = reply->branch_count; + timestamp_counter = reply->timestamp_counter; + } + SERVER_END_REQ; + + if (ret != STATUS_BUFFER_TOO_SMALL) break; + free( data ); + if (!(data = malloc( size ))) + { + ERR( "No memory.\n" ); + ret = STATUS_NO_MEMORY; + goto done; + } } - SERVER_END_REQ; + if (ret) goto done; + + curr_data = data; + for (i = 0; i < branch_count; ++i) + { + branch = *(int *)curr_data; + curr_data += sizeof(int); + if ((ret = save_registry_branch( &curr_data ))) goto done; + + SERVER_START_REQ( flush_key_done ) + { + req->branch = branch; + req->timestamp_counter = timestamp_counter; + ret = wine_server_call( req ); + } + SERVER_END_REQ; + if (ret) break; + } + +done: + release_key_flush_mutex( mutex ); + free( data ); return ret; } diff --git a/server/protocol.def b/server/protocol.def index 8e9fd62c64e..9589aacfbbc 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1837,6 +1837,18 @@ struct process_info /* Flush a registry key */ @REQ(flush_key) obj_handle_t hkey; /* handle to the key */ +@REPLY + abstime_t timestamp_counter; /* branch last change timestamp counter */ + data_size_t total; /* total length needed for data */ + int branch_count; /* number of registry branches to flush */ + VARARG(data,bytes); /* registry data */ +@END + + +/* Clear KEY_DIRTY after key flush */ +@REQ(flush_key_done) + abstime_t timestamp_counter; /* timestamp counter returned from flush_key */ + int branch; /* saved registry branch id */ @END diff --git a/server/registry.c b/server/registry.c index f2d2b64d4d9..ddfa78a155e 100644 --- a/server/registry.c +++ b/server/registry.c @@ -90,6 +90,7 @@ struct key unsigned int flags; /* flags */ timeout_t modif; /* last modification time */ struct list notify_list; /* list of notifications */ + abstime_t timestamp_counter; /* timestamp counter at last change */ }; /* key flags */ @@ -118,6 +119,8 @@ struct key_value #define MAX_NAME_LEN 256 /* max. length of a key name */ #define MAX_VALUE_LEN 16383 /* max. length of a value name */ +static abstime_t change_timestamp_counter; + /* the root of the registry tree */ static struct key *root_key; @@ -710,6 +713,7 @@ static struct key *create_key_object( struct object *parent, const struct unicod key->last_value = -1; key->values = NULL; key->modif = modif; + key->timestamp_counter = 0; list_init( &key->notify_list ); if (options & REG_OPTION_CREATE_LINK) key->flags |= KEY_SYMLINK; @@ -730,23 +734,25 @@ static struct key *create_key_object( struct object *parent, const struct unicod /* mark a key and all its parents as dirty (modified) */ static void make_dirty( struct key *key ) { + ++change_timestamp_counter; while (key) { if (key->flags & (KEY_DIRTY|KEY_VOLATILE)) return; /* nothing to do */ key->flags |= KEY_DIRTY; + key->timestamp_counter = change_timestamp_counter; key = get_parent( key ); } } /* mark a key and all its subkeys as clean (not modified) */ -static void make_clean( struct key *key ) +static void make_clean( struct key *key, abstime_t timestamp_counter ) { int i; if (key->flags & KEY_VOLATILE) return; if (!(key->flags & KEY_DIRTY)) return; - key->flags &= ~KEY_DIRTY; - for (i = 0; i <= key->last_subkey; i++) make_clean( key->subkeys[i] ); + if (key->timestamp_counter <= timestamp_counter) key->flags &= ~KEY_DIRTY; + for (i = 0; i <= key->last_subkey; i++) make_clean( key->subkeys[i], timestamp_counter ); } /* go through all the notifications and send them if necessary */ @@ -2004,6 +2010,7 @@ void init_registry(void) /* save a registry branch to a file */ static void save_all_subkeys( struct key *key, FILE *f ) { + /* Registry format in ntdll/registry.c:save_all_subkeys() should match. */ fprintf( f, "WINE REGISTRY Version 2\n" ); fprintf( f, ";; All keys relative to " ); dump_path( key, NULL, f ); @@ -2192,7 +2199,7 @@ static int save_branch( struct key *key, const char *path ) done: free( tmp ); - if (ret) make_clean( key ); + if (ret) make_clean( key, key->timestamp_counter ); return ret; } @@ -2240,6 +2247,36 @@ static int is_wow64_thread( struct thread *thread ) return (is_machine_64bit( native_machine ) && !is_machine_64bit( thread->process->machine )); } +/* find all the branches inside the specified key or the branch containing the key */ +static void find_branches_for_key( struct key *key, int *branches, int *branch_count ) +{ + struct key *k; + int i; + + *branch_count = 0; + for (i = 0; i < save_branch_count; i++) + { + k = save_branch_info[i].key; + while ((k = get_parent(k))) + { + if (k != key) continue; + branches[(*branch_count)++] = i; + break; + } + } + + if (*branch_count) return; + + do + { + for (i = 0; i < save_branch_count; i++) + { + if(key != save_branch_info[i].key) continue; + branches[(*branch_count)++] = i; + return; + } + } while ((key = get_parent( key ))); +} /* create a registry key */ DECL_HANDLER(create_key) @@ -2304,15 +2341,56 @@ DECL_HANDLER(delete_key) } } -/* flush a registry key */ +/* return registry branches snaphot data for flushing key */ DECL_HANDLER(flush_key) { struct key *key = get_hkey_obj( req->hkey, 0 ); - if (key) + int branches[3], branch_count = 0, i, path_len; + char *data; + + if (!key) return; + + reply->total = 0; + reply->branch_count = 0; + if ((key->flags & KEY_DIRTY) && !(key->flags & KEY_VOLATILE)) + find_branches_for_key( key, branches, &branch_count ); + release_object( key ); + + reply->timestamp_counter = change_timestamp_counter; + for (i = 0; i < branch_count; ++i) { - /* we don't need to do anything here with the current implementation */ - release_object( key ); + if (!(save_branch_info[branches[i]].key->flags & KEY_DIRTY)) continue; + ++reply->branch_count; + path_len = strlen( save_branch_info[branches[i]].path ) + 1; + reply->total += sizeof(int) + sizeof(int) + path_len + save_registry( save_branch_info[branches[i]].key, NULL ); + } + if (reply->total > get_reply_max_size()) + { + set_error( STATUS_BUFFER_TOO_SMALL ); + return; } + + if (!(data = set_reply_data_size( reply->total ))) return; + + for (i = 0; i < branch_count; ++i) + { + if (!(save_branch_info[branches[i]].key->flags & KEY_DIRTY)) continue; + *(int *)data = branches[i]; + data += sizeof(int); + path_len = strlen( save_branch_info[branches[i]].path ) + 1; + *(int *)data = path_len; + data += sizeof(int); + memcpy( data, save_branch_info[branches[i]].path, path_len ); + data += path_len; + data += save_registry( save_branch_info[branches[i]].key, data ); + } +} + +/* clear dirty state after successful registry branch flush */ +DECL_HANDLER(flush_key_done) +{ + if (req->branch < save_branch_count) make_clean( save_branch_info[req->branch].key, req->timestamp_counter ); + else set_error( STATUS_INVALID_PARAMETER ); } /* enumerate registry subkeys */ From 1e2dd1c5f48d431ab37d149175b5ecbcd062db25 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 20 Jun 2023 12:17:36 -0600 Subject: [PATCH 1564/2777] mountmgr.sys: Perform periodic registry flush instead of server. CW-Bug-Id: #22347 --- dlls/mountmgr.sys/mountmgr.c | 22 ++++++++++++++++++++++ server/registry.c | 26 -------------------------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/dlls/mountmgr.sys/mountmgr.c b/dlls/mountmgr.sys/mountmgr.c index 9f72eedb33b..a04449a6aa1 100644 --- a/dlls/mountmgr.sys/mountmgr.c +++ b/dlls/mountmgr.sys/mountmgr.c @@ -611,6 +611,27 @@ static DWORD WINAPI run_loop_thread( void *arg ) return MOUNTMGR_CALL( run_loop, ¶ms ); } +static DWORD WINAPI registry_flush_thread( void *arg ) +{ + UNICODE_STRING name = RTL_CONSTANT_STRING( L"\\Registry" ); + OBJECT_ATTRIBUTES attr; + HANDLE root; + + InitializeObjectAttributes( &attr, &name, 0, 0, NULL ); + if (NtOpenKeyEx( &root, MAXIMUM_ALLOWED, &attr, 0 )) + { + ERR( "Failed opening root registry key.\n" ); + return 0; + } + + for (;;) + { + Sleep( 30000 ); + if (NtFlushKey( root )) ERR( "Failed flushing registry.\n" ); + } + + return 0; +} /* main entry point for the mount point manager driver */ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) @@ -653,6 +674,7 @@ NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) thread = CreateThread( NULL, 0, device_op_thread, NULL, 0, NULL ); CloseHandle( CreateThread( NULL, 0, run_loop_thread, thread, 0, NULL )); + CloseHandle( CreateThread( NULL, 0, registry_flush_thread, thread, 0, NULL )); #ifdef _WIN64 /* create a symlink so that the Wine port overrides key can be edited with 32-bit reg or regedit */ diff --git a/server/registry.c b/server/registry.c index ddfa78a155e..c3cf9ba7dfa 100644 --- a/server/registry.c +++ b/server/registry.c @@ -125,15 +125,12 @@ static abstime_t change_timestamp_counter; static struct key *root_key; static const timeout_t ticks_1601_to_1970 = (timeout_t)86400 * (369 * 365 + 89) * TICKS_PER_SEC; -static const timeout_t save_period = 30 * -TICKS_PER_SEC; /* delay between periodic saves */ -static struct timeout_user *save_timeout_user; /* saving timer */ static enum prefix_type prefix_type; static const WCHAR wow6432node[] = {'W','o','w','6','4','3','2','N','o','d','e'}; static const WCHAR symlink_value[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e'}; static const struct unicode_str symlink_str = { symlink_value, sizeof(symlink_value) }; -static void set_periodic_save_timer(void); static struct key_value *find_value( const struct key *key, const struct unicode_str *name, int *index ); /* information about where to save a registry branch */ @@ -1983,9 +1980,6 @@ void init_registry(void) release_object( hklm ); release_object( hkcu ); - /* start the periodic save timer */ - set_periodic_save_timer(); - /* create windows directories */ if (!mkdir( "drive_c/windows", 0777 )) @@ -2203,26 +2197,6 @@ static int save_branch( struct key *key, const char *path ) return ret; } -/* periodic saving of the registry */ -static void periodic_save( void *arg ) -{ - int i; - - if (fchdir( config_dir_fd ) == -1) return; - save_timeout_user = NULL; - for (i = 0; i < save_branch_count; i++) - save_branch( save_branch_info[i].key, save_branch_info[i].path ); - if (fchdir( server_dir_fd ) == -1) fatal_error( "chdir to server dir: %s\n", strerror( errno )); - set_periodic_save_timer(); -} - -/* start the periodic save timer */ -static void set_periodic_save_timer(void) -{ - if (save_timeout_user) remove_timeout_user( save_timeout_user ); - save_timeout_user = add_timeout_user( save_period, periodic_save, NULL ); -} - /* save the modified registry branches to disk */ void flush_registry(void) { From d9472aa94da6b2fd29ceac5b0ffddbd10036b75d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 26 Jun 2023 15:30:13 -0600 Subject: [PATCH 1565/2777] rsaenh: Store keys as volatile for SF6. CW-Bug-Id: #22347 --- dlls/rsaenh/rsaenh.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/dlls/rsaenh/rsaenh.c b/dlls/rsaenh/rsaenh.c index 3a2d7126ca4..3e4646a9517 100644 --- a/dlls/rsaenh/rsaenh.c +++ b/dlls/rsaenh/rsaenh.c @@ -1211,9 +1211,20 @@ static void store_key_permissions(HCRYPTKEY hCryptKey, HKEY hKey, DWORD dwKeySpe */ static BOOL create_container_key(KEYCONTAINER *pKeyContainer, REGSAM sam, HKEY *phKey) { + static DWORD key_options = ~0ul; CHAR szRSABase[sizeof(RSAENH_REGKEY) + MAX_PATH]; HKEY hRootKey; + if (key_options == ~0ul) + { + const char *sgi; + + if ((sgi = getenv("SteamGameId")) && !strcmp(sgi, "1364780")) + key_options = REG_OPTION_VOLATILE; + else + key_options = REG_OPTION_NON_VOLATILE; + } + sprintf(szRSABase, RSAENH_REGKEY, pKeyContainer->szName); if (pKeyContainer->dwFlags & CRYPT_MACHINE_KEYSET) @@ -1224,7 +1235,7 @@ static BOOL create_container_key(KEYCONTAINER *pKeyContainer, REGSAM sam, HKEY * /* @@ Wine registry key: HKLM\Software\Wine\Crypto\RSA */ /* @@ Wine registry key: HKCU\Software\Wine\Crypto\RSA */ return RegCreateKeyExA(hRootKey, szRSABase, 0, NULL, - REG_OPTION_NON_VOLATILE, sam, NULL, phKey, NULL) + key_options, sam, NULL, phKey, NULL) == ERROR_SUCCESS; } From 99b91608bed91d4053313858b73bb26ebd5845cf Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 29 Aug 2023 19:13:56 -0600 Subject: [PATCH 1566/2777] user32/tests: Test more flags for MessageBox. (cherry picked from commit adf77c1abe6af1dfa746a5299c772947c575070a) CW-Bug-Id: #22663 --- dlls/user32/tests/dialog.c | 72 +++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/dlls/user32/tests/dialog.c b/dlls/user32/tests/dialog.c index 21958ddb193..99f52769e73 100644 --- a/dlls/user32/tests/dialog.c +++ b/dlls/user32/tests/dialog.c @@ -2123,15 +2123,36 @@ static void test_timer_message(void) DialogBoxA(g_hinst, "RADIO_TEST_DIALOG", NULL, timer_message_dlg_proc); } +static unsigned int msgbox_hook_proc_called; +static UINT msgbox_type; + static LRESULT CALLBACK msgbox_hook_proc(INT code, WPARAM wParam, LPARAM lParam) { + static const LONG considered_ex_styles = WS_EX_CONTROLPARENT | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME | WS_EX_TOPMOST; + if (code == HCBT_ACTIVATE) { HWND msgbox = (HWND)wParam, msghwnd; + LONG exstyles, expected_exstyles; + BOOL system_modal; char text[64]; if (msgbox) { + exstyles = GetWindowLongA(msgbox, GWL_EXSTYLE) & considered_ex_styles; + + ++msgbox_hook_proc_called; + system_modal = msgbox_type & MB_SYSTEMMODAL && !(msgbox_type & MB_TASKMODAL); + expected_exstyles = WS_EX_CONTROLPARENT | WS_EX_WINDOWEDGE; + if ((msgbox_type & MB_TOPMOST) || system_modal) + expected_exstyles |= WS_EX_TOPMOST; + if (!system_modal) + expected_exstyles |= WS_EX_DLGMODALFRAME; + + todo_wine_if((system_modal && exstyles == (expected_exstyles | WS_EX_DLGMODALFRAME)) + || (!system_modal && msgbox_type & MB_TOPMOST)) + ok(exstyles == expected_exstyles, "got %#lx, expected %#lx\n", exstyles, expected_exstyles); + text[0] = 0; GetWindowTextA(msgbox, text, sizeof(text)); ok(!strcmp(text, "MSGBOX caption"), "Unexpected window text \"%s\"\n", text); @@ -2141,26 +2162,9 @@ static LRESULT CALLBACK msgbox_hook_proc(INT code, WPARAM wParam, LPARAM lParam) text[0] = 0; GetWindowTextA(msghwnd, text, sizeof(text)); - ok(!strcmp(text, "Text"), "Unexpected window text \"%s\"\n", text); - - SendDlgItemMessageA(msgbox, IDCANCEL, WM_LBUTTONDOWN, 0, 0); - SendDlgItemMessageA(msgbox, IDCANCEL, WM_LBUTTONUP, 0, 0); - } - } - - return CallNextHookEx(NULL, code, wParam, lParam); -} - -static LRESULT CALLBACK msgbox_sysmodal_hook_proc(INT code, WPARAM wParam, LPARAM lParam) -{ - if (code == HCBT_ACTIVATE) - { - HWND msgbox = (HWND)wParam; - LONG exstyles = GetWindowLongA(msgbox, GWL_EXSTYLE); - if (msgbox) - { - ok(exstyles & WS_EX_TOPMOST, "expected message box to have topmost exstyle set\n"); + todo_wine_if(msgbox_type != MB_OKCANCEL && !*text) + ok(!strcmp(text, "Text"), "Unexpected window text \"%s\"\n", text); SendDlgItemMessageA(msgbox, IDCANCEL, WM_LBUTTONDOWN, 0, 0); SendDlgItemMessageA(msgbox, IDCANCEL, WM_LBUTTONUP, 0, 0); @@ -2172,20 +2176,32 @@ static LRESULT CALLBACK msgbox_sysmodal_hook_proc(INT code, WPARAM wParam, LPARA static void test_MessageBox(void) { + static const UINT tests[] = + { + MB_OKCANCEL, + MB_OKCANCEL | MB_SYSTEMMODAL, + MB_OKCANCEL | MB_TASKMODAL | MB_SYSTEMMODAL, + MB_OKCANCEL | MB_TOPMOST, + MB_OKCANCEL | MB_TOPMOST | MB_SYSTEMMODAL, + MB_OKCANCEL | MB_TASKMODAL | MB_TOPMOST, + MB_OKCANCEL | MB_TASKMODAL | MB_SYSTEMMODAL | MB_TOPMOST, + }; + unsigned int i; HHOOK hook; int ret; hook = SetWindowsHookExA(WH_CBT, msgbox_hook_proc, NULL, GetCurrentThreadId()); - ret = MessageBoxA(NULL, "Text", "MSGBOX caption", MB_OKCANCEL); - ok(ret == IDCANCEL, "got %d\n", ret); - - UnhookWindowsHookEx(hook); - - /* Test for MB_SYSTEMMODAL */ - hook = SetWindowsHookExA(WH_CBT, msgbox_sysmodal_hook_proc, NULL, GetCurrentThreadId()); - - MessageBoxA(NULL, NULL, "system modal", MB_OKCANCEL | MB_SYSTEMMODAL); + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + msgbox_type = tests[i]; + winetest_push_context("type %#x", msgbox_type); + msgbox_hook_proc_called = 0; + ret = MessageBoxA(NULL, "Text", "MSGBOX caption", msgbox_type); + ok(ret == IDCANCEL, "got %d\n", ret); + ok(msgbox_hook_proc_called, "got %u.\n", msgbox_hook_proc_called); + winetest_pop_context(); + } UnhookWindowsHookEx(hook); } From bbe155c2f5f7745595ed4543c770b80b9261a517 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 29 Aug 2023 18:19:44 -0600 Subject: [PATCH 1567/2777] user32/msgbox: Implement MB_TOPMOST. (cherry picked from commit b34c21637682673ca9c822e13e915df52232db35) CW-Bug-Id: #22663 --- dlls/user32/msgbox.c | 6 ++++-- dlls/user32/tests/dialog.c | 3 +-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/dlls/user32/msgbox.c b/dlls/user32/msgbox.c index 4a14a868c73..4d345777a10 100644 --- a/dlls/user32/msgbox.c +++ b/dlls/user32/msgbox.c @@ -110,10 +110,12 @@ static void MSGBOX_OnInit(HWND hwnd, LPMSGBOXPARAMSW lpmb) } /* handle modal message boxes */ - if (((lpmb->dwStyle & MB_TASKMODAL) && (lpmb->hwndOwner==NULL))) - NtUserSetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE ); + if (lpmb->dwStyle & MB_TASKMODAL && lpmb->hwndOwner == NULL) + NtUserSetWindowPos( hwnd, lpmb->dwStyle & MB_TOPMOST ? HWND_TOPMOST : HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE ); else if (lpmb->dwStyle & MB_SYSTEMMODAL) NtUserSetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED ); + else if (lpmb->dwStyle & MB_TOPMOST) + NtUserSetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE ); TRACE_(msgbox)("%s\n", debugstr_w(lpszText)); SetWindowTextW(GetDlgItem(hwnd, MSGBOX_IDTEXT), lpszText); diff --git a/dlls/user32/tests/dialog.c b/dlls/user32/tests/dialog.c index 99f52769e73..a24bfafd0b9 100644 --- a/dlls/user32/tests/dialog.c +++ b/dlls/user32/tests/dialog.c @@ -2149,8 +2149,7 @@ static LRESULT CALLBACK msgbox_hook_proc(INT code, WPARAM wParam, LPARAM lParam) if (!system_modal) expected_exstyles |= WS_EX_DLGMODALFRAME; - todo_wine_if((system_modal && exstyles == (expected_exstyles | WS_EX_DLGMODALFRAME)) - || (!system_modal && msgbox_type & MB_TOPMOST)) + todo_wine_if(system_modal && exstyles == (expected_exstyles | WS_EX_DLGMODALFRAME)) ok(exstyles == expected_exstyles, "got %#lx, expected %#lx\n", exstyles, expected_exstyles); text[0] = 0; From 99e137127778d328ae48c4aa875324c31910f2ec Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 29 Aug 2023 19:54:02 -0600 Subject: [PATCH 1568/2777] dinput: Unregister raw input on foreground loss. (cherry picked from commit 546f823ed17f6c28a7e32a5c66918557eba19ca4) CW-Bug-Id: #22663 --- dlls/dinput/dinput_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index c99729a3770..e4e9b21cfc5 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -322,13 +322,13 @@ static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPAR case NOTIFY_THREAD_STOP: state->running = FALSE; break; + case NOTIFY_FOREGROUND_LOST: + handle_foreground_lost( (HWND)lparam ); + /* fallthrough */ case NOTIFY_REFRESH_DEVICES: while (state->devices_count--) dinput_device_internal_release( state->devices[state->devices_count] ); input_thread_update_device_list( state ); break; - case NOTIFY_FOREGROUND_LOST: - handle_foreground_lost( (HWND)lparam ); - break; } return 0; From dc5fc234045bd3b332b24313cf29c1931e40e9aa Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Thu, 17 Aug 2023 10:16:37 +0200 Subject: [PATCH 1569/2777] msvcrt/tests: Add tests for freopen(). Signed-off-by: Eric Pouech (cherry picked from commit 65b6e237cdc142bb0dbc9fb48be0c1592a6b80f9) CW-Bug-Id: #22710 --- dlls/msvcrt/tests/file.c | 74 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/dlls/msvcrt/tests/file.c b/dlls/msvcrt/tests/file.c index 3f57b3f871f..51ba4225032 100644 --- a/dlls/msvcrt/tests/file.c +++ b/dlls/msvcrt/tests/file.c @@ -1167,6 +1167,79 @@ static void test_fputwc(void) _unlink(tempfile); } +static void test_freopen( void ) +{ + char filename1[8] = "AXXXXXX"; + char filename2[8] = "BXXXXXX"; + FILE *file; + FILE *new; + int ret; + int fd; + char ch; + long pos; + + mktemp(filename1); + mktemp(filename2); + + file = fopen(filename1, "wt"); + ok(file != NULL, "fopen(filename1) returned NULL\n"); + ret = fwrite("1", 1, 1, file); + ok(ret == 1, "fwrite() returned %d (%d)\n", ret, errno); + ret = fclose(file); + ok(ret == 0, "fclose() returned %d\n", ret); + + file = fopen(filename2, "wt"); + ok(file != NULL, "fopen(filename1) returned NULL\n"); + ret = fwrite("2", 1, 1, file); + ok(ret == 1, "fwrite() returned %d (%d)\n", ret, errno); + ret = fclose(file); + ok(ret == 0, "fclose() returned %d\n", ret); + + file = fopen(filename1, "rt"); + ok(file != NULL, "fopen(filename1) returned NULL\n"); + file = freopen(filename2, "rt", file); + ok(file != NULL, "fopen(filename2) returned NULL\n"); + ch = '#'; + ret = fread(&ch, 1, 1, file); + ok(ret == 1, "fread() returned %d\n", ret); + ok(ch == '2', "fread() read %c\n", ch); + ret = fclose(file); + ok(ret == 0, "fclose() returned %d\n", ret); + + file = fopen(filename1, "at"); + ok(file != NULL, "fopen(filename1) returned NULL\n"); + file = freopen(filename1, "rt", file); + ok(file != NULL, "fopen(filename1) returned NULL\n"); + pos = ftell(file); + ok(pos == 0, "ftell() returned %ld\n", pos); + ch = '#'; + ret = fread(&ch, 1, 1, file); + ok(ret == 1, "fread() returned %d\n", ret); + ok(ch == '1', "fread() read %c\n", ch); + ret = fclose(file); + ok(ret == 0, "fclose() returned %d\n", ret); + + file = fopen(filename1, "rt"); + ok(file != NULL, "fopen(filename1) returned NULL\n"); + fd = fileno(file); + ok(fd > 0, "fileno() returned %d\n", fd); + /* invalid filename */ + new = freopen("_:", "rt", file); + ok(new == NULL, "fopen(_:) returned non NULL\n"); + errno = 0xdeadbeef; + ch = '#'; + ret = read(fd, &ch, 1); + ok(ret == -1, "read() returned %d\n", ret); + ok(errno == EBADF, "errno is %d\n", errno); + errno = 0xdeadbeef; + ret = fclose(file); + ok(ret == EOF, "fclose(file) succeeded\n"); + ok(errno == 0xdeadbeef, "errno is %d\n", errno); + + unlink(filename1); + unlink(filename2); +} + static void test_ctrlz( void ) { char* tempf; @@ -2977,6 +3050,7 @@ START_TEST(file) test_fgetwc_locale("AB\x83\xa9", "C", 0); test_fgetwc_unicode(); test_fputwc(); + test_freopen(); test_ctrlz(); test_file_put_get(); test_tmpnam(); From d980475ebdf31e897e3fc91c9a87250a450ee5a9 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Thu, 17 Aug 2023 10:16:37 +0200 Subject: [PATCH 1570/2777] msvcrt: Fix freopen() on FILE with invalid underlying fd. Signed-off-by: Eric Pouech (cherry picked from commit 626f8d75e8b525e736c31f1e4f767a26d66c89af) CW-Bug-Id: #22710 --- dlls/msvcrt/file.c | 4 +--- dlls/msvcrt/tests/file.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/dlls/msvcrt/file.c b/dlls/msvcrt/file.c index 8a9c89b9be5..3611396d406 100644 --- a/dlls/msvcrt/file.c +++ b/dlls/msvcrt/file.c @@ -4605,9 +4605,7 @@ FILE* CDECL _wfreopen(const wchar_t *path, const wchar_t *mode, FILE* file) TRACE(":path (%s) mode (%s) file (%p) fd (%d)\n", debugstr_w(path), debugstr_w(mode), file, file ? file->_file : -1); LOCK_FILES(); - if (!file || ((fd = file->_file) < 0)) - file = NULL; - else + if (file) { fclose(file); if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1) diff --git a/dlls/msvcrt/tests/file.c b/dlls/msvcrt/tests/file.c index 51ba4225032..15f18a395c8 100644 --- a/dlls/msvcrt/tests/file.c +++ b/dlls/msvcrt/tests/file.c @@ -1236,6 +1236,25 @@ static void test_freopen( void ) ok(ret == EOF, "fclose(file) succeeded\n"); ok(errno == 0xdeadbeef, "errno is %d\n", errno); + file = fopen(filename1, "rb"); + ok(file != NULL, "couldn't open %s\n", filename1); + close(file->_file); + file->_file = -1; + + new = freopen(filename2, "rb", file); + ok(new == file, "freopen() didn't return same FILE*\n"); + + fd = fileno(file); + ok(fd > 0, "fileno() returned %d\n", fd); + + ch = '#'; + ret = fread(&ch, 1, 1, file); + ok(ret == 1, "fread() returned %d\n", ret); + ok(ch == '2', "Unexpected char\n"); + + ret = fclose(file); + ok(ret == 0, "fclose(file) returned %d\n", ret); + unlink(filename1); unlink(filename2); } From 6d90a7f4ddad5bb7219e830113a1b93d53b1442e Mon Sep 17 00:00:00 2001 From: Victor Chiletto Date: Mon, 5 Jun 2023 19:59:14 -0300 Subject: [PATCH 1571/2777] msvcr110/tests: Add tests for new setlocale behaviors. A bunch of locales had changes >= msvcr 110. (cherry picked from commit fbbe8e26be898770e98307ed3a9789ba06b5cff9) CW-Bug-Id: #19646 --- dlls/msvcr110/tests/msvcr110.c | 78 ++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/dlls/msvcr110/tests/msvcr110.c b/dlls/msvcr110/tests/msvcr110.c index 255c68b0796..cf76720d806 100644 --- a/dlls/msvcr110/tests/msvcr110.c +++ b/dlls/msvcr110/tests/msvcr110.c @@ -152,6 +152,84 @@ static void test_setlocale(void) ret = p_setlocale(LC_ALL, "en-us.1250"); ok(!ret, "setlocale(en-us.1250) succeeded (%s)\n", ret); + ret = p_setlocale(LC_ALL, "zh-Hans"); + todo_wine ok((ret != NULL + || broken(ret == NULL)), /* Vista */ + "expected success, but got NULL\n"); + if (ret) + ok(!strcmp(ret, "zh-Hans"), "setlocale zh-Hans failed\n"); + + ret = p_setlocale(LC_ALL, "zh-Hant"); + todo_wine ok((ret != NULL + || broken(ret == NULL)), /* Vista */ + "expected success, but got NULL\n"); + if (ret) + ok(!strcmp(ret, "zh-Hant"), "setlocale zh-Hant failed\n"); + + /* used to return Chinese (Simplified)_China.936 */ + ret = p_setlocale(LC_ALL, "chinese"); + ok(ret != NULL, "expected success, but got NULL\n"); + if (ret) + todo_wine ok((!strcmp(ret, "Chinese_China.936") + || broken(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936")) /* Vista */ + || broken(!strcmp(ret, "Chinese_People's Republic of China.936"))), /* 7 */ + "setlocale chinese failed, got %s\n", ret); + + /* used to return Chinese (Simplified)_China.936 */ + ret = p_setlocale(LC_ALL, "Chinese_China.936"); + ok(ret != NULL, "expected success, but got NULL\n"); + if (ret) + todo_wine ok((!strcmp(ret, "Chinese_China.936") + || broken(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936")) /* Vista */ + || broken(!strcmp(ret, "Chinese_People's Republic of China.936"))), /* 7 */ + "setlocale Chinese_China.936 failed, got %s\n", ret); + + /* used to return Chinese (Simplified)_China.936 */ + ret = p_setlocale(LC_ALL, "chinese-simplified"); + ok(ret != NULL, "expected success, but got NULL\n"); + if (ret) + todo_wine ok((!strcmp(ret, "Chinese_China.936") + || broken(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936"))), /* Vista */ + "setlocale chinese-simplified failed, got %s\n", ret); + + /* used to return Chinese (Simplified)_China.936 */ + ret = p_setlocale(LC_ALL, "chs"); + ok(ret != NULL, "expected success, but got NULL\n"); + if (ret) + todo_wine ok((!strcmp(ret, "Chinese_China.936") + || broken(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936"))), /* Vista */ + "setlocale chs failed, got %s\n", ret); + + /* used to return Chinese (Traditional)_Taiwan.950 */ + ret = p_setlocale(LC_ALL, "cht"); + ok(ret != NULL, "expected success, but got NULL\n"); + if (ret) + todo_wine ok((!strcmp(ret, "Chinese (Traditional)_Hong Kong SAR.950") + || broken(!strcmp(ret, "Chinese (Traditional)_Taiwan.950"))), /* Vista - 7 */ + "setlocale cht failed, got %s\n", ret); + + /* used to return Chinese (Traditional)_Taiwan.950 */ + ret = p_setlocale(LC_ALL, "chinese-traditional"); + ok(ret != NULL, "expected success, but got NULL\n"); + if (ret) + todo_wine ok((!strcmp(ret, "Chinese (Traditional)_Hong Kong SAR.950") + || broken(!strcmp(ret, "Chinese (Traditional)_Taiwan.950"))), /* Vista - 7 */ + "setlocale chinese-traditional failed, got %s\n", ret); + + ret = p_setlocale(LC_ALL, "norwegian-nynorsk"); + ok(ret != NULL, "expected success, but got NULL\n"); + if (ret) + todo_wine ok((!strcmp(ret, "Norwegian Nynorsk_Norway.1252") + || broken(!strcmp(ret, "Norwegian (Nynorsk)_Norway.1252"))), /* Vista - 7 */ + "setlocale norwegian-nynorsk failed, got %s\n", ret); + + ret = p_setlocale(LC_ALL, "non"); + ok(ret != NULL, "expected success, but got NULL\n"); + if (ret) + todo_wine ok((!strcmp(ret, "Norwegian Nynorsk_Norway.1252") + || broken(!strcmp(ret, "Norwegian (Nynorsk)_Norway.1252"))), /* Vista - 7 */ + "setlocale norwegian-nynorsk failed, got %s\n", ret); + p_setlocale(LC_ALL, "C"); } From 555c764a32510552219c4a2a5c1e931066839eac Mon Sep 17 00:00:00 2001 From: Victor Chiletto Date: Wed, 7 Jun 2023 17:46:59 -0300 Subject: [PATCH 1572/2777] msvcr120/tests: Check ___lc_locale_name_func with neutral Chinese locales. (cherry picked from commit 969e3626bbcc7bd9ad6bca2d368f0bb67e306786) CW-Bug-Id: #19646 --- dlls/msvcr120/tests/msvcr120.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c index 0a4fb383e0e..b8950288afe 100644 --- a/dlls/msvcr120/tests/msvcr120.c +++ b/dlls/msvcr120/tests/msvcr120.c @@ -596,6 +596,14 @@ static void test____lc_locale_name_func(void) } } + p_setlocale(LC_ALL, "zh-Hans"); + lc_names = p____lc_locale_name_func(); + todo_wine ok(!lstrcmpW(lc_names[1], L"zh-Hans"), "lc_names[1] expected zh-Hans got %s\n", wine_dbgstr_w(lc_names[1])); + + p_setlocale(LC_ALL, "zh-Hant"); + lc_names = p____lc_locale_name_func(); + todo_wine ok(!lstrcmpW(lc_names[1], L"zh-Hant"), "lc_names[1] expected zh-Hant got %s\n", wine_dbgstr_w(lc_names[1])); + p_setlocale(LC_ALL, "C"); lc_names = p____lc_locale_name_func(); ok(!lc_names[1], "___lc_locale_name_func()[1] = %s\n", wine_dbgstr_w(lc_names[1])); From 253bc0c2c277fb1a36723ffdec4fbe99c811f682 Mon Sep 17 00:00:00 2001 From: Victor Chiletto Date: Thu, 8 Jun 2023 15:14:57 -0300 Subject: [PATCH 1573/2777] msvcrt: Use snames instead of LCIDs in create_locinfo. (cherry picked from commit 24a2b625545f1875b5c3177f2b9da1b7299b864f) CW-Bug-Id: #19646 --- dlls/msvcr110/tests/msvcr110.c | 12 +- dlls/msvcrt/locale.c | 459 ++++++++++++++++++--------------- 2 files changed, 257 insertions(+), 214 deletions(-) diff --git a/dlls/msvcr110/tests/msvcr110.c b/dlls/msvcr110/tests/msvcr110.c index cf76720d806..60d876e3bfc 100644 --- a/dlls/msvcr110/tests/msvcr110.c +++ b/dlls/msvcr110/tests/msvcr110.c @@ -170,7 +170,7 @@ static void test_setlocale(void) ret = p_setlocale(LC_ALL, "chinese"); ok(ret != NULL, "expected success, but got NULL\n"); if (ret) - todo_wine ok((!strcmp(ret, "Chinese_China.936") + ok((!strcmp(ret, "Chinese_China.936") || broken(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936")) /* Vista */ || broken(!strcmp(ret, "Chinese_People's Republic of China.936"))), /* 7 */ "setlocale chinese failed, got %s\n", ret); @@ -179,7 +179,7 @@ static void test_setlocale(void) ret = p_setlocale(LC_ALL, "Chinese_China.936"); ok(ret != NULL, "expected success, but got NULL\n"); if (ret) - todo_wine ok((!strcmp(ret, "Chinese_China.936") + ok((!strcmp(ret, "Chinese_China.936") || broken(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936")) /* Vista */ || broken(!strcmp(ret, "Chinese_People's Republic of China.936"))), /* 7 */ "setlocale Chinese_China.936 failed, got %s\n", ret); @@ -188,7 +188,7 @@ static void test_setlocale(void) ret = p_setlocale(LC_ALL, "chinese-simplified"); ok(ret != NULL, "expected success, but got NULL\n"); if (ret) - todo_wine ok((!strcmp(ret, "Chinese_China.936") + ok((!strcmp(ret, "Chinese_China.936") || broken(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936"))), /* Vista */ "setlocale chinese-simplified failed, got %s\n", ret); @@ -196,7 +196,7 @@ static void test_setlocale(void) ret = p_setlocale(LC_ALL, "chs"); ok(ret != NULL, "expected success, but got NULL\n"); if (ret) - todo_wine ok((!strcmp(ret, "Chinese_China.936") + ok((!strcmp(ret, "Chinese_China.936") || broken(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936"))), /* Vista */ "setlocale chs failed, got %s\n", ret); @@ -219,14 +219,14 @@ static void test_setlocale(void) ret = p_setlocale(LC_ALL, "norwegian-nynorsk"); ok(ret != NULL, "expected success, but got NULL\n"); if (ret) - todo_wine ok((!strcmp(ret, "Norwegian Nynorsk_Norway.1252") + ok((!strcmp(ret, "Norwegian Nynorsk_Norway.1252") || broken(!strcmp(ret, "Norwegian (Nynorsk)_Norway.1252"))), /* Vista - 7 */ "setlocale norwegian-nynorsk failed, got %s\n", ret); ret = p_setlocale(LC_ALL, "non"); ok(ret != NULL, "expected success, but got NULL\n"); if (ret) - todo_wine ok((!strcmp(ret, "Norwegian Nynorsk_Norway.1252") + ok((!strcmp(ret, "Norwegian Nynorsk_Norway.1252") || broken(!strcmp(ret, "Norwegian (Nynorsk)_Norway.1252"))), /* Vista - 7 */ "setlocale norwegian-nynorsk failed, got %s\n", ret); diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 16ed68cdebd..845de26155c 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -51,6 +51,12 @@ BOOL initial_locale = TRUE; #define MSVCRT_LEADBYTE 0x8000 #define MSVCRT_C1_DEFINED 0x200 +#if _MSVCR_VER >= 110 +#define LCID_CONVERSION_FLAGS LOCALE_ALLOW_NEUTRAL_NAMES +#else +#define LCID_CONVERSION_FLAGS 0 +#endif + __lc_time_data cloc_time_data = { {{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", @@ -258,7 +264,7 @@ static BOOL CALLBACK find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam ) { locale_search_t *res = (locale_search_t *)lParam; - const LCID lcid = LocaleNameToLCID( name, 0 ); + const LCID lcid = LocaleNameToLCID( name, LCID_CONVERSION_FLAGS ); char buff[MAX_ELEM_LEN]; unsigned int flags = 0; @@ -469,8 +475,8 @@ static inline BOOL set_lc_locale_name(pthreadlocinfo locinfo, int cat) |LOCALE_NOUSEROVERRIDE, buf, 100); if(!len) return FALSE; - if(LocaleNameToLCID(buf, 0) != lcid) - len = LCIDToLocaleName(lcid, buf, 100, 0); + if(LocaleNameToLCID(buf, LOCALE_ALLOW_NEUTRAL_NAMES) != lcid) + len = LCIDToLocaleName(lcid, buf, 100, LOCALE_ALLOW_NEUTRAL_NAMES); if(!len || !(locinfo->lc_name[cat] = malloc(len*sizeof(wchar_t)))) return FALSE; @@ -486,13 +492,13 @@ static inline BOOL set_lc_locale_name(pthreadlocinfo locinfo, int cat) #endif /* INTERNAL: Set lc_handle, lc_id and lc_category in threadlocinfo struct */ -static BOOL update_threadlocinfo_category(LCID lcid, unsigned short cp, +static BOOL update_threadlocinfo_category(WCHAR *sname, unsigned short cp, pthreadlocinfo locinfo, int category) { - char buf[256], *p; + WCHAR wbuf[256], *p; - if(GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_NOUSEROVERRIDE, buf, 256)) { - p = buf; + if(GetLocaleInfoEx(sname, LOCALE_ILANGUAGE|LOCALE_NOUSEROVERRIDE, wbuf, ARRAY_SIZE(wbuf))) { + p = wbuf; locinfo->lc_id[category].wLanguage = 0; while(*p) { @@ -512,26 +518,32 @@ static BOOL update_threadlocinfo_category(LCID lcid, unsigned short cp, locinfo->lc_id[category].wCodePage = cp; - locinfo->lc_handle[category] = lcid; + locinfo->lc_handle[category] = LocaleNameToLCID(sname, LCID_CONVERSION_FLAGS); set_lc_locale_name(locinfo, category); if(!locinfo->lc_category[category].locale) { + char buf[256]; int len = 0; - if (lcid == MAKELANGID( LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK )) +#if _MSVCR_VER < 110 + if (LANGIDFROMLCID(locinfo->lc_handle[category]) == MAKELANGID(LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK)) { /* locale.nls contains "Norwegian Nynorsk" instead for LOCALE_SENGLANGUAGE */ - strcpy( buf, "Norwegian-Nynorsk" ); - len = strlen( buf ) + 1; + wcscpy( wbuf, L"Norwegian-Nynorsk" ); + len = wcslen( wbuf ) + 1; } - else len += GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE|LOCALE_NOUSEROVERRIDE, buf, 256); - buf[len-1] = '_'; - len += GetLocaleInfoA(lcid, LOCALE_SENGCOUNTRY - |LOCALE_NOUSEROVERRIDE, &buf[len], 256-len); - buf[len-1] = '.'; - sprintf(buf+len, "%d", cp); - len += strlen(buf+len); + else +#endif + len += GetLocaleInfoEx(sname, LOCALE_SENGLANGUAGE|LOCALE_NOUSEROVERRIDE, wbuf, ARRAY_SIZE(wbuf)); + wbuf[len-1] = '_'; + len += GetLocaleInfoEx(sname, LOCALE_SENGCOUNTRY + |LOCALE_NOUSEROVERRIDE, &wbuf[len], ARRAY_SIZE(wbuf) - len); + wbuf[len-1] = '.'; + swprintf(wbuf+len, ARRAY_SIZE(wbuf) - len,L"%d", cp); + len += wcslen(wbuf+len); + + WideCharToMultiByte(cp, 0, wbuf, -1, buf, ARRAY_SIZE(buf), NULL, NULL); return init_category_name(buf, len, locinfo, category); } @@ -1161,13 +1173,22 @@ void CDECL _free_locale(_locale_t locale) } static inline BOOL category_needs_update(int cat, - const threadlocinfo *locinfo, LCID lcid, unsigned short cp) + const threadlocinfo *locinfo, WCHAR *sname, unsigned short cp) { +#if _MSVCR_VER < 110 + LCID lcid; +#endif if(!locinfo) return TRUE; +#if _MSVCR_VER >= 110 + if(!locinfo->lc_name[cat] || !sname) return TRUE; + return wcscmp(sname, locinfo->lc_name[cat]) != 0 || cp!=locinfo->lc_id[cat].wCodePage; +#else + lcid = sname ? LocaleNameToLCID(sname, 0) : 0; return lcid!=locinfo->lc_handle[cat] || cp!=locinfo->lc_id[cat].wCodePage; +#endif } -static __lc_time_data* create_time_data(LCID lcid) +static __lc_time_data* create_time_data(WCHAR *sname) { static const DWORD time_data[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, @@ -1189,6 +1210,7 @@ static __lc_time_data* create_time_data(LCID lcid) __lc_time_data *cur; int i, ret, size; + LCID lcid = LocaleNameToLCID(sname, LCID_CONVERSION_FLAGS); size = sizeof(__lc_time_data); for(i=0; i= 100 - ret = GetLocaleInfoW(lcid, time_data[i], NULL, 0); + ret = GetLocaleInfoEx(sname, time_data[i], NULL, 0); if(!ret) return NULL; size += ret*sizeof(wchar_t); #endif } #if _MSVCR_VER >= 110 - size += LCIDToLocaleName(lcid, NULL, 0, 0)*sizeof(wchar_t); + size += wcslen(sname)*sizeof(wchar_t); #endif cur = malloc(size); @@ -1220,13 +1242,13 @@ static __lc_time_data* create_time_data(LCID lcid) #if _MSVCR_VER == 0 || _MSVCR_VER >= 100 for(i=0; iwstr.wstr[i] = (wchar_t*)&cur->data[ret]; - ret += GetLocaleInfoW(lcid, time_data[i], + ret += GetLocaleInfoEx(sname, time_data[i], (wchar_t*)&cur->data[ret], size-ret)*sizeof(wchar_t); } #endif #if _MSVCR_VER >= 110 cur->locname = (wchar_t*)&cur->data[ret]; - LCIDToLocaleName(lcid, (wchar_t*)&cur->data[ret], (size-ret)/sizeof(wchar_t), 0); + wcsncpy((wchar_t *) &cur->data[ret], sname, size-ret); #else cur->lcid = lcid; #endif @@ -1245,16 +1267,14 @@ static pthreadlocinfo create_locinfo(int category, static const char numeric[] = "NUMERIC="; static const char time[] = "TIME="; - pthreadlocinfo locinfo; - LCID lcid[6] = { 0 }; + pthreadlocinfo locinfo = NULL; unsigned short cp[6] = { 0 }; const char *locale_name[6] = { 0 }; + WCHAR *locale_sname[6] = { 0 }; int val, locale_len[6] = { 0 }; char buf[256]; - BOOL sname; -#if _MSVCR_VER >= 100 + BOOL sname_match; wchar_t wbuf[256]; -#endif int i; TRACE("(%d %s)\n", category, locale); @@ -1263,9 +1283,10 @@ static pthreadlocinfo create_locinfo(int category, return NULL; if(locale[0]=='C' && !locale[1]) { - lcid[0] = 0; + locale_sname[0] = NULL; cp[0] = CP_ACP; } else if (locale[0] == 'L' && locale[1] == 'C' && locale[2] == '_') { + LCID lcid; const char *p; while(1) { @@ -1286,30 +1307,39 @@ static pthreadlocinfo create_locinfo(int category, i = LC_TIME; locale += sizeof(time)-1; } else - return NULL; + goto fail; p = strchr(locale, ';'); if(locale[0]=='C' && (locale[1]==';' || locale[1]=='\0')) { - lcid[i] = 0; + lcid = 0; + locale_sname[i] = NULL; cp[i] = CP_ACP; } else if(p) { memcpy(buf, locale, p-locale); buf[p-locale] = '\0'; - lcid[i] = locale_to_LCID(buf, &cp[i], &sname); - if(sname) { + lcid = locale_to_LCID(buf, &cp[i], &sname_match); + if(sname_match) { locale_name[i] = locale; locale_len[i] = p-locale; } } else { - lcid[i] = locale_to_LCID(locale, &cp[i], &sname); - if(sname) { + lcid = locale_to_LCID(locale, &cp[i], &sname_match); + if(sname_match) { locale_name[i] = locale; locale_len[i] = strlen(locale); } } - if(lcid[i] == -1) - return NULL; + if(lcid == -1) + goto fail; + + if(lcid) { + int sname_size = LCIDToLocaleName(lcid, NULL, 0, LCID_CONVERSION_FLAGS); + locale_sname[i] = malloc(sname_size * sizeof(WCHAR)); + if(!locale_sname[i]) + goto fail; + LCIDToLocaleName(lcid, locale_sname[i], sname_size, LCID_CONVERSION_FLAGS); + } if(!p || *(p+1)!='L' || *(p+2)!='C' || *(p+3)!='_') break; @@ -1317,16 +1347,26 @@ static pthreadlocinfo create_locinfo(int category, locale = p+1; } } else { - lcid[0] = locale_to_LCID(locale, &cp[0], &sname); - if(lcid[0] == -1) + LCID lcid = locale_to_LCID(locale, &cp[0], &sname_match); + if(lcid == -1) return NULL; - if(sname) { + if(lcid) { + int sname_size = LCIDToLocaleName(lcid, NULL, 0, LCID_CONVERSION_FLAGS); + locale_sname[0] = malloc(sname_size * sizeof(WCHAR)); + if(!locale_sname[0]) + return NULL; + LCIDToLocaleName(lcid, locale_sname[0], sname_size, LCID_CONVERSION_FLAGS); + } + if(sname_match) { locale_name[0] = locale; locale_len[0] = strlen(locale); } for(i=1; i<6; i++) { - lcid[i] = lcid[0]; + locale_sname[i] = wcsdup(locale_sname[0]); + if(!locale_sname[i]) + goto fail; + cp[i] = cp[0]; locale_name[i] = locale_name[0]; locale_len[i] = locale_len[0]; @@ -1336,18 +1376,51 @@ static pthreadlocinfo create_locinfo(int category, for(i=1; i<6; i++) { #if _MSVCR_VER < 140 if(i==LC_CTYPE && cp[i]==CP_UTF8) { +#if _MSVCR_VER >= 110 + if(old_locinfo) { + locale_sname[i] = wcsdup(old_locinfo->lc_name[i]); + if (old_locinfo->lc_name[i] && !locale_sname[i]) + goto fail; + } +#else + int sname_size; + if(old_locinfo && old_locinfo->lc_handle[i]) { + sname_size = LCIDToLocaleName(old_locinfo->lc_handle[i], NULL, 0, 0); + locale_sname[i] = malloc(sname_size * sizeof(WCHAR)); + if(!locale_sname[i]) + goto fail; + LCIDToLocaleName(old_locinfo->lc_handle[i], locale_sname[i], sname_size, 0); + } else { + locale_sname[i] = NULL; + } +#endif + locale_name[i] = NULL; locale_len[i] = 0; - lcid[i] = old_locinfo ? old_locinfo->lc_handle[i] : 0; cp[i] = old_locinfo ? old_locinfo->lc_id[i].wCodePage : 0; } #endif if(category!=LC_ALL && category!=i) { if(old_locinfo) { - lcid[i] = old_locinfo->lc_handle[i]; +#if _MSVCR_VER >= 110 + locale_sname[i] = wcsdup(old_locinfo->lc_name[i]); + if(old_locinfo->lc_name[i] && !locale_sname[i]) + goto fail; +#else + int sname_size; + if(old_locinfo->lc_handle[i]) { + sname_size = LCIDToLocaleName(old_locinfo->lc_handle[i], NULL, 0, 0); + locale_sname[i] = malloc(sname_size * sizeof(WCHAR)); + if(!locale_sname[i]) + goto fail; + LCIDToLocaleName(old_locinfo->lc_handle[i], locale_sname[i], sname_size, 0); + } else { + locale_sname[i] = NULL; + } +#endif cp[i] = old_locinfo->lc_id[i].wCodePage; } else { - lcid[i] = 0; + locale_sname[i] = NULL; cp[i] = 0; } } @@ -1355,7 +1428,7 @@ static pthreadlocinfo create_locinfo(int category, locinfo = malloc(sizeof(threadlocinfo)); if(!locinfo) - return NULL; + goto fail; memset(locinfo, 0, sizeof(threadlocinfo)); locinfo->refcount = 1; @@ -1363,38 +1436,34 @@ static pthreadlocinfo create_locinfo(int category, if(locale_name[LC_COLLATE] && !init_category_name(locale_name[LC_COLLATE], locale_len[LC_COLLATE], locinfo, LC_COLLATE)) { - free_locinfo(locinfo); - return NULL; + goto fail; } if(!category_needs_update(LC_COLLATE, old_locinfo, - lcid[LC_COLLATE], cp[LC_COLLATE])) { + locale_sname[LC_COLLATE], cp[LC_COLLATE])) { copy_threadlocinfo_category(locinfo, old_locinfo, LC_COLLATE); locinfo->lc_collate_cp = old_locinfo->lc_collate_cp; - } else if(lcid[LC_COLLATE]) { - if(!update_threadlocinfo_category(lcid[LC_COLLATE], + } else if(locale_sname[LC_COLLATE]) { + if(!update_threadlocinfo_category(locale_sname[LC_COLLATE], cp[LC_COLLATE], locinfo, LC_COLLATE)) { - free_locinfo(locinfo); - return NULL; + goto fail; } locinfo->lc_collate_cp = locinfo->lc_id[LC_COLLATE].wCodePage; } else { if(!init_category_name("C", 1, locinfo, LC_COLLATE)) { - free_locinfo(locinfo); - return NULL; + goto fail; } } if(locale_name[LC_CTYPE] && !init_category_name(locale_name[LC_CTYPE], locale_len[LC_CTYPE], locinfo, LC_CTYPE)) { - free_locinfo(locinfo); - return NULL; + goto fail; } if(!category_needs_update(LC_CTYPE, old_locinfo, - lcid[LC_CTYPE], cp[LC_CTYPE])) { + locale_sname[LC_CTYPE], cp[LC_CTYPE])) { copy_threadlocinfo_category(locinfo, old_locinfo, LC_CTYPE); locinfo->lc_codepage = old_locinfo->lc_codepage; locinfo->lc_clike = old_locinfo->lc_clike; @@ -1406,28 +1475,25 @@ static pthreadlocinfo create_locinfo(int category, locinfo->pcumap = old_locinfo->pcumap; if(locinfo->ctype1_refcount) InterlockedIncrement((LONG *)locinfo->ctype1_refcount); - } else if(lcid[LC_CTYPE]) { + } else if(locale_sname[LC_CTYPE]) { CPINFO cp_info; int j; - if(!update_threadlocinfo_category(lcid[LC_CTYPE], + if(!update_threadlocinfo_category(locale_sname[LC_CTYPE], cp[LC_CTYPE], locinfo, LC_CTYPE)) { - free_locinfo(locinfo); - return NULL; + goto fail; } locinfo->lc_codepage = locinfo->lc_id[LC_CTYPE].wCodePage; locinfo->lc_clike = 1; if(!GetCPInfo(locinfo->lc_codepage, &cp_info)) { - free_locinfo(locinfo); - return NULL; + goto fail; } locinfo->mb_cur_max = cp_info.MaxCharSize; locinfo->ctype1_refcount = malloc(sizeof(int)); if(!locinfo->ctype1_refcount) { - free_locinfo(locinfo); - return NULL; + goto fail; } *locinfo->ctype1_refcount = 1; @@ -1435,8 +1501,7 @@ static pthreadlocinfo create_locinfo(int category, locinfo->pclmap = malloc(sizeof(char[256])); locinfo->pcumap = malloc(sizeof(char[256])); if(!locinfo->ctype1 || !locinfo->pclmap || !locinfo->pcumap) { - free_locinfo(locinfo); - return NULL; + goto fail; } locinfo->ctype1[0] = 0; @@ -1449,7 +1514,7 @@ static pthreadlocinfo create_locinfo(int category, /* builtin GetStringTypeA doesn't set output to 0 on invalid input */ locinfo->ctype1[i] = 0; - GetStringTypeA(lcid[LC_CTYPE], CT_CTYPE1, buf, + GetStringTypeA(locinfo->lc_handle[LC_CTYPE], CT_CTYPE1, buf, 1, locinfo->ctype1+i); } @@ -1464,9 +1529,9 @@ static pthreadlocinfo create_locinfo(int category, buf[i] = i; } - LCMapStringA(lcid[LC_CTYPE], LCMAP_LOWERCASE, buf, 256, + LCMapStringA(locinfo->lc_handle[LC_CTYPE], LCMAP_LOWERCASE, buf, 256, (char*)locinfo->pclmap, 256); - LCMapStringA(lcid[LC_CTYPE], LCMAP_UPPERCASE, buf, 256, + LCMapStringA(locinfo->lc_handle[LC_CTYPE], LCMAP_UPPERCASE, buf, 256, (char*)locinfo->pcumap, 256); } else { locinfo->lc_clike = 1; @@ -1475,20 +1540,19 @@ static pthreadlocinfo create_locinfo(int category, locinfo->pclmap = cloc_clmap; locinfo->pcumap = cloc_cumap; if(!init_category_name("C", 1, locinfo, LC_CTYPE)) { - free_locinfo(locinfo); - return NULL; + goto fail; } } if(!category_needs_update(LC_MONETARY, old_locinfo, - lcid[LC_MONETARY], cp[LC_MONETARY]) && + locale_sname[LC_MONETARY], cp[LC_MONETARY]) && !category_needs_update(LC_NUMERIC, old_locinfo, - lcid[LC_NUMERIC], cp[LC_NUMERIC])) { + locale_sname[LC_NUMERIC], cp[LC_NUMERIC])) { locinfo->lconv = old_locinfo->lconv; locinfo->lconv_intl_refcount = old_locinfo->lconv_intl_refcount; if(locinfo->lconv_intl_refcount) InterlockedIncrement((LONG *)locinfo->lconv_intl_refcount); - } else if(lcid[LC_MONETARY] || lcid[LC_NUMERIC]) { + } else if(locale_sname[LC_MONETARY] || locale_sname[LC_NUMERIC]) { locinfo->lconv = malloc(sizeof(struct lconv)); locinfo->lconv_intl_refcount = malloc(sizeof(int)); if(!locinfo->lconv || !locinfo->lconv_intl_refcount) { @@ -1496,8 +1560,7 @@ static pthreadlocinfo create_locinfo(int category, free(locinfo->lconv_intl_refcount); locinfo->lconv = NULL; locinfo->lconv_intl_refcount = NULL; - free_locinfo(locinfo); - return NULL; + goto fail; } memset(locinfo->lconv, 0, sizeof(struct lconv)); *locinfo->lconv_intl_refcount = 1; @@ -1508,12 +1571,11 @@ static pthreadlocinfo create_locinfo(int category, if(locale_name[LC_MONETARY] && !init_category_name(locale_name[LC_MONETARY], locale_len[LC_MONETARY], locinfo, LC_MONETARY)) { - free_locinfo(locinfo); - return NULL; + goto fail; } if(!category_needs_update(LC_MONETARY, old_locinfo, - lcid[LC_MONETARY], cp[LC_MONETARY])) { + locale_sname[LC_MONETARY], cp[LC_MONETARY])) { copy_threadlocinfo_category(locinfo, old_locinfo, LC_MONETARY); locinfo->lconv_mon_refcount = old_locinfo->lconv_mon_refcount; if(locinfo->lconv_mon_refcount) @@ -1543,59 +1605,58 @@ static pthreadlocinfo create_locinfo(int category, locinfo->lconv->_W_negative_sign = old_locinfo->lconv->_W_negative_sign; #endif } - } else if(lcid[LC_MONETARY]) { - if(!update_threadlocinfo_category(lcid[LC_MONETARY], + } else if(locale_sname[LC_MONETARY]) { + if(!update_threadlocinfo_category(locale_sname[LC_MONETARY], cp[LC_MONETARY], locinfo, LC_MONETARY)) { - free_locinfo(locinfo); - return NULL; + goto fail; } locinfo->lconv_mon_refcount = malloc(sizeof(int)); if(!locinfo->lconv_mon_refcount) { - free_locinfo(locinfo); - return NULL; + goto fail; } *locinfo->lconv_mon_refcount = 1; - i = GetLocaleInfoA(lcid[LC_MONETARY], LOCALE_SINTLSYMBOL - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SINTLSYMBOL + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + i = WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, NULL, 0, NULL, NULL); if(i && (locinfo->lconv->int_curr_symbol = malloc(i))) - memcpy(locinfo->lconv->int_curr_symbol, buf, i); + WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, locinfo->lconv->int_curr_symbol, i, NULL, NULL); else { - free_locinfo(locinfo); - return NULL; + goto fail; } - i = GetLocaleInfoA(lcid[LC_MONETARY], LOCALE_SCURRENCY - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SCURRENCY + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + i = WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, NULL, 0, NULL, NULL); if(i && (locinfo->lconv->currency_symbol = malloc(i))) - memcpy(locinfo->lconv->currency_symbol, buf, i); + WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, locinfo->lconv->currency_symbol, i, NULL, NULL); else { - free_locinfo(locinfo); - return NULL; + goto fail; } - i = GetLocaleInfoA(lcid[LC_MONETARY], LOCALE_SMONDECIMALSEP - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SMONDECIMALSEP + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + i = WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, NULL, 0, NULL, NULL); if(i && (locinfo->lconv->mon_decimal_point = malloc(i))) - memcpy(locinfo->lconv->mon_decimal_point, buf, i); + WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, locinfo->lconv->mon_decimal_point, i, NULL, NULL); else { - free_locinfo(locinfo); - return NULL; + goto fail; } - i = GetLocaleInfoA(lcid[LC_MONETARY], LOCALE_SMONTHOUSANDSEP - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SMONTHOUSANDSEP + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + i = WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, NULL, 0, NULL, NULL); if(i && (locinfo->lconv->mon_thousands_sep = malloc(i))) - memcpy(locinfo->lconv->mon_thousands_sep, buf, i); + WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, locinfo->lconv->mon_thousands_sep, i, NULL, NULL); else { - free_locinfo(locinfo); - return NULL; + goto fail; } - i = GetLocaleInfoA(lcid[LC_MONETARY], LOCALE_SMONGROUPING - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SMONGROUPING + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + WideCharToMultiByte(CP_ACP, 0, wbuf, -1, buf, 256, NULL, NULL); if(i>1) i = i/2 + (buf[i-2]=='0'?0:1); if(i && (locinfo->lconv->mon_grouping = malloc(i))) { @@ -1605,145 +1666,130 @@ static pthreadlocinfo create_locinfo(int category, if(buf[i] != '0') locinfo->lconv->mon_grouping[i/2+1] = 127; } else { - free_locinfo(locinfo); - return NULL; + goto fail; } - i = GetLocaleInfoA(lcid[LC_MONETARY], LOCALE_SPOSITIVESIGN - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SPOSITIVESIGN + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + i = WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, NULL, 0, NULL, NULL); if(i && (locinfo->lconv->positive_sign = malloc(i))) - memcpy(locinfo->lconv->positive_sign, buf, i); + WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, locinfo->lconv->positive_sign, i, NULL, NULL); else { - free_locinfo(locinfo); - return NULL; + goto fail; } - i = GetLocaleInfoA(lcid[LC_MONETARY], LOCALE_SNEGATIVESIGN - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SNEGATIVESIGN + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + i = WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, NULL, 0, NULL, NULL); if(i && (locinfo->lconv->negative_sign = malloc(i))) - memcpy(locinfo->lconv->negative_sign, buf, i); + WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, locinfo->lconv->negative_sign, i, NULL, NULL); else { - free_locinfo(locinfo); - return NULL; + goto fail; } - if(GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_IINTLCURRDIGITS + if(GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_IINTLCURRDIGITS |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2)) locinfo->lconv->int_frac_digits = val; else { - free_locinfo(locinfo); - return NULL; + goto fail; } - if(GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_ICURRDIGITS + if(GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_ICURRDIGITS |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2)) locinfo->lconv->frac_digits = val; else { - free_locinfo(locinfo); - return NULL; + goto fail; } - if(GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_IPOSSYMPRECEDES + if(GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_IPOSSYMPRECEDES |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2)) locinfo->lconv->p_cs_precedes = val; else { - free_locinfo(locinfo); - return NULL; + goto fail; } - if(GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_IPOSSEPBYSPACE + if(GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_IPOSSEPBYSPACE |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2)) locinfo->lconv->p_sep_by_space = val; else { - free_locinfo(locinfo); - return NULL; + goto fail; } - if(GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_INEGSYMPRECEDES + if(GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_INEGSYMPRECEDES |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2)) locinfo->lconv->n_cs_precedes = val; else { - free_locinfo(locinfo); - return NULL; + goto fail; } - if(GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_INEGSEPBYSPACE + if(GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_INEGSEPBYSPACE |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2)) locinfo->lconv->n_sep_by_space = val; else { - free_locinfo(locinfo); - return NULL; + goto fail; } - if(GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_IPOSSIGNPOSN + if(GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_IPOSSIGNPOSN |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2)) locinfo->lconv->p_sign_posn = val; else { - free_locinfo(locinfo); - return NULL; + goto fail; } - if(GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_INEGSIGNPOSN + if(GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_INEGSIGNPOSN |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2)) locinfo->lconv->n_sign_posn = val; else { - free_locinfo(locinfo); - return NULL; + goto fail; } #if _MSVCR_VER >= 100 - i = GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_SINTLSYMBOL + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SINTLSYMBOL |LOCALE_NOUSEROVERRIDE, wbuf, 256); if(i && (locinfo->lconv->_W_int_curr_symbol = malloc(i * sizeof(wchar_t)))) memcpy(locinfo->lconv->_W_int_curr_symbol, wbuf, i * sizeof(wchar_t)); else { - free_locinfo(locinfo); - return NULL; + goto fail; } - i = GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_SCURRENCY + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SCURRENCY |LOCALE_NOUSEROVERRIDE, wbuf, 256); if(i && (locinfo->lconv->_W_currency_symbol = malloc(i * sizeof(wchar_t)))) memcpy(locinfo->lconv->_W_currency_symbol, wbuf, i * sizeof(wchar_t)); else { - free_locinfo(locinfo); - return NULL; + goto fail; } - i = GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_SMONDECIMALSEP + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SMONDECIMALSEP |LOCALE_NOUSEROVERRIDE, wbuf, 256); if(i && (locinfo->lconv->_W_mon_decimal_point = malloc(i * sizeof(wchar_t)))) memcpy(locinfo->lconv->_W_mon_decimal_point, wbuf, i * sizeof(wchar_t)); else { - free_locinfo(locinfo); - return NULL; + goto fail; } - i = GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_SMONTHOUSANDSEP + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SMONTHOUSANDSEP |LOCALE_NOUSEROVERRIDE, wbuf, 256); if(i && (locinfo->lconv->_W_mon_thousands_sep = malloc(i * sizeof(wchar_t)))) memcpy(locinfo->lconv->_W_mon_thousands_sep, wbuf, i * sizeof(wchar_t)); else { - free_locinfo(locinfo); - return NULL; + goto fail; } - i = GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_SPOSITIVESIGN + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SPOSITIVESIGN |LOCALE_NOUSEROVERRIDE, wbuf, 256); if(i && (locinfo->lconv->_W_positive_sign = malloc(i * sizeof(wchar_t)))) memcpy(locinfo->lconv->_W_positive_sign, wbuf, i * sizeof(wchar_t)); else { - free_locinfo(locinfo); - return NULL; + goto fail; } - i = GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_SNEGATIVESIGN + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SNEGATIVESIGN |LOCALE_NOUSEROVERRIDE, wbuf, 256); if(i && (locinfo->lconv->_W_negative_sign = malloc(i * sizeof(wchar_t)))) memcpy(locinfo->lconv->_W_negative_sign, wbuf, i * sizeof(wchar_t)); else { - free_locinfo(locinfo); - return NULL; + goto fail; } #endif } else { @@ -1775,20 +1821,18 @@ static pthreadlocinfo create_locinfo(int category, } if(!init_category_name("C", 1, locinfo, LC_MONETARY)) { - free_locinfo(locinfo); - return NULL; + goto fail; } } if(locale_name[LC_NUMERIC] && !init_category_name(locale_name[LC_NUMERIC], locale_len[LC_NUMERIC], locinfo, LC_NUMERIC)) { - free_locinfo(locinfo); - return NULL; + goto fail; } if(!category_needs_update(LC_NUMERIC, old_locinfo, - lcid[LC_NUMERIC], cp[LC_NUMERIC])) { + locale_sname[LC_NUMERIC], cp[LC_NUMERIC])) { copy_threadlocinfo_category(locinfo, old_locinfo, LC_NUMERIC); locinfo->lconv_num_refcount = old_locinfo->lconv_num_refcount; if(locinfo->lconv_num_refcount) @@ -1802,41 +1846,40 @@ static pthreadlocinfo create_locinfo(int category, locinfo->lconv->_W_thousands_sep = old_locinfo->lconv->_W_thousands_sep; #endif } - } else if(lcid[LC_NUMERIC]) { - if(!update_threadlocinfo_category(lcid[LC_NUMERIC], + } else if(locale_sname[LC_NUMERIC]) { + if(!update_threadlocinfo_category(locale_sname[LC_NUMERIC], cp[LC_NUMERIC], locinfo, LC_NUMERIC)) { - free_locinfo(locinfo); - return NULL; + goto fail; } locinfo->lconv_num_refcount = malloc(sizeof(int)); if(!locinfo->lconv_num_refcount) { - free_locinfo(locinfo); - return NULL; + goto fail; } *locinfo->lconv_num_refcount = 1; - i = GetLocaleInfoA(lcid[LC_NUMERIC], LOCALE_SDECIMAL - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_NUMERIC], LOCALE_SDECIMAL + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + i = WideCharToMultiByte(cp[LC_NUMERIC], 0, wbuf, -1, NULL, 0, NULL, NULL); if(i && (locinfo->lconv->decimal_point = malloc(i))) - memcpy(locinfo->lconv->decimal_point, buf, i); + WideCharToMultiByte(cp[LC_NUMERIC], 0, wbuf, -1, locinfo->lconv->decimal_point, i, NULL, NULL); else { - free_locinfo(locinfo); - return NULL; + goto fail; } - i = GetLocaleInfoA(lcid[LC_NUMERIC], LOCALE_STHOUSAND - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_NUMERIC], LOCALE_STHOUSAND + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + i = WideCharToMultiByte(cp[LC_NUMERIC], 0, wbuf, -1, NULL, 0, NULL, NULL); if(i && (locinfo->lconv->thousands_sep = malloc(i))) - memcpy(locinfo->lconv->thousands_sep, buf, i); + WideCharToMultiByte(cp[LC_NUMERIC], 0, wbuf, -1, locinfo->lconv->thousands_sep, i, NULL, NULL); else { - free_locinfo(locinfo); - return NULL; + goto fail; } - i = GetLocaleInfoA(lcid[LC_NUMERIC], LOCALE_SGROUPING - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_NUMERIC], LOCALE_SGROUPING + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + WideCharToMultiByte(cp[LC_NUMERIC], 0, wbuf, -1, buf, 256, NULL, NULL); if(i>1) i = i/2 + (buf[i-2]=='0'?0:1); if(i && (locinfo->lconv->grouping = malloc(i))) { @@ -1846,27 +1889,24 @@ static pthreadlocinfo create_locinfo(int category, if(buf[i] != '0') locinfo->lconv->grouping[i/2+1] = 127; } else { - free_locinfo(locinfo); - return NULL; + goto fail; } #if _MSVCR_VER >= 100 - i = GetLocaleInfoW(lcid[LC_NUMERIC], LOCALE_SDECIMAL + i = GetLocaleInfoEx(locale_sname[LC_NUMERIC], LOCALE_SDECIMAL |LOCALE_NOUSEROVERRIDE, wbuf, 256); if(i && (locinfo->lconv->_W_decimal_point = malloc(i * sizeof(wchar_t)))) memcpy(locinfo->lconv->_W_decimal_point, wbuf, i * sizeof(wchar_t)); else { - free_locinfo(locinfo); - return NULL; + goto fail; } - i = GetLocaleInfoW(lcid[LC_NUMERIC], LOCALE_STHOUSAND + i = GetLocaleInfoEx(locale_sname[LC_NUMERIC], LOCALE_STHOUSAND |LOCALE_NOUSEROVERRIDE, wbuf, 256); if(i && (locinfo->lconv->_W_thousands_sep = malloc(i * sizeof(wchar_t)))) memcpy(locinfo->lconv->_W_thousands_sep, wbuf, i * sizeof(wchar_t)); else { - free_locinfo(locinfo); - return NULL; + goto fail; } #endif } else { @@ -1882,45 +1922,48 @@ static pthreadlocinfo create_locinfo(int category, } if (!init_category_name("C", 1, locinfo, LC_NUMERIC)) { - free_locinfo(locinfo); - return NULL; + goto fail; } } if(locale_name[LC_TIME] && !init_category_name(locale_name[LC_TIME], locale_len[LC_TIME], locinfo, LC_TIME)) { - free_locinfo(locinfo); - return NULL; + goto fail; } if(!category_needs_update(LC_TIME, old_locinfo, - lcid[LC_TIME], cp[LC_TIME])) { + locale_sname[LC_TIME], cp[LC_TIME])) { copy_threadlocinfo_category(locinfo, old_locinfo, LC_TIME); locinfo->lc_time_curr = old_locinfo->lc_time_curr; InterlockedIncrement(&locinfo->lc_time_curr->refcount); - } else if(lcid[LC_TIME]) { - if(!update_threadlocinfo_category(lcid[LC_TIME], + } else if(locale_sname[LC_TIME]) { + if(!update_threadlocinfo_category(locale_sname[LC_TIME], cp[LC_TIME], locinfo, LC_TIME)) { - free_locinfo(locinfo); - return NULL; + goto fail; } - locinfo->lc_time_curr = create_time_data(lcid[LC_TIME]); + locinfo->lc_time_curr = create_time_data(locale_sname[LC_TIME]); if(!locinfo->lc_time_curr) { - free_locinfo(locinfo); - return NULL; + goto fail; } } else { if(!init_category_name("C", 1, locinfo, LC_TIME)) { - free_locinfo(locinfo); - return NULL; + goto fail; } locinfo->lc_time_curr = &cloc_time_data; InterlockedIncrement(&locinfo->lc_time_curr->refcount); } return locinfo; + +fail: + free_locinfo(locinfo); + + for (i = 0; i < LC_MAX; i++) + free(locale_sname[i]); + + return NULL; } /********************************************************************* From c3671b388a7b9d250c74fb2750525d04b115a562 Mon Sep 17 00:00:00 2001 From: Victor Chiletto Date: Wed, 7 Jun 2023 12:41:42 -0300 Subject: [PATCH 1574/2777] msvcrt: Convert locale_to_LCID to snames. (cherry picked from commit 45dd09d0cf63892a5518ab718e32aea450580cf8) CW-Bug-Id: #19646 --- dlls/msvcrt/locale.c | 95 ++++++++++++++++++++------------------------ dlls/msvcrt/mbcs.c | 3 +- dlls/msvcrt/msvcrt.h | 5 +-- 3 files changed, 48 insertions(+), 55 deletions(-) diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 845de26155c..cfcd4410b52 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -321,28 +321,27 @@ find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam ) return CONTINUE_LOOKING; } -/* Internal: Find the LCID for a locale specification */ -LCID locale_to_LCID(const char *locale, unsigned short *codepage, BOOL *sname) +/* Internal: Find the sname for a locale specification */ +BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_match, WCHAR *sname, int sname_size) { thread_data_t *data = msvcrt_get_thread_data(); const char *cp, *region; BOOL is_sname = FALSE; DWORD locale_cp; - LCID lcid; if (!strcmp(locale, data->cached_locale)) { if (codepage) *codepage = data->cached_cp; if (sname) - *sname = data->cached_sname; - return data->cached_lcid; + wcsncpy(sname, data->cached_sname, sname_size); + return TRUE; } cp = strchr(locale, '.'); region = strchr(locale, '_'); if(!locale[0] || (cp == locale && !region)) { - lcid = GetUserDefaultLCID(); + GetUserDefaultLocaleName(sname, sname_size); } else { locale_search_t search; @@ -371,26 +370,26 @@ LCID locale_to_LCID(const char *locale, unsigned short *codepage, BOOL *sname) EnumSystemLocalesEx( find_best_locale_proc, 0, (LPARAM)&search, NULL); if (!search.match_flags) - return -1; + return FALSE; /* If we were given something that didn't match, fail */ if (search.search_language[0] && !(search.match_flags & (FOUND_SNAME | FOUND_LANGUAGE))) - return -1; + return FALSE; if (search.search_country[0] && !(search.match_flags & FOUND_COUNTRY)) - return -1; + return FALSE; - lcid = MAKELCID(search.found_lang_id, SORT_DEFAULT); + LCIDToLocaleName(search.found_lang_id, sname, sname_size, LOCALE_ALLOW_NEUTRAL_NAMES); is_sname = (search.match_flags & FOUND_SNAME) != 0; } /* Obtain code page */ if (!cp || !cp[1] || !_strnicmp(cp, ".ACP", 4)) { - GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, + GetLocaleInfoEx(sname, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR *)&locale_cp, sizeof(DWORD)/sizeof(WCHAR)); if (!locale_cp) locale_cp = GetACP(); } else if (!_strnicmp(cp, ".OCP", 4)) { - GetLocaleInfoW(lcid, LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER, + GetLocaleInfoEx(sname, LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR *)&locale_cp, sizeof(DWORD)/sizeof(WCHAR)); #if _MSVCR_VER >= 140 } else if (!_strnicmp(cp, ".UTF-8", 6) @@ -401,24 +400,23 @@ LCID locale_to_LCID(const char *locale, unsigned short *codepage, BOOL *sname) locale_cp = atoi(cp + 1); } if (!IsValidCodePage(locale_cp)) - return -1; + return FALSE; if (!locale_cp) - return -1; + return FALSE; if (codepage) *codepage = locale_cp; - if (sname) - *sname = is_sname; + if (sname_match) + *sname_match = is_sname; if (strlen(locale) < sizeof(data->cached_locale)) { strcpy(data->cached_locale, locale); - data->cached_lcid = lcid; data->cached_cp = locale_cp; - data->cached_sname = is_sname; + wcscpy(data->cached_sname, sname); } - return lcid; + return TRUE; } static void copy_threadlocinfo_category(pthreadlocinfo locinfo, @@ -1286,7 +1284,6 @@ static pthreadlocinfo create_locinfo(int category, locale_sname[0] = NULL; cp[0] = CP_ACP; } else if (locale[0] == 'L' && locale[1] == 'C' && locale[2] == '_') { - LCID lcid; const char *p; while(1) { @@ -1311,34 +1308,31 @@ static pthreadlocinfo create_locinfo(int category, p = strchr(locale, ';'); if(locale[0]=='C' && (locale[1]==';' || locale[1]=='\0')) { - lcid = 0; locale_sname[i] = NULL; cp[i] = CP_ACP; - } else if(p) { - memcpy(buf, locale, p-locale); - buf[p-locale] = '\0'; - lcid = locale_to_LCID(buf, &cp[i], &sname_match); - if(sname_match) { - locale_name[i] = locale; - locale_len[i] = p-locale; - } } else { - lcid = locale_to_LCID(locale, &cp[i], &sname_match); - if(sname_match) { - locale_name[i] = locale; - locale_len[i] = strlen(locale); + BOOL locale_found = FALSE; + + if(p) { + memcpy(buf, locale, p-locale); + buf[p-locale] = '\0'; + locale_found = locale_to_sname(buf, &cp[i], &sname_match, wbuf, LOCALE_NAME_MAX_LENGTH); + locale_sname[i] = wcsdup(wbuf); + if(sname_match) { + locale_name[i] = locale; + locale_len[i] = p-locale; + } + } else { + locale_found = locale_to_sname(buf, &cp[i], &sname_match, wbuf, LOCALE_NAME_MAX_LENGTH); + locale_sname[i] = wcsdup(wbuf); + if(sname_match) { + locale_name[i] = locale; + locale_len[i] = strlen(locale); + } } - } - - if(lcid == -1) - goto fail; - if(lcid) { - int sname_size = LCIDToLocaleName(lcid, NULL, 0, LCID_CONVERSION_FLAGS); - locale_sname[i] = malloc(sname_size * sizeof(WCHAR)); - if(!locale_sname[i]) + if(!locale_found || !locale_sname[i]) goto fail; - LCIDToLocaleName(lcid, locale_sname[i], sname_size, LCID_CONVERSION_FLAGS); } if(!p || *(p+1)!='L' || *(p+2)!='C' || *(p+3)!='_') @@ -1347,16 +1341,15 @@ static pthreadlocinfo create_locinfo(int category, locale = p+1; } } else { - LCID lcid = locale_to_LCID(locale, &cp[0], &sname_match); - if(lcid == -1) + BOOL locale_found = locale_to_sname(locale, &cp[0], &sname_match, wbuf, LOCALE_NAME_MAX_LENGTH); + + if(!locale_found) return NULL; - if(lcid) { - int sname_size = LCIDToLocaleName(lcid, NULL, 0, LCID_CONVERSION_FLAGS); - locale_sname[0] = malloc(sname_size * sizeof(WCHAR)); - if(!locale_sname[0]) - return NULL; - LCIDToLocaleName(lcid, locale_sname[0], sname_size, LCID_CONVERSION_FLAGS); - } + + locale_sname[0] = wcsdup(wbuf); + if(!locale_sname[0]) + return NULL; + if(sname_match) { locale_name[0] = locale; locale_len[0] = strlen(locale); diff --git a/dlls/msvcrt/mbcs.c b/dlls/msvcrt/mbcs.c index 16c5c378be7..8598bceb029 100644 --- a/dlls/msvcrt/mbcs.c +++ b/dlls/msvcrt/mbcs.c @@ -252,8 +252,9 @@ threadmbcinfo* create_mbcinfo(int cp, LCID lcid, threadmbcinfo *old_mbcinfo) } if(lcid == -1) { + WCHAR wbuf[LOCALE_NAME_MAX_LENGTH]; sprintf(bufA, ".%d", newcp); - mbcinfo->mblcid = locale_to_LCID(bufA, NULL, NULL); + mbcinfo->mblcid = locale_to_sname(bufA, NULL, NULL, wbuf, LOCALE_NAME_MAX_LENGTH) ? LocaleNameToLCID(wbuf, LOCALE_ALLOW_NEUTRAL_NAMES) : -1; } else { mbcinfo->mblcid = lcid; } diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h index 1d965ff8ffc..73c02cd03b4 100644 --- a/dlls/msvcrt/msvcrt.h +++ b/dlls/msvcrt/msvcrt.h @@ -160,8 +160,7 @@ struct __thread_data { int processing_throw; frame_info *frame_info_head; void *unk8[6]; - LCID cached_lcid; - BOOL cached_sname; + WCHAR cached_sname[LOCALE_NAME_MAX_LENGTH]; int unk9[2]; DWORD cached_cp; char cached_locale[131]; @@ -176,7 +175,7 @@ typedef struct __thread_data thread_data_t; extern thread_data_t *CDECL msvcrt_get_thread_data(void) DECLSPEC_HIDDEN; -LCID locale_to_LCID(const char*, unsigned short*, BOOL*) DECLSPEC_HIDDEN; +BOOL locale_to_sname(const char*, unsigned short*, BOOL*, WCHAR*, int) DECLSPEC_HIDDEN; extern _locale_t MSVCRT_locale DECLSPEC_HIDDEN; extern __lc_time_data cloc_time_data DECLSPEC_HIDDEN; extern unsigned int MSVCRT___lc_codepage; From f1f508572c38dcf94a90cef3bcff79d0b6cb8531 Mon Sep 17 00:00:00 2001 From: Victor Chiletto Date: Mon, 12 Jun 2023 16:51:02 -0300 Subject: [PATCH 1575/2777] msvcrt: Skip exhaustive locale search with valid snames. (cherry picked from commit 72c3b8f3a0a9020ce3f2667fb63b94d45828c2dd) CW-Bug-Id: #19646 --- dlls/msvcr110/tests/msvcr110.c | 4 ++-- dlls/msvcr120/tests/msvcr120.c | 4 ++-- dlls/msvcrt/locale.c | 31 ++++++++++++++++++++++--------- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/dlls/msvcr110/tests/msvcr110.c b/dlls/msvcr110/tests/msvcr110.c index 60d876e3bfc..35ba370bb49 100644 --- a/dlls/msvcr110/tests/msvcr110.c +++ b/dlls/msvcr110/tests/msvcr110.c @@ -153,14 +153,14 @@ static void test_setlocale(void) ok(!ret, "setlocale(en-us.1250) succeeded (%s)\n", ret); ret = p_setlocale(LC_ALL, "zh-Hans"); - todo_wine ok((ret != NULL + ok((ret != NULL || broken(ret == NULL)), /* Vista */ "expected success, but got NULL\n"); if (ret) ok(!strcmp(ret, "zh-Hans"), "setlocale zh-Hans failed\n"); ret = p_setlocale(LC_ALL, "zh-Hant"); - todo_wine ok((ret != NULL + ok((ret != NULL || broken(ret == NULL)), /* Vista */ "expected success, but got NULL\n"); if (ret) diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c index b8950288afe..f45152078ed 100644 --- a/dlls/msvcr120/tests/msvcr120.c +++ b/dlls/msvcr120/tests/msvcr120.c @@ -598,11 +598,11 @@ static void test____lc_locale_name_func(void) p_setlocale(LC_ALL, "zh-Hans"); lc_names = p____lc_locale_name_func(); - todo_wine ok(!lstrcmpW(lc_names[1], L"zh-Hans"), "lc_names[1] expected zh-Hans got %s\n", wine_dbgstr_w(lc_names[1])); + ok(!lstrcmpW(lc_names[1], L"zh-Hans"), "lc_names[1] expected zh-Hans got %s\n", wine_dbgstr_w(lc_names[1])); p_setlocale(LC_ALL, "zh-Hant"); lc_names = p____lc_locale_name_func(); - todo_wine ok(!lstrcmpW(lc_names[1], L"zh-Hant"), "lc_names[1] expected zh-Hant got %s\n", wine_dbgstr_w(lc_names[1])); + ok(!lstrcmpW(lc_names[1], L"zh-Hant"), "lc_names[1] expected zh-Hant got %s\n", wine_dbgstr_w(lc_names[1])); p_setlocale(LC_ALL, "C"); lc_names = p____lc_locale_name_func(); diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index cfcd4410b52..12c9bba506c 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -343,6 +343,7 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m if(!locale[0] || (cp == locale && !region)) { GetUserDefaultLocaleName(sname, sname_size); } else { + WCHAR wbuf[LOCALE_NAME_MAX_LENGTH]; locale_search_t search; memset(&search, 0, sizeof(locale_search_t)); @@ -364,21 +365,33 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m if(!cp && !region) { remap_synonym(search.search_language); +#if _MSVCR_VER >= 110 search.allow_sname = TRUE; +#endif + } + + MultiByteToWideChar(CP_ACP, 0, search.search_language, -1, wbuf, LOCALE_NAME_MAX_LENGTH); + if (search.allow_sname && IsValidLocaleName(wbuf)) + { + search.match_flags = FOUND_SNAME; + wcsncpy(sname, wbuf, sname_size); } + else + { + EnumSystemLocalesEx( find_best_locale_proc, 0, (LPARAM)&search, NULL); - EnumSystemLocalesEx( find_best_locale_proc, 0, (LPARAM)&search, NULL); + if (!search.match_flags) + return FALSE; - if (!search.match_flags) - return FALSE; + /* If we were given something that didn't match, fail */ + if (search.search_language[0] && !(search.match_flags & (FOUND_SNAME | FOUND_LANGUAGE))) + return FALSE; + if (search.search_country[0] && !(search.match_flags & FOUND_COUNTRY)) + return FALSE; - /* If we were given something that didn't match, fail */ - if (search.search_language[0] && !(search.match_flags & (FOUND_SNAME | FOUND_LANGUAGE))) - return FALSE; - if (search.search_country[0] && !(search.match_flags & FOUND_COUNTRY)) - return FALSE; + LCIDToLocaleName(search.found_lang_id, sname, sname_size, LOCALE_ALLOW_NEUTRAL_NAMES); + } - LCIDToLocaleName(search.found_lang_id, sname, sname_size, LOCALE_ALLOW_NEUTRAL_NAMES); is_sname = (search.match_flags & FOUND_SNAME) != 0; } From d45da6837a1f72f1004ac30c580d4fc0d29bcf75 Mon Sep 17 00:00:00 2001 From: Victor Chiletto Date: Wed, 12 Jul 2023 01:47:43 -0300 Subject: [PATCH 1576/2777] msvcrt: Simplify set_lc_locale_name. (cherry picked from commit d71e93949869b215cacf185afbabd560f058694d) CW-Bug-Id: #19646 --- dlls/msvcrt/locale.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 12c9bba506c..89118535494 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -471,32 +471,20 @@ static BOOL init_category_name(const char *name, int len, } #if _MSVCR_VER >= 110 -static inline BOOL set_lc_locale_name(pthreadlocinfo locinfo, int cat) +static inline BOOL set_lc_locale_name(pthreadlocinfo locinfo, int cat, WCHAR *sname) { - LCID lcid = locinfo->lc_handle[cat]; - WCHAR buf[100]; - int len; - locinfo->lc_category[cat].wrefcount = malloc(sizeof(int)); if(!locinfo->lc_category[cat].wrefcount) return FALSE; *locinfo->lc_category[cat].wrefcount = 1; - len = GetLocaleInfoW(lcid, LOCALE_SISO639LANGNAME - |LOCALE_NOUSEROVERRIDE, buf, 100); - if(!len) return FALSE; - - if(LocaleNameToLCID(buf, LOCALE_ALLOW_NEUTRAL_NAMES) != lcid) - len = LCIDToLocaleName(lcid, buf, 100, LOCALE_ALLOW_NEUTRAL_NAMES); - - if(!len || !(locinfo->lc_name[cat] = malloc(len*sizeof(wchar_t)))) + if(!(locinfo->lc_name[cat] = wcsdup(sname))) return FALSE; - memcpy(locinfo->lc_name[cat], buf, len*sizeof(wchar_t)); return TRUE; } #else -static inline BOOL set_lc_locale_name(pthreadlocinfo locinfo, int cat) +static inline BOOL set_lc_locale_name(pthreadlocinfo locinfo, int cat, WCHAR *sname) { return TRUE; } @@ -531,7 +519,7 @@ static BOOL update_threadlocinfo_category(WCHAR *sname, unsigned short cp, locinfo->lc_handle[category] = LocaleNameToLCID(sname, LCID_CONVERSION_FLAGS); - set_lc_locale_name(locinfo, category); + set_lc_locale_name(locinfo, category, sname); if(!locinfo->lc_category[category].locale) { char buf[256]; From ebea8c4ce066d2ffb70c2d8f8951b03e951ca601 Mon Sep 17 00:00:00 2001 From: Victor Chiletto Date: Thu, 8 Jun 2023 21:43:14 -0300 Subject: [PATCH 1577/2777] msvcrt: Remap synonyms to snames. Gives us more control over what we map to which is required due to changes in Chinese locales. (cherry picked from commit ec7816a42a010443110abef2bf203707623535ec) CW-Bug-Id: #19646 --- dlls/msvcrt/locale.c | 98 ++++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 41 deletions(-) diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 89118535494..7e759ddc6c6 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -172,43 +172,54 @@ static struct lconv cloc_lconv = /* Friendly country strings & language names abbreviations. */ static const char * const _country_synonyms[] = { - "american", "enu", - "american english", "enu", - "american-english", "enu", - "english-american", "enu", - "english-us", "enu", - "english-usa", "enu", - "us", "enu", - "usa", "enu", - "australian", "ena", - "english-aus", "ena", - "belgian", "nlb", - "french-belgian", "frb", - "canadian", "enc", - "english-can", "enc", - "french-canadian", "frc", - "chinese", "chs", - "chinese-simplified", "chs", - "chinese-traditional", "cht", - "dutch-belgian", "nlb", - "english-nz", "enz", - "uk", "eng", - "english-uk", "eng", - "french-swiss", "frs", - "swiss", "des", - "german-swiss", "des", - "italian-swiss", "its", - "german-austrian", "dea", - "portuguese", "ptb", - "portuguese-brazil", "ptb", - "spanish-mexican", "esm", - "norwegian-bokmal", "nor", - "norwegian-nynorsk", "non", - "spanish-modern", "esn" + "american", "en", + "american english", "en-US", + "american-english", "en-US", + "english-american", "en-US", + "english-us", "en-US", + "english-usa", "en-US", + "us", "en-US", + "usa", "en-US", + "australian", "en-AU", + "english-aus", "en-AU", + "belgian", "nl-BE", + "french-belgian", "fr-BE", + "canadian", "en-CA", + "english-can", "en-CA", + "french-canadian", "fr-CA", +#if _MSVCR_VER >= 110 + "chinese", "zh", + "chinese-simplified", "zh", + "chinese-traditional", "zh-HK", + "chs", "zh", + "cht", "zh-HK", +#else + "chinese", "zh-CN", + "chinese-simplified", "zh-CN", + "chinese-traditional", "zh-TW", + "chs", "zh-CN", + "cht", "zh-TW", +#endif + "dutch-belgian", "nl-BE", + "english-nz", "en-NZ", + "uk", "en-GB", + "english-uk", "en-GB", + "french-swiss", "fr-CH", + "swiss", "de-CH", + "german-swiss", "de-CH", + "italian-swiss", "it-CH", + "german-austrian", "de-AT", + "portuguese", "pt-BR", + "portuguese-brazil", "pt-BR", + "spanish-mexican", "es-MX", + "norwegian-bokmal", "nb", + "norwegian-nynorsk", "nn-NO", + "spanish-modern", "es-ES" }; + /* INTERNAL: Map a synonym to an ISO code */ -static void remap_synonym(char *name) +static BOOL remap_synonym(char *name) { unsigned int i; for (i = 0; i < ARRAY_SIZE(_country_synonyms); i += 2) @@ -217,9 +228,11 @@ static void remap_synonym(char *name) { TRACE(":Mapping synonym %s to %s\n",name,_country_synonyms[i+1]); strcpy(name, _country_synonyms[i+1]); - return; + return TRUE; } } + + return FALSE; } /* Note: Flags are weighted in order of matching importance */ @@ -270,7 +283,6 @@ find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam ) if (lcid == LOCALE_CUSTOM_UNSPECIFIED) return CONTINUE_LOOKING; -#if _MSVCR_VER >= 110 if (res->allow_sname && compare_info(lcid,LOCALE_SNAME,buff,res->search_language, TRUE)) { TRACE(":Found locale: %s->%s\n", res->search_language, buff); @@ -278,7 +290,6 @@ find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam ) res->found_lang_id = LANGIDFROMLCID(lcid); return STOP_LOOKING; } -#endif /* Check Language */ if (compare_info(lcid,LOCALE_SISO639LANGNAME,buff,res->search_language, TRUE) || @@ -345,6 +356,7 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m } else { WCHAR wbuf[LOCALE_NAME_MAX_LENGTH]; locale_search_t search; + BOOL remapped = FALSE; memset(&search, 0, sizeof(locale_search_t)); lstrcpynA(search.search_language, locale, MAX_ELEM_LEN); @@ -362,13 +374,17 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m search.search_language[cp-locale] = '\0'; } - if(!cp && !region) + if ((remapped = remap_synonym(search.search_language))) { - remap_synonym(search.search_language); + search.allow_sname = TRUE; + } + #if _MSVCR_VER >= 110 + if(!cp && !region) + { search.allow_sname = TRUE; -#endif } +#endif MultiByteToWideChar(CP_ACP, 0, search.search_language, -1, wbuf, LOCALE_NAME_MAX_LENGTH); if (search.allow_sname && IsValidLocaleName(wbuf)) @@ -392,7 +408,7 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m LCIDToLocaleName(search.found_lang_id, sname, sname_size, LOCALE_ALLOW_NEUTRAL_NAMES); } - is_sname = (search.match_flags & FOUND_SNAME) != 0; + is_sname = !remapped && (search.match_flags & FOUND_SNAME) != 0; } /* Obtain code page */ From e6a482a2b1e0499b29bd26c0989f03993bb1bd6c Mon Sep 17 00:00:00 2001 From: Victor Chiletto Date: Tue, 6 Jun 2023 20:12:08 -0300 Subject: [PATCH 1578/2777] msvcrt: Use GetLocaleInfoEx to compare locale info. GetLocaleInfoA doesn't return the proper sname for neutral LCIDs. (cherry picked from commit 8f663f3d5eb0ec6eb7dbb6816294df287c640487) CW-Bug-Id: #19646 --- dlls/msvcrt/locale.c | 73 ++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 7e759ddc6c6..9fa6ba76143 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -241,11 +241,11 @@ static BOOL remap_synonym(char *name) #define FOUND_COUNTRY 0x1 typedef struct { - char search_language[MAX_ELEM_LEN]; - char search_country[MAX_ELEM_LEN]; + WCHAR search_language[MAX_ELEM_LEN]; + WCHAR search_country[MAX_ELEM_LEN]; + WCHAR found_lang_sname[LOCALE_NAME_MAX_LENGTH]; DWORD found_codepage; unsigned int match_flags; - LANGID found_lang_id; BOOL allow_sname; } locale_search_t; @@ -253,50 +253,48 @@ typedef struct { #define STOP_LOOKING FALSE /* INTERNAL: Get and compare locale info with a given string */ -static int compare_info(LCID lcid, DWORD flags, char* buff, const char* cmp, BOOL exact) +static int compare_info(WCHAR *name, DWORD flags, WCHAR *buff, const WCHAR *cmp, BOOL exact) { int len; if(!cmp[0]) - return 0; + return 0; buff[0] = 0; - GetLocaleInfoA(lcid, flags|LOCALE_NOUSEROVERRIDE, buff, MAX_ELEM_LEN); + GetLocaleInfoEx(name, flags|LOCALE_NOUSEROVERRIDE, buff, MAX_ELEM_LEN); if (!buff[0]) return 0; /* Partial matches are only allowed on language/country names */ - len = strlen(cmp); + len = wcslen(cmp); + if(exact || len<=3) - return !_stricmp(cmp, buff); + return !_wcsicmp(cmp, buff); else - return !_strnicmp(cmp, buff, len); + return !_wcsnicmp(cmp, buff, len); } static BOOL CALLBACK find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam ) { locale_search_t *res = (locale_search_t *)lParam; - const LCID lcid = LocaleNameToLCID( name, LCID_CONVERSION_FLAGS ); - char buff[MAX_ELEM_LEN]; + WCHAR buff[MAX_ELEM_LEN]; unsigned int flags = 0; - if (lcid == LOCALE_CUSTOM_UNSPECIFIED) return CONTINUE_LOOKING; - - if (res->allow_sname && compare_info(lcid,LOCALE_SNAME,buff,res->search_language, TRUE)) + if (res->allow_sname && compare_info(name,LOCALE_SNAME,buff,res->search_language, TRUE)) { - TRACE(":Found locale: %s->%s\n", res->search_language, buff); + TRACE(":Found locale: %s->%s\n", wine_dbgstr_w(res->search_language), wine_dbgstr_w(buff)); res->match_flags = FOUND_SNAME; - res->found_lang_id = LANGIDFROMLCID(lcid); + wcscpy(res->found_lang_sname, name); return STOP_LOOKING; } /* Check Language */ - if (compare_info(lcid,LOCALE_SISO639LANGNAME,buff,res->search_language, TRUE) || - compare_info(lcid,LOCALE_SABBREVLANGNAME,buff,res->search_language, TRUE) || - compare_info(lcid,LOCALE_SENGLANGUAGE,buff,res->search_language, FALSE)) + if (compare_info(name,LOCALE_SISO639LANGNAME,buff,res->search_language, TRUE) || + compare_info(name,LOCALE_SABBREVLANGNAME,buff,res->search_language, TRUE) || + compare_info(name,LOCALE_SENGLANGUAGE,buff,res->search_language, FALSE)) { - TRACE(":Found language: %s->%s\n", res->search_language, buff); + TRACE(":Found language: %s->%s\n", wine_dbgstr_w(res->search_language), wine_dbgstr_w(buff)); flags |= FOUND_LANGUAGE; } else if (res->match_flags & FOUND_LANGUAGE) @@ -305,11 +303,11 @@ find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam ) } /* Check Country */ - if (compare_info(lcid,LOCALE_SISO3166CTRYNAME,buff,res->search_country, TRUE) || - compare_info(lcid,LOCALE_SABBREVCTRYNAME,buff,res->search_country, TRUE) || - compare_info(lcid,LOCALE_SENGCOUNTRY,buff,res->search_country, FALSE)) + if (compare_info(name,LOCALE_SISO3166CTRYNAME,buff,res->search_country, TRUE) || + compare_info(name,LOCALE_SABBREVCTRYNAME,buff,res->search_country, TRUE) || + compare_info(name,LOCALE_SENGCOUNTRY,buff,res->search_country, FALSE)) { - TRACE("Found country:%s->%s\n", res->search_country, buff); + TRACE("Found country:%s->%s\n", wine_dbgstr_w(res->search_country), wine_dbgstr_w(buff)); flags |= FOUND_COUNTRY; } else if (!flags && (res->match_flags & FOUND_COUNTRY)) @@ -321,7 +319,7 @@ find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam ) { /* Found a better match than previously */ res->match_flags = flags; - res->found_lang_id = LANGIDFROMLCID(lcid); + wcscpy(res->found_lang_sname, name); } if ((flags & (FOUND_LANGUAGE | FOUND_COUNTRY)) == (FOUND_LANGUAGE | FOUND_COUNTRY)) @@ -354,27 +352,27 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m if(!locale[0] || (cp == locale && !region)) { GetUserDefaultLocaleName(sname, sname_size); } else { - WCHAR wbuf[LOCALE_NAME_MAX_LENGTH]; + char search_language_buf[MAX_ELEM_LEN] = { 0 }, search_country_buf[MAX_ELEM_LEN] = { 0 }; locale_search_t search; BOOL remapped = FALSE; memset(&search, 0, sizeof(locale_search_t)); - lstrcpynA(search.search_language, locale, MAX_ELEM_LEN); + lstrcpynA(search_language_buf, locale, MAX_ELEM_LEN); if(region) { - lstrcpynA(search.search_country, region+1, MAX_ELEM_LEN); + lstrcpynA(search_country_buf, region+1, MAX_ELEM_LEN); if(region-locale < MAX_ELEM_LEN) - search.search_language[region-locale] = '\0'; + search_language_buf[region-locale] = '\0'; } else - search.search_country[0] = '\0'; + search_country_buf[0] = '\0'; if(cp) { if(region && cp-region-1 Date: Wed, 19 Jul 2023 22:17:25 +0100 Subject: [PATCH 1579/2777] msvcrt: Fix out-of-bound access in create_locinfo. Fixes regression introduced by 24a2b625545f1875b5c3177f2b9. Signed-off-by: Yuxuan Shui (cherry picked from commit f66c8972129e81707292a210ef4989a9ad57da89) CW-Bug-Id: #19646 --- dlls/msvcrt/locale.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 9fa6ba76143..10682990bfc 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -1226,7 +1226,7 @@ static __lc_time_data* create_time_data(WCHAR *sname) int i, ret, size; LCID lcid = LocaleNameToLCID(sname, LCID_CONVERSION_FLAGS); - size = sizeof(__lc_time_data); + size = 0; for(i=0; i= 110 - size += wcslen(sname)*sizeof(wchar_t); + size += (wcslen(sname) + 1) * sizeof(wchar_t); #endif - cur = malloc(size); + cur = malloc(FIELD_OFFSET(__lc_time_data, data[size])); if(!cur) return NULL; @@ -1256,13 +1256,13 @@ static __lc_time_data* create_time_data(WCHAR *sname) #if _MSVCR_VER == 0 || _MSVCR_VER >= 100 for(i=0; iwstr.wstr[i] = (wchar_t*)&cur->data[ret]; - ret += GetLocaleInfoEx(sname, time_data[i], - (wchar_t*)&cur->data[ret], size-ret)*sizeof(wchar_t); + ret += GetLocaleInfoEx(sname, time_data[i], (wchar_t*)&cur->data[ret], + (size - ret) / sizeof(wchar_t)) * sizeof(wchar_t); } #endif #if _MSVCR_VER >= 110 cur->locname = (wchar_t*)&cur->data[ret]; - wcsncpy((wchar_t *) &cur->data[ret], sname, size-ret); + wcscpy((wchar_t*)&cur->data[ret], sname); #else cur->lcid = lcid; #endif From 87f013a53f7414f17200620db21a1907562610e8 Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Fri, 21 Jul 2023 16:46:41 +0200 Subject: [PATCH 1580/2777] msvcrt: Pass correct buffer to locale_to_sname helper in create_locinfo. (cherry picked from commit 092e68b2e0654affb8a13aa5f5222315726e6278) CW-Bug-Id: #19646 --- dlls/msvcrt/locale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 10682990bfc..7e94d7bf2a8 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -1339,7 +1339,7 @@ static pthreadlocinfo create_locinfo(int category, locale_len[i] = p-locale; } } else { - locale_found = locale_to_sname(buf, &cp[i], &sname_match, wbuf, LOCALE_NAME_MAX_LENGTH); + locale_found = locale_to_sname(locale, &cp[i], &sname_match, wbuf, LOCALE_NAME_MAX_LENGTH); locale_sname[i] = wcsdup(wbuf); if(sname_match) { locale_name[i] = locale; From 6999432d55009884aa055bcbb6ff9b3bdf50b96f Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Fri, 21 Jul 2023 16:48:13 +0200 Subject: [PATCH 1581/2777] msvcrt: Improve locale_to_sname error handling. (cherry picked from commit f93f31dec58affa33d770a163490e760ed9991ee) CW-Bug-Id: #19646 --- dlls/msvcrt/locale.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 7e94d7bf2a8..854ec6e7158 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -1333,22 +1333,16 @@ static pthreadlocinfo create_locinfo(int category, memcpy(buf, locale, p-locale); buf[p-locale] = '\0'; locale_found = locale_to_sname(buf, &cp[i], &sname_match, wbuf, LOCALE_NAME_MAX_LENGTH); - locale_sname[i] = wcsdup(wbuf); - if(sname_match) { - locale_name[i] = locale; - locale_len[i] = p-locale; - } } else { locale_found = locale_to_sname(locale, &cp[i], &sname_match, wbuf, LOCALE_NAME_MAX_LENGTH); - locale_sname[i] = wcsdup(wbuf); - if(sname_match) { - locale_name[i] = locale; - locale_len[i] = strlen(locale); - } } - if(!locale_found || !locale_sname[i]) + if(!locale_found || !(locale_sname[i] = wcsdup(wbuf))) goto fail; + if(sname_match) { + locale_name[i] = locale; + locale_len[i] = p ? p-locale : strlen(locale); + } } if(!p || *(p+1)!='L' || *(p+2)!='C' || *(p+3)!='_') From a435608c6838580d4fd14b6fd4675f82a2a65fc5 Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Fri, 21 Jul 2023 17:44:02 +0200 Subject: [PATCH 1582/2777] msvcrt: Set sname_match in locale_to_sname when returning cached result. (cherry picked from commit 4a4f138fe9542e1bee240f3b98a3ab91afa842e2) CW-Bug-Id: #19646 --- dlls/msvcrt/locale.c | 6 ++++-- dlls/msvcrt/msvcrt.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 854ec6e7158..153c4fb1c7d 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -341,8 +341,9 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m if (!strcmp(locale, data->cached_locale)) { if (codepage) *codepage = data->cached_cp; - if (sname) - wcsncpy(sname, data->cached_sname, sname_size); + if (sname_match) + *sname_match = data->cached_sname_match; + wcsncpy(sname, data->cached_sname, sname_size); return TRUE; } @@ -441,6 +442,7 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m if (strlen(locale) < sizeof(data->cached_locale)) { strcpy(data->cached_locale, locale); data->cached_cp = locale_cp; + data->cached_sname_match = is_sname; wcscpy(data->cached_sname, sname); } diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h index 73c02cd03b4..35c90fd90e3 100644 --- a/dlls/msvcrt/msvcrt.h +++ b/dlls/msvcrt/msvcrt.h @@ -160,6 +160,7 @@ struct __thread_data { int processing_throw; frame_info *frame_info_head; void *unk8[6]; + BOOL cached_sname_match; WCHAR cached_sname[LOCALE_NAME_MAX_LENGTH]; int unk9[2]; DWORD cached_cp; From f3aab292dc7b49dbaddc4117cfac67870e01a6db Mon Sep 17 00:00:00 2001 From: Victor Chiletto Date: Fri, 21 Jul 2023 17:08:12 -0300 Subject: [PATCH 1583/2777] msvcrt: Remove unused struct locale_search_t member. (cherry picked from commit 85317b51cb61adb829f57ef3ef16d87a7ba30f45) CW-Bug-Id: #19646 --- dlls/msvcrt/locale.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 153c4fb1c7d..b14aa73af05 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -244,7 +244,6 @@ typedef struct { WCHAR search_language[MAX_ELEM_LEN]; WCHAR search_country[MAX_ELEM_LEN]; WCHAR found_lang_sname[LOCALE_NAME_MAX_LENGTH]; - DWORD found_codepage; unsigned int match_flags; BOOL allow_sname; } locale_search_t; From f8871a434904941cdefc6360a5a5b2a2186902e1 Mon Sep 17 00:00:00 2001 From: Victor Chiletto Date: Fri, 21 Jul 2023 19:20:21 -0300 Subject: [PATCH 1584/2777] msvcrt: Fix memory leak in create_locinfo. (cherry picked from commit 46596db7ed6a154dc1af98fc266ce2c47723fbaa) CW-Bug-Id: #19646 --- dlls/msvcrt/locale.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index b14aa73af05..a24c0c16a48 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -1959,6 +1959,9 @@ static pthreadlocinfo create_locinfo(int category, InterlockedIncrement(&locinfo->lc_time_curr->refcount); } + for (i = 0; i < LC_MAX; i++) + free(locale_sname[i]); + return locinfo; fail: From 8984af6a1c58ee7b8116f3e01a7e8b553edd8b2b Mon Sep 17 00:00:00 2001 From: Victor Chiletto Date: Fri, 21 Jul 2023 19:51:11 -0300 Subject: [PATCH 1585/2777] msvcrt: Remove uses of wcsncpy from locale_to_sname. (cherry picked from commit fd2ddf8f2a90da51635de7a7653209783f10032d) CW-Bug-Id: #19646 --- dlls/msvcrt/locale.c | 20 +++++++++++--------- dlls/msvcrt/mbcs.c | 2 +- dlls/msvcrt/msvcrt.h | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index a24c0c16a48..82083d66106 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -329,8 +329,10 @@ find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam ) return CONTINUE_LOOKING; } -/* Internal: Find the sname for a locale specification */ -BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_match, WCHAR *sname, int sname_size) +/* Internal: Find the sname for a locale specification. + * sname must be at least LOCALE_NAME_MAX_LENGTH characters long + */ +BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_match, WCHAR *sname) { thread_data_t *data = msvcrt_get_thread_data(); const char *cp, *region; @@ -342,7 +344,7 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m *codepage = data->cached_cp; if (sname_match) *sname_match = data->cached_sname_match; - wcsncpy(sname, data->cached_sname, sname_size); + wcscpy(sname, data->cached_sname); return TRUE; } @@ -350,7 +352,7 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m region = strchr(locale, '_'); if(!locale[0] || (cp == locale && !region)) { - GetUserDefaultLocaleName(sname, sname_size); + GetUserDefaultLocaleName(sname, LOCALE_NAME_MAX_LENGTH); } else { char search_language_buf[MAX_ELEM_LEN] = { 0 }, search_country_buf[MAX_ELEM_LEN] = { 0 }; locale_search_t search; @@ -388,7 +390,7 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m if (search.allow_sname && IsValidLocaleName(search.search_language)) { search.match_flags = FOUND_SNAME; - wcsncpy(sname, search.search_language, sname_size); + wcscpy(sname, search.search_language); } else { @@ -404,7 +406,7 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m if (search.search_country[0] && !(search.match_flags & FOUND_COUNTRY)) return FALSE; - wcsncpy(sname, search.found_lang_sname, sname_size); + wcscpy(sname, search.found_lang_sname); } is_sname = !remapped && (search.match_flags & FOUND_SNAME) != 0; @@ -1333,9 +1335,9 @@ static pthreadlocinfo create_locinfo(int category, if(p) { memcpy(buf, locale, p-locale); buf[p-locale] = '\0'; - locale_found = locale_to_sname(buf, &cp[i], &sname_match, wbuf, LOCALE_NAME_MAX_LENGTH); + locale_found = locale_to_sname(buf, &cp[i], &sname_match, wbuf); } else { - locale_found = locale_to_sname(locale, &cp[i], &sname_match, wbuf, LOCALE_NAME_MAX_LENGTH); + locale_found = locale_to_sname(locale, &cp[i], &sname_match, wbuf); } if(!locale_found || !(locale_sname[i] = wcsdup(wbuf))) @@ -1352,7 +1354,7 @@ static pthreadlocinfo create_locinfo(int category, locale = p+1; } } else { - BOOL locale_found = locale_to_sname(locale, &cp[0], &sname_match, wbuf, LOCALE_NAME_MAX_LENGTH); + BOOL locale_found = locale_to_sname(locale, &cp[0], &sname_match, wbuf); if(!locale_found) return NULL; diff --git a/dlls/msvcrt/mbcs.c b/dlls/msvcrt/mbcs.c index 8598bceb029..c8390288d4a 100644 --- a/dlls/msvcrt/mbcs.c +++ b/dlls/msvcrt/mbcs.c @@ -254,7 +254,7 @@ threadmbcinfo* create_mbcinfo(int cp, LCID lcid, threadmbcinfo *old_mbcinfo) if(lcid == -1) { WCHAR wbuf[LOCALE_NAME_MAX_LENGTH]; sprintf(bufA, ".%d", newcp); - mbcinfo->mblcid = locale_to_sname(bufA, NULL, NULL, wbuf, LOCALE_NAME_MAX_LENGTH) ? LocaleNameToLCID(wbuf, LOCALE_ALLOW_NEUTRAL_NAMES) : -1; + mbcinfo->mblcid = locale_to_sname(bufA, NULL, NULL, wbuf) ? LocaleNameToLCID(wbuf, LOCALE_ALLOW_NEUTRAL_NAMES) : -1; } else { mbcinfo->mblcid = lcid; } diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h index 35c90fd90e3..5fbd5497804 100644 --- a/dlls/msvcrt/msvcrt.h +++ b/dlls/msvcrt/msvcrt.h @@ -176,7 +176,7 @@ typedef struct __thread_data thread_data_t; extern thread_data_t *CDECL msvcrt_get_thread_data(void) DECLSPEC_HIDDEN; -BOOL locale_to_sname(const char*, unsigned short*, BOOL*, WCHAR*, int) DECLSPEC_HIDDEN; +BOOL locale_to_sname(const char*, unsigned short*, BOOL*, WCHAR*) DECLSPEC_HIDDEN; extern _locale_t MSVCRT_locale DECLSPEC_HIDDEN; extern __lc_time_data cloc_time_data DECLSPEC_HIDDEN; extern unsigned int MSVCRT___lc_codepage; From 47a8c57f4ce4305c75fd6587cd65040df409bd91 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Fri, 25 Aug 2023 09:34:45 +0200 Subject: [PATCH 1586/2777] dbghelp: Protect ELF's link_map walking in case of bogus entries. That's not fixing the cause of the bug below, but protects it from hanging while walking the bogus list. CW-Bug-Id: #22658 --- dlls/dbghelp/elf_module.c | 86 +++++++++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 16 deletions(-) diff --git a/dlls/dbghelp/elf_module.c b/dlls/dbghelp/elf_module.c index bc063bf1466..55d614a316c 100644 --- a/dlls/dbghelp/elf_module.c +++ b/dlls/dbghelp/elf_module.c @@ -1454,6 +1454,59 @@ static BOOL elf_search_and_load_file(struct process* pcs, const WCHAR* filename, typedef BOOL (*enum_elf_modules_cb)(const WCHAR*, ULONG_PTR load_addr, ULONG_PTR dyn_addr, BOOL is_system, void* user); +static BOOL elf_linkmap_validate_entry(const struct process* pcs, DWORD64 base, DWORD64 name_addr, WCHAR* buffer, SIZE_T buflen) +{ + static DWORD page_size; + MEMORY_BASIC_INFORMATION mem_info; + char bufstr[MAX_PATH]; + + if (!page_size) + { + SYSTEM_INFO sys_info; + GetSystemInfo(&sys_info); + page_size = sys_info.dwPageSize; + } + if (base & (page_size - 1)) + { + WARN("Unaligned base addr=%I64x page_size=%lx\n", base, page_size); + return FALSE; + } + if (VirtualQueryEx(pcs->handle, (void*)(ULONG_PTR)base, &mem_info, sizeof(mem_info))) + { + if (mem_info.BaseAddress != (void*)(ULONG_PTR)base) + { + WARN("Invalid base addr %I64x (beg map at %p)\n", base, mem_info.BaseAddress); + return FALSE; + } + } + else + { + /* Some ELF modules are loaded in 32bit mode above 2G limit, + * and virtual query will fail on these addresses when process is not large address aware. + * Don't consider this as an error for a 32bit debuggee. + */ + if (pcs->is_64bit) + { + WARN("Invalid base addr %I64x\n", base); + return FALSE; + } + } + + memset(bufstr, ' ', sizeof(bufstr)); + if (!read_process_memory(pcs, name_addr, bufstr, sizeof(bufstr))) + { + WARN("Invalid name_address %I64x\n", name_addr); + return FALSE; + } + if (!memchr(bufstr, '\0', sizeof(bufstr))) + { + WARN("Unterminated string %s\n", wine_dbgstr_an(bufstr, sizeof(bufstr))); + return FALSE; + } + MultiByteToWideChar(CP_UNIXCP, 0, bufstr, -1, buffer, buflen); + return TRUE; +} + /****************************************************************** * elf_enum_modules_internal * @@ -1463,8 +1516,7 @@ static BOOL elf_enum_modules_internal(const struct process* pcs, const WCHAR* main_name, enum_elf_modules_cb cb, void* user) { - WCHAR bufstrW[MAX_PATH]; - char bufstr[256]; + WCHAR bufstr[MAX_PATH]; ULONG_PTR lm_addr; if (pcs->is_64bit) @@ -1498,15 +1550,16 @@ static BOOL elf_enum_modules_internal(const struct process* pcs, if (!read_process_memory(pcs, lm_addr, &lm, sizeof(lm))) return FALSE; - if (lm.l_prev && /* skip first entry, normally debuggee itself */ - lm.l_name && read_process_memory(pcs, lm.l_name, bufstr, sizeof(bufstr))) + /* skip first entry(normally debuggee itself) and entries without names */ + if (!lm.l_prev || !lm.l_name) continue; + if (!elf_linkmap_validate_entry(pcs, lm.l_addr, lm.l_name, bufstr, ARRAY_SIZE(bufstr))) { - bufstr[sizeof(bufstr) - 1] = '\0'; - MultiByteToWideChar(CP_UNIXCP, 0, bufstr, -1, bufstrW, ARRAY_SIZE(bufstrW)); - if (main_name && !bufstrW[0]) lstrcpyW(bufstrW, main_name); - if (!cb(bufstrW, (ULONG_PTR)lm.l_addr, (ULONG_PTR)lm.l_ld, FALSE, user)) - break; + FIXME("Incorrect link_map entry, bailing out\n"); + return FALSE; } + if (main_name && !bufstr[0]) lstrcpyW(bufstr, main_name); + if (!cb(bufstr, (ULONG_PTR)lm.l_addr, (ULONG_PTR)lm.l_ld, FALSE, user)) + break; } } else @@ -1540,15 +1593,16 @@ static BOOL elf_enum_modules_internal(const struct process* pcs, if (!read_process_memory(pcs, lm_addr, &lm, sizeof(lm))) return FALSE; - if (lm.l_prev && /* skip first entry, normally debuggee itself */ - lm.l_name && read_process_memory(pcs, lm.l_name, bufstr, sizeof(bufstr))) + /* skip first entry(normally debuggee itself) and entries without names */ + if (!lm.l_prev || !lm.l_name) continue; + if (!elf_linkmap_validate_entry(pcs, lm.l_addr, lm.l_name, bufstr, ARRAY_SIZE(bufstr))) { - bufstr[sizeof(bufstr) - 1] = '\0'; - MultiByteToWideChar(CP_UNIXCP, 0, bufstr, -1, bufstrW, ARRAY_SIZE(bufstrW)); - if (main_name && !bufstrW[0]) lstrcpyW(bufstrW, main_name); - if (!cb(bufstrW, (ULONG_PTR)lm.l_addr, (ULONG_PTR)lm.l_ld, FALSE, user)) - break; + FIXME("Incorrect link_map entry, bailing out\n"); + return FALSE; } + if (main_name && !bufstr[0]) lstrcpyW(bufstr, main_name); + if (!cb(bufstr, (ULONG_PTR)lm.l_addr, (ULONG_PTR)lm.l_ld, FALSE, user)) + break; } } From 4846d0ba96fc8552cd4494c6afdb2b66f62238d2 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Tue, 4 Jul 2023 12:40:52 +0200 Subject: [PATCH 1587/2777] windows.media.speech: Adding a couple of synthesizer's options tests. Signed-off-by: Eric Pouech CW-Bug-Id: #20134 --- dlls/windows.media.speech/tests/speech.c | 38 ++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 445d10923ae..290a8545c0e 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -1032,16 +1032,54 @@ static void test_SpeechSynthesizer(void) if (hr == S_OK) { + ISpeechSynthesizerOptions2 *options2; ISpeechSynthesizerOptions3 *options3; + boolean bool_value; + DOUBLE double_value; + enum SpeechAppendedSilence silence_value; + enum SpeechPunctuationSilence punctuation_value; check_interface(options, &IID_IAgileObject, TRUE); + bool_value = 0xff; + hr = ISpeechSynthesizerOptions_get_IncludeSentenceBoundaryMetadata(options, &bool_value); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(! bool_value, "Got unepected option %u\n", bool_value); + bool_value = 0xff; + hr = ISpeechSynthesizerOptions_get_IncludeWordBoundaryMetadata(options, &bool_value); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!bool_value, "Got unepected option %u\n", bool_value); + check_optional_interface(options, &IID_ISpeechSynthesizerOptions2, TRUE); /* Requires Win10 >= 1709 */ + hr = ISpeechSynthesizerOptions_QueryInterface(options, &IID_ISpeechSynthesizerOptions2, (void **)&options2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ISpeechSynthesizerOptions2_get_AudioPitch(options2, &double_value); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(double_value == 1.0f, "Got unepected option %f\n", double_value); + + hr = ISpeechSynthesizerOptions2_get_AudioVolume(options2, &double_value); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(double_value == 1.0f, "Got unepected option %f\n", double_value); + + hr = ISpeechSynthesizerOptions2_get_SpeakingRate(options2, &double_value); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(double_value == 1.0f, "Got unepected option %f\n", double_value); + + ISpeechSynthesizerOptions2_Release(options2); hr = ISpeechSynthesizerOptions_QueryInterface(options, &IID_ISpeechSynthesizerOptions3, (void **)&options3); ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Got unexpected hr %#lx.\n", hr); /* Requires Win10 >= 1803 */ if (hr == S_OK) { + hr = ISpeechSynthesizerOptions3_get_AppendedSilence(options3, &silence_value); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(silence_value == SpeechAppendedSilence_Default, "Got unepected option %u\n", silence_value); + + hr = ISpeechSynthesizerOptions3_get_PunctuationSilence(options3, &punctuation_value); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(punctuation_value == SpeechPunctuationSilence_Default, "Got unepected option %u\n", punctuation_value); + ref = ISpeechSynthesizerOptions3_Release(options3); ok(ref == 2, "Got unexpected ref %lu.\n", ref); } From 035205a44756e674fda854c2612cca44c3e1b8e2 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Tue, 4 Jul 2023 12:40:52 +0200 Subject: [PATCH 1588/2777] windows.media.speech: Add basic implementation on synthesizer options. Signed-off-by: Eric Pouech CW-Bug-Id: #20134 --- dlls/windows.media.speech/synthesizer.c | 326 ++++++++++++++++++++++- dlls/windows.media.speech/tests/speech.c | 2 +- 2 files changed, 325 insertions(+), 3 deletions(-) diff --git a/dlls/windows.media.speech/synthesizer.c b/dlls/windows.media.speech/synthesizer.c index ce257c7c355..5b1fc633134 100644 --- a/dlls/windows.media.speech/synthesizer.c +++ b/dlls/windows.media.speech/synthesizer.c @@ -280,6 +280,309 @@ static HRESULT synthesis_stream_create( ISpeechSynthesisStream **out ) return hr; } +/* + * + * SpeechSynthesizerOptions runtimeclass + * + */ +struct synthesizer_options +{ + ISpeechSynthesizerOptions ISpeechSynthesizerOptions_iface; + ISpeechSynthesizerOptions2 ISpeechSynthesizerOptions2_iface; + ISpeechSynthesizerOptions3 ISpeechSynthesizerOptions3_iface; + LONG ref; + + /* options */ + boolean include_word_boundary; + boolean include_sentence_boundary; + + /* options 2 */ + double audio_volume; + double speaking_rate; + double audio_pitch; + + /* options 3 */ + enum SpeechAppendedSilence appended_silence; + enum SpeechPunctuationSilence punctuation_silence; +}; + +static inline struct synthesizer_options *impl_from_ISpeechSynthesizerOptions( ISpeechSynthesizerOptions *iface ) +{ + return CONTAINING_RECORD(iface, struct synthesizer_options, ISpeechSynthesizerOptions_iface); +} + +static HRESULT WINAPI synthesizer_options_QueryInterface( ISpeechSynthesizerOptions *iface, REFIID iid, void **out) +{ + struct synthesizer_options *impl = impl_from_ISpeechSynthesizerOptions(iface); + + TRACE("iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_IAgileObject) || + IsEqualGUID(iid, &IID_ISpeechSynthesizerOptions)) + { + IInspectable_AddRef((*out = &impl->ISpeechSynthesizerOptions_iface)); + return S_OK; + } + + if (IsEqualGUID(iid, &IID_ISpeechSynthesizerOptions2)) + { + IInspectable_AddRef((*out = &impl->ISpeechSynthesizerOptions2_iface)); + return S_OK; + } + + if (IsEqualGUID(iid, &IID_ISpeechSynthesizerOptions3)) + { + IInspectable_AddRef((*out = &impl->ISpeechSynthesizerOptions3_iface)); + return S_OK; + } + + FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI synthesizer_options_AddRef( ISpeechSynthesizerOptions *iface ) +{ + struct synthesizer_options *impl = impl_from_ISpeechSynthesizerOptions(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + + TRACE("iface %p, ref %lu.\n", iface, ref); + return ref; +} + +static ULONG WINAPI synthesizer_options_Release( ISpeechSynthesizerOptions *iface ) +{ + struct synthesizer_options *impl = impl_from_ISpeechSynthesizerOptions(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + + TRACE("iface %p, ref %lu.\n", iface, ref); + if (ref == 0) + free(impl); + return ref; +} + +static HRESULT WINAPI synthesizer_options_GetIids( ISpeechSynthesizerOptions *iface, ULONG *iid_count, IID **iids ) +{ + FIXME("iface %p, iid_count %p, iids %p stub.\n", iface, iid_count, iids); + return E_NOTIMPL; +} + +static HRESULT WINAPI synthesizer_options_GetRuntimeClassName( ISpeechSynthesizerOptions *iface, HSTRING *class_name ) +{ + FIXME("iface %p, class_name %p stub.\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT WINAPI synthesizer_options_GetTrustLevel( ISpeechSynthesizerOptions *iface, TrustLevel *trust_level ) +{ + FIXME("iface %p, trust_level %p stub.\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT WINAPI synthesizer_options_get_IncludeWordBoundaryMetadata( ISpeechSynthesizerOptions *iface, boolean *value ) +{ + struct synthesizer_options *impl = impl_from_ISpeechSynthesizerOptions(iface); + TRACE("iface %p, value %p semi-stub.\n", iface, value); + + *value = impl->include_word_boundary; + return S_OK; +} + +static HRESULT WINAPI synthesizer_options_put_IncludeWordBoundaryMetadata( ISpeechSynthesizerOptions *iface, boolean value ) +{ + struct synthesizer_options *impl = impl_from_ISpeechSynthesizerOptions(iface); + TRACE("iface %p, value %s semi-stub.\n", iface, value ? "true" : "false"); + + impl->include_word_boundary = value; + return S_OK; +} + +static HRESULT WINAPI synthesizer_options_get_IncludeSentenceBoundaryMetadata( ISpeechSynthesizerOptions *iface, boolean *value ) +{ + struct synthesizer_options *impl = impl_from_ISpeechSynthesizerOptions(iface); + TRACE("iface %p, value %p stub.\n", iface, value); + + *value = impl->include_sentence_boundary; + return S_OK; +} + +static HRESULT WINAPI synthesizer_options_put_IncludeSentenceBoundaryMetadata( ISpeechSynthesizerOptions *iface, boolean value ) +{ + struct synthesizer_options *impl = impl_from_ISpeechSynthesizerOptions(iface); + TRACE("iface %p, value %s stub.\n", iface, value ? "true" : "false"); + + impl->include_sentence_boundary = value; + return S_OK; +} + +static const struct ISpeechSynthesizerOptionsVtbl synthesizer_options_vtbl = +{ + /*** IUnknown methods ***/ + synthesizer_options_QueryInterface, + synthesizer_options_AddRef, + synthesizer_options_Release, + /*** IInspectable methods ***/ + synthesizer_options_GetIids, + synthesizer_options_GetRuntimeClassName, + synthesizer_options_GetTrustLevel, + /*** ISpeechSynthesizerOptions methods ***/ + synthesizer_options_get_IncludeWordBoundaryMetadata, + synthesizer_options_put_IncludeWordBoundaryMetadata, + synthesizer_options_get_IncludeSentenceBoundaryMetadata, + synthesizer_options_put_IncludeSentenceBoundaryMetadata, +}; + +DEFINE_IINSPECTABLE(synthesizer_options2, ISpeechSynthesizerOptions2, struct synthesizer_options, ISpeechSynthesizerOptions_iface) + +static HRESULT WINAPI synthesizer_options2_get_AudioVolume( ISpeechSynthesizerOptions2 *iface, DOUBLE *value) +{ + struct synthesizer_options *impl = impl_from_ISpeechSynthesizerOptions2(iface); + + TRACE("iface %p value %p semi-stub!\n", iface, value); + *value = impl->audio_volume; + return S_OK; +} + +static HRESULT WINAPI synthesizer_options2_put_AudioVolume( ISpeechSynthesizerOptions2 *iface, DOUBLE value) +{ + struct synthesizer_options *impl = impl_from_ISpeechSynthesizerOptions2(iface); + + TRACE("iface %p value %g semi-stub!\n", iface, value); + impl->audio_volume = value; + return S_OK; +} + +static HRESULT WINAPI synthesizer_options2_get_SpeakingRate( ISpeechSynthesizerOptions2 *iface, DOUBLE *value) +{ + struct synthesizer_options *impl = impl_from_ISpeechSynthesizerOptions2(iface); + + TRACE("iface %p value %p semi-stub!\n", iface, value); + *value = impl->speaking_rate; + return S_OK; +} + +static HRESULT WINAPI synthesizer_options2_put_SpeakingRate( ISpeechSynthesizerOptions2 *iface, DOUBLE value) +{ + struct synthesizer_options *impl = impl_from_ISpeechSynthesizerOptions2(iface); + + TRACE("iface %p value %g semi-stub!\n", iface, value); + impl->speaking_rate = value; + return S_OK; +} + +static HRESULT WINAPI synthesizer_options2_get_AudioPitch( ISpeechSynthesizerOptions2 *iface, DOUBLE *value) +{ + struct synthesizer_options *impl = impl_from_ISpeechSynthesizerOptions2(iface); + + TRACE("iface %p value %p semi-stub!\n", iface, value); + *value = impl->audio_pitch; + return S_OK; +} + +static HRESULT WINAPI synthesizer_options2_put_AudioPitch( ISpeechSynthesizerOptions2 *iface, DOUBLE value) +{ + struct synthesizer_options *impl = impl_from_ISpeechSynthesizerOptions2(iface); + + TRACE("iface %p value %g semi-stub!\n", iface, value); + impl->audio_pitch = value; + return S_OK; +} + +static const struct ISpeechSynthesizerOptions2Vtbl synthesizer_options2_vtbl = +{ + /*** IUnknown methods ***/ + synthesizer_options2_QueryInterface, + synthesizer_options2_AddRef, + synthesizer_options2_Release, + /*** IInspectable methods ***/ + synthesizer_options2_GetIids, + synthesizer_options2_GetRuntimeClassName, + synthesizer_options2_GetTrustLevel, + /*** ISpeechSynthesizerOptions methods ***/ + synthesizer_options2_get_AudioVolume, + synthesizer_options2_put_AudioVolume, + synthesizer_options2_get_SpeakingRate, + synthesizer_options2_put_SpeakingRate, + synthesizer_options2_get_AudioPitch, + synthesizer_options2_put_AudioPitch, +}; + +DEFINE_IINSPECTABLE(synthesizer_options3, ISpeechSynthesizerOptions3, struct synthesizer_options, ISpeechSynthesizerOptions_iface) + +static HRESULT WINAPI synthesizer_options3_get_AppendedSilence( ISpeechSynthesizerOptions3 *iface, enum SpeechAppendedSilence *value) +{ + struct synthesizer_options *impl = impl_from_ISpeechSynthesizerOptions3(iface); + + TRACE("iface %p value %p semi-stub!\n", iface, value); + *value = impl->appended_silence; + return S_OK; +} + +static HRESULT WINAPI synthesizer_options3_put_AppendedSilence( ISpeechSynthesizerOptions3 *iface, enum SpeechAppendedSilence value) +{ + struct synthesizer_options *impl = impl_from_ISpeechSynthesizerOptions3(iface); + + TRACE("iface %p value %u semi-stub!\n", iface, value); + impl->appended_silence = value; + return S_OK; +} + +static HRESULT WINAPI synthesizer_options3_get_PunctuationSilence( ISpeechSynthesizerOptions3 *iface, enum SpeechPunctuationSilence *value) +{ + struct synthesizer_options *impl = impl_from_ISpeechSynthesizerOptions3(iface); + + TRACE("iface %p value %p semi-stub!\n", iface, value); + *value = impl->punctuation_silence; + return S_OK; +} + +static HRESULT WINAPI synthesizer_options3_put_PunctuationSilence( ISpeechSynthesizerOptions3 *iface, enum SpeechPunctuationSilence value) +{ + struct synthesizer_options *impl = impl_from_ISpeechSynthesizerOptions3(iface); + + TRACE("iface %p value %u semi-stub!\n", iface, value); + impl->punctuation_silence = value; + return S_OK; +} + +static const struct ISpeechSynthesizerOptions3Vtbl synthesizer_options3_vtbl = +{ + /*** IUnknown methods ***/ + synthesizer_options3_QueryInterface, + synthesizer_options3_AddRef, + synthesizer_options3_Release, + /*** IInspectable methods ***/ + synthesizer_options3_GetIids, + synthesizer_options3_GetRuntimeClassName, + synthesizer_options3_GetTrustLevel, + /*** ISpeechSynthesizerOptions methods ***/ + synthesizer_options3_get_AppendedSilence, + synthesizer_options3_put_AppendedSilence, + synthesizer_options3_get_PunctuationSilence, + synthesizer_options3_put_PunctuationSilence, +}; + +static HRESULT synthesizer_options_allocate( struct synthesizer_options **out ) +{ + struct synthesizer_options *options; + + if (!(options = calloc(1, sizeof(*options)))) return E_OUTOFMEMORY; + + options->ISpeechSynthesizerOptions_iface.lpVtbl = &synthesizer_options_vtbl; + options->ISpeechSynthesizerOptions2_iface.lpVtbl = &synthesizer_options2_vtbl; + options->ISpeechSynthesizerOptions3_iface.lpVtbl = &synthesizer_options3_vtbl; + /* all other values default to 0 or false */ + options->audio_pitch = 1.0; + options->audio_volume = 1.0; + options->speaking_rate = 1.0; + options->ref = 1; + *out = options; + + return S_OK; +} + /* * * SpeechSynthesizer runtimeclass @@ -292,6 +595,8 @@ struct synthesizer ISpeechSynthesizer2 ISpeechSynthesizer2_iface; IClosable IClosable_iface; LONG ref; + + struct synthesizer_options *options; }; /* @@ -352,7 +657,11 @@ static ULONG WINAPI synthesizer_Release( ISpeechSynthesizer *iface ) TRACE("iface %p, ref %lu.\n", iface, ref); if (!ref) + { + if (impl->options) + ISpeechSynthesizerOptions_Release(&impl->options->ISpeechSynthesizerOptions_iface); free(impl); + } return ref; } @@ -440,8 +749,21 @@ DEFINE_IINSPECTABLE(synthesizer2, ISpeechSynthesizer2, struct synthesizer, ISpee static HRESULT WINAPI synthesizer2_get_Options( ISpeechSynthesizer2 *iface, ISpeechSynthesizerOptions **value ) { - FIXME("iface %p, value %p stub.\n", iface, value); - return E_NOTIMPL; + struct synthesizer *impl = impl_from_ISpeechSynthesizer2(iface); + + WARN("iface %p, value %p semi-stub.\n", iface, value); + if (!impl->options) + { + struct synthesizer_options *options; + HRESULT hr = synthesizer_options_allocate(&options); + if (FAILED(hr)) return hr; + + if (InterlockedCompareExchangePointer((void **)&impl->options, options, NULL) != NULL) + /* another thread beat us */ + ISpeechSynthesizerOptions_AddRef(&options->ISpeechSynthesizerOptions_iface); + } + ISpeechSynthesizerOptions_AddRef(*value = &impl->options->ISpeechSynthesizerOptions_iface); + return S_OK; } static const struct ISpeechSynthesizer2Vtbl synthesizer2_vtbl = diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 290a8545c0e..68ddbd87c6c 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -1028,7 +1028,7 @@ static void test_SpeechSynthesizer(void) ISpeechSynthesizerOptions *options; hr = ISpeechSynthesizer2_get_Options(synthesizer2, &options); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); if (hr == S_OK) { From d088577a834c1c74609bd9ef2f8a5abfb605f291 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Tue, 4 Jul 2023 12:40:52 +0200 Subject: [PATCH 1589/2777] windows.media.speech: Add more tests about IVoiceInformation. Signed-off-by: Eric Pouech CW-Bug-Id: #20134 --- dlls/windows.media.speech/tests/speech.c | 73 +++++++++++++++++++++++- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 68ddbd87c6c..50d944c8f61 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -682,6 +682,66 @@ static HRESULT WINAPI iterable_hstring_create_static( struct iterable_hstring *i return S_OK; } +#define check_comparable_presence(a, b) _check_comparable_presence( __LINE__, (a), (b)) +static void _check_comparable_presence( unsigned line, IVectorView_VoiceInformation *voices, IVoiceInformation *voice) +{ + HSTRING in_display, in_id, in_language; + HSTRING vc_display, vc_id, vc_language; + IVoiceInformation *vc_voice; + enum VoiceGender in_gender, vc_gender; + UINT32 size, idx, found_count = 0; + HRESULT hr; + INT32 cmp; + + hr = IVoiceInformation_get_DisplayName(voice, &in_display); + ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IVoiceInformation_get_Id(voice, &in_id); + ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IVoiceInformation_get_Language(voice, &in_language); + ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IVoiceInformation_get_Gender(voice, &in_gender); + ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IVectorView_VoiceInformation_get_Size(voices, &size); + ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + for (idx = 0; SUCCEEDED(hr = IVectorView_VoiceInformation_GetAt(voices, idx, &vc_voice)); idx++) + { + hr = IVoiceInformation_get_DisplayName(vc_voice, &vc_display); + ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IVoiceInformation_get_Id(vc_voice, &vc_id); + ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IVoiceInformation_get_Language(vc_voice, &vc_language); + ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IVoiceInformation_get_Gender(vc_voice, &vc_gender); + ok_(__FILE__, line)(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + trace("%u] %s/%s/%s/%u\n", + idx - 1, debugstr_hstring(vc_display), debugstr_hstring(vc_id), debugstr_hstring(vc_language), vc_gender); + + if (SUCCEEDED(WindowsCompareStringOrdinal(in_display, vc_display, &cmp)) && !cmp && + SUCCEEDED(WindowsCompareStringOrdinal(in_id, vc_id, &cmp)) && !cmp && + SUCCEEDED(WindowsCompareStringOrdinal(in_language, vc_language, &cmp)) && !cmp && + in_gender == vc_gender) + { + found_count++; + } + WindowsDeleteString(vc_display); + WindowsDeleteString(vc_id); + WindowsDeleteString(vc_language); + IVoiceInformation_Release(vc_voice); + } + ok(hr == E_BOUNDS, "Got unexpected hr %#lx.\n", hr); + ok(idx != 0, "Vector view shouldn't be empty!\n"); + ok(idx == size, "Incoherent index/size %u/%u!\n", idx, size); + + ok_(__FILE__, line)(found_count == 1, "Found several (%u) instances of %s/%s/%s/%u\n", + found_count, + debugstr_hstring(in_display), debugstr_hstring(in_id), debugstr_hstring(in_language), in_gender); + + WindowsDeleteString(in_display); + WindowsDeleteString(in_id); + WindowsDeleteString(in_language); +} + static void test_ActivationFactory(void) { static const WCHAR *synthesizer_name = L"Windows.Media.SpeechSynthesis.SpeechSynthesizer"; @@ -806,7 +866,8 @@ static void test_SpeechSynthesizer(void) HMODULE hdll; HSTRING str, str2; HRESULT hr; - UINT32 size; + UINT32 size, idx; + BOOLEAN found; ULONG ref; hr = RoInitialize(RO_INIT_MULTITHREADED); @@ -900,13 +961,19 @@ static void test_SpeechSynthesizer(void) ok(hr == S_OK, "IVectorView_VoiceInformation_GetMany failed, hr %#lx\n", hr); ok(size == 0, "IVectorView_VoiceInformation_GetMany returned count %u\n", size); - IVectorView_VoiceInformation_Release(voices); - hr = IInstalledVoicesStatic_get_DefaultVoice(voices_static, &voice); todo_wine ok(hr == S_OK, "IInstalledVoicesStatic_get_DefaultVoice failed, hr %#lx\n", hr); if (hr == S_OK) { + /* check that VoiceInformation in static vector voice are not shared when exposed to user */ + idx = size; + hr = IVectorView_VoiceInformation_IndexOf(voices, voice, &idx, &found); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!found, "Shouldn't find default element\n"); + + check_comparable_presence(voices, voice); + IVoiceInformation_get_Description(voice, &str2); trace("SpeechSynthesizer default voice %s.\n", debugstr_hstring(str2)); From 2f2de1e1375dc013d292c8e81edc984719e5d4b0 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Tue, 4 Jul 2023 12:40:52 +0200 Subject: [PATCH 1590/2777] windows.media.speech: Add basic implementation of IVoiceInformation. Signed-off-by: Eric Pouech CW-Bug-Id: #20134 --- dlls/windows.media.speech/synthesizer.c | 181 ++++++++++++++++++++++++ 1 file changed, 181 insertions(+) diff --git a/dlls/windows.media.speech/synthesizer.c b/dlls/windows.media.speech/synthesizer.c index 5b1fc633134..9003d041860 100644 --- a/dlls/windows.media.speech/synthesizer.c +++ b/dlls/windows.media.speech/synthesizer.c @@ -23,6 +23,187 @@ WINE_DEFAULT_DEBUG_CHANNEL(speech); +struct voice_information +{ + IVoiceInformation IVoiceInformation_iface; + LONG ref; + + HSTRING id; + HSTRING display_name; + HSTRING language; + HSTRING description; + VoiceGender gender; +}; + +static inline struct voice_information *impl_from_IVoiceInformation( IVoiceInformation *iface ) +{ + return CONTAINING_RECORD(iface, struct voice_information, IVoiceInformation_iface); +} + +static void voice_information_delete( struct voice_information *voice_info ) +{ + WindowsDeleteString(voice_info->id); + WindowsDeleteString(voice_info->display_name); + WindowsDeleteString(voice_info->language); + WindowsDeleteString(voice_info->description); + free(voice_info); +} + +static HRESULT WINAPI voice_information_QueryInterface( IVoiceInformation *iface, REFIID iid, void **ppvObject) +{ + struct voice_information *impl = impl_from_IVoiceInformation( iface ); + + TRACE("iface %p, riid %s, ppv %p\n", iface, wine_dbgstr_guid(iid), ppvObject); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_IVoiceInformation)) + { + IInspectable_AddRef((*ppvObject = &impl->IVoiceInformation_iface)); + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *ppvObject = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI voice_information_AddRef( IVoiceInformation *iface ) +{ + struct voice_information *impl = impl_from_IVoiceInformation(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + return ref; +} + +static ULONG WINAPI voice_information_Release( IVoiceInformation *iface ) +{ + struct voice_information *impl = impl_from_IVoiceInformation(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + /* all voices are (for now) statically allocated in all_voices vector. so don't free them */ + return ref; +} + +static HRESULT WINAPI voice_information_GetIids( IVoiceInformation *iface, ULONG *iid_count, IID **iids ) +{ + FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids); + return E_NOTIMPL; +} + +static HRESULT WINAPI voice_information_GetRuntimeClassName( IVoiceInformation *iface, HSTRING *class_name ) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT WINAPI voice_information_GetTrustLevel( IVoiceInformation *iface, TrustLevel *trust_level ) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT WINAPI voice_information_get_DisplayName( IVoiceInformation *iface, HSTRING *value ) +{ + struct voice_information *impl = impl_from_IVoiceInformation(iface); + + TRACE("iface %p, value %p!n", iface, value); + return WindowsDuplicateString(impl->display_name, value); +} + +static HRESULT WINAPI voice_information_get_Id( IVoiceInformation *iface, HSTRING *value ) +{ + struct voice_information *impl = impl_from_IVoiceInformation(iface); + + TRACE("iface %p, value %p\n", iface, value); + return WindowsDuplicateString(impl->id, value); +} + +static HRESULT WINAPI voice_information_get_Language( IVoiceInformation *iface, HSTRING *value ) +{ + struct voice_information *impl = impl_from_IVoiceInformation(iface); + + TRACE("iface %p, value %p\n", iface, value); + return WindowsDuplicateString(impl->language, value); +} + +static HRESULT WINAPI voice_information_get_Description( IVoiceInformation *iface, HSTRING *value ) +{ + struct voice_information *impl = impl_from_IVoiceInformation(iface); + + TRACE("iface %p, value %p\n", iface, value); + return WindowsDuplicateString(impl->description, value); +} + +static HRESULT WINAPI voice_information_get_Gender( IVoiceInformation *iface, VoiceGender *value ) +{ + struct voice_information *impl = impl_from_IVoiceInformation(iface); + + TRACE("iface %p, value %p\n", iface, value); + *value = impl->gender; + return S_OK; +} + +static const struct IVoiceInformationVtbl voice_information_vtbl = +{ + /*** IUnknown methods ***/ + voice_information_QueryInterface, + voice_information_AddRef, + voice_information_Release, + + /*** IInspectable methods ***/ + voice_information_GetIids, + voice_information_GetRuntimeClassName, + voice_information_GetTrustLevel, + + /*** IVoiceInformation methods ***/ + voice_information_get_DisplayName, + voice_information_get_Id, + voice_information_get_Language, + voice_information_get_Description, + voice_information_get_Gender, +}; + +HRESULT voice_information_allocate(const WCHAR *display_name, const WCHAR *id, const WCHAR *locale, + VoiceGender gender, IVoiceInformation **pvoice) +{ + struct voice_information *voice_info; + WCHAR *description; + HRESULT hr; + size_t len, langlen; + + voice_info = calloc(1, sizeof(*voice_info)); + if (!voice_info) return E_OUTOFMEMORY; + + len = wcslen(display_name) + 3; + langlen = GetLocaleInfoEx(locale, LOCALE_SLOCALIZEDDISPLAYNAME, NULL, 0); + description = malloc((len + langlen) * sizeof(WCHAR)); + wcscpy(description, display_name); + wcscat(description, L" - "); + GetLocaleInfoEx(locale, LOCALE_SLOCALIZEDDISPLAYNAME, description + len, langlen); + + hr = WindowsCreateString(display_name, wcslen(display_name), &voice_info->display_name); + if (SUCCEEDED(hr)) + hr = WindowsCreateString(id, wcslen(id), &voice_info->id); + if (SUCCEEDED(hr)) + hr = WindowsCreateString(locale, wcslen(locale), &voice_info->language); + if (SUCCEEDED(hr)) + hr = WindowsCreateString(description, len + langlen - 1, &voice_info->description); + if (SUCCEEDED(hr)) + { + voice_info->gender = gender; + voice_info->IVoiceInformation_iface.lpVtbl = &voice_information_vtbl; + + *pvoice = &voice_info->IVoiceInformation_iface; + } + else + { + voice_information_delete(voice_info); + } + free(description); + return hr; +} + /* * * IVectorView_VoiceInformation From 23b5f2be8f5c385fa92581437acd3ffb0f077f3c Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Tue, 4 Jul 2023 12:40:52 +0200 Subject: [PATCH 1591/2777] windows.media.speech: Finish implement the voice information view. Signed-off-by: Eric Pouech CW-Bug-Id: #20134 --- dlls/windows.media.speech/private.h | 10 +++ dlls/windows.media.speech/synthesizer.c | 95 ++++++++++++++++++++---- dlls/windows.media.speech/tests/speech.c | 2 +- 3 files changed, 92 insertions(+), 15 deletions(-) diff --git a/dlls/windows.media.speech/private.h b/dlls/windows.media.speech/private.h index 13964329697..adc3987b031 100644 --- a/dlls/windows.media.speech/private.h +++ b/dlls/windows.media.speech/private.h @@ -125,4 +125,14 @@ HRESULT vector_inspectable_create( const struct vector_iids *iids, IVector_IInsp #define DEFINE_IINSPECTABLE_OUTER( pfx, iface_type, impl_type, outer_iface ) \ DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, impl->outer_iface ) +struct synth_provider +{ + struct IVoiceInformation **voices; + unsigned num_voices; + void (*dispose)(struct synth_provider *provider); +}; + +HRESULT voice_information_allocate(const WCHAR *display_name, const WCHAR *id, const WCHAR *locale, + VoiceGender gender, IVoiceInformation **pvoice); + #endif diff --git a/dlls/windows.media.speech/synthesizer.c b/dlls/windows.media.speech/synthesizer.c index 9003d041860..4cdb194ec88 100644 --- a/dlls/windows.media.speech/synthesizer.c +++ b/dlls/windows.media.speech/synthesizer.c @@ -214,6 +214,8 @@ struct voice_information_vector { IVectorView_VoiceInformation IVectorView_VoiceInformation_iface; LONG ref; + + struct synth_provider provider; }; static inline struct voice_information_vector *impl_from_IVectorView_VoiceInformation( IVectorView_VoiceInformation *iface ) @@ -225,7 +227,7 @@ static HRESULT WINAPI vector_view_voice_information_QueryInterface( IVectorView_ { struct voice_information_vector *impl = impl_from_IVectorView_VoiceInformation(iface); - TRACE("iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out); + TRACE("iface %p, iid %s, out %p\n", iface, debugstr_guid(iid), out); if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IInspectable) || @@ -276,23 +278,39 @@ static HRESULT WINAPI vector_view_voice_information_GetTrustLevel( IVectorView_V static HRESULT WINAPI vector_view_voice_information_GetAt( IVectorView_VoiceInformation *iface, UINT32 index, IVoiceInformation **value ) { - FIXME("iface %p, index %#x, value %p stub!\n", iface, index, value); - *value = NULL; - return E_BOUNDS; + struct voice_information_vector *impl = impl_from_IVectorView_VoiceInformation(iface); + TRACE("iface %p, index %#x, value %p\n", iface, index, value); + if (index >= impl->provider.num_voices) + { + *value = NULL; + return E_BOUNDS; + } + IVoiceInformation_AddRef( *value = impl->provider.voices[index] ); + return S_OK; } static HRESULT WINAPI vector_view_voice_information_get_Size( IVectorView_VoiceInformation *iface, UINT32 *value ) { - FIXME("iface %p, value %p stub!\n", iface, value); - *value = 0; + struct voice_information_vector *impl = impl_from_IVectorView_VoiceInformation(iface); + TRACE("iface %p, value %p\n", iface, value); + *value = impl->provider.num_voices; return S_OK; } static HRESULT WINAPI vector_view_voice_information_IndexOf( IVectorView_VoiceInformation *iface, IVoiceInformation *element, UINT32 *index, BOOLEAN *found ) { - FIXME("iface %p, element %p, index %p, found %p stub!\n", iface, element, index, found); - *index = 0; + struct voice_information_vector *impl = impl_from_IVectorView_VoiceInformation(iface); + int i; + + TRACE("iface %p, element %p, index %p, found %p\n", iface, element, index, found); + for (i = 0; i < impl->provider.num_voices; i++) + if (element == impl->provider.voices[i]) + { + *index = i; + *found = TRUE; + return S_OK; + } *found = FALSE; return S_OK; } @@ -300,8 +318,18 @@ static HRESULT WINAPI vector_view_voice_information_IndexOf( IVectorView_VoiceIn static HRESULT WINAPI vector_view_voice_information_GetMany( IVectorView_VoiceInformation *iface, UINT32 start_index, UINT32 items_size, IVoiceInformation **items, UINT *value ) { - FIXME("iface %p, start_index %#x, items %p, value %p stub!\n", iface, start_index, items, value); - *value = 0; + struct voice_information_vector *impl = impl_from_IVectorView_VoiceInformation(iface); + int i; + + TRACE("iface %p, start_index %#x, items %p, value %p\n", iface, start_index, items, value); + if (start_index >= impl->provider.num_voices) + { + *value = 0; + return S_OK; + } + *value = min(impl->provider.num_voices - start_index, items_size); + for (i = 0; i < *value; i++) + IVoiceInformation_AddRef(items[i] = impl->provider.voices[start_index + i]); return S_OK; } @@ -324,7 +352,8 @@ static const struct IVectorView_VoiceInformationVtbl vector_view_voice_informati static struct voice_information_vector all_voices = { {&vector_view_voice_information_vtbl}, - 0 + 0, + {}, }; /* @@ -1107,6 +1136,26 @@ static const struct IActivationFactoryVtbl factory_vtbl = factory_ActivateInstance, }; +static HRESULT dummy_provider_init(struct synth_provider *provider) +{ + HRESULT hr; + WCHAR locale[LOCALE_NAME_MAX_LENGTH]; + + if (GetUserDefaultLocaleName(locale, ARRAY_SIZE(locale)) > ARRAY_SIZE(locale)) + return E_OUTOFMEMORY; + + provider->voices = calloc(1, sizeof(all_voices.provider.voices[0])); + if (!provider->voices) return E_OUTOFMEMORY; + hr = voice_information_allocate(L"Dummy voice", L"--noid--", locale, VoiceGender_Male, &provider->voices[0]); + if (FAILED(hr)) + { + free(provider->voices); + } + else + provider->num_voices = 1; + return hr; +} + /* * * IInstalledVoicesStatic for SpeechSynthesizer runtimeclass @@ -1115,12 +1164,30 @@ static const struct IActivationFactoryVtbl factory_vtbl = DEFINE_IINSPECTABLE(installed_voices_static, IInstalledVoicesStatic, struct synthesizer_statics, IActivationFactory_iface) +static CRITICAL_SECTION allvoices_cs; +static CRITICAL_SECTION_DEBUG allvoices_critsect_debug = +{ + 0, 0, &allvoices_cs, + { &allvoices_critsect_debug.ProcessLocksList, &allvoices_critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": allvoices_cs") } +}; +static CRITICAL_SECTION allvoices_cs = { &allvoices_critsect_debug, -1, 0, 0, 0, 0 }; + static HRESULT WINAPI installed_voices_static_get_AllVoices( IInstalledVoicesStatic *iface, IVectorView_VoiceInformation **value ) { + HRESULT hr; + TRACE("iface %p, value %p.\n", iface, value); - *value = &all_voices.IVectorView_VoiceInformation_iface; - IVectorView_VoiceInformation_AddRef(*value); - return S_OK; + + EnterCriticalSection(&allvoices_cs); + if (all_voices.provider.num_voices == 0) + hr = dummy_provider_init(&all_voices.provider); + else + hr = S_OK; + if (SUCCEEDED(hr)) + IVectorView_VoiceInformation_AddRef(*value = &all_voices.IVectorView_VoiceInformation_iface); + LeaveCriticalSection(&allvoices_cs); + return hr; } static HRESULT WINAPI installed_voices_static_get_DefaultVoice( IInstalledVoicesStatic *iface, IVoiceInformation **value ) diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 50d944c8f61..fec5c8283e4 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -950,7 +950,7 @@ static void test_SpeechSynthesizer(void) size = 0xdeadbeef; hr = IVectorView_VoiceInformation_get_Size(voices, &size); ok(hr == S_OK, "IVectorView_VoiceInformation_get_Size voices failed, hr %#lx\n", hr); - todo_wine ok(size != 0 && size != 0xdeadbeef, "IVectorView_VoiceInformation_get_Size returned %u\n", size); + ok(size != 0 && size != 0xdeadbeef, "IVectorView_VoiceInformation_get_Size returned %u\n", size); voice = (IVoiceInformation *)0xdeadbeef; hr = IVectorView_VoiceInformation_GetAt(voices, size, &voice); From 2b71173b1a3f1cedecc8bd68b520272f1294ebf4 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Tue, 4 Jul 2023 12:40:52 +0200 Subject: [PATCH 1592/2777] windows.media.speech: Add more tests about voice selection. Signed-off-by: Eric Pouech CW-Bug-Id: #20134 --- dlls/windows.media.speech/tests/speech.c | 34 +++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index fec5c8283e4..8491b2f1516 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -864,7 +864,7 @@ static void test_SpeechSynthesizer(void) IClosable *closable; struct async_inspectable_handler async_inspectable_handler; HMODULE hdll; - HSTRING str, str2; + HSTRING str, str2, default_voice_id; HRESULT hr; UINT32 size, idx; BOOLEAN found; @@ -974,13 +974,18 @@ static void test_SpeechSynthesizer(void) check_comparable_presence(voices, voice); - IVoiceInformation_get_Description(voice, &str2); + hr = IVoiceInformation_get_Description(voice, &str2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); trace("SpeechSynthesizer default voice %s.\n", debugstr_hstring(str2)); - WindowsDeleteString(str2); + + hr = IVoiceInformation_get_Id(voice, &default_voice_id); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ref = IVoiceInformation_Release(voice); ok(ref == 0, "Got unexpected ref %lu.\n", ref); } + else default_voice_id = NULL; IInstalledVoicesStatic_Release(voices_static); IAgileObject_Release(agile_object); @@ -997,6 +1002,29 @@ static void test_SpeechSynthesizer(void) hr = IInspectable_QueryInterface(inspectable, &IID_ISpeechSynthesizer, (void **)&synthesizer); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = ISpeechSynthesizer_get_Voice(synthesizer, &voice); + todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + if (default_voice_id) + { + if (hr == S_OK) + { + INT32 cmp; + IVoiceInformation_get_Id(voice, &str); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = WindowsCompareStringOrdinal(str, default_voice_id, &cmp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = WindowsDeleteString(str); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + IVoiceInformation_Release(voice); + } + + hr = WindowsDeleteString(default_voice_id); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + } + /* Test SynthesizeTextToStreamAsync */ hr = WindowsCreateString(simple_synth_text, wcslen(simple_synth_text), &str); ok(hr == S_OK, "WindowsCreateString failed, hr %#lx\n", hr); From 38ef617add8715d8713b11ee05a4136a78c44401 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Tue, 4 Jul 2023 12:40:52 +0200 Subject: [PATCH 1593/2777] windows.media.speech: Implement default voice. Signed-off-by: Eric Pouech CW-Bug-Id: #20134 --- dlls/windows.media.speech/synthesizer.c | 50 +++++++++++++++++-- dlls/windows.media.speech/tests/speech.c | 61 +++++++++++------------- 2 files changed, 73 insertions(+), 38 deletions(-) diff --git a/dlls/windows.media.speech/synthesizer.c b/dlls/windows.media.speech/synthesizer.c index 4cdb194ec88..9fff36d6bd2 100644 --- a/dlls/windows.media.speech/synthesizer.c +++ b/dlls/windows.media.speech/synthesizer.c @@ -33,6 +33,7 @@ struct voice_information HSTRING language; HSTRING description; VoiceGender gender; + BOOL is_static; }; static inline struct voice_information *impl_from_IVoiceInformation( IVoiceInformation *iface ) @@ -81,7 +82,9 @@ static ULONG WINAPI voice_information_Release( IVoiceInformation *iface ) struct voice_information *impl = impl_from_IVoiceInformation(iface); ULONG ref = InterlockedDecrement(&impl->ref); TRACE("iface %p, ref %lu.\n", iface, ref); - /* all voices are (for now) statically allocated in all_voices vector. so don't free them */ + /* only deallocate non static instances */ + if (!ref && !impl->is_static) + voice_information_delete(impl); return ref; } @@ -192,8 +195,8 @@ HRESULT voice_information_allocate(const WCHAR *display_name, const WCHAR *id, c if (SUCCEEDED(hr)) { voice_info->gender = gender; + voice_info->is_static = TRUE; voice_info->IVoiceInformation_iface.lpVtbl = &voice_information_vtbl; - *pvoice = &voice_info->IVoiceInformation_iface; } else @@ -204,6 +207,35 @@ HRESULT voice_information_allocate(const WCHAR *display_name, const WCHAR *id, c return hr; } +HRESULT voice_information_clone(IVoiceInformation *voice, IVoiceInformation **out) +{ + struct voice_information *voice_info; + HRESULT hr; + + voice_info = calloc(1, sizeof(*voice_info)); + if (!voice_info) return E_OUTOFMEMORY; + + hr = IVoiceInformation_get_DisplayName(voice, &voice_info->display_name); + if (SUCCEEDED(hr)) + hr = IVoiceInformation_get_Id(voice, &voice_info->id); + if (SUCCEEDED(hr)) + hr = IVoiceInformation_get_Language(voice, &voice_info->language); + if (SUCCEEDED(hr)) + hr = IVoiceInformation_get_Description(voice, &voice_info->description); + if (SUCCEEDED(hr)) + hr = IVoiceInformation_get_Gender(voice, &voice_info->gender); + if (SUCCEEDED(hr)) + { + voice_info->IVoiceInformation_iface.lpVtbl = &voice_information_vtbl; + voice_info->ref = 1; + *out = &voice_info->IVoiceInformation_iface; + } + else + voice_information_delete(voice_info); + + return hr; +} + /* * * IVectorView_VoiceInformation @@ -1192,8 +1224,18 @@ static HRESULT WINAPI installed_voices_static_get_AllVoices( IInstalledVoicesSta static HRESULT WINAPI installed_voices_static_get_DefaultVoice( IInstalledVoicesStatic *iface, IVoiceInformation **value ) { - FIXME("iface %p, value %p stub!\n", iface, value); - return E_NOTIMPL; + struct IVoiceInformation *static_voice; + HRESULT hr; + + TRACE("iface %p, value %p\n", iface, value); + + EnterCriticalSection(&allvoices_cs); + hr = IVectorView_VoiceInformation_GetAt(&all_voices.IVectorView_VoiceInformation_iface, 0, &static_voice); + if (SUCCEEDED(hr)) + hr = voice_information_clone(static_voice, value); + LeaveCriticalSection(&allvoices_cs); + + return hr; } static const struct IInstalledVoicesStaticVtbl installed_voices_static_vtbl = diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 8491b2f1516..1382758e8df 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -962,30 +962,26 @@ static void test_SpeechSynthesizer(void) ok(size == 0, "IVectorView_VoiceInformation_GetMany returned count %u\n", size); hr = IInstalledVoicesStatic_get_DefaultVoice(voices_static, &voice); - todo_wine ok(hr == S_OK, "IInstalledVoicesStatic_get_DefaultVoice failed, hr %#lx\n", hr); + ok(hr == S_OK, "IInstalledVoicesStatic_get_DefaultVoice failed, hr %#lx\n", hr); - if (hr == S_OK) - { - /* check that VoiceInformation in static vector voice are not shared when exposed to user */ - idx = size; - hr = IVectorView_VoiceInformation_IndexOf(voices, voice, &idx, &found); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ok(!found, "Shouldn't find default element\n"); + /* check that VoiceInformation in static vector voice are not shared when exposed to user */ + idx = size; + hr = IVectorView_VoiceInformation_IndexOf(voices, voice, &idx, &found); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(!found, "Shouldn't find default element\n"); - check_comparable_presence(voices, voice); + check_comparable_presence(voices, voice); - hr = IVoiceInformation_get_Description(voice, &str2); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - trace("SpeechSynthesizer default voice %s.\n", debugstr_hstring(str2)); - WindowsDeleteString(str2); + hr = IVoiceInformation_get_Description(voice, &str2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + trace("SpeechSynthesizer default voice %s.\n", debugstr_hstring(str2)); + WindowsDeleteString(str2); - hr = IVoiceInformation_get_Id(voice, &default_voice_id); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IVoiceInformation_get_Id(voice, &default_voice_id); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - ref = IVoiceInformation_Release(voice); - ok(ref == 0, "Got unexpected ref %lu.\n", ref); - } - else default_voice_id = NULL; + ref = IVoiceInformation_Release(voice); + ok(ref == 0, "Got unexpected ref %lu.\n", ref); IInstalledVoicesStatic_Release(voices_static); IAgileObject_Release(agile_object); @@ -1005,26 +1001,23 @@ static void test_SpeechSynthesizer(void) hr = ISpeechSynthesizer_get_Voice(synthesizer, &voice); todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - if (default_voice_id) + if (hr == S_OK) { - if (hr == S_OK) - { - INT32 cmp; - IVoiceInformation_get_Id(voice, &str); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - hr = WindowsCompareStringOrdinal(str, default_voice_id, &cmp); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - - hr = WindowsDeleteString(str); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - - IVoiceInformation_Release(voice); - } + INT32 cmp; + IVoiceInformation_get_Id(voice, &str); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = WindowsCompareStringOrdinal(str, default_voice_id, &cmp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - hr = WindowsDeleteString(default_voice_id); + hr = WindowsDeleteString(str); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + IVoiceInformation_Release(voice); } + hr = WindowsDeleteString(default_voice_id); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + /* Test SynthesizeTextToStreamAsync */ hr = WindowsCreateString(simple_synth_text, wcslen(simple_synth_text), &str); ok(hr == S_OK, "WindowsCreateString failed, hr %#lx\n", hr); From a553ab6f8b4b9e1291052834087a658b02e8f276 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Tue, 4 Jul 2023 12:40:52 +0200 Subject: [PATCH 1594/2777] windows.media.speech: Implement get/put voice on synthesizer. Signed-off-by: Eric Pouech CW-Bug-Id: #20134 --- dlls/windows.media.speech/synthesizer.c | 57 ++++++++++++++++++++++-- dlls/windows.media.speech/tests/speech.c | 22 +++++---- 2 files changed, 63 insertions(+), 16 deletions(-) diff --git a/dlls/windows.media.speech/synthesizer.c b/dlls/windows.media.speech/synthesizer.c index 9fff36d6bd2..5e5d20b8364 100644 --- a/dlls/windows.media.speech/synthesizer.c +++ b/dlls/windows.media.speech/synthesizer.c @@ -839,6 +839,7 @@ struct synthesizer LONG ref; struct synthesizer_options *options; + IVoiceInformation *current_voice; }; /* @@ -902,6 +903,8 @@ static ULONG WINAPI synthesizer_Release( ISpeechSynthesizer *iface ) { if (impl->options) ISpeechSynthesizerOptions_Release(&impl->options->ISpeechSynthesizerOptions_iface); + if (impl->current_voice) + IVoiceInformation_Release(impl->current_voice); free(impl); } @@ -954,14 +957,49 @@ static HRESULT WINAPI synthesizer_SynthesizeSsmlToStreamAsync( ISpeechSynthesize static HRESULT WINAPI synthesizer_put_Voice( ISpeechSynthesizer *iface, IVoiceInformation *value ) { - FIXME("iface %p, value %p stub.\n", iface, value); - return E_NOTIMPL; + struct synthesizer *impl = impl_from_ISpeechSynthesizer(iface); + IVoiceInformation *voice; + HSTRING id, id2; + HRESULT hr; + INT32 cmp, idx; + + TRACE("iface %p, value %p semi-stub.\n", iface, value); + + hr = IVoiceInformation_get_Id(value, &id); + if (FAILED(hr)) return hr; + + for (idx = 0; ; idx++) + { + if (SUCCEEDED(hr = IVectorView_VoiceInformation_GetAt(&all_voices.IVectorView_VoiceInformation_iface, idx, &voice))) + { + if (SUCCEEDED(hr = IVoiceInformation_get_Id(voice, &id2))) + { + hr = WindowsCompareStringOrdinal(id, id2, &cmp); + WindowsDeleteString(id2); + } + IVoiceInformation_Release(voice); + } + if (FAILED(hr) || cmp == 0) break; + } + WindowsDeleteString(id); + + if (SUCCEEDED(hr)) + { + if (impl->current_voice) + IVoiceInformation_Release(impl->current_voice); + IVoiceInformation_AddRef(impl->current_voice = value); + } + return hr; } static HRESULT WINAPI synthesizer_get_Voice( ISpeechSynthesizer *iface, IVoiceInformation **value ) { - FIXME("iface %p, value %p stub.\n", iface, value); - return E_NOTIMPL; + struct synthesizer *impl = impl_from_ISpeechSynthesizer(iface); + + TRACE("iface %p, value %p.\n", iface, value); + if (!impl->current_voice) return E_NOTIMPL; + IVoiceInformation_AddRef(*value = impl->current_voice); + return S_OK; } static const struct ISpeechSynthesizerVtbl synthesizer_vtbl = @@ -1136,7 +1174,9 @@ static HRESULT WINAPI factory_GetTrustLevel( IActivationFactory *iface, TrustLev static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInspectable **instance ) { + struct IVoiceInformation *static_voice; struct synthesizer *impl; + HRESULT hr; TRACE("iface %p, instance %p.\n", iface, instance); @@ -1149,6 +1189,15 @@ static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInsp impl->ISpeechSynthesizer_iface.lpVtbl = &synthesizer_vtbl; impl->ISpeechSynthesizer2_iface.lpVtbl = &synthesizer2_vtbl; impl->IClosable_iface.lpVtbl = &closable_vtbl; + /* assuming default is the first one... */ + hr = IVectorView_VoiceInformation_GetAt(&all_voices.IVectorView_VoiceInformation_iface, 0, &static_voice); + if (SUCCEEDED(hr)) + hr = voice_information_clone(static_voice, &impl->current_voice); + if (FAILED(hr)) + { + free(impl); + return hr; + } impl->ref = 1; *instance = (IInspectable *)&impl->ISpeechSynthesizer_iface; diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 1382758e8df..f234dc9d643 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -869,6 +869,7 @@ static void test_SpeechSynthesizer(void) UINT32 size, idx; BOOLEAN found; ULONG ref; + INT32 cmp; hr = RoInitialize(RO_INIT_MULTITHREADED); ok(hr == S_OK, "RoInitialize failed, hr %#lx\n", hr); @@ -999,21 +1000,18 @@ static void test_SpeechSynthesizer(void) ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); hr = ISpeechSynthesizer_get_Voice(synthesizer, &voice); - todo_wine ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { - INT32 cmp; - IVoiceInformation_get_Id(voice, &str); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - hr = WindowsCompareStringOrdinal(str, default_voice_id, &cmp); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IVoiceInformation_get_Id(voice, &str); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - hr = WindowsDeleteString(str); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = WindowsCompareStringOrdinal(str, default_voice_id, &cmp); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - IVoiceInformation_Release(voice); - } + hr = WindowsDeleteString(str); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + IVoiceInformation_Release(voice); hr = WindowsDeleteString(default_voice_id); ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); From 9c6b7b4bc3f77ac3e8b56328118c9495063135dc Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 8 Sep 2023 16:25:24 -0600 Subject: [PATCH 1595/2777] server: Support FileStandardInformation for pipes. CW-Bug-Id: #22718 --- dlls/ntdll/tests/pipe.c | 21 ++++++++++++++++++ server/named_pipe.c | 47 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/dlls/ntdll/tests/pipe.c b/dlls/ntdll/tests/pipe.c index 30f4b6f1405..81ef5c85152 100644 --- a/dlls/ntdll/tests/pipe.c +++ b/dlls/ntdll/tests/pipe.c @@ -2081,6 +2081,7 @@ static void test_pipe_with_data_state(HANDLE pipe, BOOL is_server, DWORD state) IO_STATUS_BLOCK io; char buf[256] = "test"; NTSTATUS status, expected_status; + FILE_STANDARD_INFORMATION std_info; memset(&io, 0xcc, sizeof(io)); status = pNtQueryInformationFile(pipe, &io, &local_info, sizeof(local_info), FilePipeLocalInformation); @@ -2104,6 +2105,26 @@ static void test_pipe_with_data_state(HANDLE pipe, BOOL is_server, DWORD state) is_server ? "server" : "client", state); } + status = pNtQueryInformationFile(pipe, &io, &std_info, sizeof(std_info), FileStandardInformation); + if (!is_server && state == FILE_PIPE_DISCONNECTED_STATE) + ok(status == STATUS_PIPE_DISCONNECTED, + "NtQueryInformationFile(FileStandardInformation) failed in %s state %lu: %lx\n", + is_server ? "server" : "client", state, status); + else + ok(status == STATUS_SUCCESS, + "NtQueryInformationFile(FileStandardInformation) failed in %s state %lu: %lx\n", + is_server ? "server" : "client", state, status); + if (!status) + { + ok(std_info.AllocationSize.QuadPart == local_info.InboundQuota + local_info.OutboundQuota, + "got %I64u, expected %lu.\n", + std_info.AllocationSize.QuadPart, local_info.InboundQuota + local_info.OutboundQuota); + ok(std_info.EndOfFile.QuadPart == local_info.ReadDataAvailable, "got %I64u.\n", std_info.EndOfFile.QuadPart); + ok(std_info.NumberOfLinks == 1, "got %lu.\n", std_info.NumberOfLinks); + todo_wine ok(std_info.DeletePending, "got %d.\n", std_info.DeletePending); + ok(!std_info.Directory, "got %d.\n", std_info.Directory); + } + status = pNtQueryInformationFile(pipe, &io, &pipe_info, sizeof(pipe_info), FilePipeInformation); if (!is_server && state == FILE_PIPE_DISCONNECTED_STATE) ok(status == STATUS_PIPE_DISCONNECTED, diff --git a/server/named_pipe.c b/server/named_pipe.c index 5c486093c76..22eacf301fb 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -608,6 +608,17 @@ static void pipe_end_flush( struct fd *fd, struct async *async ) } } +static data_size_t pipe_end_get_avail( struct pipe_end *pipe_end ) +{ + struct pipe_message *message; + data_size_t avail = 0; + + LIST_FOR_EACH_ENTRY( message, &pipe_end->message_queue, struct pipe_message, entry ) + avail += message->iosb->in_size - message->read_pos; + + return avail; +} + static void pipe_end_get_file_info( struct fd *fd, obj_handle_t handle, unsigned int info_class ) { struct pipe_end *pipe_end = get_fd_user( fd ); @@ -680,8 +691,6 @@ static void pipe_end_get_file_info( struct fd *fd, obj_handle_t handle, unsigned case FilePipeLocalInformation: { FILE_PIPE_LOCAL_INFORMATION *pipe_info; - struct pipe_message *message; - data_size_t avail = 0; if (!(get_handle_access( current->process, handle) & FILE_READ_ATTRIBUTES)) { @@ -719,9 +728,7 @@ static void pipe_end_get_file_info( struct fd *fd, obj_handle_t handle, unsigned pipe_info->CurrentInstances = pipe->instances; pipe_info->InboundQuota = pipe->insize; - LIST_FOR_EACH_ENTRY( message, &pipe_end->message_queue, struct pipe_message, entry ) - avail += message->iosb->in_size - message->read_pos; - pipe_info->ReadDataAvailable = avail; + pipe_info->ReadDataAvailable = pipe_end_get_avail( pipe_end ); pipe_info->OutboundQuota = pipe->outsize; pipe_info->WriteQuotaAvailable = 0; /* FIXME */ @@ -730,6 +737,36 @@ static void pipe_end_get_file_info( struct fd *fd, obj_handle_t handle, unsigned ? FILE_PIPE_SERVER_END : FILE_PIPE_CLIENT_END; break; } + case FileStandardInformation: + { + FILE_STANDARD_INFORMATION *std_info; + + if (!(get_handle_access( current->process, handle) & FILE_READ_ATTRIBUTES)) + { + set_error( STATUS_ACCESS_DENIED ); + return; + } + + if (get_reply_max_size() < sizeof(*std_info)) + { + set_error( STATUS_INFO_LENGTH_MISMATCH ); + return; + } + + if (!pipe) + { + set_error( STATUS_PIPE_DISCONNECTED ); + return; + } + + if (!(std_info = set_reply_data_size( sizeof(*std_info) ))) return; + std_info->AllocationSize.QuadPart = pipe->outsize + pipe->insize; + std_info->EndOfFile.QuadPart = pipe_end_get_avail( pipe_end ); + std_info->NumberOfLinks = 1; /* FIXME */ + std_info->DeletePending = 0; /* FIXME */ + std_info->Directory = 0; + break; + } default: default_fd_get_file_info( fd, handle, info_class ); } From c195dba437872675862ae354b3781984852b8420 Mon Sep 17 00:00:00 2001 From: Esme Povirk Date: Wed, 17 May 2023 11:19:46 -0500 Subject: [PATCH 1596/2777] mscoree: Update Wine Mono to 8.0.0. (cherry picked from commit 0a3fe99d2bb00ad2f8867551915a82c7983e6f5a) --- dlls/appwiz.cpl/addons.c | 4 ++-- dlls/mscoree/mscoree_private.h | 2 +- tools/gitlab/test.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/appwiz.cpl/addons.c b/dlls/appwiz.cpl/addons.c index 762c0b31f73..a53e818bbbb 100644 --- a/dlls/appwiz.cpl/addons.c +++ b/dlls/appwiz.cpl/addons.c @@ -58,10 +58,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl); #define GECKO_SHA "???" #endif -#define MONO_VERSION "7.4.1" +#define MONO_VERSION "8.0.0" #if defined(__i386__) || defined(__x86_64__) #define MONO_ARCH "x86" -#define MONO_SHA "4721de007ecd0019cc18e144a882c290da3314d7e1bc77f57c404675e644b9fe" +#define MONO_SHA "75b3f45dca1dc89857fe9e932da78710f64cc6d49ef1ab0c723a177085b4711b" #else #define MONO_ARCH "" #define MONO_SHA "???" diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h index 64a5efe8d10..a06333b6874 100644 --- a/dlls/mscoree/mscoree_private.h +++ b/dlls/mscoree/mscoree_private.h @@ -45,7 +45,7 @@ extern HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version) extern HRESULT assembly_get_vtable_fixups(ASSEMBLY *assembly, VTableFixup **fixups, DWORD *count) DECLSPEC_HIDDEN; extern HRESULT assembly_get_native_entrypoint(ASSEMBLY *assembly, NativeEntryPointFunc *func) DECLSPEC_HIDDEN; -#define WINE_MONO_VERSION "7.4.1" +#define WINE_MONO_VERSION "8.0.0" /* Mono embedding */ typedef struct _MonoDomain MonoDomain; diff --git a/tools/gitlab/test.yml b/tools/gitlab/test.yml index da34390bc1f..04ee21eb9e7 100644 --- a/tools/gitlab/test.yml +++ b/tools/gitlab/test.yml @@ -7,7 +7,7 @@ variables: GIT_STRATEGY: none GECKO_VER: 2.47.3 - MONO_VER: 7.4.0 + MONO_VER: 8.0.0 cache: - key: wine-gecko-$GECKO_VER paths: From 21af75e5ecbd3e0fc9dd35f056c771213b6b388b Mon Sep 17 00:00:00 2001 From: Esme Povirk Date: Mon, 8 May 2023 14:09:39 -0500 Subject: [PATCH 1597/2777] mscoree: Use updated preload hook function. (cherry picked from commit ddc9ef10c9de1ff8885db312f013a069dee21933) --- dlls/mscoree/metahost.c | 30 ++++++++++++++++++++++++------ dlls/mscoree/mscoree_private.h | 7 ++++++- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/dlls/mscoree/metahost.c b/dlls/mscoree/metahost.c index 23dd34ed6e3..22fed41cf15 100644 --- a/dlls/mscoree/metahost.c +++ b/dlls/mscoree/metahost.c @@ -131,11 +131,13 @@ void (CDECL *mono_thread_manage)(void); void (CDECL *mono_trace_set_print_handler)(MonoPrintCallback callback); void (CDECL *mono_trace_set_printerr_handler)(MonoPrintCallback callback); static void (CDECL *wine_mono_install_assembly_preload_hook)(WineMonoAssemblyPreLoadFunc func, void *user_data); +static void (CDECL *wine_mono_install_assembly_preload_hook_v2)(WineMonoAssemblyPreLoadFunc func, void *user_data); static BOOL find_mono_dll(LPCWSTR path, LPWSTR dll_path); static MonoAssembly* CDECL mono_assembly_preload_hook_fn(MonoAssemblyName *aname, char **assemblies_path, void *user_data); static MonoAssembly* CDECL wine_mono_assembly_preload_hook_fn(MonoAssemblyName *aname, char **assemblies_path, int *search_path, void *user_data); +static MonoAssembly* CDECL wine_mono_assembly_preload_hook_v2_fn(MonoAssemblyName *aname, char **assemblies_path, int *flags, void *user_data); static void CDECL mono_shutdown_callback_fn(MonoProfiler *prof); @@ -252,6 +254,7 @@ static HRESULT load_mono(LPCWSTR mono_path) LOAD_OPT_MONO_FUNCTION(mono_trace_set_print_handler, set_print_handler_dummy); LOAD_OPT_MONO_FUNCTION(mono_trace_set_printerr_handler, set_print_handler_dummy); LOAD_OPT_MONO_FUNCTION(wine_mono_install_assembly_preload_hook, NULL); + LOAD_OPT_MONO_FUNCTION(wine_mono_install_assembly_preload_hook_v2, NULL); #undef LOAD_OPT_MONO_FUNCTION @@ -282,7 +285,9 @@ static HRESULT load_mono(LPCWSTR mono_path) mono_config_parse(NULL); - if (wine_mono_install_assembly_preload_hook) + if (wine_mono_install_assembly_preload_hook_v2) + wine_mono_install_assembly_preload_hook_v2(wine_mono_assembly_preload_hook_v2_fn, NULL); + else if (wine_mono_install_assembly_preload_hook) wine_mono_install_assembly_preload_hook(wine_mono_assembly_preload_hook_fn, NULL); else mono_install_assembly_preload_hook(mono_assembly_preload_hook_fn, NULL); @@ -1745,11 +1750,20 @@ static BOOL compile_assembly(const char *source, const char *target, char *targe static MonoAssembly* CDECL mono_assembly_preload_hook_fn(MonoAssemblyName *aname, char **assemblies_path, void *user_data) { - int dummy; - return wine_mono_assembly_preload_hook_fn(aname, assemblies_path, &dummy, user_data); + int flags = 0; + return wine_mono_assembly_preload_hook_v2_fn(aname, assemblies_path, &flags, user_data); } static MonoAssembly* CDECL wine_mono_assembly_preload_hook_fn(MonoAssemblyName *aname, char **assemblies_path, int *halt_search, void *user_data) +{ + int flags = 0; + MonoAssembly* result = wine_mono_assembly_preload_hook_v2_fn(aname, assemblies_path, &flags, user_data); + if (flags & WINE_PRELOAD_SKIP_PRIVATE_PATH) + *halt_search = 1; + return result; +} + +static MonoAssembly* CDECL wine_mono_assembly_preload_hook_v2_fn(MonoAssemblyName *aname, char **assemblies_path, int *flags, void *user_data) { HRESULT hr; MonoAssembly *result=NULL; @@ -1902,8 +1916,6 @@ static MonoAssembly* CDECL wine_mono_assembly_preload_hook_fn(MonoAssemblyName * } } - /* FIXME: We should search the given paths before the GAC. */ - if ((search_flags & ASSEMBLY_SEARCH_GAC) != 0) { stringnameW_size = MultiByteToWideChar(CP_UTF8, 0, stringname, -1, NULL, 0); @@ -1934,6 +1946,12 @@ static MonoAssembly* CDECL wine_mono_assembly_preload_hook_fn(MonoAssemblyName * ERR("Failed to load %s, status=%u\n", debugstr_w(path), stat); HeapFree(GetProcessHeap(), 0, pathA); + + if (result) + { + *flags |= WINE_PRELOAD_SET_GAC; + goto done; + } } } } @@ -1943,7 +1961,7 @@ static MonoAssembly* CDECL wine_mono_assembly_preload_hook_fn(MonoAssemblyName * if ((search_flags & ASSEMBLY_SEARCH_PRIVATEPATH) == 0) { TRACE("skipping AppDomain search path due to override setting\n"); - *halt_search = 1; + *flags |= WINE_PRELOAD_SKIP_PRIVATE_PATH; } done: diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h index a06333b6874..50ed656a656 100644 --- a/dlls/mscoree/mscoree_private.h +++ b/dlls/mscoree/mscoree_private.h @@ -143,7 +143,12 @@ typedef enum { typedef MonoAssembly* (CDECL *MonoAssemblyPreLoadFunc)(MonoAssemblyName *aname, char **assemblies_path, void *user_data); -typedef MonoAssembly* (CDECL *WineMonoAssemblyPreLoadFunc)(MonoAssemblyName *aname, char **assemblies_path, int *halt_search, void *user_data); +#define WINE_PRELOAD_CONTINUE 0 +#define WINE_PRELOAD_SKIP_PRIVATE_PATH 1 +#define WINE_PRELOAD_SKIP_GAC 2 +#define WINE_PRELOAD_SET_GAC 4 + +typedef MonoAssembly* (CDECL *WineMonoAssemblyPreLoadFunc)(MonoAssemblyName *aname, char **assemblies_path, int *flags, void *user_data); typedef void (CDECL *MonoProfileFunc)(MonoProfiler *prof); From 365d48fce9f351d8db4bb271ba0b1365408db6b7 Mon Sep 17 00:00:00 2001 From: Esme Povirk Date: Tue, 9 May 2023 13:20:21 -0500 Subject: [PATCH 1598/2777] mscoree: Search the Mono GAC before the appdomain paths. (cherry picked from commit 629d2d09a0323f8456d78be0cc08d8206ed722df) --- dlls/mscoree/metahost.c | 44 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/dlls/mscoree/metahost.c b/dlls/mscoree/metahost.c index 22fed41cf15..6327a338596 100644 --- a/dlls/mscoree/metahost.c +++ b/dlls/mscoree/metahost.c @@ -130,6 +130,7 @@ MonoThread* (CDECL *mono_thread_attach)(MonoDomain *domain); void (CDECL *mono_thread_manage)(void); void (CDECL *mono_trace_set_print_handler)(MonoPrintCallback callback); void (CDECL *mono_trace_set_printerr_handler)(MonoPrintCallback callback); +static MonoAssembly* (CDECL *wine_mono_assembly_load_from_gac)(MonoAssemblyName *aname, MonoImageOpenStatus *status, int refonly); static void (CDECL *wine_mono_install_assembly_preload_hook)(WineMonoAssemblyPreLoadFunc func, void *user_data); static void (CDECL *wine_mono_install_assembly_preload_hook_v2)(WineMonoAssemblyPreLoadFunc func, void *user_data); @@ -253,6 +254,7 @@ static HRESULT load_mono(LPCWSTR mono_path) LOAD_OPT_MONO_FUNCTION(mono_set_crash_chaining, set_crash_chaining_dummy); LOAD_OPT_MONO_FUNCTION(mono_trace_set_print_handler, set_print_handler_dummy); LOAD_OPT_MONO_FUNCTION(mono_trace_set_printerr_handler, set_print_handler_dummy); + LOAD_OPT_MONO_FUNCTION(wine_mono_assembly_load_from_gac, NULL); LOAD_OPT_MONO_FUNCTION(wine_mono_install_assembly_preload_hook, NULL); LOAD_OPT_MONO_FUNCTION(wine_mono_install_assembly_preload_hook_v2, NULL); @@ -1375,16 +1377,19 @@ HRESULT CLRMetaHostPolicy_CreateInstance(REFIID riid, void **ppobj) * Assembly search override settings: * * WINE_MONO_OVERRIDES=*,Gac=n - * Never search the GAC for libraries. + * Never search the Windows GAC for libraries. + * + * WINE_MONO_OVERRIDES=*,MonoGac=n + * Never search the Mono GAC for libraries. * * WINE_MONO_OVERRIDES=*,PrivatePath=n * Never search the AppDomain search path for libraries. * * WINE_MONO_OVERRIDES=Microsoft.Xna.Framework,Gac=n - * Never search the GAC for Microsoft.Xna.Framework + * Never search the Windows GAC for Microsoft.Xna.Framework * * WINE_MONO_OVERRIDES=Microsoft.Xna.Framework.*,Gac=n;Microsoft.Xna.Framework.GamerServices,Gac=y - * Never search the GAC for Microsoft.Xna.Framework, or any library starting + * Never search the Windows GAC for Microsoft.Xna.Framework, or any library starting * with Microsoft.Xna.Framework, except for Microsoft.Xna.Framework.GamerServices */ @@ -1392,7 +1397,8 @@ HRESULT CLRMetaHostPolicy_CreateInstance(REFIID riid, void **ppobj) #define ASSEMBLY_SEARCH_GAC 1 #define ASSEMBLY_SEARCH_UNDEFINED 2 #define ASSEMBLY_SEARCH_PRIVATEPATH 4 -#define ASSEMBLY_SEARCH_DEFAULT (ASSEMBLY_SEARCH_GAC|ASSEMBLY_SEARCH_PRIVATEPATH) +#define ASSEMBLY_SEARCH_MONOGAC 8 +#define ASSEMBLY_SEARCH_DEFAULT (ASSEMBLY_SEARCH_GAC|ASSEMBLY_SEARCH_PRIVATEPATH|ASSEMBLY_SEARCH_MONOGAC) typedef struct override_entry { char *name; @@ -1441,6 +1447,14 @@ static void parse_override_entry(override_entry *entry, const char *string, int entry->flags &= ~ASSEMBLY_SEARCH_GAC; } break; + case 7: + if (!_strnicmp(string, "monogac", 7)) { + if (IS_OPTION_TRUE(*value)) + entry->flags |= ASSEMBLY_SEARCH_MONOGAC; + else if (IS_OPTION_FALSE(*value)) + entry->flags &= ~ASSEMBLY_SEARCH_MONOGAC; + } + break; case 11: if (!_strnicmp(string, "privatepath", 11)) { if (IS_OPTION_TRUE(*value)) @@ -1568,7 +1582,7 @@ static DWORD get_basename_search_flags(const char *basename, MonoAssemblyName *a if (strcmp(basename, "Microsoft.Xna.Framework.*") == 0 && mono_assembly_name_get_version(aname, NULL, NULL, NULL) == 4) /* Use FNA as a replacement for XNA4. */ - return 0; + return ASSEMBLY_SEARCH_MONOGAC; return ASSEMBLY_SEARCH_UNDEFINED; } @@ -1958,6 +1972,26 @@ static MonoAssembly* CDECL wine_mono_assembly_preload_hook_v2_fn(MonoAssemblyNam else TRACE("skipping Windows GAC search due to override setting\n"); + if (wine_mono_assembly_load_from_gac) + { + if (search_flags & ASSEMBLY_SEARCH_MONOGAC) + { + result = wine_mono_assembly_load_from_gac (aname, &stat, FALSE); + + if (result) + { + TRACE("found in Mono GAC\n"); + *flags |= WINE_PRELOAD_SET_GAC; + goto done; + } + } + else + { + *flags |= WINE_PRELOAD_SKIP_GAC; + TRACE("skipping Mono GAC search due to override setting\n"); + } + } + if ((search_flags & ASSEMBLY_SEARCH_PRIVATEPATH) == 0) { TRACE("skipping AppDomain search path due to override setting\n"); From a58d60b690183d789b8d662179ce2e6878e6881a Mon Sep 17 00:00:00 2001 From: Esme Povirk Date: Fri, 11 Aug 2023 13:12:58 -0500 Subject: [PATCH 1599/2777] mscoree: Update Wine Mono to 8.0.1. --- dlls/appwiz.cpl/addons.c | 4 ++-- dlls/mscoree/mscoree_private.h | 2 +- tools/gitlab/test.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/appwiz.cpl/addons.c b/dlls/appwiz.cpl/addons.c index a53e818bbbb..3f0b8b2c03e 100644 --- a/dlls/appwiz.cpl/addons.c +++ b/dlls/appwiz.cpl/addons.c @@ -58,10 +58,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl); #define GECKO_SHA "???" #endif -#define MONO_VERSION "8.0.0" +#define MONO_VERSION "8.0.1" #if defined(__i386__) || defined(__x86_64__) #define MONO_ARCH "x86" -#define MONO_SHA "75b3f45dca1dc89857fe9e932da78710f64cc6d49ef1ab0c723a177085b4711b" +#define MONO_SHA "27240085f5b4f8b175ff0479f3d6cc4309b00adbb386c00ba1fddd30f0367976" #else #define MONO_ARCH "" #define MONO_SHA "???" diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h index 50ed656a656..ca8ba343be3 100644 --- a/dlls/mscoree/mscoree_private.h +++ b/dlls/mscoree/mscoree_private.h @@ -45,7 +45,7 @@ extern HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version) extern HRESULT assembly_get_vtable_fixups(ASSEMBLY *assembly, VTableFixup **fixups, DWORD *count) DECLSPEC_HIDDEN; extern HRESULT assembly_get_native_entrypoint(ASSEMBLY *assembly, NativeEntryPointFunc *func) DECLSPEC_HIDDEN; -#define WINE_MONO_VERSION "8.0.0" +#define WINE_MONO_VERSION "8.0.1" /* Mono embedding */ typedef struct _MonoDomain MonoDomain; diff --git a/tools/gitlab/test.yml b/tools/gitlab/test.yml index 04ee21eb9e7..09387a26439 100644 --- a/tools/gitlab/test.yml +++ b/tools/gitlab/test.yml @@ -7,7 +7,7 @@ variables: GIT_STRATEGY: none GECKO_VER: 2.47.3 - MONO_VER: 8.0.0 + MONO_VER: 8.0.1 cache: - key: wine-gecko-$GECKO_VER paths: From 99e23f58cdca7e81a6d7533cc346d4d38471142b Mon Sep 17 00:00:00 2001 From: Georg Lehmann Date: Fri, 21 Jul 2023 13:19:31 +0200 Subject: [PATCH 1600/2777] winevulkan: Update to VK spec version 1.3.258. This does not enable VK_NV_device_generated_commands_compute because the extension will likely see an API breaking naming fix. (cherry picked from commit eb5be00eb005a30df1b7f828269e3c8f002e1e82) --- dlls/winevulkan/make_vulkan | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index ae00d208318..459a4f14d87 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -65,7 +65,7 @@ from enum import Enum LOGGER = logging.Logger("vulkan") LOGGER.addHandler(logging.StreamHandler()) -VK_XML_VERSION = "1.3.254" +VK_XML_VERSION = "1.3.258" WINE_VK_VERSION = (1, 3) # Filenames to create. @@ -119,6 +119,9 @@ UNSUPPORTED_EXTENSIONS = [ # Deprecated extensions "VK_NV_external_memory_capabilities", "VK_NV_external_memory_win32", + + # Likely broken: https://github.com/KhronosGroup/Vulkan-Docs/issues/2171 + "VK_NV_device_generated_commands_compute", ] # Either internal extensions which aren't present on the win32 platform which From 941ccd1eb6f6bcf1d031f7a0bbf5b0699c011f89 Mon Sep 17 00:00:00 2001 From: Georg Lehmann Date: Sat, 22 Jul 2023 16:46:06 +0200 Subject: [PATCH 1601/2777] winevulkan: Update to VK spec version 1.3.259. (cherry picked from commit b5e19a33c9360784961918a364175ab2ad93870d) --- dlls/winevulkan/make_vulkan | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 459a4f14d87..4b6a65b6f32 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -65,7 +65,7 @@ from enum import Enum LOGGER = logging.Logger("vulkan") LOGGER.addHandler(logging.StreamHandler()) -VK_XML_VERSION = "1.3.258" +VK_XML_VERSION = "1.3.259" WINE_VK_VERSION = (1, 3) # Filenames to create. @@ -119,9 +119,6 @@ UNSUPPORTED_EXTENSIONS = [ # Deprecated extensions "VK_NV_external_memory_capabilities", "VK_NV_external_memory_win32", - - # Likely broken: https://github.com/KhronosGroup/Vulkan-Docs/issues/2171 - "VK_NV_device_generated_commands_compute", ] # Either internal extensions which aren't present on the win32 platform which From 235eec9437e89a13511a33d3f69f6a0016353e31 Mon Sep 17 00:00:00 2001 From: Georg Lehmann Date: Fri, 28 Jul 2023 14:22:36 +0200 Subject: [PATCH 1602/2777] winevulkan: Update to VK spec version 1.3.260. (cherry picked from commit 08499d17e1be37bafe8a3bdea9971998217efa86) --- dlls/winevulkan/make_vulkan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 4b6a65b6f32..73681dcaff1 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -65,7 +65,7 @@ from enum import Enum LOGGER = logging.Logger("vulkan") LOGGER.addHandler(logging.StreamHandler()) -VK_XML_VERSION = "1.3.259" +VK_XML_VERSION = "1.3.260" WINE_VK_VERSION = (1, 3) # Filenames to create. From 9bca2abf6ca46d4b8b825ae7bd46743c7c83dd20 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Thu, 17 Aug 2023 17:57:29 +0300 Subject: [PATCH 1603/2777] winevulkan: Update vk.xml to 1.3.260. --- dlls/winevulkan/vk.xml | 914 +++++++++++++++++++++++++++++++++++------ 1 file changed, 786 insertions(+), 128 deletions(-) diff --git a/dlls/winevulkan/vk.xml b/dlls/winevulkan/vk.xml index 0c4bb61609f..898bd9f967e 100644 --- a/dlls/winevulkan/vk.xml +++ b/dlls/winevulkan/vk.xml @@ -175,7 +175,7 @@ branch of the member gitlab server. #define VKSC_API_VERSION_1_0 VK_MAKE_API_VERSION(VKSC_API_VARIANT, 1, 0, 0)// Patch version should always be set to 0 // Version of this file -#define VK_HEADER_VERSION 254 +#define VK_HEADER_VERSION 260 // Complete version of this file #define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(0, 1, 3, VK_HEADER_VERSION) // Version of this file @@ -390,6 +390,8 @@ typedef void* MTLSharedEvent_id; typedef VkFlags VkBuildMicromapFlagsEXT; typedef VkFlags VkMicromapCreateFlagsEXT; typedef VkFlags VkDirectDriverLoadingFlagsLUNARG; + typedef VkFlags64 VkPipelineCreateFlags2KHR; + typedef VkFlags64 VkBufferUsageFlags2KHR; WSI extensions typedef VkFlags VkCompositeAlphaFlagsKHR; @@ -465,6 +467,7 @@ typedef void* MTLSharedEvent_id; typedef VkFlags VkSubmitFlags; typedef VkFlags VkImageFormatConstraintsFlagsFUCHSIA; + typedef VkFlags VkHostImageCopyFlagsEXT; typedef VkFlags VkImageConstraintsInfoFlagsFUCHSIA; typedef VkFlags VkGraphicsPipelineLibraryFlagsEXT; typedef VkFlags VkImageCompressionFlagsEXT; @@ -711,8 +714,6 @@ typedef void* MTLSharedEvent_id; - - @@ -751,6 +752,7 @@ typedef void* MTLSharedEvent_id; + @@ -776,9 +778,15 @@ typedef void* MTLSharedEvent_id; + + + + + + WSI extensions @@ -1179,6 +1187,11 @@ typedef void* MTLSharedEvent_id; uint32_t dstArrayElementArray element within the destination binding to copy to uint32_t descriptorCountNumber of descriptors to write (determines the size of the array pointed by pDescriptors) + + VkStructureType sType + const void* pNext + VkBufferUsageFlags2KHR usage + VkStructureType sType const void* pNext @@ -1439,6 +1452,18 @@ typedef void* MTLSharedEvent_id; VkPipeline basePipelineHandleIf VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is nonzero, it specifies the handle of the base pipeline this is a derivative of int32_t basePipelineIndexIf VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is not -1, it specifies an index into pCreateInfos of the base pipeline this is a derivative of + + VkStructureType sType + const void* pNext + VkDeviceAddress deviceAddress + VkDeviceSize size + VkDeviceAddress pipelineDeviceAddressCaptureReplay + + + VkStructureType sType + const void* pNext + VkPipelineCreateFlags2KHR flags + uint32_t bindingVertex buffer binding id uint32_t strideDistance between vertices in bytes (0 = no advancement) @@ -2325,6 +2350,13 @@ typedef void* MTLSharedEvent_id; void* pNext VkBool32 deviceGeneratedCommands + + VkStructureType sType + void* pNext + VkBool32 deviceGeneratedCompute + VkBool32 deviceGeneratedComputePipelines + VkBool32 deviceGeneratedComputeCaptureReplay + VkStructureType sType const void* pNext @@ -2445,10 +2477,19 @@ typedef void* MTLSharedEvent_id; VkStructureType sType const void* pNext VkPipelineBindPoint pipelineBindPoint - VkPipeline pipeline + VkPipeline pipeline VkIndirectCommandsLayoutNV indirectCommandsLayout uint32_t maxSequencesCount + + VkStructureType sType + const void* pNext + VkPipelineBindPoint pipelineBindPoint + VkPipeline pipeline + + + VkDeviceAddress pipelineAddress + VkStructureType sType void* pNext @@ -3638,6 +3679,30 @@ typedef void* MTLSharedEvent_id; VkDeviceSize maxBufferSize + + VkStructureType sType + void* pNext + VkBool32 maintenance5 + + + VkStructureType sType + void* pNext + VkBool32 earlyFragmentMultisampleCoverageAfterSampleCounting + VkBool32 earlyFragmentSampleMaskTestBeforeSampleCounting + VkBool32 depthStencilSwizzleOneSupport + VkBool32 polygonModePointSize + VkBool32 nonStrictSinglePixelWideLinesUseParallelogram + VkBool32 nonStrictWideLinesUseParallelogram + + + VkStructureType sType + const void* pNext + uint32_t viewMask + uint32_t colorAttachmentCount + const VkFormat* pColorAttachmentFormats + VkFormat depthAttachmentFormat + VkFormat stencilAttachmentFormat + VkStructureType sType void* pNext @@ -3816,7 +3881,7 @@ typedef void* MTLSharedEvent_id; VkStructureType sType const void* pNext VkExternalMemoryHandleTypeFlagBits handleType - void* pHostPointer + void* pHostPointer VkStructureType sType @@ -4695,7 +4760,7 @@ typedef void* MTLSharedEvent_id; VkStructureType sType const void* pNext uint64_t drmFormatModifier - uint32_t drmFormatModifierPlaneCount + uint32_t drmFormatModifierPlaneCount const VkSubresourceLayout* pPlaneLayouts @@ -4945,7 +5010,7 @@ typedef void* MTLSharedEvent_id; uint64_t duration - + VkStructureType sType const void* pNext VkPipelineCreationFeedback* pPipelineCreationFeedbackOutput pipeline creation feedback. @@ -5529,7 +5594,7 @@ typedef void* MTLSharedEvent_id; VkBool32 uniformTexelBufferOffsetSingleTexelAlignment VkDeviceSize maxBufferSize - + VkStructureType sType const void* pNext VkPipelineCompilerControlFlagsAMD compilerControlFlags @@ -5599,6 +5664,10 @@ typedef void* MTLSharedEvent_id; VkDeviceAddress deviceAddress const void* hostAddress + + VkDeviceAddress deviceAddress + const void* hostAddress + VkStructureType sType const void* pNext @@ -6290,6 +6359,89 @@ typedef void* MTLSharedEvent_id; VkBool32 synchronization2 + + VkStructureType sType + void* pNext + VkBool32 hostImageCopy + + + VkStructureType sType + void* pNext + uint32_t copySrcLayoutCount + VkImageLayout* pCopySrcLayouts + uint32_t copyDstLayoutCount + VkImageLayout* pCopyDstLayouts + uint8_t optimalTilingLayoutUUID[VK_UUID_SIZE] + VkBool32 identicalMemoryTypeRequirements + + + VkStructureType sType + const void* pNext + const void* pHostPointer + uint32_t memoryRowLengthSpecified in texels + uint32_t memoryImageHeight + VkImageSubresourceLayers imageSubresource + VkOffset3D imageOffset + VkExtent3D imageExtent + + + VkStructureType sType + const void* pNext + void* pHostPointer + uint32_t memoryRowLengthSpecified in texels + uint32_t memoryImageHeight + VkImageSubresourceLayers imageSubresource + VkOffset3D imageOffset + VkExtent3D imageExtent + + + VkStructureType sType + const void* pNext + VkHostImageCopyFlagsEXT flags + VkImage dstImage + VkImageLayout dstImageLayout + uint32_t regionCount + const VkMemoryToImageCopyEXT* pRegions + + + VkStructureType sType + const void* pNext + VkHostImageCopyFlagsEXT flags + VkImage srcImage + VkImageLayout srcImageLayout + uint32_t regionCount + const VkImageToMemoryCopyEXT* pRegions + + + VkStructureType sType + const void* pNext + VkHostImageCopyFlagsEXT flags + VkImage srcImage + VkImageLayout srcImageLayout + VkImage dstImage + VkImageLayout dstImageLayout + uint32_t regionCount + const VkImageCopy2* pRegions + + + VkStructureType sType + const void* pNext + VkImage image + VkImageLayout oldLayout + VkImageLayout newLayout + VkImageSubresourceRange subresourceRange + + + VkStructureType sType + void* pNext + VkDeviceSize sizeSpecified in bytes + + + VkStructureType sType + void* pNext + VkBool32 optimalDeviceAccessSpecifies if device access is optimal + VkBool32 identicalMemoryLayoutSpecifies if memory layout is identical + VkStructureType sType void* pNext @@ -6366,8 +6518,8 @@ typedef void* MTLSharedEvent_id; VkStructureType sType const void* pNext - VkDeviceSize commandPoolReservedSize - uint32_t commandPoolMaxCommandBuffers + VkDeviceSize commandPoolReservedSize + uint32_t commandPoolMaxCommandBuffers VkStructureType sType @@ -6698,7 +6850,7 @@ typedef void* MTLSharedEvent_id; VkStructureType sType const void* pNext - VkVideoCodingControlFlagsKHR flags + VkVideoCodingControlFlagsKHR flags VkStructureType sType @@ -7594,7 +7746,7 @@ typedef void* MTLSharedEvent_id; VkStructureType sType - void* pNext + const void* pNext VkGraphicsPipelineLibraryFlagsEXT flags @@ -7648,7 +7800,7 @@ typedef void* MTLSharedEvent_id; void* pNext VkBool32 imageCompressionControl - + VkStructureType sType void* pNext VkImageCompressionFlagsEXT imageCompressionFlags @@ -7659,16 +7811,18 @@ typedef void* MTLSharedEvent_id; void* pNext VkBool32 imageCompressionControlSwapchain - - VkStructureType sType + + VkStructureType sType void* pNext VkImageSubresource imageSubresource - - VkStructureType sType + + + VkStructureType sType void* pNext VkSubresourceLayout subresourceLayout + VkStructureType sType const void* pNext @@ -8250,6 +8404,12 @@ typedef void* MTLSharedEvent_id; void* pNext VkBool32 rayTracingPositionFetch + + VkStructureType sType + const void* pNext + const VkImageCreateInfo* pCreateInfo + const VkImageSubresource2KHR* pSubresource + VkStructureType sType void* pNext @@ -8362,6 +8522,77 @@ typedef void* MTLSharedEvent_id; void* pNext VkBool32 screenBufferImport + + VkStructureType sType + void* pNext + VkBool32 cooperativeMatrix + VkBool32 cooperativeMatrixRobustBufferAccess + + + VkStructureType sType + void* pNext + uint32_t MSize + uint32_t NSize + uint32_t KSize + VkComponentTypeKHR AType + VkComponentTypeKHR BType + VkComponentTypeKHR CType + VkComponentTypeKHR ResultType + VkBool32 saturatingAccumulation + VkScopeKHR scope + + + VkStructureType sType + void* pNext + VkShaderStageFlags cooperativeMatrixSupportedStages + + + VkStructureType sType + void* pNext + uint32_t maxExecutionGraphDepth + uint32_t maxExecutionGraphShaderOutputNodes + uint32_t maxExecutionGraphShaderPayloadSize + uint32_t maxExecutionGraphShaderPayloadCount + uint32_t executionGraphDispatchAddressAlignment + + + VkStructureType sType + void* pNext + VkBool32 shaderEnqueue + + + VkStructureType sType + const void* pNext + VkPipelineCreateFlags flags + uint32_t stageCount + const VkPipelineShaderStageCreateInfo* pStages + const VkPipelineLibraryCreateInfoKHR* pLibraryInfo + VkPipelineLayout layout + VkPipeline basePipelineHandle + int32_t basePipelineIndex + + + VkStructureType sType + const void* pNext + const char* pName + uint32_t index + + + VkStructureType sType + void* pNext + VkDeviceSize size + + + uint32_t nodeIndex + uint32_t payloadCount + VkDeviceOrHostAddressConstAMDX payloads + uint64_t payloadStride + + + uint32_t count + VkDeviceOrHostAddressConstAMDX infos + uint64_t stride + @@ -8400,6 +8631,7 @@ typedef void* MTLSharedEvent_id; + @@ -9007,6 +9239,17 @@ typedef void* MTLSharedEvent_id; + + + + + + + + + + + @@ -9043,11 +9286,16 @@ typedef void* MTLSharedEvent_id; - + + + + + + @@ -9662,25 +9910,6 @@ typedef void* MTLSharedEvent_id; - - - - - - - - - - - - - - - - - - - @@ -10136,6 +10365,9 @@ typedef void* MTLSharedEvent_id; + + + @@ -10416,6 +10648,25 @@ typedef void* MTLSharedEvent_id; + + + + + + + + + + + + + + + + + + + @@ -11036,6 +11287,12 @@ typedef void* MTLSharedEvent_id; VkRenderPass renderPass VkExtent2D* pGranularity + + void vkGetRenderingAreaGranularityKHR + VkDevice device + const VkRenderingAreaInfoKHR* pRenderingAreaInfo + VkExtent2D* pGranularity + VkResult vkCreateCommandPool VkDevice device @@ -11265,6 +11522,12 @@ typedef void* MTLSharedEvent_id; VkBuffer buffer VkDeviceSize offset + + void vkCmdUpdatePipelineIndirectBufferNV + VkCommandBuffer commandBuffer + VkPipelineBindPoint pipelineBindPoint + VkPipeline pipeline + void vkCmdCopyBuffer VkCommandBuffer commandBuffer @@ -12592,7 +12855,7 @@ typedef void* MTLSharedEvent_id; VkResult vkGetMemoryHostPointerPropertiesEXT VkDevice device VkExternalMemoryHandleTypeFlagBits handleType - const void* pHostPointer + const void* pHostPointer VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties @@ -13331,6 +13594,17 @@ typedef void* MTLSharedEvent_id; VkDevice device VkDeferredOperationKHR operation + + void vkGetPipelineIndirectMemoryRequirementsNV + VkDevice device + const VkComputePipelineCreateInfo* pCreateInfo + VkMemoryRequirements2* pMemoryRequirements + + + VkDeviceAddress vkGetPipelineIndirectDeviceAddressNV + VkDevice device + const VkPipelineIndirectDeviceAddressInfoNV* pInfo + void vkCmdSetCullMode VkCommandBuffer commandBuffer @@ -13363,6 +13637,14 @@ typedef void* MTLSharedEvent_id; const VkRect2D* pScissors + + void vkCmdBindIndexBuffer2KHR + VkCommandBuffer commandBuffer + VkBuffer buffer + VkDeviceSize offset + VkDeviceSize size + VkIndexType indexType + void vkCmdBindVertexBuffers2 VkCommandBuffer commandBuffer @@ -13787,6 +14069,27 @@ typedef void* MTLSharedEvent_id; uint32_t* pCheckpointDataCount VkCheckpointData2NV* pCheckpointData + + VkResult vkCopyMemoryToImageEXT + VkDevice device + const VkCopyMemoryToImageInfoEXT* pCopyMemoryToImageInfo + + + VkResult vkCopyImageToMemoryEXT + VkDevice device + const VkCopyImageToMemoryInfoEXT* pCopyImageToMemoryInfo + + + VkResult vkCopyImageToImageEXT + VkDevice device + const VkCopyImageToImageInfoEXT* pCopyImageToImageInfo + + + VkResult vkTransitionImageLayoutEXT + VkDevice device + uint32_t transitionCount + const VkHostImageLayoutTransitionInfoEXT* pTransitions + void vkGetCommandPoolMemoryConsumption VkDevice device @@ -14194,12 +14497,13 @@ typedef void* MTLSharedEvent_id; VkShaderModuleIdentifierEXT* pIdentifier - void vkGetImageSubresourceLayout2EXT + void vkGetImageSubresourceLayout2KHR VkDevice device VkImage image - const VkImageSubresource2EXT* pSubresource - VkSubresourceLayout2EXT* pLayout + const VkImageSubresource2KHR* pSubresource + VkSubresourceLayout2KHR* pLayout + VkResult vkGetPipelinePropertiesEXT VkDevice device @@ -14274,6 +14578,12 @@ typedef void* MTLSharedEvent_id; VkDevice device const VkReleaseSwapchainImagesInfoEXT* pReleaseInfo + + void vkGetDeviceImageSubresourceLayoutKHR + VkDevice device + const VkDeviceImageSubresourceInfoKHR* pInfo + VkSubresourceLayout2KHR* pLayout + VkResult vkMapMemory2KHR VkDevice device @@ -14319,6 +14629,57 @@ typedef void* MTLSharedEvent_id; const struct _screen_buffer* buffer VkScreenBufferPropertiesQNX* pProperties + + VkResult vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR + VkPhysicalDevice physicalDevice + uint32_t* pPropertyCount + VkCooperativeMatrixPropertiesKHR* pProperties + + + VkResult vkGetExecutionGraphPipelineScratchSizeAMDX + VkDevice device + VkPipeline executionGraph + VkExecutionGraphPipelineScratchSizeAMDX* pSizeInfo + + + VkResult vkGetExecutionGraphPipelineNodeIndexAMDX + VkDevice device + VkPipeline executionGraph + const VkPipelineShaderStageNodeCreateInfoAMDX* pNodeInfo + uint32_t* pNodeIndex + + + VkResult vkCreateExecutionGraphPipelinesAMDX + VkDevice device + VkPipelineCache pipelineCache + uint32_t createInfoCount + const VkExecutionGraphPipelineCreateInfoAMDX* pCreateInfos + const VkAllocationCallbacks* pAllocator + VkPipeline* pPipelines + + + void vkCmdInitializeGraphScratchMemoryAMDX + VkCommandBuffer commandBuffer + VkDeviceAddress scratch + + + void vkCmdDispatchGraphAMDX + VkCommandBuffer commandBuffer + VkDeviceAddress scratch + const VkDispatchGraphCountInfoAMDX* pCountInfo + + + void vkCmdDispatchGraphIndirectAMDX + VkCommandBuffer commandBuffer + VkDeviceAddress scratch + const VkDispatchGraphCountInfoAMDX* pCountInfo + + + void vkCmdDispatchGraphIndirectCountAMDX + VkCommandBuffer commandBuffer + VkDeviceAddress scratch + VkDeviceAddress countInfo + @@ -16260,8 +16621,6 @@ typedef void* MTLSharedEvent_id; - - @@ -16273,6 +16632,10 @@ typedef void* MTLSharedEvent_id; + + + + @@ -17680,11 +18043,36 @@ typedef void* MTLSharedEvent_id; - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -17901,7 +18289,6 @@ typedef void* MTLSharedEvent_id; - @@ -17963,6 +18350,9 @@ typedef void* MTLSharedEvent_id; + + + @@ -18066,7 +18456,6 @@ typedef void* MTLSharedEvent_id; - @@ -18137,6 +18526,7 @@ typedef void* MTLSharedEvent_id; + @@ -18306,7 +18696,6 @@ typedef void* MTLSharedEvent_id; - @@ -18351,7 +18740,6 @@ typedef void* MTLSharedEvent_id; - @@ -18369,6 +18757,12 @@ typedef void* MTLSharedEvent_id; + + + + + + @@ -18435,6 +18829,9 @@ typedef void* MTLSharedEvent_id; + + + @@ -19158,7 +19555,7 @@ typedef void* MTLSharedEvent_id; - + @@ -19242,7 +19639,22 @@ typedef void* MTLSharedEvent_id; + + + + + + + + + + + + + + + @@ -19508,12 +19920,42 @@ typedef void* MTLSharedEvent_id; - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -19682,7 +20124,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20508,9 +20950,9 @@ typedef void* MTLSharedEvent_id; - + - + @@ -20777,7 +21219,6 @@ typedef void* MTLSharedEvent_id; - @@ -20807,6 +21248,9 @@ typedef void* MTLSharedEvent_id; + + + @@ -20823,13 +21267,14 @@ typedef void* MTLSharedEvent_id; - + - + + @@ -21198,9 +21643,9 @@ typedef void* MTLSharedEvent_id; - + - + @@ -21213,6 +21658,9 @@ typedef void* MTLSharedEvent_id; + + + @@ -21469,10 +21917,23 @@ typedef void* MTLSharedEvent_id; - + - - + + + + + + + + + + + + + + + @@ -21604,6 +22065,7 @@ typedef void* MTLSharedEvent_id; + @@ -21650,6 +22112,7 @@ typedef void* MTLSharedEvent_id; + @@ -21693,16 +22156,6 @@ typedef void* MTLSharedEvent_id; - - - - - - - - - - @@ -21728,15 +22181,39 @@ typedef void* MTLSharedEvent_id; + + + + + + + + + + + + + + + + + + + + + + + + @@ -21909,7 +22386,7 @@ typedef void* MTLSharedEvent_id; - + @@ -21918,10 +22395,132 @@ typedef void* MTLSharedEvent_id; - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -22060,16 +22659,6 @@ typedef void* MTLSharedEvent_id; - - - - - - - - - - @@ -22087,6 +22676,30 @@ typedef void* MTLSharedEvent_id; + + + + + + + + + + + + + + + + + + + + + + + + @@ -22104,6 +22717,8 @@ typedef void* MTLSharedEvent_id; + + @@ -22293,10 +22908,19 @@ typedef void* MTLSharedEvent_id; - + - - + + + + + + + + + + + @@ -22307,6 +22931,7 @@ typedef void* MTLSharedEvent_id; + @@ -22412,7 +23037,7 @@ typedef void* MTLSharedEvent_id; - + @@ -22542,6 +23167,18 @@ typedef void* MTLSharedEvent_id; + + + + + + + + + + + + @@ -22578,8 +23215,8 @@ typedef void* MTLSharedEvent_id; - + @@ -22588,6 +23225,15 @@ typedef void* MTLSharedEvent_id; + + + + + + + + + @@ -23136,15 +23782,15 @@ typedef void* MTLSharedEvent_id; - + - + - + @@ -23182,7 +23828,7 @@ typedef void* MTLSharedEvent_id; - + @@ -23264,15 +23910,15 @@ typedef void* MTLSharedEvent_id; - + - - + + @@ -24071,21 +24717,21 @@ typedef void* MTLSharedEvent_id; - + - + - + @@ -24102,7 +24748,7 @@ typedef void* MTLSharedEvent_id; - + @@ -24115,14 +24761,14 @@ typedef void* MTLSharedEvent_id; - + - + @@ -24140,6 +24786,12 @@ typedef void* MTLSharedEvent_id; + + + + + + @@ -24274,12 +24926,12 @@ typedef void* MTLSharedEvent_id; - + - + @@ -24626,6 +25278,12 @@ typedef void* MTLSharedEvent_id; + + + + + + @@ -24676,7 +25334,7 @@ typedef void* MTLSharedEvent_id; - + @@ -24735,7 +25393,7 @@ typedef void* MTLSharedEvent_id; - + @@ -24765,17 +25423,17 @@ typedef void* MTLSharedEvent_id; - + - + - + - + @@ -24819,13 +25477,13 @@ typedef void* MTLSharedEvent_id; - + - + - + @@ -24861,7 +25519,7 @@ typedef void* MTLSharedEvent_id; - + @@ -24873,13 +25531,13 @@ typedef void* MTLSharedEvent_id; - + - + @@ -24934,7 +25592,7 @@ typedef void* MTLSharedEvent_id; VK_PIPELINE_STAGE_2_HOST_BIT - VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI + VK_PIPELINE_STAGE_2_SUBPASS_SHADER_BIT_HUAWEI VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_NV From fc27831d1d6df59c89facdee598b526eb1251399 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 24 Jul 2023 13:19:04 +0300 Subject: [PATCH 1604/2777] wine.inf.in: Use native vulkan-1 for RDR2. So we don't depend only on the app id and play manifest to have the game playable. --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 5440db87f19..1e2eac889aa 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2882,3 +2882,4 @@ HKCU,Software\Wine\AppDefaults\Pentiment.exe\DllOverrides,"SpeechSynthesisWrappe HKCU,Software\Wine\AppDefaults\Maine-Win64-Shipping.exe\DllOverrides,"SpeechSynthWrapper",0x2,"disabled" HKCU,Software\Wine\AppDefaults\rayne1.exe\DllOverrides,"d3d8",,"native" HKCU,Software\Wine\AppDefaults\rayne2.exe\DllOverrides,"d3d8",,"native" +HKCU,Software\Wine\AppDefaults\RDR2.exe\DllOverrides,"vulkan-1",,"native" From 54dbf8727bbddf27944a14771f5711f4c42ffe0b Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 19 Jun 2023 17:45:01 +0300 Subject: [PATCH 1605/2777] winemenubuilder: Force-disable creating associations. CW-Bug-Id: #20433 --- programs/winemenubuilder/winemenubuilder.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c index 1579ca8dafa..e62831c71f2 100644 --- a/programs/winemenubuilder/winemenubuilder.c +++ b/programs/winemenubuilder/winemenubuilder.c @@ -2792,20 +2792,7 @@ static BOOL init_xdg(void) static BOOL associations_enabled(void) { - BOOL ret = TRUE; - HKEY hkey; - BYTE buf[32]; - DWORD len; - - if ((hkey = open_associations_reg_key())) - { - len = sizeof(buf); - if (!RegQueryValueExA(hkey, "Enable", NULL, NULL, buf, &len)) - ret = IS_OPTION_TRUE(buf[0]); - RegCloseKey( hkey ); - } - - return ret; + return FALSE; } /*********************************************************************** From d0109f6ce75e13a4972371d7ef5819d2614c6d61 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 19 Jun 2023 17:46:18 +0300 Subject: [PATCH 1606/2777] winemenubuilder: Save .desktop files in c:\proton_shortcuts\. CW-Bug-Id: #20433 --- programs/winemenubuilder/winemenubuilder.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c index e62831c71f2..0ed4f7042c6 100644 --- a/programs/winemenubuilder/winemenubuilder.c +++ b/programs/winemenubuilder/winemenubuilder.c @@ -1266,7 +1266,7 @@ static BOOL write_desktop_entry(const WCHAR *link, const WCHAR *location, const char *workdir_unix; int needs_chmod = FALSE; const WCHAR *name; - const WCHAR *prefix = _wgetenv( L"WINECONFIGDIR" ); + WCHAR *shortcuts_dir; WINE_TRACE("(%s,%s,%s,%s,%s,%s,%s,%s,%s)\n", wine_dbgstr_w(link), wine_dbgstr_w(location), wine_dbgstr_w(linkname), wine_dbgstr_w(path), wine_dbgstr_w(args), @@ -1274,11 +1274,12 @@ static BOOL write_desktop_entry(const WCHAR *link, const WCHAR *location, const wine_dbgstr_w(wmclass)); name = PathFindFileNameW( linkname ); - if (!location) - { - location = heap_wprintf(L"%s\\%s.desktop", xdg_desktop_dir, name); - needs_chmod = TRUE; - } + + shortcuts_dir = heap_wprintf(L"%s", L"c:\\proton_shortcuts"); + create_directories(shortcuts_dir); + location = heap_wprintf(L"%s\\%s.desktop", shortcuts_dir, name); + heap_free(shortcuts_dir); + needs_chmod = TRUE; file = _wfopen( location, L"wb" ); if (file == NULL) From 28b36986157836fddc7eddb7e94da7062f832e52 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 19 Jun 2023 17:47:02 +0300 Subject: [PATCH 1607/2777] winemenubuilder: User raw exe path in the created .desktop files. We don't need the magic wine/prefix invocations. CW-Bug-Id: #20433 --- programs/winemenubuilder/winemenubuilder.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c index 0ed4f7042c6..a99c88dcfa6 100644 --- a/programs/winemenubuilder/winemenubuilder.c +++ b/programs/winemenubuilder/winemenubuilder.c @@ -1288,13 +1288,8 @@ static BOOL write_desktop_entry(const WCHAR *link, const WCHAR *location, const fprintf(file, "[Desktop Entry]\n"); fprintf(file, "Name=%s\n", wchars_to_utf8_chars(name)); fprintf(file, "Exec=" ); - if (prefix) - { - char *path = wine_get_unix_file_name( prefix ); - fprintf(file, "env WINEPREFIX=\"%s\" ", path); - heap_free( path ); - } - fprintf(file, "wine %s", escape(path)); + + fprintf(file, "%s", escape(path)); if (args) fprintf(file, " %s", escape(args) ); fputc( '\n', file ); fprintf(file, "Type=Application\n"); From 0a02c50a20ddc8f4a4c540c43a8b8a686023d422 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 19 Jun 2023 17:48:37 +0300 Subject: [PATCH 1608/2777] winemenubuilder: Don't create menu entries. CW-Bug-Id: #20433 --- programs/winemenubuilder/winemenubuilder.c | 100 --------------------- 1 file changed, 100 deletions(-) diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c index a99c88dcfa6..6f653444b33 100644 --- a/programs/winemenubuilder/winemenubuilder.c +++ b/programs/winemenubuilder/winemenubuilder.c @@ -1321,100 +1321,6 @@ static BOOL write_desktop_entry(const WCHAR *link, const WCHAR *location, const return TRUE; } -static BOOL write_directory_entry(const WCHAR *directory, const WCHAR *location) -{ - FILE *file; - - WINE_TRACE("(%s,%s)\n", wine_dbgstr_w(directory), wine_dbgstr_w(location)); - - file = _wfopen( location, L"wb" ); - if (file == NULL) - return FALSE; - - fprintf(file, "[Desktop Entry]\n"); - fprintf(file, "Type=Directory\n"); - if (wcscmp(directory, L"wine") == 0) - { - fprintf(file, "Name=Wine\n"); - fprintf(file, "Icon=wine\n"); - } - else - { - fprintf(file, "Name=%s\n", wchars_to_utf8_chars(directory)); - fprintf(file, "Icon=folder\n"); - } - - fclose(file); - return TRUE; -} - -static BOOL write_menu_file(const WCHAR *windows_link, const WCHAR *link) -{ - WCHAR tempfilename[MAX_PATH]; - FILE *tempfile = NULL; - WCHAR *filename, *lastEntry, *menuPath; - int i; - int count = 0; - BOOL ret = FALSE; - - WINE_TRACE("(%s)\n", wine_dbgstr_w(link)); - - GetTempFileNameW( xdg_menu_dir, L"mnu", 0, tempfilename ); - if (!(tempfile = _wfopen( tempfilename, L"wb" ))) return FALSE; - - fprintf(tempfile, "\n"); - fprintf(tempfile, "\n"); - fprintf(tempfile, " Applications\n"); - - filename = heap_wprintf(L"wine\\%s.desktop", link); - lastEntry = filename; - for (i = 0; filename[i]; i++) - { - if (filename[i] == '\\') - { - WCHAR *dir_file_name; - const char *prefix = count ? "" : "wine-"; - - filename[i] = 0; - fprintf(tempfile, " \n"); - fprintf(tempfile, " %s%s\n", - prefix, wchars_to_xml_text(filename)); - fprintf(tempfile, " %s%s.directory\n", - prefix, wchars_to_xml_text(filename)); - dir_file_name = heap_wprintf(L"%s\\desktop-directories\\%s%s.directory", - xdg_data_dir, count ? L"" : L"wine-", filename); - if (GetFileAttributesW( dir_file_name ) == INVALID_FILE_ATTRIBUTES) - write_directory_entry(lastEntry, dir_file_name); - heap_free(dir_file_name); - filename[i] = '-'; - lastEntry = &filename[i+1]; - ++count; - } - } - filename[i] = 0; - - fprintf(tempfile, " \n"); - fprintf(tempfile, " %s\n", wchars_to_xml_text(filename)); - fprintf(tempfile, " \n"); - for (i = 0; i < count; i++) - fprintf(tempfile, " \n"); - fprintf(tempfile, "\n"); - - menuPath = heap_wprintf(L"%s\\%s", xdg_menu_dir, filename); - lstrcpyW(menuPath + lstrlenW(menuPath) - lstrlenW(L".desktop"), L".menu"); - - fclose(tempfile); - ret = MoveFileExW( tempfilename, menuPath, MOVEFILE_REPLACE_EXISTING ); - if (ret) - register_menus_entry(menuPath, windows_link); - else - DeleteFileW( tempfilename ); - heap_free(filename); - heap_free(menuPath); - return ret; -} - static BOOL write_menu_entry(const WCHAR *windows_link, const WCHAR *link, const WCHAR *path, const WCHAR *args, const WCHAR *descr, const WCHAR *workdir, const WCHAR *icon, const WCHAR *wmclass) { @@ -1444,12 +1350,6 @@ static BOOL write_menu_entry(const WCHAR *windows_link, const WCHAR *link, const goto end; } - if (!write_menu_file(windows_link, link)) - { - WINE_WARN("couldn't make menu file %s\n", wine_dbgstr_w(filename)); - ret = FALSE; - } - end: heap_free(desktopPath); heap_free(filename); From 7c040c3c0f837278e2ef3bb55fc9770f61444b36 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 19 Jun 2023 17:49:13 +0300 Subject: [PATCH 1609/2777] winemenubuilder: Save icons in c:\proton_shortcuts\icons\ CW-Bug-Id: #20433 --- programs/winemenubuilder/winemenubuilder.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c index 6f653444b33..935d81e1161 100644 --- a/programs/winemenubuilder/winemenubuilder.c +++ b/programs/winemenubuilder/winemenubuilder.c @@ -1084,7 +1084,8 @@ static HRESULT platform_write_icon(IStream *icoStream, ICONDIRENTRY *iconDirEntr LARGE_INTEGER zero; *nativeIdentifier = compute_native_identifier(exeIndex, icoPathW, destFilename); - iconsDir = heap_wprintf(L"%s\\icons\\hicolor", xdg_data_dir); + iconsDir = heap_wprintf(L"%s", L"c:\\proton_shortcuts\\icons"); + create_directories(iconsDir); for (i = 0; i < numEntries; i++) { From b31ec01f8e06bd46bd4f95e0e8f734fc1625feb4 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 19 Jun 2023 16:27:49 +0300 Subject: [PATCH 1610/2777] Revert "HACK: proton: configure: Don't build winemenubuilder." This reverts commit 5e25ae85bf50673ec63a8437a7e77fe13dba97aa. CW-Bug-Id: #20433 --- configure.ac | 1 + loader/wine.inf.in | 1 + 2 files changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac index 5f6138f68e0..100df2f395a 100644 --- a/configure.ac +++ b/configure.ac @@ -3449,6 +3449,7 @@ WINE_CONFIG_MAKEFILE(programs/wineconsole) WINE_CONFIG_MAKEFILE(programs/winedbg) WINE_CONFIG_MAKEFILE(programs/winedevice) WINE_CONFIG_MAKEFILE(programs/winefile) +WINE_CONFIG_MAKEFILE(programs/winemenubuilder) WINE_CONFIG_MAKEFILE(programs/winemine) WINE_CONFIG_MAKEFILE(programs/winemsibuilder) WINE_CONFIG_MAKEFILE(programs/winepath) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 1e2eac889aa..d22ab179ee7 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2554,6 +2554,7 @@ StartType=3 ErrorControl=1 [Services] +HKLM,%CurrentVersion%\RunServices,"winemenubuilder",2,"%11%\winemenubuilder.exe -a -r" HKLM,"System\CurrentControlSet\Services\Eventlog\Application",,16 HKLM,"System\CurrentControlSet\Services\Eventlog\System","Sources",0x10000,"" HKLM,"System\CurrentControlSet\Services\Tcpip\Parameters","DataBasePath",,"%12%\etc" From 82bdc6d2a58301e2f0745513f9410991463850f2 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 19 Jun 2023 16:28:01 +0300 Subject: [PATCH 1611/2777] wine.inf: Don't use winemenubuilder to create filetype associations. CW-Bug-Id: #20433 --- loader/wine.inf.in | 1 - 1 file changed, 1 deletion(-) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index d22ab179ee7..1e2eac889aa 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2554,7 +2554,6 @@ StartType=3 ErrorControl=1 [Services] -HKLM,%CurrentVersion%\RunServices,"winemenubuilder",2,"%11%\winemenubuilder.exe -a -r" HKLM,"System\CurrentControlSet\Services\Eventlog\Application",,16 HKLM,"System\CurrentControlSet\Services\Eventlog\System","Sources",0x10000,"" HKLM,"System\CurrentControlSet\Services\Tcpip\Parameters","DataBasePath",,"%12%\etc" From a996b069f8cd8ae7a2d058d3320777e6cc61535f Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Wed, 21 Jun 2023 11:06:10 +0200 Subject: [PATCH 1612/2777] kernelbase: Free unix console in AllocConsole. CW-Bug-Id: #22317 --- dlls/kernelbase/console.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dlls/kernelbase/console.c b/dlls/kernelbase/console.c index 38d09d6c60f..706d83b79eb 100644 --- a/dlls/kernelbase/console.c +++ b/dlls/kernelbase/console.c @@ -453,6 +453,15 @@ static BOOL alloc_console( BOOL headless ) */ BOOL WINAPI AllocConsole(void) { + RTL_USER_PROCESS_PARAMETERS *params = RtlGetCurrentPeb()->ProcessParameters; + + /* allow gui applications to create a genuine console over a unix one */ + if (RtlImageNtHeader( GetModuleHandleW( NULL ) )->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI && + (params->ConsoleHandle == CONSOLE_HANDLE_SHELL_NO_WINDOW || + console_ioctl( params->ConsoleHandle, IOCTL_CONDRV_IS_UNIX, NULL, 0, NULL, 0, NULL ))) + { + FreeConsole(); + } return alloc_console( FALSE ); } From 8323ec9adddea2b4434a24ae9a195d80db5ee015 Mon Sep 17 00:00:00 2001 From: Etaash Mathamsetty Date: Thu, 22 Jun 2023 00:11:34 -0400 Subject: [PATCH 1613/2777] wine.inf: Set msvcp140_atomic_wait to native,builtin. --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 1e2eac889aa..83397bbb9b9 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2830,6 +2830,7 @@ HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-time-l1-1-0",0x2,"native,builtin HKCU,Software\Wine\DllOverrides,"atl140",0x2,"native,builtin" HKCU,Software\Wine\DllOverrides,"concrt140",0x2,"native,builtin" HKCU,Software\Wine\DllOverrides,"msvcp140",0x2,"native,builtin" +HKCU,Software\Wine\DllOverrides,"msvcp140_atomic_wait",0x2,"native,builtin" HKCU,Software\Wine\DllOverrides,"msvcr140",0x2,"native,builtin" HKCU,Software\Wine\DllOverrides,"ucrtbase",0x2,"native,builtin" HKCU,Software\Wine\DllOverrides,"vcomp140",0x2,"native,builtin" From a752be1f55802ac48dd3b139a8a35cebc8fcdb5e Mon Sep 17 00:00:00 2001 From: "Olivier F. R. Dierick" Date: Wed, 6 Oct 2021 19:59:25 +0200 Subject: [PATCH 1614/2777] dxdiag: Ignore option /64bit on the commandline. The builtin dxdiag doesn't know about option /64bit and display an error dialog. Some games use that option internally on startup and the dialog is annoying. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49964 (cherry picked from commit 60ef0f86772559187c04098e4c3d8b4678062a1c) --- programs/dxdiag/main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/programs/dxdiag/main.c b/programs/dxdiag/main.c index 3f41a27e2f2..47909dcf2c6 100644 --- a/programs/dxdiag/main.c +++ b/programs/dxdiag/main.c @@ -165,6 +165,12 @@ static BOOL process_command_line(const WCHAR *cmdline, struct command_line_info break; + case '6': + if (wcsnicmp(cmdline, L"64bit", 5)) + return FALSE; + cmdline += 5; + break; + case 'd': case 'D': if (wcsnicmp(cmdline, L"dontskip", 8)) From 813c406130522a17766e4b7c65837324c701abad Mon Sep 17 00:00:00 2001 From: Michael Skorokhodov Date: Mon, 19 Jun 2023 21:26:02 +0300 Subject: [PATCH 1615/2777] win32u: Add DriverVersion string for GPUs to registry. Some applications (e.g. UE4) require the DriverVersion string in the registry. Signed-off-by: Mykhailo Skorokhodov (cherry picked from commit 973ed2579186385a97fc51520de75d175cc738a5) Link: https://github.com/ValveSoftware/wine/pull/191 --- dlls/win32u/sysparams.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 826a9927e03..2ecc317b509 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -1224,6 +1224,8 @@ static void add_gpu( const struct gdi_gpu *gpu, void *param ) static const WCHAR ramdacW[] = {'I','n','t','e','r','g','r','a','t','e','d',' ','R','A','M','D','A','C',0}; static const WCHAR driver_dateW[] = {'D','r','i','v','e','r','D','a','t','e',0}; + static const WCHAR driver_versionW[] = + {'D','r','i','v','e','r','V','e','r','s','i','o','n',0}; TRACE( "%s %04X %04X %08X %02X\n", debugstr_w(gpu->name), gpu->vendor_id, gpu->device_id, gpu->subsys_id, gpu->revision_id ); @@ -1368,6 +1370,31 @@ static void add_gpu( const struct gdi_gpu *gpu, void *param ) set_reg_value( hkey, chip_typeW, REG_BINARY, desc, size ); set_reg_value( hkey, dac_typeW, REG_BINARY, ramdacW, sizeof(ramdacW) ); + if (gpu->vendor_id && gpu->device_id) + { + /* The last seven digits are the driver number. */ + switch (gpu->vendor_id) + { + /* Intel */ + case 0x8086: + sprintf( buffer, "31.0.101.4576" ); + break; + /* AMD */ + case 0x1002: + sprintf( buffer, "31.0.14051.5006" ); + break; + /* Nvidia */ + case 0x10de: + sprintf( buffer, "31.0.15.3625" ); + break; + /* Default value for any other vendor. */ + default: + sprintf( buffer, "31.0.10.1000" ); + break; + } + set_reg_value( hkey, driver_versionW, REG_SZ, bufferW, asciiz_to_unicode( bufferW, buffer ) ); + } + NtClose( hkey ); link_device( ctx->gpuid, guid_devinterface_display_adapterW ); From 4a3406b5d1b39349537298aa4993f43b494bfeaa Mon Sep 17 00:00:00 2001 From: Matteo Bruni Date: Fri, 1 Sep 2023 00:54:36 +0200 Subject: [PATCH 1616/2777] kernelbase: HACK: Add --use-gl=swiftshader for EverQuest 2/LaunchPad.exe. CW-Bug-Id: #18509 --- dlls/kernelbase/process.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 46b22897712..0df1b479809 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -592,6 +592,7 @@ static const WCHAR *hack_append_command_line( const WCHAR *cmd ) {L"DC Universe Online\\LaunchPad.exe", L" --use-gl=swiftshader"}, {L"PlanetSide 2\\LaunchPad.exe", L" --use-gl=swiftshader"}, {L"PaladinLias\\Game.exe", L" --use-gl=desktop"}, + {L"EverQuest 2\\LaunchPad.exe", L" --use-gl=swiftshader"}, }; unsigned int i; From 26eb9fc40a0dce1a912ac7488e8a4797825763a6 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Wed, 28 Dec 2022 12:09:43 +0200 Subject: [PATCH 1617/2777] winegstreamer: Set n-threads for dav1d to 1. It defaults to `$(nproc)` which causes the memory footprint to skyrocet on high core count systems. Setting it to 1 makes it use a bit less memory that theora decoder and is enough to decode 1080p 30fps stream on 5950x with a speed of 4x the real time. We may want to set it to value higher than 1 for 64bit apps where limited address space is not an issue. 2 or 4 may be optimal for tiling with 2 columns and 2 rosw when encoding the video. CW-Bug-Id: #19516 --- dlls/winegstreamer/wg_parser.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 789f81a8a75..77c8e0adb36 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -586,6 +586,18 @@ static void no_more_pads_cb(GstElement *element, gpointer user) pthread_cond_signal(&parser->init_cond); } +static void deep_element_added_cb(GstBin *self, GstBin *sub_bin, GstElement *element, gpointer user) +{ + GstElementFactory *factory = gst_element_get_factory(element); + const char *name = gst_element_factory_get_longname(factory); + + if (strstr(name, "Dav1d")) + { + GST_DEBUG("%s found, setting n-threads to 1.", name); + g_object_set(element, "n-threads", G_GINT64_CONSTANT(1), NULL); + } +} + static gboolean sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) { struct wg_parser_stream *stream = gst_pad_get_element_private(pad); @@ -1685,6 +1697,7 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) g_signal_connect(element, "autoplug-select", G_CALLBACK(autoplug_select_cb), parser); g_signal_connect(element, "autoplug-sort", G_CALLBACK(autoplug_sort_cb), parser); g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads_cb), parser); + g_signal_connect(element, "deep-element-added", G_CALLBACK(deep_element_added_cb), parser); pthread_mutex_lock(&parser->mutex); parser->no_more_pads = false; From 1bdddafe755c53163f68e5019f7501f392492f3f Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Tue, 17 Jan 2023 14:38:06 +0200 Subject: [PATCH 1618/2777] winegstreamer: Set n-threads for dav1d to 4 in 64 bit mode. CW-Bug-Id: #19516 --- dlls/winegstreamer/wg_parser.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 77c8e0adb36..d12c4c2dad1 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -593,8 +593,13 @@ static void deep_element_added_cb(GstBin *self, GstBin *sub_bin, GstElement *ele if (strstr(name, "Dav1d")) { +#if defined(__x86_64__) + GST_DEBUG("%s found, setting n-threads to 4.", name); + g_object_set(element, "n-threads", G_GINT64_CONSTANT(4), NULL); +#else GST_DEBUG("%s found, setting n-threads to 1.", name); g_object_set(element, "n-threads", G_GINT64_CONSTANT(1), NULL); +#endif } } From 08e0d8ddc510fd557a7d36ebbb64f88f4b78a784 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Thu, 17 Apr 2014 16:07:46 -0600 Subject: [PATCH 1619/2777] server: Unify the storage of security attributes for files and directories. (try 7) CW-Bug-Id: #22436 --- server/change.c | 45 ++++++--------------------------------------- server/file.c | 34 ++++++++++++++++++++++------------ server/file.h | 2 ++ 3 files changed, 30 insertions(+), 51 deletions(-) diff --git a/server/change.c b/server/change.c index df79e5c8524..92f35028c5b 100644 --- a/server/change.c +++ b/server/change.c @@ -366,48 +366,15 @@ static int dir_set_sd( struct object *obj, const struct security_descriptor *sd, unsigned int set_info ) { struct dir *dir = (struct dir *)obj; - const struct sid *owner; - struct stat st; - mode_t mode; - int unix_fd; + struct fd *fd; + int ret; assert( obj->ops == &dir_ops ); - unix_fd = get_dir_unix_fd( dir ); - - if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return 1; - - if (set_info & OWNER_SECURITY_INFORMATION) - { - owner = sd_get_owner( sd ); - if (!owner) - { - set_error( STATUS_INVALID_SECURITY_DESCR ); - return 0; - } - if (!obj->sd || !equal_sid( owner, sd_get_owner( obj->sd ) )) - { - /* FIXME: get Unix uid and call fchown */ - } - } - else if (obj->sd) - owner = sd_get_owner( obj->sd ); - else - owner = token_get_owner( current->process->token ); - - if (set_info & DACL_SECURITY_INFORMATION) - { - /* keep the bits that we don't map to access rights in the ACL */ - mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX); - mode |= sd_to_mode( sd, owner ); - - if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1) - { - file_set_error(); - return 0; - } - } - return 1; + fd = dir_get_fd( obj ); + ret = set_file_sd( obj, fd, &dir->mode, &dir->uid, sd, set_info ); + release_object( fd ); + return ret; } static struct change_record *get_first_change_record( struct dir *dir ) diff --git a/server/file.c b/server/file.c index bea0d09f9de..5bbdd210a37 100644 --- a/server/file.c +++ b/server/file.c @@ -500,18 +500,13 @@ mode_t sd_to_mode( const struct security_descriptor *sd, const struct sid *owner return new_mode; } -static int file_set_sd( struct object *obj, const struct security_descriptor *sd, - unsigned int set_info ) +int set_file_sd( struct object *obj, struct fd *fd, mode_t *mode, uid_t *uid, + const struct security_descriptor *sd, unsigned int set_info ) { - struct file *file = (struct file *)obj; + int unix_fd = get_unix_fd( fd ); const struct sid *owner; struct stat st; - mode_t mode; - int unix_fd; - - assert( obj->ops == &file_ops ); - - unix_fd = get_file_unix_fd( file ); + mode_t new_mode; if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return 1; @@ -538,10 +533,10 @@ static int file_set_sd( struct object *obj, const struct security_descriptor *sd if (set_info & DACL_SECURITY_INFORMATION) { /* keep the bits that we don't map to access rights in the ACL */ - mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX); - mode |= sd_to_mode( sd, owner ); + new_mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX); + new_mode |= sd_to_mode( sd, owner ); - if (((st.st_mode ^ mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, mode ) == -1) + if (((st.st_mode ^ new_mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, new_mode ) == -1) { file_set_error(); return 0; @@ -586,6 +581,21 @@ static struct list *file_get_kernel_obj_list( struct object *obj ) return &file->kernel_object; } +static int file_set_sd( struct object *obj, const struct security_descriptor *sd, + unsigned int set_info ) +{ + struct file *file = (struct file *)obj; + struct fd *fd; + int ret; + + assert( obj->ops == &file_ops ); + + fd = file_get_fd( obj ); + ret = set_file_sd( obj, fd, &file->mode, &file->uid, sd, set_info ); + release_object( fd ); + return ret; +} + static void file_destroy( struct object *obj ) { struct file *file = (struct file *)obj; diff --git a/server/file.h b/server/file.h index 1965626dc0e..189cc7af931 100644 --- a/server/file.h +++ b/server/file.h @@ -176,6 +176,8 @@ extern void file_set_error(void); extern struct security_descriptor *mode_to_sd( mode_t mode, const struct sid *user, const struct sid *group ); extern mode_t sd_to_mode( const struct security_descriptor *sd, const struct sid *owner ); extern int is_file_executable( const char *name ); +extern int set_file_sd( struct object *obj, struct fd *fd, mode_t *mode, uid_t *uid, + const struct security_descriptor *sd, unsigned int set_info ); /* file mapping functions */ From 80177a3b6bdefdee2251325a49552aaf6fbf925f Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Thu, 17 Apr 2014 16:07:50 -0600 Subject: [PATCH 1620/2777] server: Unify the retrieval of security attributes for files and directories. (try 7) CW-Bug-Id: #22436 --- server/change.c | 32 +++++--------------------------- server/file.c | 32 +++++++++++++++++++++----------- server/file.h | 2 ++ 3 files changed, 28 insertions(+), 38 deletions(-) diff --git a/server/change.c b/server/change.c index 92f35028c5b..f6d3d0252a9 100644 --- a/server/change.c +++ b/server/change.c @@ -326,39 +326,17 @@ static struct fd *dir_get_fd( struct object *obj ) return (struct fd *)grab_object( dir->fd ); } -static int get_dir_unix_fd( struct dir *dir ) -{ - return get_unix_fd( dir->fd ); -} - static struct security_descriptor *dir_get_sd( struct object *obj ) { struct dir *dir = (struct dir *)obj; - int unix_fd; - struct stat st; struct security_descriptor *sd; - assert( obj->ops == &dir_ops ); - - unix_fd = get_dir_unix_fd( dir ); - - if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) - return obj->sd; - - /* mode and uid the same? if so, no need to re-generate security descriptor */ - if (obj->sd && - (st.st_mode & (S_IRWXU|S_IRWXO)) == (dir->mode & (S_IRWXU|S_IRWXO)) && - (st.st_uid == dir->uid)) - return obj->sd; + struct fd *fd; - sd = mode_to_sd( st.st_mode, - security_unix_uid_to_sid( st.st_uid ), - token_get_primary_group( current->process->token )); - if (!sd) return obj->sd; + assert( obj->ops == &dir_ops ); - dir->mode = st.st_mode; - dir->uid = st.st_uid; - free( obj->sd ); - obj->sd = sd; + fd = dir_get_fd( obj ); + sd = get_file_sd( obj, fd, &dir->mode, &dir->uid ); + release_object( fd ); return sd; } diff --git a/server/file.c b/server/file.c index 5bbdd210a37..0b51b9d3a2f 100644 --- a/server/file.c +++ b/server/file.c @@ -390,23 +390,19 @@ struct security_descriptor *mode_to_sd( mode_t mode, const struct sid *user, con return sd; } -static struct security_descriptor *file_get_sd( struct object *obj ) +struct security_descriptor *get_file_sd( struct object *obj, struct fd *fd, mode_t *mode, + uid_t *uid ) { - struct file *file = (struct file *)obj; + int unix_fd = get_unix_fd( fd ); struct stat st; - int unix_fd; struct security_descriptor *sd; - assert( obj->ops == &file_ops ); - - unix_fd = get_file_unix_fd( file ); - if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return obj->sd; /* mode and uid the same? if so, no need to re-generate security descriptor */ - if (obj->sd && (st.st_mode & (S_IRWXU|S_IRWXO)) == (file->mode & (S_IRWXU|S_IRWXO)) && - (st.st_uid == file->uid)) + if (obj->sd && (st.st_mode & (S_IRWXU|S_IRWXO)) == (*mode & (S_IRWXU|S_IRWXO)) && + (st.st_uid == *uid)) return obj->sd; sd = mode_to_sd( st.st_mode, @@ -414,13 +410,27 @@ static struct security_descriptor *file_get_sd( struct object *obj ) token_get_primary_group( current->process->token )); if (!sd) return obj->sd; - file->mode = st.st_mode; - file->uid = st.st_uid; + *mode = st.st_mode; + *uid = st.st_uid; free( obj->sd ); obj->sd = sd; return sd; } +static struct security_descriptor *file_get_sd( struct object *obj ) +{ + struct file *file = (struct file *)obj; + struct security_descriptor *sd; + struct fd *fd; + + assert( obj->ops == &file_ops ); + + fd = file_get_fd( obj ); + sd = get_file_sd( obj, fd, &file->mode, &file->uid ); + release_object( fd ); + return sd; +} + static mode_t file_access_to_mode( unsigned int access ) { mode_t mode = 0; diff --git a/server/file.h b/server/file.h index 189cc7af931..796027fcb76 100644 --- a/server/file.h +++ b/server/file.h @@ -178,6 +178,8 @@ extern mode_t sd_to_mode( const struct security_descriptor *sd, const struct sid extern int is_file_executable( const char *name ); extern int set_file_sd( struct object *obj, struct fd *fd, mode_t *mode, uid_t *uid, const struct security_descriptor *sd, unsigned int set_info ); +extern struct security_descriptor *get_file_sd( struct object *obj, struct fd *fd, mode_t *mode, + uid_t *uid ); /* file mapping functions */ From e5f9b8d0ab73014e1b4d1c9b12428915ccc3a5a5 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Mon, 30 Mar 2015 12:32:34 +0200 Subject: [PATCH 1621/2777] server: Add a helper function set_sd_from_token_internal to merge two security descriptors. CW-Bug-Id: #22436 --- server/object.c | 59 +++++++++++++++++++++++++++++++------------------ server/object.h | 3 +++ 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/server/object.c b/server/object.c index 89e541ffb6b..29f1ea96129 100644 --- a/server/object.c +++ b/server/object.c @@ -548,8 +548,9 @@ struct security_descriptor *default_get_sd( struct object *obj ) return obj->sd; } -int set_sd_defaults_from_token( struct object *obj, const struct security_descriptor *sd, - unsigned int set_info, struct token *token ) +struct security_descriptor *set_sd_from_token_internal( const struct security_descriptor *sd, + const struct security_descriptor *old_sd, + unsigned int set_info, struct token *token ) { struct security_descriptor new_sd, *new_sd_ptr; int present; @@ -558,8 +559,6 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri struct acl *replaced_sacl = NULL; char *ptr; - if (!set_info) return 1; - new_sd.control = sd->control & ~SE_SELF_RELATIVE; if (set_info & OWNER_SECURITY_INFORMATION && sd->owner_len) @@ -567,10 +566,10 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri owner = sd_get_owner( sd ); new_sd.owner_len = sd->owner_len; } - else if (obj->sd && obj->sd->owner_len) + else if (old_sd && old_sd->owner_len) { - owner = sd_get_owner( obj->sd ); - new_sd.owner_len = obj->sd->owner_len; + owner = sd_get_owner( old_sd ); + new_sd.owner_len = old_sd->owner_len; } else if (token) { @@ -584,10 +583,10 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri group = sd_get_group( sd ); new_sd.group_len = sd->group_len; } - else if (obj->sd && obj->sd->group_len) + else if (old_sd && old_sd->group_len) { - group = sd_get_group( obj->sd ); - new_sd.group_len = obj->sd->group_len; + group = sd_get_group( old_sd ); + new_sd.group_len = old_sd->group_len; } else if (token) { @@ -605,20 +604,20 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri else if (set_info & LABEL_SECURITY_INFORMATION && present) { const struct acl *old_sacl = NULL; - if (obj->sd && obj->sd->control & SE_SACL_PRESENT) old_sacl = sd_get_sacl( obj->sd, &present ); - if (!(replaced_sacl = replace_security_labels( old_sacl, sacl ))) return 0; + if (old_sd && old_sd->control & SE_SACL_PRESENT) old_sacl = sd_get_sacl( old_sd, &present ); + if (!(replaced_sacl = replace_security_labels( old_sacl, sacl ))) return NULL; new_sd.control |= SE_SACL_PRESENT; new_sd.sacl_len = replaced_sacl->size; sacl = replaced_sacl; } else { - if (obj->sd) sacl = sd_get_sacl( obj->sd, &present ); + if (old_sd) sacl = sd_get_sacl( old_sd, &present ); - if (obj->sd && present) + if (old_sd && present) { new_sd.control |= SE_SACL_PRESENT; - new_sd.sacl_len = obj->sd->sacl_len; + new_sd.sacl_len = old_sd->sacl_len; } else new_sd.sacl_len = 0; @@ -632,12 +631,12 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri } else { - if (obj->sd) dacl = sd_get_dacl( obj->sd, &present ); + if (old_sd) dacl = sd_get_dacl( old_sd, &present ); - if (obj->sd && present) + if (old_sd && present) { new_sd.control |= SE_DACL_PRESENT; - new_sd.dacl_len = obj->sd->dacl_len; + new_sd.dacl_len = old_sd->dacl_len; } else if (token) { @@ -653,7 +652,7 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri if (!ptr) { free( replaced_sacl ); - return 0; + return NULL; } new_sd_ptr = (struct security_descriptor*)ptr; @@ -668,9 +667,25 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri memcpy( ptr, dacl, new_sd.dacl_len ); free( replaced_sacl ); - free( obj->sd ); - obj->sd = new_sd_ptr; - return 1; + return new_sd_ptr; +} + +int set_sd_defaults_from_token( struct object *obj, const struct security_descriptor *sd, + unsigned int set_info, struct token *token ) +{ + struct security_descriptor *new_sd; + + if (!set_info) return 1; + + new_sd = set_sd_from_token_internal( sd, obj->sd, set_info, token ); + if (new_sd) + { + free( obj->sd ); + obj->sd = new_sd; + return 1; + } + + return 0; } /** Set the security descriptor using the current primary token for defaults. */ diff --git a/server/object.h b/server/object.h index 8bf236abb58..20c7ab63938 100644 --- a/server/object.h +++ b/server/object.h @@ -175,6 +175,9 @@ extern struct fd *no_get_fd( struct object *obj ); extern unsigned int default_map_access( struct object *obj, unsigned int access ); extern struct security_descriptor *default_get_sd( struct object *obj ); extern int default_set_sd( struct object *obj, const struct security_descriptor *sd, unsigned int set_info ); +extern struct security_descriptor *set_sd_from_token_internal( const struct security_descriptor *sd, + const struct security_descriptor *old_sd, + unsigned int set_info, struct token *token ); extern int set_sd_defaults_from_token( struct object *obj, const struct security_descriptor *sd, unsigned int set_info, struct token *token ); extern WCHAR *no_get_full_name( struct object *obj, data_size_t *ret_len ); From 0dbca8538f0d6d0a244e82e6191a627bad687ff8 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Mon, 30 Mar 2015 12:50:21 +0200 Subject: [PATCH 1622/2777] server: Temporarily store the full security descriptor for file objects. CW-Bug-Id: #22436 --- dlls/advapi32/tests/security.c | 16 ++---- server/change.c | 8 ++- server/file.c | 100 +++++++++++++++++++++------------ server/file.h | 3 +- 4 files changed, 80 insertions(+), 47 deletions(-) diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index c0fea3c5507..05659e05264 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -3774,7 +3774,6 @@ static void test_CreateDirectoryA(void) ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %ld\n", error); bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); ok(bret, "GetAclInformation failed\n"); - todo_wine ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%ld != 0).\n", acl_size.AceCount); LocalFree(pSD); @@ -3785,7 +3784,6 @@ static void test_CreateDirectoryA(void) ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %ld\n", error); bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); ok(bret, "GetAclInformation failed\n"); - todo_wine ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%ld != 0).\n", acl_size.AceCount); LocalFree(pSD); @@ -3908,7 +3906,6 @@ static void test_CreateDirectoryA(void) ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %d\n", error); bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation); ok(bret, "GetAclInformation failed\n"); - todo_wine ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%d != 0).\n", acl_size.AceCount); LocalFree(pSD); @@ -5024,23 +5021,22 @@ static void test_GetSecurityInfo(void) bret = GetAce(pDacl, 0, (VOID **)&ace); ok(bret, "Failed to get Current User ACE.\n"); bret = EqualSid(&ace->SidStart, user_sid); - todo_wine ok(bret, "Current User ACE (%s) != Current User SID (%s).\n", - debugstr_sid(&ace->SidStart), debugstr_sid(user_sid)); + ok(bret, "Current User ACE (%s) != Current User SID (%s).\n", debugstr_sid(&ace->SidStart), debugstr_sid(user_sid)); ok(((ACE_HEADER *)ace)->AceFlags == 0, "Current User ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags); - ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%lx != 0x1f01ff)\n", - ace->Mask); + todo_wine ok(ace->Mask == 0x1f01ff, + "Current User ACE has unexpected mask (0x%lx != 0x1f01ff)\n", ace->Mask); } if (acl_size.AceCount > 1) { bret = GetAce(pDacl, 1, (VOID **)&ace); ok(bret, "Failed to get Administators Group ACE.\n"); bret = EqualSid(&ace->SidStart, admin_sid); - todo_wine ok(bret, "Administators Group ACE (%s) != Administators Group SID (%s).\n", debugstr_sid(&ace->SidStart), debugstr_sid(admin_sid)); + ok(bret, "Administators Group ACE (%s) != Administators Group SID (%s).\n", debugstr_sid(&ace->SidStart), debugstr_sid(admin_sid)); ok(((ACE_HEADER *)ace)->AceFlags == 0, "Administators Group ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags); - ok(ace->Mask == 0x1f01ff, "Administators Group ACE has unexpected mask (0x%lx != 0x1f01ff)\n", - ace->Mask); + todo_wine ok(ace->Mask == 0x1f01ff, + "Administators Group ACE has unexpected mask (0x%lx != 0x1f01ff)\n", ace->Mask); } LocalFree(pSD); CloseHandle(obj); diff --git a/server/change.c b/server/change.c index f6d3d0252a9..9ffa8ab694f 100644 --- a/server/change.c +++ b/server/change.c @@ -1069,7 +1069,8 @@ static int dir_add_to_existing_notify( struct dir *dir ) #endif /* HAVE_SYS_INOTIFY_H */ -struct object *create_dir_obj( struct fd *fd, unsigned int access, mode_t mode ) +struct object *create_dir_obj( struct fd *fd, unsigned int access, mode_t mode, + const struct security_descriptor *sd ) { struct dir *dir; @@ -1089,6 +1090,11 @@ struct object *create_dir_obj( struct fd *fd, unsigned int access, mode_t mode ) dir->client_process = NULL; set_fd_user( fd, &dir_fd_ops, &dir->obj ); + if (sd) dir_set_sd( &dir->obj, sd, OWNER_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION | + SACL_SECURITY_INFORMATION ); + dir_add_to_existing_notify( dir ); return &dir->obj; diff --git a/server/file.c b/server/file.c index 0b51b9d3a2f..2db89ae19f9 100644 --- a/server/file.c +++ b/server/file.c @@ -189,7 +189,8 @@ struct file *create_file_for_fd_obj( struct fd *fd, unsigned int access, unsigne return file; } -static struct object *create_file_obj( struct fd *fd, unsigned int access, mode_t mode ) +static struct object *create_file_obj( struct fd *fd, unsigned int access, mode_t mode, + const struct security_descriptor *sd ) { struct file *file = alloc_object( &file_ops ); @@ -201,6 +202,12 @@ static struct object *create_file_obj( struct fd *fd, unsigned int access, mode_ list_init( &file->kernel_object ); grab_object( fd ); set_fd_user( fd, &file_fd_ops, &file->obj ); + + if (sd) file_set_sd( &file->obj, sd, OWNER_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION | + SACL_SECURITY_INFORMATION ); + return &file->obj; } @@ -273,11 +280,11 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si if (!fd) goto done; if (S_ISDIR(mode)) - obj = create_dir_obj( fd, access, mode ); + obj = create_dir_obj( fd, access, mode, sd ); else if (S_ISCHR(mode) && is_serial_fd( fd )) obj = create_serial( fd ); else - obj = create_file_obj( fd, access, mode ); + obj = create_file_obj( fd, access, mode, sd ); release_object( fd ); @@ -513,46 +520,66 @@ mode_t sd_to_mode( const struct security_descriptor *sd, const struct sid *owner int set_file_sd( struct object *obj, struct fd *fd, mode_t *mode, uid_t *uid, const struct security_descriptor *sd, unsigned int set_info ) { + struct security_descriptor *new_sd; int unix_fd = get_unix_fd( fd ); - const struct sid *owner; + const struct sid *owner, *group; struct stat st; mode_t new_mode; - if (unix_fd == -1 || fstat( unix_fd, &st ) == -1) return 1; + if (!set_info || unix_fd == -1 || fstat( unix_fd, &st ) == -1) return 1; + if (!obj->sd) get_file_sd( obj, fd, mode, uid ); - if (set_info & OWNER_SECURITY_INFORMATION) - { - owner = sd_get_owner( sd ); - if (!owner) - { - set_error( STATUS_INVALID_SECURITY_DESCR ); - return 0; - } - if (!obj->sd || !equal_sid( owner, sd_get_owner( obj->sd ) )) - { - /* FIXME: get Unix uid and call fchown */ - } - } - else if (obj->sd) - owner = sd_get_owner( obj->sd ); - else - owner = token_get_owner( current->process->token ); + /* calculate the new sd, save to a temporary variable before assigning */ + new_sd = set_sd_from_token_internal( sd, obj->sd, set_info, current->process->token ); + if (new_sd) + { + if (set_info & OWNER_SECURITY_INFORMATION) + { + owner = sd_get_owner( new_sd ); + assert( owner ); - /* group and sacl not supported */ + if (!obj->sd || !equal_sid( owner, sd_get_owner( obj->sd ) )) + { + /* FIXME: get Unix uid and call fchown */ + } + } - if (set_info & DACL_SECURITY_INFORMATION) - { - /* keep the bits that we don't map to access rights in the ACL */ - new_mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX); - new_mode |= sd_to_mode( sd, owner ); + if (set_info & GROUP_SECURITY_INFORMATION) + { + group = sd_get_group( new_sd ); + assert( group ); - if (((st.st_mode ^ new_mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, new_mode ) == -1) + if (!obj->sd || !equal_sid( group, sd_get_group( obj->sd ) )) + { + /* FIXME: get Unix uid and call fchown */ + } + } + + if (set_info & DACL_SECURITY_INFORMATION) { - file_set_error(); - return 0; - } - } - return 1; + owner = sd_get_owner( new_sd ); + assert( owner ); + + /* keep the bits that we don't map to access rights in the ACL */ + new_mode = st.st_mode & (S_ISUID|S_ISGID|S_ISVTX); + new_mode |= sd_to_mode( new_sd, owner ); + + if (((st.st_mode ^ new_mode) & (S_IRWXU|S_IRWXG|S_IRWXO)) && fchmod( unix_fd, new_mode ) == -1) + { + free( new_sd ); + file_set_error(); + return 0; + } + + *mode = (*mode & S_IFMT) | new_mode; + } + + free( obj->sd ); + obj->sd = new_sd; + return 1; + } + + return 0; } static struct object *file_lookup_name( struct object *obj, struct unicode_str *name, @@ -692,7 +719,10 @@ DECL_HANDLER(create_file) if ((file = create_file( root_fd, name, name_len, nt_name, req->access, req->sharing, req->create, req->options, req->attrs, sd ))) { - reply->handle = alloc_handle( current->process, file, req->access, objattr->attributes ); + if (get_error() == STATUS_OBJECT_NAME_EXISTS) + reply->handle = alloc_handle( current->process, file, req->access, objattr->attributes ); + else + reply->handle = alloc_handle_no_access_check( current->process, file, req->access, objattr->attributes ); release_object( file ); } if (root_fd) release_object( root_fd ); diff --git a/server/file.h b/server/file.h index 796027fcb76..4f835ab1e99 100644 --- a/server/file.h +++ b/server/file.h @@ -217,7 +217,8 @@ extern struct object *create_unix_device( struct object *root, const struct unic extern void do_change_notify( int unix_fd ); extern void sigio_callback(void); -extern struct object *create_dir_obj( struct fd *fd, unsigned int access, mode_t mode ); +extern struct object *create_dir_obj( struct fd *fd, unsigned int access, mode_t mode, + const struct security_descriptor *sd ); extern struct dir *get_dir_obj( struct process *process, obj_handle_t handle, unsigned int access ); /* completion */ From 9d8a419fa3236ed0315ef10bcf9c9ef7514a3952 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Mon, 30 Mar 2015 13:04:23 +0200 Subject: [PATCH 1623/2777] server: Store file security attributes with extended file attributes. (v8) CW-Bug-Id: #22436 --- server/file.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/server/file.c b/server/file.c index 2db89ae19f9..6214858bca3 100644 --- a/server/file.c +++ b/server/file.c @@ -31,11 +31,21 @@ #include #include #include +#include #include #ifdef HAVE_UTIME_H #include #endif #include +#ifdef HAVE_ATTR_XATTR_H +#undef XATTR_ADDITIONAL_OPTIONS +#include +#elif defined(HAVE_SYS_XATTR_H) +#include +#endif +#ifdef HAVE_SYS_EXTATTR_H +#include +#endif #include "ntstatus.h" #define WIN32_NO_STATUS @@ -63,6 +73,21 @@ struct type_descr file_type = }, }; +#ifndef XATTR_USER_PREFIX +#define XATTR_USER_PREFIX "user." +#endif +#ifndef XATTR_SIZE_MAX +#define XATTR_SIZE_MAX 65536 +#endif + +/* We intentionally do not match the Samba 4 extended attribute for NT security descriptors (SDs): + * 1) Samba stores this information using an internal data structure (we use a flat NT SD). + * 2) Samba uses the attribute "security.NTACL". This attribute is within a namespace that only + * the administrator has write access to, which prohibits the user from copying the attributes + * when copying a file and would require Wine to run with adminstrative privileges. + */ +#define WINE_XATTR_SD XATTR_USER_PREFIX "wine.sd" + struct file { struct object obj; /* object header */ @@ -217,6 +242,56 @@ int is_file_executable( const char *name ) return len >= 4 && (!strcasecmp( name + len - 4, ".exe") || !strcasecmp( name + len - 4, ".com" )); } +#ifdef HAVE_SYS_EXTATTR_H +static inline int xattr_valid_namespace( const char *name ) +{ + if (strncmp( XATTR_USER_PREFIX, name, XATTR_USER_PREFIX_LEN ) != 0) + { + errno = EPERM; + return 0; + } + return 1; +} +#endif + +static int xattr_fset( int filedes, const char *name, void *value, size_t size ) +{ +#if defined(XATTR_ADDITIONAL_OPTIONS) + return fsetxattr( filedes, name, value, size, 0, 0 ); +#elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) + return fsetxattr( filedes, name, value, size, 0 ); +#elif defined(HAVE_SYS_EXTATTR_H) + if (!xattr_valid_namespace( name )) return -1; + return extattr_set_fd( filedes, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN], + value, size ); +#else + errno = ENOSYS; + return -1; +#endif +} + +static void set_xattr_sd( int fd, const struct security_descriptor *sd ) +{ + char buffer[XATTR_SIZE_MAX]; + int present, len; + const struct acl *dacl; + + /* there's no point in storing the security descriptor if there's no DACL */ + if (!sd) return; + dacl = sd_get_dacl( sd, &present ); + if (!present || !dacl) return; + + len = 2 + sizeof(struct security_descriptor) + sd->owner_len + + sd->group_len + sd->sacl_len + sd->dacl_len; + if (len > XATTR_SIZE_MAX) return; + + /* include the descriptor revision and resource manager control bits */ + buffer[0] = SECURITY_DESCRIPTOR_REVISION; + buffer[1] = 0; + memcpy( &buffer[2], sd, len - 2 ); + xattr_fset( fd, WINE_XATTR_SD, buffer, len ); +} + static struct object *create_file( struct fd *root, const char *nameptr, data_size_t len, struct unicode_str nt_name, unsigned int access, unsigned int sharing, int create, @@ -574,6 +649,9 @@ int set_file_sd( struct object *obj, struct fd *fd, mode_t *mode, uid_t *uid, *mode = (*mode & S_IFMT) | new_mode; } + /* extended attributes are set after the file mode, to ensure it stays in sync */ + set_xattr_sd( unix_fd, new_sd ); + free( obj->sd ); obj->sd = new_sd; return 1; From 0c28a75afb690463f2cd275ecc65434f85c2edd5 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Fri, 18 Apr 2014 14:05:32 -0600 Subject: [PATCH 1624/2777] server: Convert return of file security masks with generic access mappings. (try 7) CW-Bug-Id: #22436 --- dlls/advapi32/tests/security.c | 6 +++--- server/file.c | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index 05659e05264..07a682f7759 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -5024,8 +5024,8 @@ static void test_GetSecurityInfo(void) ok(bret, "Current User ACE (%s) != Current User SID (%s).\n", debugstr_sid(&ace->SidStart), debugstr_sid(user_sid)); ok(((ACE_HEADER *)ace)->AceFlags == 0, "Current User ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags); - todo_wine ok(ace->Mask == 0x1f01ff, - "Current User ACE has unexpected mask (0x%lx != 0x1f01ff)\n", ace->Mask); + ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%lx != 0x1f01ff)\n", + ace->Mask); } if (acl_size.AceCount > 1) { @@ -5035,7 +5035,7 @@ static void test_GetSecurityInfo(void) ok(bret, "Administators Group ACE (%s) != Administators Group SID (%s).\n", debugstr_sid(&ace->SidStart), debugstr_sid(admin_sid)); ok(((ACE_HEADER *)ace)->AceFlags == 0, "Administators Group ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags); - todo_wine ok(ace->Mask == 0x1f01ff, + ok(ace->Mask == 0x1f01ff, "Administators Group ACE has unexpected mask (0x%lx != 0x1f01ff)\n", ace->Mask); } LocalFree(pSD); diff --git a/server/file.c b/server/file.c index 6214858bca3..fe1d09ed819 100644 --- a/server/file.c +++ b/server/file.c @@ -472,6 +472,26 @@ struct security_descriptor *mode_to_sd( mode_t mode, const struct sid *user, con return sd; } +/* Convert generic rights into standard access rights */ +static void convert_generic_sd( struct security_descriptor *sd ) +{ + const struct acl *dacl; + int present; + + dacl = sd_get_dacl( sd, &present ); + if (present && dacl) + { + const struct ace *ace = (const struct ace *)(dacl + 1); + ULONG i; + + for (i = 0; i < dacl->count; i++, ace = ace_next( ace )) + { + DWORD *mask = (DWORD *)(ace + 1); + *mask = map_access( *mask, &file_type.mapping ); + } + } +} + struct security_descriptor *get_file_sd( struct object *obj, struct fd *fd, mode_t *mode, uid_t *uid ) { @@ -608,6 +628,9 @@ int set_file_sd( struct object *obj, struct fd *fd, mode_t *mode, uid_t *uid, new_sd = set_sd_from_token_internal( sd, obj->sd, set_info, current->process->token ); if (new_sd) { + /* convert generic rights into standard access rights */ + convert_generic_sd( new_sd ); + if (set_info & OWNER_SECURITY_INFORMATION) { owner = sd_get_owner( new_sd ); From 0714ad19b09310909bdea366c1977f70cd10ad1b Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Fri, 18 Apr 2014 14:01:35 -0600 Subject: [PATCH 1625/2777] server: Retrieve file security attributes with extended file attributes. (try 7) CW-Bug-Id: #22436 --- dlls/advapi32/tests/security.c | 19 ++++++------- server/file.c | 50 ++++++++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 13 deletions(-) diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index 07a682f7759..5dfddf8ddde 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -3728,7 +3728,7 @@ static void test_CreateDirectoryA(void) } ok(!error, "GetNamedSecurityInfo failed with error %ld\n", error); test_inherited_dacl(pDacl, admin_sid, user_sid, OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE, - 0x1f01ff, FALSE, TRUE, FALSE, __LINE__); + 0x1f01ff, FALSE, FALSE, FALSE, __LINE__); LocalFree(pSD); /* Test inheritance of ACLs in CreateFile without security descriptor */ @@ -4182,21 +4182,20 @@ static void test_GetNamedSecurityInfoA(void) bret = GetAce(pDacl, 0, (VOID **)&ace); ok(bret, "Failed to get Current User ACE.\n"); bret = EqualSid(&ace->SidStart, user_sid); - todo_wine ok(bret, "Current User ACE (%s) != Current User SID (%s).\n", - debugstr_sid(&ace->SidStart), debugstr_sid(user_sid)); + ok(bret, "Current User ACE (%s) != Current User SID (%s).\n", + debugstr_sid(&ace->SidStart), debugstr_sid(user_sid)); ok(((ACE_HEADER *)ace)->AceFlags == 0, "Current User ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags); - ok(ace->Mask == 0x1f01ff, "Current User ACE has unexpected mask (0x%lx != 0x1f01ff)\n", - ace->Mask); + ok(ace->Mask == 0x1f01ff, + "Current User ACE has unexpected mask (0x%lx != 0x1f01ff)\n", ace->Mask); } if (acl_size.AceCount > 1) { bret = GetAce(pDacl, 1, (VOID **)&ace); ok(bret, "Failed to get Administators Group ACE.\n"); bret = EqualSid(&ace->SidStart, admin_sid); - todo_wine ok(bret || broken(!bret) /* win2k */, - "Administators Group ACE (%s) != Administators Group SID (%s).\n", - debugstr_sid(&ace->SidStart), debugstr_sid(admin_sid)); + ok(bret || broken(!bret) /* win2k */, "Administators Group ACE (%s) != Administators Group SID (%s).\n", + debugstr_sid(&ace->SidStart), debugstr_sid(admin_sid)); ok(((ACE_HEADER *)ace)->AceFlags == 0, "Administators Group ACE has unexpected flags (0x%x != 0x0)\n", ((ACE_HEADER *)ace)->AceFlags); ok(ace->Mask == 0x1f01ff || broken(ace->Mask == GENERIC_ALL) /* win2k */, @@ -4223,8 +4222,8 @@ static void test_GetNamedSecurityInfoA(void) { bret = GetAce(pDacl, 0, (VOID **)&ace); ok(bret, "Failed to get ACE.\n"); - todo_wine ok(((ACE_HEADER *)ace)->AceFlags & INHERITED_ACE, - "ACE has unexpected flags: 0x%x\n", ((ACE_HEADER *)ace)->AceFlags); + ok(((ACE_HEADER *)ace)->AceFlags & INHERITED_ACE, + "ACE has unexpected flags: 0x%x\n", ((ACE_HEADER *)ace)->AceFlags); } LocalFree(pSD); diff --git a/server/file.c b/server/file.c index fe1d09ed819..6da354af245 100644 --- a/server/file.c +++ b/server/file.c @@ -44,6 +44,7 @@ #include #endif #ifdef HAVE_SYS_EXTATTR_H +#undef XATTR_ADDITIONAL_OPTIONS #include #endif @@ -76,6 +77,9 @@ struct type_descr file_type = #ifndef XATTR_USER_PREFIX #define XATTR_USER_PREFIX "user." #endif +#ifndef XATTR_USER_PREFIX_LEN +#define XATTR_USER_PREFIX_LEN (sizeof(XATTR_USER_PREFIX) - 1) +#endif #ifndef XATTR_SIZE_MAX #define XATTR_SIZE_MAX 65536 #endif @@ -254,6 +258,22 @@ static inline int xattr_valid_namespace( const char *name ) } #endif +static int xattr_fget( int filedes, const char *name, void *value, size_t size ) +{ +#if defined(XATTR_ADDITIONAL_OPTIONS) + return fgetxattr( filedes, name, value, size, 0, 0 ); +#elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) + return fgetxattr( filedes, name, value, size ); +#elif defined(HAVE_SYS_EXTATTR_H) + if (!xattr_valid_namespace( name )) return -1; + return extattr_get_fd( filedes, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN], + value, size ); +#else + errno = ENOSYS; + return -1; +#endif +} + static int xattr_fset( int filedes, const char *name, void *value, size_t size ) { #if defined(XATTR_ADDITIONAL_OPTIONS) @@ -492,6 +512,29 @@ static void convert_generic_sd( struct security_descriptor *sd ) } } +static struct security_descriptor *get_xattr_sd( int fd ) +{ + struct security_descriptor *sd; + char buffer[XATTR_SIZE_MAX]; + int n; + + n = xattr_fget( fd, WINE_XATTR_SD, buffer, sizeof(buffer) ); + if (n == -1 || n < 2 + sizeof(struct security_descriptor)) return NULL; + + /* validate that we can handle the descriptor */ + if (buffer[0] != SECURITY_DESCRIPTOR_REVISION || buffer[1] != 0 || + !sd_is_valid( (struct security_descriptor *)&buffer[2], n - 2 )) + return NULL; + + sd = mem_alloc( n - 2 ); + if (sd) + { + memcpy( sd, &buffer[2], n - 2 ); + convert_generic_sd( sd ); /* for backwards compatibility */ + } + return sd; +} + struct security_descriptor *get_file_sd( struct object *obj, struct fd *fd, mode_t *mode, uid_t *uid ) { @@ -507,9 +550,10 @@ struct security_descriptor *get_file_sd( struct object *obj, struct fd *fd, mode (st.st_uid == *uid)) return obj->sd; - sd = mode_to_sd( st.st_mode, - security_unix_uid_to_sid( st.st_uid ), - token_get_primary_group( current->process->token )); + sd = get_xattr_sd( unix_fd ); + if (!sd) sd = mode_to_sd( st.st_mode, + security_unix_uid_to_sid( st.st_uid ), + token_get_primary_group( current->process->token )); if (!sd) return obj->sd; *mode = st.st_mode; From aff02d556f7b0d0069767d81822c3e0271c7e62b Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Tue, 12 Sep 2023 09:43:37 +0800 Subject: [PATCH 1626/2777] Revert "fixup! HACK: winex11.drv: Workaround focusing out of exclusive fullscreen windows." This reverts commit 37a95e27794ab08967026010e2f7918499f684ab. CW-Bug-Id: #22269 --- dlls/winex11.drv/window.c | 12 +----------- include/wine/gdi_driver.h | 1 - 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 8c55367e4ad..2521625180b 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -170,8 +170,6 @@ static int detect_wm(Display *dpy) cached = WINE_WM_X11_STEAMCOMPMGR; else if(strcmp(wm_name, "KWin") == 0) cached = WINE_WM_X11_KDE; - else if(strcmp(wm_name, "Xfwm4") == 0 || strcmp(wm_name, "xfwm4") == 0) - cached = WINE_WM_X11_XFCE4; else cached = WINE_WM_UNKNOWN; @@ -208,11 +206,6 @@ BOOL wm_is_kde(Display *display) return detect_wm(display) == WINE_WM_X11_KDE; } -BOOL wm_is_xfce4(Display *display) -{ - return detect_wm(display) == WINE_WM_X11_XFCE4; -} - BOOL wm_is_steamcompmgr(Display *display) { return detect_wm(display) == WINE_WM_X11_STEAMCOMPMGR; @@ -1287,12 +1280,9 @@ void update_net_wm_states( struct x11drv_win_data *data ) * Many games do not have any specific logic to get out of exclusive fullscreen * mode, and we have currently no way to tell exclusive fullscreen from a window * with topmost + fullscreen styles, so we cannot properly implement it either. - * - * XFCE doesn't make fullscreen (without above) windows appear above their panels. */ - (wm_is_xfce4(data->display) || !(new_state & (1 << NET_WM_STATE_FULLSCREEN)))) + !(new_state & (1 << NET_WM_STATE_FULLSCREEN))) new_state |= (1 << NET_WM_STATE_ABOVE); - if (!data->add_taskbar) { if (data->skip_taskbar || (ex_style & WS_EX_NOACTIVATE) diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index f556da495e9..96bedd7acab 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -347,7 +347,6 @@ extern void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT #define WINE_WM_X11_MUTTER 1 #define WINE_WM_X11_STEAMCOMPMGR 2 #define WINE_WM_X11_KDE 3 -#define WINE_WM_X11_XFCE4 4 static inline LONG_PTR __wine_get_window_manager(void) { From d61c1542f9fc687f1e0a2f24da564e5366f89b2f Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Wed, 3 Aug 2022 16:25:11 +1000 Subject: [PATCH 1627/2777] dmime: Store WAVE data when Loading. Wine-Staging: dmime-load-wave CW-Bug-Id: #22409 --- dlls/dmime/segment.c | 56 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index bf44c5e73b3..6bf9f3abf0c 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -33,6 +33,10 @@ typedef struct IDirectMusicSegment8Impl { DMUS_IO_SEGMENT_HEADER header; IDirectMusicGraph *pGraph; struct list Tracks; + + PCMWAVEFORMAT wave_format; + void *wave_data; + int data_size; } IDirectMusicSegment8Impl; IDirectMusicSegment8Impl *create_segment(void); @@ -86,6 +90,9 @@ static ULONG WINAPI IDirectMusicSegment8Impl_Release(IDirectMusicSegment8 *iface TRACE("(%p) ref=%ld\n", This, ref); if (!ref) { + if (This->wave_data) + free(This->wave_data); + HeapFree(GetProcessHeap(), 0, This); DMIME_UnlockModule(); } @@ -818,6 +825,49 @@ static inline IDirectMusicSegment8Impl *impl_from_IPersistStream(IPersistStream return CONTAINING_RECORD(iface, IDirectMusicSegment8Impl, dmobj.IPersistStream_iface); } +static HRESULT parse_wave_form(IDirectMusicSegment8Impl *This, IStream *stream, const struct chunk_entry *riff) +{ + HRESULT hr; + struct chunk_entry chunk = {.parent = riff}; + + TRACE("Parsing segment wave in %p: %s\n", stream, debugstr_chunk(riff)); + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { + switch (chunk.id) { + case mmioFOURCC('f','m','t',' '): { + if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &This->wave_format, chunk.size))) + return hr; + TRACE("Wave Format tag %d\n", This->wave_format.wf.wFormatTag); + break; + } + case mmioFOURCC('d','a','t','a'): { + TRACE("Wave Data size %lu\n", chunk.size); + This->wave_data = malloc(chunk.size); + This->data_size = chunk.size; + if (!This->wave_data) + return E_OUTOFMEMORY; + if (FAILED(hr = stream_chunk_get_data(stream, &chunk, This->wave_data, chunk.size))) + return hr; + break; + } + case FOURCC_LIST: { + FIXME("Skipping LIST tag\n"); + break; + } + case mmioFOURCC('I','S','F','T'): { + FIXME("Skipping ISFT tag\n"); + break; + } + case mmioFOURCC('f','a','c','t'): { + FIXME("Skipping fact tag\n"); + break; + } + } + } + + return S_OK; +} + static HRESULT WINAPI seg_IPersistStream_Load(IPersistStream *iface, IStream *stream) { IDirectMusicSegment8Impl *This = impl_from_IPersistStream(iface); @@ -847,10 +897,8 @@ static HRESULT WINAPI seg_IPersistStream_Load(IPersistStream *iface, IStream *st if (riff.type == DMUS_FOURCC_SEGMENT_FORM) hr = parse_segment_form(This, stream, &riff); - else { - FIXME("WAVE form loading not implemented\n"); - hr = S_OK; - } + else + hr = parse_wave_form(This, stream, &riff); return hr; } From 6024e7a04d17b72a269b6d6d8c2cf32c64b0880f Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Fri, 2 Dec 2022 14:41:30 +1100 Subject: [PATCH 1628/2777] dmime: Implement IDirectMusicSegment8 Download Wine-Staging: dmime-load-wave CW-Bug-Id: #22409 --- dlls/dmime/dmime_private.h | 2 + dlls/dmime/performance.c | 7 +++ dlls/dmime/segment.c | 87 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 93 insertions(+), 3 deletions(-) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 4159abffa99..030aab50094 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -71,6 +71,8 @@ extern void set_audiopath_perf_pointer(IDirectMusicAudioPath*,IDirectMusicPerfor extern void set_audiopath_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*) DECLSPEC_HIDDEN; extern void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*) DECLSPEC_HIDDEN; +extern IDirectSound *get_dsound_interface(IDirectMusicPerformance8*) DECLSPEC_HIDDEN; + /***************************************************************************** * Auxiliary definitions */ diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index d69a27540d6..5578c3e523b 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -252,6 +252,13 @@ static inline IDirectMusicPerformance8Impl *impl_from_IDirectMusicPerformance8(I return CONTAINING_RECORD(iface, IDirectMusicPerformance8Impl, IDirectMusicPerformance8_iface); } +IDirectSound *get_dsound_interface(IDirectMusicPerformance8* iface) +{ + IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + return This->dsound; +} + + /* IDirectMusicPerformance8 IUnknown part: */ static HRESULT WINAPI IDirectMusicPerformance8Impl_QueryInterface(IDirectMusicPerformance8 *iface, REFIID riid, void **ppv) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index 6bf9f3abf0c..0ea0c15c5e0 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -37,6 +37,7 @@ typedef struct IDirectMusicSegment8Impl { PCMWAVEFORMAT wave_format; void *wave_data; int data_size; + IDirectSoundBuffer *buffer; } IDirectMusicSegment8Impl; IDirectMusicSegment8Impl *create_segment(void); @@ -90,6 +91,8 @@ static ULONG WINAPI IDirectMusicSegment8Impl_Release(IDirectMusicSegment8 *iface TRACE("(%p) ref=%ld\n", This, ref); if (!ref) { + if (This->buffer) + IDirectSoundBuffer_Release(This->buffer); if (This->wave_data) free(This->wave_data); @@ -559,9 +562,87 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_Compose(IDirectMusicSegment8 *ifa static HRESULT WINAPI IDirectMusicSegment8Impl_Download(IDirectMusicSegment8 *iface, IUnknown *pAudioPath) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %p): stub\n", This, pAudioPath); - return S_OK; + IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + IDirectMusicPerformance8 *perf; + IDirectMusicAudioPath *audio; + IDirectSound *dsound; + HRESULT hr; + DSBUFFERDESC dsbd = {.dwSize = sizeof(dsbd)}; + void *data; + DWORD size; + DWORD buffer = 0; + + TRACE("(%p, %p)\n", This, pAudioPath); + + if (!pAudioPath) + return E_INVALIDARG; + + if (This->buffer) + { + TRACE("Using Cached buffer\n"); + return S_OK; + } + + /* pAudioPath can either be IDirectMusicAudioPath or IDirectMusicPerformance */ + hr = IUnknown_QueryInterface(pAudioPath, &IID_IDirectMusicPerformance8, (void**)&perf); + if (FAILED(hr)) + { + TRACE("Checking for IDirectMusicAudioPath interface\n"); + hr = IUnknown_QueryInterface(pAudioPath, &IID_IDirectMusicAudioPath, (void**)&audio); + if (FAILED(hr)) + { + WARN("Cannot query for IDirectMusicAudioPath\n"); + return E_INVALIDARG; + } + + IDirectMusicAudioPath_GetObjectInPath(audio, DMUS_PCHANNEL_ALL, DMUS_PATH_PERFORMANCE, buffer, &GUID_NULL, + 0, &IID_IDirectMusicPerformance, (void**)&perf); + IDirectMusicAudioPath_Release(audio); + } + + if (!perf) + { + ERR("Failed to get IDirectMusicPerformance interface\n"); + return E_INVALIDARG; + } + + dsound = get_dsound_interface(perf); + if (!dsound) + { + ERR("Failed get_dsound_interface\n"); + return E_INVALIDARG; + } + + if (This->data_size == 0) + { + FIXME("No wave data skipping\n"); + return S_OK; + } + + dsbd.dwBufferBytes = This->data_size; + dsbd.lpwfxFormat = (WAVEFORMATEX*)&This->wave_format; + + hr = IDirectSound_CreateSoundBuffer(dsound, &dsbd, &This->buffer, NULL); + if (FAILED(hr)) + { + ERR("IDirectSound_CreateSoundBuffer failed 0x%08lx\n", hr); + return E_INVALIDARG; + } + + TRACE("CreateSoundBuffer successful\n"); + + hr = IDirectSoundBuffer_Lock(This->buffer, 0, This->data_size, &data, &size, NULL, 0, 0); + TRACE("IDirectSoundBuffer_Lock hr 0x%08lx\n", hr); + + memcpy(data, This->wave_data, This->data_size); + + hr = IDirectSoundBuffer_Unlock(This->buffer, data, This->data_size, NULL, 0); + TRACE("IDirectSoundBuffer_Unlock hr 0x%08lx\n", hr); + + /*hr = IDirectSoundBuffer_Play(This->buffer, 0, 0, 0); + TRACE("IDirectSoundBuffer_Play hr 0x%08lx\n", hr);*/ + + return S_OK; } static HRESULT WINAPI IDirectMusicSegment8Impl_Unload(IDirectMusicSegment8 *iface, From 6a6da862c22772f90adb2cca67b2677aa08f7ce4 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Mon, 12 Dec 2022 15:20:10 +1100 Subject: [PATCH 1629/2777] dmime: Play a sound in IDirectMusicPerformance8 PlaySegmentEx Wine-Staging: dmime-load-wave CW-Bug-Id: #22409 --- dlls/dmime/dmime_private.h | 1 + dlls/dmime/performance.c | 25 +++++++++++++++++++------ dlls/dmime/segment.c | 6 ++++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 030aab50094..d09aba02a5c 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -72,6 +72,7 @@ extern void set_audiopath_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffe extern void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*) DECLSPEC_HIDDEN; extern IDirectSound *get_dsound_interface(IDirectMusicPerformance8*) DECLSPEC_HIDDEN; +extern IDirectSoundBuffer *get_segment_buffer(IDirectMusicSegment8 *iface) DECLSPEC_HIDDEN; /***************************************************************************** * Auxiliary definitions diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 5578c3e523b..03e59e95af3 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1043,13 +1043,26 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_PlaySegmentEx(IDirectMusicPer __int64 i64StartTime, IDirectMusicSegmentState **ppSegmentState, IUnknown *pFrom, IUnknown *pAudioPath) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + IDirectMusicSegment8 *segment; + IDirectSoundBuffer *buffer; + HRESULT hr; - FIXME("(%p, %p, %p, %p, %ld, 0x%s, %p, %p, %p): stub\n", This, pSource, pwzSegmentName, - pTransition, dwFlags, wine_dbgstr_longlong(i64StartTime), ppSegmentState, pFrom, pAudioPath); - if (ppSegmentState) - return create_dmsegmentstate(&IID_IDirectMusicSegmentState,(void**)ppSegmentState); - return S_OK; + FIXME("(%p, %p, %p, %p, %ld, 0x%s, %p, %p, %p): semi-stub\n", This, pSource, pwzSegmentName, + pTransition, dwFlags, wine_dbgstr_longlong(i64StartTime), ppSegmentState, pFrom, pAudioPath); + + hr = IUnknown_QueryInterface(pSource, &IID_IDirectMusicSegment8, (void**)&segment); + if (FAILED(hr)) + return hr; + + buffer = get_segment_buffer(segment); + + if (segment) + hr = IDirectSoundBuffer_Play(buffer, 0, 0, 0); + + if (ppSegmentState) + return create_dmsegmentstate(&IID_IDirectMusicSegmentState,(void**)ppSegmentState); + return S_OK; } static HRESULT WINAPI IDirectMusicPerformance8Impl_StopEx(IDirectMusicPerformance8 *iface, diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index 0ea0c15c5e0..b21f93bbfc6 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -47,6 +47,12 @@ static inline IDirectMusicSegment8Impl *impl_from_IDirectMusicSegment8(IDirectMu return CONTAINING_RECORD(iface, IDirectMusicSegment8Impl, IDirectMusicSegment8_iface); } +IDirectSoundBuffer *get_segment_buffer(IDirectMusicSegment8 *iface) +{ + IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + return This->buffer; +} + static HRESULT WINAPI IDirectMusicSegment8Impl_QueryInterface(IDirectMusicSegment8 *iface, REFIID riid, void **ret_iface) { From 66cd5c1c1f1cae4c76e74c5e82d7b4f1fa4d7550 Mon Sep 17 00:00:00 2001 From: Matteo Bruni Date: Tue, 12 Sep 2023 12:06:15 +0200 Subject: [PATCH 1630/2777] kernelbase: HACK: Add --use-gl=swiftshader for Everquest F2P/LaunchPad.exe. CW-Bug-Id: #18509 --- dlls/kernelbase/process.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 0df1b479809..7afd5f3a38e 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -593,6 +593,7 @@ static const WCHAR *hack_append_command_line( const WCHAR *cmd ) {L"PlanetSide 2\\LaunchPad.exe", L" --use-gl=swiftshader"}, {L"PaladinLias\\Game.exe", L" --use-gl=desktop"}, {L"EverQuest 2\\LaunchPad.exe", L" --use-gl=swiftshader"}, + {L"Everquest F2P\\LaunchPad.exe", L" --use-gl=swiftshader"}, }; unsigned int i; From 7e28f9fed8a519d1c4e2950c7e6b6e97898d498a Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Wed, 13 Sep 2023 19:08:50 +0300 Subject: [PATCH 1631/2777] dsound: Get rid of DSOUND_capturers and related lock. Ever since dcaeb6b4fdf8 ("dsound: Allow multiple buffers to capture from the same device.") it's not used for anything. (cherry picked from commit 0b7b6d10506aa4c97f6e25ef7e3577cdd5221f3f) CW-Bug-Id: #22502 --- dlls/dsound/capture.c | 12 ------------ dlls/dsound/dsound_main.c | 11 ----------- dlls/dsound/dsound_private.h | 2 -- 3 files changed, 25 deletions(-) diff --git a/dlls/dsound/capture.c b/dlls/dsound/capture.c index 6ddae8286cd..a2b866f29c3 100644 --- a/dlls/dsound/capture.c +++ b/dlls/dsound/capture.c @@ -859,10 +859,6 @@ static ULONG DirectSoundCaptureDevice_Release( if (!ref) { TRACE("deleting object\n"); - EnterCriticalSection(&DSOUND_capturers_lock); - list_remove(&device->entry); - LeaveCriticalSection(&DSOUND_capturers_lock); - if (device->capture_buffer) IDirectSoundCaptureBufferImpl_Release(&device->capture_buffer->IDirectSoundCaptureBuffer8_iface); @@ -1038,12 +1034,9 @@ static HRESULT DirectSoundCaptureDevice_Initialize( if(FAILED(hr)) return hr; - EnterCriticalSection(&DSOUND_capturers_lock); - hr = DirectSoundCaptureDevice_Create(&device); if (hr != DS_OK) { WARN("DirectSoundCaptureDevice_Create failed\n"); - LeaveCriticalSection(&DSOUND_capturers_lock); return hr; } @@ -1061,7 +1054,6 @@ static HRESULT DirectSoundCaptureDevice_Initialize( device->lock.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&device->lock); HeapFree(GetProcessHeap(), 0, device); - LeaveCriticalSection(&DSOUND_capturers_lock); return DSERR_NODRIVER; } @@ -1074,12 +1066,8 @@ static HRESULT DirectSoundCaptureDevice_Initialize( } IAudioClient_Release(client); - list_add_tail(&DSOUND_capturers, &device->entry); - *ppDevice = device; - LeaveCriticalSection(&DSOUND_capturers_lock); - return S_OK; } diff --git a/dlls/dsound/dsound_main.c b/dlls/dsound/dsound_main.c index 69cbec72ea3..3347f0243ab 100644 --- a/dlls/dsound/dsound_main.c +++ b/dlls/dsound/dsound_main.c @@ -76,16 +76,6 @@ static CRITICAL_SECTION_DEBUG DSOUND_renderers_lock_debug = }; CRITICAL_SECTION DSOUND_renderers_lock = { &DSOUND_renderers_lock_debug, -1, 0, 0, 0, 0 }; -struct list DSOUND_capturers = LIST_INIT(DSOUND_capturers); -CRITICAL_SECTION DSOUND_capturers_lock; -static CRITICAL_SECTION_DEBUG DSOUND_capturers_lock_debug = -{ - 0, 0, &DSOUND_capturers_lock, - { &DSOUND_capturers_lock_debug.ProcessLocksList, &DSOUND_capturers_lock_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": DSOUND_capturers_lock") } -}; -CRITICAL_SECTION DSOUND_capturers_lock = { &DSOUND_capturers_lock_debug, -1, 0, 0, 0, 0 }; - GUID DSOUND_renderer_guids[MAXWAVEDRIVERS]; GUID DSOUND_capture_guids[MAXWAVEDRIVERS]; @@ -782,7 +772,6 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved) case DLL_PROCESS_DETACH: if (lpvReserved) break; DeleteCriticalSection(&DSOUND_renderers_lock); - DeleteCriticalSection(&DSOUND_capturers_lock); break; } return TRUE; diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index c39d9ec40ea..09fa219ecca 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -252,8 +252,6 @@ HRESULT IDirectSoundCaptureImpl_Create(IUnknown *outer_unk, REFIID riid, void ** #define STATE_STOPPING 3 extern CRITICAL_SECTION DSOUND_renderers_lock DECLSPEC_HIDDEN; -extern CRITICAL_SECTION DSOUND_capturers_lock DECLSPEC_HIDDEN; -extern struct list DSOUND_capturers DECLSPEC_HIDDEN; extern struct list DSOUND_renderers DECLSPEC_HIDDEN; extern GUID DSOUND_renderer_guids[MAXWAVEDRIVERS] DECLSPEC_HIDDEN; From 39b8fe1a353b715c1d580fe0334257846a744005 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Fri, 15 Sep 2023 00:16:47 +0300 Subject: [PATCH 1632/2777] dsound: Get rid of the global device GUID arrays. They are not used for anything anymore and just impose limit of 10 devices of a given type (capturer / renderer) without doing bound checking. (cherry picked from commit e1f0318ec4fe83fdc86407303d55f4ee5ba3d2e7) CW-Bug-Id: #22502 --- dlls/dsound/dsound_main.c | 31 +++++++++++-------------------- dlls/dsound/dsound_private.h | 5 +---- dlls/dsound/propset.c | 12 ++++-------- 3 files changed, 16 insertions(+), 32 deletions(-) diff --git a/dlls/dsound/dsound_main.c b/dlls/dsound/dsound_main.c index 3347f0243ab..d18733294d0 100644 --- a/dlls/dsound/dsound_main.c +++ b/dlls/dsound/dsound_main.c @@ -76,9 +76,6 @@ static CRITICAL_SECTION_DEBUG DSOUND_renderers_lock_debug = }; CRITICAL_SECTION DSOUND_renderers_lock = { &DSOUND_renderers_lock_debug, -1, 0, 0, 0, 0 }; -GUID DSOUND_renderer_guids[MAXWAVEDRIVERS]; -GUID DSOUND_capture_guids[MAXWAVEDRIVERS]; - const WCHAR wine_vxd_drv[] = L"winemm.vxd"; /* All default settings, you most likely don't want to touch these, see wiki on UsefulRegistryKeys */ @@ -391,13 +388,13 @@ HRESULT get_mmdevice(EDataFlow flow, const GUID *tgt, IMMDevice **device) return DSERR_INVALIDPARAM; } -static BOOL send_device(IMMDevice *device, GUID *guid, - LPDSENUMCALLBACKW cb, void *user) +static BOOL send_device(IMMDevice *device, LPDSENUMCALLBACKW cb, void *user) { IPropertyStore *ps; PROPVARIANT pv; BOOL keep_going; HRESULT hr; + GUID guid; PropVariantInit(&pv); @@ -407,7 +404,7 @@ static BOOL send_device(IMMDevice *device, GUID *guid, return TRUE; } - hr = get_mmdevice_guid(device, ps, guid); + hr = get_mmdevice_guid(device, ps, &guid); if(FAILED(hr)){ IPropertyStore_Release(ps); return TRUE; @@ -421,10 +418,10 @@ static BOOL send_device(IMMDevice *device, GUID *guid, return TRUE; } - TRACE("Calling back with %s (%s)\n", wine_dbgstr_guid(guid), + TRACE("Calling back with %s (%s)\n", wine_dbgstr_guid(&guid), wine_dbgstr_w(pv.pwszVal)); - keep_going = cb(guid, pv.pwszVal, wine_vxd_drv, user); + keep_going = cb(&guid, pv.pwszVal, wine_vxd_drv, user); PropVariantClear(&pv); IPropertyStore_Release(ps); @@ -434,13 +431,12 @@ static BOOL send_device(IMMDevice *device, GUID *guid, /* S_FALSE means the callback returned FALSE at some point * S_OK means the callback always returned TRUE */ -HRESULT enumerate_mmdevices(EDataFlow flow, GUID *guids, - LPDSENUMCALLBACKW cb, void *user) +HRESULT enumerate_mmdevices(EDataFlow flow, LPDSENUMCALLBACKW cb, void *user) { IMMDeviceEnumerator *devenum; IMMDeviceCollection *coll; IMMDevice *defdev = NULL; - UINT count, i, n; + UINT count, i; BOOL keep_going; HRESULT hr, init_hr; @@ -479,10 +475,8 @@ HRESULT enumerate_mmdevices(EDataFlow flow, GUID *guids, eMultimedia, &defdev); if(FAILED(hr)){ defdev = NULL; - n = 0; }else{ - keep_going = send_device(defdev, &guids[0], cb, user); - n = 1; + keep_going = send_device(defdev, cb, user); } } @@ -496,8 +490,7 @@ HRESULT enumerate_mmdevices(EDataFlow flow, GUID *guids, } if(device != defdev){ - keep_going = send_device(device, &guids[n], cb, user); - ++n; + keep_going = send_device(device, cb, user); } IMMDevice_Release(device); @@ -540,8 +533,7 @@ HRESULT WINAPI DirectSoundEnumerateW( setup_dsound_options(); - hr = enumerate_mmdevices(eRender, DSOUND_renderer_guids, - lpDSEnumCallback, lpContext); + hr = enumerate_mmdevices(eRender, lpDSEnumCallback, lpContext); return SUCCEEDED(hr) ? DS_OK : hr; } @@ -604,8 +596,7 @@ DirectSoundCaptureEnumerateW( setup_dsound_options(); - hr = enumerate_mmdevices(eCapture, DSOUND_capture_guids, - lpDSEnumCallback, lpContext); + hr = enumerate_mmdevices(eCapture, lpDSEnumCallback, lpContext); return SUCCEEDED(hr) ? DS_OK : hr; } diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index 09fa219ecca..081a56b2ee7 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -254,8 +254,6 @@ HRESULT IDirectSoundCaptureImpl_Create(IUnknown *outer_unk, REFIID riid, void ** extern CRITICAL_SECTION DSOUND_renderers_lock DECLSPEC_HIDDEN; extern struct list DSOUND_renderers DECLSPEC_HIDDEN; -extern GUID DSOUND_renderer_guids[MAXWAVEDRIVERS] DECLSPEC_HIDDEN; -extern GUID DSOUND_capture_guids[MAXWAVEDRIVERS] DECLSPEC_HIDDEN; extern const WCHAR wine_vxd_drv[] DECLSPEC_HIDDEN; @@ -265,8 +263,7 @@ HRESULT get_mmdevice(EDataFlow flow, const GUID *tgt, IMMDevice **device) DECLSP BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate, DWORD depth, WORD channels) DECLSPEC_HIDDEN; -HRESULT enumerate_mmdevices(EDataFlow flow, GUID *guids, - LPDSENUMCALLBACKW cb, void *user) DECLSPEC_HIDDEN; +HRESULT enumerate_mmdevices(EDataFlow flow, LPDSENUMCALLBACKW cb, void *user) DECLSPEC_HIDDEN; static inline WCHAR *strdupW( const WCHAR *str ) { diff --git a/dlls/dsound/propset.c b/dlls/dsound/propset.c index f42cfbf4163..e72757bdb4b 100644 --- a/dlls/dsound/propset.c +++ b/dlls/dsound/propset.c @@ -136,11 +136,9 @@ static HRESULT DSPROPERTY_WaveDeviceMappingW( search.found_guid = &ppd->DeviceId; if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER) - hr = enumerate_mmdevices(eRender, DSOUND_renderer_guids, - search_callback, &search); + hr = enumerate_mmdevices(eRender, search_callback, &search); else if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE) - hr = enumerate_mmdevices(eCapture, DSOUND_capture_guids, - search_callback, &search); + hr = enumerate_mmdevices(eCapture, search_callback, &search); else return DSERR_INVALIDPARAM; @@ -318,12 +316,10 @@ static HRESULT DSPROPERTY_EnumerateW( return E_PROP_ID_UNSUPPORTED; } - hr = enumerate_mmdevices(eRender, DSOUND_renderer_guids, - enum_callback, ppd); + hr = enumerate_mmdevices(eRender, enum_callback, ppd); if(hr == S_OK) - hr = enumerate_mmdevices(eCapture, DSOUND_capture_guids, - enum_callback, ppd); + hr = enumerate_mmdevices(eCapture, enum_callback, ppd); return SUCCEEDED(hr) ? DS_OK : hr; } From 0392d2d99d4842519a6790dac0c00cc62bbc551a Mon Sep 17 00:00:00 2001 From: Mohamad Al-Jaf Date: Thu, 2 Feb 2023 22:06:57 -0500 Subject: [PATCH 1633/2777] cfgmgr32: Implement CM_MapCrToWin32Err. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53781 (cherry picked from commit 4fab9ff230f497499da223ade9bbe3633a657f05) Link: https://github.com/ValveSoftware/Proton/issues/6510#issuecomment-1546121761 Helps with Hogwarts Legacy and Unreal Engine 5.1 on ANV. --- dlls/cfgmgr32/Makefile.in | 3 ++ dlls/cfgmgr32/cfgmgr32.spec | 1 + dlls/cfgmgr32/main.c | 58 +++++++++++++++++++++++++++++++++++++ include/cfgmgr32.h | 1 + 4 files changed, 63 insertions(+) create mode 100644 dlls/cfgmgr32/main.c diff --git a/dlls/cfgmgr32/Makefile.in b/dlls/cfgmgr32/Makefile.in index 10621fa5dc7..f05b3176aa3 100644 --- a/dlls/cfgmgr32/Makefile.in +++ b/dlls/cfgmgr32/Makefile.in @@ -1,3 +1,6 @@ MODULE = cfgmgr32.dll IMPORTLIB = cfgmgr32 IMPORTS = setupapi + +C_SRCS = \ + main.c diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec index 69ec784de68..3b4f6106618 100644 --- a/dlls/cfgmgr32/cfgmgr32.spec +++ b/dlls/cfgmgr32/cfgmgr32.spec @@ -126,6 +126,7 @@ @ stdcall CM_Locate_DevNodeW(ptr wstr long) setupapi.CM_Locate_DevNodeW @ stdcall CM_Locate_DevNode_ExA(ptr str long long) setupapi.CM_Locate_DevNode_ExA @ stdcall CM_Locate_DevNode_ExW(ptr wstr long long) setupapi.CM_Locate_DevNode_ExW +@ stdcall CM_MapCrToWin32Err(long long) @ stub CM_Merge_Range_List @ stub CM_Modify_Res_Des @ stub CM_Modify_Res_Des_Ex diff --git a/dlls/cfgmgr32/main.c b/dlls/cfgmgr32/main.c new file mode 100644 index 00000000000..fee3c42a5c4 --- /dev/null +++ b/dlls/cfgmgr32/main.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2023 Mohamad Al-Jaf + * + * 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 + */ + +#include "wine/debug.h" +#include "cfgmgr32.h" + +WINE_DEFAULT_DEBUG_CHANNEL(setupapi); + +/*********************************************************************** + * CM_MapCrToWin32Err (cfgmgr32.@) + */ +DWORD WINAPI CM_MapCrToWin32Err( CONFIGRET code, DWORD default_error ) +{ + TRACE( "code: %#lx, default_error: %ld\n", code, default_error ); + + switch (code) + { + case CR_SUCCESS: return ERROR_SUCCESS; + case CR_OUT_OF_MEMORY: return ERROR_NOT_ENOUGH_MEMORY; + case CR_INVALID_POINTER: return ERROR_INVALID_USER_BUFFER; + case CR_INVALID_FLAG: return ERROR_INVALID_FLAGS; + case CR_INVALID_DEVNODE: + case CR_INVALID_DEVICE_ID: + case CR_INVALID_MACHINENAME: + case CR_INVALID_PROPERTY: + case CR_INVALID_REFERENCE_STRING: return ERROR_INVALID_DATA; + case CR_NO_SUCH_DEVNODE: + case CR_NO_SUCH_VALUE: + case CR_NO_SUCH_DEVICE_INTERFACE: return ERROR_NOT_FOUND; + case CR_ALREADY_SUCH_DEVNODE: return ERROR_ALREADY_EXISTS; + case CR_BUFFER_SMALL: return ERROR_INSUFFICIENT_BUFFER; + case CR_NO_REGISTRY_HANDLE: return ERROR_INVALID_HANDLE; + case CR_REGISTRY_ERROR: return ERROR_REGISTRY_CORRUPT; + case CR_NO_SUCH_REGISTRY_KEY: return ERROR_FILE_NOT_FOUND; + case CR_REMOTE_COMM_FAILURE: + case CR_MACHINE_UNAVAILABLE: + case CR_NO_CM_SERVICES: return ERROR_SERVICE_NOT_ACTIVE; + case CR_ACCESS_DENIED: return ERROR_ACCESS_DENIED; + case CR_CALL_NOT_IMPLEMENTED: return ERROR_CALL_NOT_IMPLEMENTED; + } + + return default_error; +} diff --git a/include/cfgmgr32.h b/include/cfgmgr32.h index bff32fe1c08..04f1f80b174 100644 --- a/include/cfgmgr32.h +++ b/include/cfgmgr32.h @@ -246,6 +246,7 @@ CMAPI WORD WINAPI CM_Get_Version(void); CMAPI CONFIGRET WINAPI CM_Locate_DevNodeA(PDEVINST,DEVINSTID_A,ULONG); CMAPI CONFIGRET WINAPI CM_Locate_DevNodeW(PDEVINST,DEVINSTID_W,ULONG); #define CM_Locate_DevNode WINELIB_NAME_AW(CM_Locate_DevNode) +CMAPI DWORD WINAPI CM_MapCrToWin32Err(CONFIGRET,DWORD); CMAPI CONFIGRET WINAPI CM_Open_DevNode_Key(DEVINST dnDevInst, REGSAM access, ULONG ulHardwareProfile, REGDISPOSITION disposition, PHKEY phkDevice, ULONG ulFlags); CMAPI CONFIGRET WINAPI CM_Request_Device_EjectA(DEVINST dev, PPNP_VETO_TYPE type, LPSTR name, ULONG length, ULONG flags); From caf2f5368d294707d912339b9466e20c0ec1972e Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Thu, 21 Sep 2023 23:34:50 +0300 Subject: [PATCH 1634/2777] fixup! winegstreamer: Set n-threads for dav1d to 1. --- dlls/winegstreamer/wg_parser.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index d12c4c2dad1..681ef4abfa7 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -588,10 +588,16 @@ static void no_more_pads_cb(GstElement *element, gpointer user) static void deep_element_added_cb(GstBin *self, GstBin *sub_bin, GstElement *element, gpointer user) { - GstElementFactory *factory = gst_element_get_factory(element); - const char *name = gst_element_factory_get_longname(factory); + GstElementFactory *factory = NULL; + const char *name = NULL; - if (strstr(name, "Dav1d")) + if (element) + factory = gst_element_get_factory(element); + + if (factory) + name = gst_element_factory_get_longname(factory); + + if (name && strstr(name, "Dav1d")) { #if defined(__x86_64__) GST_DEBUG("%s found, setting n-threads to 4.", name); From 838a3bb7e45e43495eae1af707c228061ea88632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Sun, 4 Dec 2022 00:03:50 +0100 Subject: [PATCH 1635/2777] mfmediaengine: Add support for inserting audio effects. --- dlls/mfmediaengine/main.c | 57 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 4f99513e938..d9b3bd19547 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -16,6 +16,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "winerror.h" #define COBJMACROS #include @@ -146,6 +147,11 @@ struct media_engine IMFPresentationDescriptor *pd; } presentation; struct + { + IUnknown *audio; + BOOL audio_optional; + } effects; + struct { LONGLONG pts; SIZE size; @@ -999,6 +1005,27 @@ static HRESULT media_engine_create_source_node(IMFMediaSource *source, IMFPresen return S_OK; } +static HRESULT media_engine_create_audio_effect(struct media_engine *engine, IMFTopologyNode **node) +{ + HRESULT hr; + + *node = NULL; + + if (!engine->effects.audio) + return S_OK; + + if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, node))) + return hr; + + IMFTopologyNode_SetObject(*node, (IUnknown *)engine->effects.audio); + IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE); + + IUnknown_Release(engine->effects.audio); + engine->effects.audio = NULL; + + return hr; +} + static HRESULT media_engine_create_audio_renderer(struct media_engine *engine, IMFTopologyNode **node) { unsigned int category, role; @@ -1169,7 +1196,7 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi if (SUCCEEDED(hr = MFCreateTopology(&topology))) { - IMFTopologyNode *sar_node = NULL, *audio_src = NULL; + IMFTopologyNode *sar_node = NULL, *audio_src = NULL, *audio_effect = NULL; IMFTopologyNode *grabber_node = NULL, *video_src = NULL; if (engine->flags & MF_MEDIA_ENGINE_REAL_TIME_MODE) @@ -1183,7 +1210,18 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi if (FAILED(hr = media_engine_create_audio_renderer(engine, &sar_node))) WARN("Failed to create audio renderer node, hr %#lx.\n", hr); - if (sar_node && audio_src) + if (FAILED(media_engine_create_audio_effect(engine, &audio_effect))) + WARN("Failed to create audio effect node, hr %#lx.\n", hr); + + if (sar_node && audio_src && audio_effect) + { + IMFTopology_AddNode(topology, audio_src); + IMFTopology_AddNode(topology, sar_node); + IMFTopology_AddNode(topology, audio_effect); + IMFTopologyNode_ConnectOutput(audio_src, 0, audio_effect, 0); + IMFTopologyNode_ConnectOutput(audio_effect, 0, sar_node, 0); + } + else if (sar_node && audio_src) { IMFTopology_AddNode(topology, audio_src); IMFTopology_AddNode(topology, sar_node); @@ -1192,6 +1230,8 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi if (sar_node) IMFTopologyNode_Release(sar_node); + if (audio_effect) + IMFTopologyNode_Release(audio_effect); if (audio_src) IMFTopologyNode_Release(audio_src); } @@ -2566,9 +2606,20 @@ static HRESULT WINAPI media_engine_InsertVideoEffect(IMFMediaEngineEx *iface, IU static HRESULT WINAPI media_engine_InsertAudioEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional) { + struct media_engine *impl = impl_from_IMFMediaEngineEx(iface); FIXME("%p, %p, %d stub.\n", iface, effect, is_optional); - return E_NOTIMPL; + if (!effect) + return E_POINTER; + + if (impl->effects.audio) + return MF_E_INVALIDREQUEST; + + impl->effects.audio = effect; + IUnknown_AddRef(impl->effects.audio); + impl->effects.audio_optional = is_optional; + + return S_OK; } static HRESULT WINAPI media_engine_RemoveAllEffects(IMFMediaEngineEx *iface) From d5f2dce70ec961066467e93e25adf0eef978dc56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Mon, 5 Dec 2022 23:46:20 +0100 Subject: [PATCH 1636/2777] mfmediaengine: Add support for inserting video effects. --- dlls/mfmediaengine/main.c | 51 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index d9b3bd19547..1d5b4a923ed 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -150,6 +150,8 @@ struct media_engine { IUnknown *audio; BOOL audio_optional; + IUnknown *video; + BOOL video_optional; } effects; struct { @@ -1026,6 +1028,27 @@ static HRESULT media_engine_create_audio_effect(struct media_engine *engine, IMF return hr; } +static HRESULT media_engine_create_video_effect(struct media_engine *engine, IMFTopologyNode **node) +{ + HRESULT hr; + + *node = NULL; + + if (!engine->effects.video) + return S_OK; + + if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, node))) + return hr; + + IMFTopologyNode_SetObject(*node, (IUnknown *)engine->effects.video); + IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE); + + IUnknown_Release(engine->effects.video); + engine->effects.video = NULL; + + return hr; +} + static HRESULT media_engine_create_audio_renderer(struct media_engine *engine, IMFTopologyNode **node) { unsigned int category, role; @@ -1197,7 +1220,7 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi if (SUCCEEDED(hr = MFCreateTopology(&topology))) { IMFTopologyNode *sar_node = NULL, *audio_src = NULL, *audio_effect = NULL; - IMFTopologyNode *grabber_node = NULL, *video_src = NULL; + IMFTopologyNode *grabber_node = NULL, *video_src = NULL, *video_effect = NULL; if (engine->flags & MF_MEDIA_ENGINE_REAL_TIME_MODE) IMFTopology_SetUINT32(topology, &MF_LOW_LATENCY, TRUE); @@ -1244,7 +1267,18 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi if (FAILED(hr = media_engine_create_video_renderer(engine, &grabber_node))) WARN("Failed to create video grabber node, hr %#lx.\n", hr); - if (grabber_node && video_src) + if (FAILED(media_engine_create_video_effect(engine, &video_effect))) + WARN("Failed to create video effect node, hr %#lx.\n", hr); + + if (grabber_node && video_src && video_effect) + { + IMFTopology_AddNode(topology, video_src); + IMFTopology_AddNode(topology, grabber_node); + IMFTopology_AddNode(topology, video_effect); + IMFTopologyNode_ConnectOutput(video_src, 0, video_effect, 0); + IMFTopologyNode_ConnectOutput(video_effect, 0, grabber_node, 0); + } + else if (grabber_node && video_src) { IMFTopology_AddNode(topology, video_src); IMFTopology_AddNode(topology, grabber_node); @@ -2599,9 +2633,20 @@ static HRESULT WINAPI media_engine_IsProtected(IMFMediaEngineEx *iface, BOOL *pr static HRESULT WINAPI media_engine_InsertVideoEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional) { + struct media_engine *impl = impl_from_IMFMediaEngineEx(iface); FIXME("%p, %p, %d stub.\n", iface, effect, is_optional); - return E_NOTIMPL; + if (!effect) + return E_POINTER; + + if (impl->effects.video) + return MF_E_INVALIDREQUEST; + + impl->effects.video = effect; + IUnknown_AddRef(impl->effects.video); + impl->effects.video_optional = is_optional; + + return S_OK; } static HRESULT WINAPI media_engine_InsertAudioEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional) From 2905cce13c034b8a8672d874a9e80a09bf110eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Mon, 13 Mar 2023 21:28:03 +0100 Subject: [PATCH 1637/2777] mfmediaengine: Return S_OK in SetBalance(). --- dlls/mfmediaengine/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 1d5b4a923ed..e065080fdfa 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -2517,7 +2517,7 @@ static HRESULT WINAPI media_engine_SetBalance(IMFMediaEngineEx *iface, double ba { FIXME("%p, %f stub.\n", iface, balance); - return E_NOTIMPL; + return S_OK; } static BOOL WINAPI media_engine_IsPlaybackRateSupported(IMFMediaEngineEx *iface, double rate) From f6b13077ad5a9c0a4696e159f64aa40d04fb1d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Mon, 13 Mar 2023 21:28:24 +0100 Subject: [PATCH 1638/2777] Revert "Revert "mfmediaengine: Pass volume changes to media session."" This reverts commit 602e0ee8b30b32279dcc349c538401267e7acce8. --- dlls/mfmediaengine/main.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index e065080fdfa..837aaaae106 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -843,6 +843,23 @@ static void media_engine_get_frame_size(struct media_engine *engine, IMFTopology IMFMediaType_Release(media_type); } +static void media_engine_apply_volume(const struct media_engine *engine) +{ + IMFSimpleAudioVolume *sa_volume; + HRESULT hr; + + if (!engine->session) + return; + + if (FAILED(MFGetService((IUnknown *)engine->session, &MR_POLICY_VOLUME_SERVICE, &IID_IMFSimpleAudioVolume, (void **)&sa_volume))) + return; + + if (FAILED(hr = IMFSimpleAudioVolume_SetMasterVolume(sa_volume, engine->volume))) + WARN("Failed to set master volume, hr %#lx.\n", hr); + + IMFSimpleAudioVolume_Release(sa_volume); +} + static HRESULT WINAPI media_engine_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IMFAsyncCallback) || @@ -926,6 +943,8 @@ static HRESULT WINAPI media_engine_session_events_Invoke(IMFAsyncCallback *iface EnterCriticalSection(&engine->cs); + media_engine_apply_volume(engine); + engine->ready_state = MF_MEDIA_ENGINE_READY_HAVE_METADATA; media_engine_get_frame_size(engine, topology); @@ -2086,6 +2105,7 @@ static HRESULT WINAPI media_engine_SetVolume(IMFMediaEngineEx *iface, double vol else if (volume != engine->volume) { engine->volume = volume; + media_engine_apply_volume(engine); IMFMediaEngineNotify_EventNotify(engine->callback, MF_MEDIA_ENGINE_EVENT_VOLUMECHANGE, 0, 0); } LeaveCriticalSection(&engine->cs); From 984963b127f42cb02763c82987a9b66ec298c4cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Mon, 13 Mar 2023 21:58:34 +0100 Subject: [PATCH 1639/2777] mf: Don't try to clone non existent topo connections. --- dlls/mf/topology.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c index 25a00708100..11ddf573f06 100644 --- a/dlls/mf/topology.c +++ b/dlls/mf/topology.c @@ -712,7 +712,11 @@ static HRESULT WINAPI topology_CloneFrom(IMFTopology *iface, IMFTopology *src) for (j = 0; j < outputs->count; ++j) { DWORD input_index = outputs->streams[j].connection_stream; - TOPOID id = outputs->streams[j].connection->id; + TOPOID id; + + if (!outputs->streams[j].connection) + continue; + id = outputs->streams[j].connection->id; /* Skip node lookup in destination topology, assuming same node order. */ if (SUCCEEDED(hr = topology_get_node_by_id(topology, id, &node))) From e0aca0f9120517cc8f37d612fa1a6866245130f5 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 4 May 2023 13:33:48 -0600 Subject: [PATCH 1640/2777] ntdll: HACK: Add WINE_RAM_REPORTING_BIAS option. CW-Bug-Id: #22241 --- dlls/ntdll/unix/loader.c | 6 ++++++ dlls/ntdll/unix/system.c | 8 ++++++++ dlls/ntdll/unix/unix_private.h | 1 + dlls/ntdll/unix/virtual.c | 1 + 4 files changed, 16 insertions(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 9dc11f74fb2..3e4790249f8 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2284,12 +2284,18 @@ BOOL localsystem_sid; BOOL high_dll_addresses; BOOL simulate_writecopy; SIZE_T kernel_stack_size = 0x100000; +long long ram_reporting_bias; static void hacks_init(void) { static const char upc_exe[] = "Ubisoft Game Launcher\\upc.exe"; const char *env_str, *sgi; + if ((env_str = getenv("WINE_RAM_REPORTING_BIAS"))) + { + ram_reporting_bias = atoll(env_str) * 1024 * 1024; + ERR( "HACK: ram_reporting_bias %lldMB.\n", ram_reporting_bias / (1024 * 1024) ); + } env_str = getenv("WINE_SIMULATE_ASYNC_READ"); if (env_str) diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index 16fde91ea7c..76a47f1932a 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -2042,7 +2042,15 @@ static void get_performance_info( SYSTEM_PERFORMANCE_INFORMATION *info ) mem_available = value * 1024; } fclose(fp); + totalram -= min( totalram, ram_reporting_bias ); if (mem_available) freeram = mem_available; + if ((long long)freeram >= ram_reporting_bias) freeram -= ram_reporting_bias; + else + { + long long bias = ram_reporting_bias - freeram; + freeswap -= min( bias, freeswap ); + freeram = 0; + } } } #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || \ diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index d54d802e0cb..759483ca3ba 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -159,6 +159,7 @@ extern BOOL no_priv_elevation DECLSPEC_HIDDEN; extern BOOL localsystem_sid DECLSPEC_HIDDEN; extern BOOL high_dll_addresses DECLSPEC_HIDDEN; extern BOOL simulate_writecopy DECLSPEC_HIDDEN; +extern long long ram_reporting_bias; extern void init_environment( int argc, char *argv[], char *envp[] ) DECLSPEC_HIDDEN; extern void init_startup_info(void) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index ea314dbe1d5..a7f0f2dc4c3 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -2987,6 +2987,7 @@ void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info, BOOL wow64 ) if (!sysinfo(&sinfo)) { ULONG64 total = (ULONG64)sinfo.totalram * sinfo.mem_unit; + total -= min(total, ram_reporting_bias); info->MmHighestPhysicalPage = max(1, total / page_size); } #elif defined(_SC_PHYS_PAGES) From 175aad72a09b62c4fa9720cf6c21faf6bcec0a3a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 10 May 2023 13:17:26 -0600 Subject: [PATCH 1641/2777] ntdll: Add virtstat debug channel and log memory allocation statistics. This is solely for debugging purposes and does nothing unless +virtstat logging is enabled. CW-Bug-Id: #22045 CW-Bug-Id: #22247 --- dlls/ntdll/unix/virtual.c | 56 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index a7f0f2dc4c3..b62968cb26d 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -80,6 +80,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(virtual); WINE_DECLARE_DEBUG_CHANNEL(module); WINE_DECLARE_DEBUG_CHANNEL(virtual_ranges); +WINE_DECLARE_DEBUG_CHANNEL(virtstat); struct preload_info { @@ -1172,6 +1173,53 @@ static void VIRTUAL_Dump(void) #endif +static void dump_memory_statistics(void) +{ + struct file_view *view; + SIZE_T anon_reserved = 0, anon_committed = 0, mapped = 0, mapped_committed = 0, marked_native = 0; + SIZE_T size, c_size; + char *base; + BYTE vprot; + + if (!TRACE_ON(virtstat)) return; + + WINE_RB_FOR_EACH_ENTRY( view, &views_tree, struct file_view, entry ) + { + if (view->protect & VPROT_NATIVE) + { + marked_native += view->size; + continue; + } + base = view->base; + c_size = 0; + while (base != (char *)view->base + view->size) + { + size = get_vprot_range_size( base, (char *)view->base + view->size - base, VPROT_COMMITTED, &vprot ); + if (vprot & VPROT_COMMITTED) c_size += size; + base += size; + } + if (is_view_valloc( view )) + { + anon_reserved += view->size; + anon_committed += c_size; + } + else + { + mapped += view->size; + mapped_committed += c_size; + } + } + + anon_reserved /= 1024 * 1024; + anon_committed /= 1024 * 1024; + mapped /= 1024 * 1024; + mapped_committed /= 1024 * 1024; + marked_native /= 1024 * 1024; + TRACE_(virtstat)( "Total: res %lu, comm %lu; Anon: res %lu, comm %lu, marked Unix %lu.\n", + anon_reserved + mapped, anon_committed + mapped_committed, anon_reserved, anon_committed, + marked_native ); +} + /*********************************************************************** * find_view * @@ -4147,7 +4195,11 @@ static NTSTATUS allocate_virtual_memory( void **ret, SIZE_T *size_ptr, ULONG typ } } - if (!status) VIRTUAL_DEBUG_DUMP_VIEW( view ); + if (!status) + { + VIRTUAL_DEBUG_DUMP_VIEW( view ); + dump_memory_statistics(); + } server_leave_uninterrupted_section( &virtual_mutex, &sigset ); @@ -4514,6 +4566,8 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si status = STATUS_INVALID_PARAMETER; } + dump_memory_statistics(); + server_leave_uninterrupted_section( &virtual_mutex, &sigset ); return status; } From 5e52b3165542d3244c693c408a631db2efafebf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 16 May 2023 15:35:41 +0200 Subject: [PATCH 1642/2777] Revert "winex11.drv: Send missed KEYUP events on KeymapNotify." This reverts commit 26f41550b292ce1784701c08711dbcb488f20482. --- dlls/winex11.drv/event.c | 2 -- dlls/winex11.drv/keyboard.c | 43 ++----------------------------------- dlls/winex11.drv/mouse.c | 2 -- dlls/winex11.drv/x11drv.h | 1 - 4 files changed, 2 insertions(+), 46 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 760177d0622..2aaf8e482db 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -827,8 +827,6 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (event->detail == NotifyPointer) return FALSE; if (hwnd == NtUserGetDesktopWindow()) return FALSE; - x11drv_thread_data()->keymapnotify_hwnd = hwnd; - /* Focus was just restored but it can be right after super was * pressed and gnome-shell needs a bit of time to respond and * toggle the activity view. If we grab the cursor right away diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index b51546a6340..db001696a14 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1206,19 +1206,11 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) int i, j; BYTE keystate[256]; WORD vkey; - DWORD flags; - KeyCode keycode; - HWND keymapnotify_hwnd; BOOL changed = FALSE; struct { WORD vkey; - WORD scan; WORD pressed; } keys[256]; - struct x11drv_thread_data *thread_data = x11drv_thread_data(); - - keymapnotify_hwnd = thread_data->keymapnotify_hwnd; - thread_data->keymapnotify_hwnd = NULL; if (!get_async_key_state( keystate )) return FALSE; @@ -1233,17 +1225,11 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) { for (j = 0; j < 8; j++) { - keycode = (i * 8) + j; - vkey = keyc2vkey[keycode]; + vkey = keyc2vkey[(i * 8) + j]; /* If multiple keys map to the same vkey, we want to report it as * pressed iff any of them are pressed. */ - if (!keys[vkey & 0xff].vkey) - { - keys[vkey & 0xff].vkey = vkey; - keys[vkey & 0xff].scan = keyc2scan[keycode] & 0xff; - } - + if (!keys[vkey & 0xff].vkey) keys[vkey & 0xff].vkey = vkey; if (event->xkeymap.key_vector[i] & (1<window, event->x, event->y, event->detail ); - x11drv_thread_data()->keymapnotify_hwnd = hwnd; - if (hwnd == x11drv_thread_data()->grab_hwnd) return FALSE; /* simulate a mouse motion event */ diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index f1ded52c2b8..07d821e76a8 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -382,7 +382,6 @@ struct x11drv_thread_data XEvent *current_event; /* event currently being processed */ HWND grab_hwnd; /* window that currently grabs the mouse */ HWND last_focus; /* last window that had focus */ - HWND keymapnotify_hwnd; /* window that should receive modifier release events */ XIM xim; /* input method */ HWND last_xic_hwnd; /* last xic window */ XFontSet font_set; /* international text drawing font set */ From 46d07b8e449a7fc582903e4ed5fa733d55eb7c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 16 May 2023 15:35:47 +0200 Subject: [PATCH 1643/2777] Revert "winex11.drv: Dump keysyms and translations for all keys." This reverts commit 988a654ba10d7a7eda73f358042eb2b0af17a267. --- dlls/winex11.drv/keyboard.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index db001696a14..97a85f59938 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1474,19 +1474,6 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) for (i = 0; i < syms; i++) { if (!(keysym = keycode_to_keysym (display, keyc, i))) continue; ckey[keyc][i] = keysym_to_char(keysym); - if (TRACE_ON(keyboard)) - { - char buf[32]; - WCHAR bufW[32]; - int len, lenW; - KeySym orig_keysym = keysym; - len = XkbTranslateKeySym(display, &keysym, 0, buf, sizeof(buf), NULL); - lenW = ntdll_umbstowcs(buf, len, bufW, ARRAY_SIZE(bufW)); - if (lenW < ARRAY_SIZE(bufW)) - bufW[lenW] = 0; - TRACE("keycode %u, index %d, orig_keysym 0x%04lx, keysym 0x%04lx, buf %s, bufW %s\n", - keyc, i, orig_keysym, keysym, debugstr_a(buf), debugstr_w(bufW)); - } } } From c2e86d27f0732bfe9ca1b6dbcf8e87733586dba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 16 May 2023 15:35:52 +0200 Subject: [PATCH 1644/2777] Revert "winex11.drv: Recognize the keyboard in a locale-independent way." This reverts commit 7649db953ed0b1ae06659315a987ecb97befe39f. --- dlls/winex11.drv/keyboard.c | 64 +++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 97a85f59938..12bb2b863cb 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1414,35 +1414,6 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) return TRUE; } -/* From the point of view of this function there are two types of - * keys: those for which the mapping to vkey and scancode depends on - * the keyboard layout (i.e., letters, numbers, punctuation) and those - * for which it doesn't (control keys); since this function is used to - * recognize the keyboard layout and map keysyms to vkeys and - * scancodes, we are only concerned about the first type, and map - * everything in the second type to zero. - */ -static char keysym_to_char( KeySym keysym ) -{ - /* Dead keys */ - if (0xfe50 <= keysym && keysym < 0xfed0) - return KEYBOARD_MapDeadKeysym( keysym ); - - /* Control keys (there is nothing allocated below 0xfc00, but I - take some margin in case something is added in the future) */ - if (0xf000 <= keysym && keysym < 0x10000) - return 0; - - /* XFree86 vendor keys */ - if (0x10000000 <= keysym) - return 0; - - /* "Normal" keys: return last octet, because our tables don't have - more than that; it would be better to extend the tables and - compare the whole keysym, but it's a lot of work... */ - return keysym & 0xff; -} - /********************************************************************** * X11DRV_KEYBOARD_DetectLayout * @@ -1473,7 +1444,24 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) /* get data for keycode from X server */ for (i = 0; i < syms; i++) { if (!(keysym = keycode_to_keysym (display, keyc, i))) continue; - ckey[keyc][i] = keysym_to_char(keysym); + /* Allow both one-byte and two-byte national keysyms */ + if ((keysym < 0x8000) && (keysym != ' ')) + { +#ifdef HAVE_XKB + if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL)) +#endif + { + TRACE("XKB could not translate keysym %04lx\n", keysym); + /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent + * with appropriate ShiftMask and Mode_switch, use XLookupString + * to get character in the local encoding. + */ + ckey[keyc][i] = keysym & 0xFF; + } + } + else { + ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym); + } } } @@ -1684,7 +1672,21 @@ void X11DRV_InitKeyboard( Display *display ) int maxlen=0,maxval=-1,ok; for (i=0; i Date: Mon, 23 Jan 2023 21:30:06 +0100 Subject: [PATCH 1645/2777] win32u: Silence spurious FIXME in NtUserScrollWindowEx. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54357 (cherry picked from commit 8870d51d3e09565463baa11ce7d2b43c9ca252e4) --- dlls/win32u/dce.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 773d6e0b059..d7aa75b3039 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -1725,7 +1725,7 @@ INT WINAPI NtUserScrollWindowEx( HWND hwnd, INT dx, INT dy, const RECT *rect, TRACE( "%p, %d,%d update_rgn=%p update_rect = %p %s %04x\n", hwnd, dx, dy, update_rgn, update_rect, wine_dbgstr_rect(rect), flags ); TRACE( "clip_rect = %s\n", wine_dbgstr_rect(clip_rect) ); - if (flags & ~(SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE)) + if (flags & ~(SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE | SW_NODCCACHE)) FIXME( "some flags (%04x) are unhandled\n", flags ); rdw_flags = (flags & SW_ERASE) && (flags & SW_INVALIDATE) ? From 8a21a4227ab188804e7c9304378984c59ef2e86b Mon Sep 17 00:00:00 2001 From: Fabian Maurer Date: Mon, 12 Dec 2022 18:45:17 +0100 Subject: [PATCH 1646/2777] user32/tests: Don't assign const variable to other const (gcc 4.7). Signed-off-by: Fabian Maurer (cherry picked from commit 4bc6aad375e552fa5930c65c0e9c434f1848286e) --- dlls/user32/tests/sysparams.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/user32/tests/sysparams.c b/dlls/user32/tests/sysparams.c index 5c199a07769..6ed7755b91b 100644 --- a/dlls/user32/tests/sysparams.c +++ b/dlls/user32/tests/sysparams.c @@ -3123,7 +3123,8 @@ static void test_EnumDisplaySettings(void) { static const DWORD mode_fields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY; - static const DWORD setting_fields = mode_fields | DM_POSITION; + static const DWORD setting_fields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | + DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION; CHAR primary_adapter[CCHDEVICENAME]; DPI_AWARENESS_CONTEXT ctx = NULL; DWORD err, val, device, mode; From 30fa9bd18ed277224701a379a82013dad4733624 Mon Sep 17 00:00:00 2001 From: Akihiro Sagawa Date: Fri, 20 Jan 2023 23:51:36 +0900 Subject: [PATCH 1647/2777] user32/tests: Add DBCS WM_CHAR tests for edit control. (cherry picked from commit cbe3a39b647e029df16faf1dcce2958f1ee418d0) --- dlls/user32/tests/edit.c | 53 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/dlls/user32/tests/edit.c b/dlls/user32/tests/edit.c index b70cf2d6e06..0409b3fde7c 100644 --- a/dlls/user32/tests/edit.c +++ b/dlls/user32/tests/edit.c @@ -3366,6 +3366,58 @@ static void test_wordbreak_proc(void) DestroyWindow(hwnd); } +static void test_dbcs_WM_CHAR(void) +{ + WCHAR textW[] = { 0x4e00, 0x4e8c, 0x4e09, 0 }; /* one, two, three */ + unsigned char bytes[7]; + HWND hwnd[2]; + int i; + + WideCharToMultiByte(CP_ACP, 0, textW, -1, (char *)bytes, ARRAY_SIZE(bytes), NULL, NULL); + if (!IsDBCSLeadByte(bytes[0])) + { + skip("Skipping DBCS WM_CHAR test in this codepage\n"); + return; + } + hwnd[0] = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + hwnd[1] = create_editcontrolW(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + + for (i = 0; i < ARRAY_SIZE(hwnd); i++) + { + const unsigned char* p; + WCHAR strW[4]; + char str[7]; + MSG msg; + BOOL r; + int n; + + winetest_push_context("%c", i ? 'W' : 'A'); + + r = SetWindowTextA(hwnd[i], ""); + ok(r, "SetWindowText failed\n"); + + for (p = bytes; *p; p++) + PostMessageA(hwnd[i], WM_CHAR, *p, 1); + + while (PeekMessageA(&msg, hwnd[i], 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); + + n = GetWindowTextW(hwnd[i], strW, ARRAY_SIZE(strW)); + ok(n > 0, "GetWindowTextW failed\n"); + todo_wine ok(!wcscmp(strW, textW), "got %s, expected %s\n", + wine_dbgstr_w(strW), wine_dbgstr_w(textW)); + + n = GetWindowTextA(hwnd[i], str, ARRAY_SIZE(str)); + ok(n > 0, "GetWindowText failed\n"); + todo_wine ok(!strcmp(str, (char*)bytes), "got %s, expected %s\n", + wine_dbgstr_a(str), wine_dbgstr_a((char *)bytes)); + + DestroyWindow(hwnd[i]); + + winetest_pop_context(); + } +} + START_TEST(edit) { BOOL b; @@ -3403,6 +3455,7 @@ START_TEST(edit) test_paste(); test_EM_GETLINE(); test_wordbreak_proc(); + test_dbcs_WM_CHAR(); UnregisterWindowClasses(); } From 88a35e4f9185349ced5aa0e28c4153b7143277d2 Mon Sep 17 00:00:00 2001 From: Akihiro Sagawa Date: Fri, 20 Jan 2023 23:55:59 +0900 Subject: [PATCH 1648/2777] user32/edit: Fix WM_CHAR handler for double-byte characters. After commit 2aa54a90bd24f6aa422a2eb832a54d9afe585259, a double-byte character is sent to the edit control by double WM_CHAR messages. However, its WM_CHAR handler (ANSI version) can't process a double- byte character properly because the handler converts WM_CHAR to WCHAR one by one. This fix queues the double-byte lead byte as it comes in and then uses it afterwards for the WCHAR conversion. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54337 (cherry picked from commit c385b6475e6ad07227a1ef29593170af1c3cbf99) --- dlls/user32/edit.c | 21 +++++++++++++++++++-- dlls/user32/tests/edit.c | 4 ++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/dlls/user32/edit.c b/dlls/user32/edit.c index 2e651e455dd..aa74d215673 100644 --- a/dlls/user32/edit.c +++ b/dlls/user32/edit.c @@ -113,6 +113,7 @@ typedef struct should be sent to the first parent. */ HWND hwndListBox; /* handle of ComboBox's listbox or NULL */ INT wheelDeltaRemainder; /* scroll wheel delta left over after scrolling whole lines */ + BYTE lead_byte; /* DBCS lead byte store for WM_CHAR */ /* * only for multi line controls */ @@ -4975,8 +4976,24 @@ LRESULT EditWndProc_common( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, B charW = wParam; else { - CHAR charA = wParam; - MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1); + BYTE low = wParam; + DWORD cp = get_input_codepage(); + if (es->lead_byte) + { + char ch[2]; + ch[0] = es->lead_byte; + ch[1] = low; + MultiByteToWideChar(cp, 0, ch, 2, &charW, 1); + } + else if (IsDBCSLeadByteEx(cp, low)) + { + es->lead_byte = low; + result = 1; + break; + } + else + MultiByteToWideChar(cp, 0, (char *)&low, 1, &charW, 1); + es->lead_byte = 0; } if (es->hwndListBox) diff --git a/dlls/user32/tests/edit.c b/dlls/user32/tests/edit.c index 0409b3fde7c..78328ee1729 100644 --- a/dlls/user32/tests/edit.c +++ b/dlls/user32/tests/edit.c @@ -3404,12 +3404,12 @@ static void test_dbcs_WM_CHAR(void) n = GetWindowTextW(hwnd[i], strW, ARRAY_SIZE(strW)); ok(n > 0, "GetWindowTextW failed\n"); - todo_wine ok(!wcscmp(strW, textW), "got %s, expected %s\n", + ok(!wcscmp(strW, textW), "got %s, expected %s\n", wine_dbgstr_w(strW), wine_dbgstr_w(textW)); n = GetWindowTextA(hwnd[i], str, ARRAY_SIZE(str)); ok(n > 0, "GetWindowText failed\n"); - todo_wine ok(!strcmp(str, (char*)bytes), "got %s, expected %s\n", + ok(!strcmp(str, (char*)bytes), "got %s, expected %s\n", wine_dbgstr_a(str), wine_dbgstr_a((char *)bytes)); DestroyWindow(hwnd[i]); From d6dcaf3bf9825e52d2571108d7053e0059764718 Mon Sep 17 00:00:00 2001 From: Francois Gouget Date: Tue, 20 Dec 2022 15:33:56 +0100 Subject: [PATCH 1649/2777] user32: GetClipboardData() should set last error when the format is not found. This has the benefit of indicating why GetClipboardData() failed and of matching the Windows 11 behavior. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54190 (cherry picked from commit 25d6c1a3b497c1530b4ed2c769ec5728b7c006bc) --- dlls/user32/tests/clipboard.c | 8 ++++++-- dlls/win32u/clipboard.c | 6 +++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/dlls/user32/tests/clipboard.c b/dlls/user32/tests/clipboard.c index 3131c2e0e8c..7414af996fb 100644 --- a/dlls/user32/tests/clipboard.c +++ b/dlls/user32/tests/clipboard.c @@ -986,7 +986,9 @@ static void test_synthesized(void) SetLastError(0xdeadbeef); data = GetClipboardData( CF_TEXT ); - ok(GetLastError() == 0xdeadbeef, "bad last error %ld\n", GetLastError()); + ok(GetLastError() == ERROR_NOT_FOUND /* win11 */ || + broken(GetLastError() == 0xdeadbeef), + "bad last error %ld\n", GetLastError()); ok(!data, "GetClipboardData() should have returned NULL\n"); r = CloseClipboard(); @@ -1587,7 +1589,9 @@ static void test_handles( HWND hwnd ) SetLastError( 0xdeadbeef ); data = GetClipboardData( CF_RIFF ); - ok( GetLastError() == 0xdeadbeef, "unexpected last error %ld\n", GetLastError() ); + ok( GetLastError() == ERROR_NOT_FOUND /* win11 */ || + broken(GetLastError() == 0xdeadbeef), + "unexpected last error %ld\n", GetLastError() ); ok( !data, "wrong data %p\n", data ); h = SetClipboardData( CF_PRIVATEFIRST + 7, htext4 ); diff --git a/dlls/win32u/clipboard.c b/dlls/win32u/clipboard.c index d53cd966d36..6cf484a56ca 100644 --- a/dlls/win32u/clipboard.c +++ b/dlls/win32u/clipboard.c @@ -720,7 +720,11 @@ HANDLE WINAPI NtUserGetClipboardData( UINT format, struct get_clipboard_params * params->data_size = size; return 0; } - if (status == STATUS_OBJECT_NAME_NOT_FOUND) return 0; /* no such format */ + if (status == STATUS_OBJECT_NAME_NOT_FOUND) + { + RtlSetLastWin32Error( ERROR_NOT_FOUND ); /* no such format */ + return 0; + } if (status) { RtlSetLastWin32Error( RtlNtStatusToDosError( status )); From c226aef6d38e30d8c8c67642e78d1aee3dfab8cf Mon Sep 17 00:00:00 2001 From: Francois Gouget Date: Wed, 21 Dec 2022 16:11:31 +0100 Subject: [PATCH 1650/2777] user32/tests: Use wine_dbgstr_an() to trace malformed Unicode strings. Using wine_dbgstr_wn() causes out-of-bounds memory accesses when given Unicode strings with odd sizes, most obviously 1 byte strings. Also trace the expected Ansi string for round-trip tests. (cherry picked from commit 47d492742477e5d0e94b2efda91ef7b405d34300) --- dlls/user32/tests/clipboard.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/user32/tests/clipboard.c b/dlls/user32/tests/clipboard.c index 7414af996fb..09f01b7481a 100644 --- a/dlls/user32/tests/clipboard.c +++ b/dlls/user32/tests/clipboard.c @@ -2269,7 +2269,7 @@ static void test_string_data(void) memcpy( bufferW, test_data[i].strW, test_data[i].len ); bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0; ok( !memcmp( data, bufferW, test_data[i].len ), - "wrong data %s\n", wine_dbgstr_wn( data, (test_data[i].len + 1) / sizeof(WCHAR) )); + "wrong data %s\n", wine_dbgstr_an( data, test_data[i].len )); } r = CloseClipboard(); ok( r, "gle %ld\n", GetLastError() ); @@ -2314,8 +2314,7 @@ static void test_string_data_process( int i ) ok( len == test_data[i].len, "wrong size %u / %u\n", len, test_data[i].len ); memcpy( bufferW, test_data[i].strW, test_data[i].len ); bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0; - ok( !memcmp( data, bufferW, len ), - "wrong data %s\n", wine_dbgstr_wn( data, (len + 1) / sizeof(WCHAR) )); + ok( !memcmp( data, bufferW, len ), "wrong data %s\n", wine_dbgstr_an( data, len )); data = GetClipboardData( CF_TEXT ); if (test_data[i].len >= sizeof(WCHAR)) { @@ -2325,7 +2324,8 @@ static void test_string_data_process( int i ) bufferA, ARRAY_SIZE(bufferA), NULL, NULL ); bufferA[len2 - 1] = 0; ok( len == len2, "wrong size %u / %u\n", len, len2 ); - ok( !memcmp( data, bufferA, len ), "wrong data %.*s\n", len, (char *)data ); + ok( !memcmp( data, bufferA, len ), "wrong data %s, expected %s\n", + wine_dbgstr_an( data, len ), wine_dbgstr_an( bufferA, len2 )); } else { From 2fc7f518465c8cb4a13ee81b18e3c2e793bdc1e5 Mon Sep 17 00:00:00 2001 From: Francois Gouget Date: Wed, 21 Dec 2022 18:31:41 +0100 Subject: [PATCH 1651/2777] user32: Fix a SetClipboardData() underflow and improve the tests. A 0 or 1 byte Unicode string cannot be NUL terminated. That does stop Windows 10 and older from doing so which is why the 1 byte test must be skipped to avoid a crash in the 64-bit case. But in such cases SetClipboardData() fails on Windows 11 and so should Wine (instead of underflowing the buffer like Windows). Reorganize the test data by increasing size. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54192 (cherry picked from commit ee4f8cbb2066bf7ff2721fb081c1ab091ed8840e) --- dlls/user32/clipboard.c | 1 + dlls/user32/tests/clipboard.c | 73 ++++++++++++++++++++++++----------- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/dlls/user32/clipboard.c b/dlls/user32/clipboard.c index dd33bd7df82..f006e205e05 100644 --- a/dlls/user32/clipboard.c +++ b/dlls/user32/clipboard.c @@ -160,6 +160,7 @@ static HANDLE marshal_data( UINT format, HANDLE handle, size_t *ret_size ) WCHAR *ptr; if (!(size = GlobalSize( handle ))) return 0; if ((data_size_t)size != size) return 0; + if (size < sizeof(WCHAR)) return 0; if (!(ptr = GlobalLock( handle ))) return 0; ptr[(size + 1) / sizeof(WCHAR) - 1] = 0; /* enforce null-termination */ GlobalUnlock( handle ); diff --git a/dlls/user32/tests/clipboard.c b/dlls/user32/tests/clipboard.c index 09f01b7481a..38249c24ea0 100644 --- a/dlls/user32/tests/clipboard.c +++ b/dlls/user32/tests/clipboard.c @@ -2217,35 +2217,39 @@ static const struct UINT len; } test_data[] = { - { "foo", {}, 3 }, /* 0 */ + { "foo", {}, 3 }, /* 0 */ { "foo", {}, 4 }, { "foo\0bar", {}, 7 }, { "foo\0bar", {}, 8 }, - { "", {'f','o','o'}, 3 * sizeof(WCHAR) }, - { "", {'f','o','o',0}, 4 * sizeof(WCHAR) }, /* 5 */ + { "", {}, 0 }, + { "", {'f'}, 1 }, /* 5 */ + { "", {'f'}, 2 }, + { "", {'f','o','o'}, 5 }, + { "", {'f','o','o'}, 6 }, + { "", {'f','o','o',0}, 7 }, /* 10 */ + { "", {'f','o','o',0}, 8 }, + { "", {'f','o','o',0,'b'}, 9 }, { "", {'f','o','o',0,'b','a','r'}, 7 * sizeof(WCHAR) }, { "", {'f','o','o',0,'b','a','r',0}, 8 * sizeof(WCHAR) }, - { "", {'f','o','o'}, 1 }, - { "", {'f','o','o'}, 2 }, - { "", {'f','o','o'}, 5 }, /* 10 */ - { "", {'f','o','o',0}, 7 }, - { "", {'f','o','o',0}, 9 }, }; static void test_string_data(void) { UINT i; BOOL r; - HANDLE data; + HANDLE data, clip; char cmd[16]; char bufferA[12]; WCHAR bufferW[12]; for (i = 0; i < ARRAY_SIZE(test_data); i++) { - /* 1-byte Unicode strings crash on Win64 */ #ifdef _WIN64 - if (!test_data[i].strA[0] && test_data[i].len < sizeof(WCHAR)) continue; + /* Before Windows 11 1-byte Unicode strings crash on Win64 + * because it underflows when 'appending' a 2 bytes NUL character! + */ + if (!test_data[i].strA[0] && test_data[i].len < sizeof(WCHAR) && + strcmp(winetest_platform, "windows") == 0) continue; #endif winetest_push_context("%d", i); r = open_clipboard( 0 ); @@ -2265,11 +2269,17 @@ static void test_string_data(void) else { memcpy( data, test_data[i].strW, test_data[i].len ); - SetClipboardData( CF_UNICODETEXT, data ); - memcpy( bufferW, test_data[i].strW, test_data[i].len ); - bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0; - ok( !memcmp( data, bufferW, test_data[i].len ), - "wrong data %s\n", wine_dbgstr_an( data, test_data[i].len )); + clip = SetClipboardData( CF_UNICODETEXT, data ); + if (test_data[i].len >= sizeof(WCHAR)) + { + ok( clip == data, "SetClipboardData() returned %p != %p\n", clip, data ); + memcpy( bufferW, test_data[i].strW, test_data[i].len ); + bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0; + ok( !memcmp( data, bufferW, test_data[i].len ), + "wrong data %s\n", wine_dbgstr_an( data, test_data[i].len )); + } + else + ok( !clip || broken(clip != NULL), "expected SetClipboardData() to fail\n" ); } r = CloseClipboard(); ok( r, "gle %ld\n", GetLastError() ); @@ -2309,12 +2319,27 @@ static void test_string_data_process( int i ) else { data = GetClipboardData( CF_UNICODETEXT ); - ok( data != 0, "could not get data\n" ); - len = GlobalSize( data ); - ok( len == test_data[i].len, "wrong size %u / %u\n", len, test_data[i].len ); - memcpy( bufferW, test_data[i].strW, test_data[i].len ); - bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0; - ok( !memcmp( data, bufferW, len ), "wrong data %s\n", wine_dbgstr_an( data, len )); + if (!data) + { + ok( test_data[i].len < sizeof(WCHAR), "got no data for len=%d\n", test_data[i].len ); + ok( !IsClipboardFormatAvailable( CF_UNICODETEXT ), "unicode available\n" ); + } + else if (test_data[i].len == 0) + { + /* 0-byte string handling is broken on Windows <= 10 */ + len = GlobalSize( data ); + ok( broken(len == 1), "wrong size %u / 0\n", len ); + ok( broken(*((char*)data) == 0), "wrong data %s\n", wine_dbgstr_an( data, len )); + } + else + { + len = GlobalSize( data ); + ok( len == test_data[i].len, "wrong size %u / %u\n", len, test_data[i].len ); + memcpy( bufferW, test_data[i].strW, test_data[i].len ); + bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0; + ok( !memcmp( data, bufferW, len ), "wrong data %s\n", wine_dbgstr_an( data, len )); + } + data = GetClipboardData( CF_TEXT ); if (test_data[i].len >= sizeof(WCHAR)) { @@ -2329,8 +2354,10 @@ static void test_string_data_process( int i ) } else { + BOOL available = IsClipboardFormatAvailable( CF_TEXT ); + ok( !available || broken(available /* win10 */), + "available text %d\n", available ); ok( !data, "got data for empty string\n" ); - ok( IsClipboardFormatAvailable( CF_TEXT ), "text not available\n" ); } } r = CloseClipboard(); From cc96dcdce98546098735b47bb1d63654345d6d23 Mon Sep 17 00:00:00 2001 From: Francois Gouget Date: Wed, 21 Dec 2022 18:48:29 +0100 Subject: [PATCH 1652/2777] user32: Fix a SetClipboardData() buffer overflow. Wine would append a correctly aligned NUL Unicode character to terminate the string but overflow the buffer by one byte for odd-sized strings. Windows instead overwrites the last two buffer bytes with a NUL Unicode character which ends up being misaligned for odd-sized strings. The clipboard data has a size field anyway so match the Windows behavior. Tweak the tests to show that SetClipboardData() can overwrite half of the Unicode string's last character. (cherry picked from commit 605ecafa67a4e034328b69396581e2f9b60d7af3) --- dlls/user32/clipboard.c | 5 +++-- dlls/user32/tests/clipboard.c | 14 +++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/dlls/user32/clipboard.c b/dlls/user32/clipboard.c index f006e205e05..72c7720dc17 100644 --- a/dlls/user32/clipboard.c +++ b/dlls/user32/clipboard.c @@ -157,12 +157,13 @@ static HANDLE marshal_data( UINT format, HANDLE handle, size_t *ret_size ) } case CF_UNICODETEXT: { - WCHAR *ptr; + char *ptr; if (!(size = GlobalSize( handle ))) return 0; if ((data_size_t)size != size) return 0; if (size < sizeof(WCHAR)) return 0; if (!(ptr = GlobalLock( handle ))) return 0; - ptr[(size + 1) / sizeof(WCHAR) - 1] = 0; /* enforce null-termination */ + /* enforce nul-termination the Windows way: ignoring alignment */ + *((WCHAR *)(ptr + size) - 1) = 0; GlobalUnlock( handle ); *ret_size = size; return handle; diff --git a/dlls/user32/tests/clipboard.c b/dlls/user32/tests/clipboard.c index 38249c24ea0..87df06b6621 100644 --- a/dlls/user32/tests/clipboard.c +++ b/dlls/user32/tests/clipboard.c @@ -2224,11 +2224,11 @@ static const struct { "", {}, 0 }, { "", {'f'}, 1 }, /* 5 */ { "", {'f'}, 2 }, - { "", {'f','o','o'}, 5 }, - { "", {'f','o','o'}, 6 }, - { "", {'f','o','o',0}, 7 }, /* 10 */ - { "", {'f','o','o',0}, 8 }, - { "", {'f','o','o',0,'b'}, 9 }, + { "", {0x3b1,0x3b2,0x3b3}, 5 }, /* Alpha, beta, ... */ + { "", {0x3b1,0x3b2,0x3b3}, 6 }, + { "", {0x3b1,0x3b2,0x3b3,0}, 7 }, /* 10 */ + { "", {0x3b1,0x3b2,0x3b3,0}, 8 }, + { "", {0x3b1,0x3b2,0x3b3,0,0x3b4}, 9 }, { "", {'f','o','o',0,'b','a','r'}, 7 * sizeof(WCHAR) }, { "", {'f','o','o',0,'b','a','r',0}, 8 * sizeof(WCHAR) }, }; @@ -2274,7 +2274,7 @@ static void test_string_data(void) { ok( clip == data, "SetClipboardData() returned %p != %p\n", clip, data ); memcpy( bufferW, test_data[i].strW, test_data[i].len ); - bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0; + *((WCHAR *)((char *)bufferW + test_data[i].len) - 1) = 0; ok( !memcmp( data, bufferW, test_data[i].len ), "wrong data %s\n", wine_dbgstr_an( data, test_data[i].len )); } @@ -2336,7 +2336,7 @@ static void test_string_data_process( int i ) len = GlobalSize( data ); ok( len == test_data[i].len, "wrong size %u / %u\n", len, test_data[i].len ); memcpy( bufferW, test_data[i].strW, test_data[i].len ); - bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0; + *((WCHAR *)((char *)bufferW + test_data[i].len) - 1) = 0; ok( !memcmp( data, bufferW, len ), "wrong data %s\n", wine_dbgstr_an( data, len )); } From 892398a20bfb2dfaef79a174172a9b1ab6701102 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 18 Jan 2023 19:43:08 -0600 Subject: [PATCH 1653/2777] win32u: Make call_messageAtoW() static. (cherry picked from commit e634f2365946d5c685e1679078e590d94b5e1327) --- dlls/win32u/message.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index fc405f39d4c..62924119c7d 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -3099,8 +3099,8 @@ static BOOL map_wparam_AtoW( UINT message, WPARAM *wparam, enum wm_char_mapping * * Call a window procedure, translating args from Ansi to Unicode. */ -LRESULT call_messageAtoW( winproc_callback_t callback, HWND hwnd, UINT msg, WPARAM wparam, - LPARAM lparam, LRESULT *result, void *arg, enum wm_char_mapping mapping ) +static LRESULT call_messageAtoW( winproc_callback_t callback, HWND hwnd, UINT msg, WPARAM wparam, + LPARAM lparam, LRESULT *result, void *arg, enum wm_char_mapping mapping ) { LRESULT ret = 0; From 72c715ce905839b3f2e1ebbbb7263eeac79f426f Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 18 Jan 2023 19:43:45 -0600 Subject: [PATCH 1654/2777] win32u: Make the global "caret" structure static. (cherry picked from commit 035ac4df7af40282829d8a3be8faf59810328c95) --- dlls/win32u/input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 94554fa4c5d..c537e17a157 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2050,7 +2050,7 @@ BOOL set_foreground_window( HWND hwnd, BOOL mouse ) return ret; } -struct +static struct { HBITMAP bitmap; unsigned int timeout; From 6d5ca7209f6e028fe74c2955cc447cfcbb861b1b Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 18 Jan 2023 19:44:36 -0600 Subject: [PATCH 1655/2777] win32u: Make create_brush() hidden. (cherry picked from commit ffe262b29b4617d24d4562f7efb32ecc39fb9c4a) --- dlls/win32u/ntgdi_private.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/ntgdi_private.h b/dlls/win32u/ntgdi_private.h index be3e4d8cd56..53674e0661a 100644 --- a/dlls/win32u/ntgdi_private.h +++ b/dlls/win32u/ntgdi_private.h @@ -152,7 +152,7 @@ extern DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src extern void get_mono_dc_colors( DC *dc, int color_table_size, BITMAPINFO *info, int count ) DECLSPEC_HIDDEN; /* brush.c */ -extern HBRUSH create_brush( const LOGBRUSH *brush ); +extern HBRUSH create_brush( const LOGBRUSH *brush ) DECLSPEC_HIDDEN; extern BOOL store_brush_pattern( LOGBRUSH *brush, struct brush_pattern *pattern ) DECLSPEC_HIDDEN; extern void free_brush_pattern( struct brush_pattern *pattern ) DECLSPEC_HIDDEN; From c6791a57116402a4d27152dc154802236423fa34 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 18 Jan 2023 19:45:08 -0600 Subject: [PATCH 1656/2777] win32u: Make draw_frame_caption() static. (cherry picked from commit e729c3bb70d4c733dd86a3cbd8176c1fd36e650b) --- dlls/win32u/defwnd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c index b28d02a79f4..a7f1a11897a 100644 --- a/dlls/win32u/defwnd.c +++ b/dlls/win32u/defwnd.c @@ -1302,7 +1302,7 @@ static BOOL draw_push_button( HDC dc, RECT *r, UINT flags ) return TRUE; } -BOOL draw_frame_caption( HDC dc, RECT *r, UINT flags ) +static BOOL draw_frame_caption( HDC dc, RECT *r, UINT flags ) { RECT rect; int small_diam = make_square_rect( r, &rect ) - 2; From 9b20c74b4c3ece840712d381bb7b9083cfcd8357 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 18 Jan 2023 19:46:06 -0600 Subject: [PATCH 1657/2777] win32u: Make draw_scroll_bar() static. (cherry picked from commit a0a3c25e84a4a5adb689c0b4702d01c1d4ace098) --- dlls/win32u/scroll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/scroll.c b/dlls/win32u/scroll.c index ce3af5189d3..19a9a1379f4 100644 --- a/dlls/win32u/scroll.c +++ b/dlls/win32u/scroll.c @@ -282,7 +282,7 @@ static BOOL get_scroll_bar_rect( HWND hwnd, int bar, RECT *rect, int *arrow_size * * Redraw the whole scrollbar. */ -void draw_scroll_bar( HWND hwnd, HDC hdc, int bar, enum SCROLL_HITTEST hit_test, +static void draw_scroll_bar( HWND hwnd, HDC hdc, int bar, enum SCROLL_HITTEST hit_test, const struct SCROLL_TRACKING_INFO *tracking_info, BOOL draw_arrows, BOOL draw_interior ) { From 7a96a27c32e1a296424036be574ddeb20dbdb664 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 18 Jan 2023 19:47:17 -0600 Subject: [PATCH 1658/2777] win32u: Make DrawTextW() hidden. (cherry picked from commit 4ccb65e23015f54178ff6f58ac89a7671f28caa3) --- dlls/win32u/font.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/font.c b/dlls/win32u/font.c index 679da4cc83a..da288010c0b 100644 --- a/dlls/win32u/font.c +++ b/dlls/win32u/font.c @@ -7101,7 +7101,7 @@ BOOL WINAPI NtGdiGetCharWidthInfo( HDC hdc, struct char_width_info *info ) /*********************************************************************** * DrawTextW (win32u.so) */ -INT WINAPI DrawTextW( HDC hdc, const WCHAR *str, INT count, RECT *rect, UINT flags ) +INT WINAPI DECLSPEC_HIDDEN DrawTextW( HDC hdc, const WCHAR *str, INT count, RECT *rect, UINT flags ) { struct draw_text_params *params; ULONG ret_len, size; From d99e3c737c94e2c50097f93ba44eaa4fa4e71bb4 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 18 Jan 2023 19:47:56 -0600 Subject: [PATCH 1659/2777] win32u: Make get_winproc_ptr() static. (cherry picked from commit 571f33cae67076d44569a94d8849f1c55a624e03) --- dlls/win32u/class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/class.c b/dlls/win32u/class.c index 9f3b4251e65..396e2285797 100644 --- a/dlls/win32u/class.c +++ b/dlls/win32u/class.c @@ -108,7 +108,7 @@ static WINDOWPROC *find_winproc( WNDPROC func, BOOL ansi ) /* return the window proc for a given handle, or NULL for an invalid handle, * or WINPROC_PROC16 for a handle to a 16-bit proc. */ -WINDOWPROC *get_winproc_ptr( WNDPROC handle ) +static WINDOWPROC *get_winproc_ptr( WNDPROC handle ) { UINT index = LOWORD(handle); if ((ULONG_PTR)handle >> 16 != WINPROC_HANDLE) return NULL; From 0d55150c94c7baedf7bdbf9bfea55e7b6a2118ec Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 18 Jan 2023 19:48:36 -0600 Subject: [PATCH 1660/2777] win32u: Make ImmProcessKey() hidden. (cherry picked from commit d2e60f28c141640e7b4a681b24b41cbd3c092fec) --- dlls/win32u/imm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index db077dbbef0..c35ca17989e 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -394,7 +394,7 @@ void cleanup_imm_thread(void) NtUserDestroyInputContext( UlongToHandle( thread_info->client_info.default_imc )); } -BOOL WINAPI ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM key_data, DWORD unknown ) +BOOL WINAPI DECLSPEC_HIDDEN ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM key_data, DWORD unknown ) { struct imm_process_key_params params = { .hwnd = hwnd, .hkl = hkl, .vkey = vkey, .key_data = key_data }; From 297d2835541cdca9b731e8362314dc2ebcab72ea Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 18 Jan 2023 19:48:46 -0600 Subject: [PATCH 1661/2777] win32u: Make ImmTranslateMessage() hidden. (cherry picked from commit 646d55adb224a79f8d23802c07b6157592994c46) --- dlls/win32u/imm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index c35ca17989e..d28648520a8 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -403,7 +403,7 @@ BOOL WINAPI DECLSPEC_HIDDEN ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM return KeUserModeCallback( NtUserImmProcessKey, ¶ms, sizeof(params), &ret_ptr, &ret_len ); } -BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM key_data ) +BOOL WINAPI DECLSPEC_HIDDEN ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM key_data ) { struct imm_translate_message_params params = { .hwnd = hwnd, .msg = msg, .wparam = wparam, .key_data = key_data }; From 4be192a6850f4473f87c6ff97a380d3b04a30e0a Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 18 Jan 2023 19:49:07 -0600 Subject: [PATCH 1662/2777] win32u: Make is_child() hidden. (cherry picked from commit 470723d70f88636134855ce586e3886d8f9abb88) --- dlls/win32u/ntuser_private.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 44af8158c6f..8ab1b35291e 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -273,7 +273,7 @@ static inline UINT win_get_flags( HWND hwnd ) } WND *get_win_ptr( HWND hwnd ) DECLSPEC_HIDDEN; -BOOL is_child( HWND parent, HWND child ); +BOOL is_child( HWND parent, HWND child ) DECLSPEC_HIDDEN; BOOL is_window( HWND hwnd ) DECLSPEC_HIDDEN; #if defined(__i386__) || defined(__x86_64__) From 3dae9dd2f3c262cabfe0630044e3a5630e63f067 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Fri, 27 Jan 2023 10:23:56 +0100 Subject: [PATCH 1663/2777] user32: Copy directly to the buffer in unpack_message(). This avoids compiler warnings. (cherry picked from commit d5756ff8cfb6231cef952f4265bfcf5b2ebb42d5) --- dlls/user32/winproc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dlls/user32/winproc.c b/dlls/user32/winproc.c index 6cd41b51435..9fd35e1d24e 100644 --- a/dlls/user32/winproc.c +++ b/dlls/user32/winproc.c @@ -831,7 +831,7 @@ static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lpa if (!check_string( str, size )) return FALSE; cs.lpszClass = str; } - memcpy( &ps->cs, &cs, sizeof(cs) ); + memcpy( *buffer, &cs, sizeof(cs) ); break; } case WM_GETTEXT: @@ -865,7 +865,7 @@ static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lpa dis.hDC = unpack_handle( ps->dis.hDC ); dis.rcItem = ps->dis.rcItem; dis.itemData = (ULONG_PTR)unpack_ptr( ps->dis.itemData ); - memcpy( &ps->dis, &dis, sizeof(dis) ); + memcpy( *buffer, &dis, sizeof(dis) ); break; } case WM_MEASUREITEM: @@ -878,7 +878,7 @@ static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lpa mis.itemWidth = ps->mis.itemWidth; mis.itemHeight = ps->mis.itemHeight; mis.itemData = (ULONG_PTR)unpack_ptr( ps->mis.itemData ); - memcpy( &ps->mis, &mis, sizeof(mis) ); + memcpy( *buffer, &mis, sizeof(mis) ); break; } case WM_DELETEITEM: @@ -890,7 +890,7 @@ static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lpa dls.itemID = ps->dls.itemID; dls.hwndItem = unpack_handle( ps->dls.hwndItem ); dls.itemData = (ULONG_PTR)unpack_ptr( ps->dls.itemData ); - memcpy( &ps->dls, &dls, sizeof(dls) ); + memcpy( *buffer, &dls, sizeof(dls) ); break; } case WM_COMPAREITEM: @@ -905,7 +905,7 @@ static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lpa cis.itemID2 = ps->cis.itemID2; cis.itemData2 = (ULONG_PTR)unpack_ptr( ps->cis.itemData2 ); cis.dwLocaleId = ps->cis.dwLocaleId; - memcpy( &ps->cis, &cis, sizeof(cis) ); + memcpy( *buffer, &cis, sizeof(cis) ); break; } case WM_WINDOWPOSCHANGING: @@ -920,7 +920,7 @@ static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lpa wp.cx = ps->wp.cx; wp.cy = ps->wp.cy; wp.flags = ps->wp.flags; - memcpy( &ps->wp, &wp, sizeof(wp) ); + memcpy( *buffer, &wp, sizeof(wp) ); break; } case WM_COPYDATA: @@ -1080,7 +1080,7 @@ static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lpa mnm.hmenuIn = unpack_handle( ps->mnm.hmenuIn ); mnm.hmenuNext = unpack_handle( ps->mnm.hmenuNext ); mnm.hwndNext = unpack_handle( ps->mnm.hwndNext ); - memcpy( &ps->mnm, &mnm, sizeof(mnm) ); + memcpy( *buffer, &mnm, sizeof(mnm) ); break; } case WM_SIZING: @@ -1116,7 +1116,7 @@ static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lpa if (!check_string( str, size )) return FALSE; mcs.szTitle = str; } - memcpy( &ps->mcs, &mcs, sizeof(mcs) ); + memcpy( *buffer, &mcs, sizeof(mcs) ); break; } case WM_MDIGETACTIVE: From 18941b1ec32a6f5b85d39c75c719b491b5eb549b Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 18 Jan 2023 19:50:38 -0600 Subject: [PATCH 1664/2777] win32u: Make send_message_timeout() hidden. (cherry picked from commit b2dd38372f9b800fd54704546c8a88c22eb9013f) --- dlls/win32u/win32u_private.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 87c76e7422c..bba36a43ae0 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -316,7 +316,7 @@ extern LRESULT send_internal_message_timeout( DWORD dest_pid, DWORD dest_tid, UI extern LRESULT send_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) DECLSPEC_HIDDEN; extern BOOL send_notify_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL ansi ) DECLSPEC_HIDDEN; extern LRESULT send_message_timeout( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, - UINT flags, UINT timeout, BOOL ansi ); + UINT flags, UINT timeout, BOOL ansi ) DECLSPEC_HIDDEN; /* rawinput.c */ extern BOOL process_rawinput_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data ) DECLSPEC_HIDDEN; From 88338caa1a5d8edaf96b434f5c7bd15f87f829b1 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 18 Jan 2023 19:53:09 -0600 Subject: [PATCH 1665/2777] win32u: Make set_visible_region() hidden. (cherry picked from commit dd6d837b62f5e0e3a2b1f0157c4a41b59d4ea991) --- dlls/win32u/ntgdi_private.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/ntgdi_private.h b/dlls/win32u/ntgdi_private.h index 53674e0661a..ce5e30ab07d 100644 --- a/dlls/win32u/ntgdi_private.h +++ b/dlls/win32u/ntgdi_private.h @@ -160,7 +160,7 @@ extern void free_brush_pattern( struct brush_pattern *pattern ) DECLSPEC_HIDDEN; extern BOOL clip_device_rect( DC *dc, RECT *dst, const RECT *src ) DECLSPEC_HIDDEN; extern BOOL clip_visrect( DC *dc, RECT *dst, const RECT *src ) DECLSPEC_HIDDEN; extern void set_visible_region( HDC hdc, HRGN hrgn, const RECT *vis_rect, - const RECT *device_rect, struct window_surface *surface ); + const RECT *device_rect, struct window_surface *surface ) DECLSPEC_HIDDEN; extern void update_dc_clipping( DC * dc ) DECLSPEC_HIDDEN; /* Return the total DC region (if any) */ From 799c0ef37f292ee847870c4ceccbb9a4937a8343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 16 May 2023 15:29:37 +0200 Subject: [PATCH 1666/2777] winex11: Make client_foreign_window_proc hidden. (cherry picked from commit 2b0677341704affce04710a633ba9fb5b3a134d1) --- dlls/winex11.drv/x11drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 07d821e76a8..e4fe442ccbc 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -459,7 +459,7 @@ extern int xrender_error_base DECLSPEC_HIDDEN; extern int xfixes_event_base DECLSPEC_HIDDEN; extern char *process_name DECLSPEC_HIDDEN; extern Display *clipboard_display DECLSPEC_HIDDEN; -extern WNDPROC client_foreign_window_proc; +extern WNDPROC client_foreign_window_proc DECLSPEC_HIDDEN; extern HANDLE steam_overlay_event DECLSPEC_HIDDEN; extern HANDLE steam_keyboard_event DECLSPEC_HIDDEN; From 84f7bba87242c60e10ecac3a004b0ae791f3f8cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 16 May 2023 15:30:00 +0200 Subject: [PATCH 1667/2777] winex11: Include x11drv.h in xrandr.c even if compiling without xrandr. Make sure we pull in the definition of X11DRV_XRandR_Init(), in particular because it has DECLSPEC_HIDDEN. (cherry picked from commit c05f5445dc2c330539cfb22fb5b27506061d26b4) --- dlls/winex11.drv/xrandr.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c index 35998877520..4186b404e6b 100644 --- a/dlls/winex11.drv/xrandr.c +++ b/dlls/winex11.drv/xrandr.c @@ -28,19 +28,17 @@ #define NONAMELESSSTRUCT #define NONAMELESSUNION - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(xrandr); - -#ifdef SONAME_LIBXRANDR - #include #include #include #include #include #include "x11drv.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(xrandr); + +#ifdef SONAME_LIBXRANDR #define VK_NO_PROTOTYPES #define WINE_VK_HOST From ab2e7396eb09201feb53290588d0555ff7a88e01 Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Sat, 11 Feb 2023 12:52:28 -0700 Subject: [PATCH 1668/2777] win32u: Avoid calling RtlInitUnicodeString on a static constant. (cherry picked from commit 33ddf019f7cb13f05aaeec984f3b9f3ca3411da9) --- dlls/win32u/imm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index d28648520a8..1ccc09c97b2 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -277,12 +277,11 @@ BOOL register_imm_window( HWND hwnd ) /* Create default IME window */ if (!thread_data->window_cnt++) { - UNICODE_STRING class_name, name; static const WCHAR imeW[] = {'I','M','E',0}; static const WCHAR default_imeW[] = {'D','e','f','a','u','l','t',' ','I','M','E',0}; + UNICODE_STRING class_name = RTL_CONSTANT_STRING( imeW ); + UNICODE_STRING name = RTL_CONSTANT_STRING( default_imeW ); - RtlInitUnicodeString( &class_name, imeW ); - RtlInitUnicodeString( &name, default_imeW ); thread_data->default_hwnd = NtUserCreateWindowEx( 0, &class_name, &class_name, &name, WS_POPUP | WS_DISABLED | WS_CLIPSIBLINGS, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, FALSE ); From a64d7750615dcdd5d1e837225e18b560eb54d2bd Mon Sep 17 00:00:00 2001 From: Francois Gouget Date: Mon, 13 Feb 2023 18:34:44 +0100 Subject: [PATCH 1669/2777] winex11.drv: Fix a typo in a comment. (cherry picked from commit 9338531ee40785f2237414205f8ba050e640acc1) --- dlls/winex11.drv/window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 2521625180b..300a4c983e8 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1189,7 +1189,7 @@ static void update_net_wm_fullscreen_monitors( struct x11drv_win_data *data ) if (!(data->net_wm_state & (1 << NET_WM_STATE_FULLSCREEN)) || is_virtual_desktop()) return; - /* If the current display device handler can not detect dynamic device changes, do not use + /* If the current display device handler cannot detect dynamic device changes, do not use * _NET_WM_FULLSCREEN_MONITORS because xinerama_get_fullscreen_monitors() may report wrong * indices because of stale xinerama monitor information */ if (!X11DRV_DisplayDevices_SupportEventHandlers()) From ffb23f7d7511fe1090b59df323c0759edb134c53 Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Tue, 28 Feb 2023 09:49:36 -0700 Subject: [PATCH 1670/2777] winex11: Use RTL_CONSTANT_STRING instead of reimplementing it. (cherry picked from commit 129d861656b61f9b308e9fb5f563af735871b533) --- dlls/winex11.drv/desktop.c | 4 ++-- dlls/winex11.drv/window.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c index f7f49f6ca4e..b7896632ca9 100644 --- a/dlls/winex11.drv/desktop.c +++ b/dlls/winex11.drv/desktop.c @@ -227,8 +227,8 @@ static LONG X11DRV_desktop_set_current_mode( ULONG_PTR id, const DEVMODEW *mode static void query_desktop_work_area( RECT *rc_work ) { - static const WCHAR trayW[] = {'S','h','e','l','l','_','T','r','a','y','W','n','d'}; - UNICODE_STRING str = { sizeof(trayW), sizeof(trayW), (WCHAR *)trayW }; + static const WCHAR trayW[] = {'S','h','e','l','l','_','T','r','a','y','W','n','d',0}; + UNICODE_STRING str = RTL_CONSTANT_STRING( trayW ); RECT rect; HWND hwnd = NtUserFindWindowEx( 0, 0, &str, NULL, 0 ); diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 300a4c983e8..ea2faa95828 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -3349,8 +3349,8 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, /* check if the window icon should be hidden (i.e. moved off-screen) */ static BOOL hide_icon( struct x11drv_win_data *data ) { - static const WCHAR trayW[] = {'S','h','e','l','l','_','T','r','a','y','W','n','d'}; - UNICODE_STRING str = { sizeof(trayW), sizeof(trayW), (WCHAR *)trayW }; + static const WCHAR trayW[] = {'S','h','e','l','l','_','T','r','a','y','W','n','d',0}; + UNICODE_STRING str = RTL_CONSTANT_STRING( trayW ); if (data->managed) return TRUE; /* hide icons in desktop mode when the taskbar is active */ From 4a7f30553dc1d3dd4d337f2bf014c0c76a13f840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Feb 2023 10:57:58 +0100 Subject: [PATCH 1671/2777] winex11: Assume that Xkb extension is available. (cherry picked from commit ad5cb8305f4ebc10992113f8f6a724d5f33a6bf8) --- configure.ac | 7 ------- dlls/winex11.drv/keyboard.c | 37 +++++++++------------------------- dlls/winex11.drv/x11drv.h | 1 - dlls/winex11.drv/x11drv_main.c | 14 +++---------- 4 files changed, 13 insertions(+), 46 deletions(-) diff --git a/configure.ac b/configure.ac index 100df2f395a..92dc784035d 100644 --- a/configure.ac +++ b/configure.ac @@ -1196,13 +1196,6 @@ then # include #endif]) - dnl *** Check for X keyboard extension - if test "$ac_cv_header_X11_XKBlib_h" = "yes" - then - AC_CHECK_LIB(X11, XkbQueryExtension, - AC_DEFINE(HAVE_XKB, 1, [Define if you have the XKB extension]),,[$X_LIBS $X_EXTRA_LIBS]) - fi - dnl *** Check for X cursor if test "$ac_cv_header_X11_Xcursor_Xcursor_h" = "yes" then diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 12bb2b863cb..caf1dbc6b56 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -34,9 +34,7 @@ #include #include #include -#ifdef HAVE_X11_XKBLIB_H #include -#endif #include #include @@ -66,7 +64,6 @@ WINE_DECLARE_DEBUG_CHANNEL(key); static const unsigned int ControlMask = 1 << 2; static int min_keycode, max_keycode, keysyms_per_keycode; -static KeySym *key_mapping; static WORD keyc2vkey[256], keyc2scan[256]; static int NumLockMask, ScrollLockMask, AltGrMask; /* mask in the XKeyEvent state */ @@ -1089,14 +1086,6 @@ static const WORD xfree86_vendor_key_vkey[256] = 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */ }; -static inline KeySym keycode_to_keysym( Display *display, KeyCode keycode, int index ) -{ -#ifdef HAVE_XKB - if (use_xkb) return XkbKeycodeToKeysym(display, keycode, 0, index); -#endif - return key_mapping[(keycode - min_keycode) * keysyms_per_keycode + index]; -} - /* Returns the Windows virtual key code associated with the X event */ /* kbd_section must be held */ static WORD EVENT_event_to_vkey( XIC xic, XKeyEvent *e) @@ -1443,13 +1432,11 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) for (keyc = min_keycode; keyc <= max_keycode; keyc++) { /* get data for keycode from X server */ for (i = 0; i < syms; i++) { - if (!(keysym = keycode_to_keysym (display, keyc, i))) continue; + if (!(keysym = XkbKeycodeToKeysym( display, keyc, 0, i ))) continue; /* Allow both one-byte and two-byte national keysyms */ if ((keysym < 0x8000) && (keysym != ' ')) { -#ifdef HAVE_XKB - if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL)) -#endif + if (!XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL)) { TRACE("XKB could not translate keysym %04lx\n", keysym); /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent @@ -1598,9 +1585,7 @@ void X11DRV_InitKeyboard( Display *display ) pthread_mutex_lock( &kbd_mutex ); XDisplayKeycodes(display, &min_keycode, &max_keycode); - if (key_mapping) XFree( key_mapping ); - key_mapping = XGetKeyboardMapping(display, min_keycode, - max_keycode + 1 - min_keycode, &keysyms_per_keycode); + XFree( XGetKeyboardMapping( display, min_keycode, max_keycode + 1 - min_keycode, &keysyms_per_keycode ) ); mmp = XGetModifierMapping(display); kcp = mmp->modifiermap; @@ -1614,12 +1599,12 @@ void X11DRV_InitKeyboard( Display *display ) int k; for (k = 0; k < keysyms_per_keycode; k += 1) - if (keycode_to_keysym(display, *kcp, k) == XK_Num_Lock) + if (XkbKeycodeToKeysym( display, *kcp, 0, k ) == XK_Num_Lock) { NumLockMask = 1 << i; TRACE_(key)("NumLockMask is %x\n", NumLockMask); } - else if (keycode_to_keysym(display, *kcp, k) == XK_Scroll_Lock) + else if (XkbKeycodeToKeysym( display, *kcp, 0, k ) == XK_Scroll_Lock) { ScrollLockMask = 1 << i; TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask); @@ -1671,12 +1656,10 @@ void X11DRV_InitKeyboard( Display *display ) /* we seem to need to search the layout-dependent scancodes */ int maxlen=0,maxval=-1,ok; for (i=0; i #include #include -#ifdef HAVE_XKB #include -#endif #ifdef HAVE_X11_EXTENSIONS_XRENDER_H #include #endif @@ -74,7 +72,6 @@ BOOL usexvidmode = FALSE; BOOL usexrandr = TRUE; BOOL usexcomposite = TRUE; BOOL use_xfixes = FALSE; -BOOL use_xkb = TRUE; BOOL use_take_focus = FALSE; BOOL use_primary_selection = FALSE; BOOL use_system_cursors = TRUE; @@ -828,9 +825,7 @@ static NTSTATUS x11drv_init( void *arg ) #endif X11DRV_XInput2_Load(); -#ifdef HAVE_XKB - if (use_xkb) use_xkb = XkbUseExtension( gdi_display, NULL, NULL ); -#endif + XkbUseExtension( gdi_display, NULL, NULL ); X11DRV_InitKeyboard( gdi_display ); X11DRV_InitMouse( gdi_display ); if (use_xim) use_xim = X11DRV_InitXIM( input_style ); @@ -941,11 +936,8 @@ struct x11drv_thread_data *x11drv_init_thread_data(void) fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */ -#ifdef HAVE_XKB - if (use_xkb && XkbUseExtension( data->display, NULL, NULL )) - XkbSetDetectableAutoRepeat( data->display, True, NULL ); -#endif - + XkbUseExtension( data->display, NULL, NULL ); + XkbSetDetectableAutoRepeat( data->display, True, NULL ); if (TRACE_ON(synchronous)) XSynchronize( data->display, True ); set_queue_display_fd( data->display ); From d67b56bd54345e8e6eda56337a02207db4b09b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 3 Mar 2023 10:04:07 +0100 Subject: [PATCH 1672/2777] user32/tests: Test VK_MENU effect on ToUnicode. (cherry picked from commit 3785dd1f37534777a0e20f162aee3d5d2e82eb3a) --- dlls/user32/tests/input.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index f8b40099091..1a9757bd1fb 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -3042,6 +3042,7 @@ static void test_key_map(void) #define shift 1 #define ctrl 2 +#define menu 4 static const struct tounicode_tests { @@ -3054,6 +3055,9 @@ static const struct tounicode_tests { { 0, 0, 'a', 1, {'a',0}}, { 0, shift, 'a', 1, {'A',0}}, + { 0, menu, 'a', 1, {'a',0}}, + { 0, shift|menu, 'a', 1, {'A',0}}, + { 0, shift|ctrl|menu, 'a', 0, {}}, { 0, ctrl, 'a', 1, {1, 0}}, { 0, shift|ctrl, 'a', 1, {1, 0}}, { VK_TAB, ctrl, 0, 0, {}}, @@ -3142,6 +3146,7 @@ static void test_ToUnicode(void) state[VK_SHIFT] = state[VK_LSHIFT] = (mod & shift) ? HIGHEST_BIT : 0; state[VK_CONTROL] = state[VK_LCONTROL] = (mod & ctrl) ? HIGHEST_BIT : 0; + state[VK_MENU] = state[VK_LMENU] = (mod & menu) ? HIGHEST_BIT : 0; ret = ToUnicode(vk, scan, state, wStr, 4, 0); ok(ret == utests[i].expect_ret, "%d: got %d expected %d\n", i, ret, utests[i].expect_ret); From 2ac7de07ffb1165abdd7269d31d807eb8b2109f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 4 Dec 2022 14:34:29 +0100 Subject: [PATCH 1673/2777] include: Allow overriding LANGID in module VERSIONINFO. (cherry picked from commit 653321a2b4ca672a25d5cd1a4a5ffb7d58f27f42) --- include/wine/wine_common_ver.rc | 12 ++++++++---- po/ar.po | 4 ++-- po/ast.po | 4 ++-- po/bg.po | 4 ++-- po/ca.po | 4 ++-- po/cs.po | 4 ++-- po/da.po | 4 ++-- po/de.po | 4 ++-- po/el.po | 4 ++-- po/en.po | 4 ++-- po/en_US.po | 4 ++-- po/eo.po | 4 ++-- po/es.po | 4 ++-- po/fa.po | 4 ++-- po/fi.po | 4 ++-- po/fr.po | 4 ++-- po/he.po | 4 ++-- po/hi.po | 4 ++-- po/hr.po | 4 ++-- po/hu.po | 4 ++-- po/it.po | 4 ++-- po/ja.po | 4 ++-- po/ko.po | 4 ++-- po/lt.po | 4 ++-- po/ml.po | 4 ++-- po/nb_NO.po | 4 ++-- po/nl.po | 4 ++-- po/or.po | 4 ++-- po/pa.po | 4 ++-- po/pl.po | 4 ++-- po/pt_BR.po | 4 ++-- po/pt_PT.po | 4 ++-- po/rm.po | 4 ++-- po/ro.po | 4 ++-- po/ru.po | 4 ++-- po/si.po | 4 ++-- po/sk.po | 4 ++-- po/sl.po | 4 ++-- po/sr_RS@cyrillic.po | 4 ++-- po/sr_RS@latin.po | 4 ++-- po/sv.po | 4 ++-- po/ta.po | 4 ++-- po/te.po | 4 ++-- po/th.po | 4 ++-- po/tr.po | 4 ++-- po/uk.po | 4 ++-- po/wa.po | 4 ++-- po/wine.pot | 4 ++-- po/zh_CN.po | 4 ++-- po/zh_TW.po | 4 ++-- 50 files changed, 106 insertions(+), 102 deletions(-) diff --git a/include/wine/wine_common_ver.rc b/include/wine/wine_common_ver.rc index 95ab04666e8..d79062416ed 100644 --- a/include/wine/wine_common_ver.rc +++ b/include/wine/wine_common_ver.rc @@ -115,6 +115,12 @@ never complain. #define WINE_CODEPAGE_HEX WINE_VER_HEXPREFIX(WINE_CODEPAGE) #endif +#ifndef WINE_LANGID +#define WINE_LANGID 0409 /* LANG_ENGLISH/SUBLANG_DEFAULT */ +#endif +#define WINE_LANGID_STR WINE_VER_STRINGIZE(WINE_LANGID) +#define WINE_LANGID_HEX WINE_VER_HEXPREFIX(WINE_LANGID) + VS_VERSION_INFO VERSIONINFO FILEVERSION WINE_FILEVERSION PRODUCTVERSION WINE_PRODUCTVERSION @@ -126,8 +132,7 @@ FILESUBTYPE WINE_FILESUBTYPE { BLOCK "StringFileInfo" { - /* LANG_ENGLISH/SUBLANG_DEFAULT, WINE_CODEPAGE */ - BLOCK "0409" WINE_CODEPAGE_STR + BLOCK WINE_LANGID_STR WINE_CODEPAGE_STR { VALUE "CompanyName", "Microsoft Corporation" /* GameGuard depends on this */ VALUE "FileDescription", WINE_FILEDESCRIPTION_STR @@ -142,7 +147,6 @@ FILESUBTYPE WINE_FILESUBTYPE } BLOCK "VarFileInfo" { - /* LANG_ENGLISH/SUBLANG_DEFAULT, WINE_CODEPAGE */ - VALUE "Translation", 0x0409, WINE_CODEPAGE_HEX + VALUE "Translation", WINE_LANGID_HEX, WINE_CODEPAGE_HEX } } diff --git a/po/ar.po b/po/ar.po index b87d6151a2f..8ebe10b5a0a 100644 --- a/po/ar.po +++ b/po/ar.po @@ -4117,11 +4117,11 @@ msgstr "'[object]' ليس عنصر تاريخ" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "واين" diff --git a/po/ast.po b/po/ast.po index 91d7d256182..9bb71695e12 100644 --- a/po/ast.po +++ b/po/ast.po @@ -3988,11 +3988,11 @@ msgstr "" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/bg.po b/po/bg.po index 47e12a893e8..70219b75174 100644 --- a/po/bg.po +++ b/po/bg.po @@ -4115,11 +4115,11 @@ msgstr "" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 #, fuzzy msgid "Wine" diff --git a/po/ca.po b/po/ca.po index 90ee5673f7a..1b66417b24d 100644 --- a/po/ca.po +++ b/po/ca.po @@ -4089,11 +4089,11 @@ msgstr "'this' no és un objecte de |" msgid "Property cannot have both accessors and a value" msgstr "La propietat no pot tenir ambdós mètodes d'accés i un valor" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "DLL de nucli del Wine" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/cs.po b/po/cs.po index 25a4f1b75e3..704550231b3 100644 --- a/po/cs.po +++ b/po/cs.po @@ -4058,11 +4058,11 @@ msgstr "„%s“ není platný název portu" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/da.po b/po/da.po index c7ee34b8ff9..3fc57acec52 100644 --- a/po/da.po +++ b/po/da.po @@ -4154,11 +4154,11 @@ msgstr "«[objekt]» er ikke et dato objekt" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/de.po b/po/de.po index 1ed7acd9d05..7a14c2e5a59 100644 --- a/po/de.po +++ b/po/de.po @@ -4077,11 +4077,11 @@ msgstr "'this' ist kein |-Objekt" msgid "Property cannot have both accessors and a value" msgstr "Eigenschaft kann nicht sowohl Accessoren als auch einen Wert haben" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "Wine-Kernel-DLL" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/el.po b/po/el.po index c5c8307e2cb..11180a1b639 100644 --- a/po/el.po +++ b/po/el.po @@ -4017,11 +4017,11 @@ msgstr "" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "" diff --git a/po/en.po b/po/en.po index a9ad0a9cb0a..246a8bb86f2 100644 --- a/po/en.po +++ b/po/en.po @@ -4068,11 +4068,11 @@ msgstr "'this' is not a | object" msgid "Property cannot have both accessors and a value" msgstr "Property cannot have both accessors and a value" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "Wine kernel DLL" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/en_US.po b/po/en_US.po index ab15878a97b..ad7b5b9773c 100644 --- a/po/en_US.po +++ b/po/en_US.po @@ -4068,11 +4068,11 @@ msgstr "'this' is not a | object" msgid "Property cannot have both accessors and a value" msgstr "Property cannot have both accessors and a value" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "Wine kernel DLL" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/eo.po b/po/eo.po index 050cd952e48..ad39dac7839 100644 --- a/po/eo.po +++ b/po/eo.po @@ -4024,11 +4024,11 @@ msgstr "" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/es.po b/po/es.po index c19a7daabc1..5bc81f068b8 100644 --- a/po/es.po +++ b/po/es.po @@ -4094,11 +4094,11 @@ msgstr "'[this]' no es un objeto Map" msgid "Property cannot have both accessors and a value" msgstr "La propiedad no puede tener tanto descriptores de acceso como un valor" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "DLL de núcle Wine" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/fa.po b/po/fa.po index 40491717d00..2eafe19dd2e 100644 --- a/po/fa.po +++ b/po/fa.po @@ -4044,11 +4044,11 @@ msgstr "" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "" diff --git a/po/fi.po b/po/fi.po index 51f6dc4736e..905eb06a8cc 100644 --- a/po/fi.po +++ b/po/fi.po @@ -4061,11 +4061,11 @@ msgstr "'this' ei ole |-objekti" msgid "Property cannot have both accessors and a value" msgstr "Ominaisuudella ei voi olla sekä hakufunktiota että arvoa" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "Winen ydin-DLL" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/fr.po b/po/fr.po index b3d2ea080c0..1c48ddc57a6 100644 --- a/po/fr.po +++ b/po/fr.po @@ -4086,11 +4086,11 @@ msgstr "« this » n'est pas un objet de type Map" msgid "Property cannot have both accessors and a value" msgstr "La propriété ne peut à la fois avoir une valeur et des accesseurs" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "DLL noyau de Wine" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/he.po b/po/he.po index 2e716c65960..82df9538b43 100644 --- a/po/he.po +++ b/po/he.po @@ -4108,11 +4108,11 @@ msgstr "'%s' ×ינו ×©× ×ª×§× ×™ לפתחה" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/hi.po b/po/hi.po index 08201ec785b..8ba49545d06 100644 --- a/po/hi.po +++ b/po/hi.po @@ -3973,11 +3973,11 @@ msgstr "" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "" diff --git a/po/hr.po b/po/hr.po index cab03b4c47b..c9f87d7dc66 100644 --- a/po/hr.po +++ b/po/hr.po @@ -4122,11 +4122,11 @@ msgstr "'[object]' nije vremenski objekt" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/hu.po b/po/hu.po index 6b70faab001..05920d1c8e6 100644 --- a/po/hu.po +++ b/po/hu.po @@ -4172,11 +4172,11 @@ msgstr "'Az [object]' nem egy date (dátum) objektum" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine súgó" diff --git a/po/it.po b/po/it.po index d2bf050bd81..d0663b4d1d7 100644 --- a/po/it.po +++ b/po/it.po @@ -4180,11 +4180,11 @@ msgstr "'[oggetto]' non è un oggetto data" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/ja.po b/po/ja.po index ee177c0aaa8..318f1a9029d 100644 --- a/po/ja.po +++ b/po/ja.po @@ -4060,11 +4060,11 @@ msgstr "'this' 㯠| オブジェクトã§ã¯ã‚ã‚Šã¾ã›ã‚“" msgid "Property cannot have both accessors and a value" msgstr "プロパティã¯ã‚¢ã‚¯ã‚»ã‚µãƒ¼ã¨å€¤ã®ä¸¡æ–¹ã«ãªã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/ko.po b/po/ko.po index fde0ddc1d3b..a86e129750c 100644 --- a/po/ko.po +++ b/po/ko.po @@ -4049,11 +4049,11 @@ msgstr "'this'는 '|' 개체가 아닙니다" msgid "Property cannot have both accessors and a value" msgstr "ì†ì„±ì— ì ‘ê·¼ìžì™€ ê°’ì„ ë‘˜ 다 지정할 수는 없습니다" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "Wine ì»¤ë„ DLL" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/lt.po b/po/lt.po index 2fe2909a0d6..8ede4161894 100644 --- a/po/lt.po +++ b/po/lt.po @@ -4071,11 +4071,11 @@ msgstr "„Šis“ nÄ—ra | objektas" msgid "Property cannot have both accessors and a value" msgstr "SavybÄ— negali turÄ—ti ir kreipiklių, ir reikÅ¡mÄ—s" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "Wine branduolio DLL" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/ml.po b/po/ml.po index 29b316c025c..8df38715288 100644 --- a/po/ml.po +++ b/po/ml.po @@ -3975,11 +3975,11 @@ msgstr "" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "" diff --git a/po/nb_NO.po b/po/nb_NO.po index ec59d534991..f7ddeff7cae 100644 --- a/po/nb_NO.po +++ b/po/nb_NO.po @@ -4092,11 +4092,11 @@ msgstr "'[object]' er ikke et dataobjekt" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "Wine kjerne-DLL" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/nl.po b/po/nl.po index b571b48a26b..92d601aaf92 100644 --- a/po/nl.po +++ b/po/nl.po @@ -4081,11 +4081,11 @@ msgstr "'this' is geen | object" msgid "Property cannot have both accessors and a value" msgstr "Eigenschap kan niet zowel accessors als een waarde hebben" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "Wine kernel DLL" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/or.po b/po/or.po index 4efb1620ccb..3d8ffa37e1d 100644 --- a/po/or.po +++ b/po/or.po @@ -3973,11 +3973,11 @@ msgstr "" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "" diff --git a/po/pa.po b/po/pa.po index fb970b7c963..8177d578666 100644 --- a/po/pa.po +++ b/po/pa.po @@ -3973,11 +3973,11 @@ msgstr "" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "" diff --git a/po/pl.po b/po/pl.po index 723493afaa2..dcb4daaa0bd 100644 --- a/po/pl.po +++ b/po/pl.po @@ -4093,11 +4093,11 @@ msgstr "'this' nie jest obiektem Map" msgid "Property cannot have both accessors and a value" msgstr "WÅ‚asność nie może mieć zarówno akcesorów i wartoÅ›ci" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "DLL jÄ…dra Wine" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/pt_BR.po b/po/pt_BR.po index d6821db3689..7593a85f8f3 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -4089,11 +4089,11 @@ msgstr "'this' não é um objeto Map" msgid "Property cannot have both accessors and a value" msgstr "Propriedade não pode ter ambos acessores e valor" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "Biblioteca de kernel Wine" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/pt_PT.po b/po/pt_PT.po index 833b8b23ade..be1ddf75488 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -4140,11 +4140,11 @@ msgstr "'[object]' não é um objecto de data" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/rm.po b/po/rm.po index 412e3dc6c5e..ffd9d51fc0e 100644 --- a/po/rm.po +++ b/po/rm.po @@ -4002,11 +4002,11 @@ msgstr "" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 #, fuzzy msgid "Wine" diff --git a/po/ro.po b/po/ro.po index 6c82bb5c603..3947ea81074 100644 --- a/po/ro.po +++ b/po/ro.po @@ -4095,11 +4095,11 @@ msgstr "„[obiect]†nu este un obiect de tip dată" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/ru.po b/po/ru.po index cb918603b72..b7649c75b93 100644 --- a/po/ru.po +++ b/po/ru.po @@ -4096,11 +4096,11 @@ msgstr "«this» не объект типа «Map»" msgid "Property cannot have both accessors and a value" msgstr "СвойÑтво не может одновременно иметь методы Ð´Ð»Ñ Ð´Ð¾Ñтупа и значение" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "Библиотека Ñдра Wine" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/si.po b/po/si.po index bb39137afd5..2dea09241dc 100644 --- a/po/si.po +++ b/po/si.po @@ -4025,11 +4025,11 @@ msgstr "'%s' වලංගු තොට නමක් නෙමෙයි." msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "Wine කර්නලයේ DLL" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/sk.po b/po/sk.po index c018db3e215..9caab53bd61 100644 --- a/po/sk.po +++ b/po/sk.po @@ -4062,11 +4062,11 @@ msgstr "" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/sl.po b/po/sl.po index 02638b23811..49fceead951 100644 --- a/po/sl.po +++ b/po/sl.po @@ -4174,11 +4174,11 @@ msgstr "'[object]' ni predmet datuma" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/sr_RS@cyrillic.po b/po/sr_RS@cyrillic.po index 63e76fa78f5..344a6396134 100644 --- a/po/sr_RS@cyrillic.po +++ b/po/sr_RS@cyrillic.po @@ -4150,11 +4150,11 @@ msgstr "„[object]“ није временÑки објекат" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/sr_RS@latin.po b/po/sr_RS@latin.po index e0977ce9ac3..4d5e65cb529 100644 --- a/po/sr_RS@latin.po +++ b/po/sr_RS@latin.po @@ -4235,11 +4235,11 @@ msgstr "„[object]“ nije vremenski objekat" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/sv.po b/po/sv.po index 5f4397962bf..f02e762af01 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4119,11 +4119,11 @@ msgstr "'[object]' är inte ett datumobjekt" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "Wine-kärn-DLL" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/ta.po b/po/ta.po index 2d1c803e1ad..02563f2b63d 100644 --- a/po/ta.po +++ b/po/ta.po @@ -3938,11 +3938,11 @@ msgstr "" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "" diff --git a/po/te.po b/po/te.po index c0c7e8116a0..6128822c44c 100644 --- a/po/te.po +++ b/po/te.po @@ -3973,11 +3973,11 @@ msgstr "" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "" diff --git a/po/th.po b/po/th.po index 8f563d508b7..9d99df54f41 100644 --- a/po/th.po +++ b/po/th.po @@ -4039,11 +4039,11 @@ msgstr "" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "" diff --git a/po/tr.po b/po/tr.po index 28cee4524cd..73ee1e5eb83 100644 --- a/po/tr.po +++ b/po/tr.po @@ -4087,11 +4087,11 @@ msgstr "'[object]' bir tarih nesnesi deÄŸil" msgid "Property cannot have both accessors and a value" msgstr "Nesnenin eriÅŸimcisi ve deÄŸeri birden olamaz" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "Wine çekirdek DLL'si" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/uk.po b/po/uk.po index 2d941b5248f..de0466f9971 100644 --- a/po/uk.po +++ b/po/uk.po @@ -4089,11 +4089,11 @@ msgstr "'це' не Ñ” Map об'єкта" msgid "Property cannot have both accessors and a value" msgstr "ВлаÑтивіÑÑ‚ÑŒ не може одночаÑно мати доÑтуп Ñ– значеннÑ" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "Бібліотека Ñдра Wine" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/wa.po b/po/wa.po index 13d79d4eeca..dab8e39300b 100644 --- a/po/wa.po +++ b/po/wa.po @@ -4039,11 +4039,11 @@ msgstr "" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 #, fuzzy msgid "Wine" diff --git a/po/wine.pot b/po/wine.pot index 881b048e33b..dd9701759d8 100644 --- a/po/wine.pot +++ b/po/wine.pot @@ -3927,11 +3927,11 @@ msgstr "" msgid "Property cannot have both accessors and a value" msgstr "" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "" diff --git a/po/zh_CN.po b/po/zh_CN.po index f226c3b1ced..bad68026ffa 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -4014,11 +4014,11 @@ msgstr "'this' ä¸æ˜¯ | 对象" msgid "Property cannot have both accessors and a value" msgstr "属性ä¸èƒ½åŒæ—¶åŒ…å«å­˜å–器和值" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "Wine kernel DLL" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" diff --git a/po/zh_TW.po b/po/zh_TW.po index 2a93c59445a..a54460961b3 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -4022,11 +4022,11 @@ msgstr "'this' ä¸æ˜¯ä¸€å€‹ | 物件" msgid "Property cannot have both accessors and a value" msgstr "屬性ä¸å¯åŒæ™‚有存å–å­å’Œå€¼" -#: include/wine/wine_common_ver.rc:133 +#: include/wine/wine_common_ver.rc:138 msgid "Wine kernel DLL" msgstr "Wine 核心 DLL" -#: include/wine/wine_common_ver.rc:138 dlls/winemac.drv/winemac.rc:32 +#: include/wine/wine_common_ver.rc:143 dlls/winemac.drv/winemac.rc:32 #: programs/wineboot/wineboot.rc:42 programs/winecfg/winecfg.rc:137 msgid "Wine" msgstr "Wine" From d5ad8fac2724a8750d87807d0dfda88e40ddfb82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 9 Mar 2023 08:54:44 +0100 Subject: [PATCH 1674/2777] oleaut32: Allocate a full pointer when unmarshalling byref arrays. Instead of the 4 bytes array wire size returned by get_type_size, which will truncate the pointer on 64-bit. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54562 (cherry picked from commit 76e7f030feb3b26ae409c2f1027f16168bcdd420) --- dlls/oleaut32/usrmarshal.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/oleaut32/usrmarshal.c b/dlls/oleaut32/usrmarshal.c index aa54a2b092b..4a874a23413 100644 --- a/dlls/oleaut32/usrmarshal.c +++ b/dlls/oleaut32/usrmarshal.c @@ -506,7 +506,10 @@ unsigned char * WINAPI VARIANT_UserUnmarshal(ULONG *pFlags, unsigned char *Buffe ULONG mem_size; Pos += 4; - switch (header->vt & ~VT_BYREF) + /* byref array needs to allocate a SAFEARRAY pointer */ + if (header->vt & VT_ARRAY) + mem_size = sizeof(void *); + else switch (header->vt & ~VT_BYREF) { /* these types have a different memory size compared to wire size */ case VT_UNKNOWN: From ad5f3d0127543ede21bcad46cab99ea8f740a134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 3 Mar 2023 09:59:51 +0100 Subject: [PATCH 1675/2777] win32u: Map VK_MENU / KBDALT in kbdus_tables pCharModifiers. (cherry picked from commit 2a6b80b508c6fd983729835a3d5c10f87a49f55b) --- dlls/win32u/input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index c537e17a157..9f17b71e0fe 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -135,8 +135,8 @@ static const VK_TO_BIT vk_to_bit[] = static const MODIFIERS modifiers = { .pVkToBit = (VK_TO_BIT *)vk_to_bit, - .wMaxModBits = 3, - .ModNumber = {0, 1, 2, 3}, + .wMaxModBits = 7, + .ModNumber = {0, 1, 2, 3, 0, 1, 0, 0}, }; static const VK_TO_WCHARS2 vk_to_wchars2[] = From 315eff7fb74574d272fa06b6b5a85f52d84b3c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 3 Mar 2023 10:26:37 +0100 Subject: [PATCH 1676/2777] win32u: Return the current display mode depth with nulldrv. (cherry picked from commit 8531f23a41956dcc3c68d6b02401f5c78db8ec60) --- dlls/win32u/driver.c | 2 +- dlls/win32u/sysparams.c | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 1c0708461a1..3f676dc5796 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -761,7 +761,7 @@ static BOOL nulldrv_GetCurrentDisplaySettings( LPCWSTR name, BOOL is_primary, LP static INT nulldrv_GetDisplayDepth( LPCWSTR name, BOOL is_primary ) { - return 32; + return -1; /* use default implementation */ } static BOOL nulldrv_UpdateDisplayDevices( const struct gdi_device_manager *manager, BOOL force, void *param ) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 2ecc317b509..a6c9fcd76cc 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2850,6 +2850,7 @@ static unsigned int active_monitor_count(void) INT get_display_depth( UNICODE_STRING *name ) { struct display_device *device; + BOOL is_primary; INT depth; if (!lock_display_devices()) @@ -2866,8 +2867,16 @@ INT get_display_depth( UNICODE_STRING *name ) return 32; } - depth = user_driver->pGetDisplayDepth( device->device_name, - !!(device->state_flags & DISPLAY_DEVICE_PRIMARY_DEVICE) ); + is_primary = !!(device->state_flags & DISPLAY_DEVICE_PRIMARY_DEVICE); + if ((depth = user_driver->pGetDisplayDepth( device->device_name, is_primary )) < 0) + { + struct adapter *adapter = CONTAINING_RECORD( device, struct adapter, dev ); + DEVMODEW current_mode = {.dmSize = sizeof(DEVMODEW)}; + + if (!adapter_get_current_settings( adapter, ¤t_mode )) depth = 32; + else depth = current_mode.dmBitsPerPel; + } + unlock_display_devices(); return depth; } From 6cfcc0b6aef98f3505b52cf9a76192ef552ad774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 3 Mar 2023 09:30:37 +0100 Subject: [PATCH 1677/2777] win32u: Check GUID_NULL display device if desktop atom is missing. When using nulldrv, there's no module to call __wine_set_user_driver and the user driver is still lazy_load_driver when get_display_driver gets called during desktop windows creation. Then, load_desktop_driver fails as it cannot find the not-yet-created desktop window atom, and fails later explorer.exe window creations such as the systray window. Other processes don't suffer from this as they wait for the desktop window to be fully created, and its atom will be eventually set. This change makes sure that we succeed in the case nulldrv was selected by explorer.exe, while still failing in case of error with another user driver as it would fail to open the right display device GUID. (cherry picked from commit 9c22a5ea63c6be01e257f05bbed23e03d5a7f407) --- dlls/win32u/driver.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 3f676dc5796..eb736de272d 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -923,6 +923,8 @@ static const WCHAR guid_key_suffixW[] = {'}','\\','0','0','0','0'}; static BOOL load_desktop_driver( HWND hwnd ) { + static const WCHAR guid_nullW[] = {'0','0','0','0','0','0','0','0','-','0','0','0','0','-','0','0','0','0','-', + '0','0','0','0','-','0','0','0','0','0','0','0','0','0','0','0','0',0}; WCHAR key[ARRAYSIZE(guid_key_prefixW) + 40 + ARRAYSIZE(guid_key_suffixW)], *ptr; char buf[4096]; KEY_VALUE_PARTIAL_INFORMATION *info = (void *)buf; @@ -946,9 +948,15 @@ static BOOL load_desktop_driver( HWND hwnd ) memcpy( key, guid_key_prefixW, sizeof(guid_key_prefixW) ); ptr = key + ARRAYSIZE(guid_key_prefixW); if (NtQueryInformationAtom( guid_atom, AtomBasicInformation, buf, sizeof(buf), NULL )) - return FALSE; - memcpy( ptr, abi->Name, abi->NameLength ); - ptr += abi->NameLength / sizeof(WCHAR); + { + wcscpy( ptr, guid_nullW ); + ptr += ARRAY_SIZE(guid_nullW) - 1; + } + else + { + memcpy( ptr, abi->Name, abi->NameLength ); + ptr += abi->NameLength / sizeof(WCHAR); + } memcpy( ptr, guid_key_suffixW, sizeof(guid_key_suffixW) ); ptr += ARRAY_SIZE(guid_key_suffixW); From a6b7348dcee057a12b32a4f1a81f1f8fed5b75d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 Mar 2023 13:11:04 +0100 Subject: [PATCH 1678/2777] win32u: Initialize IO_STATUS_BLOCK in load_directory_fonts. To avoid invalid writes on WOW64 Nt calls. (cherry picked from commit ec5d9f6413e6a1945c87651863d366e077cbe27e) --- dlls/win32u/font.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/font.c b/dlls/win32u/font.c index da288010c0b..d079c41f35a 100644 --- a/dlls/win32u/font.c +++ b/dlls/win32u/font.c @@ -6548,9 +6548,9 @@ static void load_system_bitmap_fonts(void) static void load_directory_fonts( WCHAR *path, UINT flags ) { + IO_STATUS_BLOCK io = {{0}}; OBJECT_ATTRIBUTES attr; UNICODE_STRING nt_name; - IO_STATUS_BLOCK io; HANDLE handle; char buf[8192]; size_t len; From 9790042267818bc9758864b81daf89b76d56c194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 Mar 2023 13:11:59 +0100 Subject: [PATCH 1679/2777] win32u: Initialize IO_STATUS_BLOCK in rawinput add_device. To avoid invalid writes on WOW64 Nt calls. (cherry picked from commit 647e20a9ff24216e61dcb9e9ee8c9ff73da812dd) --- dlls/win32u/rawinput.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/rawinput.c b/dlls/win32u/rawinput.c index f27bc092102..e5eab049fa3 100644 --- a/dlls/win32u/rawinput.c +++ b/dlls/win32u/rawinput.c @@ -220,11 +220,11 @@ static struct device *add_device( HKEY key, DWORD type ) static const RID_DEVICE_INFO_MOUSE mouse_info = {1, 5, 0, FALSE}; struct hid_preparsed_data *preparsed = NULL; HID_COLLECTION_INFORMATION hid_info; + IO_STATUS_BLOCK io = {{0}}; OBJECT_ATTRIBUTES attr; UNICODE_STRING string; struct device *device; RID_DEVICE_INFO info; - IO_STATUS_BLOCK io; unsigned int status; UINT32 handle; void *buffer; From 7f48fda8bcdb7bcd2bfa945c739147ed9a991756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 Mar 2023 13:12:19 +0100 Subject: [PATCH 1680/2777] winex11: Initialize IO_STATUS_BLOCK in X11DRV_GetICMProfile. To avoid invalid writes on WOW64 Nt calls. (cherry picked from commit eca1e4ea3666d0f9290f3bc2fc75f3e44e42656c) --- dlls/winex11.drv/graphics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/graphics.c b/dlls/winex11.drv/graphics.c index fbc1c9cde1b..ab861dc6bc8 100644 --- a/dlls/winex11.drv/graphics.c +++ b/dlls/winex11.drv/graphics.c @@ -1690,7 +1690,7 @@ BOOL CDECL X11DRV_GetICMProfile( PHYSDEV dev, BOOL allow_default, LPDWORD size, else if ((buffer = get_icm_profile( &buflen ))) { static const WCHAR icm[] = {'.','i','c','m',0}; - IO_STATUS_BLOCK io; + IO_STATUS_BLOCK io = {{0}}; UINT64 hash = 0; HANDLE file; int status; From a80687ecefe6c9d0af4bcf5c22e1384d63a48b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 3 Mar 2023 11:46:22 +0100 Subject: [PATCH 1681/2777] maintainers: Assume maintainership of IME support. (cherry picked from commit bd7a1a4d6670a58bfcc18bb077b066b308900ac0) --- MAINTAINERS | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 8c30f8c6d1d..3c4e7a308ba 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -181,8 +181,12 @@ F: dlls/win32u/rawinput.c F: server/queue.c Input methods -M: Aric Stewart +M: Rémi Bernon +P: Aric Stewart F: dlls/imm32/ +F: dlls/win32u/imm.c +F: dlls/winemac.drv/ime.c +F: dlls/winex11.drv/ime.c JavaScript M: Jacek Caban From 89edbf2a222beb95734b50733fd6464636d84472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 16 Feb 2023 17:22:25 +0100 Subject: [PATCH 1682/2777] imm32/tests: Add broken test results for w10v22H2. (cherry picked from commit b46ad448ab8ac3bdd2291f0336ec53886e5e7a20) --- dlls/imm32/tests/imm32.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 98af84383ba..ff9b9b038fb 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2277,7 +2277,9 @@ static DWORD WINAPI com_initialization_thread(void *arg) static void test_com_initialization(void) { + APTTYPEQUALIFIER qualifier; HANDLE thread; + APTTYPE type; HRESULT hr; HWND wnd; BOOL r; @@ -2332,13 +2334,17 @@ static void test_com_initialization(void) ok(hr == S_OK, "CoInitialize returned %lx\n", hr); test_apttype(APTTYPE_MTA); DestroyWindow(wnd); - test_apttype(-1); + + hr = CoGetApartmentType(&type, &qualifier); + ok(hr == CO_E_NOTINITIALIZED || broken(hr == S_OK) /* w10v22H2 */, + "CoGetApartmentType returned %#lx\n", hr); + test_apttype(hr == S_OK ? APTTYPE_MTA : -1); wnd = CreateWindowA("static", "static", WS_POPUP, 0, 0, 100, 100, 0, 0, 0, 0); ok(wnd != NULL, "CreateWindow failed\n"); - test_apttype(-1); + test_apttype(hr == S_OK ? APTTYPE_MTA : -1); ShowWindow(wnd, SW_SHOW); - test_apttype(APTTYPE_MAINSTA); + test_apttype(hr == S_OK ? APTTYPE_MTA : APTTYPE_MAINSTA); DestroyWindow(wnd); test_apttype(-1); } From 694841c908a9c4cfab9b007e7addf725d74453ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 4 Dec 2022 12:55:42 +0100 Subject: [PATCH 1683/2777] imm32/tests: Test ImmInstallIMEW with an actual IME. (cherry picked from commit d07a5e6b91352d9a44c8d23491432a6f446ada4b) --- dlls/imm32/tests/Makefile.in | 7 +- dlls/imm32/tests/ime_test.h | 35 ++++++++ dlls/imm32/tests/ime_wrapper.c | 107 +++++++++++++++++++++++ dlls/imm32/tests/ime_wrapper.rc | 28 ++++++ dlls/imm32/tests/ime_wrapper.spec | 16 ++++ dlls/imm32/tests/imm32.c | 138 +++++++++++++++++++++++++++++- 6 files changed, 327 insertions(+), 4 deletions(-) create mode 100644 dlls/imm32/tests/ime_test.h create mode 100644 dlls/imm32/tests/ime_wrapper.c create mode 100644 dlls/imm32/tests/ime_wrapper.rc create mode 100644 dlls/imm32/tests/ime_wrapper.spec diff --git a/dlls/imm32/tests/Makefile.in b/dlls/imm32/tests/Makefile.in index d0881429e34..ee4999f2855 100644 --- a/dlls/imm32/tests/Makefile.in +++ b/dlls/imm32/tests/Makefile.in @@ -1,5 +1,8 @@ TESTDLL = imm32.dll -IMPORTS = imm32 ole32 user32 +IMPORTS = imm32 ole32 user32 advapi32 -C_SRCS = \ +SOURCES = \ + ime_wrapper.c \ + ime_wrapper.rc \ + ime_wrapper.spec \ imm32.c diff --git a/dlls/imm32/tests/ime_test.h b/dlls/imm32/tests/ime_test.h new file mode 100644 index 00000000000..bdfb899b504 --- /dev/null +++ b/dlls/imm32/tests/ime_test.h @@ -0,0 +1,35 @@ +/* + * Copyright 2023 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 + */ + +#ifndef __WINE_IME_TEST_H +#define __WINE_IME_TEST_H + +#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "wingdi.h" + +#include "imm.h" +#include "immdev.h" + +#endif /* __WINE_IME_TEST_H */ diff --git a/dlls/imm32/tests/ime_wrapper.c b/dlls/imm32/tests/ime_wrapper.c new file mode 100644 index 00000000000..5bdd9afa336 --- /dev/null +++ b/dlls/imm32/tests/ime_wrapper.c @@ -0,0 +1,107 @@ +/* + * Copyright 2023 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 + */ + +#include "ime_test.h" + +BOOL WINAPI ImeConfigure( HKL hkl, HWND hwnd, DWORD mode, void *data ) +{ + return FALSE; +} + +DWORD WINAPI ImeConversionList( HIMC himc, const WCHAR *source, CANDIDATELIST *dest, DWORD dest_len, UINT flag ) +{ + return 0; +} + +BOOL WINAPI ImeDestroy( UINT force ) +{ + return FALSE; +} + +UINT WINAPI ImeEnumRegisterWord( REGISTERWORDENUMPROCW proc, const WCHAR *reading, DWORD style, + const WCHAR *string, void *data ) +{ + return 0; +} + +LRESULT WINAPI ImeEscape( HIMC himc, UINT escape, void *data ) +{ + return 0; +} + +DWORD WINAPI ImeGetImeMenuItems( HIMC himc, DWORD flags, DWORD type, IMEMENUITEMINFOW *parent, + IMEMENUITEMINFOW *menu, DWORD size ) +{ + return 0; +} + +UINT WINAPI ImeGetRegisterWordStyle( UINT item, STYLEBUFW *style_buf ) +{ + return 0; +} + +BOOL WINAPI ImeInquire( IMEINFO *info, WCHAR *ui_class, DWORD flags ) +{ + return FALSE; +} + +BOOL WINAPI ImeProcessKey( HIMC himc, UINT vkey, LPARAM key_data, BYTE *key_state ) +{ + return FALSE; +} + +BOOL WINAPI ImeRegisterWord( const WCHAR *reading, DWORD style, const WCHAR *string ) +{ + return FALSE; +} + +BOOL WINAPI ImeSelect( HIMC himc, BOOL select ) +{ + return FALSE; +} + +BOOL WINAPI ImeSetActiveContext( HIMC himc, BOOL flag ) +{ + return FALSE; +} + +BOOL WINAPI ImeSetCompositionString( HIMC himc, DWORD index, const void *comp, DWORD comp_len, + const void *read, DWORD read_len ) +{ + return FALSE; +} + +UINT WINAPI ImeToAsciiEx( UINT vkey, UINT scan_code, BYTE *key_state, TRANSMSGLIST *msgs, UINT state, HIMC himc ) +{ + return 0; +} + +BOOL WINAPI ImeUnregisterWord( const WCHAR *reading, DWORD style, const WCHAR *string ) +{ + return FALSE; +} + +BOOL WINAPI NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) +{ + return FALSE; +} + +BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, LPVOID reserved ) +{ + return TRUE; +} diff --git a/dlls/imm32/tests/ime_wrapper.rc b/dlls/imm32/tests/ime_wrapper.rc new file mode 100644 index 00000000000..6844b62195b --- /dev/null +++ b/dlls/imm32/tests/ime_wrapper.rc @@ -0,0 +1,28 @@ +/* + * Copyright 2023 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 + */ + +#pragma makedep testdll + +#define WINE_LANGID 0400 +#define WINE_FILETYPE VFT_DRV +#define WINE_FILESUBTYPE VFT2_DRV_INPUTMETHOD +#define WINE_FILENAME "ime_wrapper" +#define WINE_FILENAME_STR "ime_wrapper.dll" +#define WINE_FILEDESCRIPTION_STR "WineTest IME" + +#include "wine/wine_common_ver.rc" diff --git a/dlls/imm32/tests/ime_wrapper.spec b/dlls/imm32/tests/ime_wrapper.spec new file mode 100644 index 00000000000..937fdba922a --- /dev/null +++ b/dlls/imm32/tests/ime_wrapper.spec @@ -0,0 +1,16 @@ +@ stdcall ImeConfigure(long long long ptr) +@ stdcall ImeConversionList(long wstr ptr long long) +@ stdcall ImeDestroy(long) +@ stdcall ImeEnumRegisterWord(ptr wstr long wstr ptr) +@ stdcall ImeEscape(long long ptr) +@ stdcall ImeGetImeMenuItems(long long long ptr ptr long) +@ stdcall ImeGetRegisterWordStyle(long ptr) +@ stdcall ImeInquire(ptr wstr wstr) +@ stdcall ImeProcessKey(long long long ptr) +@ stdcall ImeRegisterWord(wstr long wstr) +@ stdcall ImeSelect(long long) +@ stdcall ImeSetActiveContext(long long) +@ stdcall ImeSetCompositionString(long long ptr long ptr long) +@ stdcall ImeToAsciiEx(long long ptr ptr long long) +@ stdcall ImeUnregisterWord(wstr long wstr) +@ stdcall NotifyIME(long long long long) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index ff9b9b038fb..127b0e90be8 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -18,7 +18,13 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include +#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" #include "wine/test.h" #include "objbase.h" @@ -27,6 +33,8 @@ #include "imm.h" #include "immdev.h" +#include "ime_test.h" + BOOL WINAPI ImmSetActiveContext(HWND, HIMC, BOOL); static BOOL (WINAPI *pImmAssociateContextEx)(HWND,HIMC,DWORD); @@ -206,6 +214,28 @@ static HWND hwnd, child; static HWND get_ime_window(void); +static void load_resource( const WCHAR *name, WCHAR *filename ) +{ + static WCHAR path[MAX_PATH]; + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + GetTempPathW( ARRAY_SIZE(path), path ); + GetTempFileNameW( path, name, 0, filename ); + + file = CreateFileW( filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 ); + ok( file != INVALID_HANDLE_VALUE, "failed to create %s, error %lu\n", debugstr_w(filename), GetLastError() ); + + res = FindResourceW( NULL, name, L"TESTDLL" ); + ok( res != 0, "couldn't find resource\n" ); + ptr = LockResource( LoadResource( GetModuleHandleW( NULL ), res ) ); + WriteFile( file, ptr, SizeofResource( GetModuleHandleW( NULL ), res ), &written, NULL ); + ok( written == SizeofResource( GetModuleHandleW( NULL ), res ), "couldn't write resource\n" ); + CloseHandle( file ); +} + static LRESULT WINAPI wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { HWND default_ime_wnd; @@ -2445,7 +2475,109 @@ static void test_ImmDisableIME(void) ok(!def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def); } -START_TEST(imm32) { +static UINT ime_count; +static WCHAR ime_path[MAX_PATH]; + +static HKL ime_install(void) +{ + WCHAR buffer[MAX_PATH]; + DWORD len, ret; + HKEY hkey; + HKL hkl; + + /* install the actual IME module, it will lookup the functions from the DLL */ + load_resource( L"ime_wrapper.dll", buffer ); + + SetLastError( 0xdeadbeef ); + swprintf( ime_path, ARRAY_SIZE(ime_path), L"c:\\windows\\system32\\wine%04x.ime", ime_count++ ); + ret = MoveFileW( buffer, ime_path ); + todo_wine_if( GetLastError() == ERROR_ALREADY_EXISTS ) + ok( ret || broken( !ret ) /* sometimes still in use */, + "MoveFileW failed, error %lu\n", GetLastError() ); + + hkl = ImmInstallIMEW( ime_path, L"WineTest IME" ); + todo_wine + ok( hkl == (HKL)(int)0xe0200400, "ImmInstallIMEW returned %p, error %lu\n", hkl, GetLastError() ); + + swprintf( buffer, ARRAY_SIZE(buffer), L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08x", hkl ); + ret = RegOpenKeyW( HKEY_LOCAL_MACHINE, buffer, &hkey ); + ok( !ret, "RegOpenKeyW returned %#lx, error %lu\n", ret, GetLastError() ); + + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = RegQueryValueExW( hkey, L"Ime File", NULL, NULL, (BYTE *)buffer, &len ); + ok( !ret, "RegQueryValueExW returned %#lx, error %lu\n", ret, GetLastError() ); + todo_wine + ok( !wcsicmp( buffer, wcsrchr( ime_path, '\\' ) + 1 ), "got Ime File %s\n", debugstr_w(buffer) ); + + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = RegQueryValueExW( hkey, L"Layout Text", NULL, NULL, (BYTE *)buffer, &len ); + ok( !ret, "RegQueryValueExW returned %#lx, error %lu\n", ret, GetLastError() ); + ok( !wcscmp( buffer, L"WineTest IME" ), "got Layout Text %s\n", debugstr_w(buffer) ); + + len = sizeof(buffer); + memset( buffer, 0xcd, sizeof(buffer) ); + ret = RegQueryValueExW( hkey, L"Layout File", NULL, NULL, (BYTE *)buffer, &len ); + todo_wine + ok( !ret, "RegQueryValueExW returned %#lx, error %lu\n", ret, GetLastError() ); + todo_wine + ok( !wcscmp( buffer, L"kbdus.dll" ), "got Layout File %s\n", debugstr_w(buffer) ); + + ret = RegCloseKey( hkey ); + ok( !ret, "RegCloseKey returned %#lx, error %lu\n", ret, GetLastError() ); + + return hkl; +} + +static void ime_cleanup( HKL hkl ) +{ + WCHAR buffer[MAX_PATH], value[MAX_PATH]; + DWORD i, buffer_len, value_len, ret; + HKEY hkey; + + ret = UnloadKeyboardLayout( hkl ); + todo_wine + ok( ret, "UnloadKeyboardLayout failed, error %lu\n", GetLastError() ); + + swprintf( buffer, ARRAY_SIZE(buffer), L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08x", hkl ); + ret = RegDeleteKeyW( HKEY_LOCAL_MACHINE, buffer ); + ok( !ret, "RegDeleteKeyW returned %#lx, error %lu\n", ret, GetLastError() ); + + ret = RegOpenKeyW( HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", &hkey ); + ok( !ret, "RegOpenKeyW returned %#lx, error %lu\n", ret, GetLastError() ); + + value_len = ARRAY_SIZE(value); + buffer_len = sizeof(buffer); + for (i = 0; !RegEnumValueW( hkey, i, value, &value_len, NULL, NULL, (void *)buffer, &buffer_len ); i++) + { + value_len = ARRAY_SIZE(value); + buffer_len = sizeof(buffer); + if (hkl != UlongToHandle( wcstoul( buffer, NULL, 16 ) )) continue; + ret = RegDeleteValueW( hkey, value ); + ok( !ret, "RegDeleteValueW returned %#lx, error %lu\n", ret, GetLastError() ); + } + + ret = RegCloseKey( hkey ); + ok( !ret, "RegCloseKey returned %#lx, error %lu\n", ret, GetLastError() ); + + ret = DeleteFileW( ime_path ); + todo_wine_if( GetLastError() == ERROR_ACCESS_DENIED ) + ok( ret || broken( !ret ) /* sometimes still in use */, + "DeleteFileW failed, error %lu\n", GetLastError() ); +} + +static void test_ImmInstallIME(void) +{ + HKL hkl; + + if (!(hkl = ime_install())) return; + + ime_cleanup( hkl ); +} + +START_TEST(imm32) +{ if (!is_ime_enabled()) { win_skip("IME support not implemented\n"); @@ -2454,6 +2586,8 @@ START_TEST(imm32) { test_com_initialization(); + test_ImmInstallIME(); + if (init()) { test_ImmNotifyIME(); From 1c148d1b2b09f515aa0efeff208e6cdc8a55abca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 Mar 2023 19:53:40 +0100 Subject: [PATCH 1684/2777] imm32/tests: Redirect IME function to the main module. For easier testing and to wokaround some Windows IME caching mechanism that prevent the IME module from reloading. (cherry picked from commit 16222f2de6e0b4619730467a66b301b62050b90a) --- dlls/imm32/tests/ime_test.h | 21 +++ dlls/imm32/tests/ime_wrapper.c | 67 +++++++--- dlls/imm32/tests/ime_wrapper.spec | 1 + dlls/imm32/tests/imm32.c | 210 ++++++++++++++++++++++++++++++ 4 files changed, 283 insertions(+), 16 deletions(-) diff --git a/dlls/imm32/tests/ime_test.h b/dlls/imm32/tests/ime_test.h index bdfb899b504..fda8065276d 100644 --- a/dlls/imm32/tests/ime_test.h +++ b/dlls/imm32/tests/ime_test.h @@ -32,4 +32,25 @@ #include "imm.h" #include "immdev.h" +struct ime_functions +{ + BOOL (*WINAPI pImeConfigure)(HKL,HWND,DWORD,void *); + DWORD (*WINAPI pImeConversionList)(HIMC,const WCHAR *,CANDIDATELIST *,DWORD,UINT); + BOOL (*WINAPI pImeDestroy)(UINT); + UINT (*WINAPI pImeEnumRegisterWord)(REGISTERWORDENUMPROCW,const WCHAR *,DWORD,const WCHAR *,void *); + LRESULT (*WINAPI pImeEscape)(HIMC,UINT,void *); + DWORD (*WINAPI pImeGetImeMenuItems)(HIMC,DWORD,DWORD,IMEMENUITEMINFOW *,IMEMENUITEMINFOW *,DWORD); + UINT (*WINAPI pImeGetRegisterWordStyle)(UINT,STYLEBUFW *); + BOOL (*WINAPI pImeInquire)(IMEINFO *,WCHAR *,DWORD); + BOOL (*WINAPI pImeProcessKey)(HIMC,UINT,LPARAM,BYTE *); + BOOL (*WINAPI pImeRegisterWord)(const WCHAR *,DWORD,const WCHAR *); + BOOL (*WINAPI pImeSelect)(HIMC,BOOL); + BOOL (*WINAPI pImeSetActiveContext)(HIMC,BOOL); + BOOL (*WINAPI pImeSetCompositionString)(HIMC,DWORD,const void *,DWORD,const void *,DWORD); + UINT (*WINAPI pImeToAsciiEx)(UINT,UINT,BYTE *,TRANSMSGLIST *,UINT,HIMC); + BOOL (*WINAPI pImeUnregisterWord)(const WCHAR *,DWORD,const WCHAR *); + BOOL (*WINAPI pNotifyIME)(HIMC,DWORD,DWORD,DWORD); + BOOL (*WINAPI pDllMain)(HINSTANCE,DWORD,void *); +}; + #endif /* __WINE_IME_TEST_H */ diff --git a/dlls/imm32/tests/ime_wrapper.c b/dlls/imm32/tests/ime_wrapper.c index 5bdd9afa336..d8a03499549 100644 --- a/dlls/imm32/tests/ime_wrapper.c +++ b/dlls/imm32/tests/ime_wrapper.c @@ -18,90 +18,125 @@ #include "ime_test.h" +struct ime_functions ime_functions = {0}; + BOOL WINAPI ImeConfigure( HKL hkl, HWND hwnd, DWORD mode, void *data ) { - return FALSE; + if (!ime_functions.pImeConfigure) return FALSE; + return ime_functions.pImeConfigure( hkl, hwnd, mode, data ); } DWORD WINAPI ImeConversionList( HIMC himc, const WCHAR *source, CANDIDATELIST *dest, DWORD dest_len, UINT flag ) { - return 0; + if (!ime_functions.pImeConversionList) return 0; + return ime_functions.pImeConversionList( himc, source, dest, dest_len, flag ); } BOOL WINAPI ImeDestroy( UINT force ) { - return FALSE; + if (!ime_functions.pImeDestroy) return FALSE; + return ime_functions.pImeDestroy( force ); } UINT WINAPI ImeEnumRegisterWord( REGISTERWORDENUMPROCW proc, const WCHAR *reading, DWORD style, const WCHAR *string, void *data ) { - return 0; + if (!ime_functions.pImeEnumRegisterWord) return 0; + return ime_functions.pImeEnumRegisterWord( proc, reading, style, string, data ); } LRESULT WINAPI ImeEscape( HIMC himc, UINT escape, void *data ) { - return 0; + if (!ime_functions.pImeEscape) return 0; + return ime_functions.pImeEscape( himc, escape, data ); } DWORD WINAPI ImeGetImeMenuItems( HIMC himc, DWORD flags, DWORD type, IMEMENUITEMINFOW *parent, IMEMENUITEMINFOW *menu, DWORD size ) { - return 0; + if (!ime_functions.pImeGetImeMenuItems) return 0; + return ime_functions.pImeGetImeMenuItems( himc, flags, type, parent, menu, size ); } UINT WINAPI ImeGetRegisterWordStyle( UINT item, STYLEBUFW *style_buf ) { - return 0; + if (!ime_functions.pImeGetRegisterWordStyle) return 0; + return ime_functions.pImeGetRegisterWordStyle( item, style_buf ); } BOOL WINAPI ImeInquire( IMEINFO *info, WCHAR *ui_class, DWORD flags ) { - return FALSE; + if (!ime_functions.pImeInquire) return FALSE; + return ime_functions.pImeInquire( info, ui_class, flags ); } BOOL WINAPI ImeProcessKey( HIMC himc, UINT vkey, LPARAM key_data, BYTE *key_state ) { - return FALSE; + if (!ime_functions.pImeProcessKey) return FALSE; + return ime_functions.pImeProcessKey( himc, vkey, key_data, key_state ); } BOOL WINAPI ImeRegisterWord( const WCHAR *reading, DWORD style, const WCHAR *string ) { - return FALSE; + if (!ime_functions.pImeRegisterWord) return FALSE; + return ime_functions.pImeRegisterWord( reading, style, string ); } BOOL WINAPI ImeSelect( HIMC himc, BOOL select ) { - return FALSE; + if (!ime_functions.pImeSelect) return FALSE; + return ime_functions.pImeSelect( himc, select ); } BOOL WINAPI ImeSetActiveContext( HIMC himc, BOOL flag ) { - return FALSE; + if (!ime_functions.pImeSetActiveContext) return FALSE; + return ime_functions.pImeSetActiveContext( himc, flag ); } BOOL WINAPI ImeSetCompositionString( HIMC himc, DWORD index, const void *comp, DWORD comp_len, const void *read, DWORD read_len ) { - return FALSE; + if (!ime_functions.pImeSetCompositionString) return FALSE; + return ime_functions.pImeSetCompositionString( himc, index, comp, comp_len, read, read_len ); } UINT WINAPI ImeToAsciiEx( UINT vkey, UINT scan_code, BYTE *key_state, TRANSMSGLIST *msgs, UINT state, HIMC himc ) { - return 0; + if (!ime_functions.pImeToAsciiEx) return 0; + return ime_functions.pImeToAsciiEx( vkey, scan_code, key_state, msgs, state, himc ); } BOOL WINAPI ImeUnregisterWord( const WCHAR *reading, DWORD style, const WCHAR *string ) { - return FALSE; + if (!ime_functions.pImeUnregisterWord) return FALSE; + return ime_functions.pImeUnregisterWord( reading, style, string ); } BOOL WINAPI NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) { - return FALSE; + if (!ime_functions.pNotifyIME) return FALSE; + return ime_functions.pNotifyIME( himc, action, index, value ); } BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, LPVOID reserved ) { + static HMODULE module; + + switch (reason) + { + case DLL_PROCESS_ATTACH: + if (!(module = GetModuleHandleW( L"winetest_ime.dll" ))) return TRUE; + ime_functions = *(struct ime_functions *)GetProcAddress( module, "ime_functions" ); + if (!ime_functions.pDllMain) return TRUE; + return ime_functions.pDllMain( instance, reason, reserved ); + + case DLL_PROCESS_DETACH: + if (module == instance) return TRUE; + if (!ime_functions.pDllMain) return TRUE; + ime_functions.pDllMain( instance, reason, reserved ); + memset( &ime_functions, 0, sizeof(ime_functions) ); + } + return TRUE; } diff --git a/dlls/imm32/tests/ime_wrapper.spec b/dlls/imm32/tests/ime_wrapper.spec index 937fdba922a..05a60e84a5d 100644 --- a/dlls/imm32/tests/ime_wrapper.spec +++ b/dlls/imm32/tests/ime_wrapper.spec @@ -14,3 +14,4 @@ @ stdcall ImeToAsciiEx(long long ptr ptr long long) @ stdcall ImeUnregisterWord(wstr long wstr) @ stdcall NotifyIME(long long long long) +@ extern -private ime_functions diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 127b0e90be8..0fd88d65aac 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2475,16 +2475,219 @@ static void test_ImmDisableIME(void) ok(!def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def); } +#define ime_trace( msg, ... ) if (winetest_debug > 1) trace( "%04lx:%s " msg, GetCurrentThreadId(), __func__, ## __VA_ARGS__ ) + +static LRESULT CALLBACK ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + ok( 0, "unexpected call\n" ); + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +static WNDCLASSEXW ime_ui_class = +{ + .cbSize = sizeof(WNDCLASSEXW), + .style = CS_IME, + .lpfnWndProc = ime_ui_window_proc, + .cbWndExtra = 2 * sizeof(LONG_PTR), + .lpszClassName = L"WineTestIME", +}; + +static BOOL WINAPI ime_ImeConfigure( HKL hkl, HWND hwnd, DWORD mode, void *data ) +{ + ime_trace( "hkl %p, hwnd %p, mode %lu, data %p\n", hkl, hwnd, mode, data ); + ok( 0, "unexpected call\n" ); + return FALSE; +} + +static DWORD WINAPI ime_ImeConversionList( HIMC himc, const WCHAR *source, CANDIDATELIST *dest, + DWORD dest_len, UINT flag ) +{ + ime_trace( "himc %p, source %s, dest %p, dest_len %lu, flag %#x\n", + himc, debugstr_w(source), dest, dest_len, flag ); + ok( 0, "unexpected call\n" ); + return 0; +} + +static BOOL WINAPI ime_ImeDestroy( UINT force ) +{ + ime_trace( "force %u\n", force ); + ok( 0, "unexpected call\n" ); + return TRUE; +} + +static UINT WINAPI ime_ImeEnumRegisterWord( REGISTERWORDENUMPROCW proc, const WCHAR *reading, DWORD style, + const WCHAR *string, void *data ) +{ + ime_trace( "proc %p, reading %s, style %lu, string %s, data %p\n", + proc, debugstr_w(reading), style, debugstr_w(string), data ); + ok( 0, "unexpected call\n" ); + return 0; +} + +static LRESULT WINAPI ime_ImeEscape( HIMC himc, UINT escape, void *data ) +{ + ime_trace( "himc %p, escape %#x, data %p\n", himc, escape, data ); + ok( 0, "unexpected call\n" ); + return TRUE; +} + +static DWORD WINAPI ime_ImeGetImeMenuItems( HIMC himc, DWORD flags, DWORD type, IMEMENUITEMINFOW *parent, + IMEMENUITEMINFOW *menu, DWORD size ) +{ + ime_trace( "himc %p, flags %#lx, type %lu, parent %p, menu %p, size %#lx\n", + himc, flags, type, parent, menu, size ); + ok( 0, "unexpected call\n" ); + return 0; +} + +static UINT WINAPI ime_ImeGetRegisterWordStyle( UINT item, STYLEBUFW *style ) +{ + ime_trace( "item %u, style %p\n", item, style ); + ok( 0, "unexpected call\n" ); + return 0; +} + +static BOOL WINAPI ime_ImeInquire( IMEINFO *info, WCHAR *ui_class, DWORD flags ) +{ + ime_trace( "info %p, ui_class %p, flags %#lx\n", info, ui_class, flags ); + ok( 0, "unexpected call\n" ); + return TRUE; +} + +static BOOL WINAPI ime_ImeProcessKey( HIMC himc, UINT vkey, LPARAM key_data, BYTE *key_state ) +{ + ime_trace( "himc %p, vkey %u, key_data %#Ix, key_state %p\n", + himc, vkey, key_data, key_state ); + ok( 0, "unexpected call\n" ); + return FALSE; +} + +static BOOL WINAPI ime_ImeRegisterWord( const WCHAR *reading, DWORD style, const WCHAR *string ) +{ + ime_trace( "reading %s, style %lu, string %s\n", debugstr_w(reading), style, debugstr_w(string) ); + ok( 0, "unexpected call\n" ); + return FALSE; +} + +static BOOL WINAPI ime_ImeSelect( HIMC himc, BOOL select ) +{ + ime_trace( "himc %p, select %d\n", himc, select ); + ok( 0, "unexpected call\n" ); + return FALSE; +} + +static BOOL WINAPI ime_ImeSetActiveContext( HIMC himc, BOOL flag ) +{ + ime_trace( "himc %p, flag %#x\n", himc, flag ); + ok( 0, "unexpected call\n" ); + return FALSE; +} + +static BOOL WINAPI ime_ImeSetCompositionString( HIMC himc, DWORD index, const void *comp, DWORD comp_len, + const void *read, DWORD read_len ) +{ + ime_trace( "himc %p, index %lu, comp %p, comp_len %lu, read %p, read_len %lu\n", + himc, index, comp, comp_len, read, read_len ); + ok( 0, "unexpected call\n" ); + return FALSE; +} + +static UINT WINAPI ime_ImeToAsciiEx( UINT vkey, UINT scan_code, BYTE *key_state, TRANSMSGLIST *msgs, UINT state, HIMC himc ) +{ + ime_trace( "vkey %u, scan_code %u, key_state %p, msgs %p, state %u, himc %p\n", + vkey, scan_code, key_state, msgs, state, himc ); + ok( 0, "unexpected call\n" ); + return 0; +} + +static BOOL WINAPI ime_ImeUnregisterWord( const WCHAR *reading, DWORD style, const WCHAR *string ) +{ + ime_trace( "reading %s, style %lu, string %s\n", debugstr_w(reading), style, debugstr_w(string) ); + ok( 0, "unexpected call\n" ); + return FALSE; +} + +static BOOL WINAPI ime_NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) +{ + ime_trace( "himc %p, action %lu, index %lu, value %lu\n", himc, action, index, value ); + ok( 0, "unexpected call\n" ); + return FALSE; +} + +static BOOL WINAPI ime_DllMain( HINSTANCE instance, DWORD reason, LPVOID reserved ) +{ + ime_trace( "instance %p, reason %lu, reserved %p.\n", instance, reason, reserved ); + + switch (reason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls( instance ); + ime_ui_class.hInstance = instance; + RegisterClassExW( &ime_ui_class ); + break; + + case DLL_PROCESS_DETACH: + UnregisterClassW( ime_ui_class.lpszClassName, instance ); + break; + } + + return TRUE; +} + +static struct ime_functions ime_functions = +{ + ime_ImeConfigure, + ime_ImeConversionList, + ime_ImeDestroy, + ime_ImeEnumRegisterWord, + ime_ImeEscape, + ime_ImeGetImeMenuItems, + ime_ImeGetRegisterWordStyle, + ime_ImeInquire, + ime_ImeProcessKey, + ime_ImeRegisterWord, + ime_ImeSelect, + ime_ImeSetActiveContext, + ime_ImeSetCompositionString, + ime_ImeToAsciiEx, + ime_ImeUnregisterWord, + ime_NotifyIME, + ime_DllMain, +}; + static UINT ime_count; static WCHAR ime_path[MAX_PATH]; static HKL ime_install(void) { WCHAR buffer[MAX_PATH]; + HMODULE module; DWORD len, ret; HKEY hkey; HKL hkl; + /* IME module gets cached and won't reload from disk as soon as a window has + * loaded it. To workaround the issue we load the module first as a DLL, + * set its function pointers from the test, and later when the cached IME + * gets loaded, read the function pointers from the separately loaded DLL. + */ + + load_resource( L"ime_wrapper.dll", buffer ); + + SetLastError( 0xdeadbeef ); + ret = MoveFileW( buffer, L"c:\\windows\\system32\\winetest_ime.dll" ); + if (!ret) + { + ok( GetLastError() == ERROR_ACCESS_DENIED, "got error %lu\n", GetLastError() ); + win_skip( "Failed to copy DLL to system directory\n" ); + return 0; + } + + module = LoadLibraryW( L"c:\\windows\\system32\\winetest_ime.dll" ); + ok( !!module, "LoadLibraryW failed, error %lu\n", GetLastError() ); + *(struct ime_functions *)GetProcAddress( module, "ime_functions" ) = ime_functions; + /* install the actual IME module, it will lookup the functions from the DLL */ load_resource( L"ime_wrapper.dll", buffer ); @@ -2532,6 +2735,7 @@ static HKL ime_install(void) static void ime_cleanup( HKL hkl ) { + HMODULE module = GetModuleHandleW( L"winetest_ime.dll" ); WCHAR buffer[MAX_PATH], value[MAX_PATH]; DWORD i, buffer_len, value_len, ret; HKEY hkey; @@ -2565,6 +2769,12 @@ static void ime_cleanup( HKL hkl ) todo_wine_if( GetLastError() == ERROR_ACCESS_DENIED ) ok( ret || broken( !ret ) /* sometimes still in use */, "DeleteFileW failed, error %lu\n", GetLastError() ); + + ret = FreeLibrary( module ); + ok( ret, "FreeLibrary failed, error %lu\n", GetLastError() ); + + ret = DeleteFileW( L"c:\\windows\\system32\\winetest_ime.dll" ); + ok( ret, "DeleteFileW failed, error %lu\n", GetLastError() ); } static void test_ImmInstallIME(void) From 7cd3a386dca8065898eda345eeea66ad722ed7fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 Mar 2023 19:19:06 +0100 Subject: [PATCH 1685/2777] imm32/tests: Test ImmGetDescription with the installed IME. (cherry picked from commit d0cc3ded0854c5140612d858b854404e70ef7470) --- dlls/imm32/tests/imm32.c | 136 +++++++++++++++++++++++---------------- 1 file changed, 80 insertions(+), 56 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 0fd88d65aac..9e24f899f3f 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -1186,61 +1186,6 @@ static void test_ImmGetContext(void) ok(ImmReleaseContext(hwnd, himc), "ImmReleaseContext failed\n"); } -static void test_ImmGetDescription(void) -{ - HKL hkl; - WCHAR descW[100]; - CHAR descA[100]; - UINT ret, lret; - - /* FIXME: invalid keyboard layouts should not pass */ - ret = ImmGetDescriptionW(NULL, NULL, 0); - ok(!ret, "ImmGetDescriptionW failed, expected 0 received %d.\n", ret); - ret = ImmGetDescriptionA(NULL, NULL, 0); - ok(!ret, "ImmGetDescriptionA failed, expected 0 received %d.\n", ret); - - /* load a language with valid IMM descriptions */ - hkl = GetKeyboardLayout(0); - ok(hkl != 0, "GetKeyboardLayout failed, expected != 0.\n"); - - ret = ImmGetDescriptionW(hkl, NULL, 0); - if(!ret) - { - win_skip("ImmGetDescriptionW is not working for current loaded keyboard.\n"); - return; - } - - SetLastError(0xdeadcafe); - ret = ImmGetDescriptionW(0, NULL, 100); - ok (ret == 0, "ImmGetDescriptionW with 0 hkl should return 0\n"); - ret = GetLastError(); - ok (ret == 0xdeadcafe, "Last Error should remain unchanged\n"); - - ret = ImmGetDescriptionW(hkl, descW, 0); - ok(ret, "ImmGetDescriptionW failed, expected != 0 received 0.\n"); - - lret = ImmGetDescriptionW(hkl, descW, ret + 1); - ok(lret, "ImmGetDescriptionW failed, expected != 0 received 0.\n"); - ok(lret == ret, "ImmGetDescriptionW failed to return the correct amount of data. Expected %d, got %d.\n", ret, lret); - - lret = ImmGetDescriptionA(hkl, descA, ret + 1); - ok(lret, "ImmGetDescriptionA failed, expected != 0 received 0.\n"); - ok(lret == ret, "ImmGetDescriptionA failed to return the correct amount of data. Expected %d, got %d.\n", ret, lret); - - ret /= 2; /* try to copy partially */ - lret = ImmGetDescriptionW(hkl, descW, ret + 1); - ok(lret, "ImmGetDescriptionW failed, expected != 0 received 0.\n"); - ok(lret == ret, "ImmGetDescriptionW failed to return the correct amount of data. Expected %d, got %d.\n", ret, lret); - - lret = ImmGetDescriptionA(hkl, descA, ret + 1); - ok(!lret, "ImmGetDescriptionA should fail\n"); - - ret = ImmGetDescriptionW(hkl, descW, 1); - ok(!ret, "ImmGetDescriptionW failed, expected 0 received %d.\n", ret); - - UnloadKeyboardLayout(hkl); -} - static LRESULT (WINAPI *old_imm_wnd_proc)(HWND, UINT, WPARAM, LPARAM); static LRESULT WINAPI imm_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { @@ -2786,6 +2731,85 @@ static void test_ImmInstallIME(void) ime_cleanup( hkl ); } +static void test_ImmGetDescription(void) +{ + HKL hkl = GetKeyboardLayout( 0 ); + WCHAR bufferW[MAX_PATH]; + char bufferA[MAX_PATH]; + DWORD ret; + + SetLastError( 0xdeadbeef ); + ret = ImmGetDescriptionW( NULL, NULL, 0 ); + ok( !ret, "ImmGetDescriptionW returned %lu\n", ret ); + ret = ImmGetDescriptionA( NULL, NULL, 0 ); + ok( !ret, "ImmGetDescriptionA returned %lu\n", ret ); + ret = ImmGetDescriptionW( NULL, NULL, 100 ); + ok( !ret, "ImmGetDescriptionW returned %lu\n", ret ); + ret = ImmGetDescriptionA( NULL, NULL, 100 ); + ok( !ret, "ImmGetDescriptionA returned %lu\n", ret ); + ret = ImmGetDescriptionW( hkl, bufferW, 100 ); + todo_wine + ok( !ret, "ImmGetDescriptionW returned %lu\n", ret ); + ret = ImmGetDescriptionA( hkl, bufferA, 100 ); + todo_wine + ok( !ret, "ImmGetDescriptionA returned %lu\n", ret ); + ret = GetLastError(); + ok( ret == 0xdeadbeef, "got error %lu\n", ret ); + + if (!(hkl = ime_install())) return; + + memset( bufferW, 0xcd, sizeof(bufferW) ); + ret = ImmGetDescriptionW( hkl, bufferW, 2 ); + ok( ret == 1, "ImmGetDescriptionW returned %lu\n", ret ); + ok( !wcscmp( bufferW, L"W" ), "got bufferW %s\n", debugstr_w(bufferW) ); + memset( bufferA, 0xcd, sizeof(bufferA) ); + ret = ImmGetDescriptionA( hkl, bufferA, 2 ); + ok( ret == 0, "ImmGetDescriptionA returned %lu\n", ret ); + todo_wine + ok( !strcmp( bufferA, "" ), "got bufferA %s\n", debugstr_a(bufferA) ); + + memset( bufferW, 0xcd, sizeof(bufferW) ); + ret = ImmGetDescriptionW( hkl, bufferW, 11 ); + todo_wine + ok( ret == 10, "ImmGetDescriptionW returned %lu\n", ret ); + todo_wine + ok( !wcscmp( bufferW, L"WineTest I" ), "got bufferW %s\n", debugstr_w(bufferW) ); + memset( bufferA, 0xcd, sizeof(bufferA) ); + ret = ImmGetDescriptionA( hkl, bufferA, 11 ); + todo_wine + ok( ret == 0, "ImmGetDescriptionA returned %lu\n", ret ); + todo_wine + ok( !strcmp( bufferA, "" ), "got bufferA %s\n", debugstr_a(bufferA) ); + + memset( bufferW, 0xcd, sizeof(bufferW) ); + ret = ImmGetDescriptionW( hkl, bufferW, 12 ); + todo_wine + ok( ret == 11, "ImmGetDescriptionW returned %lu\n", ret ); + todo_wine + ok( !wcscmp( bufferW, L"WineTest IM" ), "got bufferW %s\n", debugstr_w(bufferW) ); + memset( bufferA, 0xcd, sizeof(bufferA) ); + ret = ImmGetDescriptionA( hkl, bufferA, 12 ); + todo_wine + ok( ret == 12, "ImmGetDescriptionA returned %lu\n", ret ); + todo_wine + ok( !strcmp( bufferA, "WineTest IME" ), "got bufferA %s\n", debugstr_a(bufferA) ); + + memset( bufferW, 0xcd, sizeof(bufferW) ); + ret = ImmGetDescriptionW( hkl, bufferW, 13 ); + todo_wine + ok( ret == 12, "ImmGetDescriptionW returned %lu\n", ret ); + todo_wine + ok( !wcscmp( bufferW, L"WineTest IME" ), "got bufferW %s\n", debugstr_w(bufferW) ); + memset( bufferA, 0xcd, sizeof(bufferA) ); + ret = ImmGetDescriptionA( hkl, bufferA, 13 ); + todo_wine + ok( ret == 12, "ImmGetDescriptionA returned %lu\n", ret ); + todo_wine + ok( !strcmp( bufferA, "WineTest IME" ), "got bufferA %s\n", debugstr_a(bufferA) ); + + ime_cleanup( hkl ); +} + START_TEST(imm32) { if (!is_ime_enabled()) @@ -2797,6 +2821,7 @@ START_TEST(imm32) test_com_initialization(); test_ImmInstallIME(); + test_ImmGetDescription(); if (init()) { @@ -2809,7 +2834,6 @@ START_TEST(imm32) test_ImmThreads(); test_ImmIsUIMessage(); test_ImmGetContext(); - test_ImmGetDescription(); test_ImmDefaultHwnd(); test_default_ime_window_creation(); test_ImmGetIMCLockCount(); From 75de2ebb2964b52f527bc16a4fe95a13e496418d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 18 Feb 2023 10:33:33 +0100 Subject: [PATCH 1686/2777] imm32/tests: Test ImmGetIMEFileName with the installed IME. (cherry picked from commit 313611532405f9b0ac894d42f09832711105f678) --- dlls/imm32/tests/imm32.c | 84 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 9e24f899f3f..97f3a5394ea 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2810,6 +2810,89 @@ static void test_ImmGetDescription(void) ime_cleanup( hkl ); } +static void test_ImmGetIMEFileName(void) +{ + HKL hkl = GetKeyboardLayout( 0 ); + WCHAR bufferW[MAX_PATH], expectW[16]; + char bufferA[MAX_PATH], expectA[16]; + DWORD ret; + + SetLastError( 0xdeadbeef ); + ret = ImmGetIMEFileNameW( NULL, NULL, 0 ); + ok( !ret, "ImmGetIMEFileNameW returned %lu\n", ret ); + ret = ImmGetIMEFileNameA( NULL, NULL, 0 ); + ok( !ret, "ImmGetIMEFileNameA returned %lu\n", ret ); + ret = ImmGetIMEFileNameW( NULL, NULL, 100 ); + ok( !ret, "ImmGetIMEFileNameW returned %lu\n", ret ); + ret = ImmGetIMEFileNameA( NULL, NULL, 100 ); + ok( !ret, "ImmGetIMEFileNameA returned %lu\n", ret ); + ret = ImmGetIMEFileNameW( hkl, bufferW, 100 ); + ok( !ret, "ImmGetIMEFileNameW returned %lu\n", ret ); + ret = ImmGetIMEFileNameA( hkl, bufferA, 100 ); + ok( !ret, "ImmGetIMEFileNameA returned %lu\n", ret ); + ret = GetLastError(); + todo_wine + ok( ret == 0xdeadbeef, "got error %lu\n", ret ); + + if (!(hkl = ime_install())) return; + + memset( bufferW, 0xcd, sizeof(bufferW) ); + ret = ImmGetIMEFileNameW( hkl, bufferW, 2 ); + todo_wine + ok( ret == 1, "ImmGetIMEFileNameW returned %lu\n", ret ); + todo_wine + ok( !wcscmp( bufferW, L"W" ), "got bufferW %s\n", debugstr_w(bufferW) ); + memset( bufferA, 0xcd, sizeof(bufferA) ); + ret = ImmGetIMEFileNameA( hkl, bufferA, 2 ); + ok( ret == 0, "ImmGetIMEFileNameA returned %lu\n", ret ); + todo_wine + ok( !strcmp( bufferA, "" ), "got bufferA %s\n", debugstr_a(bufferA) ); + + swprintf( expectW, ARRAY_SIZE(expectW), L"WINE%04X.I", ime_count - 1 ); + memset( bufferW, 0xcd, sizeof(bufferW) ); + ret = ImmGetIMEFileNameW( hkl, bufferW, 11 ); + todo_wine + ok( ret == 10, "ImmGetIMEFileNameW returned %lu\n", ret ); + todo_wine + ok( !wcscmp( bufferW, expectW ), "got bufferW %s\n", debugstr_w(bufferW) ); + memset( bufferA, 0xcd, sizeof(bufferA) ); + ret = ImmGetIMEFileNameA( hkl, bufferA, 11 ); + ok( ret == 0, "ImmGetIMEFileNameA returned %lu\n", ret ); + todo_wine + ok( !strcmp( bufferA, "" ), "got bufferA %s\n", debugstr_a(bufferA) ); + + swprintf( expectW, ARRAY_SIZE(expectW), L"WINE%04X.IM", ime_count - 1 ); + memset( bufferW, 0xcd, sizeof(bufferW) ); + ret = ImmGetIMEFileNameW( hkl, bufferW, 12 ); + todo_wine + ok( ret == 11, "ImmGetIMEFileNameW returned %lu\n", ret ); + todo_wine + ok( !wcscmp( bufferW, expectW ), "got bufferW %s\n", debugstr_w(bufferW) ); + snprintf( expectA, ARRAY_SIZE(expectA), "WINE%04X.IME", ime_count - 1 ); + memset( bufferA, 0xcd, sizeof(bufferA) ); + ret = ImmGetIMEFileNameA( hkl, bufferA, 12 ); + todo_wine + ok( ret == 12, "ImmGetIMEFileNameA returned %lu\n", ret ); + todo_wine + ok( !strcmp( bufferA, expectA ), "got bufferA %s\n", debugstr_a(bufferA) ); + + swprintf( expectW, ARRAY_SIZE(expectW), L"WINE%04X.IME", ime_count - 1 ); + memset( bufferW, 0xcd, sizeof(bufferW) ); + ret = ImmGetIMEFileNameW( hkl, bufferW, 13 ); + todo_wine + ok( ret == 12, "ImmGetIMEFileNameW returned %lu\n", ret ); + todo_wine + ok( !wcscmp( bufferW, expectW ), "got bufferW %s\n", debugstr_w(bufferW) ); + memset( bufferA, 0xcd, sizeof(bufferA) ); + ret = ImmGetIMEFileNameA( hkl, bufferA, 13 ); + todo_wine + ok( ret == 12, "ImmGetIMEFileNameA returned %lu\n", ret ); + todo_wine + ok( !strcmp( bufferA, expectA ), "got bufferA %s\n", debugstr_a(bufferA) ); + + ime_cleanup( hkl ); +} + START_TEST(imm32) { if (!is_ime_enabled()) @@ -2822,6 +2905,7 @@ START_TEST(imm32) test_ImmInstallIME(); test_ImmGetDescription(); + test_ImmGetIMEFileName(); if (init()) { From 6c44aa8515e6351f4b3a9318bfc81fa19ea5fbb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 1 Mar 2023 22:57:29 +0100 Subject: [PATCH 1687/2777] user32/tests: Skip tests if layout failed to activate. (cherry picked from commit 9f072a273d35d29bd5ae09b9c6ba00ffd63236a6) --- dlls/user32/tests/input.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 1a9757bd1fb..fa659a3834a 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -3307,7 +3307,20 @@ static void test_keyboard_layout_name(void) for (i = len - 1; i >= 0; --i) { id = (DWORD_PTR)layouts[i]; + + winetest_push_context( "%08lx", id ); + ActivateKeyboardLayout(layouts[i], 0); + + tmplayout = GetKeyboardLayout(0); + todo_wine_if(tmplayout != layouts[i]) + ok( tmplayout == layouts[i], "Failed to activate keyboard layout\n"); + if (tmplayout != layouts[i]) + { + winetest_pop_context(); + continue; + } + GetKeyboardLayoutNameW(klid); for (j = 0; j < len; ++j) @@ -3346,6 +3359,8 @@ static void test_keyboard_layout_name(void) /* The layout name only depends on the keyboard layout: the high word of HKL. */ GetKeyboardLayoutNameW(tmpklid); ok(!wcsicmp(klid, tmpklid), "GetKeyboardLayoutNameW returned %s, expected %s\n", debugstr_w(tmpklid), debugstr_w(klid)); + + winetest_pop_context(); } ActivateKeyboardLayout(layout, 0); From 46fd9c285d989c577b8fa7c719d0f8c66609db00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 1 Mar 2023 22:57:29 +0100 Subject: [PATCH 1688/2777] user32/tests: Add a WM_INPUTLANGCHANGE message test. (cherry picked from commit 3a4859e22db45289f9b02ea9ab1ccc150b638d19) --- dlls/user32/tests/input.c | 173 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index fa659a3834a..5cb02443e44 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -3369,6 +3369,178 @@ static void test_keyboard_layout_name(void) free(layouts_preload); } +static HKL expect_hkl; +static HKL change_hkl; +static int got_setfocus; + +static LRESULT CALLBACK test_ActivateKeyboardLayout_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + ok( msg != WM_INPUTLANGCHANGEREQUEST, "got WM_INPUTLANGCHANGEREQUEST\n" ); + + if (msg == WM_SETFOCUS) got_setfocus = 1; + if (msg == WM_INPUTLANGCHANGE) + { + HKL layout = GetKeyboardLayout( 0 ); + CHARSETINFO info; + WCHAR klidW[64]; + UINT codepage; + LCID lcid; + + /* get keyboard layout lcid from its name, as the HKL might be aliased */ + GetKeyboardLayoutNameW( klidW ); + swscanf( klidW, L"%x", &lcid ); + lcid = LOWORD(lcid); + + if (!(HIWORD(layout) & 0x8000)) ok( lcid == HIWORD(layout), "got lcid %#lx\n", lcid ); + + GetLocaleInfoA( lcid, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, + (char *)&codepage, sizeof(codepage) ); + TranslateCharsetInfo( UlongToPtr( codepage ), &info, TCI_SRCCODEPAGE ); + + ok( !got_setfocus, "got WM_SETFOCUS before WM_INPUTLANGCHANGE\n" ); + ok( layout == expect_hkl, "got layout %p\n", layout ); + ok( wparam == info.ciCharset || broken(wparam == 0 && (HIWORD(layout) & 0x8000)), + "got wparam %#Ix\n", wparam ); + ok( lparam == (LPARAM)expect_hkl, "got lparam %#Ix\n", lparam ); + change_hkl = (HKL)lparam; + } + + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +static DWORD CALLBACK test_ActivateKeyboardLayout_thread_proc( void *arg ) +{ + ActivateKeyboardLayout( arg, 0 ); + return 0; +} + +static void test_ActivateKeyboardLayout( char **argv ) +{ + HKL layout, tmp_layout, *layouts; + HWND hwnd1, hwnd2; + HANDLE thread; + UINT i, count; + DWORD ret; + + layout = GetKeyboardLayout( 0 ); + count = GetKeyboardLayoutList( 0, NULL ); + ok( count > 0, "GetKeyboardLayoutList returned %d\n", count ); + layouts = malloc( count * sizeof(HKL) ); + ok( layouts != NULL, "Could not allocate memory\n" ); + count = GetKeyboardLayoutList( count, layouts ); + ok( count > 0, "GetKeyboardLayoutList returned %d\n", count ); + + hwnd1 = CreateWindowA( "static", "static", WS_VISIBLE | WS_POPUP, + 100, 100, 100, 100, 0, NULL, NULL, NULL ); + ok( !!hwnd1, "CreateWindow failed, error %lu\n", GetLastError() ); + empty_message_queue(); + + SetWindowLongPtrA( hwnd1, GWLP_WNDPROC, (LONG_PTR)test_ActivateKeyboardLayout_window_proc ); + + for (i = 0; i < count; ++i) + { + BOOL broken_focus_activate = FALSE; + HKL other_layout = layouts[i]; + + winetest_push_context( "%08x / %08x", (UINT)(UINT_PTR)layout, (UINT)(UINT_PTR)other_layout ); + + /* test WM_INPUTLANGCHANGE message */ + + change_hkl = 0; + expect_hkl = other_layout; + got_setfocus = 0; + ActivateKeyboardLayout( other_layout, 0 ); + if (other_layout == layout) ok( change_hkl == 0, "got change_hkl %p\n", change_hkl ); + else todo_wine ok( change_hkl == other_layout, "got change_hkl %p\n", change_hkl ); + change_hkl = expect_hkl = 0; + + tmp_layout = GetKeyboardLayout( 0 ); + todo_wine_if(layout != other_layout) + ok( tmp_layout == other_layout, "got tmp_layout %p\n", tmp_layout ); + + /* changing the layout from another thread doesn't send the message */ + + thread = CreateThread( NULL, 0, test_ActivateKeyboardLayout_thread_proc, layout, 0, 0 ); + ret = WaitForSingleObject( thread, 1000 ); + ok( !ret, "WaitForSingleObject returned %#lx\n", ret ); + CloseHandle( thread ); + + /* and has no immediate effect */ + + empty_message_queue(); + tmp_layout = GetKeyboardLayout( 0 ); + todo_wine_if(layout != other_layout) + ok( tmp_layout == other_layout, "got tmp_layout %p\n", tmp_layout ); + + /* but the change only takes effect after focus changes */ + + hwnd2 = CreateWindowA( "static", "static", WS_VISIBLE | WS_POPUP, + 100, 100, 100, 100, 0, NULL, NULL, NULL ); + ok( !!hwnd2, "CreateWindow failed, error %lu\n", GetLastError() ); + + tmp_layout = GetKeyboardLayout( 0 ); + todo_wine_if(layout != other_layout) + ok( tmp_layout == layout || broken(layout != other_layout && tmp_layout == other_layout) /* w7u */, + "got tmp_layout %p\n", tmp_layout ); + if (broken(layout != other_layout && tmp_layout == other_layout)) + { + win_skip( "Broken layout activation on focus change, skipping some tests\n" ); + broken_focus_activate = TRUE; + } + empty_message_queue(); + + /* only the focused window receives the WM_INPUTLANGCHANGE message */ + + ActivateKeyboardLayout( other_layout, 0 ); + ok( change_hkl == 0, "got change_hkl %p\n", change_hkl ); + + tmp_layout = GetKeyboardLayout( 0 ); + todo_wine_if(layout != other_layout) + ok( tmp_layout == other_layout, "got tmp_layout %p\n", tmp_layout ); + + thread = CreateThread( NULL, 0, test_ActivateKeyboardLayout_thread_proc, layout, 0, 0 ); + ret = WaitForSingleObject( thread, 1000 ); + ok( !ret, "WaitForSingleObject returned %#lx\n", ret ); + CloseHandle( thread ); + + tmp_layout = GetKeyboardLayout( 0 ); + todo_wine_if(layout != other_layout) + ok( tmp_layout == other_layout, "got tmp_layout %p\n", tmp_layout ); + + /* changing focus is enough for the layout change to take effect */ + + change_hkl = 0; + expect_hkl = layout; + got_setfocus = 0; + SetFocus( hwnd1 ); + + if (broken_focus_activate) + { + ok( got_setfocus == 1, "got got_setfocus %d\n", got_setfocus ); + ok( change_hkl == 0, "got change_hkl %p\n", change_hkl ); + got_setfocus = 0; + ActivateKeyboardLayout( layout, 0 ); + } + + if (other_layout == layout) ok( change_hkl == 0, "got change_hkl %p\n", change_hkl ); + else todo_wine ok( change_hkl == layout, "got change_hkl %p\n", change_hkl ); + change_hkl = expect_hkl = 0; + + tmp_layout = GetKeyboardLayout( 0 ); + todo_wine_if(layout != other_layout) + ok( tmp_layout == layout, "got tmp_layout %p\n", tmp_layout ); + + DestroyWindow( hwnd2 ); + empty_message_queue(); + + winetest_pop_context(); + } + + DestroyWindow( hwnd1 ); + + free( layouts ); +} + static void test_key_names(void) { char buffer[40]; @@ -4937,6 +5109,7 @@ START_TEST(input) test_ToAscii(); test_get_async_key_state(); test_keyboard_layout_name(); + test_ActivateKeyboardLayout( argv ); test_key_names(); test_attach_input(); test_GetKeyState(); From a5e9cc80753737bc651436bf46e65de530bdf476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 16 May 2023 15:39:07 +0200 Subject: [PATCH 1689/2777] win32u: Move window query functions around. (cherry picked from commit 30aa9055a0b59887cd2ef35e180ed07a58f98790) --- dlls/win32u/input.c | 86 ++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 9f17b71e0fe..9575a0a1172 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -534,6 +534,49 @@ static WCHAR kbd_tables_vkey_to_wchar( const KBDTABLES *tables, UINT vkey, const BOOL enable_mouse_in_pointer = FALSE; +/******************************************************************* + * NtUserGetForegroundWindow (win32u.@) + */ +HWND WINAPI NtUserGetForegroundWindow(void) +{ + volatile struct input_shared_memory *shared = get_foreground_shared_memory(); + HWND ret = 0; + + if (!shared) return 0; + + SHARED_READ_BEGIN( &shared->seq ) + { + ret = wine_server_ptr_handle( shared->active ); + } + SHARED_READ_END( &shared->seq ); + + return ret; +} + +/* see GetActiveWindow */ +HWND get_active_window(void) +{ + GUITHREADINFO info; + info.cbSize = sizeof(info); + return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndActive : 0; +} + +/* see GetCapture */ +HWND get_capture(void) +{ + GUITHREADINFO info; + info.cbSize = sizeof(info); + return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndCapture : 0; +} + +/* see GetFocus */ +HWND get_focus(void) +{ + GUITHREADINFO info; + info.cbSize = sizeof(info); + return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndFocus : 0; +} + /********************************************************************** * NtUserAttachThreadInput (win32u.@) */ @@ -1711,49 +1754,6 @@ BOOL WINAPI release_capture(void) return ret; } -/******************************************************************* - * NtUserGetForegroundWindow (win32u.@) - */ -HWND WINAPI NtUserGetForegroundWindow(void) -{ - volatile struct input_shared_memory *shared = get_foreground_shared_memory(); - HWND ret = 0; - - if (!shared) return 0; - - SHARED_READ_BEGIN( &shared->seq ) - { - ret = wine_server_ptr_handle( shared->active ); - } - SHARED_READ_END( &shared->seq ); - - return ret; -} - -/* see GetActiveWindow */ -HWND get_active_window(void) -{ - GUITHREADINFO info; - info.cbSize = sizeof(info); - return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndActive : 0; -} - -/* see GetCapture */ -HWND get_capture(void) -{ - GUITHREADINFO info; - info.cbSize = sizeof(info); - return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndCapture : 0; -} - -/* see GetFocus */ -HWND get_focus(void) -{ - GUITHREADINFO info; - info.cbSize = sizeof(info); - return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndFocus : 0; -} - /***************************************************************** * set_focus_window * From 216b37c9742ca3319c83421b264836081e87e642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 3 Mar 2023 13:39:26 +0100 Subject: [PATCH 1690/2777] win32u: Send WM_INPUTLANGCHANGE when activating new layout. (cherry picked from commit fee5eaecb47aca10cd17d5f84e2bbc3ca60bfa44) --- dlls/win32u/input.c | 18 +++++++++++++++++- dlls/win32u/ntgdi_private.h | 1 - dlls/win32u/win32u_private.h | 1 + 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 9575a0a1172..73b50f6d656 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1195,6 +1195,7 @@ HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags ) { struct user_thread_info *info = get_user_thread_info(); HKL old_layout; + HWND focus; TRACE_(keyboard)( "layout %p, flags %x\n", layout, flags ); @@ -1212,7 +1213,22 @@ HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags ) old_layout = info->kbd_layout; info->kbd_layout = layout; - if (old_layout != layout) info->kbd_layout_id = 0; + if (old_layout != layout) + { + const NLS_LOCALE_DATA *data; + CHARSETINFO cs = {0}; + + if (HIWORD(layout) & 0x8000) + FIXME( "Aliased keyboard layout not yet implemented\n" ); + else if (!(data = get_locale_data( HIWORD(layout) ))) + WARN( "Failed to find locale data for %04x\n", HIWORD(layout) ); + else + translate_charset_info( ULongToPtr(data->idefaultansicodepage), &cs, TCI_SRCCODEPAGE ); + + info->kbd_layout_id = 0; + if ((focus = get_focus()) && get_window_thread( focus, NULL ) == GetCurrentThreadId()) + send_message( focus, WM_INPUTLANGCHANGE, cs.ciCharset, (LPARAM)layout ); + } if (!old_layout) return get_locale_kbd_layout(); return old_layout; diff --git a/dlls/win32u/ntgdi_private.h b/dlls/win32u/ntgdi_private.h index ce5e30ab07d..93be59c9d7e 100644 --- a/dlls/win32u/ntgdi_private.h +++ b/dlls/win32u/ntgdi_private.h @@ -368,7 +368,6 @@ extern BOOL opentype_enum_full_names( const struct tt_name_v0 *tt_name_v0, extern BOOL opentype_get_properties( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, DWORD *version, FONTSIGNATURE *fs, DWORD *ntm_flags ) DECLSPEC_HIDDEN; -extern BOOL translate_charset_info( DWORD *src, CHARSETINFO *cs, DWORD flags ) DECLSPEC_HIDDEN; /* gdiobj.c */ extern HGDIOBJ alloc_gdi_handle( struct gdi_obj_header *obj, DWORD type, diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index bba36a43ae0..a885128d3a7 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -458,6 +458,7 @@ extern CPTABLEINFO ansi_cp DECLSPEC_HIDDEN; CPTABLEINFO *get_cptable( WORD cp ) DECLSPEC_HIDDEN; const NLS_LOCALE_DATA *get_locale_data( LCID lcid ) DECLSPEC_HIDDEN; +extern BOOL translate_charset_info( DWORD *src, CHARSETINFO *cs, DWORD flags ) DECLSPEC_HIDDEN; DWORD win32u_mbtowc( CPTABLEINFO *info, WCHAR *dst, DWORD dstlen, const char *src, DWORD srclen ) DECLSPEC_HIDDEN; DWORD win32u_wctomb( CPTABLEINFO *info, char *dst, DWORD dstlen, const WCHAR *src, From 237b3dd34e7457167f03a157c13b52202d7ed589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 14:44:55 +0100 Subject: [PATCH 1691/2777] imm32: Implement stubs for ImmFreeLayout and ImmLoadIME. (cherry picked from commit 89cdae2e515495fe4f9fcdb90b366e29e5df2b8c) --- dlls/imm32/imm.c | 12 ++++++++++++ dlls/imm32/imm32.spec | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 3d9cbf7e198..f9aa6e350c8 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -478,6 +478,18 @@ static HMODULE load_graphics_driver(void) return ret; } +BOOL WINAPI ImmFreeLayout( HKL hkl ) +{ + FIXME( "hkl %p stub!\n", hkl ); + return FALSE; +} + +BOOL WINAPI ImmLoadIME( HKL hkl ) +{ + FIXME( "hkl %p stub!\n", hkl ); + return FALSE; +} + /* ImmHkl loading and freeing */ #define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);} static ImmHkl *IMM_GetImmHkl(HKL hkl) diff --git a/dlls/imm32/imm32.spec b/dlls/imm32/imm32.spec index 70b8aef3a95..9c7ce13319f 100644 --- a/dlls/imm32/imm32.spec +++ b/dlls/imm32/imm32.spec @@ -18,7 +18,7 @@ @ stdcall ImmEnumRegisterWordW(long ptr wstr long wstr ptr) @ stdcall ImmEscapeA(long long long ptr) @ stdcall ImmEscapeW(long long long ptr) -@ stub ImmFreeLayout +@ stdcall ImmFreeLayout(long) @ stdcall ImmGenerateMessage(ptr) @ stdcall ImmGetCandidateListA(long long ptr long) @ stdcall ImmGetCandidateListCountA(long ptr) @@ -66,7 +66,7 @@ @ stdcall ImmIsIME(long) @ stdcall ImmIsUIMessageA(long long long long) @ stdcall ImmIsUIMessageW(long long long long) -@ stub ImmLoadIME +@ stdcall ImmLoadIME(long) @ stub ImmLoadLayout @ stub ImmLockClientImc @ stdcall ImmLockIMC(long) From 5d5b9d3c02edcb5d502f4bdf5ad34521f1a91784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 Mar 2023 19:19:06 +0100 Subject: [PATCH 1692/2777] imm32/tests: Test undocumented ImmLoadIME / ImmFreeLayout. (cherry picked from commit 05cf38bfa63980af7a094b1c087bee4ea36eb485) --- dlls/imm32/tests/imm32.c | 139 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 134 insertions(+), 5 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 97f3a5394ea..9d63c80c514 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -42,6 +42,9 @@ static UINT (WINAPI *pNtUserAssociateInputContext)(HWND,HIMC,ULONG); static BOOL (WINAPI *pImmIsUIMessageA)(HWND,UINT,WPARAM,LPARAM); static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t); +extern BOOL WINAPI ImmFreeLayout(HKL); +extern BOOL WINAPI ImmLoadIME(HKL); + #define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE, enabled_ ## func = FALSE @@ -2422,6 +2425,13 @@ static void test_ImmDisableIME(void) #define ime_trace( msg, ... ) if (winetest_debug > 1) trace( "%04lx:%s " msg, GetCurrentThreadId(), __func__, ## __VA_ARGS__ ) +DEFINE_EXPECT( ImeInquire ); +DEFINE_EXPECT( ImeDestroy ); +DEFINE_EXPECT( IME_DLL_PROCESS_ATTACH ); +DEFINE_EXPECT( IME_DLL_PROCESS_DETACH ); + +static IMEINFO ime_info; + static LRESULT CALLBACK ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); @@ -2457,7 +2467,11 @@ static DWORD WINAPI ime_ImeConversionList( HIMC himc, const WCHAR *source, CANDI static BOOL WINAPI ime_ImeDestroy( UINT force ) { ime_trace( "force %u\n", force ); - ok( 0, "unexpected call\n" ); + + CHECK_EXPECT( ImeDestroy ); + + ok( !force, "got force %u\n", force ); + return TRUE; } @@ -2496,7 +2510,21 @@ static UINT WINAPI ime_ImeGetRegisterWordStyle( UINT item, STYLEBUFW *style ) static BOOL WINAPI ime_ImeInquire( IMEINFO *info, WCHAR *ui_class, DWORD flags ) { ime_trace( "info %p, ui_class %p, flags %#lx\n", info, ui_class, flags ); - ok( 0, "unexpected call\n" ); + + CHECK_EXPECT( ImeInquire ); + + ok( !!info, "got info %p\n", info ); + ok( !!ui_class, "got ui_class %p\n", ui_class ); + ok( !flags, "got flags %#lx\n", flags ); + + *info = ime_info; + + if (ime_info.fdwProperty & IME_PROP_UNICODE) + wcscpy( ui_class, ime_ui_class.lpszClassName ); + else + WideCharToMultiByte( CP_ACP, 0, ime_ui_class.lpszClassName, -1, + (char *)ui_class, 17, NULL, NULL ); + return TRUE; } @@ -2570,10 +2598,12 @@ static BOOL WINAPI ime_DllMain( HINSTANCE instance, DWORD reason, LPVOID reserve DisableThreadLibraryCalls( instance ); ime_ui_class.hInstance = instance; RegisterClassExW( &ime_ui_class ); + CHECK_EXPECT( IME_DLL_PROCESS_ATTACH ); break; case DLL_PROCESS_DETACH: UnregisterClassW( ime_ui_class.lpszClassName, instance ); + todo_wine CHECK_EXPECT( IME_DLL_PROCESS_DETACH ); break; } @@ -2724,11 +2754,88 @@ static void ime_cleanup( HKL hkl ) static void test_ImmInstallIME(void) { + UINT ret; HKL hkl; - if (!(hkl = ime_install())) return; + SET_ENABLE( IME_DLL_PROCESS_ATTACH, TRUE ); + SET_ENABLE( ImeInquire, TRUE ); + SET_ENABLE( ImeDestroy, TRUE ); + SET_ENABLE( IME_DLL_PROCESS_DETACH, TRUE ); + + /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ + ime_info.fdwProperty = IME_PROP_END_UNLOAD; + + if (!(hkl = ime_install())) goto cleanup; + + SET_EXPECT( IME_DLL_PROCESS_ATTACH ); + SET_EXPECT( ImeInquire ); + ret = ImmLoadIME( hkl ); + todo_wine + ok( ret, "ImmLoadIME returned %#x\n", ret ); + todo_wine + CHECK_CALLED( IME_DLL_PROCESS_ATTACH ); + todo_wine + CHECK_CALLED( ImeInquire ); + + ret = ImmLoadIME( hkl ); + todo_wine + ok( ret, "ImmLoadIME returned %#x\n", ret ); + + SET_EXPECT( ImeDestroy ); + SET_EXPECT( IME_DLL_PROCESS_DETACH ); + ret = ImmFreeLayout( hkl ); + todo_wine + ok( ret, "ImmFreeLayout returned %#x\n", ret ); + todo_wine + CHECK_CALLED( ImeDestroy ); + todo_wine + CHECK_CALLED( IME_DLL_PROCESS_DETACH ); + + ret = ImmFreeLayout( hkl ); + todo_wine + ok( ret, "ImmFreeLayout returned %#x\n", ret ); + + ime_cleanup( hkl ); + + ime_info.fdwProperty = 0; + + if (!(hkl = ime_install())) goto cleanup; + + SET_EXPECT( IME_DLL_PROCESS_ATTACH ); + SET_EXPECT( ImeInquire ); + ret = ImmLoadIME( hkl ); + todo_wine + ok( ret, "ImmLoadIME returned %#x\n", ret ); + todo_wine + CHECK_CALLED( IME_DLL_PROCESS_ATTACH ); + todo_wine + CHECK_CALLED( ImeInquire ); + + ret = ImmLoadIME( hkl ); + todo_wine + ok( ret, "ImmLoadIME returned %#x\n", ret ); + + SET_EXPECT( ImeDestroy ); + SET_EXPECT( IME_DLL_PROCESS_DETACH ); + ret = ImmFreeLayout( hkl ); + todo_wine + ok( ret, "ImmFreeLayout returned %#x\n", ret ); + todo_wine + CHECK_CALLED( ImeDestroy ); + todo_wine + CHECK_CALLED( IME_DLL_PROCESS_DETACH ); + + ret = ImmFreeLayout( hkl ); + todo_wine + ok( ret, "ImmFreeLayout returned %#x\n", ret ); ime_cleanup( hkl ); + +cleanup: + SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); + SET_ENABLE( ImeInquire, FALSE ); + SET_ENABLE( ImeDestroy, FALSE ); + SET_ENABLE( IME_DLL_PROCESS_DETACH, FALSE ); } static void test_ImmGetDescription(void) @@ -2738,6 +2845,11 @@ static void test_ImmGetDescription(void) char bufferA[MAX_PATH]; DWORD ret; + SET_ENABLE( IME_DLL_PROCESS_ATTACH, TRUE ); + SET_ENABLE( ImeInquire, TRUE ); + SET_ENABLE( ImeDestroy, TRUE ); + SET_ENABLE( IME_DLL_PROCESS_DETACH, TRUE ); + SetLastError( 0xdeadbeef ); ret = ImmGetDescriptionW( NULL, NULL, 0 ); ok( !ret, "ImmGetDescriptionW returned %lu\n", ret ); @@ -2756,7 +2868,7 @@ static void test_ImmGetDescription(void) ret = GetLastError(); ok( ret == 0xdeadbeef, "got error %lu\n", ret ); - if (!(hkl = ime_install())) return; + if (!(hkl = ime_install())) goto cleanup; memset( bufferW, 0xcd, sizeof(bufferW) ); ret = ImmGetDescriptionW( hkl, bufferW, 2 ); @@ -2808,6 +2920,12 @@ static void test_ImmGetDescription(void) ok( !strcmp( bufferA, "WineTest IME" ), "got bufferA %s\n", debugstr_a(bufferA) ); ime_cleanup( hkl ); + +cleanup: + SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); + SET_ENABLE( ImeInquire, FALSE ); + SET_ENABLE( ImeDestroy, FALSE ); + SET_ENABLE( IME_DLL_PROCESS_DETACH, FALSE ); } static void test_ImmGetIMEFileName(void) @@ -2817,6 +2935,11 @@ static void test_ImmGetIMEFileName(void) char bufferA[MAX_PATH], expectA[16]; DWORD ret; + SET_ENABLE( IME_DLL_PROCESS_ATTACH, TRUE ); + SET_ENABLE( ImeInquire, TRUE ); + SET_ENABLE( ImeDestroy, TRUE ); + SET_ENABLE( IME_DLL_PROCESS_DETACH, TRUE ); + SetLastError( 0xdeadbeef ); ret = ImmGetIMEFileNameW( NULL, NULL, 0 ); ok( !ret, "ImmGetIMEFileNameW returned %lu\n", ret ); @@ -2834,7 +2957,7 @@ static void test_ImmGetIMEFileName(void) todo_wine ok( ret == 0xdeadbeef, "got error %lu\n", ret ); - if (!(hkl = ime_install())) return; + if (!(hkl = ime_install())) goto cleanup; memset( bufferW, 0xcd, sizeof(bufferW) ); ret = ImmGetIMEFileNameW( hkl, bufferW, 2 ); @@ -2891,6 +3014,12 @@ static void test_ImmGetIMEFileName(void) ok( !strcmp( bufferA, expectA ), "got bufferA %s\n", debugstr_a(bufferA) ); ime_cleanup( hkl ); + +cleanup: + SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); + SET_ENABLE( ImeInquire, FALSE ); + SET_ENABLE( ImeDestroy, FALSE ); + SET_ENABLE( IME_DLL_PROCESS_DETACH, FALSE ); } START_TEST(imm32) From 21410f6babc8a93338766c75ef5d21f8cea3152c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 11:27:38 +0100 Subject: [PATCH 1693/2777] imm32: Rename ImmHkl to struct ime. (cherry picked from commit 8f12fac6816da14b681e6bc3edcdc0994e2a8aa0) --- dlls/imm32/imm.c | 59 ++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index f9aa6e350c8..403ff17ad5c 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -52,7 +52,8 @@ static UINT WM_MSIME_RECONVERT; static UINT WM_MSIME_QUERYPOSITION; static UINT WM_MSIME_DOCUMENTFEED; -typedef struct _tagImmHkl{ +struct ime +{ struct list entry; HKL hkl; HMODULE hIME; @@ -78,7 +79,7 @@ typedef struct _tagImmHkl{ BOOL (WINAPI *pImeProcessKey)(HIMC, UINT, LPARAM, const BYTE *); UINT (WINAPI *pImeGetRegisterWordStyle)(UINT, STYLEBUFW *); DWORD (WINAPI *pImeGetImeMenuItems)(HIMC, DWORD, DWORD, IMEMENUITEMINFOW *, IMEMENUITEMINFOW *, DWORD); -} ImmHkl; +}; static HRESULT (WINAPI *pCoRevokeInitializeSpy)(ULARGE_INTEGER cookie); static void (WINAPI *pCoUninitialize)(void); @@ -90,7 +91,7 @@ typedef struct tagInputContextData INPUTCONTEXT IMC; DWORD threadID; - ImmHkl *immKbd; + struct ime *immKbd; UINT lastVK; BOOL threadDefault; } InputContextData; @@ -120,7 +121,7 @@ static inline BOOL is_himc_ime_unicode(const InputContextData *data) return !!(data->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE); } -static inline BOOL is_kbd_ime_unicode(const ImmHkl *hkl) +static inline BOOL is_kbd_ime_unicode( const struct ime *hkl ) { return !!(hkl->imeInfo.fdwProperty & IME_PROP_UNICODE); } @@ -490,23 +491,23 @@ BOOL WINAPI ImmLoadIME( HKL hkl ) return FALSE; } -/* ImmHkl loading and freeing */ +/* struct ime loading and freeing */ #define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);} -static ImmHkl *IMM_GetImmHkl(HKL hkl) +static struct ime *IMM_GetImmHkl( HKL hkl ) { - ImmHkl *ptr; + struct ime *ptr; WCHAR filename[MAX_PATH]; TRACE("Seeking ime for keyboard %p\n",hkl); - LIST_FOR_EACH_ENTRY(ptr, &ImmHklList, ImmHkl, entry) + LIST_FOR_EACH_ENTRY( ptr, &ImmHklList, struct ime, entry ) { if (ptr->hkl == hkl) return ptr; } /* not found... create it */ - ptr = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ImmHkl)); + ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct ime) ); ptr->hkl = hkl; if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename); @@ -563,9 +564,9 @@ static ImmHkl *IMM_GetImmHkl(HKL hkl) static void IMM_FreeAllImmHkl(void) { - ImmHkl *ptr,*cursor2; + struct ime *ptr, *cursor2; - LIST_FOR_EACH_ENTRY_SAFE(ptr, cursor2, &ImmHklList, ImmHkl, entry) + LIST_FOR_EACH_ENTRY_SAFE( ptr, cursor2, &ImmHklList, struct ime, entry ) { list_remove(&ptr->entry); if (ptr->hIME) @@ -762,7 +763,7 @@ BOOL WINAPI ImmAssociateContextEx(HWND hwnd, HIMC imc, DWORD flags) BOOL WINAPI ImmConfigureIMEA( HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) { - ImmHkl *immHkl = IMM_GetImmHkl(hKL); + struct ime *immHkl = IMM_GetImmHkl( hKL ); TRACE("(%p, %p, %ld, %p):\n", hKL, hWnd, dwMode, lpData); @@ -797,7 +798,7 @@ BOOL WINAPI ImmConfigureIMEA( BOOL WINAPI ImmConfigureIMEW( HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) { - ImmHkl *immHkl = IMM_GetImmHkl(hKL); + struct ime *immHkl = IMM_GetImmHkl( hKL ); TRACE("(%p, %p, %ld, %p):\n", hKL, hWnd, dwMode, lpData); @@ -938,7 +939,7 @@ UINT WINAPI ImmEnumRegisterWordA( LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister, LPVOID lpData) { - ImmHkl *immHkl = IMM_GetImmHkl(hKL); + struct ime *immHkl = IMM_GetImmHkl( hKL ); TRACE("(%p, %p, %s, %ld, %s, %p):\n", hKL, lpfnEnumProc, debugstr_a(lpszReading), dwStyle, debugstr_a(lpszRegister), lpData); if (immHkl->hIME && immHkl->pImeEnumRegisterWord) @@ -973,7 +974,7 @@ UINT WINAPI ImmEnumRegisterWordW( LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister, LPVOID lpData) { - ImmHkl *immHkl = IMM_GetImmHkl(hKL); + struct ime *immHkl = IMM_GetImmHkl( hKL ); TRACE("(%p, %p, %s, %ld, %s, %p):\n", hKL, lpfnEnumProc, debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister), lpData); if (immHkl->hIME && immHkl->pImeEnumRegisterWord) @@ -1016,7 +1017,7 @@ LRESULT WINAPI ImmEscapeA( HKL hKL, HIMC hIMC, UINT uEscape, LPVOID lpData) { - ImmHkl *immHkl = IMM_GetImmHkl(hKL); + struct ime *immHkl = IMM_GetImmHkl( hKL ); TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData); if (immHkl->hIME && immHkl->pImeEscape) @@ -1051,7 +1052,7 @@ LRESULT WINAPI ImmEscapeW( HKL hKL, HIMC hIMC, UINT uEscape, LPVOID lpData) { - ImmHkl *immHkl = IMM_GetImmHkl(hKL); + struct ime *immHkl = IMM_GetImmHkl( hKL ); TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData); if (immHkl->hIME && immHkl->pImeEscape) @@ -1620,7 +1621,7 @@ DWORD WINAPI ImmGetConversionListA( LPCSTR pSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen, UINT uFlag) { - ImmHkl *immHkl = IMM_GetImmHkl(hKL); + struct ime *immHkl = IMM_GetImmHkl( hKL ); TRACE("(%p, %p, %s, %p, %ld, %d):\n", hKL, hIMC, debugstr_a(pSrc), lpDst, dwBufLen, uFlag); if (immHkl->hIME && immHkl->pImeConversionList) @@ -1658,7 +1659,7 @@ DWORD WINAPI ImmGetConversionListW( LPCWSTR pSrc, LPCANDIDATELIST lpDst, DWORD dwBufLen, UINT uFlag) { - ImmHkl *immHkl = IMM_GetImmHkl(hKL); + struct ime *immHkl = IMM_GetImmHkl( hKL ); TRACE("(%p, %p, %s, %p, %ld, %d):\n", hKL, hIMC, debugstr_w(pSrc), lpDst, dwBufLen, uFlag); if (immHkl->hIME && immHkl->pImeConversionList) @@ -1895,7 +1896,7 @@ BOOL WINAPI ImmGetOpenStatus(HIMC hIMC) DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex) { DWORD rc = 0; - ImmHkl *kbd; + struct ime *kbd; TRACE("(%p, %ld)\n", hKL, fdwIndex); kbd = IMM_GetImmHkl(hKL); @@ -1923,7 +1924,7 @@ DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex) UINT WINAPI ImmGetRegisterWordStyleA( HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf) { - ImmHkl *immHkl = IMM_GetImmHkl(hKL); + struct ime *immHkl = IMM_GetImmHkl( hKL ); TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf); if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle) { @@ -1951,7 +1952,7 @@ UINT WINAPI ImmGetRegisterWordStyleA( UINT WINAPI ImmGetRegisterWordStyleW( HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf) { - ImmHkl *immHkl = IMM_GetImmHkl(hKL); + struct ime *immHkl = IMM_GetImmHkl( hKL ); TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf); if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle) { @@ -2102,7 +2103,7 @@ HKL WINAPI ImmInstallIMEW( */ BOOL WINAPI ImmIsIME(HKL hKL) { - ImmHkl *ptr; + struct ime *ptr; TRACE("(%p):\n", hKL); ptr = IMM_GetImmHkl(hKL); return (ptr && ptr->hIME); @@ -2183,7 +2184,7 @@ BOOL WINAPI ImmNotifyIME( BOOL WINAPI ImmRegisterWordA( HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister) { - ImmHkl *immHkl = IMM_GetImmHkl(hKL); + struct ime *immHkl = IMM_GetImmHkl( hKL ); TRACE("(%p, %s, %ld, %s):\n", hKL, debugstr_a(lpszReading), dwStyle, debugstr_a(lpszRegister)); if (immHkl->hIME && immHkl->pImeRegisterWord) @@ -2213,7 +2214,7 @@ BOOL WINAPI ImmRegisterWordA( BOOL WINAPI ImmRegisterWordW( HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister) { - ImmHkl *immHkl = IMM_GetImmHkl(hKL); + struct ime *immHkl = IMM_GetImmHkl( hKL ); TRACE("(%p, %s, %ld, %s):\n", hKL, debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister)); if (immHkl->hIME && immHkl->pImeRegisterWord) @@ -2673,7 +2674,7 @@ BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID) BOOL WINAPI ImmUnregisterWordA( HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister) { - ImmHkl *immHkl = IMM_GetImmHkl(hKL); + struct ime *immHkl = IMM_GetImmHkl( hKL ); TRACE("(%p, %s, %ld, %s):\n", hKL, debugstr_a(lpszReading), dwStyle, debugstr_a(lpszUnregister)); if (immHkl->hIME && immHkl->pImeUnregisterWord) @@ -2703,7 +2704,7 @@ BOOL WINAPI ImmUnregisterWordA( BOOL WINAPI ImmUnregisterWordW( HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister) { - ImmHkl *immHkl = IMM_GetImmHkl(hKL); + struct ime *immHkl = IMM_GetImmHkl( hKL ); TRACE("(%p, %s, %ld, %s):\n", hKL, debugstr_w(lpszReading), dwStyle, debugstr_w(lpszUnregister)); if (immHkl->hIME && immHkl->pImeUnregisterWord) @@ -3078,7 +3079,7 @@ BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD /* Make sure we are inputting to the correct keyboard */ if (data->immKbd->hkl != hKL) { - ImmHkl *new_hkl = IMM_GetImmHkl(hKL); + struct ime *new_hkl = IMM_GetImmHkl( hKL ); if (new_hkl) { data->immKbd->pImeSelect(imc, FALSE); @@ -3145,7 +3146,7 @@ BOOL WINAPI ImmDisableLegacyIME(void) static HWND get_ui_window(HKL hkl) { - ImmHkl *immHkl = IMM_GetImmHkl(hkl); + struct ime *immHkl = IMM_GetImmHkl( hkl ); return immHkl->UIWnd; } From b6bff02fc0d57532788d427c62d8dfffa15a919b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 13:30:36 +0100 Subject: [PATCH 1694/2777] imm32: Reorder control flow in ImmConfigureIMEA. (cherry picked from commit e0229ba326ffb67c108845aae4b6b1df48ac4917) --- dlls/imm32/imm.c | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 403ff17ad5c..64351a8a787 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -760,36 +760,30 @@ BOOL WINAPI ImmAssociateContextEx(HWND hwnd, HIMC imc, DWORD flags) /*********************************************************************** * ImmConfigureIMEA (IMM32.@) */ -BOOL WINAPI ImmConfigureIMEA( - HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) +BOOL WINAPI ImmConfigureIMEA( HKL hkl, HWND hwnd, DWORD mode, void *data ) { - struct ime *immHkl = IMM_GetImmHkl( hKL ); + struct ime *ime = IMM_GetImmHkl( hkl ); + BOOL ret; - TRACE("(%p, %p, %ld, %p):\n", hKL, hWnd, dwMode, lpData); + TRACE( "hkl %p, hwnd %p, mode %lu, data %p.\n", hkl, hwnd, mode, data ); - if (dwMode == IME_CONFIG_REGISTERWORD && !lpData) - return FALSE; + if (mode == IME_CONFIG_REGISTERWORD && !data) return FALSE; + if (!ime->hIME || !ime->pImeConfigure) return FALSE; - if (immHkl->hIME && immHkl->pImeConfigure) + if (mode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode( ime )) + ret = ime->pImeConfigure( hkl, hwnd, mode, data ); + else { - if (dwMode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode(immHkl)) - return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData); - else - { - REGISTERWORDW rww; - REGISTERWORDA *rwa = lpData; - BOOL rc; - - rww.lpReading = strdupAtoW(rwa->lpReading); - rww.lpWord = strdupAtoW(rwa->lpWord); - rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rww); - HeapFree(GetProcessHeap(),0,rww.lpReading); - HeapFree(GetProcessHeap(),0,rww.lpWord); - return rc; - } + REGISTERWORDA *wordA = data; + REGISTERWORDW wordW; + wordW.lpWord = strdupAtoW( wordA->lpWord ); + wordW.lpReading = strdupAtoW( wordA->lpReading ); + ret = ime->pImeConfigure( hkl, hwnd, mode, &wordW ); + HeapFree( GetProcessHeap(), 0, wordW.lpReading ); + HeapFree( GetProcessHeap(), 0, wordW.lpWord ); } - else - return FALSE; + + return ret; } /*********************************************************************** From 7a7c29b7fea9a5ee60f6f5bf38ff3c0aea0d883a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 13:30:36 +0100 Subject: [PATCH 1695/2777] imm32: Reorder control flow in ImmConfigureIMEW. (cherry picked from commit 38152f893d4a6dd1a7b0e627ff26635d76ee172e) --- dlls/imm32/imm.c | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 64351a8a787..8f1d2822ac9 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -789,36 +789,30 @@ BOOL WINAPI ImmConfigureIMEA( HKL hkl, HWND hwnd, DWORD mode, void *data ) /*********************************************************************** * ImmConfigureIMEW (IMM32.@) */ -BOOL WINAPI ImmConfigureIMEW( - HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) +BOOL WINAPI ImmConfigureIMEW( HKL hkl, HWND hwnd, DWORD mode, void *data ) { - struct ime *immHkl = IMM_GetImmHkl( hKL ); + struct ime *ime = IMM_GetImmHkl( hkl ); + BOOL ret; - TRACE("(%p, %p, %ld, %p):\n", hKL, hWnd, dwMode, lpData); + TRACE( "hkl %p, hwnd %p, mode %lu, data %p.\n", hkl, hwnd, mode, data ); - if (dwMode == IME_CONFIG_REGISTERWORD && !lpData) - return FALSE; + if (mode == IME_CONFIG_REGISTERWORD && !data) return FALSE; + if (!ime->hIME || !ime->pImeConfigure) return FALSE; - if (immHkl->hIME && immHkl->pImeConfigure) + if (mode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode( ime )) + ret = ime->pImeConfigure( hkl, hwnd, mode, data ); + else { - if (dwMode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode(immHkl)) - return immHkl->pImeConfigure(hKL,hWnd,dwMode,lpData); - else - { - REGISTERWORDW *rww = lpData; - REGISTERWORDA rwa; - BOOL rc; - - rwa.lpReading = strdupWtoA(rww->lpReading); - rwa.lpWord = strdupWtoA(rww->lpWord); - rc = immHkl->pImeConfigure(hKL,hWnd,dwMode,&rwa); - HeapFree(GetProcessHeap(),0,rwa.lpReading); - HeapFree(GetProcessHeap(),0,rwa.lpWord); - return rc; - } + REGISTERWORDW *wordW = data; + REGISTERWORDA wordA; + wordA.lpWord = strdupWtoA( wordW->lpWord ); + wordA.lpReading = strdupWtoA( wordW->lpReading ); + ret = ime->pImeConfigure( hkl, hwnd, mode, &wordA ); + HeapFree( GetProcessHeap(), 0, wordA.lpReading ); + HeapFree( GetProcessHeap(), 0, wordA.lpWord ); } - else - return FALSE; + + return ret; } static InputContextData *create_input_context(HIMC default_imc) From ae9dfddf8edac7a63467196c7113dc161b6556f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 13:30:36 +0100 Subject: [PATCH 1696/2777] imm32: Reorder control flow in ImmEnumRegisterWordA. (cherry picked from commit 93938a83df1bd33a3849df1e1c060c053d431643) --- dlls/imm32/imm.c | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 8f1d2822ac9..942088bd613 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -922,36 +922,29 @@ BOOL WINAPI ImmDestroyContext(HIMC hIMC) /*********************************************************************** * ImmEnumRegisterWordA (IMM32.@) */ -UINT WINAPI ImmEnumRegisterWordA( - HKL hKL, REGISTERWORDENUMPROCA lpfnEnumProc, - LPCSTR lpszReading, DWORD dwStyle, - LPCSTR lpszRegister, LPVOID lpData) +UINT WINAPI ImmEnumRegisterWordA( HKL hkl, REGISTERWORDENUMPROCA procA, const char *readingA, + DWORD style, const char *stringA, void *user ) { - struct ime *immHkl = IMM_GetImmHkl( hKL ); - TRACE("(%p, %p, %s, %ld, %s, %p):\n", hKL, lpfnEnumProc, - debugstr_a(lpszReading), dwStyle, debugstr_a(lpszRegister), lpData); - if (immHkl->hIME && immHkl->pImeEnumRegisterWord) - { - if (!is_kbd_ime_unicode(immHkl)) - return immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc, - (LPCWSTR)lpszReading, dwStyle, (LPCWSTR)lpszRegister, lpData); - else - { - LPWSTR lpszwReading = strdupAtoW(lpszReading); - LPWSTR lpszwRegister = strdupAtoW(lpszRegister); - BOOL rc; + struct ime *ime = IMM_GetImmHkl( hkl ); + UINT ret; - rc = immHkl->pImeEnumRegisterWord((REGISTERWORDENUMPROCW)lpfnEnumProc, - lpszwReading, dwStyle, lpszwRegister, - lpData); + TRACE( "hkl %p, procA %p, readingA %s, style %lu, stringA %s, user %p.\n", hkl, procA, + debugstr_a(readingA), style, debugstr_a(stringA), user ); - HeapFree(GetProcessHeap(),0,lpszwReading); - HeapFree(GetProcessHeap(),0,lpszwRegister); - return rc; - } - } + if (!ime->hIME || !ime->pImeEnumRegisterWord) return 0; + + if (!is_kbd_ime_unicode( ime )) + ret = ime->pImeEnumRegisterWord( (REGISTERWORDENUMPROCW)procA, (const WCHAR *)readingA, + style, (const WCHAR *)stringA, user ); else - return 0; + { + WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA ); + ret = ime->pImeEnumRegisterWord( (REGISTERWORDENUMPROCW)procA, readingW, style, stringW, user ); + HeapFree( GetProcessHeap(), 0, readingW ); + HeapFree( GetProcessHeap(), 0, stringW ); + } + + return ret; } /*********************************************************************** From dee6237d591696e8d02c4040d4591a2e9648f475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 13:30:36 +0100 Subject: [PATCH 1697/2777] imm32: Reorder control flow in ImmEnumRegisterWordW. (cherry picked from commit c358707a4d3abf1c92b05e473dace2a3f800341b) --- dlls/imm32/imm.c | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 942088bd613..448781e7815 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -950,35 +950,29 @@ UINT WINAPI ImmEnumRegisterWordA( HKL hkl, REGISTERWORDENUMPROCA procA, const ch /*********************************************************************** * ImmEnumRegisterWordW (IMM32.@) */ -UINT WINAPI ImmEnumRegisterWordW( - HKL hKL, REGISTERWORDENUMPROCW lpfnEnumProc, - LPCWSTR lpszReading, DWORD dwStyle, - LPCWSTR lpszRegister, LPVOID lpData) +UINT WINAPI ImmEnumRegisterWordW( HKL hkl, REGISTERWORDENUMPROCW procW, const WCHAR *readingW, + DWORD style, const WCHAR *stringW, void *user ) { - struct ime *immHkl = IMM_GetImmHkl( hKL ); - TRACE("(%p, %p, %s, %ld, %s, %p):\n", hKL, lpfnEnumProc, - debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister), lpData); - if (immHkl->hIME && immHkl->pImeEnumRegisterWord) - { - if (is_kbd_ime_unicode(immHkl)) - return immHkl->pImeEnumRegisterWord(lpfnEnumProc, lpszReading, dwStyle, - lpszRegister, lpData); - else - { - LPSTR lpszaReading = strdupWtoA(lpszReading); - LPSTR lpszaRegister = strdupWtoA(lpszRegister); - BOOL rc; + struct ime *ime = IMM_GetImmHkl( hkl ); + UINT ret; - rc = immHkl->pImeEnumRegisterWord(lpfnEnumProc, (LPCWSTR)lpszaReading, - dwStyle, (LPCWSTR)lpszaRegister, lpData); + TRACE( "hkl %p, procW %p, readingW %s, style %lu, stringW %s, user %p.\n", hkl, procW, + debugstr_w(readingW), style, debugstr_w(stringW), user ); - HeapFree(GetProcessHeap(),0,lpszaReading); - HeapFree(GetProcessHeap(),0,lpszaRegister); - return rc; - } - } + if (!ime->hIME || !ime->pImeEnumRegisterWord) return 0; + + if (is_kbd_ime_unicode( ime )) + ret = ime->pImeEnumRegisterWord( procW, readingW, style, stringW, user ); else - return 0; + { + char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW ); + ret = ime->pImeEnumRegisterWord( procW, (const WCHAR *)readingA, style, + (const WCHAR *)stringA, user ); + HeapFree( GetProcessHeap(), 0, readingA ); + HeapFree( GetProcessHeap(), 0, stringA ); + } + + return ret; } static inline BOOL EscapeRequiresWA(UINT uEscape) From a28883361f4a8a87e5f1aa06f88aec2c2a230261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 13:30:36 +0100 Subject: [PATCH 1698/2777] imm32: Reorder control flow in ImmEscapeA. (cherry picked from commit f5c5839bd316438e7f2d59752ab82a83d7d913f1) --- dlls/imm32/imm.c | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 448781e7815..b87ff211698 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -988,36 +988,33 @@ static inline BOOL EscapeRequiresWA(UINT uEscape) /*********************************************************************** * ImmEscapeA (IMM32.@) */ -LRESULT WINAPI ImmEscapeA( - HKL hKL, HIMC hIMC, - UINT uEscape, LPVOID lpData) +LRESULT WINAPI ImmEscapeA( HKL hkl, HIMC himc, UINT code, void *data ) { - struct ime *immHkl = IMM_GetImmHkl( hKL ); - TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData); + struct ime *ime = IMM_GetImmHkl( hkl ); + LRESULT ret; - if (immHkl->hIME && immHkl->pImeEscape) + TRACE( "hkl %p, himc %p, code %u, data %p.\n", hkl, himc, code, data ); + + if (!ime->hIME || !ime->pImeEscape) return 0; + + if (!EscapeRequiresWA( code ) || !is_kbd_ime_unicode( ime )) + ret = ime->pImeEscape( himc, code, data ); + else { - if (!EscapeRequiresWA(uEscape) || !is_kbd_ime_unicode(immHkl)) - return immHkl->pImeEscape(hIMC,uEscape,lpData); + WCHAR buffer[81]; /* largest required buffer should be 80 */ + if (code == IME_ESC_SET_EUDC_DICTIONARY) + { + MultiByteToWideChar( CP_ACP, 0, data, -1, buffer, 81 ); + ret = ime->pImeEscape( himc, code, buffer ); + } else { - WCHAR buffer[81]; /* largest required buffer should be 80 */ - LRESULT rc; - if (uEscape == IME_ESC_SET_EUDC_DICTIONARY) - { - MultiByteToWideChar(CP_ACP,0,lpData,-1,buffer,81); - rc = immHkl->pImeEscape(hIMC,uEscape,buffer); - } - else - { - rc = immHkl->pImeEscape(hIMC,uEscape,buffer); - WideCharToMultiByte(CP_ACP,0,buffer,-1,lpData,80, NULL, NULL); - } - return rc; + ret = ime->pImeEscape( himc, code, buffer ); + WideCharToMultiByte( CP_ACP, 0, buffer, -1, data, 80, NULL, NULL ); } } - else - return 0; + + return ret; } /*********************************************************************** From 513e2b27f9d3d0d8c8fcb058fc7765e34f5c6376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 13:30:36 +0100 Subject: [PATCH 1699/2777] imm32: Reorder control flow in ImmEscapeW. (cherry picked from commit af926f1bdcb952823754cdbd57c60b2943efeb97) --- dlls/imm32/imm.c | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index b87ff211698..6fab7c9981b 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1020,36 +1020,33 @@ LRESULT WINAPI ImmEscapeA( HKL hkl, HIMC himc, UINT code, void *data ) /*********************************************************************** * ImmEscapeW (IMM32.@) */ -LRESULT WINAPI ImmEscapeW( - HKL hKL, HIMC hIMC, - UINT uEscape, LPVOID lpData) +LRESULT WINAPI ImmEscapeW( HKL hkl, HIMC himc, UINT code, void *data ) { - struct ime *immHkl = IMM_GetImmHkl( hKL ); - TRACE("(%p, %p, %d, %p):\n", hKL, hIMC, uEscape, lpData); + struct ime *ime = IMM_GetImmHkl( hkl ); + LRESULT ret; - if (immHkl->hIME && immHkl->pImeEscape) + TRACE( "hkl %p, himc %p, code %u, data %p.\n", hkl, himc, code, data ); + + if (!ime->hIME || !ime->pImeEscape) return 0; + + if (!EscapeRequiresWA( code ) || is_kbd_ime_unicode( ime )) + ret = ime->pImeEscape( himc, code, data ); + else { - if (!EscapeRequiresWA(uEscape) || is_kbd_ime_unicode(immHkl)) - return immHkl->pImeEscape(hIMC,uEscape,lpData); + char buffer[81]; /* largest required buffer should be 80 */ + if (code == IME_ESC_SET_EUDC_DICTIONARY) + { + WideCharToMultiByte( CP_ACP, 0, data, -1, buffer, 81, NULL, NULL ); + ret = ime->pImeEscape( himc, code, buffer ); + } else { - CHAR buffer[81]; /* largest required buffer should be 80 */ - LRESULT rc; - if (uEscape == IME_ESC_SET_EUDC_DICTIONARY) - { - WideCharToMultiByte(CP_ACP,0,lpData,-1,buffer,81, NULL, NULL); - rc = immHkl->pImeEscape(hIMC,uEscape,buffer); - } - else - { - rc = immHkl->pImeEscape(hIMC,uEscape,buffer); - MultiByteToWideChar(CP_ACP,0,buffer,-1,lpData,80); - } - return rc; + ret = ime->pImeEscape( himc, code, buffer ); + MultiByteToWideChar( CP_ACP, 0, buffer, -1, data, 80 ); } } - else - return 0; + + return ret; } /*********************************************************************** From 333ee1b5cf5fdbcbaff8c687d6acb12253c9c834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 13:30:36 +0100 Subject: [PATCH 1700/2777] imm32: Reorder control flow in ImmGetConversionListA. (cherry picked from commit 27b587d967d0556b18265a7f6b6352ca0a1bfda4) --- dlls/imm32/imm.c | 51 +++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 6fab7c9981b..7946b54d689 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1585,39 +1585,36 @@ HIMC WINAPI ImmGetContext(HWND hWnd) /*********************************************************************** * ImmGetConversionListA (IMM32.@) */ -DWORD WINAPI ImmGetConversionListA( - HKL hKL, HIMC hIMC, - LPCSTR pSrc, LPCANDIDATELIST lpDst, - DWORD dwBufLen, UINT uFlag) +DWORD WINAPI ImmGetConversionListA( HKL hkl, HIMC himc, const char *srcA, CANDIDATELIST *listA, + DWORD lengthA, UINT flags ) { - struct ime *immHkl = IMM_GetImmHkl( hKL ); - TRACE("(%p, %p, %s, %p, %ld, %d):\n", hKL, hIMC, debugstr_a(pSrc), lpDst, - dwBufLen, uFlag); - if (immHkl->hIME && immHkl->pImeConversionList) + struct ime *ime = IMM_GetImmHkl( hkl ); + DWORD ret; + + TRACE( "hkl %p, himc %p, srcA %s, listA %p, lengthA %lu, flags %#x.\n", hkl, himc, + debugstr_a(srcA), listA, lengthA, flags ); + + if (!ime->hIME || !ime->pImeConversionList) return 0; + + if (!is_kbd_ime_unicode( ime )) + ret = ime->pImeConversionList( himc, (const WCHAR *)srcA, listA, lengthA, flags ); + else { - if (!is_kbd_ime_unicode(immHkl)) - return immHkl->pImeConversionList(hIMC,(LPCWSTR)pSrc,lpDst,dwBufLen,uFlag); + CANDIDATELIST *listW; + WCHAR *srcW = strdupAtoW( srcA ); + DWORD lengthW = ime->pImeConversionList( himc, srcW, NULL, 0, flags ); + + if (!(listW = HeapAlloc( GetProcessHeap(), 0, lengthW ))) ret = 0; else { - LPCANDIDATELIST lpwDst; - DWORD ret = 0, len; - LPWSTR pwSrc = strdupAtoW(pSrc); - - len = immHkl->pImeConversionList(hIMC, pwSrc, NULL, 0, uFlag); - lpwDst = HeapAlloc(GetProcessHeap(), 0, len); - if ( lpwDst ) - { - immHkl->pImeConversionList(hIMC, pwSrc, lpwDst, len, uFlag); - ret = convert_candidatelist_WtoA( lpwDst, lpDst, dwBufLen); - HeapFree(GetProcessHeap(), 0, lpwDst); - } - HeapFree(GetProcessHeap(), 0, pwSrc); - - return ret; + ime->pImeConversionList( himc, srcW, listW, lengthW, flags ); + ret = convert_candidatelist_WtoA( listW, listA, lengthA ); + HeapFree( GetProcessHeap(), 0, listW ); } + HeapFree( GetProcessHeap(), 0, srcW ); } - else - return 0; + + return ret; } /*********************************************************************** From a6bc55f2484ddccdb20d9e871fdc4f60fdcbb11e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 13:30:36 +0100 Subject: [PATCH 1701/2777] imm32: Reorder control flow in ImmGetConversionListW. (cherry picked from commit a8f11bb8f348c38f805bb3f85c3f88f0d86cd136) --- dlls/imm32/imm.c | 51 +++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 7946b54d689..6a5ee4f2217 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1620,39 +1620,36 @@ DWORD WINAPI ImmGetConversionListA( HKL hkl, HIMC himc, const char *srcA, CANDID /*********************************************************************** * ImmGetConversionListW (IMM32.@) */ -DWORD WINAPI ImmGetConversionListW( - HKL hKL, HIMC hIMC, - LPCWSTR pSrc, LPCANDIDATELIST lpDst, - DWORD dwBufLen, UINT uFlag) +DWORD WINAPI ImmGetConversionListW( HKL hkl, HIMC himc, const WCHAR *srcW, CANDIDATELIST *listW, + DWORD lengthW, UINT flags ) { - struct ime *immHkl = IMM_GetImmHkl( hKL ); - TRACE("(%p, %p, %s, %p, %ld, %d):\n", hKL, hIMC, debugstr_w(pSrc), lpDst, - dwBufLen, uFlag); - if (immHkl->hIME && immHkl->pImeConversionList) + struct ime *ime = IMM_GetImmHkl( hkl ); + DWORD ret; + + TRACE( "hkl %p, himc %p, srcW %s, listW %p, lengthW %lu, flags %#x.\n", hkl, himc, + debugstr_w(srcW), listW, lengthW, flags ); + + if (!ime->hIME || !ime->pImeConversionList) return 0; + + if (is_kbd_ime_unicode( ime )) + ret = ime->pImeConversionList( himc, srcW, listW, lengthW, flags ); + else { - if (is_kbd_ime_unicode(immHkl)) - return immHkl->pImeConversionList(hIMC,pSrc,lpDst,dwBufLen,uFlag); + CANDIDATELIST *listA; + char *srcA = strdupWtoA( srcW ); + DWORD lengthA = ime->pImeConversionList( himc, (const WCHAR *)srcA, NULL, 0, flags ); + + if (!(listA = HeapAlloc( GetProcessHeap(), 0, lengthA ))) ret = 0; else { - LPCANDIDATELIST lpaDst; - DWORD ret = 0, len; - LPSTR paSrc = strdupWtoA(pSrc); - - len = immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, NULL, 0, uFlag); - lpaDst = HeapAlloc(GetProcessHeap(), 0, len); - if ( lpaDst ) - { - immHkl->pImeConversionList(hIMC, (LPCWSTR)paSrc, lpaDst, len, uFlag); - ret = convert_candidatelist_AtoW( lpaDst, lpDst, dwBufLen); - HeapFree(GetProcessHeap(), 0, lpaDst); - } - HeapFree(GetProcessHeap(), 0, paSrc); - - return ret; + ime->pImeConversionList( himc, (const WCHAR *)srcA, listA, lengthA, flags ); + ret = convert_candidatelist_AtoW( listA, listW, lengthW ); + HeapFree( GetProcessHeap(), 0, listA ); } + HeapFree( GetProcessHeap(), 0, srcA ); } - else - return 0; + + return ret; } /*********************************************************************** From 5d831b85789c9b2dacf8372ec36a55443f4dbbd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 13:30:36 +0100 Subject: [PATCH 1702/2777] imm32: Reorder control flow in ImmGetProperty. (cherry picked from commit 03f1780653daf35b8654fa9610d153c47b319a8c) --- dlls/imm32/imm.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 6a5ee4f2217..de455c71b9d 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1856,29 +1856,29 @@ BOOL WINAPI ImmGetOpenStatus(HIMC hIMC) /*********************************************************************** * ImmGetProperty (IMM32.@) */ -DWORD WINAPI ImmGetProperty(HKL hKL, DWORD fdwIndex) +DWORD WINAPI ImmGetProperty( HKL hkl, DWORD index ) { - DWORD rc = 0; - struct ime *kbd; + struct ime *ime; + DWORD ret; + + TRACE( "hkl %p, index %lu.\n", hkl, index ); - TRACE("(%p, %ld)\n", hKL, fdwIndex); - kbd = IMM_GetImmHkl(hKL); + ime = IMM_GetImmHkl( hkl ); + if (!ime || !ime->hIME) return 0; - if (kbd && kbd->hIME) + switch (index) { - switch (fdwIndex) - { - case IGP_PROPERTY: rc = kbd->imeInfo.fdwProperty; break; - case IGP_CONVERSION: rc = kbd->imeInfo.fdwConversionCaps; break; - case IGP_SENTENCE: rc = kbd->imeInfo.fdwSentenceCaps; break; - case IGP_SETCOMPSTR: rc = kbd->imeInfo.fdwSCSCaps; break; - case IGP_SELECT: rc = kbd->imeInfo.fdwSelectCaps; break; - case IGP_GETIMEVERSION: rc = IMEVER_0400; break; - case IGP_UI: rc = 0; break; - default: rc = 0; - } + case IGP_PROPERTY: ret = ime->imeInfo.fdwProperty; break; + case IGP_CONVERSION: ret = ime->imeInfo.fdwConversionCaps; break; + case IGP_SENTENCE: ret = ime->imeInfo.fdwSentenceCaps; break; + case IGP_SETCOMPSTR: ret = ime->imeInfo.fdwSCSCaps; break; + case IGP_SELECT: ret = ime->imeInfo.fdwSelectCaps; break; + case IGP_GETIMEVERSION: ret = IMEVER_0400; break; + case IGP_UI: ret = 0; break; + default: ret = 0; break; } - return rc; + + return ret; } /*********************************************************************** From 0e33e8bae2d5cd47eb384df33e0846b3221233a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 13:30:36 +0100 Subject: [PATCH 1703/2777] imm32: Reorder control flow in ImmGetRegisterWordStyleA. (cherry picked from commit 4693428b0562030c2454b6601bfb29d001bfad1b) --- dlls/imm32/imm.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index de455c71b9d..2c9c04fc684 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1884,29 +1884,26 @@ DWORD WINAPI ImmGetProperty( HKL hkl, DWORD index ) /*********************************************************************** * ImmGetRegisterWordStyleA (IMM32.@) */ -UINT WINAPI ImmGetRegisterWordStyleA( - HKL hKL, UINT nItem, LPSTYLEBUFA lpStyleBuf) +UINT WINAPI ImmGetRegisterWordStyleA( HKL hkl, UINT count, STYLEBUFA *styleA ) { - struct ime *immHkl = IMM_GetImmHkl( hKL ); - TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf); - if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle) - { - if (!is_kbd_ime_unicode(immHkl)) - return immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)lpStyleBuf); - else - { - STYLEBUFW sbw; - UINT rc; + struct ime *ime = IMM_GetImmHkl( hkl ); + UINT ret; - rc = immHkl->pImeGetRegisterWordStyle(nItem,&sbw); - WideCharToMultiByte(CP_ACP, 0, sbw.szDescription, -1, - lpStyleBuf->szDescription, 32, NULL, NULL); - lpStyleBuf->dwStyle = sbw.dwStyle; - return rc; - } - } + TRACE( "hkl %p, count %u, styleA %p.\n", hkl, count, styleA ); + + if (!ime->hIME || !ime->pImeGetRegisterWordStyle) return 0; + + if (!is_kbd_ime_unicode( ime )) + ret = ime->pImeGetRegisterWordStyle( count, (STYLEBUFW *)styleA ); else - return 0; + { + STYLEBUFW styleW; + ret = ime->pImeGetRegisterWordStyle( count, &styleW ); + WideCharToMultiByte( CP_ACP, 0, styleW.szDescription, -1, styleA->szDescription, 32, NULL, NULL ); + styleA->dwStyle = styleW.dwStyle; + } + + return ret; } /*********************************************************************** From 0c452c2feddf3351431b69c4fde06dc0b47aa95f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 13:30:36 +0100 Subject: [PATCH 1704/2777] imm32: Reorder control flow in ImmGetRegisterWordStyleW. (cherry picked from commit 1bc81cd8aedcd76072710c1403467b9b79e45622) --- dlls/imm32/imm.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 2c9c04fc684..ea5dd127a9e 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1909,29 +1909,26 @@ UINT WINAPI ImmGetRegisterWordStyleA( HKL hkl, UINT count, STYLEBUFA *styleA ) /*********************************************************************** * ImmGetRegisterWordStyleW (IMM32.@) */ -UINT WINAPI ImmGetRegisterWordStyleW( - HKL hKL, UINT nItem, LPSTYLEBUFW lpStyleBuf) +UINT WINAPI ImmGetRegisterWordStyleW( HKL hkl, UINT count, STYLEBUFW *styleW ) { - struct ime *immHkl = IMM_GetImmHkl( hKL ); - TRACE("(%p, %d, %p):\n", hKL, nItem, lpStyleBuf); - if (immHkl->hIME && immHkl->pImeGetRegisterWordStyle) - { - if (is_kbd_ime_unicode(immHkl)) - return immHkl->pImeGetRegisterWordStyle(nItem,lpStyleBuf); - else - { - STYLEBUFA sba; - UINT rc; + struct ime *ime = IMM_GetImmHkl( hkl ); + UINT ret; - rc = immHkl->pImeGetRegisterWordStyle(nItem,(LPSTYLEBUFW)&sba); - MultiByteToWideChar(CP_ACP, 0, sba.szDescription, -1, - lpStyleBuf->szDescription, 32); - lpStyleBuf->dwStyle = sba.dwStyle; - return rc; - } - } + TRACE( "hkl %p, count %u, styleW %p.\n", hkl, count, styleW ); + + if (!ime->hIME || !ime->pImeGetRegisterWordStyle) return 0; + + if (is_kbd_ime_unicode( ime )) + ret = ime->pImeGetRegisterWordStyle( count, styleW ); else - return 0; + { + STYLEBUFA styleA; + ret = ime->pImeGetRegisterWordStyle( count, (STYLEBUFW *)&styleA ); + MultiByteToWideChar( CP_ACP, 0, styleA.szDescription, -1, styleW->szDescription, 32 ); + styleW->dwStyle = styleA.dwStyle; + } + + return ret; } /*********************************************************************** From 0d007d0f0851d1d0df80a6684baf2339d56a5de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 13:30:36 +0100 Subject: [PATCH 1705/2777] imm32: Reorder control flow in ImmRegisterWordA. (cherry picked from commit cda7a1338e1329299ba9347d58fade15530fbb4b) --- dlls/imm32/imm.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index ea5dd127a9e..c05a4845f5d 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2138,31 +2138,26 @@ BOOL WINAPI ImmNotifyIME( /*********************************************************************** * ImmRegisterWordA (IMM32.@) */ -BOOL WINAPI ImmRegisterWordA( - HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszRegister) +BOOL WINAPI ImmRegisterWordA( HKL hkl, const char *readingA, DWORD style, const char *stringA ) { - struct ime *immHkl = IMM_GetImmHkl( hKL ); - TRACE("(%p, %s, %ld, %s):\n", hKL, debugstr_a(lpszReading), dwStyle, - debugstr_a(lpszRegister)); - if (immHkl->hIME && immHkl->pImeRegisterWord) - { - if (!is_kbd_ime_unicode(immHkl)) - return immHkl->pImeRegisterWord((LPCWSTR)lpszReading,dwStyle, - (LPCWSTR)lpszRegister); - else - { - LPWSTR lpszwReading = strdupAtoW(lpszReading); - LPWSTR lpszwRegister = strdupAtoW(lpszRegister); - BOOL rc; + struct ime *ime = IMM_GetImmHkl( hkl ); + BOOL ret; - rc = immHkl->pImeRegisterWord(lpszwReading,dwStyle,lpszwRegister); - HeapFree(GetProcessHeap(),0,lpszwReading); - HeapFree(GetProcessHeap(),0,lpszwRegister); - return rc; - } - } + TRACE( "hkl %p, readingA %s, style %lu, stringA %s.\n", hkl, debugstr_a(readingA), style, debugstr_a(stringA) ); + + if (!ime->hIME || !ime->pImeRegisterWord) return FALSE; + + if (!is_kbd_ime_unicode( ime )) + ret = ime->pImeRegisterWord( (const WCHAR *)readingA, style, (const WCHAR *)stringA ); else - return FALSE; + { + WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA ); + ret = ime->pImeRegisterWord( readingW, style, stringW ); + HeapFree( GetProcessHeap(), 0, readingW ); + HeapFree( GetProcessHeap(), 0, stringW ); + } + + return ret; } /*********************************************************************** From 3c593757991b9d54b3394900d9cf0ae557c34b0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 13:30:36 +0100 Subject: [PATCH 1706/2777] imm32: Reorder control flow in ImmRegisterWordW. (cherry picked from commit 034148e6a146871fb1e3f85eac8d560b29e6aaec) --- dlls/imm32/imm.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index c05a4845f5d..a881ef76224 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2163,31 +2163,26 @@ BOOL WINAPI ImmRegisterWordA( HKL hkl, const char *readingA, DWORD style, const /*********************************************************************** * ImmRegisterWordW (IMM32.@) */ -BOOL WINAPI ImmRegisterWordW( - HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister) +BOOL WINAPI ImmRegisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, const WCHAR *stringW ) { - struct ime *immHkl = IMM_GetImmHkl( hKL ); - TRACE("(%p, %s, %ld, %s):\n", hKL, debugstr_w(lpszReading), dwStyle, - debugstr_w(lpszRegister)); - if (immHkl->hIME && immHkl->pImeRegisterWord) - { - if (is_kbd_ime_unicode(immHkl)) - return immHkl->pImeRegisterWord(lpszReading,dwStyle,lpszRegister); - else - { - LPSTR lpszaReading = strdupWtoA(lpszReading); - LPSTR lpszaRegister = strdupWtoA(lpszRegister); - BOOL rc; + struct ime *ime = IMM_GetImmHkl( hkl ); + BOOL ret; - rc = immHkl->pImeRegisterWord((LPCWSTR)lpszaReading,dwStyle, - (LPCWSTR)lpszaRegister); - HeapFree(GetProcessHeap(),0,lpszaReading); - HeapFree(GetProcessHeap(),0,lpszaRegister); - return rc; - } - } + TRACE( "hkl %p, readingW %s, style %lu, stringW %s.\n", hkl, debugstr_w(readingW), style, debugstr_w(stringW) ); + + if (!ime->hIME || !ime->pImeRegisterWord) return FALSE; + + if (is_kbd_ime_unicode( ime )) + ret = ime->pImeRegisterWord( readingW, style, stringW ); else - return FALSE; + { + char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW ); + ret = ime->pImeRegisterWord( (const WCHAR *)readingA, style, (const WCHAR *)stringA ); + HeapFree( GetProcessHeap(), 0, readingA ); + HeapFree( GetProcessHeap(), 0, stringA ); + } + + return ret; } /*********************************************************************** From 1addefa61f1bcf2989213a6bd1b4eda7e25d4d16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 13:30:36 +0100 Subject: [PATCH 1707/2777] imm32: Reorder control flow in ImmUnregisterWordA. (cherry picked from commit 4778d1f2bc54ec05895ef7ce895b062abe132ce6) --- dlls/imm32/imm.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index a881ef76224..f0dfd755229 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2618,31 +2618,26 @@ BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID) /*********************************************************************** * ImmUnregisterWordA (IMM32.@) */ -BOOL WINAPI ImmUnregisterWordA( - HKL hKL, LPCSTR lpszReading, DWORD dwStyle, LPCSTR lpszUnregister) +BOOL WINAPI ImmUnregisterWordA( HKL hkl, const char *readingA, DWORD style, const char *stringA ) { - struct ime *immHkl = IMM_GetImmHkl( hKL ); - TRACE("(%p, %s, %ld, %s):\n", hKL, debugstr_a(lpszReading), dwStyle, - debugstr_a(lpszUnregister)); - if (immHkl->hIME && immHkl->pImeUnregisterWord) - { - if (!is_kbd_ime_unicode(immHkl)) - return immHkl->pImeUnregisterWord((LPCWSTR)lpszReading,dwStyle, - (LPCWSTR)lpszUnregister); - else - { - LPWSTR lpszwReading = strdupAtoW(lpszReading); - LPWSTR lpszwUnregister = strdupAtoW(lpszUnregister); - BOOL rc; + struct ime *ime = IMM_GetImmHkl( hkl ); + BOOL ret; - rc = immHkl->pImeUnregisterWord(lpszwReading,dwStyle,lpszwUnregister); - HeapFree(GetProcessHeap(),0,lpszwReading); - HeapFree(GetProcessHeap(),0,lpszwUnregister); - return rc; - } - } + TRACE( "hkl %p, readingA %s, style %lu, stringA %s.\n", hkl, debugstr_a(readingA), style, debugstr_a(stringA) ); + + if (!ime->hIME || !ime->pImeUnregisterWord) return FALSE; + + if (!is_kbd_ime_unicode( ime )) + ret = ime->pImeUnregisterWord( (const WCHAR *)readingA, style, (const WCHAR *)stringA ); else - return FALSE; + { + WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA ); + ret = ime->pImeUnregisterWord( readingW, style, stringW ); + HeapFree( GetProcessHeap(), 0, readingW ); + HeapFree( GetProcessHeap(), 0, stringW ); + } + + return ret; } /*********************************************************************** From 5aa040f785d2062453beaf531e0b2107beafcff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 13:30:36 +0100 Subject: [PATCH 1708/2777] imm32: Reorder control flow in ImmUnregisterWordW. (cherry picked from commit ad2ca1e99ca34804e5c6297cb31c6c0f08d22e61) --- dlls/imm32/imm.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index f0dfd755229..2fb0e06ac77 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2643,31 +2643,26 @@ BOOL WINAPI ImmUnregisterWordA( HKL hkl, const char *readingA, DWORD style, cons /*********************************************************************** * ImmUnregisterWordW (IMM32.@) */ -BOOL WINAPI ImmUnregisterWordW( - HKL hKL, LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister) +BOOL WINAPI ImmUnregisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, const WCHAR *stringW ) { - struct ime *immHkl = IMM_GetImmHkl( hKL ); - TRACE("(%p, %s, %ld, %s):\n", hKL, debugstr_w(lpszReading), dwStyle, - debugstr_w(lpszUnregister)); - if (immHkl->hIME && immHkl->pImeUnregisterWord) + struct ime *ime = IMM_GetImmHkl( hkl ); + BOOL ret; + + TRACE( "hkl %p, readingW %s, style %lu, stringW %s.\n", hkl, debugstr_w(readingW), style, debugstr_w(stringW) ); + + if (!ime->hIME || !ime->pImeUnregisterWord) return FALSE; + + if (is_kbd_ime_unicode( ime )) + ret = ime->pImeUnregisterWord( readingW, style, stringW ); + else { - if (is_kbd_ime_unicode(immHkl)) - return immHkl->pImeUnregisterWord(lpszReading,dwStyle,lpszUnregister); - else - { - LPSTR lpszaReading = strdupWtoA(lpszReading); - LPSTR lpszaUnregister = strdupWtoA(lpszUnregister); - BOOL rc; - - rc = immHkl->pImeUnregisterWord((LPCWSTR)lpszaReading,dwStyle, - (LPCWSTR)lpszaUnregister); - HeapFree(GetProcessHeap(),0,lpszaReading); - HeapFree(GetProcessHeap(),0,lpszaUnregister); - return rc; - } + char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW ); + ret = ime->pImeUnregisterWord( (const WCHAR *)readingA, style, (const WCHAR *)stringA ); + HeapFree( GetProcessHeap(), 0, readingA ); + HeapFree( GetProcessHeap(), 0, stringA ); } - else - return FALSE; + + return ret; } /*********************************************************************** From 9a6d64ad01372bdb8d44ef84186224edd265ace6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 13:30:36 +0100 Subject: [PATCH 1709/2777] imm32: Reorder control flow in ImmGetImeMenuItemsA. (cherry picked from commit d07cec302136d32ad3adc92910f15a069dcdd97e) --- dlls/imm32/imm.c | 90 +++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 50 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 2fb0e06ac77..c7fdb096fe2 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2668,72 +2668,62 @@ BOOL WINAPI ImmUnregisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, con /*********************************************************************** * ImmGetImeMenuItemsA (IMM32.@) */ -DWORD WINAPI ImmGetImeMenuItemsA( HIMC hIMC, DWORD dwFlags, DWORD dwType, - LPIMEMENUITEMINFOA lpImeParentMenu, LPIMEMENUITEMINFOA lpImeMenu, - DWORD dwSize) +DWORD WINAPI ImmGetImeMenuItemsA( HIMC himc, DWORD flags, DWORD type, IMEMENUITEMINFOA *parentA, + IMEMENUITEMINFOA *menuA, DWORD size ) { - InputContextData *data = get_imc_data(hIMC); - TRACE("(%p, %li, %li, %p, %p, %li):\n", hIMC, dwFlags, dwType, - lpImeParentMenu, lpImeMenu, dwSize); + InputContextData *data = get_imc_data( himc ); + DWORD ret; + + TRACE( "himc %p, flags %#lx, type %lu, parentA %p, menuA %p, size %lu.\n", + himc, flags, type, parentA, menuA, size ); if (!data) { - SetLastError(ERROR_INVALID_HANDLE); + SetLastError( ERROR_INVALID_HANDLE ); return 0; } - if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems) + if (!data->immKbd->hIME || !data->immKbd->pImeGetImeMenuItems) return 0; + + if (!is_himc_ime_unicode( data ) || (!parentA && !menuA)) + ret = data->immKbd->pImeGetImeMenuItems( himc, flags, type, (IMEMENUITEMINFOW *)parentA, + (IMEMENUITEMINFOW *)menuA, size ); + else { - if (!is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu)) - return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType, - (IMEMENUITEMINFOW*)lpImeParentMenu, - (IMEMENUITEMINFOW*)lpImeMenu, dwSize); + IMEMENUITEMINFOW tmpW, *menuW, *parentW = parentA ? &tmpW : NULL; + + if (!menuA) menuW = NULL; else { - IMEMENUITEMINFOW lpImeParentMenuW; - IMEMENUITEMINFOW *lpImeMenuW, *parent = NULL; - DWORD rc; - - if (lpImeParentMenu) - parent = &lpImeParentMenuW; - if (lpImeMenu) - { - int count = dwSize / sizeof(LPIMEMENUITEMINFOA); - dwSize = count * sizeof(IMEMENUITEMINFOW); - lpImeMenuW = HeapAlloc(GetProcessHeap(), 0, dwSize); - } - else - lpImeMenuW = NULL; + int count = size / sizeof(LPIMEMENUITEMINFOA); + size = count * sizeof(IMEMENUITEMINFOW); + menuW = HeapAlloc( GetProcessHeap(), 0, size ); + } - rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType, - parent, lpImeMenuW, dwSize); + ret = data->immKbd->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size ); - if (lpImeParentMenu) - { - memcpy(lpImeParentMenu,&lpImeParentMenuW,sizeof(IMEMENUITEMINFOA)); - lpImeParentMenu->hbmpItem = lpImeParentMenuW.hbmpItem; - WideCharToMultiByte(CP_ACP, 0, lpImeParentMenuW.szString, - -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE, - NULL, NULL); - } - if (lpImeMenu && rc) + if (parentA) + { + memcpy( parentA, parentW, sizeof(IMEMENUITEMINFOA) ); + parentA->hbmpItem = parentW->hbmpItem; + WideCharToMultiByte( CP_ACP, 0, parentW->szString, -1, parentA->szString, + IMEMENUITEM_STRING_SIZE, NULL, NULL ); + } + if (menuA && ret) + { + unsigned int i; + for (i = 0; i < ret; i++) { - unsigned int i; - for (i = 0; i < rc; i++) - { - memcpy(&lpImeMenu[i],&lpImeMenuW[1],sizeof(IMEMENUITEMINFOA)); - lpImeMenu[i].hbmpItem = lpImeMenuW[i].hbmpItem; - WideCharToMultiByte(CP_ACP, 0, lpImeMenuW[i].szString, - -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE, - NULL, NULL); - } + memcpy( &menuA[i], &menuW[1], sizeof(IMEMENUITEMINFOA) ); + menuA[i].hbmpItem = menuW[i].hbmpItem; + WideCharToMultiByte( CP_ACP, 0, menuW[i].szString, -1, menuA[i].szString, + IMEMENUITEM_STRING_SIZE, NULL, NULL ); } - HeapFree(GetProcessHeap(),0,lpImeMenuW); - return rc; } + HeapFree( GetProcessHeap(), 0, menuW ); } - else - return 0; + + return ret; } /*********************************************************************** From e5b76fe0e47e0e1710c4eda34b0692df8d4f3f16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 13:30:36 +0100 Subject: [PATCH 1710/2777] imm32: Reorder control flow in ImmGetImeMenuItemsW. (cherry picked from commit 87e0c10b4c867f94570f142c6a30d2d5145973dc) --- dlls/imm32/imm.c | 86 +++++++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 48 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index c7fdb096fe2..634c4ff472c 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2729,70 +2729,60 @@ DWORD WINAPI ImmGetImeMenuItemsA( HIMC himc, DWORD flags, DWORD type, IMEMENUITE /*********************************************************************** * ImmGetImeMenuItemsW (IMM32.@) */ -DWORD WINAPI ImmGetImeMenuItemsW( HIMC hIMC, DWORD dwFlags, DWORD dwType, - LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu, - DWORD dwSize) +DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITEMINFOW *parentW, + IMEMENUITEMINFOW *menuW, DWORD size ) { - InputContextData *data = get_imc_data(hIMC); - TRACE("(%p, %li, %li, %p, %p, %li):\n", hIMC, dwFlags, dwType, - lpImeParentMenu, lpImeMenu, dwSize); + InputContextData *data = get_imc_data( himc ); + DWORD ret; + + TRACE( "himc %p, flags %#lx, type %lu, parentW %p, menuW %p, size %lu.\n", + himc, flags, type, parentW, menuW, size ); if (!data) { - SetLastError(ERROR_INVALID_HANDLE); + SetLastError( ERROR_INVALID_HANDLE ); return 0; } - if (data->immKbd->hIME && data->immKbd->pImeGetImeMenuItems) + if (!data->immKbd->hIME || !data->immKbd->pImeGetImeMenuItems) return 0; + + if (is_himc_ime_unicode( data ) || (!parentW && !menuW)) + ret = data->immKbd->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size ); + else { - if (is_himc_ime_unicode(data) || (!lpImeParentMenu && !lpImeMenu)) - return data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType, - lpImeParentMenu, lpImeMenu, dwSize); + IMEMENUITEMINFOA tmpA, *menuA, *parentA = parentW ? &tmpA : NULL; + + if (!menuW) menuA = NULL; else { - IMEMENUITEMINFOA lpImeParentMenuA; - IMEMENUITEMINFOA *lpImeMenuA, *parent = NULL; - DWORD rc; - - if (lpImeParentMenu) - parent = &lpImeParentMenuA; - if (lpImeMenu) - { - int count = dwSize / sizeof(LPIMEMENUITEMINFOW); - dwSize = count * sizeof(IMEMENUITEMINFOA); - lpImeMenuA = HeapAlloc(GetProcessHeap(), 0, dwSize); - } - else - lpImeMenuA = NULL; + int count = size / sizeof(LPIMEMENUITEMINFOW); + size = count * sizeof(IMEMENUITEMINFOA); + menuA = HeapAlloc( GetProcessHeap(), 0, size ); + } - rc = data->immKbd->pImeGetImeMenuItems(hIMC, dwFlags, dwType, - (IMEMENUITEMINFOW*)parent, - (IMEMENUITEMINFOW*)lpImeMenuA, dwSize); + ret = data->immKbd->pImeGetImeMenuItems( himc, flags, type, (IMEMENUITEMINFOW *)parentA, + (IMEMENUITEMINFOW *)menuA, size ); - if (lpImeParentMenu) - { - memcpy(lpImeParentMenu,&lpImeParentMenuA,sizeof(IMEMENUITEMINFOA)); - lpImeParentMenu->hbmpItem = lpImeParentMenuA.hbmpItem; - MultiByteToWideChar(CP_ACP, 0, lpImeParentMenuA.szString, - -1, lpImeParentMenu->szString, IMEMENUITEM_STRING_SIZE); - } - if (lpImeMenu && rc) + if (parentW) + { + memcpy( parentW, parentA, sizeof(IMEMENUITEMINFOA) ); + parentW->hbmpItem = parentA->hbmpItem; + MultiByteToWideChar( CP_ACP, 0, parentA->szString, -1, parentW->szString, IMEMENUITEM_STRING_SIZE ); + } + if (menuW && ret) + { + unsigned int i; + for (i = 0; i < ret; i++) { - unsigned int i; - for (i = 0; i < rc; i++) - { - memcpy(&lpImeMenu[i],&lpImeMenuA[1],sizeof(IMEMENUITEMINFOA)); - lpImeMenu[i].hbmpItem = lpImeMenuA[i].hbmpItem; - MultiByteToWideChar(CP_ACP, 0, lpImeMenuA[i].szString, - -1, lpImeMenu[i].szString, IMEMENUITEM_STRING_SIZE); - } + memcpy( &menuW[i], &menuA[1], sizeof(IMEMENUITEMINFOA) ); + menuW[i].hbmpItem = menuA[i].hbmpItem; + MultiByteToWideChar( CP_ACP, 0, menuA[i].szString, -1, menuW[i].szString, IMEMENUITEM_STRING_SIZE ); } - HeapFree(GetProcessHeap(),0,lpImeMenuA); - return rc; } + HeapFree( GetProcessHeap(), 0, menuA ); } - else - return 0; + + return ret; } /*********************************************************************** From ae5c3eea67de2a5169dc171d966befc684f56ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 17:25:39 +0100 Subject: [PATCH 1711/2777] imm32: Avoid casts when calling into A/W IME. (cherry picked from commit 1ac7125813ca37e88da618695bd78d0bf88d7bb4) --- dlls/imm32/imm.c | 50 ++++++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 634c4ff472c..a31e89d00c2 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -63,7 +63,7 @@ struct ime HWND UIWnd; /* Function Pointers */ - BOOL (WINAPI *pImeInquire)(IMEINFO *, WCHAR *, DWORD); + BOOL (WINAPI *pImeInquire)(IMEINFO *, void *, DWORD); BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *); BOOL (WINAPI *pImeDestroy)(UINT); LRESULT (WINAPI *pImeEscape)(HIMC, UINT, void *); @@ -71,14 +71,14 @@ struct ime BOOL (WINAPI *pImeSetActiveContext)(HIMC, BOOL); UINT (WINAPI *pImeToAsciiEx)(UINT, UINT, const BYTE *, TRANSMSGLIST *, UINT, HIMC); BOOL (WINAPI *pNotifyIME)(HIMC, DWORD, DWORD, DWORD); - BOOL (WINAPI *pImeRegisterWord)(const WCHAR *, DWORD, const WCHAR *); - BOOL (WINAPI *pImeUnregisterWord)(const WCHAR *, DWORD, const WCHAR *); - UINT (WINAPI *pImeEnumRegisterWord)(REGISTERWORDENUMPROCW, const WCHAR *, DWORD, const WCHAR *, void *); - BOOL (WINAPI *pImeSetCompositionString)(HIMC, DWORD, const void *, DWORD, const void *, DWORD); - DWORD (WINAPI *pImeConversionList)(HIMC, const WCHAR *, CANDIDATELIST *, DWORD, UINT); - BOOL (WINAPI *pImeProcessKey)(HIMC, UINT, LPARAM, const BYTE *); - UINT (WINAPI *pImeGetRegisterWordStyle)(UINT, STYLEBUFW *); - DWORD (WINAPI *pImeGetImeMenuItems)(HIMC, DWORD, DWORD, IMEMENUITEMINFOW *, IMEMENUITEMINFOW *, DWORD); + BOOL (WINAPI *pImeRegisterWord)(const void/*TCHAR*/*, DWORD, const void/*TCHAR*/*); + BOOL (WINAPI *pImeUnregisterWord)(const void/*TCHAR*/*, DWORD, const void/*TCHAR*/*); + UINT (WINAPI *pImeEnumRegisterWord)(void */*REGISTERWORDENUMPROCW*/, const void/*TCHAR*/*, DWORD, const void/*TCHAR*/*, void *); + BOOL (WINAPI *pImeSetCompositionString)(HIMC, DWORD, const void/*TCHAR*/*, DWORD, const void/*TCHAR*/*, DWORD); + DWORD (WINAPI *pImeConversionList)(HIMC, const void/*TCHAR*/*, CANDIDATELIST*, DWORD, UINT); + UINT (WINAPI *pImeGetRegisterWordStyle)(UINT, void/*STYLEBUFW*/*); + BOOL (WINAPI *pImeProcessKey)(HIMC, UINT, LPARAM, const BYTE*); + DWORD (WINAPI *pImeGetImeMenuItems)(HIMC, DWORD, DWORD, void/*IMEMENUITEMINFOW*/*, void/*IMEMENUITEMINFOW*/*, DWORD); }; static HRESULT (WINAPI *pCoRevokeInitializeSpy)(ULARGE_INTEGER cookie); @@ -934,12 +934,11 @@ UINT WINAPI ImmEnumRegisterWordA( HKL hkl, REGISTERWORDENUMPROCA procA, const ch if (!ime->hIME || !ime->pImeEnumRegisterWord) return 0; if (!is_kbd_ime_unicode( ime )) - ret = ime->pImeEnumRegisterWord( (REGISTERWORDENUMPROCW)procA, (const WCHAR *)readingA, - style, (const WCHAR *)stringA, user ); + ret = ime->pImeEnumRegisterWord( procA, readingA, style, stringA, user ); else { WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA ); - ret = ime->pImeEnumRegisterWord( (REGISTERWORDENUMPROCW)procA, readingW, style, stringW, user ); + ret = ime->pImeEnumRegisterWord( procA, readingW, style, stringW, user ); HeapFree( GetProcessHeap(), 0, readingW ); HeapFree( GetProcessHeap(), 0, stringW ); } @@ -966,8 +965,7 @@ UINT WINAPI ImmEnumRegisterWordW( HKL hkl, REGISTERWORDENUMPROCW procW, const WC else { char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW ); - ret = ime->pImeEnumRegisterWord( procW, (const WCHAR *)readingA, style, - (const WCHAR *)stringA, user ); + ret = ime->pImeEnumRegisterWord( procW, readingA, style, stringA, user ); HeapFree( GetProcessHeap(), 0, readingA ); HeapFree( GetProcessHeap(), 0, stringA ); } @@ -1597,7 +1595,7 @@ DWORD WINAPI ImmGetConversionListA( HKL hkl, HIMC himc, const char *srcA, CANDID if (!ime->hIME || !ime->pImeConversionList) return 0; if (!is_kbd_ime_unicode( ime )) - ret = ime->pImeConversionList( himc, (const WCHAR *)srcA, listA, lengthA, flags ); + ret = ime->pImeConversionList( himc, srcA, listA, lengthA, flags ); else { CANDIDATELIST *listW; @@ -1637,12 +1635,12 @@ DWORD WINAPI ImmGetConversionListW( HKL hkl, HIMC himc, const WCHAR *srcW, CANDI { CANDIDATELIST *listA; char *srcA = strdupWtoA( srcW ); - DWORD lengthA = ime->pImeConversionList( himc, (const WCHAR *)srcA, NULL, 0, flags ); + DWORD lengthA = ime->pImeConversionList( himc, srcA, NULL, 0, flags ); if (!(listA = HeapAlloc( GetProcessHeap(), 0, lengthA ))) ret = 0; else { - ime->pImeConversionList( himc, (const WCHAR *)srcA, listA, lengthA, flags ); + ime->pImeConversionList( himc, srcA, listA, lengthA, flags ); ret = convert_candidatelist_AtoW( listA, listW, lengthW ); HeapFree( GetProcessHeap(), 0, listA ); } @@ -1894,7 +1892,7 @@ UINT WINAPI ImmGetRegisterWordStyleA( HKL hkl, UINT count, STYLEBUFA *styleA ) if (!ime->hIME || !ime->pImeGetRegisterWordStyle) return 0; if (!is_kbd_ime_unicode( ime )) - ret = ime->pImeGetRegisterWordStyle( count, (STYLEBUFW *)styleA ); + ret = ime->pImeGetRegisterWordStyle( count, styleA ); else { STYLEBUFW styleW; @@ -1923,7 +1921,7 @@ UINT WINAPI ImmGetRegisterWordStyleW( HKL hkl, UINT count, STYLEBUFW *styleW ) else { STYLEBUFA styleA; - ret = ime->pImeGetRegisterWordStyle( count, (STYLEBUFW *)&styleA ); + ret = ime->pImeGetRegisterWordStyle( count, &styleA ); MultiByteToWideChar( CP_ACP, 0, styleA.szDescription, -1, styleW->szDescription, 32 ); styleW->dwStyle = styleA.dwStyle; } @@ -2148,7 +2146,7 @@ BOOL WINAPI ImmRegisterWordA( HKL hkl, const char *readingA, DWORD style, const if (!ime->hIME || !ime->pImeRegisterWord) return FALSE; if (!is_kbd_ime_unicode( ime )) - ret = ime->pImeRegisterWord( (const WCHAR *)readingA, style, (const WCHAR *)stringA ); + ret = ime->pImeRegisterWord( readingA, style, stringA ); else { WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA ); @@ -2177,7 +2175,7 @@ BOOL WINAPI ImmRegisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, const else { char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW ); - ret = ime->pImeRegisterWord( (const WCHAR *)readingA, style, (const WCHAR *)stringA ); + ret = ime->pImeRegisterWord( readingA, style, stringA ); HeapFree( GetProcessHeap(), 0, readingA ); HeapFree( GetProcessHeap(), 0, stringA ); } @@ -2628,7 +2626,7 @@ BOOL WINAPI ImmUnregisterWordA( HKL hkl, const char *readingA, DWORD style, cons if (!ime->hIME || !ime->pImeUnregisterWord) return FALSE; if (!is_kbd_ime_unicode( ime )) - ret = ime->pImeUnregisterWord( (const WCHAR *)readingA, style, (const WCHAR *)stringA ); + ret = ime->pImeUnregisterWord( readingA, style, stringA ); else { WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA ); @@ -2657,7 +2655,7 @@ BOOL WINAPI ImmUnregisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, con else { char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW ); - ret = ime->pImeUnregisterWord( (const WCHAR *)readingA, style, (const WCHAR *)stringA ); + ret = ime->pImeUnregisterWord( readingA, style, stringA ); HeapFree( GetProcessHeap(), 0, readingA ); HeapFree( GetProcessHeap(), 0, stringA ); } @@ -2686,8 +2684,7 @@ DWORD WINAPI ImmGetImeMenuItemsA( HIMC himc, DWORD flags, DWORD type, IMEMENUITE if (!data->immKbd->hIME || !data->immKbd->pImeGetImeMenuItems) return 0; if (!is_himc_ime_unicode( data ) || (!parentA && !menuA)) - ret = data->immKbd->pImeGetImeMenuItems( himc, flags, type, (IMEMENUITEMINFOW *)parentA, - (IMEMENUITEMINFOW *)menuA, size ); + ret = data->immKbd->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size ); else { IMEMENUITEMINFOW tmpW, *menuW, *parentW = parentA ? &tmpW : NULL; @@ -2760,8 +2757,7 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITE menuA = HeapAlloc( GetProcessHeap(), 0, size ); } - ret = data->immKbd->pImeGetImeMenuItems( himc, flags, type, (IMEMENUITEMINFOW *)parentA, - (IMEMENUITEMINFOW *)menuA, size ); + ret = data->immKbd->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size ); if (parentW) { From 7f2a3d8099c91f67b1dba3251de62b7b9cee14ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 14:10:59 +0100 Subject: [PATCH 1712/2777] imm32: Fail to load IME on any missing entry. Testing shows that this is what native does. (cherry picked from commit 84cec42e62c24a87298b209b53dcf1ff8a6ad626) --- dlls/imm32/imm.c | 124 +++++++++++++++++++++++------------------------ 1 file changed, 60 insertions(+), 64 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index a31e89d00c2..e2c2f7bfccf 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -492,7 +492,6 @@ BOOL WINAPI ImmLoadIME( HKL hkl ) } /* struct ime loading and freeing */ -#define LOAD_FUNCPTR(f) if((ptr->p##f = (LPVOID)GetProcAddress(ptr->hIME, #f)) == NULL){WARN("Can't find function %s in ime\n", #f);} static struct ime *IMM_GetImmHkl( HKL hkl ) { struct ime *ptr; @@ -512,54 +511,52 @@ static struct ime *IMM_GetImmHkl( HKL hkl ) ptr->hkl = hkl; if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename); if (!ptr->hIME) ptr->hIME = load_graphics_driver(); - if (ptr->hIME) + if (!ptr->hIME) goto failed; + +#define LOAD_FUNCPTR( f ) \ + if (!(ptr->p##f = (void *)GetProcAddress( ptr->hIME, #f ))) \ + { \ + WARN( "Can't find function %s in ime\n", #f ); \ + goto failed; \ + } + LOAD_FUNCPTR( ImeInquire ); + LOAD_FUNCPTR( ImeDestroy ); + LOAD_FUNCPTR( ImeSelect ); + LOAD_FUNCPTR( ImeConfigure ); + LOAD_FUNCPTR( ImeEscape ); + LOAD_FUNCPTR( ImeSetActiveContext ); + LOAD_FUNCPTR( ImeToAsciiEx ); + LOAD_FUNCPTR( NotifyIME ); + LOAD_FUNCPTR( ImeRegisterWord ); + LOAD_FUNCPTR( ImeUnregisterWord ); + LOAD_FUNCPTR( ImeEnumRegisterWord ); + LOAD_FUNCPTR( ImeSetCompositionString ); + LOAD_FUNCPTR( ImeConversionList ); + LOAD_FUNCPTR( ImeProcessKey ); + LOAD_FUNCPTR( ImeGetRegisterWordStyle ); + LOAD_FUNCPTR( ImeGetImeMenuItems ); +#undef LOAD_FUNCPTR + + if (!ptr->pImeInquire( &ptr->imeInfo, ptr->imeClassName, 0 )) goto failed; + + /* make sure our classname is WCHAR */ + if (!is_kbd_ime_unicode( ptr )) { - LOAD_FUNCPTR(ImeInquire); - if (!ptr->pImeInquire || !ptr->pImeInquire(&ptr->imeInfo, ptr->imeClassName, 0)) - { - FreeLibrary(ptr->hIME); - ptr->hIME = NULL; - } - else - { - LOAD_FUNCPTR(ImeDestroy); - LOAD_FUNCPTR(ImeSelect); - if (!ptr->pImeSelect || !ptr->pImeDestroy) - { - FreeLibrary(ptr->hIME); - ptr->hIME = NULL; - } - else - { - LOAD_FUNCPTR(ImeConfigure); - LOAD_FUNCPTR(ImeEscape); - LOAD_FUNCPTR(ImeSetActiveContext); - LOAD_FUNCPTR(ImeToAsciiEx); - LOAD_FUNCPTR(NotifyIME); - LOAD_FUNCPTR(ImeRegisterWord); - LOAD_FUNCPTR(ImeUnregisterWord); - LOAD_FUNCPTR(ImeEnumRegisterWord); - LOAD_FUNCPTR(ImeSetCompositionString); - LOAD_FUNCPTR(ImeConversionList); - LOAD_FUNCPTR(ImeProcessKey); - LOAD_FUNCPTR(ImeGetRegisterWordStyle); - LOAD_FUNCPTR(ImeGetImeMenuItems); - /* make sure our classname is WCHAR */ - if (!is_kbd_ime_unicode(ptr)) - { - WCHAR bufW[17]; - MultiByteToWideChar(CP_ACP, 0, (LPSTR)ptr->imeClassName, - -1, bufW, 17); - lstrcpyW(ptr->imeClassName, bufW); - } - } - } + WCHAR bufW[17]; + MultiByteToWideChar( CP_ACP, 0, (LPSTR)ptr->imeClassName, -1, bufW, 17 ); + lstrcpyW( ptr->imeClassName, bufW ); } + list_add_head(&ImmHklList,&ptr->entry); + return ptr; + +failed: + if (ptr->hIME) FreeLibrary( ptr->hIME ); + ptr->hIME = NULL; + list_add_head( &ImmHklList, &ptr->entry ); return ptr; } -#undef LOAD_FUNCPTR static void IMM_FreeAllImmHkl(void) @@ -684,8 +681,7 @@ BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate) { data->IMC.hWnd = activate ? hwnd : NULL; - if (data->immKbd->hIME && data->immKbd->pImeSetActiveContext) - data->immKbd->pImeSetActiveContext(himc, activate); + if (data->immKbd->hIME) data->immKbd->pImeSetActiveContext(himc, activate); } if (IsWindow(hwnd)) @@ -768,7 +764,7 @@ BOOL WINAPI ImmConfigureIMEA( HKL hkl, HWND hwnd, DWORD mode, void *data ) TRACE( "hkl %p, hwnd %p, mode %lu, data %p.\n", hkl, hwnd, mode, data ); if (mode == IME_CONFIG_REGISTERWORD && !data) return FALSE; - if (!ime->hIME || !ime->pImeConfigure) return FALSE; + if (!ime->hIME) return FALSE; if (mode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode( ime )) ret = ime->pImeConfigure( hkl, hwnd, mode, data ); @@ -797,7 +793,7 @@ BOOL WINAPI ImmConfigureIMEW( HKL hkl, HWND hwnd, DWORD mode, void *data ) TRACE( "hkl %p, hwnd %p, mode %lu, data %p.\n", hkl, hwnd, mode, data ); if (mode == IME_CONFIG_REGISTERWORD && !data) return FALSE; - if (!ime->hIME || !ime->pImeConfigure) return FALSE; + if (!ime->hIME) return FALSE; if (mode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode( ime )) ret = ime->pImeConfigure( hkl, hwnd, mode, data ); @@ -931,7 +927,7 @@ UINT WINAPI ImmEnumRegisterWordA( HKL hkl, REGISTERWORDENUMPROCA procA, const ch TRACE( "hkl %p, procA %p, readingA %s, style %lu, stringA %s, user %p.\n", hkl, procA, debugstr_a(readingA), style, debugstr_a(stringA), user ); - if (!ime->hIME || !ime->pImeEnumRegisterWord) return 0; + if (!ime->hIME) return 0; if (!is_kbd_ime_unicode( ime )) ret = ime->pImeEnumRegisterWord( procA, readingA, style, stringA, user ); @@ -958,7 +954,7 @@ UINT WINAPI ImmEnumRegisterWordW( HKL hkl, REGISTERWORDENUMPROCW procW, const WC TRACE( "hkl %p, procW %p, readingW %s, style %lu, stringW %s, user %p.\n", hkl, procW, debugstr_w(readingW), style, debugstr_w(stringW), user ); - if (!ime->hIME || !ime->pImeEnumRegisterWord) return 0; + if (!ime->hIME) return 0; if (is_kbd_ime_unicode( ime )) ret = ime->pImeEnumRegisterWord( procW, readingW, style, stringW, user ); @@ -993,7 +989,7 @@ LRESULT WINAPI ImmEscapeA( HKL hkl, HIMC himc, UINT code, void *data ) TRACE( "hkl %p, himc %p, code %u, data %p.\n", hkl, himc, code, data ); - if (!ime->hIME || !ime->pImeEscape) return 0; + if (!ime->hIME) return 0; if (!EscapeRequiresWA( code ) || !is_kbd_ime_unicode( ime )) ret = ime->pImeEscape( himc, code, data ); @@ -1025,7 +1021,7 @@ LRESULT WINAPI ImmEscapeW( HKL hkl, HIMC himc, UINT code, void *data ) TRACE( "hkl %p, himc %p, code %u, data %p.\n", hkl, himc, code, data ); - if (!ime->hIME || !ime->pImeEscape) return 0; + if (!ime->hIME) return 0; if (!EscapeRequiresWA( code ) || is_kbd_ime_unicode( ime )) ret = ime->pImeEscape( himc, code, data ); @@ -1592,7 +1588,7 @@ DWORD WINAPI ImmGetConversionListA( HKL hkl, HIMC himc, const char *srcA, CANDID TRACE( "hkl %p, himc %p, srcA %s, listA %p, lengthA %lu, flags %#x.\n", hkl, himc, debugstr_a(srcA), listA, lengthA, flags ); - if (!ime->hIME || !ime->pImeConversionList) return 0; + if (!ime->hIME) return 0; if (!is_kbd_ime_unicode( ime )) ret = ime->pImeConversionList( himc, srcA, listA, lengthA, flags ); @@ -1627,7 +1623,7 @@ DWORD WINAPI ImmGetConversionListW( HKL hkl, HIMC himc, const WCHAR *srcW, CANDI TRACE( "hkl %p, himc %p, srcW %s, listW %p, lengthW %lu, flags %#x.\n", hkl, himc, debugstr_w(srcW), listW, lengthW, flags ); - if (!ime->hIME || !ime->pImeConversionList) return 0; + if (!ime->hIME) return 0; if (is_kbd_ime_unicode( ime )) ret = ime->pImeConversionList( himc, srcW, listW, lengthW, flags ); @@ -1889,7 +1885,7 @@ UINT WINAPI ImmGetRegisterWordStyleA( HKL hkl, UINT count, STYLEBUFA *styleA ) TRACE( "hkl %p, count %u, styleA %p.\n", hkl, count, styleA ); - if (!ime->hIME || !ime->pImeGetRegisterWordStyle) return 0; + if (!ime->hIME) return 0; if (!is_kbd_ime_unicode( ime )) ret = ime->pImeGetRegisterWordStyle( count, styleA ); @@ -1914,7 +1910,7 @@ UINT WINAPI ImmGetRegisterWordStyleW( HKL hkl, UINT count, STYLEBUFW *styleW ) TRACE( "hkl %p, count %u, styleW %p.\n", hkl, count, styleW ); - if (!ime->hIME || !ime->pImeGetRegisterWordStyle) return 0; + if (!ime->hIME) return 0; if (is_kbd_ime_unicode( ime )) ret = ime->pImeGetRegisterWordStyle( count, styleW ); @@ -2125,7 +2121,7 @@ BOOL WINAPI ImmNotifyIME( return FALSE; } - if (!data || ! data->immKbd->pNotifyIME) + if (!data) { return FALSE; } @@ -2143,7 +2139,7 @@ BOOL WINAPI ImmRegisterWordA( HKL hkl, const char *readingA, DWORD style, const TRACE( "hkl %p, readingA %s, style %lu, stringA %s.\n", hkl, debugstr_a(readingA), style, debugstr_a(stringA) ); - if (!ime->hIME || !ime->pImeRegisterWord) return FALSE; + if (!ime->hIME) return FALSE; if (!is_kbd_ime_unicode( ime )) ret = ime->pImeRegisterWord( readingA, style, stringA ); @@ -2168,7 +2164,7 @@ BOOL WINAPI ImmRegisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, const TRACE( "hkl %p, readingW %s, style %lu, stringW %s.\n", hkl, debugstr_w(readingW), style, debugstr_w(stringW) ); - if (!ime->hIME || !ime->pImeRegisterWord) return FALSE; + if (!ime->hIME) return FALSE; if (is_kbd_ime_unicode( ime )) ret = ime->pImeRegisterWord( readingW, style, stringW ); @@ -2623,7 +2619,7 @@ BOOL WINAPI ImmUnregisterWordA( HKL hkl, const char *readingA, DWORD style, cons TRACE( "hkl %p, readingA %s, style %lu, stringA %s.\n", hkl, debugstr_a(readingA), style, debugstr_a(stringA) ); - if (!ime->hIME || !ime->pImeUnregisterWord) return FALSE; + if (!ime->hIME) return FALSE; if (!is_kbd_ime_unicode( ime )) ret = ime->pImeUnregisterWord( readingA, style, stringA ); @@ -2648,7 +2644,7 @@ BOOL WINAPI ImmUnregisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, con TRACE( "hkl %p, readingW %s, style %lu, stringW %s.\n", hkl, debugstr_w(readingW), style, debugstr_w(stringW) ); - if (!ime->hIME || !ime->pImeUnregisterWord) return FALSE; + if (!ime->hIME) return FALSE; if (is_kbd_ime_unicode( ime )) ret = ime->pImeUnregisterWord( readingW, style, stringW ); @@ -2681,7 +2677,7 @@ DWORD WINAPI ImmGetImeMenuItemsA( HIMC himc, DWORD flags, DWORD type, IMEMENUITE return 0; } - if (!data->immKbd->hIME || !data->immKbd->pImeGetImeMenuItems) return 0; + if (!data->immKbd->hIME) return 0; if (!is_himc_ime_unicode( data ) || (!parentA && !menuA)) ret = data->immKbd->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size ); @@ -2741,7 +2737,7 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITE return 0; } - if (!data->immKbd->hIME || !data->immKbd->pImeGetImeMenuItems) return 0; + if (!data->immKbd->hIME) return 0; if (is_himc_ime_unicode( data ) || (!parentW && !menuW)) ret = data->immKbd->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size ); @@ -2933,7 +2929,7 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD if (!(data = get_imc_data( imc ))) return FALSE; - if (!data->immKbd->hIME || !data->immKbd->pImeToAsciiEx || data->lastVK == VK_PROCESSKEY) + if (!data->immKbd->hIME || data->lastVK == VK_PROCESSKEY) return FALSE; GetKeyboardState(state); @@ -3005,7 +3001,7 @@ BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD return FALSE; } - if (!data->immKbd->hIME || !data->immKbd->pImeProcessKey) + if (!data->immKbd->hIME) return FALSE; GetKeyboardState(state); From 04c54f5fd7ce3700f291b0caffdfc2155170fe57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 14:39:39 +0100 Subject: [PATCH 1713/2777] imm32: Return early if IMM_GetImmHkl fails. (cherry picked from commit 245465ba1ddb9b5ad1bd36df047547a332fb7c50) --- dlls/imm32/imm.c | 132 +++++++++++++++++++++-------------------------- 1 file changed, 60 insertions(+), 72 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index e2c2f7bfccf..c09e51e9d6a 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -552,10 +552,8 @@ static struct ime *IMM_GetImmHkl( HKL hkl ) failed: if (ptr->hIME) FreeLibrary( ptr->hIME ); - ptr->hIME = NULL; - - list_add_head( &ImmHklList, &ptr->entry ); - return ptr; + HeapFree( GetProcessHeap(), 0, ptr ); + return NULL; } @@ -566,11 +564,8 @@ static void IMM_FreeAllImmHkl(void) LIST_FOR_EACH_ENTRY_SAFE( ptr, cursor2, &ImmHklList, struct ime, entry ) { list_remove(&ptr->entry); - if (ptr->hIME) - { - ptr->pImeDestroy(1); - FreeLibrary(ptr->hIME); - } + ptr->pImeDestroy( 1 ); + FreeLibrary( ptr->hIME ); if (ptr->UIWnd) DestroyWindow(ptr->UIWnd); HeapFree(GetProcessHeap(),0,ptr); @@ -680,8 +675,7 @@ BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate) if (data) { data->IMC.hWnd = activate ? hwnd : NULL; - - if (data->immKbd->hIME) data->immKbd->pImeSetActiveContext(himc, activate); + data->immKbd->pImeSetActiveContext( himc, activate ); } if (IsWindow(hwnd)) @@ -758,13 +752,13 @@ BOOL WINAPI ImmAssociateContextEx(HWND hwnd, HIMC imc, DWORD flags) */ BOOL WINAPI ImmConfigureIMEA( HKL hkl, HWND hwnd, DWORD mode, void *data ) { - struct ime *ime = IMM_GetImmHkl( hkl ); + struct ime *ime; BOOL ret; TRACE( "hkl %p, hwnd %p, mode %lu, data %p.\n", hkl, hwnd, mode, data ); if (mode == IME_CONFIG_REGISTERWORD && !data) return FALSE; - if (!ime->hIME) return FALSE; + if (!(ime = IMM_GetImmHkl( hkl ))) return FALSE; if (mode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode( ime )) ret = ime->pImeConfigure( hkl, hwnd, mode, data ); @@ -787,13 +781,13 @@ BOOL WINAPI ImmConfigureIMEA( HKL hkl, HWND hwnd, DWORD mode, void *data ) */ BOOL WINAPI ImmConfigureIMEW( HKL hkl, HWND hwnd, DWORD mode, void *data ) { - struct ime *ime = IMM_GetImmHkl( hkl ); + struct ime *ime; BOOL ret; TRACE( "hkl %p, hwnd %p, mode %lu, data %p.\n", hkl, hwnd, mode, data ); if (mode == IME_CONFIG_REGISTERWORD && !data) return FALSE; - if (!ime->hIME) return FALSE; + if (!(ime = IMM_GetImmHkl( hkl ))) return FALSE; if (mode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode( ime )) ret = ime->pImeConfigure( hkl, hwnd, mode, data ); @@ -822,9 +816,7 @@ static InputContextData *create_input_context(HIMC default_imc) /* Load the IME */ new_context->threadDefault = !!default_imc; - new_context->immKbd = IMM_GetImmHkl(GetKeyboardLayout(0)); - - if (!new_context->immKbd->hIME) + if (!(new_context->immKbd = IMM_GetImmHkl( GetKeyboardLayout( 0 ) ))) { TRACE("IME dll could not be loaded\n"); HeapFree(GetProcessHeap(),0,new_context); @@ -921,13 +913,13 @@ BOOL WINAPI ImmDestroyContext(HIMC hIMC) UINT WINAPI ImmEnumRegisterWordA( HKL hkl, REGISTERWORDENUMPROCA procA, const char *readingA, DWORD style, const char *stringA, void *user ) { - struct ime *ime = IMM_GetImmHkl( hkl ); + struct ime *ime; UINT ret; TRACE( "hkl %p, procA %p, readingA %s, style %lu, stringA %s, user %p.\n", hkl, procA, debugstr_a(readingA), style, debugstr_a(stringA), user ); - if (!ime->hIME) return 0; + if (!(ime = IMM_GetImmHkl( hkl ))) return 0; if (!is_kbd_ime_unicode( ime )) ret = ime->pImeEnumRegisterWord( procA, readingA, style, stringA, user ); @@ -948,13 +940,13 @@ UINT WINAPI ImmEnumRegisterWordA( HKL hkl, REGISTERWORDENUMPROCA procA, const ch UINT WINAPI ImmEnumRegisterWordW( HKL hkl, REGISTERWORDENUMPROCW procW, const WCHAR *readingW, DWORD style, const WCHAR *stringW, void *user ) { - struct ime *ime = IMM_GetImmHkl( hkl ); + struct ime *ime; UINT ret; TRACE( "hkl %p, procW %p, readingW %s, style %lu, stringW %s, user %p.\n", hkl, procW, debugstr_w(readingW), style, debugstr_w(stringW), user ); - if (!ime->hIME) return 0; + if (!(ime = IMM_GetImmHkl( hkl ))) return 0; if (is_kbd_ime_unicode( ime )) ret = ime->pImeEnumRegisterWord( procW, readingW, style, stringW, user ); @@ -984,12 +976,12 @@ static inline BOOL EscapeRequiresWA(UINT uEscape) */ LRESULT WINAPI ImmEscapeA( HKL hkl, HIMC himc, UINT code, void *data ) { - struct ime *ime = IMM_GetImmHkl( hkl ); + struct ime *ime; LRESULT ret; TRACE( "hkl %p, himc %p, code %u, data %p.\n", hkl, himc, code, data ); - if (!ime->hIME) return 0; + if (!(ime = IMM_GetImmHkl( hkl ))) return 0; if (!EscapeRequiresWA( code ) || !is_kbd_ime_unicode( ime )) ret = ime->pImeEscape( himc, code, data ); @@ -1016,12 +1008,12 @@ LRESULT WINAPI ImmEscapeA( HKL hkl, HIMC himc, UINT code, void *data ) */ LRESULT WINAPI ImmEscapeW( HKL hkl, HIMC himc, UINT code, void *data ) { - struct ime *ime = IMM_GetImmHkl( hkl ); + struct ime *ime; LRESULT ret; TRACE( "hkl %p, himc %p, code %u, data %p.\n", hkl, himc, code, data ); - if (!ime->hIME) return 0; + if (!(ime = IMM_GetImmHkl( hkl ))) return 0; if (!EscapeRequiresWA( code ) || is_kbd_ime_unicode( ime )) ret = ime->pImeEscape( himc, code, data ); @@ -1582,13 +1574,13 @@ HIMC WINAPI ImmGetContext(HWND hWnd) DWORD WINAPI ImmGetConversionListA( HKL hkl, HIMC himc, const char *srcA, CANDIDATELIST *listA, DWORD lengthA, UINT flags ) { - struct ime *ime = IMM_GetImmHkl( hkl ); + struct ime *ime; DWORD ret; TRACE( "hkl %p, himc %p, srcA %s, listA %p, lengthA %lu, flags %#x.\n", hkl, himc, debugstr_a(srcA), listA, lengthA, flags ); - if (!ime->hIME) return 0; + if (!(ime = IMM_GetImmHkl( hkl ))) return 0; if (!is_kbd_ime_unicode( ime )) ret = ime->pImeConversionList( himc, srcA, listA, lengthA, flags ); @@ -1617,13 +1609,13 @@ DWORD WINAPI ImmGetConversionListA( HKL hkl, HIMC himc, const char *srcA, CANDID DWORD WINAPI ImmGetConversionListW( HKL hkl, HIMC himc, const WCHAR *srcW, CANDIDATELIST *listW, DWORD lengthW, UINT flags ) { - struct ime *ime = IMM_GetImmHkl( hkl ); + struct ime *ime; DWORD ret; TRACE( "hkl %p, himc %p, srcW %s, listW %p, lengthW %lu, flags %#x.\n", hkl, himc, debugstr_w(srcW), listW, lengthW, flags ); - if (!ime->hIME) return 0; + if (!(ime = IMM_GetImmHkl( hkl ))) return 0; if (is_kbd_ime_unicode( ime )) ret = ime->pImeConversionList( himc, srcW, listW, lengthW, flags ); @@ -1857,8 +1849,7 @@ DWORD WINAPI ImmGetProperty( HKL hkl, DWORD index ) TRACE( "hkl %p, index %lu.\n", hkl, index ); - ime = IMM_GetImmHkl( hkl ); - if (!ime || !ime->hIME) return 0; + if (!(ime = IMM_GetImmHkl( hkl ))) return 0; switch (index) { @@ -1880,12 +1871,12 @@ DWORD WINAPI ImmGetProperty( HKL hkl, DWORD index ) */ UINT WINAPI ImmGetRegisterWordStyleA( HKL hkl, UINT count, STYLEBUFA *styleA ) { - struct ime *ime = IMM_GetImmHkl( hkl ); + struct ime *ime; UINT ret; TRACE( "hkl %p, count %u, styleA %p.\n", hkl, count, styleA ); - if (!ime->hIME) return 0; + if (!(ime = IMM_GetImmHkl( hkl ))) return 0; if (!is_kbd_ime_unicode( ime )) ret = ime->pImeGetRegisterWordStyle( count, styleA ); @@ -1905,12 +1896,12 @@ UINT WINAPI ImmGetRegisterWordStyleA( HKL hkl, UINT count, STYLEBUFA *styleA ) */ UINT WINAPI ImmGetRegisterWordStyleW( HKL hkl, UINT count, STYLEBUFW *styleW ) { - struct ime *ime = IMM_GetImmHkl( hkl ); + struct ime *ime; UINT ret; TRACE( "hkl %p, count %u, styleW %p.\n", hkl, count, styleW ); - if (!ime->hIME) return 0; + if (!(ime = IMM_GetImmHkl( hkl ))) return 0; if (is_kbd_ime_unicode( ime )) ret = ime->pImeGetRegisterWordStyle( count, styleW ); @@ -2052,12 +2043,15 @@ HKL WINAPI ImmInstallIMEW( /*********************************************************************** * ImmIsIME (IMM32.@) */ -BOOL WINAPI ImmIsIME(HKL hKL) +BOOL WINAPI ImmIsIME( HKL hkl ) { - struct ime *ptr; - TRACE("(%p):\n", hKL); - ptr = IMM_GetImmHkl(hKL); - return (ptr && ptr->hIME); + struct ime *ime; + + TRACE( "hkl %p\n", hkl ); + + if (!(ime = IMM_GetImmHkl( hkl ))) return 0; + + return TRUE; } /*********************************************************************** @@ -2134,12 +2128,12 @@ BOOL WINAPI ImmNotifyIME( */ BOOL WINAPI ImmRegisterWordA( HKL hkl, const char *readingA, DWORD style, const char *stringA ) { - struct ime *ime = IMM_GetImmHkl( hkl ); + struct ime *ime; BOOL ret; TRACE( "hkl %p, readingA %s, style %lu, stringA %s.\n", hkl, debugstr_a(readingA), style, debugstr_a(stringA) ); - if (!ime->hIME) return FALSE; + if (!(ime = IMM_GetImmHkl( hkl ))) return FALSE; if (!is_kbd_ime_unicode( ime )) ret = ime->pImeRegisterWord( readingA, style, stringA ); @@ -2159,12 +2153,12 @@ BOOL WINAPI ImmRegisterWordA( HKL hkl, const char *readingA, DWORD style, const */ BOOL WINAPI ImmRegisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, const WCHAR *stringW ) { - struct ime *ime = IMM_GetImmHkl( hkl ); + struct ime *ime; BOOL ret; TRACE( "hkl %p, readingW %s, style %lu, stringW %s.\n", hkl, debugstr_w(readingW), style, debugstr_w(stringW) ); - if (!ime->hIME) return FALSE; + if (!(ime = IMM_GetImmHkl( hkl ))) return FALSE; if (is_kbd_ime_unicode( ime )) ret = ime->pImeRegisterWord( readingW, style, stringW ); @@ -2614,12 +2608,12 @@ BOOL WINAPI ImmSimulateHotKey(HWND hWnd, DWORD dwHotKeyID) */ BOOL WINAPI ImmUnregisterWordA( HKL hkl, const char *readingA, DWORD style, const char *stringA ) { - struct ime *ime = IMM_GetImmHkl( hkl ); + struct ime *ime; BOOL ret; TRACE( "hkl %p, readingA %s, style %lu, stringA %s.\n", hkl, debugstr_a(readingA), style, debugstr_a(stringA) ); - if (!ime->hIME) return FALSE; + if (!(ime = IMM_GetImmHkl( hkl ))) return FALSE; if (!is_kbd_ime_unicode( ime )) ret = ime->pImeUnregisterWord( readingA, style, stringA ); @@ -2639,12 +2633,12 @@ BOOL WINAPI ImmUnregisterWordA( HKL hkl, const char *readingA, DWORD style, cons */ BOOL WINAPI ImmUnregisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, const WCHAR *stringW ) { - struct ime *ime = IMM_GetImmHkl( hkl ); + struct ime *ime; BOOL ret; TRACE( "hkl %p, readingW %s, style %lu, stringW %s.\n", hkl, debugstr_w(readingW), style, debugstr_w(stringW) ); - if (!ime->hIME) return FALSE; + if (!(ime = IMM_GetImmHkl( hkl ))) return FALSE; if (is_kbd_ime_unicode( ime )) ret = ime->pImeUnregisterWord( readingW, style, stringW ); @@ -2677,8 +2671,6 @@ DWORD WINAPI ImmGetImeMenuItemsA( HIMC himc, DWORD flags, DWORD type, IMEMENUITE return 0; } - if (!data->immKbd->hIME) return 0; - if (!is_himc_ime_unicode( data ) || (!parentA && !menuA)) ret = data->immKbd->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size ); else @@ -2737,8 +2729,6 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITE return 0; } - if (!data->immKbd->hIME) return 0; - if (is_himc_ime_unicode( data ) || (!parentW && !menuW)) ret = data->immKbd->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size ); else @@ -2928,9 +2918,7 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD TRACE("%p %x %x %x\n",hwnd, msg, (UINT)wParam, (UINT)lKeyData); if (!(data = get_imc_data( imc ))) return FALSE; - - if (!data->immKbd->hIME || data->lastVK == VK_PROCESSKEY) - return FALSE; + if (data->lastVK == VK_PROCESSKEY) return FALSE; GetKeyboardState(state); scancode = lKeyData >> 0x10 & 0xff; @@ -2988,21 +2976,16 @@ BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD /* Make sure we are inputting to the correct keyboard */ if (data->immKbd->hkl != hKL) { - struct ime *new_hkl = IMM_GetImmHkl( hKL ); - if (new_hkl) - { - data->immKbd->pImeSelect(imc, FALSE); - data->immKbd->uSelected--; - data->immKbd = new_hkl; - data->immKbd->pImeSelect(imc, TRUE); - data->immKbd->uSelected++; - } - else - return FALSE; - } + struct ime *new_hkl; - if (!data->immKbd->hIME) - return FALSE; + if (!(new_hkl = IMM_GetImmHkl( hKL ))) return FALSE; + + data->immKbd->pImeSelect( imc, FALSE ); + data->immKbd->uSelected--; + data->immKbd = new_hkl; + data->immKbd->pImeSelect( imc, TRUE ); + data->immKbd->uSelected++; + } GetKeyboardState(state); if (data->immKbd->pImeProcessKey(imc, vKey, lKeyData, state)) @@ -3055,8 +3038,13 @@ BOOL WINAPI ImmDisableLegacyIME(void) static HWND get_ui_window(HKL hkl) { - struct ime *immHkl = IMM_GetImmHkl( hkl ); - return immHkl->UIWnd; + struct ime *ime; + HWND hwnd; + + if (!(ime = IMM_GetImmHkl( hkl ))) return 0; + hwnd = ime->UIWnd; + + return hwnd; } static BOOL is_ime_ui_msg(UINT msg) From f10f62cae1024713eb1ae13106de44822284c02d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 17:03:45 +0100 Subject: [PATCH 1714/2777] imm32: Move IMM_FreeThreadData helper around. (cherry picked from commit 0b34236dfdc41f71b52398a15dc7e457bbf451ff) --- dlls/imm32/imm.c | 63 +++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index c09e51e9d6a..3b793b8e69d 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -421,39 +421,6 @@ static InputContextData *query_imc_data(HIMC handle) return ret && ret->handle == handle ? ret : NULL; } -static BOOL free_input_context_data(HIMC hIMC) -{ - InputContextData *data = query_imc_data(hIMC); - - if (!data) - return FALSE; - - TRACE("Destroying %p\n", hIMC); - - data->immKbd->uSelected--; - data->immKbd->pImeSelect(hIMC, FALSE); - SendMessageW(data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->immKbd); - - ImmDestroyIMCC(data->IMC.hCompStr); - ImmDestroyIMCC(data->IMC.hCandInfo); - ImmDestroyIMCC(data->IMC.hGuideLine); - ImmDestroyIMCC(data->IMC.hPrivate); - ImmDestroyIMCC(data->IMC.hMsgBuf); - - HeapFree(GetProcessHeap(), 0, data); - - return TRUE; -} - -static void IMM_FreeThreadData(void) -{ - struct coinit_spy *spy; - - free_input_context_data(UlongToHandle(NtUserGetThreadInfo()->default_imc)); - if ((spy = get_thread_coinit_spy())) - IInitializeSpy_Release(&spy->IInitializeSpy_iface); -} - static HMODULE load_graphics_driver(void) { static const WCHAR key_pathW[] = L"System\\CurrentControlSet\\Control\\Video\\{"; @@ -556,6 +523,36 @@ static struct ime *IMM_GetImmHkl( HKL hkl ) return NULL; } +static BOOL free_input_context_data( HIMC hIMC ) +{ + InputContextData *data = query_imc_data( hIMC ); + + if (!data) return FALSE; + + TRACE( "Destroying %p\n", hIMC ); + + data->immKbd->uSelected--; + data->immKbd->pImeSelect( hIMC, FALSE ); + SendMessageW( data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->immKbd ); + + ImmDestroyIMCC( data->IMC.hCompStr ); + ImmDestroyIMCC( data->IMC.hCandInfo ); + ImmDestroyIMCC( data->IMC.hGuideLine ); + ImmDestroyIMCC( data->IMC.hPrivate ); + ImmDestroyIMCC( data->IMC.hMsgBuf ); + + HeapFree( GetProcessHeap(), 0, data ); + + return TRUE; +} + +static void IMM_FreeThreadData(void) +{ + struct coinit_spy *spy; + + free_input_context_data( UlongToHandle( NtUserGetThreadInfo()->default_imc ) ); + if ((spy = get_thread_coinit_spy())) IInitializeSpy_Release( &spy->IInitializeSpy_iface ); +} static void IMM_FreeAllImmHkl(void) { From 394ba901005eb2cdc395a3a023435f54ad138c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 17:07:29 +0100 Subject: [PATCH 1715/2777] imm32: Rename input context immKbd to ime. (cherry picked from commit 4e7aa4fb6a9b890751c419d5f2416f6031bdf8b5) --- dlls/imm32/imm.c | 83 +++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 44 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 3b793b8e69d..94f8c328cce 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -91,7 +91,7 @@ typedef struct tagInputContextData INPUTCONTEXT IMC; DWORD threadID; - struct ime *immKbd; + struct ime *ime; UINT lastVK; BOOL threadDefault; } InputContextData; @@ -118,7 +118,7 @@ static const WCHAR szImeRegFmt[] = L"System\\CurrentControlSet\\Control\\Keyboar static inline BOOL is_himc_ime_unicode(const InputContextData *data) { - return !!(data->immKbd->imeInfo.fdwProperty & IME_PROP_UNICODE); + return !!(data->ime->imeInfo.fdwProperty & IME_PROP_UNICODE); } static inline BOOL is_kbd_ime_unicode( const struct ime *hkl ) @@ -531,9 +531,9 @@ static BOOL free_input_context_data( HIMC hIMC ) TRACE( "Destroying %p\n", hIMC ); - data->immKbd->uSelected--; - data->immKbd->pImeSelect( hIMC, FALSE ); - SendMessageW( data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->immKbd ); + data->ime->uSelected--; + data->ime->pImeSelect( hIMC, FALSE ); + SendMessageW( data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->ime ); ImmDestroyIMCC( data->IMC.hCompStr ); ImmDestroyIMCC( data->IMC.hCandInfo ); @@ -672,7 +672,7 @@ BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate) if (data) { data->IMC.hWnd = activate ? hwnd : NULL; - data->immKbd->pImeSetActiveContext( himc, activate ); + data->ime->pImeSetActiveContext( himc, activate ); } if (IsWindow(hwnd)) @@ -813,7 +813,7 @@ static InputContextData *create_input_context(HIMC default_imc) /* Load the IME */ new_context->threadDefault = !!default_imc; - if (!(new_context->immKbd = IMM_GetImmHkl( GetKeyboardLayout( 0 ) ))) + if (!(new_context->ime = IMM_GetImmHkl( GetKeyboardLayout( 0 ) ))) { TRACE("IME dll could not be loaded\n"); HeapFree(GetProcessHeap(),0,new_context); @@ -838,10 +838,10 @@ static InputContextData *create_input_context(HIMC default_imc) new_context->IMC.cfCandForm[i].dwIndex = ~0u; /* Initialize the IME Private */ - new_context->IMC.hPrivate = ImmCreateIMCC(new_context->immKbd->imeInfo.dwPrivateDataSize); + new_context->IMC.hPrivate = ImmCreateIMCC( new_context->ime->imeInfo.dwPrivateDataSize ); - new_context->IMC.fdwConversion = new_context->immKbd->imeInfo.fdwConversionCaps; - new_context->IMC.fdwSentence = new_context->immKbd->imeInfo.fdwSentenceCaps; + new_context->IMC.fdwConversion = new_context->ime->imeInfo.fdwConversionCaps; + new_context->IMC.fdwSentence = new_context->ime->imeInfo.fdwSentenceCaps; if (!default_imc) new_context->handle = NtUserCreateInputContext((UINT_PTR)new_context); @@ -853,16 +853,16 @@ static InputContextData *create_input_context(HIMC default_imc) return 0; } - if (!new_context->immKbd->pImeSelect(new_context->handle, TRUE)) + if (!new_context->ime->pImeSelect( new_context->handle, TRUE )) { TRACE("Selection of IME failed\n"); IMM_DestroyContext(new_context); return 0; } new_context->threadID = GetCurrentThreadId(); - SendMessageW(GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)new_context->immKbd); + SendMessageW( GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)new_context->ime ); - new_context->immKbd->uSelected++; + new_context->ime->uSelected++; TRACE("Created context %p\n", new_context); return new_context; } @@ -2117,7 +2117,7 @@ BOOL WINAPI ImmNotifyIME( return FALSE; } - return data->immKbd->pNotifyIME(hIMC,dwAction,dwIndex,dwValue); + return data->ime->pNotifyIME( hIMC, dwAction, dwIndex, dwValue ); } /*********************************************************************** @@ -2326,9 +2326,8 @@ BOOL WINAPI ImmSetCompositionStringA( dwIndex == SCS_QUERYRECONVERTSTRING)) return FALSE; - if (!is_himc_ime_unicode(data)) - return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp, - dwCompLen, lpRead, dwReadLen); + if (!is_himc_ime_unicode( data )) + return data->ime->pImeSetCompositionString( hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen ); comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0); if (comp_len) @@ -2384,9 +2383,8 @@ BOOL WINAPI ImmSetCompositionStringW( dwIndex == SCS_QUERYRECONVERTSTRING)) return FALSE; - if (is_himc_ime_unicode(data)) - return data->immKbd->pImeSetCompositionString(hIMC, dwIndex, lpComp, - dwCompLen, lpRead, dwReadLen); + if (is_himc_ime_unicode( data )) + return data->ime->pImeSetCompositionString( hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen ); comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL, NULL); @@ -2441,16 +2439,15 @@ BOOL WINAPI ImmSetCompositionWindow( data->IMC.cfCompForm = *lpCompForm; - if (IsWindowVisible(data->immKbd->UIWnd)) + if (IsWindowVisible( data->ime->UIWnd )) { reshow = TRUE; - ShowWindow(data->immKbd->UIWnd,SW_HIDE); + ShowWindow( data->ime->UIWnd, SW_HIDE ); } /* FIXME: this is a partial stub */ - if (reshow) - ShowWindow(data->immKbd->UIWnd,SW_SHOWNOACTIVATE); + if (reshow) ShowWindow( data->ime->UIWnd, SW_SHOWNOACTIVATE ); ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0); return TRUE; @@ -2512,16 +2509,14 @@ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) if (IMM_IsCrossThreadAccess(NULL, hIMC)) return FALSE; - if (data->immKbd->UIWnd == NULL) + if (data->ime->UIWnd == NULL) { /* create the ime window */ - data->immKbd->UIWnd = CreateWindowExW( WS_EX_TOOLWINDOW, - data->immKbd->imeClassName, NULL, WS_POPUP, 0, 0, 1, 1, 0, - 0, data->immKbd->hIME, 0); - SetWindowLongPtrW(data->immKbd->UIWnd, IMMGWL_IMC, (LONG_PTR)data); + data->ime->UIWnd = CreateWindowExW( WS_EX_TOOLWINDOW, data->ime->imeClassName, NULL, + WS_POPUP, 0, 0, 1, 1, 0, 0, data->ime->hIME, 0 ); + SetWindowLongPtrW( data->ime->UIWnd, IMMGWL_IMC, (LONG_PTR)data ); } - else if (fOpen) - SetWindowLongPtrW(data->immKbd->UIWnd, IMMGWL_IMC, (LONG_PTR)data); + else if (fOpen) SetWindowLongPtrW( data->ime->UIWnd, IMMGWL_IMC, (LONG_PTR)data ); if (!fOpen != !data->IMC.fOpen) { @@ -2669,7 +2664,7 @@ DWORD WINAPI ImmGetImeMenuItemsA( HIMC himc, DWORD flags, DWORD type, IMEMENUITE } if (!is_himc_ime_unicode( data ) || (!parentA && !menuA)) - ret = data->immKbd->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size ); + ret = data->ime->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size ); else { IMEMENUITEMINFOW tmpW, *menuW, *parentW = parentA ? &tmpW : NULL; @@ -2682,7 +2677,7 @@ DWORD WINAPI ImmGetImeMenuItemsA( HIMC himc, DWORD flags, DWORD type, IMEMENUITE menuW = HeapAlloc( GetProcessHeap(), 0, size ); } - ret = data->immKbd->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size ); + ret = data->ime->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size ); if (parentA) { @@ -2727,7 +2722,7 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITE } if (is_himc_ime_unicode( data ) || (!parentW && !menuW)) - ret = data->immKbd->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size ); + ret = data->ime->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size ); else { IMEMENUITEMINFOA tmpA, *menuA, *parentA = parentW ? &tmpA : NULL; @@ -2740,7 +2735,7 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITE menuA = HeapAlloc( GetProcessHeap(), 0, size ); } - ret = data->immKbd->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size ); + ret = data->ime->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size ); if (parentW) { @@ -2923,7 +2918,7 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list_count * sizeof(TRANSMSG) + sizeof(DWORD)); list->uMsgCount = list_count; - if (data->immKbd->imeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST) + if (data->ime->imeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST) { WCHAR chr; @@ -2936,7 +2931,7 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD else uVirtKey = data->lastVK; - msg_count = data->immKbd->pImeToAsciiEx(uVirtKey, scancode, state, list, 0, imc); + msg_count = data->ime->pImeToAsciiEx( uVirtKey, scancode, state, list, 0, imc ); TRACE("%i messages generated\n",msg_count); if (msg_count && msg_count <= list_count) { @@ -2971,21 +2966,21 @@ BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD if (!(data = get_imc_data( imc ))) return FALSE; /* Make sure we are inputting to the correct keyboard */ - if (data->immKbd->hkl != hKL) + if (data->ime->hkl != hKL) { struct ime *new_hkl; if (!(new_hkl = IMM_GetImmHkl( hKL ))) return FALSE; - data->immKbd->pImeSelect( imc, FALSE ); - data->immKbd->uSelected--; - data->immKbd = new_hkl; - data->immKbd->pImeSelect( imc, TRUE ); - data->immKbd->uSelected++; + data->ime->pImeSelect( imc, FALSE ); + data->ime->uSelected--; + data->ime = new_hkl; + data->ime->pImeSelect( imc, TRUE ); + data->ime->uSelected++; } GetKeyboardState(state); - if (data->immKbd->pImeProcessKey(imc, vKey, lKeyData, state)) + if (data->ime->pImeProcessKey( imc, vKey, lKeyData, state )) { data->lastVK = vKey; return TRUE; From 5ee688e51067057185410a8441dacc735c90663d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 9 Mar 2023 11:15:16 +0100 Subject: [PATCH 1716/2777] imm32: Implement ImmLoadIME and ImmFreeLayout. (cherry picked from commit fa9de19a66261cdb979ec131ff14e391ddce095b) --- dlls/imm32/imm.c | 223 +++++++++++++++++++++++++++------------ dlls/imm32/tests/imm32.c | 18 +--- 2 files changed, 154 insertions(+), 87 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 94f8c328cce..389aead8264 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -54,9 +54,12 @@ static UINT WM_MSIME_DOCUMENTFEED; struct ime { + LONG refcount; /* guarded by ime_cs */ + + HKL hkl; + HMODULE module; struct list entry; - HKL hkl; - HMODULE hIME; + IMEINFO imeInfo; WCHAR imeClassName[17]; /* 16 character max */ ULONG uSelected; @@ -112,7 +115,15 @@ struct coinit_spy } apt_flags; }; -static struct list ImmHklList = LIST_INIT(ImmHklList); +static CRITICAL_SECTION ime_cs; +static CRITICAL_SECTION_DEBUG ime_cs_debug = +{ + 0, 0, &ime_cs, + { &ime_cs_debug.ProcessLocksList, &ime_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": ime_cs") } +}; +static CRITICAL_SECTION ime_cs = { &ime_cs_debug, -1, 0, 0, 0, 0 }; +static struct list ime_list = LIST_INIT( ime_list ); static const WCHAR szImeRegFmt[] = L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08lx"; @@ -446,45 +457,62 @@ static HMODULE load_graphics_driver(void) return ret; } -BOOL WINAPI ImmFreeLayout( HKL hkl ) +/* lookup an IME from a HKL, must hold ime_cs */ +static struct ime *find_ime_from_hkl( HKL hkl ) { - FIXME( "hkl %p stub!\n", hkl ); - return FALSE; + struct ime *ime = NULL; + LIST_FOR_EACH_ENTRY( ime, &ime_list, struct ime, entry ) + if (ime->hkl == hkl) return ime; + return NULL; } -BOOL WINAPI ImmLoadIME( HKL hkl ) +BOOL WINAPI ImmFreeLayout( HKL hkl ) { - FIXME( "hkl %p stub!\n", hkl ); - return FALSE; + struct ime *ime; + + TRACE( "hkl %p\n", hkl ); + + EnterCriticalSection( &ime_cs ); + if ((ime = find_ime_from_hkl( hkl )) && ime->refcount) ime = NULL; + if (ime) list_remove( &ime->entry ); + LeaveCriticalSection( &ime_cs ); + if (!ime) return TRUE; + + if (!ime->pImeDestroy( 0 )) WARN( "ImeDestroy failed\n" ); + FreeLibrary( ime->module ); + free( ime ); + return TRUE; } -/* struct ime loading and freeing */ -static struct ime *IMM_GetImmHkl( HKL hkl ) +BOOL WINAPI ImmLoadIME( HKL hkl ) { - struct ime *ptr; - WCHAR filename[MAX_PATH]; + WCHAR buffer[MAX_PATH] = {0}; + struct ime *ime; - TRACE("Seeking ime for keyboard %p\n",hkl); + TRACE( "hkl %p\n", hkl ); - LIST_FOR_EACH_ENTRY( ptr, &ImmHklList, struct ime, entry ) - { - if (ptr->hkl == hkl) - return ptr; - } - /* not found... create it */ + EnterCriticalSection( &ime_cs ); + ime = find_ime_from_hkl( hkl ); + LeaveCriticalSection( &ime_cs ); + if (ime) return TRUE; - ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct ime) ); + if (!(ime = calloc( 1, sizeof(*ime) ))) return FALSE; + ime->hkl = hkl; - ptr->hkl = hkl; - if (ImmGetIMEFileNameW(hkl, filename, MAX_PATH)) ptr->hIME = LoadLibraryW(filename); - if (!ptr->hIME) ptr->hIME = load_graphics_driver(); - if (!ptr->hIME) goto failed; + if (!ImmGetIMEFileNameW( hkl, buffer, MAX_PATH )) ime->module = NULL; + else ime->module = LoadLibraryW( buffer ); + + if (!ime->module) + { + if (*buffer) WARN( "Failed to load %s, falling back to default.\n", debugstr_w(buffer) ); + if (!(ime->module = load_graphics_driver())) goto failed; + } -#define LOAD_FUNCPTR( f ) \ - if (!(ptr->p##f = (void *)GetProcAddress( ptr->hIME, #f ))) \ - { \ - WARN( "Can't find function %s in ime\n", #f ); \ - goto failed; \ +#define LOAD_FUNCPTR( f ) \ + if (!(ime->p##f = (void *)GetProcAddress( ime->module, #f ))) \ + { \ + WARN( "Can't find function %s in HKL %p IME\n", #f, hkl ); \ + goto failed; \ } LOAD_FUNCPTR( ImeInquire ); LOAD_FUNCPTR( ImeDestroy ); @@ -504,23 +532,57 @@ static struct ime *IMM_GetImmHkl( HKL hkl ) LOAD_FUNCPTR( ImeGetImeMenuItems ); #undef LOAD_FUNCPTR - if (!ptr->pImeInquire( &ptr->imeInfo, ptr->imeClassName, 0 )) goto failed; + if (!ime->pImeInquire( &ime->imeInfo, buffer, 0 )) goto failed; - /* make sure our classname is WCHAR */ - if (!is_kbd_ime_unicode( ptr )) + if (is_kbd_ime_unicode( ime )) lstrcpynW( ime->imeClassName, buffer, ARRAY_SIZE(ime->imeClassName) ); + else MultiByteToWideChar( CP_ACP, 0, (char *)buffer, -1, ime->imeClassName, ARRAY_SIZE(ime->imeClassName) ); + + EnterCriticalSection( &ime_cs ); + list_add_tail( &ime_list, &ime->entry ); + LeaveCriticalSection( &ime_cs ); + + TRACE( "Created IME %p for HKL %p\n", ime, hkl ); + return TRUE; + +failed: + if (ime->module) FreeLibrary( ime->module ); + free( ime ); + return FALSE; +} + +static struct ime *ime_acquire( HKL hkl ) +{ + struct ime *ime; + + EnterCriticalSection( &ime_cs ); + + if (!ImmLoadIME( hkl )) ime = NULL; + else ime = find_ime_from_hkl( hkl ); + + if (ime) { - WCHAR bufW[17]; - MultiByteToWideChar( CP_ACP, 0, (LPSTR)ptr->imeClassName, -1, bufW, 17 ); - lstrcpyW( ptr->imeClassName, bufW ); + ULONG ref = ++ime->refcount; + TRACE( "ime %p increasing refcount to %lu.\n", ime, ref ); } - list_add_head(&ImmHklList,&ptr->entry); - return ptr; + LeaveCriticalSection( &ime_cs ); -failed: - if (ptr->hIME) FreeLibrary( ptr->hIME ); - HeapFree( GetProcessHeap(), 0, ptr ); - return NULL; + return ime; +} + +static void ime_release( struct ime *ime ) +{ + ULONG ref; + + EnterCriticalSection( &ime_cs ); + + ref = --ime->refcount; + TRACE( "ime %p decreasing refcount to %lu.\n", ime, ref ); + + if (!ref && (ime->imeInfo.fdwProperty & IME_PROP_END_UNLOAD)) + ImmFreeLayout( ime->hkl ); + + LeaveCriticalSection( &ime_cs ); } static BOOL free_input_context_data( HIMC hIMC ) @@ -541,6 +603,7 @@ static BOOL free_input_context_data( HIMC hIMC ) ImmDestroyIMCC( data->IMC.hPrivate ); ImmDestroyIMCC( data->IMC.hMsgBuf ); + ime_release( data->ime ); HeapFree( GetProcessHeap(), 0, data ); return TRUE; @@ -556,16 +619,17 @@ static void IMM_FreeThreadData(void) static void IMM_FreeAllImmHkl(void) { - struct ime *ptr, *cursor2; + struct ime *ime, *next; - LIST_FOR_EACH_ENTRY_SAFE( ptr, cursor2, &ImmHklList, struct ime, entry ) + LIST_FOR_EACH_ENTRY_SAFE( ime, next, &ime_list, struct ime, entry ) { - list_remove(&ptr->entry); - ptr->pImeDestroy( 1 ); - FreeLibrary( ptr->hIME ); - if (ptr->UIWnd) - DestroyWindow(ptr->UIWnd); - HeapFree(GetProcessHeap(),0,ptr); + list_remove( &ime->entry ); + + ime->pImeDestroy( 1 ); + FreeLibrary( ime->module ); + + if (ime->UIWnd) DestroyWindow( ime->UIWnd ); + free( ime ); } } @@ -755,7 +819,7 @@ BOOL WINAPI ImmConfigureIMEA( HKL hkl, HWND hwnd, DWORD mode, void *data ) TRACE( "hkl %p, hwnd %p, mode %lu, data %p.\n", hkl, hwnd, mode, data ); if (mode == IME_CONFIG_REGISTERWORD && !data) return FALSE; - if (!(ime = IMM_GetImmHkl( hkl ))) return FALSE; + if (!(ime = ime_acquire( hkl ))) return FALSE; if (mode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode( ime )) ret = ime->pImeConfigure( hkl, hwnd, mode, data ); @@ -770,6 +834,7 @@ BOOL WINAPI ImmConfigureIMEA( HKL hkl, HWND hwnd, DWORD mode, void *data ) HeapFree( GetProcessHeap(), 0, wordW.lpWord ); } + ime_release( ime ); return ret; } @@ -784,7 +849,7 @@ BOOL WINAPI ImmConfigureIMEW( HKL hkl, HWND hwnd, DWORD mode, void *data ) TRACE( "hkl %p, hwnd %p, mode %lu, data %p.\n", hkl, hwnd, mode, data ); if (mode == IME_CONFIG_REGISTERWORD && !data) return FALSE; - if (!(ime = IMM_GetImmHkl( hkl ))) return FALSE; + if (!(ime = ime_acquire( hkl ))) return FALSE; if (mode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode( ime )) ret = ime->pImeConfigure( hkl, hwnd, mode, data ); @@ -799,6 +864,7 @@ BOOL WINAPI ImmConfigureIMEW( HKL hkl, HWND hwnd, DWORD mode, void *data ) HeapFree( GetProcessHeap(), 0, wordA.lpWord ); } + ime_release( ime ); return ret; } @@ -813,7 +879,7 @@ static InputContextData *create_input_context(HIMC default_imc) /* Load the IME */ new_context->threadDefault = !!default_imc; - if (!(new_context->ime = IMM_GetImmHkl( GetKeyboardLayout( 0 ) ))) + if (!(new_context->ime = ime_acquire( GetKeyboardLayout( 0 ) ))) { TRACE("IME dll could not be loaded\n"); HeapFree(GetProcessHeap(),0,new_context); @@ -916,7 +982,7 @@ UINT WINAPI ImmEnumRegisterWordA( HKL hkl, REGISTERWORDENUMPROCA procA, const ch TRACE( "hkl %p, procA %p, readingA %s, style %lu, stringA %s, user %p.\n", hkl, procA, debugstr_a(readingA), style, debugstr_a(stringA), user ); - if (!(ime = IMM_GetImmHkl( hkl ))) return 0; + if (!(ime = ime_acquire( hkl ))) return 0; if (!is_kbd_ime_unicode( ime )) ret = ime->pImeEnumRegisterWord( procA, readingA, style, stringA, user ); @@ -928,6 +994,7 @@ UINT WINAPI ImmEnumRegisterWordA( HKL hkl, REGISTERWORDENUMPROCA procA, const ch HeapFree( GetProcessHeap(), 0, stringW ); } + ime_release( ime ); return ret; } @@ -943,7 +1010,7 @@ UINT WINAPI ImmEnumRegisterWordW( HKL hkl, REGISTERWORDENUMPROCW procW, const WC TRACE( "hkl %p, procW %p, readingW %s, style %lu, stringW %s, user %p.\n", hkl, procW, debugstr_w(readingW), style, debugstr_w(stringW), user ); - if (!(ime = IMM_GetImmHkl( hkl ))) return 0; + if (!(ime = ime_acquire( hkl ))) return 0; if (is_kbd_ime_unicode( ime )) ret = ime->pImeEnumRegisterWord( procW, readingW, style, stringW, user ); @@ -955,6 +1022,7 @@ UINT WINAPI ImmEnumRegisterWordW( HKL hkl, REGISTERWORDENUMPROCW procW, const WC HeapFree( GetProcessHeap(), 0, stringA ); } + ime_release( ime ); return ret; } @@ -978,7 +1046,7 @@ LRESULT WINAPI ImmEscapeA( HKL hkl, HIMC himc, UINT code, void *data ) TRACE( "hkl %p, himc %p, code %u, data %p.\n", hkl, himc, code, data ); - if (!(ime = IMM_GetImmHkl( hkl ))) return 0; + if (!(ime = ime_acquire( hkl ))) return 0; if (!EscapeRequiresWA( code ) || !is_kbd_ime_unicode( ime )) ret = ime->pImeEscape( himc, code, data ); @@ -997,6 +1065,7 @@ LRESULT WINAPI ImmEscapeA( HKL hkl, HIMC himc, UINT code, void *data ) } } + ime_release( ime ); return ret; } @@ -1010,7 +1079,7 @@ LRESULT WINAPI ImmEscapeW( HKL hkl, HIMC himc, UINT code, void *data ) TRACE( "hkl %p, himc %p, code %u, data %p.\n", hkl, himc, code, data ); - if (!(ime = IMM_GetImmHkl( hkl ))) return 0; + if (!(ime = ime_acquire( hkl ))) return 0; if (!EscapeRequiresWA( code ) || is_kbd_ime_unicode( ime )) ret = ime->pImeEscape( himc, code, data ); @@ -1029,6 +1098,7 @@ LRESULT WINAPI ImmEscapeW( HKL hkl, HIMC himc, UINT code, void *data ) } } + ime_release( ime ); return ret; } @@ -1577,7 +1647,7 @@ DWORD WINAPI ImmGetConversionListA( HKL hkl, HIMC himc, const char *srcA, CANDID TRACE( "hkl %p, himc %p, srcA %s, listA %p, lengthA %lu, flags %#x.\n", hkl, himc, debugstr_a(srcA), listA, lengthA, flags ); - if (!(ime = IMM_GetImmHkl( hkl ))) return 0; + if (!(ime = ime_acquire( hkl ))) return 0; if (!is_kbd_ime_unicode( ime )) ret = ime->pImeConversionList( himc, srcA, listA, lengthA, flags ); @@ -1597,6 +1667,7 @@ DWORD WINAPI ImmGetConversionListA( HKL hkl, HIMC himc, const char *srcA, CANDID HeapFree( GetProcessHeap(), 0, srcW ); } + ime_release( ime ); return ret; } @@ -1612,7 +1683,7 @@ DWORD WINAPI ImmGetConversionListW( HKL hkl, HIMC himc, const WCHAR *srcW, CANDI TRACE( "hkl %p, himc %p, srcW %s, listW %p, lengthW %lu, flags %#x.\n", hkl, himc, debugstr_w(srcW), listW, lengthW, flags ); - if (!(ime = IMM_GetImmHkl( hkl ))) return 0; + if (!(ime = ime_acquire( hkl ))) return 0; if (is_kbd_ime_unicode( ime )) ret = ime->pImeConversionList( himc, srcW, listW, lengthW, flags ); @@ -1632,6 +1703,7 @@ DWORD WINAPI ImmGetConversionListW( HKL hkl, HIMC himc, const WCHAR *srcW, CANDI HeapFree( GetProcessHeap(), 0, srcA ); } + ime_release( ime ); return ret; } @@ -1846,7 +1918,7 @@ DWORD WINAPI ImmGetProperty( HKL hkl, DWORD index ) TRACE( "hkl %p, index %lu.\n", hkl, index ); - if (!(ime = IMM_GetImmHkl( hkl ))) return 0; + if (!(ime = ime_acquire( hkl ))) return 0; switch (index) { @@ -1860,6 +1932,7 @@ DWORD WINAPI ImmGetProperty( HKL hkl, DWORD index ) default: ret = 0; break; } + ime_release( ime ); return ret; } @@ -1873,7 +1946,7 @@ UINT WINAPI ImmGetRegisterWordStyleA( HKL hkl, UINT count, STYLEBUFA *styleA ) TRACE( "hkl %p, count %u, styleA %p.\n", hkl, count, styleA ); - if (!(ime = IMM_GetImmHkl( hkl ))) return 0; + if (!(ime = ime_acquire( hkl ))) return 0; if (!is_kbd_ime_unicode( ime )) ret = ime->pImeGetRegisterWordStyle( count, styleA ); @@ -1885,6 +1958,7 @@ UINT WINAPI ImmGetRegisterWordStyleA( HKL hkl, UINT count, STYLEBUFA *styleA ) styleA->dwStyle = styleW.dwStyle; } + ime_release( ime ); return ret; } @@ -1898,7 +1972,7 @@ UINT WINAPI ImmGetRegisterWordStyleW( HKL hkl, UINT count, STYLEBUFW *styleW ) TRACE( "hkl %p, count %u, styleW %p.\n", hkl, count, styleW ); - if (!(ime = IMM_GetImmHkl( hkl ))) return 0; + if (!(ime = ime_acquire( hkl ))) return 0; if (is_kbd_ime_unicode( ime )) ret = ime->pImeGetRegisterWordStyle( count, styleW ); @@ -1910,6 +1984,7 @@ UINT WINAPI ImmGetRegisterWordStyleW( HKL hkl, UINT count, STYLEBUFW *styleW ) styleW->dwStyle = styleA.dwStyle; } + ime_release( ime ); return ret; } @@ -2046,7 +2121,8 @@ BOOL WINAPI ImmIsIME( HKL hkl ) TRACE( "hkl %p\n", hkl ); - if (!(ime = IMM_GetImmHkl( hkl ))) return 0; + if (!(ime = ime_acquire( hkl ))) return 0; + ime_release( ime ); return TRUE; } @@ -2130,7 +2206,7 @@ BOOL WINAPI ImmRegisterWordA( HKL hkl, const char *readingA, DWORD style, const TRACE( "hkl %p, readingA %s, style %lu, stringA %s.\n", hkl, debugstr_a(readingA), style, debugstr_a(stringA) ); - if (!(ime = IMM_GetImmHkl( hkl ))) return FALSE; + if (!(ime = ime_acquire( hkl ))) return FALSE; if (!is_kbd_ime_unicode( ime )) ret = ime->pImeRegisterWord( readingA, style, stringA ); @@ -2142,6 +2218,7 @@ BOOL WINAPI ImmRegisterWordA( HKL hkl, const char *readingA, DWORD style, const HeapFree( GetProcessHeap(), 0, stringW ); } + ime_release( ime ); return ret; } @@ -2155,7 +2232,7 @@ BOOL WINAPI ImmRegisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, const TRACE( "hkl %p, readingW %s, style %lu, stringW %s.\n", hkl, debugstr_w(readingW), style, debugstr_w(stringW) ); - if (!(ime = IMM_GetImmHkl( hkl ))) return FALSE; + if (!(ime = ime_acquire( hkl ))) return FALSE; if (is_kbd_ime_unicode( ime )) ret = ime->pImeRegisterWord( readingW, style, stringW ); @@ -2167,6 +2244,7 @@ BOOL WINAPI ImmRegisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, const HeapFree( GetProcessHeap(), 0, stringA ); } + ime_release( ime ); return ret; } @@ -2513,7 +2591,7 @@ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) { /* create the ime window */ data->ime->UIWnd = CreateWindowExW( WS_EX_TOOLWINDOW, data->ime->imeClassName, NULL, - WS_POPUP, 0, 0, 1, 1, 0, 0, data->ime->hIME, 0 ); + WS_POPUP, 0, 0, 1, 1, 0, 0, data->ime->module, 0 ); SetWindowLongPtrW( data->ime->UIWnd, IMMGWL_IMC, (LONG_PTR)data ); } else if (fOpen) SetWindowLongPtrW( data->ime->UIWnd, IMMGWL_IMC, (LONG_PTR)data ); @@ -2605,7 +2683,7 @@ BOOL WINAPI ImmUnregisterWordA( HKL hkl, const char *readingA, DWORD style, cons TRACE( "hkl %p, readingA %s, style %lu, stringA %s.\n", hkl, debugstr_a(readingA), style, debugstr_a(stringA) ); - if (!(ime = IMM_GetImmHkl( hkl ))) return FALSE; + if (!(ime = ime_acquire( hkl ))) return FALSE; if (!is_kbd_ime_unicode( ime )) ret = ime->pImeUnregisterWord( readingA, style, stringA ); @@ -2617,6 +2695,7 @@ BOOL WINAPI ImmUnregisterWordA( HKL hkl, const char *readingA, DWORD style, cons HeapFree( GetProcessHeap(), 0, stringW ); } + ime_release( ime ); return ret; } @@ -2630,7 +2709,7 @@ BOOL WINAPI ImmUnregisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, con TRACE( "hkl %p, readingW %s, style %lu, stringW %s.\n", hkl, debugstr_w(readingW), style, debugstr_w(stringW) ); - if (!(ime = IMM_GetImmHkl( hkl ))) return FALSE; + if (!(ime = ime_acquire( hkl ))) return FALSE; if (is_kbd_ime_unicode( ime )) ret = ime->pImeUnregisterWord( readingW, style, stringW ); @@ -2642,6 +2721,7 @@ BOOL WINAPI ImmUnregisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, con HeapFree( GetProcessHeap(), 0, stringA ); } + ime_release( ime ); return ret; } @@ -2970,10 +3050,12 @@ BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD { struct ime *new_hkl; - if (!(new_hkl = IMM_GetImmHkl( hKL ))) return FALSE; + if (!(new_hkl = ime_acquire( hKL ))) return FALSE; data->ime->pImeSelect( imc, FALSE ); data->ime->uSelected--; + ime_release( data->ime ); + data->ime = new_hkl; data->ime->pImeSelect( imc, TRUE ); data->ime->uSelected++; @@ -3033,8 +3115,9 @@ static HWND get_ui_window(HKL hkl) struct ime *ime; HWND hwnd; - if (!(ime = IMM_GetImmHkl( hkl ))) return 0; + if (!(ime = ime_acquire( hkl ))) return 0; hwnd = ime->UIWnd; + ime_release( ime ); return hwnd; } diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 9d63c80c514..16e570c4c8d 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2603,7 +2603,7 @@ static BOOL WINAPI ime_DllMain( HINSTANCE instance, DWORD reason, LPVOID reserve case DLL_PROCESS_DETACH: UnregisterClassW( ime_ui_class.lpszClassName, instance ); - todo_wine CHECK_EXPECT( IME_DLL_PROCESS_DETACH ); + CHECK_EXPECT( IME_DLL_PROCESS_DETACH ); break; } @@ -2770,29 +2770,21 @@ static void test_ImmInstallIME(void) SET_EXPECT( IME_DLL_PROCESS_ATTACH ); SET_EXPECT( ImeInquire ); ret = ImmLoadIME( hkl ); - todo_wine ok( ret, "ImmLoadIME returned %#x\n", ret ); - todo_wine CHECK_CALLED( IME_DLL_PROCESS_ATTACH ); - todo_wine CHECK_CALLED( ImeInquire ); ret = ImmLoadIME( hkl ); - todo_wine ok( ret, "ImmLoadIME returned %#x\n", ret ); SET_EXPECT( ImeDestroy ); SET_EXPECT( IME_DLL_PROCESS_DETACH ); ret = ImmFreeLayout( hkl ); - todo_wine ok( ret, "ImmFreeLayout returned %#x\n", ret ); - todo_wine CHECK_CALLED( ImeDestroy ); - todo_wine CHECK_CALLED( IME_DLL_PROCESS_DETACH ); ret = ImmFreeLayout( hkl ); - todo_wine ok( ret, "ImmFreeLayout returned %#x\n", ret ); ime_cleanup( hkl ); @@ -2804,29 +2796,21 @@ static void test_ImmInstallIME(void) SET_EXPECT( IME_DLL_PROCESS_ATTACH ); SET_EXPECT( ImeInquire ); ret = ImmLoadIME( hkl ); - todo_wine ok( ret, "ImmLoadIME returned %#x\n", ret ); - todo_wine CHECK_CALLED( IME_DLL_PROCESS_ATTACH ); - todo_wine CHECK_CALLED( ImeInquire ); ret = ImmLoadIME( hkl ); - todo_wine ok( ret, "ImmLoadIME returned %#x\n", ret ); SET_EXPECT( ImeDestroy ); SET_EXPECT( IME_DLL_PROCESS_DETACH ); ret = ImmFreeLayout( hkl ); - todo_wine ok( ret, "ImmFreeLayout returned %#x\n", ret ); - todo_wine CHECK_CALLED( ImeDestroy ); - todo_wine CHECK_CALLED( IME_DLL_PROCESS_DETACH ); ret = ImmFreeLayout( hkl ); - todo_wine ok( ret, "ImmFreeLayout returned %#x\n", ret ); ime_cleanup( hkl ); From 0414c6b770595e94f344fc05be5f421941087ba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 17:43:58 +0100 Subject: [PATCH 1717/2777] imm32: Rename some struct ime members. (cherry picked from commit c76b55991ac57d821be2cbd7f62121bf38157956) --- dlls/imm32/imm.c | 66 ++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 389aead8264..e0366961767 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -60,12 +60,12 @@ struct ime HMODULE module; struct list entry; - IMEINFO imeInfo; - WCHAR imeClassName[17]; /* 16 character max */ - ULONG uSelected; - HWND UIWnd; + IMEINFO info; + WCHAR ui_class[17]; + HWND ui_hwnd; + + ULONG uSelected; - /* Function Pointers */ BOOL (WINAPI *pImeInquire)(IMEINFO *, void *, DWORD); BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *); BOOL (WINAPI *pImeDestroy)(UINT); @@ -129,12 +129,12 @@ static const WCHAR szImeRegFmt[] = L"System\\CurrentControlSet\\Control\\Keyboar static inline BOOL is_himc_ime_unicode(const InputContextData *data) { - return !!(data->ime->imeInfo.fdwProperty & IME_PROP_UNICODE); + return !!(data->ime->info.fdwProperty & IME_PROP_UNICODE); } static inline BOOL is_kbd_ime_unicode( const struct ime *hkl ) { - return !!(hkl->imeInfo.fdwProperty & IME_PROP_UNICODE); + return !!(hkl->info.fdwProperty & IME_PROP_UNICODE); } static BOOL IMM_DestroyContext(HIMC hIMC); @@ -532,10 +532,10 @@ BOOL WINAPI ImmLoadIME( HKL hkl ) LOAD_FUNCPTR( ImeGetImeMenuItems ); #undef LOAD_FUNCPTR - if (!ime->pImeInquire( &ime->imeInfo, buffer, 0 )) goto failed; + if (!ime->pImeInquire( &ime->info, buffer, 0 )) goto failed; - if (is_kbd_ime_unicode( ime )) lstrcpynW( ime->imeClassName, buffer, ARRAY_SIZE(ime->imeClassName) ); - else MultiByteToWideChar( CP_ACP, 0, (char *)buffer, -1, ime->imeClassName, ARRAY_SIZE(ime->imeClassName) ); + if (is_kbd_ime_unicode( ime )) lstrcpynW( ime->ui_class, buffer, ARRAY_SIZE(ime->ui_class) ); + else MultiByteToWideChar( CP_ACP, 0, (char *)buffer, -1, ime->ui_class, ARRAY_SIZE(ime->ui_class) ); EnterCriticalSection( &ime_cs ); list_add_tail( &ime_list, &ime->entry ); @@ -579,7 +579,7 @@ static void ime_release( struct ime *ime ) ref = --ime->refcount; TRACE( "ime %p decreasing refcount to %lu.\n", ime, ref ); - if (!ref && (ime->imeInfo.fdwProperty & IME_PROP_END_UNLOAD)) + if (!ref && (ime->info.fdwProperty & IME_PROP_END_UNLOAD)) ImmFreeLayout( ime->hkl ); LeaveCriticalSection( &ime_cs ); @@ -628,7 +628,7 @@ static void IMM_FreeAllImmHkl(void) ime->pImeDestroy( 1 ); FreeLibrary( ime->module ); - if (ime->UIWnd) DestroyWindow( ime->UIWnd ); + if (ime->ui_hwnd) DestroyWindow( ime->ui_hwnd ); free( ime ); } } @@ -904,10 +904,10 @@ static InputContextData *create_input_context(HIMC default_imc) new_context->IMC.cfCandForm[i].dwIndex = ~0u; /* Initialize the IME Private */ - new_context->IMC.hPrivate = ImmCreateIMCC( new_context->ime->imeInfo.dwPrivateDataSize ); + new_context->IMC.hPrivate = ImmCreateIMCC( new_context->ime->info.dwPrivateDataSize ); - new_context->IMC.fdwConversion = new_context->ime->imeInfo.fdwConversionCaps; - new_context->IMC.fdwSentence = new_context->ime->imeInfo.fdwSentenceCaps; + new_context->IMC.fdwConversion = new_context->ime->info.fdwConversionCaps; + new_context->IMC.fdwSentence = new_context->ime->info.fdwSentenceCaps; if (!default_imc) new_context->handle = NtUserCreateInputContext((UINT_PTR)new_context); @@ -1922,11 +1922,11 @@ DWORD WINAPI ImmGetProperty( HKL hkl, DWORD index ) switch (index) { - case IGP_PROPERTY: ret = ime->imeInfo.fdwProperty; break; - case IGP_CONVERSION: ret = ime->imeInfo.fdwConversionCaps; break; - case IGP_SENTENCE: ret = ime->imeInfo.fdwSentenceCaps; break; - case IGP_SETCOMPSTR: ret = ime->imeInfo.fdwSCSCaps; break; - case IGP_SELECT: ret = ime->imeInfo.fdwSelectCaps; break; + case IGP_PROPERTY: ret = ime->info.fdwProperty; break; + case IGP_CONVERSION: ret = ime->info.fdwConversionCaps; break; + case IGP_SENTENCE: ret = ime->info.fdwSentenceCaps; break; + case IGP_SETCOMPSTR: ret = ime->info.fdwSCSCaps; break; + case IGP_SELECT: ret = ime->info.fdwSelectCaps; break; case IGP_GETIMEVERSION: ret = IMEVER_0400; break; case IGP_UI: ret = 0; break; default: ret = 0; break; @@ -2517,15 +2517,15 @@ BOOL WINAPI ImmSetCompositionWindow( data->IMC.cfCompForm = *lpCompForm; - if (IsWindowVisible( data->ime->UIWnd )) + if (IsWindowVisible( data->ime->ui_hwnd )) { reshow = TRUE; - ShowWindow( data->ime->UIWnd, SW_HIDE ); + ShowWindow( data->ime->ui_hwnd, SW_HIDE ); } /* FIXME: this is a partial stub */ - if (reshow) ShowWindow( data->ime->UIWnd, SW_SHOWNOACTIVATE ); + if (reshow) ShowWindow( data->ime->ui_hwnd, SW_SHOWNOACTIVATE ); ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0); return TRUE; @@ -2587,14 +2587,14 @@ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) if (IMM_IsCrossThreadAccess(NULL, hIMC)) return FALSE; - if (data->ime->UIWnd == NULL) + if (data->ime->ui_hwnd == NULL) { /* create the ime window */ - data->ime->UIWnd = CreateWindowExW( WS_EX_TOOLWINDOW, data->ime->imeClassName, NULL, + data->ime->ui_hwnd = CreateWindowExW( WS_EX_TOOLWINDOW, data->ime->ui_class, NULL, WS_POPUP, 0, 0, 1, 1, 0, 0, data->ime->module, 0 ); - SetWindowLongPtrW( data->ime->UIWnd, IMMGWL_IMC, (LONG_PTR)data ); + SetWindowLongPtrW( data->ime->ui_hwnd, IMMGWL_IMC, (LONG_PTR)data ); } - else if (fOpen) SetWindowLongPtrW( data->ime->UIWnd, IMMGWL_IMC, (LONG_PTR)data ); + else if (fOpen) SetWindowLongPtrW( data->ime->ui_hwnd, IMMGWL_IMC, (LONG_PTR)data ); if (!fOpen != !data->IMC.fOpen) { @@ -2998,7 +2998,7 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list_count * sizeof(TRANSMSG) + sizeof(DWORD)); list->uMsgCount = list_count; - if (data->ime->imeInfo.fdwProperty & IME_PROP_KBD_CHAR_FIRST) + if (data->ime->info.fdwProperty & IME_PROP_KBD_CHAR_FIRST) { WCHAR chr; @@ -3116,7 +3116,7 @@ static HWND get_ui_window(HKL hkl) HWND hwnd; if (!(ime = ime_acquire( hkl ))) return 0; - hwnd = ime->UIWnd; + hwnd = ime->ui_hwnd; ime_release( ime ); return hwnd; @@ -3189,7 +3189,7 @@ static void init_messages(void) LRESULT WINAPI __wine_ime_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL ansi) { - HWND uiwnd; + HWND ui_hwnd; switch (msg) { @@ -3211,12 +3211,12 @@ LRESULT WINAPI __wine_ime_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lp if (is_ime_ui_msg(msg)) { - if ((uiwnd = get_ui_window(NtUserGetKeyboardLayout(0)))) + if ((ui_hwnd = get_ui_window(NtUserGetKeyboardLayout(0)))) { if (ansi) - return SendMessageA(uiwnd, msg, wparam, lparam); + return SendMessageA(ui_hwnd, msg, wparam, lparam); else - return SendMessageW(uiwnd, msg, wparam, lparam); + return SendMessageW(ui_hwnd, msg, wparam, lparam); } return FALSE; } From 934b6e3983b81e89dcd441153418872b13f4456a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 17:44:44 +0100 Subject: [PATCH 1718/2777] imm32: Delete unnecessary uSelected struct ime member. (cherry picked from commit ea4b97bf4ec332f263c6aae341daba37506e7ffb) --- dlls/imm32/imm.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index e0366961767..695e263d39b 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -64,8 +64,6 @@ struct ime WCHAR ui_class[17]; HWND ui_hwnd; - ULONG uSelected; - BOOL (WINAPI *pImeInquire)(IMEINFO *, void *, DWORD); BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *); BOOL (WINAPI *pImeDestroy)(UINT); @@ -593,7 +591,6 @@ static BOOL free_input_context_data( HIMC hIMC ) TRACE( "Destroying %p\n", hIMC ); - data->ime->uSelected--; data->ime->pImeSelect( hIMC, FALSE ); SendMessageW( data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->ime ); @@ -928,7 +925,6 @@ static InputContextData *create_input_context(HIMC default_imc) new_context->threadID = GetCurrentThreadId(); SendMessageW( GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)new_context->ime ); - new_context->ime->uSelected++; TRACE("Created context %p\n", new_context); return new_context; } @@ -3053,12 +3049,10 @@ BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD if (!(new_hkl = ime_acquire( hKL ))) return FALSE; data->ime->pImeSelect( imc, FALSE ); - data->ime->uSelected--; ime_release( data->ime ); data->ime = new_hkl; data->ime->pImeSelect( imc, TRUE ); - data->ime->uSelected++; } GetKeyboardState(state); From d3998a25fac6b1fa436c8611ff77cc427b76b7bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 17:47:29 +0100 Subject: [PATCH 1719/2777] imm32: Use a single ime_is_unicode helper. (cherry picked from commit 0392621858a46d7a282b3585e6cad2333a4ca61c) --- dlls/imm32/imm.c | 73 ++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 695e263d39b..14b357d9533 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -125,14 +125,9 @@ static struct list ime_list = LIST_INIT( ime_list ); static const WCHAR szImeRegFmt[] = L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08lx"; -static inline BOOL is_himc_ime_unicode(const InputContextData *data) +static BOOL ime_is_unicode( const struct ime *ime ) { - return !!(data->ime->info.fdwProperty & IME_PROP_UNICODE); -} - -static inline BOOL is_kbd_ime_unicode( const struct ime *hkl ) -{ - return !!(hkl->info.fdwProperty & IME_PROP_UNICODE); + return !!(ime->info.fdwProperty & IME_PROP_UNICODE); } static BOOL IMM_DestroyContext(HIMC hIMC); @@ -532,7 +527,7 @@ BOOL WINAPI ImmLoadIME( HKL hkl ) if (!ime->pImeInquire( &ime->info, buffer, 0 )) goto failed; - if (is_kbd_ime_unicode( ime )) lstrcpynW( ime->ui_class, buffer, ARRAY_SIZE(ime->ui_class) ); + if (ime_is_unicode( ime )) lstrcpynW( ime->ui_class, buffer, ARRAY_SIZE(ime->ui_class) ); else MultiByteToWideChar( CP_ACP, 0, (char *)buffer, -1, ime->ui_class, ARRAY_SIZE(ime->ui_class) ); EnterCriticalSection( &ime_cs ); @@ -818,7 +813,7 @@ BOOL WINAPI ImmConfigureIMEA( HKL hkl, HWND hwnd, DWORD mode, void *data ) if (mode == IME_CONFIG_REGISTERWORD && !data) return FALSE; if (!(ime = ime_acquire( hkl ))) return FALSE; - if (mode != IME_CONFIG_REGISTERWORD || !is_kbd_ime_unicode( ime )) + if (mode != IME_CONFIG_REGISTERWORD || !ime_is_unicode( ime )) ret = ime->pImeConfigure( hkl, hwnd, mode, data ); else { @@ -848,7 +843,7 @@ BOOL WINAPI ImmConfigureIMEW( HKL hkl, HWND hwnd, DWORD mode, void *data ) if (mode == IME_CONFIG_REGISTERWORD && !data) return FALSE; if (!(ime = ime_acquire( hkl ))) return FALSE; - if (mode != IME_CONFIG_REGISTERWORD || is_kbd_ime_unicode( ime )) + if (mode != IME_CONFIG_REGISTERWORD || ime_is_unicode( ime )) ret = ime->pImeConfigure( hkl, hwnd, mode, data ); else { @@ -980,7 +975,7 @@ UINT WINAPI ImmEnumRegisterWordA( HKL hkl, REGISTERWORDENUMPROCA procA, const ch if (!(ime = ime_acquire( hkl ))) return 0; - if (!is_kbd_ime_unicode( ime )) + if (!ime_is_unicode( ime )) ret = ime->pImeEnumRegisterWord( procA, readingA, style, stringA, user ); else { @@ -1008,7 +1003,7 @@ UINT WINAPI ImmEnumRegisterWordW( HKL hkl, REGISTERWORDENUMPROCW procW, const WC if (!(ime = ime_acquire( hkl ))) return 0; - if (is_kbd_ime_unicode( ime )) + if (ime_is_unicode( ime )) ret = ime->pImeEnumRegisterWord( procW, readingW, style, stringW, user ); else { @@ -1044,7 +1039,7 @@ LRESULT WINAPI ImmEscapeA( HKL hkl, HIMC himc, UINT code, void *data ) if (!(ime = ime_acquire( hkl ))) return 0; - if (!EscapeRequiresWA( code ) || !is_kbd_ime_unicode( ime )) + if (!EscapeRequiresWA( code ) || !ime_is_unicode( ime )) ret = ime->pImeEscape( himc, code, data ); else { @@ -1077,7 +1072,7 @@ LRESULT WINAPI ImmEscapeW( HKL hkl, HIMC himc, UINT code, void *data ) if (!(ime = ime_acquire( hkl ))) return 0; - if (!EscapeRequiresWA( code ) || is_kbd_ime_unicode( ime )) + if (!EscapeRequiresWA( code ) || ime_is_unicode( ime )) ret = ime->pImeEscape( himc, code, data ); else { @@ -1123,7 +1118,7 @@ DWORD WINAPI ImmGetCandidateListA( if ( !candlist->dwSize || !candlist->dwCount ) goto done; - if ( !is_himc_ime_unicode(data) ) + if (!ime_is_unicode( data->ime )) { ret = candlist->dwSize; if ( lpCandList && dwBufLen >= ret ) @@ -1156,7 +1151,7 @@ DWORD WINAPI ImmGetCandidateListCountA( *lpdwListCount = count = candinfo->dwCount; - if ( !is_himc_ime_unicode(data) ) + if (!ime_is_unicode( data->ime )) ret = candinfo->dwSize; else { @@ -1188,7 +1183,7 @@ DWORD WINAPI ImmGetCandidateListCountW( *lpdwListCount = count = candinfo->dwCount; - if ( is_himc_ime_unicode(data) ) + if (ime_is_unicode( data->ime )) ret = candinfo->dwSize; else { @@ -1226,7 +1221,7 @@ DWORD WINAPI ImmGetCandidateListW( if ( !candlist->dwSize || !candlist->dwCount ) goto done; - if ( is_himc_ime_unicode(data) ) + if (ime_is_unicode( data->ime )) { ret = candlist->dwSize; if ( lpCandList && dwBufLen >= ret ) @@ -1312,7 +1307,7 @@ static INT CopyCompStringIMEtoClient(const InputContextData *data, const void *s int char_size = unicode ? sizeof(WCHAR) : sizeof(char); INT ret; - if (is_himc_ime_unicode(data) ^ unicode) + if (ime_is_unicode( data->ime ) ^ unicode) { if (unicode) ret = MultiByteToWideChar(CP_ACP, 0, src, src_len, dst, dst_len / sizeof(WCHAR)); @@ -1349,7 +1344,7 @@ static INT CopyCompAttrIMEtoClient(const InputContextData *data, const BYTE *src string.str = comp_string; - if (is_himc_ime_unicode(data) && !unicode) + if (ime_is_unicode( data->ime ) && !unicode) { rc = WideCharToMultiByte(CP_ACP, 0, string.strW, str_len, NULL, 0, NULL, NULL); if (dst_len) @@ -1376,7 +1371,7 @@ static INT CopyCompAttrIMEtoClient(const InputContextData *data, const BYTE *src rc = j; } } - else if (!is_himc_ime_unicode(data) && unicode) + else if (!ime_is_unicode( data->ime ) && unicode) { rc = MultiByteToWideChar(CP_ACP, 0, string.strA, str_len, NULL, 0); if (dst_len) @@ -1412,7 +1407,7 @@ static INT CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT { INT rc; - if (is_himc_ime_unicode(data) && !unicode) + if (ime_is_unicode( data->ime ) && !unicode) { if (tlen) { @@ -1433,7 +1428,7 @@ static INT CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT else rc = slen; } - else if (!is_himc_ime_unicode(data) && unicode) + else if (!ime_is_unicode( data->ime ) && unicode) { if (tlen) { @@ -1466,11 +1461,11 @@ static INT CopyCompOffsetIMEtoClient(InputContextData *data, DWORD offset, LPBYT { int rc; - if (is_himc_ime_unicode(data) && !unicode) + if (ime_is_unicode( data->ime ) && !unicode) { rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL); } - else if (!is_himc_ime_unicode(data) && unicode) + else if (!ime_is_unicode( data->ime ) && unicode) { rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0); } @@ -1645,7 +1640,7 @@ DWORD WINAPI ImmGetConversionListA( HKL hkl, HIMC himc, const char *srcA, CANDID if (!(ime = ime_acquire( hkl ))) return 0; - if (!is_kbd_ime_unicode( ime )) + if (!ime_is_unicode( ime )) ret = ime->pImeConversionList( himc, srcA, listA, lengthA, flags ); else { @@ -1681,7 +1676,7 @@ DWORD WINAPI ImmGetConversionListW( HKL hkl, HIMC himc, const WCHAR *srcW, CANDI if (!(ime = ime_acquire( hkl ))) return 0; - if (is_kbd_ime_unicode( ime )) + if (ime_is_unicode( ime )) ret = ime->pImeConversionList( himc, srcW, listW, lengthW, flags ); else { @@ -1944,7 +1939,7 @@ UINT WINAPI ImmGetRegisterWordStyleA( HKL hkl, UINT count, STYLEBUFA *styleA ) if (!(ime = ime_acquire( hkl ))) return 0; - if (!is_kbd_ime_unicode( ime )) + if (!ime_is_unicode( ime )) ret = ime->pImeGetRegisterWordStyle( count, styleA ); else { @@ -1970,7 +1965,7 @@ UINT WINAPI ImmGetRegisterWordStyleW( HKL hkl, UINT count, STYLEBUFW *styleW ) if (!(ime = ime_acquire( hkl ))) return 0; - if (is_kbd_ime_unicode( ime )) + if (ime_is_unicode( ime )) ret = ime->pImeGetRegisterWordStyle( count, styleW ); else { @@ -2204,7 +2199,7 @@ BOOL WINAPI ImmRegisterWordA( HKL hkl, const char *readingA, DWORD style, const if (!(ime = ime_acquire( hkl ))) return FALSE; - if (!is_kbd_ime_unicode( ime )) + if (!ime_is_unicode( ime )) ret = ime->pImeRegisterWord( readingA, style, stringA ); else { @@ -2230,7 +2225,7 @@ BOOL WINAPI ImmRegisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, const if (!(ime = ime_acquire( hkl ))) return FALSE; - if (is_kbd_ime_unicode( ime )) + if (ime_is_unicode( ime )) ret = ime->pImeRegisterWord( readingW, style, stringW ); else { @@ -2400,7 +2395,7 @@ BOOL WINAPI ImmSetCompositionStringA( dwIndex == SCS_QUERYRECONVERTSTRING)) return FALSE; - if (!is_himc_ime_unicode( data )) + if (!ime_is_unicode( data->ime )) return data->ime->pImeSetCompositionString( hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen ); comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0); @@ -2457,7 +2452,7 @@ BOOL WINAPI ImmSetCompositionStringW( dwIndex == SCS_QUERYRECONVERTSTRING)) return FALSE; - if (is_himc_ime_unicode( data )) + if (ime_is_unicode( data->ime )) return data->ime->pImeSetCompositionString( hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen ); comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL, @@ -2681,7 +2676,7 @@ BOOL WINAPI ImmUnregisterWordA( HKL hkl, const char *readingA, DWORD style, cons if (!(ime = ime_acquire( hkl ))) return FALSE; - if (!is_kbd_ime_unicode( ime )) + if (!ime_is_unicode( ime )) ret = ime->pImeUnregisterWord( readingA, style, stringA ); else { @@ -2707,7 +2702,7 @@ BOOL WINAPI ImmUnregisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, con if (!(ime = ime_acquire( hkl ))) return FALSE; - if (is_kbd_ime_unicode( ime )) + if (ime_is_unicode( ime )) ret = ime->pImeUnregisterWord( readingW, style, stringW ); else { @@ -2739,7 +2734,7 @@ DWORD WINAPI ImmGetImeMenuItemsA( HIMC himc, DWORD flags, DWORD type, IMEMENUITE return 0; } - if (!is_himc_ime_unicode( data ) || (!parentA && !menuA)) + if (!ime_is_unicode( data->ime ) || (!parentA && !menuA)) ret = data->ime->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size ); else { @@ -2797,7 +2792,7 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITE return 0; } - if (is_himc_ime_unicode( data ) || (!parentW && !menuW)) + if (ime_is_unicode( data->ime ) || (!parentW && !menuW)) ret = data->ime->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size ); else { @@ -2998,8 +2993,8 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD { WCHAR chr; - if (!is_himc_ime_unicode(data)) - ToAscii(data->lastVK, scancode, state, &chr, 0); + if (!ime_is_unicode( data->ime )) + ToAscii( data->lastVK, scancode, state, &chr, 0 ); else ToUnicodeEx(data->lastVK, scancode, state, &chr, 1, 0, GetKeyboardLayout(0)); uVirtKey = MAKELONG(data->lastVK,chr); From 1dba0fcd91ff7c54b9d9f8982b23103986592505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 3 Mar 2023 17:06:24 +0100 Subject: [PATCH 1720/2777] win32u: Keep the current user locale when enumerating layouts. The low word of the enumerated HKL is the desired user locale, the high word is either the keyboard layout LANGID, or the keyboard "Layout Id" for additional layouts with the same LANGID. (cherry picked from commit d12dda395f498045edb44a6597cb4a482d27beaa) --- dlls/win32u/input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 73b50f6d656..15165ed93a8 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1275,10 +1275,10 @@ UINT WINAPI NtUserGetKeyboardLayoutList( INT size, HKL *layouts ) tmp = wcstoul( key_info->Name, NULL, 16 ); if (query_reg_ascii_value( subkey, "Layout Id", value_info, sizeof(buffer) ) && value_info->Type == REG_SZ) - tmp = MAKELONG( LOWORD( tmp ), - 0xf000 | (wcstoul( (const WCHAR *)value_info->Data, NULL, 16 ) & 0xfff) ); + tmp = 0xf000 | (wcstoul( (const WCHAR *)value_info->Data, NULL, 16 ) & 0xfff); NtClose( subkey ); + tmp = MAKELONG( LOWORD( layout ), LOWORD( tmp ) ); if (layout == UlongToHandle( tmp )) continue; count++; From 599b9d0337e811d878b9a391c5bb1ba226e13ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 9 Mar 2023 09:48:53 +0100 Subject: [PATCH 1721/2777] win32u: Keep the current user locale when loading layout. (cherry picked from commit 27c5abe3783638707928de7ad38a7a32468b6661) --- dlls/user32/input.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dlls/user32/input.c b/dlls/user32/input.c index 2e08d0e2eda..9fb270ed3ed 100644 --- a/dlls/user32/input.c +++ b/dlls/user32/input.c @@ -440,7 +440,8 @@ BOOL WINAPI BlockInput(BOOL fBlockIt) HKL WINAPI LoadKeyboardLayoutW( const WCHAR *name, UINT flags ) { WCHAR layout_path[MAX_PATH], value[5]; - DWORD value_size, tmp; + LCID locale = GetUserDefaultLCID(); + DWORD id, value_size, tmp; HKEY hkey; HKL layout; @@ -450,6 +451,9 @@ HKL WINAPI LoadKeyboardLayoutW( const WCHAR *name, UINT flags ) if (HIWORD( tmp )) layout = UlongToHandle( tmp ); else layout = UlongToHandle( MAKELONG( LOWORD( tmp ), LOWORD( tmp ) ) ); + if (!((UINT_PTR)layout >> 28)) id = LOWORD( tmp ); + else id = HIWORD( layout ); /* IME or aliased layout */ + wcscpy( layout_path, L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\" ); wcscat( layout_path, name ); @@ -457,11 +461,12 @@ HKL WINAPI LoadKeyboardLayoutW( const WCHAR *name, UINT flags ) { value_size = sizeof(value); if (!RegGetValueW( hkey, NULL, L"Layout Id", RRF_RT_REG_SZ, NULL, (void *)&value, &value_size )) - layout = UlongToHandle( MAKELONG( LOWORD( tmp ), 0xf000 | (wcstoul( value, NULL, 16 ) & 0xfff) ) ); + id = 0xf000 | (wcstoul( value, NULL, 16 ) & 0xfff); RegCloseKey( hkey ); } + layout = UlongToHandle( MAKELONG( locale, id ) ); if ((flags & KLF_ACTIVATE) && NtUserActivateKeyboardLayout( layout, 0 )) return layout; /* FIXME: semi-stub: returning default layout */ From e5ddfc45ca9496d581b7524fbb53b56dc49641b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Feb 2023 11:19:22 +0100 Subject: [PATCH 1722/2777] win32u: Prevent user locale change in NtUserActivateKeyboardLayout. (cherry picked from commit c0366cbb2e5126901de99b7742032a9ad3d9b69b) --- dlls/win32u/input.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 15165ed93a8..c7c8932e385 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1195,6 +1195,7 @@ HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags ) { struct user_thread_info *info = get_user_thread_info(); HKL old_layout; + LCID locale; HWND focus; TRACE_(keyboard)( "layout %p, flags %x\n", layout, flags ); @@ -1208,6 +1209,13 @@ HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags ) return 0; } + if (NtQueryDefaultLocale( TRUE, &locale ) || LOWORD(layout) != locale) + { + RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED ); + FIXME_(keyboard)( "Changing user locale is not supported\n" ); + return 0; + } + if (!user_driver->pActivateKeyboardLayout( layout, flags )) return 0; From cdea5fd42fd171ab7343f8ff39a148f995b3716a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Feb 2023 11:19:22 +0100 Subject: [PATCH 1723/2777] winex11: Remove now unnecessary user locale change checks. (cherry picked from commit 9d72a71f57a0afafe49eb2bc5438c9632e1e76fe) --- dlls/winex11.drv/keyboard.c | 57 ------------------------------------- 1 file changed, 57 deletions(-) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index caf1dbc6b56..8a0a22c452d 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1515,39 +1515,6 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment); } -static HKL get_locale_kbd_layout(void) -{ - LCID layout; - LANGID langid; - - /* FIXME: - * - * layout = main_key_tab[kbd_layout].lcid; - * - * Winword uses return value of GetKeyboardLayout as a codepage - * to translate ANSI keyboard messages to unicode. But we have - * a problem with it: for instance Polish keyboard layout is - * identical to the US one, and therefore instead of the Polish - * locale id we return the US one. - */ - - NtQueryDefaultLocale( TRUE, &layout ); - - /* - * Microsoft Office expects this value to be something specific - * for Japanese and Korean Windows with an IME the value is 0xe001 - * We should probably check to see if an IME exists and if so then - * set this word properly. - */ - langid = PRIMARYLANGID(LANGIDFROMLCID(layout)); - if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN) - layout = MAKELONG( layout, 0xe001 ); /* IME */ - else - layout |= layout << 16; - - return (HKL)(UINT_PTR)layout; -} - /********************************************************************** * X11DRV_InitKeyboard @@ -1819,18 +1786,6 @@ void X11DRV_InitKeyboard( Display *display ) pthread_mutex_unlock( &kbd_mutex ); } -static BOOL match_x11_keyboard_layout(HKL hkl) -{ - const DWORD isIME = 0xE0000000; - HKL xHkl = get_locale_kbd_layout(); - - /* if the layout is an IME, only match the low word (LCID) */ - if (((ULONG_PTR)hkl & isIME) == isIME) - return (LOWORD(hkl) == LOWORD(xHkl)); - else - return (hkl == xHkl); -} - /*********************************************************************** * ActivateKeyboardLayout (X11DRV.@) @@ -1846,13 +1801,6 @@ BOOL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags) return FALSE; } - if (!match_x11_keyboard_layout(hkl)) - { - RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED ); - FIXME("setting keyboard of different locales not supported\n"); - return FALSE; - } - return TRUE; } @@ -1980,8 +1928,6 @@ UINT X11DRV_MapVirtualKeyEx( UINT wCode, UINT wMapType, HKL hkl ) Display *display = thread_init_display(); TRACE("wCode=0x%x, wMapType=%d, hkl %p\n", wCode, wMapType, hkl); - if (!match_x11_keyboard_layout(hkl)) - FIXME("keyboard layout %p is not supported\n", hkl); pthread_mutex_lock( &kbd_mutex ); @@ -2350,9 +2296,6 @@ INT X11DRV_ToUnicodeEx( UINT virtKey, UINT scanCode, const BYTE *lpKeyState, return 0; } - if (!match_x11_keyboard_layout(hkl)) - FIXME_(key)("keyboard layout %p is not supported\n", hkl); - if ((lpKeyState[VK_MENU] & 0x80) && (lpKeyState[VK_CONTROL] & 0x80)) { TRACE_(key)("Ctrl+Alt+[key] won't generate a character\n"); From cb0442be9f9d9b1e8931daf496262d03fe4ba7cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Feb 2023 10:04:55 +0100 Subject: [PATCH 1724/2777] imm32: Rename szImeRegFmt to layouts_formatW. (cherry picked from commit 4eba0765d9f52e26c8cf499cac81f784ba83ddd5) --- dlls/imm32/imm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 14b357d9533..94bc0dea024 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -123,7 +123,7 @@ static CRITICAL_SECTION_DEBUG ime_cs_debug = static CRITICAL_SECTION ime_cs = { &ime_cs_debug, -1, 0, 0, 0, 0 }; static struct list ime_list = LIST_INIT( ime_list ); -static const WCHAR szImeRegFmt[] = L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08lx"; +static const WCHAR layouts_formatW[] = L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08lx"; static BOOL ime_is_unicode( const struct ime *ime ) { @@ -1842,9 +1842,9 @@ UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen) HKEY hkey; DWORD length; DWORD rc; - WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8]; + WCHAR regKey[ARRAY_SIZE(layouts_formatW)+8]; - wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hKL ); + wsprintfW( regKey, layouts_formatW, (ULONG_PTR)hKL ); rc = RegOpenKeyW( HKEY_LOCAL_MACHINE, regKey, &hkey); if (rc != ERROR_SUCCESS) { @@ -2056,7 +2056,7 @@ HKL WINAPI ImmInstallIMEW( HKL hkl; DWORD rc; HKEY hkey; - WCHAR regKey[ARRAY_SIZE(szImeRegFmt)+8]; + WCHAR regKey[ARRAY_SIZE(layouts_formatW)+8]; TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName), debugstr_w(lpszLayoutText)); @@ -2069,7 +2069,7 @@ HKL WINAPI ImmInstallIMEW( DWORD disposition = 0; hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count ); - wsprintfW( regKey, szImeRegFmt, (ULONG_PTR)hkl); + wsprintfW( regKey, layouts_formatW, (ULONG_PTR)hkl); rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition); if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY) From 918856989fa7571da1248ff20f372ce9f140227d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 20 Feb 2023 21:53:19 +0100 Subject: [PATCH 1725/2777] imm32: Transform "Ime File" value in ImmInstallIMEW. (cherry picked from commit 8b0b53379f99d6878e2189edb317780faf3abd55) --- dlls/imm32/imm.c | 61 +++++++++++++++++++--------------------- dlls/imm32/tests/imm32.c | 3 -- 2 files changed, 29 insertions(+), 35 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 94bc0dea024..a915bb25132 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2048,34 +2048,30 @@ HKL WINAPI ImmInstallIMEA( /*********************************************************************** * ImmInstallIMEW (IMM32.@) */ -HKL WINAPI ImmInstallIMEW( - LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText) +HKL WINAPI ImmInstallIMEW( const WCHAR *filename, const WCHAR *description ) { - INT lcid = GetUserDefaultLCID(); - INT count; - HKL hkl; - DWORD rc; + WCHAR path[ARRAY_SIZE(layouts_formatW)+8], buffer[MAX_PATH]; + LCID lcid = GetUserDefaultLCID(); + WORD count = 0x20; + const WCHAR *tmp; + DWORD length; HKEY hkey; - WCHAR regKey[ARRAY_SIZE(layouts_formatW)+8]; - - TRACE ("(%s, %s):\n", debugstr_w(lpszIMEFileName), - debugstr_w(lpszLayoutText)); + HKL hkl; - /* Start with 2. e001 will be blank and so default to the wine internal IME */ - count = 2; + TRACE( "filename %s, description %s\n", debugstr_w(filename), debugstr_w(description) ); while (count < 0xfff) { DWORD disposition = 0; hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count ); - wsprintfW( regKey, layouts_formatW, (ULONG_PTR)hkl); - - rc = RegCreateKeyExW(HKEY_LOCAL_MACHINE, regKey, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition); - if (rc == ERROR_SUCCESS && disposition == REG_CREATED_NEW_KEY) - break; - else if (rc == ERROR_SUCCESS) - RegCloseKey(hkey); + swprintf( path, ARRAY_SIZE(path), layouts_formatW, (ULONG_PTR)hkl); + if (!RegCreateKeyExW( HKEY_LOCAL_MACHINE, path, 0, NULL, 0, + KEY_WRITE, NULL, &hkey, &disposition )) + { + if (disposition == REG_CREATED_NEW_KEY) break; + RegCloseKey( hkey ); + } count++; } @@ -2086,21 +2082,22 @@ HKL WINAPI ImmInstallIMEW( return 0; } - if (rc == ERROR_SUCCESS) - { - rc = RegSetValueExW(hkey, L"Ime File", 0, REG_SZ, (const BYTE*)lpszIMEFileName, - (lstrlenW(lpszIMEFileName) + 1) * sizeof(WCHAR)); - if (rc == ERROR_SUCCESS) - rc = RegSetValueExW(hkey, L"Layout Text", 0, REG_SZ, (const BYTE*)lpszLayoutText, - (lstrlenW(lpszLayoutText) + 1) * sizeof(WCHAR)); - RegCloseKey(hkey); - return hkl; - } - else + if ((tmp = wcsrchr( filename, '\\' ))) tmp++; + else tmp = filename; + + length = LCMapStringW( LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, tmp, -1, buffer, ARRAY_SIZE(buffer) ); + + if (RegSetValueExW( hkey, L"Ime File", 0, REG_SZ, (const BYTE *)buffer, length * sizeof(WCHAR) ) || + RegSetValueExW( hkey, L"Layout Text", 0, REG_SZ, (const BYTE *)description, + (wcslen(description) + 1) * sizeof(WCHAR) )) { - WARN("Unable to set IME registry values\n"); - return 0; + WARN( "Unable to write registry to install IME\n"); + hkl = 0; } + RegCloseKey( hkey ); + + if (!hkl) RegDeleteKeyW( HKEY_LOCAL_MACHINE, path ); + return hkl; } /*********************************************************************** diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 16e570c4c8d..1f96431682a 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2685,7 +2685,6 @@ static HKL ime_install(void) memset( buffer, 0xcd, sizeof(buffer) ); ret = RegQueryValueExW( hkey, L"Ime File", NULL, NULL, (BYTE *)buffer, &len ); ok( !ret, "RegQueryValueExW returned %#lx, error %lu\n", ret, GetLastError() ); - todo_wine ok( !wcsicmp( buffer, wcsrchr( ime_path, '\\' ) + 1 ), "got Ime File %s\n", debugstr_w(buffer) ); len = sizeof(buffer); @@ -2988,13 +2987,11 @@ static void test_ImmGetIMEFileName(void) ret = ImmGetIMEFileNameW( hkl, bufferW, 13 ); todo_wine ok( ret == 12, "ImmGetIMEFileNameW returned %lu\n", ret ); - todo_wine ok( !wcscmp( bufferW, expectW ), "got bufferW %s\n", debugstr_w(bufferW) ); memset( bufferA, 0xcd, sizeof(bufferA) ); ret = ImmGetIMEFileNameA( hkl, bufferA, 13 ); todo_wine ok( ret == 12, "ImmGetIMEFileNameA returned %lu\n", ret ); - todo_wine ok( !strcmp( bufferA, expectA ), "got bufferA %s\n", debugstr_a(bufferA) ); ime_cleanup( hkl ); From 7fae9b9dfc1732bf896ecd1b0a9bcea93fa0b7b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 17 Feb 2023 11:00:59 +0100 Subject: [PATCH 1726/2777] imm32: Rewrite ImmGetIMEFileName(A|W). (cherry picked from commit 85489a53f5e839fd2e5d804a1172da25214351e5) --- dlls/imm32/imm.c | 87 +++++++++++++--------------------------- dlls/imm32/tests/imm32.c | 13 ------ 2 files changed, 27 insertions(+), 73 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index a915bb25132..6acdd8a7344 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1802,82 +1802,49 @@ DWORD WINAPI ImmGetGuideLineW(HIMC hIMC, DWORD dwIndex, LPWSTR lpBuf, DWORD dwBu } /*********************************************************************** - * ImmGetIMEFileNameA (IMM32.@) + * ImmGetIMEFileNameA (IMM32.@) */ -UINT WINAPI ImmGetIMEFileNameA( HKL hKL, LPSTR lpszFileName, UINT uBufLen) +UINT WINAPI ImmGetIMEFileNameA( HKL hkl, char *bufferA, UINT lengthA ) { - LPWSTR bufW = NULL; - UINT wBufLen = uBufLen; - UINT rc; + WCHAR *bufferW; + DWORD lengthW; - if (uBufLen && lpszFileName) - bufW = HeapAlloc(GetProcessHeap(),0,uBufLen * sizeof(WCHAR)); - else /* We need this to get the number of byte required */ - { - bufW = HeapAlloc(GetProcessHeap(),0,MAX_PATH * sizeof(WCHAR)); - wBufLen = MAX_PATH; - } - - rc = ImmGetIMEFileNameW(hKL,bufW,wBufLen); + TRACE( "hkl %p, bufferA %p, lengthA %d\n", hkl, bufferA, lengthA ); - if (rc > 0) - { - if (uBufLen && lpszFileName) - rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, lpszFileName, - uBufLen, NULL, NULL); - else /* get the length */ - rc = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, - NULL); - } + if (!(lengthW = ImmGetIMEFileNameW( hkl, NULL, 0 ))) return 0; + if (!(bufferW = malloc( (lengthW + 1) * sizeof(WCHAR) ))) return 0; + lengthW = ImmGetIMEFileNameW( hkl, bufferW, lengthW + 1 ); + lengthA = WideCharToMultiByte( CP_ACP, 0, bufferW, lengthW, bufferA, + bufferA ? lengthA : 0, NULL, NULL ); + if (bufferA) bufferA[lengthA] = 0; + free( bufferW ); - HeapFree(GetProcessHeap(),0,bufW); - return rc; + return lengthA; } /*********************************************************************** * ImmGetIMEFileNameW (IMM32.@) */ -UINT WINAPI ImmGetIMEFileNameW(HKL hKL, LPWSTR lpszFileName, UINT uBufLen) +UINT WINAPI ImmGetIMEFileNameW( HKL hkl, WCHAR *buffer, UINT length ) { - HKEY hkey; - DWORD length; - DWORD rc; - WCHAR regKey[ARRAY_SIZE(layouts_formatW)+8]; - - wsprintfW( regKey, layouts_formatW, (ULONG_PTR)hKL ); - rc = RegOpenKeyW( HKEY_LOCAL_MACHINE, regKey, &hkey); - if (rc != ERROR_SUCCESS) - { - SetLastError(rc); - return 0; - } + WCHAR path[MAX_PATH]; + HKEY hkey = 0; + DWORD size; - length = 0; - rc = RegGetValueW(hkey, NULL, L"Ime File", RRF_RT_REG_SZ, NULL, NULL, &length); + TRACE( "hkl %p, buffer %p, length %u\n", hkl, buffer, length ); - if (rc != ERROR_SUCCESS) - { - RegCloseKey(hkey); - SetLastError(rc); - return 0; - } - if (length > uBufLen * sizeof(WCHAR) || !lpszFileName) - { - RegCloseKey(hkey); - if (lpszFileName) - { - SetLastError(ERROR_INSUFFICIENT_BUFFER); - return 0; - } - else - return length / sizeof(WCHAR); - } + swprintf( path, ARRAY_SIZE(path), layouts_formatW, (ULONG)(ULONG_PTR)hkl ); + if (RegOpenKeyW( HKEY_LOCAL_MACHINE, path, &hkey )) return 0; - RegGetValueW(hkey, NULL, L"Ime File", RRF_RT_REG_SZ, NULL, lpszFileName, &length); + size = ARRAY_SIZE(path) * sizeof(WCHAR); + if (RegGetValueW( hkey, NULL, L"Ime File", RRF_RT_REG_SZ, NULL, path, &size )) *path = 0; + RegCloseKey( hkey ); - RegCloseKey(hkey); + size = wcslen( path ); + if (!buffer) return size; - return length / sizeof(WCHAR); + lstrcpynW( buffer, path, length ); + return wcslen( buffer ); } /*********************************************************************** diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 1f96431682a..c1038a3adb9 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2937,60 +2937,47 @@ static void test_ImmGetIMEFileName(void) ret = ImmGetIMEFileNameA( hkl, bufferA, 100 ); ok( !ret, "ImmGetIMEFileNameA returned %lu\n", ret ); ret = GetLastError(); - todo_wine ok( ret == 0xdeadbeef, "got error %lu\n", ret ); if (!(hkl = ime_install())) goto cleanup; memset( bufferW, 0xcd, sizeof(bufferW) ); ret = ImmGetIMEFileNameW( hkl, bufferW, 2 ); - todo_wine ok( ret == 1, "ImmGetIMEFileNameW returned %lu\n", ret ); - todo_wine ok( !wcscmp( bufferW, L"W" ), "got bufferW %s\n", debugstr_w(bufferW) ); memset( bufferA, 0xcd, sizeof(bufferA) ); ret = ImmGetIMEFileNameA( hkl, bufferA, 2 ); ok( ret == 0, "ImmGetIMEFileNameA returned %lu\n", ret ); - todo_wine ok( !strcmp( bufferA, "" ), "got bufferA %s\n", debugstr_a(bufferA) ); swprintf( expectW, ARRAY_SIZE(expectW), L"WINE%04X.I", ime_count - 1 ); memset( bufferW, 0xcd, sizeof(bufferW) ); ret = ImmGetIMEFileNameW( hkl, bufferW, 11 ); - todo_wine ok( ret == 10, "ImmGetIMEFileNameW returned %lu\n", ret ); - todo_wine ok( !wcscmp( bufferW, expectW ), "got bufferW %s\n", debugstr_w(bufferW) ); memset( bufferA, 0xcd, sizeof(bufferA) ); ret = ImmGetIMEFileNameA( hkl, bufferA, 11 ); ok( ret == 0, "ImmGetIMEFileNameA returned %lu\n", ret ); - todo_wine ok( !strcmp( bufferA, "" ), "got bufferA %s\n", debugstr_a(bufferA) ); swprintf( expectW, ARRAY_SIZE(expectW), L"WINE%04X.IM", ime_count - 1 ); memset( bufferW, 0xcd, sizeof(bufferW) ); ret = ImmGetIMEFileNameW( hkl, bufferW, 12 ); - todo_wine ok( ret == 11, "ImmGetIMEFileNameW returned %lu\n", ret ); - todo_wine ok( !wcscmp( bufferW, expectW ), "got bufferW %s\n", debugstr_w(bufferW) ); snprintf( expectA, ARRAY_SIZE(expectA), "WINE%04X.IME", ime_count - 1 ); memset( bufferA, 0xcd, sizeof(bufferA) ); ret = ImmGetIMEFileNameA( hkl, bufferA, 12 ); - todo_wine ok( ret == 12, "ImmGetIMEFileNameA returned %lu\n", ret ); - todo_wine ok( !strcmp( bufferA, expectA ), "got bufferA %s\n", debugstr_a(bufferA) ); swprintf( expectW, ARRAY_SIZE(expectW), L"WINE%04X.IME", ime_count - 1 ); memset( bufferW, 0xcd, sizeof(bufferW) ); ret = ImmGetIMEFileNameW( hkl, bufferW, 13 ); - todo_wine ok( ret == 12, "ImmGetIMEFileNameW returned %lu\n", ret ); ok( !wcscmp( bufferW, expectW ), "got bufferW %s\n", debugstr_w(bufferW) ); memset( bufferA, 0xcd, sizeof(bufferA) ); ret = ImmGetIMEFileNameA( hkl, bufferA, 13 ); - todo_wine ok( ret == 12, "ImmGetIMEFileNameA returned %lu\n", ret ); ok( !strcmp( bufferA, expectA ), "got bufferA %s\n", debugstr_a(bufferA) ); From 1c8fec7a11f6df1dbba9921054ebe337bccd1ec6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 17 Feb 2023 10:43:36 +0100 Subject: [PATCH 1727/2777] imm32: Rewrite ImmGetDescription(A|W). (cherry picked from commit e242e094324bf520ed0cc34b78c8696decca3294) --- dlls/imm32/imm.c | 65 +++++++++++++++++++--------------------- dlls/imm32/tests/imm32.c | 15 ---------- 2 files changed, 31 insertions(+), 49 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 6acdd8a7344..6fe6b5e3f0e 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1728,52 +1728,49 @@ HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd) } /*********************************************************************** - * ImmGetDescriptionA (IMM32.@) + * ImmGetDescriptionA (IMM32.@) */ -UINT WINAPI ImmGetDescriptionA( - HKL hKL, LPSTR lpszDescription, UINT uBufLen) +UINT WINAPI ImmGetDescriptionA( HKL hkl, LPSTR bufferA, UINT lengthA ) { - WCHAR *buf; - DWORD len; - - TRACE("%p %p %d\n", hKL, lpszDescription, uBufLen); - - /* find out how many characters in the unicode buffer */ - len = ImmGetDescriptionW( hKL, NULL, 0 ); - if (!len) - return 0; - - /* allocate a buffer of that size */ - buf = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof (WCHAR) ); - if( !buf ) - return 0; - - /* fetch the unicode buffer */ - len = ImmGetDescriptionW( hKL, buf, len + 1 ); - - /* convert it back to ANSI */ - len = WideCharToMultiByte( CP_ACP, 0, buf, len + 1, - lpszDescription, uBufLen, NULL, NULL ); + WCHAR *bufferW; + DWORD lengthW; - HeapFree( GetProcessHeap(), 0, buf ); + TRACE( "hkl %p, bufferA %p, lengthA %d\n", hkl, bufferA, lengthA ); - if (len == 0) - return 0; + if (!(lengthW = ImmGetDescriptionW( hkl, NULL, 0 ))) return 0; + if (!(bufferW = malloc( (lengthW + 1) * sizeof(WCHAR) ))) return 0; + lengthW = ImmGetDescriptionW( hkl, bufferW, lengthW + 1 ); + lengthA = WideCharToMultiByte( CP_ACP, 0, bufferW, lengthW, bufferA, + bufferA ? lengthA : 0, NULL, NULL ); + if (bufferA) bufferA[lengthA] = 0; + free( bufferW ); - return len - 1; + return lengthA; } /*********************************************************************** * ImmGetDescriptionW (IMM32.@) */ -UINT WINAPI ImmGetDescriptionW(HKL hKL, LPWSTR lpszDescription, UINT uBufLen) +UINT WINAPI ImmGetDescriptionW( HKL hkl, WCHAR *buffer, UINT length ) { - FIXME("(%p, %p, %d): semi stub\n", hKL, lpszDescription, uBufLen); + WCHAR path[MAX_PATH]; + HKEY hkey = 0; + DWORD size; + + TRACE( "hkl %p, buffer %p, length %u\n", hkl, buffer, length ); + + swprintf( path, ARRAY_SIZE(path), layouts_formatW, (ULONG)(ULONG_PTR)hkl ); + if (RegOpenKeyW( HKEY_LOCAL_MACHINE, path, &hkey )) return 0; - if (!hKL) return 0; - if (!uBufLen) return lstrlenW(L"Wine XIM" ); - lstrcpynW( lpszDescription, L"Wine XIM", uBufLen ); - return lstrlenW( lpszDescription ); + size = ARRAY_SIZE(path) * sizeof(WCHAR); + if (RegGetValueW( hkey, NULL, L"Layout Text", RRF_RT_REG_SZ, NULL, path, &size )) *path = 0; + RegCloseKey( hkey ); + + size = wcslen( path ); + if (!buffer) return size; + + lstrcpynW( buffer, path, length ); + return wcslen( buffer ); } /*********************************************************************** diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index c1038a3adb9..1ab12a6d84c 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2843,10 +2843,8 @@ static void test_ImmGetDescription(void) ret = ImmGetDescriptionA( NULL, NULL, 100 ); ok( !ret, "ImmGetDescriptionA returned %lu\n", ret ); ret = ImmGetDescriptionW( hkl, bufferW, 100 ); - todo_wine ok( !ret, "ImmGetDescriptionW returned %lu\n", ret ); ret = ImmGetDescriptionA( hkl, bufferA, 100 ); - todo_wine ok( !ret, "ImmGetDescriptionA returned %lu\n", ret ); ret = GetLastError(); ok( ret == 0xdeadbeef, "got error %lu\n", ret ); @@ -2860,46 +2858,33 @@ static void test_ImmGetDescription(void) memset( bufferA, 0xcd, sizeof(bufferA) ); ret = ImmGetDescriptionA( hkl, bufferA, 2 ); ok( ret == 0, "ImmGetDescriptionA returned %lu\n", ret ); - todo_wine ok( !strcmp( bufferA, "" ), "got bufferA %s\n", debugstr_a(bufferA) ); memset( bufferW, 0xcd, sizeof(bufferW) ); ret = ImmGetDescriptionW( hkl, bufferW, 11 ); - todo_wine ok( ret == 10, "ImmGetDescriptionW returned %lu\n", ret ); - todo_wine ok( !wcscmp( bufferW, L"WineTest I" ), "got bufferW %s\n", debugstr_w(bufferW) ); memset( bufferA, 0xcd, sizeof(bufferA) ); ret = ImmGetDescriptionA( hkl, bufferA, 11 ); - todo_wine ok( ret == 0, "ImmGetDescriptionA returned %lu\n", ret ); - todo_wine ok( !strcmp( bufferA, "" ), "got bufferA %s\n", debugstr_a(bufferA) ); memset( bufferW, 0xcd, sizeof(bufferW) ); ret = ImmGetDescriptionW( hkl, bufferW, 12 ); - todo_wine ok( ret == 11, "ImmGetDescriptionW returned %lu\n", ret ); - todo_wine ok( !wcscmp( bufferW, L"WineTest IM" ), "got bufferW %s\n", debugstr_w(bufferW) ); memset( bufferA, 0xcd, sizeof(bufferA) ); ret = ImmGetDescriptionA( hkl, bufferA, 12 ); - todo_wine ok( ret == 12, "ImmGetDescriptionA returned %lu\n", ret ); - todo_wine ok( !strcmp( bufferA, "WineTest IME" ), "got bufferA %s\n", debugstr_a(bufferA) ); memset( bufferW, 0xcd, sizeof(bufferW) ); ret = ImmGetDescriptionW( hkl, bufferW, 13 ); - todo_wine ok( ret == 12, "ImmGetDescriptionW returned %lu\n", ret ); - todo_wine ok( !wcscmp( bufferW, L"WineTest IME" ), "got bufferW %s\n", debugstr_w(bufferW) ); memset( bufferA, 0xcd, sizeof(bufferA) ); ret = ImmGetDescriptionA( hkl, bufferA, 13 ); - todo_wine ok( ret == 12, "ImmGetDescriptionA returned %lu\n", ret ); - todo_wine ok( !strcmp( bufferA, "WineTest IME" ), "got bufferA %s\n", debugstr_a(bufferA) ); ime_cleanup( hkl ); From 24be4a3cbb6874713117f8fa5db00210b7728f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 20 Feb 2023 21:58:37 +0100 Subject: [PATCH 1728/2777] imm32: Use CRT allocation functions. (cherry picked from commit 8bdee1d248b8f549c81ebea56e17505214d1e600) --- dlls/imm32/imm.c | 112 +++++++++++++++++++++++------------------------ 1 file changed, 55 insertions(+), 57 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 6fe6b5e3f0e..682fb748f2f 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -139,8 +139,7 @@ static inline WCHAR *strdupAtoW( const char *str ) if (str) { DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 ); - if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) - MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len ); + if ((ret = malloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len ); } return ret; } @@ -151,8 +150,7 @@ static inline CHAR *strdupWtoA( const WCHAR *str ) if (str) { DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL ); - if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) - WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL ); + if ((ret = malloc( len ))) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL ); } return ret; } @@ -300,7 +298,7 @@ static ULONG WINAPI InitializeSpy_Release(IInitializeSpy *iface) LONG ref = InterlockedDecrement(&spy->ref); if (!ref) { - HeapFree(GetProcessHeap(), 0, spy); + free( spy ); NtUserGetThreadInfo()->client_imm = 0; } return ref; @@ -379,7 +377,7 @@ static void imm_coinit_thread(void) if (!(spy = get_thread_coinit_spy())) { - if (!(spy = HeapAlloc(GetProcessHeap(), 0, sizeof(*spy)))) return; + if (!(spy = malloc( sizeof(*spy) ))) return; spy->IInitializeSpy_iface.lpVtbl = &InitializeSpyVtbl; spy->ref = 1; spy->cookie.QuadPart = 0; @@ -596,7 +594,7 @@ static BOOL free_input_context_data( HIMC hIMC ) ImmDestroyIMCC( data->IMC.hMsgBuf ); ime_release( data->ime ); - HeapFree( GetProcessHeap(), 0, data ); + free( data ); return TRUE; } @@ -822,8 +820,8 @@ BOOL WINAPI ImmConfigureIMEA( HKL hkl, HWND hwnd, DWORD mode, void *data ) wordW.lpWord = strdupAtoW( wordA->lpWord ); wordW.lpReading = strdupAtoW( wordA->lpReading ); ret = ime->pImeConfigure( hkl, hwnd, mode, &wordW ); - HeapFree( GetProcessHeap(), 0, wordW.lpReading ); - HeapFree( GetProcessHeap(), 0, wordW.lpWord ); + free( wordW.lpReading ); + free( wordW.lpWord ); } ime_release( ime ); @@ -852,8 +850,8 @@ BOOL WINAPI ImmConfigureIMEW( HKL hkl, HWND hwnd, DWORD mode, void *data ) wordA.lpWord = strdupWtoA( wordW->lpWord ); wordA.lpReading = strdupWtoA( wordW->lpReading ); ret = ime->pImeConfigure( hkl, hwnd, mode, &wordA ); - HeapFree( GetProcessHeap(), 0, wordA.lpReading ); - HeapFree( GetProcessHeap(), 0, wordA.lpWord ); + free( wordA.lpReading ); + free( wordA.lpWord ); } ime_release( ime ); @@ -867,14 +865,14 @@ static InputContextData *create_input_context(HIMC default_imc) LPCANDIDATEINFO ci; int i; - new_context = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputContextData)); + new_context = calloc( 1, sizeof(InputContextData) ); /* Load the IME */ new_context->threadDefault = !!default_imc; if (!(new_context->ime = ime_acquire( GetKeyboardLayout( 0 ) ))) { TRACE("IME dll could not be loaded\n"); - HeapFree(GetProcessHeap(),0,new_context); + free( new_context ); return 0; } @@ -981,8 +979,8 @@ UINT WINAPI ImmEnumRegisterWordA( HKL hkl, REGISTERWORDENUMPROCA procA, const ch { WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA ); ret = ime->pImeEnumRegisterWord( procA, readingW, style, stringW, user ); - HeapFree( GetProcessHeap(), 0, readingW ); - HeapFree( GetProcessHeap(), 0, stringW ); + free( readingW ); + free( stringW ); } ime_release( ime ); @@ -1009,8 +1007,8 @@ UINT WINAPI ImmEnumRegisterWordW( HKL hkl, REGISTERWORDENUMPROCW procW, const WC { char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW ); ret = ime->pImeEnumRegisterWord( procW, readingA, style, stringA, user ); - HeapFree( GetProcessHeap(), 0, readingA ); - HeapFree( GetProcessHeap(), 0, stringA ); + free( readingA ); + free( stringA ); } ime_release( ime ); @@ -1648,14 +1646,14 @@ DWORD WINAPI ImmGetConversionListA( HKL hkl, HIMC himc, const char *srcA, CANDID WCHAR *srcW = strdupAtoW( srcA ); DWORD lengthW = ime->pImeConversionList( himc, srcW, NULL, 0, flags ); - if (!(listW = HeapAlloc( GetProcessHeap(), 0, lengthW ))) ret = 0; + if (!(listW = malloc( lengthW ))) ret = 0; else { ime->pImeConversionList( himc, srcW, listW, lengthW, flags ); ret = convert_candidatelist_WtoA( listW, listA, lengthA ); - HeapFree( GetProcessHeap(), 0, listW ); + free( listW ); } - HeapFree( GetProcessHeap(), 0, srcW ); + free( srcW ); } ime_release( ime ); @@ -1684,14 +1682,14 @@ DWORD WINAPI ImmGetConversionListW( HKL hkl, HIMC himc, const WCHAR *srcW, CANDI char *srcA = strdupWtoA( srcW ); DWORD lengthA = ime->pImeConversionList( himc, srcA, NULL, 0, flags ); - if (!(listA = HeapAlloc( GetProcessHeap(), 0, lengthA ))) ret = 0; + if (!(listA = malloc( lengthA ))) ret = 0; else { ime->pImeConversionList( himc, srcA, listA, lengthA, flags ); ret = convert_candidatelist_AtoW( listA, listW, lengthW ); - HeapFree( GetProcessHeap(), 0, listA ); + free( listA ); } - HeapFree( GetProcessHeap(), 0, srcA ); + free( srcA ); } ime_release( ime ); @@ -1989,23 +1987,17 @@ UINT WINAPI ImmGetVirtualKey(HWND hWnd) /*********************************************************************** * ImmInstallIMEA (IMM32.@) */ -HKL WINAPI ImmInstallIMEA( - LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText) +HKL WINAPI ImmInstallIMEA( const char *filenameA, const char *descriptionA ) { - LPWSTR lpszwIMEFileName; - LPWSTR lpszwLayoutText; + WCHAR *filenameW = strdupAtoW( filenameA ), *descriptionW = strdupAtoW( descriptionA ); HKL hkl; - TRACE ("(%s, %s)\n", debugstr_a(lpszIMEFileName), - debugstr_a(lpszLayoutText)); + TRACE( "filenameA %s, descriptionA %s\n", debugstr_a(filenameA), debugstr_a(descriptionA) ); - lpszwIMEFileName = strdupAtoW(lpszIMEFileName); - lpszwLayoutText = strdupAtoW(lpszLayoutText); + hkl = ImmInstallIMEW( filenameW, descriptionW ); + free( descriptionW ); + free( filenameW ); - hkl = ImmInstallIMEW(lpszwIMEFileName, lpszwLayoutText); - - HeapFree(GetProcessHeap(),0,lpszwIMEFileName); - HeapFree(GetProcessHeap(),0,lpszwLayoutText); return hkl; } @@ -2024,6 +2016,12 @@ HKL WINAPI ImmInstallIMEW( const WCHAR *filename, const WCHAR *description ) TRACE( "filename %s, description %s\n", debugstr_w(filename), debugstr_w(description) ); + if (!filename || !description) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return 0; + } + while (count < 0xfff) { DWORD disposition = 0; @@ -2166,8 +2164,8 @@ BOOL WINAPI ImmRegisterWordA( HKL hkl, const char *readingA, DWORD style, const { WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA ); ret = ime->pImeRegisterWord( readingW, style, stringW ); - HeapFree( GetProcessHeap(), 0, readingW ); - HeapFree( GetProcessHeap(), 0, stringW ); + free( readingW ); + free( stringW ); } ime_release( ime ); @@ -2192,8 +2190,8 @@ BOOL WINAPI ImmRegisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, const { char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW ); ret = ime->pImeRegisterWord( readingA, style, stringA ); - HeapFree( GetProcessHeap(), 0, readingA ); - HeapFree( GetProcessHeap(), 0, stringA ); + free( readingA ); + free( stringA ); } ime_release( ime ); @@ -2362,22 +2360,22 @@ BOOL WINAPI ImmSetCompositionStringA( comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0); if (comp_len) { - CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len * sizeof(WCHAR)); + CompBuffer = malloc( comp_len * sizeof(WCHAR) ); MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len); } read_len = MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, NULL, 0); if (read_len) { - ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len * sizeof(WCHAR)); + ReadBuffer = malloc( read_len * sizeof(WCHAR) ); MultiByteToWideChar(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len); } rc = ImmSetCompositionStringW(hIMC, dwIndex, CompBuffer, comp_len, ReadBuffer, read_len); - HeapFree(GetProcessHeap(), 0, CompBuffer); - HeapFree(GetProcessHeap(), 0, ReadBuffer); + free( CompBuffer ); + free( ReadBuffer ); return rc; } @@ -2420,7 +2418,7 @@ BOOL WINAPI ImmSetCompositionStringW( NULL); if (comp_len) { - CompBuffer = HeapAlloc(GetProcessHeap(),0,comp_len); + CompBuffer = malloc( comp_len ); WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, CompBuffer, comp_len, NULL, NULL); } @@ -2429,7 +2427,7 @@ BOOL WINAPI ImmSetCompositionStringW( NULL); if (read_len) { - ReadBuffer = HeapAlloc(GetProcessHeap(),0,read_len); + ReadBuffer = malloc( read_len ); WideCharToMultiByte(CP_ACP, 0, lpRead, dwReadLen, ReadBuffer, read_len, NULL, NULL); } @@ -2437,8 +2435,8 @@ BOOL WINAPI ImmSetCompositionStringW( rc = ImmSetCompositionStringA(hIMC, dwIndex, CompBuffer, comp_len, ReadBuffer, read_len); - HeapFree(GetProcessHeap(), 0, CompBuffer); - HeapFree(GetProcessHeap(), 0, ReadBuffer); + free( CompBuffer ); + free( ReadBuffer ); return rc; } @@ -2643,8 +2641,8 @@ BOOL WINAPI ImmUnregisterWordA( HKL hkl, const char *readingA, DWORD style, cons { WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA ); ret = ime->pImeUnregisterWord( readingW, style, stringW ); - HeapFree( GetProcessHeap(), 0, readingW ); - HeapFree( GetProcessHeap(), 0, stringW ); + free( readingW ); + free( stringW ); } ime_release( ime ); @@ -2669,8 +2667,8 @@ BOOL WINAPI ImmUnregisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, con { char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW ); ret = ime->pImeUnregisterWord( readingA, style, stringA ); - HeapFree( GetProcessHeap(), 0, readingA ); - HeapFree( GetProcessHeap(), 0, stringA ); + free( readingA ); + free( stringA ); } ime_release( ime ); @@ -2706,7 +2704,7 @@ DWORD WINAPI ImmGetImeMenuItemsA( HIMC himc, DWORD flags, DWORD type, IMEMENUITE { int count = size / sizeof(LPIMEMENUITEMINFOA); size = count * sizeof(IMEMENUITEMINFOW); - menuW = HeapAlloc( GetProcessHeap(), 0, size ); + menuW = malloc( size ); } ret = data->ime->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size ); @@ -2729,7 +2727,7 @@ DWORD WINAPI ImmGetImeMenuItemsA( HIMC himc, DWORD flags, DWORD type, IMEMENUITE IMEMENUITEM_STRING_SIZE, NULL, NULL ); } } - HeapFree( GetProcessHeap(), 0, menuW ); + free( menuW ); } return ret; @@ -2764,7 +2762,7 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITE { int count = size / sizeof(LPIMEMENUITEMINFOW); size = count * sizeof(IMEMENUITEMINFOA); - menuA = HeapAlloc( GetProcessHeap(), 0, size ); + menuA = malloc( size ); } ret = data->ime->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size ); @@ -2785,7 +2783,7 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITE MultiByteToWideChar( CP_ACP, 0, menuA[i].szString, -1, menuW[i].szString, IMEMENUITEM_STRING_SIZE ); } } - HeapFree( GetProcessHeap(), 0, menuA ); + free( menuA ); } return ret; @@ -2947,7 +2945,7 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD GetKeyboardState(state); scancode = lKeyData >> 0x10 & 0xff; - list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list_count * sizeof(TRANSMSG) + sizeof(DWORD)); + list = calloc( list_count, sizeof(TRANSMSG) + sizeof(DWORD) ); list->uMsgCount = list_count; if (data->ime->info.fdwProperty & IME_PROP_KBD_CHAR_FIRST) @@ -2976,7 +2974,7 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD else if (msg_count > list_count) ImmGenerateMessage(imc); - HeapFree(GetProcessHeap(),0,list); + free( list ); data->lastVK = VK_PROCESSKEY; From ad0f0d89d70a4ef0cbbe12c14ddb1ecf73d6e115 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Mon, 27 Feb 2023 16:10:15 +0800 Subject: [PATCH 1729/2777] user32/tests: Do not modify cursor position when simulating clicks. FVWM by default uses a focus follow mouse model so the window under the mouse cursor automatically gets focus. Windows explorer.exe and other windows managers use click to focus model. So on FVWM, if a test changes the cursor position, it might affects other tests that rely on a specific focus window. Restore the cursor position after sending simulating clicks to avoid affecting other tests unintentionally. FVWM could be configured to use a click to focus model, but right now it will make many tests starting to succeed and other tests fail. So it seems to be too big of a change. Flaky is added to test_SetWindowPos() because this patch makes the tests succeed on Gitlab CI but the same tests still fails for other window managers and on TestBots. (cherry picked from commit 40492eb0071478812436f3e21a2cd4aee1b7bccd) --- dlls/user32/tests/win.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 1252e046ad3..31d14480861 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -3282,7 +3282,7 @@ static void test_SetWindowPos(HWND hwnd, HWND hwnd2) ret = SetWindowPos(hwnd_child, NULL, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_SHOWWINDOW); ok(ret, "Got %d\n", ret); flush_events( TRUE ); - todo_wine check_active_state(hwnd2, hwnd2, hwnd2); + flaky todo_wine check_active_state(hwnd2, hwnd2, hwnd2); DestroyWindow(hwnd_child); } @@ -10186,7 +10186,9 @@ static void simulate_click(int x, int y) { INPUT input[2]; UINT events_no; + POINT pt; + GetCursorPos(&pt); SetCursorPos(x, y); memset(input, 0, sizeof(input)); input[0].type = INPUT_MOUSE; @@ -10199,6 +10201,7 @@ static void simulate_click(int x, int y) U(input[1]).mi.dwFlags = MOUSEEVENTF_LEFTUP; events_no = SendInput(2, input, sizeof(input[0])); ok(events_no == 2, "SendInput returned %d\n", events_no); + SetCursorPos(pt.x, pt.y); } static WNDPROC def_static_proc; From 53e9b2fbc6a6628154c1600f4be9a3f0edb2cbda Mon Sep 17 00:00:00 2001 From: Alexandros Frantzis Date: Tue, 28 Feb 2023 19:22:54 +0200 Subject: [PATCH 1730/2777] win32u: Allow drivers to set the null user driver. Allow passing NULL as the user driver to __wine_set_user_driver(), to set the internal null user driver. This is useful for drivers that may need to tentatively set their own user driver during setup and reset it on failure. Signed-off-by: Alexandros Frantzis (cherry picked from commit 243c19098ee2e5c87a6bdbebdbb4c5cf598a9de2) --- dlls/win32u/driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index eb736de272d..5bae77da5f4 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -1241,7 +1241,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version } driver = malloc( sizeof(*driver) ); - *driver = *funcs; + *driver = funcs ? *funcs : null_user_driver; #define SET_USER_FUNC(name) \ do { if (!driver->p##name) driver->p##name = nulldrv_##name; } while(0) From 8deaed9864315400a0d1a59b35801a6de809f47a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 16 Mar 2023 11:25:34 +0100 Subject: [PATCH 1731/2777] imm32/tests: Use LANG_INVARIANT for the installed IME. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54669 (cherry picked from commit 7f5007f19737449a147d7c4ae356a515df264854) --- dlls/imm32/tests/ime_wrapper.rc | 2 +- dlls/imm32/tests/imm32.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/imm32/tests/ime_wrapper.rc b/dlls/imm32/tests/ime_wrapper.rc index 6844b62195b..812754ce4ce 100644 --- a/dlls/imm32/tests/ime_wrapper.rc +++ b/dlls/imm32/tests/ime_wrapper.rc @@ -18,7 +18,7 @@ #pragma makedep testdll -#define WINE_LANGID 0400 +#define WINE_LANGID 047f #define WINE_FILETYPE VFT_DRV #define WINE_FILESUBTYPE VFT2_DRV_INPUTMETHOD #define WINE_FILENAME "ime_wrapper" diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 1ab12a6d84c..646c3a2127d 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2675,7 +2675,7 @@ static HKL ime_install(void) hkl = ImmInstallIMEW( ime_path, L"WineTest IME" ); todo_wine - ok( hkl == (HKL)(int)0xe0200400, "ImmInstallIMEW returned %p, error %lu\n", hkl, GetLastError() ); + ok( hkl == (HKL)(int)0xe020047f, "ImmInstallIMEW returned %p, error %lu\n", hkl, GetLastError() ); swprintf( buffer, ARRAY_SIZE(buffer), L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08x", hkl ); ret = RegOpenKeyW( HKEY_LOCAL_MACHINE, buffer, &hkey ); From 41e9730b9f6d91880b3991562ca819c212ad0a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 9 Mar 2023 22:46:00 +0100 Subject: [PATCH 1732/2777] imm32/tests: Test ImmIsIME with the installed IME. (cherry picked from commit bb8bcf492c80dcd24cd0469d6da01a4837eeaa29) --- dlls/imm32/tests/imm32.c | 70 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 646c3a2127d..72ebde6a2c7 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -35,6 +35,28 @@ #include "ime_test.h" +static const char *debugstr_ok( const char *cond ) +{ + int c, n = 0; + /* skip possible casts */ + while ((c = *cond++)) + { + if (c == '(') n++; + if (!n) break; + if (c == ')') n--; + } + if (!strchr( cond - 1, '(' )) return wine_dbg_sprintf( "got %s", cond - 1 ); + return wine_dbg_sprintf( "%.*s returned", (int)strcspn( cond - 1, "( " ), cond - 1 ); +} + +#define ok_eq( e, r, t, f, ... ) \ + do \ + { \ + t v = (r); \ + ok( v == (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \ + } while (0) +#define ok_ret( e, r ) ok_eq( e, r, UINT_PTR, "%Iu, error %ld", GetLastError() ) + BOOL WINAPI ImmSetActiveContext(HWND, HIMC, BOOL); static BOOL (WINAPI *pImmAssociateContextEx)(HWND,HIMC,DWORD); @@ -2425,9 +2447,13 @@ static void test_ImmDisableIME(void) #define ime_trace( msg, ... ) if (winetest_debug > 1) trace( "%04lx:%s " msg, GetCurrentThreadId(), __func__, ## __VA_ARGS__ ) +static BOOL todo_ImeInquire; DEFINE_EXPECT( ImeInquire ); +static BOOL todo_ImeDestroy; DEFINE_EXPECT( ImeDestroy ); +static BOOL todo_IME_DLL_PROCESS_ATTACH; DEFINE_EXPECT( IME_DLL_PROCESS_ATTACH ); +static BOOL todo_IME_DLL_PROCESS_DETACH; DEFINE_EXPECT( IME_DLL_PROCESS_DETACH ); static IMEINFO ime_info; @@ -2468,6 +2494,7 @@ static BOOL WINAPI ime_ImeDestroy( UINT force ) { ime_trace( "force %u\n", force ); + todo_wine_if( todo_ImeDestroy ) CHECK_EXPECT( ImeDestroy ); ok( !force, "got force %u\n", force ); @@ -2511,6 +2538,7 @@ static BOOL WINAPI ime_ImeInquire( IMEINFO *info, WCHAR *ui_class, DWORD flags ) { ime_trace( "info %p, ui_class %p, flags %#lx\n", info, ui_class, flags ); + todo_wine_if( todo_ImeInquire ) CHECK_EXPECT( ImeInquire ); ok( !!info, "got info %p\n", info ); @@ -2598,11 +2626,13 @@ static BOOL WINAPI ime_DllMain( HINSTANCE instance, DWORD reason, LPVOID reserve DisableThreadLibraryCalls( instance ); ime_ui_class.hInstance = instance; RegisterClassExW( &ime_ui_class ); + todo_wine_if(todo_IME_DLL_PROCESS_ATTACH) CHECK_EXPECT( IME_DLL_PROCESS_ATTACH ); break; case DLL_PROCESS_DETACH: UnregisterClassW( ime_ui_class.lpszClassName, instance ); + todo_wine_if(todo_IME_DLL_PROCESS_DETACH) CHECK_EXPECT( IME_DLL_PROCESS_DETACH ); break; } @@ -2821,6 +2851,45 @@ static void test_ImmInstallIME(void) SET_ENABLE( IME_DLL_PROCESS_DETACH, FALSE ); } +static void test_ImmIsIME(void) +{ + HKL hkl = GetKeyboardLayout( 0 ); + + SET_ENABLE( IME_DLL_PROCESS_ATTACH, TRUE ); + SET_ENABLE( ImeInquire, TRUE ); + SET_ENABLE( ImeDestroy, TRUE ); + SET_ENABLE( IME_DLL_PROCESS_DETACH, TRUE ); + + SetLastError( 0xdeadbeef ); + todo_wine + ok_ret( 0, ImmIsIME( 0 ) ); + ok_ret( 0xdeadbeef, GetLastError() ); + ok_ret( 1, ImmIsIME( hkl ) ); + + /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ + ime_info.fdwProperty = IME_PROP_END_UNLOAD; + + if (!(hkl = ime_install())) goto cleanup; + + todo_ImeInquire = TRUE; + todo_ImeDestroy = TRUE; + todo_IME_DLL_PROCESS_ATTACH = TRUE; + todo_IME_DLL_PROCESS_DETACH = TRUE; + ok_ret( 1, ImmIsIME( hkl ) ); + todo_IME_DLL_PROCESS_ATTACH = FALSE; + todo_IME_DLL_PROCESS_DETACH = FALSE; + todo_ImeInquire = FALSE; + todo_ImeDestroy = FALSE; + + ime_cleanup( hkl ); + +cleanup: + SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); + SET_ENABLE( ImeInquire, FALSE ); + SET_ENABLE( ImeDestroy, FALSE ); + SET_ENABLE( IME_DLL_PROCESS_DETACH, FALSE ); +} + static void test_ImmGetDescription(void) { HKL hkl = GetKeyboardLayout( 0 ); @@ -2988,6 +3057,7 @@ START_TEST(imm32) test_ImmInstallIME(); test_ImmGetDescription(); test_ImmGetIMEFileName(); + test_ImmIsIME(); if (init()) { From abbbcce8ba4ed33eb704420e7717742abd0c52ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 9 Mar 2023 22:46:00 +0100 Subject: [PATCH 1733/2777] imm32/tests: Test ImmGetProperty with the installed IME. (cherry picked from commit 08a6d7687aaaedcde3fb7c3c1c32910ea651a627) --- dlls/imm32/tests/imm32.c | 93 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 72ebde6a2c7..fb6fe1cb726 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2890,6 +2890,98 @@ static void test_ImmIsIME(void) SET_ENABLE( IME_DLL_PROCESS_DETACH, FALSE ); } +static void test_ImmGetProperty(void) +{ + static const IMEINFO expect_ime_info = + { + .fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET, + }; + static const IMEINFO expect_ime_info_0411 = /* MS Japanese IME */ + { + .fdwProperty = IME_PROP_COMPLETE_ON_UNSELECT | IME_PROP_CANDLIST_START_FROM_1 | IME_PROP_UNICODE | IME_PROP_AT_CARET | 0xa, + .fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE | IME_CMODE_KATAKANA, + .fdwSentenceCaps = IME_SMODE_PLAURALCLAUSE | IME_SMODE_CONVERSATION, + .fdwSCSCaps = SCS_CAP_COMPSTR | SCS_CAP_SETRECONVERTSTRING | SCS_CAP_MAKEREAD, + .fdwSelectCaps = SELECT_CAP_CONVERSION | SELECT_CAP_SENTENCE, + .fdwUICaps = UI_CAP_ROT90, + }; + static const IMEINFO expect_ime_info_0412 = /* MS Korean IME */ + { + .fdwProperty = IME_PROP_CANDLIST_START_FROM_1 | IME_PROP_UNICODE | IME_PROP_AT_CARET | 0xa, + .fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE, + .fdwSentenceCaps = IME_SMODE_NONE, + .fdwSCSCaps = SCS_CAP_COMPSTR | SCS_CAP_SETRECONVERTSTRING, + .fdwSelectCaps = SELECT_CAP_CONVERSION, + .fdwUICaps = UI_CAP_ROT90, + }; + static const IMEINFO expect_ime_info_0804 = /* MS Chinese IME */ + { + .fdwProperty = IME_PROP_CANDLIST_START_FROM_1 | IME_PROP_UNICODE | IME_PROP_AT_CARET | 0xa, + .fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE, + .fdwSentenceCaps = IME_SMODE_PLAURALCLAUSE, + .fdwSCSCaps = SCS_CAP_COMPSTR | SCS_CAP_SETRECONVERTSTRING | SCS_CAP_MAKEREAD, + .fdwUICaps = UI_CAP_ROT90, + }; + HKL hkl = GetKeyboardLayout( 0 ); + const IMEINFO *expect; + + SET_ENABLE( ImeInquire, TRUE ); + SET_ENABLE( ImeDestroy, TRUE ); + + SetLastError( 0xdeadbeef ); + ok_ret( 0, ImmGetProperty( 0, 0 ) ); + ok_ret( 0, ImmGetProperty( hkl, 0 ) ); + + if (hkl == (HKL)0x04110411) expect = &expect_ime_info_0411; + else if (hkl == (HKL)0x04120412) expect = &expect_ime_info_0412; + else if (hkl == (HKL)0x08040804) expect = &expect_ime_info_0804; + else expect = &expect_ime_info; + + ok_ret( expect->fdwProperty, ImmGetProperty( hkl, IGP_PROPERTY ) ); + todo_wine + ok_ret( expect->fdwConversionCaps, ImmGetProperty( hkl, IGP_CONVERSION ) ); + todo_wine + ok_ret( expect->fdwSentenceCaps, ImmGetProperty( hkl, IGP_SENTENCE ) ); + ok_ret( expect->fdwSCSCaps, ImmGetProperty( hkl, IGP_SETCOMPSTR ) ); + todo_wine + ok_ret( expect->fdwSelectCaps, ImmGetProperty( hkl, IGP_SELECT ) ); + ok_ret( IMEVER_0400, ImmGetProperty( hkl, IGP_GETIMEVERSION ) ); + ok_ret( expect->fdwUICaps, ImmGetProperty( hkl, IGP_UI ) ); + ok_ret( 0xdeadbeef, GetLastError() ); + + /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ + ime_info.fdwProperty = IME_PROP_END_UNLOAD; + + if (!(hkl = ime_install())) goto cleanup; + + SET_EXPECT( ImeInquire ); + SET_EXPECT( ImeDestroy ); + ok_ret( 0, ImmGetProperty( hkl, 0 ) ); + CHECK_CALLED( ImeInquire ); + CHECK_CALLED( ImeDestroy ); + + expect = &ime_info; + todo_ImeInquire = TRUE; + todo_ImeDestroy = TRUE; + ok_ret( expect->fdwProperty, ImmGetProperty( hkl, IGP_PROPERTY ) ); + ok_ret( expect->fdwConversionCaps, ImmGetProperty( hkl, IGP_CONVERSION ) ); + ok_ret( expect->fdwSentenceCaps, ImmGetProperty( hkl, IGP_SENTENCE ) ); + ok_ret( expect->fdwSCSCaps, ImmGetProperty( hkl, IGP_SETCOMPSTR ) ); + ok_ret( expect->fdwSelectCaps, ImmGetProperty( hkl, IGP_SELECT ) ); + ok_ret( IMEVER_0400, ImmGetProperty( hkl, IGP_GETIMEVERSION ) ); + ok_ret( expect->fdwUICaps, ImmGetProperty( hkl, IGP_UI ) ); + todo_ImeInquire = FALSE; + called_ImeInquire = FALSE; + todo_ImeDestroy = FALSE; + called_ImeDestroy = FALSE; + + ime_cleanup( hkl ); + +cleanup: + SET_ENABLE( ImeInquire, FALSE ); + SET_ENABLE( ImeDestroy, FALSE ); +} + static void test_ImmGetDescription(void) { HKL hkl = GetKeyboardLayout( 0 ); @@ -3058,6 +3150,7 @@ START_TEST(imm32) test_ImmGetDescription(); test_ImmGetIMEFileName(); test_ImmIsIME(); + test_ImmGetProperty(); if (init()) { From e6cfc86f399732ac392a2bb0581d4b08f30c9b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 Mar 2023 19:33:43 +0100 Subject: [PATCH 1734/2777] imm32/tests: Test ImmEscape with the installed IME. (cherry picked from commit c959a58801183ef407cc2d2b4a149bafa8eb014c) --- dlls/imm32/tests/imm32.c | 161 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 160 insertions(+), 1 deletion(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index fb6fe1cb726..9df89a406c0 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -55,6 +55,18 @@ static const char *debugstr_ok( const char *cond ) t v = (r); \ ok( v == (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \ } while (0) +#define ok_wcs( e, r ) \ + do \ + { \ + const WCHAR *v = (r); \ + ok( !wcscmp( v, (e) ), "%s %s\n", debugstr_ok(#r), debugstr_w(v) ); \ + } while (0) +#define ok_str( e, r ) \ + do \ + { \ + const char *v = (r); \ + ok( !strcmp( v, (e) ), "%s %s\n", debugstr_ok(#r), debugstr_a(v) ); \ + } while (0) #define ok_ret( e, r ) ok_eq( e, r, UINT_PTR, "%Iu, error %ld", GetLastError() ) BOOL WINAPI ImmSetActiveContext(HWND, HIMC, BOOL); @@ -2451,6 +2463,7 @@ static BOOL todo_ImeInquire; DEFINE_EXPECT( ImeInquire ); static BOOL todo_ImeDestroy; DEFINE_EXPECT( ImeDestroy ); +DEFINE_EXPECT( ImeEscape ); static BOOL todo_IME_DLL_PROCESS_ATTACH; DEFINE_EXPECT( IME_DLL_PROCESS_ATTACH ); static BOOL todo_IME_DLL_PROCESS_DETACH; @@ -2514,7 +2527,40 @@ static UINT WINAPI ime_ImeEnumRegisterWord( REGISTERWORDENUMPROCW proc, const WC static LRESULT WINAPI ime_ImeEscape( HIMC himc, UINT escape, void *data ) { ime_trace( "himc %p, escape %#x, data %p\n", himc, escape, data ); - ok( 0, "unexpected call\n" ); + + CHECK_EXPECT( ImeEscape ); + + switch (escape) + { + case IME_ESC_SET_EUDC_DICTIONARY: + if (!data) return 4; + if (ime_info.fdwProperty & IME_PROP_UNICODE) + { + todo_wine_if(*(WCHAR *)data != 'E') + ok_wcs( L"EscapeIme", data ); + } + else + { + todo_wine_if(*(char *)data != 'E') + ok_str( "EscapeIme", data ); + } + /* fallthrough */ + case IME_ESC_QUERY_SUPPORT: + case IME_ESC_SEQUENCE_TO_INTERNAL: + case IME_ESC_GET_EUDC_DICTIONARY: + case IME_ESC_MAX_KEY: + case IME_ESC_IME_NAME: + case IME_ESC_HANJA_MODE: + case IME_ESC_GETHELPFILENAME: + if (!data) return 4; + if (ime_info.fdwProperty & IME_PROP_UNICODE) wcscpy( data, L"ImeEscape" ); + else strcpy( data, "ImeEscape" ); + return 4; + } + + ok_eq( 0xdeadbeef, escape, UINT, "%#x" ); + ok_eq( NULL, data, void *, "%p" ); + return TRUE; } @@ -3136,6 +3182,116 @@ static void test_ImmGetIMEFileName(void) SET_ENABLE( IME_DLL_PROCESS_DETACH, FALSE ); } +static void test_ImmEscape( BOOL unicode ) +{ + HKL hkl = GetKeyboardLayout( 0 ); + DWORD i, codes[] = + { + IME_ESC_QUERY_SUPPORT, + IME_ESC_SEQUENCE_TO_INTERNAL, + IME_ESC_GET_EUDC_DICTIONARY, + IME_ESC_SET_EUDC_DICTIONARY, + IME_ESC_MAX_KEY, + IME_ESC_IME_NAME, + IME_ESC_HANJA_MODE, + IME_ESC_GETHELPFILENAME, + }; + WCHAR bufferW[512]; + char bufferA[512]; + + SET_ENABLE( ImeEscape, TRUE ); + + winetest_push_context( unicode ? "unicode" : "ansi" ); + + SetLastError( 0xdeadbeef ); + ok_ret( 0, ImmEscapeW( hkl, 0, 0, NULL ) ); + ok_ret( 0, ImmEscapeA( hkl, 0, 0, NULL ) ); + todo_wine + ok_ret( 0xdeadbeef, GetLastError() ); + + /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ + ime_info.fdwProperty = IME_PROP_END_UNLOAD; + if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE; + + if (!(hkl = ime_install())) goto cleanup; + + for (i = 0; i < ARRAY_SIZE(codes); ++i) + { + winetest_push_context( "esc %#lx", codes[i] ); + + SET_EXPECT( ImeEscape ); + ok_ret( 4, ImmEscapeW( hkl, 0, codes[i], NULL ) ); + CHECK_CALLED( ImeEscape ); + + SET_EXPECT( ImeEscape ); + memset( bufferW, 0xcd, sizeof(bufferW) ); + if (codes[i] == IME_ESC_SET_EUDC_DICTIONARY) wcscpy( bufferW, L"EscapeIme" ); + ok_ret( 4, ImmEscapeW( hkl, 0, codes[i], bufferW ) ); + if (unicode || codes[i] == IME_ESC_GET_EUDC_DICTIONARY || codes[i] == IME_ESC_IME_NAME || + codes[i] == IME_ESC_GETHELPFILENAME) + { + ok_wcs( L"ImeEscape", bufferW ); + ok_eq( 0xcdcd, bufferW[10], WORD, "%#x" ); + } + else if (codes[i] == IME_ESC_SET_EUDC_DICTIONARY) + { + ok_wcs( L"EscapeIme", bufferW ); + ok_eq( 0xcdcd, bufferW[10], WORD, "%#x" ); + } + else if (codes[i] == IME_ESC_HANJA_MODE) + { + todo_wine + ok_eq( 0xcdcd, bufferW[0], WORD, "%#x" ); + } + else + { + ok( !memcmp( bufferW, "ImeEscape", 10 ), "got bufferW %s\n", debugstr_w(bufferW) ); + ok_eq( 0xcdcd, bufferW[5], WORD, "%#x" ); + } + CHECK_CALLED( ImeEscape ); + + SET_EXPECT( ImeEscape ); + ok_ret( 4, ImmEscapeA( hkl, 0, codes[i], NULL ) ); + CHECK_CALLED( ImeEscape ); + + SET_EXPECT( ImeEscape ); + memset( bufferA, 0xcd, sizeof(bufferA) ); + if (codes[i] == IME_ESC_SET_EUDC_DICTIONARY) strcpy( bufferA, "EscapeIme" ); + ok_ret( 4, ImmEscapeA( hkl, 0, codes[i], bufferA ) ); + if (!unicode || codes[i] == IME_ESC_GET_EUDC_DICTIONARY || codes[i] == IME_ESC_IME_NAME || + codes[i] == IME_ESC_GETHELPFILENAME) + { + ok_str( "ImeEscape", bufferA ); + ok_eq( 0xcd, bufferA[10], BYTE, "%#x" ); + } + else if (codes[i] == IME_ESC_SET_EUDC_DICTIONARY) + { + ok_str( "EscapeIme", bufferA ); + ok_eq( 0xcd, bufferA[10], BYTE, "%#x" ); + } + else if (codes[i] == IME_ESC_HANJA_MODE) + { + todo_wine + ok_eq( 0xcd, bufferA[0], BYTE, "%#x" ); + } + else + { + ok( !memcmp( bufferA, L"ImeEscape", 10 * sizeof(WCHAR) ), "got bufferA %s\n", debugstr_a(bufferA) ); + ok_eq( 0xcd, bufferA[20], BYTE, "%#x" ); + } + CHECK_CALLED( ImeEscape ); + + winetest_pop_context(); + } + + ime_cleanup( hkl ); + +cleanup: + SET_ENABLE( ImeEscape, FALSE ); + + winetest_pop_context(); +} + START_TEST(imm32) { if (!is_ime_enabled()) @@ -3152,6 +3308,9 @@ START_TEST(imm32) test_ImmIsIME(); test_ImmGetProperty(); + test_ImmEscape( FALSE ); + test_ImmEscape( TRUE ); + if (init()) { test_ImmNotifyIME(); From 3f612ab4100d4a8604c378fba5ad4371c3136db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 18 Feb 2023 11:10:35 +0100 Subject: [PATCH 1735/2777] imm32/tests: Test ImmEnumRegisterWord with the installed IME. (cherry picked from commit f05d4cb0c7395e6f913fdfa6a964ba83f29dfcc5) --- dlls/imm32/tests/imm32.c | 98 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 9df89a406c0..4feb423f84e 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2464,6 +2464,7 @@ DEFINE_EXPECT( ImeInquire ); static BOOL todo_ImeDestroy; DEFINE_EXPECT( ImeDestroy ); DEFINE_EXPECT( ImeEscape ); +DEFINE_EXPECT( ImeEnumRegisterWord ); static BOOL todo_IME_DLL_PROCESS_ATTACH; DEFINE_EXPECT( IME_DLL_PROCESS_ATTACH ); static BOOL todo_IME_DLL_PROCESS_DETACH; @@ -2520,7 +2521,28 @@ static UINT WINAPI ime_ImeEnumRegisterWord( REGISTERWORDENUMPROCW proc, const WC { ime_trace( "proc %p, reading %s, style %lu, string %s, data %p\n", proc, debugstr_w(reading), style, debugstr_w(string), data ); - ok( 0, "unexpected call\n" ); + + CHECK_EXPECT( ImeEnumRegisterWord ); + + if (!style) + { + ok_eq( 0, reading, const void *, "%p" ); + ok_eq( 0, string, const void *, "%p" ); + } + else if (ime_info.fdwProperty & IME_PROP_UNICODE) + { + ok_eq( 0xdeadbeef, style, UINT, "%#x" ); + ok_wcs( L"Reading", reading ); + ok_wcs( L"String", string ); + } + else + { + ok_eq( 0xdeadbeef, style, UINT, "%#x" ); + ok_str( "Reading", (char *)reading ); + ok_str( "String", (char *)string ); + } + + if (style) return proc( reading, style, string, data ); return 0; } @@ -3292,6 +3314,78 @@ static void test_ImmEscape( BOOL unicode ) winetest_pop_context(); } +static int CALLBACK enum_register_wordA( const char *reading, DWORD style, const char *string, void *user ) +{ + ime_trace( "reading %s, style %#lx, string %s, user %p\n", debugstr_a(reading), style, debugstr_a(string), user ); + + ok_eq( 0xdeadbeef, style, UINT, "%#x" ); + todo_wine_if( reading[1] == 0 ) + ok_str( "Reading", reading ); + todo_wine_if( string[1] == 0 ) + ok_str( "String", string ); + + return 0xdeadbeef; +} + +static int CALLBACK enum_register_wordW( const WCHAR *reading, DWORD style, const WCHAR *string, void *user ) +{ + ime_trace( "reading %s, style %#lx, string %s, user %p\n", debugstr_w(reading), style, debugstr_w(string), user ); + + ok_eq( 0xdeadbeef, style, UINT, "%#x" ); + todo_wine_if( reading[0] != 'R' ) + ok_wcs( L"Reading", reading ); + todo_wine_if( string[0] != 'S' ) + ok_wcs( L"String", string ); + + return 0xdeadbeef; +} + +static void test_ImmEnumRegisterWord( BOOL unicode ) +{ + HKL hkl = GetKeyboardLayout( 0 ); + + winetest_push_context( unicode ? "unicode" : "ansi" ); + + SET_ENABLE( ImeEnumRegisterWord, TRUE ); + + SetLastError( 0xdeadbeef ); + ok_ret( 0, ImmEnumRegisterWordW( NULL, enum_register_wordW, NULL, 0, NULL, NULL ) ); + ok_ret( 0, ImmEnumRegisterWordA( NULL, enum_register_wordA, NULL, 0, NULL, NULL ) ); + ok_ret( 0, ImmEnumRegisterWordW( hkl, enum_register_wordW, NULL, 0, NULL, NULL ) ); + ok_ret( 0, ImmEnumRegisterWordA( hkl, enum_register_wordA, NULL, 0, NULL, NULL ) ); + todo_wine + ok_ret( 0xdeadbeef, GetLastError() ); + + /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ + ime_info.fdwProperty = IME_PROP_END_UNLOAD; + if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE; + + if (!(hkl = ime_install())) goto cleanup; + + SET_EXPECT( ImeEnumRegisterWord ); + ok_ret( 0, ImmEnumRegisterWordW( hkl, enum_register_wordW, NULL, 0, NULL, NULL ) ); + CHECK_CALLED( ImeEnumRegisterWord ); + + SET_EXPECT( ImeEnumRegisterWord ); + ok_ret( 0, ImmEnumRegisterWordA( hkl, enum_register_wordA, NULL, 0, NULL, NULL ) ); + CHECK_CALLED( ImeEnumRegisterWord ); + + SET_EXPECT( ImeEnumRegisterWord ); + ok_ret( 0xdeadbeef, ImmEnumRegisterWordW( hkl, enum_register_wordW, L"Reading", 0xdeadbeef, L"String", NULL ) ); + CHECK_CALLED( ImeEnumRegisterWord ); + + SET_EXPECT( ImeEnumRegisterWord ); + ok_ret( 0xdeadbeef, ImmEnumRegisterWordA( hkl, enum_register_wordA, "Reading", 0xdeadbeef, "String", NULL ) ); + CHECK_CALLED( ImeEnumRegisterWord ); + + ime_cleanup( hkl ); + +cleanup: + SET_ENABLE( ImeEnumRegisterWord, FALSE ); + + winetest_pop_context(); +} + START_TEST(imm32) { if (!is_ime_enabled()) @@ -3310,6 +3404,8 @@ START_TEST(imm32) test_ImmEscape( FALSE ); test_ImmEscape( TRUE ); + test_ImmEnumRegisterWord( FALSE ); + test_ImmEnumRegisterWord( TRUE ); if (init()) { From 0a88345ce74bdd4ea977867404cf8cc9e6ee9f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 19 Feb 2023 11:55:56 +0100 Subject: [PATCH 1736/2777] imm32/tests: Test ImmRegisterWord with the installed IME. (cherry picked from commit eab785a358debb4a08c0657df6cd097fed6b4bcc) --- dlls/imm32/tests/imm32.c | 81 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 4feb423f84e..31515a8f99a 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2465,6 +2465,7 @@ static BOOL todo_ImeDestroy; DEFINE_EXPECT( ImeDestroy ); DEFINE_EXPECT( ImeEscape ); DEFINE_EXPECT( ImeEnumRegisterWord ); +DEFINE_EXPECT( ImeRegisterWord ); static BOOL todo_IME_DLL_PROCESS_ATTACH; DEFINE_EXPECT( IME_DLL_PROCESS_ATTACH ); static BOOL todo_IME_DLL_PROCESS_DETACH; @@ -2635,7 +2636,21 @@ static BOOL WINAPI ime_ImeProcessKey( HIMC himc, UINT vkey, LPARAM key_data, BYT static BOOL WINAPI ime_ImeRegisterWord( const WCHAR *reading, DWORD style, const WCHAR *string ) { ime_trace( "reading %s, style %lu, string %s\n", debugstr_w(reading), style, debugstr_w(string) ); - ok( 0, "unexpected call\n" ); + + CHECK_EXPECT( ImeRegisterWord ); + + if (style) ok_eq( 0xdeadbeef, style, UINT, "%#x" ); + if (ime_info.fdwProperty & IME_PROP_UNICODE) + { + if (reading) ok_wcs( L"Reading", reading ); + if (string) ok_wcs( L"String", string ); + } + else + { + if (reading) ok_str( "Reading", (char *)reading ); + if (string) ok_str( "String", (char *)string ); + } + return FALSE; } @@ -3386,6 +3401,68 @@ static void test_ImmEnumRegisterWord( BOOL unicode ) winetest_pop_context(); } +static void test_ImmRegisterWord( BOOL unicode ) +{ + HKL hkl = GetKeyboardLayout( 0 ); + + SET_ENABLE( ImeRegisterWord, TRUE ); + + winetest_push_context( unicode ? "unicode" : "ansi" ); + + SetLastError( 0xdeadbeef ); + ok_ret( 0, ImmRegisterWordW( NULL, NULL, 0, NULL ) ); + ok_ret( 0, ImmRegisterWordA( NULL, NULL, 0, NULL ) ); + ok_ret( 0, ImmRegisterWordW( hkl, NULL, 0, NULL ) ); + ok_ret( 0, ImmRegisterWordA( hkl, NULL, 0, NULL ) ); + todo_wine + ok_ret( 0xdeadbeef, GetLastError() ); + + /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ + ime_info.fdwProperty = IME_PROP_END_UNLOAD; + if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE; + + if (!(hkl = ime_install())) goto cleanup; + + SET_EXPECT( ImeRegisterWord ); + ok_ret( 0, ImmRegisterWordW( hkl, NULL, 0, NULL ) ); + CHECK_CALLED( ImeRegisterWord ); + + SET_EXPECT( ImeRegisterWord ); + ok_ret( 0, ImmRegisterWordA( hkl, NULL, 0, NULL ) ); + CHECK_CALLED( ImeRegisterWord ); + + SET_EXPECT( ImeRegisterWord ); + ok_ret( 0, ImmRegisterWordW( hkl, L"Reading", 0, NULL ) ); + CHECK_CALLED( ImeRegisterWord ); + + SET_EXPECT( ImeRegisterWord ); + ok_ret( 0, ImmRegisterWordA( hkl, "Reading", 0, NULL ) ); + CHECK_CALLED( ImeRegisterWord ); + + SET_EXPECT( ImeRegisterWord ); + ok_ret( 0, ImmRegisterWordW( hkl, NULL, 0xdeadbeef, NULL ) ); + CHECK_CALLED( ImeRegisterWord ); + + SET_EXPECT( ImeRegisterWord ); + ok_ret( 0, ImmRegisterWordA( hkl, NULL, 0xdeadbeef, NULL ) ); + CHECK_CALLED( ImeRegisterWord ); + + SET_EXPECT( ImeRegisterWord ); + ok_ret( 0, ImmRegisterWordW( hkl, NULL, 0, L"String" ) ); + CHECK_CALLED( ImeRegisterWord ); + + SET_EXPECT( ImeRegisterWord ); + ok_ret( 0, ImmRegisterWordA( hkl, NULL, 0, "String" ) ); + CHECK_CALLED( ImeRegisterWord ); + + ime_cleanup( hkl ); + +cleanup: + SET_ENABLE( ImeRegisterWord, FALSE ); + + winetest_pop_context(); +} + START_TEST(imm32) { if (!is_ime_enabled()) @@ -3406,6 +3483,8 @@ START_TEST(imm32) test_ImmEscape( TRUE ); test_ImmEnumRegisterWord( FALSE ); test_ImmEnumRegisterWord( TRUE ); + test_ImmRegisterWord( FALSE ); + test_ImmRegisterWord( TRUE ); if (init()) { From 64ae120c0152ee4791ba8916f381d9e21cd12990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 19 Feb 2023 11:58:44 +0100 Subject: [PATCH 1737/2777] imm32/tests: Test ImmGetRegisterWordStyle with the installed IME. (cherry picked from commit 6896953d95bbb103b04221e321a91ce7343018ba) --- dlls/imm32/tests/imm32.c | 101 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 31515a8f99a..faeb9f19a2b 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2466,6 +2466,7 @@ DEFINE_EXPECT( ImeDestroy ); DEFINE_EXPECT( ImeEscape ); DEFINE_EXPECT( ImeEnumRegisterWord ); DEFINE_EXPECT( ImeRegisterWord ); +DEFINE_EXPECT( ImeGetRegisterWordStyle ); static BOOL todo_IME_DLL_PROCESS_ATTACH; DEFINE_EXPECT( IME_DLL_PROCESS_ATTACH ); static BOOL todo_IME_DLL_PROCESS_DETACH; @@ -2599,8 +2600,25 @@ static DWORD WINAPI ime_ImeGetImeMenuItems( HIMC himc, DWORD flags, DWORD type, static UINT WINAPI ime_ImeGetRegisterWordStyle( UINT item, STYLEBUFW *style ) { ime_trace( "item %u, style %p\n", item, style ); - ok( 0, "unexpected call\n" ); - return 0; + + CHECK_EXPECT( ImeGetRegisterWordStyle ); + + if (!style) + ok_eq( 16, item, UINT, "%u" ); + else if (ime_info.fdwProperty & IME_PROP_UNICODE) + { + STYLEBUFW *styleW = style; + styleW->dwStyle = 0xdeadbeef; + wcscpy( styleW->szDescription, L"StyleDescription" ); + } + else + { + STYLEBUFA *styleA = (STYLEBUFA *)style; + styleA->dwStyle = 0xdeadbeef; + strcpy( styleA->szDescription, "StyleDescription" ); + } + + return 0xdeadbeef; } static BOOL WINAPI ime_ImeInquire( IMEINFO *info, WCHAR *ui_class, DWORD flags ) @@ -3463,6 +3481,83 @@ static void test_ImmRegisterWord( BOOL unicode ) winetest_pop_context(); } +static void test_ImmGetRegisterWordStyle( BOOL unicode ) +{ + HKL hkl = GetKeyboardLayout( 0 ); + STYLEBUFW styleW; + STYLEBUFA styleA; + + winetest_push_context( unicode ? "unicode" : "ansi" ); + + SET_ENABLE( ImeGetRegisterWordStyle, TRUE ); + + SetLastError( 0xdeadbeef ); + ok_ret( 0, ImmGetRegisterWordStyleW( NULL, 0, &styleW ) ); + ok_ret( 0, ImmGetRegisterWordStyleA( NULL, 0, &styleA ) ); + ok_ret( 0, ImmGetRegisterWordStyleW( hkl, 0, &styleW ) ); + ok_ret( 0, ImmGetRegisterWordStyleA( hkl, 0, &styleA ) ); + todo_wine + ok_ret( 0xdeadbeef, GetLastError() ); + + /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ + ime_info.fdwProperty = IME_PROP_END_UNLOAD; + if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE; + + if (!(hkl = ime_install())) goto cleanup; + + if (!strcmp( winetest_platform, "wine" )) goto skip_null; + + SET_EXPECT( ImeGetRegisterWordStyle ); + ok_ret( 0xdeadbeef, ImmGetRegisterWordStyleW( hkl, 16, NULL ) ); + CHECK_CALLED( ImeGetRegisterWordStyle ); + + SET_EXPECT( ImeGetRegisterWordStyle ); + ok_ret( 0xdeadbeef, ImmGetRegisterWordStyleA( hkl, 16, NULL ) ); + CHECK_CALLED( ImeGetRegisterWordStyle ); + +skip_null: + SET_EXPECT( ImeGetRegisterWordStyle ); + memset( &styleW, 0xcd, sizeof(styleW) ); + ok_ret( 0xdeadbeef, ImmGetRegisterWordStyleW( hkl, 1, &styleW ) ); + if (ime_info.fdwProperty & IME_PROP_UNICODE) + { + ok_eq( 0xdeadbeef, styleW.dwStyle, UINT, "%#x" ); + ok_wcs( L"StyleDescription", styleW.szDescription ); + } + else + { + todo_wine + ok_eq( 0xcdcdcdcd, styleW.dwStyle, UINT, "%#x" ); + todo_wine + ok_eq( 0xcdcd, styleW.szDescription[0], WORD, "%#x" ); + } + CHECK_CALLED( ImeGetRegisterWordStyle ); + + SET_EXPECT( ImeGetRegisterWordStyle ); + memset( &styleA, 0xcd, sizeof(styleA) ); + ok_ret( 0xdeadbeef, ImmGetRegisterWordStyleA( hkl, 1, &styleA ) ); + if (ime_info.fdwProperty & IME_PROP_UNICODE) + { + todo_wine + ok_eq( 0xcdcdcdcd, styleA.dwStyle, UINT, "%#x" ); + todo_wine + ok_eq( 0xcd, styleA.szDescription[0], BYTE, "%#x" ); + } + else + { + ok_eq( 0xdeadbeef, styleA.dwStyle, UINT, "%#x" ); + ok_str( "StyleDescription", styleA.szDescription ); + } + CHECK_CALLED( ImeGetRegisterWordStyle ); + + ime_cleanup( hkl ); + +cleanup: + SET_ENABLE( ImeGetRegisterWordStyle, FALSE ); + + winetest_pop_context(); +} + START_TEST(imm32) { if (!is_ime_enabled()) @@ -3485,6 +3580,8 @@ START_TEST(imm32) test_ImmEnumRegisterWord( TRUE ); test_ImmRegisterWord( FALSE ); test_ImmRegisterWord( TRUE ); + test_ImmGetRegisterWordStyle( FALSE ); + test_ImmGetRegisterWordStyle( TRUE ); if (init()) { From 1d205abc94f114770c5a66feb8b6f88d509fc64e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 19 Feb 2023 11:59:37 +0100 Subject: [PATCH 1738/2777] imm32/tests: Test ImmUnregisterWord with the installed IME. (cherry picked from commit 195879ada8531b5124b26ef0eda65279a8c3942a) --- dlls/imm32/tests/imm32.c | 81 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index faeb9f19a2b..7f76c59a409 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2467,6 +2467,7 @@ DEFINE_EXPECT( ImeEscape ); DEFINE_EXPECT( ImeEnumRegisterWord ); DEFINE_EXPECT( ImeRegisterWord ); DEFINE_EXPECT( ImeGetRegisterWordStyle ); +DEFINE_EXPECT( ImeUnregisterWord ); static BOOL todo_IME_DLL_PROCESS_ATTACH; DEFINE_EXPECT( IME_DLL_PROCESS_ATTACH ); static BOOL todo_IME_DLL_PROCESS_DETACH; @@ -2706,7 +2707,21 @@ static UINT WINAPI ime_ImeToAsciiEx( UINT vkey, UINT scan_code, BYTE *key_state, static BOOL WINAPI ime_ImeUnregisterWord( const WCHAR *reading, DWORD style, const WCHAR *string ) { ime_trace( "reading %s, style %lu, string %s\n", debugstr_w(reading), style, debugstr_w(string) ); - ok( 0, "unexpected call\n" ); + + CHECK_EXPECT( ImeUnregisterWord ); + + if (style) ok_eq( 0xdeadbeef, style, UINT, "%#x" ); + if (ime_info.fdwProperty & IME_PROP_UNICODE) + { + if (reading) ok_wcs( L"Reading", reading ); + if (string) ok_wcs( L"String", string ); + } + else + { + if (reading) ok_str( "Reading", (char *)reading ); + if (string) ok_str( "String", (char *)string ); + } + return FALSE; } @@ -3558,6 +3573,68 @@ static void test_ImmGetRegisterWordStyle( BOOL unicode ) winetest_pop_context(); } +static void test_ImmUnregisterWord( BOOL unicode ) +{ + HKL hkl = GetKeyboardLayout( 0 ); + + winetest_push_context( unicode ? "unicode" : "ansi" ); + + SET_ENABLE( ImeUnregisterWord, TRUE ); + + SetLastError( 0xdeadbeef ); + ok_ret( 0, ImmUnregisterWordW( NULL, NULL, 0, NULL ) ); + ok_ret( 0, ImmUnregisterWordA( NULL, NULL, 0, NULL ) ); + ok_ret( 0, ImmUnregisterWordW( hkl, NULL, 0, NULL ) ); + ok_ret( 0, ImmUnregisterWordA( hkl, NULL, 0, NULL ) ); + todo_wine + ok_ret( 0xdeadbeef, GetLastError() ); + + /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ + ime_info.fdwProperty = IME_PROP_END_UNLOAD; + if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE; + + if (!(hkl = ime_install())) goto cleanup; + + SET_EXPECT( ImeUnregisterWord ); + ok_ret( 0, ImmUnregisterWordW( hkl, NULL, 0, NULL ) ); + CHECK_CALLED( ImeUnregisterWord ); + + SET_EXPECT( ImeUnregisterWord ); + ok_ret( 0, ImmUnregisterWordA( hkl, NULL, 0, NULL ) ); + CHECK_CALLED( ImeUnregisterWord ); + + SET_EXPECT( ImeUnregisterWord ); + ok_ret( 0, ImmUnregisterWordW( hkl, L"Reading", 0, NULL ) ); + CHECK_CALLED( ImeUnregisterWord ); + + SET_EXPECT( ImeUnregisterWord ); + ok_ret( 0, ImmUnregisterWordA( hkl, "Reading", 0, NULL ) ); + CHECK_CALLED( ImeUnregisterWord ); + + SET_EXPECT( ImeUnregisterWord ); + ok_ret( 0, ImmUnregisterWordW( hkl, NULL, 0xdeadbeef, NULL ) ); + CHECK_CALLED( ImeUnregisterWord ); + + SET_EXPECT( ImeUnregisterWord ); + ok_ret( 0, ImmUnregisterWordA( hkl, NULL, 0xdeadbeef, NULL ) ); + CHECK_CALLED( ImeUnregisterWord ); + + SET_EXPECT( ImeUnregisterWord ); + ok_ret( 0, ImmUnregisterWordW( hkl, NULL, 0, L"String" ) ); + CHECK_CALLED( ImeUnregisterWord ); + + SET_EXPECT( ImeUnregisterWord ); + ok_ret( 0, ImmUnregisterWordA( hkl, NULL, 0, "String" ) ); + CHECK_CALLED( ImeUnregisterWord ); + + ime_cleanup( hkl ); + +cleanup: + SET_ENABLE( ImeUnregisterWord, FALSE ); + + winetest_pop_context(); +} + START_TEST(imm32) { if (!is_ime_enabled()) @@ -3582,6 +3659,8 @@ START_TEST(imm32) test_ImmRegisterWord( TRUE ); test_ImmGetRegisterWordStyle( FALSE ); test_ImmGetRegisterWordStyle( TRUE ); + test_ImmUnregisterWord( FALSE ); + test_ImmUnregisterWord( TRUE ); if (init()) { From aeeb6e14a67d2d2145ffb623212cfa5e98f90305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 9 Mar 2023 17:12:55 +0100 Subject: [PATCH 1739/2777] imm32/tests: Test basic ImmEnumInputContext usage. (cherry picked from commit 196295db88237b084f1825e0c9b0e4d3cf6afedd) --- dlls/imm32/tests/imm32.c | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 7f76c59a409..015d6391520 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -55,6 +55,12 @@ static const char *debugstr_ok( const char *cond ) t v = (r); \ ok( v == (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \ } while (0) +#define ok_ne( e, r, t, f, ... ) \ + do \ + { \ + t v = (r); \ + ok( v != (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \ + } while (0) #define ok_wcs( e, r ) \ do \ { \ @@ -2779,6 +2785,7 @@ static struct ime_functions ime_functions = static UINT ime_count; static WCHAR ime_path[MAX_PATH]; +static HIMC default_himc; static HKL ime_install(void) { @@ -2897,6 +2904,39 @@ static void ime_cleanup( HKL hkl ) ok( ret, "DeleteFileW failed, error %lu\n", GetLastError() ); } +static BOOL CALLBACK enum_get_context( HIMC himc, LPARAM lparam ) +{ + ime_trace( "himc %p\n", himc ); + *(HIMC *)lparam = himc; + return TRUE; +} + +static BOOL CALLBACK enum_find_context( HIMC himc, LPARAM lparam ) +{ + ime_trace( "himc %p\n", himc ); + if (lparam && lparam == (LPARAM)himc) return FALSE; + return TRUE; +} + +static void test_ImmEnumInputContext(void) +{ + HIMC himc; + + todo_wine + ok_ret( 1, ImmEnumInputContext( 0, enum_get_context, (LPARAM)&default_himc ) ); + ok_ret( 0, ImmEnumInputContext( 1, enum_find_context, 0 ) ); + todo_wine + ok_ret( 1, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context, 0 ) ); + ok_ret( 0, ImmEnumInputContext( GetCurrentProcessId(), enum_find_context, 0 ) ); + + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ok_ret( 0, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context, (LPARAM)himc ) ); + ok_ret( 1, ImmDestroyContext( himc ) ); + todo_wine + ok_ret( 1, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context, (LPARAM)himc ) ); +} + static void test_ImmInstallIME(void) { UINT ret; @@ -3645,6 +3685,8 @@ START_TEST(imm32) test_com_initialization(); + test_ImmEnumInputContext(); + test_ImmInstallIME(); test_ImmGetDescription(); test_ImmGetIMEFileName(); From bbfa02ebc84d613602ce33faf29e7efd2b54ed86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 11 Mar 2023 08:53:29 +0100 Subject: [PATCH 1740/2777] win32u/tests: Test NtUserCreateInputContext (et al.) (cherry picked from commit a865ce8298721547af62ac53c6cecc179da65dc5) --- dlls/win32u/tests/win32u.c | 98 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/dlls/win32u/tests/win32u.c b/dlls/win32u/tests/win32u.c index 60ef2d38b5f..51a67a697f5 100644 --- a/dlls/win32u/tests/win32u.c +++ b/dlls/win32u/tests/win32u.c @@ -221,6 +221,103 @@ static void test_class(void) } +static void test_NtUserCreateInputContext(void) +{ + UINT_PTR value, attr3; + HIMC himc; + UINT ret; + + SetLastError( 0xdeadbeef ); + himc = NtUserCreateInputContext( 0 ); + todo_wine + ok( !himc, "NtUserCreateInputContext succeeded\n" ); + todo_wine + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = NtUserDestroyInputContext( himc ); + todo_wine + ok( !ret, "NtUserDestroyInputContext succeeded\n" ); + todo_wine + ok( GetLastError() == ERROR_INVALID_HANDLE, "got error %lu\n", GetLastError() ); + + + himc = NtUserCreateInputContext( 0xdeadbeef ); + ok( !!himc, "NtUserCreateInputContext failed, error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + value = NtUserQueryInputContext( himc, 0 ); + todo_wine + ok( value == GetCurrentProcessId(), "NtUserQueryInputContext 0 returned %#Ix\n", value ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + value = NtUserQueryInputContext( himc, 1 ); + ok( value == GetCurrentThreadId(), "NtUserQueryInputContext 1 returned %#Ix\n", value ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + value = NtUserQueryInputContext( himc, 2 ); + ok( value == 0, "NtUserQueryInputContext 2 returned %#Ix\n", value ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + value = NtUserQueryInputContext( himc, 3 ); + todo_wine + ok( !!value, "NtUserQueryInputContext 3 returned %#Ix\n", value ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + attr3 = value; + SetLastError( 0xdeadbeef ); + value = NtUserQueryInputContext( himc, 4 ); + todo_wine + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = NtUserUpdateInputContext( himc, 0, 0 ); + todo_wine + ok( !ret, "NtUserUpdateInputContext 0 succeeded\n" ); + todo_wine + ok( GetLastError() == ERROR_ALREADY_INITIALIZED, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = NtUserUpdateInputContext( himc, 1, 0xdeadbeef ); + todo_wine + ok( !!ret, "NtUserUpdateInputContext 1 failed\n" ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = NtUserUpdateInputContext( himc, 2, 0xdeadbeef ); + ok( !ret, "NtUserUpdateInputContext 2 succeeded\n" ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = NtUserUpdateInputContext( himc, 3, 0x0badf00d ); + ok( !ret, "NtUserUpdateInputContext 3 succeeded\n" ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + ret = NtUserUpdateInputContext( himc, 4, 0xdeadbeef ); + ok( !ret, "NtUserUpdateInputContext 4 succeeded\n" ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + value = NtUserQueryInputContext( himc, 0 ); + todo_wine + ok( value == GetCurrentProcessId(), "NtUserQueryInputContext 0 returned %#Ix\n", value ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + value = NtUserQueryInputContext( himc, 1 ); + ok( value == GetCurrentThreadId(), "NtUserQueryInputContext 1 returned %#Ix\n", value ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + value = NtUserQueryInputContext( himc, 2 ); + ok( value == 0, "NtUserQueryInputContext 2 returned %#Ix\n", value ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + value = NtUserQueryInputContext( himc, 3 ); + ok( value == attr3, "NtUserQueryInputContext 3 returned %#Ix\n", value ); + ok( GetLastError() == 0xdeadbeef, "got error %lu\n", GetLastError() ); + SetLastError( 0xdeadbeef ); + value = NtUserQueryInputContext( himc, 4 ); + todo_wine + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError() ); + + ret = NtUserDestroyInputContext( himc ); + ok( !!ret, "NtUserDestroyInputContext failed, error %lu\n", GetLastError() ); +} + static BOOL WINAPI count_win( HWND hwnd, LPARAM lparam ) { ULONG *cnt = (ULONG *)lparam; @@ -1148,6 +1245,7 @@ START_TEST(win32u) test_NtUserEnumDisplayDevices(); test_window_props(); test_class(); + test_NtUserCreateInputContext(); test_NtUserBuildHwndList(); test_cursoricon(); test_message_call(); From fac285db3d094fafeb8d0255a83c79e26efd985c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 11 Mar 2023 07:54:45 +0100 Subject: [PATCH 1741/2777] win32u: Stub NtUserBuildHimcList syscall. (cherry picked from commit 7ecb1446568ac6f1511f16956a2576dc0a73fce3) --- dlls/win32u/imm.c | 11 +++++++++++ dlls/win32u/syscall.c | 1 + dlls/win32u/win32u.spec | 2 +- dlls/wow64win/syscall.h | 1 + dlls/wow64win/user.c | 19 +++++++++++++++++++ include/ntuser.h | 1 + 6 files changed, 34 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index 1ccc09c97b2..dc10eedd903 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -25,6 +25,8 @@ #endif #include +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "win32u_private.h" #include "ntuser_private.h" #include "immdev.h" @@ -393,6 +395,15 @@ void cleanup_imm_thread(void) NtUserDestroyInputContext( UlongToHandle( thread_info->client_info.default_imc )); } +/***************************************************************************** + * NtUserBuildHimcList (win32u.@) + */ +NTSTATUS WINAPI NtUserBuildHimcList( UINT thread_id, UINT count, HIMC *buffer, UINT *size ) +{ + FIXME( "thread_id %#x, count %u, buffer %p, size %p stub!\n", thread_id, count, buffer, size ); + return STATUS_NOT_IMPLEMENTED; +} + BOOL WINAPI DECLSPEC_HIDDEN ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM key_data, DWORD unknown ) { struct imm_process_key_params params = diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index e802b3d2ec0..2e39a4f62cc 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -106,6 +106,7 @@ static void * const syscalls[] = NtUserAssociateInputContext, NtUserAttachThreadInput, NtUserBeginPaint, + NtUserBuildHimcList, NtUserBuildHwndList, NtUserCallHwnd, NtUserCallHwndParam, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index d450d07635e..764eb38d862 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -762,7 +762,7 @@ @ stub NtUserBitBltSysBmp @ stub NtUserBlockInput @ stub NtUserBroadcastThemeChangeEvent -@ stub NtUserBuildHimcList +@ stdcall -syscall NtUserBuildHimcList(long long ptr ptr) @ stdcall -syscall NtUserBuildHwndList(long long long long long long ptr ptr) @ stub NtUserBuildNameList @ stub NtUserBuildPropList diff --git a/dlls/wow64win/syscall.h b/dlls/wow64win/syscall.h index 8543c877644..c9dc459709e 100644 --- a/dlls/wow64win/syscall.h +++ b/dlls/wow64win/syscall.h @@ -92,6 +92,7 @@ SYSCALL_ENTRY( NtUserAssociateInputContext ) \ SYSCALL_ENTRY( NtUserAttachThreadInput ) \ SYSCALL_ENTRY( NtUserBeginPaint ) \ + SYSCALL_ENTRY( NtUserBuildHimcList ) \ SYSCALL_ENTRY( NtUserBuildHwndList ) \ SYSCALL_ENTRY( NtUserCallHwnd ) \ SYSCALL_ENTRY( NtUserCallHwndParam ) \ diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index c8ce23a05ce..458f5cd0788 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -1182,6 +1182,25 @@ NTSTATUS WINAPI wow64_NtUserBeginPaint( UINT *args ) return HandleToUlong( ret ); } +NTSTATUS WINAPI wow64_NtUserBuildHimcList( UINT *args ) +{ + ULONG thread_id = get_ulong( &args ); + ULONG count = get_ulong( &args ); + UINT32 *buffer32 = get_ptr( &args ); + UINT *size = get_ptr( &args ); + + HIMC *buffer; + ULONG i; + NTSTATUS status; + + if (!(buffer = Wow64AllocateTemp( count * sizeof(*buffer) ))) return STATUS_NO_MEMORY; + + if ((status = NtUserBuildHimcList( thread_id, count, buffer, size ))) return status; + + for (i = 0; i < *size; i++) buffer32[i] = HandleToUlong( buffer[i] ); + return status; +} + NTSTATUS WINAPI wow64_NtUserBuildHwndList( UINT *args ) { HDESK desktop = get_handle( &args ); diff --git a/include/ntuser.h b/include/ntuser.h index 5295c2c2108..0771814c999 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -648,6 +648,7 @@ BOOL WINAPI NtUserAddClipboardFormatListener( HWND hwnd ); UINT WINAPI NtUserAssociateInputContext( HWND hwnd, HIMC ctx, ULONG flags ); BOOL WINAPI NtUserAttachThreadInput( DWORD from, DWORD to, BOOL attach ); HDC WINAPI NtUserBeginPaint( HWND hwnd, PAINTSTRUCT *ps ); +NTSTATUS WINAPI NtUserBuildHimcList( UINT thread_id, UINT count, HIMC *buffer, UINT *size ); NTSTATUS WINAPI NtUserBuildHwndList( HDESK desktop, ULONG unk2, ULONG unk3, ULONG unk4, ULONG thread_id, ULONG count, HWND *buffer, ULONG *size ); ULONG_PTR WINAPI NtUserCallHwnd( HWND hwnd, DWORD code ); From dda32c1bad91bbf36312b27e364d7f01cc352483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 11 Mar 2023 08:58:33 +0100 Subject: [PATCH 1742/2777] win32u/tests: Test NtUserBuildHimcList syscall. (cherry picked from commit 8dab5e32ab989b3b789f8f9acae2b74c5f0e234e) --- dlls/win32u/tests/win32u.c | 134 +++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/dlls/win32u/tests/win32u.c b/dlls/win32u/tests/win32u.c index 51a67a697f5..975716045cf 100644 --- a/dlls/win32u/tests/win32u.c +++ b/dlls/win32u/tests/win32u.c @@ -318,6 +318,139 @@ static void test_NtUserCreateInputContext(void) ok( !!ret, "NtUserDestroyInputContext failed, error %lu\n", GetLastError() ); } +static int himc_compare( const void *a, const void *b ) +{ + return (UINT_PTR)*(HIMC *)a - (UINT_PTR)*(HIMC *)b; +} + +static DWORD CALLBACK test_NtUserBuildHimcList_thread( void *arg ) +{ + HIMC buf[8], *himc = arg; + NTSTATUS status; + UINT size; + + size = 0xdeadbeef; + memset( buf, 0xcd, sizeof(buf) ); + status = NtUserBuildHimcList( GetCurrentThreadId(), ARRAYSIZE( buf ), buf, &size ); + todo_wine + ok( !status, "NtUserBuildHimcList failed: %#lx\n", status ); + todo_wine + ok( size == 1, "size = %u\n", size ); + ok( !!buf[0], "buf[0] = %p\n", buf[0] ); + + todo_wine + ok( buf[0] != himc[0], "buf[0] = %p\n", buf[0] ); + ok( buf[0] != himc[1], "buf[0] = %p\n", buf[0] ); + himc[2] = buf[0]; + qsort( himc, 3, sizeof(*himc), himc_compare ); + + size = 0xdeadbeef; + memset( buf, 0xcd, sizeof(buf) ); + status = NtUserBuildHimcList( -1, ARRAYSIZE( buf ), buf, &size ); + todo_wine + ok( !status, "NtUserBuildHimcList failed: %#lx\n", status ); + todo_wine + ok( size == 3, "size = %u\n", size ); + + qsort( buf, size, sizeof(*buf), himc_compare ); + ok( buf[0] == himc[0], "buf[0] = %p\n", buf[0] ); + ok( buf[1] == himc[1], "buf[1] = %p\n", buf[1] ); + todo_wine + ok( buf[2] == himc[2], "buf[2] = %p\n", buf[2] ); + + return 0; +} + +static void test_NtUserBuildHimcList(void) +{ + HIMC buf[8], himc[3], new_himc; + NTSTATUS status; + UINT size, ret; + HANDLE thread; + + size = 0xdeadbeef; + memset( buf, 0xcd, sizeof(buf) ); + status = NtUserBuildHimcList( GetCurrentThreadId(), ARRAYSIZE( buf ), buf, &size ); + todo_wine + ok( !status, "NtUserBuildHimcList failed: %#lx\n", status ); + todo_wine + ok( size == 1, "size = %u\n", size ); + ok( !!buf[0], "buf[0] = %p\n", buf[0] ); + himc[0] = buf[0]; + + + new_himc = NtUserCreateInputContext( 0xdeadbeef ); + ok( !!new_himc, "NtUserCreateInputContext failed, error %lu\n", GetLastError() ); + + himc[1] = new_himc; + qsort( himc, 2, sizeof(*himc), himc_compare ); + + size = 0xdeadbeef; + memset( buf, 0xcd, sizeof(buf) ); + status = NtUserBuildHimcList( GetCurrentThreadId(), ARRAYSIZE( buf ), buf, &size ); + todo_wine + ok( !status, "NtUserBuildHimcList failed: %#lx\n", status ); + todo_wine + ok( size == 2, "size = %u\n", size ); + + qsort( buf, size, sizeof(*buf), himc_compare ); + ok( buf[0] == himc[0], "buf[0] = %p\n", buf[0] ); + todo_wine + ok( buf[1] == himc[1], "buf[1] = %p\n", buf[1] ); + + size = 0xdeadbeef; + memset( buf, 0xcd, sizeof(buf) ); + status = NtUserBuildHimcList( 0, ARRAYSIZE( buf ), buf, &size ); + todo_wine + ok( !status, "NtUserBuildHimcList failed: %#lx\n", status ); + todo_wine + ok( size == 2, "size = %u\n", size ); + + qsort( buf, size, sizeof(*buf), himc_compare ); + ok( buf[0] == himc[0], "buf[0] = %p\n", buf[0] ); + todo_wine + ok( buf[1] == himc[1], "buf[1] = %p\n", buf[1] ); + + size = 0xdeadbeef; + memset( buf, 0xcd, sizeof(buf) ); + status = NtUserBuildHimcList( -1, ARRAYSIZE( buf ), buf, &size ); + todo_wine + ok( !status, "NtUserBuildHimcList failed: %#lx\n", status ); + todo_wine + ok( size == 2, "size = %u\n", size ); + + qsort( buf, size, sizeof(*buf), himc_compare ); + ok( buf[0] == himc[0], "buf[0] = %p\n", buf[0] ); + todo_wine + ok( buf[1] == himc[1], "buf[1] = %p\n", buf[1] ); + + thread = CreateThread( NULL, 0, test_NtUserBuildHimcList_thread, himc, 0, NULL ); + ok( !!thread, "CreateThread failed, error %lu\n", GetLastError() ); + ret = WaitForSingleObject( thread, 5000 ); + ok( !ret, "WaitForSingleObject returned %#x\n", ret ); + + size = 0xdeadbeef; + status = NtUserBuildHimcList( 1, ARRAYSIZE( buf ), buf, &size ); + todo_wine + ok( status == STATUS_INVALID_PARAMETER, "NtUserBuildHimcList returned %#lx\n", status ); + size = 0xdeadbeef; + status = NtUserBuildHimcList( GetCurrentProcessId(), ARRAYSIZE( buf ), buf, &size ); + todo_wine + ok( status == STATUS_INVALID_PARAMETER, "NtUserBuildHimcList returned %#lx\n", status ); + size = 0xdeadbeef; + status = NtUserBuildHimcList( GetCurrentThreadId(), 1, NULL, &size ); + todo_wine + ok( status == STATUS_UNSUCCESSFUL, "NtUserBuildHimcList returned %#lx\n", status ); + size = 0xdeadbeef; + status = NtUserBuildHimcList( GetCurrentThreadId(), 0, buf, &size ); + todo_wine + ok( !status, "NtUserBuildHimcList failed: %#lx\n", status ); + ok( size == 0, "size = %u\n", size ); + + ret = NtUserDestroyInputContext( new_himc ); + ok( !!ret, "NtUserDestroyInputContext failed, error %lu\n", GetLastError() ); +} + static BOOL WINAPI count_win( HWND hwnd, LPARAM lparam ) { ULONG *cnt = (ULONG *)lparam; @@ -1246,6 +1379,7 @@ START_TEST(win32u) test_window_props(); test_class(); test_NtUserCreateInputContext(); + test_NtUserBuildHimcList(); test_NtUserBuildHwndList(); test_cursoricon(); test_message_call(); From c462141c367aa0d6e92f55bb0a459bd93d8f4fb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 11 Mar 2023 09:24:35 +0100 Subject: [PATCH 1743/2777] win32u: Introduce new next_process_user_handle_ptr helper. And use it instead of next_thread_window_ptr. (cherry picked from commit 7297a8e69c5446694b2c0cc05918b4da15f01426) --- dlls/win32u/ntuser_private.h | 6 +---- dlls/win32u/window.c | 48 ++++++++++++++++++------------------ 2 files changed, 25 insertions(+), 29 deletions(-) diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 8ab1b35291e..41a53837642 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -52,11 +52,6 @@ struct user_object #define OBJ_OTHER_PROCESS ((void *)1) /* returned by get_user_handle_ptr on unknown handles */ -HANDLE alloc_user_handle( struct user_object *ptr, unsigned int type ) DECLSPEC_HIDDEN; -void *get_user_handle_ptr( HANDLE handle, unsigned int type ) DECLSPEC_HIDDEN; -void release_user_handle_ptr( void *ptr ) DECLSPEC_HIDDEN; -void *free_user_handle( HANDLE handle, unsigned int type ) DECLSPEC_HIDDEN; - typedef struct tagWND { struct user_object obj; /* object header */ @@ -253,6 +248,7 @@ HANDLE alloc_user_handle( struct user_object *ptr, unsigned int type ) DECLSPEC_ void *free_user_handle( HANDLE handle, unsigned int type ) DECLSPEC_HIDDEN; void *get_user_handle_ptr( HANDLE handle, unsigned int type ) DECLSPEC_HIDDEN; void release_user_handle_ptr( void *ptr ) DECLSPEC_HIDDEN; +void *next_process_user_handle_ptr( HANDLE *handle, unsigned int type ) DECLSPEC_HIDDEN; UINT win_set_flags( HWND hwnd, UINT set_mask, UINT clear_mask ) DECLSPEC_HIDDEN; /* winstation.c */ diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index a07be55e883..333fde4b472 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -101,6 +101,26 @@ void *get_user_handle_ptr( HANDLE handle, unsigned int type ) return ptr; } +/*********************************************************************** + * next_process_user_handle_ptr + * + * user_lock must be held by caller. + */ +void *next_process_user_handle_ptr( HANDLE *handle, unsigned int type ) +{ + struct user_object *ptr; + WORD index = *handle ? USER_HANDLE_TO_INDEX( *handle ) + 1 : 0; + + while (index < NB_USER_HANDLES) + { + if (!(ptr = user_handles[index++])) continue; /* OBJ_OTHER_PROCESS */ + if (ptr->type != type) continue; + *handle = ptr->handle; + return ptr; + } + return NULL; +} + /*********************************************************************** * set_user_handle_ptr */ @@ -142,27 +162,6 @@ void *free_user_handle( HANDLE handle, unsigned int type ) return ptr; } -/*********************************************************************** - * next_thread_window - */ -static WND *next_thread_window_ptr( HWND *hwnd ) -{ - struct user_object *ptr; - WND *win; - WORD index = *hwnd ? USER_HANDLE_TO_INDEX( *hwnd ) + 1 : 0; - - while (index < NB_USER_HANDLES) - { - if (!(ptr = user_handles[index++])) continue; - if (ptr->type != NTUSER_OBJ_WINDOW) continue; - win = (WND *)ptr; - if (win->tid != GetCurrentThreadId()) continue; - *hwnd = ptr->handle; - return win; - } - return NULL; -} - /******************************************************************* * get_hwnd_message_parent * @@ -4865,13 +4864,14 @@ BOOL WINAPI NtUserDestroyWindow( HWND hwnd ) void destroy_thread_windows(void) { WND *win, *free_list = NULL; - HWND hwnd = 0; + HANDLE handle = 0; user_lock(); - while ((win = next_thread_window_ptr( &hwnd ))) + while ((win = next_process_user_handle_ptr( &handle, NTUSER_OBJ_WINDOW ))) { + if (win->tid != GetCurrentThreadId()) continue; free_dce( win->dce, win->obj.handle ); - set_user_handle_ptr( hwnd, NULL ); + set_user_handle_ptr( handle, NULL ); win->obj.handle = free_list; free_list = win; } From c6a05aeb218cf64c77f775eedf543e5d7038d5ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 17 Mar 2023 14:54:25 +0100 Subject: [PATCH 1744/2777] win32u: Implement NtUserBuildHimcList syscall. (cherry picked from commit ac95a5d48395ffab79f2a7189b0d5ba21f473658) --- dlls/win32u/imm.c | 21 +++++++++++++++++++-- dlls/win32u/tests/win32u.c | 19 +++---------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index dc10eedd903..7dee4912e27 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -400,8 +400,25 @@ void cleanup_imm_thread(void) */ NTSTATUS WINAPI NtUserBuildHimcList( UINT thread_id, UINT count, HIMC *buffer, UINT *size ) { - FIXME( "thread_id %#x, count %u, buffer %p, size %p stub!\n", thread_id, count, buffer, size ); - return STATUS_NOT_IMPLEMENTED; + HANDLE handle = 0; + struct imc *imc; + + TRACE( "thread_id %#x, count %u, buffer %p, size %p\n", thread_id, count, buffer, size ); + + if (!buffer) return STATUS_UNSUCCESSFUL; + if (!thread_id) thread_id = GetCurrentThreadId(); + + *size = 0; + user_lock(); + while (count && (imc = next_process_user_handle_ptr( &handle, NTUSER_OBJ_IMC ))) + { + if (thread_id != -1 && imc->thread_id != thread_id) continue; + buffer[(*size)++] = handle; + count--; + } + user_unlock(); + + return STATUS_SUCCESS; } BOOL WINAPI DECLSPEC_HIDDEN ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM key_data, DWORD unknown ) diff --git a/dlls/win32u/tests/win32u.c b/dlls/win32u/tests/win32u.c index 975716045cf..04e5a2e7932 100644 --- a/dlls/win32u/tests/win32u.c +++ b/dlls/win32u/tests/win32u.c @@ -332,13 +332,11 @@ static DWORD CALLBACK test_NtUserBuildHimcList_thread( void *arg ) size = 0xdeadbeef; memset( buf, 0xcd, sizeof(buf) ); status = NtUserBuildHimcList( GetCurrentThreadId(), ARRAYSIZE( buf ), buf, &size ); - todo_wine ok( !status, "NtUserBuildHimcList failed: %#lx\n", status ); todo_wine ok( size == 1, "size = %u\n", size ); ok( !!buf[0], "buf[0] = %p\n", buf[0] ); - todo_wine ok( buf[0] != himc[0], "buf[0] = %p\n", buf[0] ); ok( buf[0] != himc[1], "buf[0] = %p\n", buf[0] ); himc[2] = buf[0]; @@ -347,13 +345,15 @@ static DWORD CALLBACK test_NtUserBuildHimcList_thread( void *arg ) size = 0xdeadbeef; memset( buf, 0xcd, sizeof(buf) ); status = NtUserBuildHimcList( -1, ARRAYSIZE( buf ), buf, &size ); - todo_wine ok( !status, "NtUserBuildHimcList failed: %#lx\n", status ); todo_wine ok( size == 3, "size = %u\n", size ); qsort( buf, size, sizeof(*buf), himc_compare ); + /* FIXME: Wine only lazily creates a default thread IMC */ + todo_wine ok( buf[0] == himc[0], "buf[0] = %p\n", buf[0] ); + todo_wine ok( buf[1] == himc[1], "buf[1] = %p\n", buf[1] ); todo_wine ok( buf[2] == himc[2], "buf[2] = %p\n", buf[2] ); @@ -371,9 +371,7 @@ static void test_NtUserBuildHimcList(void) size = 0xdeadbeef; memset( buf, 0xcd, sizeof(buf) ); status = NtUserBuildHimcList( GetCurrentThreadId(), ARRAYSIZE( buf ), buf, &size ); - todo_wine ok( !status, "NtUserBuildHimcList failed: %#lx\n", status ); - todo_wine ok( size == 1, "size = %u\n", size ); ok( !!buf[0], "buf[0] = %p\n", buf[0] ); himc[0] = buf[0]; @@ -388,40 +386,31 @@ static void test_NtUserBuildHimcList(void) size = 0xdeadbeef; memset( buf, 0xcd, sizeof(buf) ); status = NtUserBuildHimcList( GetCurrentThreadId(), ARRAYSIZE( buf ), buf, &size ); - todo_wine ok( !status, "NtUserBuildHimcList failed: %#lx\n", status ); - todo_wine ok( size == 2, "size = %u\n", size ); qsort( buf, size, sizeof(*buf), himc_compare ); ok( buf[0] == himc[0], "buf[0] = %p\n", buf[0] ); - todo_wine ok( buf[1] == himc[1], "buf[1] = %p\n", buf[1] ); size = 0xdeadbeef; memset( buf, 0xcd, sizeof(buf) ); status = NtUserBuildHimcList( 0, ARRAYSIZE( buf ), buf, &size ); - todo_wine ok( !status, "NtUserBuildHimcList failed: %#lx\n", status ); - todo_wine ok( size == 2, "size = %u\n", size ); qsort( buf, size, sizeof(*buf), himc_compare ); ok( buf[0] == himc[0], "buf[0] = %p\n", buf[0] ); - todo_wine ok( buf[1] == himc[1], "buf[1] = %p\n", buf[1] ); size = 0xdeadbeef; memset( buf, 0xcd, sizeof(buf) ); status = NtUserBuildHimcList( -1, ARRAYSIZE( buf ), buf, &size ); - todo_wine ok( !status, "NtUserBuildHimcList failed: %#lx\n", status ); - todo_wine ok( size == 2, "size = %u\n", size ); qsort( buf, size, sizeof(*buf), himc_compare ); ok( buf[0] == himc[0], "buf[0] = %p\n", buf[0] ); - todo_wine ok( buf[1] == himc[1], "buf[1] = %p\n", buf[1] ); thread = CreateThread( NULL, 0, test_NtUserBuildHimcList_thread, himc, 0, NULL ); @@ -439,11 +428,9 @@ static void test_NtUserBuildHimcList(void) ok( status == STATUS_INVALID_PARAMETER, "NtUserBuildHimcList returned %#lx\n", status ); size = 0xdeadbeef; status = NtUserBuildHimcList( GetCurrentThreadId(), 1, NULL, &size ); - todo_wine ok( status == STATUS_UNSUCCESSFUL, "NtUserBuildHimcList returned %#lx\n", status ); size = 0xdeadbeef; status = NtUserBuildHimcList( GetCurrentThreadId(), 0, buf, &size ); - todo_wine ok( !status, "NtUserBuildHimcList failed: %#lx\n", status ); ok( size == 0, "size = %u\n", size ); From 1a20365a20628afb03a4aebbbc4c06aed26b1fbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Mar 2023 09:03:16 +0100 Subject: [PATCH 1745/2777] imm32/tests: Remove GetLastError check on default IME ImmEscape tests. Wine-Bug: https://bugs.winehq.org//show_bug.cgi?id=54710 (cherry picked from commit 9ab5fb591fcfbe53bab16754adacc2adf0d27b24) --- dlls/imm32/tests/imm32.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 015d6391520..233fda84b61 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3313,11 +3313,8 @@ static void test_ImmEscape( BOOL unicode ) winetest_push_context( unicode ? "unicode" : "ansi" ); - SetLastError( 0xdeadbeef ); ok_ret( 0, ImmEscapeW( hkl, 0, 0, NULL ) ); ok_ret( 0, ImmEscapeA( hkl, 0, 0, NULL ) ); - todo_wine - ok_ret( 0xdeadbeef, GetLastError() ); /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ ime_info.fdwProperty = IME_PROP_END_UNLOAD; From d3e4064a4bd64d15b759c68deb8172b43f3893e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Mar 2023 09:05:26 +0100 Subject: [PATCH 1746/2777] imm32/tests: Update ImmGetProperty expectations for Korean locale. Wine-Bug: https://bugs.winehq.org//show_bug.cgi?id=54711 (cherry picked from commit 067b81fcfa82cd442b0c2542ff4e902fe19869a2) --- dlls/imm32/tests/imm32.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 233fda84b61..5c4d1d0725c 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3054,7 +3054,7 @@ static void test_ImmGetProperty(void) }; static const IMEINFO expect_ime_info_0411 = /* MS Japanese IME */ { - .fdwProperty = IME_PROP_COMPLETE_ON_UNSELECT | IME_PROP_CANDLIST_START_FROM_1 | IME_PROP_UNICODE | IME_PROP_AT_CARET | 0xa, + .fdwProperty = IME_PROP_CANDLIST_START_FROM_1 | IME_PROP_UNICODE | IME_PROP_AT_CARET | 0xa, .fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE | IME_CMODE_KATAKANA, .fdwSentenceCaps = IME_SMODE_PLAURALCLAUSE | IME_SMODE_CONVERSATION, .fdwSCSCaps = SCS_CAP_COMPSTR | SCS_CAP_SETRECONVERTSTRING | SCS_CAP_MAKEREAD, @@ -3093,7 +3093,8 @@ static void test_ImmGetProperty(void) else if (hkl == (HKL)0x08040804) expect = &expect_ime_info_0804; else expect = &expect_ime_info; - ok_ret( expect->fdwProperty, ImmGetProperty( hkl, IGP_PROPERTY ) ); + /* IME_PROP_COMPLETE_ON_UNSELECT seems to be somtimes set on CJK locales IMEs, sometimes not */ + ok_ret( expect->fdwProperty, ImmGetProperty( hkl, IGP_PROPERTY ) & ~IME_PROP_COMPLETE_ON_UNSELECT ); todo_wine ok_ret( expect->fdwConversionCaps, ImmGetProperty( hkl, IGP_CONVERSION ) ); todo_wine From 26faadf4a4ae73f4de7961d5f6c6a8baa88a9cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 11 Mar 2023 10:15:05 +0100 Subject: [PATCH 1747/2777] imm32: Implement ImmEnumInputContext. (cherry picked from commit a7c2f4e5bac800785b1584d9ab48b74336a35dd5) --- dlls/imm32/imm.c | 21 ++++++++++++++++++--- dlls/imm32/tests/imm32.c | 7 ++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 682fb748f2f..28344b909d6 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3033,10 +3033,25 @@ BOOL WINAPI ImmDisableTextFrameService(DWORD idThread) * ImmEnumInputContext(IMM32.@) */ -BOOL WINAPI ImmEnumInputContext(DWORD idThread, IMCENUMPROC lpfn, LPARAM lParam) +BOOL WINAPI ImmEnumInputContext( DWORD thread, IMCENUMPROC callback, LPARAM lparam ) { - FIXME("Stub\n"); - return FALSE; + HIMC buffer[256]; + NTSTATUS status; + UINT i, size; + + TRACE( "thread %lu, callback %p, lparam %#Ix\n", thread, callback, lparam ); + + if ((status = NtUserBuildHimcList( thread, ARRAY_SIZE(buffer), buffer, &size ))) + { + RtlSetLastWin32Error( RtlNtStatusToDosError( status ) ); + WARN( "NtUserBuildHimcList returned %#lx\n", status ); + return FALSE; + } + + if (size == ARRAY_SIZE(buffer)) FIXME( "NtUserBuildHimcList returned %u handles\n", size ); + for (i = 0; i < size; i++) if (!callback( buffer[i], lparam )) return FALSE; + + return TRUE; } /*********************************************************************** diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 5c4d1d0725c..73fbe9d1aa5 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2922,18 +2922,19 @@ static void test_ImmEnumInputContext(void) { HIMC himc; - todo_wine ok_ret( 1, ImmEnumInputContext( 0, enum_get_context, (LPARAM)&default_himc ) ); + ok_ret( 1, ImmEnumInputContext( -1, enum_find_context, 0 ) ); + ok_ret( 1, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context, 0 ) ); + + todo_wine ok_ret( 0, ImmEnumInputContext( 1, enum_find_context, 0 ) ); todo_wine - ok_ret( 1, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context, 0 ) ); ok_ret( 0, ImmEnumInputContext( GetCurrentProcessId(), enum_find_context, 0 ) ); himc = ImmCreateContext(); ok_ne( NULL, himc, HIMC, "%p" ); ok_ret( 0, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context, (LPARAM)himc ) ); ok_ret( 1, ImmDestroyContext( himc ) ); - todo_wine ok_ret( 1, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context, (LPARAM)himc ) ); } From 28e5a63436187d2d3143606394ffdd3229324aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 11 Mar 2023 12:13:28 +0100 Subject: [PATCH 1748/2777] imm32: Remove unnecessary threadDefault InputContextData member. (cherry picked from commit 29e51aa333ace47109fe46fc4b0f7e75e2293389) --- dlls/imm32/imm.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 28344b909d6..06d82671040 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -94,7 +94,6 @@ typedef struct tagInputContextData struct ime *ime; UINT lastVK; - BOOL threadDefault; } InputContextData; #define WINE_IMC_VALID_MAGIC 0x56434D49 @@ -404,16 +403,6 @@ static void imm_coinit_thread(void) InitOnceExecuteOnce(&init_ole32_once, init_ole32_funcs, NULL, NULL); } -static BOOL IMM_IsDefaultContext(HIMC imc) -{ - InputContextData *data = get_imc_data(imc); - - if (!data) - return FALSE; - - return data->threadDefault; -} - static InputContextData *query_imc_data(HIMC handle) { InputContextData *ret; @@ -868,7 +857,6 @@ static InputContextData *create_input_context(HIMC default_imc) new_context = calloc( 1, sizeof(InputContextData) ); /* Load the IME */ - new_context->threadDefault = !!default_imc; if (!(new_context->ime = ime_acquire( GetKeyboardLayout( 0 ) ))) { TRACE("IME dll could not be loaded\n"); @@ -953,7 +941,8 @@ static BOOL IMM_DestroyContext(HIMC hIMC) */ BOOL WINAPI ImmDestroyContext(HIMC hIMC) { - if (!IMM_IsDefaultContext(hIMC) && !IMM_IsCrossThreadAccess(NULL, hIMC)) + if ((UINT_PTR)hIMC == NtUserGetThreadInfo()->default_imc) return FALSE; + if (!IMM_IsCrossThreadAccess(NULL, hIMC)) return IMM_DestroyContext(hIMC); else return FALSE; From 25690c381360c3ac96830494d5d7000a5a85b016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 11 Mar 2023 12:08:49 +0100 Subject: [PATCH 1749/2777] imm32: Remove unused IMM_IsCrossThreadAccess hwnd parameter. (cherry picked from commit c66ea947a5ad7ccd106471488b6d3031e118df63) --- dlls/imm32/imm.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 06d82671040..26ec7c00140 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -682,15 +682,10 @@ static HIMCC ImmCreateBlankCompStr(void) return rc; } -static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC) +static BOOL IMM_IsCrossThreadAccess(HIMC hIMC) { InputContextData *data; - if (hWnd) - { - DWORD thread = GetWindowThreadProcessId(hWnd, NULL); - if (thread != GetCurrentThreadId()) return TRUE; - } data = get_imc_data(hIMC); if (data && data->threadID != GetCurrentThreadId()) return TRUE; @@ -942,7 +937,7 @@ static BOOL IMM_DestroyContext(HIMC hIMC) BOOL WINAPI ImmDestroyContext(HIMC hIMC) { if ((UINT_PTR)hIMC == NtUserGetThreadInfo()->default_imc) return FALSE; - if (!IMM_IsCrossThreadAccess(NULL, hIMC)) + if (!IMM_IsCrossThreadAccess(hIMC)) return IMM_DestroyContext(hIMC); else return FALSE; @@ -2244,7 +2239,7 @@ BOOL WINAPI ImmSetCandidateWindow( if (!data || !lpCandidate) return FALSE; - if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE; TRACE("\t%lx, %lx, %s, %s\n", @@ -2276,7 +2271,7 @@ BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) return FALSE; } - if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE; memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA)); @@ -2302,7 +2297,7 @@ BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) return FALSE; } - if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE; data->IMC.lfFont.W = *lplf; @@ -2333,7 +2328,7 @@ BOOL WINAPI ImmSetCompositionStringA( if (!data) return FALSE; - if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE; if (!(dwIndex == SCS_SETSTR || @@ -2390,7 +2385,7 @@ BOOL WINAPI ImmSetCompositionStringW( if (!data) return FALSE; - if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE; if (!(dwIndex == SCS_SETSTR || @@ -2451,7 +2446,7 @@ BOOL WINAPI ImmSetCompositionWindow( return FALSE; } - if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE; data->IMC.cfCompForm = *lpCompForm; @@ -2487,7 +2482,7 @@ BOOL WINAPI ImmSetConversionStatus( return FALSE; } - if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE; if ( fdwConversion != data->IMC.fdwConversion ) @@ -2523,7 +2518,7 @@ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) return FALSE; } - if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE; if (data->ime->ui_hwnd == NULL) @@ -2560,7 +2555,7 @@ BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) return FALSE; } - if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE; TRACE("\t%s\n", wine_dbgstr_point(lpptPos)); From 1531479380f678be9795cf25c7b7fc17073a8156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 11 Mar 2023 12:11:21 +0100 Subject: [PATCH 1750/2777] imm32: Use NtUserQueryInputContext to check cross-thread access. (cherry picked from commit 1d40658afa139b94f540e32587bd1123853e0d1f) --- dlls/imm32/imm.c | 46 +++++++++++----------------------------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 26ec7c00140..8c3f2b448ad 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -90,7 +90,6 @@ typedef struct tagInputContextData HIMC handle; DWORD dwLock; INPUTCONTEXT IMC; - DWORD threadID; struct ime *ime; UINT lastVK; @@ -682,17 +681,6 @@ static HIMCC ImmCreateBlankCompStr(void) return rc; } -static BOOL IMM_IsCrossThreadAccess(HIMC hIMC) -{ - InputContextData *data; - - data = get_imc_data(hIMC); - if (data && data->threadID != GetCurrentThreadId()) - return TRUE; - - return FALSE; -} - /*********************************************************************** * ImmSetActiveContext (IMM32.@) */ @@ -898,7 +886,6 @@ static InputContextData *create_input_context(HIMC default_imc) IMM_DestroyContext(new_context); return 0; } - new_context->threadID = GetCurrentThreadId(); SendMessageW( GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)new_context->ime ); TRACE("Created context %p\n", new_context); @@ -937,10 +924,8 @@ static BOOL IMM_DestroyContext(HIMC hIMC) BOOL WINAPI ImmDestroyContext(HIMC hIMC) { if ((UINT_PTR)hIMC == NtUserGetThreadInfo()->default_imc) return FALSE; - if (!IMM_IsCrossThreadAccess(hIMC)) - return IMM_DestroyContext(hIMC); - else - return FALSE; + if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + return IMM_DestroyContext(hIMC); } /*********************************************************************** @@ -2239,8 +2224,7 @@ BOOL WINAPI ImmSetCandidateWindow( if (!data || !lpCandidate) return FALSE; - if (IMM_IsCrossThreadAccess(hIMC)) - return FALSE; + if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; TRACE("\t%lx, %lx, %s, %s\n", lpCandidate->dwIndex, lpCandidate->dwStyle, @@ -2271,8 +2255,7 @@ BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) return FALSE; } - if (IMM_IsCrossThreadAccess(hIMC)) - return FALSE; + if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA)); MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName, @@ -2297,8 +2280,7 @@ BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) return FALSE; } - if (IMM_IsCrossThreadAccess(hIMC)) - return FALSE; + if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; data->IMC.lfFont.W = *lplf; ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT); @@ -2328,8 +2310,7 @@ BOOL WINAPI ImmSetCompositionStringA( if (!data) return FALSE; - if (IMM_IsCrossThreadAccess(hIMC)) - return FALSE; + if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; if (!(dwIndex == SCS_SETSTR || dwIndex == SCS_CHANGEATTR || @@ -2385,8 +2366,7 @@ BOOL WINAPI ImmSetCompositionStringW( if (!data) return FALSE; - if (IMM_IsCrossThreadAccess(hIMC)) - return FALSE; + if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; if (!(dwIndex == SCS_SETSTR || dwIndex == SCS_CHANGEATTR || @@ -2446,8 +2426,7 @@ BOOL WINAPI ImmSetCompositionWindow( return FALSE; } - if (IMM_IsCrossThreadAccess(hIMC)) - return FALSE; + if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; data->IMC.cfCompForm = *lpCompForm; @@ -2482,8 +2461,7 @@ BOOL WINAPI ImmSetConversionStatus( return FALSE; } - if (IMM_IsCrossThreadAccess(hIMC)) - return FALSE; + if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; if ( fdwConversion != data->IMC.fdwConversion ) { @@ -2518,8 +2496,7 @@ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) return FALSE; } - if (IMM_IsCrossThreadAccess(hIMC)) - return FALSE; + if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; if (data->ime->ui_hwnd == NULL) { @@ -2555,8 +2532,7 @@ BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) return FALSE; } - if (IMM_IsCrossThreadAccess(hIMC)) - return FALSE; + if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; TRACE("\t%s\n", wine_dbgstr_point(lpptPos)); From e6b2e65ba6f055b2f9b41dea8533408d1d413346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 9 Mar 2023 12:30:24 +0100 Subject: [PATCH 1751/2777] imm32: Rename InputContextData to struct imc. (cherry picked from commit 8f52d8a4e1f2c94e6613f77a6cd351db92b26ecd) --- dlls/imm32/imm.c | 114 +++++++++++++++++++++++------------------------ 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 8c3f2b448ad..c22c1fb9e64 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -85,7 +85,7 @@ struct ime static HRESULT (WINAPI *pCoRevokeInitializeSpy)(ULARGE_INTEGER cookie); static void (WINAPI *pCoUninitialize)(void); -typedef struct tagInputContextData +struct imc { HIMC handle; DWORD dwLock; @@ -93,7 +93,7 @@ typedef struct tagInputContextData struct ime *ime; UINT lastVK; -} InputContextData; +}; #define WINE_IMC_VALID_MAGIC 0x56434D49 @@ -129,7 +129,7 @@ static BOOL ime_is_unicode( const struct ime *ime ) } static BOOL IMM_DestroyContext(HIMC hIMC); -static InputContextData* get_imc_data(HIMC hIMC); +static struct imc *get_imc_data( HIMC hIMC ); static inline WCHAR *strdupAtoW( const char *str ) { @@ -402,9 +402,9 @@ static void imm_coinit_thread(void) InitOnceExecuteOnce(&init_ole32_once, init_ole32_funcs, NULL, NULL); } -static InputContextData *query_imc_data(HIMC handle) +static struct imc *query_imc_data( HIMC handle ) { - InputContextData *ret; + struct imc *ret; if (!handle) return NULL; ret = (void *)NtUserQueryInputContext(handle, NtUserInputContextClientPtr); @@ -566,7 +566,7 @@ static void ime_release( struct ime *ime ) static BOOL free_input_context_data( HIMC hIMC ) { - InputContextData *data = query_imc_data( hIMC ); + struct imc *data = query_imc_data( hIMC ); if (!data) return FALSE; @@ -637,7 +637,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved) } /* for posting messages as the IME */ -static void ImmInternalPostIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam) +static void ImmInternalPostIMEMessage( struct imc *data, UINT msg, WPARAM wParam, LPARAM lParam ) { HWND target = GetFocus(); if (!target) @@ -647,7 +647,7 @@ static void ImmInternalPostIMEMessage(InputContextData *data, UINT msg, WPARAM w } /* for sending messages as the IME */ -static void ImmInternalSendIMEMessage(InputContextData *data, UINT msg, WPARAM wParam, LPARAM lParam) +static void ImmInternalSendIMEMessage( struct imc *data, UINT msg, WPARAM wParam, LPARAM lParam ) { HWND target = GetFocus(); if (!target) @@ -656,7 +656,7 @@ static void ImmInternalSendIMEMessage(InputContextData *data, UINT msg, WPARAM w SendMessageW(target, msg, wParam, lParam); } -static LRESULT ImmInternalSendIMENotify(InputContextData *data, WPARAM notify, LPARAM lParam) +static LRESULT ImmInternalSendIMENotify( struct imc *data, WPARAM notify, LPARAM lParam ) { HWND target; @@ -686,7 +686,7 @@ static HIMCC ImmCreateBlankCompStr(void) */ BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate) { - InputContextData *data = get_imc_data(himc); + struct imc *data = get_imc_data( himc ); TRACE("(%p, %p, %x)\n", hwnd, himc, activate); @@ -830,14 +830,14 @@ BOOL WINAPI ImmConfigureIMEW( HKL hkl, HWND hwnd, DWORD mode, void *data ) return ret; } -static InputContextData *create_input_context(HIMC default_imc) +static struct imc *create_input_context( HIMC default_imc ) { - InputContextData *new_context; + struct imc *new_context; LPGUIDELINE gl; LPCANDIDATEINFO ci; int i; - new_context = calloc( 1, sizeof(InputContextData) ); + new_context = calloc( 1, sizeof(*new_context) ); /* Load the IME */ if (!(new_context->ime = ime_acquire( GetKeyboardLayout( 0 ) ))) @@ -892,9 +892,9 @@ static InputContextData *create_input_context(HIMC default_imc) return new_context; } -static InputContextData* get_imc_data(HIMC handle) +static struct imc *get_imc_data( HIMC handle ) { - InputContextData *ret; + struct imc *ret; if ((ret = query_imc_data(handle)) || !handle) return ret; return create_input_context(handle); @@ -905,7 +905,7 @@ static InputContextData* get_imc_data(HIMC handle) */ HIMC WINAPI ImmCreateContext(void) { - InputContextData *new_context; + struct imc *new_context; if (!(new_context = create_input_context(0))) return 0; return new_context->handle; @@ -1067,7 +1067,7 @@ DWORD WINAPI ImmGetCandidateListA( HIMC hIMC, DWORD dwIndex, LPCANDIDATELIST lpCandList, DWORD dwBufLen) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); LPCANDIDATEINFO candinfo; LPCANDIDATELIST candlist; DWORD ret = 0; @@ -1105,7 +1105,7 @@ DWORD WINAPI ImmGetCandidateListA( DWORD WINAPI ImmGetCandidateListCountA( HIMC hIMC, LPDWORD lpdwListCount) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); LPCANDIDATEINFO candinfo; DWORD ret, count; @@ -1137,7 +1137,7 @@ DWORD WINAPI ImmGetCandidateListCountA( DWORD WINAPI ImmGetCandidateListCountW( HIMC hIMC, LPDWORD lpdwListCount) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); LPCANDIDATEINFO candinfo; DWORD ret, count; @@ -1170,7 +1170,7 @@ DWORD WINAPI ImmGetCandidateListW( HIMC hIMC, DWORD dwIndex, LPCANDIDATELIST lpCandList, DWORD dwBufLen) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); LPCANDIDATEINFO candinfo; LPCANDIDATELIST candlist; DWORD ret = 0; @@ -1208,7 +1208,7 @@ DWORD WINAPI ImmGetCandidateListW( BOOL WINAPI ImmGetCandidateWindow( HIMC hIMC, DWORD dwIndex, LPCANDIDATEFORM lpCandidate) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); TRACE("%p, %ld, %p\n", hIMC, dwIndex, lpCandidate); @@ -1251,7 +1251,7 @@ BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) */ BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); TRACE("(%p, %p):\n", hIMC, lplf); @@ -1268,8 +1268,8 @@ BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) /* Source encoding is defined by context, source length is always given in respective characters. Destination buffer length is always in bytes. */ -static INT CopyCompStringIMEtoClient(const InputContextData *data, const void *src, INT src_len, void *dst, - INT dst_len, BOOL unicode) +static INT CopyCompStringIMEtoClient( const struct imc *data, const void *src, INT src_len, + void *dst, INT dst_len, BOOL unicode ) { int char_size = unicode ? sizeof(WCHAR) : sizeof(char); INT ret; @@ -1298,8 +1298,8 @@ static INT CopyCompStringIMEtoClient(const InputContextData *data, const void *s /* Composition string encoding is defined by context, returned attributes correspond to string, converted according to passed mode. String length is in characters, attributes are in byte arrays. */ -static INT CopyCompAttrIMEtoClient(const InputContextData *data, const BYTE *src, INT src_len, const void *comp_string, - INT str_len, BYTE *dst, INT dst_len, BOOL unicode) +static INT CopyCompAttrIMEtoClient( const struct imc *data, const BYTE *src, INT src_len, const void *comp_string, + INT str_len, BYTE *dst, INT dst_len, BOOL unicode ) { union { @@ -1369,8 +1369,8 @@ static INT CopyCompAttrIMEtoClient(const InputContextData *data, const BYTE *src return rc; } -static INT CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT slen, LPBYTE ssource, - LPBYTE target, INT tlen, BOOL unicode ) +static INT CopyCompClauseIMEtoClient( struct imc *data, LPBYTE source, INT slen, LPBYTE ssource, + LPBYTE target, INT tlen, BOOL unicode ) { INT rc; @@ -1424,7 +1424,7 @@ static INT CopyCompClauseIMEtoClient(InputContextData *data, LPBYTE source, INT return rc; } -static INT CopyCompOffsetIMEtoClient(InputContextData *data, DWORD offset, LPBYTE ssource, BOOL unicode) +static INT CopyCompOffsetIMEtoClient( struct imc *data, DWORD offset, LPBYTE ssource, BOOL unicode ) { int rc; @@ -1446,7 +1446,7 @@ static LONG ImmGetCompositionStringT( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen, BOOL unicode) { LONG rc = 0; - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); LPCOMPOSITIONSTRING compstr; LPBYTE compdata; @@ -1558,7 +1558,7 @@ LONG WINAPI ImmGetCompositionStringW( */ BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); TRACE("(%p, %p)\n", hIMC, lpCompForm); @@ -1583,7 +1583,7 @@ HIMC WINAPI ImmGetContext(HWND hWnd) if (rc) { - InputContextData *data = get_imc_data(rc); + struct imc *data = get_imc_data( rc ); if (data) data->IMC.hWnd = hWnd; else rc = 0; } @@ -1671,7 +1671,7 @@ DWORD WINAPI ImmGetConversionListW( HKL hkl, HIMC himc, const WCHAR *srcW, CANDI BOOL WINAPI ImmGetConversionStatus( HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); TRACE("%p %p %p\n", hIMC, lpfdwConversion, lpfdwSentence); @@ -1816,8 +1816,8 @@ UINT WINAPI ImmGetIMEFileNameW( HKL hkl, WCHAR *buffer, UINT length ) */ BOOL WINAPI ImmGetOpenStatus(HIMC hIMC) { - InputContextData *data = get_imc_data(hIMC); - static int i; + struct imc *data = get_imc_data( hIMC ); + static int i; if (!data) return FALSE; @@ -1915,7 +1915,7 @@ UINT WINAPI ImmGetRegisterWordStyleW( HKL hkl, UINT count, STYLEBUFW *styleW ) */ BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); TRACE("(%p, %p)\n", hIMC, lpptPos); @@ -1933,7 +1933,7 @@ BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) UINT WINAPI ImmGetVirtualKey(HWND hWnd) { OSVERSIONINFOA version; - InputContextData *data = get_imc_data( ImmGetContext( hWnd )); + struct imc *data = get_imc_data( ImmGetContext( hWnd ) ); TRACE("%p\n", hWnd); if ( data ) @@ -2096,7 +2096,7 @@ BOOL WINAPI ImmIsUIMessageW( BOOL WINAPI ImmNotifyIME( HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); TRACE("(%p, %ld, %ld, %ld)\n", hIMC, dwAction, dwIndex, dwValue); @@ -2186,7 +2186,7 @@ BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC) */ LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); TRACE("%p %Id %Id\n", hIMC, wParam, wParam); @@ -2201,7 +2201,7 @@ LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam) */ LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); TRACE("%p %Id %Id\n", hIMC, wParam, wParam); @@ -2217,7 +2217,7 @@ LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam) BOOL WINAPI ImmSetCandidateWindow( HIMC hIMC, LPCANDIDATEFORM lpCandidate) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); TRACE("(%p, %p)\n", hIMC, lpCandidate); @@ -2246,7 +2246,7 @@ BOOL WINAPI ImmSetCandidateWindow( */ BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); TRACE("(%p, %p)\n", hIMC, lplf); if (!data || !lplf) @@ -2271,7 +2271,7 @@ BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) */ BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); TRACE("(%p, %p)\n", hIMC, lplf); if (!data || !lplf) @@ -2302,7 +2302,7 @@ BOOL WINAPI ImmSetCompositionStringA( WCHAR *CompBuffer = NULL; WCHAR *ReadBuffer = NULL; BOOL rc; - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); TRACE("(%p, %ld, %p, %ld, %p, %ld):\n", hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); @@ -2358,7 +2358,7 @@ BOOL WINAPI ImmSetCompositionStringW( CHAR *CompBuffer = NULL; CHAR *ReadBuffer = NULL; BOOL rc; - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); TRACE("(%p, %ld, %p, %ld, %p, %ld):\n", hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); @@ -2412,7 +2412,7 @@ BOOL WINAPI ImmSetCompositionWindow( HIMC hIMC, LPCOMPOSITIONFORM lpCompForm) { BOOL reshow = FALSE; - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); TRACE("(%p, %p)\n", hIMC, lpCompForm); if (lpCompForm) @@ -2451,7 +2451,7 @@ BOOL WINAPI ImmSetConversionStatus( HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence) { DWORD oldConversion, oldSentence; - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); TRACE("%p %ld %ld\n", hIMC, fdwConversion, fdwSentence); @@ -2486,7 +2486,7 @@ BOOL WINAPI ImmSetConversionStatus( */ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); TRACE("%p %d\n", hIMC, fOpen); @@ -2522,7 +2522,7 @@ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) */ BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); TRACE("(%p, %p)\n", hIMC, lpptPos); @@ -2641,7 +2641,7 @@ BOOL WINAPI ImmUnregisterWordW( HKL hkl, const WCHAR *readingW, DWORD style, con DWORD WINAPI ImmGetImeMenuItemsA( HIMC himc, DWORD flags, DWORD type, IMEMENUITEMINFOA *parentA, IMEMENUITEMINFOA *menuA, DWORD size ) { - InputContextData *data = get_imc_data( himc ); + struct imc *data = get_imc_data( himc ); DWORD ret; TRACE( "himc %p, flags %#lx, type %lu, parentA %p, menuA %p, size %lu.\n", @@ -2699,7 +2699,7 @@ DWORD WINAPI ImmGetImeMenuItemsA( HIMC himc, DWORD flags, DWORD type, IMEMENUITE DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITEMINFOW *parentW, IMEMENUITEMINFOW *menuW, DWORD size ) { - InputContextData *data = get_imc_data( himc ); + struct imc *data = get_imc_data( himc ); DWORD ret; TRACE( "himc %p, flags %#lx, type %lu, parentW %p, menuW %p, size %lu.\n", @@ -2754,7 +2754,7 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITE */ LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); if (!data) return NULL; @@ -2767,7 +2767,7 @@ LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC) */ BOOL WINAPI ImmUnlockIMC(HIMC hIMC) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); if (!data) return FALSE; @@ -2781,7 +2781,7 @@ BOOL WINAPI ImmUnlockIMC(HIMC hIMC) */ DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); if (!data) return 0; return data->dwLock; @@ -2848,7 +2848,7 @@ DWORD WINAPI ImmGetIMCCSize(HIMCC imcc) */ BOOL WINAPI ImmGenerateMessage(HIMC hIMC) { - InputContextData *data = get_imc_data(hIMC); + struct imc *data = get_imc_data( hIMC ); if (!data) { @@ -2888,7 +2888,7 @@ BOOL WINAPI ImmGenerateMessage(HIMC hIMC) */ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData) { - InputContextData *data; + struct imc *data; HIMC imc = ImmGetContext(hwnd); BYTE state[256]; UINT scancode; @@ -2947,7 +2947,7 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD */ BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD unknown) { - InputContextData *data; + struct imc *data; HIMC imc = ImmGetContext(hwnd); BYTE state[256]; From a5681cb04928251050ddb4f1c4f6caf1261f8e25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 23 Mar 2023 12:03:51 +0100 Subject: [PATCH 1752/2777] imm32: Fix ImmEscape(A|W) with NULL data. (cherry picked from commit 8f6eda8649b6b214181aa604361b29867372706a) --- dlls/imm32/imm.c | 4 ++-- dlls/imm32/tests/imm32.c | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index c22c1fb9e64..f202c4cf1e7 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1006,7 +1006,7 @@ LRESULT WINAPI ImmEscapeA( HKL hkl, HIMC himc, UINT code, void *data ) if (!(ime = ime_acquire( hkl ))) return 0; - if (!EscapeRequiresWA( code ) || !ime_is_unicode( ime )) + if (!EscapeRequiresWA( code ) || !ime_is_unicode( ime ) || !data) ret = ime->pImeEscape( himc, code, data ); else { @@ -1039,7 +1039,7 @@ LRESULT WINAPI ImmEscapeW( HKL hkl, HIMC himc, UINT code, void *data ) if (!(ime = ime_acquire( hkl ))) return 0; - if (!EscapeRequiresWA( code ) || ime_is_unicode( ime )) + if (!EscapeRequiresWA( code ) || ime_is_unicode( ime ) || !data) ret = ime->pImeEscape( himc, code, data ); else { diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 73fbe9d1aa5..a13adf213d5 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2566,15 +2566,9 @@ static LRESULT WINAPI ime_ImeEscape( HIMC himc, UINT escape, void *data ) case IME_ESC_SET_EUDC_DICTIONARY: if (!data) return 4; if (ime_info.fdwProperty & IME_PROP_UNICODE) - { - todo_wine_if(*(WCHAR *)data != 'E') ok_wcs( L"EscapeIme", data ); - } else - { - todo_wine_if(*(char *)data != 'E') ok_str( "EscapeIme", data ); - } /* fallthrough */ case IME_ESC_QUERY_SUPPORT: case IME_ESC_SEQUENCE_TO_INTERNAL: From 05b42ecd89905567a4114bf2d0533c81b421e405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 23 Mar 2023 12:11:51 +0100 Subject: [PATCH 1753/2777] imm32: Fix ImmEnumRegisterWord(A|W) callback conversion. (cherry picked from commit 66e715f409912f814a199cab9d4c481d1acc4464) --- dlls/imm32/imm.c | 40 ++++++++++++++++++++++++++++++++++++++-- dlls/imm32/tests/imm32.c | 4 ---- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index f202c4cf1e7..e47e8aa4c44 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -928,6 +928,23 @@ BOOL WINAPI ImmDestroyContext(HIMC hIMC) return IMM_DestroyContext(hIMC); } +struct enum_register_word_params_WtoA +{ + REGISTERWORDENUMPROCA proc; + void *user; +}; + +static int CALLBACK enum_register_word_WtoA( const WCHAR *readingW, DWORD style, + const WCHAR *stringW, void *user ) +{ + char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW ); + struct enum_register_word_params_WtoA *params = user; + int ret = params->proc( readingA, style, stringA, params->user ); + free( readingA ); + free( stringA ); + return ret; +} + /*********************************************************************** * ImmEnumRegisterWordA (IMM32.@) */ @@ -946,8 +963,9 @@ UINT WINAPI ImmEnumRegisterWordA( HKL hkl, REGISTERWORDENUMPROCA procA, const ch ret = ime->pImeEnumRegisterWord( procA, readingA, style, stringA, user ); else { + struct enum_register_word_params_WtoA params = {.proc = procA, .user = user}; WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA ); - ret = ime->pImeEnumRegisterWord( procA, readingW, style, stringW, user ); + ret = ime->pImeEnumRegisterWord( enum_register_word_WtoA, readingW, style, stringW, ¶ms ); free( readingW ); free( stringW ); } @@ -956,6 +974,23 @@ UINT WINAPI ImmEnumRegisterWordA( HKL hkl, REGISTERWORDENUMPROCA procA, const ch return ret; } +struct enum_register_word_params_AtoW +{ + REGISTERWORDENUMPROCW proc; + void *user; +}; + +static int CALLBACK enum_register_word_AtoW( const char *readingA, DWORD style, + const char *stringA, void *user ) +{ + WCHAR *readingW = strdupAtoW( readingA ), *stringW = strdupAtoW( stringA ); + struct enum_register_word_params_AtoW *params = user; + int ret = params->proc( readingW, style, stringW, params->user ); + free( readingW ); + free( stringW ); + return ret; +} + /*********************************************************************** * ImmEnumRegisterWordW (IMM32.@) */ @@ -974,8 +1009,9 @@ UINT WINAPI ImmEnumRegisterWordW( HKL hkl, REGISTERWORDENUMPROCW procW, const WC ret = ime->pImeEnumRegisterWord( procW, readingW, style, stringW, user ); else { + struct enum_register_word_params_AtoW params = {.proc = procW, .user = user}; char *readingA = strdupWtoA( readingW ), *stringA = strdupWtoA( stringW ); - ret = ime->pImeEnumRegisterWord( procW, readingA, style, stringA, user ); + ret = ime->pImeEnumRegisterWord( enum_register_word_AtoW, readingA, style, stringA, ¶ms ); free( readingA ); free( stringA ); } diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index a13adf213d5..317abb44870 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3400,9 +3400,7 @@ static int CALLBACK enum_register_wordA( const char *reading, DWORD style, const ime_trace( "reading %s, style %#lx, string %s, user %p\n", debugstr_a(reading), style, debugstr_a(string), user ); ok_eq( 0xdeadbeef, style, UINT, "%#x" ); - todo_wine_if( reading[1] == 0 ) ok_str( "Reading", reading ); - todo_wine_if( string[1] == 0 ) ok_str( "String", string ); return 0xdeadbeef; @@ -3413,9 +3411,7 @@ static int CALLBACK enum_register_wordW( const WCHAR *reading, DWORD style, cons ime_trace( "reading %s, style %#lx, string %s, user %p\n", debugstr_w(reading), style, debugstr_w(string), user ); ok_eq( 0xdeadbeef, style, UINT, "%#x" ); - todo_wine_if( reading[0] != 'R' ) ok_wcs( L"Reading", reading ); - todo_wine_if( string[0] != 'S' ) ok_wcs( L"String", string ); return 0xdeadbeef; From fc45800d973bfc886c38d94a2a6da580242e786b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 23 Mar 2023 12:18:25 +0100 Subject: [PATCH 1754/2777] imm32/tests: Reduce test output unnecessary verbosity. (cherry picked from commit b48a65930811f8e84e7d35f98377960892246928) --- dlls/imm32/tests/imm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 317abb44870..6f29155dc62 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2841,7 +2841,7 @@ static HKL ime_install(void) ok( !wcscmp( buffer, L"WineTest IME" ), "got Layout Text %s\n", debugstr_w(buffer) ); len = sizeof(buffer); - memset( buffer, 0xcd, sizeof(buffer) ); + memset( buffer, 0, sizeof(buffer) ); ret = RegQueryValueExW( hkey, L"Layout File", NULL, NULL, (BYTE *)buffer, &len ); todo_wine ok( !ret, "RegQueryValueExW returned %#lx, error %lu\n", ret, GetLastError() ); From 3f5198c1285de2ec8ae53da7d5316f0701a82d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 9 Mar 2023 10:26:10 +0100 Subject: [PATCH 1755/2777] imm32: Stub ImmActivateLayout. (cherry picked from commit bcc2337f303f1c71bb3c4ed1afad174a73bfa0e3) --- dlls/imm32/imm.c | 6 ++++++ dlls/imm32/imm32.spec | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index e47e8aa4c44..1b8caf90c1c 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -564,6 +564,12 @@ static void ime_release( struct ime *ime ) LeaveCriticalSection( &ime_cs ); } +BOOL WINAPI ImmActivateLayout( HKL hkl ) +{ + FIXME( "hkl %p stub!\n", hkl ); + return FALSE; +} + static BOOL free_input_context_data( HIMC hIMC ) { struct imc *data = query_imc_data( hIMC ); diff --git a/dlls/imm32/imm32.spec b/dlls/imm32/imm32.spec index 9c7ce13319f..47b3916c822 100644 --- a/dlls/imm32/imm32.spec +++ b/dlls/imm32/imm32.spec @@ -1,4 +1,4 @@ -@ stub ImmActivateLayout +@ stdcall ImmActivateLayout(long) @ stdcall ImmAssociateContext(long long) @ stdcall ImmAssociateContextEx(long long long) @ stdcall ImmConfigureIMEA(long long long ptr) From 7512a5514845ac685efa1c6ec3117a5035de3392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 9 Mar 2023 10:35:09 +0100 Subject: [PATCH 1756/2777] imm32/tests: Test undocumented ImmActivateLayout. (cherry picked from commit 7b3e66678ab3fbb54504b4430de9393c99659b22) --- dlls/imm32/tests/imm32.c | 183 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 179 insertions(+), 4 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 6f29155dc62..d22b384c7a5 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -84,6 +84,7 @@ static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t); extern BOOL WINAPI ImmFreeLayout(HKL); extern BOOL WINAPI ImmLoadIME(HKL); +extern BOOL WINAPI ImmActivateLayout(HKL); #define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE, enabled_ ## func = FALSE @@ -2481,6 +2482,104 @@ DEFINE_EXPECT( IME_DLL_PROCESS_DETACH ); static IMEINFO ime_info; +enum ime_function +{ + IME_SELECT = 1, + IME_NOTIFY, +}; + +struct ime_call +{ + enum ime_function func; + HIMC himc; + + union + { + int select; + struct + { + int action; + int index; + int value; + } notify; + }; + + BOOL todo; +}; + +struct ime_call empty_sequence[] = {{0}}; +static struct ime_call ime_calls[1024]; +static ULONG ime_call_count; + +#define ok_call( a, b ) ok_call_( __FILE__, __LINE__, a, b ) +static void ok_call_( const char *file, int line, const struct ime_call *expected, const struct ime_call *received ) +{ + int ret; + + if ((ret = expected->func - received->func)) goto done; + if ((ret = (UINT_PTR)expected->himc - (UINT_PTR)received->himc)) goto done; + switch (expected->func) + { + case IME_SELECT: + if ((ret = expected->select - received->select)) goto done; + break; + case IME_NOTIFY: + if ((ret = expected->notify.action - received->notify.action)) goto done; + if ((ret = expected->notify.index - received->notify.index)) goto done; + if ((ret = expected->notify.value - received->notify.value)) goto done; + break; + } + +done: + switch (received->func) + { + case IME_SELECT: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "got IME_SELECT himc %p, select %u\n", received->himc, received->select ); + return; + case IME_NOTIFY: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "got IME_NOTIFY himc %p, action %#x, index %#x, value %#x\n", + received->himc, received->notify.action, received->notify.index, + received->notify.value ); + return; + } + + switch (expected->func) + { + case IME_SELECT: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "IME_SELECT himc %p, select %u\n", expected->himc, expected->select ); + break; + case IME_NOTIFY: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "IME_NOTIFY himc %p, action %#x, index %#x, value %#x\n", + expected->himc, expected->notify.action, expected->notify.index, + expected->notify.value ); + break; + } +} + +#define ok_seq( a ) ok_seq_( __FILE__, __LINE__, a, #a ) +static void ok_seq_( const char *file, int line, const struct ime_call *expected, const char *context ) +{ + const struct ime_call *received = ime_calls; + UINT i = 0; + + while (expected->func || received->func) + { + winetest_push_context( "%u%s%s", i++, !expected->func ? " (spurious)" : "", + !received->func ? " (missing)" : "" ); + ok_call_( file, line, expected, received ); + if (expected->func) expected++; + if (received->func) received++; + winetest_pop_context(); + } + + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; +} + static LRESULT CALLBACK ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); @@ -2675,9 +2774,10 @@ static BOOL WINAPI ime_ImeRegisterWord( const WCHAR *reading, DWORD style, const static BOOL WINAPI ime_ImeSelect( HIMC himc, BOOL select ) { + struct ime_call call = {.func = IME_SELECT, .himc = himc, .select = select}; ime_trace( "himc %p, select %d\n", himc, select ); - ok( 0, "unexpected call\n" ); - return FALSE; + ime_calls[ime_call_count++] = call; + return TRUE; } static BOOL WINAPI ime_ImeSetActiveContext( HIMC himc, BOOL flag ) @@ -2727,8 +2827,9 @@ static BOOL WINAPI ime_ImeUnregisterWord( const WCHAR *reading, DWORD style, con static BOOL WINAPI ime_NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) { - ime_trace( "himc %p, action %lu, index %lu, value %lu\n", himc, action, index, value ); - ok( 0, "unexpected call\n" ); + struct ime_call call = {.func = IME_NOTIFY, .himc = himc, .notify = {.action = action, .index = index, .value = value}}; + ime_trace( "himc %p, action %#lx, index %lu, value %lu\n", himc, action, index, value ); + ime_calls[ime_call_count++] = call; return FALSE; } @@ -3664,6 +3765,78 @@ static void test_ImmUnregisterWord( BOOL unicode ) winetest_pop_context(); } +static void test_ImmActivateLayout(void) +{ + const struct ime_call activate_seq[] = + { + {.func = IME_SELECT, .himc = default_himc, .select = 1, .todo = TRUE}, + {0}, + }; + const struct ime_call deactivate_seq[] = + { + {.func = IME_NOTIFY, .himc = default_himc, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0}, .todo = TRUE}, + {.func = IME_SELECT, .himc = default_himc, .select = 0, .todo = TRUE}, + {0}, + }; + HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + UINT ret; + + SET_ENABLE( ImeInquire, TRUE ); + SET_ENABLE( ImeDestroy, TRUE ); + + todo_wine + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + + ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; + + if (!(hkl = ime_install())) goto cleanup; + + /* ActivateKeyboardLayout doesn't call ImeInquire / ImeDestroy */ + + ok_seq( empty_sequence ); + ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); + ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); + ok_seq( empty_sequence ); + ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + + + /* ImmActivateLayout changes active HKL */ + + SET_EXPECT( ImeInquire ); + todo_wine + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_seq( activate_seq ); + todo_wine + CHECK_CALLED( ImeInquire ); + + todo_wine + ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + + todo_wine + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_seq( deactivate_seq ); + + ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + + ime_cleanup( hkl ); + ok_seq( empty_sequence ); + + + /* ImmActivateLayout leaks the IME, we need to free it manually */ + + SET_EXPECT( ImeDestroy ); + ret = ImmFreeLayout( hkl ); + ok( ret, "ImmFreeLayout returned %u\n", ret ); + todo_wine + CHECK_CALLED( ImeDestroy ); + ok_seq( empty_sequence ); + +cleanup: + SET_ENABLE( ImeInquire, FALSE ); + SET_ENABLE( ImeDestroy, FALSE ); +} + START_TEST(imm32) { if (!is_ime_enabled()) @@ -3693,6 +3866,8 @@ START_TEST(imm32) test_ImmUnregisterWord( FALSE ); test_ImmUnregisterWord( TRUE ); + test_ImmActivateLayout(); + if (init()) { test_ImmNotifyIME(); From 311bef7dab9f51c06367eaafc1b905213fa769f2 Mon Sep 17 00:00:00 2001 From: Francois Gouget Date: Tue, 21 Mar 2023 04:18:26 +0100 Subject: [PATCH 1757/2777] imm32/tests: Document the WINE_LANGID value. (cherry picked from commit 683ad8221b54ff37f5c185b0571da893bf409792) --- dlls/imm32/tests/ime_wrapper.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/imm32/tests/ime_wrapper.rc b/dlls/imm32/tests/ime_wrapper.rc index 812754ce4ce..e71d81f4fc9 100644 --- a/dlls/imm32/tests/ime_wrapper.rc +++ b/dlls/imm32/tests/ime_wrapper.rc @@ -18,7 +18,7 @@ #pragma makedep testdll -#define WINE_LANGID 047f +#define WINE_LANGID 047f /* LANG_INVARIANT/SUBLANG_DEFAULT */ #define WINE_FILETYPE VFT_DRV #define WINE_FILESUBTYPE VFT2_DRV_INPUTMETHOD #define WINE_FILENAME "ime_wrapper" From 38f1a0b222d0aa8b147774a440eadaf7f4f630f2 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Mon, 27 Mar 2023 13:44:57 +0100 Subject: [PATCH 1758/2777] win32u: Fix printf format warnings. (cherry picked from commit d0246c3ea0680f0bb40dcd0e5b54c942e096925c) --- dlls/win32u/input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index c7c8932e385..15eebd4a30c 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2501,7 +2501,7 @@ BOOL WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, UINT_P UINT32 *entry_count, UINT32 *pointer_count, void *pointer_info ) { FIXME( "id %#x, type %#x, unk0 %#zx, unk1 %#zx, size %#zx, entry_count %p, pointer_count %p, pointer_info %p stub!\n", - id, (int)type, unk0, unk1, (size_t)size, entry_count, pointer_count, pointer_info ); + id, (int)type, (size_t)unk0, (size_t)unk1, (size_t)size, entry_count, pointer_count, pointer_info ); RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED ); return FALSE; } From b53411f7525c60e2e29e7e42a5324ffa02356755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Mar 2023 14:45:00 +0200 Subject: [PATCH 1759/2777] win32u: Allow LANG_INVARIANT in NtUserActivateKeyboardLayout. (cherry picked from commit 4571456e703b944cdb7bc193ddb26da63635ff6e) --- dlls/win32u/input.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 15eebd4a30c..a983ac0b706 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1209,7 +1209,8 @@ HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags ) return 0; } - if (NtQueryDefaultLocale( TRUE, &locale ) || LOWORD(layout) != locale) + if (LOWORD(layout) != MAKELANGID(LANG_INVARIANT, SUBLANG_DEFAULT) && + (NtQueryDefaultLocale( TRUE, &locale ) || LOWORD(layout) != locale)) { RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED ); FIXME_(keyboard)( "Changing user locale is not supported\n" ); From 7c6f448967feb2eb89ad989f5547c37beebbf9f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Mar 2023 14:45:42 +0200 Subject: [PATCH 1760/2777] imm32: Use installed IME language for the created HKL. (cherry picked from commit db5cf9a5e12b6e8f664f54a626f4cf6efc2bfbf3) --- dlls/imm32/Makefile.in | 2 +- dlls/imm32/imm.c | 26 ++++++++++++++++++++++---- dlls/imm32/tests/imm32.c | 1 - 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/dlls/imm32/Makefile.in b/dlls/imm32/Makefile.in index 29de6063792..b4e3039849e 100644 --- a/dlls/imm32/Makefile.in +++ b/dlls/imm32/Makefile.in @@ -1,6 +1,6 @@ MODULE = imm32.dll IMPORTLIB = imm32 -IMPORTS = user32 gdi32 advapi32 win32u +IMPORTS = user32 gdi32 advapi32 kernelbase win32u DELAYIMPORTS = ole32 C_SRCS = \ diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 1b8caf90c1c..e600156f504 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2012,13 +2012,31 @@ HKL WINAPI ImmInstallIMEA( const char *filenameA, const char *descriptionA ) return hkl; } +static LCID get_ime_file_lang( const WCHAR *filename ) +{ + DWORD *languages; + LCID lcid = 0; + void *info; + UINT len; + + if (!(len = GetFileVersionInfoSizeW( filename, NULL ))) return 0; + if (!(info = malloc( len ))) goto done; + if (!GetFileVersionInfoW( filename, 0, len, info )) goto done; + if (!VerQueryValueW( info, L"\\VarFileInfo\\Translation", (void **)&languages, &len ) || !len) goto done; + lcid = languages[0]; + +done: + free( info ); + return lcid; +} + /*********************************************************************** * ImmInstallIMEW (IMM32.@) */ HKL WINAPI ImmInstallIMEW( const WCHAR *filename, const WCHAR *description ) { WCHAR path[ARRAY_SIZE(layouts_formatW)+8], buffer[MAX_PATH]; - LCID lcid = GetUserDefaultLCID(); + LCID lcid; WORD count = 0x20; const WCHAR *tmp; DWORD length; @@ -2027,7 +2045,7 @@ HKL WINAPI ImmInstallIMEW( const WCHAR *filename, const WCHAR *description ) TRACE( "filename %s, description %s\n", debugstr_w(filename), debugstr_w(description) ); - if (!filename || !description) + if (!filename || !description || !(lcid = get_ime_file_lang( filename ))) { SetLastError( ERROR_INVALID_PARAMETER ); return 0; @@ -2037,8 +2055,8 @@ HKL WINAPI ImmInstallIMEW( const WCHAR *filename, const WCHAR *description ) { DWORD disposition = 0; - hkl = (HKL)MAKELPARAM( lcid, 0xe000 | count ); - swprintf( path, ARRAY_SIZE(path), layouts_formatW, (ULONG_PTR)hkl); + hkl = (HKL)(UINT_PTR)MAKELONG( lcid, 0xe000 | count ); + swprintf( path, ARRAY_SIZE(path), layouts_formatW, (ULONG)(ULONG_PTR)hkl); if (!RegCreateKeyExW( HKEY_LOCAL_MACHINE, path, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &disposition )) { diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index d22b384c7a5..7b9abb0b079 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2922,7 +2922,6 @@ static HKL ime_install(void) "MoveFileW failed, error %lu\n", GetLastError() ); hkl = ImmInstallIMEW( ime_path, L"WineTest IME" ); - todo_wine ok( hkl == (HKL)(int)0xe020047f, "ImmInstallIMEW returned %p, error %lu\n", hkl, GetLastError() ); swprintf( buffer, ARRAY_SIZE(buffer), L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08x", hkl ); From 587cf862d6f92deabe6dfd1f6b7c2ee188bb8a1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Mar 2023 14:50:20 +0200 Subject: [PATCH 1761/2777] imm32/tests: Check current keyboard layout during ime calls. (cherry picked from commit ca97db75d12d4853285f94cd151759bbd845ef1f) --- dlls/imm32/tests/imm32.c | 65 +++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 7b9abb0b079..bfc61e05346 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2481,6 +2481,11 @@ static BOOL todo_IME_DLL_PROCESS_DETACH; DEFINE_EXPECT( IME_DLL_PROCESS_DETACH ); static IMEINFO ime_info; +static UINT ime_count; +static WCHAR ime_path[MAX_PATH]; +static HIMC default_himc; +static HKL default_hkl; +static HKL expect_ime = (HKL)(int)0xe020047f; enum ime_function { @@ -2490,8 +2495,9 @@ enum ime_function struct ime_call { - enum ime_function func; + HKL hkl; HIMC himc; + enum ime_function func; union { @@ -2518,6 +2524,7 @@ static void ok_call_( const char *file, int line, const struct ime_call *expecte if ((ret = expected->func - received->func)) goto done; if ((ret = (UINT_PTR)expected->himc - (UINT_PTR)received->himc)) goto done; + if ((ret = (UINT)(UINT_PTR)expected->hkl - (UINT)(UINT_PTR)received->hkl)) goto done; switch (expected->func) { case IME_SELECT: @@ -2535,12 +2542,12 @@ static void ok_call_( const char *file, int line, const struct ime_call *expecte { case IME_SELECT: todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "got IME_SELECT himc %p, select %u\n", received->himc, received->select ); + ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SELECT select %u\n", received->hkl, received->himc, received->select ); return; case IME_NOTIFY: todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "got IME_NOTIFY himc %p, action %#x, index %#x, value %#x\n", - received->himc, received->notify.action, received->notify.index, + ok_(file, line)( !ret, "got hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n", + received->hkl, received->himc, received->notify.action, received->notify.index, received->notify.value ); return; } @@ -2549,12 +2556,12 @@ static void ok_call_( const char *file, int line, const struct ime_call *expecte { case IME_SELECT: todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "IME_SELECT himc %p, select %u\n", expected->himc, expected->select ); + ok_(file, line)( !ret, "hkl %p, himc %p, IME_SELECT select %u\n", expected->hkl, expected->himc, expected->select ); break; case IME_NOTIFY: todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "IME_NOTIFY himc %p, action %#x, index %#x, value %#x\n", - expected->himc, expected->notify.action, expected->notify.index, + ok_(file, line)( !ret, "hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n", + expected->hkl, expected->himc, expected->notify.action, expected->notify.index, expected->notify.value ); break; } @@ -2630,6 +2637,7 @@ static UINT WINAPI ime_ImeEnumRegisterWord( REGISTERWORDENUMPROCW proc, const WC ime_trace( "proc %p, reading %s, style %lu, string %s, data %p\n", proc, debugstr_w(reading), style, debugstr_w(string), data ); + ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); CHECK_EXPECT( ImeEnumRegisterWord ); if (!style) @@ -2658,6 +2666,7 @@ static LRESULT WINAPI ime_ImeEscape( HIMC himc, UINT escape, void *data ) { ime_trace( "himc %p, escape %#x, data %p\n", himc, escape, data ); + ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); CHECK_EXPECT( ImeEscape ); switch (escape) @@ -2701,6 +2710,7 @@ static UINT WINAPI ime_ImeGetRegisterWordStyle( UINT item, STYLEBUFW *style ) { ime_trace( "item %u, style %p\n", item, style ); + ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); CHECK_EXPECT( ImeGetRegisterWordStyle ); if (!style) @@ -2747,6 +2757,7 @@ static BOOL WINAPI ime_ImeProcessKey( HIMC himc, UINT vkey, LPARAM key_data, BYT { ime_trace( "himc %p, vkey %u, key_data %#Ix, key_state %p\n", himc, vkey, key_data, key_state ); + ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); ok( 0, "unexpected call\n" ); return FALSE; } @@ -2755,6 +2766,7 @@ static BOOL WINAPI ime_ImeRegisterWord( const WCHAR *reading, DWORD style, const { ime_trace( "reading %s, style %lu, string %s\n", debugstr_w(reading), style, debugstr_w(string) ); + ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); CHECK_EXPECT( ImeRegisterWord ); if (style) ok_eq( 0xdeadbeef, style, UINT, "%#x" ); @@ -2774,7 +2786,11 @@ static BOOL WINAPI ime_ImeRegisterWord( const WCHAR *reading, DWORD style, const static BOOL WINAPI ime_ImeSelect( HIMC himc, BOOL select ) { - struct ime_call call = {.func = IME_SELECT, .himc = himc, .select = select}; + struct ime_call call = + { + .hkl = GetKeyboardLayout( 0 ), .himc = himc, + .func = IME_SELECT, .select = select + }; ime_trace( "himc %p, select %d\n", himc, select ); ime_calls[ime_call_count++] = call; return TRUE; @@ -2808,6 +2824,7 @@ static BOOL WINAPI ime_ImeUnregisterWord( const WCHAR *reading, DWORD style, con { ime_trace( "reading %s, style %lu, string %s\n", debugstr_w(reading), style, debugstr_w(string) ); + ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); CHECK_EXPECT( ImeUnregisterWord ); if (style) ok_eq( 0xdeadbeef, style, UINT, "%#x" ); @@ -2827,7 +2844,11 @@ static BOOL WINAPI ime_ImeUnregisterWord( const WCHAR *reading, DWORD style, con static BOOL WINAPI ime_NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) { - struct ime_call call = {.func = IME_NOTIFY, .himc = himc, .notify = {.action = action, .index = index, .value = value}}; + struct ime_call call = + { + .hkl = GetKeyboardLayout( 0 ), .himc = himc, + .func = IME_NOTIFY, .notify = {.action = action, .index = index, .value = value} + }; ime_trace( "himc %p, action %#lx, index %lu, value %lu\n", himc, action, index, value ); ime_calls[ime_call_count++] = call; return FALSE; @@ -2878,10 +2899,6 @@ static struct ime_functions ime_functions = ime_DllMain, }; -static UINT ime_count; -static WCHAR ime_path[MAX_PATH]; -static HIMC default_himc; - static HKL ime_install(void) { WCHAR buffer[MAX_PATH]; @@ -2922,7 +2939,7 @@ static HKL ime_install(void) "MoveFileW failed, error %lu\n", GetLastError() ); hkl = ImmInstallIMEW( ime_path, L"WineTest IME" ); - ok( hkl == (HKL)(int)0xe020047f, "ImmInstallIMEW returned %p, error %lu\n", hkl, GetLastError() ); + ok( hkl == expect_ime, "ImmInstallIMEW returned %p, error %lu\n", hkl, GetLastError() ); swprintf( buffer, ARRAY_SIZE(buffer), L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08x", hkl ); ret = RegOpenKeyW( HKEY_LOCAL_MACHINE, buffer, &hkey ); @@ -3768,13 +3785,25 @@ static void test_ImmActivateLayout(void) { const struct ime_call activate_seq[] = { - {.func = IME_SELECT, .himc = default_himc, .select = 1, .todo = TRUE}, + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_SELECT, .select = 1, + .todo = TRUE, + }, {0}, }; const struct ime_call deactivate_seq[] = { - {.func = IME_NOTIFY, .himc = default_himc, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0}, .todo = TRUE}, - {.func = IME_SELECT, .himc = default_himc, .select = 0, .todo = TRUE}, + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_NOTIFY, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0}, + .todo = TRUE, + }, + { + .hkl = default_hkl, .himc = default_himc, + .func = IME_SELECT, .select = 0, + .todo = TRUE, + }, {0}, }; HKL hkl, old_hkl = GetKeyboardLayout( 0 ); @@ -3838,6 +3867,8 @@ static void test_ImmActivateLayout(void) START_TEST(imm32) { + default_hkl = GetKeyboardLayout( 0 ); + if (!is_ime_enabled()) { win_skip("IME support not implemented\n"); From 16a5fb1c65c8b2d0763083fb00598a6f1ba1e528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Mar 2023 10:33:45 +0200 Subject: [PATCH 1762/2777] imm32: Call ActivateKeyboardLayout from ImmActivateLayout. (cherry picked from commit 47533974ce156c90b203fe59e69a17b17ed312b6) --- dlls/imm32/imm.c | 8 ++++++-- dlls/imm32/tests/imm32.c | 7 +++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index e600156f504..ee9e673233b 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -566,8 +566,12 @@ static void ime_release( struct ime *ime ) BOOL WINAPI ImmActivateLayout( HKL hkl ) { - FIXME( "hkl %p stub!\n", hkl ); - return FALSE; + FIXME( "hkl %p semi-stub!\n", hkl ); + + if (hkl == GetKeyboardLayout( 0 )) return TRUE; + if (!ActivateKeyboardLayout( hkl, 0 )) return FALSE; + + return TRUE; } static BOOL free_input_context_data( HIMC hIMC ) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index bfc61e05346..0dfe3cddf90 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3812,7 +3812,6 @@ static void test_ImmActivateLayout(void) SET_ENABLE( ImeInquire, TRUE ); SET_ENABLE( ImeDestroy, TRUE ); - todo_wine ok_ret( 1, ImmActivateLayout( old_hkl ) ); ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; @@ -3832,16 +3831,16 @@ static void test_ImmActivateLayout(void) /* ImmActivateLayout changes active HKL */ SET_EXPECT( ImeInquire ); - todo_wine ok_ret( 1, ImmActivateLayout( hkl ) ); ok_seq( activate_seq ); todo_wine CHECK_CALLED( ImeInquire ); - todo_wine ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); - todo_wine + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_seq( empty_sequence ); + ok_ret( 1, ImmActivateLayout( old_hkl ) ); ok_seq( deactivate_seq ); From 5869102d7766542bae12b454d87f18a4943ca0ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Mar 2023 15:23:11 +0200 Subject: [PATCH 1763/2777] imm32/tests: Test ImmCreateInputContext et al. (cherry picked from commit c2c27e7927a573199dbfc927d6caae2e57676ace) --- dlls/imm32/tests/imm32.c | 161 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 159 insertions(+), 2 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 0dfe3cddf90..392f14cdcf3 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2511,6 +2511,7 @@ struct ime_call }; BOOL todo; + BOOL flaky_himc; }; struct ime_call empty_sequence[] = {{0}}; @@ -2523,7 +2524,9 @@ static void ok_call_( const char *file, int line, const struct ime_call *expecte int ret; if ((ret = expected->func - received->func)) goto done; - if ((ret = (UINT_PTR)expected->himc - (UINT_PTR)received->himc)) goto done; + /* Wine doesn't allocate HIMC in a deterministic order, ignore them when they are enumerated */ + if (expected->flaky_himc && (ret = !!(UINT_PTR)expected->himc - !!(UINT_PTR)received->himc)) goto done; + if (!expected->flaky_himc && (ret = (UINT_PTR)expected->himc - (UINT_PTR)received->himc)) goto done; if ((ret = (UINT)(UINT_PTR)expected->hkl - (UINT)(UINT_PTR)received->hkl)) goto done; switch (expected->func) { @@ -2590,7 +2593,6 @@ static void ok_seq_( const char *file, int line, const struct ime_call *expected static LRESULT CALLBACK ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); - ok( 0, "unexpected call\n" ); return DefWindowProcW( hwnd, msg, wparam, lparam ); } @@ -3864,6 +3866,160 @@ static void test_ImmActivateLayout(void) SET_ENABLE( ImeDestroy, FALSE ); } +static void test_ImmCreateInputContext(void) +{ + struct ime_call activate_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_SELECT, .select = 1, + .todo = TRUE, .flaky_himc = TRUE, + }, + { + .hkl = expect_ime, .himc = 0/*himc[0]*/, + .func = IME_SELECT, .select = 1, + .todo = TRUE, .flaky_himc = TRUE, + }, + {0}, + }; + struct ime_call select1_seq[] = + { + { + .hkl = expect_ime, .himc = 0/*himc[1]*/, + .func = IME_SELECT, .select = 1, + .todo = TRUE, + }, + {0}, + }; + struct ime_call select0_seq[] = + { + { + .hkl = expect_ime, .himc = 0/*himc[1]*/, + .func = IME_SELECT, .select = 0, + }, + {0}, + }; + struct ime_call deactivate_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_NOTIFY, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0}, + .todo = TRUE, .flaky_himc = TRUE, + }, + { + .hkl = expect_ime, .himc = 0/*himc[0]*/, + .func = IME_NOTIFY, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0}, + .todo = TRUE, .flaky_himc = TRUE, + }, + { + .hkl = default_hkl, .himc = default_himc, + .func = IME_SELECT, .select = 0, + .todo = TRUE, .flaky_himc = TRUE, + }, + { + .hkl = default_hkl, .himc = 0/*himc[0]*/, + .func = IME_SELECT, .select = 0, + .todo = TRUE, .flaky_himc = TRUE, + }, + {0}, + }; + HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + INPUTCONTEXT *ctx; + HIMC himc[2]; + HWND hwnd; + + ctx = ImmLockIMC( default_himc ); + ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); + ok_ret( 0, IsWindow( ctx->hWnd ) ); + ok_ret( 1, ImmUnlockIMC( default_himc ) ); + + + /* new input contexts cannot be locked before IME window has been created */ + + himc[0] = ImmCreateContext(); + ok( !!himc[0], "ImmCreateContext failed, error %lu\n", GetLastError() ); + ctx = ImmLockIMC( himc[0] ); + todo_wine + ok( !ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); + if (ctx) ImmUnlockIMCC( himc[0] ); + + hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + + ctx = ImmLockIMC( default_himc ); + ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); + ok_ret( 1, ImmUnlockIMC( default_himc ) ); + + ctx = ImmLockIMC( himc[0] ); + ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); + ok_ret( 1, ImmUnlockIMC( himc[0] ) ); + + + ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; + ime_info.dwPrivateDataSize = 123; + + if (!(hkl = ime_install())) goto cleanup; + + + /* Activating the layout calls ImeSelect 1 on existing HIMC */ + + ok_seq( empty_sequence ); + ok_ret( 1, ImmActivateLayout( hkl ) ); + activate_seq[1].himc = himc[0]; + ok_seq( activate_seq ); + + ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + + ctx = ImmLockIMC( default_himc ); + ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); + ok_ret( 1, ImmUnlockIMC( default_himc ) ); + + ctx = ImmLockIMC( himc[0] ); + ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); + ok_ret( 1, ImmUnlockIMC( himc[0] ) ); + + + /* ImmLockIMC triggers the ImeSelect call, to allocate private data */ + + himc[1] = ImmCreateContext(); + ok( !!himc[1], "ImmCreateContext failed, error %lu\n", GetLastError() ); + + todo_wine + ok_seq( empty_sequence ); + ctx = ImmLockIMC( himc[1] ); + ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); + select1_seq[0].himc = himc[1]; + ok_seq( select1_seq ); + + ok_ret( 1, ImmUnlockIMC( himc[1] ) ); + + ok_seq( empty_sequence ); + ok_ret( 1, ImmDestroyContext( himc[1] ) ); + select0_seq[0].himc = himc[1]; + ok_seq( select0_seq ); + + + /* Deactivating the layout calls ImeSelect 0 on existing HIMC */ + + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + deactivate_seq[1].himc = himc[0]; + deactivate_seq[3].himc = himc[0]; + ok_seq( deactivate_seq ); + + ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + + ok_ret( 1, ImmFreeLayout( hkl ) ); + ime_cleanup( hkl ); + ok_seq( empty_sequence ); + +cleanup: + ok_ret( 1, ImmDestroyContext( himc[0] ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + + ime_info.dwPrivateDataSize = 0; +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); @@ -3896,6 +4052,7 @@ START_TEST(imm32) test_ImmUnregisterWord( TRUE ); test_ImmActivateLayout(); + test_ImmCreateInputContext(); if (init()) { From eec33f982ff590e1fced2c3d5618843dbead34d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 25 Mar 2023 13:47:20 +0100 Subject: [PATCH 1764/2777] imm32/tests: Test ActivateKeyboardLayout with an existing window. (cherry picked from commit 462d5ca257db7ac6a8a7f6dcee0344d6ea99547b) --- dlls/imm32/tests/imm32.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 392f14cdcf3..5dde6cd1b1f 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3861,6 +3861,44 @@ static void test_ImmActivateLayout(void) CHECK_CALLED( ImeDestroy ); ok_seq( empty_sequence ); + + /* when there's a window, ActivateKeyboardLayout calls ImeInquire */ + + if (!(hkl = ime_install())) goto cleanup; + + hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + ok_seq( empty_sequence ); + + SET_EXPECT( ImeInquire ); + ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); + todo_wine + CHECK_CALLED( ImeInquire ); + ok_seq( activate_seq ); + + ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + + ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); + ok_seq( deactivate_seq ); + + ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + + ime_cleanup( hkl ); + ok_seq( empty_sequence ); + + /* ImmActivateLayout leaks the IME, we need to free it manually */ + + SET_EXPECT( ImeDestroy ); + ret = ImmFreeLayout( hkl ); + ok( ret, "ImmFreeLayout returned %u\n", ret ); + todo_wine + CHECK_CALLED( ImeDestroy ); + ok_seq( empty_sequence ); + + ok_ret( 1, DestroyWindow( hwnd ) ); + + cleanup: SET_ENABLE( ImeInquire, FALSE ); SET_ENABLE( ImeDestroy, FALSE ); From 7cd00e2ba80d1a1f485cd38acc8cc2985842ac37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Mar 2023 12:48:51 +0200 Subject: [PATCH 1765/2777] imm32: Enumerate input contexts in ImmActivateLayout. (cherry picked from commit 0aa3b85b9795f2e18e16589c60e4bb1ed418e108) --- dlls/imm32/imm.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index ee9e673233b..803fb555786 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -564,13 +564,21 @@ static void ime_release( struct ime *ime ) LeaveCriticalSection( &ime_cs ); } +static BOOL CALLBACK enum_activate_layout( HIMC himc, LPARAM lparam ) +{ + if (ImmLockIMC( himc )) ImmUnlockIMC( himc ); + return TRUE; +} + BOOL WINAPI ImmActivateLayout( HKL hkl ) { - FIXME( "hkl %p semi-stub!\n", hkl ); + TRACE( "hkl %p\n", hkl ); if (hkl == GetKeyboardLayout( 0 )) return TRUE; if (!ActivateKeyboardLayout( hkl, 0 )) return FALSE; + ImmEnumInputContext( 0, enum_activate_layout, 0 ); + return TRUE; } From f48c5abceb922fed3959829690578489176b78ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Mar 2023 12:49:06 +0200 Subject: [PATCH 1766/2777] imm32: Introduce a new imc_select_hkl helper. (cherry picked from commit 9c8b3e6f421fa1c5a0158f596b33bd3861c28cf7) --- dlls/imm32/imm.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 803fb555786..473f1927753 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -564,6 +564,23 @@ static void ime_release( struct ime *ime ) LeaveCriticalSection( &ime_cs ); } +static void imc_select_hkl( struct imc *imc, HKL hkl ) +{ + if (imc->ime) + { + if (imc->ime->hkl == hkl) return; + imc->ime->pImeSelect( imc->handle, FALSE ); + ime_release( imc->ime ); + } + + if (!hkl) + imc->ime = NULL; + else if (!(imc->ime = ime_acquire( hkl ))) + WARN( "Failed to acquire IME for HKL %p\n", hkl ); + else + imc->ime->pImeSelect( imc->handle, TRUE ); +} + static BOOL CALLBACK enum_activate_layout( HIMC himc, LPARAM lparam ) { if (ImmLockIMC( himc )) ImmUnlockIMC( himc ); @@ -3026,20 +3043,8 @@ BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD TRACE("%p %p %x %x %lx\n",hwnd, hKL, vKey, (UINT)lKeyData, unknown); if (!(data = get_imc_data( imc ))) return FALSE; - - /* Make sure we are inputting to the correct keyboard */ - if (data->ime->hkl != hKL) - { - struct ime *new_hkl; - - if (!(new_hkl = ime_acquire( hKL ))) return FALSE; - - data->ime->pImeSelect( imc, FALSE ); - ime_release( data->ime ); - - data->ime = new_hkl; - data->ime->pImeSelect( imc, TRUE ); - } + imc_select_hkl( data, hKL ); + if (!data->ime) return FALSE; GetKeyboardState(state); if (data->ime->pImeProcessKey( imc, vKey, lKeyData, state )) From a14d783e22870ea4316f085dc89c3ffe4aff38ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 28 Mar 2023 09:27:28 +0200 Subject: [PATCH 1767/2777] imm32: Update HIMC private data when selecting IME. (cherry picked from commit de4323611a232fd0cd25c59625ff08af91c75a8f) --- dlls/imm32/imm.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 473f1927753..04bfc461658 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -571,6 +571,7 @@ static void imc_select_hkl( struct imc *imc, HKL hkl ) if (imc->ime->hkl == hkl) return; imc->ime->pImeSelect( imc->handle, FALSE ); ime_release( imc->ime ); + ImmDestroyIMCC( imc->IMC.hPrivate ); } if (!hkl) @@ -578,7 +579,13 @@ static void imc_select_hkl( struct imc *imc, HKL hkl ) else if (!(imc->ime = ime_acquire( hkl ))) WARN( "Failed to acquire IME for HKL %p\n", hkl ); else + { + if (!(imc->IMC.hPrivate = ImmCreateIMCC( imc->ime->info.dwPrivateDataSize ))) + WARN( "Failed to allocate IME private data for IMC %p\n", imc ); + imc->IMC.fdwConversion = imc->ime->info.fdwConversionCaps; + imc->IMC.fdwSentence = imc->ime->info.fdwSentenceCaps; imc->ime->pImeSelect( imc->handle, TRUE ); + } } static BOOL CALLBACK enum_activate_layout( HIMC himc, LPARAM lparam ) @@ -872,15 +879,7 @@ static struct imc *create_input_context( HIMC default_imc ) LPCANDIDATEINFO ci; int i; - new_context = calloc( 1, sizeof(*new_context) ); - - /* Load the IME */ - if (!(new_context->ime = ime_acquire( GetKeyboardLayout( 0 ) ))) - { - TRACE("IME dll could not be loaded\n"); - free( new_context ); - return 0; - } + if (!(new_context = calloc( 1, sizeof(*new_context) ))) return NULL; /* the HIMCCs are never NULL */ new_context->IMC.hCompStr = ImmCreateBlankCompStr(); @@ -899,12 +898,6 @@ static struct imc *create_input_context( HIMC default_imc ) for (i = 0; i < ARRAY_SIZE(new_context->IMC.cfCandForm); i++) new_context->IMC.cfCandForm[i].dwIndex = ~0u; - /* Initialize the IME Private */ - new_context->IMC.hPrivate = ImmCreateIMCC( new_context->ime->info.dwPrivateDataSize ); - - new_context->IMC.fdwConversion = new_context->ime->info.fdwConversionCaps; - new_context->IMC.fdwSentence = new_context->ime->info.fdwSentenceCaps; - if (!default_imc) new_context->handle = NtUserCreateInputContext((UINT_PTR)new_context); else if (NtUserUpdateInputContext(default_imc, NtUserInputContextClientPtr, (UINT_PTR)new_context)) @@ -915,12 +908,7 @@ static struct imc *create_input_context( HIMC default_imc ) return 0; } - if (!new_context->ime->pImeSelect( new_context->handle, TRUE )) - { - TRACE("Selection of IME failed\n"); - IMM_DestroyContext(new_context); - return 0; - } + imc_select_hkl( new_context, GetKeyboardLayout( 0 ) ); SendMessageW( GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)new_context->ime ); TRACE("Created context %p\n", new_context); From 50d3bcf578d5132534f258d6205da1b62e504f51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 28 Mar 2023 09:27:28 +0200 Subject: [PATCH 1768/2777] imm32: Call ImeSelect from ImmLockIMC with current IME. (cherry picked from commit 61219f1b8be1f827b99dd2ffc5c5046b751d664c) --- dlls/imm32/imm.c | 15 +++++++++------ dlls/imm32/tests/imm32.c | 20 ++++++++++++++------ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 04bfc461658..2c3af063ac5 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2829,14 +2829,17 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITE /*********************************************************************** * ImmLockIMC(IMM32.@) */ -LPINPUTCONTEXT WINAPI ImmLockIMC(HIMC hIMC) +INPUTCONTEXT *WINAPI ImmLockIMC( HIMC himc ) { - struct imc *data = get_imc_data( hIMC ); + struct imc *imc = get_imc_data( himc ); - if (!data) - return NULL; - data->dwLock++; - return &data->IMC; + TRACE( "himc %p\n", himc ); + + if (!imc) return NULL; + imc->dwLock++; + + imc_select_hkl( imc, GetKeyboardLayout( 0 ) ); + return &imc->IMC; } /*********************************************************************** diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 5dde6cd1b1f..88311a16c96 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3790,7 +3790,6 @@ static void test_ImmActivateLayout(void) { .hkl = expect_ime, .himc = default_himc, .func = IME_SELECT, .select = 1, - .todo = TRUE, }, {0}, }; @@ -3808,6 +3807,15 @@ static void test_ImmActivateLayout(void) }, {0}, }; + const struct ime_call activate_with_window_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_SELECT, .select = 1, + .todo = TRUE, + }, + {0}, + }; HKL hkl, old_hkl = GetKeyboardLayout( 0 ); UINT ret; @@ -3835,7 +3843,6 @@ static void test_ImmActivateLayout(void) SET_EXPECT( ImeInquire ); ok_ret( 1, ImmActivateLayout( hkl ) ); ok_seq( activate_seq ); - todo_wine CHECK_CALLED( ImeInquire ); ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); @@ -3843,8 +3850,10 @@ static void test_ImmActivateLayout(void) ok_ret( 1, ImmActivateLayout( hkl ) ); ok_seq( empty_sequence ); + todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ ok_ret( 1, ImmActivateLayout( old_hkl ) ); ok_seq( deactivate_seq ); + todo_ImeDestroy = FALSE; ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); @@ -3857,7 +3866,6 @@ static void test_ImmActivateLayout(void) SET_EXPECT( ImeDestroy ); ret = ImmFreeLayout( hkl ); ok( ret, "ImmFreeLayout returned %u\n", ret ); - todo_wine CHECK_CALLED( ImeDestroy ); ok_seq( empty_sequence ); @@ -3875,7 +3883,7 @@ static void test_ImmActivateLayout(void) ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); todo_wine CHECK_CALLED( ImeInquire ); - ok_seq( activate_seq ); + ok_seq( activate_with_window_seq ); ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); @@ -3911,12 +3919,12 @@ static void test_ImmCreateInputContext(void) { .hkl = expect_ime, .himc = default_himc, .func = IME_SELECT, .select = 1, - .todo = TRUE, .flaky_himc = TRUE, + .flaky_himc = TRUE, }, { .hkl = expect_ime, .himc = 0/*himc[0]*/, .func = IME_SELECT, .select = 1, - .todo = TRUE, .flaky_himc = TRUE, + .flaky_himc = TRUE, }, {0}, }; From fc35326f86a9eb820062ebb80a032c47da1ba994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 29 Mar 2023 14:18:38 +0200 Subject: [PATCH 1769/2777] imm32/tests: Add explicit ImmLoadIME / ImmFreeLayout calls. (cherry picked from commit 4b04d357739f261457316d55b79ecbcff9c0be84) --- dlls/imm32/tests/imm32.c | 45 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 88311a16c96..ef4b77d0573 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2973,7 +2973,7 @@ static HKL ime_install(void) return hkl; } -static void ime_cleanup( HKL hkl ) +static void ime_cleanup( HKL hkl, BOOL free ) { HMODULE module = GetModuleHandleW( L"winetest_ime.dll" ); WCHAR buffer[MAX_PATH], value[MAX_PATH]; @@ -2984,6 +2984,8 @@ static void ime_cleanup( HKL hkl ) todo_wine ok( ret, "UnloadKeyboardLayout failed, error %lu\n", GetLastError() ); + if (free) ok_ret( 1, ImmFreeLayout( hkl ) ); + swprintf( buffer, ARRAY_SIZE(buffer), L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08x", hkl ); ret = RegDeleteKeyW( HKEY_LOCAL_MACHINE, buffer ); ok( !ret, "RegDeleteKeyW returned %#lx, error %lu\n", ret, GetLastError() ); @@ -3086,7 +3088,7 @@ static void test_ImmInstallIME(void) ret = ImmFreeLayout( hkl ); ok( ret, "ImmFreeLayout returned %#x\n", ret ); - ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE ); ime_info.fdwProperty = 0; @@ -3112,7 +3114,7 @@ static void test_ImmInstallIME(void) ret = ImmFreeLayout( hkl ); ok( ret, "ImmFreeLayout returned %#x\n", ret ); - ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE ); cleanup: SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); @@ -3151,7 +3153,7 @@ static void test_ImmIsIME(void) todo_ImeInquire = FALSE; todo_ImeDestroy = FALSE; - ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE ); cleanup: SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); @@ -3246,7 +3248,7 @@ static void test_ImmGetProperty(void) todo_ImeDestroy = FALSE; called_ImeDestroy = FALSE; - ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE ); cleanup: SET_ENABLE( ImeInquire, FALSE ); @@ -3319,7 +3321,7 @@ static void test_ImmGetDescription(void) ok( ret == 12, "ImmGetDescriptionA returned %lu\n", ret ); ok( !strcmp( bufferA, "WineTest IME" ), "got bufferA %s\n", debugstr_a(bufferA) ); - ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE ); cleanup: SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); @@ -3398,7 +3400,7 @@ static void test_ImmGetIMEFileName(void) ok( ret == 12, "ImmGetIMEFileNameA returned %lu\n", ret ); ok( !strcmp( bufferA, expectA ), "got bufferA %s\n", debugstr_a(bufferA) ); - ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE ); cleanup: SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); @@ -3506,7 +3508,7 @@ static void test_ImmEscape( BOOL unicode ) winetest_pop_context(); } - ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE ); cleanup: SET_ENABLE( ImeEscape, FALSE ); @@ -3574,7 +3576,7 @@ static void test_ImmEnumRegisterWord( BOOL unicode ) ok_ret( 0xdeadbeef, ImmEnumRegisterWordA( hkl, enum_register_wordA, "Reading", 0xdeadbeef, "String", NULL ) ); CHECK_CALLED( ImeEnumRegisterWord ); - ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE ); cleanup: SET_ENABLE( ImeEnumRegisterWord, FALSE ); @@ -3636,7 +3638,7 @@ static void test_ImmRegisterWord( BOOL unicode ) ok_ret( 0, ImmRegisterWordA( hkl, NULL, 0, "String" ) ); CHECK_CALLED( ImeRegisterWord ); - ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE ); cleanup: SET_ENABLE( ImeRegisterWord, FALSE ); @@ -3713,7 +3715,7 @@ static void test_ImmGetRegisterWordStyle( BOOL unicode ) } CHECK_CALLED( ImeGetRegisterWordStyle ); - ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE ); cleanup: SET_ENABLE( ImeGetRegisterWordStyle, FALSE ); @@ -3775,7 +3777,7 @@ static void test_ImmUnregisterWord( BOOL unicode ) ok_ret( 0, ImmUnregisterWordA( hkl, NULL, 0, "String" ) ); CHECK_CALLED( ImeUnregisterWord ); - ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE ); cleanup: SET_ENABLE( ImeUnregisterWord, FALSE ); @@ -3844,6 +3846,7 @@ static void test_ImmActivateLayout(void) ok_ret( 1, ImmActivateLayout( hkl ) ); ok_seq( activate_seq ); CHECK_CALLED( ImeInquire ); + ok_ret( 1, ImmLoadIME( hkl ) ); ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); @@ -3857,7 +3860,7 @@ static void test_ImmActivateLayout(void) ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); - ime_cleanup( hkl ); + ime_cleanup( hkl, FALSE ); ok_seq( empty_sequence ); @@ -3884,6 +3887,9 @@ static void test_ImmActivateLayout(void) todo_wine CHECK_CALLED( ImeInquire ); ok_seq( activate_with_window_seq ); + todo_ImeInquire = TRUE; + ok_ret( 1, ImmLoadIME( hkl ) ); + todo_ImeInquire = FALSE; ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); @@ -3892,15 +3898,8 @@ static void test_ImmActivateLayout(void) ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); - ime_cleanup( hkl ); - ok_seq( empty_sequence ); - - /* ImmActivateLayout leaks the IME, we need to free it manually */ - SET_EXPECT( ImeDestroy ); - ret = ImmFreeLayout( hkl ); - ok( ret, "ImmFreeLayout returned %u\n", ret ); - todo_wine + ime_cleanup( hkl, TRUE ); CHECK_CALLED( ImeDestroy ); ok_seq( empty_sequence ); @@ -4007,6 +4006,7 @@ static void test_ImmCreateInputContext(void) if (!(hkl = ime_install())) goto cleanup; + ok_ret( 1, ImmLoadIME( hkl ) ); /* Activating the layout calls ImeSelect 1 on existing HIMC */ @@ -4055,8 +4055,7 @@ static void test_ImmCreateInputContext(void) ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); - ok_ret( 1, ImmFreeLayout( hkl ) ); - ime_cleanup( hkl ); + ime_cleanup( hkl, TRUE ); ok_seq( empty_sequence ); cleanup: From fe910657b03f091d28a79e0b850e85dbe92d3951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 28 Mar 2023 10:12:04 +0200 Subject: [PATCH 1770/2777] imm32/tests: Ignore expected calls marked with todo. (cherry picked from commit 5a6ed25f6c29f0ee98c44185f4602836748ec4d0) --- dlls/imm32/tests/imm32.c | 42 +++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index ef4b77d0573..c903b9ca115 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2519,7 +2519,7 @@ static struct ime_call ime_calls[1024]; static ULONG ime_call_count; #define ok_call( a, b ) ok_call_( __FILE__, __LINE__, a, b ) -static void ok_call_( const char *file, int line, const struct ime_call *expected, const struct ime_call *received ) +static int ok_call_( const char *file, int line, const struct ime_call *expected, const struct ime_call *received ) { int ret; @@ -2546,13 +2546,13 @@ static void ok_call_( const char *file, int line, const struct ime_call *expecte case IME_SELECT: todo_wine_if( expected->todo ) ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SELECT select %u\n", received->hkl, received->himc, received->select ); - return; + return ret; case IME_NOTIFY: todo_wine_if( expected->todo ) ok_(file, line)( !ret, "got hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n", received->hkl, received->himc, received->notify.action, received->notify.index, received->notify.value ); - return; + return ret; } switch (expected->func) @@ -2568,21 +2568,28 @@ static void ok_call_( const char *file, int line, const struct ime_call *expecte expected->notify.value ); break; } + + return 0; } #define ok_seq( a ) ok_seq_( __FILE__, __LINE__, a, #a ) static void ok_seq_( const char *file, int line, const struct ime_call *expected, const char *context ) { const struct ime_call *received = ime_calls; - UINT i = 0; + UINT i = 0, ret; while (expected->func || received->func) { winetest_push_context( "%u%s%s", i++, !expected->func ? " (spurious)" : "", !received->func ? " (missing)" : "" ); - ok_call_( file, line, expected, received ); - if (expected->func) expected++; - if (received->func) received++; + ret = ok_call_( file, line, expected, received ); + if (ret && expected->todo && !strcmp( winetest_platform, "wine" )) + expected++; + else + { + if (expected->func) expected++; + if (received->func) received++; + } winetest_pop_context(); } @@ -3805,7 +3812,6 @@ static void test_ImmActivateLayout(void) { .hkl = default_hkl, .himc = default_himc, .func = IME_SELECT, .select = 0, - .todo = TRUE, }, {0}, }; @@ -3818,6 +3824,20 @@ static void test_ImmActivateLayout(void) }, {0}, }; + const struct ime_call deactivate_with_window_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_NOTIFY, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0}, + .todo = TRUE, + }, + { + .hkl = default_hkl, .himc = default_himc, + .func = IME_SELECT, .select = 0, + .todo = TRUE, + }, + {0}, + }; HKL hkl, old_hkl = GetKeyboardLayout( 0 ); UINT ret; @@ -3894,7 +3914,7 @@ static void test_ImmActivateLayout(void) ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); - ok_seq( deactivate_seq ); + ok_seq( deactivate_with_window_seq ); ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); @@ -3959,12 +3979,12 @@ static void test_ImmCreateInputContext(void) { .hkl = default_hkl, .himc = default_himc, .func = IME_SELECT, .select = 0, - .todo = TRUE, .flaky_himc = TRUE, + .flaky_himc = TRUE, }, { .hkl = default_hkl, .himc = 0/*himc[0]*/, .func = IME_SELECT, .select = 0, - .todo = TRUE, .flaky_himc = TRUE, + .flaky_himc = TRUE, }, {0}, }; From 0a95dfdacb10659647b6f8a85a5a12fb1adf43d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 28 Mar 2023 12:55:44 +0200 Subject: [PATCH 1771/2777] imm32: Cleanup ImmProcessKey variables and traces. (cherry picked from commit 3a07b09079fff7986eb68108eb09a234d50e1e98) --- dlls/imm32/imm.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 2c3af063ac5..e3c7b3d579b 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3025,27 +3025,24 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD * ImmProcessKey(IMM32.@) * ( Undocumented, called from user32.dll ) */ -BOOL WINAPI ImmProcessKey(HWND hwnd, HKL hKL, UINT vKey, LPARAM lKeyData, DWORD unknown) +BOOL WINAPI ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM lparam, DWORD unknown ) { - struct imc *data; - HIMC imc = ImmGetContext(hwnd); + struct imc *imc; BYTE state[256]; + BOOL ret; - TRACE("%p %p %x %x %lx\n",hwnd, hKL, vKey, (UINT)lKeyData, unknown); + TRACE( "hwnd %p, hkl %p, vkey %#x, lparam %#Ix, unknown %#lx\n", hwnd, hkl, vkey, lparam, unknown ); - if (!(data = get_imc_data( imc ))) return FALSE; - imc_select_hkl( data, hKL ); - if (!data->ime) return FALSE; + if (!(imc = get_imc_data( ImmGetContext( hwnd ) ))) return FALSE; + imc_select_hkl( imc, hkl ); + if (!imc->ime) return FALSE; - GetKeyboardState(state); - if (data->ime->pImeProcessKey( imc, vKey, lKeyData, state )) - { - data->lastVK = vKey; - return TRUE; - } + GetKeyboardState( state ); - data->lastVK = VK_PROCESSKEY; - return FALSE; + ret = imc->ime->pImeProcessKey( imc->handle, vkey, lparam, state ); + imc->lastVK = ret ? vkey : VK_PROCESSKEY; + + return ret; } /*********************************************************************** From 9916a18da201000076014a432cf818ef251d2f04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 28 Mar 2023 12:56:53 +0200 Subject: [PATCH 1772/2777] imm32: Ignore ImmProcessKey if hkl isn't the current layout. (cherry picked from commit bda3ee0bd5b5083c34aa5d74ccc4db6f1cc03fdc) --- dlls/imm32/imm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index e3c7b3d579b..447fbded41d 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3033,6 +3033,7 @@ BOOL WINAPI ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM lparam, DWORD u TRACE( "hwnd %p, hkl %p, vkey %#x, lparam %#Ix, unknown %#lx\n", hwnd, hkl, vkey, lparam, unknown ); + if (hkl != GetKeyboardLayout( 0 )) return FALSE; if (!(imc = get_imc_data( ImmGetContext( hwnd ) ))) return FALSE; imc_select_hkl( imc, hkl ); if (!imc->ime) return FALSE; From ca03c7d9cfea9bbc8130957d9d64daeda1ee6b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 28 Mar 2023 10:26:14 +0200 Subject: [PATCH 1773/2777] imm32/tests: Test ImmProcessKey with the installed IME. (cherry picked from commit 9117ce4185146a5edd47467d370b3e4dfa588191) --- dlls/imm32/tests/imm32.c | 84 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index c903b9ca115..58bdeda848e 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2491,6 +2491,7 @@ enum ime_function { IME_SELECT = 1, IME_NOTIFY, + IME_PROCESS_KEY, }; struct ime_call @@ -2508,6 +2509,11 @@ struct ime_call int index; int value; } notify; + struct + { + WORD vkey; + LPARAM key_data; + } process_key; }; BOOL todo; @@ -2538,6 +2544,10 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected if ((ret = expected->notify.index - received->notify.index)) goto done; if ((ret = expected->notify.value - received->notify.value)) goto done; break; + case IME_PROCESS_KEY: + if ((ret = expected->process_key.vkey - received->process_key.vkey)) goto done; + if ((ret = expected->process_key.key_data - received->process_key.key_data)) goto done; + break; } done: @@ -2553,6 +2563,11 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected received->hkl, received->himc, received->notify.action, received->notify.index, received->notify.value ); return ret; + case IME_PROCESS_KEY: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "got hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, key_data %#Ix\n", + received->hkl, received->himc, received->process_key.vkey, received->process_key.key_data ); + return ret; } switch (expected->func) @@ -2567,6 +2582,11 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected expected->hkl, expected->himc, expected->notify.action, expected->notify.index, expected->notify.value ); break; + case IME_PROCESS_KEY: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, key_data %#Ix\n", + expected->hkl, expected->himc, expected->process_key.vkey, expected->process_key.key_data ); + break; } return 0; @@ -2764,11 +2784,15 @@ static BOOL WINAPI ime_ImeInquire( IMEINFO *info, WCHAR *ui_class, DWORD flags ) static BOOL WINAPI ime_ImeProcessKey( HIMC himc, UINT vkey, LPARAM key_data, BYTE *key_state ) { + struct ime_call call = + { + .hkl = GetKeyboardLayout( 0 ), .himc = himc, + .func = IME_PROCESS_KEY, .process_key = {.vkey = vkey, .key_data = key_data} + }; ime_trace( "himc %p, vkey %u, key_data %#Ix, key_state %p\n", himc, vkey, key_data, key_state ); - ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); - ok( 0, "unexpected call\n" ); - return FALSE; + ime_calls[ime_call_count++] = call; + return TRUE; } static BOOL WINAPI ime_ImeRegisterWord( const WCHAR *reading, DWORD style, const WCHAR *string ) @@ -3792,6 +3816,59 @@ static void test_ImmUnregisterWord( BOOL unicode ) winetest_pop_context(); } +static void test_ImmProcessKey(void) +{ + const struct ime_call process_key_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_PROCESS_KEY, .process_key = {.vkey = 'A', .key_data = 0}, + }, + {0}, + }; + HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + UINT_PTR ret; + + hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + + ok_ret( 0, ImmProcessKey( hwnd, old_hkl, 'A', 0, 0 ) ); + ok_seq( empty_sequence ); + + ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; + + if (!(hkl = ime_install())) goto cleanup; + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + ok_ret( 0, ImmProcessKey( 0, hkl, 'A', 0, 0 ) ); + ok_seq( empty_sequence ); + + ret = ImmProcessKey( hwnd, hkl, 'A', 0, 0 ); + todo_wine + ok_ret( 2, ret ); + ok_seq( process_key_seq ); + + ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + ok_ret( 0, ImmProcessKey( hwnd, old_hkl, 'A', 0, 0 ) ); + todo_wine + ok_seq( empty_sequence ); + ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + + ime_cleanup( hkl, TRUE ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + +cleanup: + ok_ret( 1, DestroyWindow( hwnd ) ); +} + static void test_ImmActivateLayout(void) { const struct ime_call activate_seq[] = @@ -4118,6 +4195,7 @@ START_TEST(imm32) test_ImmActivateLayout(); test_ImmCreateInputContext(); + test_ImmProcessKey(); if (init()) { From 42a89983bb91e38cd6a5d5defae871e2b6542d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 29 Mar 2023 15:06:51 +0200 Subject: [PATCH 1774/2777] imm32/tests: Test IME UI creation with the installed IME. (cherry picked from commit 42f3cf1bf3a48ce62b8f4241348f3139fbeeff76) --- dlls/imm32/tests/imm32.c | 176 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 171 insertions(+), 5 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 58bdeda848e..079338a044f 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -118,6 +118,17 @@ extern BOOL WINAPI ImmActivateLayout(HKL); DEFINE_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE); DEFINE_EXPECT(WM_IME_SETCONTEXT_ACTIVATE); +static void process_messages(void) +{ + MSG msg; + + while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageA( &msg ); + } +} + /* * msgspy - record and analyse message traces sent to a certain window */ @@ -2492,6 +2503,7 @@ enum ime_function IME_SELECT = 1, IME_NOTIFY, IME_PROCESS_KEY, + MSG_IME_UI, }; struct ime_call @@ -2514,9 +2526,16 @@ struct ime_call WORD vkey; LPARAM key_data; } process_key; + struct + { + UINT msg; + WPARAM wparam; + LPARAM lparam; + } message; }; BOOL todo; + BOOL broken; BOOL flaky_himc; }; @@ -2548,9 +2567,16 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected if ((ret = expected->process_key.vkey - received->process_key.vkey)) goto done; if ((ret = expected->process_key.key_data - received->process_key.key_data)) goto done; break; + case MSG_IME_UI: + if ((ret = expected->message.msg - received->message.msg)) goto done; + if ((ret = (expected->message.wparam - received->message.wparam))) goto done; + if ((ret = (expected->message.lparam - received->message.lparam))) goto done; + break; } done: + if (ret && broken( expected->broken )) return ret; + switch (received->func) { case IME_SELECT: @@ -2568,6 +2594,11 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected ok_(file, line)( !ret, "got hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, key_data %#Ix\n", received->hkl, received->himc, received->process_key.vkey, received->process_key.key_data ); return ret; + case MSG_IME_UI: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, + received->himc, received->message.msg, received->message.wparam, received->message.lparam ); + return ret; } switch (expected->func) @@ -2587,6 +2618,11 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected ok_(file, line)( !ret, "hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, key_data %#Ix\n", expected->hkl, expected->himc, expected->process_key.vkey, expected->process_key.key_data ); break; + case MSG_IME_UI: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, + expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); + break; } return 0; @@ -2605,6 +2641,8 @@ static void ok_seq_( const char *file, int line, const struct ime_call *expected ret = ok_call_( file, line, expected, received ); if (ret && expected->todo && !strcmp( winetest_platform, "wine" )) expected++; + else if (ret && broken(expected->broken)) + expected++; else { if (expected->func) expected++; @@ -2617,9 +2655,46 @@ static void ok_seq_( const char *file, int line, const struct ime_call *expected ime_call_count = 0; } +static BOOL ignore_message( UINT msg ) +{ + switch (msg) + { + case WM_IME_STARTCOMPOSITION: + case WM_IME_ENDCOMPOSITION: + case WM_IME_COMPOSITION: + case WM_IME_SETCONTEXT: + case WM_IME_NOTIFY: + case WM_IME_CONTROL: + case WM_IME_COMPOSITIONFULL: + case WM_IME_SELECT: + case WM_IME_CHAR: + case 0x287: + case WM_IME_REQUEST: + case WM_IME_KEYDOWN: + case WM_IME_KEYUP: + return FALSE; + default: + return TRUE; + } +} + static LRESULT CALLBACK ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { + struct ime_call call = + { + .hkl = GetKeyboardLayout( 0 ), .himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ), + .func = MSG_IME_UI, .message = {.msg = msg, .wparam = wparam, .lparam = lparam} + }; + LONG_PTR ptr; + ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + + if (ignore_message( msg )) return DefWindowProcW( hwnd, msg, wparam, lparam ); + + ptr = GetWindowLongPtrW( hwnd, IMMGWL_PRIVATE ); + ok( !ptr, "got IMMGWL_PRIVATE %#Ix\n", ptr ); + + ime_calls[ime_call_count++] = call; return DefWindowProcW( hwnd, msg, wparam, lparam ); } @@ -2849,7 +2924,6 @@ static UINT WINAPI ime_ImeToAsciiEx( UINT vkey, UINT scan_code, BYTE *key_state, { ime_trace( "vkey %u, scan_code %u, key_state %p, msgs %p, state %u, himc %p\n", vkey, scan_code, key_state, msgs, state, himc ); - ok( 0, "unexpected call\n" ); return 0; } @@ -3832,6 +3906,7 @@ static void test_ImmProcessKey(void) hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + process_messages(); ok_ret( 0, ImmProcessKey( hwnd, old_hkl, 'A', 0, 0 ) ); ok_seq( empty_sequence ); @@ -3842,6 +3917,7 @@ static void test_ImmProcessKey(void) ok_ret( 1, ImmActivateLayout( hkl ) ); ok_ret( 1, ImmLoadIME( hkl ) ); + process_messages(); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; @@ -3862,6 +3938,7 @@ static void test_ImmProcessKey(void) ok_ret( 1, ImmActivateLayout( old_hkl ) ); ime_cleanup( hkl, TRUE ); + process_messages(); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; @@ -3892,30 +3969,76 @@ static void test_ImmActivateLayout(void) }, {0}, }; - const struct ime_call activate_with_window_seq[] = + struct ime_call activate_with_window_seq[] = { { .hkl = expect_ime, .himc = default_himc, .func = IME_SELECT, .select = 1, + .todo = TRUE, .flaky_himc = TRUE, + }, + { + .hkl = expect_ime, .himc = 0/*himc*/, + .func = IME_SELECT, .select = 1, + .todo = TRUE, .flaky_himc = TRUE, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_SELECT, .wparam = 1, .lparam = (LPARAM)expect_ime}, + .todo = TRUE, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_OPENSTATUSWINDOW}, + .todo = TRUE, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE}, + .todo = TRUE, .broken = (default_hkl == (HKL)0x04120412), + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETSENTENCEMODE}, .todo = TRUE, }, {0}, }; - const struct ime_call deactivate_with_window_seq[] = + struct ime_call deactivate_with_window_seq[] = { { .hkl = expect_ime, .himc = default_himc, .func = IME_NOTIFY, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0}, + .todo = TRUE, .flaky_himc = TRUE, + }, + { + .hkl = expect_ime, .himc = 0/*himc*/, + .func = IME_NOTIFY, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0}, + .todo = TRUE, .flaky_himc = TRUE, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_CLOSESTATUSWINDOW}, + .todo = TRUE, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_SELECT, .wparam = 0, .lparam = (LPARAM)expect_ime}, .todo = TRUE, }, { .hkl = default_hkl, .himc = default_himc, .func = IME_SELECT, .select = 0, - .todo = TRUE, + .todo = TRUE, .flaky_himc = TRUE, + }, + { + .hkl = default_hkl, .himc = 0/*himc*/, + .func = IME_SELECT, .select = 0, + .todo = TRUE, .flaky_himc = TRUE, }, {0}, }; HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HIMC himc; UINT ret; SET_ENABLE( ImeInquire, TRUE ); @@ -3977,12 +4100,18 @@ static void test_ImmActivateLayout(void) hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + process_messages(); + ok_seq( empty_sequence ); + + himc = ImmCreateContext(); + ok( !!himc, "got himc %p\n", himc ); ok_seq( empty_sequence ); SET_EXPECT( ImeInquire ); ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); todo_wine CHECK_CALLED( ImeInquire ); + activate_with_window_seq[1].himc = himc; ok_seq( activate_with_window_seq ); todo_ImeInquire = TRUE; ok_ret( 1, ImmLoadIME( hkl ) ); @@ -3990,17 +4119,30 @@ static void test_ImmActivateLayout(void) ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + /* FIXME: ignore spurious VK_CONTROL ImeProcessKey / ImeToAsciiEx calls */ + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); + deactivate_with_window_seq[1].himc = himc; + deactivate_with_window_seq[5].himc = himc; ok_seq( deactivate_with_window_seq ); ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + ok_ret( 1, ImmDestroyContext( himc ) ); + ok_seq( empty_sequence ); + SET_EXPECT( ImeDestroy ); ime_cleanup( hkl, TRUE ); CHECK_CALLED( ImeDestroy ); ok_seq( empty_sequence ); ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; cleanup: @@ -4022,6 +4164,16 @@ static void test_ImmCreateInputContext(void) .func = IME_SELECT, .select = 1, .flaky_himc = TRUE, }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_SELECT, .wparam = 1, .lparam = (LPARAM)expect_ime}, + .todo = TRUE, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_OPENSTATUSWINDOW}, + .todo = TRUE, + }, {0}, }; struct ime_call select1_seq[] = @@ -4053,6 +4205,16 @@ static void test_ImmCreateInputContext(void) .func = IME_NOTIFY, .notify = {.action = NI_COMPOSITIONSTR, .index = CPS_CANCEL, .value = 0}, .todo = TRUE, .flaky_himc = TRUE, }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_CLOSESTATUSWINDOW}, + .todo = TRUE, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_SELECT, .wparam = 0, .lparam = (LPARAM)expect_ime}, + .todo = TRUE, + }, { .hkl = default_hkl, .himc = default_himc, .func = IME_SELECT, .select = 0, @@ -4088,6 +4250,7 @@ static void test_ImmCreateInputContext(void) hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + process_messages(); ctx = ImmLockIMC( default_himc ); ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); @@ -4147,7 +4310,7 @@ static void test_ImmCreateInputContext(void) ok_ret( 1, ImmActivateLayout( old_hkl ) ); deactivate_seq[1].himc = himc[0]; - deactivate_seq[3].himc = himc[0]; + deactivate_seq[5].himc = himc[0]; ok_seq( deactivate_seq ); ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); @@ -4158,6 +4321,9 @@ static void test_ImmCreateInputContext(void) cleanup: ok_ret( 1, ImmDestroyContext( himc[0] ) ); ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; ime_info.dwPrivateDataSize = 0; } From 47c7d8c76f2a9f46c36997cdb28820a59d22a4e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 29 Mar 2023 11:24:14 +0200 Subject: [PATCH 1775/2777] imm32/tests: Test IME UI window and IME window presence. (cherry picked from commit 43e22eaa76a443e3053868df1bd8c5d4130a9fde) --- dlls/imm32/tests/imm32.c | 46 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 079338a044f..305e152886d 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3946,6 +3946,37 @@ static void test_ImmProcessKey(void) ok_ret( 1, DestroyWindow( hwnd ) ); } +struct ime_windows +{ + HWND ime_hwnd; + HWND ime_ui_hwnd; +}; + +static BOOL CALLBACK enum_thread_ime_windows( HWND hwnd, LPARAM lparam ) +{ + struct ime_windows *params = (void *)lparam; + WCHAR buffer[256]; + UINT ret; + + ime_trace( "hwnd %p, lparam %#Ix\n", hwnd, lparam ); + + ret = RealGetWindowClassW( hwnd, buffer, ARRAY_SIZE(buffer) ); + ok( ret, "RealGetWindowClassW returned %#x\n", ret ); + + if (!wcscmp( buffer, L"IME" )) + { + ok( !params->ime_hwnd, "Found extra IME window %p\n", hwnd ); + params->ime_hwnd = hwnd; + } + if (!wcscmp( buffer, ime_ui_class.lpszClassName )) + { + ok( !params->ime_ui_hwnd, "Found extra IME UI window %p\n", hwnd ); + params->ime_ui_hwnd = hwnd; + } + + return TRUE; +} + static void test_ImmActivateLayout(void) { const struct ime_call activate_seq[] = @@ -4038,6 +4069,7 @@ static void test_ImmActivateLayout(void) {0}, }; HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + struct ime_windows ime_windows = {0}; HIMC himc; UINT ret; @@ -4134,10 +4166,22 @@ static void test_ImmActivateLayout(void) ok_ret( 1, ImmDestroyContext( himc ) ); ok_seq( empty_sequence ); + + ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); + ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + + ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) ); + ok( !!ime_windows.ime_hwnd, "missing IME window\n" ); + todo_wine ok( !!ime_windows.ime_ui_hwnd, "missing IME UI window\n" ); + todo_wine ok_ret( (UINT_PTR)ime_windows.ime_hwnd, (UINT_PTR)GetParent( ime_windows.ime_ui_hwnd ) ); + + ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); + ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + + SET_EXPECT( ImeDestroy ); ime_cleanup( hkl, TRUE ); CHECK_CALLED( ImeDestroy ); - ok_seq( empty_sequence ); ok_ret( 1, DestroyWindow( hwnd ) ); process_messages(); From 8edd50b83df56689bfe604540f1ddfcd59118369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Mar 2023 11:24:21 +0200 Subject: [PATCH 1776/2777] imm32: Update existing input contexts on layout change. (cherry picked from commit 0ddad3564f3260f53e5a50b615f6aa6ba27e032b) --- dlls/imm32/imm.c | 5 +++++ dlls/imm32/tests/imm32.c | 15 ++++++++++----- dlls/win32u/input.c | 8 +++++++- include/ntuser.h | 2 ++ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 447fbded41d..62fc855826b 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3152,6 +3152,11 @@ static LRESULT ime_internal_msg( WPARAM wparam, LPARAM lparam) ImmSetActiveContext(hwnd, himc, wparam == IME_INTERNAL_ACTIVATE); ImmReleaseContext(hwnd, himc); break; + case IME_INTERNAL_HKL_ACTIVATE: + ImmEnumInputContext( 0, enum_activate_layout, 0 ); + break; + case IME_INTERNAL_HKL_DEACTIVATE: + break; default: FIXME("wparam = %Ix\n", wparam); break; diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 305e152886d..8d3a4ce1529 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4005,12 +4005,12 @@ static void test_ImmActivateLayout(void) { .hkl = expect_ime, .himc = default_himc, .func = IME_SELECT, .select = 1, - .todo = TRUE, .flaky_himc = TRUE, + .flaky_himc = TRUE, }, { .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_SELECT, .select = 1, - .todo = TRUE, .flaky_himc = TRUE, + .flaky_himc = TRUE, }, { .hkl = expect_ime, .himc = default_himc, @@ -4059,12 +4059,12 @@ static void test_ImmActivateLayout(void) { .hkl = default_hkl, .himc = default_himc, .func = IME_SELECT, .select = 0, - .todo = TRUE, .flaky_himc = TRUE, + .flaky_himc = TRUE, }, { .hkl = default_hkl, .himc = 0/*himc*/, .func = IME_SELECT, .select = 0, - .todo = TRUE, .flaky_himc = TRUE, + .flaky_himc = TRUE, }, {0}, }; @@ -4141,7 +4141,6 @@ static void test_ImmActivateLayout(void) SET_EXPECT( ImeInquire ); ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); - todo_wine CHECK_CALLED( ImeInquire ); activate_with_window_seq[1].himc = himc; ok_seq( activate_with_window_seq ); @@ -4156,7 +4155,9 @@ static void test_ImmActivateLayout(void) memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; + todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); + todo_ImeDestroy = FALSE; deactivate_with_window_seq[1].himc = himc; deactivate_with_window_seq[5].himc = himc; ok_seq( deactivate_with_window_seq ); @@ -4167,7 +4168,9 @@ static void test_ImmActivateLayout(void) ok_seq( empty_sequence ); + todo_ImeInquire = TRUE; ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); + todo_ImeInquire = FALSE; ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) ); @@ -4175,7 +4178,9 @@ static void test_ImmActivateLayout(void) todo_wine ok( !!ime_windows.ime_ui_hwnd, "missing IME UI window\n" ); todo_wine ok_ret( (UINT_PTR)ime_windows.ime_hwnd, (UINT_PTR)GetParent( ime_windows.ime_ui_hwnd ) ); + todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); + todo_ImeDestroy = FALSE; ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index a983ac0b706..289c8c2fde4 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1221,12 +1221,14 @@ HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags ) return 0; old_layout = info->kbd_layout; - info->kbd_layout = layout; if (old_layout != layout) { + HWND ime_hwnd = get_default_ime_window( 0 ); const NLS_LOCALE_DATA *data; CHARSETINFO cs = {0}; + if (ime_hwnd) send_message( ime_hwnd, WM_IME_INTERNAL, IME_INTERNAL_HKL_DEACTIVATE, HandleToUlong(old_layout) ); + if (HIWORD(layout) & 0x8000) FIXME( "Aliased keyboard layout not yet implemented\n" ); else if (!(data = get_locale_data( HIWORD(layout) ))) @@ -1234,7 +1236,11 @@ HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags ) else translate_charset_info( ULongToPtr(data->idefaultansicodepage), &cs, TCI_SRCCODEPAGE ); + info->kbd_layout = layout; info->kbd_layout_id = 0; + + if (ime_hwnd) send_message( ime_hwnd, WM_IME_INTERNAL, IME_INTERNAL_HKL_ACTIVATE, HandleToUlong(layout) ); + if ((focus = get_focus()) && get_window_thread( focus, NULL ) == GetCurrentThreadId()) send_message( focus, WM_INPUTLANGCHANGE, cs.ciCharset, (LPARAM)layout ); } diff --git a/include/ntuser.h b/include/ntuser.h index 0771814c999..86267d3e244 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -487,6 +487,8 @@ enum wine_internal_message #define WM_IME_INTERNAL 0x287 #define IME_INTERNAL_ACTIVATE 0x17 #define IME_INTERNAL_DEACTIVATE 0x18 +#define IME_INTERNAL_HKL_ACTIVATE 0x19 +#define IME_INTERNAL_HKL_DEACTIVATE 0x20 #define WM_SYSTIMER 0x0118 From 0626d1c7bb2ded6c7ac8e0526d46347c4b467ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 27 Mar 2023 11:58:50 +0200 Subject: [PATCH 1777/2777] imm32: Keep the IME UI window on the default input context. (cherry picked from commit 2504a2d7bca47fc77bb523114d7b0b6e60213116) --- dlls/imm32/imm.c | 61 +++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 62fc855826b..d68930bade3 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -62,7 +62,6 @@ struct ime IMEINFO info; WCHAR ui_class[17]; - HWND ui_hwnd; BOOL (WINAPI *pImeInquire)(IMEINFO *, void *, DWORD); BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *); @@ -93,6 +92,8 @@ struct imc struct ime *ime; UINT lastVK; + + HWND ui_hwnd; /* IME UI window, on the default input context */ }; #define WINE_IMC_VALID_MAGIC 0x56434D49 @@ -569,6 +570,8 @@ static void imc_select_hkl( struct imc *imc, HKL hkl ) if (imc->ime) { if (imc->ime->hkl == hkl) return; + if (imc->ui_hwnd) DestroyWindow( imc->ui_hwnd ); + imc->ui_hwnd = NULL; imc->ime->pImeSelect( imc->handle, FALSE ); ime_release( imc->ime ); ImmDestroyIMCC( imc->IMC.hPrivate ); @@ -614,6 +617,7 @@ static BOOL free_input_context_data( HIMC hIMC ) TRACE( "Destroying %p\n", hIMC ); + if (data->ui_hwnd) DestroyWindow( data->ui_hwnd ); data->ime->pImeSelect( hIMC, FALSE ); SendMessageW( data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->ime ); @@ -648,7 +652,6 @@ static void IMM_FreeAllImmHkl(void) ime->pImeDestroy( 1 ); FreeLibrary( ime->module ); - if (ime->ui_hwnd) DestroyWindow( ime->ui_hwnd ); free( ime ); } } @@ -923,6 +926,29 @@ static struct imc *get_imc_data( HIMC handle ) return create_input_context(handle); } +static struct imc *default_input_context(void) +{ + UINT *himc = &NtUserGetThreadInfo()->default_imc; + if (!*himc) *himc = (UINT_PTR)NtUserCreateInputContext( 0 ); + return get_imc_data( (HIMC)(UINT_PTR)*himc ); +} + +static HWND get_ime_ui_window(void) +{ + struct imc *imc = default_input_context(); + + imc_select_hkl( imc, GetKeyboardLayout( 0 ) ); + if (!imc->ime) return 0; + + if (!imc->ui_hwnd) + { + imc->ui_hwnd = CreateWindowExW( WS_EX_TOOLWINDOW, imc->ime->ui_class, NULL, + WS_POPUP, 0, 0, 1, 1, 0, 0, imc->ime->module, 0 ); + SetWindowLongPtrW( imc->ui_hwnd, IMMGWL_IMC, (LONG_PTR)imc->handle ); + } + return imc->ui_hwnd; +} + /*********************************************************************** * ImmCreateContext (IMM32.@) */ @@ -2490,6 +2516,7 @@ BOOL WINAPI ImmSetCompositionWindow( { BOOL reshow = FALSE; struct imc *data = get_imc_data( hIMC ); + HWND ui_hwnd; TRACE("(%p, %p)\n", hIMC, lpCompForm); if (lpCompForm) @@ -2507,15 +2534,15 @@ BOOL WINAPI ImmSetCompositionWindow( data->IMC.cfCompForm = *lpCompForm; - if (IsWindowVisible( data->ime->ui_hwnd )) + if ((ui_hwnd = get_ime_ui_window()) && IsWindowVisible( ui_hwnd )) { reshow = TRUE; - ShowWindow( data->ime->ui_hwnd, SW_HIDE ); + ShowWindow( ui_hwnd, SW_HIDE ); } /* FIXME: this is a partial stub */ - if (reshow) ShowWindow( data->ime->ui_hwnd, SW_SHOWNOACTIVATE ); + if (ui_hwnd && reshow) ShowWindow( ui_hwnd, SW_SHOWNOACTIVATE ); ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0); return TRUE; @@ -2564,6 +2591,7 @@ BOOL WINAPI ImmSetConversionStatus( BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) { struct imc *data = get_imc_data( hIMC ); + HWND ui_hwnd; TRACE("%p %d\n", hIMC, fOpen); @@ -2575,14 +2603,7 @@ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; - if (data->ime->ui_hwnd == NULL) - { - /* create the ime window */ - data->ime->ui_hwnd = CreateWindowExW( WS_EX_TOOLWINDOW, data->ime->ui_class, NULL, - WS_POPUP, 0, 0, 1, 1, 0, 0, data->ime->module, 0 ); - SetWindowLongPtrW( data->ime->ui_hwnd, IMMGWL_IMC, (LONG_PTR)data ); - } - else if (fOpen) SetWindowLongPtrW( data->ime->ui_hwnd, IMMGWL_IMC, (LONG_PTR)data ); + if ((ui_hwnd = get_ime_ui_window())) SetWindowLongPtrW( ui_hwnd, IMMGWL_IMC, (LONG_PTR)data ); if (!fOpen != !data->IMC.fOpen) { @@ -3099,18 +3120,6 @@ BOOL WINAPI ImmDisableLegacyIME(void) return TRUE; } -static HWND get_ui_window(HKL hkl) -{ - struct ime *ime; - HWND hwnd; - - if (!(ime = ime_acquire( hkl ))) return 0; - hwnd = ime->ui_hwnd; - ime_release( ime ); - - return hwnd; -} - static BOOL is_ime_ui_msg(UINT msg) { switch (msg) @@ -3205,7 +3214,7 @@ LRESULT WINAPI __wine_ime_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lp if (is_ime_ui_msg(msg)) { - if ((ui_hwnd = get_ui_window(NtUserGetKeyboardLayout(0)))) + if ((ui_hwnd = get_ime_ui_window())) { if (ansi) return SendMessageA(ui_hwnd, msg, wparam, lparam); From dccf894f376a7253e9358e1b65e4f67a774728bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 28 Mar 2023 12:38:14 +0200 Subject: [PATCH 1778/2777] imm32: Re-create the IME UI window when IME changes. (cherry picked from commit bb2414fdb15a074786d463376d3bf5f17f73c459) --- dlls/imm32/imm.c | 5 ++++- dlls/imm32/tests/imm32.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index d68930bade3..ed903cb8d00 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3150,21 +3150,24 @@ static BOOL is_ime_ui_msg(UINT msg) static LRESULT ime_internal_msg( WPARAM wparam, LPARAM lparam) { - HWND hwnd = (HWND)lparam; + HWND hwnd; HIMC himc; switch (wparam) { case IME_INTERNAL_ACTIVATE: case IME_INTERNAL_DEACTIVATE: + hwnd = (HWND)lparam; himc = ImmGetContext(hwnd); ImmSetActiveContext(hwnd, himc, wparam == IME_INTERNAL_ACTIVATE); ImmReleaseContext(hwnd, himc); break; case IME_INTERNAL_HKL_ACTIVATE: ImmEnumInputContext( 0, enum_activate_layout, 0 ); + hwnd = get_ime_ui_window(); break; case IME_INTERNAL_HKL_DEACTIVATE: + hwnd = get_ime_ui_window(); break; default: FIXME("wparam = %Ix\n", wparam); diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 8d3a4ce1529..23cc9f4b906 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4175,7 +4175,7 @@ static void test_ImmActivateLayout(void) ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) ); ok( !!ime_windows.ime_hwnd, "missing IME window\n" ); - todo_wine ok( !!ime_windows.ime_ui_hwnd, "missing IME UI window\n" ); + ok( !!ime_windows.ime_ui_hwnd, "missing IME UI window\n" ); todo_wine ok_ret( (UINT_PTR)ime_windows.ime_hwnd, (UINT_PTR)GetParent( ime_windows.ime_ui_hwnd ) ); todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ From c04b99dc65fa60dc6b688836b9d35f3a72ce71cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 29 Mar 2023 11:39:41 +0200 Subject: [PATCH 1779/2777] imm32: Create the IME UI as child of the IME default window. (cherry picked from commit 585ac559b78da2a6d08b830b2f3e2310f50dc3e7) --- dlls/imm32/imm.c | 4 ++-- dlls/imm32/tests/imm32.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index ed903cb8d00..4cbdceeb9d9 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -942,8 +942,8 @@ static HWND get_ime_ui_window(void) if (!imc->ui_hwnd) { - imc->ui_hwnd = CreateWindowExW( WS_EX_TOOLWINDOW, imc->ime->ui_class, NULL, - WS_POPUP, 0, 0, 1, 1, 0, 0, imc->ime->module, 0 ); + imc->ui_hwnd = CreateWindowExW( WS_EX_TOOLWINDOW, imc->ime->ui_class, NULL, WS_POPUP, 0, 0, 1, 1, + ImmGetDefaultIMEWnd( 0 ), 0, imc->ime->module, 0 ); SetWindowLongPtrW( imc->ui_hwnd, IMMGWL_IMC, (LONG_PTR)imc->handle ); } return imc->ui_hwnd; diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 23cc9f4b906..dfc65cbec24 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4176,7 +4176,7 @@ static void test_ImmActivateLayout(void) ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) ); ok( !!ime_windows.ime_hwnd, "missing IME window\n" ); ok( !!ime_windows.ime_ui_hwnd, "missing IME UI window\n" ); - todo_wine ok_ret( (UINT_PTR)ime_windows.ime_hwnd, (UINT_PTR)GetParent( ime_windows.ime_ui_hwnd ) ); + ok_ret( (UINT_PTR)ime_windows.ime_hwnd, (UINT_PTR)GetParent( ime_windows.ime_ui_hwnd ) ); todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); From 72dcab9f50335fe778562e9ac4e2fb30b0f6d52d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 28 Mar 2023 12:01:54 +0200 Subject: [PATCH 1780/2777] imm32/tests: Test DefWindowProc with IME UI messages. (cherry picked from commit 5c98617e1b0c8d676c3149ac2b389c71bec934ce) --- dlls/imm32/tests/imm32.c | 89 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index dfc65cbec24..27e830c44ec 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2497,6 +2497,7 @@ static WCHAR ime_path[MAX_PATH]; static HIMC default_himc; static HKL default_hkl; static HKL expect_ime = (HKL)(int)0xe020047f; +static BOOL skip_DefWindowProc; enum ime_function { @@ -2695,6 +2696,7 @@ static LRESULT CALLBACK ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, ok( !ptr, "got IMMGWL_PRIVATE %#Ix\n", ptr ); ime_calls[ime_call_count++] = call; + if (skip_DefWindowProc) return 0; return DefWindowProcW( hwnd, msg, wparam, lparam ); } @@ -4377,6 +4379,92 @@ static void test_ImmCreateInputContext(void) ime_info.dwPrivateDataSize = 0; } +static void test_DefWindowProc(void) +{ + const struct ime_call start_composition_seq[] = + { + {.hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_STARTCOMPOSITION}}, + {0}, + }; + const struct ime_call end_composition_seq[] = + { + {.hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_ENDCOMPOSITION}}, + {0}, + }; + const struct ime_call composition_seq[] = + { + {.hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_COMPOSITION}}, + {0}, + }; + const struct ime_call set_context_seq[] = + { + {.hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_SETCONTEXT}}, + {0}, + }; + const struct ime_call notify_seq[] = + { + {.hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY}}, + {0}, + }; + HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + UINT_PTR ret; + + ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; + + if (!(hkl = ime_install())) return; + + hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + skip_DefWindowProc = TRUE; + ok_ret( 0, DefWindowProcW( hwnd, WM_IME_STARTCOMPOSITION, 0, 0 ) ); + ok_seq( start_composition_seq ); + ok_ret( 0, DefWindowProcW( hwnd, WM_IME_ENDCOMPOSITION, 0, 0 ) ); + ok_seq( end_composition_seq ); + ok_ret( 0, DefWindowProcW( hwnd, WM_IME_COMPOSITION, 0, 0 ) ); + ok_seq( composition_seq ); + ok_ret( 0, DefWindowProcW( hwnd, WM_IME_SETCONTEXT, 0, 0 ) ); + ok_seq( set_context_seq ); + ok_ret( 0, DefWindowProcW( hwnd, WM_IME_NOTIFY, 0, 0 ) ); + ok_seq( notify_seq ); + ok_ret( 0, DefWindowProcW( hwnd, WM_IME_CONTROL, 0, 0 ) ); + todo_wine ok_seq( empty_sequence ); + ok_ret( 0, DefWindowProcW( hwnd, WM_IME_COMPOSITIONFULL, 0, 0 ) ); + ok_seq( empty_sequence ); + ok_ret( 0, DefWindowProcW( hwnd, WM_IME_SELECT, 0, 0 ) ); + todo_wine ok_seq( empty_sequence ); + ok_ret( 0, DefWindowProcW( hwnd, WM_IME_CHAR, 0, 0 ) ); + ok_seq( empty_sequence ); + ok_ret( 0, DefWindowProcW( hwnd, 0x287, 0, 0 ) ); + ok_seq( empty_sequence ); + ok_ret( 0, DefWindowProcW( hwnd, WM_IME_REQUEST, 0, 0 ) ); + ok_seq( empty_sequence ); + ret = DefWindowProcW( hwnd, WM_IME_KEYDOWN, 0, 0 ); + todo_wine + ok_ret( 0, ret ); + ok_seq( empty_sequence ); + ret = DefWindowProcW( hwnd, WM_IME_KEYUP, 0, 0 ); + todo_wine + ok_ret( 0, ret ); + ok_seq( empty_sequence ); + skip_DefWindowProc = FALSE; + + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + + ime_cleanup( hkl, TRUE ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); @@ -4411,6 +4499,7 @@ START_TEST(imm32) test_ImmActivateLayout(); test_ImmCreateInputContext(); test_ImmProcessKey(); + test_DefWindowProc(); if (init()) { From 14003c5dc8de6c01fbc751c3000a02b517adff12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 28 Mar 2023 12:34:27 +0200 Subject: [PATCH 1781/2777] win32u: Ignore IME messages from IME UI windows in DefWindowProc. (cherry picked from commit 6fd3bd9b62f405a54db29dc5a72805063a6099ca) --- dlls/imm32/tests/imm32.c | 4 ---- dlls/win32u/defwnd.c | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 27e830c44ec..2b03b182328 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2497,7 +2497,6 @@ static WCHAR ime_path[MAX_PATH]; static HIMC default_himc; static HKL default_hkl; static HKL expect_ime = (HKL)(int)0xe020047f; -static BOOL skip_DefWindowProc; enum ime_function { @@ -2696,7 +2695,6 @@ static LRESULT CALLBACK ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, ok( !ptr, "got IMMGWL_PRIVATE %#Ix\n", ptr ); ime_calls[ime_call_count++] = call; - if (skip_DefWindowProc) return 0; return DefWindowProcW( hwnd, msg, wparam, lparam ); } @@ -4423,7 +4421,6 @@ static void test_DefWindowProc(void) memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; - skip_DefWindowProc = TRUE; ok_ret( 0, DefWindowProcW( hwnd, WM_IME_STARTCOMPOSITION, 0, 0 ) ); ok_seq( start_composition_seq ); ok_ret( 0, DefWindowProcW( hwnd, WM_IME_ENDCOMPOSITION, 0, 0 ) ); @@ -4454,7 +4451,6 @@ static void test_DefWindowProc(void) todo_wine ok_ret( 0, ret ); ok_seq( empty_sequence ); - skip_DefWindowProc = FALSE; ok_ret( 1, ImmActivateLayout( old_hkl ) ); ok_ret( 1, DestroyWindow( hwnd ) ); diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c index a7f1a11897a..51f92c38a85 100644 --- a/dlls/win32u/defwnd.c +++ b/dlls/win32u/defwnd.c @@ -2948,7 +2948,7 @@ LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, case WM_IME_CONTROL: { HWND ime_hwnd = get_default_ime_window( hwnd ); - if (ime_hwnd) + if (ime_hwnd && ime_hwnd != NtUserGetParent( hwnd )) result = NtUserMessageCall( ime_hwnd, msg, wparam, lparam, 0, NtUserSendMessage, ansi ); } From 88b103ebe811fd71ff644ea98dd9641f277c2a59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 28 Mar 2023 12:34:27 +0200 Subject: [PATCH 1782/2777] win32u: Ignore some IME messages in default_window_proc. (cherry picked from commit 3e2edac438205638f84171f5dd1bf77d9abaf26c) --- dlls/imm32/tests/imm32.c | 4 ++-- dlls/win32u/defwnd.c | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 2b03b182328..f1645983c77 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4432,11 +4432,11 @@ static void test_DefWindowProc(void) ok_ret( 0, DefWindowProcW( hwnd, WM_IME_NOTIFY, 0, 0 ) ); ok_seq( notify_seq ); ok_ret( 0, DefWindowProcW( hwnd, WM_IME_CONTROL, 0, 0 ) ); - todo_wine ok_seq( empty_sequence ); + ok_seq( empty_sequence ); ok_ret( 0, DefWindowProcW( hwnd, WM_IME_COMPOSITIONFULL, 0, 0 ) ); ok_seq( empty_sequence ); ok_ret( 0, DefWindowProcW( hwnd, WM_IME_SELECT, 0, 0 ) ); - todo_wine ok_seq( empty_sequence ); + ok_seq( empty_sequence ); ok_ret( 0, DefWindowProcW( hwnd, WM_IME_CHAR, 0, 0 ) ); ok_seq( empty_sequence ); ok_ret( 0, DefWindowProcW( hwnd, 0x287, 0, 0 ) ); diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c index 51f92c38a85..eb1c082ff20 100644 --- a/dlls/win32u/defwnd.c +++ b/dlls/win32u/defwnd.c @@ -2943,9 +2943,7 @@ LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, case WM_IME_COMPOSITION: case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION: - case WM_IME_SELECT: case WM_IME_NOTIFY: - case WM_IME_CONTROL: { HWND ime_hwnd = get_default_ime_window( hwnd ); if (ime_hwnd && ime_hwnd != NtUserGetParent( hwnd )) From 9dfaca970275f023a759415c1c89ac8c50f21e3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 30 Mar 2023 09:50:36 +0200 Subject: [PATCH 1783/2777] imm32: Pass the HIMC to the IME UI window IMMGWL_IMC. Instead of the imc pointer. (cherry picked from commit e64e4e7461c91039cb019a12880c0d6b31734772) --- dlls/imm32/imm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 4cbdceeb9d9..9b3dfc00eae 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2603,7 +2603,7 @@ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; - if ((ui_hwnd = get_ime_ui_window())) SetWindowLongPtrW( ui_hwnd, IMMGWL_IMC, (LONG_PTR)data ); + if ((ui_hwnd = get_ime_ui_window())) SetWindowLongPtrW( ui_hwnd, IMMGWL_IMC, (LONG_PTR)hIMC ); if (!fOpen != !data->IMC.fOpen) { From c1fd4d18816a80dc0500d508e72acaf6ff13d8d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 28 Mar 2023 12:43:59 +0200 Subject: [PATCH 1784/2777] imm32: Send WM_IME_SELECT messages when IME is activated. (cherry picked from commit 1b778dbea7350c6c2bf82850d54c7dae6839b214) --- dlls/imm32/imm.c | 8 ++++---- dlls/imm32/tests/imm32.c | 4 ---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 9b3dfc00eae..d73be37736a 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -619,7 +619,6 @@ static BOOL free_input_context_data( HIMC hIMC ) if (data->ui_hwnd) DestroyWindow( data->ui_hwnd ); data->ime->pImeSelect( hIMC, FALSE ); - SendMessageW( data->IMC.hWnd, WM_IME_SELECT, FALSE, (LPARAM)data->ime ); ImmDestroyIMCC( data->IMC.hCompStr ); ImmDestroyIMCC( data->IMC.hCandInfo ); @@ -912,7 +911,6 @@ static struct imc *create_input_context( HIMC default_imc ) } imc_select_hkl( new_context, GetKeyboardLayout( 0 ) ); - SendMessageW( GetFocus(), WM_IME_SELECT, TRUE, (LPARAM)new_context->ime ); TRACE("Created context %p\n", new_context); return new_context; @@ -3164,10 +3162,12 @@ static LRESULT ime_internal_msg( WPARAM wparam, LPARAM lparam) break; case IME_INTERNAL_HKL_ACTIVATE: ImmEnumInputContext( 0, enum_activate_layout, 0 ); - hwnd = get_ime_ui_window(); + if (!(hwnd = get_ime_ui_window())) break; + SendMessageW( hwnd, WM_IME_SELECT, TRUE, lparam ); break; case IME_INTERNAL_HKL_DEACTIVATE: - hwnd = get_ime_ui_window(); + if (!(hwnd = get_ime_ui_window())) break; + SendMessageW( hwnd, WM_IME_SELECT, FALSE, lparam ); break; default: FIXME("wparam = %Ix\n", wparam); diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index f1645983c77..4d9d213cb90 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4015,7 +4015,6 @@ static void test_ImmActivateLayout(void) { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_SELECT, .wparam = 1, .lparam = (LPARAM)expect_ime}, - .todo = TRUE, }, { .hkl = expect_ime, .himc = default_himc, @@ -4054,7 +4053,6 @@ static void test_ImmActivateLayout(void) { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_SELECT, .wparam = 0, .lparam = (LPARAM)expect_ime}, - .todo = TRUE, }, { .hkl = default_hkl, .himc = default_himc, @@ -4216,7 +4214,6 @@ static void test_ImmCreateInputContext(void) { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_SELECT, .wparam = 1, .lparam = (LPARAM)expect_ime}, - .todo = TRUE, }, { .hkl = expect_ime, .himc = default_himc, @@ -4262,7 +4259,6 @@ static void test_ImmCreateInputContext(void) { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_SELECT, .wparam = 0, .lparam = (LPARAM)expect_ime}, - .todo = TRUE, }, { .hkl = default_hkl, .himc = default_himc, From 9c037232ef1462080c3166864932bccdef68b6ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 28 Mar 2023 13:48:55 +0200 Subject: [PATCH 1785/2777] imm32: Select current IME on input contexts when needed. (cherry picked from commit 538d48e3f995b8840b50cc5999c726efdf69b512) --- dlls/imm32/imm.c | 172 +++++++++++++++++++++++---------------- dlls/imm32/tests/imm32.c | 3 - 2 files changed, 102 insertions(+), 73 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index d73be37736a..b2650fcfeb9 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -565,21 +565,27 @@ static void ime_release( struct ime *ime ) LeaveCriticalSection( &ime_cs ); } -static void imc_select_hkl( struct imc *imc, HKL hkl ) +static void imc_release_ime( struct imc *imc ) { + if (imc->ui_hwnd) DestroyWindow( imc->ui_hwnd ); + imc->ui_hwnd = NULL; + imc->ime->pImeSelect( imc->handle, FALSE ); + ime_release( imc->ime ); + imc->ime = NULL; + ImmDestroyIMCC( imc->IMC.hPrivate ); +} + +static struct ime *imc_select_ime( struct imc *imc ) +{ + HKL hkl = GetKeyboardLayout( 0 ); + if (imc->ime) { - if (imc->ime->hkl == hkl) return; - if (imc->ui_hwnd) DestroyWindow( imc->ui_hwnd ); - imc->ui_hwnd = NULL; - imc->ime->pImeSelect( imc->handle, FALSE ); - ime_release( imc->ime ); - ImmDestroyIMCC( imc->IMC.hPrivate ); + if (imc->ime->hkl == hkl) return imc->ime; + imc_release_ime( imc ); } - if (!hkl) - imc->ime = NULL; - else if (!(imc->ime = ime_acquire( hkl ))) + if (!(imc->ime = ime_acquire( hkl ))) WARN( "Failed to acquire IME for HKL %p\n", hkl ); else { @@ -589,6 +595,8 @@ static void imc_select_hkl( struct imc *imc, HKL hkl ) imc->IMC.fdwSentence = imc->ime->info.fdwSentenceCaps; imc->ime->pImeSelect( imc->handle, TRUE ); } + + return imc->ime; } static BOOL CALLBACK enum_activate_layout( HIMC himc, LPARAM lparam ) @@ -617,16 +625,13 @@ static BOOL free_input_context_data( HIMC hIMC ) TRACE( "Destroying %p\n", hIMC ); - if (data->ui_hwnd) DestroyWindow( data->ui_hwnd ); - data->ime->pImeSelect( hIMC, FALSE ); + if (data->ime) imc_release_ime( data ); ImmDestroyIMCC( data->IMC.hCompStr ); ImmDestroyIMCC( data->IMC.hCandInfo ); ImmDestroyIMCC( data->IMC.hGuideLine ); - ImmDestroyIMCC( data->IMC.hPrivate ); ImmDestroyIMCC( data->IMC.hMsgBuf ); - ime_release( data->ime ); free( data ); return TRUE; @@ -731,6 +736,7 @@ static HIMCC ImmCreateBlankCompStr(void) BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate) { struct imc *data = get_imc_data( himc ); + struct ime *ime; TRACE("(%p, %p, %x)\n", hwnd, himc, activate); @@ -742,7 +748,7 @@ BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate) if (data) { data->IMC.hWnd = activate ? hwnd : NULL; - data->ime->pImeSetActiveContext( himc, activate ); + if ((ime = imc_select_ime( data ))) ime->pImeSetActiveContext( himc, activate ); } if (IsWindow(hwnd)) @@ -910,8 +916,6 @@ static struct imc *create_input_context( HIMC default_imc ) return 0; } - imc_select_hkl( new_context, GetKeyboardLayout( 0 ) ); - TRACE("Created context %p\n", new_context); return new_context; } @@ -934,14 +938,14 @@ static struct imc *default_input_context(void) static HWND get_ime_ui_window(void) { struct imc *imc = default_input_context(); + struct ime *ime; - imc_select_hkl( imc, GetKeyboardLayout( 0 ) ); - if (!imc->ime) return 0; + if (!(ime = imc_select_ime( imc ))) return 0; if (!imc->ui_hwnd) { - imc->ui_hwnd = CreateWindowExW( WS_EX_TOOLWINDOW, imc->ime->ui_class, NULL, WS_POPUP, 0, 0, 1, 1, - ImmGetDefaultIMEWnd( 0 ), 0, imc->ime->module, 0 ); + imc->ui_hwnd = CreateWindowExW( WS_EX_TOOLWINDOW, ime->ui_class, NULL, WS_POPUP, 0, 0, 1, 1, + ImmGetDefaultIMEWnd( 0 ), 0, ime->module, 0 ); SetWindowLongPtrW( imc->ui_hwnd, IMMGWL_IMC, (LONG_PTR)imc->handle ); } return imc->ui_hwnd; @@ -1153,6 +1157,7 @@ DWORD WINAPI ImmGetCandidateListA( struct imc *data = get_imc_data( hIMC ); LPCANDIDATEINFO candinfo; LPCANDIDATELIST candlist; + struct ime *ime; DWORD ret = 0; TRACE("%p, %ld, %p, %ld\n", hIMC, dwIndex, lpCandList, dwBufLen); @@ -1168,7 +1173,9 @@ DWORD WINAPI ImmGetCandidateListA( if ( !candlist->dwSize || !candlist->dwCount ) goto done; - if (!ime_is_unicode( data->ime )) + if (!(ime = imc_select_ime( data ))) + ret = 0; + else if (!ime_is_unicode( ime )) { ret = candlist->dwSize; if ( lpCandList && dwBufLen >= ret ) @@ -1191,6 +1198,7 @@ DWORD WINAPI ImmGetCandidateListCountA( struct imc *data = get_imc_data( hIMC ); LPCANDIDATEINFO candinfo; DWORD ret, count; + struct ime *ime; TRACE("%p, %p\n", hIMC, lpdwListCount); @@ -1201,7 +1209,9 @@ DWORD WINAPI ImmGetCandidateListCountA( *lpdwListCount = count = candinfo->dwCount; - if (!ime_is_unicode( data->ime )) + if (!(ime = imc_select_ime( data ))) + ret = 0; + else if (!ime_is_unicode( ime )) ret = candinfo->dwSize; else { @@ -1223,6 +1233,7 @@ DWORD WINAPI ImmGetCandidateListCountW( struct imc *data = get_imc_data( hIMC ); LPCANDIDATEINFO candinfo; DWORD ret, count; + struct ime *ime; TRACE("%p, %p\n", hIMC, lpdwListCount); @@ -1233,7 +1244,9 @@ DWORD WINAPI ImmGetCandidateListCountW( *lpdwListCount = count = candinfo->dwCount; - if (ime_is_unicode( data->ime )) + if (!(ime = imc_select_ime( data ))) + ret = 0; + else if (ime_is_unicode( ime )) ret = candinfo->dwSize; else { @@ -1256,6 +1269,7 @@ DWORD WINAPI ImmGetCandidateListW( struct imc *data = get_imc_data( hIMC ); LPCANDIDATEINFO candinfo; LPCANDIDATELIST candlist; + struct ime *ime; DWORD ret = 0; TRACE("%p, %ld, %p, %ld\n", hIMC, dwIndex, lpCandList, dwBufLen); @@ -1271,7 +1285,9 @@ DWORD WINAPI ImmGetCandidateListW( if ( !candlist->dwSize || !candlist->dwCount ) goto done; - if (ime_is_unicode( data->ime )) + if (!(ime = imc_select_ime( data ))) + ret = 0; + else if (ime_is_unicode( ime )) { ret = candlist->dwSize; if ( lpCandList && dwBufLen >= ret ) @@ -1351,15 +1367,15 @@ BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) /* Source encoding is defined by context, source length is always given in respective characters. Destination buffer length is always in bytes. */ -static INT CopyCompStringIMEtoClient( const struct imc *data, const void *src, INT src_len, - void *dst, INT dst_len, BOOL unicode ) +static INT CopyCompStringIMEtoClient( BOOL src_unicode, const void *src, INT src_len, + void *dst, INT dst_len, BOOL dst_unicode ) { - int char_size = unicode ? sizeof(WCHAR) : sizeof(char); + int char_size = dst_unicode ? sizeof(WCHAR) : sizeof(char); INT ret; - if (ime_is_unicode( data->ime ) ^ unicode) + if (src_unicode ^ dst_unicode) { - if (unicode) + if (dst_unicode) ret = MultiByteToWideChar(CP_ACP, 0, src, src_len, dst, dst_len / sizeof(WCHAR)); else ret = WideCharToMultiByte(CP_ACP, 0, src, src_len, dst, dst_len, NULL, NULL); @@ -1381,8 +1397,8 @@ static INT CopyCompStringIMEtoClient( const struct imc *data, const void *src, I /* Composition string encoding is defined by context, returned attributes correspond to string, converted according to passed mode. String length is in characters, attributes are in byte arrays. */ -static INT CopyCompAttrIMEtoClient( const struct imc *data, const BYTE *src, INT src_len, const void *comp_string, - INT str_len, BYTE *dst, INT dst_len, BOOL unicode ) +static INT CopyCompAttrIMEtoClient( BOOL src_unicode, const BYTE *src, INT src_len, const void *comp_string, INT str_len, + BYTE *dst, INT dst_len, BOOL unicode ) { union { @@ -1394,7 +1410,7 @@ static INT CopyCompAttrIMEtoClient( const struct imc *data, const BYTE *src, INT string.str = comp_string; - if (ime_is_unicode( data->ime ) && !unicode) + if (src_unicode && !unicode) { rc = WideCharToMultiByte(CP_ACP, 0, string.strW, str_len, NULL, 0, NULL, NULL); if (dst_len) @@ -1421,7 +1437,7 @@ static INT CopyCompAttrIMEtoClient( const struct imc *data, const BYTE *src, INT rc = j; } } - else if (!ime_is_unicode( data->ime ) && unicode) + else if (!src_unicode && unicode) { rc = MultiByteToWideChar(CP_ACP, 0, string.strA, str_len, NULL, 0); if (dst_len) @@ -1452,12 +1468,12 @@ static INT CopyCompAttrIMEtoClient( const struct imc *data, const BYTE *src, INT return rc; } -static INT CopyCompClauseIMEtoClient( struct imc *data, LPBYTE source, INT slen, LPBYTE ssource, +static INT CopyCompClauseIMEtoClient( BOOL src_unicode, LPBYTE source, INT slen, LPBYTE ssource, LPBYTE target, INT tlen, BOOL unicode ) { INT rc; - if (ime_is_unicode( data->ime ) && !unicode) + if (src_unicode && !unicode) { if (tlen) { @@ -1478,7 +1494,7 @@ static INT CopyCompClauseIMEtoClient( struct imc *data, LPBYTE source, INT slen, else rc = slen; } - else if (!ime_is_unicode( data->ime ) && unicode) + else if (!src_unicode && unicode) { if (tlen) { @@ -1507,15 +1523,15 @@ static INT CopyCompClauseIMEtoClient( struct imc *data, LPBYTE source, INT slen, return rc; } -static INT CopyCompOffsetIMEtoClient( struct imc *data, DWORD offset, LPBYTE ssource, BOOL unicode ) +static INT CopyCompOffsetIMEtoClient( BOOL src_unicode, DWORD offset, LPBYTE ssource, BOOL unicode ) { int rc; - if (ime_is_unicode( data->ime ) && !unicode) + if (src_unicode && !unicode) { rc = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)ssource, offset, NULL, 0, NULL, NULL); } - else if (!ime_is_unicode( data->ime ) && unicode) + else if (!src_unicode && unicode) { rc = MultiByteToWideChar(CP_ACP, 0, (LPSTR)ssource, offset, NULL, 0); } @@ -1531,6 +1547,8 @@ static LONG ImmGetCompositionStringT( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, LONG rc = 0; struct imc *data = get_imc_data( hIMC ); LPCOMPOSITIONSTRING compstr; + BOOL src_unicode; + struct ime *ime; LPBYTE compdata; TRACE("(%p, 0x%lx, %p, %ld)\n", hIMC, dwIndex, lpBuf, dwBufLen); @@ -1541,6 +1559,10 @@ static LONG ImmGetCompositionStringT( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, if (!data->IMC.hCompStr) return FALSE; + if (!(ime = imc_select_ime( data ))) + return FALSE; + src_unicode = ime_is_unicode( ime ); + compdata = ImmLockIMCC(data->IMC.hCompStr); compstr = (LPCOMPOSITIONSTRING)compdata; @@ -1548,63 +1570,63 @@ static LONG ImmGetCompositionStringT( HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, { case GCS_RESULTSTR: TRACE("GCS_RESULTSTR\n"); - rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode); + rc = CopyCompStringIMEtoClient(src_unicode, compdata + compstr->dwResultStrOffset, compstr->dwResultStrLen, lpBuf, dwBufLen, unicode); break; case GCS_COMPSTR: TRACE("GCS_COMPSTR\n"); - rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode); + rc = CopyCompStringIMEtoClient(src_unicode, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode); break; case GCS_COMPATTR: TRACE("GCS_COMPATTR\n"); - rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen, + rc = CopyCompAttrIMEtoClient(src_unicode, compdata + compstr->dwCompAttrOffset, compstr->dwCompAttrLen, compdata + compstr->dwCompStrOffset, compstr->dwCompStrLen, lpBuf, dwBufLen, unicode); break; case GCS_COMPCLAUSE: TRACE("GCS_COMPCLAUSE\n"); - rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen, + rc = CopyCompClauseIMEtoClient(src_unicode, compdata + compstr->dwCompClauseOffset,compstr->dwCompClauseLen, compdata + compstr->dwCompStrOffset, lpBuf, dwBufLen, unicode); break; case GCS_RESULTCLAUSE: TRACE("GCS_RESULTCLAUSE\n"); - rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen, + rc = CopyCompClauseIMEtoClient(src_unicode, compdata + compstr->dwResultClauseOffset,compstr->dwResultClauseLen, compdata + compstr->dwResultStrOffset, lpBuf, dwBufLen, unicode); break; case GCS_RESULTREADSTR: TRACE("GCS_RESULTREADSTR\n"); - rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode); + rc = CopyCompStringIMEtoClient(src_unicode, compdata + compstr->dwResultReadStrOffset, compstr->dwResultReadStrLen, lpBuf, dwBufLen, unicode); break; case GCS_RESULTREADCLAUSE: TRACE("GCS_RESULTREADCLAUSE\n"); - rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen, + rc = CopyCompClauseIMEtoClient(src_unicode, compdata + compstr->dwResultReadClauseOffset,compstr->dwResultReadClauseLen, compdata + compstr->dwResultStrOffset, lpBuf, dwBufLen, unicode); break; case GCS_COMPREADSTR: TRACE("GCS_COMPREADSTR\n"); - rc = CopyCompStringIMEtoClient(data, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode); + rc = CopyCompStringIMEtoClient(src_unicode, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode); break; case GCS_COMPREADATTR: TRACE("GCS_COMPREADATTR\n"); - rc = CopyCompAttrIMEtoClient(data, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen, + rc = CopyCompAttrIMEtoClient(src_unicode, compdata + compstr->dwCompReadAttrOffset, compstr->dwCompReadAttrLen, compdata + compstr->dwCompReadStrOffset, compstr->dwCompReadStrLen, lpBuf, dwBufLen, unicode); break; case GCS_COMPREADCLAUSE: TRACE("GCS_COMPREADCLAUSE\n"); - rc = CopyCompClauseIMEtoClient(data, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen, + rc = CopyCompClauseIMEtoClient(src_unicode, compdata + compstr->dwCompReadClauseOffset,compstr->dwCompReadClauseLen, compdata + compstr->dwCompStrOffset, lpBuf, dwBufLen, unicode); break; case GCS_CURSORPOS: TRACE("GCS_CURSORPOS\n"); - rc = CopyCompOffsetIMEtoClient(data, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode); + rc = CopyCompOffsetIMEtoClient(src_unicode, compstr->dwCursorPos, compdata + compstr->dwCompStrOffset, unicode); break; case GCS_DELTASTART: TRACE("GCS_DELTASTART\n"); - rc = CopyCompOffsetIMEtoClient(data, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode); + rc = CopyCompOffsetIMEtoClient(src_unicode, compstr->dwDeltaStart, compdata + compstr->dwCompStrOffset, unicode); break; default: FIXME("Unhandled index 0x%lx\n",dwIndex); @@ -2198,6 +2220,7 @@ BOOL WINAPI ImmNotifyIME( HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) { struct imc *data = get_imc_data( hIMC ); + struct ime *ime; TRACE("(%p, %ld, %ld, %ld)\n", hIMC, dwAction, dwIndex, dwValue); @@ -2213,7 +2236,8 @@ BOOL WINAPI ImmNotifyIME( return FALSE; } - return data->ime->pNotifyIME( hIMC, dwAction, dwIndex, dwValue ); + if (!(ime = imc_select_ime( data ))) return FALSE; + return ime->pNotifyIME( hIMC, dwAction, dwIndex, dwValue ); } /*********************************************************************** @@ -2404,6 +2428,7 @@ BOOL WINAPI ImmSetCompositionStringA( WCHAR *ReadBuffer = NULL; BOOL rc; struct imc *data = get_imc_data( hIMC ); + struct ime *ime; TRACE("(%p, %ld, %p, %ld, %p, %ld):\n", hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); @@ -2420,8 +2445,8 @@ BOOL WINAPI ImmSetCompositionStringA( dwIndex == SCS_QUERYRECONVERTSTRING)) return FALSE; - if (!ime_is_unicode( data->ime )) - return data->ime->pImeSetCompositionString( hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen ); + if (!(ime = imc_select_ime( data ))) return FALSE; + if (!ime_is_unicode( ime )) return ime->pImeSetCompositionString( hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen ); comp_len = MultiByteToWideChar(CP_ACP, 0, lpComp, dwCompLen, NULL, 0); if (comp_len) @@ -2460,6 +2485,7 @@ BOOL WINAPI ImmSetCompositionStringW( CHAR *ReadBuffer = NULL; BOOL rc; struct imc *data = get_imc_data( hIMC ); + struct ime *ime; TRACE("(%p, %ld, %p, %ld, %p, %ld):\n", hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); @@ -2476,8 +2502,8 @@ BOOL WINAPI ImmSetCompositionStringW( dwIndex == SCS_QUERYRECONVERTSTRING)) return FALSE; - if (ime_is_unicode( data->ime )) - return data->ime->pImeSetCompositionString( hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen ); + if (!(ime = imc_select_ime( data ))) return FALSE; + if (ime_is_unicode( ime )) return ime->pImeSetCompositionString( hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen ); comp_len = WideCharToMultiByte(CP_ACP, 0, lpComp, dwCompLen, NULL, 0, NULL, NULL); @@ -2738,6 +2764,7 @@ DWORD WINAPI ImmGetImeMenuItemsA( HIMC himc, DWORD flags, DWORD type, IMEMENUITE IMEMENUITEMINFOA *menuA, DWORD size ) { struct imc *data = get_imc_data( himc ); + struct ime *ime; DWORD ret; TRACE( "himc %p, flags %#lx, type %lu, parentA %p, menuA %p, size %lu.\n", @@ -2749,8 +2776,9 @@ DWORD WINAPI ImmGetImeMenuItemsA( HIMC himc, DWORD flags, DWORD type, IMEMENUITE return 0; } - if (!ime_is_unicode( data->ime ) || (!parentA && !menuA)) - ret = data->ime->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size ); + if (!(ime = imc_select_ime( data ))) return 0; + if (!ime_is_unicode( ime ) || (!parentA && !menuA)) + ret = ime->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size ); else { IMEMENUITEMINFOW tmpW, *menuW, *parentW = parentA ? &tmpW : NULL; @@ -2763,7 +2791,7 @@ DWORD WINAPI ImmGetImeMenuItemsA( HIMC himc, DWORD flags, DWORD type, IMEMENUITE menuW = malloc( size ); } - ret = data->ime->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size ); + ret = ime->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size ); if (parentA) { @@ -2796,6 +2824,7 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITE IMEMENUITEMINFOW *menuW, DWORD size ) { struct imc *data = get_imc_data( himc ); + struct ime *ime; DWORD ret; TRACE( "himc %p, flags %#lx, type %lu, parentW %p, menuW %p, size %lu.\n", @@ -2807,8 +2836,9 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITE return 0; } - if (ime_is_unicode( data->ime ) || (!parentW && !menuW)) - ret = data->ime->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size ); + if (!(ime = imc_select_ime( data ))) return 0; + if (ime_is_unicode( ime ) || (!parentW && !menuW)) + ret = ime->pImeGetImeMenuItems( himc, flags, type, parentW, menuW, size ); else { IMEMENUITEMINFOA tmpA, *menuA, *parentA = parentW ? &tmpA : NULL; @@ -2821,7 +2851,7 @@ DWORD WINAPI ImmGetImeMenuItemsW( HIMC himc, DWORD flags, DWORD type, IMEMENUITE menuA = malloc( size ); } - ret = data->ime->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size ); + ret = ime->pImeGetImeMenuItems( himc, flags, type, parentA, menuA, size ); if (parentW) { @@ -2857,7 +2887,7 @@ INPUTCONTEXT *WINAPI ImmLockIMC( HIMC himc ) if (!imc) return NULL; imc->dwLock++; - imc_select_hkl( imc, GetKeyboardLayout( 0 ) ); + imc_select_ime( imc ); return &imc->IMC; } @@ -2988,6 +3018,7 @@ BOOL WINAPI ImmGenerateMessage(HIMC hIMC) BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData) { struct imc *data; + struct ime *ime; HIMC imc = ImmGetContext(hwnd); BYTE state[256]; UINT scancode; @@ -2999,6 +3030,7 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD TRACE("%p %x %x %x\n",hwnd, msg, (UINT)wParam, (UINT)lKeyData); if (!(data = get_imc_data( imc ))) return FALSE; + if (!(ime = imc_select_ime( imc ))) return FALSE; if (data->lastVK == VK_PROCESSKEY) return FALSE; GetKeyboardState(state); @@ -3007,11 +3039,11 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD list = calloc( list_count, sizeof(TRANSMSG) + sizeof(DWORD) ); list->uMsgCount = list_count; - if (data->ime->info.fdwProperty & IME_PROP_KBD_CHAR_FIRST) + if (ime->info.fdwProperty & IME_PROP_KBD_CHAR_FIRST) { WCHAR chr; - if (!ime_is_unicode( data->ime )) + if (!ime_is_unicode( ime )) ToAscii( data->lastVK, scancode, state, &chr, 0 ); else ToUnicodeEx(data->lastVK, scancode, state, &chr, 1, 0, GetKeyboardLayout(0)); @@ -3020,7 +3052,7 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD else uVirtKey = data->lastVK; - msg_count = data->ime->pImeToAsciiEx( uVirtKey, scancode, state, list, 0, imc ); + msg_count = ime->pImeToAsciiEx( uVirtKey, scancode, state, list, 0, imc ); TRACE("%i messages generated\n",msg_count); if (msg_count && msg_count <= list_count) { @@ -3047,6 +3079,7 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD BOOL WINAPI ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM lparam, DWORD unknown ) { struct imc *imc; + struct ime *ime; BYTE state[256]; BOOL ret; @@ -3054,12 +3087,11 @@ BOOL WINAPI ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM lparam, DWORD u if (hkl != GetKeyboardLayout( 0 )) return FALSE; if (!(imc = get_imc_data( ImmGetContext( hwnd ) ))) return FALSE; - imc_select_hkl( imc, hkl ); - if (!imc->ime) return FALSE; + if (!(ime = imc_select_ime( imc ))) return FALSE; GetKeyboardState( state ); - ret = imc->ime->pImeProcessKey( imc->handle, vkey, lparam, state ); + ret = ime->pImeProcessKey( imc->handle, vkey, lparam, state ); imc->lastVK = ret ? vkey : VK_PROCESSKEY; return ret; diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 4d9d213cb90..9a0594038c9 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3931,7 +3931,6 @@ static void test_ImmProcessKey(void) ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); ok_ret( 0, ImmProcessKey( hwnd, old_hkl, 'A', 0, 0 ) ); - todo_wine ok_seq( empty_sequence ); ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); @@ -4227,7 +4226,6 @@ static void test_ImmCreateInputContext(void) { .hkl = expect_ime, .himc = 0/*himc[1]*/, .func = IME_SELECT, .select = 1, - .todo = TRUE, }, {0}, }; @@ -4336,7 +4334,6 @@ static void test_ImmCreateInputContext(void) himc[1] = ImmCreateContext(); ok( !!himc[1], "ImmCreateContext failed, error %lu\n", GetLastError() ); - todo_wine ok_seq( empty_sequence ); ctx = ImmLockIMC( himc[1] ); ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); From abb3f74f2bd09f5cec585cb9607171bad4969e71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 9 Mar 2023 13:06:00 +0100 Subject: [PATCH 1786/2777] imm32: Introduce new input_context_init helper. (cherry picked from commit f24479793bf09f5f1820b8091d2341fc9d82d937) --- dlls/imm32/imm.c | 77 ++++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index b2650fcfeb9..b8feac86e94 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -637,6 +637,50 @@ static BOOL free_input_context_data( HIMC hIMC ) return TRUE; } +static void input_context_init( INPUTCONTEXT *ctx ) +{ + COMPOSITIONSTRING *str; + CANDIDATEINFO *info; + GUIDELINE *line; + UINT i; + + if (!(ctx->hMsgBuf = ImmCreateIMCC( 0 ))) + WARN( "Failed to allocate %p message buffer\n", ctx ); + + if (!(ctx->hCompStr = ImmCreateIMCC( sizeof(COMPOSITIONSTRING) ))) + WARN( "Failed to allocate %p COMPOSITIONSTRING\n", ctx ); + else if (!(str = ImmLockIMCC( ctx->hCompStr ))) + WARN( "Failed to lock IMCC for COMPOSITIONSTRING\n" ); + else + { + str->dwSize = sizeof(COMPOSITIONSTRING); + ImmUnlockIMCC( ctx->hCompStr ); + } + + if (!(ctx->hCandInfo = ImmCreateIMCC( sizeof(CANDIDATEINFO) ))) + WARN( "Failed to allocate %p CANDIDATEINFO\n", ctx ); + else if (!(info = ImmLockIMCC( ctx->hCandInfo ))) + WARN( "Failed to lock IMCC for CANDIDATEINFO\n" ); + else + { + info->dwSize = sizeof(CANDIDATEINFO); + ImmUnlockIMCC( ctx->hCandInfo ); + } + + if (!(ctx->hGuideLine = ImmCreateIMCC( sizeof(GUIDELINE) ))) + WARN( "Failed to allocate %p GUIDELINE\n", ctx ); + else if (!(line = ImmLockIMCC( ctx->hGuideLine ))) + WARN( "Failed to lock IMCC for GUIDELINE\n" ); + else + { + line->dwSize = sizeof(GUIDELINE); + ImmUnlockIMCC( ctx->hGuideLine ); + } + + for (i = 0; i < ARRAY_SIZE(ctx->cfCandForm); i++) + ctx->cfCandForm[i].dwIndex = ~0u; +} + static void IMM_FreeThreadData(void) { struct coinit_spy *spy; @@ -718,18 +762,6 @@ static LRESULT ImmInternalSendIMENotify( struct imc *data, WPARAM notify, LPARAM return 0; } -static HIMCC ImmCreateBlankCompStr(void) -{ - HIMCC rc; - LPCOMPOSITIONSTRING ptr; - rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING)); - ptr = ImmLockIMCC(rc); - memset(ptr,0,sizeof(COMPOSITIONSTRING)); - ptr->dwSize = sizeof(COMPOSITIONSTRING); - ImmUnlockIMCC(rc); - return rc; -} - /*********************************************************************** * ImmSetActiveContext (IMM32.@) */ @@ -883,28 +915,9 @@ BOOL WINAPI ImmConfigureIMEW( HKL hkl, HWND hwnd, DWORD mode, void *data ) static struct imc *create_input_context( HIMC default_imc ) { struct imc *new_context; - LPGUIDELINE gl; - LPCANDIDATEINFO ci; - int i; if (!(new_context = calloc( 1, sizeof(*new_context) ))) return NULL; - - /* the HIMCCs are never NULL */ - new_context->IMC.hCompStr = ImmCreateBlankCompStr(); - new_context->IMC.hMsgBuf = ImmCreateIMCC(0); - new_context->IMC.hCandInfo = ImmCreateIMCC(sizeof(CANDIDATEINFO)); - ci = ImmLockIMCC(new_context->IMC.hCandInfo); - memset(ci,0,sizeof(CANDIDATEINFO)); - ci->dwSize = sizeof(CANDIDATEINFO); - ImmUnlockIMCC(new_context->IMC.hCandInfo); - new_context->IMC.hGuideLine = ImmCreateIMCC(sizeof(GUIDELINE)); - gl = ImmLockIMCC(new_context->IMC.hGuideLine); - memset(gl,0,sizeof(GUIDELINE)); - gl->dwSize = sizeof(GUIDELINE); - ImmUnlockIMCC(new_context->IMC.hGuideLine); - - for (i = 0; i < ARRAY_SIZE(new_context->IMC.cfCandForm); i++) - new_context->IMC.cfCandForm[i].dwIndex = ~0u; + input_context_init( &new_context->IMC ); if (!default_imc) new_context->handle = NtUserCreateInputContext((UINT_PTR)new_context); From 885d9f5c90a763b16d47fe0a8b9a16d2f0306db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 6 Mar 2023 22:58:36 +0100 Subject: [PATCH 1787/2777] imm32: Add a default implementation for IME functions. To be used by graphics drivers. (cherry picked from commit 3d694c8118a848fb7df27200017e42a0efc11db8) --- dlls/imm32/Makefile.in | 1 + dlls/imm32/ime.c | 151 +++++++++++++++++++++++++++++++++++++++++ dlls/imm32/imm.c | 13 ++-- 3 files changed, 160 insertions(+), 5 deletions(-) create mode 100644 dlls/imm32/ime.c diff --git a/dlls/imm32/Makefile.in b/dlls/imm32/Makefile.in index b4e3039849e..baf10c5f1dc 100644 --- a/dlls/imm32/Makefile.in +++ b/dlls/imm32/Makefile.in @@ -4,6 +4,7 @@ IMPORTS = user32 gdi32 advapi32 kernelbase win32u DELAYIMPORTS = ole32 C_SRCS = \ + ime.c \ imm.c RC_SRCS = version.rc diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c new file mode 100644 index 00000000000..c31fd936ca1 --- /dev/null +++ b/dlls/imm32/ime.c @@ -0,0 +1,151 @@ +/* + * Copyright 2023 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 + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "imm.h" +#include "immdev.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(imm); + +BOOL WINAPI ImeInquire( IMEINFO *info, WCHAR *ui_class, DWORD flags ) +{ + FIXME( "info %p, ui_class %p, flags %#lx stub!\n", info, ui_class, flags ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +BOOL WINAPI ImeDestroy( UINT force ) +{ + FIXME( "force %u stub!\n", force ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +BOOL WINAPI ImeSelect( HIMC himc, BOOL select ) +{ + FIXME( "himc %p, select %d stub!\n", himc, select ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +BOOL WINAPI ImeSetActiveContext( HIMC himc, BOOL flag ) +{ + FIXME( "himc %p, flag %#x stub!\n", himc, flag ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +BOOL WINAPI ImeProcessKey( HIMC himc, UINT vkey, LPARAM key_data, BYTE *key_state ) +{ + FIXME( "himc %p, vkey %u, key_data %#Ix, key_state %p stub!\n", himc, vkey, key_data, key_state ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +UINT WINAPI ImeToAsciiEx( UINT vkey, UINT scan_code, BYTE *key_state, TRANSMSGLIST *msgs, UINT state, HIMC himc ) +{ + FIXME( "vkey %u, scan_code %u, key_state %p, msgs %p, state %u, himc %p stub!\n", + vkey, scan_code, key_state, msgs, state, himc ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return 0; +} + +BOOL WINAPI ImeConfigure( HKL hkl, HWND hwnd, DWORD mode, void *data ) +{ + FIXME( "hkl %p, hwnd %p, mode %lu, data %p stub!\n", hkl, hwnd, mode, data ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +DWORD WINAPI ImeConversionList( HIMC himc, const WCHAR *source, CANDIDATELIST *dest, DWORD dest_len, UINT flag ) +{ + FIXME( "himc %p, source %s, dest %p, dest_len %lu, flag %#x stub!\n", + himc, debugstr_w(source), dest, dest_len, flag ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return 0; +} + +BOOL WINAPI ImeSetCompositionString( HIMC himc, DWORD index, const void *comp, DWORD comp_len, + const void *read, DWORD read_len ) +{ + FIXME( "himc %p, index %lu, comp %p, comp_len %lu, read %p, read_len %lu stub!\n", + himc, index, comp, comp_len, read, read_len ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +BOOL WINAPI NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) +{ + FIXME( "himc %p, action %lu, index %lu, value %lu stub!\n", himc, action, index, value ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +LRESULT WINAPI ImeEscape( HIMC himc, UINT escape, void *data ) +{ + FIXME( "himc %p, escape %#x, data %p stub!\n", himc, escape, data ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return 0; +} + +DWORD WINAPI ImeGetImeMenuItems( HIMC himc, DWORD flags, DWORD type, IMEMENUITEMINFOW *parent, + IMEMENUITEMINFOW *menu, DWORD size ) +{ + FIXME( "himc %p, flags %#lx, type %lu, parent %p, menu %p, size %#lx stub!\n", + himc, flags, type, parent, menu, size ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return 0; +} + +BOOL WINAPI ImeRegisterWord( const WCHAR *reading, DWORD style, const WCHAR *string ) +{ + FIXME( "reading %s, style %lu, string %s stub!\n", debugstr_w(reading), style, debugstr_w(string) ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +UINT WINAPI ImeGetRegisterWordStyle( UINT item, STYLEBUFW *style ) +{ + FIXME( "item %u, style %p stub!\n", item, style ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return 0; +} + +BOOL WINAPI ImeUnregisterWord( const WCHAR *reading, DWORD style, const WCHAR *string ) +{ + FIXME( "reading %s, style %lu, string %s stub!\n", debugstr_w(reading), style, debugstr_w(string) ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return FALSE; +} + +UINT WINAPI ImeEnumRegisterWord( REGISTERWORDENUMPROCW proc, const WCHAR *reading, DWORD style, + const WCHAR *string, void *data ) +{ + FIXME( "proc %p, reading %s, style %lu, string %s, data %p stub!\n", + proc, debugstr_w(reading), style, debugstr_w(string), data ); + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + return 0; +} diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index b8feac86e94..e90279a4688 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -467,6 +467,7 @@ BOOL WINAPI ImmFreeLayout( HKL hkl ) BOOL WINAPI ImmLoadIME( HKL hkl ) { WCHAR buffer[MAX_PATH] = {0}; + BOOL use_default_ime; struct ime *ime; TRACE( "hkl %p\n", hkl ); @@ -479,17 +480,19 @@ BOOL WINAPI ImmLoadIME( HKL hkl ) if (!(ime = calloc( 1, sizeof(*ime) ))) return FALSE; ime->hkl = hkl; - if (!ImmGetIMEFileNameW( hkl, buffer, MAX_PATH )) ime->module = NULL; - else ime->module = LoadLibraryW( buffer ); + if (!ImmGetIMEFileNameW( hkl, buffer, MAX_PATH )) use_default_ime = TRUE; + else if (!(ime->module = LoadLibraryW( buffer ))) use_default_ime = TRUE; + else use_default_ime = FALSE; - if (!ime->module) + if (use_default_ime) { if (*buffer) WARN( "Failed to load %s, falling back to default.\n", debugstr_w(buffer) ); - if (!(ime->module = load_graphics_driver())) goto failed; + if (!(ime->module = load_graphics_driver())) ime->module = LoadLibraryW( L"imm32" ); } #define LOAD_FUNCPTR( f ) \ - if (!(ime->p##f = (void *)GetProcAddress( ime->module, #f ))) \ + if (!(ime->p##f = (void *)GetProcAddress( ime->module, #f )) && \ + !(ime->p##f = use_default_ime ? (void *)f : NULL)) \ { \ WARN( "Can't find function %s in HKL %p IME\n", #f, hkl ); \ goto failed; \ From 10c5d11ba6f9078ce6ef4af609d3b558ec95eb1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 19 Feb 2023 12:01:59 +0100 Subject: [PATCH 1788/2777] imm32: Return TRUE from ImmIsIME with any HKL. (cherry picked from commit 32c5b57ac80673c2bad7291d27b4001aac31ae9b) --- dlls/imm32/imm.c | 7 +------ dlls/imm32/tests/imm32.c | 1 - 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index e90279a4688..5cdf14cc9d9 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2175,13 +2175,8 @@ HKL WINAPI ImmInstallIMEW( const WCHAR *filename, const WCHAR *description ) */ BOOL WINAPI ImmIsIME( HKL hkl ) { - struct ime *ime; - TRACE( "hkl %p\n", hkl ); - - if (!(ime = ime_acquire( hkl ))) return 0; - ime_release( ime ); - + if (!hkl) return FALSE; return TRUE; } diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 9a0594038c9..3892eccb147 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3238,7 +3238,6 @@ static void test_ImmIsIME(void) SET_ENABLE( IME_DLL_PROCESS_DETACH, TRUE ); SetLastError( 0xdeadbeef ); - todo_wine ok_ret( 0, ImmIsIME( 0 ) ); ok_ret( 0xdeadbeef, GetLastError() ); ok_ret( 1, ImmIsIME( hkl ) ); From e337d9491e14bbdec68faee9ef0a5479f0288777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 7 Mar 2023 23:10:05 +0100 Subject: [PATCH 1789/2777] winex11: Use the default IME implementation for stubs. (cherry picked from commit 2a4dff01bd2dec7129e7b572dbb8e29ba75723df) --- dlls/imm32/ime.c | 11 ++--- dlls/imm32/tests/imm32.c | 1 + dlls/winex11.drv/ime.c | 79 ------------------------------- dlls/winex11.drv/winex11.drv.spec | 9 ---- 4 files changed, 6 insertions(+), 94 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index c31fd936ca1..c05ca6d0255 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -46,16 +46,15 @@ BOOL WINAPI ImeDestroy( UINT force ) BOOL WINAPI ImeSelect( HIMC himc, BOOL select ) { - FIXME( "himc %p, select %d stub!\n", himc, select ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + FIXME( "himc %p, select %d semi-stub!\n", himc, select ); + return TRUE; } BOOL WINAPI ImeSetActiveContext( HIMC himc, BOOL flag ) { - FIXME( "himc %p, flag %#x stub!\n", himc, flag ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + static int once; + if (!once++) FIXME( "himc %p, flag %#x stub!\n", himc, flag ); + return TRUE; } BOOL WINAPI ImeProcessKey( HIMC himc, UINT vkey, LPARAM key_data, BYTE *key_state ) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 3892eccb147..3a75d9636e7 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3324,6 +3324,7 @@ static void test_ImmGetProperty(void) ok_ret( expect->fdwSelectCaps, ImmGetProperty( hkl, IGP_SELECT ) ); ok_ret( IMEVER_0400, ImmGetProperty( hkl, IGP_GETIMEVERSION ) ); ok_ret( expect->fdwUICaps, ImmGetProperty( hkl, IGP_UI ) ); + todo_wine ok_ret( 0xdeadbeef, GetLastError() ); /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index a293daa6ad9..9c0894717ad 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -525,23 +525,6 @@ BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass, DWORD flags) return TRUE; } -BOOL WINAPI ImeConfigure(HKL hKL,HWND hWnd, DWORD dwMode, LPVOID lpData) -{ - FIXME("(%p, %p, %ld, %p): stub\n", hKL, hWnd, dwMode, lpData); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - -DWORD WINAPI ImeConversionList(HIMC hIMC, LPCWSTR lpSource, - LPCANDIDATELIST lpCandList, DWORD dwBufLen, UINT uFlag) - -{ - FIXME("(%p, %s, %p, %ld, %d): stub\n", hIMC, debugstr_w(lpSource), - lpCandList, dwBufLen, uFlag); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; -} - BOOL WINAPI ImeDestroy(UINT uForce) { TRACE("\n"); @@ -551,13 +534,6 @@ BOOL WINAPI ImeDestroy(UINT uForce) return TRUE; } -LRESULT WINAPI ImeEscape(HIMC hIMC, UINT uSubFunc, LPVOID lpData) -{ - FIXME("(%p, %d, %p): stub\n", hIMC, uSubFunc, lpData); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; -} - BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lpbKeyState) { /* See the comment at the head of this file */ @@ -602,15 +578,6 @@ BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) return TRUE; } -BOOL WINAPI ImeSetActiveContext(HIMC hIMC,BOOL fFlag) -{ - static int once; - - if (!once++) - FIXME("(%p, %x): stub\n", hIMC, fFlag); - return TRUE; -} - UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, TRANSMSGLIST *lpdwTransKey, UINT fuState, HIMC hIMC) { @@ -777,42 +744,6 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) return bRet; } -BOOL WINAPI ImeRegisterWord(LPCWSTR lpszReading, DWORD dwStyle, - LPCWSTR lpszRegister) -{ - FIXME("(%s, %ld, %s): stub\n", debugstr_w(lpszReading), dwStyle, - debugstr_w(lpszRegister)); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - -BOOL WINAPI ImeUnregisterWord(LPCWSTR lpszReading, DWORD dwStyle, - LPCWSTR lpszUnregister) -{ - FIXME("(%s, %ld, %s): stub\n", debugstr_w(lpszReading), dwStyle, - debugstr_w(lpszUnregister)); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - -UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUFW lpStyleBuf) -{ - FIXME("(%d, %p): stub\n", nItem, lpStyleBuf); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; -} - -UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROCW lpfnEnumProc, - LPCWSTR lpszReading, DWORD dwStyle, - LPCWSTR lpszRegister, LPVOID lpData) -{ - FIXME("(%p, %s, %ld, %s, %p): stub\n", lpfnEnumProc, - debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister), - lpData); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; -} - BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen, LPCVOID lpRead, DWORD dwReadLen) @@ -888,16 +819,6 @@ BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, return TRUE; } -DWORD WINAPI ImeGetImeMenuItems(HIMC hIMC, DWORD dwFlags, DWORD dwType, - LPIMEMENUITEMINFOW lpImeParentMenu, LPIMEMENUITEMINFOW lpImeMenu, - DWORD dwSize) -{ - FIXME("(%p, %lx %lx %p %p %lx): stub\n", hIMC, dwFlags, dwType, - lpImeParentMenu, lpImeMenu, dwSize); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; -} - /* Interfaces to XIM and other parts of winex11drv */ NTSTATUS x11drv_ime_set_open_status( UINT open ) diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec index 77e4a6285de..0596d48c577 100644 --- a/dlls/winex11.drv/winex11.drv.spec +++ b/dlls/winex11.drv/winex11.drv.spec @@ -12,18 +12,9 @@ #IME Interface @ stdcall ImeInquire(ptr ptr wstr) -@ stdcall ImeConfigure(long long long ptr) @ stdcall ImeDestroy(long) -@ stdcall ImeEscape(long long ptr) @ stdcall ImeSelect(long long) -@ stdcall ImeSetActiveContext(long long) @ stdcall ImeToAsciiEx(long long ptr ptr long long) @ stdcall NotifyIME(long long long long) -@ stdcall ImeRegisterWord(wstr long wstr) -@ stdcall ImeUnregisterWord(wstr long wstr) -@ stdcall ImeEnumRegisterWord(ptr wstr long wstr ptr) @ stdcall ImeSetCompositionString(long long ptr long ptr long) -@ stdcall ImeConversionList(long wstr ptr long long) @ stdcall ImeProcessKey(long long long ptr) -@ stdcall ImeGetRegisterWordStyle(long ptr) -@ stdcall ImeGetImeMenuItems(long long long ptr ptr long) From 0d7a332ce471c935fb8925c3bc27ee9b49195277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 7 Mar 2023 22:57:51 +0100 Subject: [PATCH 1790/2777] winemac: Use the default IME implementation for stubs. (cherry picked from commit 50352739cafc76e2ca27b989aaede072d5f6494d) --- dlls/winemac.drv/ime.c | 70 ------------------------------- dlls/winemac.drv/winemac.drv.spec | 9 ---- 2 files changed, 79 deletions(-) diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index 4bdfcbc6730..f779b4d06b0 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -520,23 +520,6 @@ static void UpdateDataInDefaultIMEWindow(HIMC hIMC, HWND hwnd, BOOL showable) UnlockRealIMC(hIMC); } -BOOL WINAPI ImeConfigure(HKL hKL, HWND hWnd, DWORD dwMode, LPVOID lpData) -{ - FIXME("(%p, %p, %ld, %p): stub\n", hKL, hWnd, dwMode, lpData); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - -DWORD WINAPI ImeConversionList(HIMC hIMC, LPCWSTR lpSource, LPCANDIDATELIST lpCandList, - DWORD dwBufLen, UINT uFlag) - -{ - FIXME("(%p, %s, %p, %ld, %d): stub\n", hIMC, debugstr_w(lpSource), lpCandList, - dwBufLen, uFlag); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; -} - BOOL WINAPI ImeDestroy(UINT uForce) { TRACE("\n"); @@ -546,12 +529,6 @@ BOOL WINAPI ImeDestroy(UINT uForce) return TRUE; } -LRESULT WINAPI ImeEscape(HIMC hIMC, UINT uSubFunc, LPVOID lpData) -{ - TRACE("%x %p\n", uSubFunc, lpData); - return 0; -} - BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lpbKeyState) { LPINPUTCONTEXT lpIMC; @@ -637,15 +614,6 @@ BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) return TRUE; } -BOOL WINAPI ImeSetActiveContext(HIMC hIMC, BOOL fFlag) -{ - static int once; - - if (!once++) - FIXME("(%p, %x): stub\n", hIMC, fFlag); - return TRUE; -} - UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, TRANSMSGLIST *lpdwTransKey, UINT fuState, HIMC hIMC) { @@ -870,36 +838,6 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) return bRet; } -BOOL WINAPI ImeRegisterWord(LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszRegister) -{ - FIXME("(%s, %ld, %s): stub\n", debugstr_w(lpszReading), dwStyle, debugstr_w(lpszRegister)); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - -BOOL WINAPI ImeUnregisterWord(LPCWSTR lpszReading, DWORD dwStyle, LPCWSTR lpszUnregister) -{ - FIXME("(%s, %ld, %s): stub\n", debugstr_w(lpszReading), dwStyle, debugstr_w(lpszUnregister)); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - -UINT WINAPI ImeGetRegisterWordStyle(UINT nItem, LPSTYLEBUFW lpStyleBuf) -{ - FIXME("(%d, %p): stub\n", nItem, lpStyleBuf); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; -} - -UINT WINAPI ImeEnumRegisterWord(REGISTERWORDENUMPROCW lpfnEnumProc, LPCWSTR lpszReading, - DWORD dwStyle, LPCWSTR lpszRegister, LPVOID lpData) -{ - FIXME("(%p, %s, %ld, %s, %p): stub\n", lpfnEnumProc, debugstr_w(lpszReading), dwStyle, - debugstr_w(lpszRegister), lpData); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; -} - static BOOL IME_SetCompositionString(void* hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen, DWORD cursor_pos, BOOL cursor_valid) { LPINPUTCONTEXT lpIMC; @@ -987,14 +925,6 @@ BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, DW return IME_SetCompositionString(hIMC, dwIndex, lpComp, dwCompLen, 0, FALSE); } -DWORD WINAPI ImeGetImeMenuItems(HIMC hIMC, DWORD dwFlags, DWORD dwType, LPIMEMENUITEMINFOW lpImeParentMenu, - LPIMEMENUITEMINFOW lpImeMenu, DWORD dwSize) -{ - FIXME("(%p, %lx %lx %p %p %lx): stub\n", hIMC, dwFlags, dwType, lpImeParentMenu, lpImeMenu, dwSize); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; -} - static void IME_NotifyComplete(void* hIMC) { NotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); diff --git a/dlls/winemac.drv/winemac.drv.spec b/dlls/winemac.drv/winemac.drv.spec index b060d1cc2a6..d5e94b53ce4 100644 --- a/dlls/winemac.drv/winemac.drv.spec +++ b/dlls/winemac.drv/winemac.drv.spec @@ -2,19 +2,10 @@ @ cdecl wine_notify_icon(long ptr) # IME -@ stdcall ImeConfigure(long long long ptr) -@ stdcall ImeConversionList(long wstr ptr long long) @ stdcall ImeDestroy(long) -@ stdcall ImeEnumRegisterWord(ptr wstr long wstr ptr) -@ stdcall ImeEscape(long long ptr) -@ stdcall ImeGetImeMenuItems(long long long ptr ptr long) -@ stdcall ImeGetRegisterWordStyle(long ptr) @ stdcall ImeInquire(ptr wstr wstr) @ stdcall ImeProcessKey(long long long ptr) -@ stdcall ImeRegisterWord(wstr long wstr) @ stdcall ImeSelect(long long) -@ stdcall ImeSetActiveContext(long long) @ stdcall ImeSetCompositionString(long long ptr long ptr long) @ stdcall ImeToAsciiEx(long long ptr ptr long long) -@ stdcall ImeUnregisterWord(wstr long wstr) @ stdcall NotifyIME(long long long long) From 6ac81d2fba3dde3748b39a947f523a17d32b3a13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 31 Mar 2023 08:55:57 +0200 Subject: [PATCH 1791/2777] imm32/tests: Add some ImmSetConversionStatus tests. (cherry picked from commit 13f0b5c9c6e9901ebf98a284219dd15790d620da) --- dlls/imm32/tests/imm32.c | 165 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 3a75d9636e7..772f3183679 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3890,6 +3890,168 @@ static void test_ImmUnregisterWord( BOOL unicode ) winetest_pop_context(); } +static void test_ImmSetConversionStatus(void) +{ + const struct ime_call set_conversion_status_0_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCONVERSIONMODE}, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE}, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETSENTENCEMODE}, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETSENTENCEMODE}, + }, + {0}, + }; + const struct ime_call set_conversion_status_1_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0xdeadbeef, .value = IMC_SETCONVERSIONMODE}, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE}, + }, + {0}, + }; + const struct ime_call set_conversion_status_2_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCONVERSIONMODE}, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE}, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0xfeedcafe, .value = IMC_SETSENTENCEMODE}, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETSENTENCEMODE}, + }, + {0}, + }; + DWORD old_conversion, old_sentence, conversion, sentence; + HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + INPUTCONTEXT *ctx; + + ok_ret( 0, ImmGetConversionStatus( 0, &old_conversion, &old_sentence ) ); + ok_ret( 1, ImmGetConversionStatus( default_himc, &old_conversion, &old_sentence ) ); + + ctx = ImmLockIMC( default_himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + ok_eq( old_conversion, ctx->fdwConversion, UINT, "%#x" ); + ok_eq( old_sentence, ctx->fdwSentence, UINT, "%#x" ); + + hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + process_messages(); + + ok_ret( 1, ImmGetConversionStatus( default_himc, &conversion, &sentence ) ); + ok_eq( old_conversion, conversion, UINT, "%#x" ); + ok_eq( old_sentence, sentence, UINT, "%#x" ); + ok_eq( old_conversion, ctx->fdwConversion, UINT, "%#x" ); + ok_eq( old_sentence, ctx->fdwSentence, UINT, "%#x" ); + + ok_ret( 1, ImmSetConversionStatus( default_himc, 0, 0 ) ); + ok_ret( 1, ImmGetConversionStatus( default_himc, &conversion, &sentence ) ); + ok_eq( 0, conversion, UINT, "%#x" ); + ok_eq( 0, sentence, UINT, "%#x" ); + ok_eq( 0, ctx->fdwConversion, UINT, "%#x" ); + ok_eq( 0, ctx->fdwSentence, UINT, "%#x" ); + + ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; + + if (!(hkl = ime_install())) goto cleanup; + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + process_messages(); + /* initial values are dependent on both old and new IME */ + ok_ret( 1, ImmSetConversionStatus( default_himc, 0, 0 ) ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + ok_ret( 1, ImmGetConversionStatus( default_himc, &conversion, &sentence ) ); + ok_eq( 0, conversion, UINT, "%#x" ); + ok_eq( 0, sentence, UINT, "%#x" ); + ok_eq( 0, ctx->fdwConversion, UINT, "%#x" ); + ok_eq( 0, ctx->fdwSentence, UINT, "%#x" ); + + ok_seq( empty_sequence ); + ok_ret( 1, ImmSetConversionStatus( default_himc, 0xdeadbeef, 0xfeedcafe ) ); + ok_seq( set_conversion_status_0_seq ); + + ok_ret( 1, ImmGetConversionStatus( default_himc, &conversion, &sentence ) ); + ok_eq( 0xdeadbeef, conversion, UINT, "%#x" ); + ok_eq( 0xfeedcafe, sentence, UINT, "%#x" ); + ok_eq( 0xdeadbeef, ctx->fdwConversion, UINT, "%#x" ); + ok_eq( 0xfeedcafe, ctx->fdwSentence, UINT, "%#x" ); + + ok_seq( empty_sequence ); + ok_ret( 1, ImmSetConversionStatus( default_himc, 0, 0xfeedcafe ) ); + ok_seq( set_conversion_status_1_seq ); + + ok_ret( 1, ImmGetConversionStatus( default_himc, &conversion, &sentence ) ); + ok_eq( 0, conversion, UINT, "%#x" ); + ok_eq( 0xfeedcafe, sentence, UINT, "%#x" ); + ok_eq( 0, ctx->fdwConversion, UINT, "%#x" ); + ok_eq( 0xfeedcafe, ctx->fdwSentence, UINT, "%#x" ); + + ok_seq( empty_sequence ); + ok_ret( 1, ImmSetConversionStatus( default_himc, ~0, ~0 ) ); + ok_seq( set_conversion_status_2_seq ); + + ok_ret( 1, ImmGetConversionStatus( default_himc, &conversion, &sentence ) ); + ok_eq( ~0, conversion, UINT, "%#x" ); + ok_eq( ~0, sentence, UINT, "%#x" ); + ok_eq( ~0, ctx->fdwConversion, UINT, "%#x" ); + ok_eq( ~0, ctx->fdwSentence, UINT, "%#x" ); + + /* status is cached and some bits are kept from the previous active IME */ + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + todo_wine ok_eq( 0x200, ctx->fdwConversion, UINT, "%#x" ); + ok_eq( old_sentence, ctx->fdwSentence, UINT, "%#x" ); + ok_ret( 1, ImmActivateLayout( hkl ) ); + todo_wine ok_eq( ~0, ctx->fdwConversion, UINT, "%#x" ); + todo_wine ok_eq( ~0, ctx->fdwSentence, UINT, "%#x" ); + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + todo_wine ok_eq( 0x200, ctx->fdwConversion, UINT, "%#x" ); + ok_eq( old_sentence, ctx->fdwSentence, UINT, "%#x" ); + + ime_cleanup( hkl, TRUE ); + +cleanup: + /* sanitize conversion status to some sane default */ + ok_ret( 1, ImmSetConversionStatus( default_himc, 0, 0 ) ); + ok_ret( 1, ImmGetConversionStatus( default_himc, &conversion, &sentence ) ); + ok_eq( 0, conversion, UINT, "%#x" ); + ok_eq( 0, sentence, UINT, "%#x" ); + ok_eq( 0, ctx->fdwConversion, UINT, "%#x" ); + ok_eq( 0, ctx->fdwSentence, UINT, "%#x" ); + + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + ok_ret( 1, ImmUnlockIMC( default_himc ) ); +} + static void test_ImmProcessKey(void) { const struct ime_call process_key_seq[] = @@ -4485,6 +4647,9 @@ START_TEST(imm32) test_ImmUnregisterWord( FALSE ); test_ImmUnregisterWord( TRUE ); + /* test these first to sanitize conversion / open statuses */ + test_ImmSetConversionStatus(); + test_ImmActivateLayout(); test_ImmCreateInputContext(); test_ImmProcessKey(); From 73e0d3bc251f70c5bb279f4bc49383e16b4ac23f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 31 Mar 2023 10:12:59 +0200 Subject: [PATCH 1792/2777] imm32/tests: Add some ImmSetOpenStatus tests. (cherry picked from commit feb427db1a59ed362797354eaabee4eb326de1b8) --- dlls/imm32/tests/imm32.c | 119 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 772f3183679..ae2b5b2a4f2 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4052,6 +4052,124 @@ static void test_ImmSetConversionStatus(void) ok_ret( 1, ImmUnlockIMC( default_himc ) ); } +static void test_ImmSetOpenStatus(void) +{ + const struct ime_call set_open_status_0_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS}, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS}, + }, + {0}, + }; + const struct ime_call set_open_status_1_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS}, + .todo = TRUE, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS}, + .todo = TRUE, + }, + {0}, + }; + HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + DWORD old_status, status; + INPUTCONTEXT *ctx; + + ok_ret( 0, ImmGetOpenStatus( 0 ) ); + old_status = ImmGetOpenStatus( default_himc ); + + ctx = ImmLockIMC( default_himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + ok_eq( old_status, ctx->fOpen, UINT, "%#x" ); + + hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + process_messages(); + + status = ImmGetOpenStatus( default_himc ); + ok_eq( old_status, status, UINT, "%#x" ); + ok_eq( old_status, ctx->fOpen, UINT, "%#x" ); + + ok_ret( 1, ImmSetOpenStatus( default_himc, 0 ) ); + status = ImmGetOpenStatus( default_himc ); + ok_eq( 0, status, UINT, "%#x" ); + ok_eq( 0, ctx->fOpen, UINT, "%#x" ); + + ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; + + if (!(hkl = ime_install())) goto cleanup; + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + process_messages(); + /* initial values are dependent on both old and new IME */ + ok_ret( 1, ImmSetOpenStatus( default_himc, 0 ) ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + status = ImmGetOpenStatus( default_himc ); + ok_eq( 0, status, UINT, "%#x" ); + ok_eq( 0, ctx->fOpen, UINT, "%#x" ); + + ok_seq( empty_sequence ); + ok_ret( 1, ImmSetOpenStatus( default_himc, 0xdeadbeef ) ); + ok_seq( set_open_status_0_seq ); + + status = ImmGetOpenStatus( default_himc ); + ok_eq( 0xdeadbeef, status, UINT, "%#x" ); + ok_eq( 0xdeadbeef, ctx->fOpen, UINT, "%#x" ); + + ok_seq( empty_sequence ); + ok_ret( 1, ImmSetOpenStatus( default_himc, ~0 ) ); + ok_seq( set_open_status_1_seq ); + + status = ImmGetOpenStatus( default_himc ); + todo_wine ok_eq( ~0, status, UINT, "%#x" ); + todo_wine ok_eq( ~0, ctx->fOpen, UINT, "%#x" ); + + /* status is cached between IME activations */ + + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + status = ImmGetOpenStatus( default_himc ); + todo_wine ok_eq( old_status, status, UINT, "%#x" ); + todo_wine ok_eq( old_status, ctx->fOpen, UINT, "%#x" ); + ok_ret( 1, ImmActivateLayout( hkl ) ); + status = ImmGetOpenStatus( default_himc ); + todo_wine ok_eq( 1, status, UINT, "%#x" ); + todo_wine ok_eq( 1, ctx->fOpen, UINT, "%#x" ); + ok_ret( 1, ImmSetOpenStatus( default_himc, 0 ) ); + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + status = ImmGetOpenStatus( default_himc ); + ok_eq( old_status, status, UINT, "%#x" ); + ok_eq( old_status, ctx->fOpen, UINT, "%#x" ); + + ime_cleanup( hkl, TRUE ); + +cleanup: + /* sanitize open status to some sane default */ + ok_ret( 1, ImmSetOpenStatus( default_himc, 0 ) ); + status = ImmGetOpenStatus( default_himc ); + ok_eq( 0, status, UINT, "%#x" ); + ok_eq( 0, ctx->fOpen, UINT, "%#x" ); + + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + ok_ret( 1, ImmUnlockIMC( default_himc ) ); +} + static void test_ImmProcessKey(void) { const struct ime_call process_key_seq[] = @@ -4649,6 +4767,7 @@ START_TEST(imm32) /* test these first to sanitize conversion / open statuses */ test_ImmSetConversionStatus(); + test_ImmSetOpenStatus(); test_ImmActivateLayout(); test_ImmCreateInputContext(); From dd30bf93abccc18afcfb265e856889362a28718a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 31 Mar 2023 11:32:16 +0200 Subject: [PATCH 1793/2777] imm32: Avoid recursing into ImeSelect calls. (cherry picked from commit ddfbc66fcfe5e6639352ec09cfffb753f5b6c675) --- dlls/imm32/imm.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 5cdf14cc9d9..e165544ba5e 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -568,24 +568,25 @@ static void ime_release( struct ime *ime ) LeaveCriticalSection( &ime_cs ); } -static void imc_release_ime( struct imc *imc ) +static void imc_release_ime( struct imc *imc, struct ime *ime ) { if (imc->ui_hwnd) DestroyWindow( imc->ui_hwnd ); imc->ui_hwnd = NULL; - imc->ime->pImeSelect( imc->handle, FALSE ); - ime_release( imc->ime ); - imc->ime = NULL; + ime->pImeSelect( imc->handle, FALSE ); + ime_release( ime ); ImmDestroyIMCC( imc->IMC.hPrivate ); } static struct ime *imc_select_ime( struct imc *imc ) { HKL hkl = GetKeyboardLayout( 0 ); + struct ime *ime; - if (imc->ime) + if ((ime = imc->ime)) { - if (imc->ime->hkl == hkl) return imc->ime; - imc_release_ime( imc ); + if (ime->hkl == hkl) return ime; + imc->ime = NULL; + imc_release_ime( imc, ime ); } if (!(imc->ime = ime_acquire( hkl ))) @@ -623,12 +624,13 @@ BOOL WINAPI ImmActivateLayout( HKL hkl ) static BOOL free_input_context_data( HIMC hIMC ) { struct imc *data = query_imc_data( hIMC ); + struct ime *ime; if (!data) return FALSE; TRACE( "Destroying %p\n", hIMC ); - if (data->ime) imc_release_ime( data ); + if ((ime = imc_select_ime( data ))) imc_release_ime( data, ime ); ImmDestroyIMCC( data->IMC.hCompStr ); ImmDestroyIMCC( data->IMC.hCandInfo ); From b896c3c43af813ded46c74bbe46dd68311bbe66c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 31 Mar 2023 11:32:52 +0200 Subject: [PATCH 1794/2777] imm32/tests: Init INPUTCONTEXT status in ImeSelect. (cherry picked from commit 7d03937abe899db810c983779f2566b94d787e8a) --- dlls/imm32/tests/imm32.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index ae2b5b2a4f2..76ef3bab521 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2477,6 +2477,7 @@ static void test_ImmDisableIME(void) #define ime_trace( msg, ... ) if (winetest_debug > 1) trace( "%04lx:%s " msg, GetCurrentThreadId(), __func__, ## __VA_ARGS__ ) +static BOOL ImeSelect_init_status; static BOOL todo_ImeInquire; DEFINE_EXPECT( ImeInquire ); static BOOL todo_ImeDestroy; @@ -2899,8 +2900,21 @@ static BOOL WINAPI ime_ImeSelect( HIMC himc, BOOL select ) .hkl = GetKeyboardLayout( 0 ), .himc = himc, .func = IME_SELECT, .select = select }; + INPUTCONTEXT *ctx; + ime_trace( "himc %p, select %d\n", himc, select ); ime_calls[ime_call_count++] = call; + + if (ImeSelect_init_status && select) + { + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + ctx->fOpen = ~0; + ctx->fdwConversion = ~0; + ctx->fdwSentence = ~0; + ImmUnlockIMC( himc ); + } + return TRUE; } @@ -4300,10 +4314,15 @@ static void test_ImmActivateLayout(void) .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_OPENSTATUSWINDOW}, .todo = TRUE, }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS}, + .todo = TRUE, + }, { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE}, - .todo = TRUE, .broken = (default_hkl == (HKL)0x04120412), + .todo = TRUE, }, { .hkl = expect_ime, .himc = default_himc, @@ -4768,6 +4787,7 @@ START_TEST(imm32) /* test these first to sanitize conversion / open statuses */ test_ImmSetConversionStatus(); test_ImmSetOpenStatus(); + ImeSelect_init_status = TRUE; test_ImmActivateLayout(); test_ImmCreateInputContext(); From da1916e67f4991a30cdbc9c2b596eb86074c5eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 23 Mar 2023 17:25:43 +0100 Subject: [PATCH 1795/2777] imm32/tests: Add some ImeSetActiveContext tests. (cherry picked from commit 3ed1bb2464fa15382933bfabb1ec8df049d41621) --- dlls/imm32/tests/imm32.c | 128 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 2 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 76ef3bab521..870e58c89db 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2504,6 +2504,7 @@ enum ime_function IME_SELECT = 1, IME_NOTIFY, IME_PROCESS_KEY, + IME_SET_ACTIVE_CONTEXT, MSG_IME_UI, }; @@ -2528,6 +2529,10 @@ struct ime_call LPARAM key_data; } process_key; struct + { + int flag; + } set_active_context; + struct { UINT msg; WPARAM wparam; @@ -2568,6 +2573,9 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected if ((ret = expected->process_key.vkey - received->process_key.vkey)) goto done; if ((ret = expected->process_key.key_data - received->process_key.key_data)) goto done; break; + case IME_SET_ACTIVE_CONTEXT: + if ((ret = expected->set_active_context.flag - received->set_active_context.flag)) goto done; + break; case MSG_IME_UI: if ((ret = expected->message.msg - received->message.msg)) goto done; if ((ret = (expected->message.wparam - received->message.wparam))) goto done; @@ -2595,6 +2603,11 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected ok_(file, line)( !ret, "got hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, key_data %#Ix\n", received->hkl, received->himc, received->process_key.vkey, received->process_key.key_data ); return ret; + case IME_SET_ACTIVE_CONTEXT: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", received->hkl, received->himc, + received->set_active_context.flag ); + return ret; case MSG_IME_UI: todo_wine_if( expected->todo ) ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, @@ -2619,6 +2632,11 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected ok_(file, line)( !ret, "hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, key_data %#Ix\n", expected->hkl, expected->himc, expected->process_key.vkey, expected->process_key.key_data ); break; + case IME_SET_ACTIVE_CONTEXT: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", expected->hkl, expected->himc, + expected->set_active_context.flag ); + break; case MSG_IME_UI: todo_wine_if( expected->todo ) ok_(file, line)( !ret, "hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, @@ -2920,9 +2938,14 @@ static BOOL WINAPI ime_ImeSelect( HIMC himc, BOOL select ) static BOOL WINAPI ime_ImeSetActiveContext( HIMC himc, BOOL flag ) { + struct ime_call call = + { + .hkl = GetKeyboardLayout( 0 ), .himc = himc, + .func = IME_SET_ACTIVE_CONTEXT, .set_active_context = {.flag = flag} + }; ime_trace( "himc %p, flag %#x\n", himc, flag ); - ok( 0, "unexpected call\n" ); - return FALSE; + ime_calls[ime_call_count++] = call; + return TRUE; } static BOOL WINAPI ime_ImeSetCompositionString( HIMC himc, DWORD index, const void *comp, DWORD comp_len, @@ -4753,6 +4776,106 @@ static void test_DefWindowProc(void) ime_call_count = 0; } +static void test_ImmSetActiveContext(void) +{ + const struct ime_call activate_0_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_SET_ACTIVE_CONTEXT, .set_active_context = {.flag = 1} + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_SETCONTEXT, .wparam = 1, .lparam = ISC_SHOWUIALL} + }, + {0}, + }; + const struct ime_call deactivate_0_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_SET_ACTIVE_CONTEXT, .set_active_context = {.flag = 0} + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_SETCONTEXT, .wparam = 0, .lparam = ISC_SHOWUIALL} + }, + {0}, + }; + struct ime_call deactivate_1_seq[] = + { + { + .hkl = expect_ime, .himc = 0/*himc*/, + .func = IME_SELECT, .select = 1, + }, + { + .hkl = expect_ime, .himc = 0/*himc*/, + .func = IME_SET_ACTIVE_CONTEXT, .set_active_context = {.flag = 0} + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_SETCONTEXT, .wparam = 0, .lparam = ISC_SHOWUIALL} + }, + {0}, + }; + struct ime_call activate_1_seq[] = + { + { + .hkl = expect_ime, .himc = 0/*himc*/, + .func = IME_SET_ACTIVE_CONTEXT, .set_active_context = {.flag = 1} + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_SETCONTEXT, .wparam = 1, .lparam = ISC_SHOWUIALL} + }, + {0}, + }; + HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HIMC himc; + + ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; + + if (!(hkl = ime_install())) return; + + hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + SetLastError( 0xdeadbeef ); + ok_ret( 1, ImmSetActiveContext( hwnd, default_himc, TRUE ) ); + ok_seq( activate_0_seq ); + ok_ret( 0, GetLastError() ); + ok_ret( 1, ImmSetActiveContext( hwnd, default_himc, TRUE ) ); + ok_seq( activate_0_seq ); + ok_ret( 1, ImmSetActiveContext( hwnd, default_himc, FALSE ) ); + ok_seq( deactivate_0_seq ); + + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ok_ret( 1, ImmSetActiveContext( hwnd, himc, FALSE ) ); + deactivate_1_seq[0].himc = himc; + deactivate_1_seq[1].himc = himc; + ok_seq( deactivate_1_seq ); + ok_ret( 1, ImmSetActiveContext( hwnd, himc, TRUE ) ); + activate_1_seq[0].himc = himc; + ok_seq( activate_1_seq ); + ok_ret( 1, ImmDestroyContext( himc ) ); + + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + + ime_cleanup( hkl, TRUE ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); @@ -4793,6 +4916,7 @@ START_TEST(imm32) test_ImmCreateInputContext(); test_ImmProcessKey(); test_DefWindowProc(); + test_ImmSetActiveContext(); if (init()) { From 2ba363313855123d5bb31a529d5b3584d1edb447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 31 Mar 2023 12:50:14 +0200 Subject: [PATCH 1796/2777] imm32/tests: Add some spurious IME select calls. Seen with the Korean locale from time to time, probably caused by some uninitialized input context data. (cherry picked from commit 4a52781ec97b0d5094d0e1e47012a891ee5decfc) --- dlls/imm32/tests/imm32.c | 42 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 870e58c89db..bad9e5185a5 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4545,6 +4545,26 @@ static void test_ImmCreateInputContext(void) }; struct ime_call select1_seq[] = { + { + .hkl = expect_ime, .himc = 0/*himc[0]*/, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS}, + .todo = TRUE, .flaky_himc = TRUE, .broken = TRUE /* sometimes */, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS}, + .todo = TRUE, .flaky_himc = TRUE, .broken = TRUE /* sometimes */, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS}, + .todo = TRUE, .broken = TRUE /* sometimes */, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE}, + .todo = TRUE, .broken = TRUE /* sometimes */, + }, { .hkl = expect_ime, .himc = 0/*himc[1]*/, .func = IME_SELECT, .select = 1, @@ -4659,7 +4679,8 @@ static void test_ImmCreateInputContext(void) ok_seq( empty_sequence ); ctx = ImmLockIMC( himc[1] ); ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); - select1_seq[0].himc = himc[1]; + select1_seq[0].himc = himc[0]; + select1_seq[4].himc = himc[1]; ok_seq( select1_seq ); ok_ret( 1, ImmUnlockIMC( himc[1] ) ); @@ -4804,6 +4825,21 @@ static void test_ImmSetActiveContext(void) }; struct ime_call deactivate_1_seq[] = { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS}, + .todo = TRUE, .flaky_himc = TRUE, .broken = TRUE /* sometimes */, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS}, + .todo = TRUE, .broken = TRUE /* sometimes */, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE}, + .todo = TRUE, .broken = TRUE /* sometimes */, + }, { .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_SELECT, .select = 1, @@ -4859,8 +4895,8 @@ static void test_ImmSetActiveContext(void) himc = ImmCreateContext(); ok_ne( NULL, himc, HIMC, "%p" ); ok_ret( 1, ImmSetActiveContext( hwnd, himc, FALSE ) ); - deactivate_1_seq[0].himc = himc; - deactivate_1_seq[1].himc = himc; + deactivate_1_seq[3].himc = himc; + deactivate_1_seq[4].himc = himc; ok_seq( deactivate_1_seq ); ok_ret( 1, ImmSetActiveContext( hwnd, himc, TRUE ) ); activate_1_seq[0].himc = himc; From 7d1260ba2a17ef35a2b9bbb4a9f60c0d9d0b158a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 24 Mar 2023 23:29:56 +0100 Subject: [PATCH 1797/2777] imm32/tests: Add some ImmRequestMessageW tests. (cherry picked from commit e6e63828d36f143ac754fd6e12fca8ac9081b674) --- dlls/imm32/tests/imm32.c | 174 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index bad9e5185a5..ace3e5fc1fb 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2506,6 +2506,7 @@ enum ime_function IME_PROCESS_KEY, IME_SET_ACTIVE_CONTEXT, MSG_IME_UI, + MSG_TEST_WIN, }; struct ime_call @@ -2577,6 +2578,7 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected if ((ret = expected->set_active_context.flag - received->set_active_context.flag)) goto done; break; case MSG_IME_UI: + case MSG_TEST_WIN: if ((ret = expected->message.msg - received->message.msg)) goto done; if ((ret = (expected->message.wparam - received->message.wparam))) goto done; if ((ret = (expected->message.lparam - received->message.lparam))) goto done; @@ -2613,6 +2615,10 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, received->himc, received->message.msg, received->message.wparam, received->message.lparam ); return ret; + case MSG_TEST_WIN: + ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, + received->himc, received->message.msg, received->message.wparam, received->message.lparam ); + return ret; } switch (expected->func) @@ -2642,6 +2648,10 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected ok_(file, line)( !ret, "hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); break; + case MSG_TEST_WIN: + ok_(file, line)( !ret, "hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, + expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); + break; } return 0; @@ -2717,6 +2727,22 @@ static LRESULT CALLBACK ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, return DefWindowProcW( hwnd, msg, wparam, lparam ); } +static LRESULT CALLBACK test_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + struct ime_call call = + { + .hkl = GetKeyboardLayout( 0 ), .himc = ImmGetContext( hwnd ), + .func = MSG_TEST_WIN, .message = {.msg = msg, .wparam = wparam, .lparam = lparam} + }; + + ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + + if (ignore_message( msg )) return DefWindowProcW( hwnd, msg, wparam, lparam ); + + ime_calls[ime_call_count++] = call; + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + static WNDCLASSEXW ime_ui_class = { .cbSize = sizeof(WNDCLASSEXW), @@ -2726,6 +2752,13 @@ static WNDCLASSEXW ime_ui_class = .lpszClassName = L"WineTestIME", }; +static WNDCLASSEXW test_class = +{ + .cbSize = sizeof(WNDCLASSEXW), + .lpfnWndProc = test_window_proc, + .lpszClassName = L"WineTest", +}; + static BOOL WINAPI ime_ImeConfigure( HKL hkl, HWND hwnd, DWORD mode, void *data ) { ime_trace( "hkl %p, hwnd %p, mode %lu, data %p\n", hkl, hwnd, mode, data ); @@ -4912,10 +4945,148 @@ static void test_ImmSetActiveContext(void) ime_call_count = 0; } +static void test_ImmRequestMessage(void) +{ + struct ime_call composition_window_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_REQUEST, .wparam = IMR_COMPOSITIONWINDOW, .lparam = 0/*&comp_form*/} + }, + {0}, + }; + struct ime_call candidate_window_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_REQUEST, .wparam = IMR_CANDIDATEWINDOW, .lparam = 0/*&cand_form*/} + }, + {0}, + }; + struct ime_call composition_font_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_REQUEST, .wparam = IMR_COMPOSITIONFONT, .lparam = 0/*&log_font*/} + }, + {0}, + }; + struct ime_call reconvert_string_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_REQUEST, .wparam = IMR_RECONVERTSTRING, .lparam = 0/*&reconv*/} + }, + {0}, + }; + struct ime_call confirm_reconvert_string_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_REQUEST, .wparam = IMR_CONFIRMRECONVERTSTRING, .lparam = 0/*&reconv*/} + }, + {0}, + }; + struct ime_call query_char_position_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_REQUEST, .wparam = IMR_QUERYCHARPOSITION, .lparam = 0/*&char_pos*/} + }, + {0}, + }; + struct ime_call document_feed_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_REQUEST, .wparam = IMR_DOCUMENTFEED, .lparam = 0/*&reconv*/} + }, + {0}, + }; + HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + COMPOSITIONFORM comp_form = {0}; + IMECHARPOSITION char_pos = {0}; + RECONVERTSTRING reconv = {0}; + CANDIDATEFORM cand_form = {0}; + LOGFONTW log_font = {0}; + INPUTCONTEXT *ctx; + HIMC himc; + + if (!(hkl = ime_install())) return; + + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + + ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + ok_ret( 0, ImmRequestMessageW( default_himc, 0xdeadbeef, 0 ) ); + todo_wine ok_seq( empty_sequence ); + ok_ret( 0, ImmRequestMessageW( default_himc, IMR_COMPOSITIONWINDOW, (LPARAM)&comp_form ) ); + composition_window_seq[0].message.lparam = (LPARAM)&comp_form; + ok_seq( composition_window_seq ); + ok_ret( 0, ImmRequestMessageW( default_himc, IMR_CANDIDATEWINDOW, (LPARAM)&cand_form ) ); + candidate_window_seq[0].message.lparam = (LPARAM)&cand_form; + ok_seq( candidate_window_seq ); + ok_ret( 0, ImmRequestMessageW( default_himc, IMR_COMPOSITIONFONT, (LPARAM)&log_font ) ); + composition_font_seq[0].message.lparam = (LPARAM)&log_font; + ok_seq( composition_font_seq ); + ok_ret( 0, ImmRequestMessageW( default_himc, IMR_RECONVERTSTRING, (LPARAM)&reconv ) ); + todo_wine ok_seq( empty_sequence ); + reconv.dwSize = sizeof(RECONVERTSTRING); + ok_ret( 0, ImmRequestMessageW( default_himc, IMR_RECONVERTSTRING, (LPARAM)&reconv ) ); + reconvert_string_seq[0].message.lparam = (LPARAM)&reconv; + ok_seq( reconvert_string_seq ); + ok_ret( 0, ImmRequestMessageW( default_himc, IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) ); + confirm_reconvert_string_seq[0].message.lparam = (LPARAM)&reconv; + ok_seq( confirm_reconvert_string_seq ); + ok_ret( 0, ImmRequestMessageW( default_himc, IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) ); + query_char_position_seq[0].message.lparam = (LPARAM)&char_pos; + ok_seq( query_char_position_seq ); + ok_ret( 0, ImmRequestMessageW( default_himc, IMR_DOCUMENTFEED, (LPARAM)&reconv ) ); + document_feed_seq[0].message.lparam = (LPARAM)&reconv; + ok_seq( document_feed_seq ); + + ok_ret( 0, ImmRequestMessageW( himc, IMR_CANDIDATEWINDOW, (LPARAM)&cand_form ) ); + ok_seq( empty_sequence ); + ok_ret( 1, ImmSetActiveContext( hwnd, himc, TRUE ) ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + ok_ret( 0, ImmRequestMessageW( himc, IMR_CANDIDATEWINDOW, (LPARAM)&cand_form ) ); + candidate_window_seq[0].message.lparam = (LPARAM)&cand_form; + ok_seq( candidate_window_seq ); + ok_ret( 0, ImmRequestMessageW( default_himc, IMR_CANDIDATEWINDOW, (LPARAM)&cand_form ) ); + ok_seq( candidate_window_seq ); + + ok_ret( 1, ImmUnlockIMC( himc ) ); + ok_ret( 1, ImmDestroyContext( himc ) ); + + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + + ime_cleanup( hkl, TRUE ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); + test_class.hInstance = GetModuleHandleW( NULL ); + RegisterClassExW( &test_class ); + if (!is_ime_enabled()) { win_skip("IME support not implemented\n"); @@ -4953,6 +5124,7 @@ START_TEST(imm32) test_ImmProcessKey(); test_DefWindowProc(); test_ImmSetActiveContext(); + test_ImmRequestMessage(); if (init()) { @@ -4985,4 +5157,6 @@ START_TEST(imm32) test_ImmDisableIME(); } cleanup(); + + UnregisterClassW( test_class.lpszClassName, test_class.hInstance ); } From 21d6ddafc23a3c545af4c52ad5c3af260c111ab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 31 Mar 2023 12:12:26 +0200 Subject: [PATCH 1798/2777] imm32/tests: Add some ImmGetCandidateList(W|A) tests. (cherry picked from commit 18d7be24ce398759ae0ca9a45db67926b0e7be30) --- dlls/imm32/tests/imm32.c | 156 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index ace3e5fc1fb..23f9ae1a554 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -86,6 +86,31 @@ extern BOOL WINAPI ImmFreeLayout(HKL); extern BOOL WINAPI ImmLoadIME(HKL); extern BOOL WINAPI ImmActivateLayout(HKL); +#define check_member_( file, line, val, exp, fmt, member ) \ + ok_(file, line)( (val).member == (exp).member, "got " #member " " fmt "\n", (val).member ) +#define check_member( val, exp, fmt, member ) \ + check_member_( __FILE__, __LINE__, val, exp, fmt, member ) + +#define check_candidate_list( a, b ) check_candidate_list_( __LINE__, a, b, TRUE ) +static void check_candidate_list_( int line, CANDIDATELIST *list, const CANDIDATELIST *expect, BOOL unicode ) +{ + UINT i; + + check_member_( __FILE__, line, *list, *expect, "%lu", dwSize ); + check_member_( __FILE__, line, *list, *expect, "%lu", dwStyle ); + check_member_( __FILE__, line, *list, *expect, "%lu", dwCount ); + check_member_( __FILE__, line, *list, *expect, "%lu", dwSelection ); + check_member_( __FILE__, line, *list, *expect, "%lu", dwPageStart ); + check_member_( __FILE__, line, *list, *expect, "%lu", dwPageSize ); + for (i = 0; i < list->dwCount && i < expect->dwCount; ++i) + { + void *list_str = (BYTE *)list + list->dwOffset[i], *expect_str = (BYTE *)expect + expect->dwOffset[i]; + check_member_( __FILE__, line, *list, *expect, "%lu", dwOffset[i] ); + if (unicode) ok_( __FILE__, line )( !wcscmp( list_str, expect_str ), "got %s\n", debugstr_w(list_str) ); + else ok_( __FILE__, line )( !strcmp( list_str, expect_str ), "got %s\n", debugstr_a(list_str) ); + } +} + #define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE, enabled_ ## func = FALSE @@ -5080,6 +5105,134 @@ static void test_ImmRequestMessage(void) ime_call_count = 0; } +static void test_ImmGetCandidateList( BOOL unicode ) +{ + char buffer[512], expect_bufW[512] = {0}, expect_bufA[512] = {0}; + CANDIDATELIST *cand_list = (CANDIDATELIST *)buffer, *expect_listW, *expect_listA; + HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + CANDIDATEINFO *cand_info; + INPUTCONTEXT *ctx; + HIMC himc; + + expect_listW = (CANDIDATELIST *)expect_bufW; + expect_listW->dwSize = offsetof(CANDIDATELIST, dwOffset[2]) + 32 * sizeof(WCHAR); + expect_listW->dwStyle = 0xdeadbeef; + expect_listW->dwCount = 2; + expect_listW->dwSelection = 3; + expect_listW->dwPageStart = 4; + expect_listW->dwPageSize = 5; + expect_listW->dwOffset[0] = offsetof(CANDIDATELIST, dwOffset[2]) + 2 * sizeof(WCHAR); + expect_listW->dwOffset[1] = offsetof(CANDIDATELIST, dwOffset[2]) + 16 * sizeof(WCHAR); + wcscpy( (WCHAR *)(expect_bufW + expect_listW->dwOffset[0]), L"Candidate 1" ); + wcscpy( (WCHAR *)(expect_bufW + expect_listW->dwOffset[1]), L"Candidate 2" ); + + expect_listA = (CANDIDATELIST *)expect_bufA; + expect_listA->dwSize = offsetof(CANDIDATELIST, dwOffset[2]) + 32; + expect_listA->dwStyle = 0xdeadbeef; + expect_listA->dwCount = 2; + expect_listA->dwSelection = 3; + expect_listA->dwPageStart = 4; + expect_listA->dwPageSize = 5; + expect_listA->dwOffset[0] = offsetof(CANDIDATELIST, dwOffset[2]) + 2; + expect_listA->dwOffset[1] = offsetof(CANDIDATELIST, dwOffset[2]) + 16; + strcpy( (char *)(expect_bufA + expect_listA->dwOffset[0]), "Candidate 1" ); + strcpy( (char *)(expect_bufA + expect_listA->dwOffset[1]), "Candidate 2" ); + + winetest_push_context( unicode ? "unicode" : "ansi" ); + + /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ + ime_info.fdwProperty = IME_PROP_END_UNLOAD; + if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE; + + if (!(hkl = ime_install())) goto cleanup; + + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + ok_ret( 0, ImmGetCandidateListW( default_himc, 0, NULL, 0 ) ); + ok_seq( empty_sequence ); + ok_ret( 0, ImmGetCandidateListW( default_himc, 1, NULL, 0 ) ); + ok_seq( empty_sequence ); + ok_ret( 0, ImmGetCandidateListW( default_himc, 0, cand_list, sizeof(buffer) ) ); + ok_seq( empty_sequence ); + + ok_ret( 0, ImmGetCandidateListW( himc, 0, cand_list, sizeof(buffer) ) ); + ok_seq( empty_sequence ); + + todo_wine ok_seq( empty_sequence ); + ctx->hCandInfo = ImmReSizeIMCC( ctx->hCandInfo, sizeof(*cand_info) + sizeof(buffer) ); + ok( !!ctx->hCandInfo, "ImmReSizeIMCC failed, error %lu\n", GetLastError() ); + + cand_info = ImmLockIMCC( ctx->hCandInfo ); + ok( !!cand_info, "ImmLockIMCC failed, error %lu\n", GetLastError() ); + cand_info->dwCount = 1; + cand_info->dwOffset[0] = sizeof(*cand_info); + if (unicode) memcpy( cand_info + 1, expect_bufW, sizeof(expect_bufW) ); + else memcpy( cand_info + 1, expect_bufA, sizeof(expect_bufA) ); + ok_ret( 0, ImmUnlockIMCC( ctx->hCandInfo ) ); + + ok_ret( (unicode ? 96 : 80), ImmGetCandidateListW( himc, 0, NULL, 0 ) ); + ok_seq( empty_sequence ); + ok_ret( 0, ImmGetCandidateListW( himc, 1, NULL, 0 ) ); + ok_seq( empty_sequence ); + memset( buffer, 0xcd, sizeof(buffer) ); + ok_ret( (unicode ? 96 : 80), ImmGetCandidateListW( himc, 0, cand_list, sizeof(buffer) ) ); + ok_seq( empty_sequence ); + + if (!unicode) + { + expect_listW->dwSize = offsetof(CANDIDATELIST, dwOffset[2]) + 24 * sizeof(WCHAR); + expect_listW->dwOffset[0] = offsetof(CANDIDATELIST, dwOffset[2]); + expect_listW->dwOffset[1] = offsetof(CANDIDATELIST, dwOffset[2]) + 12 * sizeof(WCHAR); + wcscpy( (WCHAR *)(expect_bufW + expect_listW->dwOffset[0]), L"Candidate 1" ); + wcscpy( (WCHAR *)(expect_bufW + expect_listW->dwOffset[1]), L"Candidate 2" ); + } + check_candidate_list_( __LINE__, cand_list, expect_listW, TRUE ); + + ok_ret( (unicode ? 56 : 64), ImmGetCandidateListA( himc, 0, NULL, 0 ) ); + ok_seq( empty_sequence ); + ok_ret( 0, ImmGetCandidateListA( himc, 1, NULL, 0 ) ); + ok_seq( empty_sequence ); + memset( buffer, 0xcd, sizeof(buffer) ); + ok_ret( (unicode ? 56 : 64), ImmGetCandidateListA( himc, 0, cand_list, sizeof(buffer) ) ); + ok_seq( empty_sequence ); + + if (unicode) + { + expect_listA->dwSize = offsetof(CANDIDATELIST, dwOffset[2]) + 24; + expect_listA->dwOffset[0] = offsetof(CANDIDATELIST, dwOffset[2]); + expect_listA->dwOffset[1] = offsetof(CANDIDATELIST, dwOffset[2]) + 12; + strcpy( (char *)(expect_bufA + expect_listA->dwOffset[0]), "Candidate 1" ); + strcpy( (char *)(expect_bufA + expect_listA->dwOffset[1]), "Candidate 2" ); + } + check_candidate_list_( __LINE__, cand_list, expect_listA, FALSE ); + + ok_ret( 1, ImmUnlockIMC( himc ) ); + ok_ret( 1, ImmDestroyContext( himc ) ); + + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + + ime_cleanup( hkl, TRUE ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + +cleanup: + winetest_pop_context(); +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); @@ -5126,6 +5279,9 @@ START_TEST(imm32) test_ImmSetActiveContext(); test_ImmRequestMessage(); + test_ImmGetCandidateList( TRUE ); + test_ImmGetCandidateList( FALSE ); + if (init()) { test_ImmNotifyIME(); From bae2a23262954f0078ba9cad31b0a5d2318af2d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 31 Mar 2023 07:59:03 +0200 Subject: [PATCH 1799/2777] imm32/tests: Add some ImmGetCandidateListCount(W|A) tests. (cherry picked from commit 91bb0bf54511c7376aa0e50f77a8bb21d1cf592c) --- dlls/imm32/tests/imm32.c | 75 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 23f9ae1a554..aa7e925f529 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -5233,6 +5233,79 @@ static void test_ImmGetCandidateList( BOOL unicode ) winetest_pop_context(); } +static void test_ImmGetCandidateListCount( BOOL unicode ) +{ + HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + CANDIDATEINFO *cand_info; + INPUTCONTEXT *ctx; + DWORD count; + HIMC himc; + + winetest_push_context( unicode ? "unicode" : "ansi" ); + + /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ + ime_info.fdwProperty = IME_PROP_END_UNLOAD; + if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE; + + if (!(hkl = ime_install())) goto cleanup; + + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + ok_ret( 144, ImmGetCandidateListCountW( default_himc, &count ) ); + ok_eq( 0, count, UINT, "%u" ); + ok_seq( empty_sequence ); + ok_ret( 144, ImmGetCandidateListCountA( default_himc, &count ) ); + ok_eq( 0, count, UINT, "%u" ); + ok_seq( empty_sequence ); + + ok_ret( 144, ImmGetCandidateListCountW( himc, &count ) ); + ok_eq( 0, count, UINT, "%u" ); + ok_seq( empty_sequence ); + ok_ret( 144, ImmGetCandidateListCountA( himc, &count ) ); + ok_eq( 0, count, UINT, "%u" ); + ok_seq( empty_sequence ); + + cand_info = ImmLockIMCC( ctx->hCandInfo ); + ok( !!cand_info, "ImmLockIMCC failed, error %lu\n", GetLastError() ); + cand_info->dwCount = 1; + ok_ret( 0, ImmUnlockIMCC( ctx->hCandInfo ) ); + + todo_wine_if(!unicode) + ok_ret( (unicode ? 144 : 172), ImmGetCandidateListCountW( himc, &count ) ); + ok_eq( 1, count, UINT, "%u" ); + ok_seq( empty_sequence ); + todo_wine_if(unicode) + ok_ret( (unicode ? 172 : 144), ImmGetCandidateListCountA( himc, &count ) ); + ok_eq( 1, count, UINT, "%u" ); + ok_seq( empty_sequence ); + + ok_ret( 1, ImmUnlockIMC( himc ) ); + ok_ret( 1, ImmDestroyContext( himc ) ); + + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + + ime_cleanup( hkl, TRUE ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + +cleanup: + winetest_pop_context(); +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); @@ -5281,6 +5354,8 @@ START_TEST(imm32) test_ImmGetCandidateList( TRUE ); test_ImmGetCandidateList( FALSE ); + test_ImmGetCandidateListCount( TRUE ); + test_ImmGetCandidateListCount( FALSE ); if (init()) { From 3ecf2c066209b382568f56a80b22c313ea0f1f7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 30 Mar 2023 22:51:14 +0200 Subject: [PATCH 1800/2777] imm32/tests: Add some ImmGetCandidateWindow tests. (cherry picked from commit 19186b506321d66b0af6449b0c05890fe0179a31) --- dlls/imm32/tests/imm32.c | 96 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index aa7e925f529..c18c76a71a2 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -91,6 +91,18 @@ extern BOOL WINAPI ImmActivateLayout(HKL); #define check_member( val, exp, fmt, member ) \ check_member_( __FILE__, __LINE__, val, exp, fmt, member ) +#define check_member_point_( file, line, val, exp, member ) \ + ok_(file, line)( !memcmp( &(val).member, &(exp).member, sizeof(POINT) ), \ + "got " #member " %s\n", wine_dbgstr_point( &(val).member ) ) +#define check_member_point( val, exp, member ) \ + check_member_point_( __FILE__, __LINE__, val, exp, member ) + +#define check_member_rect_( file, line, val, exp, member ) \ + ok_(file, line)( !memcmp( &(val).member, &(exp).member, sizeof(RECT) ), \ + "got " #member " %s\n", wine_dbgstr_rect( &(val).member ) ) +#define check_member_rect( val, exp, member ) \ + check_member_rect_( __FILE__, __LINE__, val, exp, member ) + #define check_candidate_list( a, b ) check_candidate_list_( __LINE__, a, b, TRUE ) static void check_candidate_list_( int line, CANDIDATELIST *list, const CANDIDATELIST *expect, BOOL unicode ) { @@ -111,6 +123,15 @@ static void check_candidate_list_( int line, CANDIDATELIST *list, const CANDIDAT } } +#define check_candidate_form( a, b ) check_candidate_form_( __LINE__, a, b ) +static void check_candidate_form_( int line, CANDIDATEFORM *form, const CANDIDATEFORM *expect ) +{ + check_member_( __FILE__, line, *form, *expect, "%#lx", dwIndex ); + check_member_( __FILE__, line, *form, *expect, "%#lx", dwStyle ); + check_member_point_( __FILE__, line, *form, *expect, ptCurrentPos ); + check_member_rect_( __FILE__, line, *form, *expect, rcArea ); +} + #define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE, enabled_ ## func = FALSE @@ -5306,6 +5327,80 @@ static void test_ImmGetCandidateListCount( BOOL unicode ) winetest_pop_context(); } +static void test_ImmGetCandidateWindow(void) +{ + HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + const CANDIDATEFORM expect_form = + { + .dwIndex = 0xdeadbeef, + .dwStyle = 0xfeedcafe, + .ptCurrentPos = {.x = 123, .y = 456}, + .rcArea = {.left = 1, .top = 2, .right = 3, .bottom = 4}, + }; + CANDIDATEFORM cand_form; + INPUTCONTEXT *ctx; + HIMC himc; + + ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; + + if (!(hkl = ime_install())) return; + + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + memset( &cand_form, 0xcd, sizeof(cand_form) ); + ok_ret( 0, ImmGetCandidateWindow( default_himc, 0, &cand_form ) ); + ok_eq( 0xcdcdcdcd, cand_form.dwIndex, UINT, "%u" ); + ok_ret( 0, ImmGetCandidateWindow( default_himc, 1, &cand_form ) ); + ok_eq( 0xcdcdcdcd, cand_form.dwIndex, UINT, "%u" ); + ok_ret( 0, ImmGetCandidateWindow( default_himc, 2, &cand_form ) ); + ok_eq( 0xcdcdcdcd, cand_form.dwIndex, UINT, "%u" ); + ok_ret( 0, ImmGetCandidateWindow( default_himc, 3, &cand_form ) ); + ok_eq( 0xcdcdcdcd, cand_form.dwIndex, UINT, "%u" ); + todo_wine ok_ret( 1, ImmGetCandidateWindow( default_himc, 4, &cand_form ) ); + ok_seq( empty_sequence ); + + ok_ret( 0, ImmGetCandidateWindow( himc, 0, &cand_form ) ); + ok_seq( empty_sequence ); + + todo_wine ok_seq( empty_sequence ); + ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); + ctx->cfCandForm[0] = expect_form; + + todo_wine ok_ret( 1, ImmGetCandidateWindow( himc, 0, &cand_form ) ); + todo_wine check_candidate_form( &cand_form, &expect_form ); + ok_seq( empty_sequence ); + + todo_wine ok_seq( empty_sequence ); + ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); + ctx->cfCandForm[0].dwIndex = -1; + + ok_ret( 0, ImmGetCandidateWindow( himc, 0, &cand_form ) ); + ok_seq( empty_sequence ); + + ok_ret( 1, ImmUnlockIMC( himc ) ); + ok_ret( 1, ImmDestroyContext( himc ) ); + + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + + ime_cleanup( hkl, TRUE ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); @@ -5356,6 +5451,7 @@ START_TEST(imm32) test_ImmGetCandidateList( FALSE ); test_ImmGetCandidateListCount( TRUE ); test_ImmGetCandidateListCount( FALSE ); + test_ImmGetCandidateWindow(); if (init()) { From d9f35d78cf77f0042d3392c628b9b8eeb9daf953 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 2 Apr 2023 11:24:08 +0200 Subject: [PATCH 1801/2777] winex11: Remove non-CJK specific XIC creation logic. (cherry picked from commit 41fa67c69ed040aabbfadb5add1e926ccb097bfc) --- dlls/winex11.drv/xim.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index d736dd80345..e04bf91206c 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -457,33 +457,10 @@ XIC X11DRV_CreateIC(XIM xim, struct x11drv_win_data *data) XIC xic; XICCallback destroy = {(XPointer)data, X11DRV_DestroyIC}; XICCallback P_StateNotifyCB, P_StartCB, P_DoneCB, P_DrawCB, P_CaretCB; - LCID lcid; Window win = data->whole_window; XFontSet fontSet = x11drv_thread_data()->font_set; - TRACE("xim = %p\n", xim); - - lcid = NtCurrentTeb()->CurrentLocale; - if (!lcid) NtQueryDefaultLocale( TRUE, &lcid ); - - /* use complex and slow XIC initialization method only for CJK */ - switch (PRIMARYLANGID(LANGIDFROMLCID(lcid))) - { - case LANG_CHINESE: - case LANG_JAPANESE: - case LANG_KOREAN: - break; - - default: - xic = XCreateIC(xim, - XNInputStyle, XIMPreeditNothing | XIMStatusNothing, - XNClientWindow, win, - XNFocusWindow, win, - XNDestroyCallback, &destroy, - NULL); - data->xic = xic; - return xic; - } + TRACE( "xim %p, data %p\n", xim, data ); /* create callbacks */ P_StateNotifyCB.client_data = (XPointer)data; From 5d7c1cc6246d89650c042f063b274eac109fdee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 2 Apr 2023 11:17:29 +0200 Subject: [PATCH 1802/2777] winex11: Always create XIC preedit and status attributes. (cherry picked from commit a1f5def2dc22e184deb0beb47640b4138ef2f581) --- dlls/winex11.drv/xim.c | 95 +++++++----------------------------------- 1 file changed, 14 insertions(+), 81 deletions(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index e04bf91206c..59a273d9ed3 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -452,8 +452,7 @@ static BOOL X11DRV_DestroyIC(XIC xic, XPointer p, XPointer data) XIC X11DRV_CreateIC(XIM xim, struct x11drv_win_data *data) { XPoint spot = {0}; - XVaNestedList preedit = NULL; - XVaNestedList status = NULL; + XVaNestedList preedit, status; XIC xic; XICCallback destroy = {(XPointer)data, X11DRV_DestroyIC}; XICCallback P_StateNotifyCB, P_StartCB, P_DoneCB, P_DrawCB, P_CaretCB; @@ -474,88 +473,22 @@ XIC X11DRV_CreateIC(XIM xim, struct x11drv_win_data *data) P_DrawCB.callback = (XICProc)XIMPreEditDrawCallback; P_CaretCB.callback = (XICProc)XIMPreEditCaretCallback; - if ((ximStyle & (XIMPreeditNothing | XIMPreeditNone)) == 0) - { - preedit = XVaCreateNestedList(0, - XNFontSet, fontSet, - XNSpotLocation, &spot, - XNPreeditStateNotifyCallback, &P_StateNotifyCB, - XNPreeditStartCallback, &P_StartCB, - XNPreeditDoneCallback, &P_DoneCB, - XNPreeditDrawCallback, &P_DrawCB, - XNPreeditCaretCallback, &P_CaretCB, - NULL); - TRACE("preedit = %p\n", preedit); - } - else - { - preedit = XVaCreateNestedList(0, - XNPreeditStateNotifyCallback, &P_StateNotifyCB, - XNPreeditStartCallback, &P_StartCB, - XNPreeditDoneCallback, &P_DoneCB, - XNPreeditDrawCallback, &P_DrawCB, - XNPreeditCaretCallback, &P_CaretCB, - NULL); - - TRACE("preedit = %p\n", preedit); - } - - if ((ximStyle & (XIMStatusNothing | XIMStatusNone)) == 0) - { - status = XVaCreateNestedList(0, - XNFontSet, fontSet, - NULL); - TRACE("status = %p\n", status); - } - - if (preedit != NULL && status != NULL) - { - xic = XCreateIC(xim, - XNInputStyle, ximStyle, - XNPreeditAttributes, preedit, - XNStatusAttributes, status, - XNClientWindow, win, - XNFocusWindow, win, - XNDestroyCallback, &destroy, - NULL); - } - else if (preedit != NULL) - { - xic = XCreateIC(xim, - XNInputStyle, ximStyle, - XNPreeditAttributes, preedit, - XNClientWindow, win, - XNFocusWindow, win, - XNDestroyCallback, &destroy, - NULL); - } - else if (status != NULL) - { - xic = XCreateIC(xim, - XNInputStyle, ximStyle, - XNStatusAttributes, status, - XNClientWindow, win, - XNFocusWindow, win, - XNDestroyCallback, &destroy, - NULL); - } - else - { - xic = XCreateIC(xim, - XNInputStyle, ximStyle, - XNClientWindow, win, - XNFocusWindow, win, - XNDestroyCallback, &destroy, - NULL); - } + preedit = XVaCreateNestedList( 0, XNFontSet, fontSet, + XNPreeditCaretCallback, &P_CaretCB, + XNPreeditDoneCallback, &P_DoneCB, + XNPreeditDrawCallback, &P_DrawCB, + XNPreeditStartCallback, &P_StartCB, + XNPreeditStateNotifyCallback, &P_StateNotifyCB, + XNSpotLocation, &spot, NULL ); + status = XVaCreateNestedList( 0, XNFontSet, fontSet, NULL ); + xic = XCreateIC( xim, XNInputStyle, ximStyle, XNPreeditAttributes, preedit, XNStatusAttributes, status, + XNClientWindow, win, XNFocusWindow, win, XNDestroyCallback, &destroy, NULL ); + TRACE( "created XIC %p\n", xic ); - TRACE("xic = %p\n", xic); data->xic = xic; - if (preedit != NULL) - XFree(preedit); - if (status != NULL) - XFree(status); + XFree( preedit ); + XFree( status ); return xic; } From a15058a03cbeaa84c3319e1c0b5596c0b4ec2f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 2 Apr 2023 11:28:43 +0200 Subject: [PATCH 1803/2777] winex11: Pass hwnd parameter to all XIC callbacks. (cherry picked from commit b91774a1ee6c4b2caf47943502a11b7ed3619f44) --- dlls/winex11.drv/window.c | 2 +- dlls/winex11.drv/x11drv.h | 2 +- dlls/winex11.drv/xim.c | 97 ++++++++++++++++++++++----------------- 3 files changed, 58 insertions(+), 43 deletions(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index ea2faa95828..f1b706b3721 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2771,7 +2771,7 @@ XIC X11DRV_get_ic( HWND hwnd ) { x11drv_thread_data()->last_xic_hwnd = hwnd; ret = data->xic; - if (!ret && (xim = x11drv_thread_data()->xim)) ret = X11DRV_CreateIC( xim, data ); + if (!ret && (xim = x11drv_thread_data()->xim)) ret = X11DRV_CreateIC( xim, hwnd, data ); release_win_data( data ); } return ret; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index f2b12a5c00d..f59fd63a037 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -877,7 +877,7 @@ extern struct x11drv_display_device_handler desktop_handler DECLSPEC_HIDDEN; /* XIM support */ extern BOOL X11DRV_InitXIM( const WCHAR *input_style ) DECLSPEC_HIDDEN; -extern XIC X11DRV_CreateIC(XIM xim, struct x11drv_win_data *data) DECLSPEC_HIDDEN; +extern XIC X11DRV_CreateIC( XIM xim, HWND hwnd, struct x11drv_win_data *data ) DECLSPEC_HIDDEN; extern void X11DRV_SetupXIM(void) DECLSPEC_HIDDEN; extern void X11DRV_XIMLookupChars( const char *str, UINT count ) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 59a273d9ed3..7a647e4a643 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -109,12 +109,14 @@ void X11DRV_XIMLookupChars( const char *str, UINT count ) free( output ); } -static BOOL XIMPreEditStateNotifyCallback(XIC xic, XPointer p, XPointer data) +static BOOL xic_preedit_state_notify( XIC xic, XPointer user, XPointer arg ) { - const struct x11drv_win_data * const win_data = (struct x11drv_win_data *)p; - const XIMPreeditState state = ((XIMPreeditStateNotifyCallbackStruct *)data)->state; + XIMPreeditStateNotifyCallbackStruct *params = (void *)arg; + const XIMPreeditState state = params->state; + HWND hwnd = (HWND)user; + + TRACE( "xic %p, hwnd %p, state %lu\n", xic, hwnd, state ); - TRACE("xic = %p, win = %lx, state = %lu\n", xic, win_data->whole_window, state); switch (state) { case XIMPreeditEnable: @@ -130,17 +132,23 @@ static BOOL XIMPreEditStateNotifyCallback(XIC xic, XPointer p, XPointer data) return TRUE; } -static int XIMPreEditStartCallback(XIC ic, XPointer client_data, XPointer call_data) +static int xic_preedit_start( XIC xic, XPointer user, XPointer arg ) { - TRACE("PreEditStartCallback %p\n",ic); + HWND hwnd = (HWND)user; + + TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg ); + x11drv_client_call( client_ime_set_composition_status, TRUE ); ximInComposeMode = TRUE; return -1; } -static void XIMPreEditDoneCallback(XIC ic, XPointer client_data, XPointer call_data) +static int xic_preedit_done( XIC xic, XPointer user, XPointer arg ) { - TRACE("PreeditDoneCallback %p\n",ic); + HWND hwnd = (HWND)user; + + TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg ); + ximInComposeMode = FALSE; if (dwCompStringSize) free( CompositionString ); @@ -148,12 +156,15 @@ static void XIMPreEditDoneCallback(XIC ic, XPointer client_data, XPointer call_d dwCompStringLength = 0; CompositionString = NULL; x11drv_client_call( client_ime_set_composition_status, FALSE ); + return 0; } -static void XIMPreEditDrawCallback(XIM ic, XPointer client_data, - XIMPreeditDrawCallbackStruct *P_DR) +static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) { - TRACE("PreEditDrawCallback %p\n",ic); + XIMPreeditDrawCallbackStruct *P_DR = (void *)arg; + HWND hwnd = (HWND)user; + + TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg ); if (P_DR) { @@ -189,13 +200,17 @@ static void XIMPreEditDrawCallback(XIM ic, XPointer client_data, X11DRV_ImmSetInternalString (sel, len, NULL, 0); x11drv_client_call( client_ime_set_cursor_pos, P_DR->caret ); } + TRACE("Finished\n"); + return 0; } -static void XIMPreEditCaretCallback(XIC ic, XPointer client_data, - XIMPreeditCaretCallbackStruct *P_C) +static int xic_preedit_caret( XIC xic, XPointer user, XPointer arg ) { - TRACE("PreeditCaretCallback %p\n",ic); + XIMPreeditCaretCallbackStruct *P_C = (void *)arg; + HWND hwnd = (HWND)user; + + TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg ); if (P_C) { @@ -219,7 +234,7 @@ static void XIMPreEditCaretCallback(XIC ic, XPointer client_data, break; case XIMDontChange: P_C->position = pos; - return; + return 0; case XIMCaretUp: case XIMCaretDown: case XIMPreviousLine: @@ -232,6 +247,7 @@ static void XIMPreEditCaretCallback(XIC ic, XPointer client_data, P_C->position = pos; } TRACE("Finished\n"); + return 0; } NTSTATUS x11drv_xim_reset( void *hwnd ) @@ -440,45 +456,44 @@ void X11DRV_SetupXIM(void) XRegisterIMInstantiateCallback( display, NULL, NULL, NULL, open_xim_callback, NULL ); } -static BOOL X11DRV_DestroyIC(XIC xic, XPointer p, XPointer data) +static BOOL xic_destroy( XIC xic, XPointer user, XPointer arg ) { - struct x11drv_win_data *win_data = (struct x11drv_win_data *)p; - TRACE("xic = %p, win = %lx\n", xic, win_data->whole_window); - win_data->xic = NULL; + struct x11drv_win_data *data; + HWND hwnd = (HWND)user; + + TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg ); + + if ((data = get_win_data( hwnd ))) + { + if (data->xic == xic) data->xic = NULL; + release_win_data( data ); + } + return TRUE; } - -XIC X11DRV_CreateIC(XIM xim, struct x11drv_win_data *data) +XIC X11DRV_CreateIC( XIM xim, HWND hwnd, struct x11drv_win_data *data ) { + XICCallback destroy = {.callback = xic_destroy, .client_data = (XPointer)hwnd}; + XICCallback preedit_caret = {.callback = xic_preedit_caret, .client_data = (XPointer)hwnd}; + XICCallback preedit_done = {.callback = xic_preedit_done, .client_data = (XPointer)hwnd}; + XICCallback preedit_draw = {.callback = xic_preedit_draw, .client_data = (XPointer)hwnd}; + XICCallback preedit_start = {.callback = xic_preedit_start, .client_data = (XPointer)hwnd}; + XICCallback preedit_state_notify = {.callback = xic_preedit_state_notify, .client_data = (XPointer)hwnd}; XPoint spot = {0}; XVaNestedList preedit, status; XIC xic; - XICCallback destroy = {(XPointer)data, X11DRV_DestroyIC}; - XICCallback P_StateNotifyCB, P_StartCB, P_DoneCB, P_DrawCB, P_CaretCB; Window win = data->whole_window; XFontSet fontSet = x11drv_thread_data()->font_set; - TRACE( "xim %p, data %p\n", xim, data ); - - /* create callbacks */ - P_StateNotifyCB.client_data = (XPointer)data; - P_StartCB.client_data = NULL; - P_DoneCB.client_data = NULL; - P_DrawCB.client_data = NULL; - P_CaretCB.client_data = NULL; - P_StateNotifyCB.callback = XIMPreEditStateNotifyCallback; - P_StartCB.callback = XIMPreEditStartCallback; - P_DoneCB.callback = (XICProc)XIMPreEditDoneCallback; - P_DrawCB.callback = (XICProc)XIMPreEditDrawCallback; - P_CaretCB.callback = (XICProc)XIMPreEditCaretCallback; + TRACE( "xim %p, hwnd %p, data %p\n", xim, hwnd, data ); preedit = XVaCreateNestedList( 0, XNFontSet, fontSet, - XNPreeditCaretCallback, &P_CaretCB, - XNPreeditDoneCallback, &P_DoneCB, - XNPreeditDrawCallback, &P_DrawCB, - XNPreeditStartCallback, &P_StartCB, - XNPreeditStateNotifyCallback, &P_StateNotifyCB, + XNPreeditCaretCallback, &preedit_caret, + XNPreeditDoneCallback, &preedit_done, + XNPreeditDrawCallback, &preedit_draw, + XNPreeditStartCallback, &preedit_start, + XNPreeditStateNotifyCallback, &preedit_state_notify, XNSpotLocation, &spot, NULL ); status = XVaCreateNestedList( 0, XNFontSet, fontSet, NULL ); xic = XCreateIC( xim, XNInputStyle, ximStyle, XNPreeditAttributes, preedit, XNStatusAttributes, status, From 32030851bf6ec2fdb2de4a0be0c00d61bf630cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 2 Apr 2023 11:30:50 +0200 Subject: [PATCH 1804/2777] winex11: Remove unnecessary else control flow. (cherry picked from commit cc8a6b138449e300593db1be1cf0f51c54cd9579) --- dlls/winex11.drv/xim.c | 76 ++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 7a647e4a643..dda412e5eaf 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -368,53 +368,51 @@ static BOOL open_xim( Display *display ) XGetIMValues(xim, XNQueryInputStyle, &ximStyles, NULL); if (ximStyles == 0) { - WARN("Could not find supported input style.\n"); - XCloseIM(xim); + WARN( "Could not find supported input style.\n" ); + XCloseIM( xim ); return FALSE; } - else - { - TRACE("ximStyles->count_styles = %d\n", ximStyles->count_styles); - ximStyleRoot = 0; - ximStyleNone = 0; + TRACE("ximStyles->count_styles = %d\n", ximStyles->count_styles); - for (i = 0; i < ximStyles->count_styles; ++i) + ximStyleRoot = 0; + ximStyleNone = 0; + + for (i = 0; i < ximStyles->count_styles; ++i) + { + int style = ximStyles->supported_styles[i]; + TRACE("ximStyles[%d] = %s%s%s%s%s\n", i, + (style&XIMPreeditArea)?"XIMPreeditArea ":"", + (style&XIMPreeditCallbacks)?"XIMPreeditCallbacks ":"", + (style&XIMPreeditPosition)?"XIMPreeditPosition ":"", + (style&XIMPreeditNothing)?"XIMPreeditNothing ":"", + (style&XIMPreeditNone)?"XIMPreeditNone ":""); + if (!ximStyle && (ximStyles->supported_styles[i] == + ximStyleRequest)) { - int style = ximStyles->supported_styles[i]; - TRACE("ximStyles[%d] = %s%s%s%s%s\n", i, - (style&XIMPreeditArea)?"XIMPreeditArea ":"", - (style&XIMPreeditCallbacks)?"XIMPreeditCallbacks ":"", - (style&XIMPreeditPosition)?"XIMPreeditPosition ":"", - (style&XIMPreeditNothing)?"XIMPreeditNothing ":"", - (style&XIMPreeditNone)?"XIMPreeditNone ":""); - if (!ximStyle && (ximStyles->supported_styles[i] == - ximStyleRequest)) - { - ximStyle = ximStyleRequest; - TRACE("Setting Style: ximStyle = ximStyleRequest\n"); - } - else if (!ximStyleRoot &&(ximStyles->supported_styles[i] == - STYLE_ROOT)) - { - ximStyleRoot = STYLE_ROOT; - TRACE("Setting Style: ximStyleRoot = STYLE_ROOT\n"); - } - else if (!ximStyleNone && (ximStyles->supported_styles[i] == - STYLE_NONE)) - { - TRACE("Setting Style: ximStyleNone = STYLE_NONE\n"); - ximStyleNone = STYLE_NONE; - } + ximStyle = ximStyleRequest; + TRACE("Setting Style: ximStyle = ximStyleRequest\n"); + } + else if (!ximStyleRoot &&(ximStyles->supported_styles[i] == + STYLE_ROOT)) + { + ximStyleRoot = STYLE_ROOT; + TRACE("Setting Style: ximStyleRoot = STYLE_ROOT\n"); } - XFree(ximStyles); + else if (!ximStyleNone && (ximStyles->supported_styles[i] == + STYLE_NONE)) + { + TRACE("Setting Style: ximStyleNone = STYLE_NONE\n"); + ximStyleNone = STYLE_NONE; + } + } + XFree(ximStyles); - if (ximStyle == 0) - ximStyle = ximStyleRoot; + if (ximStyle == 0) + ximStyle = ximStyleRoot; - if (ximStyle == 0) - ximStyle = ximStyleNone; - } + if (ximStyle == 0) + ximStyle = ximStyleNone; thread_data->xim = xim; From fcad4ec5968c15b1b848d270255c88966cfd6592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 16 May 2023 15:44:01 +0200 Subject: [PATCH 1805/2777] winex11: Create the thread XFontSet on thread attach. (cherry picked from commit 4390b0117633716b6e5477a35c13f6eb0fd52eff) --- dlls/winex11.drv/x11drv.h | 4 ++-- dlls/winex11.drv/x11drv_main.c | 4 ++-- dlls/winex11.drv/xim.c | 38 ++++++++++------------------------ 3 files changed, 15 insertions(+), 31 deletions(-) diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index f59fd63a037..83d30143a6a 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -876,9 +876,9 @@ extern BOOL X11DRV_DisplayDevices_SupportEventHandlers(void) DECLSPEC_HIDDEN; extern struct x11drv_display_device_handler desktop_handler DECLSPEC_HIDDEN; /* XIM support */ -extern BOOL X11DRV_InitXIM( const WCHAR *input_style ) DECLSPEC_HIDDEN; +extern BOOL xim_init( const WCHAR *input_style ) DECLSPEC_HIDDEN; extern XIC X11DRV_CreateIC( XIM xim, HWND hwnd, struct x11drv_win_data *data ) DECLSPEC_HIDDEN; -extern void X11DRV_SetupXIM(void) DECLSPEC_HIDDEN; +extern void xim_thread_attach( struct x11drv_thread_data *data ) DECLSPEC_HIDDEN; extern void X11DRV_XIMLookupChars( const char *str, UINT count ) DECLSPEC_HIDDEN; #define XEMBED_MAPPED (1 << 0) diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index a767216ee1d..3ac5d0d167c 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -828,7 +828,7 @@ static NTSTATUS x11drv_init( void *arg ) XkbUseExtension( gdi_display, NULL, NULL ); X11DRV_InitKeyboard( gdi_display ); X11DRV_InitMouse( gdi_display ); - if (use_xim) use_xim = X11DRV_InitXIM( input_style ); + if (use_xim) use_xim = xim_init( input_style ); { const char *e = getenv("WINE_DISABLE_FULLSCREEN_HACK"); @@ -943,7 +943,7 @@ struct x11drv_thread_data *x11drv_init_thread_data(void) set_queue_display_fd( data->display ); NtUserGetThreadInfo()->driver_data = (UINT_PTR)data; - if (use_xim) X11DRV_SetupXIM(); + if (use_xim) xim_thread_attach( data ); X11DRV_XInput2_Init(); if (NtUserGetWindowThread( NtUserGetDesktopWindow(), NULL ) == GetCurrentThreadId()) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index dda412e5eaf..0ab97edf5ba 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -288,13 +288,10 @@ NTSTATUS x11drv_xim_preedit_state( void *arg ) return 0; } - /*********************************************************************** - * X11DRV_InitXIM - * - * Process-wide XIM initialization. + * xim_init */ -BOOL X11DRV_InitXIM( const WCHAR *input_style ) +BOOL xim_init( const WCHAR *input_style ) { static const WCHAR offthespotW[] = {'o','f','f','t','h','e','s','p','o','t',0}; static const WCHAR overthespotW[] = {'o','v','e','r','t','h','e','s','p','o','t',0}; @@ -416,26 +413,6 @@ static BOOL open_xim( Display *display ) thread_data->xim = xim; - if ((ximStyle & (XIMPreeditNothing | XIMPreeditNone)) == 0 || - (ximStyle & (XIMStatusNothing | XIMStatusNone)) == 0) - { - char **list; - int count; - thread_data->font_set = XCreateFontSet(display, "fixed", - &list, &count, NULL); - TRACE("ximFontSet = %p\n", thread_data->font_set); - TRACE("list = %p, count = %d\n", list, count); - if (list != NULL) - { - int i; - for (i = 0; i < count; ++i) - TRACE("list[%d] = %s\n", i, list[i]); - XFreeStringList(list); - } - } - else - thread_data->font_set = NULL; - x11drv_client_call( client_ime_update_association, 0 ); return TRUE; } @@ -446,9 +423,16 @@ static void open_xim_callback( Display *display, XPointer ptr, XPointer data ) XUnregisterIMInstantiateCallback( display, NULL, NULL, NULL, open_xim_callback, NULL); } -void X11DRV_SetupXIM(void) +void xim_thread_attach( struct x11drv_thread_data *data ) { - Display *display = thread_display(); + Display *display = data->display; + int i, count; + char **list; + + data->font_set = XCreateFontSet( display, "fixed", &list, &count, NULL ); + TRACE( "created XFontSet %p, list %p, count %d\n", data->font_set, list, count ); + for (i = 0; list && i < count; ++i) TRACE( " %d: %s\n", i, list[i] ); + if (list) XFreeStringList( list ); if (!open_xim( display )) XRegisterIMInstantiateCallback( display, NULL, NULL, NULL, open_xim_callback, NULL ); From 783fa9376e2c69d1a7be1a506788dc15dab08a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 2 Apr 2023 14:06:19 +0200 Subject: [PATCH 1806/2777] winex11: Set thread data XIM pointer outside of open_xim. (cherry picked from commit f1f0386c1ec526496cb5e701a6329a97c318c599) --- dlls/winex11.drv/xim.c | 65 ++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 0ab97edf5ba..b213aa5b1fc 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -317,46 +317,26 @@ BOOL xim_init( const WCHAR *input_style ) return TRUE; } +static void xim_open( Display *display, XPointer user, XPointer arg ); +static void xim_destroy( XIM xim, XPointer user, XPointer arg ); -static void open_xim_callback( Display *display, XPointer ptr, XPointer data ); - -static void X11DRV_DestroyIM(XIM xim, XPointer p, XPointer data) -{ - struct x11drv_thread_data *thread_data = x11drv_thread_data(); - - TRACE("xim = %p, p = %p\n", xim, p); - thread_data->xim = NULL; - ximStyle = 0; - XRegisterIMInstantiateCallback( thread_data->display, NULL, NULL, NULL, open_xim_callback, NULL ); -} - -/*********************************************************************** - * X11DRV Ime creation - * - * Should always be called with the x11 lock held - */ -static BOOL open_xim( Display *display ) +static XIM xim_create( struct x11drv_thread_data *data ) { - struct x11drv_thread_data *thread_data = x11drv_thread_data(); + XIMCallback destroy = {.callback = xim_destroy, .client_data = (XPointer)data}; + Display *display = data->display; XIMStyle ximStyleNone; XIMStyles *ximStyles = NULL; INT i; XIM xim; - XIMCallback destroy; - xim = XOpenIM(display, NULL, NULL, NULL); - if (xim == NULL) + if (!(xim = XOpenIM( display, NULL, NULL, NULL ))) { WARN("Could not open input method.\n"); - return FALSE; + return NULL; } - destroy.client_data = NULL; - destroy.callback = X11DRV_DestroyIM; - if (XSetIMValues(xim, XNDestroyCallback, &destroy, NULL)) - { - WARN("Could not set destroy callback.\n"); - } + if (XSetIMValues( xim, XNDestroyCallback, &destroy, NULL )) + WARN( "Could not set destroy callback.\n" ); TRACE("xim = %p\n", xim); TRACE("X display of IM = %p\n", XDisplayOfIM(xim)); @@ -367,13 +347,14 @@ static BOOL open_xim( Display *display ) { WARN( "Could not find supported input style.\n" ); XCloseIM( xim ); - return FALSE; + return NULL; } TRACE("ximStyles->count_styles = %d\n", ximStyles->count_styles); ximStyleRoot = 0; ximStyleNone = 0; + ximStyle = 0; for (i = 0; i < ximStyles->count_styles; ++i) { @@ -411,16 +392,26 @@ static BOOL open_xim( Display *display ) if (ximStyle == 0) ximStyle = ximStyleNone; - thread_data->xim = xim; + return xim; +} + +static void xim_open( Display *display, XPointer user, XPointer arg ) +{ + struct x11drv_thread_data *data = (void *)user; + TRACE( "display %p, data %p, arg %p\n", display, user, arg ); + if (!(data->xim = xim_create( data ))) return; + XUnregisterIMInstantiateCallback( display, NULL, NULL, NULL, xim_open, user ); x11drv_client_call( client_ime_update_association, 0 ); - return TRUE; } -static void open_xim_callback( Display *display, XPointer ptr, XPointer data ) +static void xim_destroy( XIM xim, XPointer user, XPointer arg ) { - if (open_xim( display )) - XUnregisterIMInstantiateCallback( display, NULL, NULL, NULL, open_xim_callback, NULL); + struct x11drv_thread_data *data = x11drv_thread_data(); + TRACE( "xim %p, user %p, arg %p\n", xim, user, arg ); + if (data->xim != xim) return; + data->xim = NULL; + XRegisterIMInstantiateCallback( data->display, NULL, NULL, NULL, xim_open, user ); } void xim_thread_attach( struct x11drv_thread_data *data ) @@ -434,8 +425,8 @@ void xim_thread_attach( struct x11drv_thread_data *data ) for (i = 0; list && i < count; ++i) TRACE( " %d: %s\n", i, list[i] ); if (list) XFreeStringList( list ); - if (!open_xim( display )) - XRegisterIMInstantiateCallback( display, NULL, NULL, NULL, open_xim_callback, NULL ); + if ((data->xim = xim_create( data ))) x11drv_client_call( client_ime_update_association, 0 ); + else XRegisterIMInstantiateCallback( display, NULL, NULL, NULL, xim_open, (XPointer)data ); } static BOOL xic_destroy( XIC xic, XPointer user, XPointer arg ) From 3adad4db67fd05a0ae594a107e3ca3c4235b928c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 2 Apr 2023 14:08:20 +0200 Subject: [PATCH 1807/2777] winex11: Cleanup XIM initialization traces. (cherry picked from commit 64cca153292833151d1adeb185252ca57e2d1625) --- dlls/winex11.drv/xim.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index b213aa5b1fc..9f238e0cb83 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -61,6 +61,26 @@ static XIMStyle ximStyle = 0; static XIMStyle ximStyleRoot = 0; static XIMStyle ximStyleRequest = STYLE_CALLBACK; +static const char *debugstr_xim_style( XIMStyle style ) +{ + char buffer[1024], *buf = buffer; + + buf += sprintf( buf, "preedit" ); + if (style & XIMPreeditArea) buf += sprintf( buf, " area" ); + if (style & XIMPreeditCallbacks) buf += sprintf( buf, " callbacks" ); + if (style & XIMPreeditPosition) buf += sprintf( buf, " position" ); + if (style & XIMPreeditNothing) buf += sprintf( buf, " nothing" ); + if (style & XIMPreeditNone) buf += sprintf( buf, " none" ); + + buf += sprintf( buf, ", status" ); + if (style & XIMStatusArea) buf += sprintf( buf, " area" ); + if (style & XIMStatusCallbacks) buf += sprintf( buf, " callbacks" ); + if (style & XIMStatusNothing) buf += sprintf( buf, " nothing" ); + if (style & XIMStatusNone) buf += sprintf( buf, " none" ); + + return wine_dbg_sprintf( "%s", buffer ); +} + static void X11DRV_ImmSetInternalString(UINT offset, UINT selLength, LPWSTR lpComp, UINT len) { /* Composition strings are edited in chunks */ @@ -338,9 +358,8 @@ static XIM xim_create( struct x11drv_thread_data *data ) if (XSetIMValues( xim, XNDestroyCallback, &destroy, NULL )) WARN( "Could not set destroy callback.\n" ); - TRACE("xim = %p\n", xim); - TRACE("X display of IM = %p\n", XDisplayOfIM(xim)); - TRACE("Using %s locale of Input Method\n", XLocaleOfIM(xim)); + TRACE( "xim %p, XDisplayOfIM %p, XLocaleOfIM %s\n", xim, XDisplayOfIM( xim ), + debugstr_a(XLocaleOfIM( xim )) ); XGetIMValues(xim, XNQueryInputStyle, &ximStyles, NULL); if (ximStyles == 0) @@ -350,21 +369,16 @@ static XIM xim_create( struct x11drv_thread_data *data ) return NULL; } - TRACE("ximStyles->count_styles = %d\n", ximStyles->count_styles); - ximStyleRoot = 0; ximStyleNone = 0; ximStyle = 0; + TRACE( "input styles count %u\n", ximStyles->count_styles ); for (i = 0; i < ximStyles->count_styles; ++i) { - int style = ximStyles->supported_styles[i]; - TRACE("ximStyles[%d] = %s%s%s%s%s\n", i, - (style&XIMPreeditArea)?"XIMPreeditArea ":"", - (style&XIMPreeditCallbacks)?"XIMPreeditCallbacks ":"", - (style&XIMPreeditPosition)?"XIMPreeditPosition ":"", - (style&XIMPreeditNothing)?"XIMPreeditNothing ":"", - (style&XIMPreeditNone)?"XIMPreeditNone ":""); + XIMStyle style = ximStyles->supported_styles[i]; + TRACE( " %u: %#lx %s\n", i, style, debugstr_xim_style( style ) ); + if (!ximStyle && (ximStyles->supported_styles[i] == ximStyleRequest)) { From b19c329d2b381ef0091f21dda8a75ef2c5cf55ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 3 Apr 2023 16:45:44 +0200 Subject: [PATCH 1808/2777] imm32: Rewrite ImmInternalSendIMEMessage helper as imc_send_message. (cherry picked from commit f6cf1d4432b2843b789056f6e93a8c41596ef03b) --- dlls/imm32/imm.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index e165544ba5e..e815f0c479b 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -744,14 +744,11 @@ static void ImmInternalPostIMEMessage( struct imc *data, UINT msg, WPARAM wParam PostMessageW(target, msg, wParam, lParam); } -/* for sending messages as the IME */ -static void ImmInternalSendIMEMessage( struct imc *data, UINT msg, WPARAM wParam, LPARAM lParam ) +static void imc_send_message( struct imc *imc, TRANSMSG *message ) { - HWND target = GetFocus(); - if (!target) - SendMessageW(data->IMC.hWnd,msg,wParam,lParam); - else - SendMessageW(target, msg, wParam, lParam); + HWND target; + if (!(target = GetFocus()) && !(target = imc->IMC.hWnd)) return; + SendMessageW( target, message->message, message->wParam, message->lParam ); } static LRESULT ImmInternalSendIMENotify( struct imc *data, WPARAM notify, LPARAM lParam ) @@ -3014,9 +3011,7 @@ BOOL WINAPI ImmGenerateMessage(HIMC hIMC) data->IMC.dwNumMsgBuf = 0; lpTransMsg = ImmLockIMCC(hMsgBuf); - for (i = 0; i < dwNumMsgBuf; i++) - ImmInternalSendIMEMessage(data, lpTransMsg[i].message, lpTransMsg[i].wParam, lpTransMsg[i].lParam); - + for (i = 0; i < dwNumMsgBuf; i++) imc_send_message( data, lpTransMsg + i ); ImmUnlockIMCC(hMsgBuf); ImmDestroyIMCC(hMsgBuf); } From 66b7a9c5fb2fcbcacd144ba07e67a2c489ff4cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 3 Apr 2023 16:47:04 +0200 Subject: [PATCH 1809/2777] imm32: Rewrite ImmInternalPostIMEMessage helper as imc_post_message. (cherry picked from commit 3b4aa1662e79b025e46d4a10426eda504beb4c6b) --- dlls/imm32/imm.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index e815f0c479b..de32196a133 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -734,14 +734,11 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved) return TRUE; } -/* for posting messages as the IME */ -static void ImmInternalPostIMEMessage( struct imc *data, UINT msg, WPARAM wParam, LPARAM lParam ) +static void imc_post_message( struct imc *imc, TRANSMSG *message ) { - HWND target = GetFocus(); - if (!target) - PostMessageW(data->IMC.hWnd,msg,wParam,lParam); - else - PostMessageW(target, msg, wParam, lParam); + HWND target; + if (!(target = GetFocus()) && !(target = imc->IMC.hWnd)) return; + PostMessageW( target, message->message, message->wParam, message->lParam ); } static void imc_send_message( struct imc *imc, TRANSMSG *message ) @@ -3031,7 +3028,7 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD BYTE state[256]; UINT scancode; TRANSMSGLIST *list = NULL; - UINT msg_count; + UINT msg_count, i; UINT uVirtKey; static const DWORD list_count = 10; @@ -3063,13 +3060,7 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD msg_count = ime->pImeToAsciiEx( uVirtKey, scancode, state, list, 0, imc ); TRACE("%i messages generated\n",msg_count); if (msg_count && msg_count <= list_count) - { - UINT i; - LPTRANSMSG msgs = list->TransMsg; - - for (i = 0; i < msg_count; i++) - ImmInternalPostIMEMessage(data, msgs[i].message, msgs[i].wParam, msgs[i].lParam); - } + for (i = 0; i < msg_count; i++) imc_post_message( data, list->TransMsg + i ); else if (msg_count > list_count) ImmGenerateMessage(imc); From b69e54fd23c20578846555dad14aa0f01d80c991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 3 Apr 2023 17:42:26 +0200 Subject: [PATCH 1810/2777] imm32: Rewrite ImmInternalSendIMENotify helper as imc_notify_ime. (cherry picked from commit 7f0c2c48df2dab74d73ccff518f43b3eb14dbc47) --- dlls/imm32/imm.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index de32196a133..31a0b927d07 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -748,17 +748,11 @@ static void imc_send_message( struct imc *imc, TRANSMSG *message ) SendMessageW( target, message->message, message->wParam, message->lParam ); } -static LRESULT ImmInternalSendIMENotify( struct imc *data, WPARAM notify, LPARAM lParam ) +static LRESULT imc_notify_ime( struct imc *imc, WPARAM notify, LPARAM lparam ) { HWND target; - - target = data->IMC.hWnd; - if (!target) target = GetFocus(); - - if (target) - return SendMessageW(target, WM_IME_NOTIFY, notify, lParam); - - return 0; + if (!(target = imc->IMC.hWnd) && !(target = GetFocus())) return 0; + return SendMessageW( target, WM_IME_NOTIFY, notify, lparam ); } /*********************************************************************** @@ -2368,7 +2362,7 @@ BOOL WINAPI ImmSetCandidateWindow( data->IMC.cfCandForm[lpCandidate->dwIndex] = *lpCandidate; ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS); - ImmInternalSendIMENotify(data, IMN_SETCANDIDATEPOS, 1 << lpCandidate->dwIndex); + imc_notify_ime( data, IMN_SETCANDIDATEPOS, 1 << lpCandidate->dwIndex ); return TRUE; } @@ -2393,7 +2387,7 @@ BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName, LF_FACESIZE); ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT); - ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0); + imc_notify_ime( data, IMN_SETCOMPOSITIONFONT, 0 ); return TRUE; } @@ -2416,7 +2410,7 @@ BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) data->IMC.lfFont.W = *lplf; ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT); - ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONFONT, 0); + imc_notify_ime( data, IMN_SETCOMPOSITIONFONT, 0 ); return TRUE; } @@ -2575,7 +2569,7 @@ BOOL WINAPI ImmSetCompositionWindow( if (ui_hwnd && reshow) ShowWindow( ui_hwnd, SW_SHOWNOACTIVATE ); - ImmInternalSendIMENotify(data, IMN_SETCOMPOSITIONWINDOW, 0); + imc_notify_ime( data, IMN_SETCOMPOSITIONWINDOW, 0 ); return TRUE; } @@ -2603,14 +2597,14 @@ BOOL WINAPI ImmSetConversionStatus( oldConversion = data->IMC.fdwConversion; data->IMC.fdwConversion = fdwConversion; ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldConversion, IMC_SETCONVERSIONMODE); - ImmInternalSendIMENotify(data, IMN_SETCONVERSIONMODE, 0); + imc_notify_ime( data, IMN_SETCONVERSIONMODE, 0 ); } if ( fdwSentence != data->IMC.fdwSentence ) { oldSentence = data->IMC.fdwSentence; data->IMC.fdwSentence = fdwSentence; ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldSentence, IMC_SETSENTENCEMODE); - ImmInternalSendIMENotify(data, IMN_SETSENTENCEMODE, 0); + imc_notify_ime( data, IMN_SETSENTENCEMODE, 0 ); } return TRUE; @@ -2640,7 +2634,7 @@ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) { data->IMC.fOpen = fOpen; ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS); - ImmInternalSendIMENotify(data, IMN_SETOPENSTATUS, 0); + imc_notify_ime( data, IMN_SETOPENSTATUS, 0 ); } return TRUE; @@ -2667,7 +2661,7 @@ BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) data->IMC.ptStatusWndPos = *lpptPos; ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETSTATUSWINDOWPOS); - ImmInternalSendIMENotify(data, IMN_SETSTATUSWINDOWPOS, 0); + imc_notify_ime( data, IMN_SETSTATUSWINDOWPOS, 0 ); return TRUE; } From 9b725cc89a5687f3d66de37a3660a4588407be21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 3 Apr 2023 16:30:39 +0200 Subject: [PATCH 1811/2777] imm32: Fix mixed-up HIMC / imc pointers in ImmTranslateMessage. (cherry picked from commit 4445fd14d707347b0bcaf2fd5be0741586f519fa) --- dlls/imm32/imm.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 31a0b927d07..a17ffa79e73 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3018,7 +3018,6 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD { struct imc *data; struct ime *ime; - HIMC imc = ImmGetContext(hwnd); BYTE state[256]; UINT scancode; TRANSMSGLIST *list = NULL; @@ -3028,8 +3027,8 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD TRACE("%p %x %x %x\n",hwnd, msg, (UINT)wParam, (UINT)lKeyData); - if (!(data = get_imc_data( imc ))) return FALSE; - if (!(ime = imc_select_ime( imc ))) return FALSE; + if (!(data = get_imc_data( ImmGetContext( hwnd ) ))) return FALSE; + if (!(ime = imc_select_ime( data ))) return FALSE; if (data->lastVK == VK_PROCESSKEY) return FALSE; GetKeyboardState(state); @@ -3051,12 +3050,12 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD else uVirtKey = data->lastVK; - msg_count = ime->pImeToAsciiEx( uVirtKey, scancode, state, list, 0, imc ); + msg_count = ime->pImeToAsciiEx( uVirtKey, scancode, state, list, 0, data->handle ); TRACE("%i messages generated\n",msg_count); if (msg_count && msg_count <= list_count) for (i = 0; i < msg_count; i++) imc_post_message( data, list->TransMsg + i ); else if (msg_count > list_count) - ImmGenerateMessage(imc); + ImmGenerateMessage( data->handle ); free( list ); From c4943d3144f0e1155ec244ffb7d52cda1e0642b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 3 Apr 2023 18:32:29 +0200 Subject: [PATCH 1812/2777] imm32: Simplify control flow in ImmTranslateMessage. (cherry picked from commit 101743205d09919452e514c506a07f1d1fb2942f) --- dlls/imm32/imm.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index a17ffa79e73..4609c689ed2 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3033,6 +3033,7 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD GetKeyboardState(state); scancode = lKeyData >> 0x10 & 0xff; + uVirtKey = data->lastVK; list = calloc( list_count, sizeof(TRANSMSG) + sizeof(DWORD) ); list->uMsgCount = list_count; @@ -3047,15 +3048,12 @@ BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyD ToUnicodeEx(data->lastVK, scancode, state, &chr, 1, 0, GetKeyboardLayout(0)); uVirtKey = MAKELONG(data->lastVK,chr); } - else - uVirtKey = data->lastVK; msg_count = ime->pImeToAsciiEx( uVirtKey, scancode, state, list, 0, data->handle ); TRACE("%i messages generated\n",msg_count); - if (msg_count && msg_count <= list_count) - for (i = 0; i < msg_count; i++) imc_post_message( data, list->TransMsg + i ); - else if (msg_count > list_count) - ImmGenerateMessage( data->handle ); + + if (msg_count > list_count) ImmGenerateMessage( data->handle ); + else for (i = 0; i < msg_count; i++) imc_post_message( data, list->TransMsg + i ); free( list ); From 61c0de7bb232a61cd92311caeac19b5f655021c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 3 Apr 2023 18:23:38 +0200 Subject: [PATCH 1813/2777] imm32: Cleanup parameters and traces in ImmTranslateMessage. (cherry picked from commit 8d0e7d8cdcde897a9bf50a7047fc3bd4a503985c) --- dlls/imm32/imm.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 4609c689ed2..736e1dcf211 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3014,52 +3014,47 @@ BOOL WINAPI ImmGenerateMessage(HIMC hIMC) * ImmTranslateMessage(IMM32.@) * ( Undocumented, call internally and from user32.dll ) */ -BOOL WINAPI ImmTranslateMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lKeyData) +BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { + static const DWORD list_count = 10; + UINT scan, vkey, count, i; struct imc *data; struct ime *ime; BYTE state[256]; - UINT scancode; TRANSMSGLIST *list = NULL; - UINT msg_count, i; - UINT uVirtKey; - static const DWORD list_count = 10; + WCHAR chr; - TRACE("%p %x %x %x\n",hwnd, msg, (UINT)wParam, (UINT)lKeyData); + TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); if (!(data = get_imc_data( ImmGetContext( hwnd ) ))) return FALSE; if (!(ime = imc_select_ime( data ))) return FALSE; if (data->lastVK == VK_PROCESSKEY) return FALSE; - GetKeyboardState(state); - scancode = lKeyData >> 0x10 & 0xff; - uVirtKey = data->lastVK; + GetKeyboardState( state ); + scan = lparam >> 0x10 & 0xff; + vkey = data->lastVK; list = calloc( list_count, sizeof(TRANSMSG) + sizeof(DWORD) ); list->uMsgCount = list_count; if (ime->info.fdwProperty & IME_PROP_KBD_CHAR_FIRST) { - WCHAR chr; - - if (!ime_is_unicode( ime )) - ToAscii( data->lastVK, scancode, state, &chr, 0 ); - else - ToUnicodeEx(data->lastVK, scancode, state, &chr, 1, 0, GetKeyboardLayout(0)); - uVirtKey = MAKELONG(data->lastVK,chr); + if (!ime_is_unicode( ime )) ToAscii( data->lastVK, scan, state, &chr, 0 ); + else ToUnicodeEx( data->lastVK, scan, state, &chr, 1, 0, GetKeyboardLayout( 0 ) ); + vkey = MAKELONG( data->lastVK, chr ); } - msg_count = ime->pImeToAsciiEx( uVirtKey, scancode, state, list, 0, data->handle ); - TRACE("%i messages generated\n",msg_count); + count = ime->pImeToAsciiEx( vkey, scan, state, list, 0, data->handle ); + TRACE( "%u messages generated\n", count ); - if (msg_count > list_count) ImmGenerateMessage( data->handle ); - else for (i = 0; i < msg_count; i++) imc_post_message( data, list->TransMsg + i ); + if (count > list_count) ImmGenerateMessage( data->handle ); + else for (i = 0; i < count; i++) imc_post_message( data, list->TransMsg + i ); free( list ); data->lastVK = VK_PROCESSKEY; - return (msg_count > 0); + return count > 0; } /*********************************************************************** From 3aff333603ddc8e4f855aab303602bbe534f94ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 3 Apr 2023 18:33:10 +0200 Subject: [PATCH 1814/2777] imm32: Use a stack allocated buffer in ImmTranslateMessage. (cherry picked from commit 3385cda1c73d090bbb9ae030e49dcd51975b19ef) --- dlls/imm32/imm.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 736e1dcf211..e936bb27754 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3016,12 +3016,19 @@ BOOL WINAPI ImmGenerateMessage(HIMC hIMC) */ BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { - static const DWORD list_count = 10; + union + { + struct + { + UINT uMsgCount; + TRANSMSG TransMsg[10]; + }; + TRANSMSGLIST list; + } buffer = {.uMsgCount = ARRAY_SIZE(buffer.TransMsg)}; UINT scan, vkey, count, i; struct imc *data; struct ime *ime; BYTE state[256]; - TRANSMSGLIST *list = NULL; WCHAR chr; TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); @@ -3034,9 +3041,6 @@ BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar scan = lparam >> 0x10 & 0xff; vkey = data->lastVK; - list = calloc( list_count, sizeof(TRANSMSG) + sizeof(DWORD) ); - list->uMsgCount = list_count; - if (ime->info.fdwProperty & IME_PROP_KBD_CHAR_FIRST) { if (!ime_is_unicode( ime )) ToAscii( data->lastVK, scan, state, &chr, 0 ); @@ -3044,13 +3048,11 @@ BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar vkey = MAKELONG( data->lastVK, chr ); } - count = ime->pImeToAsciiEx( vkey, scan, state, list, 0, data->handle ); + count = ime->pImeToAsciiEx( vkey, scan, state, &buffer.list, 0, data->handle ); TRACE( "%u messages generated\n", count ); - if (count > list_count) ImmGenerateMessage( data->handle ); - else for (i = 0; i < count; i++) imc_post_message( data, list->TransMsg + i ); - - free( list ); + if (count > ARRAY_SIZE(buffer.TransMsg)) ImmGenerateMessage( data->handle ); + else for (i = 0; i < count; i++) imc_post_message( data, buffer.TransMsg + i ); data->lastVK = VK_PROCESSKEY; From 80c9cf5586553f8310bde53868cbf3b05bb0aa31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 30 Mar 2023 15:33:10 +0200 Subject: [PATCH 1815/2777] winemac: Rename imeData / data members and variables to himc. (cherry picked from commit 158d6caabe4fe8776cfd9702d1c8de5d082fafc7) --- dlls/winemac.drv/cocoa_window.h | 2 +- dlls/winemac.drv/cocoa_window.m | 14 +++++++------- dlls/winemac.drv/event.c | 8 ++++---- dlls/winemac.drv/ime.c | 4 ++-- dlls/winemac.drv/macdrv_cocoa.h | 4 ++-- dlls/winemac.drv/unixlib.h | 4 ++-- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/dlls/winemac.drv/cocoa_window.h b/dlls/winemac.drv/cocoa_window.h index a83f2aa803b..9539e4ebdd7 100644 --- a/dlls/winemac.drv/cocoa_window.h +++ b/dlls/winemac.drv/cocoa_window.h @@ -65,7 +65,7 @@ NSRect frameAtResizeStart; BOOL resizingFromLeft, resizingFromTop; - void* imeData; + void* himc; BOOL commandDone; NSSize savedContentMinSize; diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index 2525c894d09..67e178c8ad3 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -403,7 +403,7 @@ @interface WineWindow () @property (nonatomic) CGFloat colorKeyRed, colorKeyGreen, colorKeyBlue; @property (nonatomic) BOOL usePerPixelAlpha; -@property (assign, nonatomic) void* imeData; +@property (assign, nonatomic) void* himc; @property (nonatomic) BOOL commandDone; @property (readonly, copy, nonatomic) NSArray* childWineWindows; @@ -714,7 +714,7 @@ - (void) completeText:(NSString*)text WineWindow* window = (WineWindow*)[self window]; event = macdrv_create_event(IM_SET_TEXT, window); - event->im_set_text.data = [window imeData]; + event->im_set_text.himc = [window himc]; event->im_set_text.text = (CFStringRef)[text copy]; event->im_set_text.complete = TRUE; @@ -797,7 +797,7 @@ - (void) setMarkedText:(id)string selectedRange:(NSRange)selectedRange replaceme markedTextSelection.location += replacementRange.location; event = macdrv_create_event(IM_SET_TEXT, window); - event->im_set_text.data = [window imeData]; + event->im_set_text.himc = [window himc]; event->im_set_text.text = (CFStringRef)[[markedText string] copy]; event->im_set_text.complete = FALSE; event->im_set_text.cursor_pos = markedTextSelection.location + markedTextSelection.length; @@ -860,7 +860,7 @@ - (NSRect) firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointe query = macdrv_create_query(); query->type = QUERY_IME_CHAR_RECT; query->window = (macdrv_window)[window retain]; - query->ime_char_rect.data = [window imeData]; + query->ime_char_rect.himc = [window himc]; query->ime_char_rect.range = CFRangeMake(aRange.location, aRange.length); if ([window.queue query:query timeout:0.3 flags:WineQueryNoPreemptWait]) @@ -947,7 +947,7 @@ @implementation WineWindow @synthesize shapeChangedSinceLastDraw; @synthesize colorKeyed, colorKeyRed, colorKeyGreen, colorKeyBlue; @synthesize usePerPixelAlpha; - @synthesize imeData, commandDone; + @synthesize himc, commandDone; + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)wf windowFrame:(NSRect)window_frame @@ -3903,7 +3903,7 @@ uint32_t macdrv_window_background_color(void) /*********************************************************************** * macdrv_send_text_input_event */ -void macdrv_send_text_input_event(int pressed, unsigned int flags, int repeat, int keyc, void* data, int* done) +void macdrv_send_text_input_event(int pressed, unsigned int flags, int repeat, int keyc, void* himc, int* done) { OnMainThreadAsync(^{ BOOL ret; @@ -3922,7 +3922,7 @@ void macdrv_send_text_input_event(int pressed, unsigned int flags, int repeat, i CGEventRef c; NSEvent* event; - window.imeData = data; + window.himc = himc; fix_device_modifiers_by_generic(&localFlags); // An NSEvent created with +keyEventWithType:... is internally marked diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c index 5953dc0e0d8..03c49b34bae 100644 --- a/dlls/winemac.drv/event.c +++ b/dlls/winemac.drv/event.c @@ -154,7 +154,7 @@ static void macdrv_im_set_text(const macdrv_event *event) struct ime_set_text_params *params; CFIndex length = 0, size; - TRACE_(imm)("win %p/%p himc %p text %s complete %u\n", hwnd, event->window, event->im_set_text.data, + TRACE_(imm)("win %p/%p himc %p text %s complete %u\n", hwnd, event->window, event->im_set_text.himc, debugstr_cf(event->im_set_text.text), event->im_set_text.complete); if (event->im_set_text.text) @@ -163,7 +163,7 @@ static void macdrv_im_set_text(const macdrv_event *event) size = offsetof(struct ime_set_text_params, text[length]); if (!(params = malloc(size))) return; params->hwnd = HandleToUlong(hwnd); - params->data = (UINT_PTR)event->im_set_text.data; + params->himc = (UINT_PTR)event->im_set_text.himc; params->cursor_pos = event->im_set_text.cursor_pos; params->complete = event->im_set_text.complete; @@ -287,7 +287,7 @@ static BOOL query_drag_operation(macdrv_query *query) BOOL query_ime_char_rect(macdrv_query* query) { HWND hwnd = macdrv_get_window_hwnd(query->window); - void *himc = query->ime_char_rect.data; + void *himc = query->ime_char_rect.himc; CFRange *range = &query->ime_char_rect.range; CGRect *rect = &query->ime_char_rect.rect; struct ime_query_char_rect_result result = { .location = 0 }; @@ -298,7 +298,7 @@ BOOL query_ime_char_rect(macdrv_query* query) range->length); params.hwnd = HandleToUlong(hwnd); - params.data = (UINT_PTR)himc; + params.himc = (UINT_PTR)himc; params.result = (UINT_PTR)&result; params.location = range->location; params.length = range->length; diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index f779b4d06b0..5b422eec5c5 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -1322,7 +1322,7 @@ NTSTATUS WINAPI macdrv_ime_set_text(void *arg, ULONG size) { struct ime_set_text_params *params = arg; ULONG length = (size - offsetof(struct ime_set_text_params, text)) / sizeof(WCHAR); - void *himc = param_ptr(params->data); + void *himc = param_ptr(params->himc); HWND hwnd = UlongToHandle(params->hwnd); if (!himc) himc = RealIMC(FROM_MACDRV); @@ -1367,7 +1367,7 @@ NTSTATUS WINAPI macdrv_ime_query_char_rect(void *arg, ULONG size) { struct ime_query_char_rect_params *params = arg; struct ime_query_char_rect_result *result = param_ptr(params->result); - void *himc = param_ptr(params->data); + void *himc = param_ptr(params->himc); IMECHARPOSITION charpos; BOOL ret = FALSE; diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index a82dd319330..4f17d861785 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -378,7 +378,7 @@ typedef struct macdrv_event { unsigned long time_ms; } hotkey_press; struct { - void *data; + void *himc; CFStringRef text; /* new text or NULL if just completing existing text */ unsigned int cursor_pos; unsigned int complete; /* is completing text? */ @@ -487,7 +487,7 @@ typedef struct macdrv_query { CFTypeRef pasteboard; } drag_operation; struct { - void *data; + void *himc; CFRange range; CGRect rect; } ime_char_rect; diff --git a/dlls/winemac.drv/unixlib.h b/dlls/winemac.drv/unixlib.h index 07f0da4a6f3..108ace8914c 100644 --- a/dlls/winemac.drv/unixlib.h +++ b/dlls/winemac.drv/unixlib.h @@ -177,7 +177,7 @@ struct ime_query_char_rect_params { UINT32 hwnd; UINT32 location; - UINT64 data; + UINT64 himc; UINT64 result; /* FIXME: Use NtCallbackReturn instead */ UINT32 length; }; @@ -187,7 +187,7 @@ struct ime_set_text_params { UINT32 hwnd; UINT32 cursor_pos; - UINT64 data; + UINT64 himc; UINT32 complete; WCHAR text[1]; }; From 9dbc6dd2103d3fcf8b2accc11356315804e2ece5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 2 Apr 2023 21:00:09 +0200 Subject: [PATCH 1816/2777] winemac: Use UINT(32) for HIMC in the unixlib interface. (cherry picked from commit d69f799ced32d8a1e5a33a2f90bcb4cf8d4ee043) --- dlls/winemac.drv/ime.c | 2 +- dlls/winemac.drv/keyboard.c | 5 +++-- dlls/winemac.drv/macdrv_main.c | 4 ++-- dlls/winemac.drv/unixlib.h | 6 +++--- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index 5b422eec5c5..866998f1660 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -650,11 +650,11 @@ UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, UnlockRealIMC(hIMC); TRACE("Processing Mac 0x%04x\n", vkey); + params.himc = HandleToULong(hIMC); params.vkey = uVKey; params.scan = uScanCode; params.repeat = repeat; params.key_state = lpbKeyState; - params.himc = hIMC; params.done = &done; MACDRV_CALL(ime_process_text_input, ¶ms); diff --git a/dlls/winemac.drv/keyboard.c b/dlls/winemac.drv/keyboard.c index 9e415bd70e3..bb6fb70fd2a 100644 --- a/dlls/winemac.drv/keyboard.c +++ b/dlls/winemac.drv/keyboard.c @@ -1195,12 +1195,13 @@ NTSTATUS macdrv_ime_process_text_input(void *arg) { struct process_text_input_params *params = arg; struct macdrv_thread_data *thread_data = macdrv_thread_data(); + void *himc = UlongToHandle(params->himc); const BYTE *key_state = params->key_state; unsigned int flags; int keyc; TRACE("vkey 0x%04x scan 0x%04x repeat %u himc %p\n", params->vkey, params->scan, - params->repeat, params->himc); + params->repeat, himc); flags = thread_data->last_modifiers; if (key_state[VK_SHIFT] & 0x80) @@ -1233,7 +1234,7 @@ NTSTATUS macdrv_ime_process_text_input(void *arg) TRACE("flags 0x%08x keyc 0x%04x\n", flags, keyc); macdrv_send_text_input_event(((params->scan & 0x8000) == 0), flags, params->repeat, keyc, - params->himc, params->done); + himc, params->done); return 0; } diff --git a/dlls/winemac.drv/macdrv_main.c b/dlls/winemac.drv/macdrv_main.c index eeed9a4bcbe..a4b280283ee 100644 --- a/dlls/winemac.drv/macdrv_main.c +++ b/dlls/winemac.drv/macdrv_main.c @@ -667,20 +667,20 @@ static NTSTATUS wow64_ime_process_text_input(void *arg) { struct { + UINT himc; UINT vkey; UINT scan; UINT repeat; ULONG key_state; - ULONG himc; ULONG done; } *params32 = arg; struct process_text_input_params params; + params.himc = params32->himc; params.vkey = params32->vkey; params.scan = params32->scan; params.repeat = params32->repeat; params.key_state = UlongToPtr(params32->key_state); - params.himc = UlongToPtr(params32->himc); params.done = UlongToPtr(params32->done); return macdrv_ime_process_text_input(¶ms); } diff --git a/dlls/winemac.drv/unixlib.h b/dlls/winemac.drv/unixlib.h index 108ace8914c..ca5115f4982 100644 --- a/dlls/winemac.drv/unixlib.h +++ b/dlls/winemac.drv/unixlib.h @@ -63,11 +63,11 @@ struct dnd_have_format_params /* macdrv_ime_process_text_input params */ struct process_text_input_params { + UINT himc; UINT vkey; UINT scan; UINT repeat; const BYTE *key_state; - void *himc; int *done; }; @@ -177,7 +177,7 @@ struct ime_query_char_rect_params { UINT32 hwnd; UINT32 location; - UINT64 himc; + UINT32 himc; UINT64 result; /* FIXME: Use NtCallbackReturn instead */ UINT32 length; }; @@ -187,7 +187,7 @@ struct ime_set_text_params { UINT32 hwnd; UINT32 cursor_pos; - UINT64 himc; + UINT32 himc; UINT32 complete; WCHAR text[1]; }; From ea05b46c7a175cdc1ad5e4dc588ad391980ff128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 30 Mar 2023 11:23:32 +0200 Subject: [PATCH 1817/2777] winemac: Assume IME UI window always has a valid HIMC. (cherry picked from commit f16dcbbe470cb61edae2aa6f082de1343a01fb55) --- dlls/winemac.drv/ime.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index 866998f1660..89341ba4f10 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -498,7 +498,7 @@ static void UpdateDataInDefaultIMEWindow(HIMC hIMC, HWND hwnd, BOOL showable) LPCOMPOSITIONSTRING compstr; LPINPUTCONTEXT lpIMC; - lpIMC = LockRealIMC(hIMC); + lpIMC = ImmLockIMC(hIMC); if (lpIMC == NULL) return; @@ -517,7 +517,7 @@ static void UpdateDataInDefaultIMEWindow(HIMC hIMC, HWND hwnd, BOOL showable) if (compstr != NULL) ImmUnlockIMCC(lpIMC->hCompStr); - UnlockRealIMC(hIMC); + ImmUnlockIMC(hIMC); } BOOL WINAPI ImeDestroy(UINT uForce) @@ -945,7 +945,7 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) INT offX = 0, offY = 0; LPINPUTCONTEXT lpIMC; - lpIMC = LockRealIMC(hIMC); + lpIMC = ImmLockIMC(hIMC); if (lpIMC == NULL) return; @@ -1060,7 +1060,7 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) ImmUnlockIMCC(lpIMC->hCompStr); EndPaint(hwnd, &ps); - UnlockRealIMC(hIMC); + ImmUnlockIMC(hIMC); } static void DefaultIMEComposition(HIMC hIMC, HWND hwnd, LPARAM lParam) @@ -1074,14 +1074,14 @@ static void DefaultIMEStartComposition(HIMC hIMC, HWND hwnd) { LPINPUTCONTEXT lpIMC; - lpIMC = LockRealIMC(hIMC); + lpIMC = ImmLockIMC(hIMC); if (lpIMC == NULL) return; TRACE("IME message WM_IME_STARTCOMPOSITION\n"); lpIMC->hWnd = GetFocus(); ShowWindow(hwnd, SW_SHOWNOACTIVATE); - UnlockRealIMC(hIMC); + ImmUnlockIMC(hIMC); } static LRESULT ImeHandleNotify(HIMC hIMC, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) @@ -1150,8 +1150,6 @@ static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM */ hIMC = (HIMC)GetWindowLongPtrW(hwnd, IMMGWL_IMC); - if (!hIMC) - hIMC = RealIMC(FROM_MACDRV); /* if we have no hIMC there are many messages we cannot process */ if (hIMC == NULL) @@ -1180,14 +1178,14 @@ static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM SetWindowTextA(hwnd, "Wine Ime Active"); - lpIMC = LockRealIMC(hIMC); + lpIMC = ImmLockIMC(hIMC); if (lpIMC) { myPrivate = ImmLockIMCC(lpIMC->hPrivate); myPrivate->hwndDefault = hwnd; ImmUnlockIMCC(lpIMC->hPrivate); } - UnlockRealIMC(hIMC); + ImmUnlockIMC(hIMC); return TRUE; } From c5b8b6c00a0f1d140548ffa59ac90d1400ffc9d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 1 Apr 2023 18:58:50 +0200 Subject: [PATCH 1818/2777] winemac: Pass INPUTCONTEXT pointer to UpdateDataInDefaultIMEWindow. (cherry picked from commit 5f413c1ff58d086a8813bfce3385d26ce0f78134) --- dlls/winemac.drv/ime.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index 89341ba4f10..d9fa3dd8712 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -493,14 +493,9 @@ static void IME_AddToSelected(HIMC hIMC) hSelectedFrom[hSelectedCount - 1] = hIMC; } -static void UpdateDataInDefaultIMEWindow(HIMC hIMC, HWND hwnd, BOOL showable) +static void UpdateDataInDefaultIMEWindow(INPUTCONTEXT *lpIMC, HWND hwnd, BOOL showable) { LPCOMPOSITIONSTRING compstr; - LPINPUTCONTEXT lpIMC; - - lpIMC = ImmLockIMC(hIMC); - if (lpIMC == NULL) - return; if (lpIMC->hCompStr) compstr = ImmLockIMCC(lpIMC->hCompStr); @@ -516,8 +511,6 @@ static void UpdateDataInDefaultIMEWindow(HIMC hIMC, HWND hwnd, BOOL showable) if (compstr != NULL) ImmUnlockIMCC(lpIMC->hCompStr); - - ImmUnlockIMC(hIMC); } BOOL WINAPI ImeDestroy(UINT uForce) @@ -674,8 +667,11 @@ UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, return msgs; } - else - UpdateDataInDefaultIMEWindow(hIMC, hwndDefault, FALSE); + else if ((lpIMC = LockRealIMC(hIMC))) + { + UpdateDataInDefaultIMEWindow(lpIMC, hwndDefault, FALSE); + UnlockRealIMC(hIMC); + } return 0; } @@ -1065,9 +1061,12 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) static void DefaultIMEComposition(HIMC hIMC, HWND hwnd, LPARAM lParam) { + INPUTCONTEXT *ctx; TRACE("IME message WM_IME_COMPOSITION 0x%Ix\n", lParam); - if (!(lParam & GCS_RESULTSTR)) - UpdateDataInDefaultIMEWindow(hIMC, hwnd, TRUE); + if (lParam & GCS_RESULTSTR) return; + if (!(ctx = ImmLockIMC( hIMC ))) return; + UpdateDataInDefaultIMEWindow( ctx, hwnd, TRUE ); + ImmUnlockIMC(hIMC); } static void DefaultIMEStartComposition(HIMC hIMC, HWND hwnd) From 25376c9939cfb1559065588d1c475c5ac71aef55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 1 Apr 2023 21:01:36 +0200 Subject: [PATCH 1819/2777] winemac: Add a helper to get IME private window. (cherry picked from commit 7c09cae7f4eb23de107e1f5f0f9769f89a102fff) --- dlls/winemac.drv/ime.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index d9fa3dd8712..47e49dd0f32 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -44,7 +44,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm); #define FROM_MACDRV ((HIMC)0xcafe1337) -typedef struct _IMEPRIVATE { +typedef struct ime_private +{ BOOL bInComposition; BOOL bInternalState; HFONT textfont; @@ -67,6 +68,16 @@ static UINT WM_MSIME_RECONVERT; static UINT WM_MSIME_QUERYPOSITION; static UINT WM_MSIME_DOCUMENTFEED; +static HWND input_context_get_ui_hwnd( INPUTCONTEXT *ctx ) +{ + struct ime_private *priv; + HWND hwnd; + if (!(priv = ImmLockIMCC( ctx->hPrivate ))) return NULL; + hwnd = priv->hwndDefault; + ImmUnlockIMCC( ctx->hPrivate ); + return hwnd; +} + static HIMC RealIMC(HIMC hIMC) { if (hIMC == FROM_MACDRV) @@ -543,13 +554,14 @@ BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lp if (lpIMC) { LPIMEPRIVATE myPrivate; + HWND hwnd = input_context_get_ui_hwnd( lpIMC ); myPrivate = ImmLockIMCC(lpIMC->hPrivate); if (inIME && !myPrivate->bInternalState) ImmSetOpenStatus(RealIMC(FROM_MACDRV), TRUE); else if (!inIME && myPrivate->bInternalState) { - ShowWindow(myPrivate->hwndDefault, SW_HIDE); + ShowWindow( hwnd, SW_HIDE ); ImmDestroyIMCC(lpIMC->hCompStr); lpIMC->hCompStr = ImeCreateBlankCompStr(); ImmSetOpenStatus(RealIMC(FROM_MACDRV), FALSE); @@ -614,7 +626,7 @@ UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, UINT vkey; LPINPUTCONTEXT lpIMC; LPIMEPRIVATE myPrivate; - HWND hwndDefault; + HWND hwnd; UINT repeat; int done = 0; @@ -629,6 +641,7 @@ UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, } lpIMC = LockRealIMC(hIMC); + hwnd = input_context_get_ui_hwnd( lpIMC ); myPrivate = ImmLockIMCC(lpIMC->hPrivate); if (!myPrivate->bInternalState) { @@ -638,7 +651,6 @@ UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, } repeat = myPrivate->repeat; - hwndDefault = myPrivate->hwndDefault; ImmUnlockIMCC(lpIMC->hPrivate); UnlockRealIMC(hIMC); @@ -669,7 +681,7 @@ UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, } else if ((lpIMC = LockRealIMC(hIMC))) { - UpdateDataInDefaultIMEWindow(lpIMC, hwndDefault, FALSE); + UpdateDataInDefaultIMEWindow( lpIMC, hwnd, FALSE ); UnlockRealIMC(hIMC); } return 0; @@ -1409,11 +1421,12 @@ NTSTATUS WINAPI macdrv_ime_query_char_rect(void *arg, ULONG size) LPBYTE compdata = ImmLockIMCC(ic->hCompStr); LPCOMPOSITIONSTRING compstr = (LPCOMPOSITIONSTRING)compdata; LPWSTR str = (LPWSTR)(compdata + compstr->dwCompStrOffset); + HWND hwnd; - if (private->hwndDefault && compstr->dwCompStrOffset && - IsWindowVisible(private->hwndDefault)) + if ((hwnd = input_context_get_ui_hwnd( ic )) && IsWindowVisible( hwnd ) && + compstr->dwCompStrOffset) { - HDC dc = GetDC(private->hwndDefault); + HDC dc = GetDC( hwnd ); HFONT oldfont = NULL; SIZE size; @@ -1436,13 +1449,13 @@ NTSTATUS WINAPI macdrv_ime_query_char_rect(void *arg, ULONG size) OffsetRect(&charpos.rcDocument, 10, 10); LPtoDP(dc, (POINT*)&charpos.rcDocument, 2); - MapWindowPoints(private->hwndDefault, 0, (POINT*)&charpos.rcDocument, 2); + MapWindowPoints( hwnd, 0, (POINT *)&charpos.rcDocument, 2 ); result->rect = charpos.rcDocument; ret = TRUE; if (oldfont) SelectObject(dc, oldfont); - ReleaseDC(private->hwndDefault, dc); + ReleaseDC( hwnd, dc ); } ImmUnlockIMCC(ic->hCompStr); From 794a1e7c196354d92ef99b1c16ea739105acf0cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 1 Apr 2023 21:56:41 +0200 Subject: [PATCH 1820/2777] winemac: Add a helper to get COMPOSITIONSTRING text. (cherry picked from commit fc37fdc44ea0f7e33b968f62a0b3b19ddade4c98) --- dlls/winemac.drv/ime.c | 77 ++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index 47e49dd0f32..f99495d9a64 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -68,6 +68,27 @@ static UINT WM_MSIME_RECONVERT; static UINT WM_MSIME_QUERYPOSITION; static UINT WM_MSIME_DOCUMENTFEED; +static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT *length ) +{ + COMPOSITIONSTRING *string; + WCHAR *text = NULL; + UINT len, off; + + if (!(string = ImmLockIMCC( ctx->hCompStr ))) return NULL; + len = result ? string->dwResultStrLen : string->dwCompStrLen; + off = result ? string->dwResultStrOffset : string->dwCompStrOffset; + + if (len && off && (text = malloc( (len + 1) * sizeof(WCHAR) ))) + { + memcpy( text, (BYTE *)string + off, len * sizeof(WCHAR) ); + text[len] = 0; + *length = len; + } + + ImmUnlockIMCC( ctx->hCompStr ); + return text; +} + static HWND input_context_get_ui_hwnd( INPUTCONTEXT *ctx ) { struct ime_private *priv; @@ -760,11 +781,9 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) case CPS_COMPLETE: { HIMCC newCompStr; - DWORD cplen = 0; - LPWSTR cpstr; - LPCOMPOSITIONSTRING cs = NULL; - LPBYTE cdata = NULL; LPIMEPRIVATE myPrivate; + WCHAR *str; + UINT len; TRACE("NI_COMPOSITIONSTR: CPS_COMPLETE\n"); @@ -774,21 +793,13 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) ImmDestroyIMCC(lpIMC->hCompStr); lpIMC->hCompStr = newCompStr; - if (lpIMC->hCompStr) - { - cdata = ImmLockIMCC(lpIMC->hCompStr); - cs = (LPCOMPOSITIONSTRING)cdata; - cplen = cs->dwCompStrLen; - cpstr = (LPWSTR)&cdata[cs->dwCompStrOffset]; - ImmUnlockIMCC(lpIMC->hCompStr); - } myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (cplen > 0) + if ((str = input_context_get_comp_str( lpIMC, FALSE, &len ))) { - WCHAR param = cpstr[0]; + WCHAR param = str[0]; DWORD flags = GCS_COMPSTR; - newCompStr = updateResultStr(lpIMC->hCompStr, cpstr, cplen); + newCompStr = updateResultStr( lpIMC->hCompStr, str, len ); ImmDestroyIMCC(lpIMC->hCompStr); lpIMC->hCompStr = newCompStr; newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0, &flags); @@ -801,6 +812,7 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) GCS_RESULTSTR | GCS_RESULTCLAUSE); GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); + free( str ); } else if (myPrivate->bInComposition) GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); @@ -946,12 +958,12 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) PAINTSTRUCT ps; RECT rect; HDC hdc; - LPCOMPOSITIONSTRING compstr; - LPBYTE compdata = NULL; HMONITOR monitor; MONITORINFO mon_info; INT offX = 0, offY = 0; LPINPUTCONTEXT lpIMC; + WCHAR *str; + UINT len; lpIMC = ImmLockIMC(hIMC); if (lpIMC == NULL) @@ -962,18 +974,13 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) GetClientRect(hwnd, &rect); FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1)); - compdata = ImmLockIMCC(lpIMC->hCompStr); - compstr = (LPCOMPOSITIONSTRING)compdata; - - if (compstr->dwCompStrLen && compstr->dwCompStrOffset) + if ((str = input_context_get_comp_str( lpIMC, FALSE, &len ))) { SIZE size; POINT pt; HFONT oldfont = NULL; - LPWSTR CompString; LPIMEPRIVATE myPrivate; - CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset); myPrivate = ImmLockIMCC(lpIMC->hPrivate); if (myPrivate->textfont) @@ -981,7 +988,7 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) ImmUnlockIMCC(lpIMC->hPrivate); - GetTextExtentPoint32W(hdc, CompString, compstr->dwCompStrLen, &size); + GetTextExtentPoint32W( hdc, str, len, &size ); pt.x = size.cx; pt.y = size.cy; LPtoDP(hdc, &pt, 1); @@ -1059,10 +1066,11 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE); - TextOutW(hdc, offX, offY, CompString, compstr->dwCompStrLen); + TextOutW( hdc, offX, offY, str, len ); if (oldfont) SelectObject(hdc, oldfont); + free( str ); } ImmUnlockIMCC(lpIMC->hCompStr); @@ -1418,13 +1426,12 @@ NTSTATUS WINAPI macdrv_ime_query_char_rect(void *arg, ULONG size) if (ic) { LPIMEPRIVATE private = ImmLockIMCC(ic->hPrivate); - LPBYTE compdata = ImmLockIMCC(ic->hCompStr); - LPCOMPOSITIONSTRING compstr = (LPCOMPOSITIONSTRING)compdata; - LPWSTR str = (LPWSTR)(compdata + compstr->dwCompStrOffset); + WCHAR *str; HWND hwnd; + UINT len; if ((hwnd = input_context_get_ui_hwnd( ic )) && IsWindowVisible( hwnd ) && - compstr->dwCompStrOffset) + (str = input_context_get_comp_str( ic, FALSE, &len ))) { HDC dc = GetDC( hwnd ); HFONT oldfont = NULL; @@ -1433,15 +1440,13 @@ NTSTATUS WINAPI macdrv_ime_query_char_rect(void *arg, ULONG size) if (private->textfont) oldfont = SelectObject(dc, private->textfont); - if (result->location > compstr->dwCompStrLen) - result->location = compstr->dwCompStrLen; - if (result->location + result->length > compstr->dwCompStrLen) - result->length = compstr->dwCompStrLen - result->location; + if (result->location > len) result->location = len; + if (result->location + result->length > len) result->length = len - result->location; - GetTextExtentPoint32W(dc, str, result->location, &size); + GetTextExtentPoint32W( dc, str, result->location, &size ); charpos.rcDocument.left = size.cx; charpos.rcDocument.top = 0; - GetTextExtentPoint32W(dc, str, result->location + result->length, &size); + GetTextExtentPoint32W( dc, str, result->location + result->length, &size ); charpos.rcDocument.right = size.cx; charpos.rcDocument.bottom = size.cy; @@ -1456,9 +1461,9 @@ NTSTATUS WINAPI macdrv_ime_query_char_rect(void *arg, ULONG size) if (oldfont) SelectObject(dc, oldfont); ReleaseDC( hwnd, dc ); + free( str ); } - ImmUnlockIMCC(ic->hCompStr); ImmUnlockIMCC(ic->hPrivate); } From 375cb52fa89cb7eab3838b2c9d191d6c46143927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 1 Apr 2023 21:23:19 +0200 Subject: [PATCH 1821/2777] winemac: Add a helper to select IME private font. (cherry picked from commit addef4c979ac524bf44bae75c19190d8ae3218c5) --- dlls/winemac.drv/ime.c | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index f99495d9a64..5e78ae055fb 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -99,6 +99,16 @@ static HWND input_context_get_ui_hwnd( INPUTCONTEXT *ctx ) return hwnd; } +static HFONT input_context_select_ui_font( INPUTCONTEXT *ctx, HDC hdc ) +{ + struct ime_private *priv; + HFONT font = NULL; + if (!(priv = ImmLockIMCC( ctx->hPrivate ))) return NULL; + if (priv->textfont) font = SelectObject( hdc, priv->textfont ); + ImmUnlockIMCC( ctx->hPrivate ); + return font; +} + static HIMC RealIMC(HIMC hIMC) { if (hIMC == FROM_MACDRV) @@ -976,17 +986,9 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) if ((str = input_context_get_comp_str( lpIMC, FALSE, &len ))) { + HFONT font = input_context_select_ui_font( lpIMC, hdc ); SIZE size; POINT pt; - HFONT oldfont = NULL; - LPIMEPRIVATE myPrivate; - - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - - if (myPrivate->textfont) - oldfont = SelectObject(hdc, myPrivate->textfont); - - ImmUnlockIMCC(lpIMC->hPrivate); GetTextExtentPoint32W( hdc, str, len, &size ); pt.x = size.cx; @@ -1068,8 +1070,7 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) TextOutW( hdc, offX, offY, str, len ); - if (oldfont) - SelectObject(hdc, oldfont); + if (font) SelectObject( hdc, font ); free( str ); } @@ -1425,7 +1426,6 @@ NTSTATUS WINAPI macdrv_ime_query_char_rect(void *arg, ULONG size) if (ic) { - LPIMEPRIVATE private = ImmLockIMCC(ic->hPrivate); WCHAR *str; HWND hwnd; UINT len; @@ -1434,12 +1434,9 @@ NTSTATUS WINAPI macdrv_ime_query_char_rect(void *arg, ULONG size) (str = input_context_get_comp_str( ic, FALSE, &len ))) { HDC dc = GetDC( hwnd ); - HFONT oldfont = NULL; + HFONT font = input_context_select_ui_font( ic, dc ); SIZE size; - if (private->textfont) - oldfont = SelectObject(dc, private->textfont); - if (result->location > len) result->location = len; if (result->location + result->length > len) result->length = len - result->location; @@ -1458,13 +1455,10 @@ NTSTATUS WINAPI macdrv_ime_query_char_rect(void *arg, ULONG size) result->rect = charpos.rcDocument; ret = TRUE; - if (oldfont) - SelectObject(dc, oldfont); + if (font) SelectObject( dc, font ); ReleaseDC( hwnd, dc ); free( str ); } - - ImmUnlockIMCC(ic->hPrivate); } ImmUnlockIMC(himc); From e4f7bf205ea875e23f2ce8f0c8d363f6413e6a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 30 Mar 2023 11:17:29 +0200 Subject: [PATCH 1822/2777] winex11: Assume IME UI window always has a valid HIMC. (cherry picked from commit fd9cd64b7950a461a746b452679efade875fd891) --- dlls/winex11.drv/ime.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 9c0894717ad..c494aaed2be 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -987,7 +987,7 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) INT offX=0, offY=0; LPINPUTCONTEXT lpIMC; - lpIMC = LockRealIMC(hIMC); + lpIMC = ImmLockIMC(hIMC); if (lpIMC == NULL) return; @@ -1101,7 +1101,7 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) ImmUnlockIMCC(lpIMC->hCompStr); EndPaint(hwnd,&ps); - UnlockRealIMC(hIMC); + ImmUnlockIMC(hIMC); } static void UpdateDefaultIMEWindow(HIMC hIMC, HWND hwnd) @@ -1109,7 +1109,7 @@ static void UpdateDefaultIMEWindow(HIMC hIMC, HWND hwnd) LPCOMPOSITIONSTRING compstr; LPINPUTCONTEXT lpIMC; - lpIMC = LockRealIMC(hIMC); + lpIMC = ImmLockIMC(hIMC); if (lpIMC == NULL) return; @@ -1130,7 +1130,7 @@ static void UpdateDefaultIMEWindow(HIMC hIMC, HWND hwnd) ImmUnlockIMCC(lpIMC->hCompStr); lpIMC->hWnd = GetFocus(); - UnlockRealIMC(hIMC); + ImmUnlockIMC(hIMC); } static void DefaultIMEComposition(HIMC hIMC, HWND hwnd, LPARAM lParam) @@ -1214,8 +1214,6 @@ static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, */ hIMC = (HIMC)GetWindowLongPtrW(hwnd,IMMGWL_IMC); - if (!hIMC) - hIMC = RealIMC(FROM_X11); /* if we have no hIMC there are many messages we cannot process */ if (hIMC == NULL) @@ -1244,14 +1242,14 @@ static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, SetWindowTextA(hwnd,"Wine Ime Active"); - lpIMC = LockRealIMC(hIMC); + lpIMC = ImmLockIMC(hIMC); if (lpIMC) { myPrivate = ImmLockIMCC(lpIMC->hPrivate); myPrivate->hwndDefault = hwnd; ImmUnlockIMCC(lpIMC->hPrivate); } - UnlockRealIMC(hIMC); + ImmUnlockIMC(hIMC); return TRUE; } From 1ee65acb4d15c7d9f08e78e313c5a0d29b3f9543 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 1 Apr 2023 18:58:50 +0200 Subject: [PATCH 1823/2777] winex11: Pass INPUTCONTEXT pointer to UpdateDefaultIMEWindow. (cherry picked from commit b869270bef99e6f2f881c102a56e4576bdcf1304) --- dlls/winex11.drv/ime.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index c494aaed2be..8c7dac56251 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -1104,14 +1104,9 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) ImmUnlockIMC(hIMC); } -static void UpdateDefaultIMEWindow(HIMC hIMC, HWND hwnd) +static void UpdateDefaultIMEWindow(INPUTCONTEXT *lpIMC, HWND hwnd) { LPCOMPOSITIONSTRING compstr; - LPINPUTCONTEXT lpIMC; - - lpIMC = ImmLockIMC(hIMC); - if (lpIMC == NULL) - return; if (lpIMC->hCompStr) compstr = ImmLockIMCC(lpIMC->hCompStr); @@ -1130,20 +1125,25 @@ static void UpdateDefaultIMEWindow(HIMC hIMC, HWND hwnd) ImmUnlockIMCC(lpIMC->hCompStr); lpIMC->hWnd = GetFocus(); - ImmUnlockIMC(hIMC); } static void DefaultIMEComposition(HIMC hIMC, HWND hwnd, LPARAM lParam) { + INPUTCONTEXT *ctx; TRACE("IME message WM_IME_COMPOSITION 0x%Ix\n", lParam); - if (!(lParam & GCS_RESULTSTR)) - UpdateDefaultIMEWindow(hIMC, hwnd); + if (lParam & GCS_RESULTSTR) return; + if (!(ctx = ImmLockIMC( hIMC ))) return; + UpdateDefaultIMEWindow( ctx, hwnd ); + ImmUnlockIMC(hIMC); } static void DefaultIMEStartComposition(HIMC hIMC, HWND hwnd ) { + INPUTCONTEXT *ctx; TRACE("IME message WM_IME_STARTCOMPOSITION\n"); - UpdateDefaultIMEWindow(hIMC, hwnd); + if (!(ctx = ImmLockIMC( hIMC ))) return; + UpdateDefaultIMEWindow( ctx, hwnd ); + ImmUnlockIMC(hIMC); } static LRESULT ImeHandleNotify(HIMC hIMC, HWND hwnd, UINT msg, WPARAM wParam, From c95474ef0670bc1de4049f859bc65ee984da50c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 1 Apr 2023 20:42:39 +0200 Subject: [PATCH 1824/2777] winex11: Add a helper to get COMPOSITIONSTRING text. (cherry picked from commit 904ddc7eb5d5c31361d41d5aaaea36f1be341a0c) --- dlls/winex11.drv/ime.c | 60 +++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 8c7dac56251..050f273cf88 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -70,6 +70,27 @@ static UINT WM_MSIME_RECONVERT; static UINT WM_MSIME_QUERYPOSITION; static UINT WM_MSIME_DOCUMENTFEED; +static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT *length ) +{ + COMPOSITIONSTRING *string; + WCHAR *text = NULL; + UINT len, off; + + if (!(string = ImmLockIMCC( ctx->hCompStr ))) return NULL; + len = result ? string->dwResultStrLen : string->dwCompStrLen; + off = result ? string->dwResultStrOffset : string->dwCompStrOffset; + + if (len && off && (text = malloc( (len + 1) * sizeof(WCHAR) ))) + { + memcpy( text, (BYTE *)string + off, len * sizeof(WCHAR) ); + text[len] = 0; + *length = len; + } + + ImmUnlockIMCC( ctx->hCompStr ); + return text; +} + static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); @@ -659,11 +680,9 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) case CPS_COMPLETE: { HIMCC newCompStr; - DWORD cplen = 0; - LPWSTR cpstr; - LPCOMPOSITIONSTRING cs = NULL; - LPBYTE cdata = NULL; LPIMEPRIVATE myPrivate; + WCHAR *str; + UINT len; TRACE("CPS_COMPLETE\n"); @@ -673,20 +692,12 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) ImmDestroyIMCC(lpIMC->hCompStr); lpIMC->hCompStr = newCompStr; - if (lpIMC->hCompStr) - { - cdata = ImmLockIMCC(lpIMC->hCompStr); - cs = (LPCOMPOSITIONSTRING)cdata; - cplen = cs->dwCompStrLen; - cpstr = (LPWSTR)&(cdata[cs->dwCompStrOffset]); - ImmUnlockIMCC(lpIMC->hCompStr); - } myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (cplen > 0) + if ((str = input_context_get_comp_str( lpIMC, FALSE, &len ))) { - WCHAR param = cpstr[0]; + WCHAR param = str[0]; - newCompStr = updateResultStr(lpIMC->hCompStr, cpstr, cplen); + newCompStr = updateResultStr( lpIMC->hCompStr, str, len ); ImmDestroyIMCC(lpIMC->hCompStr); lpIMC->hCompStr = newCompStr; newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0); @@ -700,6 +711,7 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) GCS_RESULTSTR|GCS_RESULTCLAUSE); GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0); + free( str ); } else if (myPrivate->bInComposition) GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0); @@ -980,12 +992,12 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) PAINTSTRUCT ps; RECT rect; HDC hdc; - LPCOMPOSITIONSTRING compstr; - LPBYTE compdata = NULL; HMONITOR monitor; MONITORINFO mon_info; INT offX=0, offY=0; LPINPUTCONTEXT lpIMC; + WCHAR *str; + UINT len; lpIMC = ImmLockIMC(hIMC); if (lpIMC == NULL) @@ -996,18 +1008,13 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) GetClientRect(hwnd,&rect); FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1)); - compdata = ImmLockIMCC(lpIMC->hCompStr); - compstr = (LPCOMPOSITIONSTRING)compdata; - - if (compstr->dwCompStrLen && compstr->dwCompStrOffset) + if ((str = input_context_get_comp_str( lpIMC, FALSE, &len ))) { SIZE size; POINT pt; HFONT oldfont = NULL; - LPWSTR CompString; LPIMEPRIVATE myPrivate; - CompString = (LPWSTR)(compdata + compstr->dwCompStrOffset); myPrivate = ImmLockIMCC(lpIMC->hPrivate); if (myPrivate->textfont) @@ -1015,7 +1022,7 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) ImmUnlockIMCC(lpIMC->hPrivate); - GetTextExtentPoint32W(hdc, CompString, compstr->dwCompStrLen, &size); + GetTextExtentPoint32W( hdc, str, len, &size ); pt.x = size.cx; pt.y = size.cy; LPtoDP(hdc,&pt,1); @@ -1092,14 +1099,13 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE); - TextOutW(hdc, offX,offY, CompString, compstr->dwCompStrLen); + TextOutW( hdc, offX, offY, str, len ); if (oldfont) SelectObject(hdc,oldfont); + free( str ); } - ImmUnlockIMCC(lpIMC->hCompStr); - EndPaint(hwnd,&ps); ImmUnlockIMC(hIMC); } From ee851f489f3c79161bc0df8e7f33328551bce4a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 1 Apr 2023 21:23:05 +0200 Subject: [PATCH 1825/2777] winex11: Add a helper to select IME private font. (cherry picked from commit bf9a649e10503f3346d836962c50fa5a28ccdf8a) --- dlls/winex11.drv/ime.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 050f273cf88..a499c8d9dd6 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -49,7 +49,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm); #define FROM_X11 ((HIMC)0xcafe1337) -typedef struct _IMEPRIVATE { +typedef struct ime_private +{ BOOL bInComposition; BOOL bInternalState; HFONT textfont; @@ -91,6 +92,16 @@ static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT * return text; } +static HFONT input_context_select_ui_font( INPUTCONTEXT *ctx, HDC hdc ) +{ + struct ime_private *priv; + HFONT font = NULL; + if (!(priv = ImmLockIMCC( ctx->hPrivate ))) return NULL; + if (priv->textfont) font = SelectObject( hdc, priv->textfont ); + ImmUnlockIMCC( ctx->hPrivate ); + return font; +} + static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); @@ -1010,17 +1021,9 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) if ((str = input_context_get_comp_str( lpIMC, FALSE, &len ))) { + HFONT font = input_context_select_ui_font( lpIMC, hdc ); SIZE size; POINT pt; - HFONT oldfont = NULL; - LPIMEPRIVATE myPrivate; - - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - - if (myPrivate->textfont) - oldfont = SelectObject(hdc,myPrivate->textfont); - - ImmUnlockIMCC(lpIMC->hPrivate); GetTextExtentPoint32W( hdc, str, len, &size ); pt.x = size.cx; @@ -1101,8 +1104,7 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) TextOutW( hdc, offX, offY, str, len ); - if (oldfont) - SelectObject(hdc,oldfont); + if (font) SelectObject( hdc, font ); free( str ); } From cf7e51c54d333164f61bebacd0e708b45abe15e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 2 Apr 2023 13:42:00 +0200 Subject: [PATCH 1826/2777] winex11: Register XIC status callbacks. (cherry picked from commit 08bc39bd0eca69645fa3e816f47cfb8e682797dc) --- dlls/winex11.drv/xim.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 9f238e0cb83..1637549511b 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -270,6 +270,27 @@ static int xic_preedit_caret( XIC xic, XPointer user, XPointer arg ) return 0; } +static int xic_status_start( XIC xic, XPointer user, XPointer arg ) +{ + HWND hwnd = (HWND)user; + TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg ); + return 0; +} + +static int xic_status_done( XIC xic, XPointer user, XPointer arg ) +{ + HWND hwnd = (HWND)user; + TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg ); + return 0; +} + +static int xic_status_draw( XIC xic, XPointer user, XPointer arg ) +{ + HWND hwnd = (HWND)user; + TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg ); + return 0; +} + NTSTATUS x11drv_xim_reset( void *hwnd ) { XIC ic = X11DRV_get_ic(hwnd); @@ -467,6 +488,9 @@ XIC X11DRV_CreateIC( XIM xim, HWND hwnd, struct x11drv_win_data *data ) XICCallback preedit_draw = {.callback = xic_preedit_draw, .client_data = (XPointer)hwnd}; XICCallback preedit_start = {.callback = xic_preedit_start, .client_data = (XPointer)hwnd}; XICCallback preedit_state_notify = {.callback = xic_preedit_state_notify, .client_data = (XPointer)hwnd}; + XICCallback status_done = {.callback = xic_status_done, .client_data = (XPointer)hwnd}; + XICCallback status_draw = {.callback = xic_status_draw, .client_data = (XPointer)hwnd}; + XICCallback status_start = {.callback = xic_status_start, .client_data = (XPointer)hwnd}; XPoint spot = {0}; XVaNestedList preedit, status; XIC xic; @@ -482,7 +506,11 @@ XIC X11DRV_CreateIC( XIM xim, HWND hwnd, struct x11drv_win_data *data ) XNPreeditStartCallback, &preedit_start, XNPreeditStateNotifyCallback, &preedit_state_notify, XNSpotLocation, &spot, NULL ); - status = XVaCreateNestedList( 0, XNFontSet, fontSet, NULL ); + status = XVaCreateNestedList( 0, XNFontSet, fontSet, + XNStatusStartCallback, &status_start, + XNStatusDoneCallback, &status_done, + XNStatusDrawCallback, &status_draw, + NULL ); xic = XCreateIC( xim, XNInputStyle, ximStyle, XNPreeditAttributes, preedit, XNStatusAttributes, status, XNClientWindow, win, XNFocusWindow, win, XNDestroyCallback, &destroy, NULL ); TRACE( "created XIC %p\n", xic ); From 476f7a7e741a4b118f0c9a1db7b6dd3ba562efaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 2 Apr 2023 14:09:36 +0200 Subject: [PATCH 1827/2777] winex11: Refactor XIM input style selection. (cherry picked from commit d0691e8c9a0e4ebdbeacbbec92fa36f63d0cf1cc) --- dlls/winex11.drv/xim.c | 84 ++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 56 deletions(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 1637549511b..e73e019d448 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -49,17 +49,8 @@ static DWORD dwCompStringLength = 0; static LPBYTE CompositionString = NULL; static DWORD dwCompStringSize = 0; -#define STYLE_OFFTHESPOT (XIMPreeditArea | XIMStatusArea) -#define STYLE_OVERTHESPOT (XIMPreeditPosition | XIMStatusNothing) -#define STYLE_ROOT (XIMPreeditNothing | XIMStatusNothing) -/* this uses all the callbacks to utilize full IME support */ -#define STYLE_CALLBACK (XIMPreeditCallbacks | XIMStatusNothing) -/* in order to enable deadkey support */ -#define STYLE_NONE (XIMPreeditNothing | XIMStatusNothing) - -static XIMStyle ximStyle = 0; -static XIMStyle ximStyleRoot = 0; -static XIMStyle ximStyleRequest = STYLE_CALLBACK; +static XIMStyle input_style = 0; +static XIMStyle input_style_req = XIMPreeditCallbacks | XIMStatusCallbacks; static const char *debugstr_xim_style( XIMStyle style ) { @@ -338,13 +329,6 @@ BOOL xim_init( const WCHAR *input_style ) static const WCHAR overthespotW[] = {'o','v','e','r','t','h','e','s','p','o','t',0}; static const WCHAR rootW[] = {'r','o','o','t',0}; - if (!wcsicmp( input_style, offthespotW )) - ximStyleRequest = STYLE_OFFTHESPOT; - else if (!wcsicmp( input_style, overthespotW )) - ximStyleRequest = STYLE_OVERTHESPOT; - else if (!wcsicmp( input_style, rootW )) - ximStyleRequest = STYLE_ROOT; - if (!XSupportsLocale()) { WARN("X does not support locale.\n"); @@ -355,6 +339,17 @@ BOOL xim_init( const WCHAR *input_style ) WARN("Could not set locale modifiers.\n"); return FALSE; } + + if (!wcsicmp( input_style, offthespotW )) + input_style_req = XIMPreeditArea | XIMStatusArea; + else if (!wcsicmp( input_style, overthespotW )) + input_style_req = XIMPreeditPosition | XIMStatusNothing; + else if (!wcsicmp( input_style, rootW )) + input_style_req = XIMPreeditNothing | XIMStatusNothing; + + TRACE( "requesting %s style %#lx %s\n", debugstr_w(input_style), input_style_req, + debugstr_xim_style( input_style_req ) ); + return TRUE; } @@ -364,13 +359,12 @@ static void xim_destroy( XIM xim, XPointer user, XPointer arg ); static XIM xim_create( struct x11drv_thread_data *data ) { XIMCallback destroy = {.callback = xim_destroy, .client_data = (XPointer)data}; - Display *display = data->display; - XIMStyle ximStyleNone; - XIMStyles *ximStyles = NULL; + XIMStyle input_style_fallback = XIMPreeditNone | XIMStatusNone; + XIMStyles *styles = NULL; INT i; XIM xim; - if (!(xim = XOpenIM( display, NULL, NULL, NULL ))) + if (!(xim = XOpenIM( data->display, NULL, NULL, NULL ))) { WARN("Could not open input method.\n"); return NULL; @@ -382,50 +376,28 @@ static XIM xim_create( struct x11drv_thread_data *data ) TRACE( "xim %p, XDisplayOfIM %p, XLocaleOfIM %s\n", xim, XDisplayOfIM( xim ), debugstr_a(XLocaleOfIM( xim )) ); - XGetIMValues(xim, XNQueryInputStyle, &ximStyles, NULL); - if (ximStyles == 0) + XGetIMValues( xim, XNQueryInputStyle, &styles, NULL ); + if (!styles) { WARN( "Could not find supported input style.\n" ); XCloseIM( xim ); return NULL; } - ximStyleRoot = 0; - ximStyleNone = 0; - ximStyle = 0; - - TRACE( "input styles count %u\n", ximStyles->count_styles ); - for (i = 0; i < ximStyles->count_styles; ++i) + TRACE( "input styles count %u\n", styles->count_styles ); + for (i = 0, input_style = 0; i < styles->count_styles; ++i) { - XIMStyle style = ximStyles->supported_styles[i]; + XIMStyle style = styles->supported_styles[i]; TRACE( " %u: %#lx %s\n", i, style, debugstr_xim_style( style ) ); - if (!ximStyle && (ximStyles->supported_styles[i] == - ximStyleRequest)) - { - ximStyle = ximStyleRequest; - TRACE("Setting Style: ximStyle = ximStyleRequest\n"); - } - else if (!ximStyleRoot &&(ximStyles->supported_styles[i] == - STYLE_ROOT)) - { - ximStyleRoot = STYLE_ROOT; - TRACE("Setting Style: ximStyleRoot = STYLE_ROOT\n"); - } - else if (!ximStyleNone && (ximStyles->supported_styles[i] == - STYLE_NONE)) - { - TRACE("Setting Style: ximStyleNone = STYLE_NONE\n"); - ximStyleNone = STYLE_NONE; - } + if (style == input_style_req) input_style = style; + if (!input_style && (style & input_style_req)) input_style = style; + if (input_style_fallback > style) input_style_fallback = style; } - XFree(ximStyles); - - if (ximStyle == 0) - ximStyle = ximStyleRoot; + XFree(styles); - if (ximStyle == 0) - ximStyle = ximStyleNone; + if (!input_style) input_style = input_style_fallback; + TRACE( "selected style %#lx %s\n", input_style, debugstr_xim_style( input_style ) ); return xim; } @@ -511,7 +483,7 @@ XIC X11DRV_CreateIC( XIM xim, HWND hwnd, struct x11drv_win_data *data ) XNStatusDoneCallback, &status_done, XNStatusDrawCallback, &status_draw, NULL ); - xic = XCreateIC( xim, XNInputStyle, ximStyle, XNPreeditAttributes, preedit, XNStatusAttributes, status, + xic = XCreateIC( xim, XNInputStyle, input_style, XNPreeditAttributes, preedit, XNStatusAttributes, status, XNClientWindow, win, XNFocusWindow, win, XNDestroyCallback, &destroy, NULL ); TRACE( "created XIC %p\n", xic ); From 6194e6c804495c80a7b54e6c6e53496c113cefc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 2 Apr 2023 10:06:50 +0200 Subject: [PATCH 1828/2777] winex11: Reorder control flow in xic_preedit_draw. (cherry picked from commit 1a0ba03cd7530a1cd3568baa08aedf2f02cc419e) --- dlls/winex11.drv/xim.c | 55 ++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index e73e019d448..a60ee4b2042 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -172,47 +172,38 @@ static int xic_preedit_done( XIC xic, XPointer user, XPointer arg ) static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) { - XIMPreeditDrawCallbackStruct *P_DR = (void *)arg; + XIMPreeditDrawCallbackStruct *params = (void *)arg; HWND hwnd = (HWND)user; + XIMText *text; TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg ); - if (P_DR) + if (!params) return 0; + + if (!(text = params->text)) + X11DRV_ImmSetInternalString( params->chg_first, params->chg_length, NULL, 0 ); + else if (!text->encoding_is_wchar) { - int sel = P_DR->chg_first; - int len = P_DR->chg_length; - if (P_DR->text) + size_t text_len; + WCHAR *output; + + text_len = strlen( text->string.multi_byte ); + if ((output = malloc( text_len * sizeof(WCHAR) ))) { - if (! P_DR->text->encoding_is_wchar) - { - size_t text_len; - WCHAR *output; - - TRACE("multibyte\n"); - text_len = strlen( P_DR->text->string.multi_byte ); - if ((output = malloc( text_len * sizeof(WCHAR) ))) - { - text_len = ntdll_umbstowcs( P_DR->text->string.multi_byte, text_len, - output, text_len ); - - X11DRV_ImmSetInternalString( sel, len, output, text_len ); - free( output ); - } - } - else - { - FIXME("wchar PROBIBILY WRONG\n"); - X11DRV_ImmSetInternalString (sel, len, - (LPWSTR)P_DR->text->string.wide_char, - P_DR->text->length); - } + text_len = ntdll_umbstowcs( text->string.multi_byte, text_len, output, text_len ); + X11DRV_ImmSetInternalString( params->chg_first, params->chg_length, output, text_len ); + free( output ); } - else - X11DRV_ImmSetInternalString (sel, len, NULL, 0); - x11drv_client_call( client_ime_set_cursor_pos, P_DR->caret ); + } + else + { + FIXME( "wchar PROBIBILY WRONG\n" ); + X11DRV_ImmSetInternalString( params->chg_first, params->chg_length, + (WCHAR *)text->string.wide_char, text->length ); } - TRACE("Finished\n"); + x11drv_client_call( client_ime_set_cursor_pos, params->caret ); + return 0; } From edff6100de575cdb8e527cc5aee0f62f4486d88a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 2 Apr 2023 10:18:07 +0200 Subject: [PATCH 1829/2777] winex11: Fix XIM wchar encoding in xic_preedit_draw. (cherry picked from commit 994d79903a096dccb905795a96492d87268ef6d3) --- dlls/winex11.drv/xim.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index a60ee4b2042..219e5b18974 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -182,24 +182,30 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) if (!(text = params->text)) X11DRV_ImmSetInternalString( params->chg_first, params->chg_length, NULL, 0 ); - else if (!text->encoding_is_wchar) + else { size_t text_len; WCHAR *output; + char *str; + int len; + + if (!text->encoding_is_wchar) str = text->string.multi_byte; + else if ((len = wcstombs( NULL, text->string.wide_char, text->length )) < 0) str = NULL; + else if ((str = malloc( len + 1 ))) + { + wcstombs( str, text->string.wide_char, len ); + str[len] = 0; + } - text_len = strlen( text->string.multi_byte ); + text_len = str ? strlen( str ) : 0; if ((output = malloc( text_len * sizeof(WCHAR) ))) { - text_len = ntdll_umbstowcs( text->string.multi_byte, text_len, output, text_len ); + text_len = ntdll_umbstowcs( str, text_len, output, text_len ); X11DRV_ImmSetInternalString( params->chg_first, params->chg_length, output, text_len ); free( output ); } - } - else - { - FIXME( "wchar PROBIBILY WRONG\n" ); - X11DRV_ImmSetInternalString( params->chg_first, params->chg_length, - (WCHAR *)text->string.wide_char, text->length ); + + if (str != text->string.multi_byte) free( str ); } x11drv_client_call( client_ime_set_cursor_pos, params->caret ); From 5b100ffa387986e6ad4037369d12e230d2977eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 2 Apr 2023 10:21:22 +0200 Subject: [PATCH 1830/2777] winex11: Early return control flow in xic_preedit_caret. (cherry picked from commit d84f8dccf0b0e62bfba257db3bf2eed72f2bff0f) --- dlls/winex11.drv/xim.c | 67 +++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 219e5b18974..0251677eef9 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -215,46 +215,45 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) static int xic_preedit_caret( XIC xic, XPointer user, XPointer arg ) { - XIMPreeditCaretCallbackStruct *P_C = (void *)arg; + XIMPreeditCaretCallbackStruct *params = (void *)arg; HWND hwnd = (HWND)user; + int pos; TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg ); - if (P_C) + if (!params) return 0; + + pos = x11drv_client_call( client_ime_get_cursor_pos, 0 ); + switch (params->direction) { - int pos = x11drv_client_call( client_ime_get_cursor_pos, 0 ); - TRACE("pos: %d\n", pos); - switch(P_C->direction) - { - case XIMForwardChar: - case XIMForwardWord: - pos++; - break; - case XIMBackwardChar: - case XIMBackwardWord: - pos--; - break; - case XIMLineStart: - pos = 0; - break; - case XIMAbsolutePosition: - pos = P_C->position; - break; - case XIMDontChange: - P_C->position = pos; - return 0; - case XIMCaretUp: - case XIMCaretDown: - case XIMPreviousLine: - case XIMNextLine: - case XIMLineEnd: - FIXME("Not implemented\n"); - break; - } - x11drv_client_call( client_ime_set_cursor_pos, pos ); - P_C->position = pos; + case XIMForwardChar: + case XIMForwardWord: + pos++; + break; + case XIMBackwardChar: + case XIMBackwardWord: + pos--; + break; + case XIMLineStart: + pos = 0; + break; + case XIMAbsolutePosition: + pos = params->position; + break; + case XIMDontChange: + params->position = pos; + return 0; + case XIMCaretUp: + case XIMCaretDown: + case XIMPreviousLine: + case XIMNextLine: + case XIMLineEnd: + FIXME( "Not implemented\n" ); + break; } - TRACE("Finished\n"); + x11drv_client_call( client_ime_set_cursor_pos, pos ); + params->position = pos; + return 0; } From b70b3a0933e5e1bc97c3e4a54915cd65a7431a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 2 Apr 2023 22:54:20 +0200 Subject: [PATCH 1831/2777] winex11: Set x11drv_win_data XIC out of X11DRV_CreateIC. (cherry picked from commit 2be535a221cd324f8da172c4bdb677f6d59dae59) --- dlls/winex11.drv/window.c | 22 ---------------------- dlls/winex11.drv/x11drv.h | 3 +-- dlls/winex11.drv/xim.c | 22 +++++++++++++++++----- 3 files changed, 18 insertions(+), 29 deletions(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index f1b706b3721..05d8977bc34 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2756,28 +2756,6 @@ Window X11DRV_get_whole_window( HWND hwnd ) } -/*********************************************************************** - * X11DRV_get_ic - * - * Return the X input context associated with a window - */ -XIC X11DRV_get_ic( HWND hwnd ) -{ - struct x11drv_win_data *data = get_win_data( hwnd ); - XIM xim; - XIC ret = 0; - - if (data) - { - x11drv_thread_data()->last_xic_hwnd = hwnd; - ret = data->xic; - if (!ret && (xim = x11drv_thread_data()->xim)) ret = X11DRV_CreateIC( xim, hwnd, data ); - release_win_data( data ); - } - return ret; -} - - /*********************************************************************** * X11DRV_GetDC (X11DRV.@) */ diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 83d30143a6a..8a035f3a5c1 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -666,7 +666,6 @@ struct x11drv_win_data extern struct x11drv_win_data *get_win_data( HWND hwnd ) DECLSPEC_HIDDEN; extern void release_win_data( struct x11drv_win_data *data ) DECLSPEC_HIDDEN; extern Window X11DRV_get_whole_window( HWND hwnd ) DECLSPEC_HIDDEN; -extern XIC X11DRV_get_ic( HWND hwnd ) DECLSPEC_HIDDEN; extern Window get_dummy_parent(void) DECLSPEC_HIDDEN; extern void sync_gl_drawable( HWND hwnd, BOOL known_child ) DECLSPEC_HIDDEN; @@ -877,9 +876,9 @@ extern struct x11drv_display_device_handler desktop_handler DECLSPEC_HIDDEN; /* XIM support */ extern BOOL xim_init( const WCHAR *input_style ) DECLSPEC_HIDDEN; -extern XIC X11DRV_CreateIC( XIM xim, HWND hwnd, struct x11drv_win_data *data ) DECLSPEC_HIDDEN; extern void xim_thread_attach( struct x11drv_thread_data *data ) DECLSPEC_HIDDEN; extern void X11DRV_XIMLookupChars( const char *str, UINT count ) DECLSPEC_HIDDEN; +extern XIC X11DRV_get_ic( HWND hwnd ) DECLSPEC_HIDDEN; #define XEMBED_MAPPED (1 << 0) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 0251677eef9..b7f5f696ba5 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -448,7 +448,7 @@ static BOOL xic_destroy( XIC xic, XPointer user, XPointer arg ) return TRUE; } -XIC X11DRV_CreateIC( XIM xim, HWND hwnd, struct x11drv_win_data *data ) +static XIC xic_create( XIM xim, HWND hwnd, Window win ) { XICCallback destroy = {.callback = xic_destroy, .client_data = (XPointer)hwnd}; XICCallback preedit_caret = {.callback = xic_preedit_caret, .client_data = (XPointer)hwnd}; @@ -462,10 +462,9 @@ XIC X11DRV_CreateIC( XIM xim, HWND hwnd, struct x11drv_win_data *data ) XPoint spot = {0}; XVaNestedList preedit, status; XIC xic; - Window win = data->whole_window; XFontSet fontSet = x11drv_thread_data()->font_set; - TRACE( "xim %p, hwnd %p, data %p\n", xim, hwnd, data ); + TRACE( "xim %p, hwnd %p/%lx\n", xim, hwnd, win ); preedit = XVaCreateNestedList( 0, XNFontSet, fontSet, XNPreeditCaretCallback, &preedit_caret, @@ -483,10 +482,23 @@ XIC X11DRV_CreateIC( XIM xim, HWND hwnd, struct x11drv_win_data *data ) XNClientWindow, win, XNFocusWindow, win, XNDestroyCallback, &destroy, NULL ); TRACE( "created XIC %p\n", xic ); - data->xic = xic; - XFree( preedit ); XFree( status ); return xic; } + +XIC X11DRV_get_ic( HWND hwnd ) +{ + struct x11drv_win_data *data; + XIM xim; + XIC ret; + + if (!(data = get_win_data( hwnd ))) return 0; + x11drv_thread_data()->last_xic_hwnd = hwnd; + if (!(ret = data->xic) && (xim = x11drv_thread_data()->xim)) + ret = data->xic = xic_create( xim, hwnd, data->whole_window ); + release_win_data( data ); + + return ret; +} From 97a67c5739d118467bae46095dbd4548f5058c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 3 Apr 2023 16:24:08 +0200 Subject: [PATCH 1832/2777] imm32/tests: Test setting the same HIMC statuses twice. (cherry picked from commit 8cb2d2d54137247148fd3dcdfba18b669ae1778e) --- dlls/imm32/tests/imm32.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index c18c76a71a2..77c868cf168 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4118,6 +4118,14 @@ static void test_ImmSetConversionStatus(void) ok_eq( 0xdeadbeef, ctx->fdwConversion, UINT, "%#x" ); ok_eq( 0xfeedcafe, ctx->fdwSentence, UINT, "%#x" ); + ok_ret( 1, ImmSetConversionStatus( default_himc, 0xdeadbeef, 0xfeedcafe ) ); + ok_seq( empty_sequence ); + + ok_ret( 1, ImmGetConversionStatus( default_himc, &conversion, NULL ) ); + ok_eq( 0xdeadbeef, conversion, UINT, "%#x" ); + ok_eq( 0xdeadbeef, ctx->fdwConversion, UINT, "%#x" ); + ok_eq( 0xfeedcafe, ctx->fdwSentence, UINT, "%#x" ); + ok_seq( empty_sequence ); ok_ret( 1, ImmSetConversionStatus( default_himc, 0, 0xfeedcafe ) ); ok_seq( set_conversion_status_1_seq ); @@ -4132,6 +4140,14 @@ static void test_ImmSetConversionStatus(void) ok_ret( 1, ImmSetConversionStatus( default_himc, ~0, ~0 ) ); ok_seq( set_conversion_status_2_seq ); + ok_ret( 1, ImmGetConversionStatus( default_himc, NULL, &sentence ) ); + ok_eq( ~0, sentence, UINT, "%#x" ); + ok_eq( ~0, ctx->fdwConversion, UINT, "%#x" ); + ok_eq( ~0, ctx->fdwSentence, UINT, "%#x" ); + + ok_ret( 1, ImmSetConversionStatus( default_himc, ~0, ~0 ) ); + ok_seq( empty_sequence ); + ok_ret( 1, ImmGetConversionStatus( default_himc, &conversion, &sentence ) ); ok_eq( ~0, conversion, UINT, "%#x" ); ok_eq( ~0, sentence, UINT, "%#x" ); @@ -4245,6 +4261,13 @@ static void test_ImmSetOpenStatus(void) ok_eq( 0xdeadbeef, status, UINT, "%#x" ); ok_eq( 0xdeadbeef, ctx->fOpen, UINT, "%#x" ); + ok_ret( 1, ImmSetOpenStatus( default_himc, 0xdeadbeef ) ); + ok_seq( empty_sequence ); + + status = ImmGetOpenStatus( default_himc ); + ok_eq( 0xdeadbeef, status, UINT, "%#x" ); + ok_eq( 0xdeadbeef, ctx->fOpen, UINT, "%#x" ); + ok_seq( empty_sequence ); ok_ret( 1, ImmSetOpenStatus( default_himc, ~0 ) ); ok_seq( set_open_status_1_seq ); @@ -4253,6 +4276,13 @@ static void test_ImmSetOpenStatus(void) todo_wine ok_eq( ~0, status, UINT, "%#x" ); todo_wine ok_eq( ~0, ctx->fOpen, UINT, "%#x" ); + ok_ret( 1, ImmSetOpenStatus( default_himc, ~0 ) ); + ok_seq( empty_sequence ); + + status = ImmGetOpenStatus( default_himc ); + todo_wine ok_eq( ~0, status, UINT, "%#x" ); + todo_wine ok_eq( ~0, ctx->fOpen, UINT, "%#x" ); + /* status is cached between IME activations */ ok_ret( 1, ImmActivateLayout( old_hkl ) ); From 9a9c0da1f959b04dd34f50f01705a1be0b5e523b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 6 Apr 2023 00:47:15 +0200 Subject: [PATCH 1833/2777] imm32/tests: Test WM_IME_NOTIFY messages target window. Showing that they aren't sent to the focused window but only to the INPUTCONTEXT hWnd member. (cherry picked from commit 0522c01be32b56b1e295c7d683a4d63b0d86fc79) --- dlls/imm32/tests/imm32.c | 61 ++++++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 77c868cf168..b064e44e578 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2662,6 +2662,7 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected received->himc, received->message.msg, received->message.wparam, received->message.lparam ); return ret; case MSG_TEST_WIN: + todo_wine_if( expected->todo ) ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, received->himc, received->message.msg, received->message.wparam, received->message.lparam ); return ret; @@ -2695,6 +2696,7 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); break; case MSG_TEST_WIN: + todo_wine_if( expected->todo ) ok_(file, line)( !ret, "hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); break; @@ -2714,7 +2716,8 @@ static void ok_seq_( const char *file, int line, const struct ime_call *expected winetest_push_context( "%u%s%s", i++, !expected->func ? " (spurious)" : "", !received->func ? " (missing)" : "" ); ret = ok_call_( file, line, expected, received ); - if (ret && expected->todo && !strcmp( winetest_platform, "wine" )) + if (ret && expected->todo && expected->func && + !strcmp( winetest_platform, "wine" )) expected++; else if (ret && broken(expected->broken)) expected++; @@ -4014,6 +4017,10 @@ static void test_ImmSetConversionStatus(void) .hkl = expect_ime, .himc = default_himc, .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCONVERSIONMODE}, }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE}, + }, { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE}, @@ -4022,6 +4029,10 @@ static void test_ImmSetConversionStatus(void) .hkl = expect_ime, .himc = default_himc, .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETSENTENCEMODE}, }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETSENTENCEMODE}, + }, { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETSENTENCEMODE}, @@ -4034,10 +4045,7 @@ static void test_ImmSetConversionStatus(void) .hkl = expect_ime, .himc = default_himc, .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0xdeadbeef, .value = IMC_SETCONVERSIONMODE}, }, - { - .hkl = expect_ime, .himc = default_himc, - .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE}, - }, + {.todo = TRUE}, /* spurious calls */ {0}, }; const struct ime_call set_conversion_status_2_seq[] = @@ -4046,6 +4054,10 @@ static void test_ImmSetConversionStatus(void) .hkl = expect_ime, .himc = default_himc, .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCONVERSIONMODE}, }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE}, + }, { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCONVERSIONMODE}, @@ -4054,6 +4066,10 @@ static void test_ImmSetConversionStatus(void) .hkl = expect_ime, .himc = default_himc, .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0xfeedcafe, .value = IMC_SETSENTENCEMODE}, }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETSENTENCEMODE}, + }, { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETSENTENCEMODE}, @@ -4072,7 +4088,7 @@ static void test_ImmSetConversionStatus(void) ok_eq( old_conversion, ctx->fdwConversion, UINT, "%#x" ); ok_eq( old_sentence, ctx->fdwSentence, UINT, "%#x" ); - hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); process_messages(); @@ -4126,6 +4142,7 @@ static void test_ImmSetConversionStatus(void) ok_eq( 0xdeadbeef, ctx->fdwConversion, UINT, "%#x" ); ok_eq( 0xfeedcafe, ctx->fdwSentence, UINT, "%#x" ); + ctx->hWnd = 0; ok_seq( empty_sequence ); ok_ret( 1, ImmSetConversionStatus( default_himc, 0, 0xfeedcafe ) ); ok_seq( set_conversion_status_1_seq ); @@ -4136,6 +4153,7 @@ static void test_ImmSetConversionStatus(void) ok_eq( 0, ctx->fdwConversion, UINT, "%#x" ); ok_eq( 0xfeedcafe, ctx->fdwSentence, UINT, "%#x" ); + ctx->hWnd = hwnd; ok_seq( empty_sequence ); ok_ret( 1, ImmSetConversionStatus( default_himc, ~0, ~0 ) ); ok_seq( set_conversion_status_2_seq ); @@ -4192,6 +4210,10 @@ static void test_ImmSetOpenStatus(void) .hkl = expect_ime, .himc = default_himc, .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS}, }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS}, + }, { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS}, @@ -4205,6 +4227,20 @@ static void test_ImmSetOpenStatus(void) .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS}, .todo = TRUE, }, + {0}, + }; + const struct ime_call set_open_status_2_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS}, + .todo = TRUE, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS}, + .todo = TRUE, + }, { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS}, @@ -4223,7 +4259,7 @@ static void test_ImmSetOpenStatus(void) ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); ok_eq( old_status, ctx->fOpen, UINT, "%#x" ); - hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); process_messages(); @@ -4268,9 +4304,18 @@ static void test_ImmSetOpenStatus(void) ok_eq( 0xdeadbeef, status, UINT, "%#x" ); ok_eq( 0xdeadbeef, ctx->fOpen, UINT, "%#x" ); + ctx->hWnd = 0; + ok_ret( 1, ImmSetOpenStatus( default_himc, 0xfeedcafe ) ); + ok_seq( set_open_status_1_seq ); + + status = ImmGetOpenStatus( default_himc ); + todo_wine ok_eq( 0xfeedcafe, status, UINT, "%#x" ); + todo_wine ok_eq( 0xfeedcafe, ctx->fOpen, UINT, "%#x" ); + + ctx->hWnd = hwnd; ok_seq( empty_sequence ); ok_ret( 1, ImmSetOpenStatus( default_himc, ~0 ) ); - ok_seq( set_open_status_1_seq ); + ok_seq( set_open_status_2_seq ); status = ImmGetOpenStatus( default_himc ); todo_wine ok_eq( ~0, status, UINT, "%#x" ); From e0b84f4b41ba1af050b1da68149e4b9955cb814d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 1 Apr 2023 22:39:49 +0200 Subject: [PATCH 1834/2777] imm32/tests: Add more ImmGetCompositionString(W|A) tests. (cherry picked from commit 272677e7e0f476b235eaf9bf3534cfe3fd6905fc) --- dlls/imm32/tests/imm32.c | 333 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 331 insertions(+), 2 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index b064e44e578..fdc25fe4a3d 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -91,6 +91,12 @@ extern BOOL WINAPI ImmActivateLayout(HKL); #define check_member( val, exp, fmt, member ) \ check_member_( __FILE__, __LINE__, val, exp, fmt, member ) +#define check_member_wstr_( file, line, val, exp, member ) \ + ok_(file, line)( !wcscmp( (val).member, (exp).member ), "got " #member " %s\n", \ + debugstr_w((val).member) ) +#define check_member_wstr( val, exp, member ) \ + check_member_wstr_( __FILE__, __LINE__, val, exp, member ) + #define check_member_point_( file, line, val, exp, member ) \ ok_(file, line)( !memcmp( &(val).member, &(exp).member, sizeof(POINT) ), \ "got " #member " %s\n", wine_dbgstr_point( &(val).member ) ) @@ -103,6 +109,36 @@ extern BOOL WINAPI ImmActivateLayout(HKL); #define check_member_rect( val, exp, member ) \ check_member_rect_( __FILE__, __LINE__, val, exp, member ) +#define check_composition_string( a, b ) check_composition_string_( __LINE__, a, b ) +static void check_composition_string_( int line, COMPOSITIONSTRING *string, const COMPOSITIONSTRING *expect ) +{ + check_member_( __FILE__, line, *string, *expect, "%lu", dwSize ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwCompReadAttrLen ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwCompReadAttrOffset ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwCompReadClauseLen ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwCompReadClauseOffset ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwCompReadStrLen ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwCompReadStrOffset ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwCompAttrLen ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwCompAttrOffset ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwCompClauseLen ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwCompClauseOffset ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwCompStrLen ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwCompStrOffset ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwCursorPos ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwDeltaStart ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwResultReadClauseLen ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwResultReadClauseOffset ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwResultReadStrLen ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwResultReadStrOffset ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwResultClauseLen ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwResultClauseOffset ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwResultStrLen ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwResultStrOffset ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwPrivateSize ); + check_member_( __FILE__, line, *string, *expect, "%lu", dwPrivateOffset ); +} + #define check_candidate_list( a, b ) check_candidate_list_( __LINE__, a, b, TRUE ) static void check_candidate_list_( int line, CANDIDATELIST *list, const CANDIDATELIST *expect, BOOL unicode ) { @@ -600,7 +636,7 @@ static LRESULT WINAPI test_ime_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPAR hWnd, msg, wParam, lParam); } -static void test_ImmGetCompositionString(void) +static void test_SCS_SETSTR(void) { HIMC imc; static const WCHAR string[] = {'w','i','n','e',0x65e5,0x672c,0x8a9e}; @@ -5476,6 +5512,296 @@ static void test_ImmGetCandidateWindow(void) ime_call_count = 0; } +static void test_ImmGetCompositionString( BOOL unicode ) +{ + static COMPOSITIONSTRING expect_string_empty = {.dwSize = sizeof(COMPOSITIONSTRING)}; + static COMPOSITIONSTRING expect_stringA = + { + .dwSize = 176, + .dwCompReadAttrLen = 8, + .dwCompReadAttrOffset = 116, + .dwCompReadClauseLen = 8, + .dwCompReadClauseOffset = 108, + .dwCompReadStrLen = 8, + .dwCompReadStrOffset = 100, + .dwCompAttrLen = 4, + .dwCompAttrOffset = 136, + .dwCompClauseLen = 8, + .dwCompClauseOffset = 128, + .dwCompStrLen = 4, + .dwCompStrOffset = 124, + .dwCursorPos = 3, + .dwDeltaStart = 1, + .dwResultReadClauseLen = 8, + .dwResultReadClauseOffset = 150, + .dwResultReadStrLen = 10, + .dwResultReadStrOffset = 140, + .dwResultClauseLen = 8, + .dwResultClauseOffset = 164, + .dwResultStrLen = 6, + .dwResultStrOffset = 158, + .dwPrivateSize = 4, + .dwPrivateOffset = 172, + }; + static const COMPOSITIONSTRING expect_stringW = + { + .dwSize = 204, + .dwCompReadAttrLen = 8, + .dwCompReadAttrOffset = 124, + .dwCompReadClauseLen = 8, + .dwCompReadClauseOffset = 116, + .dwCompReadStrLen = 8, + .dwCompReadStrOffset = 100, + .dwCompAttrLen = 4, + .dwCompAttrOffset = 148, + .dwCompClauseLen = 8, + .dwCompClauseOffset = 140, + .dwCompStrLen = 4, + .dwCompStrOffset = 132, + .dwCursorPos = 3, + .dwDeltaStart = 1, + .dwResultReadClauseLen = 8, + .dwResultReadClauseOffset = 172, + .dwResultReadStrLen = 10, + .dwResultReadStrOffset = 152, + .dwResultClauseLen = 8, + .dwResultClauseOffset = 192, + .dwResultStrLen = 6, + .dwResultStrOffset = 180, + .dwPrivateSize = 4, + .dwPrivateOffset = 200, + }; + static const UINT gcs_indexes[] = + { + GCS_COMPREADSTR, + GCS_COMPREADATTR, + GCS_COMPREADCLAUSE, + GCS_COMPSTR, + GCS_COMPATTR, + GCS_COMPCLAUSE, + GCS_CURSORPOS, + GCS_DELTASTART, + GCS_RESULTREADSTR, + GCS_RESULTREADCLAUSE, + GCS_RESULTSTR, + GCS_RESULTCLAUSE, + }; + static const UINT expect_retW[ARRAY_SIZE(gcs_indexes)] = {16, 8, 8, 8, 4, 8, 3, 1, 20, 8, 12, 8}; + static const UINT expect_retA[ARRAY_SIZE(gcs_indexes)] = {8, 8, 8, 4, 4, 8, 3, 1, 10, 8, 6, 8}; + HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + COMPOSITIONSTRING *string; + char buffer[1024]; + INPUTCONTEXT *old_ctx, *ctx; + const void *str; + HIMCC old_himcc; + UINT i, len; + BYTE *dst; + HIMC himc; + + winetest_push_context( unicode ? "unicode" : "ansi" ); + + /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ + ime_info.fdwProperty = IME_PROP_END_UNLOAD; + if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE; + + if (!(hkl = ime_install())) goto cleanup; + + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + memset( buffer, 0xcd, sizeof(buffer) ); + todo_wine ok_ret( -2, ImmGetCompositionStringW( default_himc, GCS_COMPSTR | GCS_COMPATTR, buffer, sizeof(buffer) ) ); + memset( buffer, 0xcd, sizeof(buffer) ); + todo_wine ok_ret( -2, ImmGetCompositionStringA( default_himc, GCS_COMPSTR | GCS_COMPATTR, buffer, sizeof(buffer) ) ); + + for (i = 0; i < ARRAY_SIZE(gcs_indexes); ++i) + { + memset( buffer, 0xcd, sizeof(buffer) ); + ok_ret( 0, ImmGetCompositionStringW( default_himc, gcs_indexes[i], buffer, sizeof(buffer) ) ); + memset( buffer, 0xcd, sizeof(buffer) ); + ok_ret( 0, ImmGetCompositionStringA( default_himc, gcs_indexes[i], buffer, sizeof(buffer) ) ); + + memset( buffer, 0xcd, sizeof(buffer) ); + ok_ret( 0, ImmGetCompositionStringW( himc, gcs_indexes[i], buffer, sizeof(buffer) ) ); + memset( buffer, 0xcd, sizeof(buffer) ); + ok_ret( 0, ImmGetCompositionStringA( himc, gcs_indexes[i], buffer, sizeof(buffer) ) ); + } + + ctx->hCompStr = ImmReSizeIMCC( ctx->hCompStr, unicode ? expect_stringW.dwSize : expect_stringA.dwSize ); + string = ImmLockIMCC( ctx->hCompStr ); + ok( !!string, "ImmLockIMCC failed, error %lu\n", GetLastError() ); + check_composition_string( string, &expect_string_empty ); + + string->dwCursorPos = 3; + string->dwDeltaStart = 1; + + if (unicode) str = L"ReadComp"; + else str = "ReadComp"; + len = unicode ? wcslen( str ) : strlen( str ); + + string->dwCompReadStrLen = len; + string->dwCompReadStrOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompReadStrOffset; + memcpy( dst, str, len * (unicode ? sizeof(WCHAR) : 1) ); + string->dwSize += len * (unicode ? sizeof(WCHAR) : 1); + + string->dwCompReadClauseLen = 2 * sizeof(DWORD); + string->dwCompReadClauseOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompReadClauseOffset; + *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0; + *(DWORD *)(dst + 1 * sizeof(DWORD)) = len; + string->dwSize += 2 * sizeof(DWORD); + + string->dwCompReadAttrLen = len; + string->dwCompReadAttrOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompReadAttrOffset; + memset( dst, ATTR_INPUT, len ); + string->dwSize += len; + + if (unicode) str = L"Comp"; + else str = "Comp"; + len = unicode ? wcslen( str ) : strlen( str ); + + string->dwCompStrLen = len; + string->dwCompStrOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompStrOffset; + memcpy( dst, str, len * (unicode ? sizeof(WCHAR) : 1) ); + string->dwSize += len * (unicode ? sizeof(WCHAR) : 1); + + string->dwCompClauseLen = 2 * sizeof(DWORD); + string->dwCompClauseOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompClauseOffset; + *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0; + *(DWORD *)(dst + 1 * sizeof(DWORD)) = len; + string->dwSize += 2 * sizeof(DWORD); + + string->dwCompAttrLen = len; + string->dwCompAttrOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompAttrOffset; + memset( dst, ATTR_INPUT, len ); + string->dwSize += len; + + if (unicode) str = L"ReadResult"; + else str = "ReadResult"; + len = unicode ? wcslen( str ) : strlen( str ); + + string->dwResultReadStrLen = len; + string->dwResultReadStrOffset = string->dwSize; + dst = (BYTE *)string + string->dwResultReadStrOffset; + memcpy( dst, str, len * (unicode ? sizeof(WCHAR) : 1) ); + string->dwSize += len * (unicode ? sizeof(WCHAR) : 1); + + string->dwResultReadClauseLen = 2 * sizeof(DWORD); + string->dwResultReadClauseOffset = string->dwSize; + dst = (BYTE *)string + string->dwResultReadClauseOffset; + *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0; + *(DWORD *)(dst + 1 * sizeof(DWORD)) = len; + string->dwSize += 2 * sizeof(DWORD); + + if (unicode) str = L"Result"; + else str = "Result"; + len = unicode ? wcslen( str ) : strlen( str ); + + string->dwResultStrLen = len; + string->dwResultStrOffset = string->dwSize; + dst = (BYTE *)string + string->dwResultStrOffset; + memcpy( dst, str, len * (unicode ? sizeof(WCHAR) : 1) ); + string->dwSize += len * (unicode ? sizeof(WCHAR) : 1); + + string->dwResultClauseLen = 2 * sizeof(DWORD); + string->dwResultClauseOffset = string->dwSize; + dst = (BYTE *)string + string->dwResultClauseOffset; + *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0; + *(DWORD *)(dst + 1 * sizeof(DWORD)) = len; + string->dwSize += 2 * sizeof(DWORD); + + string->dwPrivateSize = 4; + string->dwPrivateOffset = string->dwSize; + dst = (BYTE *)string + string->dwPrivateOffset; + memset( dst, 0xa5, string->dwPrivateSize ); + string->dwSize += 4; + + check_composition_string( string, unicode ? &expect_stringW : &expect_stringA ); + ok_ret( 0, ImmUnlockIMCC( ctx->hCompStr ) ); + old_himcc = ctx->hCompStr; + + for (i = 0; i < ARRAY_SIZE(gcs_indexes); ++i) + { + UINT_PTR expect; + + winetest_push_context( "%u", i ); + + memset( buffer, 0xcd, sizeof(buffer) ); + expect = expect_retW[i]; + ok_ret( expect, ImmGetCompositionStringW( himc, gcs_indexes[i], buffer, sizeof(buffer) ) ); + memset( buffer + expect, 0, 4 ); + + if (i == 0) ok_wcs( L"ReadComp", (WCHAR *)buffer ); + else if (i == 3) ok_wcs( L"Comp", (WCHAR *)buffer ); + else if (i == 8) ok_wcs( L"ReadResult", (WCHAR *)buffer ); + else if (i == 10) ok_wcs( L"Result", (WCHAR *)buffer ); + else if (i != 6 && i != 7) ok_wcs( L"", (WCHAR *)buffer ); + + memset( buffer, 0xcd, sizeof(buffer) ); + expect = expect_retA[i]; + ok_ret( expect, ImmGetCompositionStringA( himc, gcs_indexes[i], buffer, sizeof(buffer) ) ); + memset( buffer + expect, 0, 4 ); + + if (i == 0) ok_str( "ReadComp", (char *)buffer ); + else if (i == 3) ok_str( "Comp", (char *)buffer ); + else if (i == 8) ok_str( "ReadResult", (char *)buffer ); + else if (i == 10) ok_str( "Result", (char *)buffer ); + else if (i != 6 && i != 7) ok_str( "", (char *)buffer ); + + winetest_pop_context(); + } + ok_seq( empty_sequence ); + + old_ctx = ctx; + ok_ret( 1, ImmUnlockIMC( himc ) ); + + /* composition strings are kept between IME selections */ + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ctx = ImmLockIMC( himc ); + ok_eq( old_ctx, ctx, INPUTCONTEXT *, "%p" ); + ok_eq( old_himcc, ctx->hCompStr, HIMCC, "%p" ); + string = ImmLockIMCC( ctx->hCompStr ); + ok_ne( NULL, string, COMPOSITIONSTRING *, "%p" ); + *string = expect_string_empty; + ok_ret( 0, ImmUnlockIMCC( ctx->hCompStr ) ); + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_eq( old_himcc, ctx->hCompStr, HIMCC, "%p" ); + check_composition_string( string, &expect_string_empty ); + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_eq( old_himcc, ctx->hCompStr, HIMCC, "%p" ); + check_composition_string( string, &expect_string_empty ); + + ok_ret( 1, ImmUnlockIMC( himc ) ); + ok_ret( 1, ImmDestroyContext( himc ) ); + + ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + + ime_cleanup( hkl, TRUE ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + +cleanup: + winetest_pop_context(); +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); @@ -5528,10 +5854,13 @@ START_TEST(imm32) test_ImmGetCandidateListCount( FALSE ); test_ImmGetCandidateWindow(); + test_ImmGetCompositionString( TRUE ); + test_ImmGetCompositionString( FALSE ); + if (init()) { test_ImmNotifyIME(); - test_ImmGetCompositionString(); + test_SCS_SETSTR(); test_ImmSetCompositionString(); test_ImmIME(); test_ImmAssociateContextEx(); From de2eef4b153cd11a178b5365e0c04628efd6293e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 6 Apr 2023 13:28:34 +0200 Subject: [PATCH 1835/2777] imm32/tests: Add more ImmSetCompositionString tests. (cherry picked from commit 82971f23483e58e28e7ff3961d5348161b919321) --- dlls/imm32/tests/imm32.c | 176 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 167 insertions(+), 9 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index fdc25fe4a3d..82809f37f8e 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -778,12 +778,6 @@ static void test_SCS_SETSTR(void) skip("WM_IME_COMPOSITION(GCS_RESULTSTR) isn't tested\n"); msg_spy_flush_msgs(); } -} - -static void test_ImmSetCompositionString(void) -{ - HIMC imc; - BOOL ret; SetLastError(0xdeadbeef); imc = ImmGetContext(hwnd); @@ -2569,6 +2563,8 @@ DEFINE_EXPECT( ImeEnumRegisterWord ); DEFINE_EXPECT( ImeRegisterWord ); DEFINE_EXPECT( ImeGetRegisterWordStyle ); DEFINE_EXPECT( ImeUnregisterWord ); +static BOOL todo_ImeSetCompositionString; +DEFINE_EXPECT( ImeSetCompositionString ); static BOOL todo_IME_DLL_PROCESS_ATTACH; DEFINE_EXPECT( IME_DLL_PROCESS_ATTACH ); static BOOL todo_IME_DLL_PROCESS_DETACH; @@ -3071,8 +3067,85 @@ static BOOL WINAPI ime_ImeSetCompositionString( HIMC himc, DWORD index, const vo { ime_trace( "himc %p, index %lu, comp %p, comp_len %lu, read %p, read_len %lu\n", himc, index, comp, comp_len, read, read_len ); - ok( 0, "unexpected call\n" ); - return FALSE; + CHECK_EXPECT( ImeSetCompositionString ); + + ok_eq( expect_ime, GetKeyboardLayout( 0 ), HKL, "%p" ); + ok_ne( default_himc, himc, HIMC, "%p" ); + + if (ime_info.fdwProperty & IME_PROP_UNICODE) + { + switch (index) + { + case SCS_SETSTR: + todo_wine_if( todo_ImeSetCompositionString ) + ok_eq( 22, comp_len, UINT, "%#x" ); + ok_wcs( L"CompString", comp ); + break; + case SCS_CHANGECLAUSE: + { + const UINT *clause = comp; + ok_eq( 8, comp_len, UINT, "%#x" ); + ok_eq( 0, clause[0], UINT, "%#x" ); + todo_wine_if( todo_ImeSetCompositionString ) + ok_eq( 1, clause[1], UINT, "%#x"); + break; + } + case SCS_CHANGEATTR: + { + const BYTE *attr = comp; + todo_wine_if( todo_ImeSetCompositionString && comp_len != 4 ) + ok_eq( 4, comp_len, UINT, "%#x" ); + todo_wine_if( todo_ImeSetCompositionString && attr[0] != 0xcd ) + ok_eq( 0xcd, attr[0], UINT, "%#x" ); + todo_wine_if( todo_ImeSetCompositionString ) + ok_eq( 0xcd, attr[1], UINT, "%#x" ); + break; + } + default: + ok( 0, "unexpected index %#lx\n", index ); + break; + } + } + else + { + switch (index) + { + case SCS_SETSTR: + todo_wine_if( todo_ImeSetCompositionString ) + ok_eq( 11, comp_len, UINT, "%#x" ); + ok_str( "CompString", comp ); + break; + case SCS_CHANGECLAUSE: + { + const UINT *clause = comp; + ok_eq( 8, comp_len, UINT, "%#x" ); + todo_wine_if( todo_ImeSetCompositionString ) + ok_eq( 0, clause[0], UINT, "%#x" ); + todo_wine_if( todo_ImeSetCompositionString ) + ok_eq( 1, clause[1], UINT, "%#x"); + break; + } + case SCS_CHANGEATTR: + { + const BYTE *attr = comp; + todo_wine_if( todo_ImeSetCompositionString && comp_len != 4 ) + ok_eq( 4, comp_len, UINT, "%#x" ); + todo_wine_if( todo_ImeSetCompositionString ) + ok_eq( 0xcd, attr[0], UINT, "%#x" ); + todo_wine_if( todo_ImeSetCompositionString ) + ok_eq( 0xcd, attr[1], UINT, "%#x" ); + break; + } + default: + ok( 0, "unexpected index %#lx\n", index ); + break; + } + } + + ok_eq( NULL, read, const void *, "%p" ); + ok_eq( 0, read_len, UINT, "%#x" ); + + return TRUE; } static UINT WINAPI ime_ImeToAsciiEx( UINT vkey, UINT scan_code, BYTE *key_state, TRANSMSGLIST *msgs, UINT state, HIMC himc ) @@ -5586,6 +5659,12 @@ static void test_ImmGetCompositionString( BOOL unicode ) GCS_RESULTSTR, GCS_RESULTCLAUSE, }; + static const UINT scs_indexes[] = + { + SCS_SETSTR, + SCS_CHANGEATTR, + SCS_CHANGECLAUSE, + }; static const UINT expect_retW[ARRAY_SIZE(gcs_indexes)] = {16, 8, 8, 8, 4, 8, 3, 1, 20, 8, 12, 8}; static const UINT expect_retA[ARRAY_SIZE(gcs_indexes)] = {8, 8, 8, 4, 4, 8, 3, 1, 10, 8, 6, 8}; HKL hkl, old_hkl = GetKeyboardLayout( 0 ); @@ -5598,6 +5677,8 @@ static void test_ImmGetCompositionString( BOOL unicode ) BYTE *dst; HIMC himc; + SET_ENABLE( ImeSetCompositionString, TRUE ); + winetest_push_context( unicode ? "unicode" : "ansi" ); /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ @@ -5766,6 +5847,83 @@ static void test_ImmGetCompositionString( BOOL unicode ) winetest_pop_context(); } + + for (i = 0; i < ARRAY_SIZE(gcs_indexes); ++i) + { + winetest_push_context( "%u", i ); + ok_ret( 0, ImmSetCompositionStringW( himc, gcs_indexes[i], buffer, sizeof(buffer), NULL, 0 ) ); + ok_ret( 0, ImmSetCompositionStringA( himc, gcs_indexes[i], buffer, sizeof(buffer), NULL, 0 ) ); + winetest_pop_context(); + } + ok_ret( 0, ImmSetCompositionStringW( himc, SCS_SETSTR | SCS_CHANGEATTR, buffer, sizeof(buffer), NULL, 0 ) ); + ok_ret( 0, ImmSetCompositionStringA( himc, SCS_SETSTR | SCS_CHANGEATTR, buffer, sizeof(buffer), NULL, 0 ) ); + ok_ret( 0, ImmSetCompositionStringW( himc, SCS_CHANGECLAUSE | SCS_CHANGEATTR, buffer, sizeof(buffer), NULL, 0 ) ); + ok_ret( 0, ImmSetCompositionStringA( himc, SCS_CHANGECLAUSE | SCS_CHANGEATTR, buffer, sizeof(buffer), NULL, 0 ) ); + + for (i = 0; i < ARRAY_SIZE(scs_indexes); ++i) + { + winetest_push_context( "%u", i ); + + if (scs_indexes[i] == SCS_CHANGECLAUSE) + { + memset( buffer, 0, sizeof(buffer) ); + *((DWORD *)buffer + 1) = 1; + len = 2 * sizeof(DWORD); + } + else if (scs_indexes[i] == SCS_CHANGEATTR) + { + memset( buffer, 0xcd, sizeof(buffer) ); + len = expect_stringW.dwCompAttrLen; + } + else if (scs_indexes[i] == SCS_SETSTR) + { + wcscpy( (WCHAR *)buffer, L"CompString" ); + len = 11 * sizeof(WCHAR); + } + + todo_ImeSetCompositionString = !unicode; + SET_EXPECT( ImeSetCompositionString ); + ok_ret( 1, ImmSetCompositionStringW( himc, scs_indexes[i], buffer, len, NULL, 0 ) ); + CHECK_CALLED( ImeSetCompositionString ); + todo_ImeSetCompositionString = FALSE; + ok_seq( empty_sequence ); + + string = ImmLockIMCC( ctx->hCompStr ); + ok_ne( NULL, string, COMPOSITIONSTRING *, "%p" ); + check_composition_string( string, unicode ? &expect_stringW : &expect_stringA ); + ok_ret( 0, ImmUnlockIMCC( ctx->hCompStr ) ); + + if (scs_indexes[i] == SCS_CHANGECLAUSE) + { + memset( buffer, 0, sizeof(buffer) ); + *((DWORD *)buffer + 1) = 1; + len = 2 * sizeof(DWORD); + } + else if (scs_indexes[i] == SCS_CHANGEATTR) + { + memset( buffer, 0xcd, sizeof(buffer) ); + len = expect_stringA.dwCompAttrLen; + } + else if (scs_indexes[i] == SCS_SETSTR) + { + strcpy( buffer, "CompString" ); + len = 11; + } + + todo_ImeSetCompositionString = unicode; + SET_EXPECT( ImeSetCompositionString ); + ok_ret( 1, ImmSetCompositionStringA( himc, scs_indexes[i], buffer, len, NULL, 0 ) ); + CHECK_CALLED( ImeSetCompositionString ); + todo_ImeSetCompositionString = FALSE; + ok_seq( empty_sequence ); + + string = ImmLockIMCC( ctx->hCompStr ); + ok_ne( NULL, string, COMPOSITIONSTRING *, "%p" ); + check_composition_string( string, unicode ? &expect_stringW : &expect_stringA ); + ok_ret( 0, ImmUnlockIMCC( ctx->hCompStr ) ); + + winetest_pop_context(); + } ok_seq( empty_sequence ); old_ctx = ctx; @@ -5800,6 +5958,7 @@ static void test_ImmGetCompositionString( BOOL unicode ) cleanup: winetest_pop_context(); + SET_ENABLE( ImeSetCompositionString, FALSE ); } START_TEST(imm32) @@ -5861,7 +6020,6 @@ START_TEST(imm32) { test_ImmNotifyIME(); test_SCS_SETSTR(); - test_ImmSetCompositionString(); test_ImmIME(); test_ImmAssociateContextEx(); test_NtUserAssociateInputContext(); From ff8c0c4e85d81571dfade9eba8cdacfdc490b884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 1 Apr 2023 21:25:36 +0200 Subject: [PATCH 1836/2777] winex11: Cleanup spaces in IME UI window proc. (cherry picked from commit a5117ed5cd93b54645285c89694e6069102405aa) --- dlls/winex11.drv/ime.c | 267 ++++++++++++++++++----------------------- 1 file changed, 115 insertions(+), 152 deletions(-) diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index a499c8d9dd6..931289b751b 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -998,26 +998,25 @@ NTSTATUS WINAPI x11drv_ime_set_result( void *params, ULONG len ) /***** * Internal functions to help with IME window management */ -static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) +static void PaintDefaultIMEWnd( HIMC hIMC, HWND hwnd ) { PAINTSTRUCT ps; RECT rect; HDC hdc; HMONITOR monitor; MONITORINFO mon_info; - INT offX=0, offY=0; + INT offX = 0, offY = 0; LPINPUTCONTEXT lpIMC; WCHAR *str; UINT len; - lpIMC = ImmLockIMC(hIMC); - if (lpIMC == NULL) - return; + lpIMC = ImmLockIMC( hIMC ); + if (lpIMC == NULL) return; - hdc = BeginPaint(hwnd,&ps); + hdc = BeginPaint( hwnd, &ps ); - GetClientRect(hwnd,&rect); - FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1)); + GetClientRect( hwnd, &rect ); + FillRect( hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1) ); if ((str = input_context_get_comp_str( lpIMC, FALSE, &len ))) { @@ -1028,7 +1027,7 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) GetTextExtentPoint32W( hdc, str, len, &size ); pt.x = size.cx; pt.y = size.cy; - LPtoDP(hdc,&pt,1); + LPtoDP( hdc, &pt, 1 ); /* * How this works based on tests on windows: @@ -1045,12 +1044,12 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) if (lpIMC->cfCompForm.dwStyle != CFS_DEFAULT) { POINT cpt = lpIMC->cfCompForm.ptCurrentPos; - ClientToScreen(lpIMC->hWnd,&cpt); + ClientToScreen( lpIMC->hWnd, &cpt ); rect.left = cpt.x; rect.top = cpt.y; rect.right = rect.left + pt.x; rect.bottom = rect.top + pt.y; - monitor = MonitorFromPoint(cpt, MONITOR_DEFAULTTOPRIMARY); + monitor = MonitorFromPoint( cpt, MONITOR_DEFAULTTOPRIMARY ); } else /* CFS_DEFAULT */ { @@ -1058,20 +1057,20 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) HWND target = lpIMC->hWnd; if (!target) target = GetFocus(); - GetWindowRect(target,&rect); + GetWindowRect( target, &rect ); rect.top = rect.bottom; rect.right = rect.left + pt.x + 20; rect.bottom = rect.top + pt.y + 20; - offX=offY=10; - monitor = MonitorFromWindow(target, MONITOR_DEFAULTTOPRIMARY); + offX = offY = 10; + monitor = MonitorFromWindow( target, MONITOR_DEFAULTTOPRIMARY ); } if (lpIMC->cfCompForm.dwStyle == CFS_RECT) { RECT client; - client =lpIMC->cfCompForm.rcArea; + client = lpIMC->cfCompForm.rcArea; MapWindowPoints( lpIMC->hWnd, 0, (POINT *)&client, 2 ); - IntersectRect(&rect,&rect,&client); + IntersectRect( &rect, &rect, &client ); /* TODO: Wrap the input if needed */ } @@ -1079,7 +1078,7 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) { /* make sure we are on the desktop */ mon_info.cbSize = sizeof(mon_info); - GetMonitorInfoW(monitor, &mon_info); + GetMonitorInfoW( monitor, &mon_info ); if (rect.bottom > mon_info.rcWork.bottom) { @@ -1100,118 +1099,85 @@ static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) } } - SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE); - + SetWindowPos( hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, SWP_NOACTIVATE ); TextOutW( hdc, offX, offY, str, len ); if (font) SelectObject( hdc, font ); free( str ); } - EndPaint(hwnd,&ps); - ImmUnlockIMC(hIMC); + EndPaint( hwnd, &ps ); + ImmUnlockIMC( hIMC ); } -static void UpdateDefaultIMEWindow(INPUTCONTEXT *lpIMC, HWND hwnd) +static void UpdateDefaultIMEWindow( INPUTCONTEXT *lpIMC, HWND hwnd ) { LPCOMPOSITIONSTRING compstr; - if (lpIMC->hCompStr) - compstr = ImmLockIMCC(lpIMC->hCompStr); - else - compstr = NULL; + if (lpIMC->hCompStr) compstr = ImmLockIMCC( lpIMC->hCompStr ); + else compstr = NULL; if (compstr == NULL || compstr->dwCompStrLen == 0) - ShowWindow(hwnd,SW_HIDE); + ShowWindow( hwnd, SW_HIDE ); else { - ShowWindow(hwnd,SW_SHOWNOACTIVATE); - RedrawWindow(hwnd, NULL, NULL, RDW_ERASENOW | RDW_INVALIDATE); + ShowWindow( hwnd, SW_SHOWNOACTIVATE ); + RedrawWindow( hwnd, NULL, NULL, RDW_ERASENOW | RDW_INVALIDATE ); } - if (compstr != NULL) - ImmUnlockIMCC(lpIMC->hCompStr); + if (compstr != NULL) ImmUnlockIMCC( lpIMC->hCompStr ); lpIMC->hWnd = GetFocus(); } -static void DefaultIMEComposition(HIMC hIMC, HWND hwnd, LPARAM lParam) +static void DefaultIMEComposition( HIMC hIMC, HWND hwnd, LPARAM lParam ) { INPUTCONTEXT *ctx; - TRACE("IME message WM_IME_COMPOSITION 0x%Ix\n", lParam); + TRACE( "IME message WM_IME_COMPOSITION 0x%Ix\n", lParam ); if (lParam & GCS_RESULTSTR) return; if (!(ctx = ImmLockIMC( hIMC ))) return; UpdateDefaultIMEWindow( ctx, hwnd ); - ImmUnlockIMC(hIMC); + ImmUnlockIMC( hIMC ); } -static void DefaultIMEStartComposition(HIMC hIMC, HWND hwnd ) +static void DefaultIMEStartComposition( HIMC hIMC, HWND hwnd ) { INPUTCONTEXT *ctx; - TRACE("IME message WM_IME_STARTCOMPOSITION\n"); + TRACE( "IME message WM_IME_STARTCOMPOSITION\n" ); if (!(ctx = ImmLockIMC( hIMC ))) return; UpdateDefaultIMEWindow( ctx, hwnd ); - ImmUnlockIMC(hIMC); + ImmUnlockIMC( hIMC ); } -static LRESULT ImeHandleNotify(HIMC hIMC, HWND hwnd, UINT msg, WPARAM wParam, - LPARAM lParam) +static LRESULT ImeHandleNotify( HIMC hIMC, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch (wParam) { - case IMN_OPENSTATUSWINDOW: - FIXME("WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n"); - break; - case IMN_CLOSESTATUSWINDOW: - FIXME("WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n"); - break; - case IMN_OPENCANDIDATE: - FIXME("WM_IME_NOTIFY:IMN_OPENCANDIDATE\n"); - break; - case IMN_CHANGECANDIDATE: - FIXME("WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n"); - break; - case IMN_CLOSECANDIDATE: - FIXME("WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n"); - break; - case IMN_SETCONVERSIONMODE: - FIXME("WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n"); - break; - case IMN_SETSENTENCEMODE: - FIXME("WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n"); - break; - case IMN_SETOPENSTATUS: - TRACE("WM_IME_NOTIFY:IMN_SETOPENSTATUS\n"); - break; - case IMN_SETCANDIDATEPOS: - FIXME("WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n"); - break; - case IMN_SETCOMPOSITIONFONT: - FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n"); - break; - case IMN_SETCOMPOSITIONWINDOW: - FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n"); - break; - case IMN_GUIDELINE: - FIXME("WM_IME_NOTIFY:IMN_GUIDELINE\n"); - break; - case IMN_SETSTATUSWINDOWPOS: - FIXME("WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n"); - break; - default: - FIXME("WM_IME_NOTIFY:\n",wParam); - break; + case IMN_OPENSTATUSWINDOW: FIXME( "WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n" ); break; + case IMN_CLOSESTATUSWINDOW: FIXME( "WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n" ); break; + case IMN_OPENCANDIDATE: FIXME( "WM_IME_NOTIFY:IMN_OPENCANDIDATE\n" ); break; + case IMN_CHANGECANDIDATE: FIXME( "WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n" ); break; + case IMN_CLOSECANDIDATE: FIXME( "WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n" ); break; + case IMN_SETCONVERSIONMODE: FIXME( "WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n" ); break; + case IMN_SETSENTENCEMODE: FIXME( "WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n" ); break; + case IMN_SETOPENSTATUS: TRACE( "WM_IME_NOTIFY:IMN_SETOPENSTATUS\n" ); break; + case IMN_SETCANDIDATEPOS: FIXME( "WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n" ); break; + case IMN_SETCOMPOSITIONFONT: FIXME( "WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n" ); break; + case IMN_SETCOMPOSITIONWINDOW: FIXME( "WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n" ); break; + case IMN_GUIDELINE: FIXME( "WM_IME_NOTIFY:IMN_GUIDELINE\n" ); break; + case IMN_SETSTATUSWINDOWPOS: FIXME( "WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n" ); break; + default: FIXME( "WM_IME_NOTIFY:\n", wParam ); break; } return 0; } -static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, - LPARAM lParam) +static LRESULT WINAPI IME_WindowProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { LRESULT rc = 0; - HIMC hIMC; + HIMC hIMC; - TRACE("Incoming Message 0x%x (0x%08Ix, 0x%08Ix)\n", msg, wParam, lParam); + TRACE( "Incoming Message 0x%x (0x%08Ix, 0x%08Ix)\n", msg, wParam, lParam ); /* * Each UI window contains the current Input Context. @@ -1221,12 +1187,13 @@ static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, * messages. */ - hIMC = (HIMC)GetWindowLongPtrW(hwnd,IMMGWL_IMC); + hIMC = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ); /* if we have no hIMC there are many messages we cannot process */ if (hIMC == NULL) { - switch (msg) { + switch (msg) + { case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION: case WM_IME_COMPOSITION: @@ -1234,104 +1201,100 @@ static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, case WM_IME_CONTROL: case WM_IME_COMPOSITIONFULL: case WM_IME_SELECT: - case WM_IME_CHAR: - return 0L; - default: - break; + case WM_IME_CHAR: return 0L; + default: break; } } - switch(msg) + switch (msg) { - case WM_CREATE: - { - LPIMEPRIVATE myPrivate; - LPINPUTCONTEXT lpIMC; - - SetWindowTextA(hwnd,"Wine Ime Active"); + case WM_CREATE: + { + LPIMEPRIVATE myPrivate; + LPINPUTCONTEXT lpIMC; - lpIMC = ImmLockIMC(hIMC); - if (lpIMC) - { - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - myPrivate->hwndDefault = hwnd; - ImmUnlockIMCC(lpIMC->hPrivate); - } - ImmUnlockIMC(hIMC); + SetWindowTextA( hwnd, "Wine Ime Active" ); - return TRUE; + lpIMC = ImmLockIMC( hIMC ); + if (lpIMC) + { + myPrivate = ImmLockIMCC( lpIMC->hPrivate ); + myPrivate->hwndDefault = hwnd; + ImmUnlockIMCC( lpIMC->hPrivate ); } - case WM_PAINT: - PaintDefaultIMEWnd(hIMC, hwnd); - return FALSE; - - case WM_NCCREATE: - return TRUE; + ImmUnlockIMC( hIMC ); - case WM_SETFOCUS: - if (wParam) - SetFocus((HWND)wParam); - else - FIXME("Received focus, should never have focus\n"); - break; - case WM_IME_COMPOSITION: - DefaultIMEComposition(hIMC, hwnd, lParam); - break; - case WM_IME_STARTCOMPOSITION: - DefaultIMEStartComposition(hIMC, hwnd); - break; - case WM_IME_ENDCOMPOSITION: - TRACE("IME message %s, 0x%Ix, 0x%Ix\n", - "WM_IME_ENDCOMPOSITION", wParam, lParam); - ShowWindow(hwnd,SW_HIDE); - break; - case WM_IME_SELECT: - TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_IME_SELECT", wParam, lParam); - break; - case WM_IME_CONTROL: - TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_IME_CONTROL", wParam, lParam); - rc = 1; - break; - case WM_IME_NOTIFY: - rc = ImeHandleNotify(hIMC,hwnd,msg,wParam,lParam); - break; - default: - TRACE("Non-standard message 0x%x\n",msg); + return TRUE; + } + case WM_PAINT: + PaintDefaultIMEWnd( hIMC, hwnd ); + return FALSE; + case WM_NCCREATE: + return TRUE; + case WM_SETFOCUS: + if (wParam) SetFocus( (HWND)wParam ); + else FIXME( "Received focus, should never have focus\n" ); + break; + + case WM_IME_COMPOSITION: + DefaultIMEComposition( hIMC, hwnd, lParam ); + break; + case WM_IME_STARTCOMPOSITION: + DefaultIMEStartComposition( hIMC, hwnd ); + break; + case WM_IME_ENDCOMPOSITION: + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_ENDCOMPOSITION", wParam, lParam ); + ShowWindow( hwnd, SW_HIDE ); + break; + case WM_IME_SELECT: + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_SELECT", wParam, lParam ); + break; + case WM_IME_CONTROL: + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_CONTROL", wParam, lParam ); + rc = 1; + break; + case WM_IME_NOTIFY: + rc = ImeHandleNotify( hIMC, hwnd, msg, wParam, lParam ); + break; + default: + TRACE( "Non-standard message 0x%x\n", msg ); } + /* check the MSIME messages */ if (msg == WM_MSIME_SERVICE) { - TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_SERVICE", wParam, lParam); - rc = FALSE; + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_SERVICE", wParam, lParam ); + rc = FALSE; } else if (msg == WM_MSIME_RECONVERTOPTIONS) { - TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_RECONVERTOPTIONS", wParam, lParam); + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERTOPTIONS", wParam, lParam ); } else if (msg == WM_MSIME_MOUSE) { - TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_MOUSE", wParam, lParam); + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_MOUSE", wParam, lParam ); } else if (msg == WM_MSIME_RECONVERTREQUEST) { - TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_RECONVERTREQUEST", wParam, lParam); + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERTREQUEST", wParam, lParam ); } else if (msg == WM_MSIME_RECONVERT) { - TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_RECONVERT", wParam, lParam); + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERT", wParam, lParam ); } else if (msg == WM_MSIME_QUERYPOSITION) { - TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_QUERYPOSITION", wParam, lParam); + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_QUERYPOSITION", wParam, lParam ); } else if (msg == WM_MSIME_DOCUMENTFEED) { - TRACE("IME message %s, 0x%Ix, 0x%Ix\n","WM_MSIME_DOCUMENTFEED", wParam, lParam); + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_DOCUMENTFEED", wParam, lParam ); } + /* DefWndProc if not an IME message */ if (!rc && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) || - (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP))) - rc = DefWindowProcW(hwnd,msg,wParam,lParam); + (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP))) + rc = DefWindowProcW( hwnd, msg, wParam, lParam ); return rc; } From 27719b1e42c2ea939a7ef316fa66410036576e1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 1 Apr 2023 21:59:00 +0200 Subject: [PATCH 1837/2777] winex11: Move IME UI proc to default IME implementation. (cherry picked from commit bc1b15211d4a68b9dfebd870ad2fc4ffb8be8f78) --- dlls/imm32/ime.c | 351 ++++++++++++++++++++++++-- dlls/imm32/imm.c | 71 +++--- dlls/imm32/imm_private.h | 46 ++++ dlls/winemac.drv/ime.c | 10 - dlls/winex11.drv/ime.c | 393 ------------------------------ dlls/winex11.drv/winex11.drv.spec | 2 - include/ntuser.h | 10 + 7 files changed, 422 insertions(+), 461 deletions(-) create mode 100644 dlls/imm32/imm_private.h diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index c05ca6d0255..f48a0a861d1 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -19,29 +19,352 @@ #include #include -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "imm.h" -#include "immdev.h" - -#include "wine/debug.h" +#include "imm_private.h" WINE_DEFAULT_DEBUG_CHANNEL(imm); +static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT *length ) +{ + COMPOSITIONSTRING *string; + WCHAR *text = NULL; + UINT len, off; + + if (!(string = ImmLockIMCC( ctx->hCompStr ))) return NULL; + len = result ? string->dwResultStrLen : string->dwCompStrLen; + off = result ? string->dwResultStrOffset : string->dwCompStrOffset; + + if (len && off && (text = malloc( (len + 1) * sizeof(WCHAR) ))) + { + memcpy( text, (BYTE *)string + off, len * sizeof(WCHAR) ); + text[len] = 0; + *length = len; + } + + ImmUnlockIMCC( ctx->hCompStr ); + return text; +} + +static HFONT input_context_select_ui_font( INPUTCONTEXT *ctx, HDC hdc ) +{ + struct ime_private *priv; + HFONT font = NULL; + if (!(priv = ImmLockIMCC( ctx->hPrivate ))) return NULL; + if (priv->textfont) font = SelectObject( hdc, priv->textfont ); + ImmUnlockIMCC( ctx->hPrivate ); + return font; +} + +static void ime_ui_paint( HIMC himc, HWND hwnd ) +{ + PAINTSTRUCT ps; + RECT rect; + HDC hdc; + HMONITOR monitor; + MONITORINFO mon_info; + INPUTCONTEXT *ctx; + POINT offset; + WCHAR *str; + UINT len; + + if (!(ctx = ImmLockIMC( himc ))) return; + + hdc = BeginPaint( hwnd, &ps ); + + GetClientRect( hwnd, &rect ); + FillRect( hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1) ); + + if ((str = input_context_get_comp_str( ctx, FALSE, &len ))) + { + HFONT font = input_context_select_ui_font( ctx, hdc ); + SIZE size; + POINT pt; + + GetTextExtentPoint32W( hdc, str, len, &size ); + pt.x = size.cx; + pt.y = size.cy; + LPtoDP( hdc, &pt, 1 ); + + /* + * How this works based on tests on windows: + * CFS_POINT: then we start our window at the point and grow it as large + * as it needs to be for the string. + * CFS_RECT: we still use the ptCurrentPos as a starting point and our + * window is only as large as we need for the string, but we do not + * grow such that our window exceeds the given rect. Wrapping if + * needed and possible. If our ptCurrentPos is outside of our rect + * then no window is displayed. + * CFS_FORCE_POSITION: appears to behave just like CFS_POINT + * maybe because the default MSIME does not do any IME adjusting. + */ + if (ctx->cfCompForm.dwStyle != CFS_DEFAULT) + { + POINT cpt = ctx->cfCompForm.ptCurrentPos; + ClientToScreen( ctx->hWnd, &cpt ); + rect.left = cpt.x; + rect.top = cpt.y; + rect.right = rect.left + pt.x; + rect.bottom = rect.top + pt.y; + monitor = MonitorFromPoint( cpt, MONITOR_DEFAULTTOPRIMARY ); + } + else /* CFS_DEFAULT */ + { + /* Windows places the default IME window in the bottom left */ + HWND target = ctx->hWnd; + if (!target) target = GetFocus(); + + GetWindowRect( target, &rect ); + rect.top = rect.bottom; + rect.right = rect.left + pt.x + 20; + rect.bottom = rect.top + pt.y + 20; + offset.x = offset.y = 10; + monitor = MonitorFromWindow( target, MONITOR_DEFAULTTOPRIMARY ); + } + + if (ctx->cfCompForm.dwStyle == CFS_RECT) + { + RECT client; + client = ctx->cfCompForm.rcArea; + MapWindowPoints( ctx->hWnd, 0, (POINT *)&client, 2 ); + IntersectRect( &rect, &rect, &client ); + /* TODO: Wrap the input if needed */ + } + + if (ctx->cfCompForm.dwStyle == CFS_DEFAULT) + { + /* make sure we are on the desktop */ + mon_info.cbSize = sizeof(mon_info); + GetMonitorInfoW( monitor, &mon_info ); + + if (rect.bottom > mon_info.rcWork.bottom) + { + int shift = rect.bottom - mon_info.rcWork.bottom; + rect.top -= shift; + rect.bottom -= shift; + } + if (rect.left < 0) + { + rect.right -= rect.left; + rect.left = 0; + } + if (rect.right > mon_info.rcWork.right) + { + int shift = rect.right - mon_info.rcWork.right; + rect.left -= shift; + rect.right -= shift; + } + } + + SetWindowPos( hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, SWP_NOACTIVATE ); + TextOutW( hdc, offset.x, offset.y, str, len ); + + if (font) SelectObject( hdc, font ); + free( str ); + } + + EndPaint( hwnd, &ps ); + ImmUnlockIMC( himc ); +} + +static void ime_ui_update_window( INPUTCONTEXT *ctx, HWND hwnd ) +{ + COMPOSITIONSTRING *string; + + if (ctx->hCompStr) string = ImmLockIMCC( ctx->hCompStr ); + else string = NULL; + + if (!string || string->dwCompStrLen == 0) + ShowWindow( hwnd, SW_HIDE ); + else + { + ShowWindow( hwnd, SW_SHOWNOACTIVATE ); + RedrawWindow( hwnd, NULL, NULL, RDW_ERASENOW | RDW_INVALIDATE ); + } + + if (string) ImmUnlockIMCC( ctx->hCompStr ); + + ctx->hWnd = GetFocus(); +} + +static void ime_ui_composition( HIMC himc, HWND hwnd, LPARAM lparam ) +{ + INPUTCONTEXT *ctx; + TRACE( "IME message WM_IME_COMPOSITION 0x%Ix\n", lparam ); + if (lparam & GCS_RESULTSTR) return; + if (!(ctx = ImmLockIMC( himc ))) return; + ime_ui_update_window( ctx, hwnd ); + ImmUnlockIMC( himc ); +} + +static void ime_ui_start_composition( HIMC himc, HWND hwnd ) +{ + INPUTCONTEXT *ctx; + TRACE( "IME message WM_IME_STARTCOMPOSITION\n" ); + if (!(ctx = ImmLockIMC( himc ))) return; + ime_ui_update_window( ctx, hwnd ); + ImmUnlockIMC( himc ); +} + +static LRESULT ime_ui_notify( HIMC himc, HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + switch (wparam) + { + case IMN_OPENSTATUSWINDOW: FIXME( "WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n" ); break; + case IMN_CLOSESTATUSWINDOW: FIXME( "WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n" ); break; + case IMN_OPENCANDIDATE: FIXME( "WM_IME_NOTIFY:IMN_OPENCANDIDATE\n" ); break; + case IMN_CHANGECANDIDATE: FIXME( "WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n" ); break; + case IMN_CLOSECANDIDATE: FIXME( "WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n" ); break; + case IMN_SETCONVERSIONMODE: FIXME( "WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n" ); break; + case IMN_SETSENTENCEMODE: FIXME( "WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n" ); break; + case IMN_SETOPENSTATUS: TRACE( "WM_IME_NOTIFY:IMN_SETOPENSTATUS\n" ); break; + case IMN_SETCANDIDATEPOS: FIXME( "WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n" ); break; + case IMN_SETCOMPOSITIONFONT: FIXME( "WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n" ); break; + case IMN_SETCOMPOSITIONWINDOW: FIXME( "WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n" ); break; + case IMN_GUIDELINE: FIXME( "WM_IME_NOTIFY:IMN_GUIDELINE\n" ); break; + case IMN_SETSTATUSWINDOWPOS: FIXME( "WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n" ); break; + default: FIXME( "WM_IME_NOTIFY:\n", wparam ); break; + } + return 0; +} + +static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + HIMC himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ); + INPUTCONTEXT *ctx; + LRESULT ret = 0; + + TRACE( "hwnd %p, himc %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, himc, msg, wparam, lparam ); + + /* if we have no himc there are many messages we cannot process */ + if (!himc) + { + switch (msg) + { + case WM_IME_STARTCOMPOSITION: + case WM_IME_ENDCOMPOSITION: + case WM_IME_COMPOSITION: + case WM_IME_NOTIFY: + case WM_IME_CONTROL: + case WM_IME_COMPOSITIONFULL: + case WM_IME_SELECT: + case WM_IME_CHAR: return 0L; + default: break; + } + } + + switch (msg) + { + case WM_CREATE: + { + struct ime_private *priv; + + SetWindowTextA( hwnd, "Wine Ime Active" ); + + if (!(ctx = ImmLockIMC( himc ))) return TRUE; + if ((priv = ImmLockIMCC( ctx->hPrivate ))) + { + priv->hwndDefault = hwnd; + ImmUnlockIMCC( ctx->hPrivate ); + } + ImmUnlockIMC( himc ); + return TRUE; + } + case WM_PAINT: + ime_ui_paint( himc, hwnd ); + return FALSE; + case WM_NCCREATE: + return TRUE; + case WM_SETFOCUS: + if (wparam) SetFocus( (HWND)wparam ); + else FIXME( "Received focus, should never have focus\n" ); + break; + case WM_IME_COMPOSITION: + ime_ui_composition( himc, hwnd, lparam ); + break; + case WM_IME_STARTCOMPOSITION: + ime_ui_start_composition( himc, hwnd ); + break; + case WM_IME_ENDCOMPOSITION: + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_ENDCOMPOSITION", wparam, lparam ); + ShowWindow( hwnd, SW_HIDE ); + break; + case WM_IME_SELECT: + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_SELECT", wparam, lparam ); + break; + case WM_IME_CONTROL: + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_CONTROL", wparam, lparam ); + ret = 1; + break; + case WM_IME_NOTIFY: + ret = ime_ui_notify( himc, hwnd, msg, wparam, lparam ); + break; + default: + TRACE( "Non-standard message 0x%x\n", msg ); + break; + } + + /* check the MSIME messages */ + if (msg == WM_MSIME_SERVICE) + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_SERVICE", wparam, lparam ); + else if (msg == WM_MSIME_RECONVERTOPTIONS) + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERTOPTIONS", wparam, lparam ); + else if (msg == WM_MSIME_MOUSE) + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_MOUSE", wparam, lparam ); + else if (msg == WM_MSIME_RECONVERTREQUEST) + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERTREQUEST", wparam, lparam ); + else if (msg == WM_MSIME_RECONVERT) + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERT", wparam, lparam ); + else if (msg == WM_MSIME_QUERYPOSITION) + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_QUERYPOSITION", wparam, lparam ); + else if (msg == WM_MSIME_DOCUMENTFEED) + TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_DOCUMENTFEED", wparam, lparam ); + + /* DefWndProc if not an IME message */ + if (!ret && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) || + (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP))) + ret = DefWindowProcW( hwnd, msg, wparam, lparam ); + + return ret; +} + +static WNDCLASSEXW ime_ui_class = +{ + .cbSize = sizeof(WNDCLASSEXW), + .style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW, + .lpfnWndProc = ime_ui_window_proc, + .cbWndExtra = 2 * sizeof(LONG_PTR), + .lpszClassName = L"Wine IME", + .hbrBackground = (HBRUSH)(COLOR_WINDOW + 1), +}; + BOOL WINAPI ImeInquire( IMEINFO *info, WCHAR *ui_class, DWORD flags ) { - FIXME( "info %p, ui_class %p, flags %#lx stub!\n", info, ui_class, flags ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + TRACE( "info %p, ui_class %p, flags %#lx\n", info, ui_class, flags ); + + ime_ui_class.hInstance = imm32_module; + ime_ui_class.hCursor = LoadCursorW( NULL, (LPWSTR)IDC_ARROW ); + ime_ui_class.hIcon = LoadIconW( NULL, (LPWSTR)IDI_APPLICATION ); + RegisterClassExW( &ime_ui_class ); + + wcscpy( ui_class, ime_ui_class.lpszClassName ); + memset( info, 0, sizeof(*info) ); + info->dwPrivateDataSize = sizeof(IMEPRIVATE); + info->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET; + info->fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE; + info->fdwSentenceCaps = IME_SMODE_AUTOMATIC; + info->fdwUICaps = UI_CAP_2700; + /* Tell App we cannot accept ImeSetCompositionString calls */ + info->fdwSCSCaps = 0; + info->fdwSelectCaps = SELECT_CAP_CONVERSION; + + return TRUE; } BOOL WINAPI ImeDestroy( UINT force ) { - FIXME( "force %u stub!\n", force ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + TRACE( "force %u\n", force ); + UnregisterClassW( ime_ui_class.lpszClassName, imm32_module ); + return TRUE; } BOOL WINAPI ImeSelect( HIMC himc, BOOL select ) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index e936bb27754..8eee8604bcf 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -20,37 +20,24 @@ */ #define COBJMACROS - -#include -#include - #include "initguid.h" -#include "objbase.h" -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "ntuser.h" -#include "winerror.h" -#include "wine/debug.h" -#include "imm.h" -#include "immdev.h" -#include "winnls.h" -#include "winreg.h" -#include "wine/list.h" +#include "imm_private.h" WINE_DEFAULT_DEBUG_CHANNEL(imm); #define IMM_INIT_MAGIC 0x19650412 BOOL WINAPI User32InitializeImmEntryTable(DWORD); +HMODULE imm32_module; + /* MSIME messages */ -static UINT WM_MSIME_SERVICE; -static UINT WM_MSIME_RECONVERTOPTIONS; -static UINT WM_MSIME_MOUSE; -static UINT WM_MSIME_RECONVERTREQUEST; -static UINT WM_MSIME_RECONVERT; -static UINT WM_MSIME_QUERYPOSITION; -static UINT WM_MSIME_DOCUMENTFEED; +UINT WM_MSIME_SERVICE; +UINT WM_MSIME_RECONVERTOPTIONS; +UINT WM_MSIME_MOUSE; +UINT WM_MSIME_RECONVERTREQUEST; +UINT WM_MSIME_RECONVERT; +UINT WM_MSIME_QUERYPOSITION; +UINT WM_MSIME_DOCUMENTFEED; struct ime { @@ -709,28 +696,28 @@ static void IMM_FreeAllImmHkl(void) } } -BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved) +BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved ) { - TRACE("%p, %lx, %p\n",hInstDLL,fdwReason,lpReserved); - switch (fdwReason) + TRACE( "instance %p, reason %lx, reserved %p\n", instance, reason, reserved ); + + switch (reason) { - case DLL_PROCESS_ATTACH: - if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC)) - { - return FALSE; - } - break; - case DLL_THREAD_ATTACH: - break; - case DLL_THREAD_DETACH: - IMM_FreeThreadData(); - break; - case DLL_PROCESS_DETACH: - if (lpReserved) break; - IMM_FreeThreadData(); - IMM_FreeAllImmHkl(); - break; + case DLL_PROCESS_ATTACH: + if (!User32InitializeImmEntryTable( IMM_INIT_MAGIC )) return FALSE; + imm32_module = instance; + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + IMM_FreeThreadData(); + break; + case DLL_PROCESS_DETACH: + if (reserved) break; + IMM_FreeThreadData(); + IMM_FreeAllImmHkl(); + break; } + return TRUE; } diff --git a/dlls/imm32/imm_private.h b/dlls/imm32/imm_private.h new file mode 100644 index 00000000000..57b496ef434 --- /dev/null +++ b/dlls/imm32/imm_private.h @@ -0,0 +1,46 @@ +/* + * Copyright 2023 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 + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "winreg.h" + +#include "imm.h" +#include "immdev.h" +#include "ntuser.h" +#include "objbase.h" + +#include "wine/debug.h" +#include "wine/list.h" + +extern HMODULE imm32_module; + +/* MSIME messages */ +extern UINT WM_MSIME_SERVICE; +extern UINT WM_MSIME_RECONVERTOPTIONS; +extern UINT WM_MSIME_MOUSE; +extern UINT WM_MSIME_RECONVERTREQUEST; +extern UINT WM_MSIME_RECONVERT; +extern UINT WM_MSIME_QUERYPOSITION; +extern UINT WM_MSIME_DOCUMENTFEED; diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index 5e78ae055fb..1d04092cae0 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -44,16 +44,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm); #define FROM_MACDRV ((HIMC)0xcafe1337) -typedef struct ime_private -{ - BOOL bInComposition; - BOOL bInternalState; - HFONT textfont; - HWND hwndDefault; - - UINT repeat; -} IMEPRIVATE, *LPIMEPRIVATE; - static const WCHAR UI_CLASS_NAME[] = {'W','i','n','e',' ','M','a','c',' ','I','M','E',0}; static HIMC *hSelectedFrom = NULL; diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 931289b751b..55485bfbfcf 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -49,28 +49,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm); #define FROM_X11 ((HIMC)0xcafe1337) -typedef struct ime_private -{ - BOOL bInComposition; - BOOL bInternalState; - HFONT textfont; - HWND hwndDefault; -} IMEPRIVATE, *LPIMEPRIVATE; - -static const WCHAR UI_CLASS_NAME[] = {'W','i','n','e','X','1','1','I','M','E',0}; - static HIMC *hSelectedFrom = NULL; static INT hSelectedCount = 0; -/* MSIME messages */ -static UINT WM_MSIME_SERVICE; -static UINT WM_MSIME_RECONVERTOPTIONS; -static UINT WM_MSIME_MOUSE; -static UINT WM_MSIME_RECONVERTREQUEST; -static UINT WM_MSIME_RECONVERT; -static UINT WM_MSIME_QUERYPOSITION; -static UINT WM_MSIME_DOCUMENTFEED; - static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT *length ) { COMPOSITIONSTRING *string; @@ -92,19 +73,6 @@ static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT * return text; } -static HFONT input_context_select_ui_font( INPUTCONTEXT *ctx, HDC hdc ) -{ - struct ime_private *priv; - HFONT font = NULL; - if (!(priv = ImmLockIMCC( ctx->hPrivate ))) return NULL; - if (priv->textfont) font = SelectObject( hdc, priv->textfont ); - ImmUnlockIMCC( ctx->hPrivate ); - return font; -} - -static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, - LPARAM lParam); - static HIMC RealIMC(HIMC hIMC) { if (hIMC == FROM_X11) @@ -139,34 +107,6 @@ static BOOL UnlockRealIMC(HIMC hIMC) return FALSE; } -static BOOL WINAPI register_classes( INIT_ONCE *once, void *param, void **context ) -{ - WNDCLASSW wndClass; - - ZeroMemory(&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW; - wndClass.lpfnWndProc = IME_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = 2 * sizeof(LONG_PTR); - wndClass.hInstance = x11drv_module; - wndClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW); - wndClass.hIcon = LoadIconW(NULL, (LPWSTR)IDI_APPLICATION); - wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW +1); - wndClass.lpszMenuName = 0; - wndClass.lpszClassName = UI_CLASS_NAME; - - RegisterClassW(&wndClass); - - WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService"); - WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions"); - WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation"); - WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest"); - WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert"); - WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition"); - WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed"); - return TRUE; -} - static HIMCC ImeCreateBlankCompStr(void) { HIMCC rc; @@ -537,35 +477,6 @@ static void IME_AddToSelected(HIMC hIMC) hSelectedFrom[hSelectedCount-1] = hIMC; } -BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass, DWORD flags) -{ - static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; - - TRACE("\n"); - InitOnceExecuteOnce( &init_once, register_classes, NULL, NULL ); - lpIMEInfo->dwPrivateDataSize = sizeof (IMEPRIVATE); - lpIMEInfo->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET; - lpIMEInfo->fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE; - lpIMEInfo->fdwSentenceCaps = IME_SMODE_AUTOMATIC; - lpIMEInfo->fdwUICaps = UI_CAP_2700; - /* Tell App we cannot accept ImeSetCompositionString calls */ - lpIMEInfo->fdwSCSCaps = 0; - lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION; - - lstrcpyW(lpszUIClass,UI_CLASS_NAME); - - return TRUE; -} - -BOOL WINAPI ImeDestroy(UINT uForce) -{ - TRACE("\n"); - HeapFree(GetProcessHeap(),0,hSelectedFrom); - hSelectedFrom = NULL; - hSelectedCount = 0; - return TRUE; -} - BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lpbKeyState) { /* See the comment at the head of this file */ @@ -994,307 +905,3 @@ NTSTATUS WINAPI x11drv_ime_set_result( void *params, ULONG len ) ImmUnlockIMC(imc); return 0; } - -/***** - * Internal functions to help with IME window management - */ -static void PaintDefaultIMEWnd( HIMC hIMC, HWND hwnd ) -{ - PAINTSTRUCT ps; - RECT rect; - HDC hdc; - HMONITOR monitor; - MONITORINFO mon_info; - INT offX = 0, offY = 0; - LPINPUTCONTEXT lpIMC; - WCHAR *str; - UINT len; - - lpIMC = ImmLockIMC( hIMC ); - if (lpIMC == NULL) return; - - hdc = BeginPaint( hwnd, &ps ); - - GetClientRect( hwnd, &rect ); - FillRect( hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1) ); - - if ((str = input_context_get_comp_str( lpIMC, FALSE, &len ))) - { - HFONT font = input_context_select_ui_font( lpIMC, hdc ); - SIZE size; - POINT pt; - - GetTextExtentPoint32W( hdc, str, len, &size ); - pt.x = size.cx; - pt.y = size.cy; - LPtoDP( hdc, &pt, 1 ); - - /* - * How this works based on tests on windows: - * CFS_POINT: then we start our window at the point and grow it as large - * as it needs to be for the string. - * CFS_RECT: we still use the ptCurrentPos as a starting point and our - * window is only as large as we need for the string, but we do not - * grow such that our window exceeds the given rect. Wrapping if - * needed and possible. If our ptCurrentPos is outside of our rect - * then no window is displayed. - * CFS_FORCE_POSITION: appears to behave just like CFS_POINT - * maybe because the default MSIME does not do any IME adjusting. - */ - if (lpIMC->cfCompForm.dwStyle != CFS_DEFAULT) - { - POINT cpt = lpIMC->cfCompForm.ptCurrentPos; - ClientToScreen( lpIMC->hWnd, &cpt ); - rect.left = cpt.x; - rect.top = cpt.y; - rect.right = rect.left + pt.x; - rect.bottom = rect.top + pt.y; - monitor = MonitorFromPoint( cpt, MONITOR_DEFAULTTOPRIMARY ); - } - else /* CFS_DEFAULT */ - { - /* Windows places the default IME window in the bottom left */ - HWND target = lpIMC->hWnd; - if (!target) target = GetFocus(); - - GetWindowRect( target, &rect ); - rect.top = rect.bottom; - rect.right = rect.left + pt.x + 20; - rect.bottom = rect.top + pt.y + 20; - offX = offY = 10; - monitor = MonitorFromWindow( target, MONITOR_DEFAULTTOPRIMARY ); - } - - if (lpIMC->cfCompForm.dwStyle == CFS_RECT) - { - RECT client; - client = lpIMC->cfCompForm.rcArea; - MapWindowPoints( lpIMC->hWnd, 0, (POINT *)&client, 2 ); - IntersectRect( &rect, &rect, &client ); - /* TODO: Wrap the input if needed */ - } - - if (lpIMC->cfCompForm.dwStyle == CFS_DEFAULT) - { - /* make sure we are on the desktop */ - mon_info.cbSize = sizeof(mon_info); - GetMonitorInfoW( monitor, &mon_info ); - - if (rect.bottom > mon_info.rcWork.bottom) - { - int shift = rect.bottom - mon_info.rcWork.bottom; - rect.top -= shift; - rect.bottom -= shift; - } - if (rect.left < 0) - { - rect.right -= rect.left; - rect.left = 0; - } - if (rect.right > mon_info.rcWork.right) - { - int shift = rect.right - mon_info.rcWork.right; - rect.left -= shift; - rect.right -= shift; - } - } - - SetWindowPos( hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, - rect.bottom - rect.top, SWP_NOACTIVATE ); - TextOutW( hdc, offX, offY, str, len ); - - if (font) SelectObject( hdc, font ); - free( str ); - } - - EndPaint( hwnd, &ps ); - ImmUnlockIMC( hIMC ); -} - -static void UpdateDefaultIMEWindow( INPUTCONTEXT *lpIMC, HWND hwnd ) -{ - LPCOMPOSITIONSTRING compstr; - - if (lpIMC->hCompStr) compstr = ImmLockIMCC( lpIMC->hCompStr ); - else compstr = NULL; - - if (compstr == NULL || compstr->dwCompStrLen == 0) - ShowWindow( hwnd, SW_HIDE ); - else - { - ShowWindow( hwnd, SW_SHOWNOACTIVATE ); - RedrawWindow( hwnd, NULL, NULL, RDW_ERASENOW | RDW_INVALIDATE ); - } - - if (compstr != NULL) ImmUnlockIMCC( lpIMC->hCompStr ); - - lpIMC->hWnd = GetFocus(); -} - -static void DefaultIMEComposition( HIMC hIMC, HWND hwnd, LPARAM lParam ) -{ - INPUTCONTEXT *ctx; - TRACE( "IME message WM_IME_COMPOSITION 0x%Ix\n", lParam ); - if (lParam & GCS_RESULTSTR) return; - if (!(ctx = ImmLockIMC( hIMC ))) return; - UpdateDefaultIMEWindow( ctx, hwnd ); - ImmUnlockIMC( hIMC ); -} - -static void DefaultIMEStartComposition( HIMC hIMC, HWND hwnd ) -{ - INPUTCONTEXT *ctx; - TRACE( "IME message WM_IME_STARTCOMPOSITION\n" ); - if (!(ctx = ImmLockIMC( hIMC ))) return; - UpdateDefaultIMEWindow( ctx, hwnd ); - ImmUnlockIMC( hIMC ); -} - -static LRESULT ImeHandleNotify( HIMC hIMC, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - switch (wParam) - { - case IMN_OPENSTATUSWINDOW: FIXME( "WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n" ); break; - case IMN_CLOSESTATUSWINDOW: FIXME( "WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n" ); break; - case IMN_OPENCANDIDATE: FIXME( "WM_IME_NOTIFY:IMN_OPENCANDIDATE\n" ); break; - case IMN_CHANGECANDIDATE: FIXME( "WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n" ); break; - case IMN_CLOSECANDIDATE: FIXME( "WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n" ); break; - case IMN_SETCONVERSIONMODE: FIXME( "WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n" ); break; - case IMN_SETSENTENCEMODE: FIXME( "WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n" ); break; - case IMN_SETOPENSTATUS: TRACE( "WM_IME_NOTIFY:IMN_SETOPENSTATUS\n" ); break; - case IMN_SETCANDIDATEPOS: FIXME( "WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n" ); break; - case IMN_SETCOMPOSITIONFONT: FIXME( "WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n" ); break; - case IMN_SETCOMPOSITIONWINDOW: FIXME( "WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n" ); break; - case IMN_GUIDELINE: FIXME( "WM_IME_NOTIFY:IMN_GUIDELINE\n" ); break; - case IMN_SETSTATUSWINDOWPOS: FIXME( "WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n" ); break; - default: FIXME( "WM_IME_NOTIFY:\n", wParam ); break; - } - return 0; -} - -static LRESULT WINAPI IME_WindowProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - LRESULT rc = 0; - HIMC hIMC; - - TRACE( "Incoming Message 0x%x (0x%08Ix, 0x%08Ix)\n", msg, wParam, lParam ); - - /* - * Each UI window contains the current Input Context. - * This Input Context can be obtained by calling GetWindowLong - * with IMMGWL_IMC when the UI window receives a WM_IME_xxx message. - * The UI window can refer to this Input Context and handles the - * messages. - */ - - hIMC = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ); - - /* if we have no hIMC there are many messages we cannot process */ - if (hIMC == NULL) - { - switch (msg) - { - case WM_IME_STARTCOMPOSITION: - case WM_IME_ENDCOMPOSITION: - case WM_IME_COMPOSITION: - case WM_IME_NOTIFY: - case WM_IME_CONTROL: - case WM_IME_COMPOSITIONFULL: - case WM_IME_SELECT: - case WM_IME_CHAR: return 0L; - default: break; - } - } - - switch (msg) - { - case WM_CREATE: - { - LPIMEPRIVATE myPrivate; - LPINPUTCONTEXT lpIMC; - - SetWindowTextA( hwnd, "Wine Ime Active" ); - - lpIMC = ImmLockIMC( hIMC ); - if (lpIMC) - { - myPrivate = ImmLockIMCC( lpIMC->hPrivate ); - myPrivate->hwndDefault = hwnd; - ImmUnlockIMCC( lpIMC->hPrivate ); - } - ImmUnlockIMC( hIMC ); - - return TRUE; - } - case WM_PAINT: - PaintDefaultIMEWnd( hIMC, hwnd ); - return FALSE; - case WM_NCCREATE: - return TRUE; - case WM_SETFOCUS: - if (wParam) SetFocus( (HWND)wParam ); - else FIXME( "Received focus, should never have focus\n" ); - break; - - case WM_IME_COMPOSITION: - DefaultIMEComposition( hIMC, hwnd, lParam ); - break; - case WM_IME_STARTCOMPOSITION: - DefaultIMEStartComposition( hIMC, hwnd ); - break; - case WM_IME_ENDCOMPOSITION: - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_ENDCOMPOSITION", wParam, lParam ); - ShowWindow( hwnd, SW_HIDE ); - break; - case WM_IME_SELECT: - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_SELECT", wParam, lParam ); - break; - case WM_IME_CONTROL: - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_CONTROL", wParam, lParam ); - rc = 1; - break; - case WM_IME_NOTIFY: - rc = ImeHandleNotify( hIMC, hwnd, msg, wParam, lParam ); - break; - default: - TRACE( "Non-standard message 0x%x\n", msg ); - } - - /* check the MSIME messages */ - if (msg == WM_MSIME_SERVICE) - { - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_SERVICE", wParam, lParam ); - rc = FALSE; - } - else if (msg == WM_MSIME_RECONVERTOPTIONS) - { - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERTOPTIONS", wParam, lParam ); - } - else if (msg == WM_MSIME_MOUSE) - { - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_MOUSE", wParam, lParam ); - } - else if (msg == WM_MSIME_RECONVERTREQUEST) - { - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERTREQUEST", wParam, lParam ); - } - else if (msg == WM_MSIME_RECONVERT) - { - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERT", wParam, lParam ); - } - else if (msg == WM_MSIME_QUERYPOSITION) - { - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_QUERYPOSITION", wParam, lParam ); - } - else if (msg == WM_MSIME_DOCUMENTFEED) - { - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_DOCUMENTFEED", wParam, lParam ); - } - - /* DefWndProc if not an IME message */ - if (!rc && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) || - (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP))) - rc = DefWindowProcW( hwnd, msg, wParam, lParam ); - - return rc; -} diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec index 0596d48c577..a753536eb3f 100644 --- a/dlls/winex11.drv/winex11.drv.spec +++ b/dlls/winex11.drv/winex11.drv.spec @@ -11,8 +11,6 @@ @ cdecl wine_notify_icon(long ptr) #IME Interface -@ stdcall ImeInquire(ptr ptr wstr) -@ stdcall ImeDestroy(long) @ stdcall ImeSelect(long long) @ stdcall ImeToAsciiEx(long long ptr ptr long long) @ stdcall NotifyIME(long long long long) diff --git a/include/ntuser.h b/include/ntuser.h index 86267d3e244..67f6cd54837 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -490,6 +490,16 @@ enum wine_internal_message #define IME_INTERNAL_HKL_ACTIVATE 0x19 #define IME_INTERNAL_HKL_DEACTIVATE 0x20 +/* internal IME private */ +typedef struct ime_private +{ + BOOL bInComposition; + BOOL bInternalState; + HFONT textfont; + HWND hwndDefault; + UINT repeat; +} IMEPRIVATE, *LPIMEPRIVATE; + #define WM_SYSTIMER 0x0118 /* the various structures that can be sent in messages, in platform-independent layout */ From fa3036d48dc13b3eaa581c2b1bed9e1d75250c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 7 Apr 2023 16:21:46 +0200 Subject: [PATCH 1838/2777] winemac: Use the default IME UI window proc implementation. This slightly changes ime_ui_update_window to match what was previously in winex11.drv, since e5f0cdfcf6ba1595346c4c9ed1a7cbf3de418c8e, which seems to be a more recent change. (cherry picked from commit d8fa43377d895f92149e8fc1872a8b22261b33a2) --- dlls/winemac.drv/ime.c | 391 ------------------------------ dlls/winemac.drv/winemac.drv.spec | 2 - 2 files changed, 393 deletions(-) diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index 1d04092cae0..bca8377d146 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -44,20 +44,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm); #define FROM_MACDRV ((HIMC)0xcafe1337) -static const WCHAR UI_CLASS_NAME[] = {'W','i','n','e',' ','M','a','c',' ','I','M','E',0}; - static HIMC *hSelectedFrom = NULL; static INT hSelectedCount = 0; -/* MSIME messages */ -static UINT WM_MSIME_SERVICE; -static UINT WM_MSIME_RECONVERTOPTIONS; -static UINT WM_MSIME_MOUSE; -static UINT WM_MSIME_RECONVERTREQUEST; -static UINT WM_MSIME_RECONVERT; -static UINT WM_MSIME_QUERYPOSITION; -static UINT WM_MSIME_DOCUMENTFEED; - static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT *length ) { COMPOSITIONSTRING *string; @@ -545,15 +534,6 @@ static void UpdateDataInDefaultIMEWindow(INPUTCONTEXT *lpIMC, HWND hwnd, BOOL sh ImmUnlockIMCC(lpIMC->hCompStr); } -BOOL WINAPI ImeDestroy(UINT uForce) -{ - TRACE("\n"); - HeapFree(GetProcessHeap(), 0, hSelectedFrom); - hSelectedFrom = NULL; - hSelectedCount = 0; - return TRUE; -} - BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lpbKeyState) { LPINPUTCONTEXT lpIMC; @@ -950,377 +930,6 @@ static void IME_NotifyComplete(void* hIMC) NotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); } -/***** - * Internal functions to help with IME window management - */ -static void PaintDefaultIMEWnd(HIMC hIMC, HWND hwnd) -{ - PAINTSTRUCT ps; - RECT rect; - HDC hdc; - HMONITOR monitor; - MONITORINFO mon_info; - INT offX = 0, offY = 0; - LPINPUTCONTEXT lpIMC; - WCHAR *str; - UINT len; - - lpIMC = ImmLockIMC(hIMC); - if (lpIMC == NULL) - return; - - hdc = BeginPaint(hwnd, &ps); - - GetClientRect(hwnd, &rect); - FillRect(hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1)); - - if ((str = input_context_get_comp_str( lpIMC, FALSE, &len ))) - { - HFONT font = input_context_select_ui_font( lpIMC, hdc ); - SIZE size; - POINT pt; - - GetTextExtentPoint32W( hdc, str, len, &size ); - pt.x = size.cx; - pt.y = size.cy; - LPtoDP(hdc, &pt, 1); - - /* - * How this works based on tests on windows: - * CFS_POINT: then we start our window at the point and grow it as large - * as it needs to be for the string. - * CFS_RECT: we still use the ptCurrentPos as a starting point and our - * window is only as large as we need for the string, but we do not - * grow such that our window exceeds the given rect. Wrapping if - * needed and possible. If our ptCurrentPos is outside of our rect - * then no window is displayed. - * CFS_FORCE_POSITION: appears to behave just like CFS_POINT - * maybe because the default MSIME does not do any IME adjusting. - */ - if (lpIMC->cfCompForm.dwStyle != CFS_DEFAULT) - { - POINT cpt = lpIMC->cfCompForm.ptCurrentPos; - ClientToScreen(lpIMC->hWnd, &cpt); - rect.left = cpt.x; - rect.top = cpt.y; - rect.right = rect.left + pt.x; - rect.bottom = rect.top + pt.y; - monitor = MonitorFromPoint(cpt, MONITOR_DEFAULTTOPRIMARY); - } - else /* CFS_DEFAULT */ - { - /* Windows places the default IME window in the bottom left */ - HWND target = lpIMC->hWnd; - if (!target) target = GetFocus(); - - GetWindowRect(target, &rect); - rect.top = rect.bottom; - rect.right = rect.left + pt.x + 20; - rect.bottom = rect.top + pt.y + 20; - offX=offY=10; - monitor = MonitorFromWindow(target, MONITOR_DEFAULTTOPRIMARY); - } - - if (lpIMC->cfCompForm.dwStyle == CFS_RECT) - { - RECT client; - client =lpIMC->cfCompForm.rcArea; - MapWindowPoints(lpIMC->hWnd, 0, (POINT *)&client, 2); - IntersectRect(&rect, &rect, &client); - /* TODO: Wrap the input if needed */ - } - - if (lpIMC->cfCompForm.dwStyle == CFS_DEFAULT) - { - /* make sure we are on the desktop */ - mon_info.cbSize = sizeof(mon_info); - GetMonitorInfoW(monitor, &mon_info); - - if (rect.bottom > mon_info.rcWork.bottom) - { - int shift = rect.bottom - mon_info.rcWork.bottom; - rect.top -= shift; - rect.bottom -= shift; - } - if (rect.left < 0) - { - rect.right -= rect.left; - rect.left = 0; - } - if (rect.right > mon_info.rcWork.right) - { - int shift = rect.right - mon_info.rcWork.right; - rect.left -= shift; - rect.right -= shift; - } - } - - SetWindowPos(hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, - rect.bottom - rect.top, SWP_NOACTIVATE); - - TextOutW( hdc, offX, offY, str, len ); - - if (font) SelectObject( hdc, font ); - free( str ); - } - - ImmUnlockIMCC(lpIMC->hCompStr); - - EndPaint(hwnd, &ps); - ImmUnlockIMC(hIMC); -} - -static void DefaultIMEComposition(HIMC hIMC, HWND hwnd, LPARAM lParam) -{ - INPUTCONTEXT *ctx; - TRACE("IME message WM_IME_COMPOSITION 0x%Ix\n", lParam); - if (lParam & GCS_RESULTSTR) return; - if (!(ctx = ImmLockIMC( hIMC ))) return; - UpdateDataInDefaultIMEWindow( ctx, hwnd, TRUE ); - ImmUnlockIMC(hIMC); -} - -static void DefaultIMEStartComposition(HIMC hIMC, HWND hwnd) -{ - LPINPUTCONTEXT lpIMC; - - lpIMC = ImmLockIMC(hIMC); - if (lpIMC == NULL) - return; - - TRACE("IME message WM_IME_STARTCOMPOSITION\n"); - lpIMC->hWnd = GetFocus(); - ShowWindow(hwnd, SW_SHOWNOACTIVATE); - ImmUnlockIMC(hIMC); -} - -static LRESULT ImeHandleNotify(HIMC hIMC, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (wParam) - { - case IMN_OPENSTATUSWINDOW: - FIXME("WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n"); - break; - case IMN_CLOSESTATUSWINDOW: - FIXME("WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n"); - break; - case IMN_OPENCANDIDATE: - FIXME("WM_IME_NOTIFY:IMN_OPENCANDIDATE\n"); - break; - case IMN_CHANGECANDIDATE: - FIXME("WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n"); - break; - case IMN_CLOSECANDIDATE: - FIXME("WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n"); - break; - case IMN_SETCONVERSIONMODE: - FIXME("WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n"); - break; - case IMN_SETSENTENCEMODE: - FIXME("WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n"); - break; - case IMN_SETOPENSTATUS: - FIXME("WM_IME_NOTIFY:IMN_SETOPENSTATUS\n"); - break; - case IMN_SETCANDIDATEPOS: - FIXME("WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n"); - break; - case IMN_SETCOMPOSITIONFONT: - FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n"); - break; - case IMN_SETCOMPOSITIONWINDOW: - FIXME("WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n"); - break; - case IMN_GUIDELINE: - FIXME("WM_IME_NOTIFY:IMN_GUIDELINE\n"); - break; - case IMN_SETSTATUSWINDOWPOS: - FIXME("WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n"); - break; - default: - FIXME("WM_IME_NOTIFY:\n", wParam); - break; - } - return 0; -} - -static LRESULT WINAPI IME_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - LRESULT rc = 0; - HIMC hIMC; - - TRACE("Incoming Message 0x%x (0x%08Ix, 0x%08Ix)\n", msg, wParam, lParam); - - /* - * Each UI window contains the current Input Context. - * This Input Context can be obtained by calling GetWindowLong - * with IMMGWL_IMC when the UI window receives a WM_IME_xxx message. - * The UI window can refer to this Input Context and handles the - * messages. - */ - - hIMC = (HIMC)GetWindowLongPtrW(hwnd, IMMGWL_IMC); - - /* if we have no hIMC there are many messages we cannot process */ - if (hIMC == NULL) - { - switch (msg) { - case WM_IME_STARTCOMPOSITION: - case WM_IME_ENDCOMPOSITION: - case WM_IME_COMPOSITION: - case WM_IME_NOTIFY: - case WM_IME_CONTROL: - case WM_IME_COMPOSITIONFULL: - case WM_IME_SELECT: - case WM_IME_CHAR: - return 0L; - default: - break; - } - } - - switch (msg) - { - case WM_CREATE: - { - LPIMEPRIVATE myPrivate; - LPINPUTCONTEXT lpIMC; - - SetWindowTextA(hwnd, "Wine Ime Active"); - - lpIMC = ImmLockIMC(hIMC); - if (lpIMC) - { - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - myPrivate->hwndDefault = hwnd; - ImmUnlockIMCC(lpIMC->hPrivate); - } - ImmUnlockIMC(hIMC); - - return TRUE; - } - case WM_PAINT: - PaintDefaultIMEWnd(hIMC, hwnd); - return FALSE; - - case WM_NCCREATE: - return TRUE; - - case WM_SETFOCUS: - if (wParam) - SetFocus((HWND)wParam); - else - FIXME("Received focus, should never have focus\n"); - break; - case WM_IME_COMPOSITION: - DefaultIMEComposition(hIMC, hwnd, lParam); - break; - case WM_IME_STARTCOMPOSITION: - DefaultIMEStartComposition(hIMC, hwnd); - break; - case WM_IME_ENDCOMPOSITION: - TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_ENDCOMPOSITION", wParam, lParam); - ShowWindow(hwnd, SW_HIDE); - break; - case WM_IME_SELECT: - TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_SELECT", wParam, lParam); - break; - case WM_IME_CONTROL: - TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_CONTROL", wParam, lParam); - rc = 1; - break; - case WM_IME_NOTIFY: - rc = ImeHandleNotify(hIMC, hwnd, msg, wParam, lParam); - break; - default: - TRACE("Non-standard message 0x%x\n", msg); - } - /* check the MSIME messages */ - if (msg == WM_MSIME_SERVICE) - { - TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_SERVICE", wParam, lParam); - rc = FALSE; - } - else if (msg == WM_MSIME_RECONVERTOPTIONS) - { - TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERTOPTIONS", wParam, lParam); - } - else if (msg == WM_MSIME_MOUSE) - { - TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_MOUSE", wParam, lParam); - } - else if (msg == WM_MSIME_RECONVERTREQUEST) - { - TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERTREQUEST", wParam, lParam); - } - else if (msg == WM_MSIME_RECONVERT) - { - TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERT", wParam, lParam); - } - else if (msg == WM_MSIME_QUERYPOSITION) - { - TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_QUERYPOSITION", wParam, lParam); - } - else if (msg == WM_MSIME_DOCUMENTFEED) - { - TRACE("IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_DOCUMENTFEED", wParam, lParam); - } - /* DefWndProc if not an IME message */ - if (!rc && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) || - (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP))) - rc = DefWindowProcW(hwnd, msg, wParam, lParam); - - return rc; -} - -static BOOL WINAPI register_classes( INIT_ONCE *once, void *param, void **context ) -{ - WNDCLASSW wndClass; - ZeroMemory(&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS | CS_IME | CS_HREDRAW | CS_VREDRAW; - wndClass.lpfnWndProc = (WNDPROC) IME_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = 2 * sizeof(LONG_PTR); - wndClass.hInstance = macdrv_module; - wndClass.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW); - wndClass.hIcon = LoadIconW(NULL, (LPWSTR)IDI_APPLICATION); - wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wndClass.lpszMenuName = 0; - wndClass.lpszClassName = UI_CLASS_NAME; - - RegisterClassW(&wndClass); - - WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService"); - WM_MSIME_RECONVERTOPTIONS = RegisterWindowMessageA("MSIMEReconvertOptions"); - WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation"); - WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest"); - WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert"); - WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition"); - WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed"); - return TRUE; -} - -BOOL WINAPI ImeInquire(LPIMEINFO lpIMEInfo, LPWSTR lpszUIClass, DWORD flags) -{ - static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; - - TRACE("\n"); - InitOnceExecuteOnce( &init_once, register_classes, NULL, NULL ); - lpIMEInfo->dwPrivateDataSize = sizeof(IMEPRIVATE); - lpIMEInfo->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET; - lpIMEInfo->fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE; - lpIMEInfo->fdwSentenceCaps = IME_SMODE_AUTOMATIC; - lpIMEInfo->fdwUICaps = UI_CAP_2700; - /* Tell App we cannot accept ImeSetCompositionString calls */ - /* FIXME: Can we? */ - lpIMEInfo->fdwSCSCaps = 0; - lpIMEInfo->fdwSelectCaps = SELECT_CAP_CONVERSION; - - lstrcpyW(lpszUIClass, UI_CLASS_NAME); - - return TRUE; -} - /* Interfaces to other parts of the Mac driver */ /*********************************************************************** diff --git a/dlls/winemac.drv/winemac.drv.spec b/dlls/winemac.drv/winemac.drv.spec index d5e94b53ce4..debaec8239d 100644 --- a/dlls/winemac.drv/winemac.drv.spec +++ b/dlls/winemac.drv/winemac.drv.spec @@ -2,8 +2,6 @@ @ cdecl wine_notify_icon(long ptr) # IME -@ stdcall ImeDestroy(long) -@ stdcall ImeInquire(ptr wstr wstr) @ stdcall ImeProcessKey(long long long ptr) @ stdcall ImeSelect(long long) @ stdcall ImeSetCompositionString(long long ptr long ptr long) From 26e7d67b9b3bee56ec763eb645496d8b6ddddbd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 6 Apr 2023 00:19:42 +0200 Subject: [PATCH 1839/2777] imm32: Cleanup default IME UI window proc traces. (cherry picked from commit c902be6a84c78c6b7788920525793ebadbaef186) --- dlls/imm32/ime.c | 102 ++++++++++++++++++--------------------- dlls/imm32/imm.c | 3 ++ dlls/imm32/imm_private.h | 28 +++++++++++ 3 files changed, 79 insertions(+), 54 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index f48a0a861d1..42f19b7cb2b 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -23,6 +23,45 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm); +static const char *debugstr_imn( WPARAM wparam ) +{ + switch (wparam) + { + case IMN_OPENSTATUSWINDOW: return "IMN_OPENSTATUSWINDOW"; + case IMN_CLOSESTATUSWINDOW: return "IMN_CLOSESTATUSWINDOW"; + case IMN_OPENCANDIDATE: return "IMN_OPENCANDIDATE"; + case IMN_CHANGECANDIDATE: return "IMN_CHANGECANDIDATE"; + case IMN_CLOSECANDIDATE: return "IMN_CLOSECANDIDATE"; + case IMN_SETCONVERSIONMODE: return "IMN_SETCONVERSIONMODE"; + case IMN_SETSENTENCEMODE: return "IMN_SETSENTENCEMODE"; + case IMN_SETOPENSTATUS: return "IMN_SETOPENSTATUS"; + case IMN_SETCANDIDATEPOS: return "IMN_SETCANDIDATEPOS"; + case IMN_SETCOMPOSITIONFONT: return "IMN_SETCOMPOSITIONFONT"; + case IMN_SETCOMPOSITIONWINDOW: return "IMN_SETCOMPOSITIONWINDOW"; + case IMN_GUIDELINE: return "IMN_GUIDELINE"; + case IMN_SETSTATUSWINDOWPOS: return "IMN_SETSTATUSWINDOWPOS"; + default: return wine_dbg_sprintf( "%#Ix", wparam ); + } +} + +static const char *debugstr_imc( WPARAM wparam ) +{ + switch (wparam) + { + case IMC_GETCANDIDATEPOS: return "IMC_GETCANDIDATEPOS"; + case IMC_SETCANDIDATEPOS: return "IMC_SETCANDIDATEPOS"; + case IMC_GETCOMPOSITIONFONT: return "IMC_GETCOMPOSITIONFONT"; + case IMC_SETCOMPOSITIONFONT: return "IMC_SETCOMPOSITIONFONT"; + case IMC_GETCOMPOSITIONWINDOW: return "IMC_GETCOMPOSITIONWINDOW"; + case IMC_SETCOMPOSITIONWINDOW: return "IMC_SETCOMPOSITIONWINDOW"; + case IMC_GETSTATUSWINDOWPOS: return "IMC_GETSTATUSWINDOWPOS"; + case IMC_SETSTATUSWINDOWPOS: return "IMC_SETSTATUSWINDOWPOS"; + case IMC_CLOSESTATUSWINDOW: return "IMC_CLOSESTATUSWINDOW"; + case IMC_OPENSTATUSWINDOW: return "IMC_OPENSTATUSWINDOW"; + default: return wine_dbg_sprintf( "%#Ix", wparam ); + } +} + static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT *length ) { COMPOSITIONSTRING *string; @@ -189,7 +228,6 @@ static void ime_ui_update_window( INPUTCONTEXT *ctx, HWND hwnd ) static void ime_ui_composition( HIMC himc, HWND hwnd, LPARAM lparam ) { INPUTCONTEXT *ctx; - TRACE( "IME message WM_IME_COMPOSITION 0x%Ix\n", lparam ); if (lparam & GCS_RESULTSTR) return; if (!(ctx = ImmLockIMC( himc ))) return; ime_ui_update_window( ctx, hwnd ); @@ -199,41 +237,19 @@ static void ime_ui_composition( HIMC himc, HWND hwnd, LPARAM lparam ) static void ime_ui_start_composition( HIMC himc, HWND hwnd ) { INPUTCONTEXT *ctx; - TRACE( "IME message WM_IME_STARTCOMPOSITION\n" ); if (!(ctx = ImmLockIMC( himc ))) return; ime_ui_update_window( ctx, hwnd ); ImmUnlockIMC( himc ); } -static LRESULT ime_ui_notify( HIMC himc, HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) -{ - switch (wparam) - { - case IMN_OPENSTATUSWINDOW: FIXME( "WM_IME_NOTIFY:IMN_OPENSTATUSWINDOW\n" ); break; - case IMN_CLOSESTATUSWINDOW: FIXME( "WM_IME_NOTIFY:IMN_CLOSESTATUSWINDOW\n" ); break; - case IMN_OPENCANDIDATE: FIXME( "WM_IME_NOTIFY:IMN_OPENCANDIDATE\n" ); break; - case IMN_CHANGECANDIDATE: FIXME( "WM_IME_NOTIFY:IMN_CHANGECANDIDATE\n" ); break; - case IMN_CLOSECANDIDATE: FIXME( "WM_IME_NOTIFY:IMN_CLOSECANDIDATE\n" ); break; - case IMN_SETCONVERSIONMODE: FIXME( "WM_IME_NOTIFY:IMN_SETCONVERSIONMODE\n" ); break; - case IMN_SETSENTENCEMODE: FIXME( "WM_IME_NOTIFY:IMN_SETSENTENCEMODE\n" ); break; - case IMN_SETOPENSTATUS: TRACE( "WM_IME_NOTIFY:IMN_SETOPENSTATUS\n" ); break; - case IMN_SETCANDIDATEPOS: FIXME( "WM_IME_NOTIFY:IMN_SETCANDIDATEPOS\n" ); break; - case IMN_SETCOMPOSITIONFONT: FIXME( "WM_IME_NOTIFY:IMN_SETCOMPOSITIONFONT\n" ); break; - case IMN_SETCOMPOSITIONWINDOW: FIXME( "WM_IME_NOTIFY:IMN_SETCOMPOSITIONWINDOW\n" ); break; - case IMN_GUIDELINE: FIXME( "WM_IME_NOTIFY:IMN_GUIDELINE\n" ); break; - case IMN_SETSTATUSWINDOWPOS: FIXME( "WM_IME_NOTIFY:IMN_SETSTATUSWINDOWPOS\n" ); break; - default: FIXME( "WM_IME_NOTIFY:\n", wparam ); break; - } - return 0; -} - static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { HIMC himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ); INPUTCONTEXT *ctx; LRESULT ret = 0; - TRACE( "hwnd %p, himc %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, himc, msg, wparam, lparam ); + TRACE( "hwnd %p, himc %p, msg %s, wparam %#Ix, lparam %#Ix\n", + hwnd, himc, debugstr_wm_ime(msg), wparam, lparam ); /* if we have no himc there are many messages we cannot process */ if (!himc) @@ -285,40 +301,18 @@ static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LP ime_ui_start_composition( himc, hwnd ); break; case WM_IME_ENDCOMPOSITION: - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_ENDCOMPOSITION", wparam, lparam ); ShowWindow( hwnd, SW_HIDE ); break; - case WM_IME_SELECT: - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_SELECT", wparam, lparam ); - break; - case WM_IME_CONTROL: - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_IME_CONTROL", wparam, lparam ); - ret = 1; - break; case WM_IME_NOTIFY: - ret = ime_ui_notify( himc, hwnd, msg, wparam, lparam ); - break; - default: - TRACE( "Non-standard message 0x%x\n", msg ); - break; + FIXME( "hwnd %p, himc %p, msg %s, wparam %s, lparam %#Ix stub!\n", hwnd, himc, + debugstr_wm_ime(msg), debugstr_imn(wparam), lparam ); + return 0; + case WM_IME_CONTROL: + FIXME( "hwnd %p, himc %p, msg %s, wparam %s, lparam %#Ix stub!\n", hwnd, himc, + debugstr_wm_ime(msg), debugstr_imc(wparam), lparam ); + return 1; } - /* check the MSIME messages */ - if (msg == WM_MSIME_SERVICE) - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_SERVICE", wparam, lparam ); - else if (msg == WM_MSIME_RECONVERTOPTIONS) - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERTOPTIONS", wparam, lparam ); - else if (msg == WM_MSIME_MOUSE) - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_MOUSE", wparam, lparam ); - else if (msg == WM_MSIME_RECONVERTREQUEST) - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERTREQUEST", wparam, lparam ); - else if (msg == WM_MSIME_RECONVERT) - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_RECONVERT", wparam, lparam ); - else if (msg == WM_MSIME_QUERYPOSITION) - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_QUERYPOSITION", wparam, lparam ); - else if (msg == WM_MSIME_DOCUMENTFEED) - TRACE( "IME message %s, 0x%Ix, 0x%Ix\n", "WM_MSIME_DOCUMENTFEED", wparam, lparam ); - /* DefWndProc if not an IME message */ if (!ret && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) || (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP))) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 8eee8604bcf..25d1df47a1c 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3203,6 +3203,9 @@ LRESULT WINAPI __wine_ime_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lp { HWND ui_hwnd; + TRACE( "hwnd %p, msg %s, wparam %#Ix, lparam %#Ix, ansi %u\n", + hwnd, debugstr_wm_ime(msg), wparam, lparam, ansi ); + switch (msg) { case WM_CREATE: diff --git a/dlls/imm32/imm_private.h b/dlls/imm32/imm_private.h index 57b496ef434..8a957494ce9 100644 --- a/dlls/imm32/imm_private.h +++ b/dlls/imm32/imm_private.h @@ -44,3 +44,31 @@ extern UINT WM_MSIME_RECONVERTREQUEST; extern UINT WM_MSIME_RECONVERT; extern UINT WM_MSIME_QUERYPOSITION; extern UINT WM_MSIME_DOCUMENTFEED; + +static const char *debugstr_wm_ime( UINT msg ) +{ + switch (msg) + { + case WM_IME_STARTCOMPOSITION: return "WM_IME_STARTCOMPOSITION"; + case WM_IME_ENDCOMPOSITION: return "WM_IME_ENDCOMPOSITION"; + case WM_IME_COMPOSITION: return "WM_IME_COMPOSITION"; + case WM_IME_SETCONTEXT: return "WM_IME_SETCONTEXT"; + case WM_IME_NOTIFY: return "WM_IME_NOTIFY"; + case WM_IME_CONTROL: return "WM_IME_CONTROL"; + case WM_IME_COMPOSITIONFULL: return "WM_IME_COMPOSITIONFULL"; + case WM_IME_SELECT: return "WM_IME_SELECT"; + case WM_IME_CHAR: return "WM_IME_CHAR"; + case WM_IME_REQUEST: return "WM_IME_REQUEST"; + case WM_IME_KEYDOWN: return "WM_IME_KEYDOWN"; + case WM_IME_KEYUP: return "WM_IME_KEYUP"; + default: + if (msg == WM_MSIME_SERVICE) return "WM_MSIME_SERVICE"; + else if (msg == WM_MSIME_RECONVERTOPTIONS) return "WM_MSIME_RECONVERTOPTIONS"; + else if (msg == WM_MSIME_MOUSE) return "WM_MSIME_MOUSE"; + else if (msg == WM_MSIME_RECONVERTREQUEST) return "WM_MSIME_RECONVERTREQUEST"; + else if (msg == WM_MSIME_RECONVERT) return "WM_MSIME_RECONVERT"; + else if (msg == WM_MSIME_QUERYPOSITION) return "WM_MSIME_QUERYPOSITION"; + else if (msg == WM_MSIME_DOCUMENTFEED) return "WM_MSIME_DOCUMENTFEED"; + return wine_dbg_sprintf( "%#x", msg ); + } +} From a37eecafa50530e9b202e3931722dc88fd12c05c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 1 Apr 2023 11:54:57 +0200 Subject: [PATCH 1840/2777] imm32: Call DefWindowProcW from IME UI for unhandled messages. (cherry picked from commit 617e24233b0bc4775fea58c9fe1c1672349de224) --- dlls/imm32/ime.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 42f19b7cb2b..a77dfbe09e1 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -246,7 +246,6 @@ static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LP { HIMC himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ); INPUTCONTEXT *ctx; - LRESULT ret = 0; TRACE( "hwnd %p, himc %p, msg %s, wparam %#Ix, lparam %#Ix\n", hwnd, himc, debugstr_wm_ime(msg), wparam, lparam ); @@ -288,8 +287,6 @@ static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LP case WM_PAINT: ime_ui_paint( himc, hwnd ); return FALSE; - case WM_NCCREATE: - return TRUE; case WM_SETFOCUS: if (wparam) SetFocus( (HWND)wparam ); else FIXME( "Received focus, should never have focus\n" ); @@ -313,12 +310,7 @@ static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LP return 1; } - /* DefWndProc if not an IME message */ - if (!ret && !((msg >= WM_IME_STARTCOMPOSITION && msg <= WM_IME_KEYLAST) || - (msg >= WM_IME_SETCONTEXT && msg <= WM_IME_KEYUP))) - ret = DefWindowProcW( hwnd, msg, wparam, lparam ); - - return ret; + return DefWindowProcW( hwnd, msg, wparam, lparam ); } static WNDCLASSEXW ime_ui_class = From 0029a3454ae68b184acf8766fe10766592a1f65b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 1 Apr 2023 21:37:23 +0200 Subject: [PATCH 1841/2777] imm32: Remove unnecessary HIMC check in IME UI window proc. (cherry picked from commit e04079160d6519bf06d8213350e26fd46dd2051d) --- dlls/imm32/ime.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index a77dfbe09e1..3c4550c3cd9 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -250,23 +250,6 @@ static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LP TRACE( "hwnd %p, himc %p, msg %s, wparam %#Ix, lparam %#Ix\n", hwnd, himc, debugstr_wm_ime(msg), wparam, lparam ); - /* if we have no himc there are many messages we cannot process */ - if (!himc) - { - switch (msg) - { - case WM_IME_STARTCOMPOSITION: - case WM_IME_ENDCOMPOSITION: - case WM_IME_COMPOSITION: - case WM_IME_NOTIFY: - case WM_IME_CONTROL: - case WM_IME_COMPOSITIONFULL: - case WM_IME_SELECT: - case WM_IME_CHAR: return 0L; - default: break; - } - } - switch (msg) { case WM_CREATE: From 74b97c796dce8d92e00f79f35b38c22416bffa80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 8 Apr 2023 08:53:26 +0200 Subject: [PATCH 1842/2777] imm32/tests: Reduce the number of IME installations. (cherry picked from commit 152d6e8b2760fc316b1fa06e97b225c536275a63) --- dlls/imm32/tests/imm32.c | 184 +++++++++++++++++---------------------- 1 file changed, 81 insertions(+), 103 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 82809f37f8e..f91902eb833 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2574,7 +2574,7 @@ static IMEINFO ime_info; static UINT ime_count; static WCHAR ime_path[MAX_PATH]; static HIMC default_himc; -static HKL default_hkl; +static HKL default_hkl, wineime_hkl; static HKL expect_ime = (HKL)(int)0xe020047f; enum ime_function @@ -3421,12 +3421,8 @@ static void test_ImmInstallIME(void) ret = ImmFreeLayout( hkl ); ok( ret, "ImmFreeLayout returned %#x\n", ret ); - ime_cleanup( hkl, FALSE ); - ime_info.fdwProperty = 0; - if (!(hkl = ime_install())) goto cleanup; - SET_EXPECT( IME_DLL_PROCESS_ATTACH ); SET_EXPECT( ImeInquire ); ret = ImmLoadIME( hkl ); @@ -3473,7 +3469,7 @@ static void test_ImmIsIME(void) /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ ime_info.fdwProperty = IME_PROP_END_UNLOAD; - if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup; todo_ImeInquire = TRUE; todo_ImeDestroy = TRUE; @@ -3485,8 +3481,6 @@ static void test_ImmIsIME(void) todo_ImeInquire = FALSE; todo_ImeDestroy = FALSE; - ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); SET_ENABLE( ImeInquire, FALSE ); @@ -3558,7 +3552,7 @@ static void test_ImmGetProperty(void) /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ ime_info.fdwProperty = IME_PROP_END_UNLOAD; - if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup; SET_EXPECT( ImeInquire ); SET_EXPECT( ImeDestroy ); @@ -3581,8 +3575,6 @@ static void test_ImmGetProperty(void) todo_ImeDestroy = FALSE; called_ImeDestroy = FALSE; - ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( ImeInquire, FALSE ); SET_ENABLE( ImeDestroy, FALSE ); @@ -3616,7 +3608,7 @@ static void test_ImmGetDescription(void) ret = GetLastError(); ok( ret == 0xdeadbeef, "got error %lu\n", ret ); - if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup; memset( bufferW, 0xcd, sizeof(bufferW) ); ret = ImmGetDescriptionW( hkl, bufferW, 2 ); @@ -3654,8 +3646,6 @@ static void test_ImmGetDescription(void) ok( ret == 12, "ImmGetDescriptionA returned %lu\n", ret ); ok( !strcmp( bufferA, "WineTest IME" ), "got bufferA %s\n", debugstr_a(bufferA) ); - ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); SET_ENABLE( ImeInquire, FALSE ); @@ -3691,7 +3681,7 @@ static void test_ImmGetIMEFileName(void) ret = GetLastError(); ok( ret == 0xdeadbeef, "got error %lu\n", ret ); - if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup; memset( bufferW, 0xcd, sizeof(bufferW) ); ret = ImmGetIMEFileNameW( hkl, bufferW, 2 ); @@ -3733,8 +3723,6 @@ static void test_ImmGetIMEFileName(void) ok( ret == 12, "ImmGetIMEFileNameA returned %lu\n", ret ); ok( !strcmp( bufferA, expectA ), "got bufferA %s\n", debugstr_a(bufferA) ); - ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( IME_DLL_PROCESS_ATTACH, FALSE ); SET_ENABLE( ImeInquire, FALSE ); @@ -3770,7 +3758,7 @@ static void test_ImmEscape( BOOL unicode ) ime_info.fdwProperty = IME_PROP_END_UNLOAD; if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE; - if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup; for (i = 0; i < ARRAY_SIZE(codes); ++i) { @@ -3841,8 +3829,6 @@ static void test_ImmEscape( BOOL unicode ) winetest_pop_context(); } - ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( ImeEscape, FALSE ); @@ -3891,7 +3877,7 @@ static void test_ImmEnumRegisterWord( BOOL unicode ) ime_info.fdwProperty = IME_PROP_END_UNLOAD; if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE; - if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup; SET_EXPECT( ImeEnumRegisterWord ); ok_ret( 0, ImmEnumRegisterWordW( hkl, enum_register_wordW, NULL, 0, NULL, NULL ) ); @@ -3909,8 +3895,6 @@ static void test_ImmEnumRegisterWord( BOOL unicode ) ok_ret( 0xdeadbeef, ImmEnumRegisterWordA( hkl, enum_register_wordA, "Reading", 0xdeadbeef, "String", NULL ) ); CHECK_CALLED( ImeEnumRegisterWord ); - ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( ImeEnumRegisterWord, FALSE ); @@ -3937,7 +3921,7 @@ static void test_ImmRegisterWord( BOOL unicode ) ime_info.fdwProperty = IME_PROP_END_UNLOAD; if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE; - if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup; SET_EXPECT( ImeRegisterWord ); ok_ret( 0, ImmRegisterWordW( hkl, NULL, 0, NULL ) ); @@ -3971,8 +3955,6 @@ static void test_ImmRegisterWord( BOOL unicode ) ok_ret( 0, ImmRegisterWordA( hkl, NULL, 0, "String" ) ); CHECK_CALLED( ImeRegisterWord ); - ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( ImeRegisterWord, FALSE ); @@ -4001,7 +3983,7 @@ static void test_ImmGetRegisterWordStyle( BOOL unicode ) ime_info.fdwProperty = IME_PROP_END_UNLOAD; if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE; - if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup; if (!strcmp( winetest_platform, "wine" )) goto skip_null; @@ -4048,8 +4030,6 @@ static void test_ImmGetRegisterWordStyle( BOOL unicode ) } CHECK_CALLED( ImeGetRegisterWordStyle ); - ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( ImeGetRegisterWordStyle, FALSE ); @@ -4076,7 +4056,7 @@ static void test_ImmUnregisterWord( BOOL unicode ) ime_info.fdwProperty = IME_PROP_END_UNLOAD; if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE; - if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup; SET_EXPECT( ImeUnregisterWord ); ok_ret( 0, ImmUnregisterWordW( hkl, NULL, 0, NULL ) ); @@ -4110,8 +4090,6 @@ static void test_ImmUnregisterWord( BOOL unicode ) ok_ret( 0, ImmUnregisterWordA( hkl, NULL, 0, "String" ) ); CHECK_CALLED( ImeUnregisterWord ); - ime_cleanup( hkl, FALSE ); - cleanup: SET_ENABLE( ImeUnregisterWord, FALSE ); @@ -4186,7 +4164,7 @@ static void test_ImmSetConversionStatus(void) {0}, }; DWORD old_conversion, old_sentence, conversion, sentence; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; INPUTCONTEXT *ctx; ok_ret( 0, ImmGetConversionStatus( 0, &old_conversion, &old_sentence ) ); @@ -4217,7 +4195,7 @@ static void test_ImmSetConversionStatus(void) ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; - if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup; ok_ret( 1, ImmActivateLayout( hkl ) ); ok_ret( 1, ImmLoadIME( hkl ) ); @@ -4282,17 +4260,17 @@ static void test_ImmSetConversionStatus(void) ok_eq( ~0, ctx->fdwSentence, UINT, "%#x" ); /* status is cached and some bits are kept from the previous active IME */ - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); todo_wine ok_eq( 0x200, ctx->fdwConversion, UINT, "%#x" ); ok_eq( old_sentence, ctx->fdwSentence, UINT, "%#x" ); ok_ret( 1, ImmActivateLayout( hkl ) ); todo_wine ok_eq( ~0, ctx->fdwConversion, UINT, "%#x" ); todo_wine ok_eq( ~0, ctx->fdwSentence, UINT, "%#x" ); - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); todo_wine ok_eq( 0x200, ctx->fdwConversion, UINT, "%#x" ); ok_eq( old_sentence, ctx->fdwSentence, UINT, "%#x" ); - ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); cleanup: /* sanitize conversion status to some sane default */ @@ -4357,7 +4335,7 @@ static void test_ImmSetOpenStatus(void) }, {0}, }; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; DWORD old_status, status; INPUTCONTEXT *ctx; @@ -4384,7 +4362,7 @@ static void test_ImmSetOpenStatus(void) ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; - if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup; ok_ret( 1, ImmActivateLayout( hkl ) ); ok_ret( 1, ImmLoadIME( hkl ) ); @@ -4439,7 +4417,7 @@ static void test_ImmSetOpenStatus(void) /* status is cached between IME activations */ - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); status = ImmGetOpenStatus( default_himc ); todo_wine ok_eq( old_status, status, UINT, "%#x" ); todo_wine ok_eq( old_status, ctx->fOpen, UINT, "%#x" ); @@ -4448,12 +4426,12 @@ static void test_ImmSetOpenStatus(void) todo_wine ok_eq( 1, status, UINT, "%#x" ); todo_wine ok_eq( 1, ctx->fOpen, UINT, "%#x" ); ok_ret( 1, ImmSetOpenStatus( default_himc, 0 ) ); - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); status = ImmGetOpenStatus( default_himc ); ok_eq( old_status, status, UINT, "%#x" ); ok_eq( old_status, ctx->fOpen, UINT, "%#x" ); - ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); cleanup: /* sanitize open status to some sane default */ @@ -4480,7 +4458,7 @@ static void test_ImmProcessKey(void) }, {0}, }; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; UINT_PTR ret; hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, @@ -4488,12 +4466,12 @@ static void test_ImmProcessKey(void) ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); process_messages(); - ok_ret( 0, ImmProcessKey( hwnd, old_hkl, 'A', 0, 0 ) ); + ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'A', 0, 0 ) ); ok_seq( empty_sequence ); ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; - if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup; ok_ret( 1, ImmActivateLayout( hkl ) ); ok_ret( 1, ImmLoadIME( hkl ) ); @@ -4510,13 +4488,13 @@ static void test_ImmProcessKey(void) ok_seq( process_key_seq ); ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); - ok_ret( 0, ImmProcessKey( hwnd, old_hkl, 'A', 0, 0 ) ); + ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'A', 0, 0 ) ); ok_seq( empty_sequence ); ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); - ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); process_messages(); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; @@ -4650,7 +4628,7 @@ static void test_ImmActivateLayout(void) }, {0}, }; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; struct ime_windows ime_windows = {0}; HIMC himc; UINT ret; @@ -4658,20 +4636,20 @@ static void test_ImmActivateLayout(void) SET_ENABLE( ImeInquire, TRUE ); SET_ENABLE( ImeDestroy, TRUE ); - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; - if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup; /* ActivateKeyboardLayout doesn't call ImeInquire / ImeDestroy */ ok_seq( empty_sequence ); - ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); + ok_eq( default_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); - ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); + ok_eq( hkl, ActivateKeyboardLayout( default_hkl, 0 ), HKL, "%p" ); ok_seq( empty_sequence ); - ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); /* ImmActivateLayout changes active HKL */ @@ -4688,14 +4666,11 @@ static void test_ImmActivateLayout(void) ok_seq( empty_sequence ); todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_seq( deactivate_seq ); todo_ImeDestroy = FALSE; - ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); - - ime_cleanup( hkl, FALSE ); - ok_seq( empty_sequence ); + ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); /* ImmActivateLayout leaks the IME, we need to free it manually */ @@ -4709,8 +4684,6 @@ static void test_ImmActivateLayout(void) /* when there's a window, ActivateKeyboardLayout calls ImeInquire */ - if (!(hkl = ime_install())) goto cleanup; - hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); @@ -4722,7 +4695,7 @@ static void test_ImmActivateLayout(void) ok_seq( empty_sequence ); SET_EXPECT( ImeInquire ); - ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); + ok_eq( default_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); CHECK_CALLED( ImeInquire ); activate_with_window_seq[1].himc = himc; ok_seq( activate_with_window_seq ); @@ -4738,20 +4711,20 @@ static void test_ImmActivateLayout(void) ime_call_count = 0; todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ - ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); + ok_eq( hkl, ActivateKeyboardLayout( default_hkl, 0 ), HKL, "%p" ); todo_ImeDestroy = FALSE; deactivate_with_window_seq[1].himc = himc; deactivate_with_window_seq[5].himc = himc; ok_seq( deactivate_with_window_seq ); - ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); ok_ret( 1, ImmDestroyContext( himc ) ); ok_seq( empty_sequence ); todo_ImeInquire = TRUE; - ok_eq( old_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); + ok_eq( default_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); todo_ImeInquire = FALSE; ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); @@ -4761,13 +4734,14 @@ static void test_ImmActivateLayout(void) ok_ret( (UINT_PTR)ime_windows.ime_hwnd, (UINT_PTR)GetParent( ime_windows.ime_ui_hwnd ) ); todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ - ok_eq( hkl, ActivateKeyboardLayout( old_hkl, 0 ), HKL, "%p" ); + ok_eq( hkl, ActivateKeyboardLayout( default_hkl, 0 ), HKL, "%p" ); todo_ImeDestroy = FALSE; - ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + process_messages(); SET_EXPECT( ImeDestroy ); - ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); CHECK_CALLED( ImeDestroy ); ok_ret( 1, DestroyWindow( hwnd ) ); @@ -4875,7 +4849,7 @@ static void test_ImmCreateInputContext(void) }, {0}, }; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; INPUTCONTEXT *ctx; HIMC himc[2]; HWND hwnd; @@ -4912,7 +4886,7 @@ static void test_ImmCreateInputContext(void) ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; ime_info.dwPrivateDataSize = 123; - if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup; ok_ret( 1, ImmLoadIME( hkl ) ); @@ -4956,14 +4930,14 @@ static void test_ImmCreateInputContext(void) /* Deactivating the layout calls ImeSelect 0 on existing HIMC */ - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); deactivate_seq[1].himc = himc[0]; deactivate_seq[5].himc = himc[0]; ok_seq( deactivate_seq ); - ok_eq( old_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); - ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); ok_seq( empty_sequence ); cleanup: @@ -5003,12 +4977,12 @@ static void test_DefWindowProc(void) {.hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY}}, {0}, }; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; UINT_PTR ret; ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; - if (!(hkl = ime_install())) return; + if (!(hkl = wineime_hkl)) return; hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); @@ -5051,11 +5025,11 @@ static void test_DefWindowProc(void) ok_ret( 0, ret ); ok_seq( empty_sequence ); - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_ret( 1, DestroyWindow( hwnd ) ); process_messages(); - ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; } @@ -5129,12 +5103,12 @@ static void test_ImmSetActiveContext(void) }, {0}, }; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; HIMC himc; ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; - if (!(hkl = ime_install())) return; + if (!(hkl = wineime_hkl)) return; hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); @@ -5166,11 +5140,11 @@ static void test_ImmSetActiveContext(void) ok_seq( activate_1_seq ); ok_ret( 1, ImmDestroyContext( himc ) ); - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_ret( 1, DestroyWindow( hwnd ) ); process_messages(); - ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; } @@ -5233,7 +5207,7 @@ static void test_ImmRequestMessage(void) }, {0}, }; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; COMPOSITIONFORM comp_form = {0}; IMECHARPOSITION char_pos = {0}; RECONVERTSTRING reconv = {0}; @@ -5242,7 +5216,7 @@ static void test_ImmRequestMessage(void) INPUTCONTEXT *ctx; HIMC himc; - if (!(hkl = ime_install())) return; + if (!(hkl = wineime_hkl)) return; hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); @@ -5301,11 +5275,11 @@ static void test_ImmRequestMessage(void) ok_ret( 1, ImmUnlockIMC( himc ) ); ok_ret( 1, ImmDestroyContext( himc ) ); - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_ret( 1, DestroyWindow( hwnd ) ); process_messages(); - ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; } @@ -5314,7 +5288,7 @@ static void test_ImmGetCandidateList( BOOL unicode ) { char buffer[512], expect_bufW[512] = {0}, expect_bufA[512] = {0}; CANDIDATELIST *cand_list = (CANDIDATELIST *)buffer, *expect_listW, *expect_listA; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; CANDIDATEINFO *cand_info; INPUTCONTEXT *ctx; HIMC himc; @@ -5349,7 +5323,7 @@ static void test_ImmGetCandidateList( BOOL unicode ) ime_info.fdwProperty = IME_PROP_END_UNLOAD; if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE; - if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup; hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); @@ -5426,11 +5400,11 @@ static void test_ImmGetCandidateList( BOOL unicode ) ok_ret( 1, ImmUnlockIMC( himc ) ); ok_ret( 1, ImmDestroyContext( himc ) ); - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_ret( 1, DestroyWindow( hwnd ) ); process_messages(); - ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; @@ -5440,7 +5414,7 @@ static void test_ImmGetCandidateList( BOOL unicode ) static void test_ImmGetCandidateListCount( BOOL unicode ) { - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; CANDIDATEINFO *cand_info; INPUTCONTEXT *ctx; DWORD count; @@ -5452,7 +5426,7 @@ static void test_ImmGetCandidateListCount( BOOL unicode ) ime_info.fdwProperty = IME_PROP_END_UNLOAD; if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE; - if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup; hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); @@ -5499,11 +5473,11 @@ static void test_ImmGetCandidateListCount( BOOL unicode ) ok_ret( 1, ImmUnlockIMC( himc ) ); ok_ret( 1, ImmDestroyContext( himc ) ); - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_ret( 1, DestroyWindow( hwnd ) ); process_messages(); - ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; @@ -5513,7 +5487,7 @@ static void test_ImmGetCandidateListCount( BOOL unicode ) static void test_ImmGetCandidateWindow(void) { - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; const CANDIDATEFORM expect_form = { .dwIndex = 0xdeadbeef, @@ -5527,7 +5501,7 @@ static void test_ImmGetCandidateWindow(void) ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; - if (!(hkl = ime_install())) return; + if (!(hkl = wineime_hkl)) return; hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); @@ -5576,11 +5550,11 @@ static void test_ImmGetCandidateWindow(void) ok_ret( 1, ImmUnlockIMC( himc ) ); ok_ret( 1, ImmDestroyContext( himc ) ); - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_ret( 1, DestroyWindow( hwnd ) ); process_messages(); - ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; } @@ -5667,7 +5641,7 @@ static void test_ImmGetCompositionString( BOOL unicode ) }; static const UINT expect_retW[ARRAY_SIZE(gcs_indexes)] = {16, 8, 8, 8, 4, 8, 3, 1, 20, 8, 12, 8}; static const UINT expect_retA[ARRAY_SIZE(gcs_indexes)] = {8, 8, 8, 4, 4, 8, 3, 1, 10, 8, 6, 8}; - HKL hkl, old_hkl = GetKeyboardLayout( 0 ); + HKL hkl; COMPOSITIONSTRING *string; char buffer[1024]; INPUTCONTEXT *old_ctx, *ctx; @@ -5685,7 +5659,7 @@ static void test_ImmGetCompositionString( BOOL unicode ) ime_info.fdwProperty = IME_PROP_END_UNLOAD; if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE; - if (!(hkl = ime_install())) goto cleanup; + if (!(hkl = wineime_hkl)) goto cleanup; hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); @@ -5930,7 +5904,7 @@ static void test_ImmGetCompositionString( BOOL unicode ) ok_ret( 1, ImmUnlockIMC( himc ) ); /* composition strings are kept between IME selections */ - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ctx = ImmLockIMC( himc ); ok_eq( old_ctx, ctx, INPUTCONTEXT *, "%p" ); ok_eq( old_himcc, ctx->hCompStr, HIMCC, "%p" ); @@ -5941,18 +5915,18 @@ static void test_ImmGetCompositionString( BOOL unicode ) ok_ret( 1, ImmActivateLayout( hkl ) ); ok_eq( old_himcc, ctx->hCompStr, HIMCC, "%p" ); check_composition_string( string, &expect_string_empty ); - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_eq( old_himcc, ctx->hCompStr, HIMCC, "%p" ); check_composition_string( string, &expect_string_empty ); ok_ret( 1, ImmUnlockIMC( himc ) ); ok_ret( 1, ImmDestroyContext( himc ) ); - ok_ret( 1, ImmActivateLayout( old_hkl ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_ret( 1, DestroyWindow( hwnd ) ); process_messages(); - ime_cleanup( hkl, TRUE ); + ok_ret( 1, ImmFreeLayout( hkl ) ); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; @@ -5979,6 +5953,8 @@ START_TEST(imm32) test_ImmEnumInputContext(); test_ImmInstallIME(); + wineime_hkl = ime_install(); + test_ImmGetDescription(); test_ImmGetIMEFileName(); test_ImmIsIME(); @@ -6016,6 +5992,8 @@ START_TEST(imm32) test_ImmGetCompositionString( TRUE ); test_ImmGetCompositionString( FALSE ); + if (wineime_hkl) ime_cleanup( wineime_hkl, TRUE ); + if (init()) { test_ImmNotifyIME(); From dbd0f02625c7f3114e2f046154cd9ff3f94a9fa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 8 Apr 2023 09:36:41 +0200 Subject: [PATCH 1843/2777] imm32/tests: Cleanup the cross thread IMC tests. (cherry picked from commit ff08b083fd25b29cd2d8c965bfec58efebcaa1c7) --- dlls/imm32/tests/imm32.c | 535 +++++++++++++++++++++++---------------- 1 file changed, 311 insertions(+), 224 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index f91902eb833..827a1326e3e 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -986,248 +986,335 @@ static void test_NtUserAssociateInputContext(void) ImmReleaseContext(hwnd,imc); } -typedef struct _igc_threadinfo { +struct test_cross_thread_himc_params +{ HWND hwnd; HANDLE event; - HIMC himc; - HIMC u_himc; -} igc_threadinfo; - + HIMC himc[2]; + INPUTCONTEXT *contexts[2]; +}; -static DWORD WINAPI ImmGetContextThreadFunc( LPVOID lpParam) +static DWORD WINAPI test_cross_thread_himc_thread( void *arg ) { - HIMC h1,h2; - HWND hwnd2; - COMPOSITIONFORM cf; - CANDIDATEFORM cdf; - POINT pt; + CANDIDATEFORM candidate = {.dwIndex = 1, .dwStyle = CFS_CANDIDATEPOS}; + struct test_cross_thread_himc_params *params = arg; + COMPOSITIONFORM composition = {0}; + INPUTCONTEXT *contexts[2]; + HIMC himc[2], tmp_himc; + HWND hwnd, tmp_hwnd; + POINT pos = {0}; MSG msg; - igc_threadinfo *info= (igc_threadinfo*)lpParam; - info->hwnd = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", - WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, - 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); - - h1 = ImmGetContext(hwnd); - ok(info->himc == h1, "hwnd context changed in new thread\n"); - h2 = ImmGetContext(info->hwnd); - ok(h2 != h1, "new hwnd in new thread should have different context\n"); - info->himc = h2; - ImmReleaseContext(hwnd,h1); - - hwnd2 = CreateWindowExA(WS_EX_CLIENTEDGE, wndcls, "Wine imm32.dll test", - WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, - 240, 120, NULL, NULL, GetModuleHandleW(NULL), NULL); - h1 = ImmGetContext(hwnd2); + hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok_ne( NULL, hwnd, HWND, "%p" ); + himc[0] = ImmGetContext( hwnd ); + ok_ne( NULL, himc[0], HIMC, "%p" ); + contexts[0] = ImmLockIMC( himc[0] ); + ok_ne( NULL, contexts[0], INPUTCONTEXT *, "%p" ); + + tmp_hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + tmp_himc = ImmGetContext( tmp_hwnd ); + ok_eq( himc[0], tmp_himc, HIMC, "%p" ); + ok_ret( 1, ImmReleaseContext( tmp_hwnd, tmp_himc ) ); + ok_ret( 1, DestroyWindow( tmp_hwnd ) ); - ok(h1 == h2, "Windows in same thread should have same default context\n"); - ImmReleaseContext(hwnd2,h1); - ImmReleaseContext(info->hwnd,h2); - DestroyWindow(hwnd2); + himc[1] = ImmCreateContext(); + ok_ne( NULL, himc[1], HIMC, "%p" ); + contexts[1] = ImmLockIMC( himc[1] ); + ok_ne( NULL, contexts[1], INPUTCONTEXT *, "%p" ); + + ok_ret( 1, ImmSetOpenStatus( himc[0], 0xdeadbeef ) ); + ok_ret( 1, ImmSetOpenStatus( himc[1], 0xfeedcafe ) ); + ok_ret( 1, ImmSetCompositionWindow( himc[0], &composition ) ); + ok_ret( 1, ImmSetCompositionWindow( himc[1], &composition ) ); + ok_ret( 1, ImmSetCandidateWindow( himc[0], &candidate ) ); + ok_ret( 1, ImmSetCandidateWindow( himc[1], &candidate ) ); + ok_ret( 1, ImmSetStatusWindowPos( himc[0], &pos ) ); + ok_ret( 1, ImmSetStatusWindowPos( himc[1], &pos ) ); + + params->hwnd = hwnd; + params->himc[0] = himc[0]; + params->himc[1] = himc[1]; + params->contexts[0] = contexts[0]; + params->contexts[1] = contexts[1]; + SetEvent( params->event ); + + while (GetMessageW( &msg, 0, 0, 0 )) + { + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } - /* priming for later tests */ - ImmSetCompositionWindow(h1, &cf); - ImmSetStatusWindowPos(h1, &pt); - info->u_himc = ImmCreateContext(); - ImmSetOpenStatus(info->u_himc, TRUE); - cdf.dwIndex = 0; - cdf.dwStyle = CFS_CANDIDATEPOS; - cdf.ptCurrentPos.x = 0; - cdf.ptCurrentPos.y = 0; - ImmSetCandidateWindow(info->u_himc, &cdf); + ok_ret( 1, ImmUnlockIMC( himc[0] ) ); + ok_ret( 1, ImmUnlockIMC( himc[1] ) ); - SetEvent(info->event); + ok_ret( 1, ImmDestroyContext( himc[1] ) ); + ok_ret( 1, ImmReleaseContext( hwnd, himc[0] ) ); + ok_ret( 0, DestroyWindow( hwnd ) ); - while(GetMessageW(&msg, 0, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } return 1; } -static void test_ImmThreads(void) +static void test_cross_thread_himc(void) { - HIMC himc, otherHimc, h1; - igc_threadinfo threadinfo; - HANDLE hThread; - DWORD dwThreadId; - BOOL rc; - LOGFONTA lf; - COMPOSITIONFORM cf; - CANDIDATEFORM cdf; - DWORD status, sentence; - POINT pt; + static const WCHAR comp_string[] = L"CompString"; + struct test_cross_thread_himc_params params; + COMPOSITIONFORM composition = {0}; + DWORD tid, conversion, sentence; + CANDIDATEFORM candidate = {0}; + COMPOSITIONSTRING *string; + HIMC himc[2], tmp_himc; + INPUTCONTEXT *tmp_ctx; + LOGFONTW fontW = {0}; + LOGFONTA fontA = {0}; + char buffer[512]; + POINT pos = {0}; + HANDLE thread; + BYTE *dst; + UINT ret; - himc = ImmGetContext(hwnd); - threadinfo.event = CreateEventA(NULL, TRUE, FALSE, NULL); - threadinfo.himc = himc; - hThread = CreateThread(NULL, 0, ImmGetContextThreadFunc, &threadinfo, 0, &dwThreadId ); - WaitForSingleObject(threadinfo.event, INFINITE); + himc[0] = ImmGetContext( hwnd ); + ok_ne( NULL, himc[0], HIMC, "%p" ); + ok_ne( NULL, ImmLockIMC( himc[0] ), INPUTCONTEXT *, "%p" ); + ok_ret( 1, ImmUnlockIMC( himc[0] ) ); - otherHimc = ImmGetContext(threadinfo.hwnd); + params.event = CreateEventW(NULL, TRUE, FALSE, NULL); + ok_ne( NULL, params.event, HANDLE, "%p" ); + thread = CreateThread( NULL, 0, test_cross_thread_himc_thread, ¶ms, 0, &tid ); + ok_ne( NULL, thread, HANDLE, "%p" ); + WaitForSingleObject( params.event, INFINITE ); - ok(himc != otherHimc, "Windows from other threads should have different himc\n"); - ok(otherHimc == threadinfo.himc, "Context from other thread should not change in main thread\n"); + tmp_himc = ImmGetContext( params.hwnd ); + ok_ne( himc[0], tmp_himc, HIMC, "%p" ); + ok_eq( params.himc[0], tmp_himc, HIMC, "%p" ); + ok_ret( 1, ImmReleaseContext( params.hwnd, tmp_himc ) ); - SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE, TRUE); - SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE, TRUE); - SET_EXPECT(WM_IME_SETCONTEXT_ACTIVATE); - rc = ImmSetActiveContext(hwnd, otherHimc, TRUE); - ok(rc, "ImmSetActiveContext failed\n"); - CHECK_CALLED(WM_IME_SETCONTEXT_ACTIVATE); - SET_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE); - rc = ImmSetActiveContext(hwnd, otherHimc, FALSE); - ok(rc, "ImmSetActiveContext failed\n"); - CHECK_CALLED(WM_IME_SETCONTEXT_DEACTIVATE); - SET_ENABLE(WM_IME_SETCONTEXT_DEACTIVATE, FALSE); - SET_ENABLE(WM_IME_SETCONTEXT_ACTIVATE, FALSE); + himc[1] = ImmCreateContext(); + ok_ne( NULL, himc[1], HIMC, "%p" ); + tmp_ctx = ImmLockIMC( himc[1] ); + ok_ne( NULL, tmp_ctx, INPUTCONTEXT *, "%p" ); + + tmp_ctx->hCompStr = ImmReSizeIMCC( tmp_ctx->hCompStr, 512 ); + ok_ne( NULL, tmp_ctx->hCompStr, HIMCC, "%p" ); + string = ImmLockIMCC( tmp_ctx->hCompStr ); + ok_ne( NULL, string, COMPOSITIONSTRING *, "%p" ); + string->dwSize = sizeof(COMPOSITIONSTRING); + string->dwCompStrLen = wcslen( comp_string ); + string->dwCompStrOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompStrOffset; + memcpy( dst, comp_string, string->dwCompStrLen * sizeof(WCHAR) ); + string->dwSize += string->dwCompStrLen * sizeof(WCHAR); - h1 = ImmAssociateContext(hwnd,otherHimc); - ok(h1 == NULL, "Should fail to be able to Associate a default context from a different thread\n"); - h1 = ImmGetContext(hwnd); - ok(h1 == himc, "Context for window should remain unchanged\n"); - ImmReleaseContext(hwnd,h1); - - h1 = ImmAssociateContext(hwnd, threadinfo.u_himc); - ok (h1 == NULL, "Should fail to associate a context from a different thread\n"); - h1 = ImmGetContext(hwnd); - ok(h1 == himc, "Context for window should remain unchanged\n"); - ImmReleaseContext(hwnd,h1); - - h1 = ImmAssociateContext(threadinfo.hwnd, threadinfo.u_himc); - ok (h1 == NULL, "Should fail to associate a context from a different thread into a window from that thread.\n"); - h1 = ImmGetContext(threadinfo.hwnd); - ok(h1 == threadinfo.himc, "Context for window should remain unchanged\n"); - ImmReleaseContext(threadinfo.hwnd,h1); - - /* OpenStatus */ - rc = ImmSetOpenStatus(himc, TRUE); - ok(rc != 0, "ImmSetOpenStatus failed\n"); - rc = ImmGetOpenStatus(himc); - ok(rc != 0, "ImmGetOpenStatus failed\n"); - rc = ImmSetOpenStatus(himc, FALSE); - ok(rc != 0, "ImmSetOpenStatus failed\n"); - rc = ImmGetOpenStatus(himc); - ok(rc == 0, "ImmGetOpenStatus failed\n"); - - rc = ImmSetOpenStatus(otherHimc, TRUE); - ok(rc == 0, "ImmSetOpenStatus should fail\n"); - rc = ImmSetOpenStatus(threadinfo.u_himc, TRUE); - ok(rc == 0, "ImmSetOpenStatus should fail\n"); - rc = ImmGetOpenStatus(otherHimc); - ok(rc == 0, "ImmGetOpenStatus failed\n"); - rc = ImmGetOpenStatus(threadinfo.u_himc); - ok (rc == 1 || broken(rc == 0), "ImmGetOpenStatus should return 1\n"); - rc = ImmSetOpenStatus(otherHimc, FALSE); - ok(rc == 0, "ImmSetOpenStatus should fail\n"); - rc = ImmGetOpenStatus(otherHimc); - ok(rc == 0, "ImmGetOpenStatus failed\n"); - - /* CompositionFont */ - rc = ImmGetCompositionFontA(himc, &lf); - ok(rc != 0, "ImmGetCompositionFont failed\n"); - rc = ImmSetCompositionFontA(himc, &lf); - ok(rc != 0, "ImmSetCompositionFont failed\n"); - - rc = ImmGetCompositionFontA(otherHimc, &lf); - ok(rc != 0 || broken(rc == 0), "ImmGetCompositionFont failed\n"); - rc = ImmGetCompositionFontA(threadinfo.u_himc, &lf); - ok(rc != 0 || broken(rc == 0), "ImmGetCompositionFont user himc failed\n"); - rc = ImmSetCompositionFontA(otherHimc, &lf); - ok(rc == 0, "ImmSetCompositionFont should fail\n"); - rc = ImmSetCompositionFontA(threadinfo.u_himc, &lf); - ok(rc == 0, "ImmSetCompositionFont should fail\n"); - - /* CompositionWindow */ - rc = ImmSetCompositionWindow(himc, &cf); - ok(rc != 0, "ImmSetCompositionWindow failed\n"); - rc = ImmGetCompositionWindow(himc, &cf); - ok(rc != 0, "ImmGetCompositionWindow failed\n"); - - rc = ImmSetCompositionWindow(otherHimc, &cf); - ok(rc == 0, "ImmSetCompositionWindow should fail\n"); - rc = ImmSetCompositionWindow(threadinfo.u_himc, &cf); - ok(rc == 0, "ImmSetCompositionWindow should fail\n"); - rc = ImmGetCompositionWindow(otherHimc, &cf); - ok(rc != 0 || broken(rc == 0), "ImmGetCompositionWindow failed\n"); - rc = ImmGetCompositionWindow(threadinfo.u_himc, &cf); - ok(rc != 0 || broken(rc == 0), "ImmGetCompositionWindow failed\n"); - - /* ConversionStatus */ - rc = ImmGetConversionStatus(himc, &status, &sentence); - ok(rc != 0, "ImmGetConversionStatus failed\n"); - rc = ImmSetConversionStatus(himc, status, sentence); - ok(rc != 0, "ImmSetConversionStatus failed\n"); - - rc = ImmGetConversionStatus(otherHimc, &status, &sentence); - ok(rc != 0 || broken(rc == 0), "ImmGetConversionStatus failed\n"); - rc = ImmGetConversionStatus(threadinfo.u_himc, &status, &sentence); - ok(rc != 0 || broken(rc == 0), "ImmGetConversionStatus failed\n"); - rc = ImmSetConversionStatus(otherHimc, status, sentence); - ok(rc == 0, "ImmSetConversionStatus should fail\n"); - rc = ImmSetConversionStatus(threadinfo.u_himc, status, sentence); - ok(rc == 0, "ImmSetConversionStatus should fail\n"); - - /* StatusWindowPos */ - rc = ImmSetStatusWindowPos(himc, &pt); - ok(rc != 0, "ImmSetStatusWindowPos failed\n"); - rc = ImmGetStatusWindowPos(himc, &pt); - ok(rc != 0, "ImmGetStatusWindowPos failed\n"); - - rc = ImmSetStatusWindowPos(otherHimc, &pt); - ok(rc == 0, "ImmSetStatusWindowPos should fail\n"); - rc = ImmSetStatusWindowPos(threadinfo.u_himc, &pt); - ok(rc == 0, "ImmSetStatusWindowPos should fail\n"); - rc = ImmGetStatusWindowPos(otherHimc, &pt); - ok(rc != 0 || broken(rc == 0), "ImmGetStatusWindowPos failed\n"); - rc = ImmGetStatusWindowPos(threadinfo.u_himc, &pt); - ok(rc != 0 || broken(rc == 0), "ImmGetStatusWindowPos failed\n"); - - h1 = ImmAssociateContext(threadinfo.hwnd, NULL); - ok (h1 == otherHimc, "ImmAssociateContext cross thread with NULL should work\n"); - h1 = ImmGetContext(threadinfo.hwnd); - ok (h1 == NULL, "CrossThread window context should be NULL\n"); - h1 = ImmAssociateContext(threadinfo.hwnd, h1); - ok (h1 == NULL, "Resetting cross thread context should fail\n"); - h1 = ImmGetContext(threadinfo.hwnd); - ok (h1 == NULL, "CrossThread window context should still be NULL\n"); - - rc = ImmDestroyContext(threadinfo.u_himc); - ok (rc == 0, "ImmDestroyContext Cross Thread should fail\n"); - - /* Candidate Window */ - rc = ImmGetCandidateWindow(himc, 0, &cdf); - ok (rc == 0, "ImmGetCandidateWindow should fail\n"); - cdf.dwIndex = 0; - cdf.dwStyle = CFS_CANDIDATEPOS; - cdf.ptCurrentPos.x = 0; - cdf.ptCurrentPos.y = 0; - rc = ImmSetCandidateWindow(himc, &cdf); - ok (rc == 1, "ImmSetCandidateWindow should succeed\n"); - rc = ImmGetCandidateWindow(himc, 0, &cdf); - ok (rc == 1, "ImmGetCandidateWindow should succeed\n"); - - rc = ImmGetCandidateWindow(otherHimc, 0, &cdf); - ok (rc == 0, "ImmGetCandidateWindow should fail\n"); - rc = ImmSetCandidateWindow(otherHimc, &cdf); - ok (rc == 0, "ImmSetCandidateWindow should fail\n"); - rc = ImmGetCandidateWindow(threadinfo.u_himc, 0, &cdf); - ok (rc == 1 || broken( rc == 0), "ImmGetCandidateWindow should succeed\n"); - rc = ImmSetCandidateWindow(threadinfo.u_himc, &cdf); - ok (rc == 0, "ImmSetCandidateWindow should fail\n"); - - ImmReleaseContext(threadinfo.hwnd,otherHimc); - ImmReleaseContext(hwnd,himc); - - SendMessageA(threadinfo.hwnd, WM_CLOSE, 0, 0); - rc = PostThreadMessageA(dwThreadId, WM_QUIT, 1, 0); - ok(rc == 1, "PostThreadMessage should succeed\n"); - WaitForSingleObject(hThread, INFINITE); - CloseHandle(hThread); - - himc = ImmGetContext(GetDesktopWindow()); - ok(himc == NULL, "Should not be able to get himc from other process window\n"); + string->dwCompClauseLen = 2 * sizeof(DWORD); + string->dwCompClauseOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompClauseOffset; + *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0; + *(DWORD *)(dst + 1 * sizeof(DWORD)) = string->dwCompStrLen; + string->dwSize += 2 * sizeof(DWORD); + + string->dwCompAttrLen = string->dwCompStrLen; + string->dwCompAttrOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompAttrOffset; + memset( dst, ATTR_INPUT, string->dwCompStrLen ); + string->dwSize += string->dwCompStrLen; + ok_ret( 0, ImmUnlockIMCC( tmp_ctx->hCompStr ) ); + + ok_ret( 1, ImmUnlockIMC( himc[1] ) ); + + /* ImmLockIMC should succeed with cross thread HIMC */ + + tmp_ctx = ImmLockIMC( params.himc[0] ); + ok_eq( params.contexts[0], tmp_ctx, INPUTCONTEXT *, "%p" ); + ret = ImmGetIMCLockCount( params.himc[0] ); + ok( ret >= 2, "got ret %u\n", ret ); + + tmp_ctx->hCompStr = ImmReSizeIMCC( tmp_ctx->hCompStr, 512 ); + ok_ne( NULL, tmp_ctx->hCompStr, HIMCC, "%p" ); + string = ImmLockIMCC( tmp_ctx->hCompStr ); + ok_ne( NULL, string, COMPOSITIONSTRING *, "%p" ); + string->dwSize = sizeof(COMPOSITIONSTRING); + string->dwCompStrLen = wcslen( comp_string ); + string->dwCompStrOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompStrOffset; + memcpy( dst, comp_string, string->dwCompStrLen * sizeof(WCHAR) ); + string->dwSize += string->dwCompStrLen * sizeof(WCHAR); + + string->dwCompClauseLen = 2 * sizeof(DWORD); + string->dwCompClauseOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompClauseOffset; + *(DWORD *)(dst + 0 * sizeof(DWORD)) = 0; + *(DWORD *)(dst + 1 * sizeof(DWORD)) = string->dwCompStrLen; + string->dwSize += 2 * sizeof(DWORD); + + string->dwCompAttrLen = string->dwCompStrLen; + string->dwCompAttrOffset = string->dwSize; + dst = (BYTE *)string + string->dwCompAttrOffset; + memset( dst, ATTR_INPUT, string->dwCompStrLen ); + string->dwSize += string->dwCompStrLen; + ok_ret( 0, ImmUnlockIMCC( tmp_ctx->hCompStr ) ); + + ok_ret( 1, ImmUnlockIMC( params.himc[0] ) ); + + tmp_ctx = ImmLockIMC( params.himc[1] ); + ok_eq( params.contexts[1], tmp_ctx, INPUTCONTEXT *, "%p" ); + ret = ImmGetIMCLockCount( params.himc[1] ); + ok( ret >= 2, "got ret %u\n", ret ); + ok_ret( 1, ImmUnlockIMC( params.himc[1] ) ); + + /* ImmSetActiveContext should succeed with cross thread HIMC */ + + SET_ENABLE( WM_IME_SETCONTEXT_DEACTIVATE, TRUE ); + SET_ENABLE( WM_IME_SETCONTEXT_ACTIVATE, TRUE ); + + SET_EXPECT( WM_IME_SETCONTEXT_ACTIVATE ); + ok_ret( 1, ImmSetActiveContext( hwnd, params.himc[0], TRUE ) ); + CHECK_CALLED( WM_IME_SETCONTEXT_ACTIVATE ); + + SET_EXPECT( WM_IME_SETCONTEXT_DEACTIVATE ); + ok_ret( 1, ImmSetActiveContext( hwnd, params.himc[0], FALSE ) ); + CHECK_CALLED( WM_IME_SETCONTEXT_DEACTIVATE ); + + SET_ENABLE( WM_IME_SETCONTEXT_DEACTIVATE, FALSE ); + SET_ENABLE( WM_IME_SETCONTEXT_ACTIVATE, FALSE ); + + /* ImmSetOpenStatus should fail with cross thread HIMC */ + + ok_ret( 1, ImmSetOpenStatus( himc[1], 0xdeadbeef ) ); + ok_ret( (int)0xdeadbeef, ImmGetOpenStatus( himc[1] ) ); + + ok_ret( 0, ImmSetOpenStatus( params.himc[0], TRUE ) ); + ok_ret( 0, ImmSetOpenStatus( params.himc[1], TRUE ) ); + ok_ret( (int)0xdeadbeef, ImmGetOpenStatus( params.himc[0] ) ); + ok_ret( (int)0xfeedcafe, ImmGetOpenStatus( params.himc[1] ) ); + ok_ret( 0, ImmSetOpenStatus( params.himc[0], FALSE ) ); + ok_ret( (int)0xdeadbeef, ImmGetOpenStatus( params.himc[0] ) ); + + /* ImmSetConversionStatus should fail with cross thread HIMC */ + + ok_ret( 1, ImmGetConversionStatus( himc[1], &conversion, &sentence ) ); + ok_ret( 1, ImmSetConversionStatus( himc[1], conversion, sentence ) ); + + ok_ret( 1, ImmGetConversionStatus( params.himc[0], &conversion, &sentence ) ); + ok_ret( 1, ImmGetConversionStatus( params.himc[1], &conversion, &sentence ) ); + ok_ret( 0, ImmSetConversionStatus( params.himc[0], conversion, sentence ) ); + ok_ret( 0, ImmSetConversionStatus( params.himc[1], conversion, sentence ) ); + + /* ImmSetCompositionFont(W|A) should fail with cross thread HIMC */ + + ok_ret( 1, ImmSetCompositionFontA( himc[1], &fontA ) ); + ok_ret( 1, ImmGetCompositionFontA( himc[1], &fontA ) ); + ok_ret( 1, ImmSetCompositionFontW( himc[1], &fontW ) ); + ok_ret( 1, ImmGetCompositionFontW( himc[1], &fontW ) ); + + ok_ret( 0, ImmSetCompositionFontA( params.himc[0], &fontA ) ); + ok_ret( 0, ImmSetCompositionFontA( params.himc[1], &fontA ) ); + ok_ret( 1, ImmGetCompositionFontA( params.himc[0], &fontA ) ); + ok_ret( 1, ImmGetCompositionFontA( params.himc[1], &fontA ) ); + ok_ret( 0, ImmSetCompositionFontW( params.himc[0], &fontW ) ); + ok_ret( 0, ImmSetCompositionFontW( params.himc[1], &fontW ) ); + ok_ret( 1, ImmGetCompositionFontW( params.himc[0], &fontW ) ); + ok_ret( 1, ImmGetCompositionFontW( params.himc[1], &fontW ) ); + + /* ImmSetCompositionString(W|A) should fail with cross thread HIMC */ + + ok_ret( 10, ImmGetCompositionStringA( himc[1], GCS_COMPSTR, buffer, sizeof(buffer) ) ); + ok_ret( 20, ImmGetCompositionStringW( himc[1], GCS_COMPSTR, buffer, sizeof(buffer) ) ); + ok_ret( 1, ImmSetCompositionStringA( himc[1], SCS_SETSTR, "a", 2, NULL, 0 ) ); + ok_ret( 1, ImmSetCompositionStringW( himc[1], SCS_SETSTR, L"a", 4, NULL, 0 ) ); + + ok_ret( 0, ImmSetCompositionStringA( params.himc[0], SCS_SETSTR, "a", 2, NULL, 0 ) ); + ok_ret( 0, ImmSetCompositionStringA( params.himc[1], SCS_SETSTR, "a", 2, NULL, 0 ) ); + ok_ret( 0, ImmSetCompositionStringW( params.himc[0], SCS_SETSTR, L"a", 4, NULL, 0 ) ); + ok_ret( 0, ImmSetCompositionStringW( params.himc[1], SCS_SETSTR, L"a", 4, NULL, 0 ) ); + ok_ret( 10, ImmGetCompositionStringA( params.himc[0], GCS_COMPSTR, buffer, sizeof(buffer) ) ); + ok_ret( 0, ImmGetCompositionStringA( params.himc[1], GCS_COMPSTR, buffer, sizeof(buffer) ) ); + ok_ret( 20, ImmGetCompositionStringW( params.himc[0], GCS_COMPSTR, buffer, sizeof(buffer) ) ); + ok_ret( 0, ImmGetCompositionStringW( params.himc[1], GCS_COMPSTR, buffer, sizeof(buffer) ) ); + + /* ImmSetCompositionWindow should fail with cross thread HIMC */ + + ok_ret( 1, ImmSetCompositionWindow( himc[1], &composition ) ); + ok_ret( 1, ImmGetCompositionWindow( himc[1], &composition ) ); + + ok_ret( 0, ImmSetCompositionWindow( params.himc[0], &composition ) ); + ok_ret( 0, ImmSetCompositionWindow( params.himc[1], &composition ) ); + ok_ret( 1, ImmGetCompositionWindow( params.himc[0], &composition ) ); + ok_ret( 1, ImmGetCompositionWindow( params.himc[1], &composition ) ); + + /* ImmSetCandidateWindow should fail with cross thread HIMC */ + + ok_ret( 1, ImmSetCandidateWindow( himc[1], &candidate ) ); + ok_ret( 1, ImmGetCandidateWindow( himc[1], 0, &candidate ) ); + + ok_ret( 1, ImmGetCandidateWindow( params.himc[0], 1, &candidate ) ); + ok_ret( 1, ImmGetCandidateWindow( params.himc[1], 1, &candidate ) ); + ok_ret( 0, ImmSetCandidateWindow( params.himc[0], &candidate ) ); + ok_ret( 0, ImmSetCandidateWindow( params.himc[1], &candidate ) ); + + /* ImmSetStatusWindowPos should fail with cross thread HIMC */ + + ok_ret( 1, ImmSetStatusWindowPos( himc[1], &pos ) ); + ok_ret( 1, ImmGetStatusWindowPos( himc[1], &pos ) ); + + ok_ret( 0, ImmSetStatusWindowPos( params.himc[0], &pos ) ); + ok_ret( 0, ImmSetStatusWindowPos( params.himc[1], &pos ) ); + ok_ret( 1, ImmGetStatusWindowPos( params.himc[0], &pos ) ); + ok_ret( 1, ImmGetStatusWindowPos( params.himc[1], &pos ) ); + + /* ImmGenerateMessage should fail with cross thread HIMC */ + + ok_ret( 1, ImmGenerateMessage( himc[1] ) ); + + todo_wine ok_ret( 0, ImmGenerateMessage( params.himc[0] ) ); + todo_wine ok_ret( 0, ImmGenerateMessage( params.himc[1] ) ); + + /* ImmAssociateContext should fail with cross thread HWND or HIMC */ + + tmp_himc = ImmAssociateContext( hwnd, params.himc[0] ); + ok_eq( NULL, tmp_himc, HIMC, "%p" ); + tmp_himc = ImmGetContext( hwnd ); + ok_eq( himc[0], tmp_himc, HIMC, "%p" ); + ok_ret( 1, ImmReleaseContext( hwnd, tmp_himc ) ); + + tmp_himc = ImmAssociateContext( hwnd, params.himc[1] ); + ok_eq( NULL, tmp_himc, HIMC, "%p" ); + tmp_himc = ImmGetContext( hwnd ); + ok_eq( himc[0], tmp_himc, HIMC, "%p" ); + ok_ret( 1, ImmReleaseContext( hwnd, tmp_himc ) ); + + tmp_himc = ImmAssociateContext( params.hwnd, params.himc[1] ); + ok_eq( NULL, tmp_himc, HIMC, "%p" ); + tmp_himc = ImmGetContext( params.hwnd ); + ok_eq( params.himc[0], tmp_himc, HIMC, "%p" ); + ok_ret( 1, ImmReleaseContext( params.hwnd, tmp_himc ) ); + + /* ImmAssociateContext should succeed with cross thread HWND and NULL HIMC */ + + tmp_himc = ImmAssociateContext( params.hwnd, NULL ); + ok_eq( params.himc[0], tmp_himc, HIMC, "%p" ); + tmp_himc = ImmGetContext( params.hwnd ); + ok_eq( NULL, tmp_himc, HIMC, "%p" ); + + /* ImmReleaseContext / ImmDestroyContext should fail with cross thread HIMC */ + + ok_ret( 1, ImmReleaseContext( params.hwnd, params.himc[0] ) ); + ok_ret( 0, ImmDestroyContext( params.himc[1] ) ); + + /* ImmGetContext should fail with another process HWND */ + + tmp_himc = ImmGetContext( GetDesktopWindow() ); + ok_eq( NULL, tmp_himc, HIMC, "%p" ); + + ok_ret( 0, SendMessageW( params.hwnd, WM_CLOSE, 0, 0 ) ); + ok_ret( 1, PostThreadMessageW( tid, WM_QUIT, 1, 0 ) ); + ok_ret( 0, WaitForSingleObject( thread, 5000 ) ); + ok_ret( 1, CloseHandle( thread ) ); + ok_ret( 1, CloseHandle( params.event ) ); + + ok_ret( 1, ImmReleaseContext( hwnd, himc[0] ) ); + ok_ret( 1, ImmDestroyContext( himc[1] ) ); } static void test_ImmIsUIMessage(void) @@ -6001,7 +6088,7 @@ START_TEST(imm32) test_ImmIME(); test_ImmAssociateContextEx(); test_NtUserAssociateInputContext(); - test_ImmThreads(); + test_cross_thread_himc(); test_ImmIsUIMessage(); test_ImmGetContext(); test_ImmDefaultHwnd(); From b95b20a4768dc519a505c002d06cd887169af122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 3 Apr 2023 11:33:24 +0200 Subject: [PATCH 1844/2777] imm32: Serialize ImeInquire / ImeDestroy calls. (cherry picked from commit 3cd1dc5273b9118e54ac113b52336da0f17e5f32) --- dlls/imm32/imm.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 25d1df47a1c..268d9142732 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -441,11 +441,14 @@ BOOL WINAPI ImmFreeLayout( HKL hkl ) EnterCriticalSection( &ime_cs ); if ((ime = find_ime_from_hkl( hkl )) && ime->refcount) ime = NULL; - if (ime) list_remove( &ime->entry ); + if (ime) + { + list_remove( &ime->entry ); + if (!ime->pImeDestroy( 0 )) WARN( "ImeDestroy failed\n" ); + } LeaveCriticalSection( &ime_cs ); if (!ime) return TRUE; - if (!ime->pImeDestroy( 0 )) WARN( "ImeDestroy failed\n" ); FreeLibrary( ime->module ); free( ime ); return TRUE; @@ -460,12 +463,11 @@ BOOL WINAPI ImmLoadIME( HKL hkl ) TRACE( "hkl %p\n", hkl ); EnterCriticalSection( &ime_cs ); - ime = find_ime_from_hkl( hkl ); - LeaveCriticalSection( &ime_cs ); - if (ime) return TRUE; - - if (!(ime = calloc( 1, sizeof(*ime) ))) return FALSE; - ime->hkl = hkl; + if ((ime = find_ime_from_hkl( hkl )) || !(ime = calloc( 1, sizeof(*ime) ))) + { + LeaveCriticalSection( &ime_cs ); + return !!ime; + } if (!ImmGetIMEFileNameW( hkl, buffer, MAX_PATH )) use_default_ime = TRUE; else if (!(ime->module = LoadLibraryW( buffer ))) use_default_ime = TRUE; @@ -481,6 +483,7 @@ BOOL WINAPI ImmLoadIME( HKL hkl ) if (!(ime->p##f = (void *)GetProcAddress( ime->module, #f )) && \ !(ime->p##f = use_default_ime ? (void *)f : NULL)) \ { \ + LeaveCriticalSection( &ime_cs ); \ WARN( "Can't find function %s in HKL %p IME\n", #f, hkl ); \ goto failed; \ } @@ -502,12 +505,16 @@ BOOL WINAPI ImmLoadIME( HKL hkl ) LOAD_FUNCPTR( ImeGetImeMenuItems ); #undef LOAD_FUNCPTR - if (!ime->pImeInquire( &ime->info, buffer, 0 )) goto failed; + ime->hkl = hkl; + if (!ime->pImeInquire( &ime->info, buffer, 0 )) + { + LeaveCriticalSection( &ime_cs ); + goto failed; + } if (ime_is_unicode( ime )) lstrcpynW( ime->ui_class, buffer, ARRAY_SIZE(ime->ui_class) ); else MultiByteToWideChar( CP_ACP, 0, (char *)buffer, -1, ime->ui_class, ARRAY_SIZE(ime->ui_class) ); - EnterCriticalSection( &ime_cs ); list_add_tail( &ime_list, &ime->entry ); LeaveCriticalSection( &ime_cs ); From 65020d639b40025fb19777da1b42f1c7ecc19a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 7 Apr 2023 21:27:00 +0200 Subject: [PATCH 1845/2777] imm32: Use INPUTCONTEXT directly in ImmGetOpenStatus. (cherry picked from commit 0af582947632fd827bd0edeb348aa29162e3c470) --- dlls/imm32/imm.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 268d9142732..753213b623f 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1919,20 +1919,18 @@ UINT WINAPI ImmGetIMEFileNameW( HKL hkl, WCHAR *buffer, UINT length ) /*********************************************************************** * ImmGetOpenStatus (IMM32.@) */ -BOOL WINAPI ImmGetOpenStatus(HIMC hIMC) +BOOL WINAPI ImmGetOpenStatus( HIMC himc ) { - struct imc *data = get_imc_data( hIMC ); - static int i; + INPUTCONTEXT *ctx; + BOOL status; - if (!data) - return FALSE; - - TRACE("(%p): semi-stub\n", hIMC); + TRACE( "himc %p\n", himc ); - if (!i++) - FIXME("(%p): semi-stub\n", hIMC); + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + status = ctx->fOpen; + ImmUnlockIMC( himc ); - return data->IMC.fOpen; + return status; } /*********************************************************************** From b9f3a4452f113f896cace04ddde25280f9505012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 3 Apr 2023 17:39:21 +0200 Subject: [PATCH 1846/2777] imm32: Use INPUTCONTEXT directly in ImmSetOpenStatus. (cherry picked from commit 374db20a5d011ad909a61d6857ead7a6261231ec) --- dlls/imm32/imm.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 753213b623f..a17869a1c94 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2605,30 +2605,27 @@ BOOL WINAPI ImmSetConversionStatus( /*********************************************************************** * ImmSetOpenStatus (IMM32.@) */ -BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) +BOOL WINAPI ImmSetOpenStatus( HIMC himc, BOOL status ) { - struct imc *data = get_imc_data( hIMC ); + INPUTCONTEXT *ctx; HWND ui_hwnd; - TRACE("%p %d\n", hIMC, fOpen); - - if (!data) - { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } + TRACE( "himc %p, status %u\n", himc, status ); - if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + if (!(ctx = ImmLockIMC( himc ))) return FALSE; - if ((ui_hwnd = get_ime_ui_window())) SetWindowLongPtrW( ui_hwnd, IMMGWL_IMC, (LONG_PTR)hIMC ); + if ((ui_hwnd = get_ime_ui_window())) SetWindowLongPtrW( ui_hwnd, IMMGWL_IMC, (LONG_PTR)himc ); - if (!fOpen != !data->IMC.fOpen) + if (!status != !ctx->fOpen) { - data->IMC.fOpen = fOpen; - ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS); - imc_notify_ime( data, IMN_SETOPENSTATUS, 0 ); + ctx->fOpen = status; + ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS ); + SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETOPENSTATUS, 0 ); } + ImmUnlockIMC( himc ); + return TRUE; } From 3b803cd3dfe0cc51f0c8f65a90105f6308d3592e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 7 Apr 2023 19:47:26 +0200 Subject: [PATCH 1847/2777] imm32: Cache INPUTCONTEXT values for every IME. (cherry picked from commit 6e51928ae5fbd7a7d199e2d12f25b3206e8cd94b) --- dlls/imm32/imm.c | 89 ++++++++++++++++++++++++++++++++++++---- dlls/imm32/tests/imm32.c | 18 ++------ 2 files changed, 84 insertions(+), 23 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index a17869a1c94..81444ad420c 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -39,6 +39,13 @@ UINT WM_MSIME_RECONVERT; UINT WM_MSIME_QUERYPOSITION; UINT WM_MSIME_DOCUMENTFEED; +struct imc_entry +{ + HIMC himc; + INPUTCONTEXT context; + struct list entry; +}; + struct ime { LONG refcount; /* guarded by ime_cs */ @@ -49,6 +56,7 @@ struct ime IMEINFO info; WCHAR ui_class[17]; + struct list input_contexts; BOOL (WINAPI *pImeInquire)(IMEINFO *, void *, DWORD); BOOL (WINAPI *pImeConfigure)(HKL, HWND, DWORD, void *); @@ -435,16 +443,21 @@ static struct ime *find_ime_from_hkl( HKL hkl ) BOOL WINAPI ImmFreeLayout( HKL hkl ) { + struct imc_entry *imc_entry, *imc_next; struct ime *ime; TRACE( "hkl %p\n", hkl ); EnterCriticalSection( &ime_cs ); - if ((ime = find_ime_from_hkl( hkl )) && ime->refcount) ime = NULL; - if (ime) + if ((ime = find_ime_from_hkl( hkl ))) { list_remove( &ime->entry ); if (!ime->pImeDestroy( 0 )) WARN( "ImeDestroy failed\n" ); + LIST_FOR_EACH_ENTRY_SAFE( imc_entry, imc_next, &ime->input_contexts, struct imc_entry, entry ) + { + ImmDestroyIMCC( imc_entry->context.hPrivate ); + free( imc_entry ); + } } LeaveCriticalSection( &ime_cs ); if (!ime) return TRUE; @@ -514,6 +527,7 @@ BOOL WINAPI ImmLoadIME( HKL hkl ) if (ime_is_unicode( ime )) lstrcpynW( ime->ui_class, buffer, ARRAY_SIZE(ime->ui_class) ); else MultiByteToWideChar( CP_ACP, 0, (char *)buffer, -1, ime->ui_class, ARRAY_SIZE(ime->ui_class) ); + list_init( &ime->input_contexts ); list_add_tail( &ime_list, &ime->entry ); LeaveCriticalSection( &ime_cs ); @@ -562,13 +576,63 @@ static void ime_release( struct ime *ime ) LeaveCriticalSection( &ime_cs ); } +static void ime_save_input_context( struct ime *ime, HIMC himc, INPUTCONTEXT *ctx ) +{ + static INPUTCONTEXT default_input_context = + { + .cfCandForm = {{.dwIndex = -1}, {.dwIndex = -1}, {.dwIndex = -1}, {.dwIndex = -1}} + }; + const INPUTCONTEXT old = *ctx; + struct imc_entry *entry; + + *ctx = default_input_context; + ctx->hWnd = old.hWnd; + ctx->hMsgBuf = old.hMsgBuf; + ctx->hCompStr = old.hCompStr; + ctx->hCandInfo = old.hCandInfo; + ctx->hGuideLine = old.hGuideLine; + if (!(ctx->hPrivate = ImmCreateIMCC( ime->info.dwPrivateDataSize ))) + WARN( "Failed to allocate IME private data\n" ); + + if (!(entry = malloc( sizeof(*entry) ))) return; + entry->himc = himc; + entry->context = *ctx; + + EnterCriticalSection( &ime_cs ); + + /* reference the IME the first time the input context cache is used + * in the same way Windows does it, so it doesn't get destroyed and + * INPUTCONTEXT cache lost when keyboard layout is changed + */ + if (list_empty( &ime->input_contexts )) ime->refcount++; + + list_add_tail( &ime->input_contexts, &entry->entry ); + LeaveCriticalSection( &ime_cs ); +} + +static INPUTCONTEXT *ime_find_input_context( struct ime *ime, HIMC himc ) +{ + struct imc_entry *entry; + + EnterCriticalSection( &ime_cs ); + LIST_FOR_EACH_ENTRY( entry, &ime->input_contexts, struct imc_entry, entry ) + if (entry->himc == himc) break; + LeaveCriticalSection( &ime_cs ); + + if (&entry->entry == &ime->input_contexts) return NULL; + return &entry->context; +} + static void imc_release_ime( struct imc *imc, struct ime *ime ) { + INPUTCONTEXT *ctx; + if (imc->ui_hwnd) DestroyWindow( imc->ui_hwnd ); imc->ui_hwnd = NULL; ime->pImeSelect( imc->handle, FALSE ); + + if ((ctx = ime_find_input_context( ime, imc->handle ))) *ctx = imc->IMC; ime_release( ime ); - ImmDestroyIMCC( imc->IMC.hPrivate ); } static struct ime *imc_select_ime( struct imc *imc ) @@ -587,10 +651,11 @@ static struct ime *imc_select_ime( struct imc *imc ) WARN( "Failed to acquire IME for HKL %p\n", hkl ); else { - if (!(imc->IMC.hPrivate = ImmCreateIMCC( imc->ime->info.dwPrivateDataSize ))) - WARN( "Failed to allocate IME private data for IMC %p\n", imc ); - imc->IMC.fdwConversion = imc->ime->info.fdwConversionCaps; - imc->IMC.fdwSentence = imc->ime->info.fdwSentenceCaps; + INPUTCONTEXT *ctx; + + if ((ctx = ime_find_input_context( imc->ime, imc->handle ))) imc->IMC = *ctx; + else ime_save_input_context( imc->ime, imc->handle, &imc->IMC ); + imc->ime->pImeSelect( imc->handle, TRUE ); } @@ -690,14 +755,20 @@ static void IMM_FreeThreadData(void) static void IMM_FreeAllImmHkl(void) { - struct ime *ime, *next; + struct ime *ime, *ime_next; - LIST_FOR_EACH_ENTRY_SAFE( ime, next, &ime_list, struct ime, entry ) + LIST_FOR_EACH_ENTRY_SAFE( ime, ime_next, &ime_list, struct ime, entry ) { + struct imc_entry *imc_entry, *imc_next; list_remove( &ime->entry ); ime->pImeDestroy( 1 ); FreeLibrary( ime->module ); + LIST_FOR_EACH_ENTRY_SAFE( imc_entry, imc_next, &ime->input_contexts, struct imc_entry, entry ) + { + ImmDestroyIMCC( imc_entry->context.hPrivate ); + free( imc_entry ); + } free( ime ); } diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 827a1326e3e..88b167c701d 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4351,8 +4351,8 @@ static void test_ImmSetConversionStatus(void) todo_wine ok_eq( 0x200, ctx->fdwConversion, UINT, "%#x" ); ok_eq( old_sentence, ctx->fdwSentence, UINT, "%#x" ); ok_ret( 1, ImmActivateLayout( hkl ) ); - todo_wine ok_eq( ~0, ctx->fdwConversion, UINT, "%#x" ); - todo_wine ok_eq( ~0, ctx->fdwSentence, UINT, "%#x" ); + ok_eq( ~0, ctx->fdwConversion, UINT, "%#x" ); + ok_eq( ~0, ctx->fdwSentence, UINT, "%#x" ); ok_ret( 1, ImmActivateLayout( default_hkl ) ); todo_wine ok_eq( 0x200, ctx->fdwConversion, UINT, "%#x" ); ok_eq( old_sentence, ctx->fdwSentence, UINT, "%#x" ); @@ -4506,8 +4506,8 @@ static void test_ImmSetOpenStatus(void) ok_ret( 1, ImmActivateLayout( default_hkl ) ); status = ImmGetOpenStatus( default_himc ); - todo_wine ok_eq( old_status, status, UINT, "%#x" ); - todo_wine ok_eq( old_status, ctx->fOpen, UINT, "%#x" ); + ok_eq( old_status, status, UINT, "%#x" ); + ok_eq( old_status, ctx->fOpen, UINT, "%#x" ); ok_ret( 1, ImmActivateLayout( hkl ) ); status = ImmGetOpenStatus( default_himc ); todo_wine ok_eq( 1, status, UINT, "%#x" ); @@ -4752,10 +4752,8 @@ static void test_ImmActivateLayout(void) ok_ret( 1, ImmActivateLayout( hkl ) ); ok_seq( empty_sequence ); - todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_seq( deactivate_seq ); - todo_ImeDestroy = FALSE; ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); @@ -4786,9 +4784,7 @@ static void test_ImmActivateLayout(void) CHECK_CALLED( ImeInquire ); activate_with_window_seq[1].himc = himc; ok_seq( activate_with_window_seq ); - todo_ImeInquire = TRUE; ok_ret( 1, ImmLoadIME( hkl ) ); - todo_ImeInquire = FALSE; ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); @@ -4797,9 +4793,7 @@ static void test_ImmActivateLayout(void) memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; - todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ ok_eq( hkl, ActivateKeyboardLayout( default_hkl, 0 ), HKL, "%p" ); - todo_ImeDestroy = FALSE; deactivate_with_window_seq[1].himc = himc; deactivate_with_window_seq[5].himc = himc; ok_seq( deactivate_with_window_seq ); @@ -4810,9 +4804,7 @@ static void test_ImmActivateLayout(void) ok_seq( empty_sequence ); - todo_ImeInquire = TRUE; ok_eq( default_hkl, ActivateKeyboardLayout( hkl, 0 ), HKL, "%p" ); - todo_ImeInquire = FALSE; ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) ); @@ -4820,9 +4812,7 @@ static void test_ImmActivateLayout(void) ok( !!ime_windows.ime_ui_hwnd, "missing IME UI window\n" ); ok_ret( (UINT_PTR)ime_windows.ime_hwnd, (UINT_PTR)GetParent( ime_windows.ime_ui_hwnd ) ); - todo_ImeDestroy = TRUE; /* Wine doesn't leak the IME */ ok_eq( hkl, ActivateKeyboardLayout( default_hkl, 0 ), HKL, "%p" ); - todo_ImeDestroy = FALSE; ok_eq( default_hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); process_messages(); From 662583d7bea9174ebbcd25a6e143ce8ece88a61d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 6 Apr 2023 00:54:42 +0200 Subject: [PATCH 1848/2777] imm32: Compare open status values in ImmSetOpenStatus. (cherry picked from commit 26d2d2c438d9e5f66212b22dc2d29b7881e9ad09) --- dlls/imm32/imm.c | 2 +- dlls/imm32/tests/imm32.c | 16 ++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 81444ad420c..c99feb65a45 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2688,7 +2688,7 @@ BOOL WINAPI ImmSetOpenStatus( HIMC himc, BOOL status ) if ((ui_hwnd = get_ime_ui_window())) SetWindowLongPtrW( ui_hwnd, IMMGWL_IMC, (LONG_PTR)himc ); - if (!status != !ctx->fOpen) + if (status != ctx->fOpen) { ctx->fOpen = status; ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETOPENSTATUS ); diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 88b167c701d..8c6d441181b 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4399,7 +4399,6 @@ static void test_ImmSetOpenStatus(void) { .hkl = expect_ime, .himc = default_himc, .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS}, - .todo = TRUE, }, {0}, }; @@ -4408,17 +4407,14 @@ static void test_ImmSetOpenStatus(void) { .hkl = expect_ime, .himc = default_himc, .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETOPENSTATUS}, - .todo = TRUE, }, { .hkl = expect_ime, .himc = default_himc, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS}, - .todo = TRUE, }, { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETOPENSTATUS}, - .todo = TRUE, }, {0}, }; @@ -4483,8 +4479,8 @@ static void test_ImmSetOpenStatus(void) ok_seq( set_open_status_1_seq ); status = ImmGetOpenStatus( default_himc ); - todo_wine ok_eq( 0xfeedcafe, status, UINT, "%#x" ); - todo_wine ok_eq( 0xfeedcafe, ctx->fOpen, UINT, "%#x" ); + ok_eq( 0xfeedcafe, status, UINT, "%#x" ); + ok_eq( 0xfeedcafe, ctx->fOpen, UINT, "%#x" ); ctx->hWnd = hwnd; ok_seq( empty_sequence ); @@ -4492,15 +4488,15 @@ static void test_ImmSetOpenStatus(void) ok_seq( set_open_status_2_seq ); status = ImmGetOpenStatus( default_himc ); - todo_wine ok_eq( ~0, status, UINT, "%#x" ); - todo_wine ok_eq( ~0, ctx->fOpen, UINT, "%#x" ); + ok_eq( ~0, status, UINT, "%#x" ); + ok_eq( ~0, ctx->fOpen, UINT, "%#x" ); ok_ret( 1, ImmSetOpenStatus( default_himc, ~0 ) ); ok_seq( empty_sequence ); status = ImmGetOpenStatus( default_himc ); - todo_wine ok_eq( ~0, status, UINT, "%#x" ); - todo_wine ok_eq( ~0, ctx->fOpen, UINT, "%#x" ); + ok_eq( ~0, status, UINT, "%#x" ); + ok_eq( ~0, ctx->fOpen, UINT, "%#x" ); /* status is cached between IME activations */ From 3774dccde4ff039a0d5fadeda4270eab886deae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 7 Apr 2023 21:43:27 +0200 Subject: [PATCH 1849/2777] imm32: Use INPUTCONTEXT directly in ImmGetConversionStatus. (cherry picked from commit 67ddc3146cb847e3161567a870230bba13d9c3f5) --- dlls/imm32/imm.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index c99feb65a45..b2dc58a95ab 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1844,20 +1844,16 @@ DWORD WINAPI ImmGetConversionListW( HKL hkl, HIMC himc, const WCHAR *srcW, CANDI /*********************************************************************** * ImmGetConversionStatus (IMM32.@) */ -BOOL WINAPI ImmGetConversionStatus( - HIMC hIMC, LPDWORD lpfdwConversion, LPDWORD lpfdwSentence) +BOOL WINAPI ImmGetConversionStatus( HIMC himc, DWORD *conversion, DWORD *sentence ) { - struct imc *data = get_imc_data( hIMC ); + INPUTCONTEXT *ctx; - TRACE("%p %p %p\n", hIMC, lpfdwConversion, lpfdwSentence); + TRACE( "himc %p, conversion %p, sentence %p\n", himc, conversion, sentence ); - if (!data) - return FALSE; - - if (lpfdwConversion) - *lpfdwConversion = data->IMC.fdwConversion; - if (lpfdwSentence) - *lpfdwSentence = data->IMC.fdwSentence; + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + if (conversion) *conversion = ctx->fdwConversion; + if (sentence) *sentence = ctx->fdwSentence; + ImmUnlockIMC( himc ); return TRUE; } From b92fafb9d74f35f876153dceb98516d5dc2918f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 6 Apr 2023 01:01:37 +0200 Subject: [PATCH 1850/2777] imm32: Use INPUTCONTEXT directly in ImmSetConversionStatus. (cherry picked from commit 1cd71e92be6ed57621ea545fcfbd46da7cfe7b58) --- dlls/imm32/imm.c | 41 +++++++++++++++++++--------------------- dlls/imm32/tests/imm32.c | 1 - 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index b2dc58a95ab..d29684f34a2 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2635,37 +2635,34 @@ BOOL WINAPI ImmSetCompositionWindow( /*********************************************************************** * ImmSetConversionStatus (IMM32.@) */ -BOOL WINAPI ImmSetConversionStatus( - HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence) +BOOL WINAPI ImmSetConversionStatus( HIMC himc, DWORD conversion, DWORD sentence ) { - DWORD oldConversion, oldSentence; - struct imc *data = get_imc_data( hIMC ); - - TRACE("%p %ld %ld\n", hIMC, fdwConversion, fdwSentence); + DWORD old_conversion, old_sentence; + INPUTCONTEXT *ctx; - if (!data) - { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } + TRACE( "himc %p, conversion %#lx, sentence %#lx\n", himc, conversion, sentence ); - if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + if (!(ctx = ImmLockIMC( himc ))) return FALSE; - if ( fdwConversion != data->IMC.fdwConversion ) + if (conversion != ctx->fdwConversion) { - oldConversion = data->IMC.fdwConversion; - data->IMC.fdwConversion = fdwConversion; - ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldConversion, IMC_SETCONVERSIONMODE); - imc_notify_ime( data, IMN_SETCONVERSIONMODE, 0 ); + old_conversion = ctx->fdwConversion; + ctx->fdwConversion = conversion; + ImmNotifyIME( himc, NI_CONTEXTUPDATED, old_conversion, IMC_SETCONVERSIONMODE ); + SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCONVERSIONMODE, 0 ); } - if ( fdwSentence != data->IMC.fdwSentence ) + + if (sentence != ctx->fdwSentence) { - oldSentence = data->IMC.fdwSentence; - data->IMC.fdwSentence = fdwSentence; - ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, oldSentence, IMC_SETSENTENCEMODE); - imc_notify_ime( data, IMN_SETSENTENCEMODE, 0 ); + old_sentence = ctx->fdwSentence; + ctx->fdwSentence = sentence; + ImmNotifyIME( himc, NI_CONTEXTUPDATED, old_sentence, IMC_SETSENTENCEMODE ); + SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETSENTENCEMODE, 0 ); } + ImmUnlockIMC( himc ); + return TRUE; } diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 8c6d441181b..bbfae7e65d1 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4219,7 +4219,6 @@ static void test_ImmSetConversionStatus(void) .hkl = expect_ime, .himc = default_himc, .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0xdeadbeef, .value = IMC_SETCONVERSIONMODE}, }, - {.todo = TRUE}, /* spurious calls */ {0}, }; const struct ime_call set_conversion_status_2_seq[] = From ace83d75fd18fe1a607222515701b5ed00a2c120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 13 Apr 2023 10:41:51 +0200 Subject: [PATCH 1851/2777] include: Add INPUTCONTEXT fdwInit flags definitions. (cherry picked from commit e1645155491c4195d970c59af5ce3832613db20e) --- include/immdev.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/immdev.h b/include/immdev.h index 92f2a47c167..4141e9350c0 100644 --- a/include/immdev.h +++ b/include/immdev.h @@ -134,6 +134,13 @@ DWORD WINAPI ImmGetIMCCSize(HIMCC); #define IMMGWL_IMC 0 #define IMMGWL_PRIVATE (sizeof(LONG_PTR)) +#define INIT_STATUSWNDPOS 0x00000001 +#define INIT_CONVERSION 0x00000002 +#define INIT_SENTENCE 0x00000004 +#define INIT_LOGFONT 0x00000008 +#define INIT_COMPFORM 0x00000010 +#define INIT_SOFTKBDPOS 0x00000020 + /* IME Property bits */ #define IME_PROP_END_UNLOAD 0x0001 #define IME_PROP_KBD_CHAR_FIRST 0x0002 From 98e21180b345e9fde623c77d869e1b426a983bb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 13 Apr 2023 10:01:15 +0200 Subject: [PATCH 1852/2777] imm32/tests: Add some Imm(Get|Set)CompositionWindow tests. (cherry picked from commit 7a3991913b8b3339282f9835d2361c2c3f0a2ce6) --- dlls/imm32/tests/imm32.c | 113 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index bbfae7e65d1..c3c68d1e91b 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -168,6 +168,14 @@ static void check_candidate_form_( int line, CANDIDATEFORM *form, const CANDIDAT check_member_rect_( __FILE__, line, *form, *expect, rcArea ); } +#define check_composition_form( a, b ) check_composition_form_( __LINE__, a, b ) +static void check_composition_form_( int line, COMPOSITIONFORM *form, const COMPOSITIONFORM *expect ) +{ + check_member_( __FILE__, line, *form, *expect, "%#lx", dwStyle ); + check_member_point_( __FILE__, line, *form, *expect, ptCurrentPos ); + check_member_rect_( __FILE__, line, *form, *expect, rcArea ); +} + #define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE, enabled_ ## func = FALSE @@ -6007,6 +6015,110 @@ static void test_ImmGetCompositionString( BOOL unicode ) SET_ENABLE( ImeSetCompositionString, FALSE ); } +static void test_ImmSetCompositionWindow(void) +{ + struct ime_call set_composition_window_0_seq[] = + { + { + .hkl = expect_ime, .himc = 0/*himc*/, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCOMPOSITIONWINDOW}, + .todo = TRUE + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCOMPOSITIONWINDOW}, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCOMPOSITIONWINDOW}, + }, + {0}, + }; + struct ime_call set_composition_window_1_seq[] = + { + { + .hkl = expect_ime, .himc = 0/*himc*/, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCOMPOSITIONWINDOW}, + .todo = TRUE + }, + {.todo = TRUE}, + }; + COMPOSITIONFORM comp_form, expect_form = + { + .dwStyle = 0xfeedcafe, + .ptCurrentPos = {.x = 123, .y = 456}, + .rcArea = {.left = 1, .top = 2, .right = 3, .bottom = 4}, + }; + INPUTCONTEXT *ctx; + HIMC himc; + HKL hkl; + + ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; + + if (!(hkl = wineime_hkl)) return; + + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + set_composition_window_0_seq[0].himc = himc; + set_composition_window_1_seq[0].himc = himc; + + ctx->cfCompForm = expect_form; + ctx->fdwInit = ~INIT_COMPFORM; + memset( &comp_form, 0xcd, sizeof(comp_form) ); + todo_wine ok_ret( 0, ImmGetCompositionWindow( himc, &comp_form ) ); + todo_wine ok_eq( 0xcdcdcdcd, comp_form.dwStyle, UINT, "%#x" ); + ctx->fdwInit = INIT_COMPFORM; + ok_ret( 1, ImmGetCompositionWindow( himc, &comp_form ) ); + check_composition_form( &comp_form, &expect_form ); + ok_seq( empty_sequence ); + + ctx->hWnd = hwnd; + ctx->fdwInit = 0; + memset( &comp_form, 0xcd, sizeof(comp_form) ); + ok_ret( 1, ImmSetCompositionWindow( himc, &comp_form ) ); + ok_seq( set_composition_window_0_seq ); + todo_wine ok_eq( INIT_COMPFORM, ctx->fdwInit, UINT, "%u" ); + check_composition_form( &ctx->cfCompForm, &comp_form ); + + ok_ret( 1, ImmSetCompositionWindow( himc, &expect_form ) ); + ok_seq( set_composition_window_0_seq ); + check_composition_form( &ctx->cfCompForm, &expect_form ); + + ctx->cfCompForm = expect_form; + ok_ret( 1, ImmGetCompositionWindow( himc, &comp_form ) ); + check_composition_form( &comp_form, &expect_form ); + ok_seq( empty_sequence ); + + ctx->hWnd = 0; + memset( &comp_form, 0xcd, sizeof(comp_form) ); + ok_ret( 1, ImmSetCompositionWindow( himc, &comp_form ) ); + ok_seq( set_composition_window_1_seq ); + check_composition_form( &ctx->cfCompForm, &comp_form ); + + ok_ret( 1, ImmUnlockIMC( himc ) ); + ok_ret( 1, ImmDestroyContext( himc ) ); + + ok_ret( 1, ImmActivateLayout( default_hkl ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + + ok_ret( 1, ImmFreeLayout( hkl ) ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); @@ -6063,6 +6175,7 @@ START_TEST(imm32) test_ImmGetCompositionString( TRUE ); test_ImmGetCompositionString( FALSE ); + test_ImmSetCompositionWindow(); if (wineime_hkl) ime_cleanup( wineime_hkl, TRUE ); From 1411abb9474a498366b117f350959ee47074ce24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 30 Mar 2023 23:25:29 +0200 Subject: [PATCH 1853/2777] imm32/tests: Add some Imm(Get|Set)StatusWindowPos tests. (cherry picked from commit f35cb95d5f4a918234f5d7b837eea6c99d79ed40) --- dlls/imm32/tests/imm32.c | 99 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index c3c68d1e91b..60ecf7b050b 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -6119,6 +6119,104 @@ static void test_ImmSetCompositionWindow(void) ime_call_count = 0; } +static void test_ImmSetStatusWindowPos(void) +{ + struct ime_call set_status_window_pos_0_seq[] = + { + { + .hkl = expect_ime, .himc = 0/*himc*/, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETSTATUSWINDOWPOS}, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETSTATUSWINDOWPOS}, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETSTATUSWINDOWPOS}, + }, + {0}, + }; + struct ime_call set_status_window_pos_1_seq[] = + { + { + .hkl = expect_ime, .himc = 0/*himc*/, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETSTATUSWINDOWPOS}, + }, + {.todo = TRUE}, + }; + INPUTCONTEXT *ctx; + POINT pos; + HIMC himc; + HKL hkl; + + ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; + + if (!(hkl = wineime_hkl)) return; + + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + set_status_window_pos_0_seq[0].himc = himc; + set_status_window_pos_1_seq[0].himc = himc; + + memset( &pos, 0xcd, sizeof(pos) ); + ctx->ptStatusWndPos.x = 0xdeadbeef; + ctx->ptStatusWndPos.y = 0xfeedcafe; + ctx->fdwInit = ~INIT_STATUSWNDPOS; + todo_wine ok_ret( 0, ImmGetStatusWindowPos( himc, &pos ) ); + todo_wine ok_eq( 0xcdcdcdcd, pos.x, UINT, "%u" ); + todo_wine ok_eq( 0xcdcdcdcd, pos.y, UINT, "%u" ); + ctx->fdwInit = INIT_STATUSWNDPOS; + ok_ret( 1, ImmGetStatusWindowPos( himc, &pos ) ); + ok_eq( 0xdeadbeef, pos.x, UINT, "%u" ); + ok_eq( 0xfeedcafe, pos.y, UINT, "%u" ); + ok_seq( empty_sequence ); + + pos.x = 123; + pos.y = 456; + ctx->hWnd = hwnd; + ctx->fdwInit = 0; + ok_ret( 1, ImmSetStatusWindowPos( himc, &pos ) ); + ok_seq( set_status_window_pos_0_seq ); + todo_wine ok_eq( INIT_STATUSWNDPOS, ctx->fdwInit, UINT, "%u" ); + + ok_ret( 1, ImmSetStatusWindowPos( himc, &pos ) ); + ok_seq( set_status_window_pos_0_seq ); + ok_ret( 1, ImmGetStatusWindowPos( himc, &pos ) ); + ok_eq( 123, pos.x, UINT, "%u" ); + ok_eq( 123, ctx->ptStatusWndPos.x, UINT, "%u" ); + ok_eq( 456, pos.y, UINT, "%u" ); + ok_eq( 456, ctx->ptStatusWndPos.y, UINT, "%u" ); + ok_seq( empty_sequence ); + + ctx->hWnd = 0; + ok_ret( 1, ImmSetStatusWindowPos( himc, &pos ) ); + ok_seq( set_status_window_pos_1_seq ); + + ok_ret( 1, ImmUnlockIMC( himc ) ); + ok_ret( 1, ImmDestroyContext( himc ) ); + + ok_ret( 1, ImmActivateLayout( default_hkl ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + + ok_ret( 1, ImmFreeLayout( hkl ) ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); @@ -6176,6 +6274,7 @@ START_TEST(imm32) test_ImmGetCompositionString( TRUE ); test_ImmGetCompositionString( FALSE ); test_ImmSetCompositionWindow(); + test_ImmSetStatusWindowPos(); if (wineime_hkl) ime_cleanup( wineime_hkl, TRUE ); From e567982ab509ae48b04d6779a394ecbb2f09338f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 30 Mar 2023 23:06:05 +0200 Subject: [PATCH 1854/2777] imm32/tests: Add some Imm(Get|Set)CompositionFont tests. (cherry picked from commit 7ddc95d4aa7c0fa4db0e928d7af59f8886ace3f8) --- dlls/imm32/tests/imm32.c | 205 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 60ecf7b050b..8202d1f7c1f 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -97,6 +97,12 @@ extern BOOL WINAPI ImmActivateLayout(HKL); #define check_member_wstr( val, exp, member ) \ check_member_wstr_( __FILE__, __LINE__, val, exp, member ) +#define check_member_str_( file, line, val, exp, member ) \ + ok_(file, line)( !strcmp( (val).member, (exp).member ), "got " #member " %s\n", \ + debugstr_a((val).member) ) +#define check_member_str( val, exp, member ) \ + check_member_str_( __FILE__, __LINE__, val, exp, member ) + #define check_member_point_( file, line, val, exp, member ) \ ok_(file, line)( !memcmp( &(val).member, &(exp).member, sizeof(POINT) ), \ "got " #member " %s\n", wine_dbgstr_point( &(val).member ) ) @@ -176,6 +182,44 @@ static void check_composition_form_( int line, COMPOSITIONFORM *form, const COMP check_member_rect_( __FILE__, line, *form, *expect, rcArea ); } +#define check_logfont_w( a, b ) check_logfont_w_( __LINE__, a, b, FALSE ) +static void check_logfont_w_( int line, LOGFONTW *font, const LOGFONTW *expect, BOOL todo ) +{ + check_member_( __FILE__, line, *font, *expect, "%lu", lfHeight ); + check_member_( __FILE__, line, *font, *expect, "%lu", lfWidth ); + check_member_( __FILE__, line, *font, *expect, "%lu", lfEscapement ); + check_member_( __FILE__, line, *font, *expect, "%lu", lfOrientation ); + check_member_( __FILE__, line, *font, *expect, "%lu", lfWeight ); + check_member_( __FILE__, line, *font, *expect, "%u", lfItalic ); + check_member_( __FILE__, line, *font, *expect, "%u", lfUnderline ); + check_member_( __FILE__, line, *font, *expect, "%u", lfStrikeOut ); + check_member_( __FILE__, line, *font, *expect, "%u", lfCharSet ); + check_member_( __FILE__, line, *font, *expect, "%u", lfOutPrecision ); + check_member_( __FILE__, line, *font, *expect, "%u", lfClipPrecision ); + check_member_( __FILE__, line, *font, *expect, "%u", lfQuality ); + check_member_( __FILE__, line, *font, *expect, "%u", lfPitchAndFamily ); + todo_wine_if(todo) check_member_wstr_( __FILE__, line, *font, *expect, lfFaceName ); +} + +#define check_logfont_a( a, b ) check_logfont_a_( __LINE__, a, b, FALSE ) +static void check_logfont_a_( int line, LOGFONTA *font, const LOGFONTA *expect, BOOL todo ) +{ + check_member_( __FILE__, line, *font, *expect, "%lu", lfHeight ); + check_member_( __FILE__, line, *font, *expect, "%lu", lfWidth ); + check_member_( __FILE__, line, *font, *expect, "%lu", lfEscapement ); + check_member_( __FILE__, line, *font, *expect, "%lu", lfOrientation ); + check_member_( __FILE__, line, *font, *expect, "%lu", lfWeight ); + check_member_( __FILE__, line, *font, *expect, "%u", lfItalic ); + check_member_( __FILE__, line, *font, *expect, "%u", lfUnderline ); + check_member_( __FILE__, line, *font, *expect, "%u", lfStrikeOut ); + check_member_( __FILE__, line, *font, *expect, "%u", lfCharSet ); + check_member_( __FILE__, line, *font, *expect, "%u", lfOutPrecision ); + check_member_( __FILE__, line, *font, *expect, "%u", lfClipPrecision ); + check_member_( __FILE__, line, *font, *expect, "%u", lfQuality ); + check_member_( __FILE__, line, *font, *expect, "%u", lfPitchAndFamily ); + todo_wine_if(todo) check_member_str_( __FILE__, line, *font, *expect, lfFaceName ); +} + #define DEFINE_EXPECT(func) \ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE, enabled_ ## func = FALSE @@ -1009,6 +1053,7 @@ static DWORD WINAPI test_cross_thread_himc_thread( void *arg ) COMPOSITIONFORM composition = {0}; INPUTCONTEXT *contexts[2]; HIMC himc[2], tmp_himc; + LOGFONTW fontW = {0}; HWND hwnd, tmp_hwnd; POINT pos = {0}; MSG msg; @@ -1041,6 +1086,8 @@ static DWORD WINAPI test_cross_thread_himc_thread( void *arg ) ok_ret( 1, ImmSetCandidateWindow( himc[1], &candidate ) ); ok_ret( 1, ImmSetStatusWindowPos( himc[0], &pos ) ); ok_ret( 1, ImmSetStatusWindowPos( himc[1], &pos ) ); + ok_ret( 1, ImmSetCompositionFontW( himc[0], &fontW ) ); + ok_ret( 1, ImmSetCompositionFontW( himc[1], &fontW ) ); params->hwnd = hwnd; params->himc[0] = himc[0]; @@ -6217,6 +6264,162 @@ static void test_ImmSetStatusWindowPos(void) ime_call_count = 0; } +static void test_ImmSetCompositionFont( BOOL unicode ) +{ + struct ime_call set_composition_font_0_seq[] = + { + { + .hkl = expect_ime, .himc = 0/*himc*/, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCOMPOSITIONFONT}, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCOMPOSITIONFONT}, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCOMPOSITIONFONT}, + }, + {0}, + }; + struct ime_call set_composition_font_1_seq[] = + { + { + .hkl = expect_ime, .himc = 0/*himc*/, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCOMPOSITIONFONT}, + }, + {.todo = TRUE}, + }; + LOGFONTW fontW, expect_fontW = + { + .lfHeight = 1, + .lfWidth = 2, + .lfEscapement = 3, + .lfOrientation = 4, + .lfWeight = 5, + .lfItalic = 6, + .lfUnderline = 7, + .lfStrikeOut = 8, + .lfCharSet = 8, + .lfOutPrecision = 10, + .lfClipPrecision = 11, + .lfQuality = 12, + .lfPitchAndFamily = 13, + .lfFaceName = L"FontFace", + }; + LOGFONTA fontA, expect_fontA = + { + .lfHeight = 1, + .lfWidth = 2, + .lfEscapement = 3, + .lfOrientation = 4, + .lfWeight = 5, + .lfItalic = 6, + .lfUnderline = 7, + .lfStrikeOut = 8, + .lfCharSet = 8, + .lfOutPrecision = 10, + .lfClipPrecision = 11, + .lfQuality = 12, + .lfPitchAndFamily = 13, + .lfFaceName = "FontFace", + }; + INPUTCONTEXT *ctx; + HIMC himc; + HKL hkl; + + winetest_push_context( unicode ? "unicode" : "ansi" ); + + /* IME_PROP_END_UNLOAD for the IME to unload / reload. */ + ime_info.fdwProperty = IME_PROP_END_UNLOAD; + if (unicode) ime_info.fdwProperty |= IME_PROP_UNICODE; + + if (!(hkl = wineime_hkl)) goto cleanup; + + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + set_composition_font_0_seq[0].himc = himc; + set_composition_font_1_seq[0].himc = himc; + + memset( &fontW, 0xcd, sizeof(fontW) ); + memset( &fontA, 0xcd, sizeof(fontA) ); + + if (unicode) ctx->lfFont.W = expect_fontW; + else ctx->lfFont.A = expect_fontA; + ctx->fdwInit = ~INIT_LOGFONT; + todo_wine ok_ret( 0, ImmGetCompositionFontW( himc, &fontW ) ); + todo_wine ok_ret( 0, ImmGetCompositionFontA( himc, &fontA ) ); + ctx->fdwInit = INIT_LOGFONT; + ok_ret( 1, ImmGetCompositionFontW( himc, &fontW ) ); + check_logfont_w_( __LINE__, &fontW, &expect_fontW, !unicode ); + ok_ret( 1, ImmGetCompositionFontA( himc, &fontA ) ); + check_logfont_a_( __LINE__, &fontA, &expect_fontA, !unicode ); + + ctx->hWnd = hwnd; + ctx->fdwInit = 0; + memset( &ctx->lfFont, 0xcd, sizeof(ctx->lfFont) ); + ok_ret( 1, ImmSetCompositionFontW( himc, &expect_fontW ) ); + todo_wine ok_eq( INIT_LOGFONT, ctx->fdwInit, UINT, "%u" ); + ok_seq( set_composition_font_0_seq ); + ok_ret( 1, ImmSetCompositionFontW( himc, &expect_fontW ) ); + ok_seq( set_composition_font_0_seq ); + if (unicode) check_logfont_w( &ctx->lfFont.W, &expect_fontW ); + else check_logfont_a_( __LINE__, &ctx->lfFont.A, &expect_fontA, TRUE ); + + ok_ret( 1, ImmGetCompositionFontW( himc, &fontW ) ); + check_logfont_w( &fontW, &expect_fontW ); + ok_ret( 1, ImmGetCompositionFontA( himc, &fontA ) ); + check_logfont_a( &fontA, &expect_fontA ); + + ctx->hWnd = hwnd; + ctx->fdwInit = 0; + memset( &ctx->lfFont, 0xcd, sizeof(ctx->lfFont) ); + ok_ret( 1, ImmSetCompositionFontA( himc, &expect_fontA ) ); + todo_wine ok_eq( INIT_LOGFONT, ctx->fdwInit, UINT, "%u" ); + ok_seq( set_composition_font_0_seq ); + ok_ret( 1, ImmSetCompositionFontA( himc, &expect_fontA ) ); + ok_seq( set_composition_font_0_seq ); + if (unicode) check_logfont_w( &ctx->lfFont.W, &expect_fontW ); + else check_logfont_a_( __LINE__, &ctx->lfFont.A, &expect_fontA, TRUE ); + + ok_ret( 1, ImmGetCompositionFontW( himc, &fontW ) ); + check_logfont_w( &fontW, &expect_fontW ); + ok_ret( 1, ImmGetCompositionFontA( himc, &fontA ) ); + check_logfont_a( &fontA, &expect_fontA ); + + ctx->hWnd = 0; + ok_ret( 1, ImmSetCompositionFontW( himc, &expect_fontW ) ); + ok_seq( set_composition_font_1_seq ); + ok_ret( 1, ImmSetCompositionFontA( himc, &expect_fontA ) ); + ok_seq( set_composition_font_1_seq ); + + ok_ret( 1, ImmUnlockIMC( himc ) ); + ok_ret( 1, ImmDestroyContext( himc ) ); + + ok_ret( 1, ImmActivateLayout( default_hkl ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + + ok_ret( 1, ImmFreeLayout( hkl ) ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + +cleanup: + winetest_pop_context(); +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); @@ -6275,6 +6478,8 @@ START_TEST(imm32) test_ImmGetCompositionString( FALSE ); test_ImmSetCompositionWindow(); test_ImmSetStatusWindowPos(); + test_ImmSetCompositionFont( TRUE ); + test_ImmSetCompositionFont( FALSE ); if (wineime_hkl) ime_cleanup( wineime_hkl, TRUE ); From d8c9dcbf06c75755354b760ac1e5349f3e6543cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 13 Apr 2023 11:06:21 +0200 Subject: [PATCH 1855/2777] imm32/tests: Add some Imm(Get|Set)CandidateWindow tests. (cherry picked from commit 564deb8a34f4bc4054d04352e01d8665c87685a4) --- dlls/imm32/tests/imm32.c | 101 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 8202d1f7c1f..ccdc6b8f801 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -6420,6 +6420,106 @@ static void test_ImmSetCompositionFont( BOOL unicode ) winetest_pop_context(); } +static void test_ImmSetCandidateWindow(void) +{ + struct ime_call set_candidate_window_0_seq[] = + { + { + .hkl = expect_ime, .himc = 0/*himc*/, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCANDIDATEPOS}, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCANDIDATEPOS, .lparam = 4}, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_SETCANDIDATEPOS, .lparam = 4}, + }, + {0}, + }; + struct ime_call set_candidate_window_1_seq[] = + { + { + .hkl = expect_ime, .himc = 0/*himc*/, + .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCANDIDATEPOS}, + }, + {.todo = TRUE}, + }; + CANDIDATEFORM cand_form, expect_form = + { + .dwIndex = 2, .dwStyle = 0xfeedcafe, + .ptCurrentPos = {.x = 123, .y = 456}, + .rcArea = {.left = 1, .top = 2, .right = 3, .bottom = 4}, + }; + INPUTCONTEXT *ctx; + HIMC himc; + HKL hkl; + + ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; + + if (!(hkl = wineime_hkl)) return; + + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + set_candidate_window_0_seq[0].himc = himc; + set_candidate_window_1_seq[0].himc = himc; + + ctx->cfCandForm[1] = expect_form; + ctx->cfCandForm[2] = expect_form; + ctx->fdwInit = 0; + memset( &cand_form, 0xcd, sizeof(cand_form) ); + ok_ret( 0, ImmGetCandidateWindow( himc, 0, &cand_form ) ); + ok_eq( 0xcdcdcdcd, cand_form.dwStyle, UINT, "%#x" ); + todo_wine ok_ret( 1, ImmGetCandidateWindow( himc, 1, &cand_form ) ); + todo_wine check_candidate_form( &cand_form, &expect_form ); + ok_ret( 1, ImmGetCandidateWindow( himc, 2, &cand_form ) ); + check_candidate_form( &cand_form, &expect_form ); + ok_seq( empty_sequence ); + + ctx->hWnd = hwnd; + memset( &cand_form, 0xcd, sizeof(cand_form) ); + cand_form.dwIndex = 2; + ok_ret( 1, ImmSetCandidateWindow( himc, &cand_form ) ); + ok_seq( set_candidate_window_0_seq ); + check_candidate_form( &ctx->cfCandForm[2], &cand_form ); + ok_eq( 0, ctx->fdwInit, UINT, "%u" ); + + ok_ret( 1, ImmSetCandidateWindow( himc, &expect_form ) ); + ok_seq( set_candidate_window_0_seq ); + check_candidate_form( &ctx->cfCandForm[2], &expect_form ); + + ctx->hWnd = 0; + memset( &cand_form, 0xcd, sizeof(cand_form) ); + cand_form.dwIndex = 2; + ok_ret( 1, ImmSetCandidateWindow( himc, &cand_form ) ); + ok_seq( set_candidate_window_1_seq ); + check_candidate_form( &ctx->cfCandForm[2], &cand_form ); + + ok_ret( 1, ImmUnlockIMC( himc ) ); + ok_ret( 1, ImmDestroyContext( himc ) ); + + ok_ret( 1, ImmActivateLayout( default_hkl ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + + ok_ret( 1, ImmFreeLayout( hkl ) ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); @@ -6480,6 +6580,7 @@ START_TEST(imm32) test_ImmSetStatusWindowPos(); test_ImmSetCompositionFont( TRUE ); test_ImmSetCompositionFont( FALSE ); + test_ImmSetCandidateWindow(); if (wineime_hkl) ime_cleanup( wineime_hkl, TRUE ); From 0c953a9f4c6bd3b1a71475a136eea1c6e811d3ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 6 Apr 2023 01:18:56 +0200 Subject: [PATCH 1856/2777] imm32: Use INPUTCONTEXT directly in ImmSetCompositionWindow. (cherry picked from commit 048d2f0d13011cc2d4b574bb0e42f20126cfe2de) --- dlls/imm32/imm.c | 39 ++++++++++++++++++++------------------- dlls/imm32/tests/imm32.c | 6 ++---- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index d29684f34a2..16c36c0173d 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -119,6 +119,14 @@ static struct list ime_list = LIST_INIT( ime_list ); static const WCHAR layouts_formatW[] = L"System\\CurrentControlSet\\Control\\Keyboard Layouts\\%08lx"; +static const char *debugstr_composition( const COMPOSITIONFORM *composition ) +{ + if (!composition) return "(null)"; + return wine_dbg_sprintf( "style %#lx, pos %s, area %s", composition->dwStyle, + wine_dbgstr_point( &composition->ptCurrentPos ), + wine_dbgstr_rect( &composition->rcArea ) ); +} + static BOOL ime_is_unicode( const struct ime *ime ) { return !!(ime->info.fdwProperty & IME_PROP_UNICODE); @@ -2595,28 +2603,19 @@ BOOL WINAPI ImmSetCompositionStringW( /*********************************************************************** * ImmSetCompositionWindow (IMM32.@) */ -BOOL WINAPI ImmSetCompositionWindow( - HIMC hIMC, LPCOMPOSITIONFORM lpCompForm) +BOOL WINAPI ImmSetCompositionWindow( HIMC himc, COMPOSITIONFORM *composition ) { BOOL reshow = FALSE; - struct imc *data = get_imc_data( hIMC ); + INPUTCONTEXT *ctx; HWND ui_hwnd; - TRACE("(%p, %p)\n", hIMC, lpCompForm); - if (lpCompForm) - TRACE("\t%lx, %s, %s\n", lpCompForm->dwStyle, - wine_dbgstr_point(&lpCompForm->ptCurrentPos), - wine_dbgstr_rect(&lpCompForm->rcArea)); + TRACE( "himc %p, composition %s\n", himc, debugstr_composition( composition ) ); - if (!data) - { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - - if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + if (!(ctx = ImmLockIMC( himc ))) return FALSE; - data->IMC.cfCompForm = *lpCompForm; + ctx->cfCompForm = *composition; + ctx->fdwInit |= INIT_COMPFORM; if ((ui_hwnd = get_ime_ui_window()) && IsWindowVisible( ui_hwnd )) { @@ -2624,11 +2623,13 @@ BOOL WINAPI ImmSetCompositionWindow( ShowWindow( ui_hwnd, SW_HIDE ); } - /* FIXME: this is a partial stub */ - if (ui_hwnd && reshow) ShowWindow( ui_hwnd, SW_SHOWNOACTIVATE ); - imc_notify_ime( data, IMN_SETCOMPOSITIONWINDOW, 0 ); + ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONWINDOW ); + SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCOMPOSITIONWINDOW, 0 ); + + ImmUnlockIMC( himc ); + return TRUE; } diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index ccdc6b8f801..45efd946d4e 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -6069,7 +6069,6 @@ static void test_ImmSetCompositionWindow(void) { .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCOMPOSITIONWINDOW}, - .todo = TRUE }, { .hkl = expect_ime, .himc = default_himc, @@ -6086,9 +6085,8 @@ static void test_ImmSetCompositionWindow(void) { .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCOMPOSITIONWINDOW}, - .todo = TRUE }, - {.todo = TRUE}, + {0}, }; COMPOSITIONFORM comp_form, expect_form = { @@ -6136,7 +6134,7 @@ static void test_ImmSetCompositionWindow(void) memset( &comp_form, 0xcd, sizeof(comp_form) ); ok_ret( 1, ImmSetCompositionWindow( himc, &comp_form ) ); ok_seq( set_composition_window_0_seq ); - todo_wine ok_eq( INIT_COMPFORM, ctx->fdwInit, UINT, "%u" ); + ok_eq( INIT_COMPFORM, ctx->fdwInit, UINT, "%u" ); check_composition_form( &ctx->cfCompForm, &comp_form ); ok_ret( 1, ImmSetCompositionWindow( himc, &expect_form ) ); From 840c5cb8ddf6413a38d0fc5bf932766d66518f33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 8 Apr 2023 12:00:52 +0200 Subject: [PATCH 1857/2777] imm32: Use INPUTCONTEXT directly in ImmGetCompositionWindow. (cherry picked from commit e49feacdb4206ea8e90e7126aa026dbfde930c9b) --- dlls/imm32/imm.c | 15 ++++++++------- dlls/imm32/tests/imm32.c | 4 ++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 16c36c0173d..31a63ecbc80 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1740,17 +1740,18 @@ LONG WINAPI ImmGetCompositionStringW( /*********************************************************************** * ImmGetCompositionWindow (IMM32.@) */ -BOOL WINAPI ImmGetCompositionWindow(HIMC hIMC, LPCOMPOSITIONFORM lpCompForm) +BOOL WINAPI ImmGetCompositionWindow( HIMC himc, COMPOSITIONFORM *composition ) { - struct imc *data = get_imc_data( hIMC ); + INPUTCONTEXT *ctx; + BOOL ret; - TRACE("(%p, %p)\n", hIMC, lpCompForm); + TRACE( "himc %p, composition %p\n", himc, composition ); - if (!data) - return FALSE; + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + if ((ret = !!(ctx->fdwInit & INIT_COMPFORM))) *composition = ctx->cfCompForm; + ImmUnlockIMC( himc ); - *lpCompForm = data->IMC.cfCompForm; - return TRUE; + return ret; } /*********************************************************************** diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 45efd946d4e..3aa50ea3582 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -6122,8 +6122,8 @@ static void test_ImmSetCompositionWindow(void) ctx->cfCompForm = expect_form; ctx->fdwInit = ~INIT_COMPFORM; memset( &comp_form, 0xcd, sizeof(comp_form) ); - todo_wine ok_ret( 0, ImmGetCompositionWindow( himc, &comp_form ) ); - todo_wine ok_eq( 0xcdcdcdcd, comp_form.dwStyle, UINT, "%#x" ); + ok_ret( 0, ImmGetCompositionWindow( himc, &comp_form ) ); + ok_eq( 0xcdcdcdcd, comp_form.dwStyle, UINT, "%#x" ); ctx->fdwInit = INIT_COMPFORM; ok_ret( 1, ImmGetCompositionWindow( himc, &comp_form ) ); check_composition_form( &comp_form, &expect_form ); From 2a616e4972ab8d8bb33528eaddfb97c954f7c430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 6 Apr 2023 01:05:13 +0200 Subject: [PATCH 1858/2777] imm32: Use INPUTCONTEXT directly in ImmSetStatusWindowPos. (cherry picked from commit d0a88bf7de160185476f593eb50142ab9dc85435) --- dlls/imm32/imm.c | 23 +++++++++++++---------- dlls/imm32/tests/imm32.c | 4 ++-- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 31a63ecbc80..b88ca86c15c 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2698,25 +2698,28 @@ BOOL WINAPI ImmSetOpenStatus( HIMC himc, BOOL status ) /*********************************************************************** * ImmSetStatusWindowPos (IMM32.@) */ -BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) +BOOL WINAPI ImmSetStatusWindowPos( HIMC himc, POINT *pos ) { - struct imc *data = get_imc_data( hIMC ); + INPUTCONTEXT *ctx; - TRACE("(%p, %p)\n", hIMC, lpptPos); + TRACE( "himc %p, pos %s\n", himc, wine_dbgstr_point( pos ) ); - if (!data || !lpptPos) + if (!pos) { - SetLastError(ERROR_INVALID_HANDLE); + SetLastError( ERROR_INVALID_HANDLE ); return FALSE; } - if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + if (!(ctx = ImmLockIMC( himc ))) return FALSE; - TRACE("\t%s\n", wine_dbgstr_point(lpptPos)); + ctx->ptStatusWndPos = *pos; + ctx->fdwInit |= INIT_STATUSWNDPOS; - data->IMC.ptStatusWndPos = *lpptPos; - ImmNotifyIME( hIMC, NI_CONTEXTUPDATED, 0, IMC_SETSTATUSWINDOWPOS); - imc_notify_ime( data, IMN_SETSTATUSWINDOWPOS, 0 ); + ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETSTATUSWINDOWPOS ); + SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETSTATUSWINDOWPOS, 0 ); + + ImmUnlockIMC( himc ); return TRUE; } diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 3aa50ea3582..cc09d5d969d 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -6188,7 +6188,7 @@ static void test_ImmSetStatusWindowPos(void) .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETSTATUSWINDOWPOS}, }, - {.todo = TRUE}, + {0}, }; INPUTCONTEXT *ctx; POINT pos; @@ -6235,7 +6235,7 @@ static void test_ImmSetStatusWindowPos(void) ctx->fdwInit = 0; ok_ret( 1, ImmSetStatusWindowPos( himc, &pos ) ); ok_seq( set_status_window_pos_0_seq ); - todo_wine ok_eq( INIT_STATUSWNDPOS, ctx->fdwInit, UINT, "%u" ); + ok_eq( INIT_STATUSWNDPOS, ctx->fdwInit, UINT, "%u" ); ok_ret( 1, ImmSetStatusWindowPos( himc, &pos ) ); ok_seq( set_status_window_pos_0_seq ); From d6586cb841ef3e16360c05aaf911f96cfc2ffae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 8 Apr 2023 11:59:38 +0200 Subject: [PATCH 1859/2777] imm32: Use INPUTCONTEXT directly in ImmGetStatusWindowPos. (cherry picked from commit 9a4b9a3ae5c9b283ca33171afb90fd94ee3bb33b) --- dlls/imm32/imm.c | 16 ++++++++-------- dlls/imm32/tests/imm32.c | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index b88ca86c15c..8ff3a99324a 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2092,18 +2092,18 @@ UINT WINAPI ImmGetRegisterWordStyleW( HKL hkl, UINT count, STYLEBUFW *styleW ) /*********************************************************************** * ImmGetStatusWindowPos (IMM32.@) */ -BOOL WINAPI ImmGetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) +BOOL WINAPI ImmGetStatusWindowPos( HIMC himc, POINT *pos ) { - struct imc *data = get_imc_data( hIMC ); - - TRACE("(%p, %p)\n", hIMC, lpptPos); + INPUTCONTEXT *ctx; + BOOL ret; - if (!data || !lpptPos) - return FALSE; + TRACE( "himc %p, pos %p\n", himc, pos ); - *lpptPos = data->IMC.ptStatusWndPos; + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + if ((ret = !!(ctx->fdwInit & INIT_STATUSWNDPOS))) *pos = ctx->ptStatusWndPos; + ImmUnlockIMC( himc ); - return TRUE; + return ret; } /*********************************************************************** diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index cc09d5d969d..0dda2217979 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -6220,9 +6220,9 @@ static void test_ImmSetStatusWindowPos(void) ctx->ptStatusWndPos.x = 0xdeadbeef; ctx->ptStatusWndPos.y = 0xfeedcafe; ctx->fdwInit = ~INIT_STATUSWNDPOS; - todo_wine ok_ret( 0, ImmGetStatusWindowPos( himc, &pos ) ); - todo_wine ok_eq( 0xcdcdcdcd, pos.x, UINT, "%u" ); - todo_wine ok_eq( 0xcdcdcdcd, pos.y, UINT, "%u" ); + ok_ret( 0, ImmGetStatusWindowPos( himc, &pos ) ); + ok_eq( 0xcdcdcdcd, pos.x, UINT, "%u" ); + ok_eq( 0xcdcdcdcd, pos.y, UINT, "%u" ); ctx->fdwInit = INIT_STATUSWNDPOS; ok_ret( 1, ImmGetStatusWindowPos( himc, &pos ) ); ok_eq( 0xdeadbeef, pos.x, UINT, "%u" ); From 9471eb46da94472a104e0784179f60d3854a5aed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 6 Apr 2023 01:15:56 +0200 Subject: [PATCH 1860/2777] imm32: Use INPUTCONTEXT directly in ImmSetCompositionFont(A|W). (cherry picked from commit d4318270da18ffb72a214910db1583366d2d0786) --- dlls/imm32/imm.c | 78 +++++++++++++++++++++++++++------------- dlls/imm32/tests/imm32.c | 18 +++++----- 2 files changed, 63 insertions(+), 33 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 8ff3a99324a..d261725bc08 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -132,6 +132,12 @@ static BOOL ime_is_unicode( const struct ime *ime ) return !!(ime->info.fdwProperty & IME_PROP_UNICODE); } +static BOOL input_context_is_unicode( INPUTCONTEXT *ctx ) +{ + struct imc *imc = CONTAINING_RECORD( ctx, struct imc, IMC ); + return !imc->ime || ime_is_unicode( imc->ime ); +} + static BOOL IMM_DestroyContext(HIMC hIMC); static struct imc *get_imc_data( HIMC hIMC ); @@ -2438,49 +2444,73 @@ BOOL WINAPI ImmSetCandidateWindow( /*********************************************************************** * ImmSetCompositionFontA (IMM32.@) */ -BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) +BOOL WINAPI ImmSetCompositionFontA( HIMC himc, LOGFONTA *fontA ) { - struct imc *data = get_imc_data( hIMC ); - TRACE("(%p, %p)\n", hIMC, lplf); + INPUTCONTEXT *ctx; + BOOL ret = TRUE; - if (!data || !lplf) + TRACE( "hwnd %p, fontA %p\n", himc, fontA ); + + if (!fontA) return FALSE; + + if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + + if (input_context_is_unicode( ctx )) { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; + LOGFONTW fontW; + memcpy( &fontW, fontA, offsetof(LOGFONTW, lfFaceName) ); + MultiByteToWideChar( CP_ACP, 0, fontA->lfFaceName, -1, fontW.lfFaceName, LF_FACESIZE ); + ret = ImmSetCompositionFontW( himc, &fontW ); } + else + { + ctx->lfFont.A = *fontA; + ctx->fdwInit |= INIT_LOGFONT; - if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT ); + SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCOMPOSITIONFONT, 0 ); + } - memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA)); - MultiByteToWideChar(CP_ACP, 0, lplf->lfFaceName, -1, data->IMC.lfFont.W.lfFaceName, - LF_FACESIZE); - ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT); - imc_notify_ime( data, IMN_SETCOMPOSITIONFONT, 0 ); + ImmUnlockIMC( himc ); - return TRUE; + return ret; } /*********************************************************************** * ImmSetCompositionFontW (IMM32.@) */ -BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) +BOOL WINAPI ImmSetCompositionFontW( HIMC himc, LOGFONTW *fontW ) { - struct imc *data = get_imc_data( hIMC ); - TRACE("(%p, %p)\n", hIMC, lplf); + INPUTCONTEXT *ctx; + BOOL ret = TRUE; - if (!data || !lplf) + TRACE( "hwnd %p, fontW %p\n", himc, fontW ); + + if (!fontW) return FALSE; + + if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + + if (!input_context_is_unicode( ctx )) { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; + LOGFONTA fontA; + memcpy( &fontA, fontW, offsetof(LOGFONTA, lfFaceName) ); + WideCharToMultiByte( CP_ACP, 0, fontW->lfFaceName, -1, fontA.lfFaceName, LF_FACESIZE, NULL, NULL ); + ret = ImmSetCompositionFontA( himc, &fontA ); } + else + { + ctx->lfFont.W = *fontW; + ctx->fdwInit |= INIT_LOGFONT; - if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT ); + SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCOMPOSITIONFONT, 0 ); + } - data->IMC.lfFont.W = *lplf; - ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONFONT); - imc_notify_ime( data, IMN_SETCOMPOSITIONFONT, 0 ); + ImmUnlockIMC( himc ); - return TRUE; + return ret; } /*********************************************************************** diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 0dda2217979..2e59f04e108 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -6286,7 +6286,7 @@ static void test_ImmSetCompositionFont( BOOL unicode ) .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCOMPOSITIONFONT}, }, - {.todo = TRUE}, + {0}, }; LOGFONTW fontW, expect_fontW = { @@ -6369,33 +6369,33 @@ static void test_ImmSetCompositionFont( BOOL unicode ) ctx->fdwInit = 0; memset( &ctx->lfFont, 0xcd, sizeof(ctx->lfFont) ); ok_ret( 1, ImmSetCompositionFontW( himc, &expect_fontW ) ); - todo_wine ok_eq( INIT_LOGFONT, ctx->fdwInit, UINT, "%u" ); + ok_eq( INIT_LOGFONT, ctx->fdwInit, UINT, "%u" ); ok_seq( set_composition_font_0_seq ); ok_ret( 1, ImmSetCompositionFontW( himc, &expect_fontW ) ); ok_seq( set_composition_font_0_seq ); if (unicode) check_logfont_w( &ctx->lfFont.W, &expect_fontW ); - else check_logfont_a_( __LINE__, &ctx->lfFont.A, &expect_fontA, TRUE ); + else check_logfont_a( &ctx->lfFont.A, &expect_fontA ); ok_ret( 1, ImmGetCompositionFontW( himc, &fontW ) ); - check_logfont_w( &fontW, &expect_fontW ); + check_logfont_w_( __LINE__, &fontW, &expect_fontW, !unicode ); ok_ret( 1, ImmGetCompositionFontA( himc, &fontA ) ); - check_logfont_a( &fontA, &expect_fontA ); + check_logfont_a_( __LINE__, &fontA, &expect_fontA, !unicode ); ctx->hWnd = hwnd; ctx->fdwInit = 0; memset( &ctx->lfFont, 0xcd, sizeof(ctx->lfFont) ); ok_ret( 1, ImmSetCompositionFontA( himc, &expect_fontA ) ); - todo_wine ok_eq( INIT_LOGFONT, ctx->fdwInit, UINT, "%u" ); + ok_eq( INIT_LOGFONT, ctx->fdwInit, UINT, "%u" ); ok_seq( set_composition_font_0_seq ); ok_ret( 1, ImmSetCompositionFontA( himc, &expect_fontA ) ); ok_seq( set_composition_font_0_seq ); if (unicode) check_logfont_w( &ctx->lfFont.W, &expect_fontW ); - else check_logfont_a_( __LINE__, &ctx->lfFont.A, &expect_fontA, TRUE ); + else check_logfont_a( &ctx->lfFont.A, &expect_fontA ); ok_ret( 1, ImmGetCompositionFontW( himc, &fontW ) ); - check_logfont_w( &fontW, &expect_fontW ); + check_logfont_w_( __LINE__, &fontW, &expect_fontW, !unicode ); ok_ret( 1, ImmGetCompositionFontA( himc, &fontA ) ); - check_logfont_a( &fontA, &expect_fontA ); + check_logfont_a_( __LINE__, &fontA, &expect_fontA, !unicode ); ctx->hWnd = 0; ok_ret( 1, ImmSetCompositionFontW( himc, &expect_fontW ) ); From df8e654167f0a88f45c3ccc7acce27cfebb867b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 13 Apr 2023 12:00:18 +0200 Subject: [PATCH 1861/2777] imm32: Use INPUTCONTEXT directly in ImmGetCompositionFont(A|W). (cherry picked from commit 93b6c4557d442cdd71cb01fa2ea05810306f91ab) --- dlls/imm32/imm.c | 51 ++++++++++++++++++++++++++-------------- dlls/imm32/tests/imm32.c | 28 +++++++++++----------- 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index d261725bc08..68196bf0149 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1413,38 +1413,53 @@ BOOL WINAPI ImmGetCandidateWindow( /*********************************************************************** * ImmGetCompositionFontA (IMM32.@) */ -BOOL WINAPI ImmGetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) +BOOL WINAPI ImmGetCompositionFontA( HIMC himc, LOGFONTA *fontA ) { - LOGFONTW lfW; - BOOL rc; + INPUTCONTEXT *ctx; + LOGFONTW fontW; + BOOL ret = TRUE; - TRACE("(%p, %p):\n", hIMC, lplf); + TRACE( "himc %p, fontA %p\n", himc, fontA ); - rc = ImmGetCompositionFontW(hIMC,&lfW); - if (!rc || !lplf) - return FALSE; + if (!fontA) return FALSE; - memcpy(lplf,&lfW,sizeof(LOGFONTA)); - WideCharToMultiByte(CP_ACP, 0, lfW.lfFaceName, -1, lplf->lfFaceName, - LF_FACESIZE, NULL, NULL); - return TRUE; + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + if (!(ctx->fdwInit & INIT_LOGFONT)) ret = FALSE; + else if (!input_context_is_unicode( ctx )) *fontA = ctx->lfFont.A; + else if ((ret = ImmGetCompositionFontW( himc, &fontW ))) + { + memcpy( fontA, &fontW, offsetof(LOGFONTA, lfFaceName) ); + WideCharToMultiByte( CP_ACP, 0, fontW.lfFaceName, -1, fontA->lfFaceName, LF_FACESIZE, NULL, NULL ); + } + ImmUnlockIMC( himc ); + + return ret; } /*********************************************************************** * ImmGetCompositionFontW (IMM32.@) */ -BOOL WINAPI ImmGetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) +BOOL WINAPI ImmGetCompositionFontW( HIMC himc, LOGFONTW *fontW ) { - struct imc *data = get_imc_data( hIMC ); + INPUTCONTEXT *ctx; + LOGFONTA fontA; + BOOL ret = TRUE; - TRACE("(%p, %p):\n", hIMC, lplf); + TRACE( "himc %p, fontW %p\n", himc, fontW ); - if (!data || !lplf) - return FALSE; + if (!fontW) return FALSE; - *lplf = data->IMC.lfFont.W; + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + if (!(ctx->fdwInit & INIT_LOGFONT)) ret = FALSE; + else if (input_context_is_unicode( ctx )) *fontW = ctx->lfFont.W; + else if ((ret = ImmGetCompositionFontA( himc, &fontA ))) + { + memcpy( fontW, &fontA, offsetof(LOGFONTW, lfFaceName) ); + MultiByteToWideChar( CP_ACP, 0, fontA.lfFaceName, -1, fontW->lfFaceName, LF_FACESIZE ); + } + ImmUnlockIMC( himc ); - return TRUE; + return ret; } diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 2e59f04e108..3b8b4755080 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -182,8 +182,8 @@ static void check_composition_form_( int line, COMPOSITIONFORM *form, const COMP check_member_rect_( __FILE__, line, *form, *expect, rcArea ); } -#define check_logfont_w( a, b ) check_logfont_w_( __LINE__, a, b, FALSE ) -static void check_logfont_w_( int line, LOGFONTW *font, const LOGFONTW *expect, BOOL todo ) +#define check_logfont_w( a, b ) check_logfont_w_( __LINE__, a, b ) +static void check_logfont_w_( int line, LOGFONTW *font, const LOGFONTW *expect ) { check_member_( __FILE__, line, *font, *expect, "%lu", lfHeight ); check_member_( __FILE__, line, *font, *expect, "%lu", lfWidth ); @@ -198,11 +198,11 @@ static void check_logfont_w_( int line, LOGFONTW *font, const LOGFONTW *expect, check_member_( __FILE__, line, *font, *expect, "%u", lfClipPrecision ); check_member_( __FILE__, line, *font, *expect, "%u", lfQuality ); check_member_( __FILE__, line, *font, *expect, "%u", lfPitchAndFamily ); - todo_wine_if(todo) check_member_wstr_( __FILE__, line, *font, *expect, lfFaceName ); + check_member_wstr_( __FILE__, line, *font, *expect, lfFaceName ); } -#define check_logfont_a( a, b ) check_logfont_a_( __LINE__, a, b, FALSE ) -static void check_logfont_a_( int line, LOGFONTA *font, const LOGFONTA *expect, BOOL todo ) +#define check_logfont_a( a, b ) check_logfont_a_( __LINE__, a, b ) +static void check_logfont_a_( int line, LOGFONTA *font, const LOGFONTA *expect ) { check_member_( __FILE__, line, *font, *expect, "%lu", lfHeight ); check_member_( __FILE__, line, *font, *expect, "%lu", lfWidth ); @@ -217,7 +217,7 @@ static void check_logfont_a_( int line, LOGFONTA *font, const LOGFONTA *expect, check_member_( __FILE__, line, *font, *expect, "%u", lfClipPrecision ); check_member_( __FILE__, line, *font, *expect, "%u", lfQuality ); check_member_( __FILE__, line, *font, *expect, "%u", lfPitchAndFamily ); - todo_wine_if(todo) check_member_str_( __FILE__, line, *font, *expect, lfFaceName ); + check_member_str_( __FILE__, line, *font, *expect, lfFaceName ); } #define DEFINE_EXPECT(func) \ @@ -6357,13 +6357,13 @@ static void test_ImmSetCompositionFont( BOOL unicode ) if (unicode) ctx->lfFont.W = expect_fontW; else ctx->lfFont.A = expect_fontA; ctx->fdwInit = ~INIT_LOGFONT; - todo_wine ok_ret( 0, ImmGetCompositionFontW( himc, &fontW ) ); - todo_wine ok_ret( 0, ImmGetCompositionFontA( himc, &fontA ) ); + ok_ret( 0, ImmGetCompositionFontW( himc, &fontW ) ); + ok_ret( 0, ImmGetCompositionFontA( himc, &fontA ) ); ctx->fdwInit = INIT_LOGFONT; ok_ret( 1, ImmGetCompositionFontW( himc, &fontW ) ); - check_logfont_w_( __LINE__, &fontW, &expect_fontW, !unicode ); + check_logfont_w( &fontW, &expect_fontW ); ok_ret( 1, ImmGetCompositionFontA( himc, &fontA ) ); - check_logfont_a_( __LINE__, &fontA, &expect_fontA, !unicode ); + check_logfont_a( &fontA, &expect_fontA ); ctx->hWnd = hwnd; ctx->fdwInit = 0; @@ -6377,9 +6377,9 @@ static void test_ImmSetCompositionFont( BOOL unicode ) else check_logfont_a( &ctx->lfFont.A, &expect_fontA ); ok_ret( 1, ImmGetCompositionFontW( himc, &fontW ) ); - check_logfont_w_( __LINE__, &fontW, &expect_fontW, !unicode ); + check_logfont_w( &fontW, &expect_fontW ); ok_ret( 1, ImmGetCompositionFontA( himc, &fontA ) ); - check_logfont_a_( __LINE__, &fontA, &expect_fontA, !unicode ); + check_logfont_a( &fontA, &expect_fontA ); ctx->hWnd = hwnd; ctx->fdwInit = 0; @@ -6393,9 +6393,9 @@ static void test_ImmSetCompositionFont( BOOL unicode ) else check_logfont_a( &ctx->lfFont.A, &expect_fontA ); ok_ret( 1, ImmGetCompositionFontW( himc, &fontW ) ); - check_logfont_w_( __LINE__, &fontW, &expect_fontW, !unicode ); + check_logfont_w( &fontW, &expect_fontW ); ok_ret( 1, ImmGetCompositionFontA( himc, &fontA ) ); - check_logfont_a_( __LINE__, &fontA, &expect_fontA, !unicode ); + check_logfont_a( &fontA, &expect_fontA ); ctx->hWnd = 0; ok_ret( 1, ImmSetCompositionFontW( himc, &expect_fontW ) ); From e67e27ef4c61768195a5cbd09afe09ebfa3efe37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 6 Apr 2023 01:11:14 +0200 Subject: [PATCH 1862/2777] imm32: Use INPUTCONTEXT directly in ImmSetCandidateWindow. (cherry picked from commit cf03ab413383df151d82a573d5934e18c0889360) --- dlls/imm32/imm.c | 42 ++++++++++++++++++---------------------- dlls/imm32/tests/imm32.c | 2 +- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 68196bf0149..aa63be82e4b 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -127,6 +127,14 @@ static const char *debugstr_composition( const COMPOSITIONFORM *composition ) wine_dbgstr_rect( &composition->rcArea ) ); } +static const char *debugstr_candidate( const CANDIDATEFORM *candidate ) +{ + if (!candidate) return "(null)"; + return wine_dbg_sprintf( "idx %#lx, style %#lx, pos %s, area %s", candidate->dwIndex, + candidate->dwStyle, wine_dbgstr_point( &candidate->ptCurrentPos ), + wine_dbgstr_rect( &candidate->rcArea ) ); +} + static BOOL ime_is_unicode( const struct ime *ime ) { return !!(ime->info.fdwProperty & IME_PROP_UNICODE); @@ -827,13 +835,6 @@ static void imc_send_message( struct imc *imc, TRANSMSG *message ) SendMessageW( target, message->message, message->wParam, message->lParam ); } -static LRESULT imc_notify_ime( struct imc *imc, WPARAM notify, LPARAM lparam ) -{ - HWND target; - if (!(target = imc->IMC.hWnd) && !(target = GetFocus())) return 0; - return SendMessageW( target, WM_IME_NOTIFY, notify, lparam ); -} - /*********************************************************************** * ImmSetActiveContext (IMM32.@) */ @@ -2429,29 +2430,24 @@ LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam) /*********************************************************************** * ImmSetCandidateWindow (IMM32.@) */ -BOOL WINAPI ImmSetCandidateWindow( - HIMC hIMC, LPCANDIDATEFORM lpCandidate) +BOOL WINAPI ImmSetCandidateWindow( HIMC himc, CANDIDATEFORM *candidate ) { - struct imc *data = get_imc_data( hIMC ); + INPUTCONTEXT *ctx; - TRACE("(%p, %p)\n", hIMC, lpCandidate); + TRACE( "hwnd %p, candidate %s\n", himc, debugstr_candidate( candidate ) ); - if (!data || !lpCandidate) - return FALSE; + if (!candidate) return FALSE; + if (candidate->dwIndex >= ARRAY_SIZE(ctx->cfCandForm)) return FALSE; - if (NtUserQueryInputContext( hIMC, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + if (!(ctx = ImmLockIMC( himc ))) return FALSE; - TRACE("\t%lx, %lx, %s, %s\n", - lpCandidate->dwIndex, lpCandidate->dwStyle, - wine_dbgstr_point(&lpCandidate->ptCurrentPos), - wine_dbgstr_rect(&lpCandidate->rcArea)); + ctx->cfCandForm[candidate->dwIndex] = *candidate; - if (lpCandidate->dwIndex >= ARRAY_SIZE(data->IMC.cfCandForm)) - return FALSE; + ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS ); + SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCANDIDATEPOS, 1 << candidate->dwIndex ); - data->IMC.cfCandForm[lpCandidate->dwIndex] = *lpCandidate; - ImmNotifyIME(hIMC, NI_CONTEXTUPDATED, 0, IMC_SETCANDIDATEPOS); - imc_notify_ime( data, IMN_SETCANDIDATEPOS, 1 << lpCandidate->dwIndex ); + ImmUnlockIMC( himc ); return TRUE; } diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 3b8b4755080..cf6c521e52f 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -6442,7 +6442,7 @@ static void test_ImmSetCandidateWindow(void) .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_NOTIFY, .notify = {.action = NI_CONTEXTUPDATED, .index = 0, .value = IMC_SETCANDIDATEPOS}, }, - {.todo = TRUE}, + {0}, }; CANDIDATEFORM cand_form, expect_form = { From 5e380fa6e1628b6f93213217b004c30ab9cc6515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 8 Apr 2023 12:02:21 +0200 Subject: [PATCH 1863/2777] imm32: Use INPUTCONTEXT directly in ImmGetCandidateWindow. (cherry picked from commit 01677af42ae683d3b86e68e3a7cc71b1d68844ed) --- dlls/imm32/imm.c | 24 ++++++++++-------------- dlls/imm32/tests/imm32.c | 14 +++++++------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index aa63be82e4b..62b95eba77a 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1390,25 +1390,21 @@ DWORD WINAPI ImmGetCandidateListW( /*********************************************************************** * ImmGetCandidateWindow (IMM32.@) */ -BOOL WINAPI ImmGetCandidateWindow( - HIMC hIMC, DWORD dwIndex, LPCANDIDATEFORM lpCandidate) +BOOL WINAPI ImmGetCandidateWindow( HIMC himc, DWORD index, CANDIDATEFORM *candidate ) { - struct imc *data = get_imc_data( hIMC ); - - TRACE("%p, %ld, %p\n", hIMC, dwIndex, lpCandidate); - - if (!data || !lpCandidate) - return FALSE; + INPUTCONTEXT *ctx; + BOOL ret = TRUE; - if (dwIndex >= ARRAY_SIZE(data->IMC.cfCandForm)) - return FALSE; + TRACE( "himc %p, index %lu, candidate %p\n", himc, index, candidate ); - if (data->IMC.cfCandForm[dwIndex].dwIndex != dwIndex) - return FALSE; + if (!candidate) return FALSE; - *lpCandidate = data->IMC.cfCandForm[dwIndex]; + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + if (ctx->cfCandForm[index].dwIndex == -1) ret = FALSE; + else *candidate = ctx->cfCandForm[index]; + ImmUnlockIMC( himc ); - return TRUE; + return ret; } /*********************************************************************** diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index cf6c521e52f..a623cabef7b 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -5653,21 +5653,21 @@ static void test_ImmGetCandidateWindow(void) ok_eq( 0xcdcdcdcd, cand_form.dwIndex, UINT, "%u" ); ok_ret( 0, ImmGetCandidateWindow( default_himc, 3, &cand_form ) ); ok_eq( 0xcdcdcdcd, cand_form.dwIndex, UINT, "%u" ); - todo_wine ok_ret( 1, ImmGetCandidateWindow( default_himc, 4, &cand_form ) ); + ok_ret( 1, ImmGetCandidateWindow( default_himc, 4, &cand_form ) ); ok_seq( empty_sequence ); ok_ret( 0, ImmGetCandidateWindow( himc, 0, &cand_form ) ); ok_seq( empty_sequence ); - todo_wine ok_seq( empty_sequence ); + ok_seq( empty_sequence ); ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); ctx->cfCandForm[0] = expect_form; - todo_wine ok_ret( 1, ImmGetCandidateWindow( himc, 0, &cand_form ) ); - todo_wine check_candidate_form( &cand_form, &expect_form ); + ok_ret( 1, ImmGetCandidateWindow( himc, 0, &cand_form ) ); + check_candidate_form( &cand_form, &expect_form ); ok_seq( empty_sequence ); - todo_wine ok_seq( empty_sequence ); + ok_seq( empty_sequence ); ok( !!ctx, "ImmLockIMC failed, error %lu\n", GetLastError() ); ctx->cfCandForm[0].dwIndex = -1; @@ -6481,8 +6481,8 @@ static void test_ImmSetCandidateWindow(void) memset( &cand_form, 0xcd, sizeof(cand_form) ); ok_ret( 0, ImmGetCandidateWindow( himc, 0, &cand_form ) ); ok_eq( 0xcdcdcdcd, cand_form.dwStyle, UINT, "%#x" ); - todo_wine ok_ret( 1, ImmGetCandidateWindow( himc, 1, &cand_form ) ); - todo_wine check_candidate_form( &cand_form, &expect_form ); + ok_ret( 1, ImmGetCandidateWindow( himc, 1, &cand_form ) ); + check_candidate_form( &cand_form, &expect_form ); ok_ret( 1, ImmGetCandidateWindow( himc, 2, &cand_form ) ); check_candidate_form( &cand_form, &expect_form ); ok_seq( empty_sequence ); From 294224b411ff31d57567d95486722edacf3ca024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 31 Mar 2023 12:01:32 +0200 Subject: [PATCH 1864/2777] imm32/tests: Test that ImmSetOpenStatus doesn't set IMMGWL_IMC. (cherry picked from commit 3e3706adccf45757593c2c5206bd4ffeb9801077) --- dlls/imm32/tests/imm32.c | 92 ++++++++++++++++++++++++++-------------- 1 file changed, 61 insertions(+), 31 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index a623cabef7b..a062604f116 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4238,6 +4238,37 @@ static void test_ImmUnregisterWord( BOOL unicode ) winetest_pop_context(); } +struct ime_windows +{ + HWND ime_hwnd; + HWND ime_ui_hwnd; +}; + +static BOOL CALLBACK enum_thread_ime_windows( HWND hwnd, LPARAM lparam ) +{ + struct ime_windows *params = (void *)lparam; + WCHAR buffer[256]; + UINT ret; + + ime_trace( "hwnd %p, lparam %#Ix\n", hwnd, lparam ); + + ret = RealGetWindowClassW( hwnd, buffer, ARRAY_SIZE(buffer) ); + ok( ret, "RealGetWindowClassW returned %#x\n", ret ); + + if (!wcscmp( buffer, L"IME" )) + { + ok( !params->ime_hwnd, "Found extra IME window %p\n", hwnd ); + params->ime_hwnd = hwnd; + } + if (!wcscmp( buffer, ime_ui_class.lpszClassName )) + { + ok( !params->ime_ui_hwnd, "Found extra IME UI window %p\n", hwnd ); + params->ime_ui_hwnd = hwnd; + } + + return TRUE; +} + static void test_ImmSetConversionStatus(void) { const struct ime_call set_conversion_status_0_seq[] = @@ -4473,8 +4504,10 @@ static void test_ImmSetOpenStatus(void) {0}, }; HKL hkl; + struct ime_windows ime_windows = {0}; DWORD old_status, status; INPUTCONTEXT *ctx; + HIMC himc; ok_ret( 0, ImmGetOpenStatus( 0 ) ); old_status = ImmGetOpenStatus( default_himc ); @@ -4521,6 +4554,22 @@ static void test_ImmSetOpenStatus(void) ok_eq( 0xdeadbeef, status, UINT, "%#x" ); ok_eq( 0xdeadbeef, ctx->fOpen, UINT, "%#x" ); + + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) ); + ok_ne( NULL, ime_windows.ime_hwnd, HWND, "%p" ); + ok_ne( NULL, ime_windows.ime_ui_hwnd, HWND, "%p" ); + ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); + ok_ret( 1, ImmSetOpenStatus( himc, TRUE ) ); + todo_wine ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); + ok_ret( 1, ImmSetOpenStatus( himc, FALSE ) ); + todo_wine ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); + ok_ret( 1, ImmDestroyContext( himc ) ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + ok_ret( 1, ImmSetOpenStatus( default_himc, 0xdeadbeef ) ); ok_seq( empty_sequence ); @@ -4640,37 +4689,6 @@ static void test_ImmProcessKey(void) ok_ret( 1, DestroyWindow( hwnd ) ); } -struct ime_windows -{ - HWND ime_hwnd; - HWND ime_ui_hwnd; -}; - -static BOOL CALLBACK enum_thread_ime_windows( HWND hwnd, LPARAM lparam ) -{ - struct ime_windows *params = (void *)lparam; - WCHAR buffer[256]; - UINT ret; - - ime_trace( "hwnd %p, lparam %#Ix\n", hwnd, lparam ); - - ret = RealGetWindowClassW( hwnd, buffer, ARRAY_SIZE(buffer) ); - ok( ret, "RealGetWindowClassW returned %#x\n", ret ); - - if (!wcscmp( buffer, L"IME" )) - { - ok( !params->ime_hwnd, "Found extra IME window %p\n", hwnd ); - params->ime_hwnd = hwnd; - } - if (!wcscmp( buffer, ime_ui_class.lpszClassName )) - { - ok( !params->ime_ui_hwnd, "Found extra IME UI window %p\n", hwnd ); - params->ime_ui_hwnd = hwnd; - } - - return TRUE; -} - static void test_ImmActivateLayout(void) { const struct ime_call activate_seq[] = @@ -5231,6 +5249,7 @@ static void test_ImmSetActiveContext(void) {0}, }; HKL hkl; + struct ime_windows ime_windows = {0}; HIMC himc; ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; @@ -5247,6 +5266,10 @@ static void test_ImmSetActiveContext(void) memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; + ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) ); + ok_ne( NULL, ime_windows.ime_hwnd, HWND, "%p" ); + ok_ne( NULL, ime_windows.ime_ui_hwnd, HWND, "%p" ); + SetLastError( 0xdeadbeef ); ok_ret( 1, ImmSetActiveContext( hwnd, default_himc, TRUE ) ); ok_seq( activate_0_seq ); @@ -5265,6 +5288,13 @@ static void test_ImmSetActiveContext(void) ok_ret( 1, ImmSetActiveContext( hwnd, himc, TRUE ) ); activate_1_seq[0].himc = himc; ok_seq( activate_1_seq ); + + ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); + ok_ret( 1, ImmSetActiveContext( hwnd, himc, TRUE ) ); + ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); + ok_eq( default_himc, ImmAssociateContext( hwnd, himc ), HIMC, "%p" ); + todo_wine ok_eq( himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); + ok_ret( 1, ImmDestroyContext( himc ) ); ok_ret( 1, ImmActivateLayout( default_hkl ) ); From 1d755733efdd74d1290f3106e0454df4380c9a6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 17 Apr 2023 09:17:31 +0200 Subject: [PATCH 1865/2777] imm32/tests: Check IME UI visibility vs ImmSetCompositionWindow. (cherry picked from commit c8d560377692132740a6fb404f8a5d23da43eb0b) --- dlls/imm32/tests/imm32.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index a062604f116..5542887c168 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2907,6 +2907,8 @@ static void ok_seq_( const char *file, int line, const struct ime_call *expected ime_call_count = 0; } +static BOOL check_WM_SHOWWINDOW; + static BOOL ignore_message( UINT msg ) { switch (msg) @@ -2925,6 +2927,8 @@ static BOOL ignore_message( UINT msg ) case WM_IME_KEYDOWN: case WM_IME_KEYUP: return FALSE; + case WM_SHOWWINDOW: + return !check_WM_SHOWWINDOW; default: return TRUE; } @@ -5269,11 +5273,13 @@ static void test_ImmSetActiveContext(void) ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) ); ok_ne( NULL, ime_windows.ime_hwnd, HWND, "%p" ); ok_ne( NULL, ime_windows.ime_ui_hwnd, HWND, "%p" ); + ok_ret( 0, IsWindowVisible( ime_windows.ime_ui_hwnd ) ); SetLastError( 0xdeadbeef ); ok_ret( 1, ImmSetActiveContext( hwnd, default_himc, TRUE ) ); ok_seq( activate_0_seq ); ok_ret( 0, GetLastError() ); + ok_ret( 0, IsWindowVisible( ime_windows.ime_ui_hwnd ) ); ok_ret( 1, ImmSetActiveContext( hwnd, default_himc, TRUE ) ); ok_seq( activate_0_seq ); ok_ret( 1, ImmSetActiveContext( hwnd, default_himc, FALSE ) ); @@ -5291,9 +5297,11 @@ static void test_ImmSetActiveContext(void) ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); ok_ret( 1, ImmSetActiveContext( hwnd, himc, TRUE ) ); + ok_ret( 0, IsWindowVisible( ime_windows.ime_ui_hwnd ) ); ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); ok_eq( default_himc, ImmAssociateContext( hwnd, himc ), HIMC, "%p" ); todo_wine ok_eq( himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); + ok_ret( 0, IsWindowVisible( ime_windows.ime_ui_hwnd ) ); ok_ret( 1, ImmDestroyContext( himc ) ); @@ -6124,6 +6132,7 @@ static void test_ImmSetCompositionWindow(void) .ptCurrentPos = {.x = 123, .y = 456}, .rcArea = {.left = 1, .top = 2, .right = 3, .bottom = 4}, }; + struct ime_windows ime_windows = {0}; INPUTCONTEXT *ctx; HIMC himc; HKL hkl; @@ -6149,6 +6158,10 @@ static void test_ImmSetCompositionWindow(void) set_composition_window_0_seq[0].himc = himc; set_composition_window_1_seq[0].himc = himc; + ok_ret( 1, EnumThreadWindows( GetCurrentThreadId(), enum_thread_ime_windows, (LPARAM)&ime_windows ) ); + ok_ne( NULL, ime_windows.ime_hwnd, HWND, "%p" ); + ok_ne( NULL, ime_windows.ime_ui_hwnd, HWND, "%p" ); + ctx->cfCompForm = expect_form; ctx->fdwInit = ~INIT_COMPFORM; memset( &comp_form, 0xcd, sizeof(comp_form) ); @@ -6158,14 +6171,27 @@ static void test_ImmSetCompositionWindow(void) ok_ret( 1, ImmGetCompositionWindow( himc, &comp_form ) ); check_composition_form( &comp_form, &expect_form ); ok_seq( empty_sequence ); + ok_ret( 0, IsWindowVisible( ime_windows.ime_ui_hwnd ) ); + + ok_ret( 0, ShowWindow( ime_windows.ime_ui_hwnd, SW_SHOWNOACTIVATE ) ); + process_messages(); + ok_seq( empty_sequence ); + check_WM_SHOWWINDOW = TRUE; ctx->hWnd = hwnd; ctx->fdwInit = 0; memset( &comp_form, 0xcd, sizeof(comp_form) ); ok_ret( 1, ImmSetCompositionWindow( himc, &comp_form ) ); - ok_seq( set_composition_window_0_seq ); + process_messages(); + todo_wine ok_seq( set_composition_window_0_seq ); ok_eq( INIT_COMPFORM, ctx->fdwInit, UINT, "%u" ); check_composition_form( &ctx->cfCompForm, &comp_form ); + ok_ret( 1, IsWindowVisible( ime_windows.ime_ui_hwnd ) ); + check_WM_SHOWWINDOW = FALSE; + + ShowWindow( ime_windows.ime_ui_hwnd, SW_HIDE ); + process_messages(); + ok_seq( empty_sequence ); ok_ret( 1, ImmSetCompositionWindow( himc, &expect_form ) ); ok_seq( set_composition_window_0_seq ); From 72d663272bb86fceabfc871a83c6f1a422862fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 17 Apr 2023 09:47:01 +0200 Subject: [PATCH 1866/2777] imm32/tests: Check ImmSetActiveContext effect on INPUTCONTEXT hWnd member. (cherry picked from commit 53ae92fab44ca632c71300d1ad3b0cd766f0fd57) --- dlls/imm32/tests/imm32.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 5542887c168..6d5a751b837 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -5240,6 +5240,18 @@ static void test_ImmSetActiveContext(void) }, {0}, }; + struct ime_call deactivate_2_seq[] = + { + { + .hkl = expect_ime, .himc = 0/*himc*/, + .func = IME_SET_ACTIVE_CONTEXT, .set_active_context = {.flag = 0} + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_SETCONTEXT, .wparam = 0, .lparam = ISC_SHOWUIALL} + }, + {0}, + }; struct ime_call activate_1_seq[] = { { @@ -5254,6 +5266,7 @@ static void test_ImmSetActiveContext(void) }; HKL hkl; struct ime_windows ime_windows = {0}; + INPUTCONTEXT *ctx; HIMC himc; ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; @@ -5287,6 +5300,10 @@ static void test_ImmSetActiveContext(void) himc = ImmCreateContext(); ok_ne( NULL, himc, HIMC, "%p" ); + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + ok_eq( 0, ctx->hWnd, HWND, "%p" ); + ok_ret( 1, ImmSetActiveContext( hwnd, himc, FALSE ) ); deactivate_1_seq[3].himc = himc; deactivate_1_seq[4].himc = himc; @@ -5295,14 +5312,35 @@ static void test_ImmSetActiveContext(void) activate_1_seq[0].himc = himc; ok_seq( activate_1_seq ); + ctx->hWnd = (HWND)0xdeadbeef; + ok_ret( 1, ImmSetActiveContext( hwnd, himc, FALSE ) ); + todo_wine ok_eq( (HWND)0xdeadbeef, ctx->hWnd, HWND, "%p" ); + deactivate_2_seq[0].himc = himc; + ok_seq( deactivate_2_seq ); + + ctx->hWnd = 0; + ok_ret( 1, ImmSetActiveContext( hwnd, himc, TRUE ) ); + ok_eq( hwnd, ctx->hWnd, HWND, "%p" ); + activate_1_seq[0].himc = himc; + ok_seq( activate_1_seq ); + ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); ok_ret( 1, ImmSetActiveContext( hwnd, himc, TRUE ) ); ok_ret( 0, IsWindowVisible( ime_windows.ime_ui_hwnd ) ); ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); + + ctx->hWnd = 0; ok_eq( default_himc, ImmAssociateContext( hwnd, himc ), HIMC, "%p" ); todo_wine ok_eq( himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); ok_ret( 0, IsWindowVisible( ime_windows.ime_ui_hwnd ) ); + ok_eq( hwnd, ctx->hWnd, HWND, "%p" ); + + ctx->hWnd = (HWND)0xdeadbeef; + ok_eq( himc, ImmGetContext( hwnd ), HIMC, "%p" ); + todo_wine ok_eq( (HWND)0xdeadbeef, ctx->hWnd, HWND, "%p" ); + ok_ret( 1, ImmReleaseContext( hwnd, himc ) ); + ok_ret( 1, ImmUnlockIMC( himc ) ); ok_ret( 1, ImmDestroyContext( himc ) ); ok_ret( 1, ImmActivateLayout( default_hkl ) ); From 490509f86ed72e0342729c09375dd8c0e5b1596c Mon Sep 17 00:00:00 2001 From: Byeongsik Jeon Date: Mon, 17 Apr 2023 06:28:41 +0900 Subject: [PATCH 1867/2777] imm32: Stop updating INPUTCONTEXT hWnd member in ImmGetContext. (cherry picked from commit 5ef8554ee9e607def521a07eafa390ad321bfccb) --- dlls/imm32/imm.c | 3 +-- dlls/imm32/tests/imm32.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 62b95eba77a..0bd71244203 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1787,8 +1787,7 @@ HIMC WINAPI ImmGetContext(HWND hWnd) if (rc) { struct imc *data = get_imc_data( rc ); - if (data) data->IMC.hWnd = hWnd; - else rc = 0; + if (!data) rc = 0; } TRACE("returning %p\n", rc); diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 6d5a751b837..d9f8c7c446a 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -5337,7 +5337,7 @@ static void test_ImmSetActiveContext(void) ctx->hWnd = (HWND)0xdeadbeef; ok_eq( himc, ImmGetContext( hwnd ), HIMC, "%p" ); - todo_wine ok_eq( (HWND)0xdeadbeef, ctx->hWnd, HWND, "%p" ); + ok_eq( (HWND)0xdeadbeef, ctx->hWnd, HWND, "%p" ); ok_ret( 1, ImmReleaseContext( hwnd, himc ) ); ok_ret( 1, ImmUnlockIMC( himc ) ); From 251ce39e57c7db47c34af7027bb7e5911262b632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 17 Apr 2023 10:08:58 +0200 Subject: [PATCH 1868/2777] imm32: Forward ImmGetContext to NtUserGetWindowInputContext directly. (cherry picked from commit 422ee56c1b1f489d3a7a7aab97950ee93cc91549) --- dlls/imm32/imm.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 0bd71244203..5a32138561c 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1776,23 +1776,10 @@ BOOL WINAPI ImmGetCompositionWindow( HIMC himc, COMPOSITIONFORM *composition ) * ImmGetContext (IMM32.@) * */ -HIMC WINAPI ImmGetContext(HWND hWnd) +HIMC WINAPI ImmGetContext( HWND hwnd ) { - HIMC rc; - - TRACE("%p\n", hWnd); - - rc = NtUserGetWindowInputContext(hWnd); - - if (rc) - { - struct imc *data = get_imc_data( rc ); - if (!data) rc = 0; - } - - TRACE("returning %p\n", rc); - - return rc; + TRACE( "hwnd %p\n", hwnd ); + return NtUserGetWindowInputContext( hwnd ); } /*********************************************************************** From 7e387a96666233c181a058cb74d477a30844bced Mon Sep 17 00:00:00 2001 From: Byeong-Sik Jeon Date: Mon, 17 Apr 2023 10:10:28 +0200 Subject: [PATCH 1869/2777] imm32: Avoid updating INPUTCONTEXT hWnd on ImmSetActiveContext deactivation. (cherry picked from commit 93e5d7b317e9a9dc90a95dc731e5e07e8b1ec776) --- dlls/imm32/imm.c | 2 +- dlls/imm32/tests/imm32.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 5a32138561c..2fd247f36c7 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -852,7 +852,7 @@ BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate) if (data) { - data->IMC.hWnd = activate ? hwnd : NULL; + if (activate) data->IMC.hWnd = hwnd; if ((ime = imc_select_ime( data ))) ime->pImeSetActiveContext( himc, activate ); } diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index d9f8c7c446a..92b59b7d005 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -5314,7 +5314,7 @@ static void test_ImmSetActiveContext(void) ctx->hWnd = (HWND)0xdeadbeef; ok_ret( 1, ImmSetActiveContext( hwnd, himc, FALSE ) ); - todo_wine ok_eq( (HWND)0xdeadbeef, ctx->hWnd, HWND, "%p" ); + ok_eq( (HWND)0xdeadbeef, ctx->hWnd, HWND, "%p" ); deactivate_2_seq[0].himc = himc; ok_seq( deactivate_2_seq ); From 13c8b541adae915cb10745b086f623fb44d3aca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 17 Apr 2023 09:35:04 +0200 Subject: [PATCH 1870/2777] user32: Move WM_IME_COMPOSITION DefWindowProc handlers in separate helpers. (cherry picked from commit 45b096abb489f0a92b03a73328de7ca9958a4322) --- dlls/user32/defwnd.c | 110 +++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/dlls/user32/defwnd.c b/dlls/user32/defwnd.c index b4b42b86ae1..6c45f89e392 100644 --- a/dlls/user32/defwnd.c +++ b/dlls/user32/defwnd.c @@ -25,6 +25,59 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); +static void default_ime_compositionW( HWND hwnd, WPARAM wparam, LPARAM lparam ) +{ + WCHAR *buf = NULL; + LONG size, i; + HIMC himc; + + if (!(lparam & GCS_RESULTSTR) || !(himc = ImmGetContext( hwnd ))) return; + + if ((size = ImmGetCompositionStringW( himc, GCS_RESULTSTR, NULL, 0 ))) + { + if (!(buf = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) size = 0; + else size = ImmGetCompositionStringW( himc, GCS_RESULTSTR, buf, size * sizeof(WCHAR) ); + } + ImmReleaseContext( hwnd, himc ); + + for (i = 0; i < size / sizeof(WCHAR); i++) + SendMessageW( hwnd, WM_IME_CHAR, buf[i], 1 ); + HeapFree( GetProcessHeap(), 0, buf ); +} + +static void default_ime_compositionA( HWND hwnd, WPARAM wparam, LPARAM lparam ) +{ + unsigned char lead = 0; + char *buf = NULL; + LONG size, i; + HIMC himc; + + if (!(lparam & GCS_RESULTSTR) || !(himc = ImmGetContext( hwnd ))) return; + + if ((size = ImmGetCompositionStringA( himc, GCS_RESULTSTR, NULL, 0 ))) + { + if (!(buf = HeapAlloc( GetProcessHeap(), 0, size ))) size = 0; + else size = ImmGetCompositionStringA( himc, GCS_RESULTSTR, buf, size ); + } + ImmReleaseContext( hwnd, himc ); + + for (i = 0; i < size; i++) + { + unsigned char c = buf[i]; + if (!lead) + { + if (IsDBCSLeadByte( c )) lead = c; + else SendMessageA( hwnd, WM_IME_CHAR, c, 1 ); + } + else + { + SendMessageA( hwnd, WM_IME_CHAR, MAKEWORD(c, lead), 1 ); + lead = 0; + } + } + + HeapFree( GetProcessHeap(), 0, buf ); +} /*********************************************************************** * DefWindowProcA (USER32.@) @@ -66,41 +119,7 @@ LRESULT WINAPI DefWindowProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam break; case WM_IME_COMPOSITION: - if (lParam & GCS_RESULTSTR) - { - LONG size, i; - unsigned char lead = 0; - char *buf = NULL; - HIMC himc = ImmGetContext( hwnd ); - - if (himc) - { - if ((size = ImmGetCompositionStringA( himc, GCS_RESULTSTR, NULL, 0 ))) - { - if (!(buf = HeapAlloc( GetProcessHeap(), 0, size ))) size = 0; - else size = ImmGetCompositionStringA( himc, GCS_RESULTSTR, buf, size ); - } - ImmReleaseContext( hwnd, himc ); - - for (i = 0; i < size; i++) - { - unsigned char c = buf[i]; - if (!lead) - { - if (IsDBCSLeadByte( c )) - lead = c; - else - SendMessageA( hwnd, WM_IME_CHAR, c, 1 ); - } - else - { - SendMessageA( hwnd, WM_IME_CHAR, MAKEWORD(c, lead), 1 ); - lead = 0; - } - } - HeapFree( GetProcessHeap(), 0, buf ); - } - } + default_ime_compositionA( hwnd, wParam, lParam ); /* fall through */ default: @@ -159,26 +178,7 @@ LRESULT WINAPI DefWindowProcW( break; case WM_IME_COMPOSITION: - if (lParam & GCS_RESULTSTR) - { - LONG size, i; - WCHAR *buf = NULL; - HIMC himc = ImmGetContext( hwnd ); - - if (himc) - { - if ((size = ImmGetCompositionStringW( himc, GCS_RESULTSTR, NULL, 0 ))) - { - if (!(buf = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) size = 0; - else size = ImmGetCompositionStringW( himc, GCS_RESULTSTR, buf, size * sizeof(WCHAR) ); - } - ImmReleaseContext( hwnd, himc ); - - for (i = 0; i < size / sizeof(WCHAR); i++) - SendMessageW( hwnd, WM_IME_CHAR, buf[i], 1 ); - HeapFree( GetProcessHeap(), 0, buf ); - } - } + default_ime_compositionW( hwnd, wParam, lParam ); /* fall through */ default: From 3e4ef1e71ac66b2c0285a2f233abf0d301214291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 17 Apr 2023 09:37:58 +0200 Subject: [PATCH 1871/2777] user32: Ignore WM_IME_COMPOSITION from the IME UI window in DefWindowProc. As in 6fd3bd9b62f405a54db29dc5a72805063a6099ca. (cherry picked from commit 6fb47669476a2cdd982b5e3a461d0d97ebf74dec) --- dlls/user32/defwnd.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dlls/user32/defwnd.c b/dlls/user32/defwnd.c index 6c45f89e392..60afec4e7c6 100644 --- a/dlls/user32/defwnd.c +++ b/dlls/user32/defwnd.c @@ -119,8 +119,13 @@ LRESULT WINAPI DefWindowProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam break; case WM_IME_COMPOSITION: + { + HWND ime_hwnd = NtUserGetDefaultImeWindow( hwnd ); + if (!ime_hwnd || ime_hwnd == NtUserGetParent( hwnd )) break; + default_ime_compositionA( hwnd, wParam, lParam ); /* fall through */ + } default: result = NtUserMessageCall( hwnd, msg, wParam, lParam, 0, NtUserDefWindowProc, TRUE ); @@ -178,8 +183,13 @@ LRESULT WINAPI DefWindowProcW( break; case WM_IME_COMPOSITION: + { + HWND ime_hwnd = NtUserGetDefaultImeWindow( hwnd ); + if (!ime_hwnd || ime_hwnd == NtUserGetParent( hwnd )) break; + default_ime_compositionW( hwnd, wParam, lParam ); /* fall through */ + } default: result = NtUserMessageCall( hwnd, msg, wParam, lParam, 0, NtUserDefWindowProc, FALSE ); From 5a2b82a4768ae92eaab3c44466c5de7f0a1b6642 Mon Sep 17 00:00:00 2001 From: Michael Stefaniuc Date: Wed, 19 Apr 2023 19:28:53 +0200 Subject: [PATCH 1872/2777] win32u: Use ARRAY_SIZE() instead of open coding it. (cherry picked from commit 5cae9680f44eee6a97cb76fdf5c56d35d5b2ee14) --- dlls/win32u/input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 289c8c2fde4..24321d6d5a2 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -398,7 +398,7 @@ static const KBDTABLES kbdus_tables = .pKeyNames = (VSC_LPWSTR *)key_names, .pKeyNamesExt = (VSC_LPWSTR *)key_names_ext, .pusVSCtoVK = (USHORT *)vsc_to_vk, - .bMaxVSCtoVK = sizeof(vsc_to_vk) / sizeof(vsc_to_vk[0]), + .bMaxVSCtoVK = ARRAY_SIZE(vsc_to_vk), .pVSCtoVK_E0 = (VSC_VK *)vsc_to_vk_e0, .pVSCtoVK_E1 = (VSC_VK *)vsc_to_vk_e1, .fLocaleFlags = MAKELONG(0, KBD_VERSION), From 1baab3764b5780649dba0594bc24a592b93351cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 14 Apr 2023 09:17:17 +0200 Subject: [PATCH 1873/2777] imm32: Don't hide/show IME UI window in ImmSetCompositionWindow. (cherry picked from commit 2fda6abfc4ecd1ddbac658fd59b3a4d85d516a2d) --- dlls/imm32/imm.c | 10 ---------- dlls/imm32/tests/imm32.c | 2 +- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 2fd247f36c7..554cc00b457 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2629,9 +2629,7 @@ BOOL WINAPI ImmSetCompositionStringW( */ BOOL WINAPI ImmSetCompositionWindow( HIMC himc, COMPOSITIONFORM *composition ) { - BOOL reshow = FALSE; INPUTCONTEXT *ctx; - HWND ui_hwnd; TRACE( "himc %p, composition %s\n", himc, debugstr_composition( composition ) ); @@ -2641,14 +2639,6 @@ BOOL WINAPI ImmSetCompositionWindow( HIMC himc, COMPOSITIONFORM *composition ) ctx->cfCompForm = *composition; ctx->fdwInit |= INIT_COMPFORM; - if ((ui_hwnd = get_ime_ui_window()) && IsWindowVisible( ui_hwnd )) - { - reshow = TRUE; - ShowWindow( ui_hwnd, SW_HIDE ); - } - - if (ui_hwnd && reshow) ShowWindow( ui_hwnd, SW_SHOWNOACTIVATE ); - ImmNotifyIME( himc, NI_CONTEXTUPDATED, 0, IMC_SETCOMPOSITIONWINDOW ); SendMessageW( ctx->hWnd, WM_IME_NOTIFY, IMN_SETCOMPOSITIONWINDOW, 0 ); diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 92b59b7d005..9857583fafa 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -6221,7 +6221,7 @@ static void test_ImmSetCompositionWindow(void) memset( &comp_form, 0xcd, sizeof(comp_form) ); ok_ret( 1, ImmSetCompositionWindow( himc, &comp_form ) ); process_messages(); - todo_wine ok_seq( set_composition_window_0_seq ); + ok_seq( set_composition_window_0_seq ); ok_eq( INIT_COMPFORM, ctx->fdwInit, UINT, "%u" ); check_composition_form( &ctx->cfCompForm, &comp_form ); ok_ret( 1, IsWindowVisible( ime_windows.ime_ui_hwnd ) ); From 6cb9c3d3c1b3f7213c7beef8d56903d9d6288a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 14 Apr 2023 09:32:30 +0200 Subject: [PATCH 1874/2777] imm32: Move ImmAssociateContext(Ex) around. (cherry picked from commit b5c30f8ef26b1ae45ea401a63f4534cb59604d1a) --- dlls/imm32/imm.c | 116 +++++++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 60 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 554cc00b457..f7304897f15 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -865,66 +865,6 @@ BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate) return TRUE; } -/*********************************************************************** - * ImmAssociateContext (IMM32.@) - */ -HIMC WINAPI ImmAssociateContext(HWND hwnd, HIMC imc) -{ - HIMC old; - UINT ret; - - TRACE("(%p, %p):\n", hwnd, imc); - - old = NtUserGetWindowInputContext(hwnd); - ret = NtUserAssociateInputContext(hwnd, imc, 0); - if (ret == AICR_FOCUS_CHANGED) - { - ImmSetActiveContext(hwnd, old, FALSE); - ImmSetActiveContext(hwnd, imc, TRUE); - } - return ret == AICR_FAILED ? 0 : old; -} - - -/* - * Helper function for ImmAssociateContextEx - */ -static BOOL CALLBACK _ImmAssociateContextExEnumProc(HWND hwnd, LPARAM lParam) -{ - HIMC hImc = (HIMC)lParam; - ImmAssociateContext(hwnd,hImc); - return TRUE; -} - -/*********************************************************************** - * ImmAssociateContextEx (IMM32.@) - */ -BOOL WINAPI ImmAssociateContextEx(HWND hwnd, HIMC imc, DWORD flags) -{ - HIMC old; - UINT ret; - - TRACE("(%p, %p, 0x%lx):\n", hwnd, imc, flags); - - if (!hwnd) - return FALSE; - - if (flags == IACE_CHILDREN) - { - EnumChildWindows(hwnd, _ImmAssociateContextExEnumProc, (LPARAM)imc); - return TRUE; - } - - old = NtUserGetWindowInputContext(hwnd); - ret = NtUserAssociateInputContext(hwnd, imc, flags); - if (ret == AICR_FOCUS_CHANGED) - { - ImmSetActiveContext(hwnd, old, FALSE); - ImmSetActiveContext(hwnd, imc, TRUE); - } - return ret != AICR_FAILED; -} - /*********************************************************************** * ImmConfigureIMEA (IMM32.@) */ @@ -1065,6 +1005,62 @@ BOOL WINAPI ImmDestroyContext(HIMC hIMC) return IMM_DestroyContext(hIMC); } +/*********************************************************************** + * ImmAssociateContext (IMM32.@) + */ +HIMC WINAPI ImmAssociateContext( HWND hwnd, HIMC new_himc ) +{ + HIMC old_himc; + UINT ret; + + TRACE( "hwnd %p, new_himc %p\n", hwnd, new_himc ); + + old_himc = NtUserGetWindowInputContext( hwnd ); + ret = NtUserAssociateInputContext( hwnd, new_himc, 0 ); + if (ret == AICR_FOCUS_CHANGED) + { + ImmSetActiveContext( hwnd, old_himc, FALSE ); + ImmSetActiveContext( hwnd, new_himc, TRUE ); + } + + return ret == AICR_FAILED ? 0 : old_himc; +} + +static BOOL CALLBACK enum_associate_context( HWND hwnd, LPARAM lparam ) +{ + ImmAssociateContext( hwnd, (HIMC)lparam ); + return TRUE; +} + +/*********************************************************************** + * ImmAssociateContextEx (IMM32.@) + */ +BOOL WINAPI ImmAssociateContextEx( HWND hwnd, HIMC new_himc, DWORD flags ) +{ + HIMC old_himc; + UINT ret; + + TRACE( "hwnd %p, new_himc %p, flags %#lx\n", hwnd, new_himc, flags ); + + if (!hwnd) return FALSE; + + if (flags == IACE_CHILDREN) + { + EnumChildWindows( hwnd, enum_associate_context, (LPARAM)new_himc ); + return TRUE; + } + + old_himc = NtUserGetWindowInputContext( hwnd ); + ret = NtUserAssociateInputContext( hwnd, new_himc, flags ); + if (ret == AICR_FOCUS_CHANGED) + { + ImmSetActiveContext( hwnd, old_himc, FALSE ); + ImmSetActiveContext( hwnd, new_himc, TRUE ); + } + + return ret != AICR_FAILED; +} + struct enum_register_word_params_WtoA { REGISTERWORDENUMPROCA proc; From 21d363f0a3ced32df64e6d5accabbea46221a83c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 25 Apr 2023 11:36:13 +0200 Subject: [PATCH 1875/2777] imm32: Update IME UI window IMMGWL_IMC when focus or HIMC changes. (cherry picked from commit 920154672d49241512cac9c49f92ceadfec759c8) --- dlls/imm32/imm.c | 24 +++++++++++++++++------- dlls/imm32/tests/imm32.c | 6 +++--- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index f7304897f15..7d4f4b4c13f 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -972,11 +972,18 @@ static HWND get_ime_ui_window(void) { imc->ui_hwnd = CreateWindowExW( WS_EX_TOOLWINDOW, ime->ui_class, NULL, WS_POPUP, 0, 0, 1, 1, ImmGetDefaultIMEWnd( 0 ), 0, ime->module, 0 ); - SetWindowLongPtrW( imc->ui_hwnd, IMMGWL_IMC, (LONG_PTR)imc->handle ); + SetWindowLongPtrW( imc->ui_hwnd, IMMGWL_IMC, (LONG_PTR)NtUserGetWindowInputContext( GetFocus() ) ); } return imc->ui_hwnd; } +static void set_ime_ui_window_himc( HIMC himc ) +{ + HWND hwnd; + if (!(hwnd = get_ime_ui_window())) return; + SetWindowLongPtrW( hwnd, IMMGWL_IMC, (LONG_PTR)himc ); +} + /*********************************************************************** * ImmCreateContext (IMM32.@) */ @@ -1021,6 +1028,7 @@ HIMC WINAPI ImmAssociateContext( HWND hwnd, HIMC new_himc ) { ImmSetActiveContext( hwnd, old_himc, FALSE ); ImmSetActiveContext( hwnd, new_himc, TRUE ); + if (hwnd == GetFocus()) set_ime_ui_window_himc( new_himc ); } return ret == AICR_FAILED ? 0 : old_himc; @@ -1056,6 +1064,7 @@ BOOL WINAPI ImmAssociateContextEx( HWND hwnd, HIMC new_himc, DWORD flags ) { ImmSetActiveContext( hwnd, old_himc, FALSE ); ImmSetActiveContext( hwnd, new_himc, TRUE ); + if (hwnd == GetFocus()) set_ime_ui_window_himc( new_himc ); } return ret != AICR_FAILED; @@ -2683,15 +2692,12 @@ BOOL WINAPI ImmSetConversionStatus( HIMC himc, DWORD conversion, DWORD sentence BOOL WINAPI ImmSetOpenStatus( HIMC himc, BOOL status ) { INPUTCONTEXT *ctx; - HWND ui_hwnd; TRACE( "himc %p, status %u\n", himc, status ); if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; if (!(ctx = ImmLockIMC( himc ))) return FALSE; - if ((ui_hwnd = get_ime_ui_window())) SetWindowLongPtrW( ui_hwnd, IMMGWL_IMC, (LONG_PTR)himc ); - if (status != ctx->fOpen) { ctx->fOpen = status; @@ -3240,11 +3246,15 @@ static LRESULT ime_internal_msg( WPARAM wparam, LPARAM lparam) switch (wparam) { case IME_INTERNAL_ACTIVATE: + hwnd = (HWND)lparam; + himc = NtUserGetWindowInputContext( hwnd ); + ImmSetActiveContext( hwnd, himc, TRUE ); + set_ime_ui_window_himc( himc ); + break; case IME_INTERNAL_DEACTIVATE: hwnd = (HWND)lparam; - himc = ImmGetContext(hwnd); - ImmSetActiveContext(hwnd, himc, wparam == IME_INTERNAL_ACTIVATE); - ImmReleaseContext(hwnd, himc); + himc = NtUserGetWindowInputContext( hwnd ); + ImmSetActiveContext( hwnd, himc, FALSE ); break; case IME_INTERNAL_HKL_ACTIVATE: ImmEnumInputContext( 0, enum_activate_layout, 0 ); diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 9857583fafa..206d58ac9d8 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4566,9 +4566,9 @@ static void test_ImmSetOpenStatus(void) ok_ne( NULL, ime_windows.ime_ui_hwnd, HWND, "%p" ); ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); ok_ret( 1, ImmSetOpenStatus( himc, TRUE ) ); - todo_wine ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); + ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); ok_ret( 1, ImmSetOpenStatus( himc, FALSE ) ); - todo_wine ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); + ok_eq( default_himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); ok_ret( 1, ImmDestroyContext( himc ) ); memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; @@ -5331,7 +5331,7 @@ static void test_ImmSetActiveContext(void) ctx->hWnd = 0; ok_eq( default_himc, ImmAssociateContext( hwnd, himc ), HIMC, "%p" ); - todo_wine ok_eq( himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); + ok_eq( himc, (HIMC)GetWindowLongPtrW( ime_windows.ime_ui_hwnd, IMMGWL_IMC ), HIMC, "%p" ); ok_ret( 0, IsWindowVisible( ime_windows.ime_ui_hwnd ) ); ok_eq( hwnd, ctx->hWnd, HWND, "%p" ); From bcf505f6a93bb2079c687bd431fac1c6dc352419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 25 Apr 2023 12:05:07 +0200 Subject: [PATCH 1876/2777] imm32/tests: Add some ImmGenerateMessage tests. (cherry picked from commit 1d591d08fd253e8941a04262403df648039bd96f) --- dlls/imm32/tests/imm32.c | 105 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 206d58ac9d8..344729b9866 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -6612,6 +6612,109 @@ static void test_ImmSetCandidateWindow(void) ime_call_count = 0; } +static void test_ImmGenerateMessage(void) +{ + const struct ime_call generate_sequence[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_TEST_WIN, .message = {.msg = WM_IME_COMPOSITION, .wparam = 0, .lparam = GCS_COMPSTR}, + .todo = TRUE, + }, + { + .hkl = expect_ime, .himc = default_himc, + .func = MSG_IME_UI, .message = {.msg = WM_IME_COMPOSITION, .wparam = 0, .lparam = GCS_COMPSTR}, + .todo = TRUE, + }, + {0}, + }; + TRANSMSG *msgs, *tmp_msgs; + INPUTCONTEXT *ctx; + HIMC himc; + HKL hkl; + + ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; + + if (!(hkl = wineime_hkl)) return; + + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + todo_wine ok_ret( 4, ImmGetIMCCSize( ctx->hMsgBuf ) ); + ctx->hMsgBuf = ImmReSizeIMCC( ctx->hMsgBuf, sizeof(*msgs) ); + ok_ne( NULL, ctx->hMsgBuf, HIMCC, "%p" ); + + msgs = ImmLockIMCC( ctx->hMsgBuf ); + ok_ne( NULL, msgs, TRANSMSG *, "%p" ); + msgs[0].message = WM_IME_COMPOSITION; + msgs[0].wParam = 0; + msgs[0].lParam = GCS_COMPSTR; + ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) ); + + ctx->hWnd = 0; + ctx->dwNumMsgBuf = 0; + ok_ret( 1, ImmGenerateMessage( himc ) ); + ok_seq( empty_sequence ); + ok_ret( sizeof(*msgs), ImmGetIMCCSize( ctx->hMsgBuf ) ); + tmp_msgs = ImmLockIMCC( ctx->hMsgBuf ); + ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" ); + ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) ); + + ctx->dwNumMsgBuf = 1; + ok_ret( 1, ImmGenerateMessage( himc ) ); + todo_wine ok_seq( empty_sequence ); + ok_eq( 0, ctx->dwNumMsgBuf, UINT, "%u" ); + todo_wine ok_ret( sizeof(*msgs), ImmGetIMCCSize( ctx->hMsgBuf ) ); + tmp_msgs = ImmLockIMCC( ctx->hMsgBuf ); + todo_wine ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" ); + ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) ); + + ctx->hWnd = hwnd; + ctx->dwNumMsgBuf = 0; + ok_ret( 1, ImmGenerateMessage( himc ) ); + ok_seq( empty_sequence ); + todo_wine ok_ret( sizeof(*msgs), ImmGetIMCCSize( ctx->hMsgBuf ) ); + tmp_msgs = ImmLockIMCC( ctx->hMsgBuf ); + todo_wine ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" ); + ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) ); + if (!tmp_msgs) ctx->hMsgBuf = ImmReSizeIMCC( ctx->hMsgBuf, sizeof(*msgs) ); + + ctx->dwNumMsgBuf = 1; + ok_ret( 1, ImmGenerateMessage( himc ) ); + ok_seq( generate_sequence ); + ok_eq( 0, ctx->dwNumMsgBuf, UINT, "%u" ); + todo_wine ok_ret( sizeof(*msgs), ImmGetIMCCSize( ctx->hMsgBuf ) ); + tmp_msgs = ImmLockIMCC( ctx->hMsgBuf ); + todo_wine ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" ); + ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) ); + + tmp_msgs = ImmLockIMCC( ctx->hMsgBuf ); + todo_wine ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" ); + ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) ); + + ok_ret( 1, ImmUnlockIMC( himc ) ); + ok_ret( 1, ImmDestroyContext( himc ) ); + + ok_ret( 1, ImmActivateLayout( default_hkl ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + + ok_ret( 1, ImmFreeLayout( hkl ) ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); @@ -6674,6 +6777,8 @@ START_TEST(imm32) test_ImmSetCompositionFont( FALSE ); test_ImmSetCandidateWindow(); + test_ImmGenerateMessage(); + if (wineime_hkl) ime_cleanup( wineime_hkl, TRUE ); if (init()) From 4c3578a9a3380db9f74d67f89e897825b031d457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 25 Apr 2023 12:14:54 +0200 Subject: [PATCH 1877/2777] imm32: Send messages one by one in ImmGenerateMessage. (cherry picked from commit 08e2edce964ef6f58f3fd874bc5001f8b9ec0292) --- dlls/imm32/imm.c | 46 ++++++++++++---------------------------- dlls/imm32/tests/imm32.c | 23 +++++++++----------- 2 files changed, 24 insertions(+), 45 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 7d4f4b4c13f..dfe81ddaaf7 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -828,13 +828,6 @@ static void imc_post_message( struct imc *imc, TRANSMSG *message ) PostMessageW( target, message->message, message->wParam, message->lParam ); } -static void imc_send_message( struct imc *imc, TRANSMSG *message ) -{ - HWND target; - if (!(target = GetFocus()) && !(target = imc->IMC.hWnd)) return; - SendMessageW( target, message->message, message->wParam, message->lParam ); -} - /*********************************************************************** * ImmSetActiveContext (IMM32.@) */ @@ -3049,36 +3042,25 @@ DWORD WINAPI ImmGetIMCCSize(HIMCC imcc) /*********************************************************************** * ImmGenerateMessage(IMM32.@) */ -BOOL WINAPI ImmGenerateMessage(HIMC hIMC) +BOOL WINAPI ImmGenerateMessage( HIMC himc ) { - struct imc *data = get_imc_data( hIMC ); - - if (!data) - { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - - TRACE("%li messages queued\n",data->IMC.dwNumMsgBuf); - if (data->IMC.dwNumMsgBuf > 0) - { - LPTRANSMSG lpTransMsg; - HIMCC hMsgBuf; - DWORD i, dwNumMsgBuf; + INPUTCONTEXT *ctx; - /* We are going to detach our hMsgBuff so that if processing messages - generates new messages they go into a new buffer */ - hMsgBuf = data->IMC.hMsgBuf; - dwNumMsgBuf = data->IMC.dwNumMsgBuf; + TRACE( "himc %p\n", himc ); - data->IMC.hMsgBuf = ImmCreateIMCC(0); - data->IMC.dwNumMsgBuf = 0; + if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; + if (!(ctx = ImmLockIMC( himc ))) return FALSE; - lpTransMsg = ImmLockIMCC(hMsgBuf); - for (i = 0; i < dwNumMsgBuf; i++) imc_send_message( data, lpTransMsg + i ); - ImmUnlockIMCC(hMsgBuf); - ImmDestroyIMCC(hMsgBuf); + while (ctx->dwNumMsgBuf--) + { + TRANSMSG *msgs, msg; + if (!(msgs = ImmLockIMCC( ctx->hMsgBuf ))) return FALSE; + msg = msgs[0]; + memmove( msgs, msgs + 1, ctx->dwNumMsgBuf * sizeof(*msgs) ); + ImmUnlockIMCC( ctx->hMsgBuf ); + SendMessageW( ctx->hWnd, msg.message, msg.wParam, msg.lParam ); } + ctx->dwNumMsgBuf++; return TRUE; } diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 344729b9866..093b79ff86b 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -1322,8 +1322,8 @@ static void test_cross_thread_himc(void) ok_ret( 1, ImmGenerateMessage( himc[1] ) ); - todo_wine ok_ret( 0, ImmGenerateMessage( params.himc[0] ) ); - todo_wine ok_ret( 0, ImmGenerateMessage( params.himc[1] ) ); + ok_ret( 0, ImmGenerateMessage( params.himc[0] ) ); + ok_ret( 0, ImmGenerateMessage( params.himc[1] ) ); /* ImmAssociateContext should fail with cross thread HWND or HIMC */ @@ -6619,12 +6619,10 @@ static void test_ImmGenerateMessage(void) { .hkl = expect_ime, .himc = default_himc, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_COMPOSITION, .wparam = 0, .lparam = GCS_COMPSTR}, - .todo = TRUE, }, { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_COMPOSITION, .wparam = 0, .lparam = GCS_COMPSTR}, - .todo = TRUE, }, {0}, }; @@ -6673,34 +6671,33 @@ static void test_ImmGenerateMessage(void) ctx->dwNumMsgBuf = 1; ok_ret( 1, ImmGenerateMessage( himc ) ); - todo_wine ok_seq( empty_sequence ); + ok_seq( empty_sequence ); ok_eq( 0, ctx->dwNumMsgBuf, UINT, "%u" ); - todo_wine ok_ret( sizeof(*msgs), ImmGetIMCCSize( ctx->hMsgBuf ) ); + ok_ret( sizeof(*msgs), ImmGetIMCCSize( ctx->hMsgBuf ) ); tmp_msgs = ImmLockIMCC( ctx->hMsgBuf ); - todo_wine ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" ); + ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" ); ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) ); ctx->hWnd = hwnd; ctx->dwNumMsgBuf = 0; ok_ret( 1, ImmGenerateMessage( himc ) ); ok_seq( empty_sequence ); - todo_wine ok_ret( sizeof(*msgs), ImmGetIMCCSize( ctx->hMsgBuf ) ); + ok_ret( sizeof(*msgs), ImmGetIMCCSize( ctx->hMsgBuf ) ); tmp_msgs = ImmLockIMCC( ctx->hMsgBuf ); - todo_wine ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" ); + ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" ); ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) ); - if (!tmp_msgs) ctx->hMsgBuf = ImmReSizeIMCC( ctx->hMsgBuf, sizeof(*msgs) ); ctx->dwNumMsgBuf = 1; ok_ret( 1, ImmGenerateMessage( himc ) ); ok_seq( generate_sequence ); ok_eq( 0, ctx->dwNumMsgBuf, UINT, "%u" ); - todo_wine ok_ret( sizeof(*msgs), ImmGetIMCCSize( ctx->hMsgBuf ) ); + ok_ret( sizeof(*msgs), ImmGetIMCCSize( ctx->hMsgBuf ) ); tmp_msgs = ImmLockIMCC( ctx->hMsgBuf ); - todo_wine ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" ); + ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" ); ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) ); tmp_msgs = ImmLockIMCC( ctx->hMsgBuf ); - todo_wine ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" ); + ok_eq( msgs, tmp_msgs, TRANSMSG *, "%p" ); ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) ); ok_ret( 1, ImmUnlockIMC( himc ) ); From fabe5063d1e1ae5b8078266c2a924abfb705e064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 4 May 2023 11:23:08 +0200 Subject: [PATCH 1878/2777] riched20: Update the editor IME position on GCS_RESULTSTR. So that a GCS_RESULTSTR followed by GCS_COMPSTR, without interruping the composition, begins inserting the new composition text after the result instead of before it. (cherry picked from commit de45bc33a73eac5dbc3502b4a43cd48399507c73) --- dlls/riched20/editor.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c index c4b4d7e72be..e993646f5a3 100644 --- a/dlls/riched20/editor.c +++ b/dlls/riched20/editor.c @@ -4145,6 +4145,8 @@ LRESULT editor_handle_message( ME_TextEditor *editor, UINT msg, WPARAM wParam, if (dwIndex == GCS_COMPSTR) set_selection_cursors(editor,editor->imeStartIndex, editor->imeStartIndex + dwBufLen/sizeof(WCHAR)); + else + editor->imeStartIndex = ME_GetCursorOfs(&editor->pCursors[0]); } ME_ReleaseStyle(style); ME_CommitUndo(editor); From a752dcfcf3252d0be739736863269ae45f790d17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 1 May 2023 16:17:05 +0200 Subject: [PATCH 1879/2777] winex11: Rename preedit buffer and related variables. (cherry picked from commit cbe434299c9f65efb86b6e54c07be9a4b648bda7) --- dlls/winex11.drv/xim.c | 52 +++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index b7f5f696ba5..4372faed3d6 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -44,10 +44,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(xim); BOOL ximInComposeMode=FALSE; -/* moved here from imm32 for dll separation */ -static DWORD dwCompStringLength = 0; -static LPBYTE CompositionString = NULL; -static DWORD dwCompStringSize = 0; +static BYTE *ime_comp_buf; +static DWORD ime_comp_len; +static DWORD ime_comp_max; static XIMStyle input_style = 0; static XIMStyle input_style_req = XIMPreeditCallbacks | XIMStatusCallbacks; @@ -72,38 +71,36 @@ static const char *debugstr_xim_style( XIMStyle style ) return wine_dbg_sprintf( "%s", buffer ); } -static void X11DRV_ImmSetInternalString(UINT offset, UINT selLength, LPWSTR lpComp, UINT len) +static void xim_update_comp_string( UINT offset, UINT old_len, const WCHAR *text, UINT new_len ) { /* Composition strings are edited in chunks */ - unsigned int byte_length = len * sizeof(WCHAR); + unsigned int byte_length = new_len * sizeof(WCHAR); unsigned int byte_offset = offset * sizeof(WCHAR); - unsigned int byte_selection = selLength * sizeof(WCHAR); + unsigned int byte_selection = old_len * sizeof(WCHAR); int byte_expansion = byte_length - byte_selection; - LPBYTE ptr_new; + BYTE *ptr_new; - TRACE("( %i, %i, %p, %d):\n", offset, selLength, lpComp, len ); + TRACE( "(%i, %i, %p, %d):\n", offset, old_len, text, new_len ); - if (byte_expansion + dwCompStringLength >= dwCompStringSize) + if (byte_expansion + ime_comp_len >= ime_comp_max) { - ptr_new = realloc( CompositionString, dwCompStringSize + byte_expansion ); - if (ptr_new == NULL) + if (!(ptr_new = realloc( ime_comp_buf, ime_comp_max + byte_expansion ))) { ERR("Couldn't expand composition string buffer\n"); return; } - CompositionString = ptr_new; - dwCompStringSize += byte_expansion; + ime_comp_buf = ptr_new; + ime_comp_max += byte_expansion; } - ptr_new = CompositionString + byte_offset; - memmove(ptr_new + byte_length, ptr_new + byte_selection, - dwCompStringLength - byte_offset - byte_selection); - if (lpComp) memcpy(ptr_new, lpComp, byte_length); - dwCompStringLength += byte_expansion; + ptr_new = ime_comp_buf + byte_offset; + memmove( ptr_new + byte_length, ptr_new + byte_selection, + ime_comp_len - byte_offset - byte_selection ); + if (text) memcpy( ptr_new, text, byte_length ); + ime_comp_len += byte_expansion; - x11drv_client_func( client_func_ime_set_composition_string, - CompositionString, dwCompStringLength ); + x11drv_client_func( client_func_ime_set_composition_string, ime_comp_buf, ime_comp_len ); } void X11DRV_XIMLookupChars( const char *str, UINT count ) @@ -161,11 +158,10 @@ static int xic_preedit_done( XIC xic, XPointer user, XPointer arg ) TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg ); ximInComposeMode = FALSE; - if (dwCompStringSize) - free( CompositionString ); - dwCompStringSize = 0; - dwCompStringLength = 0; - CompositionString = NULL; + free( ime_comp_buf ); + ime_comp_buf = NULL; + ime_comp_max = 0; + ime_comp_len = 0; x11drv_client_call( client_ime_set_composition_status, FALSE ); return 0; } @@ -181,7 +177,7 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) if (!params) return 0; if (!(text = params->text)) - X11DRV_ImmSetInternalString( params->chg_first, params->chg_length, NULL, 0 ); + xim_update_comp_string( params->chg_first, params->chg_length, NULL, 0 ); else { size_t text_len; @@ -201,7 +197,7 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) if ((output = malloc( text_len * sizeof(WCHAR) ))) { text_len = ntdll_umbstowcs( str, text_len, output, text_len ); - X11DRV_ImmSetInternalString( params->chg_first, params->chg_length, output, text_len ); + xim_update_comp_string( params->chg_first, params->chg_length, output, text_len ); free( output ); } From ce6a9c3dc825d2484e9c83611f7df6c5039eb902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 May 2023 16:11:30 +0200 Subject: [PATCH 1880/2777] winex11: Simplify xic_preedit_draw control flow. (cherry picked from commit 6a36990f10f2b7d86c1802b95f93a93ec05f8393) --- dlls/winex11.drv/xim.c | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 4372faed3d6..b113dca20e9 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -170,40 +170,36 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) { XIMPreeditDrawCallbackStruct *params = (void *)arg; HWND hwnd = (HWND)user; + size_t text_len; XIMText *text; + WCHAR *output; + char *str; + int len; TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg ); if (!params) return 0; - if (!(text = params->text)) + if (!(text = params->text)) str = NULL; + else if (!text->encoding_is_wchar) str = text->string.multi_byte; + else if ((len = wcstombs( NULL, text->string.wide_char, text->length )) < 0) str = NULL; + else if ((str = malloc( len + 1 ))) + { + wcstombs( str, text->string.wide_char, len ); + str[len] = 0; + } + + if (!str || !(text_len = strlen( str )) || !(output = malloc( text_len * sizeof(WCHAR) ))) xim_update_comp_string( params->chg_first, params->chg_length, NULL, 0 ); else { - size_t text_len; - WCHAR *output; - char *str; - int len; - - if (!text->encoding_is_wchar) str = text->string.multi_byte; - else if ((len = wcstombs( NULL, text->string.wide_char, text->length )) < 0) str = NULL; - else if ((str = malloc( len + 1 ))) - { - wcstombs( str, text->string.wide_char, len ); - str[len] = 0; - } - - text_len = str ? strlen( str ) : 0; - if ((output = malloc( text_len * sizeof(WCHAR) ))) - { - text_len = ntdll_umbstowcs( str, text_len, output, text_len ); - xim_update_comp_string( params->chg_first, params->chg_length, output, text_len ); - free( output ); - } - - if (str != text->string.multi_byte) free( str ); + text_len = ntdll_umbstowcs( str, text_len, output, text_len ); + xim_update_comp_string( params->chg_first, params->chg_length, output, text_len ); + free( output ); } + if (text && str != text->string.multi_byte) free( str ); + x11drv_client_call( client_ime_set_cursor_pos, params->caret ); return 0; From bd92485c5dfac8c8f725c3d90c313dd7df7169d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 1 May 2023 16:27:10 +0200 Subject: [PATCH 1881/2777] winex11: Compute preedit text buffer sizes in WCHAR units. (cherry picked from commit 3723b7867a95e1be4c152365a5e0d532109d56a1) --- dlls/winex11.drv/xim.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index b113dca20e9..1aca49871e9 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -44,7 +44,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(xim); BOOL ximInComposeMode=FALSE; -static BYTE *ime_comp_buf; +static WCHAR *ime_comp_buf; static DWORD ime_comp_len; static DWORD ime_comp_max; @@ -73,34 +73,29 @@ static const char *debugstr_xim_style( XIMStyle style ) static void xim_update_comp_string( UINT offset, UINT old_len, const WCHAR *text, UINT new_len ) { - /* Composition strings are edited in chunks */ - unsigned int byte_length = new_len * sizeof(WCHAR); - unsigned int byte_offset = offset * sizeof(WCHAR); - unsigned int byte_selection = old_len * sizeof(WCHAR); - int byte_expansion = byte_length - byte_selection; - BYTE *ptr_new; + int diff = new_len - old_len; + WCHAR *ptr; - TRACE( "(%i, %i, %p, %d):\n", offset, old_len, text, new_len ); + TRACE( "offset %u, old_len %u, text %s\n", offset, old_len, debugstr_wn(text, new_len) ); - if (byte_expansion + ime_comp_len >= ime_comp_max) + if (diff + ime_comp_len >= ime_comp_max) { - if (!(ptr_new = realloc( ime_comp_buf, ime_comp_max + byte_expansion ))) + if (!(ptr = realloc( ime_comp_buf, (ime_comp_max + diff) * sizeof(WCHAR) ))) { ERR("Couldn't expand composition string buffer\n"); return; } - ime_comp_buf = ptr_new; - ime_comp_max += byte_expansion; + ime_comp_buf = ptr; + ime_comp_max += diff; } - ptr_new = ime_comp_buf + byte_offset; - memmove( ptr_new + byte_length, ptr_new + byte_selection, - ime_comp_len - byte_offset - byte_selection ); - if (text) memcpy( ptr_new, text, byte_length ); - ime_comp_len += byte_expansion; + ptr = ime_comp_buf + offset; + memmove( ptr + new_len, ptr + old_len, (ime_comp_len - offset - old_len) * sizeof(WCHAR) ); + if (text) memcpy( ptr, text, new_len * sizeof(WCHAR) ); + ime_comp_len += diff; - x11drv_client_func( client_func_ime_set_composition_string, ime_comp_buf, ime_comp_len ); + x11drv_client_func( client_func_ime_set_composition_string, ime_comp_buf, ime_comp_len * sizeof(WCHAR) ); } void X11DRV_XIMLookupChars( const char *str, UINT count ) From ee1539cc6fb1ba4d82b687b63d83aa0207345d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 May 2023 16:12:45 +0200 Subject: [PATCH 1882/2777] winex11: Always zero terminate XIM composition string buffer. (cherry picked from commit 0f16bf1daf3d8f451a54215178114b418b8e9c9d) --- dlls/winex11.drv/xim.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 1aca49871e9..3601cb8c680 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -45,8 +45,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(xim); BOOL ximInComposeMode=FALSE; static WCHAR *ime_comp_buf; -static DWORD ime_comp_len; -static DWORD ime_comp_max; static XIMStyle input_style = 0; static XIMStyle input_style_req = XIMPreeditCallbacks | XIMStatusCallbacks; @@ -73,29 +71,26 @@ static const char *debugstr_xim_style( XIMStyle style ) static void xim_update_comp_string( UINT offset, UINT old_len, const WCHAR *text, UINT new_len ) { + UINT len = ime_comp_buf ? wcslen( ime_comp_buf ) : 0; int diff = new_len - old_len; WCHAR *ptr; TRACE( "offset %u, old_len %u, text %s\n", offset, old_len, debugstr_wn(text, new_len) ); - if (diff + ime_comp_len >= ime_comp_max) + if (!(ptr = realloc( ime_comp_buf, (len + max(0, diff) + 1) * sizeof(WCHAR) ))) { - if (!(ptr = realloc( ime_comp_buf, (ime_comp_max + diff) * sizeof(WCHAR) ))) - { - ERR("Couldn't expand composition string buffer\n"); - return; - } - - ime_comp_buf = ptr; - ime_comp_max += diff; + ERR( "Failed to reallocate composition string buffer\n" ); + return; } + ime_comp_buf = ptr; ptr = ime_comp_buf + offset; - memmove( ptr + new_len, ptr + old_len, (ime_comp_len - offset - old_len) * sizeof(WCHAR) ); + memmove( ptr + new_len, ptr + old_len, (len - offset - old_len) * sizeof(WCHAR) ); if (text) memcpy( ptr, text, new_len * sizeof(WCHAR) ); - ime_comp_len += diff; + len += diff; + ime_comp_buf[len] = 0; - x11drv_client_func( client_func_ime_set_composition_string, ime_comp_buf, ime_comp_len * sizeof(WCHAR) ); + x11drv_client_func( client_func_ime_set_composition_string, ime_comp_buf, len * sizeof(WCHAR) ); } void X11DRV_XIMLookupChars( const char *str, UINT count ) @@ -105,8 +100,9 @@ void X11DRV_XIMLookupChars( const char *str, UINT count ) TRACE("%p %u\n", str, count); - if (!(output = malloc( count * sizeof(WCHAR) ))) return; + if (!(output = malloc( (count + 1) * sizeof(WCHAR) ))) return; len = ntdll_umbstowcs( str, count, output, count ); + output[len] = 0; x11drv_client_func( client_func_ime_set_result, output, len * sizeof(WCHAR) ); free( output ); @@ -155,8 +151,7 @@ static int xic_preedit_done( XIC xic, XPointer user, XPointer arg ) ximInComposeMode = FALSE; free( ime_comp_buf ); ime_comp_buf = NULL; - ime_comp_max = 0; - ime_comp_len = 0; + x11drv_client_call( client_ime_set_composition_status, FALSE ); return 0; } From 75daed168c040b3da5a39e4a7f0cf6732bea81f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 30 Apr 2023 13:16:01 +0200 Subject: [PATCH 1883/2777] imm32/tests: Move IME calls test helpers around. (cherry picked from commit 4ccc47c0ca9fdf2a415fdaaa1328376bb2aacea0) --- dlls/imm32/tests/imm32.c | 738 +++++++++++++++++++-------------------- 1 file changed, 369 insertions(+), 369 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 093b79ff86b..d06ad1fae3d 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -263,6 +263,299 @@ static void process_messages(void) } } +#define ime_trace( msg, ... ) if (winetest_debug > 1) trace( "%04lx:%s " msg, GetCurrentThreadId(), __func__, ## __VA_ARGS__ ) + +static BOOL ImeSelect_init_status; +static BOOL todo_ImeInquire; +DEFINE_EXPECT( ImeInquire ); +static BOOL todo_ImeDestroy; +DEFINE_EXPECT( ImeDestroy ); +DEFINE_EXPECT( ImeEscape ); +DEFINE_EXPECT( ImeEnumRegisterWord ); +DEFINE_EXPECT( ImeRegisterWord ); +DEFINE_EXPECT( ImeGetRegisterWordStyle ); +DEFINE_EXPECT( ImeUnregisterWord ); +static BOOL todo_ImeSetCompositionString; +DEFINE_EXPECT( ImeSetCompositionString ); +static BOOL todo_IME_DLL_PROCESS_ATTACH; +DEFINE_EXPECT( IME_DLL_PROCESS_ATTACH ); +static BOOL todo_IME_DLL_PROCESS_DETACH; +DEFINE_EXPECT( IME_DLL_PROCESS_DETACH ); + +static IMEINFO ime_info; +static UINT ime_count; +static WCHAR ime_path[MAX_PATH]; +static HIMC default_himc; +static HKL default_hkl, wineime_hkl; +static HKL expect_ime = (HKL)(int)0xe020047f; + +enum ime_function +{ + IME_SELECT = 1, + IME_NOTIFY, + IME_PROCESS_KEY, + IME_SET_ACTIVE_CONTEXT, + MSG_IME_UI, + MSG_TEST_WIN, +}; + +struct ime_call +{ + HKL hkl; + HIMC himc; + enum ime_function func; + + union + { + int select; + struct + { + int action; + int index; + int value; + } notify; + struct + { + WORD vkey; + LPARAM lparam; + } process_key; + struct + { + int flag; + } set_active_context; + struct + { + UINT msg; + WPARAM wparam; + LPARAM lparam; + } message; + }; + + BOOL todo; + BOOL broken; + BOOL flaky_himc; +}; + +struct ime_call empty_sequence[] = {{0}}; +static struct ime_call ime_calls[1024]; +static ULONG ime_call_count; + +#define ok_call( a, b ) ok_call_( __FILE__, __LINE__, a, b ) +static int ok_call_( const char *file, int line, const struct ime_call *expected, const struct ime_call *received ) +{ + int ret; + + if ((ret = expected->func - received->func)) goto done; + /* Wine doesn't allocate HIMC in a deterministic order, ignore them when they are enumerated */ + if (expected->flaky_himc && (ret = !!(UINT_PTR)expected->himc - !!(UINT_PTR)received->himc)) goto done; + if (!expected->flaky_himc && (ret = (UINT_PTR)expected->himc - (UINT_PTR)received->himc)) goto done; + if ((ret = (UINT)(UINT_PTR)expected->hkl - (UINT)(UINT_PTR)received->hkl)) goto done; + switch (expected->func) + { + case IME_SELECT: + if ((ret = expected->select - received->select)) goto done; + break; + case IME_NOTIFY: + if ((ret = expected->notify.action - received->notify.action)) goto done; + if ((ret = expected->notify.index - received->notify.index)) goto done; + if ((ret = expected->notify.value - received->notify.value)) goto done; + break; + case IME_PROCESS_KEY: + if ((ret = expected->process_key.vkey - received->process_key.vkey)) goto done; + if ((ret = expected->process_key.lparam - received->process_key.lparam)) goto done; + break; + case IME_SET_ACTIVE_CONTEXT: + if ((ret = expected->set_active_context.flag - received->set_active_context.flag)) goto done; + break; + case MSG_IME_UI: + case MSG_TEST_WIN: + if ((ret = expected->message.msg - received->message.msg)) goto done; + if ((ret = (expected->message.wparam - received->message.wparam))) goto done; + if ((ret = (expected->message.lparam - received->message.lparam))) goto done; + break; + } + +done: + if (ret && broken( expected->broken )) return ret; + + switch (received->func) + { + case IME_SELECT: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SELECT select %u\n", received->hkl, received->himc, received->select ); + return ret; + case IME_NOTIFY: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "got hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n", + received->hkl, received->himc, received->notify.action, received->notify.index, + received->notify.value ); + return ret; + case IME_PROCESS_KEY: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "got hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, lparam %#Ix\n", + received->hkl, received->himc, received->process_key.vkey, received->process_key.lparam ); + return ret; + case IME_SET_ACTIVE_CONTEXT: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", received->hkl, received->himc, + received->set_active_context.flag ); + return ret; + case MSG_IME_UI: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, + received->himc, received->message.msg, received->message.wparam, received->message.lparam ); + return ret; + case MSG_TEST_WIN: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, + received->himc, received->message.msg, received->message.wparam, received->message.lparam ); + return ret; + } + + switch (expected->func) + { + case IME_SELECT: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "hkl %p, himc %p, IME_SELECT select %u\n", expected->hkl, expected->himc, expected->select ); + break; + case IME_NOTIFY: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n", + expected->hkl, expected->himc, expected->notify.action, expected->notify.index, + expected->notify.value ); + break; + case IME_PROCESS_KEY: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, lparam %#Ix\n", + expected->hkl, expected->himc, expected->process_key.vkey, expected->process_key.lparam ); + break; + case IME_SET_ACTIVE_CONTEXT: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", expected->hkl, expected->himc, + expected->set_active_context.flag ); + break; + case MSG_IME_UI: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, + expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); + break; + case MSG_TEST_WIN: + todo_wine_if( expected->todo ) + ok_(file, line)( !ret, "hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, + expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); + break; + } + + return 0; +} + +#define ok_seq( a ) ok_seq_( __FILE__, __LINE__, a, #a ) +static void ok_seq_( const char *file, int line, const struct ime_call *expected, const char *context ) +{ + const struct ime_call *received = ime_calls; + UINT i = 0, ret; + + while (expected->func || received->func) + { + winetest_push_context( "%u%s%s", i++, !expected->func ? " (spurious)" : "", + !received->func ? " (missing)" : "" ); + ret = ok_call_( file, line, expected, received ); + if (ret && expected->todo && expected->func && + !strcmp( winetest_platform, "wine" )) + expected++; + else if (ret && broken(expected->broken)) + expected++; + else + { + if (expected->func) expected++; + if (received->func) received++; + } + winetest_pop_context(); + } + + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; +} + +static BOOL check_WM_SHOWWINDOW; + +static BOOL ignore_message( UINT msg ) +{ + switch (msg) + { + case WM_IME_STARTCOMPOSITION: + case WM_IME_ENDCOMPOSITION: + case WM_IME_COMPOSITION: + case WM_IME_SETCONTEXT: + case WM_IME_NOTIFY: + case WM_IME_CONTROL: + case WM_IME_COMPOSITIONFULL: + case WM_IME_SELECT: + case WM_IME_CHAR: + case 0x287: + case WM_IME_REQUEST: + case WM_IME_KEYDOWN: + case WM_IME_KEYUP: + return FALSE; + case WM_SHOWWINDOW: + return !check_WM_SHOWWINDOW; + default: + return TRUE; + } +} + +static LRESULT CALLBACK ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + struct ime_call call = + { + .hkl = GetKeyboardLayout( 0 ), .himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ), + .func = MSG_IME_UI, .message = {.msg = msg, .wparam = wparam, .lparam = lparam} + }; + LONG_PTR ptr; + + ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + + if (ignore_message( msg )) return DefWindowProcW( hwnd, msg, wparam, lparam ); + + ptr = GetWindowLongPtrW( hwnd, IMMGWL_PRIVATE ); + ok( !ptr, "got IMMGWL_PRIVATE %#Ix\n", ptr ); + + ime_calls[ime_call_count++] = call; + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +static LRESULT CALLBACK test_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + struct ime_call call = + { + .hkl = GetKeyboardLayout( 0 ), .himc = ImmGetContext( hwnd ), + .func = MSG_TEST_WIN, .message = {.msg = msg, .wparam = wparam, .lparam = lparam} + }; + + ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + + if (ignore_message( msg )) return DefWindowProcW( hwnd, msg, wparam, lparam ); + + ime_calls[ime_call_count++] = call; + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +static WNDCLASSEXW ime_ui_class = +{ + .cbSize = sizeof(WNDCLASSEXW), + .style = CS_IME, + .lpfnWndProc = ime_ui_window_proc, + .cbWndExtra = 2 * sizeof(LONG_PTR), + .lpszClassName = L"WineTestIME", +}; + +static WNDCLASSEXW test_class = +{ + .cbSize = sizeof(WNDCLASSEXW), + .lpfnWndProc = test_window_proc, + .lpszClassName = L"WineTest", +}; + /* * msgspy - record and analyse message traces sent to a certain window */ @@ -2595,397 +2888,104 @@ static void test_com_initialization(void) test_apttype(hr == S_OK ? APTTYPE_MTA : APTTYPE_MAINSTA); DestroyWindow(wnd); test_apttype(-1); -} - -static DWORD WINAPI disable_ime_thread(void *arg) -{ - HWND h, def; - MSG msg; - BOOL r; - - h = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0); - ok(h != NULL, "CreateWindow failed\n"); - def = ImmGetDefaultIMEWnd(h); - ok(def != NULL, "ImmGetDefaultIMEWnd returned NULL\n"); - - r = ImmDisableIME(arg ? GetCurrentThreadId() : 0); - ok(r, "ImmDisableIME failed\n"); - - if (arg) - { - def = ImmGetDefaultIMEWnd(h); - todo_wine ok(def != NULL, "ImmGetDefaultIMEWnd returned NULL\n"); - while(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) - DispatchMessageA(&msg); - } - def = ImmGetDefaultIMEWnd(h); - ok(!def, "ImmGetDefaultIMEWnd returned %p\n", def); - return 0; -} - -static DWORD WINAPI check_not_disabled_ime_thread(void *arg) -{ - HWND def, hwnd; - - WaitForSingleObject(arg, INFINITE); - hwnd = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0); - ok(hwnd != NULL, "CreateWindow failed\n"); - def = ImmGetDefaultIMEWnd(hwnd); - ok(def != NULL, "ImmGetDefaultIMEWnd returned %p\n", def); - return 0; -} - -static DWORD WINAPI disable_ime_process(void *arg) -{ - BOOL r = ImmDisableIME(-1); - ok(r, "ImmDisableIME failed\n"); - return 0; -} - -static void test_ImmDisableIME(void) -{ - HANDLE thread, event; - DWORD tid; - HWND def, def2; - BOOL r; - - def = ImmGetDefaultIMEWnd(hwnd); - ok(def != NULL, "ImmGetDefaultIMEWnd(hwnd) returned NULL\n"); - - event = CreateEventW(NULL, TRUE, FALSE, FALSE); - thread = CreateThread(NULL, 0, check_not_disabled_ime_thread, event, 0, &tid); - ok(thread != NULL, "CreateThread failed\n"); - r = ImmDisableIME(tid); - ok(!r, "ImmDisableIME(tid) succeeded\n"); - SetEvent(event); - WaitForSingleObject(thread, INFINITE); - CloseHandle(thread); - CloseHandle(event); - - thread = CreateThread(NULL, 0, disable_ime_thread, 0, 0, NULL); - ok(thread != NULL, "CreateThread failed\n"); - WaitForSingleObject(thread, INFINITE); - CloseHandle(thread); - - thread = CreateThread(NULL, 0, disable_ime_thread, (void*)1, 0, NULL); - ok(thread != NULL, "CreateThread failed\n"); - WaitForSingleObject(thread, INFINITE); - CloseHandle(thread); - - msg_spy_pump_msg_queue(); - thread = CreateThread(NULL, 0, disable_ime_process, 0, 0, NULL); - ok(thread != NULL, "CreateThread failed\n"); - WaitForSingleObject(thread, INFINITE); - CloseHandle(thread); - - ok(IsWindow(def), "not a window\n"); - def2 = ImmGetDefaultIMEWnd(hwnd); - ok(def2 == def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def2); - ok(IsWindow(def), "not a window\n"); - msg_spy_pump_msg_queue(); - ok(!IsWindow(def), "window is still valid\n"); - def = ImmGetDefaultIMEWnd(hwnd); - ok(!def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def); - - r = ImmDisableIME(-1); - ok(r, "ImmDisableIME(-1) failed\n"); - def = ImmGetDefaultIMEWnd(hwnd); - ok(!def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def); -} - -#define ime_trace( msg, ... ) if (winetest_debug > 1) trace( "%04lx:%s " msg, GetCurrentThreadId(), __func__, ## __VA_ARGS__ ) - -static BOOL ImeSelect_init_status; -static BOOL todo_ImeInquire; -DEFINE_EXPECT( ImeInquire ); -static BOOL todo_ImeDestroy; -DEFINE_EXPECT( ImeDestroy ); -DEFINE_EXPECT( ImeEscape ); -DEFINE_EXPECT( ImeEnumRegisterWord ); -DEFINE_EXPECT( ImeRegisterWord ); -DEFINE_EXPECT( ImeGetRegisterWordStyle ); -DEFINE_EXPECT( ImeUnregisterWord ); -static BOOL todo_ImeSetCompositionString; -DEFINE_EXPECT( ImeSetCompositionString ); -static BOOL todo_IME_DLL_PROCESS_ATTACH; -DEFINE_EXPECT( IME_DLL_PROCESS_ATTACH ); -static BOOL todo_IME_DLL_PROCESS_DETACH; -DEFINE_EXPECT( IME_DLL_PROCESS_DETACH ); - -static IMEINFO ime_info; -static UINT ime_count; -static WCHAR ime_path[MAX_PATH]; -static HIMC default_himc; -static HKL default_hkl, wineime_hkl; -static HKL expect_ime = (HKL)(int)0xe020047f; - -enum ime_function -{ - IME_SELECT = 1, - IME_NOTIFY, - IME_PROCESS_KEY, - IME_SET_ACTIVE_CONTEXT, - MSG_IME_UI, - MSG_TEST_WIN, -}; - -struct ime_call -{ - HKL hkl; - HIMC himc; - enum ime_function func; - - union - { - int select; - struct - { - int action; - int index; - int value; - } notify; - struct - { - WORD vkey; - LPARAM key_data; - } process_key; - struct - { - int flag; - } set_active_context; - struct - { - UINT msg; - WPARAM wparam; - LPARAM lparam; - } message; - }; - - BOOL todo; - BOOL broken; - BOOL flaky_himc; -}; - -struct ime_call empty_sequence[] = {{0}}; -static struct ime_call ime_calls[1024]; -static ULONG ime_call_count; +} -#define ok_call( a, b ) ok_call_( __FILE__, __LINE__, a, b ) -static int ok_call_( const char *file, int line, const struct ime_call *expected, const struct ime_call *received ) +static DWORD WINAPI disable_ime_thread(void *arg) { - int ret; - - if ((ret = expected->func - received->func)) goto done; - /* Wine doesn't allocate HIMC in a deterministic order, ignore them when they are enumerated */ - if (expected->flaky_himc && (ret = !!(UINT_PTR)expected->himc - !!(UINT_PTR)received->himc)) goto done; - if (!expected->flaky_himc && (ret = (UINT_PTR)expected->himc - (UINT_PTR)received->himc)) goto done; - if ((ret = (UINT)(UINT_PTR)expected->hkl - (UINT)(UINT_PTR)received->hkl)) goto done; - switch (expected->func) - { - case IME_SELECT: - if ((ret = expected->select - received->select)) goto done; - break; - case IME_NOTIFY: - if ((ret = expected->notify.action - received->notify.action)) goto done; - if ((ret = expected->notify.index - received->notify.index)) goto done; - if ((ret = expected->notify.value - received->notify.value)) goto done; - break; - case IME_PROCESS_KEY: - if ((ret = expected->process_key.vkey - received->process_key.vkey)) goto done; - if ((ret = expected->process_key.key_data - received->process_key.key_data)) goto done; - break; - case IME_SET_ACTIVE_CONTEXT: - if ((ret = expected->set_active_context.flag - received->set_active_context.flag)) goto done; - break; - case MSG_IME_UI: - case MSG_TEST_WIN: - if ((ret = expected->message.msg - received->message.msg)) goto done; - if ((ret = (expected->message.wparam - received->message.wparam))) goto done; - if ((ret = (expected->message.lparam - received->message.lparam))) goto done; - break; - } + HWND h, def; + MSG msg; + BOOL r; -done: - if (ret && broken( expected->broken )) return ret; + h = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0); + ok(h != NULL, "CreateWindow failed\n"); + def = ImmGetDefaultIMEWnd(h); + ok(def != NULL, "ImmGetDefaultIMEWnd returned NULL\n"); - switch (received->func) - { - case IME_SELECT: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SELECT select %u\n", received->hkl, received->himc, received->select ); - return ret; - case IME_NOTIFY: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "got hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n", - received->hkl, received->himc, received->notify.action, received->notify.index, - received->notify.value ); - return ret; - case IME_PROCESS_KEY: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "got hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, key_data %#Ix\n", - received->hkl, received->himc, received->process_key.vkey, received->process_key.key_data ); - return ret; - case IME_SET_ACTIVE_CONTEXT: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", received->hkl, received->himc, - received->set_active_context.flag ); - return ret; - case MSG_IME_UI: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, - received->himc, received->message.msg, received->message.wparam, received->message.lparam ); - return ret; - case MSG_TEST_WIN: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, - received->himc, received->message.msg, received->message.wparam, received->message.lparam ); - return ret; - } + r = ImmDisableIME(arg ? GetCurrentThreadId() : 0); + ok(r, "ImmDisableIME failed\n"); - switch (expected->func) + if (arg) { - case IME_SELECT: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "hkl %p, himc %p, IME_SELECT select %u\n", expected->hkl, expected->himc, expected->select ); - break; - case IME_NOTIFY: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n", - expected->hkl, expected->himc, expected->notify.action, expected->notify.index, - expected->notify.value ); - break; - case IME_PROCESS_KEY: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, key_data %#Ix\n", - expected->hkl, expected->himc, expected->process_key.vkey, expected->process_key.key_data ); - break; - case IME_SET_ACTIVE_CONTEXT: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", expected->hkl, expected->himc, - expected->set_active_context.flag ); - break; - case MSG_IME_UI: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, - expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); - break; - case MSG_TEST_WIN: - todo_wine_if( expected->todo ) - ok_(file, line)( !ret, "hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, - expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); - break; + def = ImmGetDefaultIMEWnd(h); + todo_wine ok(def != NULL, "ImmGetDefaultIMEWnd returned NULL\n"); + while(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); } - + def = ImmGetDefaultIMEWnd(h); + ok(!def, "ImmGetDefaultIMEWnd returned %p\n", def); return 0; } -#define ok_seq( a ) ok_seq_( __FILE__, __LINE__, a, #a ) -static void ok_seq_( const char *file, int line, const struct ime_call *expected, const char *context ) +static DWORD WINAPI check_not_disabled_ime_thread(void *arg) { - const struct ime_call *received = ime_calls; - UINT i = 0, ret; - - while (expected->func || received->func) - { - winetest_push_context( "%u%s%s", i++, !expected->func ? " (spurious)" : "", - !received->func ? " (missing)" : "" ); - ret = ok_call_( file, line, expected, received ); - if (ret && expected->todo && expected->func && - !strcmp( winetest_platform, "wine" )) - expected++; - else if (ret && broken(expected->broken)) - expected++; - else - { - if (expected->func) expected++; - if (received->func) received++; - } - winetest_pop_context(); - } + HWND def, hwnd; - memset( ime_calls, 0, sizeof(ime_calls) ); - ime_call_count = 0; + WaitForSingleObject(arg, INFINITE); + hwnd = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0); + ok(hwnd != NULL, "CreateWindow failed\n"); + def = ImmGetDefaultIMEWnd(hwnd); + ok(def != NULL, "ImmGetDefaultIMEWnd returned %p\n", def); + return 0; } -static BOOL check_WM_SHOWWINDOW; - -static BOOL ignore_message( UINT msg ) +static DWORD WINAPI disable_ime_process(void *arg) { - switch (msg) - { - case WM_IME_STARTCOMPOSITION: - case WM_IME_ENDCOMPOSITION: - case WM_IME_COMPOSITION: - case WM_IME_SETCONTEXT: - case WM_IME_NOTIFY: - case WM_IME_CONTROL: - case WM_IME_COMPOSITIONFULL: - case WM_IME_SELECT: - case WM_IME_CHAR: - case 0x287: - case WM_IME_REQUEST: - case WM_IME_KEYDOWN: - case WM_IME_KEYUP: - return FALSE; - case WM_SHOWWINDOW: - return !check_WM_SHOWWINDOW; - default: - return TRUE; - } + BOOL r = ImmDisableIME(-1); + ok(r, "ImmDisableIME failed\n"); + return 0; } -static LRESULT CALLBACK ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +static void test_ImmDisableIME(void) { - struct ime_call call = - { - .hkl = GetKeyboardLayout( 0 ), .himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ), - .func = MSG_IME_UI, .message = {.msg = msg, .wparam = wparam, .lparam = lparam} - }; - LONG_PTR ptr; - - ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + HANDLE thread, event; + DWORD tid; + HWND def, def2; + BOOL r; - if (ignore_message( msg )) return DefWindowProcW( hwnd, msg, wparam, lparam ); + def = ImmGetDefaultIMEWnd(hwnd); + ok(def != NULL, "ImmGetDefaultIMEWnd(hwnd) returned NULL\n"); - ptr = GetWindowLongPtrW( hwnd, IMMGWL_PRIVATE ); - ok( !ptr, "got IMMGWL_PRIVATE %#Ix\n", ptr ); + event = CreateEventW(NULL, TRUE, FALSE, FALSE); + thread = CreateThread(NULL, 0, check_not_disabled_ime_thread, event, 0, &tid); + ok(thread != NULL, "CreateThread failed\n"); + r = ImmDisableIME(tid); + ok(!r, "ImmDisableIME(tid) succeeded\n"); + SetEvent(event); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + CloseHandle(event); - ime_calls[ime_call_count++] = call; - return DefWindowProcW( hwnd, msg, wparam, lparam ); -} + thread = CreateThread(NULL, 0, disable_ime_thread, 0, 0, NULL); + ok(thread != NULL, "CreateThread failed\n"); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); -static LRESULT CALLBACK test_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) -{ - struct ime_call call = - { - .hkl = GetKeyboardLayout( 0 ), .himc = ImmGetContext( hwnd ), - .func = MSG_TEST_WIN, .message = {.msg = msg, .wparam = wparam, .lparam = lparam} - }; + thread = CreateThread(NULL, 0, disable_ime_thread, (void*)1, 0, NULL); + ok(thread != NULL, "CreateThread failed\n"); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); - ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + msg_spy_pump_msg_queue(); + thread = CreateThread(NULL, 0, disable_ime_process, 0, 0, NULL); + ok(thread != NULL, "CreateThread failed\n"); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); - if (ignore_message( msg )) return DefWindowProcW( hwnd, msg, wparam, lparam ); + ok(IsWindow(def), "not a window\n"); + def2 = ImmGetDefaultIMEWnd(hwnd); + ok(def2 == def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def2); + ok(IsWindow(def), "not a window\n"); + msg_spy_pump_msg_queue(); + ok(!IsWindow(def), "window is still valid\n"); + def = ImmGetDefaultIMEWnd(hwnd); + ok(!def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def); - ime_calls[ime_call_count++] = call; - return DefWindowProcW( hwnd, msg, wparam, lparam ); + r = ImmDisableIME(-1); + ok(r, "ImmDisableIME(-1) failed\n"); + def = ImmGetDefaultIMEWnd(hwnd); + ok(!def, "ImmGetDefaultIMEWnd(hwnd) returned %p\n", def); } -static WNDCLASSEXW ime_ui_class = -{ - .cbSize = sizeof(WNDCLASSEXW), - .style = CS_IME, - .lpfnWndProc = ime_ui_window_proc, - .cbWndExtra = 2 * sizeof(LONG_PTR), - .lpszClassName = L"WineTestIME", -}; - -static WNDCLASSEXW test_class = -{ - .cbSize = sizeof(WNDCLASSEXW), - .lpfnWndProc = test_window_proc, - .lpszClassName = L"WineTest", -}; - static BOOL WINAPI ime_ImeConfigure( HKL hkl, HWND hwnd, DWORD mode, void *data ) { ime_trace( "hkl %p, hwnd %p, mode %lu, data %p\n", hkl, hwnd, mode, data ); @@ -3136,15 +3136,15 @@ static BOOL WINAPI ime_ImeInquire( IMEINFO *info, WCHAR *ui_class, DWORD flags ) return TRUE; } -static BOOL WINAPI ime_ImeProcessKey( HIMC himc, UINT vkey, LPARAM key_data, BYTE *key_state ) +static BOOL WINAPI ime_ImeProcessKey( HIMC himc, UINT vkey, LPARAM lparam, BYTE *state ) { struct ime_call call = { .hkl = GetKeyboardLayout( 0 ), .himc = himc, - .func = IME_PROCESS_KEY, .process_key = {.vkey = vkey, .key_data = key_data} + .func = IME_PROCESS_KEY, .process_key = {.vkey = vkey, .lparam = lparam} }; - ime_trace( "himc %p, vkey %u, key_data %#Ix, key_state %p\n", - himc, vkey, key_data, key_state ); + ime_trace( "himc %p, vkey %u, lparam %#Ix, state %p\n", + himc, vkey, lparam, state ); ime_calls[ime_call_count++] = call; return TRUE; } @@ -4644,7 +4644,7 @@ static void test_ImmProcessKey(void) { { .hkl = expect_ime, .himc = default_himc, - .func = IME_PROCESS_KEY, .process_key = {.vkey = 'A', .key_data = 0}, + .func = IME_PROCESS_KEY, .process_key = {.vkey = 'A', .lparam = 0}, }, {0}, }; From be00f4eb1a4eb1d957375046fb34dad8f88e54d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 30 Apr 2023 13:02:36 +0200 Subject: [PATCH 1884/2777] imm32/tests: Test cross-thread ImmRequestMessage(W|A) calls. (cherry picked from commit c4187bc46bb39f9b5517fbb1feb0baf855d6effc) --- dlls/imm32/tests/imm32.c | 102 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index d06ad1fae3d..9290c9c5d0b 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -1351,13 +1351,14 @@ static DWORD WINAPI test_cross_thread_himc_thread( void *arg ) POINT pos = {0}; MSG msg; - hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); ok_ne( NULL, hwnd, HWND, "%p" ); himc[0] = ImmGetContext( hwnd ); ok_ne( NULL, himc[0], HIMC, "%p" ); contexts[0] = ImmLockIMC( himc[0] ); ok_ne( NULL, contexts[0], INPUTCONTEXT *, "%p" ); + contexts[0]->hWnd = hwnd; tmp_hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); @@ -1370,6 +1371,7 @@ static DWORD WINAPI test_cross_thread_himc_thread( void *arg ) ok_ne( NULL, himc[1], HIMC, "%p" ); contexts[1] = ImmLockIMC( himc[1] ); ok_ne( NULL, contexts[1], INPUTCONTEXT *, "%p" ); + contexts[1]->hWnd = hwnd; ok_ret( 1, ImmSetOpenStatus( himc[0], 0xdeadbeef ) ); ok_ret( 1, ImmSetOpenStatus( himc[1], 0xfeedcafe ) ); @@ -1408,9 +1410,11 @@ static DWORD WINAPI test_cross_thread_himc_thread( void *arg ) static void test_cross_thread_himc(void) { static const WCHAR comp_string[] = L"CompString"; + RECONVERTSTRING reconv = {.dwSize = sizeof(RECONVERTSTRING)}; struct test_cross_thread_himc_params params; COMPOSITIONFORM composition = {0}; DWORD tid, conversion, sentence; + IMECHARPOSITION char_pos = {0}; CANDIDATEFORM candidate = {0}; COMPOSITIONSTRING *string; HIMC himc[2], tmp_himc; @@ -1434,6 +1438,9 @@ static void test_cross_thread_himc(void) ok_ne( NULL, thread, HANDLE, "%p" ); WaitForSingleObject( params.event, INFINITE ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + tmp_himc = ImmGetContext( params.hwnd ); ok_ne( himc[0], tmp_himc, HIMC, "%p" ); ok_eq( params.himc[0], tmp_himc, HIMC, "%p" ); @@ -1565,6 +1572,18 @@ static void test_cross_thread_himc(void) ok_ret( 1, ImmGetCompositionFontW( params.himc[0], &fontW ) ); ok_ret( 1, ImmGetCompositionFontW( params.himc[1], &fontW ) ); + /* ImmRequestMessage(W|A) should fail with cross thread HIMC */ + + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_COMPOSITIONFONT, (LPARAM)&fontW ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_COMPOSITIONFONT, (LPARAM)&fontA ) ); + + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_COMPOSITIONFONT, (LPARAM)&fontW ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_COMPOSITIONFONT, (LPARAM)&fontA ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_COMPOSITIONFONT, (LPARAM)&fontW ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_COMPOSITIONFONT, (LPARAM)&fontA ) ); + + todo_wine ok_seq( empty_sequence ); + /* ImmSetCompositionString(W|A) should fail with cross thread HIMC */ ok_ret( 10, ImmGetCompositionStringA( himc[1], GCS_COMPSTR, buffer, sizeof(buffer) ) ); @@ -1581,6 +1600,46 @@ static void test_cross_thread_himc(void) ok_ret( 20, ImmGetCompositionStringW( params.himc[0], GCS_COMPSTR, buffer, sizeof(buffer) ) ); ok_ret( 0, ImmGetCompositionStringW( params.himc[1], GCS_COMPSTR, buffer, sizeof(buffer) ) ); + /* ImmRequestMessage(W|A) should fail with cross thread HIMC */ + + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_RECONVERTSTRING, 0 ) ); + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_RECONVERTSTRING, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_RECONVERTSTRING, 0 ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_RECONVERTSTRING, (LPARAM)&reconv ) ); + + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_RECONVERTSTRING, 0 ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_RECONVERTSTRING, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_RECONVERTSTRING, 0 ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_RECONVERTSTRING, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_RECONVERTSTRING, 0 ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_RECONVERTSTRING, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_RECONVERTSTRING, 0 ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_RECONVERTSTRING, (LPARAM)&reconv ) ); + + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_DOCUMENTFEED, 0 ) ); + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_DOCUMENTFEED, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_DOCUMENTFEED, 0 ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_DOCUMENTFEED, (LPARAM)&reconv ) ); + + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_DOCUMENTFEED, 0 ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_DOCUMENTFEED, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_DOCUMENTFEED, 0 ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_DOCUMENTFEED, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_DOCUMENTFEED, 0 ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_DOCUMENTFEED, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_DOCUMENTFEED, 0 ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_DOCUMENTFEED, (LPARAM)&reconv ) ); + + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) ); + + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) ); + + todo_wine ok_seq( empty_sequence ); + /* ImmSetCompositionWindow should fail with cross thread HIMC */ ok_ret( 1, ImmSetCompositionWindow( himc[1], &composition ) ); @@ -1591,6 +1650,18 @@ static void test_cross_thread_himc(void) ok_ret( 1, ImmGetCompositionWindow( params.himc[0], &composition ) ); ok_ret( 1, ImmGetCompositionWindow( params.himc[1], &composition ) ); + /* ImmRequestMessage(W|A) should fail with cross thread HIMC */ + + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) ); + + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) ); + + todo_wine ok_seq( empty_sequence ); + /* ImmSetCandidateWindow should fail with cross thread HIMC */ ok_ret( 1, ImmSetCandidateWindow( himc[1], &candidate ) ); @@ -1601,6 +1672,23 @@ static void test_cross_thread_himc(void) ok_ret( 0, ImmSetCandidateWindow( params.himc[0], &candidate ) ); ok_ret( 0, ImmSetCandidateWindow( params.himc[1], &candidate ) ); + /* ImmRequestMessage(W|A) should fail with cross thread HIMC */ + + candidate.dwIndex = -1; + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); + + candidate.dwIndex = 0; + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); + + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); + + todo_wine ok_seq( empty_sequence ); + /* ImmSetStatusWindowPos should fail with cross thread HIMC */ ok_ret( 1, ImmSetStatusWindowPos( himc[1], &pos ) ); @@ -1611,6 +1699,18 @@ static void test_cross_thread_himc(void) ok_ret( 1, ImmGetStatusWindowPos( params.himc[0], &pos ) ); ok_ret( 1, ImmGetStatusWindowPos( params.himc[1], &pos ) ); + /* ImmRequestMessage(W|A) should fail with cross thread HIMC */ + + ok_ret( 0, ImmRequestMessageW( himc[1], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) ); + ok_ret( 0, ImmRequestMessageA( himc[1], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) ); + + ok_ret( 0, ImmRequestMessageW( params.himc[0], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[0], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) ); + ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) ); + ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) ); + + todo_wine ok_seq( empty_sequence ); + /* ImmGenerateMessage should fail with cross thread HIMC */ ok_ret( 1, ImmGenerateMessage( himc[1] ) ); From c3004eea478a5fa09748126de770d033dc644da0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 30 Apr 2023 13:36:07 +0200 Subject: [PATCH 1885/2777] imm32: Use INPUTCONTEXT directly in ImmRequestMessage(W|A). (cherry picked from commit a117b9b202da3865603951d383a01e0d4e7a33cf) --- dlls/imm32/imm.c | 60 ++++++++++++++++++++++++++++++++-------- dlls/imm32/tests/imm32.c | 10 +++---- 2 files changed, 53 insertions(+), 17 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index dfe81ddaaf7..08af055275e 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -2380,31 +2380,67 @@ BOOL WINAPI ImmReleaseContext(HWND hWnd, HIMC hIMC) /*********************************************************************** * ImmRequestMessageA(IMM32.@) */ -LRESULT WINAPI ImmRequestMessageA(HIMC hIMC, WPARAM wParam, LPARAM lParam) +LRESULT WINAPI ImmRequestMessageA( HIMC himc, WPARAM wparam, LPARAM lparam ) { - struct imc *data = get_imc_data( hIMC ); + INPUTCONTEXT *ctx; + LRESULT res; - TRACE("%p %Id %Id\n", hIMC, wParam, wParam); + TRACE( "himc %p, wparam %#Ix, lparam %#Ix\n", himc, wparam, lparam ); - if (data) return SendMessageA(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam); + if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; - SetLastError(ERROR_INVALID_HANDLE); - return 0; + switch (wparam) + { + case IMR_CANDIDATEWINDOW: + case IMR_COMPOSITIONFONT: + case IMR_COMPOSITIONWINDOW: + case IMR_CONFIRMRECONVERTSTRING: + case IMR_DOCUMENTFEED: + case IMR_QUERYCHARPOSITION: + case IMR_RECONVERTSTRING: + break; + default: + return FALSE; + } + + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + res = SendMessageA( ctx->hWnd, WM_IME_REQUEST, wparam, lparam ); + ImmUnlockIMC( himc ); + + return res; } /*********************************************************************** * ImmRequestMessageW(IMM32.@) */ -LRESULT WINAPI ImmRequestMessageW(HIMC hIMC, WPARAM wParam, LPARAM lParam) +LRESULT WINAPI ImmRequestMessageW( HIMC himc, WPARAM wparam, LPARAM lparam ) { - struct imc *data = get_imc_data( hIMC ); + INPUTCONTEXT *ctx; + LRESULT res; - TRACE("%p %Id %Id\n", hIMC, wParam, wParam); + TRACE( "himc %p, wparam %#Ix, lparam %#Ix\n", himc, wparam, lparam ); - if (data) return SendMessageW(data->IMC.hWnd, WM_IME_REQUEST, wParam, lParam); + if (NtUserQueryInputContext( himc, NtUserInputContextThreadId ) != GetCurrentThreadId()) return FALSE; - SetLastError(ERROR_INVALID_HANDLE); - return 0; + switch (wparam) + { + case IMR_CANDIDATEWINDOW: + case IMR_COMPOSITIONFONT: + case IMR_COMPOSITIONWINDOW: + case IMR_CONFIRMRECONVERTSTRING: + case IMR_DOCUMENTFEED: + case IMR_QUERYCHARPOSITION: + case IMR_RECONVERTSTRING: + break; + default: + return FALSE; + } + + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + res = SendMessageW( ctx->hWnd, WM_IME_REQUEST, wparam, lparam ); + ImmUnlockIMC( himc ); + + return res; } /*********************************************************************** diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 9290c9c5d0b..5593f2d391c 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -1582,7 +1582,7 @@ static void test_cross_thread_himc(void) ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_COMPOSITIONFONT, (LPARAM)&fontW ) ); ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_COMPOSITIONFONT, (LPARAM)&fontA ) ); - todo_wine ok_seq( empty_sequence ); + ok_seq( empty_sequence ); /* ImmSetCompositionString(W|A) should fail with cross thread HIMC */ @@ -1638,7 +1638,7 @@ static void test_cross_thread_himc(void) ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) ); ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_CONFIRMRECONVERTSTRING, (LPARAM)&reconv ) ); - todo_wine ok_seq( empty_sequence ); + ok_seq( empty_sequence ); /* ImmSetCompositionWindow should fail with cross thread HIMC */ @@ -1660,7 +1660,7 @@ static void test_cross_thread_himc(void) ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) ); ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_COMPOSITIONWINDOW, (LPARAM)&composition ) ); - todo_wine ok_seq( empty_sequence ); + ok_seq( empty_sequence ); /* ImmSetCandidateWindow should fail with cross thread HIMC */ @@ -1687,7 +1687,7 @@ static void test_cross_thread_himc(void) ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_CANDIDATEWINDOW, (LPARAM)&candidate ) ); - todo_wine ok_seq( empty_sequence ); + ok_seq( empty_sequence ); /* ImmSetStatusWindowPos should fail with cross thread HIMC */ @@ -1709,7 +1709,7 @@ static void test_cross_thread_himc(void) ok_ret( 0, ImmRequestMessageW( params.himc[1], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) ); ok_ret( 0, ImmRequestMessageA( params.himc[1], IMR_QUERYCHARPOSITION, (LPARAM)&char_pos ) ); - todo_wine ok_seq( empty_sequence ); + ok_seq( empty_sequence ); /* ImmGenerateMessage should fail with cross thread HIMC */ From 46856180d8baae1a9b26b6587bf937c55340fe93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 30 Apr 2023 14:37:16 +0200 Subject: [PATCH 1886/2777] imm32/tests: Add more ImmProcessKey and ImmGetVirtualKey tests. (cherry picked from commit 655bd354eec1e21a4ded282cf59e3d93cb25ed5f) --- dlls/imm32/tests/imm32.c | 49 +++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 5593f2d391c..7841fc179f6 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3246,7 +3246,7 @@ static BOOL WINAPI ime_ImeProcessKey( HIMC himc, UINT vkey, LPARAM lparam, BYTE ime_trace( "himc %p, vkey %u, lparam %#Ix, state %p\n", himc, vkey, lparam, state ); ime_calls[ime_call_count++] = call; - return TRUE; + return LOWORD(lparam); } static BOOL WINAPI ime_ImeRegisterWord( const WCHAR *reading, DWORD style, const WCHAR *string ) @@ -4740,23 +4740,40 @@ static void test_ImmSetOpenStatus(void) static void test_ImmProcessKey(void) { - const struct ime_call process_key_seq[] = + const struct ime_call process_key_0[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_PROCESS_KEY, .process_key = {.vkey = 'A', .lparam = MAKELONG(0, 0x1e)}, + }, + {0}, + }; + const struct ime_call process_key_1[] = { { .hkl = expect_ime, .himc = default_himc, - .func = IME_PROCESS_KEY, .process_key = {.vkey = 'A', .lparam = 0}, + .func = IME_PROCESS_KEY, .process_key = {.vkey = 'A', .lparam = MAKELONG(1, 0x1e)}, + }, + {0}, + }; + const struct ime_call process_key_2[] = + { + { + .hkl = expect_ime, .himc = default_himc, + .func = IME_PROCESS_KEY, .process_key = {.vkey = 'A', .lparam = MAKELONG(2, 0x1e)}, }, {0}, }; HKL hkl; UINT_PTR ret; + HIMC himc; hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); process_messages(); - ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'A', 0, 0 ) ); + ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'A', MAKELONG(1, 0x1e), 0 ) ); ok_seq( empty_sequence ); ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; @@ -4769,19 +4786,35 @@ static void test_ImmProcessKey(void) memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; - ok_ret( 0, ImmProcessKey( 0, hkl, 'A', 0, 0 ) ); + ok_ret( 0, ImmProcessKey( 0, hkl, 'A', MAKELONG(1, 0x1e), 0 ) ); ok_seq( empty_sequence ); - ret = ImmProcessKey( hwnd, hkl, 'A', 0, 0 ); + ok_ret( 0, ImmProcessKey( hwnd, hkl, 'A', MAKELONG(0, 0x1e), 0 ) ); + ok_seq( process_key_0 ); + ret = ImmProcessKey( hwnd, hkl, 'A', MAKELONG(1, 0x1e), 0 ); todo_wine ok_ret( 2, ret ); - ok_seq( process_key_seq ); + ok_seq( process_key_1 ); + ok_ret( 2, ImmProcessKey( hwnd, hkl, 'A', MAKELONG(2, 0x1e), 0 ) ); + ok_seq( process_key_2 ); ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); - ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'A', 0, 0 ) ); + ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'A', MAKELONG(1, 0x1e), 0 ) ); ok_seq( empty_sequence ); ok_eq( hkl, GetKeyboardLayout( 0 ), HKL, "%p" ); + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ok_ret( 'A', ImmGetVirtualKey( hwnd ) ); + ok_eq( default_himc, ImmAssociateContext( hwnd, himc ), HIMC, "%p" ); + todo_wine ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) ); + ok_eq( himc, ImmAssociateContext( hwnd, default_himc ), HIMC, "%p" ); + ok_ret( 'A', ImmGetVirtualKey( hwnd ) ); + ImmDestroyContext( himc ); + + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'A', 0 ) ); + ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) ); + ok_ret( 1, ImmActivateLayout( default_hkl ) ); ok_ret( 1, ImmFreeLayout( hkl ) ); From 91389302c6c6ca2144d3800dd2f137eab1cd3003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 30 Apr 2023 14:42:22 +0200 Subject: [PATCH 1887/2777] imm32/tests: Test ImmTranslateMessage / ImeToAsciiEx calls. (cherry picked from commit 4b621dd9ae0dc891ac1bec2990db139df6830aae) --- dlls/imm32/tests/imm32.c | 354 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 336 insertions(+), 18 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 7841fc179f6..b8bb1b72249 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -252,17 +252,37 @@ static void check_logfont_a_( int line, LOGFONTA *font, const LOGFONTA *expect ) DEFINE_EXPECT(WM_IME_SETCONTEXT_DEACTIVATE); DEFINE_EXPECT(WM_IME_SETCONTEXT_ACTIVATE); -static void process_messages(void) +#define process_messages() process_messages_(0) +static void process_messages_(HWND hwnd) { MSG msg; - while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) + while (PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE )) { TranslateMessage( &msg ); DispatchMessageA( &msg ); } } +/* try to make sure pending X events have been processed before continuing */ +#define flush_events() flush_events_( 100, 200 ) +static void flush_events_( int min_timeout, int max_timeout ) +{ + DWORD time = GetTickCount() + max_timeout; + MSG msg; + + while (max_timeout > 0) + { + if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break; + while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageA( &msg ); + } + max_timeout = time - GetTickCount(); + } +} + #define ime_trace( msg, ... ) if (winetest_debug > 1) trace( "%04lx:%s " msg, GetCurrentThreadId(), __func__, ## __VA_ARGS__ ) static BOOL ImeSelect_init_status; @@ -294,6 +314,7 @@ enum ime_function IME_SELECT = 1, IME_NOTIFY, IME_PROCESS_KEY, + IME_TO_ASCII_EX, IME_SET_ACTIVE_CONTEXT, MSG_IME_UI, MSG_TEST_WIN, @@ -320,6 +341,12 @@ struct ime_call LPARAM lparam; } process_key; struct + { + UINT vkey; + UINT vsc; + UINT flags; + } to_ascii_ex; + struct { int flag; } set_active_context; @@ -334,6 +361,7 @@ struct ime_call BOOL todo; BOOL broken; BOOL flaky_himc; + BOOL todo_value; }; struct ime_call empty_sequence[] = {{0}}; @@ -364,6 +392,11 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected if ((ret = expected->process_key.vkey - received->process_key.vkey)) goto done; if ((ret = expected->process_key.lparam - received->process_key.lparam)) goto done; break; + case IME_TO_ASCII_EX: + if ((ret = expected->to_ascii_ex.vkey - received->to_ascii_ex.vkey)) goto done; + if ((ret = expected->to_ascii_ex.vsc - received->to_ascii_ex.vsc)) goto done; + if ((ret = expected->to_ascii_ex.flags - received->to_ascii_ex.flags)) goto done; + break; case IME_SET_ACTIVE_CONTEXT: if ((ret = expected->set_active_context.flag - received->set_active_context.flag)) goto done; break; @@ -381,32 +414,38 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected switch (received->func) { case IME_SELECT: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SELECT select %u\n", received->hkl, received->himc, received->select ); return ret; case IME_NOTIFY: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "got hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n", received->hkl, received->himc, received->notify.action, received->notify.index, received->notify.value ); return ret; case IME_PROCESS_KEY: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "got hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, lparam %#Ix\n", received->hkl, received->himc, received->process_key.vkey, received->process_key.lparam ); return ret; + case IME_TO_ASCII_EX: + todo_wine_if( expected->todo || expected->todo_value ) + ok_(file, line)( !ret, "got hkl %p, himc %p, IME_TO_ASCII_EX vkey %#x, vsc %#x, flags %#x\n", + received->hkl, received->himc, received->to_ascii_ex.vkey, received->to_ascii_ex.vsc, + received->to_ascii_ex.flags ); + return ret; case IME_SET_ACTIVE_CONTEXT: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "got hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", received->hkl, received->himc, received->set_active_context.flag ); return ret; case MSG_IME_UI: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, received->himc, received->message.msg, received->message.wparam, received->message.lparam ); return ret; case MSG_TEST_WIN: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, received->himc, received->message.msg, received->message.wparam, received->message.lparam ); return ret; @@ -415,32 +454,38 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected switch (expected->func) { case IME_SELECT: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "hkl %p, himc %p, IME_SELECT select %u\n", expected->hkl, expected->himc, expected->select ); break; case IME_NOTIFY: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "hkl %p, himc %p, IME_NOTIFY action %#x, index %#x, value %#x\n", expected->hkl, expected->himc, expected->notify.action, expected->notify.index, expected->notify.value ); break; case IME_PROCESS_KEY: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "hkl %p, himc %p, IME_PROCESS_KEY vkey %#x, lparam %#Ix\n", expected->hkl, expected->himc, expected->process_key.vkey, expected->process_key.lparam ); break; + case IME_TO_ASCII_EX: + todo_wine_if( expected->todo || expected->todo_value ) + ok_(file, line)( !ret, "hkl %p, himc %p, IME_TO_ASCII_EX vkey %#x, vsc %#x, flags %#x\n", + expected->hkl, expected->himc, expected->to_ascii_ex.vkey, expected->to_ascii_ex.vsc, + expected->to_ascii_ex.flags ); + break; case IME_SET_ACTIVE_CONTEXT: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "hkl %p, himc %p, IME_SET_ACTIVE_CONTEXT flag %u\n", expected->hkl, expected->himc, expected->set_active_context.flag ); break; case MSG_IME_UI: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); break; case MSG_TEST_WIN: - todo_wine_if( expected->todo ) + todo_wine_if( expected->todo || expected->todo_value ) ok_(file, line)( !ret, "hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); break; @@ -3394,11 +3439,70 @@ static BOOL WINAPI ime_ImeSetCompositionString( HIMC himc, DWORD index, const vo return TRUE; } -static UINT WINAPI ime_ImeToAsciiEx( UINT vkey, UINT scan_code, BYTE *key_state, TRANSMSGLIST *msgs, UINT state, HIMC himc ) +static UINT WINAPI ime_ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGLIST *msgs, UINT flags, HIMC himc ) { - ime_trace( "vkey %u, scan_code %u, key_state %p, msgs %p, state %u, himc %p\n", - vkey, scan_code, key_state, msgs, state, himc ); - return 0; + struct ime_call call = + { + .hkl = GetKeyboardLayout( 0 ), .himc = himc, + .func = IME_TO_ASCII_EX, .to_ascii_ex = {.vkey = vkey, .vsc = vsc, .flags = flags} + }; + INPUTCONTEXT *ctx; + UINT count = 0; + + ime_trace( "vkey %#x, vsc %#x, state %p, msgs %p, flags %#x, himc %p\n", + vkey, vsc, state, msgs, flags, himc ); + ime_calls[ime_call_count++] = call; + + ok_ne( NULL, msgs, TRANSMSGLIST *, "%p" ); + todo_wine ok_eq( 256, msgs->uMsgCount, UINT, "%u" ); + + ctx = ImmLockIMC( himc ); + todo_wine ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( ctx->hWnd ) ); + + if (vsc & 0x200) + { + msgs->TransMsg[0].message = WM_IME_STARTCOMPOSITION; + msgs->TransMsg[0].wParam = 1; + msgs->TransMsg[0].lParam = 0; + count++; + msgs->TransMsg[1].message = WM_IME_ENDCOMPOSITION; + msgs->TransMsg[1].wParam = 1; + msgs->TransMsg[1].lParam = 0; + count++; + } + + if (vsc & 0x400) + { + TRANSMSG *msgs; + + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + + ok_ne( NULL, ctx->hMsgBuf, HIMCC, "%p" ); + ok_eq( 0, ctx->dwNumMsgBuf, UINT, "%u" ); + + ctx->hMsgBuf = ImmReSizeIMCC( ctx->hMsgBuf, 64 * sizeof(*msgs) ); + ok_ne( NULL, ctx->hMsgBuf, HIMCC, "%p" ); + + msgs = ImmLockIMCC( ctx->hMsgBuf ); + ok_ne( NULL, msgs, TRANSMSG *, "%p" ); + + msgs[ctx->dwNumMsgBuf].message = WM_IME_STARTCOMPOSITION; + msgs[ctx->dwNumMsgBuf].wParam = 2; + msgs[ctx->dwNumMsgBuf].lParam = 0; + ctx->dwNumMsgBuf++; + msgs[ctx->dwNumMsgBuf].message = WM_IME_ENDCOMPOSITION; + msgs[ctx->dwNumMsgBuf].wParam = 2; + msgs[ctx->dwNumMsgBuf].lParam = 0; + ctx->dwNumMsgBuf++; + + ok_ret( 0, ImmUnlockIMCC( ctx->hMsgBuf ) ); + } + + ok_ret( 1, ImmUnlockIMC( himc ) ); + + if (vsc & 0x800) count = ~0; + return count; } static BOOL WINAPI ime_ImeUnregisterWord( const WCHAR *reading, DWORD style, const WCHAR *string ) @@ -6845,6 +6949,218 @@ static void test_ImmGenerateMessage(void) ime_call_count = 0; } +static void test_ImmTranslateMessage( BOOL kbd_char_first ) +{ + const struct ime_call process_key_seq[] = + { + { + .hkl = expect_ime, .himc = default_himc, .func = IME_PROCESS_KEY, + .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0x10)}, + }, + { + .hkl = expect_ime, .himc = default_himc, .func = IME_PROCESS_KEY, + .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0xc010)}, + }, + {.todo = TRUE}, + }; + const struct ime_call to_ascii_ex_0[] = + { + { + .hkl = expect_ime, .himc = default_himc, .func = IME_TO_ASCII_EX, + .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0x10}, + }, + {0}, + }; + const struct ime_call to_ascii_ex_1[] = + { + { + .hkl = expect_ime, .himc = default_himc, .func = IME_PROCESS_KEY, + .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0xc010)}, + }, + { + .hkl = expect_ime, .himc = default_himc, .func = IME_TO_ASCII_EX, + /* FIXME what happened to kbd_char_first here!? */ + .to_ascii_ex = {.vkey = 'Q', .vsc = 0xc010}, + .todo_value = TRUE, + }, + {0}, + }; + struct ime_call to_ascii_ex_2[] = + { + { + .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY, + .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0x210)}, + }, + { + .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX, + .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0x210}, + .todo_value = TRUE, + }, + { + .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY, + .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0x410)}, + }, + { + .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX, + .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0x410}, + .todo_value = TRUE, + }, + {0}, + }; + struct ime_call to_ascii_ex_3[] = + { + { + .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY, + .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0xa10)}, + }, + { + .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX, + .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0xa10}, + .todo_value = TRUE, + }, + { + .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY, + .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0xc10)}, + }, + { + .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX, + .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0xc10}, + .todo_value = TRUE, + }, + {0}, + }; + struct ime_call post_messages[] = + { + {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 1}}, + {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_IME_UI, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 1}}, + {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 1}}, + {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_IME_UI, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 1}}, + {0}, + }; + struct ime_call sent_messages[] = + { + {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 2}}, + {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_IME_UI, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 2}}, + {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 2}}, + {.hkl = expect_ime, .himc = 0/*himc*/, .func = MSG_IME_UI, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 2}}, + {0}, + }; + HWND hwnd, other_hwnd; + INPUTCONTEXT *ctx; + HIMC himc; + HKL hkl; + UINT i, ret; + + ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; + if (kbd_char_first) ime_info.fdwProperty |= IME_PROP_KBD_CHAR_FIRST; + + winetest_push_context( kbd_char_first ? "kbd_char_first" : "default" ); + + if (!(hkl = wineime_hkl)) goto cleanup; + + other_hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!other_hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + flush_events(); + + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + flush_events(); + + ok_ret( 1, ImmActivateLayout( hkl ) ); + ok_ret( 1, ImmLoadIME( hkl ) ); + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + process_messages(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0x10), 0 ) ); + ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0xc010), 0 ) ); + + ok_ret( 0, ImmTranslateMessage( hwnd, 0, 0, 0 ) ); + todo_wine ok_ret( 'Q', ImmGetVirtualKey( hwnd ) ); + ok_seq( process_key_seq ); + + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'Q', MAKELONG(2, 0x10) ) ); + ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) ); + todo_wine ok_seq( to_ascii_ex_0 ); + + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0xc010) ) ); + ok_seq( empty_sequence ); + + ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0xc010), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0xc010) ) ); + ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) ); + ok_seq( to_ascii_ex_1 ); + + ok_eq( default_himc, ImmAssociateContext( hwnd, himc ), HIMC, "%p" ); + ok_eq( default_himc, ImmAssociateContext( other_hwnd, himc ), HIMC, "%p" ); + for (i = 0; i < ARRAY_SIZE(to_ascii_ex_2); i++) to_ascii_ex_2[i].himc = himc; + for (i = 0; i < ARRAY_SIZE(to_ascii_ex_3); i++) to_ascii_ex_3[i].himc = himc; + for (i = 0; i < ARRAY_SIZE(post_messages); i++) post_messages[i].himc = himc; + for (i = 0; i < ARRAY_SIZE(sent_messages); i++) sent_messages[i].himc = himc; + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + ctx->hWnd = hwnd; + ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0x210), 0 ) ); + ret = ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x210) ); + todo_wine ok_eq( 1, ret, UINT, "%u" ); + ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0x410), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x410) ) ); + ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) ); + ok_seq( to_ascii_ex_2 ); + process_messages(); + todo_wine ok_seq( post_messages ); + ok_ret( 1, ImmGenerateMessage( himc ) ); + todo_wine ok_seq( sent_messages ); + + ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0xa10), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0xa10) ) ); + ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0xc10), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0xc10) ) ); + ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) ); + ok_seq( to_ascii_ex_3 ); + process_messages(); + ok_seq( empty_sequence ); + ok_ret( 1, ImmGenerateMessage( himc ) ); + todo_wine ok_seq( sent_messages ); + + ctx->hWnd = 0; + ok_ret( 2, ImmProcessKey( other_hwnd, expect_ime, 'Q', MAKELONG(2, 0x210), 0 ) ); + ret = ImmTranslateMessage( other_hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x210) ); + todo_wine ok_eq( 1, ret, UINT, "%u" ); + ok_ret( 2, ImmProcessKey( other_hwnd, expect_ime, 'Q', MAKELONG(2, 0x410), 0 ) ); + ok_ret( 0, ImmTranslateMessage( other_hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x410) ) ); + ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( other_hwnd ) ); + ok_seq( to_ascii_ex_2 ); + process_messages_( hwnd ); + ok_seq( empty_sequence ); + process_messages_( other_hwnd ); + todo_wine ok_seq( post_messages ); + ok_ret( 1, ImmGenerateMessage( himc ) ); + ok_seq( empty_sequence ); + + ok_ret( 1, ImmUnlockIMC( himc ) ); + ok_ret( 1, ImmDestroyContext( himc ) ); + + ok_ret( 1, ImmActivateLayout( default_hkl ) ); + ok_ret( 1, DestroyWindow( other_hwnd ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + + ok_ret( 1, ImmFreeLayout( hkl ) ); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + +cleanup: + winetest_pop_context(); +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); @@ -6908,6 +7224,8 @@ START_TEST(imm32) test_ImmSetCandidateWindow(); test_ImmGenerateMessage(); + test_ImmTranslateMessage( FALSE ); + test_ImmTranslateMessage( TRUE ); if (wineime_hkl) ime_cleanup( wineime_hkl, TRUE ); From 429fecc0875de1e12da36e40f042d27121f6a33d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 30 Apr 2023 23:26:32 +0200 Subject: [PATCH 1888/2777] imm32: Ignore some messages in ImmTranslateMessage. (cherry picked from commit bfb7799b74e6deac213e224bc384186d8e88282f) --- dlls/imm32/imm.c | 1 + dlls/imm32/tests/imm32.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 08af055275e..82d2ea4d897 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3124,6 +3124,7 @@ BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + if (msg < WM_KEYDOWN || msg > WM_KEYUP) return FALSE; if (!(data = get_imc_data( ImmGetContext( hwnd ) ))) return FALSE; if (!(ime = imc_select_ime( data ))) return FALSE; if (data->lastVK == VK_PROCESSKEY) return FALSE; diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index b8bb1b72249..3f8736483d8 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -7082,12 +7082,12 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0xc010), 0 ) ); ok_ret( 0, ImmTranslateMessage( hwnd, 0, 0, 0 ) ); - todo_wine ok_ret( 'Q', ImmGetVirtualKey( hwnd ) ); + ok_ret( 'Q', ImmGetVirtualKey( hwnd ) ); ok_seq( process_key_seq ); ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'Q', MAKELONG(2, 0x10) ) ); ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) ); - todo_wine ok_seq( to_ascii_ex_0 ); + ok_seq( to_ascii_ex_0 ); ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0xc010) ) ); ok_seq( empty_sequence ); From b68e428629e4b42564cdf9bcf76a45279a254b40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 1 May 2023 11:37:50 +0200 Subject: [PATCH 1889/2777] imm32: Clear vkey before calling ToAsciiEx in ImmTranslateMessage. (cherry picked from commit 1c96ed9bd9f44bc6b2bf2ea5c4c38c2dbf1a3f1e) --- dlls/imm32/imm.c | 48 ++++++++++++++-------------------------- dlls/imm32/tests/imm32.c | 2 +- 2 files changed, 18 insertions(+), 32 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 82d2ea4d897..8b086027fa0 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -85,8 +85,8 @@ struct imc DWORD dwLock; INPUTCONTEXT IMC; - struct ime *ime; - UINT lastVK; + struct ime *ime; + UINT vkey; HWND ui_hwnd; /* IME UI window, on the default input context */ }; @@ -2111,27 +2111,15 @@ BOOL WINAPI ImmGetStatusWindowPos( HIMC himc, POINT *pos ) /*********************************************************************** * ImmGetVirtualKey (IMM32.@) */ -UINT WINAPI ImmGetVirtualKey(HWND hWnd) -{ - OSVERSIONINFOA version; - struct imc *data = get_imc_data( ImmGetContext( hWnd ) ); - TRACE("%p\n", hWnd); - - if ( data ) - return data->lastVK; - - version.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); - GetVersionExA( &version ); - switch(version.dwPlatformId) - { - case VER_PLATFORM_WIN32_WINDOWS: - return VK_PROCESSKEY; - case VER_PLATFORM_WIN32_NT: - return 0; - default: - FIXME("%ld not supported\n",version.dwPlatformId); - return VK_PROCESSKEY; - } +UINT WINAPI ImmGetVirtualKey( HWND hwnd ) +{ + HIMC himc = ImmGetContext( hwnd ); + struct imc *imc; + + TRACE( "%p\n", hwnd ); + + if ((imc = get_imc_data( himc ))) return imc->vkey; + return VK_PROCESSKEY; } /*********************************************************************** @@ -3127,17 +3115,17 @@ BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar if (msg < WM_KEYDOWN || msg > WM_KEYUP) return FALSE; if (!(data = get_imc_data( ImmGetContext( hwnd ) ))) return FALSE; if (!(ime = imc_select_ime( data ))) return FALSE; - if (data->lastVK == VK_PROCESSKEY) return FALSE; + if ((vkey = data->vkey) == VK_PROCESSKEY) return FALSE; + data->vkey = VK_PROCESSKEY; GetKeyboardState( state ); scan = lparam >> 0x10 & 0xff; - vkey = data->lastVK; if (ime->info.fdwProperty & IME_PROP_KBD_CHAR_FIRST) { - if (!ime_is_unicode( ime )) ToAscii( data->lastVK, scan, state, &chr, 0 ); - else ToUnicodeEx( data->lastVK, scan, state, &chr, 1, 0, GetKeyboardLayout( 0 ) ); - vkey = MAKELONG( data->lastVK, chr ); + if (!ime_is_unicode( ime )) ToAscii( vkey, scan, state, &chr, 0 ); + else ToUnicodeEx( vkey, scan, state, &chr, 1, 0, GetKeyboardLayout( 0 ) ); + vkey = MAKELONG( vkey, chr ); } count = ime->pImeToAsciiEx( vkey, scan, state, &buffer.list, 0, data->handle ); @@ -3146,8 +3134,6 @@ BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar if (count > ARRAY_SIZE(buffer.TransMsg)) ImmGenerateMessage( data->handle ); else for (i = 0; i < count; i++) imc_post_message( data, buffer.TransMsg + i ); - data->lastVK = VK_PROCESSKEY; - return count > 0; } @@ -3171,7 +3157,7 @@ BOOL WINAPI ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM lparam, DWORD u GetKeyboardState( state ); ret = ime->pImeProcessKey( imc->handle, vkey, lparam, state ); - imc->lastVK = ret ? vkey : VK_PROCESSKEY; + imc->vkey = ret ? vkey : VK_PROCESSKEY; return ret; } diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 3f8736483d8..d7748c53df2 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -3457,7 +3457,7 @@ static UINT WINAPI ime_ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGL todo_wine ok_eq( 256, msgs->uMsgCount, UINT, "%u" ); ctx = ImmLockIMC( himc ); - todo_wine ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( ctx->hWnd ) ); + ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( ctx->hWnd ) ); if (vsc & 0x200) { From 1a19ed9d7367a54b72284ed464f5d1b9e05a7e71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 1 May 2023 11:34:58 +0200 Subject: [PATCH 1890/2777] imm32: Post messages to the target window in ImmTranslateMessage. (cherry picked from commit f99ad772d1d5d43204d6ca730c72fda21bebdafc) --- dlls/imm32/imm.c | 16 +++++----------- dlls/imm32/tests/imm32.c | 22 ++++++++-------------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 8b086027fa0..2fe355da5bb 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -821,13 +821,6 @@ BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved ) return TRUE; } -static void imc_post_message( struct imc *imc, TRANSMSG *message ) -{ - HWND target; - if (!(target = GetFocus()) && !(target = imc->IMC.hWnd)) return; - PostMessageW( target, message->message, message->wParam, message->lParam ); -} - /*********************************************************************** * ImmSetActiveContext (IMM32.@) */ @@ -3104,6 +3097,7 @@ BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar }; TRANSMSGLIST list; } buffer = {.uMsgCount = ARRAY_SIZE(buffer.TransMsg)}; + TRANSMSG *msgs = buffer.TransMsg; UINT scan, vkey, count, i; struct imc *data; struct ime *ime; @@ -3119,7 +3113,7 @@ BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar if ((vkey = data->vkey) == VK_PROCESSKEY) return FALSE; data->vkey = VK_PROCESSKEY; GetKeyboardState( state ); - scan = lparam >> 0x10 & 0xff; + scan = lparam >> 0x10; if (ime->info.fdwProperty & IME_PROP_KBD_CHAR_FIRST) { @@ -3129,10 +3123,10 @@ BOOL WINAPI ImmTranslateMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar } count = ime->pImeToAsciiEx( vkey, scan, state, &buffer.list, 0, data->handle ); - TRACE( "%u messages generated\n", count ); + if (count >= ARRAY_SIZE(buffer.TransMsg)) return 0; - if (count > ARRAY_SIZE(buffer.TransMsg)) ImmGenerateMessage( data->handle ); - else for (i = 0; i < count; i++) imc_post_message( data, buffer.TransMsg + i ); + for (i = 0; i < count; i++) PostMessageW( hwnd, msgs[i].message, msgs[i].wParam, msgs[i].lParam ); + TRACE( "%u messages generated\n", count ); return count > 0; } diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index d7748c53df2..990d410f985 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -6961,7 +6961,7 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) .hkl = expect_ime, .himc = default_himc, .func = IME_PROCESS_KEY, .process_key = {.vkey = 'Q', .lparam = MAKELONG(2, 0xc010)}, }, - {.todo = TRUE}, + {0}, }; const struct ime_call to_ascii_ex_0[] = { @@ -6994,7 +6994,6 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) { .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX, .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0x210}, - .todo_value = TRUE, }, { .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY, @@ -7003,7 +7002,6 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) { .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX, .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0x410}, - .todo_value = TRUE, }, {0}, }; @@ -7016,7 +7014,6 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) { .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX, .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0xa10}, - .todo_value = TRUE, }, { .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_PROCESS_KEY, @@ -7025,7 +7022,6 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) { .hkl = expect_ime, .himc = 0/*himc*/, .func = IME_TO_ASCII_EX, .to_ascii_ex = {.vkey = kbd_char_first ? MAKELONG('Q', 'q') : 'Q', .vsc = 0xc10}, - .todo_value = TRUE, }, {0}, }; @@ -7049,7 +7045,7 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) INPUTCONTEXT *ctx; HIMC himc; HKL hkl; - UINT i, ret; + UINT i; ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; if (kbd_char_first) ime_info.fdwProperty |= IME_PROP_KBD_CHAR_FIRST; @@ -7108,16 +7104,15 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) ctx->hWnd = hwnd; ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0x210), 0 ) ); - ret = ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x210) ); - todo_wine ok_eq( 1, ret, UINT, "%u" ); + ok_ret( 1, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x210) ) ); ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0x410), 0 ) ); ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x410) ) ); ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( hwnd ) ); ok_seq( to_ascii_ex_2 ); process_messages(); - todo_wine ok_seq( post_messages ); + ok_seq( post_messages ); ok_ret( 1, ImmGenerateMessage( himc ) ); - todo_wine ok_seq( sent_messages ); + ok_seq( sent_messages ); ok_ret( 2, ImmProcessKey( hwnd, expect_ime, 'Q', MAKELONG(2, 0xa10), 0 ) ); ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0xa10) ) ); @@ -7128,12 +7123,11 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) process_messages(); ok_seq( empty_sequence ); ok_ret( 1, ImmGenerateMessage( himc ) ); - todo_wine ok_seq( sent_messages ); + ok_seq( sent_messages ); ctx->hWnd = 0; ok_ret( 2, ImmProcessKey( other_hwnd, expect_ime, 'Q', MAKELONG(2, 0x210), 0 ) ); - ret = ImmTranslateMessage( other_hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x210) ); - todo_wine ok_eq( 1, ret, UINT, "%u" ); + ok_ret( 1, ImmTranslateMessage( other_hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x210) ) ); ok_ret( 2, ImmProcessKey( other_hwnd, expect_ime, 'Q', MAKELONG(2, 0x410), 0 ) ); ok_ret( 0, ImmTranslateMessage( other_hwnd, WM_KEYUP, 'Q', MAKELONG(2, 0x410) ) ); ok_ret( VK_PROCESSKEY, ImmGetVirtualKey( other_hwnd ) ); @@ -7141,7 +7135,7 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) process_messages_( hwnd ); ok_seq( empty_sequence ); process_messages_( other_hwnd ); - todo_wine ok_seq( post_messages ); + ok_seq( post_messages ); ok_ret( 1, ImmGenerateMessage( himc ) ); ok_seq( empty_sequence ); From 309135fcea663e18e06c7ec42a38755b39367ec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 5 May 2023 08:45:34 +0200 Subject: [PATCH 1891/2777] imm32/tests: Adjust the ImmSetOpenStatus tests for MS Korean IME. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54864 (cherry picked from commit 2fe97d51787ca0f8f85f92a5e328d91f53f2cb78) --- dlls/imm32/tests/imm32.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 990d410f985..7e8af4094ca 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4762,6 +4762,8 @@ static void test_ImmSetOpenStatus(void) ok_eq( 0xdeadbeef, status, UINT, "%#x" ); ok_eq( 0xdeadbeef, ctx->fOpen, UINT, "%#x" ); + ok_ret( 1, ImmSetOpenStatus( default_himc, 0xdeadbeef ) ); + ok_seq( empty_sequence ); himc = ImmCreateContext(); ok_ne( NULL, himc, HIMC, "%p" ); @@ -4777,13 +4779,9 @@ static void test_ImmSetOpenStatus(void) memset( ime_calls, 0, sizeof(ime_calls) ); ime_call_count = 0; - - ok_ret( 1, ImmSetOpenStatus( default_himc, 0xdeadbeef ) ); - ok_seq( empty_sequence ); - status = ImmGetOpenStatus( default_himc ); - ok_eq( 0xdeadbeef, status, UINT, "%#x" ); - ok_eq( 0xdeadbeef, ctx->fOpen, UINT, "%#x" ); + ok( status == 0xdeadbeef || status == 0 /* MS Korean IME */, "got status %#lx\n", status ); + ok_eq( status, ctx->fOpen, UINT, "%#x" ); ctx->hWnd = 0; ok_ret( 1, ImmSetOpenStatus( default_himc, 0xfeedcafe ) ); From 52fe3b182c3c96630335972deca69737415c356d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 30 Apr 2023 20:18:20 +0200 Subject: [PATCH 1892/2777] imm32/tests: Print human readable IME message names. (cherry picked from commit fc7203fb136edf7f9e7460bb2534fe2052ea27c0) --- dlls/imm32/tests/imm32.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 7e8af4094ca..78cae50dbbb 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -35,6 +35,26 @@ #include "ime_test.h" +static const char *debugstr_wm_ime( UINT msg ) +{ + switch (msg) + { + case WM_IME_STARTCOMPOSITION: return "WM_IME_STARTCOMPOSITION"; + case WM_IME_ENDCOMPOSITION: return "WM_IME_ENDCOMPOSITION"; + case WM_IME_COMPOSITION: return "WM_IME_COMPOSITION"; + case WM_IME_SETCONTEXT: return "WM_IME_SETCONTEXT"; + case WM_IME_NOTIFY: return "WM_IME_NOTIFY"; + case WM_IME_CONTROL: return "WM_IME_CONTROL"; + case WM_IME_COMPOSITIONFULL: return "WM_IME_COMPOSITIONFULL"; + case WM_IME_SELECT: return "WM_IME_SELECT"; + case WM_IME_CHAR: return "WM_IME_CHAR"; + case WM_IME_REQUEST: return "WM_IME_REQUEST"; + case WM_IME_KEYDOWN: return "WM_IME_KEYDOWN"; + case WM_IME_KEYUP: return "WM_IME_KEYUP"; + default: return wine_dbg_sprintf( "%#x", msg ); + } +} + static const char *debugstr_ok( const char *cond ) { int c, n = 0; @@ -441,13 +461,13 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected return ret; case MSG_IME_UI: todo_wine_if( expected->todo || expected->todo_value ) - ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, - received->himc, received->message.msg, received->message.wparam, received->message.lparam ); + ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_IME_UI msg %s, wparam %#Ix, lparam %#Ix\n", received->hkl, + received->himc, debugstr_wm_ime(received->message.msg), received->message.wparam, received->message.lparam ); return ret; case MSG_TEST_WIN: todo_wine_if( expected->todo || expected->todo_value ) - ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", received->hkl, - received->himc, received->message.msg, received->message.wparam, received->message.lparam ); + ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_TEST_WIN msg %s, wparam %#Ix, lparam %#Ix\n", received->hkl, + received->himc, debugstr_wm_ime(received->message.msg), received->message.wparam, received->message.lparam ); return ret; } @@ -481,13 +501,13 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected break; case MSG_IME_UI: todo_wine_if( expected->todo || expected->todo_value ) - ok_(file, line)( !ret, "hkl %p, himc %p, MSG_IME_UI msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, - expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); + ok_(file, line)( !ret, "hkl %p, himc %p, MSG_IME_UI msg %s, wparam %#Ix, lparam %#Ix\n", expected->hkl, + expected->himc, debugstr_wm_ime(expected->message.msg), expected->message.wparam, expected->message.lparam ); break; case MSG_TEST_WIN: todo_wine_if( expected->todo || expected->todo_value ) - ok_(file, line)( !ret, "hkl %p, himc %p, MSG_TEST_WIN msg %#x, wparam %#Ix, lparam %#Ix\n", expected->hkl, - expected->himc, expected->message.msg, expected->message.wparam, expected->message.lparam ); + ok_(file, line)( !ret, "hkl %p, himc %p, MSG_TEST_WIN msg %s, wparam %#Ix, lparam %#Ix\n", expected->hkl, + expected->himc, debugstr_wm_ime(expected->message.msg), expected->message.wparam, expected->message.lparam ); break; } From 147cd413e7ab2fa3fc08cf7585d33928b491bf5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 30 Apr 2023 20:45:28 +0200 Subject: [PATCH 1893/2777] imm32/tests: Ignore some unknown WM_IME_NOTIFY messages. (cherry picked from commit 24ccd03e3ef71bbf77a625f0fb80bbd9b7423887) --- dlls/imm32/tests/imm32.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 78cae50dbbb..c7805dec996 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -544,15 +544,16 @@ static void ok_seq_( const char *file, int line, const struct ime_call *expected static BOOL check_WM_SHOWWINDOW; -static BOOL ignore_message( UINT msg ) +static BOOL ignore_message( UINT msg, WPARAM wparam ) { switch (msg) { + case WM_IME_NOTIFY: + return wparam > IMN_PRIVATE; case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION: case WM_IME_COMPOSITION: case WM_IME_SETCONTEXT: - case WM_IME_NOTIFY: case WM_IME_CONTROL: case WM_IME_COMPOSITIONFULL: case WM_IME_SELECT: @@ -580,7 +581,7 @@ static LRESULT CALLBACK ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); - if (ignore_message( msg )) return DefWindowProcW( hwnd, msg, wparam, lparam ); + if (ignore_message( msg, wparam )) return DefWindowProcW( hwnd, msg, wparam, lparam ); ptr = GetWindowLongPtrW( hwnd, IMMGWL_PRIVATE ); ok( !ptr, "got IMMGWL_PRIVATE %#Ix\n", ptr ); @@ -599,7 +600,7 @@ static LRESULT CALLBACK test_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LP ime_trace( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); - if (ignore_message( msg )) return DefWindowProcW( hwnd, msg, wparam, lparam ); + if (ignore_message( msg, wparam )) return DefWindowProcW( hwnd, msg, wparam, lparam ); ime_calls[ime_call_count++] = call; return DefWindowProcW( hwnd, msg, wparam, lparam ); From 1eefd7e328d07c662a4cbcc98ecbb1ccd9f070fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 5 May 2023 07:46:26 +0200 Subject: [PATCH 1894/2777] imm32/tests: Add some missing local variables declarations. (cherry picked from commit 828fc9f50df2e55e9a8005f395e633bb59d9d17d) --- dlls/imm32/tests/imm32.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index c7805dec996..a6b57c123b7 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -4567,6 +4567,7 @@ static void test_ImmSetConversionStatus(void) DWORD old_conversion, old_sentence, conversion, sentence; HKL hkl; INPUTCONTEXT *ctx; + HWND hwnd; ok_ret( 0, ImmGetConversionStatus( 0, &old_conversion, &old_sentence ) ); ok_ret( 1, ImmGetConversionStatus( default_himc, &old_conversion, &old_sentence ) ); @@ -4737,6 +4738,7 @@ static void test_ImmSetOpenStatus(void) DWORD old_status, status; INPUTCONTEXT *ctx; HIMC himc; + HWND hwnd; ok_ret( 0, ImmGetOpenStatus( 0 ) ); old_status = ImmGetOpenStatus( default_himc ); @@ -4890,6 +4892,7 @@ static void test_ImmProcessKey(void) HKL hkl; UINT_PTR ret; HIMC himc; + HWND hwnd; hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 100, 100, NULL, NULL, NULL, NULL ); @@ -5046,6 +5049,7 @@ static void test_ImmActivateLayout(void) HKL hkl; struct ime_windows ime_windows = {0}; HIMC himc; + HWND hwnd; UINT ret; SET_ENABLE( ImeInquire, TRUE ); @@ -5384,6 +5388,7 @@ static void test_DefWindowProc(void) }; HKL hkl; UINT_PTR ret; + HWND hwnd; ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; @@ -5524,6 +5529,7 @@ static void test_ImmSetActiveContext(void) struct ime_windows ime_windows = {0}; INPUTCONTEXT *ctx; HIMC himc; + HWND hwnd; ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; @@ -5674,6 +5680,7 @@ static void test_ImmRequestMessage(void) LOGFONTW log_font = {0}; INPUTCONTEXT *ctx; HIMC himc; + HWND hwnd; if (!(hkl = wineime_hkl)) return; @@ -5751,6 +5758,7 @@ static void test_ImmGetCandidateList( BOOL unicode ) CANDIDATEINFO *cand_info; INPUTCONTEXT *ctx; HIMC himc; + HWND hwnd; expect_listW = (CANDIDATELIST *)expect_bufW; expect_listW->dwSize = offsetof(CANDIDATELIST, dwOffset[2]) + 32 * sizeof(WCHAR); @@ -5878,6 +5886,7 @@ static void test_ImmGetCandidateListCount( BOOL unicode ) INPUTCONTEXT *ctx; DWORD count; HIMC himc; + HWND hwnd; winetest_push_context( unicode ? "unicode" : "ansi" ); @@ -5957,6 +5966,7 @@ static void test_ImmGetCandidateWindow(void) CANDIDATEFORM cand_form; INPUTCONTEXT *ctx; HIMC himc; + HWND hwnd; ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; @@ -6109,6 +6119,7 @@ static void test_ImmGetCompositionString( BOOL unicode ) UINT i, len; BYTE *dst; HIMC himc; + HWND hwnd; SET_ENABLE( ImeSetCompositionString, TRUE ); @@ -6429,6 +6440,7 @@ static void test_ImmSetCompositionWindow(void) struct ime_windows ime_windows = {0}; INPUTCONTEXT *ctx; HIMC himc; + HWND hwnd; HKL hkl; ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; @@ -6543,6 +6555,7 @@ static void test_ImmSetStatusWindowPos(void) INPUTCONTEXT *ctx; POINT pos; HIMC himc; + HWND hwnd; HKL hkl; ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; @@ -6674,6 +6687,7 @@ static void test_ImmSetCompositionFont( BOOL unicode ) }; INPUTCONTEXT *ctx; HIMC himc; + HWND hwnd; HKL hkl; winetest_push_context( unicode ? "unicode" : "ansi" ); @@ -6802,6 +6816,7 @@ static void test_ImmSetCandidateWindow(void) }; INPUTCONTEXT *ctx; HIMC himc; + HWND hwnd; HKL hkl; ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; @@ -6885,6 +6900,7 @@ static void test_ImmGenerateMessage(void) TRANSMSG *msgs, *tmp_msgs; INPUTCONTEXT *ctx; HIMC himc; + HWND hwnd; HKL hkl; ime_info.fdwProperty = IME_PROP_END_UNLOAD | IME_PROP_UNICODE; From 27ff9fd8e74f8b008d4fac5d862298aca97c70d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 30 Apr 2023 20:25:51 +0200 Subject: [PATCH 1895/2777] imm32/tests: Test MS Korean IME GA-NA-DA sequence. Credits to Byeong-Sik Jeon for the sequence, thanks! (cherry picked from commit 2024e45b9f17c62913c8f3837f7fa5ee8d589c26) --- dlls/imm32/tests/imm32.c | 279 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 275 insertions(+), 4 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index a6b57c123b7..03bf91286a5 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -346,6 +346,9 @@ struct ime_call HIMC himc; enum ime_function func; + WCHAR comp[16]; + WCHAR result[16]; + union { int select; @@ -425,6 +428,8 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected if ((ret = expected->message.msg - received->message.msg)) goto done; if ((ret = (expected->message.wparam - received->message.wparam))) goto done; if ((ret = (expected->message.lparam - received->message.lparam))) goto done; + if ((ret = wcscmp( expected->comp, received->comp ))) goto done; + if ((ret = wcscmp( expected->result, received->result ))) goto done; break; } @@ -466,8 +471,9 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected return ret; case MSG_TEST_WIN: todo_wine_if( expected->todo || expected->todo_value ) - ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_TEST_WIN msg %s, wparam %#Ix, lparam %#Ix\n", received->hkl, - received->himc, debugstr_wm_ime(received->message.msg), received->message.wparam, received->message.lparam ); + ok_(file, line)( !ret, "got hkl %p, himc %p, MSG_TEST_WIN msg %s, wparam %#Ix, lparam %#Ix, comp %s, result %s\n", received->hkl, + received->himc, debugstr_wm_ime(received->message.msg), received->message.wparam, received->message.lparam, + debugstr_w(received->comp), debugstr_w(received->result) ); return ret; } @@ -506,8 +512,9 @@ static int ok_call_( const char *file, int line, const struct ime_call *expected break; case MSG_TEST_WIN: todo_wine_if( expected->todo || expected->todo_value ) - ok_(file, line)( !ret, "hkl %p, himc %p, MSG_TEST_WIN msg %s, wparam %#Ix, lparam %#Ix\n", expected->hkl, - expected->himc, debugstr_wm_ime(expected->message.msg), expected->message.wparam, expected->message.lparam ); + ok_(file, line)( !ret, "hkl %p, himc %p, MSG_TEST_WIN msg %s, wparam %#Ix, lparam %#Ix, comp %s, result %s\n", expected->hkl, + expected->himc, debugstr_wm_ime(expected->message.msg), expected->message.wparam, expected->message.lparam, + debugstr_w(expected->comp), debugstr_w(expected->result) ); break; } @@ -602,6 +609,12 @@ static LRESULT CALLBACK test_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LP if (ignore_message( msg, wparam )) return DefWindowProcW( hwnd, msg, wparam, lparam ); + if (msg == WM_IME_COMPOSITION) + { + ImmGetCompositionStringW( call.himc, GCS_COMPSTR, call.comp, sizeof(call.comp) ); + ImmGetCompositionStringW( call.himc, GCS_RESULTSTR, call.result, sizeof(call.result) ); + } + ime_calls[ime_call_count++] = call; return DefWindowProcW( hwnd, msg, wparam, lparam ); } @@ -7190,6 +7203,262 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first ) winetest_pop_context(); } +static void test_ga_na_da(void) +{ + /* These sequences have some additional WM_IME_NOTIFY messages with unknown wparam > IMN_PRIVATE */ + struct ime_call complete_seq[] = + { + /* G */ + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 0, .lparam = 0}}, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u3131", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x3131, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET}, + }, + /* A */ + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uac00", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac00, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET}, + }, + /* N */ + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uac04", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac04, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET}, + }, + /* A */ + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub098", .result = L"\uac00", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac00, .lparam = GCS_RESULTSTR}, + }, + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0xac00, .lparam = 0x1}}, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub098", .result = L"\uac00", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb098, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET}, + }, + /* D */ + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub09f", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb09f, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET}, + }, + /* A */ + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub2e4", .result = L"\ub098", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb098, .lparam = GCS_RESULTSTR}, + }, + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0xb098, .lparam = 0x1}}, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub2e4", .result = L"\ub098", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb2e4, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET}, + }, + /* RETURN */ + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 0, .lparam = 0}}, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"", .result = L"\ub2e4", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb2e4, .lparam = GCS_RESULTSTR}, + }, + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0xb2e4, .lparam = 0x1}}, + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_KEYDOWN, .wparam = 0xd, .lparam = 0x1c0001}}, + {0}, + }; + struct ime_call partial_g_seq[] = + { + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 0, .lparam = 0}}, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u3131", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x3131, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET}, + }, + {0}, + }; + struct ime_call partial_ga_seq[] = + { + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uac00", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac00, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET}, + }, + {0}, + }; + struct ime_call partial_n_seq[] = + { + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uac04", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac04, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET}, + }, + {0}, + }; + struct ime_call partial_na_seq[] = + { + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub098", .result = L"\uac00", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xac00, .lparam = GCS_RESULTSTR}, + }, + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0xac00, .lparam = 0x1}}, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub098", .result = L"\uac00", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb098, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET}, + }, + {0}, + }; + struct ime_call partial_d_seq[] = + { + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub09f", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb09f, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET}, + }, + {0}, + }; + struct ime_call partial_da_seq[] = + { + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub2e4", .result = L"\ub098", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb098, .lparam = GCS_RESULTSTR}, + }, + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0xb098, .lparam = 0x1}}, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\ub2e4", .result = L"\ub098", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb2e4, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET}, + }, + {0}, + }; + struct ime_call partial_return_seq[] = + { + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 0, .lparam = 0}}, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"", .result = L"\ub2e4", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xb2e4, .lparam = GCS_RESULTSTR}, + }, + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0xb2e4, .lparam = 0x1}}, + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_KEYDOWN, .wparam = 0xd, .lparam = 0x1c0001}}, + {0}, + }; + + INPUTCONTEXT *ctx; + HWND hwnd; + HIMC himc; + UINT i; + + /* this test doesn't work on Win32 / WoW64 */ + if (sizeof(void *) == 4 || default_hkl != (HKL)0x04120412 /* MS Korean IME */) + { + skip( "Got hkl %p, skipping Korean IME-specific test\n", default_hkl ); + process_messages(); + return; + } + + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + flush_events(); + + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + ok_eq( default_himc, ImmAssociateContext( hwnd, himc ), HIMC, "%p" ); + ok_ret( 1, ImmSetOpenStatus( himc, TRUE ) ); + ok_ret( 1, ImmSetConversionStatus( himc, IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE, IME_SMODE_PHRASEPREDICT ) ); + flush_events(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + for (i = 0; i < ARRAY_SIZE(complete_seq); i++) complete_seq[i].himc = himc; + for (i = 0; i < ARRAY_SIZE(partial_g_seq); i++) partial_g_seq[i].himc = himc; + for (i = 0; i < ARRAY_SIZE(partial_ga_seq); i++) partial_ga_seq[i].himc = himc; + for (i = 0; i < ARRAY_SIZE(partial_n_seq); i++) partial_n_seq[i].himc = himc; + for (i = 0; i < ARRAY_SIZE(partial_na_seq); i++) partial_na_seq[i].himc = himc; + for (i = 0; i < ARRAY_SIZE(partial_d_seq); i++) partial_d_seq[i].himc = himc; + for (i = 0; i < ARRAY_SIZE(partial_da_seq); i++) partial_da_seq[i].himc = himc; + for (i = 0; i < ARRAY_SIZE(partial_return_seq); i++) partial_return_seq[i].himc = himc; + + keybd_event( 'R', 0x13, 0, 0 ); + flush_events(); + keybd_event( 'R', 0x13, KEYEVENTF_KEYUP, 0 ); + + keybd_event( 'K', 0x25, 0, 0 ); + flush_events(); + keybd_event( 'K', 0x25, KEYEVENTF_KEYUP, 0 ); + + keybd_event( 'S', 0x1f, 0, 0 ); + flush_events(); + keybd_event( 'S', 0x1f, KEYEVENTF_KEYUP, 0 ); + + keybd_event( 'K', 0x25, 0, 0 ); + flush_events(); + keybd_event( 'K', 0x25, KEYEVENTF_KEYUP, 0 ); + + keybd_event( 'E', 0x12, 0, 0 ); + flush_events(); + keybd_event( 'E', 0x12, KEYEVENTF_KEYUP, 0 ); + + keybd_event( 'K', 0x25, 0, 0 ); + flush_events(); + keybd_event( 'K', 0x25, KEYEVENTF_KEYUP, 0 ); + + keybd_event( VK_RETURN, 0x1c, 0, 0 ); + flush_events(); + keybd_event( VK_RETURN, 0x1c, KEYEVENTF_KEYUP, 0 ); + + flush_events(); + todo_wine ok_seq( complete_seq ); + + + /* Korean IME uses ImeProcessKey and posts messages */ + + todo_wine ok_ret( 2, ImmProcessKey( hwnd, default_hkl, 'R', MAKELONG(1, 0x13), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'R', MAKELONG(1, 0x13) ) ); + ok_seq( empty_sequence ); + process_messages(); + todo_wine ok_seq( partial_g_seq ); + + /* Korean IME doesn't eat WM_KEYUP */ + + ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'R', MAKELONG(1, 0xc013), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'R', MAKELONG(1, 0xc013) ) ); + process_messages(); + ok_seq( empty_sequence ); + + todo_wine ok_ret( 2, ImmProcessKey( hwnd, default_hkl, 'K', MAKELONG(1, 0x25), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'K', MAKELONG(1, 0x25) ) ); + process_messages(); + todo_wine ok_seq( partial_ga_seq ); + + todo_wine ok_ret( 2, ImmProcessKey( hwnd, default_hkl, 'S', MAKELONG(1, 0x1f), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'S', MAKELONG(1, 0x1f) ) ); + process_messages(); + todo_wine ok_seq( partial_n_seq ); + + todo_wine ok_ret( 2, ImmProcessKey( hwnd, default_hkl, 'K', MAKELONG(1, 0x25), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'K', MAKELONG(1, 0x25) ) ); + process_messages(); + todo_wine ok_seq( partial_na_seq ); + + todo_wine ok_ret( 2, ImmProcessKey( hwnd, default_hkl, 'E', MAKELONG(1, 0x12), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'E', MAKELONG(1, 0x12) ) ); + process_messages(); + todo_wine ok_seq( partial_d_seq ); + + todo_wine ok_ret( 2, ImmProcessKey( hwnd, default_hkl, 'K', MAKELONG(1, 0x25), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'K', MAKELONG(1, 0x25) ) ); + process_messages(); + todo_wine ok_seq( partial_da_seq ); + + todo_wine ok_ret( 2, ImmProcessKey( hwnd, default_hkl, VK_RETURN, MAKELONG(1, 0x1c), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, VK_RETURN, MAKELONG(1, 0x1c) ) ); + process_messages(); + todo_wine ok_seq( partial_return_seq ); + + + ok_ret( 1, ImmSetConversionStatus( himc, 0, IME_SMODE_PHRASEPREDICT ) ); + ok_ret( 1, ImmSetOpenStatus( himc, FALSE ) ); + + ok_ret( 1, ImmUnlockIMC( himc ) ); + ok_ret( 1, ImmDestroyContext( himc ) ); + + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); @@ -7258,6 +7527,8 @@ START_TEST(imm32) if (wineime_hkl) ime_cleanup( wineime_hkl, TRUE ); + test_ga_na_da(); + if (init()) { test_ImmNotifyIME(); From c62ec817af4f8bb7add90e10e993d37fb5c86015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 30 Apr 2023 16:51:44 +0200 Subject: [PATCH 1896/2777] imm32/tests: Test MS Japanese IME NIHONGO-NO sequence. (cherry picked from commit e6b21cc57703c02387d2ba55c1fa87902e1c560f) --- dlls/imm32/tests/imm32.c | 180 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 179 insertions(+), 1 deletion(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 03bf91286a5..456c5d88b7e 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -550,13 +550,19 @@ static void ok_seq_( const char *file, int line, const struct ime_call *expected } static BOOL check_WM_SHOWWINDOW; +static BOOL ignore_WM_IME_NOTIFY; +static BOOL ignore_WM_IME_REQUEST; static BOOL ignore_message( UINT msg, WPARAM wparam ) { switch (msg) { case WM_IME_NOTIFY: + if (ignore_WM_IME_NOTIFY) return TRUE; return wparam > IMN_PRIVATE; + case WM_IME_REQUEST: + if (ignore_WM_IME_REQUEST) return TRUE; + return FALSE; case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION: case WM_IME_COMPOSITION: @@ -566,7 +572,6 @@ static BOOL ignore_message( UINT msg, WPARAM wparam ) case WM_IME_SELECT: case WM_IME_CHAR: case 0x287: - case WM_IME_REQUEST: case WM_IME_KEYDOWN: case WM_IME_KEYUP: return FALSE; @@ -7459,6 +7464,178 @@ static void test_ga_na_da(void) ime_call_count = 0; } +static void test_nihongo_no(void) +{ + /* These sequences have some additional WM_IME_NOTIFY messages with wparam > IMN_PRIVATE */ + /* Some out-of-order WM_IME_REQUEST and WM_IME_NOTIFY messages are also ignored */ + struct ime_call complete_seq[] = + { + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 0, .lparam = 0}}, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uff4e", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xff4e, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS}, + }, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS}, + }, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b\uff48", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS}, + }, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b\u307b", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS}, + }, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b\u307b\uff4e", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS}, + }, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b\u307b\u3093\uff47", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS}, + }, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306b\u307b\u3093\u3054", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306b, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS}, + }, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u65e5\u672c\u8a9e", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x65e5, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS}, + }, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"", .result = L"\u65e5\u672c\u8a9e", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x65e5, .lparam = GCS_RESULTSTR|GCS_RESULTCLAUSE|GCS_RESULTREADSTR|GCS_RESULTREADCLAUSE}, + }, + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0x65e5, .lparam = 0x1}}, + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0x672c, .lparam = 0x1}}, + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0x8a9e, .lparam = 0x1}}, + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 0, .lparam = 0}}, + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 0, .lparam = 0}}, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\uff4e", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0xff4e, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS}, + }, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u306e", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306e, .lparam = GCS_COMPSTR|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPREADSTR|GCS_DELTASTART|GCS_CURSORPOS}, + }, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"", .result = L"\u306e", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x306e, .lparam = GCS_RESULTSTR|GCS_RESULTCLAUSE|GCS_RESULTREADSTR|GCS_RESULTREADCLAUSE}, + }, + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_CHAR, .wparam = 0x306e, .lparam = 0x1}}, + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 0, .lparam = 0}}, + {0}, + }; + + INPUTCONTEXT *ctx; + HWND hwnd; + HIMC himc; + UINT i; + + /* this test doesn't work on Win32 / WoW64 */ + if (sizeof(void *) == 4 || default_hkl != (HKL)0x04110411 /* MS Japanese IME */) + { + skip( "Got hkl %p, skipping Japanese IME-specific test\n", default_hkl ); + return; + } + + hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 100, 100, 100, 100, NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + flush_events(); + + himc = ImmCreateContext(); + ok_ne( NULL, himc, HIMC, "%p" ); + ctx = ImmLockIMC( himc ); + ok_ne( NULL, ctx, INPUTCONTEXT *, "%p" ); + ok_eq( default_himc, ImmAssociateContext( hwnd, himc ), HIMC, "%p" ); + ok_ret( 1, ImmSetOpenStatus( himc, TRUE ) ); + ok_ret( 1, ImmSetConversionStatus( himc, IME_CMODE_FULLSHAPE | IME_CMODE_NATIVE, IME_SMODE_PHRASEPREDICT ) ); + flush_events(); + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; + + for (i = 0; i < ARRAY_SIZE(complete_seq); i++) complete_seq[i].himc = himc; + ignore_WM_IME_REQUEST = TRUE; + ignore_WM_IME_NOTIFY = TRUE; + + + keybd_event( 'N', 0x31, 0, 0 ); + flush_events(); + keybd_event( 'N', 0x31, KEYEVENTF_KEYUP, 0 ); + + keybd_event( 'I', 0x17, 0, 0 ); + flush_events(); + keybd_event( 'I', 0x17, KEYEVENTF_KEYUP, 0 ); + + keybd_event( 'H', 0x23, 0, 0 ); + flush_events(); + keybd_event( 'H', 0x23, KEYEVENTF_KEYUP, 0 ); + + keybd_event( 'O', 0x18, 0, 0 ); + flush_events(); + keybd_event( 'O', 0x18, KEYEVENTF_KEYUP, 0 ); + + keybd_event( 'N', 0x31, 0, 0 ); + flush_events(); + keybd_event( 'N', 0x31, KEYEVENTF_KEYUP, 0 ); + + keybd_event( 'G', 0x22, 0, 0 ); + flush_events(); + keybd_event( 'G', 0x22, KEYEVENTF_KEYUP, 0 ); + + keybd_event( 'O', 0x18, 0, 0 ); + flush_events(); + keybd_event( 'O', 0x18, KEYEVENTF_KEYUP, 0 ); + + keybd_event( VK_SPACE, 0x39, 0, 0 ); + flush_events(); + keybd_event( VK_SPACE, 0x39, KEYEVENTF_KEYUP, 0 ); + + keybd_event( 'N', 0x31, 0, 0 ); + flush_events(); + keybd_event( 'N', 0x31, KEYEVENTF_KEYUP, 0 ); + + keybd_event( 'O', 0x18, 0, 0 ); + flush_events(); + keybd_event( 'O', 0x18, KEYEVENTF_KEYUP, 0 ); + + keybd_event( VK_RETURN, 0x1c, 0, 0 ); + flush_events(); + keybd_event( VK_RETURN, 0x1c, KEYEVENTF_KEYUP, 0 ); + + flush_events(); + todo_wine ok_seq( complete_seq ); + + ignore_WM_IME_REQUEST = FALSE; + ignore_WM_IME_NOTIFY = FALSE; + + /* Japanese IME doesn't take input from ImmProcessKey */ + + ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'N', MAKELONG(1, 0x31), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYDOWN, 'N', MAKELONG(1, 0x31) ) ); + flush_events(); + ok_ret( 0, ImmProcessKey( hwnd, default_hkl, 'N', MAKELONG(1, 0xc031), 0 ) ); + ok_ret( 0, ImmTranslateMessage( hwnd, WM_KEYUP, 'N', MAKELONG(1, 0xc031) ) ); + flush_events(); + ok_seq( empty_sequence ); + + + ok_ret( 1, ImmSetConversionStatus( himc, 0, IME_SMODE_PHRASEPREDICT ) ); + ok_ret( 1, ImmSetOpenStatus( himc, FALSE ) ); + + ok_ret( 1, ImmUnlockIMC( himc ) ); + ok_ret( 1, ImmDestroyContext( himc ) ); + + ok_ret( 1, DestroyWindow( hwnd ) ); + process_messages(); + + memset( ime_calls, 0, sizeof(ime_calls) ); + ime_call_count = 0; +} + START_TEST(imm32) { default_hkl = GetKeyboardLayout( 0 ); @@ -7528,6 +7705,7 @@ START_TEST(imm32) if (wineime_hkl) ime_cleanup( wineime_hkl, TRUE ); test_ga_na_da(); + test_nihongo_no(); if (init()) { From 9440fd1e124aad44499f82e4b6a9e96f6fd82981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 May 2023 11:55:46 +0200 Subject: [PATCH 1897/2777] winemac: Delay ime_set_text until ImeToAsciiEx requests it. (cherry picked from commit 4071f49fb2dd963d6446ac7b86973c83a482cf7f) --- dlls/winemac.drv/event.c | 47 ++++++++++++++++++++++++++++++++-- dlls/winemac.drv/ime.c | 12 ++++++--- dlls/winemac.drv/macdrv.h | 1 + dlls/winemac.drv/macdrv_main.c | 2 ++ dlls/winemac.drv/unixlib.h | 1 + 5 files changed, 58 insertions(+), 5 deletions(-) diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c index 03c49b34bae..cc8aa4681c6 100644 --- a/dlls/winemac.drv/event.c +++ b/dlls/winemac.drv/event.c @@ -32,6 +32,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(event); WINE_DECLARE_DEBUG_CHANNEL(imm); +struct ime_update +{ + struct ime_set_text_params *comp_params; + DWORD comp_size; + struct ime_set_text_params *result_params; + DWORD result_size; +}; +static struct ime_update ime_update; /* return the name of an Mac event */ static const char *dbgstr_event(int type) @@ -170,7 +178,20 @@ static void macdrv_im_set_text(const macdrv_event *event) if (length) CFStringGetCharacters(event->im_set_text.text, CFRangeMake(0, length), params->text); - macdrv_client_func(client_func_ime_set_text, params, size); + free(ime_update.comp_params); + ime_update.comp_params = NULL; + + if (params->complete) + { + free(ime_update.result_params); + ime_update.result_params = params; + ime_update.result_size = size; + } + else + { + ime_update.comp_params = params; + ime_update.comp_size = size; + } } /*********************************************************************** @@ -179,7 +200,29 @@ static void macdrv_im_set_text(const macdrv_event *event) static void macdrv_sent_text_input(const macdrv_event *event) { TRACE_(imm)("handled: %s\n", event->sent_text_input.handled ? "TRUE" : "FALSE"); - *event->sent_text_input.done = event->sent_text_input.handled ? 1 : -1; + *event->sent_text_input.done = event->sent_text_input.handled || ime_update.result_params ? 1 : -1; +} + + +/*********************************************************************** + * macdrv_ime_get_text_input + */ +NTSTATUS macdrv_ime_get_text_input(void *arg) +{ + if (ime_update.result_params) + { + macdrv_client_func(client_func_ime_set_text, ime_update.result_params, ime_update.result_size); + free(ime_update.result_params); + ime_update.result_params = NULL; + } + if (ime_update.comp_params) + { + macdrv_client_func(client_func_ime_set_text, ime_update.comp_params, ime_update.comp_size); + free(ime_update.comp_params); + ime_update.comp_params = NULL; + } + + return 0; } diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index bca8377d146..616dc82cc70 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -680,10 +680,16 @@ UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, return msgs; } - else if ((lpIMC = LockRealIMC(hIMC))) + else { - UpdateDataInDefaultIMEWindow( lpIMC, hwnd, FALSE ); - UnlockRealIMC(hIMC); + /* trigger the pending client_func_ime_set_text call */ + MACDRV_CALL(ime_get_text_input, NULL); + + if ((lpIMC = LockRealIMC(hIMC))) + { + UpdateDataInDefaultIMEWindow( lpIMC, hwnd, FALSE ); + UnlockRealIMC(hIMC); + } } return 0; } diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 281d49c1e9a..b77e62f75db 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -277,6 +277,7 @@ extern NTSTATUS macdrv_dnd_have_format(void *arg) DECLSPEC_HIDDEN; extern NTSTATUS macdrv_dnd_release(void *arg) DECLSPEC_HIDDEN; extern NTSTATUS macdrv_dnd_retain(void *arg) DECLSPEC_HIDDEN; extern NTSTATUS macdrv_ime_process_text_input(void *arg) DECLSPEC_HIDDEN; +extern NTSTATUS macdrv_ime_get_text_input(void *arg) DECLSPEC_HIDDEN; extern NTSTATUS macdrv_notify_icon(void *arg) DECLSPEC_HIDDEN; extern NTSTATUS macdrv_client_func(enum macdrv_client_funcs func, const void *params, diff --git a/dlls/winemac.drv/macdrv_main.c b/dlls/winemac.drv/macdrv_main.c index a4b280283ee..bf03ab6f5fe 100644 --- a/dlls/winemac.drv/macdrv_main.c +++ b/dlls/winemac.drv/macdrv_main.c @@ -635,6 +635,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = macdrv_dnd_retain, macdrv_ime_clear, macdrv_ime_process_text_input, + macdrv_ime_get_text_input, macdrv_ime_using_input_method, macdrv_init, macdrv_notify_icon, @@ -761,6 +762,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = macdrv_dnd_retain, macdrv_ime_clear, wow64_ime_process_text_input, + macdrv_ime_get_text_input, macdrv_ime_using_input_method, wow64_init, wow64_notify_icon, diff --git a/dlls/winemac.drv/unixlib.h b/dlls/winemac.drv/unixlib.h index ca5115f4982..b3f45291904 100644 --- a/dlls/winemac.drv/unixlib.h +++ b/dlls/winemac.drv/unixlib.h @@ -28,6 +28,7 @@ enum macdrv_funcs unix_dnd_retain, unix_ime_clear, unix_ime_process_text_input, + unix_ime_get_text_input, unix_ime_using_input_method, unix_init, unix_notify_icon, From 73afc0b7860f1bcba34d960b5f865012e2537b53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 2 Apr 2023 21:11:20 +0200 Subject: [PATCH 1898/2777] winemac: Wait for IME input result on the unix side. (cherry picked from commit 3b42967442924fb154ddf8d0c598ae890cfb6133) --- dlls/winemac.drv/ime.c | 10 +++------- dlls/winemac.drv/keyboard.c | 14 ++++++-------- dlls/winemac.drv/macdrv_main.c | 2 -- dlls/winemac.drv/unixlib.h | 1 - 4 files changed, 9 insertions(+), 18 deletions(-) diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index 616dc82cc70..0abdeaeb680 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -629,7 +629,7 @@ UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, LPIMEPRIVATE myPrivate; HWND hwnd; UINT repeat; - int done = 0; + UINT ret; TRACE("uVKey 0x%04x uScanCode 0x%04x fuState %u hIMC %p\n", uVKey, uScanCode, fuState, hIMC); @@ -661,13 +661,9 @@ UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, params.scan = uScanCode; params.repeat = repeat; params.key_state = lpbKeyState; - params.done = &done; - MACDRV_CALL(ime_process_text_input, ¶ms); + ret = MACDRV_CALL(ime_process_text_input, ¶ms); - while (!done) - MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_POSTMESSAGE | QS_SENDMESSAGE, 0); - - if (done < 0) + if (!ret) { UINT msgs = 0; UINT msg = (uScanCode & 0x8000) ? WM_KEYUP : WM_KEYDOWN; diff --git a/dlls/winemac.drv/keyboard.c b/dlls/winemac.drv/keyboard.c index bb6fb70fd2a..0f45873a831 100644 --- a/dlls/winemac.drv/keyboard.c +++ b/dlls/winemac.drv/keyboard.c @@ -1198,7 +1198,7 @@ NTSTATUS macdrv_ime_process_text_input(void *arg) void *himc = UlongToHandle(params->himc); const BYTE *key_state = params->key_state; unsigned int flags; - int keyc; + int keyc, done = 0; TRACE("vkey 0x%04x scan 0x%04x repeat %u himc %p\n", params->vkey, params->scan, params->repeat, himc); @@ -1225,17 +1225,15 @@ NTSTATUS macdrv_ime_process_text_input(void *arg) for (keyc = 0; keyc < ARRAY_SIZE(thread_data->keyc2vkey); keyc++) if (thread_data->keyc2vkey[keyc] == params->vkey) break; - if (keyc >= ARRAY_SIZE(thread_data->keyc2vkey)) - { - *params->done = -1; - return 0; - } + if (keyc >= ARRAY_SIZE(thread_data->keyc2vkey)) return 0; TRACE("flags 0x%08x keyc 0x%04x\n", flags, keyc); macdrv_send_text_input_event(((params->scan & 0x8000) == 0), flags, params->repeat, keyc, - himc, params->done); - return 0; + himc, &done); + while (!done) NtUserMsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_POSTMESSAGE | QS_SENDMESSAGE, 0); + + return done > 0; } diff --git a/dlls/winemac.drv/macdrv_main.c b/dlls/winemac.drv/macdrv_main.c index bf03ab6f5fe..7e91e0ca3e1 100644 --- a/dlls/winemac.drv/macdrv_main.c +++ b/dlls/winemac.drv/macdrv_main.c @@ -673,7 +673,6 @@ static NTSTATUS wow64_ime_process_text_input(void *arg) UINT scan; UINT repeat; ULONG key_state; - ULONG done; } *params32 = arg; struct process_text_input_params params; @@ -682,7 +681,6 @@ static NTSTATUS wow64_ime_process_text_input(void *arg) params.scan = params32->scan; params.repeat = params32->repeat; params.key_state = UlongToPtr(params32->key_state); - params.done = UlongToPtr(params32->done); return macdrv_ime_process_text_input(¶ms); } diff --git a/dlls/winemac.drv/unixlib.h b/dlls/winemac.drv/unixlib.h index b3f45291904..493e4f6c139 100644 --- a/dlls/winemac.drv/unixlib.h +++ b/dlls/winemac.drv/unixlib.h @@ -69,7 +69,6 @@ struct process_text_input_params UINT scan; UINT repeat; const BYTE *key_state; - int *done; }; /* macdrv_init params */ From d319e9b3ef9a52022450f435f1f3f9c3151b076d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 May 2023 13:55:53 +0200 Subject: [PATCH 1899/2777] winemac: Send IME key input from ImeProcessKey. (cherry picked from commit 39696138a67e39c5a6d429bf1b7ea8632eb35cff) --- dlls/winemac.drv/ime.c | 72 ++++++++++-------------------------------- include/ntuser.h | 1 - 2 files changed, 17 insertions(+), 56 deletions(-) diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index 0abdeaeb680..dae7da3b8f3 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -470,24 +470,6 @@ static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam, LPARAM lParam UnlockRealIMC(hIMC); } -static BOOL GenerateMessageToTransKey(TRANSMSGLIST *lpTransBuf, UINT *uNumTranMsgs, - UINT msg, WPARAM wParam, LPARAM lParam) -{ - LPTRANSMSG ptr; - - if (*uNumTranMsgs + 1 >= lpTransBuf->uMsgCount) - return FALSE; - - ptr = lpTransBuf->TransMsg + *uNumTranMsgs; - ptr->message = msg; - ptr->wParam = wParam; - ptr->lParam = lParam; - (*uNumTranMsgs)++; - - return TRUE; -} - - static BOOL IME_RemoveFromSelected(HIMC hIMC) { int i; @@ -536,8 +518,14 @@ static void UpdateDataInDefaultIMEWindow(INPUTCONTEXT *lpIMC, HWND hwnd, BOOL sh BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lpbKeyState) { + struct process_text_input_params params = + { + .himc = (UINT_PTR)hIMC, .vkey = LOWORD(vKey), .scan = HIWORD(lKeyData), + .repeat = !!(lKeyData >> 30), .key_state = lpbKeyState, + }; LPINPUTCONTEXT lpIMC; BOOL inIME; + UINT ret; TRACE("hIMC %p vKey 0x%04x lKeyData 0x%08Ix lpbKeyState %p\n", hIMC, vKey, lKeyData, lpbKeyState); @@ -568,14 +556,17 @@ BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lp ImmSetOpenStatus(RealIMC(FROM_MACDRV), FALSE); } - myPrivate->repeat = (lKeyData >> 30) & 0x1; - myPrivate->bInternalState = inIME; ImmUnlockIMCC(lpIMC->hPrivate); } UnlockRealIMC(hIMC); - return inIME; + if (!inIME) return FALSE; + + TRACE( "Processing Mac 0x%04x\n", vKey ); + ret = MACDRV_CALL( ime_process_text_input, ¶ms ); + + return ret != 0; } BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) @@ -612,7 +603,6 @@ BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) myPrivate->bInternalState = FALSE; myPrivate->textfont = NULL; myPrivate->hwndDefault = NULL; - myPrivate->repeat = 0; ImmUnlockIMCC(lpIMC->hPrivate); UnlockRealIMC(hIMC); } @@ -623,13 +613,10 @@ BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, TRANSMSGLIST *lpdwTransKey, UINT fuState, HIMC hIMC) { - struct process_text_input_params params; UINT vkey; LPINPUTCONTEXT lpIMC; LPIMEPRIVATE myPrivate; HWND hwnd; - UINT repeat; - UINT ret; TRACE("uVKey 0x%04x uScanCode 0x%04x fuState %u hIMC %p\n", uVKey, uScanCode, fuState, hIMC); @@ -651,41 +638,16 @@ UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, return 0; } - repeat = myPrivate->repeat; ImmUnlockIMCC(lpIMC->hPrivate); UnlockRealIMC(hIMC); - TRACE("Processing Mac 0x%04x\n", vkey); - params.himc = HandleToULong(hIMC); - params.vkey = uVKey; - params.scan = uScanCode; - params.repeat = repeat; - params.key_state = lpbKeyState; - ret = MACDRV_CALL(ime_process_text_input, ¶ms); - - if (!ret) - { - UINT msgs = 0; - UINT msg = (uScanCode & 0x8000) ? WM_KEYUP : WM_KEYDOWN; - - /* KeyStroke not processed by the IME - * so we need to rebuild the KeyDown message and pass it on to WINE - */ - if (!GenerateMessageToTransKey(lpdwTransKey, &msgs, msg, vkey, MAKELONG(0x0001, uScanCode))) - GenerateIMEMessage(hIMC, msg, vkey, MAKELONG(0x0001, uScanCode)); + /* trigger the pending client_func_ime_set_text call */ + MACDRV_CALL(ime_get_text_input, NULL); - return msgs; - } - else + if ((lpIMC = LockRealIMC(hIMC))) { - /* trigger the pending client_func_ime_set_text call */ - MACDRV_CALL(ime_get_text_input, NULL); - - if ((lpIMC = LockRealIMC(hIMC))) - { - UpdateDataInDefaultIMEWindow( lpIMC, hwnd, FALSE ); - UnlockRealIMC(hIMC); - } + UpdateDataInDefaultIMEWindow( lpIMC, hwnd, FALSE ); + UnlockRealIMC(hIMC); } return 0; } diff --git a/include/ntuser.h b/include/ntuser.h index 67f6cd54837..ee386c143be 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -497,7 +497,6 @@ typedef struct ime_private BOOL bInternalState; HFONT textfont; HWND hwndDefault; - UINT repeat; } IMEPRIVATE, *LPIMEPRIVATE; #define WM_SYSTIMER 0x0118 From a011c697640891ecc1607805b0c6fa0e22313761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 17:15:39 +0200 Subject: [PATCH 1900/2777] imm32/tests: Mark some tests as broken by prior SetForegroundWindow call. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54760 (cherry picked from commit c11ed566cb762850f2fe84e68025c8f9071b2244) --- dlls/imm32/tests/imm32.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 456c5d88b7e..4bdb6be4a31 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -5012,7 +5012,7 @@ static void test_ImmActivateLayout(void) { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_OPENSTATUSWINDOW}, - .todo = TRUE, + .todo = TRUE, .broken = TRUE, /* broken after SetForegroundWindow(GetDesktopWindow()) as in d3d8:device */ }, { .hkl = expect_ime, .himc = default_himc, @@ -5046,7 +5046,7 @@ static void test_ImmActivateLayout(void) { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_CLOSESTATUSWINDOW}, - .todo = TRUE, + .todo = TRUE, .broken = TRUE, /* broken after SetForegroundWindow(GetDesktopWindow()) as in d3d8:device */ }, { .hkl = expect_ime, .himc = default_himc, @@ -5203,7 +5203,7 @@ static void test_ImmCreateInputContext(void) { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_OPENSTATUSWINDOW}, - .todo = TRUE, + .todo = TRUE, .broken = TRUE, /* broken after SetForegroundWindow(GetDesktopWindow()) as in d3d8:device */ }, {0}, }; @@ -5258,7 +5258,7 @@ static void test_ImmCreateInputContext(void) { .hkl = expect_ime, .himc = default_himc, .func = MSG_IME_UI, .message = {.msg = WM_IME_NOTIFY, .wparam = IMN_CLOSESTATUSWINDOW}, - .todo = TRUE, + .todo = TRUE, .broken = TRUE, /* broken after SetForegroundWindow(GetDesktopWindow()) as in d3d8:device */ }, { .hkl = expect_ime, .himc = default_himc, From b855d7aa31814522864153448c3ddd04519e4229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 10:47:33 +0200 Subject: [PATCH 1901/2777] winex11: Use a helper to change internal composition status. (cherry picked from commit f3696e6a9c0fbc05a13e63af073dd834784b3bca) --- dlls/winex11.drv/ime.c | 76 +++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 46 deletions(-) diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 55485bfbfcf..bfca49ab22b 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -453,6 +453,25 @@ static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam, UnlockRealIMC(hIMC); } +static void ime_set_composition_status( HIMC himc, BOOL composition ) +{ + struct ime_private *priv; + INPUTCONTEXT *ctx; + UINT msg = 0; + + if (!(ctx = ImmLockIMC( himc ))) return; + if ((priv = ImmLockIMCC( ctx->hPrivate ))) + { + if (!priv->bInComposition && composition) msg = WM_IME_STARTCOMPOSITION; + else if (priv->bInComposition && !composition) msg = WM_IME_ENDCOMPOSITION; + priv->bInComposition = composition; + ImmUnlockIMCC( ctx->hPrivate ); + } + ImmUnlockIMC( himc ); + + if (msg) GenerateIMEMessage( himc, msg, 0, 0 ); +} + static BOOL IME_RemoveFromSelected(HIMC hIMC) { int i; @@ -580,16 +599,8 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) X11DRV_CALL( xim_preedit_state, &preedit_params ); if (!lpIMC->fOpen) { - LPIMEPRIVATE myPrivate; - - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (myPrivate->bInComposition) - { - X11DRV_CALL( xim_reset, lpIMC->hWnd ); - GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); - myPrivate->bInComposition = FALSE; - } - ImmUnlockIMCC(lpIMC->hPrivate); + X11DRV_CALL( xim_reset, lpIMC->hWnd ); + ime_set_composition_status( hIMC, FALSE ); } break; @@ -602,7 +613,6 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) case CPS_COMPLETE: { HIMCC newCompStr; - LPIMEPRIVATE myPrivate; WCHAR *str; UINT len; @@ -614,7 +624,6 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) ImmDestroyIMCC(lpIMC->hCompStr); lpIMC->hCompStr = newCompStr; - myPrivate = ImmLockIMCC(lpIMC->hPrivate); if ((str = input_context_get_comp_str( lpIMC, FALSE, &len ))) { WCHAR param = str[0]; @@ -631,15 +640,10 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, param, GCS_RESULTSTR|GCS_RESULTCLAUSE); - - GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0); free( str ); } - else if (myPrivate->bInComposition) - GenerateIMEMessage(hIMC,WM_IME_ENDCOMPOSITION, 0, 0); - myPrivate->bInComposition = FALSE; - ImmUnlockIMCC(lpIMC->hPrivate); + ime_set_composition_status( hIMC, FALSE ); bRet = TRUE; } @@ -648,8 +652,6 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) case CPS_REVERT: FIXME("CPS_REVERT\n"); break; case CPS_CANCEL: { - LPIMEPRIVATE myPrivate; - TRACE("CPS_CANCEL\n"); X11DRV_CALL( xim_reset, lpIMC->hWnd ); @@ -658,13 +660,7 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) ImmDestroyIMCC(lpIMC->hCompStr); lpIMC->hCompStr = ImeCreateBlankCompStr(); - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (myPrivate->bInComposition) - { - GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); - myPrivate->bInComposition = FALSE; - } - ImmUnlockIMCC(lpIMC->hPrivate); + ime_set_composition_status( hIMC, FALSE ); bRet = TRUE; } break; @@ -685,7 +681,6 @@ BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, LPINPUTCONTEXT lpIMC; DWORD flags = 0; WCHAR wParam = 0; - LPIMEPRIVATE myPrivate; TRACE("(%p, %ld, %p, %ld, %p, %ld):\n", hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); @@ -710,17 +705,11 @@ BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, if (lpIMC == NULL) return FALSE; - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (dwIndex == SCS_SETSTR) { HIMCC newCompStr; - if (!myPrivate->bInComposition) - { - GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0); - myPrivate->bInComposition = TRUE; - } + ime_set_composition_status( hIMC, TRUE ); /* clear existing result */ newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0); @@ -768,30 +757,25 @@ NTSTATUS x11drv_ime_set_composition_status( UINT open ) { HIMC imc; LPINPUTCONTEXT lpIMC; - LPIMEPRIVATE myPrivate; imc = RealIMC(FROM_X11); lpIMC = ImmLockIMC(imc); if (lpIMC == NULL) return 0; - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - - if (open && !myPrivate->bInComposition) - { - GenerateIMEMessage(imc, WM_IME_STARTCOMPOSITION, 0, 0); - } - else if (!open && myPrivate->bInComposition) + if (!open) { + struct ime_private *myPrivate = ImmLockIMCC(lpIMC->hPrivate); ShowWindow(myPrivate->hwndDefault, SW_HIDE); ImmDestroyIMCC(lpIMC->hCompStr); lpIMC->hCompStr = ImeCreateBlankCompStr(); - GenerateIMEMessage(imc, WM_IME_ENDCOMPOSITION, 0, 0); + ImmUnlockIMCC(lpIMC->hPrivate); } - myPrivate->bInComposition = open; - ImmUnlockIMCC(lpIMC->hPrivate); ImmUnlockIMC(imc); + + ime_set_composition_status( imc, open ); + return 0; } From f2fa286ad4debd0fdda9ccb9f456490cf0f2a639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 10:53:14 +0200 Subject: [PATCH 1902/2777] winex11: Clear the composition string when input context is closed. (cherry picked from commit d9fc3eab9a4ae39c94fa484d65679de22d02e75a) --- dlls/winex11.drv/ime.c | 49 ++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index bfca49ab22b..ece40f0dfc2 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -73,6 +73,20 @@ static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT * return text; } +static void input_context_reset_comp_str( INPUTCONTEXT *ctx ) +{ + COMPOSITIONSTRING *compstr; + + if (!(compstr = ImmLockIMCC( ctx->hCompStr ))) + WARN( "Failed to lock input context composition string\n" ); + else + { + memset( compstr, 0, sizeof(*compstr) ); + compstr->dwSize = sizeof(*compstr); + ImmUnlockIMCC( ctx->hCompStr ); + } +} + static HIMC RealIMC(HIMC hIMC) { if (hIMC == FROM_X11) @@ -107,18 +121,6 @@ static BOOL UnlockRealIMC(HIMC hIMC) return FALSE; } -static HIMCC ImeCreateBlankCompStr(void) -{ - HIMCC rc; - LPCOMPOSITIONSTRING ptr; - rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING)); - ptr = ImmLockIMCC(rc); - memset(ptr,0,sizeof(COMPOSITIONSTRING)); - ptr->dwSize = sizeof(COMPOSITIONSTRING); - ImmUnlockIMCC(rc); - return rc; -} - static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset, LPBYTE target, LPBYTE source, DWORD* lenParam, DWORD* offsetParam, BOOL wchars ) @@ -591,8 +593,6 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) } break; case IMC_SETOPENSTATUS: - TRACE("IMC_SETOPENSTATUS\n"); - bRet = TRUE; preedit_params.hwnd = lpIMC->hWnd; preedit_params.open = lpIMC->fOpen; @@ -600,9 +600,9 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) if (!lpIMC->fOpen) { X11DRV_CALL( xim_reset, lpIMC->hWnd ); + input_context_reset_comp_str( lpIMC ); ime_set_composition_status( hIMC, FALSE ); } - break; default: FIXME("Unknown\n"); break; } @@ -643,27 +643,17 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) free( str ); } - ime_set_composition_status( hIMC, FALSE ); - + ImmSetOpenStatus( hIMC, FALSE ); bRet = TRUE; } break; case CPS_CONVERT: FIXME("CPS_CONVERT\n"); break; case CPS_REVERT: FIXME("CPS_REVERT\n"); break; case CPS_CANCEL: - { - TRACE("CPS_CANCEL\n"); - - X11DRV_CALL( xim_reset, lpIMC->hWnd ); - - if (lpIMC->hCompStr) - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = ImeCreateBlankCompStr(); - + input_context_reset_comp_str( lpIMC ); ime_set_composition_status( hIMC, FALSE ); bRet = TRUE; - } - break; + break; default: FIXME("Unknown\n"); break; } break; @@ -767,8 +757,7 @@ NTSTATUS x11drv_ime_set_composition_status( UINT open ) { struct ime_private *myPrivate = ImmLockIMCC(lpIMC->hPrivate); ShowWindow(myPrivate->hwndDefault, SW_HIDE); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = ImeCreateBlankCompStr(); + input_context_reset_comp_str( lpIMC ); ImmUnlockIMCC(lpIMC->hPrivate); } From 4ebb25f951002e70668807094f1ad007df43e2b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 13:04:26 +0200 Subject: [PATCH 1903/2777] winex11: Simplify NotifyIME with NI_COMPOSITIONSTR / CPS_COMPLETE. (cherry picked from commit e2674379c57e202aa6b72e94421284ef41a134e9) --- dlls/winex11.drv/ime.c | 67 ++++++++++++------------------------------ 1 file changed, 19 insertions(+), 48 deletions(-) diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index ece40f0dfc2..900a6a3e5d3 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -52,27 +52,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm); static HIMC *hSelectedFrom = NULL; static INT hSelectedCount = 0; -static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT *length ) -{ - COMPOSITIONSTRING *string; - WCHAR *text = NULL; - UINT len, off; - - if (!(string = ImmLockIMCC( ctx->hCompStr ))) return NULL; - len = result ? string->dwResultStrLen : string->dwCompStrLen; - off = result ? string->dwResultStrOffset : string->dwCompStrOffset; - - if (len && off && (text = malloc( (len + 1) * sizeof(WCHAR) ))) - { - memcpy( text, (BYTE *)string + off, len * sizeof(WCHAR) ); - text[len] = 0; - *length = len; - } - - ImmUnlockIMCC( ctx->hCompStr ); - return text; -} - static void input_context_reset_comp_str( INPUTCONTEXT *ctx ) { COMPOSITIONSTRING *compstr; @@ -612,35 +591,27 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) { case CPS_COMPLETE: { - HIMCC newCompStr; - WCHAR *str; - UINT len; - - TRACE("CPS_COMPLETE\n"); - - /* clear existing result */ - newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0); - - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; + COMPOSITIONSTRING *compstr; - if ((str = input_context_get_comp_str( lpIMC, FALSE, &len ))) + if (!(compstr = ImmLockIMCC( lpIMC->hCompStr ))) + WARN( "Failed to lock input context composition string\n" ); + else { - WCHAR param = str[0]; - - newCompStr = updateResultStr( lpIMC->hCompStr, str, len ); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - - GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0, - GCS_COMPSTR); - - GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, param, - GCS_RESULTSTR|GCS_RESULTCLAUSE); - free( str ); + WCHAR wchr = *(WCHAR *)((BYTE *)compstr + compstr->dwCompStrOffset); + COMPOSITIONSTRING tmp = *compstr; + UINT flags = 0; + + memset( compstr, 0, sizeof(*compstr) ); + compstr->dwSize = tmp.dwSize; + compstr->dwResultStrLen = tmp.dwCompStrLen; + compstr->dwResultStrOffset = tmp.dwCompStrOffset; + compstr->dwResultClauseLen = tmp.dwCompClauseLen; + compstr->dwResultClauseOffset = tmp.dwCompClauseOffset; + ImmUnlockIMCC( lpIMC->hCompStr ); + + if (tmp.dwCompStrLen) flags |= GCS_RESULTSTR; + if (tmp.dwCompClauseLen) flags |= GCS_RESULTCLAUSE; + if (flags) GenerateIMEMessage( hIMC, WM_IME_COMPOSITION, wchr, flags ); } ImmSetOpenStatus( hIMC, FALSE ); From e7007ea85c001998a063c59ae5cfc408f6374a85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 13:04:52 +0200 Subject: [PATCH 1904/2777] win32u: Introduce new NtUserNotifyIMEStatus syscall. (cherry picked from commit 56d0b870b6b443accde891b31251b5cbd7acf6b6) --- dlls/win32u/driver.c | 11 +++++++++ dlls/win32u/imm.c | 8 +++++++ dlls/win32u/syscall.c | 1 + dlls/win32u/win32u.spec | 2 +- dlls/winex11.drv/ime.c | 8 ++----- dlls/winex11.drv/init.c | 1 + dlls/winex11.drv/unixlib.h | 2 -- dlls/winex11.drv/x11drv.h | 3 +-- dlls/winex11.drv/x11drv_main.c | 18 --------------- dlls/winex11.drv/xim.c | 42 +++++++++++----------------------- dlls/wow64win/syscall.h | 1 + dlls/wow64win/user.c | 9 ++++++++ include/ntuser.h | 1 + include/wine/gdi_driver.h | 2 ++ 14 files changed, 51 insertions(+), 58 deletions(-) diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 5bae77da5f4..f0055b68d1e 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -716,6 +716,10 @@ static SHORT nulldrv_VkKeyScanEx( WCHAR ch, HKL layout ) return -256; /* use default implementation */ } +static void nulldrv_NotifyIMEStatus( HWND hwnd, UINT status ) +{ +} + static LRESULT nulldrv_DesktopWindowProc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { return default_window_proc( hwnd, msg, wparam, lparam, FALSE ); @@ -1070,6 +1074,11 @@ static SHORT loaderdrv_VkKeyScanEx( WCHAR ch, HKL layout ) return load_driver()->pVkKeyScanEx( ch, layout ); } +static void loaderdrv_NotifyIMEStatus( HWND hwnd, UINT status ) +{ + return load_driver()->pNotifyIMEStatus( hwnd, status ); +} + static LONG loaderdrv_ChangeDisplaySettings( LPDEVMODEW displays, LPCWSTR primary_name, HWND hwnd, DWORD flags, LPVOID lparam ) { @@ -1176,6 +1185,7 @@ static const struct user_driver_funcs lazy_load_driver = loaderdrv_ToUnicodeEx, loaderdrv_UnregisterHotKey, loaderdrv_VkKeyScanEx, + loaderdrv_NotifyIMEStatus, /* cursor/icon functions */ nulldrv_DestroyCursorIcon, loaderdrv_SetCursor, @@ -1255,6 +1265,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version SET_USER_FUNC(ToUnicodeEx); SET_USER_FUNC(UnregisterHotKey); SET_USER_FUNC(VkKeyScanEx); + SET_USER_FUNC(NotifyIMEStatus); SET_USER_FUNC(DestroyCursorIcon); SET_USER_FUNC(SetCursor); SET_USER_FUNC(GetCursorPos); diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index 7dee4912e27..328a4a3eddf 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -421,6 +421,14 @@ NTSTATUS WINAPI NtUserBuildHimcList( UINT thread_id, UINT count, HIMC *buffer, U return STATUS_SUCCESS; } +/***************************************************************************** + * NtUserNotifyIMEStatus (win32u.@) + */ +void WINAPI NtUserNotifyIMEStatus( HWND hwnd, UINT status ) +{ + user_driver->pNotifyIMEStatus( hwnd, status ); +} + BOOL WINAPI DECLSPEC_HIDDEN ImmProcessKey( HWND hwnd, HKL hkl, UINT vkey, LPARAM key_data, DWORD unknown ) { struct imm_process_key_params params = diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index 2e39a4f62cc..3581bc4c27d 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -235,6 +235,7 @@ static void * const syscalls[] = NtUserMessageCall, NtUserMoveWindow, NtUserMsgWaitForMultipleObjectsEx, + NtUserNotifyIMEStatus, NtUserNotifyWinEvent, NtUserOpenClipboard, NtUserOpenDesktop, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 764eb38d862..7b0629d9d65 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1087,7 +1087,7 @@ @ stdcall -syscall NtUserMoveWindow(long long long long long long) @ stdcall -syscall NtUserMsgWaitForMultipleObjectsEx(long ptr long long long) @ stub NtUserNavigateFocus -@ stub NtUserNotifyIMEStatus +@ stdcall -syscall NtUserNotifyIMEStatus(long long) @ stub NtUserNotifyProcessCreate @ stdcall -syscall NtUserNotifyWinEvent(long long long long) @ stdcall -syscall NtUserOpenClipboard(long long) diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 900a6a3e5d3..cbd8908a12d 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -531,7 +531,6 @@ UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) { - struct xim_preedit_state_params preedit_params; BOOL bRet = FALSE; LPINPUTCONTEXT lpIMC; @@ -572,16 +571,13 @@ BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) } break; case IMC_SETOPENSTATUS: - bRet = TRUE; - preedit_params.hwnd = lpIMC->hWnd; - preedit_params.open = lpIMC->fOpen; - X11DRV_CALL( xim_preedit_state, &preedit_params ); if (!lpIMC->fOpen) { - X11DRV_CALL( xim_reset, lpIMC->hWnd ); input_context_reset_comp_str( lpIMC ); ime_set_composition_status( hIMC, FALSE ); } + NtUserNotifyIMEStatus( lpIMC->hWnd, lpIMC->fOpen ); + bRet = TRUE; break; default: FIXME("Unknown\n"); break; } diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index ef11461ea67..bc4627d0b1c 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -400,6 +400,7 @@ static const struct user_driver_funcs x11drv_funcs = .pMapVirtualKeyEx = X11DRV_MapVirtualKeyEx, .pToUnicodeEx = X11DRV_ToUnicodeEx, .pVkKeyScanEx = X11DRV_VkKeyScanEx, + .pNotifyIMEStatus = X11DRV_NotifyIMEStatus, .pDestroyCursorIcon = X11DRV_DestroyCursorIcon, .pSetCursor = X11DRV_SetCursor, .pGetCursorPos = X11DRV_GetCursorPos, diff --git a/dlls/winex11.drv/unixlib.h b/dlls/winex11.drv/unixlib.h index 7dc1d9f0ca7..20279bdb2ac 100644 --- a/dlls/winex11.drv/unixlib.h +++ b/dlls/winex11.drv/unixlib.h @@ -31,8 +31,6 @@ enum x11drv_funcs unix_tablet_get_packet, unix_tablet_info, unix_tablet_load_info, - unix_xim_preedit_state, - unix_xim_reset, unix_funcs_count, }; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 8a035f3a5c1..3bfe28f39a4 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -211,6 +211,7 @@ extern UINT X11DRV_MapVirtualKeyEx( UINT code, UINT map_type, HKL hkl ) DECLSPEC extern INT X11DRV_ToUnicodeEx( UINT virtKey, UINT scanCode, const BYTE *lpKeyState, LPWSTR bufW, int bufW_size, UINT flags, HKL hkl ) DECLSPEC_HIDDEN; extern SHORT X11DRV_VkKeyScanEx( WCHAR wChar, HKL hkl ) DECLSPEC_HIDDEN; +extern void X11DRV_NotifyIMEStatus( HWND hwnd, UINT status ) DECLSPEC_HIDDEN; extern void X11DRV_DestroyCursorIcon( HCURSOR handle ) DECLSPEC_HIDDEN; extern void X11DRV_SetCursor( HCURSOR handle ) DECLSPEC_HIDDEN; extern BOOL X11DRV_SetCursorPos( INT x, INT y ) DECLSPEC_HIDDEN; @@ -902,8 +903,6 @@ extern NTSTATUS x11drv_tablet_attach_queue( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_tablet_get_packet( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_tablet_load_info( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_tablet_info( void *arg ) DECLSPEC_HIDDEN; -extern NTSTATUS x11drv_xim_preedit_state( void *arg ) DECLSPEC_HIDDEN; -extern NTSTATUS x11drv_xim_reset( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_client_func( enum x11drv_client_funcs func, const void *params, ULONG size ) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 3ac5d0d167c..0366ed51d8d 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -1486,8 +1486,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = x11drv_tablet_get_packet, x11drv_tablet_info, x11drv_tablet_load_info, - x11drv_xim_preedit_state, - x11drv_xim_reset, }; @@ -1564,20 +1562,6 @@ static NTSTATUS x11drv_wow64_tablet_info( void *arg ) return x11drv_tablet_info( ¶ms ); } -static NTSTATUS x11drv_wow64_xim_preedit_state( void *arg ) -{ - struct - { - ULONG hwnd; - BOOL open; - } *params32 = arg; - struct xim_preedit_state_params params; - - params.hwnd = UlongToHandle( params32->hwnd ); - params.open = params32->open; - return x11drv_xim_preedit_state( ¶ms ); -} - const unixlib_entry_t __wine_unix_call_wow64_funcs[] = { x11drv_create_desktop, @@ -1590,8 +1574,6 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = x11drv_wow64_tablet_get_packet, x11drv_wow64_tablet_info, x11drv_tablet_load_info, - x11drv_wow64_xim_preedit_state, - x11drv_xim_reset, }; C_ASSERT( ARRAYSIZE(__wine_unix_call_wow64_funcs) == unix_funcs_count ); diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 3601cb8c680..b7ab69029b9 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -260,42 +260,26 @@ static int xic_status_draw( XIC xic, XPointer user, XPointer arg ) return 0; } -NTSTATUS x11drv_xim_reset( void *hwnd ) -{ - XIC ic = X11DRV_get_ic(hwnd); - if (ic) - { - char* leftover; - TRACE("Forcing Reset %p\n",ic); - leftover = XmbResetIC(ic); - XFree(leftover); - } - return 0; -} - -NTSTATUS x11drv_xim_preedit_state( void *arg ) +/*********************************************************************** + * NotifyIMEStatus (X11DRV.@) + */ +void X11DRV_NotifyIMEStatus( HWND hwnd, UINT status ) { - struct xim_preedit_state_params *params = arg; - XIC ic; - XIMPreeditState state; + XIMPreeditState state = status ? XIMPreeditEnable : XIMPreeditDisable; XVaNestedList attr; + XIC xic; - ic = X11DRV_get_ic( params->hwnd ); - if (!ic) - return 0; + TRACE( "hwnd %p, status %#x\n", hwnd, status ); - if (params->open) - state = XIMPreeditEnable; - else - state = XIMPreeditDisable; + if (!(xic = X11DRV_get_ic( hwnd ))) return; - attr = XVaCreateNestedList(0, XNPreeditState, state, NULL); - if (attr != NULL) + if ((attr = XVaCreateNestedList( 0, XNPreeditState, state, NULL ))) { - XSetICValues(ic, XNPreeditAttributes, attr, NULL); - XFree(attr); + XSetICValues( xic, XNPreeditAttributes, attr, NULL ); + XFree( attr ); } - return 0; + + if (!status) XFree( XmbResetIC( xic ) ); } /*********************************************************************** diff --git a/dlls/wow64win/syscall.h b/dlls/wow64win/syscall.h index c9dc459709e..3ff6ecf7c0e 100644 --- a/dlls/wow64win/syscall.h +++ b/dlls/wow64win/syscall.h @@ -220,6 +220,7 @@ SYSCALL_ENTRY( NtUserMessageCall ) \ SYSCALL_ENTRY( NtUserMoveWindow ) \ SYSCALL_ENTRY( NtUserMsgWaitForMultipleObjectsEx ) \ + SYSCALL_ENTRY( NtUserNotifyIMEStatus ) \ SYSCALL_ENTRY( NtUserNotifyWinEvent ) \ SYSCALL_ENTRY( NtUserOpenClipboard ) \ SYSCALL_ENTRY( NtUserOpenDesktop ) \ diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index 458f5cd0788..f0b57f7c886 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -3164,6 +3164,15 @@ NTSTATUS WINAPI wow64_NtUserMsgWaitForMultipleObjectsEx( UINT *args ) return NtUserMsgWaitForMultipleObjectsEx( count, handles, timeout, mask, flags ); } +NTSTATUS WINAPI wow64_NtUserNotifyIMEStatus( UINT *args ) +{ + HWND hwnd = get_handle( &args ); + ULONG status = get_ulong( &args ); + + NtUserNotifyIMEStatus( hwnd, status ); + return 0; +} + NTSTATUS WINAPI wow64_NtUserNotifyWinEvent( UINT *args ) { DWORD event = get_ulong( &args ); diff --git a/include/ntuser.h b/include/ntuser.h index ee386c143be..198f7889020 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -819,6 +819,7 @@ LRESULT WINAPI NtUserMessageCall( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpa BOOL WINAPI NtUserMoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy, BOOL repaint ); DWORD WINAPI NtUserMsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, DWORD timeout, DWORD mask, DWORD flags ); +void WINAPI NtUserNotifyIMEStatus( HWND hwnd, UINT status ); void WINAPI NtUserNotifyWinEvent( DWORD event, HWND hwnd, LONG object_id, LONG child_id ); HWINSTA WINAPI NtUserOpenWindowStation( OBJECT_ATTRIBUTES *attr, ACCESS_MASK access ); BOOL WINAPI NtUserOpenClipboard( HWND hwnd, ULONG unk ); diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 96bedd7acab..bd7916da900 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -286,6 +286,8 @@ struct user_driver_funcs INT (*pToUnicodeEx)(UINT,UINT,const BYTE *,LPWSTR,int,UINT,HKL); void (*pUnregisterHotKey)(HWND, UINT, UINT); SHORT (*pVkKeyScanEx)(WCHAR, HKL); + /* IME functions */ + void (*pNotifyIMEStatus)(HWND,UINT); /* cursor/icon functions */ void (*pDestroyCursorIcon)(HCURSOR); void (*pSetCursor)(HCURSOR); From 6300552b77ecede3c952aa5f9bf2317bba7fd88a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 13:06:17 +0200 Subject: [PATCH 1905/2777] winex11: Move NotifyIME to the default IME implementation. (cherry picked from commit 800af36d9305fe24099805fb9100e03a77925c62) --- dlls/imm32/ime.c | 140 +++++++++++++++++++++++++++++- dlls/winex11.drv/ime.c | 102 ---------------------- dlls/winex11.drv/winex11.drv.spec | 1 - 3 files changed, 137 insertions(+), 106 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 3c4550c3cd9..44b1173b1db 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -83,6 +83,20 @@ static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT * return text; } +static void input_context_reset_comp_str( INPUTCONTEXT *ctx ) +{ + COMPOSITIONSTRING *compstr; + + if (!(compstr = ImmLockIMCC( ctx->hCompStr ))) + WARN( "Failed to lock input context composition string\n" ); + else + { + memset( compstr, 0, sizeof(*compstr) ); + compstr->dwSize = sizeof(*compstr); + ImmUnlockIMCC( ctx->hCompStr ); + } +} + static HFONT input_context_select_ui_font( INPUTCONTEXT *ctx, HDC hdc ) { struct ime_private *priv; @@ -93,6 +107,47 @@ static HFONT input_context_select_ui_font( INPUTCONTEXT *ctx, HDC hdc ) return font; } +static void ime_send_message( HIMC himc, UINT message, WPARAM wparam, LPARAM lparam ) +{ + INPUTCONTEXT *ctx; + TRANSMSG *msgs; + HIMCC himcc; + + if (!(ctx = ImmLockIMC( himc ))) return; + if (!(himcc = ImmReSizeIMCC( ctx->hMsgBuf, (ctx->dwNumMsgBuf + 1) * sizeof(*msgs) ))) + WARN( "Failed to resize input context message buffer\n" ); + else if (!(msgs = ImmLockIMCC( (ctx->hMsgBuf = himcc) ))) + WARN( "Failed to lock input context message buffer\n" ); + else + { + TRANSMSG msg = {.message = message, .wParam = wparam, .lParam = lparam}; + msgs[ctx->dwNumMsgBuf++] = msg; + ImmUnlockIMCC( ctx->hMsgBuf ); + } + + ImmUnlockIMC( himc ); + ImmGenerateMessage( himc ); +} + +static void ime_set_composition_status( HIMC himc, BOOL composition ) +{ + struct ime_private *priv; + INPUTCONTEXT *ctx; + UINT msg = 0; + + if (!(ctx = ImmLockIMC( himc ))) return; + if ((priv = ImmLockIMCC( ctx->hPrivate ))) + { + if (!priv->bInComposition && composition) msg = WM_IME_STARTCOMPOSITION; + else if (priv->bInComposition && !composition) msg = WM_IME_ENDCOMPOSITION; + priv->bInComposition = composition; + ImmUnlockIMCC( ctx->hPrivate ); + } + ImmUnlockIMC( himc ); + + if (msg) ime_send_message( himc, msg, 0, 0 ); +} + static void ime_ui_paint( HIMC himc, HWND hwnd ) { PAINTSTRUCT ps; @@ -390,9 +445,88 @@ BOOL WINAPI ImeSetCompositionString( HIMC himc, DWORD index, const void *comp, D BOOL WINAPI NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) { - FIXME( "himc %p, action %lu, index %lu, value %lu stub!\n", himc, action, index, value ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + struct ime_private *priv; + INPUTCONTEXT *ctx; + + TRACE( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc, action, index, value ); + + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + + switch (action) + { + case NI_CONTEXTUPDATED: + switch (value) + { + case IMC_SETCOMPOSITIONFONT: + if ((priv = ImmLockIMCC( ctx->hPrivate ))) + { + if (priv->textfont) DeleteObject( priv->textfont ); + priv->textfont = CreateFontIndirectW( &ctx->lfFont.W ); + ImmUnlockIMCC( ctx->hPrivate ); + } + break; + case IMC_SETOPENSTATUS: + if (!ctx->fOpen) + { + input_context_reset_comp_str( ctx ); + ime_set_composition_status( himc, FALSE ); + } + NtUserNotifyIMEStatus( ctx->hWnd, ctx->fOpen ); + break; + default: + FIXME( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc, action, index, value ); + break; + } + break; + + case NI_COMPOSITIONSTR: + switch (index) + { + case CPS_COMPLETE: + { + COMPOSITIONSTRING *compstr; + + if (!(compstr = ImmLockIMCC( ctx->hCompStr ))) + WARN( "Failed to lock input context composition string\n" ); + else + { + WCHAR wchr = *(WCHAR *)((BYTE *)compstr + compstr->dwCompStrOffset); + COMPOSITIONSTRING tmp = *compstr; + UINT flags = 0; + + memset( compstr, 0, sizeof(*compstr) ); + compstr->dwSize = tmp.dwSize; + compstr->dwResultStrLen = tmp.dwCompStrLen; + compstr->dwResultStrOffset = tmp.dwCompStrOffset; + compstr->dwResultClauseLen = tmp.dwCompClauseLen; + compstr->dwResultClauseOffset = tmp.dwCompClauseOffset; + ImmUnlockIMCC( ctx->hCompStr ); + + if (tmp.dwCompStrLen) flags |= GCS_RESULTSTR; + if (tmp.dwCompClauseLen) flags |= GCS_RESULTCLAUSE; + if (flags) ime_send_message( himc, WM_IME_COMPOSITION, wchr, flags ); + } + + ImmSetOpenStatus( himc, FALSE ); + break; + } + case CPS_CANCEL: + input_context_reset_comp_str( ctx ); + ImmSetOpenStatus( himc, FALSE ); + break; + default: + FIXME( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc, action, index, value ); + break; + } + break; + + default: + FIXME( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc, action, index, value ); + break; + } + + ImmUnlockIMC( himc ); + return TRUE; } LRESULT WINAPI ImeEscape( HIMC himc, UINT escape, void *data ) diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index cbd8908a12d..3cc73c3974c 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -529,108 +529,6 @@ UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, return 0; } -BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) -{ - BOOL bRet = FALSE; - LPINPUTCONTEXT lpIMC; - - TRACE("%p %li %li %li\n",hIMC,dwAction,dwIndex,dwValue); - - lpIMC = LockRealIMC(hIMC); - if (lpIMC == NULL) - return FALSE; - - switch (dwAction) - { - case NI_OPENCANDIDATE: FIXME("NI_OPENCANDIDATE\n"); break; - case NI_CLOSECANDIDATE: FIXME("NI_CLOSECANDIDATE\n"); break; - case NI_SELECTCANDIDATESTR: FIXME("NI_SELECTCANDIDATESTR\n"); break; - case NI_CHANGECANDIDATELIST: FIXME("NI_CHANGECANDIDATELIST\n"); break; - case NI_SETCANDIDATE_PAGESTART: FIXME("NI_SETCANDIDATE_PAGESTART\n"); break; - case NI_SETCANDIDATE_PAGESIZE: FIXME("NI_SETCANDIDATE_PAGESIZE\n"); break; - case NI_CONTEXTUPDATED: - switch (dwValue) - { - case IMC_SETCOMPOSITIONWINDOW: FIXME("IMC_SETCOMPOSITIONWINDOW\n"); break; - case IMC_SETCONVERSIONMODE: FIXME("IMC_SETCONVERSIONMODE\n"); break; - case IMC_SETSENTENCEMODE: FIXME("IMC_SETSENTENCEMODE\n"); break; - case IMC_SETCANDIDATEPOS: FIXME("IMC_SETCANDIDATEPOS\n"); break; - case IMC_SETCOMPOSITIONFONT: - { - LPIMEPRIVATE myPrivate; - TRACE("IMC_SETCOMPOSITIONFONT\n"); - - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (myPrivate->textfont) - { - DeleteObject(myPrivate->textfont); - myPrivate->textfont = NULL; - } - myPrivate->textfont = CreateFontIndirectW(&lpIMC->lfFont.W); - ImmUnlockIMCC(lpIMC->hPrivate); - } - break; - case IMC_SETOPENSTATUS: - if (!lpIMC->fOpen) - { - input_context_reset_comp_str( lpIMC ); - ime_set_composition_status( hIMC, FALSE ); - } - NtUserNotifyIMEStatus( lpIMC->hWnd, lpIMC->fOpen ); - bRet = TRUE; - break; - default: FIXME("Unknown\n"); break; - } - break; - case NI_COMPOSITIONSTR: - switch (dwIndex) - { - case CPS_COMPLETE: - { - COMPOSITIONSTRING *compstr; - - if (!(compstr = ImmLockIMCC( lpIMC->hCompStr ))) - WARN( "Failed to lock input context composition string\n" ); - else - { - WCHAR wchr = *(WCHAR *)((BYTE *)compstr + compstr->dwCompStrOffset); - COMPOSITIONSTRING tmp = *compstr; - UINT flags = 0; - - memset( compstr, 0, sizeof(*compstr) ); - compstr->dwSize = tmp.dwSize; - compstr->dwResultStrLen = tmp.dwCompStrLen; - compstr->dwResultStrOffset = tmp.dwCompStrOffset; - compstr->dwResultClauseLen = tmp.dwCompClauseLen; - compstr->dwResultClauseOffset = tmp.dwCompClauseOffset; - ImmUnlockIMCC( lpIMC->hCompStr ); - - if (tmp.dwCompStrLen) flags |= GCS_RESULTSTR; - if (tmp.dwCompClauseLen) flags |= GCS_RESULTCLAUSE; - if (flags) GenerateIMEMessage( hIMC, WM_IME_COMPOSITION, wchr, flags ); - } - - ImmSetOpenStatus( hIMC, FALSE ); - bRet = TRUE; - } - break; - case CPS_CONVERT: FIXME("CPS_CONVERT\n"); break; - case CPS_REVERT: FIXME("CPS_REVERT\n"); break; - case CPS_CANCEL: - input_context_reset_comp_str( lpIMC ); - ime_set_composition_status( hIMC, FALSE ); - bRet = TRUE; - break; - default: FIXME("Unknown\n"); break; - } - break; - default: FIXME("Unknown Message\n"); break; - } - - UnlockRealIMC(hIMC); - return bRet; -} - BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen, LPCVOID lpRead, DWORD dwReadLen) diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec index a753536eb3f..da502c4832e 100644 --- a/dlls/winex11.drv/winex11.drv.spec +++ b/dlls/winex11.drv/winex11.drv.spec @@ -13,6 +13,5 @@ #IME Interface @ stdcall ImeSelect(long long) @ stdcall ImeToAsciiEx(long long ptr ptr long long) -@ stdcall NotifyIME(long long long long) @ stdcall ImeSetCompositionString(long long ptr long ptr long) @ stdcall ImeProcessKey(long long long ptr) From e69df13398074a692797e70407e07bf2ab85c84b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 11:38:32 +0200 Subject: [PATCH 1906/2777] winemac: Use the default IME implementation for NotifyIME. (cherry picked from commit 4c9154536737e33bb17e3dafb073dba3292570dd) --- dlls/winemac.drv/event.c | 10 ++ dlls/winemac.drv/gdi.c | 1 + dlls/winemac.drv/ime.c | 154 +----------------------------- dlls/winemac.drv/macdrv.h | 1 + dlls/winemac.drv/macdrv_main.c | 9 -- dlls/winemac.drv/unixlib.h | 1 - dlls/winemac.drv/winemac.drv.spec | 1 - 7 files changed, 14 insertions(+), 163 deletions(-) diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c index cc8aa4681c6..6a695f87e58 100644 --- a/dlls/winemac.drv/event.c +++ b/dlls/winemac.drv/event.c @@ -356,6 +356,16 @@ BOOL query_ime_char_rect(macdrv_query* query) } +/*********************************************************************** + * NotifyIMEStatus (X11DRV.@) + */ +void macdrv_NotifyIMEStatus( HWND hwnd, UINT status ) +{ + TRACE_(imm)( "hwnd %p, status %#x\n", hwnd, status ); + if (!status) macdrv_clear_ime_text(); +} + + /*********************************************************************** * macdrv_query_event * diff --git a/dlls/winemac.drv/gdi.c b/dlls/winemac.drv/gdi.c index d22532fd3b7..9c594a5fff6 100644 --- a/dlls/winemac.drv/gdi.c +++ b/dlls/winemac.drv/gdi.c @@ -302,6 +302,7 @@ static const struct user_driver_funcs macdrv_funcs = .pUpdateClipboard = macdrv_UpdateClipboard, .pUpdateLayeredWindow = macdrv_UpdateLayeredWindow, .pVkKeyScanEx = macdrv_VkKeyScanEx, + .pNotifyIMEStatus = macdrv_NotifyIMEStatus, .pWindowMessage = macdrv_WindowMessage, .pWindowPosChanged = macdrv_WindowPosChanged, .pWindowPosChanging = macdrv_WindowPosChanging, diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index dae7da3b8f3..617533e956f 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -652,156 +652,6 @@ UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, return 0; } -BOOL WINAPI NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) -{ - BOOL bRet = FALSE; - LPINPUTCONTEXT lpIMC; - - TRACE("%p %li %li %li\n", hIMC, dwAction, dwIndex, dwValue); - - lpIMC = LockRealIMC(hIMC); - if (lpIMC == NULL) - return FALSE; - - switch (dwAction) - { - case NI_OPENCANDIDATE: FIXME("NI_OPENCANDIDATE\n"); break; - case NI_CLOSECANDIDATE: FIXME("NI_CLOSECANDIDATE\n"); break; - case NI_SELECTCANDIDATESTR: FIXME("NI_SELECTCANDIDATESTR\n"); break; - case NI_CHANGECANDIDATELIST: FIXME("NI_CHANGECANDIDATELIST\n"); break; - case NI_SETCANDIDATE_PAGESTART: FIXME("NI_SETCANDIDATE_PAGESTART\n"); break; - case NI_SETCANDIDATE_PAGESIZE: FIXME("NI_SETCANDIDATE_PAGESIZE\n"); break; - case NI_CONTEXTUPDATED: - switch (dwValue) - { - case IMC_SETCOMPOSITIONWINDOW: FIXME("NI_CONTEXTUPDATED: IMC_SETCOMPOSITIONWINDOW\n"); break; - case IMC_SETCONVERSIONMODE: FIXME("NI_CONTEXTUPDATED: IMC_SETCONVERSIONMODE\n"); break; - case IMC_SETSENTENCEMODE: FIXME("NI_CONTEXTUPDATED: IMC_SETSENTENCEMODE\n"); break; - case IMC_SETCANDIDATEPOS: FIXME("NI_CONTEXTUPDATED: IMC_SETCANDIDATEPOS\n"); break; - case IMC_SETCOMPOSITIONFONT: - { - LPIMEPRIVATE myPrivate; - TRACE("NI_CONTEXTUPDATED: IMC_SETCOMPOSITIONFONT\n"); - - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (myPrivate->textfont) - { - DeleteObject(myPrivate->textfont); - myPrivate->textfont = NULL; - } - myPrivate->textfont = CreateFontIndirectW(&lpIMC->lfFont.W); - ImmUnlockIMCC(lpIMC->hPrivate); - } - break; - case IMC_SETOPENSTATUS: - { - LPIMEPRIVATE myPrivate; - TRACE("NI_CONTEXTUPDATED: IMC_SETOPENSTATUS\n"); - - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (lpIMC->fOpen != myPrivate->bInternalState && myPrivate->bInComposition) - { - if(lpIMC->fOpen == FALSE) - { - GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); - myPrivate->bInComposition = FALSE; - } - else - { - GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0); - GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0, 0); - } - } - myPrivate->bInternalState = lpIMC->fOpen; - bRet = TRUE; - } - break; - default: FIXME("NI_CONTEXTUPDATED: Unknown\n"); break; - } - break; - case NI_COMPOSITIONSTR: - switch (dwIndex) - { - case CPS_COMPLETE: - { - HIMCC newCompStr; - LPIMEPRIVATE myPrivate; - WCHAR *str; - UINT len; - - TRACE("NI_COMPOSITIONSTR: CPS_COMPLETE\n"); - - /* clear existing result */ - newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0); - - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if ((str = input_context_get_comp_str( lpIMC, FALSE, &len ))) - { - WCHAR param = str[0]; - DWORD flags = GCS_COMPSTR; - - newCompStr = updateResultStr( lpIMC->hCompStr, str, len ); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0, &flags); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - - GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, 0, flags); - - GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, param, - GCS_RESULTSTR | GCS_RESULTCLAUSE); - - GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); - free( str ); - } - else if (myPrivate->bInComposition) - GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); - - - myPrivate->bInComposition = FALSE; - ImmUnlockIMCC(lpIMC->hPrivate); - - bRet = TRUE; - } - break; - case CPS_CONVERT: FIXME("NI_COMPOSITIONSTR: CPS_CONVERT\n"); break; - case CPS_REVERT: FIXME("NI_COMPOSITIONSTR: CPS_REVERT\n"); break; - case CPS_CANCEL: - { - LPIMEPRIVATE myPrivate; - - TRACE("NI_COMPOSITIONSTR: CPS_CANCEL\n"); - - MACDRV_CALL(ime_clear, NULL); - if (lpIMC->hCompStr) - ImmDestroyIMCC(lpIMC->hCompStr); - - lpIMC->hCompStr = ImeCreateBlankCompStr(); - - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (myPrivate->bInComposition) - { - GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); - myPrivate->bInComposition = FALSE; - } - ImmUnlockIMCC(lpIMC->hPrivate); - bRet = TRUE; - } - break; - default: FIXME("NI_COMPOSITIONSTR: Unknown\n"); break; - } - break; - default: FIXME("Unknown Message\n"); break; - } - - UnlockRealIMC(hIMC); - return bRet; -} - static BOOL IME_SetCompositionString(void* hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen, DWORD cursor_pos, BOOL cursor_valid) { LPINPUTCONTEXT lpIMC; @@ -863,7 +713,7 @@ static BOOL IME_SetCompositionString(void* hIMC, DWORD dwIndex, LPCVOID lpComp, } else { - NotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0); + ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0); sendMessage = FALSE; } @@ -891,7 +741,7 @@ BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, DW static void IME_NotifyComplete(void* hIMC) { - NotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); + ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); } /* Interfaces to other parts of the Mac driver */ diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index b77e62f75db..71f1215da60 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -167,6 +167,7 @@ extern INT macdrv_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyStat LPWSTR bufW, int bufW_size, UINT flags, HKL hkl) DECLSPEC_HIDDEN; extern UINT macdrv_GetKeyboardLayoutList(INT size, HKL *list) DECLSPEC_HIDDEN; extern INT macdrv_GetKeyNameText(LONG lparam, LPWSTR buffer, INT size) DECLSPEC_HIDDEN; +extern void macdrv_NotifyIMEStatus( HWND hwnd, UINT status ) DECLSPEC_HIDDEN; extern BOOL macdrv_SystemParametersInfo(UINT action, UINT int_param, void *ptr_param, UINT flags) DECLSPEC_HIDDEN; extern BOOL macdrv_ProcessEvents(DWORD mask) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/macdrv_main.c b/dlls/winemac.drv/macdrv_main.c index 7e91e0ca3e1..9125574e35b 100644 --- a/dlls/winemac.drv/macdrv_main.c +++ b/dlls/winemac.drv/macdrv_main.c @@ -605,13 +605,6 @@ NTSTATUS macdrv_client_func(enum macdrv_client_funcs id, const void *params, ULO } -static NTSTATUS macdrv_ime_clear(void *arg) -{ - macdrv_clear_ime_text(); - return 0; -} - - static NTSTATUS macdrv_ime_using_input_method(void *arg) { return macdrv_using_input_method(); @@ -633,7 +626,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = macdrv_dnd_have_format, macdrv_dnd_release, macdrv_dnd_retain, - macdrv_ime_clear, macdrv_ime_process_text_input, macdrv_ime_get_text_input, macdrv_ime_using_input_method, @@ -758,7 +750,6 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = macdrv_dnd_have_format, macdrv_dnd_release, macdrv_dnd_retain, - macdrv_ime_clear, wow64_ime_process_text_input, macdrv_ime_get_text_input, macdrv_ime_using_input_method, diff --git a/dlls/winemac.drv/unixlib.h b/dlls/winemac.drv/unixlib.h index 493e4f6c139..1f7840a1546 100644 --- a/dlls/winemac.drv/unixlib.h +++ b/dlls/winemac.drv/unixlib.h @@ -26,7 +26,6 @@ enum macdrv_funcs unix_dnd_have_format, unix_dnd_release, unix_dnd_retain, - unix_ime_clear, unix_ime_process_text_input, unix_ime_get_text_input, unix_ime_using_input_method, diff --git a/dlls/winemac.drv/winemac.drv.spec b/dlls/winemac.drv/winemac.drv.spec index debaec8239d..5a9403c3cf5 100644 --- a/dlls/winemac.drv/winemac.drv.spec +++ b/dlls/winemac.drv/winemac.drv.spec @@ -6,4 +6,3 @@ @ stdcall ImeSelect(long long) @ stdcall ImeSetCompositionString(long long ptr long ptr long) @ stdcall ImeToAsciiEx(long long ptr ptr long long) -@ stdcall NotifyIME(long long long long) From 62d492e732806bddf9c0c5fdfa4b4fb93160a712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 5 May 2023 14:24:43 +0200 Subject: [PATCH 1907/2777] winex11: Use the default IME implementation for ImeSetCompositionString. (cherry picked from commit 2c74f4ede1ebb0ac25eb4c1a20ec99c8af4f29e0) --- dlls/imm32/ime.c | 70 +++++++++++++++++++++++++++---- dlls/winex11.drv/ime.c | 70 +------------------------------ dlls/winex11.drv/winex11.drv.spec | 1 - 3 files changed, 63 insertions(+), 78 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 44b1173b1db..3e5f34d6760 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -83,16 +83,51 @@ static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT * return text; } -static void input_context_reset_comp_str( INPUTCONTEXT *ctx ) +static void input_context_set_comp_str( INPUTCONTEXT *ctx, const WCHAR *str, UINT len ) { COMPOSITIONSTRING *compstr; + HIMCC himcc; + UINT size; + BYTE *dst; + + size = sizeof(*compstr); + size += len * sizeof(WCHAR); /* GCS_COMPSTR */ + size += len; /* GCS_COMPSTRATTR */ + size += 2 * sizeof(DWORD); /* GCS_COMPSTRCLAUSE */ - if (!(compstr = ImmLockIMCC( ctx->hCompStr ))) + if (!(himcc = ImmReSizeIMCC( ctx->hCompStr, size ))) + WARN( "Failed to resize input context composition string\n" ); + else if (!(compstr = ImmLockIMCC( (ctx->hCompStr = himcc) ))) WARN( "Failed to lock input context composition string\n" ); else { memset( compstr, 0, sizeof(*compstr) ); compstr->dwSize = sizeof(*compstr); + + if (len) + { + compstr->dwCursorPos = len; + + compstr->dwCompStrLen = len; + compstr->dwCompStrOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwCompStrOffset; + memcpy( dst, str, compstr->dwCompStrLen * sizeof(WCHAR) ); + compstr->dwSize += compstr->dwCompStrLen * sizeof(WCHAR); + + compstr->dwCompClauseLen = 2 * sizeof(DWORD); + compstr->dwCompClauseOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwCompClauseOffset; + *((DWORD *)dst + 0) = 0; + *((DWORD *)dst + 1) = compstr->dwCompStrLen; + compstr->dwSize += compstr->dwCompClauseLen; + + compstr->dwCompAttrLen = compstr->dwCompStrLen; + compstr->dwCompAttrOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwCompAttrOffset; + memset( dst, ATTR_INPUT, compstr->dwCompAttrLen ); + compstr->dwSize += compstr->dwCompAttrLen; + } + ImmUnlockIMCC( ctx->hCompStr ); } } @@ -437,10 +472,29 @@ DWORD WINAPI ImeConversionList( HIMC himc, const WCHAR *source, CANDIDATELIST *d BOOL WINAPI ImeSetCompositionString( HIMC himc, DWORD index, const void *comp, DWORD comp_len, const void *read, DWORD read_len ) { - FIXME( "himc %p, index %lu, comp %p, comp_len %lu, read %p, read_len %lu stub!\n", - himc, index, comp, comp_len, read, read_len ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + INPUTCONTEXT *ctx; + + FIXME( "himc %p, index %lu, comp %p, comp_len %lu, read %p, read_len %lu semi-stub!\n", + himc, index, comp, comp_len, read, read_len ); + if (read && read_len) FIXME( "Read string unimplemented\n" ); + if (index != SCS_SETSTR && index != SCS_CHANGECLAUSE && index != SCS_CHANGEATTR) return FALSE; + + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + + if (index != SCS_SETSTR) + FIXME( "index %#lx not implemented\n", index ); + else + { + UINT flags = GCS_COMPSTR | GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART | GCS_CURSORPOS; + WCHAR wparam = comp && comp_len >= sizeof(WCHAR) ? *(WCHAR *)comp : 0; + input_context_set_comp_str( ctx, comp, comp_len / sizeof(WCHAR) ); + ime_set_composition_status( himc, TRUE ); + ime_send_message( himc, WM_IME_COMPOSITION, wparam, flags ); + } + + ImmUnlockIMC( himc ); + + return TRUE; } BOOL WINAPI NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) @@ -468,7 +522,7 @@ BOOL WINAPI NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) case IMC_SETOPENSTATUS: if (!ctx->fOpen) { - input_context_reset_comp_str( ctx ); + input_context_set_comp_str( ctx, NULL, 0 ); ime_set_composition_status( himc, FALSE ); } NtUserNotifyIMEStatus( ctx->hWnd, ctx->fOpen ); @@ -511,7 +565,7 @@ BOOL WINAPI NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) break; } case CPS_CANCEL: - input_context_reset_comp_str( ctx ); + input_context_set_comp_str( ctx, NULL, 0 ); ImmSetOpenStatus( himc, FALSE ); break; default: diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 3cc73c3974c..b46c2d86892 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -529,74 +529,6 @@ UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, return 0; } -BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, - DWORD dwCompLen, LPCVOID lpRead, - DWORD dwReadLen) -{ - LPINPUTCONTEXT lpIMC; - DWORD flags = 0; - WCHAR wParam = 0; - - TRACE("(%p, %ld, %p, %ld, %p, %ld):\n", - hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); - - - if (hIMC != FROM_X11) - FIXME("PROBLEM: This only sets the wine level string\n"); - - /* - * Explanation: - * this sets the composition string in the imm32.dll level - * of the composition buffer. we cannot manipulate the xim level - * buffer, which means that once the xim level buffer changes again - * any call to this function from the application will be lost - */ - - if (lpRead && dwReadLen) - FIXME("Reading string unimplemented\n"); - - lpIMC = LockRealIMC(hIMC); - - if (lpIMC == NULL) - return FALSE; - - if (dwIndex == SCS_SETSTR) - { - HIMCC newCompStr; - - ime_set_composition_status( hIMC, TRUE ); - - /* clear existing result */ - newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - - flags = GCS_COMPSTR; - - if (dwCompLen && lpComp) - { - newCompStr = updateCompStr(lpIMC->hCompStr, (LPCWSTR)lpComp, dwCompLen / sizeof(WCHAR)); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - - wParam = ((const WCHAR*)lpComp)[0]; - flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART; - } - else - { - newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - } - } - - GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, wParam, flags); - ImmUnlockIMCC(lpIMC->hPrivate); - UnlockRealIMC(hIMC); - - return TRUE; -} - /* Interfaces to XIM and other parts of winex11drv */ NTSTATUS x11drv_ime_set_open_status( UINT open ) @@ -693,7 +625,7 @@ NTSTATUS x11drv_ime_update_association( UINT arg ) NTSTATUS WINAPI x11drv_ime_set_composition_string( void *param, ULONG size ) { - return ImeSetCompositionString(FROM_X11, SCS_SETSTR, param, size, NULL, 0); + return ImmSetCompositionStringW( RealIMC(FROM_X11), SCS_SETSTR, param, size, NULL, 0 ); } NTSTATUS WINAPI x11drv_ime_set_result( void *params, ULONG len ) diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec index da502c4832e..64154d709a2 100644 --- a/dlls/winex11.drv/winex11.drv.spec +++ b/dlls/winex11.drv/winex11.drv.spec @@ -13,5 +13,4 @@ #IME Interface @ stdcall ImeSelect(long long) @ stdcall ImeToAsciiEx(long long ptr ptr long long) -@ stdcall ImeSetCompositionString(long long ptr long ptr long) @ stdcall ImeProcessKey(long long long ptr) From efc05ecd23ddba071b2cac1f1557dc57183a4e42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 13:44:43 +0200 Subject: [PATCH 1908/2777] winemac: Use the default IME implementation for ImeSetCompositionString. (cherry picked from commit ab98b13480049b3cdb0e842adcde28b8ee9e265e) --- dlls/winemac.drv/ime.c | 11 ----------- dlls/winemac.drv/winemac.drv.spec | 1 - 2 files changed, 12 deletions(-) diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index 617533e956f..65a79df2570 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -728,17 +728,6 @@ static BOOL IME_SetCompositionString(void* hIMC, DWORD dwIndex, LPCVOID lpComp, return TRUE; } -BOOL WINAPI ImeSetCompositionString(HIMC hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen, - LPCVOID lpRead, DWORD dwReadLen) -{ - TRACE("(%p, %ld, %p, %ld, %p, %ld):\n", hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen); - - if (lpRead && dwReadLen) - FIXME("Reading string unimplemented\n"); - - return IME_SetCompositionString(hIMC, dwIndex, lpComp, dwCompLen, 0, FALSE); -} - static void IME_NotifyComplete(void* hIMC) { ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); diff --git a/dlls/winemac.drv/winemac.drv.spec b/dlls/winemac.drv/winemac.drv.spec index 5a9403c3cf5..aca1c58cf13 100644 --- a/dlls/winemac.drv/winemac.drv.spec +++ b/dlls/winemac.drv/winemac.drv.spec @@ -4,5 +4,4 @@ # IME @ stdcall ImeProcessKey(long long long ptr) @ stdcall ImeSelect(long long) -@ stdcall ImeSetCompositionString(long long ptr long ptr long) @ stdcall ImeToAsciiEx(long long ptr ptr long long) From 0349c88ce08fc247b66a374e5e8966c27288bcc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 12 May 2023 07:23:00 +0200 Subject: [PATCH 1909/2777] win32u: Introduce a new ImeProcessKey call through NtUserMessageCall. (cherry picked from commit c7dc10b19256f27a1a6a6f2e32aadaeebef07eb4) --- dlls/imm32/ime.c | 17 +++++++++++++---- dlls/win32u/driver.c | 12 ++++++++++++ dlls/win32u/imm.c | 13 +++++++++++++ dlls/win32u/message.c | 3 +++ dlls/win32u/ntuser_private.h | 4 ++++ dlls/winex11.drv/ime.c | 7 ------- dlls/winex11.drv/winex11.drv.spec | 1 - dlls/wow64win/user.c | 13 +++++++++++++ include/ntuser.h | 14 ++++++++++++++ include/wine/gdi_driver.h | 1 + 10 files changed, 73 insertions(+), 12 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 3e5f34d6760..eee623a6eb5 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -439,11 +439,20 @@ BOOL WINAPI ImeSetActiveContext( HIMC himc, BOOL flag ) return TRUE; } -BOOL WINAPI ImeProcessKey( HIMC himc, UINT vkey, LPARAM key_data, BYTE *key_state ) +BOOL WINAPI ImeProcessKey( HIMC himc, UINT vkey, LPARAM lparam, BYTE *state ) { - FIXME( "himc %p, vkey %u, key_data %#Ix, key_state %p stub!\n", himc, vkey, key_data, key_state ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return FALSE; + struct ime_driver_call_params params = {.himc = himc, .state = state}; + INPUTCONTEXT *ctx; + LRESULT ret; + + TRACE( "himc %p, vkey %#x, lparam %#Ix, state %p\n", himc, vkey, lparam, state ); + + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + ret = NtUserMessageCall( ctx->hWnd, WINE_IME_PROCESS_KEY, vkey, lparam, ¶ms, + NtUserImeDriverCall, FALSE ); + ImmUnlockIMC( himc ); + + return ret; } UINT WINAPI ImeToAsciiEx( UINT vkey, UINT scan_code, BYTE *key_state, TRANSMSGLIST *msgs, UINT state, HIMC himc ) diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index f0055b68d1e..e1dd1a1ebcf 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -716,6 +716,11 @@ static SHORT nulldrv_VkKeyScanEx( WCHAR ch, HKL layout ) return -256; /* use default implementation */ } +static UINT nulldrv_ImeProcessKey( HIMC himc, UINT wparam, UINT lparam, const BYTE *state ) +{ + return 0; +} + static void nulldrv_NotifyIMEStatus( HWND hwnd, UINT status ) { } @@ -1074,6 +1079,11 @@ static SHORT loaderdrv_VkKeyScanEx( WCHAR ch, HKL layout ) return load_driver()->pVkKeyScanEx( ch, layout ); } +static UINT loaderdrv_ImeProcessKey( HIMC himc, UINT wparam, UINT lparam, const BYTE *state ) +{ + return load_driver()->pImeProcessKey( himc, wparam, lparam, state ); +} + static void loaderdrv_NotifyIMEStatus( HWND hwnd, UINT status ) { return load_driver()->pNotifyIMEStatus( hwnd, status ); @@ -1185,6 +1195,7 @@ static const struct user_driver_funcs lazy_load_driver = loaderdrv_ToUnicodeEx, loaderdrv_UnregisterHotKey, loaderdrv_VkKeyScanEx, + loaderdrv_ImeProcessKey, loaderdrv_NotifyIMEStatus, /* cursor/icon functions */ nulldrv_DestroyCursorIcon, @@ -1265,6 +1276,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version SET_USER_FUNC(ToUnicodeEx); SET_USER_FUNC(UnregisterHotKey); SET_USER_FUNC(VkKeyScanEx); + SET_USER_FUNC(ImeProcessKey); SET_USER_FUNC(NotifyIMEStatus); SET_USER_FUNC(DestroyCursorIcon); SET_USER_FUNC(SetCursor); diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index 328a4a3eddf..b91c3617472 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -421,6 +421,19 @@ NTSTATUS WINAPI NtUserBuildHimcList( UINT thread_id, UINT count, HIMC *buffer, U return STATUS_SUCCESS; } +LRESULT ime_driver_call( HWND hwnd, enum wine_ime_call call, WPARAM wparam, LPARAM lparam, + struct ime_driver_call_params *params ) +{ + switch (call) + { + case WINE_IME_PROCESS_KEY: + return user_driver->pImeProcessKey( params->himc, wparam, lparam, params->state ); + default: + ERR( "Unknown IME driver call %#x\n", call ); + return 0; + } +} + /***************************************************************************** * NtUserNotifyIMEStatus (win32u.@) */ diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 62924119c7d..8c7548a396a 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -3688,6 +3688,9 @@ LRESULT WINAPI NtUserMessageCall( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpa spy_exit_message( ansi, hwnd, msg, (LPARAM)result_info, wparam, lparam ); return 0; + case NtUserImeDriverCall: + return ime_driver_call( hwnd, msg, wparam, lparam, result_info ); + default: FIXME( "%p %x %lx %lx %p %x %x\n", hwnd, msg, (long)wparam, lparam, result_info, (int)type, ansi ); } diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 41a53837642..b7d2b633eb5 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -236,6 +236,10 @@ BOOL needs_ime_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void register_builtin_classes(void) DECLSPEC_HIDDEN; extern void register_desktop_class(void) DECLSPEC_HIDDEN; +/* imm.c */ +extern LRESULT ime_driver_call( HWND hwnd, enum wine_ime_call call, WPARAM wparam, LPARAM lparam, + struct ime_driver_call_params *params ) DECLSPEC_HIDDEN; + /* cursoricon.c */ HICON alloc_cursoricon_handle( BOOL is_icon ) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index b46c2d86892..348be4f0ad6 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -477,13 +477,6 @@ static void IME_AddToSelected(HIMC hIMC) hSelectedFrom[hSelectedCount-1] = hIMC; } -BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lpbKeyState) -{ - /* See the comment at the head of this file */ - TRACE("We do no processing via this route\n"); - return FALSE; -} - BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) { LPINPUTCONTEXT lpIMC; diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec index 64154d709a2..8b286033250 100644 --- a/dlls/winex11.drv/winex11.drv.spec +++ b/dlls/winex11.drv/winex11.drv.spec @@ -13,4 +13,3 @@ #IME Interface @ stdcall ImeSelect(long long) @ stdcall ImeToAsciiEx(long long ptr ptr long long) -@ stdcall ImeProcessKey(long long long ptr) diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index f0b57f7c886..02c2d9d975e 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -3126,6 +3126,19 @@ NTSTATUS WINAPI wow64_NtUserMessageCall( UINT *args ) return message_call_32to64( hwnd, msg, wparam, lparam, LongToPtr( result32 ), type, ansi ); } + + case NtUserImeDriverCall: + { + struct + { + ULONG himc; + ULONG state; + } *params32 = result_info; + struct ime_driver_call_params params; + params.himc = UlongToPtr( params32->himc ); + params.state = UlongToPtr( params32->state ); + return NtUserMessageCall( hwnd, msg, wparam, lparam, ¶ms, type, ansi ); + } } return message_call_32to64( hwnd, msg, wparam, lparam, result_info, type, ansi ); diff --git a/include/ntuser.h b/include/ntuser.h index 198f7889020..86c18426701 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -305,6 +305,7 @@ enum NtUserSpyEnter = 0x0304, NtUserSpyExit = 0x0305, NtUserWinProcResult = 0x0306, + NtUserImeDriverCall = 0x0307, }; /* NtUserThunkedMenuItemInfo codes */ @@ -490,6 +491,19 @@ enum wine_internal_message #define IME_INTERNAL_HKL_ACTIVATE 0x19 #define IME_INTERNAL_HKL_DEACTIVATE 0x20 +/* builtin IME driver calls */ +enum wine_ime_call +{ + WINE_IME_PROCESS_KEY, +}; + +/* NtUserImeDriverCall params */ +struct ime_driver_call_params +{ + HIMC himc; + const BYTE *state; +}; + /* internal IME private */ typedef struct ime_private { diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index bd7916da900..03d164c05b9 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -287,6 +287,7 @@ struct user_driver_funcs void (*pUnregisterHotKey)(HWND, UINT, UINT); SHORT (*pVkKeyScanEx)(WCHAR, HKL); /* IME functions */ + UINT (*pImeProcessKey)(HIMC,UINT,UINT,const BYTE*); void (*pNotifyIMEStatus)(HWND,UINT); /* cursor/icon functions */ void (*pDestroyCursorIcon)(HCURSOR); From cdf62585e0412de1f2eeb14b6976992913ac481f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 2 May 2023 12:14:19 +0200 Subject: [PATCH 1910/2777] winemac: Use the ImeProcessKey driver entry to process IME input. (cherry picked from commit f185dc1701f2076758ca59233fffc93924da1814) --- dlls/winemac.drv/gdi.c | 1 + dlls/winemac.drv/ime.c | 90 +------------------------------ dlls/winemac.drv/keyboard.c | 29 ++++++---- dlls/winemac.drv/macdrv.h | 2 +- dlls/winemac.drv/macdrv_main.c | 30 ----------- dlls/winemac.drv/unixlib.h | 12 ----- dlls/winemac.drv/winemac.drv.spec | 1 - 7 files changed, 22 insertions(+), 143 deletions(-) diff --git a/dlls/winemac.drv/gdi.c b/dlls/winemac.drv/gdi.c index 9c594a5fff6..059b99a2465 100644 --- a/dlls/winemac.drv/gdi.c +++ b/dlls/winemac.drv/gdi.c @@ -302,6 +302,7 @@ static const struct user_driver_funcs macdrv_funcs = .pUpdateClipboard = macdrv_UpdateClipboard, .pUpdateLayeredWindow = macdrv_UpdateLayeredWindow, .pVkKeyScanEx = macdrv_VkKeyScanEx, + .pImeProcessKey = macdrv_ImeProcessKey, .pNotifyIMEStatus = macdrv_NotifyIMEStatus, .pWindowMessage = macdrv_WindowMessage, .pWindowPosChanged = macdrv_WindowPosChanged, diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index 65a79df2570..8ce9f4cd1ef 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -122,18 +122,6 @@ static BOOL UnlockRealIMC(HIMC hIMC) return FALSE; } -static HIMCC ImeCreateBlankCompStr(void) -{ - HIMCC rc; - LPCOMPOSITIONSTRING ptr; - rc = ImmCreateIMCC(sizeof(COMPOSITIONSTRING)); - ptr = ImmLockIMCC(rc); - memset(ptr, 0, sizeof(COMPOSITIONSTRING)); - ptr->dwSize = sizeof(COMPOSITIONSTRING); - ImmUnlockIMCC(rc); - return rc; -} - static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset, LPBYTE target, LPBYTE source, DWORD* lenParam, DWORD* offsetParam, BOOL wchars) @@ -516,59 +504,6 @@ static void UpdateDataInDefaultIMEWindow(INPUTCONTEXT *lpIMC, HWND hwnd, BOOL sh ImmUnlockIMCC(lpIMC->hCompStr); } -BOOL WINAPI ImeProcessKey(HIMC hIMC, UINT vKey, LPARAM lKeyData, const LPBYTE lpbKeyState) -{ - struct process_text_input_params params = - { - .himc = (UINT_PTR)hIMC, .vkey = LOWORD(vKey), .scan = HIWORD(lKeyData), - .repeat = !!(lKeyData >> 30), .key_state = lpbKeyState, - }; - LPINPUTCONTEXT lpIMC; - BOOL inIME; - UINT ret; - - TRACE("hIMC %p vKey 0x%04x lKeyData 0x%08Ix lpbKeyState %p\n", hIMC, vKey, lKeyData, lpbKeyState); - - switch (vKey) - { - case VK_SHIFT: - case VK_CONTROL: - case VK_CAPITAL: - case VK_MENU: - return FALSE; - } - - inIME = MACDRV_CALL(ime_using_input_method, NULL); - lpIMC = LockRealIMC(hIMC); - if (lpIMC) - { - LPIMEPRIVATE myPrivate; - HWND hwnd = input_context_get_ui_hwnd( lpIMC ); - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - - if (inIME && !myPrivate->bInternalState) - ImmSetOpenStatus(RealIMC(FROM_MACDRV), TRUE); - else if (!inIME && myPrivate->bInternalState) - { - ShowWindow( hwnd, SW_HIDE ); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = ImeCreateBlankCompStr(); - ImmSetOpenStatus(RealIMC(FROM_MACDRV), FALSE); - } - - myPrivate->bInternalState = inIME; - ImmUnlockIMCC(lpIMC->hPrivate); - } - UnlockRealIMC(hIMC); - - if (!inIME) return FALSE; - - TRACE( "Processing Mac 0x%04x\n", vKey ); - ret = MACDRV_CALL( ime_process_text_input, ¶ms ); - - return ret != 0; -} - BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) { LPINPUTCONTEXT lpIMC; @@ -613,39 +548,16 @@ BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, TRANSMSGLIST *lpdwTransKey, UINT fuState, HIMC hIMC) { - UINT vkey; LPINPUTCONTEXT lpIMC; - LPIMEPRIVATE myPrivate; - HWND hwnd; TRACE("uVKey 0x%04x uScanCode 0x%04x fuState %u hIMC %p\n", uVKey, uScanCode, fuState, hIMC); - vkey = LOWORD(uVKey); - - if (vkey == VK_KANA || vkey == VK_KANJI || vkey == VK_MENU) - { - TRACE("Skipping metakey\n"); - return 0; - } - - lpIMC = LockRealIMC(hIMC); - hwnd = input_context_get_ui_hwnd( lpIMC ); - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (!myPrivate->bInternalState) - { - ImmUnlockIMCC(lpIMC->hPrivate); - UnlockRealIMC(hIMC); - return 0; - } - - ImmUnlockIMCC(lpIMC->hPrivate); - UnlockRealIMC(hIMC); - /* trigger the pending client_func_ime_set_text call */ MACDRV_CALL(ime_get_text_input, NULL); if ((lpIMC = LockRealIMC(hIMC))) { + HWND hwnd = input_context_get_ui_hwnd( lpIMC ); UpdateDataInDefaultIMEWindow( lpIMC, hwnd, FALSE ); UnlockRealIMC(hIMC); } diff --git a/dlls/winemac.drv/keyboard.c b/dlls/winemac.drv/keyboard.c index 0f45873a831..14f0010e37e 100644 --- a/dlls/winemac.drv/keyboard.c +++ b/dlls/winemac.drv/keyboard.c @@ -1189,19 +1189,29 @@ void macdrv_hotkey_press(const macdrv_event *event) /*********************************************************************** - * macdrv_process_text_input + * ImeProcessKey (MACDRV.@) */ -NTSTATUS macdrv_ime_process_text_input(void *arg) +UINT macdrv_ImeProcessKey(HIMC himc, UINT wparam, UINT lparam, const BYTE *key_state) { - struct process_text_input_params *params = arg; struct macdrv_thread_data *thread_data = macdrv_thread_data(); - void *himc = UlongToHandle(params->himc); - const BYTE *key_state = params->key_state; + WORD scan = HIWORD(lparam) & 0x1ff, vkey = LOWORD(wparam); + BOOL repeat = !!(lparam >> 30), pressed = !(lparam >> 31); unsigned int flags; int keyc, done = 0; - TRACE("vkey 0x%04x scan 0x%04x repeat %u himc %p\n", params->vkey, params->scan, - params->repeat, himc); + TRACE("himc %p, scan %#x, vkey %#x, repeat %u, pressed %u\n", + himc, scan, vkey, repeat, pressed); + + if (!macdrv_using_input_method()) return 0; + + switch (vkey) + { + case VK_SHIFT: + case VK_CONTROL: + case VK_CAPITAL: + case VK_MENU: + return 0; + } flags = thread_data->last_modifiers; if (key_state[VK_SHIFT] & 0x80) @@ -1223,14 +1233,13 @@ NTSTATUS macdrv_ime_process_text_input(void *arg) /* Find the Mac keycode corresponding to the scan code */ for (keyc = 0; keyc < ARRAY_SIZE(thread_data->keyc2vkey); keyc++) - if (thread_data->keyc2vkey[keyc] == params->vkey) break; + if (thread_data->keyc2vkey[keyc] == vkey) break; if (keyc >= ARRAY_SIZE(thread_data->keyc2vkey)) return 0; TRACE("flags 0x%08x keyc 0x%04x\n", flags, keyc); - macdrv_send_text_input_event(((params->scan & 0x8000) == 0), flags, params->repeat, keyc, - himc, &done); + macdrv_send_text_input_event(pressed, flags, repeat, keyc, himc, &done); while (!done) NtUserMsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_POSTMESSAGE | QS_SENDMESSAGE, 0); return done > 0; diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 71f1215da60..86b2e68e11b 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -162,6 +162,7 @@ extern BOOL macdrv_SetCursorPos(INT x, INT y) DECLSPEC_HIDDEN; extern BOOL macdrv_RegisterHotKey(HWND hwnd, UINT mod_flags, UINT vkey) DECLSPEC_HIDDEN; extern void macdrv_UnregisterHotKey(HWND hwnd, UINT modifiers, UINT vkey) DECLSPEC_HIDDEN; extern SHORT macdrv_VkKeyScanEx(WCHAR wChar, HKL hkl) DECLSPEC_HIDDEN; +extern UINT macdrv_ImeProcessKey(HIMC himc, UINT wparam, UINT lparam, const BYTE *state) DECLSPEC_HIDDEN; extern UINT macdrv_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl) DECLSPEC_HIDDEN; extern INT macdrv_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState, LPWSTR bufW, int bufW_size, UINT flags, HKL hkl) DECLSPEC_HIDDEN; @@ -277,7 +278,6 @@ extern NTSTATUS macdrv_dnd_get_formats(void *arg) DECLSPEC_HIDDEN; extern NTSTATUS macdrv_dnd_have_format(void *arg) DECLSPEC_HIDDEN; extern NTSTATUS macdrv_dnd_release(void *arg) DECLSPEC_HIDDEN; extern NTSTATUS macdrv_dnd_retain(void *arg) DECLSPEC_HIDDEN; -extern NTSTATUS macdrv_ime_process_text_input(void *arg) DECLSPEC_HIDDEN; extern NTSTATUS macdrv_ime_get_text_input(void *arg) DECLSPEC_HIDDEN; extern NTSTATUS macdrv_notify_icon(void *arg) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/macdrv_main.c b/dlls/winemac.drv/macdrv_main.c index 9125574e35b..84369284444 100644 --- a/dlls/winemac.drv/macdrv_main.c +++ b/dlls/winemac.drv/macdrv_main.c @@ -605,12 +605,6 @@ NTSTATUS macdrv_client_func(enum macdrv_client_funcs id, const void *params, ULO } -static NTSTATUS macdrv_ime_using_input_method(void *arg) -{ - return macdrv_using_input_method(); -} - - static NTSTATUS macdrv_quit_result(void *arg) { struct quit_result_params *params = arg; @@ -626,9 +620,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = macdrv_dnd_have_format, macdrv_dnd_release, macdrv_dnd_retain, - macdrv_ime_process_text_input, macdrv_ime_get_text_input, - macdrv_ime_using_input_method, macdrv_init, macdrv_notify_icon, macdrv_quit_result, @@ -656,26 +648,6 @@ static NTSTATUS wow64_dnd_get_data(void *arg) return macdrv_dnd_get_data(¶ms); } -static NTSTATUS wow64_ime_process_text_input(void *arg) -{ - struct - { - UINT himc; - UINT vkey; - UINT scan; - UINT repeat; - ULONG key_state; - } *params32 = arg; - struct process_text_input_params params; - - params.himc = params32->himc; - params.vkey = params32->vkey; - params.scan = params32->scan; - params.repeat = params32->repeat; - params.key_state = UlongToPtr(params32->key_state); - return macdrv_ime_process_text_input(¶ms); -} - static NTSTATUS wow64_init(void *arg) { struct @@ -750,9 +722,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = macdrv_dnd_have_format, macdrv_dnd_release, macdrv_dnd_retain, - wow64_ime_process_text_input, macdrv_ime_get_text_input, - macdrv_ime_using_input_method, wow64_init, wow64_notify_icon, macdrv_quit_result, diff --git a/dlls/winemac.drv/unixlib.h b/dlls/winemac.drv/unixlib.h index 1f7840a1546..219d0e3dd46 100644 --- a/dlls/winemac.drv/unixlib.h +++ b/dlls/winemac.drv/unixlib.h @@ -26,9 +26,7 @@ enum macdrv_funcs unix_dnd_have_format, unix_dnd_release, unix_dnd_retain, - unix_ime_process_text_input, unix_ime_get_text_input, - unix_ime_using_input_method, unix_init, unix_notify_icon, unix_quit_result, @@ -60,16 +58,6 @@ struct dnd_have_format_params UINT format; }; -/* macdrv_ime_process_text_input params */ -struct process_text_input_params -{ - UINT himc; - UINT vkey; - UINT scan; - UINT repeat; - const BYTE *key_state; -}; - /* macdrv_init params */ struct localized_string { diff --git a/dlls/winemac.drv/winemac.drv.spec b/dlls/winemac.drv/winemac.drv.spec index aca1c58cf13..27143ab560b 100644 --- a/dlls/winemac.drv/winemac.drv.spec +++ b/dlls/winemac.drv/winemac.drv.spec @@ -2,6 +2,5 @@ @ cdecl wine_notify_icon(long ptr) # IME -@ stdcall ImeProcessKey(long long long ptr) @ stdcall ImeSelect(long long) @ stdcall ImeToAsciiEx(long long ptr ptr long long) From 7c8ca68b683a73e491880f9428f797ecea320af3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 14:33:37 +0200 Subject: [PATCH 1911/2777] win32u: Introduce a new ImeToAsciiEx call through NtUserMessageCall. (cherry picked from commit bfa19f8c7e5a361fa72ca2c68ba47f350641158a) --- dlls/imm32/ime.c | 28 +++++++++++++++++++++++----- dlls/win32u/driver.c | 12 ++++++++++++ dlls/win32u/imm.c | 2 ++ dlls/winex11.drv/ime.c | 8 -------- dlls/winex11.drv/winex11.drv.spec | 1 - dlls/wow64win/user.c | 2 ++ include/ntuser.h | 3 +++ include/wine/gdi_driver.h | 2 ++ 8 files changed, 44 insertions(+), 14 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index eee623a6eb5..db9cdfa9a3b 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -455,12 +455,30 @@ BOOL WINAPI ImeProcessKey( HIMC himc, UINT vkey, LPARAM lparam, BYTE *state ) return ret; } -UINT WINAPI ImeToAsciiEx( UINT vkey, UINT scan_code, BYTE *key_state, TRANSMSGLIST *msgs, UINT state, HIMC himc ) +UINT WINAPI ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGLIST *msgs, UINT flags, HIMC himc ) { - FIXME( "vkey %u, scan_code %u, key_state %p, msgs %p, state %u, himc %p stub!\n", - vkey, scan_code, key_state, msgs, state, himc ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return 0; + struct ime_driver_call_params params = {.himc = himc, .state = state}; + COMPOSITIONSTRING *compstr; + UINT count = 0; + INPUTCONTEXT *ctx; + NTSTATUS status; + + TRACE( "vkey %#x, vsc %#x, state %p, msgs %p, flags %#x, himc %p\n", + vkey, vsc, state, msgs, flags, himc ); + + if (!(ctx = ImmLockIMC( himc ))) return 0; + if (!(compstr = ImmLockIMCC( ctx->hCompStr ))) goto done; + + params.compstr = compstr; + status = NtUserMessageCall( ctx->hWnd, WINE_IME_TO_ASCII_EX, vkey, vsc, ¶ms, + NtUserImeDriverCall, FALSE ); + if (status) WARN( "WINE_IME_TO_ASCII_EX returned status %#lx\n", status ); + + ImmUnlockIMCC( ctx->hCompStr ); + +done: + ImmUnlockIMC( himc ); + return count; } BOOL WINAPI ImeConfigure( HKL hkl, HWND hwnd, DWORD mode, void *data ) diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index e1dd1a1ebcf..5b8cbb56813 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -721,6 +721,11 @@ static UINT nulldrv_ImeProcessKey( HIMC himc, UINT wparam, UINT lparam, const BY return 0; } +static UINT nulldrv_ImeToAsciiEx( UINT vkey, UINT vsc, const BYTE *state, COMPOSITIONSTRING *compstr, HIMC himc ) +{ + return 0; +} + static void nulldrv_NotifyIMEStatus( HWND hwnd, UINT status ) { } @@ -1084,6 +1089,11 @@ static UINT loaderdrv_ImeProcessKey( HIMC himc, UINT wparam, UINT lparam, const return load_driver()->pImeProcessKey( himc, wparam, lparam, state ); } +static UINT loaderdrv_ImeToAsciiEx( UINT vkey, UINT vsc, const BYTE *state, COMPOSITIONSTRING *compstr, HIMC himc ) +{ + return load_driver()->pImeToAsciiEx( vkey, vsc, state, compstr, himc ); +} + static void loaderdrv_NotifyIMEStatus( HWND hwnd, UINT status ) { return load_driver()->pNotifyIMEStatus( hwnd, status ); @@ -1196,6 +1206,7 @@ static const struct user_driver_funcs lazy_load_driver = loaderdrv_UnregisterHotKey, loaderdrv_VkKeyScanEx, loaderdrv_ImeProcessKey, + loaderdrv_ImeToAsciiEx, loaderdrv_NotifyIMEStatus, /* cursor/icon functions */ nulldrv_DestroyCursorIcon, @@ -1277,6 +1288,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version SET_USER_FUNC(UnregisterHotKey); SET_USER_FUNC(VkKeyScanEx); SET_USER_FUNC(ImeProcessKey); + SET_USER_FUNC(ImeToAsciiEx); SET_USER_FUNC(NotifyIMEStatus); SET_USER_FUNC(DestroyCursorIcon); SET_USER_FUNC(SetCursor); diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index b91c3617472..287596e60ef 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -428,6 +428,8 @@ LRESULT ime_driver_call( HWND hwnd, enum wine_ime_call call, WPARAM wparam, LPAR { case WINE_IME_PROCESS_KEY: return user_driver->pImeProcessKey( params->himc, wparam, lparam, params->state ); + case WINE_IME_TO_ASCII_EX: + return user_driver->pImeToAsciiEx( wparam, lparam, params->state, params->compstr, params->himc ); default: ERR( "Unknown IME driver call %#x\n", call ); return 0; diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 348be4f0ad6..b375b7f8e2a 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -514,14 +514,6 @@ BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) return TRUE; } -UINT WINAPI ImeToAsciiEx (UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, - TRANSMSGLIST *lpdwTransKey, UINT fuState, HIMC hIMC) -{ - /* See the comment at the head of this file */ - TRACE("We do no processing via this route\n"); - return 0; -} - /* Interfaces to XIM and other parts of winex11drv */ NTSTATUS x11drv_ime_set_open_status( UINT open ) diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec index 8b286033250..c8d52d07f6d 100644 --- a/dlls/winex11.drv/winex11.drv.spec +++ b/dlls/winex11.drv/winex11.drv.spec @@ -12,4 +12,3 @@ #IME Interface @ stdcall ImeSelect(long long) -@ stdcall ImeToAsciiEx(long long ptr ptr long long) diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index 02c2d9d975e..11ef806929a 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -3133,10 +3133,12 @@ NTSTATUS WINAPI wow64_NtUserMessageCall( UINT *args ) { ULONG himc; ULONG state; + ULONG compstr; } *params32 = result_info; struct ime_driver_call_params params; params.himc = UlongToPtr( params32->himc ); params.state = UlongToPtr( params32->state ); + params.compstr = UlongToPtr( params32->compstr ); return NtUserMessageCall( hwnd, msg, wparam, lparam, ¶ms, type, ansi ); } } diff --git a/include/ntuser.h b/include/ntuser.h index 86c18426701..45082f67dfb 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -22,6 +22,7 @@ #include #include #include +#include #include /* KernelCallbackTable codes, not compatible with Windows */ @@ -495,6 +496,7 @@ enum wine_internal_message enum wine_ime_call { WINE_IME_PROCESS_KEY, + WINE_IME_TO_ASCII_EX, }; /* NtUserImeDriverCall params */ @@ -502,6 +504,7 @@ struct ime_driver_call_params { HIMC himc; const BYTE *state; + COMPOSITIONSTRING *compstr; }; /* internal IME private */ diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 03d164c05b9..e66585384e2 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -23,6 +23,7 @@ #include "winternl.h" #include "ntuser.h" +#include "immdev.h" #include "ddk/d3dkmthk.h" #include "wine/list.h" @@ -288,6 +289,7 @@ struct user_driver_funcs SHORT (*pVkKeyScanEx)(WCHAR, HKL); /* IME functions */ UINT (*pImeProcessKey)(HIMC,UINT,UINT,const BYTE*); + UINT (*pImeToAsciiEx)(UINT,UINT,const BYTE*,COMPOSITIONSTRING*,HIMC); void (*pNotifyIMEStatus)(HWND,UINT); /* cursor/icon functions */ void (*pDestroyCursorIcon)(HCURSOR); From ca7bce1ab9aa4af2ea0b54d3aafca01491d959fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 11 May 2023 08:39:30 +0200 Subject: [PATCH 1912/2777] winemac: Use the ImeToAsciiEx driver entry to retrieve IME result. (cherry picked from commit 54bbdb83e9a99615815e028e7423e5f125dc7754) --- dlls/winemac.drv/event.c | 6 +++-- dlls/winemac.drv/gdi.c | 1 + dlls/winemac.drv/ime.c | 39 ------------------------------- dlls/winemac.drv/macdrv.h | 2 +- dlls/winemac.drv/macdrv_main.c | 2 -- dlls/winemac.drv/unixlib.h | 1 - dlls/winemac.drv/winemac.drv.spec | 1 - 7 files changed, 6 insertions(+), 46 deletions(-) diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c index 6a695f87e58..cc2dc352c32 100644 --- a/dlls/winemac.drv/event.c +++ b/dlls/winemac.drv/event.c @@ -205,10 +205,12 @@ static void macdrv_sent_text_input(const macdrv_event *event) /*********************************************************************** - * macdrv_ime_get_text_input + * ImeToAsciiEx (MACDRV.@) */ -NTSTATUS macdrv_ime_get_text_input(void *arg) +UINT macdrv_ImeToAsciiEx(UINT vkey, UINT vsc, const BYTE *state, COMPOSITIONSTRING *compstr, HIMC himc) { + TRACE_(imm)("vkey %#x, vsc %#x, state %p, compstr %p, himc %p\n", vkey, vsc, state, compstr, himc); + if (ime_update.result_params) { macdrv_client_func(client_func_ime_set_text, ime_update.result_params, ime_update.result_size); diff --git a/dlls/winemac.drv/gdi.c b/dlls/winemac.drv/gdi.c index 059b99a2465..ef19b39cade 100644 --- a/dlls/winemac.drv/gdi.c +++ b/dlls/winemac.drv/gdi.c @@ -303,6 +303,7 @@ static const struct user_driver_funcs macdrv_funcs = .pUpdateLayeredWindow = macdrv_UpdateLayeredWindow, .pVkKeyScanEx = macdrv_VkKeyScanEx, .pImeProcessKey = macdrv_ImeProcessKey, + .pImeToAsciiEx = macdrv_ImeToAsciiEx, .pNotifyIMEStatus = macdrv_NotifyIMEStatus, .pWindowMessage = macdrv_WindowMessage, .pWindowPosChanged = macdrv_WindowPosChanged, diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index 8ce9f4cd1ef..aab93ecc629 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -484,26 +484,6 @@ static void IME_AddToSelected(HIMC hIMC) hSelectedFrom[hSelectedCount - 1] = hIMC; } -static void UpdateDataInDefaultIMEWindow(INPUTCONTEXT *lpIMC, HWND hwnd, BOOL showable) -{ - LPCOMPOSITIONSTRING compstr; - - if (lpIMC->hCompStr) - compstr = ImmLockIMCC(lpIMC->hCompStr); - else - compstr = NULL; - - if (compstr == NULL || compstr->dwCompStrLen == 0) - ShowWindow(hwnd, SW_HIDE); - else if (showable) - ShowWindow(hwnd, SW_SHOWNOACTIVATE); - - RedrawWindow(hwnd, NULL, NULL, RDW_ERASENOW | RDW_INVALIDATE); - - if (compstr != NULL) - ImmUnlockIMCC(lpIMC->hCompStr); -} - BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) { LPINPUTCONTEXT lpIMC; @@ -545,25 +525,6 @@ BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) return TRUE; } -UINT WINAPI ImeToAsciiEx(UINT uVKey, UINT uScanCode, const LPBYTE lpbKeyState, - TRANSMSGLIST *lpdwTransKey, UINT fuState, HIMC hIMC) -{ - LPINPUTCONTEXT lpIMC; - - TRACE("uVKey 0x%04x uScanCode 0x%04x fuState %u hIMC %p\n", uVKey, uScanCode, fuState, hIMC); - - /* trigger the pending client_func_ime_set_text call */ - MACDRV_CALL(ime_get_text_input, NULL); - - if ((lpIMC = LockRealIMC(hIMC))) - { - HWND hwnd = input_context_get_ui_hwnd( lpIMC ); - UpdateDataInDefaultIMEWindow( lpIMC, hwnd, FALSE ); - UnlockRealIMC(hIMC); - } - return 0; -} - static BOOL IME_SetCompositionString(void* hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen, DWORD cursor_pos, BOOL cursor_valid) { LPINPUTCONTEXT lpIMC; diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 86b2e68e11b..1a2bb684583 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -163,6 +163,7 @@ extern BOOL macdrv_RegisterHotKey(HWND hwnd, UINT mod_flags, UINT vkey) DECLSPEC extern void macdrv_UnregisterHotKey(HWND hwnd, UINT modifiers, UINT vkey) DECLSPEC_HIDDEN; extern SHORT macdrv_VkKeyScanEx(WCHAR wChar, HKL hkl) DECLSPEC_HIDDEN; extern UINT macdrv_ImeProcessKey(HIMC himc, UINT wparam, UINT lparam, const BYTE *state) DECLSPEC_HIDDEN; +extern UINT macdrv_ImeToAsciiEx(UINT vkey, UINT vsc, const BYTE *state, COMPOSITIONSTRING *compstr, HIMC himc) DECLSPEC_HIDDEN; extern UINT macdrv_MapVirtualKeyEx(UINT wCode, UINT wMapType, HKL hkl) DECLSPEC_HIDDEN; extern INT macdrv_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState, LPWSTR bufW, int bufW_size, UINT flags, HKL hkl) DECLSPEC_HIDDEN; @@ -278,7 +279,6 @@ extern NTSTATUS macdrv_dnd_get_formats(void *arg) DECLSPEC_HIDDEN; extern NTSTATUS macdrv_dnd_have_format(void *arg) DECLSPEC_HIDDEN; extern NTSTATUS macdrv_dnd_release(void *arg) DECLSPEC_HIDDEN; extern NTSTATUS macdrv_dnd_retain(void *arg) DECLSPEC_HIDDEN; -extern NTSTATUS macdrv_ime_get_text_input(void *arg) DECLSPEC_HIDDEN; extern NTSTATUS macdrv_notify_icon(void *arg) DECLSPEC_HIDDEN; extern NTSTATUS macdrv_client_func(enum macdrv_client_funcs func, const void *params, diff --git a/dlls/winemac.drv/macdrv_main.c b/dlls/winemac.drv/macdrv_main.c index 84369284444..cafd2f13347 100644 --- a/dlls/winemac.drv/macdrv_main.c +++ b/dlls/winemac.drv/macdrv_main.c @@ -620,7 +620,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = macdrv_dnd_have_format, macdrv_dnd_release, macdrv_dnd_retain, - macdrv_ime_get_text_input, macdrv_init, macdrv_notify_icon, macdrv_quit_result, @@ -722,7 +721,6 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = macdrv_dnd_have_format, macdrv_dnd_release, macdrv_dnd_retain, - macdrv_ime_get_text_input, wow64_init, wow64_notify_icon, macdrv_quit_result, diff --git a/dlls/winemac.drv/unixlib.h b/dlls/winemac.drv/unixlib.h index 219d0e3dd46..08c36860dd7 100644 --- a/dlls/winemac.drv/unixlib.h +++ b/dlls/winemac.drv/unixlib.h @@ -26,7 +26,6 @@ enum macdrv_funcs unix_dnd_have_format, unix_dnd_release, unix_dnd_retain, - unix_ime_get_text_input, unix_init, unix_notify_icon, unix_quit_result, diff --git a/dlls/winemac.drv/winemac.drv.spec b/dlls/winemac.drv/winemac.drv.spec index 27143ab560b..68bebc794aa 100644 --- a/dlls/winemac.drv/winemac.drv.spec +++ b/dlls/winemac.drv/winemac.drv.spec @@ -3,4 +3,3 @@ # IME @ stdcall ImeSelect(long long) -@ stdcall ImeToAsciiEx(long long ptr ptr long long) From 0ee19914ed8bb408e3c769398d7e252aea9d0a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 12 May 2023 08:54:55 +0200 Subject: [PATCH 1913/2777] winemac: Compute the required COMPOSITIONSTRING size in ImeToAsciiEx. (cherry picked from commit 3cee423da03383ac7a94e6bf422c676c565300b4) --- dlls/winemac.drv/event.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c index cc2dc352c32..d7e76a5cbc7 100644 --- a/dlls/winemac.drv/event.c +++ b/dlls/winemac.drv/event.c @@ -26,6 +26,8 @@ #include "config.h" +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "macdrv.h" #include "oleidl.h" @@ -34,6 +36,8 @@ WINE_DECLARE_DEBUG_CHANNEL(imm); struct ime_update { + WCHAR *comp_str; + WCHAR *result_str; struct ime_set_text_params *comp_params; DWORD comp_size; struct ime_set_text_params *result_params; @@ -168,7 +172,7 @@ static void macdrv_im_set_text(const macdrv_event *event) if (event->im_set_text.text) length = CFStringGetLength(event->im_set_text.text); - size = offsetof(struct ime_set_text_params, text[length]); + size = offsetof(struct ime_set_text_params, text[length + 1]); if (!(params = malloc(size))) return; params->hwnd = HandleToUlong(hwnd); params->himc = (UINT_PTR)event->im_set_text.himc; @@ -177,20 +181,24 @@ static void macdrv_im_set_text(const macdrv_event *event) if (length) CFStringGetCharacters(event->im_set_text.text, CFRangeMake(0, length), params->text); + params->text[length] = 0; free(ime_update.comp_params); ime_update.comp_params = NULL; + ime_update.comp_str = NULL; if (params->complete) { free(ime_update.result_params); ime_update.result_params = params; ime_update.result_size = size; + ime_update.result_str = params->text; } else { ime_update.comp_params = params; ime_update.comp_size = size; + ime_update.comp_str = params->text; } } @@ -200,7 +208,7 @@ static void macdrv_im_set_text(const macdrv_event *event) static void macdrv_sent_text_input(const macdrv_event *event) { TRACE_(imm)("handled: %s\n", event->sent_text_input.handled ? "TRUE" : "FALSE"); - *event->sent_text_input.done = event->sent_text_input.handled || ime_update.result_params ? 1 : -1; + *event->sent_text_input.done = event->sent_text_input.handled || ime_update.result_str ? 1 : -1; } @@ -209,19 +217,47 @@ static void macdrv_sent_text_input(const macdrv_event *event) */ UINT macdrv_ImeToAsciiEx(UINT vkey, UINT vsc, const BYTE *state, COMPOSITIONSTRING *compstr, HIMC himc) { + UINT needed = sizeof(COMPOSITIONSTRING), comp_len, result_len; + struct ime_update *update = &ime_update; + TRACE_(imm)("vkey %#x, vsc %#x, state %p, compstr %p, himc %p\n", vkey, vsc, state, compstr, himc); + if (!update->comp_str) comp_len = 0; + else + { + comp_len = wcslen(update->comp_str); + needed += comp_len * sizeof(WCHAR); /* GCS_COMPSTR */ + needed += comp_len; /* GCS_COMPATTR */ + needed += 2 * sizeof(DWORD); /* GCS_COMPCLAUSE */ + } + + if (!update->result_str) result_len = 0; + else + { + result_len = wcslen(update->result_str); + needed += result_len * sizeof(WCHAR); /* GCS_RESULTSTR */ + needed += 2 * sizeof(DWORD); /* GCS_RESULTCLAUSE */ + } + if (ime_update.result_params) { macdrv_client_func(client_func_ime_set_text, ime_update.result_params, ime_update.result_size); free(ime_update.result_params); ime_update.result_params = NULL; + ime_update.result_str = NULL; } if (ime_update.comp_params) { macdrv_client_func(client_func_ime_set_text, ime_update.comp_params, ime_update.comp_size); free(ime_update.comp_params); ime_update.comp_params = NULL; + ime_update.comp_str = NULL; + } + + if (compstr->dwSize < needed) + { + compstr->dwSize = needed; + return STATUS_BUFFER_TOO_SMALL; } return 0; From 0f0c5dc7c868516852a25e8d654a5c152502a794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 11 May 2023 08:22:08 +0200 Subject: [PATCH 1914/2777] imm32: Resize the composition string if the driver requested so. (cherry picked from commit 4870a9dfad3527c9eca7ed0ac9481281cbdfc254) --- dlls/imm32/ime.c | 22 +++++++++++++++++----- dlls/imm32/imm_private.h | 2 ++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index db9cdfa9a3b..b544035dbd7 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -457,9 +457,8 @@ BOOL WINAPI ImeProcessKey( HIMC himc, UINT vkey, LPARAM lparam, BYTE *state ) UINT WINAPI ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGLIST *msgs, UINT flags, HIMC himc ) { - struct ime_driver_call_params params = {.himc = himc, .state = state}; COMPOSITIONSTRING *compstr; - UINT count = 0; + UINT size, count = 0; INPUTCONTEXT *ctx; NTSTATUS status; @@ -468,10 +467,23 @@ UINT WINAPI ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGLIST *msgs, if (!(ctx = ImmLockIMC( himc ))) return 0; if (!(compstr = ImmLockIMCC( ctx->hCompStr ))) goto done; + size = compstr->dwSize; + + do + { + struct ime_driver_call_params params = {.himc = himc, .state = state}; + HIMCC himcc; + + ImmUnlockIMCC( ctx->hCompStr ); + if (!(himcc = ImmReSizeIMCC( ctx->hCompStr, size ))) goto done; + if (!(compstr = ImmLockIMCC( (ctx->hCompStr = himcc) ))) goto done; + + params.compstr = compstr; + status = NtUserMessageCall( ctx->hWnd, WINE_IME_TO_ASCII_EX, vkey, vsc, ¶ms, + NtUserImeDriverCall, FALSE ); + size = compstr->dwSize; + } while (status == STATUS_BUFFER_TOO_SMALL); - params.compstr = compstr; - status = NtUserMessageCall( ctx->hWnd, WINE_IME_TO_ASCII_EX, vkey, vsc, ¶ms, - NtUserImeDriverCall, FALSE ); if (status) WARN( "WINE_IME_TO_ASCII_EX returned status %#lx\n", status ); ImmUnlockIMCC( ctx->hCompStr ); diff --git a/dlls/imm32/imm_private.h b/dlls/imm32/imm_private.h index 8a957494ce9..4cc4acda6c1 100644 --- a/dlls/imm32/imm_private.h +++ b/dlls/imm32/imm_private.h @@ -19,6 +19,8 @@ #include #include +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "wingdi.h" From d178979a139c7927fab4eccd31548fb6d15feaea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 11 May 2023 08:47:06 +0200 Subject: [PATCH 1915/2777] winemac: Write the IME strings to the COMPOSITIONSTRING in ImeToAsciiEx. (cherry picked from commit 8c08ffcdec5d5b9a098a14ceb300cffd2c3a3980) --- dlls/winemac.drv/event.c | 58 +++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c index d7e76a5cbc7..a5a0fac8ad4 100644 --- a/dlls/winemac.drv/event.c +++ b/dlls/winemac.drv/event.c @@ -36,6 +36,7 @@ WINE_DECLARE_DEBUG_CHANNEL(imm); struct ime_update { + DWORD cursor_pos; WCHAR *comp_str; WCHAR *result_str; struct ime_set_text_params *comp_params; @@ -199,6 +200,7 @@ static void macdrv_im_set_text(const macdrv_event *event) ime_update.comp_params = params; ime_update.comp_size = size; ime_update.comp_str = params->text; + ime_update.cursor_pos = event->im_set_text.cursor_pos; } } @@ -219,6 +221,7 @@ UINT macdrv_ImeToAsciiEx(UINT vkey, UINT vsc, const BYTE *state, COMPOSITIONSTRI { UINT needed = sizeof(COMPOSITIONSTRING), comp_len, result_len; struct ime_update *update = &ime_update; + void *dst; TRACE_(imm)("vkey %#x, vsc %#x, state %p, compstr %p, himc %p\n", vkey, vsc, state, compstr, himc); @@ -239,6 +242,55 @@ UINT macdrv_ImeToAsciiEx(UINT vkey, UINT vsc, const BYTE *state, COMPOSITIONSTRI needed += 2 * sizeof(DWORD); /* GCS_RESULTCLAUSE */ } + if (compstr->dwSize < needed) + { + compstr->dwSize = needed; + return STATUS_BUFFER_TOO_SMALL; + } + + memset( compstr, 0, sizeof(*compstr) ); + compstr->dwSize = sizeof(*compstr); + + if (update->comp_str) + { + compstr->dwCursorPos = update->cursor_pos; + + compstr->dwCompStrLen = comp_len; + compstr->dwCompStrOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwCompStrOffset; + memcpy(dst, update->comp_str, compstr->dwCompStrLen * sizeof(WCHAR)); + compstr->dwSize += compstr->dwCompStrLen * sizeof(WCHAR); + + compstr->dwCompClauseLen = 2 * sizeof(DWORD); + compstr->dwCompClauseOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwCompClauseOffset; + *((DWORD *)dst + 0) = 0; + *((DWORD *)dst + 1) = compstr->dwCompStrLen; + compstr->dwSize += compstr->dwCompClauseLen; + + compstr->dwCompAttrLen = compstr->dwCompStrLen; + compstr->dwCompAttrOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwCompAttrOffset; + memset(dst, ATTR_INPUT, compstr->dwCompAttrLen); + compstr->dwSize += compstr->dwCompAttrLen; + } + + if (update->result_str) + { + compstr->dwResultStrLen = result_len; + compstr->dwResultStrOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwResultStrOffset; + memcpy(dst, update->result_str, compstr->dwResultStrLen * sizeof(WCHAR)); + compstr->dwSize += compstr->dwResultStrLen * sizeof(WCHAR); + + compstr->dwResultClauseLen = 2 * sizeof(DWORD); + compstr->dwResultClauseOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwResultClauseOffset; + *((DWORD *)dst + 0) = 0; + *((DWORD *)dst + 1) = compstr->dwResultStrLen; + compstr->dwSize += compstr->dwResultClauseLen; + } + if (ime_update.result_params) { macdrv_client_func(client_func_ime_set_text, ime_update.result_params, ime_update.result_size); @@ -254,12 +306,6 @@ UINT macdrv_ImeToAsciiEx(UINT vkey, UINT vsc, const BYTE *state, COMPOSITIONSTRI ime_update.comp_str = NULL; } - if (compstr->dwSize < needed) - { - compstr->dwSize = needed; - return STATUS_BUFFER_TOO_SMALL; - } - return 0; } From f7cea8312f9641456dcefdf9aebf2aac20b6343f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 16 May 2023 15:50:10 +0200 Subject: [PATCH 1916/2777] winemac: Generate IME messages from the default ImeToAsciiEx implementation. (cherry picked from commit 8ae0c308233e61cfc01ef52886077960d6513d93) --- dlls/imm32/ime.c | 38 ++- dlls/winemac.drv/dllmain.c | 1 - dlls/winemac.drv/event.c | 69 +++--- dlls/winemac.drv/ime.c | 433 ---------------------------------- dlls/winemac.drv/macdrv.h | 3 + dlls/winemac.drv/macdrv_dll.h | 1 - dlls/winemac.drv/unixlib.h | 11 - 7 files changed, 62 insertions(+), 494 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index b544035dbd7..c615e3406c9 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -164,13 +164,13 @@ static void ime_send_message( HIMC himc, UINT message, WPARAM wparam, LPARAM lpa ImmGenerateMessage( himc ); } -static void ime_set_composition_status( HIMC himc, BOOL composition ) +static UINT ime_set_composition_status( HIMC himc, BOOL composition ) { struct ime_private *priv; INPUTCONTEXT *ctx; UINT msg = 0; - if (!(ctx = ImmLockIMC( himc ))) return; + if (!(ctx = ImmLockIMC( himc ))) return 0; if ((priv = ImmLockIMCC( ctx->hPrivate ))) { if (!priv->bInComposition && composition) msg = WM_IME_STARTCOMPOSITION; @@ -180,7 +180,7 @@ static void ime_set_composition_status( HIMC himc, BOOL composition ) } ImmUnlockIMC( himc ); - if (msg) ime_send_message( himc, msg, 0, 0 ); + return msg; } static void ime_ui_paint( HIMC himc, HWND hwnd ) @@ -485,10 +485,35 @@ UINT WINAPI ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGLIST *msgs, } while (status == STATUS_BUFFER_TOO_SMALL); if (status) WARN( "WINE_IME_TO_ASCII_EX returned status %#lx\n", status ); + else + { + TRANSMSG status_msg = {.message = ime_set_composition_status( himc, !!compstr->dwCompStrOffset )}; + if (status_msg.message) msgs->TransMsg[count++] = status_msg; + + if (compstr->dwResultStrLen) + { + const WCHAR *result = (WCHAR *)((BYTE *)compstr + compstr->dwResultStrOffset); + TRANSMSG msg = {.message = WM_IME_COMPOSITION, .wParam = result[0], .lParam = GCS_RESULTSTR}; + if (compstr->dwResultClauseOffset) msg.lParam |= GCS_RESULTCLAUSE; + msgs->TransMsg[count++] = msg; + } + + if (compstr->dwCompStrLen) + { + const WCHAR *comp = (WCHAR *)((BYTE *)compstr + compstr->dwCompStrOffset); + TRANSMSG msg = {.message = WM_IME_COMPOSITION, .wParam = comp[0], .lParam = GCS_COMPSTR | GCS_CURSORPOS | GCS_DELTASTART}; + if (compstr->dwCompAttrOffset) msg.lParam |= GCS_COMPATTR; + if (compstr->dwCompClauseOffset) msg.lParam |= GCS_COMPCLAUSE; + else msg.lParam |= CS_INSERTCHAR|CS_NOMOVECARET; + msgs->TransMsg[count++] = msg; + } + } ImmUnlockIMCC( ctx->hCompStr ); done: + if (count >= msgs->uMsgCount) FIXME( "More than %u messages queued, messages possibly lost\n", msgs->uMsgCount ); + else TRACE( "Returning %u messages queued\n", count ); ImmUnlockIMC( himc ); return count; } @@ -524,10 +549,10 @@ BOOL WINAPI ImeSetCompositionString( HIMC himc, DWORD index, const void *comp, D FIXME( "index %#lx not implemented\n", index ); else { - UINT flags = GCS_COMPSTR | GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART | GCS_CURSORPOS; + UINT msg, flags = GCS_COMPSTR | GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART | GCS_CURSORPOS; WCHAR wparam = comp && comp_len >= sizeof(WCHAR) ? *(WCHAR *)comp : 0; input_context_set_comp_str( ctx, comp, comp_len / sizeof(WCHAR) ); - ime_set_composition_status( himc, TRUE ); + if ((msg = ime_set_composition_status( himc, TRUE ))) ime_send_message( himc, msg, 0, 0 ); ime_send_message( himc, WM_IME_COMPOSITION, wparam, flags ); } @@ -540,6 +565,7 @@ BOOL WINAPI NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) { struct ime_private *priv; INPUTCONTEXT *ctx; + UINT msg; TRACE( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc, action, index, value ); @@ -562,7 +588,7 @@ BOOL WINAPI NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) if (!ctx->fOpen) { input_context_set_comp_str( ctx, NULL, 0 ); - ime_set_composition_status( himc, FALSE ); + if ((msg = ime_set_composition_status( himc, TRUE ))) ime_send_message( himc, msg, 0, 0 ); } NtUserNotifyIMEStatus( ctx->hWnd, ctx->fOpen ); break; diff --git a/dlls/winemac.drv/dllmain.c b/dlls/winemac.drv/dllmain.c index 41e9e908b61..265d6e46d5c 100644 --- a/dlls/winemac.drv/dllmain.c +++ b/dlls/winemac.drv/dllmain.c @@ -375,7 +375,6 @@ static const kernel_callback kernel_callbacks[] = macdrv_dnd_query_drop, macdrv_dnd_query_exited, macdrv_ime_query_char_rect, - macdrv_ime_set_text, }; C_ASSERT(NtUserDriverCallbackFirst + ARRAYSIZE(kernel_callbacks) == client_func_last); diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c index a5a0fac8ad4..1565cd9cbdd 100644 --- a/dlls/winemac.drv/event.c +++ b/dlls/winemac.drv/event.c @@ -34,15 +34,22 @@ WINE_DEFAULT_DEBUG_CHANNEL(event); WINE_DECLARE_DEBUG_CHANNEL(imm); +/* IME works synchronously, key input is passed from ImeProcessKey, to the + * host IME. We wait for it to be handled, or not, which is notified using + * the sent_text_input event. Meanwhile, while processing the key, the host + * IME may send one or more im_set_text events to update the input text. + * + * If ImeProcessKey returns TRUE, ImeToAsciiEx is then be called to retrieve + * the composition string updates. We use ime_update.comp_str != NULL as flag that + * composition is started, even if the preedit text is empty. + * + * If ImeProcessKey returns FALSE, ImeToAsciiEx will not be called. + */ struct ime_update { DWORD cursor_pos; WCHAR *comp_str; WCHAR *result_str; - struct ime_set_text_params *comp_params; - DWORD comp_size; - struct ime_set_text_params *result_params; - DWORD result_size; }; static struct ime_update ime_update; @@ -164,42 +171,33 @@ static macdrv_event_mask get_event_mask(DWORD mask) static void macdrv_im_set_text(const macdrv_event *event) { HWND hwnd = macdrv_get_window_hwnd(event->window); - struct ime_set_text_params *params; - CFIndex length = 0, size; + CFIndex length = 0; + WCHAR *text = NULL; TRACE_(imm)("win %p/%p himc %p text %s complete %u\n", hwnd, event->window, event->im_set_text.himc, debugstr_cf(event->im_set_text.text), event->im_set_text.complete); if (event->im_set_text.text) + { length = CFStringGetLength(event->im_set_text.text); + if (!(text = malloc((length + 1) * sizeof(WCHAR)))) return; + if (length) CFStringGetCharacters(event->im_set_text.text, CFRangeMake(0, length), text); + text[length] = 0; + } - size = offsetof(struct ime_set_text_params, text[length + 1]); - if (!(params = malloc(size))) return; - params->hwnd = HandleToUlong(hwnd); - params->himc = (UINT_PTR)event->im_set_text.himc; - params->cursor_pos = event->im_set_text.cursor_pos; - params->complete = event->im_set_text.complete; - - if (length) - CFStringGetCharacters(event->im_set_text.text, CFRangeMake(0, length), params->text); - params->text[length] = 0; - - free(ime_update.comp_params); - ime_update.comp_params = NULL; + /* discard any pending comp text */ + free(ime_update.comp_str); ime_update.comp_str = NULL; + ime_update.cursor_pos = -1; - if (params->complete) + if (event->im_set_text.complete) { - free(ime_update.result_params); - ime_update.result_params = params; - ime_update.result_size = size; - ime_update.result_str = params->text; + free(ime_update.result_str); + ime_update.result_str = text; } else { - ime_update.comp_params = params; - ime_update.comp_size = size; - ime_update.comp_str = params->text; + ime_update.comp_str = text; ime_update.cursor_pos = event->im_set_text.cursor_pos; } } @@ -291,21 +289,8 @@ UINT macdrv_ImeToAsciiEx(UINT vkey, UINT vsc, const BYTE *state, COMPOSITIONSTRI compstr->dwSize += compstr->dwResultClauseLen; } - if (ime_update.result_params) - { - macdrv_client_func(client_func_ime_set_text, ime_update.result_params, ime_update.result_size); - free(ime_update.result_params); - ime_update.result_params = NULL; - ime_update.result_str = NULL; - } - if (ime_update.comp_params) - { - macdrv_client_func(client_func_ime_set_text, ime_update.comp_params, ime_update.comp_size); - free(ime_update.comp_params); - ime_update.comp_params = NULL; - ime_update.comp_str = NULL; - } - + free(update->result_str); + update->result_str = NULL; return 0; } diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index aab93ecc629..87adab88876 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -122,313 +122,6 @@ static BOOL UnlockRealIMC(HIMC hIMC) return FALSE; } -static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset, - LPBYTE target, LPBYTE source, DWORD* lenParam, - DWORD* offsetParam, BOOL wchars) -{ - if (origLen > 0 && origOffset > 0) - { - int truelen = origLen; - if (wchars) - truelen *= sizeof(WCHAR); - - memcpy(&target[currentOffset], &source[origOffset], truelen); - - *lenParam = origLen; - *offsetParam = currentOffset; - currentOffset += truelen; - } - return currentOffset; -} - -static HIMCC updateCompStr(HIMCC old, LPCWSTR compstr, DWORD len, DWORD *flags) -{ - /* We need to make sure the CompStr, CompClause and CompAttr fields are all - * set and correct. */ - int needed_size; - HIMCC rc; - LPBYTE newdata = NULL; - LPBYTE olddata = NULL; - LPCOMPOSITIONSTRING new_one; - LPCOMPOSITIONSTRING lpcs = NULL; - INT current_offset = 0; - - TRACE("%s, %li\n", debugstr_wn(compstr, len), len); - - if (old == NULL && compstr == NULL && len == 0) - return NULL; - - if (compstr == NULL && len != 0) - { - ERR("compstr is NULL however we have a len! Please report\n"); - len = 0; - } - - if (old != NULL) - { - olddata = ImmLockIMCC(old); - lpcs = (LPCOMPOSITIONSTRING)olddata; - } - - needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) + - len + sizeof(DWORD) * 2; - - if (lpcs != NULL) - { - needed_size += lpcs->dwCompReadAttrLen; - needed_size += lpcs->dwCompReadClauseLen; - needed_size += lpcs->dwCompReadStrLen * sizeof(WCHAR); - needed_size += lpcs->dwResultReadClauseLen; - needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR); - needed_size += lpcs->dwResultClauseLen; - needed_size += lpcs->dwResultStrLen * sizeof(WCHAR); - needed_size += lpcs->dwPrivateSize; - } - rc = ImmCreateIMCC(needed_size); - newdata = ImmLockIMCC(rc); - new_one = (LPCOMPOSITIONSTRING)newdata; - - new_one->dwSize = needed_size; - current_offset = sizeof(COMPOSITIONSTRING); - if (lpcs != NULL) - { - current_offset = updateField(lpcs->dwCompReadAttrLen, - lpcs->dwCompReadAttrOffset, - current_offset, newdata, olddata, - &new_one->dwCompReadAttrLen, - &new_one->dwCompReadAttrOffset, FALSE); - - current_offset = updateField(lpcs->dwCompReadClauseLen, - lpcs->dwCompReadClauseOffset, - current_offset, newdata, olddata, - &new_one->dwCompReadClauseLen, - &new_one->dwCompReadClauseOffset, FALSE); - - current_offset = updateField(lpcs->dwCompReadStrLen, - lpcs->dwCompReadStrOffset, - current_offset, newdata, olddata, - &new_one->dwCompReadStrLen, - &new_one->dwCompReadStrOffset, TRUE); - - /* new CompAttr, CompClause, CompStr, dwCursorPos */ - new_one->dwDeltaStart = 0; - new_one->dwCursorPos = lpcs->dwCursorPos; - - current_offset = updateField(lpcs->dwResultReadClauseLen, - lpcs->dwResultReadClauseOffset, - current_offset, newdata, olddata, - &new_one->dwResultReadClauseLen, - &new_one->dwResultReadClauseOffset, FALSE); - - current_offset = updateField(lpcs->dwResultReadStrLen, - lpcs->dwResultReadStrOffset, - current_offset, newdata, olddata, - &new_one->dwResultReadStrLen, - &new_one->dwResultReadStrOffset, TRUE); - - current_offset = updateField(lpcs->dwResultClauseLen, - lpcs->dwResultClauseOffset, - current_offset, newdata, olddata, - &new_one->dwResultClauseLen, - &new_one->dwResultClauseOffset, FALSE); - - current_offset = updateField(lpcs->dwResultStrLen, - lpcs->dwResultStrOffset, - current_offset, newdata, olddata, - &new_one->dwResultStrLen, - &new_one->dwResultStrOffset, TRUE); - - current_offset = updateField(lpcs->dwPrivateSize, - lpcs->dwPrivateOffset, - current_offset, newdata, olddata, - &new_one->dwPrivateSize, - &new_one->dwPrivateOffset, FALSE); - } - else - { - new_one->dwCursorPos = len; - *flags |= GCS_CURSORPOS; - } - - /* set new data */ - /* CompAttr */ - new_one->dwCompAttrLen = len; - if (len > 0) - { - new_one->dwCompAttrOffset = current_offset; - memset(&newdata[current_offset], ATTR_INPUT, len); - current_offset += len; - } - - /* CompClause */ - if (len > 0) - { - new_one->dwCompClauseLen = sizeof(DWORD) * 2; - new_one->dwCompClauseOffset = current_offset; - *(DWORD*)&newdata[current_offset] = 0; - current_offset += sizeof(DWORD); - *(DWORD*)&newdata[current_offset] = len; - current_offset += sizeof(DWORD); - } - else - new_one->dwCompClauseLen = 0; - - /* CompStr */ - new_one->dwCompStrLen = len; - if (len > 0) - { - new_one->dwCompStrOffset = current_offset; - memcpy(&newdata[current_offset], compstr, len * sizeof(WCHAR)); - } - - - ImmUnlockIMCC(rc); - if (lpcs) - ImmUnlockIMCC(old); - - return rc; -} - -static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len) -{ - /* we need to make sure the ResultStr and ResultClause fields are all - * set and correct */ - int needed_size; - HIMCC rc; - LPBYTE newdata = NULL; - LPBYTE olddata = NULL; - LPCOMPOSITIONSTRING new_one; - LPCOMPOSITIONSTRING lpcs = NULL; - INT current_offset = 0; - - TRACE("%s, %li\n", debugstr_wn(resultstr, len), len); - - if (old == NULL && resultstr == NULL && len == 0) - return NULL; - - if (resultstr == NULL && len != 0) - { - ERR("resultstr is NULL however we have a len! Please report\n"); - len = 0; - } - - if (old != NULL) - { - olddata = ImmLockIMCC(old); - lpcs = (LPCOMPOSITIONSTRING)olddata; - } - - needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) + - sizeof(DWORD) * 2; - - if (lpcs != NULL) - { - needed_size += lpcs->dwCompReadAttrLen; - needed_size += lpcs->dwCompReadClauseLen; - needed_size += lpcs->dwCompReadStrLen * sizeof(WCHAR); - needed_size += lpcs->dwCompAttrLen; - needed_size += lpcs->dwCompClauseLen; - needed_size += lpcs->dwCompStrLen * sizeof(WCHAR); - needed_size += lpcs->dwResultReadClauseLen; - needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR); - needed_size += lpcs->dwPrivateSize; - } - rc = ImmCreateIMCC(needed_size); - newdata = ImmLockIMCC(rc); - new_one = (LPCOMPOSITIONSTRING)newdata; - - new_one->dwSize = needed_size; - current_offset = sizeof(COMPOSITIONSTRING); - if (lpcs != NULL) - { - current_offset = updateField(lpcs->dwCompReadAttrLen, - lpcs->dwCompReadAttrOffset, - current_offset, newdata, olddata, - &new_one->dwCompReadAttrLen, - &new_one->dwCompReadAttrOffset, FALSE); - - current_offset = updateField(lpcs->dwCompReadClauseLen, - lpcs->dwCompReadClauseOffset, - current_offset, newdata, olddata, - &new_one->dwCompReadClauseLen, - &new_one->dwCompReadClauseOffset, FALSE); - - current_offset = updateField(lpcs->dwCompReadStrLen, - lpcs->dwCompReadStrOffset, - current_offset, newdata, olddata, - &new_one->dwCompReadStrLen, - &new_one->dwCompReadStrOffset, TRUE); - - current_offset = updateField(lpcs->dwCompAttrLen, - lpcs->dwCompAttrOffset, - current_offset, newdata, olddata, - &new_one->dwCompAttrLen, - &new_one->dwCompAttrOffset, FALSE); - - current_offset = updateField(lpcs->dwCompClauseLen, - lpcs->dwCompClauseOffset, - current_offset, newdata, olddata, - &new_one->dwCompClauseLen, - &new_one->dwCompClauseOffset, FALSE); - - current_offset = updateField(lpcs->dwCompStrLen, - lpcs->dwCompStrOffset, - current_offset, newdata, olddata, - &new_one->dwCompStrLen, - &new_one->dwCompStrOffset, TRUE); - - new_one->dwCursorPos = lpcs->dwCursorPos; - new_one->dwDeltaStart = 0; - - current_offset = updateField(lpcs->dwResultReadClauseLen, - lpcs->dwResultReadClauseOffset, - current_offset, newdata, olddata, - &new_one->dwResultReadClauseLen, - &new_one->dwResultReadClauseOffset, FALSE); - - current_offset = updateField(lpcs->dwResultReadStrLen, - lpcs->dwResultReadStrOffset, - current_offset, newdata, olddata, - &new_one->dwResultReadStrLen, - &new_one->dwResultReadStrOffset, TRUE); - - /* new ResultClause , ResultStr */ - - current_offset = updateField(lpcs->dwPrivateSize, - lpcs->dwPrivateOffset, - current_offset, newdata, olddata, - &new_one->dwPrivateSize, - &new_one->dwPrivateOffset, FALSE); - } - - /* set new data */ - /* ResultClause */ - if (len > 0) - { - new_one->dwResultClauseLen = sizeof(DWORD) * 2; - new_one->dwResultClauseOffset = current_offset; - *(DWORD*)&newdata[current_offset] = 0; - current_offset += sizeof(DWORD); - *(DWORD*)&newdata[current_offset] = len; - current_offset += sizeof(DWORD); - } - else - new_one->dwResultClauseLen = 0; - - /* ResultStr */ - new_one->dwResultStrLen = len; - if (len > 0) - { - new_one->dwResultStrOffset = current_offset; - memcpy(&newdata[current_offset], resultstr, len * sizeof(WCHAR)); - } - ImmUnlockIMCC(rc); - if (lpcs) - ImmUnlockIMCC(old); - - return rc; -} - static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam, LPARAM lParam) { LPINPUTCONTEXT lpIMC; @@ -525,134 +218,8 @@ BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) return TRUE; } -static BOOL IME_SetCompositionString(void* hIMC, DWORD dwIndex, LPCVOID lpComp, DWORD dwCompLen, DWORD cursor_pos, BOOL cursor_valid) -{ - LPINPUTCONTEXT lpIMC; - DWORD flags = 0; - WCHAR wParam = 0; - LPIMEPRIVATE myPrivate; - BOOL sendMessage = TRUE; - - TRACE("(%p, %ld, %p, %ld):\n", hIMC, dwIndex, lpComp, dwCompLen); - - /* - * Explanation: - * this sets the composition string in the imm32.dll level - * of the composition buffer. - * TODO: set the Cocoa window's marked text string and tell text input context - */ - - lpIMC = LockRealIMC(hIMC); - - if (lpIMC == NULL) - return FALSE; - - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - - if (dwIndex == SCS_SETSTR) - { - HIMCC newCompStr; - - if (!myPrivate->bInComposition) - { - GenerateIMEMessage(hIMC, WM_IME_STARTCOMPOSITION, 0, 0); - myPrivate->bInComposition = TRUE; - } - - /* clear existing result */ - newCompStr = updateResultStr(lpIMC->hCompStr, NULL, 0); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - - flags = GCS_COMPSTR; - - if (dwCompLen && lpComp) - { - newCompStr = updateCompStr(lpIMC->hCompStr, (LPCWSTR)lpComp, dwCompLen / sizeof(WCHAR), &flags); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - - wParam = ((const WCHAR*)lpComp)[0]; - flags |= GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART; - - if (cursor_valid) - { - LPCOMPOSITIONSTRING compstr; - compstr = ImmLockIMCC(lpIMC->hCompStr); - compstr->dwCursorPos = cursor_pos; - ImmUnlockIMCC(lpIMC->hCompStr); - flags |= GCS_CURSORPOS; - } - } - else - { - ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0); - sendMessage = FALSE; - } - - } - - if (sendMessage) { - GenerateIMEMessage(hIMC, WM_IME_COMPOSITION, wParam, flags); - ImmUnlockIMCC(lpIMC->hPrivate); - UnlockRealIMC(hIMC); - } - - return TRUE; -} - -static void IME_NotifyComplete(void* hIMC) -{ - ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); -} - /* Interfaces to other parts of the Mac driver */ -/*********************************************************************** - * macdrv_ime_set_text - */ -NTSTATUS WINAPI macdrv_ime_set_text(void *arg, ULONG size) -{ - struct ime_set_text_params *params = arg; - ULONG length = (size - offsetof(struct ime_set_text_params, text)) / sizeof(WCHAR); - void *himc = param_ptr(params->himc); - HWND hwnd = UlongToHandle(params->hwnd); - - if (!himc) himc = RealIMC(FROM_MACDRV); - - if (length) - { - if (himc) - IME_SetCompositionString(himc, SCS_SETSTR, params->text, length * sizeof(WCHAR), - params->cursor_pos, !params->complete); - else - { - RAWINPUT rawinput; - INPUT input; - unsigned int i; - - input.type = INPUT_KEYBOARD; - input.ki.wVk = 0; - input.ki.time = 0; - input.ki.dwExtraInfo = 0; - - for (i = 0; i < length; i++) - { - input.ki.wScan = params->text[i]; - input.ki.dwFlags = KEYEVENTF_UNICODE; - __wine_send_input(hwnd, &input, &rawinput); - - input.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP; - __wine_send_input(hwnd, &input, &rawinput); - } - } - } - - if (params->complete) - IME_NotifyComplete(himc); - return 0; -} - /************************************************************************** * macdrv_ime_query_char_rect */ diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 1a2bb684583..3dedd5e3043 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -28,6 +28,9 @@ #endif #include "macdrv_cocoa.h" + +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "ntgdi.h" diff --git a/dlls/winemac.drv/macdrv_dll.h b/dlls/winemac.drv/macdrv_dll.h index 3a11528eabc..8f13b6b69aa 100644 --- a/dlls/winemac.drv/macdrv_dll.h +++ b/dlls/winemac.drv/macdrv_dll.h @@ -31,7 +31,6 @@ extern NTSTATUS WINAPI macdrv_dnd_query_drag(void *arg, ULONG size) DECLSPEC_HID extern NTSTATUS WINAPI macdrv_dnd_query_drop(void *arg, ULONG size) DECLSPEC_HIDDEN; extern NTSTATUS WINAPI macdrv_dnd_query_exited(void *arg, ULONG size) DECLSPEC_HIDDEN; -extern NTSTATUS WINAPI macdrv_ime_set_text(void *params, ULONG size) DECLSPEC_HIDDEN; extern NTSTATUS WINAPI macdrv_ime_query_char_rect(void *params, ULONG size) DECLSPEC_HIDDEN; extern HMODULE macdrv_module DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/unixlib.h b/dlls/winemac.drv/unixlib.h index 08c36860dd7..337caa6def2 100644 --- a/dlls/winemac.drv/unixlib.h +++ b/dlls/winemac.drv/unixlib.h @@ -92,7 +92,6 @@ enum macdrv_client_funcs client_func_dnd_query_drop, client_func_dnd_query_exited, client_func_ime_query_char_rect, - client_func_ime_set_text, client_func_last }; @@ -168,16 +167,6 @@ struct ime_query_char_rect_params UINT32 length; }; -/* macdrv_ime_set_text params */ -struct ime_set_text_params -{ - UINT32 hwnd; - UINT32 cursor_pos; - UINT32 himc; - UINT32 complete; - WCHAR text[1]; -}; - static inline void *param_ptr(UINT64 param) { return (void *)(UINT_PTR)param; From 21d5b511fdf6af775d01c12b5924a4a025045ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 15:42:44 +0200 Subject: [PATCH 1917/2777] imm32: Update the IME composition window position after drawing. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53860 (cherry picked from commit bbfb15a5e5c20097be0bb882eb2800b77ba5c1b5) --- dlls/imm32/ime.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index c615e3406c9..b31f56f234f 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -186,7 +186,7 @@ static UINT ime_set_composition_status( HIMC himc, BOOL composition ) static void ime_ui_paint( HIMC himc, HWND hwnd ) { PAINTSTRUCT ps; - RECT rect; + RECT rect, new_rect; HDC hdc; HMONITOR monitor; MONITORINFO mon_info; @@ -201,6 +201,7 @@ static void ime_ui_paint( HIMC himc, HWND hwnd ) GetClientRect( hwnd, &rect ); FillRect( hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1) ); + new_rect = rect; if ((str = input_context_get_comp_str( ctx, FALSE, &len ))) { @@ -233,6 +234,7 @@ static void ime_ui_paint( HIMC himc, HWND hwnd ) rect.top = cpt.y; rect.right = rect.left + pt.x; rect.bottom = rect.top + pt.y; + offset.x = offset.y = 0; monitor = MonitorFromPoint( cpt, MONITOR_DEFAULTTOPRIMARY ); } else /* CFS_DEFAULT */ @@ -283,8 +285,7 @@ static void ime_ui_paint( HIMC himc, HWND hwnd ) } } - SetWindowPos( hwnd, HWND_TOPMOST, rect.left, rect.top, rect.right - rect.left, - rect.bottom - rect.top, SWP_NOACTIVATE ); + new_rect = rect; TextOutW( hdc, offset.x, offset.y, str, len ); if (font) SelectObject( hdc, font ); @@ -293,6 +294,10 @@ static void ime_ui_paint( HIMC himc, HWND hwnd ) EndPaint( hwnd, &ps ); ImmUnlockIMC( himc ); + + if (!EqualRect( &rect, &new_rect )) + SetWindowPos( hwnd, HWND_TOPMOST, new_rect.left, new_rect.top, new_rect.right - new_rect.left, + new_rect.bottom - new_rect.top, SWP_NOACTIVATE ); } static void ime_ui_update_window( INPUTCONTEXT *ctx, HWND hwnd ) From fa58369f3b3fada36e2795f4a0792e299e61a496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 15:44:19 +0200 Subject: [PATCH 1918/2777] imm32: Use DrawTextW to wrap IME composition string. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53860 (cherry picked from commit 478ffa8c12d6c2635ff5493b0be40f9eac736376) --- dlls/imm32/ime.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index b31f56f234f..c10db8958f7 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -253,11 +253,10 @@ static void ime_ui_paint( HIMC himc, HWND hwnd ) if (ctx->cfCompForm.dwStyle == CFS_RECT) { - RECT client; - client = ctx->cfCompForm.rcArea; + RECT client = ctx->cfCompForm.rcArea; MapWindowPoints( ctx->hWnd, 0, (POINT *)&client, 2 ); IntersectRect( &rect, &rect, &client ); - /* TODO: Wrap the input if needed */ + DrawTextW( hdc, str, len, &rect, DT_WORDBREAK | DT_CALCRECT ); } if (ctx->cfCompForm.dwStyle == CFS_DEFAULT) @@ -286,7 +285,8 @@ static void ime_ui_paint( HIMC himc, HWND hwnd ) } new_rect = rect; - TextOutW( hdc, offset.x, offset.y, str, len ); + OffsetRect( &rect, offset.x - rect.left, offset.y - rect.top ); + DrawTextW( hdc, str, len, &rect, DT_WORDBREAK ); if (font) SelectObject( hdc, font ); free( str ); From 131f0c935a286f08d2e7123bc0d0d011f0f6af78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 15:12:01 +0200 Subject: [PATCH 1919/2777] user32/edit: Notify IME on position, format_rect and font changes. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53860 (cherry picked from commit 40fddc6233856674c133142f816c2161e52cba9a) --- dlls/user32/edit.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/dlls/user32/edit.c b/dlls/user32/edit.c index aa74d215673..19df11e1a8a 100644 --- a/dlls/user32/edit.c +++ b/dlls/user32/edit.c @@ -1779,6 +1779,20 @@ static LRESULT EDIT_EM_Scroll(EDITSTATE *es, INT action) } +static void EDIT_UpdateImmCompositionWindow(EDITSTATE *es, UINT x, UINT y) +{ + COMPOSITIONFORM form = + { + .dwStyle = CFS_RECT, + .ptCurrentPos = {.x = x, .y = y}, + .rcArea = es->format_rect, + }; + HIMC himc = ImmGetContext(es->hwndSelf); + ImmSetCompositionWindow(himc, &form); + ImmReleaseContext(es->hwndSelf, himc); +} + + /********************************************************************* * * EDIT_SetCaretPos @@ -1794,6 +1808,7 @@ static void EDIT_SetCaretPos(EDITSTATE *es, INT pos, res = EDIT_EM_PosFromChar(es, pos, after_wrap); TRACE("%d - %dx%d\n", pos, (short)LOWORD(res), (short)HIWORD(res)); SetCaretPos((short)LOWORD(res), (short)HIWORD(res)); + EDIT_UpdateImmCompositionWindow(es, (short)LOWORD(res), (short)HIWORD(res)); } } @@ -3841,6 +3856,15 @@ static DWORD get_font_margins(HDC hdc, const TEXTMETRICW *tm, BOOL unicode) return MAKELONG(left, right); } +static void EDIT_UpdateImmCompositionFont(EDITSTATE *es) +{ + LOGFONTW composition_font; + HIMC himc = ImmGetContext(es->hwndSelf); + GetObjectW(es->font, sizeof(LOGFONTW), &composition_font); + ImmSetCompositionFontW(himc, &composition_font); + ImmReleaseContext(es->hwndSelf, himc); +} + /********************************************************************* * * WM_SETFONT @@ -3892,6 +3916,8 @@ static void EDIT_WM_SetFont(EDITSTATE *es, HFONT font, BOOL redraw) es->flags & EF_AFTER_WRAP); NtUserShowCaret( es->hwndSelf ); } + + EDIT_UpdateImmCompositionFont(es); } @@ -4687,6 +4713,7 @@ LRESULT EditWndProc_common( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, B { EDITSTATE *es = (EDITSTATE *)GetWindowLongPtrW( hwnd, 0 ); LRESULT result = 0; + POINT pt; TRACE("hwnd=%p msg=%x (%s) wparam=%Ix lparam=%Ix\n", hwnd, msg, SPY_GetMsgName(msg, hwnd), wParam, lParam); @@ -5198,6 +5225,9 @@ LRESULT EditWndProc_common( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, B /* IME messages to make the edit control IME aware */ case WM_IME_SETCONTEXT: + NtUserGetCaretPos(&pt); + EDIT_UpdateImmCompositionWindow(es, pt.x, pt.y); + EDIT_UpdateImmCompositionFont(es); break; case WM_IME_STARTCOMPOSITION: From 3bb2be7d0181a9da2036631afcb8d5032434306e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 4 May 2023 20:54:44 +0200 Subject: [PATCH 1920/2777] user32/edit: Delegate composition string rendering to the IME UI. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53860 (cherry picked from commit 851c57d47506640f00399933d7411b62891157f3) --- dlls/user32/edit.c | 167 ++++----------------------------------------- 1 file changed, 13 insertions(+), 154 deletions(-) diff --git a/dlls/user32/edit.c b/dlls/user32/edit.c index 19df11e1a8a..73df9d0b330 100644 --- a/dlls/user32/edit.c +++ b/dlls/user32/edit.c @@ -128,9 +128,8 @@ typedef struct /* * IME Data */ - UINT composition_len; /* length of composition, 0 == no composition */ - int composition_start; /* the character position for the composition */ - UINT ime_status; /* IME status flag */ + UINT ime_status; /* IME status flag */ + /* * Uniscribe Data */ @@ -2149,9 +2148,6 @@ static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col { COLORREF BkColor; COLORREF TextColor; - LOGFONTW underline_font; - HFONT hUnderline = 0; - HFONT old_font = 0; INT ret; INT li; INT BkMode; @@ -2163,20 +2159,9 @@ static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col BkColor = GetBkColor(dc); TextColor = GetTextColor(dc); if (rev) { - if (es->composition_len == 0) - { - SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT)); - SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT)); - SetBkMode( dc, OPAQUE); - } - else - { - HFONT current = GetCurrentObject(dc,OBJ_FONT); - GetObjectW(current,sizeof(LOGFONTW),&underline_font); - underline_font.lfUnderline = TRUE; - hUnderline = CreateFontIndirectW(&underline_font); - old_font = SelectObject(dc,hUnderline); - } + SetBkColor(dc, GetSysColor(COLOR_HIGHLIGHT)); + SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetBkMode(dc, OPAQUE); } li = EDIT_EM_LineIndex(es, line); if (es->style & ES_MULTILINE) { @@ -2188,19 +2173,9 @@ static INT EDIT_PaintText(EDITSTATE *es, HDC dc, INT x, INT y, INT line, INT col ret = size.cx; } if (rev) { - if (es->composition_len == 0) - { - SetBkColor(dc, BkColor); - SetTextColor(dc, TextColor); - SetBkMode( dc, BkMode); - } - else - { - if (old_font) - SelectObject(dc,old_font); - if (hUnderline) - DeleteObject(hUnderline); - } + SetBkColor(dc, BkColor); + SetTextColor(dc, TextColor); + SetBkMode(dc, BkMode); } return ret; } @@ -4362,75 +4337,6 @@ static LRESULT EDIT_EM_GetThumb(EDITSTATE *es) * The Following code is to handle inline editing from IMEs */ -static void EDIT_GetCompositionStr(HIMC hIMC, LPARAM CompFlag, EDITSTATE *es) -{ - LONG buflen; - LPWSTR lpCompStr; - LPSTR lpCompStrAttr = NULL; - DWORD dwBufLenAttr; - - buflen = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, NULL, 0); - - if (buflen < 0) - { - return; - } - - lpCompStr = HeapAlloc(GetProcessHeap(),0,buflen); - if (!lpCompStr) - { - ERR("Unable to allocate IME CompositionString\n"); - return; - } - - if (buflen) - ImmGetCompositionStringW(hIMC, GCS_COMPSTR, lpCompStr, buflen); - - if (CompFlag & GCS_COMPATTR) - { - /* - * We do not use the attributes yet. it would tell us what characters - * are in transition and which are converted or decided upon - */ - dwBufLenAttr = ImmGetCompositionStringW(hIMC, GCS_COMPATTR, NULL, 0); - if (dwBufLenAttr) - { - dwBufLenAttr ++; - lpCompStrAttr = HeapAlloc(GetProcessHeap(),0,dwBufLenAttr+1); - if (!lpCompStrAttr) - { - ERR("Unable to allocate IME Attribute String\n"); - HeapFree(GetProcessHeap(),0,lpCompStr); - return; - } - ImmGetCompositionStringW(hIMC,GCS_COMPATTR, lpCompStrAttr, - dwBufLenAttr); - lpCompStrAttr[dwBufLenAttr] = 0; - } - } - - /* check for change in composition start */ - if (es->selection_end < es->composition_start) - es->composition_start = es->selection_end; - - /* replace existing selection string */ - es->selection_start = es->composition_start; - - if (es->composition_len > 0) - es->selection_end = es->composition_start + es->composition_len; - else - es->selection_end = es->selection_start; - - EDIT_EM_ReplaceSel(es, FALSE, lpCompStr, buflen / sizeof(WCHAR), TRUE, TRUE); - es->composition_len = abs(es->composition_start - es->selection_end); - - es->selection_start = es->composition_start; - es->selection_end = es->selection_start + es->composition_len; - - HeapFree(GetProcessHeap(),0,lpCompStrAttr); - HeapFree(GetProcessHeap(),0,lpCompStr); -} - static void EDIT_GetResultStr(HIMC hIMC, EDITSTATE *es) { LONG buflen; @@ -4450,48 +4356,22 @@ static void EDIT_GetResultStr(HIMC hIMC, EDITSTATE *es) } ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, lpResultStr, buflen); - - /* check for change in composition start */ - if (es->selection_end < es->composition_start) - es->composition_start = es->selection_end; - - es->selection_start = es->composition_start; - es->selection_end = es->composition_start + es->composition_len; EDIT_EM_ReplaceSel(es, TRUE, lpResultStr, buflen / sizeof(WCHAR), TRUE, TRUE); - es->composition_start = es->selection_end; - es->composition_len = 0; - HeapFree(GetProcessHeap(),0,lpResultStr); } static void EDIT_ImeComposition(HWND hwnd, LPARAM CompFlag, EDITSTATE *es) { HIMC hIMC; - int cursor; - - if (es->composition_len == 0 && es->selection_start != es->selection_end) - { - EDIT_EM_ReplaceSel(es, TRUE, NULL, 0, TRUE, TRUE); - es->composition_start = es->selection_end; - } hIMC = ImmGetContext(hwnd); if (!hIMC) return; if (CompFlag & GCS_RESULTSTR) - { EDIT_GetResultStr(hIMC, es); - cursor = 0; - } - else - { - if (CompFlag & GCS_COMPSTR) - EDIT_GetCompositionStr(hIMC, CompFlag, es); - cursor = ImmGetCompositionStringW(hIMC, GCS_CURSORPOS, 0, 0); - } + ImmReleaseContext(hwnd, hIMC); - EDIT_SetCaretPos(es, es->selection_start + cursor, es->flags & EF_AFTER_WRAP); } @@ -5230,32 +5110,11 @@ LRESULT EditWndProc_common( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, B EDIT_UpdateImmCompositionFont(es); break; - case WM_IME_STARTCOMPOSITION: - es->composition_start = es->selection_end; - es->composition_len = 0; - break; - case WM_IME_COMPOSITION: - if (lParam & GCS_RESULTSTR && !(es->ime_status & EIMES_GETCOMPSTRATONCE)) - { - DefWindowProcT(hwnd, msg, wParam, lParam, unicode); - break; - } - - EDIT_ImeComposition(hwnd, lParam, es); - break; - - case WM_IME_ENDCOMPOSITION: - if (es->composition_len > 0) - { - EDIT_EM_ReplaceSel(es, TRUE, NULL, 0, TRUE, TRUE); - es->selection_end = es->selection_start; - es->composition_len= 0; - } - break; - - case WM_IME_COMPOSITIONFULL: - break; + EDIT_EM_ReplaceSel(es, TRUE, NULL, 0, TRUE, TRUE); + if ((lParam & GCS_RESULTSTR) && (es->ime_status & EIMES_GETCOMPSTRATONCE)) + EDIT_ImeComposition(hwnd, lParam, es); + return DefWindowProcW(hwnd, msg, wParam, lParam); case WM_IME_SELECT: break; From 45d9ce0828ddd32bd890b6fe384a283209e5b4b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 21:43:58 +0200 Subject: [PATCH 1921/2777] winemac: Return the caret position in query_ime_char_rect. And drop the ime_query_char_rect driver user callback. (cherry picked from commit 6a7c131d0ec87cf1719868be22ff5054573f4c48) --- dlls/winemac.drv/dllmain.c | 1 - dlls/winemac.drv/event.c | 22 +++-- dlls/winemac.drv/ime.c | 147 ---------------------------------- dlls/winemac.drv/macdrv_dll.h | 2 - dlls/winemac.drv/unixlib.h | 19 ----- 5 files changed, 9 insertions(+), 182 deletions(-) diff --git a/dlls/winemac.drv/dllmain.c b/dlls/winemac.drv/dllmain.c index 265d6e46d5c..b20f8d71dc9 100644 --- a/dlls/winemac.drv/dllmain.c +++ b/dlls/winemac.drv/dllmain.c @@ -374,7 +374,6 @@ static const kernel_callback kernel_callbacks[] = macdrv_dnd_query_drag, macdrv_dnd_query_drop, macdrv_dnd_query_exited, - macdrv_ime_query_char_rect, }; C_ASSERT(NtUserDriverCallbackFirst + ARRAYSIZE(kernel_callbacks) == client_func_last); diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c index 1565cd9cbdd..11f5dd3314c 100644 --- a/dlls/winemac.drv/event.c +++ b/dlls/winemac.drv/event.c @@ -401,25 +401,21 @@ BOOL query_ime_char_rect(macdrv_query* query) HWND hwnd = macdrv_get_window_hwnd(query->window); void *himc = query->ime_char_rect.himc; CFRange *range = &query->ime_char_rect.range; - CGRect *rect = &query->ime_char_rect.rect; - struct ime_query_char_rect_result result = { .location = 0 }; - struct ime_query_char_rect_params params; - BOOL ret; + GUITHREADINFO info = {.cbSize = sizeof(info)}; + BOOL ret = FALSE; TRACE_(imm)("win %p/%p himc %p range %ld-%ld\n", hwnd, query->window, himc, range->location, range->length); - params.hwnd = HandleToUlong(hwnd); - params.himc = (UINT_PTR)himc; - params.result = (UINT_PTR)&result; - params.location = range->location; - params.length = range->length; - ret = macdrv_client_func(client_func_ime_query_char_rect, ¶ms, sizeof(params)); - *range = CFRangeMake(result.location, result.length); - *rect = cgrect_from_rect(result.rect); + if (NtUserGetGUIThreadInfo(0, &info)) + { + NtUserMapWindowPoints(info.hwndCaret, 0, (POINT*)&info.rcCaret, 2); + if (range->length && info.rcCaret.left == info.rcCaret.right) info.rcCaret.right++; + query->ime_char_rect.rect = cgrect_from_rect(info.rcCaret); + } TRACE_(imm)(" -> %s range %ld-%ld rect %s\n", ret ? "TRUE" : "FALSE", range->location, - range->length, wine_dbgstr_cgrect(*rect)); + range->length, wine_dbgstr_cgrect(query->ime_char_rect.rect)); return ret; } diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index 87adab88876..ca54c34714c 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -47,47 +47,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm); static HIMC *hSelectedFrom = NULL; static INT hSelectedCount = 0; -static WCHAR *input_context_get_comp_str( INPUTCONTEXT *ctx, BOOL result, UINT *length ) -{ - COMPOSITIONSTRING *string; - WCHAR *text = NULL; - UINT len, off; - - if (!(string = ImmLockIMCC( ctx->hCompStr ))) return NULL; - len = result ? string->dwResultStrLen : string->dwCompStrLen; - off = result ? string->dwResultStrOffset : string->dwCompStrOffset; - - if (len && off && (text = malloc( (len + 1) * sizeof(WCHAR) ))) - { - memcpy( text, (BYTE *)string + off, len * sizeof(WCHAR) ); - text[len] = 0; - *length = len; - } - - ImmUnlockIMCC( ctx->hCompStr ); - return text; -} - -static HWND input_context_get_ui_hwnd( INPUTCONTEXT *ctx ) -{ - struct ime_private *priv; - HWND hwnd; - if (!(priv = ImmLockIMCC( ctx->hPrivate ))) return NULL; - hwnd = priv->hwndDefault; - ImmUnlockIMCC( ctx->hPrivate ); - return hwnd; -} - -static HFONT input_context_select_ui_font( INPUTCONTEXT *ctx, HDC hdc ) -{ - struct ime_private *priv; - HFONT font = NULL; - if (!(priv = ImmLockIMCC( ctx->hPrivate ))) return NULL; - if (priv->textfont) font = SelectObject( hdc, priv->textfont ); - ImmUnlockIMCC( ctx->hPrivate ); - return font; -} - static HIMC RealIMC(HIMC hIMC) { if (hIMC == FROM_MACDRV) @@ -217,109 +176,3 @@ BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) return TRUE; } - -/* Interfaces to other parts of the Mac driver */ - -/************************************************************************** - * macdrv_ime_query_char_rect - */ -NTSTATUS WINAPI macdrv_ime_query_char_rect(void *arg, ULONG size) -{ - struct ime_query_char_rect_params *params = arg; - struct ime_query_char_rect_result *result = param_ptr(params->result); - void *himc = param_ptr(params->himc); - IMECHARPOSITION charpos; - BOOL ret = FALSE; - - result->location = params->location; - result->length = params->length; - - if (!himc) himc = RealIMC(FROM_MACDRV); - - charpos.dwSize = sizeof(charpos); - charpos.dwCharPos = params->location; - if (ImmRequestMessageW(himc, IMR_QUERYCHARPOSITION, (ULONG_PTR)&charpos)) - { - int i; - - SetRect(&result->rect, charpos.pt.x, charpos.pt.y, 0, charpos.pt.y + charpos.cLineHeight); - - /* iterate over rest of length to extend rect */ - for (i = 1; i < params->length; i++) - { - charpos.dwSize = sizeof(charpos); - charpos.dwCharPos = params->location + i; - if (!ImmRequestMessageW(himc, IMR_QUERYCHARPOSITION, (ULONG_PTR)&charpos) || - charpos.pt.y != result->rect.top) - { - result->length = i; - break; - } - - result->rect.right = charpos.pt.x; - } - - ret = TRUE; - } - - if (!ret) - { - LPINPUTCONTEXT ic = ImmLockIMC(himc); - - if (ic) - { - WCHAR *str; - HWND hwnd; - UINT len; - - if ((hwnd = input_context_get_ui_hwnd( ic )) && IsWindowVisible( hwnd ) && - (str = input_context_get_comp_str( ic, FALSE, &len ))) - { - HDC dc = GetDC( hwnd ); - HFONT font = input_context_select_ui_font( ic, dc ); - SIZE size; - - if (result->location > len) result->location = len; - if (result->location + result->length > len) result->length = len - result->location; - - GetTextExtentPoint32W( dc, str, result->location, &size ); - charpos.rcDocument.left = size.cx; - charpos.rcDocument.top = 0; - GetTextExtentPoint32W( dc, str, result->location + result->length, &size ); - charpos.rcDocument.right = size.cx; - charpos.rcDocument.bottom = size.cy; - - if (ic->cfCompForm.dwStyle == CFS_DEFAULT) - OffsetRect(&charpos.rcDocument, 10, 10); - - LPtoDP(dc, (POINT*)&charpos.rcDocument, 2); - MapWindowPoints( hwnd, 0, (POINT *)&charpos.rcDocument, 2 ); - result->rect = charpos.rcDocument; - ret = TRUE; - - if (font) SelectObject( dc, font ); - ReleaseDC( hwnd, dc ); - free( str ); - } - } - - ImmUnlockIMC(himc); - } - - if (!ret) - { - GUITHREADINFO gti; - gti.cbSize = sizeof(gti); - if (GetGUIThreadInfo(0, >i)) - { - MapWindowPoints(gti.hwndCaret, 0, (POINT*)>i.rcCaret, 2); - result->rect = gti.rcCaret; - ret = TRUE; - } - } - - if (ret && result->length && result->rect.left == result->rect.right) - result->rect.right++; - - return ret; -} diff --git a/dlls/winemac.drv/macdrv_dll.h b/dlls/winemac.drv/macdrv_dll.h index 8f13b6b69aa..1bbc7dfc7d6 100644 --- a/dlls/winemac.drv/macdrv_dll.h +++ b/dlls/winemac.drv/macdrv_dll.h @@ -31,8 +31,6 @@ extern NTSTATUS WINAPI macdrv_dnd_query_drag(void *arg, ULONG size) DECLSPEC_HID extern NTSTATUS WINAPI macdrv_dnd_query_drop(void *arg, ULONG size) DECLSPEC_HIDDEN; extern NTSTATUS WINAPI macdrv_dnd_query_exited(void *arg, ULONG size) DECLSPEC_HIDDEN; -extern NTSTATUS WINAPI macdrv_ime_query_char_rect(void *params, ULONG size) DECLSPEC_HIDDEN; - extern HMODULE macdrv_module DECLSPEC_HIDDEN; #endif /* __WINE_MACDRV_DLL_H */ diff --git a/dlls/winemac.drv/unixlib.h b/dlls/winemac.drv/unixlib.h index 337caa6def2..61f4f44fb75 100644 --- a/dlls/winemac.drv/unixlib.h +++ b/dlls/winemac.drv/unixlib.h @@ -91,7 +91,6 @@ enum macdrv_client_funcs client_func_dnd_query_drag, client_func_dnd_query_drop, client_func_dnd_query_exited, - client_func_ime_query_char_rect, client_func_last }; @@ -149,24 +148,6 @@ struct dnd_query_exited_params UINT32 hwnd; }; -/* macdrv_ime_query_char_rect result */ -struct ime_query_char_rect_result -{ - RECT rect; - UINT32 location; - UINT32 length; -}; - -/* macdrv_ime_query_char_rect params */ -struct ime_query_char_rect_params -{ - UINT32 hwnd; - UINT32 location; - UINT32 himc; - UINT64 result; /* FIXME: Use NtCallbackReturn instead */ - UINT32 length; -}; - static inline void *param_ptr(UINT64 param) { return (void *)(UINT_PTR)param; From 2450f98519b6ac50240ed7159ec3921af8612146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 21:54:13 +0200 Subject: [PATCH 1922/2777] winemac: Remove now unnecessary selected HIMC tracking code. (cherry picked from commit 70ff82312e562578d0a98285df12fa32d1a3144f) --- dlls/winemac.drv/ime.c | 92 ++++-------------------------------------- 1 file changed, 7 insertions(+), 85 deletions(-) diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c index ca54c34714c..5564203b78a 100644 --- a/dlls/winemac.drv/ime.c +++ b/dlls/winemac.drv/ime.c @@ -42,51 +42,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm); -#define FROM_MACDRV ((HIMC)0xcafe1337) - -static HIMC *hSelectedFrom = NULL; -static INT hSelectedCount = 0; - -static HIMC RealIMC(HIMC hIMC) -{ - if (hIMC == FROM_MACDRV) - { - INT i; - HWND wnd = GetFocus(); - HIMC winHimc = ImmGetContext(wnd); - for (i = 0; i < hSelectedCount; i++) - if (winHimc == hSelectedFrom[i]) - return winHimc; - return NULL; - } - else - return hIMC; -} - -static LPINPUTCONTEXT LockRealIMC(HIMC hIMC) -{ - HIMC real_imc = RealIMC(hIMC); - if (real_imc) - return ImmLockIMC(real_imc); - else - return NULL; -} - -static BOOL UnlockRealIMC(HIMC hIMC) -{ - HIMC real_imc = RealIMC(hIMC); - if (real_imc) - return ImmUnlockIMC(real_imc); - else - return FALSE; -} - static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam, LPARAM lParam) { LPINPUTCONTEXT lpIMC; LPTRANSMSG lpTransMsg; - lpIMC = LockRealIMC(hIMC); + lpIMC = ImmLockIMC(hIMC); if (lpIMC == NULL) return; @@ -106,34 +67,8 @@ static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam, LPARAM lParam ImmUnlockIMCC(lpIMC->hMsgBuf); lpIMC->dwNumMsgBuf++; - ImmGenerateMessage(RealIMC(hIMC)); - UnlockRealIMC(hIMC); -} - -static BOOL IME_RemoveFromSelected(HIMC hIMC) -{ - int i; - for (i = 0; i < hSelectedCount; i++) - { - if (hSelectedFrom[i] == hIMC) - { - if (i < hSelectedCount - 1) - memmove(&hSelectedFrom[i], &hSelectedFrom[i + 1], (hSelectedCount - i - 1) * sizeof(HIMC)); - hSelectedCount--; - return TRUE; - } - } - return FALSE; -} - -static void IME_AddToSelected(HIMC hIMC) -{ - hSelectedCount++; - if (hSelectedFrom) - hSelectedFrom = HeapReAlloc(GetProcessHeap(), 0, hSelectedFrom, hSelectedCount * sizeof(HIMC)); - else - hSelectedFrom = HeapAlloc(GetProcessHeap(), 0, sizeof(HIMC)); - hSelectedFrom[hSelectedCount - 1] = hIMC; + ImmGenerateMessage(hIMC); + ImmUnlockIMC(hIMC); } BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) @@ -141,23 +76,10 @@ BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) LPINPUTCONTEXT lpIMC; TRACE("%p %s\n", hIMC, fSelect ? "TRUE" : "FALSE"); - if (hIMC == FROM_MACDRV) - { - ERR("ImeSelect should never be called from Cocoa\n"); - return FALSE; - } - - if (!hIMC) - return TRUE; - - /* not selected */ - if (!fSelect) - return IME_RemoveFromSelected(hIMC); - - IME_AddToSelected(hIMC); + if (!hIMC || !fSelect) return TRUE; /* Initialize our structures */ - lpIMC = LockRealIMC(hIMC); + lpIMC = ImmLockIMC(hIMC); if (lpIMC != NULL) { LPIMEPRIVATE myPrivate; @@ -165,13 +87,13 @@ BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) if (myPrivate->bInComposition) GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); if (myPrivate->bInternalState) - ImmSetOpenStatus(RealIMC(FROM_MACDRV), FALSE); + ImmSetOpenStatus( hIMC, FALSE ); myPrivate->bInComposition = FALSE; myPrivate->bInternalState = FALSE; myPrivate->textfont = NULL; myPrivate->hwndDefault = NULL; ImmUnlockIMCC(lpIMC->hPrivate); - UnlockRealIMC(hIMC); + ImmUnlockIMC(hIMC); } return TRUE; From 556f341dda5f9f69ce748ecf442eea9980db9138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 12 May 2023 07:45:40 +0200 Subject: [PATCH 1923/2777] winemac: Use the default IME implementation for ImeSelect. (cherry picked from commit b3fbc16feaf4119be9ce7f20848995fb2388f489) --- dlls/imm32/ime.c | 18 +++++- dlls/winemac.drv/Makefile.in | 1 - dlls/winemac.drv/ime.c | 100 ------------------------------ dlls/winemac.drv/winemac.drv.spec | 3 - 4 files changed, 17 insertions(+), 105 deletions(-) delete mode 100644 dlls/winemac.drv/ime.c diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index c10db8958f7..f5799440709 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -433,7 +433,23 @@ BOOL WINAPI ImeDestroy( UINT force ) BOOL WINAPI ImeSelect( HIMC himc, BOOL select ) { - FIXME( "himc %p, select %d semi-stub!\n", himc, select ); + struct ime_private *priv; + INPUTCONTEXT *ctx; + + TRACE( "himc %p, select %u\n", himc, select ); + + if (!himc || !select) return TRUE; + if (!(ctx = ImmLockIMC( himc ))) return FALSE; + + ImmSetOpenStatus( himc, FALSE ); + + if ((priv = ImmLockIMCC( ctx->hPrivate ))) + { + memset( priv, 0, sizeof(*priv) ); + ImmUnlockIMCC( ctx->hPrivate ); + } + + ImmUnlockIMC( himc ); return TRUE; } diff --git a/dlls/winemac.drv/Makefile.in b/dlls/winemac.drv/Makefile.in index 9735890b221..7228dfbac4f 100644 --- a/dlls/winemac.drv/Makefile.in +++ b/dlls/winemac.drv/Makefile.in @@ -12,7 +12,6 @@ C_SRCS = \ event.c \ gdi.c \ image.c \ - ime.c \ keyboard.c \ macdrv_main.c \ mouse.c \ diff --git a/dlls/winemac.drv/ime.c b/dlls/winemac.drv/ime.c deleted file mode 100644 index 5564203b78a..00000000000 --- a/dlls/winemac.drv/ime.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * The IME for interfacing with Mac input methods - * - * Copyright 2008, 2013 CodeWeavers, Aric Stewart - * Copyright 2013 Ken Thomases for CodeWeavers Inc. - * - * 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 - */ - -/* - * Notes: - * The normal flow for IMM/IME Processing is as follows. - * 1) The Keyboard Driver generates key messages which are first passed to - * the IMM and then to IME via ImeProcessKey. If the IME returns 0 then - * it does not want the key and the keyboard driver then generates the - * WM_KEYUP/WM_KEYDOWN messages. However if the IME is going to process the - * key it returns non-zero. - * 2) If the IME is going to process the key then the IMM calls ImeToAsciiEx to - * process the key. the IME modifies the HIMC structure to reflect the - * current state and generates any messages it needs the IMM to process. - * 3) IMM checks the messages and send them to the application in question. From - * here the IMM level deals with if the application is IME aware or not. - */ - -#include "macdrv_dll.h" -#include "imm.h" -#include "immdev.h" -#include "wine/server.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(imm); - -static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam, LPARAM lParam) -{ - LPINPUTCONTEXT lpIMC; - LPTRANSMSG lpTransMsg; - - lpIMC = ImmLockIMC(hIMC); - if (lpIMC == NULL) - return; - - lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * sizeof(TRANSMSG)); - if (!lpIMC->hMsgBuf) - return; - - lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf); - if (!lpTransMsg) - return; - - lpTransMsg += lpIMC->dwNumMsgBuf; - lpTransMsg->message = msg; - lpTransMsg->wParam = wParam; - lpTransMsg->lParam = lParam; - - ImmUnlockIMCC(lpIMC->hMsgBuf); - lpIMC->dwNumMsgBuf++; - - ImmGenerateMessage(hIMC); - ImmUnlockIMC(hIMC); -} - -BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) -{ - LPINPUTCONTEXT lpIMC; - TRACE("%p %s\n", hIMC, fSelect ? "TRUE" : "FALSE"); - - if (!hIMC || !fSelect) return TRUE; - - /* Initialize our structures */ - lpIMC = ImmLockIMC(hIMC); - if (lpIMC != NULL) - { - LPIMEPRIVATE myPrivate; - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - if (myPrivate->bInComposition) - GenerateIMEMessage(hIMC, WM_IME_ENDCOMPOSITION, 0, 0); - if (myPrivate->bInternalState) - ImmSetOpenStatus( hIMC, FALSE ); - myPrivate->bInComposition = FALSE; - myPrivate->bInternalState = FALSE; - myPrivate->textfont = NULL; - myPrivate->hwndDefault = NULL; - ImmUnlockIMCC(lpIMC->hPrivate); - ImmUnlockIMC(hIMC); - } - - return TRUE; -} diff --git a/dlls/winemac.drv/winemac.drv.spec b/dlls/winemac.drv/winemac.drv.spec index 68bebc794aa..5f086f5c4e5 100644 --- a/dlls/winemac.drv/winemac.drv.spec +++ b/dlls/winemac.drv/winemac.drv.spec @@ -1,5 +1,2 @@ # System tray @ cdecl wine_notify_icon(long ptr) - -# IME -@ stdcall ImeSelect(long long) From 0b66ed2321ba383c3d50728a73660d985226401a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 5 May 2023 09:15:23 +0200 Subject: [PATCH 1924/2777] winex11: Use ime_comp_buf != NULL instead of ximInComposeMode. (cherry picked from commit e70b1b722aebf22f52b90f9f00e9ea37935de752) --- dlls/winex11.drv/event.c | 4 +--- dlls/winex11.drv/x11drv.h | 2 +- dlls/winex11.drv/xim.c | 12 ++++++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 2aaf8e482db..adcf286546d 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -49,8 +49,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(event); WINE_DECLARE_DEBUG_CHANNEL(xdnd); -extern BOOL ximInComposeMode; - #define DndNotDnd -1 /* OffiX drag&drop */ #define DndUnknown 0 #define DndRawData 1 @@ -887,7 +885,7 @@ static void focus_out( Display *display , HWND hwnd ) XIC xic; struct x11drv_win_data *data; - if (ximInComposeMode) return; + if (xim_in_compose_mode()) return; data = get_win_data(hwnd); if(data){ diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 3bfe28f39a4..8d3f75a2a2e 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -439,7 +439,6 @@ extern BOOL clipping_cursor DECLSPEC_HIDDEN; extern unsigned int screen_bpp DECLSPEC_HIDDEN; extern BOOL usexrandr DECLSPEC_HIDDEN; extern BOOL usexvidmode DECLSPEC_HIDDEN; -extern BOOL ximInComposeMode DECLSPEC_HIDDEN; extern BOOL use_take_focus DECLSPEC_HIDDEN; extern BOOL use_primary_selection DECLSPEC_HIDDEN; extern BOOL use_system_cursors DECLSPEC_HIDDEN; @@ -878,6 +877,7 @@ extern struct x11drv_display_device_handler desktop_handler DECLSPEC_HIDDEN; /* XIM support */ extern BOOL xim_init( const WCHAR *input_style ) DECLSPEC_HIDDEN; extern void xim_thread_attach( struct x11drv_thread_data *data ) DECLSPEC_HIDDEN; +extern BOOL xim_in_compose_mode(void) DECLSPEC_HIDDEN; extern void X11DRV_XIMLookupChars( const char *str, UINT count ) DECLSPEC_HIDDEN; extern XIC X11DRV_get_ic( HWND hwnd ) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index b7ab69029b9..9f7efd78f84 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -42,8 +42,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(xim); #define XICProc XIMProc #endif -BOOL ximInComposeMode=FALSE; - static WCHAR *ime_comp_buf; static XIMStyle input_style = 0; @@ -69,6 +67,11 @@ static const char *debugstr_xim_style( XIMStyle style ) return wine_dbg_sprintf( "%s", buffer ); } +BOOL xim_in_compose_mode(void) +{ + return !!ime_comp_buf; +} + static void xim_update_comp_string( UINT offset, UINT old_len, const WCHAR *text, UINT new_len ) { UINT len = ime_comp_buf ? wcslen( ime_comp_buf ) : 0; @@ -138,7 +141,9 @@ static int xic_preedit_start( XIC xic, XPointer user, XPointer arg ) TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg ); x11drv_client_call( client_ime_set_composition_status, TRUE ); - ximInComposeMode = TRUE; + if ((ime_comp_buf = realloc( ime_comp_buf, sizeof(WCHAR) ))) *ime_comp_buf = 0; + else ERR( "Failed to allocate preedit buffer\n" ); + return -1; } @@ -148,7 +153,6 @@ static int xic_preedit_done( XIC xic, XPointer user, XPointer arg ) TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg ); - ximInComposeMode = FALSE; free( ime_comp_buf ); ime_comp_buf = NULL; From 14f13ad6c5b291c4248e6da698c8fb1ea6916b4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 7 May 2023 22:16:08 +0200 Subject: [PATCH 1925/2777] winex11: Keep track of the cursor position on the XIM side. The caret callback is rarely used and XIM also doesn't support changing the preedit string, so we cannot support composition string updates from the PE side either. Requesting only the cursor position, is then likely not useful. (cherry picked from commit 5d0526d29847325de24c99b75d833fe393acfbef) --- dlls/winex11.drv/dllmain.c | 1 - dlls/winex11.drv/ime.c | 20 -------------------- dlls/winex11.drv/unixlib.h | 1 - dlls/winex11.drv/x11drv_dll.h | 1 - dlls/winex11.drv/xim.c | 5 +++-- 5 files changed, 3 insertions(+), 25 deletions(-) diff --git a/dlls/winex11.drv/dllmain.c b/dlls/winex11.drv/dllmain.c index 500a4a6bc44..858c8dc4ee4 100644 --- a/dlls/winex11.drv/dllmain.c +++ b/dlls/winex11.drv/dllmain.c @@ -30,7 +30,6 @@ static const callback_func callback_funcs[] = { x11drv_dnd_drop_event, x11drv_dnd_leave_event, - x11drv_ime_get_cursor_pos, x11drv_ime_set_composition_status, x11drv_ime_set_cursor_pos, x11drv_ime_set_open_status, diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index b375b7f8e2a..37e84ec4f6b 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -550,26 +550,6 @@ NTSTATUS x11drv_ime_set_composition_status( UINT open ) return 0; } -NTSTATUS x11drv_ime_get_cursor_pos( UINT arg ) -{ - LPINPUTCONTEXT lpIMC; - INT rc = 0; - LPCOMPOSITIONSTRING compstr; - - if (!hSelectedFrom) - return rc; - - lpIMC = LockRealIMC(FROM_X11); - if (lpIMC) - { - compstr = ImmLockIMCC(lpIMC->hCompStr); - rc = compstr->dwCursorPos; - ImmUnlockIMCC(lpIMC->hCompStr); - } - UnlockRealIMC(FROM_X11); - return rc; -} - NTSTATUS x11drv_ime_set_cursor_pos( UINT pos ) { LPINPUTCONTEXT lpIMC; diff --git a/dlls/winex11.drv/unixlib.h b/dlls/winex11.drv/unixlib.h index 20279bdb2ac..8cd35583f5d 100644 --- a/dlls/winex11.drv/unixlib.h +++ b/dlls/winex11.drv/unixlib.h @@ -94,7 +94,6 @@ enum client_callback { client_dnd_drop_event, client_dnd_leave_event, - client_ime_get_cursor_pos, client_ime_set_composition_status, client_ime_set_cursor_pos, client_ime_set_open_status, diff --git a/dlls/winex11.drv/x11drv_dll.h b/dlls/winex11.drv/x11drv_dll.h index 047bb430d39..6740609f9ab 100644 --- a/dlls/winex11.drv/x11drv_dll.h +++ b/dlls/winex11.drv/x11drv_dll.h @@ -36,7 +36,6 @@ extern NTSTATUS WINAPI x11drv_systray_change_owner( void *params, ULONG size ) D extern NTSTATUS x11drv_dnd_drop_event( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_dnd_leave_event( UINT arg ) DECLSPEC_HIDDEN; -extern NTSTATUS x11drv_ime_get_cursor_pos( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_ime_set_composition_status( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_ime_set_cursor_pos( UINT pos ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_ime_set_open_status( UINT open ) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 9f7efd78f84..2f3886f1095 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -201,6 +201,7 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) static int xic_preedit_caret( XIC xic, XPointer user, XPointer arg ) { + static int xim_caret_pos; XIMPreeditCaretCallbackStruct *params = (void *)arg; HWND hwnd = (HWND)user; int pos; @@ -209,7 +210,7 @@ static int xic_preedit_caret( XIC xic, XPointer user, XPointer arg ) if (!params) return 0; - pos = x11drv_client_call( client_ime_get_cursor_pos, 0 ); + pos = xim_caret_pos; switch (params->direction) { case XIMForwardChar: @@ -238,7 +239,7 @@ static int xic_preedit_caret( XIC xic, XPointer user, XPointer arg ) break; } x11drv_client_call( client_ime_set_cursor_pos, pos ); - params->position = pos; + params->position = xim_caret_pos = pos; return 0; } From f24ae7a323c0ea45831fdfd50f409cd076dc4eb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 1 Apr 2023 11:56:58 +0200 Subject: [PATCH 1926/2777] winex11: Send an internal WM_IME_NOTIFY wparam to set open status. (cherry picked from commit 4e92c5722160fc17fbb8aedf0e7560d64179339a) --- dlls/imm32/ime.c | 19 ++++++++++++++++--- dlls/winex11.drv/dllmain.c | 1 - dlls/winex11.drv/ime.c | 9 --------- dlls/winex11.drv/unixlib.h | 1 - dlls/winex11.drv/x11drv_dll.h | 1 - dlls/winex11.drv/xim.c | 6 ++---- include/ntuser.h | 3 +++ 7 files changed, 21 insertions(+), 19 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index f5799440709..46f12ef6f45 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -40,6 +40,7 @@ static const char *debugstr_imn( WPARAM wparam ) case IMN_SETCOMPOSITIONWINDOW: return "IMN_SETCOMPOSITIONWINDOW"; case IMN_GUIDELINE: return "IMN_GUIDELINE"; case IMN_SETSTATUSWINDOWPOS: return "IMN_SETSTATUSWINDOWPOS"; + case IMN_WINE_SET_OPEN_STATUS: return "IMN_WINE_SET_OPEN_STATUS"; default: return wine_dbg_sprintf( "%#Ix", wparam ); } } @@ -337,6 +338,20 @@ static void ime_ui_start_composition( HIMC himc, HWND hwnd ) ImmUnlockIMC( himc ); } +static LRESULT ime_ui_notify( HIMC himc, HWND hwnd, WPARAM wparam, LPARAM lparam ) +{ + TRACE( "himc %p, hwnd %p, wparam %s, lparam %#Ix\n", hwnd, himc, debugstr_imn(wparam), lparam ); + + switch (wparam) + { + case IMN_WINE_SET_OPEN_STATUS: + return ImmSetOpenStatus( himc, lparam ); + default: + FIXME( "himc %p, hwnd %p, wparam %s, lparam %#Ix stub!\n", hwnd, himc, debugstr_imn(wparam), lparam ); + return 0; + } +} + static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { HIMC himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ); @@ -379,9 +394,7 @@ static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LP ShowWindow( hwnd, SW_HIDE ); break; case WM_IME_NOTIFY: - FIXME( "hwnd %p, himc %p, msg %s, wparam %s, lparam %#Ix stub!\n", hwnd, himc, - debugstr_wm_ime(msg), debugstr_imn(wparam), lparam ); - return 0; + return ime_ui_notify( himc, hwnd, wparam, lparam ); case WM_IME_CONTROL: FIXME( "hwnd %p, himc %p, msg %s, wparam %s, lparam %#Ix stub!\n", hwnd, himc, debugstr_wm_ime(msg), debugstr_imc(wparam), lparam ); diff --git a/dlls/winex11.drv/dllmain.c b/dlls/winex11.drv/dllmain.c index 858c8dc4ee4..a3375e60957 100644 --- a/dlls/winex11.drv/dllmain.c +++ b/dlls/winex11.drv/dllmain.c @@ -32,7 +32,6 @@ static const callback_func callback_funcs[] = x11drv_dnd_leave_event, x11drv_ime_set_composition_status, x11drv_ime_set_cursor_pos, - x11drv_ime_set_open_status, x11drv_ime_update_association, }; diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 37e84ec4f6b..11832996084 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -516,15 +516,6 @@ BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) /* Interfaces to XIM and other parts of winex11drv */ -NTSTATUS x11drv_ime_set_open_status( UINT open ) -{ - HIMC imc; - - imc = RealIMC(FROM_X11); - ImmSetOpenStatus(imc, open); - return 0; -} - NTSTATUS x11drv_ime_set_composition_status( UINT open ) { HIMC imc; diff --git a/dlls/winex11.drv/unixlib.h b/dlls/winex11.drv/unixlib.h index 8cd35583f5d..ef965381479 100644 --- a/dlls/winex11.drv/unixlib.h +++ b/dlls/winex11.drv/unixlib.h @@ -96,7 +96,6 @@ enum client_callback client_dnd_leave_event, client_ime_set_composition_status, client_ime_set_cursor_pos, - client_ime_set_open_status, client_ime_update_association, client_funcs_count }; diff --git a/dlls/winex11.drv/x11drv_dll.h b/dlls/winex11.drv/x11drv_dll.h index 6740609f9ab..2cc27abd362 100644 --- a/dlls/winex11.drv/x11drv_dll.h +++ b/dlls/winex11.drv/x11drv_dll.h @@ -38,7 +38,6 @@ extern NTSTATUS x11drv_dnd_drop_event( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_dnd_leave_event( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_ime_set_composition_status( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_ime_set_cursor_pos( UINT pos ) DECLSPEC_HIDDEN; -extern NTSTATUS x11drv_ime_set_open_status( UINT open ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_ime_update_association( UINT arg ) DECLSPEC_HIDDEN; extern LRESULT WINAPI foreign_window_proc( HWND hwnd, UINT msg, WPARAM wparam, diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 2f3886f1095..0d12b155da4 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -122,12 +122,10 @@ static BOOL xic_preedit_state_notify( XIC xic, XPointer user, XPointer arg ) switch (state) { case XIMPreeditEnable: - x11drv_client_call( client_ime_set_open_status, TRUE ); + send_message( hwnd, WM_IME_NOTIFY, IMN_WINE_SET_OPEN_STATUS, TRUE ); break; case XIMPreeditDisable: - x11drv_client_call( client_ime_set_open_status, FALSE ); - break; - default: + send_message( hwnd, WM_IME_NOTIFY, IMN_WINE_SET_OPEN_STATUS, FALSE ); break; } diff --git a/include/ntuser.h b/include/ntuser.h index 45082f67dfb..c8a3133a36a 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -492,6 +492,9 @@ enum wine_internal_message #define IME_INTERNAL_HKL_ACTIVATE 0x19 #define IME_INTERNAL_HKL_DEACTIVATE 0x20 +/* internal WM_IME_NOTIFY wparams, not compatible with Windows */ +#define IMN_WINE_SET_OPEN_STATUS 0x000f + /* builtin IME driver calls */ enum wine_ime_call { From f075bb0e6182592b5da3ed1d04cbdbfad7d66200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 19 May 2023 10:29:22 +0200 Subject: [PATCH 1927/2777] winex11: Set or clear XIC focus using a xim_set_focus helper. (cherry picked from commit ecd8c9310ff9e6fd15ee9e174729655766d5218a) --- dlls/winex11.drv/event.c | 7 +++---- dlls/winex11.drv/x11drv.h | 1 + dlls/winex11.drv/xim.c | 10 ++++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index adcf286546d..e760986807c 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -816,7 +816,6 @@ static const char * const focus_modes[] = static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) { XFocusChangeEvent *event = &xev->xfocus; - XIC xic; if (!hwnd) return FALSE; @@ -853,7 +852,8 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; - if ((xic = X11DRV_get_ic( hwnd ))) XSetICFocus( xic ); + xim_set_focus( hwnd, TRUE ); + if (use_take_focus) { if (hwnd == NtUserGetForegroundWindow()) clip_fullscreen_window( hwnd, FALSE ); @@ -882,7 +882,6 @@ static void focus_out( Display *display , HWND hwnd ) HWND hwnd_tmp; Window focus_win; int revert; - XIC xic; struct x11drv_win_data *data; if (xim_in_compose_mode()) return; @@ -908,7 +907,7 @@ static void focus_out( Display *display , HWND hwnd ) } x11drv_thread_data()->last_focus = hwnd; - if ((xic = X11DRV_get_ic( hwnd ))) XUnsetICFocus( xic ); + xim_set_focus( hwnd, FALSE ); if (is_virtual_desktop()) { diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 8d3f75a2a2e..5d208bdce39 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -880,6 +880,7 @@ extern void xim_thread_attach( struct x11drv_thread_data *data ) DECLSPEC_HIDDEN extern BOOL xim_in_compose_mode(void) DECLSPEC_HIDDEN; extern void X11DRV_XIMLookupChars( const char *str, UINT count ) DECLSPEC_HIDDEN; extern XIC X11DRV_get_ic( HWND hwnd ) DECLSPEC_HIDDEN; +extern void xim_set_focus( HWND hwnd, BOOL focus ) DECLSPEC_HIDDEN; #define XEMBED_MAPPED (1 << 0) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 0d12b155da4..760bbae42d8 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -471,3 +471,13 @@ XIC X11DRV_get_ic( HWND hwnd ) return ret; } + +void xim_set_focus( HWND hwnd, BOOL focus ) +{ + XIC xic; + + if (!(xic = X11DRV_get_ic( hwnd ))) return; + + if (focus) XSetICFocus( xic ); + else XUnsetICFocus( xic ); +} From 97022d691edd597f853d0fd73d11e146d69e2b5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 14:29:18 +0200 Subject: [PATCH 1928/2777] winex11: Post internal WM_IME_NOTIFY wparam on composition updates. (cherry picked from commit 9b4c09d8c43de61a5cf9e1918cc4d6373aa971f0) --- dlls/imm32/ime.c | 25 +++++++++++++ dlls/winex11.drv/init.c | 1 + dlls/winex11.drv/keyboard.c | 2 +- dlls/winex11.drv/x11drv.h | 4 +- dlls/winex11.drv/xim.c | 75 ++++++++++++++++++++++++++++++++++++- include/ntuser.h | 1 + 6 files changed, 104 insertions(+), 4 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 46f12ef6f45..35e94404b99 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -41,6 +41,7 @@ static const char *debugstr_imn( WPARAM wparam ) case IMN_GUIDELINE: return "IMN_GUIDELINE"; case IMN_SETSTATUSWINDOWPOS: return "IMN_SETSTATUSWINDOWPOS"; case IMN_WINE_SET_OPEN_STATUS: return "IMN_WINE_SET_OPEN_STATUS"; + case IMN_WINE_SET_COMP_STRING: return "IMN_WINE_SET_COMP_STRING"; default: return wine_dbg_sprintf( "%#Ix", wparam ); } } @@ -338,6 +339,28 @@ static void ime_ui_start_composition( HIMC himc, HWND hwnd ) ImmUnlockIMC( himc ); } +static UINT ime_set_comp_string( HIMC himc, LPARAM lparam ) +{ + union + { + struct + { + UINT uMsgCount; + TRANSMSG TransMsg[10]; + }; + TRANSMSGLIST list; + } buffer = {.uMsgCount = ARRAY_SIZE(buffer.TransMsg)}; + UINT count; + + TRACE( "himc %p\n", himc ); + + count = ImeToAsciiEx( VK_PROCESSKEY, lparam, NULL, &buffer.list, 0, himc ); + if (count >= buffer.uMsgCount) + WARN( "ImeToAsciiEx returned %#x messages\n", count ); + + return count; +} + static LRESULT ime_ui_notify( HIMC himc, HWND hwnd, WPARAM wparam, LPARAM lparam ) { TRACE( "himc %p, hwnd %p, wparam %s, lparam %#Ix\n", hwnd, himc, debugstr_imn(wparam), lparam ); @@ -346,6 +369,8 @@ static LRESULT ime_ui_notify( HIMC himc, HWND hwnd, WPARAM wparam, LPARAM lparam { case IMN_WINE_SET_OPEN_STATUS: return ImmSetOpenStatus( himc, lparam ); + case IMN_WINE_SET_COMP_STRING: + return ime_set_comp_string( himc, lparam ); default: FIXME( "himc %p, hwnd %p, wparam %s, lparam %#Ix stub!\n", hwnd, himc, debugstr_imn(wparam), lparam ); return 0; diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index bc4627d0b1c..fb879c9b483 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -400,6 +400,7 @@ static const struct user_driver_funcs x11drv_funcs = .pMapVirtualKeyEx = X11DRV_MapVirtualKeyEx, .pToUnicodeEx = X11DRV_ToUnicodeEx, .pVkKeyScanEx = X11DRV_VkKeyScanEx, + .pImeToAsciiEx = X11DRV_ImeToAsciiEx, .pNotifyIMEStatus = X11DRV_NotifyIMEStatus, .pDestroyCursorIcon = X11DRV_DestroyCursorIcon, .pSetCursor = X11DRV_SetCursor, diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 8a0a22c452d..c099c3a2727 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1348,7 +1348,7 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) if (status == XLookupChars) { - X11DRV_XIMLookupChars( Str, ascii_chars ); + xim_set_result_string( hwnd, Str, ascii_chars ); if (buf != Str) free( Str ); return TRUE; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 5d208bdce39..6567eb91b2e 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -210,6 +210,8 @@ extern INT X11DRV_GetKeyNameText( LONG lparam, LPWSTR buffer, INT size ) DECLSPE extern UINT X11DRV_MapVirtualKeyEx( UINT code, UINT map_type, HKL hkl ) DECLSPEC_HIDDEN; extern INT X11DRV_ToUnicodeEx( UINT virtKey, UINT scanCode, const BYTE *lpKeyState, LPWSTR bufW, int bufW_size, UINT flags, HKL hkl ) DECLSPEC_HIDDEN; +extern UINT X11DRV_ImeToAsciiEx( UINT vkey, UINT vsc, const BYTE *state, + COMPOSITIONSTRING *compstr, HIMC himc ) DECLSPEC_HIDDEN; extern SHORT X11DRV_VkKeyScanEx( WCHAR wChar, HKL hkl ) DECLSPEC_HIDDEN; extern void X11DRV_NotifyIMEStatus( HWND hwnd, UINT status ) DECLSPEC_HIDDEN; extern void X11DRV_DestroyCursorIcon( HCURSOR handle ) DECLSPEC_HIDDEN; @@ -878,7 +880,7 @@ extern struct x11drv_display_device_handler desktop_handler DECLSPEC_HIDDEN; extern BOOL xim_init( const WCHAR *input_style ) DECLSPEC_HIDDEN; extern void xim_thread_attach( struct x11drv_thread_data *data ) DECLSPEC_HIDDEN; extern BOOL xim_in_compose_mode(void) DECLSPEC_HIDDEN; -extern void X11DRV_XIMLookupChars( const char *str, UINT count ) DECLSPEC_HIDDEN; +extern void xim_set_result_string( HWND hwnd, const char *str, UINT count ) DECLSPEC_HIDDEN; extern XIC X11DRV_get_ic( HWND hwnd ) DECLSPEC_HIDDEN; extern void xim_set_focus( HWND hwnd, BOOL focus ) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 760bbae42d8..1dde1fc936c 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -27,6 +27,8 @@ #include #include +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "winnls.h" @@ -42,6 +44,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(xim); #define XICProc XIMProc #endif +struct ime_update +{ + struct list entry; + DWORD id; +}; + +static pthread_mutex_t ime_mutex = PTHREAD_MUTEX_INITIALIZER; +static struct list ime_updates = LIST_INIT(ime_updates); +static DWORD ime_update_count; static WCHAR *ime_comp_buf; static XIMStyle input_style = 0; @@ -72,6 +83,21 @@ BOOL xim_in_compose_mode(void) return !!ime_comp_buf; } +static void post_ime_update( HWND hwnd ) +{ + UINT id; + struct ime_update *update; + + if (!(update = malloc( sizeof(struct ime_update) ))) return; + + pthread_mutex_lock( &ime_mutex ); + id = update->id = ++ime_update_count; + list_add_tail( &ime_updates, &update->entry ); + pthread_mutex_unlock( &ime_mutex ); + + NtUserPostMessage( hwnd, WM_IME_NOTIFY, IMN_WINE_SET_COMP_STRING, id ); +} + static void xim_update_comp_string( UINT offset, UINT old_len, const WCHAR *text, UINT new_len ) { UINT len = ime_comp_buf ? wcslen( ime_comp_buf ) : 0; @@ -96,18 +122,20 @@ static void xim_update_comp_string( UINT offset, UINT old_len, const WCHAR *text x11drv_client_func( client_func_ime_set_composition_string, ime_comp_buf, len * sizeof(WCHAR) ); } -void X11DRV_XIMLookupChars( const char *str, UINT count ) +void xim_set_result_string( HWND hwnd, const char *str, UINT count ) { WCHAR *output; DWORD len; - TRACE("%p %u\n", str, count); + TRACE( "hwnd %p, string %s\n", hwnd, debugstr_an(str, count) ); if (!(output = malloc( (count + 1) * sizeof(WCHAR) ))) return; len = ntdll_umbstowcs( str, count, output, count ); output[len] = 0; + post_ime_update( hwnd ); x11drv_client_func( client_func_ime_set_result, output, len * sizeof(WCHAR) ); + free( output ); } @@ -142,6 +170,8 @@ static int xic_preedit_start( XIC xic, XPointer user, XPointer arg ) if ((ime_comp_buf = realloc( ime_comp_buf, sizeof(WCHAR) ))) *ime_comp_buf = 0; else ERR( "Failed to allocate preedit buffer\n" ); + post_ime_update( hwnd ); + return -1; } @@ -155,6 +185,8 @@ static int xic_preedit_done( XIC xic, XPointer user, XPointer arg ) ime_comp_buf = NULL; x11drv_client_call( client_ime_set_composition_status, FALSE ); + post_ime_update( hwnd ); + return 0; } @@ -193,6 +225,7 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) if (text && str != text->string.multi_byte) free( str ); x11drv_client_call( client_ime_set_cursor_pos, params->caret ); + post_ime_update( hwnd ); return 0; } @@ -239,6 +272,8 @@ static int xic_preedit_caret( XIC xic, XPointer user, XPointer arg ) x11drv_client_call( client_ime_set_cursor_pos, pos ); params->position = xim_caret_pos = pos; + post_ime_update( hwnd ); + return 0; } @@ -474,10 +509,46 @@ XIC X11DRV_get_ic( HWND hwnd ) void xim_set_focus( HWND hwnd, BOOL focus ) { + struct list updates = LIST_INIT(updates); + struct ime_update *update, *next; XIC xic; if (!(xic = X11DRV_get_ic( hwnd ))) return; if (focus) XSetICFocus( xic ); else XUnsetICFocus( xic ); + + pthread_mutex_lock( &ime_mutex ); + list_move_tail( &updates, &ime_updates ); + pthread_mutex_unlock( &ime_mutex ); + + LIST_FOR_EACH_ENTRY_SAFE( update, next, &updates, struct ime_update, entry ) free( update ); +} + +static struct ime_update *find_ime_update( UINT id ) +{ + struct ime_update *update; + LIST_FOR_EACH_ENTRY( update, &ime_updates, struct ime_update, entry ) + if (update->id == id) return update; + return NULL; +} + +/*********************************************************************** + * ImeToAsciiEx (X11DRV.@) + */ +UINT X11DRV_ImeToAsciiEx( UINT vkey, UINT lparam, const BYTE *state, COMPOSITIONSTRING *compstr, HIMC himc ) +{ + struct ime_update *update; + + TRACE( "vkey %#x, lparam %#x, state %p, compstr %p, himc %p\n", vkey, lparam, state, compstr, himc ); + + pthread_mutex_lock( &ime_mutex ); + + if ((update = find_ime_update( lparam ))) + list_remove( &update->entry ); + + pthread_mutex_unlock( &ime_mutex ); + + free( update ); + return 0; } diff --git a/include/ntuser.h b/include/ntuser.h index c8a3133a36a..0eb597d2b17 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -494,6 +494,7 @@ enum wine_internal_message /* internal WM_IME_NOTIFY wparams, not compatible with Windows */ #define IMN_WINE_SET_OPEN_STATUS 0x000f +#define IMN_WINE_SET_COMP_STRING 0x0010 /* builtin IME driver calls */ enum wine_ime_call From 312651a49f436e6dd9c9775d9e22a4b45077afe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 13 May 2023 10:53:42 +0200 Subject: [PATCH 1929/2777] winex11: Include the XIM preedit and result text into the IME updates. (cherry picked from commit c28f571a55e4eb376c91207b5c4b635cdb19b82d) --- dlls/winex11.drv/xim.c | 59 +++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 1dde1fc936c..efe9498c054 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -48,6 +48,10 @@ struct ime_update { struct list entry; DWORD id; + DWORD cursor_pos; + WCHAR *comp_str; + WCHAR *result_str; + WCHAR buffer[]; }; static pthread_mutex_t ime_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -83,12 +87,18 @@ BOOL xim_in_compose_mode(void) return !!ime_comp_buf; } -static void post_ime_update( HWND hwnd ) +static void post_ime_update( HWND hwnd, UINT cursor_pos, WCHAR *comp_str, WCHAR *result_str ) { - UINT id; + UINT id, comp_len, result_len; struct ime_update *update; - if (!(update = malloc( sizeof(struct ime_update) ))) return; + comp_len = comp_str ? wcslen( comp_str ) + 1 : 0; + result_len = result_str ? wcslen( result_str ) + 1 : 0; + + if (!(update = malloc( offsetof(struct ime_update, buffer[comp_len + result_len]) ))) return; + update->cursor_pos = cursor_pos; + update->comp_str = comp_str ? memcpy( update->buffer, comp_str, comp_len * sizeof(WCHAR) ) : NULL; + update->result_str = result_str ? memcpy( update->buffer + comp_len, result_str, result_len * sizeof(WCHAR) ) : NULL; pthread_mutex_lock( &ime_mutex ); id = update->id = ++ime_update_count; @@ -133,7 +143,7 @@ void xim_set_result_string( HWND hwnd, const char *str, UINT count ) len = ntdll_umbstowcs( str, count, output, count ); output[len] = 0; - post_ime_update( hwnd ); + post_ime_update( hwnd, 0, ime_comp_buf, output ); x11drv_client_func( client_func_ime_set_result, output, len * sizeof(WCHAR) ); free( output ); @@ -170,7 +180,7 @@ static int xic_preedit_start( XIC xic, XPointer user, XPointer arg ) if ((ime_comp_buf = realloc( ime_comp_buf, sizeof(WCHAR) ))) *ime_comp_buf = 0; else ERR( "Failed to allocate preedit buffer\n" ); - post_ime_update( hwnd ); + post_ime_update( hwnd, 0, ime_comp_buf, NULL ); return -1; } @@ -185,7 +195,7 @@ static int xic_preedit_done( XIC xic, XPointer user, XPointer arg ) ime_comp_buf = NULL; x11drv_client_call( client_ime_set_composition_status, FALSE ); - post_ime_update( hwnd ); + post_ime_update( hwnd, 0, NULL, NULL ); return 0; } @@ -225,7 +235,7 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) if (text && str != text->string.multi_byte) free( str ); x11drv_client_call( client_ime_set_cursor_pos, params->caret ); - post_ime_update( hwnd ); + post_ime_update( hwnd, params->caret, ime_comp_buf, NULL ); return 0; } @@ -272,7 +282,7 @@ static int xic_preedit_caret( XIC xic, XPointer user, XPointer arg ) x11drv_client_call( client_ime_set_cursor_pos, pos ); params->position = xim_caret_pos = pos; - post_ime_update( hwnd ); + post_ime_update( hwnd, pos, ime_comp_buf, NULL ); return 0; } @@ -538,15 +548,44 @@ static struct ime_update *find_ime_update( UINT id ) */ UINT X11DRV_ImeToAsciiEx( UINT vkey, UINT lparam, const BYTE *state, COMPOSITIONSTRING *compstr, HIMC himc ) { + UINT needed = sizeof(COMPOSITIONSTRING), comp_len, result_len; struct ime_update *update; TRACE( "vkey %#x, lparam %#x, state %p, compstr %p, himc %p\n", vkey, lparam, state, compstr, himc ); pthread_mutex_lock( &ime_mutex ); - if ((update = find_ime_update( lparam ))) - list_remove( &update->entry ); + if (!(update = find_ime_update( lparam ))) + { + pthread_mutex_unlock( &ime_mutex ); + return 0; + } + + if (!update->comp_str) comp_len = 0; + else + { + comp_len = wcslen( update->comp_str ); + needed += comp_len * sizeof(WCHAR); /* GCS_COMPSTR */ + needed += comp_len; /* GCS_COMPATTR */ + needed += 2 * sizeof(DWORD); /* GCS_COMPCLAUSE */ + } + + if (!update->result_str) result_len = 0; + else + { + result_len = wcslen( update->result_str ); + needed += result_len * sizeof(WCHAR); /* GCS_RESULTSTR */ + needed += 2 * sizeof(DWORD); /* GCS_RESULTCLAUSE */ + } + + if (compstr->dwSize < needed) + { + compstr->dwSize = needed; + pthread_mutex_unlock( &ime_mutex ); + return STATUS_BUFFER_TOO_SMALL; + } + list_remove( &update->entry ); pthread_mutex_unlock( &ime_mutex ); free( update ); From 7d002d068045825562a2eff102e6d7c1cbae1fdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 14:29:18 +0200 Subject: [PATCH 1930/2777] winex11: Generate IME messages using WM_IME_NOTIFY instead of callbacks. (cherry picked from commit b9bfd74acc0992ef56f814b60e831cba01f6be85) --- dlls/imm32/ime.c | 18 ++ dlls/winex11.drv/dllmain.c | 4 - dlls/winex11.drv/ime.c | 472 ---------------------------------- dlls/winex11.drv/unixlib.h | 4 - dlls/winex11.drv/x11drv_dll.h | 4 - dlls/winex11.drv/xim.c | 62 ++++- 6 files changed, 69 insertions(+), 495 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 35e94404b99..a4cdcade73e 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -350,13 +350,31 @@ static UINT ime_set_comp_string( HIMC himc, LPARAM lparam ) }; TRANSMSGLIST list; } buffer = {.uMsgCount = ARRAY_SIZE(buffer.TransMsg)}; + INPUTCONTEXT *ctx; + TRANSMSG *msgs; + HIMCC himcc; UINT count; TRACE( "himc %p\n", himc ); + if (!(ctx = ImmLockIMC( himc ))) return 0; + count = ImeToAsciiEx( VK_PROCESSKEY, lparam, NULL, &buffer.list, 0, himc ); if (count >= buffer.uMsgCount) WARN( "ImeToAsciiEx returned %#x messages\n", count ); + else if (!(himcc = ImmReSizeIMCC( ctx->hMsgBuf, (ctx->dwNumMsgBuf + count) * sizeof(*msgs) ))) + WARN( "Failed to resize input context message buffer\n" ); + else if (!(msgs = ImmLockIMCC( (ctx->hMsgBuf = himcc) ))) + WARN( "Failed to lock input context message buffer\n" ); + else + { + memcpy( msgs + ctx->dwNumMsgBuf, buffer.TransMsg, count * sizeof(*msgs) ); + ImmUnlockIMCC( ctx->hMsgBuf ); + ctx->dwNumMsgBuf += count; + } + + ImmUnlockIMC( himc ); + ImmGenerateMessage( himc ); return count; } diff --git a/dlls/winex11.drv/dllmain.c b/dlls/winex11.drv/dllmain.c index a3375e60957..7c463d4e401 100644 --- a/dlls/winex11.drv/dllmain.c +++ b/dlls/winex11.drv/dllmain.c @@ -30,8 +30,6 @@ static const callback_func callback_funcs[] = { x11drv_dnd_drop_event, x11drv_dnd_leave_event, - x11drv_ime_set_composition_status, - x11drv_ime_set_cursor_pos, x11drv_ime_update_association, }; @@ -50,8 +48,6 @@ static const kernel_callback kernel_callbacks[] = x11drv_dnd_enter_event, x11drv_dnd_position_event, x11drv_dnd_post_drop, - x11drv_ime_set_composition_string, - x11drv_ime_set_result, x11drv_systray_change_owner, }; diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 11832996084..16357e80548 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -52,20 +52,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm); static HIMC *hSelectedFrom = NULL; static INT hSelectedCount = 0; -static void input_context_reset_comp_str( INPUTCONTEXT *ctx ) -{ - COMPOSITIONSTRING *compstr; - - if (!(compstr = ImmLockIMCC( ctx->hCompStr ))) - WARN( "Failed to lock input context composition string\n" ); - else - { - memset( compstr, 0, sizeof(*compstr) ); - compstr->dwSize = sizeof(*compstr); - ImmUnlockIMCC( ctx->hCompStr ); - } -} - static HIMC RealIMC(HIMC hIMC) { if (hIMC == FROM_X11) @@ -100,359 +86,6 @@ static BOOL UnlockRealIMC(HIMC hIMC) return FALSE; } -static int updateField(DWORD origLen, DWORD origOffset, DWORD currentOffset, - LPBYTE target, LPBYTE source, DWORD* lenParam, - DWORD* offsetParam, BOOL wchars ) -{ - if (origLen > 0 && origOffset > 0) - { - int truelen = origLen; - if (wchars) - truelen *= sizeof(WCHAR); - - memcpy(&target[currentOffset], &source[origOffset], truelen); - - *lenParam = origLen; - *offsetParam = currentOffset; - currentOffset += truelen; - } - return currentOffset; -} - -static HIMCC updateCompStr(HIMCC old, LPCWSTR compstr, DWORD len) -{ - /* We need to make sure the CompStr, CompClause and CompAttr fields are all - * set and correct. */ - int needed_size; - HIMCC rc; - LPBYTE newdata = NULL; - LPBYTE olddata = NULL; - LPCOMPOSITIONSTRING new_one; - LPCOMPOSITIONSTRING lpcs = NULL; - INT current_offset = 0; - - TRACE("%s, %li\n",debugstr_wn(compstr,len),len); - - if (old == NULL && compstr == NULL && len == 0) - return NULL; - - if (compstr == NULL && len != 0) - { - ERR("compstr is NULL however we have a len! Please report\n"); - len = 0; - } - - if (old != NULL) - { - olddata = ImmLockIMCC(old); - lpcs = (LPCOMPOSITIONSTRING)olddata; - } - - needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) + - len + sizeof(DWORD) * 2; - - if (lpcs != NULL) - { - needed_size += lpcs->dwCompReadAttrLen; - needed_size += lpcs->dwCompReadClauseLen; - needed_size += lpcs->dwCompReadStrLen * sizeof(WCHAR); - needed_size += lpcs->dwResultReadClauseLen; - needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR); - needed_size += lpcs->dwResultClauseLen; - needed_size += lpcs->dwResultStrLen * sizeof(WCHAR); - needed_size += lpcs->dwPrivateSize; - } - rc = ImmCreateIMCC(needed_size); - newdata = ImmLockIMCC(rc); - new_one = (LPCOMPOSITIONSTRING)newdata; - - new_one->dwSize = needed_size; - current_offset = sizeof(COMPOSITIONSTRING); - if (lpcs != NULL) - { - current_offset = updateField(lpcs->dwCompReadAttrLen, - lpcs->dwCompReadAttrOffset, - current_offset, newdata, olddata, - &new_one->dwCompReadAttrLen, - &new_one->dwCompReadAttrOffset, FALSE); - - current_offset = updateField(lpcs->dwCompReadClauseLen, - lpcs->dwCompReadClauseOffset, - current_offset, newdata, olddata, - &new_one->dwCompReadClauseLen, - &new_one->dwCompReadClauseOffset, FALSE); - - current_offset = updateField(lpcs->dwCompReadStrLen, - lpcs->dwCompReadStrOffset, - current_offset, newdata, olddata, - &new_one->dwCompReadStrLen, - &new_one->dwCompReadStrOffset, TRUE); - - /* new CompAttr, CompClause, CompStr, dwCursorPos */ - new_one->dwDeltaStart = 0; - - current_offset = updateField(lpcs->dwResultReadClauseLen, - lpcs->dwResultReadClauseOffset, - current_offset, newdata, olddata, - &new_one->dwResultReadClauseLen, - &new_one->dwResultReadClauseOffset, FALSE); - - current_offset = updateField(lpcs->dwResultReadStrLen, - lpcs->dwResultReadStrOffset, - current_offset, newdata, olddata, - &new_one->dwResultReadStrLen, - &new_one->dwResultReadStrOffset, TRUE); - - current_offset = updateField(lpcs->dwResultClauseLen, - lpcs->dwResultClauseOffset, - current_offset, newdata, olddata, - &new_one->dwResultClauseLen, - &new_one->dwResultClauseOffset, FALSE); - - current_offset = updateField(lpcs->dwResultStrLen, - lpcs->dwResultStrOffset, - current_offset, newdata, olddata, - &new_one->dwResultStrLen, - &new_one->dwResultStrOffset, TRUE); - - current_offset = updateField(lpcs->dwPrivateSize, - lpcs->dwPrivateOffset, - current_offset, newdata, olddata, - &new_one->dwPrivateSize, - &new_one->dwPrivateOffset, FALSE); - } - - /* set new data */ - /* CompAttr */ - new_one->dwCompAttrLen = len; - if (len > 0) - { - new_one->dwCompAttrOffset = current_offset; - memset(&newdata[current_offset],ATTR_INPUT,len); - current_offset += len; - } - - /* CompClause */ - if (len > 0) - { - new_one->dwCompClauseLen = sizeof(DWORD) * 2; - new_one->dwCompClauseOffset = current_offset; - *(DWORD*)(&newdata[current_offset]) = 0; - current_offset += sizeof(DWORD); - *(DWORD*)(&newdata[current_offset]) = len; - current_offset += sizeof(DWORD); - } - else - new_one->dwCompClauseLen = 0; - - /* CompStr */ - new_one->dwCompStrLen = len; - if (len > 0) - { - new_one->dwCompStrOffset = current_offset; - memcpy(&newdata[current_offset],compstr,len*sizeof(WCHAR)); - } - - /* CursorPos */ - new_one->dwCursorPos = len; - - ImmUnlockIMCC(rc); - if (lpcs) - ImmUnlockIMCC(old); - - return rc; -} - -static HIMCC updateResultStr(HIMCC old, LPWSTR resultstr, DWORD len) -{ - /* we need to make sure the ResultStr and ResultClause fields are all - * set and correct */ - int needed_size; - HIMCC rc; - LPBYTE newdata = NULL; - LPBYTE olddata = NULL; - LPCOMPOSITIONSTRING new_one; - LPCOMPOSITIONSTRING lpcs = NULL; - INT current_offset = 0; - - TRACE("%s, %li\n",debugstr_wn(resultstr,len),len); - - if (old == NULL && resultstr == NULL && len == 0) - return NULL; - - if (resultstr == NULL && len != 0) - { - ERR("resultstr is NULL however we have a len! Please report\n"); - len = 0; - } - - if (old != NULL) - { - olddata = ImmLockIMCC(old); - lpcs = (LPCOMPOSITIONSTRING)olddata; - } - - needed_size = sizeof(COMPOSITIONSTRING) + len * sizeof(WCHAR) + - sizeof(DWORD) * 2; - - if (lpcs != NULL) - { - needed_size += lpcs->dwCompReadAttrLen; - needed_size += lpcs->dwCompReadClauseLen; - needed_size += lpcs->dwCompReadStrLen * sizeof(WCHAR); - needed_size += lpcs->dwCompAttrLen; - needed_size += lpcs->dwCompClauseLen; - needed_size += lpcs->dwCompStrLen * sizeof(WCHAR); - needed_size += lpcs->dwResultReadClauseLen; - needed_size += lpcs->dwResultReadStrLen * sizeof(WCHAR); - needed_size += lpcs->dwPrivateSize; - } - rc = ImmCreateIMCC(needed_size); - newdata = ImmLockIMCC(rc); - new_one = (LPCOMPOSITIONSTRING)newdata; - - new_one->dwSize = needed_size; - current_offset = sizeof(COMPOSITIONSTRING); - if (lpcs != NULL) - { - current_offset = updateField(lpcs->dwCompReadAttrLen, - lpcs->dwCompReadAttrOffset, - current_offset, newdata, olddata, - &new_one->dwCompReadAttrLen, - &new_one->dwCompReadAttrOffset, FALSE); - - current_offset = updateField(lpcs->dwCompReadClauseLen, - lpcs->dwCompReadClauseOffset, - current_offset, newdata, olddata, - &new_one->dwCompReadClauseLen, - &new_one->dwCompReadClauseOffset, FALSE); - - current_offset = updateField(lpcs->dwCompReadStrLen, - lpcs->dwCompReadStrOffset, - current_offset, newdata, olddata, - &new_one->dwCompReadStrLen, - &new_one->dwCompReadStrOffset, TRUE); - - current_offset = updateField(lpcs->dwCompAttrLen, - lpcs->dwCompAttrOffset, - current_offset, newdata, olddata, - &new_one->dwCompAttrLen, - &new_one->dwCompAttrOffset, FALSE); - - current_offset = updateField(lpcs->dwCompClauseLen, - lpcs->dwCompClauseOffset, - current_offset, newdata, olddata, - &new_one->dwCompClauseLen, - &new_one->dwCompClauseOffset, FALSE); - - current_offset = updateField(lpcs->dwCompStrLen, - lpcs->dwCompStrOffset, - current_offset, newdata, olddata, - &new_one->dwCompStrLen, - &new_one->dwCompStrOffset, TRUE); - - new_one->dwCursorPos = lpcs->dwCursorPos; - new_one->dwDeltaStart = 0; - - current_offset = updateField(lpcs->dwResultReadClauseLen, - lpcs->dwResultReadClauseOffset, - current_offset, newdata, olddata, - &new_one->dwResultReadClauseLen, - &new_one->dwResultReadClauseOffset, FALSE); - - current_offset = updateField(lpcs->dwResultReadStrLen, - lpcs->dwResultReadStrOffset, - current_offset, newdata, olddata, - &new_one->dwResultReadStrLen, - &new_one->dwResultReadStrOffset, TRUE); - - /* new ResultClause , ResultStr */ - - current_offset = updateField(lpcs->dwPrivateSize, - lpcs->dwPrivateOffset, - current_offset, newdata, olddata, - &new_one->dwPrivateSize, - &new_one->dwPrivateOffset, FALSE); - } - - /* set new data */ - /* ResultClause */ - if (len > 0) - { - new_one->dwResultClauseLen = sizeof(DWORD) * 2; - new_one->dwResultClauseOffset = current_offset; - *(DWORD*)(&newdata[current_offset]) = 0; - current_offset += sizeof(DWORD); - *(DWORD*)(&newdata[current_offset]) = len; - current_offset += sizeof(DWORD); - } - else - new_one->dwResultClauseLen = 0; - - /* ResultStr */ - new_one->dwResultStrLen = len; - if (len > 0) - { - new_one->dwResultStrOffset = current_offset; - memcpy(&newdata[current_offset],resultstr,len*sizeof(WCHAR)); - } - ImmUnlockIMCC(rc); - if (lpcs) - ImmUnlockIMCC(old); - - return rc; -} - -static void GenerateIMEMessage(HIMC hIMC, UINT msg, WPARAM wParam, - LPARAM lParam) -{ - LPINPUTCONTEXT lpIMC; - LPTRANSMSG lpTransMsg; - - lpIMC = LockRealIMC(hIMC); - if (lpIMC == NULL) - return; - - lpIMC->hMsgBuf = ImmReSizeIMCC(lpIMC->hMsgBuf, (lpIMC->dwNumMsgBuf + 1) * - sizeof(TRANSMSG)); - if (!lpIMC->hMsgBuf) - return; - - lpTransMsg = ImmLockIMCC(lpIMC->hMsgBuf); - if (!lpTransMsg) - return; - - lpTransMsg += lpIMC->dwNumMsgBuf; - lpTransMsg->message = msg; - lpTransMsg->wParam = wParam; - lpTransMsg->lParam = lParam; - - ImmUnlockIMCC(lpIMC->hMsgBuf); - lpIMC->dwNumMsgBuf++; - - ImmGenerateMessage(RealIMC(hIMC)); - UnlockRealIMC(hIMC); -} - -static void ime_set_composition_status( HIMC himc, BOOL composition ) -{ - struct ime_private *priv; - INPUTCONTEXT *ctx; - UINT msg = 0; - - if (!(ctx = ImmLockIMC( himc ))) return; - if ((priv = ImmLockIMCC( ctx->hPrivate ))) - { - if (!priv->bInComposition && composition) msg = WM_IME_STARTCOMPOSITION; - else if (priv->bInComposition && !composition) msg = WM_IME_ENDCOMPOSITION; - priv->bInComposition = composition; - ImmUnlockIMCC( ctx->hPrivate ); - } - ImmUnlockIMC( himc ); - - if (msg) GenerateIMEMessage( himc, msg, 0, 0 ); -} - static BOOL IME_RemoveFromSelected(HIMC hIMC) { int i; @@ -516,57 +149,6 @@ BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) /* Interfaces to XIM and other parts of winex11drv */ -NTSTATUS x11drv_ime_set_composition_status( UINT open ) -{ - HIMC imc; - LPINPUTCONTEXT lpIMC; - - imc = RealIMC(FROM_X11); - lpIMC = ImmLockIMC(imc); - if (lpIMC == NULL) - return 0; - - if (!open) - { - struct ime_private *myPrivate = ImmLockIMCC(lpIMC->hPrivate); - ShowWindow(myPrivate->hwndDefault, SW_HIDE); - input_context_reset_comp_str( lpIMC ); - ImmUnlockIMCC(lpIMC->hPrivate); - } - - ImmUnlockIMC(imc); - - ime_set_composition_status( imc, open ); - - return 0; -} - -NTSTATUS x11drv_ime_set_cursor_pos( UINT pos ) -{ - LPINPUTCONTEXT lpIMC; - LPCOMPOSITIONSTRING compstr; - - if (!hSelectedFrom) - return 0; - - lpIMC = LockRealIMC(FROM_X11); - if (!lpIMC) - return 0; - - compstr = ImmLockIMCC(lpIMC->hCompStr); - if (!compstr) - { - UnlockRealIMC(FROM_X11); - return 0; - } - - compstr->dwCursorPos = pos; - ImmUnlockIMCC(lpIMC->hCompStr); - UnlockRealIMC(FROM_X11); - GenerateIMEMessage(FROM_X11, WM_IME_COMPOSITION, pos, GCS_CURSORPOS); - return 0; -} - NTSTATUS x11drv_ime_update_association( UINT arg ) { HWND focus = UlongToHandle( arg ); @@ -577,57 +159,3 @@ NTSTATUS x11drv_ime_update_association( UINT arg ) ImmAssociateContext(focus,RealIMC(FROM_X11)); return 0; } - - -NTSTATUS WINAPI x11drv_ime_set_composition_string( void *param, ULONG size ) -{ - return ImmSetCompositionStringW( RealIMC(FROM_X11), SCS_SETSTR, param, size, NULL, 0 ); -} - -NTSTATUS WINAPI x11drv_ime_set_result( void *params, ULONG len ) -{ - WCHAR *lpResult = params; - HIMC imc; - LPINPUTCONTEXT lpIMC; - HIMCC newCompStr; - LPIMEPRIVATE myPrivate; - BOOL inComp; - HWND focus; - - len /= sizeof(WCHAR); - if ((focus = GetFocus())) - x11drv_ime_update_association( HandleToUlong( focus )); - - imc = RealIMC(FROM_X11); - lpIMC = ImmLockIMC(imc); - if (lpIMC == NULL) - return 0; - - newCompStr = updateCompStr(lpIMC->hCompStr, NULL, 0); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - - newCompStr = updateResultStr(lpIMC->hCompStr, lpResult, len); - ImmDestroyIMCC(lpIMC->hCompStr); - lpIMC->hCompStr = newCompStr; - - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - inComp = myPrivate->bInComposition; - ImmUnlockIMCC(lpIMC->hPrivate); - - if (!inComp) - { - ImmSetOpenStatus(imc, TRUE); - GenerateIMEMessage(imc, WM_IME_STARTCOMPOSITION, 0, 0); - } - - GenerateIMEMessage(imc, WM_IME_COMPOSITION, 0, GCS_COMPSTR); - GenerateIMEMessage(imc, WM_IME_COMPOSITION, lpResult[0], GCS_RESULTSTR|GCS_RESULTCLAUSE); - GenerateIMEMessage(imc, WM_IME_ENDCOMPOSITION, 0, 0); - - if (!inComp) - ImmSetOpenStatus(imc, FALSE); - - ImmUnlockIMC(imc); - return 0; -} diff --git a/dlls/winex11.drv/unixlib.h b/dlls/winex11.drv/unixlib.h index ef965381479..dba2c8e1060 100644 --- a/dlls/winex11.drv/unixlib.h +++ b/dlls/winex11.drv/unixlib.h @@ -81,8 +81,6 @@ enum x11drv_client_funcs client_func_dnd_enter_event, client_func_dnd_position_event, client_func_dnd_post_drop, - client_func_ime_set_composition_string, - client_func_ime_set_result, client_func_systray_change_owner, client_func_last }; @@ -94,8 +92,6 @@ enum client_callback { client_dnd_drop_event, client_dnd_leave_event, - client_ime_set_composition_status, - client_ime_set_cursor_pos, client_ime_update_association, client_funcs_count }; diff --git a/dlls/winex11.drv/x11drv_dll.h b/dlls/winex11.drv/x11drv_dll.h index 2cc27abd362..fbd2a3e74b2 100644 --- a/dlls/winex11.drv/x11drv_dll.h +++ b/dlls/winex11.drv/x11drv_dll.h @@ -30,14 +30,10 @@ extern NTSTATUS WINAPI x11drv_dnd_enter_event( void *params, ULONG size ) DECLSPEC_HIDDEN; extern NTSTATUS WINAPI x11drv_dnd_position_event( void *params, ULONG size ) DECLSPEC_HIDDEN; extern NTSTATUS WINAPI x11drv_dnd_post_drop( void *data, ULONG size ) DECLSPEC_HIDDEN; -extern NTSTATUS WINAPI x11drv_ime_set_composition_string( void *params, ULONG size ) DECLSPEC_HIDDEN; -extern NTSTATUS WINAPI x11drv_ime_set_result( void *params, ULONG size ) DECLSPEC_HIDDEN; extern NTSTATUS WINAPI x11drv_systray_change_owner( void *params, ULONG size ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_dnd_drop_event( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_dnd_leave_event( UINT arg ) DECLSPEC_HIDDEN; -extern NTSTATUS x11drv_ime_set_composition_status( UINT arg ) DECLSPEC_HIDDEN; -extern NTSTATUS x11drv_ime_set_cursor_pos( UINT pos ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_ime_update_association( UINT arg ) DECLSPEC_HIDDEN; extern LRESULT WINAPI foreign_window_proc( HWND hwnd, UINT msg, WPARAM wparam, diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index efe9498c054..e5cea5941f7 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -126,10 +126,7 @@ static void xim_update_comp_string( UINT offset, UINT old_len, const WCHAR *text ptr = ime_comp_buf + offset; memmove( ptr + new_len, ptr + old_len, (len - offset - old_len) * sizeof(WCHAR) ); if (text) memcpy( ptr, text, new_len * sizeof(WCHAR) ); - len += diff; - ime_comp_buf[len] = 0; - - x11drv_client_func( client_func_ime_set_composition_string, ime_comp_buf, len * sizeof(WCHAR) ); + ime_comp_buf[len + diff] = 0; } void xim_set_result_string( HWND hwnd, const char *str, UINT count ) @@ -144,7 +141,6 @@ void xim_set_result_string( HWND hwnd, const char *str, UINT count ) output[len] = 0; post_ime_update( hwnd, 0, ime_comp_buf, output ); - x11drv_client_func( client_func_ime_set_result, output, len * sizeof(WCHAR) ); free( output ); } @@ -160,10 +156,10 @@ static BOOL xic_preedit_state_notify( XIC xic, XPointer user, XPointer arg ) switch (state) { case XIMPreeditEnable: - send_message( hwnd, WM_IME_NOTIFY, IMN_WINE_SET_OPEN_STATUS, TRUE ); + NtUserPostMessage( hwnd, WM_IME_NOTIFY, IMN_WINE_SET_OPEN_STATUS, TRUE ); break; case XIMPreeditDisable: - send_message( hwnd, WM_IME_NOTIFY, IMN_WINE_SET_OPEN_STATUS, FALSE ); + NtUserPostMessage( hwnd, WM_IME_NOTIFY, IMN_WINE_SET_OPEN_STATUS, FALSE ); break; } @@ -176,7 +172,6 @@ static int xic_preedit_start( XIC xic, XPointer user, XPointer arg ) TRACE( "xic %p, hwnd %p, arg %p\n", xic, hwnd, arg ); - x11drv_client_call( client_ime_set_composition_status, TRUE ); if ((ime_comp_buf = realloc( ime_comp_buf, sizeof(WCHAR) ))) *ime_comp_buf = 0; else ERR( "Failed to allocate preedit buffer\n" ); @@ -194,7 +189,6 @@ static int xic_preedit_done( XIC xic, XPointer user, XPointer arg ) free( ime_comp_buf ); ime_comp_buf = NULL; - x11drv_client_call( client_ime_set_composition_status, FALSE ); post_ime_update( hwnd, 0, NULL, NULL ); return 0; @@ -234,7 +228,6 @@ static int xic_preedit_draw( XIC xic, XPointer user, XPointer arg ) if (text && str != text->string.multi_byte) free( str ); - x11drv_client_call( client_ime_set_cursor_pos, params->caret ); post_ime_update( hwnd, params->caret, ime_comp_buf, NULL ); return 0; @@ -279,7 +272,6 @@ static int xic_preedit_caret( XIC xic, XPointer user, XPointer arg ) FIXME( "Not implemented\n" ); break; } - x11drv_client_call( client_ime_set_cursor_pos, pos ); params->position = xim_caret_pos = pos; post_ime_update( hwnd, pos, ime_comp_buf, NULL ); @@ -545,11 +537,16 @@ static struct ime_update *find_ime_update( UINT id ) /*********************************************************************** * ImeToAsciiEx (X11DRV.@) + * + * As XIM filters key events upfront, we don't use ImeProcessKey and ImeToAsciiEx is instead called + * back from the IME UI window procedure when WM_IME_NOTIFY / IMN_WINE_SET_COMP_STRING messages are + * sent to it, to retrieve composition string updates and generate WM_IME messages. */ UINT X11DRV_ImeToAsciiEx( UINT vkey, UINT lparam, const BYTE *state, COMPOSITIONSTRING *compstr, HIMC himc ) { UINT needed = sizeof(COMPOSITIONSTRING), comp_len, result_len; struct ime_update *update; + void *dst; TRACE( "vkey %#x, lparam %#x, state %p, compstr %p, himc %p\n", vkey, lparam, state, compstr, himc ); @@ -588,6 +585,49 @@ UINT X11DRV_ImeToAsciiEx( UINT vkey, UINT lparam, const BYTE *state, COMPOSITION list_remove( &update->entry ); pthread_mutex_unlock( &ime_mutex ); + memset( compstr, 0, sizeof(*compstr) ); + compstr->dwSize = sizeof(*compstr); + + if (update->comp_str) + { + compstr->dwCursorPos = update->cursor_pos; + + compstr->dwCompStrLen = comp_len; + compstr->dwCompStrOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwCompStrOffset; + memcpy( dst, update->comp_str, compstr->dwCompStrLen * sizeof(WCHAR) ); + compstr->dwSize += compstr->dwCompStrLen * sizeof(WCHAR); + + compstr->dwCompClauseLen = 2 * sizeof(DWORD); + compstr->dwCompClauseOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwCompClauseOffset; + *((DWORD *)dst + 0) = 0; + *((DWORD *)dst + 1) = compstr->dwCompStrLen; + compstr->dwSize += compstr->dwCompClauseLen; + + compstr->dwCompAttrLen = compstr->dwCompStrLen; + compstr->dwCompAttrOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwCompAttrOffset; + memset( dst, ATTR_INPUT, compstr->dwCompAttrLen ); + compstr->dwSize += compstr->dwCompAttrLen; + } + + if (update->result_str) + { + compstr->dwResultStrLen = result_len; + compstr->dwResultStrOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwResultStrOffset; + memcpy( dst, update->result_str, compstr->dwResultStrLen * sizeof(WCHAR) ); + compstr->dwSize += compstr->dwResultStrLen * sizeof(WCHAR); + + compstr->dwResultClauseLen = 2 * sizeof(DWORD); + compstr->dwResultClauseOffset = compstr->dwSize; + dst = (BYTE *)compstr + compstr->dwResultClauseOffset; + *((DWORD *)dst + 0) = 0; + *((DWORD *)dst + 1) = compstr->dwResultStrLen; + compstr->dwSize += compstr->dwResultClauseLen; + } + free( update ); return 0; } From 51ad184b5848d7c3c70e036a9d95da835dd51b1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 13 May 2023 10:59:32 +0200 Subject: [PATCH 1931/2777] winex11: Drop the x11drv_ime_update_association user callback. (cherry picked from commit 9f05a79bd63795664bcd20f69a81e1437536dad2) --- dlls/winex11.drv/dllmain.c | 1 - dlls/winex11.drv/ime.c | 13 ------------- dlls/winex11.drv/unixlib.h | 1 - dlls/winex11.drv/x11drv_dll.h | 1 - dlls/winex11.drv/xim.c | 6 ++---- 5 files changed, 2 insertions(+), 20 deletions(-) diff --git a/dlls/winex11.drv/dllmain.c b/dlls/winex11.drv/dllmain.c index 7c463d4e401..3aa0a9875d0 100644 --- a/dlls/winex11.drv/dllmain.c +++ b/dlls/winex11.drv/dllmain.c @@ -30,7 +30,6 @@ static const callback_func callback_funcs[] = { x11drv_dnd_drop_event, x11drv_dnd_leave_event, - x11drv_ime_update_association, }; C_ASSERT( ARRAYSIZE(callback_funcs) == client_funcs_count ); diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 16357e80548..019312cfd5a 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -146,16 +146,3 @@ BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) return TRUE; } - -/* Interfaces to XIM and other parts of winex11drv */ - -NTSTATUS x11drv_ime_update_association( UINT arg ) -{ - HWND focus = UlongToHandle( arg ); - - ImmGetContext(focus); - - if (focus && hSelectedFrom) - ImmAssociateContext(focus,RealIMC(FROM_X11)); - return 0; -} diff --git a/dlls/winex11.drv/unixlib.h b/dlls/winex11.drv/unixlib.h index dba2c8e1060..0c812896fbc 100644 --- a/dlls/winex11.drv/unixlib.h +++ b/dlls/winex11.drv/unixlib.h @@ -92,7 +92,6 @@ enum client_callback { client_dnd_drop_event, client_dnd_leave_event, - client_ime_update_association, client_funcs_count }; diff --git a/dlls/winex11.drv/x11drv_dll.h b/dlls/winex11.drv/x11drv_dll.h index fbd2a3e74b2..bab27afce14 100644 --- a/dlls/winex11.drv/x11drv_dll.h +++ b/dlls/winex11.drv/x11drv_dll.h @@ -34,7 +34,6 @@ extern NTSTATUS WINAPI x11drv_systray_change_owner( void *params, ULONG size ) D extern NTSTATUS x11drv_dnd_drop_event( UINT arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_dnd_leave_event( UINT arg ) DECLSPEC_HIDDEN; -extern NTSTATUS x11drv_ime_update_association( UINT arg ) DECLSPEC_HIDDEN; extern LRESULT WINAPI foreign_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index e5cea5941f7..1c3d2dd9875 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -410,8 +410,6 @@ static void xim_open( Display *display, XPointer user, XPointer arg ) TRACE( "display %p, data %p, arg %p\n", display, user, arg ); if (!(data->xim = xim_create( data ))) return; XUnregisterIMInstantiateCallback( display, NULL, NULL, NULL, xim_open, user ); - - x11drv_client_call( client_ime_update_association, 0 ); } static void xim_destroy( XIM xim, XPointer user, XPointer arg ) @@ -434,8 +432,8 @@ void xim_thread_attach( struct x11drv_thread_data *data ) for (i = 0; list && i < count; ++i) TRACE( " %d: %s\n", i, list[i] ); if (list) XFreeStringList( list ); - if ((data->xim = xim_create( data ))) x11drv_client_call( client_ime_update_association, 0 ); - else XRegisterIMInstantiateCallback( display, NULL, NULL, NULL, xim_open, (XPointer)data ); + if ((data->xim = xim_create( data ))) return; + XRegisterIMInstantiateCallback( display, NULL, NULL, NULL, xim_open, (XPointer)data ); } static BOOL xic_destroy( XIC xic, XPointer user, XPointer arg ) From 1ba8b5cca4eb58384d41881fecc449642f50dd85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 1 Apr 2023 22:24:19 +0200 Subject: [PATCH 1932/2777] winex11: Remove now unnecessary selected HIMC tracking code. (cherry picked from commit cbf719d72d885e9da96acf1fec6fc89ca95660e7) --- dlls/winex11.drv/ime.c | 82 ++---------------------------------------- 1 file changed, 3 insertions(+), 79 deletions(-) diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c index 019312cfd5a..daf6d89dc7a 100644 --- a/dlls/winex11.drv/ime.c +++ b/dlls/winex11.drv/ime.c @@ -47,91 +47,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm); -#define FROM_X11 ((HIMC)0xcafe1337) - -static HIMC *hSelectedFrom = NULL; -static INT hSelectedCount = 0; - -static HIMC RealIMC(HIMC hIMC) -{ - if (hIMC == FROM_X11) - { - INT i; - HWND wnd = GetFocus(); - HIMC winHimc = ImmGetContext(wnd); - for (i = 0; i < hSelectedCount; i++) - if (winHimc == hSelectedFrom[i]) - return winHimc; - return NULL; - } - else - return hIMC; -} - -static LPINPUTCONTEXT LockRealIMC(HIMC hIMC) -{ - HIMC real_imc = RealIMC(hIMC); - if (real_imc) - return ImmLockIMC(real_imc); - else - return NULL; -} - -static BOOL UnlockRealIMC(HIMC hIMC) -{ - HIMC real_imc = RealIMC(hIMC); - if (real_imc) - return ImmUnlockIMC(real_imc); - else - return FALSE; -} - -static BOOL IME_RemoveFromSelected(HIMC hIMC) -{ - int i; - for (i = 0; i < hSelectedCount; i++) - if (hSelectedFrom[i] == hIMC) - { - if (i < hSelectedCount - 1) - memmove(&hSelectedFrom[i], &hSelectedFrom[i+1], (hSelectedCount - i - 1)*sizeof(HIMC)); - hSelectedCount --; - return TRUE; - } - return FALSE; -} - -static void IME_AddToSelected(HIMC hIMC) -{ - hSelectedCount++; - if (hSelectedFrom) - hSelectedFrom = HeapReAlloc(GetProcessHeap(), 0, hSelectedFrom, hSelectedCount*sizeof(HIMC)); - else - hSelectedFrom = HeapAlloc(GetProcessHeap(), 0, sizeof(HIMC)); - hSelectedFrom[hSelectedCount-1] = hIMC; -} - BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) { LPINPUTCONTEXT lpIMC; TRACE("%p %s\n",hIMC,(fSelect)?"TRUE":"FALSE"); - if (hIMC == FROM_X11) - { - ERR("ImeSelect should never be called from X11\n"); - return FALSE; - } - - if (!hIMC) - return TRUE; - - /* not selected */ - if (!fSelect) - return IME_RemoveFromSelected(hIMC); - - IME_AddToSelected(hIMC); + if (!hIMC || !fSelect) return TRUE; /* Initialize our structures */ - lpIMC = LockRealIMC(hIMC); + lpIMC = ImmLockIMC(hIMC); if (lpIMC != NULL) { LPIMEPRIVATE myPrivate; @@ -141,7 +65,7 @@ BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) myPrivate->textfont = NULL; myPrivate->hwndDefault = NULL; ImmUnlockIMCC(lpIMC->hPrivate); - UnlockRealIMC(hIMC); + ImmUnlockIMC(hIMC); } return TRUE; From 9a423b9aba33de3648fa31ed5af73f3b6a4b96d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 1 Apr 2023 22:25:01 +0200 Subject: [PATCH 1933/2777] winex11: Use the default IME implementation for ImeSelect. (cherry picked from commit f7d4eec45920ac18cbd55f85918d9a73b6bd5d0c) --- dlls/winex11.drv/Makefile.in | 1 - dlls/winex11.drv/ime.c | 72 ------------------------------- dlls/winex11.drv/winex11.drv.spec | 3 -- 3 files changed, 76 deletions(-) delete mode 100644 dlls/winex11.drv/ime.c diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in index c9e76002b2c..3629ca17c67 100644 --- a/dlls/winex11.drv/Makefile.in +++ b/dlls/winex11.drv/Makefile.in @@ -15,7 +15,6 @@ C_SRCS = \ event.c \ fs.c \ graphics.c \ - ime.c \ init.c \ keyboard.c \ mouse.c \ diff --git a/dlls/winex11.drv/ime.c b/dlls/winex11.drv/ime.c deleted file mode 100644 index daf6d89dc7a..00000000000 --- a/dlls/winex11.drv/ime.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * The IME for interfacing with XIM - * - * Copyright 2008 CodeWeavers, Aric Stewart - * - * 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 - */ - -/* - * Notes: - * The normal flow for IMM/IME Processing is as follows. - * 1) The Keyboard Driver generates key messages which are first passed to - * the IMM and then to IME via ImeProcessKey. If the IME returns 0 then - * it does not want the key and the keyboard driver then generates the - * WM_KEYUP/WM_KEYDOWN messages. However if the IME is going to process the - * key it returns non-zero. - * 2) If the IME is going to process the key then the IMM calls ImeToAsciiEx to - * process the key. the IME modifies the HIMC structure to reflect the - * current state and generates any messages it needs the IMM to process. - * 3) IMM checks the messages and send them to the application in question. From - * here the IMM level deals with if the application is IME aware or not. - * - * This flow does not work well for the X11 driver and XIM. - * (It works fine for Mac) - * As such we will have to reroute step 1. Instead the x11drv driver will - * generate an XIM events and call directly into this IME implementation. - * As such we will have to use the alternative ImmGenerateMessage path to be - * generate the messages that we want the IMM layer to send to the application. - */ - -#include "x11drv_dll.h" -#include "wine/debug.h" -#include "imm.h" -#include "immdev.h" - -WINE_DEFAULT_DEBUG_CHANNEL(imm); - -BOOL WINAPI ImeSelect(HIMC hIMC, BOOL fSelect) -{ - LPINPUTCONTEXT lpIMC; - TRACE("%p %s\n",hIMC,(fSelect)?"TRUE":"FALSE"); - - if (!hIMC || !fSelect) return TRUE; - - /* Initialize our structures */ - lpIMC = ImmLockIMC(hIMC); - if (lpIMC != NULL) - { - LPIMEPRIVATE myPrivate; - myPrivate = ImmLockIMCC(lpIMC->hPrivate); - myPrivate->bInComposition = FALSE; - myPrivate->bInternalState = FALSE; - myPrivate->textfont = NULL; - myPrivate->hwndDefault = NULL; - ImmUnlockIMCC(lpIMC->hPrivate); - ImmUnlockIMC(hIMC); - } - - return TRUE; -} diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec index c8d52d07f6d..a7334eef3d9 100644 --- a/dlls/winex11.drv/winex11.drv.spec +++ b/dlls/winex11.drv/winex11.drv.spec @@ -9,6 +9,3 @@ # System tray @ cdecl wine_notify_icon(long ptr) - -#IME Interface -@ stdcall ImeSelect(long long) From d78c3adb6af186cc80a28a7e477f61c93d656fd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 10 May 2023 23:34:37 +0200 Subject: [PATCH 1934/2777] imm32: Get rid of the graphics driver loading mechanism. (cherry picked from commit d61a786461f1b1bfdd6f17125db124cd5e06fa3f) --- dlls/imm32/imm.c | 100 +++++++++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 55 deletions(-) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 2fe355da5bb..aa1881e0918 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -429,31 +429,6 @@ static struct imc *query_imc_data( HIMC handle ) return ret && ret->handle == handle ? ret : NULL; } -static HMODULE load_graphics_driver(void) -{ - static const WCHAR key_pathW[] = L"System\\CurrentControlSet\\Control\\Video\\{"; - static const WCHAR displayW[] = L"}\\0000"; - - HMODULE ret = 0; - HKEY hkey; - DWORD size; - WCHAR path[MAX_PATH]; - WCHAR key[ARRAY_SIZE( key_pathW ) + ARRAY_SIZE( displayW ) + 40]; - UINT guid_atom = HandleToULong( GetPropW( GetDesktopWindow(), L"__wine_display_device_guid" )); - - if (!guid_atom) return 0; - memcpy( key, key_pathW, sizeof(key_pathW) ); - if (!GlobalGetAtomNameW( guid_atom, key + lstrlenW(key), 40 )) return 0; - lstrcatW( key, displayW ); - if (RegOpenKeyW( HKEY_LOCAL_MACHINE, key, &hkey )) return 0; - size = sizeof(path); - if (!RegQueryValueExW( hkey, L"GraphicsDriver", NULL, NULL, (BYTE *)path, &size )) - ret = LoadLibraryW( path ); - RegCloseKey( hkey ); - TRACE( "%s %p\n", debugstr_w(path), ret ); - return ret; -} - /* lookup an IME from a HKL, must hold ime_cs */ static struct ime *find_ime_from_hkl( HKL hkl ) { @@ -511,41 +486,54 @@ BOOL WINAPI ImmLoadIME( HKL hkl ) if (use_default_ime) { if (*buffer) WARN( "Failed to load %s, falling back to default.\n", debugstr_w(buffer) ); - if (!(ime->module = load_graphics_driver())) ime->module = LoadLibraryW( L"imm32" ); + ime->module = LoadLibraryW( L"imm32" ); + ime->pImeInquire = (void *)ImeInquire; + ime->pImeDestroy = ImeDestroy; + ime->pImeSelect = ImeSelect; + ime->pImeConfigure = ImeConfigure; + ime->pImeEscape = ImeEscape; + ime->pImeSetActiveContext = ImeSetActiveContext; + ime->pImeToAsciiEx = (void *)ImeToAsciiEx; + ime->pNotifyIME = NotifyIME; + ime->pImeRegisterWord = (void *)ImeRegisterWord; + ime->pImeUnregisterWord = (void *)ImeUnregisterWord; + ime->pImeEnumRegisterWord = (void *)ImeEnumRegisterWord; + ime->pImeSetCompositionString = ImeSetCompositionString; + ime->pImeConversionList = (void *)ImeConversionList; + ime->pImeProcessKey = (void *)ImeProcessKey; + ime->pImeGetRegisterWordStyle = (void *)ImeGetRegisterWordStyle; + ime->pImeGetImeMenuItems = (void *)ImeGetImeMenuItems; } - + else + { #define LOAD_FUNCPTR( f ) \ - if (!(ime->p##f = (void *)GetProcAddress( ime->module, #f )) && \ - !(ime->p##f = use_default_ime ? (void *)f : NULL)) \ - { \ - LeaveCriticalSection( &ime_cs ); \ - WARN( "Can't find function %s in HKL %p IME\n", #f, hkl ); \ - goto failed; \ - } - LOAD_FUNCPTR( ImeInquire ); - LOAD_FUNCPTR( ImeDestroy ); - LOAD_FUNCPTR( ImeSelect ); - LOAD_FUNCPTR( ImeConfigure ); - LOAD_FUNCPTR( ImeEscape ); - LOAD_FUNCPTR( ImeSetActiveContext ); - LOAD_FUNCPTR( ImeToAsciiEx ); - LOAD_FUNCPTR( NotifyIME ); - LOAD_FUNCPTR( ImeRegisterWord ); - LOAD_FUNCPTR( ImeUnregisterWord ); - LOAD_FUNCPTR( ImeEnumRegisterWord ); - LOAD_FUNCPTR( ImeSetCompositionString ); - LOAD_FUNCPTR( ImeConversionList ); - LOAD_FUNCPTR( ImeProcessKey ); - LOAD_FUNCPTR( ImeGetRegisterWordStyle ); - LOAD_FUNCPTR( ImeGetImeMenuItems ); + if (!(ime->p##f = (void *)GetProcAddress( ime->module, #f ))) \ + { \ + WARN( "Can't find function %s in HKL %p IME\n", #f, hkl ); \ + goto failed; \ + } + + LOAD_FUNCPTR( ImeInquire ); + LOAD_FUNCPTR( ImeDestroy ); + LOAD_FUNCPTR( ImeSelect ); + LOAD_FUNCPTR( ImeConfigure ); + LOAD_FUNCPTR( ImeEscape ); + LOAD_FUNCPTR( ImeSetActiveContext ); + LOAD_FUNCPTR( ImeToAsciiEx ); + LOAD_FUNCPTR( NotifyIME ); + LOAD_FUNCPTR( ImeRegisterWord ); + LOAD_FUNCPTR( ImeUnregisterWord ); + LOAD_FUNCPTR( ImeEnumRegisterWord ); + LOAD_FUNCPTR( ImeSetCompositionString ); + LOAD_FUNCPTR( ImeConversionList ); + LOAD_FUNCPTR( ImeProcessKey ); + LOAD_FUNCPTR( ImeGetRegisterWordStyle ); + LOAD_FUNCPTR( ImeGetImeMenuItems ); #undef LOAD_FUNCPTR + } ime->hkl = hkl; - if (!ime->pImeInquire( &ime->info, buffer, 0 )) - { - LeaveCriticalSection( &ime_cs ); - goto failed; - } + if (!ime->pImeInquire( &ime->info, buffer, 0 )) goto failed; if (ime_is_unicode( ime )) lstrcpynW( ime->ui_class, buffer, ARRAY_SIZE(ime->ui_class) ); else MultiByteToWideChar( CP_ACP, 0, (char *)buffer, -1, ime->ui_class, ARRAY_SIZE(ime->ui_class) ); @@ -558,6 +546,8 @@ BOOL WINAPI ImmLoadIME( HKL hkl ) return TRUE; failed: + LeaveCriticalSection( &ime_cs ); + if (ime->module) FreeLibrary( ime->module ); free( ime ); return FALSE; From fc4430a39049238a6528bf359a878668c43de50b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 9 May 2023 21:58:24 +0200 Subject: [PATCH 1935/2777] imm32: Remove now unused members from ime_private. And move its definition to ime.c. (cherry picked from commit 65d0f7a75626983bb7cc2b6c7ace41d44d730560) --- dlls/imm32/ime.c | 34 +++++++++++++--------------------- include/ntuser.h | 9 --------- 2 files changed, 13 insertions(+), 30 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index a4cdcade73e..10fd234a2c1 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -23,6 +23,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(imm); +struct ime_private +{ + BOOL in_composition; + HFONT hfont; +}; + static const char *debugstr_imn( WPARAM wparam ) { switch (wparam) @@ -139,7 +145,7 @@ static HFONT input_context_select_ui_font( INPUTCONTEXT *ctx, HDC hdc ) struct ime_private *priv; HFONT font = NULL; if (!(priv = ImmLockIMCC( ctx->hPrivate ))) return NULL; - if (priv->textfont) font = SelectObject( hdc, priv->textfont ); + if (priv->hfont) font = SelectObject( hdc, priv->hfont ); ImmUnlockIMCC( ctx->hPrivate ); return font; } @@ -175,9 +181,9 @@ static UINT ime_set_composition_status( HIMC himc, BOOL composition ) if (!(ctx = ImmLockIMC( himc ))) return 0; if ((priv = ImmLockIMCC( ctx->hPrivate ))) { - if (!priv->bInComposition && composition) msg = WM_IME_STARTCOMPOSITION; - else if (priv->bInComposition && !composition) msg = WM_IME_ENDCOMPOSITION; - priv->bInComposition = composition; + if (!priv->in_composition && composition) msg = WM_IME_STARTCOMPOSITION; + else if (priv->in_composition && !composition) msg = WM_IME_ENDCOMPOSITION; + priv->in_composition = composition; ImmUnlockIMCC( ctx->hPrivate ); } ImmUnlockIMC( himc ); @@ -398,7 +404,6 @@ static LRESULT ime_ui_notify( HIMC himc, HWND hwnd, WPARAM wparam, LPARAM lparam static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { HIMC himc = (HIMC)GetWindowLongPtrW( hwnd, IMMGWL_IMC ); - INPUTCONTEXT *ctx; TRACE( "hwnd %p, himc %p, msg %s, wparam %#Ix, lparam %#Ix\n", hwnd, himc, debugstr_wm_ime(msg), wparam, lparam ); @@ -406,20 +411,7 @@ static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LP switch (msg) { case WM_CREATE: - { - struct ime_private *priv; - - SetWindowTextA( hwnd, "Wine Ime Active" ); - - if (!(ctx = ImmLockIMC( himc ))) return TRUE; - if ((priv = ImmLockIMCC( ctx->hPrivate ))) - { - priv->hwndDefault = hwnd; - ImmUnlockIMCC( ctx->hPrivate ); - } - ImmUnlockIMC( himc ); return TRUE; - } case WM_PAINT: ime_ui_paint( himc, hwnd ); return FALSE; @@ -468,7 +460,7 @@ BOOL WINAPI ImeInquire( IMEINFO *info, WCHAR *ui_class, DWORD flags ) wcscpy( ui_class, ime_ui_class.lpszClassName ); memset( info, 0, sizeof(*info) ); - info->dwPrivateDataSize = sizeof(IMEPRIVATE); + info->dwPrivateDataSize = sizeof(struct ime_private); info->fdwProperty = IME_PROP_UNICODE | IME_PROP_AT_CARET; info->fdwConversionCaps = IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE; info->fdwSentenceCaps = IME_SMODE_AUTOMATIC; @@ -656,8 +648,8 @@ BOOL WINAPI NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) case IMC_SETCOMPOSITIONFONT: if ((priv = ImmLockIMCC( ctx->hPrivate ))) { - if (priv->textfont) DeleteObject( priv->textfont ); - priv->textfont = CreateFontIndirectW( &ctx->lfFont.W ); + if (priv->hfont) DeleteObject( priv->hfont ); + priv->hfont = CreateFontIndirectW( &ctx->lfFont.W ); ImmUnlockIMCC( ctx->hPrivate ); } break; diff --git a/include/ntuser.h b/include/ntuser.h index 0eb597d2b17..f9c63a48cee 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -511,15 +511,6 @@ struct ime_driver_call_params COMPOSITIONSTRING *compstr; }; -/* internal IME private */ -typedef struct ime_private -{ - BOOL bInComposition; - BOOL bInternalState; - HFONT textfont; - HWND hwndDefault; -} IMEPRIVATE, *LPIMEPRIVATE; - #define WM_SYSTIMER 0x0118 /* the various structures that can be sent in messages, in platform-independent layout */ From bbf40ec29c4a2304389e86c39bd236e39bc8f9ed Mon Sep 17 00:00:00 2001 From: Jinoh Kang Date: Sat, 20 May 2023 23:34:23 +0900 Subject: [PATCH 1936/2777] imm32: Don't erroneously start composition when handling IMC_SETOPENSTATUS. Fixes: 8ae0c308233e61cfc01ef52886077960d6513d93 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54965 --- dlls/imm32/ime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 10fd234a2c1..e15367f5fa8 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -657,7 +657,7 @@ BOOL WINAPI NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) if (!ctx->fOpen) { input_context_set_comp_str( ctx, NULL, 0 ); - if ((msg = ime_set_composition_status( himc, TRUE ))) ime_send_message( himc, msg, 0, 0 ); + if ((msg = ime_set_composition_status( himc, FALSE ))) ime_send_message( himc, msg, 0, 0 ); } NtUserNotifyIMEStatus( ctx->hWnd, ctx->fOpen ); break; From 4458bd9aafff2fa1c7defb28f5bdccc6be5eec1a Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 7 Dec 2020 09:31:52 +0100 Subject: [PATCH 1937/2777] winex11.drv: Recognize the keyboard in a locale-independent way. Try to recognize the keyboard comparing keysyms instead of converting them to multibyte strings, which makes the process locale-dependent and therefore more fragile. Unfortunately this means that the layout tables might need to be updated. However, this change is known to fix the recognitions of a few keys in the French layout. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=30984 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45605 CW-Bug-Id: #16793 --- dlls/winex11.drv/keyboard.c | 62 +++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index c099c3a2727..9217ebb46ac 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1403,6 +1403,35 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) return TRUE; } +/* From the point of view of this function there are two types of + * keys: those for which the mapping to vkey and scancode depends on + * the keyboard layout (i.e., letters, numbers, punctuation) and those + * for which it doesn't (control keys); since this function is used to + * recognize the keyboard layout and map keysyms to vkeys and + * scancodes, we are only concerned about the first type, and map + * everything in the second type to zero. + */ +static char keysym_to_char( KeySym keysym ) +{ + /* Dead keys */ + if (0xfe50 <= keysym && keysym < 0xfed0) + return KEYBOARD_MapDeadKeysym( keysym ); + + /* Control keys (there is nothing allocated below 0xfc00, but I + take some margin in case something is added in the future) */ + if (0xf000 <= keysym && keysym < 0x10000) + return 0; + + /* XFree86 vendor keys */ + if (0x10000000 <= keysym) + return 0; + + /* "Normal" keys: return last octet, because our tables don't have + more than that; it would be better to extend the tables and + compare the whole keysym, but it's a lot of work... */ + return keysym & 0xff; +} + /********************************************************************** * X11DRV_KEYBOARD_DetectLayout * @@ -1433,22 +1462,7 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) /* get data for keycode from X server */ for (i = 0; i < syms; i++) { if (!(keysym = XkbKeycodeToKeysym( display, keyc, 0, i ))) continue; - /* Allow both one-byte and two-byte national keysyms */ - if ((keysym < 0x8000) && (keysym != ' ')) - { - if (!XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL)) - { - TRACE("XKB could not translate keysym %04lx\n", keysym); - /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent - * with appropriate ShiftMask and Mode_switch, use XLookupString - * to get character in the local encoding. - */ - ckey[keyc][i] = keysym & 0xFF; - } - } - else { - ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym); - } + ckey[keyc][i] = keysym_to_char(keysym); } } @@ -1623,20 +1637,8 @@ void X11DRV_InitKeyboard( Display *display ) /* we seem to need to search the layout-dependent scancodes */ int maxlen=0,maxval=-1,ok; for (i=0; i Date: Mon, 7 Dec 2020 09:49:53 +0100 Subject: [PATCH 1938/2777] winex11.drv: Dump keysyms and translations for all keys. Dump all we can see about the user keyboard, so that their +keyboard logs can be used to fix layout tables. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=30984 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45605 CW-Bug-Id: #16793 --- dlls/winex11.drv/keyboard.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 9217ebb46ac..1d6cef40efb 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1463,6 +1463,19 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) for (i = 0; i < syms; i++) { if (!(keysym = XkbKeycodeToKeysym( display, keyc, 0, i ))) continue; ckey[keyc][i] = keysym_to_char(keysym); + if (TRACE_ON(keyboard)) + { + char buf[32]; + WCHAR bufW[32]; + int len, lenW; + KeySym orig_keysym = keysym; + len = XkbTranslateKeySym(display, &keysym, 0, buf, sizeof(buf), NULL); + lenW = ntdll_umbstowcs(buf, len, bufW, ARRAY_SIZE(bufW)); + if (lenW < ARRAY_SIZE(bufW)) + bufW[lenW] = 0; + TRACE("keycode %u, index %d, orig_keysym 0x%04lx, keysym 0x%04lx, buf %s, bufW %s\n", + keyc, i, orig_keysym, keysym, debugstr_a(buf), debugstr_w(bufW)); + } } } From 40543bb5213625a61b7086f5212aab50822cb26c Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Tue, 8 Jun 2021 16:01:54 +0300 Subject: [PATCH 1939/2777] winex11.drv: Send missed KEYUP events on KeymapNotify. Full focus lost / focus gained events on the Windows side are not feasible for X11's FocusIn/FocusOut events generated by keyboard grabs (see XGrabKeyboard()) that are used for example for Atl+Tab handling. Using them would degrade user's experience, especially with our full screen hack, by causing the window to minimize or flash multiple times depending on a game/window manager combo. Because of that the programs may miss on some KEYUP events that happen during the grab, and since there are no focus changes on the Windows side the state doesn't get resynced. This change attempts to improve user experience by syncing any missed key release events that happened while the window haven't had focus on the X11 side. There's no syncing of key presses as those are more problematic because of window manager quirks, e.g. on KDE it may end up syncing the Tab press portion of Alt+Tab. Luckily missing key events for keys that were pressed and not released while the WM had the keyboard grab is not nearly as confusing as stuck keys. For Warhammer: Chaosbane, theHunter: Call of the Wild, Far Cry Primal and many other games that end up with stuck Alt after Alt+Tabbing. CW-Bug-ID: #17046 CW-Bug-ID: #18904 --- dlls/winex11.drv/event.c | 2 ++ dlls/winex11.drv/keyboard.c | 43 +++++++++++++++++++++++++++++++++++-- dlls/winex11.drv/mouse.c | 2 ++ dlls/winex11.drv/x11drv.h | 1 + 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index e760986807c..7656803180b 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -824,6 +824,8 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (event->detail == NotifyPointer) return FALSE; if (hwnd == NtUserGetDesktopWindow()) return FALSE; + x11drv_thread_data()->keymapnotify_hwnd = hwnd; + /* Focus was just restored but it can be right after super was * pressed and gnome-shell needs a bit of time to respond and * toggle the activity view. If we grab the cursor right away diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 1d6cef40efb..f476919f9f5 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1195,11 +1195,19 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) int i, j; BYTE keystate[256]; WORD vkey; + DWORD flags; + KeyCode keycode; + HWND keymapnotify_hwnd; BOOL changed = FALSE; struct { WORD vkey; + WORD scan; WORD pressed; } keys[256]; + struct x11drv_thread_data *thread_data = x11drv_thread_data(); + + keymapnotify_hwnd = thread_data->keymapnotify_hwnd; + thread_data->keymapnotify_hwnd = NULL; if (!get_async_key_state( keystate )) return FALSE; @@ -1214,11 +1222,17 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) { for (j = 0; j < 8; j++) { - vkey = keyc2vkey[(i * 8) + j]; + keycode = (i * 8) + j; + vkey = keyc2vkey[keycode]; /* If multiple keys map to the same vkey, we want to report it as * pressed iff any of them are pressed. */ - if (!keys[vkey & 0xff].vkey) keys[vkey & 0xff].vkey = vkey; + if (!keys[vkey & 0xff].vkey) + { + keys[vkey & 0xff].vkey = vkey; + keys[vkey & 0xff].scan = keyc2scan[keycode] & 0xff; + } + if (event->xkeymap.key_vector[i] & (1<window, event->x, event->y, event->detail ); + x11drv_thread_data()->keymapnotify_hwnd = hwnd; + if (hwnd == x11drv_thread_data()->grab_hwnd) return FALSE; /* simulate a mouse motion event */ diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 6567eb91b2e..12a6cdefa82 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -385,6 +385,7 @@ struct x11drv_thread_data XEvent *current_event; /* event currently being processed */ HWND grab_hwnd; /* window that currently grabs the mouse */ HWND last_focus; /* last window that had focus */ + HWND keymapnotify_hwnd; /* window that should receive modifier release events */ XIM xim; /* input method */ HWND last_xic_hwnd; /* last xic window */ XFontSet font_set; /* international text drawing font set */ From 36d90914e67cd29bd8e14f2918cfd8df1bb93034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 12 Apr 2023 10:14:50 +0200 Subject: [PATCH 1940/2777] HACK: winex11: Create a dedicated thread for input events. CW-Bug-Id: #21879 --- dlls/winex11.drv/desktop.c | 5 +- dlls/winex11.drv/dllmain.c | 36 +++++++++++++ dlls/winex11.drv/event.c | 93 ++++++++++++++++++++++++++++++++++ dlls/winex11.drv/unixlib.h | 2 + dlls/winex11.drv/window.c | 7 ++- dlls/winex11.drv/x11drv.h | 5 ++ dlls/winex11.drv/x11drv_main.c | 11 ++++ 7 files changed, 153 insertions(+), 6 deletions(-) diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c index b7896632ca9..351552674e3 100644 --- a/dlls/winex11.drv/desktop.c +++ b/dlls/winex11.drv/desktop.c @@ -376,8 +376,9 @@ NTSTATUS x11drv_create_desktop( void *arg ) if (!wcsicmp( name, rootW )) return FALSE; /* Create window */ - win_attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | EnterWindowMask | - PointerMotionMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask; + win_attr.event_mask = ExposureMask | FocusChangeMask | EnterWindowMask | + PointerMotionMask | ButtonPressMask | ButtonReleaseMask; + if (!input_thread_hack) win_attr.event_mask |= KeyPressMask | KeyReleaseMask; win_attr.cursor = XCreateFontCursor( display, XC_top_left_arrow ); if (default_visual.visual != DefaultVisual( display, DefaultScreen(display) )) diff --git a/dlls/winex11.drv/dllmain.c b/dlls/winex11.drv/dllmain.c index 3aa0a9875d0..f1553152dcf 100644 --- a/dlls/winex11.drv/dllmain.c +++ b/dlls/winex11.drv/dllmain.c @@ -22,6 +22,8 @@ #include "wine/debug.h" +WINE_DEFAULT_DEBUG_CHANNEL(x11drv); + HMODULE x11drv_module = 0; @@ -53,8 +55,29 @@ static const kernel_callback kernel_callbacks[] = C_ASSERT( NtUserDriverCallbackFirst + ARRAYSIZE(kernel_callbacks) == client_func_last ); +static DWORD CALLBACK input_thread( void *arg ) +{ + NTSTATUS status; + + SetThreadDescription( GetCurrentThread(), L"wine_x11drv_input" ); + + TRACE("\n"); + + /* wait for explorer startup sequence to complete */ + SendMessageW( GetDesktopWindow(), WM_NULL, 0, 0 ); + + for (;;) + { + status = X11DRV_CALL( input_thread, NULL ); + WARN( "input_thread returned %#lx\n", status ); + } + + return 0; +} + BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved ) { + static HANDLE thread; void **callback_table; struct init_params params = { @@ -62,6 +85,13 @@ BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved ) &show_systray, }; + if (reason == DLL_PROCESS_DETACH && !reserved && thread) + { + TerminateThread( thread, -1 ); + WaitForSingleObject( thread, INFINITE ); + CloseHandle( thread ); + } + if (reason != DLL_PROCESS_ATTACH) return TRUE; DisableThreadLibraryCalls( instance ); @@ -69,6 +99,12 @@ BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved ) if (__wine_init_unix_call()) return FALSE; if (X11DRV_CALL( init, ¶ms )) return FALSE; + if (params.input_thread_hack) + { + thread = CreateThread( NULL, 0, input_thread, NULL, 0, NULL ); + if (!thread) ERR( "Failed to create input monitor thread, error %lu\n", GetLastError() ); + } + callback_table = NtCurrentTeb()->Peb->KernelCallbackTable; memcpy( callback_table + NtUserDriverCallbackFirst, kernel_callbacks, sizeof(kernel_callbacks) ); return TRUE; diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 7656803180b..91329a39167 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -147,6 +147,69 @@ static const char * event_names[MAX_EVENT_HANDLERS] = int xinput2_opcode = 0; +static pthread_mutex_t input_cs = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t input_cond = PTHREAD_COND_INITIALIZER; +static Display *input_display; + +/* wait for the input thread to startup and return the input display */ +static Display *x11drv_input_display(void) +{ + if (input_thread_hack && !input_display) + { + pthread_mutex_lock( &input_cs ); + while (!input_display) pthread_cond_wait( &input_cond, &input_cs ); + pthread_mutex_unlock( &input_cs ); + } + + return input_display; +} + +/* set the input display and notify waiters */ +static void x11drv_set_input_display( Display *display ) +{ + if (input_display) return; + + pthread_mutex_lock( &input_cs ); + input_display = display; + pthread_mutex_unlock( &input_cs ); + pthread_cond_broadcast( &input_cond ); +} + +/* add a window to the windows we get input for */ +void x11drv_input_add_window( HWND hwnd, Window window ) +{ + long mask = KeyPressMask | KeyReleaseMask | KeymapStateMask; + Display *display = x11drv_input_display(); + + if (!input_thread_hack) return; + + TRACE( "display %p, window %p/%lx\n", display, hwnd, window ); + + pthread_mutex_lock( &input_cs ); + XSaveContext( display, window, winContext, (char *)hwnd ); + pthread_mutex_unlock( &input_cs ); + + XSelectInput( display, window, mask ); + XFlush( display ); +} + +/* remove a window from the windows we get input for */ +void x11drv_input_remove_window( Window window ) +{ + Display *display = x11drv_input_display(); + + if (!input_thread_hack) return; + + TRACE( "display %p, window %lx\n", display, window ); + + XSelectInput( display, window, 0 ); + XFlush( display ); + + pthread_mutex_lock( &input_cs ); + XDeleteContext( display, window, winContext ); + pthread_mutex_unlock( &input_cs ); +} + /* return the name of an X event */ static const char *dbgstr_event( int type ) { @@ -421,11 +484,13 @@ static inline BOOL call_event_handler( Display *display, XEvent *event ) return FALSE; /* no handler, ignore it */ } + pthread_mutex_lock( &input_cs ); #ifdef GenericEvent if (event->type == GenericEvent) hwnd = 0; else #endif if (XFindContext( display, event->xany.window, winContext, (char **)&hwnd ) != 0) hwnd = 0; /* not for a registered window */ + pthread_mutex_unlock( &input_cs ); if (!hwnd && event->xany.window == root_window) hwnd = NtUserGetDesktopWindow(); TRACE( "%lu %s for hwnd/window %p/%lx\n", @@ -460,6 +525,15 @@ static BOOL process_events( Display *display, Bool (*filter)(Display*, XEvent*,X prev_event.type = 0; while (XCheckIfEvent( display, &event, filter, (char *)arg )) { + switch (event.type) + { + case KeyPress: + case KeyRelease: + case KeymapNotify: + if (input_thread_hack && display != x11drv_input_display()) continue; + break; + } + count++; if (overlay_enabled && filter_event( display, &event, (char *)overlay_filter )) continue; if (steam_keyboard_opened && filter_event( display, &event, (char *)keyboard_filter )) continue; @@ -1055,6 +1129,8 @@ static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event ) { struct x11drv_win_data *data; + x11drv_input_add_window( hwnd, event->xany.window ); + if (event->xany.window == x11drv_thread_data()->clip_window) return TRUE; if (!(data = get_win_data( hwnd ))) return FALSE; @@ -1075,6 +1151,7 @@ static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event ) */ static BOOL X11DRV_UnmapNotify( HWND hwnd, XEvent *event ) { + x11drv_input_remove_window( event->xany.window ); return TRUE; } @@ -2098,3 +2175,19 @@ static BOOL X11DRV_ClientMessage( HWND hwnd, XEvent *xev ) TRACE( "no handler found for %ld\n", event->message_type ); return FALSE; } + +NTSTATUS x11drv_input_thread( void *arg ) +{ + struct x11drv_thread_data *data = x11drv_init_thread_data(); + + x11drv_set_input_display( data->display ); + + for (;;) + { + XEvent event; + XPeekEvent( data->display, &event ); + process_events( data->display, filter_event, QS_ALLINPUT ); + } + + return 0; +} diff --git a/dlls/winex11.drv/unixlib.h b/dlls/winex11.drv/unixlib.h index 0c812896fbc..45377effdc7 100644 --- a/dlls/winex11.drv/unixlib.h +++ b/dlls/winex11.drv/unixlib.h @@ -31,6 +31,7 @@ enum x11drv_funcs unix_tablet_get_packet, unix_tablet_info, unix_tablet_load_info, + unix_input_thread, unix_funcs_count, }; @@ -48,6 +49,7 @@ struct init_params { WNDPROC foreign_window_proc; BOOL *show_systray; + BOOL input_thread_hack; }; struct systray_dock_params diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 05d8977bc34..2e297ed3e05 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -446,11 +446,10 @@ static int get_window_attributes( struct x11drv_win_data *data, XSetWindowAttrib attr->bit_gravity = NorthWestGravity; attr->backing_store = NotUseful; attr->border_pixel = 0; - attr->event_mask = (ExposureMask | PointerMotionMask | - ButtonPressMask | ButtonReleaseMask | EnterWindowMask | - KeyPressMask | KeyReleaseMask | FocusChangeMask | - KeymapStateMask | StructureNotifyMask); + attr->event_mask = (ExposureMask | FocusChangeMask | StructureNotifyMask | + PointerMotionMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask); if (data->managed) attr->event_mask |= PropertyChangeMask; + if (!input_thread_hack) attr->event_mask |= KeyPressMask | KeyReleaseMask | KeymapStateMask; return (CWOverrideRedirect | CWSaveUnder | CWColormap | CWBorderPixel | CWEventMask | CWBitGravity | CWBackingStore); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 12a6cdefa82..e6fd5ef940b 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -599,6 +599,9 @@ extern void (*pXFreeEventData)( Display *display, XEvent /*XGenericEventCookie*/ extern DWORD x11drv_time_to_ticks(Time time) DECLSPEC_HIDDEN; +extern void x11drv_input_add_window( HWND hwnd, Window window ) DECLSPEC_HIDDEN; +extern void x11drv_input_remove_window( Window window ) DECLSPEC_HIDDEN; + /* X11 driver private messages, must be in the range 0x80001000..0x80001fff */ enum x11drv_window_messages { @@ -907,6 +910,7 @@ extern NTSTATUS x11drv_tablet_attach_queue( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_tablet_get_packet( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_tablet_load_info( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_tablet_info( void *arg ) DECLSPEC_HIDDEN; +extern NTSTATUS x11drv_input_thread( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_client_func( enum x11drv_client_funcs func, const void *params, ULONG size ) DECLSPEC_HIDDEN; @@ -1017,5 +1021,6 @@ static inline UINT asciiz_to_unicode( WCHAR *dst, const char *src ) extern BOOL layered_window_client_hack; extern BOOL vulkan_gdi_blit_source_hack; extern BOOL vulkan_disable_child_window_rendering_hack; +extern BOOL input_thread_hack; #endif /* __WINE_X11DRV_H */ diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 0366ed51d8d..923b0037217 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -97,6 +97,7 @@ HANDLE steam_keyboard_event; BOOL layered_window_client_hack = FALSE; BOOL vulkan_gdi_blit_source_hack = FALSE; BOOL vulkan_disable_child_window_rendering_hack = FALSE; +BOOL input_thread_hack = FALSE; static x11drv_error_callback err_callback; /* current callback for error */ static Display *err_callback_display; /* display callback is set for */ @@ -859,11 +860,19 @@ static NTSTATUS x11drv_init( void *arg ) !strcmp(sgi, "1009290") /* Bug 21949 : SWORD ART ONLINE Alicization Lycoris video tearing */ )) || (e && *e != '\0' && *e != '0'); + + e = getenv("WINE_INPUT_THREAD_HACK"); + input_thread_hack = + (sgi && ( + !strcmp(sgi, "1938010") + )) || + (e && *e != '\0' && *e != '0'); } init_user_driver(); X11DRV_DisplayDevices_Init(FALSE); *params->show_systray = show_systray; + params->input_thread_hack = input_thread_hack; return STATUS_SUCCESS; } @@ -1486,6 +1495,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = x11drv_tablet_get_packet, x11drv_tablet_info, x11drv_tablet_load_info, + x11drv_input_thread, }; @@ -1574,6 +1584,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] = x11drv_wow64_tablet_get_packet, x11drv_wow64_tablet_info, x11drv_tablet_load_info, + x11drv_input_thread, }; C_ASSERT( ARRAYSIZE(__wine_unix_call_wow64_funcs) == unix_funcs_count ); From feca43e71a9445087ffdd8547ca484cc75a7b23f Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 7 Aug 2023 21:49:05 +0300 Subject: [PATCH 1941/2777] Revert "winegstreamer: Free the media source work queue outside of the CS." This reverts commit df2606689a51737200cbac94a30a63a368747459. --- 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 c9ee6f227e6..ec201c5437b 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1236,7 +1236,6 @@ static ULONG WINAPI media_source_Release(IMFMediaSource *iface) if (!ref) { IMFMediaSource_Shutdown(iface); - MFUnlockWorkQueue(source->async_commands_queue); IMFPresentationDescriptor_Release(source->pres_desc); IMFMediaEventQueue_Release(source->event_queue); IMFByteStream_Release(source->byte_stream); @@ -1438,6 +1437,8 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) } free(source->streams); + MFUnlockWorkQueue(source->async_commands_queue); + LeaveCriticalSection(&source->cs); return S_OK; From e6914a83167358c191beed955032d6ed678fd459 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 7 Aug 2023 21:49:19 +0300 Subject: [PATCH 1942/2777] Revert "fixup! winegstreamer: Allow concurrent wait_on_sample in the media source." This reverts commit 5034527cb3573fadb11587949ba41ab4d7ab62be. --- dlls/winegstreamer/media_source.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index ec201c5437b..6c00f103662 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -44,12 +44,11 @@ struct media_stream LONG token_queue_count; LONG token_queue_cap; + CRITICAL_SECTION cs; + DWORD stream_id; BOOL active; BOOL eos; - - DWORD busy; - CONDITION_VARIABLE cond; }; enum source_async_op @@ -539,12 +538,17 @@ static void wait_on_sample(struct media_stream *stream, IUnknown *token) TRACE("%p, %p\n", stream, token); - stream->busy = TRUE; + EnterCriticalSection(&stream->cs); + + if (!stream->wg_stream) + { + LeaveCriticalSection(&stream->cs); + return; + } + LeaveCriticalSection(&source->cs); ret = wg_parser_stream_get_buffer(source->wg_parser, stream->wg_stream, &buffer); EnterCriticalSection(&source->cs); - stream->busy = FALSE; - WakeConditionVariable(&stream->cond); if (source->state == SOURCE_SHUTDOWN) WARN("media source has been shutdown, returning\n"); @@ -556,6 +560,8 @@ static void wait_on_sample(struct media_stream *stream, IUnknown *token) IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty_var); dispatch_end_of_presentation(source); } + + LeaveCriticalSection(&stream->cs); } static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) @@ -715,6 +721,8 @@ static ULONG WINAPI media_stream_Release(IMFMediaStream *iface) IMFStreamDescriptor_Release(stream->descriptor); IMFMediaEventQueue_Release(stream->event_queue); flush_token_queue(stream, FALSE); + stream->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&stream->cs); free(stream); } @@ -879,6 +887,9 @@ static HRESULT media_stream_create(IMFMediaSource *source, DWORD id, object->eos = FALSE; object->wg_stream = wg_parser_get_stream(wg_parser, id); + InitializeCriticalSection(&object->cs); + object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs"); + TRACE("Created stream object %p.\n", object); *out = object; @@ -1416,8 +1427,10 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) { struct media_stream *stream = source->streams[i]; wg_parser_stream_disable(stream->wg_stream); - while (stream->busy) - SleepConditionVariableCS(&stream->cond, &source->cs, INFINITE); + + EnterCriticalSection(&stream->cs); + stream->wg_stream = NULL; + LeaveCriticalSection(&stream->cs); } wg_parser_disconnect(source->wg_parser); From 81bb94a17d2c1a39a44ae3bb2874e9eb8085498b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 5 Jul 2023 21:41:58 +0200 Subject: [PATCH 1943/2777] Revert "winegstreamer: Allow concurrent wait_on_sample in the media source." This reverts commit d0cb048bfdedc77164a1a4451b6ceeb8ba1a493a. --- dlls/winegstreamer/media_source.c | 37 ++----------------------------- 1 file changed, 2 insertions(+), 35 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 6c00f103662..e6e78fd4de3 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -44,8 +44,6 @@ struct media_stream LONG token_queue_count; LONG token_queue_cap; - CRITICAL_SECTION cs; - DWORD stream_id; BOOL active; BOOL eos; @@ -534,34 +532,19 @@ static void wait_on_sample(struct media_stream *stream, IUnknown *token) struct media_source *source = impl_from_IMFMediaSource(stream->media_source); PROPVARIANT empty_var = {.vt = VT_EMPTY}; struct wg_parser_buffer buffer; - BOOL ret; TRACE("%p, %p\n", stream, token); - EnterCriticalSection(&stream->cs); - - if (!stream->wg_stream) + if (wg_parser_stream_get_buffer(source->wg_parser, stream->wg_stream, &buffer)) { - LeaveCriticalSection(&stream->cs); - return; - } - - LeaveCriticalSection(&source->cs); - ret = wg_parser_stream_get_buffer(source->wg_parser, stream->wg_stream, &buffer); - EnterCriticalSection(&source->cs); - - if (source->state == SOURCE_SHUTDOWN) - WARN("media source has been shutdown, returning\n"); - else if (ret) send_buffer(stream, &buffer, token); + } else { stream->eos = TRUE; IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty_var); dispatch_end_of_presentation(source); } - - LeaveCriticalSection(&stream->cs); } static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) @@ -721,8 +704,6 @@ static ULONG WINAPI media_stream_Release(IMFMediaStream *iface) IMFStreamDescriptor_Release(stream->descriptor); IMFMediaEventQueue_Release(stream->event_queue); flush_token_queue(stream, FALSE); - stream->cs.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&stream->cs); free(stream); } @@ -887,9 +868,6 @@ static HRESULT media_stream_create(IMFMediaSource *source, DWORD id, object->eos = FALSE; object->wg_stream = wg_parser_get_stream(wg_parser, id); - InitializeCriticalSection(&object->cs); - object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs"); - TRACE("Created stream object %p.\n", object); *out = object; @@ -1409,7 +1387,6 @@ static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) { struct media_source *source = impl_from_IMFMediaSource(iface); - UINT i; TRACE("%p.\n", iface); @@ -1423,16 +1400,6 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) source->state = SOURCE_SHUTDOWN; - for (i = 0; i < source->stream_count; i++) - { - struct media_stream *stream = source->streams[i]; - wg_parser_stream_disable(stream->wg_stream); - - EnterCriticalSection(&stream->cs); - stream->wg_stream = NULL; - LeaveCriticalSection(&stream->cs); - } - wg_parser_disconnect(source->wg_parser); source->read_thread_shutdown = true; From 33c22b48bce23079956a9d9d99fb551c45c324d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 14 Apr 2023 15:19:52 +0200 Subject: [PATCH 1944/2777] Revert "winegstreamer: add http/https/rtsp scheme handler" This reverts commit 43109ae880034dd9e8c7053ef8fa596931eea3d8. --- dlls/winegstreamer/Makefile.in | 1 - dlls/winegstreamer/gst_private.h | 2 - dlls/winegstreamer/mfplat.c | 3 - dlls/winegstreamer/scheme_handler.c | 408 ------------------- dlls/winegstreamer/winegstreamer.rgs | 28 -- dlls/winegstreamer/winegstreamer_classes.idl | 7 - 6 files changed, 449 deletions(-) delete mode 100644 dlls/winegstreamer/scheme_handler.c diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index ea232db3ff1..39faf453fe8 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -16,7 +16,6 @@ C_SRCS = \ quartz_parser.c \ quartz_transform.c \ resampler.c \ - scheme_handler.c \ unixlib.c \ video_decoder.c \ video_processor.c \ diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index e4d0af8af44..ab489ea7d20 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -149,12 +149,10 @@ HRESULT wg_transform_read_mf(struct wg_transform *transform, IMFSample *sample, HRESULT wg_transform_read_quartz(struct wg_transform *transform, struct wg_sample *sample); HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj); -HRESULT winegstreamer_create_media_source_from_uri(const WCHAR *uri, IUnknown **out_media_source) DECLSPEC_HIDDEN; HRESULT aac_decoder_create(REFIID riid, void **ret); HRESULT h264_decoder_create(REFIID riid, void **ret); HRESULT video_processor_create(REFIID riid, void **ret); -HRESULT gstreamer_scheme_handler_construct(REFIID riid, void **ret) DECLSPEC_HIDDEN; extern const GUID MFAudioFormat_RAW_AAC; diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index c1deffbb1cc..ea5ea33ee9d 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -122,8 +122,6 @@ static const IClassFactoryVtbl class_factory_vtbl = static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; -static const GUID CLSID_GStreamerSchemePlugin = {0x587eeb6a,0x7336,0x4ebd,{0xa4,0xf2,0x91,0xc9,0x48,0xde,0x62,0x2c}}; - static const struct class_object { const GUID *clsid; @@ -135,7 +133,6 @@ class_objects[] = { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, { &CLSID_MSAACDecMFT, &aac_decoder_create }, { &CLSID_MSH264DecoderMFT, &h264_decoder_create }, - { &CLSID_GStreamerSchemePlugin, &gstreamer_scheme_handler_construct }, }; HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) diff --git a/dlls/winegstreamer/scheme_handler.c b/dlls/winegstreamer/scheme_handler.c deleted file mode 100644 index 1aa36b8b7a5..00000000000 --- a/dlls/winegstreamer/scheme_handler.c +++ /dev/null @@ -1,408 +0,0 @@ -#include - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "mfidl.h" -#include "mferror.h" -#include "mfapi.h" -#include "gst_private.h" - -#include "wine/debug.h" -#include "wine/list.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mfplat); - -struct gstreamer_scheme_handler_result -{ - struct list entry; - IMFAsyncResult *result; - IUnknown *object; -}; - -struct gstreamer_scheme_handler -{ - IMFSchemeHandler IMFSchemeHandler_iface; - IMFAsyncCallback IMFAsyncCallback_iface; - LONG refcount; - struct list results; - CRITICAL_SECTION cs; -}; - -static struct gstreamer_scheme_handler *impl_from_IMFSchemeHandler(IMFSchemeHandler *iface) -{ - return CONTAINING_RECORD(iface, struct gstreamer_scheme_handler, IMFSchemeHandler_iface); -} - -static struct gstreamer_scheme_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) -{ - return CONTAINING_RECORD(iface, struct gstreamer_scheme_handler, IMFAsyncCallback_iface); -} - -static HRESULT WINAPI gstreamer_scheme_handler_QueryIntace(IMFSchemeHandler *iface, REFIID riid, void **obj) -{ - TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); - - if (IsEqualIID(riid, &IID_IMFSchemeHandler) || - IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IMFSchemeHandler_AddRef(iface); - return S_OK; - } - - WARN("Unsupported %s.\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI gstreamer_scheme_handler_AddRef(IMFSchemeHandler *iface) -{ - struct gstreamer_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); - ULONG refcount = InterlockedIncrement(&handler->refcount); - - TRACE("%p, refcount %lu.\n", handler, refcount); - - return refcount; -} - -static ULONG WINAPI gstreamer_scheme_handler_Release(IMFSchemeHandler *iface) -{ - struct gstreamer_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); - ULONG refcount = InterlockedDecrement(&handler->refcount); - struct gstreamer_scheme_handler_result *result, *next; - - TRACE("%p, refcount %lu.\n", iface, refcount); - - if (!refcount) - { - LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct gstreamer_scheme_handler_result, entry) - { - list_remove(&result->entry); - IMFAsyncResult_Release(result->result); - if (result->object) - IUnknown_Release(result->object); - free(result); - } - DeleteCriticalSection(&handler->cs); - free(handler); - } - - return refcount; -} - -struct create_object_context -{ - IUnknown IUnknown_iface; - LONG refcount; - - IPropertyStore *props; - WCHAR *url; - DWORD flags; -}; - -static struct create_object_context *impl_from_IUnknown(IUnknown *iface) -{ - return CONTAINING_RECORD(iface, struct create_object_context, IUnknown_iface); -} - -static HRESULT WINAPI create_object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj) -{ - TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); - - if (IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IUnknown_AddRef(iface); - return S_OK; - } - - WARN("Unsupported %s.\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI create_object_context_AddRef(IUnknown *iface) -{ - struct create_object_context *context = impl_from_IUnknown(iface); - ULONG refcount = InterlockedIncrement(&context->refcount); - - TRACE("%p, refcount %lu.\n", iface, refcount); - - return refcount; -} - -static ULONG WINAPI create_object_context_Release(IUnknown *iface) -{ - struct create_object_context *context = impl_from_IUnknown(iface); - ULONG refcount = InterlockedDecrement(&context->refcount); - - TRACE("%p, refcount %lu.\n", iface, refcount); - - if (!refcount) - { - if (context->props) - IPropertyStore_Release(context->props); - free(context->url); - free(context); - } - - return refcount; -} - -static const IUnknownVtbl create_object_context_vtbl = -{ - create_object_context_QueryInterface, - create_object_context_AddRef, - create_object_context_Release, -}; - -static HRESULT WINAPI gstreamer_scheme_handler_BeginCreateObject(IMFSchemeHandler *iface, const WCHAR *url, DWORD flags, - IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state) -{ - struct gstreamer_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); - struct create_object_context *context; - IMFAsyncResult *caller, *item; - HRESULT hr; - - TRACE("%p, %s, %#lx, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state); - - if (cancel_cookie) - *cancel_cookie = NULL; - - if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller))) - return hr; - - if (!(context = malloc(sizeof(*context)))) - { - IMFAsyncResult_Release(caller); - return E_OUTOFMEMORY; - } - - context->IUnknown_iface.lpVtbl = &create_object_context_vtbl; - context->refcount = 1; - context->props = props; - if (context->props) - IPropertyStore_AddRef(context->props); - context->flags = flags; - context->url = wcsdup(url); - if (!context->url) - { - IMFAsyncResult_Release(caller); - IUnknown_Release(&context->IUnknown_iface); - return E_OUTOFMEMORY; - } - - hr = MFCreateAsyncResult(&context->IUnknown_iface, &handler->IMFAsyncCallback_iface, (IUnknown *)caller, &item); - IUnknown_Release(&context->IUnknown_iface); - if (SUCCEEDED(hr)) - { - if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item))) - { - if (cancel_cookie) - { - *cancel_cookie = (IUnknown *)caller; - IUnknown_AddRef(*cancel_cookie); - } - } - - IMFAsyncResult_Release(item); - } - IMFAsyncResult_Release(caller); - - return hr; -} - -static HRESULT WINAPI gstreamer_scheme_handler_EndCreateObject(IMFSchemeHandler *iface, IMFAsyncResult *result, - MF_OBJECT_TYPE *obj_type, IUnknown **object) -{ - struct gstreamer_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); - struct gstreamer_scheme_handler_result *found = NULL, *cur; - HRESULT hr; - - TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object); - - EnterCriticalSection(&handler->cs); - - LIST_FOR_EACH_ENTRY(cur, &handler->results, struct gstreamer_scheme_handler_result, entry) - { - if (result == cur->result) - { - list_remove(&cur->entry); - found = cur; - break; - } - } - - LeaveCriticalSection(&handler->cs); - - if (found) - { - *obj_type = MF_OBJECT_MEDIASOURCE; - *object = found->object; - hr = IMFAsyncResult_GetStatus(found->result); - IMFAsyncResult_Release(found->result); - free(found); - } - else - { - *obj_type = MF_OBJECT_INVALID; - *object = NULL; - hr = MF_E_UNEXPECTED; - } - - return hr; -} - -static HRESULT WINAPI gstreamer_scheme_handler_CancelObjectCreation(IMFSchemeHandler *iface, IUnknown *cancel_cookie) -{ - struct gstreamer_scheme_handler *handler = impl_from_IMFSchemeHandler(iface); - struct gstreamer_scheme_handler_result *found = NULL, *cur; - - TRACE("%p, %p.\n", iface, cancel_cookie); - - EnterCriticalSection(&handler->cs); - - LIST_FOR_EACH_ENTRY(cur, &handler->results, struct gstreamer_scheme_handler_result, entry) - { - if (cancel_cookie == (IUnknown *)cur->result) - { - list_remove(&cur->entry); - found = cur; - break; - } - } - - LeaveCriticalSection(&handler->cs); - - if (found) - { - IMFAsyncResult_Release(found->result); - if (found->object) - IUnknown_Release(found->object); - free(found); - } - - return found ? S_OK : MF_E_UNEXPECTED; -} - -static const IMFSchemeHandlerVtbl gstreamer_scheme_handler_vtbl = -{ - gstreamer_scheme_handler_QueryIntace, - gstreamer_scheme_handler_AddRef, - gstreamer_scheme_handler_Release, - gstreamer_scheme_handler_BeginCreateObject, - gstreamer_scheme_handler_EndCreateObject, - gstreamer_scheme_handler_CancelObjectCreation, -}; - -static HRESULT WINAPI gstreamer_scheme_handler_callback_QueryIntace(IMFAsyncCallback *iface, REFIID riid, void **obj) -{ - if (IsEqualIID(riid, &IID_IMFAsyncCallback) || - IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IMFAsyncCallback_AddRef(iface); - return S_OK; - } - - WARN("Unsupported %s.\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI gstreamer_scheme_handler_callback_AddRef(IMFAsyncCallback *iface) -{ - struct gstreamer_scheme_handler *handler = impl_from_IMFAsyncCallback(iface); - return IMFSchemeHandler_AddRef(&handler->IMFSchemeHandler_iface); -} - -static ULONG WINAPI gstreamer_scheme_handler_callback_Release(IMFAsyncCallback *iface) -{ - struct gstreamer_scheme_handler *handler = impl_from_IMFAsyncCallback(iface); - return IMFSchemeHandler_Release(&handler->IMFSchemeHandler_iface); -} - -static HRESULT WINAPI gstreamer_scheme_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) -{ - return E_NOTIMPL; -} - -static HRESULT WINAPI gstreamer_scheme_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) -{ - IMFAsyncResult *caller; - struct gstreamer_scheme_handler *handler = impl_from_IMFAsyncCallback(iface); - struct gstreamer_scheme_handler_result *handler_result; - IUnknown *object = NULL, *context_object; - struct create_object_context *context; - HRESULT hr; - - caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result); - - if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object))) - { - WARN("Expected context set for callee result.\n"); - return hr; - } - - context = impl_from_IUnknown(context_object); - - hr = winegstreamer_create_media_source_from_uri(context->url, &object); - - handler_result = malloc(sizeof(*handler_result)); - if (handler_result) - { - handler_result->result = caller; - IMFAsyncResult_AddRef(handler_result->result); - - handler_result->object = object; - - EnterCriticalSection(&handler->cs); - list_add_tail(&handler->results, &handler_result->entry); - LeaveCriticalSection(&handler->cs); - } - else - { - if (object) - IUnknown_Release(object); - hr = E_OUTOFMEMORY; - } - - IMFAsyncResult_SetStatus(caller, hr); - MFInvokeCallback(caller); - - return S_OK; -} - -static const IMFAsyncCallbackVtbl gstreamer_scheme_handler_callback_vtbl = -{ - gstreamer_scheme_handler_callback_QueryIntace, - gstreamer_scheme_handler_callback_AddRef, - gstreamer_scheme_handler_callback_Release, - gstreamer_scheme_handler_callback_GetParameters, - gstreamer_scheme_handler_callback_Invoke, -}; - -HRESULT gstreamer_scheme_handler_construct(REFIID riid, void **obj) -{ - struct gstreamer_scheme_handler *handler; - HRESULT hr; - - TRACE("%s, %p.\n", debugstr_guid(riid), obj); - - if (!(handler = calloc(1, sizeof(*handler)))) - return E_OUTOFMEMORY; - - handler->IMFSchemeHandler_iface.lpVtbl = &gstreamer_scheme_handler_vtbl; - handler->IMFAsyncCallback_iface.lpVtbl = &gstreamer_scheme_handler_callback_vtbl; - handler->refcount = 1; - list_init(&handler->results); - InitializeCriticalSection(&handler->cs); - - hr = IMFSchemeHandler_QueryInterface(&handler->IMFSchemeHandler_iface, riid, obj); - IMFSchemeHandler_Release(&handler->IMFSchemeHandler_iface); - - return hr; -} - diff --git a/dlls/winegstreamer/winegstreamer.rgs b/dlls/winegstreamer/winegstreamer.rgs index c50d3a05747..923ba673f8c 100644 --- a/dlls/winegstreamer/winegstreamer.rgs +++ b/dlls/winegstreamer/winegstreamer.rgs @@ -12,31 +12,3 @@ HKCR } } } - -HKLM -{ - NoRemove 'Software' - { - NoRemove 'Microsoft' - { - NoRemove 'Windows Media Foundation' - { - NoRemove 'SchemeHandlers' - { - 'http:' - { - val '{587eeb6a-7336-4ebd-a4f2-91c948de622c}' = s 'GStreamer Scheme Handler' - } - 'https:' - { - val '{587eeb6a-7336-4ebd-a4f2-91c948de622c}' = s 'GStreamer Scheme Handler' - } - 'rtsp:' - { - val '{587eeb6a-7336-4ebd-a4f2-91c948de622c}' = s 'GStreamer Scheme Handler' - } - } - } - } - } -} diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index 1b87dcde716..30a99c9acfb 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl @@ -111,10 +111,3 @@ coclass CResamplerMediaObject {} uuid(98230571-0087-4204-b020-3282538e57d3) ] coclass CColorConvertDMO {} - -[ - helpstring("GStreamer scheme handler"), - threading(both), - uuid(587eeb6a-7336-4ebd-a4f2-91c948de622c) -] -coclass GStreamerSchemePlugin { } From 0499f7f15721c8956624dbf5ce2fd53c2e27a857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 May 2023 10:39:18 +0200 Subject: [PATCH 1945/2777] winegstreamer: Move GStreamerByteStreamHandler to mf_handler.c. CW-Bug-Id: #21953 --- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/media_source.c | 463 +---------------------------- dlls/winegstreamer/mf_handler.c | 466 ++++++++++++++++++++++++++++++ 4 files changed, 470 insertions(+), 461 deletions(-) create mode 100644 dlls/winegstreamer/mf_handler.c diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 39faf453fe8..49b4dd2c631 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -12,6 +12,7 @@ C_SRCS = \ h264_decoder.c \ main.c \ media_source.c \ + mf_handler.c \ mfplat.c \ quartz_parser.c \ quartz_transform.c \ diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index ab489ea7d20..fde5c231c07 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -149,6 +149,7 @@ HRESULT wg_transform_read_mf(struct wg_transform *transform, IMFSample *sample, HRESULT wg_transform_read_quartz(struct wg_transform *transform, struct wg_sample *sample); HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj); +HRESULT media_source_create_from_stream(IMFByteStream *stream, IMFMediaSource **out); HRESULT aac_decoder_create(REFIID riid, void **ret); HRESULT h264_decoder_create(REFIID riid, void **ret); diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index e6e78fd4de3..78e507347a6 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1441,7 +1441,7 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = media_source_Shutdown, }; -static HRESULT media_source_constructor(IMFByteStream *bytestream, const WCHAR *uri, struct media_source **out_media_source) +HRESULT media_source_create_from_stream(IMFByteStream *bytestream, IMFMediaSource **out) { BOOL video_selected = FALSE, audio_selected = FALSE; IMFStreamDescriptor **descriptors = NULL; @@ -1608,7 +1608,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, const WCHAR * object->state = SOURCE_STOPPED; - *out_media_source = object; + *out = &object->IMFMediaSource_iface; return S_OK; fail: @@ -1646,462 +1646,3 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, const WCHAR * free(object); return hr; } - -HRESULT winegstreamer_create_media_source_from_uri(const WCHAR *uri, IUnknown **out_object) -{ - struct media_source *object; - IMFByteStream *bytestream; - IStream *stream; - HRESULT hr; - - if (FAILED(hr = CreateStreamOnHGlobal(0, TRUE, &stream))) - return hr; - - hr = MFCreateMFByteStreamOnStream(stream, &bytestream); - IStream_Release(stream); - if (FAILED(hr)) - return hr; - - if (SUCCEEDED(hr = media_source_constructor(bytestream, uri, &object))) - *out_object = (IUnknown*)&object->IMFMediaSource_iface; - - IMFByteStream_Release(bytestream); - return hr; -} - -struct winegstreamer_stream_handler_result -{ - struct list entry; - IMFAsyncResult *result; - MF_OBJECT_TYPE obj_type; - IUnknown *object; -}; - -struct winegstreamer_stream_handler -{ - IMFByteStreamHandler IMFByteStreamHandler_iface; - IMFAsyncCallback IMFAsyncCallback_iface; - LONG refcount; - struct list results; - CRITICAL_SECTION cs; -}; - -static struct winegstreamer_stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface) -{ - return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFByteStreamHandler_iface); -} - -static struct winegstreamer_stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) -{ - return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFAsyncCallback_iface); -} - -static HRESULT WINAPI winegstreamer_stream_handler_QueryInterface(IMFByteStreamHandler *iface, REFIID riid, void **obj) -{ - TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); - - if (IsEqualIID(riid, &IID_IMFByteStreamHandler) || - IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IMFByteStreamHandler_AddRef(iface); - return S_OK; - } - - WARN("Unsupported %s.\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI winegstreamer_stream_handler_AddRef(IMFByteStreamHandler *iface) -{ - struct winegstreamer_stream_handler *handler = impl_from_IMFByteStreamHandler(iface); - ULONG refcount = InterlockedIncrement(&handler->refcount); - - TRACE("%p, refcount %lu.\n", handler, refcount); - - return refcount; -} - -static ULONG WINAPI winegstreamer_stream_handler_Release(IMFByteStreamHandler *iface) -{ - struct winegstreamer_stream_handler *handler = impl_from_IMFByteStreamHandler(iface); - ULONG refcount = InterlockedDecrement(&handler->refcount); - struct winegstreamer_stream_handler_result *result, *next; - - TRACE("%p, refcount %lu.\n", iface, refcount); - - if (!refcount) - { - LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct winegstreamer_stream_handler_result, entry) - { - list_remove(&result->entry); - IMFAsyncResult_Release(result->result); - if (result->object) - IUnknown_Release(result->object); - free(result); - } - DeleteCriticalSection(&handler->cs); - free(handler); - } - - return refcount; -} - -struct create_object_context -{ - IUnknown IUnknown_iface; - LONG refcount; - - IPropertyStore *props; - IMFByteStream *stream; - WCHAR *url; - DWORD flags; -}; - -static struct create_object_context *impl_from_IUnknown(IUnknown *iface) -{ - return CONTAINING_RECORD(iface, struct create_object_context, IUnknown_iface); -} - -static HRESULT WINAPI create_object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj) -{ - TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); - - if (IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IUnknown_AddRef(iface); - return S_OK; - } - - WARN("Unsupported %s.\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI create_object_context_AddRef(IUnknown *iface) -{ - struct create_object_context *context = impl_from_IUnknown(iface); - ULONG refcount = InterlockedIncrement(&context->refcount); - - TRACE("%p, refcount %lu.\n", iface, refcount); - - return refcount; -} - -static ULONG WINAPI create_object_context_Release(IUnknown *iface) -{ - struct create_object_context *context = impl_from_IUnknown(iface); - ULONG refcount = InterlockedDecrement(&context->refcount); - - TRACE("%p, refcount %lu.\n", iface, refcount); - - if (!refcount) - { - if (context->props) - IPropertyStore_Release(context->props); - if (context->stream) - IMFByteStream_Release(context->stream); - free(context->url); - free(context); - } - - return refcount; -} - -static const IUnknownVtbl create_object_context_vtbl = -{ - create_object_context_QueryInterface, - create_object_context_AddRef, - create_object_context_Release, -}; - -static HRESULT WINAPI winegstreamer_stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags, - IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state) -{ - struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface); - struct create_object_context *context; - IMFAsyncResult *caller, *item; - HRESULT hr; - - TRACE("%p, %s, %#lx, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state); - - if (cancel_cookie) - *cancel_cookie = NULL; - - if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller))) - return hr; - - if (!(context = calloc(1, sizeof(*context)))) - { - IMFAsyncResult_Release(caller); - return E_OUTOFMEMORY; - } - - context->IUnknown_iface.lpVtbl = &create_object_context_vtbl; - context->refcount = 1; - context->props = props; - if (context->props) - IPropertyStore_AddRef(context->props); - context->flags = flags; - context->stream = stream; - if (context->stream) - IMFByteStream_AddRef(context->stream); - if (url) - context->url = wcsdup(url); - if (!context->stream) - { - IMFAsyncResult_Release(caller); - IUnknown_Release(&context->IUnknown_iface); - return E_OUTOFMEMORY; - } - - hr = MFCreateAsyncResult(&context->IUnknown_iface, &this->IMFAsyncCallback_iface, (IUnknown *)caller, &item); - IUnknown_Release(&context->IUnknown_iface); - if (SUCCEEDED(hr)) - { - if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item))) - { - if (cancel_cookie) - { - *cancel_cookie = (IUnknown *)caller; - IUnknown_AddRef(*cancel_cookie); - } - } - - IMFAsyncResult_Release(item); - } - IMFAsyncResult_Release(caller); - - return hr; -} - -static HRESULT WINAPI winegstreamer_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result, - MF_OBJECT_TYPE *obj_type, IUnknown **object) -{ - struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface); - struct winegstreamer_stream_handler_result *found = NULL, *cur; - HRESULT hr; - - TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object); - - EnterCriticalSection(&this->cs); - - LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry) - { - if (result == cur->result) - { - list_remove(&cur->entry); - found = cur; - break; - } - } - - LeaveCriticalSection(&this->cs); - - if (found) - { - *obj_type = found->obj_type; - *object = found->object; - hr = IMFAsyncResult_GetStatus(found->result); - IMFAsyncResult_Release(found->result); - free(found); - } - else - { - *obj_type = MF_OBJECT_INVALID; - *object = NULL; - hr = MF_E_UNEXPECTED; - } - - return hr; -} - -static HRESULT WINAPI winegstreamer_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cancel_cookie) -{ - struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface); - struct winegstreamer_stream_handler_result *found = NULL, *cur; - - TRACE("%p, %p.\n", iface, cancel_cookie); - - EnterCriticalSection(&this->cs); - - LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry) - { - if (cancel_cookie == (IUnknown *)cur->result) - { - list_remove(&cur->entry); - found = cur; - break; - } - } - - LeaveCriticalSection(&this->cs); - - if (found) - { - IMFAsyncResult_Release(found->result); - if (found->object) - IUnknown_Release(found->object); - free(found); - } - - return found ? S_OK : MF_E_UNEXPECTED; -} - -static HRESULT WINAPI winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes) -{ - FIXME("stub (%p %p)\n", iface, bytes); - return E_NOTIMPL; -} - -static const IMFByteStreamHandlerVtbl winegstreamer_stream_handler_vtbl = -{ - winegstreamer_stream_handler_QueryInterface, - winegstreamer_stream_handler_AddRef, - winegstreamer_stream_handler_Release, - winegstreamer_stream_handler_BeginCreateObject, - winegstreamer_stream_handler_EndCreateObject, - winegstreamer_stream_handler_CancelObjectCreation, - winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution, -}; - -static HRESULT WINAPI winegstreamer_stream_handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) -{ - if (IsEqualIID(riid, &IID_IMFAsyncCallback) || - IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IMFAsyncCallback_AddRef(iface); - return S_OK; - } - - WARN("Unsupported %s.\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI winegstreamer_stream_handler_callback_AddRef(IMFAsyncCallback *iface) -{ - struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface); - return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface); -} - -static ULONG WINAPI winegstreamer_stream_handler_callback_Release(IMFAsyncCallback *iface) -{ - struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface); - return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface); -} - -static HRESULT WINAPI winegstreamer_stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) -{ - return E_NOTIMPL; -} - -static HRESULT winegstreamer_stream_handler_create_object(struct winegstreamer_stream_handler *This, WCHAR *url, IMFByteStream *stream, DWORD flags, - IPropertyStore *props, IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type) -{ - TRACE("%p, %s, %p, %#lx, %p, %p, %p.\n", This, debugstr_w(url), stream, flags, props, out_object, out_obj_type); - - if (flags & MF_RESOLUTION_MEDIASOURCE) - { - HRESULT hr; - struct media_source *new_source; - - if (FAILED(hr = media_source_constructor(stream, NULL, &new_source))) - return hr; - - TRACE("->(%p)\n", new_source); - - *out_object = (IUnknown*)&new_source->IMFMediaSource_iface; - *out_obj_type = MF_OBJECT_MEDIASOURCE; - - return S_OK; - } - else - { - FIXME("Unhandled flags %#lx.\n", flags); - return E_NOTIMPL; - } -} - -static HRESULT WINAPI winegstreamer_stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) -{ - struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface); - struct winegstreamer_stream_handler_result *handler_result; - MF_OBJECT_TYPE obj_type = MF_OBJECT_INVALID; - IUnknown *object = NULL, *context_object; - struct create_object_context *context; - IMFAsyncResult *caller; - HRESULT hr; - - caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result); - - if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object))) - { - WARN("Expected context set for callee result.\n"); - return hr; - } - - context = impl_from_IUnknown(context_object); - - hr = winegstreamer_stream_handler_create_object(handler, context->url, context->stream, context->flags, context->props, &object, &obj_type); - - if ((handler_result = malloc(sizeof(*handler_result)))) - { - handler_result->result = caller; - IMFAsyncResult_AddRef(handler_result->result); - handler_result->obj_type = obj_type; - handler_result->object = object; - - EnterCriticalSection(&handler->cs); - list_add_tail(&handler->results, &handler_result->entry); - LeaveCriticalSection(&handler->cs); - } - else - { - if (object) - IUnknown_Release(object); - hr = E_OUTOFMEMORY; - } - - IUnknown_Release(&context->IUnknown_iface); - - IMFAsyncResult_SetStatus(caller, hr); - MFInvokeCallback(caller); - - return S_OK; -} - -static const IMFAsyncCallbackVtbl winegstreamer_stream_handler_callback_vtbl = -{ - winegstreamer_stream_handler_callback_QueryInterface, - winegstreamer_stream_handler_callback_AddRef, - winegstreamer_stream_handler_callback_Release, - winegstreamer_stream_handler_callback_GetParameters, - winegstreamer_stream_handler_callback_Invoke, -}; - -HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) -{ - struct winegstreamer_stream_handler *this; - HRESULT hr; - - TRACE("%s, %p.\n", debugstr_guid(riid), obj); - - if (!(this = calloc(1, sizeof(*this)))) - return E_OUTOFMEMORY; - - list_init(&this->results); - InitializeCriticalSection(&this->cs); - - this->IMFByteStreamHandler_iface.lpVtbl = &winegstreamer_stream_handler_vtbl; - this->IMFAsyncCallback_iface.lpVtbl = &winegstreamer_stream_handler_callback_vtbl; - this->refcount = 1; - - hr = IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface, riid, obj); - IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface); - - return hr; -} diff --git a/dlls/winegstreamer/mf_handler.c b/dlls/winegstreamer/mf_handler.c new file mode 100644 index 00000000000..ffb12be38e3 --- /dev/null +++ b/dlls/winegstreamer/mf_handler.c @@ -0,0 +1,466 @@ +/* + * Copyright 2020 Derek Lesho + * Copyright 2020 Zebediah Figura 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 + */ + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "mfidl.h" +#include "mferror.h" +#include "mfapi.h" +#include "gst_private.h" + +#include "wine/debug.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +struct result_entry +{ + struct list entry; + IMFAsyncResult *result; + MF_OBJECT_TYPE type; + IUnknown *object; +}; + +struct async_create_object +{ + IUnknown IUnknown_iface; + LONG refcount; + + IPropertyStore *props; + IMFByteStream *stream; + WCHAR *url; + DWORD flags; +}; + +static struct async_create_object *impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct async_create_object, IUnknown_iface); +} + +static HRESULT WINAPI async_create_object_QueryInterface(IUnknown *iface, REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IUnknown_AddRef(iface); + return S_OK; + } + + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI async_create_object_AddRef(IUnknown *iface) +{ + struct async_create_object *async = impl_from_IUnknown(iface); + ULONG refcount = InterlockedIncrement(&async->refcount); + TRACE("%p, refcount %lu.\n", iface, refcount); + return refcount; +} + +static ULONG WINAPI async_create_object_Release(IUnknown *iface) +{ + struct async_create_object *async = impl_from_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&async->refcount); + + TRACE("%p, refcount %lu.\n", iface, refcount); + + if (!refcount) + { + if (async->props) + IPropertyStore_Release(async->props); + if (async->stream) + IMFByteStream_Release(async->stream); + free(async->url); + free(async); + } + + return refcount; +} + +static const IUnknownVtbl async_create_object_vtbl = +{ + async_create_object_QueryInterface, + async_create_object_AddRef, + async_create_object_Release, +}; + +struct handler +{ + IMFByteStreamHandler IMFByteStreamHandler_iface; + IMFAsyncCallback IMFAsyncCallback_iface; + LONG refcount; + struct list results; + CRITICAL_SECTION cs; +}; + +static struct handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct handler, IMFAsyncCallback_iface); +} + +static struct handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface) +{ + return CONTAINING_RECORD(iface, struct handler, IMFByteStreamHandler_iface); +} + +static HRESULT WINAPI async_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IMFAsyncCallback) + || IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFAsyncCallback_AddRef(iface); + return S_OK; + } + + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI async_callback_AddRef(IMFAsyncCallback *iface) +{ + struct handler *handler = impl_from_IMFAsyncCallback(iface); + return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface); +} + +static ULONG WINAPI async_callback_Release(IMFAsyncCallback *iface) +{ + struct handler *handler = impl_from_IMFAsyncCallback(iface); + return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface); +} + +static HRESULT WINAPI async_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) +{ + return E_NOTIMPL; +} + +static HRESULT stream_handler_create_object(struct handler *handler, WCHAR *url, + IMFByteStream *stream, DWORD flags, IPropertyStore *props, IUnknown **object, MF_OBJECT_TYPE *type) +{ + TRACE("%p, %s, %p, %#lx, %p, %p, %p.\n", handler, debugstr_w(url), stream, flags, props, object, type); + + if (flags & MF_RESOLUTION_MEDIASOURCE) + { + HRESULT hr; + + if (FAILED(hr = media_source_create_from_stream(stream, (IMFMediaSource **)object))) + return hr; + + *type = MF_OBJECT_MEDIASOURCE; + return S_OK; + } + else + { + FIXME("Unhandled flags %#lx.\n", flags); + return E_NOTIMPL; + } +} + +static HRESULT WINAPI async_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct handler *handler = impl_from_IMFAsyncCallback(iface); + MF_OBJECT_TYPE type = MF_OBJECT_INVALID; + IUnknown *object = NULL, *context_object; + struct async_create_object *async; + struct result_entry *entry; + IMFAsyncResult *caller; + HRESULT hr; + + caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result); + + if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object))) + { + WARN("Expected context set for callee result.\n"); + return hr; + } + + async = impl_from_IUnknown(context_object); + + hr = stream_handler_create_object(handler, async->url, async->stream, async->flags, + async->props, &object, &type); + + if ((entry = malloc(sizeof(*entry)))) + { + entry->result = caller; + IMFAsyncResult_AddRef(entry->result); + entry->type = type; + entry->object = object; + + EnterCriticalSection(&handler->cs); + list_add_tail(&handler->results, &entry->entry); + LeaveCriticalSection(&handler->cs); + } + else + { + if (object) + IUnknown_Release(object); + hr = E_OUTOFMEMORY; + } + + IUnknown_Release(&async->IUnknown_iface); + + IMFAsyncResult_SetStatus(caller, hr); + MFInvokeCallback(caller); + + return S_OK; +} + +static const IMFAsyncCallbackVtbl async_callback_vtbl = +{ + async_callback_QueryInterface, + async_callback_AddRef, + async_callback_Release, + async_callback_GetParameters, + async_callback_Invoke, +}; + +static HRESULT WINAPI stream_handler_QueryInterface(IMFByteStreamHandler *iface, REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFByteStreamHandler) + || IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFByteStreamHandler_AddRef(iface); + return S_OK; + } + + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI stream_handler_AddRef(IMFByteStreamHandler *iface) +{ + struct handler *handler = impl_from_IMFByteStreamHandler(iface); + ULONG refcount = InterlockedIncrement(&handler->refcount); + TRACE("%p, refcount %lu.\n", handler, refcount); + return refcount; +} + +static ULONG WINAPI stream_handler_Release(IMFByteStreamHandler *iface) +{ + struct handler *handler = impl_from_IMFByteStreamHandler(iface); + ULONG refcount = InterlockedDecrement(&handler->refcount); + struct result_entry *entry, *next; + + TRACE("%p, refcount %lu.\n", iface, refcount); + + if (!refcount) + { + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &handler->results, struct result_entry, entry) + { + list_remove(&entry->entry); + IMFAsyncResult_Release(entry->result); + if (entry->object) + IUnknown_Release(entry->object); + free(entry); + } + DeleteCriticalSection(&handler->cs); + free(handler); + } + + return refcount; +} + +static HRESULT WINAPI stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, + IMFByteStream *stream, const WCHAR *url, DWORD flags, IPropertyStore *props, + IUnknown **cookie, IMFAsyncCallback *callback, IUnknown *state) +{ + struct handler *handler = impl_from_IMFByteStreamHandler(iface); + struct async_create_object *async; + IMFAsyncResult *caller, *item; + HRESULT hr; + + TRACE("%p, %s, %#lx, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cookie, callback, state); + + if (cookie) + *cookie = NULL; + + if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller))) + return hr; + + if (!(async = calloc(1, sizeof(*async)))) + { + IMFAsyncResult_Release(caller); + return E_OUTOFMEMORY; + } + + async->IUnknown_iface.lpVtbl = &async_create_object_vtbl; + async->refcount = 1; + async->props = props; + if (async->props) + IPropertyStore_AddRef(async->props); + async->flags = flags; + async->stream = stream; + if (async->stream) + IMFByteStream_AddRef(async->stream); + if (url) + async->url = wcsdup(url); + if (!async->stream) + { + IMFAsyncResult_Release(caller); + IUnknown_Release(&async->IUnknown_iface); + return E_OUTOFMEMORY; + } + + hr = MFCreateAsyncResult(&async->IUnknown_iface, &handler->IMFAsyncCallback_iface, + (IUnknown *)caller, &item); + IUnknown_Release(&async->IUnknown_iface); + if (SUCCEEDED(hr)) + { + if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item))) + { + if (cookie) + { + *cookie = (IUnknown *)caller; + IUnknown_AddRef(*cookie); + } + } + + IMFAsyncResult_Release(item); + } + IMFAsyncResult_Release(caller); + + return hr; +} + +static HRESULT WINAPI stream_handler_EndCreateObject(IMFByteStreamHandler *iface, + IMFAsyncResult *result, MF_OBJECT_TYPE *type, IUnknown **object) +{ + struct handler *handler = impl_from_IMFByteStreamHandler(iface); + struct result_entry *found = NULL, *entry; + HRESULT hr; + + TRACE("%p, %p, %p, %p.\n", iface, result, type, object); + + EnterCriticalSection(&handler->cs); + + LIST_FOR_EACH_ENTRY(entry, &handler->results, struct result_entry, entry) + { + if (result == entry->result) + { + list_remove(&entry->entry); + found = entry; + break; + } + } + + LeaveCriticalSection(&handler->cs); + + if (found) + { + *type = found->type; + *object = found->object; + hr = IMFAsyncResult_GetStatus(found->result); + IMFAsyncResult_Release(found->result); + free(found); + } + else + { + *type = MF_OBJECT_INVALID; + *object = NULL; + hr = MF_E_UNEXPECTED; + } + + return hr; +} + +static HRESULT WINAPI stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cookie) +{ + struct handler *handler = impl_from_IMFByteStreamHandler(iface); + struct result_entry *found = NULL, *entry; + + TRACE("%p, %p.\n", iface, cookie); + + EnterCriticalSection(&handler->cs); + + LIST_FOR_EACH_ENTRY(entry, &handler->results, struct result_entry, entry) + { + if (cookie == (IUnknown *)entry->result) + { + list_remove(&entry->entry); + found = entry; + break; + } + } + + LeaveCriticalSection(&handler->cs); + + if (found) + { + IMFAsyncResult_Release(found->result); + if (found->object) + IUnknown_Release(found->object); + free(found); + } + + return found ? S_OK : MF_E_UNEXPECTED; +} + +static HRESULT WINAPI stream_handler_GetMaxNumberOfBytesRequiredForResolution( + IMFByteStreamHandler *iface, QWORD *bytes) +{ + FIXME("stub (%p %p)\n", iface, bytes); + return E_NOTIMPL; +} + +static const IMFByteStreamHandlerVtbl stream_handler_vtbl = +{ + stream_handler_QueryInterface, + stream_handler_AddRef, + stream_handler_Release, + stream_handler_BeginCreateObject, + stream_handler_EndCreateObject, + stream_handler_CancelObjectCreation, + stream_handler_GetMaxNumberOfBytesRequiredForResolution, +}; + +HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) +{ + struct handler *handler; + HRESULT hr; + + TRACE("%s, %p.\n", debugstr_guid(riid), obj); + + if (!(handler = calloc(1, sizeof(*handler)))) + return E_OUTOFMEMORY; + + list_init(&handler->results); + InitializeCriticalSection(&handler->cs); + + handler->IMFByteStreamHandler_iface.lpVtbl = &stream_handler_vtbl; + handler->IMFAsyncCallback_iface.lpVtbl = &async_callback_vtbl; + handler->refcount = 1; + + hr = IMFByteStreamHandler_QueryInterface(&handler->IMFByteStreamHandler_iface, riid, obj); + IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface); + + return hr; +} From 097cd35c88764ff09790b5b2038c153ad7f4170f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 May 2023 10:23:38 +0200 Subject: [PATCH 1946/2777] winegstreamer: Move GStreamerByteStreamHandler to mf_handler.c. CW-Bug-Id: #21953 --- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/media_source.c | 2 +- dlls/winegstreamer/mf_handler.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index fde5c231c07..34237da2109 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -149,7 +149,7 @@ HRESULT wg_transform_read_mf(struct wg_transform *transform, IMFSample *sample, HRESULT wg_transform_read_quartz(struct wg_transform *transform, struct wg_sample *sample); HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj); -HRESULT media_source_create_from_stream(IMFByteStream *stream, IMFMediaSource **out); +HRESULT media_source_create(IMFByteStream *stream, const WCHAR *url, IMFMediaSource **out); HRESULT aac_decoder_create(REFIID riid, void **ret); HRESULT h264_decoder_create(REFIID riid, void **ret); diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 78e507347a6..4b62b20c93f 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1441,7 +1441,7 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = media_source_Shutdown, }; -HRESULT media_source_create_from_stream(IMFByteStream *bytestream, IMFMediaSource **out) +HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *uri, IMFMediaSource **out) { BOOL video_selected = FALSE, audio_selected = FALSE; IMFStreamDescriptor **descriptors = NULL; diff --git a/dlls/winegstreamer/mf_handler.c b/dlls/winegstreamer/mf_handler.c index ffb12be38e3..36739269a58 100644 --- a/dlls/winegstreamer/mf_handler.c +++ b/dlls/winegstreamer/mf_handler.c @@ -168,7 +168,7 @@ static HRESULT stream_handler_create_object(struct handler *handler, WCHAR *url, { HRESULT hr; - if (FAILED(hr = media_source_create_from_stream(stream, (IMFMediaSource **)object))) + if (FAILED(hr = media_source_create(stream, NULL, (IMFMediaSource **)object))) return hr; *type = MF_OBJECT_MEDIASOURCE; From ec61a48c51fab39ce0dc256568a21c4c633c3841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 15 Apr 2023 20:14:27 +0200 Subject: [PATCH 1947/2777] winegstreamer: Make IMFAsyncCallback the primary handler interface. CW-Bug-Id: #21953 --- dlls/winegstreamer/mf_handler.c | 61 ++++++++++++++++----------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/dlls/winegstreamer/mf_handler.c b/dlls/winegstreamer/mf_handler.c index 36739269a58..a8c69b292eb 100644 --- a/dlls/winegstreamer/mf_handler.c +++ b/dlls/winegstreamer/mf_handler.c @@ -110,8 +110,8 @@ static const IUnknownVtbl async_create_object_vtbl = struct handler { - IMFByteStreamHandler IMFByteStreamHandler_iface; IMFAsyncCallback IMFAsyncCallback_iface; + IMFByteStreamHandler IMFByteStreamHandler_iface; LONG refcount; struct list results; CRITICAL_SECTION cs; @@ -145,13 +145,34 @@ static HRESULT WINAPI async_callback_QueryInterface(IMFAsyncCallback *iface, REF static ULONG WINAPI async_callback_AddRef(IMFAsyncCallback *iface) { struct handler *handler = impl_from_IMFAsyncCallback(iface); - return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface); + ULONG refcount = InterlockedIncrement(&handler->refcount); + TRACE("%p, refcount %lu.\n", handler, refcount); + return refcount; } static ULONG WINAPI async_callback_Release(IMFAsyncCallback *iface) { struct handler *handler = impl_from_IMFAsyncCallback(iface); - return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface); + ULONG refcount = InterlockedDecrement(&handler->refcount); + struct result_entry *entry, *next; + + TRACE("%p, refcount %lu.\n", iface, refcount); + + if (!refcount) + { + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &handler->results, struct result_entry, entry) + { + list_remove(&entry->entry); + IMFAsyncResult_Release(entry->result); + if (entry->object) + IUnknown_Release(entry->object); + free(entry); + } + DeleteCriticalSection(&handler->cs); + free(handler); + } + + return refcount; } static HRESULT WINAPI async_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) @@ -259,34 +280,13 @@ static HRESULT WINAPI stream_handler_QueryInterface(IMFByteStreamHandler *iface, static ULONG WINAPI stream_handler_AddRef(IMFByteStreamHandler *iface) { struct handler *handler = impl_from_IMFByteStreamHandler(iface); - ULONG refcount = InterlockedIncrement(&handler->refcount); - TRACE("%p, refcount %lu.\n", handler, refcount); - return refcount; + return IMFAsyncCallback_AddRef(&handler->IMFAsyncCallback_iface); } static ULONG WINAPI stream_handler_Release(IMFByteStreamHandler *iface) { struct handler *handler = impl_from_IMFByteStreamHandler(iface); - ULONG refcount = InterlockedDecrement(&handler->refcount); - struct result_entry *entry, *next; - - TRACE("%p, refcount %lu.\n", iface, refcount); - - if (!refcount) - { - LIST_FOR_EACH_ENTRY_SAFE(entry, next, &handler->results, struct result_entry, entry) - { - list_remove(&entry->entry); - IMFAsyncResult_Release(entry->result); - if (entry->object) - IUnknown_Release(entry->object); - free(entry); - } - DeleteCriticalSection(&handler->cs); - free(handler); - } - - return refcount; + return IMFAsyncCallback_Release(&handler->IMFAsyncCallback_iface); } static HRESULT WINAPI stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, @@ -452,15 +452,14 @@ HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) if (!(handler = calloc(1, sizeof(*handler)))) return E_OUTOFMEMORY; - list_init(&handler->results); - InitializeCriticalSection(&handler->cs); - - handler->IMFByteStreamHandler_iface.lpVtbl = &stream_handler_vtbl; handler->IMFAsyncCallback_iface.lpVtbl = &async_callback_vtbl; + handler->IMFByteStreamHandler_iface.lpVtbl = &stream_handler_vtbl; handler->refcount = 1; + list_init(&handler->results); + InitializeCriticalSection(&handler->cs); hr = IMFByteStreamHandler_QueryInterface(&handler->IMFByteStreamHandler_iface, riid, obj); - IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface); + IMFAsyncCallback_Release(&handler->IMFAsyncCallback_iface); return hr; } From a90a0fb81f5603c6a1a5b25853d2c14d5ab32409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 May 2023 10:41:24 +0200 Subject: [PATCH 1948/2777] winegstreamer: Use helpers to manage handler results. CW-Bug-Id: #21953 --- dlls/winegstreamer/mf_handler.c | 342 ++++++++++++++++---------------- 1 file changed, 172 insertions(+), 170 deletions(-) diff --git a/dlls/winegstreamer/mf_handler.c b/dlls/winegstreamer/mf_handler.c index a8c69b292eb..63a6cf6011d 100644 --- a/dlls/winegstreamer/mf_handler.c +++ b/dlls/winegstreamer/mf_handler.c @@ -41,19 +41,45 @@ struct result_entry IUnknown *object; }; +static HRESULT result_entry_create(IMFAsyncResult *result, MF_OBJECT_TYPE type, + IUnknown *object, struct result_entry **out) +{ + struct result_entry *entry; + + if (!(entry = malloc(sizeof(*entry)))) + return E_OUTOFMEMORY; + + IMFAsyncResult_AddRef((entry->result = result)); + entry->type = type; + if ((entry->object = object)) + IUnknown_AddRef(entry->object); + + *out = entry; + return S_OK; +} + +static void result_entry_destroy(struct result_entry *entry) +{ + IMFAsyncResult_Release(entry->result); + if (entry->object) + IUnknown_Release(entry->object); + free(entry); +} + struct async_create_object { IUnknown IUnknown_iface; LONG refcount; - IPropertyStore *props; IMFByteStream *stream; WCHAR *url; DWORD flags; + IMFAsyncResult *result; }; static struct async_create_object *impl_from_IUnknown(IUnknown *iface) { + if (!iface) return NULL; return CONTAINING_RECORD(iface, struct async_create_object, IUnknown_iface); } @@ -90,8 +116,7 @@ static ULONG WINAPI async_create_object_Release(IUnknown *iface) if (!refcount) { - if (async->props) - IPropertyStore_Release(async->props); + IMFAsyncResult_Release(async->result); if (async->stream) IMFByteStream_Release(async->stream); free(async->url); @@ -108,6 +133,68 @@ static const IUnknownVtbl async_create_object_vtbl = async_create_object_Release, }; +static HRESULT async_create_object_create(DWORD flags, IMFByteStream *stream, const WCHAR *url, + IMFAsyncResult *result, IUnknown **out) +{ + WCHAR *tmp_url = url ? wcsdup(url) : NULL; + struct async_create_object *impl; + + if (!stream && !tmp_url) + return E_INVALIDARG; + if (!(impl = calloc(1, sizeof(*impl)))) + { + free(tmp_url); + return E_OUTOFMEMORY; + } + + impl->IUnknown_iface.lpVtbl = &async_create_object_vtbl; + impl->refcount = 1; + impl->flags = flags; + if ((impl->stream = stream)) + IMFByteStream_AddRef(impl->stream); + impl->url = tmp_url; + IMFAsyncResult_AddRef((impl->result = result)); + + *out = &impl->IUnknown_iface; + return S_OK; +} + +static HRESULT async_create_object_complete(struct async_create_object *async, + struct list *results, CRITICAL_SECTION *results_cs) +{ + IUnknown *object; + HRESULT hr; + + if (async->flags & MF_RESOLUTION_MEDIASOURCE) + hr = media_source_create(async->stream, NULL, (IMFMediaSource **)&object); + else + { + FIXME("Unhandled flags %#lx.\n", async->flags); + hr = E_NOTIMPL; + } + + if (FAILED(hr)) + WARN("Failed to create object, hr %#lx.\n", hr); + else + { + struct result_entry *entry; + + if (FAILED(hr = result_entry_create(async->result, MF_OBJECT_MEDIASOURCE, object, &entry))) + WARN("Failed to add handler result, hr %#lx\n", hr); + else + { + EnterCriticalSection(results_cs); + list_add_tail(results, &entry->entry); + LeaveCriticalSection(results_cs); + } + + IUnknown_Release(object); + } + + IMFAsyncResult_SetStatus(async->result, hr); + return MFInvokeCallback(async->result); +} + struct handler { IMFAsyncCallback IMFAsyncCallback_iface; @@ -117,6 +204,75 @@ struct handler CRITICAL_SECTION cs; }; +static HRESULT handler_begin_create_object(struct handler *handler, DWORD flags, + IMFByteStream *stream, const WCHAR *url, IMFAsyncResult *result) +{ + IUnknown *async; + HRESULT hr; + + if (SUCCEEDED(hr = async_create_object_create(flags, stream, url, result, &async))) + { + if (FAILED(hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_IO, &handler->IMFAsyncCallback_iface, async))) + WARN("Failed to queue async work item, hr %#lx\n", hr); + IUnknown_Release(async); + } + + return hr; +} + +static struct result_entry *handler_find_result_entry(struct handler *handler, IMFAsyncResult *result) +{ + struct result_entry *entry; + + EnterCriticalSection(&handler->cs); + LIST_FOR_EACH_ENTRY(entry, &handler->results, struct result_entry, entry) + { + if (result == entry->result) + { + list_remove(&entry->entry); + LeaveCriticalSection(&handler->cs); + return entry; + } + } + LeaveCriticalSection(&handler->cs); + + return NULL; +} + +static HRESULT handler_end_create_object(struct handler *handler, + IMFAsyncResult *result, MF_OBJECT_TYPE *type, IUnknown **object) +{ + struct result_entry *entry; + HRESULT hr; + + if (!(entry = handler_find_result_entry(handler, result))) + { + *type = MF_OBJECT_INVALID; + *object = NULL; + return MF_E_UNEXPECTED; + } + + hr = IMFAsyncResult_GetStatus(entry->result); + *type = entry->type; + *object = entry->object; + entry->object = NULL; + + result_entry_destroy(entry); + return hr; +} + +static HRESULT handler_cancel_object_creation(struct handler *handler, IUnknown *cookie) +{ + IMFAsyncResult *result = (IMFAsyncResult *)cookie; + struct result_entry *entry; + + if (!(entry = handler_find_result_entry(handler, result))) + return MF_E_UNEXPECTED; + + result_entry_destroy(entry); + return S_OK; +} + static struct handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) { return CONTAINING_RECORD(iface, struct handler, IMFAsyncCallback_iface); @@ -161,13 +317,7 @@ static ULONG WINAPI async_callback_Release(IMFAsyncCallback *iface) if (!refcount) { LIST_FOR_EACH_ENTRY_SAFE(entry, next, &handler->results, struct result_entry, entry) - { - list_remove(&entry->entry); - IMFAsyncResult_Release(entry->result); - if (entry->object) - IUnknown_Release(entry->object); - free(entry); - } + result_entry_destroy(entry); DeleteCriticalSection(&handler->cs); free(handler); } @@ -180,75 +330,20 @@ static HRESULT WINAPI async_callback_GetParameters(IMFAsyncCallback *iface, DWOR return E_NOTIMPL; } -static HRESULT stream_handler_create_object(struct handler *handler, WCHAR *url, - IMFByteStream *stream, DWORD flags, IPropertyStore *props, IUnknown **object, MF_OBJECT_TYPE *type) -{ - TRACE("%p, %s, %p, %#lx, %p, %p, %p.\n", handler, debugstr_w(url), stream, flags, props, object, type); - - if (flags & MF_RESOLUTION_MEDIASOURCE) - { - HRESULT hr; - - if (FAILED(hr = media_source_create(stream, NULL, (IMFMediaSource **)object))) - return hr; - - *type = MF_OBJECT_MEDIASOURCE; - return S_OK; - } - else - { - FIXME("Unhandled flags %#lx.\n", flags); - return E_NOTIMPL; - } -} - static HRESULT WINAPI async_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { struct handler *handler = impl_from_IMFAsyncCallback(iface); - MF_OBJECT_TYPE type = MF_OBJECT_INVALID; - IUnknown *object = NULL, *context_object; struct async_create_object *async; - struct result_entry *entry; - IMFAsyncResult *caller; - HRESULT hr; - caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result); + TRACE("iface %p, result %p\n", iface, result); - if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object))) + if (!(async = impl_from_IUnknown(IMFAsyncResult_GetStateNoAddRef(result)))) { WARN("Expected context set for callee result.\n"); - return hr; - } - - async = impl_from_IUnknown(context_object); - - hr = stream_handler_create_object(handler, async->url, async->stream, async->flags, - async->props, &object, &type); - - if ((entry = malloc(sizeof(*entry)))) - { - entry->result = caller; - IMFAsyncResult_AddRef(entry->result); - entry->type = type; - entry->object = object; - - EnterCriticalSection(&handler->cs); - list_add_tail(&handler->results, &entry->entry); - LeaveCriticalSection(&handler->cs); + return E_FAIL; } - else - { - if (object) - IUnknown_Release(object); - hr = E_OUTOFMEMORY; - } - - IUnknown_Release(&async->IUnknown_iface); - - IMFAsyncResult_SetStatus(caller, hr); - MFInvokeCallback(caller); - return S_OK; + return async_create_object_complete(async, &handler->results, &handler->cs); } static const IMFAsyncCallbackVtbl async_callback_vtbl = @@ -294,8 +389,7 @@ static HRESULT WINAPI stream_handler_BeginCreateObject(IMFByteStreamHandler *ifa IUnknown **cookie, IMFAsyncCallback *callback, IUnknown *state) { struct handler *handler = impl_from_IMFByteStreamHandler(iface); - struct async_create_object *async; - IMFAsyncResult *caller, *item; + IMFAsyncResult *result; HRESULT hr; TRACE("%p, %s, %#lx, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cookie, callback, state); @@ -303,50 +397,16 @@ static HRESULT WINAPI stream_handler_BeginCreateObject(IMFByteStreamHandler *ifa if (cookie) *cookie = NULL; - if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller))) + if (FAILED(hr = MFCreateAsyncResult((IUnknown *)iface, callback, state, &result))) return hr; - if (!(async = calloc(1, sizeof(*async)))) - { - IMFAsyncResult_Release(caller); - return E_OUTOFMEMORY; - } - - async->IUnknown_iface.lpVtbl = &async_create_object_vtbl; - async->refcount = 1; - async->props = props; - if (async->props) - IPropertyStore_AddRef(async->props); - async->flags = flags; - async->stream = stream; - if (async->stream) - IMFByteStream_AddRef(async->stream); - if (url) - async->url = wcsdup(url); - if (!async->stream) + if (SUCCEEDED(hr = handler_begin_create_object(handler, flags, stream, url, result)) && cookie) { - IMFAsyncResult_Release(caller); - IUnknown_Release(&async->IUnknown_iface); - return E_OUTOFMEMORY; + *cookie = (IUnknown *)result; + IUnknown_AddRef(*cookie); } - hr = MFCreateAsyncResult(&async->IUnknown_iface, &handler->IMFAsyncCallback_iface, - (IUnknown *)caller, &item); - IUnknown_Release(&async->IUnknown_iface); - if (SUCCEEDED(hr)) - { - if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item))) - { - if (cookie) - { - *cookie = (IUnknown *)caller; - IUnknown_AddRef(*cookie); - } - } - - IMFAsyncResult_Release(item); - } - IMFAsyncResult_Release(caller); + IMFAsyncResult_Release(result); return hr; } @@ -355,73 +415,15 @@ static HRESULT WINAPI stream_handler_EndCreateObject(IMFByteStreamHandler *iface IMFAsyncResult *result, MF_OBJECT_TYPE *type, IUnknown **object) { struct handler *handler = impl_from_IMFByteStreamHandler(iface); - struct result_entry *found = NULL, *entry; - HRESULT hr; - TRACE("%p, %p, %p, %p.\n", iface, result, type, object); - - EnterCriticalSection(&handler->cs); - - LIST_FOR_EACH_ENTRY(entry, &handler->results, struct result_entry, entry) - { - if (result == entry->result) - { - list_remove(&entry->entry); - found = entry; - break; - } - } - - LeaveCriticalSection(&handler->cs); - - if (found) - { - *type = found->type; - *object = found->object; - hr = IMFAsyncResult_GetStatus(found->result); - IMFAsyncResult_Release(found->result); - free(found); - } - else - { - *type = MF_OBJECT_INVALID; - *object = NULL; - hr = MF_E_UNEXPECTED; - } - - return hr; + return handler_end_create_object(handler, result, type, object); } static HRESULT WINAPI stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cookie) { struct handler *handler = impl_from_IMFByteStreamHandler(iface); - struct result_entry *found = NULL, *entry; - TRACE("%p, %p.\n", iface, cookie); - - EnterCriticalSection(&handler->cs); - - LIST_FOR_EACH_ENTRY(entry, &handler->results, struct result_entry, entry) - { - if (cookie == (IUnknown *)entry->result) - { - list_remove(&entry->entry); - found = entry; - break; - } - } - - LeaveCriticalSection(&handler->cs); - - if (found) - { - IMFAsyncResult_Release(found->result); - if (found->object) - IUnknown_Release(found->object); - free(found); - } - - return found ? S_OK : MF_E_UNEXPECTED; + return handler_cancel_object_creation(handler, cookie); } static HRESULT WINAPI stream_handler_GetMaxNumberOfBytesRequiredForResolution( From 3b2e9d35ed55e67615fd0b3ef66356f6836767d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 May 2023 10:42:23 +0200 Subject: [PATCH 1949/2777] winegstreamer: Implement a scheme handler for the media source. Link: https://github.com/ValveSoftware/wine/pull/142 CW-Bug-Id: #20485 CW-Bug-Id: #21953 --- dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/media_source.c | 20 ++++ dlls/winegstreamer/mf_handler.c | 115 ++++++++++++++++++- dlls/winegstreamer/mfplat.c | 2 + dlls/winegstreamer/winegstreamer.rgs | 28 +++++ dlls/winegstreamer/winegstreamer_classes.idl | 6 + 6 files changed, 172 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 34237da2109..0cd2dbc0825 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -149,7 +149,9 @@ HRESULT wg_transform_read_mf(struct wg_transform *transform, IMFSample *sample, HRESULT wg_transform_read_quartz(struct wg_transform *transform, struct wg_sample *sample); HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj); +HRESULT winegstreamer_scheme_handler_create(REFIID riid, void **obj); HRESULT media_source_create(IMFByteStream *stream, const WCHAR *url, IMFMediaSource **out); +HRESULT media_source_create_from_url(const WCHAR *url, IMFMediaSource **out); HRESULT aac_decoder_create(REFIID riid, void **ret); HRESULT h264_decoder_create(REFIID riid, void **ret); diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 4b62b20c93f..0a307a9a6d2 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1646,3 +1646,23 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *uri, IMFMedi free(object); return hr; } + +HRESULT media_source_create_from_url(const WCHAR *url, IMFMediaSource **out) +{ + IMFByteStream *bytestream; + IStream *stream; + HRESULT hr; + + if (FAILED(hr = CreateStreamOnHGlobal(0, TRUE, &stream))) + return hr; + + hr = MFCreateMFByteStreamOnStream(stream, &bytestream); + IStream_Release(stream); + if (FAILED(hr)) + return hr; + + hr = media_source_create(bytestream, url, out); + IMFByteStream_Release(bytestream); + + return hr; +} diff --git a/dlls/winegstreamer/mf_handler.c b/dlls/winegstreamer/mf_handler.c index 63a6cf6011d..e030854ccd5 100644 --- a/dlls/winegstreamer/mf_handler.c +++ b/dlls/winegstreamer/mf_handler.c @@ -166,7 +166,12 @@ static HRESULT async_create_object_complete(struct async_create_object *async, HRESULT hr; if (async->flags & MF_RESOLUTION_MEDIASOURCE) - hr = media_source_create(async->stream, NULL, (IMFMediaSource **)&object); + { + if (!async->stream) + hr = media_source_create_from_url(async->url, (IMFMediaSource **)&object); + else + hr = media_source_create(async->stream, NULL, (IMFMediaSource **)&object); + } else { FIXME("Unhandled flags %#lx.\n", async->flags); @@ -199,6 +204,7 @@ struct handler { IMFAsyncCallback IMFAsyncCallback_iface; IMFByteStreamHandler IMFByteStreamHandler_iface; + IMFSchemeHandler IMFSchemeHandler_iface; LONG refcount; struct list results; CRITICAL_SECTION cs; @@ -283,6 +289,11 @@ static struct handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *ifac return CONTAINING_RECORD(iface, struct handler, IMFByteStreamHandler_iface); } +static struct handler *impl_from_IMFSchemeHandler(IMFSchemeHandler *iface) +{ + return CONTAINING_RECORD(iface, struct handler, IMFSchemeHandler_iface); +} + static HRESULT WINAPI async_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IMFAsyncCallback) @@ -444,6 +455,86 @@ static const IMFByteStreamHandlerVtbl stream_handler_vtbl = stream_handler_GetMaxNumberOfBytesRequiredForResolution, }; +static HRESULT WINAPI scheme_handler_QueryInterface(IMFSchemeHandler *iface, REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFSchemeHandler) + || IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFSchemeHandler_AddRef(iface); + return S_OK; + } + + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI scheme_handler_AddRef(IMFSchemeHandler *iface) +{ + struct handler *handler = impl_from_IMFSchemeHandler(iface); + return IMFAsyncCallback_AddRef(&handler->IMFAsyncCallback_iface); +} + +static ULONG WINAPI scheme_handler_Release(IMFSchemeHandler *iface) +{ + struct handler *handler = impl_from_IMFSchemeHandler(iface); + return IMFAsyncCallback_Release(&handler->IMFAsyncCallback_iface); +} + +static HRESULT WINAPI scheme_handler_BeginCreateObject(IMFSchemeHandler *iface, const WCHAR *url, + DWORD flags, IPropertyStore *props, IUnknown **cookie, IMFAsyncCallback *callback, IUnknown *state) +{ + struct handler *handler = impl_from_IMFSchemeHandler(iface); + IMFAsyncResult *result; + HRESULT hr; + + TRACE("%p, %s, %#lx, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cookie, callback, state); + + if (cookie) + *cookie = NULL; + + if (FAILED(hr = MFCreateAsyncResult((IUnknown *)iface, callback, state, &result))) + return hr; + + if (SUCCEEDED(hr = handler_begin_create_object(handler, flags, NULL, url, result)) && cookie) + { + *cookie = (IUnknown *)result; + IUnknown_AddRef(*cookie); + } + + IMFAsyncResult_Release(result); + + return hr; +} + +static HRESULT WINAPI scheme_handler_EndCreateObject(IMFSchemeHandler *iface, + IMFAsyncResult *result, MF_OBJECT_TYPE *type, IUnknown **object) +{ + struct handler *handler = impl_from_IMFSchemeHandler(iface); + TRACE("%p, %p, %p, %p.\n", iface, result, type, object); + return handler_end_create_object(handler, result, type, object); +} + +static HRESULT WINAPI scheme_handler_CancelObjectCreation(IMFSchemeHandler *iface, IUnknown *cookie) +{ + struct handler *handler = impl_from_IMFSchemeHandler(iface); + TRACE("%p, %p.\n", iface, cookie); + return handler_cancel_object_creation(handler, cookie); +} + +static const IMFSchemeHandlerVtbl scheme_handler_vtbl = +{ + scheme_handler_QueryInterface, + scheme_handler_AddRef, + scheme_handler_Release, + scheme_handler_BeginCreateObject, + scheme_handler_EndCreateObject, + scheme_handler_CancelObjectCreation, +}; + HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) { struct handler *handler; @@ -465,3 +556,25 @@ HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) return hr; } + +HRESULT winegstreamer_scheme_handler_create(REFIID riid, void **obj) +{ + struct handler *handler; + HRESULT hr; + + TRACE("%s, %p.\n", debugstr_guid(riid), obj); + + if (!(handler = calloc(1, sizeof(*handler)))) + return E_OUTOFMEMORY; + + handler->IMFAsyncCallback_iface.lpVtbl = &async_callback_vtbl; + handler->IMFSchemeHandler_iface.lpVtbl = &scheme_handler_vtbl; + handler->refcount = 1; + list_init(&handler->results); + InitializeCriticalSection(&handler->cs); + + hr = IMFSchemeHandler_QueryInterface(&handler->IMFSchemeHandler_iface, riid, obj); + IMFAsyncCallback_Release(&handler->IMFAsyncCallback_iface); + + return hr; +} diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index ea5ea33ee9d..27ec2aaea86 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -121,6 +121,7 @@ static const IClassFactoryVtbl class_factory_vtbl = }; static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; +static const GUID CLSID_GStreamerSchemeHandler = {0x587eeb6a,0x7336,0x4ebd,{0xa4,0xf2,0x91,0xc9,0x48,0xde,0x62,0x2c}}; static const struct class_object { @@ -131,6 +132,7 @@ class_objects[] = { { &CLSID_VideoProcessorMFT, &video_processor_create }, { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, + { &CLSID_GStreamerSchemeHandler, &winegstreamer_scheme_handler_create }, { &CLSID_MSAACDecMFT, &aac_decoder_create }, { &CLSID_MSH264DecoderMFT, &h264_decoder_create }, }; diff --git a/dlls/winegstreamer/winegstreamer.rgs b/dlls/winegstreamer/winegstreamer.rgs index 923ba673f8c..c50d3a05747 100644 --- a/dlls/winegstreamer/winegstreamer.rgs +++ b/dlls/winegstreamer/winegstreamer.rgs @@ -12,3 +12,31 @@ HKCR } } } + +HKLM +{ + NoRemove 'Software' + { + NoRemove 'Microsoft' + { + NoRemove 'Windows Media Foundation' + { + NoRemove 'SchemeHandlers' + { + 'http:' + { + val '{587eeb6a-7336-4ebd-a4f2-91c948de622c}' = s 'GStreamer Scheme Handler' + } + 'https:' + { + val '{587eeb6a-7336-4ebd-a4f2-91c948de622c}' = s 'GStreamer Scheme Handler' + } + 'rtsp:' + { + val '{587eeb6a-7336-4ebd-a4f2-91c948de622c}' = s 'GStreamer Scheme Handler' + } + } + } + } + } +} diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index 30a99c9acfb..13b8a044695 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl @@ -111,3 +111,9 @@ coclass CResamplerMediaObject {} uuid(98230571-0087-4204-b020-3282538e57d3) ] coclass CColorConvertDMO {} + +[ + threading(both), + uuid(587eeb6a-7336-4ebd-a4f2-91c948de622c) +] +coclass GStreamerSchemeHandler {} From 272ce8f80d45c548df08dd9e8f95a7aefef4899e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Apr 2023 17:49:08 +0200 Subject: [PATCH 1950/2777] mfplat: Use the io queue for bytestream requests. CW-Bug-Id: #21953 --- dlls/mfplat/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index ed69d501f2a..d8f621d4559 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -3826,7 +3826,7 @@ static HRESULT bytestream_create_io_request(struct bytestream *stream, enum asyn &stream->write_callback, NULL, &request))) goto failed; - RtwqPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, 0, request); + RtwqPutWorkItem(MFASYNC_CALLBACK_QUEUE_IO, 0, request); IRtwqAsyncResult_Release(request); failed: From 63898ad4325b6717bcddf6e4a57284b9ece628fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Apr 2023 19:16:18 +0200 Subject: [PATCH 1951/2777] winegstreamer: Call BeginRead / EndRead to read the bytestream header. CW-Bug-Id: #21953 --- dlls/winegstreamer/mf_handler.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/dlls/winegstreamer/mf_handler.c b/dlls/winegstreamer/mf_handler.c index e030854ccd5..3d7f36e749c 100644 --- a/dlls/winegstreamer/mf_handler.c +++ b/dlls/winegstreamer/mf_handler.c @@ -75,8 +75,13 @@ struct async_create_object WCHAR *url; DWORD flags; IMFAsyncResult *result; + + UINT64 size; + BYTE buffer[]; }; +C_ASSERT(sizeof(struct async_create_object) == offsetof(struct async_create_object, buffer[0])); + static struct async_create_object *impl_from_IUnknown(IUnknown *iface) { if (!iface) return NULL; @@ -134,14 +139,14 @@ static const IUnknownVtbl async_create_object_vtbl = }; static HRESULT async_create_object_create(DWORD flags, IMFByteStream *stream, const WCHAR *url, - IMFAsyncResult *result, IUnknown **out) + IMFAsyncResult *result, UINT size, IUnknown **out, BYTE **buffer) { WCHAR *tmp_url = url ? wcsdup(url) : NULL; struct async_create_object *impl; if (!stream && !tmp_url) return E_INVALIDARG; - if (!(impl = calloc(1, sizeof(*impl)))) + if (!(impl = calloc(1, offsetof(struct async_create_object, buffer[size])))) { free(tmp_url); return E_OUTOFMEMORY; @@ -155,6 +160,7 @@ static HRESULT async_create_object_create(DWORD flags, IMFByteStream *stream, co impl->url = tmp_url; IMFAsyncResult_AddRef((impl->result = result)); + *buffer = impl->buffer; *out = &impl->IUnknown_iface; return S_OK; } @@ -213,12 +219,16 @@ struct handler static HRESULT handler_begin_create_object(struct handler *handler, DWORD flags, IMFByteStream *stream, const WCHAR *url, IMFAsyncResult *result) { + UINT size = 0x2000; IUnknown *async; HRESULT hr; + BYTE *buffer; - if (SUCCEEDED(hr = async_create_object_create(flags, stream, url, result, &async))) + if (SUCCEEDED(hr = async_create_object_create(flags, stream, url, result, size, &async, &buffer))) { - if (FAILED(hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_IO, &handler->IMFAsyncCallback_iface, async))) + if (stream && FAILED(hr = IMFByteStream_BeginRead(stream, buffer, size, &handler->IMFAsyncCallback_iface, async))) + WARN("Failed to begin reading from stream, hr %#lx\n", hr); + if (!stream && FAILED(hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_IO, &handler->IMFAsyncCallback_iface, async))) WARN("Failed to queue async work item, hr %#lx\n", hr); IUnknown_Release(async); } @@ -338,13 +348,17 @@ static ULONG WINAPI async_callback_Release(IMFAsyncCallback *iface) static HRESULT WINAPI async_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue) { - return E_NOTIMPL; + *flags = 0; + *queue = MFASYNC_CALLBACK_QUEUE_IO; + return S_OK; } static HRESULT WINAPI async_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { struct handler *handler = impl_from_IMFAsyncCallback(iface); struct async_create_object *async; + ULONG size = 0; + HRESULT hr; TRACE("iface %p, result %p\n", iface, result); @@ -354,6 +368,10 @@ static HRESULT WINAPI async_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncRes return E_FAIL; } + if (async->stream && FAILED(hr = IMFByteStream_EndRead(async->stream, result, &size))) + WARN("Failed to complete stream read, hr %#lx\n", hr); + async->size = size; + return async_create_object_complete(async, &handler->results, &handler->cs); } From 623d7f0b4bdb9f9be67234ed250b4b7ce861f870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 May 2023 10:51:25 +0200 Subject: [PATCH 1952/2777] winegstreamer: Guard new media source implementation with WINE_NEW_MEDIA_SOURCE. CW-Bug-Id: #21953 --- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 3 +- dlls/winegstreamer/media_source.c | 26 +- dlls/winegstreamer/media_source_old.c | 1668 +++++++++++++++++++++++++ dlls/winegstreamer/mf_handler.c | 10 +- 5 files changed, 1682 insertions(+), 26 deletions(-) create mode 100644 dlls/winegstreamer/media_source_old.c diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 49b4dd2c631..56afcea3189 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -12,6 +12,7 @@ C_SRCS = \ h264_decoder.c \ main.c \ media_source.c \ + media_source_old.c \ mf_handler.c \ mfplat.c \ quartz_parser.c \ diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 0cd2dbc0825..bb5db1c5f51 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -150,7 +150,8 @@ HRESULT wg_transform_read_quartz(struct wg_transform *transform, struct wg_sampl HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj); HRESULT winegstreamer_scheme_handler_create(REFIID riid, void **obj); -HRESULT media_source_create(IMFByteStream *stream, const WCHAR *url, IMFMediaSource **out); +HRESULT media_source_create(IMFByteStream *stream, const WCHAR *url, BYTE *data, UINT64 size, IMFMediaSource **out); +HRESULT media_source_create_old(IMFByteStream *stream, const WCHAR *url, IMFMediaSource **out); HRESULT media_source_create_from_url(const WCHAR *url, IMFMediaSource **out); HRESULT aac_decoder_create(REFIID riid, void **ret); diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 0a307a9a6d2..ec1223c7bfd 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1441,7 +1441,7 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = media_source_Shutdown, }; -HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *uri, IMFMediaSource **out) +HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *data, UINT64 size, IMFMediaSource **out) { BOOL video_selected = FALSE, audio_selected = FALSE; IMFStreamDescriptor **descriptors = NULL; @@ -1490,7 +1490,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *uri, IMFMedi if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue))) goto fail; - if (!(parser = wg_parser_create(uri ? WG_PARSER_URIDECODEBIN : WG_PARSER_DECODEBIN, false))) + if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, false))) { hr = E_OUTOFMEMORY; goto fail; @@ -1501,7 +1501,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *uri, IMFMedi object->state = SOURCE_OPENING; - if (FAILED(hr = wg_parser_connect(parser, file_size, uri))) + if (FAILED(hr = wg_parser_connect(parser, file_size, NULL))) goto fail; stream_count = wg_parser_get_stream_count(parser); @@ -1646,23 +1646,3 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *uri, IMFMedi free(object); return hr; } - -HRESULT media_source_create_from_url(const WCHAR *url, IMFMediaSource **out) -{ - IMFByteStream *bytestream; - IStream *stream; - HRESULT hr; - - if (FAILED(hr = CreateStreamOnHGlobal(0, TRUE, &stream))) - return hr; - - hr = MFCreateMFByteStreamOnStream(stream, &bytestream); - IStream_Release(stream); - if (FAILED(hr)) - return hr; - - hr = media_source_create(bytestream, url, out); - IMFByteStream_Release(bytestream); - - return hr; -} diff --git a/dlls/winegstreamer/media_source_old.c b/dlls/winegstreamer/media_source_old.c new file mode 100644 index 00000000000..a2fe13e4da8 --- /dev/null +++ b/dlls/winegstreamer/media_source_old.c @@ -0,0 +1,1668 @@ +/* GStreamer Media Source + * + * Copyright 2020 Derek Lesho + * Copyright 2020 Zebediah Figura 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 + */ + +#include "gst_private.h" + +#include "mfapi.h" +#include "mferror.h" + +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +extern const GUID MFVideoFormat_ABGR32; + +struct media_stream +{ + IMFMediaStream IMFMediaStream_iface; + LONG ref; + + IMFMediaSource *media_source; + IMFMediaEventQueue *event_queue; + IMFStreamDescriptor *descriptor; + + struct wg_parser_stream *wg_stream; + + IUnknown **token_queue; + LONG token_queue_count; + LONG token_queue_cap; + + DWORD stream_id; + BOOL active; + BOOL eos; +}; + +enum source_async_op +{ + SOURCE_ASYNC_START, + SOURCE_ASYNC_PAUSE, + SOURCE_ASYNC_STOP, + SOURCE_ASYNC_REQUEST_SAMPLE, +}; + +struct source_async_command +{ + IUnknown IUnknown_iface; + LONG refcount; + enum source_async_op op; + union + { + struct + { + IMFPresentationDescriptor *descriptor; + GUID format; + PROPVARIANT position; + } start; + struct + { + struct media_stream *stream; + IUnknown *token; + } request_sample; + } u; +}; + +struct media_source +{ + IMFMediaSource IMFMediaSource_iface; + IMFGetService IMFGetService_iface; + IMFRateSupport IMFRateSupport_iface; + IMFRateControl IMFRateControl_iface; + IMFAsyncCallback async_commands_callback; + LONG ref; + DWORD async_commands_queue; + IMFMediaEventQueue *event_queue; + IMFByteStream *byte_stream; + + CRITICAL_SECTION cs; + + struct wg_parser *wg_parser; + + struct media_stream **streams; + ULONG stream_count; + IMFPresentationDescriptor *pres_desc; + enum + { + SOURCE_OPENING, + SOURCE_STOPPED, + SOURCE_PAUSED, + SOURCE_RUNNING, + SOURCE_SHUTDOWN, + } state; + float rate; + + HANDLE read_thread; + bool read_thread_shutdown; +}; + +static inline struct media_stream *impl_from_IMFMediaStream(IMFMediaStream *iface) +{ + return CONTAINING_RECORD(iface, struct media_stream, IMFMediaStream_iface); +} + +static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *iface) +{ + return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface); +} + +static inline struct media_source *impl_from_IMFGetService(IMFGetService *iface) +{ + return CONTAINING_RECORD(iface, struct media_source, IMFGetService_iface); +} + +static inline struct media_source *impl_from_IMFRateSupport(IMFRateSupport *iface) +{ + return CONTAINING_RECORD(iface, struct media_source, IMFRateSupport_iface); +} + +static inline struct media_source *impl_from_IMFRateControl(IMFRateControl *iface) +{ + return CONTAINING_RECORD(iface, struct media_source, IMFRateControl_iface); +} + +static inline struct media_source *impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct media_source, async_commands_callback); +} + +static inline struct source_async_command *impl_from_async_command_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct source_async_command, IUnknown_iface); +} + +static HRESULT WINAPI source_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj) +{ + if (IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IUnknown_AddRef(iface); + return S_OK; + } + + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI source_async_command_AddRef(IUnknown *iface) +{ + struct source_async_command *command = impl_from_async_command_IUnknown(iface); + return InterlockedIncrement(&command->refcount); +} + +static ULONG WINAPI source_async_command_Release(IUnknown *iface) +{ + struct source_async_command *command = impl_from_async_command_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&command->refcount); + + if (!refcount) + { + if (command->op == SOURCE_ASYNC_START) + PropVariantClear(&command->u.start.position); + else if (command->op == SOURCE_ASYNC_REQUEST_SAMPLE) + { + if (command->u.request_sample.token) + IUnknown_Release(command->u.request_sample.token); + } + free(command); + } + + return refcount; +} + +static const IUnknownVtbl source_async_command_vtbl = +{ + source_async_command_QueryInterface, + source_async_command_AddRef, + source_async_command_Release, +}; + +static HRESULT source_create_async_op(enum source_async_op op, struct source_async_command **ret) +{ + struct source_async_command *command; + + if (!(command = calloc(1, sizeof(*command)))) + return E_OUTOFMEMORY; + + command->IUnknown_iface.lpVtbl = &source_async_command_vtbl; + command->op = op; + + *ret = command; + + return S_OK; +} + +static HRESULT WINAPI callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFAsyncCallback) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = iface; + IMFAsyncCallback_AddRef(iface); + return S_OK; + } + + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static HRESULT WINAPI callback_GetParameters(IMFAsyncCallback *iface, + DWORD *flags, DWORD *queue) +{ + return E_NOTIMPL; +} + +static ULONG WINAPI source_async_commands_callback_AddRef(IMFAsyncCallback *iface) +{ + struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface); + return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); +} + +static ULONG WINAPI source_async_commands_callback_Release(IMFAsyncCallback *iface) +{ + struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface); + return IMFMediaSource_Release(&source->IMFMediaSource_iface); +} + +static IMFStreamDescriptor *stream_descriptor_from_id(IMFPresentationDescriptor *pres_desc, DWORD id, BOOL *selected) +{ + ULONG sd_count; + IMFStreamDescriptor *ret; + unsigned int i; + + if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(pres_desc, &sd_count))) + return NULL; + + for (i = 0; i < sd_count; i++) + { + DWORD stream_id; + + if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pres_desc, i, selected, &ret))) + return NULL; + + if (SUCCEEDED(IMFStreamDescriptor_GetStreamIdentifier(ret, &stream_id)) && stream_id == id) + return ret; + + IMFStreamDescriptor_Release(ret); + } + return NULL; +} + +static BOOL enqueue_token(struct media_stream *stream, IUnknown *token) +{ + if (stream->token_queue_count == stream->token_queue_cap) + { + IUnknown **buf; + stream->token_queue_cap = stream->token_queue_cap * 2 + 1; + buf = realloc(stream->token_queue, stream->token_queue_cap * sizeof(*buf)); + if (buf) + stream->token_queue = buf; + else + { + stream->token_queue_cap = stream->token_queue_count; + return FALSE; + } + } + stream->token_queue[stream->token_queue_count++] = token; + return TRUE; +} + +static void flush_token_queue(struct media_stream *stream, BOOL send) +{ + struct media_source *source = impl_from_IMFMediaSource(stream->media_source); + LONG i; + + for (i = 0; i < stream->token_queue_count; i++) + { + if (send) + { + HRESULT hr; + struct source_async_command *command; + if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &command))) + { + command->u.request_sample.stream = stream; + command->u.request_sample.token = stream->token_queue[i]; + + hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, + &command->IUnknown_iface); + } + if (FAILED(hr)) + WARN("Could not enqueue sample request, hr %#lx\n", hr); + } + else if (stream->token_queue[i]) + IUnknown_Release(stream->token_queue[i]); + } + free(stream->token_queue); + stream->token_queue = NULL; + stream->token_queue_count = 0; + stream->token_queue_cap = 0; +} + +static void start_pipeline(struct media_source *source, struct source_async_command *command) +{ + PROPVARIANT *position = &command->u.start.position; + BOOL seek_message = source->state != SOURCE_STOPPED && position->vt != VT_EMPTY; + unsigned int i; + + /* seek to beginning on stop->play */ + if (source->state == SOURCE_STOPPED && position->vt == VT_EMPTY) + { + position->vt = VT_I8; + position->hVal.QuadPart = 0; + } + + for (i = 0; i < source->stream_count; i++) + { + struct media_stream *stream; + IMFStreamDescriptor *sd; + IMFMediaTypeHandler *mth; + IMFMediaType *current_mt; + DWORD stream_id; + BOOL was_active; + BOOL selected; + + stream = source->streams[i]; + + IMFStreamDescriptor_GetStreamIdentifier(stream->descriptor, &stream_id); + + sd = stream_descriptor_from_id(command->u.start.descriptor, stream_id, &selected); + IMFStreamDescriptor_Release(sd); + + was_active = stream->active; + stream->active = selected; + + if (selected) + { + struct wg_format format; + + IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &mth); + IMFMediaTypeHandler_GetCurrentMediaType(mth, ¤t_mt); + + mf_media_type_to_wg_format(current_mt, &format); + wg_parser_stream_enable(stream->wg_stream, &format, 0); + + IMFMediaType_Release(current_mt); + IMFMediaTypeHandler_Release(mth); + } + else + { + wg_parser_stream_disable(stream->wg_stream); + } + + if (position->vt != VT_EMPTY) + stream->eos = FALSE; + + if (selected) + { + TRACE("Stream %u (%p) selected\n", i, stream); + IMFMediaEventQueue_QueueEventParamUnk(source->event_queue, + was_active ? MEUpdatedStream : MENewStream, &GUID_NULL, + S_OK, (IUnknown*) &stream->IMFMediaStream_iface); + + IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, + seek_message ? MEStreamSeeked : MEStreamStarted, &GUID_NULL, S_OK, position); + } + } + + IMFMediaEventQueue_QueueEventParamVar(source->event_queue, + seek_message ? MESourceSeeked : MESourceStarted, + &GUID_NULL, S_OK, position); + + source->state = SOURCE_RUNNING; + + if (position->vt == VT_I8) + wg_parser_stream_seek(source->streams[0]->wg_stream, 1.0, position->hVal.QuadPart, 0, + AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning); + + for (i = 0; i < source->stream_count; i++) + flush_token_queue(source->streams[i], position->vt == VT_EMPTY); +} + +static void pause_pipeline(struct media_source *source) +{ + unsigned int i; + HRESULT hr; + + for (i = 0; i < source->stream_count; i++) + { + struct media_stream *stream = source->streams[i]; + if (stream->active && FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamPaused, + &GUID_NULL, S_OK, NULL))) + WARN("Failed to queue MEStreamPaused event, hr %#lx\n", hr); + } + + IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourcePaused, &GUID_NULL, S_OK, NULL); + + source->state = SOURCE_PAUSED; +} + +static void stop_pipeline(struct media_source *source) +{ + unsigned int i; + HRESULT hr; + + for (i = 0; i < source->stream_count; i++) + { + struct media_stream *stream = source->streams[i]; + if (stream->active && FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamStopped, + &GUID_NULL, S_OK, NULL))) + WARN("Failed to queue MEStreamStopped event, hr %#lx\n", hr); + } + + IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceStopped, &GUID_NULL, S_OK, NULL); + + source->state = SOURCE_STOPPED; + + for (i = 0; i < source->stream_count; i++) + flush_token_queue(source->streams[i], FALSE); +} + +static void dispatch_end_of_presentation(struct media_source *source) +{ + PROPVARIANT empty = {.vt = VT_EMPTY}; + unsigned int i; + + /* A stream has ended, check whether all have */ + for (i = 0; i < source->stream_count; i++) + { + struct media_stream *stream = source->streams[i]; + if (stream->active && !stream->eos) + return; + } + + IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, &empty); +} + +static void send_buffer(struct media_stream *stream, const struct wg_parser_buffer *wg_buffer, IUnknown *token) +{ + IMFMediaBuffer *buffer; + IMFSample *sample; + HRESULT hr; + BYTE *data; + + if (FAILED(hr = MFCreateSample(&sample))) + { + ERR("Failed to create sample, hr %#lx.\n", hr); + return; + } + + if (FAILED(hr = MFCreateMemoryBuffer(wg_buffer->size, &buffer))) + { + ERR("Failed to create buffer, hr %#lx.\n", hr); + IMFSample_Release(sample); + return; + } + + if (FAILED(hr = IMFSample_AddBuffer(sample, buffer))) + { + ERR("Failed to add buffer, hr %#lx.\n", hr); + goto out; + } + + if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, wg_buffer->size))) + { + ERR("Failed to set size, hr %#lx.\n", hr); + goto out; + } + + if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL))) + { + ERR("Failed to lock buffer, hr %#lx.\n", hr); + goto out; + } + + if (!wg_parser_stream_copy_buffer(stream->wg_stream, data, 0, wg_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 = IMFMediaBuffer_Unlock(buffer))) + { + ERR("Failed to unlock buffer, hr %#lx.\n", hr); + goto out; + } + + if (FAILED(hr = IMFSample_SetSampleTime(sample, wg_buffer->pts))) + { + ERR("Failed to set sample time, hr %#lx.\n", hr); + goto out; + } + + if (FAILED(hr = IMFSample_SetSampleDuration(sample, wg_buffer->duration))) + { + ERR("Failed to set sample duration, hr %#lx.\n", hr); + goto out; + } + + if (token) + IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token); + + IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample, + &GUID_NULL, S_OK, (IUnknown *)sample); + +out: + IMFMediaBuffer_Release(buffer); + IMFSample_Release(sample); +} + +static void wait_on_sample(struct media_stream *stream, IUnknown *token) +{ + struct media_source *source = impl_from_IMFMediaSource(stream->media_source); + PROPVARIANT empty_var = {.vt = VT_EMPTY}; + struct wg_parser_buffer buffer; + + TRACE("%p, %p\n", stream, token); + + if (wg_parser_stream_get_buffer(source->wg_parser, stream->wg_stream, &buffer)) + { + send_buffer(stream, &buffer, token); + } + else + { + stream->eos = TRUE; + IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty_var); + dispatch_end_of_presentation(source); + } +} + +static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface); + struct source_async_command *command; + IUnknown *state; + HRESULT hr; + + if (FAILED(hr = IMFAsyncResult_GetState(result, &state))) + return hr; + + EnterCriticalSection(&source->cs); + + command = impl_from_async_command_IUnknown(state); + switch (command->op) + { + case SOURCE_ASYNC_START: + if (source->state != SOURCE_SHUTDOWN) + start_pipeline(source, command); + break; + case SOURCE_ASYNC_PAUSE: + if (source->state != SOURCE_SHUTDOWN) + pause_pipeline(source); + break; + case SOURCE_ASYNC_STOP: + if (source->state != SOURCE_SHUTDOWN) + stop_pipeline(source); + break; + case SOURCE_ASYNC_REQUEST_SAMPLE: + if (source->state == SOURCE_PAUSED) + enqueue_token(command->u.request_sample.stream, command->u.request_sample.token); + else if (source->state == SOURCE_RUNNING) + wait_on_sample(command->u.request_sample.stream, command->u.request_sample.token); + break; + } + + LeaveCriticalSection(&source->cs); + + IUnknown_Release(state); + + return S_OK; +} + +static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl = +{ + callback_QueryInterface, + source_async_commands_callback_AddRef, + source_async_commands_callback_Release, + callback_GetParameters, + source_async_commands_Invoke, +}; + +static DWORD CALLBACK read_thread(void *arg) +{ + struct media_source *source = arg; + IMFByteStream *byte_stream = source->byte_stream; + size_t buffer_size = 4096; + uint64_t file_size; + void *data; + + if (!(data = malloc(buffer_size))) + return 0; + + IMFByteStream_GetLength(byte_stream, &file_size); + + TRACE("Starting read thread for media source %p.\n", source); + + while (!source->read_thread_shutdown) + { + uint64_t offset; + ULONG ret_size; + uint32_t size; + HRESULT hr; + + if (!wg_parser_get_next_read_offset(source->wg_parser, &offset, &size)) + continue; + + if (offset >= file_size) + size = 0; + else if (offset + size >= file_size) + size = file_size - offset; + + /* Some IMFByteStreams (including the standard file-based stream) return + * an error when reading past the file size. */ + if (!size) + { + wg_parser_push_data(source->wg_parser, data, 0); + continue; + } + + if (!array_reserve(&data, &buffer_size, size, 1)) + { + free(data); + return 0; + } + + ret_size = 0; + + if (SUCCEEDED(hr = IMFByteStream_SetCurrentPosition(byte_stream, offset))) + hr = IMFByteStream_Read(byte_stream, data, size, &ret_size); + if (FAILED(hr)) + ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size, offset, hr); + else if (ret_size != size) + ERR("Unexpected short read: requested %u bytes, got %lu.\n", size, ret_size); + wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? data : NULL, ret_size); + } + + free(data); + TRACE("Media source is shutting down; exiting.\n"); + return 0; +} + +static HRESULT WINAPI media_stream_QueryInterface(IMFMediaStream *iface, REFIID riid, void **out) +{ + struct media_stream *stream = impl_from_IMFMediaStream(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IMFMediaStream) || + IsEqualIID(riid, &IID_IMFMediaEventGenerator) || + IsEqualIID(riid, &IID_IUnknown)) + { + *out = &stream->IMFMediaStream_iface; + } + else + { + FIXME("(%s, %p)\n", debugstr_guid(riid), out); + *out = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*out); + return S_OK; +} + +static ULONG WINAPI media_stream_AddRef(IMFMediaStream *iface) +{ + struct media_stream *stream = impl_from_IMFMediaStream(iface); + ULONG ref = InterlockedIncrement(&stream->ref); + + TRACE("%p, refcount %lu.\n", iface, ref); + + return ref; +} + +static ULONG WINAPI media_stream_Release(IMFMediaStream *iface) +{ + struct media_stream *stream = impl_from_IMFMediaStream(iface); + ULONG ref = InterlockedDecrement(&stream->ref); + + TRACE("%p, refcount %lu.\n", iface, ref); + + if (!ref) + { + IMFMediaSource_Release(stream->media_source); + IMFStreamDescriptor_Release(stream->descriptor); + IMFMediaEventQueue_Release(stream->event_queue); + flush_token_queue(stream, FALSE); + free(stream); + } + + return ref; +} + +static HRESULT WINAPI media_stream_GetEvent(IMFMediaStream *iface, DWORD flags, IMFMediaEvent **event) +{ + struct media_stream *stream = impl_from_IMFMediaStream(iface); + + TRACE("%p, %#lx, %p.\n", iface, flags, event); + + return IMFMediaEventQueue_GetEvent(stream->event_queue, flags, event); +} + +static HRESULT WINAPI media_stream_BeginGetEvent(IMFMediaStream *iface, IMFAsyncCallback *callback, IUnknown *state) +{ + struct media_stream *stream = impl_from_IMFMediaStream(iface); + + TRACE("%p, %p, %p.\n", iface, callback, state); + + return IMFMediaEventQueue_BeginGetEvent(stream->event_queue, callback, state); +} + +static HRESULT WINAPI media_stream_EndGetEvent(IMFMediaStream *iface, IMFAsyncResult *result, IMFMediaEvent **event) +{ + struct media_stream *stream = impl_from_IMFMediaStream(iface); + + TRACE("%p, %p, %p.\n", stream, result, event); + + return IMFMediaEventQueue_EndGetEvent(stream->event_queue, result, event); +} + +static HRESULT WINAPI media_stream_QueueEvent(IMFMediaStream *iface, MediaEventType event_type, REFGUID ext_type, + HRESULT hr, const PROPVARIANT *value) +{ + struct media_stream *stream = impl_from_IMFMediaStream(iface); + + TRACE("%p, %lu, %s, %#lx, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value); + + return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value); +} + +static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **out) +{ + struct media_stream *stream = impl_from_IMFMediaStream(iface); + struct media_source *source = impl_from_IMFMediaSource(stream->media_source); + HRESULT hr = S_OK; + + TRACE("%p, %p.\n", iface, out); + + EnterCriticalSection(&source->cs); + + if (source->state == SOURCE_SHUTDOWN) + hr = MF_E_SHUTDOWN; + else + { + IMFMediaSource_AddRef(&source->IMFMediaSource_iface); + *out = &source->IMFMediaSource_iface; + } + + LeaveCriticalSection(&source->cs); + + return hr; +} + +static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IMFStreamDescriptor **descriptor) +{ + struct media_stream *stream = impl_from_IMFMediaStream(iface); + struct media_source *source = impl_from_IMFMediaSource(stream->media_source); + HRESULT hr = S_OK; + + TRACE("%p, %p.\n", iface, descriptor); + + EnterCriticalSection(&source->cs); + + if (source->state == SOURCE_SHUTDOWN) + hr = MF_E_SHUTDOWN; + else + { + IMFStreamDescriptor_AddRef(stream->descriptor); + *descriptor = stream->descriptor; + } + + LeaveCriticalSection(&source->cs); + + return hr; +} + +static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token) +{ + struct media_stream *stream = impl_from_IMFMediaStream(iface); + struct media_source *source = impl_from_IMFMediaSource(stream->media_source); + struct source_async_command *command; + HRESULT hr; + + TRACE("%p, %p.\n", iface, token); + + EnterCriticalSection(&source->cs); + + if (source->state == SOURCE_SHUTDOWN) + hr = MF_E_SHUTDOWN; + else if (!stream->active) + hr = MF_E_MEDIA_SOURCE_WRONGSTATE; + else if (stream->eos) + hr = MF_E_END_OF_STREAM; + else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &command))) + { + command->u.request_sample.stream = stream; + if (token) + IUnknown_AddRef(token); + command->u.request_sample.token = token; + + hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface); + } + + LeaveCriticalSection(&source->cs); + + return hr; +} + +static const IMFMediaStreamVtbl media_stream_vtbl = +{ + media_stream_QueryInterface, + media_stream_AddRef, + media_stream_Release, + media_stream_GetEvent, + media_stream_BeginGetEvent, + media_stream_EndGetEvent, + media_stream_QueueEvent, + media_stream_GetMediaSource, + media_stream_GetStreamDescriptor, + media_stream_RequestSample +}; + +static HRESULT media_stream_create(IMFMediaSource *source, DWORD id, + struct media_stream **out) +{ + struct wg_parser *wg_parser = impl_from_IMFMediaSource(source)->wg_parser; + struct media_stream *object; + HRESULT hr; + + TRACE("source %p, id %lu.\n", source, id); + + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl; + object->ref = 1; + + if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) + { + free(object); + return hr; + } + + IMFMediaSource_AddRef(source); + object->media_source = source; + object->stream_id = id; + + object->active = FALSE; + object->eos = FALSE; + object->wg_stream = wg_parser_get_stream(wg_parser, id); + + TRACE("Created stream object %p.\n", object); + + *out = object; + return S_OK; +} + +static HRESULT media_stream_init_desc(struct media_stream *stream) +{ + IMFMediaTypeHandler *type_handler = NULL; + IMFMediaType *stream_types[9]; + struct wg_format format; + DWORD type_count = 0; + HRESULT hr = S_OK; + unsigned int i; + + wg_parser_stream_get_preferred_format(stream->wg_stream, &format); + + if (format.major_type == WG_MAJOR_TYPE_VIDEO) + { + /* These are the most common native output types of decoders: + https://docs.microsoft.com/en-us/windows/win32/medfound/mft-decoder-expose-output-types-in-native-order */ + static const GUID *const video_types[] = + { + &MFVideoFormat_NV12, + &MFVideoFormat_YV12, + &MFVideoFormat_YUY2, + &MFVideoFormat_IYUV, + &MFVideoFormat_I420, + &MFVideoFormat_ARGB32, + &MFVideoFormat_RGB32, + &MFVideoFormat_ABGR32, + }; + + IMFMediaType *base_type = mf_media_type_from_wg_format(&format); + GUID base_subtype; + + if (!base_type) + { + hr = MF_E_INVALIDMEDIATYPE; + goto done; + } + + IMFMediaType_SetUINT32(base_type, &MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_Normal); + + IMFMediaType_GetGUID(base_type, &MF_MT_SUBTYPE, &base_subtype); + + stream_types[0] = base_type; + type_count = 1; + + for (i = 0; i < ARRAY_SIZE(video_types); i++) + { + IMFMediaType *new_type; + + if (IsEqualGUID(&base_subtype, video_types[i])) + continue; + + if (FAILED(hr = MFCreateMediaType(&new_type))) + goto done; + stream_types[type_count++] = new_type; + + if (FAILED(hr = IMFMediaType_CopyAllItems(base_type, (IMFAttributes *) new_type))) + goto done; + if (FAILED(hr = IMFMediaType_SetGUID(new_type, &MF_MT_SUBTYPE, video_types[i]))) + goto done; + } + } + else if (format.major_type == WG_MAJOR_TYPE_AUDIO) + { + /* Expose at least one PCM and one floating point type for the + consumer to pick from. Moreover, ensure that we expose S16LE first, + as games such as MGSV expect the native media type to be 16 bps. */ + static const enum wg_audio_format audio_types[] = + { + WG_AUDIO_FORMAT_S16LE, + WG_AUDIO_FORMAT_F32LE, + }; + + BOOL has_native_format = FALSE; + + for (i = 0; i < ARRAY_SIZE(audio_types); i++) + { + struct wg_format new_format; + + new_format = format; + new_format.u.audio.format = audio_types[i]; + if ((stream_types[type_count] = mf_media_type_from_wg_format(&new_format))) + { + if (format.u.audio.format == audio_types[i]) + has_native_format = TRUE; + type_count++; + } + } + + if (!has_native_format && (stream_types[type_count] = mf_media_type_from_wg_format(&format))) + type_count++; + } + else + { + if ((stream_types[0] = mf_media_type_from_wg_format(&format))) + type_count = 1; + } + + assert(type_count <= ARRAY_SIZE(stream_types)); + + if (!type_count) + { + ERR("Failed to establish an IMFMediaType from any of the possible stream caps!\n"); + return E_FAIL; + } + + if (FAILED(hr = MFCreateStreamDescriptor(stream->stream_id, type_count, stream_types, &stream->descriptor))) + goto done; + + if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &type_handler))) + { + IMFStreamDescriptor_Release(stream->descriptor); + goto done; + } + + if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, stream_types[0]))) + { + IMFStreamDescriptor_Release(stream->descriptor); + goto done; + } + +done: + if (type_handler) + IMFMediaTypeHandler_Release(type_handler); + for (i = 0; i < type_count; i++) + IMFMediaType_Release(stream_types[i]); + return hr; +} + +static HRESULT WINAPI media_source_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj) +{ + struct media_source *source = impl_from_IMFGetService(iface); + return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); +} + +static ULONG WINAPI media_source_get_service_AddRef(IMFGetService *iface) +{ + struct media_source *source = impl_from_IMFGetService(iface); + return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); +} + +static ULONG WINAPI media_source_get_service_Release(IMFGetService *iface) +{ + struct media_source *source = impl_from_IMFGetService(iface); + return IMFMediaSource_Release(&source->IMFMediaSource_iface); +} + +static HRESULT WINAPI media_source_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj) +{ + struct media_source *source = impl_from_IMFGetService(iface); + + TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj); + + *obj = NULL; + + if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE)) + { + if (IsEqualIID(riid, &IID_IMFRateSupport)) + { + *obj = &source->IMFRateSupport_iface; + } + else if (IsEqualIID(riid, &IID_IMFRateControl)) + { + *obj = &source->IMFRateControl_iface; + } + } + else + FIXME("Unsupported service %s.\n", debugstr_guid(service)); + + if (*obj) + IUnknown_AddRef((IUnknown *)*obj); + + return *obj ? S_OK : E_NOINTERFACE; +} + +static const IMFGetServiceVtbl media_source_get_service_vtbl = +{ + media_source_get_service_QueryInterface, + media_source_get_service_AddRef, + media_source_get_service_Release, + media_source_get_service_GetService, +}; + +static HRESULT WINAPI media_source_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj) +{ + struct media_source *source = impl_from_IMFRateSupport(iface); + return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); +} + +static ULONG WINAPI media_source_rate_support_AddRef(IMFRateSupport *iface) +{ + struct media_source *source = impl_from_IMFRateSupport(iface); + return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); +} + +static ULONG WINAPI media_source_rate_support_Release(IMFRateSupport *iface) +{ + struct media_source *source = impl_from_IMFRateSupport(iface); + return IMFMediaSource_Release(&source->IMFMediaSource_iface); +} + +static HRESULT WINAPI media_source_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate) +{ + TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate); + + *rate = 0.0f; + + return S_OK; +} + +static HRESULT WINAPI media_source_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate) +{ + TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate); + + *rate = direction == MFRATE_FORWARD ? 1e6f : -1e6f; + + return S_OK; +} + +static HRESULT WINAPI media_source_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate, + float *nearest_rate) +{ + TRACE("%p, %d, %f, %p.\n", iface, thin, rate, nearest_rate); + + if (nearest_rate) + *nearest_rate = rate; + + return rate >= -1e6f && rate <= 1e6f ? S_OK : MF_E_UNSUPPORTED_RATE; +} + +static const IMFRateSupportVtbl media_source_rate_support_vtbl = +{ + media_source_rate_support_QueryInterface, + media_source_rate_support_AddRef, + media_source_rate_support_Release, + media_source_rate_support_GetSlowestRate, + media_source_rate_support_GetFastestRate, + media_source_rate_support_IsRateSupported, +}; + +static HRESULT WINAPI media_source_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj) +{ + struct media_source *source = impl_from_IMFRateControl(iface); + return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj); +} + +static ULONG WINAPI media_source_rate_control_AddRef(IMFRateControl *iface) +{ + struct media_source *source = impl_from_IMFRateControl(iface); + return IMFMediaSource_AddRef(&source->IMFMediaSource_iface); +} + +static ULONG WINAPI media_source_rate_control_Release(IMFRateControl *iface) +{ + struct media_source *source = impl_from_IMFRateControl(iface); + return IMFMediaSource_Release(&source->IMFMediaSource_iface); +} + +static HRESULT WINAPI media_source_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate) +{ + struct media_source *source = impl_from_IMFRateControl(iface); + HRESULT hr; + + FIXME("%p, %d, %f.\n", iface, thin, rate); + + if (rate < 0.0f) + return MF_E_REVERSE_UNSUPPORTED; + + if (thin) + return MF_E_THINNING_UNSUPPORTED; + + if (FAILED(hr = IMFRateSupport_IsRateSupported(&source->IMFRateSupport_iface, thin, rate, NULL))) + return hr; + + EnterCriticalSection(&source->cs); + source->rate = rate; + LeaveCriticalSection(&source->cs); + + return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceRateChanged, &GUID_NULL, S_OK, NULL); +} + +static HRESULT WINAPI media_source_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate) +{ + struct media_source *source = impl_from_IMFRateControl(iface); + + TRACE("%p, %p, %p.\n", iface, thin, rate); + + if (thin) + *thin = FALSE; + + EnterCriticalSection(&source->cs); + *rate = source->rate; + LeaveCriticalSection(&source->cs); + + return S_OK; +} + +static const IMFRateControlVtbl media_source_rate_control_vtbl = +{ + media_source_rate_control_QueryInterface, + media_source_rate_control_AddRef, + media_source_rate_control_Release, + media_source_rate_control_SetRate, + media_source_rate_control_GetRate, +}; + +static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IMFMediaSource) || + IsEqualIID(riid, &IID_IMFMediaEventGenerator) || + IsEqualIID(riid, &IID_IUnknown)) + { + *out = &source->IMFMediaSource_iface; + } + else if (IsEqualIID(riid, &IID_IMFGetService)) + { + *out = &source->IMFGetService_iface; + } + else + { + FIXME("%s, %p.\n", debugstr_guid(riid), out); + *out = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*out); + return S_OK; +} + +static ULONG WINAPI media_source_AddRef(IMFMediaSource *iface) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + ULONG ref = InterlockedIncrement(&source->ref); + + TRACE("%p, refcount %lu.\n", iface, ref); + + return ref; +} + +static ULONG WINAPI media_source_Release(IMFMediaSource *iface) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + ULONG ref = InterlockedDecrement(&source->ref); + + TRACE("%p, refcount %lu.\n", iface, ref); + + if (!ref) + { + IMFMediaSource_Shutdown(iface); + IMFPresentationDescriptor_Release(source->pres_desc); + IMFMediaEventQueue_Release(source->event_queue); + IMFByteStream_Release(source->byte_stream); + wg_parser_destroy(source->wg_parser); + source->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&source->cs); + free(source); + } + + return ref; +} + +static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + + TRACE("%p, %#lx, %p.\n", iface, flags, event); + + return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event); +} + +static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + + TRACE("%p, %p, %p.\n", iface, callback, state); + + return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state); +} + +static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + + TRACE("%p, %p, %p.\n", iface, result, event); + + return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event); +} + +static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type, + HRESULT hr, const PROPVARIANT *value) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + + TRACE("%p, %lu, %s, %#lx, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value); + + return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value); +} + +static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + HRESULT hr = S_OK; + + TRACE("%p, %p.\n", iface, characteristics); + + EnterCriticalSection(&source->cs); + + if (source->state == SOURCE_SHUTDOWN) + hr = MF_E_SHUTDOWN; + else + *characteristics = MFMEDIASOURCE_CAN_SEEK | MFMEDIASOURCE_CAN_PAUSE; + + LeaveCriticalSection(&source->cs); + + return hr; +} + +static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + HRESULT hr; + + TRACE("%p, %p.\n", iface, descriptor); + + EnterCriticalSection(&source->cs); + + if (source->state == SOURCE_SHUTDOWN) + hr = MF_E_SHUTDOWN; + else + hr = IMFPresentationDescriptor_Clone(source->pres_desc, descriptor); + + LeaveCriticalSection(&source->cs); + + return hr; +} + +static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor, + const GUID *time_format, const PROPVARIANT *position) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + struct source_async_command *command; + HRESULT hr; + + TRACE("%p, %p, %p, %p.\n", iface, descriptor, time_format, position); + + EnterCriticalSection(&source->cs); + + if (source->state == SOURCE_SHUTDOWN) + hr = MF_E_SHUTDOWN; + else if (!(IsEqualIID(time_format, &GUID_NULL))) + hr = MF_E_UNSUPPORTED_TIME_FORMAT; + else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_START, &command))) + { + command->u.start.descriptor = descriptor; + command->u.start.format = *time_format; + PropVariantCopy(&command->u.start.position, position); + + hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface); + } + + LeaveCriticalSection(&source->cs); + + return hr; +} + +static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + struct source_async_command *command; + HRESULT hr; + + TRACE("%p.\n", iface); + + EnterCriticalSection(&source->cs); + + if (source->state == SOURCE_SHUTDOWN) + hr = MF_E_SHUTDOWN; + else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_STOP, &command))) + hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface); + + LeaveCriticalSection(&source->cs); + + return hr; +} + +static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + struct source_async_command *command; + HRESULT hr; + + TRACE("%p.\n", iface); + + EnterCriticalSection(&source->cs); + + if (source->state == SOURCE_SHUTDOWN) + hr = MF_E_SHUTDOWN; + else if (source->state != SOURCE_RUNNING) + hr = MF_E_INVALID_STATE_TRANSITION; + else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_PAUSE, &command))) + hr = MFPutWorkItem(source->async_commands_queue, + &source->async_commands_callback, &command->IUnknown_iface); + + LeaveCriticalSection(&source->cs); + + return S_OK; +} + +static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) +{ + struct media_source *source = impl_from_IMFMediaSource(iface); + + TRACE("%p.\n", iface); + + EnterCriticalSection(&source->cs); + + if (source->state == SOURCE_SHUTDOWN) + { + LeaveCriticalSection(&source->cs); + return MF_E_SHUTDOWN; + } + + source->state = SOURCE_SHUTDOWN; + + wg_parser_disconnect(source->wg_parser); + + source->read_thread_shutdown = true; + WaitForSingleObject(source->read_thread, INFINITE); + CloseHandle(source->read_thread); + + IMFMediaEventQueue_Shutdown(source->event_queue); + IMFByteStream_Close(source->byte_stream); + + while (source->stream_count--) + { + struct media_stream *stream = source->streams[source->stream_count]; + IMFMediaEventQueue_Shutdown(stream->event_queue); + IMFMediaStream_Release(&stream->IMFMediaStream_iface); + } + free(source->streams); + + MFUnlockWorkQueue(source->async_commands_queue); + + LeaveCriticalSection(&source->cs); + + return S_OK; +} + +static const IMFMediaSourceVtbl IMFMediaSource_vtbl = +{ + media_source_QueryInterface, + media_source_AddRef, + media_source_Release, + media_source_GetEvent, + media_source_BeginGetEvent, + media_source_EndGetEvent, + media_source_QueueEvent, + media_source_GetCharacteristics, + media_source_CreatePresentationDescriptor, + media_source_Start, + media_source_Stop, + media_source_Pause, + media_source_Shutdown, +}; + +HRESULT media_source_create_old(IMFByteStream *bytestream, const WCHAR *uri, IMFMediaSource **out) +{ + BOOL video_selected = FALSE, audio_selected = FALSE; + IMFStreamDescriptor **descriptors = NULL; + unsigned int stream_count = UINT_MAX; + struct media_source *object; + UINT64 total_pres_time = 0; + struct wg_parser *parser; + DWORD bytestream_caps; + uint64_t file_size; + unsigned int i; + HRESULT hr; + + if (FAILED(hr = IMFByteStream_GetCapabilities(bytestream, &bytestream_caps))) + return hr; + + if (!(bytestream_caps & MFBYTESTREAM_IS_SEEKABLE)) + { + FIXME("Non-seekable bytestreams not supported.\n"); + return MF_E_BYTESTREAM_NOT_SEEKABLE; + } + + if (FAILED(hr = IMFByteStream_GetLength(bytestream, &file_size))) + { + FIXME("Failed to get byte stream length, hr %#lx.\n", hr); + return hr; + } + + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl; + object->IMFGetService_iface.lpVtbl = &media_source_get_service_vtbl; + object->IMFRateSupport_iface.lpVtbl = &media_source_rate_support_vtbl; + object->IMFRateControl_iface.lpVtbl = &media_source_rate_control_vtbl; + object->async_commands_callback.lpVtbl = &source_async_commands_callback_vtbl; + object->ref = 1; + object->byte_stream = bytestream; + IMFByteStream_AddRef(bytestream); + object->rate = 1.0f; + InitializeCriticalSection(&object->cs); + object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs"); + + if (FAILED(hr = MFCreateEventQueue(&object->event_queue))) + goto fail; + + if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue))) + goto fail; + + if (!(parser = wg_parser_create(uri ? WG_PARSER_URIDECODEBIN : WG_PARSER_DECODEBIN, false))) + { + hr = E_OUTOFMEMORY; + goto fail; + } + object->wg_parser = parser; + + object->read_thread = CreateThread(NULL, 0, read_thread, object, 0, NULL); + + object->state = SOURCE_OPENING; + + if (FAILED(hr = wg_parser_connect(parser, file_size, uri))) + goto fail; + + stream_count = wg_parser_get_stream_count(parser); + + if (!(object->streams = calloc(stream_count, sizeof(*object->streams)))) + { + hr = E_OUTOFMEMORY; + goto fail; + } + + for (i = 0; i < stream_count; ++i) + { + if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, i, &object->streams[i]))) + goto fail; + + if (FAILED(hr = media_stream_init_desc(object->streams[i]))) + { + ERR("Failed to finish initialization of media stream %p, hr %#lx.\n", object->streams[i], hr); + IMFMediaSource_Release(object->streams[i]->media_source); + IMFMediaEventQueue_Release(object->streams[i]->event_queue); + free(object->streams[i]); + goto fail; + } + + object->stream_count++; + } + + /* init presentation descriptor */ + + descriptors = malloc(object->stream_count * sizeof(IMFStreamDescriptor *)); + for (i = 0; i < object->stream_count; i++) + { + static const struct + { + enum wg_parser_tag tag; + const GUID *mf_attr; + } + tags[] = + { + {WG_PARSER_TAG_LANGUAGE, &MF_SD_LANGUAGE}, + {WG_PARSER_TAG_NAME, &MF_SD_STREAM_NAME}, + }; + IMFStreamDescriptor **descriptor = descriptors + object->stream_count - 1 - i; + unsigned int j; + WCHAR *strW; + DWORD len; + char *str; + + IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, descriptor); + + for (j = 0; j < ARRAY_SIZE(tags); ++j) + { + if (!(str = wg_parser_stream_get_tag(object->streams[i]->wg_stream, tags[j].tag))) + continue; + if (!(len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0))) + { + free(str); + continue; + } + strW = malloc(len * sizeof(*strW)); + if (MultiByteToWideChar(CP_UTF8, 0, str, -1, strW, len)) + IMFStreamDescriptor_SetString(*descriptor, tags[j].mf_attr, strW); + free(strW); + free(str); + } + } + + if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc))) + goto fail; + + /* Select one of each major type. */ + for (i = 0; i < object->stream_count; i++) + { + IMFMediaTypeHandler *handler; + GUID major_type; + BOOL select_stream = FALSE; + + IMFStreamDescriptor_GetMediaTypeHandler(descriptors[i], &handler); + IMFMediaTypeHandler_GetMajorType(handler, &major_type); + if (IsEqualGUID(&major_type, &MFMediaType_Video) && !video_selected) + { + select_stream = TRUE; + video_selected = TRUE; + } + if (IsEqualGUID(&major_type, &MFMediaType_Audio) && !audio_selected) + { + select_stream = TRUE; + audio_selected = TRUE; + } + if (select_stream) + IMFPresentationDescriptor_SelectStream(object->pres_desc, i); + IMFMediaTypeHandler_Release(handler); + IMFStreamDescriptor_Release(descriptors[i]); + } + free(descriptors); + descriptors = NULL; + + for (i = 0; i < object->stream_count; i++) + total_pres_time = max(total_pres_time, + wg_parser_stream_get_duration(object->streams[i]->wg_stream)); + + if (object->stream_count) + IMFPresentationDescriptor_SetUINT64(object->pres_desc, &MF_PD_DURATION, total_pres_time); + + object->state = SOURCE_STOPPED; + + *out = &object->IMFMediaSource_iface; + return S_OK; + + fail: + WARN("Failed to construct MFMediaSource, hr %#lx.\n", hr); + + if (descriptors) + { + for (i = 0; i < object->stream_count; i++) + IMFStreamDescriptor_Release(descriptors[i]); + free(descriptors); + } + + while (object->streams && object->stream_count--) + { + struct media_stream *stream = object->streams[object->stream_count]; + IMFMediaStream_Release(&stream->IMFMediaStream_iface); + } + free(object->streams); + + if (stream_count != UINT_MAX) + wg_parser_disconnect(object->wg_parser); + if (object->read_thread) + { + object->read_thread_shutdown = true; + WaitForSingleObject(object->read_thread, INFINITE); + CloseHandle(object->read_thread); + } + if (object->wg_parser) + wg_parser_destroy(object->wg_parser); + if (object->async_commands_queue) + MFUnlockWorkQueue(object->async_commands_queue); + if (object->event_queue) + IMFMediaEventQueue_Release(object->event_queue); + IMFByteStream_Release(object->byte_stream); + free(object); + return hr; +} + +HRESULT media_source_create_from_url(const WCHAR *url, IMFMediaSource **out) +{ + IMFByteStream *bytestream; + IStream *stream; + HRESULT hr; + + if (FAILED(hr = CreateStreamOnHGlobal(0, TRUE, &stream))) + return hr; + + hr = MFCreateMFByteStreamOnStream(stream, &bytestream); + IStream_Release(stream); + if (FAILED(hr)) + return hr; + + hr = media_source_create_old(bytestream, url, out); + IMFByteStream_Release(bytestream); + + return hr; +} diff --git a/dlls/winegstreamer/mf_handler.c b/dlls/winegstreamer/mf_handler.c index 3d7f36e749c..7472f8c324a 100644 --- a/dlls/winegstreamer/mf_handler.c +++ b/dlls/winegstreamer/mf_handler.c @@ -173,10 +173,16 @@ static HRESULT async_create_object_complete(struct async_create_object *async, if (async->flags & MF_RESOLUTION_MEDIASOURCE) { + const char *env = getenv("WINE_NEW_MEDIA_SOURCE"); if (!async->stream) hr = media_source_create_from_url(async->url, (IMFMediaSource **)&object); - else - hr = media_source_create(async->stream, NULL, (IMFMediaSource **)&object); + else if (!env || !atoi(env)) + hr = media_source_create_old(async->stream, NULL, (IMFMediaSource **)&object); + else if (FAILED(hr = media_source_create(async->stream, async->url, async->buffer, async->size, (IMFMediaSource **)&object))) + { + FIXME("Failed to create new media source, falling back to old implementation, hr %#lx\n", hr); + hr = media_source_create_old(async->stream, NULL, (IMFMediaSource **)&object); + } } else { From 52775088d4bf9cb88db6c1d9817902d83a6eabce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 May 2023 10:54:03 +0200 Subject: [PATCH 1953/2777] Revert "HACK: winegstreamer: Expose S16LE as the first native media type in MFSourceReader." This reverts commit f5f7e7f9b5699d6be6956836b6655c814a9b3efc. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index ec1223c7bfd..5832d9c912e 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -937,32 +937,26 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) else if (format.major_type == WG_MAJOR_TYPE_AUDIO) { /* Expose at least one PCM and one floating point type for the - consumer to pick from. Moreover, ensure that we expose S16LE first, - as games such as MGSV expect the native media type to be 16 bps. */ + consumer to pick from. */ static const enum wg_audio_format audio_types[] = { WG_AUDIO_FORMAT_S16LE, WG_AUDIO_FORMAT_F32LE, }; - BOOL has_native_format = FALSE; + if ((stream_types[0] = mf_media_type_from_wg_format(&format))) + type_count = 1; for (i = 0; i < ARRAY_SIZE(audio_types); i++) { struct wg_format new_format; - + if (format.u.audio.format == audio_types[i]) + continue; new_format = format; new_format.u.audio.format = audio_types[i]; if ((stream_types[type_count] = mf_media_type_from_wg_format(&new_format))) - { - if (format.u.audio.format == audio_types[i]) - has_native_format = TRUE; type_count++; - } } - - if (!has_native_format && (stream_types[type_count] = mf_media_type_from_wg_format(&format))) - type_count++; } else { From b8fdbba718b0224bd889e68cd038248bd537d8d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 May 2023 10:54:12 +0200 Subject: [PATCH 1954/2777] Revert "winegstreamer: Add MF_MT_VIDEO_NOMINAL_RANGE attribute to base video output type." This reverts commit ab7bba8affa3f99c71daa70a202b526a91bff806. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 5832d9c912e..40f989781b3 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -910,8 +910,6 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) goto done; } - IMFMediaType_SetUINT32(base_type, &MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_Normal); - IMFMediaType_GetGUID(base_type, &MF_MT_SUBTYPE, &base_subtype); stream_types[0] = base_type; From 4d475e5037e42cbd5037555247058c72da0c3be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 May 2023 10:54:15 +0200 Subject: [PATCH 1955/2777] Revert "winegstreamer: Add MFVideoFormat_ABGR32 media type to media source video stream descriptor." This reverts commit 08929931ec120b7370696dca5943b2da64b4cd7e. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 40f989781b3..00840f8b2ec 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -27,8 +27,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); -extern const GUID MFVideoFormat_ABGR32; - struct media_stream { IMFMediaStream IMFMediaStream_iface; @@ -877,7 +875,7 @@ static HRESULT media_stream_create(IMFMediaSource *source, DWORD id, static HRESULT media_stream_init_desc(struct media_stream *stream) { IMFMediaTypeHandler *type_handler = NULL; - IMFMediaType *stream_types[9]; + IMFMediaType *stream_types[8]; struct wg_format format; DWORD type_count = 0; HRESULT hr = S_OK; @@ -898,7 +896,6 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) &MFVideoFormat_I420, &MFVideoFormat_ARGB32, &MFVideoFormat_RGB32, - &MFVideoFormat_ABGR32, }; IMFMediaType *base_type = mf_media_type_from_wg_format(&format); From 605bf6ec04c854e4ef67c1e655adc8f8a61484af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 May 2023 10:54:27 +0200 Subject: [PATCH 1956/2777] Revert "winegstreamer: Add MFVideoFormat_RGB32 output for the source." This reverts commit 1f337574a6a6bbd09ae80e818c20b80dfaddc91b. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 00840f8b2ec..732285ad09f 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -875,7 +875,7 @@ static HRESULT media_stream_create(IMFMediaSource *source, DWORD id, static HRESULT media_stream_init_desc(struct media_stream *stream) { IMFMediaTypeHandler *type_handler = NULL; - IMFMediaType *stream_types[8]; + IMFMediaType *stream_types[7]; struct wg_format format; DWORD type_count = 0; HRESULT hr = S_OK; @@ -895,7 +895,6 @@ 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 08da46e553e8b1c418848700bde86725a9e4034b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 May 2023 10:54:30 +0200 Subject: [PATCH 1957/2777] Revert "winegstreamer: Add MFVideoFormat_ARGB32 output for the source." This reverts commit 39e48f1a2ac64d43694a7baa5ae7ebe84b866550. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 732285ad09f..36d3d2674ad 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -875,7 +875,7 @@ static HRESULT media_stream_create(IMFMediaSource *source, DWORD id, static HRESULT media_stream_init_desc(struct media_stream *stream) { IMFMediaTypeHandler *type_handler = NULL; - IMFMediaType *stream_types[7]; + IMFMediaType *stream_types[6]; struct wg_format format; DWORD type_count = 0; HRESULT hr = S_OK; @@ -894,7 +894,6 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) &MFVideoFormat_YUY2, &MFVideoFormat_IYUV, &MFVideoFormat_I420, - &MFVideoFormat_ARGB32, }; IMFMediaType *base_type = mf_media_type_from_wg_format(&format); From 10822f6258fcd7103043b5c0ae81c076876e6659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 May 2023 10:54:34 +0200 Subject: [PATCH 1958/2777] Revert "winegstreamer: In the default configuration, select one stream of each major type." This reverts commit bedb7b53764576d95dd01ea99fc6f290edc9ed3a. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 36d3d2674ad..8e0c2b4068f 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1430,7 +1430,6 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *data, UINT64 size, IMFMediaSource **out) { - BOOL video_selected = FALSE, audio_selected = FALSE; IMFStreamDescriptor **descriptors = NULL; unsigned int stream_count = UINT_MAX; struct media_source *object; @@ -1559,28 +1558,9 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc))) goto fail; - /* Select one of each major type. */ for (i = 0; i < object->stream_count; i++) { - IMFMediaTypeHandler *handler; - GUID major_type; - BOOL select_stream = FALSE; - - IMFStreamDescriptor_GetMediaTypeHandler(descriptors[i], &handler); - IMFMediaTypeHandler_GetMajorType(handler, &major_type); - if (IsEqualGUID(&major_type, &MFMediaType_Video) && !video_selected) - { - select_stream = TRUE; - video_selected = TRUE; - } - if (IsEqualGUID(&major_type, &MFMediaType_Audio) && !audio_selected) - { - select_stream = TRUE; - audio_selected = TRUE; - } - if (select_stream) - IMFPresentationDescriptor_SelectStream(object->pres_desc, i); - IMFMediaTypeHandler_Release(handler); + IMFPresentationDescriptor_SelectStream(object->pres_desc, i); IMFStreamDescriptor_Release(descriptors[i]); } free(descriptors); From bbe60680b4d60e2244073fa4a9155572e0a8ef1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 May 2023 10:54:37 +0200 Subject: [PATCH 1959/2777] Revert "winegstreamer: Report streams backwards in media source." This reverts commit 4f3d59529f9c4dc9f06cae344cf796275b85558e. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 8e0c2b4068f..2c397dd6be5 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1530,13 +1530,12 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d {WG_PARSER_TAG_LANGUAGE, &MF_SD_LANGUAGE}, {WG_PARSER_TAG_NAME, &MF_SD_STREAM_NAME}, }; - IMFStreamDescriptor **descriptor = descriptors + object->stream_count - 1 - i; unsigned int j; WCHAR *strW; DWORD len; char *str; - IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, descriptor); + IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[i]); for (j = 0; j < ARRAY_SIZE(tags); ++j) { @@ -1549,7 +1548,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d } strW = malloc(len * sizeof(*strW)); if (MultiByteToWideChar(CP_UTF8, 0, str, -1, strW, len)) - IMFStreamDescriptor_SetString(*descriptor, tags[j].mf_attr, strW); + IMFStreamDescriptor_SetString(descriptors[i], tags[j].mf_attr, strW); free(strW); free(str); } From 1912f053b64aaff4918d2265ba81c78409a97e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 17 Apr 2023 12:20:25 +0200 Subject: [PATCH 1960/2777] winegstreamer: Return a IUnknown pointer from source_create_async_op. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 41 ++++++++++++++++--------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 2c397dd6be5..efde37f7523 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -191,7 +191,7 @@ static const IUnknownVtbl source_async_command_vtbl = source_async_command_Release, }; -static HRESULT source_create_async_op(enum source_async_op op, struct source_async_command **ret) +static HRESULT source_create_async_op(enum source_async_op op, IUnknown **out) { struct source_async_command *command; @@ -201,8 +201,7 @@ static HRESULT source_create_async_op(enum source_async_op op, struct source_asy command->IUnknown_iface.lpVtbl = &source_async_command_vtbl; command->op = op; - *ret = command; - + *out = &command->IUnknown_iface; return S_OK; } @@ -293,15 +292,16 @@ static void flush_token_queue(struct media_stream *stream, BOOL send) { if (send) { + IUnknown *op; HRESULT hr; - struct source_async_command *command; - if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &command))) + + if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &op))) { + struct source_async_command *command = impl_from_async_command_IUnknown(op); command->u.request_sample.stream = stream; command->u.request_sample.token = stream->token_queue[i]; - hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, - &command->IUnknown_iface); + hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op); } if (FAILED(hr)) WARN("Could not enqueue sample request, hr %#lx\n", hr); @@ -795,7 +795,7 @@ static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown { struct media_stream *stream = impl_from_IMFMediaStream(iface); struct media_source *source = impl_from_IMFMediaSource(stream->media_source); - struct source_async_command *command; + IUnknown *op; HRESULT hr; TRACE("%p, %p.\n", iface, token); @@ -808,14 +808,15 @@ static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown hr = MF_E_MEDIA_SOURCE_WRONGSTATE; else if (stream->eos) hr = MF_E_END_OF_STREAM; - else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &command))) + else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &op))) { + struct source_async_command *command = impl_from_async_command_IUnknown(op); command->u.request_sample.stream = stream; if (token) IUnknown_AddRef(token); command->u.request_sample.token = token; - hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface); + hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op); } LeaveCriticalSection(&source->cs); @@ -1303,7 +1304,7 @@ static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationD const GUID *time_format, const PROPVARIANT *position) { struct media_source *source = impl_from_IMFMediaSource(iface); - struct source_async_command *command; + IUnknown *op; HRESULT hr; TRACE("%p, %p, %p, %p.\n", iface, descriptor, time_format, position); @@ -1314,13 +1315,14 @@ static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationD hr = MF_E_SHUTDOWN; else if (!(IsEqualIID(time_format, &GUID_NULL))) hr = MF_E_UNSUPPORTED_TIME_FORMAT; - else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_START, &command))) + else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_START, &op))) { + struct source_async_command *command = impl_from_async_command_IUnknown(op); command->u.start.descriptor = descriptor; command->u.start.format = *time_format; PropVariantCopy(&command->u.start.position, position); - hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface); + hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op); } LeaveCriticalSection(&source->cs); @@ -1331,7 +1333,7 @@ static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationD static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface) { struct media_source *source = impl_from_IMFMediaSource(iface); - struct source_async_command *command; + IUnknown *op; HRESULT hr; TRACE("%p.\n", iface); @@ -1340,8 +1342,8 @@ static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface) if (source->state == SOURCE_SHUTDOWN) hr = MF_E_SHUTDOWN; - else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_STOP, &command))) - hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface); + else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_STOP, &op))) + hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op); LeaveCriticalSection(&source->cs); @@ -1351,7 +1353,7 @@ static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface) static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) { struct media_source *source = impl_from_IMFMediaSource(iface); - struct source_async_command *command; + IUnknown *op; HRESULT hr; TRACE("%p.\n", iface); @@ -1362,9 +1364,8 @@ static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) hr = MF_E_SHUTDOWN; else if (source->state != SOURCE_RUNNING) hr = MF_E_INVALID_STATE_TRANSITION; - else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_PAUSE, &command))) - hr = MFPutWorkItem(source->async_commands_queue, - &source->async_commands_callback, &command->IUnknown_iface); + else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_PAUSE, &op))) + hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op); LeaveCriticalSection(&source->cs); From 1adb330371bc8521e1f4f1b9928c5828e7222426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Apr 2023 21:52:36 +0200 Subject: [PATCH 1961/2777] winegstreamer: Avoid leaking media source async commands. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index efde37f7523..2e1221d1fed 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -199,6 +199,7 @@ static HRESULT source_create_async_op(enum source_async_op op, IUnknown **out) return E_OUTOFMEMORY; command->IUnknown_iface.lpVtbl = &source_async_command_vtbl; + command->refcount = 1; command->op = op; *out = &command->IUnknown_iface; @@ -302,6 +303,7 @@ static void flush_token_queue(struct media_stream *stream, BOOL send) command->u.request_sample.token = stream->token_queue[i]; hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op); + IUnknown_Release(op); } if (FAILED(hr)) WARN("Could not enqueue sample request, hr %#lx\n", hr); @@ -817,6 +819,7 @@ static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown command->u.request_sample.token = token; hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op); + IUnknown_Release(op); } LeaveCriticalSection(&source->cs); @@ -1323,6 +1326,7 @@ static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationD PropVariantCopy(&command->u.start.position, position); hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op); + IUnknown_Release(op); } LeaveCriticalSection(&source->cs); @@ -1343,7 +1347,10 @@ static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface) if (source->state == SOURCE_SHUTDOWN) hr = MF_E_SHUTDOWN; else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_STOP, &op))) + { hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op); + IUnknown_Release(op); + } LeaveCriticalSection(&source->cs); @@ -1365,7 +1372,10 @@ static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) else if (source->state != SOURCE_RUNNING) hr = MF_E_INVALID_STATE_TRANSITION; else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_PAUSE, &op))) + { hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op); + IUnknown_Release(op); + } LeaveCriticalSection(&source->cs); From bb0581dc880fd8753f0f2d76c47ed74a17836716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 29 Apr 2023 11:40:19 +0200 Subject: [PATCH 1962/2777] winegstreamer: Convert stream descriptor media type to wg_format using helpers. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 41 ++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 2e1221d1fed..15c8721c83f 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -241,6 +241,32 @@ static ULONG WINAPI source_async_commands_callback_Release(IMFAsyncCallback *ifa return IMFMediaSource_Release(&source->IMFMediaSource_iface); } +static HRESULT stream_descriptor_get_media_type(IMFStreamDescriptor *descriptor, IMFMediaType **media_type) +{ + IMFMediaTypeHandler *handler; + HRESULT hr; + + if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(descriptor, &handler))) + return hr; + hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, media_type); + IMFMediaTypeHandler_Release(handler); + + return hr; +} + +static HRESULT wg_format_from_stream_descriptor(IMFStreamDescriptor *descriptor, struct wg_format *format) +{ + IMFMediaType *media_type; + HRESULT hr; + + if (FAILED(hr = stream_descriptor_get_media_type(descriptor, &media_type))) + return hr; + mf_media_type_to_wg_format(media_type, format); + IMFMediaType_Release(media_type); + + return hr; +} + static IMFStreamDescriptor *stream_descriptor_from_id(IMFPresentationDescriptor *pres_desc, DWORD id, BOOL *selected) { ULONG sd_count; @@ -322,6 +348,7 @@ static void start_pipeline(struct media_source *source, struct source_async_comm PROPVARIANT *position = &command->u.start.position; BOOL seek_message = source->state != SOURCE_STOPPED && position->vt != VT_EMPTY; unsigned int i; + HRESULT hr; /* seek to beginning on stop->play */ if (source->state == SOURCE_STOPPED && position->vt == VT_EMPTY) @@ -334,8 +361,7 @@ static void start_pipeline(struct media_source *source, struct source_async_comm { struct media_stream *stream; IMFStreamDescriptor *sd; - IMFMediaTypeHandler *mth; - IMFMediaType *current_mt; + struct wg_format format; DWORD stream_id; BOOL was_active; BOOL selected; @@ -352,16 +378,9 @@ static void start_pipeline(struct media_source *source, struct source_async_comm if (selected) { - struct wg_format format; - - IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &mth); - IMFMediaTypeHandler_GetCurrentMediaType(mth, ¤t_mt); - - mf_media_type_to_wg_format(current_mt, &format); + if (FAILED(hr = wg_format_from_stream_descriptor(stream->descriptor, &format))) + WARN("Failed to get wg_format from stream descriptor, hr %#lx\n", hr); wg_parser_stream_enable(stream->wg_stream, &format, 0); - - IMFMediaType_Release(current_mt); - IMFMediaTypeHandler_Release(mth); } else { From 25a17fef0f7c94b253f4cd648e28557146410ee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 29 Apr 2023 11:59:32 +0200 Subject: [PATCH 1963/2777] winegstreamer: Start media streams in a dedicated media_stream_start helper. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 53 +++++++++++++++---------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 15c8721c83f..f88ce18f6d5 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -343,6 +343,25 @@ static void flush_token_queue(struct media_stream *stream, BOOL send) stream->token_queue_cap = 0; } +static HRESULT media_stream_start(struct media_stream *stream, BOOL active, BOOL seeking, const PROPVARIANT *position) +{ + struct media_source *source = impl_from_IMFMediaSource(stream->media_source); + struct wg_format format; + HRESULT hr; + + TRACE("source %p, stream %p\n", source, stream); + + if (FAILED(hr = wg_format_from_stream_descriptor(stream->descriptor, &format))) + WARN("Failed to get wg_format from stream descriptor, hr %#lx\n", hr); + wg_parser_stream_enable(stream->wg_stream, &format, 0); + + if (FAILED(hr = IMFMediaEventQueue_QueueEventParamUnk(source->event_queue, active ? MEUpdatedStream : MENewStream, + &GUID_NULL, S_OK, (IUnknown *)&stream->IMFMediaStream_iface))) + WARN("Failed to send source stream event, hr %#lx\n", hr); + return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, seeking ? MEStreamSeeked : MEStreamStarted, + &GUID_NULL, S_OK, position); +} + static void start_pipeline(struct media_source *source, struct source_async_command *command) { PROPVARIANT *position = &command->u.start.position; @@ -360,46 +379,24 @@ static void start_pipeline(struct media_source *source, struct source_async_comm for (i = 0; i < source->stream_count; i++) { struct media_stream *stream; + BOOL was_active, selected; IMFStreamDescriptor *sd; - struct wg_format format; DWORD stream_id; - BOOL was_active; - BOOL selected; stream = source->streams[i]; + was_active = stream->active; IMFStreamDescriptor_GetStreamIdentifier(stream->descriptor, &stream_id); - sd = stream_descriptor_from_id(command->u.start.descriptor, stream_id, &selected); IMFStreamDescriptor_Release(sd); - was_active = stream->active; - stream->active = selected; - - if (selected) - { - if (FAILED(hr = wg_format_from_stream_descriptor(stream->descriptor, &format))) - WARN("Failed to get wg_format from stream descriptor, hr %#lx\n", hr); - wg_parser_stream_enable(stream->wg_stream, &format, 0); - } - else - { - wg_parser_stream_disable(stream->wg_stream); - } - if (position->vt != VT_EMPTY) stream->eos = FALSE; - if (selected) - { - TRACE("Stream %u (%p) selected\n", i, stream); - IMFMediaEventQueue_QueueEventParamUnk(source->event_queue, - was_active ? MEUpdatedStream : MENewStream, &GUID_NULL, - S_OK, (IUnknown*) &stream->IMFMediaStream_iface); - - IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, - seek_message ? MEStreamSeeked : MEStreamStarted, &GUID_NULL, S_OK, position); - } + if (!(stream->active = selected)) + wg_parser_stream_disable(stream->wg_stream); + else if (FAILED(hr = media_stream_start(stream, was_active, seek_message, position))) + WARN("Failed to start media stream, hr %#lx\n", hr); } IMFMediaEventQueue_QueueEventParamVar(source->event_queue, From 2623db0c7792409d0bac2b7606af157312906c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 29 Apr 2023 11:04:36 +0200 Subject: [PATCH 1964/2777] winegstreamer: Simplify media source wait_on_sample control flow. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 113 ++++++++++++------------------ 1 file changed, 43 insertions(+), 70 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index f88ce18f6d5..a995ec6bdff 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -452,59 +452,19 @@ static void stop_pipeline(struct media_source *source) flush_token_queue(source->streams[i], FALSE); } -static void dispatch_end_of_presentation(struct media_source *source) -{ - PROPVARIANT empty = {.vt = VT_EMPTY}; - unsigned int i; - - /* A stream has ended, check whether all have */ - for (i = 0; i < source->stream_count; i++) - { - struct media_stream *stream = source->streams[i]; - if (stream->active && !stream->eos) - return; - } - - IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, &empty); -} - -static void send_buffer(struct media_stream *stream, const struct wg_parser_buffer *wg_buffer, IUnknown *token) +static HRESULT media_stream_send_sample(struct media_stream *stream, const struct wg_parser_buffer *wg_buffer, IUnknown *token) { + IMFSample *sample = NULL; IMFMediaBuffer *buffer; - IMFSample *sample; HRESULT hr; BYTE *data; - if (FAILED(hr = MFCreateSample(&sample))) - { - ERR("Failed to create sample, hr %#lx.\n", hr); - return; - } - if (FAILED(hr = MFCreateMemoryBuffer(wg_buffer->size, &buffer))) - { - ERR("Failed to create buffer, hr %#lx.\n", hr); - IMFSample_Release(sample); - return; - } - - if (FAILED(hr = IMFSample_AddBuffer(sample, buffer))) - { - ERR("Failed to add buffer, hr %#lx.\n", hr); - goto out; - } - + return hr; if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, wg_buffer->size))) - { - ERR("Failed to set size, hr %#lx.\n", hr); goto out; - } - if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL))) - { - ERR("Failed to lock buffer, hr %#lx.\n", hr); goto out; - } if (!wg_parser_stream_copy_buffer(stream->wg_stream, data, 0, wg_buffer->size)) { @@ -515,52 +475,62 @@ static void send_buffer(struct media_stream *stream, const struct wg_parser_buff wg_parser_stream_release_buffer(stream->wg_stream); if (FAILED(hr = IMFMediaBuffer_Unlock(buffer))) - { - ERR("Failed to unlock buffer, hr %#lx.\n", hr); goto out; - } + if (FAILED(hr = MFCreateSample(&sample))) + goto out; + if (FAILED(hr = IMFSample_AddBuffer(sample, buffer))) + goto out; if (FAILED(hr = IMFSample_SetSampleTime(sample, wg_buffer->pts))) - { - ERR("Failed to set sample time, hr %#lx.\n", hr); goto out; - } - if (FAILED(hr = IMFSample_SetSampleDuration(sample, wg_buffer->duration))) - { - ERR("Failed to set sample duration, hr %#lx.\n", hr); goto out; - } - - if (token) - IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token); + if (token && FAILED(hr = IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token))) + goto out; - IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample, + hr = IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample, &GUID_NULL, S_OK, (IUnknown *)sample); out: + if (sample) + IMFSample_Release(sample); IMFMediaBuffer_Release(buffer); - IMFSample_Release(sample); + return hr; +} + +static HRESULT media_stream_send_eos(struct media_source *source, struct media_stream *stream) +{ + PROPVARIANT empty = {.vt = VT_EMPTY}; + HRESULT hr; + UINT i; + + stream->eos = TRUE; + if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty))) + WARN("Failed to queue MEEndOfStream event, hr %#lx\n", hr); + + for (i = 0; i < source->stream_count; i++) + { + struct media_stream *stream = source->streams[i]; + if (stream->active && !stream->eos) + return S_OK; + } + + if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, &empty))) + WARN("Failed to queue MEEndOfPresentation event, hr %#lx\n", hr); + return S_OK; } -static void wait_on_sample(struct media_stream *stream, IUnknown *token) +static HRESULT wait_on_sample(struct media_stream *stream, IUnknown *token) { struct media_source *source = impl_from_IMFMediaSource(stream->media_source); - PROPVARIANT empty_var = {.vt = VT_EMPTY}; struct wg_parser_buffer buffer; TRACE("%p, %p\n", stream, token); if (wg_parser_stream_get_buffer(source->wg_parser, stream->wg_stream, &buffer)) - { - send_buffer(stream, &buffer, token); - } - else - { - stream->eos = TRUE; - IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty_var); - dispatch_end_of_presentation(source); - } + return media_stream_send_sample(stream, &buffer, token); + + return media_stream_send_eos(source, stream); } static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) @@ -594,7 +564,10 @@ static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFA if (source->state == SOURCE_PAUSED) enqueue_token(command->u.request_sample.stream, command->u.request_sample.token); else if (source->state == SOURCE_RUNNING) - wait_on_sample(command->u.request_sample.stream, command->u.request_sample.token); + { + if (FAILED(hr = wait_on_sample(command->u.request_sample.stream, command->u.request_sample.token))) + WARN("Failed to request sample, hr %#lx\n", hr); + } break; } From 92930bd970b688906299b97b7967f19c49102b21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 29 Apr 2023 12:00:49 +0200 Subject: [PATCH 1965/2777] winegstreamer: Avoid eating errors in media source async commands. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 60 +++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index a995ec6bdff..6c94c9d196c 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -362,13 +362,19 @@ static HRESULT media_stream_start(struct media_stream *stream, BOOL active, BOOL &GUID_NULL, S_OK, position); } -static void start_pipeline(struct media_source *source, struct source_async_command *command) +static HRESULT media_source_start(struct media_source *source, IMFPresentationDescriptor *descriptor, + GUID *format, PROPVARIANT *position) { - PROPVARIANT *position = &command->u.start.position; BOOL seek_message = source->state != SOURCE_STOPPED && position->vt != VT_EMPTY; unsigned int i; HRESULT hr; + TRACE("source %p, descriptor %p, format %s, position %s\n", source, descriptor, + debugstr_guid(format), wine_dbgstr_variant((VARIANT *)position)); + + if (source->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + /* seek to beginning on stop->play */ if (source->state == SOURCE_STOPPED && position->vt == VT_EMPTY) { @@ -387,7 +393,7 @@ static void start_pipeline(struct media_source *source, struct source_async_comm was_active = stream->active; IMFStreamDescriptor_GetStreamIdentifier(stream->descriptor, &stream_id); - sd = stream_descriptor_from_id(command->u.start.descriptor, stream_id, &selected); + sd = stream_descriptor_from_id(descriptor, stream_id, &selected); IMFStreamDescriptor_Release(sd); if (position->vt != VT_EMPTY) @@ -399,10 +405,6 @@ static void start_pipeline(struct media_source *source, struct source_async_comm WARN("Failed to start media stream, hr %#lx\n", hr); } - IMFMediaEventQueue_QueueEventParamVar(source->event_queue, - seek_message ? MESourceSeeked : MESourceStarted, - &GUID_NULL, S_OK, position); - source->state = SOURCE_RUNNING; if (position->vt == VT_I8) @@ -411,13 +413,21 @@ static void start_pipeline(struct media_source *source, struct source_async_comm for (i = 0; i < source->stream_count; i++) flush_token_queue(source->streams[i], position->vt == VT_EMPTY); + + return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, + seek_message ? MESourceSeeked : MESourceStarted, &GUID_NULL, S_OK, position); } -static void pause_pipeline(struct media_source *source) +static HRESULT media_source_pause(struct media_source *source) { unsigned int i; HRESULT hr; + TRACE("source %p\n", source); + + if (source->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + for (i = 0; i < source->stream_count; i++) { struct media_stream *stream = source->streams[i]; @@ -426,16 +436,20 @@ static void pause_pipeline(struct media_source *source) WARN("Failed to queue MEStreamPaused event, hr %#lx\n", hr); } - IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourcePaused, &GUID_NULL, S_OK, NULL); - source->state = SOURCE_PAUSED; + return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourcePaused, &GUID_NULL, S_OK, NULL); } -static void stop_pipeline(struct media_source *source) +static HRESULT media_source_stop(struct media_source *source) { unsigned int i; HRESULT hr; + TRACE("source %p\n", source); + + if (source->state == SOURCE_SHUTDOWN) + return MF_E_SHUTDOWN; + for (i = 0; i < source->stream_count; i++) { struct media_stream *stream = source->streams[i]; @@ -444,12 +458,12 @@ static void stop_pipeline(struct media_source *source) WARN("Failed to queue MEStreamStopped event, hr %#lx\n", hr); } - IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceStopped, &GUID_NULL, S_OK, NULL); - source->state = SOURCE_STOPPED; for (i = 0; i < source->stream_count; i++) flush_token_queue(source->streams[i], FALSE); + + return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceStopped, &GUID_NULL, S_OK, NULL); } static HRESULT media_stream_send_sample(struct media_stream *stream, const struct wg_parser_buffer *wg_buffer, IUnknown *token) @@ -504,6 +518,8 @@ static HRESULT media_stream_send_eos(struct media_source *source, struct media_s HRESULT hr; UINT i; + TRACE("source %p, stream %p\n", source, stream); + stream->eos = TRUE; if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty))) WARN("Failed to queue MEEndOfStream event, hr %#lx\n", hr); @@ -549,16 +565,22 @@ static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFA switch (command->op) { case SOURCE_ASYNC_START: - if (source->state != SOURCE_SHUTDOWN) - start_pipeline(source, command); + { + IMFPresentationDescriptor *descriptor = command->u.start.descriptor; + GUID format = command->u.start.format; + PROPVARIANT position = command->u.start.position; + + if (FAILED(hr = media_source_start(source, descriptor, &format, &position))) + WARN("Failed to start source %p, hr %#lx\n", source, hr); break; + } case SOURCE_ASYNC_PAUSE: - if (source->state != SOURCE_SHUTDOWN) - pause_pipeline(source); + if (FAILED(hr = media_source_pause(source))) + WARN("Failed to pause source %p, hr %#lx\n", source, hr); break; case SOURCE_ASYNC_STOP: - if (source->state != SOURCE_SHUTDOWN) - stop_pipeline(source); + if (FAILED(hr = media_source_stop(source))) + WARN("Failed to stop source %p, hr %#lx\n", source, hr); break; case SOURCE_ASYNC_REQUEST_SAMPLE: if (source->state == SOURCE_PAUSED) From ff45cc75d6629953cdc51e28ec7613555a1a94ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Apr 2023 18:41:17 +0200 Subject: [PATCH 1966/2777] winegstreamer: Keep a stream descriptor array on the media source. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 48 ++++++++++++++----------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 6c94c9d196c..db92219182a 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -92,8 +92,10 @@ struct media_source struct wg_parser *wg_parser; + IMFStreamDescriptor **descriptors; struct media_stream **streams; ULONG stream_count; + IMFPresentationDescriptor *pres_desc; enum { @@ -1421,9 +1423,11 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) while (source->stream_count--) { struct media_stream *stream = source->streams[source->stream_count]; + IMFStreamDescriptor_Release(source->descriptors[source->stream_count]); IMFMediaEventQueue_Shutdown(stream->event_queue); IMFMediaStream_Release(&stream->IMFMediaStream_iface); } + free(source->descriptors); free(source->streams); MFUnlockWorkQueue(source->async_commands_queue); @@ -1452,7 +1456,6 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *data, UINT64 size, IMFMediaSource **out) { - IMFStreamDescriptor **descriptors = NULL; unsigned int stream_count = UINT_MAX; struct media_source *object; UINT64 total_pres_time = 0; @@ -1514,32 +1517,37 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d stream_count = wg_parser_get_stream_count(parser); - if (!(object->streams = calloc(stream_count, sizeof(*object->streams)))) + if (!(object->descriptors = calloc(stream_count, sizeof(*object->descriptors))) + || !(object->streams = calloc(stream_count, sizeof(*object->streams)))) { + free(object->descriptors); hr = E_OUTOFMEMORY; goto fail; } for (i = 0; i < stream_count; ++i) { - if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, i, &object->streams[i]))) - goto fail; + struct media_stream *stream; - if (FAILED(hr = media_stream_init_desc(object->streams[i]))) + if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, i, &stream))) + goto fail; + if (FAILED(hr = media_stream_init_desc(stream))) { - ERR("Failed to finish initialization of media stream %p, hr %#lx.\n", object->streams[i], hr); - IMFMediaSource_Release(object->streams[i]->media_source); - IMFMediaEventQueue_Release(object->streams[i]->event_queue); - free(object->streams[i]); + ERR("Failed to finish initialization of media stream %p, hr %#lx.\n", stream, hr); + IMFMediaSource_Release(stream->media_source); + IMFMediaEventQueue_Release(stream->event_queue); + free(stream); goto fail; } + IMFStreamDescriptor_AddRef(stream->descriptor); + object->descriptors[i] = stream->descriptor; + object->streams[i] = stream; object->stream_count++; } /* init presentation descriptor */ - descriptors = malloc(object->stream_count * sizeof(IMFStreamDescriptor *)); for (i = 0; i < object->stream_count; i++) { static const struct @@ -1557,8 +1565,6 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d DWORD len; char *str; - IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[i]); - for (j = 0; j < ARRAY_SIZE(tags); ++j) { if (!(str = wg_parser_stream_get_tag(object->streams[i]->wg_stream, tags[j].tag))) @@ -1570,22 +1576,17 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d } strW = malloc(len * sizeof(*strW)); if (MultiByteToWideChar(CP_UTF8, 0, str, -1, strW, len)) - IMFStreamDescriptor_SetString(descriptors[i], tags[j].mf_attr, strW); + IMFStreamDescriptor_SetString(object->descriptors[i], tags[j].mf_attr, strW); free(strW); free(str); } } - if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc))) + if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, object->descriptors, &object->pres_desc))) goto fail; for (i = 0; i < object->stream_count; i++) - { IMFPresentationDescriptor_SelectStream(object->pres_desc, i); - IMFStreamDescriptor_Release(descriptors[i]); - } - free(descriptors); - descriptors = NULL; for (i = 0; i < object->stream_count; i++) total_pres_time = max(total_pres_time, @@ -1602,18 +1603,13 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d fail: WARN("Failed to construct MFMediaSource, hr %#lx.\n", hr); - if (descriptors) - { - for (i = 0; i < object->stream_count; i++) - IMFStreamDescriptor_Release(descriptors[i]); - free(descriptors); - } - while (object->streams && object->stream_count--) { struct media_stream *stream = object->streams[object->stream_count]; + IMFStreamDescriptor_Release(object->descriptors[object->stream_count]); IMFMediaStream_Release(&stream->IMFMediaStream_iface); } + free(object->descriptors); free(object->streams); if (stream_count != UINT_MAX) From d79f3df4dc57e59874e1c914301792434d94599a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 29 Apr 2023 12:08:21 +0200 Subject: [PATCH 1967/2777] winegstreamer: Create media source presentation descriptor as needed. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 42 +++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index db92219182a..f25af8962fd 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -91,12 +91,12 @@ struct media_source CRITICAL_SECTION cs; struct wg_parser *wg_parser; + UINT64 duration; IMFStreamDescriptor **descriptors; struct media_stream **streams; ULONG stream_count; - IMFPresentationDescriptor *pres_desc; enum { SOURCE_OPENING, @@ -367,7 +367,7 @@ static HRESULT media_stream_start(struct media_stream *stream, BOOL active, BOOL static HRESULT media_source_start(struct media_source *source, IMFPresentationDescriptor *descriptor, GUID *format, PROPVARIANT *position) { - BOOL seek_message = source->state != SOURCE_STOPPED && position->vt != VT_EMPTY; + BOOL starting = source->state == SOURCE_STOPPED, seek_message = !starting && position->vt != VT_EMPTY; unsigned int i; HRESULT hr; @@ -392,7 +392,7 @@ static HRESULT media_source_start(struct media_source *source, IMFPresentationDe DWORD stream_id; stream = source->streams[i]; - was_active = stream->active; + was_active = !starting && stream->active; IMFStreamDescriptor_GetStreamIdentifier(stream->descriptor, &stream_id); sd = stream_descriptor_from_id(descriptor, stream_id, &selected); @@ -879,7 +879,7 @@ static HRESULT media_stream_create(IMFMediaSource *source, DWORD id, object->media_source = source; object->stream_id = id; - object->active = FALSE; + object->active = TRUE; object->eos = FALSE; object->wg_stream = wg_parser_get_stream(wg_parser, id); @@ -1229,7 +1229,6 @@ static ULONG WINAPI media_source_Release(IMFMediaSource *iface) if (!ref) { IMFMediaSource_Shutdown(iface); - IMFPresentationDescriptor_Release(source->pres_desc); IMFMediaEventQueue_Release(source->event_queue); IMFByteStream_Release(source->byte_stream); wg_parser_destroy(source->wg_parser); @@ -1301,6 +1300,7 @@ static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource * { struct media_source *source = impl_from_IMFMediaSource(iface); HRESULT hr; + UINT i; TRACE("%p, %p.\n", iface, descriptor); @@ -1308,8 +1308,21 @@ static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource * if (source->state == SOURCE_SHUTDOWN) hr = MF_E_SHUTDOWN; - else - hr = IMFPresentationDescriptor_Clone(source->pres_desc, descriptor); + else if (SUCCEEDED(hr = MFCreatePresentationDescriptor(source->stream_count, source->descriptors, descriptor))) + { + if (FAILED(hr = IMFPresentationDescriptor_SetUINT64(*descriptor, &MF_PD_DURATION, source->duration))) + WARN("Failed to set presentation descriptor MF_PD_DURATION, hr %#lx\n", hr); + + for (i = 0; i < source->stream_count; ++i) + { + if (!source->streams[i]->active) + continue; + if (FAILED(hr = IMFPresentationDescriptor_SelectStream(*descriptor, i))) + WARN("Failed to select stream %u, hr %#lx\n", i, hr); + } + + hr = S_OK; + } LeaveCriticalSection(&source->cs); @@ -1458,7 +1471,6 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d { unsigned int stream_count = UINT_MAX; struct media_source *object; - UINT64 total_pres_time = 0; struct wg_parser *parser; DWORD bytestream_caps; uint64_t file_size; @@ -1540,6 +1552,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d goto fail; } + object->duration = max(object->duration, wg_parser_stream_get_duration(stream->wg_stream)); IMFStreamDescriptor_AddRef(stream->descriptor); object->descriptors[i] = stream->descriptor; object->streams[i] = stream; @@ -1582,19 +1595,6 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d } } - if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, object->descriptors, &object->pres_desc))) - goto fail; - - for (i = 0; i < object->stream_count; i++) - IMFPresentationDescriptor_SelectStream(object->pres_desc, i); - - for (i = 0; i < object->stream_count; i++) - total_pres_time = max(total_pres_time, - wg_parser_stream_get_duration(object->streams[i]->wg_stream)); - - if (object->stream_count) - IMFPresentationDescriptor_SetUINT64(object->pres_desc, &MF_PD_DURATION, total_pres_time); - object->state = SOURCE_STOPPED; *out = &object->IMFMediaSource_iface; From 01b1a9b445731f4131bf0d60bf8ab71c0bd290cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 29 Apr 2023 14:01:57 +0200 Subject: [PATCH 1968/2777] winegstreamer: Iterate presentation descriptor before starting streams. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 92 +++++++++++++++---------------- 1 file changed, 43 insertions(+), 49 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index f25af8962fd..6c18b44fd3e 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -269,30 +269,6 @@ static HRESULT wg_format_from_stream_descriptor(IMFStreamDescriptor *descriptor, return hr; } -static IMFStreamDescriptor *stream_descriptor_from_id(IMFPresentationDescriptor *pres_desc, DWORD id, BOOL *selected) -{ - ULONG sd_count; - IMFStreamDescriptor *ret; - unsigned int i; - - if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(pres_desc, &sd_count))) - return NULL; - - for (i = 0; i < sd_count; i++) - { - DWORD stream_id; - - if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pres_desc, i, selected, &ret))) - return NULL; - - if (SUCCEEDED(IMFStreamDescriptor_GetStreamIdentifier(ret, &stream_id)) && stream_id == id) - return ret; - - IMFStreamDescriptor_Release(ret); - } - return NULL; -} - static BOOL enqueue_token(struct media_stream *stream, IUnknown *token) { if (stream->token_queue_count == stream->token_queue_cap) @@ -368,7 +344,8 @@ static HRESULT media_source_start(struct media_source *source, IMFPresentationDe GUID *format, PROPVARIANT *position) { BOOL starting = source->state == SOURCE_STOPPED, seek_message = !starting && position->vt != VT_EMPTY; - unsigned int i; + IMFStreamDescriptor **descriptors; + DWORD i, count; HRESULT hr; TRACE("source %p, descriptor %p, format %s, position %s\n", source, descriptor, @@ -384,29 +361,47 @@ static HRESULT media_source_start(struct media_source *source, IMFPresentationDe position->hVal.QuadPart = 0; } - for (i = 0; i < source->stream_count; i++) - { - struct media_stream *stream; - BOOL was_active, selected; - IMFStreamDescriptor *sd; - DWORD stream_id; + if (!(descriptors = calloc(source->stream_count, sizeof(*descriptors)))) + return E_OUTOFMEMORY; - stream = source->streams[i]; - was_active = !starting && stream->active; + if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor, &count))) + WARN("Failed to get presentation descriptor stream count, hr %#lx\n", hr); - IMFStreamDescriptor_GetStreamIdentifier(stream->descriptor, &stream_id); - sd = stream_descriptor_from_id(descriptor, stream_id, &selected); - IMFStreamDescriptor_Release(sd); + for (i = 0; i < count; i++) + { + IMFStreamDescriptor *stream_descriptor; + BOOL selected; + DWORD id; + + if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor, i, &selected, &stream_descriptor))) + WARN("Failed to get presentation stream descriptor, hr %#lx\n", hr); + else if (!selected || FAILED(hr = IMFStreamDescriptor_GetStreamIdentifier(stream_descriptor, &id))) + IMFStreamDescriptor_Release(stream_descriptor); + else + descriptors[id] = stream_descriptor; + } + + source->state = SOURCE_RUNNING; + for (i = 0; i < source->stream_count; i++) + { + struct media_stream *stream = source->streams[i]; + BOOL was_active = !starting && stream->active; if (position->vt != VT_EMPTY) stream->eos = FALSE; - if (!(stream->active = selected)) + if (!(stream->active = !!descriptors[i])) wg_parser_stream_disable(stream->wg_stream); - else if (FAILED(hr = media_stream_start(stream, was_active, seek_message, position))) - WARN("Failed to start media stream, hr %#lx\n", hr); + else + { + if (FAILED(hr = media_stream_start(stream, was_active, seek_message, position))) + WARN("Failed to start media stream, hr %#lx\n", hr); + IMFStreamDescriptor_Release(descriptors[i]); + } } + free(descriptors); + source->state = SOURCE_RUNNING; if (position->vt == VT_I8) @@ -854,14 +849,13 @@ static const IMFMediaStreamVtbl media_stream_vtbl = media_stream_RequestSample }; -static HRESULT media_stream_create(IMFMediaSource *source, DWORD id, +static HRESULT media_stream_create(IMFMediaSource *source, struct wg_parser_stream *wg_stream, struct media_stream **out) { - struct wg_parser *wg_parser = impl_from_IMFMediaSource(source)->wg_parser; struct media_stream *object; HRESULT hr; - TRACE("source %p, id %lu.\n", source, id); + TRACE("source %p, wg_stream %p.\n", source, wg_stream); if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; @@ -877,11 +871,10 @@ static HRESULT media_stream_create(IMFMediaSource *source, DWORD id, IMFMediaSource_AddRef(source); object->media_source = source; - object->stream_id = id; object->active = TRUE; object->eos = FALSE; - object->wg_stream = wg_parser_get_stream(wg_parser, id); + object->wg_stream = wg_stream; TRACE("Created stream object %p.\n", object); @@ -889,7 +882,7 @@ static HRESULT media_stream_create(IMFMediaSource *source, DWORD id, return S_OK; } -static HRESULT media_stream_init_desc(struct media_stream *stream) +static HRESULT media_stream_init_desc(struct media_stream *stream, UINT id) { IMFMediaTypeHandler *type_handler = NULL; IMFMediaType *stream_types[6]; @@ -982,7 +975,7 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) return E_FAIL; } - if (FAILED(hr = MFCreateStreamDescriptor(stream->stream_id, type_count, stream_types, &stream->descriptor))) + if (FAILED(hr = MFCreateStreamDescriptor(id, type_count, stream_types, &stream->descriptor))) goto done; if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &type_handler))) @@ -1539,11 +1532,12 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d for (i = 0; i < stream_count; ++i) { + struct wg_parser_stream *wg_stream = wg_parser_get_stream(parser, i); struct media_stream *stream; - if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, i, &stream))) + if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, wg_stream, &stream))) goto fail; - if (FAILED(hr = media_stream_init_desc(stream))) + if (FAILED(hr = media_stream_init_desc(stream, i))) { ERR("Failed to finish initialization of media stream %p, hr %#lx.\n", stream, hr); IMFMediaSource_Release(stream->media_source); @@ -1552,7 +1546,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d goto fail; } - object->duration = max(object->duration, wg_parser_stream_get_duration(stream->wg_stream)); + object->duration = max(object->duration, wg_parser_stream_get_duration(wg_stream)); IMFStreamDescriptor_AddRef(stream->descriptor); object->descriptors[i] = stream->descriptor; object->streams[i] = stream; From b1dfc48d0b0dc7a4e2a938f4c8e488216291557b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 May 2023 10:54:55 +0200 Subject: [PATCH 1969/2777] winegstreamer: Introduce new stream_descriptor_set_tag helper. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 82 +++++++++++++++++-------------- 1 file changed, 46 insertions(+), 36 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 6c18b44fd3e..3501325dcc5 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -269,6 +269,32 @@ static HRESULT wg_format_from_stream_descriptor(IMFStreamDescriptor *descriptor, return hr; } +static HRESULT stream_descriptor_set_tag(IMFStreamDescriptor *descriptor, struct wg_parser_stream *stream, + const GUID *attr, enum wg_parser_tag tag) +{ + WCHAR *strW; + HRESULT hr; + DWORD len; + char *str; + + if (!(str = wg_parser_stream_get_tag(stream, tag)) + || !(len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0))) + hr = S_OK; + else if (!(strW = malloc(len * sizeof(*strW)))) + hr = E_OUTOFMEMORY; + else + { + if (MultiByteToWideChar(CP_UTF8, 0, str, -1, strW, len)) + hr = IMFStreamDescriptor_SetString(descriptor, attr, strW); + else + hr = E_FAIL; + free(strW); + } + + free(str); + return hr; +} + static BOOL enqueue_token(struct media_stream *stream, IUnknown *token) { if (stream->token_queue_count == stream->token_queue_cap) @@ -1460,6 +1486,25 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = media_source_Shutdown, }; +static void media_source_init_descriptors(struct media_source *source) +{ + HRESULT hr = S_OK; + UINT i; + + for (i = 0; i < source->stream_count; i++) + { + struct media_stream *stream = source->streams[i]; + IMFStreamDescriptor *descriptor = stream->descriptor; + + if (FAILED(hr = stream_descriptor_set_tag(descriptor, stream->wg_stream, + &MF_SD_LANGUAGE, WG_PARSER_TAG_LANGUAGE))) + WARN("Failed to set stream descriptor language, hr %#lx\n", hr); + if (FAILED(hr = stream_descriptor_set_tag(descriptor, stream->wg_stream, + &MF_SD_STREAM_NAME, WG_PARSER_TAG_NAME))) + WARN("Failed to set stream descriptor name, hr %#lx\n", hr); + } +} + HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *data, UINT64 size, IMFMediaSource **out) { unsigned int stream_count = UINT_MAX; @@ -1553,42 +1598,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d object->stream_count++; } - /* init presentation descriptor */ - - for (i = 0; i < object->stream_count; i++) - { - static const struct - { - enum wg_parser_tag tag; - const GUID *mf_attr; - } - tags[] = - { - {WG_PARSER_TAG_LANGUAGE, &MF_SD_LANGUAGE}, - {WG_PARSER_TAG_NAME, &MF_SD_STREAM_NAME}, - }; - unsigned int j; - WCHAR *strW; - DWORD len; - char *str; - - for (j = 0; j < ARRAY_SIZE(tags); ++j) - { - if (!(str = wg_parser_stream_get_tag(object->streams[i]->wg_stream, tags[j].tag))) - continue; - if (!(len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0))) - { - free(str); - continue; - } - strW = malloc(len * sizeof(*strW)); - if (MultiByteToWideChar(CP_UTF8, 0, str, -1, strW, len)) - IMFStreamDescriptor_SetString(object->descriptors[i], tags[j].mf_attr, strW); - free(strW); - free(str); - } - } - + media_source_init_descriptors(object); object->state = SOURCE_STOPPED; *out = &object->IMFMediaSource_iface; From 9337cb91d95f9a3f176b39b48495d33051c20e4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 16 Apr 2023 11:29:30 +0200 Subject: [PATCH 1970/2777] winegstreamer: Expose a single audio media type from the media source. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 3501325dcc5..3cbbc109480 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -963,30 +963,6 @@ static HRESULT media_stream_init_desc(struct media_stream *stream, UINT id) goto done; } } - else if (format.major_type == WG_MAJOR_TYPE_AUDIO) - { - /* Expose at least one PCM and one floating point type for the - consumer to pick from. */ - static const enum wg_audio_format audio_types[] = - { - WG_AUDIO_FORMAT_S16LE, - WG_AUDIO_FORMAT_F32LE, - }; - - if ((stream_types[0] = mf_media_type_from_wg_format(&format))) - type_count = 1; - - for (i = 0; i < ARRAY_SIZE(audio_types); i++) - { - struct wg_format new_format; - if (format.u.audio.format == audio_types[i]) - continue; - new_format = format; - new_format.u.audio.format = audio_types[i]; - if ((stream_types[type_count] = mf_media_type_from_wg_format(&new_format))) - type_count++; - } - } else { if ((stream_types[0] = mf_media_type_from_wg_format(&format))) From 7e2bd01a68919829f39941489ad7b73fa71e9266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Apr 2023 13:44:45 +0200 Subject: [PATCH 1971/2777] winegstreamer: Expose a single video media type from the media source. CW-Bug-Id: #21953 --- dlls/mfmediaengine/tests/mfmediaengine.c | 2 +- dlls/winegstreamer/media_source.c | 52 +++--------------------- 2 files changed, 6 insertions(+), 48 deletions(-) diff --git a/dlls/mfmediaengine/tests/mfmediaengine.c b/dlls/mfmediaengine/tests/mfmediaengine.c index 3a5b2bf8253..1a23de5ec86 100644 --- a/dlls/mfmediaengine/tests/mfmediaengine.c +++ b/dlls/mfmediaengine/tests/mfmediaengine.c @@ -146,7 +146,7 @@ static void check_rgb32_data_(int line, const WCHAR *filename, const BYTE *data, expect_data = LockResource(LoadResource(GetModuleHandleW(NULL), resource)); diff = compare_rgb32(data, &length, rect, expect_data); - ok_(__FILE__, line)(diff == 0, "Unexpected %lu%% diff\n", diff); + ok_(__FILE__, line)(diff <= 3 /* small difference in wine */, "Unexpected %lu%% diff\n", diff); } static void init_functions(void) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 3cbbc109480..ccc122343f8 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -919,56 +919,14 @@ static HRESULT media_stream_init_desc(struct media_stream *stream, UINT id) wg_parser_stream_get_preferred_format(stream->wg_stream, &format); - if (format.major_type == WG_MAJOR_TYPE_VIDEO) - { - /* These are the most common native output types of decoders: - https://docs.microsoft.com/en-us/windows/win32/medfound/mft-decoder-expose-output-types-in-native-order */ - static const GUID *const video_types[] = - { - &MFVideoFormat_NV12, - &MFVideoFormat_YV12, - &MFVideoFormat_YUY2, - &MFVideoFormat_IYUV, - &MFVideoFormat_I420, - }; - - IMFMediaType *base_type = mf_media_type_from_wg_format(&format); - GUID base_subtype; + /* native exposes NV12 video format before I420 */ + if (format.major_type == WG_MAJOR_TYPE_VIDEO + && format.u.video.format == WG_VIDEO_FORMAT_I420) + format.u.video.format = WG_VIDEO_FORMAT_NV12; - if (!base_type) - { - hr = MF_E_INVALIDMEDIATYPE; - goto done; - } - - IMFMediaType_GetGUID(base_type, &MF_MT_SUBTYPE, &base_subtype); - - stream_types[0] = base_type; + if ((stream_types[0] = mf_media_type_from_wg_format(&format))) type_count = 1; - for (i = 0; i < ARRAY_SIZE(video_types); i++) - { - IMFMediaType *new_type; - - if (IsEqualGUID(&base_subtype, video_types[i])) - continue; - - if (FAILED(hr = MFCreateMediaType(&new_type))) - goto done; - stream_types[type_count++] = new_type; - - if (FAILED(hr = IMFMediaType_CopyAllItems(base_type, (IMFAttributes *) new_type))) - goto done; - if (FAILED(hr = IMFMediaType_SetGUID(new_type, &MF_MT_SUBTYPE, video_types[i]))) - goto done; - } - } - else - { - if ((stream_types[0] = mf_media_type_from_wg_format(&format))) - type_count = 1; - } - assert(type_count <= ARRAY_SIZE(stream_types)); if (!type_count) From 8e9fec431e2dd63bbda51c1f24441555bf6c94e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Apr 2023 18:11:18 +0200 Subject: [PATCH 1972/2777] winegstreamer: Introduce new stream_descriptor_create helper. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 101 +++++++++++++----------------- 1 file changed, 42 insertions(+), 59 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index ccc122343f8..eaef1ae791c 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -269,6 +269,37 @@ static HRESULT wg_format_from_stream_descriptor(IMFStreamDescriptor *descriptor, return hr; } +static HRESULT stream_descriptor_create(UINT32 id, struct wg_format *format, IMFStreamDescriptor **out) +{ + IMFStreamDescriptor *descriptor; + IMFMediaTypeHandler *handler; + IMFMediaType *type; + HRESULT hr; + + /* native exposes NV12 video format before I420 */ + if (format->major_type == WG_MAJOR_TYPE_VIDEO + && format->u.video.format == WG_VIDEO_FORMAT_I420) + format->u.video.format = WG_VIDEO_FORMAT_NV12; + + if (!(type = mf_media_type_from_wg_format(format))) + return MF_E_INVALIDMEDIATYPE; + if (FAILED(hr = MFCreateStreamDescriptor(id, 1, &type, &descriptor))) + goto done; + + if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(descriptor, &handler))) + IMFStreamDescriptor_Release(descriptor); + else + { + hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, type); + IMFMediaTypeHandler_Release(handler); + } + +done: + IMFMediaType_Release(type); + *out = SUCCEEDED(hr) ? descriptor : NULL; + return hr; +} + static HRESULT stream_descriptor_set_tag(IMFStreamDescriptor *descriptor, struct wg_parser_stream *stream, const GUID *attr, enum wg_parser_tag tag) { @@ -876,7 +907,7 @@ static const IMFMediaStreamVtbl media_stream_vtbl = }; static HRESULT media_stream_create(IMFMediaSource *source, struct wg_parser_stream *wg_stream, - struct media_stream **out) + IMFStreamDescriptor *descriptor, struct media_stream **out) { struct media_stream *object; HRESULT hr; @@ -897,6 +928,8 @@ static HRESULT media_stream_create(IMFMediaSource *source, struct wg_parser_stre IMFMediaSource_AddRef(source); object->media_source = source; + IMFStreamDescriptor_AddRef(descriptor); + object->descriptor = descriptor; object->active = TRUE; object->eos = FALSE; @@ -908,56 +941,6 @@ static HRESULT media_stream_create(IMFMediaSource *source, struct wg_parser_stre return S_OK; } -static HRESULT media_stream_init_desc(struct media_stream *stream, UINT id) -{ - IMFMediaTypeHandler *type_handler = NULL; - IMFMediaType *stream_types[6]; - struct wg_format format; - DWORD type_count = 0; - HRESULT hr = S_OK; - unsigned int i; - - wg_parser_stream_get_preferred_format(stream->wg_stream, &format); - - /* native exposes NV12 video format before I420 */ - if (format.major_type == WG_MAJOR_TYPE_VIDEO - && format.u.video.format == WG_VIDEO_FORMAT_I420) - format.u.video.format = WG_VIDEO_FORMAT_NV12; - - if ((stream_types[0] = mf_media_type_from_wg_format(&format))) - type_count = 1; - - assert(type_count <= ARRAY_SIZE(stream_types)); - - if (!type_count) - { - ERR("Failed to establish an IMFMediaType from any of the possible stream caps!\n"); - return E_FAIL; - } - - if (FAILED(hr = MFCreateStreamDescriptor(id, type_count, stream_types, &stream->descriptor))) - goto done; - - if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &type_handler))) - { - IMFStreamDescriptor_Release(stream->descriptor); - goto done; - } - - if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, stream_types[0]))) - { - IMFStreamDescriptor_Release(stream->descriptor); - goto done; - } - -done: - if (type_handler) - IMFMediaTypeHandler_Release(type_handler); - for (i = 0; i < type_count; i++) - IMFMediaType_Release(stream_types[i]); - return hr; -} - static HRESULT WINAPI media_source_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj) { struct media_source *source = impl_from_IMFGetService(iface); @@ -1512,22 +1495,22 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d for (i = 0; i < stream_count; ++i) { struct wg_parser_stream *wg_stream = wg_parser_get_stream(parser, i); + IMFStreamDescriptor *descriptor; struct media_stream *stream; + struct wg_format format; - if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, wg_stream, &stream))) + wg_parser_stream_get_preferred_format(wg_stream, &format); + if (FAILED(hr = stream_descriptor_create(i, &format, &descriptor))) goto fail; - if (FAILED(hr = media_stream_init_desc(stream, i))) + if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, wg_stream, descriptor, &stream))) { - ERR("Failed to finish initialization of media stream %p, hr %#lx.\n", stream, hr); - IMFMediaSource_Release(stream->media_source); - IMFMediaEventQueue_Release(stream->event_queue); - free(stream); + IMFStreamDescriptor_Release(descriptor); goto fail; } object->duration = max(object->duration, wg_parser_stream_get_duration(wg_stream)); - IMFStreamDescriptor_AddRef(stream->descriptor); - object->descriptors[i] = stream->descriptor; + IMFStreamDescriptor_AddRef(descriptor); + object->descriptors[i] = descriptor; object->streams[i] = stream; object->stream_count++; } From 6444e4ef57cefe55afd635bee4647da1a0a04eee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 26 Apr 2023 16:23:26 +0200 Subject: [PATCH 1973/2777] winegstreamer: Introduce a new wg_source interface. CW-Bug-Id: #21953 --- MAINTAINERS | 1 + dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 3 + dlls/winegstreamer/main.c | 28 +++++++++ dlls/winegstreamer/media_source.c | 15 ++++- dlls/winegstreamer/unix_private.h | 6 ++ dlls/winegstreamer/unixlib.c | 30 ++++++++++ dlls/winegstreamer/unixlib.h | 11 ++++ dlls/winegstreamer/wg_parser.c | 3 + dlls/winegstreamer/wg_source.c | 99 +++++++++++++++++++++++++++++++ 10 files changed, 195 insertions(+), 2 deletions(-) create mode 100644 dlls/winegstreamer/wg_source.c diff --git a/MAINTAINERS b/MAINTAINERS index 3c4e7a308ba..22a5114e70d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -218,6 +218,7 @@ F: dlls/winegstreamer/h264_decoder.c F: dlls/winegstreamer/resampler.c F: dlls/winegstreamer/video_decoder.c F: dlls/winegstreamer/video_processor.c +F: dlls/winegstreamer/wg_source.c F: dlls/winegstreamer/wg_sample.c F: dlls/winegstreamer/wg_transform.c F: dlls/winegstreamer/wma_decoder.c diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 56afcea3189..acf4840e1d6 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -25,6 +25,7 @@ C_SRCS = \ wg_format.c \ wg_parser.c \ wg_sample.c \ + wg_source.c \ wg_transform.c \ wm_reader.c \ wma_decoder.c \ diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index bb5db1c5f51..1b91ef863a7 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -107,6 +107,9 @@ bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_fo bool wg_transform_get_status(struct wg_transform *transform, bool *accepts_input); HRESULT wg_transform_drain(struct wg_transform *transform, BOOL flush); +struct wg_source *wg_source_create(const WCHAR *url, const void *data, uint32_t size); +void wg_source_destroy(struct wg_source *source); + unsigned int wg_format_get_max_size(const struct wg_format *format); HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 232e81a6f27..7c917e2a39d 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -428,6 +428,34 @@ HRESULT wg_transform_drain(struct wg_transform *transform, BOOL flush) return WINE_UNIX_CALL(unix_wg_transform_drain, ¶ms); } +struct wg_source *wg_source_create(const WCHAR *url, const void *data, uint32_t size) +{ + struct wg_source_create_params params = + { + .data = data, .size = size, + }; + UINT len = url ? WideCharToMultiByte(CP_ACP, 0, url, -1, NULL, 0, NULL, NULL) : 0; + char *tmp = url ? malloc(len) : NULL; + + TRACE("url %s, data %p, size %#x\n", debugstr_w(url), data, size); + + if ((params.url = tmp)) + WideCharToMultiByte(CP_ACP, 0, url, -1, tmp, len, NULL, NULL); + + if (!WINE_UNIX_CALL(unix_wg_source_create, ¶ms)) + TRACE("Returning source %p.\n", params.source); + + free(tmp); + return params.source; +} + +void wg_source_destroy(struct wg_source *source) +{ + TRACE("source %p.\n", source); + + WINE_UNIX_CALL(unix_wg_source_destroy, source); +} + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { if (reason == DLL_PROCESS_ATTACH) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index eaef1ae791c..b31948b3003 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -90,6 +90,7 @@ struct media_source CRITICAL_SECTION cs; + struct wg_source *wg_source; struct wg_parser *wg_parser; UINT64 duration; @@ -1167,6 +1168,7 @@ static ULONG WINAPI media_source_Release(IMFMediaSource *iface) IMFMediaSource_Shutdown(iface); IMFMediaEventQueue_Release(source->event_queue); IMFByteStream_Release(source->byte_stream); + wg_source_destroy(source->wg_source); wg_parser_destroy(source->wg_parser); source->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&source->cs); @@ -1426,6 +1428,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d { unsigned int stream_count = UINT_MAX; struct media_source *object; + struct wg_source *wg_source; struct wg_parser *parser; DWORD bytestream_caps; uint64_t file_size; @@ -1447,8 +1450,14 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d return hr; } + if (!(wg_source = wg_source_create(url, data, size))) + return MF_E_UNSUPPORTED_FORMAT; + if (!(object = calloc(1, sizeof(*object)))) + { + wg_source_destroy(wg_source); return E_OUTOFMEMORY; + } object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl; object->IMFGetService_iface.lpVtbl = &media_source_get_service_vtbl; @@ -1456,8 +1465,9 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d object->IMFRateControl_iface.lpVtbl = &media_source_rate_control_vtbl; object->async_commands_callback.lpVtbl = &source_async_commands_callback_vtbl; object->ref = 1; - object->byte_stream = bytestream; IMFByteStream_AddRef(bytestream); + object->byte_stream = bytestream; + object->wg_source = wg_source; object->rate = 1.0f; InitializeCriticalSection(&object->cs); object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs"); @@ -1521,7 +1531,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d *out = &object->IMFMediaSource_iface; return S_OK; - fail: +fail: WARN("Failed to construct MFMediaSource, hr %#lx.\n", hr); while (object->streams && object->stream_count--) @@ -1548,6 +1558,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d if (object->event_queue) IMFMediaEventQueue_Release(object->event_queue); IMFByteStream_Release(object->byte_stream); + wg_source_destroy(wg_source); free(object); return hr; } diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 1b892cb0a98..9fc071206bc 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -43,6 +43,7 @@ extern GstElement *find_element(GstElementFactoryListType type, GstCaps *src_cap extern bool append_element(GstElement *container, GstElement *element, GstElement **first, GstElement **last) DECLSPEC_HIDDEN; extern bool link_src_to_element(GstPad *src_pad, GstElement *element) DECLSPEC_HIDDEN; extern bool link_element_to_sink(GstElement *element, GstPad *sink_pad) DECLSPEC_HIDDEN; +extern GstCaps *detect_caps_from_data(const char *url, const void *data, guint size) DECLSPEC_HIDDEN; /* wg_format.c */ @@ -60,6 +61,11 @@ extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_get_status(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_drain(void *args) DECLSPEC_HIDDEN; +/* wg_source.c */ + +extern NTSTATUS wg_source_create(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_source_destroy(void *args) DECLSPEC_HIDDEN; + /* wg_allocator.c */ /* wg_allocator_release_sample can be used to release any sample that was requested. */ diff --git a/dlls/winegstreamer/unixlib.c b/dlls/winegstreamer/unixlib.c index a185000654d..707a28fed97 100644 --- a/dlls/winegstreamer/unixlib.c +++ b/dlls/winegstreamer/unixlib.c @@ -30,6 +30,10 @@ #define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_30 #include +#include +#include +#include +#include #include #include "ntstatus.h" @@ -193,6 +197,32 @@ bool link_element_to_sink(GstElement *element, GstPad *sink_pad) return !ret; } +GstCaps *detect_caps_from_data(const char *url, const void *data, guint size) +{ + const char *extension = url ? strrchr(url, '.') : NULL; + GstTypeFindProbability probability; + GstCaps *caps; + gchar *str; + + if (!(caps = gst_type_find_helper_for_data_with_extension(NULL, data, size, + extension ? extension + 1 : NULL, &probability))) + { + GST_ERROR("Failed to detect caps for url %s, data %p, size %u", url, data, size); + return NULL; + } + + str = gst_caps_to_string(caps); + if (probability > GST_TYPE_FIND_POSSIBLE) + GST_INFO("Detected caps %s with probability %u for url %s, data %p, size %u", + str, probability, url, data, size); + else + GST_FIXME("Detected caps %s with probability %u for url %s, data %p, size %u", + str, probability, url, data, size); + g_free(str); + + return caps; +} + NTSTATUS wg_init_gstreamer(void *arg) { static GstGLContext *gl_context; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 9134cc47413..67e4ce6e831 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -336,6 +336,14 @@ struct wg_transform_drain_params BOOL flush; }; +struct wg_source_create_params +{ + const char *url; + const void *data; + UINT32 size; + struct wg_source *source; +}; + enum unix_funcs { unix_wg_init_gstreamer, @@ -373,6 +381,9 @@ enum unix_funcs unix_wg_transform_read_data, unix_wg_transform_get_status, unix_wg_transform_drain, + + unix_wg_source_create, + unix_wg_source_destroy, }; #endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 681ef4abfa7..f2b2ece4adc 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1918,4 +1918,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_transform_read_data), X(wg_transform_get_status), X(wg_transform_drain), + + X(wg_source_create), + X(wg_source_destroy), }; diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c new file mode 100644 index 00000000000..cce7e157dba --- /dev/null +++ b/dlls/winegstreamer/wg_source.c @@ -0,0 +1,99 @@ +/* + * Copyright 2023 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 + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "winternl.h" +#include "mferror.h" + +#include "unix_private.h" + +struct wg_source +{ + GstElement *container; +}; + +NTSTATUS wg_source_create(void *args) +{ + struct wg_source_create_params *params = args; + struct wg_source *source; + GstCaps *src_caps; + + if (!(src_caps = detect_caps_from_data(params->url, params->data, params->size))) + return STATUS_UNSUCCESSFUL; + if (!(source = calloc(1, sizeof(*source)))) + { + gst_caps_unref(src_caps); + return STATUS_UNSUCCESSFUL; + } + + if (!(source->container = gst_bin_new("wg_source"))) + goto error; + + gst_element_set_state(source->container, GST_STATE_PAUSED); + if (!gst_element_get_state(source->container, NULL, NULL, -1)) + goto error; + + gst_caps_unref(src_caps); + + params->source = source; + GST_INFO("Created winegstreamer source %p.", source); + return STATUS_SUCCESS; + +error: + if (source->container) + { + gst_element_set_state(source->container, GST_STATE_NULL); + gst_object_unref(source->container); + } + free(source); + + gst_caps_unref(src_caps); + + GST_ERROR("Failed to create winegstreamer source."); + return STATUS_UNSUCCESSFUL; +} + +NTSTATUS wg_source_destroy(void *args) +{ + struct wg_source *source = args; + + GST_TRACE("source %p", source); + + gst_element_set_state(source->container, GST_STATE_NULL); + gst_object_unref(source->container); + free(source); + + return STATUS_SUCCESS; +} From 8f76b3c2ab5328955ffdb0fb3fef2f0b23c004f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 26 Apr 2023 18:06:11 +0200 Subject: [PATCH 1974/2777] winegstreamer: Create a source pad on the wg_source. CW-Bug-Id: #21953 --- dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.c | 15 +++++++++++++++ dlls/winegstreamer/wg_parser.c | 4 +--- dlls/winegstreamer/wg_source.c | 7 +++++++ dlls/winegstreamer/wg_transform.c | 13 ++----------- 5 files changed, 26 insertions(+), 14 deletions(-) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 9fc071206bc..2185efbaf91 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -44,6 +44,7 @@ extern bool append_element(GstElement *container, GstElement *element, GstElemen extern bool link_src_to_element(GstPad *src_pad, GstElement *element) DECLSPEC_HIDDEN; extern bool link_element_to_sink(GstElement *element, GstPad *sink_pad) DECLSPEC_HIDDEN; extern GstCaps *detect_caps_from_data(const char *url, const void *data, guint size) DECLSPEC_HIDDEN; +extern GstPad *create_pad_with_caps(GstPadDirection direction, GstCaps *caps) DECLSPEC_HIDDEN; /* wg_format.c */ diff --git a/dlls/winegstreamer/unixlib.c b/dlls/winegstreamer/unixlib.c index 707a28fed97..777c210fa52 100644 --- a/dlls/winegstreamer/unixlib.c +++ b/dlls/winegstreamer/unixlib.c @@ -223,6 +223,21 @@ GstCaps *detect_caps_from_data(const char *url, const void *data, guint size) return caps; } +GstPad *create_pad_with_caps(GstPadDirection direction, GstCaps *caps) +{ + GstCaps *pad_caps = caps ? gst_caps_ref(caps) : gst_caps_new_any(); + const char *name = direction == GST_PAD_SRC ? "src" : "sink"; + GstPadTemplate *template; + GstPad *pad; + + if (!pad_caps || !(template = gst_pad_template_new(name, direction, GST_PAD_ALWAYS, pad_caps))) + return NULL; + pad = gst_pad_new_from_template(template, "src"); + g_object_unref(template); + gst_caps_unref(pad_caps); + return pad; +} + NTSTATUS wg_init_gstreamer(void *arg) { static GstGLContext *gl_context; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index f2b2ece4adc..a5e1716f5e8 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1461,8 +1461,6 @@ static void query_tags(struct wg_parser_stream *stream) static NTSTATUS wg_parser_connect(void *args) { - GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("quartz_src", - GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); const struct wg_parser_connect_params *params = args; struct wg_parser *parser = params->parser; const WCHAR *uri = params->uri; @@ -1493,7 +1491,7 @@ static NTSTATUS wg_parser_connect(void *args) if (parser->context) gst_element_set_context(parser->container, parser->context); - parser->my_src = gst_pad_new_from_static_template(&src_template, "quartz-src"); + parser->my_src = create_pad_with_caps(GST_PAD_SRC, NULL); gst_pad_set_getrange_function(parser->my_src, src_getrange_cb); gst_pad_set_query_function(parser->my_src, src_query_cb); gst_pad_set_activatemode_function(parser->my_src, src_activate_mode_cb); diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index cce7e157dba..3bda766c5eb 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -41,6 +41,7 @@ struct wg_source { + GstPad *src_pad; GstElement *container; }; @@ -60,6 +61,9 @@ NTSTATUS wg_source_create(void *args) if (!(source->container = gst_bin_new("wg_source"))) goto error; + if (!(source->src_pad = create_pad_with_caps(GST_PAD_SRC, src_caps))) + goto error; + gst_pad_set_element_private(source->src_pad, source); gst_element_set_state(source->container, GST_STATE_PAUSED); if (!gst_element_get_state(source->container, NULL, NULL, -1)) @@ -77,6 +81,8 @@ NTSTATUS wg_source_create(void *args) gst_element_set_state(source->container, GST_STATE_NULL); gst_object_unref(source->container); } + if (source->src_pad) + gst_object_unref(source->src_pad); free(source); gst_caps_unref(src_caps); @@ -93,6 +99,7 @@ NTSTATUS wg_source_destroy(void *args) gst_element_set_state(source->container, GST_STATE_NULL); gst_object_unref(source->container); + gst_object_unref(source->src_pad); free(source); return STATUS_SUCCESS; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index f5fd96ba674..18ba562ab22 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -284,7 +284,6 @@ NTSTATUS wg_transform_create(void *args) GstElement *first = NULL, *last = NULL, *element; GstCaps *raw_caps = NULL, *src_caps = NULL; NTSTATUS status = STATUS_UNSUCCESSFUL; - GstPadTemplate *template = NULL; struct wg_transform *transform; const gchar *media_type; GstEvent *event; @@ -310,20 +309,12 @@ NTSTATUS wg_transform_create(void *args) if (!(src_caps = wg_format_to_caps(&input_format))) goto out; - if (!(template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps))) - goto out; - transform->my_src = gst_pad_new_from_template(template, "src"); - g_object_unref(template); - if (!transform->my_src) + if (!(transform->my_src = create_pad_with_caps(GST_PAD_SRC, src_caps))) goto out; if (!(transform->output_caps = wg_format_to_caps(&output_format))) goto out; - if (!(template = gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS, transform->output_caps))) - goto out; - transform->my_sink = gst_pad_new_from_template(template, "sink"); - g_object_unref(template); - if (!transform->my_sink) + if (!(transform->my_sink = create_pad_with_caps(GST_PAD_SINK, transform->output_caps))) goto out; gst_pad_set_element_private(transform->my_sink, transform); From 7aeed26aa65ea9f062a89fa3b18f15cfb798ac80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Apr 2023 15:22:44 +0200 Subject: [PATCH 1975/2777] winegstreamer: Create a demuxer element in wg_source_create. CW-Bug-Id: #21953 --- dlls/winegstreamer/wg_source.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 3bda766c5eb..17147afdec6 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -48,8 +48,9 @@ struct wg_source NTSTATUS wg_source_create(void *args) { struct wg_source_create_params *params = args; + GstElement *first = NULL, *last = NULL, *element; + GstCaps *src_caps, *any_caps; struct wg_source *source; - GstCaps *src_caps; if (!(src_caps = detect_caps_from_data(params->url, params->data, params->size))) return STATUS_UNSUCCESSFUL; @@ -65,6 +66,21 @@ NTSTATUS wg_source_create(void *args) goto error; gst_pad_set_element_private(source->src_pad, source); + if (!(any_caps = gst_caps_new_any())) + goto error; + if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODABLE, src_caps, any_caps)) + || !append_element(source->container, element, &first, &last)) + { + gst_caps_unref(any_caps); + goto error; + } + gst_caps_unref(any_caps); + + if (!link_src_to_element(source->src_pad, first)) + goto error; + if (!gst_pad_set_active(source->src_pad, true)) + goto error; + gst_element_set_state(source->container, GST_STATE_PAUSED); if (!gst_element_get_state(source->container, NULL, NULL, -1)) goto error; From e71be53594fa4e40b9785db7a24be119a1ef1b42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Apr 2023 15:22:55 +0200 Subject: [PATCH 1976/2777] winegstreamer: Push a stream and segment event to the wg_source. CW-Bug-Id: #21953 --- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/main.c | 12 +++++++++ dlls/winegstreamer/media_source.c | 3 +++ dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 8 ++++++ dlls/winegstreamer/wg_parser.c | 1 + dlls/winegstreamer/wg_source.c | 42 +++++++++++++++++++++++++++++++ 7 files changed, 68 insertions(+) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 1b91ef863a7..bad1d2506e3 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -109,6 +109,7 @@ HRESULT wg_transform_drain(struct wg_transform *transform, BOOL flush); struct wg_source *wg_source_create(const WCHAR *url, const void *data, uint32_t size); void wg_source_destroy(struct wg_source *source); +HRESULT wg_source_push_data(struct wg_source *source, const void *data, uint32_t size); unsigned int wg_format_get_max_size(const struct wg_format *format); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 7c917e2a39d..43409ef7512 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -456,6 +456,18 @@ void wg_source_destroy(struct wg_source *source) WINE_UNIX_CALL(unix_wg_source_destroy, source); } +HRESULT wg_source_push_data(struct wg_source *source, const void *data, uint32_t size) +{ + struct wg_source_push_data_params params = + { + .source = source, + .data = data, + .size = size, + }; + TRACE("source %p, data %p, size %#x\n", source, data, size); + return HRESULT_FROM_NT(WINE_UNIX_CALL(unix_wg_source_push_data, ¶ms)); +} + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { if (reason == DLL_PROCESS_ATTACH) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index b31948b3003..b04b3c468c9 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1453,6 +1453,9 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d if (!(wg_source = wg_source_create(url, data, size))) return MF_E_UNSUPPORTED_FORMAT; + if (FAILED(hr = wg_source_push_data(wg_source, data, size))) + WARN("Failed to push initial data, hr %#lx\n", hr); + if (!(object = calloc(1, sizeof(*object)))) { wg_source_destroy(wg_source); diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 2185efbaf91..2d7d487b1a2 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -66,6 +66,7 @@ extern NTSTATUS wg_transform_drain(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_source_create(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_source_destroy(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_source_push_data(void *args) DECLSPEC_HIDDEN; /* wg_allocator.c */ diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 67e4ce6e831..ffd42b61260 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -344,6 +344,13 @@ struct wg_source_create_params struct wg_source *source; }; +struct wg_source_push_data_params +{ + struct wg_source *source; + const void *data; + UINT32 size; +}; + enum unix_funcs { unix_wg_init_gstreamer, @@ -384,6 +391,7 @@ enum unix_funcs unix_wg_source_create, unix_wg_source_destroy, + unix_wg_source_push_data, }; #endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index a5e1716f5e8..5b72579da31 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1919,4 +1919,5 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_source_create), X(wg_source_destroy), + X(wg_source_push_data), }; diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 17147afdec6..7b72ab2ebf2 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -43,14 +43,33 @@ struct wg_source { GstPad *src_pad; GstElement *container; + GstSegment segment; + bool valid_segment; }; +static GstEvent *create_stream_start_event(const char *stream_id) +{ + GstStream *stream; + GstEvent *event; + + if (!(stream = gst_stream_new(stream_id, NULL, GST_STREAM_TYPE_UNKNOWN, 0))) + return NULL; + if ((event = gst_event_new_stream_start(stream_id))) + { + gst_event_set_stream(event, stream); + gst_object_unref(stream); + } + + return event; +} + NTSTATUS wg_source_create(void *args) { struct wg_source_create_params *params = args; GstElement *first = NULL, *last = NULL, *element; GstCaps *src_caps, *any_caps; struct wg_source *source; + GstEvent *event; if (!(src_caps = detect_caps_from_data(params->url, params->data, params->size))) return STATUS_UNSUCCESSFUL; @@ -59,6 +78,7 @@ NTSTATUS wg_source_create(void *args) gst_caps_unref(src_caps); return STATUS_UNSUCCESSFUL; } + gst_segment_init(&source->segment, GST_FORMAT_BYTES); if (!(source->container = gst_bin_new("wg_source"))) goto error; @@ -85,6 +105,9 @@ NTSTATUS wg_source_create(void *args) if (!gst_element_get_state(source->container, NULL, NULL, -1)) goto error; + if (!(event = create_stream_start_event("wg_source")) + || !gst_pad_push_event(source->src_pad, event)) + goto error; gst_caps_unref(src_caps); params->source = source; @@ -120,3 +143,22 @@ NTSTATUS wg_source_destroy(void *args) return STATUS_SUCCESS; } + +NTSTATUS wg_source_push_data(void *args) +{ + struct wg_source_push_data_params *params = args; + struct wg_source *source = params->source; + GstEvent *event; + + GST_TRACE("source %p, data %p, size %#x", source, params->data, params->size); + + if (!source->valid_segment) + { + if (!(event = gst_event_new_segment(&source->segment)) + || !gst_pad_push_event(source->src_pad, event)) + GST_ERROR("Failed to push new segment event"); + source->valid_segment = true; + } + + return STATUS_SUCCESS; +} From 13d4eb394e16f4a8446ea1c6cda10be2e190a458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Apr 2023 15:28:21 +0200 Subject: [PATCH 1977/2777] winegstreamer: Handle GST_QUERY_DURATION on wg_source src pad. CW-Bug-Id: #21953 --- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 7 +++++-- dlls/winegstreamer/media_source.c | 2 +- dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_source.c | 28 ++++++++++++++++++++++++++++ 5 files changed, 36 insertions(+), 4 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index bad1d2506e3..84f53405f1d 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -107,7 +107,7 @@ bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_fo bool wg_transform_get_status(struct wg_transform *transform, bool *accepts_input); HRESULT wg_transform_drain(struct wg_transform *transform, BOOL flush); -struct wg_source *wg_source_create(const WCHAR *url, const void *data, uint32_t size); +struct wg_source *wg_source_create(const WCHAR *url, uint64_t file_size, const void *data, uint32_t size); void wg_source_destroy(struct wg_source *source); HRESULT wg_source_push_data(struct wg_source *source, const void *data, uint32_t size); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 43409ef7512..6498b312f52 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -428,16 +428,19 @@ HRESULT wg_transform_drain(struct wg_transform *transform, BOOL flush) return WINE_UNIX_CALL(unix_wg_transform_drain, ¶ms); } -struct wg_source *wg_source_create(const WCHAR *url, const void *data, uint32_t size) +struct wg_source *wg_source_create(const WCHAR *url, uint64_t file_size, + const void *data, uint32_t size) { struct wg_source_create_params params = { + .file_size = file_size, .data = data, .size = size, }; UINT len = url ? WideCharToMultiByte(CP_ACP, 0, url, -1, NULL, 0, NULL, NULL) : 0; char *tmp = url ? malloc(len) : NULL; - TRACE("url %s, data %p, size %#x\n", debugstr_w(url), data, size); + TRACE("url %s, file_size %#I64x, data %p, size %#x\n", debugstr_w(url), + file_size, data, size); if ((params.url = tmp)) WideCharToMultiByte(CP_ACP, 0, url, -1, tmp, len, NULL, NULL); diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index b04b3c468c9..bb9dacd75ca 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1450,7 +1450,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d return hr; } - if (!(wg_source = wg_source_create(url, data, size))) + if (!(wg_source = wg_source_create(url, file_size, data, size))) return MF_E_UNSUPPORTED_FORMAT; if (FAILED(hr = wg_source_push_data(wg_source, data, size))) diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index ffd42b61260..23f6db0d0e8 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -339,6 +339,7 @@ struct wg_transform_drain_params struct wg_source_create_params { const char *url; + UINT64 file_size; const void *data; UINT32 size; struct wg_source *source; diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 7b72ab2ebf2..65f489215ac 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -47,6 +47,32 @@ struct wg_source bool valid_segment; }; +static gboolean src_query_duration(struct wg_source *source, GstQuery *query) +{ + GstFormat format; + + gst_query_parse_duration(query, &format, NULL); + GST_TRACE("source %p, format %s", source, gst_format_get_name(format)); + if (format != GST_FORMAT_BYTES) + return false; + + gst_query_set_duration(query, format, source->segment.stop); + return true; +} + +static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) +{ + struct wg_source *source = gst_pad_get_element_private(pad); + + switch (GST_QUERY_TYPE(query)) + { + case GST_QUERY_DURATION: + return src_query_duration(source, query); + default: + return gst_pad_query_default(pad, parent, query); + } +} + static GstEvent *create_stream_start_event(const char *stream_id) { GstStream *stream; @@ -79,12 +105,14 @@ NTSTATUS wg_source_create(void *args) return STATUS_UNSUCCESSFUL; } gst_segment_init(&source->segment, GST_FORMAT_BYTES); + source->segment.stop = params->file_size; if (!(source->container = gst_bin_new("wg_source"))) goto error; if (!(source->src_pad = create_pad_with_caps(GST_PAD_SRC, src_caps))) goto error; gst_pad_set_element_private(source->src_pad, source); + gst_pad_set_query_function(source->src_pad, src_query_cb); if (!(any_caps = gst_caps_new_any())) goto error; From 00cd1043737681e325e67c4cd100272d87748d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 26 Apr 2023 18:49:44 +0200 Subject: [PATCH 1978/2777] winegstreamer: Handle GST_QUERY_SCHEDULING on wg_source src pad. CW-Bug-Id: #21953 --- dlls/winegstreamer/wg_source.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 65f489215ac..6e4efd4a39d 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -60,6 +60,14 @@ static gboolean src_query_duration(struct wg_source *source, GstQuery *query) return true; } +static gboolean src_query_scheduling(struct wg_source *source, GstQuery *query) +{ + GST_TRACE("source %p", source); + gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0); + gst_query_add_scheduling_mode(query, GST_PAD_MODE_PUSH); + return true; +} + static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) { struct wg_source *source = gst_pad_get_element_private(pad); @@ -68,6 +76,8 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) { case GST_QUERY_DURATION: return src_query_duration(source, query); + case GST_QUERY_SCHEDULING: + return src_query_scheduling(source, query); default: return gst_pad_query_default(pad, parent, query); } From b47bed2d2d6f99e384393ca207c8cd21508eb883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 29 Apr 2023 18:31:16 +0200 Subject: [PATCH 1979/2777] winegstreamer: Create and link sink pads in the wg_source. CW-Bug-Id: #21953 --- dlls/winegstreamer/wg_source.c | 58 ++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 6e4efd4a39d..f30fafb85a2 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -39,12 +39,17 @@ #include "unix_private.h" +#define WG_SOURCE_MAX_STREAMS 32 + struct wg_source { GstPad *src_pad; GstElement *container; GstSegment segment; bool valid_segment; + + GstPad *stream_pads[WG_SOURCE_MAX_STREAMS]; + guint stream_count; }; static gboolean src_query_duration(struct wg_source *source, GstQuery *query) @@ -83,6 +88,14 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) } } +static GstFlowReturn sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) +{ + struct wg_soutce *source = gst_pad_get_element_private(pad); + GST_TRACE("source %p, pad %p, buffer %p.", source, pad, buffer); + gst_buffer_unref(buffer); + return GST_FLOW_EOS; +} + static GstEvent *create_stream_start_event(const char *stream_id) { GstStream *stream; @@ -99,6 +112,24 @@ static GstEvent *create_stream_start_event(const char *stream_id) return event; } +static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) +{ + struct wg_source *source = user; + GstPad *sink_pad; + guint index; + + GST_TRACE("source %p, element %p, pad %p.", source, element, pad); + if ((index = source->stream_count++) >= ARRAY_SIZE(source->stream_pads)) + { + GST_FIXME("Not enough sink pads, need %u", source->stream_count); + return; + } + + sink_pad = source->stream_pads[index]; + if (gst_pad_link(pad, sink_pad) < 0 || !gst_pad_set_active(sink_pad, true)) + GST_ERROR("Failed to link new pad to sink pad %p", sink_pad); +} + NTSTATUS wg_source_create(void *args) { struct wg_source_create_params *params = args; @@ -106,6 +137,8 @@ NTSTATUS wg_source_create(void *args) GstCaps *src_caps, *any_caps; struct wg_source *source; GstEvent *event; + GstPad *peer; + guint i; if (!(src_caps = detect_caps_from_data(params->url, params->data, params->size))) return STATUS_UNSUCCESSFUL; @@ -124,6 +157,14 @@ NTSTATUS wg_source_create(void *args) gst_pad_set_element_private(source->src_pad, source); gst_pad_set_query_function(source->src_pad, src_query_cb); + for (i = 0; i < ARRAY_SIZE(source->stream_pads); i++) + { + if (!(source->stream_pads[i] = create_pad_with_caps(GST_PAD_SINK, NULL))) + goto error; + gst_pad_set_element_private(source->stream_pads[i], source); + gst_pad_set_chain_function(source->stream_pads[i], sink_chain_cb); + } + if (!(any_caps = gst_caps_new_any())) goto error; if (!(element = find_element(GST_ELEMENT_FACTORY_TYPE_DECODABLE, src_caps, any_caps)) @@ -132,6 +173,7 @@ NTSTATUS wg_source_create(void *args) gst_caps_unref(any_caps); goto error; } + g_signal_connect(element, "pad-added", G_CALLBACK(pad_added_cb), source); gst_caps_unref(any_caps); if (!link_src_to_element(source->src_pad, first)) @@ -139,6 +181,17 @@ NTSTATUS wg_source_create(void *args) if (!gst_pad_set_active(source->src_pad, true)) goto error; + /* try to link the first output pad, some demuxers only have static pads */ + if ((peer = gst_element_get_static_pad(last, "src"))) + { + GstPad *sink_pad = source->stream_pads[0]; + if (gst_pad_link(peer, sink_pad) < 0 || !gst_pad_set_active(sink_pad, true)) + GST_ERROR("Failed to link static source pad %p", peer); + else + source->stream_count++; + gst_object_unref(peer); + } + gst_element_set_state(source->container, GST_STATE_PAUSED); if (!gst_element_get_state(source->container, NULL, NULL, -1)) goto error; @@ -158,6 +211,8 @@ NTSTATUS wg_source_create(void *args) gst_element_set_state(source->container, GST_STATE_NULL); gst_object_unref(source->container); } + for (i = 0; i < ARRAY_SIZE(source->stream_pads) && source->stream_pads[i]; i++) + gst_object_unref(source->stream_pads[i]); if (source->src_pad) gst_object_unref(source->src_pad); free(source); @@ -171,11 +226,14 @@ NTSTATUS wg_source_create(void *args) NTSTATUS wg_source_destroy(void *args) { struct wg_source *source = args; + guint i; GST_TRACE("source %p", source); gst_element_set_state(source->container, GST_STATE_NULL); gst_object_unref(source->container); + for (i = 0; i < ARRAY_SIZE(source->stream_pads); i++) + gst_object_unref(source->stream_pads[i]); gst_object_unref(source->src_pad); free(source); From dc0f784c345c47cfb909047229c5e907f6d48e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Apr 2023 15:28:30 +0200 Subject: [PATCH 1980/2777] winegstreamer: Push the initial data from to the wg_source. CW-Bug-Id: #21953 --- dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.c | 15 +++++++++++++++ dlls/winegstreamer/wg_source.c | 16 ++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 2d7d487b1a2..b15efa1fe51 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -45,6 +45,7 @@ extern bool link_src_to_element(GstPad *src_pad, GstElement *element) DECLSPEC_H extern bool link_element_to_sink(GstElement *element, GstPad *sink_pad) DECLSPEC_HIDDEN; extern GstCaps *detect_caps_from_data(const char *url, const void *data, guint size) DECLSPEC_HIDDEN; extern GstPad *create_pad_with_caps(GstPadDirection direction, GstCaps *caps) DECLSPEC_HIDDEN; +extern GstBuffer *create_buffer_from_bytes(const void *data, guint size) DECLSPEC_HIDDEN; /* wg_format.c */ diff --git a/dlls/winegstreamer/unixlib.c b/dlls/winegstreamer/unixlib.c index 777c210fa52..618897f0632 100644 --- a/dlls/winegstreamer/unixlib.c +++ b/dlls/winegstreamer/unixlib.c @@ -238,6 +238,21 @@ GstPad *create_pad_with_caps(GstPadDirection direction, GstCaps *caps) return pad; } +GstBuffer *create_buffer_from_bytes(const void *data, guint size) +{ + GstBuffer *buffer; + + if (!(buffer = gst_buffer_new_and_alloc(size))) + GST_ERROR("Failed to allocate buffer for %#x bytes\n", size); + else + { + gst_buffer_fill(buffer, 0, data, size); + gst_buffer_set_size(buffer, size); + } + + return buffer; +} + NTSTATUS wg_init_gstreamer(void *arg) { static GstGLContext *gl_context; diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index f30fafb85a2..2675d22db29 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -244,6 +244,8 @@ NTSTATUS wg_source_push_data(void *args) { struct wg_source_push_data_params *params = args; struct wg_source *source = params->source; + GstFlowReturn ret = GST_FLOW_OK; + GstBuffer *buffer; GstEvent *event; GST_TRACE("source %p, data %p, size %#x", source, params->data, params->size); @@ -256,5 +258,19 @@ NTSTATUS wg_source_push_data(void *args) source->valid_segment = true; } + if (!(buffer = create_buffer_from_bytes(params->data, params->size))) + { + GST_WARNING("Failed to allocate buffer for data"); + return STATUS_UNSUCCESSFUL; + } + + source->segment.start += params->size; + if ((ret = gst_pad_push(source->src_pad, buffer)) && ret != GST_FLOW_EOS) + { + GST_WARNING("Failed to push data buffer, ret %d", ret); + source->segment.start -= params->size; + return STATUS_UNSUCCESSFUL; + } + return STATUS_SUCCESS; } From 070346f66820366d315196e21c3a980173deeab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Apr 2023 22:44:15 +0200 Subject: [PATCH 1981/2777] winegstreamer: Push EOS event when segment is complete. CW-Bug-Id: #21953 --- dlls/winegstreamer/wg_source.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 2675d22db29..9f42c496fcf 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -272,5 +272,12 @@ NTSTATUS wg_source_push_data(void *args) return STATUS_UNSUCCESSFUL; } + if (source->segment.start != source->segment.stop) + return STATUS_SUCCESS; + + if (!(event = gst_event_new_eos()) + || !gst_pad_push_event(source->src_pad, event)) + GST_WARNING("Failed to push EOS event"); + return STATUS_SUCCESS; } From 62f698530973affb23bbced90e2a4a2647c9abc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Apr 2023 17:33:07 +0200 Subject: [PATCH 1982/2777] winegstreamer: Handle GST_EVENT_SEEK on wg_source src pad. CW-Bug-Id: #21953 --- dlls/winegstreamer/wg_source.c | 77 ++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 9f42c496fcf..9076bf2a8d5 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -52,6 +52,67 @@ struct wg_source guint stream_count; }; +static gboolean src_event_seek(struct wg_source *source, GstEvent *event) +{ + guint32 seqnum = gst_event_get_seqnum(event); + GstSeekType cur_type, stop_type; + GstSeekFlags flags; + GstFormat format; + gint64 cur, stop; + gdouble rate; + + gst_event_parse_seek(event, &rate, &format, &flags, &cur_type, &cur, &stop_type, &stop); + gst_event_unref(event); + if (format != GST_FORMAT_BYTES) + return false; + + GST_TRACE("source %p, rate %f, format %s, flags %#x, cur_type %u, cur %#" G_GINT64_MODIFIER "x, " + "stop_type %u, stop %#" G_GINT64_MODIFIER "x.", source, rate, gst_format_get_name(format), + flags, cur_type, cur, stop_type, stop); + + if (flags & GST_SEEK_FLAG_FLUSH) + { + if (!(event = gst_event_new_flush_start())) + GST_ERROR("Failed to allocate flush_start event"); + else + { + gst_event_set_seqnum(event, seqnum); + if (!gst_pad_push_event(source->src_pad, event)) + GST_ERROR("Failed to push flush_start event"); + } + } + + source->segment.start = cur; + + if (flags & GST_SEEK_FLAG_FLUSH) + { + if (!(event = gst_event_new_flush_stop(true))) + GST_ERROR("Failed to allocate flush_stop event"); + else + { + gst_event_set_seqnum(event, seqnum); + if (!gst_pad_push_event(source->src_pad, event)) + GST_ERROR("Failed to push flush_stop event"); + } + source->valid_segment = false; + } + + return true; +} + +static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) +{ + struct wg_source *source = gst_pad_get_element_private(pad); + + switch (GST_EVENT_TYPE(event)) + { + case GST_EVENT_SEEK: + return src_event_seek(source, event); + default: + return gst_pad_event_default(pad, parent, event); + } +} + static gboolean src_query_duration(struct wg_source *source, GstQuery *query) { GstFormat format; @@ -73,6 +134,19 @@ static gboolean src_query_scheduling(struct wg_source *source, GstQuery *query) return true; } +static gboolean src_query_seeking(struct wg_source *source, GstQuery *query) +{ + GstFormat format; + + gst_query_parse_seeking(query, &format, NULL, NULL, NULL); + GST_TRACE("source %p, format %s", source, gst_format_get_name(format)); + if (format != GST_FORMAT_BYTES) + return false; + + gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, source->segment.stop); + return true; +} + static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) { struct wg_source *source = gst_pad_get_element_private(pad); @@ -83,6 +157,8 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) return src_query_duration(source, query); case GST_QUERY_SCHEDULING: return src_query_scheduling(source, query); + case GST_QUERY_SEEKING: + return src_query_seeking(source, query); default: return gst_pad_query_default(pad, parent, query); } @@ -156,6 +232,7 @@ NTSTATUS wg_source_create(void *args) goto error; gst_pad_set_element_private(source->src_pad, source); gst_pad_set_query_function(source->src_pad, src_query_cb); + gst_pad_set_event_function(source->src_pad, src_event_cb); for (i = 0; i < ARRAY_SIZE(source->stream_pads); i++) { From 537c41232c7ecfd2b8b77e3c550b811f6290b1c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Apr 2023 11:53:27 +0200 Subject: [PATCH 1983/2777] winegstreamer: Handle GST_EVENT_STREAM_START and create wg_source streams. CW-Bug-Id: #21953 --- dlls/winegstreamer/wg_source.c | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 9076bf2a8d5..ae631d32259 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -172,6 +172,38 @@ static GstFlowReturn sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *bu return GST_FLOW_EOS; } +static gboolean sink_event_stream_start(struct wg_source *source, GstPad *pad, GstEvent *event) +{ + guint group, flags; + GstStream *stream; + const gchar *id; + + gst_event_parse_stream_start(event, &id); + gst_event_parse_stream(event, &stream); + gst_event_parse_stream_flags(event, &flags); + if (!gst_event_parse_group_id(event, &group)) + group = -1; + + GST_TRACE("source %p, pad %p, stream %p, id %s, flags %#x, group %d, duration %" GST_TIME_FORMAT, + source, pad, stream, id, flags, group, GST_TIME_ARGS(duration)); + + gst_event_unref(event); + return true; +} + +static gboolean sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) +{ + struct wg_source *source = gst_pad_get_element_private(pad); + + switch (GST_EVENT_TYPE(event)) + { + case GST_EVENT_STREAM_START: + return sink_event_stream_start(source, pad, event); + default: + return gst_pad_event_default(pad, parent, event); + } +} + static GstEvent *create_stream_start_event(const char *stream_id) { GstStream *stream; @@ -191,7 +223,10 @@ static GstEvent *create_stream_start_event(const char *stream_id) static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) { struct wg_source *source = user; + char stream_id[256]; + GstFlowReturn ret; GstPad *sink_pad; + GstEvent *event; guint index; GST_TRACE("source %p, element %p, pad %p.", source, element, pad); @@ -204,6 +239,18 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) sink_pad = source->stream_pads[index]; if (gst_pad_link(pad, sink_pad) < 0 || !gst_pad_set_active(sink_pad, true)) GST_ERROR("Failed to link new pad to sink pad %p", sink_pad); + + snprintf(stream_id, ARRAY_SIZE(stream_id), "wg_source/%03u", index); + if (!(event = create_stream_start_event(stream_id))) + GST_ERROR("Failed to create stream event for sink pad %p", sink_pad); + else + { + if ((ret = gst_pad_store_sticky_event(pad, event)) < 0) + GST_ERROR("Failed to create pad %p stream, ret %d", sink_pad, ret); + if ((ret = gst_pad_store_sticky_event(sink_pad, event)) < 0) + GST_ERROR("Failed to create pad %p stream, ret %d", sink_pad, ret); + gst_event_unref(event); + } } NTSTATUS wg_source_create(void *args) @@ -240,6 +287,7 @@ NTSTATUS wg_source_create(void *args) goto error; gst_pad_set_element_private(source->stream_pads[i], source); gst_pad_set_chain_function(source->stream_pads[i], sink_chain_cb); + gst_pad_set_event_function(source->stream_pads[i], sink_event_cb); } if (!(any_caps = gst_caps_new_any())) From 2c7f7848f25fed97028317268eba4da82bb45c54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 15 Mar 2023 11:47:15 +0100 Subject: [PATCH 1984/2777] winegstreamer: Query stream duration from GST_EVENT_STREAM_START. CW-Bug-Id: #21953 --- dlls/winegstreamer/wg_source.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index ae631d32259..e39d44da1b5 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -48,6 +48,7 @@ struct wg_source GstSegment segment; bool valid_segment; + guint64 max_duration; GstPad *stream_pads[WG_SOURCE_MAX_STREAMS]; guint stream_count; }; @@ -176,6 +177,7 @@ static gboolean sink_event_stream_start(struct wg_source *source, GstPad *pad, G { guint group, flags; GstStream *stream; + gint64 duration; const gchar *id; gst_event_parse_stream_start(event, &id); @@ -183,6 +185,8 @@ static gboolean sink_event_stream_start(struct wg_source *source, GstPad *pad, G gst_event_parse_stream_flags(event, &flags); if (!gst_event_parse_group_id(event, &group)) group = -1; + if (gst_pad_peer_query_duration(pad, GST_FORMAT_TIME, &duration) && GST_CLOCK_TIME_IS_VALID(duration)) + source->max_duration = max(source->max_duration, duration); GST_TRACE("source %p, pad %p, stream %p, id %s, flags %#x, group %d, duration %" GST_TIME_FORMAT, source, pad, stream, id, flags, group, GST_TIME_ARGS(duration)); From d6691716678625596c0b0b3a2ee0834127d58f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Apr 2023 12:20:15 +0200 Subject: [PATCH 1985/2777] winegstreamer: Handle GST_EVENT_CAPS and update wg_source streams caps. CW-Bug-Id: #21953 --- dlls/winegstreamer/wg_source.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index e39d44da1b5..cace89c1444 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -173,6 +173,28 @@ static GstFlowReturn sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *bu return GST_FLOW_EOS; } +static gboolean sink_event_caps(struct wg_source *source, GstPad *pad, GstEvent *event) +{ + GstStream *stream; + GstCaps *caps; + gchar *str; + + gst_event_parse_caps(event, &caps); + str = gst_caps_to_string(caps); + GST_TRACE("source %p, pad %p, caps %s", source, pad, str); + g_free(str); + + if ((stream = gst_pad_get_stream(pad))) + { + gst_stream_set_caps(stream, gst_caps_copy(caps)); + gst_stream_set_stream_type(stream, stream_type_from_caps(caps)); + gst_object_unref(stream); + } + + gst_event_unref(event); + return !!stream; +} + static gboolean sink_event_stream_start(struct wg_source *source, GstPad *pad, GstEvent *event) { guint group, flags; @@ -201,6 +223,8 @@ static gboolean sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) switch (GST_EVENT_TYPE(event)) { + case GST_EVENT_CAPS: + return sink_event_caps(source, pad, event); case GST_EVENT_STREAM_START: return sink_event_stream_start(source, pad, event); default: From 0c08afb7425e2703ccd23b2b9e5879eddaf3c71e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 26 Apr 2023 18:49:44 +0200 Subject: [PATCH 1986/2777] winegstreamer: Introduce a new wg_source_get_status unix call. CW-Bug-Id: #21953 --- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/main.c | 19 ++++++++++++++++ dlls/winegstreamer/media_source.c | 6 ++++-- dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 7 ++++++ dlls/winegstreamer/wg_parser.c | 1 + dlls/winegstreamer/wg_source.c | 36 +++++++++++++++++++++++++++++++ 7 files changed, 69 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 84f53405f1d..5661d9e3717 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -109,6 +109,7 @@ HRESULT wg_transform_drain(struct wg_transform *transform, BOOL flush); struct wg_source *wg_source_create(const WCHAR *url, uint64_t file_size, const void *data, uint32_t size); void wg_source_destroy(struct wg_source *source); +bool wg_source_get_status(struct wg_source *source, uint32_t *stream_count); HRESULT wg_source_push_data(struct wg_source *source, const void *data, uint32_t size); unsigned int wg_format_get_max_size(const struct wg_format *format); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 6498b312f52..d5fe2455932 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -459,6 +459,25 @@ void wg_source_destroy(struct wg_source *source) WINE_UNIX_CALL(unix_wg_source_destroy, source); } +bool wg_source_get_status(struct wg_source *source, uint32_t *stream_count) +{ + struct wg_source_get_status_params params = + { + .source = source, + }; + NTSTATUS status; + + TRACE("source %p, stream_count %p\n", source, stream_count); + + if ((status = WINE_UNIX_CALL(unix_wg_source_get_status, ¶ms)) + && status != STATUS_PENDING) + return false; + + *stream_count = params.stream_count; + TRACE("source %p, stream_count %u\n", source, *stream_count); + return true; +} + HRESULT wg_source_push_data(struct wg_source *source, const void *data, uint32_t size) { struct wg_source_push_data_params params = diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index bb9dacd75ca..33a8b86d2a3 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1426,7 +1426,7 @@ static void media_source_init_descriptors(struct media_source *source) HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *data, UINT64 size, IMFMediaSource **out) { - unsigned int stream_count = UINT_MAX; + UINT32 stream_count; struct media_source *object; struct wg_source *wg_source; struct wg_parser *parser; @@ -1455,6 +1455,8 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d if (FAILED(hr = wg_source_push_data(wg_source, data, size))) WARN("Failed to push initial data, hr %#lx\n", hr); + if (wg_source_get_status(wg_source, &stream_count)) + TRACE("Found %u streams\n", stream_count); if (!(object = calloc(1, sizeof(*object)))) { @@ -1546,7 +1548,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d free(object->descriptors); free(object->streams); - if (stream_count != UINT_MAX) + if (object->state == SOURCE_OPENING) wg_parser_disconnect(object->wg_parser); if (object->read_thread) { diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index b15efa1fe51..774df66c247 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -67,6 +67,7 @@ extern NTSTATUS wg_transform_drain(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_source_create(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_source_destroy(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_source_get_status(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_source_push_data(void *args) DECLSPEC_HIDDEN; /* wg_allocator.c */ diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 23f6db0d0e8..1e30b9a991a 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -345,6 +345,12 @@ struct wg_source_create_params struct wg_source *source; }; +struct wg_source_get_status_params +{ + struct wg_source *source; + UINT32 stream_count; +}; + struct wg_source_push_data_params { struct wg_source *source; @@ -392,6 +398,7 @@ enum unix_funcs unix_wg_source_create, unix_wg_source_destroy, + unix_wg_source_get_status, unix_wg_source_push_data, }; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 5b72579da31..b3d0e6d2716 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1919,5 +1919,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_source_create), X(wg_source_destroy), + X(wg_source_get_status), X(wg_source_push_data), }; diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index cace89c1444..7ad30bd5429 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -53,6 +53,22 @@ struct wg_source guint stream_count; }; +static GstStream *source_get_stream(struct wg_source *source, guint index) +{ + return index >= source->stream_count ? NULL : gst_pad_get_stream(source->stream_pads[index]); +} + +static GstCaps *source_get_stream_caps(struct wg_source *source, guint index) +{ + GstStream *stream; + GstCaps *caps; + if (!(stream = source_get_stream(source, index))) + return NULL; + caps = gst_stream_get_caps(stream); + gst_object_unref(stream); + return caps; +} + static gboolean src_event_seek(struct wg_source *source, GstEvent *event) { guint32 seqnum = gst_event_get_seqnum(event); @@ -393,6 +409,26 @@ NTSTATUS wg_source_destroy(void *args) return STATUS_SUCCESS; } +NTSTATUS wg_source_get_status(void *args) +{ + struct wg_source_get_status_params *params = args; + struct wg_source *source = params->source; + UINT i, stream_count; + GstCaps *caps; + + GST_TRACE("source %p", source); + + for (i = 0, stream_count = source->stream_count; i < stream_count; i++) + { + if (!(caps = source_get_stream_caps(source, i))) + return STATUS_PENDING; + gst_caps_unref(caps); + } + + params->stream_count = stream_count; + return STATUS_SUCCESS; +} + NTSTATUS wg_source_push_data(void *args) { struct wg_source_push_data_params *params = args; From 5fcfc7a5f94f2fe933920117ebbc3128b0047a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 29 Apr 2023 16:27:15 +0200 Subject: [PATCH 1987/2777] winegstreamer: Set the MF_PD_TOTAL_FILE_SIZE presentation descriptor attribute. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 33a8b86d2a3..b013703ee58 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -92,6 +92,7 @@ struct media_source struct wg_source *wg_source; struct wg_parser *wg_parser; + UINT64 file_size; UINT64 duration; IMFStreamDescriptor **descriptors; @@ -1248,6 +1249,8 @@ static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource * hr = MF_E_SHUTDOWN; else if (SUCCEEDED(hr = MFCreatePresentationDescriptor(source->stream_count, source->descriptors, descriptor))) { + if (FAILED(hr = IMFPresentationDescriptor_SetUINT64(*descriptor, &MF_PD_TOTAL_FILE_SIZE, source->file_size))) + WARN("Failed to set presentation descriptor MF_PD_TOTAL_FILE_SIZE, hr %#lx\n", hr); if (FAILED(hr = IMFPresentationDescriptor_SetUINT64(*descriptor, &MF_PD_DURATION, source->duration))) WARN("Failed to set presentation descriptor MF_PD_DURATION, hr %#lx\n", hr); @@ -1473,6 +1476,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d IMFByteStream_AddRef(bytestream); object->byte_stream = bytestream; object->wg_source = wg_source; + object->file_size = file_size; object->rate = 1.0f; InitializeCriticalSection(&object->cs); object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs"); From 3e3566b359de898e4d6a719b34dcc5a3d064540e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 29 Apr 2023 16:44:32 +0200 Subject: [PATCH 1988/2777] winegstreamer: Read stream data and provide samples to wg_source. CW-Bug-Id: #21953 --- dlls/winegstreamer/gst_private.h | 3 ++- dlls/winegstreamer/main.c | 10 +++++++--- dlls/winegstreamer/media_source.c | 23 +++++++++++++++++------ dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_source.c | 1 + 5 files changed, 28 insertions(+), 10 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 5661d9e3717..a0ced0b4035 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -109,7 +109,8 @@ HRESULT wg_transform_drain(struct wg_transform *transform, BOOL flush); struct wg_source *wg_source_create(const WCHAR *url, uint64_t file_size, const void *data, uint32_t size); void wg_source_destroy(struct wg_source *source); -bool wg_source_get_status(struct wg_source *source, uint32_t *stream_count); +bool wg_source_get_status(struct wg_source *source, uint32_t *stream_count, + uint64_t *read_offset); HRESULT wg_source_push_data(struct wg_source *source, const void *data, uint32_t size); unsigned int wg_format_get_max_size(const struct wg_format *format); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index d5fe2455932..69b8361361a 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -459,7 +459,8 @@ void wg_source_destroy(struct wg_source *source) WINE_UNIX_CALL(unix_wg_source_destroy, source); } -bool wg_source_get_status(struct wg_source *source, uint32_t *stream_count) +bool wg_source_get_status(struct wg_source *source, uint32_t *stream_count, + uint64_t *read_offset) { struct wg_source_get_status_params params = { @@ -467,14 +468,17 @@ bool wg_source_get_status(struct wg_source *source, uint32_t *stream_count) }; NTSTATUS status; - TRACE("source %p, stream_count %p\n", source, stream_count); + TRACE("source %p, stream_count %p, read_offset %p\n", + source, stream_count, read_offset); if ((status = WINE_UNIX_CALL(unix_wg_source_get_status, ¶ms)) && status != STATUS_PENDING) return false; *stream_count = params.stream_count; - TRACE("source %p, stream_count %u\n", source, *stream_count); + *read_offset = params.read_offset; + TRACE("source %p, stream_count %u, read_offset %#I64x\n", + source, *stream_count, *read_offset); return true; } diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index b013703ee58..4bc260b1f75 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1429,12 +1429,12 @@ static void media_source_init_descriptors(struct media_source *source) HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *data, UINT64 size, IMFMediaSource **out) { + UINT64 next_offset, file_size; UINT32 stream_count; struct media_source *object; struct wg_source *wg_source; struct wg_parser *parser; - DWORD bytestream_caps; - uint64_t file_size; + DWORD bytestream_caps, read_size = size; unsigned int i; HRESULT hr; @@ -1456,10 +1456,21 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d if (!(wg_source = wg_source_create(url, file_size, data, size))) return MF_E_UNSUPPORTED_FORMAT; - if (FAILED(hr = wg_source_push_data(wg_source, data, size))) - WARN("Failed to push initial data, hr %#lx\n", hr); - if (wg_source_get_status(wg_source, &stream_count)) - TRACE("Found %u streams\n", stream_count); + while (SUCCEEDED(hr) && SUCCEEDED(hr = wg_source_push_data(wg_source, data, read_size)) + && wg_source_get_status(wg_source, &stream_count, &next_offset) + && !stream_count && (read_size = min(file_size - min(file_size, next_offset), size))) + { + if (FAILED(hr = IMFByteStream_SetCurrentPosition(bytestream, next_offset))) + WARN("Failed to seek stream to %#I64x, hr %#lx\n", next_offset, hr); + else if (FAILED(hr = IMFByteStream_Read(bytestream, data, read_size, &read_size))) + WARN("Failed to read %#lx bytes from stream, hr %#lx\n", read_size, hr); + } + + if (!stream_count) + { + wg_source_destroy(wg_source); + return MF_E_UNSUPPORTED_FORMAT; + } if (!(object = calloc(1, sizeof(*object)))) { diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 1e30b9a991a..be9fe19911d 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -349,6 +349,7 @@ struct wg_source_get_status_params { struct wg_source *source; UINT32 stream_count; + UINT64 read_offset; }; struct wg_source_push_data_params diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 7ad30bd5429..e444eeff7a3 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -426,6 +426,7 @@ NTSTATUS wg_source_get_status(void *args) } params->stream_count = stream_count; + params->read_offset = source->segment.start; return STATUS_SUCCESS; } From d4ec6c6d4a012b157fc5e5e032b0f6ca1041697c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 26 Apr 2023 18:49:44 +0200 Subject: [PATCH 1989/2777] winegstreamer: Query the stream max duration from the wg_source. CW-Bug-Id: #21953 --- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 11 ++++++----- dlls/winegstreamer/media_source.c | 6 +++--- dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_source.c | 1 + 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index a0ced0b4035..483ce1cf994 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -110,7 +110,7 @@ HRESULT wg_transform_drain(struct wg_transform *transform, BOOL flush); struct wg_source *wg_source_create(const WCHAR *url, uint64_t file_size, const void *data, uint32_t size); void wg_source_destroy(struct wg_source *source); bool wg_source_get_status(struct wg_source *source, uint32_t *stream_count, - uint64_t *read_offset); + uint64_t *duration, uint64_t *read_offset); HRESULT wg_source_push_data(struct wg_source *source, const void *data, uint32_t size); unsigned int wg_format_get_max_size(const struct wg_format *format); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 69b8361361a..94d765bfde7 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -460,7 +460,7 @@ void wg_source_destroy(struct wg_source *source) } bool wg_source_get_status(struct wg_source *source, uint32_t *stream_count, - uint64_t *read_offset) + uint64_t *duration, uint64_t *read_offset) { struct wg_source_get_status_params params = { @@ -468,17 +468,18 @@ bool wg_source_get_status(struct wg_source *source, uint32_t *stream_count, }; NTSTATUS status; - TRACE("source %p, stream_count %p, read_offset %p\n", - source, stream_count, read_offset); + TRACE("source %p, stream_count %p, duration %p, read_offset %p\n", + source, stream_count, duration, read_offset); if ((status = WINE_UNIX_CALL(unix_wg_source_get_status, ¶ms)) && status != STATUS_PENDING) return false; *stream_count = params.stream_count; + *duration = params.duration; *read_offset = params.read_offset; - TRACE("source %p, stream_count %u, read_offset %#I64x\n", - source, *stream_count, *read_offset); + TRACE("source %p, stream_count %u, duration %s, read_offset %#I64x\n", + source, *stream_count, debugstr_time(*duration), *read_offset); return true; } diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 4bc260b1f75..65424150ee7 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1429,7 +1429,7 @@ static void media_source_init_descriptors(struct media_source *source) HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *data, UINT64 size, IMFMediaSource **out) { - UINT64 next_offset, file_size; + UINT64 duration, next_offset, file_size; UINT32 stream_count; struct media_source *object; struct wg_source *wg_source; @@ -1457,7 +1457,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d return MF_E_UNSUPPORTED_FORMAT; while (SUCCEEDED(hr) && SUCCEEDED(hr = wg_source_push_data(wg_source, data, read_size)) - && wg_source_get_status(wg_source, &stream_count, &next_offset) + && wg_source_get_status(wg_source, &stream_count, &duration, &next_offset) && !stream_count && (read_size = min(file_size - min(file_size, next_offset), size))) { if (FAILED(hr = IMFByteStream_SetCurrentPosition(bytestream, next_offset))) @@ -1488,6 +1488,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d object->byte_stream = bytestream; object->wg_source = wg_source; object->file_size = file_size; + object->duration = duration; object->rate = 1.0f; InitializeCriticalSection(&object->cs); object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs"); @@ -1538,7 +1539,6 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d goto fail; } - object->duration = max(object->duration, wg_parser_stream_get_duration(wg_stream)); IMFStreamDescriptor_AddRef(descriptor); object->descriptors[i] = descriptor; object->streams[i] = stream; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index be9fe19911d..9e8d91b3316 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -349,6 +349,7 @@ struct wg_source_get_status_params { struct wg_source *source; UINT32 stream_count; + UINT64 duration; UINT64 read_offset; }; diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index e444eeff7a3..570c2f19c72 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -426,6 +426,7 @@ NTSTATUS wg_source_get_status(void *args) } params->stream_count = stream_count; + params->duration = source->max_duration / 100; params->read_offset = source->segment.start; return STATUS_SUCCESS; } From a28ab7853c3aa80d3ab1c5a68b6e37314e5914af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 26 Apr 2023 18:05:14 +0200 Subject: [PATCH 1990/2777] winegstreamer: Set the MF_PD_MIME_TYPE presentation descriptor attribute. CW-Bug-Id: #21953 --- dlls/winegstreamer/gst_private.h | 3 ++- dlls/winegstreamer/main.c | 9 ++++++--- dlls/winegstreamer/media_source.c | 7 ++++++- dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_source.c | 9 +++++++++ 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 483ce1cf994..394cb821e58 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -107,7 +107,8 @@ bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_fo bool wg_transform_get_status(struct wg_transform *transform, bool *accepts_input); HRESULT wg_transform_drain(struct wg_transform *transform, BOOL flush); -struct wg_source *wg_source_create(const WCHAR *url, uint64_t file_size, const void *data, uint32_t size); +struct wg_source *wg_source_create(const WCHAR *url, uint64_t file_size, + const void *data, uint32_t size, WCHAR mime_type[256]); void wg_source_destroy(struct wg_source *source); bool wg_source_get_status(struct wg_source *source, uint32_t *stream_count, uint64_t *duration, uint64_t *read_offset); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 94d765bfde7..a4020746e20 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -429,7 +429,7 @@ HRESULT wg_transform_drain(struct wg_transform *transform, BOOL flush) } struct wg_source *wg_source_create(const WCHAR *url, uint64_t file_size, - const void *data, uint32_t size) + const void *data, uint32_t size, WCHAR mime_type[256]) { struct wg_source_create_params params = { @@ -439,14 +439,17 @@ struct wg_source *wg_source_create(const WCHAR *url, uint64_t file_size, UINT len = url ? WideCharToMultiByte(CP_ACP, 0, url, -1, NULL, 0, NULL, NULL) : 0; char *tmp = url ? malloc(len) : NULL; - TRACE("url %s, file_size %#I64x, data %p, size %#x\n", debugstr_w(url), - file_size, data, size); + TRACE("url %s, file_size %#I64x, data %p, size %#x, mime_type %p\n", debugstr_w(url), + file_size, data, size, mime_type); if ((params.url = tmp)) WideCharToMultiByte(CP_ACP, 0, url, -1, tmp, len, NULL, NULL); if (!WINE_UNIX_CALL(unix_wg_source_create, ¶ms)) + { + MultiByteToWideChar(CP_ACP, 0, params.mime_type, -1, mime_type, 256); TRACE("Returning source %p.\n", params.source); + } free(tmp); return params.source; diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 65424150ee7..e77033c5cb7 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -92,6 +92,7 @@ struct media_source struct wg_source *wg_source; struct wg_parser *wg_parser; + WCHAR mime_type[256]; UINT64 file_size; UINT64 duration; @@ -1249,6 +1250,8 @@ static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource * hr = MF_E_SHUTDOWN; else if (SUCCEEDED(hr = MFCreatePresentationDescriptor(source->stream_count, source->descriptors, descriptor))) { + if (FAILED(hr = IMFPresentationDescriptor_SetString(*descriptor, &MF_PD_MIME_TYPE, source->mime_type))) + WARN("Failed to set presentation descriptor MF_PD_MIME_TYPE, hr %#lx\n", hr); if (FAILED(hr = IMFPresentationDescriptor_SetUINT64(*descriptor, &MF_PD_TOTAL_FILE_SIZE, source->file_size))) WARN("Failed to set presentation descriptor MF_PD_TOTAL_FILE_SIZE, hr %#lx\n", hr); if (FAILED(hr = IMFPresentationDescriptor_SetUINT64(*descriptor, &MF_PD_DURATION, source->duration))) @@ -1435,6 +1438,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d struct wg_source *wg_source; struct wg_parser *parser; DWORD bytestream_caps, read_size = size; + WCHAR mime_type[256]; unsigned int i; HRESULT hr; @@ -1453,7 +1457,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d return hr; } - if (!(wg_source = wg_source_create(url, file_size, data, size))) + if (!(wg_source = wg_source_create(url, file_size, data, size, mime_type))) return MF_E_UNSUPPORTED_FORMAT; while (SUCCEEDED(hr) && SUCCEEDED(hr = wg_source_push_data(wg_source, data, read_size)) @@ -1487,6 +1491,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d IMFByteStream_AddRef(bytestream); object->byte_stream = bytestream; object->wg_source = wg_source; + wcscpy(object->mime_type, mime_type); object->file_size = file_size; object->duration = duration; object->rate = 1.0f; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 9e8d91b3316..c685529562d 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -342,6 +342,7 @@ struct wg_source_create_params UINT64 file_size; const void *data; UINT32 size; + char mime_type[256]; struct wg_source *source; }; diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 570c2f19c72..928f0bdb074 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -303,6 +303,7 @@ NTSTATUS wg_source_create(void *args) GstElement *first = NULL, *last = NULL, *element; GstCaps *src_caps, *any_caps; struct wg_source *source; + const gchar *media_type; GstEvent *event; GstPad *peer; guint i; @@ -317,6 +318,14 @@ NTSTATUS wg_source_create(void *args) gst_segment_init(&source->segment, GST_FORMAT_BYTES); source->segment.stop = params->file_size; + media_type = gst_structure_get_name(gst_caps_get_structure(src_caps, 0)); + if (!strcmp(media_type, "video/quicktime")) + strcpy(params->mime_type, "video/mp4"); + else if (!strcmp(media_type, "video/x-msvideo")) + strcpy(params->mime_type, "video/avi"); + else + lstrcpynA(params->mime_type, media_type, ARRAY_SIZE(params->mime_type)); + if (!(source->container = gst_bin_new("wg_source"))) goto error; if (!(source->src_pad = create_pad_with_caps(GST_PAD_SRC, src_caps))) From 7ea898f89acd7f413c571de92e9c53cb129d34cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 29 Apr 2023 18:35:22 +0200 Subject: [PATCH 1991/2777] winegstreamer: Handle GST_EVENT_TAG and udpate wg_source streams tags. CW-Bug-Id: #21953 --- dlls/winegstreamer/wg_source.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 928f0bdb074..ab588bd5016 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -211,6 +211,31 @@ static gboolean sink_event_caps(struct wg_source *source, GstPad *pad, GstEvent return !!stream; } +static gboolean sink_event_tag(struct wg_source *source, GstPad *pad, GstEvent *event) +{ + GstTagList *new_tags; + GstStream *stream; + + gst_event_parse_tag(event, &new_tags); + GST_TRACE("source %p, pad %p, new_tags %p", source, pad, new_tags); + + if ((stream = gst_pad_get_stream(pad))) + { + GstTagList *old_tags = gst_stream_get_tags(stream); + if ((new_tags = gst_tag_list_merge(old_tags, new_tags, GST_TAG_MERGE_REPLACE))) + { + gst_stream_set_tags(stream, new_tags); + gst_tag_list_unref(new_tags); + } + if (old_tags) + gst_tag_list_unref(old_tags); + gst_object_unref(stream); + } + + gst_event_unref(event); + return stream && new_tags; +} + static gboolean sink_event_stream_start(struct wg_source *source, GstPad *pad, GstEvent *event) { guint group, flags; @@ -241,6 +266,8 @@ static gboolean sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) { case GST_EVENT_CAPS: return sink_event_caps(source, pad, event); + case GST_EVENT_TAG: + return sink_event_tag(source, pad, event); case GST_EVENT_STREAM_START: return sink_event_stream_start(source, pad, event); default: From 4a438875a8612949e8b4e96da1a0b17ce284051c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 29 Apr 2023 19:09:23 +0200 Subject: [PATCH 1992/2777] winegstreamer: Sort media source "video/mp4" streams by stream type. CW-Bug-Id: #21953 --- dlls/winegstreamer/gst_private.h | 2 ++ dlls/winegstreamer/main.c | 19 ++++++++++++ dlls/winegstreamer/media_source.c | 50 +++++++++++++++++++++++++++++-- dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 8 +++++ dlls/winegstreamer/wg_parser.c | 1 + dlls/winegstreamer/wg_source.c | 18 +++++++++++ 7 files changed, 97 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 394cb821e58..b6c94cb7f52 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -113,6 +113,8 @@ void wg_source_destroy(struct wg_source *source); bool wg_source_get_status(struct wg_source *source, uint32_t *stream_count, uint64_t *duration, uint64_t *read_offset); HRESULT wg_source_push_data(struct wg_source *source, const void *data, uint32_t size); +bool wg_source_get_stream_format(struct wg_source *source, UINT32 index, + struct wg_format *format); unsigned int wg_format_get_max_size(const struct wg_format *format); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index a4020746e20..bb7bcb414fe 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -498,6 +498,25 @@ HRESULT wg_source_push_data(struct wg_source *source, const void *data, uint32_t return HRESULT_FROM_NT(WINE_UNIX_CALL(unix_wg_source_push_data, ¶ms)); } +bool wg_source_get_stream_format(struct wg_source *source, UINT32 index, + struct wg_format *format) +{ + struct wg_source_get_stream_format_params params = + { + .source = source, + .index = index, + }; + + TRACE("source %p, index %u, format %p\n", source, + index, format); + + if (WINE_UNIX_CALL(unix_wg_source_get_stream_format, ¶ms)) + return false; + + *format = params.format; + return true; +} + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { if (reason == DLL_PROCESS_ATTACH) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index e77033c5cb7..4ee7250cb3a 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -99,6 +99,7 @@ struct media_source IMFStreamDescriptor **descriptors; struct media_stream **streams; ULONG stream_count; + UINT *stream_map; enum { @@ -1384,6 +1385,7 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) IMFMediaEventQueue_Shutdown(stream->event_queue); IMFMediaStream_Release(&stream->IMFMediaStream_iface); } + free(source->stream_map); free(source->descriptors); free(source->streams); @@ -1411,6 +1413,46 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = media_source_Shutdown, }; +static void media_source_init_stream_map(struct media_source *source, UINT stream_count) +{ + struct wg_format format; + int i, n = 0; + + if (wcscmp(source->mime_type, L"video/mp4")) + { + for (i = stream_count - 1; i >= 0; i--) + { + TRACE("mapping stream %u to wg_source stream %u\n", i, i); + source->stream_map[i] = i; + } + return; + } + + for (i = stream_count - 1; i >= 0; i--) + { + wg_source_get_stream_format(source->wg_source, i, &format); + if (format.major_type == WG_MAJOR_TYPE_UNKNOWN) continue; + if (format.major_type >= WG_MAJOR_TYPE_VIDEO) continue; + TRACE("mapping stream %u to wg_source stream %u\n", n, i); + source->stream_map[n++] = i; + } + for (i = stream_count - 1; i >= 0; i--) + { + wg_source_get_stream_format(source->wg_source, i, &format); + if (format.major_type == WG_MAJOR_TYPE_UNKNOWN) continue; + if (format.major_type < WG_MAJOR_TYPE_VIDEO) continue; + TRACE("mapping stream %u to wg_source stream %u\n", n, i); + source->stream_map[n++] = i; + } + for (i = stream_count - 1; i >= 0; i--) + { + wg_source_get_stream_format(source->wg_source, i, &format); + if (format.major_type != WG_MAJOR_TYPE_UNKNOWN) continue; + TRACE("mapping stream %u to wg_source stream %u\n", n, i); + source->stream_map[n++] = i; + } +} + static void media_source_init_descriptors(struct media_source *source) { HRESULT hr = S_OK; @@ -1518,16 +1560,19 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d if (FAILED(hr = wg_parser_connect(parser, file_size, NULL))) goto fail; - stream_count = wg_parser_get_stream_count(parser); - if (!(object->descriptors = calloc(stream_count, sizeof(*object->descriptors))) + || !(object->stream_map = calloc(stream_count, sizeof(*object->stream_map))) || !(object->streams = calloc(stream_count, sizeof(*object->streams)))) { + free(object->stream_map); free(object->descriptors); hr = E_OUTOFMEMORY; goto fail; } + media_source_init_stream_map(object, stream_count); + + stream_count = wg_parser_get_stream_count(parser); for (i = 0; i < stream_count; ++i) { struct wg_parser_stream *wg_stream = wg_parser_get_stream(parser, i); @@ -1565,6 +1610,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d IMFStreamDescriptor_Release(object->descriptors[object->stream_count]); IMFMediaStream_Release(&stream->IMFMediaStream_iface); } + free(object->stream_map); free(object->descriptors); free(object->streams); diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 774df66c247..293c9c407de 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -69,6 +69,7 @@ extern NTSTATUS wg_source_create(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_source_destroy(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_source_get_status(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_source_push_data(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_source_get_stream_format(void *args) DECLSPEC_HIDDEN; /* wg_allocator.c */ diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index c685529562d..7979beaeedb 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -361,6 +361,13 @@ struct wg_source_push_data_params UINT32 size; }; +struct wg_source_get_stream_format_params +{ + struct wg_source *source; + UINT32 index; + struct wg_format format; +}; + enum unix_funcs { unix_wg_init_gstreamer, @@ -403,6 +410,7 @@ enum unix_funcs unix_wg_source_destroy, unix_wg_source_get_status, unix_wg_source_push_data, + unix_wg_source_get_stream_format, }; #endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index b3d0e6d2716..105b25006fb 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1921,4 +1921,5 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_source_destroy), X(wg_source_get_status), X(wg_source_push_data), + X(wg_source_get_stream_format), }; diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index ab588bd5016..8b51d8c54cd 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -508,3 +508,21 @@ NTSTATUS wg_source_push_data(void *args) return STATUS_SUCCESS; } + +NTSTATUS wg_source_get_stream_format(void *args) +{ + struct wg_source_get_stream_format_params *params = args; + struct wg_source *source = params->source; + guint index = params->index; + GstCaps *caps; + + GST_TRACE("source %p, index %u", source, index); + + if (!(caps = source_get_stream_caps(source, index))) + return STATUS_UNSUCCESSFUL; + wg_format_from_caps(¶ms->format, caps); + + gst_caps_unref(caps); + return STATUS_SUCCESS; +} + From e3c9763c86955af9955154a7e8c9753b0b575e47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 May 2023 10:14:04 +0200 Subject: [PATCH 1993/2777] winegstreamer: Initialize media source presentation from wg_source. CW-Bug-Id: #21953 --- dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/main.c | 27 +++++++ dlls/winegstreamer/media_source.c | 114 +++++++++++++++++++++++------- dlls/winegstreamer/unix_private.h | 6 ++ dlls/winegstreamer/unixlib.c | 50 +++++++++++++ dlls/winegstreamer/unixlib.h | 10 +++ dlls/winegstreamer/wg_parser.c | 1 + dlls/winegstreamer/wg_source.c | 70 ++++++++++++++++++ 8 files changed, 254 insertions(+), 26 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index b6c94cb7f52..b31feddd5ef 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -115,6 +115,8 @@ bool wg_source_get_status(struct wg_source *source, uint32_t *stream_count, HRESULT wg_source_push_data(struct wg_source *source, const void *data, uint32_t size); bool wg_source_get_stream_format(struct wg_source *source, UINT32 index, struct wg_format *format); +char *wg_source_get_stream_tag(struct wg_source *source, UINT32 index, + enum wg_parser_tag tag); unsigned int wg_format_get_max_size(const struct wg_format *format); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index bb7bcb414fe..6175fc94a01 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -517,6 +517,33 @@ bool wg_source_get_stream_format(struct wg_source *source, UINT32 index, return true; } +char *wg_source_get_stream_tag(struct wg_source *source, UINT32 index, enum wg_parser_tag tag) +{ + struct wg_source_get_stream_tag_params params = + { + .source = source, + .index = index, + .tag = tag, + }; + char *buffer; + + if (WINE_UNIX_CALL(unix_wg_source_get_stream_tag, ¶ms) != STATUS_BUFFER_TOO_SMALL) + return NULL; + if (!(buffer = malloc(params.size))) + { + ERR("No memory.\n"); + return NULL; + } + params.buffer = buffer; + if (WINE_UNIX_CALL(unix_wg_source_get_stream_tag, ¶ms)) + { + ERR("wg_source_get_stream_tag failed unexpectedly.\n"); + free(buffer); + return NULL; + } + return buffer; +} + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { if (reason == DLL_PROCESS_ATTACH) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 4ee7250cb3a..e2a53247588 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -36,8 +36,6 @@ struct media_stream IMFMediaEventQueue *event_queue; IMFStreamDescriptor *descriptor; - struct wg_parser_stream *wg_stream; - IUnknown **token_queue; LONG token_queue_count; LONG token_queue_cap; @@ -304,15 +302,15 @@ static HRESULT stream_descriptor_create(UINT32 id, struct wg_format *format, IMF return hr; } -static HRESULT stream_descriptor_set_tag(IMFStreamDescriptor *descriptor, struct wg_parser_stream *stream, - const GUID *attr, enum wg_parser_tag tag) +static HRESULT stream_descriptor_set_tag(IMFStreamDescriptor *descriptor, + struct wg_source *source, UINT index, const GUID *attr, enum wg_parser_tag tag) { WCHAR *strW; HRESULT hr; DWORD len; char *str; - if (!(str = wg_parser_stream_get_tag(stream, tag)) + if (!(str = wg_source_get_stream_tag(source, index, tag)) || !(len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0))) hr = S_OK; else if (!(strW = malloc(len * sizeof(*strW)))) @@ -330,6 +328,49 @@ static HRESULT stream_descriptor_set_tag(IMFStreamDescriptor *descriptor, struct return hr; } +static HRESULT map_stream_to_wg_parser_stream(struct media_source *source, UINT stream) +{ + struct wg_parser_stream *wg_stream; + struct wg_format stream_format; + HRESULT hr; + UINT i; + + if (!(wg_stream = wg_parser_get_stream(source->wg_parser, stream))) + return E_FAIL; + wg_parser_stream_get_preferred_format(wg_stream, &stream_format); + + for (i = 0; i < source->stream_count; i++) + { + struct wg_format format; + + if (FAILED(hr = wg_format_from_stream_descriptor(source->descriptors[i], &format))) + return hr; + if (stream_format.major_type != format.major_type) + continue; + if (source->stream_map[i]) + continue; + + TRACE("Mapped stream %u with descriptor %u\n", stream, i); + source->stream_map[i] = stream + 1; + return S_OK; + } + + return E_FAIL; +} + +static HRESULT media_stream_get_wg_parser_stream(struct media_stream *stream, struct wg_parser_stream **wg_stream) +{ + struct media_source *source = impl_from_IMFMediaSource(stream->media_source); + HRESULT hr; + DWORD id; + + if (FAILED(hr = IMFStreamDescriptor_GetStreamIdentifier(stream->descriptor, &id))) + return hr; + if (!(id = source->stream_map[id]) || !(*wg_stream = wg_parser_get_stream(source->wg_parser, id - 1))) + return MF_E_INVALIDSTREAMNUMBER; + return S_OK; +} + static BOOL enqueue_token(struct media_stream *stream, IUnknown *token) { if (stream->token_queue_count == stream->token_queue_cap) @@ -385,14 +426,17 @@ static void flush_token_queue(struct media_stream *stream, BOOL send) static HRESULT media_stream_start(struct media_stream *stream, BOOL active, BOOL seeking, const PROPVARIANT *position) { struct media_source *source = impl_from_IMFMediaSource(stream->media_source); + struct wg_parser_stream *wg_stream; struct wg_format format; HRESULT hr; TRACE("source %p, stream %p\n", source, stream); + if (FAILED(hr = media_stream_get_wg_parser_stream(stream, &wg_stream))) + return hr; if (FAILED(hr = wg_format_from_stream_descriptor(stream->descriptor, &format))) WARN("Failed to get wg_format from stream descriptor, hr %#lx\n", hr); - wg_parser_stream_enable(stream->wg_stream, &format, 0); + wg_parser_stream_enable(wg_stream, &format, 0); if (FAILED(hr = IMFMediaEventQueue_QueueEventParamUnk(source->event_queue, active ? MEUpdatedStream : MENewStream, &GUID_NULL, S_OK, (IUnknown *)&stream->IMFMediaStream_iface))) @@ -447,12 +491,17 @@ static HRESULT media_source_start(struct media_source *source, IMFPresentationDe { struct media_stream *stream = source->streams[i]; BOOL was_active = !starting && stream->active; + struct wg_parser_stream *wg_stream; if (position->vt != VT_EMPTY) stream->eos = FALSE; if (!(stream->active = !!descriptors[i])) - wg_parser_stream_disable(stream->wg_stream); + { + if (FAILED(hr = media_stream_get_wg_parser_stream(stream, &wg_stream))) + return hr; + wg_parser_stream_disable(wg_stream); + } else { if (FAILED(hr = media_stream_start(stream, was_active, seek_message, position))) @@ -466,8 +515,11 @@ static HRESULT media_source_start(struct media_source *source, IMFPresentationDe source->state = SOURCE_RUNNING; if (position->vt == VT_I8) - wg_parser_stream_seek(source->streams[0]->wg_stream, 1.0, position->hVal.QuadPart, 0, + { + struct wg_parser_stream *wg_stream = wg_parser_get_stream(source->wg_parser, 0); + wg_parser_stream_seek(wg_stream, 1.0, position->hVal.QuadPart, 0, AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning); + } for (i = 0; i < source->stream_count; i++) flush_token_queue(source->streams[i], position->vt == VT_EMPTY); @@ -524,7 +576,8 @@ static HRESULT media_source_stop(struct media_source *source) return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceStopped, &GUID_NULL, S_OK, NULL); } -static HRESULT media_stream_send_sample(struct media_stream *stream, const struct wg_parser_buffer *wg_buffer, IUnknown *token) +static HRESULT media_stream_send_sample(struct media_stream *stream, struct wg_parser_stream *wg_stream, + const struct wg_parser_buffer *wg_buffer, IUnknown *token) { IMFSample *sample = NULL; IMFMediaBuffer *buffer; @@ -538,13 +591,13 @@ static HRESULT media_stream_send_sample(struct media_stream *stream, const struc if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL))) goto out; - if (!wg_parser_stream_copy_buffer(stream->wg_stream, data, 0, wg_buffer->size)) + if (!wg_parser_stream_copy_buffer(wg_stream, data, 0, wg_buffer->size)) { - wg_parser_stream_release_buffer(stream->wg_stream); + wg_parser_stream_release_buffer(wg_stream); IMFMediaBuffer_Unlock(buffer); goto out; } - wg_parser_stream_release_buffer(stream->wg_stream); + wg_parser_stream_release_buffer(wg_stream); if (FAILED(hr = IMFMediaBuffer_Unlock(buffer))) goto out; @@ -597,12 +650,16 @@ static HRESULT media_stream_send_eos(struct media_source *source, struct media_s static HRESULT wait_on_sample(struct media_stream *stream, IUnknown *token) { struct media_source *source = impl_from_IMFMediaSource(stream->media_source); + struct wg_parser_stream *wg_stream; struct wg_parser_buffer buffer; + HRESULT hr; TRACE("%p, %p\n", stream, token); - if (wg_parser_stream_get_buffer(source->wg_parser, stream->wg_stream, &buffer)) - return media_stream_send_sample(stream, &buffer, token); + if (FAILED(hr = media_stream_get_wg_parser_stream(stream, &wg_stream))) + return hr; + if (wg_parser_stream_get_buffer(source->wg_parser, wg_stream, &buffer)) + return media_stream_send_sample(stream, wg_stream, &buffer, token); return media_stream_send_eos(source, stream); } @@ -910,13 +967,13 @@ static const IMFMediaStreamVtbl media_stream_vtbl = media_stream_RequestSample }; -static HRESULT media_stream_create(IMFMediaSource *source, struct wg_parser_stream *wg_stream, - IMFStreamDescriptor *descriptor, struct media_stream **out) +static HRESULT media_stream_create(IMFMediaSource *source, IMFStreamDescriptor *descriptor, + struct media_stream **out) { struct media_stream *object; HRESULT hr; - TRACE("source %p, wg_stream %p.\n", source, wg_stream); + TRACE("source %p, descriptor %p.\n", source, descriptor); if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; @@ -937,7 +994,6 @@ static HRESULT media_stream_create(IMFMediaSource *source, struct wg_parser_stre object->active = TRUE; object->eos = FALSE; - object->wg_stream = wg_stream; TRACE("Created stream object %p.\n", object); @@ -1455,21 +1511,28 @@ static void media_source_init_stream_map(struct media_source *source, UINT strea static void media_source_init_descriptors(struct media_source *source) { - HRESULT hr = S_OK; + HRESULT hr; UINT i; for (i = 0; i < source->stream_count; i++) { - struct media_stream *stream = source->streams[i]; - IMFStreamDescriptor *descriptor = stream->descriptor; + IMFStreamDescriptor *descriptor = source->descriptors[i]; - if (FAILED(hr = stream_descriptor_set_tag(descriptor, stream->wg_stream, + if (FAILED(hr = stream_descriptor_set_tag(descriptor, source->wg_source, source->stream_map[i], &MF_SD_LANGUAGE, WG_PARSER_TAG_LANGUAGE))) WARN("Failed to set stream descriptor language, hr %#lx\n", hr); - if (FAILED(hr = stream_descriptor_set_tag(descriptor, stream->wg_stream, + if (FAILED(hr = stream_descriptor_set_tag(descriptor, source->wg_source, source->stream_map[i], &MF_SD_STREAM_NAME, WG_PARSER_TAG_NAME))) WARN("Failed to set stream descriptor name, hr %#lx\n", hr); } + + /* reset the stream map to map wg_stream numbers instead */ + memset(source->stream_map, 0, source->stream_count * sizeof(*source->stream_map)); + for (i = 0; i < source->stream_count; i++) + { + if (FAILED(hr = map_stream_to_wg_parser_stream(source, i))) + WARN("Failed to map stream descriptor %u, hr %#lx\n", i, hr); + } } HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *data, UINT64 size, IMFMediaSource **out) @@ -1575,15 +1638,14 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d stream_count = wg_parser_get_stream_count(parser); for (i = 0; i < stream_count; ++i) { - struct wg_parser_stream *wg_stream = wg_parser_get_stream(parser, i); IMFStreamDescriptor *descriptor; struct media_stream *stream; struct wg_format format; - wg_parser_stream_get_preferred_format(wg_stream, &format); + wg_source_get_stream_format(wg_source, object->stream_map[i], &format); if (FAILED(hr = stream_descriptor_create(i, &format, &descriptor))) goto fail; - if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, wg_stream, descriptor, &stream))) + if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, descriptor, &stream))) { IMFStreamDescriptor_Release(descriptor); goto fail; diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 293c9c407de..d74e1fdf11c 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -46,6 +46,8 @@ extern bool link_element_to_sink(GstElement *element, GstPad *sink_pad) DECLSPEC extern GstCaps *detect_caps_from_data(const char *url, const void *data, guint size) DECLSPEC_HIDDEN; extern GstPad *create_pad_with_caps(GstPadDirection direction, GstCaps *caps) DECLSPEC_HIDDEN; extern GstBuffer *create_buffer_from_bytes(const void *data, guint size) DECLSPEC_HIDDEN; +extern gchar *stream_lang_from_tags(GstTagList *tags, GstCaps *caps) DECLSPEC_HIDDEN; +extern gchar *stream_name_from_tags(GstTagList *tags) DECLSPEC_HIDDEN; /* wg_format.c */ @@ -53,6 +55,9 @@ extern void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) D extern bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) DECLSPEC_HIDDEN; extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN; +extern gchar *wg_stream_lang_from_tags(GstTagList *tags, GstCaps *caps) DECLSPEC_HIDDEN; +extern gchar *wg_stream_name_from_tags(GstTagList *tags) DECLSPEC_HIDDEN; + /* wg_transform.c */ extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; @@ -70,6 +75,7 @@ extern NTSTATUS wg_source_destroy(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_source_get_status(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_source_push_data(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_source_get_stream_format(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_source_get_stream_tag(void *args) DECLSPEC_HIDDEN; /* wg_allocator.c */ diff --git a/dlls/winegstreamer/unixlib.c b/dlls/winegstreamer/unixlib.c index 618897f0632..77f8dda0928 100644 --- a/dlls/winegstreamer/unixlib.c +++ b/dlls/winegstreamer/unixlib.c @@ -253,6 +253,56 @@ GstBuffer *create_buffer_from_bytes(const void *data, guint size) return buffer; } +gchar *stream_lang_from_tags(GstTagList *tags, GstCaps *caps) +{ + gchar *value; + + if (!gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &value) || !value) + return NULL; + + return value; +} + +gchar *stream_name_from_tags(GstTagList *tags) +{ + /* Extract stream name from Quick Time demuxer private tag where it puts unrecognized chunks. */ + guint i, tag_count = gst_tag_list_get_tag_size(tags, "private-qt-tag"); + gchar *value = NULL; + + for (i = 0; !value && i < tag_count; ++i) + { + const gchar *name; + const GValue *val; + GstSample *sample; + GstBuffer *buf; + gsize size; + + if (!(val = gst_tag_list_get_value_index(tags, "private-qt-tag", i))) + continue; + if (!GST_VALUE_HOLDS_SAMPLE(val) || !(sample = gst_value_get_sample(val))) + continue; + name = gst_structure_get_name(gst_sample_get_info(sample)); + if (!name || strcmp(name, "application/x-gst-qt-name-tag")) + continue; + if (!(buf = gst_sample_get_buffer(sample))) + continue; + if ((size = gst_buffer_get_size(buf)) < 8) + continue; + size -= 8; + if (!(value = g_malloc(size + 1))) + return NULL; + if (gst_buffer_extract(buf, 8, value, size) != size) + { + g_free(value); + value = NULL; + continue; + } + value[size] = 0; + } + + return value; +} + NTSTATUS wg_init_gstreamer(void *arg) { static GstGLContext *gl_context; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 7979beaeedb..2fe2a24e03b 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -368,6 +368,15 @@ struct wg_source_get_stream_format_params struct wg_format format; }; +struct wg_source_get_stream_tag_params +{ + struct wg_source *source; + UINT32 index; + enum wg_parser_tag tag; + UINT32 size; + char *buffer; +}; + enum unix_funcs { unix_wg_init_gstreamer, @@ -411,6 +420,7 @@ enum unix_funcs unix_wg_source_get_status, unix_wg_source_push_data, unix_wg_source_get_stream_format, + unix_wg_source_get_stream_tag, }; #endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 105b25006fb..002142a6beb 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1922,4 +1922,5 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_source_get_status), X(wg_source_push_data), X(wg_source_get_stream_format), + X(wg_source_get_stream_tag), }; diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 8b51d8c54cd..274420ffb09 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -69,6 +69,17 @@ static GstCaps *source_get_stream_caps(struct wg_source *source, guint index) return caps; } +static GstTagList *source_get_stream_tags(struct wg_source *source, guint index) +{ + GstStream *stream; + GstTagList *tags; + if (!(stream = source_get_stream(source, index))) + return NULL; + tags = gst_stream_get_tags(stream); + gst_object_unref(stream); + return tags; +} + static gboolean src_event_seek(struct wg_source *source, GstEvent *event) { guint32 seqnum = gst_event_get_seqnum(event); @@ -526,3 +537,62 @@ NTSTATUS wg_source_get_stream_format(void *args) return STATUS_SUCCESS; } +NTSTATUS wg_source_get_stream_tag(void *args) +{ + struct wg_source_get_stream_tag_params *params = args; + struct wg_source *source = params->source; + enum wg_parser_tag tag = params->tag; + guint index = params->index; + GstTagList *tags; + NTSTATUS status; + uint32_t len; + gchar *value; + + GST_TRACE("source %p, index %u, tag %u", source, index, tag); + + if (params->tag >= WG_PARSER_TAG_COUNT) + return STATUS_INVALID_PARAMETER; + if (!(tags = source_get_stream_tags(source, index))) + return STATUS_UNSUCCESSFUL; + + switch (tag) + { + case WG_PARSER_TAG_LANGUAGE: + { + GstCaps *caps = gst_pad_get_current_caps(source->src_pad); + value = stream_lang_from_tags(tags, caps); + if (caps) + gst_caps_unref(caps); + break; + } + case WG_PARSER_TAG_NAME: + value = stream_name_from_tags(tags); + break; + default: + GST_FIXME("Unsupported stream tag %u", tag); + value = NULL; + break; + } + + if (!value) + goto error; + + if ((len = strlen(value) + 1) > params->size) + { + params->size = len; + status = STATUS_BUFFER_TOO_SMALL; + } + else + { + memcpy(params->buffer, value, len); + status = STATUS_SUCCESS; + } + + gst_tag_list_unref(tags); + g_free(value); + return status; + +error: + gst_tag_list_unref(tags); + return STATUS_NOT_FOUND; +} From f2e8d2f8604431f060bab7580f3596431d8e83ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 28 Apr 2023 19:13:44 +0200 Subject: [PATCH 1994/2777] winegstreamer: Set MF_SD_MUTUALLY_EXCLUSIVE stream descriptor attribute. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index e2a53247588..5d07ef30ff7 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1511,12 +1511,36 @@ static void media_source_init_stream_map(struct media_source *source, UINT strea static void media_source_init_descriptors(struct media_source *source) { + UINT i, last_audio = -1, last_video = -1; HRESULT hr; - UINT i; for (i = 0; i < source->stream_count; i++) { IMFStreamDescriptor *descriptor = source->descriptors[i]; + struct wg_format format = {0}; + UINT exclude = -1; + + if (FAILED(hr = wg_format_from_stream_descriptor(descriptor, &format))) + WARN("Failed to get format from stream descriptor, hr %#lx\n", hr); + + if (format.major_type == WG_MAJOR_TYPE_AUDIO) + { + exclude = last_audio; + last_audio = i; + } + else if (format.major_type == WG_MAJOR_TYPE_VIDEO) + { + exclude = last_video; + last_video = i; + } + + if (exclude != -1) + { + if (FAILED(IMFStreamDescriptor_SetUINT32(source->descriptors[exclude], &MF_SD_MUTUALLY_EXCLUSIVE, 1))) + WARN("Failed to set stream %u MF_SD_MUTUALLY_EXCLUSIVE\n", exclude); + else if (FAILED(IMFStreamDescriptor_SetUINT32(descriptor, &MF_SD_MUTUALLY_EXCLUSIVE, 1))) + WARN("Failed to set stream %u MF_SD_MUTUALLY_EXCLUSIVE\n", i); + } if (FAILED(hr = stream_descriptor_set_tag(descriptor, source->wg_source, source->stream_map[i], &MF_SD_LANGUAGE, WG_PARSER_TAG_LANGUAGE))) From e960a00b37e998ddb64d97433c7962c227d9ba63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 29 Apr 2023 14:51:54 +0200 Subject: [PATCH 1995/2777] winegstreamer: Select one stream descriptor for each major type. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 5d07ef30ff7..92cddc3721b 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -992,9 +992,6 @@ static HRESULT media_stream_create(IMFMediaSource *source, IMFStreamDescriptor * IMFStreamDescriptor_AddRef(descriptor); object->descriptor = descriptor; - object->active = TRUE; - object->eos = FALSE; - TRACE("Created stream object %p.\n", object); *out = object; @@ -1511,7 +1508,7 @@ static void media_source_init_stream_map(struct media_source *source, UINT strea static void media_source_init_descriptors(struct media_source *source) { - UINT i, last_audio = -1, last_video = -1; + UINT i, last_audio = -1, last_video = -1, first_audio = -1, first_video = -1; HRESULT hr; for (i = 0; i < source->stream_count; i++) @@ -1525,11 +1522,15 @@ static void media_source_init_descriptors(struct media_source *source) if (format.major_type == WG_MAJOR_TYPE_AUDIO) { + if (first_audio == -1) + first_audio = i; exclude = last_audio; last_audio = i; } else if (format.major_type == WG_MAJOR_TYPE_VIDEO) { + if (first_video == -1) + first_video = i; exclude = last_video; last_video = i; } @@ -1557,6 +1558,21 @@ static void media_source_init_descriptors(struct media_source *source) if (FAILED(hr = map_stream_to_wg_parser_stream(source, i))) WARN("Failed to map stream descriptor %u, hr %#lx\n", i, hr); } + + if (!wcscmp(source->mime_type, L"video/mp4")) + { + if (last_audio != -1) + source->streams[last_audio]->active = TRUE; + if (last_video != -1) + source->streams[last_video]->active = TRUE; + } + else + { + if (first_audio != -1) + source->streams[first_audio]->active = TRUE; + if (first_video != -1) + source->streams[first_video]->active = TRUE; + } } HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *data, UINT64 size, IMFMediaSource **out) From 24b84e4175244ae428e9dd0e3760144dfd03ce48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 29 Apr 2023 19:15:31 +0200 Subject: [PATCH 1996/2777] winegstreamer: Use 1-based ids in media source stream descriptors. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 92cddc3721b..9e3dc2a35de 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -366,7 +366,7 @@ static HRESULT media_stream_get_wg_parser_stream(struct media_stream *stream, st if (FAILED(hr = IMFStreamDescriptor_GetStreamIdentifier(stream->descriptor, &id))) return hr; - if (!(id = source->stream_map[id]) || !(*wg_stream = wg_parser_get_stream(source->wg_parser, id - 1))) + if (!(id = source->stream_map[id - 1]) || !(*wg_stream = wg_parser_get_stream(source->wg_parser, id - 1))) return MF_E_INVALIDSTREAMNUMBER; return S_OK; } @@ -483,7 +483,7 @@ static HRESULT media_source_start(struct media_source *source, IMFPresentationDe else if (!selected || FAILED(hr = IMFStreamDescriptor_GetStreamIdentifier(stream_descriptor, &id))) IMFStreamDescriptor_Release(stream_descriptor); else - descriptors[id] = stream_descriptor; + descriptors[id - 1] = stream_descriptor; } source->state = SOURCE_RUNNING; @@ -1683,7 +1683,7 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d struct wg_format format; wg_source_get_stream_format(wg_source, object->stream_map[i], &format); - if (FAILED(hr = stream_descriptor_create(i, &format, &descriptor))) + if (FAILED(hr = stream_descriptor_create(i + 1, &format, &descriptor))) goto fail; if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, descriptor, &stream))) { From bdf9ae79bd0a7bfe42a8d0a00ad99fc9922315f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 May 2023 10:16:05 +0200 Subject: [PATCH 1997/2777] winegstreamer: Delay wg_parser creation to media source start. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 66 ++++++++++++++----------------- 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 9e3dc2a35de..56b46a4e3cf 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -445,6 +445,8 @@ static HRESULT media_stream_start(struct media_stream *stream, BOOL active, BOOL &GUID_NULL, S_OK, position); } +static DWORD CALLBACK read_thread(void *arg); + static HRESULT media_source_start(struct media_source *source, IMFPresentationDescriptor *descriptor, GUID *format, PROPVARIANT *position) { @@ -459,6 +461,30 @@ static HRESULT media_source_start(struct media_source *source, IMFPresentationDe if (source->state == SOURCE_SHUTDOWN) return MF_E_SHUTDOWN; + if (!source->wg_parser) + { + /* In Media Foundation, sources may read from any media source stream + * without fear of blocking due to buffering limits on another. Trailmakers, + * a Unity3D Engine game, only reads one sample from the audio stream (and + * 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 (!(source->wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, true))) + return E_OUTOFMEMORY; + if (!(source->read_thread = CreateThread(NULL, 0, read_thread, source, 0, NULL))) + return E_OUTOFMEMORY; + if (FAILED(hr = wg_parser_connect(source->wg_parser, source->file_size, NULL))) + return hr; + + /* reset the stream map to map wg_stream numbers instead */ + memset(source->stream_map, 0, source->stream_count * sizeof(*source->stream_map)); + for (i = 0; i < source->stream_count; i++) + { + if (FAILED(hr = map_stream_to_wg_parser_stream(source, i))) + WARN("Failed to map stream %lu, hr %#lx\n", i, hr); + } + } + /* seek to beginning on stop->play */ if (source->state == SOURCE_STOPPED && position->vt == VT_EMPTY) { @@ -1225,7 +1251,8 @@ static ULONG WINAPI media_source_Release(IMFMediaSource *iface) IMFMediaEventQueue_Release(source->event_queue); IMFByteStream_Release(source->byte_stream); wg_source_destroy(source->wg_source); - wg_parser_destroy(source->wg_parser); + if (source->wg_parser) + wg_parser_destroy(source->wg_parser); source->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&source->cs); free(source); @@ -1422,7 +1449,8 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) source->state = SOURCE_SHUTDOWN; - wg_parser_disconnect(source->wg_parser); + if (source->wg_parser) + wg_parser_disconnect(source->wg_parser); source->read_thread_shutdown = true; WaitForSingleObject(source->read_thread, INFINITE); @@ -1551,14 +1579,6 @@ static void media_source_init_descriptors(struct media_source *source) WARN("Failed to set stream descriptor name, hr %#lx\n", hr); } - /* reset the stream map to map wg_stream numbers instead */ - memset(source->stream_map, 0, source->stream_count * sizeof(*source->stream_map)); - for (i = 0; i < source->stream_count; i++) - { - if (FAILED(hr = map_stream_to_wg_parser_stream(source, i))) - WARN("Failed to map stream descriptor %u, hr %#lx\n", i, hr); - } - if (!wcscmp(source->mime_type, L"video/mp4")) { if (last_audio != -1) @@ -1581,7 +1601,6 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d UINT32 stream_count; struct media_source *object; struct wg_source *wg_source; - struct wg_parser *parser; DWORD bytestream_caps, read_size = size; WCHAR mime_type[256]; unsigned int i; @@ -1649,20 +1668,6 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue))) goto fail; - if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, false))) - { - hr = E_OUTOFMEMORY; - goto fail; - } - object->wg_parser = parser; - - object->read_thread = CreateThread(NULL, 0, read_thread, object, 0, NULL); - - object->state = SOURCE_OPENING; - - if (FAILED(hr = wg_parser_connect(parser, file_size, NULL))) - goto fail; - if (!(object->descriptors = calloc(stream_count, sizeof(*object->descriptors))) || !(object->stream_map = calloc(stream_count, sizeof(*object->stream_map))) || !(object->streams = calloc(stream_count, sizeof(*object->streams)))) @@ -1675,7 +1680,6 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d media_source_init_stream_map(object, stream_count); - stream_count = wg_parser_get_stream_count(parser); for (i = 0; i < stream_count; ++i) { IMFStreamDescriptor *descriptor; @@ -1716,16 +1720,6 @@ HRESULT media_source_create(IMFByteStream *bytestream, const WCHAR *url, BYTE *d free(object->descriptors); free(object->streams); - if (object->state == SOURCE_OPENING) - wg_parser_disconnect(object->wg_parser); - if (object->read_thread) - { - object->read_thread_shutdown = true; - WaitForSingleObject(object->read_thread, INFINITE); - CloseHandle(object->read_thread); - } - if (object->wg_parser) - wg_parser_destroy(object->wg_parser); if (object->async_commands_queue) MFUnlockWorkQueue(object->async_commands_queue); if (object->event_queue) From 571a6d1780144f19e20323bce9088843b4682ee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 13 Mar 2023 17:00:39 +0100 Subject: [PATCH 1998/2777] HACK: winegstreamer: Fake raw formats for wg_source streams. CW-Bug-Id: #21953 --- dlls/winegstreamer/wg_source.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/wg_source.c b/dlls/winegstreamer/wg_source.c index 274420ffb09..114a0e60582 100644 --- a/dlls/winegstreamer/wg_source.c +++ b/dlls/winegstreamer/wg_source.c @@ -525,14 +525,32 @@ NTSTATUS wg_source_get_stream_format(void *args) struct wg_source_get_stream_format_params *params = args; struct wg_source *source = params->source; guint index = params->index; - GstCaps *caps; + GstCaps *caps, *copy; GST_TRACE("source %p, index %u", source, index); if (!(caps = source_get_stream_caps(source, index))) return STATUS_UNSUCCESSFUL; - wg_format_from_caps(¶ms->format, caps); + if (!(copy = gst_caps_copy(caps))) + goto done; + switch (stream_type_from_caps(caps)) + { + case GST_STREAM_TYPE_VIDEO: + gst_structure_set_name(gst_caps_get_structure(copy, 0), "video/x-raw"); + gst_caps_set_simple(copy, "format", G_TYPE_STRING, "NV12", NULL); + break; + case GST_STREAM_TYPE_AUDIO: + gst_structure_set_name(gst_caps_get_structure(copy, 0), "audio/x-raw"); + gst_caps_set_simple(copy, "format", G_TYPE_STRING, "S16LE", NULL); + gst_caps_set_simple(copy, "layout", G_TYPE_STRING, "interleaved", NULL); + break; + default: break; + } + wg_format_from_caps(¶ms->format, copy); + gst_caps_unref(copy); + +done: gst_caps_unref(caps); return STATUS_SUCCESS; } From 918385b3e8f37627aeeba01c28cec867856ed890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 3 May 2023 11:10:01 +0200 Subject: [PATCH 1999/2777] HACK: winegstreamer: Enable new media source for Bloodstained. CW-Bug-Id: #21953 --- dlls/winegstreamer/mf_handler.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/mf_handler.c b/dlls/winegstreamer/mf_handler.c index 7472f8c324a..bd1bd810c96 100644 --- a/dlls/winegstreamer/mf_handler.c +++ b/dlls/winegstreamer/mf_handler.c @@ -173,7 +173,9 @@ static HRESULT async_create_object_complete(struct async_create_object *async, if (async->flags & MF_RESOLUTION_MEDIASOURCE) { - const char *env = getenv("WINE_NEW_MEDIA_SOURCE"); + const char *sgi, *env = getenv("WINE_NEW_MEDIA_SOURCE"); + if (!env && (sgi = getenv("SteamGameId")) && (!strcmp(sgi, "692850"))) env = "1"; + if (!async->stream) hr = media_source_create_from_url(async->url, (IMFMediaSource **)&object); else if (!env || !atoi(env)) From c43c139dea4e6b4a6de767a8adf5c5ebeafefc38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 12 May 2023 13:34:23 +0200 Subject: [PATCH 2000/2777] winegstreamer: Introduce and use a new wg_task_pool helper. To better track GStreamer threads, avoiding potential task leaks in the default pool which keeps some thread alive. CW-Bug-Id: #22045 --- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/unix_private.h | 4 ++ dlls/winegstreamer/wg_parser.c | 28 +++++++++ dlls/winegstreamer/wg_task_pool.c | 98 +++++++++++++++++++++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 dlls/winegstreamer/wg_task_pool.c diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index acf4840e1d6..d811cfd810c 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -26,6 +26,7 @@ C_SRCS = \ wg_parser.c \ wg_sample.c \ wg_source.c \ + wg_task_pool.c \ wg_transform.c \ wm_reader.c \ wma_decoder.c \ diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index d74e1fdf11c..1f4ebf0a2df 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -77,6 +77,10 @@ extern NTSTATUS wg_source_push_data(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_source_get_stream_format(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_source_get_stream_tag(void *args) DECLSPEC_HIDDEN; +/* wg_task_pool.c */ + +extern GstTaskPool *wg_task_pool_new(void) DECLSPEC_HIDDEN; + /* wg_allocator.c */ /* wg_allocator_release_sample can be used to release any sample that was requested. */ diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 002142a6beb..0407676e63a 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -64,6 +64,7 @@ struct wg_parser GstElement *container, *decodebin; GstBus *bus; + GstTaskPool *task_pool; GstPad *my_src; guint64 file_size, start_offset, next_offset, stop_offset; @@ -1327,6 +1328,24 @@ static GstBusSyncReply bus_handler_cb(GstBus *bus, GstMessage *msg, gpointer use } break; + case GST_MESSAGE_STREAM_STATUS: + { + GstStreamStatusType type; + GstElement *element; + const GValue *val; + GstTask *task; + + gst_message_parse_stream_status(msg, &type, &element); + val = gst_message_get_stream_status_object(msg); + GST_DEBUG("parser %p, message %s, type %u, value %p (%s).", parser, GST_MESSAGE_TYPE_NAME(msg), type, val, G_VALUE_TYPE_NAME(val)); + + if (G_VALUE_TYPE(val) == GST_TYPE_TASK && (task = g_value_get_object(val)) + && type == GST_STREAM_STATUS_TYPE_CREATE) + gst_task_set_pool(task, parser->task_pool); + + break; + } + default: break; } @@ -1687,6 +1706,7 @@ static NTSTATUS wg_parser_disconnect(void *args) gst_object_unref(parser->container); parser->container = NULL; + gst_task_pool_cleanup(parser->task_pool); return S_OK; } @@ -1829,6 +1849,7 @@ static NTSTATUS wg_parser_create(void *args) struct wg_parser_create_params *params = args; struct wg_parser *parser; + GError *error; if (!(parser = calloc(1, sizeof(*parser)))) return E_OUTOFMEMORY; @@ -1842,6 +1863,12 @@ static NTSTATUS wg_parser_create(void *args) parser->use_opengl = FALSE; } } + if (!(parser->task_pool = wg_task_pool_new())) + { + free(parser); + return E_OUTOFMEMORY; + } + gst_task_pool_prepare(parser->task_pool, &error); pthread_mutex_init(&parser->mutex, NULL); pthread_cond_init(&parser->init_cond, NULL); @@ -1864,6 +1891,7 @@ static NTSTATUS wg_parser_destroy(void *args) gst_bus_set_sync_handler(parser->bus, NULL, NULL, NULL); gst_object_unref(parser->bus); } + gst_object_unref(parser->task_pool); if (parser->context) gst_context_unref(parser->context); diff --git a/dlls/winegstreamer/wg_task_pool.c b/dlls/winegstreamer/wg_task_pool.c new file mode 100644 index 00000000000..ec7da286d5f --- /dev/null +++ b/dlls/winegstreamer/wg_task_pool.c @@ -0,0 +1,98 @@ +/* + * GStreamer task pool + * + * Copyright 2023 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 + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include +#include + +#include + +#include "unix_private.h" + +typedef struct +{ + GstTaskPool parent; +} WgTaskPool; + +typedef struct +{ + GstTaskPoolClass parent_class; +} WgTaskPoolClass; + +G_DEFINE_TYPE(WgTaskPool, wg_task_pool, GST_TYPE_TASK_POOL); + +static void wg_task_pool_prepare(GstTaskPool *pool, GError **error) +{ + GST_LOG("pool %p, error %p", pool, error); +} + +static void wg_task_pool_cleanup(GstTaskPool *pool) +{ + GST_LOG("pool %p", pool); +} + +static gpointer wg_task_pool_push(GstTaskPool *pool, GstTaskPoolFunction func, gpointer data, GError **error) +{ + pthread_t *tid; + gint res; + + GST_LOG("pool %p, func %p, data %p, error %p", pool, func, data, error); + + if (!(tid = malloc(sizeof(*tid))) || !(res = pthread_create(tid, NULL, (void *)func, data))) + return tid; + + g_set_error(error, G_THREAD_ERROR, G_THREAD_ERROR_AGAIN, "Error creating thread: %s", g_strerror(res)); + free(tid); + + return NULL; +} + +static void wg_task_pool_join(GstTaskPool *pool, gpointer id) +{ + pthread_t *tid = id; + + GST_LOG("pool %p, id %p", pool, id); + + pthread_join(*tid, NULL); + free(tid); +} + +static void wg_task_pool_class_init(WgTaskPoolClass *klass) +{ + GstTaskPoolClass *parent_class = (GstTaskPoolClass *)klass; + parent_class->prepare = wg_task_pool_prepare; + parent_class->cleanup = wg_task_pool_cleanup; + parent_class->push = wg_task_pool_push; + parent_class->join = wg_task_pool_join; +} + +static void wg_task_pool_init(WgTaskPool *pool) +{ +} + +GstTaskPool *wg_task_pool_new(void) +{ + return g_object_new(wg_task_pool_get_type(), NULL); +} From 7c9eec349998505bdd55203e698fe17ecfa4b5f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 16 May 2023 11:44:16 +0200 Subject: [PATCH 2001/2777] HACK: winegstreamer: Don't use opengl for the new media source wg_parser. As a hack because the parameter has a different meaning upstream. CW-Bug-Id: #21953 --- dlls/winegstreamer/media_source.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 56b46a4e3cf..3cb57e94384 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -469,7 +469,7 @@ static HRESULT media_source_start(struct media_source *source, IMFPresentationDe * 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 (!(source->wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, true))) + if (!(source->wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, false))) return E_OUTOFMEMORY; if (!(source->read_thread = CreateThread(NULL, 0, read_thread, source, 0, NULL))) return E_OUTOFMEMORY; From f64062bb6e4091a978c982061011c3499e2f6224 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 2 Jun 2023 16:37:42 +0200 Subject: [PATCH 2002/2777] winegstreamer: Check the absolute value of the height in mf_media_type_from_wg_format_video(). Inverted height indicates vertically flipped video. We don't currently handle that either, but one thing at a time. (cherry picked from commit 98c266c0bdd02c4569fb2acaf70da66e66b79c72) --- dlls/winegstreamer/mfplat.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 27ec2aaea86..24bb092d39c 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -518,13 +518,15 @@ static IMFMediaType *mf_media_type_from_wg_format_video(const struct wg_format * { if (format->u.video.format == video_formats[i].format) { + int32_t height = abs(format->u.video.height); + int32_t width = format->u.video.width; + if (FAILED(MFCreateMediaType(&type))) return NULL; IMFMediaType_SetGUID(type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video); IMFMediaType_SetGUID(type, &MF_MT_SUBTYPE, video_formats[i].subtype); - IMFMediaType_SetUINT64(type, &MF_MT_FRAME_SIZE, - make_uint64(format->u.video.width, format->u.video.height)); + IMFMediaType_SetUINT64(type, &MF_MT_FRAME_SIZE, make_uint64(width, height)); IMFMediaType_SetUINT64(type, &MF_MT_FRAME_RATE, make_uint64(format->u.video.fps_n, format->u.video.fps_d)); IMFMediaType_SetUINT32(type, &MF_MT_COMPRESSED, FALSE); @@ -537,8 +539,8 @@ static IMFMediaType *mf_media_type_from_wg_format_video(const struct wg_format * { .OffsetX = {.value = format->u.video.padding.left}, .OffsetY = {.value = format->u.video.padding.top}, - .Area.cx = format->u.video.width - format->u.video.padding.right - format->u.video.padding.left, - .Area.cy = format->u.video.height - format->u.video.padding.bottom - format->u.video.padding.top, + .Area.cx = width - format->u.video.padding.right - format->u.video.padding.left, + .Area.cy = height - format->u.video.padding.bottom - format->u.video.padding.top, }; IMFMediaType_SetBlob(type, &MF_MT_MINIMUM_DISPLAY_APERTURE, From 9f6b46adfbaa547452eb40ce4973693921a301c1 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 2 Jun 2023 16:37:42 +0200 Subject: [PATCH 2003/2777] winegstreamer: Separate a mf_video_format_to_wg() helper. (cherry picked from commit 2803a220f684869ccd66e78778133b2586282da9) --- dlls/winegstreamer/mfplat.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 24bb092d39c..c39fc20b510 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -682,11 +682,23 @@ static void mf_media_type_to_wg_format_audio_mpeg4(IMFMediaType *type, const GUI format->u.audio_mpeg4.codec_data_len = codec_data_size; } +static enum wg_video_format mf_video_format_to_wg(const GUID *subtype) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(video_formats); ++i) + { + if (IsEqualGUID(subtype, video_formats[i].subtype)) + return video_formats[i].format; + } + FIXME("Unrecognized video subtype %s.\n", debugstr_guid(subtype)); + return WG_VIDEO_FORMAT_UNKNOWN; +} + static void mf_media_type_to_wg_format_video(IMFMediaType *type, const GUID *subtype, struct wg_format *format) { UINT64 frame_rate, frame_size; MFVideoArea aperture; - unsigned int i; UINT32 size; if (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) @@ -716,15 +728,7 @@ static void mf_media_type_to_wg_format_video(IMFMediaType *type, const GUID *sub format->u.video.fps_d = (UINT32)frame_rate; } - for (i = 0; i < ARRAY_SIZE(video_formats); ++i) - { - if (IsEqualGUID(subtype, video_formats[i].subtype)) - { - format->u.video.format = video_formats[i].format; - return; - } - } - FIXME("Unrecognized video subtype %s.\n", debugstr_guid(subtype)); + format->u.video.format = mf_video_format_to_wg(subtype); } static void mf_media_type_to_wg_format_audio_wma(IMFMediaType *type, const GUID *subtype, struct wg_format *format) From 2b268f523473164dda9e1c4670dea91c11e05adc Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Fri, 2 Jun 2023 16:37:42 +0200 Subject: [PATCH 2004/2777] winegstreamer: Initialize media source video types from a wg_video_format array. The mf_media_type_from_wg_format function will use the video format to calculate stride. (adapted from commit 98d209752cee9abd8dc31dfe1f28811066b0b83f) --- dlls/winegstreamer/media_source_old.c | 49 ++++++++++++++++----------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/dlls/winegstreamer/media_source_old.c b/dlls/winegstreamer/media_source_old.c index a2fe13e4da8..624ecc86cad 100644 --- a/dlls/winegstreamer/media_source_old.c +++ b/dlls/winegstreamer/media_source_old.c @@ -887,18 +887,18 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) if (format.major_type == WG_MAJOR_TYPE_VIDEO) { - /* These are the most common native output types of decoders: - https://docs.microsoft.com/en-us/windows/win32/medfound/mft-decoder-expose-output-types-in-native-order */ - static const GUID *const video_types[] = + /* Try to prefer YUV formats over RGB ones. Most decoders output in the + * YUV color space, and it's generally much less expensive for + * videoconvert to do YUV -> YUV transformations. */ + static const enum wg_video_format video_formats[] = { - &MFVideoFormat_NV12, - &MFVideoFormat_YV12, - &MFVideoFormat_YUY2, - &MFVideoFormat_IYUV, - &MFVideoFormat_I420, - &MFVideoFormat_ARGB32, - &MFVideoFormat_RGB32, - &MFVideoFormat_ABGR32, + WG_VIDEO_FORMAT_NV12, + WG_VIDEO_FORMAT_YV12, + WG_VIDEO_FORMAT_YUY2, + WG_VIDEO_FORMAT_I420, + WG_VIDEO_FORMAT_BGRA, + WG_VIDEO_FORMAT_BGRx, + WG_VIDEO_FORMAT_RGBA, }; IMFMediaType *base_type = mf_media_type_from_wg_format(&format); @@ -917,21 +917,32 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) stream_types[0] = base_type; type_count = 1; - for (i = 0; i < ARRAY_SIZE(video_types); i++) + for (i = 0; i < ARRAY_SIZE(video_formats); ++i) { + struct wg_format new_format = format; IMFMediaType *new_type; - if (IsEqualGUID(&base_subtype, video_types[i])) - continue; + new_format.u.video.format = video_formats[i]; - if (FAILED(hr = MFCreateMediaType(&new_type))) + if (!(new_type = mf_media_type_from_wg_format(&new_format))) + { + hr = E_OUTOFMEMORY; goto done; + } stream_types[type_count++] = new_type; - if (FAILED(hr = IMFMediaType_CopyAllItems(base_type, (IMFAttributes *) new_type))) - goto done; - if (FAILED(hr = IMFMediaType_SetGUID(new_type, &MF_MT_SUBTYPE, video_types[i]))) - goto done; + if (video_formats[i] == WG_VIDEO_FORMAT_I420) + { + IMFMediaType *iyuv_type; + + if (FAILED(hr = MFCreateMediaType(&iyuv_type))) + goto done; + if (FAILED(hr = IMFMediaType_CopyAllItems(new_type, (IMFAttributes *)iyuv_type))) + goto done; + if (FAILED(hr = IMFMediaType_SetGUID(iyuv_type, &MF_MT_SUBTYPE, &MFVideoFormat_IYUV))) + goto done; + stream_types[type_count++] = iyuv_type; + } } } else if (format.major_type == WG_MAJOR_TYPE_AUDIO) From 426362bda0f7fd3af2b37e18f2d56a754ec8a6ea Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 2 Jun 2023 16:37:42 +0200 Subject: [PATCH 2005/2777] winegstreamer: Set the MF_MT_DEFAULT_STRIDE attribute in mf_media_type_from_wg_format(). (partial import of ef354da59097b206122ec9101ee1f44201cca466) --- dlls/winegstreamer/gst_private.h | 4 ++ dlls/winegstreamer/main.c | 66 ++++++++++++++++++++++++++++++++ dlls/winegstreamer/mfplat.c | 7 ++++ 3 files changed, 77 insertions(+) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index b31feddd5ef..7103793cf50 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -165,6 +165,10 @@ HRESULT media_source_create(IMFByteStream *stream, const WCHAR *url, BYTE *data, HRESULT media_source_create_old(IMFByteStream *stream, const WCHAR *url, IMFMediaSource **out); HRESULT media_source_create_from_url(const WCHAR *url, IMFMediaSource **out); +unsigned int wg_format_get_stride(const struct wg_format *format); + +bool wg_video_format_is_rgb(enum wg_video_format format); + HRESULT aac_decoder_create(REFIID riid, void **ret); HRESULT h264_decoder_create(REFIID riid, void **ret); HRESULT video_processor_create(REFIID riid, void **ret); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 6175fc94a01..b0afca51d74 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -544,6 +544,72 @@ char *wg_source_get_stream_tag(struct wg_source *source, UINT32 index, enum wg_p return buffer; } +#define ALIGN(n, alignment) (((n) + (alignment) - 1) & ~((alignment) - 1)) + +unsigned int wg_format_get_stride(const struct wg_format *format) +{ + const unsigned int width = format->u.video.width; + + switch (format->u.video.format) + { + case WG_VIDEO_FORMAT_AYUV: + return width * 4; + + case WG_VIDEO_FORMAT_BGRA: + case WG_VIDEO_FORMAT_BGRx: + case WG_VIDEO_FORMAT_RGBA: + return width * 4; + + case WG_VIDEO_FORMAT_BGR: + return ALIGN(width * 3, 4); + + case WG_VIDEO_FORMAT_UYVY: + case WG_VIDEO_FORMAT_YUY2: + case WG_VIDEO_FORMAT_YVYU: + return ALIGN(width * 2, 4); + + case WG_VIDEO_FORMAT_RGB15: + case WG_VIDEO_FORMAT_RGB16: + return ALIGN(width * 2, 4); + + case WG_VIDEO_FORMAT_I420: + case WG_VIDEO_FORMAT_NV12: + case WG_VIDEO_FORMAT_YV12: + return ALIGN(width, 4); /* Y plane */ + + case WG_VIDEO_FORMAT_UNKNOWN: + FIXME("Cannot calculate stride for unknown video format.\n"); + } + + return 0; +} + +bool wg_video_format_is_rgb(enum wg_video_format format) +{ + switch (format) + { + case WG_VIDEO_FORMAT_BGRA: + case WG_VIDEO_FORMAT_BGRx: + case WG_VIDEO_FORMAT_RGBA: + case WG_VIDEO_FORMAT_BGR: + case WG_VIDEO_FORMAT_RGB15: + case WG_VIDEO_FORMAT_RGB16: + return true; + + 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: + break; + } + + return false; +} + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { if (reason == DLL_PROCESS_ATTACH) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index c39fc20b510..78e823e003f 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -518,6 +518,7 @@ static IMFMediaType *mf_media_type_from_wg_format_video(const struct wg_format * { if (format->u.video.format == video_formats[i].format) { + unsigned int stride = wg_format_get_stride(format); int32_t height = abs(format->u.video.height); int32_t width = format->u.video.width; @@ -533,6 +534,12 @@ static IMFMediaType *mf_media_type_from_wg_format_video(const struct wg_format * IMFMediaType_SetUINT32(type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); IMFMediaType_SetUINT32(type, &MF_MT_VIDEO_ROTATION, MFVideoRotationFormat_0); + if (wg_video_format_is_rgb(format->u.video.format)) + stride = -stride; + if (format->u.video.height < 0) + stride = -stride; + IMFMediaType_SetUINT32(type, &MF_MT_DEFAULT_STRIDE, stride); + if (!IsRectEmpty(&format->u.video.padding)) { MFVideoArea aperture = From a0997101ebba9785db861f4f5dff04af85aebc35 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 2 Jun 2023 16:37:42 +0200 Subject: [PATCH 2006/2777] winegstreamer: Translate the MF_MT_DEFAULT_STRIDE attribute to flipped video in mf_media_type_to_wg_format(). (cherry picked from commit af82c44e03ab5355f60b0796b5420b3688ea86a3) --- dlls/winegstreamer/mfplat.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 78e823e003f..48c2bb39657 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -706,7 +706,7 @@ static void mf_media_type_to_wg_format_video(IMFMediaType *type, const GUID *sub { UINT64 frame_rate, frame_size; MFVideoArea aperture; - UINT32 size; + UINT32 size, stride; if (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) { @@ -736,6 +736,14 @@ static void mf_media_type_to_wg_format_video(IMFMediaType *type, const GUID *sub } format->u.video.format = mf_video_format_to_wg(subtype); + + if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_DEFAULT_STRIDE, &stride))) + { + if (wg_video_format_is_rgb(format->u.video.format)) + format->u.video.height = -format->u.video.height; + if ((int)stride < 0) + format->u.video.height = -format->u.video.height; + } } static void mf_media_type_to_wg_format_audio_wma(IMFMediaType *type, const GUID *subtype, struct wg_format *format) From 551113bffc5abd1e1e3e50bd4b8804d0d2f8e0f2 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 2 Jun 2023 16:37:42 +0200 Subject: [PATCH 2007/2777] winegstreamer: Move flipping based on RGB to the frontends. Give the backend a more simple and self-consistent API. This commit also changes behaviour, by virtue of *not* changing some frontends. In specific, this commit does not modify the AVI splitter, which is known to output top-down RGB samples on Windows if the original video uses them (this is trivial to test by modifying test.avi in quartz to use "bgra" instead of "yuv420p"). It also does not modify the Media Foundation color converter DMO, whose tests imply that the MF_MT_DEFAULT_STRIDE attribute is always positive. (adapted from commit 6c11a4af5885c6485a908ea5c547e072fe71aa23) --- dlls/winegstreamer/mfplat.c | 8 ++++---- dlls/winegstreamer/quartz_parser.c | 9 ++++++++- dlls/winegstreamer/unixlib.h | 2 ++ dlls/winegstreamer/wg_parser.c | 29 ++--------------------------- dlls/winegstreamer/wm_reader.c | 9 ++++++++- dlls/winegstreamer/wmv_decoder.c | 15 ++++++++++++--- 6 files changed, 36 insertions(+), 36 deletions(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 48c2bb39657..9e0f3db23bb 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -534,8 +534,6 @@ static IMFMediaType *mf_media_type_from_wg_format_video(const struct wg_format * IMFMediaType_SetUINT32(type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); IMFMediaType_SetUINT32(type, &MF_MT_VIDEO_ROTATION, MFVideoRotationFormat_0); - if (wg_video_format_is_rgb(format->u.video.format)) - stride = -stride; if (format->u.video.height < 0) stride = -stride; IMFMediaType_SetUINT32(type, &MF_MT_DEFAULT_STRIDE, stride); @@ -739,11 +737,13 @@ static void mf_media_type_to_wg_format_video(IMFMediaType *type, const GUID *sub if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_DEFAULT_STRIDE, &stride))) { - if (wg_video_format_is_rgb(format->u.video.format)) - format->u.video.height = -format->u.video.height; if ((int)stride < 0) format->u.video.height = -format->u.video.height; } + else if (wg_video_format_is_rgb(format->u.video.format)) + { + format->u.video.height = -format->u.video.height; + } } static void mf_media_type_to_wg_format_audio_wma(IMFMediaType *type, const GUID *subtype, struct wg_format *format) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 4f91b2584e2..dfbe62a7a81 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -546,7 +546,7 @@ static bool amt_from_wg_format_video(AM_MEDIA_TYPE *mt, const struct wg_format * if (wm) { - SetRect(&video_format->rcSource, 0, 0, format->u.video.width, format->u.video.height); + SetRect(&video_format->rcSource, 0, 0, format->u.video.width, abs(format->u.video.height)); video_format->rcTarget = video_format->rcSource; } if ((frame_time = MulDiv(10000000, format->u.video.fps_d, format->u.video.fps_n)) != -1) @@ -554,6 +554,8 @@ static bool amt_from_wg_format_video(AM_MEDIA_TYPE *mt, const struct wg_format * video_format->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); video_format->bmiHeader.biWidth = format->u.video.width; video_format->bmiHeader.biHeight = format->u.video.height; + if (wg_video_format_is_rgb(format->u.video.format)) + video_format->bmiHeader.biHeight = -format->u.video.height; video_format->bmiHeader.biPlanes = 1; video_format->bmiHeader.biBitCount = wg_video_format_get_depth(format->u.video.format); video_format->bmiHeader.biCompression = wg_video_format_get_compression(format->u.video.format); @@ -826,6 +828,8 @@ static bool amt_to_wg_format_video(const AM_MEDIA_TYPE *mt, struct wg_format *fo if (IsEqualGUID(&mt->subtype, format_map[i].subtype)) { format->u.video.format = format_map[i].format; + if (wg_video_format_is_rgb(format->u.video.format)) + format->u.video.height = -format->u.video.height; return true; } } @@ -1470,6 +1474,9 @@ static HRESULT decodebin_parser_source_get_media_type(struct parser_source *pin, if (format.major_type == WG_MAJOR_TYPE_VIDEO && index < ARRAY_SIZE(video_formats)) { format.u.video.format = video_formats[index]; + /* Downstream filters probably expect RGB video to be bottom-up. */ + if (format.u.video.height > 0 && wg_video_format_is_rgb(video_formats[index])) + format.u.video.height = -format.u.video.height; if (!amt_from_wg_format(mt, &format, false)) return E_OUTOFMEMORY; return S_OK; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 2fe2a24e03b..79f151bd965 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -112,6 +112,8 @@ struct wg_format WG_VIDEO_FORMAT_YV12, WG_VIDEO_FORMAT_YVYU, } format; + /* Positive height indicates top-down video; negative height + * indicates bottom-up video. */ int32_t width, height; uint32_t fps_n, fps_d; RECT padding; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 0407676e63a..eb928059a7a 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -225,34 +225,9 @@ static NTSTATUS wg_parser_stream_enable(void *args) if (format->major_type == WG_MAJOR_TYPE_VIDEO) { - if (params->flags & STREAM_ENABLE_FLAG_FLIP_RGB) - { - bool flip = (format->u.video.height < 0); - - switch (format->u.video.format) - { - case WG_VIDEO_FORMAT_BGRA: - case WG_VIDEO_FORMAT_BGRx: - case WG_VIDEO_FORMAT_BGR: - case WG_VIDEO_FORMAT_RGBA: - case WG_VIDEO_FORMAT_RGB15: - case WG_VIDEO_FORMAT_RGB16: - flip = !flip; - break; + bool flip = (params->flags & STREAM_ENABLE_FLAG_FLIP_RGB) && (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: - break; - } - - gst_util_set_object_arg(G_OBJECT(stream->flip), "method", flip ? "vertical-flip" : "none"); - } + gst_util_set_object_arg(G_OBJECT(stream->flip), "method", flip ? "vertical-flip" : "none"); } gst_pad_push_event(stream->my_sink, gst_event_new_reconfigure()); diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 5e86b4f2b33..05b6960abe4 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1522,6 +1522,10 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) if (id && !strcmp(id, "1113000")) stream->format.u.video.format = WG_VIDEO_FORMAT_BGRx; } + + /* API consumers expect RGB video to be bottom-up. */ + if (stream->format.u.video.height > 0) + stream->format.u.video.height = -stream->format.u.video.height; } wg_parser_stream_enable(stream->wg_stream, &stream->format, STREAM_ENABLE_FLAG_FLIP_RGB); } @@ -1935,6 +1939,9 @@ static HRESULT WINAPI reader_GetOutputFormat(IWMSyncReader2 *iface, return NS_E_INVALID_OUTPUT_FORMAT; } format.u.video.format = video_formats[index]; + /* API consumers expect RGB video to be bottom-up. */ + if (format.u.video.height > 0 && wg_video_format_is_rgb(format.u.video.format)) + format.u.video.height = -format.u.video.height; break; case WG_MAJOR_TYPE_AUDIO: @@ -2227,7 +2234,7 @@ static HRESULT WINAPI reader_SetOutputProps(IWMSyncReader2 *iface, DWORD output, hr = NS_E_INVALID_OUTPUT_FORMAT; else if (pref_format.u.video.width != format.u.video.width) hr = NS_E_INVALID_OUTPUT_FORMAT; - else if (pref_format.u.video.height != format.u.video.height) + else if (abs(pref_format.u.video.height) != abs(format.u.video.height)) hr = NS_E_INVALID_OUTPUT_FORMAT; break; diff --git a/dlls/winegstreamer/wmv_decoder.c b/dlls/winegstreamer/wmv_decoder.c index b81639f312a..9af4a18a5fd 100644 --- a/dlls/winegstreamer/wmv_decoder.c +++ b/dlls/winegstreamer/wmv_decoder.c @@ -382,7 +382,12 @@ static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index if (!format.u.video.width) format.u.video.width = 1920; if (!format.u.video.height) - format.u.video.height = 1080; + { + if (wg_video_format_is_rgb(format.u.video.format)) + format.u.video.height = -1080; + else + format.u.video.height = 1080; + } if (!format.u.video.fps_d) format.u.video.fps_d = 1; if (!format.u.video.fps_n) @@ -410,12 +415,16 @@ static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD inde if (!format.u.video.width) format.u.video.width = 1920; if (!format.u.video.height) - format.u.video.height = 1080; + { + if (wg_video_format_is_rgb(format.u.video.format)) + format.u.video.height = -1080; + else + format.u.video.height = 1080; + } if (!format.u.video.fps_d) format.u.video.fps_d = 1; if (!format.u.video.fps_n) format.u.video.fps_n = 1; - if (!amt_from_wg_format((AM_MEDIA_TYPE *)type, &format, false)) return VFW_E_NO_TYPES; From fa2abde2d4413e27c047479c386c47d129c08112 Mon Sep 17 00:00:00 2001 From: Anton Baskanov Date: Fri, 2 Jun 2023 16:37:42 +0200 Subject: [PATCH 2008/2777] winegstreamer: Fix negative height image size calculation. Fixes intro video playback in multiple games (e.g. Earth 2150). (cherry picked from commit a455dd53d5af144aae70263d9f4e798a305ab775) --- 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 dfbe62a7a81..889a9223d3e 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -343,7 +343,7 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) { case WG_MAJOR_TYPE_VIDEO: { - unsigned int width = format->u.video.width, height = format->u.video.height; + unsigned int width = format->u.video.width, height = abs(format->u.video.height); switch (format->u.video.format) { From 004e83effc089e7a544601fdc756888696650a26 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Fri, 2 Jun 2023 16:37:42 +0200 Subject: [PATCH 2009/2777] winegstreamer: In video_processor, activate a videoflip converter. The app I'm considering opens a video_processor on its own, with a NV12 format on input and a ARGB32 format on output. Tested on Windows: the samples are flipped vertically. While Wine keeps them untouched. So added a videoflip in the video processor to be activated when needed. CW-Bug-Id: 21028 Signed-off-by: Eric Pouech --- dlls/winegstreamer/color_convert.c | 28 ++++++++++++++++++++++++++++ dlls/winegstreamer/wg_transform.c | 23 +++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/dlls/winegstreamer/color_convert.c b/dlls/winegstreamer/color_convert.c index 0eaddc687ee..ed591c8e669 100644 --- a/dlls/winegstreamer/color_convert.c +++ b/dlls/winegstreamer/color_convert.c @@ -363,6 +363,7 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM struct color_convert *impl = impl_from_IMFTransform(iface); GUID major, subtype; UINT64 frame_size; + UINT32 stride; HRESULT hr; ULONG i; @@ -392,6 +393,19 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM IMFMediaType_Release(impl->input_type); impl->input_type = NULL; } + if (FAILED(IMFMediaType_GetUINT32(impl->input_type, &MF_MT_DEFAULT_STRIDE, &stride))) + { + if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, frame_size >> 32, (LONG *)&stride))) + { + IMFMediaType_Release(impl->input_type); + impl->input_type = NULL; + } + if (FAILED(hr = IMFMediaType_SetUINT32(impl->input_type, &MF_MT_DEFAULT_STRIDE, abs((INT32)stride)))) + { + IMFMediaType_Release(impl->input_type); + impl->input_type = NULL; + } + } if (impl->output_type && FAILED(hr = try_create_wg_transform(impl))) { @@ -411,6 +425,7 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF struct color_convert *impl = impl_from_IMFTransform(iface); GUID major, subtype; UINT64 frame_size; + UINT32 stride; HRESULT hr; ULONG i; @@ -440,6 +455,19 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF IMFMediaType_Release(impl->output_type); impl->output_type = NULL; } + if (FAILED(IMFMediaType_GetUINT32(impl->output_type, &MF_MT_DEFAULT_STRIDE, &stride))) + { + if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, frame_size >> 32, (LONG *)&stride))) + { + IMFMediaType_Release(impl->output_type); + impl->output_type = NULL; + } + if (FAILED(hr = IMFMediaType_SetUINT32(impl->output_type, &MF_MT_DEFAULT_STRIDE, abs((INT32)stride)))) + { + IMFMediaType_Release(impl->output_type); + impl->output_type = NULL; + } + } if (impl->input_type && FAILED(hr = try_create_wg_transform(impl))) { diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 18ba562ab22..41f49351b0a 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -52,6 +52,9 @@ struct wg_transform guint input_max_length; GstAtomicQueue *input_queue; + bool input_is_flipped; + GstElement *video_flip; + guint output_plane_align; struct wg_sample *output_wg_sample; GstAtomicQueue *output_queue; @@ -276,6 +279,11 @@ static struct wg_sample *transform_request_sample(gsize size, void *context) return InterlockedExchangePointer((void **)&transform->output_wg_sample, NULL); } +static bool wg_format_video_is_flipped(const struct wg_format *format) +{ + return format->major_type == WG_MAJOR_TYPE_VIDEO && (format->u.video.height < 0); +} + NTSTATUS wg_transform_create(void *args) { struct wg_transform_create_params *params = args; @@ -392,6 +400,12 @@ NTSTATUS wg_transform_create(void *args) break; case WG_MAJOR_TYPE_VIDEO: + if (!(transform->video_flip = create_element("videoflip", "base")) + || !append_element(transform->container, transform->video_flip, &first, &last)) + goto out; + transform->input_is_flipped = wg_format_video_is_flipped(&input_format); + if (transform->input_is_flipped != wg_format_video_is_flipped(&output_format)) + gst_util_set_object_arg(G_OBJECT(transform->video_flip), "method", "vertical-flip"); if (!(element = create_element("videoconvert", "base")) || !append_element(transform->container, element, &first, &last)) goto out; @@ -519,6 +533,15 @@ NTSTATUS wg_transform_set_output_format(void *args) transform->setting_output_format = true; + if (transform->video_flip) + { + const char *value; + if (transform->input_is_flipped != wg_format_video_is_flipped(format)) + value = "vertical-flip"; + else + value = "none"; + gst_util_set_object_arg(G_OBJECT(transform->video_flip), "method", value); + } if (!gst_pad_push_event(transform->my_sink, gst_event_new_reconfigure())) { GST_ERROR("Failed to reconfigure transform %p.", transform); From 8c294ba01a5f058fd5c9491c2384aa63c887b362 Mon Sep 17 00:00:00 2001 From: Anton Baskanov Date: Fri, 2 Jun 2023 16:37:42 +0200 Subject: [PATCH 2010/2777] winegstreamer: Add a second videoconvert before the videoflip. videoflip can't handle 15/16-bit RGB. Fixes video playback in multiple games (e.g. Hard Truck 2, Firestarter). (cherry picked from commit dd20b895713b4e9384267765ee4181d32855472e) --- dlls/winegstreamer/wg_transform.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 41f49351b0a..dc5fd51e998 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -400,6 +400,9 @@ NTSTATUS wg_transform_create(void *args) break; case WG_MAJOR_TYPE_VIDEO: + if (!(element = create_element("videoconvert", "base")) + || !append_element(transform->container, element, &first, &last)) + goto out; if (!(transform->video_flip = create_element("videoflip", "base")) || !append_element(transform->container, transform->video_flip, &first, &last)) goto out; From 2ec6a43f709fa4c326e04326b6896bd3a9d0ebc9 Mon Sep 17 00:00:00 2001 From: Anton Baskanov Date: Fri, 2 Jun 2023 16:37:42 +0200 Subject: [PATCH 2011/2777] winegstreamer: Don't force top-down orientation when changing output format in video_decoder. (cherry picked from commit c73e8b8551947e9547331ff5b72b206981c5f645) --- dlls/winegstreamer/video_decoder.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 1fdabd46b96..04d175c7910 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -310,8 +310,6 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF { mf_media_type_to_wg_format(decoder->output_type, &output_format); - output_format.u.video.width = frame_size >> 32; - output_format.u.video.height = (UINT32)frame_size; output_format.u.video.fps_d = 0; output_format.u.video.fps_n = 0; From 2e9c512af49d20a55698e71af763d9ccbc707e1b Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 1 Feb 2023 01:34:12 -0500 Subject: [PATCH 2012/2777] ir50_32: Add stub dll. (cherry picked from commit 91c1c05f5b0d224b664ae5fd6c0bc93db4eab872) CW-Bug-Id: #21175 --- configure.ac | 1 + dlls/ir50_32/Makefile.in | 7 ++ dlls/ir50_32/ir50.c | 180 ++++++++++++++++++++++++++++++++++++ dlls/ir50_32/ir50_32.rc | 29 ++++++ dlls/ir50_32/ir50_32.spec | 1 + dlls/ir50_32/ir50_private.h | 34 +++++++ po/ar.po | 12 +++ po/ast.po | 8 ++ po/bg.po | 10 ++ po/ca.po | 12 +++ po/cs.po | 12 +++ po/da.po | 12 +++ po/de.po | 12 +++ po/el.po | 8 ++ po/en.po | 8 ++ po/en_US.po | 8 ++ po/eo.po | 10 ++ po/es.po | 12 +++ po/fa.po | 8 ++ po/fi.po | 12 +++ po/fr.po | 12 +++ po/he.po | 12 +++ po/hi.po | 8 ++ po/hr.po | 12 +++ po/hu.po | 12 +++ po/it.po | 12 +++ po/ja.po | 12 +++ po/ko.po | 12 +++ po/lt.po | 12 +++ po/ml.po | 8 ++ po/nb_NO.po | 12 +++ po/nl.po | 12 +++ po/or.po | 8 ++ po/pa.po | 8 ++ po/pl.po | 12 +++ po/pt_BR.po | 12 +++ po/pt_PT.po | 12 +++ po/rm.po | 9 ++ po/ro.po | 12 +++ po/ru.po | 12 +++ po/si.po | 12 +++ po/sk.po | 10 ++ po/sl.po | 12 +++ po/sr_RS@cyrillic.po | 11 +++ po/sr_RS@latin.po | 12 +++ po/sv.po | 12 +++ po/ta.po | 10 ++ po/te.po | 8 ++ po/th.po | 8 ++ po/tr.po | 12 +++ po/uk.po | 12 +++ po/wa.po | 9 ++ po/wine.pot | 8 ++ po/zh_CN.po | 12 +++ po/zh_TW.po | 12 +++ 55 files changed, 777 insertions(+) create mode 100644 dlls/ir50_32/Makefile.in create mode 100644 dlls/ir50_32/ir50.c create mode 100644 dlls/ir50_32/ir50_32.rc create mode 100644 dlls/ir50_32/ir50_32.spec create mode 100644 dlls/ir50_32/ir50_private.h diff --git a/configure.ac b/configure.ac index 92dc784035d..e4b85800b4b 100644 --- a/configure.ac +++ b/configure.ac @@ -2703,6 +2703,7 @@ WINE_CONFIG_MAKEFILE(dlls/inseng) WINE_CONFIG_MAKEFILE(dlls/iphlpapi) WINE_CONFIG_MAKEFILE(dlls/iphlpapi/tests) WINE_CONFIG_MAKEFILE(dlls/iprop) +WINE_CONFIG_MAKEFILE(dlls/ir50_32) WINE_CONFIG_MAKEFILE(dlls/irprops.cpl) WINE_CONFIG_MAKEFILE(dlls/itircl) WINE_CONFIG_MAKEFILE(dlls/itss) diff --git a/dlls/ir50_32/Makefile.in b/dlls/ir50_32/Makefile.in new file mode 100644 index 00000000000..7bac0ccc9ca --- /dev/null +++ b/dlls/ir50_32/Makefile.in @@ -0,0 +1,7 @@ +MODULE = ir50_32.dll +IMPORTS = user32 + +C_SRCS = \ + ir50.c + +RC_SRCS = ir50_32.rc diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c new file mode 100644 index 00000000000..3019301742e --- /dev/null +++ b/dlls/ir50_32/ir50.c @@ -0,0 +1,180 @@ +/* + * Intel Indeo 5 Video Decoder + * Copyright 2023 Shaun Ren 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 + * + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "commdlg.h" +#include "vfw.h" +#include "ir50_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ir50_32); + +static HINSTANCE IR50_32_hModule; + +#define IV50_MAGIC mmioFOURCC('I','V','5','0') + + +static LRESULT +IV50_Open( const ICINFO *icinfo ) +{ + FIXME("DRV_OPEN %p\n", icinfo); + return 0; +} + +static LRESULT +IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) +{ + FIXME("ICM_DECOMPRESS_QUERY %p %p\n", in, out); + return ICERR_UNSUPPORTED; +} + +static LRESULT +IV50_DecompressGetFormat( LPBITMAPINFO in, LPBITMAPINFO out ) +{ + FIXME("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out); + return ICERR_UNSUPPORTED; +} + +static LRESULT IV50_DecompressBegin( IMFTransform *decoder, LPBITMAPINFO in, LPBITMAPINFO out ) +{ + FIXME("ICM_DECOMPRESS_BEGIN %p %p %p\n", decoder, in, out); + return ICERR_UNSUPPORTED; +} + +static LRESULT IV50_Decompress( IMFTransform *decoder, ICDECOMPRESS *icd, DWORD size ) +{ + FIXME("ICM_DECOMPRESS %p %p %lu\n", decoder, icd, size); + return ICERR_UNSUPPORTED; +} + +static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize ) +{ + FIXME("ICM_GETINFO %p %lu\n", icinfo, dwSize); + return ICERR_UNSUPPORTED; +} + +/*********************************************************************** + * DriverProc (IR50_32.@) + */ +LRESULT WINAPI IV50_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg, + LPARAM lParam1, LPARAM lParam2 ) +{ + IMFTransform *decoder = (IMFTransform *) dwDriverId; + LRESULT r = ICERR_UNSUPPORTED; + + TRACE("%Id %p %04x %08Ix %08Ix\n", dwDriverId, hdrvr, msg, lParam1, lParam2); + + switch( msg ) + { + case DRV_LOAD: + TRACE("DRV_LOAD\n"); + r = 1; + break; + + case DRV_OPEN: + r = IV50_Open((ICINFO *)lParam2); + break; + + case DRV_CLOSE: + FIXME("DRV_CLOSE\n"); + break; + + case DRV_ENABLE: + case DRV_DISABLE: + case DRV_FREE: + break; + + case ICM_GETINFO: + r = IV50_GetInfo( (ICINFO *) lParam1, (DWORD) lParam2 ); + break; + + case ICM_DECOMPRESS_QUERY: + r = IV50_DecompressQuery( (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 ); + break; + + case ICM_DECOMPRESS_GET_FORMAT: + r = IV50_DecompressGetFormat( (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 ); + break; + + case ICM_DECOMPRESS_GET_PALETTE: + FIXME("ICM_DECOMPRESS_GET_PALETTE\n"); + break; + + case ICM_DECOMPRESS: + r = IV50_Decompress( decoder, (ICDECOMPRESS *) lParam1, (DWORD) lParam2 ); + break; + + case ICM_DECOMPRESS_BEGIN: + r = IV50_DecompressBegin( decoder, (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 ); + break; + + case ICM_DECOMPRESS_END: + r = ICERR_UNSUPPORTED; + break; + + case ICM_DECOMPRESSEX_QUERY: + FIXME("ICM_DECOMPRESSEX_QUERY\n"); + break; + + case ICM_DECOMPRESSEX: + FIXME("ICM_DECOMPRESSEX\n"); + break; + + case ICM_COMPRESS_QUERY: + r = ICERR_BADFORMAT; + /* fall through */ + case ICM_COMPRESS_GET_FORMAT: + case ICM_COMPRESS_END: + case ICM_COMPRESS: + FIXME("compression not implemented\n"); + break; + + case ICM_CONFIGURE: + break; + + default: + FIXME("Unknown message: %04x %Id %Id\n", msg, lParam1, lParam2); + } + + return r; +} + +/*********************************************************************** + * DllMain + */ +BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved) +{ + TRACE("(%p,%lu,%p)\n", hModule, dwReason, lpReserved); + + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hModule); + IR50_32_hModule = hModule; + break; + } + return TRUE; +} diff --git a/dlls/ir50_32/ir50_32.rc b/dlls/ir50_32/ir50_32.rc new file mode 100644 index 00000000000..fd98f76fbf6 --- /dev/null +++ b/dlls/ir50_32/ir50_32.rc @@ -0,0 +1,29 @@ +/* + * Copyright 2023 Shaun Ren 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 + */ + +#include "ir50_private.h" + +#pragma makedep po + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT + +STRINGTABLE +{ + IDS_NAME "Indeo5" + IDS_DESCRIPTION "Indeo Video Interactive version 5 video codec" +} diff --git a/dlls/ir50_32/ir50_32.spec b/dlls/ir50_32/ir50_32.spec new file mode 100644 index 00000000000..e5c54ef9c56 --- /dev/null +++ b/dlls/ir50_32/ir50_32.spec @@ -0,0 +1 @@ +@ stdcall -private DriverProc(long long long long long) IV50_DriverProc diff --git a/dlls/ir50_32/ir50_private.h b/dlls/ir50_32/ir50_private.h new file mode 100644 index 00000000000..c022a8196d2 --- /dev/null +++ b/dlls/ir50_32/ir50_private.h @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Shaun Ren 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 + */ + +#ifndef __IR50_PRIVATE_H +#define __IR50_PRIVATE_H + +#include + +#define COBJMACROS +#include "mfapi.h" +#include "mferror.h" +#include "mfobjects.h" +#include "mfidl.h" +#include "mftransform.h" + +#define IDS_NAME 100 +#define IDS_DESCRIPTION 101 + +#endif /* __IR50_PRIVATE_H */ diff --git a/po/ar.po b/po/ar.po index 8ebe10b5a0a..5fdad68ed12 100644 --- a/po/ar.po +++ b/po/ar.po @@ -3732,6 +3732,18 @@ msgstr "زائد" msgid "High" msgstr "عالي" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "الÙهرس" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "ترميز واين المرئي الأول" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "مقابض اللعب" diff --git a/po/ast.po b/po/ast.po index 9bb71695e12..359de815a1a 100644 --- a/po/ast.po +++ b/po/ast.po @@ -3626,6 +3626,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/bg.po b/po/bg.po index 70219b75174..cac408aef44 100644 --- a/po/bg.po +++ b/po/bg.po @@ -3744,6 +3744,16 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +msgid "Indeo5" +msgstr "&Съдържание" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine MS-RLE видео кодек" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/ca.po b/po/ca.po index 1b66417b24d..00cb01b7ce2 100644 --- a/po/ca.po +++ b/po/ca.po @@ -3724,6 +3724,18 @@ msgstr "Elevat" msgid "High" msgstr "Alt" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Ãndex" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Còdec de vídeo Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Palanques de control" diff --git a/po/cs.po b/po/cs.po index 704550231b3..b2c53f1d99a 100644 --- a/po/cs.po +++ b/po/cs.po @@ -3681,6 +3681,18 @@ msgstr "Zvýšená" msgid "High" msgstr "Vysoká" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Rejstřík" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Videokodek Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Pákové ovladaÄe" diff --git a/po/da.po b/po/da.po index 3fc57acec52..53aa5e9ac72 100644 --- a/po/da.po +++ b/po/da.po @@ -3763,6 +3763,18 @@ msgstr "Øget" msgid "High" msgstr "&Høj" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Indeks" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 videokodeks" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/de.po b/po/de.po index 7a14c2e5a59..e970e9175df 100644 --- a/po/de.po +++ b/po/de.po @@ -3714,6 +3714,18 @@ msgstr "Erhöht" msgid "High" msgstr "Hoch" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Index" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine-Video-1-Videocodec" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/el.po b/po/el.po index 11180a1b639..f4ca06d96fb 100644 --- a/po/el.po +++ b/po/el.po @@ -3661,6 +3661,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/en.po b/po/en.po index 246a8bb86f2..a5425b52486 100644 --- a/po/en.po +++ b/po/en.po @@ -3707,6 +3707,14 @@ msgstr "Increased" msgid "High" msgstr "High" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "Indeo5" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Indeo Video Interactive version 5 video codec" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/en_US.po b/po/en_US.po index ad7b5b9773c..0735be69271 100644 --- a/po/en_US.po +++ b/po/en_US.po @@ -3707,6 +3707,14 @@ msgstr "Increased" msgid "High" msgstr "High" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "Indeo5" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Indeo Video Interactive version 5 video codec" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/eo.po b/po/eo.po index ad39dac7839..f2ff3e010a1 100644 --- a/po/eo.po +++ b/po/eo.po @@ -3649,6 +3649,16 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Indekso" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/es.po b/po/es.po index 5bc81f068b8..4f363add9c4 100644 --- a/po/es.po +++ b/po/es.po @@ -3727,6 +3727,18 @@ msgstr "Aumentada" msgid "High" msgstr "Alta" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Ãndice" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Códec de vídeo Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Comando de juego" diff --git a/po/fa.po b/po/fa.po index 2eafe19dd2e..2ea2a88163a 100644 --- a/po/fa.po +++ b/po/fa.po @@ -3692,6 +3692,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/fi.po b/po/fi.po index 905eb06a8cc..dc90507d60e 100644 --- a/po/fi.po +++ b/po/fi.po @@ -3701,6 +3701,18 @@ msgstr "Korotettu" msgid "High" msgstr "Korkea" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Sisällys" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Winen Video 1 -videokoodekki" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joystickit" diff --git a/po/fr.po b/po/fr.po index 1c48ddc57a6..b00b7235c3e 100644 --- a/po/fr.po +++ b/po/fr.po @@ -3732,6 +3732,18 @@ msgstr "Augmentée" msgid "High" msgstr "Haute" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Index" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Codec vidéo Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/he.po b/po/he.po index 82df9538b43..58dcefcebd4 100644 --- a/po/he.po +++ b/po/he.po @@ -3727,6 +3727,18 @@ msgstr "מוגברת" msgid "High" msgstr "גבוהה" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "מפתח" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "מקודד הוויד×ו Video 1 של Wine" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/hi.po b/po/hi.po index 8ba49545d06..7663549c7a2 100644 --- a/po/hi.po +++ b/po/hi.po @@ -3625,6 +3625,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/hr.po b/po/hr.po index c9f87d7dc66..f04c70940fa 100644 --- a/po/hr.po +++ b/po/hr.po @@ -3737,6 +3737,18 @@ msgstr "Povećane" msgid "High" msgstr "Visoke" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Indeks" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 video codec" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joystici" diff --git a/po/hu.po b/po/hu.po index 05920d1c8e6..24c0eeecd35 100644 --- a/po/hu.po +++ b/po/hu.po @@ -3779,6 +3779,18 @@ msgstr "Megnövelt" msgid "High" msgstr "Magas" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "&Témakörök" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 video kodek" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/it.po b/po/it.po index d0663b4d1d7..0449017ac23 100644 --- a/po/it.po +++ b/po/it.po @@ -3787,6 +3787,18 @@ msgstr "Aumentato" msgid "High" msgstr "Alta" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Indice" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Codec Video Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/ja.po b/po/ja.po index 318f1a9029d..43bf855ddcd 100644 --- a/po/ja.po +++ b/po/ja.po @@ -3699,6 +3699,18 @@ msgstr "中高" msgid "High" msgstr "高" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "索引" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine ビデオ 1 ビデオコーデック" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "ジョイスティック" diff --git a/po/ko.po b/po/ko.po index a86e129750c..c1272917c81 100644 --- a/po/ko.po +++ b/po/ko.po @@ -3689,6 +3689,18 @@ msgstr "ì¦ê°€" msgid "High" msgstr "높ìŒ" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "ì¸ë±ìŠ¤" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine 비디오 1 비디오 ì½”ë±" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "ì¡°ì´ìŠ¤í‹±" diff --git a/po/lt.po b/po/lt.po index 8ede4161894..e4f347061d6 100644 --- a/po/lt.po +++ b/po/lt.po @@ -3710,6 +3710,18 @@ msgstr "Padidintos" msgid "High" msgstr "AukÅ¡tos" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Indeksas" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "„Wine“ Video 1 vaizdo kodekas" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "VairasvirtÄ—s" diff --git a/po/ml.po b/po/ml.po index 8df38715288..b612d8ef96e 100644 --- a/po/ml.po +++ b/po/ml.po @@ -3627,6 +3627,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/nb_NO.po b/po/nb_NO.po index f7ddeff7cae..da72e8d86f8 100644 --- a/po/nb_NO.po +++ b/po/nb_NO.po @@ -3715,6 +3715,18 @@ msgstr "Økt" msgid "High" msgstr "Høy" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Innhold" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 videokodeks" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Styrespaker" diff --git a/po/nl.po b/po/nl.po index 92d601aaf92..b6df43c1006 100644 --- a/po/nl.po +++ b/po/nl.po @@ -3720,6 +3720,18 @@ msgstr "Verhoogd" msgid "High" msgstr "Hoog" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Index" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 video codec" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/or.po b/po/or.po index 3d8ffa37e1d..f380aee4c32 100644 --- a/po/or.po +++ b/po/or.po @@ -3625,6 +3625,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/pa.po b/po/pa.po index 8177d578666..02417daffe3 100644 --- a/po/pa.po +++ b/po/pa.po @@ -3625,6 +3625,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/pl.po b/po/pl.po index dcb4daaa0bd..9689ee339e0 100644 --- a/po/pl.po +++ b/po/pl.po @@ -3726,6 +3726,18 @@ msgstr "Wysoki" msgid "High" msgstr "Najwyższy" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Indeks" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Kodek Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticki" diff --git a/po/pt_BR.po b/po/pt_BR.po index 7593a85f8f3..15079a024e1 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -3722,6 +3722,18 @@ msgstr "Elevada" msgid "High" msgstr "Alta" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Ãndice" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Codec de vídeo Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Controles" diff --git a/po/pt_PT.po b/po/pt_PT.po index be1ddf75488..55807dedfdd 100644 --- a/po/pt_PT.po +++ b/po/pt_PT.po @@ -3763,6 +3763,18 @@ msgstr "Aumentada" msgid "High" msgstr "Alta" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Ãndice" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "codec video Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/rm.po b/po/rm.po index ffd9d51fc0e..eb130bb02c2 100644 --- a/po/rm.po +++ b/po/rm.po @@ -3653,6 +3653,15 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +msgid "Indeo5" +msgstr "&Cuntgn�" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/ro.po b/po/ro.po index 3947ea81074..d042fde175b 100644 --- a/po/ro.po +++ b/po/ro.po @@ -3720,6 +3720,18 @@ msgstr "Mărit" msgid "High" msgstr "ÃŽnalt" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Index" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Codecul video Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joystick-uri" diff --git a/po/ru.po b/po/ru.po index b7649c75b93..483e925f005 100644 --- a/po/ru.po +++ b/po/ru.po @@ -3725,6 +3725,18 @@ msgstr "Повышенный" msgid "High" msgstr "Ð’Ñ‹Ñокий" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Указатель" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Видео кодек Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "ДжойÑтики" diff --git a/po/si.po b/po/si.po index 2dea09241dc..395e7c3aa23 100644 --- a/po/si.po +++ b/po/si.po @@ -3652,6 +3652,18 @@ msgstr "" msgid "High" msgstr "à·€à·à¶©à·’" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "දර්à·à¶šà¶º" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine වීඩිය෠1 වීඩිය෠කොඩෙක්" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "නියà·à¶¸à¶š යටි" diff --git a/po/sk.po b/po/sk.po index 9caab53bd61..5a74fd54a99 100644 --- a/po/sk.po +++ b/po/sk.po @@ -3694,6 +3694,16 @@ msgstr "Zvýšené" msgid "High" msgstr "Vysoké" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Obsah" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/sl.po b/po/sl.po index 49fceead951..f2a06472681 100644 --- a/po/sl.po +++ b/po/sl.po @@ -3781,6 +3781,18 @@ msgstr "PoveÄano" msgid "High" msgstr "Visoka" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Kazalo" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 video kodek" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/sr_RS@cyrillic.po b/po/sr_RS@cyrillic.po index 344a6396134..3f6bf0232b1 100644 --- a/po/sr_RS@cyrillic.po +++ b/po/sr_RS@cyrillic.po @@ -3762,6 +3762,17 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +msgid "Indeo5" +msgstr "&ПопиÑ" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 видео кодек" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/sr_RS@latin.po b/po/sr_RS@latin.po index 4d5e65cb529..ea6b3aecae5 100644 --- a/po/sr_RS@latin.po +++ b/po/sr_RS@latin.po @@ -3846,6 +3846,18 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Index" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 video kodek" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/sv.po b/po/sv.po index f02e762af01..c4ed81856f5 100644 --- a/po/sv.po +++ b/po/sv.po @@ -3742,6 +3742,18 @@ msgstr "Ökad" msgid "High" msgstr "Hög" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Index" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 videokodek" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Joysticks" diff --git a/po/ta.po b/po/ta.po index 02563f2b63d..656f7a07b3a 100644 --- a/po/ta.po +++ b/po/ta.po @@ -3589,6 +3589,16 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine வீடியோ 1 வீடியோ கோடெகà¯" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/te.po b/po/te.po index 6128822c44c..8b69b08e201 100644 --- a/po/te.po +++ b/po/te.po @@ -3625,6 +3625,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/th.po b/po/th.po index 9d99df54f41..41de65e1d68 100644 --- a/po/th.po +++ b/po/th.po @@ -3680,6 +3680,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/tr.po b/po/tr.po index 73ee1e5eb83..0a6e29835f6 100644 --- a/po/tr.po +++ b/po/tr.po @@ -3716,6 +3716,18 @@ msgstr "Arttırılmış" msgid "High" msgstr "Yüksek" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "İçindekiler" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 video çözücü" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "Oyun Kolları" diff --git a/po/uk.po b/po/uk.po index de0466f9971..57307a18199 100644 --- a/po/uk.po +++ b/po/uk.po @@ -3713,6 +3713,18 @@ msgstr "Збільшені" msgid "High" msgstr "ВиÑокі" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "Вказівник" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Відео кодек Wine Video 1" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "ДжойÑтик" diff --git a/po/wa.po b/po/wa.po index dab8e39300b..891cf5fb6e3 100644 --- a/po/wa.po +++ b/po/wa.po @@ -3688,6 +3688,15 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +msgid "Indeo5" +msgstr "Ã…&dvins" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/wine.pot b/po/wine.pot index dd9701759d8..5241318e3bf 100644 --- a/po/wine.pot +++ b/po/wine.pot @@ -3580,6 +3580,14 @@ msgstr "" msgid "High" msgstr "" +#: dlls/ir50_32/ir50_32.rc:28 +msgid "Indeo5" +msgstr "" + +#: dlls/ir50_32/ir50_32.rc:29 +msgid "Indeo Video Interactive version 5 video codec" +msgstr "" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "" diff --git a/po/zh_CN.po b/po/zh_CN.po index bad68026ffa..022dd3369a4 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -3657,6 +3657,18 @@ msgstr "较高" msgid "High" msgstr "高" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "索引" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine Video 1 视频编解ç å™¨" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "æ“纵æ†" diff --git a/po/zh_TW.po b/po/zh_TW.po index a54460961b3..3d888ac2790 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -3663,6 +3663,18 @@ msgstr "ç¨é«˜" msgid "High" msgstr "高" +#: dlls/ir50_32/ir50_32.rc:28 +#, fuzzy +#| msgid "Index" +msgid "Indeo5" +msgstr "索引" + +#: dlls/ir50_32/ir50_32.rc:29 +#, fuzzy +#| msgid "Wine Video 1 video codec" +msgid "Indeo Video Interactive version 5 video codec" +msgstr "Wine 視訊 1 視訊編碼解碼器" + #: dlls/joy.cpl/joy.rc:37 msgid "Joysticks" msgstr "æ–æ¡¿" From db73e15eb595d80a4d0cba2a8cc173f327089855 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 1 Feb 2023 01:37:09 -0500 Subject: [PATCH 2013/2777] ir50_32: Implement IV50_GetInfo. (cherry picked from commit 05eef506149ca2892b5727d8a5a7eb9e71638b08) CW-Bug-Id: #21175 --- dlls/ir50_32/ir50.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 3019301742e..0e1c9b4d2e4 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -72,8 +72,23 @@ static LRESULT IV50_Decompress( IMFTransform *decoder, ICDECOMPRESS *icd, DWORD static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize ) { - FIXME("ICM_GETINFO %p %lu\n", icinfo, dwSize); - return ICERR_UNSUPPORTED; + TRACE("ICM_GETINFO %p %lu\n", icinfo, dwSize); + + if ( !icinfo ) return sizeof(ICINFO); + if ( dwSize < sizeof(ICINFO) ) return 0; + + icinfo->dwSize = sizeof(ICINFO); + icinfo->fccType = ICTYPE_VIDEO; + icinfo->fccHandler = IV50_MAGIC; + icinfo->dwFlags = 0; + icinfo->dwVersion = ICVERSION; + icinfo->dwVersionICM = ICVERSION; + + LoadStringW( IR50_32_hModule, IDS_NAME, icinfo->szName, ARRAY_SIZE(icinfo->szName) ); + LoadStringW( IR50_32_hModule, IDS_DESCRIPTION, icinfo->szDescription, ARRAY_SIZE(icinfo->szDescription) ); + /* msvfw32 will fill icinfo->szDriver for us */ + + return sizeof(ICINFO); } /*********************************************************************** From 2447ef9ba843e3e9adadcb486b7708626fbdc7e7 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 1 Feb 2023 01:38:30 -0500 Subject: [PATCH 2014/2777] ir50_32: Implement IV50_DecompressQuery. (cherry picked from commit b979f3b8aa9cc395a6dfc314fc4f48af4ef215c4) CW-Bug-Id: #21175 --- dlls/ir50_32/ir50.c | 47 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 0e1c9b4d2e4..92e4c8a49be 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -47,8 +47,51 @@ IV50_Open( const ICINFO *icinfo ) static LRESULT IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) { - FIXME("ICM_DECOMPRESS_QUERY %p %p\n", in, out); - return ICERR_UNSUPPORTED; + TRACE("ICM_DECOMPRESS_QUERY %p %p\n", in, out); + + TRACE("in->planes = %d\n", in->bmiHeader.biPlanes); + TRACE("in->bpp = %d\n", in->bmiHeader.biBitCount); + TRACE("in->height = %ld\n", in->bmiHeader.biHeight); + TRACE("in->width = %ld\n", in->bmiHeader.biWidth); + TRACE("in->compr = %#lx\n", in->bmiHeader.biCompression); + + if ( in->bmiHeader.biCompression != IV50_MAGIC ) + { + TRACE("can't do %#lx compression\n", in->bmiHeader.biCompression); + return ICERR_BADFORMAT; + } + + /* output must be same dimensions as input */ + if ( out ) + { + TRACE("out->planes = %d\n", out->bmiHeader.biPlanes); + TRACE("out->bpp = %d\n", out->bmiHeader.biBitCount); + TRACE("out->height = %ld\n", out->bmiHeader.biHeight); + TRACE("out->width = %ld\n", out->bmiHeader.biWidth); + TRACE("out->compr = %#lx\n", out->bmiHeader.biCompression); + + if ( out->bmiHeader.biCompression != BI_RGB ) + { + TRACE("incompatible compression requested\n"); + return ICERR_BADFORMAT; + } + + if ( out->bmiHeader.biBitCount != 32 && out->bmiHeader.biBitCount != 16 ) + { + TRACE("incompatible depth requested\n"); + return ICERR_BADFORMAT; + } + + if ( in->bmiHeader.biPlanes != out->bmiHeader.biPlanes || + in->bmiHeader.biHeight != abs(out->bmiHeader.biHeight) || + in->bmiHeader.biWidth != out->bmiHeader.biWidth ) + { + TRACE("incompatible output dimensions requested\n"); + return ICERR_BADFORMAT; + } + } + + return ICERR_OK; } static LRESULT From f5756fbcfe18fb6de75d00798d34ff4eb404901c Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 1 Feb 2023 01:42:13 -0500 Subject: [PATCH 2015/2777] ir50_32: Implement IV50_DecompressGetFormat. (cherry picked from commit e8cfcbb2f4d4cd04e3ea77979214c4fccf503c92) CW-Bug-Id: #21175 --- dlls/ir50_32/ir50.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 92e4c8a49be..7e494d50761 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -97,8 +97,28 @@ IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) static LRESULT IV50_DecompressGetFormat( LPBITMAPINFO in, LPBITMAPINFO out ) { - FIXME("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out); - return ICERR_UNSUPPORTED; + DWORD size; + + TRACE("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out); + + if ( !in ) + return ICERR_BADPARAM; + + if ( in->bmiHeader.biCompression != IV50_MAGIC ) + return ICERR_BADFORMAT; + + size = in->bmiHeader.biSize; + if ( out ) + { + memcpy( out, in, size ); + out->bmiHeader.biHeight = abs(in->bmiHeader.biHeight); + out->bmiHeader.biCompression = BI_RGB; + out->bmiHeader.biBitCount = 32; + out->bmiHeader.biSizeImage = out->bmiHeader.biWidth * out->bmiHeader.biHeight * 4; + return ICERR_OK; + } + + return size; } static LRESULT IV50_DecompressBegin( IMFTransform *decoder, LPBITMAPINFO in, LPBITMAPINFO out ) From d40d215370d03b8621e5b13512f7a1f6f3187932 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Fri, 3 Feb 2023 02:16:34 -0500 Subject: [PATCH 2016/2777] ir50_32: Implement open and close. (cherry picked from commit 3dd09ed8f9ecf99439a372b6d0be076cef8aaef3) CW-Bug-Id: #21175 --- dlls/ir50_32/Makefile.in | 3 ++- dlls/ir50_32/ir50.c | 19 ++++++++++++++++--- dlls/ir50_32/ir50_private.h | 2 ++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/dlls/ir50_32/Makefile.in b/dlls/ir50_32/Makefile.in index 7bac0ccc9ca..2db9c8076c9 100644 --- a/dlls/ir50_32/Makefile.in +++ b/dlls/ir50_32/Makefile.in @@ -1,5 +1,6 @@ MODULE = ir50_32.dll -IMPORTS = user32 +IMPORTS = user32 mfplat mfuuid +DELAYIMPORTS = winegstreamer C_SRCS = \ ir50.c diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 7e494d50761..428108f09ba 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -35,13 +35,23 @@ WINE_DEFAULT_DEBUG_CHANNEL(ir50_32); static HINSTANCE IR50_32_hModule; #define IV50_MAGIC mmioFOURCC('I','V','5','0') +#define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020) static LRESULT IV50_Open( const ICINFO *icinfo ) { - FIXME("DRV_OPEN %p\n", icinfo); - return 0; + IMFTransform *decoder = NULL; + + TRACE("DRV_OPEN %p\n", icinfo); + + if ( icinfo && compare_fourcc( icinfo->fccType, ICTYPE_VIDEO ) ) + return 0; + + if ( FAILED(winegstreamer_create_video_decoder( &decoder )) ) + return 0; + + return (LRESULT)decoder; } static LRESULT @@ -177,7 +187,10 @@ LRESULT WINAPI IV50_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg, break; case DRV_CLOSE: - FIXME("DRV_CLOSE\n"); + TRACE("DRV_CLOSE\n"); + if ( decoder ) + IMFTransform_Release( decoder ); + r = 1; break; case DRV_ENABLE: diff --git a/dlls/ir50_32/ir50_private.h b/dlls/ir50_32/ir50_private.h index c022a8196d2..c0b96bc17e4 100644 --- a/dlls/ir50_32/ir50_private.h +++ b/dlls/ir50_32/ir50_private.h @@ -31,4 +31,6 @@ #define IDS_NAME 100 #define IDS_DESCRIPTION 101 +HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out); + #endif /* __IR50_PRIVATE_H */ From 139cf070df68466d91d87d77f4753aadf17628bc Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 8 Feb 2023 02:04:02 -0500 Subject: [PATCH 2017/2777] ir50_32: Implement decompression. (cherry picked from commit 4eac23121d17e5b5cca61516429398aac1ed8e5a) CW-Bug-Id: #21175 --- dlls/ir50_32/ir50.c | 149 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 145 insertions(+), 4 deletions(-) diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 428108f09ba..87807aba25f 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -26,6 +26,7 @@ #include "winuser.h" #include "commdlg.h" #include "vfw.h" +#include "initguid.h" #include "ir50_private.h" #include "wine/debug.h" @@ -37,6 +38,14 @@ static HINSTANCE IR50_32_hModule; #define IV50_MAGIC mmioFOURCC('I','V','5','0') #define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020) +DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50, MAKEFOURCC('I','V','5','0')); + +static inline UINT64 +make_uint64( UINT32 high, UINT32 low ) +{ + return ((UINT64)high << 32) | low; +} + static LRESULT IV50_Open( const ICINFO *icinfo ) @@ -133,14 +142,146 @@ IV50_DecompressGetFormat( LPBITMAPINFO in, LPBITMAPINFO out ) static LRESULT IV50_DecompressBegin( IMFTransform *decoder, LPBITMAPINFO in, LPBITMAPINFO out ) { - FIXME("ICM_DECOMPRESS_BEGIN %p %p %p\n", decoder, in, out); - return ICERR_UNSUPPORTED; + IMFMediaType *input_type, *output_type; + const GUID *output_subtype; + LRESULT r = ICERR_INTERNAL; + + TRACE("ICM_DECOMPRESS_BEGIN %p %p %p\n", decoder, in, out); + + if ( !decoder ) + return ICERR_BADPARAM; + + if ( out->bmiHeader.biBitCount == 32 ) + output_subtype = &MFVideoFormat_RGB32; + else if ( out->bmiHeader.biBitCount == 16 ) + output_subtype = &MFVideoFormat_RGB555; + else + return ICERR_BADFORMAT; + + if ( FAILED(MFCreateMediaType( &input_type )) ) + return ICERR_INTERNAL; + + if ( FAILED(MFCreateMediaType( &output_type )) ) + { + IMFMediaType_Release( input_type ); + return ICERR_INTERNAL; + } + + if ( FAILED(IMFMediaType_SetGUID( input_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video )) || + FAILED(IMFMediaType_SetGUID( input_type, &MF_MT_SUBTYPE, &MFVideoFormat_IV50 )) ) + goto done; + if ( FAILED(IMFMediaType_SetUINT64( + input_type, &MF_MT_FRAME_SIZE, + make_uint64( in->bmiHeader.biWidth, in->bmiHeader.biHeight ) )) ) + goto done; + + if ( FAILED(IMFMediaType_SetGUID( output_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video )) || + FAILED(IMFMediaType_SetGUID( output_type, &MF_MT_SUBTYPE, output_subtype )) ) + goto done; + if ( FAILED(IMFMediaType_SetUINT64( + output_type, &MF_MT_FRAME_SIZE, + make_uint64( out->bmiHeader.biWidth, abs(out->bmiHeader.biHeight) ) )) ) + goto done; + + if ( FAILED(IMFTransform_SetInputType( decoder, 0, input_type, 0 )) || + FAILED(IMFTransform_SetOutputType( decoder, 0, output_type, 0 )) ) + goto done; + + r = ICERR_OK; + +done: + IMFMediaType_Release( input_type ); + IMFMediaType_Release( output_type ); + return r; } static LRESULT IV50_Decompress( IMFTransform *decoder, ICDECOMPRESS *icd, DWORD size ) { - FIXME("ICM_DECOMPRESS %p %p %lu\n", decoder, icd, size); - return ICERR_UNSUPPORTED; + IMFSample *in_sample = NULL, *out_sample = NULL; + IMFMediaBuffer *in_buf = NULL, *out_buf = NULL; + MFT_OUTPUT_DATA_BUFFER mft_buf; + DWORD mft_status; + BYTE *data; + HRESULT hr; + LRESULT r = ICERR_INTERNAL; + + TRACE("ICM_DECOMPRESS %p %p %lu\n", decoder, icd, size); + + if ( FAILED(MFCreateSample( &in_sample )) ) + return ICERR_INTERNAL; + + if ( FAILED(MFCreateMemoryBuffer( icd->lpbiInput->biSizeImage, &in_buf )) ) + goto done; + + if ( FAILED(IMFSample_AddBuffer( in_sample, in_buf )) ) + goto done; + + if ( FAILED(MFCreateSample( &out_sample )) ) + goto done; + + if ( FAILED(MFCreateMemoryBuffer( icd->lpbiOutput->biSizeImage, &out_buf )) ) + goto done; + + if ( FAILED(IMFSample_AddBuffer( out_sample, out_buf )) ) + goto done; + + if ( FAILED(IMFMediaBuffer_Lock( in_buf, &data, NULL, NULL ))) + goto done; + + memcpy( data, icd->lpInput, icd->lpbiInput->biSizeImage ); + + if ( FAILED(IMFMediaBuffer_Unlock( in_buf )) ) + goto done; + + if ( FAILED(IMFMediaBuffer_SetCurrentLength( in_buf, icd->lpbiInput->biSizeImage )) ) + goto done; + + if ( FAILED(IMFTransform_ProcessInput( decoder, 0, in_sample, 0 )) ) + goto done; + + memset( &mft_buf, 0, sizeof(mft_buf) ); + mft_buf.pSample = out_sample; + + hr = IMFTransform_ProcessOutput( decoder, 0, 1, &mft_buf, &mft_status ); + if ( SUCCEEDED(hr) && (mft_status & MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE) ) + hr = IMFTransform_ProcessOutput( decoder, 0, 1, &mft_buf, &mft_status ); + + if ( SUCCEEDED(hr) ) + { + LONG width = icd->lpbiOutput->biWidth * (icd->lpbiOutput->biBitCount / 8); + LONG height = abs( icd->lpbiOutput->biHeight ); + LONG data_stride = (width + 3) & ~3; + LONG out_stride = icd->lpbiOutput->biHeight >= 0 ? -data_stride : data_stride; + BYTE *output_start = (BYTE *)icd->lpOutput; + + if (out_stride < 0) + output_start += (height - 1) * abs(out_stride); + + if ( FAILED(IMFMediaBuffer_Lock( out_buf, &data, NULL, NULL ))) + goto done; + + MFCopyImage( output_start, out_stride, data, data_stride, width, height ); + + IMFMediaBuffer_Unlock( out_buf ); + r = ICERR_OK; + } + else if ( hr == MF_E_TRANSFORM_NEED_MORE_INPUT ) + { + TRACE("no output received.\n"); + r = ICERR_OK; + } + +done: + if ( in_buf ) + IMFMediaBuffer_Release( in_buf ); + if ( in_sample ) + IMFSample_Release( in_sample ); + if ( out_buf ) + IMFMediaBuffer_Release( out_buf ); + if ( out_sample ) + IMFSample_Release( out_sample ); + + return r; } static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize ) From aca44a75dab444ca6e5b2f125749211bd52dc00d Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 8 Feb 2023 02:46:23 -0500 Subject: [PATCH 2018/2777] wine.inf: Enable ir50_32 video codec. (cherry picked from commit d83e03f638094cbac14307b0eabc9b71025dbaae) CW-Bug-Id: #21175 --- loader/wine.inf.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 83397bbb9b9..6273413d92e 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2339,7 +2339,7 @@ system.ini, drivers32,,"msacm.msgsm610=msgsm32.acm" system.ini, drivers32,,"vidc.mrle=msrle32.dll" system.ini, drivers32,,"vidc.msvc=msvidc32.dll" system.ini, drivers32,,"vidc.cvid=iccvid.dll" -system.ini, drivers32,,"; vidc.IV50=ir50_32.dll" +system.ini, drivers32,,"vidc.IV50=ir50_32.dll" system.ini, drivers32,,"; vidc.IV31=ir32_32.dll" system.ini, drivers32,,"; vidc.IV32=ir32_32.dll" From 00d13dd964afc220421b8a332b25ebcdccc1f3a1 Mon Sep 17 00:00:00 2001 From: Anton Baskanov Date: Fri, 2 Jun 2023 16:37:42 +0200 Subject: [PATCH 2019/2777] ir50_32: Let video_decoder flip the video instead of doing it manually. Fixes upside-down videos in multiple games (e.g. Hard Truck 2, Firestarter). (cherry picked from commit 79ce998e794189b4f9cd11916e1dbc0d7508ca75) --- dlls/ir50_32/ir50.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 87807aba25f..280983e58d8 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -145,6 +145,7 @@ static LRESULT IV50_DecompressBegin( IMFTransform *decoder, LPBITMAPINFO in, LPB IMFMediaType *input_type, *output_type; const GUID *output_subtype; LRESULT r = ICERR_INTERNAL; + unsigned int stride; TRACE("ICM_DECOMPRESS_BEGIN %p %p %p\n", decoder, in, out); @@ -158,6 +159,10 @@ static LRESULT IV50_DecompressBegin( IMFTransform *decoder, LPBITMAPINFO in, LPB else return ICERR_BADFORMAT; + stride = (out->bmiHeader.biWidth + 3) & ~3; + if (out->bmiHeader.biHeight >= 0) + stride = -stride; + if ( FAILED(MFCreateMediaType( &input_type )) ) return ICERR_INTERNAL; @@ -182,6 +187,8 @@ static LRESULT IV50_DecompressBegin( IMFTransform *decoder, LPBITMAPINFO in, LPB output_type, &MF_MT_FRAME_SIZE, make_uint64( out->bmiHeader.biWidth, abs(out->bmiHeader.biHeight) ) )) ) goto done; + if ( FAILED(IMFMediaType_SetUINT32( output_type, &MF_MT_DEFAULT_STRIDE, stride)) ) + goto done; if ( FAILED(IMFTransform_SetInputType( decoder, 0, input_type, 0 )) || FAILED(IMFTransform_SetOutputType( decoder, 0, output_type, 0 )) ) @@ -250,17 +257,13 @@ static LRESULT IV50_Decompress( IMFTransform *decoder, ICDECOMPRESS *icd, DWORD { LONG width = icd->lpbiOutput->biWidth * (icd->lpbiOutput->biBitCount / 8); LONG height = abs( icd->lpbiOutput->biHeight ); - LONG data_stride = (width + 3) & ~3; - LONG out_stride = icd->lpbiOutput->biHeight >= 0 ? -data_stride : data_stride; - BYTE *output_start = (BYTE *)icd->lpOutput; - - if (out_stride < 0) - output_start += (height - 1) * abs(out_stride); + LONG stride = (width + 3) & ~3; + BYTE *output = (BYTE *)icd->lpOutput; if ( FAILED(IMFMediaBuffer_Lock( out_buf, &data, NULL, NULL ))) goto done; - MFCopyImage( output_start, out_stride, data, data_stride, width, height ); + MFCopyImage( output, stride, data, stride, width, height ); IMFMediaBuffer_Unlock( out_buf ); r = ICERR_OK; From 05d56819a573455d4b3caebbe3630d7b0b7681a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 22:59:39 +0200 Subject: [PATCH 2020/2777] Revert "winegstreamer: Implement MFT_MESSAGE_COMMAND_FLUSH for h264 decoder." This reverts commit 6fc8c46aab46ad5e3ccc1019a44288f3143279e9. CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/mf/tests/transform.c | 19 ++++++++++++++++--- dlls/winegstreamer/aac_decoder.c | 2 +- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/h264_decoder.c | 4 +--- dlls/winegstreamer/main.c | 3 +-- dlls/winegstreamer/resampler.c | 2 +- dlls/winegstreamer/unixlib.h | 1 - dlls/winegstreamer/video_processor.c | 2 +- dlls/winegstreamer/wg_transform.c | 14 +------------- dlls/winegstreamer/wma_decoder.c | 2 +- 10 files changed, 24 insertions(+), 27 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 2cf36bf4b38..05504cac9b3 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -6567,9 +6567,6 @@ static void test_h264_reuse(void) ok(hr == S_OK, "got %#lx\n", hr); IMFSample_Release(output_sample); - hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_FLUSH, 0); - ok(hr == S_OK, "got %#lx\n", hr); - IMFSample_Release(input_sample); load_resource(L"stream2.bin", &data1, &data1_len); @@ -6600,6 +6597,22 @@ static void test_h264_reuse(void) i++; } trace("i %d.\n", i); + ok(hr == S_OK, "got %#lx\n", hr); + while (hr == S_OK) + { + IMFSample_Release(output_sample); + output_sample = create_sample(NULL, width * height * 3 / 2); + hr = check_mft_process_output(transform, output_sample, &output_status); + } + while (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) + { + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == S_OK, "got %#lx\n", hr); + IMFSample_Release(input_sample); + input_sample = next_h264_sample(&data1, &data1_len); + + hr = check_mft_process_output(transform, output_sample, &output_status); + } ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "got %#lx\n", hr); diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index 01f07e6b713..3be7e91147f 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -542,7 +542,7 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ return MF_E_TRANSFORM_TYPE_NOT_SET; if (message == MFT_MESSAGE_COMMAND_DRAIN) - return wg_transform_drain(decoder->wg_transform, FALSE); + return wg_transform_drain(decoder->wg_transform); FIXME("Ignoring message %#x.\n", message); diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 7103793cf50..81aefe4234f 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -105,7 +105,7 @@ struct wg_transform *wg_transform_create(const struct wg_format *input_format, void wg_transform_destroy(struct wg_transform *transform); bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_format *format); bool wg_transform_get_status(struct wg_transform *transform, bool *accepts_input); -HRESULT wg_transform_drain(struct wg_transform *transform, BOOL flush); +HRESULT wg_transform_drain(struct wg_transform *transform); struct wg_source *wg_source_create(const WCHAR *url, uint64_t file_size, const void *data, uint32_t size, WCHAR mime_type[256]); diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index c5600389be7..a1d70eb5733 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -590,9 +590,7 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ return MF_E_TRANSFORM_TYPE_NOT_SET; if (message == MFT_MESSAGE_COMMAND_DRAIN) - return wg_transform_drain(decoder->wg_transform, FALSE); - if (message == MFT_MESSAGE_COMMAND_FLUSH) - return wg_transform_drain(decoder->wg_transform, TRUE); + return wg_transform_drain(decoder->wg_transform); FIXME("Ignoring message %#x.\n", message); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index b0afca51d74..df7f123aaee 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -415,12 +415,11 @@ bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_fo return !WINE_UNIX_CALL(unix_wg_transform_set_output_format, ¶ms); } -HRESULT wg_transform_drain(struct wg_transform *transform, BOOL flush) +HRESULT wg_transform_drain(struct wg_transform *transform) { struct wg_transform_drain_params params = { .transform = transform, - .flush = flush, }; TRACE("transform %p.\n", transform); diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c index 4c8d27856f9..c4efd5fb82c 100644 --- a/dlls/winegstreamer/resampler.c +++ b/dlls/winegstreamer/resampler.c @@ -513,7 +513,7 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ return MF_E_TRANSFORM_TYPE_NOT_SET; if (message == MFT_MESSAGE_COMMAND_DRAIN) - return wg_transform_drain(impl->wg_transform, FALSE); + return wg_transform_drain(impl->wg_transform); FIXME("Ignoring message %#x.\n", message); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 79f151bd965..175538ad147 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -335,7 +335,6 @@ struct wg_transform_get_status_params struct wg_transform_drain_params { struct wg_transform *transform; - BOOL flush; }; struct wg_source_create_params diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index 03186b36d9d..d8ef51b7bf2 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -513,7 +513,7 @@ static HRESULT WINAPI video_processor_ProcessMessage(IMFTransform *iface, MFT_ME return MF_E_TRANSFORM_TYPE_NOT_SET; if (message == MFT_MESSAGE_COMMAND_DRAIN) - return wg_transform_drain(impl->wg_transform, FALSE); + return wg_transform_drain(impl->wg_transform); FIXME("Ignoring message %#x.\n", message); diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index dc5fd51e998..63d27b8bc32 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -573,16 +573,13 @@ NTSTATUS wg_transform_drain(void *args) struct wg_transform_drain_params *params = args; struct wg_transform *transform = params->transform; GstBuffer *input_buffer; - GstSample *sample; GstFlowReturn ret; GstEvent *event; while ((input_buffer = gst_atomic_queue_pop(transform->input_queue))) { - if (params->flush) - gst_buffer_unref(input_buffer); - else if ((ret = gst_pad_push(transform->my_src, input_buffer))) + if ((ret = gst_pad_push(transform->my_src, input_buffer))) { GST_ERROR("Failed to push transform input, error %d", ret); return S_OK; @@ -612,15 +609,6 @@ NTSTATUS wg_transform_drain(void *args) return MF_E_STREAM_ERROR; } - if (params->flush) - { - if (transform->output_sample) - gst_sample_unref(transform->output_sample); - while ((sample = gst_atomic_queue_pop(transform->output_queue))) - gst_sample_unref(sample); - transform->output_sample = NULL; - } - return S_OK; } diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index fa649fea63b..9354822e45c 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -530,7 +530,7 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ return MF_E_TRANSFORM_TYPE_NOT_SET; if (message == MFT_MESSAGE_COMMAND_DRAIN) - return wg_transform_drain(decoder->wg_transform, FALSE); + return wg_transform_drain(decoder->wg_transform); FIXME("Ignoring message %#x.\n", message); From 95eac4a71601e405976e85d1297730d3dea24b69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 22:59:40 +0200 Subject: [PATCH 2021/2777] Revert "winegstreamer: Return gst_pad_query_default() when processing GST_QUERY_CAPS for input stream format change." This reverts commit a76a0c4b0ca3cbf892b3f377ed2923a70b510b1f. CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/mf/tests/resource.rc | 19 ---- dlls/mf/tests/stream1.bin | Bin 7174 -> 0 bytes dlls/mf/tests/stream2.bin | Bin 4416 -> 0 bytes dlls/mf/tests/transform.c | 168 ------------------------------ dlls/winegstreamer/wg_transform.c | 7 -- 5 files changed, 194 deletions(-) delete mode 100644 dlls/mf/tests/stream1.bin delete mode 100644 dlls/mf/tests/stream2.bin diff --git a/dlls/mf/tests/resource.rc b/dlls/mf/tests/resource.rc index 58654b93c33..25768d21983 100644 --- a/dlls/mf/tests/resource.rc +++ b/dlls/mf/tests/resource.rc @@ -63,25 +63,6 @@ mp3decdata.bin RCDATA mp3decdata.bin /* @makedep: h264data.bin */ h264data.bin RCDATA h264data.bin - -/* Generated with: - * gst-launch-1.0 videotestsrc num-buffers=60 pattern=smpte100 ! \ - * video/x-raw,format=I420,width=1920,height=1080,framerate=30000/1001 ! \ - * videoflip method=clockwise ! videoconvert ! \ - * x264enc ! filesink location=dlls/mf/tests/h264data.bin - */ -/* @makedep: stream1.bin */ -stream1.bin RCDATA stream1.bin - -/* Generated with: - * gst-launch-1.0 videotestsrc num-buffers=60 pattern=smpte100 ! \ - * video/x-raw,format=I420,width=1280,height=720,framerate=30000/1001 ! \ - * videoflip method=clockwise ! videoconvert ! \ - * x264enc ! filesink location=dlls/mf/tests/h264data.bin - */ -/* @makedep: stream2.bin */ -stream2.bin RCDATA stream2.bin - /* Generated from running the tests on Windows */ /* @makedep: nv12frame.bmp */ nv12frame.bmp RCDATA nv12frame.bmp diff --git a/dlls/mf/tests/stream1.bin b/dlls/mf/tests/stream1.bin deleted file mode 100644 index f16bdaec31cd097310c31af70e15e30f9175b3e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7174 zcmb_f4LDS38$L4#vC66}#hw)vi}~@hewvsSDTJ_V+n?#oILt7AW(LFdGb`z5w^F_= zkx8{hY>{k~jnc-pwQ7@AQmIW}M7Ba@@x5opOvCE>Fs{or-uFGvdq2-}KhHVu{X!6g z)13){->3*^QBjlUQjOa0t5-`TlKl|04u;J94IfM+S7QdujwdHLY>IBmf6m=vL!2@4=U_b~6@?K`=2va}t z0+tad13d8J@e|o-qzEPxi4JyTBAE;pnIaM2jX+39NU)D*MW8%3!nNlKq6nB5d!~rP z1~xpth{fXy-CzbnM;H_mEI=bE4sZlYXY&{_6p|a!jR+%LgqL<$fNDg z5htQJ60tA^2*#-Z6*9qg0fVMY7ke&XP#AOp%%KBfv9#zcU=I=`6CGV(Y$W2bu@b?t zSaKAiy)zi{F-Nlhh?wH+3KoPSluvPlmz@Rl~Oi*<$ zC>0#ZVzW_s8*~=%1Y$yBK_g*p0ZBmTqgzrSlcB-B>mHX+bo9BFJ;?7nkh_59 z6=#LZ&bZL&25dAGfBJ?iM2;z5A&%W?*b>eF(wYakRBIBUP)O$`ZZ@<)qLqf52N5KC z)p!`%f*H+%{~k11p95KJr@idmHFR&Kw5Td4_n+$}by2x91)UIskBZNR z9I%HMbyVrTI$^vykd(7c^UR|?Gn4*gi`g=0lZK&r)?G$NPSUSD_p`k#z7|A$;}Wl# z?2FBGCm6=)m~~Rx?N9wW*!W9>gEv9P`j-LI(3~X0mfCM;-ysxHb_JQGi^_kKyT!-x z0>UgJZkEkdiDNY0IG7l*Mel5JN==&kxvhUDmGWH9r@!a!{$eJr>Vrl5@J{Y8);em3 zT)JL*kaww9ymw`R!+tChoRPM;=TiMQe2f5{Xb`|&msVW9Gvm`A6H1E~|J4sWfUPL0Z`c=J=%7PM?b>7>8Z-^8`_2m1w z@5b7wwMU7L%SA*~!dOOQg{9(8wnZ~X1&9%?2GBkkkep)X@_Z^Y%U{QCXdFb34oML< zu22~oH8<7U(AH>ZvRP{2XDG37xj(4Gmpo0Zthn4G>hL8eUd~q$;EO$_d|mRMJ!O17 zR);Uu{_2=2zPg9`A`A^Sepfu%uHaCWO+l3!OdVlTJ9P+CX)q~aiU`YgoEpMBRR~)( zg@nbbLzqg3Nrh8In0S~lr=h`Hhr=h^Va|Cfgk=E2=1l$*25pxp!En+t5jAkKQEA|e zRgg|aQ+bm{g0_DngOYv5vMa|!nqI}>mU!4i+Og(ln3EN=>(12aqHbz|0*i9SrR;-xx^r(PX9oZeeV@?UH2RVudj2RUmeibUFvRR zTf3p(CbGD5Q|IsI)@HY^Whj8xR4cinN^gM@nyOJk-3lcbPWnnj-Kp@RIP>0i7XEwP z@}3G*e>7D(d8qdcWl-`O-W#iic+Y3GLy!?6sV1nfZU3c5Ek7B4VO(uNxw~}d<&ODU zb?+B^Sz920{LE7LEt`6DG+^jR-<5#d{XZ2bc~oS$a&1u6Kx2LN%JrQso7u@{0(5<% zPxoBbDYg8|Jo%wn@M)LKz{D>}+oCP}HgyOrjZHTP8*j|k8~Alg>$0q_;7_}zYu4(2 z_(L*j^&aEnRS^sIPg-q+O{zTNZIinLw_WyG9Mw!4uzr7zcOrdL{es3z&*E+`xyaXg zn9x$@Up$SwuIT&BljiALPo#dX-B`CeRF{1+diYLxFqjZSFy)1eQjGSi8N)<35vEL3h z3j5#F5kZGbF3xMWV2TG+^m8ySStl{z>Mt5u1q^B>v=wHRyu`uuGjf(Tzev2Rv zBK<4H^q!A@_VJA@yJ{OO;vIHG6XR2KSPkPa)EsWj}0$);VXE97n$GYSuZXchAuL>49Z! zal4ZLn$d9VK|=*(wd1@C_x$S=TpAS8-*&ibU2~}7B*W<*>FJo|mbU3e+Q5QToy9(Z zP;#H$;gWYgvR&(O@sH?7sUJSx?GfM5Eg3GA$=@oa!7e8gD9!Yu0jll6#dXn8-#!vS2c(X)@8T*=9`&Oi%nD*5+MeLy2R;cDazo@p% zXD{YA;%m+-rHpEj-%jLJ1{a<2J643Q>}u7cH~Y+3M=##<`Ne0ZlErow{8o^#3Ie`y z^F7o$(O}_w{+|{4E_+uiyt3q-odJetkm`5cgc?l_#!b#AY&^PGe93SxU0Y)+>hn(+ zL;c}gU%2(RIbFjpf*O$C`oVva>+AifZseQ(GIz56q(5?4D; N35S!uR*$^${{cQ_{{#R4 diff --git a/dlls/mf/tests/stream2.bin b/dlls/mf/tests/stream2.bin deleted file mode 100644 index 265878cced89f3a465b72e123c8e93a7f49ef1e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4416 zcmeHJdsGzH9iHVSqM+u~AezFMLXgN~_Q7jqPFM*MkEDmFh)L9Oc6OE>o!uE`2H4do zV0>1>X*D3?aTl!-BocC{#2O#qqX`;nTQv&!2qtMNQNWa(ps}*O!?Md_VOjoa|L8fK z+26hQyWjnO-+lamAV@NCDg?gS8YtvwTk465wpx2{rFNeFt}X3&S!65R_N(q5qbyDVN5KTck+2kmoE%Avh1EDoDi8z=q(uWj z%2X#Ta-cOyFvqK&3E8YEe0?A=NZPtVN|tM2Wz-0jEtoi6Tb15;01p za#&BII?@R9xoQx_!z^zCQ^6PGG^jKh0h7Q7)>B4OgNck%FazUoLpF&@<6uI^F?t*W zQ>C!Lku**5AWASMXb1rWM2;RsfCOB#jxms^Od2Vb!djdcFqU6Su_D4oki%k(R?CwD z8YP1T9S3Frq6C;`n6K^dY*fW=5)XmN|+95Fc*iH-vyD=swfiyP6n zM9{$tB#SEGJarzX$Bjb_Vuw0c%TwzBxlEP-gQJ1zz^)s>R>4||rb*FPiUqq3P8L`R zXu@;AK@yJzR0vK!xqUM<)7sy6?RZOl*AnKFN!5J^%`agoxnYuhWf!`X0OL9M*ST~P z@lH4Nx8h@B$C4($^1!K!&b~S!ZSL8v{?L^^=7-X*M|M1hKmA>E$K>;7m52X?o78`u}n;^*l;hdsl zzo;BqcJ9{LttWj`o-{vs{obiPmZUfDz^Yj5%I^!#b(k7X9P&n_U2^m4WNbx2R_1T` z+6#BtCUUtb+Y`;Z``$Na|CzpGh|H19V9-odrC%?T^<4h?`nKjTk8xiu&YI_S{^gsQ z{bAQ7uXOJ`vhrzAFe-=yQx;9@yL55=E_KJqbdnv4NjG*EAhM0Z;u{ZmdgVM0?mn3C z!WNIK$!~h0-+d^jI9RfG{~=4={vpzoE33{Vg@pbIWN!EQnPAK21KX>Z){;eh{E3#O zDc&=(wE62>GS87O_E$aXd3^C+z~v6p=G(F^;zqJa(tBz9z0cqMw)~GHGfG|z_tfmk zzYtKIShS#Svhv8TLqB;ZdfoAr7MD&;4wn)ZVODly}N$}&1M zveF4ktZ@lFFaWj5)h(=6>Gr1k##&vAKI@=YnYX4+i=1g4UCS`pAGnrn(;}K7F;}^k zZOhOm`zVl2yCJ*DN%p1G>F&$!bS>Ma#U}f{`?4RpDci|yOTai}TcQM2oqHQ&iCNvvnyszs_MKMU>92woT`!qk-$3_RF8?{QBctIE=F&E(V5?KA!J^S+dU<1t*0q~D3=iTe(9JnN8W#Kq$s zQSbZwef8)6iVyqZeAkvAm%TlEPw$j={(NA~^zUUUu^$x?nayuMy8TVHPgg|z?S}M^ zA!v4c=hwY489Ti0CflVce)6aIMpdiW_S@@_r!of*nNB!;o%|%H*wf24~mnkcgN|{m_c!J1$DX!6=HF6=aqN5z@Rvd z2VS_TuCUYReD-P*sJC;w0%U-uCO~(m&Ar_5S+laktL3VyR?(PyzC^DoMKT zz^dPe%HO*8eC&!Xjqlx278> 32; - width = frame_size & 0xffffffff; - ok(width == 1920, "got %u.\n", width); - ok(height == 1088, "got %u.\n", height); - IMFMediaType_Release(type); - - output_sample = create_sample(NULL, 0x1000); - hr = check_mft_process_output(transform, output_sample, &output_status); - ok(hr == E_FAIL, "got %#lx\n", hr); - IMFSample_Release(output_sample); - - output_sample = create_sample(NULL, width * height * 3 / 2); - hr = check_mft_process_output(transform, output_sample, &output_status); - ok(hr == S_OK, "got %#lx\n", hr); - IMFSample_Release(output_sample); - - IMFSample_Release(input_sample); - - load_resource(L"stream2.bin", &data1, &data1_len); - i = 0; - input_sample = next_h264_sample(&data1, &data1_len); - while (1) - { - output_sample = create_sample(NULL, width * height * 3 / 2); - hr = check_mft_process_output(transform, output_sample, &output_status); - if (hr != MF_E_TRANSFORM_NEED_MORE_INPUT) break; - - ok(output_status == 0, "got output[0].dwStatus %#lx\n", output_status); - hr = IMFSample_GetTotalLength(output_sample, &length); - ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr); - ok(length == 0, "got length %lu\n", length); - IMFSample_Release(output_sample); - - hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); - ok(hr == S_OK, "got %#lx\n", hr); - IMFSample_Release(input_sample); - input_sample = next_h264_sample(&data1, &data1_len); - - hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); - ok(hr == S_OK, "got %#lx\n", hr); - IMFSample_Release(input_sample); - input_sample = next_h264_sample(&data1, &data1_len); - - i++; - } - trace("i %d.\n", i); - ok(hr == S_OK, "got %#lx\n", hr); - while (hr == S_OK) - { - IMFSample_Release(output_sample); - output_sample = create_sample(NULL, width * height * 3 / 2); - hr = check_mft_process_output(transform, output_sample, &output_status); - } - while (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) - { - hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); - ok(hr == S_OK, "got %#lx\n", hr); - IMFSample_Release(input_sample); - input_sample = next_h264_sample(&data1, &data1_len); - - hr = check_mft_process_output(transform, output_sample, &output_status); - } - - ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "got %#lx\n", hr); - - hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &type); - ok(hr == S_OK, "got %#lx\n", hr); - IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size); - ok(hr == S_OK, "got %#lx\n", hr); - height = frame_size >> 32; - width = frame_size & 0xffffffff; - ok(width == 1280, "got %u.\n", width); - ok(height == 720, "got %u.\n", height); - IMFMediaType_Release(type); - - IMFSample_Release(output_sample); - IMFSample_Release(input_sample); - - IMFTransform_Release(transform); -failed: - CoUninitialize(); -} - START_TEST(transform) { init_functions(); @@ -6652,5 +6485,4 @@ START_TEST(transform) test_color_convert(); test_video_processor(); test_mp3_decoder(); - test_h264_reuse(); } diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 63d27b8bc32..2d9eb57fa6d 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -62,7 +62,6 @@ struct wg_transform bool output_caps_changed; GstCaps *output_caps; bool broken_timestamps; - bool setting_output_format; }; static void align_video_info_planes(gsize plane_align, GstVideoInfo *info, GstVideoAlignment *align) @@ -180,9 +179,6 @@ static gboolean transform_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery GstCaps *caps, *filter, *temp; gchar *str; - if (!transform->setting_output_format) - return gst_pad_query_default(pad, parent, query); - gst_query_parse_caps(query, &filter); caps = gst_caps_ref(transform->output_caps); @@ -222,7 +218,6 @@ static gboolean transform_sink_event_cb(GstPad *pad, GstObject *parent, GstEvent { GstCaps *caps; - transform->setting_output_format = false; gst_event_parse_caps(event, &caps); transform->output_caps_changed = transform->output_caps_changed @@ -534,8 +529,6 @@ NTSTATUS wg_transform_set_output_format(void *args) gst_caps_unref(transform->output_caps); transform->output_caps = caps; - transform->setting_output_format = true; - if (transform->video_flip) { const char *value; From ff374a7e986a2dc6a219764008a1b93376a0a315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 23:01:29 +0200 Subject: [PATCH 2022/2777] Revert "winegstreamer: Don't pre-check sample size in wg_transform_read_mf()." This reverts commit 6af55bf56157767b8c8d6c8a4415aa45589be6f2. CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/winegstreamer/wg_sample.c | 5 ++++ dlls/winegstreamer/wg_transform.c | 48 +++++++++++-------------------- 2 files changed, 22 insertions(+), 31 deletions(-) diff --git a/dlls/winegstreamer/wg_sample.c b/dlls/winegstreamer/wg_sample.c index 1278ccf7347..d20583bdb22 100644 --- a/dlls/winegstreamer/wg_sample.c +++ b/dlls/winegstreamer/wg_sample.c @@ -353,6 +353,11 @@ HRESULT wg_transform_read_mf(struct wg_transform *transform, IMFSample *sample, return hr; wg_sample->size = 0; + if (wg_sample->max_size < sample_size) + { + wg_sample_release(wg_sample); + return MF_E_BUFFERTOOSMALL; + } if (FAILED(hr = wg_transform_read_data(transform, wg_sample, format))) { diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 2d9eb57fa6d..c8f292e60d5 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -654,19 +654,19 @@ NTSTATUS wg_transform_push_data(void *args) return STATUS_SUCCESS; } -static NTSTATUS copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_align, +static bool copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_align, struct wg_sample *sample, gsize *total_size) { - NTSTATUS status = STATUS_UNSUCCESSFUL; GstVideoFrame src_frame, dst_frame; GstVideoInfo src_info, dst_info; GstVideoAlignment align; GstBuffer *dst_buffer; + bool ret = false; if (!gst_video_info_from_caps(&src_info, caps)) { GST_ERROR("Failed to get video info from caps."); - return STATUS_UNSUCCESSFUL; + return false; } dst_info = src_info; @@ -675,14 +675,14 @@ static NTSTATUS copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_ if (sample->max_size < dst_info.size) { GST_ERROR("Output buffer is too small."); - return STATUS_BUFFER_TOO_SMALL; + return false; } if (!(dst_buffer = gst_buffer_new_wrapped_full(0, sample->data, sample->max_size, 0, sample->max_size, 0, NULL))) { GST_ERROR("Failed to wrap wg_sample into GstBuffer"); - return STATUS_UNSUCCESSFUL; + return false; } gst_buffer_set_size(dst_buffer, dst_info.size); *total_size = sample->size = dst_info.size; @@ -695,9 +695,7 @@ static NTSTATUS copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_ GST_ERROR("Failed to map destination frame."); else { - if (gst_video_frame_copy(&dst_frame, &src_frame)) - status = STATUS_SUCCESS; - else + if (!(ret = gst_video_frame_copy(&dst_frame, &src_frame))) GST_ERROR("Failed to copy video frame."); gst_video_frame_unmap(&dst_frame); } @@ -705,16 +703,16 @@ static NTSTATUS copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_ } gst_buffer_unref(dst_buffer); - return status; + return ret; } -static NTSTATUS copy_buffer(GstBuffer *buffer, GstCaps *caps, struct wg_sample *sample, +static bool copy_buffer(GstBuffer *buffer, GstCaps *caps, struct wg_sample *sample, gsize *total_size) { GstMapInfo info; if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) - return STATUS_UNSUCCESSFUL; + return false; if (sample->max_size >= info.size) sample->size = info.size; @@ -731,16 +729,15 @@ static NTSTATUS copy_buffer(GstBuffer *buffer, GstCaps *caps, struct wg_sample * gst_buffer_resize(buffer, sample->size, -1); *total_size = info.size; - return STATUS_SUCCESS; + return true; } static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsize plane_align, struct wg_sample *sample) { + bool ret, needs_copy; gsize total_size; - bool needs_copy; GstMapInfo info; - NTSTATUS status; if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) { @@ -751,24 +748,18 @@ static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsi needs_copy = info.data != sample->data; gst_buffer_unmap(buffer, &info); - if (!needs_copy) - { + if ((ret = !needs_copy)) total_size = sample->size = info.size; - status = STATUS_SUCCESS; - } + else if (stream_type_from_caps(caps) == GST_STREAM_TYPE_VIDEO) + ret = copy_video_buffer(buffer, caps, plane_align, sample, &total_size); else - { - if (stream_type_from_caps(caps) == GST_STREAM_TYPE_VIDEO) - status = copy_video_buffer(buffer, caps, plane_align, sample, &total_size); - else - status = copy_buffer(buffer, caps, sample, &total_size); - } + ret = copy_buffer(buffer, caps, sample, &total_size); - if (status) + if (!ret) { GST_ERROR("Failed to copy buffer %p", buffer); sample->size = 0; - return status; + return STATUS_UNSUCCESSFUL; } if (GST_BUFFER_PTS_IS_VALID(buffer)) @@ -905,11 +896,6 @@ NTSTATUS wg_transform_read_data(void *args) if ((status = read_transform_output_data(output_buffer, output_caps, transform->output_plane_align, sample))) { - if (status == STATUS_BUFFER_TOO_SMALL) - { - status = 0; - params->result = E_FAIL; - } wg_allocator_release_sample(transform->allocator, sample, false); return status; } From a03b70be62e5ae5db9f0483292e0c83d95b63c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 23:07:55 +0200 Subject: [PATCH 2023/2777] Revert "winegstreamer: Implement MFT_MESSAGE_COMMAND_DRAIN for wma decoder." This reverts commit 051fd7938d4e0a59872ab18cae9fbe957c889a62. CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/winegstreamer/wma_decoder.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 9354822e45c..10a41a0c92f 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -522,18 +522,7 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - struct wma_decoder *decoder = impl_from_IMFTransform(iface); - - TRACE("iface %p, message %#x, param %p.\n", iface, message, (void *)param); - - if (!decoder->wg_transform) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - if (message == MFT_MESSAGE_COMMAND_DRAIN) - return wg_transform_drain(decoder->wg_transform); - - FIXME("Ignoring message %#x.\n", message); - + FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); return S_OK; } From 56578eb660c786ce14bd2deb7d2eb6180d068c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 23:07:57 +0200 Subject: [PATCH 2024/2777] Revert "winegstreamer: Implement MFT_MESSAGE_COMMAND_DRAIN for video processor." This reverts commit 6b04b251a08801467ffc36da2afd4f02c1ac5ea4. CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/winegstreamer/video_processor.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index d8ef51b7bf2..21bc46b0bb3 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -505,18 +505,7 @@ static HRESULT WINAPI video_processor_ProcessEvent(IMFTransform *iface, DWORD id static HRESULT WINAPI video_processor_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - struct video_processor *impl = impl_from_IMFTransform(iface); - - TRACE("iface %p, message %#x, param %p.\n", iface, message, (void *)param); - - if (!impl->wg_transform) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - if (message == MFT_MESSAGE_COMMAND_DRAIN) - return wg_transform_drain(impl->wg_transform); - - FIXME("Ignoring message %#x.\n", message); - + FIXME("iface %p, message %#x, param %#Ix stub!\n", iface, message, param); return S_OK; } From e5c41d3ef82ce53eedf02bf8cb3cb0a02504a86d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 23:08:00 +0200 Subject: [PATCH 2025/2777] Revert "winegstreamer: Implement MFT_MESSAGE_COMMAND_DRAIN for resampler." This reverts commit 0799ee446e37cbc69c0078f952b3b89552f39465. CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/winegstreamer/resampler.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c index c4efd5fb82c..88e9727ff21 100644 --- a/dlls/winegstreamer/resampler.c +++ b/dlls/winegstreamer/resampler.c @@ -505,18 +505,7 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - struct resampler *impl = impl_from_IMFTransform(iface); - - TRACE("iface %p, message %#x, param %p.\n", iface, message, (void *)param); - - if (!impl->wg_transform) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - if (message == MFT_MESSAGE_COMMAND_DRAIN) - return wg_transform_drain(impl->wg_transform); - - FIXME("Ignoring message %#x.\n", message); - + FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); return S_OK; } From 4742e916306e52c3b4cfba2ad53fe5582765d1c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 23:08:10 +0200 Subject: [PATCH 2026/2777] Revert "winegstreamer: Implement MFT_MESSAGE_COMMAND_DRAIN for aac decoder." This reverts commit 37e94ecce5752e10842601d8a30dd971ad1348a7. CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/mf/tests/transform.c | 13 ++----------- dlls/winegstreamer/aac_decoder.c | 13 +------------ 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 476d385f862..acd9439b6b1 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -2470,17 +2470,8 @@ static void test_aac_decoder_subtype(const struct attribute_desc *input_type_des hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0); ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr); - flags = 0xdeadbeef; - hr = IMFTransform_GetInputStatus(transform, 0, &flags); - ok(hr == S_OK, "Got %#lx\n", hr); - ok(!flags, "Got flags %#lx.\n", flags); - if (0) - { - /* This is fine on Windows but currently MFT_MESSAGE_COMMAND_DRAIN removes input sample from the queue - * and makes next _ProcessInput succeed on Wine breaking the tests below. */ - hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); - ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr); - } + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr); hr = MFCreateCollection(&output_samples); ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr); diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index 3be7e91147f..d79ede69c9d 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -534,18 +534,7 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - struct aac_decoder *decoder = impl_from_IMFTransform(iface); - - TRACE("iface %p, message %#x, param %p.\n", iface, message, (void *)param); - - if (!decoder->wg_transform) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - if (message == MFT_MESSAGE_COMMAND_DRAIN) - return wg_transform_drain(decoder->wg_transform); - - FIXME("Ignoring message %#x.\n", message); - + FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); return S_OK; } From c9550922b08cf0de236f8f83586ab3edac24a2bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 23:08:58 +0200 Subject: [PATCH 2027/2777] Revert "winegstreamer: Implement MFT_MESSAGE_COMMAND_DRAIN for h264 transform." This reverts commit fa28d88d4ffe78448fbdd27b37633628a37f7bf5. CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/mf/tests/transform.c | 1 + dlls/winegstreamer/gst_private.h | 1 - dlls/winegstreamer/h264_decoder.c | 13 +------- dlls/winegstreamer/main.c | 12 -------- dlls/winegstreamer/unix_private.h | 1 - dlls/winegstreamer/unixlib.h | 6 ---- dlls/winegstreamer/wg_parser.c | 1 - dlls/winegstreamer/wg_transform.c | 49 ------------------------------- 8 files changed, 2 insertions(+), 82 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index acd9439b6b1..d3dca90cdf7 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -3700,6 +3700,7 @@ static void test_h264_decoder(void) ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr); } ok(i == 2, "got %lu iterations\n", i); + todo_wine ok(h264_encoded_data_len == 1180, "got h264_encoded_data_len %lu\n", h264_encoded_data_len); ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "ProcessOutput returned %#lx\n", hr); ok(output_status == MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE, "got output[0].dwStatus %#lx\n", output_status); diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 81aefe4234f..e2c32d12b64 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -105,7 +105,6 @@ struct wg_transform *wg_transform_create(const struct wg_format *input_format, void wg_transform_destroy(struct wg_transform *transform); bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_format *format); bool wg_transform_get_status(struct wg_transform *transform, bool *accepts_input); -HRESULT wg_transform_drain(struct wg_transform *transform); struct wg_source *wg_source_create(const WCHAR *url, uint64_t file_size, const void *data, uint32_t size, WCHAR mime_type[256]); diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index a1d70eb5733..3088f2f7837 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -582,18 +582,7 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - - TRACE("iface %p, message %#x, param %Ix.\n", iface, message, param); - - if (!decoder->wg_transform) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - if (message == MFT_MESSAGE_COMMAND_DRAIN) - return wg_transform_drain(decoder->wg_transform); - - FIXME("Ignoring message %#x.\n", message); - + FIXME("iface %p, message %#x, param %Ix stub!\n", iface, message, param); return S_OK; } diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index df7f123aaee..5cbaf49e38a 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -415,18 +415,6 @@ bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_fo return !WINE_UNIX_CALL(unix_wg_transform_set_output_format, ¶ms); } -HRESULT wg_transform_drain(struct wg_transform *transform) -{ - struct wg_transform_drain_params params = - { - .transform = transform, - }; - - TRACE("transform %p.\n", transform); - - return WINE_UNIX_CALL(unix_wg_transform_drain, ¶ms); -} - struct wg_source *wg_source_create(const WCHAR *url, uint64_t file_size, const void *data, uint32_t size, WCHAR mime_type[256]) { diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 1f4ebf0a2df..025ef83ed99 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -66,7 +66,6 @@ extern NTSTATUS wg_transform_set_output_format(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_get_status(void *args) DECLSPEC_HIDDEN; -extern NTSTATUS wg_transform_drain(void *args) DECLSPEC_HIDDEN; /* wg_source.c */ diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 175538ad147..660a32374e2 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -332,11 +332,6 @@ struct wg_transform_get_status_params UINT32 accepts_input; }; -struct wg_transform_drain_params -{ - struct wg_transform *transform; -}; - struct wg_source_create_params { const char *url; @@ -414,7 +409,6 @@ enum unix_funcs unix_wg_transform_push_data, unix_wg_transform_read_data, unix_wg_transform_get_status, - unix_wg_transform_drain, unix_wg_source_create, unix_wg_source_destroy, diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index eb928059a7a..ee612a4f74f 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1918,7 +1918,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_transform_push_data), X(wg_transform_read_data), X(wg_transform_get_status), - X(wg_transform_drain), X(wg_source_create), X(wg_source_destroy), diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index c8f292e60d5..8bc0507b760 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -85,11 +85,6 @@ static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, Gst GST_LOG("transform %p, buffer %p.", transform, buffer); - if (GST_BUFFER_PTS_IS_VALID(buffer)) - transform->segment.start = GST_BUFFER_PTS(buffer); - else if (GST_BUFFER_DURATION_IS_VALID(buffer)) - transform->segment.start += GST_BUFFER_DURATION(buffer); - if (!(sample = gst_sample_new(buffer, transform->output_caps, NULL, NULL))) { GST_ERROR("Failed to allocate transform %p output sample.", transform); @@ -561,50 +556,6 @@ NTSTATUS wg_transform_set_output_format(void *args) return STATUS_SUCCESS; } -NTSTATUS wg_transform_drain(void *args) -{ - struct wg_transform_drain_params *params = args; - struct wg_transform *transform = params->transform; - GstBuffer *input_buffer; - GstFlowReturn ret; - GstEvent *event; - - - while ((input_buffer = gst_atomic_queue_pop(transform->input_queue))) - { - if ((ret = gst_pad_push(transform->my_src, input_buffer))) - { - GST_ERROR("Failed to push transform input, error %d", ret); - return S_OK; - } - } - - if (!gst_pad_peer_query(transform->my_src, transform->drain_query)) - { - GST_ERROR("Drain query failed, transform %p.", transform); - return MF_E_STREAM_ERROR; - } - if (!(event = gst_event_new_segment_done(GST_FORMAT_TIME, transform->segment.start)) - || !gst_pad_push_event(transform->my_src, event)) - { - GST_ERROR("Sending segment done event failed, transform %p.", transform); - return MF_E_STREAM_ERROR; - } - if (!gst_pad_peer_query(transform->my_src, transform->drain_query)) - { - GST_ERROR("Drain query failed, transform %p.", transform); - return MF_E_STREAM_ERROR; - } - if (!(event = gst_event_new_segment(&transform->segment)) - || !gst_pad_push_event(transform->my_src, event)) - { - GST_ERROR("Sending new segment event failed, transform %p.", transform); - return MF_E_STREAM_ERROR; - } - - return S_OK; -} - static void wg_sample_free_notify(void *arg) { struct wg_sample *sample = arg; From cb797cba7abb15246ba8b24791c26ec45b57fbae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 23:10:49 +0200 Subject: [PATCH 2028/2777] Revert "HACK: winegstreamer: Fake H264 timestamps if framerate cannot be trusted." This reverts commit 0486aee9fe84dbb3ba650747df0f8de7c0c2acb4. CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/winegstreamer/h264_decoder.c | 18 +----------------- dlls/winegstreamer/wg_transform.c | 9 ++------- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 3088f2f7837..439701098ad 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -58,8 +58,6 @@ struct h264_decoder IMFMediaType *output_type; MFT_OUTPUT_STREAM_INFO output_info; - UINT64 last_pts; - struct wg_format wg_format; struct wg_transform *wg_transform; struct wg_sample_queue *wg_sample_queue; @@ -75,7 +73,6 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) struct wg_format input_format; struct wg_format output_format; - decoder->last_pts = 0; if (decoder->wg_transform) wg_transform_destroy(decoder->wg_transform); decoder->wg_transform = NULL; @@ -602,10 +599,9 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { struct h264_decoder *decoder = impl_from_IMFTransform(iface); - UINT64 frame_rate, duration; struct wg_format wg_format; UINT32 sample_size; - LONGLONG time; + UINT64 frame_rate; GUID subtype; HRESULT hr; @@ -629,20 +625,8 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample, sample_size, &wg_format, &samples->dwStatus))) - { wg_sample_queue_flush(decoder->wg_sample_queue, false); - if (FAILED(IMFSample_GetSampleTime(samples->pSample, &time)) - || FAILED(IMFSample_GetSampleDuration(samples->pSample, &time))) - { - frame_rate = (UINT64)decoder->wg_format.u.video.fps_n << 32 | decoder->wg_format.u.video.fps_d; - duration = (UINT64)10000000 * (UINT32)frame_rate / (frame_rate >> 32); - IMFSample_SetSampleTime(samples->pSample, decoder->last_pts); - IMFSample_SetSampleDuration(samples->pSample, duration); - decoder->last_pts += duration; - } - } - if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { decoder->wg_format = wg_format; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 8bc0507b760..7a0e4876dc4 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -61,7 +61,6 @@ struct wg_transform GstSample *output_sample; bool output_caps_changed; GstCaps *output_caps; - bool broken_timestamps; }; static void align_video_info_planes(gsize plane_align, GstVideoInfo *info, GstVideoAlignment *align) @@ -338,10 +337,9 @@ NTSTATUS wg_transform_create(void *args) */ transform->input_max_length = 16; transform->output_plane_align = 15; - if ((element = create_element("h264parse", "base")) - && !append_element(transform->container, element, &first, &last)) + if (!(element = create_element("h264parse", "base")) + || !append_element(transform->container, element, &first, &last)) goto out; - transform->broken_timestamps = !element; /* fallthrough */ case WG_MAJOR_TYPE_AUDIO_MPEG1: case WG_MAJOR_TYPE_AUDIO_MPEG4: @@ -874,9 +872,6 @@ NTSTATUS wg_transform_read_data(void *args) transform->output_sample = NULL; } - if (transform->broken_timestamps) - sample->flags &= ~(WG_SAMPLE_FLAG_HAS_PTS|WG_SAMPLE_FLAG_HAS_DURATION); - params->result = S_OK; wg_allocator_release_sample(transform->allocator, sample, discard_data); return STATUS_SUCCESS; From 1ee413c5d9f6b97b390e966378ea8314d960ef4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 17 May 2023 14:23:37 +0200 Subject: [PATCH 2029/2777] winegstreamer: Forbid vaapidecodebin when looking for a specific element. This will eventually fallback to vaapih264dec and similar decoders if VA-API plugins are indeed available. (cherry picked from commit 0c760ef70de7be47684de82fcd5dc7e71aeb3e22) CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/winegstreamer/unixlib.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dlls/winegstreamer/unixlib.c b/dlls/winegstreamer/unixlib.c index 77f8dda0928..346adec81f8 100644 --- a/dlls/winegstreamer/unixlib.c +++ b/dlls/winegstreamer/unixlib.c @@ -106,6 +106,16 @@ GstElement *find_element(GstElementFactoryListType type, GstCaps *src_caps, GstC for (tmp = transforms; tmp != NULL && element == NULL; tmp = tmp->next) { name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(tmp->data)); + + if (!strcmp(name, "vaapidecodebin")) + { + /* vaapidecodebin adds asynchronicity which breaks wg_transform synchronous drain / flush + * requirements. Ignore it and use VA-API decoders directly instead. + */ + GST_WARNING("Ignoring vaapidecodebin decoder."); + continue; + } + if (!(element = gst_element_factory_create(GST_ELEMENT_FACTORY(tmp->data), NULL))) GST_WARNING("Failed to create %s element.", name); } From 9785379c71333de1e9d620e283a1a6129045b0f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 24 May 2023 09:38:10 +0200 Subject: [PATCH 2030/2777] winegstreamer: Only warn on wg_transform input buffer push errors. Some GStreamer plugins such as openh264 return spurious errors when running the tests. They pass the tests successfull if we simply ignore them. It does not make much difference with returning the error, as they are not supposed to happen anyway, and most of the time the MFT clients don't expect or handle errors. (cherry picked from commit 2a2ed45566eb29c6bef7a610d52f25f65542a9a2) CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/winegstreamer/wg_transform.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 7a0e4876dc4..27f61ddc9df 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -750,30 +750,25 @@ static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsi static bool get_transform_output(struct wg_transform *transform, struct wg_sample *sample) { - GstFlowReturn ret = GST_FLOW_OK; GstBuffer *input_buffer; + GstFlowReturn ret; /* Provide the sample for transform_request_sample to pick it up */ InterlockedIncrement(&sample->refcount); InterlockedExchangePointer((void **)&transform->output_wg_sample, sample); - while (!(transform->output_sample = gst_atomic_queue_pop(transform->output_queue))) + while (!(transform->output_sample = gst_atomic_queue_pop(transform->output_queue)) + && (input_buffer = gst_atomic_queue_pop(transform->input_queue))) { - if (!(input_buffer = gst_atomic_queue_pop(transform->input_queue))) - break; - if ((ret = gst_pad_push(transform->my_src, input_buffer))) - { - GST_ERROR("Failed to push transform input, error %d", ret); - break; - } + GST_WARNING("Failed to push transform input, error %d", ret); } /* Remove the sample so transform_request_sample cannot use it */ if (InterlockedExchangePointer((void **)&transform->output_wg_sample, NULL)) InterlockedDecrement(&sample->refcount); - return ret == GST_FLOW_OK; + return !!transform->output_sample; } NTSTATUS wg_transform_read_data(void *args) @@ -788,12 +783,6 @@ NTSTATUS wg_transform_read_data(void *args) NTSTATUS status; if (!transform->output_sample && !get_transform_output(transform, sample)) - { - wg_allocator_release_sample(transform->allocator, sample, false); - return STATUS_UNSUCCESSFUL; - } - - if (!transform->output_sample) { sample->size = 0; params->result = MF_E_TRANSFORM_NEED_MORE_INPUT; From 27439540977cfb79b9c2f7152c35a6ac21fc0613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 25 May 2023 15:21:18 +0200 Subject: [PATCH 2031/2777] winegstreamer: Set the default H264 caps profile to "baseline". Some elements such as openh264dec require it to be present. (cherry picked from commit 34b990fe176672a46a63864b6e121ba88ffecb7e) CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/winegstreamer/wg_format.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 9507d6475b0..5ab2665f38d 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -529,11 +529,10 @@ static GstCaps *wg_format_to_caps_video_h264(const struct wg_format *format) GST_FIXME("H264 profile attribute %u not implemented.", format->u.video_h264.profile); /* fallthrough */ case eAVEncH264VProfile_unknown: - profile = NULL; + profile = "baseline"; break; } - if (profile) - gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL); + gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL); switch (format->u.video_h264.level) { From cd35124a4203ce5fce5bb11a887d98ec47a97122 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 31 Mar 2023 19:16:59 -0600 Subject: [PATCH 2032/2777] winegstreamer: Process MFT_MESSAGE_SET_D3D_MANAGER in h264 decoder. (cherry picked from commit 3f2ff939a10bc9ec14172d2798ea6f02e73048d2) CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/winegstreamer/h264_decoder.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 439701098ad..211e5faea88 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -61,6 +61,8 @@ struct h264_decoder struct wg_format wg_format; struct wg_transform *wg_transform; struct wg_sample_queue *wg_sample_queue; + + IMFVideoSampleAllocatorEx *allocator; }; static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) @@ -240,6 +242,7 @@ static ULONG WINAPI transform_Release(IMFTransform *iface) if (!refcount) { + IMFVideoSampleAllocatorEx_Release(decoder->allocator); if (decoder->wg_transform) wg_transform_destroy(decoder->wg_transform); if (decoder->input_type) @@ -250,7 +253,6 @@ static ULONG WINAPI transform_Release(IMFTransform *iface) IMFAttributes_Release(decoder->output_attributes); if (decoder->attributes) IMFAttributes_Release(decoder->attributes); - wg_sample_queue_destroy(decoder->wg_sample_queue); free(decoder); } @@ -579,7 +581,14 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - FIXME("iface %p, message %#x, param %Ix stub!\n", iface, message, param); + struct h264_decoder *decoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, message %#x, param %Ix.\n", iface, message, param); + + if (message == MFT_MESSAGE_SET_D3D_MANAGER) + return IMFVideoSampleAllocatorEx_SetDirectXManager(decoder->allocator, (IUnknown *)param); + + FIXME("Ignoring message %#x.\n", message); return S_OK; } @@ -731,12 +740,16 @@ HRESULT h264_decoder_create(REFIID riid, void **ret) goto failed; if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue))) goto failed; + if (FAILED(hr = MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&decoder->allocator))) + goto failed; *ret = &decoder->IMFTransform_iface; TRACE("Created decoder %p\n", *ret); return S_OK; failed: + if (decoder->wg_sample_queue) + wg_sample_queue_destroy(decoder->wg_sample_queue); if (decoder->output_attributes) IMFAttributes_Release(decoder->output_attributes); if (decoder->attributes) From 270f32f77c79148bc73cd873373ee88fd0e3cdca Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 31 Mar 2023 20:08:19 -0600 Subject: [PATCH 2033/2777] winegstreamer: Provide samples if DXGI device manager is set in h264 decoder. (cherry picked from commit a208589b2732f852d741b14b920714fba390c952) CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/winegstreamer/h264_decoder.c | 63 +++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 211e5faea88..a04f49abd0e 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -63,6 +63,7 @@ struct h264_decoder struct wg_sample_queue *wg_sample_queue; IMFVideoSampleAllocatorEx *allocator; + BOOL allocator_initialized; }; static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) @@ -203,6 +204,26 @@ static HRESULT fill_output_media_type(struct h264_decoder *decoder, IMFMediaType return S_OK; } +static HRESULT init_allocator(struct h264_decoder *decoder) +{ + HRESULT hr; + + if (decoder->allocator_initialized) + return S_OK; + + if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(decoder->allocator, 10, 10, + decoder->attributes, decoder->output_type))) + return hr; + decoder->allocator_initialized = TRUE; + return S_OK; +} + +static void uninit_allocator(struct h264_decoder *decoder) +{ + IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(decoder->allocator); + decoder->allocator_initialized = FALSE; +} + static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) { struct h264_decoder *decoder = impl_from_IMFTransform(iface); @@ -582,11 +603,22 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { struct h264_decoder *decoder = impl_from_IMFTransform(iface); + HRESULT hr; TRACE("iface %p, message %#x, param %Ix.\n", iface, message, param); if (message == MFT_MESSAGE_SET_D3D_MANAGER) - return IMFVideoSampleAllocatorEx_SetDirectXManager(decoder->allocator, (IUnknown *)param); + { + if (FAILED(hr = IMFVideoSampleAllocatorEx_SetDirectXManager(decoder->allocator, (IUnknown *)param))) + return hr; + + uninit_allocator(decoder); + if (param) + decoder->output_info.dwFlags |= MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; + else + decoder->output_info.dwFlags &= ~MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; + return S_OK; + } FIXME("Ignoring message %#x.\n", message); return S_OK; @@ -610,6 +642,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, struct h264_decoder *decoder = impl_from_IMFTransform(iface); struct wg_format wg_format; UINT32 sample_size; + IMFSample *sample; UINT64 frame_rate; GUID subtype; HRESULT hr; @@ -623,7 +656,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, return MF_E_TRANSFORM_TYPE_NOT_SET; *status = samples->dwStatus = 0; - if (!samples->pSample) + if (!(sample = samples->pSample) && !(decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES)) return E_INVALIDARG; if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype))) @@ -632,7 +665,21 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, decoder->wg_format.u.video.height, &sample_size))) return hr; - if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample, + if (decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) + { + if (FAILED(hr = init_allocator(decoder))) + { + ERR("Failed to initialize allocator, hr %#lx.\n", hr); + return hr; + } + if (FAILED(hr = IMFVideoSampleAllocatorEx_AllocateSample(decoder->allocator, &sample))) + { + ERR("Failed to allocate sample, hr %#lx.\n", hr); + return hr; + } + } + + if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, sample, sample_size, &wg_format, &samples->dwStatus))) wg_sample_queue_flush(decoder->wg_sample_queue, false); @@ -651,6 +698,16 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; + + uninit_allocator(decoder); + } + + if (decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) + { + if (hr == S_OK) + samples->pSample = sample; + else + IMFSample_Release(sample); } return hr; From 12475199ed86d8ec104505da73758a6f244292b3 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 4 Apr 2023 18:14:48 -0600 Subject: [PATCH 2034/2777] winegstreamer: Pass temporary sample to wg_transform_read_mf() in h264 decoder. (cherry picked from commit 17c86f42de494620efb133ab471bb1b0b8ef9d0d) CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/winegstreamer/Makefile.in | 2 +- dlls/winegstreamer/h264_decoder.c | 69 +++++++++++++++++++++++++++---- 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index d811cfd810c..7624948dba8 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -2,7 +2,7 @@ MODULE = winegstreamer.dll UNIXLIB = winegstreamer.so IMPORTLIB = winegstreamer IMPORTS = strmbase ole32 oleaut32 msdmo -DELAYIMPORTS = mfplat +DELAYIMPORTS = mfplat mf UNIX_CFLAGS = $(GSTREAMER_CFLAGS) UNIX_LIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index a04f49abd0e..c8b72eb9c26 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -64,6 +64,8 @@ struct h264_decoder IMFVideoSampleAllocatorEx *allocator; BOOL allocator_initialized; + IMFTransform *copier; + IMFMediaBuffer *temp_buffer; }; static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) @@ -211,6 +213,11 @@ static HRESULT init_allocator(struct h264_decoder *decoder) if (decoder->allocator_initialized) return S_OK; + if (FAILED(hr = IMFTransform_SetInputType(decoder->copier, 0, decoder->output_type, 0))) + return hr; + if (FAILED(hr = IMFTransform_SetOutputType(decoder->copier, 0, decoder->output_type, 0))) + return hr; + if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(decoder->allocator, 10, 10, decoder->attributes, decoder->output_type))) return hr; @@ -263,7 +270,10 @@ static ULONG WINAPI transform_Release(IMFTransform *iface) if (!refcount) { + IMFTransform_Release(decoder->copier); IMFVideoSampleAllocatorEx_Release(decoder->allocator); + if (decoder->temp_buffer) + IMFMediaBuffer_Release(decoder->temp_buffer); if (decoder->wg_transform) wg_transform_destroy(decoder->wg_transform); if (decoder->input_type) @@ -636,6 +646,36 @@ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFS return wg_transform_push_mf(decoder->wg_transform, sample, decoder->wg_sample_queue); } +static HRESULT output_sample(struct h264_decoder *decoder, IMFSample **out, IMFSample *src_sample) +{ + MFT_OUTPUT_DATA_BUFFER output[1]; + IMFSample *sample; + DWORD status; + HRESULT hr; + + if (FAILED(hr = init_allocator(decoder))) + { + ERR("Failed to initialize allocator, hr %#lx.\n", hr); + return hr; + } + if (FAILED(hr = IMFVideoSampleAllocatorEx_AllocateSample(decoder->allocator, &sample))) + return hr; + + if (FAILED(hr = IMFTransform_ProcessInput(decoder->copier, 0, src_sample, 0))) + { + IMFSample_Release(sample); + return hr; + } + output[0].pSample = sample; + if (FAILED(hr = IMFTransform_ProcessOutput(decoder->copier, 0, 1, output, &status))) + { + IMFSample_Release(sample); + return hr; + } + *out = sample; + return S_OK; +} + static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { @@ -645,6 +685,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, IMFSample *sample; UINT64 frame_rate; GUID subtype; + DWORD size; HRESULT hr; TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); @@ -667,14 +708,21 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, if (decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) { - if (FAILED(hr = init_allocator(decoder))) + if (decoder->temp_buffer) { - ERR("Failed to initialize allocator, hr %#lx.\n", hr); - return hr; + if (FAILED(IMFMediaBuffer_GetMaxLength(decoder->temp_buffer, &size)) || size < sample_size) + { + IMFMediaBuffer_Release(decoder->temp_buffer); + decoder->temp_buffer = NULL; + } } - if (FAILED(hr = IMFVideoSampleAllocatorEx_AllocateSample(decoder->allocator, &sample))) + if (!decoder->temp_buffer && FAILED(hr = MFCreateMemoryBuffer(sample_size, &decoder->temp_buffer))) + return hr; + if (FAILED(hr = MFCreateSample(&sample))) + return hr; + if (FAILED(hr = IMFSample_AddBuffer(sample, decoder->temp_buffer))) { - ERR("Failed to allocate sample, hr %#lx.\n", hr); + IMFSample_Release(sample); return hr; } } @@ -704,10 +752,9 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, if (decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) { - if (hr == S_OK) - samples->pSample = sample; - else - IMFSample_Release(sample); + if (hr == S_OK && FAILED(hr = output_sample(decoder, &samples->pSample, sample))) + ERR("Failed to output sample, hr %#lx.\n", hr); + IMFSample_Release(sample); } return hr; @@ -799,12 +846,16 @@ HRESULT h264_decoder_create(REFIID riid, void **ret) goto failed; if (FAILED(hr = MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&decoder->allocator))) goto failed; + if (FAILED(hr = MFCreateSampleCopierMFT(&decoder->copier))) + goto failed; *ret = &decoder->IMFTransform_iface; TRACE("Created decoder %p\n", *ret); return S_OK; failed: + if (decoder->allocator) + IMFVideoSampleAllocatorEx_Release(decoder->allocator); if (decoder->wg_sample_queue) wg_sample_queue_destroy(decoder->wg_sample_queue); if (decoder->output_attributes) From 14a4c867955906dae5df3b5932928b3fa2c06ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 25 May 2023 13:39:33 +0200 Subject: [PATCH 2035/2777] winegstreamer: Use an IMFMediaType for the internal stream type. (cherry picked from commit 8caaca177e7b3545296a099a0dd43a375cb13cdf) CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/winegstreamer/h264_decoder.c | 92 ++++++++++++++++--------------- 1 file changed, 49 insertions(+), 43 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index c8b72eb9c26..8eeeb52fd60 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -57,8 +57,8 @@ struct h264_decoder MFT_INPUT_STREAM_INFO input_info; IMFMediaType *output_type; MFT_OUTPUT_STREAM_INFO output_info; + IMFMediaType *stream_type; - struct wg_format wg_format; struct wg_transform *wg_transform; struct wg_sample_queue *wg_sample_queue; @@ -107,8 +107,8 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) static HRESULT fill_output_media_type(struct h264_decoder *decoder, IMFMediaType *media_type) { IMFMediaType *default_type = decoder->output_type; - struct wg_format *wg_format = &decoder->wg_format; UINT32 value, width, height; + MFVideoArea aperture; UINT64 ratio; GUID subtype; HRESULT hr; @@ -118,7 +118,8 @@ static HRESULT fill_output_media_type(struct h264_decoder *decoder, IMFMediaType if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &ratio))) { - ratio = (UINT64)wg_format->u.video.width << 32 | wg_format->u.video.height; + if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &ratio))) + ratio = (UINT64)1920 << 32 | 1080; if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ratio))) return hr; } @@ -127,14 +128,16 @@ static HRESULT fill_output_media_type(struct h264_decoder *decoder, IMFMediaType if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FRAME_RATE, NULL))) { - ratio = (UINT64)wg_format->u.video.fps_n << 32 | wg_format->u.video.fps_d; + if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, &ratio))) + ratio = (UINT64)30000 << 32 | 1001; if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, ratio))) return hr; } if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL))) { - ratio = (UINT64)1 << 32 | 1; /* FIXME: read it from format */ + if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_PIXEL_ASPECT_RATIO, &ratio))) + ratio = (UINT64)1 << 32 | 1; if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio))) return hr; } @@ -188,16 +191,9 @@ static HRESULT fill_output_media_type(struct h264_decoder *decoder, IMFMediaType } if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL)) - && !IsRectEmpty(&wg_format->u.video.padding)) + && SUCCEEDED(hr = IMFMediaType_GetBlob(decoder->stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, + (BYTE *)&aperture, sizeof(aperture), &value))) { - MFVideoArea aperture = - { - .OffsetX = {.value = wg_format->u.video.padding.left}, - .OffsetY = {.value = wg_format->u.video.padding.top}, - .Area.cx = wg_format->u.video.width - wg_format->u.video.padding.right - wg_format->u.video.padding.left, - .Area.cy = wg_format->u.video.height - wg_format->u.video.padding.bottom - wg_format->u.video.padding.top, - }; - if (FAILED(hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&aperture, sizeof(aperture)))) return hr; @@ -481,10 +477,9 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) { - decoder->wg_format.u.video.width = frame_size >> 32; - decoder->wg_format.u.video.height = (UINT32)frame_size; - decoder->output_info.cbSize = decoder->wg_format.u.video.width - * decoder->wg_format.u.video.height * 2; + if (FAILED(hr = IMFMediaType_SetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, frame_size))) + WARN("Failed to update stream type frame size, hr %#lx\n", hr); + decoder->output_info.cbSize = (frame_size >> 32) * (UINT32)frame_size * 2; } return S_OK; @@ -493,8 +488,8 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { struct h264_decoder *decoder = impl_from_IMFTransform(iface); + UINT64 frame_size, stream_frame_size; GUID major, subtype; - UINT64 frame_size; HRESULT hr; ULONG i; @@ -516,9 +511,10 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF if (i == ARRAY_SIZE(h264_decoder_output_types)) return MF_E_INVALIDMEDIATYPE; - if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)) - || (frame_size >> 32) != decoder->wg_format.u.video.width - || (UINT32)frame_size != decoder->wg_format.u.video.height) + if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) + return MF_E_INVALIDMEDIATYPE; + if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &stream_frame_size)) + && frame_size != stream_frame_size) return MF_E_INVALIDMEDIATYPE; if (flags & MFT_SET_TYPE_TEST_ONLY) return S_OK; @@ -676,6 +672,28 @@ static HRESULT output_sample(struct h264_decoder *decoder, IMFSample **out, IMFS return S_OK; } +static HRESULT handle_stream_type_change(struct h264_decoder *decoder, const struct wg_format *format) +{ + UINT64 frame_size, frame_rate; + HRESULT hr; + + if (decoder->stream_type) + IMFMediaType_Release(decoder->stream_type); + if (!(decoder->stream_type = mf_media_type_from_wg_format(format))) + return E_OUTOFMEMORY; + + if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate)) + && FAILED(hr = IMFMediaType_SetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, frame_rate))) + WARN("Failed to update stream type frame size, hr %#lx\n", hr); + + if (FAILED(hr = IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &frame_size))) + return hr; + decoder->output_info.cbSize = (frame_size >> 32) * (UINT32)frame_size * 2; + uninit_allocator(decoder); + + return MF_E_TRANSFORM_STREAM_CHANGE; +} + static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { @@ -683,7 +701,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, struct wg_format wg_format; UINT32 sample_size; IMFSample *sample; - UINT64 frame_rate; + UINT64 frame_size; GUID subtype; DWORD size; HRESULT hr; @@ -702,8 +720,9 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype))) return hr; - if (FAILED(hr = MFCalculateImageSize(&subtype, decoder->wg_format.u.video.width, - decoder->wg_format.u.video.height, &sample_size))) + if (FAILED(hr = IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_SIZE, &frame_size))) + return hr; + if (FAILED(hr = MFCalculateImageSize(&subtype, frame_size >> 32, (UINT32)frame_size, &sample_size))) return hr; if (decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) @@ -733,21 +752,9 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { - decoder->wg_format = wg_format; - decoder->output_info.cbSize = ALIGN_SIZE(decoder->wg_format.u.video.width, 0xf) - * ALIGN_SIZE(decoder->wg_format.u.video.height, 0xf) * 2; - - /* keep the frame rate that was requested, GStreamer doesn't provide any */ - if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate))) - { - decoder->wg_format.u.video.fps_n = frame_rate >> 32; - decoder->wg_format.u.video.fps_d = (UINT32)frame_rate; - } - samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; - - uninit_allocator(decoder); + hr = handle_stream_type_change(decoder, &wg_format); } if (decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) @@ -821,11 +828,6 @@ HRESULT h264_decoder_create(REFIID riid, void **ret) decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; decoder->refcount = 1; - decoder->wg_format.u.video.format = WG_VIDEO_FORMAT_UNKNOWN; - decoder->wg_format.u.video.width = 1920; - decoder->wg_format.u.video.height = 1080; - decoder->wg_format.u.video.fps_n = 30000; - decoder->wg_format.u.video.fps_d = 1001; decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; @@ -834,6 +836,8 @@ HRESULT h264_decoder_create(REFIID riid, void **ret) | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; decoder->output_info.cbSize = 1920 * 1088 * 2; + if (FAILED(hr = MFCreateMediaType(&decoder->stream_type))) + goto failed; if (FAILED(hr = MFCreateAttributes(&decoder->attributes, 16))) goto failed; if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_LOW_LATENCY, 0))) @@ -862,6 +866,8 @@ HRESULT h264_decoder_create(REFIID riid, void **ret) IMFAttributes_Release(decoder->output_attributes); if (decoder->attributes) IMFAttributes_Release(decoder->attributes); + if (decoder->stream_type) + IMFMediaType_Release(decoder->stream_type); free(decoder); return hr; } From e0a96cafa3ec31e50953e08c1b95c5e5b168ce4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 25 May 2023 14:42:28 +0200 Subject: [PATCH 2036/2777] winegstreamer: Generate H264 timestamps using the input type frame rate. And remove h264parse element requirement. (cherry picked from commit 52387aa1a4e25ee2dec4117201658b32b160a4ca) CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/winegstreamer/h264_decoder.c | 16 +++++++++++++++- dlls/winegstreamer/wg_transform.c | 3 --- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 8eeeb52fd60..97289f69a4d 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -53,6 +53,7 @@ struct h264_decoder IMFAttributes *attributes; IMFAttributes *output_attributes; + UINT64 sample_time; IMFMediaType *input_type; MFT_INPUT_STREAM_INFO input_info; IMFMediaType *output_type; @@ -700,8 +701,9 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, struct h264_decoder *decoder = impl_from_IMFTransform(iface); struct wg_format wg_format; UINT32 sample_size; + LONGLONG duration; IMFSample *sample; - UINT64 frame_size; + UINT64 frame_size, frame_rate; GUID subtype; DWORD size; HRESULT hr; @@ -748,8 +750,20 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, sample, sample_size, &wg_format, &samples->dwStatus))) + { wg_sample_queue_flush(decoder->wg_sample_queue, false); + if (FAILED(IMFMediaType_GetUINT64(decoder->input_type, &MF_MT_FRAME_RATE, &frame_rate))) + frame_rate = (UINT64)30000 << 32 | 1001; + + duration = (UINT64)10000000 * (UINT32)frame_rate / (frame_rate >> 32); + if (FAILED(IMFSample_SetSampleTime(sample, decoder->sample_time))) + WARN("Failed to set sample time\n"); + if (FAILED(IMFSample_SetSampleDuration(sample, duration))) + WARN("Failed to set sample duration\n"); + decoder->sample_time += duration; + } + if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 27f61ddc9df..a8ee302469c 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -337,9 +337,6 @@ NTSTATUS wg_transform_create(void *args) */ transform->input_max_length = 16; transform->output_plane_align = 15; - if (!(element = create_element("h264parse", "base")) - || !append_element(transform->container, element, &first, &last)) - goto out; /* fallthrough */ case WG_MAJOR_TYPE_AUDIO_MPEG1: case WG_MAJOR_TYPE_AUDIO_MPEG4: From af8b197a3f15bb5ba3d13be6a6307bc446a52e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 25 May 2023 15:03:22 +0200 Subject: [PATCH 2037/2777] winegstreamer: Use the output wg_format in CAPS sink query. Instead of constraining the output caps to the current resolution, which breaks when streams with different resolutions are concatenated. (cherry picked from commit 4d1a331c6619703e5766d50ddf0399eaa079ffe3) CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/winegstreamer/wg_transform.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index a8ee302469c..b64944264ee 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -56,6 +56,7 @@ struct wg_transform GstElement *video_flip; guint output_plane_align; + struct wg_format output_format; struct wg_sample *output_wg_sample; GstAtomicQueue *output_queue; GstSample *output_sample; @@ -174,7 +175,8 @@ static gboolean transform_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery gchar *str; gst_query_parse_caps(query, &filter); - caps = gst_caps_ref(transform->output_caps); + if (!(caps = wg_format_to_caps(&transform->output_format))) + break; if (filter) { @@ -303,6 +305,7 @@ NTSTATUS wg_transform_create(void *args) goto out; transform->input_max_length = 1; transform->output_plane_align = 0; + transform->output_format = output_format; if (!(src_caps = wg_format_to_caps(&input_format))) goto out; @@ -503,6 +506,7 @@ NTSTATUS wg_transform_set_output_format(void *args) GST_ERROR("Failed to convert format %p to caps.", format); return STATUS_UNSUCCESSFUL; } + transform->output_format = *format; if (gst_caps_is_always_compatible(transform->output_caps, caps)) { From d424fd953fcf40de472104b0153fca42c1e9ed48 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 28 Feb 2023 12:07:55 -0600 Subject: [PATCH 2038/2777] winegstreamer: Don't pre-check sample size in wg_transform_read_mf(). (cherry picked from commit 596dfad38b9cb327b73c6b2f1c42e42080218cb6) CW-Bug-Id: #21804 CW-Bug-Id: #21813 CW-Bug-Id: #22299 --- dlls/winegstreamer/wg_sample.c | 5 ---- dlls/winegstreamer/wg_transform.c | 38 +++++++++++++++++-------------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/dlls/winegstreamer/wg_sample.c b/dlls/winegstreamer/wg_sample.c index d20583bdb22..1278ccf7347 100644 --- a/dlls/winegstreamer/wg_sample.c +++ b/dlls/winegstreamer/wg_sample.c @@ -353,11 +353,6 @@ HRESULT wg_transform_read_mf(struct wg_transform *transform, IMFSample *sample, return hr; wg_sample->size = 0; - if (wg_sample->max_size < sample_size) - { - wg_sample_release(wg_sample); - return MF_E_BUFFERTOOSMALL; - } if (FAILED(hr = wg_transform_read_data(transform, wg_sample, format))) { diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index b64944264ee..564a5e12083 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -604,19 +604,19 @@ NTSTATUS wg_transform_push_data(void *args) return STATUS_SUCCESS; } -static bool copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_align, +static NTSTATUS copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_align, struct wg_sample *sample, gsize *total_size) { + NTSTATUS status = STATUS_UNSUCCESSFUL; GstVideoFrame src_frame, dst_frame; GstVideoInfo src_info, dst_info; GstVideoAlignment align; GstBuffer *dst_buffer; - bool ret = false; if (!gst_video_info_from_caps(&src_info, caps)) { GST_ERROR("Failed to get video info from caps."); - return false; + return STATUS_UNSUCCESSFUL; } dst_info = src_info; @@ -625,14 +625,14 @@ static bool copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_alig if (sample->max_size < dst_info.size) { GST_ERROR("Output buffer is too small."); - return false; + return STATUS_BUFFER_TOO_SMALL; } if (!(dst_buffer = gst_buffer_new_wrapped_full(0, sample->data, sample->max_size, 0, sample->max_size, 0, NULL))) { GST_ERROR("Failed to wrap wg_sample into GstBuffer"); - return false; + return STATUS_UNSUCCESSFUL; } gst_buffer_set_size(dst_buffer, dst_info.size); *total_size = sample->size = dst_info.size; @@ -645,7 +645,9 @@ static bool copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_alig GST_ERROR("Failed to map destination frame."); else { - if (!(ret = gst_video_frame_copy(&dst_frame, &src_frame))) + if (gst_video_frame_copy(&dst_frame, &src_frame)) + status = STATUS_SUCCESS; + else GST_ERROR("Failed to copy video frame."); gst_video_frame_unmap(&dst_frame); } @@ -653,16 +655,16 @@ static bool copy_video_buffer(GstBuffer *buffer, GstCaps *caps, gsize plane_alig } gst_buffer_unref(dst_buffer); - return ret; + return status; } -static bool copy_buffer(GstBuffer *buffer, GstCaps *caps, struct wg_sample *sample, +static NTSTATUS copy_buffer(GstBuffer *buffer, GstCaps *caps, struct wg_sample *sample, gsize *total_size) { GstMapInfo info; if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) - return false; + return STATUS_UNSUCCESSFUL; if (sample->max_size >= info.size) sample->size = info.size; @@ -679,14 +681,15 @@ static bool copy_buffer(GstBuffer *buffer, GstCaps *caps, struct wg_sample *samp gst_buffer_resize(buffer, sample->size, -1); *total_size = info.size; - return true; + return STATUS_SUCCESS; } static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsize plane_align, struct wg_sample *sample) { - bool ret, needs_copy; gsize total_size; + bool needs_copy; + NTSTATUS status; GstMapInfo info; if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) @@ -696,20 +699,21 @@ static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsi return STATUS_UNSUCCESSFUL; } needs_copy = info.data != sample->data; + total_size = sample->size = info.size; gst_buffer_unmap(buffer, &info); - if ((ret = !needs_copy)) - total_size = sample->size = info.size; + if (!needs_copy) + status = STATUS_SUCCESS; else if (stream_type_from_caps(caps) == GST_STREAM_TYPE_VIDEO) - ret = copy_video_buffer(buffer, caps, plane_align, sample, &total_size); + status = copy_video_buffer(buffer, caps, plane_align, sample, &total_size); else - ret = copy_buffer(buffer, caps, sample, &total_size); + status = copy_buffer(buffer, caps, sample, &total_size); - if (!ret) + if (status) { GST_ERROR("Failed to copy buffer %p", buffer); sample->size = 0; - return STATUS_UNSUCCESSFUL; + return status; } if (GST_BUFFER_PTS_IS_VALID(buffer)) From 2db7f53fccfce9af8c6817a46b47f258655f6a84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 25 May 2023 14:37:04 +0200 Subject: [PATCH 2039/2777] winegstreamer: Implement MFT_MESSAGE_COMMAND_DRAIN for H264 decoder. (cherry picked from commit 16347299c132a128f4b72a95c1e4207f469c8ce6) CW-Bug-Id: #21804 CW-Bug-Id: #22299 --- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/h264_decoder.c | 13 ++++++++---- dlls/winegstreamer/main.c | 15 +++++++++++++ dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_parser.c | 1 + dlls/winegstreamer/wg_transform.c | 35 +++++++++++++++++++++++++++++++ 7 files changed, 63 insertions(+), 4 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index e2c32d12b64..81aefe4234f 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -105,6 +105,7 @@ struct wg_transform *wg_transform_create(const struct wg_format *input_format, void wg_transform_destroy(struct wg_transform *transform); bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_format *format); bool wg_transform_get_status(struct wg_transform *transform, bool *accepts_input); +HRESULT wg_transform_drain(struct wg_transform *transform); struct wg_source *wg_source_create(const WCHAR *url, uint64_t file_size, const void *data, uint32_t size, WCHAR mime_type[256]); diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 97289f69a4d..96888e49178 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -614,8 +614,9 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ TRACE("iface %p, message %#x, param %Ix.\n", iface, message, param); - if (message == MFT_MESSAGE_SET_D3D_MANAGER) + switch (message) { + case MFT_MESSAGE_SET_D3D_MANAGER: if (FAILED(hr = IMFVideoSampleAllocatorEx_SetDirectXManager(decoder->allocator, (IUnknown *)param))) return hr; @@ -625,10 +626,14 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ else decoder->output_info.dwFlags &= ~MFT_OUTPUT_STREAM_PROVIDES_SAMPLES; return S_OK; - } - FIXME("Ignoring message %#x.\n", message); - return S_OK; + case MFT_MESSAGE_COMMAND_DRAIN: + return wg_transform_drain(decoder->wg_transform); + + default: + FIXME("Ignoring message %#x.\n", message); + return S_OK; + } } static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 5cbaf49e38a..00469b3d0b6 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -415,6 +415,21 @@ bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_fo return !WINE_UNIX_CALL(unix_wg_transform_set_output_format, ¶ms); } +HRESULT wg_transform_drain(struct wg_transform *transform) +{ + NTSTATUS status; + + TRACE("transform %p.\n", transform); + + if ((status = WINE_UNIX_CALL(unix_wg_transform_drain, transform))) + { + WARN("wg_transform_drain returned status %#lx\n", status); + return HRESULT_FROM_NT(status); + } + + return S_OK; +} + struct wg_source *wg_source_create(const WCHAR *url, uint64_t file_size, const void *data, uint32_t size, WCHAR mime_type[256]) { diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 025ef83ed99..1f4ebf0a2df 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -66,6 +66,7 @@ extern NTSTATUS wg_transform_set_output_format(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_get_status(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_transform_drain(void *args) DECLSPEC_HIDDEN; /* wg_source.c */ diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 660a32374e2..072b5d045da 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -409,6 +409,7 @@ enum unix_funcs unix_wg_transform_push_data, unix_wg_transform_read_data, unix_wg_transform_get_status, + unix_wg_transform_drain, unix_wg_source_create, unix_wg_source_destroy, diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index ee612a4f74f..eb928059a7a 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1918,6 +1918,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_transform_push_data), X(wg_transform_read_data), X(wg_transform_get_status), + X(wg_transform_drain), X(wg_source_create), X(wg_source_destroy), diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 564a5e12083..7de2fb5f5a5 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -879,3 +879,38 @@ NTSTATUS wg_transform_get_status(void *args) params->accepts_input = gst_atomic_queue_length(transform->input_queue) < transform->input_max_length; return STATUS_SUCCESS; } + +NTSTATUS wg_transform_drain(void *args) +{ + struct wg_transform *transform = args; + GstBuffer *input_buffer; + GstFlowReturn ret; + GstEvent *event; + + GST_LOG("transform %p", transform); + + while ((input_buffer = gst_atomic_queue_pop(transform->input_queue))) + { + if ((ret = gst_pad_push(transform->my_src, input_buffer))) + GST_WARNING("Failed to push transform input, error %d", ret); + } + + if (!(event = gst_event_new_segment_done(GST_FORMAT_TIME, -1)) + || !gst_pad_push_event(transform->my_src, event)) + goto error; + if (!(event = gst_event_new_eos()) + || !gst_pad_push_event(transform->my_src, event)) + goto error; + if (!(event = gst_event_new_stream_start("stream")) + || !gst_pad_push_event(transform->my_src, event)) + goto error; + if (!(event = gst_event_new_segment(&transform->segment)) + || !gst_pad_push_event(transform->my_src, event)) + goto error; + + return STATUS_SUCCESS; + +error: + GST_ERROR("Failed to drain transform %p.", transform); + return STATUS_UNSUCCESSFUL; +} From b8e9d6363aa48227625c8cb2d96c6d894a55a5c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 25 May 2023 15:07:20 +0200 Subject: [PATCH 2040/2777] winegstreamer: Implement MFT_MESSAGE_COMMAND_FLUSH for H264 decoder. (cherry picked from commit 4f4ee0e16b343c2c6f935c465c59dc3c705ebd65) CW-Bug-Id: #21804 CW-Bug-Id: #22299 --- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/h264_decoder.c | 3 +++ dlls/winegstreamer/main.c | 15 +++++++++++++++ dlls/winegstreamer/unix_private.h | 1 + dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_parser.c | 1 + dlls/winegstreamer/wg_transform.c | 24 ++++++++++++++++++++++++ 7 files changed, 46 insertions(+) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 81aefe4234f..b1bc3a26cb2 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -106,6 +106,7 @@ void wg_transform_destroy(struct wg_transform *transform); bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_format *format); bool wg_transform_get_status(struct wg_transform *transform, bool *accepts_input); HRESULT wg_transform_drain(struct wg_transform *transform); +HRESULT wg_transform_flush(struct wg_transform *transform); struct wg_source *wg_source_create(const WCHAR *url, uint64_t file_size, const void *data, uint32_t size, WCHAR mime_type[256]); diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 96888e49178..f8d4ea10d5e 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -630,6 +630,9 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ case MFT_MESSAGE_COMMAND_DRAIN: return wg_transform_drain(decoder->wg_transform); + case MFT_MESSAGE_COMMAND_FLUSH: + return wg_transform_flush(decoder->wg_transform); + default: FIXME("Ignoring message %#x.\n", message); return S_OK; diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 00469b3d0b6..47fc4c8c6e1 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -430,6 +430,21 @@ HRESULT wg_transform_drain(struct wg_transform *transform) return S_OK; } +HRESULT wg_transform_flush(struct wg_transform *transform) +{ + NTSTATUS status; + + TRACE("transform %p.\n", transform); + + if ((status = WINE_UNIX_CALL(unix_wg_transform_flush, transform))) + { + WARN("wg_transform_flush returned status %#lx\n", status); + return HRESULT_FROM_NT(status); + } + + return S_OK; +} + struct wg_source *wg_source_create(const WCHAR *url, uint64_t file_size, const void *data, uint32_t size, WCHAR mime_type[256]) { diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h index 1f4ebf0a2df..434b81715e8 100644 --- a/dlls/winegstreamer/unix_private.h +++ b/dlls/winegstreamer/unix_private.h @@ -67,6 +67,7 @@ extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_get_status(void *args) DECLSPEC_HIDDEN; extern NTSTATUS wg_transform_drain(void *args) DECLSPEC_HIDDEN; +extern NTSTATUS wg_transform_flush(void *args) DECLSPEC_HIDDEN; /* wg_source.c */ diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 072b5d045da..1825d90ee11 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -410,6 +410,7 @@ enum unix_funcs unix_wg_transform_read_data, unix_wg_transform_get_status, unix_wg_transform_drain, + unix_wg_transform_flush, unix_wg_source_create, unix_wg_source_destroy, diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index eb928059a7a..959a2141f2c 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1919,6 +1919,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_transform_read_data), X(wg_transform_get_status), X(wg_transform_drain), + X(wg_transform_flush), X(wg_source_create), X(wg_source_destroy), diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 7de2fb5f5a5..30c3b6e59d3 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -914,3 +914,27 @@ NTSTATUS wg_transform_drain(void *args) GST_ERROR("Failed to drain transform %p.", transform); return STATUS_UNSUCCESSFUL; } + +NTSTATUS wg_transform_flush(void *args) +{ + struct wg_transform *transform = args; + GstBuffer *input_buffer; + GstSample *sample; + NTSTATUS status; + + GST_LOG("transform %p", transform); + + while ((input_buffer = gst_atomic_queue_pop(transform->input_queue))) + gst_buffer_unref(input_buffer); + + if ((status = wg_transform_drain(transform))) + return status; + + while ((sample = gst_atomic_queue_pop(transform->output_queue))) + gst_sample_unref(sample); + if ((sample = transform->output_sample)) + gst_sample_unref(sample); + transform->output_sample = NULL; + + return STATUS_SUCCESS; +} From 94659261ac3a6c558e57bc483c92cefa3d05fed0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 17 May 2023 14:23:15 +0200 Subject: [PATCH 2041/2777] winegstreamer: Pass desired output plane alignment to wg_transform_create. (cherry picked from commit f83922fd98d79a6d79c538755c2889d6e362e1a3) CW-Bug-Id: #21804 CW-Bug-Id: #22299 --- dlls/winegstreamer/aac_decoder.c | 6 ++++-- dlls/winegstreamer/color_convert.c | 6 ++++-- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/h264_decoder.c | 9 +++++++-- dlls/winegstreamer/main.c | 3 ++- dlls/winegstreamer/quartz_transform.c | 9 ++++++--- dlls/winegstreamer/resampler.c | 6 ++++-- dlls/winegstreamer/unixlib.h | 6 ++++++ dlls/winegstreamer/video_decoder.c | 3 ++- dlls/winegstreamer/video_processor.c | 6 ++++-- dlls/winegstreamer/wg_transform.c | 12 ++++++------ dlls/winegstreamer/wma_decoder.c | 14 ++++++++++---- 12 files changed, 56 insertions(+), 26 deletions(-) diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index d79ede69c9d..1fc545fc283 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -67,6 +67,7 @@ static struct aac_decoder *impl_from_IMFTransform(IMFTransform *iface) static HRESULT try_create_wg_transform(struct aac_decoder *decoder) { struct wg_format input_format, output_format; + struct wg_transform_attrs attrs = {0}; if (decoder->wg_transform) wg_transform_destroy(decoder->wg_transform); @@ -80,7 +81,7 @@ static HRESULT try_create_wg_transform(struct aac_decoder *decoder) if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE; - if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format))) + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) return E_FAIL; return S_OK; @@ -625,13 +626,14 @@ HRESULT aac_decoder_create(REFIID riid, void **ret) }, }; static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_AUDIO_MPEG4}; + struct wg_transform_attrs attrs = {0}; struct wg_transform *transform; struct aac_decoder *decoder; HRESULT hr; TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); - if (!(transform = wg_transform_create(&input_format, &output_format))) + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) { ERR_(winediag)("GStreamer doesn't support WMA decoding, please install appropriate plugins\n"); return E_FAIL; diff --git a/dlls/winegstreamer/color_convert.c b/dlls/winegstreamer/color_convert.c index ed591c8e669..624191daf33 100644 --- a/dlls/winegstreamer/color_convert.c +++ b/dlls/winegstreamer/color_convert.c @@ -98,6 +98,7 @@ static inline struct color_convert *impl_from_IUnknown(IUnknown *iface) static HRESULT try_create_wg_transform(struct color_convert *impl) { struct wg_format input_format, output_format; + struct wg_transform_attrs attrs = {0}; if (impl->wg_transform) wg_transform_destroy(impl->wg_transform); @@ -111,7 +112,7 @@ static HRESULT try_create_wg_transform(struct color_convert *impl) if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE; - if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format))) + if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) return E_FAIL; return S_OK; @@ -936,13 +937,14 @@ HRESULT color_convert_create(IUnknown *outer, IUnknown **out) .height = 1080, }, }; + struct wg_transform_attrs attrs = {0}; struct wg_transform *transform; struct color_convert *impl; HRESULT hr; TRACE("outer %p, out %p.\n", outer, out); - if (!(transform = wg_transform_create(&input_format, &output_format))) + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) { ERR_(winediag)("GStreamer doesn't support video conversion, please install appropriate plugins.\n"); return E_FAIL; diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index b1bc3a26cb2..c53483c0ca7 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -101,7 +101,7 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); struct wg_transform *wg_transform_create(const struct wg_format *input_format, - const struct wg_format *output_format); + const struct wg_format *output_format, const struct wg_transform_attrs *attrs); void wg_transform_destroy(struct wg_transform *transform); bool wg_transform_set_output_format(struct wg_transform *transform, struct wg_format *format); bool wg_transform_get_status(struct wg_transform *transform, bool *accepts_input); diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index f8d4ea10d5e..81b06445df9 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -76,6 +76,10 @@ static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) static HRESULT try_create_wg_transform(struct h264_decoder *decoder) { + struct wg_transform_attrs attrs = + { + .output_plane_align = 15, + }; struct wg_format input_format; struct wg_format output_format; @@ -99,7 +103,7 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) output_format.u.video.fps_d = 0; output_format.u.video.fps_n = 0; - if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format))) + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) return E_FAIL; return S_OK; @@ -832,13 +836,14 @@ HRESULT h264_decoder_create(REFIID riid, void **ret) }, }; static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_VIDEO_H264}; + struct wg_transform_attrs attrs = {0}; struct wg_transform *transform; struct h264_decoder *decoder; HRESULT hr; TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); - if (!(transform = wg_transform_create(&input_format, &output_format))) + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) { ERR_(winediag)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n"); return E_FAIL; diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 47fc4c8c6e1..261d810795f 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -326,12 +326,13 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, } struct wg_transform *wg_transform_create(const struct wg_format *input_format, - const struct wg_format *output_format) + const struct wg_format *output_format, const struct wg_transform_attrs *attrs) { struct wg_transform_create_params params = { .input_format = input_format, .output_format = output_format, + .attrs = attrs, }; TRACE("input_format %p, output_format %p.\n", input_format, output_format); diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index 09ad4862410..84f6bbd6361 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -98,6 +98,7 @@ static HRESULT transform_init_stream(struct strmbase_filter *iface) { struct transform *filter = impl_from_strmbase_filter(iface); struct wg_format input_format, output_format; + struct wg_transform_attrs attrs = {0}; HRESULT hr; if (filter->source.pin.peer) @@ -111,7 +112,7 @@ static HRESULT transform_init_stream(struct strmbase_filter *iface) if (FAILED(hr = wg_sample_queue_create(&filter->sample_queue))) return hr; - filter->transform = wg_transform_create(&input_format, &output_format); + filter->transform = wg_transform_create(&input_format, &output_format, &attrs); if (!filter->transform) { wg_sample_queue_destroy(filter->sample_queue); @@ -710,11 +711,12 @@ HRESULT mpeg_audio_codec_create(IUnknown *outer, IUnknown **out) .rate = 44100, }, }; + struct wg_transform_attrs attrs = {0}; struct wg_transform *transform; struct transform *object; HRESULT hr; - transform = wg_transform_create(&input_format, &output_format); + transform = wg_transform_create(&input_format, &output_format, &attrs); if (!transform) { ERR_(winediag)("GStreamer doesn't support MPEG-1 audio decoding, please install appropriate plugins.\n"); @@ -844,11 +846,12 @@ HRESULT mpeg_layer3_decoder_create(IUnknown *outer, IUnknown **out) .rate = 44100, }, }; + struct wg_transform_attrs attrs = {0}; struct wg_transform *transform; struct transform *object; HRESULT hr; - transform = wg_transform_create(&input_format, &output_format); + transform = wg_transform_create(&input_format, &output_format, &attrs); if (!transform) { ERR_(winediag)("GStreamer doesn't support MPEG-1 audio decoding, please install appropriate plugins.\n"); diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c index 88e9727ff21..7ed8cf48fbf 100644 --- a/dlls/winegstreamer/resampler.c +++ b/dlls/winegstreamer/resampler.c @@ -56,6 +56,7 @@ struct resampler static HRESULT try_create_wg_transform(struct resampler *impl) { struct wg_format input_format, output_format; + struct wg_transform_attrs attrs = {0}; if (impl->wg_transform) wg_transform_destroy(impl->wg_transform); @@ -69,7 +70,7 @@ static HRESULT try_create_wg_transform(struct resampler *impl) if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE; - if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format))) + if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) return E_FAIL; return S_OK; @@ -895,13 +896,14 @@ HRESULT resampler_create(IUnknown *outer, IUnknown **out) .rate = 44100, }, }; + struct wg_transform_attrs attrs = {0}; struct wg_transform *transform; struct resampler *impl; HRESULT hr; TRACE("outer %p, out %p.\n", outer, out); - if (!(transform = wg_transform_create(&input_format, &output_format))) + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) { ERR_(winediag)("GStreamer doesn't support audio resampling, please install appropriate plugins.\n"); return E_FAIL; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 1825d90ee11..750f47c1820 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -298,11 +298,17 @@ struct wg_parser_stream_seek_params DWORD start_flags, stop_flags; }; +struct wg_transform_attrs +{ + UINT32 output_plane_align; +}; + struct wg_transform_create_params { struct wg_transform *transform; const struct wg_format *input_format; const struct wg_format *output_format; + const struct wg_transform_attrs *attrs; }; struct wg_transform_push_data_params diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 04d175c7910..abcadf90a32 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -68,6 +68,7 @@ static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface) static HRESULT try_create_wg_transform(struct video_decoder *decoder) { + struct wg_transform_attrs attrs = {0}; struct wg_format input_format; struct wg_format output_format; @@ -86,7 +87,7 @@ static HRESULT try_create_wg_transform(struct video_decoder *decoder) output_format.u.video.fps_d = 0; output_format.u.video.fps_n = 0; - if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format))) + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) { ERR("Failed to create transform with input major_type %u.\n", input_format.major_type); return E_FAIL; diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index 21bc46b0bb3..3cb0ccc090b 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -88,6 +88,7 @@ struct video_processor static HRESULT try_create_wg_transform(struct video_processor *impl) { struct wg_format input_format, output_format; + struct wg_transform_attrs attrs = {0}; if (impl->wg_transform) wg_transform_destroy(impl->wg_transform); @@ -101,7 +102,7 @@ static HRESULT try_create_wg_transform(struct video_processor *impl) if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE; - if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format))) + if (!(impl->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) return E_FAIL; return S_OK; @@ -602,13 +603,14 @@ HRESULT video_processor_create(REFIID riid, void **ret) .height = 1080, }, }; + struct wg_transform_attrs attrs = {0}; struct wg_transform *transform; struct video_processor *impl; HRESULT hr; TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); - if (!(transform = wg_transform_create(&input_format, &output_format))) + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) { ERR_(winediag)("GStreamer doesn't support video conversion, please install appropriate plugins.\n"); return E_FAIL; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 30c3b6e59d3..dc5af0fae02 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -43,6 +43,8 @@ struct wg_transform { + struct wg_transform_attrs attrs; + GstElement *container; GstAllocator *allocator; GstPad *my_src, *my_sink; @@ -55,7 +57,6 @@ struct wg_transform bool input_is_flipped; GstElement *video_flip; - guint output_plane_align; struct wg_format output_format; struct wg_sample *output_wg_sample; GstAtomicQueue *output_queue; @@ -111,7 +112,7 @@ static gboolean transform_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery { case GST_QUERY_ALLOCATION: { - gsize plane_align = transform->output_plane_align; + gsize plane_align = transform->attrs.output_plane_align; GstStructure *config, *params; GstVideoAlignment align; gboolean needs_pool; @@ -303,8 +304,8 @@ NTSTATUS wg_transform_create(void *args) goto out; if (!(transform->allocator = wg_allocator_create(transform_request_sample, transform))) goto out; + transform->attrs = *params->attrs; transform->input_max_length = 1; - transform->output_plane_align = 0; transform->output_format = output_format; if (!(src_caps = wg_format_to_caps(&input_format))) @@ -339,7 +340,6 @@ NTSTATUS wg_transform_create(void *args) * to match its expectations. */ transform->input_max_length = 16; - transform->output_plane_align = 15; /* fallthrough */ case WG_MAJOR_TYPE_AUDIO_MPEG1: case WG_MAJOR_TYPE_AUDIO_MPEG4: @@ -805,7 +805,7 @@ NTSTATUS wg_transform_read_data(void *args) if (format) { - gsize plane_align = transform->output_plane_align; + gsize plane_align = transform->attrs.output_plane_align; GstVideoAlignment align; GstVideoInfo info; @@ -837,7 +837,7 @@ NTSTATUS wg_transform_read_data(void *args) } if ((status = read_transform_output_data(output_buffer, output_caps, - transform->output_plane_align, sample))) + transform->attrs.output_plane_align, sample))) { wg_allocator_release_sample(transform->allocator, sample, false); return status; diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 10a41a0c92f..10bcd4162a1 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -76,6 +76,7 @@ static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface) static HRESULT try_create_wg_transform(struct wma_decoder *decoder) { struct wg_format input_format, output_format; + struct wg_transform_attrs attrs = {0}; if (decoder->wg_transform) wg_transform_destroy(decoder->wg_transform); @@ -89,7 +90,7 @@ static HRESULT try_create_wg_transform(struct wma_decoder *decoder) if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) return MF_E_INVALIDMEDIATYPE; - if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format))) + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) return E_FAIL; return S_OK; @@ -741,6 +742,8 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index return VFW_E_INVALIDMEDIATYPE; if (!(flags & DMO_SET_TYPEF_TEST_ONLY)) { + struct wg_transform_attrs attrs = {0}; + impl->input_format = wg_format; if (!impl->output_format.major_type) return S_OK; @@ -749,7 +752,7 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index wg_transform_destroy(impl->wg_transform); impl->wg_transform = NULL; - if (!(impl->wg_transform = wg_transform_create(&impl->input_format, &impl->output_format))) + if (!(impl->wg_transform = wg_transform_create(&impl->input_format, &impl->output_format, &attrs))) return E_FAIL; } @@ -777,6 +780,8 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde return VFW_E_INVALIDMEDIATYPE; if (!(flags & DMO_SET_TYPEF_TEST_ONLY)) { + struct wg_transform_attrs attrs = {0}; + impl->output_format = wg_format; if (!impl->input_format.major_type) return S_OK; @@ -785,7 +790,7 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde wg_transform_destroy(impl->wg_transform); impl->wg_transform = NULL; - if (!(impl->wg_transform = wg_transform_create(&impl->input_format, &impl->output_format))) + if (!(impl->wg_transform = wg_transform_create(&impl->input_format, &impl->output_format, &attrs))) return E_FAIL; } @@ -1007,13 +1012,14 @@ HRESULT wma_decoder_create(IUnknown *outer, IUnknown **out) }, }; static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_AUDIO_WMA}; + struct wg_transform_attrs attrs = {0}; struct wg_transform *transform; struct wma_decoder *decoder; HRESULT hr; TRACE("outer %p, out %p.\n", outer, out); - if (!(transform = wg_transform_create(&input_format, &output_format))) + if (!(transform = wg_transform_create(&input_format, &output_format, &attrs))) { ERR_(winediag)("GStreamer doesn't support WMA decoding, please install appropriate plugins\n"); return E_FAIL; From 96963fce1fb75ced79fc75f8499e9fdda13aa2eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 24 May 2023 10:07:56 +0200 Subject: [PATCH 2042/2777] winegstreamer: Pass desired input queue length to wg_transform_create. (cherry picked from commit 036166faf7671d2e2c4c11422a55170323503cff) CW-Bug-Id: #21804 CW-Bug-Id: #22299 --- dlls/winegstreamer/color_convert.c | 2 +- dlls/winegstreamer/h264_decoder.c | 6 ++++++ dlls/winegstreamer/resampler.c | 2 +- dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/video_processor.c | 2 +- dlls/winegstreamer/wg_transform.c | 14 ++------------ 6 files changed, 12 insertions(+), 15 deletions(-) diff --git a/dlls/winegstreamer/color_convert.c b/dlls/winegstreamer/color_convert.c index 624191daf33..598b2aa5b43 100644 --- a/dlls/winegstreamer/color_convert.c +++ b/dlls/winegstreamer/color_convert.c @@ -98,7 +98,7 @@ static inline struct color_convert *impl_from_IUnknown(IUnknown *iface) static HRESULT try_create_wg_transform(struct color_convert *impl) { struct wg_format input_format, output_format; - struct wg_transform_attrs attrs = {0}; + struct wg_transform_attrs attrs = {.input_queue_length = 15}; if (impl->wg_transform) wg_transform_destroy(impl->wg_transform); diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 81b06445df9..8795d12169f 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -76,9 +76,15 @@ static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) static HRESULT try_create_wg_transform(struct h264_decoder *decoder) { + /* Call of Duty: Black Ops 3 doesn't care about the ProcessInput/ProcessOutput + * return values, it calls them in a specific order and expects the decoder + * transform to be able to queue its input buffers. We need to use a buffer list + * to match its expectations. + */ struct wg_transform_attrs attrs = { .output_plane_align = 15, + .input_queue_length = 15, }; struct wg_format input_format; struct wg_format output_format; diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c index 7ed8cf48fbf..9c87a5431b2 100644 --- a/dlls/winegstreamer/resampler.c +++ b/dlls/winegstreamer/resampler.c @@ -56,7 +56,7 @@ struct resampler static HRESULT try_create_wg_transform(struct resampler *impl) { struct wg_format input_format, output_format; - struct wg_transform_attrs attrs = {0}; + struct wg_transform_attrs attrs = {.input_queue_length = 15}; if (impl->wg_transform) wg_transform_destroy(impl->wg_transform); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 750f47c1820..82f063e2da7 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -301,6 +301,7 @@ struct wg_parser_stream_seek_params struct wg_transform_attrs { UINT32 output_plane_align; + UINT32 input_queue_length; }; struct wg_transform_create_params diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index 3cb0ccc090b..0164557234a 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -88,7 +88,7 @@ struct video_processor static HRESULT try_create_wg_transform(struct video_processor *impl) { struct wg_format input_format, output_format; - struct wg_transform_attrs attrs = {0}; + struct wg_transform_attrs attrs = {.input_queue_length = 15}; if (impl->wg_transform) wg_transform_destroy(impl->wg_transform); diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index dc5af0fae02..db9af28488a 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -51,7 +51,6 @@ struct wg_transform GstSegment segment; GstQuery *drain_query; - guint input_max_length; GstAtomicQueue *input_queue; bool input_is_flipped; @@ -305,7 +304,6 @@ NTSTATUS wg_transform_create(void *args) if (!(transform->allocator = wg_allocator_create(transform_request_sample, transform))) goto out; transform->attrs = *params->attrs; - transform->input_max_length = 1; transform->output_format = output_format; if (!(src_caps = wg_format_to_caps(&input_format))) @@ -334,13 +332,6 @@ NTSTATUS wg_transform_create(void *args) switch (input_format.major_type) { case WG_MAJOR_TYPE_VIDEO_H264: - /* Call of Duty: Black Ops 3 doesn't care about the ProcessInput/ProcessOutput - * return values, it calls them in a specific order and expects the decoder - * transform to be able to queue its input buffers. We need to use a buffer list - * to match its expectations. - */ - transform->input_max_length = 16; - /* fallthrough */ case WG_MAJOR_TYPE_AUDIO_MPEG1: case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: @@ -357,7 +348,6 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_AUDIO: case WG_MAJOR_TYPE_VIDEO: - transform->input_max_length = 16; break; case WG_MAJOR_TYPE_UNKNOWN: GST_FIXME("Format %u not implemented!", input_format.major_type); @@ -571,7 +561,7 @@ NTSTATUS wg_transform_push_data(void *args) guint length; length = gst_atomic_queue_length(transform->input_queue); - if (length >= transform->input_max_length) + if (length >= transform->attrs.input_queue_length + 1) { GST_INFO("Refusing %u bytes, %u buffers already queued", sample->size, length); params->result = MF_E_NOTACCEPTING; @@ -876,7 +866,7 @@ NTSTATUS wg_transform_get_status(void *args) struct wg_transform_get_status_params *params = args; struct wg_transform *transform = params->transform; - params->accepts_input = gst_atomic_queue_length(transform->input_queue) < transform->input_max_length; + params->accepts_input = gst_atomic_queue_length(transform->input_queue) < transform->attrs.input_queue_length + 1; return STATUS_SUCCESS; } From 8086903fa7a1215452cf8a12a673e025af72dc41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 25 May 2023 14:15:43 +0200 Subject: [PATCH 2043/2777] winegstreamer: Implement MF_LOW_LATENCY attribute and latency query. (cherry picked from commit 226f8b7c28408762bc54c32406d57377b19f0866) CW-Bug-Id: #21804 CW-Bug-Id: #22299 --- dlls/winegstreamer/h264_decoder.c | 4 ++++ dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_transform.c | 23 +++++++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 8795d12169f..c6e817df6b0 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -88,6 +88,7 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) }; struct wg_format input_format; struct wg_format output_format; + UINT32 low_latency; if (decoder->wg_transform) wg_transform_destroy(decoder->wg_transform); @@ -109,6 +110,9 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) output_format.u.video.fps_d = 0; output_format.u.video.fps_n = 0; + if (SUCCEEDED(IMFAttributes_GetUINT32(decoder->attributes, &MF_LOW_LATENCY, &low_latency))) + attrs.low_latency = !!low_latency; + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) return E_FAIL; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 82f063e2da7..e3d259a7fd2 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -302,6 +302,7 @@ struct wg_transform_attrs { UINT32 output_plane_align; UINT32 input_queue_length; + BOOL low_latency; }; struct wg_transform_create_params diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index db9af28488a..1369b5f6591 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -101,6 +101,26 @@ static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, Gst return GST_FLOW_OK; } +static gboolean transform_src_query_latency(struct wg_transform *transform, GstQuery *query) +{ + GST_LOG("transform %p, query %p", transform, query); + gst_query_set_latency(query, transform->attrs.low_latency, 0, 0); + return true; +} + +static gboolean transform_src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) +{ + struct wg_transform *transform = gst_pad_get_element_private(pad); + + switch (query->type) + { + case GST_QUERY_LATENCY: + return transform_src_query_latency(transform, query); + default: + return gst_pad_query_default(pad, parent, query); + } +} + static gboolean transform_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) { struct wg_transform *transform = gst_pad_get_element_private(pad); @@ -311,6 +331,9 @@ NTSTATUS wg_transform_create(void *args) if (!(transform->my_src = create_pad_with_caps(GST_PAD_SRC, src_caps))) goto out; + gst_pad_set_element_private(transform->my_src, transform); + gst_pad_set_query_function(transform->my_src, transform_src_query_cb); + if (!(transform->output_caps = wg_format_to_caps(&output_format))) goto out; if (!(transform->my_sink = create_pad_with_caps(GST_PAD_SINK, transform->output_caps))) From 34fc7820c6dc1908a0d4286807087e2d934719bf Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 20 Jan 2023 14:18:25 -0600 Subject: [PATCH 2044/2777] winegstreamer: Implement MFT_MESSAGE_COMMAND_DRAIN for aac decoder. CW-Bug-Id: #21804 CW-Bug-Id: #22299 --- dlls/mf/tests/transform.c | 9 +++++++-- dlls/winegstreamer/aac_decoder.c | 13 ++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index d3dca90cdf7..36181c33d20 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -2470,8 +2470,13 @@ static void test_aac_decoder_subtype(const struct attribute_desc *input_type_des hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, 0); ok(hr == S_OK, "ProcessMessage returned %#lx\n", hr); - hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); - ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr); + if (0) + { + /* This is fine on Windows but currently MFT_MESSAGE_COMMAND_DRAIN removes input sample from the queue + * and makes next _ProcessInput succeed on Wine breaking the tests below. */ + hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); + ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#lx\n", hr); + } hr = MFCreateCollection(&output_samples); ok(hr == S_OK, "MFCreateCollection returned %#lx\n", hr); diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index 1fc545fc283..69c91b0d6d0 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -535,7 +535,18 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); + struct aac_decoder *decoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, message %#x, param %p.\n", iface, message, (void *)param); + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (message == MFT_MESSAGE_COMMAND_DRAIN) + return wg_transform_drain(decoder->wg_transform); + + FIXME("Ignoring message %#x.\n", message); + return S_OK; } From 99a326a950b1f4bc8eb2b8fb49cbf7facb1ac367 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 20 Jan 2023 14:47:47 -0600 Subject: [PATCH 2045/2777] winegstreamer: Implement MFT_MESSAGE_COMMAND_DRAIN for resampler. CW-Bug-Id: #21804 CW-Bug-Id: #22299 --- dlls/winegstreamer/resampler.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c index 9c87a5431b2..9df0d6fe563 100644 --- a/dlls/winegstreamer/resampler.c +++ b/dlls/winegstreamer/resampler.c @@ -506,7 +506,18 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); + struct resampler *impl = impl_from_IMFTransform(iface); + + TRACE("iface %p, message %#x, param %p.\n", iface, message, (void *)param); + + if (!impl->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (message == MFT_MESSAGE_COMMAND_DRAIN) + return wg_transform_drain(impl->wg_transform); + + FIXME("Ignoring message %#x.\n", message); + return S_OK; } From 4b9875341a29e13653f5cd0e8f34f20f49d80e6f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 20 Jan 2023 14:48:48 -0600 Subject: [PATCH 2046/2777] winegstreamer: Implement MFT_MESSAGE_COMMAND_DRAIN for video processor. CW-Bug-Id: #21804 CW-Bug-Id: #22299 --- dlls/winegstreamer/video_processor.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index 0164557234a..4c5e822d14a 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -506,7 +506,18 @@ static HRESULT WINAPI video_processor_ProcessEvent(IMFTransform *iface, DWORD id static HRESULT WINAPI video_processor_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - FIXME("iface %p, message %#x, param %#Ix stub!\n", iface, message, param); + struct video_processor *impl = impl_from_IMFTransform(iface); + + TRACE("iface %p, message %#x, param %p.\n", iface, message, (void *)param); + + if (!impl->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (message == MFT_MESSAGE_COMMAND_DRAIN) + return wg_transform_drain(impl->wg_transform); + + FIXME("Ignoring message %#x.\n", message); + return S_OK; } From e27e2d4a42e3d30bf361f30ab8c6b836b5f1d3e8 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 20 Jan 2023 14:50:38 -0600 Subject: [PATCH 2047/2777] winegstreamer: Implement MFT_MESSAGE_COMMAND_DRAIN for wma decoder. CW-Bug-Id: #21804 CW-Bug-Id: #22299 --- dlls/winegstreamer/wma_decoder.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c index 10bcd4162a1..eff8c414ea8 100644 --- a/dlls/winegstreamer/wma_decoder.c +++ b/dlls/winegstreamer/wma_decoder.c @@ -523,7 +523,18 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { - FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); + struct wma_decoder *decoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, message %#x, param %p.\n", iface, message, (void *)param); + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (message == MFT_MESSAGE_COMMAND_DRAIN) + return wg_transform_drain(decoder->wg_transform); + + FIXME("Ignoring message %#x.\n", message); + return S_OK; } From b164066f09f52a50f4a9bbceb9921b835972674a Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Fri, 2 Jun 2023 17:30:13 +0800 Subject: [PATCH 2048/2777] winegstreamer: Fix check for non-zero padding in mf_media_type_from_wg_format_video(). Similar to 35f9091, IsRectEmpty() is the wrong way to check if padding is empty. CW-Bug-Id: #22299 --- dlls/winegstreamer/mfplat.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 9e0f3db23bb..09b0cc9eb2a 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -538,7 +538,8 @@ static IMFMediaType *mf_media_type_from_wg_format_video(const struct wg_format * stride = -stride; IMFMediaType_SetUINT32(type, &MF_MT_DEFAULT_STRIDE, stride); - if (!IsRectEmpty(&format->u.video.padding)) + if (format->u.video.padding.left || format->u.video.padding.right + || format->u.video.padding.top || format->u.video.padding.bottom) { MFVideoArea aperture = { From 8075bbf8ece5d6319469acdf4496b840cc737adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 29 Jun 2023 11:48:55 +0200 Subject: [PATCH 2049/2777] winegstreamer: Allow concurrent wait_on_sample in the media source. Fixes deadlock in Disaster Report 4: Summer Memories. CW-Bug-Id: #22377 --- dlls/winegstreamer/media_source_old.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/media_source_old.c b/dlls/winegstreamer/media_source_old.c index 624ecc86cad..d60bed89eb4 100644 --- a/dlls/winegstreamer/media_source_old.c +++ b/dlls/winegstreamer/media_source_old.c @@ -47,6 +47,9 @@ struct media_stream DWORD stream_id; BOOL active; BOOL eos; + + DWORD busy; + CONDITION_VARIABLE cond; }; enum source_async_op @@ -532,13 +535,21 @@ static void wait_on_sample(struct media_stream *stream, IUnknown *token) struct media_source *source = impl_from_IMFMediaSource(stream->media_source); PROPVARIANT empty_var = {.vt = VT_EMPTY}; struct wg_parser_buffer buffer; + BOOL ret; TRACE("%p, %p\n", stream, token); - if (wg_parser_stream_get_buffer(source->wg_parser, stream->wg_stream, &buffer)) - { + stream->busy = TRUE; + LeaveCriticalSection(&source->cs); + ret = wg_parser_stream_get_buffer(source->wg_parser, stream->wg_stream, &buffer); + EnterCriticalSection(&source->cs); + stream->busy = FALSE; + WakeConditionVariable(&stream->cond); + + if (source->state == SOURCE_SHUTDOWN) + WARN("media source has been shutdown, returning\n"); + else if (ret) send_buffer(stream, &buffer, token); - } else { stream->eos = TRUE; @@ -1398,6 +1409,7 @@ static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface) static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) { struct media_source *source = impl_from_IMFMediaSource(iface); + UINT i; TRACE("%p.\n", iface); @@ -1411,6 +1423,14 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) source->state = SOURCE_SHUTDOWN; + for (i = 0; i < source->stream_count; i++) + { + struct media_stream *stream = source->streams[i]; + wg_parser_stream_disable(stream->wg_stream); + while (stream->busy) + SleepConditionVariableCS(&stream->cond, &source->cs, INFINITE); + } + wg_parser_disconnect(source->wg_parser); source->read_thread_shutdown = true; From eb2aaad42904deb56f7e684fa605cdfff8bb32b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 6 Jun 2023 16:16:10 +0200 Subject: [PATCH 2050/2777] HACK: winegstreamer: Add MF_MT_VIDEO_NOMINAL_RANGE on every video stream types. This seems to be currently required for the source reader to match media types. We need to confirm that the attribute is supposed to be there. CW-Bug-Id: #22324 --- dlls/winegstreamer/media_source_old.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dlls/winegstreamer/media_source_old.c b/dlls/winegstreamer/media_source_old.c index d60bed89eb4..c9a76349e82 100644 --- a/dlls/winegstreamer/media_source_old.c +++ b/dlls/winegstreamer/media_source_old.c @@ -921,8 +921,6 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) goto done; } - IMFMediaType_SetUINT32(base_type, &MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_Normal); - IMFMediaType_GetGUID(base_type, &MF_MT_SUBTYPE, &base_subtype); stream_types[0] = base_type; @@ -955,6 +953,12 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) stream_types[type_count++] = iyuv_type; } } + + for (i = 0; i < type_count; i++) + { + IMFMediaType_SetUINT32(stream_types[i], &MF_MT_VIDEO_NOMINAL_RANGE, + MFNominalRange_Normal); + } } else if (format.major_type == WG_MAJOR_TYPE_AUDIO) { From 40bc3433d5aa684fbd2b248d974279200b31cd0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 2 Jun 2023 11:40:34 +0200 Subject: [PATCH 2051/2777] Revert "winex11.drv: Cache clip window." This reverts commit 671e9f996519cc6bbfecc7fafee9eb759ad2d2a2. CW-Bug-Id: #21879 --- dlls/winex11.drv/mouse.c | 41 +++++++++------------------------------ dlls/winex11.drv/x11drv.h | 1 - 2 files changed, 9 insertions(+), 33 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 739960b083e..4142536b96f 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -152,34 +152,6 @@ MAKE_FUNCPTR(XGetDeviceButtonMapping); #undef MAKE_FUNCPTR #endif -static HWND get_clip_hwnd(void) -{ - static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0}; - struct x11drv_thread_data *data = x11drv_thread_data(); - UNICODE_STRING class_name; - HWND ret; - - if (data->cached_clip_hwnd) - { - ret = data->cached_clip_hwnd; - data->cached_clip_hwnd = NULL; - return ret; - } - RtlInitUnicodeString( &class_name, messageW ); - return NtUserCreateWindowEx( 0, &class_name, &class_name, NULL, 0, 0, 0, 0, 0, - HWND_MESSAGE, 0, NtCurrentTeb()->Peb->ImageBaseAddress, - NULL, 0, NULL, 0, FALSE ); -} - -static void release_clip_hwnd( HWND hwnd ) -{ - struct x11drv_thread_data *data = x11drv_thread_data(); - - if (data->cached_clip_hwnd) - NtUserDestroyWindow( data->cached_clip_hwnd ); - data->cached_clip_hwnd = hwnd; -} - /*********************************************************************** * X11DRV_Xcursor_Init * @@ -464,7 +436,9 @@ void X11DRV_XInput2_Enable( Display *display, Window window, long event_mask ) static BOOL grab_clipping_window( const RECT *clip ) { #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0}; struct x11drv_thread_data *data = x11drv_thread_data(); + UNICODE_STRING class_name; Window clip_window; HWND msg_hwnd = 0; POINT pos; @@ -476,7 +450,10 @@ static BOOL grab_clipping_window( const RECT *clip ) if (!data) return FALSE; if (!(clip_window = init_clip_window())) return TRUE; - if (!(msg_hwnd = get_clip_hwnd())) + RtlInitUnicodeString( &class_name, messageW ); + if (!(msg_hwnd = NtUserCreateWindowEx( 0, &class_name, &class_name, NULL, 0, 0, 0, 0, 0, + HWND_MESSAGE, 0, NtCurrentTeb()->Peb->ImageBaseAddress, + NULL, 0, NULL, 0, FALSE ))) return TRUE; /* enable XInput2 unless we are already clipping */ @@ -515,7 +492,7 @@ static BOOL grab_clipping_window( const RECT *clip ) if (!clipping_cursor) { X11DRV_XInput2_Enable( data->display, None, 0 ); - release_clip_hwnd( msg_hwnd ); + NtUserDestroyWindow( msg_hwnd ); return FALSE; } clip_rect = *clip; @@ -588,7 +565,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) data->clip_hwnd = 0; data->clip_reset = NtGetTickCount(); X11DRV_XInput2_Enable( data->display, None, 0 ); - release_clip_hwnd( hwnd ); + NtUserDestroyWindow( hwnd ); } else if (prev_clip_hwnd) { @@ -596,7 +573,7 @@ LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) * dangling clip window. */ TRACE( "destroying old clip hwnd %p\n", prev_clip_hwnd ); - release_clip_hwnd( prev_clip_hwnd ); + NtUserDestroyWindow( prev_clip_hwnd ); } return 0; } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index e6fd5ef940b..0bc79bd7a4d 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -402,7 +402,6 @@ struct x11drv_thread_data int xi2_active_touches; int xi2_primary_touchid; #endif /* HAVE_X11_EXTENSIONS_XINPUT2_H */ - HWND cached_clip_hwnd; }; extern struct x11drv_thread_data *x11drv_init_thread_data(void) DECLSPEC_HIDDEN; From e31e5ed296cc2c1a225cfc76d08e4d8cc9524094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 2 Jun 2023 11:17:19 +0200 Subject: [PATCH 2052/2777] Revert "winex11.drv: Flush X connection after ungrabbing the pointer." This reverts commit 4866e64ec2877b0b91da8f745ed550127f8fb59e. CW-Bug-Id: #21879 --- dlls/winex11.drv/mouse.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 4142536b96f..ba16ea861be 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -521,11 +521,7 @@ void ungrab_clipping_window(void) TRACE( "no longer clipping\n" ); XUnmapWindow( display, clip_window ); - if (clipping_cursor) - { - XUngrabPointer( display, CurrentTime ); - XFlush( display ); - } + if (clipping_cursor) XUngrabPointer( display, CurrentTime ); clipping_cursor = FALSE; send_notify_message( NtUserGetDesktopWindow(), WM_X11DRV_CLIP_CURSOR_NOTIFY, 0, 0 ); } From 1aa605825f503654da06bb92c2a525f6f774f559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 26 Jun 2023 10:59:45 +0200 Subject: [PATCH 2053/2777] Revert "winex11.drv: Send missed KEYUP events on KeymapNotify." This reverts commit f7199f591890c5f826fe52ddbdf9f01a19f44dc9. --- dlls/winex11.drv/event.c | 2 -- dlls/winex11.drv/keyboard.c | 43 ++----------------------------------- dlls/winex11.drv/mouse.c | 2 -- dlls/winex11.drv/x11drv.h | 1 - 4 files changed, 2 insertions(+), 46 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 91329a39167..0a27fbfb065 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -898,8 +898,6 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (event->detail == NotifyPointer) return FALSE; if (hwnd == NtUserGetDesktopWindow()) return FALSE; - x11drv_thread_data()->keymapnotify_hwnd = hwnd; - /* Focus was just restored but it can be right after super was * pressed and gnome-shell needs a bit of time to respond and * toggle the activity view. If we grab the cursor right away diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index f476919f9f5..1d6cef40efb 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1195,19 +1195,11 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) int i, j; BYTE keystate[256]; WORD vkey; - DWORD flags; - KeyCode keycode; - HWND keymapnotify_hwnd; BOOL changed = FALSE; struct { WORD vkey; - WORD scan; WORD pressed; } keys[256]; - struct x11drv_thread_data *thread_data = x11drv_thread_data(); - - keymapnotify_hwnd = thread_data->keymapnotify_hwnd; - thread_data->keymapnotify_hwnd = NULL; if (!get_async_key_state( keystate )) return FALSE; @@ -1222,17 +1214,11 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) { for (j = 0; j < 8; j++) { - keycode = (i * 8) + j; - vkey = keyc2vkey[keycode]; + vkey = keyc2vkey[(i * 8) + j]; /* If multiple keys map to the same vkey, we want to report it as * pressed iff any of them are pressed. */ - if (!keys[vkey & 0xff].vkey) - { - keys[vkey & 0xff].vkey = vkey; - keys[vkey & 0xff].scan = keyc2scan[keycode] & 0xff; - } - + if (!keys[vkey & 0xff].vkey) keys[vkey & 0xff].vkey = vkey; if (event->xkeymap.key_vector[i] & (1<window, event->x, event->y, event->detail ); - x11drv_thread_data()->keymapnotify_hwnd = hwnd; - if (hwnd == x11drv_thread_data()->grab_hwnd) return FALSE; /* simulate a mouse motion event */ diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 0bc79bd7a4d..5f8cef45928 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -385,7 +385,6 @@ struct x11drv_thread_data XEvent *current_event; /* event currently being processed */ HWND grab_hwnd; /* window that currently grabs the mouse */ HWND last_focus; /* last window that had focus */ - HWND keymapnotify_hwnd; /* window that should receive modifier release events */ XIM xim; /* input method */ HWND last_xic_hwnd; /* last xic window */ XFontSet font_set; /* international text drawing font set */ From bbfd22bf7bf795d8c33e0c97d77c543b3171dd66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 2 Jun 2023 11:19:10 +0200 Subject: [PATCH 2054/2777] Revert "HACK: mutter: winex11.drv: Add a bit of delay before restoring mouse grabs on FocusIn." This reverts commit 0063bac7b18e10547de2ca1125f62ebbb98dd16b. CW-Bug-Id: #21879 --- dlls/winex11.drv/event.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 0a27fbfb065..755dfc6506d 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -898,17 +898,6 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (event->detail == NotifyPointer) return FALSE; if (hwnd == NtUserGetDesktopWindow()) return FALSE; - /* Focus was just restored but it can be right after super was - * pressed and gnome-shell needs a bit of time to respond and - * toggle the activity view. If we grab the cursor right away - * it will cancel it and super key will do nothing. - */ - if (event->mode == NotifyUngrab && wm_is_mutter(event->display)) - { - LARGE_INTEGER timeout = {.QuadPart = 100 * -10000}; - NtDelayExecution( FALSE, &timeout ); - } - if (!try_grab_pointer( event->display )) { /* ask the desktop window to release its grab before trying to get ours */ From 1b579cb4ddfefe3291cd07cb52300ff9db27398e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 2 Jun 2023 11:17:48 +0200 Subject: [PATCH 2055/2777] Revert "Revert "winex11.drv: Only call XWarpPointer if we can get exclusive pointer grab."" This reverts commit 7dc685f645fff8a6215006b42deb8fa8a1329a6e. CW-Bug-Id: #21879 --- dlls/winex11.drv/mouse.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 7d6e482d740..d3950b7d7d3 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1569,10 +1569,23 @@ BOOL X11DRV_SetCursorPos( INT x, INT y ) struct x11drv_thread_data *data = x11drv_init_thread_data(); POINT pos = virtual_screen_to_root( x, y ); + if (!clipping_cursor && + XGrabPointer( data->display, root_window, False, + PointerMotionMask | ButtonPressMask | ButtonReleaseMask, + GrabModeAsync, GrabModeAsync, None, None, CurrentTime ) != GrabSuccess) + { + WARN( "refusing to warp pointer to %u, %u without exclusive grab\n", (int)pos.x, (int)pos.y ); + return FALSE; + } + TRACE( "real setting to %s\n", wine_dbgstr_point( &pos ) ); XWarpPointer( data->display, root_window, root_window, 0, 0, 0, 0, pos.x, pos.y ); data->warp_serial = NextRequest( data->display ); + + if (!clipping_cursor) + XUngrabPointer( data->display, CurrentTime ); + XNoOp( data->display ); XFlush( data->display ); /* avoids bad mouse lag in games that do their own mouse warping */ TRACE( "warped to (fake) %d,%d serial %lu\n", x, y, data->warp_serial ); From 07c090fc91951385410ebc9e7cff941f34dec106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 2 Jun 2023 11:19:18 +0200 Subject: [PATCH 2056/2777] Revert "Revert "winex11.drv: Only grab or warp the cursor when keyboard isn't grabbed."" This reverts commit d3b5338ca388aa26374fed748ef2c493dd173609. CW-Bug-Id: #21879 --- dlls/winex11.drv/event.c | 37 +++++++++++++++++++++++++++++++++++++ dlls/winex11.drv/mouse.c | 12 ++++++++++++ dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 50 insertions(+) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 755dfc6506d..84f72176665 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -145,6 +145,9 @@ static const char * event_names[MAX_EVENT_HANDLERS] = "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent" }; +/* is someone else grabbing the keyboard, for example the WM, when manipulating the window */ +BOOL keyboard_grabbed = FALSE; + int xinput2_opcode = 0; static pthread_mutex_t input_cs = PTHREAD_MUTEX_INITIALIZER; @@ -898,6 +901,23 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (event->detail == NotifyPointer) return FALSE; if (hwnd == NtUserGetDesktopWindow()) return FALSE; + switch (event->mode) + { + case NotifyGrab: + /* these are received when moving undecorated managed windows on mutter */ + keyboard_grabbed = TRUE; + break; + case NotifyWhileGrabbed: + keyboard_grabbed = TRUE; + break; + case NotifyNormal: + keyboard_grabbed = FALSE; + break; + case NotifyUngrab: + keyboard_grabbed = FALSE; + break; + } + if (!try_grab_pointer( event->display )) { /* ask the desktop window to release its grab before trying to get ours */ @@ -1023,6 +1043,23 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) } if (!hwnd) return FALSE; + switch (event->mode) + { + case NotifyUngrab: + /* these are received when moving undecorated managed windows on mutter */ + keyboard_grabbed = FALSE; + break; + case NotifyNormal: + keyboard_grabbed = FALSE; + break; + case NotifyWhileGrabbed: + keyboard_grabbed = TRUE; + break; + case NotifyGrab: + keyboard_grabbed = TRUE; + break; + } + if (hwnd == NtUserGetForegroundWindow()) ungrab_clipping_window(); /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index d3950b7d7d3..0e4a87e6cd6 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -456,6 +456,12 @@ static BOOL grab_clipping_window( const RECT *clip ) NULL, 0, NULL, 0, FALSE ))) return TRUE; + if (keyboard_grabbed) + { + WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) ); + return FALSE; + } + /* enable XInput2 unless we are already clipping */ if (!data->clip_hwnd) X11DRV_XInput2_Enable( data->display, None, PointerMotionMask ); @@ -1569,6 +1575,12 @@ BOOL X11DRV_SetCursorPos( INT x, INT y ) struct x11drv_thread_data *data = x11drv_init_thread_data(); POINT pos = virtual_screen_to_root( x, y ); + if (keyboard_grabbed) + { + WARN( "refusing to warp to %u, %u\n", (int)pos.x, (int)pos.y ); + return FALSE; + } + if (!clipping_cursor && XGrabPointer( data->display, root_window, False, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 5f8cef45928..1d4e2f75486 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -437,6 +437,7 @@ extern Colormap default_colormap DECLSPEC_HIDDEN; extern XPixmapFormatValues **pixmap_formats DECLSPEC_HIDDEN; extern Window root_window DECLSPEC_HIDDEN; extern BOOL clipping_cursor DECLSPEC_HIDDEN; +extern BOOL keyboard_grabbed DECLSPEC_HIDDEN; extern unsigned int screen_bpp DECLSPEC_HIDDEN; extern BOOL usexrandr DECLSPEC_HIDDEN; extern BOOL usexvidmode DECLSPEC_HIDDEN; From bdc73a41952cc1d757673506e54b2b19d2190931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 2 Jun 2023 11:19:22 +0200 Subject: [PATCH 2057/2777] Revert "winex11.drv: Restore pointer grab on FocusIn events." This reverts commit 48294dc6b2b35cac26badd08f07306b416e0aba0. CW-Bug-Id: #21879 --- dlls/winex11.drv/event.c | 13 +++++++------ dlls/winex11.drv/mouse.c | 24 ++++++++++++++++++++++++ dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 84f72176665..bca0d4e62a4 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -915,6 +915,7 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) break; case NotifyUngrab: keyboard_grabbed = FALSE; + retry_grab_clipping_window(); break; } @@ -926,12 +927,6 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) return FALSE; } - /* ask the foreground window to re-apply the current ClipCursor rect */ - if (!send_message_timeout( NtUserGetForegroundWindow(), WM_X11DRV_CLIP_CURSOR_REQUEST, 0, 0, - SMTO_NOTIMEOUTIFNOTHUNG, 500, NULL ) && - RtlGetLastWin32Error() == ERROR_TIMEOUT) - ERR( "WM_X11DRV_CLIP_CURSOR_REQUEST timed out.\n" ); - /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; @@ -1057,6 +1052,12 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) break; case NotifyGrab: keyboard_grabbed = TRUE; + + /* This will do nothing due to keyboard_grabbed == TRUE, but it + * will save the current clipping rect so we can restore it on + * FocusIn with NotifyUngrab mode. + */ + retry_grab_clipping_window(); break; } diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 0e4a87e6cd6..90ecd457f34 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -129,6 +129,9 @@ XContext cursor_context = 0; static HWND cursor_window; static HCURSOR last_cursor; static DWORD last_cursor_change; +static RECT last_clip_rect; +static HWND last_clip_foreground_window; +static BOOL last_clip_refused; static RECT clip_rect; static Cursor create_cursor( HANDLE handle ); @@ -459,8 +462,15 @@ static BOOL grab_clipping_window( const RECT *clip ) if (keyboard_grabbed) { WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) ); + last_clip_refused = TRUE; + last_clip_foreground_window = NtUserGetForegroundWindow(); + last_clip_rect = *clip; return FALSE; } + else + { + last_clip_refused = FALSE; + } /* enable XInput2 unless we are already clipping */ if (!data->clip_hwnd) X11DRV_XInput2_Enable( data->display, None, PointerMotionMask ); @@ -543,6 +553,20 @@ void reset_clipping_window(void) NtUserClipCursor( NULL ); /* make sure the clip rectangle is reset too */ } +/*********************************************************************** + * retry_grab_clipping_window + * + * Restore the current clip rectangle or retry the last one if it has + * been refused because of an active keyboard grab. + */ +void retry_grab_clipping_window(void) +{ + if (clipping_cursor) + NtUserClipCursor( &clip_rect ); + else if (last_clip_refused && NtUserGetForegroundWindow() == last_clip_foreground_window) + NtUserClipCursor( &last_clip_rect ); +} + /*********************************************************************** * clip_cursor_notify * diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 1d4e2f75486..b601ab6880e 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -742,6 +742,7 @@ extern LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip extern LRESULT clip_cursor_request( HWND hwnd, BOOL fullscreen, BOOL reset ) DECLSPEC_HIDDEN; extern void ungrab_clipping_window(void) DECLSPEC_HIDDEN; extern void reset_clipping_window(void) DECLSPEC_HIDDEN; +extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN; extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN; extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN; extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN; From 8e278ca53fa69b475177d489b737824008b5c23f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 2 Jun 2023 11:19:23 +0200 Subject: [PATCH 2058/2777] Revert "winex11.drv: Release pointer grab on FocusOut events." This reverts commit 0227566268174b62cd0a6dbe97fdb25b1a398e17. CW-Bug-Id: #21879 --- dlls/winex11.drv/event.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index bca0d4e62a4..ec585c17a11 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1061,8 +1061,6 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) break; } - if (hwnd == NtUserGetForegroundWindow()) ungrab_clipping_window(); - /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; From 09fb11c2fad66f05d7bd37d12de0612d2d62caa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 2 Jun 2023 11:19:24 +0200 Subject: [PATCH 2059/2777] Revert "winex11.drv: Release pointer grab on focus change." This reverts commit bf0570916cb297aebe9a1361bf0c63d4f378dca0. CW-Bug-Id: #21879 --- dlls/winex11.drv/event.c | 2 -- dlls/winex11.drv/window.c | 2 -- dlls/winex11.drv/x11drv.h | 3 +-- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index ec585c17a11..b3073fc4423 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -706,8 +706,6 @@ static void set_focus( XEvent *xev, HWND hwnd, Time time ) if (!try_grab_pointer( xev->xany.display )) { - /* ask the foreground window to release its grab before trying to get ours */ - send_message( NtUserGetForegroundWindow(), WM_X11DRV_RELEASE_CURSOR, 0, 0 ); XSendEvent( xev->xany.display, xev->xany.window, False, 0, xev ); return; } diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 2e297ed3e05..3bbe4e20cf5 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -3722,8 +3722,6 @@ LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) return 0; case WM_X11DRV_ADD_TAB: taskbar_add_tab( hwnd ); - case WM_X11DRV_RELEASE_CURSOR: - ungrab_clipping_window(); return 0; default: FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, (long)wp, lp ); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index b601ab6880e..b082ee6a219 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -611,8 +611,7 @@ enum x11drv_window_messages WM_X11DRV_CLIP_CURSOR_NOTIFY, WM_X11DRV_CLIP_CURSOR_REQUEST, WM_X11DRV_DELETE_TAB, - WM_X11DRV_ADD_TAB, - WM_X11DRV_RELEASE_CURSOR, + WM_X11DRV_ADD_TAB }; /* _NET_WM_STATE properties that we keep track of */ From bd1ea9ad197b5e1a4eef13fbfc5034430e10c372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 2 Jun 2023 11:19:24 +0200 Subject: [PATCH 2060/2777] Revert "winex11.drv: Wait for pointer grab on FocusIn/WM_TAKE_FOCUS events." This reverts commit 14ad9a3418d8ac76cc956cd6878a4b393dc48937. CW-Bug-Id: #21879 --- dlls/winex11.drv/event.c | 43 +++------------------------------------- 1 file changed, 3 insertions(+), 40 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index b3073fc4423..98ecf4b8ad9 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -386,25 +386,6 @@ static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawE } #endif -static int try_grab_pointer( Display *display ) -{ - if (!grab_pointer) - return 1; - - /* if we are already clipping the cursor in the current thread, we should not - * call XGrabPointer here or it would change the confine-to window. */ - if (clipping_cursor && x11drv_thread_data()->clip_hwnd) - return 1; - - if (XGrabPointer( display, root_window, False, 0, GrabModeAsync, GrabModeAsync, - None, None, CurrentTime ) != GrabSuccess) - return 0; - - XUngrabPointer( display, CurrentTime ); - XFlush( display ); - return 1; -} - /*********************************************************************** * merge_events * @@ -704,16 +685,8 @@ static void set_focus( XEvent *xev, HWND hwnd, Time time ) Window win; GUITHREADINFO threadinfo; - if (!try_grab_pointer( xev->xany.display )) - { - XSendEvent( xev->xany.display, xev->xany.window, False, 0, xev ); - return; - } - else - { - TRACE( "setting foreground window to %p\n", hwnd ); - NtUserSetForegroundWindow( hwnd ); - } + TRACE( "setting foreground window to %p\n", hwnd ); + NtUserSetForegroundWindow( hwnd ); threadinfo.cbSize = sizeof(threadinfo); NtUserGetGUIThreadInfo( 0, &threadinfo ); @@ -917,14 +890,6 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) break; } - if (!try_grab_pointer( event->display )) - { - /* ask the desktop window to release its grab before trying to get ours */ - send_message( NtUserGetDesktopWindow(), WM_X11DRV_RELEASE_CURSOR, 0, 0 ); - XSendEvent( event->display, event->window, False, 0, xev ); - return FALSE; - } - /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; @@ -943,10 +908,8 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (!hwnd) hwnd = get_active_window(); if (!hwnd) hwnd = x11drv_thread_data()->last_focus; if (hwnd && can_activate_window(hwnd)) set_focus( xev, hwnd, CurrentTime ); - return TRUE; } - - NtUserSetForegroundWindow( hwnd ); + else NtUserSetForegroundWindow( hwnd ); return TRUE; } From c41d03291fd89aefa40d18c6288a394148d8ef50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 2 Jun 2023 11:19:37 +0200 Subject: [PATCH 2061/2777] Revert "winex11.drv: Merge FocusIn/FocusOut NotifyGrab/NotifyUngrab cases." This reverts commit 0fc22ab365fd4c5728d9f51d4d844afb5b85aa6a. CW-Bug-Id: #21879 --- dlls/winex11.drv/event.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 98ecf4b8ad9..85d655a5251 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -877,7 +877,7 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) case NotifyGrab: /* these are received when moving undecorated managed windows on mutter */ keyboard_grabbed = TRUE; - break; + return FALSE; case NotifyWhileGrabbed: keyboard_grabbed = TRUE; break; @@ -887,14 +887,10 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) case NotifyUngrab: keyboard_grabbed = FALSE; retry_grab_clipping_window(); - break; + return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ } - /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ - if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; - xim_set_focus( hwnd, TRUE ); - if (use_take_focus) { if (hwnd == NtUserGetForegroundWindow()) clip_fullscreen_window( hwnd, FALSE ); @@ -1004,7 +1000,7 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) case NotifyUngrab: /* these are received when moving undecorated managed windows on mutter */ keyboard_grabbed = FALSE; - break; + return FALSE; case NotifyNormal: keyboard_grabbed = FALSE; break; @@ -1019,11 +1015,9 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) * FocusIn with NotifyUngrab mode. */ retry_grab_clipping_window(); - break; - } - /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ - if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; + return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ + } focus_out( event->display, hwnd ); return TRUE; From bc6666b04d2ab9220971ced4a08bceeeb7d0d5f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 5 Jun 2023 10:44:28 +0200 Subject: [PATCH 2062/2777] Revert "winex11.drv: Pass XEvent instead of Display to set_focus." This reverts commit 0ff06a59a96d89b1dcb203f340a871f1a0885a57. CW-Bug-Id: #21879 --- dlls/winex11.drv/event.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 85d655a5251..72eb2cfe443 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -679,7 +679,7 @@ static void set_input_focus( struct x11drv_win_data *data ) /********************************************************************** * set_focus */ -static void set_focus( XEvent *xev, HWND hwnd, Time time ) +static void set_focus( Display *display, HWND hwnd, Time time ) { HWND focus; Window win; @@ -698,7 +698,7 @@ static void set_focus( XEvent *xev, HWND hwnd, Time time ) if (win) { TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time ); - XSetInputFocus( xev->xany.display, win, RevertToParent, time ); + XSetInputFocus( display, win, RevertToParent, time ); } } @@ -807,7 +807,7 @@ static void handle_wm_protocols( HWND hwnd, XEvent *xev ) MAKELONG( HTMENU, WM_LBUTTONDOWN ) ); if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) { - set_focus( xev, hwnd, event_time ); + set_focus( event->display, hwnd, event_time ); return; } } @@ -816,7 +816,7 @@ static void handle_wm_protocols( HWND hwnd, XEvent *xev ) hwnd = NtUserGetForegroundWindow(); if (!hwnd) hwnd = last_focus; if (!hwnd) hwnd = NtUserGetDesktopWindow(); - set_focus( xev, hwnd, event_time ); + set_focus( event->display, hwnd, event_time ); return; } /* try to find some other window to give the focus to */ @@ -824,7 +824,7 @@ static void handle_wm_protocols( HWND hwnd, XEvent *xev ) if (hwnd) hwnd = NtUserGetAncestor( hwnd, GA_ROOT ); if (!hwnd) hwnd = get_active_window(); if (!hwnd) hwnd = last_focus; - if (hwnd && can_activate_window(hwnd)) set_focus( xev, hwnd, event_time ); + if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time ); } else if (protocol == x11drv_atom(_NET_WM_PING)) { @@ -903,7 +903,7 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (hwnd) hwnd = NtUserGetAncestor( hwnd, GA_ROOT ); if (!hwnd) hwnd = get_active_window(); if (!hwnd) hwnd = x11drv_thread_data()->last_focus; - if (hwnd && can_activate_window(hwnd)) set_focus( xev, hwnd, CurrentTime ); + if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime ); } else NtUserSetForegroundWindow( hwnd ); return TRUE; From 60cc101c5fe3be981cd3ef314c36fe5b8803f36e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 2 Jun 2023 11:20:50 +0200 Subject: [PATCH 2063/2777] Revert "winex11.drv: Ignore ClipCursor if desktop window is foreground." This reverts commit 5d75cc698669673ab44e65a3181f93d6a99512af. CW-Bug-Id: #21879 --- dlls/winex11.drv/mouse.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 90ecd457f34..eebfb4939a8 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1667,13 +1667,6 @@ BOOL X11DRV_ClipCursor( LPCRECT clip ) HWND foreground = NtUserGetForegroundWindow(); DWORD tid, pid; - if (foreground == NtUserGetDesktopWindow()) - { - WARN( "desktop is foreground, ignoring ClipCursor\n" ); - ungrab_clipping_window(); - return TRUE; - } - /* forward request to the foreground window if it's in a different thread */ tid = NtUserGetWindowThread( foreground, &pid ); if (tid && tid != GetCurrentThreadId() && pid == GetCurrentProcessId()) From bd700ab56d44343c142879312f39c201f5469905 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 2 Jun 2023 11:21:35 +0200 Subject: [PATCH 2064/2777] Revert "server: Use the helper to reset the clip rect when the desktop size changes." This reverts commit 2a44dd0e99fb87b86441e43a181251a0f061a59c. CW-Bug-Id: #21879 --- server/queue.c | 2 +- server/user.h | 1 - server/window.c | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/server/queue.c b/server/queue.c index f51263ed692..d1ebe48958d 100644 --- a/server/queue.c +++ b/server/queue.c @@ -538,7 +538,7 @@ static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsig } /* set the cursor clip rectangle */ -void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int send_clip_msg ) +static void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int send_clip_msg ) { rectangle_t top_rect, new_rect; int x, y; diff --git a/server/user.h b/server/user.h index deebd92ee6a..bbc665b1da1 100644 --- a/server/user.h +++ b/server/user.h @@ -117,7 +117,6 @@ extern void post_win_event( struct thread *thread, unsigned int event, user_handle_t handle ); extern void free_hotkeys( struct desktop *desktop, user_handle_t window ); extern void free_touches( struct desktop *desktop, user_handle_t window ); -extern void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int send_clip_msg ); /* region functions */ diff --git a/server/window.c b/server/window.c index 302aa2e6071..83aab43a583 100644 --- a/server/window.c +++ b/server/window.c @@ -1831,7 +1831,7 @@ static void set_window_pos( struct window *win, struct window *previous, } /* reset cursor clip rectangle when the desktop changes size */ - if (win == win->desktop->top_window) set_clip_rectangle( win->desktop, NULL, 0 ); + if (win == win->desktop->top_window) win->desktop->shared->cursor.clip = *window_rect; /* if the window is not visible, everything is easy */ if (!visible) return; From 85aa45465e6cd38477b03d25ed3bde90e383e9ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 2 Jun 2023 11:39:26 +0200 Subject: [PATCH 2065/2777] Revert "winex11.drv: Enable fullscreen clipping even if not already clipping." This reverts commit dba0a0db9bb647ab8d0d5b894d9e8cc00ea181b5. CW-Bug-Id: #21879 --- dlls/winex11.drv/mouse.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index eebfb4939a8..4d475173347 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1682,12 +1682,12 @@ BOOL X11DRV_ClipCursor( LPCRECT clip ) { if (grab_clipping_window( clip )) return TRUE; } - else /* check if we should switch to fullscreen clipping */ + else /* if currently clipping, check if we should switch to fullscreen clipping */ { struct x11drv_thread_data *data = x11drv_thread_data(); - if (data) + if (data && data->clip_hwnd) { - if ((data->clip_hwnd && EqualRect( clip, &clip_rect ) && !EqualRect(&clip_rect, &virtual_rect)) || clip_fullscreen_window( foreground, TRUE )) + if (EqualRect( clip, &clip_rect ) || clip_fullscreen_window( foreground, TRUE )) return TRUE; } } From 125397c2408e1d0458bbc7fb4be56401944207f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 2 Jun 2023 11:43:09 +0200 Subject: [PATCH 2066/2777] Revert "winex11.drv: Ignore clip_reset when trying to clip the mouse after the desktop has been resized." This reverts commit e56ad03113d0a67024b6e207af27cc434dc85b1f. CW-Bug-Id: #21879 --- dlls/winex11.drv/mouse.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 4d475173347..a4a3715994f 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -629,10 +629,9 @@ BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) release_win_data( data ); if (!fullscreen) return FALSE; if (!(thread_data = x11drv_thread_data())) return FALSE; - if (!reset) { - if (NtGetTickCount() - thread_data->clip_reset < 1000) return FALSE; - if (!reset && clipping_cursor && thread_data->clip_hwnd) return FALSE; /* already clipping */ - } + if (NtGetTickCount() - thread_data->clip_reset < 1000) return FALSE; + if (!reset && clipping_cursor && thread_data->clip_hwnd) return FALSE; /* already clipping */ + monitor = NtUserMonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST ); if (!monitor) return FALSE; monitor_info.cbSize = sizeof(monitor_info); From 81cc4f2d6b49b88f60104147c5b68eb229be5a0c Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Tue, 28 Feb 2023 09:49:36 -0700 Subject: [PATCH 2067/2777] winex11: Avoid calling RtlInitUnicodeString on a static constant. (cherry picked from commit 354e999c5a8f284af3fe833f9fb45bace151a44e) --- dlls/winex11.drv/mouse.c | 3 +-- dlls/winex11.drv/window.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index a4a3715994f..faa3aacdd3f 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -441,7 +441,7 @@ static BOOL grab_clipping_window( const RECT *clip ) #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0}; struct x11drv_thread_data *data = x11drv_thread_data(); - UNICODE_STRING class_name; + UNICODE_STRING class_name = RTL_CONSTANT_STRING( messageW ); Window clip_window; HWND msg_hwnd = 0; POINT pos; @@ -453,7 +453,6 @@ static BOOL grab_clipping_window( const RECT *clip ) if (!data) return FALSE; if (!(clip_window = init_clip_window())) return TRUE; - RtlInitUnicodeString( &class_name, messageW ); if (!(msg_hwnd = NtUserCreateWindowEx( 0, &class_name, &class_name, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, NtCurrentTeb()->Peb->ImageBaseAddress, NULL, 0, NULL, 0, FALSE ))) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 3bbe4e20cf5..849b7fe0596 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2501,7 +2501,7 @@ HWND create_foreign_window( Display *display, Window xwin ) unsigned int nchildren; XWindowAttributes attr; UINT style = WS_CLIPCHILDREN; - UNICODE_STRING class_name; + UNICODE_STRING class_name = RTL_CONSTANT_STRING( classW ); if (!class_registered) { @@ -2512,7 +2512,6 @@ HWND create_foreign_window( Display *display, Window xwin ) class.cbSize = sizeof(class); class.lpfnWndProc = client_foreign_window_proc; class.lpszClassName = classW; - RtlInitUnicodeString( &class_name, classW ); if (!NtUserRegisterClassExWOW( &class, &class_name, &version, NULL, 0, 0, NULL ) && RtlGetLastWin32Error() != ERROR_CLASS_ALREADY_EXISTS) { From 76a573efbb5cb6dd294739fcb5ad86cc1e4543ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 30 May 2023 23:39:59 +0200 Subject: [PATCH 2068/2777] server: Assume the internal clip message to be WM_WINE_CLIPCURSOR. (cherry picked from commit 61dbfea452c0efc676d521ab5374abda108f4f1e) CW-Bug-Id: #21879 --- dlls/win32u/cursoricon.c | 1 - include/wine/server_protocol.h | 2 -- server/protocol.def | 1 - server/queue.c | 9 ++------- server/request.h | 3 +-- server/trace.c | 1 - server/user.h | 1 - server/winstation.c | 1 - 8 files changed, 3 insertions(+), 16 deletions(-) diff --git a/dlls/win32u/cursoricon.c b/dlls/win32u/cursoricon.c index eb1d07afb6c..ec143b841fd 100644 --- a/dlls/win32u/cursoricon.c +++ b/dlls/win32u/cursoricon.c @@ -174,7 +174,6 @@ BOOL WINAPI NtUserClipCursor( const RECT *rect ) SERVER_START_REQ( set_cursor ) { - req->clip_msg = WM_WINE_CLIPCURSOR; if (rect) { req->flags = SET_CURSOR_CLIP; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 472c0ea709d..7a7b22c0883 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -5281,8 +5281,6 @@ struct set_cursor_request int x; int y; rectangle_t clip; - unsigned int clip_msg; - char __pad_52[4]; }; struct set_cursor_reply { diff --git a/server/protocol.def b/server/protocol.def index 9589aacfbbc..9770db77706 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3749,7 +3749,6 @@ struct handle_info int x; /* cursor position */ int y; rectangle_t clip; /* cursor clip rectangle */ - unsigned int clip_msg; /* message to post on cursor clip changes */ @REPLY user_handle_t prev_handle; /* previous handle */ int prev_count; /* previous show count */ diff --git a/server/queue.c b/server/queue.c index d1ebe48958d..94e8aa5448e 100644 --- a/server/queue.c +++ b/server/queue.c @@ -34,6 +34,7 @@ #include "wingdi.h" #include "winuser.h" #include "winternl.h" +#include "ntuser.h" #include "handle.h" #include "file.h" @@ -558,8 +559,7 @@ static void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect SHARED_WRITE_BEGIN( &desktop->shared->seq ); desktop->shared->cursor.clip = new_rect; - if (desktop->cursor_clip_msg && send_clip_msg) - post_desktop_message( desktop, desktop->cursor_clip_msg, rect != NULL, 0 ); + if (send_clip_msg) post_desktop_message( desktop, WM_WINE_CLIPCURSOR, rect != NULL, 0 ); /* warp the mouse to be inside the clip rect */ x = max( min( desktop->shared->cursor.x, desktop->shared->cursor.clip.right - 1 ), desktop->shared->cursor.clip.left ); @@ -3718,11 +3718,6 @@ DECL_HANDLER(set_cursor) if (req->flags & (SET_CURSOR_CLIP | SET_CURSOR_NOCLIP)) { struct desktop *desktop = input->desktop; - - /* only the desktop owner can set the message */ - if (req->clip_msg && get_top_window_owner(desktop) == current->process) - desktop->cursor_clip_msg = req->clip_msg; - set_clip_rectangle( desktop, (req->flags & SET_CURSOR_NOCLIP) ? NULL : &req->clip, 0 ); } diff --git a/server/request.h b/server/request.h index 089af79e199..3443ee93c17 100644 --- a/server/request.h +++ b/server/request.h @@ -2209,8 +2209,7 @@ C_ASSERT( FIELD_OFFSET(struct set_cursor_request, show_count) == 20 ); C_ASSERT( FIELD_OFFSET(struct set_cursor_request, x) == 24 ); C_ASSERT( FIELD_OFFSET(struct set_cursor_request, y) == 28 ); C_ASSERT( FIELD_OFFSET(struct set_cursor_request, clip) == 32 ); -C_ASSERT( FIELD_OFFSET(struct set_cursor_request, clip_msg) == 48 ); -C_ASSERT( sizeof(struct set_cursor_request) == 56 ); +C_ASSERT( sizeof(struct set_cursor_request) == 48 ); C_ASSERT( FIELD_OFFSET(struct set_cursor_reply, prev_handle) == 8 ); C_ASSERT( FIELD_OFFSET(struct set_cursor_reply, prev_count) == 12 ); C_ASSERT( FIELD_OFFSET(struct set_cursor_reply, prev_x) == 16 ); diff --git a/server/trace.c b/server/trace.c index b749c54a900..a360b4706ce 100644 --- a/server/trace.c +++ b/server/trace.c @@ -4398,7 +4398,6 @@ static void dump_set_cursor_request( const struct set_cursor_request *req ) fprintf( stderr, ", x=%d", req->x ); fprintf( stderr, ", y=%d", req->y ); dump_rectangle( ", clip=", &req->clip ); - fprintf( stderr, ", clip_msg=%08x", req->clip_msg ); } static void dump_set_cursor_reply( const struct set_cursor_reply *req ) diff --git a/server/user.h b/server/user.h index bbc665b1da1..c8dc6e922d8 100644 --- a/server/user.h +++ b/server/user.h @@ -68,7 +68,6 @@ struct desktop struct thread_input *foreground_input; /* thread input of foreground thread */ unsigned int users; /* processes and threads using this desktop */ unsigned char keystate[256]; /* asynchronous key state */ - unsigned int cursor_clip_msg; /* message to post for cursor clip changes */ user_handle_t cursor_win; /* window that contains the cursor */ struct object *shared_mapping; /* desktop shared memory mapping */ volatile struct desktop_shared_memory *shared; /* desktop shared memory ptr */ diff --git a/server/winstation.c b/server/winstation.c index 53613592a82..9e5d3871a6f 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -260,7 +260,6 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned desktop->close_timeout_val = 0; desktop->foreground_input = NULL; desktop->users = 0; - desktop->cursor_clip_msg = 0; desktop->cursor_win = 0; desktop->last_press_alt = 0; list_add_tail( &winstation->desktops, &desktop->entry ); From 5229412d7e40aadad01649a3b3475ebdc8591dee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Jan 2021 15:05:19 +0100 Subject: [PATCH 2069/2777] server: Move set_cursor desktop local variable to wider scope. (cherry picked from commit 26c6386de90b93503231dcf44dc4efee28bbd736) CW-Bug-Id: #21879 --- server/queue.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/server/queue.c b/server/queue.c index 94e8aa5448e..b1c2bc65218 100644 --- a/server/queue.c +++ b/server/queue.c @@ -3684,14 +3684,16 @@ DECL_HANDLER(set_cursor) { struct msg_queue *queue = get_current_queue(); struct thread_input *input; + struct desktop *desktop; if (!queue) return; input = queue->input; + desktop = input->desktop; reply->prev_handle = input->shared->cursor; reply->prev_count = input->shared->cursor_count; - reply->prev_x = input->desktop->shared->cursor.x; - reply->prev_y = input->desktop->shared->cursor.y; + reply->prev_x = desktop->shared->cursor.x; + reply->prev_y = desktop->shared->cursor.y; if ((req->flags & SET_CURSOR_HANDLE) && req->handle && !get_user_object( req->handle, USER_CLIENT )) @@ -3711,20 +3713,14 @@ DECL_HANDLER(set_cursor) input->shared->cursor_count += req->show_count; } SHARED_WRITE_END( &input->shared->seq ); - if (req->flags & SET_CURSOR_POS) - { - set_cursor_pos( input->desktop, req->x, req->y ); - } - if (req->flags & (SET_CURSOR_CLIP | SET_CURSOR_NOCLIP)) - { - struct desktop *desktop = input->desktop; - set_clip_rectangle( desktop, (req->flags & SET_CURSOR_NOCLIP) ? NULL : &req->clip, 0 ); - } - - reply->new_x = input->desktop->shared->cursor.x; - reply->new_y = input->desktop->shared->cursor.y; - reply->new_clip = input->desktop->shared->cursor.clip; - reply->last_change = input->desktop->shared->cursor.last_change; + if (req->flags & SET_CURSOR_POS) set_cursor_pos( desktop, req->x, req->y ); + if (req->flags & SET_CURSOR_CLIP) set_clip_rectangle( desktop, &req->clip, 0 ); + if (req->flags & SET_CURSOR_NOCLIP) set_clip_rectangle( desktop, NULL, 0 ); + + reply->new_x = desktop->shared->cursor.x; + reply->new_y = desktop->shared->cursor.y; + reply->new_clip = desktop->shared->cursor.clip; + reply->last_change = desktop->shared->cursor.last_change; } /* Get the history of the 64 last cursor positions */ From fdb37f132b376835c3863425681b4af8ab619ddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 May 2023 13:50:11 +0200 Subject: [PATCH 2070/2777] win32u: Rename user driver CreateDesktopWindow entry to SetDesktopWindow. This doesn't create anything, but instead notifies the user driver of the current desktop window, either when it is created, or when a thread calling NtUserGetDesktopWindow receives the current desktop window. (cherry picked from commit 15dfe2ed2d625d0a80c6189472285af67a5f252d) CW-Bug-Id: #21879 --- dlls/win32u/driver.c | 23 +++++++++++------------ dlls/win32u/window.c | 4 +--- dlls/win32u/winstation.c | 5 ++--- dlls/winemac.drv/gdi.c | 2 +- dlls/winemac.drv/macdrv.h | 2 +- dlls/winemac.drv/window.c | 5 ++--- dlls/winex11.drv/init.c | 2 +- dlls/winex11.drv/window.c | 5 ++--- dlls/winex11.drv/x11drv.h | 2 +- include/wine/gdi_driver.h | 2 +- 10 files changed, 23 insertions(+), 29 deletions(-) diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 5b8cbb56813..2d5d987652c 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -783,11 +783,6 @@ static BOOL nulldrv_UpdateDisplayDevices( const struct gdi_device_manager *manag return FALSE; } -static BOOL nulldrv_CreateDesktopWindow( HWND hwnd ) -{ - return TRUE; -} - static BOOL nodrv_CreateWindow( HWND hwnd ) { static int warned; @@ -842,6 +837,10 @@ static void nulldrv_SetCapture( HWND hwnd, UINT flags ) { } +static void nulldrv_SetDesktopWindow( HWND hwnd ) +{ +} + static void nulldrv_SetFocus( HWND hwnd ) { } @@ -1150,11 +1149,6 @@ static BOOL loaderdrv_UpdateDisplayDevices( const struct gdi_device_manager *man return load_driver()->pUpdateDisplayDevices( manager, force, param ); } -static BOOL loaderdrv_CreateDesktopWindow( HWND hwnd ) -{ - return load_driver()->pCreateDesktopWindow( hwnd ); -} - static BOOL loaderdrv_CreateWindow( HWND hwnd ) { return load_driver()->pCreateWindow( hwnd ); @@ -1171,6 +1165,11 @@ static void loaderdrv_FlashWindowEx( FLASHWINFO *info ) load_driver()->pFlashWindowEx( info ); } +static void loaderdrv_SetDesktopWindow( HWND hwnd ) +{ + load_driver()->pSetDesktopWindow( hwnd ); +} + static void loaderdrv_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags ) { load_driver()->pSetLayeredWindowAttributes( hwnd, key, alpha, flags ); @@ -1223,7 +1222,6 @@ static const struct user_driver_funcs lazy_load_driver = loaderdrv_GetDisplayDepth, loaderdrv_UpdateDisplayDevices, /* windowing functions */ - loaderdrv_CreateDesktopWindow, loaderdrv_CreateWindow, nulldrv_DesktopWindowProc, nulldrv_DestroyWindow, @@ -1233,6 +1231,7 @@ static const struct user_driver_funcs lazy_load_driver = nulldrv_ReleaseDC, nulldrv_ScrollDC, nulldrv_SetCapture, + loaderdrv_SetDesktopWindow, nulldrv_SetFocus, loaderdrv_SetLayeredWindowAttributes, nulldrv_SetParent, @@ -1301,7 +1300,6 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version SET_USER_FUNC(GetCurrentDisplaySettings); SET_USER_FUNC(GetDisplayDepth); SET_USER_FUNC(UpdateDisplayDevices); - SET_USER_FUNC(CreateDesktopWindow); SET_USER_FUNC(CreateWindow); SET_USER_FUNC(DesktopWindowProc); SET_USER_FUNC(DestroyWindow); @@ -1311,6 +1309,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version SET_USER_FUNC(ReleaseDC); SET_USER_FUNC(ScrollDC); SET_USER_FUNC(SetCapture); + SET_USER_FUNC(SetDesktopWindow); SET_USER_FUNC(SetFocus); SET_USER_FUNC(SetLayeredWindowAttributes); SET_USER_FUNC(SetParent); diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 333fde4b472..eb9a71fa86f 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -4972,9 +4972,7 @@ static WND *create_window_handle( HWND parent, HWND owner, UNICODE_STRING *name, if (!thread_info->top_window) thread_info->top_window = HandleToUlong( full_parent ? full_parent : handle ); else assert( full_parent == UlongToHandle( thread_info->top_window )); - if (full_parent && - !user_driver->pCreateDesktopWindow( UlongToHandle( thread_info->top_window ))) - ERR( "failed to create desktop window\n" ); + if (full_parent) user_driver->pSetDesktopWindow( UlongToHandle( thread_info->top_window )); register_builtin_classes(); } else /* HWND_MESSAGE parent */ diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 79808010598..79dfa4671ac 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -520,9 +520,8 @@ HWND get_desktop_window(void) SERVER_END_REQ; } - if (!thread_info->top_window || - !user_driver->pCreateDesktopWindow( UlongToHandle( thread_info->top_window ))) - ERR_(win)( "failed to create desktop window\n" ); + if (!thread_info->top_window) ERR_(win)( "failed to create desktop window\n" ); + else user_driver->pSetDesktopWindow( UlongToHandle( thread_info->top_window )); register_builtin_classes(); return UlongToHandle( thread_info->top_window ); diff --git a/dlls/winemac.drv/gdi.c b/dlls/winemac.drv/gdi.c index ef19b39cade..4d2f25983f8 100644 --- a/dlls/winemac.drv/gdi.c +++ b/dlls/winemac.drv/gdi.c @@ -271,7 +271,6 @@ static const struct user_driver_funcs macdrv_funcs = .pChangeDisplaySettings = macdrv_ChangeDisplaySettings, .pClipCursor = macdrv_ClipCursor, .pClipboardWindowProc = macdrv_ClipboardWindowProc, - .pCreateDesktopWindow = macdrv_CreateDesktopWindow, .pDesktopWindowProc = macdrv_DesktopWindowProc, .pDestroyCursorIcon = macdrv_DestroyCursorIcon, .pDestroyWindow = macdrv_DestroyWindow, @@ -287,6 +286,7 @@ static const struct user_driver_funcs macdrv_funcs = .pSetCapture = macdrv_SetCapture, .pSetCursor = macdrv_SetCursor, .pSetCursorPos = macdrv_SetCursorPos, + .pSetDesktopWindow = macdrv_SetDesktopWindow, .pSetFocus = macdrv_SetFocus, .pSetLayeredWindowAttributes = macdrv_SetLayeredWindowAttributes, .pSetParent = macdrv_SetParent, diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 3dedd5e3043..d0fddcc0f21 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -134,9 +134,9 @@ extern BOOL macdrv_UpdateDisplayDevices( const struct gdi_device_manager *device extern BOOL macdrv_GetDeviceGammaRamp(PHYSDEV dev, LPVOID ramp) DECLSPEC_HIDDEN; extern BOOL macdrv_SetDeviceGammaRamp(PHYSDEV dev, LPVOID ramp) DECLSPEC_HIDDEN; extern BOOL macdrv_ClipCursor(LPCRECT clip) DECLSPEC_HIDDEN; -extern BOOL macdrv_CreateDesktopWindow(HWND hwnd) DECLSPEC_HIDDEN; extern LRESULT macdrv_DesktopWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) DECLSPEC_HIDDEN; extern void macdrv_DestroyWindow(HWND hwnd) DECLSPEC_HIDDEN; +extern void macdrv_SetDesktopWindow(HWND hwnd) DECLSPEC_HIDDEN; extern void macdrv_SetFocus(HWND hwnd) DECLSPEC_HIDDEN; extern void macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alpha, DWORD flags) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index 896efb6a68e..5b053f379a5 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -1528,9 +1528,9 @@ static void perform_window_command(HWND hwnd, unsigned int style_any, unsigned i /********************************************************************** - * CreateDesktopWindow (MACDRV.@) + * SetDesktopWindow (MACDRV.@) */ -BOOL macdrv_CreateDesktopWindow(HWND hwnd) +void macdrv_SetDesktopWindow(HWND hwnd) { unsigned int width, height; @@ -1567,7 +1567,6 @@ BOOL macdrv_CreateDesktopWindow(HWND hwnd) } set_app_icon(); - return TRUE; } void macdrv_resize_desktop(void) diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index fb879c9b483..9b457b6ccd8 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -411,7 +411,6 @@ static const struct user_driver_funcs x11drv_funcs = .pGetCurrentDisplaySettings = X11DRV_GetCurrentDisplaySettings, .pGetDisplayDepth = X11DRV_GetDisplayDepth, .pUpdateDisplayDevices = X11DRV_UpdateDisplayDevices, - .pCreateDesktopWindow = X11DRV_CreateDesktopWindow, .pCreateWindow = X11DRV_CreateWindow, .pDesktopWindowProc = X11DRV_DesktopWindowProc, .pDestroyWindow = X11DRV_DestroyWindow, @@ -421,6 +420,7 @@ static const struct user_driver_funcs x11drv_funcs = .pReleaseDC = X11DRV_ReleaseDC, .pScrollDC = X11DRV_ScrollDC, .pSetCapture = X11DRV_SetCapture, + .pSetDesktopWindow = X11DRV_SetDesktopWindow, .pSetFocus = X11DRV_SetFocus, .pSetLayeredWindowAttributes = X11DRV_SetLayeredWindowAttributes, .pSetParent = X11DRV_SetParent, diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 849b7fe0596..ef9521b2457 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2302,9 +2302,9 @@ BOOL create_desktop_win_data( Window win ) } /********************************************************************** - * CreateDesktopWindow (X11DRV.@) + * SetDesktopWindow (X11DRV.@) */ -BOOL X11DRV_CreateDesktopWindow( HWND hwnd ) +void X11DRV_SetDesktopWindow( HWND hwnd ) { unsigned int width, height; @@ -2344,7 +2344,6 @@ BOOL X11DRV_CreateDesktopWindow( HWND hwnd ) Window win = (Window)NtUserGetProp( hwnd, whole_window_prop ); if (win && win != root_window) X11DRV_init_desktop( win, width, height ); } - return TRUE; } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index b082ee6a219..089fd849cb9 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -224,7 +224,6 @@ extern BOOL X11DRV_GetCurrentDisplaySettings( LPCWSTR name, BOOL is_primary, LPD extern INT X11DRV_GetDisplayDepth( LPCWSTR name, BOOL is_primary ) DECLSPEC_HIDDEN; extern BOOL X11DRV_UpdateDisplayDevices( const struct gdi_device_manager *device_manager, BOOL force, void *param ) DECLSPEC_HIDDEN; -extern BOOL X11DRV_CreateDesktopWindow( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL X11DRV_CreateWindow( HWND hwnd ) DECLSPEC_HIDDEN; extern LRESULT X11DRV_DesktopWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) DECLSPEC_HIDDEN; extern void X11DRV_DestroyWindow( HWND hwnd ) DECLSPEC_HIDDEN; @@ -234,6 +233,7 @@ extern void X11DRV_GetDC( HDC hdc, HWND hwnd, HWND top, const RECT *win_rect, extern void X11DRV_ReleaseDC( HWND hwnd, HDC hdc ) DECLSPEC_HIDDEN; extern BOOL X11DRV_ScrollDC( HDC hdc, INT dx, INT dy, HRGN update ) DECLSPEC_HIDDEN; extern void X11DRV_SetCapture( HWND hwnd, UINT flags ) DECLSPEC_HIDDEN; +extern void X11DRV_SetDesktopWindow( HWND hwnd ) DECLSPEC_HIDDEN; extern void X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags ) DECLSPEC_HIDDEN; extern void X11DRV_SetParent( HWND hwnd, HWND parent, HWND old_parent ) DECLSPEC_HIDDEN; diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index e66585384e2..d5bbb5f9676 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -306,7 +306,6 @@ struct user_driver_funcs INT (*pGetDisplayDepth)(LPCWSTR,BOOL); BOOL (*pUpdateDisplayDevices)(const struct gdi_device_manager *,BOOL,void*); /* windowing functions */ - BOOL (*pCreateDesktopWindow)(HWND); BOOL (*pCreateWindow)(HWND); LRESULT (*pDesktopWindowProc)(HWND,UINT,WPARAM,LPARAM); void (*pDestroyWindow)(HWND); @@ -316,6 +315,7 @@ struct user_driver_funcs void (*pReleaseDC)(HWND,HDC); BOOL (*pScrollDC)(HDC,INT,INT,HRGN); void (*pSetCapture)(HWND,UINT); + void (*pSetDesktopWindow)(HWND); void (*pSetFocus)(HWND); void (*pSetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD); void (*pSetParent)(HWND,HWND,HWND); From beae7a40de21de2f9153728a7463922dcd9ef894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 May 2023 13:52:16 +0200 Subject: [PATCH 2071/2777] win32u: Call SetDesktopWindow when desktop window is successfully created. When the default desktop window is created, its parent is always NULL, and SetDesktopWindow is never called here. (cherry picked from commit 8b5bdb10d586d069e3ed5bc5138015f742a9183b) CW-Bug-Id: #21879 --- dlls/win32u/window.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index eb9a71fa86f..95569ba187a 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -4969,10 +4969,10 @@ static WND *create_window_handle( HWND parent, HWND owner, UNICODE_STRING *name, if (name->Buffer == (const WCHAR *)DESKTOP_CLASS_ATOM) { - if (!thread_info->top_window) - thread_info->top_window = HandleToUlong( full_parent ? full_parent : handle ); + if (!thread_info->top_window) thread_info->top_window = HandleToUlong( full_parent ? full_parent : handle ); else assert( full_parent == UlongToHandle( thread_info->top_window )); - if (full_parent) user_driver->pSetDesktopWindow( UlongToHandle( thread_info->top_window )); + if (!thread_info->top_window) ERR_(win)( "failed to create desktop window\n" ); + else user_driver->pSetDesktopWindow( UlongToHandle( thread_info->top_window )); register_builtin_classes(); } else /* HWND_MESSAGE parent */ From 4c1cae8d4770e8da136a8d44c157c3798cd1783f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 May 2023 16:18:17 +0200 Subject: [PATCH 2072/2777] explorer: Load graphics driver before calling CreateDesktopW. (cherry picked from commit f9c1b6af126a948750adb658248141a8f0178f46) CW-Bug-Id: #21879 --- programs/explorer/desktop.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c index 14b2cbc2aff..8ac4a5e03c6 100644 --- a/programs/explorer/desktop.c +++ b/programs/explorer/desktop.c @@ -1114,6 +1114,10 @@ void manage_desktop( WCHAR *arg ) if (name) enable_shell = get_default_enable_shell( name ); + UuidCreate( &guid ); + TRACE( "display guid %s\n", debugstr_guid(&guid) ); + graphics_driver = load_graphics_driver( driver, &guid ); + if (name && width && height) { if (!(desktop = CreateDesktopW( name, NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ))) @@ -1124,10 +1128,6 @@ void manage_desktop( WCHAR *arg ) SetThreadDesktop( desktop ); } - UuidCreate( &guid ); - TRACE( "display guid %s\n", debugstr_guid(&guid) ); - graphics_driver = load_graphics_driver( driver, &guid ); - /* create the desktop window */ hwnd = CreateWindowExW( 0, DESKTOP_CLASS_ATOM, NULL, WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 0, 0, 0, 0, 0, &guid ); From 58736bd24041645efdfda06f52083096863254e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 May 2023 17:33:03 +0200 Subject: [PATCH 2073/2777] explorer: Use root window if driver doesn't implement create_desktop. (cherry picked from commit dbb63987f0b6ed821d872fe44eed7eebd0e7fda2) CW-Bug-Id: #21879 --- programs/explorer/desktop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c index 8ac4a5e03c6..11f81b1d800 100644 --- a/programs/explorer/desktop.c +++ b/programs/explorer/desktop.c @@ -773,7 +773,7 @@ static LRESULT WINAPI desktop_wnd_proc( HWND hwnd, UINT message, WPARAM wp, LPAR /* create the desktop and the associated driver window, and make it the current desktop */ static BOOL create_desktop( HMODULE driver, const WCHAR *name, unsigned int width, unsigned int height ) { - BOOL ret = FALSE; + BOOL ret = TRUE; BOOL (CDECL *create_desktop_func)(unsigned int, unsigned int); if (driver) From b791410c37ee23302a260f36b03b8b2808aee26f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 May 2023 14:33:06 +0200 Subject: [PATCH 2074/2777] explorer: Don't call driver create_desktop if desktop name is "root". (cherry picked from commit 0edc848bee16ae2115f47e2a09435cc1b3834eb0) CW-Bug-Id: #21879 --- dlls/winex11.drv/desktop.c | 11 ----------- programs/explorer/desktop.c | 6 ++++-- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c index 351552674e3..5d9a5e7a2cc 100644 --- a/dlls/winex11.drv/desktop.c +++ b/dlls/winex11.drv/desktop.c @@ -359,21 +359,10 @@ void X11DRV_init_desktop( Window win, unsigned int width, unsigned int height ) */ NTSTATUS x11drv_create_desktop( void *arg ) { - static const WCHAR rootW[] = {'r','o','o','t',0}; const struct create_desktop_params *params = arg; XSetWindowAttributes win_attr; Window win; Display *display = thread_init_display(); - WCHAR name[MAX_PATH]; - - if (!NtUserGetObjectInformation( NtUserGetThreadDesktop( GetCurrentThreadId() ), - UOI_NAME, name, sizeof(name), NULL )) - name[0] = 0; - - TRACE( "%s %ux%u\n", debugstr_w(name), params->width, params->height ); - - /* magic: desktop "root" means use the root window */ - if (!wcsicmp( name, rootW )) return FALSE; /* Create window */ win_attr.event_mask = ExposureMask | FocusChangeMask | EnterWindowMask | diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c index 11f81b1d800..c5490c06d97 100644 --- a/programs/explorer/desktop.c +++ b/programs/explorer/desktop.c @@ -42,7 +42,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(explorer); static const WCHAR default_driver[] = {'m','a','c',',','x','1','1',0}; -static BOOL using_root; +static BOOL using_root = TRUE; struct launcher { @@ -1120,6 +1120,8 @@ void manage_desktop( WCHAR *arg ) if (name && width && height) { + /* magic: desktop "root" means use the root window */ + using_root = !wcsicmp( name, L"root" ); if (!(desktop = CreateDesktopW( name, NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ))) { WINE_ERR( "failed to create desktop %s error %ld\n", wine_dbgstr_w(name), GetLastError() ); @@ -1140,7 +1142,7 @@ void manage_desktop( WCHAR *arg ) desktop_orig_wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)desktop_wnd_proc ); - using_root = !desktop || !create_desktop( graphics_driver, name, width, height ); + if (!using_root) using_root = !create_desktop( graphics_driver, name, width, height ); SendMessageW( hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIconW( 0, MAKEINTRESOURCEW(OIC_WINLOGO))); if (name) set_desktop_window_title( hwnd, name ); SetWindowPos( hwnd, 0, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN), From 1733c8fb3046efcdd8b644965025cc386c4666b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 May 2023 12:43:38 +0200 Subject: [PATCH 2075/2777] explorer: Call user driver through a new CreateDesktop callback. (cherry picked from commit f7d45533d13e5d98e1b280b569123d80cfb23f2a) CW-Bug-Id: #21879 --- dlls/user32/winstation.c | 2 +- dlls/win32u/driver.c | 12 ++++++++++++ dlls/win32u/winstation.c | 12 +++++++++++- include/ntuser.h | 3 +++ include/wine/gdi_driver.h | 1 + programs/explorer/desktop.c | 6 ++++-- 6 files changed, 32 insertions(+), 4 deletions(-) diff --git a/dlls/user32/winstation.c b/dlls/user32/winstation.c index 23844482f2c..62593ca046f 100644 --- a/dlls/user32/winstation.c +++ b/dlls/user32/winstation.c @@ -256,7 +256,7 @@ HDESK WINAPI CreateDesktopW( LPCWSTR name, LPCWSTR device, LPDEVMODEW devmode, OBJECT_ATTRIBUTES attr; UNICODE_STRING str; - if (device || devmode) + if (device || (devmode && !(flags & DF_WINE_CREATE_DESKTOP))) { SetLastError( ERROR_INVALID_PARAMETER ); return 0; diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 2d5d987652c..7a2e4c3bcdd 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -783,6 +783,11 @@ static BOOL nulldrv_UpdateDisplayDevices( const struct gdi_device_manager *manag return FALSE; } +static BOOL nulldrv_CreateDesktop( const WCHAR *name, UINT width, UINT height ) +{ + return TRUE; +} + static BOOL nodrv_CreateWindow( HWND hwnd ) { static int warned; @@ -1149,6 +1154,11 @@ static BOOL loaderdrv_UpdateDisplayDevices( const struct gdi_device_manager *man return load_driver()->pUpdateDisplayDevices( manager, force, param ); } +static BOOL loaderdrv_CreateDesktop( const WCHAR *name, UINT width, UINT height ) +{ + return load_driver()->pCreateDesktop( name, width, height ); +} + static BOOL loaderdrv_CreateWindow( HWND hwnd ) { return load_driver()->pCreateWindow( hwnd ); @@ -1222,6 +1232,7 @@ static const struct user_driver_funcs lazy_load_driver = loaderdrv_GetDisplayDepth, loaderdrv_UpdateDisplayDevices, /* windowing functions */ + loaderdrv_CreateDesktop, loaderdrv_CreateWindow, nulldrv_DesktopWindowProc, nulldrv_DestroyWindow, @@ -1300,6 +1311,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version SET_USER_FUNC(GetCurrentDisplaySettings); SET_USER_FUNC(GetDisplayDepth); SET_USER_FUNC(UpdateDisplayDevices); + SET_USER_FUNC(CreateDesktop); SET_USER_FUNC(CreateWindow); SET_USER_FUNC(DesktopWindowProc); SET_USER_FUNC(DestroyWindow); diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 79dfa4671ac..8ab6122709e 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -141,9 +141,10 @@ HDESK WINAPI NtUserCreateDesktopEx( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *dev DEVMODEW *devmode, DWORD flags, ACCESS_MASK access, ULONG heap_size ) { + WCHAR buffer[MAX_PATH]; HANDLE ret; - if ((device && device->Length) || devmode) + if ((device && device->Length) || (devmode && !(flags & DF_WINE_CREATE_DESKTOP))) { RtlSetLastWin32Error( ERROR_INVALID_PARAMETER ); return 0; @@ -163,6 +164,15 @@ HDESK WINAPI NtUserCreateDesktopEx( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *dev ret = wine_server_ptr_handle( reply->handle ); } SERVER_END_REQ; + if (!devmode) return ret; + + lstrcpynW( buffer, attr->ObjectName->Buffer, attr->ObjectName->Length / sizeof(WCHAR) + 1 ); + if (!user_driver->pCreateDesktop( buffer, devmode->dmPelsWidth, devmode->dmPelsHeight )) + { + NtUserCloseDesktop( ret ); + return 0; + } + return ret; } diff --git a/include/ntuser.h b/include/ntuser.h index f9c63a48cee..1e2b47e627d 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -286,6 +286,9 @@ struct unpack_dde_message_params #define SPY_RESULT_OK 0x0001 #define SPY_RESULT_DEFWND 0x0002 +/* CreateDesktop wine specific flag */ +#define DF_WINE_CREATE_DESKTOP 0x80000000 + /* NtUserMessageCall codes */ enum { diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index d5bbb5f9676..f320805c752 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -306,6 +306,7 @@ struct user_driver_funcs INT (*pGetDisplayDepth)(LPCWSTR,BOOL); BOOL (*pUpdateDisplayDevices)(const struct gdi_device_manager *,BOOL,void*); /* windowing functions */ + BOOL (*pCreateDesktop)(const WCHAR *,UINT,UINT); BOOL (*pCreateWindow)(HWND); LRESULT (*pDesktopWindowProc)(HWND,UINT,WPARAM,LPARAM); void (*pDestroyWindow)(HWND); diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c index c5490c06d97..9e86aa9c076 100644 --- a/programs/explorer/desktop.c +++ b/programs/explorer/desktop.c @@ -1120,9 +1120,11 @@ void manage_desktop( WCHAR *arg ) if (name && width && height) { + DEVMODEW devmode = {.dmPelsWidth = width, .dmPelsHeight = height}; /* magic: desktop "root" means use the root window */ - using_root = !wcsicmp( name, L"root" ); - if (!(desktop = CreateDesktopW( name, NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ))) + if ((using_root = !wcsicmp( name, L"root" ))) desktop = CreateDesktopW( name, NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); + else desktop = CreateDesktopW( name, NULL, &devmode, DF_WINE_CREATE_DESKTOP, DESKTOP_ALL_ACCESS, NULL ); + if (!desktop) { WINE_ERR( "failed to create desktop %s error %ld\n", wine_dbgstr_w(name), GetLastError() ); ExitProcess( 1 ); From 82ed8cf94e677fabd901d10f14da9bb60b2a59e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 May 2023 14:12:25 +0200 Subject: [PATCH 2076/2777] wineandroid: Use the user driver interface to create host desktops. (cherry picked from commit e0d3683d8947cd9a3cb20acdf69091b183a90861) CW-Bug-Id: #21879 --- dlls/wineandroid.drv/android.h | 2 +- dlls/wineandroid.drv/dllmain.c | 9 --------- dlls/wineandroid.drv/init.c | 2 +- dlls/wineandroid.drv/unixlib.h | 1 - dlls/wineandroid.drv/window.c | 4 ++-- dlls/wineandroid.drv/wineandroid.drv.spec | 2 -- 6 files changed, 4 insertions(+), 16 deletions(-) diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h index 0d073a63bcc..d12cfa28f04 100644 --- a/dlls/wineandroid.drv/android.h +++ b/dlls/wineandroid.drv/android.h @@ -87,6 +87,7 @@ extern INT ANDROID_GetKeyNameText( LONG lparam, LPWSTR buffer, INT size ) DECLSP extern UINT ANDROID_MapVirtualKeyEx( UINT code, UINT maptype, HKL hkl ) DECLSPEC_HIDDEN; extern SHORT ANDROID_VkKeyScanEx( WCHAR ch, HKL hkl ) DECLSPEC_HIDDEN; extern void ANDROID_SetCursor( HCURSOR handle ) DECLSPEC_HIDDEN; +extern BOOL ANDROID_CreateDesktop( const WCHAR *name, UINT width, UINT height ) DECLSPEC_HIDDEN; extern BOOL ANDROID_CreateWindow( HWND hwnd ) DECLSPEC_HIDDEN; extern void ANDROID_DestroyWindow( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL ANDROID_ProcessEvents( DWORD mask ) DECLSPEC_HIDDEN; @@ -112,7 +113,6 @@ extern void ANDROID_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_fla /* unixlib interface */ -extern NTSTATUS android_create_desktop( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS android_dispatch_ioctl( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS android_java_init( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS android_java_uninit( void *arg ) DECLSPEC_HIDDEN; diff --git a/dlls/wineandroid.drv/dllmain.c b/dlls/wineandroid.drv/dllmain.c index 3f6dbd388eb..320e47e88d2 100644 --- a/dlls/wineandroid.drv/dllmain.c +++ b/dlls/wineandroid.drv/dllmain.c @@ -132,12 +132,3 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved ) return TRUE; } - - -/*********************************************************************** - * wine_create_desktop (wineandroid.@) - */ -BOOL CDECL wine_create_desktop( UINT width, UINT height ) -{ - return ANDROID_CALL( create_desktop, NULL ); -} diff --git a/dlls/wineandroid.drv/init.c b/dlls/wineandroid.drv/init.c index 074aa6c6257..50659171f08 100644 --- a/dlls/wineandroid.drv/init.c +++ b/dlls/wineandroid.drv/init.c @@ -349,6 +349,7 @@ static const struct user_driver_funcs android_drv_funcs = .pChangeDisplaySettings = ANDROID_ChangeDisplaySettings, .pGetCurrentDisplaySettings = ANDROID_GetCurrentDisplaySettings, .pUpdateDisplayDevices = ANDROID_UpdateDisplayDevices, + .pCreateDesktop = ANDROID_CreateDesktop, .pCreateWindow = ANDROID_CreateWindow, .pDesktopWindowProc = ANDROID_DesktopWindowProc, .pDestroyWindow = ANDROID_DestroyWindow, @@ -609,7 +610,6 @@ static HRESULT android_init( void *arg ) const unixlib_entry_t __wine_unix_call_funcs[] = { - android_create_desktop, android_dispatch_ioctl, android_init, android_java_init, diff --git a/dlls/wineandroid.drv/unixlib.h b/dlls/wineandroid.drv/unixlib.h index a180e6660c8..f1ba25720fd 100644 --- a/dlls/wineandroid.drv/unixlib.h +++ b/dlls/wineandroid.drv/unixlib.h @@ -21,7 +21,6 @@ enum android_funcs { - unix_create_desktop, unix_dispatch_ioctl, unix_init, unix_java_init, diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index eb96300da89..905f4672580 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -1670,9 +1670,9 @@ LRESULT ANDROID_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) /*********************************************************************** - * android_create_desktop + * ANDROID_CreateDesktop */ -NTSTATUS android_create_desktop( void *arg ) +BOOL ANDROID_CreateDesktop( const WCHAR *name, UINT width, UINT height ) { /* wait until we receive the surface changed event */ while (!screen_width) diff --git a/dlls/wineandroid.drv/wineandroid.drv.spec b/dlls/wineandroid.drv/wineandroid.drv.spec index 22b97356521..e69de29bb2d 100644 --- a/dlls/wineandroid.drv/wineandroid.drv.spec +++ b/dlls/wineandroid.drv/wineandroid.drv.spec @@ -1,2 +0,0 @@ -# Desktop -@ cdecl wine_create_desktop(long long) From 7cfdbeb5c8889d57252e24d8f3590b4db39f830f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 May 2023 14:12:25 +0200 Subject: [PATCH 2077/2777] winex11: Use the user driver interface to create host desktops. (cherry picked from commit 4fcbbf8c9a15c9f18259d5c57b61fa8974121964) CW-Bug-Id: #21879 --- dlls/winex11.drv/desktop.c | 22 +++++++--------------- dlls/winex11.drv/dllmain.c | 10 ---------- dlls/winex11.drv/init.c | 1 + dlls/winex11.drv/unixlib.h | 8 -------- dlls/winex11.drv/window.c | 29 +++++++++++++++++++++++++---- dlls/winex11.drv/winex11.drv.spec | 3 --- dlls/winex11.drv/x11drv.h | 3 +-- dlls/winex11.drv/x11drv_main.c | 2 -- 8 files changed, 34 insertions(+), 44 deletions(-) diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c index 5d9a5e7a2cc..66cbee171a5 100644 --- a/dlls/winex11.drv/desktop.c +++ b/dlls/winex11.drv/desktop.c @@ -348,22 +348,22 @@ void X11DRV_init_desktop( Window win, unsigned int width, unsigned int height ) desktop_handler.free_monitors = X11DRV_desktop_free_monitors; desktop_handler.register_event_handlers = NULL; TRACE("Display device functions are now handled by: Virtual Desktop\n"); - X11DRV_DisplayDevices_Init( TRUE ); } /*********************************************************************** - * x11drv_create_desktop + * X11DRV_CreateDesktop * * Create the X11 desktop window for the desktop mode. */ -NTSTATUS x11drv_create_desktop( void *arg ) +BOOL X11DRV_CreateDesktop( const WCHAR *name, UINT width, UINT height ) { - const struct create_desktop_params *params = arg; XSetWindowAttributes win_attr; Window win; Display *display = thread_init_display(); + TRACE( "%s %ux%u\n", debugstr_w(name), width, height ); + /* Create window */ win_attr.event_mask = ExposureMask | FocusChangeMask | EnterWindowMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask; @@ -377,21 +377,13 @@ NTSTATUS x11drv_create_desktop( void *arg ) win_attr.colormap = None; win = XCreateWindow( display, DefaultRootWindow(display), - 0, 0, params->width, params->height, 0, default_visual.depth, InputOutput, + 0, 0, width, height, 0, default_visual.depth, InputOutput, default_visual.visual, CWEventMask | CWCursor | CWColormap, &win_attr ); if (!win) return FALSE; X11DRV_XInput2_Enable( display, win, win_attr.event_mask ); - if (!create_desktop_win_data( win )) return FALSE; - - X11DRV_init_desktop( win, params->width, params->height ); - if (is_desktop_fullscreen()) - { - TRACE("setting desktop to fullscreen\n"); - XChangeProperty( display, win, x11drv_atom(_NET_WM_STATE), XA_ATOM, 32, - PropModeReplace, (unsigned char*)&x11drv_atom(_NET_WM_STATE_FULLSCREEN), - 1); - } XFlush( display ); + + X11DRV_init_desktop( win, width, height ); return TRUE; } diff --git a/dlls/winex11.drv/dllmain.c b/dlls/winex11.drv/dllmain.c index f1553152dcf..bed88671131 100644 --- a/dlls/winex11.drv/dllmain.c +++ b/dlls/winex11.drv/dllmain.c @@ -110,16 +110,6 @@ BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved ) return TRUE; } - -/*********************************************************************** - * wine_create_desktop (winex11.@) - */ -BOOL CDECL wine_create_desktop( UINT width, UINT height ) -{ - struct create_desktop_params params = { .width = width, .height = height }; - return X11DRV_CALL( create_desktop, ¶ms ); -} - /*********************************************************************** * AttachEventQueueToTablet (winex11.@) */ diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index 9b457b6ccd8..173822b455f 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -411,6 +411,7 @@ static const struct user_driver_funcs x11drv_funcs = .pGetCurrentDisplaySettings = X11DRV_GetCurrentDisplaySettings, .pGetDisplayDepth = X11DRV_GetDisplayDepth, .pUpdateDisplayDevices = X11DRV_UpdateDisplayDevices, + .pCreateDesktop = X11DRV_CreateDesktop, .pCreateWindow = X11DRV_CreateWindow, .pDesktopWindowProc = X11DRV_DesktopWindowProc, .pDestroyWindow = X11DRV_DestroyWindow, diff --git a/dlls/winex11.drv/unixlib.h b/dlls/winex11.drv/unixlib.h index 45377effdc7..7dc911d6846 100644 --- a/dlls/winex11.drv/unixlib.h +++ b/dlls/winex11.drv/unixlib.h @@ -21,7 +21,6 @@ enum x11drv_funcs { - unix_create_desktop, unix_init, unix_systray_clear, unix_systray_dock, @@ -37,13 +36,6 @@ enum x11drv_funcs #define X11DRV_CALL(func, params) WINE_UNIX_CALL( unix_ ## func, params ) -/* x11drv_create_desktop params */ -struct create_desktop_params -{ - UINT width; - UINT height; -}; - /* x11drv_init params */ struct init_params { diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index ef9521b2457..38a55c47a08 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2285,13 +2285,13 @@ BOOL X11DRV_DestroyNotify( HWND hwnd, XEvent *event ) /* initialize the desktop window id in the desktop manager process */ -BOOL create_desktop_win_data( Window win ) +static BOOL create_desktop_win_data( Window win, HWND hwnd ) { struct x11drv_thread_data *thread_data = x11drv_thread_data(); Display *display = thread_data->display; struct x11drv_win_data *data; - if (!(data = alloc_win_data( display, NtUserGetDesktopWindow() ))) return FALSE; + if (!(data = alloc_win_data( display, hwnd ))) return FALSE; data->whole_window = win; data->managed = TRUE; NtUserSetProp( data->hwnd, whole_window_prop, (HANDLE)win ); @@ -2323,7 +2323,10 @@ void X11DRV_SetDesktopWindow( HWND hwnd ) if (!width && !height) /* not initialized yet */ { - RECT rect = NtUserGetVirtualScreenRect(); + RECT rect; + + X11DRV_DisplayDevices_Init( TRUE ); + rect = NtUserGetVirtualScreenRect(); SERVER_START_REQ( set_window_pos ) { @@ -2338,11 +2341,29 @@ void X11DRV_SetDesktopWindow( HWND hwnd ) wine_server_call( req ); } SERVER_END_REQ; + + if (!is_virtual_desktop()) return; + if (!create_desktop_win_data( root_window, hwnd )) + { + ERR( "Failed to create virtual desktop window data\n" ); + root_window = DefaultRootWindow( gdi_display ); + } + else if (is_desktop_fullscreen()) + { + Display *display = x11drv_thread_data()->display; + TRACE("setting desktop to fullscreen\n"); + XChangeProperty( display, root_window, x11drv_atom(_NET_WM_STATE), XA_ATOM, 32, PropModeReplace, + (unsigned char*)&x11drv_atom(_NET_WM_STATE_FULLSCREEN), 1 ); + } } else { Window win = (Window)NtUserGetProp( hwnd, whole_window_prop ); - if (win && win != root_window) X11DRV_init_desktop( win, width, height ); + if (win && win != root_window) + { + X11DRV_init_desktop( win, width, height ); + X11DRV_DisplayDevices_Init( TRUE ); + } } } diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec index a7334eef3d9..6dedae550e8 100644 --- a/dlls/winex11.drv/winex11.drv.spec +++ b/dlls/winex11.drv/winex11.drv.spec @@ -4,8 +4,5 @@ @ cdecl LoadTabletInfo(long) X11DRV_LoadTabletInfo @ cdecl WTInfoW(long long ptr) X11DRV_WTInfoW -# Desktop -@ cdecl wine_create_desktop(long long) - # System tray @ cdecl wine_notify_icon(long ptr) diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 089fd849cb9..a2e1998be8d 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -224,6 +224,7 @@ extern BOOL X11DRV_GetCurrentDisplaySettings( LPCWSTR name, BOOL is_primary, LPD extern INT X11DRV_GetDisplayDepth( LPCWSTR name, BOOL is_primary ) DECLSPEC_HIDDEN; extern BOOL X11DRV_UpdateDisplayDevices( const struct gdi_device_manager *device_manager, BOOL force, void *param ) DECLSPEC_HIDDEN; +extern BOOL X11DRV_CreateDesktop( const WCHAR *name, UINT width, UINT height ) DECLSPEC_HIDDEN; extern BOOL X11DRV_CreateWindow( HWND hwnd ) DECLSPEC_HIDDEN; extern LRESULT X11DRV_DesktopWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) DECLSPEC_HIDDEN; extern void X11DRV_DestroyWindow( HWND hwnd ) DECLSPEC_HIDDEN; @@ -821,7 +822,6 @@ extern void init_registry_display_settings(void) DECLSPEC_HIDDEN; extern BOOL is_virtual_desktop(void) DECLSPEC_HIDDEN; extern BOOL is_desktop_fullscreen(void) DECLSPEC_HIDDEN; extern BOOL is_detached_mode(const DEVMODEW *) DECLSPEC_HIDDEN; -extern BOOL create_desktop_win_data( Window win ) DECLSPEC_HIDDEN; void X11DRV_Settings_Init(void) DECLSPEC_HIDDEN; void X11DRV_XF86VM_Init(void) DECLSPEC_HIDDEN; @@ -900,7 +900,6 @@ static inline BOOL is_window_rect_mapped( const RECT *rect ) /* unixlib interface */ -extern NTSTATUS x11drv_create_desktop( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_systray_clear( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_systray_dock( void *arg ) DECLSPEC_HIDDEN; extern NTSTATUS x11drv_systray_hide( void *arg ) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 923b0037217..5e700df456a 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -1485,7 +1485,6 @@ NTSTATUS x11drv_client_call( enum client_callback func, UINT arg ) const unixlib_entry_t __wine_unix_call_funcs[] = { - x11drv_create_desktop, x11drv_init, x11drv_systray_clear, x11drv_systray_dock, @@ -1574,7 +1573,6 @@ static NTSTATUS x11drv_wow64_tablet_info( void *arg ) const unixlib_entry_t __wine_unix_call_wow64_funcs[] = { - x11drv_create_desktop, x11drv_wow64_init, x11drv_wow64_systray_clear, x11drv_wow64_systray_dock, From 29e352706e40060adcf3fbeeb44b2f475bd3cff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 May 2023 14:12:25 +0200 Subject: [PATCH 2078/2777] explorer: Remove now unnecessary wine_create_desktop entry. (cherry picked from commit 4b5311c7e02aa7ab2409f8fdcd22233f116dc4bc) CW-Bug-Id: #21879 --- programs/explorer/desktop.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c index 9e86aa9c076..cb17eaeb18e 100644 --- a/programs/explorer/desktop.c +++ b/programs/explorer/desktop.c @@ -770,20 +770,6 @@ static LRESULT WINAPI desktop_wnd_proc( HWND hwnd, UINT message, WPARAM wp, LPAR return desktop_orig_wndproc( hwnd, message, wp, lp ); } -/* create the desktop and the associated driver window, and make it the current desktop */ -static BOOL create_desktop( HMODULE driver, const WCHAR *name, unsigned int width, unsigned int height ) -{ - BOOL ret = TRUE; - BOOL (CDECL *create_desktop_func)(unsigned int, unsigned int); - - if (driver) - { - create_desktop_func = (void *)GetProcAddress( driver, "wine_create_desktop" ); - if (create_desktop_func) ret = create_desktop_func( width, height ); - } - return ret; -} - /* parse the desktop size specification */ static BOOL parse_size( const WCHAR *size, unsigned int *width, unsigned int *height ) { @@ -1144,7 +1130,6 @@ void manage_desktop( WCHAR *arg ) desktop_orig_wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)desktop_wnd_proc ); - if (!using_root) using_root = !create_desktop( graphics_driver, name, width, height ); SendMessageW( hwnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIconW( 0, MAKEINTRESOURCEW(OIC_WINLOGO))); if (name) set_desktop_window_title( hwnd, name ); SetWindowPos( hwnd, 0, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN), From 470a69254a2c9e5aa45667f4b31fb909d944c247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 30 May 2023 11:01:17 +0200 Subject: [PATCH 2079/2777] imm32: Query the new input context in ImmAssociateContextEx / IACE_DEFAULT. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54991 (cherry picked from commit 7ed63c30e8dee3509c52e11230470be2dcfe6cf5) CW-Bug-Id: #21879 --- dlls/imm32/imm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index aa1881e0918..a17593d18a8 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -1038,6 +1038,7 @@ BOOL WINAPI ImmAssociateContextEx( HWND hwnd, HIMC new_himc, DWORD flags ) ret = NtUserAssociateInputContext( hwnd, new_himc, flags ); if (ret == AICR_FOCUS_CHANGED) { + if (flags == IACE_DEFAULT) new_himc = NtUserGetWindowInputContext( hwnd ); ImmSetActiveContext( hwnd, old_himc, FALSE ); ImmSetActiveContext( hwnd, new_himc, TRUE ); if (hwnd == GetFocus()) set_ime_ui_window_himc( new_himc ); From 2c422270e0b08fd52d25356e516b4dd2a3afae03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 16 Jun 2023 13:17:34 +0200 Subject: [PATCH 2080/2777] server: Use get_hardware_msg_bit consistently to classify messages. (cherry picked from commit 8f9610fdff41b26c5129ee7a46c05ecbbf73042f) CW-Bug-Id: #21879 --- server/queue.c | 69 +++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 38 deletions(-) diff --git a/server/queue.c b/server/queue.c index b1c2bc65218..ba292a430ac 100644 --- a/server/queue.c +++ b/server/queue.c @@ -643,12 +643,6 @@ static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits SHARED_WRITE_END( &queue->shared->seq ); } -/* check whether msg is a keyboard message */ -static inline int is_keyboard_msg( struct message *msg ) -{ - return (msg->msg >= WM_KEYFIRST && msg->msg <= WM_KEYLAST); -} - /* check if message is matched by the filter */ static inline int check_msg_filter( unsigned int msg, unsigned int first, unsigned int last ) { @@ -674,10 +668,10 @@ static inline int filter_contains_hw_range( unsigned int first, unsigned int las static inline int get_hardware_msg_bit( struct message *msg ) { if (msg->msg == WM_INPUT_DEVICE_CHANGE || msg->msg == WM_INPUT) return QS_RAWINPUT; - if (msg->msg == WM_MOUSEMOVE || msg->msg == WM_NCMOUSEMOVE || - msg->msg == WM_POINTERDOWN || msg->msg == WM_POINTERUP || - msg->msg == WM_POINTERUPDATE) return QS_MOUSEMOVE; - if (is_keyboard_msg( msg )) return QS_KEY; + if (msg->msg == WM_MOUSEMOVE || msg->msg == WM_NCMOUSEMOVE) return QS_MOUSEMOVE; + if (msg->msg >= WM_KEYFIRST && msg->msg <= WM_KEYLAST) return QS_KEY; + if (msg->msg == WM_POINTERDOWN || msg->msg == WM_POINTERUP || + msg->msg == WM_POINTERUPDATE) return QS_POINTER; return QS_MOUSEBUTTON; } @@ -1741,26 +1735,28 @@ static user_handle_t find_hardware_message_window( struct desktop *desktop, stru *thread = NULL; *msg_code = msg->msg; - if (msg->msg == WM_INPUT || msg->msg == WM_INPUT_DEVICE_CHANGE || - msg->msg == WM_POINTERDOWN || msg->msg == WM_POINTERUP || - msg->msg == WM_POINTERUPDATE) + switch (get_hardware_msg_bit( msg )) { + case QS_POINTER: + case QS_RAWINPUT: if (!(win = msg->win) && input) win = input->shared->focus; - } - else if (is_keyboard_msg( msg )) - { + break; + case QS_KEY: if (input && !(win = input->shared->focus)) { win = input->shared->active; if (*msg_code < WM_SYSKEYDOWN) *msg_code += WM_SYSKEYDOWN - WM_KEYDOWN; } - } - else if (!input || !(win = input->shared->capture)) /* mouse message */ - { - if (is_window_visible( msg->win ) && !is_window_transparent( msg->win )) win = msg->win; - else win = shallow_window_from_point( desktop, msg->x, msg->y ); - - *thread = window_thread_from_point( win, msg->x, msg->y ); + break; + case QS_MOUSEMOVE: + case QS_MOUSEBUTTON: + if (!input || !(win = input->shared->capture)) + { + if (is_window_visible( msg->win ) && !is_window_transparent( msg->win )) win = msg->win; + else win = shallow_window_from_point( desktop, msg->x, msg->y ); + *thread = window_thread_from_point( win, msg->x, msg->y ); + } + break; } if (!*thread) @@ -1804,28 +1800,26 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg last_input_time = get_tick_count(); if (msg->msg != WM_MOUSEMOVE) always_queue = 1; - if (is_keyboard_msg( msg )) + switch (get_hardware_msg_bit( msg )) { + case QS_KEY: if (queue_hotkey_message( desktop, msg )) return; if (desktop->shared->keystate[VK_MENU] & 0x80) msg->lparam |= KF_ALTDOWN << 16; if (msg->wparam == VK_SHIFT || msg->wparam == VK_LSHIFT || msg->wparam == VK_RSHIFT) msg->lparam &= ~(KF_EXTENDED << 16); - } - else if (msg->msg == WM_POINTERDOWN || msg->msg == WM_POINTERUP || msg->msg == WM_POINTERUPDATE) - { + break; + case QS_POINTER: if (IS_POINTER_PRIMARY_WPARAM( msg_data->rawinput.mouse.data )) { prepend_cursor_history( msg->x, msg->y, msg->time, msg_data->info ); if (update_desktop_cursor_pos( desktop, msg->x, msg->y )) always_queue = 1; } - } - else if (msg->msg != WM_INPUT && msg->msg != WM_INPUT_DEVICE_CHANGE) - { - if (msg->msg == WM_MOUSEMOVE) - { - prepend_cursor_history( msg->x, msg->y, msg->time, msg_data->info ); - if (update_desktop_cursor_pos( desktop, msg->x, msg->y )) always_queue = 1; - } + break; + case QS_MOUSEMOVE: + prepend_cursor_history( msg->x, msg->y, msg->time, msg_data->info ); + if (update_desktop_cursor_pos( desktop, msg->x, msg->y )) always_queue = 1; + /* fallthrough */ + case QS_MOUSEBUTTON: if (desktop->shared->keystate[VK_LBUTTON] & 0x80) msg->wparam |= MK_LBUTTON; if (desktop->shared->keystate[VK_MBUTTON] & 0x80) msg->wparam |= MK_MBUTTON; if (desktop->shared->keystate[VK_RBUTTON] & 0x80) msg->wparam |= MK_RBUTTON; @@ -1833,6 +1827,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg if (desktop->shared->keystate[VK_CONTROL] & 0x80) msg->wparam |= MK_CONTROL; if (desktop->shared->keystate[VK_XBUTTON1] & 0x80) msg->wparam |= MK_XBUTTON1; if (desktop->shared->keystate[VK_XBUTTON2] & 0x80) msg->wparam |= MK_XBUTTON2; + break; } msg->x = desktop->shared->cursor.x; msg->y = desktop->shared->cursor.y; @@ -2518,9 +2513,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user data->hw_id = msg->unique_id; set_reply_data( msg->data, msg->data_size ); - if ((msg->msg == WM_INPUT || msg->msg == WM_INPUT_DEVICE_CHANGE || - msg->msg == WM_POINTERDOWN || msg->msg == WM_POINTERUP || - msg->msg == WM_POINTERUPDATE) && (flags & PM_REMOVE)) + if ((get_hardware_msg_bit( msg ) & (QS_POINTER | QS_RAWINPUT)) && (flags & PM_REMOVE)) release_hardware_message( current->queue, data->hw_id ); return 1; } From 56d68719c06bab9123c5b640832913a364ea718f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 16 Jun 2023 13:27:01 +0200 Subject: [PATCH 2081/2777] fixup! server: Move the desktop keystate to shared memory. --- server/user.h | 1 - 1 file changed, 1 deletion(-) diff --git a/server/user.h b/server/user.h index c8dc6e922d8..1de900ae310 100644 --- a/server/user.h +++ b/server/user.h @@ -67,7 +67,6 @@ struct desktop struct list touches; /* list of active touches */ struct thread_input *foreground_input; /* thread input of foreground thread */ unsigned int users; /* processes and threads using this desktop */ - unsigned char keystate[256]; /* asynchronous key state */ user_handle_t cursor_win; /* window that contains the cursor */ struct object *shared_mapping; /* desktop shared memory mapping */ volatile struct desktop_shared_memory *shared; /* desktop shared memory ptr */ From ff0c9129733785256845e9f41dcf6e1fe1cfa97d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 22:55:34 +0200 Subject: [PATCH 2082/2777] win32u: Move some window functions to window.c. (cherry picked from commit c22c10d6e923ea3fb53412b3f218bf9eeeef4cb2) CW-Bug-Id: #21879 --- dlls/win32u/input.c | 112 ---------------------------------- dlls/win32u/win32u_private.h | 10 ++-- dlls/win32u/window.c | 113 +++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 117 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 24321d6d5a2..98642c3605c 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2513,118 +2513,6 @@ BOOL WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, UINT_P return FALSE; } -HWND get_shell_window(void) -{ - HWND hwnd = 0; - - SERVER_START_REQ(set_global_windows) - { - req->flags = 0; - if (!wine_server_call_err(req)) - hwnd = wine_server_ptr_handle( reply->old_shell_window ); - } - SERVER_END_REQ; - - return hwnd; -} - -/*********************************************************************** -* NtUserSetShellWindowEx (win32u.@) -*/ -BOOL WINAPI NtUserSetShellWindowEx( HWND shell, HWND list_view ) -{ - BOOL ret; - - /* shell = Progman[Program Manager] - * |-> SHELLDLL_DefView - * list_view = | |-> SysListView32 - * | | |-> tooltips_class32 - * | | - * | |-> SysHeader32 - * | - * |-> ProxyTarget - */ - - if (get_shell_window()) - return FALSE; - - if (get_window_long( shell, GWL_EXSTYLE ) & WS_EX_TOPMOST) - return FALSE; - - if (list_view != shell && (get_window_long( list_view, GWL_EXSTYLE ) & WS_EX_TOPMOST)) - return FALSE; - - if (list_view && list_view != shell) - NtUserSetWindowPos( list_view, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE ); - - NtUserSetWindowPos( shell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE ); - - SERVER_START_REQ(set_global_windows) - { - req->flags = SET_GLOBAL_SHELL_WINDOWS; - req->shell_window = wine_server_user_handle( shell ); - req->shell_listview = wine_server_user_handle( list_view ); - ret = !wine_server_call_err(req); - } - SERVER_END_REQ; - return ret; -} - -HWND get_progman_window(void) -{ - HWND ret = 0; - - SERVER_START_REQ(set_global_windows) - { - req->flags = 0; - if (!wine_server_call_err(req)) - ret = wine_server_ptr_handle( reply->old_progman_window ); - } - SERVER_END_REQ; - return ret; -} - -HWND set_progman_window( HWND hwnd ) -{ - SERVER_START_REQ(set_global_windows) - { - req->flags = SET_GLOBAL_PROGMAN_WINDOW; - req->progman_window = wine_server_user_handle( hwnd ); - if (wine_server_call_err( req )) hwnd = 0; - } - SERVER_END_REQ; - return hwnd; -} - -HWND get_taskman_window(void) -{ - HWND ret = 0; - - SERVER_START_REQ(set_global_windows) - { - req->flags = 0; - if (!wine_server_call_err(req)) - ret = wine_server_ptr_handle( reply->old_taskman_window ); - } - SERVER_END_REQ; - return ret; -} - -HWND set_taskman_window( HWND hwnd ) -{ - /* hwnd = MSTaskSwWClass - * |-> SysTabControl32 - */ - SERVER_START_REQ(set_global_windows) - { - req->flags = SET_GLOBAL_TASKMAN_WINDOW; - req->taskman_window = wine_server_user_handle( hwnd ); - if (wine_server_call_err( req )) hwnd = 0; - } - SERVER_END_REQ; - return hwnd; -} - /***************************************************************************** * NtUserGetTouchInputInfo (WIN32U.@) */ diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index a885128d3a7..29cc0c46476 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -271,17 +271,12 @@ extern HWND get_capture(void) DECLSPEC_HIDDEN; extern BOOL get_cursor_pos( POINT *pt ) DECLSPEC_HIDDEN; extern HWND get_focus(void) DECLSPEC_HIDDEN; extern DWORD get_input_state(void) DECLSPEC_HIDDEN; -extern HWND get_progman_window(void) DECLSPEC_HIDDEN; -extern HWND get_shell_window(void) DECLSPEC_HIDDEN; -extern HWND get_taskman_window(void) DECLSPEC_HIDDEN; extern BOOL register_touch_window( HWND hwnd, UINT flags ) DECLSPEC_HIDDEN; extern BOOL WINAPI release_capture(void) DECLSPEC_HIDDEN; extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) DECLSPEC_HIDDEN; extern BOOL set_caret_blink_time( unsigned int time ) DECLSPEC_HIDDEN; extern BOOL set_caret_pos( int x, int y ) DECLSPEC_HIDDEN; extern BOOL set_foreground_window( HWND hwnd, BOOL mouse ) DECLSPEC_HIDDEN; -extern HWND set_progman_window( HWND hwnd ) DECLSPEC_HIDDEN; -extern HWND set_taskman_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void toggle_caret( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL unregister_touch_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void update_mouse_tracking_info( HWND hwnd ) DECLSPEC_HIDDEN; @@ -411,6 +406,11 @@ extern ULONG set_window_style( HWND hwnd, ULONG set_bits, ULONG clear_bits ) DEC extern BOOL show_owned_popups( HWND owner, BOOL show ) DECLSPEC_HIDDEN; extern void update_window_state( HWND hwnd ) DECLSPEC_HIDDEN; extern HWND window_from_point( HWND hwnd, POINT pt, INT *hittest ) DECLSPEC_HIDDEN; +extern HWND get_shell_window(void) DECLSPEC_HIDDEN; +extern HWND get_progman_window(void) DECLSPEC_HIDDEN; +extern HWND set_progman_window( HWND hwnd ) DECLSPEC_HIDDEN; +extern HWND get_taskman_window(void) DECLSPEC_HIDDEN; +extern HWND set_taskman_window( HWND hwnd ) DECLSPEC_HIDDEN; /* to release pointers retrieved by win_get_ptr */ static inline void release_win_ptr( struct tagWND *ptr ) diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 95569ba187a..81a13c7ad65 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -5682,3 +5682,116 @@ DWORD WINAPI NtUserDragObject( HWND parent, HWND hwnd, UINT fmt, ULONG_PTR data, return 0; } + + +HWND get_shell_window(void) +{ + HWND hwnd = 0; + + SERVER_START_REQ(set_global_windows) + { + req->flags = 0; + if (!wine_server_call_err(req)) + hwnd = wine_server_ptr_handle( reply->old_shell_window ); + } + SERVER_END_REQ; + + return hwnd; +} + +/*********************************************************************** +* NtUserSetShellWindowEx (win32u.@) +*/ +BOOL WINAPI NtUserSetShellWindowEx( HWND shell, HWND list_view ) +{ + BOOL ret; + + /* shell = Progman[Program Manager] + * |-> SHELLDLL_DefView + * list_view = | |-> SysListView32 + * | | |-> tooltips_class32 + * | | + * | |-> SysHeader32 + * | + * |-> ProxyTarget + */ + + if (get_shell_window()) + return FALSE; + + if (get_window_long( shell, GWL_EXSTYLE ) & WS_EX_TOPMOST) + return FALSE; + + if (list_view != shell && (get_window_long( list_view, GWL_EXSTYLE ) & WS_EX_TOPMOST)) + return FALSE; + + if (list_view && list_view != shell) + NtUserSetWindowPos( list_view, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE ); + + NtUserSetWindowPos( shell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE ); + + SERVER_START_REQ(set_global_windows) + { + req->flags = SET_GLOBAL_SHELL_WINDOWS; + req->shell_window = wine_server_user_handle( shell ); + req->shell_listview = wine_server_user_handle( list_view ); + ret = !wine_server_call_err(req); + } + SERVER_END_REQ; + return ret; +} + +HWND get_progman_window(void) +{ + HWND ret = 0; + + SERVER_START_REQ(set_global_windows) + { + req->flags = 0; + if (!wine_server_call_err(req)) + ret = wine_server_ptr_handle( reply->old_progman_window ); + } + SERVER_END_REQ; + return ret; +} + +HWND set_progman_window( HWND hwnd ) +{ + SERVER_START_REQ(set_global_windows) + { + req->flags = SET_GLOBAL_PROGMAN_WINDOW; + req->progman_window = wine_server_user_handle( hwnd ); + if (wine_server_call_err( req )) hwnd = 0; + } + SERVER_END_REQ; + return hwnd; +} + +HWND get_taskman_window(void) +{ + HWND ret = 0; + + SERVER_START_REQ(set_global_windows) + { + req->flags = 0; + if (!wine_server_call_err(req)) + ret = wine_server_ptr_handle( reply->old_taskman_window ); + } + SERVER_END_REQ; + return ret; +} + +HWND set_taskman_window( HWND hwnd ) +{ + /* hwnd = MSTaskSwWClass + * |-> SysTabControl32 + */ + SERVER_START_REQ(set_global_windows) + { + req->flags = SET_GLOBAL_TASKMAN_WINDOW; + req->taskman_window = wine_server_user_handle( hwnd ); + if (wine_server_call_err( req )) hwnd = 0; + } + SERVER_END_REQ; + return hwnd; +} From 5c8a462913baee7e5d525cbd8d50b66224d26197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 26 May 2023 22:04:20 +0200 Subject: [PATCH 2083/2777] win32u: Move cursor clipping functions to input.c. (cherry picked from commit 1cea2be9e822d25b508f8b709d58602768b37d2d) CW-Bug-Id: #21879 --- dlls/win32u/cursoricon.c | 71 ------------------------------------ dlls/win32u/input.c | 71 ++++++++++++++++++++++++++++++++++++ dlls/win32u/win32u_private.h | 2 +- 3 files changed, 72 insertions(+), 72 deletions(-) diff --git a/dlls/win32u/cursoricon.c b/dlls/win32u/cursoricon.c index ec143b841fd..bfcb805901c 100644 --- a/dlls/win32u/cursoricon.c +++ b/dlls/win32u/cursoricon.c @@ -150,77 +150,6 @@ HCURSOR WINAPI NtUserGetCursor(void) return ret; } -/*********************************************************************** - * NtUserClipCursor (win32u.@) - */ -BOOL WINAPI NtUserClipCursor( const RECT *rect ) -{ - UINT dpi; - BOOL ret; - RECT new_rect; - - TRACE( "Clipping to %s\n", wine_dbgstr_rect(rect) ); - - if (rect) - { - if (rect->left > rect->right || rect->top > rect->bottom) return FALSE; - if ((dpi = get_thread_dpi())) - { - HMONITOR monitor = monitor_from_rect( rect, MONITOR_DEFAULTTOPRIMARY, dpi ); - new_rect = map_dpi_rect( *rect, dpi, get_monitor_dpi( monitor )); - rect = &new_rect; - } - } - - SERVER_START_REQ( set_cursor ) - { - if (rect) - { - req->flags = SET_CURSOR_CLIP; - req->clip.left = rect->left; - req->clip.top = rect->top; - req->clip.right = rect->right; - req->clip.bottom = rect->bottom; - } - else req->flags = SET_CURSOR_NOCLIP; - - if ((ret = !wine_server_call( req ))) - { - new_rect.left = reply->new_clip.left; - new_rect.top = reply->new_clip.top; - new_rect.right = reply->new_clip.right; - new_rect.bottom = reply->new_clip.bottom; - } - } - SERVER_END_REQ; - if (ret) user_driver->pClipCursor( &new_rect ); - return ret; -} - -BOOL get_clip_cursor( RECT *rect ) -{ - volatile struct desktop_shared_memory *shared = get_desktop_shared_memory(); - UINT dpi; - - if (!rect || !shared) return FALSE; - - SHARED_READ_BEGIN( &shared->seq ) - { - rect->left = shared->cursor.clip.left; - rect->top = shared->cursor.clip.top; - rect->right = shared->cursor.clip.right; - rect->bottom = shared->cursor.clip.bottom; - } - SHARED_READ_END( &shared->seq ); - - if ((dpi = get_thread_dpi())) - { - HMONITOR monitor = monitor_from_rect( rect, MONITOR_DEFAULTTOPRIMARY, 0 ); - *rect = map_dpi_rect( *rect, get_monitor_dpi( monitor ), dpi ); - } - return TRUE; -} - HICON alloc_cursoricon_handle( BOOL is_icon ) { struct cursoricon_object *obj; diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 98642c3605c..244df7a7cec 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2513,6 +2513,77 @@ BOOL WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, UINT_P return FALSE; } +BOOL get_clip_cursor( RECT *rect ) +{ + volatile struct desktop_shared_memory *shared = get_desktop_shared_memory(); + UINT dpi; + + if (!rect || !shared) return FALSE; + + SHARED_READ_BEGIN( &shared->seq ) + { + rect->left = shared->cursor.clip.left; + rect->top = shared->cursor.clip.top; + rect->right = shared->cursor.clip.right; + rect->bottom = shared->cursor.clip.bottom; + } + SHARED_READ_END( &shared->seq ); + + if ((dpi = get_thread_dpi())) + { + HMONITOR monitor = monitor_from_rect( rect, MONITOR_DEFAULTTOPRIMARY, 0 ); + *rect = map_dpi_rect( *rect, get_monitor_dpi( monitor ), dpi ); + } + return TRUE; +} + +/*********************************************************************** + * NtUserClipCursor (win32u.@) + */ +BOOL WINAPI NtUserClipCursor( const RECT *rect ) +{ + UINT dpi; + BOOL ret; + RECT new_rect; + + TRACE( "Clipping to %s\n", wine_dbgstr_rect(rect) ); + + if (rect) + { + if (rect->left > rect->right || rect->top > rect->bottom) return FALSE; + if ((dpi = get_thread_dpi())) + { + HMONITOR monitor = monitor_from_rect( rect, MONITOR_DEFAULTTOPRIMARY, dpi ); + new_rect = map_dpi_rect( *rect, dpi, get_monitor_dpi( monitor )); + rect = &new_rect; + } + } + + SERVER_START_REQ( set_cursor ) + { + if (rect) + { + req->flags = SET_CURSOR_CLIP; + req->clip.left = rect->left; + req->clip.top = rect->top; + req->clip.right = rect->right; + req->clip.bottom = rect->bottom; + } + else req->flags = SET_CURSOR_NOCLIP; + + if ((ret = !wine_server_call( req ))) + { + new_rect.left = reply->new_clip.left; + new_rect.top = reply->new_clip.top; + new_rect.right = reply->new_clip.right; + new_rect.bottom = reply->new_clip.bottom; + } + } + SERVER_END_REQ; + if (ret) user_driver->pClipCursor( &new_rect ); + return ret; +} + /***************************************************************************** * NtUserGetTouchInputInfo (WIN32U.@) */ diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 29cc0c46476..dc653258d66 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -216,7 +216,6 @@ extern void release_clipboard_owner( HWND hwnd ) DECLSPEC_HIDDEN; /* cursoricon.c */ extern HICON alloc_cursoricon_handle( BOOL is_icon ) DECLSPEC_HIDDEN; -extern BOOL get_clip_cursor( RECT *rect ) DECLSPEC_HIDDEN; extern ULONG_PTR get_icon_param( HICON handle ) DECLSPEC_HIDDEN; extern ULONG_PTR set_icon_param( HICON handle, ULONG_PTR param ) DECLSPEC_HIDDEN; @@ -280,6 +279,7 @@ extern BOOL set_foreground_window( HWND hwnd, BOOL mouse ) DECLSPEC_HIDDEN; extern void toggle_caret( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL unregister_touch_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void update_mouse_tracking_info( HWND hwnd ) DECLSPEC_HIDDEN; +extern BOOL get_clip_cursor( RECT *rect ) DECLSPEC_HIDDEN; /* menu.c */ extern HMENU create_menu( BOOL is_popup ) DECLSPEC_HIDDEN; From 39f088c58c19782c6b5a1e4a8bff33bcdb4700b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 26 May 2023 22:18:32 +0200 Subject: [PATCH 2084/2777] win32u: Add a separate function to process WM_WINE_CLIPCURSOR. (cherry picked from commit 3bce247bd2c6b678d23c271fb5a8c8867a1be3f2) CW-Bug-Id: #21879 --- dlls/win32u/input.c | 12 ++++++++++++ dlls/win32u/message.c | 8 +------- dlls/win32u/win32u_private.h | 1 + 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 244df7a7cec..e6a49ce7a1d 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2537,6 +2537,18 @@ BOOL get_clip_cursor( RECT *rect ) return TRUE; } +BOOL process_wine_clipcursor( BOOL empty ) +{ + RECT rect; + + TRACE( "empty %u\n", empty ); + + if (empty) return user_driver->pClipCursor( NULL ); + + get_clip_cursor( &rect ); + return user_driver->pClipCursor( &rect ); +} + /*********************************************************************** * NtUserClipCursor (win32u.@) */ diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 8c7548a396a..eb7a3aa37b1 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1287,13 +1287,7 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR return call_current_hook( h_extra->handle, HC_ACTION, wparam, h_extra->lparam ); } case WM_WINE_CLIPCURSOR: - if (wparam) - { - RECT rect; - get_clip_cursor( &rect ); - return user_driver->pClipCursor( &rect ); - } - return user_driver->pClipCursor( NULL ); + return process_wine_clipcursor( !wparam ); case WM_WINE_UPDATEWINDOWSTATE: update_window_state( hwnd ); return 0; diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index dc653258d66..286df9419a6 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -280,6 +280,7 @@ extern void toggle_caret( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL unregister_touch_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void update_mouse_tracking_info( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL get_clip_cursor( RECT *rect ) DECLSPEC_HIDDEN; +extern BOOL process_wine_clipcursor( BOOL empty ) DECLSPEC_HIDDEN; /* menu.c */ extern HMENU create_menu( BOOL is_popup ) DECLSPEC_HIDDEN; From bea39fb432bc968130a6ddd85ecf7f2b459f044f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 11:23:40 +0200 Subject: [PATCH 2085/2777] win32u: Use WM_WINE_CLIPCURSOR / TRUE for empty clipping rect. (cherry picked from commit 900ba826540f4b10ad834109e520b097e2dbf415) CW-Bug-Id: #21879 --- dlls/win32u/message.c | 2 +- server/queue.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index eb7a3aa37b1..dead1ab3951 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1287,7 +1287,7 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR return call_current_hook( h_extra->handle, HC_ACTION, wparam, h_extra->lparam ); } case WM_WINE_CLIPCURSOR: - return process_wine_clipcursor( !wparam ); + return process_wine_clipcursor( wparam ); case WM_WINE_UPDATEWINDOWSTATE: update_window_state( hwnd ); return 0; diff --git a/server/queue.c b/server/queue.c index ba292a430ac..79a57bad9db 100644 --- a/server/queue.c +++ b/server/queue.c @@ -559,7 +559,7 @@ static void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect SHARED_WRITE_BEGIN( &desktop->shared->seq ); desktop->shared->cursor.clip = new_rect; - if (send_clip_msg) post_desktop_message( desktop, WM_WINE_CLIPCURSOR, rect != NULL, 0 ); + if (send_clip_msg) post_desktop_message( desktop, WM_WINE_CLIPCURSOR, rect == NULL, 0 ); /* warp the mouse to be inside the clip rect */ x = max( min( desktop->shared->cursor.x, desktop->shared->cursor.clip.right - 1 ), desktop->shared->cursor.clip.left ); From 9b4c20eeba16dadb6f202cade2c66ec2b52924a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 11:56:30 +0200 Subject: [PATCH 2086/2777] user32: Remove now unused virtual screen helpers. (cherry picked from commit 46d276188e306104eb60c113f40372d8cc9c7976) CW-Bug-Id: #21879 --- dlls/user32/sysparams.c | 37 ------------------------------------- dlls/user32/user_private.h | 3 --- 2 files changed, 40 deletions(-) diff --git a/dlls/user32/sysparams.c b/dlls/user32/sysparams.c index c7bd702726a..5a9087881ce 100644 --- a/dlls/user32/sysparams.c +++ b/dlls/user32/sysparams.c @@ -160,43 +160,6 @@ static void SYSPARAMS_NonClientMetrics32ATo32W( const NONCLIENTMETRICSA* lpnm32A /* Helper functions to retrieve monitors info */ -static BOOL CALLBACK get_virtual_screen_proc( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp ) -{ - RECT *virtual_rect = (RECT *)lp; - - UnionRect( virtual_rect, virtual_rect, rect ); - return TRUE; -} - -RECT get_virtual_screen_rect(void) -{ - RECT rect = {0}; - - NtUserEnumDisplayMonitors( 0, NULL, get_virtual_screen_proc, (LPARAM)&rect ); - return rect; -} - -static BOOL CALLBACK get_primary_monitor_proc( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp ) -{ - RECT *primary_rect = (RECT *)lp; - - if (!rect->top && !rect->left && rect->right && rect->bottom) - { - *primary_rect = *rect; - return FALSE; - } - - return TRUE; -} - -RECT get_primary_monitor_rect(void) -{ - RECT rect = {0}; - - NtUserEnumDisplayMonitors( 0, NULL, get_primary_monitor_proc, (LPARAM)&rect ); - return rect; -} - HDC get_display_dc(void) { EnterCriticalSection( &display_dc_section ); diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 430ac826f7e..c3f877758c1 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -55,10 +55,7 @@ extern HANDLE render_synthesized_format( UINT format, UINT from ) DECLSPEC_HIDDE extern void CLIPBOARD_ReleaseOwner( HWND hwnd ) DECLSPEC_HIDDEN; extern HDC get_display_dc(void) DECLSPEC_HIDDEN; extern void release_display_dc( HDC hdc ) DECLSPEC_HIDDEN; -extern void wait_graphics_driver_ready(void) DECLSPEC_HIDDEN; extern void *get_hook_proc( void *proc, const WCHAR *module, HMODULE *free_module ) DECLSPEC_HIDDEN; -extern RECT get_virtual_screen_rect(void) DECLSPEC_HIDDEN; -extern RECT get_primary_monitor_rect(void) DECLSPEC_HIDDEN; extern DWORD get_input_codepage( void ) DECLSPEC_HIDDEN; extern BOOL map_wparam_AtoW( UINT message, WPARAM *wparam, enum wm_char_mapping mapping ) DECLSPEC_HIDDEN; extern HPEN SYSCOLOR_GetPen( INT index ) DECLSPEC_HIDDEN; From a03d45a1fcf9cd503780e462fae84bde986d8c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 30 May 2023 23:27:53 +0200 Subject: [PATCH 2087/2777] user32/tests: Zero-initialize keyboard state array. (cherry picked from commit 29ac54e3004e2a37b77983253a64e456d5507ffd) CW-Bug-Id: #21879 --- dlls/user32/tests/input.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 5cb02443e44..ae037313576 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -4350,7 +4350,7 @@ static DWORD WINAPI get_key_state_thread(void *arg) struct get_key_state_test_desc* test; HANDLE *semaphores = params->semaphores; DWORD result; - BYTE keystate[256]; + BYTE keystate[256] = {0}; BOOL has_queue; BOOL expect_x, expect_c; MSG msg; @@ -4412,7 +4412,7 @@ static void test_GetKeyState(void) struct get_key_state_thread_params params; HANDLE thread; DWORD result; - BYTE keystate[256]; + BYTE keystate[256] = {0}; BOOL expect_x, expect_c; HWND hwnd; MSG msg; @@ -4425,7 +4425,6 @@ static void test_GetKeyState(void) return; } - memset(keystate, 0, sizeof(keystate)); params.semaphores[0] = CreateSemaphoreA(NULL, 0, 1, NULL); ok(params.semaphores[0] != NULL, "CreateSemaphoreA failed %lu\n", GetLastError()); params.semaphores[1] = CreateSemaphoreA(NULL, 0, 1, NULL); From 75bdd3e0305a7077168ae1cab7def9961782f468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 11:45:15 +0200 Subject: [PATCH 2088/2777] user32/tests: Add a helper to run a test in a process. (cherry picked from commit 1bf316c0d9d9afe2c1af10a3a3b21735a6d88994) CW-Bug-Id: #21879 --- dlls/user32/tests/input.c | 86 +++++++++++++++------------------------ 1 file changed, 33 insertions(+), 53 deletions(-) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index ae037313576..72e8070da52 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -180,6 +180,24 @@ static void init_function_pointers(void) is_wow64 = FALSE; } +#define run_in_process( a, b ) run_in_process_( __FILE__, __LINE__, a, b ) +static void run_in_process_( const char *file, int line, char **argv, const char *args ) +{ + STARTUPINFOA startup = {.cb = sizeof(STARTUPINFOA)}; + PROCESS_INFORMATION info = {0}; + char cmdline[MAX_PATH * 2]; + DWORD ret; + + sprintf( cmdline, "%s %s %s", argv[0], argv[1], args ); + ret = CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ); + ok_(file, line)( ret, "CreateProcessA failed, error %lu\n", GetLastError() ); + if (!ret) return; + + wait_child_process( info.hProcess ); + CloseHandle( info.hThread ); + CloseHandle( info.hProcess ); +} + static int KbdMessage( KEV kev, WPARAM *pwParam, LPARAM *plParam ) { UINT message; @@ -1471,13 +1489,10 @@ static void test_mouse_ll_hook(void) SetCursorPos(pt_org.x, pt_org.y); } -static void test_GetMouseMovePointsEx(const char *argv0) +static void test_GetMouseMovePointsEx( char **argv ) { #define BUFLIM 64 #define MYERROR 0xdeadbeef - PROCESS_INFORMATION process_info; - STARTUPINFOA startup_info; - char path[MAX_PATH]; int i, count, retval; MOUSEMOVEPOINT in; MOUSEMOVEPOINT out[200]; @@ -1695,16 +1710,7 @@ static void test_GetMouseMovePointsEx(const char *argv0) retval = pGetMouseMovePointsEx( sizeof(MOUSEMOVEPOINT), &in, out, BUFLIM, GMMP_USE_HIGH_RESOLUTION_POINTS ); todo_wine ok( retval == 64, "expected to get 64 high resolution mouse move points but got %d\n", retval ); - sprintf(path, "%s input get_mouse_move_points_test", argv0); - memset(&startup_info, 0, sizeof(startup_info)); - startup_info.cb = sizeof(startup_info); - startup_info.dwFlags = STARTF_USESHOWWINDOW; - startup_info.wShowWindow = SW_SHOWNORMAL; - retval = CreateProcessA(NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup_info, &process_info ); - ok(retval, "CreateProcess \"%s\" failed err %lu.\n", path, GetLastError()); - winetest_wait_child_process(process_info.hProcess); - CloseHandle(process_info.hProcess); - CloseHandle(process_info.hThread); + run_in_process( argv, "test_GetMouseMovePointsEx_process" ); #undef BUFLIM #undef MYERROR } @@ -5021,11 +5027,13 @@ static void test_GetPointerInfo( BOOL mouse_in_pointer_enabled ) ok( ret, "UnregisterClassW failed: %lu\n", GetLastError() ); } -static void test_EnableMouseInPointer_process( const char *arg ) +static void test_EnableMouseInPointer( const char *arg ) { DWORD enable = strtoul( arg, 0, 10 ); BOOL ret; + winetest_push_context( "enable %lu", enable ); + ret = pEnableMouseInPointer( enable ); todo_wine ok( ret, "EnableMouseInPointer failed, error %lu\n", GetLastError() ); @@ -5047,23 +5055,8 @@ static void test_EnableMouseInPointer_process( const char *arg ) ok( ret == enable, "IsMouseInPointerEnabled returned %u, error %lu\n", ret, GetLastError() ); test_GetPointerInfo( enable ); -} - -static void test_EnableMouseInPointer( char **argv, BOOL enable ) -{ - STARTUPINFOA startup = {.cb = sizeof(STARTUPINFOA)}; - PROCESS_INFORMATION info = {0}; - char cmdline[MAX_PATH * 2]; - BOOL ret; - sprintf( cmdline, "%s %s EnableMouseInPointer %u", argv[0], argv[1], enable ); - ret = CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ); - ok( ret, "CreateProcessA failed, error %lu\n", GetLastError() ); - if (!ret) return; - - wait_child_process( info.hProcess ); - CloseHandle( info.hThread ); - CloseHandle( info.hProcess ); + winetest_pop_context(); } START_TEST(input) @@ -5076,25 +5069,12 @@ START_TEST(input) GetCursorPos( &pos ); argc = winetest_get_mainargs(&argv); - if (argc >= 3 && strcmp(argv[2], "rawinput_test") == 0) - { - rawinput_test_process(); - return; - } - - if (argc >= 3 && strcmp(argv[2], "get_mouse_move_points_test") == 0) - { - test_GetMouseMovePointsEx_process(); - return; - } - - if (argc >= 4 && strcmp( argv[2], "EnableMouseInPointer" ) == 0) - { - winetest_push_context( "enable %s", argv[3] ); - test_EnableMouseInPointer_process( argv[3] ); - winetest_pop_context(); - return; - } + if (argc >= 3 && !strcmp( argv[2], "rawinput_test" )) + return rawinput_test_process(); + if (argc >= 3 && !strcmp( argv[2], "test_GetMouseMovePointsEx_process" )) + return test_GetMouseMovePointsEx_process(); + if (argc >= 4 && !strcmp( argv[2], "test_EnableMouseInPointer" )) + return test_EnableMouseInPointer( argv[3] ); test_SendInput(); test_Input_blackbox(); @@ -5120,7 +5100,7 @@ START_TEST(input) test_DefRawInputProc(); if(pGetMouseMovePointsEx) - test_GetMouseMovePointsEx(argv[0]); + test_GetMouseMovePointsEx( argv ); else win_skip("GetMouseMovePointsEx is not available\n"); @@ -5147,7 +5127,7 @@ START_TEST(input) win_skip( "EnableMouseInPointer not found, skipping tests\n" ); else { - test_EnableMouseInPointer( argv, FALSE ); - test_EnableMouseInPointer( argv, TRUE ); + run_in_process( argv, "test_EnableMouseInPointer 0" ); + run_in_process( argv, "test_EnableMouseInPointer 1" ); } } From f6da04964e9f04cfedbc8e92fca9537454ebab9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 14:42:16 +0200 Subject: [PATCH 2089/2777] user32/tests: Test more ClipCursor reset scenarios. (cherry picked from commit 0a33018211ab50620923943876994266c06cfe3e) CW-Bug-Id: #21879 --- dlls/user32/tests/input.c | 294 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 72e8070da52..fea207cf435 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -180,6 +180,34 @@ static void init_function_pointers(void) is_wow64 = FALSE; } +static const char *debugstr_ok( const char *cond ) +{ + int c, n = 0; + /* skip possible casts */ + while ((c = *cond++)) + { + if (c == '(') n++; + if (!n) break; + if (c == ')') n--; + } + if (!strchr( cond - 1, '(' )) return wine_dbg_sprintf( "got %s", cond - 1 ); + return wine_dbg_sprintf( "%.*s returned", (int)strcspn( cond - 1, "( " ), cond - 1 ); +} + +#define ok_eq( e, r, t, f, ... ) \ + do \ + { \ + t v = (r); \ + ok( v == (e), "%s " f "\n", debugstr_ok( #r ), v, ##__VA_ARGS__ ); \ + } while (0) +#define ok_rect( e, r ) \ + do \ + { \ + RECT v = (r); \ + ok( EqualRect( &v, &(e) ), "%s %s\n", debugstr_ok(#r), wine_dbgstr_rect(&v) ); \ + } while (0) +#define ok_ret( e, r ) ok_eq( e, r, UINT_PTR, "%Iu, error %ld", GetLastError() ) + #define run_in_process( a, b ) run_in_process_( __FILE__, __LINE__, a, b ) static void run_in_process_( const char *file, int line, char **argv, const char *args ) { @@ -198,6 +226,72 @@ static void run_in_process_( const char *file, int line, char **argv, const char CloseHandle( info.hProcess ); } +#define run_in_desktop( a, b, c ) run_in_desktop_( __FILE__, __LINE__, a, b, c ) +static void run_in_desktop_( const char *file, int line, char **argv, + const char *args, BOOL input ) +{ + const char *desktop_name = "WineTest Desktop"; + STARTUPINFOA startup = {.cb = sizeof(STARTUPINFOA)}; + PROCESS_INFORMATION info = {0}; + HDESK old_desktop, desktop; + char cmdline[MAX_PATH * 2]; + DWORD ret; + + old_desktop = OpenInputDesktop( 0, FALSE, DESKTOP_ALL_ACCESS ); + ok_(file, line)( !!old_desktop, "OpenInputDesktop failed, error %lu\n", GetLastError() ); + desktop = CreateDesktopA( desktop_name, NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); + ok_(file, line)( !!desktop, "CreateDesktopA failed, error %lu\n", GetLastError() ); + if (input) + { + ret = SwitchDesktop( desktop ); + ok_(file, line)( ret, "SwitchDesktop failed, error %lu\n", GetLastError() ); + } + + startup.lpDesktop = (char *)desktop_name; + sprintf( cmdline, "%s %s %s", argv[0], argv[1], args ); + ret = CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ); + ok_(file, line)( ret, "CreateProcessA failed, error %lu\n", GetLastError() ); + if (!ret) return; + + wait_child_process( info.hProcess ); + CloseHandle( info.hThread ); + CloseHandle( info.hProcess ); + + if (input) + { + ret = SwitchDesktop( old_desktop ); + ok_(file, line)( ret, "SwitchDesktop failed, error %lu\n", GetLastError() ); + } + ret = CloseDesktop( desktop ); + ok_(file, line)( ret, "CloseDesktop failed, error %lu\n", GetLastError() ); + ret = CloseDesktop( old_desktop ); + ok_(file, line)( ret, "CloseDesktop failed, error %lu\n", GetLastError() ); +} + +#define msg_wait_for_events( a, b, c ) msg_wait_for_events_( __FILE__, __LINE__, a, b, c ) +static DWORD msg_wait_for_events_( const char *file, int line, DWORD count, HANDLE *events, DWORD timeout ) +{ + DWORD ret, end = GetTickCount() + min( timeout, 5000 ); + MSG msg; + + while ((ret = MsgWaitForMultipleObjects( count, events, FALSE, min( timeout, 5000 ), QS_ALLINPUT )) <= count) + { + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } + if (ret < count) return ret; + if (timeout >= 5000) continue; + if (end <= GetTickCount()) timeout = 0; + else timeout = end - GetTickCount(); + } + + if (timeout >= 5000) ok_(file, line)( 0, "MsgWaitForMultipleObjects returned %#lx\n", ret ); + else ok_(file, line)( ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %#lx\n", ret ); + return ret; +} + static int KbdMessage( KEV kev, WPARAM *pwParam, LPARAM *plParam ) { UINT message; @@ -5059,6 +5153,198 @@ static void test_EnableMouseInPointer( const char *arg ) winetest_pop_context(); } +static BOOL CALLBACK get_virtual_screen_proc( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp ) +{ + RECT *virtual_rect = (RECT *)lp; + UnionRect( virtual_rect, virtual_rect, rect ); + return TRUE; +} + +RECT get_virtual_screen_rect(void) +{ + RECT rect = {0}; + EnumDisplayMonitors( 0, NULL, get_virtual_screen_proc, (LPARAM)&rect ); + return rect; +} + +static void test_ClipCursor_dirty( const char *arg ) +{ + RECT rect, expect_rect = {1, 2, 3, 4}; + + /* check leaked clip rect from another desktop or process */ + ok_ret( 1, GetClipCursor( &rect ) ); + todo_wine_if( !strcmp( arg, "desktop" ) ) + ok_rect( expect_rect, rect ); + + /* intentionally leaking clipping rect */ +} + +static DWORD CALLBACK test_ClipCursor_thread( void *arg ) +{ + RECT rect, clip_rect, virtual_rect = get_virtual_screen_rect(); + HWND hwnd; + + clip_rect.left = clip_rect.right = (virtual_rect.left + virtual_rect.right) / 2; + clip_rect.top = clip_rect.bottom = (virtual_rect.top + virtual_rect.bottom) / 2; + + /* creating a window doesn't reset clipping rect */ + hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, + NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* setting a window foreground does, even from the same process */ + ok_ret( 1, SetForegroundWindow( hwnd ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( virtual_rect, rect ); + + /* destroying the window doesn't reset the clipping rect */ + InflateRect( &clip_rect, +1, +1 ); + ok_ret( 1, ClipCursor( &clip_rect ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* intentionally leaking clipping rect */ + return 0; +} + +static void test_ClipCursor_process(void) +{ + RECT rect, clip_rect, virtual_rect = get_virtual_screen_rect(); + HWND hwnd, tmp_hwnd; + HANDLE thread; + + clip_rect.left = clip_rect.right = (virtual_rect.left + virtual_rect.right) / 2; + clip_rect.top = clip_rect.bottom = (virtual_rect.top + virtual_rect.bottom) / 2; + + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* creating an invisible window doesn't reset clip cursor */ + hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, + NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + ok_ret( 1, DestroyWindow( hwnd ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* setting a window foreground, even invisible, resets it */ + hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, + NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + ok_ret( 1, SetForegroundWindow( hwnd ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( virtual_rect, rect ); + + ok_ret( 1, ClipCursor( &clip_rect ) ); + + /* creating and setting another window foreground doesn't reset it */ + tmp_hwnd = CreateWindowW( L"static", NULL, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, + NULL, NULL, NULL, NULL ); + ok( !!tmp_hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + ok_ret( 1, SetForegroundWindow( tmp_hwnd ) ); + ok_ret( 1, DestroyWindow( tmp_hwnd ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* but changing foreground to another thread in the same process reset it */ + thread = CreateThread( NULL, 0, test_ClipCursor_thread, NULL, 0, NULL ); + ok( !!thread, "CreateThread failed, error %lu\n", GetLastError() ); + msg_wait_for_events( 1, &thread, 5000 ); + + /* thread exit and foreground window destruction doesn't reset the clipping rect */ + InflateRect( &clip_rect, +1, +1 ); + ok_ret( 1, DestroyWindow( hwnd ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + todo_wine + ok_rect( clip_rect, rect ); + + /* intentionally leaking clipping rect */ +} + +static void test_ClipCursor_desktop( char **argv ) +{ + RECT rect, clip_rect, virtual_rect = get_virtual_screen_rect(); + + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( virtual_rect, rect ); + + /* ClipCursor clips rectangle to the virtual screen rect */ + clip_rect = virtual_rect; + InflateRect( &clip_rect, +1, +1 ); + ok_ret( 1, ClipCursor( &clip_rect ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( virtual_rect, rect ); + + clip_rect = virtual_rect; + InflateRect( &clip_rect, -1, -1 ); + ok_ret( 1, ClipCursor( &clip_rect ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* ClipCursor(NULL) resets to the virtual screen rect */ + ok_ret( 1, ClipCursor( NULL ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( virtual_rect, rect ); + + clip_rect.left = clip_rect.right = (virtual_rect.left + virtual_rect.right) / 2; + clip_rect.top = clip_rect.bottom = (virtual_rect.top + virtual_rect.bottom) / 2; + ok_ret( 1, ClipCursor( &clip_rect ) ); + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* ClipCursor rejects invalid rectangles */ + clip_rect.right -= 1; + clip_rect.bottom -= 1; + SetLastError( 0xdeadbeef ); + ok_ret( 0, ClipCursor( &clip_rect ) ); + todo_wine + ok_ret( ERROR_ACCESS_DENIED, GetLastError() ); + + /* which doesn't reset the previous clip rect */ + clip_rect.right += 1; + clip_rect.bottom += 1; + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* running a process causes it to leak until foreground actually changes */ + run_in_process( argv, "test_ClipCursor_process" ); + + /* as foreground window is now transient, cursor clipping isn't reset */ + InflateRect( &clip_rect, +1, +1 ); + ok_ret( 1, GetClipCursor( &rect ) ); + todo_wine + ok_rect( clip_rect, rect ); + + /* intentionally leaking clipping rect */ +} + +static void test_ClipCursor( char **argv ) +{ + RECT rect, clip_rect = {1, 2, 3, 4}, virtual_rect = get_virtual_screen_rect(); + + ok_ret( 1, ClipCursor( &clip_rect ) ); + + /* running a new process doesn't reset clipping rectangle */ + run_in_process( argv, "test_ClipCursor_dirty process" ); + + /* running in a separate desktop, without switching desktop as well */ + run_in_desktop( argv, "test_ClipCursor_dirty desktop", 0 ); + + ok_ret( 1, GetClipCursor( &rect ) ); + ok_rect( clip_rect, rect ); + + /* running in a desktop and switching input resets the clipping rect */ + run_in_desktop( argv, "test_ClipCursor_desktop", 1 ); + + ok_ret( 1, GetClipCursor( &rect ) ); + todo_wine + ok_rect( virtual_rect, rect ); + if (!EqualRect( &rect, &virtual_rect )) ok_ret( 1, ClipCursor( NULL ) ); +} + START_TEST(input) { char **argv; @@ -5075,6 +5361,12 @@ START_TEST(input) return test_GetMouseMovePointsEx_process(); if (argc >= 4 && !strcmp( argv[2], "test_EnableMouseInPointer" )) return test_EnableMouseInPointer( argv[3] ); + if (argc >= 4 && !strcmp( argv[2], "test_ClipCursor_dirty" )) + return test_ClipCursor_dirty( argv[3] ); + if (argc >= 3 && !strcmp( argv[2], "test_ClipCursor_process" )) + return test_ClipCursor_process(); + if (argc >= 3 && !strcmp( argv[2], "test_ClipCursor_desktop" )) + return test_ClipCursor_desktop( argv ); test_SendInput(); test_Input_blackbox(); @@ -5130,4 +5422,6 @@ START_TEST(input) run_in_process( argv, "test_EnableMouseInPointer 0" ); run_in_process( argv, "test_EnableMouseInPointer 1" ); } + + test_ClipCursor( argv ); } From ec6c171ff7a48f796403282fc298cbb8692792ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 26 May 2023 19:50:57 +0200 Subject: [PATCH 2090/2777] win32u: Reset cursor clipping rectangle on display mode change. (cherry picked from commit 18cb55583a50aabf60467316dd23b7c2763ea271) CW-Bug-Id: #21879 --- dlls/win32u/sysparams.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index a6c9fcd76cc..38562fe47f4 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2726,6 +2726,7 @@ static LONG apply_display_settings( const WCHAR *devname, const DEVMODEW *devmod if (!adapter_get_current_settings( adapter, ¤t_mode )) WARN( "Failed to get primary adapter current display settings.\n" ); adapter_release( adapter ); + NtUserClipCursor( NULL ); send_notify_message( NtUserGetDesktopWindow(), WM_DISPLAYCHANGE, current_mode.dmBitsPerPel, MAKELPARAM( current_mode.dmPelsWidth, current_mode.dmPelsHeight ), FALSE ); send_message_timeout( HWND_BROADCAST, WM_DISPLAYCHANGE, current_mode.dmBitsPerPel, From 29bb956ed545fc90095d48e8b43eb1e3ee80e3db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 26 May 2023 19:50:57 +0200 Subject: [PATCH 2091/2777] winex11: Rely on win32u to reset clipping on display mode change. (cherry picked from commit 5bdbbee6f4a874159f2e527f39f071547c513ee4) CW-Bug-Id: #21879 --- dlls/winex11.drv/desktop.c | 1 - dlls/winex11.drv/mouse.c | 2 +- dlls/winex11.drv/x11drv.h | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c index 66cbee171a5..f0c038d8981 100644 --- a/dlls/winex11.drv/desktop.c +++ b/dlls/winex11.drv/desktop.c @@ -448,7 +448,6 @@ void X11DRV_resize_desktop(void) NtUserSetWindowPos( hwnd, 0, virtual_rect.left, virtual_rect.top, virtual_rect.right - virtual_rect.left, virtual_rect.bottom - virtual_rect.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE ); - ungrab_clipping_window(); /* HACK: always send the desktop resize notification, to eventually update fshack on windows */ send_message_timeout( HWND_BROADCAST, WM_X11DRV_DESKTOP_RESIZED, old_virtual_rect.left, diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index faa3aacdd3f..81aa9294baa 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -527,7 +527,7 @@ static BOOL grab_clipping_window( const RECT *clip ) * * Release the pointer grab on the clip window. */ -void ungrab_clipping_window(void) +static void ungrab_clipping_window(void) { Display *display = thread_init_display(); Window clip_window = init_clip_window(); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index a2e1998be8d..faf236e253c 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -740,7 +740,6 @@ extern void set_window_cursor( Window window, HCURSOR handle ) DECLSPEC_HIDDEN; extern void sync_window_cursor( Window window ) DECLSPEC_HIDDEN; extern LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) DECLSPEC_HIDDEN; extern LRESULT clip_cursor_request( HWND hwnd, BOOL fullscreen, BOOL reset ) DECLSPEC_HIDDEN; -extern void ungrab_clipping_window(void) DECLSPEC_HIDDEN; extern void reset_clipping_window(void) DECLSPEC_HIDDEN; extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN; extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN; From 75cc6a47ebe6d8e9e28e5ccf5d5c5bbb79ea2c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 26 May 2023 19:53:23 +0200 Subject: [PATCH 2092/2777] winex11: Reset clipping by calling NtUserClipCursor directly. (cherry picked from commit b863d3ab141a5243c6024a75185f9869b2f4e667) CW-Bug-Id: #21879 --- dlls/winex11.drv/event.c | 4 ++-- dlls/winex11.drv/mouse.c | 11 ----------- dlls/winex11.drv/window.c | 2 +- dlls/winex11.drv/x11drv.h | 1 - 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 72eb2cfe443..9c518176e1e 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -946,7 +946,7 @@ static void focus_out( Display *display , HWND hwnd ) if (is_virtual_desktop()) { - if (hwnd == NtUserGetDesktopWindow()) reset_clipping_window(); + if (hwnd == NtUserGetDesktopWindow()) NtUserClipCursor( NULL ); return; } if (hwnd != NtUserGetForegroundWindow()) return; @@ -990,7 +990,7 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) if (event->detail == NotifyPointer) { - if (!hwnd && event->window == x11drv_thread_data()->clip_window) reset_clipping_window(); + if (!hwnd && event->window == x11drv_thread_data()->clip_window) NtUserClipCursor( NULL ); return TRUE; } if (!hwnd) return FALSE; diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 81aa9294baa..29ead8aa562 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -541,17 +541,6 @@ static void ungrab_clipping_window(void) send_notify_message( NtUserGetDesktopWindow(), WM_X11DRV_CLIP_CURSOR_NOTIFY, 0, 0 ); } -/*********************************************************************** - * reset_clipping_window - * - * Forcibly reset the window clipping on external events. - */ -void reset_clipping_window(void) -{ - ungrab_clipping_window(); - NtUserClipCursor( NULL ); /* make sure the clip rectangle is reset too */ -} - /*********************************************************************** * retry_grab_clipping_window * diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 38a55c47a08..8edf5829add 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -3264,7 +3264,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, { release_win_data( data ); unmap_window( hwnd ); - if (NtUserIsWindowRectFullScreen( &old_window_rect )) reset_clipping_window(); + if (NtUserIsWindowRectFullScreen( &old_window_rect )) NtUserClipCursor( NULL ); if (!(data = get_win_data( hwnd ))) return; } } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index faf236e253c..93dff142a69 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -740,7 +740,6 @@ extern void set_window_cursor( Window window, HCURSOR handle ) DECLSPEC_HIDDEN; extern void sync_window_cursor( Window window ) DECLSPEC_HIDDEN; extern LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) DECLSPEC_HIDDEN; extern LRESULT clip_cursor_request( HWND hwnd, BOOL fullscreen, BOOL reset ) DECLSPEC_HIDDEN; -extern void reset_clipping_window(void) DECLSPEC_HIDDEN; extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN; extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN; extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN; From f899a617c88dc67d574c287147810a443ec7dd55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 11:11:10 +0200 Subject: [PATCH 2093/2777] server: Don't reset cursor clipping on foreground thread exit. It will be reset on foreground input changes, when it happens. (cherry picked from commit 88cbc08b7fcb90c6048f5868c82e3c2165dcc1cd) CW-Bug-Id: #21879 --- dlls/user32/tests/input.c | 2 -- server/queue.c | 7 ++++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index fea207cf435..52418d9c864 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -5258,7 +5258,6 @@ static void test_ClipCursor_process(void) InflateRect( &clip_rect, +1, +1 ); ok_ret( 1, DestroyWindow( hwnd ) ); ok_ret( 1, GetClipCursor( &rect ) ); - todo_wine ok_rect( clip_rect, rect ); /* intentionally leaking clipping rect */ @@ -5315,7 +5314,6 @@ static void test_ClipCursor_desktop( char **argv ) /* as foreground window is now transient, cursor clipping isn't reset */ InflateRect( &clip_rect, +1, +1 ); ok_ret( 1, GetClipCursor( &rect ) ); - todo_wine ok_rect( clip_rect, rect ); /* intentionally leaking clipping rect */ diff --git a/server/queue.c b/server/queue.c index 79a57bad9db..5c9b4581cf1 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1294,12 +1294,13 @@ static void thread_input_dump( struct object *obj, int verbose ) static void thread_input_destroy( struct object *obj ) { struct thread_input *input = (struct thread_input *)obj; + struct desktop *desktop; empty_msg_list( &input->msg_list ); - if (input->desktop) + if ((desktop = input->desktop)) { - if (input->desktop->foreground_input == input) set_foreground_input( input->desktop, NULL ); - release_object( input->desktop ); + if (desktop->foreground_input == input) desktop->foreground_input = NULL; + release_object( desktop ); } release_object( input->shared_mapping ); } From 0e881d71544fb4923bcfd95027d9734aced06f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 29 May 2023 15:11:32 +0200 Subject: [PATCH 2094/2777] win32u: Add a reset parameter to WM_WINE_CLIPCURSOR and driver ClipCursor. (cherry picked from commit b7570b798eab0a6995d6c163ab04ef336311e52d) --- dlls/win32u/driver.c | 6 +++--- dlls/win32u/input.c | 10 +++++----- dlls/win32u/message.c | 2 +- dlls/win32u/win32u_private.h | 2 +- dlls/winemac.drv/macdrv.h | 3 +-- dlls/winemac.drv/mouse.c | 6 ++++-- dlls/winex11.drv/mouse.c | 13 +++++++------ dlls/winex11.drv/x11drv.h | 2 +- include/wine/gdi_driver.h | 2 +- 9 files changed, 24 insertions(+), 22 deletions(-) diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 7a2e4c3bcdd..3a96b45d03f 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -753,7 +753,7 @@ static BOOL nulldrv_SetCursorPos( INT x, INT y ) return TRUE; } -static BOOL nulldrv_ClipCursor( LPCRECT clip ) +static BOOL nulldrv_ClipCursor( const RECT *clip, BOOL reset ) { return TRUE; } @@ -1134,9 +1134,9 @@ static BOOL loaderdrv_SetCursorPos( INT x, INT y ) return load_driver()->pSetCursorPos( x, y ); } -static BOOL loaderdrv_ClipCursor( const RECT *clip ) +static BOOL loaderdrv_ClipCursor( const RECT *clip, BOOL reset ) { - return load_driver()->pClipCursor( clip ); + return load_driver()->pClipCursor( clip, reset ); } static LRESULT nulldrv_ClipboardWindowProc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index e6a49ce7a1d..f56adb576d8 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2537,16 +2537,16 @@ BOOL get_clip_cursor( RECT *rect ) return TRUE; } -BOOL process_wine_clipcursor( BOOL empty ) +BOOL process_wine_clipcursor( BOOL empty, BOOL reset ) { RECT rect; - TRACE( "empty %u\n", empty ); + TRACE( "empty %u, reset %u\n", empty, reset ); - if (empty) return user_driver->pClipCursor( NULL ); + if (empty || reset) return user_driver->pClipCursor( NULL, reset ); get_clip_cursor( &rect ); - return user_driver->pClipCursor( &rect ); + return user_driver->pClipCursor( &rect, FALSE ); } /*********************************************************************** @@ -2592,7 +2592,7 @@ BOOL WINAPI NtUserClipCursor( const RECT *rect ) } } SERVER_END_REQ; - if (ret) user_driver->pClipCursor( &new_rect ); + if (ret) user_driver->pClipCursor( &new_rect, FALSE ); return ret; } diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index dead1ab3951..5b3cc86870e 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1287,7 +1287,7 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR return call_current_hook( h_extra->handle, HC_ACTION, wparam, h_extra->lparam ); } case WM_WINE_CLIPCURSOR: - return process_wine_clipcursor( wparam ); + return process_wine_clipcursor( wparam, lparam ); case WM_WINE_UPDATEWINDOWSTATE: update_window_state( hwnd ); return 0; diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 286df9419a6..8cfa108e5b9 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -280,7 +280,7 @@ extern void toggle_caret( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL unregister_touch_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void update_mouse_tracking_info( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL get_clip_cursor( RECT *rect ) DECLSPEC_HIDDEN; -extern BOOL process_wine_clipcursor( BOOL empty ) DECLSPEC_HIDDEN; +extern BOOL process_wine_clipcursor( BOOL empty, BOOL reset ) DECLSPEC_HIDDEN; /* menu.c */ extern HMENU create_menu( BOOL is_popup ) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index d0fddcc0f21..39cb31bfdca 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -133,7 +133,7 @@ extern BOOL macdrv_UpdateDisplayDevices( const struct gdi_device_manager *device BOOL force, void *param ) DECLSPEC_HIDDEN; extern BOOL macdrv_GetDeviceGammaRamp(PHYSDEV dev, LPVOID ramp) DECLSPEC_HIDDEN; extern BOOL macdrv_SetDeviceGammaRamp(PHYSDEV dev, LPVOID ramp) DECLSPEC_HIDDEN; -extern BOOL macdrv_ClipCursor(LPCRECT clip) DECLSPEC_HIDDEN; +extern BOOL macdrv_ClipCursor(const RECT *clip, BOOL reset) DECLSPEC_HIDDEN; extern LRESULT macdrv_DesktopWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) DECLSPEC_HIDDEN; extern void macdrv_DestroyWindow(HWND hwnd) DECLSPEC_HIDDEN; extern void macdrv_SetDesktopWindow(HWND hwnd) DECLSPEC_HIDDEN; @@ -157,7 +157,6 @@ extern void macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags const RECT *visible_rect, const RECT *valid_rects, struct window_surface *surface) DECLSPEC_HIDDEN; extern void macdrv_DestroyCursorIcon(HCURSOR cursor) DECLSPEC_HIDDEN; -extern BOOL macdrv_ClipCursor(LPCRECT clip) DECLSPEC_HIDDEN; extern BOOL macdrv_GetCursorPos(LPPOINT pos) DECLSPEC_HIDDEN; extern void macdrv_SetCapture(HWND hwnd, UINT flags) DECLSPEC_HIDDEN; extern void macdrv_SetCursor(HCURSOR cursor) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/mouse.c b/dlls/winemac.drv/mouse.c index 74c329488c4..9dfd1801fc9 100644 --- a/dlls/winemac.drv/mouse.c +++ b/dlls/winemac.drv/mouse.c @@ -660,11 +660,13 @@ void macdrv_DestroyCursorIcon(HCURSOR cursor) * * Set the cursor clipping rectangle. */ -BOOL macdrv_ClipCursor(LPCRECT clip) +BOOL macdrv_ClipCursor(const RECT *clip, BOOL reset) { CGRect rect; - TRACE("%s\n", wine_dbgstr_rect(clip)); + TRACE("%s %u\n", wine_dbgstr_rect(clip), reset); + + if (reset) return TRUE; if (clip) { diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 29ead8aa562..b6986a9d68c 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1643,17 +1643,18 @@ BOOL X11DRV_GetCursorPos(LPPOINT pos) /*********************************************************************** * ClipCursor (X11DRV.@) */ -BOOL X11DRV_ClipCursor( LPCRECT clip ) +BOOL X11DRV_ClipCursor( const RECT *clip, BOOL reset ) { - RECT virtual_rect = NtUserGetVirtualScreenRect(); + TRACE( "clip %p, reset %u\n", clip, reset ); - if (!clip) clip = &virtual_rect; - - if (grab_pointer) + if (!reset && grab_pointer) { + RECT virtual_rect = NtUserGetVirtualScreenRect(); HWND foreground = NtUserGetForegroundWindow(); DWORD tid, pid; + if (!clip) clip = &virtual_rect; + /* forward request to the foreground window if it's in a different thread */ tid = NtUserGetWindowThread( foreground, &pid ); if (tid && tid != GetCurrentThreadId() && pid == GetCurrentProcessId()) @@ -1701,7 +1702,7 @@ LRESULT clip_cursor_request( HWND hwnd, BOOL fullscreen, BOOL reset ) else { NtUserGetClipCursor( &clip ); - X11DRV_ClipCursor( &clip ); + X11DRV_ClipCursor( &clip, FALSE ); } return 0; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 93dff142a69..4416f6403a1 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -218,7 +218,7 @@ extern void X11DRV_DestroyCursorIcon( HCURSOR handle ) DECLSPEC_HIDDEN; extern void X11DRV_SetCursor( HCURSOR handle ) DECLSPEC_HIDDEN; extern BOOL X11DRV_SetCursorPos( INT x, INT y ) DECLSPEC_HIDDEN; extern BOOL X11DRV_GetCursorPos( LPPOINT pos ) DECLSPEC_HIDDEN; -extern BOOL X11DRV_ClipCursor( LPCRECT clip ) DECLSPEC_HIDDEN; +extern BOOL X11DRV_ClipCursor( const RECT *clip, BOOL reset ) DECLSPEC_HIDDEN; extern LONG X11DRV_ChangeDisplaySettings( LPDEVMODEW displays, LPCWSTR primary_name, HWND hwnd, DWORD flags, LPVOID lpvoid ) DECLSPEC_HIDDEN; extern BOOL X11DRV_GetCurrentDisplaySettings( LPCWSTR name, BOOL is_primary, LPDEVMODEW devmode ) DECLSPEC_HIDDEN; extern INT X11DRV_GetDisplayDepth( LPCWSTR name, BOOL is_primary ) DECLSPEC_HIDDEN; diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index f320805c752..dd7d3eed2ad 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -296,7 +296,7 @@ struct user_driver_funcs void (*pSetCursor)(HCURSOR); BOOL (*pGetCursorPos)(LPPOINT); BOOL (*pSetCursorPos)(INT,INT); - BOOL (*pClipCursor)(LPCRECT); + BOOL (*pClipCursor)(const RECT*,BOOL); /* clipboard functions */ LRESULT (*pClipboardWindowProc)(HWND,UINT,WPARAM,LPARAM); void (*pUpdateClipboard)(void); From 8284c4dd8b9d6b319a7ba397d2d5e62b4bfb1de7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 16 Jun 2023 10:50:41 +0200 Subject: [PATCH 2095/2777] server: Use the helper to reset the clip rect when the desktop size changes. (cherry picked from commit 2101d4d6ad64369e34f4e2d24de62447f677ea30) --- server/queue.c | 2 +- server/user.h | 1 + server/window.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/server/queue.c b/server/queue.c index 5c9b4581cf1..079310f0c16 100644 --- a/server/queue.c +++ b/server/queue.c @@ -539,7 +539,7 @@ static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsig } /* set the cursor clip rectangle */ -static void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int send_clip_msg ) +void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int send_clip_msg ) { rectangle_t top_rect, new_rect; int x, y; diff --git a/server/user.h b/server/user.h index 1de900ae310..523a533ca4f 100644 --- a/server/user.h +++ b/server/user.h @@ -104,6 +104,7 @@ extern void queue_cleanup_window( struct thread *thread, user_handle_t win ); extern int init_thread_queue( struct thread *thread ); extern int attach_thread_input( struct thread *thread_from, struct thread *thread_to ); extern void detach_thread_input( struct thread *thread_from ); +extern void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int send_clip_msg ); extern void post_message( user_handle_t win, unsigned int message, lparam_t wparam, lparam_t lparam ); extern void send_notify_message( user_handle_t win, unsigned int message, diff --git a/server/window.c b/server/window.c index 83aab43a583..260b44c07a8 100644 --- a/server/window.c +++ b/server/window.c @@ -1831,7 +1831,7 @@ static void set_window_pos( struct window *win, struct window *previous, } /* reset cursor clip rectangle when the desktop changes size */ - if (win == win->desktop->top_window) win->desktop->shared->cursor.clip = *window_rect; + if (win == win->desktop->top_window) set_clip_rectangle( win->desktop, NULL, 1 ); /* if the window is not visible, everything is easy */ if (!visible) return; From a6376ddf0f444db2dcaf32590c4ecdd1d807080f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 6 Jun 2023 09:53:55 +0200 Subject: [PATCH 2096/2777] server: Use a separate helper to merge WM_MOUSEMOVE messages. (cherry picked from commit bd06c87b5b9d495824769876cdcc64c5ebc2bd9b) --- server/queue.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/server/queue.c b/server/queue.c index 079310f0c16..477b85a54cf 100644 --- a/server/queue.c +++ b/server/queue.c @@ -721,14 +721,12 @@ static int merge_pointer_update_message( struct thread_input *input, const struc return 1; } -/* try to merge a message with the last in the list; return 1 if successful */ -static int merge_message( struct thread_input *input, const struct message *msg ) +/* try to merge a WM_MOUSEMOVE message with the last in the list; return 1 if successful */ +static int merge_mousemove( struct thread_input *input, const struct message *msg ) { struct message *prev; struct list *ptr; - if (msg->msg == WM_POINTERUPDATE) return merge_pointer_update_message( input, msg ); - if (msg->msg != WM_MOUSEMOVE) return 0; for (ptr = list_tail( &input->msg_list ); ptr; ptr = list_prev( &input->msg_list, ptr )) { prev = LIST_ENTRY( ptr, struct message, entry ); @@ -756,6 +754,14 @@ static int merge_message( struct thread_input *input, const struct message *msg return 1; } +/* try to merge a message with the messages in the list; return 1 if successful */ +static int merge_message( struct thread_input *input, const struct message *msg ) +{ + if (msg->msg == WM_POINTERUPDATE) return merge_pointer_update_message( input, msg ); + if (msg->msg == WM_MOUSEMOVE) return merge_mousemove( input, msg ); + return 0; +} + /* free a result structure */ static void free_result( struct message_result *result ) { From f7ce546515dd07a55fb670e68b9d9fbcc9f60295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 2 Jun 2023 12:11:21 +0200 Subject: [PATCH 2097/2777] server: Queue a hardware WM_WINE_CLIPCURSOR message to the foreground thread. When applying a new cursor clipping rect, or to the previous foreground thread when foreground changes, to notify it of the cursor clipping rect being reset. (cherry picked from commit 5ebb1ed132d5261f410d7ff4f99c803f50752ed9) --- server/queue.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++--- server/user.h | 2 +- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/server/queue.c b/server/queue.c index 477b85a54cf..a820ce6d285 100644 --- a/server/queue.c +++ b/server/queue.c @@ -538,8 +538,25 @@ static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsig *time = get_tick_count(); } +static void queue_clip_cursor_msg( struct desktop *desktop, lparam_t wparam, lparam_t lparam ) +{ + static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM }; + struct thread_input *input; + struct message *msg; + + if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return; + + msg->msg = WM_WINE_CLIPCURSOR; + msg->wparam = wparam; + msg->lparam = lparam; + msg->x = desktop->shared->cursor.x; + msg->y = desktop->shared->cursor.y; + if ((input = desktop->foreground_input)) msg->win = input->shared->active; + queue_hardware_message( desktop, msg, 1 ); +} + /* set the cursor clip rectangle */ -void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int send_clip_msg ) +void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int reset ) { rectangle_t top_rect, new_rect; int x, y; @@ -559,13 +576,17 @@ void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int s SHARED_WRITE_BEGIN( &desktop->shared->seq ); desktop->shared->cursor.clip = new_rect; - if (send_clip_msg) post_desktop_message( desktop, WM_WINE_CLIPCURSOR, rect == NULL, 0 ); - /* warp the mouse to be inside the clip rect */ x = max( min( desktop->shared->cursor.x, desktop->shared->cursor.clip.right - 1 ), desktop->shared->cursor.clip.left ); y = max( min( desktop->shared->cursor.y, desktop->shared->cursor.clip.bottom - 1 ), desktop->shared->cursor.clip.top ); if (x != desktop->shared->cursor.x || y != desktop->shared->cursor.y) set_cursor_pos( desktop, x, y ); SHARED_WRITE_END( &desktop->shared->seq ); + + /* request clip cursor rectangle reset to the desktop thread */ + if (reset) post_desktop_message( desktop, WM_WINE_CLIPCURSOR, TRUE, FALSE ); + + /* notify foreground thread, of reset, or to apply new cursor clipping rect */ + queue_clip_cursor_msg( desktop, rect == NULL, reset ); } /* change the foreground input and reset the cursor clip rect */ @@ -672,6 +693,7 @@ static inline int get_hardware_msg_bit( struct message *msg ) if (msg->msg >= WM_KEYFIRST && msg->msg <= WM_KEYLAST) return QS_KEY; if (msg->msg == WM_POINTERDOWN || msg->msg == WM_POINTERUP || msg->msg == WM_POINTERUPDATE) return QS_POINTER; + if (msg->msg == WM_WINE_CLIPCURSOR) return QS_RAWINPUT; return QS_MOUSEBUTTON; } @@ -754,11 +776,37 @@ static int merge_mousemove( struct thread_input *input, const struct message *ms return 1; } +/* try to merge a WM_WINE_CLIPCURSOR message with the last in the list; return 1 if successful */ +static int merge_wine_clipcursor( struct thread_input *input, const struct message *msg ) +{ + struct message *prev; + + LIST_FOR_EACH_ENTRY_REV( prev, &input->msg_list, struct message, entry ) + if (prev->msg == WM_WINE_CLIPCURSOR) break; + if (&prev->entry == &input->msg_list) return 0; + + if (prev->result) return 0; + if (prev->win != msg->win) return 0; + if (prev->type != msg->type) return 0; + + /* now we can merge it */ + prev->wparam = msg->wparam; + prev->lparam = msg->lparam; + prev->x = msg->x; + prev->y = msg->y; + prev->time = msg->time; + list_remove( &prev->entry ); + list_add_tail( &input->msg_list, &prev->entry ); + + return 1; +} + /* try to merge a message with the messages in the list; return 1 if successful */ static int merge_message( struct thread_input *input, const struct message *msg ) { if (msg->msg == WM_POINTERUPDATE) return merge_pointer_update_message( input, msg ); if (msg->msg == WM_MOUSEMOVE) return merge_mousemove( input, msg ); + if (msg->msg == WM_WINE_CLIPCURSOR) return merge_wine_clipcursor( input, msg ); return 0; } diff --git a/server/user.h b/server/user.h index 523a533ca4f..4f6dc4755d5 100644 --- a/server/user.h +++ b/server/user.h @@ -104,7 +104,7 @@ extern void queue_cleanup_window( struct thread *thread, user_handle_t win ); extern int init_thread_queue( struct thread *thread ); extern int attach_thread_input( struct thread *thread_from, struct thread *thread_to ); extern void detach_thread_input( struct thread *thread_from ); -extern void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int send_clip_msg ); +extern void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int reset ); extern void post_message( user_handle_t win, unsigned int message, lparam_t wparam, lparam_t lparam ); extern void send_notify_message( user_handle_t win, unsigned int message, From a400dfc634d774929945c2e01d0c7e6572357507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 11:23:54 +0200 Subject: [PATCH 2098/2777] win32u: Asynchronously apply or reset ClipCursor from the hardware message. (cherry picked from commit 47e208e9ec91b3ac0aca7042778ff7d56c14ab4d) --- dlls/win32u/input.c | 2 +- dlls/win32u/message.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index f56adb576d8..ae8444ecd87 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2592,7 +2592,7 @@ BOOL WINAPI NtUserClipCursor( const RECT *rect ) } } SERVER_END_REQ; - if (ret) user_driver->pClipCursor( &new_rect, FALSE ); + return ret; } diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 5b3cc86870e..8c0ba27efd5 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1867,6 +1867,8 @@ static BOOL process_hardware_message( MSG *msg, UINT hw_id, const struct hardwar ret = process_keyboard_message( msg, hw_id, hwnd_filter, first, last, remove ); else if (is_mouse_message( msg->message )) ret = process_mouse_message( msg, hw_id, msg_data->info, hwnd_filter, first, last, remove ); + else if (msg->message == WM_WINE_CLIPCURSOR) + process_wine_clipcursor( msg->wParam, msg->lParam ); else ERR( "unknown message type %x\n", msg->message ); SetThreadDpiAwarenessContext( context ); From bbc4cf0a8c6269cf7933ca1f8ded0cbc5c4cfe78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 26 May 2023 23:02:17 +0200 Subject: [PATCH 2099/2777] winex11: Remove now unnecessary ClipCursor forwarding to foreground thread. (cherry picked from commit 397cd1c0c00ce3dc62b0c32b234ede5a0f48aea0) --- dlls/winex11.drv/mouse.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index b6986a9d68c..5158eda7984 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1650,20 +1650,9 @@ BOOL X11DRV_ClipCursor( const RECT *clip, BOOL reset ) if (!reset && grab_pointer) { RECT virtual_rect = NtUserGetVirtualScreenRect(); - HWND foreground = NtUserGetForegroundWindow(); - DWORD tid, pid; if (!clip) clip = &virtual_rect; - /* forward request to the foreground window if it's in a different thread */ - tid = NtUserGetWindowThread( foreground, &pid ); - if (tid && tid != GetCurrentThreadId() && pid == GetCurrentProcessId()) - { - TRACE( "forwarding clip request to %p\n", foreground ); - send_notify_message( foreground, WM_X11DRV_CLIP_CURSOR_REQUEST, FALSE, FALSE ); - return TRUE; - } - /* we are clipping if the clip rectangle is smaller than the screen */ if (clip->left > virtual_rect.left || clip->right < virtual_rect.right || clip->top > virtual_rect.top || clip->bottom < virtual_rect.bottom) @@ -1675,8 +1664,8 @@ BOOL X11DRV_ClipCursor( const RECT *clip, BOOL reset ) struct x11drv_thread_data *data = x11drv_thread_data(); if (data && data->clip_hwnd) { - if (EqualRect( clip, &clip_rect ) || clip_fullscreen_window( foreground, TRUE )) - return TRUE; + if (EqualRect( clip, &clip_rect )) return TRUE; + if (clip_fullscreen_window( NtUserGetForegroundWindow(), TRUE )) return TRUE; } } } @@ -1691,20 +1680,12 @@ BOOL X11DRV_ClipCursor( const RECT *clip, BOOL reset ) */ LRESULT clip_cursor_request( HWND hwnd, BOOL fullscreen, BOOL reset ) { - RECT clip; - if (hwnd == NtUserGetDesktopWindow()) WARN( "ignoring clip cursor request on desktop window.\n" ); else if (hwnd != NtUserGetForegroundWindow()) WARN( "ignoring clip cursor request on non-foreground window.\n" ); else if (fullscreen) clip_fullscreen_window( hwnd, reset ); - else - { - NtUserGetClipCursor( &clip ); - X11DRV_ClipCursor( &clip, FALSE ); - } - return 0; } From ab572eda14a87efd2d9d8203261062cad314f15a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 12 Jun 2023 23:29:42 +0200 Subject: [PATCH 2100/2777] server: Pass the message code to get_hardware_msg_bit. (cherry picked from commit 3ae2dc46484712cd2454b5aab4e82bd2c63d9ef4) --- server/queue.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/server/queue.c b/server/queue.c index a820ce6d285..befc113f84b 100644 --- a/server/queue.c +++ b/server/queue.c @@ -686,14 +686,14 @@ static inline int filter_contains_hw_range( unsigned int first, unsigned int las } /* get the QS_* bit corresponding to a given hardware message */ -static inline int get_hardware_msg_bit( struct message *msg ) -{ - if (msg->msg == WM_INPUT_DEVICE_CHANGE || msg->msg == WM_INPUT) return QS_RAWINPUT; - if (msg->msg == WM_MOUSEMOVE || msg->msg == WM_NCMOUSEMOVE) return QS_MOUSEMOVE; - if (msg->msg >= WM_KEYFIRST && msg->msg <= WM_KEYLAST) return QS_KEY; - if (msg->msg == WM_POINTERDOWN || msg->msg == WM_POINTERUP || - msg->msg == WM_POINTERUPDATE) return QS_POINTER; - if (msg->msg == WM_WINE_CLIPCURSOR) return QS_RAWINPUT; +static inline int get_hardware_msg_bit( unsigned int message ) +{ + if (message == WM_INPUT_DEVICE_CHANGE || message == WM_INPUT) return QS_RAWINPUT; + if (message == WM_MOUSEMOVE || message == WM_NCMOUSEMOVE) return QS_MOUSEMOVE; + if (message >= WM_KEYFIRST && message <= WM_KEYLAST) return QS_KEY; + if (message == WM_POINTERDOWN || message == WM_POINTERUP || + message == WM_POINTERUPDATE) return QS_POINTER; + if (message == WM_WINE_CLIPCURSOR) return QS_RAWINPUT; return QS_MOUSEBUTTON; } @@ -1728,10 +1728,10 @@ static void release_hardware_message( struct msg_queue *queue, unsigned int hw_i if (&msg->entry == &input->msg_list) return; /* not found */ /* clear the queue bit for that message */ - clr_bit = get_hardware_msg_bit( msg ); + clr_bit = get_hardware_msg_bit( msg->msg ); LIST_FOR_EACH_ENTRY( other, &input->msg_list, struct message, entry ) { - if (other != msg && get_hardware_msg_bit( other ) == clr_bit) + if (other != msg && get_hardware_msg_bit( other->msg ) == clr_bit) { clr_bit = 0; break; @@ -1790,7 +1790,7 @@ static user_handle_t find_hardware_message_window( struct desktop *desktop, stru *thread = NULL; *msg_code = msg->msg; - switch (get_hardware_msg_bit( msg )) + switch (get_hardware_msg_bit( msg->msg )) { case QS_POINTER: case QS_RAWINPUT: @@ -1855,7 +1855,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg last_input_time = get_tick_count(); if (msg->msg != WM_MOUSEMOVE) always_queue = 1; - switch (get_hardware_msg_bit( msg )) + switch (get_hardware_msg_bit( msg->msg )) { case QS_KEY: if (queue_hotkey_message( desktop, msg )) return; @@ -1911,7 +1911,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg { msg->unique_id = 0; /* will be set once we return it to the app */ list_add_tail( &input->msg_list, &msg->entry ); - set_queue_bits( thread->queue, get_hardware_msg_bit(msg) ); + set_queue_bits( thread->queue, get_hardware_msg_bit( msg->msg ) ); } release_object( thread ); } @@ -2525,7 +2525,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user if (win_thread->queue->input == input) { /* wake the other thread */ - set_queue_bits( win_thread->queue, get_hardware_msg_bit(msg) ); + set_queue_bits( win_thread->queue, get_hardware_msg_bit( msg->msg ) ); got_one = 1; } else @@ -2544,7 +2544,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user * match the filter we skip it */ if (got_one || !check_hw_message_filter( win, msg_code, filter_win, first, last )) { - clear_bits &= ~get_hardware_msg_bit( msg ); + clear_bits &= ~get_hardware_msg_bit( msg->msg ); continue; } @@ -2568,7 +2568,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user data->hw_id = msg->unique_id; set_reply_data( msg->data, msg->data_size ); - if ((get_hardware_msg_bit( msg ) & (QS_POINTER | QS_RAWINPUT)) && (flags & PM_REMOVE)) + if ((get_hardware_msg_bit( msg->msg ) & (QS_POINTER | QS_RAWINPUT)) && (flags & PM_REMOVE)) release_hardware_message( current->queue, data->hw_id ); return 1; } From 803e889dcdd5e0569eaf04e4570ede4819fb8b3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 10 Jun 2023 15:17:41 +0200 Subject: [PATCH 2101/2777] server: Use hardware message category when checking filter. (cherry picked from commit 6ac82b2a24a8dc9c4547ba896c9313c5864795a7) --- server/queue.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/server/queue.c b/server/queue.c index befc113f84b..abbe99e0042 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2444,19 +2444,19 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ static int check_hw_message_filter( user_handle_t win, unsigned int msg_code, user_handle_t filter_win, unsigned int first, unsigned int last ) { - if (msg_code >= WM_KEYFIRST && msg_code <= WM_KEYLAST) + switch (get_hardware_msg_bit( msg_code )) { + case QS_KEY: /* we can only test the window for a keyboard message since the * dest window for a mouse message depends on hittest */ if (filter_win && win != filter_win && !is_child_window( filter_win, win )) return 0; /* the message code is final for a keyboard message, we can simply check it */ return check_msg_filter( msg_code, first, last ); - } - else /* mouse message */ - { - /* we need to check all possible values that the message can have in the end */ + case QS_MOUSEMOVE: + case QS_MOUSEBUTTON: + /* we need to check all possible values that the message can have in the end */ if (check_msg_filter( msg_code, first, last )) return 1; if (msg_code == WM_MOUSEWHEEL) return 0; /* no other possible value for this one */ @@ -2471,6 +2471,9 @@ static int check_hw_message_filter( user_handle_t win, unsigned int msg_code, if (check_msg_filter( msg_code + (WM_NCLBUTTONDBLCLK - WM_LBUTTONDOWN), first, last )) return 1; } return 0; + + default: + return check_msg_filter( msg_code, first, last ); } } From 53dbf5a2c09cddced47a0ec121a8d9f627a1d78c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 12 Jun 2023 10:37:56 +0200 Subject: [PATCH 2102/2777] imm32: Avoid resizing IMCC to zero-size buffer. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55027 (cherry picked from commit 5911f36cfff1b48047042f2848b59a626258b29c) --- dlls/imm32/ime.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index e15367f5fa8..b1ff6c54c4e 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -366,7 +366,9 @@ static UINT ime_set_comp_string( HIMC himc, LPARAM lparam ) if (!(ctx = ImmLockIMC( himc ))) return 0; count = ImeToAsciiEx( VK_PROCESSKEY, lparam, NULL, &buffer.list, 0, himc ); - if (count >= buffer.uMsgCount) + if (!count) + TRACE( "ImeToAsciiEx returned no messages\n" ); + else if (count >= buffer.uMsgCount) WARN( "ImeToAsciiEx returned %#x messages\n", count ); else if (!(himcc = ImmReSizeIMCC( ctx->hMsgBuf, (ctx->dwNumMsgBuf + count) * sizeof(*msgs) ))) WARN( "Failed to resize input context message buffer\n" ); @@ -536,7 +538,7 @@ UINT WINAPI ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGLIST *msgs, if (!(ctx = ImmLockIMC( himc ))) return 0; if (!(compstr = ImmLockIMCC( ctx->hCompStr ))) goto done; - size = compstr->dwSize; + size = max( compstr->dwSize, sizeof(COMPOSITIONSTRING) ); do { From dd8df863956840ad9fb48eaada9bc55f0e40cd1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 12 Jun 2023 23:30:42 +0200 Subject: [PATCH 2103/2777] winex11: Remove now unnecessary WM_X11DRV_CLIP_CURSOR_NOTIFY. (cherry picked from commit bb043fb63eeec5346588762178f0bae8be0f51a6) --- dlls/winex11.drv/mouse.c | 49 ++++++--------------------------------- dlls/winex11.drv/window.c | 2 -- dlls/winex11.drv/x11drv.h | 2 -- 3 files changed, 7 insertions(+), 46 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 5158eda7984..b2c82b00a67 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -514,7 +514,6 @@ static BOOL grab_clipping_window( const RECT *clip ) if (!data->clip_hwnd) sync_window_cursor( clip_window ); InterlockedExchangePointer( (void **)&cursor_window, msg_hwnd ); data->clip_hwnd = msg_hwnd; - send_notify_message( NtUserGetDesktopWindow(), WM_X11DRV_CLIP_CURSOR_NOTIFY, 0, (LPARAM)msg_hwnd ); return TRUE; #else WARN( "XInput2 was not available at compile time\n" ); @@ -529,16 +528,19 @@ static BOOL grab_clipping_window( const RECT *clip ) */ static void ungrab_clipping_window(void) { - Display *display = thread_init_display(); + struct x11drv_thread_data *data = x11drv_init_thread_data(); Window clip_window = init_clip_window(); if (!clip_window) return; TRACE( "no longer clipping\n" ); - XUnmapWindow( display, clip_window ); - if (clipping_cursor) XUngrabPointer( display, CurrentTime ); + XUnmapWindow( data->display, clip_window ); + if (clipping_cursor) XUngrabPointer( data->display, CurrentTime ); clipping_cursor = FALSE; - send_notify_message( NtUserGetDesktopWindow(), WM_X11DRV_CLIP_CURSOR_NOTIFY, 0, 0 ); + NtUserDestroyWindow( data->clip_hwnd ); + data->clip_hwnd = 0; + data->clip_reset = NtGetTickCount(); + X11DRV_XInput2_Enable( data->display, None, 0 ); } /*********************************************************************** @@ -555,43 +557,6 @@ void retry_grab_clipping_window(void) NtUserClipCursor( &last_clip_rect ); } -/*********************************************************************** - * clip_cursor_notify - * - * Notification function called upon receiving a WM_X11DRV_CLIP_CURSOR_NOTIFY. - */ -LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) -{ - struct x11drv_thread_data *data = x11drv_init_thread_data(); - - if (hwnd == NtUserGetDesktopWindow()) /* change the clip window stored in the desktop process */ - { - static HWND clip_hwnd; - - HWND prev = clip_hwnd; - clip_hwnd = new_clip_hwnd; - if (prev || new_clip_hwnd) TRACE( "clip hwnd changed from %p to %p\n", prev, new_clip_hwnd ); - if (prev) send_notify_message( prev, WM_X11DRV_CLIP_CURSOR_NOTIFY, (WPARAM)prev, 0 ); - } - else if (hwnd == data->clip_hwnd) /* this is a notification that clipping has been reset */ - { - TRACE( "clip hwnd reset from %p\n", hwnd ); - data->clip_hwnd = 0; - data->clip_reset = NtGetTickCount(); - X11DRV_XInput2_Enable( data->display, None, 0 ); - NtUserDestroyWindow( hwnd ); - } - else if (prev_clip_hwnd) - { - /* This is a notification send by the desktop window to an old - * dangling clip window. - */ - TRACE( "destroying old clip hwnd %p\n", prev_clip_hwnd ); - NtUserDestroyWindow( prev_clip_hwnd ); - } - return 0; -} - /*********************************************************************** * clip_fullscreen_window * diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 8edf5829add..0e7821e8c1a 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -3732,8 +3732,6 @@ LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) } return 0; } - case WM_X11DRV_CLIP_CURSOR_NOTIFY: - return clip_cursor_notify( hwnd, (HWND)wp, (HWND)lp ); case WM_X11DRV_CLIP_CURSOR_REQUEST: return clip_cursor_request( hwnd, (BOOL)wp, (BOOL)lp ); case WM_X11DRV_DELETE_TAB: diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 4416f6403a1..6dd4077fccc 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -609,7 +609,6 @@ enum x11drv_window_messages WM_X11DRV_SET_WIN_REGION, WM_X11DRV_DESKTOP_RESIZED, WM_X11DRV_SET_CURSOR, - WM_X11DRV_CLIP_CURSOR_NOTIFY, WM_X11DRV_CLIP_CURSOR_REQUEST, WM_X11DRV_DELETE_TAB, WM_X11DRV_ADD_TAB @@ -738,7 +737,6 @@ extern XContext cursor_context DECLSPEC_HIDDEN; extern void X11DRV_SetFocus( HWND hwnd ) DECLSPEC_HIDDEN; extern void set_window_cursor( Window window, HCURSOR handle ) DECLSPEC_HIDDEN; extern void sync_window_cursor( Window window ) DECLSPEC_HIDDEN; -extern LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip_hwnd ) DECLSPEC_HIDDEN; extern LRESULT clip_cursor_request( HWND hwnd, BOOL fullscreen, BOOL reset ) DECLSPEC_HIDDEN; extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN; extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN; From 89e5d3cdd2607b144d087ca7e05a22f3777d2cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 12 Jun 2023 23:31:26 +0200 Subject: [PATCH 2104/2777] win32u: Move grab_pointer registry option from winex11. (cherry picked from commit f47ed2926037b96942bd40f6140601987a3025cb) --- dlls/win32u/input.c | 7 +++- dlls/win32u/sysparams.c | 75 +++++++++++++++++++++++++++++++++- dlls/win32u/win32u_private.h | 1 + dlls/winex11.drv/mouse.c | 2 +- dlls/winex11.drv/x11drv.h | 1 - dlls/winex11.drv/x11drv_main.c | 4 -- 6 files changed, 81 insertions(+), 9 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index ae8444ecd87..b150a656b82 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -405,6 +405,8 @@ static const KBDTABLES kbdus_tables = }; +BOOL grab_pointer = TRUE; + static void kbd_tables_init_vsc2vk( const KBDTABLES *tables, BYTE vsc2vk[0x300] ) { const VSC_VK *entry; @@ -2543,7 +2545,10 @@ BOOL process_wine_clipcursor( BOOL empty, BOOL reset ) TRACE( "empty %u, reset %u\n", empty, reset ); - if (empty || reset) return user_driver->pClipCursor( NULL, reset ); + if (reset) return user_driver->pClipCursor( NULL, TRUE ); + + if (!grab_pointer) return TRUE; + if (empty) return user_driver->pClipCursor( NULL, reset ); get_clip_cursor( &rect ); return user_driver->pClipCursor( &rect, FALSE ); diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 38562fe47f4..52f1293a388 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -4127,13 +4127,47 @@ static union sysparam_all_entry * const default_entries[] = (union sysparam_all_entry *)&entry_AUDIODESC_ON, }; -void sysparams_init(void) +/*********************************************************************** + * get_config_key + * + * Get a config key from either the app-specific or the default config + */ +static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name, + WCHAR *buffer, DWORD size ) { + WCHAR nameW[128]; + char buf[2048]; + KEY_VALUE_PARTIAL_INFORMATION *info = (void *)buf; + + asciiz_to_unicode( nameW, name ); + + if (appkey && query_reg_value( appkey, nameW, info, sizeof(buf) )) + { + size = min( info->DataLength, size - sizeof(WCHAR) ); + memcpy( buffer, info->Data, size ); + buffer[size / sizeof(WCHAR)] = 0; + return 0; + } + + if (defkey && query_reg_value( defkey, nameW, info, sizeof(buf) )) + { + size = min( info->DataLength, size - sizeof(WCHAR) ); + memcpy( buffer, info->Data, size ); + buffer[size / sizeof(WCHAR)] = 0; + return 0; + } + + return ERROR_FILE_NOT_FOUND; +} +void sysparams_init(void) +{ + WCHAR buffer[MAX_PATH+16], *p, *appname; DWORD i, dispos, dpi_scaling; WCHAR layout[KL_NAMELENGTH]; pthread_mutexattr_t attr; - HKEY hkey; + HKEY hkey, appkey = 0; + DWORD len; static const WCHAR software_wineW[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e'}; static const WCHAR temporary_system_parametersW[] = @@ -4142,6 +4176,7 @@ void sysparams_init(void) static const WCHAR oneW[] = {'1',0}; static const WCHAR kl_preloadW[] = {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d'}; + static const WCHAR x11driverW[] = {'\\','X','1','1',' ','D','r','i','v','e','r',0}; pthread_mutexattr_init( &attr ); pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ); @@ -4201,6 +4236,42 @@ void sysparams_init(void) for (i = 0; i < ARRAY_SIZE( default_entries ); i++) default_entries[i]->hdr.init( default_entries[i] ); } + + /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */ + hkey = reg_open_hkcu_key( "Software\\Wine\\X11 Driver" ); + + /* open the app-specific key */ + + appname = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer; + if ((p = wcsrchr( appname, '/' ))) appname = p + 1; + if ((p = wcsrchr( appname, '\\' ))) appname = p + 1; + len = lstrlenW( appname ); + + if (len && len < MAX_PATH) + { + HKEY tmpkey; + int i; + + for (i = 0; appname[i]; i++) buffer[i] = RtlDowncaseUnicodeChar( appname[i] ); + buffer[i] = 0; + appname = buffer; + memcpy( appname + i, x11driverW, sizeof(x11driverW) ); + + /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\X11 Driver */ + if ((tmpkey = reg_open_hkcu_key( "Software\\Wine\\AppDefaults" ))) + { + appkey = reg_open_key( tmpkey, appname, lstrlenW( appname ) * sizeof(WCHAR) ); + NtClose( tmpkey ); + } + } + +#define IS_OPTION_TRUE(ch) \ + ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1') + + if (!get_config_key( hkey, appkey, "GrabPointer", buffer, sizeof(buffer) )) + grab_pointer = IS_OPTION_TRUE( buffer[0] ); + +#undef IS_OPTION_TRUE } static BOOL update_desktop_wallpaper(void) diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 8cfa108e5b9..7faa33f2aad 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -263,6 +263,7 @@ extern BOOL register_imm_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void unregister_imm_window( HWND hwnd ) DECLSPEC_HIDDEN; /* input.c */ +extern BOOL grab_pointer DECLSPEC_HIDDEN; extern BOOL destroy_caret(void) DECLSPEC_HIDDEN; extern BOOL enable_mouse_in_pointer DECLSPEC_HIDDEN; extern HWND get_active_window(void) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index b2c82b00a67..cefe42d1d69 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1612,7 +1612,7 @@ BOOL X11DRV_ClipCursor( const RECT *clip, BOOL reset ) { TRACE( "clip %p, reset %u\n", clip, reset ); - if (!reset && grab_pointer) + if (!reset) { RECT virtual_rect = NtUserGetVirtualScreenRect(); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 6dd4077fccc..ade0deb45da 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -446,7 +446,6 @@ extern BOOL use_take_focus DECLSPEC_HIDDEN; extern BOOL use_primary_selection DECLSPEC_HIDDEN; extern BOOL use_system_cursors DECLSPEC_HIDDEN; extern BOOL show_systray DECLSPEC_HIDDEN; -extern BOOL grab_pointer DECLSPEC_HIDDEN; extern BOOL grab_fullscreen DECLSPEC_HIDDEN; extern BOOL usexcomposite DECLSPEC_HIDDEN; extern BOOL use_xfixes DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 5e700df456a..3a0f2a0e48e 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -76,7 +76,6 @@ BOOL use_take_focus = FALSE; BOOL use_primary_selection = FALSE; BOOL use_system_cursors = TRUE; BOOL show_systray = TRUE; -BOOL grab_pointer = TRUE; BOOL grab_fullscreen = FALSE; BOOL managed_mode = TRUE; BOOL decorated_mode = TRUE; @@ -525,9 +524,6 @@ static void setup_options(void) if (!get_config_key( hkey, appkey, "ShowSystray", buffer, sizeof(buffer) )) show_systray = IS_OPTION_TRUE( buffer[0] ); - if (!get_config_key( hkey, appkey, "GrabPointer", buffer, sizeof(buffer) )) - grab_pointer = IS_OPTION_TRUE( buffer[0] ); - if (!get_config_key( hkey, appkey, "GrabFullscreen", buffer, sizeof(buffer) )) grab_fullscreen = IS_OPTION_TRUE( buffer[0] ); From 26f467a616dea057bb79837f95dcf1b31af95c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 12 Jun 2023 23:31:59 +0200 Subject: [PATCH 2105/2777] win32u: Add a clipping_reset member to user_thread_info. (cherry picked from commit 89a7c05ad91e7ba92326205593918fec2c75e7bc) --- dlls/win32u/input.c | 7 ++++++- dlls/win32u/ntuser_private.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index b150a656b82..12e64bd8bff 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2541,11 +2541,16 @@ BOOL get_clip_cursor( RECT *rect ) BOOL process_wine_clipcursor( BOOL empty, BOOL reset ) { + struct user_thread_info *thread_info = get_user_thread_info(); RECT rect; TRACE( "empty %u, reset %u\n", empty, reset ); - if (reset) return user_driver->pClipCursor( NULL, TRUE ); + if (reset) + { + thread_info->clipping_reset = NtGetTickCount(); + return user_driver->pClipCursor( NULL, TRUE ); + } if (!grab_pointer) return TRUE; if (empty) return user_driver->pClipCursor( NULL, reset ); diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index b7d2b633eb5..56b74ce0ebc 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -140,6 +140,7 @@ struct user_thread_info struct rawinput_thread_data *rawinput; /* RawInput thread local data / buffer */ struct touchinput_thread_data *touchinput; /* touch input thread local buffer */ UINT spy_indent; /* Current spy indent */ + DWORD clipping_reset; /* time when clipping was last reset */ struct desktop_shared_memory *desktop_shared_memory; /* Ptr to server's desktop shared memory */ struct queue_shared_memory *queue_shared_memory; /* Ptr to server's thread queue shared memory */ struct input_shared_memory *input_shared_memory; /* Ptr to server's thread input shared memory */ From a30f20f38a32fdcd495522a8feeb47fa5f2a4cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 18:43:48 +0200 Subject: [PATCH 2106/2777] win32u: Add a clipping_cursor member to user_thread_info. (cherry picked from commit 3cca65e3283d12d5b61b2ac9b314c36c30a3fa1d) --- dlls/win32u/input.c | 9 ++++++++- dlls/win32u/ntuser_private.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 12e64bd8bff..9530cba031b 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -404,6 +404,7 @@ static const KBDTABLES kbdus_tables = .fLocaleFlags = MAKELONG(0, KBD_VERSION), }; +static LONG clipping_cursor; /* clipping thread counter */ BOOL grab_pointer = TRUE; @@ -2546,6 +2547,9 @@ BOOL process_wine_clipcursor( BOOL empty, BOOL reset ) TRACE( "empty %u, reset %u\n", empty, reset ); + if (thread_info->clipping_cursor) InterlockedDecrement( &clipping_cursor ); + thread_info->clipping_cursor = FALSE; + if (reset) { thread_info->clipping_reset = NtGetTickCount(); @@ -2556,7 +2560,10 @@ BOOL process_wine_clipcursor( BOOL empty, BOOL reset ) if (empty) return user_driver->pClipCursor( NULL, reset ); get_clip_cursor( &rect ); - return user_driver->pClipCursor( &rect, FALSE ); + if (!user_driver->pClipCursor( &rect, FALSE )) return FALSE; + InterlockedIncrement( &clipping_cursor ); + thread_info->clipping_cursor = TRUE; + return TRUE; } /*********************************************************************** diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 56b74ce0ebc..3b49ff48f35 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -140,6 +140,7 @@ struct user_thread_info struct rawinput_thread_data *rawinput; /* RawInput thread local data / buffer */ struct touchinput_thread_data *touchinput; /* touch input thread local buffer */ UINT spy_indent; /* Current spy indent */ + BOOL clipping_cursor; /* thread is currently clipping */ DWORD clipping_reset; /* time when clipping was last reset */ struct desktop_shared_memory *desktop_shared_memory; /* Ptr to server's desktop shared memory */ struct queue_shared_memory *queue_shared_memory; /* Ptr to server's thread queue shared memory */ From 016d341fd06d0438beb468015ba7339a6113d7df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 31 May 2023 21:15:00 +0200 Subject: [PATCH 2107/2777] winex11: Move clip_fullscreen_window foreground check inside it. (cherry picked from commit b1d273bba3a5e02d78889e1798d22226d41bc0b7) --- dlls/winex11.drv/event.c | 2 +- dlls/winex11.drv/mouse.c | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 9c518176e1e..d7e68827cbc 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -893,7 +893,7 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) xim_set_focus( hwnd, TRUE ); if (use_take_focus) { - if (hwnd == NtUserGetForegroundWindow()) clip_fullscreen_window( hwnd, FALSE ); + clip_fullscreen_window( hwnd, FALSE ); return TRUE; } diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index cefe42d1d69..781bd4fe575 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -572,6 +572,8 @@ BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) BOOL fullscreen; if (hwnd == NtUserGetDesktopWindow()) return FALSE; + if (hwnd != NtUserGetForegroundWindow()) return FALSE; + style = NtUserGetWindowLongW( hwnd, GWL_STYLE ); if (!(style & WS_VISIBLE)) return FALSE; if ((style & (WS_POPUP | WS_CHILD)) == WS_CHILD) return FALSE; @@ -708,12 +710,8 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU last_cursor_change = input->u.mi.time; } - if (hwnd != NtUserGetDesktopWindow()) - { - hwnd = NtUserGetAncestor( hwnd, GA_ROOT ); - if ((input->u.mi.dwFlags & (MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_RIGHTDOWN)) && hwnd == NtUserGetForegroundWindow()) - clip_fullscreen_window( hwnd, FALSE ); - } + if (input->u.mi.dwFlags & (MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_RIGHTDOWN)) + clip_fullscreen_window( hwnd, FALSE ); /* update the wine server Z-order */ From f873b820a08aeff12cea227815105ca04c2a6d5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 12 Jun 2023 23:32:59 +0200 Subject: [PATCH 2108/2777] win32u: Move fullscreen window cursor clipping from winex11. (cherry picked from commit af902c188ebaf7d6dda3b628409d8c390ab410d5) --- dlls/win32u/input.c | 67 ++++++++++++++++++++++++--- dlls/win32u/message.c | 8 +++- dlls/win32u/ntgdi_private.h | 9 ---- dlls/win32u/sysparams.c | 4 ++ dlls/win32u/win32u_private.h | 16 ++++++- dlls/win32u/winstation.c | 13 ++++++ dlls/winex11.drv/desktop.c | 3 -- dlls/winex11.drv/event.c | 7 +-- dlls/winex11.drv/mouse.c | 89 +----------------------------------- dlls/winex11.drv/window.c | 2 - dlls/winex11.drv/x11drv.h | 4 -- 11 files changed, 102 insertions(+), 120 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 9530cba031b..61adcd1bff8 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -407,6 +407,7 @@ static const KBDTABLES kbdus_tables = static LONG clipping_cursor; /* clipping thread counter */ BOOL grab_pointer = TRUE; +BOOL grab_fullscreen = FALSE; static void kbd_tables_init_vsc2vk( const KBDTABLES *tables, BYTE vsc2vk[0x300] ) { @@ -1855,7 +1856,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) if (previous == hwnd) { if (prev) *prev = hwnd; - return TRUE; + goto done; } if (prev) *prev = previous; @@ -1952,6 +1953,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) done: win_set_flags( hwnd, 0, WIN_IS_ACTIVATING ); + if (ret && hwnd) clip_fullscreen_window( hwnd, FALSE ); return ret; } @@ -2478,6 +2480,49 @@ BOOL WINAPI NtUserIsMouseInPointerEnabled(void) return FALSE; } +/*********************************************************************** + * clip_fullscreen_window + * + * Turn on clipping if the active window is fullscreen. + */ +BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + MONITORINFO monitor_info = {.cbSize = sizeof(MONITORINFO)}; + RECT rect, virtual_rect = NtUserGetVirtualScreenRect(); + HMONITOR monitor; + DWORD style; + + if (hwnd == NtUserGetDesktopWindow()) return FALSE; + if (hwnd != NtUserGetForegroundWindow()) return FALSE; + + style = NtUserGetWindowLongW( hwnd, GWL_STYLE ); + if (!(style & WS_VISIBLE)) return FALSE; + if ((style & (WS_POPUP | WS_CHILD)) == WS_CHILD) return FALSE; + /* maximized windows don't count as full screen */ + if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION) return FALSE; + + if (!NtUserGetWindowRect( hwnd, &rect )) return FALSE; + if (!NtUserIsWindowRectFullScreen( &rect )) return FALSE; + if (NtGetTickCount() - thread_info->clipping_reset < 1000) return FALSE; + if (!reset && clipping_cursor && thread_info->clipping_cursor) return FALSE; /* already clipping */ + + if (!(monitor = NtUserMonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST ))) return FALSE; + if (!NtUserGetMonitorInfo( monitor, &monitor_info )) return FALSE; + if (!grab_fullscreen) + { + RECT virtual_rect = NtUserGetVirtualScreenRect(); + if (!EqualRect( &monitor_info.rcMonitor, &virtual_rect )) return FALSE; + if (is_virtual_desktop()) return FALSE; + } + + /* shrink the clipping rect to make sure it is not ignored for being fullscreen */ + if (EqualRect( &monitor_info.rcMonitor, &virtual_rect )) InflateRect( &monitor_info.rcMonitor, -1, -1 ); + + TRACE( "win %p clipping fullscreen\n", hwnd ); + return NtUserClipCursor( &monitor_info.rcMonitor ); +} + /********************************************************************** * NtUserIsTouchWindow (win32u.@) */ @@ -2540,14 +2585,15 @@ BOOL get_clip_cursor( RECT *rect ) return TRUE; } -BOOL process_wine_clipcursor( BOOL empty, BOOL reset ) +BOOL process_wine_clipcursor( HWND hwnd, BOOL empty, BOOL reset ) { struct user_thread_info *thread_info = get_user_thread_info(); - RECT rect; + RECT rect, virtual_rect = NtUserGetVirtualScreenRect(); + BOOL was_clipping; - TRACE( "empty %u, reset %u\n", empty, reset ); + TRACE( "hwnd %p, empty %u, reset %u\n", hwnd, empty, reset ); - if (thread_info->clipping_cursor) InterlockedDecrement( &clipping_cursor ); + if ((was_clipping = thread_info->clipping_cursor)) InterlockedDecrement( &clipping_cursor ); thread_info->clipping_cursor = FALSE; if (reset) @@ -2557,9 +2603,18 @@ BOOL process_wine_clipcursor( BOOL empty, BOOL reset ) } if (!grab_pointer) return TRUE; - if (empty) return user_driver->pClipCursor( NULL, reset ); + /* we are clipping if the clip rectangle is smaller than the screen */ get_clip_cursor( &rect ); + intersect_rect( &rect, &rect, &virtual_rect ); + if (EqualRect( &rect, &virtual_rect )) empty = TRUE; + if (empty) + { + /* if currently clipping, check if we should switch to fullscreen clipping */ + if (was_clipping && clip_fullscreen_window( hwnd, TRUE )) return TRUE; + return user_driver->pClipCursor( NULL, FALSE ); + } + if (!user_driver->pClipCursor( &rect, FALSE )) return FALSE; InterlockedIncrement( &clipping_cursor ); thread_info->clipping_cursor = TRUE; diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 8c0ba27efd5..9abdcf890a3 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1287,7 +1287,8 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR return call_current_hook( h_extra->handle, HC_ACTION, wparam, h_extra->lparam ); } case WM_WINE_CLIPCURSOR: - return process_wine_clipcursor( wparam, lparam ); + if (wparam && lparam) return clip_fullscreen_window( hwnd, FALSE ); + return process_wine_clipcursor( hwnd, wparam, lparam ); case WM_WINE_UPDATEWINDOWSTATE: update_window_state( hwnd ); return 0; @@ -1868,7 +1869,7 @@ static BOOL process_hardware_message( MSG *msg, UINT hw_id, const struct hardwar else if (is_mouse_message( msg->message )) ret = process_mouse_message( msg, hw_id, msg_data->info, hwnd_filter, first, last, remove ); else if (msg->message == WM_WINE_CLIPCURSOR) - process_wine_clipcursor( msg->wParam, msg->lParam ); + process_wine_clipcursor( msg->hwnd, msg->wParam, msg->lParam ); else ERR( "unknown message type %x\n", msg->message ); SetThreadDpiAwarenessContext( context ); @@ -2759,6 +2760,9 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r info.timeout = 0; info.params = NULL; + if (input->type == INPUT_MOUSE && (input->mi.dwFlags & (MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_RIGHTDOWN))) + clip_fullscreen_window( hwnd, FALSE ); + if (input->type == INPUT_HARDWARE && rawinput->header.dwType == RIM_TYPEHID) { if (input->hi.uMsg == WM_INPUT_DEVICE_CHANGE) diff --git a/dlls/win32u/ntgdi_private.h b/dlls/win32u/ntgdi_private.h index 93be59c9d7e..3262f5c2e2a 100644 --- a/dlls/win32u/ntgdi_private.h +++ b/dlls/win32u/ntgdi_private.h @@ -528,15 +528,6 @@ static inline DC *get_physdev_dc( PHYSDEV dev ) return get_nulldrv_dc( dev ); } -static inline BOOL intersect_rect( RECT *dst, const RECT *src1, const RECT *src2 ) -{ - dst->left = max( src1->left, src2->left ); - dst->top = max( src1->top, src2->top ); - dst->right = min( src1->right, src2->right ); - dst->bottom = min( src1->bottom, src2->bottom ); - return !IsRectEmpty( dst ); -} - static inline void order_rect( RECT *rect ) { if (rect->left > rect->right) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 52f1293a388..13a11581e79 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2732,6 +2732,8 @@ static LONG apply_display_settings( const WCHAR *devname, const DEVMODEW *devmod send_message_timeout( HWND_BROADCAST, WM_DISPLAYCHANGE, current_mode.dmBitsPerPel, MAKELPARAM( current_mode.dmPelsWidth, current_mode.dmPelsHeight ), SMTO_ABORTIFHUNG, 2000, FALSE ); + /* post clip_fullscreen_window request to the foreground window */ + NtUserPostMessage( NtUserGetForegroundWindow(), WM_WINE_CLIPCURSOR, TRUE, TRUE ); } return ret; @@ -4270,6 +4272,8 @@ void sysparams_init(void) if (!get_config_key( hkey, appkey, "GrabPointer", buffer, sizeof(buffer) )) grab_pointer = IS_OPTION_TRUE( buffer[0] ); + if (!get_config_key( hkey, appkey, "GrabFullscreen", buffer, sizeof(buffer) )) + grab_fullscreen = IS_OPTION_TRUE( buffer[0] ); #undef IS_OPTION_TRUE } diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 7faa33f2aad..c78d039d91f 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -264,6 +264,7 @@ extern void unregister_imm_window( HWND hwnd ) DECLSPEC_HIDDEN; /* input.c */ extern BOOL grab_pointer DECLSPEC_HIDDEN; +extern BOOL grab_fullscreen DECLSPEC_HIDDEN; extern BOOL destroy_caret(void) DECLSPEC_HIDDEN; extern BOOL enable_mouse_in_pointer DECLSPEC_HIDDEN; extern HWND get_active_window(void) DECLSPEC_HIDDEN; @@ -281,7 +282,8 @@ extern void toggle_caret( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL unregister_touch_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void update_mouse_tracking_info( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL get_clip_cursor( RECT *rect ) DECLSPEC_HIDDEN; -extern BOOL process_wine_clipcursor( BOOL empty, BOOL reset ) DECLSPEC_HIDDEN; +extern BOOL process_wine_clipcursor( HWND hwnd, BOOL empty, BOOL reset ) DECLSPEC_HIDDEN; +extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN; /* menu.c */ extern HMENU create_menu( BOOL is_popup ) DECLSPEC_HIDDEN; @@ -362,6 +364,9 @@ extern void user_lock(void) DECLSPEC_HIDDEN; extern void user_unlock(void) DECLSPEC_HIDDEN; extern void user_check_not_lock(void) DECLSPEC_HIDDEN; +/* winstation.c */ +extern BOOL is_virtual_desktop(void) DECLSPEC_HIDDEN; + /* window.c */ struct tagWND; extern HDWP begin_defer_window_pos( INT count ) DECLSPEC_HIDDEN; @@ -528,4 +533,13 @@ static inline const char *debugstr_color( COLORREF color ) return wine_dbg_sprintf( "RGB(%02x,%02x,%02x)", GetRValue(color), GetGValue(color), GetBValue(color) ); } +static inline BOOL intersect_rect( RECT *dst, const RECT *src1, const RECT *src2 ) +{ + dst->left = max( src1->left, src2->left ); + dst->top = max( src1->top, src2->top ); + dst->right = min( src1->right, src2->right ); + dst->bottom = min( src1->bottom, src2->bottom ); + return !IsRectEmpty( dst ); +} + #endif /* __WINE_WIN32U_PRIVATE */ diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 8ab6122709e..f0190d2335e 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -40,6 +40,19 @@ WINE_DECLARE_DEBUG_CHANNEL(win); #define DESKTOP_ALL_ACCESS 0x01ff +BOOL is_virtual_desktop(void) +{ + HANDLE desktop = NtUserGetThreadDesktop( GetCurrentThreadId() ); + USEROBJECTFLAGS flags = {0}; + NTSTATUS status; + DWORD len; + + status = NtUserGetObjectInformation( desktop, UOI_FLAGS, &flags, sizeof(flags), &len ); + if (status) return FALSE; + + return !!(flags.dwFlags & DF_WINE_CREATE_DESKTOP); +} + /*********************************************************************** * NtUserCreateWindowStation (win32u.@) */ diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c index f0c038d8981..9bfdf24dc01 100644 --- a/dlls/winex11.drv/desktop.c +++ b/dlls/winex11.drv/desktop.c @@ -453,8 +453,5 @@ void X11DRV_resize_desktop(void) send_message_timeout( HWND_BROADCAST, WM_X11DRV_DESKTOP_RESIZED, old_virtual_rect.left, old_virtual_rect.top, SMTO_ABORTIFHUNG, 2000, FALSE ); - /* forward clip_fullscreen_window request to the foreground window */ - send_notify_message( NtUserGetForegroundWindow(), WM_X11DRV_CLIP_CURSOR_REQUEST, TRUE, TRUE ); - old_virtual_rect = virtual_rect; } diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index d7e68827cbc..45cf20aa0b2 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -891,11 +891,8 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) } xim_set_focus( hwnd, TRUE ); - if (use_take_focus) - { - clip_fullscreen_window( hwnd, FALSE ); - return TRUE; - } + + if (use_take_focus) return TRUE; if (!can_activate_window(hwnd)) { diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 781bd4fe575..1993e973d24 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -539,7 +539,6 @@ static void ungrab_clipping_window(void) clipping_cursor = FALSE; NtUserDestroyWindow( data->clip_hwnd ); data->clip_hwnd = 0; - data->clip_reset = NtGetTickCount(); X11DRV_XInput2_Enable( data->display, None, 0 ); } @@ -557,50 +556,6 @@ void retry_grab_clipping_window(void) NtUserClipCursor( &last_clip_rect ); } -/*********************************************************************** - * clip_fullscreen_window - * - * Turn on clipping if the active window is fullscreen. - */ -BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) -{ - struct x11drv_win_data *data; - struct x11drv_thread_data *thread_data; - MONITORINFO monitor_info; - HMONITOR monitor; - DWORD style; - BOOL fullscreen; - - if (hwnd == NtUserGetDesktopWindow()) return FALSE; - if (hwnd != NtUserGetForegroundWindow()) return FALSE; - - style = NtUserGetWindowLongW( hwnd, GWL_STYLE ); - if (!(style & WS_VISIBLE)) return FALSE; - if ((style & (WS_POPUP | WS_CHILD)) == WS_CHILD) return FALSE; - /* maximized windows don't count as full screen */ - if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION) return FALSE; - if (!(data = get_win_data( hwnd ))) return FALSE; - fullscreen = NtUserIsWindowRectFullScreen( &data->whole_rect ); - release_win_data( data ); - if (!fullscreen) return FALSE; - if (!(thread_data = x11drv_thread_data())) return FALSE; - if (NtGetTickCount() - thread_data->clip_reset < 1000) return FALSE; - if (!reset && clipping_cursor && thread_data->clip_hwnd) return FALSE; /* already clipping */ - - monitor = NtUserMonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST ); - if (!monitor) return FALSE; - monitor_info.cbSize = sizeof(monitor_info); - if (!NtUserGetMonitorInfo( monitor, &monitor_info )) return FALSE; - if (!grab_fullscreen) - { - RECT virtual_rect = NtUserGetVirtualScreenRect(); - if (!EqualRect( &monitor_info.rcMonitor, &virtual_rect )) return FALSE; - if (is_virtual_desktop()) return FALSE; - } - TRACE( "win %p clipping fullscreen\n", hwnd ); - return grab_clipping_window( &monitor_info.rcMonitor ); -} - /*********************************************************************** * is_old_motion_event @@ -710,9 +665,6 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU last_cursor_change = input->u.mi.time; } - if (input->u.mi.dwFlags & (MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_RIGHTDOWN)) - clip_fullscreen_window( hwnd, FALSE ); - /* update the wine server Z-order */ if (hwnd != x11drv_thread_data()->grab_hwnd && @@ -1608,50 +1560,11 @@ BOOL X11DRV_GetCursorPos(LPPOINT pos) */ BOOL X11DRV_ClipCursor( const RECT *clip, BOOL reset ) { - TRACE( "clip %p, reset %u\n", clip, reset ); - - if (!reset) - { - RECT virtual_rect = NtUserGetVirtualScreenRect(); - - if (!clip) clip = &virtual_rect; - - /* we are clipping if the clip rectangle is smaller than the screen */ - if (clip->left > virtual_rect.left || clip->right < virtual_rect.right || - clip->top > virtual_rect.top || clip->bottom < virtual_rect.bottom) - { - if (grab_clipping_window( clip )) return TRUE; - } - else /* if currently clipping, check if we should switch to fullscreen clipping */ - { - struct x11drv_thread_data *data = x11drv_thread_data(); - if (data && data->clip_hwnd) - { - if (EqualRect( clip, &clip_rect )) return TRUE; - if (clip_fullscreen_window( NtUserGetForegroundWindow(), TRUE )) return TRUE; - } - } - } + if (!reset && clip && grab_clipping_window( clip )) return TRUE; ungrab_clipping_window(); return TRUE; } -/*********************************************************************** - * clip_cursor_request - * - * Function called upon receiving a WM_X11DRV_CLIP_CURSOR_REQUEST. - */ -LRESULT clip_cursor_request( HWND hwnd, BOOL fullscreen, BOOL reset ) -{ - if (hwnd == NtUserGetDesktopWindow()) - WARN( "ignoring clip cursor request on desktop window.\n" ); - else if (hwnd != NtUserGetForegroundWindow()) - WARN( "ignoring clip cursor request on non-foreground window.\n" ); - else if (fullscreen) - clip_fullscreen_window( hwnd, reset ); - return 0; -} - /*********************************************************************** * move_resize_window */ diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 0e7821e8c1a..1408f1c1ab2 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -3732,8 +3732,6 @@ LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) } return 0; } - case WM_X11DRV_CLIP_CURSOR_REQUEST: - return clip_cursor_request( hwnd, (BOOL)wp, (BOOL)lp ); case WM_X11DRV_DELETE_TAB: taskbar_delete_tab( hwnd ); return 0; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index ade0deb45da..663f510965d 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -393,7 +393,6 @@ struct x11drv_thread_data unsigned long warp_serial; /* serial number of last pointer warp request */ Window clip_window; /* window used for cursor clipping */ HWND clip_hwnd; /* message window stored in desktop while clipping is active */ - DWORD clip_reset; /* time when clipping was last reset */ #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H XIValuatorClassInfo x_valuator; XIValuatorClassInfo y_valuator; @@ -608,7 +607,6 @@ enum x11drv_window_messages WM_X11DRV_SET_WIN_REGION, WM_X11DRV_DESKTOP_RESIZED, WM_X11DRV_SET_CURSOR, - WM_X11DRV_CLIP_CURSOR_REQUEST, WM_X11DRV_DELETE_TAB, WM_X11DRV_ADD_TAB }; @@ -736,9 +734,7 @@ extern XContext cursor_context DECLSPEC_HIDDEN; extern void X11DRV_SetFocus( HWND hwnd ) DECLSPEC_HIDDEN; extern void set_window_cursor( Window window, HCURSOR handle ) DECLSPEC_HIDDEN; extern void sync_window_cursor( Window window ) DECLSPEC_HIDDEN; -extern LRESULT clip_cursor_request( HWND hwnd, BOOL fullscreen, BOOL reset ) DECLSPEC_HIDDEN; extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN; -extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN; extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN; extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN; extern void X11DRV_InitMouse( Display *display ) DECLSPEC_HIDDEN; From b98007d95e10070bbcb1838ba53fdd68cd6af249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 13 Jun 2023 23:05:01 +0200 Subject: [PATCH 2109/2777] server: Update desktop cursor window when cursor pos changes. (cherry picked from commit 10f5ff7f06595bf9d1f487f91dbbd869e5105d26) --- server/queue.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/server/queue.c b/server/queue.c index abbe99e0042..15c01e2e77e 100644 --- a/server/queue.c +++ b/server/queue.c @@ -489,8 +489,16 @@ static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_sour return msg; } -static int update_desktop_cursor_pos( struct desktop *desktop, int x, int y ) +static int update_desktop_cursor_window( struct desktop *desktop, user_handle_t win ) { + int updated = win != desktop->cursor_win; + desktop->cursor_win = win; + return updated; +} + +static int update_desktop_cursor_pos( struct desktop *desktop, user_handle_t win, int x, int y ) +{ + struct thread_input *input; int updated; unsigned int time = get_tick_count(); @@ -504,6 +512,11 @@ static int update_desktop_cursor_pos( struct desktop *desktop, int x, int y ) desktop->shared->cursor.last_change = time; SHARED_WRITE_END( &desktop->shared->seq ); + if (!win && (input = desktop->foreground_input)) win = input->shared->capture; + if (!win || !is_window_visible( win ) || is_window_transparent( win )) + win = shallow_window_from_point( desktop, x, y ); + if (update_desktop_cursor_window( desktop, win )) updated = 1; + return updated; } @@ -516,7 +529,7 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y ) if ((device = current->process->rawinput_mouse) && (device->flags & RIDEV_NOLEGACY)) { - update_desktop_cursor_pos( desktop, x, y ); + update_desktop_cursor_pos( desktop, 0, x, y ); return; } @@ -1691,11 +1704,8 @@ static void update_desktop_key_state( struct desktop *desktop, unsigned int msg, } /* update the desktop key state according to a mouse message flags */ -static void update_desktop_mouse_state( struct desktop *desktop, unsigned int flags, - int x, int y, lparam_t wparam ) +static void update_desktop_mouse_state( struct desktop *desktop, unsigned int flags, lparam_t wparam ) { - if (flags & MOUSEEVENTF_MOVE) - update_desktop_cursor_pos( desktop, x, y ); if (flags & MOUSEEVENTF_LEFTDOWN) update_desktop_key_state( desktop, WM_LBUTTONDOWN, wparam ); if (flags & MOUSEEVENTF_LEFTUP) @@ -1867,12 +1877,12 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg if (IS_POINTER_PRIMARY_WPARAM( msg_data->rawinput.mouse.data )) { prepend_cursor_history( msg->x, msg->y, msg->time, msg_data->info ); - if (update_desktop_cursor_pos( desktop, msg->x, msg->y )) always_queue = 1; + if (update_desktop_cursor_pos( desktop, msg->win, msg->x, msg->y )) always_queue = 1; } break; case QS_MOUSEMOVE: prepend_cursor_history( msg->x, msg->y, msg->time, msg_data->info ); - if (update_desktop_cursor_pos( desktop, msg->x, msg->y )) always_queue = 1; + if (update_desktop_cursor_pos( desktop, msg->win, msg->x, msg->y )) always_queue = 1; /* fallthrough */ case QS_MOUSEBUTTON: if (desktop->shared->keystate[VK_LBUTTON] & 0x80) msg->wparam |= MK_LBUTTON; @@ -1903,9 +1913,6 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg } input = thread->queue->input; - if (win != desktop->cursor_win) always_queue = 1; - desktop->cursor_win = win; - if (!always_queue || merge_message( input, msg )) free_message( msg ); else { @@ -2082,7 +2089,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons if ((input->mouse.info & 0xffffff00) == 0xff515700) source.origin = IMDT_TOUCH; - update_desktop_cursor_pos( desktop, desktop->shared->cursor.x, desktop->shared->cursor.y ); /* Update last change time */ + update_desktop_cursor_pos( desktop, desktop->cursor_win, desktop->shared->cursor.x, desktop->shared->cursor.y ); /* Update last change time */ flags = input->mouse.flags; time = input->mouse.time; if (!time) time = desktop->shared->cursor.last_change; @@ -2133,7 +2140,8 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons if ((device = current->process->rawinput_mouse) && (device->flags & RIDEV_NOLEGACY)) { - update_desktop_mouse_state( desktop, flags, x, y, input->mouse.data << 16 ); + if (flags & MOUSEEVENTF_MOVE) update_desktop_cursor_pos( desktop, win, x, y ); + update_desktop_mouse_state( desktop, flags, input->mouse.data << 16 ); return 0; } From 49f0fbb0b1d567fbc2cb489f7ac1ba824a18b644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 13 Jun 2023 23:06:52 +0200 Subject: [PATCH 2110/2777] server: Keep track of the current desktop cursor handle. (cherry picked from commit b04ef1993054a5e8dc3413beadf10150457a7b39) --- server/queue.c | 11 +++++++++++ server/user.h | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/server/queue.c b/server/queue.c index 15c01e2e77e..c9dd06be23a 100644 --- a/server/queue.c +++ b/server/queue.c @@ -520,6 +520,11 @@ static int update_desktop_cursor_pos( struct desktop *desktop, user_handle_t win return updated; } +static void update_desktop_cursor_handle( struct desktop *desktop, user_handle_t handle ) +{ + desktop->cursor_handle = handle; +} + /* set the cursor position and queue the corresponding mouse message */ static void set_cursor_pos( struct desktop *desktop, int x, int y ) { @@ -3776,6 +3781,12 @@ DECL_HANDLER(set_cursor) if (req->flags & SET_CURSOR_CLIP) set_clip_rectangle( desktop, &req->clip, 0 ); if (req->flags & SET_CURSOR_NOCLIP) set_clip_rectangle( desktop, NULL, 0 ); + if (req->flags & (SET_CURSOR_HANDLE | SET_CURSOR_COUNT)) + { + if (input->shared->cursor_count < 0) update_desktop_cursor_handle( desktop, 0 ); + else update_desktop_cursor_handle( desktop, input->shared->cursor ); + } + reply->new_x = desktop->shared->cursor.x; reply->new_y = desktop->shared->cursor.y; reply->new_clip = desktop->shared->cursor.clip; diff --git a/server/user.h b/server/user.h index 4f6dc4755d5..347e84e10bc 100644 --- a/server/user.h +++ b/server/user.h @@ -67,7 +67,8 @@ struct desktop struct list touches; /* list of active touches */ struct thread_input *foreground_input; /* thread input of foreground thread */ unsigned int users; /* processes and threads using this desktop */ - user_handle_t cursor_win; /* window that contains the cursor */ + user_handle_t cursor_win; /* window that contains the cursor */ + user_handle_t cursor_handle; /* last set cursor handle */ struct object *shared_mapping; /* desktop shared memory mapping */ volatile struct desktop_shared_memory *shared; /* desktop shared memory ptr */ unsigned int last_press_alt:1; /* last key press was Alt (used to determine msg on Alt release) */ From 5aaca49a7c7086c617c627bcaa1c0a8fa1eb6779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 16 Jun 2023 10:38:46 +0200 Subject: [PATCH 2111/2777] server: Introduce and send new WM_WINE_SETCURSOR hardware message. (cherry picked from commit 25906eedd8679fdb474976563f4a05a92e11bbd6) --- dlls/win32u/cursoricon.c | 6 ++++ dlls/win32u/message.c | 5 +++ dlls/win32u/win32u_private.h | 1 + include/ntuser.h | 1 + server/queue.c | 69 ++++++++++++++++++++++++------------ 5 files changed, 60 insertions(+), 22 deletions(-) diff --git a/dlls/win32u/cursoricon.c b/dlls/win32u/cursoricon.c index bfcb805901c..b09ee74f793 100644 --- a/dlls/win32u/cursoricon.c +++ b/dlls/win32u/cursoricon.c @@ -74,6 +74,12 @@ static struct cursoricon_object *get_icon_ptr( HICON handle ) return obj; } +BOOL process_wine_setcursor( HWND hwnd, HWND window, HCURSOR handle ) +{ + TRACE( "hwnd %p, window %p, hcursor %p\n", hwnd, window, handle ); + return TRUE; +} + /*********************************************************************** * NtUserShowCursor (win32u.@) */ diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 9abdcf890a3..eb700321708 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1289,6 +1289,9 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR case WM_WINE_CLIPCURSOR: if (wparam && lparam) return clip_fullscreen_window( hwnd, FALSE ); return process_wine_clipcursor( hwnd, wparam, lparam ); + case WM_WINE_SETCURSOR: + FIXME( "Unexpected non-hardware WM_WINE_SETCURSOR message\n" ); + return FALSE; case WM_WINE_UPDATEWINDOWSTATE: update_window_state( hwnd ); return 0; @@ -1870,6 +1873,8 @@ static BOOL process_hardware_message( MSG *msg, UINT hw_id, const struct hardwar ret = process_mouse_message( msg, hw_id, msg_data->info, hwnd_filter, first, last, remove ); else if (msg->message == WM_WINE_CLIPCURSOR) process_wine_clipcursor( msg->hwnd, msg->wParam, msg->lParam ); + else if (msg->message == WM_WINE_SETCURSOR) + process_wine_setcursor( msg->hwnd, (HWND)msg->wParam, (HCURSOR)msg->lParam ); else ERR( "unknown message type %x\n", msg->message ); SetThreadDpiAwarenessContext( context ); diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index c78d039d91f..784bb9778ae 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -215,6 +215,7 @@ extern UINT enum_clipboard_formats( UINT format ) DECLSPEC_HIDDEN; extern void release_clipboard_owner( HWND hwnd ) DECLSPEC_HIDDEN; /* cursoricon.c */ +extern BOOL process_wine_setcursor( HWND hwnd, HWND window, HCURSOR handle ) DECLSPEC_HIDDEN; extern HICON alloc_cursoricon_handle( BOOL is_icon ) DECLSPEC_HIDDEN; extern ULONG_PTR get_icon_param( HICON handle ) DECLSPEC_HIDDEN; extern ULONG_PTR set_icon_param( HICON handle, ULONG_PTR param ) DECLSPEC_HIDDEN; diff --git a/include/ntuser.h b/include/ntuser.h index 1e2b47e627d..5ba3ae1dfd2 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -483,6 +483,7 @@ enum wine_internal_message WM_WINE_KEYBOARD_LL_HOOK, WM_WINE_MOUSE_LL_HOOK, WM_WINE_CLIPCURSOR, + WM_WINE_SETCURSOR, WM_WINE_UPDATEWINDOWSTATE, WM_WINE_FIRST_DRIVER_MSG = 0x80001000, /* range of messages reserved for the USER driver */ WM_WINE_LAST_DRIVER_MSG = 0x80001fff diff --git a/server/queue.c b/server/queue.c index c9dd06be23a..0a7b5fa70aa 100644 --- a/server/queue.c +++ b/server/queue.c @@ -489,10 +489,42 @@ static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_sour return msg; } +static int is_cursor_clipped( struct desktop *desktop ) +{ + rectangle_t top_rect, clip_rect = desktop->shared->cursor.clip; + get_top_window_rectangle( desktop, &top_rect ); + return !is_rect_equal( &clip_rect, &top_rect ); +} + +static void queue_cursor_message( struct desktop *desktop, user_handle_t win, unsigned int message, + lparam_t wparam, lparam_t lparam ) +{ + static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM }; + struct thread_input *input; + struct message *msg; + + if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return; + + msg->msg = message; + msg->wparam = wparam; + msg->lparam = lparam; + msg->x = desktop->shared->cursor.x; + msg->y = desktop->shared->cursor.y; + if (!(msg->win = win) && (input = desktop->foreground_input)) msg->win = input->shared->active; + queue_hardware_message( desktop, msg, 1 ); +} + static int update_desktop_cursor_window( struct desktop *desktop, user_handle_t win ) { int updated = win != desktop->cursor_win; + user_handle_t handle = desktop->cursor_handle; desktop->cursor_win = win; + if (updated) + { + /* when clipping send the message to the foreground window as well, as some driver have an artificial overlay window */ + if (is_cursor_clipped( desktop )) queue_cursor_message( desktop, 0, WM_WINE_SETCURSOR, win, handle ); + queue_cursor_message( desktop, win, WM_WINE_SETCURSOR, win, handle ); + } return updated; } @@ -522,7 +554,15 @@ static int update_desktop_cursor_pos( struct desktop *desktop, user_handle_t win static void update_desktop_cursor_handle( struct desktop *desktop, user_handle_t handle ) { + int updated = desktop->cursor_handle != handle; + user_handle_t win = desktop->cursor_win; desktop->cursor_handle = handle; + if (updated) + { + /* when clipping send the message to the foreground window as well, as some driver have an artificial overlay window */ + if (is_cursor_clipped( desktop )) queue_cursor_message( desktop, 0, WM_WINE_SETCURSOR, win, handle ); + queue_cursor_message( desktop, win, WM_WINE_SETCURSOR, win, handle ); + } } /* set the cursor position and queue the corresponding mouse message */ @@ -556,23 +596,6 @@ static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsig *time = get_tick_count(); } -static void queue_clip_cursor_msg( struct desktop *desktop, lparam_t wparam, lparam_t lparam ) -{ - static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM }; - struct thread_input *input; - struct message *msg; - - if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return; - - msg->msg = WM_WINE_CLIPCURSOR; - msg->wparam = wparam; - msg->lparam = lparam; - msg->x = desktop->shared->cursor.x; - msg->y = desktop->shared->cursor.y; - if ((input = desktop->foreground_input)) msg->win = input->shared->active; - queue_hardware_message( desktop, msg, 1 ); -} - /* set the cursor clip rectangle */ void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int reset ) { @@ -604,7 +627,7 @@ void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int r if (reset) post_desktop_message( desktop, WM_WINE_CLIPCURSOR, TRUE, FALSE ); /* notify foreground thread, of reset, or to apply new cursor clipping rect */ - queue_clip_cursor_msg( desktop, rect == NULL, reset ); + queue_cursor_message( desktop, 0, WM_WINE_CLIPCURSOR, rect == NULL, reset ); } /* change the foreground input and reset the cursor clip rect */ @@ -712,6 +735,7 @@ static inline int get_hardware_msg_bit( unsigned int message ) if (message == WM_POINTERDOWN || message == WM_POINTERUP || message == WM_POINTERUPDATE) return QS_POINTER; if (message == WM_WINE_CLIPCURSOR) return QS_RAWINPUT; + if (message == WM_WINE_SETCURSOR) return QS_RAWINPUT; return QS_MOUSEBUTTON; } @@ -794,13 +818,13 @@ static int merge_mousemove( struct thread_input *input, const struct message *ms return 1; } -/* try to merge a WM_WINE_CLIPCURSOR message with the last in the list; return 1 if successful */ -static int merge_wine_clipcursor( struct thread_input *input, const struct message *msg ) +/* try to merge a unique message with the last in the list; return 1 if successful */ +static int merge_unique_message( struct thread_input *input, unsigned int message, const struct message *msg ) { struct message *prev; LIST_FOR_EACH_ENTRY_REV( prev, &input->msg_list, struct message, entry ) - if (prev->msg == WM_WINE_CLIPCURSOR) break; + if (prev->msg == message) break; if (&prev->entry == &input->msg_list) return 0; if (prev->result) return 0; @@ -824,7 +848,8 @@ static int merge_message( struct thread_input *input, const struct message *msg { if (msg->msg == WM_POINTERUPDATE) return merge_pointer_update_message( input, msg ); if (msg->msg == WM_MOUSEMOVE) return merge_mousemove( input, msg ); - if (msg->msg == WM_WINE_CLIPCURSOR) return merge_wine_clipcursor( input, msg ); + if (msg->msg == WM_WINE_CLIPCURSOR) return merge_unique_message( input, WM_WINE_CLIPCURSOR, msg ); + if (msg->msg == WM_WINE_SETCURSOR) return merge_unique_message( input, WM_WINE_SETCURSOR, msg ); return 0; } From 2a84b18ed09b81628959ad7507bf4044d9b7d0ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Jan 2023 11:09:30 +0100 Subject: [PATCH 2112/2777] win32u: Add a hwnd parameter to SetCursor driver entry points. (cherry picked from commit 3afff1a690b17bd3cf3685c5538f542a4afc0d48) --- dlls/win32u/cursoricon.c | 6 +++--- dlls/win32u/driver.c | 6 +++--- dlls/wineandroid.drv/android.h | 3 +-- dlls/wineandroid.drv/window.c | 2 +- dlls/winemac.drv/macdrv.h | 2 +- dlls/winemac.drv/mouse.c | 4 ++-- dlls/winex11.drv/mouse.c | 2 +- dlls/winex11.drv/x11drv.h | 2 +- include/wine/gdi_driver.h | 2 +- 9 files changed, 14 insertions(+), 15 deletions(-) diff --git a/dlls/win32u/cursoricon.c b/dlls/win32u/cursoricon.c index b09ee74f793..6045852459b 100644 --- a/dlls/win32u/cursoricon.c +++ b/dlls/win32u/cursoricon.c @@ -101,8 +101,8 @@ INT WINAPI NtUserShowCursor( BOOL show ) TRACE("%d, count=%d\n", show, count ); - if (show && !count) user_driver->pSetCursor( cursor ); - else if (!show && count == -1) user_driver->pSetCursor( 0 ); + if (show && !count) user_driver->pSetCursor( 0, cursor ); + else if (!show && count == -1) user_driver->pSetCursor( 0, 0 ); return count; } @@ -132,7 +132,7 @@ HCURSOR WINAPI NtUserSetCursor( HCURSOR cursor ) SERVER_END_REQ; if (!ret) return 0; - user_driver->pSetCursor( show_count >= 0 ? cursor : 0 ); + user_driver->pSetCursor( 0, show_count >= 0 ? cursor : 0 ); if (!(obj = get_icon_ptr( old_cursor ))) return 0; release_user_handle_ptr( obj ); diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 3a96b45d03f..2a1da075dd4 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -739,7 +739,7 @@ static void nulldrv_DestroyCursorIcon( HCURSOR cursor ) { } -static void nulldrv_SetCursor( HCURSOR cursor ) +static void nulldrv_SetCursor( HWND hwnd, HCURSOR cursor ) { } @@ -1119,9 +1119,9 @@ static INT loaderdrv_GetDisplayDepth( LPCWSTR name, BOOL is_primary ) return load_driver()->pGetDisplayDepth( name, is_primary ); } -static void loaderdrv_SetCursor( HCURSOR cursor ) +static void loaderdrv_SetCursor( HWND hwnd, HCURSOR cursor ) { - load_driver()->pSetCursor( cursor ); + load_driver()->pSetCursor( hwnd, cursor ); } static BOOL loaderdrv_GetCursorPos( POINT *pt ) diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h index d12cfa28f04..2eb6a288a72 100644 --- a/dlls/wineandroid.drv/android.h +++ b/dlls/wineandroid.drv/android.h @@ -86,13 +86,12 @@ extern pthread_mutex_t win_data_mutex DECLSPEC_HIDDEN; extern INT ANDROID_GetKeyNameText( LONG lparam, LPWSTR buffer, INT size ) DECLSPEC_HIDDEN; extern UINT ANDROID_MapVirtualKeyEx( UINT code, UINT maptype, HKL hkl ) DECLSPEC_HIDDEN; extern SHORT ANDROID_VkKeyScanEx( WCHAR ch, HKL hkl ) DECLSPEC_HIDDEN; -extern void ANDROID_SetCursor( HCURSOR handle ) DECLSPEC_HIDDEN; +extern void ANDROID_SetCursor( HWND hwnd, HCURSOR handle ) DECLSPEC_HIDDEN; extern BOOL ANDROID_CreateDesktop( const WCHAR *name, UINT width, UINT height ) DECLSPEC_HIDDEN; extern BOOL ANDROID_CreateWindow( HWND hwnd ) DECLSPEC_HIDDEN; extern void ANDROID_DestroyWindow( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL ANDROID_ProcessEvents( DWORD mask ) DECLSPEC_HIDDEN; extern LRESULT ANDROID_DesktopWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) DECLSPEC_HIDDEN; -extern void ANDROID_SetCursor( HCURSOR handle ) DECLSPEC_HIDDEN; extern void ANDROID_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags ) DECLSPEC_HIDDEN; extern void ANDROID_SetParent( HWND hwnd, HWND parent, HWND old_parent ) DECLSPEC_HIDDEN; diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index 905f4672580..d3e1693c82e 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -1447,7 +1447,7 @@ static BOOL get_icon_info( HICON handle, ICONINFOEXW *ret ) /*********************************************************************** * ANDROID_SetCursor */ -void ANDROID_SetCursor( HCURSOR handle ) +void ANDROID_SetCursor( HWND hwnd, HCURSOR handle ) { static HCURSOR last_cursor; static DWORD last_cursor_change; diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 39cb31bfdca..a1919596b74 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -159,7 +159,7 @@ extern void macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags extern void macdrv_DestroyCursorIcon(HCURSOR cursor) DECLSPEC_HIDDEN; extern BOOL macdrv_GetCursorPos(LPPOINT pos) DECLSPEC_HIDDEN; extern void macdrv_SetCapture(HWND hwnd, UINT flags) DECLSPEC_HIDDEN; -extern void macdrv_SetCursor(HCURSOR cursor) DECLSPEC_HIDDEN; +extern void macdrv_SetCursor(HWND hwnd, HCURSOR cursor) DECLSPEC_HIDDEN; extern BOOL macdrv_SetCursorPos(INT x, INT y) DECLSPEC_HIDDEN; extern BOOL macdrv_RegisterHotKey(HWND hwnd, UINT mod_flags, UINT vkey) DECLSPEC_HIDDEN; extern void macdrv_UnregisterHotKey(HWND hwnd, UINT modifiers, UINT vkey) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/mouse.c b/dlls/winemac.drv/mouse.c index 9dfd1801fc9..260831c44dc 100644 --- a/dlls/winemac.drv/mouse.c +++ b/dlls/winemac.drv/mouse.c @@ -745,12 +745,12 @@ static BOOL get_icon_info(HICON handle, ICONINFOEXW *ret) /*********************************************************************** * SetCursor (MACDRV.@) */ -void macdrv_SetCursor(HCURSOR cursor) +void macdrv_SetCursor(HWND hwnd, HCURSOR cursor) { CFStringRef cursor_name = NULL; CFArrayRef cursor_frames = NULL; - TRACE("%p\n", cursor); + TRACE("%p %p\n", hwnd, cursor); if (cursor) { diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 1993e973d24..2e9df02af86 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1482,7 +1482,7 @@ void X11DRV_DestroyCursorIcon( HCURSOR handle ) /*********************************************************************** * SetCursor (X11DRV.@) */ -void X11DRV_SetCursor( HCURSOR handle ) +void X11DRV_SetCursor( HWND hwnd, HCURSOR handle ) { if (InterlockedExchangePointer( (void **)&last_cursor, handle ) != handle || NtGetTickCount() - last_cursor_change > 100) diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 663f510965d..393bf5df17f 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -215,7 +215,7 @@ extern UINT X11DRV_ImeToAsciiEx( UINT vkey, UINT vsc, const BYTE *state, extern SHORT X11DRV_VkKeyScanEx( WCHAR wChar, HKL hkl ) DECLSPEC_HIDDEN; extern void X11DRV_NotifyIMEStatus( HWND hwnd, UINT status ) DECLSPEC_HIDDEN; extern void X11DRV_DestroyCursorIcon( HCURSOR handle ) DECLSPEC_HIDDEN; -extern void X11DRV_SetCursor( HCURSOR handle ) DECLSPEC_HIDDEN; +extern void X11DRV_SetCursor( HWND hwnd, HCURSOR handle ) DECLSPEC_HIDDEN; extern BOOL X11DRV_SetCursorPos( INT x, INT y ) DECLSPEC_HIDDEN; extern BOOL X11DRV_GetCursorPos( LPPOINT pos ) DECLSPEC_HIDDEN; extern BOOL X11DRV_ClipCursor( const RECT *clip, BOOL reset ) DECLSPEC_HIDDEN; diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index dd7d3eed2ad..60c3779727b 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -293,7 +293,7 @@ struct user_driver_funcs void (*pNotifyIMEStatus)(HWND,UINT); /* cursor/icon functions */ void (*pDestroyCursorIcon)(HCURSOR); - void (*pSetCursor)(HCURSOR); + void (*pSetCursor)(HWND,HCURSOR); BOOL (*pGetCursorPos)(LPPOINT); BOOL (*pSetCursorPos)(INT,INT); BOOL (*pClipCursor)(const RECT*,BOOL); From 47a636df29f30ddcc0912248950fc83fe27ebe77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Jan 2023 11:52:44 +0100 Subject: [PATCH 2113/2777] win32u: Notify drivers of cursor changes on WM_WINE_SETCURSOR. (cherry picked from commit 4b968267c1169c5437e9fc5d8ec5d4fd24491436) --- dlls/win32u/cursoricon.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/dlls/win32u/cursoricon.c b/dlls/win32u/cursoricon.c index 6045852459b..fa51788dce9 100644 --- a/dlls/win32u/cursoricon.c +++ b/dlls/win32u/cursoricon.c @@ -77,6 +77,7 @@ static struct cursoricon_object *get_icon_ptr( HICON handle ) BOOL process_wine_setcursor( HWND hwnd, HWND window, HCURSOR handle ) { TRACE( "hwnd %p, window %p, hcursor %p\n", hwnd, window, handle ); + user_driver->pSetCursor( window, handle ); return TRUE; } @@ -85,7 +86,6 @@ BOOL process_wine_setcursor( HWND hwnd, HWND window, HCURSOR handle ) */ INT WINAPI NtUserShowCursor( BOOL show ) { - HCURSOR cursor; int increment = show ? 1 : -1; int count; @@ -94,16 +94,11 @@ INT WINAPI NtUserShowCursor( BOOL show ) req->flags = SET_CURSOR_COUNT; req->show_count = increment; wine_server_call( req ); - cursor = wine_server_ptr_handle( reply->prev_handle ); count = reply->prev_count + increment; } SERVER_END_REQ; TRACE("%d, count=%d\n", show, count ); - - if (show && !count) user_driver->pSetCursor( 0, cursor ); - else if (!show && count == -1) user_driver->pSetCursor( 0, 0 ); - return count; } @@ -114,7 +109,6 @@ HCURSOR WINAPI NtUserSetCursor( HCURSOR cursor ) { struct cursoricon_object *obj; HCURSOR old_cursor; - int show_count; BOOL ret; TRACE( "%p\n", cursor ); @@ -124,16 +118,11 @@ HCURSOR WINAPI NtUserSetCursor( HCURSOR cursor ) req->flags = SET_CURSOR_HANDLE; req->handle = wine_server_user_handle( cursor ); if ((ret = !wine_server_call_err( req ))) - { old_cursor = wine_server_ptr_handle( reply->prev_handle ); - show_count = reply->prev_count; - } } SERVER_END_REQ; if (!ret) return 0; - user_driver->pSetCursor( 0, show_count >= 0 ? cursor : 0 ); - if (!(obj = get_icon_ptr( old_cursor ))) return 0; release_user_handle_ptr( obj ); return old_cursor; From 59c9d7a03cc5c0cad60b4d0e32979bc85e0b5392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Jan 2023 12:30:04 +0100 Subject: [PATCH 2114/2777] wineandroid: Set the window cursor immediately in SetCursor. (cherry picked from commit b17b77c707cd3467fd2d00b6634d92868a1be57f) --- dlls/wineandroid.drv/window.c | 47 ++++++++++++++--------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c index d3e1693c82e..74ab61b9a4f 100644 --- a/dlls/wineandroid.drv/window.c +++ b/dlls/wineandroid.drv/window.c @@ -1449,42 +1449,33 @@ static BOOL get_icon_info( HICON handle, ICONINFOEXW *ret ) */ void ANDROID_SetCursor( HWND hwnd, HCURSOR handle ) { - static HCURSOR last_cursor; - static DWORD last_cursor_change; - - if (InterlockedExchangePointer( (void **)&last_cursor, handle ) != handle || - NtGetTickCount() - last_cursor_change > 100) + if (handle) { - last_cursor_change = NtGetTickCount(); + unsigned int width = 0, height = 0, *bits = NULL; + ICONINFOEXW info; + int id; - if (handle) - { - unsigned int width = 0, height = 0, *bits = NULL; - ICONINFOEXW info; - int id; + if (!get_icon_info( handle, &info )) return; - if (!get_icon_info( handle, &info )) return; + if (!(id = get_cursor_system_id( &info ))) + { + HDC hdc = NtGdiCreateCompatibleDC( 0 ); + bits = get_bitmap_argb( hdc, info.hbmColor, info.hbmMask, &width, &height ); + NtGdiDeleteObjectApp( hdc ); - if (!(id = get_cursor_system_id( &info ))) + /* make sure hotspot is valid */ + if (info.xHotspot >= width || info.yHotspot >= height) { - HDC hdc = NtGdiCreateCompatibleDC( 0 ); - bits = get_bitmap_argb( hdc, info.hbmColor, info.hbmMask, &width, &height ); - NtGdiDeleteObjectApp( hdc ); - - /* make sure hotspot is valid */ - if (info.xHotspot >= width || info.yHotspot >= height) - { - info.xHotspot = width / 2; - info.yHotspot = height / 2; - } + info.xHotspot = width / 2; + info.yHotspot = height / 2; } - ioctl_set_cursor( id, width, height, info.xHotspot, info.yHotspot, bits ); - free( bits ); - NtGdiDeleteObjectApp( info.hbmColor ); - NtGdiDeleteObjectApp( info.hbmMask ); } - else ioctl_set_cursor( 0, 0, 0, 0, 0, NULL ); + ioctl_set_cursor( id, width, height, info.xHotspot, info.yHotspot, bits ); + free( bits ); + NtGdiDeleteObjectApp( info.hbmColor ); + NtGdiDeleteObjectApp( info.hbmMask ); } + else ioctl_set_cursor( 0, 0, 0, 0, 0, NULL ); } From 42cda654d5d7a3527ea510f9f19f2b2eb0f38f7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 13 Jun 2023 23:09:55 +0200 Subject: [PATCH 2115/2777] winex11: Set the window cursor immediately in SetCursor. Instead of synchronizing the cursor on mouse changes. The SetCursor call should now only be made when cursor or window handle have changed. (cherry picked from commit 9f8d9eef216d4ede3b53d3caab222ad8f896f10b) --- dlls/winex11.drv/mouse.c | 61 ++++++++++++--------------------------- dlls/winex11.drv/window.c | 23 --------------- dlls/winex11.drv/x11drv.h | 2 -- 3 files changed, 19 insertions(+), 67 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 2e9df02af86..8227a7be56f 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -126,9 +126,6 @@ static const UINT button_up_data[NB_BUTTONS] = XContext cursor_context = 0; -static HWND cursor_window; -static HCURSOR last_cursor; -static DWORD last_cursor_change; static RECT last_clip_rect; static HWND last_clip_foreground_window; static BOOL last_clip_refused; @@ -242,24 +239,6 @@ void set_window_cursor( Window window, HCURSOR handle ) XFlush( gdi_display ); } -/*********************************************************************** - * sync_window_cursor - */ -void sync_window_cursor( Window window ) -{ - HCURSOR cursor; - - SERVER_START_REQ( set_cursor ) - { - req->flags = 0; - wine_server_call( req ); - cursor = reply->prev_count >= 0 ? wine_server_ptr_handle( reply->prev_handle ) : 0; - } - SERVER_END_REQ; - - set_window_cursor( window, cursor ); -} - struct mouse_button_mapping { int deviceid; @@ -444,6 +423,7 @@ static BOOL grab_clipping_window( const RECT *clip ) UNICODE_STRING class_name = RTL_CONSTANT_STRING( messageW ); Window clip_window; HWND msg_hwnd = 0; + HCURSOR cursor; POINT pos; RECT real_clip; @@ -504,6 +484,17 @@ static BOOL grab_clipping_window( const RECT *clip ) GrabModeAsync, GrabModeAsync, clip_window, None, CurrentTime )) clipping_cursor = TRUE; + SERVER_START_REQ( set_cursor ) + { + req->flags = 0; + wine_server_call( req ); + if (reply->prev_count < 0) cursor = 0; + else cursor = wine_server_ptr_handle( reply->prev_handle ); + } + SERVER_END_REQ; + + set_window_cursor( clip_window, cursor ); + if (!clipping_cursor) { X11DRV_XInput2_Enable( data->display, None, 0 ); @@ -511,8 +502,6 @@ static BOOL grab_clipping_window( const RECT *clip ) return FALSE; } clip_rect = *clip; - if (!data->clip_hwnd) sync_window_cursor( clip_window ); - InterlockedExchangePointer( (void **)&cursor_window, msg_hwnd ); data->clip_hwnd = msg_hwnd; return TRUE; #else @@ -634,7 +623,6 @@ static void map_event_coords( HWND hwnd, Window window, Window event_root, int x static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPUT *input ) { struct x11drv_win_data *data; - Window win = 0; input->type = INPUT_MOUSE; @@ -645,25 +633,12 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU if (!clip_hwnd) return; if (thread_data->clip_window != window) return; - if (InterlockedExchangePointer( (void **)&cursor_window, clip_hwnd ) != clip_hwnd || - input->u.mi.time - last_cursor_change > 100) - { - sync_window_cursor( window ); - last_cursor_change = input->u.mi.time; - } __wine_send_input( hwnd, input, NULL ); return; } if (!(data = get_win_data( hwnd ))) return; - win = data->whole_window; release_win_data( data ); - if (InterlockedExchangePointer( (void **)&cursor_window, hwnd ) != hwnd || - input->u.mi.time - last_cursor_change > 100) - { - sync_window_cursor( win ); - last_cursor_change = input->u.mi.time; - } /* update the wine server Z-order */ @@ -1484,13 +1459,15 @@ void X11DRV_DestroyCursorIcon( HCURSOR handle ) */ void X11DRV_SetCursor( HWND hwnd, HCURSOR handle ) { - if (InterlockedExchangePointer( (void **)&last_cursor, handle ) != handle || - NtGetTickCount() - last_cursor_change > 100) + struct x11drv_win_data *data; + + if ((data = get_win_data( hwnd ))) { - last_cursor_change = NtGetTickCount(); - if (cursor_window) send_notify_message( cursor_window, WM_X11DRV_SET_CURSOR, - GetCurrentThreadId(), (LPARAM)handle ); + set_window_cursor( data->whole_window, handle ); + release_win_data( data ); } + + if (clipping_cursor) set_window_cursor( x11drv_thread_data()->clip_window, handle ); } /*********************************************************************** diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 1408f1c1ab2..4121b558ca9 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2079,8 +2079,6 @@ static void create_whole_window( struct x11drv_win_data *data ) XFlush( data->display ); /* make sure the window exists before we start painting to it */ - sync_window_cursor( data->whole_window ); - done: if (win_rgn) NtGdiDeleteObjectApp( win_rgn ); } @@ -3711,27 +3709,6 @@ LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) release_win_data( data ); } return 0; - case WM_X11DRV_SET_CURSOR: - { - Window win = 0; - - if ((data = get_win_data( hwnd ))) - { - win = data->whole_window; - release_win_data( data ); - } - else if (hwnd == x11drv_thread_data()->clip_hwnd) - win = x11drv_thread_data()->clip_window; - - if (win) - { - if (wp == GetCurrentThreadId()) - set_window_cursor( win, (HCURSOR)lp ); - else - sync_window_cursor( win ); - } - return 0; - } case WM_X11DRV_DELETE_TAB: taskbar_delete_tab( hwnd ); return 0; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 393bf5df17f..3f572343357 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -606,7 +606,6 @@ enum x11drv_window_messages WM_X11DRV_UPDATE_CLIPBOARD = 0x80001000, WM_X11DRV_SET_WIN_REGION, WM_X11DRV_DESKTOP_RESIZED, - WM_X11DRV_SET_CURSOR, WM_X11DRV_DELETE_TAB, WM_X11DRV_ADD_TAB }; @@ -733,7 +732,6 @@ extern XContext cursor_context DECLSPEC_HIDDEN; extern void X11DRV_SetFocus( HWND hwnd ) DECLSPEC_HIDDEN; extern void set_window_cursor( Window window, HCURSOR handle ) DECLSPEC_HIDDEN; -extern void sync_window_cursor( Window window ) DECLSPEC_HIDDEN; extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN; extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN; extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN; From 1b1962296714a34aab1d9d7bd8d173304d4bc02c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 14 Jun 2023 19:25:40 +0200 Subject: [PATCH 2116/2777] server: Update the DF_WINE_CREATE_DESKTOP desktop flag on opening. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55047 (cherry picked from commit f4cb3230d84042075961b95178d3e1ac4bc49271) --- server/winstation.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/winstation.c b/server/winstation.c index 9e5d3871a6f..d9617b5509e 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -30,6 +30,7 @@ #include "winbase.h" #include "winuser.h" #include "winternl.h" +#include "ntuser.h" #include "object.h" #include "handle.h" @@ -271,7 +272,11 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned return NULL; } } - else clear_error(); + else + { + desktop->flags |= (flags & DF_WINE_CREATE_DESKTOP); + clear_error(); + } } return desktop; } From 820543f39bc753aa36f796a9a4caf5ad9f3e930d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 14 Jun 2023 19:27:59 +0200 Subject: [PATCH 2117/2777] win32u: NtUserGetObjectInformation returns a BOOL, not NTSTATUS. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55047 (cherry picked from commit b3c1bd33e0c913def8f214baf7875f2ef8a46e6e) --- dlls/win32u/winstation.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index f0190d2335e..9ddc67fcf8f 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -44,12 +44,9 @@ BOOL is_virtual_desktop(void) { HANDLE desktop = NtUserGetThreadDesktop( GetCurrentThreadId() ); USEROBJECTFLAGS flags = {0}; - NTSTATUS status; DWORD len; - status = NtUserGetObjectInformation( desktop, UOI_FLAGS, &flags, sizeof(flags), &len ); - if (status) return FALSE; - + if (!NtUserGetObjectInformation( desktop, UOI_FLAGS, &flags, sizeof(flags), &len )) return FALSE; return !!(flags.dwFlags & DF_WINE_CREATE_DESKTOP); } From 8fa77ae791dd581fa9383a9f2c241fb4c4f184a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Jun 2023 09:34:53 +0200 Subject: [PATCH 2118/2777] winex11: Don't grab the cursor if another process is focused. This might be the case when in virtual desktop mode for instance, where we don't change Wine foreground window when the virtual desktop is focused out. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55046 (cherry picked from commit 89415925b7a43d11317c5ffc27ef2d29c20d0970) --- dlls/winex11.drv/event.c | 24 +++++++++++++----------- dlls/winex11.drv/mouse.c | 6 ++++-- dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 45cf20aa0b2..d97dee8faf5 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -858,6 +858,18 @@ static const char * const focus_modes[] = "NotifyWhileGrabbed" }; +BOOL is_current_process_focused(void) +{ + Display *display = x11drv_thread_data()->display; + Window focus; + int revert; + HWND hwnd; + + XGetInputFocus( display, &focus, &revert ); + if (focus && !XFindContext( display, focus, winContext, (char **)&hwnd )) return TRUE; + return FALSE; +} + /********************************************************************** * X11DRV_FocusIn */ @@ -911,9 +923,6 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) */ static void focus_out( Display *display , HWND hwnd ) { - HWND hwnd_tmp; - Window focus_win; - int revert; struct x11drv_win_data *data; if (xim_in_compose_mode()) return; @@ -953,14 +962,7 @@ static void focus_out( Display *display , HWND hwnd ) /* don't reset the foreground window, if the window which is getting the focus is a Wine window */ - XGetInputFocus( display, &focus_win, &revert ); - if (focus_win) - { - if (XFindContext( display, focus_win, winContext, (char **)&hwnd_tmp ) != 0) - focus_win = 0; - } - - if (!focus_win) + if (!is_current_process_focused()) { /* Abey : 6-Oct-99. Check again if the focus out window is the Foreground window, because in most cases the messages sent diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 8227a7be56f..dd8fb02ba90 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -427,8 +427,10 @@ static BOOL grab_clipping_window( const RECT *clip ) POINT pos; RECT real_clip; - if (NtUserGetWindowThread( NtUserGetDesktopWindow(), NULL ) == GetCurrentThreadId()) - return TRUE; /* don't clip in the desktop process */ + /* don't clip in the desktop process */ + if (NtUserGetWindowThread( NtUserGetDesktopWindow(), NULL ) == GetCurrentThreadId()) return TRUE; + /* don't clip the cursor if the X input focus is on another process window */ + if (!is_current_process_focused()) return TRUE; if (!data) return FALSE; if (!(clip_window = init_clip_window())) return TRUE; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 3f572343357..83a9fe31bab 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -730,6 +730,7 @@ extern XContext winContext DECLSPEC_HIDDEN; /* X context to associate an X cursor to a Win32 cursor handle */ extern XContext cursor_context DECLSPEC_HIDDEN; +extern BOOL is_current_process_focused(void) DECLSPEC_HIDDEN; extern void X11DRV_SetFocus( HWND hwnd ) DECLSPEC_HIDDEN; extern void set_window_cursor( Window window, HCURSOR handle ) DECLSPEC_HIDDEN; extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN; From 238d9059e46b8cbd4f25c4ce1cff026f8cfb72a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Jun 2023 08:53:08 +0200 Subject: [PATCH 2119/2777] winex11: Simplify the cursor clipping retry mechanism. If the focus changes between Wine windows, the wineserver logic will decide to reset the clipping rectangle. However winex11 also needs to support the case when focus changes to a host window, in virtual desktop mode, and in this case the foreground window doesn't actually change. To fix this, in virtual desktop mode, release the cursor on focus out events, and reapply the cursor clipping rect when the virtual desktop window is focused again. We can use the same logic on NotifyGrab events, when the WM grabs the keyboard, and later reapply the Wine clipping rect when we are notified about the keyboard ungrab. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55046 (cherry picked from commit 1f90d03b7888f902d2aa6101bd60aa47766071cd) --- dlls/winex11.drv/event.c | 60 ++++++++++----------------------------- dlls/winex11.drv/mouse.c | 22 ++++---------- dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 21 insertions(+), 62 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index d97dee8faf5..374394a46aa 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -876,31 +876,23 @@ BOOL is_current_process_focused(void) static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) { XFocusChangeEvent *event = &xev->xfocus; + BOOL was_grabbed; if (!hwnd) return FALSE; TRACE( "win %p xwin %lx detail=%s mode=%s\n", hwnd, event->window, focus_details[event->detail], focus_modes[event->mode] ); if (event->detail == NotifyPointer) return FALSE; + /* when focusing in the virtual desktop window, re-apply the cursor clipping rect */ + if (is_virtual_desktop() && hwnd == NtUserGetDesktopWindow()) retry_grab_clipping_window(); if (hwnd == NtUserGetDesktopWindow()) return FALSE; - switch (event->mode) - { - case NotifyGrab: - /* these are received when moving undecorated managed windows on mutter */ - keyboard_grabbed = TRUE; - return FALSE; - case NotifyWhileGrabbed: - keyboard_grabbed = TRUE; - break; - case NotifyNormal: - keyboard_grabbed = FALSE; - break; - case NotifyUngrab: - keyboard_grabbed = FALSE; - retry_grab_clipping_window(); - return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ - } + /* when keyboard grab is released, re-apply the cursor clipping rect */ + was_grabbed = keyboard_grabbed; + keyboard_grabbed = event->mode == NotifyGrab || event->mode == NotifyWhileGrabbed; + if (was_grabbed > keyboard_grabbed) retry_grab_clipping_window(); + /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ + if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; xim_set_focus( hwnd, TRUE ); @@ -950,11 +942,7 @@ static void focus_out( Display *display , HWND hwnd ) x11drv_thread_data()->last_focus = hwnd; xim_set_focus( hwnd, FALSE ); - if (is_virtual_desktop()) - { - if (hwnd == NtUserGetDesktopWindow()) NtUserClipCursor( NULL ); - return; - } + if (is_virtual_desktop()) return; if (hwnd != NtUserGetForegroundWindow()) return; if (!(NtUserGetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)) send_message( hwnd, WM_CANCELMODE, 0, 0 ); @@ -994,29 +982,11 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) } if (!hwnd) return FALSE; - switch (event->mode) - { - case NotifyUngrab: - /* these are received when moving undecorated managed windows on mutter */ - keyboard_grabbed = FALSE; - return FALSE; - case NotifyNormal: - keyboard_grabbed = FALSE; - break; - case NotifyWhileGrabbed: - keyboard_grabbed = TRUE; - break; - case NotifyGrab: - keyboard_grabbed = TRUE; - - /* This will do nothing due to keyboard_grabbed == TRUE, but it - * will save the current clipping rect so we can restore it on - * FocusIn with NotifyUngrab mode. - */ - retry_grab_clipping_window(); - - return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ - } + /* in virtual desktop mode or when keyboard is grabbed, release any cursor grab but keep the clipping rect */ + keyboard_grabbed = event->mode == NotifyGrab || event->mode == NotifyWhileGrabbed; + if (is_virtual_desktop() || keyboard_grabbed) ungrab_clipping_window(); + /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ + if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; focus_out( event->display, hwnd ); return TRUE; diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index dd8fb02ba90..63f7655be9e 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -126,9 +126,6 @@ static const UINT button_up_data[NB_BUTTONS] = XContext cursor_context = 0; -static RECT last_clip_rect; -static HWND last_clip_foreground_window; -static BOOL last_clip_refused; static RECT clip_rect; static Cursor create_cursor( HANDLE handle ); @@ -443,15 +440,8 @@ static BOOL grab_clipping_window( const RECT *clip ) if (keyboard_grabbed) { WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) ); - last_clip_refused = TRUE; - last_clip_foreground_window = NtUserGetForegroundWindow(); - last_clip_rect = *clip; return FALSE; } - else - { - last_clip_refused = FALSE; - } /* enable XInput2 unless we are already clipping */ if (!data->clip_hwnd) X11DRV_XInput2_Enable( data->display, None, PointerMotionMask ); @@ -517,7 +507,7 @@ static BOOL grab_clipping_window( const RECT *clip ) * * Release the pointer grab on the clip window. */ -static void ungrab_clipping_window(void) +void ungrab_clipping_window(void) { struct x11drv_thread_data *data = x11drv_init_thread_data(); Window clip_window = init_clip_window(); @@ -536,15 +526,13 @@ static void ungrab_clipping_window(void) /*********************************************************************** * retry_grab_clipping_window * - * Restore the current clip rectangle or retry the last one if it has - * been refused because of an active keyboard grab. + * Restore the current clip rectangle. */ void retry_grab_clipping_window(void) { - if (clipping_cursor) - NtUserClipCursor( &clip_rect ); - else if (last_clip_refused && NtUserGetForegroundWindow() == last_clip_foreground_window) - NtUserClipCursor( &last_clip_rect ); + RECT rect; + NtUserGetClipCursor( &rect ); + NtUserClipCursor( &rect ); } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 83a9fe31bab..d9881f635c4 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -734,6 +734,7 @@ extern BOOL is_current_process_focused(void) DECLSPEC_HIDDEN; extern void X11DRV_SetFocus( HWND hwnd ) DECLSPEC_HIDDEN; extern void set_window_cursor( Window window, HCURSOR handle ) DECLSPEC_HIDDEN; extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN; +extern void ungrab_clipping_window(void) DECLSPEC_HIDDEN; extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN; extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN; extern void X11DRV_InitMouse( Display *display ) DECLSPEC_HIDDEN; From 2da5518bb0a084a54efc9e4f2d247afc426bd4b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 14 Jun 2023 00:12:03 +0200 Subject: [PATCH 2120/2777] winex11: Replace the clipping message HWND with a BOOL flag. We don't need the window anymore, it was only used to send ClipCursor notifications. This improves cursor clipping performance a lot as it avoids re-creating a window every time. (cherry picked from commit 272f712b605174e946da1dc65f927a23ee92a572) --- dlls/winex11.drv/mouse.c | 27 +++++++-------------------- dlls/winex11.drv/x11drv.h | 2 +- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 63f7655be9e..cb07e459c1c 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -415,11 +415,8 @@ void X11DRV_XInput2_Enable( Display *display, Window window, long event_mask ) static BOOL grab_clipping_window( const RECT *clip ) { #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - static const WCHAR messageW[] = {'M','e','s','s','a','g','e',0}; struct x11drv_thread_data *data = x11drv_thread_data(); - UNICODE_STRING class_name = RTL_CONSTANT_STRING( messageW ); Window clip_window; - HWND msg_hwnd = 0; HCURSOR cursor; POINT pos; RECT real_clip; @@ -432,11 +429,6 @@ static BOOL grab_clipping_window( const RECT *clip ) if (!data) return FALSE; if (!(clip_window = init_clip_window())) return TRUE; - if (!(msg_hwnd = NtUserCreateWindowEx( 0, &class_name, &class_name, NULL, 0, 0, 0, 0, 0, - HWND_MESSAGE, 0, NtCurrentTeb()->Peb->ImageBaseAddress, - NULL, 0, NULL, 0, FALSE ))) - return TRUE; - if (keyboard_grabbed) { WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) ); @@ -444,11 +436,11 @@ static BOOL grab_clipping_window( const RECT *clip ) } /* enable XInput2 unless we are already clipping */ - if (!data->clip_hwnd) X11DRV_XInput2_Enable( data->display, None, PointerMotionMask ); + if (!data->clipping_cursor) X11DRV_XInput2_Enable( data->display, None, PointerMotionMask ); TRACE( "clipping to %s win %lx\n", wine_dbgstr_rect(clip), clip_window ); - if (!data->clip_hwnd) XUnmapWindow( data->display, clip_window ); + if (!data->clipping_cursor) XUnmapWindow( data->display, clip_window ); TRACE( "user clip rect %s\n", wine_dbgstr_rect( clip ) ); @@ -467,7 +459,7 @@ static BOOL grab_clipping_window( const RECT *clip ) XMapWindow( data->display, clip_window ); /* if the rectangle is shrinking we may get a pointer warp */ - if (!data->clip_hwnd || clip->left > clip_rect.left || clip->top > clip_rect.top || + if (!data->clipping_cursor || clip->left > clip_rect.left || clip->top > clip_rect.top || clip->right < clip_rect.right || clip->bottom < clip_rect.bottom) data->warp_serial = NextRequest( data->display ); @@ -490,11 +482,10 @@ static BOOL grab_clipping_window( const RECT *clip ) if (!clipping_cursor) { X11DRV_XInput2_Enable( data->display, None, 0 ); - NtUserDestroyWindow( msg_hwnd ); return FALSE; } clip_rect = *clip; - data->clip_hwnd = msg_hwnd; + data->clipping_cursor = TRUE; return TRUE; #else WARN( "XInput2 was not available at compile time\n" ); @@ -518,8 +509,7 @@ void ungrab_clipping_window(void) XUnmapWindow( data->display, clip_window ); if (clipping_cursor) XUngrabPointer( data->display, CurrentTime ); clipping_cursor = FALSE; - NtUserDestroyWindow( data->clip_hwnd ); - data->clip_hwnd = 0; + data->clipping_cursor = FALSE; X11DRV_XInput2_Enable( data->display, None, 0 ); } @@ -567,7 +557,7 @@ static void map_event_coords( HWND hwnd, Window window, Window event_root, int x if (!hwnd) { thread_data = x11drv_thread_data(); - if (!thread_data->clip_hwnd) return; + if (!thread_data->clipping_cursor) return; if (thread_data->clip_window != window) return; pt.x = clip_rect.left; pt.y = clip_rect.top; @@ -619,10 +609,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU if (!hwnd) { struct x11drv_thread_data *thread_data = x11drv_thread_data(); - HWND clip_hwnd = thread_data->clip_hwnd; - - if (!clip_hwnd) return; - if (thread_data->clip_window != window) return; + if (!thread_data->clipping_cursor || thread_data->clip_window != window) return; __wine_send_input( hwnd, input, NULL ); return; } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index d9881f635c4..480a2937f3a 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -392,7 +392,7 @@ struct x11drv_thread_data Window selection_wnd; /* window used for selection interactions */ unsigned long warp_serial; /* serial number of last pointer warp request */ Window clip_window; /* window used for cursor clipping */ - HWND clip_hwnd; /* message window stored in desktop while clipping is active */ + BOOL clipping_cursor; /* whether thread is currently clipping the cursor */ #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H XIValuatorClassInfo x_valuator; XIValuatorClassInfo y_valuator; From 0895c6e1940cd6d204b7f91cbb0679f7ca3d9b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 16 Jun 2023 08:42:52 +0200 Subject: [PATCH 2121/2777] win32u: Remove unnecessary set_cursor new_clip rect copy. (cherry picked from commit 56e2a08dae6ead7738488c0b33832abb7b3a91d1) --- dlls/win32u/input.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 61adcd1bff8..b55e89a3d7b 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2655,13 +2655,7 @@ BOOL WINAPI NtUserClipCursor( const RECT *rect ) } else req->flags = SET_CURSOR_NOCLIP; - if ((ret = !wine_server_call( req ))) - { - new_rect.left = reply->new_clip.left; - new_rect.top = reply->new_clip.top; - new_rect.right = reply->new_clip.right; - new_rect.bottom = reply->new_clip.bottom; - } + ret = !wine_server_call( req ); } SERVER_END_REQ; From cc8a695ba0771c0246f63391a6ec3b9c0f81d8ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 16 Jun 2023 08:54:43 +0200 Subject: [PATCH 2122/2777] server: Pass set_cursor flags in WM_WINE_CLIPCURSOR wparam. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55047 (cherry picked from commit ab9b99c4a51afa36fdbec950aee1abbdc2fe28a6) --- dlls/win32u/input.c | 6 +++--- dlls/win32u/message.c | 4 +++- dlls/win32u/sysparams.c | 2 +- dlls/win32u/win32u_private.h | 2 +- server/queue.c | 12 ++++++------ server/user.h | 3 ++- server/window.c | 2 +- 7 files changed, 17 insertions(+), 14 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index b55e89a3d7b..70d84981e79 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2585,13 +2585,13 @@ BOOL get_clip_cursor( RECT *rect ) return TRUE; } -BOOL process_wine_clipcursor( HWND hwnd, BOOL empty, BOOL reset ) +BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ) { struct user_thread_info *thread_info = get_user_thread_info(); RECT rect, virtual_rect = NtUserGetVirtualScreenRect(); - BOOL was_clipping; + BOOL was_clipping, empty = !!(flags & SET_CURSOR_NOCLIP); - TRACE( "hwnd %p, empty %u, reset %u\n", hwnd, empty, reset ); + TRACE( "hwnd %p, flags %#x, reset %u\n", hwnd, flags, reset ); if ((was_clipping = thread_info->clipping_cursor)) InterlockedDecrement( &clipping_cursor ); thread_info->clipping_cursor = FALSE; diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index eb700321708..8c9d96f8e43 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1287,7 +1287,9 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR return call_current_hook( h_extra->handle, HC_ACTION, wparam, h_extra->lparam ); } case WM_WINE_CLIPCURSOR: - if (wparam && lparam) return clip_fullscreen_window( hwnd, FALSE ); + /* non-hardware message, posted on display mode change to trigger fullscreen + clipping or to the desktop window to forcefully release the cursor grabs */ + if (!wparam) return clip_fullscreen_window( hwnd, FALSE ); return process_wine_clipcursor( hwnd, wparam, lparam ); case WM_WINE_SETCURSOR: FIXME( "Unexpected non-hardware WM_WINE_SETCURSOR message\n" ); diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 13a11581e79..42febfa487c 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2733,7 +2733,7 @@ static LONG apply_display_settings( const WCHAR *devname, const DEVMODEW *devmod MAKELPARAM( current_mode.dmPelsWidth, current_mode.dmPelsHeight ), SMTO_ABORTIFHUNG, 2000, FALSE ); /* post clip_fullscreen_window request to the foreground window */ - NtUserPostMessage( NtUserGetForegroundWindow(), WM_WINE_CLIPCURSOR, TRUE, TRUE ); + NtUserPostMessage( NtUserGetForegroundWindow(), WM_WINE_CLIPCURSOR, 0, 0 ); } return ret; diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 784bb9778ae..1d1317b113c 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -283,7 +283,7 @@ extern void toggle_caret( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL unregister_touch_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void update_mouse_tracking_info( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL get_clip_cursor( RECT *rect ) DECLSPEC_HIDDEN; -extern BOOL process_wine_clipcursor( HWND hwnd, BOOL empty, BOOL reset ) DECLSPEC_HIDDEN; +extern BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ) DECLSPEC_HIDDEN; extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN; /* menu.c */ diff --git a/server/queue.c b/server/queue.c index 0a7b5fa70aa..549d08cbcf5 100644 --- a/server/queue.c +++ b/server/queue.c @@ -597,7 +597,7 @@ static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsig } /* set the cursor clip rectangle */ -void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int reset ) +void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, unsigned int flags, int reset ) { rectangle_t top_rect, new_rect; int x, y; @@ -624,17 +624,17 @@ void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int r SHARED_WRITE_END( &desktop->shared->seq ); /* request clip cursor rectangle reset to the desktop thread */ - if (reset) post_desktop_message( desktop, WM_WINE_CLIPCURSOR, TRUE, FALSE ); + if (reset) post_desktop_message( desktop, WM_WINE_CLIPCURSOR, flags, FALSE ); /* notify foreground thread, of reset, or to apply new cursor clipping rect */ - queue_cursor_message( desktop, 0, WM_WINE_CLIPCURSOR, rect == NULL, reset ); + queue_cursor_message( desktop, 0, WM_WINE_CLIPCURSOR, flags, reset ); } /* change the foreground input and reset the cursor clip rect */ static void set_foreground_input( struct desktop *desktop, struct thread_input *input ) { if (desktop->foreground_input == input) return; - set_clip_rectangle( desktop, NULL, 1 ); + set_clip_rectangle( desktop, NULL, SET_CURSOR_NOCLIP, 1 ); desktop->foreground_input = input; SHARED_WRITE_BEGIN( &desktop->shared->seq ); desktop->shared->foreground_tid = input ? input->shared->tid : 0; @@ -3803,8 +3803,8 @@ DECL_HANDLER(set_cursor) } SHARED_WRITE_END( &input->shared->seq ); if (req->flags & SET_CURSOR_POS) set_cursor_pos( desktop, req->x, req->y ); - if (req->flags & SET_CURSOR_CLIP) set_clip_rectangle( desktop, &req->clip, 0 ); - if (req->flags & SET_CURSOR_NOCLIP) set_clip_rectangle( desktop, NULL, 0 ); + if (req->flags & SET_CURSOR_CLIP) set_clip_rectangle( desktop, &req->clip, req->flags, 0 ); + if (req->flags & SET_CURSOR_NOCLIP) set_clip_rectangle( desktop, NULL, SET_CURSOR_NOCLIP, 0 ); if (req->flags & (SET_CURSOR_HANDLE | SET_CURSOR_COUNT)) { diff --git a/server/user.h b/server/user.h index 347e84e10bc..d9e4c023e29 100644 --- a/server/user.h +++ b/server/user.h @@ -105,7 +105,8 @@ extern void queue_cleanup_window( struct thread *thread, user_handle_t win ); extern int init_thread_queue( struct thread *thread ); extern int attach_thread_input( struct thread *thread_from, struct thread *thread_to ); extern void detach_thread_input( struct thread *thread_from ); -extern void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int reset ); +extern void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, + unsigned int flags, int reset ); extern void post_message( user_handle_t win, unsigned int message, lparam_t wparam, lparam_t lparam ); extern void send_notify_message( user_handle_t win, unsigned int message, diff --git a/server/window.c b/server/window.c index 260b44c07a8..7220fd65e53 100644 --- a/server/window.c +++ b/server/window.c @@ -1831,7 +1831,7 @@ static void set_window_pos( struct window *win, struct window *previous, } /* reset cursor clip rectangle when the desktop changes size */ - if (win == win->desktop->top_window) set_clip_rectangle( win->desktop, NULL, 1 ); + if (win == win->desktop->top_window) set_clip_rectangle( win->desktop, NULL, SET_CURSOR_NOCLIP, 1 ); /* if the window is not visible, everything is easy */ if (!visible) return; From c6f1169a5eded98d719a2fbf6a4991c1ec9132ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 16 Jun 2023 23:34:53 +0200 Subject: [PATCH 2123/2777] win32u: Use a specific flag instead of shrinking the clip rect. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55047 (cherry picked from commit 8d2de5dbe1f317ba8f9f7e2f88fb3a0629e5e174) --- dlls/win32u/input.c | 22 ++++++++++++++++------ dlls/win32u/message.c | 2 +- dlls/win32u/sysparams.c | 2 +- include/wine/server_protocol.h | 1 + server/protocol.def | 1 + 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 70d84981e79..9f561b1749b 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2489,9 +2489,10 @@ BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) { struct user_thread_info *thread_info = get_user_thread_info(); MONITORINFO monitor_info = {.cbSize = sizeof(MONITORINFO)}; - RECT rect, virtual_rect = NtUserGetVirtualScreenRect(); + RECT rect; HMONITOR monitor; DWORD style; + BOOL ret; if (hwnd == NtUserGetDesktopWindow()) return FALSE; if (hwnd != NtUserGetForegroundWindow()) return FALSE; @@ -2516,11 +2517,20 @@ BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) if (is_virtual_desktop()) return FALSE; } - /* shrink the clipping rect to make sure it is not ignored for being fullscreen */ - if (EqualRect( &monitor_info.rcMonitor, &virtual_rect )) InflateRect( &monitor_info.rcMonitor, -1, -1 ); - TRACE( "win %p clipping fullscreen\n", hwnd ); - return NtUserClipCursor( &monitor_info.rcMonitor ); + + SERVER_START_REQ( set_cursor ) + { + req->flags = SET_CURSOR_CLIP | SET_CURSOR_FSCLIP; + req->clip.left = monitor_info.rcMonitor.left; + req->clip.top = monitor_info.rcMonitor.top; + req->clip.right = monitor_info.rcMonitor.right; + req->clip.bottom = monitor_info.rcMonitor.bottom; + ret = !wine_server_call( req ); + } + SERVER_END_REQ; + + return ret; } /********************************************************************** @@ -2608,7 +2618,7 @@ BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ) get_clip_cursor( &rect ); intersect_rect( &rect, &rect, &virtual_rect ); if (EqualRect( &rect, &virtual_rect )) empty = TRUE; - if (empty) + if (empty && !(flags & SET_CURSOR_FSCLIP)) { /* if currently clipping, check if we should switch to fullscreen clipping */ if (was_clipping && clip_fullscreen_window( hwnd, TRUE )) return TRUE; diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 8c9d96f8e43..6a9e77f796c 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1289,7 +1289,7 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR case WM_WINE_CLIPCURSOR: /* non-hardware message, posted on display mode change to trigger fullscreen clipping or to the desktop window to forcefully release the cursor grabs */ - if (!wparam) return clip_fullscreen_window( hwnd, FALSE ); + if (wparam & SET_CURSOR_FSCLIP) return clip_fullscreen_window( hwnd, FALSE ); return process_wine_clipcursor( hwnd, wparam, lparam ); case WM_WINE_SETCURSOR: FIXME( "Unexpected non-hardware WM_WINE_SETCURSOR message\n" ); diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 42febfa487c..aa6aca43c7b 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2733,7 +2733,7 @@ static LONG apply_display_settings( const WCHAR *devname, const DEVMODEW *devmod MAKELPARAM( current_mode.dmPelsWidth, current_mode.dmPelsHeight ), SMTO_ABORTIFHUNG, 2000, FALSE ); /* post clip_fullscreen_window request to the foreground window */ - NtUserPostMessage( NtUserGetForegroundWindow(), WM_WINE_CLIPCURSOR, 0, 0 ); + NtUserPostMessage( NtUserGetForegroundWindow(), WM_WINE_CLIPCURSOR, SET_CURSOR_FSCLIP, 0 ); } return ret; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 7a7b22c0883..2c8189b79cf 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -5300,6 +5300,7 @@ struct set_cursor_reply #define SET_CURSOR_POS 0x04 #define SET_CURSOR_CLIP 0x08 #define SET_CURSOR_NOCLIP 0x10 +#define SET_CURSOR_FSCLIP 0x20 struct get_cursor_history_request diff --git a/server/protocol.def b/server/protocol.def index 9770db77706..cef5a16decb 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3764,6 +3764,7 @@ struct handle_info #define SET_CURSOR_POS 0x04 #define SET_CURSOR_CLIP 0x08 #define SET_CURSOR_NOCLIP 0x10 +#define SET_CURSOR_FSCLIP 0x20 /* Get the history of the 64 last cursor positions */ @REQ(get_cursor_history) From d99d16874446b6cca4b5902b992c2fbde51d9c81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 20 Jun 2023 09:53:02 +0200 Subject: [PATCH 2124/2777] imm32/tests: Test how deleting a character can behave. (cherry picked from commit d1f9aae59973aae89a228a3f16a28d41470fea96) --- dlls/imm32/tests/imm32.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 4bdb6be4a31..081a54fd878 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -7213,6 +7213,20 @@ static void test_ga_na_da(void) /* These sequences have some additional WM_IME_NOTIFY messages with unknown wparam > IMN_PRIVATE */ struct ime_call complete_seq[] = { + /* G */ + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 0, .lparam = 0}}, + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"\u3131", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x3131, .lparam = GCS_COMPSTR|GCS_COMPATTR|CS_INSERTCHAR|CS_NOMOVECARET}, + }, + + { + .hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .comp = L"", .result = L"", + .message = {.msg = WM_IME_COMPOSITION, .wparam = 0x1b, .lparam = GCS_CURSORPOS|GCS_DELTASTART|GCS_COMPSTR|GCS_COMPATTR|GCS_COMPCLAUSE| + GCS_COMPREADSTR|GCS_COMPREADATTR|GCS_COMPREADCLAUSE}, + }, + {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_ENDCOMPOSITION, .wparam = 0, .lparam = 0}}, + /* G */ {.hkl = default_hkl, .himc = 0/*himc*/, .func = MSG_TEST_WIN, .message = {.msg = WM_IME_STARTCOMPOSITION, .wparam = 0, .lparam = 0}}, { @@ -7377,6 +7391,14 @@ static void test_ga_na_da(void) flush_events(); keybd_event( 'R', 0x13, KEYEVENTF_KEYUP, 0 ); + keybd_event( VK_BACK, 0x0e, 0, 0 ); + flush_events(); + keybd_event( VK_BACK, 0x0e, KEYEVENTF_KEYUP, 0 ); + + keybd_event( 'R', 0x13, 0, 0 ); + flush_events(); + keybd_event( 'R', 0x13, KEYEVENTF_KEYUP, 0 ); + keybd_event( 'K', 0x25, 0, 0 ); flush_events(); keybd_event( 'K', 0x25, KEYEVENTF_KEYUP, 0 ); From e5a4f85bb731524c31c297a4a7ae76b55516a98d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 15 Jun 2023 14:56:35 +0200 Subject: [PATCH 2125/2777] imm32: Use offsets instead of lengths to decide on sending updates. The composition or result strings may be present, but with zero length. In which case we still want to send the messages, to indicate any change for instance whenever a character is deleted and strings become empty. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55055 (cherry picked from commit e5646191723fa4b5e4cb38187e1611a58ebc8695) --- dlls/imm32/ime.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index b1ff6c54c4e..2717b198c60 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -561,7 +561,7 @@ UINT WINAPI ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGLIST *msgs, TRANSMSG status_msg = {.message = ime_set_composition_status( himc, !!compstr->dwCompStrOffset )}; if (status_msg.message) msgs->TransMsg[count++] = status_msg; - if (compstr->dwResultStrLen) + if (compstr->dwResultStrOffset) { const WCHAR *result = (WCHAR *)((BYTE *)compstr + compstr->dwResultStrOffset); TRANSMSG msg = {.message = WM_IME_COMPOSITION, .wParam = result[0], .lParam = GCS_RESULTSTR}; @@ -569,7 +569,7 @@ UINT WINAPI ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGLIST *msgs, msgs->TransMsg[count++] = msg; } - if (compstr->dwCompStrLen) + if (compstr->dwCompStrOffset) { const WCHAR *comp = (WCHAR *)((BYTE *)compstr + compstr->dwCompStrOffset); TRANSMSG msg = {.message = WM_IME_COMPOSITION, .wParam = comp[0], .lParam = GCS_COMPSTR | GCS_CURSORPOS | GCS_DELTASTART}; From 0960e8a04a821d0af9a2e8be830be577aa82a44a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 13 Jun 2023 07:14:33 +0200 Subject: [PATCH 2126/2777] winex11: Report empty preedit string when result string is committed. Based on a patch from Byeong-Sik Jeon . Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55027 (cherry picked from commit 97c0a52ae552ed856c0955e8badfe0ddf88be91d) --- dlls/winex11.drv/xim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 1c3d2dd9875..1b063cfe886 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -140,7 +140,7 @@ void xim_set_result_string( HWND hwnd, const char *str, UINT count ) len = ntdll_umbstowcs( str, count, output, count ); output[len] = 0; - post_ime_update( hwnd, 0, ime_comp_buf, output ); + post_ime_update( hwnd, 0, NULL, output ); free( output ); } From c875bfb338be5f5c5f08c3d692c7fbfb7a0af867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 30 May 2023 13:16:39 +0200 Subject: [PATCH 2127/2777] winex11: Make sure HIMC is opened before sending IME updates. (cherry picked from commit f7e76184f1c5064604381cdfc3c30ef357955e52) --- dlls/winex11.drv/xim.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 1b063cfe886..209d63f0402 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -175,6 +175,7 @@ static int xic_preedit_start( XIC xic, XPointer user, XPointer arg ) if ((ime_comp_buf = realloc( ime_comp_buf, sizeof(WCHAR) ))) *ime_comp_buf = 0; else ERR( "Failed to allocate preedit buffer\n" ); + NtUserPostMessage( hwnd, WM_IME_NOTIFY, IMN_WINE_SET_OPEN_STATUS, TRUE ); post_ime_update( hwnd, 0, ime_comp_buf, NULL ); return -1; @@ -190,6 +191,7 @@ static int xic_preedit_done( XIC xic, XPointer user, XPointer arg ) ime_comp_buf = NULL; post_ime_update( hwnd, 0, NULL, NULL ); + NtUserPostMessage( hwnd, WM_IME_NOTIFY, IMN_WINE_SET_OPEN_STATUS, FALSE ); return 0; } From 1ebe436112c340d923236dd7a9f81dc6641af9f9 Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Wed, 17 Oct 2018 19:55:27 +0300 Subject: [PATCH 2128/2777] winex11.drv: Ignore clip_reset when trying to clip the mouse after the desktop has been resized. This fixes the mouse clipping when the desktop is resized multiple times in a row. CW-Bug-Id: #21879 --- dlls/win32u/input.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 9f561b1749b..5c9825a1ce8 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2505,7 +2505,8 @@ BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) if (!NtUserGetWindowRect( hwnd, &rect )) return FALSE; if (!NtUserIsWindowRectFullScreen( &rect )) return FALSE; - if (NtGetTickCount() - thread_info->clipping_reset < 1000) return FALSE; + + if (!reset && NtGetTickCount() - thread_info->clipping_reset < 1000) return FALSE; if (!reset && clipping_cursor && thread_info->clipping_cursor) return FALSE; /* already clipping */ if (!(monitor = NtUserMonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST ))) return FALSE; From 8fca1060ad4a12a1e8ab7acd9bc97e847b315c45 Mon Sep 17 00:00:00 2001 From: Alexey Prokhin Date: Sat, 20 Oct 2018 18:07:12 +0300 Subject: [PATCH 2129/2777] winex11.drv: Enable fullscreen clipping even if not already clipping. CW-Bug-Id: #21879 --- dlls/win32u/input.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 5c9825a1ce8..800635e3753 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2600,11 +2600,11 @@ BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ) { struct user_thread_info *thread_info = get_user_thread_info(); RECT rect, virtual_rect = NtUserGetVirtualScreenRect(); - BOOL was_clipping, empty = !!(flags & SET_CURSOR_NOCLIP); + BOOL empty = !!(flags & SET_CURSOR_NOCLIP); TRACE( "hwnd %p, flags %#x, reset %u\n", hwnd, flags, reset ); - if ((was_clipping = thread_info->clipping_cursor)) InterlockedDecrement( &clipping_cursor ); + if (thread_info->clipping_cursor) InterlockedDecrement( &clipping_cursor ); thread_info->clipping_cursor = FALSE; if (reset) @@ -2622,7 +2622,7 @@ BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ) if (empty && !(flags & SET_CURSOR_FSCLIP)) { /* if currently clipping, check if we should switch to fullscreen clipping */ - if (was_clipping && clip_fullscreen_window( hwnd, TRUE )) return TRUE; + if (clip_fullscreen_window( hwnd, TRUE )) return TRUE; return user_driver->pClipCursor( NULL, FALSE ); } From 039488fc9b621d7124445f025644ceb98a0407b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 21 Jan 2020 21:05:05 +0100 Subject: [PATCH 2130/2777] winex11.drv: Ignore ClipCursor if desktop window is foreground. CW-Bug-Id: #21879 --- dlls/win32u/input.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 800635e3753..b6f6883621a 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2643,6 +2643,12 @@ BOOL WINAPI NtUserClipCursor( const RECT *rect ) TRACE( "Clipping to %s\n", wine_dbgstr_rect(rect) ); + if (NtUserGetForegroundWindow() == NtUserGetDesktopWindow()) + { + WARN( "desktop is foreground, ignoring ClipCursor\n" ); + rect = NULL; + } + if (rect) { if (rect->left > rect->right || rect->top > rect->bottom) return FALSE; From 6a72d8ad772978a5027aa7b85f6ab73571ae5b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 19 Sep 2019 15:42:09 +0200 Subject: [PATCH 2131/2777] winex11.drv: Wait for pointer grab on FocusIn/WM_TAKE_FOCUS events. The FocusIn/WM_TAKE_FOCUS events are received as soon as a window is clicked, but when some modifier key is pressed or when the click is on the window frame, the WM may still be controlling the window size or position. It usually grabs the cursor while doing so - and if not then there's apparently nothing we can do. When using undecorated mode we handle this case "correctly" by going through the corresponding Windows non-client message loop until mouse buttons are released, but when using decorated windows the window decoration is empty from the Wine perspective and any window event is considered as happening in the client area. This leads to some issues when the window is moved or resized, with applications applying clipping rectangles immediately and not updating it on subsequent window move/resize messages. Delaying the WM_ACTIVATE until the WM releases its grab and the window move is complete helps solving this situation. This delay is implemented here by resending the FocusIn/WM_TAKE_FOCUS events to the window until the cursor can be grabbed and then processing them normally. winex11.drv: Fix focus delay issues with desktop clipping. CW-Bug-Id: #21879 --- dlls/winex11.drv/event.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 374394a46aa..a3954db4e8c 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -337,6 +337,27 @@ static Bool filter_event( Display *display, XEvent *event, char *arg ) } } +static void wait_grab_pointer( Display *display ) +{ + RECT rect; + + /* release cursor grab held by any Wine process */ + NtUserGetClipCursor( &rect ); + NtUserClipCursor( NULL ); + + while (XGrabPointer( display, root_window, False, 0, GrabModeAsync, GrabModeAsync, + None, None, CurrentTime ) != GrabSuccess) + { + LARGE_INTEGER timeout = {.QuadPart = -10 * (ULONGLONG)10000}; + NtDelayExecution( FALSE, &timeout ); + } + + XUngrabPointer( display, CurrentTime ); + XFlush( display ); + + /* restore the previously used clipping rect */ + NtUserClipCursor( &rect ); +} enum event_merge_action { @@ -685,6 +706,8 @@ static void set_focus( Display *display, HWND hwnd, Time time ) Window win; GUITHREADINFO threadinfo; + wait_grab_pointer( display ); + TRACE( "setting foreground window to %p\n", hwnd ); NtUserSetForegroundWindow( hwnd ); From 14644fa2c51b5f2d8a381cac334e0b7f3a9234e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 17 Dec 2019 16:58:07 +0100 Subject: [PATCH 2132/2777] Revert "winex11.drv: Only call XWarpPointer if we can get exclusive pointer grab." This reverts commit 74efb3e872aebf57a42d62b52e149ae26f320c9a. We are now only activating windows only once the window manager has released its grab, it should be safer to let them move the pointer around and this should not be needed anymore. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47771 CW-Bug-Id: #21879 --- dlls/winex11.drv/mouse.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index cb07e459c1c..5049d323fbe 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1461,23 +1461,10 @@ BOOL X11DRV_SetCursorPos( INT x, INT y ) return FALSE; } - if (!clipping_cursor && - XGrabPointer( data->display, root_window, False, - PointerMotionMask | ButtonPressMask | ButtonReleaseMask, - GrabModeAsync, GrabModeAsync, None, None, CurrentTime ) != GrabSuccess) - { - WARN( "refusing to warp pointer to %u, %u without exclusive grab\n", (int)pos.x, (int)pos.y ); - return FALSE; - } - TRACE( "real setting to %s\n", wine_dbgstr_point( &pos ) ); XWarpPointer( data->display, root_window, root_window, 0, 0, 0, 0, pos.x, pos.y ); data->warp_serial = NextRequest( data->display ); - - if (!clipping_cursor) - XUngrabPointer( data->display, CurrentTime ); - XNoOp( data->display ); XFlush( data->display ); /* avoids bad mouse lag in games that do their own mouse warping */ TRACE( "warped to (fake) %d,%d serial %lu\n", x, y, data->warp_serial ); From 74428e24c163430141f71ddea1a04680b495235b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 9 Dec 2019 20:28:20 +0100 Subject: [PATCH 2133/2777] HACK: mutter: winex11.drv: Add a bit of delay before restoring mouse grabs on FocusIn. CW-Bug-Id: #21879 --- dlls/winex11.drv/event.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index a3954db4e8c..5d15c9cb7bd 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -910,6 +910,17 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (is_virtual_desktop() && hwnd == NtUserGetDesktopWindow()) retry_grab_clipping_window(); if (hwnd == NtUserGetDesktopWindow()) return FALSE; + /* Focus was just restored but it can be right after super was + * pressed and gnome-shell needs a bit of time to respond and + * toggle the activity view. If we grab the cursor right away + * it will cancel it and super key will do nothing. + */ + if (event->mode == NotifyUngrab && wm_is_mutter(event->display)) + { + LARGE_INTEGER timeout = {.QuadPart = 100 * -10000}; + NtDelayExecution( FALSE, &timeout ); + } + /* when keyboard grab is released, re-apply the cursor clipping rect */ was_grabbed = keyboard_grabbed; keyboard_grabbed = event->mode == NotifyGrab || event->mode == NotifyWhileGrabbed; From c8d77ecf32952cb5660c0dfcd4eaa2340eb87787 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 15 Mar 2021 12:01:25 -0500 Subject: [PATCH 2134/2777] winex11.drv: Flush X connection after ungrabbing the pointer. CW-Bug-Id: #18169 CW-Bug-Id: #21879 --- dlls/winex11.drv/mouse.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 5049d323fbe..52ff8eddc25 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -507,7 +507,11 @@ void ungrab_clipping_window(void) TRACE( "no longer clipping\n" ); XUnmapWindow( data->display, clip_window ); - if (clipping_cursor) XUngrabPointer( data->display, CurrentTime ); + if (clipping_cursor) + { + XUngrabPointer( data->display, CurrentTime ); + XFlush( data->display ); + } clipping_cursor = FALSE; data->clipping_cursor = FALSE; X11DRV_XInput2_Enable( data->display, None, 0 ); From 1a1f4c1e17c37f8a30b3e04201c7866ad8c1f73d Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Tue, 8 Jun 2021 16:01:54 +0300 Subject: [PATCH 2135/2777] winex11.drv: Send missed KEYUP events on KeymapNotify. Full focus lost / focus gained events on the Windows side are not feasible for X11's FocusIn/FocusOut events generated by keyboard grabs (see XGrabKeyboard()) that are used for example for Atl+Tab handling. Using them would degrade user's experience, especially with our full screen hack, by causing the window to minimize or flash multiple times depending on a game/window manager combo. Because of that the programs may miss on some KEYUP events that happen during the grab, and since there are no focus changes on the Windows side the state doesn't get resynced. This change attempts to improve user experience by syncing any missed key release events that happened while the window haven't had focus on the X11 side. There's no syncing of key presses as those are more problematic because of window manager quirks, e.g. on KDE it may end up syncing the Tab press portion of Alt+Tab. Luckily missing key events for keys that were pressed and not released while the WM had the keyboard grab is not nearly as confusing as stuck keys. For Warhammer: Chaosbane, theHunter: Call of the Wild, Far Cry Primal and many other games that end up with stuck Alt after Alt+Tabbing. CW-Bug-ID: #17046 CW-Bug-ID: #18904 --- dlls/winex11.drv/event.c | 2 ++ dlls/winex11.drv/keyboard.c | 43 +++++++++++++++++++++++++++++++++++-- dlls/winex11.drv/mouse.c | 2 ++ dlls/winex11.drv/x11drv.h | 1 + 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 5d15c9cb7bd..a7d4f4a2436 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -910,6 +910,8 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (is_virtual_desktop() && hwnd == NtUserGetDesktopWindow()) retry_grab_clipping_window(); if (hwnd == NtUserGetDesktopWindow()) return FALSE; + x11drv_thread_data()->keymapnotify_hwnd = hwnd; + /* Focus was just restored but it can be right after super was * pressed and gnome-shell needs a bit of time to respond and * toggle the activity view. If we grab the cursor right away diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 1d6cef40efb..f476919f9f5 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1195,11 +1195,19 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) int i, j; BYTE keystate[256]; WORD vkey; + DWORD flags; + KeyCode keycode; + HWND keymapnotify_hwnd; BOOL changed = FALSE; struct { WORD vkey; + WORD scan; WORD pressed; } keys[256]; + struct x11drv_thread_data *thread_data = x11drv_thread_data(); + + keymapnotify_hwnd = thread_data->keymapnotify_hwnd; + thread_data->keymapnotify_hwnd = NULL; if (!get_async_key_state( keystate )) return FALSE; @@ -1214,11 +1222,17 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) { for (j = 0; j < 8; j++) { - vkey = keyc2vkey[(i * 8) + j]; + keycode = (i * 8) + j; + vkey = keyc2vkey[keycode]; /* If multiple keys map to the same vkey, we want to report it as * pressed iff any of them are pressed. */ - if (!keys[vkey & 0xff].vkey) keys[vkey & 0xff].vkey = vkey; + if (!keys[vkey & 0xff].vkey) + { + keys[vkey & 0xff].vkey = vkey; + keys[vkey & 0xff].scan = keyc2scan[keycode] & 0xff; + } + if (event->xkeymap.key_vector[i] & (1<window, event->x, event->y, event->detail ); + x11drv_thread_data()->keymapnotify_hwnd = hwnd; + if (hwnd == x11drv_thread_data()->grab_hwnd) return FALSE; /* simulate a mouse motion event */ diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 480a2937f3a..37112b80903 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -386,6 +386,7 @@ struct x11drv_thread_data XEvent *current_event; /* event currently being processed */ HWND grab_hwnd; /* window that currently grabs the mouse */ HWND last_focus; /* last window that had focus */ + HWND keymapnotify_hwnd; /* window that should receive modifier release events */ XIM xim; /* input method */ HWND last_xic_hwnd; /* last xic window */ XFontSet font_set; /* international text drawing font set */ From baf88676a64e18c86af336a933224a60ea76ecd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 26 Jun 2023 10:37:59 +0200 Subject: [PATCH 2136/2777] win32u: Keep the clipping rectangle inside a fullscreen window. CW-Bug-Id: #21707 --- dlls/win32u/input.c | 15 +++++++++++++-- dlls/win32u/sysparams.c | 2 +- dlls/win32u/win32u_private.h | 1 + 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index b6f6883621a..c3ee888557a 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2637,13 +2637,14 @@ BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ) */ BOOL WINAPI NtUserClipCursor( const RECT *rect ) { + HWND foreground = NtUserGetForegroundWindow(); UINT dpi; BOOL ret; - RECT new_rect; + RECT new_rect, full_rect; TRACE( "Clipping to %s\n", wine_dbgstr_rect(rect) ); - if (NtUserGetForegroundWindow() == NtUserGetDesktopWindow()) + if (foreground == NtUserGetDesktopWindow()) { WARN( "desktop is foreground, ignoring ClipCursor\n" ); rect = NULL; @@ -2658,6 +2659,16 @@ BOOL WINAPI NtUserClipCursor( const RECT *rect ) new_rect = map_dpi_rect( *rect, dpi, get_monitor_dpi( monitor )); rect = &new_rect; } + + /* keep the mouse clipped inside of a fullscreen foreground window */ + if (NtUserGetWindowRect( foreground, &full_rect ) && is_window_rect_full_screen( &full_rect )) + { + full_rect.left = max( full_rect.left, min( full_rect.right - 1, rect->left ) ); + full_rect.right = max( full_rect.left, min( full_rect.right - 1, rect->right ) ); + full_rect.top = max( full_rect.top, min( full_rect.bottom - 1, rect->top ) ); + full_rect.bottom = max( full_rect.top, min( full_rect.bottom - 1, rect->bottom ) ); + rect = &full_rect; + } } SERVER_START_REQ( set_cursor ) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index aa6aca43c7b..6630250b667 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2075,7 +2075,7 @@ RECT get_virtual_screen_rect( UINT dpi ) return rect; } -static BOOL is_window_rect_full_screen( const RECT *rect ) +BOOL is_window_rect_full_screen( const RECT *rect ) { struct monitor *monitor; BOOL ret = FALSE; diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 1d1317b113c..3d1c7c99a43 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -351,6 +351,7 @@ extern int get_system_metrics( int index ) DECLSPEC_HIDDEN; extern UINT get_thread_dpi(void) DECLSPEC_HIDDEN; extern DPI_AWARENESS get_thread_dpi_awareness(void) DECLSPEC_HIDDEN; extern RECT get_virtual_screen_rect( UINT dpi ) DECLSPEC_HIDDEN; +extern BOOL is_window_rect_full_screen( const RECT *rect ) DECLSPEC_HIDDEN; extern BOOL is_exiting_thread( DWORD tid ) DECLSPEC_HIDDEN; extern POINT map_dpi_point( POINT pt, UINT dpi_from, UINT dpi_to ) DECLSPEC_HIDDEN; extern RECT map_dpi_rect( RECT rect, UINT dpi_from, UINT dpi_to ) DECLSPEC_HIDDEN; From 50bf308956f045a6d65f97191cea89583c3b4fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 26 Jun 2023 14:27:03 +0200 Subject: [PATCH 2137/2777] fixup! winex11.drv: Listen to RawMotion and RawButton* events in the desktop thread. --- dlls/winex11.drv/mouse.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index ec97ce51a36..dd362e18e3d 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -514,7 +514,10 @@ void ungrab_clipping_window(void) } clipping_cursor = FALSE; data->clipping_cursor = FALSE; - X11DRV_XInput2_Enable( data->display, None, 0 ); + + /* desktop window needs to listen to XInput2 events all the time for rawinput to work */ + if (NtUserGetWindowThread( NtUserGetDesktopWindow(), NULL ) != GetCurrentThreadId()) + X11DRV_XInput2_Enable( data->display, None, 0 ); } /*********************************************************************** From ae5199f37323a3daafa335edb797de332cb3872e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 27 Jun 2023 09:06:05 +0200 Subject: [PATCH 2138/2777] imm32: Avoid closing the input context on CPS_CANCEL. CW-Bug-Id: #22370 --- dlls/imm32/ime.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 2717b198c60..0c6ed9c49e1 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -702,7 +702,8 @@ BOOL WINAPI NotifyIME( HIMC himc, DWORD action, DWORD index, DWORD value ) } case CPS_CANCEL: input_context_set_comp_str( ctx, NULL, 0 ); - ImmSetOpenStatus( himc, FALSE ); + if ((msg = ime_set_composition_status( himc, FALSE ))) ime_send_message( himc, msg, 0, 0 ); + NtUserNotifyIMEStatus( ctx->hWnd, FALSE ); break; default: FIXME( "himc %p, action %#lx, index %#lx, value %#lx stub!\n", himc, action, index, value ); From 8a2a544f43349ff7a301cb3579b7b6fb71a9d183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Tue, 7 Jun 2022 12:51:22 +0200 Subject: [PATCH 2139/2777] windows.media.speech: Move constraints vector to the recognition session. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl (cherry picked from commit e203d3be0ae022fae376bb6f1499dc875ad5c7b1) CW-Bug-Id: #20134 --- dlls/windows.media.speech/recognizer.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index bdcc57f883e..105ed2b0b05 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -156,6 +156,8 @@ struct session ISpeechContinuousRecognitionSession ISpeechContinuousRecognitionSession_iface; LONG ref; + IVector_ISpeechRecognitionConstraint *constraints; + struct list completed_handlers; struct list result_handlers; }; @@ -208,6 +210,7 @@ static ULONG WINAPI session_Release( ISpeechContinuousRecognitionSession *iface { typed_event_handlers_clear(&impl->completed_handlers); typed_event_handlers_clear(&impl->result_handlers); + IVector_ISpeechRecognitionConstraint_Release(impl->constraints); free(impl); } @@ -360,7 +363,6 @@ struct recognizer LONG ref; ISpeechContinuousRecognitionSession *session; - IVector_ISpeechRecognitionConstraint *constraints; }; /* @@ -424,7 +426,6 @@ static ULONG WINAPI recognizer_Release( ISpeechRecognizer *iface ) if (!ref) { ISpeechContinuousRecognitionSession_Release(impl->session); - IVector_ISpeechRecognitionConstraint_Release(impl->constraints); free(impl); } @@ -452,8 +453,11 @@ static HRESULT WINAPI recognizer_GetTrustLevel( ISpeechRecognizer *iface, TrustL static HRESULT WINAPI recognizer_get_Constraints( ISpeechRecognizer *iface, IVector_ISpeechRecognitionConstraint **vector ) { struct recognizer *impl = impl_from_ISpeechRecognizer(iface); + struct session *session = impl_from_ISpeechContinuousRecognitionSession(impl->session); + TRACE("iface %p, operation %p.\n", iface, vector); - IVector_ISpeechRecognitionConstraint_AddRef((*vector = impl->constraints)); + + IVector_ISpeechRecognitionConstraint_AddRef((*vector = session->constraints)); return S_OK; } @@ -797,18 +801,22 @@ static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface if (language) FIXME("language parameter unused. Stub!\n"); + /* Init ISpeechContinuousRecognitionSession */ session->ISpeechContinuousRecognitionSession_iface.lpVtbl = &session_vtbl; session->ref = 1; + list_init(&session->completed_handlers); list_init(&session->result_handlers); + if (FAILED(hr = vector_inspectable_create(&constraints_iids, (IVector_IInspectable**)&session->constraints))) + goto error; + + /* Init ISpeechRecognizer */ impl->ISpeechRecognizer_iface.lpVtbl = &speech_recognizer_vtbl; impl->IClosable_iface.lpVtbl = &closable_vtbl; impl->ISpeechRecognizer2_iface.lpVtbl = &speech_recognizer2_vtbl; impl->session = &session->ISpeechContinuousRecognitionSession_iface; impl->ref = 1; - if (FAILED(hr = vector_inspectable_create(&constraints_iids, (IVector_IInspectable**)&impl->constraints))) - goto error; TRACE("created SpeechRecognizer %p.\n", impl); @@ -816,6 +824,7 @@ static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface return S_OK; error: + if (session->constraints) IVector_ISpeechRecognitionConstraint_Release(session->constraints); free(session); free(impl); From 7fdf3744ebad9d350ff246d76be5ef91c9e5cbe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Tue, 3 Jan 2023 15:08:28 +0100 Subject: [PATCH 2140/2777] windows.media.speech: Do not force calling convention on internal callbacks. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl (cherry picked from commit 754452dd9d840a03c3996a53fb27bfe30089ddf7) CW-Bug-Id: #20134 --- dlls/windows.media.speech/private.h | 4 ++-- dlls/windows.media.speech/recognizer.c | 8 ++++---- dlls/windows.media.speech/synthesizer.c | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/dlls/windows.media.speech/private.h b/dlls/windows.media.speech/private.h index adc3987b031..f2abaf8b5d5 100644 --- a/dlls/windows.media.speech/private.h +++ b/dlls/windows.media.speech/private.h @@ -69,8 +69,8 @@ struct vector_iids const GUID *view; }; -typedef HRESULT (WINAPI *async_action_callback)( IInspectable *invoker ); -typedef HRESULT (WINAPI *async_operation_inspectable_callback)( IInspectable *invoker, IInspectable **result ); +typedef HRESULT (*async_action_callback)( IInspectable *invoker ); +typedef HRESULT (*async_operation_inspectable_callback)( IInspectable *invoker, IInspectable **result ); HRESULT async_action_create( IInspectable *invoker, async_action_callback callback, IAsyncAction **out ); HRESULT async_operation_inspectable_create( const GUID *iid, IInspectable *invoker, async_operation_inspectable_callback callback, diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 105ed2b0b05..aaf9c5f8908 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -247,7 +247,7 @@ static HRESULT WINAPI session_set_AutoStopSilenceTimeout( ISpeechContinuousRecog return E_NOTIMPL; } -static HRESULT WINAPI start_callback( IInspectable *invoker ) +static HRESULT session_start_async( IInspectable *invoker ) { return S_OK; } @@ -255,7 +255,7 @@ static HRESULT WINAPI start_callback( IInspectable *invoker ) static HRESULT WINAPI session_StartAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action ) { FIXME("iface %p, action %p stub!\n", iface, action); - return async_action_create(NULL, start_callback, action); + return async_action_create(NULL, session_start_async, action); } static HRESULT WINAPI session_StartWithModeAsync( ISpeechContinuousRecognitionSession *iface, @@ -479,7 +479,7 @@ static HRESULT WINAPI recognizer_get_UIOptions( ISpeechRecognizer *iface, ISpeec return E_NOTIMPL; } -static HRESULT WINAPI compile_callback( IInspectable *invoker, IInspectable **result ) +static HRESULT recognizer_compile_constraints_async( IInspectable *invoker, IInspectable **result ) { return compilation_result_create(SpeechRecognitionResultStatus_Success, (ISpeechRecognitionCompilationResult **) result); } @@ -489,7 +489,7 @@ static HRESULT WINAPI recognizer_CompileConstraintsAsync( ISpeechRecognizer *ifa { IAsyncOperation_IInspectable **value = (IAsyncOperation_IInspectable **)operation; FIXME("iface %p, operation %p semi-stub!\n", iface, operation); - return async_operation_inspectable_create(&IID_IAsyncOperation_SpeechRecognitionCompilationResult, NULL, compile_callback, value); + return async_operation_inspectable_create(&IID_IAsyncOperation_SpeechRecognitionCompilationResult, NULL, recognizer_compile_constraints_async, value); } static HRESULT WINAPI recognizer_RecognizeAsync( ISpeechRecognizer *iface, diff --git a/dlls/windows.media.speech/synthesizer.c b/dlls/windows.media.speech/synthesizer.c index 5e5d20b8364..bdf7325f669 100644 --- a/dlls/windows.media.speech/synthesizer.c +++ b/dlls/windows.media.speech/synthesizer.c @@ -929,7 +929,7 @@ static HRESULT WINAPI synthesizer_GetTrustLevel( ISpeechSynthesizer *iface, Trus return E_NOTIMPL; } -static HRESULT CALLBACK text_to_stream_operation( IInspectable *invoker, IInspectable **result ) +static HRESULT synthesizer_synthesize_text_to_stream_async( IInspectable *invoker, IInspectable **result ) { return synthesis_stream_create((ISpeechSynthesisStream **)result); } @@ -939,10 +939,10 @@ static HRESULT WINAPI synthesizer_SynthesizeTextToStreamAsync( ISpeechSynthesize { TRACE("iface %p, text %p, operation %p.\n", iface, text, operation); return async_operation_inspectable_create(&IID_IAsyncOperation_SpeechSynthesisStream, NULL, - text_to_stream_operation, (IAsyncOperation_IInspectable **)operation); + synthesizer_synthesize_text_to_stream_async, (IAsyncOperation_IInspectable **)operation); } -static HRESULT CALLBACK ssml_to_stream_operation( IInspectable *invoker, IInspectable **result ) +static HRESULT synthesizer_synthesize_ssml_to_stream_async( IInspectable *invoker, IInspectable **result ) { return synthesis_stream_create((ISpeechSynthesisStream **)result); } @@ -952,7 +952,7 @@ static HRESULT WINAPI synthesizer_SynthesizeSsmlToStreamAsync( ISpeechSynthesize { TRACE("iface %p, ssml %p, operation %p.\n", iface, ssml, operation); return async_operation_inspectable_create(&IID_IAsyncOperation_SpeechSynthesisStream, NULL, - ssml_to_stream_operation, (IAsyncOperation_IInspectable **)operation); + synthesizer_synthesize_ssml_to_stream_async, (IAsyncOperation_IInspectable **)operation); } static HRESULT WINAPI synthesizer_put_Voice( ISpeechSynthesizer *iface, IVoiceInformation *value ) From 217b56f56d7b8e1a62b0b252739d015eb9057a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Tue, 3 May 2022 17:04:08 +0200 Subject: [PATCH 2141/2777] windows.media.speech: Return IAsyncAction from session_StopAsync. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl (cherry picked from commit d21b872a8063494404d4fd9fca6f31610d33c89c) CW-Bug-Id: #20134 --- dlls/windows.media.speech/recognizer.c | 7 ++++++- dlls/windows.media.speech/tests/speech.c | 24 ++++++++++-------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index aaf9c5f8908..b4f68489bd0 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -266,10 +266,15 @@ static HRESULT WINAPI session_StartWithModeAsync( ISpeechContinuousRecognitionSe return E_NOTIMPL; } +static HRESULT session_stop_async( IInspectable *invoker ) +{ + return S_OK; +} + static HRESULT WINAPI session_StopAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action ) { FIXME("iface %p, action %p stub!\n", iface, action); - return E_NOTIMPL; + return async_action_create(NULL, session_stop_async, action); } static HRESULT WINAPI session_CancelAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action ) diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index f234dc9d643..767f559a1fd 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -1886,9 +1886,7 @@ static void test_Recognition(void) */ hr = ISpeechContinuousRecognitionSession_StopAsync(session, &action2); - todo_wine ok(hr == S_OK, "ISpeechContinuousRecognitionSession_StopAsync failed, hr %#lx.\n", hr); - - if (FAILED(hr)) goto skip_action; + ok(hr == S_OK, "ISpeechContinuousRecognitionSession_StopAsync failed, hr %#lx.\n", hr); async_void_handler_create_static(&action_handler); action_handler.event_block = CreateEventW(NULL, FALSE, FALSE, NULL); @@ -1900,40 +1898,38 @@ static void test_Recognition(void) put_param.handler = &action_handler.IAsyncActionCompletedHandler_iface; put_param.action = action2; put_thread = CreateThread(NULL, 0, action_put_completed_thread, &put_param, 0, NULL); - todo_wine ok(!WaitForSingleObject(action_handler.event_finished , 5000), "Wait for event_finished failed.\n"); + ok(!WaitForSingleObject(action_handler.event_finished , 5000), "Wait for event_finished failed.\n"); handler = (void *)0xdeadbeef; old_ref = action_handler.ref; hr = IAsyncAction_get_Completed(action2, &handler); - todo_wine ok(hr == S_OK, "IAsyncAction_get_Completed failed, hr %#lx.\n", hr); + ok(hr == S_OK, "IAsyncAction_get_Completed failed, hr %#lx.\n", hr); - todo_wine ok(handler == &action_handler.IAsyncActionCompletedHandler_iface || /* Broken on 1507. */ - broken(handler != NULL && handler != (void *)0xdeadbeef), "Handler was %p.\n", handler); + todo_wine ok(handler == &action_handler.IAsyncActionCompletedHandler_iface, "Handler was %p.\n", handler); ref = action_handler.ref - old_ref; todo_wine ok(ref == 1, "The ref was increased by %lu.\n", ref); - IAsyncActionCompletedHandler_Release(handler); + if (handler) IAsyncActionCompletedHandler_Release(handler); hr = IAsyncAction_QueryInterface(action2, &IID_IAsyncInfo, (void **)&info); - todo_wine ok(hr == S_OK, "IAsyncAction_QueryInterface failed, hr %#lx.\n", hr); + ok(hr == S_OK, "IAsyncAction_QueryInterface failed, hr %#lx.\n", hr); hr = IAsyncInfo_Close(info); /* If IAsyncInfo_Close would wait for the handler to finish, the test would get stuck here. */ - todo_wine ok(hr == S_OK, "IAsyncInfo_Close failed, hr %#lx.\n", hr); + ok(hr == S_OK, "IAsyncInfo_Close failed, hr %#lx.\n", hr); check_async_info((IInspectable *)action2, 3, AsyncStatus_Closed, S_OK); set = SetEvent(action_handler.event_block); - todo_wine ok(set == TRUE, "Event 'event_block' wasn't set.\n"); - todo_wine ok(!WaitForSingleObject(put_thread , 1000), "Wait for put_thread failed.\n"); + ok(set == TRUE, "Event 'event_block' wasn't set.\n"); + ok(!WaitForSingleObject(put_thread , 1000), "Wait for put_thread failed.\n"); IAsyncInfo_Release(info); CloseHandle(action_handler.event_finished); CloseHandle(action_handler.event_block); CloseHandle(put_thread); - todo_wine ok(action != action2, "actions were the same!\n"); + ok(action != action2, "actions were the same!\n"); IAsyncAction_Release(action2); -skip_action: IAsyncAction_Release(action); hr = ISpeechContinuousRecognitionSession_remove_ResultGenerated(session, token); From 65726d883c6f8a21f235b025815aa9b40b34a4c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Tue, 3 May 2022 20:04:11 +0200 Subject: [PATCH 2142/2777] windows.media.speech: Return IAsyncAction from session_PauseAsync. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl (cherry picked from commit 4e88f093b011ee70165d026a5233ce7b1445470e) CW-Bug-Id: #20134 --- dlls/windows.media.speech/recognizer.c | 7 ++++++- dlls/windows.media.speech/tests/speech.c | 11 ++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index b4f68489bd0..54a0e165f5f 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -283,10 +283,15 @@ static HRESULT WINAPI session_CancelAsync( ISpeechContinuousRecognitionSession * return E_NOTIMPL; } +static HRESULT session_pause_async( IInspectable *invoker ) +{ + return S_OK; +} + static HRESULT WINAPI session_PauseAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action ) { FIXME("iface %p, action %p stub!\n", iface, action); - return E_NOTIMPL; + return async_action_create(NULL, session_pause_async, action); } static HRESULT WINAPI session_Resume( ISpeechContinuousRecognitionSession *iface ) diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 767f559a1fd..f425e32f170 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -1885,6 +1885,15 @@ static void test_Recognition(void) * TODO: Use a loopback device together with prerecorded audio files to test the recognizer's functionality. */ + hr = ISpeechContinuousRecognitionSession_PauseAsync(session, &action2); + ok(hr == S_OK, "ISpeechContinuousRecognitionSession_PauseAsync failed, hr %#lx.\n", hr); + await_async_void(action2, &action_handler); + check_async_info((IInspectable *)action2, 3, Completed, S_OK); + IAsyncAction_Release(action2); + + hr = ISpeechContinuousRecognitionSession_Resume(session); + todo_wine ok(hr == S_OK, "ISpeechContinuousRecognitionSession_Resume failed, hr %#lx.\n", hr); + hr = ISpeechContinuousRecognitionSession_StopAsync(session, &action2); ok(hr == S_OK, "ISpeechContinuousRecognitionSession_StopAsync failed, hr %#lx.\n", hr); @@ -1916,7 +1925,7 @@ static void test_Recognition(void) hr = IAsyncInfo_Close(info); /* If IAsyncInfo_Close would wait for the handler to finish, the test would get stuck here. */ ok(hr == S_OK, "IAsyncInfo_Close failed, hr %#lx.\n", hr); - check_async_info((IInspectable *)action2, 3, AsyncStatus_Closed, S_OK); + check_async_info((IInspectable *)action2, 4, AsyncStatus_Closed, S_OK); set = SetEvent(action_handler.event_block); ok(set == TRUE, "Event 'event_block' wasn't set.\n"); From 42641bb38e3e6b04b855801067a9f27b184a6818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Mon, 16 May 2022 18:40:22 +0200 Subject: [PATCH 2143/2777] windows.media.speech/tests: Test the recognizer state. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl (cherry picked from commit b36871b85a40c0da6c56f8d9f06303d42ce75095) CW-Bug-Id: #20134 --- dlls/windows.media.speech/tests/speech.c | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index f425e32f170..c8bbf8d9d54 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -1743,6 +1743,7 @@ static void test_Recognition(void) struct iterator_hstring iterator_hstring; struct iterable_hstring iterable_hstring; EventRegistrationToken token = { .value = 0 }; + SpeechRecognizerState recog_state; HSTRING commands[3], hstr, tag; HANDLE put_thread; LONG ref, old_ref; @@ -1841,6 +1842,11 @@ static void test_Recognition(void) ok(hr == S_OK, "ISpeechContinuousRecognitionSession_add_ResultGenerated failed, hr %#lx.\n", hr); ok(token.value != 0xdeadbeef, "Got unexpexted token: %#I64x.\n", token.value); + recog_state = 0xdeadbeef; + hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); + todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); + todo_wine ok(recog_state == SpeechRecognizerState_Idle, "recog_state was %u.\n", recog_state); + hr = ISpeechRecognizer_CompileConstraintsAsync(recognizer, &operation); ok(hr == S_OK, "ISpeechRecognizer_CompileConstraintsAsync failed, hr %#lx.\n", hr); await_async_inspectable((IAsyncOperation_IInspectable *)operation, @@ -1881,6 +1887,11 @@ static void test_Recognition(void) IAsyncInfo_Release(info); + recog_state = 0xdeadbeef; + hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); + todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); + todo_wine ok(recog_state == SpeechRecognizerState_Capturing, "recog_state was %u.\n", recog_state); + /* * TODO: Use a loopback device together with prerecorded audio files to test the recognizer's functionality. */ @@ -1891,9 +1902,20 @@ static void test_Recognition(void) check_async_info((IInspectable *)action2, 3, Completed, S_OK); IAsyncAction_Release(action2); + recog_state = 0xdeadbeef; + hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); + todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); + todo_wine ok(recog_state == SpeechRecognizerState_Paused || /* Broken on Win10 1507 */ + broken(recog_state == SpeechRecognizerState_Capturing) , "recog_state was %u.\n", recog_state); + hr = ISpeechContinuousRecognitionSession_Resume(session); todo_wine ok(hr == S_OK, "ISpeechContinuousRecognitionSession_Resume failed, hr %#lx.\n", hr); + recog_state = 0xdeadbeef; + hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); + todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); + todo_wine ok(recog_state == SpeechRecognizerState_Capturing, "recog_state was %u.\n", recog_state); + hr = ISpeechContinuousRecognitionSession_StopAsync(session, &action2); ok(hr == S_OK, "ISpeechContinuousRecognitionSession_StopAsync failed, hr %#lx.\n", hr); @@ -1941,6 +1963,11 @@ static void test_Recognition(void) IAsyncAction_Release(action2); IAsyncAction_Release(action); + recog_state = 0xdeadbeef; + hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); + todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); + todo_wine ok(recog_state == SpeechRecognizerState_Idle, "recog_state was %u.\n", recog_state); + hr = ISpeechContinuousRecognitionSession_remove_ResultGenerated(session, token); ok(hr == S_OK, "ISpeechContinuousRecognitionSession_remove_ResultGenerated failed, hr %#lx.\n", hr); From 4a7e7e353c8e7c0870f483ffda0c3be89c72e536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Tue, 3 Jan 2023 12:15:05 +0100 Subject: [PATCH 2144/2777] windows.media.speech/tests: Test starting, stopping, pausing and resuming the recognition session. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl (cherry picked from commit 86fb17c8fbffd8bcc039ca4412393d26cef73278) CW-Bug-Id: #20134 --- dlls/windows.media.speech/tests/speech.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index c8bbf8d9d54..9f150d68433 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -18,6 +18,7 @@ #define COBJMACROS #include +#include "corerror.h" #include "windef.h" #include "winbase.h" #include "winerror.h" @@ -1865,6 +1866,11 @@ static void test_Recognition(void) await_async_void(action, &action_handler); + action2 = (void *)0xdeadbeef; + hr = ISpeechContinuousRecognitionSession_StartAsync(session, &action2); + todo_wine ok(hr == COR_E_INVALIDOPERATION, "ISpeechContinuousRecognitionSession_StartAsync failed, hr %#lx.\n", hr); + todo_wine ok(action2 == NULL, "action2 was %p.\n", action2); + hr = IAsyncAction_QueryInterface(action, &IID_IAsyncInfo, (void **)&info); ok(hr == S_OK, "IAsyncAction_QueryInterface failed, hr %#lx.\n", hr); check_async_info((IInspectable *)action, 1, Completed, S_OK); @@ -1908,6 +1914,17 @@ static void test_Recognition(void) todo_wine ok(recog_state == SpeechRecognizerState_Paused || /* Broken on Win10 1507 */ broken(recog_state == SpeechRecognizerState_Capturing) , "recog_state was %u.\n", recog_state); + /* Check what happens if we try to pause again, when the session is already paused. */ + hr = ISpeechContinuousRecognitionSession_PauseAsync(session, &action2); + ok(hr == S_OK, "ISpeechContinuousRecognitionSession_PauseAsync failed, hr %#lx.\n", hr); + await_async_void(action2, &action_handler); + check_async_info((IInspectable *)action2, 4, Completed, S_OK); + IAsyncAction_Release(action2); + + hr = ISpeechContinuousRecognitionSession_Resume(session); + todo_wine ok(hr == S_OK, "ISpeechContinuousRecognitionSession_Resume failed, hr %#lx.\n", hr); + + /* Resume when already resumed. */ hr = ISpeechContinuousRecognitionSession_Resume(session); todo_wine ok(hr == S_OK, "ISpeechContinuousRecognitionSession_Resume failed, hr %#lx.\n", hr); @@ -1947,7 +1964,7 @@ static void test_Recognition(void) hr = IAsyncInfo_Close(info); /* If IAsyncInfo_Close would wait for the handler to finish, the test would get stuck here. */ ok(hr == S_OK, "IAsyncInfo_Close failed, hr %#lx.\n", hr); - check_async_info((IInspectable *)action2, 4, AsyncStatus_Closed, S_OK); + check_async_info((IInspectable *)action2, 5, AsyncStatus_Closed, S_OK); set = SetEvent(action_handler.event_block); ok(set == TRUE, "Event 'event_block' wasn't set.\n"); @@ -1968,6 +1985,11 @@ static void test_Recognition(void) todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); todo_wine ok(recog_state == SpeechRecognizerState_Idle, "recog_state was %u.\n", recog_state); + /* Try stopping, when already stopped. */ + hr = ISpeechContinuousRecognitionSession_StopAsync(session, &action); + todo_wine ok(hr == COR_E_INVALIDOPERATION, "ISpeechContinuousRecognitionSession_StopAsync failed, hr %#lx.\n", hr); + todo_wine ok(action == NULL, "action was %p.\n", action); + hr = ISpeechContinuousRecognitionSession_remove_ResultGenerated(session, token); ok(hr == S_OK, "ISpeechContinuousRecognitionSession_remove_ResultGenerated failed, hr %#lx.\n", hr); From 79d158df1bada2e266246b4e646af9bcfa9b753e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Tue, 3 Jan 2023 14:16:06 +0100 Subject: [PATCH 2145/2777] windows.media.speech: Add a worker thread to the recognition session. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl (cherry picked from commit 9515736a85c19344f2f5f2d1752cf0036be9129b) CW-Bug-Id: #20134 --- dlls/windows.media.speech/private.h | 1 + dlls/windows.media.speech/recognizer.c | 132 +++++++++++++++++++++-- dlls/windows.media.speech/tests/speech.c | 8 +- 3 files changed, 131 insertions(+), 10 deletions(-) diff --git a/dlls/windows.media.speech/private.h b/dlls/windows.media.speech/private.h index f2abaf8b5d5..d03fe0e773e 100644 --- a/dlls/windows.media.speech/private.h +++ b/dlls/windows.media.speech/private.h @@ -23,6 +23,7 @@ #include #define COBJMACROS +#include "corerror.h" #include "windef.h" #include "winbase.h" #include "winstring.h" diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 54a0e165f5f..aabfd56694a 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -160,6 +160,10 @@ struct session struct list completed_handlers; struct list result_handlers; + + HANDLE worker_thread, worker_control_event; + BOOLEAN worker_running; + CRITICAL_SECTION cs; }; /* @@ -173,6 +177,31 @@ static inline struct session *impl_from_ISpeechContinuousRecognitionSession( ISp return CONTAINING_RECORD(iface, struct session, ISpeechContinuousRecognitionSession_iface); } +static DWORD CALLBACK session_worker_thread_cb( void *args ) +{ + ISpeechContinuousRecognitionSession *iface = args; + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + BOOLEAN running = TRUE; + DWORD status; + + SetThreadDescription(GetCurrentThread(), L"wine_speech_recognition_session_worker"); + + while (running) + { + status = WaitForMultipleObjects(1, &impl->worker_control_event, FALSE, INFINITE); + if (status == 0) /* worker_control_event signaled */ + { + EnterCriticalSection(&impl->cs); + running = impl->worker_running; + LeaveCriticalSection(&impl->cs); + } + + /* TODO: Send mic data to recognizer and handle results. */ + } + + return 0; +} + static HRESULT WINAPI session_QueryInterface( ISpeechContinuousRecognitionSession *iface, REFIID iid, void **out ) { struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); @@ -208,8 +237,24 @@ static ULONG WINAPI session_Release( ISpeechContinuousRecognitionSession *iface if (!ref) { + HANDLE thread; + + EnterCriticalSection(&impl->cs); + thread = impl->worker_thread; + impl->worker_running = FALSE; + impl->worker_thread = INVALID_HANDLE_VALUE; + LeaveCriticalSection(&impl->cs); + + SetEvent(impl->worker_control_event); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + typed_event_handlers_clear(&impl->completed_handlers); typed_event_handlers_clear(&impl->result_handlers); + + impl->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&impl->cs); + IVector_ISpeechRecognitionConstraint_Release(impl->constraints); free(impl); } @@ -254,8 +299,37 @@ static HRESULT session_start_async( IInspectable *invoker ) static HRESULT WINAPI session_StartAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action ) { - FIXME("iface %p, action %p stub!\n", iface, action); - return async_action_create(NULL, session_start_async, action); + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + HRESULT hr; + + TRACE("iface %p, action %p.\n", iface, action); + + if (FAILED(hr = async_action_create(NULL, session_start_async, action))) + return hr; + + EnterCriticalSection(&impl->cs); + if (impl->worker_running || impl->worker_thread) + { + hr = COR_E_INVALIDOPERATION; + } + else if (!(impl->worker_thread = CreateThread(NULL, 0, session_worker_thread_cb, impl, 0, NULL))) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + impl->worker_running = FALSE; + } + else + { + impl->worker_running = TRUE; + } + LeaveCriticalSection(&impl->cs); + + if (FAILED(hr)) + { + IAsyncAction_Release(*action); + *action = NULL; + } + + return hr; } static HRESULT WINAPI session_StartWithModeAsync( ISpeechContinuousRecognitionSession *iface, @@ -273,8 +347,45 @@ static HRESULT session_stop_async( IInspectable *invoker ) static HRESULT WINAPI session_StopAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action ) { - FIXME("iface %p, action %p stub!\n", iface, action); - return async_action_create(NULL, session_stop_async, action); + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + HANDLE thread; + HRESULT hr; + + TRACE("iface %p, action %p.\n", iface, action); + + if (FAILED(hr = async_action_create(NULL, session_stop_async, action))) + return hr; + + EnterCriticalSection(&impl->cs); + if (impl->worker_running && impl->worker_thread) + { + thread = impl->worker_thread; + impl->worker_thread = INVALID_HANDLE_VALUE; + impl->worker_running = FALSE; + } + else + { + hr = COR_E_INVALIDOPERATION; + } + LeaveCriticalSection(&impl->cs); + + if (SUCCEEDED(hr)) + { + SetEvent(impl->worker_control_event); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + + EnterCriticalSection(&impl->cs); + impl->worker_thread = NULL; + LeaveCriticalSection(&impl->cs); + } + else + { + IAsyncAction_Release(*action); + *action = NULL; + } + + return hr; } static HRESULT WINAPI session_CancelAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action ) @@ -818,9 +929,18 @@ static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface list_init(&session->completed_handlers); list_init(&session->result_handlers); + if (!(session->worker_control_event = CreateEventW(NULL, FALSE, FALSE, NULL))) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto error; + } + if (FAILED(hr = vector_inspectable_create(&constraints_iids, (IVector_IInspectable**)&session->constraints))) goto error; + InitializeCriticalSection(&session->cs); + session->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": recognition_session.cs"); + /* Init ISpeechRecognizer */ impl->ISpeechRecognizer_iface.lpVtbl = &speech_recognizer_vtbl; impl->IClosable_iface.lpVtbl = &closable_vtbl; @@ -828,13 +948,13 @@ static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface impl->session = &session->ISpeechContinuousRecognitionSession_iface; impl->ref = 1; - TRACE("created SpeechRecognizer %p.\n", impl); - *speechrecognizer = &impl->ISpeechRecognizer_iface; + TRACE("created SpeechRecognizer %p.\n", *speechrecognizer); return S_OK; error: if (session->constraints) IVector_ISpeechRecognitionConstraint_Release(session->constraints); + if (session->worker_control_event) CloseHandle(session->worker_control_event); free(session); free(impl); diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 9f150d68433..9ef3f56c3d5 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -1868,8 +1868,8 @@ static void test_Recognition(void) action2 = (void *)0xdeadbeef; hr = ISpeechContinuousRecognitionSession_StartAsync(session, &action2); - todo_wine ok(hr == COR_E_INVALIDOPERATION, "ISpeechContinuousRecognitionSession_StartAsync failed, hr %#lx.\n", hr); - todo_wine ok(action2 == NULL, "action2 was %p.\n", action2); + ok(hr == COR_E_INVALIDOPERATION, "ISpeechContinuousRecognitionSession_StartAsync failed, hr %#lx.\n", hr); + ok(action2 == NULL, "action2 was %p.\n", action2); hr = IAsyncAction_QueryInterface(action, &IID_IAsyncInfo, (void **)&info); ok(hr == S_OK, "IAsyncAction_QueryInterface failed, hr %#lx.\n", hr); @@ -1987,8 +1987,8 @@ static void test_Recognition(void) /* Try stopping, when already stopped. */ hr = ISpeechContinuousRecognitionSession_StopAsync(session, &action); - todo_wine ok(hr == COR_E_INVALIDOPERATION, "ISpeechContinuousRecognitionSession_StopAsync failed, hr %#lx.\n", hr); - todo_wine ok(action == NULL, "action was %p.\n", action); + ok(hr == COR_E_INVALIDOPERATION, "ISpeechContinuousRecognitionSession_StopAsync failed, hr %#lx.\n", hr); + ok(action == NULL, "action was %p.\n", action); hr = ISpeechContinuousRecognitionSession_remove_ResultGenerated(session, token); ok(hr == S_OK, "ISpeechContinuousRecognitionSession_remove_ResultGenerated failed, hr %#lx.\n", hr); From 9456eff5f1f6553cd6064f2a6fff096fa2a79ef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Sat, 14 Jan 2023 23:15:09 +0100 Subject: [PATCH 2146/2777] windows.media.speech/tests: Check if stopping the session resets the paused state. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl (cherry picked from commit e1c4035efd9d916b09d141e6fb2012450f867f96) CW-Bug-Id: #20134 --- dlls/windows.media.speech/tests/speech.c | 50 ++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 9ef3f56c3d5..adfdf690ee2 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -1911,8 +1911,8 @@ static void test_Recognition(void) recog_state = 0xdeadbeef; hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); - todo_wine ok(recog_state == SpeechRecognizerState_Paused || /* Broken on Win10 1507 */ - broken(recog_state == SpeechRecognizerState_Capturing) , "recog_state was %u.\n", recog_state); + todo_wine ok(recog_state == SpeechRecognizerState_Paused || + broken(recog_state == SpeechRecognizerState_Capturing) /* Broken on Win10 1507 */, "recog_state was %u.\n", recog_state); /* Check what happens if we try to pause again, when the session is already paused. */ hr = ISpeechContinuousRecognitionSession_PauseAsync(session, &action2); @@ -1968,7 +1968,7 @@ static void test_Recognition(void) set = SetEvent(action_handler.event_block); ok(set == TRUE, "Event 'event_block' wasn't set.\n"); - ok(!WaitForSingleObject(put_thread , 1000), "Wait for put_thread failed.\n"); + ok(!WaitForSingleObject(put_thread, 1000), "Wait for put_thread failed.\n"); IAsyncInfo_Release(info); CloseHandle(action_handler.event_finished); @@ -1990,6 +1990,50 @@ static void test_Recognition(void) ok(hr == COR_E_INVALIDOPERATION, "ISpeechContinuousRecognitionSession_StopAsync failed, hr %#lx.\n", hr); ok(action == NULL, "action was %p.\n", action); + /* Test, if Start/StopAsync resets the pause state. */ + hr = ISpeechContinuousRecognitionSession_StartAsync(session, &action); + ok(hr == S_OK, "ISpeechContinuousRecognitionSession_StartAsync failed, hr %#lx.\n", hr); + await_async_void(action, &action_handler); + IAsyncAction_Release(action); + + hr = ISpeechContinuousRecognitionSession_PauseAsync(session, &action); + ok(hr == S_OK, "ISpeechContinuousRecognitionSession_PauseAsync failed, hr %#lx.\n", hr); + await_async_void(action, &action_handler); + IAsyncAction_Release(action); + + recog_state = 0xdeadbeef; + hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); + todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); + todo_wine ok(recog_state == SpeechRecognizerState_Paused || + broken(recog_state == SpeechRecognizerState_Capturing) /* Broken on Win10 1507 */, "recog_state was %u.\n", recog_state); + + hr = ISpeechContinuousRecognitionSession_StopAsync(session, &action); + ok(hr == S_OK, "ISpeechContinuousRecognitionSession_PauseAsync failed, hr %#lx.\n", hr); + await_async_void(action, &action_handler); + IAsyncAction_Release(action); + + recog_state = 0xdeadbeef; + hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); + todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); + todo_wine ok(recog_state == SpeechRecognizerState_Idle, "recog_state was %u.\n", recog_state); + + hr = ISpeechContinuousRecognitionSession_StartAsync(session, &action); + ok(hr == S_OK, "ISpeechContinuousRecognitionSession_PauseAsync failed, hr %#lx.\n", hr); + await_async_void(action, &action_handler); + IAsyncAction_Release(action); + + recog_state = 0xdeadbeef; + hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); + todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); + todo_wine ok(recog_state == SpeechRecognizerState_Capturing + || broken(recog_state == SpeechRecognizerState_Idle) /* Sometimes Windows is a little behind. */, + "recog_state was %u.\n", recog_state); + + hr = ISpeechContinuousRecognitionSession_StopAsync(session, &action); + ok(hr == S_OK, "ISpeechContinuousRecognitionSession_PauseAsync failed, hr %#lx.\n", hr); + await_async_void(action, &action_handler); + IAsyncAction_Release(action); + hr = ISpeechContinuousRecognitionSession_remove_ResultGenerated(session, token); ok(hr == S_OK, "ISpeechContinuousRecognitionSession_remove_ResultGenerated failed, hr %#lx.\n", hr); From 733d357baf29132e2a53c49c5e0c685a9003d734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Tue, 3 Jan 2023 14:26:57 +0100 Subject: [PATCH 2147/2777] windows.media.speech: Allow the recognition session worker to be paused. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl (cherry picked from commit c8a68f2a7a7d458bdf27913eb52f5544a618b0ec) CW-Bug-Id: #20134 --- dlls/windows.media.speech/recognizer.c | 41 +++++++++++++++++++++--- dlls/windows.media.speech/tests/speech.c | 4 +-- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index aabfd56694a..80cf40fbef9 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -162,7 +162,7 @@ struct session struct list result_handlers; HANDLE worker_thread, worker_control_event; - BOOLEAN worker_running; + BOOLEAN worker_running, worker_paused; CRITICAL_SECTION cs; }; @@ -362,6 +362,7 @@ static HRESULT WINAPI session_StopAsync( ISpeechContinuousRecognitionSession *if thread = impl->worker_thread; impl->worker_thread = INVALID_HANDLE_VALUE; impl->worker_running = FALSE; + impl->worker_paused = FALSE; } else { @@ -401,14 +402,44 @@ static HRESULT session_pause_async( IInspectable *invoker ) static HRESULT WINAPI session_PauseAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action ) { - FIXME("iface %p, action %p stub!\n", iface, action); - return async_action_create(NULL, session_pause_async, action); + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + HRESULT hr = S_OK; + + TRACE("iface %p, action %p.\n", iface, action); + + *action = NULL; + + if (FAILED(hr = async_action_create(NULL, session_pause_async, action))) + return hr; + + EnterCriticalSection(&impl->cs); + if (impl->worker_running) + { + impl->worker_paused = TRUE; + } + LeaveCriticalSection(&impl->cs); + + SetEvent(impl->worker_control_event); + + return hr; } static HRESULT WINAPI session_Resume( ISpeechContinuousRecognitionSession *iface ) { - FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; + struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + + TRACE("iface %p.\n", iface); + + EnterCriticalSection(&impl->cs); + if (impl->worker_running) + { + impl->worker_paused = FALSE; + } + LeaveCriticalSection(&impl->cs); + + SetEvent(impl->worker_control_event); + + return S_OK; } static HRESULT WINAPI session_add_Completed( ISpeechContinuousRecognitionSession *iface, diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index adfdf690ee2..b767fd90b11 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -1922,11 +1922,11 @@ static void test_Recognition(void) IAsyncAction_Release(action2); hr = ISpeechContinuousRecognitionSession_Resume(session); - todo_wine ok(hr == S_OK, "ISpeechContinuousRecognitionSession_Resume failed, hr %#lx.\n", hr); + ok(hr == S_OK, "ISpeechContinuousRecognitionSession_Resume failed, hr %#lx.\n", hr); /* Resume when already resumed. */ hr = ISpeechContinuousRecognitionSession_Resume(session); - todo_wine ok(hr == S_OK, "ISpeechContinuousRecognitionSession_Resume failed, hr %#lx.\n", hr); + ok(hr == S_OK, "ISpeechContinuousRecognitionSession_Resume failed, hr %#lx.\n", hr); recog_state = 0xdeadbeef; hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); From c0fe26cdef844395f919750a8d504054abe7f207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Fri, 6 Jan 2023 18:19:31 +0100 Subject: [PATCH 2148/2777] windows.media.speech: Add an audio capturing system. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl (cherry picked from commit 85ce23a9bf8ac6501e042590448e710012c15987) CW-Bug-Id: #20134 --- dlls/windows.media.speech/recognizer.c | 124 ++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 5 deletions(-) diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 80cf40fbef9..0def2fc3cbd 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -19,6 +19,10 @@ #include "private.h" +#include "initguid.h" +#include "audioclient.h" +#include "mmdeviceapi.h" + #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(speech); @@ -161,7 +165,11 @@ struct session struct list completed_handlers; struct list result_handlers; - HANDLE worker_thread, worker_control_event; + IAudioClient *audio_client; + IAudioCaptureClient *capture_client; + WAVEFORMATEX capture_wfx; + + HANDLE worker_thread, worker_control_event, audio_buf_event; BOOLEAN worker_running, worker_paused; CRITICAL_SECTION cs; }; @@ -181,25 +189,73 @@ static DWORD CALLBACK session_worker_thread_cb( void *args ) { ISpeechContinuousRecognitionSession *iface = args; struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); - BOOLEAN running = TRUE; - DWORD status; + BOOLEAN running = TRUE, paused = FALSE; + DWORD flags, status; + HANDLE events[2]; + BYTE *audio_buf; + HRESULT hr; SetThreadDescription(GetCurrentThread(), L"wine_speech_recognition_session_worker"); + if (FAILED(hr = IAudioClient_Start(impl->audio_client))) + goto error; + while (running) { - status = WaitForMultipleObjects(1, &impl->worker_control_event, FALSE, INFINITE); + BOOLEAN old_paused = paused; + UINT32 count = 0; + + events[count++] = impl->worker_control_event; + if (!paused) events[count++] = impl->audio_buf_event; + + status = WaitForMultipleObjects(count, events, FALSE, INFINITE); if (status == 0) /* worker_control_event signaled */ { EnterCriticalSection(&impl->cs); + paused = impl->worker_paused; running = impl->worker_running; LeaveCriticalSection(&impl->cs); + + if (old_paused < paused) + { + if (FAILED(hr = IAudioClient_Stop(impl->audio_client))) goto error; + if (FAILED(hr = IAudioClient_Reset(impl->audio_client))) goto error; + TRACE("session worker paused.\n"); + } + else if (old_paused > paused) + { + if (FAILED(hr = IAudioClient_Start(impl->audio_client))) goto error; + TRACE("session worker resumed.\n"); + } } + else if (status == 1) /* audio_buf_event signaled */ + { + UINT32 frames_available = 0; - /* TODO: Send mic data to recognizer and handle results. */ + while (IAudioCaptureClient_GetBuffer(impl->capture_client, &audio_buf, &frames_available, &flags, NULL, NULL) == S_OK) + { + /* TODO: Send mic data to recognizer and handle results. */ + IAudioCaptureClient_ReleaseBuffer(impl->capture_client, frames_available); + } + } + else + { + ERR("Unexpected state entered. Aborting worker.\n"); + break; + } } + if (FAILED(hr = IAudioClient_Stop(impl->audio_client))) + ERR("IAudioClient_Stop failed with %#lx.\n", hr); + + if (FAILED(hr = IAudioClient_Reset(impl->audio_client))) + ERR("IAudioClient_Reset failed with %#lx.\n", hr); + return 0; + +error: + ERR("The recognition session worker encountered a serious error and needs to stop. hr: %lx.\n", hr); + return 1; } static HRESULT WINAPI session_QueryInterface( ISpeechContinuousRecognitionSession *iface, REFIID iid, void **out ) @@ -252,6 +308,9 @@ static ULONG WINAPI session_Release( ISpeechContinuousRecognitionSession *iface typed_event_handlers_clear(&impl->completed_handlers); typed_event_handlers_clear(&impl->result_handlers); + IAudioCaptureClient_Release(impl->capture_client); + IAudioClient_Release(impl->audio_client); + impl->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&impl->cs); @@ -926,6 +985,55 @@ static const struct IActivationFactoryVtbl activation_factory_vtbl = DEFINE_IINSPECTABLE(recognizer_factory, ISpeechRecognizerFactory, struct recognizer_statics, IActivationFactory_iface) +static HRESULT recognizer_factory_create_audio_capture(struct session *session) +{ + const REFERENCE_TIME buffer_duration = 5000000; /* 0.5 second */ + IMMDeviceEnumerator *mm_enum = NULL; + IMMDevice *mm_device = NULL; + WAVEFORMATEX wfx = { 0 }; + WCHAR *str = NULL; + HRESULT hr = S_OK; + + if (!(session->audio_buf_event = CreateEventW(NULL, FALSE, FALSE, NULL))) + return HRESULT_FROM_WIN32(GetLastError()); + + if (FAILED(hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void **)&mm_enum))) + goto cleanup; + + if (FAILED(hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(mm_enum, eCapture, eMultimedia, &mm_device))) + goto cleanup; + + if (FAILED(hr = IMMDevice_Activate(mm_device, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void **)&session->audio_client))) + goto cleanup; + + hr = IMMDevice_GetId(mm_device, &str); + TRACE("selected capture device ID: %s, hr %#lx\n", debugstr_w(str), hr); + + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nSamplesPerSec = 16000; + wfx.nChannels = 1; + wfx.wBitsPerSample = 16; + wfx.nBlockAlign = (wfx.wBitsPerSample + 7) / 8 * wfx.nChannels; + wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; + TRACE("wfx tag %u, channels %u, samples %lu, bits %u, align %u.\n", wfx.wFormatTag, wfx.nChannels, wfx.nSamplesPerSec, wfx.wBitsPerSample, wfx.nBlockAlign); + + if (FAILED(hr = IAudioClient_Initialize(session->audio_client, AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, buffer_duration, 0, &wfx, NULL))) + goto cleanup; + + if (FAILED(hr = IAudioClient_SetEventHandle(session->audio_client, session->audio_buf_event))) + goto cleanup; + + hr = IAudioClient_GetService(session->audio_client, &IID_IAudioCaptureClient, (void **)&session->capture_client); + + session->capture_wfx = wfx; + +cleanup: + if (mm_device) IMMDevice_Release(mm_device); + if (mm_enum) IMMDeviceEnumerator_Release(mm_enum); + CoTaskMemFree(str); + return hr; +} + static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface, ILanguage *language, ISpeechRecognizer **speechrecognizer ) { struct recognizer *impl; @@ -969,6 +1077,9 @@ static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface if (FAILED(hr = vector_inspectable_create(&constraints_iids, (IVector_IInspectable**)&session->constraints))) goto error; + if (FAILED(hr = recognizer_factory_create_audio_capture(session))) + goto error; + InitializeCriticalSection(&session->cs); session->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": recognition_session.cs"); @@ -984,6 +1095,9 @@ static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface return S_OK; error: + if (session->capture_client) IAudioCaptureClient_Release(session->capture_client); + if (session->audio_client) IAudioClient_Release(session->audio_client); + if (session->audio_buf_event) CloseHandle(session->audio_buf_event); if (session->constraints) IVector_ISpeechRecognitionConstraint_Release(session->constraints); if (session->worker_control_event) CloseHandle(session->worker_control_event); free(session); From e399d34441f950d3038dd6270d9461f2c1f83f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Sun, 15 Jan 2023 13:15:17 +0100 Subject: [PATCH 2149/2777] windows.media.speech: Partially implement the speech recognizer state. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl (cherry picked from commit 74129bd8fb619806b1c4fcb09c0db2fedca72efd) CW-Bug-Id: #20134 --- dlls/windows.media.speech/recognizer.c | 21 +++++++++++-- dlls/windows.media.speech/tests/speech.c | 40 ++++++++++++------------ 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 0def2fc3cbd..72c08a1b06c 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -162,6 +162,8 @@ struct session IVector_ISpeechRecognitionConstraint *constraints; + SpeechRecognizerState recognizer_state; + struct list completed_handlers; struct list result_handlers; @@ -379,6 +381,7 @@ static HRESULT WINAPI session_StartAsync( ISpeechContinuousRecognitionSession *i else { impl->worker_running = TRUE; + impl->recognizer_state = SpeechRecognizerState_Capturing; } LeaveCriticalSection(&impl->cs); @@ -422,6 +425,7 @@ static HRESULT WINAPI session_StopAsync( ISpeechContinuousRecognitionSession *if impl->worker_thread = INVALID_HANDLE_VALUE; impl->worker_running = FALSE; impl->worker_paused = FALSE; + impl->recognizer_state = SpeechRecognizerState_Idle; } else { @@ -475,6 +479,7 @@ static HRESULT WINAPI session_PauseAsync( ISpeechContinuousRecognitionSession *i if (impl->worker_running) { impl->worker_paused = TRUE; + impl->recognizer_state = SpeechRecognizerState_Paused; } LeaveCriticalSection(&impl->cs); @@ -493,6 +498,7 @@ static HRESULT WINAPI session_Resume( ISpeechContinuousRecognitionSession *iface if (impl->worker_running) { impl->worker_paused = FALSE; + impl->recognizer_state = SpeechRecognizerState_Capturing; } LeaveCriticalSection(&impl->cs); @@ -816,8 +822,19 @@ static HRESULT WINAPI recognizer2_get_ContinuousRecognitionSession( ISpeechRecog static HRESULT WINAPI recognizer2_get_State( ISpeechRecognizer2 *iface, SpeechRecognizerState *state ) { - FIXME("iface %p, state %p stub!\n", iface, state); - return E_NOTIMPL; + struct recognizer *impl = impl_from_ISpeechRecognizer2(iface); + struct session *session = impl_from_ISpeechContinuousRecognitionSession(impl->session); + + FIXME("iface %p, state %p not all states are supported, yet.\n", iface, state); + + if (!state) + return E_POINTER; + + EnterCriticalSection(&session->cs); + *state = session->recognizer_state; + LeaveCriticalSection(&session->cs); + + return S_OK; } static HRESULT WINAPI recognizer2_StopRecognitionAsync( ISpeechRecognizer2 *iface, IAsyncAction **action ) diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index b767fd90b11..fd013a1016e 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -1845,8 +1845,8 @@ static void test_Recognition(void) recog_state = 0xdeadbeef; hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); - todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); - todo_wine ok(recog_state == SpeechRecognizerState_Idle, "recog_state was %u.\n", recog_state); + ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); + ok(recog_state == SpeechRecognizerState_Idle, "recog_state was %u.\n", recog_state); hr = ISpeechRecognizer_CompileConstraintsAsync(recognizer, &operation); ok(hr == S_OK, "ISpeechRecognizer_CompileConstraintsAsync failed, hr %#lx.\n", hr); @@ -1895,8 +1895,8 @@ static void test_Recognition(void) recog_state = 0xdeadbeef; hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); - todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); - todo_wine ok(recog_state == SpeechRecognizerState_Capturing, "recog_state was %u.\n", recog_state); + ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); + ok(recog_state == SpeechRecognizerState_Capturing, "recog_state was %u.\n", recog_state); /* * TODO: Use a loopback device together with prerecorded audio files to test the recognizer's functionality. @@ -1910,9 +1910,9 @@ static void test_Recognition(void) recog_state = 0xdeadbeef; hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); - todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); - todo_wine ok(recog_state == SpeechRecognizerState_Paused || - broken(recog_state == SpeechRecognizerState_Capturing) /* Broken on Win10 1507 */, "recog_state was %u.\n", recog_state); + ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); + ok(recog_state == SpeechRecognizerState_Paused || + broken(recog_state == SpeechRecognizerState_Capturing) /* Broken on Win10 1507 */, "recog_state was %u.\n", recog_state); /* Check what happens if we try to pause again, when the session is already paused. */ hr = ISpeechContinuousRecognitionSession_PauseAsync(session, &action2); @@ -1930,8 +1930,8 @@ static void test_Recognition(void) recog_state = 0xdeadbeef; hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); - todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); - todo_wine ok(recog_state == SpeechRecognizerState_Capturing, "recog_state was %u.\n", recog_state); + ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); + ok(recog_state == SpeechRecognizerState_Capturing, "recog_state was %u.\n", recog_state); hr = ISpeechContinuousRecognitionSession_StopAsync(session, &action2); ok(hr == S_OK, "ISpeechContinuousRecognitionSession_StopAsync failed, hr %#lx.\n", hr); @@ -1982,8 +1982,8 @@ static void test_Recognition(void) recog_state = 0xdeadbeef; hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); - todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); - todo_wine ok(recog_state == SpeechRecognizerState_Idle, "recog_state was %u.\n", recog_state); + ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); + ok(recog_state == SpeechRecognizerState_Idle, "recog_state was %u.\n", recog_state); /* Try stopping, when already stopped. */ hr = ISpeechContinuousRecognitionSession_StopAsync(session, &action); @@ -2003,9 +2003,9 @@ static void test_Recognition(void) recog_state = 0xdeadbeef; hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); - todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); - todo_wine ok(recog_state == SpeechRecognizerState_Paused || - broken(recog_state == SpeechRecognizerState_Capturing) /* Broken on Win10 1507 */, "recog_state was %u.\n", recog_state); + ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); + ok(recog_state == SpeechRecognizerState_Paused || + broken(recog_state == SpeechRecognizerState_Capturing) /* Broken on Win10 1507 */, "recog_state was %u.\n", recog_state); hr = ISpeechContinuousRecognitionSession_StopAsync(session, &action); ok(hr == S_OK, "ISpeechContinuousRecognitionSession_PauseAsync failed, hr %#lx.\n", hr); @@ -2014,8 +2014,8 @@ static void test_Recognition(void) recog_state = 0xdeadbeef; hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); - todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); - todo_wine ok(recog_state == SpeechRecognizerState_Idle, "recog_state was %u.\n", recog_state); + ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); + ok(recog_state == SpeechRecognizerState_Idle, "recog_state was %u.\n", recog_state); hr = ISpeechContinuousRecognitionSession_StartAsync(session, &action); ok(hr == S_OK, "ISpeechContinuousRecognitionSession_PauseAsync failed, hr %#lx.\n", hr); @@ -2024,10 +2024,10 @@ static void test_Recognition(void) recog_state = 0xdeadbeef; hr = ISpeechRecognizer2_get_State(recognizer2, &recog_state); - todo_wine ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); - todo_wine ok(recog_state == SpeechRecognizerState_Capturing - || broken(recog_state == SpeechRecognizerState_Idle) /* Sometimes Windows is a little behind. */, - "recog_state was %u.\n", recog_state); + ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); + ok(recog_state == SpeechRecognizerState_Capturing + || broken(recog_state == SpeechRecognizerState_Idle) /* Sometimes Windows is a little behind. */, + "recog_state was %u.\n", recog_state); hr = ISpeechContinuousRecognitionSession_StopAsync(session, &action); ok(hr == S_OK, "ISpeechContinuousRecognitionSession_PauseAsync failed, hr %#lx.\n", hr); From 03fba3bb5cecfcbb28a5b42e7a1c8f8456f3e980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Wed, 18 May 2022 18:47:30 +0200 Subject: [PATCH 2150/2777] windows.media.speech: Store recorded audio in a temporary ringbuffer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl (cherry picked from commit d1d186eef20f4960b32f1f0d1b7df41726b43792) CW-Bug-Id: #20134 --- dlls/windows.media.speech/recognizer.c | 34 +++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 72c08a1b06c..c2f386206b8 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -192,9 +192,10 @@ static DWORD CALLBACK session_worker_thread_cb( void *args ) ISpeechContinuousRecognitionSession *iface = args; struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); BOOLEAN running = TRUE, paused = FALSE; + UINT32 frame_count, tmp_buf_size; + BYTE *audio_buf, *tmp_buf; DWORD flags, status; HANDLE events[2]; - BYTE *audio_buf; HRESULT hr; SetThreadDescription(GetCurrentThread(), L"wine_speech_recognition_session_worker"); @@ -202,6 +203,16 @@ static DWORD CALLBACK session_worker_thread_cb( void *args ) if (FAILED(hr = IAudioClient_Start(impl->audio_client))) goto error; + if (FAILED(hr = IAudioClient_GetBufferSize(impl->audio_client, &frame_count))) + goto error; + + tmp_buf_size = sizeof(*tmp_buf) * frame_count * impl->capture_wfx.nBlockAlign; + if (!(tmp_buf = malloc(tmp_buf_size))) + { + ERR("Memory allocation failed.\n"); + return 1; + } + while (running) { BOOLEAN old_paused = paused; @@ -232,13 +243,28 @@ static DWORD CALLBACK session_worker_thread_cb( void *args ) } else if (status == 1) /* audio_buf_event signaled */ { + SIZE_T packet_size = 0, tmp_buf_offset = 0; UINT32 frames_available = 0; - while (IAudioCaptureClient_GetBuffer(impl->capture_client, &audio_buf, &frames_available, &flags, NULL, NULL) == S_OK) + while (tmp_buf_offset < tmp_buf_size + && IAudioCaptureClient_GetBuffer(impl->capture_client, &audio_buf, &frames_available, &flags, NULL, NULL) == S_OK) { - /* TODO: Send mic data to recognizer and handle results. */ + packet_size = frames_available * impl->capture_wfx.nBlockAlign; + if (tmp_buf_offset + packet_size > tmp_buf_size) + { + /* Defer processing until the next iteration of the worker loop. */ + IAudioCaptureClient_ReleaseBuffer(impl->capture_client, 0); + SetEvent(impl->audio_buf_event); + break; + } + + memcpy(tmp_buf + tmp_buf_offset, audio_buf, packet_size); + tmp_buf_offset += packet_size; + IAudioCaptureClient_ReleaseBuffer(impl->capture_client, frames_available); } + + /* TODO: Send mic data to recognizer and handle results. */ } else { @@ -253,6 +279,8 @@ static DWORD CALLBACK session_worker_thread_cb( void *args ) if (FAILED(hr = IAudioClient_Reset(impl->audio_client))) ERR("IAudioClient_Reset failed with %#lx.\n", hr); + free(tmp_buf); + return 0; error: From c909a8e111b8ad289d5cf7fa9bf37f01447de129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Mon, 13 Feb 2023 15:05:53 +0100 Subject: [PATCH 2151/2777] windows.media.speech: Add Vosk checks to autoconf. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl CW-Bug-Id: #20134 --- configure.ac | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index e4b85800b4b..c58fced1539 100644 --- a/configure.ac +++ b/configure.ac @@ -60,6 +60,7 @@ AC_ARG_WITH(udev, AS_HELP_STRING([--without-udev],[do not use udev (plug an AC_ARG_WITH(unwind, AS_HELP_STRING([--without-unwind],[do not use the libunwind library (exception handling)])) AC_ARG_WITH(usb, AS_HELP_STRING([--without-usb],[do not use the libusb library])) AC_ARG_WITH(v4l2, AS_HELP_STRING([--without-v4l2],[do not use v4l2 (video capture)])) +AC_ARG_WITH(vosk, AS_HELP_STRING([--without-vosk],[do not use Vosk])) AC_ARG_WITH(vulkan, AS_HELP_STRING([--without-vulkan],[do not use Vulkan])) AC_ARG_WITH(xcomposite,AS_HELP_STRING([--without-xcomposite],[do not use the Xcomposite extension]), [if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xcomposite_h=no; fi]) @@ -488,7 +489,8 @@ AC_CHECK_HEADERS(\ syscall.h \ utime.h \ valgrind/memcheck.h \ - valgrind/valgrind.h + valgrind/valgrind.h \ + vosk_api.h ) WINE_HEADER_MAJOR() AC_HEADER_STAT() @@ -1793,6 +1795,14 @@ then WINE_WARNING([No sound system was found. Windows applications will be silent.]) fi +dnl **** Check for Vosk **** +if test x$with_vosk != xno +then + WINE_CHECK_SONAME(vosk,vosk_recognizer_new) +fi +WINE_NOTICE_WITH(vosk,[test x$ac_cv_lib_soname_vosk = x], + [libvosk ${notice_platform}development files not found, speech recognition won't be supported.]) + dnl *** Check for Vulkan *** if test "x$with_vulkan" != "xno" then From 2778fd4b80e6b80a352e1fea9e01721bca2b0bee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Mon, 13 Feb 2023 00:17:50 +0100 Subject: [PATCH 2152/2777] windows.media.speech: Add unixlib stub. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl CW-Bug-Id: #20134 --- dlls/windows.media.speech/Makefile.in | 2 + dlls/windows.media.speech/main.c | 26 ++++++ dlls/windows.media.speech/private.h | 4 + dlls/windows.media.speech/unixlib.c | 122 ++++++++++++++++++++++++++ dlls/windows.media.speech/unixlib.h | 39 ++++++++ 5 files changed, 193 insertions(+) create mode 100644 dlls/windows.media.speech/unixlib.c create mode 100644 dlls/windows.media.speech/unixlib.h diff --git a/dlls/windows.media.speech/Makefile.in b/dlls/windows.media.speech/Makefile.in index 10903cb1d7b..64376514d58 100644 --- a/dlls/windows.media.speech/Makefile.in +++ b/dlls/windows.media.speech/Makefile.in @@ -1,4 +1,5 @@ MODULE = windows.media.speech.dll +UNIXLIB = windows.media.speech.so IMPORTS = combase uuid C_SRCS = \ @@ -8,6 +9,7 @@ C_SRCS = \ main.c \ recognizer.c \ synthesizer.c \ + unixlib.c \ vector.c IDL_SRCS = classes.idl diff --git a/dlls/windows.media.speech/main.c b/dlls/windows.media.speech/main.c index e772a791588..d53e1599eb8 100644 --- a/dlls/windows.media.speech/main.c +++ b/dlls/windows.media.speech/main.c @@ -20,10 +20,36 @@ #include "initguid.h" #include "private.h" +#include "unixlib.h" + #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(speech); +BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved ) +{ + NTSTATUS status; + + switch (reason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(instance); + + if ((status = __wine_init_unix_call())) + ERR("loading the unixlib failed with status %#lx.\n", status); + + if ((status = WINE_UNIX_CALL(unix_process_attach, NULL))) + WARN("initializing the unixlib failed with status %#lx.\n", status); + + break; + case DLL_PROCESS_DETACH: + WINE_UNIX_CALL(unix_process_detach, NULL); + break; + } + + return TRUE; +} + HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out) { FIXME("clsid %s, riid %s, out %p stub!\n", debugstr_guid(clsid), debugstr_guid(riid), out); diff --git a/dlls/windows.media.speech/private.h b/dlls/windows.media.speech/private.h index d03fe0e773e..4b6a8327d6e 100644 --- a/dlls/windows.media.speech/private.h +++ b/dlls/windows.media.speech/private.h @@ -22,6 +22,10 @@ #include +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "winerror.h" +#include "winternl.h" #define COBJMACROS #include "corerror.h" #include "windef.h" diff --git a/dlls/windows.media.speech/unixlib.c b/dlls/windows.media.speech/unixlib.c new file mode 100644 index 00000000000..d6f748b9426 --- /dev/null +++ b/dlls/windows.media.speech/unixlib.c @@ -0,0 +1,122 @@ +/* + * Unixlib for Windows.Media.Speech + * + * Copyright 2023 Bernhard Kölbl 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 + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include +#include +#include +#include +#include + +#ifdef SONAME_LIBVOSK +#include +#endif + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "winerror.h" +#include "winternl.h" + +#include "wine/debug.h" + +#include "unixlib.h" + +WINE_DEFAULT_DEBUG_CHANNEL(speech); +#ifdef SONAME_LIBVOSK +WINE_DECLARE_DEBUG_CHANNEL(winediag); + +static void *vosk_handle; +#define MAKE_FUNCPTR( f ) static typeof(f) * p_##f +MAKE_FUNCPTR(vosk_model_new); +MAKE_FUNCPTR(vosk_model_free); +MAKE_FUNCPTR(vosk_recognizer_new); +MAKE_FUNCPTR(vosk_recognizer_free); +#undef MAKE_FUNCPTR + +static NTSTATUS process_attach( void *args ) +{ + if (!(vosk_handle = dlopen(SONAME_LIBVOSK, RTLD_NOW))) + { + ERR_(winediag)("Wine is unable to load the Unix side dependencies for speech recognition. " + "Make sure Vosk is installed and up to date on your system and try again.\n"); + return STATUS_DLL_NOT_FOUND; + } + +#define LOAD_FUNCPTR( f ) \ + if (!(p_##f = dlsym(vosk_handle, #f))) \ + { \ + ERR("failed to load %s\n", #f); \ + goto error; \ + } + LOAD_FUNCPTR(vosk_model_new) + LOAD_FUNCPTR(vosk_model_free) + LOAD_FUNCPTR(vosk_recognizer_new) + LOAD_FUNCPTR(vosk_recognizer_free) +#undef LOAD_FUNCPTR + + return STATUS_SUCCESS; + +error: + dlclose(vosk_handle); + vosk_handle = NULL; + return STATUS_DLL_NOT_FOUND; +} + +static NTSTATUS process_detach( void *args ) +{ + if (vosk_handle) + { + dlclose(vosk_handle); + vosk_handle = NULL; + } + return STATUS_SUCCESS; +} + +#else /* SONAME_LIBVOSK */ + +#define MAKE_UNSUPPORTED_FUNC( f ) \ + static NTSTATUS f( void *args ) \ + { \ + ERR("wine was compiled without Vosk support. Speech recognition won't work.\n"); \ + return STATUS_NOT_SUPPORTED; \ + } + +MAKE_UNSUPPORTED_FUNC(process_attach) +MAKE_UNSUPPORTED_FUNC(process_detach) +#undef MAKE_UNSUPPORTED_FUNC + +#endif /* SONAME_LIBVOSK */ + +unixlib_entry_t __wine_unix_call_funcs[] = +{ + process_attach, + process_detach, +}; + +unixlib_entry_t __wine_unix_call_wow64_funcs[] = +{ + process_attach, + process_detach, +}; diff --git a/dlls/windows.media.speech/unixlib.h b/dlls/windows.media.speech/unixlib.h new file mode 100644 index 00000000000..6c337e54511 --- /dev/null +++ b/dlls/windows.media.speech/unixlib.h @@ -0,0 +1,39 @@ +/* + * Unix library interface for Windows.Media.Speech + * + * Copyright 2023 Bernhard Kölbl 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 + */ + +#ifndef __WINE_WINDOWS_MEDIA_SPEECH_UNIXLIB_H +#define __WINE_WINDOWS_MEDIA_SPEECH_UNIXLIB_H + +#include +#include + +#include "windef.h" +#include "winternl.h" +#include "wtypes.h" + +#include "wine/unixlib.h" + +enum unix_funcs +{ + unix_process_attach, + unix_process_detach, +}; + +#endif From 432a14f6b7f261fe35cbcfd89d7ad8f2314eaf2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Mon, 6 Feb 2023 21:24:26 +0100 Subject: [PATCH 2153/2777] windows.media.speech/tests: Get rid of duplicated hresult. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl CW-Bug-Id: #20134 --- dlls/windows.media.speech/tests/speech.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index fd013a1016e..558b82ceca2 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -42,7 +42,6 @@ #define AsyncStatus_Closed 4 #define SPERR_WINRT_INTERNAL_ERROR 0x800455a0 -#define SPERR_WINRT_INCORRECT_FORMAT 0x80131537 #define IHandler_RecognitionResult ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgs #define IHandler_RecognitionResultVtbl ITypedEventHandler_SpeechContinuousRecognitionSession_SpeechContinuousRecognitionResultGeneratedEventArgsVtbl @@ -1091,7 +1090,7 @@ static void test_SpeechSynthesizer(void) operation_ss_stream = (void *)0xdeadbeef; hr = ISpeechSynthesizer_SynthesizeSsmlToStreamAsync(synthesizer, str, &operation_ss_stream); /* Broken on Win 8 + 8.1 */ - ok(hr == S_OK || broken(hr == SPERR_WINRT_INCORRECT_FORMAT), "ISpeechSynthesizer_SynthesizeSsmlToStreamAsync failed, hr %#lx\n", hr); + ok(hr == S_OK || broken(hr == COR_E_FORMAT), "ISpeechSynthesizer_SynthesizeSsmlToStreamAsync failed, hr %#lx\n", hr); if (hr == S_OK) { From 4e42f3745435cb960788192f9383f51de5b86f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Mon, 20 Feb 2023 23:10:16 +0100 Subject: [PATCH 2154/2777] windows.media.speech/tests: Allow the SpeechRecognizer creation to fail in Wine. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To allow for error handling of missing Unix-side dependencies. Signed-off-by: Bernhard Kölbl CW-Bug-Id: #20134 --- dlls/windows.media.speech/tests/speech.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index 558b82ceca2..f941edee0df 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -1316,7 +1316,7 @@ static void test_SpeechRecognizer(void) ok(ref == 1, "Got unexpected ref %lu.\n", ref); hr = RoActivateInstance(hstr, &inspectable); - ok(hr == S_OK || broken(hr == SPERR_WINRT_INTERNAL_ERROR), "Got unexpected hr %#lx.\n", hr); + ok(hr == S_OK || hr == SPERR_WINRT_INTERNAL_ERROR, "Got unexpected hr %#lx.\n", hr); if (hr == S_OK) { @@ -1535,7 +1535,7 @@ static void test_SpeechRecognizer(void) } else if (hr == SPERR_WINRT_INTERNAL_ERROR) /* Not sure when this triggers. Probably if a language pack is not installed. */ { - win_skip("Could not init SpeechRecognizer with default language!\n"); + skip("Could not init SpeechRecognizer with default language!\n"); } done: @@ -1775,12 +1775,12 @@ static void test_Recognition(void) ok(hr == S_OK, "WindowsCreateString failed, hr %#lx.\n", hr); hr = RoActivateInstance(hstr, &inspectable); - ok(hr == S_OK || broken(hr == SPERR_WINRT_INTERNAL_ERROR || hr == REGDB_E_CLASSNOTREG), "Got unexpected hr %#lx.\n", hr); + ok(hr == S_OK || hr == SPERR_WINRT_INTERNAL_ERROR || broken(hr == REGDB_E_CLASSNOTREG), "Got unexpected hr %#lx.\n", hr); WindowsDeleteString(hstr); - if (FAILED(hr)) /* Win 8 and 8.1 and Win10 without enabled SR. */ + if (FAILED(hr)) /* Win 8 and 8.1 and Win10 without enabled SR. Wine with missing Unix side dependencies. */ { - win_skip("SpeechRecognizer cannot be activated!\n"); + skip("SpeechRecognizer cannot be activated!\n"); goto done; } From 18f29b9643c497eee13b67c2c904767d68128ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Mon, 20 Feb 2023 23:11:02 +0100 Subject: [PATCH 2155/2777] windows.media.speech: Implement Vosk create and release functions in the unixlib. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl CW-Bug-Id: #20134 --- dlls/windows.media.speech/Makefile.in | 2 +- dlls/windows.media.speech/private.h | 3 + dlls/windows.media.speech/recognizer.c | 42 ++++++ dlls/windows.media.speech/unixlib.c | 169 ++++++++++++++++++++++++- dlls/windows.media.speech/unixlib.h | 16 +++ 5 files changed, 230 insertions(+), 2 deletions(-) diff --git a/dlls/windows.media.speech/Makefile.in b/dlls/windows.media.speech/Makefile.in index 64376514d58..455f81c0840 100644 --- a/dlls/windows.media.speech/Makefile.in +++ b/dlls/windows.media.speech/Makefile.in @@ -1,6 +1,6 @@ MODULE = windows.media.speech.dll UNIXLIB = windows.media.speech.so -IMPORTS = combase uuid +IMPORTS = combase uuid user32 C_SRCS = \ async.c \ diff --git a/dlls/windows.media.speech/private.h b/dlls/windows.media.speech/private.h index 4b6a8327d6e..60d09c9f7d1 100644 --- a/dlls/windows.media.speech/private.h +++ b/dlls/windows.media.speech/private.h @@ -31,6 +31,7 @@ #include "windef.h" #include "winbase.h" #include "winstring.h" +#include "winuser.h" #include "objbase.h" #include "activation.h" @@ -47,6 +48,8 @@ #include "wine/list.h" +#define SPERR_WINRT_INTERNAL_ERROR 0x800455a0 + /* * * Windows.Media.SpeechRecognition diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index c2f386206b8..6938f6d7604 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -25,6 +25,9 @@ #include "wine/debug.h" +#include "unixlib.h" +#include "wine/unixlib.h" + WINE_DEFAULT_DEBUG_CHANNEL(speech); /* @@ -171,6 +174,8 @@ struct session IAudioCaptureClient *capture_client; WAVEFORMATEX capture_wfx; + speech_recognizer_handle unix_handle; + HANDLE worker_thread, worker_control_event, audio_buf_event; BOOLEAN worker_running, worker_paused; CRITICAL_SECTION cs; @@ -318,7 +323,9 @@ static ULONG WINAPI session_AddRef( ISpeechContinuousRecognitionSession *iface ) static ULONG WINAPI session_Release( ISpeechContinuousRecognitionSession *iface ) { struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + struct speech_release_recognizer_params release_params; ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); if (!ref) @@ -344,6 +351,9 @@ static ULONG WINAPI session_Release( ISpeechContinuousRecognitionSession *iface impl->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&impl->cs); + release_params.handle = impl->unix_handle; + WINE_UNIX_CALL(unix_speech_release_recognizer, &release_params); + IVector_ISpeechRecognitionConstraint_Release(impl->constraints); free(impl); } @@ -1079,6 +1089,35 @@ static HRESULT recognizer_factory_create_audio_capture(struct session *session) return hr; } +static HRESULT recognizer_factory_create_unix_instance( struct session *session ) +{ + struct speech_create_recognizer_params create_params = { 0 }; + WCHAR locale[LOCALE_NAME_MAX_LENGTH]; + NTSTATUS status; + INT len; + + if (!(len = GetUserDefaultLocaleName(locale, LOCALE_NAME_MAX_LENGTH))) + return E_FAIL; + + if (CharLowerBuffW(locale, len) != len) + return E_FAIL; + + if (!WideCharToMultiByte(CP_ACP, 0, locale, len, create_params.locale, ARRAY_SIZE(create_params.locale), NULL, NULL)) + return HRESULT_FROM_WIN32(GetLastError()); + + create_params.sample_rate = (FLOAT)session->capture_wfx.nSamplesPerSec; + + if ((status = WINE_UNIX_CALL(unix_speech_create_recognizer, &create_params))) + { + ERR("Unable to create Vosk instance for locale %s, status %#lx. Speech recognition won't work.\n", debugstr_a(create_params.locale), status); + return SPERR_WINRT_INTERNAL_ERROR; + } + + session->unix_handle = create_params.handle; + + return S_OK; +} + static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface, ILanguage *language, ISpeechRecognizer **speechrecognizer ) { struct recognizer *impl; @@ -1125,6 +1164,9 @@ static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface if (FAILED(hr = recognizer_factory_create_audio_capture(session))) goto error; + if (FAILED(hr = recognizer_factory_create_unix_instance(session))) + goto error; + InitializeCriticalSection(&session->cs); session->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": recognition_session.cs"); diff --git a/dlls/windows.media.speech/unixlib.c b/dlls/windows.media.speech/unixlib.c index d6f748b9426..362649e76f2 100644 --- a/dlls/windows.media.speech/unixlib.c +++ b/dlls/windows.media.speech/unixlib.c @@ -26,9 +26,12 @@ #include #include -#include #include +#include +#include #include +#include +#include #ifdef SONAME_LIBVOSK #include @@ -94,6 +97,164 @@ static NTSTATUS process_detach( void *args ) return STATUS_SUCCESS; } +static inline speech_recognizer_handle vosk_recognizer_to_handle( VoskRecognizer *recognizer ) +{ + return (speech_recognizer_handle)(UINT_PTR)recognizer; +} + +static inline VoskRecognizer *vosk_recognizer_from_handle( speech_recognizer_handle handle ) +{ + return (VoskRecognizer *)(UINT_PTR)handle; +} + +static NTSTATUS find_model_by_locale_and_path( const char *path, const char *locale, VoskModel **model ) +{ + static const char *vosk_model_identifier_small = "vosk-model-small-"; + static const char *vosk_model_identifier = "vosk-model-"; + size_t ident_small_len = strlen(vosk_model_identifier_small); + size_t ident_len = strlen(vosk_model_identifier); + char *ent_name, *model_path, *best_match, *delim; + NTSTATUS status = STATUS_UNSUCCESSFUL; + struct dirent *dirent; + size_t path_len, len; + DIR *dir; + + TRACE("path %s, locale %s, model %p.\n", path, debugstr_a(locale), model); + + if (!path || !locale || (len = strlen(locale)) < 4) + return STATUS_UNSUCCESSFUL; + + if (!(dir = opendir(path))) + return STATUS_UNSUCCESSFUL; + + delim = strchr(locale, '-'); + path_len = strlen(path); + best_match = NULL; + *model = NULL; + + while ((dirent = readdir(dir))) + { + ent_name = dirent->d_name; + + if (!strncmp(ent_name, vosk_model_identifier_small, ident_small_len)) + ent_name += ident_small_len; + else if (!strncmp(ent_name, vosk_model_identifier, ident_len)) + ent_name += ident_len; + else + continue; + + /* + * Find the first matching model for lang and region (en-us). + * If there isn't any, pick the first one just matching lang (en). + */ + if (!strncmp(ent_name, locale, len)) + { + if (best_match) free(best_match); + best_match = strdup(dirent->d_name); + break; + } + + if (!best_match && !strncmp(ent_name, locale, delim - locale)) + best_match = strdup(dirent->d_name); + } + + closedir(dir); + + if (!best_match) + return STATUS_UNSUCCESSFUL; + + if (!(model_path = malloc(path_len + 1 /* '/' */ + strlen(best_match) + 1))) + { + status = STATUS_NO_MEMORY; + goto done; + } + + sprintf(model_path, "%s/%s", path, best_match); + + TRACE("trying to load Vosk model %s.\n", debugstr_a(model_path)); + + if ((*model = p_vosk_model_new(model_path)) != NULL) + status = STATUS_SUCCESS; + +done: + free(model_path); + free(best_match); + + return status; +} + +static NTSTATUS find_model_by_locale( const char *locale, VoskModel **model ) +{ + const char *suffix = NULL; + char *env, *path = NULL; + NTSTATUS status; + + TRACE("locale %s, model %p.\n", debugstr_a(locale), model); + + if (!model) + return STATUS_UNSUCCESSFUL; + + if (!find_model_by_locale_and_path(getenv("VOSK_MODEL_PATH"), locale, model)) + return STATUS_SUCCESS; + if (!find_model_by_locale_and_path("/usr/share/vosk", locale, model)) + return STATUS_SUCCESS; + + if ((env = getenv("XDG_CACHE_HOME"))) + suffix = "/vosk"; + else if ((env = getenv("HOME"))) + suffix = "/.cache/vosk"; + else + return STATUS_UNSUCCESSFUL; + + if (!(path = malloc(strlen(env) + strlen(suffix) + 1))) + return STATUS_NO_MEMORY; + + sprintf(path, "%s%s", env, suffix); + status = find_model_by_locale_and_path(path, locale, model); + free(path); + + return status; +} + +static NTSTATUS speech_create_recognizer( void *args ) +{ + struct speech_create_recognizer_params *params = args; + VoskRecognizer *recognizer = NULL; + VoskModel *model = NULL; + NTSTATUS status = STATUS_SUCCESS; + + TRACE("args %p.\n", args); + + if (!vosk_handle) + return STATUS_NOT_SUPPORTED; + + if ((status = find_model_by_locale(params->locale, &model))) + return status; + + if (!(recognizer = p_vosk_recognizer_new(model, params->sample_rate))) + status = STATUS_UNSUCCESSFUL; + + /* VoskModel is reference-counted. A VoskRecognizer keeps a reference to its model. */ + p_vosk_model_free(model); + + params->handle = vosk_recognizer_to_handle(recognizer); + return status; +} + +static NTSTATUS speech_release_recognizer( void *args ) +{ + struct speech_release_recognizer_params *params = args; + + TRACE("args %p.\n", args); + + if (!vosk_handle) + return STATUS_NOT_SUPPORTED; + + p_vosk_recognizer_free(vosk_recognizer_from_handle(params->handle)); + + return STATUS_SUCCESS; +} + #else /* SONAME_LIBVOSK */ #define MAKE_UNSUPPORTED_FUNC( f ) \ @@ -105,6 +266,8 @@ static NTSTATUS process_detach( void *args ) MAKE_UNSUPPORTED_FUNC(process_attach) MAKE_UNSUPPORTED_FUNC(process_detach) +MAKE_UNSUPPORTED_FUNC(speech_create_recognizer) +MAKE_UNSUPPORTED_FUNC(speech_release_recognizer) #undef MAKE_UNSUPPORTED_FUNC #endif /* SONAME_LIBVOSK */ @@ -113,10 +276,14 @@ unixlib_entry_t __wine_unix_call_funcs[] = { process_attach, process_detach, + speech_create_recognizer, + speech_release_recognizer, }; unixlib_entry_t __wine_unix_call_wow64_funcs[] = { process_attach, process_detach, + speech_create_recognizer, + speech_release_recognizer, }; diff --git a/dlls/windows.media.speech/unixlib.h b/dlls/windows.media.speech/unixlib.h index 6c337e54511..974e8d5f797 100644 --- a/dlls/windows.media.speech/unixlib.h +++ b/dlls/windows.media.speech/unixlib.h @@ -30,10 +30,26 @@ #include "wine/unixlib.h" +typedef UINT64 speech_recognizer_handle; + +struct speech_create_recognizer_params +{ + speech_recognizer_handle handle; + CHAR locale[LOCALE_NAME_MAX_LENGTH]; + FLOAT sample_rate; +}; + +struct speech_release_recognizer_params +{ + speech_recognizer_handle handle; +}; + enum unix_funcs { unix_process_attach, unix_process_detach, + unix_speech_create_recognizer, + unix_speech_release_recognizer, }; #endif From d7330b30cb5126b5510a2bcbbb89bde0b97a99b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Mon, 6 Mar 2023 23:51:31 +0100 Subject: [PATCH 2156/2777] windows.media.speech: Move unix side recognizer creation to recognizer_CompileConstraintsAsync(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl CW-Bug-Id: #20134 --- dlls/windows.media.speech/recognizer.c | 76 ++++++++++++++------------ 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 6938f6d7604..81f2b9d3155 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -734,17 +734,55 @@ static HRESULT WINAPI recognizer_get_UIOptions( ISpeechRecognizer *iface, ISpeec return E_NOTIMPL; } +static HRESULT recognizer_create_unix_instance( struct session *session ) +{ + struct speech_create_recognizer_params create_params = { 0 }; + WCHAR locale[LOCALE_NAME_MAX_LENGTH]; + NTSTATUS status; + INT len; + + if (!(len = GetUserDefaultLocaleName(locale, LOCALE_NAME_MAX_LENGTH))) + return E_FAIL; + + if (CharLowerBuffW(locale, len) != len) + return E_FAIL; + + if (!WideCharToMultiByte(CP_ACP, 0, locale, len, create_params.locale, ARRAY_SIZE(create_params.locale), NULL, NULL)) + return HRESULT_FROM_WIN32(GetLastError()); + + create_params.sample_rate = (FLOAT)session->capture_wfx.nSamplesPerSec; + + if ((status = WINE_UNIX_CALL(unix_speech_create_recognizer, &create_params))) + { + ERR("Unable to create Vosk instance for locale %s, status %#lx. Speech recognition won't work.\n", debugstr_a(create_params.locale), status); + return SPERR_WINRT_INTERNAL_ERROR; + } + + session->unix_handle = create_params.handle; + + return S_OK; +} + static HRESULT recognizer_compile_constraints_async( IInspectable *invoker, IInspectable **result ) { - return compilation_result_create(SpeechRecognitionResultStatus_Success, (ISpeechRecognitionCompilationResult **) result); + struct recognizer *impl = impl_from_ISpeechRecognizer((ISpeechRecognizer *)invoker); + struct session *session = impl_from_ISpeechContinuousRecognitionSession(impl->session); + HRESULT hr; + + if (FAILED(hr = recognizer_create_unix_instance(session))) + { + WARN("Failed to created recognizer instance.\n"); + return compilation_result_create(SpeechRecognitionResultStatus_GrammarCompilationFailure, (ISpeechRecognitionCompilationResult **) result); + } + else return compilation_result_create(SpeechRecognitionResultStatus_Success, (ISpeechRecognitionCompilationResult **) result); } static HRESULT WINAPI recognizer_CompileConstraintsAsync( ISpeechRecognizer *iface, IAsyncOperation_SpeechRecognitionCompilationResult **operation ) { IAsyncOperation_IInspectable **value = (IAsyncOperation_IInspectable **)operation; - FIXME("iface %p, operation %p semi-stub!\n", iface, operation); - return async_operation_inspectable_create(&IID_IAsyncOperation_SpeechRecognitionCompilationResult, NULL, recognizer_compile_constraints_async, value); + TRACE("iface %p, operation %p semi-stub!\n", iface, operation); + return async_operation_inspectable_create(&IID_IAsyncOperation_SpeechRecognitionCompilationResult, (IInspectable *)iface, recognizer_compile_constraints_async, value); } static HRESULT WINAPI recognizer_RecognizeAsync( ISpeechRecognizer *iface, @@ -1089,35 +1127,6 @@ static HRESULT recognizer_factory_create_audio_capture(struct session *session) return hr; } -static HRESULT recognizer_factory_create_unix_instance( struct session *session ) -{ - struct speech_create_recognizer_params create_params = { 0 }; - WCHAR locale[LOCALE_NAME_MAX_LENGTH]; - NTSTATUS status; - INT len; - - if (!(len = GetUserDefaultLocaleName(locale, LOCALE_NAME_MAX_LENGTH))) - return E_FAIL; - - if (CharLowerBuffW(locale, len) != len) - return E_FAIL; - - if (!WideCharToMultiByte(CP_ACP, 0, locale, len, create_params.locale, ARRAY_SIZE(create_params.locale), NULL, NULL)) - return HRESULT_FROM_WIN32(GetLastError()); - - create_params.sample_rate = (FLOAT)session->capture_wfx.nSamplesPerSec; - - if ((status = WINE_UNIX_CALL(unix_speech_create_recognizer, &create_params))) - { - ERR("Unable to create Vosk instance for locale %s, status %#lx. Speech recognition won't work.\n", debugstr_a(create_params.locale), status); - return SPERR_WINRT_INTERNAL_ERROR; - } - - session->unix_handle = create_params.handle; - - return S_OK; -} - static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface, ILanguage *language, ISpeechRecognizer **speechrecognizer ) { struct recognizer *impl; @@ -1164,9 +1173,6 @@ static HRESULT WINAPI recognizer_factory_Create( ISpeechRecognizerFactory *iface if (FAILED(hr = recognizer_factory_create_audio_capture(session))) goto error; - if (FAILED(hr = recognizer_factory_create_unix_instance(session))) - goto error; - InitializeCriticalSection(&session->cs); session->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": recognition_session.cs"); From a7076e9b1d99e66acec228726be5907697ef5354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Mon, 27 Feb 2023 13:22:00 +0100 Subject: [PATCH 2157/2777] windows.media.speech: Implement recognition in the unixlib. CW-Bug-Id: #20134 --- dlls/windows.media.speech/recognizer.c | 35 +++++++++++- dlls/windows.media.speech/unixlib.c | 79 ++++++++++++++++++++++++++ dlls/windows.media.speech/unixlib.h | 26 ++++++++- 3 files changed, 138 insertions(+), 2 deletions(-) diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 81f2b9d3155..eb5fd9277a4 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -196,10 +196,13 @@ static DWORD CALLBACK session_worker_thread_cb( void *args ) { ISpeechContinuousRecognitionSession *iface = args; struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); + struct speech_get_recognition_result_params recognition_result_params; + struct speech_recognize_audio_params recognize_audio_params; BOOLEAN running = TRUE, paused = FALSE; UINT32 frame_count, tmp_buf_size; BYTE *audio_buf, *tmp_buf; DWORD flags, status; + NTSTATUS nt_status; HANDLE events[2]; HRESULT hr; @@ -269,7 +272,37 @@ static DWORD CALLBACK session_worker_thread_cb( void *args ) IAudioCaptureClient_ReleaseBuffer(impl->capture_client, frames_available); } - /* TODO: Send mic data to recognizer and handle results. */ + recognize_audio_params.handle = impl->unix_handle; + recognize_audio_params.samples = tmp_buf; + recognize_audio_params.samples_size = tmp_buf_offset; + recognize_audio_params.status = RECOGNITION_STATUS_EXCEPTION; + + if (NT_ERROR(nt_status = WINE_UNIX_CALL(unix_speech_recognize_audio, &recognize_audio_params))) + WARN("unix_speech_recognize_audio failed with status %#lx.\n", nt_status); + + if (recognize_audio_params.status != RECOGNITION_STATUS_RESULT_AVAILABLE) + continue; + + recognition_result_params.handle = impl->unix_handle; + recognition_result_params.result_buf = NULL; + recognition_result_params.result_buf_size = 512; + + do + { + recognition_result_params.result_buf = realloc(recognition_result_params.result_buf, recognition_result_params.result_buf_size); + } + while (WINE_UNIX_CALL(unix_speech_get_recognition_result, &recognition_result_params) == STATUS_BUFFER_TOO_SMALL && + recognition_result_params.result_buf); + + if (!recognition_result_params.result_buf) + { + WARN("memory allocation failed.\n"); + break; + } + + /* TODO: Compare recognized text to available options. */ + + free(recognition_result_params.result_buf); } else { diff --git a/dlls/windows.media.speech/unixlib.c b/dlls/windows.media.speech/unixlib.c index 362649e76f2..177256b2060 100644 --- a/dlls/windows.media.speech/unixlib.c +++ b/dlls/windows.media.speech/unixlib.c @@ -56,6 +56,9 @@ MAKE_FUNCPTR(vosk_model_new); MAKE_FUNCPTR(vosk_model_free); MAKE_FUNCPTR(vosk_recognizer_new); MAKE_FUNCPTR(vosk_recognizer_free); +MAKE_FUNCPTR(vosk_recognizer_accept_waveform); +MAKE_FUNCPTR(vosk_recognizer_final_result); +MAKE_FUNCPTR(vosk_recognizer_reset); #undef MAKE_FUNCPTR static NTSTATUS process_attach( void *args ) @@ -77,6 +80,9 @@ static NTSTATUS process_attach( void *args ) LOAD_FUNCPTR(vosk_model_free) LOAD_FUNCPTR(vosk_recognizer_new) LOAD_FUNCPTR(vosk_recognizer_free) + LOAD_FUNCPTR(vosk_recognizer_accept_waveform) + LOAD_FUNCPTR(vosk_recognizer_final_result) + LOAD_FUNCPTR(vosk_recognizer_reset) #undef LOAD_FUNCPTR return STATUS_SUCCESS; @@ -255,6 +261,73 @@ static NTSTATUS speech_release_recognizer( void *args ) return STATUS_SUCCESS; } +static NTSTATUS speech_recognize_audio( void *args ) +{ + struct speech_recognize_audio_params *params = args; + VoskRecognizer *recognizer = vosk_recognizer_from_handle(params->handle); + + if (!vosk_handle) + return STATUS_NOT_SUPPORTED; + + if (!recognizer) + return STATUS_UNSUCCESSFUL; + + params->status = p_vosk_recognizer_accept_waveform(recognizer, (const char *)params->samples, params->samples_size); + + return STATUS_SUCCESS; +} + +static NTSTATUS speech_get_recognition_result( void* args ) +{ + struct speech_get_recognition_result_params *params = args; + VoskRecognizer *recognizer = vosk_recognizer_from_handle(params->handle); + static const char *result_json_start = "{\n \"text\" : \""; + const size_t json_start_len = strlen(result_json_start); + static size_t last_result_len = 0; + static char *last_result = NULL; + const char *tmp = NULL; + + TRACE("args %p.\n", args); + + if (!vosk_handle) + return STATUS_NOT_SUPPORTED; + + if (!recognizer) + return STATUS_UNSUCCESSFUL; + + if (!last_result) + { + if ((tmp = p_vosk_recognizer_final_result(recognizer))) + { + last_result = strdup(tmp); + tmp = last_result; + + /* Operations to remove the JSON wrapper "{\n \"text\" : \"some recognized text\"\n}" -> "some recognized text\0" */ + memmove(last_result, last_result + json_start_len, strlen(last_result) - json_start_len + 1); + last_result = strrchr(last_result, '\"'); + last_result[0] = '\0'; + + last_result = (char *)tmp; + last_result_len = strlen(last_result); + TRACE("last_result %s.\n", debugstr_a(last_result)); + } + else return STATUS_NOT_FOUND; + } + else if (params->result_buf_size >= last_result_len + 1) + { + memcpy(params->result_buf, last_result, last_result_len + 1); + p_vosk_recognizer_reset(recognizer); + + free (last_result); + last_result = NULL; + + return STATUS_SUCCESS; + } + + params->result_buf_size = last_result_len + 1; + return STATUS_BUFFER_TOO_SMALL; +} + #else /* SONAME_LIBVOSK */ #define MAKE_UNSUPPORTED_FUNC( f ) \ @@ -268,6 +341,8 @@ MAKE_UNSUPPORTED_FUNC(process_attach) MAKE_UNSUPPORTED_FUNC(process_detach) MAKE_UNSUPPORTED_FUNC(speech_create_recognizer) MAKE_UNSUPPORTED_FUNC(speech_release_recognizer) +MAKE_UNSUPPORTED_FUNC(speech_recognize_audio) +MAKE_UNSUPPORTED_FUNC(speech_get_recognition_result) #undef MAKE_UNSUPPORTED_FUNC #endif /* SONAME_LIBVOSK */ @@ -278,6 +353,8 @@ unixlib_entry_t __wine_unix_call_funcs[] = process_detach, speech_create_recognizer, speech_release_recognizer, + speech_recognize_audio, + speech_get_recognition_result, }; unixlib_entry_t __wine_unix_call_wow64_funcs[] = @@ -286,4 +363,6 @@ unixlib_entry_t __wine_unix_call_wow64_funcs[] = process_detach, speech_create_recognizer, speech_release_recognizer, + speech_recognize_audio, + speech_get_recognition_result, }; diff --git a/dlls/windows.media.speech/unixlib.h b/dlls/windows.media.speech/unixlib.h index 974e8d5f797..a07d76705d5 100644 --- a/dlls/windows.media.speech/unixlib.h +++ b/dlls/windows.media.speech/unixlib.h @@ -44,12 +44,36 @@ struct speech_release_recognizer_params speech_recognizer_handle handle; }; -enum unix_funcs +enum speech_recognition_status +{ + RECOGNITION_STATUS_CONTINUING, + RECOGNITION_STATUS_RESULT_AVAILABLE, + RECOGNITION_STATUS_EXCEPTION, +}; + +struct speech_recognize_audio_params +{ + speech_recognizer_handle handle; + const BYTE *samples; + UINT32 samples_size; + enum speech_recognition_status status; +}; + +struct speech_get_recognition_result_params +{ + speech_recognizer_handle handle; + char *result_buf; + UINT32 result_buf_size; +}; + +enum vosk_funcs { unix_process_attach, unix_process_detach, unix_speech_create_recognizer, unix_speech_release_recognizer, + unix_speech_recognize_audio, + unix_speech_get_recognition_result, }; #endif From 2ae20fcba7070af79281db6465c653950fcd6e90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Wed, 25 May 2022 14:14:18 +0200 Subject: [PATCH 2158/2777] windows.media.speech: Compare recognized words with available constraints. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl CW-Bug-Id: #20134 --- dlls/windows.media.speech/recognizer.c | 115 ++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index eb5fd9277a4..3c1ded1d349 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -192,18 +192,105 @@ static inline struct session *impl_from_ISpeechContinuousRecognitionSession( ISp return CONTAINING_RECORD(iface, struct session, ISpeechContinuousRecognitionSession_iface); } +static HRESULT session_find_constraint_by_string(struct session *session, WCHAR *str, HSTRING *hstr_out, ISpeechRecognitionConstraint **out) +{ + ISpeechRecognitionListConstraint *list_constraint; + IIterable_IInspectable *constraints_iterable; + IIterator_IInspectable *constraints_iterator; + ISpeechRecognitionConstraint *constraint; + IIterable_HSTRING *commands_iterable; + IIterator_HSTRING *commands_iterator; + BOOL has_constraint, has_command; + IVector_HSTRING *commands; + const WCHAR *command_str; + HSTRING command; + HRESULT hr; + + TRACE("session %p, str %s, out %p.\n", session, debugstr_w(str), out); + + if (FAILED(hr = IVector_ISpeechRecognitionConstraint_QueryInterface(session->constraints, &IID_IIterable_ISpeechRecognitionConstraint, (void **)&constraints_iterable))) + return hr; + + if (FAILED(hr = IIterable_IInspectable_First(constraints_iterable, &constraints_iterator))) + { + IIterable_IInspectable_Release(constraints_iterable); + return hr; + } + + *out = NULL; + + for (hr = IIterator_IInspectable_get_HasCurrent(constraints_iterator, &has_constraint); SUCCEEDED(hr) && has_constraint && !(*out); hr = IIterator_IInspectable_MoveNext(constraints_iterator, &has_constraint)) + { + list_constraint = NULL; + commands_iterable = NULL; + commands_iterator = NULL; + commands = NULL; + + if (FAILED(IIterator_IInspectable_get_Current(constraints_iterator, (IInspectable **)&constraint))) + goto skip; + + if (FAILED(ISpeechRecognitionConstraint_QueryInterface(constraint, &IID_ISpeechRecognitionListConstraint, (void**)&list_constraint))) + goto skip; + + if (FAILED(ISpeechRecognitionListConstraint_get_Commands(list_constraint, &commands))) + goto skip; + + if (FAILED(IVector_HSTRING_QueryInterface(commands, &IID_IIterable_HSTRING, (void **)&commands_iterable))) + goto skip; + + if (FAILED(IIterable_HSTRING_First(commands_iterable, &commands_iterator))) + goto skip; + + for (hr = IIterator_HSTRING_get_HasCurrent(commands_iterator, &has_command); SUCCEEDED(hr) && has_command && !(*out); hr = IIterator_HSTRING_MoveNext(commands_iterator, &has_command)) + { + if (FAILED(IIterator_HSTRING_get_Current(commands_iterator, &command))) + continue; + + command_str = WindowsGetStringRawBuffer(command, NULL); + + TRACE("Comparing str %s to command_str %s.\n", debugstr_w(str), debugstr_w(command_str)); + + if (!wcsicmp(str, command_str)) + { + TRACE("constraint %p has str %s.\n", constraint, debugstr_w(str)); + ISpeechRecognitionConstraint_AddRef((*out = constraint)); + WindowsDuplicateString(command, hstr_out); + } + + WindowsDeleteString(command); + } + +skip: + if (commands_iterator) IIterator_HSTRING_Release(commands_iterator); + if (commands_iterable) IIterable_HSTRING_Release(commands_iterable); + if (commands) IVector_HSTRING_Release(commands); + + if (list_constraint) ISpeechRecognitionListConstraint_Release(list_constraint); + if (constraint) ISpeechRecognitionConstraint_Release(constraint); + } + + IIterator_IInspectable_Release(constraints_iterator); + IIterable_IInspectable_Release(constraints_iterable); + + hr = (*out) ? S_OK : COR_E_KEYNOTFOUND; + return hr; +} + static DWORD CALLBACK session_worker_thread_cb( void *args ) { ISpeechContinuousRecognitionSession *iface = args; struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); struct speech_get_recognition_result_params recognition_result_params; struct speech_recognize_audio_params recognize_audio_params; + ISpeechRecognitionConstraint *constraint; BOOLEAN running = TRUE, paused = FALSE; UINT32 frame_count, tmp_buf_size; BYTE *audio_buf, *tmp_buf; + WCHAR *recognized_text; DWORD flags, status; NTSTATUS nt_status; HANDLE events[2]; + HSTRING hstring; HRESULT hr; SetThreadDescription(GetCurrentThread(), L"wine_speech_recognition_session_worker"); @@ -253,6 +340,7 @@ static DWORD CALLBACK session_worker_thread_cb( void *args ) { SIZE_T packet_size = 0, tmp_buf_offset = 0; UINT32 frames_available = 0; + INT recognized_text_len = 0; while (tmp_buf_offset < tmp_buf_size && IAudioCaptureClient_GetBuffer(impl->capture_client, &audio_buf, &frames_available, &flags, NULL, NULL) == S_OK) @@ -300,8 +388,33 @@ static DWORD CALLBACK session_worker_thread_cb( void *args ) break; } - /* TODO: Compare recognized text to available options. */ + /* Silence was recognized. */ + if (!strcmp(recognition_result_params.result_buf, "")) + { + free(recognition_result_params.result_buf); + continue; + } + + recognized_text_len = MultiByteToWideChar(CP_UTF8, 0, recognition_result_params.result_buf, -1, NULL, 0); + + if (!(recognized_text = malloc(recognized_text_len * sizeof(WCHAR)))) + { + free(recognition_result_params.result_buf); + WARN("memory allocation failed.\n"); + break; + } + + MultiByteToWideChar(CP_UTF8, 0, recognition_result_params.result_buf, -1, recognized_text, recognized_text_len); + + if (SUCCEEDED(hr = session_find_constraint_by_string(impl, recognized_text, &hstring, &constraint))) + { + /* TODO: Send event. */ + + WindowsDeleteString(hstring); + ISpeechRecognitionConstraint_Release(constraint); + } + free(recognized_text); free(recognition_result_params.result_buf); } else From 257d6e5a657e898d99b82f20ad342dfe83f68e72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Mon, 30 May 2022 18:36:51 +0200 Subject: [PATCH 2159/2777] windows.media.speech: Send event on recognition success. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl CW-Bug-Id: #20134 --- dlls/windows.media.speech/recognizer.c | 377 ++++++++++++++++++++++++- 1 file changed, 376 insertions(+), 1 deletion(-) diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 3c1ded1d349..0f38bcca1f3 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -30,6 +30,372 @@ WINE_DEFAULT_DEBUG_CHANNEL(speech); +static const char *debugstr_hstring(HSTRING hstr) +{ + const WCHAR *str; + UINT32 len; + if (hstr && !((ULONG_PTR)hstr >> 16)) return "(invalid)"; + str = WindowsGetStringRawBuffer(hstr, &len); + return wine_dbgstr_wn(str, len); +} + +struct recognition_result +{ + ISpeechRecognitionResult ISpeechRecognitionResult_iface; + ISpeechRecognitionResult2 ISpeechRecognitionResult2_iface; + LONG ref; + + ISpeechRecognitionConstraint *constraint; + HSTRING text; +}; + +static inline struct recognition_result *impl_from_ISpeechRecognitionResult( ISpeechRecognitionResult *iface ) +{ + return CONTAINING_RECORD(iface, struct recognition_result, ISpeechRecognitionResult_iface); +} + +static HRESULT WINAPI recognition_result_QueryInterface( ISpeechRecognitionResult *iface, REFIID iid, void **out ) +{ + struct recognition_result *impl = impl_from_ISpeechRecognitionResult(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_IAgileObject) || + IsEqualGUID(iid, &IID_ISpeechRecognitionResult)) + { + IInspectable_AddRef((*out = &impl->ISpeechRecognitionResult_iface)); + return S_OK; + } + + if (IsEqualGUID(iid, &IID_ISpeechRecognitionResult2)) + { + IInspectable_AddRef((*out = &impl->ISpeechRecognitionResult2_iface)); + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI recognition_result_AddRef( ISpeechRecognitionResult *iface ) +{ + struct recognition_result *impl = impl_from_ISpeechRecognitionResult(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + return ref; +} + +static ULONG WINAPI recognition_result_Release( ISpeechRecognitionResult *iface ) +{ + struct recognition_result *impl = impl_from_ISpeechRecognitionResult(iface); + + ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + + if(!ref) + { + ISpeechRecognitionConstraint_Release(impl->constraint); + WindowsDeleteString(impl->text); + free(impl); + } + + return ref; +} + +static HRESULT WINAPI recognition_result_GetIids( ISpeechRecognitionResult *iface, ULONG *iid_count, IID **iids ) +{ + FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids); + return E_NOTIMPL; +} + +static HRESULT WINAPI recognition_result_GetRuntimeClassName( ISpeechRecognitionResult *iface, HSTRING *class_name ) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT WINAPI recognition_result_GetTrustLevel( ISpeechRecognitionResult *iface, TrustLevel *trust_level ) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT WINAPI recognition_result_get_Status( ISpeechRecognitionResult *iface, SpeechRecognitionResultStatus *value ) +{ + FIXME("iface %p, operation %p stub!\n", iface, value); + *value = SpeechRecognitionResultStatus_Success; + return S_OK; +} + +static HRESULT WINAPI recognition_result_get_Text( ISpeechRecognitionResult *iface, HSTRING *value ) +{ + struct recognition_result *impl = impl_from_ISpeechRecognitionResult(iface); + TRACE("iface %p, operation %p, text: %s.\n", iface, value, debugstr_hstring(impl->text)); + return WindowsDuplicateString(impl->text, value); +} + +static HRESULT WINAPI recognition_result_get_Confidence( ISpeechRecognitionResult *iface, SpeechRecognitionConfidence *value ) +{ + FIXME("iface %p, operation %p semi stub!\n", iface, value); + *value = SpeechRecognitionConfidence_High; + return S_OK; +} + +static HRESULT WINAPI recognition_result_get_SemanticInterpretation( ISpeechRecognitionResult *iface, + ISpeechRecognitionSemanticInterpretation **value ) +{ + FIXME("iface %p, operation %p stub!\n", iface, value); + return E_NOTIMPL; +} + +static HRESULT WINAPI recognition_result_GetAlternates( ISpeechRecognitionResult *iface, + UINT32 max_amount, + IVectorView_SpeechRecognitionResult **results ) +{ + IVector_IInspectable *vector; + struct vector_iids constraints_iids = + { + .iterable = &IID_IVectorView_SpeechRecognitionResult, + .iterator = &IID_IVectorView_SpeechRecognitionResult, + .vector = &IID_IVector_IInspectable, + .view = &IID_IVectorView_SpeechRecognitionResult, + }; + + FIXME("iface %p, max_amount %u, results %p stub!\n", iface, max_amount, results); + + vector_inspectable_create(&constraints_iids, (IVector_IInspectable **)&vector); + IVector_IInspectable_GetView(vector, (IVectorView_IInspectable **)results); + IVector_IInspectable_Release(vector); + return S_OK; +} + +static HRESULT WINAPI recognition_result_get_Constraint( ISpeechRecognitionResult *iface, ISpeechRecognitionConstraint **value ) +{ + struct recognition_result *impl = impl_from_ISpeechRecognitionResult(iface); + TRACE("iface %p, operation %p.\n", iface, value); + ISpeechRecognitionConstraint_AddRef((*value = impl->constraint)); + return S_OK; +} + +static HRESULT WINAPI recognition_result_get_RulePath( ISpeechRecognitionResult *iface, IVectorView_HSTRING **value ) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI recognition_result_get_RawConfidence( ISpeechRecognitionResult *iface, DOUBLE *value ) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static const struct ISpeechRecognitionResultVtbl recognition_result_vtbl = +{ + /* IUnknown methods */ + recognition_result_QueryInterface, + recognition_result_AddRef, + recognition_result_Release, + /* IInspectable methods */ + recognition_result_GetIids, + recognition_result_GetRuntimeClassName, + recognition_result_GetTrustLevel, + /* ISpeechRecognitionResult methods */ + recognition_result_get_Status, + recognition_result_get_Text, + recognition_result_get_Confidence, + recognition_result_get_SemanticInterpretation, + recognition_result_GetAlternates, + recognition_result_get_Constraint, + recognition_result_get_RulePath, + recognition_result_get_RawConfidence +}; + +DEFINE_IINSPECTABLE(recognition_result2, ISpeechRecognitionResult2, struct recognition_result, ISpeechRecognitionResult_iface) + +static HRESULT WINAPI recognition_result2_get_PhraseStartTime( ISpeechRecognitionResult2 *iface, DateTime *value ) +{ + DateTime dt = { .UniversalTime = 0 }; + FIXME("iface %p, value %p stub!\n", iface, value); + *value = dt; + return S_OK; +} + + +static HRESULT WINAPI recognition_result2_get_PhraseDuration( ISpeechRecognitionResult2 *iface, TimeSpan *value ) +{ + TimeSpan ts = { .Duration = 50000000LL }; /* Use 5 seconds as stub value. */ + FIXME("iface %p, value %p stub!\n", iface, value); + *value = ts; + return S_OK; +} + +static const struct ISpeechRecognitionResult2Vtbl recognition_result2_vtbl = +{ + /* IUnknown methods */ + recognition_result2_QueryInterface, + recognition_result2_AddRef, + recognition_result2_Release, + /* IInspectable methods */ + recognition_result2_GetIids, + recognition_result2_GetRuntimeClassName, + recognition_result2_GetTrustLevel, + /* ISpeechRecognitionResult2 methods */ + recognition_result2_get_PhraseStartTime, + recognition_result2_get_PhraseDuration +}; + +static HRESULT WINAPI recognition_result_create( ISpeechRecognitionConstraint *constraint, + HSTRING result_text, + ISpeechRecognitionResult **out ) +{ + struct recognition_result *impl; + + TRACE("out %p.\n", out); + + if (!(impl = calloc(1, sizeof(*impl)))) + { + *out = NULL; + return E_OUTOFMEMORY; + } + + impl->ISpeechRecognitionResult_iface.lpVtbl = &recognition_result_vtbl; + impl->ISpeechRecognitionResult2_iface.lpVtbl = &recognition_result2_vtbl; + impl->ref = 1; + + if (constraint) ISpeechRecognitionConstraint_AddRef((impl->constraint = constraint)); + WindowsDuplicateString(result_text, &impl->text); + + *out = &impl->ISpeechRecognitionResult_iface; + + TRACE("created %p.\n", *out); + + return S_OK; +} + +struct recognition_result_event_args +{ + ISpeechContinuousRecognitionResultGeneratedEventArgs ISpeechContinuousRecognitionResultGeneratedEventArgs_iface; + LONG ref; + + ISpeechRecognitionResult *result; +}; + +static inline struct recognition_result_event_args *impl_from_ISpeechContinuousRecognitionResultGeneratedEventArgs( ISpeechContinuousRecognitionResultGeneratedEventArgs *iface ) +{ + return CONTAINING_RECORD(iface, struct recognition_result_event_args, ISpeechContinuousRecognitionResultGeneratedEventArgs_iface); +} + +static HRESULT WINAPI recognition_result_event_args_QueryInterface( ISpeechContinuousRecognitionResultGeneratedEventArgs *iface, REFIID iid, void **out ) +{ + struct recognition_result_event_args *impl = impl_from_ISpeechContinuousRecognitionResultGeneratedEventArgs(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_IAgileObject) || + IsEqualGUID(iid, &IID_ISpeechContinuousRecognitionResultGeneratedEventArgs)) + { + IInspectable_AddRef((*out = &impl->ISpeechContinuousRecognitionResultGeneratedEventArgs_iface)); + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI recognition_result_event_args_AddRef( ISpeechContinuousRecognitionResultGeneratedEventArgs *iface ) +{ + struct recognition_result_event_args *impl = impl_from_ISpeechContinuousRecognitionResultGeneratedEventArgs(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + return ref; +} + +static ULONG WINAPI recognition_result_event_args_Release( ISpeechContinuousRecognitionResultGeneratedEventArgs *iface ) +{ + struct recognition_result_event_args *impl = impl_from_ISpeechContinuousRecognitionResultGeneratedEventArgs(iface); + + ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + + if (!ref) + { + if (impl->result) ISpeechRecognitionResult_Release(impl->result); + free(impl); + } + + return ref; +} + +static HRESULT WINAPI recognition_result_event_args_GetIids( ISpeechContinuousRecognitionResultGeneratedEventArgs *iface, ULONG *iid_count, IID **iids ) +{ + FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids); + return E_NOTIMPL; +} + +static HRESULT WINAPI recognition_result_event_args_GetRuntimeClassName( ISpeechContinuousRecognitionResultGeneratedEventArgs *iface, HSTRING *class_name ) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +static HRESULT WINAPI recognition_result_event_args_GetTrustLevel( ISpeechContinuousRecognitionResultGeneratedEventArgs *iface, TrustLevel *trust_level ) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +static HRESULT WINAPI recognition_result_event_args_get_Result( ISpeechContinuousRecognitionResultGeneratedEventArgs *iface, + ISpeechRecognitionResult **value ) +{ + struct recognition_result_event_args *impl = impl_from_ISpeechContinuousRecognitionResultGeneratedEventArgs(iface); + FIXME("iface %p value %p stub!\n", iface, value); + ISpeechRecognitionResult_AddRef((*value = impl->result)); + return S_OK; +} + +static const struct ISpeechContinuousRecognitionResultGeneratedEventArgsVtbl recognition_result_event_args_vtbl = +{ + /* IUnknown methods */ + recognition_result_event_args_QueryInterface, + recognition_result_event_args_AddRef, + recognition_result_event_args_Release, + /* IInspectable methods */ + recognition_result_event_args_GetIids, + recognition_result_event_args_GetRuntimeClassName, + recognition_result_event_args_GetTrustLevel, + /* ISpeechContinuousRecognitionResultGeneratedEventArgs methods */ + recognition_result_event_args_get_Result +}; + +static HRESULT WINAPI recognition_result_event_args_create( ISpeechRecognitionResult *result, + ISpeechContinuousRecognitionResultGeneratedEventArgs **out ) +{ + struct recognition_result_event_args *impl; + + TRACE("out %p.\n", out); + + if (!(impl = calloc(1, sizeof(*impl)))) + { + *out = NULL; + return E_OUTOFMEMORY; + } + + impl->ISpeechContinuousRecognitionResultGeneratedEventArgs_iface.lpVtbl = &recognition_result_event_args_vtbl; + impl->ref = 1; + if (result) ISpeechRecognitionResult_AddRef((impl->result = result)); + + *out = &impl->ISpeechContinuousRecognitionResultGeneratedEventArgs_iface; + + TRACE("created %p.\n", *out); + return S_OK; +} + /* * * ISpeechRecognitionCompilationResult @@ -282,7 +648,9 @@ static DWORD CALLBACK session_worker_thread_cb( void *args ) struct session *impl = impl_from_ISpeechContinuousRecognitionSession(iface); struct speech_get_recognition_result_params recognition_result_params; struct speech_recognize_audio_params recognize_audio_params; + ISpeechContinuousRecognitionResultGeneratedEventArgs *event_args; ISpeechRecognitionConstraint *constraint; + ISpeechRecognitionResult *result; BOOLEAN running = TRUE, paused = FALSE; UINT32 frame_count, tmp_buf_size; BYTE *audio_buf, *tmp_buf; @@ -408,8 +776,15 @@ static DWORD CALLBACK session_worker_thread_cb( void *args ) if (SUCCEEDED(hr = session_find_constraint_by_string(impl, recognized_text, &hstring, &constraint))) { - /* TODO: Send event. */ + recognition_result_create(constraint, hstring, &result); + recognition_result_event_args_create(result, &event_args); + + typed_event_handlers_notify(&impl->result_handlers, + (IInspectable *)&impl->ISpeechContinuousRecognitionSession_iface, + (IInspectable *)event_args); + ISpeechContinuousRecognitionResultGeneratedEventArgs_Release(event_args); + ISpeechRecognitionResult_Release(result); WindowsDeleteString(hstring); ISpeechRecognitionConstraint_Release(constraint); } From d1ce6febc43907701d48a5cae8e630e6e1bc33f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Mon, 30 May 2022 18:37:41 +0200 Subject: [PATCH 2160/2777] windows.media.speech: Add ISpeechRecognitionSemanticInterpretation stub. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl CW-Bug-Id: #20134 --- dlls/windows.media.speech/recognizer.c | 112 ++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 0f38bcca1f3..3d434068148 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -39,6 +39,116 @@ static const char *debugstr_hstring(HSTRING hstr) return wine_dbgstr_wn(str, len); } +struct semantic_interpretation +{ + ISpeechRecognitionSemanticInterpretation ISpeechRecognitionSemanticInterpretation_iface; + LONG ref; +}; + +static inline struct semantic_interpretation *impl_from_ISpeechRecognitionSemanticInterpretation( ISpeechRecognitionSemanticInterpretation *iface ) +{ + return CONTAINING_RECORD(iface, struct semantic_interpretation, ISpeechRecognitionSemanticInterpretation_iface); +} + +HRESULT WINAPI semantic_interpretation_QueryInterface( ISpeechRecognitionSemanticInterpretation *iface, REFIID iid, void **out ) +{ + struct semantic_interpretation *impl = impl_from_ISpeechRecognitionSemanticInterpretation(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_ISpeechRecognitionSemanticInterpretation)) + { + IInspectable_AddRef((*out = &impl->ISpeechRecognitionSemanticInterpretation_iface)); + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +ULONG WINAPI semantic_interpretation_AddRef( ISpeechRecognitionSemanticInterpretation *iface ) +{ + struct semantic_interpretation *impl = impl_from_ISpeechRecognitionSemanticInterpretation(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + return ref; +} + +ULONG WINAPI semantic_interpretation_Release( ISpeechRecognitionSemanticInterpretation *iface ) +{ + struct semantic_interpretation *impl = impl_from_ISpeechRecognitionSemanticInterpretation(iface); + + ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + + if(!ref) + free(impl); + + return ref; +} + +HRESULT WINAPI semantic_interpretation_GetIids( ISpeechRecognitionSemanticInterpretation *iface, ULONG *iid_count, IID **iids ) +{ + FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids); + return E_NOTIMPL; +} + +HRESULT WINAPI semantic_interpretation_GetRuntimeClassName( ISpeechRecognitionSemanticInterpretation *iface, HSTRING *class_name ) +{ + FIXME("iface %p, class_name %p stub!\n", iface, class_name); + return E_NOTIMPL; +} + +HRESULT WINAPI semantic_interpretation_GetTrustLevel( ISpeechRecognitionSemanticInterpretation *iface, TrustLevel *trust_level ) +{ + FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); + return E_NOTIMPL; +} + +HRESULT WINAPI semantic_interpretation_get_Properties( ISpeechRecognitionSemanticInterpretation *iface, IMapView_HSTRING_IVectorView_HSTRING **value ) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static const struct ISpeechRecognitionSemanticInterpretationVtbl semantic_interpretation_vtbl = +{ + /* IUnknown methods */ + semantic_interpretation_QueryInterface, + semantic_interpretation_AddRef, + semantic_interpretation_Release, + /* IInspectable methods */ + semantic_interpretation_GetIids, + semantic_interpretation_GetRuntimeClassName, + semantic_interpretation_GetTrustLevel, + /* ISpeechRecognitionSemanticInterpretation methods */ + semantic_interpretation_get_Properties +}; + + +static HRESULT semantic_interpretation_create( ISpeechRecognitionSemanticInterpretation **out ) +{ + struct semantic_interpretation *impl; + + TRACE("out %p.\n", out); + + if (!(impl = calloc(1, sizeof(*impl)))) + { + *out = NULL; + return E_OUTOFMEMORY; + } + + impl->ISpeechRecognitionSemanticInterpretation_iface.lpVtbl = &semantic_interpretation_vtbl; + impl->ref = 1; + + *out = &impl->ISpeechRecognitionSemanticInterpretation_iface; + TRACE("created %p\n", *out); + return S_OK; +} + struct recognition_result { ISpeechRecognitionResult ISpeechRecognitionResult_iface; @@ -148,7 +258,7 @@ static HRESULT WINAPI recognition_result_get_SemanticInterpretation( ISpeechReco ISpeechRecognitionSemanticInterpretation **value ) { FIXME("iface %p, operation %p stub!\n", iface, value); - return E_NOTIMPL; + return semantic_interpretation_create(value); } static HRESULT WINAPI recognition_result_GetAlternates( ISpeechRecognitionResult *iface, From 8ccbf1747bfa396e2209aff16cc77192995fbad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Mon, 30 May 2022 18:44:05 +0200 Subject: [PATCH 2161/2777] HACK: windows.media.speech: Stub semantic_interpretation_get_Properties. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl CW-Bug-Id: #20134 --- dlls/windows.media.speech/recognizer.c | 134 ++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 1 deletion(-) diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 3d434068148..165f4f4a9ee 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -39,6 +39,138 @@ static const char *debugstr_hstring(HSTRING hstr) return wine_dbgstr_wn(str, len); } +struct map_view_hstring_vector_view_hstring +{ + IMapView_HSTRING_IVectorView_HSTRING IMapView_HSTRING_IVectorView_HSTRING_iface; + LONG ref; +}; + +static inline struct map_view_hstring_vector_view_hstring *impl_from_IMapView_HSTRING_IVectorView_HSTRING( IMapView_HSTRING_IVectorView_HSTRING *iface ) +{ + return CONTAINING_RECORD(iface, struct map_view_hstring_vector_view_hstring, IMapView_HSTRING_IVectorView_HSTRING_iface); +} + +HRESULT WINAPI map_view_hstring_vector_view_hstring_QueryInterface( IMapView_HSTRING_IVectorView_HSTRING *iface, REFIID iid, void **out ) +{ + struct map_view_hstring_vector_view_hstring *impl = impl_from_IMapView_HSTRING_IVectorView_HSTRING(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IInspectable) || + IsEqualGUID(iid, &IID_IMapView_HSTRING_IVectorView_HSTRING)) + { + IInspectable_AddRef((*out = &impl->IMapView_HSTRING_IVectorView_HSTRING_iface)); + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +ULONG WINAPI map_view_hstring_vector_view_hstring_AddRef( IMapView_HSTRING_IVectorView_HSTRING *iface ) +{ + struct map_view_hstring_vector_view_hstring *impl = impl_from_IMapView_HSTRING_IVectorView_HSTRING(iface); + ULONG ref = InterlockedIncrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + return ref; +} + +ULONG WINAPI map_view_hstring_vector_view_hstring_Release( IMapView_HSTRING_IVectorView_HSTRING *iface ) +{ + struct map_view_hstring_vector_view_hstring *impl = impl_from_IMapView_HSTRING_IVectorView_HSTRING(iface); + + ULONG ref = InterlockedDecrement(&impl->ref); + TRACE("iface %p, ref %lu.\n", iface, ref); + + if(!ref) + free(impl); + + return ref; +} + +HRESULT WINAPI map_view_hstring_vector_view_hstring_GetIids( IMapView_HSTRING_IVectorView_HSTRING *iface, ULONG *iidCount, IID **iids ) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +HRESULT WINAPI map_view_hstring_vector_view_hstring_GetRuntimeClassName( IMapView_HSTRING_IVectorView_HSTRING *iface, HSTRING *className ) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +HRESULT WINAPI map_view_hstring_vector_view_hstring_GetTrustLevel( IMapView_HSTRING_IVectorView_HSTRING *iface, TrustLevel *trustLevel ) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +HRESULT WINAPI map_view_hstring_vector_view_hstring_Lookup( IMapView_HSTRING_IVectorView_HSTRING *iface, HSTRING key, IVectorView_HSTRING **value ) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +HRESULT WINAPI map_view_hstring_vector_view_hstring_get_Size( IMapView_HSTRING_IVectorView_HSTRING *iface, unsigned int *size ) +{ + FIXME("iface %p stub!\n", iface); + *size = 0; + return S_OK; +} + +HRESULT WINAPI map_view_hstring_vector_view_hstring_HasKey( IMapView_HSTRING_IVectorView_HSTRING *iface, HSTRING key, boolean *found ) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +HRESULT WINAPI map_view_hstring_vector_view_hstring_Split( IMapView_HSTRING_IVectorView_HSTRING *iface, IMapView_HSTRING_IVectorView_HSTRING **first, IMapView_HSTRING_IVectorView_HSTRING **second ) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static const struct IMapView_HSTRING_IVectorView_HSTRINGVtbl map_view_hstring_vector_view_hstring_vtbl = +{ + /* IUnknown methods */ + map_view_hstring_vector_view_hstring_QueryInterface, + map_view_hstring_vector_view_hstring_AddRef, + map_view_hstring_vector_view_hstring_Release, + /* IInspectable methods */ + map_view_hstring_vector_view_hstring_GetIids, + map_view_hstring_vector_view_hstring_GetRuntimeClassName, + map_view_hstring_vector_view_hstring_GetTrustLevel, + /* IMapView* > methods */ + map_view_hstring_vector_view_hstring_Lookup, + map_view_hstring_vector_view_hstring_get_Size, + map_view_hstring_vector_view_hstring_HasKey, + map_view_hstring_vector_view_hstring_Split +}; + + +static HRESULT map_view_hstring_vector_view_hstring_create( IMapView_HSTRING_IVectorView_HSTRING **out ) +{ + struct map_view_hstring_vector_view_hstring *impl; + + TRACE("out %p.\n", out); + + if (!(impl = calloc(1, sizeof(*impl)))) + { + *out = NULL; + return E_OUTOFMEMORY; + } + + impl->IMapView_HSTRING_IVectorView_HSTRING_iface.lpVtbl = &map_view_hstring_vector_view_hstring_vtbl; + impl->ref = 1; + + *out = &impl->IMapView_HSTRING_IVectorView_HSTRING_iface; + TRACE("created %p\n", *out); + return S_OK; +} + struct semantic_interpretation { ISpeechRecognitionSemanticInterpretation ISpeechRecognitionSemanticInterpretation_iface; @@ -111,7 +243,7 @@ HRESULT WINAPI semantic_interpretation_GetTrustLevel( ISpeechRecognitionSemantic HRESULT WINAPI semantic_interpretation_get_Properties( ISpeechRecognitionSemanticInterpretation *iface, IMapView_HSTRING_IVectorView_HSTRING **value ) { FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; + return map_view_hstring_vector_view_hstring_create(value); } static const struct ISpeechRecognitionSemanticInterpretationVtbl semantic_interpretation_vtbl = From 75f4455db28e48b7c0ac3a12f270ff3b1fad7d58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Tue, 28 Feb 2023 16:11:36 +0100 Subject: [PATCH 2162/2777] WIP: windows.media.speech: Implement grammar. CW-Bug-Id: #20134 --- dlls/windows.media.speech/recognizer.c | 106 ++++++++++++++++++++++++- dlls/windows.media.speech/unixlib.c | 61 +++++++++++++- dlls/windows.media.speech/unixlib.h | 2 + 3 files changed, 164 insertions(+), 5 deletions(-) diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c index 165f4f4a9ee..218453a2203 100644 --- a/dlls/windows.media.speech/recognizer.c +++ b/dlls/windows.media.speech/recognizer.c @@ -1497,7 +1497,7 @@ static HRESULT WINAPI recognizer_get_UIOptions( ISpeechRecognizer *iface, ISpeec return E_NOTIMPL; } -static HRESULT recognizer_create_unix_instance( struct session *session ) +static HRESULT recognizer_create_unix_instance( struct session *session, const char **grammar, UINT32 grammar_size ) { struct speech_create_recognizer_params create_params = { 0 }; WCHAR locale[LOCALE_NAME_MAX_LENGTH]; @@ -1514,6 +1514,8 @@ static HRESULT recognizer_create_unix_instance( struct session *session ) return HRESULT_FROM_WIN32(GetLastError()); create_params.sample_rate = (FLOAT)session->capture_wfx.nSamplesPerSec; + create_params.grammar = grammar; + create_params.grammar_size = grammar_size; if ((status = WINE_UNIX_CALL(unix_speech_create_recognizer, &create_params))) { @@ -1530,11 +1532,109 @@ static HRESULT recognizer_compile_constraints_async( IInspectable *invoker, IIns { struct recognizer *impl = impl_from_ISpeechRecognizer((ISpeechRecognizer *)invoker); struct session *session = impl_from_ISpeechContinuousRecognitionSession(impl->session); + struct speech_release_recognizer_params release_params; + ISpeechRecognitionListConstraint *list_constraint; + IIterable_IInspectable *constraints_iterable; + IIterator_IInspectable *constraints_iterator; + ISpeechRecognitionConstraint *constraint; + IIterable_HSTRING *commands_iterable; + IIterator_HSTRING *commands_iterator; + BOOL has_constraint, has_command; + IVector_HSTRING *commands; + const WCHAR *command_str; + UINT32 grammar_size = 0, i = 0; + char **grammar = NULL; + HSTRING command; + UINT32 size = 0; HRESULT hr; - if (FAILED(hr = recognizer_create_unix_instance(session))) + if (FAILED(hr = IVector_ISpeechRecognitionConstraint_QueryInterface(session->constraints, &IID_IIterable_ISpeechRecognitionConstraint, (void **)&constraints_iterable))) + return hr; + + if (FAILED(hr = IIterable_IInspectable_First(constraints_iterable, &constraints_iterator))) + { + IIterable_IInspectable_Release(constraints_iterable); + return hr; + } + + for (hr = IIterator_IInspectable_get_HasCurrent(constraints_iterator, &has_constraint); SUCCEEDED(hr) && has_constraint; hr = IIterator_IInspectable_MoveNext(constraints_iterator, &has_constraint)) + { + list_constraint = NULL; + commands_iterable = NULL; + commands_iterator = NULL; + commands = NULL; + + if (FAILED(IIterator_IInspectable_get_Current(constraints_iterator, (IInspectable **)&constraint))) + goto skip; + + if (FAILED(ISpeechRecognitionConstraint_QueryInterface(constraint, &IID_ISpeechRecognitionListConstraint, (void**)&list_constraint))) + goto skip; + + if (FAILED(ISpeechRecognitionListConstraint_get_Commands(list_constraint, &commands))) + goto skip; + + if (FAILED(IVector_HSTRING_QueryInterface(commands, &IID_IIterable_HSTRING, (void **)&commands_iterable))) + goto skip; + + if (FAILED(IIterable_HSTRING_First(commands_iterable, &commands_iterator))) + goto skip; + + if (FAILED(IVector_HSTRING_get_Size(commands, &size))) + goto skip; + + grammar_size += size; + grammar = realloc(grammar, grammar_size * sizeof(char *)); + + for (hr = IIterator_HSTRING_get_HasCurrent(commands_iterator, &has_command); SUCCEEDED(hr) && has_command; hr = IIterator_HSTRING_MoveNext(commands_iterator, &has_command)) + { + if (FAILED(IIterator_HSTRING_get_Current(commands_iterator, &command))) + continue; + + command_str = WindowsGetStringRawBuffer(command, NULL); + + if (command_str) + { + WCHAR *wstr = wcsdup(command_str); + size_t len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, grammar[i], 0, NULL, NULL); + grammar[i] = malloc(len * sizeof(char)); + + CharLowerW(wstr); + WideCharToMultiByte(CP_UTF8, 0, wstr, -1, grammar[i], len, NULL, NULL); + free(wstr); + i++; + } + + WindowsDeleteString(command); + } + +skip: + if (commands_iterator) IIterator_HSTRING_Release(commands_iterator); + if (commands_iterable) IIterable_HSTRING_Release(commands_iterable); + if (commands) IVector_HSTRING_Release(commands); + + if (list_constraint) ISpeechRecognitionListConstraint_Release(list_constraint); + if (constraint) ISpeechRecognitionConstraint_Release(constraint); + } + + IIterator_IInspectable_Release(constraints_iterator); + IIterable_IInspectable_Release(constraints_iterable); + + if (session->unix_handle) + { + release_params.handle = session->unix_handle; + WINE_UNIX_CALL(unix_speech_release_recognizer, &release_params); + session->unix_handle = 0; + } + + hr = recognizer_create_unix_instance(session, (const char **)grammar, grammar_size); + + for(i = 0; i < grammar_size; ++i) + free(grammar[i]); + free(grammar); + + if (FAILED(hr)) { - WARN("Failed to created recognizer instance.\n"); + WARN("Failed to created recognizer instance with grammar.\n"); return compilation_result_create(SpeechRecognitionResultStatus_GrammarCompilationFailure, (ISpeechRecognitionCompilationResult **) result); } else return compilation_result_create(SpeechRecognitionResultStatus_Success, (ISpeechRecognitionCompilationResult **) result); diff --git a/dlls/windows.media.speech/unixlib.c b/dlls/windows.media.speech/unixlib.c index 177256b2060..92dec9e2908 100644 --- a/dlls/windows.media.speech/unixlib.c +++ b/dlls/windows.media.speech/unixlib.c @@ -55,6 +55,7 @@ static void *vosk_handle; MAKE_FUNCPTR(vosk_model_new); MAKE_FUNCPTR(vosk_model_free); MAKE_FUNCPTR(vosk_recognizer_new); +MAKE_FUNCPTR(vosk_recognizer_new_grm); MAKE_FUNCPTR(vosk_recognizer_free); MAKE_FUNCPTR(vosk_recognizer_accept_waveform); MAKE_FUNCPTR(vosk_recognizer_final_result); @@ -77,6 +78,8 @@ static NTSTATUS process_attach( void *args ) goto error; \ } LOAD_FUNCPTR(vosk_model_new) + LOAD_FUNCPTR(vosk_recognizer_new) + LOAD_FUNCPTR(vosk_recognizer_new_grm) LOAD_FUNCPTR(vosk_model_free) LOAD_FUNCPTR(vosk_recognizer_new) LOAD_FUNCPTR(vosk_recognizer_free) @@ -222,12 +225,58 @@ static NTSTATUS find_model_by_locale( const char *locale, VoskModel **model ) return status; } +static NTSTATUS grammar_to_json_array(const char **grammar, UINT32 grammar_size, const char **array) +{ + size_t buf_size = strlen("[]") + 1, len; + char *buf; + UINT32 i; + + for (i = 0; i < grammar_size; ++i) + { + buf_size += strlen(grammar[i]) + 4; /* (4) - two double quotes, a comma and a space */ + } + + if (!(buf = malloc(buf_size))) + return STATUS_NO_MEMORY; + + *array = buf; + + *buf = '['; + buf++; + + for (i = 0; i < grammar_size; ++i) + { + *buf = '\"'; + buf++; + len = strlen(grammar[i]); + memcpy(buf, grammar[i], len); + buf += len; + *buf = '\"'; + buf++; + if (i < (grammar_size - 1)) + { + *buf = ','; + buf++; + *buf = ' '; + buf++; + } + } + + *buf = ']'; + buf++; + *buf = '\0'; + + TRACE("created json array %s.\n", debugstr_a(*array)); + return STATUS_SUCCESS; +} + static NTSTATUS speech_create_recognizer( void *args ) { struct speech_create_recognizer_params *params = args; VoskRecognizer *recognizer = NULL; VoskModel *model = NULL; NTSTATUS status = STATUS_SUCCESS; + const char *grammar_json; TRACE("args %p.\n", args); @@ -237,8 +286,16 @@ static NTSTATUS speech_create_recognizer( void *args ) if ((status = find_model_by_locale(params->locale, &model))) return status; - if (!(recognizer = p_vosk_recognizer_new(model, params->sample_rate))) - status = STATUS_UNSUCCESSFUL; + if (params->grammar && grammar_to_json_array(params->grammar, params->grammar_size, &grammar_json) == STATUS_SUCCESS) + { + if (!(recognizer = p_vosk_recognizer_new_grm(model, params->sample_rate, grammar_json))) + status = STATUS_UNSUCCESSFUL; + } + else + { + if (!(recognizer = p_vosk_recognizer_new(model, params->sample_rate))) + status = STATUS_UNSUCCESSFUL; + } /* VoskModel is reference-counted. A VoskRecognizer keeps a reference to its model. */ p_vosk_model_free(model); diff --git a/dlls/windows.media.speech/unixlib.h b/dlls/windows.media.speech/unixlib.h index a07d76705d5..ad2fab738b9 100644 --- a/dlls/windows.media.speech/unixlib.h +++ b/dlls/windows.media.speech/unixlib.h @@ -37,6 +37,8 @@ struct speech_create_recognizer_params speech_recognizer_handle handle; CHAR locale[LOCALE_NAME_MAX_LENGTH]; FLOAT sample_rate; + const char **grammar; + unsigned int grammar_size; }; struct speech_release_recognizer_params From c656ad9eb04e7808052faad5fa1774d33eaf58d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Tue, 28 Feb 2023 22:06:23 +0100 Subject: [PATCH 2163/2777] HACK: windows.media.speech/tests: Add tests for manual recognition testing. Speak during the delay, to test the code. CW-Bug-Id: #20134 --- dlls/windows.media.speech/tests/speech.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/dlls/windows.media.speech/tests/speech.c b/dlls/windows.media.speech/tests/speech.c index f941edee0df..1b9198ac10a 100644 --- a/dlls/windows.media.speech/tests/speech.c +++ b/dlls/windows.media.speech/tests/speech.c @@ -211,7 +211,23 @@ HRESULT WINAPI recognition_result_handler_Invoke( IHandler_RecognitionResult *if ISpeechContinuousRecognitionSession *sender, ISpeechContinuousRecognitionResultGeneratedEventArgs *args ) { - trace("iface %p, sender %p, args %p.\n", iface, sender, args); + ISpeechRecognitionResult *result; + HSTRING hstring; + HRESULT hr; + + if (!args) return S_OK; + + hr = ISpeechContinuousRecognitionResultGeneratedEventArgs_get_Result(args, &result); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ISpeechRecognitionResult_get_Text(result, &hstring); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + trace("iface %p, sender %p, args %p, text %s.\n", iface, sender, args, debugstr_w(WindowsGetStringRawBuffer(hstring, NULL))); + + WindowsDeleteString(hstring); + ISpeechRecognitionResult_Release(result); + return S_OK; } @@ -1723,7 +1739,7 @@ static void test_Recognition(void) static const WCHAR *list_constraint_name = L"Windows.Media.SpeechRecognition.SpeechRecognitionListConstraint"; static const WCHAR *recognizer_name = L"Windows.Media.SpeechRecognition.SpeechRecognizer"; static const WCHAR *speech_constraint_tag = L"test_message"; - static const WCHAR *speech_constraints[] = { L"This is a test.", L"Number 5!", L"What time is it?" }; + static const WCHAR *speech_constraints[] = { L"This is a test", L"Number 5", L"What time is it" }; ISpeechRecognitionListConstraintFactory *listconstraint_factory = NULL; IAsyncOperation_SpeechRecognitionCompilationResult *operation = NULL; IVector_ISpeechRecognitionConstraint *constraints = NULL; @@ -1897,6 +1913,8 @@ static void test_Recognition(void) ok(hr == S_OK, "ISpeechRecognizer2_get_State failed, hr %#lx.\n", hr); ok(recog_state == SpeechRecognizerState_Capturing, "recog_state was %u.\n", recog_state); + + Sleep(10000); /* * TODO: Use a loopback device together with prerecorded audio files to test the recognizer's functionality. */ From 4bcf98229506c8a705528d037f123b53239fca68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Tue, 7 Mar 2023 15:31:08 +0100 Subject: [PATCH 2164/2777] HACK: windows.media.speech: Load Vosk models from Phasmophobia. CW-Bug-Id: #20134 --- dlls/windows.media.speech/unixlib.c | 67 +++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/dlls/windows.media.speech/unixlib.c b/dlls/windows.media.speech/unixlib.c index 92dec9e2908..38ec8d3ca90 100644 --- a/dlls/windows.media.speech/unixlib.c +++ b/dlls/windows.media.speech/unixlib.c @@ -116,13 +116,55 @@ static inline VoskRecognizer *vosk_recognizer_from_handle( speech_recognizer_han return (VoskRecognizer *)(UINT_PTR)handle; } +static const char* map_lang_to_phasmophobia_dir(const char* lang, size_t len) +{ + if (!strncmp(lang, "ar", len)) + return "Arabic"; + if (!strncmp(lang, "ca", len)) + return "Catalan"; + if (!strncmp(lang, "zn", len)) + return "Chinese"; + if (!strncmp(lang, "cs", len)) + return "Czech"; + if (!strncmp(lang, "nl", len)) + return "Dutch"; + if (!strncmp(lang, "en", len)) + return "English"; + if (!strncmp(lang, "fr", len)) + return "French"; + if (!strncmp(lang, "de", len)) + return "German"; + if (!strncmp(lang, "de", len)) + return "German"; + if (!strncmp(lang, "el", len)) + return "Greek"; + if (!strncmp(lang, "it", len)) + return "Italian"; + if (!strncmp(lang, "ja", len)) + return "Japanese"; + if (!strncmp(lang, "pt", len)) + return "Portuguese"; + if (!strncmp(lang, "ru", len)) + return "Russian"; + if (!strncmp(lang, "es", len)) + return "Spanish"; + if (!strncmp(lang, "sw", len)) + return "Swedish"; + if (!strncmp(lang, "tr", len)) + return "Turkish"; + if (!strncmp(lang, "uk", len)) + return "Ukrainian"; + + return ""; +} + static NTSTATUS find_model_by_locale_and_path( const char *path, const char *locale, VoskModel **model ) { static const char *vosk_model_identifier_small = "vosk-model-small-"; static const char *vosk_model_identifier = "vosk-model-"; size_t ident_small_len = strlen(vosk_model_identifier_small); size_t ident_len = strlen(vosk_model_identifier); - char *ent_name, *model_path, *best_match, *delim; + char *ent_name, *model_path, *best_match, *delim, *appid = getenv("SteamAppId"), *str = NULL; NTSTATUS status = STATUS_UNSUCCESSFUL; struct dirent *dirent; size_t path_len, len; @@ -149,7 +191,7 @@ static NTSTATUS find_model_by_locale_and_path( const char *path, const char *loc ent_name += ident_small_len; else if (!strncmp(ent_name, vosk_model_identifier, ident_len)) ent_name += ident_len; - else + else if (strcmp(appid, "739630") != 0) continue; /* @@ -165,6 +207,12 @@ static NTSTATUS find_model_by_locale_and_path( const char *path, const char *loc if (!best_match && !strncmp(ent_name, locale, delim - locale)) best_match = strdup(dirent->d_name); + + if (!best_match && !strcmp(appid, "739630")) + { + if ((str = (char *)map_lang_to_phasmophobia_dir(locale, delim - locale))) + best_match = strdup(str); + } } closedir(dir); @@ -195,7 +243,7 @@ static NTSTATUS find_model_by_locale_and_path( const char *path, const char *loc static NTSTATUS find_model_by_locale( const char *locale, VoskModel **model ) { const char *suffix = NULL; - char *env, *path = NULL; + char *env, *path = NULL, *appid = getenv("SteamAppId"); NTSTATUS status; TRACE("locale %s, model %p.\n", debugstr_a(locale), model); @@ -222,6 +270,19 @@ static NTSTATUS find_model_by_locale( const char *locale, VoskModel **model ) status = find_model_by_locale_and_path(path, locale, model); free(path); + /* Hack to load Vosk models from Phasmophobia, so they don't need to be downloaded separately.*/ + if (status && appid && !strcmp(appid, "739630") && (env = getenv("PWD"))) + { + suffix = "/Phasmophobia_Data/StreamingAssets/LanguageModels"; + + if (!(path = malloc(strlen(env) + strlen(suffix) + 1))) + return STATUS_NO_MEMORY; + + sprintf(path, "%s%s", env, suffix); + status = find_model_by_locale_and_path(path, locale, model); + free(path); + } + return status; } From 377a34110d47ddb0b1bb028d29a2dc7757265894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Tue, 7 Mar 2023 16:36:36 +0100 Subject: [PATCH 2165/2777] windows.media.speech: Suppress verbose Unixlib traces. CW-Bug-Id: #20134 --- dlls/windows.media.speech/unixlib.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dlls/windows.media.speech/unixlib.c b/dlls/windows.media.speech/unixlib.c index 38ec8d3ca90..e98e2e69fb3 100644 --- a/dlls/windows.media.speech/unixlib.c +++ b/dlls/windows.media.speech/unixlib.c @@ -327,7 +327,6 @@ static NTSTATUS grammar_to_json_array(const char **grammar, UINT32 grammar_size, buf++; *buf = '\0'; - TRACE("created json array %s.\n", debugstr_a(*array)); return STATUS_SUCCESS; } @@ -405,8 +404,6 @@ static NTSTATUS speech_get_recognition_result( void* args ) static char *last_result = NULL; const char *tmp = NULL; - TRACE("args %p.\n", args); - if (!vosk_handle) return STATUS_NOT_SUPPORTED; @@ -427,7 +424,6 @@ static NTSTATUS speech_get_recognition_result( void* args ) last_result = (char *)tmp; last_result_len = strlen(last_result); - TRACE("last_result %s.\n", debugstr_a(last_result)); } else return STATUS_NOT_FOUND; } From 84ab296a4214223ffc00fab1cab488baecad0c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 7 Jul 2023 20:53:07 +0200 Subject: [PATCH 2166/2777] winegstreamer: Free the media source work queue outside of the CS. Possibly fixing some rare deadlock with MSFS. --- dlls/winegstreamer/media_source_old.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dlls/winegstreamer/media_source_old.c b/dlls/winegstreamer/media_source_old.c index c9a76349e82..7dd7a989d4a 100644 --- a/dlls/winegstreamer/media_source_old.c +++ b/dlls/winegstreamer/media_source_old.c @@ -1251,6 +1251,7 @@ static ULONG WINAPI media_source_Release(IMFMediaSource *iface) if (!ref) { IMFMediaSource_Shutdown(iface); + MFUnlockWorkQueue(source->async_commands_queue); IMFPresentationDescriptor_Release(source->pres_desc); IMFMediaEventQueue_Release(source->event_queue); IMFByteStream_Release(source->byte_stream); @@ -1452,8 +1453,6 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) } free(source->streams); - MFUnlockWorkQueue(source->async_commands_queue); - LeaveCriticalSection(&source->cs); return S_OK; From 8aa0257cf34d55a5d82be7671581bd94197e84cb Mon Sep 17 00:00:00 2001 From: Santino Mazza Date: Thu, 9 Mar 2023 11:28:41 -0300 Subject: [PATCH 2167/2777] mf/tests: Test media session error handling. Test error handling for mfsession_Start when a source fails at different stages. Cw-Bug-Id: #21809 (cherry picked from commit 2580799e7068ff405ee55032dcdd8dcb941d604a) --- dlls/mf/tests/mf.c | 183 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 179 insertions(+), 4 deletions(-) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 399f983983f..d4a956b5459 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -41,6 +41,39 @@ #include "initguid.h" #include "evr9.h" +#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + expect_ ## func = TRUE + +#define CHECK_EXPECT2(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func = TRUE; \ + }while(0) + +#define CHECK_EXPECT(func) \ + do { \ + CHECK_EXPECT2(func); \ + expect_ ## func = FALSE; \ + }while(0) + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +#define CHECK_NOT_CALLED(func) \ + do { \ + ok(!called_ ## func, "unexpected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +#define CLEAR_CALLED(func) \ + expect_ ## func = called_ ## func = FALSE + extern GUID DMOVideoFormat_RGB32; HRESULT (WINAPI *pMFCreateSampleCopierMFT)(IMFTransform **copier); @@ -236,10 +269,15 @@ static void init_sink_node(IMFStreamSink *stream_sink, MF_CONNECT_METHOD method, } } +DEFINE_EXPECT(test_source_BeginGetEvent); +DEFINE_EXPECT(test_source_QueueEvent); +DEFINE_EXPECT(test_source_Start); + struct test_source { IMFMediaSource IMFMediaSource_iface; LONG refcount; + HRESULT begin_get_event_res; IMFPresentationDescriptor *pd; }; @@ -294,8 +332,9 @@ static HRESULT WINAPI test_source_GetEvent(IMFMediaSource *iface, DWORD flags, I static HRESULT WINAPI test_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state) { - ok(0, "Unexpected call.\n"); - return E_NOTIMPL; + struct test_source *source = impl_from_IMFMediaSource(iface); + CHECK_EXPECT(test_source_BeginGetEvent); + return source->begin_get_event_res; } static HRESULT WINAPI test_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event) @@ -307,7 +346,7 @@ static HRESULT WINAPI test_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncRes static HRESULT WINAPI test_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type, HRESULT hr, const PROPVARIANT *value) { - ok(0, "Unexpected call.\n"); + CHECK_EXPECT(test_source_QueueEvent); return E_NOTIMPL; } @@ -326,7 +365,7 @@ static HRESULT WINAPI test_source_CreatePresentationDescriptor(IMFMediaSource *i static HRESULT WINAPI test_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *pd, const GUID *time_format, const PROPVARIANT *start_position) { - ok(0, "Unexpected call.\n"); + CHECK_EXPECT(test_source_Start); return E_NOTIMPL; } @@ -372,6 +411,7 @@ static IMFMediaSource *create_test_source(IMFPresentationDescriptor *pd) source = calloc(1, sizeof(*source)); source->IMFMediaSource_iface.lpVtbl = &test_source_vtbl; source->refcount = 1; + source->begin_get_event_res = E_NOTIMPL; IMFPresentationDescriptor_AddRef((source->pd = pd)); return &source->IMFMediaSource_iface; @@ -1914,6 +1954,41 @@ static HRESULT wait_media_event_(int line, IMFMediaSession *session, IMFAsyncCal return status; } +#define wait_media_event_until_blocking(a, b, c, d, e) wait_media_event_until_blocking_(__LINE__, a, b, c, d, e) +static HRESULT wait_media_event_until_blocking_(int line, IMFMediaSession *session, IMFAsyncCallback *callback, + MediaEventType expect_type, DWORD timeout, PROPVARIANT *value) +{ + struct test_callback *impl = impl_from_IMFAsyncCallback(callback); + MediaEventType type; + HRESULT hr, status; + DWORD ret; + GUID guid; + + do + { + hr = IMFMediaSession_BeginGetEvent(session, &impl->IMFAsyncCallback_iface, (IUnknown *)session); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ret = WaitForSingleObject(impl->event, timeout); + if (ret == WAIT_TIMEOUT) return WAIT_TIMEOUT; + hr = IMFMediaEvent_GetType(impl->media_event, &type); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } while (type != expect_type); + + ok_(__FILE__, line)(type == expect_type, "got type %lu\n", type); + + hr = IMFMediaEvent_GetExtendedType(impl->media_event, &guid); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok_(__FILE__, line)(IsEqualGUID(&guid, &GUID_NULL), "got extended type %s\n", debugstr_guid(&guid)); + + hr = IMFMediaEvent_GetValue(impl->media_event, value); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaEvent_GetStatus(impl->media_event, &status); + ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + return status; +} + static IMFMediaSource *create_media_source(const WCHAR *name, const WCHAR *mime) { IMFSourceResolver *resolver; @@ -1985,6 +2060,7 @@ static void test_media_session_events(void) struct test_stream_sink stream_sink = test_stream_sink; struct test_media_sink media_sink = test_media_sink; struct test_handler handler = test_handler; + struct test_source *source_impl; IMFAsyncCallback *callback, *callback2; IMFMediaType *input_type, *output_type; IMFTopologyNode *src_node, *sink_node; @@ -2363,6 +2439,105 @@ static void test_media_session_events(void) /* sometimes briefly leaking */ IMFMediaSession_Release(session); + + /* test IMFMediaSession_Start with source returning an error in BeginGetEvent */ + source_impl = impl_from_IMFMediaSource(source); + + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); + ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar); + + source_impl->begin_get_event_res = 0x80001234; + + SET_EXPECT(test_source_BeginGetEvent); + SET_EXPECT(test_source_QueueEvent); + SET_EXPECT(test_source_Start); + + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_until_blocking(session, callback, MESessionStarted, 1000, &propvar); + todo_wine ok(hr == 0x80001234, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar); + + CHECK_CALLED(test_source_BeginGetEvent); + todo_wine { CHECK_NOT_CALLED(test_source_Start); } + + hr = IMFMediaSession_ClearTopologies(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(media_sink.shutdown, "media sink didn't shutdown.\n"); + media_sink.shutdown = FALSE; + + source_impl->begin_get_event_res = E_NOTIMPL; + + CLEAR_CALLED(test_source_BeginGetEvent); + CLEAR_CALLED(test_source_QueueEvent); + CLEAR_CALLED(test_source_Start); + + /* sometimes briefly leaking */ + IMFMediaSession_Release(session); + + + /* test IMFMediaSession_Start when test source BeginGetEvent returns S_OK */ + hr = MFCreateMediaSession(NULL, &session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaSession_SetTopology(session, 0, topology); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event(session, callback, MESessionTopologySet, 1000, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_UNKNOWN, "got vt %u\n", propvar.vt); + ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar); + + source_impl = impl_from_IMFMediaSource(source); + source_impl->begin_get_event_res = S_OK; + + SET_EXPECT(test_source_BeginGetEvent); + SET_EXPECT(test_source_QueueEvent); + SET_EXPECT(test_source_Start); + + propvar.vt = VT_EMPTY; + hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = wait_media_event_until_blocking(session, callback, MESessionStarted, 1000, &propvar); + todo_wine ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr); + ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); + ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); + PropVariantClear(&propvar); + + CHECK_CALLED(test_source_BeginGetEvent); + CHECK_CALLED(test_source_Start); + + hr = IMFMediaSession_ClearTopologies(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaSession_Shutdown(session); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(media_sink.shutdown, "media sink didn't shutdown.\n"); + media_sink.shutdown = FALSE; + + source_impl->begin_get_event_res = E_NOTIMPL; + + CLEAR_CALLED(test_source_BeginGetEvent); + CLEAR_CALLED(test_source_QueueEvent); + CLEAR_CALLED(test_source_Start); + + /* sometimes briefly leaking */ + IMFMediaSession_Release(session); + IMFAsyncCallback_Release(callback); if (handler.current_type) From 03a6aa2b49c2f92199c4aa61a59ebeebaccf461f Mon Sep 17 00:00:00 2001 From: Santino Mazza Date: Thu, 9 Mar 2023 11:50:30 -0300 Subject: [PATCH 2168/2777] mf/session: Handle errors when subscribing to source's events. Cw-Bug-Id: #21809 (cherry picked from commit 74b64eab2049c0c6de7dded39bf5ffcf8c921da2) --- dlls/mf/session.c | 18 +++++++++++------- dlls/mf/tests/mf.c | 4 ++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 004dcc88b98..f940dd2c89f 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -866,13 +866,13 @@ static void session_command_complete_with_event(struct media_session *session, M session_command_complete(session); } -static void session_subscribe_sources(struct media_session *session) +static HRESULT session_subscribe_sources(struct media_session *session) { struct media_source *source; - HRESULT hr; + HRESULT hr = S_OK; if (session->presentation.flags & SESSION_FLAG_SOURCES_SUBSCRIBED) - return; + return hr; LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) { @@ -880,10 +880,12 @@ static void session_subscribe_sources(struct media_session *session) source->object))) { WARN("Failed to subscribe to source events, hr %#lx.\n", hr); + return hr; } } session->presentation.flags |= SESSION_FLAG_SOURCES_SUBSCRIBED; + return hr; } static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position) @@ -909,7 +911,11 @@ static void session_start(struct media_session *session, const GUID *time_format session->presentation.start_position.vt = VT_EMPTY; PropVariantCopy(&session->presentation.start_position, start_position); - session_subscribe_sources(session); + if (FAILED(hr = session_subscribe_sources(session))) + { + session_command_complete_with_event(session, MESessionStarted, hr, NULL); + return; + } LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) { @@ -1308,10 +1314,8 @@ static void session_set_rate(struct media_session *session, BOOL thin, float rat if (SUCCEEDED(hr)) hr = IMFRateControl_GetRate(session->clock_rate_control, NULL, &clock_rate); - if (SUCCEEDED(hr) && (rate != clock_rate)) + if (SUCCEEDED(hr) && (rate != clock_rate) && SUCCEEDED(hr = session_subscribe_sources(session))) { - session_subscribe_sources(session); - LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) { if (SUCCEEDED(hr = MFGetService(source->object, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateControl, diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index d4a956b5459..d2cb0ff792b 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -2464,13 +2464,13 @@ static void test_media_session_events(void) hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = wait_media_event_until_blocking(session, callback, MESessionStarted, 1000, &propvar); - todo_wine ok(hr == 0x80001234, "Unexpected hr %#lx.\n", hr); + ok(hr == 0x80001234, "Unexpected hr %#lx.\n", hr); ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); PropVariantClear(&propvar); CHECK_CALLED(test_source_BeginGetEvent); - todo_wine { CHECK_NOT_CALLED(test_source_Start); } + CHECK_NOT_CALLED(test_source_Start); hr = IMFMediaSession_ClearTopologies(session); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); From fb4b9e437aaf5caf84767b913bf6bd5991fd6c55 Mon Sep 17 00:00:00 2001 From: Santino Mazza Date: Fri, 7 Apr 2023 14:07:26 -0300 Subject: [PATCH 2169/2777] mf/session: Handle error when a source fails to start. Cw-Bug-Id: #21809 (cherry picked from commit dd6b2f9ab5e65142882748f873a1c7c2ed10cb00) --- dlls/mf/session.c | 4 ++++ dlls/mf/tests/mf.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index f940dd2c89f..e4d35f08e6a 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -920,7 +920,11 @@ static void session_start(struct media_session *session, const GUID *time_format LIST_FOR_EACH_ENTRY(source, &session->presentation.sources, struct media_source, entry) { if (FAILED(hr = IMFMediaSource_Start(source->source, source->pd, &GUID_NULL, start_position))) + { WARN("Failed to start media source %p, hr %#lx.\n", source->source, hr); + session_command_complete_with_event(session, MESessionStarted, hr, NULL); + return; + } } session->state = SESSION_STATE_STARTING_SOURCES; diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index d2cb0ff792b..cc28786cf65 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -2513,7 +2513,7 @@ static void test_media_session_events(void) hr = IMFMediaSession_Start(session, &GUID_NULL, &propvar); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = wait_media_event_until_blocking(session, callback, MESessionStarted, 1000, &propvar); - todo_wine ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr); + ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr); ok(propvar.vt == VT_EMPTY, "got vt %u\n", propvar.vt); ok(propvar.punkVal != (IUnknown *)topology, "got punkVal %p\n", propvar.punkVal); PropVariantClear(&propvar); From f08ca377b21da906e0f778c4cf87be4931da086b Mon Sep 17 00:00:00 2001 From: Santino Mazza Date: Tue, 2 May 2023 18:32:18 -0300 Subject: [PATCH 2170/2777] mf/session: Reset presentation flags when session_clear_presentation is called. This prevents hangs when a program sets a new topology after stopping the current topology, because if we don't reset the flags to 0 the session will not subscribe to the events of the new topology sources. Cw-Bug-Id: #21809 (cherry picked from commit dedc0684e9de95059a8605e8592d1c734375c5c4) --- dlls/mf/session.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index e4d35f08e6a..75441e99775 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -800,6 +800,7 @@ static void session_clear_presentation(struct media_session *session) IMFTopology_Clear(session->presentation.current_topology); session->presentation.topo_status = MF_TOPOSTATUS_INVALID; + session->presentation.flags = 0; LIST_FOR_EACH_ENTRY_SAFE(source, source2, &session->presentation.sources, struct media_source, entry) { From 153911dbb44f49c8200392ea0246ac3adc5bce2e Mon Sep 17 00:00:00 2001 From: Santino Mazza Date: Fri, 9 Jun 2023 16:59:27 -0300 Subject: [PATCH 2171/2777] mf: Clear end of presentation only if topo_status is ready. Cw-Bug-Id: #21809 --- dlls/mf/session.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 75441e99775..25e1c474b44 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -2570,7 +2570,8 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, case SESSION_CMD_STOP: if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION) session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED); - session_clear_end_of_presentation(session); + if (session->presentation.topo_status == MF_TOPOSTATUS_READY) + session_clear_end_of_presentation(session); session_stop(session); break; case SESSION_CMD_CLOSE: From 0e26373ad406238b7e831f6cd68dfd399ca4d414 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Sat, 22 Jul 2023 14:47:13 -0400 Subject: [PATCH 2172/2777] Revert "sapi: ISpObjectToken CreateInstance support ISpAudio" This reverts commit b9f13c5efd15621354e4ebd02c5164a24d5b6047. CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/token.c | 279 +--------------------------------------------- 1 file changed, 1 insertion(+), 278 deletions(-) diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index 4e44ba8a354..385555a4cef 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -1166,290 +1166,13 @@ static HRESULT WINAPI token_GetCategory( ISpObjectToken *iface, return E_NOTIMPL; } -struct speech_audio -{ - ISpAudio ISpAudio_iface; - LONG ref; -}; - -static inline struct speech_audio *impl_from_ISpAudio(ISpAudio *iface) -{ - return CONTAINING_RECORD(iface, struct speech_audio, ISpAudio_iface); -} - -static HRESULT WINAPI spaudio_QueryInterface(ISpAudio *iface, REFIID iid, void **obj) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - - TRACE("(%p, %s %p).\n", audio, debugstr_guid(iid), obj); - - if (IsEqualIID(iid, &IID_IUnknown) || - IsEqualIID(iid, &IID_ISequentialStream) || - IsEqualIID(iid, &IID_IStream) || - IsEqualIID(iid, &IID_ISpStreamFormat) || - IsEqualIID(iid, &IID_ISpAudio)) - *obj = &audio->ISpAudio_iface; - else - { - *obj = NULL; - FIXME("interface %s not implemented.\n", debugstr_guid(iid)); - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown *)*obj); - return S_OK; -} - -static ULONG WINAPI spaudio_AddRef(ISpAudio *iface) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - ULONG ref = InterlockedIncrement(&audio->ref); - - TRACE("(%p): ref=%lu.\n", audio, ref); - - return ref; -} - -static ULONG WINAPI spaudio_Release(ISpAudio *iface) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - ULONG ref = InterlockedDecrement(&audio->ref); - - TRACE("(%p): ref=%lu.\n", audio, ref); - - if (!ref) - { - heap_free(audio); - } - - return ref; -} - -static HRESULT WINAPI spaudio_Read(ISpAudio *iface,void *pv, ULONG cb, ULONG *pcbRead) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - - FIXME("%p, %p, %ld %p\n", audio, pv, cb, pcbRead); - - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_Write(ISpAudio *iface, const void *pv, ULONG cb, ULONG *pcbWritten) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - - FIXME("%p, %p, %ld %p\n", audio, pv, cb, pcbWritten); - - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_Seek(ISpAudio *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("%p, %s, %ld, %p\n", audio, wine_dbgstr_longlong(dlibMove.QuadPart), dwOrigin, plibNewPosition); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_SetSize(ISpAudio *iface, ULARGE_INTEGER libNewSize) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("(%p, %s)\n", audio, wine_dbgstr_longlong(libNewSize.QuadPart)); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_CopyTo(ISpAudio *iface,IStream *pstm, ULARGE_INTEGER cb, - ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("(%p, %p, %s, %p, %p)\n", audio, pstm, wine_dbgstr_longlong(cb.QuadPart), pcbRead, pcbWritten); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_Commit(ISpAudio *iface,DWORD grfCommitFlags) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("(%p, %#lx)\n", audio, grfCommitFlags); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_Revert(ISpAudio *iface) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("(%p)\n", audio); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_LockRegion(ISpAudio *iface, ULARGE_INTEGER offset, ULARGE_INTEGER cb, DWORD dwLockType) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("(%p, %s, %s, %ld)\n", audio, wine_dbgstr_longlong(offset.QuadPart), - wine_dbgstr_longlong(cb.QuadPart), dwLockType); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_UnlockRegion(ISpAudio *iface,ULARGE_INTEGER offset, ULARGE_INTEGER cb, DWORD dwLockType) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("(%p, %s, %s, %ld)\n", audio, wine_dbgstr_longlong(offset.QuadPart), - wine_dbgstr_longlong(cb.QuadPart), dwLockType); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_Stat(ISpAudio *iface, STATSTG *stg, DWORD flag) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("%p, %p, %ld\n", audio, stg, flag); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_Clone(ISpAudio *iface, IStream **ppstm) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("%p, %p\n", audio, ppstm); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_GetFormat(ISpAudio *iface, GUID *format, WAVEFORMATEX **wave) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("%p, %p, %p\n", audio, format, wave); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_SetState(ISpAudio *iface, SPAUDIOSTATE state, ULONGLONG reserved) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("%p, %d, %s\n", audio, state, wine_dbgstr_longlong(reserved)); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_SetFormat(ISpAudio *iface, REFGUID guid, const WAVEFORMATEX *wave) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("%p, %s, %p\n", audio, debugstr_guid(guid), wave); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_GetStatus(ISpAudio *iface, SPAUDIOSTATUS *status) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("%p, %p\n", audio, status); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_SetBufferInfo(ISpAudio *iface,const SPAUDIOBUFFERINFO *buffer) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("%p, %p\n", audio, buffer); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_GetBufferInfo(ISpAudio *iface, SPAUDIOBUFFERINFO *buffer) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("%p, %p\n", audio, buffer); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_GetDefaultFormat(ISpAudio *iface, GUID *guid, WAVEFORMATEX **wave) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("%p, %p, %p\n", audio, guid, wave); - return E_NOTIMPL; -} - -static HANDLE WINAPI spaudio_EventHandle(ISpAudio *iface) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("%p\n", audio); - return NULL; -} - -static HRESULT WINAPI spaudio_GetVolumeLevel(ISpAudio *iface, ULONG *level) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("%p, %p\n", audio, level); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_SetVolumeLevel(ISpAudio *iface, ULONG level) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("%p, %ld\n", audio, level); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_GetBufferNotifySize(ISpAudio *iface, ULONG *size) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("%p, %p\n", audio, size); - return E_NOTIMPL; -} - -static HRESULT WINAPI spaudio_SetBufferNotifySize(ISpAudio *iface, ULONG size) -{ - struct speech_audio *audio = impl_from_ISpAudio(iface); - FIXME("%p, %ld\n", audio, size); - return E_NOTIMPL; -} - -const struct ISpAudioVtbl spaudio_vtbl = -{ - spaudio_QueryInterface, - spaudio_AddRef, - spaudio_Release, - spaudio_Read, - spaudio_Write, - spaudio_Seek, - spaudio_SetSize, - spaudio_CopyTo, - spaudio_Commit, - spaudio_Revert, - spaudio_LockRegion, - spaudio_UnlockRegion, - spaudio_Stat, - spaudio_Clone, - spaudio_GetFormat, - spaudio_SetState, - spaudio_SetFormat, - spaudio_GetStatus, - spaudio_SetBufferInfo, - spaudio_GetBufferInfo, - spaudio_GetDefaultFormat, - spaudio_EventHandle, - spaudio_GetVolumeLevel, - spaudio_SetVolumeLevel, - spaudio_GetBufferNotifySize, - spaudio_SetBufferNotifySize -}; - -static HRESULT speech_audio_create(void **obj) -{ - struct speech_audio *This = heap_alloc(sizeof(*This)); - - if (!This) - return E_OUTOFMEMORY; - This->ISpAudio_iface.lpVtbl = &spaudio_vtbl; - This->ref = 1; - - *obj = &This->ISpAudio_iface; - return S_OK; -} - static HRESULT WINAPI token_CreateInstance( ISpObjectToken *iface, IUnknown *outer, DWORD class_context, REFIID riid, void **object ) { - struct object_token *This = impl_from_ISpObjectToken( iface ); - - FIXME( "(%p)->(%p 0x%08lx %s, %p): semi-stub\n", This, outer, class_context, debugstr_guid( riid ), object); - - if (IsEqualIID(riid, &IID_ISpAudio)) - { - return speech_audio_create(object); - } + FIXME( "stub\n" ); return E_NOTIMPL; } From 3519eb67fa2f397d3f605664ceb8bc99308cea5b Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Tue, 25 Apr 2023 19:15:59 -0400 Subject: [PATCH 2173/2777] include: Add more sapi structs and enums. (cherry picked from commit 5f977d2fa878297748839eb767857d5a84954688) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- include/sapi.idl | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/include/sapi.idl b/include/sapi.idl index cd5d6044bdf..92a2881501c 100644 --- a/include/sapi.idl +++ b/include/sapi.idl @@ -574,6 +574,59 @@ typedef [restricted, hidden] struct SPAUDIOBUFFERINFO ULONG ulMsEventBias; } SPAUDIOBUFFERINFO; +typedef [hidden] enum SPPARTOFSPEECH +{ + SPPS_NotOverriden = -1, + SPPS_Unknown = 0, + SPPS_Noun = 0x1000, + SPPS_Verb = 0x2000, + SPPS_Modifier = 0x3000, + SPPS_Function = 0x4000, + SPPS_Interjection = 0x5000, + SPPS_Noncontent = 0x6000, + SPPS_LMA = 0x7000, + SPPS_SuppressWord = 0xF000 +} SPPARTOFSPEECH; + +typedef [restricted, hidden] struct SPVPITCH +{ + long MiddleAdj; + long RangeAdj; +} SPVPITCH; + +typedef [hidden] enum SPVACTIONS +{ + SPVA_Speak = 0, + SPVA_Silence, + SPVA_Pronounce, + SPVA_Bookmark, + SPVA_SpellOut, + SPVA_Section, + SPVA_ParseUnknownTag +} SPVACTIONS; + +typedef [restricted, hidden] struct SPVCONTEXT +{ + LPCWSTR pCategory; + LPCWSTR pBefore; + LPCWSTR pAfter; +} SPVCONTEXT; + +typedef [restricted, hidden] struct SPVSTATE +{ + SPVACTIONS eAction; + LANGID LangID; + WORD wReserved; + long EmphAdj; + long RateAdj; + ULONG Volume; + SPVPITCH PitchAdj; + ULONG SilenceMSecs; + SPPHONEID *pPhoneIds; + SPPARTOFSPEECH ePartOfSpeech; + SPVCONTEXT Context; +} SPVSTATE; + cpp_quote("#if defined(__GNUC__)") cpp_quote("#define SPCAT_AUDIOOUT (const WCHAR []){ 'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E','\\\\','S','O','F','T','W','A','R','E','\\\\','M','i','c','r','o','s','o','f','t','\\\\','S','p','e','e','c','h','\\\\','A','u','d','i','o','O','u','t','p','u','t',0 }") From 07995c5c07bb900351df31dc3817843e88d7718b Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Tue, 25 Apr 2023 19:17:50 -0400 Subject: [PATCH 2174/2777] include: Add ISpTTSEngineSite and ISpTTSEngine interfaces. (cherry picked from commit 7f1df4b27dde3d79a6d5f0b709c1e5c32582b20b) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- include/sapiddk.idl | 63 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/include/sapiddk.idl b/include/sapiddk.idl index 670b8c0dce5..46aebbb9a12 100644 --- a/include/sapiddk.idl +++ b/include/sapiddk.idl @@ -49,6 +49,69 @@ interface ISpObjectTokenEnumBuilder : IEnumSpObjectTokens HRESULT Sort([in] LPCWSTR pszTokenIdToListFirst); } +typedef enum SPVSKIPTYPE +{ + SPVST_SENTENCE = (1L << 0) +} SPVSKIPTYPE; + +typedef enum SPVESACTIONS +{ + SPVES_CONTINUE = 0, + SPVES_ABORT = (1L << 0), + SPVES_SKIP = (1L << 1), + SPVES_RATE = (1L << 2), + SPVES_VOLUME = (1L << 3) +} SPVESACTIONS; + +[ + object, + uuid(9880499b-cce9-11d2-b503-00c04f797396), + helpstring("ISpTTSEngineSite"), + pointer_default(unique), + local +] +interface ISpTTSEngineSite : ISpEventSink +{ + HRESULT GetActions(); + HRESULT Write([in] const void *pBuff, + [in] ULONG cb, + [out] ULONG *pcbWritten); + HRESULT GetRate([out] long *pRateAdjust); + HRESULT GetVolume([out] USHORT *pusVolume); + HRESULT GetSkipInfo([out] SPVSKIPTYPE *peType, + [out] long *plNumItems); + HRESULT CompleteSkip([in] long lNumSkipped); +}; + +typedef struct SPVTEXTFRAG +{ + struct SPVTEXTFRAG* pNext; + SPVSTATE State; + LPCWSTR pTextStart; + ULONG ulTextLen; + ULONG ulTextSrcOffset; +} SPVTEXTFRAG; + +[ + object, + uuid(a74d7c8e-4cc5-4f2f-a6eb-804dee18500e), + helpstring("ISpTTSEngine"), + pointer_default(unique), + local +] +interface ISpTTSEngine : IUnknown +{ + HRESULT Speak([in] DWORD dwSpeakFlags, + [in] REFGUID rguidFormatId, + [in] const WAVEFORMATEX *pWaveFormatEx, + [in] const SPVTEXTFRAG *pTextFragList, + [in] ISpTTSEngineSite *pOutputSite); + HRESULT GetOutputFormat([in] const GUID *pTargetFmtId, + [in] const WAVEFORMATEX *pTargetWaveFormatEx, + [out] GUID *pOutputFormatId, + [out] WAVEFORMATEX **ppCoMemOutputWaveFormatEx); +}; + [ helpstring("Speech Object DDK Library"), uuid(9903f14c-12ce-4c99-9986-2ee3d7d588a8), From 0aed394c5bcf57c5552b3ce5a9d4d75cae80cb05 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Thu, 4 May 2023 00:11:29 -0400 Subject: [PATCH 2175/2777] sapi: Implement ISpRegDataKey::SetStringValue. (cherry picked from commit 762918c2ecc9d11c9d54a9f1147f6f1241017e40) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/token.c | 14 +++++++++++++- dlls/sapi/token.c | 14 ++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/dlls/sapi/tests/token.c b/dlls/sapi/tests/token.c index 958c50359f5..792b65a6366 100644 --- a/dlls/sapi/tests/token.c +++ b/dlls/sapi/tests/token.c @@ -33,7 +33,7 @@ static void test_data_key(void) HRESULT hr; HKEY key; LONG res; - WCHAR *value; + WCHAR *value = NULL; hr = CoCreateInstance( &CLSID_SpDataKey, NULL, CLSCTX_INPROC_SERVER, &IID_ISpRegDataKey, (void **)&data_key ); @@ -49,6 +49,9 @@ static void test_data_key(void) hr = ISpRegDataKey_GetStringValue( data_key, L"Voice", &value ); ok( hr == E_HANDLE, "got %08lx\n", hr ); + hr = ISpRegDataKey_SetStringValue( data_key, L"Voice", L"Test" ); + ok( hr == E_HANDLE, "got %08lx\n", hr ); + hr = ISpRegDataKey_SetKey( data_key, key, FALSE ); ok( hr == S_OK, "got %08lx\n", hr ); hr = ISpRegDataKey_SetKey( data_key, key, FALSE ); @@ -60,6 +63,14 @@ static void test_data_key(void) hr = ISpRegDataKey_GetStringValue( data_key, L"", &value ); ok( hr == SPERR_NOT_FOUND, "got %08lx\n", hr ); + hr = ISpRegDataKey_SetStringValue( data_key, L"Voice", L"Test" ); + ok( hr == S_OK, "got %08lx\n", hr ); + + hr = ISpRegDataKey_GetStringValue( data_key, L"Voice", &value ); + ok( hr == S_OK, "got %08lx\n", hr ); + ok( !wcscmp( value, L"Test" ), "got %s\n", wine_dbgstr_w(value) ); + CoTaskMemFree( value ); + hr = ISpRegDataKey_CreateKey( data_key, L"Testing", &sub ); ok( hr == S_OK, "got %08lx\n", hr ); ISpDataKey_Release(sub); @@ -361,6 +372,7 @@ static void test_object_token(void) START_TEST(token) { CoInitialize( NULL ); + RegDeleteTreeA( HKEY_CURRENT_USER, "Software\\Winetest\\sapi" ); test_data_key(); test_token_category(); test_token_enum(); diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index 385555a4cef..6c862bb030c 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -124,8 +124,18 @@ static HRESULT WINAPI data_key_GetData( ISpRegDataKey *iface, LPCWSTR name, static HRESULT WINAPI data_key_SetStringValue( ISpRegDataKey *iface, LPCWSTR name, LPCWSTR value ) { - FIXME( "stub\n" ); - return E_NOTIMPL; + struct data_key *This = impl_from_ISpRegDataKey( iface ); + DWORD ret, size; + + TRACE( "%p, %s, %s\n", This, debugstr_w(name), debugstr_w(value) ); + + if (!This->key) + return E_HANDLE; + + size = (wcslen(value) + 1) * sizeof(WCHAR); + ret = RegSetValueExW( This->key, name, 0, REG_SZ, (BYTE *)value, size ); + + return HRESULT_FROM_WIN32(ret); } static HRESULT WINAPI data_key_GetStringValue( ISpRegDataKey *iface, From 213dd4193e4e275d2e7797aef76e1afe53bbcdb9 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Thu, 4 May 2023 12:34:13 -0400 Subject: [PATCH 2176/2777] sapi: Ignore read_only in ISpRegDataKey::SetKey. (cherry picked from commit 51e84c02e72319bf2532b3c2b1e320abd1f6ca54) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/token.c | 24 ++++++++++++++++++++++++ dlls/sapi/token.c | 4 +--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/dlls/sapi/tests/token.c b/dlls/sapi/tests/token.c index 792b65a6366..603e2143ff9 100644 --- a/dlls/sapi/tests/token.c +++ b/dlls/sapi/tests/token.c @@ -76,6 +76,30 @@ static void test_data_key(void) ISpDataKey_Release(sub); ISpRegDataKey_Release( data_key ); + + hr = CoCreateInstance( &CLSID_SpDataKey, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpRegDataKey, (void **)&data_key ); + ok( hr == S_OK, "got %08lx\n", hr ); + + res = RegOpenKeyExA( HKEY_CURRENT_USER, "Software\\Winetest\\sapi", 0, KEY_ALL_ACCESS, &key ); + ok( res == ERROR_SUCCESS, "got %ld\n", res ); + + hr = ISpRegDataKey_SetKey( data_key, key, TRUE ); + ok( hr == S_OK, "got %08lx\n", hr ); + + hr = ISpRegDataKey_SetStringValue( data_key, L"Voice2", L"Test2" ); + ok( hr == S_OK, "got %08lx\n", hr ); + + hr = ISpRegDataKey_GetStringValue( data_key, L"Voice2", &value ); + ok( hr == S_OK, "got %08lx\n", hr ); + ok( !wcscmp( value, L"Test2" ), "got %s\n", wine_dbgstr_w(value) ); + CoTaskMemFree( value ); + + hr = ISpRegDataKey_CreateKey( data_key, L"Testing2", &sub ); + ok( hr == S_OK, "got %08lx\n", hr ); + ISpDataKey_Release(sub); + + ISpRegDataKey_Release( data_key ); } static void test_token_category(void) diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index 6c862bb030c..74ef6884fbc 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -40,7 +40,6 @@ struct data_key LONG ref; HKEY key; - BOOL read_only; }; static struct data_key *impl_from_ISpRegDataKey( ISpRegDataKey *iface ) @@ -253,8 +252,8 @@ static HRESULT WINAPI data_key_SetKey( ISpRegDataKey *iface, if (This->key) return SPERR_ALREADY_INITIALIZED; + /* read_only is ignored in Windows implementations. */ This->key = key; - This->read_only = read_only; return S_OK; } @@ -287,7 +286,6 @@ HRESULT data_key_create( IUnknown *outer, REFIID iid, void **obj ) This->ISpRegDataKey_iface.lpVtbl = &data_key_vtbl; This->ref = 1; This->key = NULL; - This->read_only = FALSE; hr = ISpRegDataKey_QueryInterface( &This->ISpRegDataKey_iface, iid, obj ); From dbeddd320096f0e36e479f61f7efbd87062b2dcd Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Thu, 4 May 2023 00:17:23 -0400 Subject: [PATCH 2177/2777] sapi: Implement ISpRegDataKey::OpenKey. (cherry picked from commit 3bba4065d3af9868c56afe3046220dd11592a5d9) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/token.c | 7 +++++++ dlls/sapi/token.c | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/dlls/sapi/tests/token.c b/dlls/sapi/tests/token.c index 603e2143ff9..2602b043980 100644 --- a/dlls/sapi/tests/token.c +++ b/dlls/sapi/tests/token.c @@ -71,10 +71,17 @@ static void test_data_key(void) ok( !wcscmp( value, L"Test" ), "got %s\n", wine_dbgstr_w(value) ); CoTaskMemFree( value ); + hr = ISpRegDataKey_OpenKey( data_key, L"Testing", &sub ); + ok( hr == SPERR_NOT_FOUND, "got %08lx\n", hr ); + hr = ISpRegDataKey_CreateKey( data_key, L"Testing", &sub ); ok( hr == S_OK, "got %08lx\n", hr ); ISpDataKey_Release(sub); + hr = ISpRegDataKey_OpenKey( data_key, L"Testing", &sub ); + ok( hr == S_OK, "got %08lx\n", hr ); + ISpDataKey_Release(sub); + ISpRegDataKey_Release( data_key ); hr = CoCreateInstance( &CLSID_SpDataKey, NULL, CLSCTX_INPROC_SERVER, diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index 74ef6884fbc..7bd28dca31c 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -186,8 +186,37 @@ static HRESULT WINAPI data_key_GetDWORD( ISpRegDataKey *iface, static HRESULT WINAPI data_key_OpenKey( ISpRegDataKey *iface, LPCWSTR name, ISpDataKey **sub_key ) { - FIXME( "stub\n" ); - return E_NOTIMPL; + struct data_key *This = impl_from_ISpRegDataKey( iface ); + ISpRegDataKey *spregkey; + HRESULT hr; + HKEY key; + LONG ret; + + TRACE( "%p, %s, %p\n", This, debugstr_w(name), sub_key ); + + ret = RegOpenKeyExW( This->key, name, 0, KEY_ALL_ACCESS, &key ); + if (ret != ERROR_SUCCESS) + return SPERR_NOT_FOUND; + + hr = data_key_create( NULL, &IID_ISpRegDataKey, (void**)&spregkey ); + if (FAILED(hr)) + { + RegCloseKey( key ); + return hr; + } + + hr = ISpRegDataKey_SetKey( spregkey, key, FALSE ); + if (FAILED(hr)) + { + RegCloseKey( key ); + ISpRegDataKey_Release( spregkey ); + return hr; + } + + hr = ISpRegDataKey_QueryInterface( spregkey, &IID_ISpDataKey, (void**)sub_key ); + ISpRegDataKey_Release( spregkey ); + + return hr; } static HRESULT WINAPI data_key_CreateKey( ISpRegDataKey *iface, From 6c6b5f461432718a613d4f8d25d262f45af031b7 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Thu, 4 May 2023 00:23:35 -0400 Subject: [PATCH 2178/2777] sapi: Use ISpRegDataKey in object_token. (cherry picked from commit f6c1a7444ccb96c4990f55a6a42e5d3fb0d05534) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/token.c | 102 ++++++++++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 45 deletions(-) diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index 7bd28dca31c..0465819de56 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -52,7 +52,7 @@ struct object_token ISpObjectToken ISpObjectToken_iface; LONG ref; - HKEY token_key; + ISpRegDataKey *data_key; WCHAR *token_id; }; @@ -496,6 +496,23 @@ static HRESULT parse_cat_id( const WCHAR *str, HKEY *root, const WCHAR **sub_key return S_FALSE; } +static HRESULT WINAPI create_data_key_with_hkey( HKEY key, ISpRegDataKey **data_key ) +{ + HRESULT hr; + + if (FAILED(hr = CoCreateInstance( &CLSID_SpDataKey, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpRegDataKey, (void **)data_key ) )) + return hr; + + if (FAILED(hr = ISpRegDataKey_SetKey( *data_key, key, TRUE ))) + { + ISpRegDataKey_Release( *data_key ); + *data_key = NULL; + } + + return hr; +} + static HRESULT WINAPI token_category_SetId( ISpObjectTokenCategory *iface, LPCWSTR id, BOOL create ) { @@ -518,17 +535,12 @@ static HRESULT WINAPI token_category_SetId( ISpObjectTokenCategory *iface, res = RegOpenKeyExW( root, subkey, 0, KEY_ALL_ACCESS, &key ); if (res) return SPERR_INVALID_REGISTRY_KEY; - hr = CoCreateInstance( &CLSID_SpDataKey, NULL, CLSCTX_ALL, - &IID_ISpRegDataKey, (void **)&This->data_key ); - if (FAILED(hr)) goto fail; - - hr = ISpRegDataKey_SetKey( This->data_key, key, FALSE ); - if (FAILED(hr)) goto fail; - - return hr; + if (FAILED(hr = create_data_key_with_hkey( key, &This->data_key ))) + { + RegCloseKey( key ); + return hr; + } -fail: - RegCloseKey( key ); return hr; } @@ -748,6 +760,7 @@ static HRESULT WINAPI token_enum_Next( ISpObjectTokenEnumBuilder *iface, WCHAR *subkey_name; HKEY sub_key; DWORD size; + ISpRegDataKey *data_key; TRACE( "(%p)->(%lu %p %p)\n", This, num, tokens, fetched ); @@ -777,15 +790,24 @@ static HRESULT WINAPI token_enum_Next( ISpObjectTokenEnumBuilder *iface, return E_FAIL; } + hr = create_data_key_with_hkey( sub_key, &data_key ); + if (FAILED(hr)) + { + free( subkey_name ); + RegCloseKey( sub_key ); + return hr; + } + hr = token_create( NULL, &IID_ISpObjectToken, (void**)tokens ); if (FAILED(hr)) { free( subkey_name ); + ISpRegDataKey_Release( data_key ); return hr; } object = impl_from_ISpObjectToken( *tokens ); - object->token_key = sub_key; + object->data_key = data_key; object->token_id = subkey_name; if (fetched) *fetched = 1; @@ -823,6 +845,7 @@ static HRESULT WINAPI token_enum_Item( ISpObjectTokenEnumBuilder *iface, DWORD size; LONG ret; HKEY key; + ISpRegDataKey *data_key; TRACE( "%p, %lu, %p\n", This, index, token ); @@ -849,15 +872,24 @@ static HRESULT WINAPI token_enum_Item( ISpObjectTokenEnumBuilder *iface, return HRESULT_FROM_WIN32(ret); } + hr = create_data_key_with_hkey( key, &data_key ); + if (FAILED(hr)) + { + free( subkey ); + RegCloseKey( key ); + return hr; + } + hr = token_create( NULL, &IID_ISpObjectToken, (void**)&subtoken ); if (FAILED(hr)) { free( subkey ); + ISpRegDataKey_Release( data_key ); return hr; } object = impl_from_ISpObjectToken( subtoken ); - object->token_key = key; + object->data_key = data_key; object->token_id = subkey; *token = subtoken; @@ -1014,7 +1046,7 @@ static ULONG WINAPI token_Release( ISpObjectToken *iface ) if (!ref) { - if (This->token_key) RegCloseKey( This->token_key ); + if (This->data_key) ISpRegDataKey_Release( This->data_key ); free( This->token_id ); free( This ); } @@ -1070,36 +1102,10 @@ static HRESULT WINAPI token_OpenKey( ISpObjectToken *iface, LPCWSTR name, ISpDataKey **sub_key ) { struct object_token *This = impl_from_ISpObjectToken( iface ); - ISpRegDataKey *spregkey; - HRESULT hr; - HKEY key; - LONG ret; TRACE( "%p, %s, %p\n", This, debugstr_w(name), sub_key ); - ret = RegOpenKeyExW (This->token_key, name, 0, KEY_ALL_ACCESS, &key); - if (ret != ERROR_SUCCESS) - return SPERR_NOT_FOUND; - - hr = data_key_create(NULL, &IID_ISpRegDataKey, (void**)&spregkey); - if (FAILED(hr)) - { - RegCloseKey(key); - return hr; - } - - hr = ISpRegDataKey_SetKey(spregkey, key, FALSE); - if (FAILED(hr)) - { - RegCloseKey(key); - ISpRegDataKey_Release(spregkey); - return hr; - } - - hr = ISpRegDataKey_QueryInterface(spregkey, &IID_ISpDataKey, (void**)sub_key); - ISpRegDataKey_Release(spregkey); - - return hr; + return ISpRegDataKey_OpenKey( This->data_key, name, sub_key ); } static HRESULT WINAPI token_CreateKey( ISpObjectToken *iface, @@ -1150,7 +1156,7 @@ static HRESULT WINAPI token_SetId( ISpObjectToken *iface, FIXME( "(%p)->(%s %s %d): semi-stub\n", This, debugstr_w( category_id ), debugstr_w(token_id), create ); - if (This->token_key) return SPERR_ALREADY_INITIALIZED; + if (This->data_key) return SPERR_ALREADY_INITIALIZED; if (!token_id) return E_POINTER; @@ -1163,7 +1169,13 @@ static HRESULT WINAPI token_SetId( ISpObjectToken *iface, res = RegOpenKeyExW( root, subkey, 0, KEY_ALL_ACCESS, &key ); if (res) return SPERR_NOT_FOUND; - This->token_key = key; + hr = create_data_key_with_hkey( key, &This->data_key ); + if (FAILED(hr)) + { + RegCloseKey( key ); + return hr; + } + This->token_id = wcsdup(token_id); return S_OK; @@ -1176,7 +1188,7 @@ static HRESULT WINAPI token_GetId( ISpObjectToken *iface, TRACE( "%p, %p\n", This, token_id); - if (!This->token_key) + if (!This->data_key) return SPERR_UNINITIALIZED; if (!token_id) @@ -1309,7 +1321,7 @@ HRESULT token_create( IUnknown *outer, REFIID iid, void **obj ) This->ISpObjectToken_iface.lpVtbl = &token_vtbl; This->ref = 1; - This->token_key = NULL; + This->data_key = NULL; This->token_id = NULL; hr = ISpObjectToken_QueryInterface( &This->ISpObjectToken_iface, iid, obj ); From 6f155a952deb7d869b64ac69d09c6a3ca83c72cd Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Thu, 4 May 2023 00:25:03 -0400 Subject: [PATCH 2179/2777] sapi: Implement ISpObjectToken::Set/GetStringValue. (cherry picked from commit 26d60533d206a633242f79749f0d54ae2665d134) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/token.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index 0465819de56..6f8d677c9d0 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -1073,15 +1073,21 @@ static HRESULT WINAPI token_GetData( ISpObjectToken *iface, static HRESULT WINAPI token_SetStringValue( ISpObjectToken *iface, LPCWSTR name, LPCWSTR value ) { - FIXME( "stub\n" ); - return E_NOTIMPL; + struct object_token *This = impl_from_ISpObjectToken( iface ); + + TRACE( "%p, %s, %s\n", This, debugstr_w(name), debugstr_w(value) ); + + return ISpRegDataKey_SetStringValue( This->data_key, name, value ); } static HRESULT WINAPI token_GetStringValue( ISpObjectToken *iface, LPCWSTR name, LPWSTR *value ) { - FIXME( "stub\n" ); - return E_NOTIMPL; + struct object_token *This = impl_from_ISpObjectToken( iface ); + + TRACE( "%p, %s, %p\n", This, debugstr_w(name), value ); + + return ISpRegDataKey_GetStringValue( This->data_key, name, value ); } static HRESULT WINAPI token_SetDWORD( ISpObjectToken *iface, From c2571261a1fe95bf63891c9968766c076beaa83c Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Thu, 4 May 2023 00:32:24 -0400 Subject: [PATCH 2180/2777] sapi: Implement ISpObjectToken::CreateInstance. (cherry picked from commit bfe018095709fa0f99b40b82e1192d0c89a4cd75) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/token.c | 149 ++++++++++++++++++++++++++++++++++++++++ dlls/sapi/token.c | 35 +++++++++- 2 files changed, 182 insertions(+), 2 deletions(-) diff --git a/dlls/sapi/tests/token.c b/dlls/sapi/tests/token.c index 2602b043980..3629a86b126 100644 --- a/dlls/sapi/tests/token.c +++ b/dlls/sapi/tests/token.c @@ -268,13 +268,117 @@ static void tests_token_voices(void) IEnumSpObjectTokens_Release(tokens); } + +#define TESTCLASS_CLSID L"{67DD26B6-50BA-3297-253E-619346F177F8}" +static const GUID CLSID_TestClass = {0x67DD26B6,0x50BA,0x3297,{0x25,0x3E,0x61,0x93,0x46,0xF1,0x77,0xF8}}; + +static ISpObjectToken *test_class_token; + +static HRESULT WINAPI test_class_QueryInterface(ISpObjectWithToken *iface, REFIID riid, void **ppv) +{ + if (IsEqualGUID( riid, &IID_IUnknown ) || IsEqualGUID( riid, &IID_ISpObjectWithToken )) + { + *ppv = iface; + return S_OK; + } + + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_class_AddRef(ISpObjectWithToken *iface) +{ + return 2; +} + +static ULONG WINAPI test_class_Release(ISpObjectWithToken *iface) +{ + return 1; +} + +static HRESULT WINAPI test_class_SetObjectToken(ISpObjectWithToken *iface, ISpObjectToken *token) +{ + ok( token != NULL, "token == NULL\n" ); + test_class_token = token; + ISpObjectToken_AddRef(test_class_token); + return S_OK; +} + +static HRESULT WINAPI test_class_GetObjectToken(ISpObjectWithToken *iface, ISpObjectToken **token) +{ + ok( 0, "unexpected call\n" ); + return E_NOTIMPL; +} + +static const ISpObjectWithTokenVtbl test_class_vtbl = { + test_class_QueryInterface, + test_class_AddRef, + test_class_Release, + test_class_SetObjectToken, + test_class_GetObjectToken +}; + +static ISpObjectWithToken test_class = { &test_class_vtbl }; + +static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) +{ + if (IsEqualGUID( &IID_IUnknown, riid ) || IsEqualGUID( &IID_IClassFactory, riid )) + { + *ppv = iface; + return S_OK; + } + + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) +{ + return 2; +} + +static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) +{ + return 1; +} + +static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, + IUnknown *pUnkOuter, REFIID riid, void **ppv) +{ + ok( pUnkOuter == NULL, "pUnkOuter != NULL\n" ); + ok( IsEqualGUID(riid, &IID_IUnknown), "riid = %s\n", wine_dbgstr_guid(riid) ); + + *ppv = &test_class; + return S_OK; +} + +static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock) +{ + ok( 0, "unexpected call\n" ); + return E_NOTIMPL; +} + +static const IClassFactoryVtbl ClassFactoryVtbl = { + ClassFactory_QueryInterface, + ClassFactory_AddRef, + ClassFactory_Release, + ClassFactory_CreateInstance, + ClassFactory_LockServer +}; + +static IClassFactory test_class_cf = { &ClassFactoryVtbl }; + static void test_object_token(void) { + static const WCHAR test_token_id[] = L"HKEY_CURRENT_USER\\Software\\Winetest\\sapi\\TestToken"; + ISpObjectToken *token; ISpDataKey *sub_key; HRESULT hr; LPWSTR tempW, token_id; ISpObjectTokenCategory *cat; + DWORD regid; + IUnknown *obj; hr = CoCreateInstance( &CLSID_SpObjectToken, NULL, CLSCTX_INPROC_SERVER, &IID_ISpObjectToken, (void **)&token ); @@ -397,6 +501,51 @@ static void test_object_token(void) ISpObjectTokenCategory_Release( cat ); } + hr = CoRegisterClassObject( &CLSID_TestClass, (IUnknown *)&test_class_cf, + CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®id ); + ok( hr == S_OK, "got %08lx\n", hr ); + + ISpObjectToken_Release( token ); + hr = CoCreateInstance( &CLSID_SpObjectToken, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpObjectToken, (void **)&token ); + ok( hr == S_OK, "got %08lx\n", hr ); + + hr = ISpObjectToken_SetId( token, NULL, test_token_id, TRUE ); + ok( hr == S_OK, "got %08lx\n", hr ); + + hr = ISpObjectToken_SetStringValue( token, L"CLSID", TESTCLASS_CLSID ); + ok( hr == S_OK, "got %08lx\n", hr ); + + tempW = NULL; + hr = ISpObjectToken_GetStringValue( token, L"CLSID", &tempW ); + + ok( hr == S_OK, "got %08lx\n", hr ); + if ( tempW ) { + ok( !wcsncmp( tempW, TESTCLASS_CLSID, wcslen(TESTCLASS_CLSID) ), + "got %s (expected %s)\n", wine_dbgstr_w(tempW), wine_dbgstr_w(TESTCLASS_CLSID) ); + CoTaskMemFree( tempW ); + } + + test_class_token = NULL; + hr = ISpObjectToken_CreateInstance( token, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&obj ); + if ( hr == E_ACCESSDENIED ) { + win_skip( "ISpObjectToken_CreateInstance returned E_ACCESSDENIED\n" ); + return; + } + ok( hr == S_OK, "got %08lx\n", hr ); + ok( test_class_token != NULL, "test_class_token not set\n" ); + + tempW = NULL; + hr = ISpObjectToken_GetId( test_class_token, &tempW ); + ok( tempW != NULL, "got %p\n", tempW ); + if (tempW) { + ok( !wcsncmp(tempW, test_token_id, wcslen(test_token_id)), + "got %s (expected %s)\n", wine_dbgstr_w(tempW), wine_dbgstr_w(test_token_id) ); + CoTaskMemFree( tempW ); + } + + ISpObjectToken_Release( test_class_token ); + IUnknown_Release( obj ); ISpObjectToken_Release( token ); } diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index 6f8d677c9d0..6cc7ccd6d73 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -1227,8 +1227,39 @@ static HRESULT WINAPI token_CreateInstance( ISpObjectToken *iface, REFIID riid, void **object ) { - FIXME( "stub\n" ); - return E_NOTIMPL; + WCHAR *clsid_str; + CLSID clsid; + IUnknown *unk; + ISpObjectWithToken *obj_token_iface; + HRESULT hr; + + TRACE( "%p, %p, %#lx, %s, %p\n", iface, outer, class_context, debugstr_guid( riid ), object ); + + if (FAILED(hr = ISpObjectToken_GetStringValue( iface, L"CLSID", &clsid_str ))) + return hr; + + hr = CLSIDFromString( clsid_str, &clsid ); + CoTaskMemFree( clsid_str ); + if (FAILED(hr)) + return hr; + + if (FAILED(hr = CoCreateInstance( &clsid, outer, class_context, &IID_IUnknown, (void **)&unk ))) + return hr; + + /* Call ISpObjectWithToken::SetObjectToken if the interface is available. */ + if (SUCCEEDED(IUnknown_QueryInterface( unk, &IID_ISpObjectWithToken, (void **)&obj_token_iface ))) + { + hr = ISpObjectWithToken_SetObjectToken( obj_token_iface, iface ); + ISpObjectWithToken_Release( obj_token_iface ); + if (FAILED(hr)) + goto done; + } + + hr = IUnknown_QueryInterface( unk, riid, object ); + +done: + IUnknown_Release( unk ); + return hr; } static HRESULT WINAPI token_GetStorageFileName( ISpObjectToken *iface, From 65e7107f55f722bc4266b5a4716a4d727d869ef4 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Thu, 25 May 2023 23:35:28 -0400 Subject: [PATCH 2181/2777] sapi: Implement ISpObjectToken::CreateKey. (cherry picked from commit e071a70ba870cee586d28beca8f8965f63378eef) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/token.c | 4 ++++ dlls/sapi/token.c | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/dlls/sapi/tests/token.c b/dlls/sapi/tests/token.c index 3629a86b126..287c74a3e58 100644 --- a/dlls/sapi/tests/token.c +++ b/dlls/sapi/tests/token.c @@ -513,6 +513,10 @@ static void test_object_token(void) hr = ISpObjectToken_SetId( token, NULL, test_token_id, TRUE ); ok( hr == S_OK, "got %08lx\n", hr ); + hr = ISpObjectToken_CreateKey( token, L"Attributes", &sub_key ); + ok( hr == S_OK, "got %08lx\n", hr ); + ISpDataKey_Release( sub_key ); + hr = ISpObjectToken_SetStringValue( token, L"CLSID", TESTCLASS_CLSID ); ok( hr == S_OK, "got %08lx\n", hr ); diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index 6cc7ccd6d73..dbbc14b6e56 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -1117,8 +1117,11 @@ static HRESULT WINAPI token_OpenKey( ISpObjectToken *iface, static HRESULT WINAPI token_CreateKey( ISpObjectToken *iface, LPCWSTR name, ISpDataKey **sub_key ) { - FIXME( "stub\n" ); - return E_NOTIMPL; + struct object_token *This = impl_from_ISpObjectToken( iface ); + + TRACE( "%p, %s, %p\n", iface, debugstr_w(name), sub_key ); + + return ISpRegDataKey_CreateKey( This->data_key, name, sub_key ); } static HRESULT WINAPI token_DeleteKey( ISpObjectToken *iface, From c681bd5d7af54dc674d97ed301e1a6e0e20fbbc8 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Fri, 26 May 2023 00:09:45 -0400 Subject: [PATCH 2182/2777] sapi: Partially reimplement ISpObjectTokenEnumBuilder storing a token array. This is needed in order to implement filtering and sorting in ISpObjectTokenCategory::EnumTokens. (cherry picked from commit f286ee9bfa9dc0b4fb7f66ad0e406c6c729ce1c8) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/token.c | 112 ++++++++++++++++- dlls/sapi/token.c | 270 +++++++++++++++++++++++----------------- 2 files changed, 260 insertions(+), 122 deletions(-) diff --git a/dlls/sapi/tests/token.c b/dlls/sapi/tests/token.c index 287c74a3e58..128210fca0b 100644 --- a/dlls/sapi/tests/token.c +++ b/dlls/sapi/tests/token.c @@ -109,6 +109,63 @@ static void test_data_key(void) ISpRegDataKey_Release( data_key ); } +static void setup_test_voice_tokens(void) +{ + HKEY key; + ISpRegDataKey *data_key; + ISpDataKey *attrs_key; + LSTATUS ret; + HRESULT hr; + + ret = RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Winetest\\sapi\\TestVoices\\Tokens", 0, NULL, 0, + KEY_ALL_ACCESS, NULL, &key, NULL ); + ok( ret == ERROR_SUCCESS, "got %ld\n", ret ); + + hr = CoCreateInstance( &CLSID_SpDataKey, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpRegDataKey, (void **)&data_key ); + ok( hr == S_OK, "got %08lx\n", hr ); + hr = ISpRegDataKey_SetKey( data_key, key, FALSE ); + ok( hr == S_OK, "got %08lx\n", hr ); + + ISpRegDataKey_CreateKey( data_key, L"Voice1\\Attributes", &attrs_key ); + ISpDataKey_SetStringValue( attrs_key, L"Language", L"409" ); + ISpDataKey_SetStringValue( attrs_key, L"Gender", L"Female" ); + ISpDataKey_SetStringValue( attrs_key, L"Age", L"Child" ); + ISpDataKey_SetStringValue( attrs_key, L"Vendor", L"Vendor2" ); + ISpDataKey_Release( attrs_key ); + + ISpRegDataKey_CreateKey( data_key, L"Voice2\\Attributes", &attrs_key ); + ISpDataKey_SetStringValue( attrs_key, L"Language", L"406;407;408;409;40a" ); + ISpDataKey_SetStringValue( attrs_key, L"Gender", L"Female" ); + ISpDataKey_SetStringValue( attrs_key, L"Age", L"Adult" ); + ISpDataKey_SetStringValue( attrs_key, L"Vendor", L"Vendor1" ); + ISpDataKey_Release( attrs_key ); + + ISpRegDataKey_CreateKey( data_key, L"Voice3\\Attributes", &attrs_key ); + ISpDataKey_SetStringValue( attrs_key, L"Language", L"409;411" ); + ISpDataKey_SetStringValue( attrs_key, L"Gender", L"Female" ); + ISpDataKey_SetStringValue( attrs_key, L"Age", L"Child" ); + ISpDataKey_SetStringValue( attrs_key, L"Vendor", L"Vendor1" ); + ISpDataKey_Release( attrs_key ); + + ISpRegDataKey_CreateKey( data_key, L"Voice4\\Attributes", &attrs_key ); + ISpDataKey_SetStringValue( attrs_key, L"Language", L"411" ); + ISpDataKey_SetStringValue( attrs_key, L"Gender", L"Male" ); + ISpDataKey_SetStringValue( attrs_key, L"Age", L"Adult" ); + ISpDataKey_Release( attrs_key ); + + ISpRegDataKey_CreateKey( data_key, L"Voice5\\Attributes", &attrs_key ); + ISpDataKey_SetStringValue( attrs_key, L"Language", L"411" ); + ISpDataKey_SetStringValue( attrs_key, L"Gender", L"Female" ); + ISpDataKey_SetStringValue( attrs_key, L"Age", L"Adult" ); + ISpDataKey_SetStringValue( attrs_key, L"Vendor", L"Vendor2" ); + ISpDataKey_Release( attrs_key ); + + ISpRegDataKey_Release( data_key ); +} + +static const WCHAR test_cat[] = L"HKEY_CURRENT_USER\\Software\\Winetest\\sapi\\TestVoices"; + static void test_token_category(void) { ISpObjectTokenCategory *cat; @@ -126,17 +183,19 @@ static void test_token_category(void) hr = ISpObjectTokenCategory_SetId( cat, L"bogus", FALSE ); ok( hr == SPERR_INVALID_REGISTRY_KEY, "got %08lx\n", hr ); - hr = ISpObjectTokenCategory_SetId( cat, SPCAT_VOICES, FALSE ); + hr = ISpObjectTokenCategory_SetId( cat, test_cat, FALSE ); ok( hr == S_OK, "got %08lx\n", hr ); - hr = ISpObjectTokenCategory_SetId( cat, SPCAT_VOICES, FALSE ); + hr = ISpObjectTokenCategory_SetId( cat, test_cat, FALSE ); ok( hr == SPERR_ALREADY_INITIALIZED, "got %08lx\n", hr ); hr = ISpObjectTokenCategory_EnumTokens( cat, NULL, NULL, &enum_tokens ); ok( hr == S_OK, "got %08lx\n", hr ); + count = 0xdeadbeef; hr = IEnumSpObjectTokens_GetCount( enum_tokens, &count ); ok( hr == S_OK, "got %08lx\n", hr ); + ok( count == 5, "got %lu\n", count ); IEnumSpObjectTokens_Release( enum_tokens ); ISpObjectTokenCategory_Release( cat ); @@ -146,8 +205,11 @@ static void test_token_enum(void) { ISpObjectTokenEnumBuilder *token_enum; HRESULT hr; - ISpObjectToken *token; + ISpObjectToken *tokens[3]; + ISpObjectToken *out_tokens[3]; + WCHAR token_id[MAX_PATH]; ULONG count; + int i; hr = CoCreateInstance( &CLSID_SpObjectTokenEnum, NULL, CLSCTX_INPROC_SERVER, &IID_ISpObjectTokenEnumBuilder, (void **)&token_enum ); @@ -156,7 +218,7 @@ static void test_token_enum(void) hr = ISpObjectTokenEnumBuilder_GetCount( token_enum, &count ); ok( hr == SPERR_UNINITIALIZED, "got %08lx\n", hr ); - hr = ISpObjectTokenEnumBuilder_Next( token_enum, 1, &token, &count ); + hr = ISpObjectTokenEnumBuilder_Next( token_enum, 1, tokens, &count ); ok( hr == SPERR_UNINITIALIZED, "got %08lx\n", hr ); hr = ISpObjectTokenEnumBuilder_SetAttribs( token_enum, NULL, NULL ); @@ -168,11 +230,50 @@ static void test_token_enum(void) ok( count == 0, "got %lu\n", count ); count = 0xdeadbeef; - hr = ISpObjectTokenEnumBuilder_Next( token_enum, 1, &token, &count ); + hr = ISpObjectTokenEnumBuilder_Next( token_enum, 1, &out_tokens[0], &count ); ok( hr == S_FALSE, "got %08lx\n", hr ); ok( count == 0, "got %lu\n", count ); + for ( i = 0; i < 3; i++ ) { + hr = CoCreateInstance( &CLSID_SpObjectToken, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpObjectToken, (void **)&tokens[i] ); + ok( hr == S_OK, "got %08lx\n", hr ); + + swprintf( token_id, MAX_PATH, L"%ls\\Tokens\\Voice%d", test_cat, i + 1 ); + hr = ISpObjectToken_SetId( tokens[i], NULL, token_id, FALSE ); + ok( hr == S_OK, "got %08lx\n", hr ); + } + + hr = ISpObjectTokenEnumBuilder_AddTokens( token_enum, 3, tokens ); + ok( hr == S_OK, "got %08lx\n", hr ); + + out_tokens[0] = (ISpObjectToken *)0xdeadbeef; + hr = ISpObjectTokenEnumBuilder_Next( token_enum, 1, &out_tokens[0], NULL ); + ok( hr == S_OK, "got %08lx\n", hr ); + ok( out_tokens[0] == tokens[0], "got %p\n", out_tokens[0] ); + + out_tokens[0] = (ISpObjectToken *)0xdeadbeef; + hr = ISpObjectTokenEnumBuilder_Item( token_enum, 0, &out_tokens[0] ); + ok( hr == S_OK, "got %08lx\n", hr ); + ok( out_tokens[0] == tokens[0], "got %p\n", out_tokens[0] ); + + hr = ISpObjectTokenEnumBuilder_Item( token_enum, 3, &out_tokens[0] ); + ok( hr == SPERR_NO_MORE_ITEMS, "got %08lx\n", hr ); + + hr = ISpObjectTokenEnumBuilder_Next( token_enum, 3, &out_tokens[1], NULL ); + ok( hr == E_POINTER, "got %08lx\n", hr ); + + count = 0xdeadbeef; + out_tokens[1] = out_tokens[2] = (ISpObjectToken *)0xdeadbeef; + hr = ISpObjectTokenEnumBuilder_Next( token_enum, 3, &out_tokens[1], &count ); + ok( hr == S_FALSE, "got %08lx\n", hr ); + ok( count == 2, "got %lu\n", count ); + ok( out_tokens[1] == tokens[1], "got %p\n", out_tokens[1] ); + ok( out_tokens[2] == tokens[2], "got %p\n", out_tokens[2] ); + ISpObjectTokenEnumBuilder_Release( token_enum ); + + for ( i = 0; i < 3; i++ ) ISpObjectToken_Release( tokens[i] ); } static void test_default_token_id(void) @@ -558,6 +659,7 @@ START_TEST(token) CoInitialize( NULL ); RegDeleteTreeA( HKEY_CURRENT_USER, "Software\\Winetest\\sapi" ); test_data_key(); + setup_test_voice_tokens(); test_token_category(); test_token_enum(); test_default_token_id(); diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index dbbc14b6e56..fedf70e69d5 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -19,6 +19,7 @@ */ #include +#include #define COBJMACROS @@ -328,6 +329,7 @@ struct token_category LONG ref; ISpRegDataKey *data_key; + WCHAR *id; }; static struct token_category *impl_from_ISpObjectTokenCategory( ISpObjectTokenCategory *iface ) @@ -375,6 +377,7 @@ static ULONG WINAPI token_category_Release( ISpObjectTokenCategory *iface ) if (!ref) { if (This->data_key) ISpRegDataKey_Release( This->data_key ); + free( This->id ); free( This ); } return ref; @@ -541,6 +544,8 @@ static HRESULT WINAPI token_category_SetId( ISpObjectTokenCategory *iface, return hr; } + This->id = wcsdup( id ); + return hr; } @@ -559,6 +564,12 @@ static HRESULT WINAPI token_category_GetDataKey( ISpObjectTokenCategory *iface, return E_NOTIMPL; } +struct token_with_score +{ + ISpObjectToken *token; + uint64_t score; +}; + struct token_enum { ISpObjectTokenEnumBuilder ISpObjectTokenEnumBuilder_iface; @@ -566,8 +577,8 @@ struct token_enum BOOL init; WCHAR *req, *opt; - ULONG count; - HKEY key; + struct token_with_score *tokens; + ULONG capacity, count; DWORD index; }; @@ -582,8 +593,12 @@ static HRESULT WINAPI token_category_EnumTokens( ISpObjectTokenCategory *iface, { struct token_category *This = impl_from_ISpObjectTokenCategory( iface ); ISpObjectTokenEnumBuilder *builder; - struct token_enum *tokenenum; struct data_key *this_data_key; + HKEY tokens_key; + DWORD count, max_subkey_size, root_len, token_id_size; + DWORD size, i; + WCHAR *token_id = NULL; + ISpObjectToken *token = NULL; HRESULT hr; TRACE( "(%p)->(%s %s %p)\n", This, debugstr_w( req ), debugstr_w( opt ), enum_tokens ); @@ -599,12 +614,43 @@ static HRESULT WINAPI token_category_EnumTokens( ISpObjectTokenCategory *iface, this_data_key = impl_from_ISpRegDataKey( This->data_key ); - tokenenum = impl_from_ISpObjectTokenEnumBuilder( builder ); - - if (!RegOpenKeyExW( this_data_key->key, L"Tokens", 0, KEY_ALL_ACCESS, &tokenenum->key )) + if (!RegOpenKeyExW( this_data_key->key, L"Tokens", 0, KEY_ALL_ACCESS, &tokens_key )) { - RegQueryInfoKeyW(tokenenum->key, NULL, NULL, NULL, &tokenenum->count, NULL, NULL, - NULL, NULL, NULL, NULL, NULL); + RegQueryInfoKeyW( tokens_key, NULL, NULL, NULL, &count, &max_subkey_size, NULL, + NULL, NULL, NULL, NULL, NULL ); + max_subkey_size++; + + root_len = wcslen( This->id ); + token_id_size = root_len + sizeof("\\Tokens\\") + max_subkey_size; + token_id = malloc( token_id_size * sizeof(WCHAR) ); + if (!token_id) + { + hr = E_OUTOFMEMORY; + goto fail; + } + root_len = swprintf( token_id, token_id_size, L"%ls%lsTokens\\", + This->id, This->id[root_len - 1] == L'\\' ? L"" : L"\\" ); + + for ( i = 0; i < count; i++ ) + { + size = max_subkey_size; + hr = HRESULT_FROM_WIN32(RegEnumKeyExW( tokens_key, i, token_id + root_len, &size, NULL, NULL, NULL, NULL )); + if (FAILED(hr)) goto fail; + + hr = token_create( NULL, &IID_ISpObjectToken, (void **)&token ); + if (FAILED(hr)) goto fail; + + hr = ISpObjectToken_SetId( token, NULL, token_id, FALSE ); + if (FAILED(hr)) goto fail; + + hr = ISpObjectTokenEnumBuilder_AddTokens( builder, 1, &token ); + if (FAILED(hr)) goto fail; + ISpObjectToken_Release( token ); + token = NULL; + } + + hr = ISpObjectTokenEnumBuilder_Sort( builder, NULL ); + if (FAILED(hr)) goto fail; } hr = ISpObjectTokenEnumBuilder_QueryInterface( builder, &IID_IEnumSpObjectTokens, @@ -612,6 +658,8 @@ static HRESULT WINAPI token_category_EnumTokens( ISpObjectTokenCategory *iface, fail: ISpObjectTokenEnumBuilder_Release( builder ); + if ( token ) ISpObjectToken_Release( token ); + free( token_id ); return hr; } @@ -693,6 +741,7 @@ HRESULT token_category_create( IUnknown *outer, REFIID iid, void **obj ) This->ISpObjectTokenCategory_iface.lpVtbl = &token_category_vtbl; This->ref = 1; This->data_key = NULL; + This->id = NULL; hr = ISpObjectTokenCategory_QueryInterface( &This->ISpObjectTokenCategory_iface, iid, obj ); @@ -739,10 +788,16 @@ static ULONG WINAPI token_enum_Release( ISpObjectTokenEnumBuilder *iface ) if (!ref) { - if (This->key) - RegCloseKey(This->key); free( This->req ); free( This->opt ); + if (This->tokens) + { + ULONG i; + for ( i = 0; i < This->count; i++ ) + if ( This->tokens[i].token ) + ISpObjectToken_Release( This->tokens[i].token ); + free( This->tokens ); + } free( This ); } @@ -754,64 +809,23 @@ static HRESULT WINAPI token_enum_Next( ISpObjectTokenEnumBuilder *iface, ULONG *fetched ) { struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface ); - struct object_token *object; - HRESULT hr; - DWORD retCode; - WCHAR *subkey_name; - HKEY sub_key; - DWORD size; - ISpRegDataKey *data_key; + ULONG i; TRACE( "(%p)->(%lu %p %p)\n", This, num, tokens, fetched ); if (!This->init) return SPERR_UNINITIALIZED; - if (fetched) *fetched = 0; - - *tokens = NULL; - - RegQueryInfoKeyW( This->key, NULL, NULL, NULL, NULL, &size, NULL, NULL, NULL, NULL, NULL, NULL ); - size = (size+1) * sizeof(WCHAR); - subkey_name = malloc( size ); - if (!subkey_name) - return E_OUTOFMEMORY; + if (!fetched && num != 1) return E_POINTER; + if (!tokens) return E_POINTER; - retCode = RegEnumKeyExW( This->key, This->index, subkey_name, &size, NULL, NULL, NULL, NULL ); - if (retCode != ERROR_SUCCESS) + for ( i = 0; i < num && This->index < This->count; i++, This->index++ ) { - free( subkey_name ); - return S_FALSE; + ISpObjectToken_AddRef( This->tokens[This->index].token ); + tokens[i] = This->tokens[This->index].token; } - This->index++; - - if (RegOpenKeyExW( This->key, subkey_name, 0, KEY_READ, &sub_key ) != ERROR_SUCCESS) - { - free( subkey_name ); - return E_FAIL; - } + if (fetched) *fetched = i; - hr = create_data_key_with_hkey( sub_key, &data_key ); - if (FAILED(hr)) - { - free( subkey_name ); - RegCloseKey( sub_key ); - return hr; - } - - hr = token_create( NULL, &IID_ISpObjectToken, (void**)tokens ); - if (FAILED(hr)) - { - free( subkey_name ); - ISpRegDataKey_Release( data_key ); - return hr; - } - - object = impl_from_ISpObjectToken( *tokens ); - object->data_key = data_key; - object->token_id = subkey_name; - - if (fetched) *fetched = 1; - return hr; + return i == num ? S_OK : S_FALSE; } static HRESULT WINAPI token_enum_Skip( ISpObjectTokenEnumBuilder *iface, @@ -838,63 +852,18 @@ static HRESULT WINAPI token_enum_Item( ISpObjectTokenEnumBuilder *iface, ULONG index, ISpObjectToken **token ) { struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface ); - struct object_token *object; - ISpObjectToken *subtoken; - HRESULT hr; - WCHAR *subkey; - DWORD size; - LONG ret; - HKEY key; - ISpRegDataKey *data_key; - - TRACE( "%p, %lu, %p\n", This, index, token ); - - if (!This->init) - return SPERR_UNINITIALIZED; - - RegQueryInfoKeyW(This->key, NULL, NULL, NULL, NULL, &size, NULL, NULL, NULL, NULL, NULL, NULL); - size = (size+1) * sizeof(WCHAR); - subkey = malloc( size ); - if (!subkey) - return E_OUTOFMEMORY; - - ret = RegEnumKeyExW(This->key, index, subkey, &size, NULL, NULL, NULL, NULL); - if (ret != ERROR_SUCCESS) - { - free( subkey ); - return HRESULT_FROM_WIN32(ret); - } - - ret = RegOpenKeyExW (This->key, subkey, 0, KEY_READ, &key); - if (ret != ERROR_SUCCESS) - { - free( subkey ); - return HRESULT_FROM_WIN32(ret); - } - hr = create_data_key_with_hkey( key, &data_key ); - if (FAILED(hr)) - { - free( subkey ); - RegCloseKey( key ); - return hr; - } + TRACE( "(%p)->(%lu %p)\n", This, index, token ); - hr = token_create( NULL, &IID_ISpObjectToken, (void**)&subtoken ); - if (FAILED(hr)) - { - free( subkey ); - ISpRegDataKey_Release( data_key ); - return hr; - } + if (!This->init) return SPERR_UNINITIALIZED; - object = impl_from_ISpObjectToken( subtoken ); - object->data_key = data_key; - object->token_id = subkey; + if (!token) return E_POINTER; + if (index >= This->count) return SPERR_NO_MORE_ITEMS; - *token = subtoken; + ISpObjectToken_AddRef( This->tokens[index].token ); + *token = This->tokens[index].token; - return hr; + return S_OK; } static HRESULT WINAPI token_enum_GetCount( ISpObjectTokenEnumBuilder *iface, @@ -939,11 +908,60 @@ static HRESULT WINAPI token_enum_SetAttribs( ISpObjectTokenEnumBuilder *iface, return E_OUTOFMEMORY; } +static BOOL grow_tokens_array( struct token_enum *This ) +{ + struct token_with_score *new_tokens; + ULONG new_cap; + + if (This->count < This->capacity) return TRUE; + + if (This->capacity > 0) + { + new_cap = This->capacity * 2; + new_tokens = realloc( This->tokens, new_cap * sizeof(*new_tokens) ); + } + else + { + new_cap = 1; + new_tokens = malloc( sizeof(*new_tokens) ); + } + + if (!new_tokens) return FALSE; + + This->tokens = new_tokens; + This->capacity = new_cap; + return TRUE; +} + static HRESULT WINAPI token_enum_AddTokens( ISpObjectTokenEnumBuilder *iface, ULONG num, ISpObjectToken **tokens ) { - FIXME( "stub\n" ); - return E_NOTIMPL; + struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface ); + ULONG i; + + TRACE( "(%p)->(%lu %p)\n", iface, num, tokens ); + + if (!This->init) return SPERR_UNINITIALIZED; + if (!tokens) return E_POINTER; + + if (This->req || This->opt) + { + FIXME( "filtering and sorting of tokens is not implemented\n" ); + return E_NOTIMPL; + } + + for ( i = 0; i < num; i++ ) + { + if (!tokens[i]) return E_POINTER; + + if (!grow_tokens_array( This )) return E_OUTOFMEMORY; + ISpObjectToken_AddRef( tokens[i] ); + This->tokens[This->count].token = tokens[i]; + This->tokens[This->count].score = 0; + This->count++; + } + + return S_OK; } static HRESULT WINAPI token_enum_AddTokensFromDataKey( ISpObjectTokenEnumBuilder *iface, @@ -964,8 +982,26 @@ static HRESULT WINAPI token_enum_AddTokensFromTokenEnum( ISpObjectTokenEnumBuild static HRESULT WINAPI token_enum_Sort( ISpObjectTokenEnumBuilder *iface, LPCWSTR first ) { - FIXME( "stub\n" ); - return E_NOTIMPL; + struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface ); + + FIXME( "(%p)->(%s): semi-stub\n", iface, debugstr_w(first) ); + + if (!This->init) return SPERR_UNINITIALIZED; + if (!This->tokens) return S_OK; + + if (first) + { + FIXME( "first != NULL is not implemented.\n" ); + return E_NOTIMPL; + } + + if (This->opt) + { + FIXME( "sorting with optional attributes is not implemented.\n" ); + return E_NOTIMPL; + } + + return S_OK; } const struct ISpObjectTokenEnumBuilderVtbl token_enum_vtbl = @@ -997,8 +1033,8 @@ HRESULT token_enum_create( IUnknown *outer, REFIID iid, void **obj ) This->req = NULL; This->opt = NULL; This->init = FALSE; - This->count = 0; - This->key = NULL; + This->tokens = NULL; + This->capacity = This->count = 0; This->index = 0; hr = ISpObjectTokenEnumBuilder_QueryInterface( &This->ISpObjectTokenEnumBuilder_iface, iid, obj ); From 11d0946d24be67631256221eb2cddf6714da9dc5 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Fri, 26 May 2023 00:35:48 -0400 Subject: [PATCH 2183/2777] sapi: Implement token filtering and sorting in ISpObjectTokenEnumBuilder. (cherry picked from commit db2640d06b49b7d28fe556d582de8b5a4ae6ccea) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/token.c | 138 ++++++++++++++++++++++++++++++++++++++-- dlls/sapi/token.c | 131 ++++++++++++++++++++++++++++++++++---- 2 files changed, 253 insertions(+), 16 deletions(-) diff --git a/dlls/sapi/tests/token.c b/dlls/sapi/tests/token.c index 128210fca0b..5a3bc0e340e 100644 --- a/dlls/sapi/tests/token.c +++ b/dlls/sapi/tests/token.c @@ -172,6 +172,10 @@ static void test_token_category(void) IEnumSpObjectTokens *enum_tokens; HRESULT hr; ULONG count; + int i; + ISpObjectToken *token; + WCHAR *token_id; + WCHAR tmp[MAX_PATH]; hr = CoCreateInstance( &CLSID_SpObjectTokenCategory, NULL, CLSCTX_INPROC_SERVER, &IID_ISpObjectTokenCategory, (void **)&cat ); @@ -198,6 +202,43 @@ static void test_token_category(void) ok( count == 5, "got %lu\n", count ); IEnumSpObjectTokens_Release( enum_tokens ); + + hr = ISpObjectTokenCategory_EnumTokens( cat, L"Language=409", NULL, &enum_tokens ); + ok( hr == S_OK, "got %08lx\n", hr ); + + count = 0xdeadbeef; + hr = IEnumSpObjectTokens_GetCount( enum_tokens, &count ); + ok( hr == S_OK, "got %08lx\n", hr ); + ok( count == 3, "got %lu\n", count ); + + IEnumSpObjectTokens_Release( enum_tokens ); + + hr = ISpObjectTokenCategory_EnumTokens( cat, L"Language=409", L"Vendor=Vendor1;Age=Child;Gender=Female", + &enum_tokens ); + ok( hr == S_OK, "got %08lx\n", hr ); + + count = 0xdeadbeef; + hr = IEnumSpObjectTokens_GetCount( enum_tokens, &count ); + ok( hr == S_OK, "got %08lx\n", hr ); + ok( count == 3, "got %lu\n", count ); + + for ( i = 0; i < 3; i++ ) { + token = NULL; + hr = IEnumSpObjectTokens_Item( enum_tokens, i, &token ); + ok( hr == S_OK, "i = %d: got %08lx\n", i, hr ); + + token_id = NULL; + hr = ISpObjectToken_GetId( token, &token_id ); + ok( hr == S_OK, "i = %d: got %08lx\n", i, hr ); + swprintf( tmp, MAX_PATH, L"%ls\\Tokens\\Voice%d", test_cat, 3 - i ); + ok( !wcscmp( token_id, tmp ), "i = %d: got %s\n", i, wine_dbgstr_w(token_id) ); + + CoTaskMemFree( token_id ); + ISpObjectToken_Release( token ); + } + + IEnumSpObjectTokens_Release( enum_tokens ); + ISpObjectTokenCategory_Release( cat ); } @@ -205,8 +246,8 @@ static void test_token_enum(void) { ISpObjectTokenEnumBuilder *token_enum; HRESULT hr; - ISpObjectToken *tokens[3]; - ISpObjectToken *out_tokens[3]; + ISpObjectToken *tokens[5]; + ISpObjectToken *out_tokens[5]; WCHAR token_id[MAX_PATH]; ULONG count; int i; @@ -234,7 +275,7 @@ static void test_token_enum(void) ok( hr == S_FALSE, "got %08lx\n", hr ); ok( count == 0, "got %lu\n", count ); - for ( i = 0; i < 3; i++ ) { + for ( i = 0; i < 5; i++ ) { hr = CoCreateInstance( &CLSID_SpObjectToken, NULL, CLSCTX_INPROC_SERVER, &IID_ISpObjectToken, (void **)&tokens[i] ); ok( hr == S_OK, "got %08lx\n", hr ); @@ -273,7 +314,96 @@ static void test_token_enum(void) ISpObjectTokenEnumBuilder_Release( token_enum ); - for ( i = 0; i < 3; i++ ) ISpObjectToken_Release( tokens[i] ); + hr = CoCreateInstance( &CLSID_SpObjectTokenEnum, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpObjectTokenEnumBuilder, (void **)&token_enum ); + ok( hr == S_OK, "got %08lx\n", hr ); + + /* Vendor attribute must exist */ + hr = ISpObjectTokenEnumBuilder_SetAttribs( token_enum, L"Vendor", NULL ); + ok( hr == S_OK, "got %08lx\n", hr ); + hr = ISpObjectTokenEnumBuilder_AddTokens( token_enum, 5, tokens ); + ok( hr == S_OK, "got %08lx\n", hr ); + + count = 0xdeadbeef; + hr = ISpObjectTokenEnumBuilder_Next( token_enum, 5, &out_tokens[0], &count ); + ok( hr == S_FALSE, "got %08lx\n", hr ); + ok( count == 4, "got %lu\n", count ); + + ISpObjectTokenEnumBuilder_Release( token_enum ); + + hr = CoCreateInstance( &CLSID_SpObjectTokenEnum, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpObjectTokenEnumBuilder, (void **)&token_enum ); + ok( hr == S_OK, "got %08lx\n", hr ); + + /* Vendor attribute must contain Vendor1 */ + hr = ISpObjectTokenEnumBuilder_SetAttribs( token_enum, L"Vendor=Vendor1", NULL ); + ok( hr == S_OK, "got %08lx\n", hr ); + hr = ISpObjectTokenEnumBuilder_AddTokens( token_enum, 5, tokens ); + ok( hr == S_OK, "got %08lx\n", hr ); + + count = 0xdeadbeef; + hr = ISpObjectTokenEnumBuilder_Next( token_enum, 5, &out_tokens[0], &count ); + ok( hr == S_FALSE, "got %08lx\n", hr ); + ok( count == 2, "got %lu\n", count ); + + ISpObjectTokenEnumBuilder_Release( token_enum ); + + hr = CoCreateInstance( &CLSID_SpObjectTokenEnum, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpObjectTokenEnumBuilder, (void **)&token_enum ); + ok( hr == S_OK, "got %08lx\n", hr ); + + /* Vendor attribute must not contain Vendor1 */ + hr = ISpObjectTokenEnumBuilder_SetAttribs( token_enum, L"Vendor!=Vendor1", NULL ); + ok( hr == S_OK, "got %08lx\n", hr ); + hr = ISpObjectTokenEnumBuilder_AddTokens( token_enum, 5, tokens ); + ok( hr == S_OK, "got %08lx\n", hr ); + + count = 0xdeadbeef; + hr = ISpObjectTokenEnumBuilder_Next( token_enum, 5, &out_tokens[0], &count ); + ok( hr == S_FALSE, "got %08lx\n", hr ); + ok( count == 3, "got %lu\n", count ); + + ISpObjectTokenEnumBuilder_Release( token_enum ); + + hr = CoCreateInstance( &CLSID_SpObjectTokenEnum, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpObjectTokenEnumBuilder, (void **)&token_enum ); + ok( hr == S_OK, "got %08lx\n", hr ); + + /* Vendor attribute must contain Vendor1 and Language attribute must contain 407 */ + hr = ISpObjectTokenEnumBuilder_SetAttribs( token_enum, L"Vendor=Vendor1;Language=407", NULL ); + ok( hr == S_OK, "got %08lx\n", hr ); + hr = ISpObjectTokenEnumBuilder_AddTokens( token_enum, 5, tokens ); + ok( hr == S_OK, "got %08lx\n", hr ); + + count = 0xdeadbeef; + hr = ISpObjectTokenEnumBuilder_Next( token_enum, 5, &out_tokens[0], &count ); + ok( hr == S_FALSE, "got %08lx\n", hr ); + ok( count == 1, "got %lu\n", count ); + + hr = CoCreateInstance( &CLSID_SpObjectTokenEnum, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpObjectTokenEnumBuilder, (void **)&token_enum ); + ok( hr == S_OK, "got %08lx\n", hr ); + + hr = ISpObjectTokenEnumBuilder_SetAttribs( token_enum, L"Language=409", + L"Vendor=Vendor1;Age=Child;Gender=Female" ); + ok( hr == S_OK, "got %08lx\n", hr ); + hr = ISpObjectTokenEnumBuilder_AddTokens( token_enum, 5, tokens ); + ok( hr == S_OK, "got %08lx\n", hr ); + + hr = ISpObjectTokenEnumBuilder_Sort( token_enum, NULL ); + ok( hr == S_OK, "got %08lx\n", hr ); + + count = 0xdeadbeef; + hr = ISpObjectTokenEnumBuilder_Next( token_enum, 5, &out_tokens[0], &count ); + ok( hr == S_FALSE, "got %08lx\n", hr ); + ok( count == 3, "got %lu\n", count ); + ok( out_tokens[0] == tokens[2], "got %p\n", out_tokens[0] ); + ok( out_tokens[1] == tokens[1], "got %p\n", out_tokens[1] ); + ok( out_tokens[2] == tokens[0], "got %p\n", out_tokens[2] ); + + ISpObjectTokenEnumBuilder_Release( token_enum ); + + for ( i = 0; i < 5; i++ ) ISpObjectToken_Release( tokens[i] ); } static void test_default_token_id(void) diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index fedf70e69d5..af98db02048 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -908,6 +908,104 @@ static HRESULT WINAPI token_enum_SetAttribs( ISpObjectTokenEnumBuilder *iface, return E_OUTOFMEMORY; } +static HRESULT score_attributes( ISpObjectToken *token, const WCHAR *attrs, + BOOL match_all, uint64_t *score ) +{ + ISpDataKey *attrs_key; + WCHAR *attr, *attr_ctx, *buf; + BOOL match[64]; + unsigned int i, j; + HRESULT hr; + + if (!attrs) + { + *score = 1; + return S_OK; + } + *score = 0; + + if (FAILED(hr = ISpObjectToken_OpenKey( token, L"Attributes", &attrs_key ))) + return hr == SPERR_NOT_FOUND ? S_OK : hr; + + memset( match, 0, sizeof(match) ); + + /* attrs is a semicolon-separated list of attribute clauses. + * Each clause consists of an attribute name and an optional operator and value. + * The meaning of a clause depends on the operator given: + * If no operator is given, the attribute must exist. + * If the operator is '=', the attribute must contain the given value. + * If the operator is '!=', the attribute must not exist or contain the given value. + */ + if (!(buf = wcsdup( attrs ))) return E_OUTOFMEMORY; + for ( attr = wcstok_s( buf, L";", &attr_ctx ), i = 0; attr && i < 64; + attr = wcstok_s( NULL, L";", &attr_ctx ), i++ ) + { + WCHAR *p = wcspbrk( attr, L"!=" ); + WCHAR op = p ? *p : L'\0'; + WCHAR *value = NULL, *res; + if ( p ) + { + if ( op == L'=' ) + value = p + 1; + else if ( op == L'!' ) + { + if ( *(p + 1) != L'=' ) + { + WARN( "invalid attr operator '!%lc'.\n", *(p + 1) ); + hr = E_INVALIDARG; + goto done; + } + value = p + 2; + } + *p = L'\0'; + } + + hr = ISpDataKey_GetStringValue( attrs_key, attr, &res ); + if ( p ) *p = op; + if (SUCCEEDED(hr)) + { + if ( !op ) + match[i] = TRUE; + else + { + WCHAR *val, *val_ctx; + + match[i] = FALSE; + for ( val = wcstok_s( res, L";", &val_ctx ); val && !match[i]; + val = wcstok_s( NULL, L";", &val_ctx ) ) + match[i] = !wcscmp( val, value ); + + if (op == L'!') match[i] = !match[i]; + } + CoTaskMemFree( res ); + } + else if (hr == SPERR_NOT_FOUND) + { + hr = S_OK; + if (op == L'!') match[i] = TRUE; + } + else + goto done; + + if ( match_all && !match[i] ) + goto done; + } + + if ( attr ) + hr = E_INVALIDARG; + else + { + /* Attributes in attrs are ordered from highest to lowest priority. */ + for ( j = 0; j < i; j++ ) + if ( match[j] ) + *score |= 1ULL << (i - 1 - j); + } + +done: + free( buf ); + return hr; +} + static BOOL grow_tokens_array( struct token_enum *This ) { struct token_with_score *new_tokens; @@ -938,26 +1036,29 @@ static HRESULT WINAPI token_enum_AddTokens( ISpObjectTokenEnumBuilder *iface, { struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface ); ULONG i; + uint64_t score; + HRESULT hr; TRACE( "(%p)->(%lu %p)\n", iface, num, tokens ); if (!This->init) return SPERR_UNINITIALIZED; if (!tokens) return E_POINTER; - if (This->req || This->opt) - { - FIXME( "filtering and sorting of tokens is not implemented\n" ); - return E_NOTIMPL; - } - for ( i = 0; i < num; i++ ) { if (!tokens[i]) return E_POINTER; + hr = score_attributes( tokens[i], This->req, TRUE, &score ); + if (FAILED(hr)) return hr; + if (!score) continue; + + hr = score_attributes( tokens[i], This->opt, FALSE, &score ); + if (FAILED(hr)) return hr; + if (!grow_tokens_array( This )) return E_OUTOFMEMORY; ISpObjectToken_AddRef( tokens[i] ); This->tokens[This->count].token = tokens[i]; - This->tokens[This->count].score = 0; + This->tokens[This->count].score = score; This->count++; } @@ -979,12 +1080,21 @@ static HRESULT WINAPI token_enum_AddTokensFromTokenEnum( ISpObjectTokenEnumBuild return E_NOTIMPL; } +static int __cdecl token_with_score_cmp( const void *a, const void *b ) +{ + const struct token_with_score *ta = a, *tb = b; + + if (ta->score > tb->score) return -1; + else if (ta->score < tb->score) return 1; + else return 0; +} + static HRESULT WINAPI token_enum_Sort( ISpObjectTokenEnumBuilder *iface, LPCWSTR first ) { struct token_enum *This = impl_from_ISpObjectTokenEnumBuilder( iface ); - FIXME( "(%p)->(%s): semi-stub\n", iface, debugstr_w(first) ); + TRACE( "(%p)->(%s).\n", iface, debugstr_w(first) ); if (!This->init) return SPERR_UNINITIALIZED; if (!This->tokens) return S_OK; @@ -996,10 +1106,7 @@ static HRESULT WINAPI token_enum_Sort( ISpObjectTokenEnumBuilder *iface, } if (This->opt) - { - FIXME( "sorting with optional attributes is not implemented.\n" ); - return E_NOTIMPL; - } + qsort( This->tokens, This->count, sizeof(*This->tokens), token_with_score_cmp ); return S_OK; } From 46ca883784d66faaebf8b4a3549669904b891434 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Tue, 16 May 2023 18:55:31 -0400 Subject: [PATCH 2184/2777] sapi: Add SpMMAudioOut stub. (cherry picked from commit 33c8d7b8a5b140241ca42da539a5c353f0cd0d09) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/Makefile.in | 1 + dlls/sapi/main.c | 3 + dlls/sapi/mmaudio.c | 633 ++++++++++++++++++++++++++++++++++++ dlls/sapi/sapi_classes.idl | 15 + dlls/sapi/sapi_private.h | 1 + dlls/sapi/tests/Makefile.in | 1 + dlls/sapi/tests/mmaudio.c | 68 ++++ 7 files changed, 722 insertions(+) create mode 100644 dlls/sapi/mmaudio.c create mode 100644 dlls/sapi/tests/mmaudio.c diff --git a/dlls/sapi/Makefile.in b/dlls/sapi/Makefile.in index e0f9a8cdd07..ca64edec6dd 100644 --- a/dlls/sapi/Makefile.in +++ b/dlls/sapi/Makefile.in @@ -4,6 +4,7 @@ IMPORTS = uuid ole32 user32 advapi32 C_SRCS = \ automation.c \ main.c \ + mmaudio.c \ resource.c \ stream.c \ token.c \ diff --git a/dlls/sapi/main.c b/dlls/sapi/main.c index d83d2257186..108db7d13d8 100644 --- a/dlls/sapi/main.c +++ b/dlls/sapi/main.c @@ -105,6 +105,7 @@ static const struct IClassFactoryVtbl class_factory_vtbl = static struct class_factory data_key_cf = { { &class_factory_vtbl }, data_key_create }; static struct class_factory file_stream_cf = { { &class_factory_vtbl }, file_stream_create }; +static struct class_factory mmaudio_out_cf = { { &class_factory_vtbl }, mmaudio_out_create }; static struct class_factory resource_mgr_cf = { { &class_factory_vtbl }, resource_manager_create }; static struct class_factory speech_stream_cf = { { &class_factory_vtbl }, speech_stream_create }; static struct class_factory speech_voice_cf = { { &class_factory_vtbl }, speech_voice_create }; @@ -125,6 +126,8 @@ HRESULT WINAPI DllGetClassObject( REFCLSID clsid, REFIID iid, void **obj ) cf = &data_key_cf.IClassFactory_iface; else if (IsEqualCLSID( clsid, &CLSID_SpFileStream )) cf = &file_stream_cf.IClassFactory_iface; + else if (IsEqualCLSID( clsid, &CLSID_SpMMAudioOut )) + cf = &mmaudio_out_cf.IClassFactory_iface; else if (IsEqualCLSID( clsid, &CLSID_SpObjectTokenCategory )) cf = &token_category_cf.IClassFactory_iface; else if (IsEqualCLSID( clsid, &CLSID_SpObjectTokenEnum )) diff --git a/dlls/sapi/mmaudio.c b/dlls/sapi/mmaudio.c new file mode 100644 index 00000000000..684476f5c56 --- /dev/null +++ b/dlls/sapi/mmaudio.c @@ -0,0 +1,633 @@ +/* + * Speech API (SAPI) winmm audio implementation. + * + * Copyright 2023 Shaun Ren 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 + */ + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + +#include "sapiddk.h" +#include "sperror.h" + +#include "wine/debug.h" + +#include "sapi_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(sapi); + +enum flow_type { FLOW_IN, FLOW_OUT }; + +struct mmaudio +{ + ISpEventSource ISpEventSource_iface; + ISpEventSink ISpEventSink_iface; + ISpObjectWithToken ISpObjectWithToken_iface; + ISpMMSysAudio ISpMMSysAudio_iface; + LONG ref; + + enum flow_type flow; + ISpObjectToken *token; +}; + +static inline struct mmaudio *impl_from_ISpEventSource(ISpEventSource *iface) +{ + return CONTAINING_RECORD(iface, struct mmaudio, ISpEventSource_iface); +} + +static inline struct mmaudio *impl_from_ISpEventSink(ISpEventSink *iface) +{ + return CONTAINING_RECORD(iface, struct mmaudio, ISpEventSink_iface); +} + +static inline struct mmaudio *impl_from_ISpObjectWithToken(ISpObjectWithToken *iface) +{ + return CONTAINING_RECORD(iface, struct mmaudio, ISpObjectWithToken_iface); +} + +static inline struct mmaudio *impl_from_ISpMMSysAudio(ISpMMSysAudio *iface) +{ + return CONTAINING_RECORD(iface, struct mmaudio, ISpMMSysAudio_iface); +} + +static HRESULT WINAPI event_source_QueryInterface(ISpEventSource *iface, REFIID iid, void **obj) +{ + struct mmaudio *This = impl_from_ISpEventSource(iface); + + TRACE("(%p, %s, %p).\n", iface, debugstr_guid(iid), obj); + + return ISpMMSysAudio_QueryInterface(&This->ISpMMSysAudio_iface, iid, obj); +} + +static ULONG WINAPI event_source_AddRef(ISpEventSource *iface) +{ + struct mmaudio *This = impl_from_ISpEventSource(iface); + + TRACE("(%p).\n", iface); + + return ISpMMSysAudio_AddRef(&This->ISpMMSysAudio_iface); +} + +static ULONG WINAPI event_source_Release(ISpEventSource *iface) +{ + struct mmaudio *This = impl_from_ISpEventSource(iface); + + TRACE("(%p).\n", iface); + + return ISpMMSysAudio_Release(&This->ISpMMSysAudio_iface); +} + +static HRESULT WINAPI event_source_SetNotifySink(ISpEventSource *iface, ISpNotifySink *sink) +{ + FIXME("(%p, %p): stub.\n", iface, sink); + + return E_NOTIMPL; +} + +static HRESULT WINAPI event_source_SetNotifyWindowMessage(ISpEventSource *iface, HWND hwnd, + UINT msg, WPARAM wparam, LPARAM lparam) +{ + FIXME("(%p, %p, %u, %Ix, %Ix): stub.\n", iface, hwnd, msg, wparam, lparam); + + return E_NOTIMPL; +} + +static HRESULT WINAPI event_source_SetNotifyCallbackFunction(ISpEventSource *iface, SPNOTIFYCALLBACK *callback, + WPARAM wparam, LPARAM lparam) +{ + FIXME("(%p, %p, %Ix, %Ix): stub.\n", iface, callback, wparam, lparam); + + return E_NOTIMPL; +} + +static HRESULT WINAPI event_source_SetNotifyCallbackInterface(ISpEventSource *iface, ISpNotifyCallback *callback, + WPARAM wparam, LPARAM lparam) +{ + FIXME("(%p, %p, %Ix, %Ix): stub.\n", iface, callback, wparam, lparam); + + return E_NOTIMPL; +} + +static HRESULT WINAPI event_source_SetNotifyWin32Event(ISpEventSource *iface) +{ + FIXME("(%p): stub.\n", iface); + + return E_NOTIMPL; +} + +static HRESULT WINAPI event_source_WaitForNotifyEvent(ISpEventSource *iface, DWORD milliseconds) +{ + FIXME("(%p, %ld): stub.\n", iface, milliseconds); + + return E_NOTIMPL; +} + +static HANDLE WINAPI event_source_GetNotifyEventHandle(ISpEventSource *iface) +{ + FIXME("(%p): stub.\n", iface); + + return NULL; +} + +static HRESULT WINAPI event_source_SetInterest(ISpEventSource *iface, ULONGLONG event, ULONGLONG queued) +{ + FIXME("(%p, %s, %s): stub.\n", iface, wine_dbgstr_longlong(event), wine_dbgstr_longlong(queued)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI event_source_GetEvents(ISpEventSource *iface, ULONG count, SPEVENT *array, ULONG *fetched) +{ + FIXME("(%p, %lu, %p, %p): stub.\n", iface, count, array, fetched); + + return E_NOTIMPL; +} + +static HRESULT WINAPI event_source_GetInfo(ISpEventSource *iface, SPEVENTSOURCEINFO *info) +{ + FIXME("(%p, %p): stub.\n", iface, info); + + return E_NOTIMPL; +} + +static const ISpEventSourceVtbl event_source_vtbl = +{ + event_source_QueryInterface, + event_source_AddRef, + event_source_Release, + event_source_SetNotifySink, + event_source_SetNotifyWindowMessage, + event_source_SetNotifyCallbackFunction, + event_source_SetNotifyCallbackInterface, + event_source_SetNotifyWin32Event, + event_source_WaitForNotifyEvent, + event_source_GetNotifyEventHandle, + event_source_SetInterest, + event_source_GetEvents, + event_source_GetInfo +}; + +static HRESULT WINAPI event_sink_QueryInterface(ISpEventSink *iface, REFIID iid, void **obj) +{ + struct mmaudio *This = impl_from_ISpEventSink(iface); + + TRACE("(%p, %s, %p).\n", iface, debugstr_guid(iid), obj); + + return ISpMMSysAudio_QueryInterface(&This->ISpMMSysAudio_iface, iid, obj); +} + +static ULONG WINAPI event_sink_AddRef(ISpEventSink *iface) +{ + struct mmaudio *This = impl_from_ISpEventSink(iface); + + TRACE("(%p).\n", iface); + + return ISpMMSysAudio_AddRef(&This->ISpMMSysAudio_iface); +} + +static ULONG WINAPI event_sink_Release(ISpEventSink *iface) +{ + struct mmaudio *This = impl_from_ISpEventSink(iface); + + TRACE("(%p).\n", iface); + + return ISpMMSysAudio_Release(&This->ISpMMSysAudio_iface); +} + +static HRESULT WINAPI event_sink_AddEvents(ISpEventSink *iface, const SPEVENT *events, ULONG count) +{ + FIXME("(%p, %p, %lu).\n", iface, events, count); + + return E_NOTIMPL; +} + +static HRESULT WINAPI event_sink_GetEventInterest(ISpEventSink *iface, ULONGLONG *interest) +{ + FIXME("(%p, %p).\n", iface, interest); + + return E_NOTIMPL; +} + +static const ISpEventSinkVtbl event_sink_vtbl = +{ + event_sink_QueryInterface, + event_sink_AddRef, + event_sink_Release, + event_sink_AddEvents, + event_sink_GetEventInterest +}; + +static HRESULT WINAPI objwithtoken_QueryInterface(ISpObjectWithToken *iface, REFIID iid, void **obj) +{ + struct mmaudio *This = impl_from_ISpObjectWithToken(iface); + + TRACE("(%p, %s, %p).\n", iface, debugstr_guid(iid), obj); + + return ISpMMSysAudio_QueryInterface(&This->ISpMMSysAudio_iface, iid, obj); +} + +static ULONG WINAPI objwithtoken_AddRef(ISpObjectWithToken *iface) +{ + struct mmaudio *This = impl_from_ISpObjectWithToken(iface); + + TRACE("(%p).\n", iface); + + return ISpMMSysAudio_AddRef(&This->ISpMMSysAudio_iface); +} + +static ULONG WINAPI objwithtoken_Release(ISpObjectWithToken *iface) +{ + struct mmaudio *This = impl_from_ISpObjectWithToken(iface); + + TRACE("(%p).\n", iface); + + return ISpMMSysAudio_Release(&This->ISpMMSysAudio_iface); +} + +static HRESULT WINAPI objwithtoken_SetObjectToken(ISpObjectWithToken *iface, ISpObjectToken *token) +{ + struct mmaudio *This = impl_from_ISpObjectWithToken(iface); + + FIXME("(%p, %p): semi-stub.\n", iface, token); + + if (!token) + return E_INVALIDARG; + if (This->token) + return SPERR_ALREADY_INITIALIZED; + + This->token = token; + return S_OK; +} + +static HRESULT WINAPI objwithtoken_GetObjectToken(ISpObjectWithToken *iface, ISpObjectToken **token) +{ + struct mmaudio *This = impl_from_ISpObjectWithToken(iface); + + TRACE("(%p, %p).\n", iface, token); + + if (!token) + return E_POINTER; + + *token = This->token; + if (*token) + { + ISpObjectToken_AddRef(*token); + return S_OK; + } + else + return S_FALSE; +} + +static const ISpObjectWithTokenVtbl objwithtoken_vtbl = +{ + objwithtoken_QueryInterface, + objwithtoken_AddRef, + objwithtoken_Release, + objwithtoken_SetObjectToken, + objwithtoken_GetObjectToken +}; + +static HRESULT WINAPI mmsysaudio_QueryInterface(ISpMMSysAudio *iface, REFIID iid, void **obj) +{ + struct mmaudio *This = impl_from_ISpMMSysAudio(iface); + + TRACE("(%p, %s, %p).\n", iface, debugstr_guid(iid), obj); + + if (IsEqualIID(iid, &IID_IUnknown) || + IsEqualIID(iid, &IID_ISequentialStream) || + IsEqualIID(iid, &IID_IStream) || + IsEqualIID(iid, &IID_ISpStreamFormat) || + IsEqualIID(iid, &IID_ISpAudio) || + IsEqualIID(iid, &IID_ISpMMSysAudio)) + *obj = &This->ISpMMSysAudio_iface; + else if (IsEqualIID(iid, &IID_ISpEventSource)) + *obj = &This->ISpEventSource_iface; + else if (IsEqualIID(iid, &IID_ISpEventSink)) + *obj = &This->ISpEventSink_iface; + else if (IsEqualIID(iid, &IID_ISpObjectWithToken)) + *obj = &This->ISpObjectWithToken_iface; + else + { + *obj = NULL; + FIXME("interface %s not implemented.\n", debugstr_guid(iid)); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*obj); + return S_OK; +} + +static ULONG WINAPI mmsysaudio_AddRef(ISpMMSysAudio *iface) +{ + struct mmaudio *This = impl_from_ISpMMSysAudio(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p): ref=%lu\n", iface, ref); + + return ref; +} + +static ULONG WINAPI mmsysaudio_Release(ISpMMSysAudio *iface) +{ + struct mmaudio *This = impl_from_ISpMMSysAudio(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p): ref=%lu\n", iface, ref); + + if (!ref) + { + if (This->token) ISpObjectToken_Release(This->token); + + heap_free(This); + } + + return ref; +} + +static HRESULT WINAPI mmsysaudio_Read(ISpMMSysAudio *iface, void *pv, ULONG cb, ULONG *cb_read) +{ + FIXME("(%p, %p, %lu, %p): stub.\n", iface, pv, cb, cb_read); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_Write(ISpMMSysAudio *iface, const void *pv, ULONG cb, ULONG *cb_written) +{ + FIXME("(%p, %p, %lu, %p): stub.\n", iface, pv, cb, cb_written); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_Seek(ISpMMSysAudio *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *new_pos) +{ + FIXME("(%p, %s, %lu, %p): stub.\n", iface, wine_dbgstr_longlong(move.QuadPart), origin, new_pos); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_SetSize(ISpMMSysAudio *iface, ULARGE_INTEGER new_size) +{ + FIXME("(%p, %s): stub.\n", iface, wine_dbgstr_longlong(new_size.QuadPart)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_CopyTo(ISpMMSysAudio *iface, IStream *stream, ULARGE_INTEGER cb, + ULARGE_INTEGER *cb_read, ULARGE_INTEGER *cb_written) +{ + FIXME("(%p, %p, %s, %p, %p): stub.\n", iface, stream, wine_dbgstr_longlong(cb.QuadPart), cb_read, cb_written); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_Commit(ISpMMSysAudio *iface, DWORD flags) +{ + FIXME("(%p, %#lx): stub.\n", iface, flags); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_Revert(ISpMMSysAudio *iface) +{ + FIXME("(%p).\n", iface); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_LockRegion(ISpMMSysAudio *iface, ULARGE_INTEGER offset, ULARGE_INTEGER cb, + DWORD lock_type) +{ + FIXME("(%p, %s, %s, %#lx): stub.\n", iface, wine_dbgstr_longlong(offset.QuadPart), + wine_dbgstr_longlong(cb.QuadPart), lock_type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_UnlockRegion(ISpMMSysAudio *iface, ULARGE_INTEGER offset, ULARGE_INTEGER cb, + DWORD lock_type) +{ + FIXME("(%p, %s, %s, %#lx): stub.\n", iface, wine_dbgstr_longlong(offset.QuadPart), + wine_dbgstr_longlong(cb.QuadPart), lock_type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_Stat(ISpMMSysAudio *iface, STATSTG *statstg, DWORD flags) +{ + FIXME("(%p, %p, %#lx): stub.\n", iface, statstg, flags); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_Clone(ISpMMSysAudio *iface, IStream **stream) +{ + FIXME("(%p, %p): stub.\n", iface, stream); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_GetFormat(ISpMMSysAudio *iface, GUID *format, WAVEFORMATEX **wfx) +{ + FIXME("(%p, %p, %p): stub.\n", iface, format, wfx); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_SetState(ISpMMSysAudio *iface, SPAUDIOSTATE state, ULONGLONG reserved) +{ + FIXME("(%p, %u, %s): stub.\n", iface, state, wine_dbgstr_longlong(reserved)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_SetFormat(ISpMMSysAudio *iface, const GUID *guid, const WAVEFORMATEX *wfx) +{ + FIXME("(%p, %s, %p): stub.\n", iface, debugstr_guid(guid), wfx); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_GetStatus(ISpMMSysAudio *iface, SPAUDIOSTATUS *status) +{ + FIXME("(%p, %p): stub.\n", iface, status); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_SetBufferInfo(ISpMMSysAudio *iface, const SPAUDIOBUFFERINFO *info) +{ + FIXME("(%p, %p): stub.\n", iface, info); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_GetBufferInfo(ISpMMSysAudio *iface, SPAUDIOBUFFERINFO *info) +{ + FIXME("(%p, %p): stub.\n", iface, info); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_GetDefaultFormat(ISpMMSysAudio *iface, GUID *guid, WAVEFORMATEX **wfx) +{ + FIXME("(%p, %p, %p): stub.\n", iface, guid, wfx); + + return E_NOTIMPL; +} + +static HANDLE WINAPI mmsysaudio_EventHandle(ISpMMSysAudio *iface) +{ + FIXME("(%p): stub.\n", iface); + + return NULL; +} + +static HRESULT WINAPI mmsysaudio_GetVolumeLevel(ISpMMSysAudio *iface, ULONG *level) +{ + FIXME("(%p, %p): stub.\n", iface, level); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_SetVolumeLevel(ISpMMSysAudio *iface, ULONG level) +{ + FIXME("(%p, %lu): stub.\n", iface, level); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_GetBufferNotifySize(ISpMMSysAudio *iface, ULONG *size) +{ + FIXME("(%p, %p): stub.\n", iface, size); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_SetBufferNotifySize(ISpMMSysAudio *iface, ULONG size) +{ + FIXME("(%p, %lu): stub.\n", iface, size); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_GetDeviceId(ISpMMSysAudio *iface, UINT *id) +{ + FIXME("(%p, %p): stub.\n", iface, id); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_SetDeviceId(ISpMMSysAudio *iface, UINT id) +{ + FIXME("(%p, %u): stub.\n", iface, id); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_GetMMHandle(ISpMMSysAudio *iface, void **handle) +{ + FIXME("(%p, %p): stub.\n", iface, handle); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_GetLineId(ISpMMSysAudio *iface, UINT *id) +{ + FIXME("(%p, %p): stub.\n", iface, id); + + return E_NOTIMPL; +} + +static HRESULT WINAPI mmsysaudio_SetLineId(ISpMMSysAudio *iface, UINT id) +{ + FIXME("(%p, %u): stub.\n", iface, id); + + return E_NOTIMPL; +} + +static const ISpMMSysAudioVtbl mmsysaudio_vtbl = +{ + mmsysaudio_QueryInterface, + mmsysaudio_AddRef, + mmsysaudio_Release, + mmsysaudio_Read, + mmsysaudio_Write, + mmsysaudio_Seek, + mmsysaudio_SetSize, + mmsysaudio_CopyTo, + mmsysaudio_Commit, + mmsysaudio_Revert, + mmsysaudio_LockRegion, + mmsysaudio_UnlockRegion, + mmsysaudio_Stat, + mmsysaudio_Clone, + mmsysaudio_GetFormat, + mmsysaudio_SetState, + mmsysaudio_SetFormat, + mmsysaudio_GetStatus, + mmsysaudio_SetBufferInfo, + mmsysaudio_GetBufferInfo, + mmsysaudio_GetDefaultFormat, + mmsysaudio_EventHandle, + mmsysaudio_GetVolumeLevel, + mmsysaudio_SetVolumeLevel, + mmsysaudio_GetBufferNotifySize, + mmsysaudio_SetBufferNotifySize, + mmsysaudio_GetDeviceId, + mmsysaudio_SetDeviceId, + mmsysaudio_GetMMHandle, + mmsysaudio_GetLineId, + mmsysaudio_SetLineId +}; + +static HRESULT mmaudio_create(IUnknown *outer, REFIID iid, void **obj, enum flow_type flow) +{ + struct mmaudio *This; + HRESULT hr; + + if (flow != FLOW_OUT) + { + FIXME("flow %d not implemented.\n", flow); + return E_NOTIMPL; + } + + if (!(This = heap_alloc_zero(sizeof(*This)))) + return E_OUTOFMEMORY; + This->ISpEventSource_iface.lpVtbl = &event_source_vtbl; + This->ISpEventSink_iface.lpVtbl = &event_sink_vtbl; + This->ISpObjectWithToken_iface.lpVtbl = &objwithtoken_vtbl; + This->ISpMMSysAudio_iface.lpVtbl = &mmsysaudio_vtbl; + This->ref = 1; + + This->flow = flow; + This->token = NULL; + + hr = ISpMMSysAudio_QueryInterface(&This->ISpMMSysAudio_iface, iid, obj); + + ISpMMSysAudio_Release(&This->ISpMMSysAudio_iface); + return hr; +} + +HRESULT mmaudio_out_create(IUnknown *outer, REFIID iid, void **obj) +{ + return mmaudio_create(outer, iid, obj, FLOW_OUT); +} diff --git a/dlls/sapi/sapi_classes.idl b/dlls/sapi/sapi_classes.idl index bb580dde18e..14f24aa9c02 100644 --- a/dlls/sapi/sapi_classes.idl +++ b/dlls/sapi/sapi_classes.idl @@ -103,3 +103,18 @@ coclass SpFileStream interface ISpStream; [default] interface ISpeechFileStream; } + +[ + uuid(a8c680eb-3d32-11d2-9ee7-00c04f797396), + helpstring("SpMMAudioOut"), + progid("SAPI.SpMMAudioOut.1"), + vi_progid("SAPI.SpMMAudioOut"), + threading(both) +] +coclass SpMMAudioOut +{ + interface ISpEventSource; + interface ISpEventSink; + interface ISpObjectWithToken; + interface ISpMMSysAudio; +} diff --git a/dlls/sapi/sapi_private.h b/dlls/sapi/sapi_private.h index fcecafb450e..88b1a27516f 100644 --- a/dlls/sapi/sapi_private.h +++ b/dlls/sapi/sapi_private.h @@ -25,6 +25,7 @@ HRESULT file_stream_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_H HRESULT resource_manager_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN; HRESULT speech_stream_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN; HRESULT speech_voice_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN; +HRESULT mmaudio_out_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN; HRESULT token_category_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN; HRESULT token_enum_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN; HRESULT token_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN; diff --git a/dlls/sapi/tests/Makefile.in b/dlls/sapi/tests/Makefile.in index 75c70d072d8..981bb828b8b 100644 --- a/dlls/sapi/tests/Makefile.in +++ b/dlls/sapi/tests/Makefile.in @@ -3,6 +3,7 @@ IMPORTS = ole32 user32 advapi32 C_SRCS = \ automation.c \ + mmaudio.c \ resource.c \ stream.c \ token.c \ diff --git a/dlls/sapi/tests/mmaudio.c b/dlls/sapi/tests/mmaudio.c new file mode 100644 index 00000000000..5dd0d91ab1d --- /dev/null +++ b/dlls/sapi/tests/mmaudio.c @@ -0,0 +1,68 @@ +/* + * Speech API (SAPI) winmm audio tests. + * + * Copyright 2023 Shaun Ren 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 + */ + +#define COBJMACROS + +#include "sapiddk.h" +#include "sperror.h" + +#include "wine/test.h" + +static void test_interfaces(void) +{ + ISpMMSysAudio *mmaudio; + IUnknown *unk; + ISpEventSource *source; + ISpEventSink *sink; + ISpObjectWithToken *obj_with_token; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_SpMMAudioOut, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpMMSysAudio, (void **)&mmaudio); + ok(hr == S_OK, "Failed to create ISpMMSysAudio interface: %#lx.\n", hr); + ISpMMSysAudio_Release(mmaudio); + + hr = CoCreateInstance(&CLSID_SpMMAudioOut, NULL, CLSCTX_INPROC_SERVER, + &IID_IUnknown, (void **)&unk); + ok(hr == S_OK, "Failed to create IUnknown interface: %#lx.\n", hr); + IUnknown_Release(unk); + + hr = CoCreateInstance(&CLSID_SpMMAudioOut, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpEventSource, (void **)&source); + ok(hr == S_OK, "Failed to create ISpEventSource interface: %#lx.\n", hr); + ISpEventSource_Release(source); + + hr = CoCreateInstance(&CLSID_SpMMAudioOut, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpEventSink, (void **)&sink); + ok(hr == S_OK, "Failed to create ISpEventSink interface: %#lx.\n", hr); + ISpEventSink_Release(sink); + + hr = CoCreateInstance(&CLSID_SpMMAudioOut, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpObjectWithToken, (void **)&obj_with_token); + ok(hr == S_OK, "Failed to create ISpObjectWithToken interface: %#lx.\n", hr); + ISpObjectWithToken_Release(obj_with_token); +} + +START_TEST(mmaudio) +{ + CoInitialize(NULL); + test_interfaces(); + CoUninitialize(); +} From b3a4aca6969ee6e80a4f36f0e6be22097613e981 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Fri, 26 May 2023 23:56:47 -0400 Subject: [PATCH 2185/2777] sapi: Implement ISpMMSysAudio::Get/SetDeviceId. (cherry picked from commit 454283ec2225bc2b64a643fe9977d842a7036a4a) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/Makefile.in | 1 + dlls/sapi/mmaudio.c | 32 ++++++++++++++++++++++++----- dlls/sapi/tests/Makefile.in | 2 +- dlls/sapi/tests/mmaudio.c | 40 +++++++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 6 deletions(-) diff --git a/dlls/sapi/Makefile.in b/dlls/sapi/Makefile.in index ca64edec6dd..8a1ead0b78b 100644 --- a/dlls/sapi/Makefile.in +++ b/dlls/sapi/Makefile.in @@ -1,5 +1,6 @@ MODULE = sapi.dll IMPORTS = uuid ole32 user32 advapi32 +DELAYIMPORTS = winmm C_SRCS = \ automation.c \ diff --git a/dlls/sapi/mmaudio.c b/dlls/sapi/mmaudio.c index 684476f5c56..ec9c02cb210 100644 --- a/dlls/sapi/mmaudio.c +++ b/dlls/sapi/mmaudio.c @@ -47,6 +47,8 @@ struct mmaudio enum flow_type flow; ISpObjectToken *token; + UINT device_id; + CRITICAL_SECTION cs; }; static inline struct mmaudio *impl_from_ISpEventSource(ISpEventSource *iface) @@ -356,6 +358,7 @@ static ULONG WINAPI mmsysaudio_Release(ISpMMSysAudio *iface) if (!ref) { if (This->token) ISpObjectToken_Release(This->token); + DeleteCriticalSection(&This->cs); heap_free(This); } @@ -531,16 +534,33 @@ static HRESULT WINAPI mmsysaudio_SetBufferNotifySize(ISpMMSysAudio *iface, ULONG static HRESULT WINAPI mmsysaudio_GetDeviceId(ISpMMSysAudio *iface, UINT *id) { - FIXME("(%p, %p): stub.\n", iface, id); + struct mmaudio *This = impl_from_ISpMMSysAudio(iface); - return E_NOTIMPL; + TRACE("(%p, %p).\n", iface, id); + + if (!id) return E_POINTER; + + EnterCriticalSection(&This->cs); + *id = This->device_id; + LeaveCriticalSection(&This->cs); + + return S_OK; } static HRESULT WINAPI mmsysaudio_SetDeviceId(ISpMMSysAudio *iface, UINT id) { - FIXME("(%p, %u): stub.\n", iface, id); + struct mmaudio *This = impl_from_ISpMMSysAudio(iface); - return E_NOTIMPL; + TRACE("(%p, %u).\n", iface, id); + + if (id != WAVE_MAPPER && id >= waveOutGetNumDevs()) + return E_INVALIDARG; + + EnterCriticalSection(&This->cs); + This->device_id = id; + LeaveCriticalSection(&This->cs); + + return S_OK; } static HRESULT WINAPI mmsysaudio_GetMMHandle(ISpMMSysAudio *iface, void **handle) @@ -620,9 +640,11 @@ static HRESULT mmaudio_create(IUnknown *outer, REFIID iid, void **obj, enum flow This->flow = flow; This->token = NULL; + This->device_id = WAVE_MAPPER; - hr = ISpMMSysAudio_QueryInterface(&This->ISpMMSysAudio_iface, iid, obj); + InitializeCriticalSection(&This->cs); + hr = ISpMMSysAudio_QueryInterface(&This->ISpMMSysAudio_iface, iid, obj); ISpMMSysAudio_Release(&This->ISpMMSysAudio_iface); return hr; } diff --git a/dlls/sapi/tests/Makefile.in b/dlls/sapi/tests/Makefile.in index 981bb828b8b..ea14710194f 100644 --- a/dlls/sapi/tests/Makefile.in +++ b/dlls/sapi/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = sapi.dll -IMPORTS = ole32 user32 advapi32 +IMPORTS = ole32 user32 advapi32 winmm C_SRCS = \ automation.c \ diff --git a/dlls/sapi/tests/mmaudio.c b/dlls/sapi/tests/mmaudio.c index 5dd0d91ab1d..3816c0caf9c 100644 --- a/dlls/sapi/tests/mmaudio.c +++ b/dlls/sapi/tests/mmaudio.c @@ -60,9 +60,49 @@ static void test_interfaces(void) ISpObjectWithToken_Release(obj_with_token); } +static void test_device_id(void) +{ + ISpMMSysAudio *mmaudio; + UINT id, num_devs; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_SpMMAudioOut, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpMMSysAudio, (void **)&mmaudio); + ok(hr == S_OK, "failed to create SpMMAudioOut instance: %#lx.\n", hr); + + id = 0xdeadbeef; + hr = ISpMMSysAudio_GetDeviceId(mmaudio, &id); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(id == WAVE_MAPPER, "got %#x.\n", id); + + hr = ISpMMSysAudio_SetDeviceId(mmaudio, WAVE_MAPPER); + ok(hr == S_OK, "got %#lx.\n", hr); + + num_devs = waveOutGetNumDevs(); + if (num_devs == 0) { + skip("no wave out devices.\n"); + ISpMMSysAudio_Release(mmaudio); + return; + } + + hr = ISpMMSysAudio_SetDeviceId(mmaudio, num_devs); + ok(hr == E_INVALIDARG, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_SetDeviceId(mmaudio, 0); + ok(hr == S_OK || broken(hr == S_FALSE) /* Windows */, "got %#lx.\n", hr); + + id = 0xdeadbeef; + hr = ISpMMSysAudio_GetDeviceId(mmaudio, &id); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(id == 0, "got %u.\n", id); + + ISpMMSysAudio_Release(mmaudio); +} + START_TEST(mmaudio) { CoInitialize(NULL); test_interfaces(); + test_device_id(); CoUninitialize(); } From dd5f017fb99aab2f90a2706b992bb8e47746f179 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Mon, 15 May 2023 23:06:47 -0400 Subject: [PATCH 2186/2777] sapi: Add GUIDs SPDFID_Text/WaveFormatEx. (cherry picked from commit 615852a97fe73964973f465a8db7227232c2464e) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/mmaudio.c | 5 +++++ include/sapi.idl | 3 +++ 2 files changed, 8 insertions(+) diff --git a/dlls/sapi/mmaudio.c b/dlls/sapi/mmaudio.c index ec9c02cb210..c9eb12bdcb5 100644 --- a/dlls/sapi/mmaudio.c +++ b/dlls/sapi/mmaudio.c @@ -29,12 +29,17 @@ #include "sapiddk.h" #include "sperror.h" +#include "initguid.h" + #include "wine/debug.h" #include "sapi_private.h" WINE_DEFAULT_DEBUG_CHANNEL(sapi); +DEFINE_GUID(SPDFID_Text, 0x7ceef9f9, 0x3d13, 0x11d2, 0x9e, 0xe7, 0x00, 0xc0, 0x4f, 0x79, 0x73, 0x96); +DEFINE_GUID(SPDFID_WaveFormatEx, 0xc31adbae, 0x527f, 0x4ff5, 0xa2, 0x30, 0xf6, 0x2b, 0xb6, 0x1f, 0xf7, 0x0c); + enum flow_type { FLOW_IN, FLOW_OUT }; struct mmaudio diff --git a/include/sapi.idl b/include/sapi.idl index 92a2881501c..16b8348d73b 100644 --- a/include/sapi.idl +++ b/include/sapi.idl @@ -426,6 +426,9 @@ typedef [hidden] enum SPSTREAMFORMAT SPSF_NUM_FORMATS } SPSTREAMFORMAT; +cpp_quote("EXTERN_C const GUID SPDFID_Text;") +cpp_quote("EXTERN_C const GUID SPDFID_WaveFormatEx;") + typedef unsigned short SPPHONEID; typedef [restricted, hidden] struct SPPHRASEELEMENT From 3a45cccd7c7df0bd54a300ebdc044094004c0b0a Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Fri, 26 May 2023 14:31:51 -0400 Subject: [PATCH 2187/2777] include: Add sperror error code SPERR_UNSUPPORTED_FORMAT. (cherry picked from commit b24c1abf623ce08370b70da9de93efd615a55e21) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- include/sperror.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/sperror.h b/include/sperror.h index cd8ed9b948d..0e37ac91c87 100644 --- a/include/sperror.h +++ b/include/sperror.h @@ -47,6 +47,7 @@ #define SPERR_UNINITIALIZED 0x80045001 #define SPERR_ALREADY_INITIALIZED 0x80045002 +#define SPERR_UNSUPPORTED_FORMAT 0x80045003 #define SPERR_INVALID_FLAGS 0x80045004 #define SPERR_DEVICE_BUSY 0x80045006 #define SPERR_DEVICE_NOT_SUPPORTED 0x80045007 From 3f5a7e77e4ea1172e439da454b03f55401014ce1 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Sat, 27 May 2023 16:26:34 -0400 Subject: [PATCH 2188/2777] sapi: Implement ISpMMSysAudio::Get/SetFormat. (cherry picked from commit 473a5462e583cefff3e276cdf1e16b953466baa0) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/mmaudio.c | 68 ++++++++++++++++++++++++++++++++++++--- dlls/sapi/tests/mmaudio.c | 60 ++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 4 deletions(-) diff --git a/dlls/sapi/mmaudio.c b/dlls/sapi/mmaudio.c index c9eb12bdcb5..690e540122b 100644 --- a/dlls/sapi/mmaudio.c +++ b/dlls/sapi/mmaudio.c @@ -53,6 +53,7 @@ struct mmaudio enum flow_type flow; ISpObjectToken *token; UINT device_id; + WAVEFORMATEX *wfx; CRITICAL_SECTION cs; }; @@ -363,6 +364,7 @@ static ULONG WINAPI mmsysaudio_Release(ISpMMSysAudio *iface) if (!ref) { if (This->token) ISpObjectToken_Release(This->token); + heap_free(This->wfx); DeleteCriticalSection(&This->cs); heap_free(This); @@ -455,9 +457,26 @@ static HRESULT WINAPI mmsysaudio_Clone(ISpMMSysAudio *iface, IStream **stream) static HRESULT WINAPI mmsysaudio_GetFormat(ISpMMSysAudio *iface, GUID *format, WAVEFORMATEX **wfx) { - FIXME("(%p, %p, %p): stub.\n", iface, format, wfx); + struct mmaudio *This = impl_from_ISpMMSysAudio(iface); - return E_NOTIMPL; + TRACE("(%p, %p, %p).\n", iface, format, wfx); + + if (!format || !wfx) + return E_POINTER; + + EnterCriticalSection(&This->cs); + + if (!(*wfx = CoTaskMemAlloc(sizeof(WAVEFORMATEX) + This->wfx->cbSize))) + { + LeaveCriticalSection(&This->cs); + return E_OUTOFMEMORY; + } + *format = SPDFID_WaveFormatEx; + memcpy(*wfx, This->wfx, sizeof(WAVEFORMATEX) + This->wfx->cbSize); + + LeaveCriticalSection(&This->cs); + + return S_OK; } static HRESULT WINAPI mmsysaudio_SetState(ISpMMSysAudio *iface, SPAUDIOSTATE state, ULONGLONG reserved) @@ -469,9 +488,37 @@ static HRESULT WINAPI mmsysaudio_SetState(ISpMMSysAudio *iface, SPAUDIOSTATE sta static HRESULT WINAPI mmsysaudio_SetFormat(ISpMMSysAudio *iface, const GUID *guid, const WAVEFORMATEX *wfx) { - FIXME("(%p, %s, %p): stub.\n", iface, debugstr_guid(guid), wfx); + struct mmaudio *This = impl_from_ISpMMSysAudio(iface); + MMRESULT res; + WAVEFORMATEX *new_wfx; - return E_NOTIMPL; + TRACE("(%p, %s, %p).\n", iface, debugstr_guid(guid), wfx); + + if (!guid || !wfx || !IsEqualGUID(guid, &SPDFID_WaveFormatEx)) + return E_INVALIDARG; + + EnterCriticalSection(&This->cs); + + /* Determine whether the device supports the requested format. */ + res = waveOutOpen(NULL, This->device_id, wfx, 0, 0, WAVE_FORMAT_QUERY); + if (res != MMSYSERR_NOERROR) + { + LeaveCriticalSection(&This->cs); + return res == WAVERR_BADFORMAT ? SPERR_UNSUPPORTED_FORMAT : SPERR_GENERIC_MMSYS_ERROR; + } + + if (!(new_wfx = heap_alloc(sizeof(*wfx) + wfx->cbSize))) + { + LeaveCriticalSection(&This->cs); + return E_OUTOFMEMORY; + } + memcpy(new_wfx, wfx, sizeof(*wfx) + wfx->cbSize); + heap_free(This->wfx); + This->wfx = new_wfx; + + LeaveCriticalSection(&This->cs); + + return S_OK; } static HRESULT WINAPI mmsysaudio_GetStatus(ISpMMSysAudio *iface, SPAUDIOSTATUS *status) @@ -647,6 +694,19 @@ static HRESULT mmaudio_create(IUnknown *outer, REFIID iid, void **obj, enum flow This->token = NULL; This->device_id = WAVE_MAPPER; + if (!(This->wfx = heap_alloc(sizeof(*This->wfx)))) + { + heap_free(This); + return E_OUTOFMEMORY; + } + This->wfx->wFormatTag = WAVE_FORMAT_PCM; + This->wfx->nChannels = 1; + This->wfx->nSamplesPerSec = 22050; + This->wfx->nAvgBytesPerSec = 22050 * 2; + This->wfx->nBlockAlign = 2; + This->wfx->wBitsPerSample = 16; + This->wfx->cbSize = 0; + InitializeCriticalSection(&This->cs); hr = ISpMMSysAudio_QueryInterface(&This->ISpMMSysAudio_iface, iid, obj); diff --git a/dlls/sapi/tests/mmaudio.c b/dlls/sapi/tests/mmaudio.c index 3816c0caf9c..8611242e2b7 100644 --- a/dlls/sapi/tests/mmaudio.c +++ b/dlls/sapi/tests/mmaudio.c @@ -22,9 +22,13 @@ #include "sapiddk.h" #include "sperror.h" +#include "initguid.h" #include "wine/test.h" +DEFINE_GUID(SPDFID_Text, 0x7ceef9f9, 0x3d13, 0x11d2, 0x9e, 0xe7, 0x00, 0xc0, 0x4f, 0x79, 0x73, 0x96); +DEFINE_GUID(SPDFID_WaveFormatEx, 0xc31adbae, 0x527f, 0x4ff5, 0xa2, 0x30, 0xf6, 0x2b, 0xb6, 0x1f, 0xf7, 0x0c); + static void test_interfaces(void) { ISpMMSysAudio *mmaudio; @@ -99,10 +103,66 @@ static void test_device_id(void) ISpMMSysAudio_Release(mmaudio); } +static void test_formats(void) +{ + ISpMMSysAudio *mmaudio; + GUID fmtid; + WAVEFORMATEX *wfx; + WAVEFORMATEX wfx2; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_SpMMAudioOut, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpMMSysAudio, (void **)&mmaudio); + ok(hr == S_OK, "failed to create SpMMAudioOut instance: %#lx.\n", hr); + + wfx = NULL; + hr = ISpMMSysAudio_GetFormat(mmaudio, &fmtid, &wfx); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(IsEqualGUID(&fmtid, &SPDFID_WaveFormatEx), "got %s.\n", wine_dbgstr_guid(&fmtid)); + ok(wfx != NULL, "wfx == NULL.\n"); + ok(wfx->wFormatTag == WAVE_FORMAT_PCM, "got %u.\n", wfx->wFormatTag); + ok(wfx->nChannels == 1, "got %u.\n", wfx->nChannels); + ok(wfx->nSamplesPerSec == 22050, "got %lu.\n", wfx->nSamplesPerSec); + ok(wfx->nAvgBytesPerSec == 22050 * 2, "got %lu.\n", wfx->nAvgBytesPerSec); + ok(wfx->nBlockAlign == 2, "got %u.\n", wfx->nBlockAlign); + ok(wfx->wBitsPerSample == 16, "got %u.\n", wfx->wBitsPerSample); + ok(wfx->cbSize == 0, "got %u.\n", wfx->cbSize); + CoTaskMemFree(wfx); + + hr = ISpMMSysAudio_SetFormat(mmaudio, NULL, NULL); + ok(hr == E_INVALIDARG, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_SetFormat(mmaudio, &SPDFID_Text, NULL); + ok(hr == E_INVALIDARG, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_SetFormat(mmaudio, &SPDFID_WaveFormatEx, NULL); + ok(hr == E_INVALIDARG, "got %#lx.\n", hr); + + if (waveOutGetNumDevs() == 0) { + skip("no wave out devices.\n"); + ISpMMSysAudio_Release(mmaudio); + return; + } + + wfx2.wFormatTag = WAVE_FORMAT_PCM; + wfx2.nChannels = 2; + wfx2.nSamplesPerSec = 16000; + wfx2.nAvgBytesPerSec = 16000 * 2 * 2; + wfx2.nBlockAlign = 2 * 2; + wfx2.wBitsPerSample = 16; + wfx2.cbSize = 0; + + hr = ISpMMSysAudio_SetFormat(mmaudio, &SPDFID_WaveFormatEx, &wfx2); + ok(hr == S_OK, "got %#lx.\n", hr); + + ISpMMSysAudio_Release(mmaudio); +} + START_TEST(mmaudio) { CoInitialize(NULL); test_interfaces(); test_device_id(); + test_formats(); CoUninitialize(); } From 45e67347ecbfa874249411a13155465b540bd89a Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Sat, 27 May 2023 17:20:03 -0400 Subject: [PATCH 2189/2777] sapi: Partially implement ISpMMSysAudio::SetState. (cherry picked from commit 107d95165a0902828124bb1d9bf5adda987c9810) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/mmaudio.c | 73 +++++++++++++++++++++++++++++++++++++-- dlls/sapi/tests/mmaudio.c | 62 +++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 2 deletions(-) diff --git a/dlls/sapi/mmaudio.c b/dlls/sapi/mmaudio.c index 690e540122b..20e6cc5064f 100644 --- a/dlls/sapi/mmaudio.c +++ b/dlls/sapi/mmaudio.c @@ -53,7 +53,13 @@ struct mmaudio enum flow_type flow; ISpObjectToken *token; UINT device_id; + SPAUDIOSTATE state; WAVEFORMATEX *wfx; + union + { + HWAVEIN in; + HWAVEOUT out; + } hwave; CRITICAL_SECTION cs; }; @@ -363,6 +369,8 @@ static ULONG WINAPI mmsysaudio_Release(ISpMMSysAudio *iface) if (!ref) { + ISpMMSysAudio_SetState(iface, SPAS_CLOSED, 0); + if (This->token) ISpObjectToken_Release(This->token); heap_free(This->wfx); DeleteCriticalSection(&This->cs); @@ -481,9 +489,45 @@ static HRESULT WINAPI mmsysaudio_GetFormat(ISpMMSysAudio *iface, GUID *format, W static HRESULT WINAPI mmsysaudio_SetState(ISpMMSysAudio *iface, SPAUDIOSTATE state, ULONGLONG reserved) { - FIXME("(%p, %u, %s): stub.\n", iface, state, wine_dbgstr_longlong(reserved)); + struct mmaudio *This = impl_from_ISpMMSysAudio(iface); + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("(%p, %u, %s).\n", iface, state, wine_dbgstr_longlong(reserved)); + + if (state != SPAS_CLOSED && state != SPAS_RUN) + { + FIXME("state %#x not implemented.\n", state); + return E_NOTIMPL; + } + + EnterCriticalSection(&This->cs); + + if (This->state == state) + goto done; + + if (This->state == SPAS_CLOSED) + { + if (waveOutOpen(&This->hwave.out, This->device_id, This->wfx, 0, 0, 0) != MMSYSERR_NOERROR) + { + hr = SPERR_GENERIC_MMSYS_ERROR; + goto done; + } + } + + if (state == SPAS_CLOSED && This->state != SPAS_CLOSED) + { + if (waveOutClose(This->hwave.out) != MMSYSERR_NOERROR) + { + hr = SPERR_GENERIC_MMSYS_ERROR; + goto done; + } + } + + This->state = state; + +done: + LeaveCriticalSection(&This->cs); + return hr; } static HRESULT WINAPI mmsysaudio_SetFormat(ISpMMSysAudio *iface, const GUID *guid, const WAVEFORMATEX *wfx) @@ -499,6 +543,18 @@ static HRESULT WINAPI mmsysaudio_SetFormat(ISpMMSysAudio *iface, const GUID *gui EnterCriticalSection(&This->cs); + if (!memcmp(wfx, This->wfx, sizeof(*wfx)) && !memcmp(wfx + 1, This->wfx + 1, wfx->cbSize)) + { + LeaveCriticalSection(&This->cs); + return S_OK; + } + + if (This->state != SPAS_CLOSED) + { + LeaveCriticalSection(&This->cs); + return SPERR_DEVICE_BUSY; + } + /* Determine whether the device supports the requested format. */ res = waveOutOpen(NULL, This->device_id, wfx, 0, 0, WAVE_FORMAT_QUERY); if (res != MMSYSERR_NOERROR) @@ -609,7 +665,19 @@ static HRESULT WINAPI mmsysaudio_SetDeviceId(ISpMMSysAudio *iface, UINT id) return E_INVALIDARG; EnterCriticalSection(&This->cs); + + if (id == This->device_id) + { + LeaveCriticalSection(&This->cs); + return S_OK; + } + if (This->state != SPAS_CLOSED) + { + LeaveCriticalSection(&This->cs); + return SPERR_DEVICE_BUSY; + } This->device_id = id; + LeaveCriticalSection(&This->cs); return S_OK; @@ -693,6 +761,7 @@ static HRESULT mmaudio_create(IUnknown *outer, REFIID iid, void **obj, enum flow This->flow = flow; This->token = NULL; This->device_id = WAVE_MAPPER; + This->state = SPAS_CLOSED; if (!(This->wfx = heap_alloc(sizeof(*This->wfx)))) { diff --git a/dlls/sapi/tests/mmaudio.c b/dlls/sapi/tests/mmaudio.c index 8611242e2b7..85a3570f490 100644 --- a/dlls/sapi/tests/mmaudio.c +++ b/dlls/sapi/tests/mmaudio.c @@ -158,11 +158,73 @@ static void test_formats(void) ISpMMSysAudio_Release(mmaudio); } +static void test_audio_out(void) +{ + ISpMMSysAudio *mmaudio; + GUID fmtid; + WAVEFORMATEX *wfx = NULL; + UINT devid; + HRESULT hr; + + if (waveOutGetNumDevs() == 0) { + skip("no wave out devices.\n"); + return; + } + + hr = CoCreateInstance(&CLSID_SpMMAudioOut, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpMMSysAudio, (void **)&mmaudio); + ok(hr == S_OK, "failed to create SPMMAudioOut instance: %#lx.\n", hr); + + hr = ISpMMSysAudio_SetState(mmaudio, SPAS_CLOSED, 0); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_GetFormat(mmaudio, &fmtid, &wfx); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(IsEqualGUID(&fmtid, &SPDFID_WaveFormatEx), "got %s.\n", wine_dbgstr_guid(&fmtid)); + ok(wfx != NULL, "wfx == NULL.\n"); + + hr = ISpMMSysAudio_SetFormat(mmaudio, &fmtid, wfx); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_SetDeviceId(mmaudio, WAVE_MAPPER); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_SetState(mmaudio, SPAS_RUN, 0); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_SetDeviceId(mmaudio, WAVE_MAPPER); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_SetDeviceId(mmaudio, 0); + ok(hr == SPERR_DEVICE_BUSY, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_SetFormat(mmaudio, &fmtid, wfx); + ok(hr == S_OK, "got %#lx.\n", hr); + + wfx->nChannels = wfx->nChannels == 1 ? 2 : 1; + wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nChannels * wfx->wBitsPerSample / 8; + wfx->nBlockAlign = wfx->nChannels * wfx->wBitsPerSample / 8; + hr = ISpMMSysAudio_SetFormat(mmaudio, &fmtid, wfx); + ok(hr == SPERR_DEVICE_BUSY, "got %#lx.\n", hr); + + devid = 0xdeadbeef; + hr = ISpMMSysAudio_GetDeviceId(mmaudio, &devid); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(devid == WAVE_MAPPER, "got %#x.\n", devid); + + hr = ISpMMSysAudio_SetState(mmaudio, SPAS_CLOSED, 0); + ok(hr == S_OK, "got %#lx.\n", hr); + + CoTaskMemFree(wfx); + ISpMMSysAudio_Release(mmaudio); +} + START_TEST(mmaudio) { CoInitialize(NULL); test_interfaces(); test_device_id(); test_formats(); + test_audio_out(); CoUninitialize(); } From c94fe4be0c5e54f3d6133134397b01e7556b19e1 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Tue, 30 May 2023 23:29:22 -0400 Subject: [PATCH 2190/2777] sapi: Free completed buffers asynchronously in SpMMAudio. Also introduce async helpers. The buffers cannot be freed directly in wave_out_proc, because calling waveOut related functions in the callback could cause a deadlock. (cherry picked from commit 7bced2878a55d388beaeae76d58d693391e4de24) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/Makefile.in | 1 + dlls/sapi/async.c | 175 +++++++++++++++++++++++++++++++++++++++ dlls/sapi/mmaudio.c | 78 ++++++++++++++++- dlls/sapi/sapi_private.h | 24 ++++++ 4 files changed, 277 insertions(+), 1 deletion(-) create mode 100644 dlls/sapi/async.c diff --git a/dlls/sapi/Makefile.in b/dlls/sapi/Makefile.in index 8a1ead0b78b..4229320e473 100644 --- a/dlls/sapi/Makefile.in +++ b/dlls/sapi/Makefile.in @@ -3,6 +3,7 @@ IMPORTS = uuid ole32 user32 advapi32 DELAYIMPORTS = winmm C_SRCS = \ + async.c \ automation.c \ main.c \ mmaudio.c \ diff --git a/dlls/sapi/async.c b/dlls/sapi/async.c new file mode 100644 index 00000000000..57ae89ad723 --- /dev/null +++ b/dlls/sapi/async.c @@ -0,0 +1,175 @@ +/* + * Speech API (SAPI) async helper implementation. + * + * Copyright 2023 Shaun Ren 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 + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + +#include "wine/heap.h" +#include "wine/list.h" +#include "wine/debug.h" + +#include "sapi_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(sapi); + +static struct async_task *async_dequeue_task(struct async_queue *queue) +{ + struct async_task *task = NULL; + struct list *head; + + EnterCriticalSection(&queue->cs); + if ((head = list_head(&queue->tasks))) + { + task = LIST_ENTRY(head, struct async_task, entry); + list_remove(head); + } + LeaveCriticalSection(&queue->cs); + + return task; +} + +void async_empty_queue(struct async_queue *queue) +{ + struct async_task *task, *next; + + EnterCriticalSection(&queue->cs); + LIST_FOR_EACH_ENTRY_SAFE(task, next, &queue->tasks, struct async_task, entry) + { + list_remove(&task->entry); + heap_free(task); + } + LeaveCriticalSection(&queue->cs); + + SetEvent(queue->empty); +} + +static void CALLBACK async_worker(TP_CALLBACK_INSTANCE *instance, void *ctx) +{ + struct async_queue *queue = ctx; + HANDLE handles[2] = { queue->cancel, queue->wait }; + DWORD ret; + + SetEvent(queue->ready); + + for (;;) + { + ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE); + if (ret == WAIT_OBJECT_0) + goto cancel; + else if (ret == WAIT_OBJECT_0 + 1) + { + struct async_task *task; + + while ((task = async_dequeue_task(queue))) + { + ResetEvent(queue->empty); + task->proc(task); + heap_free(task); + if (WaitForSingleObject(queue->cancel, 0) == WAIT_OBJECT_0) + goto cancel; + } + + SetEvent(queue->empty); + } + else + ERR("WaitForMultipleObjects failed: %#lx.\n", ret); + } + +cancel: + async_empty_queue(queue); + TRACE("cancelled.\n"); + SetEvent(queue->ready); +} + +HRESULT async_start_queue(struct async_queue *queue) +{ + HRESULT hr; + + if (queue->init) + return S_OK; + + InitializeCriticalSection(&queue->cs); + list_init(&queue->tasks); + + if (!(queue->wait = CreateEventW(NULL, FALSE, FALSE, NULL)) || + !(queue->ready = CreateEventW(NULL, FALSE, FALSE, NULL)) || + !(queue->cancel = CreateEventW(NULL, FALSE, FALSE, NULL)) || + !(queue->empty = CreateEventW(NULL, TRUE, TRUE, NULL))) + goto fail; + + queue->init = TRUE; + + if (!TrySubmitThreadpoolCallback(async_worker, queue, NULL)) + goto fail; + + WaitForSingleObject(queue->ready, INFINITE); + return S_OK; + +fail: + hr = HRESULT_FROM_WIN32(GetLastError()); + DeleteCriticalSection(&queue->cs); + if (queue->wait) CloseHandle(queue->wait); + if (queue->ready) CloseHandle(queue->ready); + if (queue->cancel) CloseHandle(queue->cancel); + if (queue->empty) CloseHandle(queue->empty); + memset(queue, 0, sizeof(*queue)); + return hr; +} + +void async_cancel_queue(struct async_queue *queue) +{ + if (!queue->init) return; + + SetEvent(queue->cancel); + WaitForSingleObject(queue->ready, INFINITE); + + DeleteCriticalSection(&queue->cs); + CloseHandle(queue->wait); + CloseHandle(queue->ready); + CloseHandle(queue->cancel); + CloseHandle(queue->empty); + + memset(queue, 0, sizeof(*queue)); +} + +HRESULT async_queue_task(struct async_queue *queue, struct async_task *task) +{ + HRESULT hr; + + if (FAILED(hr = async_start_queue(queue))) + return hr; + + EnterCriticalSection(&queue->cs); + list_add_tail(&queue->tasks, &task->entry); + LeaveCriticalSection(&queue->cs); + + SetEvent(queue->wait); + + return S_OK; +} + +void async_wait_queue_empty(struct async_queue *queue, DWORD timeout) +{ + if (!queue->init) return; + WaitForSingleObject(queue->empty, timeout); +} diff --git a/dlls/sapi/mmaudio.c b/dlls/sapi/mmaudio.c index 20e6cc5064f..add670ff3dc 100644 --- a/dlls/sapi/mmaudio.c +++ b/dlls/sapi/mmaudio.c @@ -60,7 +60,12 @@ struct mmaudio HWAVEIN in; HWAVEOUT out; } hwave; + HANDLE event; + struct async_queue queue; CRITICAL_SECTION cs; + + size_t pending_buf_count; + CRITICAL_SECTION pending_cs; }; static inline struct mmaudio *impl_from_ISpEventSource(ISpEventSource *iface) @@ -371,8 +376,13 @@ static ULONG WINAPI mmsysaudio_Release(ISpMMSysAudio *iface) { ISpMMSysAudio_SetState(iface, SPAS_CLOSED, 0); + async_wait_queue_empty(&This->queue, INFINITE); + async_cancel_queue(&This->queue); + if (This->token) ISpObjectToken_Release(This->token); heap_free(This->wfx); + CloseHandle(This->event); + DeleteCriticalSection(&This->pending_cs); DeleteCriticalSection(&This->cs); heap_free(This); @@ -487,6 +497,57 @@ static HRESULT WINAPI mmsysaudio_GetFormat(ISpMMSysAudio *iface, GUID *format, W return S_OK; } +struct free_buf_task +{ + struct async_task task; + struct mmaudio *audio; + WAVEHDR *buf; +}; + +static void free_out_buf_proc(struct async_task *task) +{ + struct free_buf_task *fbt = (struct free_buf_task *)task; + size_t buf_count; + + TRACE("(%p).\n", task); + + waveOutUnprepareHeader(fbt->audio->hwave.out, fbt->buf, sizeof(WAVEHDR)); + heap_free(fbt->buf); + + EnterCriticalSection(&fbt->audio->pending_cs); + buf_count = --fbt->audio->pending_buf_count; + LeaveCriticalSection(&fbt->audio->pending_cs); + if (!buf_count) + SetEvent(fbt->audio->event); + TRACE("pending_buf_count = %Iu.\n", buf_count); +} + +static void CALLBACK wave_out_proc(HWAVEOUT hwo, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2) +{ + struct mmaudio *This = (struct mmaudio *)instance; + struct free_buf_task *task; + + TRACE("(%p, %#x, %08Ix, %08Ix, %08Ix).\n", hwo, msg, instance, param1, param2); + + switch (msg) + { + case WOM_DONE: + if (!(task = heap_alloc(sizeof(*task)))) + { + ERR("failed to allocate free_buf_task.\n"); + break; + } + task->task.proc = free_out_buf_proc; + task->audio = This; + task->buf = (WAVEHDR *)param1; + async_queue_task(&This->queue, (struct async_task *)task); + break; + + default: + break; + } +} + static HRESULT WINAPI mmsysaudio_SetState(ISpMMSysAudio *iface, SPAUDIOSTATE state, ULONGLONG reserved) { struct mmaudio *This = impl_from_ISpMMSysAudio(iface); @@ -507,7 +568,14 @@ static HRESULT WINAPI mmsysaudio_SetState(ISpMMSysAudio *iface, SPAUDIOSTATE sta if (This->state == SPAS_CLOSED) { - if (waveOutOpen(&This->hwave.out, This->device_id, This->wfx, 0, 0, 0) != MMSYSERR_NOERROR) + if (FAILED(hr = async_start_queue(&This->queue))) + { + ERR("Failed to start async queue: %#lx.\n", hr); + goto done; + } + + if (waveOutOpen(&This->hwave.out, This->device_id, This->wfx, (DWORD_PTR)wave_out_proc, + (DWORD_PTR)This, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { hr = SPERR_GENERIC_MMSYS_ERROR; goto done; @@ -516,6 +584,10 @@ static HRESULT WINAPI mmsysaudio_SetState(ISpMMSysAudio *iface, SPAUDIOSTATE sta if (state == SPAS_CLOSED && This->state != SPAS_CLOSED) { + waveOutReset(This->hwave.out); + /* Wait until all buffers are freed. */ + WaitForSingleObject(This->event, INFINITE); + if (waveOutClose(This->hwave.out) != MMSYSERR_NOERROR) { hr = SPERR_GENERIC_MMSYS_ERROR; @@ -776,7 +848,11 @@ static HRESULT mmaudio_create(IUnknown *outer, REFIID iid, void **obj, enum flow This->wfx->wBitsPerSample = 16; This->wfx->cbSize = 0; + This->pending_buf_count = 0; + This->event = CreateEventW(NULL, TRUE, TRUE, NULL); + InitializeCriticalSection(&This->cs); + InitializeCriticalSection(&This->pending_cs); hr = ISpMMSysAudio_QueryInterface(&This->ISpMMSysAudio_iface, iid, obj); ISpMMSysAudio_Release(&This->ISpMMSysAudio_iface); diff --git a/dlls/sapi/sapi_private.h b/dlls/sapi/sapi_private.h index 88b1a27516f..d0cd7669623 100644 --- a/dlls/sapi/sapi_private.h +++ b/dlls/sapi/sapi_private.h @@ -19,6 +19,30 @@ */ #include "wine/heap.h" +#include "wine/list.h" + +struct async_task +{ + struct list entry; + void (*proc)(struct async_task *); +}; + +struct async_queue +{ + BOOL init; + HANDLE wait; + HANDLE ready; + HANDLE empty; + HANDLE cancel; + struct list tasks; + CRITICAL_SECTION cs; +}; + +HRESULT async_start_queue(struct async_queue *queue); +void async_empty_queue(struct async_queue *queue); +void async_cancel_queue(struct async_queue *queue); +HRESULT async_queue_task(struct async_queue *queue, struct async_task *task); +void async_wait_queue_empty(struct async_queue *queue, DWORD timeout); HRESULT data_key_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN; HRESULT file_stream_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN; From fae56426a41d7a992426304c398df2041ebd8666 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Tue, 30 May 2023 23:58:32 -0400 Subject: [PATCH 2191/2777] sapi: Implement ISpMMSysAudio::Write. (cherry picked from commit ef730b6e41f04d2810bbc6cc869d9fdf1d789c1d) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/mmaudio.c | 53 +++++++++++++++++++++++++++++++++++-- dlls/sapi/tests/mmaudio.c | 55 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 102 insertions(+), 6 deletions(-) diff --git a/dlls/sapi/mmaudio.c b/dlls/sapi/mmaudio.c index add670ff3dc..dadd767b9a1 100644 --- a/dlls/sapi/mmaudio.c +++ b/dlls/sapi/mmaudio.c @@ -400,9 +400,58 @@ static HRESULT WINAPI mmsysaudio_Read(ISpMMSysAudio *iface, void *pv, ULONG cb, static HRESULT WINAPI mmsysaudio_Write(ISpMMSysAudio *iface, const void *pv, ULONG cb, ULONG *cb_written) { - FIXME("(%p, %p, %lu, %p): stub.\n", iface, pv, cb, cb_written); + struct mmaudio *This = impl_from_ISpMMSysAudio(iface); + HRESULT hr = S_OK; + WAVEHDR *buf; - return E_NOTIMPL; + TRACE("(%p, %p, %lu, %p).\n", iface, pv, cb, cb_written); + + if (This->flow != FLOW_OUT) + return STG_E_ACCESSDENIED; + + if (cb_written) + *cb_written = 0; + + EnterCriticalSection(&This->cs); + + if (This->state == SPAS_CLOSED || This->state == SPAS_STOP) + { + LeaveCriticalSection(&This->cs); + return SP_AUDIO_STOPPED; + } + + if (!(buf = heap_alloc(sizeof(WAVEHDR) + cb))) + { + LeaveCriticalSection(&This->cs); + return E_OUTOFMEMORY; + } + memcpy((char *)(buf + 1), pv, cb); + buf->lpData = (char *)(buf + 1); + buf->dwBufferLength = cb; + buf->dwFlags = 0; + + if (waveOutPrepareHeader(This->hwave.out, buf, sizeof(WAVEHDR)) != MMSYSERR_NOERROR) + { + LeaveCriticalSection(&This->cs); + heap_free(buf); + return E_FAIL; + } + + waveOutWrite(This->hwave.out, buf, sizeof(WAVEHDR)); + + EnterCriticalSection(&This->pending_cs); + ++This->pending_buf_count; + TRACE("pending_buf_count = %Iu\n", This->pending_buf_count); + LeaveCriticalSection(&This->pending_cs); + + ResetEvent(This->event); + + LeaveCriticalSection(&This->cs); + + if (cb_written) + *cb_written = cb; + + return hr; } static HRESULT WINAPI mmsysaudio_Seek(ISpMMSysAudio *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *new_pos) diff --git a/dlls/sapi/tests/mmaudio.c b/dlls/sapi/tests/mmaudio.c index 85a3570f490..38df432c181 100644 --- a/dlls/sapi/tests/mmaudio.c +++ b/dlls/sapi/tests/mmaudio.c @@ -163,7 +163,10 @@ static void test_audio_out(void) ISpMMSysAudio *mmaudio; GUID fmtid; WAVEFORMATEX *wfx = NULL; + WAVEFORMATEX wfx2; UINT devid; + char *buf = NULL; + ULONG written; HRESULT hr; if (waveOutGetNumDevs() == 0) { @@ -182,6 +185,8 @@ static void test_audio_out(void) ok(hr == S_OK, "got %#lx.\n", hr); ok(IsEqualGUID(&fmtid, &SPDFID_WaveFormatEx), "got %s.\n", wine_dbgstr_guid(&fmtid)); ok(wfx != NULL, "wfx == NULL.\n"); + ok(wfx->wFormatTag == WAVE_FORMAT_PCM, "got %u.\n", wfx->wFormatTag); + ok(wfx->cbSize == 0, "got %u.\n", wfx->cbSize); hr = ISpMMSysAudio_SetFormat(mmaudio, &fmtid, wfx); ok(hr == S_OK, "got %#lx.\n", hr); @@ -201,10 +206,12 @@ static void test_audio_out(void) hr = ISpMMSysAudio_SetFormat(mmaudio, &fmtid, wfx); ok(hr == S_OK, "got %#lx.\n", hr); - wfx->nChannels = wfx->nChannels == 1 ? 2 : 1; - wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nChannels * wfx->wBitsPerSample / 8; - wfx->nBlockAlign = wfx->nChannels * wfx->wBitsPerSample / 8; - hr = ISpMMSysAudio_SetFormat(mmaudio, &fmtid, wfx); + memcpy(&wfx2, wfx, sizeof(wfx2)); + wfx2.nChannels = wfx->nChannels == 1 ? 2 : 1; + wfx2.nAvgBytesPerSec = wfx2.nSamplesPerSec * wfx2.nChannels * wfx2.wBitsPerSample / 8; + wfx2.nBlockAlign = wfx2.nChannels * wfx2.wBitsPerSample / 8; + + hr = ISpMMSysAudio_SetFormat(mmaudio, &fmtid, &wfx2); ok(hr == SPERR_DEVICE_BUSY, "got %#lx.\n", hr); devid = 0xdeadbeef; @@ -215,7 +222,47 @@ static void test_audio_out(void) hr = ISpMMSysAudio_SetState(mmaudio, SPAS_CLOSED, 0); ok(hr == S_OK, "got %#lx.\n", hr); + buf = calloc(1, wfx->nAvgBytesPerSec); + ok(buf != NULL, "failed to allocate buffer.\n"); + + hr = ISpMMSysAudio_Write(mmaudio, buf, wfx->nAvgBytesPerSec, NULL); + ok(hr == SP_AUDIO_STOPPED, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_SetState(mmaudio, SPAS_STOP, 0); + todo_wine ok(hr == S_OK, "got %#lx.\n", hr); + if (hr == S_OK) + { + hr = ISpMMSysAudio_Write(mmaudio, buf, wfx->nAvgBytesPerSec, NULL); + ok(hr == SP_AUDIO_STOPPED, "got %#lx.\n", hr); + } + + hr = ISpMMSysAudio_SetState(mmaudio, SPAS_CLOSED, 0); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_SetState(mmaudio, SPAS_RUN, 0); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_Write(mmaudio, buf, wfx->nAvgBytesPerSec, NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + + Sleep(200); + + hr = ISpMMSysAudio_SetState(mmaudio, SPAS_CLOSED, 0); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = ISpMMSysAudio_SetState(mmaudio, SPAS_RUN, 0); + ok(hr == S_OK, "got %#lx.\n", hr); + + written = 0xdeadbeef; + hr = ISpMMSysAudio_Write(mmaudio, buf, wfx->nAvgBytesPerSec * 200 / 1000, &written); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(written == wfx->nAvgBytesPerSec * 200 / 1000, "got %lu.\n", written); + + hr = ISpMMSysAudio_SetState(mmaudio, SPAS_CLOSED, 0); + ok(hr == S_OK, "got %#lx.\n", hr); + CoTaskMemFree(wfx); + free(buf); ISpMMSysAudio_Release(mmaudio); } From 390f14f4a08d54bc20666a85b582dd3286e04574 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 31 May 2023 00:09:50 -0400 Subject: [PATCH 2192/2777] sapi: Implement ISpMMSysAudio::EventHandle. (cherry picked from commit 7cd77b2a7890e6fbe97f52fe852e7dfa4e403570) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/mmaudio.c | 6 ++++-- dlls/sapi/tests/mmaudio.c | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/dlls/sapi/mmaudio.c b/dlls/sapi/mmaudio.c index dadd767b9a1..d99bcb13672 100644 --- a/dlls/sapi/mmaudio.c +++ b/dlls/sapi/mmaudio.c @@ -728,9 +728,11 @@ static HRESULT WINAPI mmsysaudio_GetDefaultFormat(ISpMMSysAudio *iface, GUID *gu static HANDLE WINAPI mmsysaudio_EventHandle(ISpMMSysAudio *iface) { - FIXME("(%p): stub.\n", iface); + struct mmaudio *This = impl_from_ISpMMSysAudio(iface); - return NULL; + TRACE("(%p).\n", iface); + + return This->event; } static HRESULT WINAPI mmsysaudio_GetVolumeLevel(ISpMMSysAudio *iface, ULONG *level) diff --git a/dlls/sapi/tests/mmaudio.c b/dlls/sapi/tests/mmaudio.c index 38df432c181..7c72fb112bf 100644 --- a/dlls/sapi/tests/mmaudio.c +++ b/dlls/sapi/tests/mmaudio.c @@ -167,6 +167,8 @@ static void test_audio_out(void) UINT devid; char *buf = NULL; ULONG written; + DWORD start, end; + HANDLE event = NULL; HRESULT hr; if (waveOutGetNumDevs() == 0) { @@ -258,6 +260,20 @@ static void test_audio_out(void) ok(hr == S_OK, "got %#lx.\n", hr); ok(written == wfx->nAvgBytesPerSec * 200 / 1000, "got %lu.\n", written); + hr = ISpMMSysAudio_Write(mmaudio, buf, wfx->nAvgBytesPerSec * 200 / 1000, NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + + start = GetTickCount(); + + event = ISpMMSysAudio_EventHandle(mmaudio); + ok(event != NULL, "event == NULL.\n"); + + hr = WaitForSingleObject(event, 1000); + ok(hr == WAIT_OBJECT_0, "got %#lx.\n", hr); + + end = GetTickCount(); + ok(end - start <= 500, "waited for %lu ms.\n", end - start); + hr = ISpMMSysAudio_SetState(mmaudio, SPAS_CLOSED, 0); ok(hr == S_OK, "got %#lx.\n", hr); From 666fdd0b9443cc9bca696c18d15b925af93e09fb Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Tue, 20 Jun 2023 23:15:28 -0400 Subject: [PATCH 2193/2777] sapi: Implement ISpVoice::SetOutput. (cherry picked from commit 8c6bb3caee22c8dbaf157b4f2d608ff9a1ac3740) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/tts.c | 30 +++++++++++++++++++++++ dlls/sapi/tts.c | 56 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 83 insertions(+), 3 deletions(-) diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index 8303dfc6ebc..5d0cfd1bc1b 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -93,9 +93,39 @@ static void test_interfaces(void) ISpeechVoice_Release(speech_voice); } +static void test_spvoice(void) +{ + ISpVoice *voice; + ISpMMSysAudio *audio_out; + HRESULT hr; + + if (waveOutGetNumDevs() == 0) { + skip("no wave out devices.\n"); + return; + } + + hr = CoCreateInstance(&CLSID_SpVoice, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpVoice, (void **)&voice); + ok(hr == S_OK, "Failed to create SpVoice: %#lx.\n", hr); + + hr = ISpVoice_SetOutput(voice, NULL, TRUE); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = CoCreateInstance(&CLSID_SpMMAudioOut, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpMMSysAudio, (void **)&audio_out); + ok(hr == S_OK, "Failed to create SpMMAudioOut: %#lx.\n", hr); + + hr = ISpVoice_SetOutput(voice, (IUnknown *)audio_out, TRUE); + todo_wine ok(hr == S_FALSE, "got %#lx.\n", hr); + + ISpVoice_Release(voice); + ISpMMSysAudio_Release(audio_out); +} + START_TEST(tts) { CoInitialize(NULL); test_interfaces(); + test_spvoice(); CoUninitialize(); } diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index 9f60c70e6c4..bebda86f09d 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -40,6 +40,9 @@ struct speech_voice ISpVoice ISpVoice_iface; IConnectionPointContainer IConnectionPointContainer_iface; LONG ref; + + ISpStreamFormat *output; + CRITICAL_SECTION cs; }; static inline struct speech_voice *impl_from_ISpeechVoice(ISpeechVoice *iface) @@ -102,6 +105,9 @@ static ULONG WINAPI speech_voice_Release(ISpeechVoice *iface) if (!ref) { + if (This->output) ISpStreamFormat_Release(This->output); + DeleteCriticalSection(&This->cs); + heap_free(This); } @@ -515,11 +521,51 @@ static HRESULT WINAPI spvoice_GetInfo(ISpVoice *iface, SPEVENTSOURCEINFO *info) return E_NOTIMPL; } -static HRESULT WINAPI spvoice_SetOutput(ISpVoice *iface, IUnknown *unk, BOOL changes) +static HRESULT WINAPI spvoice_SetOutput(ISpVoice *iface, IUnknown *unk, BOOL allow_format_changes) { - FIXME("(%p, %p, %d): stub.\n", iface, unk, changes); + struct speech_voice *This = impl_from_ISpVoice(iface); + ISpStreamFormat *stream = NULL; + ISpObjectToken *token = NULL; + HRESULT hr; - return E_NOTIMPL; + TRACE("(%p, %p, %d).\n", iface, unk, allow_format_changes); + + if (!allow_format_changes) + FIXME("ignoring allow_format_changes = FALSE.\n"); + + if (!unk) + { + /* TODO: Create the default SpAudioOut token here once SpMMAudioEnum is implemented. */ + if (FAILED(hr = CoCreateInstance(&CLSID_SpMMAudioOut, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpStreamFormat, (void **)&stream))) + return hr; + } + else + { + if (FAILED(IUnknown_QueryInterface(unk, &IID_ISpStreamFormat, (void **)&stream))) + { + if (FAILED(IUnknown_QueryInterface(unk, &IID_ISpObjectToken, (void **)&token))) + return E_INVALIDARG; + } + } + + if (!stream) + { + hr = ISpObjectToken_CreateInstance(token, NULL, CLSCTX_ALL, &IID_ISpStreamFormat, (void **)&stream); + ISpObjectToken_Release(token); + if (FAILED(hr)) + return hr; + } + + EnterCriticalSection(&This->cs); + + if (This->output) + ISpStreamFormat_Release(This->output); + This->output = stream; + + LeaveCriticalSection(&This->cs); + + return S_OK; } static HRESULT WINAPI spvoice_GetOutputObjectToken(ISpVoice *iface, ISpObjectToken **token) @@ -798,6 +844,10 @@ HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj) This->IConnectionPointContainer_iface.lpVtbl = &container_vtbl; This->ref = 1; + This->output = NULL; + + InitializeCriticalSection(&This->cs); + hr = ISpeechVoice_QueryInterface(&This->ISpeechVoice_iface, iid, obj); ISpeechVoice_Release(&This->ISpeechVoice_iface); From 64c8de642d21a7d235c43463d74ddfe72834fa6d Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 21 Jun 2023 01:29:55 -0400 Subject: [PATCH 2194/2777] sapi: Implement ISpVoice::Set/GetVoice. (cherry picked from commit 17635423938d3041b806506f1c4a9caff4dd1018) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/tts.c | 31 +++++++++++++++ dlls/sapi/tts.c | 93 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 120 insertions(+), 4 deletions(-) diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index 5d0cfd1bc1b..5141bc27b8c 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -97,6 +97,9 @@ static void test_spvoice(void) { ISpVoice *voice; ISpMMSysAudio *audio_out; + ISpObjectTokenCategory *token_cat; + ISpObjectToken *token; + WCHAR *token_id = NULL, *default_token_id = NULL; HRESULT hr; if (waveOutGetNumDevs() == 0) { @@ -118,6 +121,34 @@ static void test_spvoice(void) hr = ISpVoice_SetOutput(voice, (IUnknown *)audio_out, TRUE); todo_wine ok(hr == S_FALSE, "got %#lx.\n", hr); + hr = ISpVoice_SetVoice(voice, NULL); + todo_wine ok(hr == S_OK, "got %#lx.\n", hr); + + hr = ISpVoice_GetVoice(voice, &token); + todo_wine ok(hr == S_OK, "got %#lx.\n", hr); + + if (SUCCEEDED(hr)) + { + hr = ISpObjectToken_GetId(token, &token_id); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = CoCreateInstance(&CLSID_SpObjectTokenCategory, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpObjectTokenCategory, (void **)&token_cat); + ok(hr == S_OK, "Failed to create SpObjectTokenCategory: %#lx.\n", hr); + + hr = ISpObjectTokenCategory_SetId(token_cat, SPCAT_VOICES, FALSE); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = ISpObjectTokenCategory_GetDefaultTokenId(token_cat, &default_token_id); + ok(hr == S_OK, "got %#lx.\n", hr); + + ok(!wcscmp(token_id, default_token_id), "token_id != default_token_id\n"); + + CoTaskMemFree(token_id); + CoTaskMemFree(default_token_id); + ISpObjectToken_Release(token); + ISpObjectTokenCategory_Release(token_cat); + } + ISpVoice_Release(voice); ISpMMSysAudio_Release(audio_out); } diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index bebda86f09d..b7af24790e0 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -42,6 +42,7 @@ struct speech_voice LONG ref; ISpStreamFormat *output; + ISpTTSEngine *engine; CRITICAL_SECTION cs; }; @@ -60,6 +61,41 @@ static inline struct speech_voice *impl_from_IConnectionPointContainer(IConnecti return CONTAINING_RECORD(iface, struct speech_voice, IConnectionPointContainer_iface); } +static HRESULT create_default_token(const WCHAR *cat_id, ISpObjectToken **token) +{ + ISpObjectTokenCategory *cat; + WCHAR *default_token_id = NULL; + HRESULT hr; + + TRACE("(%s, %p).\n", debugstr_w(cat_id), token); + + if (FAILED(hr = CoCreateInstance(&CLSID_SpObjectTokenCategory, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpObjectTokenCategory, (void **)&cat))) + return hr; + + if (FAILED(hr = ISpObjectTokenCategory_SetId(cat, cat_id, FALSE)) || + FAILED(hr = ISpObjectTokenCategory_GetDefaultTokenId(cat, &default_token_id))) + { + ISpObjectTokenCategory_Release(cat); + return hr; + } + ISpObjectTokenCategory_Release(cat); + + if (FAILED(hr = CoCreateInstance(&CLSID_SpObjectToken, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpObjectToken, (void **)token))) + goto done; + + if (FAILED(hr = ISpObjectToken_SetId(*token, NULL, default_token_id, FALSE))) + { + ISpObjectToken_Release(*token); + *token = NULL; + } + +done: + CoTaskMemFree(default_token_id); + return hr; +} + /* ISpeechVoice interface */ static HRESULT WINAPI speech_voice_QueryInterface(ISpeechVoice *iface, REFIID iid, void **obj) { @@ -106,6 +142,7 @@ static ULONG WINAPI speech_voice_Release(ISpeechVoice *iface) if (!ref) { if (This->output) ISpStreamFormat_Release(This->output); + if (This->engine) ISpTTSEngine_Release(This->engine); DeleteCriticalSection(&This->cs); heap_free(This); @@ -598,16 +635,63 @@ static HRESULT WINAPI spvoice_Resume(ISpVoice *iface) static HRESULT WINAPI spvoice_SetVoice(ISpVoice *iface, ISpObjectToken *token) { - FIXME("(%p, %p): stub.\n", iface, token); + struct speech_voice *This = impl_from_ISpVoice(iface); + ISpTTSEngine *engine; + HRESULT hr; - return E_NOTIMPL; + + TRACE("(%p, %p).\n", iface, token); + + if (!token) + { + if (FAILED(hr = create_default_token(SPCAT_VOICES, &token))) + return hr; + } + + hr = ISpObjectToken_CreateInstance(token, NULL, CLSCTX_ALL, &IID_ISpTTSEngine, (void **)&engine); + ISpObjectToken_Release(token); + if (FAILED(hr)) + return hr; + + EnterCriticalSection(&This->cs); + + if (This->engine) + ISpTTSEngine_Release(This->engine); + This->engine = engine; + + LeaveCriticalSection(&This->cs); + + return S_OK; } static HRESULT WINAPI spvoice_GetVoice(ISpVoice *iface, ISpObjectToken **token) { - FIXME("(%p, %p): stub.\n", iface, token); + struct speech_voice *This = impl_from_ISpVoice(iface); + ISpObjectWithToken *engine_token_iface; + HRESULT hr; + + TRACE("(%p, %p).\n", iface, token); - return token_create(NULL, &IID_ISpObjectToken, (void **)token); + if (!token) + return E_POINTER; + + EnterCriticalSection(&This->cs); + + if (!This->engine) + { + LeaveCriticalSection(&This->cs); + return create_default_token(SPCAT_VOICES, token); + } + + if (SUCCEEDED(hr = ISpTTSEngine_QueryInterface(This->engine, &IID_ISpObjectWithToken, (void **)&engine_token_iface))) + { + hr = ISpObjectWithToken_GetObjectToken(engine_token_iface, token); + ISpObjectWithToken_Release(engine_token_iface); + } + + LeaveCriticalSection(&This->cs); + + return hr; } static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWORD flags, ULONG *number) @@ -845,6 +929,7 @@ HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj) This->ref = 1; This->output = NULL; + This->engine = NULL; InitializeCriticalSection(&This->cs); From 3b872e1c4b5281163d6b29b2f6eb01bd6924c888 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 21 Jun 2023 01:58:58 -0400 Subject: [PATCH 2195/2777] sapi: Implement ISpVoice::Set/GetRate. (cherry picked from commit 5793c57cbc8ff1e2d58af7d495272244bf094ff2) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/tts.c | 30 ++++++++++++++++++++++++++++++ dlls/sapi/tts.c | 26 ++++++++++++++++++++------ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index 5141bc27b8c..8564d049949 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -100,6 +100,7 @@ static void test_spvoice(void) ISpObjectTokenCategory *token_cat; ISpObjectToken *token; WCHAR *token_id = NULL, *default_token_id = NULL; + LONG rate; HRESULT hr; if (waveOutGetNumDevs() == 0) { @@ -149,6 +150,35 @@ static void test_spvoice(void) ISpObjectTokenCategory_Release(token_cat); } + rate = 0xdeadbeef; + hr = ISpVoice_GetRate(voice, &rate); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(rate == 0, "rate = %ld\n", rate); + + hr = ISpVoice_SetRate(voice, 1); + ok(hr == S_OK, "got %#lx.\n", hr); + + rate = 0xdeadbeef; + hr = ISpVoice_GetRate(voice, &rate); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(rate == 1, "rate = %ld\n", rate); + + hr = ISpVoice_SetRate(voice, -1000); + ok(hr == S_OK, "got %#lx.\n", hr); + + rate = 0xdeadbeef; + hr = ISpVoice_GetRate(voice, &rate); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(rate == -1000, "rate = %ld\n", rate); + + hr = ISpVoice_SetRate(voice, 1000); + ok(hr == S_OK, "got %#lx.\n", hr); + + rate = 0xdeadbeef; + hr = ISpVoice_GetRate(voice, &rate); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(rate == 1000, "rate = %ld\n", rate); + ISpVoice_Release(voice); ISpMMSysAudio_Release(audio_out); } diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index b7af24790e0..32d3aa31335 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -43,6 +43,7 @@ struct speech_voice ISpStreamFormat *output; ISpTTSEngine *engine; + LONG rate; CRITICAL_SECTION cs; }; @@ -750,18 +751,30 @@ static HRESULT WINAPI spvoice_GetAlertBoundary(ISpVoice *iface, SPEVENTENUM *bou return E_NOTIMPL; } -static HRESULT WINAPI spvoice_SetRate(ISpVoice *iface, LONG adjust) +static HRESULT WINAPI spvoice_SetRate(ISpVoice *iface, LONG rate) { - FIXME("(%p, %ld): stub.\n", iface, adjust); + struct speech_voice *This = impl_from_ISpVoice(iface); - return E_NOTIMPL; + TRACE("(%p, %ld).\n", iface, rate); + + EnterCriticalSection(&This->cs); + This->rate = rate; + LeaveCriticalSection(&This->cs); + + return S_OK; } -static HRESULT WINAPI spvoice_GetRate(ISpVoice *iface, LONG *adjust) +static HRESULT WINAPI spvoice_GetRate(ISpVoice *iface, LONG *rate) { - FIXME("(%p, %p): stub.\n", iface, adjust); + struct speech_voice *This = impl_from_ISpVoice(iface); - return E_NOTIMPL; + TRACE("(%p, %p).\n", iface, rate); + + EnterCriticalSection(&This->cs); + *rate = This->rate; + LeaveCriticalSection(&This->cs); + + return S_OK; } static HRESULT WINAPI spvoice_SetVolume(ISpVoice *iface, USHORT volume) @@ -930,6 +943,7 @@ HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj) This->output = NULL; This->engine = NULL; + This->rate = 0; InitializeCriticalSection(&This->cs); From d1826d55a9b640fce7c6e7f34513f00ca5d877e5 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 21 Jun 2023 02:11:02 -0400 Subject: [PATCH 2196/2777] sapi: Implement ISpVoice::Set/GetVolume. (cherry picked from commit 02081ed6ff142628c556a8d17f3caa355e0b821f) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/tts.c | 25 +++++++++++++++++++++++++ dlls/sapi/tts.c | 25 +++++++++++++++++++++---- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index 8564d049949..534e5842f39 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -101,6 +101,7 @@ static void test_spvoice(void) ISpObjectToken *token; WCHAR *token_id = NULL, *default_token_id = NULL; LONG rate; + USHORT volume; HRESULT hr; if (waveOutGetNumDevs() == 0) { @@ -179,6 +180,30 @@ static void test_spvoice(void) ok(hr == S_OK, "got %#lx.\n", hr); ok(rate == 1000, "rate = %ld\n", rate); + volume = 0xbeef; + hr = ISpVoice_GetVolume(voice, &volume); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(volume == 100, "volume = %d\n", volume); + + hr = ISpVoice_SetVolume(voice, 0); + ok(hr == S_OK, "got %#lx.\n", hr); + + volume = 0xbeef; + hr = ISpVoice_GetVolume(voice, &volume); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(volume == 0, "volume = %d\n", volume); + + hr = ISpVoice_SetVolume(voice, 100); + ok(hr == S_OK, "got %#lx.\n", hr); + + volume = 0xbeef; + hr = ISpVoice_GetVolume(voice, &volume); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(volume == 100, "volume = %d\n", volume); + + hr = ISpVoice_SetVolume(voice, 101); + ok(hr == E_INVALIDARG, "got %#lx.\n", hr); + ISpVoice_Release(voice); ISpMMSysAudio_Release(audio_out); } diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index 32d3aa31335..147734cc9a9 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -43,6 +43,7 @@ struct speech_voice ISpStreamFormat *output; ISpTTSEngine *engine; + USHORT volume; LONG rate; CRITICAL_SECTION cs; }; @@ -779,16 +780,31 @@ static HRESULT WINAPI spvoice_GetRate(ISpVoice *iface, LONG *rate) static HRESULT WINAPI spvoice_SetVolume(ISpVoice *iface, USHORT volume) { - FIXME("(%p, %d): stub.\n", iface, volume); + struct speech_voice *This = impl_from_ISpVoice(iface); - return E_NOTIMPL; + TRACE("(%p, %d).\n", iface, volume); + + if (volume > 100) + return E_INVALIDARG; + + EnterCriticalSection(&This->cs); + This->volume = volume; + LeaveCriticalSection(&This->cs); + + return S_OK; } static HRESULT WINAPI spvoice_GetVolume(ISpVoice *iface, USHORT *volume) { - FIXME("(%p, %p): stub.\n", iface, volume); + struct speech_voice *This = impl_from_ISpVoice(iface); - return E_NOTIMPL; + TRACE("(%p, %p).\n", iface, volume); + + EnterCriticalSection(&This->cs); + *volume = This->volume; + LeaveCriticalSection(&This->cs); + + return S_OK; } static HRESULT WINAPI spvoice_WaitUntilDone(ISpVoice *iface, ULONG timeout) @@ -943,6 +959,7 @@ HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj) This->output = NULL; This->engine = NULL; + This->volume = 100; This->rate = 0; InitializeCriticalSection(&This->cs); From 89a5c4a59b6c1571ae508160047c6d9c57197f94 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Thu, 13 Jul 2023 19:15:24 -0400 Subject: [PATCH 2197/2777] sapi: Invoke AddRef in mmaudio SetObjectToken. (cherry picked from commit 5fccc408c66717166b42f6ec5dd508b73193b0aa) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/mmaudio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/sapi/mmaudio.c b/dlls/sapi/mmaudio.c index d99bcb13672..7452d9a7257 100644 --- a/dlls/sapi/mmaudio.c +++ b/dlls/sapi/mmaudio.c @@ -293,6 +293,7 @@ static HRESULT WINAPI objwithtoken_SetObjectToken(ISpObjectWithToken *iface, ISp if (This->token) return SPERR_ALREADY_INITIALIZED; + ISpObjectToken_AddRef(token); This->token = token; return S_OK; } From 2d1269796aeb7d4bb59b85828ae7cbef5e547d0f Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Thu, 13 Jul 2023 19:20:13 -0400 Subject: [PATCH 2198/2777] sapi: Invoke AddRef in ISpVoice::SetVoice. (cherry picked from commit 9941a716493a4049ef85c691b851513be10dd99d) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tts.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index 147734cc9a9..b0b3bbd2eff 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -641,7 +641,6 @@ static HRESULT WINAPI spvoice_SetVoice(ISpVoice *iface, ISpObjectToken *token) ISpTTSEngine *engine; HRESULT hr; - TRACE("(%p, %p).\n", iface, token); if (!token) @@ -649,6 +648,8 @@ static HRESULT WINAPI spvoice_SetVoice(ISpVoice *iface, ISpObjectToken *token) if (FAILED(hr = create_default_token(SPCAT_VOICES, &token))) return hr; } + else + ISpObjectToken_AddRef(token); hr = ISpObjectToken_CreateInstance(token, NULL, CLSCTX_ALL, &IID_ISpTTSEngine, (void **)&engine); ISpObjectToken_Release(token); From 001d9f7cc58a0fd2b3c496164e72ded062c9b238 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Fri, 14 Jul 2023 14:10:22 -0400 Subject: [PATCH 2199/2777] sapi/tests: Fix intermittent duration test failure in mmaudio. (cherry picked from commit bc479f2a19d3f094a7002c74302f200a9c5bb993) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/mmaudio.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dlls/sapi/tests/mmaudio.c b/dlls/sapi/tests/mmaudio.c index 7c72fb112bf..a990430d784 100644 --- a/dlls/sapi/tests/mmaudio.c +++ b/dlls/sapi/tests/mmaudio.c @@ -167,7 +167,7 @@ static void test_audio_out(void) UINT devid; char *buf = NULL; ULONG written; - DWORD start, end; + DWORD start, duration; HANDLE event = NULL; HRESULT hr; @@ -256,6 +256,7 @@ static void test_audio_out(void) ok(hr == S_OK, "got %#lx.\n", hr); written = 0xdeadbeef; + start = GetTickCount(); hr = ISpMMSysAudio_Write(mmaudio, buf, wfx->nAvgBytesPerSec * 200 / 1000, &written); ok(hr == S_OK, "got %#lx.\n", hr); ok(written == wfx->nAvgBytesPerSec * 200 / 1000, "got %lu.\n", written); @@ -263,7 +264,8 @@ static void test_audio_out(void) hr = ISpMMSysAudio_Write(mmaudio, buf, wfx->nAvgBytesPerSec * 200 / 1000, NULL); ok(hr == S_OK, "got %#lx.\n", hr); - start = GetTickCount(); + hr = ISpMMSysAudio_Commit(mmaudio, STGC_DEFAULT); + todo_wine ok(hr == S_OK, "got %#lx.\n", hr); event = ISpMMSysAudio_EventHandle(mmaudio); ok(event != NULL, "event == NULL.\n"); @@ -271,8 +273,8 @@ static void test_audio_out(void) hr = WaitForSingleObject(event, 1000); ok(hr == WAIT_OBJECT_0, "got %#lx.\n", hr); - end = GetTickCount(); - ok(end - start <= 500, "waited for %lu ms.\n", end - start); + duration = GetTickCount() - start; + ok(duration > 200 && duration < 800, "took %lu ms.\n", duration); hr = ISpMMSysAudio_SetState(mmaudio, SPAS_CLOSED, 0); ok(hr == S_OK, "got %#lx.\n", hr); From e76d838319fe6c5edb36237714025a31b9234d69 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Fri, 14 Jul 2023 14:17:26 -0400 Subject: [PATCH 2200/2777] sapi/tests: Fix ISpObjectToken::CreateInstance E_ACCESSDENIED error. (cherry picked from commit 327667a620b1d0c9f8dd47b9a85343a7badd4b20) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/token.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/dlls/sapi/tests/token.c b/dlls/sapi/tests/token.c index 5a3bc0e340e..8befd98c2a5 100644 --- a/dlls/sapi/tests/token.c +++ b/dlls/sapi/tests/token.c @@ -601,7 +601,7 @@ static IClassFactory test_class_cf = { &ClassFactoryVtbl }; static void test_object_token(void) { - static const WCHAR test_token_id[] = L"HKEY_CURRENT_USER\\Software\\Winetest\\sapi\\TestToken"; + static const WCHAR test_token_id[] = L"HKEY_LOCAL_MACHINE\\Software\\Wine\\Winetest\\sapi\\TestToken"; ISpObjectToken *token; ISpDataKey *sub_key; @@ -742,7 +742,12 @@ static void test_object_token(void) ok( hr == S_OK, "got %08lx\n", hr ); hr = ISpObjectToken_SetId( token, NULL, test_token_id, TRUE ); - ok( hr == S_OK, "got %08lx\n", hr ); + ok( hr == S_OK || broken(hr == E_ACCESSDENIED) /* win1064_adm */, "got %08lx\n", hr ); + if (hr == E_ACCESSDENIED) { + win_skip( "token SetId access denied\n" ); + ISpObjectToken_Release( token ); + return; + } hr = ISpObjectToken_CreateKey( token, L"Attributes", &sub_key ); ok( hr == S_OK, "got %08lx\n", hr ); @@ -763,10 +768,6 @@ static void test_object_token(void) test_class_token = NULL; hr = ISpObjectToken_CreateInstance( token, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&obj ); - if ( hr == E_ACCESSDENIED ) { - win_skip( "ISpObjectToken_CreateInstance returned E_ACCESSDENIED\n" ); - return; - } ok( hr == S_OK, "got %08lx\n", hr ); ok( test_class_token != NULL, "test_class_token not set\n" ); From 4de68838395c643460c292ab8fd533b12fa0ff67 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 28 Jun 2023 02:10:48 -0400 Subject: [PATCH 2201/2777] include: Fix ISpTTSEngineSite::GetActions return type. (cherry picked from commit 5f3dee9702f965c1906f7b466fd18451a0a1a87b) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- include/sapiddk.idl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sapiddk.idl b/include/sapiddk.idl index 46aebbb9a12..8f9abf4e117 100644 --- a/include/sapiddk.idl +++ b/include/sapiddk.idl @@ -72,7 +72,7 @@ typedef enum SPVESACTIONS ] interface ISpTTSEngineSite : ISpEventSink { - HRESULT GetActions(); + DWORD GetActions(); HRESULT Write([in] const void *pBuff, [in] ULONG cb, [out] ULONG *pcbWritten); From 9ac3fb004ca6232d2f9da5b8e9170bfb2114e428 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 19 Jul 2023 12:46:04 -0400 Subject: [PATCH 2202/2777] sapi: Handle queue not initialized in async_empty_queue. (cherry picked from commit 4bfd0a2370a24c2038e03454ca6511534aac0d20) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/async.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/sapi/async.c b/dlls/sapi/async.c index 57ae89ad723..e09c6c64f9a 100644 --- a/dlls/sapi/async.c +++ b/dlls/sapi/async.c @@ -52,6 +52,8 @@ void async_empty_queue(struct async_queue *queue) { struct async_task *task, *next; + if (!queue->init) return; + EnterCriticalSection(&queue->cs); LIST_FOR_EACH_ENTRY_SAFE(task, next, &queue->tasks, struct async_task, entry) { From 397e8895a0687caab19bfea1fffa12ba44350054 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 19 Jul 2023 12:47:00 -0400 Subject: [PATCH 2203/2777] sapi: Reset empty event after queuing a task in async_queue_task. (cherry picked from commit 9d407a111781548db23d1a38ca61fd6b8f50fdf8) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/async.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/sapi/async.c b/dlls/sapi/async.c index e09c6c64f9a..491ca657c1a 100644 --- a/dlls/sapi/async.c +++ b/dlls/sapi/async.c @@ -165,6 +165,7 @@ HRESULT async_queue_task(struct async_queue *queue, struct async_task *task) list_add_tail(&queue->tasks, &task->entry); LeaveCriticalSection(&queue->cs); + ResetEvent(queue->empty); SetEvent(queue->wait); return S_OK; From fdfcfa1d50e3f0631307ddef92813450e10b7a34 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 19 Jul 2023 12:57:49 -0400 Subject: [PATCH 2204/2777] sapi: Implement ISpVoice::Speak SPF_PURGEBEFORESPEAK. Also introduce an async task queue. (cherry picked from commit f9dff8a6fa759cd1a2d9f32dcafe9588e80a5469) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/tts.c | 9 +++++++++ dlls/sapi/tts.c | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index 534e5842f39..586869aa33e 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -102,6 +102,7 @@ static void test_spvoice(void) WCHAR *token_id = NULL, *default_token_id = NULL; LONG rate; USHORT volume; + ULONG stream_num; HRESULT hr; if (waveOutGetNumDevs() == 0) { @@ -204,6 +205,14 @@ static void test_spvoice(void) hr = ISpVoice_SetVolume(voice, 101); ok(hr == E_INVALIDARG, "got %#lx.\n", hr); + hr = ISpVoice_Speak(voice, NULL, SPF_PURGEBEFORESPEAK, NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + + stream_num = 0xdeadbeef; + hr = ISpVoice_Speak(voice, NULL, SPF_PURGEBEFORESPEAK, &stream_num); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(stream_num == 0xdeadbeef, "got %lu.\n", stream_num); + ISpVoice_Release(voice); ISpMMSysAudio_Release(audio_out); } diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index b0b3bbd2eff..98d74a11f2d 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -45,6 +45,7 @@ struct speech_voice ISpTTSEngine *engine; USHORT volume; LONG rate; + struct async_queue queue; CRITICAL_SECTION cs; }; @@ -143,6 +144,7 @@ static ULONG WINAPI speech_voice_Release(ISpeechVoice *iface) if (!ref) { + async_cancel_queue(&This->queue); if (This->output) ISpStreamFormat_Release(This->output); if (This->engine) ISpTTSEngine_Release(This->engine); DeleteCriticalSection(&This->cs); @@ -697,9 +699,39 @@ static HRESULT WINAPI spvoice_GetVoice(ISpVoice *iface, ISpObjectToken **token) return hr; } -static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWORD flags, ULONG *number) +static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWORD flags, ULONG *stream_num_out) { - FIXME("(%p, %p, %#lx, %p): stub.\n", iface, contents, flags, number); + struct speech_voice *This = impl_from_ISpVoice(iface); + + FIXME("(%p, %p, %#lx, %p): semi-stub.\n", iface, contents, flags, stream_num_out); + + if (flags & ~SPF_PURGEBEFORESPEAK) + { + FIXME("flags %#lx not implemented.\n", flags & ~SPF_PURGEBEFORESPEAK); + return E_NOTIMPL; + } + + if (flags & SPF_PURGEBEFORESPEAK) + { + ISpAudio *audio; + + EnterCriticalSection(&This->cs); + + if (This->output && SUCCEEDED(ISpStreamFormat_QueryInterface(This->output, &IID_ISpAudio, (void **)&audio))) + { + ISpAudio_SetState(audio, SPAS_CLOSED, 0); + ISpAudio_Release(audio); + } + + LeaveCriticalSection(&This->cs); + + async_empty_queue(&This->queue); + + if (!contents || !*contents) + return S_OK; + } + else if (!contents) + return E_POINTER; return E_NOTIMPL; } @@ -962,6 +994,7 @@ HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj) This->engine = NULL; This->volume = 100; This->rate = 0; + memset(&This->queue, 0, sizeof(This->queue)); InitializeCriticalSection(&This->cs); From a1174b3a36c7bd279b4ffd8d98c45686d6c6e38f Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 19 Jul 2023 13:49:09 -0400 Subject: [PATCH 2205/2777] sapi: Partially implement ISpVoice::Speak SPF_ASYNC. (cherry picked from commit a234bbc748a0e02b00f059e739dc3ca8135264a0) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tts.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 3 deletions(-) diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index 98d74a11f2d..bc4a225a3f5 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -699,15 +699,34 @@ static HRESULT WINAPI spvoice_GetVoice(ISpVoice *iface, ISpObjectToken **token) return hr; } +struct speak_task +{ + struct async_task task; + + struct speech_voice *voice; + SPVTEXTFRAG *frag_list; + DWORD flags; +}; + +static void speak_proc(struct async_task *task) +{ + FIXME("(%p): stub.\n", task); +} + static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWORD flags, ULONG *stream_num_out) { struct speech_voice *This = impl_from_ISpVoice(iface); + SPVTEXTFRAG *frag; + struct speak_task *speak_task = NULL; + size_t contents_len, contents_size; + HRESULT hr; FIXME("(%p, %p, %#lx, %p): semi-stub.\n", iface, contents, flags, stream_num_out); - if (flags & ~SPF_PURGEBEFORESPEAK) + flags &= ~SPF_IS_NOT_XML; + if (flags & ~(SPF_ASYNC | SPF_PURGEBEFORESPEAK | SPF_NLP_SPEAK_PUNC)) { - FIXME("flags %#lx not implemented.\n", flags & ~SPF_PURGEBEFORESPEAK); + FIXME("flags %#lx not implemented.\n", flags & ~(SPF_ASYNC | SPF_PURGEBEFORESPEAK | SPF_NLP_SPEAK_PUNC)); return E_NOTIMPL; } @@ -733,7 +752,57 @@ static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWOR else if (!contents) return E_POINTER; - return E_NOTIMPL; + if (!(flags & SPF_ASYNC)) + { + FIXME("Synchronous Speak not implemented.\n"); + return E_NOTIMPL; + } + + contents_len = wcslen(contents); + contents_size = sizeof(WCHAR) * (contents_len + 1); + + if (!This->output) + { + /* Create a new output stream with the default output. */ + if (FAILED(hr = ISpVoice_SetOutput(iface, NULL, TRUE))) + return hr; + } + + if (!This->engine) + { + /* Create a new engine with the default voice. */ + if (FAILED(hr = ISpVoice_SetVoice(iface, NULL))) + return hr; + } + + if (!(frag = heap_alloc(sizeof(*frag) + contents_size))) + return E_OUTOFMEMORY; + memset(frag, 0, sizeof(*frag)); + memcpy(frag + 1, contents, contents_size); + frag->State.eAction = SPVA_Speak; + frag->State.Volume = 100; + frag->pTextStart = (WCHAR *)(frag + 1); + frag->ulTextLen = contents_len; + frag->ulTextSrcOffset = 0; + speak_task = heap_alloc(sizeof(*speak_task)); + + speak_task->task.proc = speak_proc; + speak_task->voice = This; + speak_task->frag_list = frag; + speak_task->flags = flags & SPF_NLP_SPEAK_PUNC; + + if (FAILED(hr = async_queue_task(&This->queue, (struct async_task *)speak_task))) + { + WARN("Failed to queue task: %#lx.\n", hr); + goto fail; + } + + if (flags & SPF_ASYNC) + return S_OK; +fail: + heap_free(frag); + heap_free(speak_task); + return hr; } static HRESULT WINAPI spvoice_SpeakStream(ISpVoice *iface, IStream *stream, DWORD flags, ULONG *number) From 654a310ee1cb2beb9994cc0597da55e158c4b595 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 19 Jul 2023 13:17:43 -0400 Subject: [PATCH 2206/2777] sapi: Implement synchronous ISpVoice::Speak. (cherry picked from commit 86a31446830c8dcadc558b6793b0c339d709d709) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tts.c | 49 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index bc4a225a3f5..fb2fc9b9991 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -699,9 +699,16 @@ static HRESULT WINAPI spvoice_GetVoice(ISpVoice *iface, ISpObjectToken **token) return hr; } +struct async_result +{ + HANDLE done; + HRESULT hr; +}; + struct speak_task { struct async_task task; + struct async_result *result; struct speech_voice *voice; SPVTEXTFRAG *frag_list; @@ -710,7 +717,15 @@ struct speak_task static void speak_proc(struct async_task *task) { + struct speak_task *speak_task = (struct speak_task *)task; + FIXME("(%p): stub.\n", task); + + if (speak_task->result) + { + speak_task->result->hr = E_NOTIMPL; + SetEvent(speak_task->result->done); + } } static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWORD flags, ULONG *stream_num_out) @@ -718,6 +733,7 @@ static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWOR struct speech_voice *This = impl_from_ISpVoice(iface); SPVTEXTFRAG *frag; struct speak_task *speak_task = NULL; + struct async_result *result = NULL; size_t contents_len, contents_size; HRESULT hr; @@ -752,12 +768,6 @@ static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWOR else if (!contents) return E_POINTER; - if (!(flags & SPF_ASYNC)) - { - FIXME("Synchronous Speak not implemented.\n"); - return E_NOTIMPL; - } - contents_len = wcslen(contents); contents_size = sizeof(WCHAR) * (contents_len + 1); @@ -787,10 +797,23 @@ static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWOR speak_task = heap_alloc(sizeof(*speak_task)); speak_task->task.proc = speak_proc; + speak_task->result = NULL; speak_task->voice = This; speak_task->frag_list = frag; speak_task->flags = flags & SPF_NLP_SPEAK_PUNC; + if (!(flags & SPF_ASYNC)) + { + if (!(result = heap_alloc(sizeof(*result)))) + { + hr = E_OUTOFMEMORY; + goto fail; + } + result->hr = E_FAIL; + result->done = CreateEventW(NULL, FALSE, FALSE, NULL); + speak_task->result = result; + } + if (FAILED(hr = async_queue_task(&This->queue, (struct async_task *)speak_task))) { WARN("Failed to queue task: %#lx.\n", hr); @@ -799,9 +822,23 @@ static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWOR if (flags & SPF_ASYNC) return S_OK; + else + { + WaitForSingleObject(result->done, INFINITE); + hr = result->hr; + CloseHandle(result->done); + heap_free(result); + return hr; + } + fail: heap_free(frag); heap_free(speak_task); + if (result) + { + CloseHandle(result->done); + heap_free(result); + } return hr; } From b9ae99cb92012d6c0767ef447760c66fc5b2d3ea Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 19 Jul 2023 13:19:18 -0400 Subject: [PATCH 2207/2777] sapi: Introduce ISpTTSEngineSite stub. (cherry picked from commit 68660958f63dce365125e0b4d50479d7788e43e2) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/tts.c | 5 ++ dlls/sapi/tts.c | 173 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+) diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index 586869aa33e..ffe2e5f73a7 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -38,6 +38,7 @@ static void test_interfaces(void) { ISpeechVoice *speech_voice, *speech_voice2; IConnectionPointContainer *container; + ISpTTSEngineSite *site; ISpVoice *spvoice, *spvoice2; IDispatch *dispatch; IUnknown *unk; @@ -90,6 +91,10 @@ static void test_interfaces(void) EXPECT_REF(container, 2); IConnectionPointContainer_Release(container); + hr = ISpeechVoice_QueryInterface(speech_voice, &IID_ISpTTSEngineSite, + (void **)&site); + ok(hr == E_NOINTERFACE, "ISpeechVoice_QueryInterface for ISpTTSEngineSite returned: %#lx.\n", hr); + ISpeechVoice_Release(speech_voice); } diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index fb2fc9b9991..7ec5aa059d9 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -43,6 +43,7 @@ struct speech_voice ISpStreamFormat *output; ISpTTSEngine *engine; + LONG cur_stream_num; USHORT volume; LONG rate; struct async_queue queue; @@ -64,6 +65,20 @@ static inline struct speech_voice *impl_from_IConnectionPointContainer(IConnecti return CONTAINING_RECORD(iface, struct speech_voice, IConnectionPointContainer_iface); } +struct tts_engine_site +{ + ISpTTSEngineSite ISpTTSEngineSite_iface; + LONG ref; + + struct speech_voice *voice; + ULONG stream_num; +}; + +static inline struct tts_engine_site *impl_from_ISpTTSEngineSite(ISpTTSEngineSite *iface) +{ + return CONTAINING_RECORD(iface, struct tts_engine_site, ISpTTSEngineSite_iface); +} + static HRESULT create_default_token(const WCHAR *cat_id, ISpObjectToken **token) { ISpObjectTokenCategory *cat; @@ -712,6 +727,7 @@ struct speak_task struct speech_voice *voice; SPVTEXTFRAG *frag_list; + ISpTTSEngineSite *site; DWORD flags; }; @@ -728,13 +744,17 @@ static void speak_proc(struct async_task *task) } } +static HRESULT ttsenginesite_create(struct speech_voice *voice, ULONG stream_num, ISpTTSEngineSite **site); + static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWORD flags, ULONG *stream_num_out) { struct speech_voice *This = impl_from_ISpVoice(iface); + ISpTTSEngineSite *site = NULL; SPVTEXTFRAG *frag; struct speak_task *speak_task = NULL; struct async_result *result = NULL; size_t contents_len, contents_size; + ULONG stream_num; HRESULT hr; FIXME("(%p, %p, %#lx, %p): semi-stub.\n", iface, contents, flags, stream_num_out); @@ -794,12 +814,21 @@ static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWOR frag->pTextStart = (WCHAR *)(frag + 1); frag->ulTextLen = contents_len; frag->ulTextSrcOffset = 0; + + stream_num = InterlockedIncrement(&This->cur_stream_num); + if (FAILED(hr = ttsenginesite_create(This, stream_num, &site))) + { + FIXME("Failed to create ttsenginesite: %#lx.\n", hr); + goto fail; + } + speak_task = heap_alloc(sizeof(*speak_task)); speak_task->task.proc = speak_proc; speak_task->result = NULL; speak_task->voice = This; speak_task->frag_list = frag; + speak_task->site = site; speak_task->flags = flags & SPF_NLP_SPEAK_PUNC; if (!(flags & SPF_ASYNC)) @@ -820,6 +849,9 @@ static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWOR goto fail; } + if (stream_num_out) + *stream_num_out = stream_num; + if (flags & SPF_ASYNC) return S_OK; else @@ -832,6 +864,7 @@ static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWOR } fail: + if (site) ISpTTSEngineSite_Release(site); heap_free(frag); heap_free(speak_task); if (result) @@ -1032,6 +1065,145 @@ static const ISpVoiceVtbl spvoice_vtbl = spvoice_DisplayUI }; +/* ISpTTSEngineSite interface */ +static HRESULT WINAPI ttsenginesite_QueryInterface(ISpTTSEngineSite *iface, REFIID iid, void **obj) +{ + struct tts_engine_site *This = impl_from_ISpTTSEngineSite(iface); + + TRACE("(%p, %s %p).\n", iface, debugstr_guid(iid), obj); + + if (IsEqualIID(iid, &IID_IUnknown) || + IsEqualIID(iid, &IID_ISpTTSEngineSite)) + *obj = &This->ISpTTSEngineSite_iface; + else + { + *obj = NULL; + FIXME("interface %s not implemented.\n", debugstr_guid(iid)); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*obj); + return S_OK; +} + +static ULONG WINAPI ttsenginesite_AddRef(ISpTTSEngineSite *iface) +{ + struct tts_engine_site *This = impl_from_ISpTTSEngineSite(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p): ref=%lu.\n", iface, ref); + + return ref; +} + +static ULONG WINAPI ttsenginesite_Release(ISpTTSEngineSite *iface) +{ + struct tts_engine_site *This = impl_from_ISpTTSEngineSite(iface); + + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p): ref=%lu.\n", iface, ref); + + if (!ref) + { + if (This->voice) + ISpeechVoice_Release(&This->voice->ISpeechVoice_iface); + heap_free(This); + } + + return ref; +} + +static HRESULT WINAPI ttsenginesite_AddEvents(ISpTTSEngineSite *iface, const SPEVENT *events, ULONG count) +{ + FIXME("(%p, %p, %ld): stub.\n", iface, events, count); + + return S_OK; +} + +static HRESULT WINAPI ttsenginesite_GetEventInterest(ISpTTSEngineSite *iface, ULONGLONG *interest) +{ + FIXME("(%p, %p): stub.\n", iface, interest); + + return E_NOTIMPL; +} + +static DWORD WINAPI ttsenginesite_GetActions(ISpTTSEngineSite *iface) +{ + FIXME("(%p): stub.\n", iface); + + return SPVES_CONTINUE; +} + +static HRESULT WINAPI ttsenginesite_Write(ISpTTSEngineSite *iface, const void *buf, ULONG cb, ULONG *cb_written) +{ + FIXME("(%p, %p, %ld, %p): stub.\n", iface, buf, cb, cb_written); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ttsenginesite_GetRate(ISpTTSEngineSite *iface, LONG *rate) +{ + FIXME("(%p, %p): stub.\n", iface, rate); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ttsenginesite_GetVolume(ISpTTSEngineSite *iface, USHORT *volume) +{ + FIXME("(%p, %p): stub.\n", iface, volume); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ttsenginesite_GetSkipInfo(ISpTTSEngineSite *iface, SPVSKIPTYPE *type, LONG *skip_count) +{ + FIXME("(%p, %p, %p): stub.\n", iface, type, skip_count); + + return E_NOTIMPL; +} + +static HRESULT WINAPI ttsenginesite_CompleteSkip(ISpTTSEngineSite *iface, LONG num_skipped) +{ + FIXME("(%p, %ld): stub.\n", iface, num_skipped); + + return E_NOTIMPL; +} + +const static ISpTTSEngineSiteVtbl ttsenginesite_vtbl = +{ + ttsenginesite_QueryInterface, + ttsenginesite_AddRef, + ttsenginesite_Release, + ttsenginesite_AddEvents, + ttsenginesite_GetEventInterest, + ttsenginesite_GetActions, + ttsenginesite_Write, + ttsenginesite_GetRate, + ttsenginesite_GetVolume, + ttsenginesite_GetSkipInfo, + ttsenginesite_CompleteSkip +}; + +static HRESULT ttsenginesite_create(struct speech_voice *voice, ULONG stream_num, ISpTTSEngineSite **site) +{ + struct tts_engine_site *This = heap_alloc(sizeof(*This)); + + if (!This) return E_OUTOFMEMORY; + + This->ISpTTSEngineSite_iface.lpVtbl = &ttsenginesite_vtbl; + + This->ref = 1; + This->voice = voice; + This->stream_num = stream_num; + + ISpeechVoice_AddRef(&This->voice->ISpeechVoice_iface); + + *site = &This->ISpTTSEngineSite_iface; + + return S_OK; +} + /* IConnectionPointContainer interface */ static HRESULT WINAPI container_QueryInterface(IConnectionPointContainer *iface, REFIID iid, void **obj) { @@ -1098,6 +1270,7 @@ HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj) This->output = NULL; This->engine = NULL; + This->cur_stream_num = 0; This->volume = 100; This->rate = 0; memset(&This->queue, 0, sizeof(This->queue)); From 64e941e550d351d47318639aa232d0352d2124dc Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Wed, 19 Jul 2023 13:28:21 -0400 Subject: [PATCH 2208/2777] sapi: Implement ISpVoice::Speak speak_proc. (cherry picked from commit 303bdc2e4bd9f6b0b1056a3607abc236aa63bbf0) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/tts.c | 314 ++++++++++++++++++++++++++++++++++++++++++ dlls/sapi/tts.c | 80 ++++++++++- 2 files changed, 391 insertions(+), 3 deletions(-) diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index ffe2e5f73a7..c17e4f5b7c3 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -98,16 +98,266 @@ static void test_interfaces(void) ISpeechVoice_Release(speech_voice); } +#define TESTENGINE_CLSID L"{57C7E6B1-2FC2-4E8E-B968-1410A39E7198}" +static const GUID CLSID_TestEngine = {0x57C7E6B1,0x2FC2,0x4E8E,{0xB9,0x68,0x14,0x10,0xA3,0x9E,0x71,0x98}}; + +struct test_engine +{ + ISpTTSEngine ISpTTSEngine_iface; + ISpObjectWithToken ISpObjectWithToken_iface; + + ISpObjectToken *token; + + BOOL speak_called; + DWORD flags; + GUID fmtid; + SPVTEXTFRAG *frag_list; +}; + +static void copy_frag_list(const SPVTEXTFRAG *frag_list, SPVTEXTFRAG **ret_frag_list) +{ + SPVTEXTFRAG *frag, *prev = NULL; + + if (!frag_list) + { + *ret_frag_list = NULL; + return; + } + + while (frag_list) + { + frag = malloc(sizeof(*frag) + frag_list->ulTextLen * sizeof(WCHAR)); + memcpy(frag, frag_list, sizeof(*frag)); + + if (frag_list->pTextStart) + { + frag->pTextStart = (WCHAR *)(frag + 1); + memcpy(frag + 1, frag_list->pTextStart, frag->ulTextLen * sizeof(WCHAR)); + } + + frag->pNext = NULL; + + if (prev) + prev->pNext = frag; + else + *ret_frag_list = frag; + + prev = frag; + frag_list = frag_list->pNext; + } +} + +static void reset_engine_params(struct test_engine *engine) +{ + SPVTEXTFRAG *frag, *next; + + engine->speak_called = FALSE; + engine->flags = 0xdeadbeef; + memset(&engine->fmtid, 0xde, sizeof(engine->fmtid)); + + for (frag = engine->frag_list; frag; frag = next) + { + next = frag->pNext; + free(frag); + } + engine->frag_list = NULL; +} + +static inline struct test_engine *impl_from_ISpTTSEngine(ISpTTSEngine *iface) +{ + return CONTAINING_RECORD(iface, struct test_engine, ISpTTSEngine_iface); +} + +static inline struct test_engine *impl_from_ISpObjectWithToken(ISpObjectWithToken *iface) +{ + return CONTAINING_RECORD(iface, struct test_engine, ISpObjectWithToken_iface); +} + +static HRESULT WINAPI test_engine_QueryInterface(ISpTTSEngine *iface, REFIID iid, void **obj) +{ + struct test_engine *engine = impl_from_ISpTTSEngine(iface); + + if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ISpTTSEngine)) + *obj = &engine->ISpTTSEngine_iface; + else if (IsEqualIID(iid, &IID_ISpObjectWithToken)) + *obj = &engine->ISpObjectWithToken_iface; + else + { + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*obj); + return S_OK; +} + +static ULONG WINAPI test_engine_AddRef(ISpTTSEngine *iface) +{ + return 2; +} + +static ULONG WINAPI test_engine_Release(ISpTTSEngine *iface) +{ + return 1; +} + +static HRESULT WINAPI test_engine_Speak(ISpTTSEngine *iface, DWORD flags, REFGUID fmtid, + const WAVEFORMATEX *wfx, const SPVTEXTFRAG *frag_list, + ISpTTSEngineSite *site) +{ + struct test_engine *engine = impl_from_ISpTTSEngine(iface); + + engine->flags = flags; + engine->fmtid = *fmtid; + copy_frag_list(frag_list, &engine->frag_list); + engine->speak_called = TRUE; + + return S_OK; +} + +static HRESULT WINAPI test_engine_GetOutputFormat(ISpTTSEngine *iface, const GUID *fmtid, + const WAVEFORMATEX *wfx, GUID *out_fmtid, + WAVEFORMATEX **out_wfx) +{ + *out_fmtid = SPDFID_WaveFormatEx; + *out_wfx = CoTaskMemAlloc(sizeof(WAVEFORMATEX)); + (*out_wfx)->wFormatTag = WAVE_FORMAT_PCM; + (*out_wfx)->nChannels = 1; + (*out_wfx)->nSamplesPerSec = 22050; + (*out_wfx)->wBitsPerSample = 16; + (*out_wfx)->nBlockAlign = 2; + (*out_wfx)->nAvgBytesPerSec = 22050 * 2; + (*out_wfx)->cbSize = 0; + + return S_OK; +} + +static ISpTTSEngineVtbl test_engine_vtbl = +{ + test_engine_QueryInterface, + test_engine_AddRef, + test_engine_Release, + test_engine_Speak, + test_engine_GetOutputFormat, +}; + +static HRESULT WINAPI objwithtoken_QueryInterface(ISpObjectWithToken *iface, REFIID iid, void **obj) +{ + struct test_engine *engine = impl_from_ISpObjectWithToken(iface); + + return ISpTTSEngine_QueryInterface(&engine->ISpTTSEngine_iface, iid, obj); +} + +static ULONG WINAPI objwithtoken_AddRef(ISpObjectWithToken *iface) +{ + return 2; +} + +static ULONG WINAPI objwithtoken_Release(ISpObjectWithToken *iface) +{ + return 1; +} + +static HRESULT WINAPI objwithtoken_SetObjectToken(ISpObjectWithToken *iface, ISpObjectToken *token) +{ + struct test_engine *engine = impl_from_ISpObjectWithToken(iface); + + if (!token) + return E_INVALIDARG; + + ISpObjectToken_AddRef(token); + engine->token = token; + + return S_OK; +} + +static HRESULT WINAPI objwithtoken_GetObjectToken(ISpObjectWithToken *iface, ISpObjectToken **token) +{ + struct test_engine *engine = impl_from_ISpObjectWithToken(iface); + + *token = engine->token; + if (*token) + ISpObjectToken_AddRef(*token); + + return S_OK; +} + +static const ISpObjectWithTokenVtbl objwithtoken_vtbl = +{ + objwithtoken_QueryInterface, + objwithtoken_AddRef, + objwithtoken_Release, + objwithtoken_SetObjectToken, + objwithtoken_GetObjectToken +}; + +static struct test_engine test_engine = {{&test_engine_vtbl}, {&objwithtoken_vtbl}}; + +static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) +{ + if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IClassFactory, riid)) + { + *ppv = iface; + return S_OK; + } + + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) +{ + return 2; +} + +static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) +{ + return 1; +} + +static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, + IUnknown *pUnkOuter, REFIID riid, void **ppv) +{ + ok(pUnkOuter == NULL, "pUnkOuter != NULL.\n"); + ok(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISpTTSEngine), + "riid = %s.\n", wine_dbgstr_guid(riid)); + + *ppv = &test_engine.ISpTTSEngine_iface; + return S_OK; +} + +static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock) +{ + ok(0, "unexpected call.\n"); + return E_NOTIMPL; +} + +static const IClassFactoryVtbl ClassFactoryVtbl = { + ClassFactory_QueryInterface, + ClassFactory_AddRef, + ClassFactory_Release, + ClassFactory_CreateInstance, + ClassFactory_LockServer +}; + +static IClassFactory test_engine_cf = { &ClassFactoryVtbl }; + static void test_spvoice(void) { + static const WCHAR test_token_id[] = L"HKEY_LOCAL_MACHINE\\Software\\Wine\\Winetest\\sapi\\tts\\TestEngine"; + static const WCHAR test_text[] = L"Hello! This is a test sentence."; + ISpVoice *voice; ISpMMSysAudio *audio_out; ISpObjectTokenCategory *token_cat; ISpObjectToken *token; WCHAR *token_id = NULL, *default_token_id = NULL; + ISpDataKey *attrs_key; LONG rate; USHORT volume; ULONG stream_num; + DWORD regid; + DWORD start, duration; HRESULT hr; if (waveOutGetNumDevs() == 0) { @@ -210,15 +460,79 @@ static void test_spvoice(void) hr = ISpVoice_SetVolume(voice, 101); ok(hr == E_INVALIDARG, "got %#lx.\n", hr); + hr = CoRegisterClassObject(&CLSID_TestEngine, (IUnknown *)&test_engine_cf, + CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®id); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = CoCreateInstance(&CLSID_SpObjectToken, NULL, CLSCTX_INPROC_SERVER, + &IID_ISpObjectToken, (void **)&token); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = ISpObjectToken_SetId(token, NULL, test_token_id, TRUE); + ok(hr == S_OK || broken(hr == E_ACCESSDENIED) /* w1064_adm */, "got %#lx.\n", hr); + if (hr == E_ACCESSDENIED) + { + win_skip("token SetId access denied.\n"); + goto done; + } + + ISpObjectToken_SetStringValue(token, L"CLSID", TESTENGINE_CLSID); + hr = ISpObjectToken_CreateKey(token, L"Attributes", &attrs_key); + ok(hr == S_OK, "got %#lx.\n", hr); + ISpDataKey_SetStringValue(attrs_key, L"Language", L"409"); + ISpDataKey_Release(attrs_key); + + hr = ISpVoice_SetVoice(voice, token); + ok(hr == S_OK, "got %#lx.\n", hr); + + test_engine.speak_called = FALSE; hr = ISpVoice_Speak(voice, NULL, SPF_PURGEBEFORESPEAK, NULL); ok(hr == S_OK, "got %#lx.\n", hr); + ok(!test_engine.speak_called, "ISpTTSEngine::Speak was called.\n"); stream_num = 0xdeadbeef; hr = ISpVoice_Speak(voice, NULL, SPF_PURGEBEFORESPEAK, &stream_num); ok(hr == S_OK, "got %#lx.\n", hr); ok(stream_num == 0xdeadbeef, "got %lu.\n", stream_num); + test_engine.speak_called = FALSE; + stream_num = 0xdeadbeef; + start = GetTickCount(); + hr = ISpVoice_Speak(voice, test_text, SPF_DEFAULT, &stream_num); + duration = GetTickCount() - start; + ok(hr == S_OK, "got %#lx.\n", hr); + ok(test_engine.speak_called, "ISpTTSEngine::Speak was not called.\n"); + ok(test_engine.flags == SPF_DEFAULT, "got %#lx.\n", test_engine.flags); + ok(test_engine.frag_list != NULL, "frag_list is NULL.\n"); + ok(test_engine.frag_list->pNext == NULL, "frag_list->pNext != NULL.\n"); + ok(test_engine.frag_list->ulTextLen == wcslen(test_text), "got %lu.\n", test_engine.frag_list->ulTextLen); + ok(!wcsncmp(test_text, test_engine.frag_list->pTextStart, wcslen(test_text)), + "got %s.\n", wine_dbgstr_w(test_engine.frag_list->pTextStart)); + ok(stream_num == 1, "got %lu.\n", stream_num); + ok(duration < 500, "took %lu ms.\n", duration); + + reset_engine_params(&test_engine); + stream_num = 0xdeadbeef; + start = GetTickCount(); + hr = ISpVoice_Speak(voice, test_text, SPF_DEFAULT | SPF_ASYNC | SPF_NLP_SPEAK_PUNC, &stream_num); + duration = GetTickCount() - start; + ok(hr == S_OK, "got %#lx.\n", hr); + todo_wine ok(stream_num == 1, "got %lu.\n", stream_num); + ok(duration < 500, "took %lu ms.\n", duration); + + Sleep(200); + ok(test_engine.speak_called, "ISpTTSEngine::Speak was not called.\n"); + ok(test_engine.flags == SPF_NLP_SPEAK_PUNC, "got %#lx.\n", test_engine.flags); + ok(test_engine.frag_list != NULL, "frag_list is NULL.\n"); + ok(test_engine.frag_list->pNext == NULL, "frag_list->pNext != NULL.\n"); + ok(test_engine.frag_list->ulTextLen == wcslen(test_text), "got %lu.\n", test_engine.frag_list->ulTextLen); + ok(!wcsncmp(test_text, test_engine.frag_list->pTextStart, wcslen(test_text)), + "got %s.\n", wine_dbgstr_w(test_engine.frag_list->pTextStart)); + +done: + reset_engine_params(&test_engine); ISpVoice_Release(voice); + ISpObjectToken_Release(token); ISpMMSysAudio_Release(audio_out); } diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index 7ec5aa059d9..9a022aca73c 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -731,15 +731,89 @@ struct speak_task DWORD flags; }; +static HRESULT set_output_format(ISpStreamFormat *output, ISpTTSEngine *engine, GUID *fmtid, WAVEFORMATEX **wfx) +{ + GUID output_fmtid; + WAVEFORMATEX *output_wfx = NULL; + ISpAudio *audio = NULL; + HRESULT hr; + + if (FAILED(hr = ISpStreamFormat_GetFormat(output, &output_fmtid, &output_wfx))) + return hr; + if (FAILED(hr = ISpTTSEngine_GetOutputFormat(engine, &output_fmtid, output_wfx, fmtid, wfx))) + goto done; + if (!IsEqualGUID(fmtid, &SPDFID_WaveFormatEx)) + { + hr = E_INVALIDARG; + goto done; + } + + if (memcmp(output_wfx, *wfx, sizeof(WAVEFORMATEX)) || + memcmp(output_wfx + 1, *wfx + 1, output_wfx->cbSize)) + { + if (FAILED(hr = ISpStreamFormat_QueryInterface(output, &IID_ISpAudio, (void **)&audio)) || + FAILED(hr = ISpAudio_SetFormat(audio, &SPDFID_WaveFormatEx, *wfx))) + goto done; + } + +done: + CoTaskMemFree(output_wfx); + if (audio) ISpAudio_Release(audio); + return hr; +} + static void speak_proc(struct async_task *task) { struct speak_task *speak_task = (struct speak_task *)task; + struct speech_voice *This = speak_task->voice; + GUID fmtid; + WAVEFORMATEX *wfx = NULL; + ISpTTSEngine *engine = NULL; + ISpAudio *audio = NULL; + HRESULT hr; + + TRACE("(%p).\n", task); - FIXME("(%p): stub.\n", task); + EnterCriticalSection(&This->cs); + + if (FAILED(hr = set_output_format(This->output, This->engine, &fmtid, &wfx))) + { + LeaveCriticalSection(&This->cs); + ERR("failed setting output format: %#lx.\n", hr); + goto done; + } + engine = This->engine; + ISpTTSEngine_AddRef(engine); + + if (SUCCEEDED(ISpStreamFormat_QueryInterface(This->output, &IID_ISpAudio, (void **)&audio))) + ISpAudio_SetState(audio, SPAS_RUN, 0); + + LeaveCriticalSection(&This->cs); + + hr = ISpTTSEngine_Speak(engine, speak_task->flags, &fmtid, wfx, speak_task->frag_list, speak_task->site); + if (SUCCEEDED(hr)) + { + ISpStreamFormat_Commit(This->output, STGC_DEFAULT); + if (audio) + WaitForSingleObject(ISpAudio_EventHandle(audio), INFINITE); + } + else + WARN("ISpTTSEngine_Speak failed: %#lx.\n", hr); + +done: + if (audio) + { + ISpAudio_SetState(audio, SPAS_CLOSED, 0); + ISpAudio_Release(audio); + } + CoTaskMemFree(wfx); + if (engine) ISpTTSEngine_Release(engine); + heap_free(speak_task->frag_list); + ISpTTSEngineSite_Release(speak_task->site); if (speak_task->result) { - speak_task->result->hr = E_NOTIMPL; + speak_task->result->hr = hr; SetEvent(speak_task->result->done); } } @@ -757,7 +831,7 @@ static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWOR ULONG stream_num; HRESULT hr; - FIXME("(%p, %p, %#lx, %p): semi-stub.\n", iface, contents, flags, stream_num_out); + TRACE("(%p, %p, %#lx, %p).\n", iface, contents, flags, stream_num_out); flags &= ~SPF_IS_NOT_XML; if (flags & ~(SPF_ASYNC | SPF_PURGEBEFORESPEAK | SPF_NLP_SPEAK_PUNC)) From 31bfb6d0863e0c5e4b2826ae81534aa27520b2a3 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Thu, 13 Jul 2023 19:51:16 -0400 Subject: [PATCH 2209/2777] sapi: Implement ISpTTSEngineSite::Write. (cherry picked from commit 0d09ab378e98b7b5da1ac78439fec09d1ce30994) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/tts.c | 14 +++++++++++++- dlls/sapi/tts.c | 10 ++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index c17e4f5b7c3..d2b98e6fbfb 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -206,12 +206,24 @@ static HRESULT WINAPI test_engine_Speak(ISpTTSEngine *iface, DWORD flags, REFGUI ISpTTSEngineSite *site) { struct test_engine *engine = impl_from_ISpTTSEngine(iface); + char *buf; + int i; + HRESULT hr; engine->flags = flags; engine->fmtid = *fmtid; copy_frag_list(frag_list, &engine->frag_list); engine->speak_called = TRUE; + buf = calloc(1, 22050 * 2 / 5); + for (i = 0; i < 5; i++) + { + hr = ISpTTSEngineSite_Write(site, buf, 22050 * 2 / 5, NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + Sleep(100); + } + free(buf); + return S_OK; } @@ -509,7 +521,7 @@ static void test_spvoice(void) ok(!wcsncmp(test_text, test_engine.frag_list->pTextStart, wcslen(test_text)), "got %s.\n", wine_dbgstr_w(test_engine.frag_list->pTextStart)); ok(stream_num == 1, "got %lu.\n", stream_num); - ok(duration < 500, "took %lu ms.\n", duration); + ok(duration > 800 && duration < 3000, "took %lu ms.\n", duration); reset_engine_params(&test_engine); stream_num = 0xdeadbeef; diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index 9a022aca73c..acbef907646 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -27,6 +27,7 @@ #include "objbase.h" #include "sapiddk.h" +#include "sperror.h" #include "wine/debug.h" @@ -1211,9 +1212,14 @@ static DWORD WINAPI ttsenginesite_GetActions(ISpTTSEngineSite *iface) static HRESULT WINAPI ttsenginesite_Write(ISpTTSEngineSite *iface, const void *buf, ULONG cb, ULONG *cb_written) { - FIXME("(%p, %p, %ld, %p): stub.\n", iface, buf, cb, cb_written); + struct tts_engine_site *This = impl_from_ISpTTSEngineSite(iface); - return E_NOTIMPL; + TRACE("(%p, %p, %ld, %p).\n", iface, buf, cb, cb_written); + + if (!This->voice->output) + return SPERR_UNINITIALIZED; + + return ISpStreamFormat_Write(This->voice->output, buf, cb, cb_written); } static HRESULT WINAPI ttsenginesite_GetRate(ISpTTSEngineSite *iface, LONG *rate) From d7e11654d02106ebec7aa740ca0eca14705a6755 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Thu, 13 Jul 2023 19:51:36 -0400 Subject: [PATCH 2210/2777] sapi: Implement ISpTTSEngineSite::GetActions/Rate/Volume. (cherry picked from commit ee8c8f6533583f1603a292d0d33d939b815beb22) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/tts.c | 44 +++++++++++++++++++++++++++++++++++-- dlls/sapi/tts.c | 51 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 87 insertions(+), 8 deletions(-) diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index d2b98e6fbfb..86a9312a37b 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -112,6 +112,8 @@ struct test_engine DWORD flags; GUID fmtid; SPVTEXTFRAG *frag_list; + LONG rate; + USHORT volume; }; static void copy_frag_list(const SPVTEXTFRAG *frag_list, SPVTEXTFRAG **ret_frag_list) @@ -154,6 +156,8 @@ static void reset_engine_params(struct test_engine *engine) engine->speak_called = FALSE; engine->flags = 0xdeadbeef; memset(&engine->fmtid, 0xde, sizeof(engine->fmtid)); + engine->rate = 0xdeadbeef; + engine->volume = 0xbeef; for (frag = engine->frag_list; frag; frag = next) { @@ -206,6 +210,7 @@ static HRESULT WINAPI test_engine_Speak(ISpTTSEngine *iface, DWORD flags, REFGUI ISpTTSEngineSite *site) { struct test_engine *engine = impl_from_ISpTTSEngine(iface); + DWORD actions; char *buf; int i; HRESULT hr; @@ -215,11 +220,26 @@ static HRESULT WINAPI test_engine_Speak(ISpTTSEngine *iface, DWORD flags, REFGUI copy_frag_list(frag_list, &engine->frag_list); engine->speak_called = TRUE; + actions = ISpTTSEngineSite_GetActions(site); + ok(actions == (SPVES_CONTINUE | SPVES_RATE | SPVES_VOLUME), "got %#lx.\n", actions); + + hr = ISpTTSEngineSite_GetRate(site, &engine->rate); + ok(hr == S_OK, "got %#lx.\n", hr); + actions = ISpTTSEngineSite_GetActions(site); + ok(actions == (SPVES_CONTINUE | SPVES_VOLUME), "got %#lx.\n", actions); + + hr = ISpTTSEngineSite_GetVolume(site, &engine->volume); + ok(hr == S_OK, "got %#lx.\n", hr); + actions = ISpTTSEngineSite_GetActions(site); + ok(actions == SPVES_CONTINUE, "got %#lx.\n", actions); + buf = calloc(1, 22050 * 2 / 5); for (i = 0; i < 5; i++) { + if (ISpTTSEngineSite_GetActions(site) & SPVES_ABORT) + break; hr = ISpTTSEngineSite_Write(site, buf, 22050 * 2 / 5, NULL); - ok(hr == S_OK, "got %#lx.\n", hr); + ok(hr == S_OK || hr == SP_AUDIO_STOPPED, "got %#lx.\n", hr); Sleep(100); } free(buf); @@ -507,7 +527,10 @@ static void test_spvoice(void) ok(hr == S_OK, "got %#lx.\n", hr); ok(stream_num == 0xdeadbeef, "got %lu.\n", stream_num); - test_engine.speak_called = FALSE; + ISpVoice_SetRate(voice, 0); + ISpVoice_SetVolume(voice, 100); + + reset_engine_params(&test_engine); stream_num = 0xdeadbeef; start = GetTickCount(); hr = ISpVoice_Speak(voice, test_text, SPF_DEFAULT, &stream_num); @@ -520,6 +543,8 @@ static void test_spvoice(void) ok(test_engine.frag_list->ulTextLen == wcslen(test_text), "got %lu.\n", test_engine.frag_list->ulTextLen); ok(!wcsncmp(test_text, test_engine.frag_list->pTextStart, wcslen(test_text)), "got %s.\n", wine_dbgstr_w(test_engine.frag_list->pTextStart)); + ok(test_engine.rate == 0, "got %ld.\n", test_engine.rate); + ok(test_engine.volume == 100, "got %d.\n", test_engine.volume); ok(stream_num == 1, "got %lu.\n", stream_num); ok(duration > 800 && duration < 3000, "took %lu ms.\n", duration); @@ -540,6 +565,21 @@ static void test_spvoice(void) ok(test_engine.frag_list->ulTextLen == wcslen(test_text), "got %lu.\n", test_engine.frag_list->ulTextLen); ok(!wcsncmp(test_text, test_engine.frag_list->pTextStart, wcslen(test_text)), "got %s.\n", wine_dbgstr_w(test_engine.frag_list->pTextStart)); + ok(test_engine.rate == 0, "got %ld.\n", test_engine.rate); + ok(test_engine.volume == 100, "got %d.\n", test_engine.volume); + + Sleep(2000); + + reset_engine_params(&test_engine); + hr = ISpVoice_Speak(voice, test_text, SPF_DEFAULT | SPF_ASYNC, NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + + Sleep(200); + start = GetTickCount(); + hr = ISpVoice_Speak(voice, NULL, SPF_PURGEBEFORESPEAK, NULL); + duration = GetTickCount() - start; + ok(hr == S_OK, "got %#lx.\n", hr); + ok(duration < 300, "took %lu ms.\n", duration); done: reset_engine_params(&test_engine); diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index acbef907646..432a021ea1c 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -45,6 +45,7 @@ struct speech_voice ISpStreamFormat *output; ISpTTSEngine *engine; LONG cur_stream_num; + DWORD actions; USHORT volume; LONG rate; struct async_queue queue; @@ -777,6 +778,13 @@ static void speak_proc(struct async_task *task) EnterCriticalSection(&This->cs); + if (This->actions & SPVES_ABORT) + { + LeaveCriticalSection(&This->cs); + hr = S_OK; + goto done; + } + if (FAILED(hr = set_output_format(This->output, This->engine, &fmtid, &wfx))) { LeaveCriticalSection(&This->cs); @@ -789,6 +797,8 @@ static void speak_proc(struct async_task *task) if (SUCCEEDED(ISpStreamFormat_QueryInterface(This->output, &IID_ISpAudio, (void **)&audio))) ISpAudio_SetState(audio, SPAS_RUN, 0); + This->actions = SPVES_RATE | SPVES_VOLUME; + LeaveCriticalSection(&This->cs); hr = ISpTTSEngine_Speak(engine, speak_task->flags, &fmtid, wfx, speak_task->frag_list, speak_task->site); @@ -847,6 +857,7 @@ static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWOR EnterCriticalSection(&This->cs); + This->actions = SPVES_ABORT; if (This->output && SUCCEEDED(ISpStreamFormat_QueryInterface(This->output, &IID_ISpAudio, (void **)&audio))) { ISpAudio_SetState(audio, SPAS_CLOSED, 0); @@ -857,6 +868,10 @@ static HRESULT WINAPI spvoice_Speak(ISpVoice *iface, const WCHAR *contents, DWOR async_empty_queue(&This->queue); + EnterCriticalSection(&This->cs); + This->actions = SPVES_CONTINUE; + LeaveCriticalSection(&This->cs); + if (!contents || !*contents) return S_OK; } @@ -1007,6 +1022,7 @@ static HRESULT WINAPI spvoice_SetRate(ISpVoice *iface, LONG rate) EnterCriticalSection(&This->cs); This->rate = rate; + This->actions |= SPVES_RATE; LeaveCriticalSection(&This->cs); return S_OK; @@ -1036,6 +1052,7 @@ static HRESULT WINAPI spvoice_SetVolume(ISpVoice *iface, USHORT volume) EnterCriticalSection(&This->cs); This->volume = volume; + This->actions |= SPVES_VOLUME; LeaveCriticalSection(&This->cs); return S_OK; @@ -1205,9 +1222,16 @@ static HRESULT WINAPI ttsenginesite_GetEventInterest(ISpTTSEngineSite *iface, UL static DWORD WINAPI ttsenginesite_GetActions(ISpTTSEngineSite *iface) { - FIXME("(%p): stub.\n", iface); + struct tts_engine_site *This = impl_from_ISpTTSEngineSite(iface); + DWORD actions; + + TRACE("(%p).\n", iface); + + EnterCriticalSection(&This->voice->cs); + actions = This->voice->actions; + LeaveCriticalSection(&This->voice->cs); - return SPVES_CONTINUE; + return actions; } static HRESULT WINAPI ttsenginesite_Write(ISpTTSEngineSite *iface, const void *buf, ULONG cb, ULONG *cb_written) @@ -1224,16 +1248,30 @@ static HRESULT WINAPI ttsenginesite_Write(ISpTTSEngineSite *iface, const void *b static HRESULT WINAPI ttsenginesite_GetRate(ISpTTSEngineSite *iface, LONG *rate) { - FIXME("(%p, %p): stub.\n", iface, rate); + struct tts_engine_site *This = impl_from_ISpTTSEngineSite(iface); - return E_NOTIMPL; + TRACE("(%p, %p).\n", iface, rate); + + EnterCriticalSection(&This->voice->cs); + *rate = This->voice->rate; + This->voice->actions &= ~SPVES_RATE; + LeaveCriticalSection(&This->voice->cs); + + return S_OK; } static HRESULT WINAPI ttsenginesite_GetVolume(ISpTTSEngineSite *iface, USHORT *volume) { - FIXME("(%p, %p): stub.\n", iface, volume); + struct tts_engine_site *This = impl_from_ISpTTSEngineSite(iface); - return E_NOTIMPL; + TRACE("(%p, %p).\n", iface, volume); + + EnterCriticalSection(&This->voice->cs); + *volume = This->voice->volume; + This->voice->actions &= ~SPVES_VOLUME; + LeaveCriticalSection(&This->voice->cs); + + return S_OK; } static HRESULT WINAPI ttsenginesite_GetSkipInfo(ISpTTSEngineSite *iface, SPVSKIPTYPE *type, LONG *skip_count) @@ -1351,6 +1389,7 @@ HRESULT speech_voice_create(IUnknown *outer, REFIID iid, void **obj) This->output = NULL; This->engine = NULL; This->cur_stream_num = 0; + This->actions = SPVES_CONTINUE; This->volume = 100; This->rate = 0; memset(&This->queue, 0, sizeof(This->queue)); From dee87f150b698615c784a32789daacb9b486a9f1 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Thu, 20 Jul 2023 17:24:56 -0400 Subject: [PATCH 2211/2777] sapi: Return wait status in async_wait_queue_empty. (cherry picked from commit b89c5361bbf7cd14b2e62194da4242069ee7a8c8) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/async.c | 6 +++--- dlls/sapi/sapi_private.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/sapi/async.c b/dlls/sapi/async.c index 491ca657c1a..b02778ae7ba 100644 --- a/dlls/sapi/async.c +++ b/dlls/sapi/async.c @@ -171,8 +171,8 @@ HRESULT async_queue_task(struct async_queue *queue, struct async_task *task) return S_OK; } -void async_wait_queue_empty(struct async_queue *queue, DWORD timeout) +HRESULT async_wait_queue_empty(struct async_queue *queue, DWORD timeout) { - if (!queue->init) return; - WaitForSingleObject(queue->empty, timeout); + if (!queue->init) return WAIT_OBJECT_0; + return WaitForSingleObject(queue->empty, timeout); } diff --git a/dlls/sapi/sapi_private.h b/dlls/sapi/sapi_private.h index d0cd7669623..d38efb73b2e 100644 --- a/dlls/sapi/sapi_private.h +++ b/dlls/sapi/sapi_private.h @@ -42,7 +42,7 @@ HRESULT async_start_queue(struct async_queue *queue); void async_empty_queue(struct async_queue *queue); void async_cancel_queue(struct async_queue *queue); HRESULT async_queue_task(struct async_queue *queue, struct async_task *task); -void async_wait_queue_empty(struct async_queue *queue, DWORD timeout); +HRESULT async_wait_queue_empty(struct async_queue *queue, DWORD timeout); HRESULT data_key_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN; HRESULT file_stream_create( IUnknown *outer, REFIID iid, void **obj ) DECLSPEC_HIDDEN; From 8ab41f7499fed3007f2dfbcaf587a2e232768077 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Thu, 20 Jul 2023 17:27:12 -0400 Subject: [PATCH 2212/2777] sapi: Implement ISpVoice::WaitUntilDone. (cherry picked from commit 61ad9174e28530b9e31daf7683ce17dfa68287e3) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/tts.c | 17 ++++++++++++++--- dlls/sapi/tts.c | 11 +++++++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index 86a9312a37b..39f62ac551e 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -548,6 +548,12 @@ static void test_spvoice(void) ok(stream_num == 1, "got %lu.\n", stream_num); ok(duration > 800 && duration < 3000, "took %lu ms.\n", duration); + start = GetTickCount(); + hr = ISpVoice_WaitUntilDone(voice, INFINITE); + duration = GetTickCount() - start; + ok(hr == S_OK, "got %#lx.\n", hr); + ok(duration < 200, "took %lu ms.\n", duration); + reset_engine_params(&test_engine); stream_num = 0xdeadbeef; start = GetTickCount(); @@ -557,7 +563,14 @@ static void test_spvoice(void) todo_wine ok(stream_num == 1, "got %lu.\n", stream_num); ok(duration < 500, "took %lu ms.\n", duration); - Sleep(200); + hr = ISpVoice_WaitUntilDone(voice, 100); + ok(hr == S_FALSE, "got %#lx.\n", hr); + + hr = ISpVoice_WaitUntilDone(voice, INFINITE); + duration = GetTickCount() - start; + ok(hr == S_OK, "got %#lx.\n", hr); + ok(duration > 800 && duration < 3000, "took %lu ms.\n", duration); + ok(test_engine.speak_called, "ISpTTSEngine::Speak was not called.\n"); ok(test_engine.flags == SPF_NLP_SPEAK_PUNC, "got %#lx.\n", test_engine.flags); ok(test_engine.frag_list != NULL, "frag_list is NULL.\n"); @@ -568,8 +581,6 @@ static void test_spvoice(void) ok(test_engine.rate == 0, "got %ld.\n", test_engine.rate); ok(test_engine.volume == 100, "got %d.\n", test_engine.volume); - Sleep(2000); - reset_engine_params(&test_engine); hr = ISpVoice_Speak(voice, test_text, SPF_DEFAULT | SPF_ASYNC, NULL); ok(hr == S_OK, "got %#lx.\n", hr); diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index 432a021ea1c..4763ef9f324 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -1073,9 +1073,16 @@ static HRESULT WINAPI spvoice_GetVolume(ISpVoice *iface, USHORT *volume) static HRESULT WINAPI spvoice_WaitUntilDone(ISpVoice *iface, ULONG timeout) { - FIXME("(%p, %ld): stub.\n", iface, timeout); + struct speech_voice *This = impl_from_ISpVoice(iface); + HRESULT hr; - return E_NOTIMPL; + TRACE("(%p, %ld).\n", iface, timeout); + + hr = async_wait_queue_empty(&This->queue, timeout); + + if (hr == WAIT_OBJECT_0) return S_OK; + else if (hr == WAIT_TIMEOUT) return S_FALSE; + return hr; } static HRESULT WINAPI spvoice_SetSyncSpeakTimeout(ISpVoice *iface, ULONG timeout) From de8d12348661327cd0cb7d237ca878b98e86671b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 24 Jul 2023 19:38:56 -0600 Subject: [PATCH 2213/2777] nsiproxy.sys: Detect wireless interface type on Linux. CW-Bug-Id: #22496 --- dlls/nsiproxy.sys/ndis.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dlls/nsiproxy.sys/ndis.c b/dlls/nsiproxy.sys/ndis.c index 73c047586a9..9c4fe80e865 100644 --- a/dlls/nsiproxy.sys/ndis.c +++ b/dlls/nsiproxy.sys/ndis.c @@ -200,7 +200,6 @@ static NTSTATUS if_get_physical( const char *name, UINT *type, IF_PHYSICAL_ADDRE } #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H) - static NTSTATUS if_get_physical( const char *name, UINT *type, IF_PHYSICAL_ADDRESS *phys_addr ) { struct if_msghdr *ifm; From bf5bf63f314851fddde758b198ef0548868de641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 25 Jul 2023 10:38:35 +0200 Subject: [PATCH 2214/2777] winex11: Use XFixes to hide cursor before warping it. XWayland only allows warping the cursor if it is not visible. Fixes a regression from the periodic cursor sync removal. CW-Bug-Id: #21879 --- dlls/winex11.drv/mouse.c | 4 +++- dlls/winex11.drv/x11drv_main.c | 4 ++++ dlls/winex11.drv/xfixes.h | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index dd362e18e3d..72a5d0173e4 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -55,6 +55,7 @@ MAKE_FUNCPTR(XcursorLibraryLoadCursor); #define OEMRESOURCE #include "x11drv.h" +#include "xfixes.h" #include "winreg.h" #include "wine/server.h" #include "wine/debug.h" @@ -1470,9 +1471,10 @@ BOOL X11DRV_SetCursorPos( INT x, INT y ) TRACE( "real setting to %s\n", wine_dbgstr_point( &pos ) ); + pXFixesHideCursor( data->display, root_window ); XWarpPointer( data->display, root_window, root_window, 0, 0, 0, 0, pos.x, pos.y ); data->warp_serial = NextRequest( data->display ); - XNoOp( data->display ); + pXFixesShowCursor( data->display, root_window ); XFlush( data->display ); /* avoids bad mouse lag in games that do their own mouse warping */ TRACE( "warped to (fake) %d,%d serial %lu\n", x, y, data->warp_serial ); return TRUE; diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 3a0f2a0e48e..d1257701b9d 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -629,11 +629,13 @@ static void X11DRV_XComposite_Init(void) #ifdef SONAME_LIBXFIXES #define MAKE_FUNCPTR(f) typeof(f) * p##f; +MAKE_FUNCPTR(XFixesHideCursor) MAKE_FUNCPTR(XFixesQueryExtension) MAKE_FUNCPTR(XFixesQueryVersion) MAKE_FUNCPTR(XFixesCreateRegion) MAKE_FUNCPTR(XFixesCreateRegionFromGC) MAKE_FUNCPTR(XFixesSelectSelectionInput) +MAKE_FUNCPTR(XFixesShowCursor) #undef MAKE_FUNCPTR static void x11drv_load_xfixes(void) @@ -654,11 +656,13 @@ static void x11drv_load_xfixes(void) dlclose(xfixes); \ return; \ } + LOAD_FUNCPTR(XFixesHideCursor) LOAD_FUNCPTR(XFixesQueryExtension) LOAD_FUNCPTR(XFixesQueryVersion) LOAD_FUNCPTR(XFixesCreateRegion) LOAD_FUNCPTR(XFixesCreateRegionFromGC) LOAD_FUNCPTR(XFixesSelectSelectionInput) + LOAD_FUNCPTR(XFixesShowCursor) #undef LOAD_FUNCPTR if (!pXFixesQueryExtension(gdi_display, &event, &error)) diff --git a/dlls/winex11.drv/xfixes.h b/dlls/winex11.drv/xfixes.h index 3ab31201d3d..10c9543ce3c 100644 --- a/dlls/winex11.drv/xfixes.h +++ b/dlls/winex11.drv/xfixes.h @@ -27,9 +27,11 @@ #ifdef SONAME_LIBXFIXES #include #define MAKE_FUNCPTR(f) extern typeof(f) * p##f DECLSPEC_HIDDEN; +MAKE_FUNCPTR(XFixesHideCursor) MAKE_FUNCPTR(XFixesQueryExtension) MAKE_FUNCPTR(XFixesQueryVersion) MAKE_FUNCPTR(XFixesSelectSelectionInput) +MAKE_FUNCPTR(XFixesShowCursor) #undef MAKE_FUNCPTR #endif /* defined(SONAME_LIBXFIXES) */ From c305ca8b036626663f6564bc7425d5ab5ffc6827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 25 Jul 2023 11:35:19 +0200 Subject: [PATCH 2215/2777] imm32: Hide the composition window if the string is empty. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55258 (cherry picked from commit 428120441bd39f9311d75aa6ebad97d342837f45) --- dlls/imm32/ime.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 0c6ed9c49e1..3217b6c6562 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -98,6 +98,8 @@ static void input_context_set_comp_str( INPUTCONTEXT *ctx, const WCHAR *str, UIN UINT size; BYTE *dst; + TRACE( "ctx %p, str %s\n", ctx, debugstr_wn( str, len ) ); + size = sizeof(*compstr); size += len * sizeof(WCHAR); /* GCS_COMPSTR */ size += len; /* GCS_COMPSTRATTR */ @@ -310,20 +312,17 @@ static void ime_ui_paint( HIMC himc, HWND hwnd ) static void ime_ui_update_window( INPUTCONTEXT *ctx, HWND hwnd ) { - COMPOSITIONSTRING *string; - - if (ctx->hCompStr) string = ImmLockIMCC( ctx->hCompStr ); - else string = NULL; + WCHAR *str; + UINT len; - if (!string || string->dwCompStrLen == 0) + if (!(str = input_context_get_comp_str( ctx, FALSE, &len )) || !*str) ShowWindow( hwnd, SW_HIDE ); else { ShowWindow( hwnd, SW_SHOWNOACTIVATE ); RedrawWindow( hwnd, NULL, NULL, RDW_ERASENOW | RDW_INVALIDATE ); } - - if (string) ImmUnlockIMCC( ctx->hCompStr ); + free( str ); ctx->hWnd = GetFocus(); } From bd86248c88860f70281935549f549d177c0ff22f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 8 Aug 2023 17:55:31 +0200 Subject: [PATCH 2216/2777] imm32: Return success from WM_IME_CONTROL. CW-Bug-Id: #22569 --- dlls/imm32/ime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c index 3217b6c6562..38a2a070117 100644 --- a/dlls/imm32/ime.c +++ b/dlls/imm32/ime.c @@ -434,7 +434,7 @@ static LRESULT WINAPI ime_ui_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LP case WM_IME_CONTROL: FIXME( "hwnd %p, himc %p, msg %s, wparam %s, lparam %#Ix stub!\n", hwnd, himc, debugstr_wm_ime(msg), debugstr_imc(wparam), lparam ); - return 1; + return 0; } return DefWindowProcW( hwnd, msg, wparam, lparam ); From d9d4f27bc3ae540240a595c5686e38ae06e37ef6 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Fri, 4 Aug 2023 13:41:42 -0400 Subject: [PATCH 2217/2777] sapi: Call CoInitializeEx/CoUninitialize in async_worker. (cherry picked from commit 679e3a9d003f2bb0d11e620171a048f23ac82fc6) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/async.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/sapi/async.c b/dlls/sapi/async.c index b02778ae7ba..61b99019abe 100644 --- a/dlls/sapi/async.c +++ b/dlls/sapi/async.c @@ -71,6 +71,7 @@ static void CALLBACK async_worker(TP_CALLBACK_INSTANCE *instance, void *ctx) HANDLE handles[2] = { queue->cancel, queue->wait }; DWORD ret; + CoInitializeEx(NULL, COINIT_MULTITHREADED); SetEvent(queue->ready); for (;;) @@ -99,6 +100,7 @@ static void CALLBACK async_worker(TP_CALLBACK_INSTANCE *instance, void *ctx) cancel: async_empty_queue(queue); + CoUninitialize(); TRACE("cancelled.\n"); SetEvent(queue->ready); } From 050699729bff10f29e60786bef8d054ab5e91004 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Fri, 4 Aug 2023 13:43:13 -0400 Subject: [PATCH 2218/2777] sapi: Start async queue in ISpVoice::SetOutput. (cherry picked from commit cdc3eeb77638f925e2af1228f32255bcb4fd719f) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tts.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/sapi/tts.c b/dlls/sapi/tts.c index 4763ef9f324..b1c90627d5e 100644 --- a/dlls/sapi/tts.c +++ b/dlls/sapi/tts.c @@ -591,6 +591,9 @@ static HRESULT WINAPI spvoice_SetOutput(ISpVoice *iface, IUnknown *unk, BOOL all if (!allow_format_changes) FIXME("ignoring allow_format_changes = FALSE.\n"); + if (FAILED(hr = async_start_queue(&This->queue))) + return hr; + if (!unk) { /* TODO: Create the default SpAudioOut token here once SpMMAudioEnum is implemented. */ From e2e806a50f417d8e4d63622ff6f2d3f8671c95a5 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Fri, 4 Aug 2023 13:44:04 -0400 Subject: [PATCH 2219/2777] sapi/tests: Add test for implicit MTA initialized by SpVoice. Based on a patch by Connor McAdams. (cherry picked from commit 738bbeb9b7d6be802119cb0d78735a1fbf023d0b) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/tts.c | 96 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 3 deletions(-) diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index 39f62ac551e..eb0258bbef3 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -34,6 +34,46 @@ static void _expect_ref(IUnknown *obj, ULONG ref, int line) ok_(__FILE__,line)(rc == ref, "Unexpected refcount %ld, expected %ld.\n", rc, ref); } +#define APTTYPE_UNITIALIZED APTTYPE_CURRENT +static struct +{ + APTTYPE type; + APTTYPEQUALIFIER qualifier; +} test_apt_data; + +static DWORD WINAPI test_apt_thread(void *param) +{ + HRESULT hr; + + hr = CoGetApartmentType(&test_apt_data.type, &test_apt_data.qualifier); + if (hr == CO_E_NOTINITIALIZED) + { + test_apt_data.type = APTTYPE_UNITIALIZED; + test_apt_data.qualifier = 0; + } + + return 0; +} + +static void check_apttype(void) +{ + HANDLE thread; + MSG msg; + + memset(&test_apt_data, 0xde, sizeof(test_apt_data)); + + thread = CreateThread(NULL, 0, test_apt_thread, NULL, 0, NULL); + while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0) + { + while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + CloseHandle(thread); +} + static void test_interfaces(void) { ISpeechVoice *speech_voice, *speech_voice2; @@ -380,6 +420,7 @@ static void test_spvoice(void) static const WCHAR test_text[] = L"Hello! This is a test sentence."; ISpVoice *voice; + IUnknown *dummy; ISpMMSysAudio *audio_out; ISpObjectTokenCategory *token_cat; ISpObjectToken *token; @@ -397,23 +438,57 @@ static void test_spvoice(void) return; } + check_apttype(); + ok(test_apt_data.type == APTTYPE_UNITIALIZED, "got apt type %d.\n", test_apt_data.type); + hr = CoCreateInstance(&CLSID_SpVoice, NULL, CLSCTX_INPROC_SERVER, &IID_ISpVoice, (void **)&voice); ok(hr == S_OK, "Failed to create SpVoice: %#lx.\n", hr); - hr = ISpVoice_SetOutput(voice, NULL, TRUE); - ok(hr == S_OK, "got %#lx.\n", hr); + check_apttype(); + ok(test_apt_data.type == APTTYPE_UNITIALIZED, "got apt type %d.\n", test_apt_data.type); + + /* SpVoice initializes a MTA in SetOutput even if an invalid output object is given. */ + hr = CoCreateInstance(&CLSID_SpDataKey, NULL, CLSCTX_INPROC_SERVER, + &IID_IUnknown, (void **)&dummy); + ok(hr == S_OK, "Failed to create dummy: %#lx.\n", hr); + + hr = ISpVoice_SetOutput(voice, dummy, TRUE); + ok(hr == E_INVALIDARG, "got %#lx.\n", hr); + + check_apttype(); + ok(test_apt_data.type == APTTYPE_MTA || broken(test_apt_data.type == APTTYPE_UNITIALIZED) /* w8, w10v1507 */, + "got apt type %d.\n", test_apt_data.type); + if (test_apt_data.type == APTTYPE_MTA) + ok(test_apt_data.qualifier == APTTYPEQUALIFIER_IMPLICIT_MTA, + "got apt type qualifier %d.\n", test_apt_data.qualifier); + else + win_skip("apt type is not MTA.\n"); + + IUnknown_Release(dummy); hr = CoCreateInstance(&CLSID_SpMMAudioOut, NULL, CLSCTX_INPROC_SERVER, &IID_ISpMMSysAudio, (void **)&audio_out); ok(hr == S_OK, "Failed to create SpMMAudioOut: %#lx.\n", hr); + hr = ISpVoice_SetOutput(voice, NULL, TRUE); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = ISpVoice_SetOutput(voice, (IUnknown *)audio_out, TRUE); todo_wine ok(hr == S_FALSE, "got %#lx.\n", hr); hr = ISpVoice_SetVoice(voice, NULL); todo_wine ok(hr == S_OK, "got %#lx.\n", hr); + check_apttype(); + ok(test_apt_data.type == APTTYPE_MTA || broken(test_apt_data.type == APTTYPE_UNITIALIZED) /* w8, w10v1507 */, + "got apt type %d.\n", test_apt_data.type); + if (test_apt_data.type == APTTYPE_MTA) + ok(test_apt_data.qualifier == APTTYPEQUALIFIER_IMPLICIT_MTA, + "got apt type qualifier %d.\n", test_apt_data.qualifier); + else + win_skip("apt type is not MTA.\n"); + hr = ISpVoice_GetVoice(voice, &token); todo_wine ok(hr == S_OK, "got %#lx.\n", hr); @@ -517,6 +592,15 @@ static void test_spvoice(void) hr = ISpVoice_SetVoice(voice, token); ok(hr == S_OK, "got %#lx.\n", hr); + check_apttype(); + ok(test_apt_data.type == APTTYPE_MTA || broken(test_apt_data.type == APTTYPE_UNITIALIZED) /* w8, w10v1507 */, + "got apt type %d.\n", test_apt_data.type); + if (test_apt_data.type == APTTYPE_MTA) + ok(test_apt_data.qualifier == APTTYPEQUALIFIER_IMPLICIT_MTA, + "got apt type qualifier %d.\n", test_apt_data.qualifier); + else + win_skip("apt type is not MTA.\n"); + test_engine.speak_called = FALSE; hr = ISpVoice_Speak(voice, NULL, SPF_PURGEBEFORESPEAK, NULL); ok(hr == S_OK, "got %#lx.\n", hr); @@ -548,6 +632,11 @@ static void test_spvoice(void) ok(stream_num == 1, "got %lu.\n", stream_num); ok(duration > 800 && duration < 3000, "took %lu ms.\n", duration); + check_apttype(); + ok(test_apt_data.type == APTTYPE_MTA, "got apt type %d.\n", test_apt_data.type); + ok(test_apt_data.qualifier == APTTYPEQUALIFIER_IMPLICIT_MTA, + "got apt type qualifier %d.\n", test_apt_data.qualifier); + start = GetTickCount(); hr = ISpVoice_WaitUntilDone(voice, INFINITE); duration = GetTickCount() - start; @@ -602,7 +691,8 @@ static void test_spvoice(void) START_TEST(tts) { CoInitialize(NULL); - test_interfaces(); + /* Run spvoice tests before interface tests so that a MTA won't be created before this test is run. */ test_spvoice(); + test_interfaces(); CoUninitialize(); } From fa64f49ad69e297e446ae81b89efb9119802bbae Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Fri, 4 Aug 2023 13:51:17 -0400 Subject: [PATCH 2220/2777] sapi: Change ISpObjectToken::SetId FIXME to TRACE. (cherry picked from commit b9dbe482eea774122d2293a3bb3bdb0f0e645a88) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/token.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c index af98db02048..f599bdb6b14 100644 --- a/dlls/sapi/token.c +++ b/dlls/sapi/token.c @@ -1305,7 +1305,7 @@ static HRESULT WINAPI token_SetId( ISpObjectToken *iface, HKEY root, key; const WCHAR *subkey; - FIXME( "(%p)->(%s %s %d): semi-stub\n", This, debugstr_w( category_id ), + TRACE( "(%p)->(%s %s %d)\n", This, debugstr_w( category_id ), debugstr_w(token_id), create ); if (This->data_key) return SPERR_ALREADY_INITIALIZED; From 905dd28173c3a98cbe444926ac9d0101a3e889a0 Mon Sep 17 00:00:00 2001 From: Shaun Ren Date: Fri, 4 Aug 2023 13:57:55 -0400 Subject: [PATCH 2221/2777] sapi/tests: Increase timeout in tts test_spvoice. (cherry picked from commit cff2e87e03ff045fbe1a3718a81574fe077ab189) CW-Bug-Id: #18723 CW-Bug-Id: #20918 CW-Bug-Id: #21259 --- dlls/sapi/tests/tts.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/sapi/tests/tts.c b/dlls/sapi/tests/tts.c index eb0258bbef3..6912dc08e0d 100644 --- a/dlls/sapi/tests/tts.c +++ b/dlls/sapi/tests/tts.c @@ -630,7 +630,7 @@ static void test_spvoice(void) ok(test_engine.rate == 0, "got %ld.\n", test_engine.rate); ok(test_engine.volume == 100, "got %d.\n", test_engine.volume); ok(stream_num == 1, "got %lu.\n", stream_num); - ok(duration > 800 && duration < 3000, "took %lu ms.\n", duration); + ok(duration > 800 && duration < 3500, "took %lu ms.\n", duration); check_apttype(); ok(test_apt_data.type == APTTYPE_MTA, "got apt type %d.\n", test_apt_data.type); @@ -658,7 +658,7 @@ static void test_spvoice(void) hr = ISpVoice_WaitUntilDone(voice, INFINITE); duration = GetTickCount() - start; ok(hr == S_OK, "got %#lx.\n", hr); - ok(duration > 800 && duration < 3000, "took %lu ms.\n", duration); + ok(duration > 800 && duration < 3500, "took %lu ms.\n", duration); ok(test_engine.speak_called, "ISpTTSEngine::Speak was not called.\n"); ok(test_engine.flags == SPF_NLP_SPEAK_PUNC, "got %#lx.\n", test_engine.flags); From 74300abe0b1a276391f5d64d3fafc667fc3938c9 Mon Sep 17 00:00:00 2001 From: Santino Mazza Date: Mon, 14 Aug 2023 16:21:07 -0300 Subject: [PATCH 2222/2777] evr: Release sample queue when streaming ends. (cherry picked from commit 072fe5d62a63b9b46de030a5d3d437cf9ff481a8) --- dlls/evr/presenter.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index 06592f8766e..97080717288 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -467,6 +467,18 @@ static BOOL video_presenter_sample_queue_pop(struct video_presenter *presenter, return *sample != NULL; } + +static void video_presenter_sample_queue_free(struct video_presenter *presenter) +{ + struct sample_queue *queue = &presenter->thread.queue; + IMFSample *sample; + + while (video_presenter_sample_queue_pop(presenter, &sample)) + IMFSample_Release(sample); + + free(queue->samples); +} + static HRESULT video_presenter_get_sample_surface(IMFSample *sample, IDirect3DSurface9 **surface) { IMFMediaBuffer *buffer; @@ -754,6 +766,7 @@ static HRESULT video_presenter_end_streaming(struct video_presenter *presenter) if (presenter->thread.queue.last_presented) IMFSample_Release(presenter->thread.queue.last_presented); + video_presenter_sample_queue_free(presenter); memset(&presenter->thread, 0, sizeof(presenter->thread)); video_presenter_set_allocator_callback(presenter, NULL); From 768bd5aa15561a9ee10e47d916db685a564a0ada Mon Sep 17 00:00:00 2001 From: Santino Mazza Date: Mon, 31 Jul 2023 11:44:35 -0300 Subject: [PATCH 2223/2777] evr: Create critical section for sample queue. (cherry picked from commit 7c0731e1849ea2c007783145d7335f7b4fce7081) --- dlls/evr/presenter.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index 97080717288..645a2461e4c 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -66,6 +66,7 @@ struct sample_queue unsigned int front; unsigned int back; IMFSample *last_presented; + CRITICAL_SECTION cs; }; struct streaming_thread @@ -425,6 +426,7 @@ static HRESULT video_presenter_sample_queue_init(struct video_presenter *present queue->size = presenter->allocator_capacity; queue->back = queue->size - 1; + InitializeCriticalSection(&queue->cs); return S_OK; } @@ -435,7 +437,7 @@ static void video_presenter_sample_queue_push(struct video_presenter *presenter, struct sample_queue *queue = &presenter->thread.queue; unsigned int idx; - EnterCriticalSection(&presenter->cs); + EnterCriticalSection(&queue->cs); if (queue->used != queue->size) { if (at_front) @@ -446,14 +448,14 @@ static void video_presenter_sample_queue_push(struct video_presenter *presenter, queue->used++; IMFSample_AddRef(sample); } - LeaveCriticalSection(&presenter->cs); + LeaveCriticalSection(&queue->cs); } static BOOL video_presenter_sample_queue_pop(struct video_presenter *presenter, IMFSample **sample) { struct sample_queue *queue = &presenter->thread.queue; - EnterCriticalSection(&presenter->cs); + EnterCriticalSection(&queue->cs); if (queue->used) { *sample = queue->samples[queue->front]; @@ -462,7 +464,7 @@ static BOOL video_presenter_sample_queue_pop(struct video_presenter *presenter, } else *sample = NULL; - LeaveCriticalSection(&presenter->cs); + LeaveCriticalSection(&queue->cs); return *sample != NULL; } @@ -477,6 +479,7 @@ static void video_presenter_sample_queue_free(struct video_presenter *presenter) IMFSample_Release(sample); free(queue->samples); + DeleteCriticalSection(&queue->cs); } static HRESULT video_presenter_get_sample_surface(IMFSample *sample, IDirect3DSurface9 **surface) @@ -502,6 +505,7 @@ static void video_presenter_sample_present(struct video_presenter *presenter, IM { IDirect3DSurface9 *surface, *backbuffer; IDirect3DDevice9 *device; + struct sample_queue *queue = &presenter->thread.queue; HRESULT hr; if (FAILED(hr = video_presenter_get_sample_surface(sample, &surface))) @@ -527,12 +531,12 @@ static void video_presenter_sample_present(struct video_presenter *presenter, IM WARN("Failed to get a backbuffer, hr %#lx.\n", hr); } - 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); + EnterCriticalSection(&queue->cs); + if (queue->last_presented) + IMFSample_Release(queue->last_presented); + queue->last_presented = sample; + IMFSample_AddRef(queue->last_presented); + LeaveCriticalSection(&queue->cs); IDirect3DSurface9_Release(surface); } From 61bf462cbcc698e0ec792e2cd810c58131a67733 Mon Sep 17 00:00:00 2001 From: Santino Mazza Date: Wed, 9 Aug 2023 19:43:42 -0300 Subject: [PATCH 2224/2777] evr: Don't lock presenter allocator when calling NotifyRelease. The changes in the video sample allocator are not part of the public api specification, it's only made for internal use in the evr presenter implementation. (cherry picked from commit fa3ebd5044d26e6364e0ea0068cb3c4716b50b4e) --- dlls/evr/evr_private.h | 2 ++ dlls/evr/presenter.c | 2 +- dlls/evr/sample.c | 30 ++++++++++++++++++++++++++---- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/dlls/evr/evr_private.h b/dlls/evr/evr_private.h index ef38b0f70cf..93047b50c94 100644 --- a/dlls/evr/evr_private.h +++ b/dlls/evr/evr_private.h @@ -55,4 +55,6 @@ HRESULT evr_filter_create(IUnknown *outer_unk, void **ppv) DECLSPEC_HIDDEN; HRESULT evr_mixer_create(IUnknown *outer_unk, void **ppv) DECLSPEC_HIDDEN; HRESULT evr_presenter_create(IUnknown *outer_unk, void **ppv) DECLSPEC_HIDDEN; +HRESULT create_video_sample_allocator(BOOL lock_notify_release, REFIID riid, void **obj); + #endif /* __EVR_PRIVATE_INCLUDED__ */ diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index 645a2461e4c..3ae9b24ad4a 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -2149,7 +2149,7 @@ static HRESULT video_presenter_init_d3d(struct video_presenter *presenter) if (FAILED(hr)) WARN("Failed to set new device for the manager, hr %#lx.\n", hr); - if (SUCCEEDED(hr = MFCreateVideoSampleAllocator(&IID_IMFVideoSampleAllocator, (void **)&presenter->allocator))) + if (SUCCEEDED(hr = create_video_sample_allocator(FALSE, &IID_IMFVideoSampleAllocator, (void **)&presenter->allocator))) { hr = IMFVideoSampleAllocator_SetDirectXManager(presenter->allocator, (IUnknown *)presenter->device_manager); } diff --git a/dlls/evr/sample.c b/dlls/evr/sample.c index 6a1bbf564f5..aa3f120b115 100644 --- a/dlls/evr/sample.c +++ b/dlls/evr/sample.c @@ -395,6 +395,7 @@ struct sample_allocator unsigned int free_sample_count; struct list free_samples; struct list used_samples; + BOOL lock_notify_release; CRITICAL_SECTION cs; }; @@ -809,6 +810,7 @@ static HRESULT WINAPI sample_allocator_tracking_callback_Invoke(IMFAsyncCallback struct queued_sample *iter; IUnknown *object = NULL; IMFSample *sample = NULL; + IMFVideoSampleAllocatorNotify *callback = NULL; HRESULT hr; if (FAILED(IMFAsyncResult_GetObject(result, &object))) @@ -836,10 +838,24 @@ static HRESULT WINAPI sample_allocator_tracking_callback_Invoke(IMFAsyncCallback IMFSample_Release(sample); if (allocator->callback) - IMFVideoSampleAllocatorNotify_NotifyRelease(allocator->callback); + { + if (allocator->lock_notify_release) + IMFVideoSampleAllocatorNotify_NotifyRelease(allocator->callback); + else + { + callback = allocator->callback; + IMFVideoSampleAllocatorNotify_AddRef(callback); + } + } LeaveCriticalSection(&allocator->cs); + if (callback) + { + IMFVideoSampleAllocatorNotify_NotifyRelease(callback); + IMFVideoSampleAllocatorNotify_Release(callback); + } + return S_OK; } @@ -852,13 +868,11 @@ static const IMFAsyncCallbackVtbl sample_allocator_tracking_callback_vtbl = sample_allocator_tracking_callback_Invoke, }; -HRESULT WINAPI MFCreateVideoSampleAllocator(REFIID riid, void **obj) +HRESULT create_video_sample_allocator(BOOL lock_notify_release, REFIID riid, void **obj) { struct sample_allocator *object; HRESULT hr; - TRACE("%s, %p.\n", debugstr_guid(riid), obj); - if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; @@ -868,6 +882,7 @@ HRESULT WINAPI MFCreateVideoSampleAllocator(REFIID riid, void **obj) object->refcount = 1; list_init(&object->used_samples); list_init(&object->free_samples); + object->lock_notify_release = lock_notify_release; InitializeCriticalSection(&object->cs); hr = IMFVideoSampleAllocator_QueryInterface(&object->IMFVideoSampleAllocator_iface, riid, obj); @@ -876,6 +891,13 @@ HRESULT WINAPI MFCreateVideoSampleAllocator(REFIID riid, void **obj) return hr; } +HRESULT WINAPI MFCreateVideoSampleAllocator(REFIID riid, void **obj) +{ + TRACE("%s, %p.\n", debugstr_guid(riid), obj); + + return create_video_sample_allocator(TRUE, riid, obj); +} + static HRESULT WINAPI video_sample_QueryInterface(IMFSample *iface, REFIID riid, void **out) { struct video_sample *sample = impl_from_IMFSample(iface); From 533c0651555b5673e4aae0613248b757cd9b37df Mon Sep 17 00:00:00 2001 From: Santino Mazza Date: Thu, 3 Aug 2023 12:23:17 -0300 Subject: [PATCH 2225/2777] evr: Remove process input handling from streaming thread. (cherry picked from commit f8cf88dcf4e23e23b087e95eda746348aff24ad5) --- dlls/evr/presenter.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index 3ae9b24ad4a..2dc01608caf 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -55,7 +55,6 @@ enum streaming_thread_message { EVRM_STOP = WM_USER, EVRM_PRESENT = WM_USER + 1, - EVRM_PROCESS_INPUT = WM_USER + 2, }; struct sample_queue @@ -706,11 +705,6 @@ static DWORD CALLBACK video_presenter_streaming_thread(void *arg) } break; - case EVRM_PROCESS_INPUT: - EnterCriticalSection(&presenter->cs); - video_presenter_process_input(presenter); - LeaveCriticalSection(&presenter->cs); - break; default: ; } @@ -1811,9 +1805,9 @@ static HRESULT WINAPI video_presenter_allocator_cb_NotifyRelease(IMFVideoSampleA { struct video_presenter *presenter = impl_from_IMFVideoSampleAllocatorNotify(iface); - /* Release notification is executed under allocator lock, instead of processing samples here - notify streaming thread. */ - PostThreadMessageW(presenter->thread.tid, EVRM_PROCESS_INPUT, 0, 0); + EnterCriticalSection(&presenter->cs); + video_presenter_process_input(presenter); + LeaveCriticalSection(&presenter->cs); return S_OK; } From e2d344ee6a4791a24fbaa183765ff6ec8e604a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Tue, 8 Aug 2023 17:46:43 +0200 Subject: [PATCH 2226/2777] Revert "mfmediaengine: Add support for inserting video effects." This reverts commit 5bb1f1fa49afb44a9f4cba896265fe521b939b45. --- dlls/mfmediaengine/main.c | 51 +++------------------------------------ 1 file changed, 3 insertions(+), 48 deletions(-) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 837aaaae106..12263941583 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -150,8 +150,6 @@ struct media_engine { IUnknown *audio; BOOL audio_optional; - IUnknown *video; - BOOL video_optional; } effects; struct { @@ -1047,27 +1045,6 @@ static HRESULT media_engine_create_audio_effect(struct media_engine *engine, IMF return hr; } -static HRESULT media_engine_create_video_effect(struct media_engine *engine, IMFTopologyNode **node) -{ - HRESULT hr; - - *node = NULL; - - if (!engine->effects.video) - return S_OK; - - if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, node))) - return hr; - - IMFTopologyNode_SetObject(*node, (IUnknown *)engine->effects.video); - IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE); - - IUnknown_Release(engine->effects.video); - engine->effects.video = NULL; - - return hr; -} - static HRESULT media_engine_create_audio_renderer(struct media_engine *engine, IMFTopologyNode **node) { unsigned int category, role; @@ -1239,7 +1216,7 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi if (SUCCEEDED(hr = MFCreateTopology(&topology))) { IMFTopologyNode *sar_node = NULL, *audio_src = NULL, *audio_effect = NULL; - IMFTopologyNode *grabber_node = NULL, *video_src = NULL, *video_effect = NULL; + IMFTopologyNode *grabber_node = NULL, *video_src = NULL; if (engine->flags & MF_MEDIA_ENGINE_REAL_TIME_MODE) IMFTopology_SetUINT32(topology, &MF_LOW_LATENCY, TRUE); @@ -1286,18 +1263,7 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi if (FAILED(hr = media_engine_create_video_renderer(engine, &grabber_node))) WARN("Failed to create video grabber node, hr %#lx.\n", hr); - if (FAILED(media_engine_create_video_effect(engine, &video_effect))) - WARN("Failed to create video effect node, hr %#lx.\n", hr); - - if (grabber_node && video_src && video_effect) - { - IMFTopology_AddNode(topology, video_src); - IMFTopology_AddNode(topology, grabber_node); - IMFTopology_AddNode(topology, video_effect); - IMFTopologyNode_ConnectOutput(video_src, 0, video_effect, 0); - IMFTopologyNode_ConnectOutput(video_effect, 0, grabber_node, 0); - } - else if (grabber_node && video_src) + if (grabber_node && video_src) { IMFTopology_AddNode(topology, video_src); IMFTopology_AddNode(topology, grabber_node); @@ -2653,20 +2619,9 @@ static HRESULT WINAPI media_engine_IsProtected(IMFMediaEngineEx *iface, BOOL *pr static HRESULT WINAPI media_engine_InsertVideoEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional) { - struct media_engine *impl = impl_from_IMFMediaEngineEx(iface); FIXME("%p, %p, %d stub.\n", iface, effect, is_optional); - if (!effect) - return E_POINTER; - - if (impl->effects.video) - return MF_E_INVALIDREQUEST; - - impl->effects.video = effect; - IUnknown_AddRef(impl->effects.video); - impl->effects.video_optional = is_optional; - - return S_OK; + return E_NOTIMPL; } static HRESULT WINAPI media_engine_InsertAudioEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional) From e9c575406ea5870be811accdb8780bebb0671f0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Tue, 8 Aug 2023 17:46:54 +0200 Subject: [PATCH 2227/2777] Revert "mfmediaengine: Add support for inserting audio effects." This reverts commit ee95a94b993550e12befe8b84b2c171a22441de3. --- dlls/mfmediaengine/main.c | 57 +++------------------------------------ 1 file changed, 3 insertions(+), 54 deletions(-) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 12263941583..c7c74119fa3 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -16,7 +16,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "winerror.h" #define COBJMACROS #include @@ -147,11 +146,6 @@ struct media_engine IMFPresentationDescriptor *pd; } presentation; struct - { - IUnknown *audio; - BOOL audio_optional; - } effects; - struct { LONGLONG pts; SIZE size; @@ -1024,27 +1018,6 @@ static HRESULT media_engine_create_source_node(IMFMediaSource *source, IMFPresen return S_OK; } -static HRESULT media_engine_create_audio_effect(struct media_engine *engine, IMFTopologyNode **node) -{ - HRESULT hr; - - *node = NULL; - - if (!engine->effects.audio) - return S_OK; - - if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, node))) - return hr; - - IMFTopologyNode_SetObject(*node, (IUnknown *)engine->effects.audio); - IMFTopologyNode_SetUINT32(*node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE); - - IUnknown_Release(engine->effects.audio); - engine->effects.audio = NULL; - - return hr; -} - static HRESULT media_engine_create_audio_renderer(struct media_engine *engine, IMFTopologyNode **node) { unsigned int category, role; @@ -1215,7 +1188,7 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi if (SUCCEEDED(hr = MFCreateTopology(&topology))) { - IMFTopologyNode *sar_node = NULL, *audio_src = NULL, *audio_effect = NULL; + IMFTopologyNode *sar_node = NULL, *audio_src = NULL; IMFTopologyNode *grabber_node = NULL, *video_src = NULL; if (engine->flags & MF_MEDIA_ENGINE_REAL_TIME_MODE) @@ -1229,18 +1202,7 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi if (FAILED(hr = media_engine_create_audio_renderer(engine, &sar_node))) WARN("Failed to create audio renderer node, hr %#lx.\n", hr); - if (FAILED(media_engine_create_audio_effect(engine, &audio_effect))) - WARN("Failed to create audio effect node, hr %#lx.\n", hr); - - if (sar_node && audio_src && audio_effect) - { - IMFTopology_AddNode(topology, audio_src); - IMFTopology_AddNode(topology, sar_node); - IMFTopology_AddNode(topology, audio_effect); - IMFTopologyNode_ConnectOutput(audio_src, 0, audio_effect, 0); - IMFTopologyNode_ConnectOutput(audio_effect, 0, sar_node, 0); - } - else if (sar_node && audio_src) + if (sar_node && audio_src) { IMFTopology_AddNode(topology, audio_src); IMFTopology_AddNode(topology, sar_node); @@ -1249,8 +1211,6 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi if (sar_node) IMFTopologyNode_Release(sar_node); - if (audio_effect) - IMFTopologyNode_Release(audio_effect); if (audio_src) IMFTopologyNode_Release(audio_src); } @@ -2626,20 +2586,9 @@ static HRESULT WINAPI media_engine_InsertVideoEffect(IMFMediaEngineEx *iface, IU static HRESULT WINAPI media_engine_InsertAudioEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional) { - struct media_engine *impl = impl_from_IMFMediaEngineEx(iface); FIXME("%p, %p, %d stub.\n", iface, effect, is_optional); - if (!effect) - return E_POINTER; - - if (impl->effects.audio) - return MF_E_INVALIDREQUEST; - - impl->effects.audio = effect; - IUnknown_AddRef(impl->effects.audio); - impl->effects.audio_optional = is_optional; - - return S_OK; + return E_NOTIMPL; } static HRESULT WINAPI media_engine_RemoveAllEffects(IMFMediaEngineEx *iface) From b539dbc9e1131bfca5085f8a8347753b05e496ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Mon, 5 Dec 2022 23:46:20 +0100 Subject: [PATCH 2228/2777] mfmediaengine: Add support for inserting video effects. (cherry picked from commit de1dd6cbf79d451ca35cd63810557e3d347e0211) --- dlls/mfmediaengine/main.c | 110 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 3 deletions(-) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index c7c74119fa3..57ddbcc7de0 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -113,6 +113,19 @@ struct rect float left, top, right, bottom; }; +struct effect +{ + IUnknown *object; + BOOL optional; +}; + +struct effects +{ + struct effect *effects; + size_t count; + size_t capacity; +}; + struct media_engine { IMFMediaEngineEx IMFMediaEngineEx_iface; @@ -145,6 +158,7 @@ struct media_engine IMFMediaSource *source; IMFPresentationDescriptor *pd; } presentation; + struct effects video_effects; struct { LONGLONG pts; @@ -1018,6 +1032,46 @@ static HRESULT media_engine_create_source_node(IMFMediaSource *source, IMFPresen return S_OK; } +static HRESULT media_engine_create_effects(struct effect *effects, size_t count, + IMFTopologyNode *src, IMFTopologyNode *sink, IMFTopology *topology) +{ + IMFTopologyNode *last = src; + HRESULT hr = S_OK; + size_t i; + + IMFTopologyNode_AddRef(last); + + for (i = 0; i < count; ++i) + { + IMFTopologyNode *node = NULL; + + if (FAILED(hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &node))) + { + WARN("Failed to create transform node, hr %#lx", hr); + break; + } + + IMFTopologyNode_SetObject(node, (IUnknown *)effects[i].object); + IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE); + + if (effects[i].optional) + IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_CONNECT_METHOD, MF_CONNECT_AS_OPTIONAL); + + IMFTopology_AddNode(topology, node); + IMFTopologyNode_ConnectOutput(last, 0, node, 0); + + IMFTopologyNode_Release(last); + last = node; + } + + IMFTopologyNode_Release(last); + + if (SUCCEEDED(hr)) + hr = IMFTopologyNode_ConnectOutput(last, 0, sink, 0); + + return hr; +} + static HRESULT media_engine_create_audio_renderer(struct media_engine *engine, IMFTopologyNode **node) { unsigned int category, role; @@ -1105,6 +1159,20 @@ static void media_engine_clear_presentation(struct media_engine *engine) memset(&engine->presentation, 0, sizeof(engine->presentation)); } +static void media_engine_clear_effects(struct effects *effects) +{ + size_t i; + + for (i = 0; i < effects->count; ++i) + { + if (effects->effects[i].object) + IUnknown_Release(effects->effects[i].object); + } + + free(effects->effects); + memset(effects, 0, sizeof(*effects)); +} + static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMediaSource *source) { IMFStreamDescriptor *sd_audio = NULL, *sd_video = NULL; @@ -1227,7 +1295,10 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi { IMFTopology_AddNode(topology, video_src); IMFTopology_AddNode(topology, grabber_node); - IMFTopologyNode_ConnectOutput(video_src, 0, grabber_node, 0); + + if (FAILED(hr = media_engine_create_effects(engine->video_effects.effects, engine->video_effects.count, + video_src, grabber_node, topology))) + WARN("Failed to create video effect nodes, hr %#lx.\n", hr); } if (SUCCEEDED(hr)) @@ -1382,6 +1453,7 @@ static void free_media_engine(struct media_engine *engine) IMFAttributes_Release(engine->attributes); if (engine->resolver) IMFSourceResolver_Release(engine->resolver); + media_engine_clear_effects(&engine->video_effects); media_engine_release_video_frame_resources(engine); media_engine_clear_presentation(engine); if (engine->device_manager) @@ -2577,11 +2649,43 @@ static HRESULT WINAPI media_engine_IsProtected(IMFMediaEngineEx *iface, BOOL *pr return E_NOTIMPL; } +static HRESULT media_engine_insert_effect(struct media_engine *engine, struct effects *effects, IUnknown *object, BOOL is_optional) +{ + HRESULT hr = S_OK; + + if (engine->flags & FLAGS_ENGINE_SHUT_DOWN) + hr = MF_E_SHUTDOWN; + else if (!mf_array_reserve((void **)&effects->effects, &effects->capacity, effects->count + 1, sizeof(*effects->effects))) + { + hr = E_OUTOFMEMORY; + } + else + { + effects->effects[effects->count].object = object; + if (object) + { + IUnknown_AddRef(effects->effects[effects->count].object); + } + effects->effects[effects->count].optional = is_optional; + + effects->count++; + } + + return hr; +} + static HRESULT WINAPI media_engine_InsertVideoEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional) { - FIXME("%p, %p, %d stub.\n", iface, effect, is_optional); + struct media_engine *engine = impl_from_IMFMediaEngineEx(iface); + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("%p, %p, %d.\n", iface, effect, is_optional); + + EnterCriticalSection(&engine->cs); + hr = media_engine_insert_effect(engine, &engine->video_effects, effect, is_optional); + LeaveCriticalSection(&engine->cs); + + return hr; } static HRESULT WINAPI media_engine_InsertAudioEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional) From 77b5eb9eced4b8fb34cde3b9e26ed1a4369ba790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Sun, 4 Dec 2022 00:03:50 +0100 Subject: [PATCH 2229/2777] mfmediaengine: Add support for inserting audio effects. (cherry picked from commit 91a84cff9570d97be3ba3ce915b0cb91541cb480) --- dlls/mfmediaengine/main.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 57ddbcc7de0..9ad6174baa1 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -159,6 +159,7 @@ struct media_engine IMFPresentationDescriptor *pd; } presentation; struct effects video_effects; + struct effects audio_effects; struct { LONGLONG pts; @@ -1274,7 +1275,10 @@ static HRESULT media_engine_create_topology(struct media_engine *engine, IMFMedi { IMFTopology_AddNode(topology, audio_src); IMFTopology_AddNode(topology, sar_node); - IMFTopologyNode_ConnectOutput(audio_src, 0, sar_node, 0); + + if (FAILED(hr = media_engine_create_effects(engine->audio_effects.effects, engine->audio_effects.count, + audio_src, sar_node, topology))) + WARN("Failed to create audio effect nodes, hr %#lx.\n", hr); } if (sar_node) @@ -1453,6 +1457,7 @@ static void free_media_engine(struct media_engine *engine) IMFAttributes_Release(engine->attributes); if (engine->resolver) IMFSourceResolver_Release(engine->resolver); + media_engine_clear_effects(&engine->audio_effects); media_engine_clear_effects(&engine->video_effects); media_engine_release_video_frame_resources(engine); media_engine_clear_presentation(engine); @@ -2690,9 +2695,16 @@ static HRESULT WINAPI media_engine_InsertVideoEffect(IMFMediaEngineEx *iface, IU static HRESULT WINAPI media_engine_InsertAudioEffect(IMFMediaEngineEx *iface, IUnknown *effect, BOOL is_optional) { - FIXME("%p, %p, %d stub.\n", iface, effect, is_optional); + struct media_engine *engine = impl_from_IMFMediaEngineEx(iface); + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("%p, %p, %d.\n", iface, effect, is_optional); + + EnterCriticalSection(&engine->cs); + hr = media_engine_insert_effect(engine, &engine->audio_effects, effect, is_optional); + LeaveCriticalSection(&engine->cs); + + return hr; } static HRESULT WINAPI media_engine_RemoveAllEffects(IMFMediaEngineEx *iface) From 237e63746092e6c0c7ac833149bd60737592ae6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Tue, 18 Jul 2023 13:55:08 +0200 Subject: [PATCH 2230/2777] mfmediaengine: Implement RemoveAllEffects(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernhard Kölbl (cherry picked from commit 13106b2b38ca01178060be15c96ee5382cb625dd) --- dlls/mfmediaengine/main.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index 9ad6174baa1..bbe7248c145 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -2709,9 +2709,22 @@ static HRESULT WINAPI media_engine_InsertAudioEffect(IMFMediaEngineEx *iface, IU static HRESULT WINAPI media_engine_RemoveAllEffects(IMFMediaEngineEx *iface) { - FIXME("%p stub.\n", iface); + struct media_engine *engine = impl_from_IMFMediaEngineEx(iface); + HRESULT hr = S_OK; - return E_NOTIMPL; + TRACE("%p.\n", iface); + + EnterCriticalSection(&engine->cs); + if (engine->flags & FLAGS_ENGINE_SHUT_DOWN) + hr = MF_E_SHUTDOWN; + else + { + media_engine_clear_effects(&engine->audio_effects); + media_engine_clear_effects(&engine->video_effects); + } + LeaveCriticalSection(&engine->cs); + + return hr; } static HRESULT WINAPI media_engine_SetTimelineMarkerTimer(IMFMediaEngineEx *iface, double timeout) From 1a625230efd5a9775182601ac27d4a93839ec39a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 17 Aug 2023 11:21:56 +0200 Subject: [PATCH 2231/2777] HACK: winegstreamer: Do not report live latency for some games. CW-Bug-Id: #22581 --- dlls/winegstreamer/h264_decoder.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index c6e817df6b0..bcc40839881 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -113,6 +113,12 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) if (SUCCEEDED(IMFAttributes_GetUINT32(decoder->attributes, &MF_LOW_LATENCY, &low_latency))) attrs.low_latency = !!low_latency; + { + const char *sgi; + if ((sgi = getenv("SteamGameId")) && (!strcmp(sgi, "2009100"))) + attrs.low_latency = FALSE; + } + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs))) return E_FAIL; From c33fa31361e91350e0cd13f7a5f97666830ea3e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 21 Aug 2023 19:17:48 +0200 Subject: [PATCH 2232/2777] HACK: winegstreamer: Don't add unnecessary and slow? videoflip for some games. CW-Bug-Id: #22581 --- dlls/winegstreamer/wg_transform.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 1369b5f6591..a6df4a4d0e0 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -401,6 +401,19 @@ NTSTATUS wg_transform_create(void *args) break; case WG_MAJOR_TYPE_VIDEO: + { + const char *sgi; + if ((sgi = getenv("SteamGameId")) && (!strcmp(sgi, "2009100"))) + { + if (!(element = create_element("videoconvert", "base")) + || !append_element(transform->container, element, &first, &last)) + goto out; + gst_util_set_object_arg(G_OBJECT(element), "n-threads", "0"); + /* HACK: skip slow?? videoflip for some games */ + break; + } + } + if (!(element = create_element("videoconvert", "base")) || !append_element(transform->container, element, &first, &last)) goto out; From 92460954a2700c78648bbc6bfbe9aa273c54ef21 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 21 Aug 2023 12:52:48 -0600 Subject: [PATCH 2233/2777] HACK: winegstreamer: Disable MF_SA_D3D11_AWARE for some games. CW-Bug-Id: #22581 --- dlls/winegstreamer/h264_decoder.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index bcc40839881..1b1646a9ed3 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -887,6 +887,13 @@ HRESULT h264_decoder_create(REFIID riid, void **ret) goto failed; if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, TRUE))) goto failed; + + { + const char *sgi; + if ((sgi = getenv("SteamGameId")) && (!strcmp(sgi, "2009100"))) + IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, FALSE); + } + if (FAILED(hr = MFCreateAttributes(&decoder->output_attributes, 0))) goto failed; if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue))) From 79da11e94637b3587a49dd3f0524b5e94aaa0a56 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Thu, 31 Aug 2023 09:25:29 +0200 Subject: [PATCH 2234/2777] ntdll/tests: Add test for Win10 OutputDebugStringW evolution. Signed-off-by: Eric Pouech (cherry picked from commit b7004335c5f4509ecd2518aa8ed3d0e7db2a653e) --- dlls/ntdll/tests/exception.c | 155 +++++++++++++++++++++++++++++++---- 1 file changed, 138 insertions(+), 17 deletions(-) diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 98624d3b7ac..2155e47b9ab 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -76,6 +76,7 @@ static BOOL (WINAPI *pInitializeContext2)(void *buffer, DWORD context_flags static void * (WINAPI *pLocateXStateFeature)(CONTEXT *context, DWORD feature_id, DWORD *length); static BOOL (WINAPI *pSetXStateFeaturesMask)(CONTEXT *context, DWORD64 feature_mask); static BOOL (WINAPI *pGetXStateFeaturesMask)(CONTEXT *context, DWORD64 *feature_mask); +static BOOL (WINAPI *pWaitForDebugEventEx)(DEBUG_EVENT *, DWORD); #define RTL_UNLOAD_EVENT_TRACE_NUMBER 64 @@ -8445,25 +8446,43 @@ static void test_debug_service(DWORD numexc) } #endif /* defined(__i386__) || defined(__x86_64__) */ -static DWORD outputdebugstring_exceptions; +static DWORD outputdebugstring_exceptions_ansi; +static DWORD outputdebugstring_exceptions_unicode; static LONG CALLBACK outputdebugstring_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo) { PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord; trace("vect. handler %08lx addr:%p\n", rec->ExceptionCode, rec->ExceptionAddress); - ok(rec->ExceptionCode == DBG_PRINTEXCEPTION_C, "ExceptionCode is %08lx instead of %08lx\n", - rec->ExceptionCode, DBG_PRINTEXCEPTION_C); - ok(rec->NumberParameters == 2, "ExceptionParameters is %ld instead of 2\n", rec->NumberParameters); - ok(rec->ExceptionInformation[0] == 12, "ExceptionInformation[0] = %ld instead of 12\n", (DWORD)rec->ExceptionInformation[0]); - ok(!strcmp((char *)rec->ExceptionInformation[1], "Hello World"), - "ExceptionInformation[1] = '%s' instead of 'Hello World'\n", (char *)rec->ExceptionInformation[1]); + switch (rec->ExceptionCode) + { + case DBG_PRINTEXCEPTION_C: + ok(rec->NumberParameters == 2, "ExceptionParameters is %ld instead of 2\n", rec->NumberParameters); + ok(rec->ExceptionInformation[0] == 12, "ExceptionInformation[0] = %ld instead of 12\n", (DWORD)rec->ExceptionInformation[0]); + ok(!strcmp((char *)rec->ExceptionInformation[1], "Hello World"), + "ExceptionInformation[1] = '%s' instead of 'Hello World'\n", (char *)rec->ExceptionInformation[1]); + outputdebugstring_exceptions_ansi++; + break; + case DBG_PRINTEXCEPTION_WIDE_C: + ok(outputdebugstring_exceptions_ansi == 0, "Unicode exception should come first\n"); + ok(rec->NumberParameters == 4, "ExceptionParameters is %ld instead of 4\n", rec->NumberParameters); + ok(rec->ExceptionInformation[0] == 12, "ExceptionInformation[0] = %ld instead of 12\n", (DWORD)rec->ExceptionInformation[0]); + ok(!wcscmp((WCHAR *)rec->ExceptionInformation[1], L"Hello World"), + "ExceptionInformation[1] = '%s' instead of 'Hello World'\n", (char *)rec->ExceptionInformation[1]); + ok(rec->ExceptionInformation[2] == 12, "ExceptionInformation[2] = %ld instead of 12\n", (DWORD)rec->ExceptionInformation[2]); + ok(!strcmp((char *)rec->ExceptionInformation[3], "Hello World"), + "ExceptionInformation[3] = '%s' instead of 'Hello World'\n", (char *)rec->ExceptionInformation[3]); + outputdebugstring_exceptions_unicode++; + break; + default: + ok(0, "ExceptionCode is %08lx unexpected\n", rec->ExceptionCode); + break; + } - outputdebugstring_exceptions++; return EXCEPTION_CONTINUE_SEARCH; } -static void test_outputdebugstring(DWORD numexc, BOOL todo) +static void test_outputdebugstring(BOOL unicode, DWORD numexc_ansi, BOOL todo_ansi, DWORD numexc_unicode) { PVOID vectored_handler; @@ -8476,12 +8495,111 @@ static void test_outputdebugstring(DWORD numexc, BOOL todo) vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &outputdebugstring_vectored_handler); ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n"); - outputdebugstring_exceptions = 0; - OutputDebugStringA("Hello World"); + outputdebugstring_exceptions_ansi = outputdebugstring_exceptions_unicode = 0; + + if (unicode) + OutputDebugStringW(L"Hello World"); + else + OutputDebugStringA("Hello World"); + + todo_wine_if(todo_ansi) + ok(outputdebugstring_exceptions_ansi == numexc_ansi, + "OutputDebugString%c generated %ld ansi exceptions, expected %ld\n", + unicode ? 'W' : 'A', outputdebugstring_exceptions_ansi, numexc_ansi); + todo_wine_if(unicode) + ok(outputdebugstring_exceptions_unicode == numexc_unicode, + "OutputDebugString%c generated %lu unicode exceptions, expected %ld\n", + unicode ? 'W' : 'A', outputdebugstring_exceptions_unicode, numexc_unicode); + + pRtlRemoveVectoredExceptionHandler(vectored_handler); +} + +static DWORD outputdebugstring_exceptions_newmodel_order; +static DWORD outputdebugstring_newmodel_return; + +static LONG CALLBACK outputdebugstring_new_model_vectored_handler(EXCEPTION_POINTERS *ExceptionInfo) +{ + PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord; + trace("vect. handler %08lx addr:%p\n", rec->ExceptionCode, rec->ExceptionAddress); + + switch (rec->ExceptionCode) + { + case DBG_PRINTEXCEPTION_C: + ok(rec->NumberParameters == 2, "ExceptionParameters is %ld instead of 2\n", rec->NumberParameters); + ok(rec->ExceptionInformation[0] == 12, "ExceptionInformation[0] = %ld instead of 12\n", (DWORD)rec->ExceptionInformation[0]); + ok(!strcmp((char *)rec->ExceptionInformation[1], "Hello World"), + "ExceptionInformation[1] = '%s' instead of 'Hello World'\n", (char *)rec->ExceptionInformation[1]); + outputdebugstring_exceptions_newmodel_order = + (outputdebugstring_exceptions_newmodel_order << 8) | 'A'; + break; + case DBG_PRINTEXCEPTION_WIDE_C: + ok(rec->NumberParameters == 4, "ExceptionParameters is %ld instead of 4\n", rec->NumberParameters); + ok(rec->ExceptionInformation[0] == 12, "ExceptionInformation[0] = %ld instead of 12\n", (DWORD)rec->ExceptionInformation[0]); + ok(!wcscmp((WCHAR *)rec->ExceptionInformation[1], L"Hello World"), + "ExceptionInformation[1] = '%s' instead of 'Hello World'\n", (char *)rec->ExceptionInformation[1]); + ok(rec->ExceptionInformation[2] == 12, "ExceptionInformation[2] = %ld instead of 12\n", (DWORD)rec->ExceptionInformation[2]); + ok(!strcmp((char *)rec->ExceptionInformation[3], "Hello World"), + "ExceptionInformation[3] = '%s' instead of 'Hello World'\n", (char *)rec->ExceptionInformation[3]); + outputdebugstring_exceptions_newmodel_order = + (outputdebugstring_exceptions_newmodel_order << 8) | 'W'; + break; + default: + ok(0, "ExceptionCode is %08lx unexpected\n", rec->ExceptionCode); + break; + } + + return outputdebugstring_newmodel_return; +} + +static void test_outputdebugstring_newmodel(void) +{ + PVOID vectored_handler; + struct + { + /* input */ + BOOL unicode; + DWORD ret_code; + /* expected output */ + DWORD exceptions_order; + } + tests[] = + { + {FALSE, EXCEPTION_CONTINUE_EXECUTION, 'A'}, + {FALSE, EXCEPTION_CONTINUE_SEARCH, 'A'}, + {TRUE, EXCEPTION_CONTINUE_EXECUTION, 'W'}, + {TRUE, EXCEPTION_CONTINUE_SEARCH, ('W' << 8) | 'A'}, + }; + int i; + + if (!pWaitForDebugEventEx) + { + skip("Unsupported new unicode debug string model\n"); + return; + } + if (!pRtlAddVectoredExceptionHandler || !pRtlRemoveVectoredExceptionHandler) + { + skip("RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler not found\n"); + return; + } + + vectored_handler = pRtlAddVectoredExceptionHandler(TRUE, &outputdebugstring_new_model_vectored_handler); + ok(vectored_handler != 0, "RtlAddVectoredExceptionHandler failed\n"); + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + outputdebugstring_exceptions_newmodel_order = 0; + outputdebugstring_newmodel_return = tests[i].ret_code; - todo_wine_if(todo) - ok(outputdebugstring_exceptions == numexc, "OutputDebugStringA generated %ld exceptions, expected %ld\n", - outputdebugstring_exceptions, numexc); + if (tests[i].unicode) + OutputDebugStringW(L"Hello World"); + else + OutputDebugStringA("Hello World"); + + ok(outputdebugstring_exceptions_newmodel_order == tests[i].exceptions_order, + "OutputDebugString%c/%u generated exceptions %04lxs, expected %04lx\n", + tests[i].unicode ? 'W' : 'A', i, + outputdebugstring_exceptions_newmodel_order, tests[i].exceptions_order); + } pRtlRemoveVectoredExceptionHandler(vectored_handler); } @@ -10907,6 +11025,7 @@ START_TEST(exception) X(LocateXStateFeature); X(SetXStateFeaturesMask); X(GetXStateFeaturesMask); + X(WaitForDebugEventEx); #undef X if (pRtlAddVectoredExceptionHandler && pRtlRemoveVectoredExceptionHandler) @@ -10955,9 +11074,9 @@ START_TEST(exception) else skip( "RtlRaiseException not found\n" ); #endif test_stage = 3; - test_outputdebugstring(0, FALSE); + test_outputdebugstring(FALSE, 0, FALSE, 0); test_stage = 4; - test_outputdebugstring(2, TRUE); /* is this a Windows bug? */ + test_outputdebugstring(FALSE, 2, TRUE, 0); /* is 2 a Windows bug? */ test_stage = 5; test_ripevent(0); test_stage = 6; @@ -11071,7 +11190,9 @@ START_TEST(exception) test_debugger(DBG_EXCEPTION_HANDLED); test_debugger(DBG_CONTINUE); test_thread_context(); - test_outputdebugstring(1, FALSE); + test_outputdebugstring(FALSE, 1, FALSE, 0); + test_outputdebugstring(TRUE, 1, FALSE, 1); + test_outputdebugstring_newmodel(); test_ripevent(1); test_fastfail(); test_breakpoint(1); From 4a3825c73ffbc19f300e985330514a4aae6b3878 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Thu, 31 Aug 2023 09:25:29 +0200 Subject: [PATCH 2235/2777] ntdll/tests: Introduce enumeration to handle stages in test_debugger(). It'll be easier to add stages. Signed-off-by: Eric Pouech (cherry picked from commit 33db5b78bc7357251172411c93bb13d4359e2f1a) --- dlls/ntdll/tests/exception.c | 211 +++++++++++++++++++---------------- 1 file changed, 116 insertions(+), 95 deletions(-) diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 2155e47b9ab..8b45bcd096d 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -190,14 +190,34 @@ static VOID (WINAPI *pRtlUnwindEx)(VOID*, VOID*, EXCEPTION_RECORD*, VOID*, static int (CDECL *p_setjmp)(_JUMP_BUFFER*); #endif +enum debugger_stages +{ + STAGE_RTLRAISE_NOT_HANDLED = 1, + STAGE_RTLRAISE_HANDLE_LAST_CHANCE, + STAGE_OUTPUTDEBUGSTRINGA_CONTINUE, + STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED, + STAGE_RIPEVENT_CONTINUE, + STAGE_RIPEVENT_NOT_HANDLED, + STAGE_SERVICE_CONTINUE, + STAGE_SERVICE_NOT_HANDLED, + STAGE_BREAKPOINT_CONTINUE, + STAGE_BREAKPOINT_NOT_HANDLED, + STAGE_EXCEPTION_INVHANDLE_CONTINUE, + STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED, + STAGE_NO_EXCEPTION_INVHANDLE_NOT_HANDLED, + STAGE_XSTATE, + STAGE_XSTATE_LEGACY_SSE, + STAGE_SEGMENTS, +}; + static int my_argc; static char** my_argv; static BOOL is_wow64; static BOOL have_vectored_api; -static int test_stage; +static enum debugger_stages test_stage; #if defined(__i386__) || defined(__x86_64__) -static void test_debugger_xstate(HANDLE thread, CONTEXT *ctx, int stage) +static void test_debugger_xstate(HANDLE thread, CONTEXT *ctx, enum debugger_stages stage) { char context_buffer[sizeof(CONTEXT) + sizeof(CONTEXT_EX) + sizeof(XSTATE) + 63]; CONTEXT_EX *c_ex; @@ -212,7 +232,7 @@ static void test_debugger_xstate(HANDLE thread, CONTEXT *ctx, int stage) if (!pRtlGetEnabledExtendedFeatures || !pRtlGetEnabledExtendedFeatures(1 << XSTATE_AVX)) return; - if (stage == 14) + if (stage == STAGE_XSTATE) return; length = sizeof(context_buffer); @@ -525,7 +545,7 @@ static DWORD rtlraiseexception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTR /* give the debugger a chance to examine the state a second time */ /* without the exception handler changing Eip */ - if (test_stage == 2) + if (test_stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) return ExceptionContinueSearch; /* Eip in context is decreased by 1 @@ -1110,7 +1130,7 @@ static void test_debugger(DWORD cont_status) else if (de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { CONTEXT ctx; - int stage; + enum debugger_stages stage; counter++; status = pNtReadVirtualMemory(pi.hProcess, &code_mem, &code_mem_address, @@ -1146,7 +1166,7 @@ static void test_debugger(DWORD cont_status) } else { - if (stage == 1) + if (stage == STAGE_RTLRAISE_NOT_HANDLED) { ok((char *)ctx.Eip == (char *)code_mem_address + 0xb, "Eip at %lx instead of %p\n", ctx.Eip, (char *)code_mem_address + 0xb); @@ -1157,7 +1177,7 @@ static void test_debugger(DWORD cont_status) /* let the debuggee handle the exception */ continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 2) + else if (stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) { if (de.u.Exception.dwFirstChance) { @@ -1193,25 +1213,25 @@ static void test_debugger(DWORD cont_status) /* here we handle exception */ } } - else if (stage == 7 || stage == 8) + else if (stage == STAGE_SERVICE_CONTINUE || stage == STAGE_SERVICE_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "expected EXCEPTION_BREAKPOINT, got %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode); ok((char *)ctx.Eip == (char *)code_mem_address + 0x1d, "expected Eip = %p, got 0x%lx\n", (char *)code_mem_address + 0x1d, ctx.Eip); - if (stage == 8) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_SERVICE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 9 || stage == 10) + else if (stage == STAGE_BREAKPOINT_CONTINUE || stage == STAGE_BREAKPOINT_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "expected EXCEPTION_BREAKPOINT, got %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode); ok((char *)ctx.Eip == (char *)code_mem_address + 2, "expected Eip = %p, got 0x%lx\n", (char *)code_mem_address + 2, ctx.Eip); - if (stage == 10) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_BREAKPOINT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 11 || stage == 12) + else if (stage == STAGE_EXCEPTION_INVHANDLE_CONTINUE || stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_INVALID_HANDLE, "unexpected exception code %08lx, expected %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode, @@ -1219,18 +1239,18 @@ static void test_debugger(DWORD cont_status) ok(de.u.Exception.ExceptionRecord.NumberParameters == 0, "unexpected number of parameters %ld, expected 0\n", de.u.Exception.ExceptionRecord.NumberParameters); - if (stage == 12) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 13) + else if (stage == STAGE_NO_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(FALSE || broken(TRUE) /* < Win10 */, "should not throw exception\n"); continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 14 || stage == 15) + else if (stage == STAGE_XSTATE || stage == STAGE_XSTATE_LEGACY_SSE) { test_debugger_xstate(pi.hThread, &ctx, stage); } - else if (stage == 16) + else if (stage == STAGE_SEGMENTS) { USHORT ss; __asm__( "movw %%ss,%0" : "=r" (ss) ); @@ -1258,7 +1278,7 @@ static void test_debugger(DWORD cont_status) } else if (de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { - int stage; + enum debugger_stages stage; char buffer[64]; status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, @@ -1274,22 +1294,22 @@ static void test_debugger(DWORD cont_status) de.u.DebugString.nDebugStringLength, &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status); - if (stage == 3 || stage == 4) + if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); else /* ignore unrelated debug strings like 'SHIMVIEW: ShimInfo(Complete)' */ ok(strstr(buffer, "SHIMVIEW") != NULL, "unexpected stage %x, got debug string event '%s'\n", stage, buffer); - if (stage == 4) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } else if (de.dwDebugEventCode == RIP_EVENT) { - int stage; + enum debugger_stages stage; status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status); - if (stage == 5 || stage == 6) + if (stage == STAGE_RIPEVENT_CONTINUE || stage == STAGE_RIPEVENT_NOT_HANDLED) { ok(de.u.RipInfo.dwError == 0x11223344, "got unexpected rip error code %08lx, expected %08x\n", de.u.RipInfo.dwError, 0x11223344); @@ -1299,7 +1319,7 @@ static void test_debugger(DWORD cont_status) else ok(FALSE, "unexpected stage %x\n", stage); - if (stage == 6) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_RIPEVENT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } ContinueDebugEvent(de.dwProcessId, de.dwThreadId, continuestatus); @@ -3653,7 +3673,7 @@ static void rtlraiseexception_handler_( EXCEPTION_RECORD *rec, EXCEPTION_REGISTR /* give the debugger a chance to examine the state a second time */ /* without the exception handler changing pc */ - if (test_stage == 2) + if (test_stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) return; /* pc in context is decreased by 1 @@ -3667,7 +3687,7 @@ static LONG CALLBACK rtlraiseexception_unhandled_handler(EXCEPTION_POINTERS *Exc PCONTEXT context = ExceptionInfo->ContextRecord; PEXCEPTION_RECORD rec = ExceptionInfo->ExceptionRecord; rtlraiseexception_handler_(rec, NULL, context, NULL, TRUE); - if (test_stage == 2) return EXCEPTION_CONTINUE_SEARCH; + if (test_stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) return EXCEPTION_CONTINUE_SEARCH; return EXCEPTION_CONTINUE_EXECUTION; } @@ -3675,7 +3695,7 @@ static DWORD rtlraiseexception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTR CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) { rtlraiseexception_handler_(rec, frame, context, dispatcher, FALSE); - if (test_stage == 2) return ExceptionContinueSearch; + if (test_stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) return ExceptionContinueSearch; return ExceptionContinueExecution; } @@ -3741,7 +3761,7 @@ static void run_rtlraiseexception_test(DWORD exceptioncode) todo_wine ok( !rtlraiseexception_handler_called, "Frame handler called\n" ); - todo_wine_if (test_stage != 2) + todo_wine_if (test_stage != STAGE_RTLRAISE_HANDLE_LAST_CHANCE) ok( rtlraiseexception_unhandled_handler_called, "UnhandledExceptionFilter wasn't called\n" ); if (have_vectored_api) @@ -3818,7 +3838,7 @@ static void test_debugger(DWORD cont_status) else if (de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { CONTEXT ctx; - int stage; + enum debugger_stages stage; counter++; status = pNtReadVirtualMemory(pi.hProcess, &code_mem, &code_mem_address, @@ -3855,7 +3875,7 @@ static void test_debugger(DWORD cont_status) } else { - if (stage == 1) + if (stage == STAGE_RTLRAISE_NOT_HANDLED) { ok((char *)ctx.Rip == (char *)code_mem_address + 0x10, "Rip at %p instead of %p\n", (char *)ctx.Rip, (char *)code_mem_address + 0x10); @@ -3866,7 +3886,7 @@ static void test_debugger(DWORD cont_status) /* let the debuggee handle the exception */ continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 2) + else if (stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) { if (de.u.Exception.dwFirstChance) { @@ -3894,23 +3914,23 @@ static void test_debugger(DWORD cont_status) /* here we handle exception */ } } - else if (stage == 7 || stage == 8) + else if (stage == STAGE_SERVICE_CONTINUE || stage == STAGE_SERVICE_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "expected EXCEPTION_BREAKPOINT, got %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode); ok((char *)ctx.Rip == (char *)code_mem_address + 0x30, "expected Rip = %p, got %p\n", (char *)code_mem_address + 0x30, (char *)ctx.Rip); - if (stage == 8) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_SERVICE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 9 || stage == 10) + else if (stage == STAGE_BREAKPOINT_CONTINUE || stage == STAGE_BREAKPOINT_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "expected EXCEPTION_BREAKPOINT, got %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode); ok((char *)ctx.Rip == (char *)code_mem_address + 2, "expected Rip = %p, got %p\n", (char *)code_mem_address + 2, (char *)ctx.Rip); - if (stage == 10) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_BREAKPOINT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 11 || stage == 12) + else if (stage == STAGE_EXCEPTION_INVHANDLE_CONTINUE || stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_INVALID_HANDLE, "unexpected exception code %08lx, expected %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode, @@ -3918,18 +3938,18 @@ static void test_debugger(DWORD cont_status) ok(de.u.Exception.ExceptionRecord.NumberParameters == 0, "unexpected number of parameters %ld, expected 0\n", de.u.Exception.ExceptionRecord.NumberParameters); - if (stage == 12) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 13) + else if (stage == STAGE_NO_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(FALSE || broken(TRUE) /* < Win10 */, "should not throw exception\n"); continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 14 || stage == 15) + else if (stage == STAGE_XSTATE || stage == STAGE_XSTATE_LEGACY_SSE) { test_debugger_xstate(pi.hThread, &ctx, stage); } - else if (stage == 16) + else if (stage == STAGE_SEGMENTS) { USHORT ss; __asm__( "movw %%ss,%0" : "=r" (ss) ); @@ -3961,7 +3981,7 @@ static void test_debugger(DWORD cont_status) } else if (de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { - int stage; + enum debugger_stages stage; char buffer[64]; status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, @@ -3977,22 +3997,22 @@ static void test_debugger(DWORD cont_status) de.u.DebugString.nDebugStringLength, &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status); - if (stage == 3 || stage == 4) + if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); else /* ignore unrelated debug strings like 'SHIMVIEW: ShimInfo(Complete)' */ ok(strstr(buffer, "SHIMVIEW") != NULL, "unexpected stage %x, got debug string event '%s'\n", stage, buffer); - if (stage == 4) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } else if (de.dwDebugEventCode == RIP_EVENT) { - int stage; + enum debugger_stages stage; status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status); - if (stage == 5 || stage == 6) + if (stage == STAGE_RIPEVENT_CONTINUE || stage == STAGE_RIPEVENT_NOT_HANDLED) { ok(de.u.RipInfo.dwError == 0x11223344, "got unexpected rip error code %08lx, expected %08x\n", de.u.RipInfo.dwError, 0x11223344); @@ -4002,7 +4022,7 @@ static void test_debugger(DWORD cont_status) else ok(FALSE, "unexpected stage %x\n", stage); - if (stage == 6) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_RIPEVENT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } ContinueDebugEvent(de.dwProcessId, de.dwThreadId, continuestatus); @@ -6636,7 +6656,7 @@ static void test_debugger(DWORD cont_status) else if (de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { CONTEXT ctx; - int stage; + enum debugger_stages stage; counter++; status = pNtReadVirtualMemory(pi.hProcess, &code_mem, &code_mem_address, @@ -6673,7 +6693,7 @@ static void test_debugger(DWORD cont_status) } else { - if (stage == 1) + if (stage == STAGE_RTLRAISE_NOT_HANDLED) { ok((char *)ctx.Pc == (char *)code_mem_address + 0xb, "Pc at %lx instead of %p\n", ctx.Pc, (char *)code_mem_address + 0xb); @@ -6684,7 +6704,7 @@ static void test_debugger(DWORD cont_status) /* let the debuggee handle the exception */ continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 2) + else if (stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) { if (de.u.Exception.dwFirstChance) { @@ -6713,23 +6733,23 @@ static void test_debugger(DWORD cont_status) /* here we handle exception */ } } - else if (stage == 7 || stage == 8) + else if (stage == STAGE_SERVICE_CONTINUE || stage == STAGE_SERVICE_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "expected EXCEPTION_BREAKPOINT, got %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode); ok((char *)ctx.Pc == (char *)code_mem_address + 0x1d, "expected Pc = %p, got 0x%lx\n", (char *)code_mem_address + 0x1d, ctx.Pc); - if (stage == 8) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_SERVICE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 9 || stage == 10) + else if (stage == STAGE_BREAKPOINT_CONTINUE || stage == STAGE_BREAKPOINT_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "expected EXCEPTION_BREAKPOINT, got %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode); ok((char *)ctx.Pc == (char *)code_mem_address + 3, "expected Pc = %p, got 0x%lx\n", (char *)code_mem_address + 3, ctx.Pc); - if (stage == 10) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_BREAKPOINT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 11 || stage == 12) + else if (stage == STAGE_EXCEPTION_INVHANDLE_CONTINUE || stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_INVALID_HANDLE, "unexpected exception code %08lx, expected %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode, @@ -6737,9 +6757,9 @@ static void test_debugger(DWORD cont_status) ok(de.u.Exception.ExceptionRecord.NumberParameters == 0, "unexpected number of parameters %ld, expected 0\n", de.u.Exception.ExceptionRecord.NumberParameters); - if (stage == 12) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 13) + else if (stage == STAGE_NO_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(FALSE || broken(TRUE) /* < Win10 */, "should not throw exception\n"); continuestatus = DBG_EXCEPTION_NOT_HANDLED; @@ -6753,7 +6773,7 @@ static void test_debugger(DWORD cont_status) } else if (de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { - int stage; + enum debugger_stages stage; char buffer[64]; status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, @@ -6769,22 +6789,22 @@ static void test_debugger(DWORD cont_status) de.u.DebugString.nDebugStringLength, &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status); - if (stage == 3 || stage == 4) + if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); else /* ignore unrelated debug strings like 'SHIMVIEW: ShimInfo(Complete)' */ ok(strstr(buffer, "SHIMVIEW") != NULL, "unexpected stage %x, got debug string event '%s'\n", stage, buffer); - if (stage == 4) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } else if (de.dwDebugEventCode == RIP_EVENT) { - int stage; + enum debugger_stages stage; status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status); - if (stage == 5 || stage == 6) + if (stage == STAGE_RIPEVENT_CONTINUE || stage == STAGE_RIPEVENT_NOT_HANDLED) { ok(de.u.RipInfo.dwError == 0x11223344, "got unexpected rip error code %08lx, expected %08x\n", de.u.RipInfo.dwError, 0x11223344); @@ -6794,7 +6814,7 @@ static void test_debugger(DWORD cont_status) else ok(FALSE, "unexpected stage %x\n", stage); - if (stage == 6) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_RIPEVENT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } ContinueDebugEvent(de.dwProcessId, de.dwThreadId, continuestatus); @@ -7891,7 +7911,7 @@ static void test_debugger(DWORD cont_status) else if (de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { CONTEXT ctx; - int stage; + enum debugger_stages stage; counter++; status = pNtReadVirtualMemory(pi.hProcess, &code_mem, &code_mem_address, @@ -7928,7 +7948,7 @@ static void test_debugger(DWORD cont_status) } else { - if (stage == 1) + if (stage == STAGE_RTLRAISE_NOT_HANDLED) { ok((char *)ctx.Pc == (char *)code_mem_address + 0xb, "Pc at %p instead of %p\n", (char *)ctx.Pc, (char *)code_mem_address + 0xb); @@ -7939,7 +7959,7 @@ static void test_debugger(DWORD cont_status) /* let the debuggee handle the exception */ continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 2) + else if (stage == STAGE_RTLRAISE_HANDLE_LAST_CHANCE) { if (de.u.Exception.dwFirstChance) { @@ -7968,23 +7988,23 @@ static void test_debugger(DWORD cont_status) /* here we handle exception */ } } - else if (stage == 7 || stage == 8) + else if (stage == STAGE_SERVICE_CONTINUE || stage == STAGE_SERVICE_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "expected EXCEPTION_BREAKPOINT, got %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode); ok((char *)ctx.Pc == (char *)code_mem_address + 0x1d, "expected Pc = %p, got %p\n", (char *)code_mem_address + 0x1d, (char *)ctx.Pc); - if (stage == 8) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_SERVICE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 9 || stage == 10) + else if (stage == STAGE_BREAKPOINT_CONTINUE || stage == STAGE_BREAKPOINT_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT, "expected EXCEPTION_BREAKPOINT, got %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode); ok((char *)ctx.Pc == (char *)code_mem_address + 4, "expected Pc = %p, got %p\n", (char *)code_mem_address + 4, (char *)ctx.Pc); - if (stage == 10) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_BREAKPOINT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 11 || stage == 12) + else if (stage == STAGE_EXCEPTION_INVHANDLE_CONTINUE || stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_INVALID_HANDLE, "unexpected exception code %08lx, expected %08lx\n", de.u.Exception.ExceptionRecord.ExceptionCode, @@ -7992,9 +8012,9 @@ static void test_debugger(DWORD cont_status) ok(de.u.Exception.ExceptionRecord.NumberParameters == 0, "unexpected number of parameters %ld, expected 0\n", de.u.Exception.ExceptionRecord.NumberParameters); - if (stage == 12) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } - else if (stage == 13) + else if (stage == STAGE_NO_EXCEPTION_INVHANDLE_NOT_HANDLED) { ok(FALSE || broken(TRUE) /* < Win10 */, "should not throw exception\n"); continuestatus = DBG_EXCEPTION_NOT_HANDLED; @@ -8008,7 +8028,7 @@ static void test_debugger(DWORD cont_status) } else if (de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { - int stage; + enum debugger_stages stage; char buffer[128]; status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, @@ -8024,23 +8044,23 @@ static void test_debugger(DWORD cont_status) de.u.DebugString.nDebugStringLength, &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status); - if (stage == 3 || stage == 4) + if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); else /* ignore unrelated debug strings like 'SHIMVIEW: ShimInfo(Complete)' */ ok(strstr(buffer, "SHIMVIEW") || !strncmp(buffer, "RTL:", 4), "unexpected stage %x, got debug string event '%s'\n", stage, buffer); - if (stage == 4) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } else if (de.dwDebugEventCode == RIP_EVENT) { - int stage; + enum debugger_stages stage; status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status); - if (stage == 5 || stage == 6) + if (stage == STAGE_RIPEVENT_CONTINUE || stage == STAGE_RIPEVENT_NOT_HANDLED) { ok(de.u.RipInfo.dwError == 0x11223344, "got unexpected rip error code %08lx, expected %08x\n", de.u.RipInfo.dwError, 0x11223344); @@ -8050,7 +8070,7 @@ static void test_debugger(DWORD cont_status) else ok(FALSE, "unexpected stage %x\n", stage); - if (stage == 6) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_RIPEVENT_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; } ContinueDebugEvent(de.dwProcessId, de.dwThreadId, continuestatus); @@ -8854,12 +8874,12 @@ static void test_debuggee_xstate(void) func(); for (i = 0; i < 4; ++i) - ok(data[i] == (test_stage == 14 ? i + 1 : 0x28282828), + ok(data[i] == (test_stage == STAGE_XSTATE ? i + 1 : 0x28282828), "Got unexpected data %#x, test_stage %u, i %u.\n", data[i], test_stage, i); for ( ; i < ARRAY_SIZE(data); ++i) - ok(data[i] == (test_stage == 14 ? i + 1 : 0x48484848) - || broken(test_stage == 15 && data[i] == i + 1) /* Win7 */, + ok(data[i] == (test_stage == STAGE_XSTATE ? i + 1 : 0x48484848) + || broken(test_stage == STAGE_XSTATE_LEGACY_SSE && data[i] == i + 1) /* Win7 */, "Got unexpected data %#x, test_stage %u, i %u.\n", data[i], test_stage, i); } @@ -11062,40 +11082,41 @@ START_TEST(exception) #if defined(__i386__) || defined(__x86_64__) if (pRtlRaiseException) { - test_stage = 1; + test_stage = STAGE_RTLRAISE_NOT_HANDLED; run_rtlraiseexception_test(0x12345); run_rtlraiseexception_test(EXCEPTION_BREAKPOINT); run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE); - test_stage = 2; + test_stage = STAGE_RTLRAISE_HANDLE_LAST_CHANCE; run_rtlraiseexception_test(0x12345); run_rtlraiseexception_test(EXCEPTION_BREAKPOINT); run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE); } else skip( "RtlRaiseException not found\n" ); #endif - test_stage = 3; + + test_stage = STAGE_OUTPUTDEBUGSTRINGA_CONTINUE; test_outputdebugstring(FALSE, 0, FALSE, 0); - test_stage = 4; + test_stage = STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED; test_outputdebugstring(FALSE, 2, TRUE, 0); /* is 2 a Windows bug? */ - test_stage = 5; + test_stage = STAGE_RIPEVENT_CONTINUE; test_ripevent(0); - test_stage = 6; + test_stage = STAGE_RIPEVENT_NOT_HANDLED; test_ripevent(1); - test_stage = 7; + test_stage = STAGE_SERVICE_CONTINUE; test_debug_service(0); - test_stage = 8; + test_stage = STAGE_SERVICE_NOT_HANDLED; test_debug_service(1); - test_stage = 9; + test_stage = STAGE_BREAKPOINT_CONTINUE; test_breakpoint(0); - test_stage = 10; + test_stage = STAGE_BREAKPOINT_NOT_HANDLED; test_breakpoint(1); - test_stage = 11; + test_stage = STAGE_EXCEPTION_INVHANDLE_CONTINUE; test_closehandle(0, (HANDLE)0xdeadbeef); test_closehandle(0, (HANDLE)0x7fffffff); - test_stage = 12; + test_stage = STAGE_EXCEPTION_INVHANDLE_NOT_HANDLED; test_closehandle(1, (HANDLE)0xdeadbeef); test_closehandle(1, (HANDLE)~(ULONG_PTR)6); - test_stage = 13; /* special cases */ + test_stage = STAGE_NO_EXCEPTION_INVHANDLE_NOT_HANDLED; /* special cases */ test_closehandle(0, 0); test_closehandle(0, INVALID_HANDLE_VALUE); test_closehandle(0, GetCurrentProcess()); @@ -11105,11 +11126,11 @@ START_TEST(exception) test_closehandle(0, GetCurrentThreadToken()); test_closehandle(0, GetCurrentThreadEffectiveToken()); #if defined(__i386__) || defined(__x86_64__) - test_stage = 14; + test_stage = STAGE_XSTATE; test_debuggee_xstate(); - test_stage = 15; + test_stage = STAGE_XSTATE_LEGACY_SSE; test_debuggee_xstate(); - test_stage = 16; + test_stage = STAGE_SEGMENTS; test_debuggee_segments(); #endif From cd65117ba99d4e9310f2fa9c220e445b62ef9ec9 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Thu, 31 Aug 2023 09:25:29 +0200 Subject: [PATCH 2236/2777] ntdll/tests: Add tests for debuggee and new Win10 unicode debug strings. Signed-off-by: Eric Pouech (cherry picked from commit 514f63f3b5b56f8437ae5ed85fa4a81220477093) --- dlls/ntdll/tests/exception.c | 188 +++++++++++++++++++++++++++-------- 1 file changed, 144 insertions(+), 44 deletions(-) diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 8b45bcd096d..0d5a4b59295 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -196,6 +196,8 @@ enum debugger_stages STAGE_RTLRAISE_HANDLE_LAST_CHANCE, STAGE_OUTPUTDEBUGSTRINGA_CONTINUE, STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED, + STAGE_OUTPUTDEBUGSTRINGW_CONTINUE, + STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED, STAGE_RIPEVENT_CONTINUE, STAGE_RIPEVENT_NOT_HANDLED, STAGE_SERVICE_CONTINUE, @@ -1077,7 +1079,7 @@ static void test_exceptions(void) ok( res == STATUS_SUCCESS, "NtSetContextThread failed with %lx\n", res ); } -static void test_debugger(DWORD cont_status) +static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) { char cmdline[MAX_PATH]; PROCESS_INFORMATION pi; @@ -1097,6 +1099,12 @@ static void test_debugger(DWORD cont_status) return; } + if (with_WaitForDebugEventEx && !pWaitForDebugEventEx) + { + skip("WaitForDebugEventEx not found, skipping unicode strings in OutputDebugStringW\n"); + return; + } + sprintf(cmdline, "%s %s %s %p", my_argv[0], my_argv[1], "debuggee", &test_stage); ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi); ok(ret, "could not create child process error: %lu\n", GetLastError()); @@ -1106,7 +1114,8 @@ static void test_debugger(DWORD cont_status) do { continuestatus = cont_status; - ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n"); + ret = with_WaitForDebugEventEx ? pWaitForDebugEventEx(&de, INFINITE) : WaitForDebugEvent(&de, INFINITE); + ok(ret, "reading debug event\n"); ret = ContinueDebugEvent(de.dwProcessId, de.dwThreadId, 0xdeadbeef); ok(!ret, "ContinueDebugEvent unexpectedly succeeded\n"); @@ -1279,27 +1288,43 @@ static void test_debugger(DWORD cont_status) else if (de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { enum debugger_stages stage; - char buffer[64]; + char buffer[64 * sizeof(WCHAR)]; + unsigned char_size = de.u.DebugString.fUnicode ? sizeof(WCHAR) : sizeof(char); status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status); - ok(!de.u.DebugString.fUnicode, "unexpected unicode debug string event\n"); - ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) - 1, "buffer not large enough to hold %d bytes\n", - de.u.DebugString.nDebugStringLength); + if (de.u.DebugString.fUnicode) + ok(with_WaitForDebugEventEx && + (stage == STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED), + "unexpected unicode debug string event\n"); + else + ok(!with_WaitForDebugEventEx || stage != STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || cont_status != DBG_CONTINUE, + "unexpected ansi debug string event %u %s %lx\n", + stage, with_WaitForDebugEventEx ? "with" : "without", cont_status); + + ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) / char_size - 1, + "buffer not large enough to hold %d bytes\n", de.u.DebugString.nDebugStringLength); memset(buffer, 0, sizeof(buffer)); status = pNtReadVirtualMemory(pi.hProcess, de.u.DebugString.lpDebugStringData, buffer, - de.u.DebugString.nDebugStringLength, &size_read); + de.u.DebugString.nDebugStringLength * char_size, &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status); - if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) - ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); + if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED || + stage == STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED) + { + if (de.u.DebugString.fUnicode) + ok(!wcscmp((WCHAR*)buffer, L"Hello World"), "got unexpected debug string '%ls'\n", (WCHAR*)buffer); + else + ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); + } else /* ignore unrelated debug strings like 'SHIMVIEW: ShimInfo(Complete)' */ ok(strstr(buffer, "SHIMVIEW") != NULL, "unexpected stage %x, got debug string event '%s'\n", stage, buffer); - if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED) + continuestatus = DBG_EXCEPTION_NOT_HANDLED; } else if (de.dwDebugEventCode == RIP_EVENT) { @@ -3785,7 +3810,7 @@ static void test_rtlraiseexception(void) run_rtlraiseexception_test(EXCEPTION_INVALID_HANDLE); } -static void test_debugger(DWORD cont_status) +static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) { char cmdline[MAX_PATH]; PROCESS_INFORMATION pi; @@ -3805,6 +3830,12 @@ static void test_debugger(DWORD cont_status) return; } + if (with_WaitForDebugEventEx && !pWaitForDebugEventEx) + { + skip("WaitForDebugEventEx not found, skipping unicode strings in OutputDebugStringW\n"); + return; + } + sprintf(cmdline, "%s %s %s %p", my_argv[0], my_argv[1], "debuggee", &test_stage); ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi); ok(ret, "could not create child process error: %lu\n", GetLastError()); @@ -3814,7 +3845,8 @@ static void test_debugger(DWORD cont_status) do { continuestatus = cont_status; - ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n"); + ret = with_WaitForDebugEventEx ? pWaitForDebugEventEx(&de, INFINITE) : WaitForDebugEvent(&de, INFINITE); + ok(ret, "reading debug event\n"); ret = ContinueDebugEvent(de.dwProcessId, de.dwThreadId, 0xdeadbeef); ok(!ret, "ContinueDebugEvent unexpectedly succeeded\n"); @@ -3982,27 +4014,43 @@ static void test_debugger(DWORD cont_status) else if (de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { enum debugger_stages stage; - char buffer[64]; + char buffer[64 * sizeof(WCHAR)]; + unsigned char_size = de.u.DebugString.fUnicode ? sizeof(WCHAR) : sizeof(char); status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status); - ok(!de.u.DebugString.fUnicode, "unexpected unicode debug string event\n"); - ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) - 1, "buffer not large enough to hold %d bytes\n", - de.u.DebugString.nDebugStringLength); + if (de.u.DebugString.fUnicode) + ok(with_WaitForDebugEventEx && + (stage == STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED), + "unexpected unicode debug string event\n"); + else + ok(!with_WaitForDebugEventEx || stage != STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || cont_status != DBG_CONTINUE, + "unexpected ansi debug string event %u %s %lx\n", + stage, with_WaitForDebugEventEx ? "with" : "without", cont_status); + + ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) / char_size - 1, + "buffer not large enough to hold %d bytes\n", de.u.DebugString.nDebugStringLength); memset(buffer, 0, sizeof(buffer)); status = pNtReadVirtualMemory(pi.hProcess, de.u.DebugString.lpDebugStringData, buffer, - de.u.DebugString.nDebugStringLength, &size_read); + de.u.DebugString.nDebugStringLength * char_size, &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status); - if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) - ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); + if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED || + stage == STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED) + { + if (de.u.DebugString.fUnicode) + ok(!wcscmp((WCHAR*)buffer, L"Hello World"), "got unexpected debug string '%ls'\n", (WCHAR*)buffer); + else + ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); + } else /* ignore unrelated debug strings like 'SHIMVIEW: ShimInfo(Complete)' */ ok(strstr(buffer, "SHIMVIEW") != NULL, "unexpected stage %x, got debug string event '%s'\n", stage, buffer); - if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED) + continuestatus = DBG_EXCEPTION_NOT_HANDLED; } else if (de.dwDebugEventCode == RIP_EVENT) { @@ -6603,7 +6651,7 @@ static void test_thread_context(void) #undef COMPARE } -static void test_debugger(DWORD cont_status) +static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) { char cmdline[MAX_PATH]; PROCESS_INFORMATION pi; @@ -6623,6 +6671,12 @@ static void test_debugger(DWORD cont_status) return; } + if (with_WaitForDebugEventEx && !pWaitForDebugEventEx) + { + skip("WaitForDebugEventEx not found, skipping unicode strings in OutputDebugStringW\n"); + return; + } + sprintf(cmdline, "%s %s %s %p", my_argv[0], my_argv[1], "debuggee", &test_stage); ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi); ok(ret, "could not create child process error: %lu\n", GetLastError()); @@ -6632,7 +6686,8 @@ static void test_debugger(DWORD cont_status) do { continuestatus = cont_status; - ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n"); + ret = with_WaitForDebugEventEx ? pWaitForDebugEventEx(&de, INFINITE) : WaitForDebugEvent(&de, INFINITE); + ok(ret, "reading debug event\n"); ret = ContinueDebugEvent(de.dwProcessId, de.dwThreadId, 0xdeadbeef); ok(!ret, "ContinueDebugEvent unexpectedly succeeded\n"); @@ -6774,27 +6829,43 @@ static void test_debugger(DWORD cont_status) else if (de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { enum debugger_stages stage; - char buffer[64]; + char buffer[64 * sizeof(WCHAR)]; + unsigned char_size = de.u.DebugString.fUnicode ? sizeof(WCHAR) : sizeof(char); status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status); - ok(!de.u.DebugString.fUnicode, "unexpected unicode debug string event\n"); - ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) - 1, "buffer not large enough to hold %d bytes\n", - de.u.DebugString.nDebugStringLength); + if (de.u.DebugString.fUnicode) + ok(with_WaitForDebugEventEx && + (stage == STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED), + "unexpected unicode debug string event\n"); + else + ok(!with_WaitForDebugEventEx || stage != STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || cont_status != DBG_CONTINUE, + "unexpected ansi debug string event %u %s %lx\n", + stage, with_WaitForDebugEventEx ? "with" : "without", cont_status); + + ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) / char_size - 1, + "buffer not large enough to hold %d bytes\n", de.u.DebugString.nDebugStringLength); memset(buffer, 0, sizeof(buffer)); status = pNtReadVirtualMemory(pi.hProcess, de.u.DebugString.lpDebugStringData, buffer, - de.u.DebugString.nDebugStringLength, &size_read); + de.u.DebugString.nDebugStringLength * char_size, &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status); - if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) - ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); + if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED || + stage == STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED) + { + if (de.u.DebugString.fUnicode) + ok(!wcscmp((WCHAR*)buffer, L"Hello World"), "got unexpected debug string '%ls'\n", (WCHAR*)buffer); + else + ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); + } else /* ignore unrelated debug strings like 'SHIMVIEW: ShimInfo(Complete)' */ ok(strstr(buffer, "SHIMVIEW") != NULL, "unexpected stage %x, got debug string event '%s'\n", stage, buffer); - if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED) + continuestatus = DBG_EXCEPTION_NOT_HANDLED; } else if (de.dwDebugEventCode == RIP_EVENT) { @@ -7858,7 +7929,7 @@ static void test_thread_context(void) #undef COMPARE } -static void test_debugger(DWORD cont_status) +static void test_debugger(DWORD cont_status, BOOL with_WaitForDebugEventEx) { char cmdline[MAX_PATH]; PROCESS_INFORMATION pi; @@ -7878,6 +7949,12 @@ static void test_debugger(DWORD cont_status) return; } + if (with_WaitForDebugEventEx && !pWaitForDebugEventEx) + { + skip("WaitForDebugEventEx not found, skipping unicode strings in OutputDebugStringW\n"); + return; + } + sprintf(cmdline, "%s %s %s %p", my_argv[0], my_argv[1], "debuggee", &test_stage); ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi); ok(ret, "could not create child process error: %lu\n", GetLastError()); @@ -7887,7 +7964,8 @@ static void test_debugger(DWORD cont_status) do { continuestatus = cont_status; - ok(WaitForDebugEvent(&de, INFINITE), "reading debug event\n"); + ret = with_WaitForDebugEventEx ? pWaitForDebugEventEx(&de, INFINITE) : WaitForDebugEvent(&de, INFINITE); + ok(ret, "reading debug event\n"); ret = ContinueDebugEvent(de.dwProcessId, de.dwThreadId, 0xdeadbeef); ok(!ret, "ContinueDebugEvent unexpectedly succeeded\n"); @@ -8029,28 +8107,44 @@ static void test_debugger(DWORD cont_status) else if (de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) { enum debugger_stages stage; - char buffer[128]; + char buffer[128 * sizeof(WCHAR)]; + unsigned char_size = de.u.DebugString.fUnicode ? sizeof(WCHAR) : sizeof(char); status = pNtReadVirtualMemory(pi.hProcess, &test_stage, &stage, sizeof(stage), &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status); - ok(!de.u.DebugString.fUnicode, "unexpected unicode debug string event\n"); - ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) - 1, "buffer not large enough to hold %d bytes\n", - de.u.DebugString.nDebugStringLength); + if (de.u.DebugString.fUnicode) + ok(with_WaitForDebugEventEx && + (stage == STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED), + "unexpected unicode debug string event\n"); + else + ok(!with_WaitForDebugEventEx || stage != STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || cont_status != DBG_CONTINUE, + "unexpected ansi debug string event %u %s %lx\n", + stage, with_WaitForDebugEventEx ? "with" : "without", cont_status); + + ok(de.u.DebugString.nDebugStringLength < sizeof(buffer) / char_size - 1, + "buffer not large enough to hold %d bytes\n", de.u.DebugString.nDebugStringLength); memset(buffer, 0, sizeof(buffer)); status = pNtReadVirtualMemory(pi.hProcess, de.u.DebugString.lpDebugStringData, buffer, - de.u.DebugString.nDebugStringLength, &size_read); + de.u.DebugString.nDebugStringLength * char_size, &size_read); ok(!status,"NtReadVirtualMemory failed with 0x%lx\n", status); - if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) - ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); + if (stage == STAGE_OUTPUTDEBUGSTRINGA_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED || + stage == STAGE_OUTPUTDEBUGSTRINGW_CONTINUE || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED) + { + if (de.u.DebugString.fUnicode) + ok(!wcscmp((WCHAR*)buffer, L"Hello World"), "got unexpected debug string '%ls'\n", (WCHAR*)buffer); + else + ok(!strcmp(buffer, "Hello World"), "got unexpected debug string '%s'\n", buffer); + } else /* ignore unrelated debug strings like 'SHIMVIEW: ShimInfo(Complete)' */ ok(strstr(buffer, "SHIMVIEW") || !strncmp(buffer, "RTL:", 4), - "unexpected stage %x, got debug string event '%s'\n", stage, buffer); + "unexpected stage %x, got debug string event '%s'\n", stage, buffer); - if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED) continuestatus = DBG_EXCEPTION_NOT_HANDLED; + if (stage == STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED || stage == STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED) + continuestatus = DBG_EXCEPTION_NOT_HANDLED; } else if (de.dwDebugEventCode == RIP_EVENT) { @@ -8526,7 +8620,7 @@ static void test_outputdebugstring(BOOL unicode, DWORD numexc_ansi, BOOL todo_an ok(outputdebugstring_exceptions_ansi == numexc_ansi, "OutputDebugString%c generated %ld ansi exceptions, expected %ld\n", unicode ? 'W' : 'A', outputdebugstring_exceptions_ansi, numexc_ansi); - todo_wine_if(unicode) + todo_wine_if(unicode && numexc_unicode) ok(outputdebugstring_exceptions_unicode == numexc_unicode, "OutputDebugString%c generated %lu unicode exceptions, expected %ld\n", unicode ? 'W' : 'A', outputdebugstring_exceptions_unicode, numexc_unicode); @@ -11098,6 +11192,10 @@ START_TEST(exception) test_outputdebugstring(FALSE, 0, FALSE, 0); test_stage = STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED; test_outputdebugstring(FALSE, 2, TRUE, 0); /* is 2 a Windows bug? */ + test_stage = STAGE_OUTPUTDEBUGSTRINGW_CONTINUE; + test_outputdebugstring(TRUE, 0, FALSE, 0); + test_stage = STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED; + test_outputdebugstring(TRUE, 2, TRUE, 1); /* is 2 a Windows bug? */ test_stage = STAGE_RIPEVENT_CONTINUE; test_ripevent(0); test_stage = STAGE_RIPEVENT_NOT_HANDLED; @@ -11208,8 +11306,10 @@ START_TEST(exception) #endif - test_debugger(DBG_EXCEPTION_HANDLED); - test_debugger(DBG_CONTINUE); + test_debugger(DBG_EXCEPTION_HANDLED, FALSE); + test_debugger(DBG_CONTINUE, FALSE); + test_debugger(DBG_EXCEPTION_HANDLED, TRUE); + test_debugger(DBG_CONTINUE, TRUE); test_thread_context(); test_outputdebugstring(FALSE, 1, FALSE, 0); test_outputdebugstring(TRUE, 1, FALSE, 1); From c4a24ec256782546e4c431868473f3fabd0cd0b0 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Thu, 31 Aug 2023 09:25:29 +0200 Subject: [PATCH 2237/2777] kernelbase: Emit DBG_PRINTEXCEPTION_WIDE_C from OutputDebugStringW. Also modifying WaitForDebugEvent() to force resending the ansi DBG_PRINTEXCEPTION_C exception instead. Signed-off-by: Eric Pouech (cherry picked from commit 090fb2cc19f2cb8930933f1931e6ccb77d88c470) --- dlls/kernelbase/debug.c | 29 +++++++++++++++++++++++++- dlls/kernelbase/sync.c | 11 ++++++++++ dlls/ntdll/tests/exception.c | 40 +++++++++++++++++++++--------------- 3 files changed, 62 insertions(+), 18 deletions(-) diff --git a/dlls/kernelbase/debug.c b/dlls/kernelbase/debug.c index 652f1cf8809..8af51dd7d71 100644 --- a/dlls/kernelbase/debug.c +++ b/dlls/kernelbase/debug.c @@ -262,6 +262,11 @@ void WINAPI DECLSPEC_HOTPATCH OutputDebugStringA( LPCSTR str ) } } +static LONG WINAPI debug_exception_handler_wide( EXCEPTION_POINTERS *eptr ) +{ + EXCEPTION_RECORD *rec = eptr->ExceptionRecord; + return (rec->ExceptionCode == DBG_PRINTEXCEPTION_WIDE_C) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; +} /*********************************************************************** * OutputDebugStringW (kernelbase.@) @@ -271,10 +276,32 @@ void WINAPI DECLSPEC_HOTPATCH OutputDebugStringW( LPCWSTR str ) UNICODE_STRING strW; STRING strA; + WARN( "%s\n", debugstr_w(str) ); + RtlInitUnicodeString( &strW, str ); if (!RtlUnicodeStringToAnsiString( &strA, &strW, TRUE )) { - OutputDebugStringA( strA.Buffer ); + BOOL exc_handled; + + __TRY + { + ULONG_PTR args[4]; + args[0] = wcslen(str) + 1; + args[1] = (ULONG_PTR)str; + args[2] = strlen(strA.Buffer) + 1; + args[3] = (ULONG_PTR)strA.Buffer; + RaiseException( DBG_PRINTEXCEPTION_WIDE_C, 0, 4, args ); + exc_handled = TRUE; + } + __EXCEPT(debug_exception_handler_wide) + { + exc_handled = FALSE; + } + __ENDTRY + + if (!exc_handled) + OutputDebugStringA( strA.Buffer ); + RtlFreeAnsiString( &strA ); } } diff --git a/dlls/kernelbase/sync.c b/dlls/kernelbase/sync.c index 4c366f859c6..797e43fbedc 100644 --- a/dlls/kernelbase/sync.c +++ b/dlls/kernelbase/sync.c @@ -364,6 +364,17 @@ BOOL WINAPI DECLSPEC_HOTPATCH WaitForDebugEvent( DEBUG_EVENT *event, DWORD timeo switch (status) { case STATUS_SUCCESS: + /* continue on wide print exceptions to force resending an ANSI one. */ + if (state.NewState == DbgExceptionStateChange) + { + DBGKM_EXCEPTION *info = &state.StateInfo.Exception; + DWORD code = info->ExceptionRecord.ExceptionCode; + if (code == DBG_PRINTEXCEPTION_WIDE_C && info->ExceptionRecord.NumberParameters >= 2) + { + DbgUiContinue( &state.AppClientId, DBG_EXCEPTION_NOT_HANDLED ); + break; + } + } DbgUiConvertStateChangeStructure( &state, event ); return TRUE; case STATUS_USER_APC: diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 0d5a4b59295..0b55a93e898 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -8596,7 +8596,8 @@ static LONG CALLBACK outputdebugstring_vectored_handler(EXCEPTION_POINTERS *Exce return EXCEPTION_CONTINUE_SEARCH; } -static void test_outputdebugstring(BOOL unicode, DWORD numexc_ansi, BOOL todo_ansi, DWORD numexc_unicode) +static void test_outputdebugstring(BOOL unicode, DWORD numexc_ansi, BOOL todo_ansi, + DWORD numexc_unicode_low, DWORD numexc_unicode_high) { PVOID vectored_handler; @@ -8620,10 +8621,11 @@ static void test_outputdebugstring(BOOL unicode, DWORD numexc_ansi, BOOL todo_an ok(outputdebugstring_exceptions_ansi == numexc_ansi, "OutputDebugString%c generated %ld ansi exceptions, expected %ld\n", unicode ? 'W' : 'A', outputdebugstring_exceptions_ansi, numexc_ansi); - todo_wine_if(unicode && numexc_unicode) - ok(outputdebugstring_exceptions_unicode == numexc_unicode, - "OutputDebugString%c generated %lu unicode exceptions, expected %ld\n", - unicode ? 'W' : 'A', outputdebugstring_exceptions_unicode, numexc_unicode); + todo_wine_if(unicode && numexc_unicode_low) + ok(outputdebugstring_exceptions_unicode >= numexc_unicode_low && + outputdebugstring_exceptions_unicode <= numexc_unicode_high, + "OutputDebugString%c generated %lu unicode exceptions, expected %ld-%ld\n", + unicode ? 'W' : 'A', outputdebugstring_exceptions_unicode, numexc_unicode_low, numexc_unicode_high); pRtlRemoveVectoredExceptionHandler(vectored_handler); } @@ -8685,11 +8687,6 @@ static void test_outputdebugstring_newmodel(void) }; int i; - if (!pWaitForDebugEventEx) - { - skip("Unsupported new unicode debug string model\n"); - return; - } if (!pRtlAddVectoredExceptionHandler || !pRtlRemoveVectoredExceptionHandler) { skip("RtlAddVectoredExceptionHandler or RtlRemoveVectoredExceptionHandler not found\n"); @@ -11189,13 +11186,16 @@ START_TEST(exception) #endif test_stage = STAGE_OUTPUTDEBUGSTRINGA_CONTINUE; - test_outputdebugstring(FALSE, 0, FALSE, 0); + + test_outputdebugstring(FALSE, 0, FALSE, 0, 0); test_stage = STAGE_OUTPUTDEBUGSTRINGA_NOT_HANDLED; - test_outputdebugstring(FALSE, 2, TRUE, 0); /* is 2 a Windows bug? */ + test_outputdebugstring(FALSE, 2, TRUE, 0, 0); /* is 2 a Windows bug? */ test_stage = STAGE_OUTPUTDEBUGSTRINGW_CONTINUE; - test_outputdebugstring(TRUE, 0, FALSE, 0); + /* depending on value passed DebugContinue we can get the unicode exception or not */ + test_outputdebugstring(TRUE, 0, FALSE, 0, 1); test_stage = STAGE_OUTPUTDEBUGSTRINGW_NOT_HANDLED; - test_outputdebugstring(TRUE, 2, TRUE, 1); /* is 2 a Windows bug? */ + /* depending on value passed DebugContinue we can get the unicode exception or not */ + test_outputdebugstring(TRUE, 2, TRUE, 0, 1); /* is 2 a Windows bug? */ test_stage = STAGE_RIPEVENT_CONTINUE; test_ripevent(0); test_stage = STAGE_RIPEVENT_NOT_HANDLED; @@ -11311,9 +11311,15 @@ START_TEST(exception) test_debugger(DBG_EXCEPTION_HANDLED, TRUE); test_debugger(DBG_CONTINUE, TRUE); test_thread_context(); - test_outputdebugstring(FALSE, 1, FALSE, 0); - test_outputdebugstring(TRUE, 1, FALSE, 1); - test_outputdebugstring_newmodel(); + test_outputdebugstring(FALSE, 1, FALSE, 0, 0); + if (pWaitForDebugEventEx) + { + test_outputdebugstring(TRUE, 1, FALSE, 1, 1); + test_outputdebugstring_newmodel(); + } + else + skip("Unsupported new unicode debug string model\n"); + test_ripevent(1); test_fastfail(); test_breakpoint(1); From fed0b4105215a54d555bb4a58eb6435a5084b3f1 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Thu, 31 Aug 2023 09:25:29 +0200 Subject: [PATCH 2238/2777] kernelbase: Implement WaitForDebugEventEx(). Signed-off-by: Eric Pouech (cherry picked from commit e09dde5c949a5650ac9be0f2ccc457552e854dee) --- dlls/kernel32/kernel32.spec | 1 + dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/sync.c | 28 ++++++++++++++++++++++++++++ dlls/ntdll/process.c | 7 +++++++ dlls/ntdll/tests/exception.c | 1 - include/winbase.h | 1 + 6 files changed, 38 insertions(+), 2 deletions(-) diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 1d6dcc11f77..c9172e8022e 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -1606,6 +1606,7 @@ @ stdcall WTSGetActiveConsoleSessionId() @ stdcall -import WaitCommEvent(long ptr ptr) @ stdcall -import WaitForDebugEvent(ptr long) +@ stdcall -import WaitForDebugEventEx(ptr long) @ stdcall -import WaitForMultipleObjects(long ptr long long) @ stdcall -import WaitForMultipleObjectsEx(long ptr long long long) @ stdcall -import WaitForSingleObject(long long) diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index c14f2a87472..9c3571260ab 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -1730,7 +1730,7 @@ # @ stub WTSIsServerContainer @ stdcall WaitCommEvent(long ptr ptr) @ stdcall WaitForDebugEvent(ptr long) -# @ stub WaitForDebugEventEx +@ stdcall WaitForDebugEventEx(ptr long) # @ stub WaitForMachinePolicyForegroundProcessingInternal @ stdcall WaitForMultipleObjects(long ptr long long) @ stdcall WaitForMultipleObjectsEx(long ptr long long long) diff --git a/dlls/kernelbase/sync.c b/dlls/kernelbase/sync.c index 797e43fbedc..270ce137a02 100644 --- a/dlls/kernelbase/sync.c +++ b/dlls/kernelbase/sync.c @@ -388,6 +388,34 @@ BOOL WINAPI DECLSPEC_HOTPATCH WaitForDebugEvent( DEBUG_EVENT *event, DWORD timeo } } +/****************************************************************************** + * WaitForDebugEventEx (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH WaitForDebugEventEx( DEBUG_EVENT *event, DWORD timeout ) +{ + NTSTATUS status; + LARGE_INTEGER time; + DBGUI_WAIT_STATE_CHANGE state; + + for (;;) + { + status = DbgUiWaitStateChange( &state, get_nt_timeout( &time, timeout ) ); + switch (status) + { + case STATUS_SUCCESS: + DbgUiConvertStateChangeStructure( &state, event ); + return TRUE; + case STATUS_USER_APC: + continue; + case STATUS_TIMEOUT: + SetLastError( ERROR_SEM_TIMEOUT ); + return FALSE; + default: + return set_ntstatus( status ); + } + } +} + /*********************************************************************** * WaitOnAddress (kernelbase.@) diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c index 0b4245fdd42..dbfcd14060b 100644 --- a/dlls/ntdll/process.c +++ b/dlls/ntdll/process.c @@ -487,6 +487,13 @@ NTSTATUS WINAPI DbgUiConvertStateChangeStructure( DBGUI_WAIT_STATE_CHANGE *state event->u.DebugString.fUnicode = FALSE; event->u.DebugString.nDebugStringLength = info->ExceptionRecord.ExceptionInformation[0]; } + else if (code == DBG_PRINTEXCEPTION_WIDE_C && info->ExceptionRecord.NumberParameters >= 2) + { + event->dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT; + event->u.DebugString.lpDebugStringData = (void *)info->ExceptionRecord.ExceptionInformation[1]; + event->u.DebugString.fUnicode = TRUE; + event->u.DebugString.nDebugStringLength = info->ExceptionRecord.ExceptionInformation[0]; + } else if (code == DBG_RIPEXCEPTION && info->ExceptionRecord.NumberParameters >= 2) { event->dwDebugEventCode = RIP_EVENT; diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 0b55a93e898..af215c1c12b 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -8621,7 +8621,6 @@ static void test_outputdebugstring(BOOL unicode, DWORD numexc_ansi, BOOL todo_an ok(outputdebugstring_exceptions_ansi == numexc_ansi, "OutputDebugString%c generated %ld ansi exceptions, expected %ld\n", unicode ? 'W' : 'A', outputdebugstring_exceptions_ansi, numexc_ansi); - todo_wine_if(unicode && numexc_unicode_low) ok(outputdebugstring_exceptions_unicode >= numexc_unicode_low && outputdebugstring_exceptions_unicode <= numexc_unicode_high, "OutputDebugString%c generated %lu unicode exceptions, expected %ld-%ld\n", diff --git a/include/winbase.h b/include/winbase.h index 9859e22598d..5a2170882a1 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -2806,6 +2806,7 @@ WINBASEAPI BOOL WINAPI VirtualUnlock(LPVOID,SIZE_T); WINBASEAPI DWORD WINAPI WTSGetActiveConsoleSessionId(void); WINBASEAPI BOOL WINAPI WaitCommEvent(HANDLE,LPDWORD,LPOVERLAPPED); WINBASEAPI BOOL WINAPI WaitForDebugEvent(LPDEBUG_EVENT,DWORD); +WINBASEAPI BOOL WINAPI WaitForDebugEventEx(LPDEBUG_EVENT,DWORD); WINBASEAPI DWORD WINAPI WaitForMultipleObjects(DWORD,const HANDLE*,BOOL,DWORD); WINBASEAPI DWORD WINAPI WaitForMultipleObjectsEx(DWORD,const HANDLE*,BOOL,DWORD,BOOL); WINBASEAPI DWORD WINAPI WaitForSingleObject(HANDLE,DWORD); From 5632bb3270029acf233bafbb8e9b93778acb5f92 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 1 Sep 2023 12:56:39 -0600 Subject: [PATCH 2239/2777] server: Don't set SO_RCVBUF below default value on Unix socket. CW-Bug-Id: #22692 --- dlls/ws2_32/tests/sock.c | 59 +++++++++++++++++++++++++++++++++++++++- server/sock.c | 10 +++++-- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 21c6b81028d..ae582aba406 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -161,6 +161,7 @@ static GUID WSARecvMsg_GUID = WSAID_WSARECVMSG; static SOCKET setup_server_socket(struct sockaddr_in *addr, int *len); static SOCKET setup_connector_socket(const struct sockaddr_in *addr, int len, BOOL nonblock); +static int sync_recv(SOCKET s, void *buffer, int len, DWORD flags); static void tcp_socketpair_flags(SOCKET *src, SOCKET *dst, DWORD flags) { @@ -1230,7 +1231,7 @@ static void test_set_getsockopt(void) {AF_INET6, SOCK_DGRAM, IPPROTO_IPV6, IPV6_UNICAST_HOPS, TRUE, {1, 1, 4}, {0}, FALSE}, {AF_INET6, SOCK_DGRAM, IPPROTO_IPV6, IPV6_V6ONLY, TRUE, {1, 1, 1}, {0}, TRUE}, }; - SOCKET s, s2; + SOCKET s, s2, src, dst; int i, j, err, lasterr; int timeout; LINGER lingval; @@ -1242,6 +1243,7 @@ static void test_set_getsockopt(void) int expected_err, expected_size; DWORD value, save_value; UINT64 value64; + char buffer[4096]; struct _prottest { @@ -1307,6 +1309,61 @@ static void test_set_getsockopt(void) ok( !err, "getsockopt(SO_RCVBUF) failed error: %u\n", WSAGetLastError() ); ok( value == 4096, "expected 4096, got %lu\n", value ); + value = 0; + size = sizeof(value); + err = setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&value, size); + ok( !err, "setsockopt(SO_RCVBUF) failed error: %u\n", WSAGetLastError() ); + value = 0xdeadbeef; + err = getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&value, &size); + ok( !err, "getsockopt(SO_RCVBUF) failed error: %u\n", WSAGetLastError() ); + ok( value == 0, "expected 0, got %lu\n", value ); + + /* Test non-blocking receive with too short SO_RCVBUF. */ + tcp_socketpair(&src, &dst); + set_blocking(src, FALSE); + set_blocking(dst, FALSE); + + value = 0; + size = sizeof(value); + err = setsockopt(src, SOL_SOCKET, SO_SNDBUF, (char *)&value, size); + ok( !err, "got %d, error %u.\n", err, WSAGetLastError() ); + + value = 0xdeadbeef; + err = getsockopt(dst, SOL_SOCKET, SO_RCVBUF, (char *)&value, &size); + ok( !err, "got %d, error %u.\n", err, WSAGetLastError() ); + if (value >= sizeof(buffer) * 3) + { + value = 1024; + size = sizeof(value); + err = setsockopt(dst, SOL_SOCKET, SO_RCVBUF, (char *)&value, size); + ok( !err, "got %d, error %u.\n", err, WSAGetLastError() ); + value = 0xdeadbeef; + err = getsockopt(dst, SOL_SOCKET, SO_RCVBUF, (char *)&value, &size); + ok( !err, "got %d, error %u.\n", err, WSAGetLastError() ); + ok( value == 1024, "expected 0, got %lu\n", value ); + + err = send(src, buffer, sizeof(buffer), 0); + ok(err == sizeof(buffer), "got %d\n", err); + err = send(src, buffer, sizeof(buffer), 0); + ok(err == sizeof(buffer), "got %d\n", err); + err = send(src, buffer, sizeof(buffer), 0); + ok(err == sizeof(buffer), "got %d\n", err); + + err = sync_recv(dst, buffer, sizeof(buffer), 0); + ok(err == sizeof(buffer), "got %d, error %u\n", err, WSAGetLastError()); + err = sync_recv(dst, buffer, sizeof(buffer), 0); + ok(err == sizeof(buffer), "got %d, error %u\n", err, WSAGetLastError()); + err = sync_recv(dst, buffer, sizeof(buffer), 0); + ok(err == sizeof(buffer), "got %d, error %u\n", err, WSAGetLastError()); + } + else + { + skip("Default SO_RCVBUF %lu is too small, skipping test.\n", value); + } + + closesocket(src); + closesocket(dst); + /* SO_LINGER */ for( i = 0; i < ARRAY_SIZE(linger_testvals);i++) { size = sizeof(lingval); diff --git a/server/sock.c b/server/sock.c index 16769fc2b4b..62b9ceca0a2 100644 --- a/server/sock.c +++ b/server/sock.c @@ -239,6 +239,7 @@ struct sock struct poll_req *main_poll; /* main poll */ union win_sockaddr addr; /* socket name */ int addr_len; /* socket name length */ + unsigned int default_rcvbuf; /* initial advisory recv buffer size */ unsigned int rcvbuf; /* advisory recv buffer size */ unsigned int sndbuf; /* advisory send buffer size */ unsigned int rcvtimeo; /* receive timeout in ms */ @@ -1729,6 +1730,7 @@ static struct sock *create_socket(void) sock->reset = 0; sock->reuseaddr = 0; sock->exclusiveaddruse = 0; + sock->default_rcvbuf = 0; sock->rcvbuf = 0; sock->sndbuf = 0; sock->rcvtimeo = 0; @@ -1912,7 +1914,7 @@ static int init_socket( struct sock *sock, int family, int type, int protocol ) len = sizeof(value); if (!getsockopt( sockfd, SOL_SOCKET, SO_RCVBUF, &value, &len )) - sock->rcvbuf = value; + sock->rcvbuf = sock->default_rcvbuf = value; len = sizeof(value); if (!getsockopt( sockfd, SOL_SOCKET, SO_SNDBUF, &value, &len )) @@ -2007,6 +2009,7 @@ static struct sock *accept_socket( struct sock *sock ) acceptsock->reuseaddr = sock->reuseaddr; acceptsock->exclusiveaddruse = sock->exclusiveaddruse; acceptsock->sndbuf = sock->sndbuf; + acceptsock->default_rcvbuf = sock->default_rcvbuf; acceptsock->rcvbuf = sock->rcvbuf; acceptsock->sndtimeo = sock->sndtimeo; acceptsock->rcvtimeo = sock->rcvtimeo; @@ -3086,7 +3089,7 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) case IOCTL_AFD_WINE_SET_SO_RCVBUF: { - DWORD rcvbuf; + DWORD rcvbuf, set_rcvbuf; if (get_req_data_size() < sizeof(rcvbuf)) { @@ -3094,8 +3097,9 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return; } rcvbuf = *(DWORD *)get_req_data(); + set_rcvbuf = max( rcvbuf, sock->default_rcvbuf ); - if (!setsockopt( unix_fd, SOL_SOCKET, SO_RCVBUF, (char *)&rcvbuf, sizeof(rcvbuf) )) + if (!setsockopt( unix_fd, SOL_SOCKET, SO_RCVBUF, (char *)&set_rcvbuf, sizeof(set_rcvbuf) )) sock->rcvbuf = rcvbuf; else set_error( sock_get_ntstatus( errno ) ); From 057bdf02e4f52c38b271ef77558e0c08ab2f6ab9 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Thu, 10 Aug 2023 22:41:16 +0800 Subject: [PATCH 2240/2777] winex11.drv: Use thread display instead of gdi_display to move windows. Thread display instead of gdi_display should be used to move X11 windows. Otherwise, in sync_client_position() the thread display is used but in window_update_fshack() gdi_display is used. Since they are on a different display, their window configure requests might not be handled in the correct order. CW-Bug-Id: #22345 --- dlls/winex11.drv/window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 4121b558ca9..4940ddc7804 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -3020,7 +3020,7 @@ static void window_update_fshack( struct x11drv_win_data *data, const RECT *wind client_rect_host.right = min( max( client_rect_host.right, 1 ), 65535 ); client_rect_host.bottom = min( max( client_rect_host.bottom, 1 ), 65535 ); - XMoveResizeWindow( gdi_display, data->client_window, top_left.x, top_left.y, client_rect_host.right, client_rect_host.bottom ); + XMoveResizeWindow( data->display, data->client_window, top_left.x, top_left.y, client_rect_host.right, client_rect_host.bottom ); sync_gl_drawable( data->hwnd, !data->whole_window ); invalidate_vk_surfaces( data->hwnd ); From e8b6e4e73edcee9a4c988ea91b9a7e8e7d7dfdb5 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 30 Aug 2023 12:19:48 -0600 Subject: [PATCH 2241/2777] ntdll/tests: Add tests for RtlGetFullPathName_U and RtlDosPathNameToNtPathName_U with mask. (cherry picked from commit 9e04cd31bcfacbfbccf1f0c9525493189710e8de) CW-Bug-Id: #22684 --- dlls/ntdll/tests/path.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/ntdll/tests/path.c b/dlls/ntdll/tests/path.c index 4732f6a6aa8..64bc92a4f72 100644 --- a/dlls/ntdll/tests/path.c +++ b/dlls/ntdll/tests/path.c @@ -306,6 +306,9 @@ static void test_RtlGetFullPathName_U(void) { "c:/test../file", "c:\\test.\\file", "file", "c:\\test..\\file", "file"}, /* vista */ { "c:\\test", "c:\\test", "test"}, + { "c:\\test\\*.", "c:\\test\\*", "*"}, + { "c:\\test\\a*b.*", "c:\\test\\a*b.*", "a*b.*"}, + { "c:\\test\\a*b*.", "c:\\test\\a*b*", "a*b*"}, { "C:\\test", "C:\\test", "test"}, { "c:/", "c:\\", NULL}, { "c:.", "C:\\windows", "windows"}, @@ -440,6 +443,7 @@ static void test_RtlDosPathNameToNtPathName_U(void) tests[] = { {L"c:\\", L"\\??\\c:\\", -1}, + {L"c:\\test\\*.", L"\\??\\c:\\test\\*", 12}, {L"c:/", L"\\??\\c:\\", -1}, {L"c:/foo", L"\\??\\c:\\foo", 7}, {L"c:/foo.", L"\\??\\c:\\foo", 7}, From 80e524ce33c0762b1d3ac18c33929f592fe9afe7 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 30 Aug 2023 13:19:51 -0600 Subject: [PATCH 2242/2777] ntdll/tests: Test NtQueryDirectoryFile with wildcards. (cherry picked from commit 98c929d73e684f42c5d77044e7fa2fe27d4c5cec) CW-Bug-Id: #22684 --- dlls/ntdll/tests/directory.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/tests/directory.c b/dlls/ntdll/tests/directory.c index a5ea7900f8d..9ff5c7a2bc2 100644 --- a/dlls/ntdll/tests/directory.c +++ b/dlls/ntdll/tests/directory.c @@ -70,6 +70,7 @@ static struct testfile_s { { 0, FILE_ATTRIBUTE_NORMAL, {0xe9,'a','.','t','m','p'}, "normal" }, { 0, FILE_ATTRIBUTE_NORMAL, {0xc9,'b','.','t','m','p'}, "normal" }, { 0, FILE_ATTRIBUTE_NORMAL, {'e','a','.','t','m','p'}, "normal" }, + { 0, FILE_ATTRIBUTE_NORMAL, {'e','a'}, "normal" }, { 0, FILE_ATTRIBUTE_DIRECTORY, {'.'}, ". directory" }, { 0, FILE_ATTRIBUTE_DIRECTORY, {'.','.'}, ".. directory" } }; @@ -237,13 +238,13 @@ static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char } ok(numfiles < max_test_dir_size, "too many loops\n"); - if (mask) + if (mask && !wcspbrk( mask->Buffer, L"*?" )) for (i = 0; i < test_dir_count; i++) ok(testfiles[i].nfound == (testfiles[i].name == mask->Buffer), "Wrong number %d of %s files found (single_entry=%d,mask=%s)\n", testfiles[i].nfound, testfiles[i].description, single_entry, wine_dbgstr_wn(mask->Buffer, mask->Length/sizeof(WCHAR) )); - else + else if (!mask) for (i = 0; i < test_dir_count; i++) ok(testfiles[i].nfound == 1, "Wrong number %d of %s files found (single_entry=%d,restart=%d)\n", testfiles[i].nfound, testfiles[i].description, single_entry, restart_flag); @@ -448,11 +449,27 @@ static void test_NtQueryDirectoryFile_classes( HANDLE handle, UNICODE_STRING *ma static void test_NtQueryDirectoryFile(void) { + static const struct + { + const WCHAR *mask; + int found[ARRAY_SIZE(testfiles)]; + BOOL todo_missing; + } + mask_tests[] = + { + {L"*.", {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, TRUE}, + {L"*.*", {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1}, TRUE}, + {L"*.**", {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1}, TRUE}, + {L"*", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, + {L"**", {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, + {L"??.???", {0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0}}, + }; + OBJECT_ATTRIBUTES attr; UNICODE_STRING ntdirname, mask; char testdirA[MAX_PATH], buffer[MAX_PATH]; WCHAR testdirW[MAX_PATH]; - int i; + int i, j; IO_STATUS_BLOCK io; WCHAR short_name[12]; UINT data_size; @@ -494,6 +511,19 @@ static void test_NtQueryDirectoryFile(void) test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, TRUE, FALSE); } + for (i = 0; i < ARRAY_SIZE(mask_tests); ++i) + { + winetest_push_context("mask %s", debugstr_w(mask_tests[i].mask)); + RtlInitUnicodeString(&mask, mask_tests[i].mask); + test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, FALSE, TRUE); + for (j = 0; j < test_dir_count; j++) + { + todo_wine_if(mask_tests[i].todo_missing && !mask_tests[i].found[j]) + ok(testfiles[j].nfound == mask_tests[i].found[j], "%S, got %d.\n", testfiles[j].name, testfiles[j].nfound); + } + winetest_pop_context(); + } + /* short path passed as mask */ status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE); From 063c8a7bcd0a2473cb7def0c40bbef459a6cc731 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 31 Aug 2023 11:59:14 -0600 Subject: [PATCH 2243/2777] kernel32/tests: Add more tests for FindFirstFile with wildcards. (cherry picked from commit 6f3c76c9a576b2e3c424124aa586b8f8858426c7) CW-Bug-Id: #22684 --- dlls/kernel32/tests/file.c | 39 +++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index 73ae75d52af..f2751c51e65 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -2963,38 +2963,43 @@ static void test_FindFirstFile_wildcards(void) int i; static const char* files[] = { "..a", "..a.a", ".a", ".a..a", ".a.a", ".aaa", - "a", "a..a", "a.a", "a.a.a", "aa", "aaa", "aaaa" + "a", "a..a", "a.a", "a.a.a", "aa", "aaa", "aaaa", " .a" }; static const struct { int todo; const char *pattern, *result; } tests[] = { - {0, "*.*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, - {0, "*.*.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, + {0, "*.*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {0, "*.*.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, {0, ".*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa'"}, - {0, "*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, + {0, "*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, {0, ".*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa'"}, {1, "*.", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {0, "*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, + {0, "*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, {1, "*..*", ", '.', '..', '..a', '..a.a', '.a..a', 'a..a'"}, {1, "*..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, {1, ".*.", ", '.', '..', '.a', '.aaa'"}, {0, "..*", ", '.', '..', '..a', '..a.a'"}, - {0, "**", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, - {0, "**.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, - {0, "*. ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, + {0, "**", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {0, "**.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {0, "*. ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, {1, "* .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {0, "* . ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, - {0, "*.. ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, + {0, "* . ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {0, "*.. ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, {1, "*. .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, {1, "* ..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {0, " *..", ""}, + {1, " *..", ""}, {0, "..* ", ", '.', '..', '..a', '..a.a'"}, + {1, "a*.", ", '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, + {0, "*a ", ", '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + + /* a.a.a not found due to short name mismatch, a.a.a -> "AA6BF5~1.A on Windows. */ + {1, "*aa*", ", '.aaa', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, {1, "<.<.<", ", '..a', '..a.a', '.a..a', '.a.a', 'a..a', 'a.a.a'"}, - {1, "<.<.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a..a', 'a.a', 'a.a.a'"}, + {1, "<.<.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a..a', 'a.a', 'a.a.a', ' .a'"}, {1, ".<.<", ", '..a', '..a.a', '.a..a', '.a.a'"}, - {1, "<.<", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a..a', 'a.a', 'a.a.a'"}, + {1, "<.<", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a..a', 'a.a', 'a.a.a', ' .a'"}, {1, ".<", ", '.', '..', '.a', '.aaa'"}, {1, "<.", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, {1, "<", ", '.', '..', '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, @@ -3002,8 +3007,8 @@ static void test_FindFirstFile_wildcards(void) {1, "<..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, {1, ".<.", ", '.', '..', '.a', '.aaa'"}, {1, "..<", ", '..a'"}, - {1, "<<", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, - {1, "<<.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa'"}, + {1, "<<", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, + {1, "<<.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, {1, "<. ", ", '.', '..', '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, {1, "< .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, {1, "< . ", ", '.', '..', '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, @@ -3019,7 +3024,7 @@ static void test_FindFirstFile_wildcards(void) {1, "??.", ", '.', '..', 'a', 'aa'"}, {1, "??. ", ", '.', '..', 'a', 'aa'"}, {1, "???.", ", '.', '..', 'a', 'aa', 'aaa'"}, - {1, "?.??.", ", '.', '..', '.a', 'a', 'a.a'"}, + {1, "?.??.", ", '.', '..', '.a', 'a', 'a.a', ' .a'"}, {1, ">", ", '.', '..', 'a'"}, {1, ">.", ", '.', '..', 'a'"}, @@ -3027,7 +3032,7 @@ static void test_FindFirstFile_wildcards(void) {1, ">>.", ", '.', '..', 'a', 'aa'"}, {1, ">>. ", ", '.', '..', 'a', 'aa'"}, {1, ">>>.", ", '.', '..', 'a', 'aa', 'aaa'"}, - {1, ">.>>.", ", '.', '..', '.a', 'a.a'"}, + {1, ">.>>.", ", '.', '..', '.a', 'a.a', ' .a'"}, }; CreateDirectoryA("test-dir", NULL); From 7f395dbb9131e6c9b8434f3410b80772efa21df2 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 30 Aug 2023 16:10:44 -0600 Subject: [PATCH 2244/2777] kernelbase: Duplicate file name matching code for FindNextFileW(). (cherry picked from commit 68fecd77eb103b6a6cfa53f8de559fb28b29b7b6) CW-Bug-Id: #22684 --- dlls/kernelbase/file.c | 97 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 4 deletions(-) diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c index 0088bc8747b..4d94945cf4e 100644 --- a/dlls/kernelbase/file.c +++ b/dlls/kernelbase/file.c @@ -60,6 +60,7 @@ typedef struct UINT data_pos; /* current position in dir data */ UINT data_len; /* length of dir data */ UINT data_size; /* size of data buffer, or 0 when everything has been read */ + WCHAR *mask; /* mask string to match if wildcards are used */ BYTE data[1]; /* directory data */ } FIND_FIRST_INFO; @@ -1127,7 +1128,7 @@ HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_ OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK io; NTSTATUS status; - DWORD size, device = 0; + DWORD size, mask_size = 0, device = 0; TRACE( "%s %d %p %d %p %lx\n", debugstr_w(filename), level, data, search_op, filter, flags ); @@ -1189,10 +1190,15 @@ HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_ { nt_name.Length = (mask - nt_name.Buffer) * sizeof(WCHAR); has_wildcard = wcspbrk( mask, L"*?" ) != NULL; - size = has_wildcard ? 8192 : max_entry_size; + if (has_wildcard) + { + size = 8192; + mask_size = (lstrlenW( mask ) + 1) * sizeof(*mask); + } + else size = max_entry_size; } - if (!(info = HeapAlloc( GetProcessHeap(), 0, offsetof( FIND_FIRST_INFO, data[size] )))) + if (!(info = HeapAlloc( GetProcessHeap(), 0, offsetof( FIND_FIRST_INFO, data[size + mask_size] )))) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); goto error; @@ -1236,6 +1242,13 @@ HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_ info->data_size = size; info->search_op = search_op; info->level = level; + if (mask_size) + { + info->mask = (WCHAR *)(info->data + size); + memcpy( info->mask, mask, mask_size ); + mask = NULL; + } + else info->mask = NULL; if (device) { @@ -1253,7 +1266,7 @@ HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_ RtlInitUnicodeString( &mask_str, mask ); status = NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, info->data_size, - FileBothDirectoryInformation, FALSE, &mask_str, TRUE ); + FileBothDirectoryInformation, FALSE, has_wildcard ? NULL : &mask_str, TRUE ); if (status) { FindClose( info ); @@ -1336,6 +1349,74 @@ BOOL WINAPI DECLSPEC_HOTPATCH FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *da } +/*********************************************************************** + * match_filename + * + * Check if the file name matches mask containing wildcards. + */ +static BOOL match_filename( const WCHAR *name, int length, const WCHAR *mask ) +{ + BOOL mismatch; + const WCHAR *name_end = name + length; + const WCHAR *mask_end = mask + lstrlenW( mask ); + const WCHAR *lastjoker = NULL; + const WCHAR *next_to_retry = NULL; + + while (name < name_end && mask < mask_end) + { + switch(*mask) + { + case '*': + mask++; + while (mask < mask_end && *mask == '*') mask++; + if (mask == mask_end) return TRUE; /* end of mask is all '*', so match */ + lastjoker = mask; + + /* skip to the next match after the joker(s) */ + while (name < name_end && towupper( *name ) != towupper( *mask )) name++; + next_to_retry = name; + break; + case '?': + case '>': + mask++; + name++; + break; + default: + mismatch = towupper( *mask ) != towupper( *name ); + + if (!mismatch) + { + mask++; + name++; + if (mask == mask_end) + { + if (name == name_end) return TRUE; + if (lastjoker) mask = lastjoker; + } + } + else /* mismatch ! */ + { + if (lastjoker) /* we had an '*', so we can try unlimitedly */ + { + mask = lastjoker; + + /* this scan sequence was a mismatch, so restart + * 1 char after the first char we checked last time */ + next_to_retry++; + name = next_to_retry; + } + else return FALSE; + } + break; + } + } + + while (mask < mask_end && (*mask == '.' || *mask == '*')) + mask++; + return (name == name_end && mask == mask_end); +} + + /****************************************************************************** * FindNextFileW (kernelbase.@) */ @@ -1395,6 +1476,14 @@ BOOL WINAPI DECLSPEC_HOTPATCH FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *da dir_info->FileName[0] == '.' && dir_info->FileName[1] == '.') continue; } + if (info->mask) + { + if (!match_filename( dir_info->FileName, dir_info->FileNameLength / sizeof(WCHAR), info->mask ) + && (!dir_info->ShortNameLength + || !match_filename( dir_info->ShortName, dir_info->ShortNameLength / sizeof(WCHAR), info->mask ))) + continue; + } + data->dwFileAttributes = dir_info->FileAttributes; data->ftCreationTime = *(FILETIME *)&dir_info->CreationTime; data->ftLastAccessTime = *(FILETIME *)&dir_info->LastAccessTime; From 776c31d4f8d975432ce2f70f2ab14918583c0113 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 30 Aug 2023 18:36:25 -0600 Subject: [PATCH 2245/2777] kernelbase: Get unprocessed mask in FindFirstFileExW(). (cherry picked from commit a90f695f78e67b0e4cdd330c8898a72be4c7b09a) CW-Bug-Id: #22684 --- dlls/kernel32/tests/file.c | 4 ++-- dlls/kernelbase/file.c | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index f2751c51e65..35d568a24a1 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -3019,8 +3019,8 @@ static void test_FindFirstFile_wildcards(void) {1, "..< ", ", '..a'"}, {1, "?", ", '.', '..', 'a'"}, - {1, "?.", ", '.', '..', 'a'"}, - {1, "?. ", ", '.', '..', 'a'"}, + {0, "?.", ", '.', '..', 'a'"}, + {0, "?. ", ", '.', '..', 'a'"}, {1, "??.", ", '.', '..', 'a', 'aa'"}, {1, "??. ", ", '.', '..', 'a', 'aa'"}, {1, "???.", ", '.', '..', 'a', 'aa', 'aaa'"}, diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c index 4d94945cf4e..470fdd31423 100644 --- a/dlls/kernelbase/file.c +++ b/dlls/kernelbase/file.c @@ -1193,6 +1193,7 @@ HANDLE WINAPI DECLSPEC_HOTPATCH FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_ if (has_wildcard) { size = 8192; + mask = PathFindFileNameW( filename ); mask_size = (lstrlenW( mask ) + 1) * sizeof(*mask); } else size = max_entry_size; @@ -1411,7 +1412,7 @@ static BOOL match_filename( const WCHAR *name, int length, const WCHAR *mask ) } } - while (mask < mask_end && (*mask == '.' || *mask == '*')) + while (mask < mask_end && (*mask == ' ' || *mask == '.' || *mask == '*')) mask++; return (name == name_end && mask == mask_end); } From 0156602dd2041a292a1613e74f47eb49be6823ba Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 30 Aug 2023 21:07:19 -0600 Subject: [PATCH 2246/2777] kernelbase: Support masks suggesting no extension in FindNextFile(). (cherry picked from commit 9ff0569667e2eaa84ddbb99303231ecd1d6e0d99) CW-Bug-Id: #22684 --- dlls/kernel32/tests/file.c | 12 ++++++------ dlls/kernelbase/file.c | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index 35d568a24a1..66be69409b0 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -2974,21 +2974,21 @@ static void test_FindFirstFile_wildcards(void) {0, ".*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa'"}, {0, "*.*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, {0, ".*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa'"}, - {1, "*.", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {0, "*.", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, {0, "*", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, {1, "*..*", ", '.', '..', '..a', '..a.a', '.a..a', 'a..a'"}, - {1, "*..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {0, "*..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, {1, ".*.", ", '.', '..', '.a', '.aaa'"}, {0, "..*", ", '.', '..', '..a', '..a.a'"}, {0, "**", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, {0, "**.", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, {0, "*. ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, - {1, "* .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {0, "* .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, {0, "* . ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, {0, "*.. ", ", '.', '..', '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, - {1, "*. .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {1, "* ..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, - {1, " *..", ""}, + {0, "*. .", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {0, "* ..", ", '.', '..', 'a', '.a', '..a', 'aa', 'aaa', 'aaaa', '.aaa'"}, + {0, " *..", ""}, {0, "..* ", ", '.', '..', '..a', '..a.a'"}, {1, "a*.", ", '..a', '.a', '.aaa', 'a', 'aa', 'aaa', 'aaaa'"}, {0, "*a ", ", '..a', '..a.a', '.a', '.a..a', '.a.a', '.aaa', 'a', 'a..a', 'a.a', 'a.a.a', 'aa', 'aaa', 'aaaa', ' .a'"}, diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c index 470fdd31423..a497904b9d3 100644 --- a/dlls/kernelbase/file.c +++ b/dlls/kernelbase/file.c @@ -1350,6 +1350,19 @@ BOOL WINAPI DECLSPEC_HOTPATCH FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *da } +/*********************************************************************** + * name_has_ext + * + * Check if the file name has extension (skipping leading dots). + */ +static BOOL name_has_ext( const WCHAR *name, const WCHAR *name_end ) +{ + while (name != name_end && *name == '.') ++name; + while (name != name_end && *name != '.') ++name; + return name != name_end; +} + + /*********************************************************************** * match_filename * @@ -1362,6 +1375,14 @@ static BOOL match_filename( const WCHAR *name, int length, const WCHAR *mask ) const WCHAR *mask_end = mask + lstrlenW( mask ); const WCHAR *lastjoker = NULL; const WCHAR *next_to_retry = NULL; + const WCHAR *asterisk; + + if (mask != mask_end && mask_end[-1] == '.' && (asterisk = wcschr( mask, '*' )) && asterisk == wcsrchr( mask, '*' ) + && name_has_ext( name, name_end )) + { + /* Single '*' mask ending with '.' only matches files without extension. */ + return FALSE; + } while (name < name_end && mask < mask_end) { From 92a21d1b622952462e392b2f320dc9e54ed2b8d3 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 15 Aug 2023 11:22:40 -0600 Subject: [PATCH 2247/2777] Revert "mfplat/buffer: Use appropriate Map flags." This reverts commit 737c30ae820e7bcc20d8f0db0ef6a0a7f7eb31cd. CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 70 ++++---------------------------------------- 1 file changed, 5 insertions(+), 65 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index 6cdc57692a0..97c1ceb5d44 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -967,27 +967,8 @@ static HRESULT dxgi_surface_buffer_create_readback_texture(struct buffer *buffer { D3D11_TEXTURE2D_DESC texture_desc; ID3D11Device *device; - UINT cpu_usage; HRESULT hr; - switch (buffer->_2d.lock_flags) - { - case MF2DBuffer_LockFlags_Read: - cpu_usage = D3D11_CPU_ACCESS_READ; - break; - - case MF2DBuffer_LockFlags_Write: - cpu_usage = D3D11_CPU_ACCESS_WRITE; - break; - - case MF2DBuffer_LockFlags_ReadWrite: - cpu_usage = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; - break; - - default: - return E_INVALIDARG; - } - if (buffer->dxgi_surface.rb_texture) return S_OK; @@ -996,7 +977,7 @@ static HRESULT dxgi_surface_buffer_create_readback_texture(struct buffer *buffer ID3D11Texture2D_GetDesc(buffer->dxgi_surface.texture, &texture_desc); texture_desc.Usage = D3D11_USAGE_STAGING; texture_desc.BindFlags = 0; - texture_desc.CPUAccessFlags = cpu_usage; + texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; texture_desc.MiscFlags = 0; texture_desc.MipLevels = 1; if (FAILED(hr = ID3D11Device_CreateTexture2D(device, &texture_desc, NULL, &buffer->dxgi_surface.rb_texture))) @@ -1011,30 +992,7 @@ static HRESULT dxgi_surface_buffer_map(struct buffer *buffer) { ID3D11DeviceContext *immediate_context; ID3D11Device *device; - D3D11_MAP map_type; HRESULT hr; - BOOL copy; - - switch (buffer->_2d.lock_flags) - { - case MF2DBuffer_LockFlags_Read: - map_type = D3D11_MAP_READ; - copy = TRUE; - break; - - case MF2DBuffer_LockFlags_Write: - map_type = D3D11_MAP_WRITE; - copy = FALSE; - break; - - case MF2DBuffer_LockFlags_ReadWrite: - map_type = D3D11_MAP_READ_WRITE; - copy = TRUE; - break; - - default: - return E_INVALIDARG; - } if (FAILED(hr = dxgi_surface_buffer_create_readback_texture(buffer))) return hr; @@ -1042,15 +1000,16 @@ static HRESULT dxgi_surface_buffer_map(struct buffer *buffer) ID3D11Texture2D_GetDevice(buffer->dxgi_surface.texture, &device); ID3D11Device_GetImmediateContext(device, &immediate_context); - if (copy) + if (buffer->_2d.lock_flags == MF2DBuffer_LockFlags_Read || buffer->_2d.lock_flags == MF2DBuffer_LockFlags_ReadWrite) { ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.texture, buffer->dxgi_surface.sub_resource_idx, NULL); } + // TODO: fix _Map flags memset(&buffer->dxgi_surface.map_desc, 0, sizeof(buffer->dxgi_surface.map_desc)); if (FAILED(hr = ID3D11DeviceContext_Map(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, - 0, map_type, 0, &buffer->dxgi_surface.map_desc))) + 0, D3D11_MAP_READ_WRITE, 0, &buffer->dxgi_surface.map_desc))) { WARN("Failed to map readback texture, hr %#lx.\n", hr); } @@ -1065,32 +1024,13 @@ static void dxgi_surface_buffer_unmap(struct buffer *buffer) { ID3D11DeviceContext *immediate_context; ID3D11Device *device; - BOOL copy; - - switch (buffer->_2d.lock_flags) - { - case MF2DBuffer_LockFlags_Read: - copy = FALSE; - break; - - case MF2DBuffer_LockFlags_Write: - copy = TRUE; - break; - - case MF2DBuffer_LockFlags_ReadWrite: - copy = TRUE; - break; - - default: - copy = FALSE; - } ID3D11Texture2D_GetDevice(buffer->dxgi_surface.texture, &device); ID3D11Device_GetImmediateContext(device, &immediate_context); ID3D11DeviceContext_Unmap(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0); memset(&buffer->dxgi_surface.map_desc, 0, sizeof(buffer->dxgi_surface.map_desc)); - if (copy) + if (buffer->_2d.lock_flags == MF2DBuffer_LockFlags_Write || buffer->_2d.lock_flags == MF2DBuffer_LockFlags_ReadWrite) { ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.texture, buffer->dxgi_surface.sub_resource_idx, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0, NULL); From e07ed9f6e80d712cf0429b1c04d2fe7e67940d34 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 15 Aug 2023 11:22:41 -0600 Subject: [PATCH 2248/2777] Revert "mfplat/buffer: Optimize locking a DXGI surface buffer." This reverts commit c42c848ff6fe77f9aa4c9261920642217dbf5995. CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index 97c1ceb5d44..94f34b236f5 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -56,7 +56,6 @@ struct buffer unsigned int height; int pitch; unsigned int locks; - MF2DBuffer_LockFlags lock_flags; p_copy_image_func copy_image; } _2d; struct @@ -999,14 +998,9 @@ static HRESULT dxgi_surface_buffer_map(struct buffer *buffer) ID3D11Texture2D_GetDevice(buffer->dxgi_surface.texture, &device); ID3D11Device_GetImmediateContext(device, &immediate_context); + ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, + 0, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.texture, buffer->dxgi_surface.sub_resource_idx, NULL); - if (buffer->_2d.lock_flags == MF2DBuffer_LockFlags_Read || buffer->_2d.lock_flags == MF2DBuffer_LockFlags_ReadWrite) - { - ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, - 0, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.texture, buffer->dxgi_surface.sub_resource_idx, NULL); - } - - // TODO: fix _Map flags memset(&buffer->dxgi_surface.map_desc, 0, sizeof(buffer->dxgi_surface.map_desc)); if (FAILED(hr = ID3D11DeviceContext_Map(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0, D3D11_MAP_READ_WRITE, 0, &buffer->dxgi_surface.map_desc))) @@ -1030,11 +1024,8 @@ static void dxgi_surface_buffer_unmap(struct buffer *buffer) ID3D11DeviceContext_Unmap(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0); memset(&buffer->dxgi_surface.map_desc, 0, sizeof(buffer->dxgi_surface.map_desc)); - if (buffer->_2d.lock_flags == MF2DBuffer_LockFlags_Write || buffer->_2d.lock_flags == MF2DBuffer_LockFlags_ReadWrite) - { - ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.texture, - buffer->dxgi_surface.sub_resource_idx, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0, NULL); - } + ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.texture, + buffer->dxgi_surface.sub_resource_idx, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0, NULL); ID3D11DeviceContext_Release(immediate_context); ID3D11Device_Release(device); @@ -1062,7 +1053,6 @@ static HRESULT WINAPI dxgi_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat if (SUCCEEDED(hr)) { - buffer->_2d.lock_flags = MF2DBuffer_LockFlags_ReadWrite; hr = dxgi_surface_buffer_map(buffer); if (SUCCEEDED(hr)) { @@ -1132,14 +1122,7 @@ static HRESULT dxgi_surface_buffer_lock(struct buffer *buffer, MF2DBuffer_LockFl if (buffer->_2d.linear_buffer) hr = MF_E_UNEXPECTED; else if (!buffer->_2d.locks++) - { - buffer->_2d.lock_flags = flags; hr = dxgi_surface_buffer_map(buffer); - } - else if (buffer->_2d.lock_flags != flags) - { - WARN("relocking DXGI surface buffer %p with different flags!\n", buffer); - } if (SUCCEEDED(hr)) { From 8d9f3fb0b63a0b810cfe2e2078b3b25d7fdc5106 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 15 Aug 2023 11:22:42 -0600 Subject: [PATCH 2249/2777] Revert "mfplat/buffer: Implement ContiguousCopyFrom()." This reverts commit 5cfa3a0c0d422b0e809e2fb849681a28570f7dac. CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index 94f34b236f5..bdec2777c39 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -627,34 +627,9 @@ static HRESULT WINAPI memory_2d_buffer_ContiguousCopyTo(IMF2DBuffer2 *iface, BYT static HRESULT WINAPI memory_2d_buffer_ContiguousCopyFrom(IMF2DBuffer2 *iface, const BYTE *src_buffer, DWORD src_length) { - struct buffer *buffer = impl_from_IMF2DBuffer2(iface); - BYTE *dst_scanline0, *dst_buffer_start; - DWORD dst_length; - HRESULT hr, hr2; - LONG dst_pitch; - - TRACE("%p, %p, %lu.\n", iface, src_buffer, src_length); - - if (src_length != buffer->_2d.plane_size) - { - WARN("truncating contiguous copy not implemented\n"); - return E_NOTIMPL; - } - - hr = IMF2DBuffer2_Lock2DSize(iface, MF2DBuffer_LockFlags_Write, &dst_scanline0, &dst_pitch, &dst_buffer_start, &dst_length); + FIXME("%p, %p, %lu.\n", iface, src_buffer, src_length); - if (SUCCEEDED(hr)) - { - hr = copy_image(buffer, dst_scanline0, dst_pitch, src_buffer, buffer->_2d.width, buffer->_2d.width, buffer->_2d.height, buffer->max_length); - } - - hr2 = IMF2DBuffer2_Unlock2D(iface); - if (FAILED(hr2)) - WARN("Unlocking destination buffer %p failed with hr %#lx.\n", iface, hr2); - if (FAILED(hr2) && SUCCEEDED(hr)) - hr = hr2; - - return hr; + return E_NOTIMPL; } static HRESULT WINAPI memory_2d_buffer_Lock2DSize(IMF2DBuffer2 *iface, MF2DBuffer_LockFlags flags, BYTE **scanline0, From 9059288e88421ccd16284840b3d05fda6e90584c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 15 Aug 2023 11:22:43 -0600 Subject: [PATCH 2250/2777] Revert "mfplat: Implement IMF2DBuffer2::Copy2DTo()." This reverts commit 968ac2bffba1db38b9afd93bb4ef9770d1da21cf. CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 49 ++++---------------------------------------- 1 file changed, 4 insertions(+), 45 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index bdec2777c39..c617abf7ae0 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -652,52 +652,11 @@ static HRESULT WINAPI memory_2d_buffer_Lock2DSize(IMF2DBuffer2 *iface, MF2DBuffe return hr; } -static HRESULT WINAPI memory_2d_buffer_Copy2DTo(IMF2DBuffer2 *iface, IMF2DBuffer2 *dst_buffer) +static HRESULT WINAPI memory_2d_buffer_Copy2DTo(IMF2DBuffer2 *iface, IMF2DBuffer2 *dest_buffer) { - struct buffer *buffer = impl_from_IMF2DBuffer2(iface); - BYTE *src_scanline0, *dst_scanline0, *src_buffer_start, *dst_buffer_start; - DWORD src_length, dst_length; - LONG src_pitch, dst_pitch; - BOOL src_locked = FALSE, dst_locked = FALSE; - HRESULT hr, hr2; - - TRACE("%p, %p.\n", iface, dst_buffer); - - hr = IMF2DBuffer2_Lock2DSize(iface, MF2DBuffer_LockFlags_Read, &src_scanline0, - &src_pitch, &src_buffer_start, &src_length); - if (FAILED(hr)) - goto end; - src_locked = TRUE; + FIXME("%p, %p.\n", iface, dest_buffer); - hr = IMF2DBuffer2_Lock2DSize(dst_buffer, MF2DBuffer_LockFlags_Write, &dst_scanline0, - &dst_pitch, &dst_buffer_start, &dst_length); - if (FAILED(hr)) - goto end; - dst_locked = TRUE; - - hr = copy_image(buffer, dst_scanline0, dst_pitch, src_scanline0, src_pitch, - buffer->_2d.width, buffer->_2d.height, dst_length); - -end: - if (src_locked) - { - hr2 = IMF2DBuffer2_Unlock2D(iface); - if (FAILED(hr2)) - WARN("Unlocking source buffer %p failed with hr %#lx.\n", iface, hr2); - if (FAILED(hr2) && SUCCEEDED(hr)) - hr = hr2; - } - - if (dst_locked) - { - hr2 = IMF2DBuffer2_Unlock2D(dst_buffer); - if (FAILED(hr2)) - WARN("Unlocking destination buffer %p failed with hr %#lx.\n", dst_buffer, hr2); - if (FAILED(hr2) && SUCCEEDED(hr)) - hr = hr2; - } - - return hr; + return E_NOTIMPL; } static const IMF2DBuffer2Vtbl memory_2d_buffer_vtbl = @@ -1380,7 +1339,7 @@ static p_copy_image_func get_2d_buffer_copy_func(DWORD fourcc) return copy_image_nv12; if (fourcc == MAKEFOURCC('I','M','C','1') || fourcc == MAKEFOURCC('I','M','C','3')) return copy_image_imc1; - if (fourcc == MAKEFOURCC('I','M','C','2') || fourcc == MAKEFOURCC('I','M','C','4') || fourcc == MAKEFOURCC('Y','V','1', '2')) + if (fourcc == MAKEFOURCC('I','M','C','2') || fourcc == MAKEFOURCC('I','M','C','4')) return copy_image_imc2; return NULL; } From 691b2b726065cae48a56dd18528c28d11624b2d7 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 15 Aug 2023 11:22:44 -0600 Subject: [PATCH 2251/2777] Revert "mfplat/buffer: Validate buffer size in image copying functions." This reverts commit eefc50a6d3bd6a08db1d4701442493448e6baf9d. CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index c617abf7ae0..b955a0ac8b9 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -80,9 +80,6 @@ static HRESULT copy_image(const struct buffer *buffer, BYTE *dest, LONG dest_str { HRESULT hr = S_OK; - if (width > abs(dest_stride) || abs(dest_stride) * lines > dest_size) - return E_NOT_SUFFICIENT_BUFFER; - hr = MFCopyImage(dest, dest_stride, src, src_stride, width, lines); if (SUCCEEDED(hr) && buffer->_2d.copy_image) @@ -98,27 +95,18 @@ static HRESULT copy_image(const struct buffer *buffer, BYTE *dest, LONG dest_str static HRESULT copy_image_nv12(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines, DWORD dest_size) { - if (abs(dest_stride) * (lines + lines / 2) > dest_size) - return E_NOT_SUFFICIENT_BUFFER; - return MFCopyImage(dest, dest_stride, src, src_stride, width, lines / 2); } static HRESULT copy_image_imc1(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines, DWORD dest_size) { - if (abs(dest_stride) * (2 * lines) > dest_size) - return E_NOT_SUFFICIENT_BUFFER; - return MFCopyImage(dest, dest_stride, src, src_stride, width / 2, lines); } static HRESULT copy_image_imc2(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines, DWORD dest_size) { - if (abs(dest_stride) * 3 * lines / 2 > dest_size) - return E_NOT_SUFFICIENT_BUFFER; - return MFCopyImage(dest, dest_stride / 2, src, src_stride / 2, width / 2, lines); } From 399b5ea3f60dca2730f33e7f7b1ff0938edae4f0 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 15 Aug 2023 11:22:49 -0600 Subject: [PATCH 2252/2777] Revert "mfplat/buffer: Prepare image copying functions for error checking." This reverts commit 3b621e598b0c7ce54610c5c81fcb3e9deea67e3b. CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 58 +++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index b955a0ac8b9..e3d38438b88 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -32,7 +32,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); #define ALIGN_SIZE(size, alignment) (((size) + (alignment)) & ~((alignment))) -typedef HRESULT (*p_copy_image_func)(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines, DWORD dest_size); +typedef void (*p_copy_image_func)(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines); struct buffer { @@ -75,39 +75,32 @@ struct buffer CRITICAL_SECTION cs; }; -static HRESULT copy_image(const struct buffer *buffer, BYTE *dest, LONG dest_stride, const BYTE *src, - LONG src_stride, DWORD width, DWORD lines, DWORD dest_size) +static void copy_image(const struct buffer *buffer, BYTE *dest, LONG dest_stride, const BYTE *src, + LONG src_stride, DWORD width, DWORD lines) { - HRESULT hr = S_OK; - - hr = MFCopyImage(dest, dest_stride, src, src_stride, width, lines); + MFCopyImage(dest, dest_stride, src, src_stride, width, lines); - if (SUCCEEDED(hr) && buffer->_2d.copy_image) + if (buffer->_2d.copy_image) { dest += dest_stride * lines; src += src_stride * lines; - hr = buffer->_2d.copy_image(dest, dest_stride, src, src_stride, width, lines, dest_size); + buffer->_2d.copy_image(dest, dest_stride, src, src_stride, width, lines); } - - return hr; } -static HRESULT copy_image_nv12(BYTE *dest, LONG dest_stride, const BYTE *src, - LONG src_stride, DWORD width, DWORD lines, DWORD dest_size) +static void copy_image_nv12(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines) { - return MFCopyImage(dest, dest_stride, src, src_stride, width, lines / 2); + MFCopyImage(dest, dest_stride, src, src_stride, width, lines / 2); } -static HRESULT copy_image_imc1(BYTE *dest, LONG dest_stride, const BYTE *src, - LONG src_stride, DWORD width, DWORD lines, DWORD dest_size) +static void copy_image_imc1(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines) { - return MFCopyImage(dest, dest_stride, src, src_stride, width / 2, lines); + MFCopyImage(dest, dest_stride, src, src_stride, width / 2, lines); } -static HRESULT copy_image_imc2(BYTE *dest, LONG dest_stride, const BYTE *src, - LONG src_stride, DWORD width, DWORD lines, DWORD dest_size) +static void copy_image_imc2(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines) { - return MFCopyImage(dest, dest_stride / 2, src, src_stride / 2, width / 2, lines); + MFCopyImage(dest, dest_stride / 2, src, src_stride / 2, width / 2, lines); } static inline struct buffer *impl_from_IMFMediaBuffer(IMFMediaBuffer *iface) @@ -319,8 +312,8 @@ static HRESULT WINAPI memory_1d_2d_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat hr = E_OUTOFMEMORY; if (SUCCEEDED(hr)) - hr = copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, buffer->data, buffer->_2d.pitch, - buffer->_2d.width, buffer->_2d.height, buffer->_2d.plane_size); + copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, buffer->data, buffer->_2d.pitch, + buffer->_2d.width, buffer->_2d.height); } if (SUCCEEDED(hr)) @@ -341,7 +334,6 @@ static HRESULT WINAPI memory_1d_2d_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat static HRESULT WINAPI memory_1d_2d_buffer_Unlock(IMFMediaBuffer *iface) { struct buffer *buffer = impl_from_IMFMediaBuffer(iface); - HRESULT hr = S_OK; TRACE("%p.\n", iface); @@ -349,8 +341,8 @@ static HRESULT WINAPI memory_1d_2d_buffer_Unlock(IMFMediaBuffer *iface) if (buffer->_2d.linear_buffer && !--buffer->_2d.locks) { - hr = copy_image(buffer, buffer->data, buffer->_2d.pitch, buffer->_2d.linear_buffer, buffer->_2d.width, - buffer->_2d.width, buffer->_2d.height, buffer->max_length); + copy_image(buffer, buffer->data, buffer->_2d.pitch, buffer->_2d.linear_buffer, buffer->_2d.width, + buffer->_2d.width, buffer->_2d.height); free(buffer->_2d.linear_buffer); buffer->_2d.linear_buffer = NULL; @@ -358,7 +350,7 @@ static HRESULT WINAPI memory_1d_2d_buffer_Unlock(IMFMediaBuffer *iface) LeaveCriticalSection(&buffer->cs); - return hr; + return S_OK; } static const IMFMediaBufferVtbl memory_1d_2d_buffer_vtbl = @@ -399,8 +391,8 @@ static HRESULT WINAPI d3d9_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &rect, NULL, 0); if (SUCCEEDED(hr)) { - hr = copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, rect.pBits, rect.Pitch, - buffer->_2d.width, buffer->_2d.height, buffer->_2d.plane_size); + copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, rect.pBits, rect.Pitch, + buffer->_2d.width, buffer->_2d.height); IDirect3DSurface9_UnlockRect(buffer->d3d9_surface.surface); } } @@ -438,8 +430,8 @@ static HRESULT WINAPI d3d9_surface_buffer_Unlock(IMFMediaBuffer *iface) if (SUCCEEDED(hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &rect, NULL, 0))) { - hr = copy_image(buffer, rect.pBits, rect.Pitch, buffer->_2d.linear_buffer, buffer->_2d.width, - buffer->_2d.width, buffer->_2d.height, buffer->max_length); + copy_image(buffer, rect.pBits, rect.Pitch, buffer->_2d.linear_buffer, buffer->_2d.width, + buffer->_2d.width, buffer->_2d.height); IDirect3DSurface9_UnlockRect(buffer->d3d9_surface.surface); } @@ -978,8 +970,8 @@ static HRESULT WINAPI dxgi_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat hr = dxgi_surface_buffer_map(buffer); if (SUCCEEDED(hr)) { - hr = copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, buffer->dxgi_surface.map_desc.pData, - buffer->dxgi_surface.map_desc.RowPitch, buffer->_2d.width, buffer->_2d.height, buffer->_2d.plane_size); + copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, buffer->dxgi_surface.map_desc.pData, + buffer->dxgi_surface.map_desc.RowPitch, buffer->_2d.width, buffer->_2d.height); } } } @@ -1012,8 +1004,8 @@ static HRESULT WINAPI dxgi_surface_buffer_Unlock(IMFMediaBuffer *iface) hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED); else if (!--buffer->_2d.locks) { - hr = copy_image(buffer, buffer->dxgi_surface.map_desc.pData, buffer->dxgi_surface.map_desc.RowPitch, - buffer->_2d.linear_buffer, buffer->_2d.width, buffer->_2d.width, buffer->_2d.height, buffer->max_length); + copy_image(buffer, buffer->dxgi_surface.map_desc.pData, buffer->dxgi_surface.map_desc.RowPitch, + buffer->_2d.linear_buffer, buffer->_2d.width, buffer->_2d.width, buffer->_2d.height); dxgi_surface_buffer_unmap(buffer); free(buffer->_2d.linear_buffer); From f7598bc02d8dbbd729a7ae78e14f0507cd5629c7 Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Wed, 21 Dec 2022 16:57:36 +0800 Subject: [PATCH 2253/2777] mfplat: Support YVYU, NV11, MEDIASUBTYPE_RGB* media types. (cherry picked from commit df26eae97dce7907cff087bde36775504fcb5c3e) CW-Bug-Id: #22084 --- dlls/mf/tests/transform.c | 4 ++-- dlls/mfplat/buffer.c | 3 +++ dlls/mfplat/mediatype.c | 11 +++++++++++ dlls/mfplat/tests/mfplat.c | 9 --------- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 36181c33d20..60ea02313ac 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -5836,8 +5836,8 @@ static void test_video_processor(void) && !IsEqualGUID(&guid, &MEDIASUBTYPE_Y42T)) { hr = MFCalculateImageSize(&guid, 16, 16, (UINT32 *)&input_info.cbSize); - todo_wine_if(IsEqualGUID(&guid, &MFVideoFormat_NV11) || IsEqualGUID(&guid, &MFVideoFormat_YVYU) - || IsEqualGUID(&guid, &MFVideoFormat_Y216) || IsEqualGUID(&guid, &MFVideoFormat_v410) + todo_wine_if(IsEqualGUID(&guid, &MFVideoFormat_Y216) + || IsEqualGUID(&guid, &MFVideoFormat_v410) || IsEqualGUID(&guid, &MFVideoFormat_Y41P)) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); } diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index e3d38438b88..a221c6d55b8 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -1357,6 +1357,7 @@ static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, BOOL bo break; case MAKEFOURCC('I','M','C','2'): case MAKEFOURCC('I','M','C','4'): + case MAKEFOURCC('N','V','1','1'): plane_size = stride * 3 / 2 * height; break; case MAKEFOURCC('N','V','1','2'): @@ -1379,6 +1380,7 @@ static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, BOOL bo case MAKEFOURCC('I','M','C','3'): case MAKEFOURCC('I','M','C','4'): case MAKEFOURCC('Y','V','1','2'): + case MAKEFOURCC('N','V','1','1'): row_alignment = MF_128_BYTE_ALIGNMENT; break; default: @@ -1397,6 +1399,7 @@ static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, BOOL bo case MAKEFOURCC('Y','V','1','2'): case MAKEFOURCC('I','M','C','2'): case MAKEFOURCC('I','M','C','4'): + case MAKEFOURCC('N','V','1','1'): max_length = pitch * height * 3 / 2; break; default: diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 2e16de96849..374024d8190 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -2713,13 +2713,20 @@ static const struct uncompressed_video_format video_formats[] = { &MFVideoFormat_IMC3, 2, 3, 0, 1 }, { &MFVideoFormat_IMC4, 1, 0, 0, 1 }, { &MFVideoFormat_IYUV, 1, 0, 0, 1 }, + { &MFVideoFormat_NV11, 1, 0, 0, 1 }, { &MFVideoFormat_NV12, 1, 0, 0, 1 }, { &MFVideoFormat_D16, 2, 3, 0, 0 }, { &MFVideoFormat_L16, 2, 3, 0, 0 }, { &MFVideoFormat_UYVY, 2, 0, 0, 1 }, { &MFVideoFormat_YUY2, 2, 0, 0, 1 }, { &MFVideoFormat_YV12, 1, 0, 0, 1 }, + { &MFVideoFormat_YVYU, 2, 0, 0, 1 }, { &MFVideoFormat_A16B16G16R16F, 8, 3, 1, 0 }, + { &MEDIASUBTYPE_RGB8, 1, 3, 1, 0 }, + { &MEDIASUBTYPE_RGB565, 2, 3, 1, 0 }, + { &MEDIASUBTYPE_RGB555, 2, 3, 1, 0 }, + { &MEDIASUBTYPE_RGB24, 3, 3, 1, 0 }, + { &MEDIASUBTYPE_RGB32, 4, 3, 1, 0 }, }; static struct uncompressed_video_format *mf_get_video_format(const GUID *subtype) @@ -2799,6 +2806,9 @@ HRESULT WINAPI MFCalculateImageSize(REFGUID subtype, UINT32 width, UINT32 height /* 2 x 2 block, interleaving UV for half the height */ *size = ((width + 1) & ~1) * height * 3 / 2; break; + case MAKEFOURCC('N','V','1','1'): + *size = ((width + 3) & ~3) * height * 3 / 2; + break; case D3DFMT_L8: case D3DFMT_L16: case D3DFMT_D16: @@ -2839,6 +2849,7 @@ HRESULT WINAPI MFGetPlaneSize(DWORD fourcc, DWORD width, DWORD height, DWORD *si case MAKEFOURCC('Y','V','1','2'): case MAKEFOURCC('I','4','2','0'): case MAKEFOURCC('I','Y','U','V'): + case MAKEFOURCC('N','V','1','1'): *size = stride * height * 3 / 2; break; default: diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 2dd3e834a0e..9969fd7213e 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -4453,7 +4453,6 @@ static void test_MFCalculateImageSize(void) IsEqualGUID(ptr->subtype, &MFVideoFormat_A2R10G10B10); hr = MFCalculateImageSize(ptr->subtype, ptr->width, ptr->height, &size); - todo_wine_if(is_MEDIASUBTYPE_RGB(ptr->subtype) || IsEqualGUID(ptr->subtype, &MFVideoFormat_NV11)) ok(hr == S_OK || (is_broken && hr == E_INVALIDARG), "%u: failed to calculate image size, hr %#lx.\n", i, hr); todo_wine_if(is_MEDIASUBTYPE_RGB(ptr->subtype) || IsEqualGUID(ptr->subtype, &MFVideoFormat_NV11) @@ -5827,9 +5826,7 @@ static void test_MFGetStrideForBitmapInfoHeader(void) for (i = 0; i < ARRAY_SIZE(stride_tests); ++i) { hr = pMFGetStrideForBitmapInfoHeader(stride_tests[i].subtype->Data1, stride_tests[i].width, &stride); - todo_wine_if(IsEqualGUID(stride_tests[i].subtype, &MFVideoFormat_NV11)) ok(hr == S_OK, "%u: failed to get stride, hr %#lx.\n", i, hr); - todo_wine_if(IsEqualGUID(stride_tests[i].subtype, &MFVideoFormat_NV11)) ok(stride == stride_tests[i].stride, "%u: format %s, unexpected stride %ld, expected %ld.\n", i, wine_dbgstr_an((char *)&stride_tests[i].subtype->Data1, 4), stride, stride_tests[i].stride); } @@ -6042,10 +6039,7 @@ static void test_MFCreate2DMediaBuffer(void) continue; hr = pMFCreate2DMediaBuffer(ptr->width, ptr->height, ptr->subtype->Data1, FALSE, &buffer); - todo_wine_if(IsEqualGUID(ptr->subtype, &MFVideoFormat_NV11)) ok(hr == S_OK, "Failed to create a buffer, hr %#lx.\n", hr); - if (hr != S_OK) - continue; hr = IMFMediaBuffer_GetMaxLength(buffer, &length); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -6188,10 +6182,7 @@ static void test_MFCreate2DMediaBuffer(void) continue; hr = pMFCreate2DMediaBuffer(ptr->width, ptr->height, ptr->subtype->Data1, FALSE, &buffer); - todo_wine_if(IsEqualGUID(ptr->subtype, &MFVideoFormat_NV11)) ok(hr == S_OK, "Failed to create a buffer, hr %#lx.\n", hr); - if (hr != S_OK) - continue; hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer, (void **)&_2dbuffer); ok(hr == S_OK, "Failed to get interface, hr %#lx.\n", hr); From 11bc79706b17e0a4cdc34d9f3bfa90c14684f910 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Thu, 13 Apr 2023 15:47:44 +0200 Subject: [PATCH 2254/2777] mfplat: Fix locking flags usage for D3D9 buffers. (cherry picked from commit 91c0eda70972f1d6421d9dbb035b3ca50aef8d76) CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 8 ++++++-- dlls/mfplat/tests/mfplat.c | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index a221c6d55b8..df85af37126 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -56,6 +56,7 @@ struct buffer unsigned int height; int pitch; unsigned int locks; + MF2DBuffer_LockFlags lock_flags; p_copy_image_func copy_image; } _2d; struct @@ -663,12 +664,14 @@ static HRESULT d3d9_surface_buffer_lock(struct buffer *buffer, MF2DBuffer_LockFl if (buffer->_2d.linear_buffer) hr = MF_E_UNEXPECTED; else if (!buffer->_2d.locks) - { hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &buffer->d3d9_surface.rect, NULL, 0); - } + else if (buffer->_2d.lock_flags == MF2DBuffer_LockFlags_Write && flags != MF2DBuffer_LockFlags_Write) + hr = HRESULT_FROM_WIN32(ERROR_WAS_LOCKED); if (SUCCEEDED(hr)) { + if (!buffer->_2d.locks) + buffer->_2d.lock_flags = flags; buffer->_2d.locks++; *scanline0 = buffer->d3d9_surface.rect.pBits; *pitch = buffer->d3d9_surface.rect.Pitch; @@ -715,6 +718,7 @@ static HRESULT WINAPI d3d9_surface_buffer_Unlock2D(IMF2DBuffer2 *iface) { IDirect3DSurface9_UnlockRect(buffer->d3d9_surface.surface); memset(&buffer->d3d9_surface.rect, 0, sizeof(buffer->d3d9_surface.rect)); + buffer->_2d.lock_flags = 0; } } else diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 9969fd7213e..ff2d6fa15aa 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -6706,7 +6706,39 @@ static void test_MFCreateDXSurfaceBuffer(void) hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_ReadWrite, &data, &pitch, &data2, &length); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - IMF2DBuffer2_Unlock2D(_2dbuffer2); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_Lock2D(_2dbuffer, &data, &pitch); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Except when originally locking for writing. */ + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_ReadWrite, &data, &pitch, &data2, &length); + ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_LOCKED), "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_LOCKED), "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_Lock2D(_2dbuffer, &data, &pitch); + ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_LOCKED), "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED), "Unexpected hr %#lx.\n", hr); IMF2DBuffer2_Release(_2dbuffer2); From cab64e1bde59bf3581172c8958f7f76910083401 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 17 Apr 2023 15:24:08 +0200 Subject: [PATCH 2255/2777] mfplat: Do not mark a DXGI buffer as locked if surface mapping fails. Analogous to 44c9ea50432771258e9eed012967a16c6f132fe9. (cherry picked from commit df660e80f07fd129a9fbbd3c01c153c6a2ebb558) CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index df85af37126..1c38e03c3e1 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -1039,11 +1039,12 @@ static HRESULT dxgi_surface_buffer_lock(struct buffer *buffer, MF2DBuffer_LockFl if (buffer->_2d.linear_buffer) hr = MF_E_UNEXPECTED; - else if (!buffer->_2d.locks++) + else if (!buffer->_2d.locks) hr = dxgi_surface_buffer_map(buffer); if (SUCCEEDED(hr)) { + buffer->_2d.locks++; *scanline0 = buffer->dxgi_surface.map_desc.pData; *pitch = buffer->dxgi_surface.map_desc.RowPitch; if (buffer_start) From 125a7e6d2f397c6da0231311ad7fa0355927e1e9 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 17 Apr 2023 15:45:38 +0200 Subject: [PATCH 2256/2777] mfplat: Fix locking flags usage for DXGI buffers. (cherry picked from commit 071eb50ff08a8a73484830dbb37509a350f099ae) CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 7 +++ dlls/mfplat/tests/mfplat.c | 115 +++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index 1c38e03c3e1..c8e797e6743 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -1041,9 +1041,13 @@ static HRESULT dxgi_surface_buffer_lock(struct buffer *buffer, MF2DBuffer_LockFl hr = MF_E_UNEXPECTED; else if (!buffer->_2d.locks) hr = dxgi_surface_buffer_map(buffer); + else if (buffer->_2d.lock_flags == MF2DBuffer_LockFlags_Write && flags != MF2DBuffer_LockFlags_Write) + hr = HRESULT_FROM_WIN32(ERROR_WAS_LOCKED); if (SUCCEEDED(hr)) { + if (!buffer->_2d.locks) + buffer->_2d.lock_flags = flags; buffer->_2d.locks++; *scanline0 = buffer->dxgi_surface.map_desc.pData; *pitch = buffer->dxgi_surface.map_desc.RowPitch; @@ -1087,7 +1091,10 @@ static HRESULT WINAPI dxgi_surface_buffer_Unlock2D(IMF2DBuffer2 *iface) if (buffer->_2d.locks) { if (!--buffer->_2d.locks) + { dxgi_surface_buffer_unmap(buffer); + buffer->_2d.lock_flags = 0; + } } else hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED); diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index ff2d6fa15aa..f324379c387 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7299,7 +7299,122 @@ static void test_d3d11_surface_buffer(void) hr = IMF2DBuffer_Unlock2D(_2d_buffer); ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED), "Unexpected hr %#lx.\n", hr); + hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMF2DBuffer_Lock2D(_2d_buffer, &data, &pitch); + ok(hr == MF_E_UNEXPECTED, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMF2DBuffer_Release(_2d_buffer); + + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer2, (void **)&_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Lock flags are honored, so reads and writes are discarded if + * the flags are not correct. */ + put_d3d11_texture_color(texture, 0, 0, 0xcdcdcdcd); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(data == data2, "Unexpected scanline pointer.\n"); + ok(*(DWORD *)data == 0xcdcdcdcd, "Unexpected leading dword %#lx.\n", *(DWORD *)data); + memset(data, 0xab, 4); + IMF2DBuffer2_Unlock2D(_2dbuffer2); + + color = get_d3d11_texture_color(texture, 0, 0); + todo_wine + ok(color == 0xcdcdcdcd, "Unexpected leading dword %#lx.\n", color); + put_d3d11_texture_color(texture, 0, 0, 0xefefefef); + + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(*(DWORD *)data != 0xefefefef, "Unexpected leading dword.\n"); + memset(data, 0x89, 4); + IMF2DBuffer2_Unlock2D(_2dbuffer2); + + color = get_d3d11_texture_color(texture, 0, 0); + ok(color == 0x89898989, "Unexpected leading dword %#lx.\n", color); + + /* When relocking for writing, stores are committed even if they + * were issued before relocking. */ + put_d3d11_texture_color(texture, 0, 0, 0xcdcdcdcd); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + memset(data, 0xab, 4); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMF2DBuffer2_Unlock2D(_2dbuffer2); + IMF2DBuffer2_Unlock2D(_2dbuffer2); + + color = get_d3d11_texture_color(texture, 0, 0); + ok(color == 0xabababab, "Unexpected leading dword %#lx.\n", color); + + /* Flags incompatibilities. */ + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_ReadWrite, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_ReadWrite, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_Lock2D(_2d_buffer, &data, &pitch); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_ReadWrite, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_Lock2D(_2d_buffer, &data, &pitch); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Except when originally locking for writing. */ + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_ReadWrite, &data, &pitch, &data2, &length); + ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_LOCKED), "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &data2, &length); + ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_LOCKED), "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer_Lock2D(_2d_buffer, &data, &pitch); + ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_LOCKED), "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED), "Unexpected hr %#lx.\n", hr); + + IMF2DBuffer2_Release(_2dbuffer2); IMFMediaBuffer_Release(buffer); /* Bottom up. */ From b88c73d801bc6c3b706c35c93ac6305a5418c6c8 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 17 Apr 2023 15:52:17 +0200 Subject: [PATCH 2257/2777] mfplat: Only download surface data from GPU for DXGI buffers when reading. (cherry picked from commit 49b8e55b3c086754418ecec015c2e30ea72160c9) CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 14 +++++++++----- dlls/mfplat/tests/mfplat.c | 1 - 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index c8e797e6743..c0874faa23d 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -905,7 +905,7 @@ static HRESULT dxgi_surface_buffer_create_readback_texture(struct buffer *buffer return hr; } -static HRESULT dxgi_surface_buffer_map(struct buffer *buffer) +static HRESULT dxgi_surface_buffer_map(struct buffer *buffer, MF2DBuffer_LockFlags flags) { ID3D11DeviceContext *immediate_context; ID3D11Device *device; @@ -916,8 +916,12 @@ static HRESULT dxgi_surface_buffer_map(struct buffer *buffer) ID3D11Texture2D_GetDevice(buffer->dxgi_surface.texture, &device); ID3D11Device_GetImmediateContext(device, &immediate_context); - ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, - 0, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.texture, buffer->dxgi_surface.sub_resource_idx, NULL); + + if (flags == MF2DBuffer_LockFlags_Read || flags == MF2DBuffer_LockFlags_ReadWrite) + { + ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, + 0, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.texture, buffer->dxgi_surface.sub_resource_idx, NULL); + } memset(&buffer->dxgi_surface.map_desc, 0, sizeof(buffer->dxgi_surface.map_desc)); if (FAILED(hr = ID3D11DeviceContext_Map(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, @@ -971,7 +975,7 @@ static HRESULT WINAPI dxgi_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat if (SUCCEEDED(hr)) { - hr = dxgi_surface_buffer_map(buffer); + hr = dxgi_surface_buffer_map(buffer, MF2DBuffer_LockFlags_ReadWrite); if (SUCCEEDED(hr)) { copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, buffer->dxgi_surface.map_desc.pData, @@ -1040,7 +1044,7 @@ static HRESULT dxgi_surface_buffer_lock(struct buffer *buffer, MF2DBuffer_LockFl if (buffer->_2d.linear_buffer) hr = MF_E_UNEXPECTED; else if (!buffer->_2d.locks) - hr = dxgi_surface_buffer_map(buffer); + hr = dxgi_surface_buffer_map(buffer, flags); else if (buffer->_2d.lock_flags == MF2DBuffer_LockFlags_Write && flags != MF2DBuffer_LockFlags_Write) hr = HRESULT_FROM_WIN32(ERROR_WAS_LOCKED); diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index f324379c387..99cdd04976f 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7330,7 +7330,6 @@ static void test_d3d11_surface_buffer(void) hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Write, &data, &pitch, &data2, &length); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(*(DWORD *)data != 0xefefefef, "Unexpected leading dword.\n"); memset(data, 0x89, 4); IMF2DBuffer2_Unlock2D(_2dbuffer2); From c2ed34573eb832c735cbe5a6366f0bcab1f2f03f Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 17 Apr 2023 16:02:10 +0200 Subject: [PATCH 2258/2777] mfplat: Only upload surface data to GPU for DXGI buffers when writing. (cherry picked from commit d073d3ea18d32d35a1d324d5567f7d743372a25c) CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 15 ++++++++++----- dlls/mfplat/tests/mfplat.c | 1 - 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index c0874faa23d..d8de06fb23a 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -936,7 +936,7 @@ static HRESULT dxgi_surface_buffer_map(struct buffer *buffer, MF2DBuffer_LockFla return hr; } -static void dxgi_surface_buffer_unmap(struct buffer *buffer) +static void dxgi_surface_buffer_unmap(struct buffer *buffer, MF2DBuffer_LockFlags flags) { ID3D11DeviceContext *immediate_context; ID3D11Device *device; @@ -946,8 +946,11 @@ static void dxgi_surface_buffer_unmap(struct buffer *buffer) ID3D11DeviceContext_Unmap(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0); memset(&buffer->dxgi_surface.map_desc, 0, sizeof(buffer->dxgi_surface.map_desc)); - ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.texture, - buffer->dxgi_surface.sub_resource_idx, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0, NULL); + if (flags == MF2DBuffer_LockFlags_Write || flags == MF2DBuffer_LockFlags_ReadWrite) + { + ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.texture, + buffer->dxgi_surface.sub_resource_idx, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0, NULL); + } ID3D11DeviceContext_Release(immediate_context); ID3D11Device_Release(device); @@ -1014,7 +1017,7 @@ static HRESULT WINAPI dxgi_surface_buffer_Unlock(IMFMediaBuffer *iface) { copy_image(buffer, buffer->dxgi_surface.map_desc.pData, buffer->dxgi_surface.map_desc.RowPitch, buffer->_2d.linear_buffer, buffer->_2d.width, buffer->_2d.width, buffer->_2d.height); - dxgi_surface_buffer_unmap(buffer); + dxgi_surface_buffer_unmap(buffer, MF2DBuffer_LockFlags_ReadWrite); free(buffer->_2d.linear_buffer); buffer->_2d.linear_buffer = NULL; @@ -1052,6 +1055,8 @@ static HRESULT dxgi_surface_buffer_lock(struct buffer *buffer, MF2DBuffer_LockFl { if (!buffer->_2d.locks) buffer->_2d.lock_flags = flags; + else + buffer->_2d.lock_flags |= flags; buffer->_2d.locks++; *scanline0 = buffer->dxgi_surface.map_desc.pData; *pitch = buffer->dxgi_surface.map_desc.RowPitch; @@ -1096,7 +1101,7 @@ static HRESULT WINAPI dxgi_surface_buffer_Unlock2D(IMF2DBuffer2 *iface) { if (!--buffer->_2d.locks) { - dxgi_surface_buffer_unmap(buffer); + dxgi_surface_buffer_unmap(buffer, buffer->_2d.lock_flags); buffer->_2d.lock_flags = 0; } } diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 99cdd04976f..507830e5843 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7324,7 +7324,6 @@ static void test_d3d11_surface_buffer(void) IMF2DBuffer2_Unlock2D(_2dbuffer2); color = get_d3d11_texture_color(texture, 0, 0); - todo_wine ok(color == 0xcdcdcdcd, "Unexpected leading dword %#lx.\n", color); put_d3d11_texture_color(texture, 0, 0, 0xefefefef); From 6cf6a291931d190af504adcb96d61fb8f2a4e503 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 4 Apr 2023 16:07:19 -0600 Subject: [PATCH 2259/2777] mfplat: Fix returned buffer length in dxgi_surface_buffer_lock(). (cherry picked from commit 5a162f2c316a28ad45f7c0707ed16b194204227e) CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 2 +- dlls/mfplat/tests/mfplat.c | 52 +++++++++++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index d8de06fb23a..1b9ba24a408 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -1063,7 +1063,7 @@ static HRESULT dxgi_surface_buffer_lock(struct buffer *buffer, MF2DBuffer_LockFl if (buffer_start) *buffer_start = *scanline0; if (buffer_length) - *buffer_length = buffer->dxgi_surface.map_desc.RowPitch * buffer->_2d.height; + *buffer_length = buffer->dxgi_surface.map_desc.DepthPitch; } return hr; diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 507830e5843..1307b690f4a 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -7128,6 +7128,7 @@ static ID3D12Device *create_d3d12_device(void) static void test_d3d11_surface_buffer(void) { DWORD max_length, cur_length, length, color; + BYTE *data, *data2, *buffer_start; IMFDXGIBuffer *dxgi_buffer; D3D11_TEXTURE2D_DESC desc; ID3D11Texture2D *texture; @@ -7135,7 +7136,6 @@ static void test_d3d11_surface_buffer(void) IMFMediaBuffer *buffer; ID3D11Device *device; BYTE buff[64 * 64 * 4]; - BYTE *data, *data2; LONG pitch, pitch2; UINT index, size; IUnknown *obj; @@ -7438,7 +7438,54 @@ static void test_d3d11_surface_buffer(void) ID3D11Texture2D_Release(texture); - /* Subresource index 1. */ + memset(&desc, 0, sizeof(desc)); + desc.Width = 64; + desc.Height = 64; + desc.ArraySize = 1; + desc.MipLevels = 1; + desc.Format = DXGI_FORMAT_NV12; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + + hr = ID3D11Device_CreateTexture2D(device, &desc, NULL, &texture); + if (SUCCEEDED(hr)) + { + hr = pMFCreateDXGISurfaceBuffer(&IID_ID3D11Texture2D, (IUnknown *)texture, 0, FALSE, &buffer); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer2, (void **)&_2dbuffer2); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = IMF2DBuffer2_Lock2DSize(_2dbuffer2, MF2DBuffer_LockFlags_Read, &data, &pitch, &buffer_start, &length); + ok(hr == S_OK, "got %#lx.\n", hr); + + ok(pitch >= desc.Width, "got %ld.\n", pitch); + ok(length == pitch * desc.Height * 3 / 2, "got %lu.\n", length); + + hr = IMF2DBuffer2_Unlock2D(_2dbuffer2); + ok(hr == S_OK, "got %#lx.\n", hr); + + IMF2DBuffer2_Release(_2dbuffer2); + IMFMediaBuffer_Release(buffer); + ID3D11Texture2D_Release(texture); + } + else + { + win_skip("Failed to create NV12 texture, hr %#lx, skipping test.\n", hr); + ID3D11Device_Release(device); + return; + } + + /* Subresource index 1. + * When WARP d3d11 device is used, this test leaves the device in a broken state, so it should + * be kept last. */ + memset(&desc, 0, sizeof(desc)); + desc.Width = 64; + desc.Height = 64; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + hr = ID3D11Device_CreateTexture2D(device, &desc, NULL, &texture); ok(hr == S_OK, "Failed to create a texture, hr %#lx.\n", hr); @@ -7463,7 +7510,6 @@ static void test_d3d11_surface_buffer(void) IMF2DBuffer_Release(_2d_buffer); IMFMediaBuffer_Release(buffer); - ID3D11Texture2D_Release(texture); ID3D11Device_Release(device); From 61af157199591c2b0f002675e4e7a6b7a1019071 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Wed, 3 May 2023 16:55:46 +0200 Subject: [PATCH 2260/2777] mfplat/buffer: Use the appropriate image copy function for NV11. (cherry picked from commit 6d1fc9096d26e98e946013efa8cc9f29a2b8909d) CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 24 +++++++++++++++++------- dlls/mfplat/tests/mfplat.c | 2 ++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index 1b9ba24a408..493451a7d5b 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -1336,13 +1336,23 @@ static HRESULT create_1d_buffer(DWORD max_length, DWORD alignment, IMFMediaBuffe static p_copy_image_func get_2d_buffer_copy_func(DWORD fourcc) { - if (fourcc == MAKEFOURCC('N','V','1','2')) - return copy_image_nv12; - if (fourcc == MAKEFOURCC('I','M','C','1') || fourcc == MAKEFOURCC('I','M','C','3')) - return copy_image_imc1; - if (fourcc == MAKEFOURCC('I','M','C','2') || fourcc == MAKEFOURCC('I','M','C','4')) - return copy_image_imc2; - return NULL; + switch (fourcc) + { + case MAKEFOURCC('I','M','C','1'): + case MAKEFOURCC('I','M','C','3'): + return copy_image_imc1; + + case MAKEFOURCC('I','M','C','2'): + case MAKEFOURCC('I','M','C','4'): + case MAKEFOURCC('N','V','1','1'): + return copy_image_imc2; + + case MAKEFOURCC('N','V','1','2'): + return copy_image_nv12; + + default: + return NULL; + } } static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, BOOL bottom_up, IMFMediaBuffer **buffer) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 1307b690f4a..d4d6eaf984f 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -6088,6 +6088,7 @@ static void test_MFCreate2DMediaBuffer(void) case MAKEFOURCC('I','M','C','2'): case MAKEFOURCC('I','M','C','4'): + case MAKEFOURCC('N','V','1','1'): ok(stride * 3 / 2 * ptr->height <= length2, "Insufficient buffer space: expected at least %lu bytes, got only %lu\n", stride * 3 / 2 * ptr->height, length2); for (j = 0; j < ptr->height; j++) @@ -6138,6 +6139,7 @@ static void test_MFCreate2DMediaBuffer(void) case MAKEFOURCC('I','M','C','2'): case MAKEFOURCC('I','M','C','4'): + case MAKEFOURCC('N','V','1','1'): for (j = 0; j < ptr->height; j++) for (k = 0; k < stride / 2; k++) ok(data[j * (pitch / 2) + k] == (((j + ptr->height) % 16) << 4) + (k % 16), From 1de11aa500c815bd7ae82dd46bbf5ec553e78f3c Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Tue, 14 Jun 2022 12:39:42 +0200 Subject: [PATCH 2261/2777] mfplat/buffer: Support YV12, I420 and IYUV image formats. (cherry picked from commit 480554602458a5be721f7e650f64ec15c1e45ade) CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 13 +++++++++--- dlls/mfplat/tests/mfplat.c | 42 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index 493451a7d5b..f090dd13417 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -1345,6 +1345,9 @@ static p_copy_image_func get_2d_buffer_copy_func(DWORD fourcc) case MAKEFOURCC('I','M','C','2'): case MAKEFOURCC('I','M','C','4'): case MAKEFOURCC('N','V','1','1'): + case MAKEFOURCC('Y','V','1','2'): + case MAKEFOURCC('I','4','2','0'): + case MAKEFOURCC('I','Y','U','V'): return copy_image_imc2; case MAKEFOURCC('N','V','1','2'): @@ -1389,12 +1392,12 @@ static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, BOOL bo case MAKEFOURCC('I','M','C','2'): case MAKEFOURCC('I','M','C','4'): case MAKEFOURCC('N','V','1','1'): - plane_size = stride * 3 / 2 * height; - break; - case MAKEFOURCC('N','V','1','2'): case MAKEFOURCC('Y','V','1','2'): case MAKEFOURCC('I','4','2','0'): case MAKEFOURCC('I','Y','U','V'): + plane_size = stride * 3 / 2 * height; + break; + case MAKEFOURCC('N','V','1','2'): plane_size = stride * height * 3 / 2; break; default: @@ -1412,6 +1415,8 @@ static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, BOOL bo case MAKEFOURCC('I','M','C','4'): case MAKEFOURCC('Y','V','1','2'): case MAKEFOURCC('N','V','1','1'): + case MAKEFOURCC('I','4','2','0'): + case MAKEFOURCC('I','Y','U','V'): row_alignment = MF_128_BYTE_ALIGNMENT; break; default: @@ -1431,6 +1436,8 @@ static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, BOOL bo case MAKEFOURCC('I','M','C','2'): case MAKEFOURCC('I','M','C','4'): case MAKEFOURCC('N','V','1','1'): + case MAKEFOURCC('I','4','2','0'): + case MAKEFOURCC('I','Y','U','V'): max_length = pitch * height * 3 / 2; break; default: diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index d4d6eaf984f..5c50ebe3b17 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -4431,6 +4431,42 @@ image_size_tests[] = { &MFVideoFormat_NV11, 3, 2, 12, 9, 384, 8, 128 }, { &MFVideoFormat_NV11, 4, 2, 12, 0, 384, 12, 128 }, { &MFVideoFormat_NV11, 320, 240, 115200, 0, 138240, 115200, 384 }, + + { &MFVideoFormat_YV12, 1, 1, 3, 1, 192, 1, 128 }, + { &MFVideoFormat_YV12, 1, 2, 6, 3, 384, 2, 128 }, + { &MFVideoFormat_YV12, 1, 3, 9, 4, 576, 3, 128 }, + { &MFVideoFormat_YV12, 2, 1, 3, 0, 192, 3, 128 }, + { &MFVideoFormat_YV12, 2, 2, 6, 6, 384, 6, 128 }, + { &MFVideoFormat_YV12, 2, 4, 12, 0, 768, 12, 128 }, + { &MFVideoFormat_YV12, 3, 2, 12, 9, 384, 8, 128 }, + { &MFVideoFormat_YV12, 3, 5, 30, 22, 960, 20, 128 }, + { &MFVideoFormat_YV12, 4, 2, 12, 0, 384, 12, 128 }, + { &MFVideoFormat_YV12, 4, 3, 18, 0, 576, 18, 128 }, + { &MFVideoFormat_YV12, 320, 240, 115200, 0, 138240, 115200, 384 }, + + { &MFVideoFormat_I420, 1, 1, 3, 1, 192, 1, 128 }, + { &MFVideoFormat_I420, 1, 2, 6, 3, 384, 2, 128 }, + { &MFVideoFormat_I420, 1, 3, 9, 4, 576, 3, 128 }, + { &MFVideoFormat_I420, 2, 1, 3, 0, 192, 3, 128 }, + { &MFVideoFormat_I420, 2, 2, 6, 6, 384, 6, 128 }, + { &MFVideoFormat_I420, 2, 4, 12, 0, 768, 12, 128 }, + { &MFVideoFormat_I420, 3, 2, 12, 9, 384, 8, 128 }, + { &MFVideoFormat_I420, 3, 5, 30, 22, 960, 20, 128 }, + { &MFVideoFormat_I420, 4, 2, 12, 0, 384, 12, 128 }, + { &MFVideoFormat_I420, 4, 3, 18, 0, 576, 18, 128 }, + { &MFVideoFormat_I420, 320, 240, 115200, 0, 138240, 115200, 384 }, + + { &MFVideoFormat_IYUV, 1, 1, 3, 1, 192, 1, 128 }, + { &MFVideoFormat_IYUV, 1, 2, 6, 3, 384, 2, 128 }, + { &MFVideoFormat_IYUV, 1, 3, 9, 4, 576, 3, 128 }, + { &MFVideoFormat_IYUV, 2, 1, 3, 0, 192, 3, 128 }, + { &MFVideoFormat_IYUV, 2, 2, 6, 6, 384, 6, 128 }, + { &MFVideoFormat_IYUV, 2, 4, 12, 0, 768, 12, 128 }, + { &MFVideoFormat_IYUV, 3, 2, 12, 9, 384, 8, 128 }, + { &MFVideoFormat_IYUV, 3, 5, 30, 22, 960, 20, 128 }, + { &MFVideoFormat_IYUV, 4, 2, 12, 0, 384, 12, 128 }, + { &MFVideoFormat_IYUV, 4, 3, 18, 0, 576, 18, 128 }, + { &MFVideoFormat_IYUV, 320, 240, 115200, 0, 138240, 115200, 384 }, }; static void test_MFCalculateImageSize(void) @@ -6089,6 +6125,9 @@ static void test_MFCreate2DMediaBuffer(void) case MAKEFOURCC('I','M','C','2'): case MAKEFOURCC('I','M','C','4'): case MAKEFOURCC('N','V','1','1'): + case MAKEFOURCC('Y','V','1','2'): + case MAKEFOURCC('I','4','2','0'): + case MAKEFOURCC('I','Y','U','V'): ok(stride * 3 / 2 * ptr->height <= length2, "Insufficient buffer space: expected at least %lu bytes, got only %lu\n", stride * 3 / 2 * ptr->height, length2); for (j = 0; j < ptr->height; j++) @@ -6140,6 +6179,9 @@ static void test_MFCreate2DMediaBuffer(void) case MAKEFOURCC('I','M','C','2'): case MAKEFOURCC('I','M','C','4'): case MAKEFOURCC('N','V','1','1'): + case MAKEFOURCC('Y','V','1','2'): + case MAKEFOURCC('I','4','2','0'): + case MAKEFOURCC('I','Y','U','V'): for (j = 0; j < ptr->height; j++) for (k = 0; k < stride / 2; k++) ok(data[j * (pitch / 2) + k] == (((j + ptr->height) % 16) << 4) + (k % 16), From ad6f164495e7707cf773aca51d06b266bb171c04 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 11 Jul 2022 12:54:25 +0200 Subject: [PATCH 2262/2777] mfplat/buffer: Implement IMF2DBuffer::ContiguousCopyFrom(). This is a generic implementation, which is probably fine for buffers backed by system memory. The implementation for buffers backed by GPU memory can probably be optimized. (cherry picked from commit da1885ce230ed7097b7513e7cb8abc7b7158e41e) CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 23 +++++++++++- dlls/mfplat/tests/mfplat.c | 77 +++++++++++++++++++++++++++++++++++--- 2 files changed, 92 insertions(+), 8 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index f090dd13417..63647c33ece 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -608,9 +608,28 @@ static HRESULT WINAPI memory_2d_buffer_ContiguousCopyTo(IMF2DBuffer2 *iface, BYT static HRESULT WINAPI memory_2d_buffer_ContiguousCopyFrom(IMF2DBuffer2 *iface, const BYTE *src_buffer, DWORD src_length) { - FIXME("%p, %p, %lu.\n", iface, src_buffer, src_length); + struct buffer *buffer = impl_from_IMF2DBuffer2(iface); + BYTE *dst_scanline0, *dst_buffer_start; + DWORD dst_length; + LONG dst_pitch; + HRESULT hr; - return E_NOTIMPL; + TRACE("%p, %p, %lu.\n", iface, src_buffer, src_length); + + if (src_length < buffer->_2d.plane_size) + return E_INVALIDARG; + + hr = IMF2DBuffer2_Lock2DSize(iface, MF2DBuffer_LockFlags_Write, &dst_scanline0, &dst_pitch, &dst_buffer_start, &dst_length); + + if (SUCCEEDED(hr)) + { + copy_image(buffer, dst_scanline0, dst_pitch, src_buffer, buffer->_2d.width, buffer->_2d.width, buffer->_2d.height); + + if (FAILED(IMF2DBuffer2_Unlock2D(iface))) + WARN("Couldn't unlock destination buffer %p, hr %#lx.\n", iface, hr); + } + + return hr; } static HRESULT WINAPI memory_2d_buffer_Lock2DSize(IMF2DBuffer2 *iface, MF2DBuffer_LockFlags flags, BYTE **scanline0, diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 5c50ebe3b17..a9ae6c18218 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -6074,29 +6074,94 @@ static void test_MFCreate2DMediaBuffer(void) if (is_MEDIASUBTYPE_RGB(ptr->subtype)) continue; + winetest_push_context("%u, %u x %u, format %s", i, ptr->width, ptr->height, wine_dbgstr_guid(ptr->subtype)); + hr = pMFCreate2DMediaBuffer(ptr->width, ptr->height, ptr->subtype->Data1, FALSE, &buffer); ok(hr == S_OK, "Failed to create a buffer, hr %#lx.\n", hr); hr = IMFMediaBuffer_GetMaxLength(buffer, &length); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(length == ptr->max_length, "%u: unexpected maximum length %lu for %u x %u, format %s.\n", - i, length, ptr->width, ptr->height, wine_dbgstr_guid(ptr->subtype)); + ok(length == ptr->max_length, "Unexpected maximum length %lu.\n", length); hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer, (void **)&_2dbuffer); ok(hr == S_OK, "Failed to get interface, hr %#lx.\n", hr); + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer2, (void **)&_2dbuffer2); + ok(hr == S_OK, "Failed to get interface, hr %#lx.\n", hr); + hr = IMF2DBuffer_GetContiguousLength(_2dbuffer, &length); ok(hr == S_OK, "Failed to get length, hr %#lx.\n", hr); - todo_wine_if(IsEqualGUID(ptr->subtype, &MFVideoFormat_RGB24) && ptr->width % 4 == 0) - ok(length == ptr->contiguous_length, "%d: unexpected contiguous length %lu for %u x %u, format %s.\n", - i, length, ptr->width, ptr->height, wine_dbgstr_guid(ptr->subtype)); + ok(length == ptr->contiguous_length, "Unexpected contiguous length %lu.\n", length); + + data2 = malloc(ptr->contiguous_length + 16); + ok(!!data2, "Failed to allocate buffer.\n"); + + for (j = 0; j < ptr->contiguous_length + 16; j++) + data2[j] = j & 0x7f; + + hr = IMF2DBuffer2_ContiguousCopyFrom(_2dbuffer2, data2, ptr->contiguous_length - 1); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = IMFMediaBuffer_Lock(buffer, &data, &length2, NULL); + ok(hr == S_OK, "Failed to lock buffer, hr %#lx.\n", hr); + ok(length2 == ptr->contiguous_length, "Unexpected linear buffer length %lu.\n", length2); + + memset(data, 0xff, length2); + + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "Failed to unlock buffer, hr %#lx.\n", hr); + + hr = IMF2DBuffer2_ContiguousCopyFrom(_2dbuffer2, data2, ptr->contiguous_length + 16); + ok(hr == S_OK, "Failed to copy from contiguous buffer, hr %#lx.\n", hr); + + hr = IMFMediaBuffer_Lock(buffer, &data, &length2, NULL); + ok(hr == S_OK, "Failed to lock buffer, hr %#lx.\n", hr); + ok(length2 == ptr->contiguous_length, "%d: unexpected linear buffer length %lu for %u x %u, format %s.\n", + i, length2, ptr->width, ptr->height, wine_dbgstr_guid(ptr->subtype)); + + for (j = 0; j < ptr->contiguous_length; j++) + { + if (IsEqualGUID(ptr->subtype, &MFVideoFormat_IMC1) || IsEqualGUID(ptr->subtype, &MFVideoFormat_IMC3)) + { + if (j < ptr->height * ptr->pitch && j % ptr->pitch >= ptr->width) + continue; + if (j >= ptr->height * ptr->pitch && j % ptr->pitch >= ptr->width / 2) + continue; + } + if (data[j] != (j & 0x7f)) + break; + } + ok(j == ptr->contiguous_length, "Unexpected byte %02x instead of %02x at position %u.\n", data[j], j & 0x7f, j); + + memset(data, 0xff, length2); + + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "Failed to unlock buffer, hr %#lx.\n", hr); + + hr = IMF2DBuffer2_ContiguousCopyFrom(_2dbuffer2, data2, ptr->contiguous_length); + ok(hr == S_OK, "Failed to copy from contiguous buffer, hr %#lx.\n", hr); + + free(data2); hr = IMFMediaBuffer_Lock(buffer, &data, &length2, NULL); ok(hr == S_OK, "Failed to lock buffer, hr %#lx.\n", hr); - todo_wine_if(IsEqualGUID(ptr->subtype, &MFVideoFormat_RGB24) && ptr->width % 4 == 0) ok(length2 == ptr->contiguous_length, "%d: unexpected linear buffer length %lu for %u x %u, format %s.\n", i, length2, ptr->width, ptr->height, wine_dbgstr_guid(ptr->subtype)); + for (j = 0; j < ptr->contiguous_length; j++) + { + if (IsEqualGUID(ptr->subtype, &MFVideoFormat_IMC1) || IsEqualGUID(ptr->subtype, &MFVideoFormat_IMC3)) + { + if (j < ptr->height * ptr->pitch && j % ptr->pitch >= ptr->width) + continue; + if (j >= ptr->height * ptr->pitch && j % ptr->pitch >= ptr->width / 2) + continue; + } + if (data[j] != (j & 0x7f)) + break; + } + ok(j == ptr->contiguous_length, "Unexpected byte %02x instead of %02x at position %u.\n", data[j], j & 0x7f, j); + hr = pMFGetStrideForBitmapInfoHeader(ptr->subtype->Data1, ptr->width, &stride); ok(hr == S_OK, "Failed to get stride, hr %#lx.\n", hr); stride = abs(stride); From e09f550ed95d63753d172501327c02e38c26f586 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Mon, 11 Jul 2022 13:17:30 +0200 Subject: [PATCH 2263/2777] mfplat/buffer: Implement IMF2DBuffer::ContiguousCopyTo(). (cherry picked from commit 885d8dfab221e1b1a9deeb09c61b69e125380984) CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 23 +++++++++++++++-- dlls/mfplat/tests/mfplat.c | 51 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index 63647c33ece..cb1b3176a08 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -601,9 +601,28 @@ static HRESULT WINAPI memory_2d_buffer_GetContiguousLength(IMF2DBuffer2 *iface, static HRESULT WINAPI memory_2d_buffer_ContiguousCopyTo(IMF2DBuffer2 *iface, BYTE *dest_buffer, DWORD dest_length) { - FIXME("%p, %p, %lu.\n", iface, dest_buffer, dest_length); + struct buffer *buffer = impl_from_IMF2DBuffer2(iface); + BYTE *src_scanline0, *src_buffer_start; + DWORD src_length; + LONG src_pitch; + HRESULT hr; - return E_NOTIMPL; + TRACE("%p, %p, %lu.\n", iface, dest_buffer, dest_length); + + if (dest_length < buffer->_2d.plane_size) + return E_INVALIDARG; + + hr = IMF2DBuffer2_Lock2DSize(iface, MF2DBuffer_LockFlags_Read, &src_scanline0, &src_pitch, &src_buffer_start, &src_length); + + if (SUCCEEDED(hr)) + { + copy_image(buffer, dest_buffer, buffer->_2d.width, src_scanline0, src_pitch, buffer->_2d.width, buffer->_2d.height); + + if (FAILED(IMF2DBuffer2_Unlock2D(iface))) + WARN("Couldn't unlock source buffer %p, hr %#lx.\n", iface, hr); + } + + return S_OK; } static HRESULT WINAPI memory_2d_buffer_ContiguousCopyFrom(IMF2DBuffer2 *iface, const BYTE *src_buffer, DWORD src_length) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index a9ae6c18218..5309016152d 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -6162,6 +6162,57 @@ static void test_MFCreate2DMediaBuffer(void) } ok(j == ptr->contiguous_length, "Unexpected byte %02x instead of %02x at position %u.\n", data[j], j & 0x7f, j); + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "Failed to unlock buffer, hr %#lx.\n", hr); + + hr = IMF2DBuffer2_ContiguousCopyTo(_2dbuffer2, data2, ptr->contiguous_length - 1); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + memset(data2, 0xff, ptr->contiguous_length + 16); + + hr = IMF2DBuffer2_ContiguousCopyTo(_2dbuffer2, data2, ptr->contiguous_length + 16); + ok(hr == S_OK, "Failed to copy to contiguous buffer, hr %#lx.\n", hr); + + for (j = 0; j < ptr->contiguous_length; j++) + { + if (IsEqualGUID(ptr->subtype, &MFVideoFormat_IMC1) || IsEqualGUID(ptr->subtype, &MFVideoFormat_IMC3)) + { + if (j < ptr->height * ptr->pitch && j % ptr->pitch >= ptr->width) + continue; + if (j >= ptr->height * ptr->pitch && j % ptr->pitch >= ptr->width / 2) + continue; + } + if (data2[j] != (j & 0x7f)) + break; + } + ok(j == ptr->contiguous_length, "Unexpected byte %02x instead of %02x at position %u.\n", data2[j], j & 0x7f, j); + + memset(data2, 0xff, ptr->contiguous_length + 16); + + hr = IMF2DBuffer2_ContiguousCopyTo(_2dbuffer2, data2, ptr->contiguous_length); + ok(hr == S_OK, "Failed to copy to contiguous buffer, hr %#lx.\n", hr); + + for (j = 0; j < ptr->contiguous_length; j++) + { + if (IsEqualGUID(ptr->subtype, &MFVideoFormat_IMC1) || IsEqualGUID(ptr->subtype, &MFVideoFormat_IMC3)) + { + if (j < ptr->height * ptr->pitch && j % ptr->pitch >= ptr->width) + continue; + if (j >= ptr->height * ptr->pitch && j % ptr->pitch >= ptr->width / 2) + continue; + } + if (data2[j] != (j & 0x7f)) + break; + } + ok(j == ptr->contiguous_length, "Unexpected byte %02x instead of %02x at position %u.\n", data2[j], j & 0x7f, j); + + free(data2); + + hr = IMFMediaBuffer_Lock(buffer, &data, &length2, NULL); + ok(hr == S_OK, "Failed to lock buffer, hr %#lx.\n", hr); + ok(length2 == ptr->contiguous_length, "%d: unexpected linear buffer length %lu for %u x %u, format %s.\n", + i, length2, ptr->width, ptr->height, wine_dbgstr_guid(ptr->subtype)); + hr = pMFGetStrideForBitmapInfoHeader(ptr->subtype->Data1, ptr->width, &stride); ok(hr == S_OK, "Failed to get stride, hr %#lx.\n", hr); stride = abs(stride); From 4332fbc546f3d80256656e07f3770149a9f43580 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 9 May 2023 19:22:04 -0600 Subject: [PATCH 2264/2777] mfplat/buffer: Use absolute pitch in memory_1d_2d_buffer_[Un]Lock(). CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index cb1b3176a08..52d05f4ef80 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -313,8 +313,14 @@ static HRESULT WINAPI memory_1d_2d_buffer_Lock(IMFMediaBuffer *iface, BYTE **dat hr = E_OUTOFMEMORY; if (SUCCEEDED(hr)) - copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, buffer->data, buffer->_2d.pitch, + { + int pitch = buffer->_2d.pitch; + + if (pitch < 0) + pitch = -pitch; + copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, buffer->data, pitch, buffer->_2d.width, buffer->_2d.height); + } } if (SUCCEEDED(hr)) @@ -342,7 +348,11 @@ static HRESULT WINAPI memory_1d_2d_buffer_Unlock(IMFMediaBuffer *iface) if (buffer->_2d.linear_buffer && !--buffer->_2d.locks) { - copy_image(buffer, buffer->data, buffer->_2d.pitch, buffer->_2d.linear_buffer, buffer->_2d.width, + int pitch = buffer->_2d.pitch; + + if (pitch < 0) + pitch = -pitch; + copy_image(buffer, buffer->data, pitch, buffer->_2d.linear_buffer, buffer->_2d.width, buffer->_2d.width, buffer->_2d.height); free(buffer->_2d.linear_buffer); From db8bf7bb3820b7151e307fd637f9961bd998db98 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 9 May 2023 13:28:48 -0600 Subject: [PATCH 2265/2777] mfplat/tests: Add more tests for copying 2d buffers. CW-Bug-Id: #22084 --- dlls/mfplat/tests/mfplat.c | 187 +++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 5309016152d..11a8620b0ee 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -8944,6 +8944,192 @@ static void test_MFInitMediaTypeFromAMMediaType(void) IMFMediaType_Release(media_type); } +#define check_reset_data(a, b, c, d, e, f) check_reset_data_(__LINE__, a, b, c, d, e, f) +static void check_reset_data_(unsigned int line, IMF2DBuffer2 *buffer2d, const BYTE *data, BOOL bottom_up, + DWORD width, DWORD height, BOOL todo) +{ + BYTE *scanline0, *buffer_start; + DWORD length, max_length; + IMFMediaBuffer *buffer; + LONG pitch; + BYTE *lock; + HRESULT hr; + int i; + + hr = IMF2DBuffer2_QueryInterface(buffer2d, &IID_IMFMediaBuffer, (void **)&buffer); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + hr = IMF2DBuffer2_Lock2DSize(buffer2d, MF2DBuffer_LockFlags_Read, &scanline0, &pitch, &buffer_start, &length); + ok(hr == S_OK, "got hr %#lx.\n", hr); + if (bottom_up) + { + ok(pitch < 0, "got pitch %ld.\n", pitch); + ok(buffer_start == scanline0 + pitch * (LONG)(height - 1), "buffer start mismatch.\n"); + } + else + { + ok(pitch > 0, "got pitch %ld.\n", pitch); + ok(buffer_start == scanline0, "buffer start mismatch.\n"); + } + for (i = 0; i < height; ++i) + todo_wine_if(bottom_up && todo) ok_(__FILE__,line)(!memcmp(buffer_start + abs(pitch) * i, data + width * i * 4, width * 4), + "2D Data mismatch, scaline %d.\n", i); + hr = IMF2DBuffer2_Unlock2D(buffer2d); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + hr = IMFMediaBuffer_Lock(buffer, &lock, &max_length, &length); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ok_(__FILE__,line)(max_length == width * height * 4, "got max_length %lu.\n", max_length); + ok_(__FILE__,line)(length == width * height * 4, "got length %lu.\n", length); + todo_wine_if(bottom_up && todo) ok_(__FILE__,line)(!memcmp(lock, data, length), "contiguous data mismatch.\n"); + memset(lock, 0xcc, length); + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + IMFMediaBuffer_Release(buffer); +} + +static void test_2dbuffer_copy_(IMFMediaBuffer *buffer, BOOL bottom_up, DWORD width, DWORD height) +{ + static const unsigned int test_data[] = + { + 0x01010101, 0x01010101, + 0x02020202, 0x02020202, + }; + + BYTE data[sizeof(test_data)]; + IMFMediaBuffer *src_buffer; + DWORD length, max_length; + IMF2DBuffer2 *buffer2d; + IMFSample *sample; + BYTE *lock; + HRESULT hr; + ULONG ref; + + hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer2, (void **)&buffer2d); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + hr = MFCreateSample(&sample); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = MFCreateMemoryBuffer(sizeof(test_data) * 2, &src_buffer); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFSample_AddBuffer(sample, src_buffer); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + hr = IMFMediaBuffer_Lock(src_buffer, &lock, &max_length, &length); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ok(max_length == sizeof(test_data) * 2, "got %lu.\n", max_length); + memcpy(lock, test_data, sizeof(test_data)); + hr = IMFMediaBuffer_Unlock(src_buffer); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + hr = IMFMediaBuffer_Lock(buffer, &lock, &max_length, &length); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ok(max_length == 16, "got %lu.\n", max_length); + ok(length == 16, "got %lu.\n", length); + memset(lock, 0xcc, length); + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + hr = IMFMediaBuffer_SetCurrentLength(src_buffer, 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFSample_CopyToBuffer(sample, buffer); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + memset(data, 0xcc, sizeof(data)); + data[0] = ((BYTE *)test_data)[0]; + check_reset_data(buffer2d, data, bottom_up, width, height, FALSE); + + hr = IMF2DBuffer2_ContiguousCopyFrom(buffer2d, (BYTE *)test_data, sizeof(test_data)); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMF2DBuffer2_ContiguousCopyTo(buffer2d, data, sizeof(data)); + ok(hr == S_OK, "got hr %#lx.\n", hr); + ok(!memcmp(data, test_data, sizeof(data)), "data mismatch.\n"); + + check_reset_data(buffer2d, (const BYTE *)test_data, bottom_up, width, height, TRUE); + + hr = IMFMediaBuffer_SetCurrentLength(src_buffer, sizeof(test_data) + 1); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFSample_CopyToBuffer(sample, buffer); + ok(hr == MF_E_BUFFERTOOSMALL, "got hr %#lx.\n", hr); + + hr = IMFMediaBuffer_SetCurrentLength(src_buffer, sizeof(test_data)); + ok(hr == S_OK, "got hr %#lx.\n", hr); + hr = IMFSample_CopyToBuffer(sample, buffer); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + check_reset_data(buffer2d, (const BYTE *)test_data, bottom_up, width, height, FALSE); + + IMF2DBuffer2_Release(buffer2d); + ref = IMFSample_Release(sample); + ok(!ref, "got %lu.\n", ref); + ref = IMFMediaBuffer_Release(src_buffer); + ok(!ref, "got %lu.\n", ref); +} + +static void test_2dbuffer_copy(void) +{ + D3D11_TEXTURE2D_DESC desc; + ID3D11Texture2D *texture; + IMFMediaBuffer *buffer; + ID3D11Device *device; + HRESULT hr; + ULONG ref; + + if (!pMFCreate2DMediaBuffer) + { + win_skip("MFCreate2DMediaBuffer() is not available.\n"); + return; + } + + winetest_push_context("top down"); + hr = pMFCreate2DMediaBuffer(2, 2, D3DFMT_A8R8G8B8, FALSE, &buffer); + ok(hr == S_OK, "got hr %#lx.\n", hr); + test_2dbuffer_copy_(buffer, FALSE, 2, 2); + ref = IMFMediaBuffer_Release(buffer); + ok(!ref, "got %lu.\n", ref); + winetest_pop_context(); + + winetest_push_context("bottom up"); + hr = pMFCreate2DMediaBuffer(2, 2, D3DFMT_A8R8G8B8, TRUE, &buffer); + ok(hr == S_OK, "got hr %#lx.\n", hr); + test_2dbuffer_copy_(buffer, TRUE, 2, 2); + ref = IMFMediaBuffer_Release(buffer); + ok(!ref, "got %lu.\n", ref); + winetest_pop_context(); + + if (!pMFCreateDXGISurfaceBuffer) + { + win_skip("MFCreateDXGISurfaceBuffer() is not available.\n"); + return; + } + + if (!(device = create_d3d11_device())) + { + skip("Failed to create a D3D11 device, skipping tests.\n"); + return; + } + + memset(&desc, 0, sizeof(desc)); + desc.Width = 2; + desc.Height = 2; + desc.ArraySize = 1; + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + hr = ID3D11Device_CreateTexture2D(device, &desc, NULL, &texture); + ok(hr == S_OK, "Failed to create a texture, hr %#lx.\n", hr); + + hr = pMFCreateDXGISurfaceBuffer(&IID_ID3D11Texture2D, (IUnknown *)texture, 0, FALSE, &buffer); + ok(hr == S_OK, "Failed to create a buffer, hr %#lx.\n", hr); + test_2dbuffer_copy_(buffer, FALSE, 2, 2); + + ID3D11Texture2D_Release(texture); + ref = IMFMediaBuffer_Release(buffer); + ok(!ref, "got %lu.\n", ref); + ID3D11Device_Release(device); +} + START_TEST(mfplat) { char **argv; @@ -9027,6 +9213,7 @@ START_TEST(mfplat) test_MFCreateVideoMediaTypeFromVideoInfoHeader(); test_MFInitMediaTypeFromVideoInfoHeader(); test_MFInitMediaTypeFromAMMediaType(); + test_2dbuffer_copy(); CoUninitialize(); } From d595f45e5865e4bf4da6773375716803daadcc34 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 9 May 2023 19:24:23 -0600 Subject: [PATCH 2266/2777] mfplat/buffer: Do not flip in memory_2d_buffer_ContiguousCopy{From|To}(). CW-Bug-Id: #22084 --- dlls/mfplat/buffer.c | 10 ++++++++-- dlls/mfplat/tests/mfplat.c | 14 +++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index 52d05f4ef80..3850efa594c 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -626,7 +626,10 @@ static HRESULT WINAPI memory_2d_buffer_ContiguousCopyTo(IMF2DBuffer2 *iface, BYT if (SUCCEEDED(hr)) { - copy_image(buffer, dest_buffer, buffer->_2d.width, src_scanline0, src_pitch, buffer->_2d.width, buffer->_2d.height); + if (src_pitch < 0) + src_pitch = -src_pitch; + copy_image(buffer, dest_buffer, buffer->_2d.width, src_buffer_start, src_pitch, + buffer->_2d.width, buffer->_2d.height); if (FAILED(IMF2DBuffer2_Unlock2D(iface))) WARN("Couldn't unlock source buffer %p, hr %#lx.\n", iface, hr); @@ -652,7 +655,10 @@ static HRESULT WINAPI memory_2d_buffer_ContiguousCopyFrom(IMF2DBuffer2 *iface, c if (SUCCEEDED(hr)) { - copy_image(buffer, dst_scanline0, dst_pitch, src_buffer, buffer->_2d.width, buffer->_2d.width, buffer->_2d.height); + if (dst_pitch < 0) + dst_pitch = -dst_pitch; + copy_image(buffer, dst_buffer_start, dst_pitch, src_buffer, buffer->_2d.width, + buffer->_2d.width, buffer->_2d.height); if (FAILED(IMF2DBuffer2_Unlock2D(iface))) WARN("Couldn't unlock destination buffer %p, hr %#lx.\n", iface, hr); diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 11a8620b0ee..7264db7f79b 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -8944,9 +8944,9 @@ static void test_MFInitMediaTypeFromAMMediaType(void) IMFMediaType_Release(media_type); } -#define check_reset_data(a, b, c, d, e, f) check_reset_data_(__LINE__, a, b, c, d, e, f) +#define check_reset_data(a, b, c, d, e) check_reset_data_(__LINE__, a, b, c, d, e) static void check_reset_data_(unsigned int line, IMF2DBuffer2 *buffer2d, const BYTE *data, BOOL bottom_up, - DWORD width, DWORD height, BOOL todo) + DWORD width, DWORD height) { BYTE *scanline0, *buffer_start; DWORD length, max_length; @@ -8972,7 +8972,7 @@ static void check_reset_data_(unsigned int line, IMF2DBuffer2 *buffer2d, const B ok(buffer_start == scanline0, "buffer start mismatch.\n"); } for (i = 0; i < height; ++i) - todo_wine_if(bottom_up && todo) ok_(__FILE__,line)(!memcmp(buffer_start + abs(pitch) * i, data + width * i * 4, width * 4), + ok_(__FILE__,line)(!memcmp(buffer_start + abs(pitch) * i, data + width * i * 4, width * 4), "2D Data mismatch, scaline %d.\n", i); hr = IMF2DBuffer2_Unlock2D(buffer2d); ok(hr == S_OK, "got hr %#lx.\n", hr); @@ -8981,7 +8981,7 @@ static void check_reset_data_(unsigned int line, IMF2DBuffer2 *buffer2d, const B ok(hr == S_OK, "got hr %#lx.\n", hr); ok_(__FILE__,line)(max_length == width * height * 4, "got max_length %lu.\n", max_length); ok_(__FILE__,line)(length == width * height * 4, "got length %lu.\n", length); - todo_wine_if(bottom_up && todo) ok_(__FILE__,line)(!memcmp(lock, data, length), "contiguous data mismatch.\n"); + ok_(__FILE__,line)(!memcmp(lock, data, length), "contiguous data mismatch.\n"); memset(lock, 0xcc, length); hr = IMFMediaBuffer_Unlock(buffer); ok(hr == S_OK, "got hr %#lx.\n", hr); @@ -9038,7 +9038,7 @@ static void test_2dbuffer_copy_(IMFMediaBuffer *buffer, BOOL bottom_up, DWORD wi memset(data, 0xcc, sizeof(data)); data[0] = ((BYTE *)test_data)[0]; - check_reset_data(buffer2d, data, bottom_up, width, height, FALSE); + check_reset_data(buffer2d, data, bottom_up, width, height); hr = IMF2DBuffer2_ContiguousCopyFrom(buffer2d, (BYTE *)test_data, sizeof(test_data)); ok(hr == S_OK, "got hr %#lx.\n", hr); @@ -9046,7 +9046,7 @@ static void test_2dbuffer_copy_(IMFMediaBuffer *buffer, BOOL bottom_up, DWORD wi ok(hr == S_OK, "got hr %#lx.\n", hr); ok(!memcmp(data, test_data, sizeof(data)), "data mismatch.\n"); - check_reset_data(buffer2d, (const BYTE *)test_data, bottom_up, width, height, TRUE); + check_reset_data(buffer2d, (const BYTE *)test_data, bottom_up, width, height); hr = IMFMediaBuffer_SetCurrentLength(src_buffer, sizeof(test_data) + 1); ok(hr == S_OK, "got hr %#lx.\n", hr); @@ -9058,7 +9058,7 @@ static void test_2dbuffer_copy_(IMFMediaBuffer *buffer, BOOL bottom_up, DWORD wi hr = IMFSample_CopyToBuffer(sample, buffer); ok(hr == S_OK, "got hr %#lx.\n", hr); - check_reset_data(buffer2d, (const BYTE *)test_data, bottom_up, width, height, FALSE); + check_reset_data(buffer2d, (const BYTE *)test_data, bottom_up, width, height); IMF2DBuffer2_Release(buffer2d); ref = IMFSample_Release(sample); From 02fb0c7cbe73397668c40407c400c2bf41ed858f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 9 May 2023 11:14:32 -0600 Subject: [PATCH 2267/2777] mfplat/sample: Refactor sample_CopyToBuffer(). CW-Bug-Id: #22084 --- dlls/mfplat/sample.c | 52 ++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/dlls/mfplat/sample.c b/dlls/mfplat/sample.c index 6a589e4757b..513b8bb4ca9 100644 --- a/dlls/mfplat/sample.c +++ b/dlls/mfplat/sample.c @@ -875,36 +875,42 @@ static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buff dst_ptr = NULL; dst_length = current_length = 0; locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, ¤t_length)); - if (locked) + if (!locked) + goto done; + + if (dst_length < total_length) { - if (dst_length < total_length) - hr = MF_E_BUFFERTOOSMALL; - else if (dst_ptr) + hr = MF_E_BUFFERTOOSMALL; + goto done; + } + + if (!dst_ptr) + goto done; + + for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i) + { + src_ptr = NULL; + src_max_length = current_length = 0; + + if (FAILED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, ¤t_length))) + continue; + + if (src_ptr) { - for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i) + if (current_length > dst_length) + hr = MF_E_BUFFERTOOSMALL; + else if (current_length) { - src_ptr = NULL; - src_max_length = current_length = 0; - if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, ¤t_length))) - { - if (src_ptr) - { - if (current_length > dst_length) - hr = MF_E_BUFFERTOOSMALL; - else if (current_length) - { - memcpy(dst_ptr, src_ptr, current_length); - dst_length -= current_length; - dst_current_length += current_length; - dst_ptr += current_length; - } - } - IMFMediaBuffer_Unlock(sample->buffers[i]); - } + memcpy(dst_ptr, src_ptr, current_length); + dst_length -= current_length; + dst_current_length += current_length; + dst_ptr += current_length; } } + IMFMediaBuffer_Unlock(sample->buffers[i]); } +done: IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length); if (locked) From f8b15fbc99aed74431a7f1e8810e37390436289f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 9 May 2023 12:24:46 -0600 Subject: [PATCH 2268/2777] mfplat/sample: Optimize copying to 2d buffer. CW-Bug-Id: #22084 --- dlls/mfplat/sample.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/dlls/mfplat/sample.c b/dlls/mfplat/sample.c index 513b8bb4ca9..8e489d22acd 100644 --- a/dlls/mfplat/sample.c +++ b/dlls/mfplat/sample.c @@ -852,8 +852,9 @@ static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buff struct sample *sample = impl_from_IMFSample(iface); DWORD total_length, dst_length, dst_current_length, src_max_length, current_length; BYTE *src_ptr, *dst_ptr; - BOOL locked; - HRESULT hr; + IMF2DBuffer *buffer2d; + BOOL locked = FALSE; + HRESULT hr = E_FAIL; size_t i; TRACE("%p, %p.\n", iface, buffer); @@ -872,6 +873,25 @@ static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buff total_length = sample_get_total_length(sample); dst_current_length = 0; + if (sample->buffer_count == 1 + && SUCCEEDED(IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer, (void **)&buffer2d))) + { + if (SUCCEEDED(IMFMediaBuffer_GetCurrentLength(sample->buffers[0], ¤t_length)) + && SUCCEEDED(IMF2DBuffer_GetContiguousLength(buffer2d, &dst_length)) + && current_length == dst_length + && SUCCEEDED(IMFMediaBuffer_Lock(sample->buffers[0], &src_ptr, &src_max_length, ¤t_length))) + { + hr = IMF2DBuffer_ContiguousCopyFrom(buffer2d, src_ptr, current_length); + IMFMediaBuffer_Unlock(sample->buffers[0]); + } + IMF2DBuffer_Release(buffer2d); + if (SUCCEEDED(hr)) + { + dst_current_length = current_length; + goto done; + } + } + dst_ptr = NULL; dst_length = current_length = 0; locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, ¤t_length)); From 86af89ca3f2e6f578d3991f5ff9f7c762111c778 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 5 Sep 2023 12:28:19 -0600 Subject: [PATCH 2269/2777] Revert "HACK: msmpeg2vdec: Refuse to load DLL for some games." This reverts commit 7267a0e38eee69af7042292bff435b98a8e1898b. CW-Bug-Id: #22084 --- dlls/msmpeg2vdec/Makefile.in | 3 --- dlls/msmpeg2vdec/main.c | 48 ------------------------------------ 2 files changed, 51 deletions(-) delete mode 100644 dlls/msmpeg2vdec/main.c diff --git a/dlls/msmpeg2vdec/Makefile.in b/dlls/msmpeg2vdec/Makefile.in index 609c6a34f9a..d2dbf5adda0 100644 --- a/dlls/msmpeg2vdec/Makefile.in +++ b/dlls/msmpeg2vdec/Makefile.in @@ -1,4 +1 @@ MODULE = msmpeg2vdec.dll - -C_SRCS = \ - main.c diff --git a/dlls/msmpeg2vdec/main.c b/dlls/msmpeg2vdec/main.c deleted file mode 100644 index 348d3d405b4..00000000000 --- a/dlls/msmpeg2vdec/main.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2023 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 - */ - -#include -#include -#include - -#include "windef.h" -#include "winbase.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mfplat); - -BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved ) -{ - TRACE( "instance %p, reason %#lx, reserved %p\n", instance, reason, reserved ); - - switch (reason) - { - case DLL_PROCESS_ATTACH: - { - const char *sgi; - if ((sgi = getenv( "SteamGameId" )) && !strcmp( sgi, "1498570" )) return FALSE; - DisableThreadLibraryCalls( instance ); - break; - } - case DLL_PROCESS_DETACH: - break; - } - - return TRUE; -} From 6171b883ad0b130bdbc50a39884c364e03803a2b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 7 Sep 2023 10:03:00 -0600 Subject: [PATCH 2270/2777] wtsapi32: Improve WTSEnumerateSessionsW() stub. CW-Bug-Id: #22715 --- dlls/wtsapi32/tests/wtsapi.c | 33 +++++++++++++++++++++++++++++++++ dlls/wtsapi32/wtsapi32.c | 27 ++++++++++++++++++++------- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/dlls/wtsapi32/tests/wtsapi.c b/dlls/wtsapi32/tests/wtsapi.c index 2023a21e938..02d6bb61d90 100644 --- a/dlls/wtsapi32/tests/wtsapi.c +++ b/dlls/wtsapi32/tests/wtsapi.c @@ -305,6 +305,38 @@ static void test_WTSQueryUserToken(void) ok(GetLastError()==ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got: %ld\n", GetLastError()); } +static void test_WTSEnumerateSessions(void) +{ + BOOL console_found = FALSE, services_found = FALSE; + WTS_SESSION_INFOW *info; + unsigned int i; + DWORD count; + BOOL bret; + + bret = WTSEnumerateSessionsW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &info, &count); + ok(bret, "got error %lu.\n", GetLastError()); + todo_wine_if(count == 1) ok(count >= 2, "got %lu.\n", count); + + for (i = 0; i < count; ++i) + { + trace("SessionId %lu, name %s, State %d.\n", info[i].SessionId, debugstr_w(info[i].pWinStationName), info[i].State); + if (!wcscmp(info[i].pWinStationName, L"Console")) + { + console_found = TRUE; + ok(info[i].State == WTSActive, "got State %d.\n", info[i].State); + } + else if (!wcscmp(info[i].pWinStationName, L"Services")) + { + services_found = TRUE; + ok(info[i].State == WTSDisconnected, "got State %d.\n", info[i].State); + } + } + ok(console_found, "Console session not found.\n"); + todo_wine ok(services_found, "Services session not found.\n"); + + WTSFreeMemory(info); +} + START_TEST (wtsapi) { pWTSEnumerateProcessesExW = (void *)GetProcAddress(GetModuleHandleA("wtsapi32"), "WTSEnumerateProcessesExW"); @@ -313,4 +345,5 @@ START_TEST (wtsapi) test_WTSEnumerateProcessesW(); test_WTSQuerySessionInformation(); test_WTSQueryUserToken(); + test_WTSEnumerateSessions(); } diff --git a/dlls/wtsapi32/wtsapi32.c b/dlls/wtsapi32/wtsapi32.c index 7de1b8124ea..0071922d866 100644 --- a/dlls/wtsapi32/wtsapi32.c +++ b/dlls/wtsapi32/wtsapi32.c @@ -309,16 +309,29 @@ BOOL WINAPI WTSEnumerateSessionsA(HANDLE hServer, DWORD Reserved, DWORD Version, /************************************************************ * WTSEnumerateEnumerateSessionsW (WTSAPI32.@) */ -BOOL WINAPI WTSEnumerateSessionsW(HANDLE hServer, DWORD Reserved, DWORD Version, - PWTS_SESSION_INFOW* ppSessionInfo, DWORD* pCount) +BOOL WINAPI WTSEnumerateSessionsW(HANDLE server, DWORD reserved, DWORD version, + PWTS_SESSION_INFOW *session_info, DWORD *count) { - FIXME("Stub %p 0x%08lx 0x%08lx %p %p\n", hServer, Reserved, Version, - ppSessionInfo, pCount); + static const WCHAR session_name[] = L"Console"; - if (!ppSessionInfo || !pCount) return FALSE; + FIXME("%p 0x%08lx 0x%08lx %p %p semi-stub.\n", server, reserved, version, session_info, count); - *pCount = 0; - *ppSessionInfo = NULL; + if (!session_info || !count) return FALSE; + + if (!(*session_info = heap_alloc(sizeof(**session_info) + sizeof(session_name)))) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + if (!ProcessIdToSessionId( GetCurrentProcessId(), &(*session_info)->SessionId)) + { + WTSFreeMemory(*session_info); + return FALSE; + } + *count = 1; + (*session_info)->State = WTSActive; + (*session_info)->pWinStationName = (WCHAR *)((char *)*session_info + sizeof(**session_info)); + memcpy((*session_info)->pWinStationName, session_name, sizeof(session_name)); return TRUE; } From 0f268292b29415cc46dfff9652e729c76bd54f60 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 7 Sep 2023 10:51:07 -0600 Subject: [PATCH 2271/2777] wtsapi32: Implement WTSEnumerateSessionsA() on top of WTSEnumerateSessionsW(). CW-Bug-Id: #22715 --- dlls/wtsapi32/tests/wtsapi.c | 10 ++++++- dlls/wtsapi32/wtsapi32.c | 55 ++++++++++++++++++++++++++++++------ 2 files changed, 55 insertions(+), 10 deletions(-) diff --git a/dlls/wtsapi32/tests/wtsapi.c b/dlls/wtsapi32/tests/wtsapi.c index 02d6bb61d90..abd4825056d 100644 --- a/dlls/wtsapi32/tests/wtsapi.c +++ b/dlls/wtsapi32/tests/wtsapi.c @@ -309,14 +309,19 @@ static void test_WTSEnumerateSessions(void) { BOOL console_found = FALSE, services_found = FALSE; WTS_SESSION_INFOW *info; + WTS_SESSION_INFOA *infoA; + DWORD count, count2; unsigned int i; - DWORD count; BOOL bret; bret = WTSEnumerateSessionsW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &info, &count); ok(bret, "got error %lu.\n", GetLastError()); todo_wine_if(count == 1) ok(count >= 2, "got %lu.\n", count); + bret = WTSEnumerateSessionsA(WTS_CURRENT_SERVER_HANDLE, 0, 1, &infoA, &count2); + ok(bret, "got error %lu.\n", GetLastError()); + ok(count2 == count, "got %lu.\n", count2); + for (i = 0; i < count; ++i) { trace("SessionId %lu, name %s, State %d.\n", info[i].SessionId, debugstr_w(info[i].pWinStationName), info[i].State); @@ -324,17 +329,20 @@ static void test_WTSEnumerateSessions(void) { console_found = TRUE; ok(info[i].State == WTSActive, "got State %d.\n", info[i].State); + ok(!strcmp(infoA[i].pWinStationName, "Console"), "got %s.\n", debugstr_a(infoA[i].pWinStationName)); } else if (!wcscmp(info[i].pWinStationName, L"Services")) { services_found = TRUE; ok(info[i].State == WTSDisconnected, "got State %d.\n", info[i].State); + ok(!strcmp(infoA[i].pWinStationName, "Services"), "got %s.\n", debugstr_a(infoA[i].pWinStationName)); } } ok(console_found, "Console session not found.\n"); todo_wine ok(services_found, "Services session not found.\n"); WTSFreeMemory(info); + WTSFreeMemory(infoA); } START_TEST (wtsapi) diff --git a/dlls/wtsapi32/wtsapi32.c b/dlls/wtsapi32/wtsapi32.c index 0071922d866..6eaea8d3c6f 100644 --- a/dlls/wtsapi32/wtsapi32.c +++ b/dlls/wtsapi32/wtsapi32.c @@ -266,7 +266,6 @@ BOOL WINAPI WTSEnumerateServersW(LPWSTR pDomainName, DWORD Reserved, DWORD Versi return FALSE; } - /************************************************************ * WTSEnumerateEnumerateSessionsExW (WTSAPI32.@) */ @@ -290,19 +289,57 @@ BOOL WINAPI WTSEnumerateSessionsExA(HANDLE server, DWORD *level, DWORD filter, W /************************************************************ * WTSEnumerateEnumerateSessionsA (WTSAPI32.@) */ -BOOL WINAPI WTSEnumerateSessionsA(HANDLE hServer, DWORD Reserved, DWORD Version, - PWTS_SESSION_INFOA* ppSessionInfo, DWORD* pCount) +BOOL WINAPI WTSEnumerateSessionsA(HANDLE server, DWORD reserved, DWORD version, + PWTS_SESSION_INFOA *session_info, DWORD *count) { - static int once; + PWTS_SESSION_INFOW infoW; + DWORD size, offset; + unsigned int i; + int len; - if (!once++) FIXME("Stub %p 0x%08lx 0x%08lx %p %p\n", hServer, Reserved, Version, - ppSessionInfo, pCount); + TRACE("%p 0x%08lx 0x%08lx %p %p.\n", server, reserved, version, session_info, count); - if (!ppSessionInfo || !pCount) return FALSE; + if (!session_info || !count) return FALSE; - *pCount = 0; - *ppSessionInfo = NULL; + if (!WTSEnumerateSessionsW(server, reserved, version, &infoW, count)) return FALSE; + + size = 0; + for (i = 0; i < *count; ++i) + { + if (!(len = WideCharToMultiByte(CP_ACP, 0, infoW[i].pWinStationName, -1, NULL, 0, NULL, NULL))) + { + ERR("WideCharToMultiByte failed.\n"); + WTSFreeMemory(infoW); + return FALSE; + } + size += sizeof(**session_info) + len; + } + + if (!(*session_info = heap_alloc(size))) + { + WTSFreeMemory(infoW); + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + + offset = *count * sizeof(**session_info); + for (i = 0; i < *count; ++i) + { + (*session_info)[i].State = infoW[i].State; + (*session_info)[i].SessionId = infoW[i].SessionId; + (*session_info)[i].pWinStationName = (char *)(*session_info) + offset; + len = WideCharToMultiByte(CP_ACP, 0, infoW[i].pWinStationName, -1, (*session_info)[i].pWinStationName, + size - offset, NULL, NULL); + if (!len) + { + ERR("WideCharToMultiByte failed.\n"); + WTSFreeMemory(*session_info); + WTSFreeMemory(infoW); + } + offset += len; + } + WTSFreeMemory(infoW); return TRUE; } From 9e1bfd2b9eda77032590439cbae5cd01e75361f6 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 7 Sep 2023 11:06:00 -0600 Subject: [PATCH 2272/2777] wtsapi32: Handle WTSConnectState class in WTSQuerySessionInformationW(). CW-Bug-Id: #22715 --- dlls/wtsapi32/tests/wtsapi.c | 15 +++++++++++++++ dlls/wtsapi32/wtsapi32.c | 24 +++++++++++++----------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/dlls/wtsapi32/tests/wtsapi.c b/dlls/wtsapi32/tests/wtsapi.c index abd4825056d..2748f63a132 100644 --- a/dlls/wtsapi32/tests/wtsapi.c +++ b/dlls/wtsapi32/tests/wtsapi.c @@ -191,10 +191,25 @@ static void test_WTSQuerySessionInformation(void) { WCHAR *buf1, usernameW[UNLEN + 1], computernameW[MAX_COMPUTERNAME_LENGTH + 1]; char *buf2, username[UNLEN + 1], computername[MAX_COMPUTERNAME_LENGTH + 1]; + WTS_CONNECTSTATE_CLASS *state; DWORD count, tempsize; USHORT *protocol; BOOL ret; + count = 0; + ret = WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSConnectState, (WCHAR **)&state, &count); + ok(ret, "got error %lu\n", GetLastError()); + ok(count == sizeof(*state), "got %lu\n", count); + ok(*state == WTSActive, "got %d.\n", *state); + WTSFreeMemory(state); + + count = 0; + ret = WTSQuerySessionInformationA(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSConnectState, (char **)&state, &count); + ok(ret, "got error %lu\n", GetLastError()); + ok(count == sizeof(*state), "got %lu\n", count); + ok(*state == WTSActive, "got %d.\n", *state); + WTSFreeMemory(state); + SetLastError(0xdeadbeef); count = 0; ret = WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSUserName, NULL, &count); diff --git a/dlls/wtsapi32/wtsapi32.c b/dlls/wtsapi32/wtsapi32.c index 6eaea8d3c6f..f4072e7090b 100644 --- a/dlls/wtsapi32/wtsapi32.c +++ b/dlls/wtsapi32/wtsapi32.c @@ -468,17 +468,8 @@ BOOL WINAPI WTSQuerySessionInformationA(HANDLE server, DWORD session_id, WTS_INF return FALSE; } - if (class == WTSClientProtocolType) - { - USHORT *protocol; - - if (!(protocol = heap_alloc(sizeof(*protocol)))) return FALSE; - FIXME("returning 0 protocol type\n"); - *protocol = 0; - *buffer = (char *)protocol; - *count = sizeof(*protocol); - return TRUE; - } + if (class == WTSClientProtocolType || class == WTSConnectState) + return WTSQuerySessionInformationW(server, session_id, class, (WCHAR **)buffer, count); if (!WTSQuerySessionInformationW(server, session_id, class, &bufferW, count)) return FALSE; @@ -520,6 +511,17 @@ BOOL WINAPI WTSQuerySessionInformationW(HANDLE server, DWORD session_id, WTS_INF return FALSE; } + if (class == WTSConnectState) + { + WTS_CONNECTSTATE_CLASS *state; + + if (!(state = heap_alloc(sizeof(*state)))) return FALSE; + *state = WTSActive; + *buffer = (WCHAR *)state; + *count = sizeof(*state); + return TRUE; + } + if (class == WTSClientProtocolType) { USHORT *protocol; From a1a1cd10f183e530cb6af537f2bc2f7e8af179cc Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Thu, 7 Sep 2023 20:26:43 +0300 Subject: [PATCH 2273/2777] Revert "nsiproxy.sys: Detect wireless interface type on Linux." This reverts commit e7fdbdab8b25bf8cde5d2ad1738a5ecf45643784. This commit is already included as a cherry-pick. Upon experimental rebase only whitespace removal was left - we can remove that. --- dlls/nsiproxy.sys/ndis.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/nsiproxy.sys/ndis.c b/dlls/nsiproxy.sys/ndis.c index 9c4fe80e865..73c047586a9 100644 --- a/dlls/nsiproxy.sys/ndis.c +++ b/dlls/nsiproxy.sys/ndis.c @@ -200,6 +200,7 @@ static NTSTATUS if_get_physical( const char *name, UINT *type, IF_PHYSICAL_ADDRE } #elif defined (HAVE_SYS_SYSCTL_H) && defined (HAVE_NET_IF_DL_H) + static NTSTATUS if_get_physical( const char *name, UINT *type, IF_PHYSICAL_ADDRESS *phys_addr ) { struct if_msghdr *ifm; From dd8bf9aa59fc5921b0a6d02bdbf30a612a995d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 7 Sep 2023 19:41:46 +0200 Subject: [PATCH 2274/2777] dinput: Assume that clipping the cursor succeeds. Fixes a regression (in Deathloop) where it falls back to SetCursorPos as we now sometimes shrink the clipping rectangle. CW-Bug-Id: #21707 --- dlls/dinput/mouse.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c index ec30c825733..d376546f1a9 100644 --- a/dlls/dinput/mouse.c +++ b/dlls/dinput/mouse.c @@ -306,8 +306,8 @@ static void warp_check( struct mouse *impl, BOOL force ) if (force || (impl->need_warp && (now - impl->last_warped > interval))) { - RECT rect, new_rect; POINT mapped_center; + RECT rect; impl->last_warped = now; impl->need_warp = FALSE; @@ -328,8 +328,7 @@ static void warp_check( struct mouse *impl, BOOL force ) rect.right = min( rect.right, rect.left + GetSystemMetrics( SM_CXVIRTUALSCREEN ) - 2 ); rect.bottom = min( rect.bottom, rect.top + GetSystemMetrics( SM_CYVIRTUALSCREEN ) - 2 ); TRACE("Clipping mouse to %s\n", wine_dbgstr_rect( &rect )); - ClipCursor( &rect ); - impl->clipped = GetClipCursor( &new_rect ) && EqualRect( &rect, &new_rect ); + impl->clipped = ClipCursor( &rect ); } } } From 119b578887847b9147a49d72749c947d68ef4024 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Thu, 7 Sep 2023 14:00:34 +0200 Subject: [PATCH 2275/2777] winegstreamer: Block protonvideoconvert autoplug when not trying for it. Signed-off-by: Derek Lesho --- dlls/winegstreamer/wg_parser.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 959a2141f2c..3e5afe49bf0 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -493,6 +493,11 @@ static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad, } if (!strcmp(name, "QuickTime demuxer")) parser->using_qtdemux = true; + if (!strcmp(name, "Proton video converter") && !parser->use_mediaconv) + { + GST_INFO("Skipping \"Proton video converter\"."); + return GST_AUTOPLUG_SELECT_SKIP; + } return GST_AUTOPLUG_SELECT_TRY; } From a1c074a5eec1e9a005cdfaec915dd860e84c4ab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 8 Sep 2023 14:24:11 +0200 Subject: [PATCH 2276/2777] winex11: Always ignore MotionNotify event after SetCursorPos. Trying to workaround spurious Wayland mouse motion. CW-Bug-Id: #22650 --- dlls/winex11.drv/mouse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 72a5d0173e4..2f208da3645 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -1674,7 +1674,7 @@ BOOL X11DRV_MotionNotify( HWND hwnd, XEvent *xev ) input.u.mi.time = x11drv_time_to_ticks( event->time ); input.u.mi.dwExtraInfo = 0; - if (!hwnd && is_old_motion_event( event->serial )) + if (is_old_motion_event( event->serial )) { TRACE( "pos %d,%d old serial %lu, ignoring\n", event->x, event->y, event->serial ); return FALSE; @@ -1935,7 +1935,7 @@ static BOOL X11DRV_XIDeviceEvent( XIDeviceEvent *event ) TRACE( "evtype %u hwnd %p/%lx pos %f,%f detail %u flags %#x serial %lu\n", event->evtype, hwnd, event->event, event->event_x, event->event_y, event->detail, event->flags, event->serial ); - if (!hwnd && is_old_motion_event( event->serial )) + if (is_old_motion_event( event->serial )) { TRACE( "pos %f,%f old serial %lu, ignoring\n", event->event_x, event->event_y, event->serial ); return FALSE; From be37b0664feefb420ca6dce18dfc1336eebf1f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 8 Sep 2023 19:26:51 +0200 Subject: [PATCH 2277/2777] dinput: Only call SetCursorPos if clipping fails. Fixes mouse sometimes jumping around in Mechwarrior Online on KDE/Wayland. CW-Bug-Id: #22650 --- dlls/dinput/mouse.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c index d376546f1a9..2d4e0a6b42c 100644 --- a/dlls/dinput/mouse.c +++ b/dlls/dinput/mouse.c @@ -313,13 +313,6 @@ static void warp_check( struct mouse *impl, BOOL force ) impl->need_warp = FALSE; if (!GetClientRect( impl->base.win, &rect )) return; MapWindowPoints( impl->base.win, 0, (POINT *)&rect, 2 ); - if (!impl->clipped) - { - mapped_center.x = (rect.left + rect.right) / 2; - mapped_center.y = (rect.top + rect.bottom) / 2; - TRACE( "Warping mouse to x %+ld, y %+ld.\n", mapped_center.x, mapped_center.y ); - SetCursorPos( mapped_center.x, mapped_center.y ); - } if (impl->base.dwCoopLevel & DISCL_EXCLUSIVE) { /* make sure we clip even if the window covers the whole screen */ @@ -330,6 +323,13 @@ static void warp_check( struct mouse *impl, BOOL force ) TRACE("Clipping mouse to %s\n", wine_dbgstr_rect( &rect )); impl->clipped = ClipCursor( &rect ); } + if (!impl->clipped) + { + mapped_center.x = (rect.left + rect.right) / 2; + mapped_center.y = (rect.top + rect.bottom) / 2; + TRACE( "Warping mouse to x %+ld, y %+ld.\n", mapped_center.x, mapped_center.y ); + SetCursorPos( mapped_center.x, mapped_center.y ); + } } } From a16948553d06d9581d2e9553610c891464f1adbe Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 8 Sep 2023 16:28:09 -0600 Subject: [PATCH 2278/2777] winex11.drv: Use offscreen windows instead of pixmaps for layered windows GL drawing. CW-Bug-Id: #22716 --- dlls/winex11.drv/opengl.c | 50 +++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 3cf88a7d4bc..e35748b45e8 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1522,21 +1522,7 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel gl->layered_type = get_gl_layered_type( hwnd ); - if (gl->layered_type) - { - detach_client_window( hwnd, 0 ); - gl->type = DC_GL_PIXMAP_WIN; - gl->pixmap = XCreatePixmap( gdi_display, root_window, width, height, visual->depth ); - if (gl->pixmap) - { - gl->drawable = pglXCreatePixmap( gdi_display, gl->format->fbconfig, gl->pixmap, NULL ); - if (!gl->drawable) XFreePixmap( gdi_display, gl->pixmap ); - gl->pixmap_size.cx = width; - gl->pixmap_size.cy = height; - } - TRACE( "%p created pixmap drawable %lx for layered window, type %u.\n", hwnd, gl->drawable, gl->layered_type ); - } - else if (!drawable_needs_clipping( hwnd, known_child )) /* childless top-level window */ + if (!gl->layered_type && !drawable_needs_clipping( hwnd, known_child )) /* childless top-level window */ { struct x11drv_win_data *data; @@ -1566,6 +1552,7 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel gl->fs_hack = data->fs_hack || fs_hack_get_gamma_ramp( NULL ); if (gl->fs_hack) TRACE( "Window %p has the fullscreen hack enabled\n", hwnd ); release_win_data( data ); + if (gl->layered_type) detach_client_window( hwnd, 0 ); TRACE( "%p created child %lx drawable %lx\n", hwnd, gl->window, gl->drawable ); } #endif @@ -1690,7 +1677,7 @@ void sync_gl_drawable( HWND hwnd, BOOL known_child ) known_child = drawable_needs_clipping( hwnd, known_child ); - if (old->type == DC_GL_PIXMAP_WIN || (known_child && old->type == DC_GL_WINDOW) + if (old->layered_type || (known_child && old->type == DC_GL_WINDOW) || (!known_child && old->type != DC_GL_WINDOW) || old->layered_type != new_layered_type) { @@ -3313,6 +3300,11 @@ static BOOL glxdrv_wglShareLists(struct wgl_context *org, struct wgl_context *de return FALSE; } +static int XGetImage_handler( Display *dpy, XErrorEvent *event, void *arg ) +{ + return event->request_code == X_GetImage && event->error_code == BadMatch; +} + static void update_window_surface(struct gl_drawable *gl, HWND hwnd) { char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; @@ -3326,7 +3318,7 @@ static void update_window_surface(struct gl_drawable *gl, HWND hwnd) TRACE( "gl %p, hwnd %p, gl->layered_type %u.\n", gl, hwnd, gl->layered_type ); - if (gl->layered_type != DC_GL_LAYERED_ATTRIBUTES || !gl->pixmap) return; + if (gl->layered_type != DC_GL_LAYERED_ATTRIBUTES || !gl->window) return; if (!(data = get_win_data( hwnd ))) return; @@ -3347,11 +3339,18 @@ static void update_window_surface(struct gl_drawable *gl, HWND hwnd) rect.right = min( rect.right, abs( bmi->bmiHeader.biWidth )); rect.bottom = min( rect.bottom, abs( bmi->bmiHeader.biHeight )); - width = min( rect.right - rect.left, gl->pixmap_size.cx ); - height = min( rect.bottom - rect.top, gl->pixmap_size.cy ); + width = rect.right - rect.left; + height = rect.bottom - rect.top; - image = XGetImage( gdi_display, gl->pixmap, 0, 0, width, height, + TRACE( "client_rect %s, whole_rect %s bmi %dx%d, rect %s.\n", + wine_dbgstr_rect(&data->client_rect), wine_dbgstr_rect(&data->whole_rect), + (int)bmi->bmiHeader.biWidth, (int)bmi->bmiHeader.biHeight, + wine_dbgstr_rect(&rect) ); + + X11DRV_expect_error( gdi_display, XGetImage_handler, NULL ); + image = XGetImage( gdi_display, gl->window, 0, 0, width, height, AllPlanes, ZPixmap ); + if (X11DRV_check_error()) ERR( "XGetImage error.\n" ); if (!image) { TRACE( "NULL image.\n" ); @@ -3373,7 +3372,6 @@ static void update_window_surface(struct gl_drawable *gl, HWND hwnd) for (y = 0; y < height; ++y) memcpy( dst_bits + (y + rect.top) * pitch + rect.left * stride, src_bits + y * image->bytes_per_line, width * stride ); - add_bounds_rect( surface->funcs->get_bounds( surface ), &rect ); done: @@ -3398,7 +3396,7 @@ static void wglFinish(void) switch (gl->type) { case DC_GL_PIXMAP_WIN: if (!gl->layered_type) escape.drawable = gl->pixmap; break; - case DC_GL_CHILD_WIN: escape.drawable = gl->window; break; + case DC_GL_CHILD_WIN: if (!gl->layered_type) escape.drawable = gl->window; break; default: break; } sync_context(ctx); @@ -3439,7 +3437,7 @@ static void wglFlush(void) switch (gl->type) { case DC_GL_PIXMAP_WIN: if (!gl->layered_type) escape.drawable = gl->pixmap; break; - case DC_GL_CHILD_WIN: escape.drawable = gl->window; break; + case DC_GL_CHILD_WIN: if (!gl->layered_type) escape.drawable = gl->window; break; default: break; } sync_context(ctx); @@ -4893,7 +4891,7 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) case DC_GL_WINDOW: case DC_GL_CHILD_WIN: if (ctx) sync_context( ctx ); - if (gl->type == DC_GL_CHILD_WIN) escape.drawable = gl->window; + if (gl->type == DC_GL_CHILD_WIN && !gl->layered_type) escape.drawable = gl->window; /* fall through */ default: if (gl->fs_hack) @@ -4908,7 +4906,7 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) ctx->fs_hack = FALSE; fs_hack_setup_context( ctx, gl ); } - if (escape.drawable && pglXSwapBuffersMscOML) + if ((escape.drawable || gl->layered_type) && pglXSwapBuffersMscOML) { pglFlush(); target_sbc = pglXSwapBuffersMscOML( gdi_display, gl->drawable, 0, 0, 0 ); @@ -4918,7 +4916,7 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) break; } - if (escape.drawable && pglXWaitForSbcOML) + if ((escape.drawable || gl->layered_type) && pglXWaitForSbcOML) pglXWaitForSbcOML( gdi_display, gl->drawable, target_sbc, &ust, &msc, &sbc ); update_window_surface( gl, hwnd ); From cbe3bb57855747dcd546e477ae3c8039f616cb8c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 12 Sep 2023 14:47:07 -0600 Subject: [PATCH 2279/2777] combase/tests: Add tests for implicit MTA with RoGetActivationFactory(). CW-Bug-Id: #22728 --- dlls/combase/tests/roapi.c | 198 +++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) diff --git a/dlls/combase/tests/roapi.c b/dlls/combase/tests/roapi.c index f10cbb4507b..3959d7435b0 100644 --- a/dlls/combase/tests/roapi.c +++ b/dlls/combase/tests/roapi.c @@ -116,12 +116,210 @@ static void test_ActivationFactories(void) RoUninitialize(); } +static APTTYPE check_thread_apttype; +static APTTYPEQUALIFIER check_thread_aptqualifier; +static HRESULT check_thread_hr; + +static DWORD WINAPI check_apartment_thread(void *dummy) +{ + check_thread_apttype = 0xdeadbeef; + check_thread_aptqualifier = 0xdeadbeef; + check_thread_hr = CoGetApartmentType(&check_thread_apttype, &check_thread_aptqualifier); + return 0; +} + +#define check_thread_apartment(a) check_thread_apartment_(__LINE__, FALSE, a) +#define check_thread_apartment_broken(a) check_thread_apartment_(__LINE__, TRUE, a) +static void check_thread_apartment_(unsigned int line, BOOL broken_fail, HRESULT expected_hr_thread) +{ + HANDLE thread; + + check_thread_hr = 0xdeadbeef; + thread = CreateThread(NULL, 0, check_apartment_thread, NULL, 0, NULL); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + ok_(__FILE__, line)(check_thread_hr == expected_hr_thread + || broken(broken_fail && expected_hr_thread == S_OK && check_thread_hr == CO_E_NOTINITIALIZED), + "got %#lx, expected %#lx.\n", check_thread_hr, expected_hr_thread); + if (SUCCEEDED(check_thread_hr)) + { + ok_(__FILE__, line)(check_thread_apttype == APTTYPE_MTA, "got %d.\n", check_thread_apttype); + ok_(__FILE__, line)(check_thread_aptqualifier == APTTYPEQUALIFIER_IMPLICIT_MTA, "got %d.\n", check_thread_aptqualifier); + } +} + +static HANDLE mta_init_thread_init_done_event, mta_init_thread_done_event; + +static DWORD WINAPI mta_init_thread(void *dummy) +{ + HRESULT hr; + + hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + ok(hr == S_OK, "got %#lx.\n", hr); + SetEvent(mta_init_thread_init_done_event); + + WaitForSingleObject(mta_init_thread_done_event, INFINITE); + CoUninitialize(); + return 0; +} + +static DWORD WINAPI mta_init_implicit_thread(void *dummy) +{ + IActivationFactory *factory; + HSTRING str; + HRESULT hr; + + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = WindowsCreateString(L"Does.Not.Exist", ARRAY_SIZE(L"Does.Not.Exist") - 1, &str); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory); + ok(hr == REGDB_E_CLASSNOTREG, "got %#lx.\n", hr); + WindowsDeleteString(str); + + SetEvent(mta_init_thread_init_done_event); + WaitForSingleObject(mta_init_thread_done_event, INFINITE); + + /* No CoUninitialize(), testing cleanup on thread exit. */ + return 0; +} + +static void test_implicit_mta(void) +{ + static const struct + { + BOOL ro_init; + BOOL mta; + BOOL ro_uninit; + } + tests[] = + { + { TRUE, TRUE, TRUE }, + { TRUE, FALSE, FALSE }, + { TRUE, FALSE, TRUE }, + { FALSE, FALSE, FALSE }, + { FALSE, FALSE, TRUE }, + }; + APTTYPEQUALIFIER aptqualifier; + IActivationFactory *factory; + APTTYPE apttype; + unsigned int i; + HANDLE thread; + HSTRING str; + HRESULT hr; + + hr = WindowsCreateString(L"Does.Not.Exist", ARRAY_SIZE(L"Does.Not.Exist") - 1, &str); + ok(hr == S_OK, "got %#lx.\n", hr); + /* RoGetActivationFactory doesn't implicitly initialize COM. */ + hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory); + todo_wine ok(hr == CO_E_NOTINITIALIZED, "got %#lx.\n", hr); + + check_thread_apartment(CO_E_NOTINITIALIZED); + + /* RoGetActivationFactory initializes implicit MTA. */ + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context("test %u", i); + if (tests[i].ro_init) + hr = RoInitialize(tests[i].mta ? RO_INIT_MULTITHREADED : RO_INIT_SINGLETHREADED); + else + hr = CoInitializeEx(NULL, tests[i].mta ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED); + ok(hr == S_OK, "got %#lx.\n", hr); + check_thread_apartment(tests[i].mta ? S_OK : CO_E_NOTINITIALIZED); + hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory); + ok(hr == REGDB_E_CLASSNOTREG, "got %#lx.\n", hr); + todo_wine_if(!tests[i].mta) check_thread_apartment_broken(S_OK); /* Broken on Win8. */ + hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory); + ok(hr == REGDB_E_CLASSNOTREG, "got %#lx.\n", hr); + todo_wine_if(!tests[i].mta) check_thread_apartment_broken(S_OK); /* Broken on Win8. */ + if (tests[i].ro_uninit) + RoUninitialize(); + else + CoUninitialize(); + check_thread_apartment(CO_E_NOTINITIALIZED); + winetest_pop_context(); + } + + mta_init_thread_init_done_event = CreateEventW(NULL, FALSE, FALSE, NULL); + mta_init_thread_done_event = CreateEventW(NULL, FALSE, FALSE, NULL); + + /* RoGetActivationFactory references implicit MTA in a current thread + * even if implicit MTA was already initialized: check with STA init + * after RoGetActivationFactory(). */ + thread = CreateThread(NULL, 0, mta_init_thread, NULL, 0, NULL); + ok(!!thread, "failed.\n"); + WaitForSingleObject(mta_init_thread_init_done_event, INFINITE); + check_thread_apartment(S_OK); + + hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory); + ok(hr == REGDB_E_CLASSNOTREG, "got %#lx.\n", hr); + check_thread_apartment(S_OK); + + hr = CoGetApartmentType(&apttype, &aptqualifier); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(apttype == APTTYPE_MTA, "got %d.\n", apttype); + ok(aptqualifier == APTTYPEQUALIFIER_IMPLICIT_MTA, "got %d.\n", aptqualifier); + + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = CoGetApartmentType(&apttype, &aptqualifier); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(apttype == APTTYPE_MAINSTA, "got %d.\n", apttype); + ok(aptqualifier == APTTYPEQUALIFIER_NONE, "got %d.\n", aptqualifier); + + SetEvent(mta_init_thread_done_event); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + todo_wine check_thread_apartment_broken(S_OK); /* Broken on Win8. */ + CoUninitialize(); + check_thread_apartment(CO_E_NOTINITIALIZED); + + /* RoGetActivationFactory references implicit MTA in a current thread + * even if implicit MTA was already initialized: check with STA init + * before RoGetActivationFactory(). */ + thread = CreateThread(NULL, 0, mta_init_thread, NULL, 0, NULL); + ok(!!thread, "failed.\n"); + WaitForSingleObject(mta_init_thread_init_done_event, INFINITE); + check_thread_apartment(S_OK); + + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory); + ok(hr == REGDB_E_CLASSNOTREG, "got %#lx.\n", hr); + check_thread_apartment(S_OK); + + SetEvent(mta_init_thread_done_event); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + todo_wine check_thread_apartment_broken(S_OK); /* Broken on Win8. */ + CoUninitialize(); + check_thread_apartment(CO_E_NOTINITIALIZED); + + /* Test implicit MTA apartment thread exit. */ + thread = CreateThread(NULL, 0, mta_init_implicit_thread, NULL, 0, NULL); + ok(!!thread, "failed.\n"); + WaitForSingleObject(mta_init_thread_init_done_event, INFINITE); + todo_wine check_thread_apartment_broken(S_OK); /* Broken on Win8. */ + SetEvent(mta_init_thread_done_event); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + check_thread_apartment(CO_E_NOTINITIALIZED); + + CloseHandle(mta_init_thread_init_done_event); + CloseHandle(mta_init_thread_done_event); + WindowsDeleteString(str); +} + START_TEST(roapi) { BOOL ret; load_resource(L"wine.combase.test.dll"); + test_implicit_mta(); test_ActivationFactories(); SetLastError(0xdeadbeef); From b91b97ba1063945234fdf7f349ef8f0e38fcba56 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 12 Sep 2023 12:53:27 -0600 Subject: [PATCH 2280/2777] combase: Create implicit MTA in STA apartment in RoGetActivationFactory(). CW-Bug-Id: #22728 --- dlls/combase/apartment.c | 32 ++++++++++++++++++++++++++++++++ dlls/combase/combase.c | 3 +++ dlls/combase/combase_private.h | 2 ++ dlls/combase/roapi.c | 5 +++++ dlls/combase/tests/roapi.c | 12 ++++++------ dlls/ole32/compobj_private.h | 1 + 6 files changed, 49 insertions(+), 6 deletions(-) diff --git a/dlls/combase/apartment.c b/dlls/combase/apartment.c index eb63fea6ef8..38a58aa0e72 100644 --- a/dlls/combase/apartment.c +++ b/dlls/combase/apartment.c @@ -1159,6 +1159,11 @@ void leave_apartment(struct tlsdata *data) if (data->ole_inits) WARN( "Uninitializing apartment while Ole is still initialized\n" ); apartment_release(data->apt); + if (data->implicit_mta) + { + apartment_release(data->implicit_mta); + data->implicit_mta = NULL; + } data->apt = NULL; data->flags &= ~(OLETLS_DISABLE_OLE1DDE | OLETLS_APARTMENTTHREADED | OLETLS_MULTITHREADED); } @@ -1290,3 +1295,30 @@ void apartment_global_cleanup(void) apartment_release_dlls(); DeleteCriticalSection(&apt_cs); } + +HRESULT reference_implicit_mta_from_sta(void) +{ + struct tlsdata *data; + HRESULT hr; + struct apartment *apt, *apt_mt; + + if (FAILED(hr = com_get_tlsdata(&data))) + return hr; + if ((apt = data->apt) && (data->implicit_mta || apt->multi_threaded)) + return S_OK; + + EnterCriticalSection(&apt_cs); + if (apt && !mta) + apt_mt = mta = apartment_construct(COINIT_MULTITHREADED); + else if ((apt_mt = mta)) + apartment_addref(mta); + LeaveCriticalSection(&apt_cs); + + if (!apt_mt) + { + ERR("Apartment not initialized.\n"); + return CO_E_NOTINITIALIZED; + } + data->implicit_mta = apt_mt; + return S_OK; +} diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c index 0695bb77405..16c149679df 100644 --- a/dlls/combase/combase.c +++ b/dlls/combase/combase.c @@ -410,6 +410,9 @@ static void com_cleanup_tlsdata(void) if (tlsdata->apt) apartment_release(tlsdata->apt); + if (tlsdata->implicit_mta) + apartment_release(tlsdata->implicit_mta); + if (tlsdata->errorinfo) IErrorInfo_Release(tlsdata->errorinfo); if (tlsdata->state) diff --git a/dlls/combase/combase_private.h b/dlls/combase/combase_private.h index 19e3def0b4e..79f3aba91b0 100644 --- a/dlls/combase/combase_private.h +++ b/dlls/combase/combase_private.h @@ -92,6 +92,7 @@ struct tlsdata struct list spies; /* Spies installed with CoRegisterInitializeSpy */ DWORD spies_lock; DWORD cancelcount; + struct apartment *implicit_mta; /* mta referenced by roapi from sta thread */ }; extern HRESULT WINAPI InternalTlsAllocData(struct tlsdata **data); @@ -161,6 +162,7 @@ void apartment_release(struct apartment *apt) DECLSPEC_HIDDEN; struct apartment * apartment_get_current_or_mta(void) DECLSPEC_HIDDEN; HRESULT apartment_increment_mta_usage(CO_MTA_USAGE_COOKIE *cookie) DECLSPEC_HIDDEN; void apartment_decrement_mta_usage(CO_MTA_USAGE_COOKIE cookie) DECLSPEC_HIDDEN; +HRESULT reference_implicit_mta_from_sta(void) DECLSPEC_HIDDEN; struct apartment * apartment_get_mta(void) DECLSPEC_HIDDEN; HRESULT apartment_get_inproc_class_object(struct apartment *apt, const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, DWORD class_context, void **ppv) DECLSPEC_HIDDEN; diff --git a/dlls/combase/roapi.c b/dlls/combase/roapi.c index 78f35de39d4..807a9059fa7 100644 --- a/dlls/combase/roapi.c +++ b/dlls/combase/roapi.c @@ -24,6 +24,8 @@ #include "roerrorapi.h" #include "winstring.h" +#include "combase_private.h" + #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(combase); @@ -163,6 +165,9 @@ HRESULT WINAPI RoGetActivationFactory(HSTRING classid, REFIID iid, void **class_ if (!iid || !class_factory) return E_INVALIDARG; + if (FAILED(hr = reference_implicit_mta_from_sta())) + return hr; + hr = get_library_for_classid(WindowsGetStringRawBuffer(classid, NULL), &library); if (FAILED(hr)) { diff --git a/dlls/combase/tests/roapi.c b/dlls/combase/tests/roapi.c index 3959d7435b0..ef0035dae4e 100644 --- a/dlls/combase/tests/roapi.c +++ b/dlls/combase/tests/roapi.c @@ -213,7 +213,7 @@ static void test_implicit_mta(void) ok(hr == S_OK, "got %#lx.\n", hr); /* RoGetActivationFactory doesn't implicitly initialize COM. */ hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory); - todo_wine ok(hr == CO_E_NOTINITIALIZED, "got %#lx.\n", hr); + ok(hr == CO_E_NOTINITIALIZED, "got %#lx.\n", hr); check_thread_apartment(CO_E_NOTINITIALIZED); @@ -229,10 +229,10 @@ static void test_implicit_mta(void) check_thread_apartment(tests[i].mta ? S_OK : CO_E_NOTINITIALIZED); hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory); ok(hr == REGDB_E_CLASSNOTREG, "got %#lx.\n", hr); - todo_wine_if(!tests[i].mta) check_thread_apartment_broken(S_OK); /* Broken on Win8. */ + check_thread_apartment_broken(S_OK); /* Broken on Win8. */ hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)&factory); ok(hr == REGDB_E_CLASSNOTREG, "got %#lx.\n", hr); - todo_wine_if(!tests[i].mta) check_thread_apartment_broken(S_OK); /* Broken on Win8. */ + check_thread_apartment_broken(S_OK); /* Broken on Win8. */ if (tests[i].ro_uninit) RoUninitialize(); else @@ -272,7 +272,7 @@ static void test_implicit_mta(void) SetEvent(mta_init_thread_done_event); WaitForSingleObject(thread, INFINITE); CloseHandle(thread); - todo_wine check_thread_apartment_broken(S_OK); /* Broken on Win8. */ + check_thread_apartment_broken(S_OK); /* Broken on Win8. */ CoUninitialize(); check_thread_apartment(CO_E_NOTINITIALIZED); @@ -294,7 +294,7 @@ static void test_implicit_mta(void) SetEvent(mta_init_thread_done_event); WaitForSingleObject(thread, INFINITE); CloseHandle(thread); - todo_wine check_thread_apartment_broken(S_OK); /* Broken on Win8. */ + check_thread_apartment_broken(S_OK); /* Broken on Win8. */ CoUninitialize(); check_thread_apartment(CO_E_NOTINITIALIZED); @@ -302,7 +302,7 @@ static void test_implicit_mta(void) thread = CreateThread(NULL, 0, mta_init_implicit_thread, NULL, 0, NULL); ok(!!thread, "failed.\n"); WaitForSingleObject(mta_init_thread_init_done_event, INFINITE); - todo_wine check_thread_apartment_broken(S_OK); /* Broken on Win8. */ + check_thread_apartment_broken(S_OK); /* Broken on Win8. */ SetEvent(mta_init_thread_done_event); WaitForSingleObject(thread, INFINITE); CloseHandle(thread); diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index 34f5a8ec485..ad6b70d7a44 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -63,6 +63,7 @@ struct oletls struct list spies; /* Spies installed with CoRegisterInitializeSpy */ DWORD spies_lock; DWORD cancelcount; + struct apartment *implicit_mta; /* mta referenced by roapi from sta thread */ }; /* Global Interface Table Functions */ From ed51426269e7fbfe32391b6d1083a72441cc13ab Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 14 Sep 2023 16:20:08 -0600 Subject: [PATCH 2281/2777] d3dx9: Handle special adjacency index value in d3dx9_mesh_OptimizeInplace(). CW-Bug-Id: #22737 --- dlls/d3dx9_36/mesh.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index f033ac14cb7..47a0cadde67 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -1624,6 +1624,13 @@ static HRESULT remap_faces_for_attrsort(struct d3dx9_mesh *This, const DWORD *in return D3D_OK; } +static DWORD adjacency_remap(DWORD *face_remap, DWORD index) +{ + if (index == 0xffffffff) + return index; + return face_remap[index]; +} + static HRESULT WINAPI d3dx9_mesh_OptimizeInplace(ID3DXMesh *iface, DWORD flags, const DWORD *adjacency_in, DWORD *adjacency_out, DWORD *face_remap_out, ID3DXBuffer **vertex_remap_out) { @@ -1778,9 +1785,10 @@ static HRESULT WINAPI d3dx9_mesh_OptimizeInplace(ID3DXMesh *iface, DWORD flags, for (i = 0; i < This->numfaces; i++) { DWORD old_pos = i * 3; DWORD new_pos = face_remap[i] * 3; - adjacency_out[new_pos++] = face_remap[adjacency_in[old_pos++]]; - adjacency_out[new_pos++] = face_remap[adjacency_in[old_pos++]]; - adjacency_out[new_pos++] = face_remap[adjacency_in[old_pos++]]; + + adjacency_out[new_pos++] = adjacency_remap(face_remap, adjacency_in[old_pos++]); + adjacency_out[new_pos++] = adjacency_remap(face_remap, adjacency_in[old_pos++]); + adjacency_out[new_pos] = adjacency_remap(face_remap, adjacency_in[old_pos]); } } else { memcpy(adjacency_out, adjacency_in, This->numfaces * 3 * sizeof(*adjacency_out)); From 2223786722e740508cf36b6e0cb9cacda50314ea Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 14 Sep 2023 16:20:36 -0600 Subject: [PATCH 2282/2777] d3dx9/tests: Add a basic test for d3dx9_mesh_OptimizeInplace(). CW-Bug-Id: #22737 --- dlls/d3dx9_36/tests/mesh.c | 117 +++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c index f44e8f9be52..c988c368382 100644 --- a/dlls/d3dx9_36/tests/mesh.c +++ b/dlls/d3dx9_36/tests/mesh.c @@ -11439,6 +11439,122 @@ static void test_load_skin_mesh_from_xof(void) DestroyWindow(hwnd); } +static void test_mesh_optimize(void) +{ +/* + * . _ . + * / \ / \ + * . _ . _ . + * \ / \ / + * . _ . + */ + static const struct + { + float c[3]; + float n[3]; + float t[2]; + } + vertices[] = + { + { {-0.5f, -1.0f, 0.0f,}, {0.0f, 0.0f, 1.0f}, {-0.5f, -1.0f} }, + { { 0.5f, -1.0f, 0.0f,}, {0.0f, 0.0f, 1.0f}, { 0.5f, -1.0f} }, + + { {-1.0f, 0.0f, 0.0f,}, {0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f} }, + { { 0.0f, 0.0f, 0.0f,}, {0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f} }, + { { 1.0f, 0.0f, 0.0f,}, {0.0f, 0.0f, 1.0f}, { 1.0f, 0.0f} }, + + { {-0.5f, 1.0f, 0.0f,}, {0.0f, 0.0f, 1.0f}, {-0.5f, 1.0f} }, + { { 0.5f, 1.0f, 0.0f,}, {0.0f, 0.0f, 1.0f}, { 0.5f, 1.0f} }, + }; + static const unsigned short indices[] = + { + 3, 0, 2, + 3, 2, 5, + 3, 5, 6, + 3, 6, 4, + 3, 4, 1, + 3, 1, 0, + }; + static const DWORD attrs[] = { 1, 2, 1, 2, 1, 2 }; + static const DWORD expected_adjacency[] = + { + 5, 0xffffffff, 1, + 0, 0xffffffff, 2, + 1, 0xffffffff, 3, + 2, 0xffffffff, 4, + 3, 0xffffffff, 5, + 4, 0xffffffff, 0, + }; + static const DWORD expected_adjacency_out[] = + { + 5, 0xffffffff, 3, + 3, 0xffffffff, 4, + 4, 0xffffffff, 5, + 0, 0xffffffff, 1, + 1, 0xffffffff, 2, + 2, 0xffffffff, 0, + }; + + DWORD adjacency[6 * 3], adjacency_out[6 * 3]; + struct test_context *test_context; + IDirect3DDevice9 *device; + ID3DXBuffer *buffer; + ID3DXMesh *mesh; + unsigned int i; + DWORD size; + HRESULT hr; + void *data; + + test_context = new_test_context(); + if (!test_context) + { + skip("Couldn't create test context\n"); + return; + } + device = test_context->device; + + hr = D3DXCreateMeshFVF(ARRAY_SIZE(attrs), ARRAY_SIZE(vertices), D3DXMESH_VB_MANAGED | D3DXMESH_IB_MANAGED, + D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1, device, &mesh); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = mesh->lpVtbl->LockVertexBuffer(mesh, 0, &data); + ok(hr == S_OK, "got %#lx.\n", hr); + memcpy(data, vertices, sizeof(vertices)); + hr = mesh->lpVtbl->UnlockVertexBuffer(mesh); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = mesh->lpVtbl->LockIndexBuffer(mesh, 0, &data); + ok(hr == S_OK, "got %#lx.\n", hr); + memcpy(data, indices, sizeof(indices)); + hr = mesh->lpVtbl->UnlockIndexBuffer(mesh); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = mesh->lpVtbl->LockAttributeBuffer(mesh, 0, (DWORD **)&data); + ok(hr == S_OK, "got %#lx.\n", hr); + memcpy(data, attrs, sizeof(attrs)); + hr = mesh->lpVtbl->UnlockAttributeBuffer(mesh); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = mesh->lpVtbl->GenerateAdjacency(mesh, 0.0f, adjacency); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(!memcmp(adjacency, expected_adjacency, sizeof(adjacency)), "data mismatch.\n"); + + hr = mesh->lpVtbl->OptimizeInplace(mesh, D3DXMESHOPT_IGNOREVERTS | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_DONOTSPLIT, + adjacency, adjacency_out, NULL, &buffer); + ok(hr == S_OK, "got %#lx.\n", hr); + + size = buffer->lpVtbl->GetBufferSize(buffer); + ok(size == sizeof(DWORD) * ARRAY_SIZE(vertices), "got %lu.\n", size); + data = buffer->lpVtbl->GetBufferPointer(buffer); + for (i = 0; i < ARRAY_SIZE(vertices); ++i) + ok(((DWORD *)data)[i] == i, "i %u, got %lu.\n", i, ((DWORD *)data)[i]); + ok(!memcmp(adjacency_out, expected_adjacency_out, sizeof(adjacency)), "data mismatch.\n"); + + buffer->lpVtbl->Release(buffer); + mesh->lpVtbl->Release(mesh); + free_test_context(test_context); +} + START_TEST(mesh) { D3DXBoundProbeTest(); @@ -11472,4 +11588,5 @@ START_TEST(mesh) test_compute_normals(); test_D3DXFrameFind(); test_load_skin_mesh_from_xof(); + test_mesh_optimize(); } From fba48ad5682705f1ef48f5cf33424bc7ba8e4bf8 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 15 Sep 2023 15:13:10 -0600 Subject: [PATCH 2283/2777] kernelbase, winex11.drv: HACK: Add --use-angle=gl for Red Tie Runner. And override Nvidia in GL so that works on Nvidia. CW-Bug-Id: #22742 --- dlls/kernelbase/process.c | 1 + dlls/winex11.drv/opengl.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 7afd5f3a38e..3c52ef6fa3c 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -594,6 +594,7 @@ static const WCHAR *hack_append_command_line( const WCHAR *cmd ) {L"PaladinLias\\Game.exe", L" --use-gl=desktop"}, {L"EverQuest 2\\LaunchPad.exe", L" --use-gl=swiftshader"}, {L"Everquest F2P\\LaunchPad.exe", L" --use-gl=swiftshader"}, + {L"Red Tie Runner.exe", L" --use-angle=gl"}, }; unsigned int i; diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index e35748b45e8..0380aa4cc63 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -3484,7 +3484,7 @@ static const GLubyte *wglGetString(GLenum name) if ((sz = read(fd, buffer, sizeof(buffer) - 1)) > 0) { buffer[sz] = 0; - if (strstr(buffer, "\\Paradox Launcher.exe")) + if (strstr(buffer, "\\Paradox Launcher.exe") || strstr(buffer, "Red Tie Runner.exe")) { FIXME("HACK: overriding GL vendor and renderer.\n"); override_vendor = 1; From 4cb5d6f81e1dedd8de2d62a9124df1812705895d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 15 Sep 2023 15:16:10 -0600 Subject: [PATCH 2284/2777] ntdll: HACK: Enable WINE_SIMULATE_WRITECOPY for Red Tie Runner. CW-Bug-Id: #22742 --- dlls/ntdll/unix/loader.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 3e4790249f8..b9b6f66c52f 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2363,6 +2363,7 @@ static void hacks_init(void) || !strcmp(sgi, "1680700") /* Purgo box */ || !strcmp(sgi, "2095300") /* Breakout 13 */ || !strcmp(sgi, "2053940") /* Idol Hands 2 */ + || !strcmp(sgi, "391150") /* Red Tie Runner */ || !strcmp(sgi, "2176450"); /* Mr. Hopp's Playhouse 3 */ if (main_argc > 1 && strstr(main_argv[1], "MicrosoftEdgeUpdate.exe")) From 49c83cda5a07b450700c4fe046897b56ffc2afea Mon Sep 17 00:00:00 2001 From: Fabian Maurer Date: Sun, 2 Jul 2023 22:22:42 +0200 Subject: [PATCH 2285/2777] dcomp: Add stub for DCompositionCreateDevice3. This is needed by recent chromium CW-Bug-Id: #22749 --- dlls/dcomp/dcomp.spec | 2 +- dlls/dcomp/device.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/dlls/dcomp/dcomp.spec b/dlls/dcomp/dcomp.spec index 8d625cc036a..2120ce8b6f6 100644 --- a/dlls/dcomp/dcomp.spec +++ b/dlls/dcomp/dcomp.spec @@ -14,7 +14,7 @@ @ stub DCompositionAttachMouseDragToHwnd @ stub DCompositionAttachMouseWheelToHwnd @ stdcall DCompositionCreateDevice2(ptr ptr ptr) -@ stub DCompositionCreateDevice3 +@ stdcall DCompositionCreateDevice3(ptr ptr ptr) @ stdcall DCompositionCreateDevice(ptr ptr ptr) @ stub DCompositionCreateSurfaceHandle @ stub DeserializeEffectDescription diff --git a/dlls/dcomp/device.c b/dlls/dcomp/device.c index 2d0600ce50a..2744d758e91 100644 --- a/dlls/dcomp/device.c +++ b/dlls/dcomp/device.c @@ -38,3 +38,10 @@ HRESULT WINAPI DCompositionCreateDevice2(IUnknown *rendering_device, REFIID iid, return E_NOTIMPL; } + +HRESULT WINAPI DCompositionCreateDevice3(IUnknown *rendering_device, REFIID iid, void **device) +{ + FIXME("%p, %s, %p.\n", rendering_device, debugstr_guid(iid), device); + + return E_NOTIMPL; +} From 00c1e8b951428cbf39cab9c80fa2ccbb2164e8c3 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 18 Sep 2023 19:10:05 -0600 Subject: [PATCH 2286/2777] mf/tests: Add tests for AAC decoder with different input number of channels. CW-Bug-Id: #22717 --- dlls/mf/tests/transform.c | 168 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 60ea02313ac..2ab39f33c58 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -35,6 +35,8 @@ #include "wmcodecdsp.h" #include "mediaerr.h" #include "amvideo.h" +#include "ks.h" +#include "ksmedia.h" #include "mf_test.h" @@ -2530,6 +2532,169 @@ static void test_aac_decoder_subtype(const struct attribute_desc *input_type_des CoUninitialize(); } +static void test_aac_decoder_channels(const struct attribute_desc *input_type_desc) +{ + static const struct attribute_desc expect_output_attributes[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + {0}, + }; + static const media_type_desc expect_available_outputs[] = + { + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float), + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 32), + }, + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM), + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16), + }, + }; + static const UINT32 expected_mask[7] = + { + 0, + 0, + 0, + SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_CENTER, + KSAUDIO_SPEAKER_QUAD, + KSAUDIO_SPEAKER_QUAD | SPEAKER_FRONT_CENTER, + KSAUDIO_SPEAKER_5POINT1, + }; + + UINT32 value, num_channels, expected_chans, format_index, sample_size; + unsigned int num_channels_index = ~0u; + struct attribute_desc input_desc[64]; + IMFTransform *transform; + IMFAttributes *attrs; + IMFMediaType *type; + BOOL many_channels; + ULONG i, ret; + HRESULT hr; + + for (i = 0; i < ARRAY_SIZE(input_desc); i++) + { + input_desc[i] = input_type_desc[i]; + if (!input_desc[i].key) + break; + if (IsEqualGUID(input_desc[i].key, &MF_MT_AUDIO_NUM_CHANNELS)) + num_channels_index = i; + } + + ok(num_channels_index != ~0u, "Could not find MF_MT_AUDIO_NUM_CHANNELS.\n"); + ok(i < ARRAY_SIZE(input_desc), "Too many attributes.\n"); + + hr = CoInitialize(NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + winetest_push_context("aacdec channels"); + + if (FAILED(hr = CoCreateInstance(&CLSID_MSAACDecMFT, NULL, CLSCTX_INPROC_SERVER, + &IID_IMFTransform, (void **)&transform))) + { + win_skip("AAC decoder transform is not available.\n"); + goto failed; + } + + for (num_channels = 0; num_channels < 16; ++num_channels) + { + many_channels = num_channels > 2; + winetest_push_context("chans %u", num_channels); + input_desc[num_channels_index].value.ulVal = num_channels; + + hr = MFCreateMediaType(&type); + ok(hr == S_OK, "got %#lx.\n", hr); + init_media_type(type, input_desc, -1); + hr = IMFTransform_SetInputType(transform, 0, type, 0); + IMFMediaType_Release(type); + if (num_channels <= 6) + ok(hr == S_OK, "got %#lx.\n", hr); + else + { + todo_wine ok(hr == MF_E_INVALIDMEDIATYPE, "got %#lx.\n", hr); + winetest_pop_context(); + continue; + } + + i = -1; + while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &type))) + { + winetest_push_context("out %lu", i); + ok(hr == S_OK, "got %#lx.\n", hr); + check_media_type(type, expect_output_attributes, -1); + format_index = i % 2; + sample_size = format_index ? 2 : 4; + check_media_type(type, expect_available_outputs[format_index], -1); + attrs = (IMFAttributes *)type; + + hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_NUM_CHANNELS, &value); + ok(hr == S_OK, "got %#lx.\n", hr); + if (!num_channels || i >= ARRAY_SIZE(expect_available_outputs)) + expected_chans = 2; + else + expected_chans = num_channels; + todo_wine_if(!num_channels) + ok(value == expected_chans, "got %u, expected %u.\n", value, expected_chans); + + hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &value); + ok(hr == S_OK, "got %#lx.\n", hr); + todo_wine_if(!num_channels) + ok(value == sample_size * 44100 * expected_chans, "got %u, expected %u.\n", + value, sample_size * 44100 * expected_chans); + + hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &value); + ok(hr == S_OK, "got %#lx.\n", hr); + todo_wine_if(!num_channels) + ok(value == sample_size * expected_chans, "got %u, expected %u.\n", value, sample_size * expected_chans); + + hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, &value); + if (many_channels && i < ARRAY_SIZE(expect_available_outputs)) + { + todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "got %#lx.\n", hr); + } + else + { + ok(hr == S_OK, "got %#lx.\n", hr); + ok(value == 1, "got %u.\n", value); + } + + value = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_CHANNEL_MASK, &value); + if (expected_chans <= 2) + { + ok(hr == MF_E_ATTRIBUTENOTFOUND, "got %#lx.\n", hr); + } + else + { + todo_wine { + ok(hr == S_OK, "got %#lx.\n", hr); + ok(value == expected_mask[expected_chans], "got %#x, expected %#x.\n", + value, expected_mask[expected_chans]); + } + } + + ret = IMFMediaType_Release(type); + ok(ret <= 1, "got %lu.\n", ret); + winetest_pop_context(); + } + ok(hr == MF_E_NO_MORE_TYPES, "got %#lx.\n", hr); + if (many_channels) + todo_wine ok(i == ARRAY_SIZE(expect_available_outputs) * 2, "got %lu media types.\n", i); + else + ok(i == ARRAY_SIZE(expect_available_outputs), "got %lu media types.\n", i); + winetest_pop_context(); + } + + ret = IMFTransform_Release(transform); + ok(!ret, "got %lu.\n", ret); + +failed: + winetest_pop_context(); + CoUninitialize(); +} + static void test_aac_decoder(void) { static const BYTE aac_raw_codec_data[] = {0x12, 0x08}; @@ -2558,6 +2723,9 @@ static void test_aac_decoder(void) test_aac_decoder_subtype(aac_input_type_desc); test_aac_decoder_subtype(raw_aac_input_type_desc); + + test_aac_decoder_channels(aac_input_type_desc); + test_aac_decoder_channels(raw_aac_input_type_desc); } static const BYTE wma_codec_data[10] = {0, 0x44, 0, 0, 0x17, 0, 0, 0, 0, 0}; From e538c75f8685e2c01856514d85df10171c412afc Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 18 Sep 2023 19:22:37 -0600 Subject: [PATCH 2287/2777] winegstreamer: Handle missing or zero channel count in _GetOutputAvailableType in AAC decoder. CW-Bug-Id: #22717 --- dlls/mf/tests/transform.c | 19 ++++++++++++++++--- dlls/winegstreamer/aac_decoder.c | 6 ++++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 2ab39f33c58..8a47938a51c 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -2598,6 +2598,22 @@ static void test_aac_decoder_channels(const struct attribute_desc *input_type_de goto failed; } + hr = MFCreateMediaType(&type); + ok(hr == S_OK, "got %#lx.\n", hr); + input_desc[num_channels_index].value.vt = VT_UI8; + input_desc[num_channels_index].value.ulVal = 1; + init_media_type(type, input_desc, -1); + hr = IMFTransform_SetInputType(transform, 0, type, 0); + ok(hr == S_OK, "got %#lx.\n", hr); + IMFMediaType_Release(type); + hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &type); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IMFAttributes_GetUINT32((IMFAttributes *)type, &MF_MT_AUDIO_NUM_CHANNELS, &value); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(value == 2, "got %u.\n", value); + IMFMediaType_Release(type); + input_desc[num_channels_index].value.vt = VT_UI4; + for (num_channels = 0; num_channels < 16; ++num_channels) { many_channels = num_channels > 2; @@ -2635,18 +2651,15 @@ static void test_aac_decoder_channels(const struct attribute_desc *input_type_de expected_chans = 2; else expected_chans = num_channels; - todo_wine_if(!num_channels) ok(value == expected_chans, "got %u, expected %u.\n", value, expected_chans); hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &value); ok(hr == S_OK, "got %#lx.\n", hr); - todo_wine_if(!num_channels) ok(value == sample_size * 44100 * expected_chans, "got %u, expected %u.\n", value, sample_size * 44100 * expected_chans); hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &value); ok(hr == S_OK, "got %#lx.\n", hr); - todo_wine_if(!num_channels) ok(value == sample_size * expected_chans, "got %u, expected %u.\n", value, sample_size * expected_chans); hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, &value); diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index 69c91b0d6d0..a24c29f9eed 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -291,6 +291,10 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR *type = NULL; + if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count)) + || !channel_count) + channel_count = 2; + if (index >= ARRAY_SIZE(aac_decoder_output_types)) return MF_E_NO_MORE_TYPES; index = ARRAY_SIZE(aac_decoder_output_types) - index - 1; @@ -318,8 +322,6 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, sample_size))) goto done; - if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count))) - goto done; if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, channel_count))) goto done; From 5ff0beadc20607d5cfe3f4ade87b5c70a1718ca6 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 18 Sep 2023 20:00:41 -0600 Subject: [PATCH 2288/2777] winegstreamer: Correct output available types attrs in AAC decoder for channel count > 2. CW-Bug-Id: #22717 --- dlls/mf/tests/transform.c | 4 +--- dlls/winegstreamer/aac_decoder.c | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 8a47938a51c..7d4522ebf23 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -2665,7 +2665,7 @@ static void test_aac_decoder_channels(const struct attribute_desc *input_type_de hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, &value); if (many_channels && i < ARRAY_SIZE(expect_available_outputs)) { - todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "got %#lx.\n", hr); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "got %#lx.\n", hr); } else { @@ -2681,11 +2681,9 @@ static void test_aac_decoder_channels(const struct attribute_desc *input_type_de } else { - todo_wine { ok(hr == S_OK, "got %#lx.\n", hr); ok(value == expected_mask[expected_chans], "got %#x, expected %#x.\n", value, expected_mask[expected_chans]); - } } ret = IMFMediaType_Release(type); diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index a24c29f9eed..0cb5ccf6efd 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -24,6 +24,8 @@ #include "mfobjects.h" #include "mftransform.h" #include "wmcodecdsp.h" +#include "ks.h" +#include "ksmedia.h" #include "wine/debug.h" @@ -48,6 +50,17 @@ static const GUID *const aac_decoder_output_types[] = &MFAudioFormat_Float, }; +static const UINT32 default_channel_mask[7] = +{ + 0, + 0, + 0, + SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_CENTER, + KSAUDIO_SPEAKER_QUAD, + KSAUDIO_SPEAKER_QUAD | SPEAKER_FRONT_CENTER, + KSAUDIO_SPEAKER_5POINT1, +}; + struct aac_decoder { IMFTransform IMFTransform_iface; @@ -295,6 +308,9 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR || !channel_count) channel_count = 2; + if (channel_count >= ARRAY_SIZE(default_channel_mask)) + return MF_E_INVALIDMEDIATYPE; + if (index >= ARRAY_SIZE(aac_decoder_output_types)) return MF_E_NO_MORE_TYPES; index = ARRAY_SIZE(aac_decoder_output_types) - index - 1; @@ -340,7 +356,10 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR goto done; if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1))) goto done; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1))) + if (channel_count < 3 && FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1))) + goto done; + if (channel_count >= 3 && FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_CHANNEL_MASK, + default_channel_mask[channel_count]))) goto done; done: From 669fb6ad41701a66a8d36c6d8f1e9652abce2bab Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 18 Sep 2023 20:28:15 -0600 Subject: [PATCH 2289/2777] winegstreamer: Validate maximum channel count in _SetInputType in AAC decoder. CW-Bug-Id: #22717 --- dlls/mf/tests/transform.c | 2 +- dlls/winegstreamer/aac_decoder.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 7d4522ebf23..2c7337d50cd 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -2629,7 +2629,7 @@ static void test_aac_decoder_channels(const struct attribute_desc *input_type_de ok(hr == S_OK, "got %#lx.\n", hr); else { - todo_wine ok(hr == MF_E_INVALIDMEDIATYPE, "got %#lx.\n", hr); + ok(hr == MF_E_INVALIDMEDIATYPE, "got %#lx.\n", hr); winetest_pop_context(); continue; } diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index 0cb5ccf6efd..ab94349d9e6 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -374,6 +374,7 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM { struct aac_decoder *decoder = impl_from_IMFTransform(iface); MF_ATTRIBUTE_TYPE item_type; + UINT32 channel_count; GUID major, subtype; HRESULT hr; ULONG i; @@ -396,6 +397,10 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM if (i == ARRAY_SIZE(aac_decoder_input_types)) return MF_E_INVALIDMEDIATYPE; + if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count)) + && channel_count >= ARRAY_SIZE(default_channel_mask)) + return MF_E_INVALIDMEDIATYPE; + if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &item_type)) || item_type != MF_ATTRIBUTE_UINT32) return MF_E_INVALIDMEDIATYPE; From 1a3b318a19649befeaceabaf4c0d03d08073c4e1 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 18 Sep 2023 20:05:21 -0600 Subject: [PATCH 2290/2777] winegstreamer: Also return output with 2 channels for multichannel inputs from AAC decoder. CW-Bug-Id: #22717 --- dlls/mf/tests/transform.c | 2 +- dlls/winegstreamer/aac_decoder.c | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 2c7337d50cd..a0df24bab6e 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -2692,7 +2692,7 @@ static void test_aac_decoder_channels(const struct attribute_desc *input_type_de } ok(hr == MF_E_NO_MORE_TYPES, "got %#lx.\n", hr); if (many_channels) - todo_wine ok(i == ARRAY_SIZE(expect_available_outputs) * 2, "got %lu media types.\n", i); + ok(i == ARRAY_SIZE(expect_available_outputs) * 2, "got %lu media types.\n", i); else ok(i == ARRAY_SIZE(expect_available_outputs), "got %lu media types.\n", i); winetest_pop_context(); diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index ab94349d9e6..bee353a7174 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -311,6 +311,14 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR if (channel_count >= ARRAY_SIZE(default_channel_mask)) return MF_E_INVALIDMEDIATYPE; + if (channel_count > 2 && index >= ARRAY_SIZE(aac_decoder_output_types)) + { + /* If there are more than two channels in the input type GetOutputAvailableType additionally lists + * types with 2 channels. */ + index -= ARRAY_SIZE(aac_decoder_output_types); + channel_count = 2; + } + if (index >= ARRAY_SIZE(aac_decoder_output_types)) return MF_E_NO_MORE_TYPES; index = ARRAY_SIZE(aac_decoder_output_types) - index - 1; From abc049ad3b58570766397805e3e4130ea1fa0e83 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 20 Sep 2023 15:45:43 -0600 Subject: [PATCH 2291/2777] wine.inf: Set FLG_HEAP_ENABLE_FREE_CHECK for Crysis 2 Remastered. CW-Bug-Id: #22761 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 6273413d92e..e31c426ca04 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -420,6 +420,7 @@ HKLM,%CurrentVersionNT%\ProfileList,,16 HKLM,%CurrentVersionNT%\Winlogon,"Shell",,"explorer.exe" ;; App specific heap debug flags HKLM,%CurrentVersionNT%\Image File Execution Options\ChaosCode.exe,GlobalFlag,0x00040002,0x00000020 +HKLM,%CurrentVersionNT%\Image File Execution Options\Crysis2Remastered.exe,GlobalFlag,0x00040002,0x00000020 [CurrentVersionWow64] HKLM,%CurrentVersion%,"ProgramFilesDir (x86)",,"%16426%" From 8d18881c52e7f11a3a85ac2085502a83aa191129 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 21 Sep 2023 16:23:33 -0600 Subject: [PATCH 2292/2777] ntdll: Remove entries from queue in RtlWakeAddressAll(). CW-Bug-Id: #22770 --- dlls/ntdll/sync.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 4f5ee820286..11cea3c27ae 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -954,8 +954,8 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size void WINAPI RtlWakeAddressAll( const void *addr ) { struct futex_queue *queue = get_futex_queue( addr ); + struct futex_entry *entry, *next; unsigned int count = 0, i; - struct futex_entry *entry; DWORD tids[256]; TRACE("%p\n", addr); @@ -967,10 +967,12 @@ void WINAPI RtlWakeAddressAll( const void *addr ) if (!queue->queue.next) list_init(&queue->queue); - LIST_FOR_EACH_ENTRY( entry, &queue->queue, struct futex_entry, entry ) + LIST_FOR_EACH_ENTRY_SAFE( entry, next, &queue->queue, struct futex_entry, entry ) { if (entry->addr == addr) { + entry->addr = NULL; + list_remove( &entry->entry ); /* Try to buffer wakes, so that we don't make a system call while * holding a spinlock. */ if (count < ARRAY_SIZE(tids)) From b038988a92cac82e604a199ce97ba0556fdefb8b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 21 Sep 2023 16:29:14 -0600 Subject: [PATCH 2293/2777] ntdll: Pre-check entry->addr before taking a spin lock in RtlWaitOnAddress(). CW-Bug-Id: #22770 --- dlls/ntdll/sync.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 11cea3c27ae..650226b89f4 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -936,11 +936,14 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size ret = NtWaitForAlertByThreadId( NULL, timeout ); - spin_lock( &queue->lock ); - /* We may have already been removed by a call to RtlWakeAddressSingle(). */ + /* We may have already been removed by a call to RtlWakeAddressSingle() or RtlWakeAddressAll(). */ if (entry.addr) - list_remove( &entry.entry ); - spin_unlock( &queue->lock ); + { + spin_lock( &queue->lock ); + if (entry.addr) + list_remove( &entry.entry ); + spin_unlock( &queue->lock ); + } TRACE("returning %#lx\n", ret); From 002567d321f51390653e37706cfe46b2d89e21eb Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Tue, 19 Sep 2023 15:21:25 +0200 Subject: [PATCH 2294/2777] ntdll: Allow empty application nodes in actctx. Signed-off-by: Eric Pouech (cherry picked from commit 6558611fa2d24447297cb62d168b924c33839c43) CW-Bug-ID: #20860 This patch doesn't let the game start; this patch lets the game crash a little bit further down the road. --- dlls/kernel32/tests/actctx.c | 34 ++++++++++++++++++++++++++++++++++ dlls/ntdll/actctx.c | 9 +++++++++ 2 files changed, 43 insertions(+) diff --git a/dlls/kernel32/tests/actctx.c b/dlls/kernel32/tests/actctx.c index bec04b7f066..fe4b24cf20d 100644 --- a/dlls/kernel32/tests/actctx.c +++ b/dlls/kernel32/tests/actctx.c @@ -506,6 +506,23 @@ static const char settings_manifest3[] = " " ""; +static const char settings_manifest4[] = +"" +" " +" " +" " +" " +" true" +" " +" " +" " +" " +" " +" true" +" " +" " +""; + static const char two_dll_manifest_dll[] = "" " " @@ -3302,6 +3319,23 @@ static void test_settings(void) ok( !ret, "QueryActCtxSettingsW succeeded\n" ); ok( GetLastError() == ERROR_SXS_KEY_NOT_FOUND, "wrong error %lu\n", GetLastError() ); ReleaseActCtx(handle); + + /* lookup occurs in first non empty node */ + create_manifest_file( "manifest_settings4.manifest", settings_manifest4, -1, NULL, NULL ); + handle = test_create("manifest_settings4.manifest"); + ok( handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %lu\n", GetLastError() ); + DeleteFileA( "manifest_settings3.manifest" ); + SetLastError( 0xdeadbeef ); + size = 0xdead; + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pQueryActCtxSettingsW( 0, handle, NULL, dpiAwareW, buffer, 80, &size ); + ok( ret, "QueryActCtxSettingsW failed\n" ); + SetLastError( 0xdeadbeef ); + size = 0xdead; + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pQueryActCtxSettingsW( 0, handle, NULL, dpiAwarenessW, buffer, 80, &size ); + ok( !ret, "QueryActCtxSettingsW succeeded\n" ); + ReleaseActCtx(handle); } typedef struct diff --git a/dlls/ntdll/actctx.c b/dlls/ntdll/actctx.c index 721a2f339a5..99a5c8f9b8a 100644 --- a/dlls/ntdll/actctx.c +++ b/dlls/ntdll/actctx.c @@ -2565,6 +2565,15 @@ static void parse_application_elem( xmlbuf_t *xmlbuf, struct assembly *assembly, struct actctx_loader *acl, const struct xml_elem *parent ) { struct xml_elem elem; + struct xml_attr attr; + BOOL end = FALSE; + + while (next_xml_attr(xmlbuf, &attr, &end)) + { + if (!is_xmlns_attr( &attr )) WARN( "unknown attr %s\n", debugstr_xml_attr(&attr) ); + } + + if (end) return; while (next_xml_elem( xmlbuf, &elem, parent )) { From 1b4edd6a753d1aec6c643b5e75bb7d0dc7f0671f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 21 Oct 2020 17:19:30 +0200 Subject: [PATCH 2295/2777] makedep: Allow building modules with C++ sources. CW-Bug-Id: #22729 --- tools/makedep.c | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/tools/makedep.c b/tools/makedep.c index 3dd58428c99..12dc51cdf17 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -201,6 +201,7 @@ struct makefile int data_only; int is_win16; int is_exe; + int has_cxx; int disabled[MAX_ARCHS]; /* values generated at output time */ @@ -1185,6 +1186,7 @@ static const struct } parse_functions[] = { { ".c", parse_c_file }, + { ".cpp", parse_c_file }, { ".h", parse_c_file }, { ".inl", parse_c_file }, { ".l", parse_c_file }, @@ -1498,7 +1500,7 @@ static struct file *open_include_file( const struct makefile *make, struct incl_ return file; } - if (make->extlib) return NULL; /* ignore missing files in external libs */ + if (make->extlib || make->has_cxx) return NULL; /* ignore missing files in external libs */ fprintf( stderr, "%s:%d: error: ", pFile->included_by->file->name, pFile->included_line ); perror( pFile->name ); @@ -1551,6 +1553,13 @@ static void parse_file( struct makefile *make, struct incl_file *source, int src { struct file *file = src ? open_src_file( make, source ) : open_include_file( make, source ); + if (strendswith( source->name, ".cpp" )) + { + /* ignore missing headers or unsupported includes in .cpp files */ + source->is_external = 1; + make->has_cxx = 1; + } + if (!file) return; source->file = file; @@ -2416,9 +2425,11 @@ static const char *cmd_prefix( const char *cmd ) /******************************************************************* * output_winegcc_command */ -static void output_winegcc_command( struct makefile *make, unsigned int arch ) +static void output_winegcc_command( struct makefile *make, unsigned int arch, int is_cxx ) { - output( "\t%s%s -o $@", cmd_prefix( "CCLD" ), tools_path( make, "winegcc" )); + const char *tool = tools_path( make, "winegcc" ); + if (is_cxx) strcpy( strrchr( tool, 'w' ), "wineg++" ); + output( "\t%s%s -o $@", cmd_prefix( "CCLD" ), tool ); output_filename( "--wine-objdir ." ); if (tools_dir) { @@ -3111,7 +3122,7 @@ static void output_source_spec( struct makefile *make, struct incl_file *source, output_filename( tools_path( make, "winebuild" )); output_filename( tools_path( make, "winegcc" )); output( "\n" ); - output_winegcc_command( make, arch ); + output_winegcc_command( make, arch, 0 ); output_filename( "-s" ); output_filenames( dll_flags ); if (arch) output_filenames( get_expanded_arch_var_array( make, "EXTRADLLFLAGS", arch )); @@ -3134,9 +3145,11 @@ static void output_source_one_arch( struct makefile *make, struct incl_file *sou struct strarray defines, struct strarray *targets, unsigned int arch, int is_dll_src ) { + const int is_cxx = strendswith( source->name, ".cpp" ); const char *obj_name; if (make->disabled[arch] && !(source->file->flags & FLAG_C_IMPLIB)) return; + make->has_cxx |= is_cxx; if (arch) { @@ -3164,10 +3177,11 @@ static void output_source_one_arch( struct makefile *make, struct incl_file *sou strarray_add( &make->clean_files, obj_name ); output( "%s: %s\n", obj_dir_path( make, obj_name ), source->filename ); - output( "\t%s%s -c -o $@ %s", cmd_prefix( "CC" ), arch_make_variable( "CC", arch ), source->filename ); + if (is_cxx) output( "\t%s%s -c -o $@ %s", cmd_prefix( "CXX" ), arch_make_variable( "CXX", arch ), source->filename ); + else output( "\t%s%s -c -o $@ %s", cmd_prefix( "CC" ), arch_make_variable( "CC", arch ), source->filename ); output_filenames( defines ); if (!source->use_msvcrt) output_filenames( make->unix_cflags ); - output_filenames( make->extlib ? extra_cflags_extlib[arch] : extra_cflags[arch] ); + output_filenames( make->extlib || is_cxx ? extra_cflags_extlib[arch] : extra_cflags[arch] ); if (!arch) { if (make->sharedlib || (source->file->flags & FLAG_C_UNIX)) @@ -3188,7 +3202,8 @@ static void output_source_one_arch( struct makefile *make, struct incl_file *sou } output_filenames( cpp_flags ); - output_filename( arch_make_variable( "CFLAGS", arch )); + if (is_cxx) output_filename( arch_make_variable( "CXXFLAGS", arch )); + else output_filename( arch_make_variable( "CFLAGS", arch )); output( "\n" ); if (make->testdll && !is_dll_src && strendswith( source->name, ".c" ) && @@ -3290,7 +3305,7 @@ static void output_fake_module( struct makefile *make ) output_filename( tools_path( make, "winebuild" )); output_filename( tools_path( make, "winegcc" )); output( "\n" ); - output_winegcc_command( make, arch ); + output_winegcc_command( make, arch, 0 ); output_filename( "-Wb,--fake-module" ); if (spec_file) { @@ -3314,7 +3329,7 @@ static void output_module( struct makefile *make, unsigned int arch ) struct strarray imports = make->imports; const char *module_name; const char *debug_file; - char *spec_file = NULL; + char *tool, *spec_file = NULL; unsigned int i; if (make->disabled[arch]) return; @@ -3358,9 +3373,15 @@ static void output_module( struct makefile *make, unsigned int arch ) output_filenames_obj_dir( make, make->res_files[arch] ); output_filenames( dep_libs ); output_filename( tools_path( make, "winebuild" )); - output_filename( tools_path( make, "winegcc" )); + tool = tools_path( make, "winegcc" ); + output_filename( tool ); + if (make->has_cxx) + { + strcpy( strrchr( tool, 'w' ), "wineg++" ); + output_filename( tool ); + } output( "\n" ); - output_winegcc_command( make, arch ); + output_winegcc_command( make, arch, make->has_cxx ); if (arch) output_filename( "-Wl,--wine-builtin" ); if (spec_file) { @@ -3527,7 +3548,7 @@ static void output_test_module( struct makefile *make, unsigned int arch ) strarray_add( &make->all_targets[arch], testmodule ); strarray_add( &make->clean_files, stripped ); output( "%s:\n", obj_dir_path( make, testmodule )); - output_winegcc_command( make, arch ); + output_winegcc_command( make, arch, 0 ); output_filenames( make->extradllflags ); output_filenames_obj_dir( make, make->object_files[arch] ); output_filenames_obj_dir( make, make->res_files[arch] ); @@ -3537,7 +3558,7 @@ static void output_test_module( struct makefile *make, unsigned int arch ) output_filename( arch_make_variable( "LDFLAGS", arch )); output( "\n" ); output( "%s:\n", obj_dir_path( make, stripped )); - output_winegcc_command( make, arch ); + output_winegcc_command( make, arch, 0 ); output_filename( "-s" ); output_filename( strmake( "-Wb,-F,%s_test.exe", basemodule )); output_filenames( make->extradllflags ); @@ -4208,6 +4229,7 @@ static void load_sources( struct makefile *make ) { "SOURCES", "C_SRCS", + "CXX_SRCS", "OBJC_SRCS", "RC_SRCS", "MC_SRCS", From e093242feb88db181ea034aa2581ec325b41ab32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 20 Sep 2023 00:06:48 +0200 Subject: [PATCH 2296/2777] Revert "makedep: Assume that all modules are built with msvcrt." This reverts commit a9183c7e3bd6ee25aeab2aed6c57a58d9558b614. CW-Bug-Id: #22729 --- tools/makedep.c | 53 ++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/tools/makedep.c b/tools/makedep.c index 12dc51cdf17..9497a8a7b97 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -198,6 +198,7 @@ struct makefile const char *staticlib; const char *importlib; const char *unixlib; + int use_msvcrt; int data_only; int is_win16; int is_exe; @@ -598,17 +599,6 @@ static int is_multiarch( unsigned int arch ) } -/******************************************************************* - * is_using_msvcrt - * - * Check if the files of a makefile use msvcrt by default. - */ -static int is_using_msvcrt( struct makefile *make ) -{ - return make->module || make->testdll; -} - - /******************************************************************* * arch_module_name */ @@ -867,7 +857,7 @@ static struct incl_file *add_generated_source( struct makefile *make, const char file->basename = xstrdup( filename ? filename : name ); file->filename = obj_dir_path( make, file->basename ); file->file->flags = FLAG_GENERATED; - file->use_msvcrt = is_using_msvcrt( make ); + file->use_msvcrt = make->use_msvcrt; list_add_tail( &make->sources, &file->entry ); if (make == include_makefile) { @@ -1624,7 +1614,7 @@ static struct incl_file *add_src_file( struct makefile *make, const char *name ) memset( file, 0, sizeof(*file) ); file->name = xstrdup(name); - file->use_msvcrt = is_using_msvcrt( make ); + file->use_msvcrt = make->use_msvcrt; file->is_external = !!make->extlib; list_add_tail( &make->sources, &file->entry ); if (make == include_makefile) @@ -1822,12 +1812,13 @@ static void add_generated_sources( struct makefile *make ) unsigned int i, arch; struct incl_file *source, *next, *file, *dlldata = NULL; struct strarray objs = get_expanded_make_var_array( make, "EXTRA_OBJS" ); + int multiarch = archs.count > 1 && make->use_msvcrt; LIST_FOR_EACH_ENTRY_SAFE( source, next, &make->sources, struct incl_file, entry ) { for (arch = 0; arch < archs.count; arch++) { - if (!is_multiarch( arch )) continue; + if (!arch != !multiarch) continue; if (source->file->flags & FLAG_IDL_CLIENT) { file = add_generated_source( make, replace_extension( source->name, ".idl", "_c.c" ), NULL, arch ); @@ -1931,7 +1922,7 @@ static void add_generated_sources( struct makefile *make ) { for (arch = 0; arch < archs.count; arch++) { - if (!is_multiarch( arch )) continue; + if (!arch != !multiarch) continue; file = add_generated_source( make, "testlist.o", "testlist.c", arch ); add_dependency( file->file, "wine/test.h", INCL_NORMAL ); add_all_includes( make, file, file->file ); @@ -2185,6 +2176,7 @@ static int is_crt_module( const char *file ) */ static const char *get_default_crt( const struct makefile *make ) { + if (!make->use_msvcrt) return NULL; if (make->module && is_crt_module( make->module )) return NULL; /* don't add crt import to crt dlls */ return !make->testdll && (!make->staticlib || make->extlib) ? "ucrtbase" : "msvcrt"; } @@ -2374,7 +2366,6 @@ static struct strarray get_source_defines( struct makefile *make, struct incl_fi strarray_add( &ret, strmake( "-I%s", root_src_dir_path( "include/msvcrt" ))); for (i = 0; i < make->include_paths.count; i++) strarray_add( &ret, strmake( "-I%s", make->include_paths.str[i] )); - strarray_add( &ret, get_crt_define( make )); } strarray_addall( &ret, make->define_args ); strarray_addall( &ret, get_expanded_file_local_var( make, obj, "EXTRADEFS" )); @@ -2437,9 +2428,7 @@ static void output_winegcc_command( struct makefile *make, unsigned int arch, in output_filename( tools_path( make, "winebuild" )); } output_filenames( target_flags[arch] ); - if (arch) return; - output_filename( "-mno-cygwin" ); - output_filenames( lddll_flags ); + if (!arch) output_filenames( lddll_flags ); } @@ -2861,6 +2850,7 @@ static void output_source_idl( struct makefile *make, struct incl_file *source, if (!(source->file->flags & idl_outputs[i].flag)) continue; for (arch = 0; arch < archs.count; arch++) { + if (!make->use_msvcrt) continue; if (!is_multiarch( arch )) continue; if (make->disabled[arch]) continue; dest = strmake( "%s%s%s", arch_dirs[arch], obj, idl_outputs[i].ext ); @@ -3154,13 +3144,13 @@ static void output_source_one_arch( struct makefile *make, struct incl_file *sou if (arch) { if (source->file->flags & FLAG_C_UNIX) return; - if (!is_using_msvcrt( make ) && !make->staticlib && !(source->file->flags & FLAG_C_IMPLIB)) return; + if (!make->use_msvcrt && !make->staticlib && !(source->file->flags & FLAG_C_IMPLIB)) return; } else if (source->file->flags & FLAG_C_UNIX) { if (!*dll_ext) return; } - else if (archs.count > 1 && is_using_msvcrt( make ) && + else if (archs.count > 1 && make->use_msvcrt && !(source->file->flags & FLAG_C_IMPLIB) && (!make->staticlib || make->extlib)) return; @@ -3347,6 +3337,12 @@ static void output_module( struct makefile *make, unsigned int arch ) strarray_addall( &all_libs, add_import_libs( make, &dep_libs, default_imports, IMPORT_TYPE_DEFAULT, arch ) ); if (!arch) strarray_addall( &all_libs, libs ); + if (!make->use_msvcrt) + { + strarray_addall( &all_libs, get_expanded_make_var_array( make, "UNIX_LIBS" )); + strarray_addall( &all_libs, libs ); + } + if (delay_load_flags[arch]) { for (i = 0; i < make->delayimports.count; i++) @@ -3589,7 +3585,7 @@ static void output_test_module( struct makefile *make, unsigned int arch ) output( ": %s", obj_dir_path( make, testmodule )); if (parent) { - char *parent_module = arch_module_name( make->testdll, arch ); + char *parent_module = arch_module_name( make->testdll, parent->use_msvcrt ? arch : 0 ); output_filename( obj_dir_path( parent, parent_module )); if (parent->unixlib) output_filename( obj_dir_path( parent, parent->unixlib )); } @@ -3839,7 +3835,12 @@ static void output_sources( struct makefile *make ) } else if (make->module) { - for (arch = 0; arch < archs.count; arch++) if (is_multiarch( arch )) output_module( make, arch ); + if (!make->use_msvcrt) output_module( make, 0 ); + else + { + for (arch = 0; arch < archs.count; arch++) + if (is_multiarch( arch )) output_module( make, arch ); + } if (make->unixlib) output_unix_lib( make ); if (make->importlib) for (arch = 0; arch < archs.count; arch++) output_import_lib( make, arch ); if (make->is_exe && !make->is_win16 && *dll_ext && strendswith( make->module, ".exe" )) @@ -4282,9 +4283,13 @@ static void load_sources( struct makefile *make ) } make->is_win16 = strarray_exists( &make->extradllflags, "-m16" ); make->data_only = strarray_exists( &make->extradllflags, "-Wb,--data-only" ); + make->use_msvcrt = (make->module || make->testdll || make->is_win16) && + !strarray_exists( &make->extradllflags, "-mcygwin" ); make->is_exe = strarray_exists( &make->extradllflags, "-mconsole" ) || strarray_exists( &make->extradllflags, "-mwindows" ); + if (make->use_msvcrt) strarray_add_uniq( &make->extradllflags, "-mno-cygwin" ); + if (make->module) { /* add default install rules if nothing was specified */ @@ -4341,6 +4346,8 @@ static void load_sources( struct makefile *make ) add_generated_sources( make ); + if (make->use_msvcrt) strarray_add( &make->define_args, get_crt_define( make )); + LIST_FOR_EACH_ENTRY( file, &make->includes, struct incl_file, entry ) parse_file( make, file, 0 ); LIST_FOR_EACH_ENTRY( file, &make->sources, struct incl_file, entry ) get_dependencies( file, file ); From aabaf8d435a1e2dd0f4b080382b71da55376e4f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 20 Sep 2023 00:03:48 +0200 Subject: [PATCH 2297/2777] makedep: Allow building modules from external sources. CW-Bug-Id: #22729 --- tools/makedep.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/makedep.c b/tools/makedep.c index 9497a8a7b97..77fa990b6b5 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -4414,7 +4414,7 @@ static int parse_option( const char *opt ) int main( int argc, char *argv[] ) { const char *makeflags = getenv( "MAKEFLAGS" ); - const char *target; + const char *target, *tmp; unsigned int i, j, arch; if (makeflags) parse_makeflags( makeflags ); @@ -4530,7 +4530,12 @@ int main( int argc, char *argv[] ) subdirs = get_expanded_make_var_array( top_makefile, "SUBDIRS" ); submakes = xmalloc( subdirs.count * sizeof(*submakes) ); - for (i = 0; i < subdirs.count; i++) submakes[i] = parse_makefile( subdirs.str[i] ); + for (i = 0; i < subdirs.count; i++) + { + submakes[i] = parse_makefile( subdirs.str[i] ); + if (*(tmp = subdirs.str[i]) == '/') tmp = strmake( "dlls%s", strrchr( tmp, '/' ) ); + submakes[i]->obj_dir = subdirs.str[i] = tmp; + } load_sources( top_makefile ); load_sources( include_makefile ); From d45cd219db5159bb1d3748dbbebb17d3fcda0fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 26 Sep 2023 16:34:16 +0200 Subject: [PATCH 2298/2777] makedep: Allow using an external wine object dir. CW-Bug-Id: #22729 --- tools/makedep.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tools/makedep.c b/tools/makedep.c index 77fa990b6b5..3436ee7a84f 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -143,6 +143,7 @@ static struct strarray subdirs; static struct strarray delay_import_libs; static struct strarray top_install[NB_INSTALL_RULES]; static const char *root_src_dir; +static const char *root_obj_dir; static const char *tools_dir; static const char *tools_ext; static const char *exe_ext; @@ -645,6 +646,16 @@ static char *root_src_dir_path( const char *path ) } +/******************************************************************* + * root_obj_dir_path + */ +static char *root_obj_dir_path( const char *path ) +{ + if (!root_obj_dir) return (char *)path; + return concat_paths( root_obj_dir, path ); +} + + /******************************************************************* * tools_dir_path */ @@ -2421,7 +2432,7 @@ static void output_winegcc_command( struct makefile *make, unsigned int arch, in const char *tool = tools_path( make, "winegcc" ); if (is_cxx) strcpy( strrchr( tool, 'w' ), "wineg++" ); output( "\t%s%s -o $@", cmd_prefix( "CCLD" ), tool ); - output_filename( "--wine-objdir ." ); + output_filename( strmake( "--wine-objdir %s", root_obj_dir_path( "." ) ) ); if (tools_dir) { output_filename( "--winebuild" ); @@ -4332,7 +4343,7 @@ static void load_sources( struct makefile *make ) strarray_add( &make->include_args, strmake( "-I%s", make->src_dir )); if (make->parent_dir) strarray_add( &make->include_args, strmake( "-I%s", src_dir_path( make, make->parent_dir ))); - strarray_add( &make->include_args, "-Iinclude" ); + strarray_add( &make->include_args, strmake( "-I%s", root_obj_dir_path( "include" ) ) ); if (root_src_dir) strarray_add( &make->include_args, strmake( "-I%s", root_src_dir_path( "include" ))); list_init( &make->sources ); @@ -4470,6 +4481,7 @@ int main( int argc, char *argv[] ) top_install[i] = get_expanded_make_var_array( top_makefile, strmake( "TOP_%s", install_variables[i] )); root_src_dir = get_expanded_make_variable( top_makefile, "srcdir" ); + root_obj_dir = get_expanded_make_variable( top_makefile, "objdir" ); tools_dir = get_expanded_make_variable( top_makefile, "toolsdir" ); tools_ext = get_expanded_make_variable( top_makefile, "toolsext" ); exe_ext = get_expanded_make_variable( top_makefile, "EXEEXT" ); From c1bfdf13c76761f77f07c04657a770d487a3d0e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 26 Sep 2023 16:34:50 +0200 Subject: [PATCH 2299/2777] makedep: Allow include to be missing from SUBDIRS. CW-Bug-Id: #22729 --- tools/makedep.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/makedep.c b/tools/makedep.c index 3436ee7a84f..3f3baf826df 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -1446,9 +1446,9 @@ static struct file *open_include_file( const struct makefile *make, struct incl_ if ((file = open_local_file( make, pFile->name, &pFile->filename ))) return file; /* check for global importlib (module dependency) */ - if (pFile->type == INCL_IMPORTLIB && find_importlib_module( pFile->name )) + if (pFile->type == INCL_IMPORTLIB) { - pFile->filename = pFile->name; + if (find_importlib_module( pFile->name )) pFile->filename = pFile->name; return NULL; } @@ -4549,6 +4549,8 @@ int main( int argc, char *argv[] ) submakes[i]->obj_dir = subdirs.str[i] = tmp; } + if (!include_makefile) include_makefile = parse_makefile( root_src_dir_path( "include" ) ); + load_sources( top_makefile ); load_sources( include_makefile ); for (i = 0; i < subdirs.count; i++) From 5666eb754b790ad3998a7121cded96c947ffd8d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 20 Sep 2023 09:49:29 +0200 Subject: [PATCH 2300/2777] makedep: Allow modules to have a different 64bit name. CW-Bug-Id: #22729 --- tools/makedep.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/tools/makedep.c b/tools/makedep.c index 3f3baf826df..6b02b154e45 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -193,6 +193,7 @@ struct makefile const char *obj_dir; const char *parent_dir; const char *module; + const char *module_x64; const char *testdll; const char *extlib; const char *sharedlib; @@ -3291,14 +3292,17 @@ static const struct static void output_fake_module( struct makefile *make ) { unsigned int arch = 0; /* fake modules are always native */ - const char *spec_file = NULL, *name = strmake( "%s%s", arch_pe_dirs[arch], make->module ); + const char *spec_file = NULL, *name; + const char *module = make->module; if (make->disabled[arch]) return; - if (!make->is_exe) spec_file = src_dir_path( make, replace_extension( make->module, ".dll", ".spec" )); + if (make->module_x64 && !strcmp( archs.str[arch], "x86_64" )) module = make->module_x64; + if (!make->is_exe) spec_file = src_dir_path( make, replace_extension( module, ".dll", ".spec" )); + name = strmake( "%s%s", arch_pe_dirs[arch], module ); strarray_add( &make->all_targets[arch], name ); - add_install_rule( make, make->module, arch, name, strmake( "d$(dlldir)/%s", name )); + add_install_rule( make, module, arch, name, strmake( "d$(dlldir)/%s", name )); output( "%s:", obj_dir_path( make, name )); if (spec_file) output_filename( spec_file ); @@ -3328,18 +3332,19 @@ static void output_module( struct makefile *make, unsigned int arch ) struct strarray all_libs = empty_strarray; struct strarray dep_libs = empty_strarray; struct strarray imports = make->imports; - const char *module_name; + const char *module_name, *module = make->module; const char *debug_file; char *tool, *spec_file = NULL; unsigned int i; if (make->disabled[arch]) return; - if (!make->is_exe) spec_file = src_dir_path( make, replace_extension( make->module, ".dll", ".spec" )); + if (make->module_x64 && !strcmp( archs.str[arch], "x86_64" )) module = make->module_x64; + if (!make->is_exe) spec_file = src_dir_path( make, replace_extension( module, ".dll", ".spec" )); if (!make->data_only) { - module_name = arch_module_name( make->module, arch ); + module_name = arch_module_name( module, arch ); if (!strarray_exists( &make->extradllflags, "-nodefaultlibs" )) default_imports = get_default_imports( make, imports ); @@ -3363,15 +3368,15 @@ static void output_module( struct makefile *make, unsigned int arch ) } } } - else module_name = strmake( "%s%s", arch_pe_dirs[arch], make->module ); + else module_name = strmake( "%s%s", arch_pe_dirs[arch], module ); strarray_add( &make->all_targets[arch], module_name ); if (make->data_only) - add_install_rule( make, make->module, arch, module_name, - strmake( "d$(dlldir)/%s%s", arch_pe_dirs[arch], make->module )); + add_install_rule( make, module, arch, module_name, + strmake( "d$(dlldir)/%s%s", arch_pe_dirs[arch], module )); else - add_install_rule( make, make->module, arch, module_name, - strmake( "%c%s%s%s", '0' + arch, arch_install_dirs[arch], make->module, + add_install_rule( make, module, arch, module_name, + strmake( "%c%s%s%s", '0' + arch, arch_install_dirs[arch], module, arch ? "" : dll_ext )); output( "%s:", obj_dir_path( make, module_name )); @@ -4267,6 +4272,7 @@ static void load_sources( struct makefile *make ) make->parent_dir = get_expanded_make_variable( make, "PARENTSRC" ); make->module = get_expanded_make_variable( make, "MODULE" ); + make->module_x64 = get_expanded_make_variable( make, "MODULE_x64" ); make->testdll = get_expanded_make_variable( make, "TESTDLL" ); make->sharedlib = get_expanded_make_variable( make, "SHAREDLIB" ); make->staticlib = get_expanded_make_variable( make, "STATICLIB" ); @@ -4310,6 +4316,7 @@ static void load_sources( struct makefile *make ) if (make->importlib) strarray_add( &make->install[INSTALL_DEV], make->importlib ); if (make->staticlib) strarray_add( &make->install[INSTALL_DEV], make->staticlib ); else strarray_add( &make->install[INSTALL_LIB], make->module ); + if (make->module_x64) strarray_add( &make->install[INSTALL_LIB], make->module_x64 ); } } From 1f107270f441525dba97c313383a8a7211becbb0 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Mon, 25 Sep 2023 18:23:21 +0100 Subject: [PATCH 2301/2777] rtworkq: Fix leak of thread pool work items. (cherry picked from commit 34319496d83a816bc22005851cce32bd480892af) CW-Bug-Id: #22498 --- dlls/rtworkq/queue.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/dlls/rtworkq/queue.c b/dlls/rtworkq/queue.c index baf648bf771..c088d892f39 100644 --- a/dlls/rtworkq/queue.c +++ b/dlls/rtworkq/queue.c @@ -120,6 +120,13 @@ enum system_queue_index SYS_QUEUE_COUNT, }; +enum work_item_type +{ + WORK_ITEM_WORK, + WORK_ITEM_TIMER, + WORK_ITEM_WAIT, +}; + struct work_item { IUnknown IUnknown_iface; @@ -131,10 +138,11 @@ struct work_item RTWQWORKITEM_KEY key; LONG priority; DWORD flags; - TP_WORK *work_object; PTP_SIMPLE_CALLBACK finalization_callback; + enum work_item_type type; union { + TP_WORK *work_object; TP_WAIT *wait_object; TP_TIMER *timer_object; } u; @@ -389,8 +397,9 @@ static void pool_queue_submit(struct queue *queue, struct work_item *item) we need finalization callback. */ if (item->finalization_callback) IUnknown_AddRef(&item->IUnknown_iface); - item->work_object = CreateThreadpoolWork(standard_queue_worker, item, (TP_CALLBACK_ENVIRON *)&env); - SubmitThreadpoolWork(item->work_object); + item->u.work_object = CreateThreadpoolWork(standard_queue_worker, item, (TP_CALLBACK_ENVIRON *)&env); + item->type = WORK_ITEM_WORK; + SubmitThreadpoolWork(item->u.work_object); TRACE("dispatched %p.\n", item->result); } @@ -551,8 +560,18 @@ static ULONG WINAPI work_item_Release(IUnknown *iface) if (!refcount) { - if (item->work_object) - CloseThreadpoolWork(item->work_object); + switch (item->type) + { + case WORK_ITEM_WORK: + if (item->u.work_object) CloseThreadpoolWork(item->u.work_object); + break; + case WORK_ITEM_WAIT: + if (item->u.wait_object) CloseThreadpoolWait(item->u.wait_object); + break; + case WORK_ITEM_TIMER: + if (item->u.timer_object) CloseThreadpoolTimer(item->u.timer_object); + break; + } if (item->reply_result) IRtwqAsyncResult_Release(item->reply_result); IRtwqAsyncResult_Release(item->result); @@ -816,6 +835,7 @@ static HRESULT queue_submit_wait(struct queue *queue, HANDLE event, LONG priorit item->u.wait_object = CreateThreadpoolWait(callback, item, (TP_CALLBACK_ENVIRON *)&queue->envs[TP_CALLBACK_PRIORITY_NORMAL]); + item->type = WORK_ITEM_WAIT; SetThreadpoolWait(item->u.wait_object, event, NULL); TRACE("dispatched %p.\n", result); @@ -850,6 +870,7 @@ static HRESULT queue_submit_timer(struct queue *queue, IRtwqAsyncResult *result, item->u.timer_object = CreateThreadpoolTimer(callback, item, (TP_CALLBACK_ENVIRON *)&queue->envs[TP_CALLBACK_PRIORITY_NORMAL]); + item->type = WORK_ITEM_TIMER; SetThreadpoolTimer(item->u.timer_object, &filetime, period, 0); TRACE("dispatched %p.\n", result); From 87fbf3305fe733b475a1f907a730f40b4823424b Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 30 May 2023 12:11:51 +0200 Subject: [PATCH 2302/2777] include: Don't align the stack for PE builds. (upstream commit 62173699c38453777c7d5638ed2e779790506b75) CW-Bug-Id: #22660 --- include/msvcrt/corecrt.h | 9 +++------ include/windef.h | 23 +++++++++-------------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/include/msvcrt/corecrt.h b/include/msvcrt/corecrt.h index aba9bc9422e..4ddea3edb1e 100644 --- a/include/msvcrt/corecrt.h +++ b/include/msvcrt/corecrt.h @@ -82,7 +82,7 @@ #define __has_attribute(x) 0 #endif -#ifndef _MSC_VER +#if !defined(_MSC_VER) && !defined(__MINGW32__) # undef __stdcall # ifdef __i386__ # ifdef __GNUC__ @@ -100,16 +100,13 @@ # else # define __stdcall __attribute__((ms_abi)) # endif -# elif defined(__arm__) && defined (__GNUC__) && !defined(__SOFTFP__) && !defined(__MINGW32__) && !defined(__CYGWIN__) +# elif defined(__arm__) && defined (__GNUC__) && !defined(__SOFTFP__) && !defined(__CYGWIN__) # define __stdcall __attribute__((pcs("aapcs-vfp"))) # elif defined(__aarch64__) && defined (__GNUC__) && __has_attribute(ms_abi) # define __stdcall __attribute__((ms_abi)) # else /* __i386__ */ # define __stdcall # endif /* __i386__ */ -#endif /* __stdcall */ - -#ifndef _MSC_VER # undef __cdecl # if defined(__i386__) && defined(__GNUC__) # if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) || defined(__APPLE__) @@ -120,7 +117,7 @@ # else # define __cdecl __stdcall # endif -#endif +#endif /* _MSC_VER || __MINGW32__ */ #if (defined(__x86_64__) || (defined(__aarch64__) && __has_attribute(ms_abi))) && defined (__GNUC__) # include diff --git a/include/windef.h b/include/windef.h index cb7eb1179c8..827e9f92a26 100644 --- a/include/windef.h +++ b/include/windef.h @@ -54,7 +54,7 @@ extern "C" { # endif #endif -#ifndef _MSC_VER +#if !defined(_MSC_VER) && !defined(__MINGW32__) # undef __stdcall # ifdef __i386__ # ifdef __GNUC__ @@ -72,16 +72,13 @@ extern "C" { # else # define __stdcall __attribute__((ms_abi)) # endif -# elif defined(__arm__) && defined (__GNUC__) && !defined(__SOFTFP__) && !defined(__MINGW32__) && !defined(__CYGWIN__) +# elif defined(__arm__) && defined (__GNUC__) && !defined(__SOFTFP__) && !defined(__CYGWIN__) # define __stdcall __attribute__((pcs("aapcs-vfp"))) # elif defined(__aarch64__) && defined (__GNUC__) && __has_attribute(ms_abi) # define __stdcall __attribute__((ms_abi)) # else /* __i386__ */ # define __stdcall # endif /* __i386__ */ -#endif /* __stdcall */ - -#ifndef _MSC_VER # undef __cdecl # if defined(__i386__) && defined(__GNUC__) # if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) || defined(__APPLE__) @@ -92,15 +89,13 @@ extern "C" { # else # define __cdecl __stdcall # endif -#endif - -#if !defined(_MSC_VER) && !defined(__fastcall) -# define __fastcall __stdcall -#endif - -#if (!defined(_MSC_VER) || !defined(__clang__)) && !defined(__thiscall) -# define __thiscall __stdcall -#endif +# ifndef __fastcall +# define __fastcall __stdcall +# endif +# ifndef __thiscall +# define __thiscall __stdcall +# endif +#endif /* _MSC_VER || __MINGW32__ */ #ifndef __ms_va_list # if (defined(__x86_64__) || (defined(__aarch64__) && __has_attribute(ms_abi))) && defined (__GNUC__) From 7f7f1f7707fa71391070a2c6d34e344c6837a77b Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Wed, 20 Sep 2023 14:29:33 +0100 Subject: [PATCH 2303/2777] gdi32: Make GetStockObject hotpatchable. Needed for ntlea. (upstream commit 74027f37311098859b1b279384e79dabb9468546) CW-Bug-Id: #22660 --- dlls/gdi32/objects.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/gdi32/objects.c b/dlls/gdi32/objects.c index 24ac5b015ea..bddc29a3007 100644 --- a/dlls/gdi32/objects.c +++ b/dlls/gdi32/objects.c @@ -418,7 +418,7 @@ HGDIOBJ WINAPI GetCurrentObject( HDC hdc, UINT type ) /*********************************************************************** * GetStockObject (GDI32.@) */ -HGDIOBJ WINAPI GetStockObject( INT obj ) +HGDIOBJ WINAPI DECLSPEC_HOTPATCH GetStockObject( INT obj ) { if (obj < 0 || obj > STOCK_LAST + 1 || obj == 9) return 0; From 1135dee9a4d5d33dc59f9532ebf7f979cd9f2937 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Wed, 20 Sep 2023 14:29:33 +0100 Subject: [PATCH 2304/2777] user32: Make CallWindowProcA hotpatchable. Needed for ntlea. (upstream commit 2508bb83633c7732bab376da2e4d9f8da2a1a00b) CW-Bug-Id: #22660 --- dlls/user32/winproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/user32/winproc.c b/dlls/user32/winproc.c index 9fd35e1d24e..83cc9533fe2 100644 --- a/dlls/user32/winproc.c +++ b/dlls/user32/winproc.c @@ -1251,7 +1251,7 @@ BOOL WINAPI User32CallSendAsyncCallback( const struct send_async_params *params, * * ECMA-234, Win32 */ -LRESULT WINAPI CallWindowProcA( WNDPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) +LRESULT WINAPI DECLSPEC_HOTPATCH CallWindowProcA( WNDPROC func, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { struct win_proc_params params; LRESULT result; From 4fb9230526fa3888f2fad3885d65acafc16715fa Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Wed, 20 Sep 2023 14:29:33 +0100 Subject: [PATCH 2305/2777] user32: Add hotpatchable wrapper for GetWindowLongA. ntlea for some reason expects GetWindowLongA to start with a "push $-2", and will try to skip over this instruction. If we don't anticipate this, it will ended up either skipping over critical instructions, or on a desync address. (upstream commit f9f9481b67f7ecddd7cb5ddd308a9338d26445e4) CW-Bug-Id: #22660 --- dlls/user32/win.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/dlls/user32/win.c b/dlls/user32/win.c index 28cf40441d9..7eaaa41e951 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -888,7 +888,28 @@ WORD WINAPI GetWindowWord( HWND hwnd, INT offset ) /********************************************************************** * GetWindowLongA (USER32.@) */ -LONG WINAPI GetWindowLongA( HWND hwnd, INT offset ) + +#ifdef __i386__ + +/* This wrapper is here to workaround a ntlea quirk. First of all, ntlea + * checks whether GetWindowLongA starts with the Win32 hotpatchable prologue, + * if it can find that, it will use a hooking strategy more difficult for us + * to deal with. Secondly, it assumes what follows the prologue is a `pushl $-2`, + * and will try to skip over this instruction when calling `GetWindowLongA`, + * (i.e. it tries to jump to `GetWindowLongA + 7`, 5 bytes for the prologue, 2 + * bytes for the `pushl`.). We have to anticipate that and make sure the result + * of doing this won't be a messed up stack, or a desynced PC. + */ +__ASM_STDCALL_FUNC( GetWindowLongA, 8, + ".byte 0x8b, 0xff, 0x55, 0x8b, 0xec\n" /* Win32 hotpatchable prologue. */ + "pushl $-2\n" + "addl $4, %esp\n" + "popl %ebp\n" + "jmp " __ASM_STDCALL("get_window_longA", 8) ) +LONG WINAPI get_window_longA( HWND hwnd, INT offset ) +#else +LONG WINAPI DECLSPEC_HOTPATCH GetWindowLongA( HWND hwnd, INT offset ) +#endif { switch (offset) { From 3a142cbedb414ceaf10986058e06230af24eb371 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 27 Sep 2023 20:17:13 -0600 Subject: [PATCH 2306/2777] ntdll: Map EDESTADDRREQ to STATUS_INVALID_CONNECTION. CW-Bug-Id: #22794 --- dlls/ntdll/unix/socket.c | 2 +- dlls/ws2_32/tests/sock.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 32a40570d14..dfbc892be05 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -170,7 +170,7 @@ static NTSTATUS sock_errno_to_status( int err ) case EWOULDBLOCK: return STATUS_DEVICE_NOT_READY; case EALREADY: return STATUS_NETWORK_BUSY; case ENOTSOCK: return STATUS_OBJECT_TYPE_MISMATCH; - case EDESTADDRREQ: return STATUS_INVALID_PARAMETER; + case EDESTADDRREQ: return STATUS_INVALID_CONNECTION; case EMSGSIZE: return STATUS_BUFFER_OVERFLOW; case EPROTONOSUPPORT: case ESOCKTNOSUPPORT: diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index ae582aba406..8dab68b8938 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -13759,7 +13759,7 @@ static void test_connect_udp(void) SetLastError(0xdeadbeef); ret = send(client, "data", 4, 0); ok(ret == -1, "got %d\n", ret); - todo_wine ok(GetLastError() == WSAENOTCONN, "got error %lu\n", GetLastError()); + ok(GetLastError() == WSAENOTCONN, "got error %lu\n", GetLastError()); SetLastError(0xdeadbeef); ret = recv(server, buffer, sizeof(buffer), 0); @@ -13807,7 +13807,7 @@ static void test_connect_udp(void) SetLastError(0xdeadbeef); ret = send(server, "data", 4, 0); ok(ret == -1, "got %d\n", ret); - todo_wine ok(GetLastError() == WSAENOTCONN, "got error %lu\n", GetLastError()); + ok(GetLastError() == WSAENOTCONN, "got error %lu\n", GetLastError()); ret = connect(client, (struct sockaddr *)&addr, sizeof(addr)); ok(!ret, "got error %lu\n", GetLastError()); From c58f5eceba1fd744d9d40ab9eafa1e26e7ef3417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 28 Sep 2023 09:06:28 +0200 Subject: [PATCH 2307/2777] makedep: Track external modules with a dedicated flag. CW-Bug-Id: #22729 --- tools/makedep.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/tools/makedep.c b/tools/makedep.c index 6b02b154e45..9612eae4802 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -205,6 +205,7 @@ struct makefile int is_win16; int is_exe; int has_cxx; + int is_external; int disabled[MAX_ARCHS]; /* values generated at output time */ @@ -1502,7 +1503,7 @@ static struct file *open_include_file( const struct makefile *make, struct incl_ return file; } - if (make->extlib || make->has_cxx) return NULL; /* ignore missing files in external libs */ + if (make->extlib || make->is_external) return NULL; /* ignore missing files in external libs */ fprintf( stderr, "%s:%d: error: ", pFile->included_by->file->name, pFile->included_line ); perror( pFile->name ); @@ -1555,13 +1556,6 @@ static void parse_file( struct makefile *make, struct incl_file *source, int src { struct file *file = src ? open_src_file( make, source ) : open_include_file( make, source ); - if (strendswith( source->name, ".cpp" )) - { - /* ignore missing headers or unsupported includes in .cpp files */ - source->is_external = 1; - make->has_cxx = 1; - } - if (!file) return; source->file = file; @@ -1627,7 +1621,7 @@ static struct incl_file *add_src_file( struct makefile *make, const char *name ) memset( file, 0, sizeof(*file) ); file->name = xstrdup(name); file->use_msvcrt = make->use_msvcrt; - file->is_external = !!make->extlib; + file->is_external = !!make->extlib || make->is_external; list_add_tail( &make->sources, &file->entry ); if (make == include_makefile) { @@ -4552,7 +4546,11 @@ int main( int argc, char *argv[] ) for (i = 0; i < subdirs.count; i++) { submakes[i] = parse_makefile( subdirs.str[i] ); - if (*(tmp = subdirs.str[i]) == '/') tmp = strmake( "dlls%s", strrchr( tmp, '/' ) ); + if (*(tmp = subdirs.str[i]) == '/') + { + tmp = strmake( "dlls%s", strrchr( tmp, '/' ) ); + submakes[i]->is_external = 1; + } submakes[i]->obj_dir = subdirs.str[i] = tmp; } From 87377a5248c21a4dbc16940344817ac1bdf19661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 28 Sep 2023 09:06:55 +0200 Subject: [PATCH 2308/2777] makedep: Avoid linking external modules with -lntdll. They don't have ntdll module source so this won't be translated into ntdll.so path. External modules will have to do that elsewhere. CW-Bug-Id: #22729 --- tools/makedep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/makedep.c b/tools/makedep.c index 9612eae4802..cb85b50960c 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -2140,7 +2140,7 @@ static struct strarray add_unix_libraries( const struct makefile *make, struct s struct strarray all_libs = empty_strarray; unsigned int i, j; - if (strcmp( make->unixlib, "ntdll.so" )) strarray_add( &all_libs, "-lntdll" ); + if (strcmp( make->unixlib, "ntdll.so" ) && !make->is_external) strarray_add( &all_libs, "-lntdll" ); strarray_addall( &all_libs, get_expanded_make_var_array( make, "UNIX_LIBS" )); for (i = 0; i < all_libs.count; i++) From c7862e4f8600bf433e4c34e460eb8a257b8419ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 28 Sep 2023 09:07:45 +0200 Subject: [PATCH 2309/2777] makedep: Correctly link unixlib with C++ sources with g++. CW-Bug-Id: #22729 --- tools/makedep.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/makedep.c b/tools/makedep.c index cb85b50960c..2707e1c77bc 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -3460,7 +3460,8 @@ static void output_unix_lib( struct makefile *make ) output_filenames_obj_dir( make, make->unixobj_files ); output_filenames( unix_deps ); output( "\n" ); - output( "\t%s$(CC) -o $@", cmd_prefix( "CCLD" )); + if (make->has_cxx) output( "\t%s$(CXX) -o $@", cmd_prefix( "CCLD" )); + else output( "\t%s$(CC) -o $@", cmd_prefix( "CCLD" )); output_filenames( get_expanded_make_var_array( make, "UNIXLDFLAGS" )); output_filenames_obj_dir( make, make->unixobj_files ); output_filenames( unix_libs ); From 8acb51613e66989baecd3e4276c0455f5926309b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 28 Sep 2023 09:14:25 +0200 Subject: [PATCH 2310/2777] nsiproxy.sys: Fix compilation warnings. --- dlls/nsiproxy.sys/device.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/nsiproxy.sys/device.c b/dlls/nsiproxy.sys/device.c index 8acdecdb735..9a8b1a5905e 100644 --- a/dlls/nsiproxy.sys/device.c +++ b/dlls/nsiproxy.sys/device.c @@ -19,6 +19,8 @@ */ #include +#include +#include #include "ntstatus.h" #define WIN32_NO_STATUS From 5c4d869e0d87c7ae91fab3ab77eaf37504235441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 28 Sep 2023 17:36:01 +0200 Subject: [PATCH 2311/2777] fixup! win32u: Keep the clipping rectangle inside a fullscreen window. --- dlls/win32u/input.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index c3ee888557a..060ee2e23d6 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2637,6 +2637,7 @@ BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ) */ BOOL WINAPI NtUserClipCursor( const RECT *rect ) { + static int keep_inside_window = -1; HWND foreground = NtUserGetForegroundWindow(); UINT dpi; BOOL ret; @@ -2660,8 +2661,14 @@ BOOL WINAPI NtUserClipCursor( const RECT *rect ) rect = &new_rect; } + if (keep_inside_window == -1) + { + const char *sgi = getenv( "SteamGameId" ); + keep_inside_window = sgi && !strcmp( sgi, "730830" ); /* Escape from Monkey Island */ + } + /* keep the mouse clipped inside of a fullscreen foreground window */ - if (NtUserGetWindowRect( foreground, &full_rect ) && is_window_rect_full_screen( &full_rect )) + if (keep_inside_window && NtUserGetWindowRect( foreground, &full_rect ) && is_window_rect_full_screen( &full_rect )) { full_rect.left = max( full_rect.left, min( full_rect.right - 1, rect->left ) ); full_rect.right = max( full_rect.left, min( full_rect.right - 1, rect->right ) ); From fbf9cf6ebadc7d50c8fb7a130851c3658607b343 Mon Sep 17 00:00:00 2001 From: Jiajin Cui Date: Wed, 21 Jun 2023 17:53:52 +0800 Subject: [PATCH 2312/2777] shell32: Make sure wcmd has enough space to hold the string. If the length of wszApplicationName exceeds 1024, it will cause an error when writing to the subsequent stack space after exceeding the wcmd space, Wcmd needs to be modified to dynamic allocation. Signed-off-by: Jiajin Cui (cherry picked from commit eee640c93874317ab3ff62ca6afda962ac96d999) CW-Bug-Id: #22797 --- dlls/shell32/shlexec.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index 411d0c691a3..bc3f2ceabb4 100644 --- a/dlls/shell32/shlexec.c +++ b/dlls/shell32/shlexec.c @@ -1764,6 +1764,14 @@ static BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) TRACE("execute:%s,%s,%s\n", debugstr_w(wszApplicationName), debugstr_w(wszParameters), debugstr_w(wszDir)); lpFile = sei_tmp.lpFile; wcmd = wcmdBuffer; + len = lstrlenW(wszApplicationName) + 3; + if (sei_tmp.lpParameters[0]) + len += 1 + lstrlenW(wszParameters); + if (len > wcmdLen) + { + wcmd = heap_alloc(len * sizeof(WCHAR)); + wcmdLen = len; + } lstrcpyW(wcmd, wszApplicationName); if (sei_tmp.lpDirectory) { From 9b73e3df90970c7784f18da259606440ecea14e4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 28 Sep 2023 19:29:03 -0600 Subject: [PATCH 2313/2777] shell32: Avoid stack corruption with long name in SHELL_TryAppPathW(). CW-Bug-Id: #22797 --- dlls/shell32/shlexec.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index bc3f2ceabb4..099343334c3 100644 --- a/dlls/shell32/shlexec.c +++ b/dlls/shell32/shlexec.c @@ -428,8 +428,14 @@ static BOOL SHELL_TryAppPathW( LPCWSTR szName, LPWSTR lpResult, WCHAR **env) BOOL found = FALSE; if (env) *env = NULL; - lstrcpyW(buffer, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\"); - lstrcatW(buffer, szName); + wcscpy(buffer, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\"); + if (wcslen(buffer) + wcslen(szName) + 1 > ARRAY_SIZE(buffer)) + { + WARN("Name is too big.\n"); + return FALSE; + } + + wcscat(buffer, szName); res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buffer, 0, KEY_READ, &hkApp); if (res) goto end; From 3f3a500f1d8dc5099a7ef593e03f792c6b29599b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 28 Sep 2023 19:23:41 -0600 Subject: [PATCH 2314/2777] shell32: Handle long command line in execute_from_key(). CW-Bug-Id: #22797 --- dlls/shell32/shlexec.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index 099343334c3..2d1830ad838 100644 --- a/dlls/shell32/shlexec.c +++ b/dlls/shell32/shlexec.c @@ -965,7 +965,7 @@ static UINT_PTR execute_from_key(LPCWSTR key, LPCWSTR lpFile, WCHAR *env, LPCWST SHELL_ExecuteW32 execfunc, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out) { - WCHAR cmd[256], param[1024], ddeexec[256]; + WCHAR cmd[256], parambuffer[1024], ddeexec[256], *param = parambuffer; LONG cmdlen = sizeof(cmd), ddeexeclen = sizeof(ddeexec); UINT_PTR retval = SE_ERR_NOASSOC; DWORD resultLen; @@ -987,9 +987,14 @@ static UINT_PTR execute_from_key(LPCWSTR key, LPCWSTR lpFile, WCHAR *env, LPCWST if (cmdlen >= ARRAY_SIZE(cmd)) cmdlen = ARRAY_SIZE(cmd) - 1; cmd[cmdlen] = '\0'; - SHELL_ArgifyW(param, ARRAY_SIZE(param), cmd, lpFile, psei->lpIDList, szCommandline, &resultLen); - if (resultLen > ARRAY_SIZE(param)) - ERR("Argify buffer not large enough, truncating\n"); + SHELL_ArgifyW(param, ARRAY_SIZE(parambuffer), cmd, lpFile, psei->lpIDList, szCommandline, &resultLen); + if (resultLen > ARRAY_SIZE(parambuffer)) + { + if ((param = malloc(resultLen * sizeof(*param)))) + SHELL_ArgifyW(param, resultLen, cmd, lpFile, psei->lpIDList, szCommandline, &resultLen); + else + ERR("No memory."); + } } /* Get the parameters needed by the application @@ -1012,6 +1017,7 @@ static UINT_PTR execute_from_key(LPCWSTR key, LPCWSTR lpFile, WCHAR *env, LPCWST else WARN("Nothing appropriate found for %s\n", debugstr_w(key)); + if (param != parambuffer) free(param); return retval; } From ff75f2ab3c10d509f930e2ade063386d8186240a Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Fri, 29 Sep 2023 16:39:51 +0100 Subject: [PATCH 2315/2777] Revert "include: Don't align the stack for PE builds." This reverts commit 87fbf3305fe733b475a1f907a730f40b4823424b. We saw hangs in Phasmophobia with the commit, and then discovered this commit is not strictly necessary for ntlea, so we revert it. --- include/msvcrt/corecrt.h | 9 ++++++--- include/windef.h | 23 ++++++++++++++--------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/include/msvcrt/corecrt.h b/include/msvcrt/corecrt.h index 4ddea3edb1e..aba9bc9422e 100644 --- a/include/msvcrt/corecrt.h +++ b/include/msvcrt/corecrt.h @@ -82,7 +82,7 @@ #define __has_attribute(x) 0 #endif -#if !defined(_MSC_VER) && !defined(__MINGW32__) +#ifndef _MSC_VER # undef __stdcall # ifdef __i386__ # ifdef __GNUC__ @@ -100,13 +100,16 @@ # else # define __stdcall __attribute__((ms_abi)) # endif -# elif defined(__arm__) && defined (__GNUC__) && !defined(__SOFTFP__) && !defined(__CYGWIN__) +# elif defined(__arm__) && defined (__GNUC__) && !defined(__SOFTFP__) && !defined(__MINGW32__) && !defined(__CYGWIN__) # define __stdcall __attribute__((pcs("aapcs-vfp"))) # elif defined(__aarch64__) && defined (__GNUC__) && __has_attribute(ms_abi) # define __stdcall __attribute__((ms_abi)) # else /* __i386__ */ # define __stdcall # endif /* __i386__ */ +#endif /* __stdcall */ + +#ifndef _MSC_VER # undef __cdecl # if defined(__i386__) && defined(__GNUC__) # if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) || defined(__APPLE__) @@ -117,7 +120,7 @@ # else # define __cdecl __stdcall # endif -#endif /* _MSC_VER || __MINGW32__ */ +#endif #if (defined(__x86_64__) || (defined(__aarch64__) && __has_attribute(ms_abi))) && defined (__GNUC__) # include diff --git a/include/windef.h b/include/windef.h index 827e9f92a26..cb7eb1179c8 100644 --- a/include/windef.h +++ b/include/windef.h @@ -54,7 +54,7 @@ extern "C" { # endif #endif -#if !defined(_MSC_VER) && !defined(__MINGW32__) +#ifndef _MSC_VER # undef __stdcall # ifdef __i386__ # ifdef __GNUC__ @@ -72,13 +72,16 @@ extern "C" { # else # define __stdcall __attribute__((ms_abi)) # endif -# elif defined(__arm__) && defined (__GNUC__) && !defined(__SOFTFP__) && !defined(__CYGWIN__) +# elif defined(__arm__) && defined (__GNUC__) && !defined(__SOFTFP__) && !defined(__MINGW32__) && !defined(__CYGWIN__) # define __stdcall __attribute__((pcs("aapcs-vfp"))) # elif defined(__aarch64__) && defined (__GNUC__) && __has_attribute(ms_abi) # define __stdcall __attribute__((ms_abi)) # else /* __i386__ */ # define __stdcall # endif /* __i386__ */ +#endif /* __stdcall */ + +#ifndef _MSC_VER # undef __cdecl # if defined(__i386__) && defined(__GNUC__) # if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) || defined(__APPLE__) @@ -89,13 +92,15 @@ extern "C" { # else # define __cdecl __stdcall # endif -# ifndef __fastcall -# define __fastcall __stdcall -# endif -# ifndef __thiscall -# define __thiscall __stdcall -# endif -#endif /* _MSC_VER || __MINGW32__ */ +#endif + +#if !defined(_MSC_VER) && !defined(__fastcall) +# define __fastcall __stdcall +#endif + +#if (!defined(_MSC_VER) || !defined(__clang__)) && !defined(__thiscall) +# define __thiscall __stdcall +#endif #ifndef __ms_va_list # if (defined(__x86_64__) || (defined(__aarch64__) && __has_attribute(ms_abi))) && defined (__GNUC__) From ea95125cf60ec539c8a613e9a5baef3a861f6074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 7 Jun 2023 16:24:20 +0200 Subject: [PATCH 2316/2777] mf/session: Use local variables to access transform node streams. (cherry picked from commit b3e4a52fcc750f4b2900c71665ccdefe378ff342) CW-Bug-Id: #21713 --- dlls/mf/session.c | 48 +++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 25e1c474b44..a31a8110f37 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -3139,6 +3139,8 @@ static HRESULT transform_node_pull_samples(const struct media_session *session, /* Collect returned samples for all streams. */ for (i = 0; i < node->u.transform.output_count; ++i) { + struct transform_stream *stream = &node->u.transform.outputs[i]; + if (buffers[i].pEvents) IMFCollection_Release(buffers[i].pEvents); @@ -3148,7 +3150,7 @@ static HRESULT transform_node_pull_samples(const struct media_session *session, IMFQualityManager_NotifyProcessOutput(session->quality_manager, node->node, i, buffers[i].pSample); queued_sample = transform_create_sample(buffers[i].pSample); - list_add_tail(&node->u.transform.outputs[i].samples, &queued_sample->entry); + list_add_tail(&stream->samples, &queued_sample->entry); } if (buffers[i].pSample) @@ -3200,17 +3202,21 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop } break; case MF_TOPOLOGY_TRANSFORM_NODE: + { + struct transform_stream *input_stream = &topo_node->u.transform.inputs[input]; transform_node_pull_samples(session, topo_node); sample_entry = transform_create_sample(sample); - list_add_tail(&topo_node->u.transform.inputs[input].samples, &sample_entry->entry); + list_add_tail(&input_stream->samples, &sample_entry->entry); for (i = 0; i < topo_node->u.transform.input_count; ++i) { + struct transform_stream *stream = &topo_node->u.transform.inputs[i]; + stream_id = transform_node_get_stream_id(topo_node, FALSE, i); - LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.inputs[i].samples, - struct sample, entry) + + LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &stream->samples, struct sample, entry) { if (sample_entry->sample) { @@ -3223,7 +3229,7 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop } else { - transform_stream_drop_samples(&topo_node->u.transform.inputs[i]); + transform_stream_drop_samples(stream); drain = TRUE; } } @@ -3242,28 +3248,32 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop { for (i = 0; i < topo_node->u.transform.output_count; ++i) { - if ((sample_entry = transform_create_sample(NULL))) - list_add_tail(&topo_node->u.transform.outputs[i].samples, &sample_entry->entry); + struct transform_stream *stream = &topo_node->u.transform.outputs[i]; + + if ((sample_entry = transform_create_sample(NULL))) + list_add_tail(&stream->samples, &sample_entry->entry); } } /* Push down all available output. */ for (i = 0; i < topo_node->u.transform.output_count; ++i) { + struct transform_stream *stream = &topo_node->u.transform.outputs[i]; + if (FAILED(IMFTopologyNode_GetOutput(node, i, &downstream_node, &downstream_input))) { WARN("Failed to get connected node for output %u.\n", i); continue; } - LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.outputs[i].samples, + LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &stream->samples, struct sample, entry) { - if (!topo_node->u.transform.outputs[i].requests) + if (!stream->requests) break; session_deliver_sample_to_node(session, downstream_node, downstream_input, sample_entry->sample); - topo_node->u.transform.outputs[i].requests--; + stream->requests--; transform_release_sample(sample_entry); } @@ -3272,6 +3282,7 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop } break; + } case MF_TOPOLOGY_TEE_NODE: FIXME("Unhandled downstream node type %d.\n", node_type); break; @@ -3304,20 +3315,22 @@ static void session_deliver_pending_samples(struct media_session *session, IMFTo /* Push down all available output. */ for (i = 0; i < topo_node->u.transform.output_count; ++i) { + struct transform_stream *stream = &topo_node->u.transform.outputs[i]; + if (FAILED(IMFTopologyNode_GetOutput(node, i, &downstream_node, &downstream_input))) { WARN("Failed to get connected node for output %u.\n", i); continue; } - LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &topo_node->u.transform.outputs[i].samples, + LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &stream->samples, struct sample, entry) { - if (!topo_node->u.transform.outputs[i].requests) + if (!stream->requests) break; session_deliver_sample_to_node(session, downstream_node, downstream_input, sample_entry->sample); - topo_node->u.transform.outputs[i].requests--; + stream->requests--; transform_release_sample(sample_entry); } @@ -3353,14 +3366,16 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I WARN("Sample request failed, hr %#lx.\n", hr); break; case MF_TOPOLOGY_TRANSFORM_NODE: + { + struct transform_stream *stream = &topo_node->u.transform.outputs[output]; - if (list_empty(&topo_node->u.transform.outputs[output].samples)) + if (list_empty(&stream->samples)) { /* Forward request to upstream node. */ if (SUCCEEDED(hr = IMFTopologyNode_GetInput(node, 0 /* FIXME */, &upstream_node, &upstream_output))) { if (SUCCEEDED(hr = session_request_sample_from_node(session, upstream_node, upstream_output))) - topo_node->u.transform.outputs[output].requests++; + stream->requests++; IMFTopologyNode_Release(upstream_node); } } @@ -3368,7 +3383,7 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I { if (SUCCEEDED(hr = IMFTopologyNode_GetOutput(node, output, &downstream_node, &downstream_input))) { - sample = LIST_ENTRY(list_head(&topo_node->u.transform.outputs[output].samples), struct sample, entry); + sample = LIST_ENTRY(list_head(&stream->samples), struct sample, entry); session_deliver_sample_to_node(session, downstream_node, downstream_input, sample->sample); transform_release_sample(sample); IMFTopologyNode_Release(downstream_node); @@ -3376,6 +3391,7 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I } break; + } case MF_TOPOLOGY_TEE_NODE: FIXME("Unhandled upstream node type %d.\n", node_type); default: From 86294623c0a0b37bf7bded04adcb7abd2722e586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 4 Jul 2023 09:30:26 +0200 Subject: [PATCH 2317/2777] mf/session: Use a helper to deliver transform node requested samples. (cherry picked from commit 46743a0546d381d65346de65c0ad7e64a2fd50f3) CW-Bug-Id: #21713 --- dlls/mf/session.c | 98 +++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 59 deletions(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index a31a8110f37..bf338dee3a2 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -3162,12 +3162,47 @@ static HRESULT transform_node_pull_samples(const struct media_session *session, return hr; } +static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input, + IMFSample *sample); + +static void transform_node_deliver_samples(struct media_session *session, struct topo_node *topo_node) +{ + IMFTopologyNode *up_node = topo_node->node, *down_node; + struct sample *sample, *next; + DWORD output, input; + HRESULT hr; + + /* Push down all available output. */ + for (output = 0; output < topo_node->u.transform.output_count; ++output) + { + struct transform_stream *stream = &topo_node->u.transform.outputs[output]; + + if (FAILED(hr = IMFTopologyNode_GetOutput(up_node, output, &down_node, &input))) + { + WARN("Failed to node %p/%lu output, hr %#lx.\n", up_node, output, hr); + continue; + } + + LIST_FOR_EACH_ENTRY_SAFE(sample, next, &stream->samples, struct sample, entry) + { + if (!stream->requests) + break; + + session_deliver_sample_to_node(session, down_node, input, sample->sample); + stream->requests--; + + transform_release_sample(sample); + } + + IMFTopologyNode_Release(down_node); + } +} + static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input, IMFSample *sample) { struct sample *sample_entry, *sample_entry2; - DWORD stream_id, downstream_input; - IMFTopologyNode *downstream_node; + DWORD stream_id; struct topo_node *topo_node; MF_TOPOLOGY_TYPE node_type; BOOL drain = FALSE; @@ -3255,32 +3290,7 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop } } - /* Push down all available output. */ - for (i = 0; i < topo_node->u.transform.output_count; ++i) - { - struct transform_stream *stream = &topo_node->u.transform.outputs[i]; - - if (FAILED(IMFTopologyNode_GetOutput(node, i, &downstream_node, &downstream_input))) - { - WARN("Failed to get connected node for output %u.\n", i); - continue; - } - - LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &stream->samples, - struct sample, entry) - { - if (!stream->requests) - break; - - session_deliver_sample_to_node(session, downstream_node, downstream_input, sample_entry->sample); - stream->requests--; - - transform_release_sample(sample_entry); - } - - IMFTopologyNode_Release(downstream_node); - } - + transform_node_deliver_samples(session, topo_node); break; } case MF_TOPOLOGY_TEE_NODE: @@ -3293,13 +3303,9 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop static void session_deliver_pending_samples(struct media_session *session, IMFTopologyNode *node) { - struct sample *sample_entry, *sample_entry2; - IMFTopologyNode *downstream_node; struct topo_node *topo_node; MF_TOPOLOGY_TYPE node_type; - DWORD downstream_input; TOPOID node_id; - unsigned int i; IMFTopologyNode_GetNodeType(node, &node_type); IMFTopologyNode_GetTopoNodeID(node, &node_id); @@ -3309,34 +3315,8 @@ static void session_deliver_pending_samples(struct media_session *session, IMFTo switch (node_type) { case MF_TOPOLOGY_TRANSFORM_NODE: - transform_node_pull_samples(session, topo_node); - - /* Push down all available output. */ - for (i = 0; i < topo_node->u.transform.output_count; ++i) - { - struct transform_stream *stream = &topo_node->u.transform.outputs[i]; - - if (FAILED(IMFTopologyNode_GetOutput(node, i, &downstream_node, &downstream_input))) - { - WARN("Failed to get connected node for output %u.\n", i); - continue; - } - - LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &stream->samples, - struct sample, entry) - { - if (!stream->requests) - break; - - session_deliver_sample_to_node(session, downstream_node, downstream_input, sample_entry->sample); - stream->requests--; - - transform_release_sample(sample_entry); - } - - IMFTopologyNode_Release(downstream_node); - } + transform_node_deliver_samples(session, topo_node); break; default: FIXME("Unexpected node type %u.\n", node_type); From 277b89688aed1e44cd3a39b87c722b9f968c50eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 6 Jul 2023 10:59:40 +0200 Subject: [PATCH 2318/2777] mf/session: Drain transform node input streams individually. (cherry picked from commit 6946c761bf0a043b1c777b39311addc5f66859e6) CW-Bug-Id: #21713 --- dlls/mf/session.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index bf338dee3a2..aa496494a01 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -3266,16 +3266,14 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop { transform_stream_drop_samples(stream); drain = TRUE; + + if (FAILED(hr = IMFTransform_ProcessMessage(topo_node->object.transform, + MFT_MESSAGE_COMMAND_DRAIN, stream_id))) + WARN("Drain command failed for transform, hr %#lx.\n", hr); } } } - if (drain) - { - if (FAILED(hr = IMFTransform_ProcessMessage(topo_node->object.transform, MFT_MESSAGE_COMMAND_DRAIN, 0))) - WARN("Drain command failed for transform, hr %#lx.\n", hr); - } - transform_node_pull_samples(session, topo_node); /* Remaining unprocessed input has been discarded, now queue markers for every output. */ From 4148e4f7384f107782c41ca907c80389ab618abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 8 Aug 2023 11:39:43 +0200 Subject: [PATCH 2319/2777] mf/session: Drain remaining requests in transform_node_deliver_samples. (cherry picked from commit b60db1693e91c01f8055b56cd595cb04c6c3c54c) CW-Bug-Id: #21713 --- dlls/mf/session.c | 55 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index aa496494a01..ff2f70f29aa 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -155,6 +155,7 @@ struct transform_stream struct list samples; unsigned int requests; unsigned int min_buffer_size; + BOOL draining; }; enum topo_node_flags @@ -892,7 +893,9 @@ static HRESULT session_subscribe_sources(struct media_session *session) static void session_start(struct media_session *session, const GUID *time_format, const PROPVARIANT *start_position) { struct media_source *source; + struct topo_node *topo_node; HRESULT hr; + UINT i; switch (session->state) { @@ -928,6 +931,18 @@ static void session_start(struct media_session *session, const GUID *time_format } } + LIST_FOR_EACH_ENTRY(topo_node, &session->presentation.nodes, struct topo_node, entry) + { + if (topo_node->type == MF_TOPOLOGY_TRANSFORM_NODE) + { + for (i = 0; i < topo_node->u.transform.input_count; i++) + { + struct transform_stream *stream = &topo_node->u.transform.inputs[i]; + stream->draining = FALSE; + } + } + } + session->state = SESSION_STATE_STARTING_SOURCES; break; case SESSION_STATE_STARTED: @@ -3162,12 +3177,27 @@ static HRESULT transform_node_pull_samples(const struct media_session *session, return hr; } +static BOOL transform_node_is_drained(struct topo_node *topo_node) +{ + UINT i; + + for (i = 0; i < topo_node->u.transform.input_count; i++) + { + struct transform_stream *stream = &topo_node->u.transform.inputs[i]; + if (!stream->draining) + return FALSE; + } + + return TRUE; +} + static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input, IMFSample *sample); static void transform_node_deliver_samples(struct media_session *session, struct topo_node *topo_node) { IMFTopologyNode *up_node = topo_node->node, *down_node; + BOOL drained = transform_node_is_drained(topo_node); struct sample *sample, *next; DWORD output, input; HRESULT hr; @@ -3194,6 +3224,12 @@ static void transform_node_deliver_samples(struct media_session *session, struct transform_release_sample(sample); } + while (stream->requests && drained) + { + session_deliver_sample_to_node(session, down_node, input, NULL); + stream->requests--; + } + IMFTopologyNode_Release(down_node); } } @@ -3205,7 +3241,6 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop DWORD stream_id; struct topo_node *topo_node; MF_TOPOLOGY_TYPE node_type; - BOOL drain = FALSE; TOPOID node_id; unsigned int i; HRESULT hr; @@ -3264,30 +3299,16 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop } else { - transform_stream_drop_samples(stream); - drain = TRUE; - if (FAILED(hr = IMFTransform_ProcessMessage(topo_node->object.transform, MFT_MESSAGE_COMMAND_DRAIN, stream_id))) WARN("Drain command failed for transform, hr %#lx.\n", hr); + else + stream->draining = TRUE; } } } transform_node_pull_samples(session, topo_node); - - /* Remaining unprocessed input has been discarded, now queue markers for every output. */ - if (drain) - { - for (i = 0; i < topo_node->u.transform.output_count; ++i) - { - struct transform_stream *stream = &topo_node->u.transform.outputs[i]; - - if ((sample_entry = transform_create_sample(NULL))) - list_add_tail(&stream->samples, &sample_entry->entry); - } - } - transform_node_deliver_samples(session, topo_node); break; } From ff7ca2da72637f7917ffc7e77c2b203dc65c6f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 8 Aug 2023 11:32:44 +0200 Subject: [PATCH 2320/2777] mf/session: Use helpers to push and pop samples for transform streams. (cherry picked from commit 5d5134927652ca0fc07dd57f9aeb433a25dd3986) CW-Bug-Id: #21713 --- dlls/mf/session.c | 80 ++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index ff2f70f29aa..3dab2f3bd24 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -681,12 +681,41 @@ static void transform_release_sample(struct sample *sample) free(sample); } +static HRESULT transform_stream_push_sample(struct transform_stream *stream, IMFSample *sample) +{ + struct sample *entry; + + if (!(entry = calloc(1, sizeof(*entry)))) + return E_OUTOFMEMORY; + + entry->sample = sample; + IMFSample_AddRef(entry->sample); + + list_add_tail(&stream->samples, &entry->entry); + return S_OK; +} + +static HRESULT transform_stream_pop_sample(struct transform_stream *stream, IMFSample **sample) +{ + struct sample *entry; + struct list *ptr; + + if (!(ptr = list_head(&stream->samples))) + return E_FAIL; + + entry = LIST_ENTRY(ptr, struct sample, entry); + list_remove(&entry->entry); + *sample = entry->sample; + free(entry); + return S_OK; +} + static void transform_stream_drop_samples(struct transform_stream *stream) { - struct sample *sample, *sample2; + IMFSample *sample; - LIST_FOR_EACH_ENTRY_SAFE(sample, sample2, &stream->samples, struct sample, entry) - transform_release_sample(sample); + while (SUCCEEDED(transform_stream_pop_sample(stream, &sample))) + IMFSample_Release(sample); } static void release_topo_node(struct topo_node *node) @@ -3060,20 +3089,6 @@ static void session_set_sink_stream_state(struct media_session *session, IMFStre } } -static struct sample *transform_create_sample(IMFSample *sample) -{ - struct sample *sample_entry = calloc(1, sizeof(*sample_entry)); - - if (sample_entry) - { - sample_entry->sample = sample; - if (sample_entry->sample) - IMFSample_AddRef(sample_entry->sample); - } - - return sample_entry; -} - static HRESULT transform_get_external_output_sample(const struct media_session *session, struct topo_node *transform, unsigned int output_index, const MFT_OUTPUT_STREAM_INFO *stream_info, IMFSample **sample) { @@ -3122,7 +3137,6 @@ static HRESULT transform_node_pull_samples(const struct media_session *session, { MFT_OUTPUT_STREAM_INFO stream_info; MFT_OUTPUT_DATA_BUFFER *buffers; - struct sample *queued_sample; HRESULT hr = E_UNEXPECTED; DWORD status = 0; unsigned int i; @@ -3163,9 +3177,8 @@ static HRESULT transform_node_pull_samples(const struct media_session *session, { if (session->quality_manager) IMFQualityManager_NotifyProcessOutput(session->quality_manager, node->node, i, buffers[i].pSample); - - queued_sample = transform_create_sample(buffers[i].pSample); - list_add_tail(&stream->samples, &queued_sample->entry); + if (FAILED(hr = transform_stream_push_sample(stream, buffers[i].pSample))) + WARN("Failed to queue output sample, hr %#lx\n", hr); } if (buffers[i].pSample) @@ -3198,8 +3211,8 @@ static void transform_node_deliver_samples(struct media_session *session, struct { IMFTopologyNode *up_node = topo_node->node, *down_node; BOOL drained = transform_node_is_drained(topo_node); - struct sample *sample, *next; DWORD output, input; + IMFSample *sample; HRESULT hr; /* Push down all available output. */ @@ -3213,15 +3226,11 @@ static void transform_node_deliver_samples(struct media_session *session, struct continue; } - LIST_FOR_EACH_ENTRY_SAFE(sample, next, &stream->samples, struct sample, entry) + while (stream->requests && SUCCEEDED(hr = transform_stream_pop_sample(stream, &sample))) { - if (!stream->requests) - break; - - session_deliver_sample_to_node(session, down_node, input, sample->sample); + session_deliver_sample_to_node(session, down_node, input, sample); stream->requests--; - - transform_release_sample(sample); + IMFSample_Release(sample); } while (stream->requests && drained) @@ -3277,8 +3286,7 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop transform_node_pull_samples(session, topo_node); - sample_entry = transform_create_sample(sample); - list_add_tail(&input_stream->samples, &sample_entry->entry); + transform_stream_push_sample(input_stream, sample); for (i = 0; i < topo_node->u.transform.input_count; ++i) { @@ -3349,7 +3357,7 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I DWORD downstream_input, upstream_output; struct topo_node *topo_node; MF_TOPOLOGY_TYPE node_type; - struct sample *sample; + IMFSample *sample; TOPOID node_id; HRESULT hr; @@ -3368,7 +3376,7 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I { struct transform_stream *stream = &topo_node->u.transform.outputs[output]; - if (list_empty(&stream->samples)) + if (FAILED(hr = transform_stream_pop_sample(stream, &sample))) { /* Forward request to upstream node. */ if (SUCCEEDED(hr = IMFTopologyNode_GetInput(node, 0 /* FIXME */, &upstream_node, &upstream_output))) @@ -3382,11 +3390,11 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I { if (SUCCEEDED(hr = IMFTopologyNode_GetOutput(node, output, &downstream_node, &downstream_input))) { - sample = LIST_ENTRY(list_head(&stream->samples), struct sample, entry); - session_deliver_sample_to_node(session, downstream_node, downstream_input, sample->sample); - transform_release_sample(sample); + session_deliver_sample_to_node(session, downstream_node, downstream_input, sample); IMFTopologyNode_Release(downstream_node); } + + IMFSample_Release(sample); } break; From eca73348c4ddd70eff68edfcdf2e8290376162b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 8 Aug 2023 11:41:13 +0200 Subject: [PATCH 2321/2777] mf/session: Push transform input samples directly to ProcessInput. (cherry picked from commit 986d82d147040a1e4e513d6a04283a71881f1279) CW-Bug-Id: #21713 --- dlls/mf/session.c | 74 +++++++++++++++++------------------------------ 1 file changed, 27 insertions(+), 47 deletions(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 3dab2f3bd24..6770cf8bbbf 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -673,14 +673,6 @@ static void session_set_caps(struct media_session *session, DWORD caps) IMFMediaEvent_Release(event); } -static void transform_release_sample(struct sample *sample) -{ - list_remove(&sample->entry); - if (sample->sample) - IMFSample_Release(sample->sample); - free(sample); -} - static HRESULT transform_stream_push_sample(struct transform_stream *stream, IMFSample *sample) { struct sample *entry; @@ -3204,6 +3196,31 @@ static BOOL transform_node_is_drained(struct topo_node *topo_node) return TRUE; } +static HRESULT transform_node_push_sample(const struct media_session *session, struct topo_node *topo_node, + UINT input, IMFSample *sample) +{ + struct transform_stream *stream = &topo_node->u.transform.inputs[input]; + UINT id = transform_node_get_stream_id(topo_node, FALSE, input); + IMFTransform *transform = topo_node->object.transform; + HRESULT hr; + + if (sample) + { + hr = IMFTransform_ProcessInput(transform, id, sample, 0); + if (hr == MF_E_NOTACCEPTING) + hr = transform_stream_push_sample(stream, sample); + } + else + { + if (FAILED(hr = IMFTransform_ProcessMessage(transform, MFT_MESSAGE_COMMAND_DRAIN, id))) + WARN("Drain command failed for transform, hr %#lx.\n", hr); + else + stream->draining = TRUE; + } + + return hr; +} + static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input, IMFSample *sample); @@ -3246,12 +3263,9 @@ static void transform_node_deliver_samples(struct media_session *session, struct static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input, IMFSample *sample) { - struct sample *sample_entry, *sample_entry2; - DWORD stream_id; struct topo_node *topo_node; MF_TOPOLOGY_TYPE node_type; TOPOID node_id; - unsigned int i; HRESULT hr; if (session->quality_manager) @@ -3281,45 +3295,11 @@ static void session_deliver_sample_to_node(struct media_session *session, IMFTop } break; case MF_TOPOLOGY_TRANSFORM_NODE: - { - struct transform_stream *input_stream = &topo_node->u.transform.inputs[input]; - - transform_node_pull_samples(session, topo_node); - - transform_stream_push_sample(input_stream, sample); - - for (i = 0; i < topo_node->u.transform.input_count; ++i) - { - struct transform_stream *stream = &topo_node->u.transform.inputs[i]; - - stream_id = transform_node_get_stream_id(topo_node, FALSE, i); - - LIST_FOR_EACH_ENTRY_SAFE(sample_entry, sample_entry2, &stream->samples, struct sample, entry) - { - if (sample_entry->sample) - { - if ((hr = IMFTransform_ProcessInput(topo_node->object.transform, stream_id, - sample_entry->sample, 0)) == MF_E_NOTACCEPTING) - break; - if (FAILED(hr)) - WARN("Failed to process input for stream %u/%lu, hr %#lx.\n", i, stream_id, hr); - transform_release_sample(sample_entry); - } - else - { - if (FAILED(hr = IMFTransform_ProcessMessage(topo_node->object.transform, - MFT_MESSAGE_COMMAND_DRAIN, stream_id))) - WARN("Drain command failed for transform, hr %#lx.\n", hr); - else - stream->draining = TRUE; - } - } - } - + if (FAILED(hr = transform_node_push_sample(session, topo_node, input, sample))) + WARN("Failed to push or queue sample to transform, hr %#lx\n", hr); transform_node_pull_samples(session, topo_node); transform_node_deliver_samples(session, topo_node); break; - } case MF_TOPOLOGY_TEE_NODE: FIXME("Unhandled downstream node type %d.\n", node_type); break; From 605f02cd23332cdaac7da539212a4b828a64399f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 4 Jul 2023 10:15:18 +0200 Subject: [PATCH 2322/2777] mf/session: Request more samples from upstream when necessary. (cherry picked from commit 4d30ce831e7a17a8de9a19caa04bee67ae7dc8db) CW-Bug-Id: #21713 --- dlls/mf/session.c | 48 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 6770cf8bbbf..39d6c764a50 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -200,6 +200,7 @@ struct topo_node struct transform_stream *inputs; DWORD *input_map; unsigned int input_count; + unsigned int next_input; struct transform_stream *outputs; DWORD *output_map; @@ -693,7 +694,7 @@ static HRESULT transform_stream_pop_sample(struct transform_stream *stream, IMFS struct list *ptr; if (!(ptr = list_head(&stream->samples))) - return E_FAIL; + return MF_E_TRANSFORM_NEED_MORE_INPUT; entry = LIST_ENTRY(ptr, struct sample, entry); list_remove(&entry->entry); @@ -3196,6 +3197,17 @@ static BOOL transform_node_is_drained(struct topo_node *topo_node) return TRUE; } +static BOOL transform_node_has_requests(struct topo_node *topo_node) +{ + UINT i; + + for (i = 0; i < topo_node->u.transform.output_count; i++) + if (topo_node->u.transform.outputs[i].requests) + return TRUE; + + return FALSE; +} + static HRESULT transform_node_push_sample(const struct media_session *session, struct topo_node *topo_node, UINT input, IMFSample *sample) { @@ -3230,10 +3242,10 @@ static void transform_node_deliver_samples(struct media_session *session, struct BOOL drained = transform_node_is_drained(topo_node); DWORD output, input; IMFSample *sample; - HRESULT hr; + HRESULT hr = S_OK; /* Push down all available output. */ - for (output = 0; output < topo_node->u.transform.output_count; ++output) + for (output = 0; SUCCEEDED(hr) && output < topo_node->u.transform.output_count; ++output) { struct transform_stream *stream = &topo_node->u.transform.outputs[output]; @@ -3243,8 +3255,17 @@ static void transform_node_deliver_samples(struct media_session *session, struct continue; } - while (stream->requests && SUCCEEDED(hr = transform_stream_pop_sample(stream, &sample))) + while (stream->requests) { + if (FAILED(hr = transform_stream_pop_sample(stream, &sample))) + { + /* try getting more samples by calling IMFTransform_ProcessOutput */ + if (FAILED(hr = transform_node_pull_samples(session, topo_node))) + break; + if (FAILED(hr = transform_stream_pop_sample(stream, &sample))) + break; + } + session_deliver_sample_to_node(session, down_node, input, sample); stream->requests--; IMFSample_Release(sample); @@ -3258,6 +3279,25 @@ static void transform_node_deliver_samples(struct media_session *session, struct IMFTopologyNode_Release(down_node); } + + if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT && transform_node_has_requests(topo_node)) + { + struct transform_stream *stream; + + input = topo_node->u.transform.next_input++ % topo_node->u.transform.input_count; + stream = &topo_node->u.transform.inputs[input]; + + if (SUCCEEDED(transform_stream_pop_sample(stream, &sample))) + session_deliver_sample_to_node(session, topo_node->node, input, sample); + else if (FAILED(hr = IMFTopologyNode_GetInput(topo_node->node, input, &up_node, &output))) + WARN("Failed to get node %p/%lu input, hr %#lx\n", topo_node->node, input, hr); + else + { + if (FAILED(hr = session_request_sample_from_node(session, up_node, output))) + WARN("Failed to request sample from upstream node %p/%lu, hr %#lx\n", up_node, output, hr); + IMFTopologyNode_Release(up_node); + } + } } static void session_deliver_sample_to_node(struct media_session *session, IMFTopologyNode *node, unsigned int input, From 72e83904bf2fc81c64ffdefd11d0ac59a23ba2c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 4 Jul 2023 10:15:18 +0200 Subject: [PATCH 2323/2777] mf/session: Increase the request count when requests are already queued. (cherry picked from commit 57bd5b10a11c9b80d0cd2ef48bcab286bceea405) CW-Bug-Id: #21713 --- dlls/mf/session.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 39d6c764a50..7a578d2c8d8 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -3373,13 +3373,13 @@ static void session_deliver_pending_samples(struct media_session *session, IMFTo static HRESULT session_request_sample_from_node(struct media_session *session, IMFTopologyNode *node, DWORD output) { - IMFTopologyNode *downstream_node, *upstream_node; - DWORD downstream_input, upstream_output; + IMFTopologyNode *down_node; struct topo_node *topo_node; MF_TOPOLOGY_TYPE node_type; + HRESULT hr = S_OK; IMFSample *sample; TOPOID node_id; - HRESULT hr; + DWORD input; IMFTopologyNode_GetNodeType(node, &node_type); IMFTopologyNode_GetTopoNodeID(node, &node_id); @@ -3396,27 +3396,29 @@ static HRESULT session_request_sample_from_node(struct media_session *session, I { struct transform_stream *stream = &topo_node->u.transform.outputs[output]; - if (FAILED(hr = transform_stream_pop_sample(stream, &sample))) + if (FAILED(hr = IMFTopologyNode_GetOutput(node, output, &down_node, &input))) { - /* Forward request to upstream node. */ - if (SUCCEEDED(hr = IMFTopologyNode_GetInput(node, 0 /* FIXME */, &upstream_node, &upstream_output))) - { - if (SUCCEEDED(hr = session_request_sample_from_node(session, upstream_node, upstream_output))) - stream->requests++; - IMFTopologyNode_Release(upstream_node); - } + WARN("Failed to node %p/%lu output, hr %#lx.\n", node, output, hr); + break; } - else - { - if (SUCCEEDED(hr = IMFTopologyNode_GetOutput(node, output, &downstream_node, &downstream_input))) - { - session_deliver_sample_to_node(session, downstream_node, downstream_input, sample); - IMFTopologyNode_Release(downstream_node); - } + if (SUCCEEDED(transform_stream_pop_sample(stream, &sample))) + { + session_deliver_sample_to_node(session, down_node, input, sample); IMFSample_Release(sample); } + else if (transform_node_has_requests(topo_node)) + { + /* there's already requests pending, just increase the counter */ + stream->requests++; + } + else + { + stream->requests++; + transform_node_deliver_samples(session, topo_node); + } + IMFTopologyNode_Release(down_node); break; } case MF_TOPOLOGY_TEE_NODE: From 7a90e28c58cc4d5fa60e7c1ff9d4aba12bdfa3d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 20 Sep 2023 09:49:29 +0200 Subject: [PATCH 2324/2777] makedep: Allow unixlibs to have a different 64bit name. CW-Bug-Id: #22729 --- tools/makedep.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tools/makedep.c b/tools/makedep.c index 2707e1c77bc..3a028287245 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -200,6 +200,7 @@ struct makefile const char *staticlib; const char *importlib; const char *unixlib; + const char *unixlib_x64; int use_msvcrt; int data_only; int is_win16; @@ -3450,13 +3451,15 @@ static void output_unix_lib( struct makefile *make ) struct strarray unix_deps = empty_strarray; struct strarray unix_libs = add_unix_libraries( make, &unix_deps ); unsigned int arch = 0; /* unix libs are always native */ + const char *unixlib = make->unixlib; if (make->disabled[arch]) return; + if (make->unixlib_x64 && !strcmp( archs.str[arch], "x86_64" )) unixlib = make->unixlib_x64; - strarray_add( &make->all_targets[arch], make->unixlib ); - add_install_rule( make, make->module, arch, make->unixlib, - strmake( "p%s%s", arch_install_dirs[arch], make->unixlib )); - output( "%s:", obj_dir_path( make, make->unixlib )); + strarray_add( &make->all_targets[arch], unixlib ); + add_install_rule( make, make->module, arch, unixlib, + strmake( "p%s%s", arch_install_dirs[arch], unixlib )); + output( "%s:", obj_dir_path( make, unixlib )); output_filenames_obj_dir( make, make->unixobj_files ); output_filenames( unix_deps ); output( "\n" ); @@ -4273,7 +4276,11 @@ static void load_sources( struct makefile *make ) make->staticlib = get_expanded_make_variable( make, "STATICLIB" ); make->importlib = get_expanded_make_variable( make, "IMPORTLIB" ); make->extlib = get_expanded_make_variable( make, "EXTLIB" ); - if (*dll_ext) make->unixlib = get_expanded_make_variable( make, "UNIXLIB" ); + if (*dll_ext) + { + make->unixlib = get_expanded_make_variable( make, "UNIXLIB" ); + make->unixlib_x64 = get_expanded_make_variable( make, "UNIXLIB_x64" ); + } make->programs = get_expanded_make_var_array( make, "PROGRAMS" ); make->scripts = get_expanded_make_var_array( make, "SCRIPTS" ); From c3e75250e8b32a995c1133aba607d3a663e91a2d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 3 Oct 2023 15:02:44 -0600 Subject: [PATCH 2325/2777] fixup! ntdll: Use kernel soft dirty flags for write watches support. CW-Bug-Id: #22809 --- dlls/ntdll/unix/virtual.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index b62968cb26d..05e91bd4f8c 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -1609,7 +1609,10 @@ static NTSTATUS create_view( struct file_view **view_ret, void *base, size_t siz } if (vprot & VPROT_WRITEWATCH && use_kernel_writewatch) + { + madvise( view->base, view->size, MADV_NOHUGEPAGE ); reset_write_watches( view->base, view->size ); + } return STATUS_SUCCESS; } @@ -2201,7 +2204,10 @@ static NTSTATUS map_view( struct file_view **view_ret, void *base, size_t size, if (!set_vprot( *view_ret, base, size, vprot | VPROT_COMMITTED )) ERR("set_protection failed.\n"); if (vprot & VPROT_WRITEWATCH) + { + madvise( base, size, MADV_NOHUGEPAGE ); reset_write_watches( base, size ); + } return STATUS_SUCCESS; } TRACE("MEM_REPLACE_PLACEHOLDER view not found.\n"); From 709458a262f7c3f1194d013bc7384e6d8d96e821 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 3 Oct 2023 16:02:55 -0600 Subject: [PATCH 2326/2777] secur32: Syncrhonize access to schannel handle table. CW-Bug-Id: #22809 --- dlls/secur32/schannel.c | 47 +++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c index d4aab2b4c2a..a1c641cd34e 100644 --- a/dlls/secur32/schannel.c +++ b/dlls/secur32/schannel.c @@ -71,6 +71,7 @@ static struct schan_handle *schan_handle_table; static struct schan_handle *schan_free_handles; static SIZE_T schan_handle_table_size; static SIZE_T schan_handle_count; +static SRWLOCK handle_table_lock = SRWLOCK_INIT; /* Protocols enabled, only those may be used for the connection. */ static DWORD config_enabled_protocols; @@ -81,22 +82,24 @@ static DWORD config_default_disabled_protocols; static ULONG_PTR schan_alloc_handle(void *object, enum schan_handle_type type) { struct schan_handle *handle; + ULONG_PTR index = SCHAN_INVALID_HANDLE; + AcquireSRWLockExclusive(&handle_table_lock); if (schan_free_handles) { - DWORD index = schan_free_handles - schan_handle_table; /* Use a free handle */ handle = schan_free_handles; if (handle->type != SCHAN_HANDLE_FREE) { - ERR("Handle %ld(%p) is in the free list, but has type %#x.\n", index, handle, handle->type); - return SCHAN_INVALID_HANDLE; + ERR("Handle %p is in the free list, but has type %#x.\n", handle, handle->type); + goto done; } + index = schan_free_handles - schan_handle_table; schan_free_handles = handle->object; handle->object = object; handle->type = type; - return index; + goto done; } if (!(schan_handle_count < schan_handle_table_size)) { @@ -106,7 +109,7 @@ static ULONG_PTR schan_alloc_handle(void *object, enum schan_handle_type type) if (!new_table) { ERR("Failed to grow the handle table\n"); - return SCHAN_INVALID_HANDLE; + goto done; } schan_handle_table = new_table; schan_handle_table_size = new_size; @@ -116,21 +119,30 @@ static ULONG_PTR schan_alloc_handle(void *object, enum schan_handle_type type) handle->object = object; handle->type = type; - return handle - schan_handle_table; + index = handle - schan_handle_table; + +done: + ReleaseSRWLockExclusive(&handle_table_lock); + return index; } static void *schan_free_handle(ULONG_PTR handle_idx, enum schan_handle_type type) { struct schan_handle *handle; - void *object; + void *object = NULL; if (handle_idx == SCHAN_INVALID_HANDLE) return NULL; - if (handle_idx >= schan_handle_count) return NULL; + + AcquireSRWLockExclusive(&handle_table_lock); + + if (handle_idx >= schan_handle_count) + goto done; + handle = &schan_handle_table[handle_idx]; if (handle->type != type) { ERR("Handle %Id(%p) is not of type %#x\n", handle_idx, handle, type); - return NULL; + goto done; } object = handle->object; @@ -138,23 +150,32 @@ static void *schan_free_handle(ULONG_PTR handle_idx, enum schan_handle_type type handle->type = SCHAN_HANDLE_FREE; schan_free_handles = handle; +done: + ReleaseSRWLockExclusive(&handle_table_lock); return object; } static void *schan_get_object(ULONG_PTR handle_idx, enum schan_handle_type type) { struct schan_handle *handle; + void *object = NULL; if (handle_idx == SCHAN_INVALID_HANDLE) return NULL; - if (handle_idx >= schan_handle_count) return NULL; + + AcquireSRWLockShared(&handle_table_lock); + if (handle_idx >= schan_handle_count) + goto done; handle = &schan_handle_table[handle_idx]; if (handle->type != type) { - ERR("Handle %Id(%p) is not of type %#x\n", handle_idx, handle, type); - return NULL; + ERR("Handle %Id(%p) is not of type %#x (%#x)\n", handle_idx, handle, type, handle->type); + goto done; } + object = handle->object; - return handle->object; +done: + ReleaseSRWLockShared(&handle_table_lock); + return object; } static void read_config(void) From 513d371c76b45e383a20e05a64c8c75dc52d5b0b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 3 Oct 2023 16:37:20 -0600 Subject: [PATCH 2327/2777] secur32: Get rid of schannel free handle list. CW-Bug-Id: #22809 --- dlls/secur32/schannel.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c index a1c641cd34e..8129c17ad17 100644 --- a/dlls/secur32/schannel.c +++ b/dlls/secur32/schannel.c @@ -68,7 +68,6 @@ struct schan_context }; static struct schan_handle *schan_handle_table; -static struct schan_handle *schan_free_handles; static SIZE_T schan_handle_table_size; static SIZE_T schan_handle_count; static SRWLOCK handle_table_lock = SRWLOCK_INIT; @@ -82,23 +81,17 @@ static DWORD config_default_disabled_protocols; static ULONG_PTR schan_alloc_handle(void *object, enum schan_handle_type type) { struct schan_handle *handle; - ULONG_PTR index = SCHAN_INVALID_HANDLE; + ULONG_PTR index = SCHAN_INVALID_HANDLE, i; AcquireSRWLockExclusive(&handle_table_lock); - if (schan_free_handles) + for (i = 0; i < schan_handle_table_size; ++i) { - /* Use a free handle */ - handle = schan_free_handles; + handle = &schan_handle_table[i]; if (handle->type != SCHAN_HANDLE_FREE) - { - ERR("Handle %p is in the free list, but has type %#x.\n", handle, handle->type); - goto done; - } - index = schan_free_handles - schan_handle_table; - schan_free_handles = handle->object; + continue; handle->object = object; handle->type = type; - + index = i; goto done; } if (!(schan_handle_count < schan_handle_table_size)) @@ -146,9 +139,8 @@ static void *schan_free_handle(ULONG_PTR handle_idx, enum schan_handle_type type } object = handle->object; - handle->object = schan_free_handles; + handle->object = NULL; handle->type = SCHAN_HANDLE_FREE; - schan_free_handles = handle; done: ReleaseSRWLockExclusive(&handle_table_lock); From f3be587d495cb9a747ff714db44ba4e63e4ec23c Mon Sep 17 00:00:00 2001 From: Santino Mazza Date: Wed, 4 Oct 2023 16:05:30 -0300 Subject: [PATCH 2328/2777] mf: Clear end of presentation if topo_status is not invalid. Cw-Bug-Id: #22719 Cw-Bug-Id: #21809 --- dlls/mf/session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 7a578d2c8d8..0d3ed620a0c 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -2607,7 +2607,7 @@ static HRESULT WINAPI session_commands_callback_Invoke(IMFAsyncCallback *iface, case SESSION_CMD_STOP: if (session->presentation.flags & SESSION_FLAG_END_OF_PRESENTATION) session_set_topo_status(session, S_OK, MF_TOPOSTATUS_ENDED); - if (session->presentation.topo_status == MF_TOPOSTATUS_READY) + if (session->presentation.topo_status != MF_TOPOSTATUS_INVALID) session_clear_end_of_presentation(session); session_stop(session); break; From 264d01417ab5cf23c922f8f86310b7bc6af7b2f5 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 5 Oct 2023 08:37:31 -0600 Subject: [PATCH 2329/2777] Revert "msxml3: Implement FreeThreadedXMLHTTP60." This reverts commit 758483d719f42fad51d22f7d609bb521e8acc46c. CW-Bug-Id: #22822 --- dlls/msxml3/Makefile.in | 2 +- dlls/msxml3/factory.c | 5 - dlls/msxml3/httprequest.c | 496 +----------------------------------- dlls/msxml3/msxml_private.h | 1 - dlls/msxml3/tests/httpreq.c | 395 +--------------------------- dlls/msxml3/tests/schema.c | 6 - dlls/msxml3/uuid.c | 5 - 7 files changed, 5 insertions(+), 905 deletions(-) diff --git a/dlls/msxml3/Makefile.in b/dlls/msxml3/Makefile.in index e2d737599b1..2bf789732da 100644 --- a/dlls/msxml3/Makefile.in +++ b/dlls/msxml3/Makefile.in @@ -1,5 +1,5 @@ MODULE = msxml3.dll -IMPORTS = $(XSLT_PE_LIBS) $(XML2_PE_LIBS) uuid urlmon shlwapi oleaut32 ole32 user32 advapi32 rtworkq +IMPORTS = $(XSLT_PE_LIBS) $(XML2_PE_LIBS) uuid urlmon shlwapi oleaut32 ole32 user32 advapi32 EXTRAINCL = $(XSLT_PE_CFLAGS) $(XML2_PE_CFLAGS) C_SRCS = \ diff --git a/dlls/msxml3/factory.c b/dlls/msxml3/factory.c index 323c7b49848..243ee379712 100644 --- a/dlls/msxml3/factory.c +++ b/dlls/msxml3/factory.c @@ -279,7 +279,6 @@ static HRESULT DOMClassFactory_Create(const GUID *clsid, REFIID riid, void **ppv static ClassFactory xmldoccf = { { &ClassFactoryVtbl }, XMLDocument_create }; static ClassFactory httpreqcf = { { &ClassFactoryVtbl }, XMLHTTPRequest_create }; -static ClassFactory httpreqcf2 = { { &ClassFactoryVtbl }, XMLHTTPRequest2_create }; static ClassFactory serverhttp = { { &ClassFactoryVtbl }, ServerXMLHTTP_create }; static ClassFactory xsltemplatecf = { { &ClassFactoryVtbl }, XSLTemplate_create }; static ClassFactory mxnsmanagercf = { {&ClassFactoryVtbl }, MXNamespaceManager_create }; @@ -341,10 +340,6 @@ HRESULT WINAPI DllGetClassObject( REFCLSID rclsid, REFIID riid, void **ppv ) { cf = &httpreqcf.IClassFactory_iface; } - else if( IsEqualCLSID( rclsid, &CLSID_FreeThreadedXMLHTTP60 )) - { - cf = &httpreqcf2.IClassFactory_iface; - } else if( IsEqualCLSID( rclsid, &CLSID_ServerXMLHTTP ) || IsEqualCLSID( rclsid, &CLSID_ServerXMLHTTP30 ) || IsEqualCLSID( rclsid, &CLSID_ServerXMLHTTP40 ) || diff --git a/dlls/msxml3/httprequest.c b/dlls/msxml3/httprequest.c index 903787f9af0..cc384a380e5 100644 --- a/dlls/msxml3/httprequest.c +++ b/dlls/msxml3/httprequest.c @@ -38,12 +38,10 @@ #include "shlwapi.h" #include "msxml_dispex.h" -#include "initguid.h" -#include "rtworkq.h" #include "wine/debug.h" -WINE_DEFAULT_DEBUG_CHANNEL(xmlhttp); +WINE_DEFAULT_DEBUG_CHANNEL(msxml); static const WCHAR colspaceW[] = {':',' ',0}; static const WCHAR crlfW[] = {'\r','\n',0}; @@ -2060,468 +2058,6 @@ static const struct IServerXMLHTTPRequestVtbl ServerXMLHTTPRequestVtbl = ServerXMLHTTPRequest_setOption }; -static DWORD xhr2_work_queue; - -struct xml_http_request_2 -{ - httprequest req; - IXMLHTTPRequest3 IXMLHTTPRequest3_iface; - IRtwqAsyncCallback IRtwqAsyncCallback_iface; - IDispatch IDispatch_iface; - - IXMLHTTPRequest2Callback *callback; - IXMLHTTPRequest3Callback *callback3; - ISequentialStream *response_body; - ISequentialStream *request_body; - ULONGLONG request_body_size; -}; - -static inline struct xml_http_request_2 *impl_from_IXMLHTTPRequest3(IXMLHTTPRequest3 *iface) -{ - return CONTAINING_RECORD(iface, struct xml_http_request_2, IXMLHTTPRequest3_iface); -} - -static inline struct xml_http_request_2 *xml_http_request_2_from_IRtwqAsyncCallback(IRtwqAsyncCallback *iface) -{ - return CONTAINING_RECORD(iface, struct xml_http_request_2, IRtwqAsyncCallback_iface); -} - -static inline struct xml_http_request_2 *xml_http_request_2_from_IDispatch(IDispatch *iface) -{ - return CONTAINING_RECORD(iface, struct xml_http_request_2, IDispatch_iface); -} - -static HRESULT WINAPI xml_http_request_2_QueryInterface(IXMLHTTPRequest3 *iface, REFIID riid, void **obj) -{ - struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); - - TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); - - if (IsEqualGUID(riid, &IID_IXMLHTTPRequest3) || IsEqualGUID(riid, &IID_IXMLHTTPRequest2) - || IsEqualGUID(riid, &IID_IUnknown)) - { - *obj = iface; - IUnknown_AddRef((IUnknown*)*obj); - return S_OK; - } - - FIXME("Unsupported interface %s\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI xml_http_request_2_AddRef(IXMLHTTPRequest3 *iface) -{ - struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); - ULONG ref = InterlockedIncrement(&This->req.ref); - TRACE("(%p)->(%lu)\n", This, ref); - return ref; -} - -static ULONG WINAPI xml_http_request_2_Release(IXMLHTTPRequest3 *iface) -{ - struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); - ULONG ref = InterlockedDecrement(&This->req.ref); - - TRACE("(%p)->(%lu)\n", This, ref); - - if (ref == 0) - { - /* do not call httprequest_put_onreadystatechange to avoid ref cycle */ - This->req.sink = NULL; - if (This->response_body) ISequentialStream_Release(This->response_body); - if (This->request_body) ISequentialStream_Release(This->request_body); - if (This->callback3) IXMLHTTPRequest3Callback_Release(This->callback3); - if (This->callback) IXMLHTTPRequest2Callback_Release(This->callback); - heap_free(This); - RtwqShutdown(); - } - - return ref; -} - -static HRESULT WINAPI xml_http_request_2_Open(IXMLHTTPRequest3 *iface, const WCHAR *method, - const WCHAR *url, IXMLHTTPRequest2Callback *callback, - const WCHAR *username, const WCHAR *password, - const WCHAR *proxy_username, const WCHAR *proxy_password) -{ - static const WCHAR accept_encoding[] = {'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0}; - static const WCHAR empty = 0; - struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); - VARIANT async_v, username_v, password_v; - HRESULT hr; - - TRACE("(%p)->(%s %s %p %s %s %s %s)\n", This, debugstr_w(method), debugstr_w(url), callback, - debugstr_w(username), debugstr_w(password), debugstr_w(proxy_username), debugstr_w(proxy_password)); - - if (This->callback) IXMLHTTPRequest2Callback_Release(This->callback); - if (This->callback3) IXMLHTTPRequest3Callback_Release(This->callback3); - IXMLHTTPRequest2Callback_AddRef(callback); - This->callback = callback; - if (FAILED(IXMLHTTPRequest2Callback_QueryInterface(callback, &IID_IXMLHTTPRequest3Callback, (void **)&This->callback3))) - This->callback3 = NULL; - - if (proxy_username || proxy_password) FIXME("proxy credentials not implemented\n"); - - VariantInit(&async_v); - V_VT(&async_v) = VT_BOOL; - V_BOOL(&async_v) = FALSE; /* FIXME: TRUE needs a RTWQ_WINDOW_WORKQUEUE */ - - VariantInit(&username_v); - V_VT(&username_v) = VT_BSTR; - if (username) V_BSTR(&username_v) = SysAllocString(username); - else V_BSTR(&username_v) = SysAllocString(&empty); - - VariantInit(&password_v); - V_VT(&password_v) = VT_BSTR; - if (password) V_BSTR(&password_v) = SysAllocString(password); - else V_BSTR(&password_v) = SysAllocString(&empty); - - if (FAILED(hr = httprequest_open(&This->req, (BSTR)method, (BSTR)url, async_v, username_v, password_v))) - return hr; - return httprequest_setRequestHeader(&This->req, (BSTR)accept_encoding, (BSTR)&empty); -} - -static HRESULT WINAPI xml_http_request_2_Send(IXMLHTTPRequest3 *iface, ISequentialStream *body, ULONGLONG body_size) -{ - struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); - IRtwqAsyncResult *result; - HRESULT hr; - - TRACE("(%p)->(%p %s)\n", This, body, wine_dbgstr_longlong( body_size )); - - if (body_size) - { - ISequentialStream_AddRef(body); - This->request_body = body; - This->request_body_size = body_size; - } - - if (FAILED(hr = RtwqCreateAsyncResult(NULL, &This->IRtwqAsyncCallback_iface, NULL, &result))) - return hr; - // IRtwqAsyncCallback_Invoke(&This->IRtwqAsyncCallback_iface, result); - hr = RtwqPutWorkItem(xhr2_work_queue, 0, result); - if (result) IRtwqAsyncResult_Release(result); - - return hr; -} - -static HRESULT WINAPI xml_http_request_2_Abort(IXMLHTTPRequest3 *iface) -{ - struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); - TRACE("(%p) stub!\n", This); - return E_NOTIMPL; -} - -static HRESULT WINAPI xml_http_request_2_SetCookie(IXMLHTTPRequest3 *iface, const XHR_COOKIE *cookie, DWORD *state) -{ - struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); - FIXME("(%p)->(%p %p) stub!\n", This, cookie, state); - return E_NOTIMPL; -} - -static HRESULT WINAPI xml_http_request_2_SetCustomResponseStream(IXMLHTTPRequest3 *iface, ISequentialStream *stream) -{ - struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); - FIXME("(%p)->(%p) stub!\n", This, stream); - return E_NOTIMPL; -} - -static HRESULT WINAPI xml_http_request_2_SetProperty(IXMLHTTPRequest3 *iface, XHR_PROPERTY property, ULONGLONG value) -{ - struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); - FIXME("(%p)->(%#x %s) stub!\n", This, property, wine_dbgstr_longlong( value )); - return E_NOTIMPL; -} - -static HRESULT WINAPI xml_http_request_2_SetRequestHeader(IXMLHTTPRequest3 *iface, - const WCHAR *header, const WCHAR *value) -{ - struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); - TRACE("(%p)->(%s %s)\n", This, debugstr_w(header), debugstr_w(value)); - return httprequest_setRequestHeader(&This->req, (BSTR)header, (BSTR)value); -} - -static HRESULT WINAPI xml_http_request_2_GetAllResponseHeaders(IXMLHTTPRequest3 *iface, WCHAR **headers) -{ - struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); - FIXME("(%p)->(%p) stub!\n", This, headers); - return E_NOTIMPL; -} - -static HRESULT WINAPI xml_http_request_2_GetCookie(IXMLHTTPRequest3 *iface, const WCHAR *url, - const WCHAR *name, DWORD flags, - ULONG *cookies_count, XHR_COOKIE **cookies) -{ - struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); - FIXME("(%p)->(%s %s %#lx %p %p) stub!\n", This, debugstr_w(url), debugstr_w(name), flags, cookies_count, cookies); - return E_NOTIMPL; -} - -static HRESULT WINAPI xml_http_request_2_GetResponseHeader(IXMLHTTPRequest3 *iface, - const WCHAR *header, WCHAR **value) -{ - struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); - HRESULT hr; - - TRACE("(%p)->(%s %p)\n", This, debugstr_w(header), value); - - if (FAILED(hr = httprequest_getResponseHeader(&This->req, (BSTR)header, value))) - return hr; - -#define E_FILE_NOT_FOUND _HRESULT_TYPEDEF_(0x80070002) - - if (hr == S_FALSE) - { - *value = NULL; - return E_FILE_NOT_FOUND; - } - - return hr; -} - -static HRESULT WINAPI xml_http_request_3_SetClientCertificate(IXMLHTTPRequest3 *iface, DWORD count, const BYTE *hashes, const WCHAR *pin) -{ - struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); - FIXME("(%p)->(%ld %p %s) stub!\n", This, count, hashes, debugstr_w(pin)); - return E_NOTIMPL; -} - -static const struct IXMLHTTPRequest3Vtbl XMLHTTPRequest3Vtbl = { - /* IUnknown methods */ - xml_http_request_2_QueryInterface, - xml_http_request_2_AddRef, - xml_http_request_2_Release, - /* IXMLHTTPRequest2 methods */ - xml_http_request_2_Open, - xml_http_request_2_Send, - xml_http_request_2_Abort, - xml_http_request_2_SetCookie, - xml_http_request_2_SetCustomResponseStream, - xml_http_request_2_SetProperty, - xml_http_request_2_SetRequestHeader, - xml_http_request_2_GetAllResponseHeaders, - xml_http_request_2_GetCookie, - xml_http_request_2_GetResponseHeader, - /* IXMLHTTPRequest3 methods */ - xml_http_request_3_SetClientCertificate, -}; - -static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_QueryInterface(IRtwqAsyncCallback *iface, REFIID riid, void **obj) -{ - struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); - TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); - - if (IsEqualGUID(riid, &IID_IRtwqAsyncCallback) || IsEqualGUID(riid, &IID_IUnknown)) - { - IRtwqAsyncCallback_AddRef(iface); - *obj = iface; - return S_OK; - } - - FIXME("Unsupported interface %s\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI xml_http_request_2_IRtwqAsyncCallback_AddRef(IRtwqAsyncCallback *iface) -{ - struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); - TRACE("(%p)\n", This); - return xml_http_request_2_AddRef(&This->IXMLHTTPRequest3_iface); -} - -static ULONG WINAPI xml_http_request_2_IRtwqAsyncCallback_Release(IRtwqAsyncCallback *iface) -{ - struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); - TRACE("(%p)\n", This); - return xml_http_request_2_Release(&This->IXMLHTTPRequest3_iface); -} - -static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_GetParameters(IRtwqAsyncCallback *iface, - DWORD *flags, DWORD *queue) -{ - struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); - - TRACE("(%p)->(%p %p)\n", This, flags, queue); - - *flags = 0; - *queue = xhr2_work_queue; - return S_OK; -} - -static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_Invoke(IRtwqAsyncCallback *iface, - IRtwqAsyncResult *result) -{ - struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); - VARIANT body_v; - HRESULT hr; - ULONG read; - - TRACE("(%p)->(%p)\n", This, result); - - VariantInit(&body_v); - - if (This->request_body) - { - V_VT(&body_v) = VT_BSTR; - V_BSTR(&body_v) = CoTaskMemAlloc(This->request_body_size); - - if (FAILED(hr = ISequentialStream_Read(This->request_body, V_BSTR(&body_v), This->request_body_size, &read)) || - read < This->request_body_size) - { - ERR("Failed to allocate request body memory, hr %#lx\n", hr); - CoTaskMemFree(V_BSTR(&body_v)); - goto done; - } - - ISequentialStream_Release(This->request_body); - This->request_body = NULL; - } - - hr = httprequest_send(&This->req, body_v); - -done: - return IRtwqAsyncResult_SetStatus(result, hr); -} - -static const struct IRtwqAsyncCallbackVtbl xml_http_request_2_IRtwqAsyncCallbackVtbl = { - /* IUnknown methods */ - xml_http_request_2_IRtwqAsyncCallback_QueryInterface, - xml_http_request_2_IRtwqAsyncCallback_AddRef, - xml_http_request_2_IRtwqAsyncCallback_Release, - /* IRtwqAsyncCallback methods */ - xml_http_request_2_IRtwqAsyncCallback_GetParameters, - xml_http_request_2_IRtwqAsyncCallback_Invoke, -}; - -static HRESULT WINAPI xml_http_request_2_IDispatch_QueryInterface(IDispatch *iface, REFIID riid, void **obj) -{ - struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); - TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); - - if (IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, &IID_IUnknown)) - { - IDispatch_AddRef(iface); - *obj = iface; - return S_OK; - } - - FIXME("Unsupported interface %s\n", debugstr_guid(riid)); - *obj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI xml_http_request_2_IDispatch_AddRef(IDispatch *iface) -{ - struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); - TRACE("(%p)\n", This); - return xml_http_request_2_AddRef(&This->IXMLHTTPRequest3_iface); -} - -static ULONG WINAPI xml_http_request_2_IDispatch_Release(IDispatch *iface) -{ - struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); - TRACE("(%p)\n", This); - return xml_http_request_2_Release(&This->IXMLHTTPRequest3_iface); -} - -static HRESULT WINAPI xml_http_request_2_IDispatch_GetTypeInfoCount(IDispatch *iface, UINT *value) -{ - struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); - FIXME("(%p)->(%p) stub!\n", This, value); - *value = 0; - return S_OK; -} - -static HRESULT WINAPI xml_http_request_2_IDispatch_GetTypeInfo(IDispatch *iface, UINT index, - LCID lcid, ITypeInfo **value) -{ - struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); - FIXME("(%p)->(%d %lu %p) stub!\n", This, index, lcid, value); - *value = NULL; - return S_OK; -} - -static HRESULT WINAPI xml_http_request_2_IDispatch_GetIDsOfNames(IDispatch *iface, REFIID riid, - OLECHAR **names, UINT names_count, - LCID lcid, DISPID *disp_ids) -{ - struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); - FIXME("(%p)->(%s %p %d %lu %p) stub!\n", This, debugstr_guid(riid), names, names_count, lcid, disp_ids); - return S_OK; -} - -static HRESULT WINAPI xml_http_request_2_IDispatch_Invoke(IDispatch *iface, DISPID id, REFIID riid, - LCID lcid, WORD flags, DISPPARAMS *params, - VARIANT *result, EXCEPINFO *exception, UINT *arg_err) -{ - struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); - IXMLHTTPRequest2 *xhr2_iface = (IXMLHTTPRequest2*)&This->IXMLHTTPRequest3_iface; - HRESULT hr; - LONG status; - BSTR status_str = NULL; - - TRACE("(%p)->(%ld %s %lu %d %p %p %p %p) stub!\n", This, id, debugstr_guid(riid), lcid, flags, - params, result, exception, arg_err); - - if (This->req.state == READYSTATE_COMPLETE) - { - VARIANT body_v; - VariantInit(&body_v); - - IXMLHTTPRequest2Callback_AddRef(This->callback); - if (This->callback3) - { - IXMLHTTPRequest3Callback_AddRef(This->callback3); - IXMLHTTPRequest3Callback_OnServerCertificateReceived(This->callback3, (IXMLHTTPRequest3 *)xhr2_iface, 0, 1, NULL); - IXMLHTTPRequest3Callback_Release(This->callback3); - } - - if (FAILED(hr = httprequest_get_status(&This->req, &status)) || - FAILED(hr = httprequest_get_statusText(&This->req, &status_str))) - { - WARN("failed to get response status, error %#lx\n", hr); - IXMLHTTPRequest2Callback_OnError(This->callback, xhr2_iface, hr); - IXMLHTTPRequest2Callback_Release(This->callback); - return S_OK; - } - - IXMLHTTPRequest2Callback_OnHeadersAvailable(This->callback, xhr2_iface, status, status_str); - SysFreeString(status_str); - - if (This->response_body) ISequentialStream_Release(This->response_body); - This->response_body = NULL; - - if (FAILED(hr = httprequest_get_responseStream(&This->req, &body_v)) || - FAILED(hr = IUnknown_QueryInterface(V_UNKNOWN(&body_v), &IID_ISequentialStream, (void **)&This->response_body))) - { - WARN("failed to get response stream, error %#lx\n", hr); - IXMLHTTPRequest2Callback_OnError(This->callback, xhr2_iface, hr); - IXMLHTTPRequest2Callback_Release(This->callback); - return S_OK; - } - - IXMLHTTPRequest2Callback_OnDataAvailable(This->callback, xhr2_iface, This->response_body); - IXMLHTTPRequest2Callback_OnResponseReceived(This->callback, xhr2_iface, This->response_body); - IXMLHTTPRequest2Callback_Release(This->callback); - } - - return S_OK; -} - -static const struct IDispatchVtbl xml_http_request_2_IDispatchVtbl = { - /* IUnknown methods */ - xml_http_request_2_IDispatch_QueryInterface, - xml_http_request_2_IDispatch_AddRef, - xml_http_request_2_IDispatch_Release, - /* IDispatch methods */ - xml_http_request_2_IDispatch_GetTypeInfoCount, - xml_http_request_2_IDispatch_GetTypeInfo, - xml_http_request_2_IDispatch_GetIDsOfNames, - xml_http_request_2_IDispatch_Invoke, -}; - static void init_httprequest(httprequest *req) { req->IXMLHTTPRequest_iface.lpVtbl = &XMLHTTPRequestVtbl; @@ -2571,35 +2107,6 @@ HRESULT XMLHTTPRequest_create(void **obj) return S_OK; } -HRESULT XMLHTTPRequest2_create(void **obj) -{ - struct xml_http_request_2 *xhr2; - TRACE("(%p)\n", obj); - - if (!(xhr2 = heap_alloc(sizeof(*xhr2)))) return E_OUTOFMEMORY; - - init_httprequest(&xhr2->req); - xhr2->IXMLHTTPRequest3_iface.lpVtbl = &XMLHTTPRequest3Vtbl; - xhr2->IRtwqAsyncCallback_iface.lpVtbl = &xml_http_request_2_IRtwqAsyncCallbackVtbl; - xhr2->IDispatch_iface.lpVtbl = &xml_http_request_2_IDispatchVtbl; - - /* do not call httprequest_put_onreadystatechange to avoid ref cycle */ - xhr2->req.sink = &xhr2->IDispatch_iface; - - xhr2->callback = NULL; - xhr2->callback3 = NULL; - xhr2->request_body = NULL; - xhr2->response_body = NULL; - - /* for async http requests we need window message queue */ - RtwqStartup(); - if (!xhr2_work_queue) RtwqAllocateWorkQueue(RTWQ_MULTITHREADED_WORKQUEUE, &xhr2_work_queue); - - *obj = &xhr2->IXMLHTTPRequest3_iface; - TRACE("returning iface %p\n", *obj); - return S_OK; -} - HRESULT ServerXMLHTTP_create(void **obj) { serverhttp *req; @@ -2619,4 +2126,3 @@ HRESULT ServerXMLHTTP_create(void **obj) return S_OK; } - diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h index f3c9edd2c70..cd8ae547c73 100644 --- a/dlls/msxml3/msxml_private.h +++ b/dlls/msxml3/msxml_private.h @@ -344,7 +344,6 @@ extern HRESULT XMLDocument_create(void**) DECLSPEC_HIDDEN; extern HRESULT SAXXMLReader_create(MSXML_VERSION, void**) DECLSPEC_HIDDEN; extern HRESULT SAXAttributes_create(MSXML_VERSION, void**) DECLSPEC_HIDDEN; extern HRESULT XMLHTTPRequest_create(void **) DECLSPEC_HIDDEN; -extern HRESULT XMLHTTPRequest2_create(void **) DECLSPEC_HIDDEN; extern HRESULT ServerXMLHTTP_create(void **) DECLSPEC_HIDDEN; extern HRESULT XSLTemplate_create(void**) DECLSPEC_HIDDEN; extern HRESULT MXWriter_create(MSXML_VERSION, void**) DECLSPEC_HIDDEN; diff --git a/dlls/msxml3/tests/httpreq.c b/dlls/msxml3/tests/httpreq.c index bac1c1bc40d..bccfbaf582a 100644 --- a/dlls/msxml3/tests/httpreq.c +++ b/dlls/msxml3/tests/httpreq.c @@ -26,9 +26,9 @@ #include #include "windows.h" + #include "msxml2.h" -#include "msxml6.h" -#include "msxml6did.h" +#include "msxml2did.h" #include "dispex.h" #include "initguid.h" @@ -1344,17 +1344,6 @@ static IXMLHttpRequest *create_xhr(void) return SUCCEEDED(hr) ? ret : NULL; } -static IXMLHTTPRequest2 *create_xhr2(void) -{ - IXMLHTTPRequest2 *ret; - HRESULT hr; - - hr = CoCreateInstance(&CLSID_FreeThreadedXMLHTTP60, NULL, CLSCTX_INPROC_SERVER, - &IID_IXMLHTTPRequest2, (void**)&ret); - - return SUCCEEDED(hr) ? ret : NULL; -} - static IServerXMLHTTPRequest *create_server_xhr(void) { IServerXMLHTTPRequest *ret; @@ -1915,388 +1904,11 @@ static void test_supporterrorinfo(void) IServerXMLHTTPRequest_Release(server_xhr); } -struct xhr3_callback -{ - IXMLHTTPRequest3Callback IXMLHTTPRequest3Callback_iface; - LONG ref; - HANDLE event; -}; - -static inline struct xhr3_callback *xhr3_callback_from_IXMLHTTPRequest3Callback(IXMLHTTPRequest3Callback *iface) -{ - return CONTAINING_RECORD(iface, struct xhr3_callback, IXMLHTTPRequest3Callback_iface); -} - -static HRESULT WINAPI xhr3_callback_QueryInterface(IXMLHTTPRequest3Callback *iface, REFIID riid, void **obj) -{ - struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); - trace("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); - - if (IsEqualGUID(riid, &IID_IXMLHTTPRequest3Callback) || IsEqualGUID(riid, &IID_IXMLHTTPRequest2Callback) || IsEqualGUID(riid, &IID_IUnknown)) - { - IXMLHTTPRequest3Callback_AddRef(iface); - *obj = iface; - return S_OK; - } - - ok(0, "unexpected interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI xhr3_callback_AddRef(IXMLHTTPRequest3Callback *iface) -{ - struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); - ULONG ref = InterlockedIncrement(&This->ref); - trace("(%p)->(%u)\n", This, ref); - return ref; -} - -static ULONG WINAPI xhr3_callback_Release(IXMLHTTPRequest3Callback *iface) -{ - struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); - ULONG ref = InterlockedDecrement(&This->ref); - trace("(%p)->(%u)\n", This, ref); - if (ref == 0) HeapFree(GetProcessHeap(), 0, This); - return ref; -} - -static HRESULT WINAPI xhr3_callback_OnRedirect(IXMLHTTPRequest3Callback *iface, - IXMLHTTPRequest2 *request, const WCHAR* redirect_url) -{ - struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); - trace("(%p)->(%p %s)\n", This, request, debugstr_w(redirect_url)); - return S_OK; -} - -static HRESULT WINAPI xhr3_callback_OnHeadersAvailable(IXMLHTTPRequest3Callback *iface, - IXMLHTTPRequest2 *request, DWORD status, const WCHAR *status_str) -{ - struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); - WCHAR *header = NULL; - HRESULT hr; - - trace("(%p)->(%p %d %s)\n", This, request, status, debugstr_w(status_str)); - - header = (void *)0xdeadbeef; - hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Content-Length", &header); - trace("Content-Length: %p (%s), hr %#x\n", header, debugstr_w(header), hr); - - return S_OK; -} - -static HRESULT WINAPI xhr3_callback_OnDataAvailable(IXMLHTTPRequest3Callback *iface, - IXMLHTTPRequest2 *request, ISequentialStream *response) -{ - struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); - trace("(%p)->(%p %p)\n", This, request, response); - return S_OK; -} - -static HRESULT WINAPI xhr3_callback_OnResponseReceived(IXMLHTTPRequest3Callback *iface, - IXMLHTTPRequest2 *request, ISequentialStream *response) -{ - struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); - WCHAR *header = NULL; - char *buffer = HeapAlloc( GetProcessHeap(), 0, 256 ); - ULONG read_size = 0; - HRESULT hr; - - memset(buffer, '?', 256); - buffer[255] = 0; - - trace("(%p)->(%p %p)\n", This, request, response); - - header = (void *)0xdeadbeef; - hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Cache-Control", &header); - trace("Cache-Control: %p (%s), hr %#x\n", header, debugstr_w(header), hr); - - header = (void *)0xdeadbeef; - hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Expires", &header); - trace("Expires: %p (%s), hr %#x\n", header, debugstr_w(header), hr); - - header = (void *)0xdeadbeef; - hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Content-Type", &header); - trace("Content-Type: %p (%s), hr %#x\n", header, debugstr_w(header), hr); - - read_size = 0xdeadbeef; - hr = ISequentialStream_Read(response, buffer, 214, &read_size); - trace("Response: (%d) %s, hr %#x\n", read_size, debugstr_a(buffer), hr); - - read_size = 0xdeadbeef; - hr = ISequentialStream_Read(response, buffer, 1, &read_size); - trace("Response: (%d) %s, hr %#x\n", read_size, debugstr_a(buffer), hr); - - HeapFree( GetProcessHeap(), 0, buffer ); - SetEvent(This->event); - - return S_OK; -} - -static HRESULT WINAPI xhr3_callback_OnError(IXMLHTTPRequest3Callback *iface, - IXMLHTTPRequest2 *request, HRESULT error) -{ - struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); - trace("(%p)->(%p %#x)\n", This, request, error); - SetEvent(This->event); - return S_OK; -} - -static HRESULT WINAPI xhr3_callback_OnServerCertificateReceived(IXMLHTTPRequest3Callback *iface, - IXMLHTTPRequest3 *request, DWORD errors, DWORD chain_size, const XHR_CERT *chain) -{ - struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); - trace("(%p)->(%p %u %u %p)\n", This, request, errors, chain_size, chain); - return S_OK; -} - -static HRESULT WINAPI xhr3_callback_OnClientCertificateRequested(IXMLHTTPRequest3Callback *iface, - IXMLHTTPRequest3 *request, DWORD issuers_size, const WCHAR **issuers) -{ - struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); - trace("(%p)->(%p %u %p)\n", This, request, issuers_size, issuers); - return S_OK; -} - -static const IXMLHTTPRequest3CallbackVtbl xhr3_callback_vtbl = -{ - xhr3_callback_QueryInterface, - xhr3_callback_AddRef, - xhr3_callback_Release, - /* IXMLHTTPRequest2Callback methods */ - xhr3_callback_OnRedirect, - xhr3_callback_OnHeadersAvailable, - xhr3_callback_OnDataAvailable, - xhr3_callback_OnResponseReceived, - xhr3_callback_OnError, - /* IXMLHTTPRequest3Callback methods */ - xhr3_callback_OnServerCertificateReceived, - xhr3_callback_OnClientCertificateRequested, -}; - -static IXMLHTTPRequest2Callback* xhr3_callback_create(HANDLE event) -{ - struct xhr3_callback *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); - ok(This != NULL, "failed to allocate object\n"); - if (!This) return NULL; - - This->IXMLHTTPRequest3Callback_iface.lpVtbl = &xhr3_callback_vtbl; - This->ref = 1; - This->event = event; - - return (IXMLHTTPRequest2Callback*)&This->IXMLHTTPRequest3Callback_iface; -} - -struct xhr2_stream -{ - IStream IStream_iface; - LONG ref; - IStream *stream; -}; - -static inline struct xhr2_stream *xhr2_stream_from_IStream(IStream *iface) -{ - return CONTAINING_RECORD(iface, struct xhr2_stream, IStream_iface); -} - -static HRESULT WINAPI xhr2_stream_QueryInterface(IStream *iface, REFIID riid, void **obj) -{ - struct xhr2_stream *This = xhr2_stream_from_IStream(iface); - trace("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); - - if (IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_ISequentialStream) || IsEqualGUID(riid, &IID_IUnknown)) - { - IStream_AddRef(iface); - *obj = iface; - return S_OK; - } - - ok(0, "unexpected interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI xhr2_stream_AddRef(IStream *iface) -{ - struct xhr2_stream *This = xhr2_stream_from_IStream(iface); - ULONG ref = InterlockedIncrement(&This->ref); - trace("(%p)->(%u)\n", This, ref); - return ref; -} - -static ULONG WINAPI xhr2_stream_Release(IStream *iface) -{ - struct xhr2_stream *This = xhr2_stream_from_IStream(iface); - ULONG ref = InterlockedDecrement(&This->ref); - trace("(%p)->(%u)\n", This, ref); - if (ref == 0) - { - IStream_Release(This->stream); - HeapFree(GetProcessHeap(), 0, This); - } - return ref; -} - -static HRESULT WINAPI xhr2_stream_Read(IStream *iface, void *pv, ULONG cb, - ULONG *pcbRead) -{ - struct xhr2_stream *This = xhr2_stream_from_IStream(iface); - trace("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); - return IStream_Read(This->stream, pv, cb, pcbRead); -} - -static HRESULT WINAPI xhr2_stream_Write(IStream *iface, const void *pv, - ULONG cb, ULONG *pcbWritten) -{ - struct xhr2_stream *This = xhr2_stream_from_IStream(iface); - trace("(%p)->(%p %u %p)\n", This, pv, cb, pcbWritten); - return IStream_Write(This->stream, pv, cb, pcbWritten); -} - -static HRESULT WINAPI xhr2_stream_Seek(IStream *iface, LARGE_INTEGER dlibMove, - DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) -{ - struct xhr2_stream *This = xhr2_stream_from_IStream(iface); - trace("(%p)->(%lu, %u %p)\n", This, dlibMove.QuadPart, dwOrigin, plibNewPosition); - return IStream_Seek(This->stream, dlibMove, dwOrigin, plibNewPosition); -} - -static HRESULT WINAPI xhr2_stream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize) -{ - struct xhr2_stream *This = xhr2_stream_from_IStream(iface); - trace("(%p)->(%lu)\n", This, libNewSize.QuadPart); - return IStream_SetSize(This->stream, libNewSize); -} - -static HRESULT WINAPI xhr2_stream_CopyTo(IStream *iface, IStream *pstm, - ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) -{ - struct xhr2_stream *This = xhr2_stream_from_IStream(iface); - trace("(%p)->(%p %lu %p %p)\n", This, pstm, cb.QuadPart, pcbRead, pcbWritten); - return IStream_CopyTo(This->stream, pstm, cb, pcbRead, pcbWritten); -} - -static HRESULT WINAPI xhr2_stream_Commit(IStream *iface, DWORD grfCommitFlags) -{ - struct xhr2_stream *This = xhr2_stream_from_IStream(iface); - trace("(%p)->(%#x)\n", This, grfCommitFlags); - return IStream_Commit(This->stream, grfCommitFlags); -} - -static HRESULT WINAPI xhr2_stream_Revert(IStream *iface) -{ - struct xhr2_stream *This = xhr2_stream_from_IStream(iface); - trace("(%p)->()\n", This); - return IStream_Revert(This->stream); -} - -static HRESULT WINAPI xhr2_stream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset, - ULARGE_INTEGER cb, DWORD dwLockType) -{ - struct xhr2_stream *This = xhr2_stream_from_IStream(iface); - trace("(%p)->(%lu %lu %u)\n", This, libOffset.QuadPart, cb.QuadPart, dwLockType); - return IStream_LockRegion(This->stream, libOffset, cb, dwLockType); -} - -static HRESULT WINAPI xhr2_stream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset, - ULARGE_INTEGER cb, DWORD dwLockType) -{ - struct xhr2_stream *This = xhr2_stream_from_IStream(iface); - trace("(%p)->(%lu %lu %u)\n", This, libOffset.QuadPart, cb.QuadPart, dwLockType); - return IStream_UnlockRegion(This->stream, libOffset, cb, dwLockType); -} - -static HRESULT WINAPI xhr2_stream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag) -{ - struct xhr2_stream *This = xhr2_stream_from_IStream(iface); - trace("(%p)->(%p %#x)\n", This, pstatstg, grfStatFlag); - return IStream_Stat(This->stream, pstatstg, grfStatFlag); -} - -static HRESULT WINAPI xhr2_stream_Clone(IStream *iface, IStream **ppstm) -{ - struct xhr2_stream *This = xhr2_stream_from_IStream(iface); - trace("(%p)->(%p)\n", This, ppstm); - return IStream_Clone(This->stream, ppstm); -} - -static const IStreamVtbl xhr2_stream_vtbl = -{ - xhr2_stream_QueryInterface, - xhr2_stream_AddRef, - xhr2_stream_Release, - /* IStream methods */ - xhr2_stream_Read, - xhr2_stream_Write, - xhr2_stream_Seek, - xhr2_stream_SetSize, - xhr2_stream_CopyTo, - xhr2_stream_Commit, - xhr2_stream_Revert, - xhr2_stream_LockRegion, - xhr2_stream_UnlockRegion, - xhr2_stream_Stat, - xhr2_stream_Clone -}; - -static ISequentialStream *xhr2_stream_create(void) -{ - struct xhr2_stream *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); - ok(This != NULL, "failed to allocate object\n"); - if (!This) return NULL; - - This->IStream_iface.lpVtbl = &xhr2_stream_vtbl; - This->ref = 1; - CreateStreamOnHGlobal(NULL, TRUE, &This->stream); - - return (ISequentialStream*)&This->IStream_iface; -} - -static void test_IXMLHTTPRequest2(void) -{ - IXMLHTTPRequest2 *xhr2[16]; - IXMLHTTPRequest2Callback *xhr3_callback; - ISequentialStream *stream; - HANDLE events[16]; - HRESULT hr; - int i = 0; - - if (!(xhr2[i] = create_xhr2())) - { - win_skip("IXMLHTTPRequest2 is not available\n"); - return; - } - - events[i] = CreateEventW(NULL, FALSE, FALSE, NULL); - if (!(xhr3_callback = xhr3_callback_create(events[i]))) - return; - - trace("IXMLHTTPRequest2_Open (%p)->(L\"GET\", L\"http://test.winehq.org/\", xhr3_callback, NULL, NULL, NULL, NULL)\n", GetCurrentThreadId(), xhr2[i]); - hr = IXMLHTTPRequest2_Open(xhr2[i], L"GET", L"http://test.winehq.org/", xhr3_callback, NULL, NULL, NULL, NULL); - ok(SUCCEEDED(hr), "IXMLHTTPRequest2_Send failed %#x\n", hr); - - if ((stream = xhr2_stream_create())) - { - trace("IXMLHTTPRequest2_Send (%p)->(%p 0)\n", GetCurrentThreadId(), xhr2[i], stream); - hr = IXMLHTTPRequest2_Send(xhr2[i], stream, 0); - ok(SUCCEEDED(hr), "IXMLHTTPRequest2_Send failed %#x\n", hr); - - ISequentialStream_Release(stream); - } - - IXMLHTTPRequest2Callback_Release(xhr3_callback); - i++; - - while (i--) - { - WaitForSingleObject(events[i], INFINITE); - IXMLHTTPRequest2_Release(xhr2[i]); - } -} - START_TEST(httpreq) { IXMLHttpRequest *xhr; - CoInitializeEx(NULL, COINIT_MULTITHREADED); + CoInitialize(NULL); if (!(xhr = create_xhr())) { @@ -2311,7 +1923,6 @@ START_TEST(httpreq) test_server_xhr(); test_safe_httpreq(); test_supporterrorinfo(); - test_IXMLHTTPRequest2(); CoUninitialize(); } diff --git a/dlls/msxml3/tests/schema.c b/dlls/msxml3/tests/schema.c index 2b63182e2e4..99c7d35cc10 100644 --- a/dlls/msxml3/tests/schema.c +++ b/dlls/msxml3/tests/schema.c @@ -32,16 +32,10 @@ #include "dispex.h" #include "cguid.h" -DEFINE_GUID(CLSID_FreeThreadedDOMDocument60, 0x88d96a06, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -DEFINE_GUID(CLSID_FreeThreadedXMLHTTP60, 0x88d96a09, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_MXXMLWriter60, 0x88d96a0f, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_SAXAttributes60, 0x88d96a0e, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_SAXXMLReader60, 0x88d96a0c, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_XMLSchemaCache60, 0x88d96a07, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -DEFINE_GUID(IID_IXMLHTTPRequest2, 0xe5d37dc0, 0x552a, 0x4d52, 0x9c,0xc0, 0xa1,0x4d,0x54,0x6f,0xbd,0x04); -DEFINE_GUID(IID_IXMLHTTPRequest3, 0xa1c9feee, 0x0617, 0x4f23, 0x9d,0x58, 0x89,0x61,0xea,0x43,0x56,0x7c); -DEFINE_GUID(IID_IXMLHTTPRequest2Callback, 0xa44a9299, 0xe321, 0x40de, 0x88,0x66, 0x34,0x1b,0x41,0x66,0x91,0x62); -DEFINE_GUID(IID_IXMLHTTPRequest3Callback, 0xb9e57830, 0x8c6c, 0x4a6f, 0x9c,0x13, 0x47,0x77,0x2b,0xb0,0x47,0xbb); #include "wine/test.h" diff --git a/dlls/msxml3/uuid.c b/dlls/msxml3/uuid.c index 1b4f0452c5f..333d4f3d3c7 100644 --- a/dlls/msxml3/uuid.c +++ b/dlls/msxml3/uuid.c @@ -43,7 +43,6 @@ /* Cannot include msxml6 here since we will get a duplicate LIBID_MSXML2 error. */ DEFINE_GUID(CLSID_FreeThreadedDOMDocument60, 0x88d96a06, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -DEFINE_GUID(CLSID_FreeThreadedXMLHTTP60, 0x88d96a09, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_MXNamespaceManager60, 0x88d96a11, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_MXXMLWriter60, 0x88d96a0f, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_SAXAttributes60, 0x88d96a0e, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); @@ -52,10 +51,6 @@ DEFINE_GUID(CLSID_ServerXMLHTTP60, 0x88d96a0b, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0 DEFINE_GUID(CLSID_XMLHTTP60, 0x88d96a0a, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_XMLSchemaCache60, 0x88d96a07, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_XSLTemplate60, 0x88d96a08, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -DEFINE_GUID(IID_IXMLHTTPRequest2, 0xe5d37dc0, 0x552a, 0x4d52, 0x9c,0xc0, 0xa1,0x4d,0x54,0x6f,0xbd,0x04); -DEFINE_GUID(IID_IXMLHTTPRequest3, 0xa1c9feee, 0x0617, 0x4f23, 0x9d,0x58, 0x89,0x61,0xea,0x43,0x56,0x7c); -DEFINE_GUID(IID_IXMLHTTPRequest2Callback, 0xa44a9299, 0xe321, 0x40de, 0x88,0x66, 0x34,0x1b,0x41,0x66,0x91,0x62); -DEFINE_GUID(IID_IXMLHTTPRequest3Callback, 0xb9e57830, 0x8c6c, 0x4a6f, 0x9c,0x13, 0x47,0x77,0x2b,0xb0,0x47,0xbb); /* * Note that because of a #define in msxml2.h, we end up initializing From e3c51122fb3a11201794d53c674afba003be206c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 5 Oct 2023 08:37:32 -0600 Subject: [PATCH 2330/2777] Revert "include: Remove interfaces already define in msxml6.idl" This reverts commit a3c9cb385e8de27d248587fe31aa529dde454514. CW-Bug-Id: #22822 --- dlls/msxml3/factory.c | 1 - dlls/msxml3/tests/saxreader.c | 1 - dlls/msxml3/tests/schema.c | 5 -- dlls/msxml3/uuid.c | 11 ---- include/msxml2.idl | 109 ++++++++++++++++++++++++++++++++++ include/msxml6.idl | 24 ++++---- 6 files changed, 121 insertions(+), 30 deletions(-) diff --git a/dlls/msxml3/factory.c b/dlls/msxml3/factory.c index 243ee379712..c2d3cd30c60 100644 --- a/dlls/msxml3/factory.c +++ b/dlls/msxml3/factory.c @@ -31,7 +31,6 @@ #include "ole2.h" #include "msxml.h" #include "msxml2.h" -#include "msxml6.h" #include "xmlparser.h" /* undef the #define in msxml2 so that we can access the v.2 version diff --git a/dlls/msxml3/tests/saxreader.c b/dlls/msxml3/tests/saxreader.c index 48cfa8f5593..e123d4eba5a 100644 --- a/dlls/msxml3/tests/saxreader.c +++ b/dlls/msxml3/tests/saxreader.c @@ -29,7 +29,6 @@ #include "windows.h" #include "ole2.h" #include "msxml2.h" -#include "msxml6.h" #include "msxml2did.h" #include "ocidl.h" #include "dispex.h" diff --git a/dlls/msxml3/tests/schema.c b/dlls/msxml3/tests/schema.c index 99c7d35cc10..3d209c0e4a0 100644 --- a/dlls/msxml3/tests/schema.c +++ b/dlls/msxml3/tests/schema.c @@ -32,11 +32,6 @@ #include "dispex.h" #include "cguid.h" -DEFINE_GUID(CLSID_MXXMLWriter60, 0x88d96a0f, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -DEFINE_GUID(CLSID_SAXAttributes60, 0x88d96a0e, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -DEFINE_GUID(CLSID_SAXXMLReader60, 0x88d96a0c, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -DEFINE_GUID(CLSID_XMLSchemaCache60, 0x88d96a07, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); - #include "wine/test.h" #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) diff --git a/dlls/msxml3/uuid.c b/dlls/msxml3/uuid.c index 333d4f3d3c7..4abbe5e4763 100644 --- a/dlls/msxml3/uuid.c +++ b/dlls/msxml3/uuid.c @@ -41,17 +41,6 @@ #include "initguid.h" #include "msxml2.h" -/* Cannot include msxml6 here since we will get a duplicate LIBID_MSXML2 error. */ -DEFINE_GUID(CLSID_FreeThreadedDOMDocument60, 0x88d96a06, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -DEFINE_GUID(CLSID_MXNamespaceManager60, 0x88d96a11, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -DEFINE_GUID(CLSID_MXXMLWriter60, 0x88d96a0f, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -DEFINE_GUID(CLSID_SAXAttributes60, 0x88d96a0e, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -DEFINE_GUID(CLSID_SAXXMLReader60, 0x88d96a0c, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -DEFINE_GUID(CLSID_ServerXMLHTTP60, 0x88d96a0b, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -DEFINE_GUID(CLSID_XMLHTTP60, 0x88d96a0a, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -DEFINE_GUID(CLSID_XMLSchemaCache60, 0x88d96a07, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -DEFINE_GUID(CLSID_XSLTemplate60, 0x88d96a08, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); - /* * Note that because of a #define in msxml2.h, we end up initializing * CLSID_DOMDocument2 to be the v.3 version independent DOMDocument diff --git a/include/msxml2.idl b/include/msxml2.idl index 1d1ba7a5248..916e0e8ab3d 100644 --- a/include/msxml2.idl +++ b/include/msxml2.idl @@ -1612,6 +1612,15 @@ coclass FreeThreadedDOMDocument40 [default, source] dispinterface XMLDOMDocumentEvents; } +[ + uuid(88d96a06-f192-11d4-a65f-0040963251e5), +] +coclass FreeThreadedDOMDocument60 +{ + [default] interface IXMLDOMDocument3; + [default, source] dispinterface XMLDOMDocumentEvents; +} + [ helpstring("Free threaded XML DOM Document"), progid("Msxml2.FreeThreadedDOMDocument"), @@ -1653,6 +1662,14 @@ coclass XMLHTTP40 [default] interface IXMLHTTPRequest; } +[ + uuid(88d96a0a-f192-11d4-a65f-0040963251e5) +] +coclass XMLHTTP60 +{ + [default] interface IXMLHTTPRequest; +} + [ helpstring("XML HTTP"), progid("Msxml2.XMLHTTP"), @@ -1685,6 +1702,14 @@ coclass ServerXMLHTTP40 [default] interface IServerXMLHTTPRequest2; } +[ + uuid(88d96a0b-f192-11d4-a65f-0040963251e5) +] +coclass ServerXMLHTTP60 +{ + [default] interface IServerXMLHTTPRequest2; +} + [ helpstring("Server XML HTTP"), progid("Msxml2.ServerXMLHTTP"), @@ -1725,6 +1750,14 @@ coclass XMLSchemaCache40 [default] interface IXMLDOMSchemaCollection2; } +[ + uuid(88d96a07-f192-11d4-a65f-0040963251e5) +] +coclass XMLSchemaCache60 +{ + [default] interface IXMLDOMSchemaCollection2; +} + [ helpstring("XML Schema Cache"), progid("Msxml2.XMLSchemaCache"), @@ -1765,6 +1798,14 @@ coclass XSLTemplate40 [default] interface IXSLTemplate; } +[ + uuid(88d96a08-f192-11d4-a65f-0040963251e5) +] +coclass XSLTemplate60 +{ + [default] interface IXSLTemplate; +} + [ helpstring("XSL Template"), progid("Msxml2.XSLTemplate"), @@ -3256,6 +3297,15 @@ coclass SAXXMLReader40 interface ISAXXMLReader; } +[ + uuid(88d96a0c-f192-11d4-a65f-0040963251e5) +] +coclass SAXXMLReader60 +{ + [default] interface IVBSAXXMLReader; + interface ISAXXMLReader; +} + [ helpstring("SAX XML Reader"), progid("Msxml2.SAXXMLReader"), @@ -3330,6 +3380,26 @@ coclass MXHTMLWriter40 interface IVBSAXLexicalHandler; } +[ + uuid(88d96a10-f192-11d4-a65f-0040963251e5) +] +coclass MXHTMLWriter60 +{ + [default] interface IMXWriter; + + interface ISAXContentHandler; + interface ISAXDeclHandler; + interface ISAXDTDHandler; + interface ISAXErrorHandler; + interface ISAXLexicalHandler; + + interface IVBSAXContentHandler; + interface IVBSAXDeclHandler; + interface IVBSAXDTDHandler; + interface IVBSAXErrorHandler; + interface IVBSAXLexicalHandler; +} + [ helpstring("MXXMLWriter 3.0"), progid("Msxml2.MXXMLWriter.3.0"), @@ -3374,6 +3444,26 @@ coclass MXXMLWriter40 interface IVBSAXLexicalHandler; } +[ + uuid(88d96a0f-f192-11d4-a65f-0040963251e5) +] +coclass MXXMLWriter60 +{ + [default] interface IMXWriter; + + interface ISAXContentHandler; + interface ISAXDeclHandler; + interface ISAXDTDHandler; + interface ISAXErrorHandler; + interface ISAXLexicalHandler; + + interface IVBSAXContentHandler; + interface IVBSAXDeclHandler; + interface IVBSAXDTDHandler; + interface IVBSAXErrorHandler; + interface IVBSAXLexicalHandler; +} + [ helpstring("MXXMLWriter"), progid("Msxml2.MXXMLWriter"), @@ -3416,6 +3506,15 @@ coclass MXNamespaceManager40 interface IMXNamespaceManager; } +[ + uuid(88d96a11-f192-11d4-a65f-0040963251e5) +] +coclass MXNamespaceManager60 +{ + [default] interface IVBMXNamespaceManager; + interface IMXNamespaceManager; +} + [ helpstring("SAXAttributes 3.0"), progid("Msxml2.SAXAttributes.3.0"), @@ -3440,6 +3539,16 @@ coclass SAXAttributes40 interface ISAXAttributes; } +[ + uuid(88d96a0e-f192-11d4-a65f-0040963251e5) +] +coclass SAXAttributes60 +{ + [default] interface IMXAttributes; + interface IVBSAXAttributes; + interface ISAXAttributes; +} + [ helpstring("SAXAttributes"), progid("Msxml2.SAXAttributes"), diff --git a/include/msxml6.idl b/include/msxml6.idl index 4672ae80626..458c43e389d 100644 --- a/include/msxml6.idl +++ b/include/msxml6.idl @@ -3051,6 +3051,18 @@ coclass DOMDocument60 [default, source] dispinterface XMLDOMDocumentEvents; } +[ + helpstring("Free threaded XML DOM Document 6.0"), + progid("Msxml2.FreeThreadedDOMDocument.6.0"), + threading(both), + uuid(88d96a06-f192-11d4-a65f-0040963251e5), +] +coclass FreeThreadedDOMDocument60 +{ + [default] interface IXMLDOMDocument3; + [default, source] dispinterface XMLDOMDocumentEvents; +} + [ helpstring("SAX XML Reader 6.0"), progid("Msxml2.SAXXMLReader.6.0"), @@ -3156,18 +3168,6 @@ coclass XSLTemplate60 [default] interface IXSLTemplate; } -[ - helpstring("Free threaded XML DOM Document 6.0"), - progid("Msxml2.FreeThreadedDOMDocument.6.0"), - threading(both), - uuid(88d96a06-f192-11d4-a65f-0040963251e5), -] -coclass FreeThreadedDOMDocument60 -{ - [default] interface IXMLDOMDocument3; - [default, source] dispinterface XMLDOMDocumentEvents; -} - [ helpstring("XML HTTP 6.0"), progid("Msxml2.XMLHTTP.6.0"), From fbd4d019a3b1f98f63d62300cbd9c7f0efe01dfe Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Tue, 10 Jan 2023 16:22:14 +1100 Subject: [PATCH 2331/2777] include: Add _XHR enum values. (cherry picked from commit d05ce2e72da6e576b509076224aed866ff7275cb) CW-Bug-Id: #22822 --- include/msxml6.idl | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/msxml6.idl b/include/msxml6.idl index 458c43e389d..d4a5c490243 100644 --- a/include/msxml6.idl +++ b/include/msxml6.idl @@ -256,6 +256,20 @@ typedef enum _SCHEMATYPEVARIETY } SCHEMATYPEVARIETY; cpp_quote("#endif /* __msxml_som_enums__ */") +typedef [v1_enum] enum _XHR_CRED_PROMPT +{ + XHR_CRED_PROMPT_ALL, + XHR_CRED_PROMPT_NONE, + XHR_CRED_PROMPT_PROXY +} XHR_CRED_PROMPT; + +typedef [v1_enum] enum _XHR_AUTH +{ + XHR_AUTH_ALL, + XHR_AUTH_NONE, + XHR_AUTH_PROXY +} XHR_AUTH; + typedef [v1_enum] enum _XHR_PROPERTY { XHR_PROP_NO_CRED_PROMPT, From e13978fa3e8e23b7ab3bcfbca608808c0bab4426 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Fri, 11 Sep 2020 17:55:59 +1000 Subject: [PATCH 2332/2777] include: Remove interfaces already define in msxml6.idl Signed-off-by: Alistair Leslie-Hughes CW-Bug-Id: #22822 --- dlls/msxml3/factory.c | 1 + dlls/msxml3/tests/saxreader.c | 1 + dlls/msxml3/tests/schema.c | 5 ++ dlls/msxml3/uuid.c | 11 ++++ include/msxml2.idl | 109 ---------------------------------- include/msxml6.idl | 24 ++++---- 6 files changed, 30 insertions(+), 121 deletions(-) diff --git a/dlls/msxml3/factory.c b/dlls/msxml3/factory.c index c2d3cd30c60..243ee379712 100644 --- a/dlls/msxml3/factory.c +++ b/dlls/msxml3/factory.c @@ -31,6 +31,7 @@ #include "ole2.h" #include "msxml.h" #include "msxml2.h" +#include "msxml6.h" #include "xmlparser.h" /* undef the #define in msxml2 so that we can access the v.2 version diff --git a/dlls/msxml3/tests/saxreader.c b/dlls/msxml3/tests/saxreader.c index e123d4eba5a..48cfa8f5593 100644 --- a/dlls/msxml3/tests/saxreader.c +++ b/dlls/msxml3/tests/saxreader.c @@ -29,6 +29,7 @@ #include "windows.h" #include "ole2.h" #include "msxml2.h" +#include "msxml6.h" #include "msxml2did.h" #include "ocidl.h" #include "dispex.h" diff --git a/dlls/msxml3/tests/schema.c b/dlls/msxml3/tests/schema.c index 3d209c0e4a0..99c7d35cc10 100644 --- a/dlls/msxml3/tests/schema.c +++ b/dlls/msxml3/tests/schema.c @@ -32,6 +32,11 @@ #include "dispex.h" #include "cguid.h" +DEFINE_GUID(CLSID_MXXMLWriter60, 0x88d96a0f, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_SAXAttributes60, 0x88d96a0e, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_SAXXMLReader60, 0x88d96a0c, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_XMLSchemaCache60, 0x88d96a07, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); + #include "wine/test.h" #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) diff --git a/dlls/msxml3/uuid.c b/dlls/msxml3/uuid.c index 4abbe5e4763..333d4f3d3c7 100644 --- a/dlls/msxml3/uuid.c +++ b/dlls/msxml3/uuid.c @@ -41,6 +41,17 @@ #include "initguid.h" #include "msxml2.h" +/* Cannot include msxml6 here since we will get a duplicate LIBID_MSXML2 error. */ +DEFINE_GUID(CLSID_FreeThreadedDOMDocument60, 0x88d96a06, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_MXNamespaceManager60, 0x88d96a11, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_MXXMLWriter60, 0x88d96a0f, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_SAXAttributes60, 0x88d96a0e, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_SAXXMLReader60, 0x88d96a0c, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_ServerXMLHTTP60, 0x88d96a0b, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_XMLHTTP60, 0x88d96a0a, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_XMLSchemaCache60, 0x88d96a07, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_XSLTemplate60, 0x88d96a08, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); + /* * Note that because of a #define in msxml2.h, we end up initializing * CLSID_DOMDocument2 to be the v.3 version independent DOMDocument diff --git a/include/msxml2.idl b/include/msxml2.idl index 916e0e8ab3d..1d1ba7a5248 100644 --- a/include/msxml2.idl +++ b/include/msxml2.idl @@ -1612,15 +1612,6 @@ coclass FreeThreadedDOMDocument40 [default, source] dispinterface XMLDOMDocumentEvents; } -[ - uuid(88d96a06-f192-11d4-a65f-0040963251e5), -] -coclass FreeThreadedDOMDocument60 -{ - [default] interface IXMLDOMDocument3; - [default, source] dispinterface XMLDOMDocumentEvents; -} - [ helpstring("Free threaded XML DOM Document"), progid("Msxml2.FreeThreadedDOMDocument"), @@ -1662,14 +1653,6 @@ coclass XMLHTTP40 [default] interface IXMLHTTPRequest; } -[ - uuid(88d96a0a-f192-11d4-a65f-0040963251e5) -] -coclass XMLHTTP60 -{ - [default] interface IXMLHTTPRequest; -} - [ helpstring("XML HTTP"), progid("Msxml2.XMLHTTP"), @@ -1702,14 +1685,6 @@ coclass ServerXMLHTTP40 [default] interface IServerXMLHTTPRequest2; } -[ - uuid(88d96a0b-f192-11d4-a65f-0040963251e5) -] -coclass ServerXMLHTTP60 -{ - [default] interface IServerXMLHTTPRequest2; -} - [ helpstring("Server XML HTTP"), progid("Msxml2.ServerXMLHTTP"), @@ -1750,14 +1725,6 @@ coclass XMLSchemaCache40 [default] interface IXMLDOMSchemaCollection2; } -[ - uuid(88d96a07-f192-11d4-a65f-0040963251e5) -] -coclass XMLSchemaCache60 -{ - [default] interface IXMLDOMSchemaCollection2; -} - [ helpstring("XML Schema Cache"), progid("Msxml2.XMLSchemaCache"), @@ -1798,14 +1765,6 @@ coclass XSLTemplate40 [default] interface IXSLTemplate; } -[ - uuid(88d96a08-f192-11d4-a65f-0040963251e5) -] -coclass XSLTemplate60 -{ - [default] interface IXSLTemplate; -} - [ helpstring("XSL Template"), progid("Msxml2.XSLTemplate"), @@ -3297,15 +3256,6 @@ coclass SAXXMLReader40 interface ISAXXMLReader; } -[ - uuid(88d96a0c-f192-11d4-a65f-0040963251e5) -] -coclass SAXXMLReader60 -{ - [default] interface IVBSAXXMLReader; - interface ISAXXMLReader; -} - [ helpstring("SAX XML Reader"), progid("Msxml2.SAXXMLReader"), @@ -3380,26 +3330,6 @@ coclass MXHTMLWriter40 interface IVBSAXLexicalHandler; } -[ - uuid(88d96a10-f192-11d4-a65f-0040963251e5) -] -coclass MXHTMLWriter60 -{ - [default] interface IMXWriter; - - interface ISAXContentHandler; - interface ISAXDeclHandler; - interface ISAXDTDHandler; - interface ISAXErrorHandler; - interface ISAXLexicalHandler; - - interface IVBSAXContentHandler; - interface IVBSAXDeclHandler; - interface IVBSAXDTDHandler; - interface IVBSAXErrorHandler; - interface IVBSAXLexicalHandler; -} - [ helpstring("MXXMLWriter 3.0"), progid("Msxml2.MXXMLWriter.3.0"), @@ -3444,26 +3374,6 @@ coclass MXXMLWriter40 interface IVBSAXLexicalHandler; } -[ - uuid(88d96a0f-f192-11d4-a65f-0040963251e5) -] -coclass MXXMLWriter60 -{ - [default] interface IMXWriter; - - interface ISAXContentHandler; - interface ISAXDeclHandler; - interface ISAXDTDHandler; - interface ISAXErrorHandler; - interface ISAXLexicalHandler; - - interface IVBSAXContentHandler; - interface IVBSAXDeclHandler; - interface IVBSAXDTDHandler; - interface IVBSAXErrorHandler; - interface IVBSAXLexicalHandler; -} - [ helpstring("MXXMLWriter"), progid("Msxml2.MXXMLWriter"), @@ -3506,15 +3416,6 @@ coclass MXNamespaceManager40 interface IMXNamespaceManager; } -[ - uuid(88d96a11-f192-11d4-a65f-0040963251e5) -] -coclass MXNamespaceManager60 -{ - [default] interface IVBMXNamespaceManager; - interface IMXNamespaceManager; -} - [ helpstring("SAXAttributes 3.0"), progid("Msxml2.SAXAttributes.3.0"), @@ -3539,16 +3440,6 @@ coclass SAXAttributes40 interface ISAXAttributes; } -[ - uuid(88d96a0e-f192-11d4-a65f-0040963251e5) -] -coclass SAXAttributes60 -{ - [default] interface IMXAttributes; - interface IVBSAXAttributes; - interface ISAXAttributes; -} - [ helpstring("SAXAttributes"), progid("Msxml2.SAXAttributes"), diff --git a/include/msxml6.idl b/include/msxml6.idl index d4a5c490243..7396826a1f6 100644 --- a/include/msxml6.idl +++ b/include/msxml6.idl @@ -3065,18 +3065,6 @@ coclass DOMDocument60 [default, source] dispinterface XMLDOMDocumentEvents; } -[ - helpstring("Free threaded XML DOM Document 6.0"), - progid("Msxml2.FreeThreadedDOMDocument.6.0"), - threading(both), - uuid(88d96a06-f192-11d4-a65f-0040963251e5), -] -coclass FreeThreadedDOMDocument60 -{ - [default] interface IXMLDOMDocument3; - [default, source] dispinterface XMLDOMDocumentEvents; -} - [ helpstring("SAX XML Reader 6.0"), progid("Msxml2.SAXXMLReader.6.0"), @@ -3182,6 +3170,18 @@ coclass XSLTemplate60 [default] interface IXSLTemplate; } +[ + helpstring("Free threaded XML DOM Document 6.0"), + progid("Msxml2.FreeThreadedDOMDocument.6.0"), + threading(both), + uuid(88d96a06-f192-11d4-a65f-0040963251e5), +] +coclass FreeThreadedDOMDocument60 +{ + [default] interface IXMLDOMDocument3; + [default, source] dispinterface XMLDOMDocumentEvents; +} + [ helpstring("XML HTTP 6.0"), progid("Msxml2.XMLHTTP.6.0"), From fab157c128d108beddf7295514c840c8054a5a02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 8 Sep 2020 18:43:52 +0200 Subject: [PATCH 2333/2777] msxml3: Implement FreeThreadedXMLHTTP60. Update from Gijs Vermeulen CW-Bug-Id: #22822 --- dlls/msxml3/Makefile.in | 2 +- dlls/msxml3/factory.c | 5 + dlls/msxml3/httprequest.c | 495 +++++++++++++++++++++++++++++++++++- dlls/msxml3/msxml_private.h | 1 + dlls/msxml3/tests/httpreq.c | 395 +++++++++++++++++++++++++++- dlls/msxml3/tests/schema.c | 6 + dlls/msxml3/uuid.c | 5 + 7 files changed, 904 insertions(+), 5 deletions(-) diff --git a/dlls/msxml3/Makefile.in b/dlls/msxml3/Makefile.in index 2bf789732da..e2d737599b1 100644 --- a/dlls/msxml3/Makefile.in +++ b/dlls/msxml3/Makefile.in @@ -1,5 +1,5 @@ MODULE = msxml3.dll -IMPORTS = $(XSLT_PE_LIBS) $(XML2_PE_LIBS) uuid urlmon shlwapi oleaut32 ole32 user32 advapi32 +IMPORTS = $(XSLT_PE_LIBS) $(XML2_PE_LIBS) uuid urlmon shlwapi oleaut32 ole32 user32 advapi32 rtworkq EXTRAINCL = $(XSLT_PE_CFLAGS) $(XML2_PE_CFLAGS) C_SRCS = \ diff --git a/dlls/msxml3/factory.c b/dlls/msxml3/factory.c index 243ee379712..323c7b49848 100644 --- a/dlls/msxml3/factory.c +++ b/dlls/msxml3/factory.c @@ -279,6 +279,7 @@ static HRESULT DOMClassFactory_Create(const GUID *clsid, REFIID riid, void **ppv static ClassFactory xmldoccf = { { &ClassFactoryVtbl }, XMLDocument_create }; static ClassFactory httpreqcf = { { &ClassFactoryVtbl }, XMLHTTPRequest_create }; +static ClassFactory httpreqcf2 = { { &ClassFactoryVtbl }, XMLHTTPRequest2_create }; static ClassFactory serverhttp = { { &ClassFactoryVtbl }, ServerXMLHTTP_create }; static ClassFactory xsltemplatecf = { { &ClassFactoryVtbl }, XSLTemplate_create }; static ClassFactory mxnsmanagercf = { {&ClassFactoryVtbl }, MXNamespaceManager_create }; @@ -340,6 +341,10 @@ HRESULT WINAPI DllGetClassObject( REFCLSID rclsid, REFIID riid, void **ppv ) { cf = &httpreqcf.IClassFactory_iface; } + else if( IsEqualCLSID( rclsid, &CLSID_FreeThreadedXMLHTTP60 )) + { + cf = &httpreqcf2.IClassFactory_iface; + } else if( IsEqualCLSID( rclsid, &CLSID_ServerXMLHTTP ) || IsEqualCLSID( rclsid, &CLSID_ServerXMLHTTP30 ) || IsEqualCLSID( rclsid, &CLSID_ServerXMLHTTP40 ) || diff --git a/dlls/msxml3/httprequest.c b/dlls/msxml3/httprequest.c index cc384a380e5..98dd23c9fbb 100644 --- a/dlls/msxml3/httprequest.c +++ b/dlls/msxml3/httprequest.c @@ -38,10 +38,12 @@ #include "shlwapi.h" #include "msxml_dispex.h" +#include "initguid.h" +#include "rtworkq.h" #include "wine/debug.h" -WINE_DEFAULT_DEBUG_CHANNEL(msxml); +WINE_DEFAULT_DEBUG_CHANNEL(xmlhttp); static const WCHAR colspaceW[] = {':',' ',0}; static const WCHAR crlfW[] = {'\r','\n',0}; @@ -2058,6 +2060,468 @@ static const struct IServerXMLHTTPRequestVtbl ServerXMLHTTPRequestVtbl = ServerXMLHTTPRequest_setOption }; +static DWORD xhr2_work_queue; + +struct xml_http_request_2 +{ + httprequest req; + IXMLHTTPRequest3 IXMLHTTPRequest3_iface; + IRtwqAsyncCallback IRtwqAsyncCallback_iface; + IDispatch IDispatch_iface; + + IXMLHTTPRequest2Callback *callback; + IXMLHTTPRequest3Callback *callback3; + ISequentialStream *response_body; + ISequentialStream *request_body; + ULONGLONG request_body_size; +}; + +static inline struct xml_http_request_2 *impl_from_IXMLHTTPRequest3(IXMLHTTPRequest3 *iface) +{ + return CONTAINING_RECORD(iface, struct xml_http_request_2, IXMLHTTPRequest3_iface); +} + +static inline struct xml_http_request_2 *xml_http_request_2_from_IRtwqAsyncCallback(IRtwqAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct xml_http_request_2, IRtwqAsyncCallback_iface); +} + +static inline struct xml_http_request_2 *xml_http_request_2_from_IDispatch(IDispatch *iface) +{ + return CONTAINING_RECORD(iface, struct xml_http_request_2, IDispatch_iface); +} + +static HRESULT WINAPI xml_http_request_2_QueryInterface(IXMLHTTPRequest3 *iface, REFIID riid, void **obj) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); + + if (IsEqualGUID(riid, &IID_IXMLHTTPRequest3) || IsEqualGUID(riid, &IID_IXMLHTTPRequest2) + || IsEqualGUID(riid, &IID_IUnknown)) + { + *obj = iface; + IUnknown_AddRef((IUnknown*)*obj); + return S_OK; + } + + FIXME("Unsupported interface %s\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI xml_http_request_2_AddRef(IXMLHTTPRequest3 *iface) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + ULONG ref = InterlockedIncrement(&This->req.ref); + TRACE("(%p)->(%lu)\n", This, ref); + return ref; +} + +static ULONG WINAPI xml_http_request_2_Release(IXMLHTTPRequest3 *iface) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + ULONG ref = InterlockedDecrement(&This->req.ref); + + TRACE("(%p)->(%lu)\n", This, ref); + + if (ref == 0) + { + /* do not call httprequest_put_onreadystatechange to avoid ref cycle */ + This->req.sink = NULL; + if (This->response_body) ISequentialStream_Release(This->response_body); + if (This->request_body) ISequentialStream_Release(This->request_body); + if (This->callback3) IXMLHTTPRequest3Callback_Release(This->callback3); + if (This->callback) IXMLHTTPRequest2Callback_Release(This->callback); + heap_free(This); + RtwqShutdown(); + } + + return ref; +} + +static HRESULT WINAPI xml_http_request_2_Open(IXMLHTTPRequest3 *iface, const WCHAR *method, + const WCHAR *url, IXMLHTTPRequest2Callback *callback, + const WCHAR *username, const WCHAR *password, + const WCHAR *proxy_username, const WCHAR *proxy_password) +{ + static const WCHAR accept_encoding[] = {'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0}; + static const WCHAR empty = 0; + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + VARIANT async_v, username_v, password_v; + HRESULT hr; + + TRACE("(%p)->(%s %s %p %s %s %s %s)\n", This, debugstr_w(method), debugstr_w(url), callback, + debugstr_w(username), debugstr_w(password), debugstr_w(proxy_username), debugstr_w(proxy_password)); + + if (This->callback) IXMLHTTPRequest2Callback_Release(This->callback); + if (This->callback3) IXMLHTTPRequest3Callback_Release(This->callback3); + IXMLHTTPRequest2Callback_AddRef(callback); + This->callback = callback; + if (FAILED(IXMLHTTPRequest2Callback_QueryInterface(callback, &IID_IXMLHTTPRequest3Callback, (void **)&This->callback3))) + This->callback3 = NULL; + + if (proxy_username || proxy_password) FIXME("proxy credentials not implemented\n"); + + VariantInit(&async_v); + V_VT(&async_v) = VT_BOOL; + V_BOOL(&async_v) = FALSE; /* FIXME: TRUE needs a RTWQ_WINDOW_WORKQUEUE */ + + VariantInit(&username_v); + V_VT(&username_v) = VT_BSTR; + if (username) V_BSTR(&username_v) = SysAllocString(username); + else V_BSTR(&username_v) = SysAllocString(&empty); + + VariantInit(&password_v); + V_VT(&password_v) = VT_BSTR; + if (password) V_BSTR(&password_v) = SysAllocString(password); + else V_BSTR(&password_v) = SysAllocString(&empty); + + if (FAILED(hr = httprequest_open(&This->req, (BSTR)method, (BSTR)url, async_v, username_v, password_v))) + return hr; + return httprequest_setRequestHeader(&This->req, (BSTR)accept_encoding, (BSTR)&empty); +} + +static HRESULT WINAPI xml_http_request_2_Send(IXMLHTTPRequest3 *iface, ISequentialStream *body, ULONGLONG body_size) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + IRtwqAsyncResult *result; + HRESULT hr; + + TRACE("(%p)->(%p %s)\n", This, body, wine_dbgstr_longlong( body_size )); + + if (body_size) + { + ISequentialStream_AddRef(body); + This->request_body = body; + This->request_body_size = body_size; + } + + if (FAILED(hr = RtwqCreateAsyncResult(NULL, &This->IRtwqAsyncCallback_iface, NULL, &result))) + return hr; + // IRtwqAsyncCallback_Invoke(&This->IRtwqAsyncCallback_iface, result); + hr = RtwqPutWorkItem(xhr2_work_queue, 0, result); + if (result) IRtwqAsyncResult_Release(result); + + return hr; +} + +static HRESULT WINAPI xml_http_request_2_Abort(IXMLHTTPRequest3 *iface) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + TRACE("(%p) stub!\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI xml_http_request_2_SetCookie(IXMLHTTPRequest3 *iface, const XHR_COOKIE *cookie, DWORD *state) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + FIXME("(%p)->(%p %p) stub!\n", This, cookie, state); + return E_NOTIMPL; +} + +static HRESULT WINAPI xml_http_request_2_SetCustomResponseStream(IXMLHTTPRequest3 *iface, ISequentialStream *stream) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + FIXME("(%p)->(%p) stub!\n", This, stream); + return E_NOTIMPL; +} + +static HRESULT WINAPI xml_http_request_2_SetProperty(IXMLHTTPRequest3 *iface, XHR_PROPERTY property, ULONGLONG value) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + FIXME("(%p)->(%#x %s) stub!\n", This, property, wine_dbgstr_longlong( value )); + return E_NOTIMPL; +} + +static HRESULT WINAPI xml_http_request_2_SetRequestHeader(IXMLHTTPRequest3 *iface, + const WCHAR *header, const WCHAR *value) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + TRACE("(%p)->(%s %s)\n", This, debugstr_w(header), debugstr_w(value)); + return httprequest_setRequestHeader(&This->req, (BSTR)header, (BSTR)value); +} + +static HRESULT WINAPI xml_http_request_2_GetAllResponseHeaders(IXMLHTTPRequest3 *iface, WCHAR **headers) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + FIXME("(%p)->(%p) stub!\n", This, headers); + return E_NOTIMPL; +} + +static HRESULT WINAPI xml_http_request_2_GetCookie(IXMLHTTPRequest3 *iface, const WCHAR *url, + const WCHAR *name, DWORD flags, + ULONG *cookies_count, XHR_COOKIE **cookies) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + FIXME("(%p)->(%s %s %ld %p %p) stub!\n", This, debugstr_w(url), debugstr_w(name), flags, cookies_count, cookies); + return E_NOTIMPL; +} + +static HRESULT WINAPI xml_http_request_2_GetResponseHeader(IXMLHTTPRequest3 *iface, + const WCHAR *header, WCHAR **value) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + HRESULT hr; + + TRACE("(%p)->(%s %p)\n", This, debugstr_w(header), value); + + if (FAILED(hr = httprequest_getResponseHeader(&This->req, (BSTR)header, value))) + return hr; + +#define E_FILE_NOT_FOUND _HRESULT_TYPEDEF_(0x80070002) + + if (hr == S_FALSE) + { + *value = NULL; + return E_FILE_NOT_FOUND; + } + + return hr; +} + +static HRESULT WINAPI xml_http_request_3_SetClientCertificate(IXMLHTTPRequest3 *iface, DWORD count, const BYTE *hashes, const WCHAR *pin) +{ + struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); + FIXME("(%p)->(%ld %p %s) stub!\n", This, count, hashes, debugstr_w(pin)); + return E_NOTIMPL; +} + +static const struct IXMLHTTPRequest3Vtbl XMLHTTPRequest3Vtbl = { + /* IUnknown methods */ + xml_http_request_2_QueryInterface, + xml_http_request_2_AddRef, + xml_http_request_2_Release, + /* IXMLHTTPRequest2 methods */ + xml_http_request_2_Open, + xml_http_request_2_Send, + xml_http_request_2_Abort, + xml_http_request_2_SetCookie, + xml_http_request_2_SetCustomResponseStream, + xml_http_request_2_SetProperty, + xml_http_request_2_SetRequestHeader, + xml_http_request_2_GetAllResponseHeaders, + xml_http_request_2_GetCookie, + xml_http_request_2_GetResponseHeader, + /* IXMLHTTPRequest3 methods */ + xml_http_request_3_SetClientCertificate, +}; + +static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_QueryInterface(IRtwqAsyncCallback *iface, REFIID riid, void **obj) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); + + if (IsEqualGUID(riid, &IID_IRtwqAsyncCallback) || IsEqualGUID(riid, &IID_IUnknown)) + { + IRtwqAsyncCallback_AddRef(iface); + *obj = iface; + return S_OK; + } + + FIXME("Unsupported interface %s\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI xml_http_request_2_IRtwqAsyncCallback_AddRef(IRtwqAsyncCallback *iface) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); + TRACE("(%p)\n", This); + return xml_http_request_2_AddRef(&This->IXMLHTTPRequest3_iface); +} + +static ULONG WINAPI xml_http_request_2_IRtwqAsyncCallback_Release(IRtwqAsyncCallback *iface) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); + TRACE("(%p)\n", This); + return xml_http_request_2_Release(&This->IXMLHTTPRequest3_iface); +} + +static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_GetParameters(IRtwqAsyncCallback *iface, + DWORD *flags, DWORD *queue) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); + + TRACE("(%p)->(%p %p)\n", This, flags, queue); + + *flags = 0; + *queue = xhr2_work_queue; + return S_OK; +} + +static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_Invoke(IRtwqAsyncCallback *iface, + IRtwqAsyncResult *result) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); + VARIANT body_v; + HRESULT hr; + ULONG read; + + TRACE("(%p)->(%p)\n", This, result); + + VariantInit(&body_v); + + if (This->request_body) + { + V_VT(&body_v) = VT_BSTR; + V_BSTR(&body_v) = CoTaskMemAlloc(This->request_body_size); + + if (FAILED(hr = ISequentialStream_Read(This->request_body, V_BSTR(&body_v), This->request_body_size, &read)) || + read < This->request_body_size) + { + ERR("Failed to allocate request body memory, hr %#lx\n", hr); + CoTaskMemFree(V_BSTR(&body_v)); + goto done; + } + + ISequentialStream_Release(This->request_body); + This->request_body = NULL; + } + + hr = httprequest_send(&This->req, body_v); + +done: + return IRtwqAsyncResult_SetStatus(result, hr); +} + +static const struct IRtwqAsyncCallbackVtbl xml_http_request_2_IRtwqAsyncCallbackVtbl = { + /* IUnknown methods */ + xml_http_request_2_IRtwqAsyncCallback_QueryInterface, + xml_http_request_2_IRtwqAsyncCallback_AddRef, + xml_http_request_2_IRtwqAsyncCallback_Release, + /* IRtwqAsyncCallback methods */ + xml_http_request_2_IRtwqAsyncCallback_GetParameters, + xml_http_request_2_IRtwqAsyncCallback_Invoke, +}; + +static HRESULT WINAPI xml_http_request_2_IDispatch_QueryInterface(IDispatch *iface, REFIID riid, void **obj) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); + + if (IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, &IID_IUnknown)) + { + IDispatch_AddRef(iface); + *obj = iface; + return S_OK; + } + + FIXME("Unsupported interface %s\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI xml_http_request_2_IDispatch_AddRef(IDispatch *iface) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); + TRACE("(%p)\n", This); + return xml_http_request_2_AddRef(&This->IXMLHTTPRequest3_iface); +} + +static ULONG WINAPI xml_http_request_2_IDispatch_Release(IDispatch *iface) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); + TRACE("(%p)\n", This); + return xml_http_request_2_Release(&This->IXMLHTTPRequest3_iface); +} + +static HRESULT WINAPI xml_http_request_2_IDispatch_GetTypeInfoCount(IDispatch *iface, UINT *value) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); + FIXME("(%p)->(%p) stub!\n", This, value); + *value = 0; + return S_OK; +} + +static HRESULT WINAPI xml_http_request_2_IDispatch_GetTypeInfo(IDispatch *iface, UINT index, + LCID lcid, ITypeInfo **value) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); + FIXME("(%p)->(%d %lu %p) stub!\n", This, index, lcid, value); + *value = NULL; + return S_OK; +} + +static HRESULT WINAPI xml_http_request_2_IDispatch_GetIDsOfNames(IDispatch *iface, REFIID riid, + OLECHAR **names, UINT names_count, + LCID lcid, DISPID *disp_ids) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); + FIXME("(%p)->(%s %p %d %lu %p) stub!\n", This, debugstr_guid(riid), names, names_count, lcid, disp_ids); + return S_OK; +} + +static HRESULT WINAPI xml_http_request_2_IDispatch_Invoke(IDispatch *iface, DISPID id, REFIID riid, + LCID lcid, WORD flags, DISPPARAMS *params, + VARIANT *result, EXCEPINFO *exception, UINT *arg_err) +{ + struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); + IXMLHTTPRequest2 *xhr2_iface = (IXMLHTTPRequest2*)&This->IXMLHTTPRequest3_iface; + HRESULT hr; + LONG status; + BSTR status_str = NULL; + + TRACE("(%p)->(%ld %s %lu %d %p %p %p %p) stub!\n", This, id, debugstr_guid(riid), lcid, flags, + params, result, exception, arg_err); + + if (This->req.state == READYSTATE_COMPLETE) + { + VARIANT body_v; + VariantInit(&body_v); + + IXMLHTTPRequest2Callback_AddRef(This->callback); + if (This->callback3) + { + IXMLHTTPRequest3Callback_AddRef(This->callback3); + IXMLHTTPRequest3Callback_OnServerCertificateReceived(This->callback3, (IXMLHTTPRequest3 *)xhr2_iface, 0, 1, NULL); + IXMLHTTPRequest3Callback_Release(This->callback3); + } + + if (FAILED(hr = httprequest_get_status(&This->req, &status)) || + FAILED(hr = httprequest_get_statusText(&This->req, &status_str))) + { + WARN("failed to get response status, error %#lx\n", hr); + IXMLHTTPRequest2Callback_OnError(This->callback, xhr2_iface, hr); + IXMLHTTPRequest2Callback_Release(This->callback); + return S_OK; + } + + IXMLHTTPRequest2Callback_OnHeadersAvailable(This->callback, xhr2_iface, status, status_str); + SysFreeString(status_str); + + if (This->response_body) ISequentialStream_Release(This->response_body); + This->response_body = NULL; + + if (FAILED(hr = httprequest_get_responseStream(&This->req, &body_v)) || + FAILED(hr = IUnknown_QueryInterface(V_UNKNOWN(&body_v), &IID_ISequentialStream, (void **)&This->response_body))) + { + WARN("failed to get response stream, error %#lx\n", hr); + IXMLHTTPRequest2Callback_OnError(This->callback, xhr2_iface, hr); + IXMLHTTPRequest2Callback_Release(This->callback); + return S_OK; + } + + IXMLHTTPRequest2Callback_OnDataAvailable(This->callback, xhr2_iface, This->response_body); + IXMLHTTPRequest2Callback_OnResponseReceived(This->callback, xhr2_iface, This->response_body); + IXMLHTTPRequest2Callback_Release(This->callback); + } + + return S_OK; +} + +static const struct IDispatchVtbl xml_http_request_2_IDispatchVtbl = { + /* IUnknown methods */ + xml_http_request_2_IDispatch_QueryInterface, + xml_http_request_2_IDispatch_AddRef, + xml_http_request_2_IDispatch_Release, + /* IDispatch methods */ + xml_http_request_2_IDispatch_GetTypeInfoCount, + xml_http_request_2_IDispatch_GetTypeInfo, + xml_http_request_2_IDispatch_GetIDsOfNames, + xml_http_request_2_IDispatch_Invoke, +}; + static void init_httprequest(httprequest *req) { req->IXMLHTTPRequest_iface.lpVtbl = &XMLHTTPRequestVtbl; @@ -2107,6 +2571,35 @@ HRESULT XMLHTTPRequest_create(void **obj) return S_OK; } +HRESULT XMLHTTPRequest2_create(void **obj) +{ + struct xml_http_request_2 *xhr2; + TRACE("(%p)\n", obj); + + if (!(xhr2 = heap_alloc(sizeof(*xhr2)))) return E_OUTOFMEMORY; + + init_httprequest(&xhr2->req); + xhr2->IXMLHTTPRequest3_iface.lpVtbl = &XMLHTTPRequest3Vtbl; + xhr2->IRtwqAsyncCallback_iface.lpVtbl = &xml_http_request_2_IRtwqAsyncCallbackVtbl; + xhr2->IDispatch_iface.lpVtbl = &xml_http_request_2_IDispatchVtbl; + + /* do not call httprequest_put_onreadystatechange to avoid ref cycle */ + xhr2->req.sink = &xhr2->IDispatch_iface; + + xhr2->callback = NULL; + xhr2->callback3 = NULL; + xhr2->request_body = NULL; + xhr2->response_body = NULL; + + /* for async http requests we need window message queue */ + RtwqStartup(); + if (!xhr2_work_queue) RtwqAllocateWorkQueue(RTWQ_MULTITHREADED_WORKQUEUE, &xhr2_work_queue); + + *obj = &xhr2->IXMLHTTPRequest3_iface; + TRACE("returning iface %p\n", *obj); + return S_OK; +} + HRESULT ServerXMLHTTP_create(void **obj) { serverhttp *req; diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h index cd8ae547c73..f3c9edd2c70 100644 --- a/dlls/msxml3/msxml_private.h +++ b/dlls/msxml3/msxml_private.h @@ -344,6 +344,7 @@ extern HRESULT XMLDocument_create(void**) DECLSPEC_HIDDEN; extern HRESULT SAXXMLReader_create(MSXML_VERSION, void**) DECLSPEC_HIDDEN; extern HRESULT SAXAttributes_create(MSXML_VERSION, void**) DECLSPEC_HIDDEN; extern HRESULT XMLHTTPRequest_create(void **) DECLSPEC_HIDDEN; +extern HRESULT XMLHTTPRequest2_create(void **) DECLSPEC_HIDDEN; extern HRESULT ServerXMLHTTP_create(void **) DECLSPEC_HIDDEN; extern HRESULT XSLTemplate_create(void**) DECLSPEC_HIDDEN; extern HRESULT MXWriter_create(MSXML_VERSION, void**) DECLSPEC_HIDDEN; diff --git a/dlls/msxml3/tests/httpreq.c b/dlls/msxml3/tests/httpreq.c index bccfbaf582a..23d7680d196 100644 --- a/dlls/msxml3/tests/httpreq.c +++ b/dlls/msxml3/tests/httpreq.c @@ -26,9 +26,9 @@ #include #include "windows.h" - #include "msxml2.h" -#include "msxml2did.h" +#include "msxml6.h" +#include "msxml6did.h" #include "dispex.h" #include "initguid.h" @@ -1344,6 +1344,17 @@ static IXMLHttpRequest *create_xhr(void) return SUCCEEDED(hr) ? ret : NULL; } +static IXMLHTTPRequest2 *create_xhr2(void) +{ + IXMLHTTPRequest2 *ret; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_FreeThreadedXMLHTTP60, NULL, CLSCTX_INPROC_SERVER, + &IID_IXMLHTTPRequest2, (void**)&ret); + + return SUCCEEDED(hr) ? ret : NULL; +} + static IServerXMLHTTPRequest *create_server_xhr(void) { IServerXMLHTTPRequest *ret; @@ -1904,11 +1915,388 @@ static void test_supporterrorinfo(void) IServerXMLHTTPRequest_Release(server_xhr); } +struct xhr3_callback +{ + IXMLHTTPRequest3Callback IXMLHTTPRequest3Callback_iface; + LONG ref; + HANDLE event; +}; + +static inline struct xhr3_callback *xhr3_callback_from_IXMLHTTPRequest3Callback(IXMLHTTPRequest3Callback *iface) +{ + return CONTAINING_RECORD(iface, struct xhr3_callback, IXMLHTTPRequest3Callback_iface); +} + +static HRESULT WINAPI xhr3_callback_QueryInterface(IXMLHTTPRequest3Callback *iface, REFIID riid, void **obj) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + trace("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); + + if (IsEqualGUID(riid, &IID_IXMLHTTPRequest3Callback) || IsEqualGUID(riid, &IID_IXMLHTTPRequest2Callback) || IsEqualGUID(riid, &IID_IUnknown)) + { + IXMLHTTPRequest3Callback_AddRef(iface); + *obj = iface; + return S_OK; + } + + ok(0, "unexpected interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI xhr3_callback_AddRef(IXMLHTTPRequest3Callback *iface) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + ULONG ref = InterlockedIncrement(&This->ref); + trace("(%p)->(%lu)\n", This, ref); + return ref; +} + +static ULONG WINAPI xhr3_callback_Release(IXMLHTTPRequest3Callback *iface) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + ULONG ref = InterlockedDecrement(&This->ref); + trace("(%p)->(%lu)\n", This, ref); + if (ref == 0) HeapFree(GetProcessHeap(), 0, This); + return ref; +} + +static HRESULT WINAPI xhr3_callback_OnRedirect(IXMLHTTPRequest3Callback *iface, + IXMLHTTPRequest2 *request, const WCHAR* redirect_url) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + trace("(%p)->(%p %s)\n", This, request, debugstr_w(redirect_url)); + return S_OK; +} + +static HRESULT WINAPI xhr3_callback_OnHeadersAvailable(IXMLHTTPRequest3Callback *iface, + IXMLHTTPRequest2 *request, DWORD status, const WCHAR *status_str) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + WCHAR *header = NULL; + HRESULT hr; + + trace("(%p)->(%p %lu %s)\n", This, request, status, debugstr_w(status_str)); + + header = (void *)0xdeadbeef; + hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Content-Length", &header); + trace("Content-Length: %p (%s), hr %#lx\n", header, debugstr_w(header), hr); + + return S_OK; +} + +static HRESULT WINAPI xhr3_callback_OnDataAvailable(IXMLHTTPRequest3Callback *iface, + IXMLHTTPRequest2 *request, ISequentialStream *response) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + trace("(%p)->(%p %p)\n", This, request, response); + return S_OK; +} + +static HRESULT WINAPI xhr3_callback_OnResponseReceived(IXMLHTTPRequest3Callback *iface, + IXMLHTTPRequest2 *request, ISequentialStream *response) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + WCHAR *header = NULL; + char *buffer = HeapAlloc( GetProcessHeap(), 0, 256 ); + ULONG read_size = 0; + HRESULT hr; + + memset(buffer, '?', 256); + buffer[255] = 0; + + trace("(%p)->(%p %p)\n", This, request, response); + + header = (void *)0xdeadbeef; + hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Cache-Control", &header); + trace("Cache-Control: %p (%s), hr %#lx\n", header, debugstr_w(header), hr); + + header = (void *)0xdeadbeef; + hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Expires", &header); + trace("Expires: %p (%s), hr %#lx\n", header, debugstr_w(header), hr); + + header = (void *)0xdeadbeef; + hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Content-Type", &header); + trace("Content-Type: %p (%s), hr %#lx\n", header, debugstr_w(header), hr); + + read_size = 0xdeadbeef; + hr = ISequentialStream_Read(response, buffer, 214, &read_size); + trace("Response: (%ld) %s, hr %#lx\n", read_size, debugstr_a(buffer), hr); + + read_size = 0xdeadbeef; + hr = ISequentialStream_Read(response, buffer, 1, &read_size); + trace("Response: (%ld) %s, hr %#lx\n", read_size, debugstr_a(buffer), hr); + + HeapFree( GetProcessHeap(), 0, buffer ); + SetEvent(This->event); + + return S_OK; +} + +static HRESULT WINAPI xhr3_callback_OnError(IXMLHTTPRequest3Callback *iface, + IXMLHTTPRequest2 *request, HRESULT error) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + trace("(%p)->(%p %#lx)\n", This, request, error); + SetEvent(This->event); + return S_OK; +} + +static HRESULT WINAPI xhr3_callback_OnServerCertificateReceived(IXMLHTTPRequest3Callback *iface, + IXMLHTTPRequest3 *request, DWORD errors, DWORD chain_size, const XHR_CERT *chain) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + trace("(%p)->(%p %lu %lu %p)\n", This, request, errors, chain_size, chain); + return S_OK; +} + +static HRESULT WINAPI xhr3_callback_OnClientCertificateRequested(IXMLHTTPRequest3Callback *iface, + IXMLHTTPRequest3 *request, DWORD issuers_size, const WCHAR **issuers) +{ + struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); + trace("(%p)->(%p %lu %p)\n", This, request, issuers_size, issuers); + return S_OK; +} + +static const IXMLHTTPRequest3CallbackVtbl xhr3_callback_vtbl = +{ + xhr3_callback_QueryInterface, + xhr3_callback_AddRef, + xhr3_callback_Release, + /* IXMLHTTPRequest2Callback methods */ + xhr3_callback_OnRedirect, + xhr3_callback_OnHeadersAvailable, + xhr3_callback_OnDataAvailable, + xhr3_callback_OnResponseReceived, + xhr3_callback_OnError, + /* IXMLHTTPRequest3Callback methods */ + xhr3_callback_OnServerCertificateReceived, + xhr3_callback_OnClientCertificateRequested, +}; + +static IXMLHTTPRequest2Callback* xhr3_callback_create(HANDLE event) +{ + struct xhr3_callback *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + ok(This != NULL, "failed to allocate object\n"); + if (!This) return NULL; + + This->IXMLHTTPRequest3Callback_iface.lpVtbl = &xhr3_callback_vtbl; + This->ref = 1; + This->event = event; + + return (IXMLHTTPRequest2Callback*)&This->IXMLHTTPRequest3Callback_iface; +} + +struct xhr2_stream +{ + IStream IStream_iface; + LONG ref; + IStream *stream; +}; + +static inline struct xhr2_stream *xhr2_stream_from_IStream(IStream *iface) +{ + return CONTAINING_RECORD(iface, struct xhr2_stream, IStream_iface); +} + +static HRESULT WINAPI xhr2_stream_QueryInterface(IStream *iface, REFIID riid, void **obj) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); + + if (IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_ISequentialStream) || IsEqualGUID(riid, &IID_IUnknown)) + { + IStream_AddRef(iface); + *obj = iface; + return S_OK; + } + + ok(0, "unexpected interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI xhr2_stream_AddRef(IStream *iface) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + ULONG ref = InterlockedIncrement(&This->ref); + trace("(%p)->(%lu)\n", This, ref); + return ref; +} + +static ULONG WINAPI xhr2_stream_Release(IStream *iface) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + ULONG ref = InterlockedDecrement(&This->ref); + trace("(%p)->(%lu)\n", This, ref); + if (ref == 0) + { + IStream_Release(This->stream); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +static HRESULT WINAPI xhr2_stream_Read(IStream *iface, void *pv, ULONG cb, + ULONG *pcbRead) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%p %lu %p)\n", This, pv, cb, pcbRead); + return IStream_Read(This->stream, pv, cb, pcbRead); +} + +static HRESULT WINAPI xhr2_stream_Write(IStream *iface, const void *pv, + ULONG cb, ULONG *pcbWritten) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%p %lu %p)\n", This, pv, cb, pcbWritten); + return IStream_Write(This->stream, pv, cb, pcbWritten); +} + +static HRESULT WINAPI xhr2_stream_Seek(IStream *iface, LARGE_INTEGER dlibMove, + DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%I64u, %lu %p)\n", This, dlibMove.QuadPart, dwOrigin, plibNewPosition); + return IStream_Seek(This->stream, dlibMove, dwOrigin, plibNewPosition); +} + +static HRESULT WINAPI xhr2_stream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%I64u)\n", This, libNewSize.QuadPart); + return IStream_SetSize(This->stream, libNewSize); +} + +static HRESULT WINAPI xhr2_stream_CopyTo(IStream *iface, IStream *pstm, + ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%p %I64u %p %p)\n", This, pstm, cb.QuadPart, pcbRead, pcbWritten); + return IStream_CopyTo(This->stream, pstm, cb, pcbRead, pcbWritten); +} + +static HRESULT WINAPI xhr2_stream_Commit(IStream *iface, DWORD grfCommitFlags) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%#lx)\n", This, grfCommitFlags); + return IStream_Commit(This->stream, grfCommitFlags); +} + +static HRESULT WINAPI xhr2_stream_Revert(IStream *iface) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->()\n", This); + return IStream_Revert(This->stream); +} + +static HRESULT WINAPI xhr2_stream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset, + ULARGE_INTEGER cb, DWORD dwLockType) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%I64u %I64u %lu)\n", This, libOffset.QuadPart, cb.QuadPart, dwLockType); + return IStream_LockRegion(This->stream, libOffset, cb, dwLockType); +} + +static HRESULT WINAPI xhr2_stream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset, + ULARGE_INTEGER cb, DWORD dwLockType) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%I64u %I64u %lu)\n", This, libOffset.QuadPart, cb.QuadPart, dwLockType); + return IStream_UnlockRegion(This->stream, libOffset, cb, dwLockType); +} + +static HRESULT WINAPI xhr2_stream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%p %#lx)\n", This, pstatstg, grfStatFlag); + return IStream_Stat(This->stream, pstatstg, grfStatFlag); +} + +static HRESULT WINAPI xhr2_stream_Clone(IStream *iface, IStream **ppstm) +{ + struct xhr2_stream *This = xhr2_stream_from_IStream(iface); + trace("(%p)->(%p)\n", This, ppstm); + return IStream_Clone(This->stream, ppstm); +} + +static const IStreamVtbl xhr2_stream_vtbl = +{ + xhr2_stream_QueryInterface, + xhr2_stream_AddRef, + xhr2_stream_Release, + /* IStream methods */ + xhr2_stream_Read, + xhr2_stream_Write, + xhr2_stream_Seek, + xhr2_stream_SetSize, + xhr2_stream_CopyTo, + xhr2_stream_Commit, + xhr2_stream_Revert, + xhr2_stream_LockRegion, + xhr2_stream_UnlockRegion, + xhr2_stream_Stat, + xhr2_stream_Clone +}; + +static ISequentialStream *xhr2_stream_create(void) +{ + struct xhr2_stream *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + ok(This != NULL, "failed to allocate object\n"); + if (!This) return NULL; + + This->IStream_iface.lpVtbl = &xhr2_stream_vtbl; + This->ref = 1; + CreateStreamOnHGlobal(NULL, TRUE, &This->stream); + + return (ISequentialStream*)&This->IStream_iface; +} + +static void test_IXMLHTTPRequest2(void) +{ + IXMLHTTPRequest2 *xhr2[16]; + IXMLHTTPRequest2Callback *xhr3_callback; + ISequentialStream *stream; + HANDLE events[16]; + HRESULT hr; + int i = 0; + + if (!(xhr2[i] = create_xhr2())) + { + win_skip("IXMLHTTPRequest2 is not available\n"); + return; + } + + events[i] = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!(xhr3_callback = xhr3_callback_create(events[i]))) + return; + + trace("%lu: IXMLHTTPRequest2_Open (%p)->(L\"GET\", L\"http://test.winehq.org/\", xhr3_callback, NULL, NULL, NULL, NULL)\n", GetCurrentThreadId(), xhr2[i]); + hr = IXMLHTTPRequest2_Open(xhr2[i], L"GET", L"http://test.winehq.org/", xhr3_callback, NULL, NULL, NULL, NULL); + ok(SUCCEEDED(hr), "IXMLHTTPRequest2_Send failed %#lx\n", hr); + + if ((stream = xhr2_stream_create())) + { + trace("%lu: IXMLHTTPRequest2_Send (%p)->(%p 0)\n", GetCurrentThreadId(), xhr2[i], stream); + hr = IXMLHTTPRequest2_Send(xhr2[i], stream, 0); + ok(SUCCEEDED(hr), "IXMLHTTPRequest2_Send failed %#lx\n", hr); + + ISequentialStream_Release(stream); + } + + IXMLHTTPRequest2Callback_Release(xhr3_callback); + i++; + + while (i--) + { + WaitForSingleObject(events[i], INFINITE); + IXMLHTTPRequest2_Release(xhr2[i]); + } +} + START_TEST(httpreq) { IXMLHttpRequest *xhr; - CoInitialize(NULL); + CoInitializeEx(NULL, COINIT_MULTITHREADED); if (!(xhr = create_xhr())) { @@ -1923,6 +2311,7 @@ START_TEST(httpreq) test_server_xhr(); test_safe_httpreq(); test_supporterrorinfo(); + test_IXMLHTTPRequest2(); CoUninitialize(); } diff --git a/dlls/msxml3/tests/schema.c b/dlls/msxml3/tests/schema.c index 99c7d35cc10..2b63182e2e4 100644 --- a/dlls/msxml3/tests/schema.c +++ b/dlls/msxml3/tests/schema.c @@ -32,10 +32,16 @@ #include "dispex.h" #include "cguid.h" +DEFINE_GUID(CLSID_FreeThreadedDOMDocument60, 0x88d96a06, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_FreeThreadedXMLHTTP60, 0x88d96a09, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_MXXMLWriter60, 0x88d96a0f, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_SAXAttributes60, 0x88d96a0e, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_SAXXMLReader60, 0x88d96a0c, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_XMLSchemaCache60, 0x88d96a07, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(IID_IXMLHTTPRequest2, 0xe5d37dc0, 0x552a, 0x4d52, 0x9c,0xc0, 0xa1,0x4d,0x54,0x6f,0xbd,0x04); +DEFINE_GUID(IID_IXMLHTTPRequest3, 0xa1c9feee, 0x0617, 0x4f23, 0x9d,0x58, 0x89,0x61,0xea,0x43,0x56,0x7c); +DEFINE_GUID(IID_IXMLHTTPRequest2Callback, 0xa44a9299, 0xe321, 0x40de, 0x88,0x66, 0x34,0x1b,0x41,0x66,0x91,0x62); +DEFINE_GUID(IID_IXMLHTTPRequest3Callback, 0xb9e57830, 0x8c6c, 0x4a6f, 0x9c,0x13, 0x47,0x77,0x2b,0xb0,0x47,0xbb); #include "wine/test.h" diff --git a/dlls/msxml3/uuid.c b/dlls/msxml3/uuid.c index 333d4f3d3c7..1b4f0452c5f 100644 --- a/dlls/msxml3/uuid.c +++ b/dlls/msxml3/uuid.c @@ -43,6 +43,7 @@ /* Cannot include msxml6 here since we will get a duplicate LIBID_MSXML2 error. */ DEFINE_GUID(CLSID_FreeThreadedDOMDocument60, 0x88d96a06, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(CLSID_FreeThreadedXMLHTTP60, 0x88d96a09, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_MXNamespaceManager60, 0x88d96a11, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_MXXMLWriter60, 0x88d96a0f, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_SAXAttributes60, 0x88d96a0e, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); @@ -51,6 +52,10 @@ DEFINE_GUID(CLSID_ServerXMLHTTP60, 0x88d96a0b, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0 DEFINE_GUID(CLSID_XMLHTTP60, 0x88d96a0a, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_XMLSchemaCache60, 0x88d96a07, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); DEFINE_GUID(CLSID_XSLTemplate60, 0x88d96a08, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); +DEFINE_GUID(IID_IXMLHTTPRequest2, 0xe5d37dc0, 0x552a, 0x4d52, 0x9c,0xc0, 0xa1,0x4d,0x54,0x6f,0xbd,0x04); +DEFINE_GUID(IID_IXMLHTTPRequest3, 0xa1c9feee, 0x0617, 0x4f23, 0x9d,0x58, 0x89,0x61,0xea,0x43,0x56,0x7c); +DEFINE_GUID(IID_IXMLHTTPRequest2Callback, 0xa44a9299, 0xe321, 0x40de, 0x88,0x66, 0x34,0x1b,0x41,0x66,0x91,0x62); +DEFINE_GUID(IID_IXMLHTTPRequest3Callback, 0xb9e57830, 0x8c6c, 0x4a6f, 0x9c,0x13, 0x47,0x77,0x2b,0xb0,0x47,0xbb); /* * Note that because of a #define in msxml2.h, we end up initializing From dab9b7c5cae50651fe616ac978a776641ae030f3 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 5 Jan 2023 14:36:31 +1100 Subject: [PATCH 2334/2777] msxml3: Implement IXMLHTTPRequest3 SetProperty CW-Bug-Id: #22822 --- dlls/msxml3/httprequest.c | 77 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/dlls/msxml3/httprequest.c b/dlls/msxml3/httprequest.c index 98dd23c9fbb..d8360680411 100644 --- a/dlls/msxml3/httprequest.c +++ b/dlls/msxml3/httprequest.c @@ -102,6 +102,21 @@ typedef struct /* IObjectSafety */ DWORD safeopt; + + /* Properties */ + DWORD no_prompt; + DWORD no_auth; + DWORD timeout; + BOOL no_headeres; + BOOL redirect; + BOOL cache; + BOOL extended; + BOOL query_utf8; + BOOL ignore_errors; + BOOL threshold; + DWORD enterrprised_id; + DWORD max_connections; + } httprequest; typedef struct @@ -2230,8 +2245,52 @@ static HRESULT WINAPI xml_http_request_2_SetCustomResponseStream(IXMLHTTPRequest static HRESULT WINAPI xml_http_request_2_SetProperty(IXMLHTTPRequest3 *iface, XHR_PROPERTY property, ULONGLONG value) { struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); - FIXME("(%p)->(%#x %s) stub!\n", This, property, wine_dbgstr_longlong( value )); - return E_NOTIMPL; + + TRACE("(%p)->(%#x %s) stub!\n", This, property, wine_dbgstr_longlong( value )); + + switch (property) + { + case XHR_PROP_NO_CRED_PROMPT: + This->req.no_prompt = value; + break; + case XHR_PROP_NO_AUTH: + This->req.no_auth = value; + break; + case XHR_PROP_TIMEOUT: + This->req.timeout = value; + break; + case XHR_PROP_NO_DEFAULT_HEADERS: + This->req.no_headeres = value != 0; + break; + case XHR_PROP_REPORT_REDIRECT_STATUS: + This->req.redirect = value != 0; + break; + case XHR_PROP_NO_CACHE: + This->req.cache = value != 0; + break; + case XHR_PROP_EXTENDED_ERROR: + This->req.extended = value != 0; + break; + case XHR_PROP_QUERY_STRING_UTF8: + This->req.query_utf8 = value != 0; + break; + case XHR_PROP_IGNORE_CERT_ERRORS: + This->req.ignore_errors = value != 0; + break; + case XHR_PROP_ONDATA_THRESHOLD: + This->req.threshold = value; + break; + case XHR_PROP_SET_ENTERPRISEID: + This->req.enterrprised_id = value; + break; + case XHR_PROP_MAX_CONNECTIONS: + This->req.max_connections = value; + break; + default: + WARN("Invalid property %#x\n", property); + return E_INVALIDARG; + } + return S_OK; } static HRESULT WINAPI xml_http_request_2_SetRequestHeader(IXMLHTTPRequest3 *iface, @@ -2551,6 +2610,20 @@ static void init_httprequest(httprequest *req) req->site = NULL; req->safeopt = 0; + + /* Properties */ + req->no_prompt = XHR_CRED_PROMPT_ALL; + req->no_auth = XHR_AUTH_ALL; + req->timeout = 0xFFFFFFFF; + req->no_headeres = FALSE; + req->redirect = FALSE; + req->cache = FALSE; + req->extended = FALSE; + req->query_utf8 = FALSE;; + req->ignore_errors = FALSE;; + req->threshold = 0x100; + req->enterrprised_id = 0; + req->max_connections = 10; } HRESULT XMLHTTPRequest_create(void **obj) From e2b8621b9446437507742ecfe3a8a1f2e1df0624 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 12 Jan 2023 08:21:48 +1100 Subject: [PATCH 2335/2777] msxml3: Correct xml_http_request_2_GetResponseHeader CW-Bug-Id: #22822 --- dlls/msxml3/httprequest.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dlls/msxml3/httprequest.c b/dlls/msxml3/httprequest.c index d8360680411..cd0b11e3faa 100644 --- a/dlls/msxml3/httprequest.c +++ b/dlls/msxml3/httprequest.c @@ -2325,8 +2325,7 @@ static HRESULT WINAPI xml_http_request_2_GetResponseHeader(IXMLHTTPRequest3 *ifa TRACE("(%p)->(%s %p)\n", This, debugstr_w(header), value); - if (FAILED(hr = httprequest_getResponseHeader(&This->req, (BSTR)header, value))) - return hr; + hr = httprequest_getResponseHeader(&This->req, (BSTR)header, value); #define E_FILE_NOT_FOUND _HRESULT_TYPEDEF_(0x80070002) From 530f1b2f839b7ab48be8d3c5ad6b7498cf444c26 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 5 Oct 2023 08:43:07 -0600 Subject: [PATCH 2336/2777] fixup! msxml3: Implement FreeThreadedXMLHTTP60. CW-Bug-Id: #22822 --- include/msxml6.idl | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/include/msxml6.idl b/include/msxml6.idl index 7396826a1f6..b2d8bd3b337 100644 --- a/include/msxml6.idl +++ b/include/msxml6.idl @@ -1715,17 +1715,6 @@ interface ISAXDeclHandler : IUnknown [in] int nSystemId); } -[ - helpstring("Free Threaded XML HTTP Request class 6.0"), - progid("Msxml2.FreeThreadedXMLHTTP60.6.0"), - threading(both), - uuid(88d96a09-f192-11d4-a65f-0040963251e5) -] -coclass FreeThreadedXMLHTTP60 -{ - [default] interface IXMLHTTPRequest2; -} - [ object, local, @@ -3053,6 +3042,17 @@ interface ISchemaNotation; SCHEMATYPEVARIETY __schemaTypeVariety__; } __msxml6_ReferenceRemainingTypes__; +[ + helpstring("Free Threaded XML HTTP Request class 6.0"), + progid("Msxml2.FreeThreadedXMLHTTP60.6.0"), + threading(both), + uuid(88d96a09-f192-11d4-a65f-0040963251e5) +] +coclass FreeThreadedXMLHTTP60 +{ + [default] interface IXMLHTTPRequest2; +} + [ helpstring("XML DOM Document 6.0"), progid("Msxml2.DOMDocument.6.0"), From 63b6d8b285ef002a35942fc16804488a3a5b0b79 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 5 Oct 2023 11:38:00 -0600 Subject: [PATCH 2337/2777] msxml3: Treat body as data array in xml_http_request_2_IRtwqAsyncCallback_Invoke(). CW-Bug-Id: #22822 --- dlls/msxml3/httprequest.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/dlls/msxml3/httprequest.c b/dlls/msxml3/httprequest.c index cd0b11e3faa..ee6543dd8ea 100644 --- a/dlls/msxml3/httprequest.c +++ b/dlls/msxml3/httprequest.c @@ -2412,6 +2412,7 @@ static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_Invoke(IRtwqAsyncCal IRtwqAsyncResult *result) { struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); + SAFEARRAY *sa = NULL; VARIANT body_v; HRESULT hr; ULONG read; @@ -2422,14 +2423,25 @@ static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_Invoke(IRtwqAsyncCal if (This->request_body) { - V_VT(&body_v) = VT_BSTR; - V_BSTR(&body_v) = CoTaskMemAlloc(This->request_body_size); + SAFEARRAYBOUND bound; + void *ptr; - if (FAILED(hr = ISequentialStream_Read(This->request_body, V_BSTR(&body_v), This->request_body_size, &read)) || - read < This->request_body_size) + bound.lLbound = 0; + bound.cElements = This->request_body_size; + if (!(sa = SafeArrayCreate(VT_UI1, 1, &bound))) + { + ERR("No memory.\n"); + hr = E_OUTOFMEMORY; + goto done; + } + V_ARRAY(&body_v) = sa; + V_VT(&body_v) = VT_ARRAY | VT_UI1; + SafeArrayAccessData(sa, &ptr); + hr = ISequentialStream_Read(This->request_body, ptr, This->request_body_size, &read); + SafeArrayUnaccessData(sa); + if (FAILED(hr) || read < This->request_body_size) { - ERR("Failed to allocate request body memory, hr %#lx\n", hr); - CoTaskMemFree(V_BSTR(&body_v)); + ERR("Failed to read from stream, hr %#lx\n", hr); goto done; } @@ -2440,6 +2452,8 @@ static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_Invoke(IRtwqAsyncCal hr = httprequest_send(&This->req, body_v); done: + if (sa) + SafeArrayDestroy(sa); return IRtwqAsyncResult_SetStatus(result, hr); } From 1ada8bda12558de83460c67696d1189efda29b1d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 5 Oct 2023 12:05:28 -0600 Subject: [PATCH 2338/2777] msxml3: Try to get body size from stream in xml_http_request_2_IRtwqAsyncCallback_Invoke(). CW-Bug-Id: #22822 --- dlls/msxml3/httprequest.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/dlls/msxml3/httprequest.c b/dlls/msxml3/httprequest.c index ee6543dd8ea..6a40a02958e 100644 --- a/dlls/msxml3/httprequest.c +++ b/dlls/msxml3/httprequest.c @@ -2412,6 +2412,7 @@ static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_Invoke(IRtwqAsyncCal IRtwqAsyncResult *result) { struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); + IStream *stream = NULL; SAFEARRAY *sa = NULL; VARIANT body_v; HRESULT hr; @@ -2424,10 +2425,27 @@ static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_Invoke(IRtwqAsyncCal if (This->request_body) { SAFEARRAYBOUND bound; + ULONGLONG body_size; + STATSTG stream_stat; + LARGE_INTEGER li; void *ptr; + if (SUCCEEDED(ISequentialStream_QueryInterface(This->request_body, &IID_IStream, (void **)&stream)) + && SUCCEEDED(IStream_Stat(stream, &stream_stat, 0))) + { + body_size = stream_stat.cbSize.QuadPart; + li.QuadPart = 0; + IStream_Seek(stream, li, STREAM_SEEK_SET, NULL); + } + else + { + body_size = This->request_body_size; + } + + TRACE("body_size %I64u.\n", body_size); + bound.lLbound = 0; - bound.cElements = This->request_body_size; + bound.cElements = body_size; if (!(sa = SafeArrayCreate(VT_UI1, 1, &bound))) { ERR("No memory.\n"); @@ -2437,9 +2455,13 @@ static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_Invoke(IRtwqAsyncCal V_ARRAY(&body_v) = sa; V_VT(&body_v) = VT_ARRAY | VT_UI1; SafeArrayAccessData(sa, &ptr); - hr = ISequentialStream_Read(This->request_body, ptr, This->request_body_size, &read); + + if (stream) + hr = IStream_Read(stream, ptr, body_size, &read); + else + hr = ISequentialStream_Read(This->request_body, ptr, body_size, &read); SafeArrayUnaccessData(sa); - if (FAILED(hr) || read < This->request_body_size) + if (FAILED(hr) || read < body_size) { ERR("Failed to read from stream, hr %#lx\n", hr); goto done; @@ -2454,6 +2476,8 @@ static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_Invoke(IRtwqAsyncCal done: if (sa) SafeArrayDestroy(sa); + if (stream) + IStream_Release(stream); return IRtwqAsyncResult_SetStatus(result, hr); } From 57c5732ca8d1d7e1caa2e5d840b7087c55cac484 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 5 Oct 2023 12:02:44 -0600 Subject: [PATCH 2339/2777] msxml3: Don't fail xml_http_request_2_IRtwqAsyncCallback_Invoke() on stream read failures. CW-Bug-Id: #22822 --- dlls/msxml3/httprequest.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dlls/msxml3/httprequest.c b/dlls/msxml3/httprequest.c index 6a40a02958e..646ffbecf74 100644 --- a/dlls/msxml3/httprequest.c +++ b/dlls/msxml3/httprequest.c @@ -2463,8 +2463,12 @@ static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_Invoke(IRtwqAsyncCal SafeArrayUnaccessData(sa); if (FAILED(hr) || read < body_size) { - ERR("Failed to read from stream, hr %#lx\n", hr); - goto done; + /* Windows doesn't send the body in this case but still sends request with Content-Length + * set to requested body size. */ + ERR("Failed to read from stream, hr %#lx, read %lu\n", hr, read); + SafeArrayDestroy(sa); + sa = NULL; + V_VT(&body_v) = VT_NULL; } ISequentialStream_Release(This->request_body); From 9181b884fd3dce0a065e83b700810197cc9c5178 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 6 Oct 2023 17:54:50 -0600 Subject: [PATCH 2340/2777] imagehlp: Import functions instead of forwarding. CW-Bug-Id: #22828 --- dlls/imagehlp/imagehlp.spec | 148 ++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/dlls/imagehlp/imagehlp.spec b/dlls/imagehlp/imagehlp.spec index 744b339caf8..7d934dcc96e 100644 --- a/dlls/imagehlp/imagehlp.spec +++ b/dlls/imagehlp/imagehlp.spec @@ -1,35 +1,35 @@ @ stdcall BindImage(str str str) @ stdcall BindImageEx(long str str str ptr) @ stdcall CheckSumMappedFile(ptr long ptr ptr) -@ stdcall EnumerateLoadedModules64(long ptr ptr) dbghelp.EnumerateLoadedModules64 -@ stdcall EnumerateLoadedModules(long ptr ptr) dbghelp.EnumerateLoadedModules -@ stdcall FindDebugInfoFile(str str ptr) dbghelp.FindDebugInfoFile -@ stdcall FindDebugInfoFileEx(str str ptr ptr ptr) dbghelp.FindDebugInfoFileEx -@ stdcall FindExecutableImage(str str str) dbghelp.FindExecutableImage -@ stdcall FindExecutableImageEx(str str ptr ptr ptr) dbghelp.FindExecutableImageEx +@ stdcall -import EnumerateLoadedModules64(long ptr ptr) +@ stdcall -import EnumerateLoadedModules(long ptr ptr) +@ stdcall -import FindDebugInfoFile(str str ptr) +@ stdcall -import FindDebugInfoFileEx(str str ptr ptr ptr) +@ stdcall -import FindExecutableImage(str str str) +@ stdcall -import FindExecutableImageEx(str str ptr ptr ptr) @ stub FindFileInPath @ stub FindFileInSearchPath @ stdcall GetImageConfigInformation(ptr ptr) @ stdcall GetImageUnusedHeaderBytes(ptr ptr) -@ stdcall GetTimestampForLoadedLibrary(long) dbghelp.GetTimestampForLoadedLibrary +@ stdcall -import GetTimestampForLoadedLibrary(long) @ stdcall ImageAddCertificate(long ptr ptr) -@ stdcall ImageDirectoryEntryToData(ptr long long ptr) dbghelp.ImageDirectoryEntryToData -@ stdcall ImageDirectoryEntryToDataEx(ptr long long ptr ptr) dbghelp.ImageDirectoryEntryToDataEx +@ stdcall -import ImageDirectoryEntryToData(ptr long long ptr) +@ stdcall -import ImageDirectoryEntryToDataEx(ptr long long ptr ptr) @ stdcall ImageEnumerateCertificates(long long ptr ptr long) @ stdcall ImageGetCertificateData(long long ptr ptr) @ stdcall ImageGetCertificateHeader(long long ptr) @ stdcall ImageGetDigestStream(long long ptr long) @ stdcall ImageLoad(str str) -@ stdcall ImageNtHeader(ptr) ntdll.RtlImageNtHeader +@ stdcall -import ImageNtHeader(ptr) RtlImageNtHeader @ stdcall ImageRemoveCertificate(long long) -@ stdcall ImageRvaToSection(ptr ptr long) ntdll.RtlImageRvaToSection -@ stdcall ImageRvaToVa(ptr ptr long ptr) ntdll.RtlImageRvaToVa +@ stdcall -import ImageRvaToSection(ptr ptr long) RtlImageRvaToSection +@ stdcall -import ImageRvaToVa(ptr ptr long ptr) RtlImageRvaToVa @ stdcall ImageUnload(ptr) -@ stdcall ImagehlpApiVersion() dbghelp.ImagehlpApiVersion -@ stdcall ImagehlpApiVersionEx(ptr) dbghelp.ImagehlpApiVersionEx -@ stdcall MakeSureDirectoryPathExists(str) dbghelp.MakeSureDirectoryPathExists +@ stdcall -import ImagehlpApiVersion() +@ stdcall -import ImagehlpApiVersionEx(ptr) +@ stdcall -import MakeSureDirectoryPathExists(str) @ stdcall MapAndLoad(str str ptr long long) -@ stdcall MapDebugInformation(long str str long) dbghelp.MapDebugInformation +@ stdcall -import -arch=win32 MapDebugInformation(long str str long) @ stdcall MapFileAndCheckSumA(str ptr ptr) @ stdcall MapFileAndCheckSumW(wstr ptr ptr) @ stub MarkImageAsRunFromSwap @@ -38,72 +38,72 @@ @ stdcall RemovePrivateCvSymbolic(ptr ptr ptr) @ stub RemovePrivateCvSymbolicEx @ stdcall RemoveRelocations(ptr) -@ stdcall SearchTreeForFile(str str ptr) dbghelp.SearchTreeForFile +@ stdcall -import SearchTreeForFile(str str ptr) @ stdcall SetImageConfigInformation(ptr ptr) @ stdcall SplitSymbols(str str str long) -@ stdcall StackWalk64(long long long ptr ptr ptr ptr ptr ptr) dbghelp.StackWalk64 -@ stdcall StackWalk(long long long ptr ptr ptr ptr ptr ptr) dbghelp.StackWalk -@ stdcall SymCleanup(long) dbghelp.SymCleanup -@ stdcall SymEnumSourceFiles(ptr int64 str ptr ptr) dbghelp.SymEnumSourceFiles +@ stdcall -import StackWalk64(long long long ptr ptr ptr ptr ptr ptr) +@ stdcall -import StackWalk(long long long ptr ptr ptr ptr ptr ptr) +@ stdcall -import SymCleanup(long) +@ stdcall SymEnumSourceFiles(ptr int64 str ptr ptr) SymEnumSourceFiles @ stub SymEnumSym -@ stdcall SymEnumSymbols(ptr int64 str ptr ptr) dbghelp.SymEnumSymbols -@ stdcall SymEnumTypes(ptr int64 ptr ptr) dbghelp.SymEnumTypes -@ stdcall SymEnumerateModules64(long ptr ptr) dbghelp.SymEnumerateModules64 -@ stdcall SymEnumerateModules(long ptr ptr) dbghelp.SymEnumerateModules -@ stdcall SymEnumerateSymbols64(long int64 ptr ptr) dbghelp.SymEnumerateSymbols64 -@ stdcall SymEnumerateSymbols(long long ptr ptr) dbghelp.SymEnumerateSymbols +@ stdcall -import SymEnumSymbols(ptr int64 str ptr ptr) +@ stdcall -import SymEnumTypes(ptr int64 ptr ptr) +@ stdcall -import SymEnumerateModules64(long ptr ptr) +@ stdcall -import SymEnumerateModules(long ptr ptr) +@ stdcall -import SymEnumerateSymbols64(long int64 ptr ptr) +@ stdcall -import SymEnumerateSymbols(long long ptr ptr) @ stub SymEnumerateSymbolsW64 @ stub SymEnumerateSymbolsW -@ stdcall SymFindFileInPath(long str str ptr long long long ptr ptr ptr) dbghelp.SymFindFileInPath -@ stdcall SymFromAddr(ptr int64 ptr ptr) dbghelp.SymFromAddr -@ stdcall SymFromName(long str ptr) dbghelp.SymFromName -@ stdcall SymFunctionTableAccess64(long int64) dbghelp.SymFunctionTableAccess64 -@ stdcall SymFunctionTableAccess(long long) dbghelp.SymFunctionTableAccess -@ stdcall SymGetLineFromAddr64(long int64 ptr ptr) dbghelp.SymGetLineFromAddr64 -@ stdcall SymGetLineFromAddr(long long ptr ptr) dbghelp.SymGetLineFromAddr +@ stdcall -import SymFindFileInPath(long str str ptr long long long ptr ptr ptr) +@ stdcall -import SymFromAddr(ptr int64 ptr ptr) +@ stdcall -import SymFromName(long str ptr) +@ stdcall -import SymFunctionTableAccess64(long int64) +@ stdcall -import SymFunctionTableAccess(long long) +@ stdcall -import SymGetLineFromAddr64(long int64 ptr ptr) +@ stdcall -import SymGetLineFromAddr(long long ptr ptr) @ stub SymGetLineFromName64 @ stub SymGetLineFromName -@ stdcall SymGetLineNext64(long ptr) dbghelp.SymGetLineNext64 -@ stdcall SymGetLineNext(long ptr) dbghelp.SymGetLineNext -@ stdcall SymGetLinePrev64(long ptr) dbghelp.SymGetLinePrev64 -@ stdcall SymGetLinePrev(long ptr) dbghelp.SymGetLinePrev -@ stdcall SymGetModuleBase64(long int64) dbghelp.SymGetModuleBase64 -@ stdcall SymGetModuleBase(long long) dbghelp.SymGetModuleBase -@ stdcall SymGetModuleInfo64(long int64 ptr) dbghelp.SymGetModuleInfo64 -@ stdcall SymGetModuleInfo(long long ptr) dbghelp.SymGetModuleInfo -@ stdcall SymGetModuleInfoW64(long int64 ptr) dbghelp.SymGetModuleInfoW64 -@ stdcall SymGetModuleInfoW(long long ptr) dbghelp.SymGetModuleInfoW -@ stdcall SymGetOptions() dbghelp.SymGetOptions -@ stdcall SymGetSearchPath(long ptr long) dbghelp.SymGetSearchPath -@ stdcall SymGetSymFromAddr64(long int64 ptr ptr) dbghelp.SymGetSymFromAddr64 -@ stdcall SymGetSymFromAddr(long long ptr ptr) dbghelp.SymGetSymFromAddr -@ stdcall SymGetSymFromName64(long str ptr) dbghelp.SymGetSymFromName64 -@ stdcall SymGetSymFromName(long str ptr) dbghelp.SymGetSymFromName -@ stdcall SymGetSymNext64(long ptr) dbghelp.SymGetSymNext64 -@ stdcall SymGetSymNext(long ptr) dbghelp.SymGetSymNext -@ stdcall SymGetSymPrev64(long ptr) dbghelp.SymGetSymPrev64 -@ stdcall SymGetSymPrev(long ptr) dbghelp.SymGetSymPrev -@ stdcall SymGetTypeFromName(ptr int64 str ptr) dbghelp.SymGetTypeFromName -@ stdcall SymGetTypeInfo(ptr int64 long long ptr) dbghelp.SymGetTypeInfo -@ stdcall SymInitialize(long str long) dbghelp.SymInitialize -@ stdcall SymLoadModule64(long long str str int64 long) dbghelp.SymLoadModule64 -@ stdcall SymLoadModule(long long str str long long) dbghelp.SymLoadModule -@ stdcall SymMatchFileName(str str ptr ptr) dbghelp.SymMatchFileName -@ stdcall SymMatchString(str str long) dbghelp.SymMatchString -@ stdcall SymRegisterCallback64(long ptr int64) dbghelp.SymRegisterCallback64 -@ stdcall SymRegisterCallback(long ptr ptr) dbghelp.SymRegisterCallback -@ stdcall SymRegisterFunctionEntryCallback64(ptr ptr int64) dbghelp.SymRegisterFunctionEntryCallback64 -@ stdcall SymRegisterFunctionEntryCallback(ptr ptr ptr) dbghelp.SymRegisterFunctionEntryCallback -@ stdcall SymSetContext(long ptr ptr) dbghelp.SymSetContext -@ stdcall SymSetOptions(long) dbghelp.SymSetOptions -@ stdcall SymSetSearchPath(long str) dbghelp.SymSetSearchPath -@ stdcall SymUnDName64(ptr str long) dbghelp.SymUnDName64 -@ stdcall SymUnDName(ptr str long) dbghelp.SymUnDName -@ stdcall SymUnloadModule64(long int64) dbghelp.SymUnloadModule64 -@ stdcall SymUnloadModule(long long) dbghelp.SymUnloadModule +@ stdcall -import SymGetLineNext64(long ptr) +@ stdcall -import SymGetLineNext(long ptr) +@ stdcall -import SymGetLinePrev64(long ptr) +@ stdcall -import SymGetLinePrev(long ptr) +@ stdcall -import SymGetModuleBase64(long int64) +@ stdcall -import SymGetModuleBase(long long) +@ stdcall -import SymGetModuleInfo64(long int64 ptr) +@ stdcall -import SymGetModuleInfo(long long ptr) +@ stdcall -import SymGetModuleInfoW64(long int64 ptr) +@ stdcall -import SymGetModuleInfoW(long long ptr) +@ stdcall -import SymGetOptions() +@ stdcall -import SymGetSearchPath(long ptr long) +@ stdcall -import SymGetSymFromAddr64(long int64 ptr ptr) +@ stdcall -import SymGetSymFromAddr(long long ptr ptr) +@ stdcall -import SymGetSymFromName64(long str ptr) +@ stdcall -import SymGetSymFromName(long str ptr) +@ stdcall -import SymGetSymNext64(long ptr) +@ stdcall -import SymGetSymNext(long ptr) +@ stdcall -import SymGetSymPrev64(long ptr) +@ stdcall -import SymGetSymPrev(long ptr) +@ stdcall -import SymGetTypeFromName(ptr int64 str ptr) +@ stdcall -import SymGetTypeInfo(ptr int64 long long ptr) +@ stdcall -import SymInitialize(long str long) +@ stdcall -import SymLoadModule64(long long str str int64 long) +@ stdcall -import SymLoadModule(long long str str long long) +@ stdcall -import SymMatchFileName(str str ptr ptr) +@ stdcall -import SymMatchString(str str long) +@ stdcall -import SymRegisterCallback64(long ptr int64) +@ stdcall -import SymRegisterCallback(long ptr ptr) +@ stdcall -import SymRegisterFunctionEntryCallback64(ptr ptr int64) +@ stdcall -import SymRegisterFunctionEntryCallback(ptr ptr ptr) +@ stdcall -import SymSetContext(long ptr ptr) +@ stdcall -import SymSetOptions(long) +@ stdcall -import SymSetSearchPath(long str) +@ stdcall -import SymUnDName64(ptr str long) +@ stdcall -import SymUnDName(ptr str long) +@ stdcall -import SymUnloadModule64(long int64) +@ stdcall -import SymUnloadModule(long long) @ stdcall TouchFileTimes(long ptr) -@ stdcall UnDecorateSymbolName(str str long long) dbghelp.UnDecorateSymbolName +@ stdcall -import UnDecorateSymbolName(str str long long) @ stdcall UnMapAndLoad(ptr) -@ stdcall UnmapDebugInformation(ptr) dbghelp.UnmapDebugInformation +@ stdcall -import -arch=win32 UnmapDebugInformation(ptr) @ stdcall UpdateDebugInfoFile(str str str ptr) @ stdcall UpdateDebugInfoFileEx(str str str ptr long) From 77992a3afcab468b5cc66e0dd9099a650d537b58 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 12 Apr 2022 20:27:25 +0300 Subject: [PATCH 2341/2777] winex11.drv: fshack: Don't set 'pending_fullscreen' if window already has NET_WM_STATE_FULLSCREEN. CW-Bug-Id: #20483 CW-Bug-Id: #22796 --- dlls/winex11.drv/window.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 4940ddc7804..4aa9878ad76 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1330,7 +1330,9 @@ void update_net_wm_states( struct x11drv_win_data *data ) if (i == NET_WM_STATE_FULLSCREEN) { - data->pending_fullscreen = (new_state & (1 << i)) != 0; + data->pending_fullscreen = (new_state & (1 << i)) + && !(data->net_wm_state & (1 << NET_WM_STATE_FULLSCREEN) + && wm_is_steamcompmgr(data->display)); TRACE( "set pending_fullscreen to: %u\n", data->pending_fullscreen ); } From cb163ce171f7662b37457202566a02794883735a Mon Sep 17 00:00:00 2001 From: Esme Povirk Date: Mon, 9 Oct 2023 15:49:27 -0500 Subject: [PATCH 2342/2777] mscoree: Add work-around for Grotesque Tactics. CW-Bug-Id: #22841 --- dlls/mscoree/metahost.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/mscoree/metahost.c b/dlls/mscoree/metahost.c index 6327a338596..8dd77e287b3 100644 --- a/dlls/mscoree/metahost.c +++ b/dlls/mscoree/metahost.c @@ -1906,6 +1906,12 @@ static MonoAssembly* CDECL wine_mono_assembly_preload_hook_v2_fn(MonoAssemblyNam "321360", /* Primal Carnage: Extinction */ "namespace ContentBrowser { class IContentBrowserBackendInterface {} class Package {} } " }, + { + "DockPanel", + "DockPanel.dll", + "46450", /* Grotesque Tactics: Evil Heroes */ + "namespace WeifenLuo.WinFormsUI { class DockPanel {} }" + }, }; for (i = 0; i < ARRAY_SIZE(assembly_hacks); ++i) From 59bd1f5bde1d230f7bea620cf5811d770a4072c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 10 Oct 2023 18:02:42 +0200 Subject: [PATCH 2343/2777] server: Send WM_WINE_SETCURSOR with the last thread input cursor handle. Which may be different from the last desktop cursor handle. This makes the behavior better match the old winex11 behavior, which queried the current thread input cursor handle on every mouse move to sync it with X11, although it contradicts MSDN documentation which states that the cursor handle is global. This fixes the X11 cursor being visible in "Deus Ex: GOTY Edition". CW-Bug-Id: #22838 --- server/queue.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/server/queue.c b/server/queue.c index 549d08cbcf5..084416e3776 100644 --- a/server/queue.c +++ b/server/queue.c @@ -514,13 +514,22 @@ static void queue_cursor_message( struct desktop *desktop, user_handle_t win, un queue_hardware_message( desktop, msg, 1 ); } -static int update_desktop_cursor_window( struct desktop *desktop, user_handle_t win ) +static int update_desktop_cursor_window( struct desktop *desktop, user_handle_t win, int x, int y ) { int updated = win != desktop->cursor_win; user_handle_t handle = desktop->cursor_handle; desktop->cursor_win = win; if (updated) { + struct thread *thread; + + if ((thread = window_thread_from_point( win, x, y ))) + { + struct thread_input *input = thread->queue->input; + if (input) handle = input->shared->cursor_count < 0 ? 0 : input->shared->cursor; + release_object( thread ); + } + /* when clipping send the message to the foreground window as well, as some driver have an artificial overlay window */ if (is_cursor_clipped( desktop )) queue_cursor_message( desktop, 0, WM_WINE_SETCURSOR, win, handle ); queue_cursor_message( desktop, win, WM_WINE_SETCURSOR, win, handle ); @@ -547,7 +556,7 @@ static int update_desktop_cursor_pos( struct desktop *desktop, user_handle_t win if (!win && (input = desktop->foreground_input)) win = input->shared->capture; if (!win || !is_window_visible( win ) || is_window_transparent( win )) win = shallow_window_from_point( desktop, x, y ); - if (update_desktop_cursor_window( desktop, win )) updated = 1; + if (update_desktop_cursor_window( desktop, win, x, y )) updated = 1; return updated; } From 8a671f6fd6bf86d508ebe4ed829a06d9040d87cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 10 Oct 2023 18:47:30 +0200 Subject: [PATCH 2344/2777] fixup! server: Get rid of the global cursor structure. --- server/winstation.c | 1 + 1 file changed, 1 insertion(+) diff --git a/server/winstation.c b/server/winstation.c index d9617b5509e..57668f0a025 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -262,6 +262,7 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned desktop->foreground_input = NULL; desktop->users = 0; desktop->cursor_win = 0; + desktop->cursor_handle = 0; desktop->last_press_alt = 0; list_add_tail( &winstation->desktops, &desktop->entry ); list_init( &desktop->hotkeys ); From c3448cdbb9d05b27d00924e55e01bda8a4adeb4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 11 Oct 2023 11:39:32 +0200 Subject: [PATCH 2345/2777] amend! win32u: Support multiple touches in WM_TOUCH message. win32u: Support multiple touches in WM_TOUCH message. CW-Bug-Id: #21796 CW-Bug-Id: #22849 --- dlls/win32u/defwnd.c | 58 +++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c index eb1c082ff20..2015515b94f 100644 --- a/dlls/win32u/defwnd.c +++ b/dlls/win32u/defwnd.c @@ -2956,15 +2956,22 @@ LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, case WM_POINTERUP: case WM_POINTERUPDATE: { + TOUCHINPUT *touches, *end, *touch, *match = NULL; struct touchinput_thread_data *thread_data; - TOUCHINPUT *touches, *end, *touch; UINT i; if (!NtUserIsTouchWindow( hwnd, NULL )) return 0; if (!(thread_data = touch_input_thread_data())) return 0; - for (touches = thread_data->current, end = touches + ARRAY_SIZE(thread_data->current), touch = touches; touch < end; touch++) - if (!touch->dwID || touch->dwID == GET_POINTERID_WPARAM( wparam )) break; + touches = thread_data->current; + end = touches + ARRAY_SIZE(thread_data->current); + for (touch = touches; touch < end && touch->dwID; touch++) + { + if (touch->dwID == GET_POINTERID_WPARAM( wparam )) match = touch; + touch->dwFlags &= ~TOUCHEVENTF_DOWN; + touch->dwFlags |= TOUCHEVENTF_MOVE; + } + if (match) touch = match; if (touch == end || (msg != WM_POINTERDOWN && !touch->dwID)) { @@ -2973,36 +2980,33 @@ LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, break; } - while (end > touch && !(end - 1)->dwID) end--; + while (end > (touch + 1) && !(end - 1)->dwID) end--; - if (msg == WM_POINTERUP) - { - while (++touch < end) *(touch - 1) = *touch; - memset( touch - 1, 0, sizeof(*touch) ); - end--; - } - else - { - touch->x = LOWORD( lparam ) * 100; - touch->y = HIWORD( lparam ) * 100; - touch->hSource = WINE_MOUSE_HANDLE; - touch->dwID = GET_POINTERID_WPARAM( wparam ); - touch->dwFlags = TOUCHEVENTF_NOCOALESCE | TOUCHEVENTF_PALM; - if (msg == WM_POINTERDOWN) touch->dwFlags |= TOUCHEVENTF_DOWN; - if (msg == WM_POINTERUP) touch->dwFlags |= TOUCHEVENTF_UP; - if (msg == WM_POINTERUPDATE) touch->dwFlags |= TOUCHEVENTF_MOVE; - if (IS_POINTER_PRIMARY_WPARAM( wparam )) touch->dwFlags |= TOUCHEVENTF_PRIMARY; - touch->dwMask = 0; - touch->dwTime = NtGetTickCount(); - touch->dwExtraInfo = 0; - touch->cxContact = 0; - touch->cyContact = 0; - } + touch->x = LOWORD( lparam ) * 100; + touch->y = HIWORD( lparam ) * 100; + touch->hSource = WINE_MOUSE_HANDLE; + touch->dwID = GET_POINTERID_WPARAM( wparam ); + touch->dwFlags = 0; + if (msg == WM_POINTERUP) touch->dwFlags |= TOUCHEVENTF_UP; + if (msg == WM_POINTERDOWN) touch->dwFlags |= TOUCHEVENTF_INRANGE | TOUCHEVENTF_DOWN; + if (msg == WM_POINTERUPDATE) touch->dwFlags |= TOUCHEVENTF_INRANGE | TOUCHEVENTF_MOVE; + if (IS_POINTER_PRIMARY_WPARAM( wparam )) touch->dwFlags |= TOUCHEVENTF_PRIMARY; + touch->dwMask = 0; + touch->dwTime = NtGetTickCount(); + touch->dwExtraInfo = 0; + touch->cxContact = 0; + touch->cyContact = 0; i = thread_data->index++ % ARRAY_SIZE(thread_data->history); memcpy( thread_data->history + i, thread_data->current, sizeof(thread_data->current) ); send_message( hwnd, WM_TOUCH, MAKELONG(end - touches, 0), (LPARAM)i ); + + if (msg == WM_POINTERUP) + { + while (++touch < end) *(touch - 1) = *touch; + memset( touch - 1, 0, sizeof(*touch) ); + } break; } From 939c40cbb6326907e4d064ebb39e1aceef2cf37f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 10 Oct 2023 14:27:58 -0600 Subject: [PATCH 2346/2777] win32u: Don't fail update_display_cache_from_registry() if there is no adapters. CW-Bug-Id: #22813 --- dlls/win32u/sysparams.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 6630250b667..5a0f34fbc32 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -1662,7 +1662,6 @@ static BOOL update_display_cache_from_registry(void) struct monitor *monitor, *monitor2; HANDLE mutex = NULL; NTSTATUS status; - BOOL ret; /* If user driver did initialize the registry, then exit */ if (!video_key && !(video_key = reg_open_key( NULL, devicemap_video_keyW, @@ -1720,11 +1719,15 @@ static BOOL update_display_cache_from_registry(void) } } - if ((ret = !list_empty( &adapters ) && !list_empty( &monitors ))) - last_query_display_time = key.LastWriteTime.QuadPart; + if (list_empty( &adapters )) + { + WARN( "No adapters found.\n" ); + assert( list_empty( &monitors )); + } + else if (!list_empty( &monitors )) last_query_display_time = key.LastWriteTime.QuadPart; pthread_mutex_unlock( &display_lock ); release_display_device_init_mutex( mutex ); - return ret; + return TRUE; } static BOOL update_display_cache( BOOL force ) @@ -2454,6 +2457,8 @@ static DEVMODEW *get_display_settings( const WCHAR *devname, const DEVMODEW *dev struct adapter *adapter; BOOL ret; + if (list_empty( &adapters )) return NULL; + /* allocate an extra mode for easier iteration */ if (!(displays = calloc( list_count( &adapters ) + 1, sizeof(DEVMODEW) ))) return NULL; mode = displays; From e229aae4af013589f7a8d06b219956019953e690 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Tue, 10 Oct 2023 13:08:12 +0300 Subject: [PATCH 2347/2777] xinput1_3: Hold module reference while the hid thread is running. We have no means of stopping the thread from DllMain on DLL_PROCESS_DETACH without having a race condition - waiting on the thread itself is not an option due to the loader lock. The best we can do is just never unload the DLL as long as the thread is active which is forever. This fixes crashes in Mighty Switch Force! Collection while controllers are unplugged - the game loads and frees xinput in a loop. (cherry picked from commit 10a0a8eabc5882bf045ca08d4fc4768533e9a8dc) --- dlls/xinput1_3/main.c | 52 +++++++++++-------------------------------- 1 file changed, 13 insertions(+), 39 deletions(-) diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c index 192d75413fa..a18f63545cc 100644 --- a/dlls/xinput1_3/main.c +++ b/dlls/xinput1_3/main.c @@ -121,8 +121,6 @@ static struct xinput_controller controllers[XUSER_MAX_COUNT] = static HMODULE xinput_instance; static HANDLE start_event; -static HANDLE stop_event; -static HANDLE done_event; static HANDLE update_event; static HANDLE steam_overlay_event; static HANDLE steam_keyboard_event; @@ -569,23 +567,6 @@ static void update_controller_list(void) SetupDiDestroyDeviceInfoList(set); } -static void stop_update_thread(void) -{ - int i; - - SetEvent(stop_event); - WaitForSingleObject(done_event, INFINITE); - - CloseHandle(start_event); - CloseHandle(stop_event); - CloseHandle(done_event); - CloseHandle(update_event); - CloseHandle(steam_overlay_event); - CloseHandle(steam_keyboard_event); - - for (i = 0; i < XUSER_MAX_COUNT; i++) controller_destroy(&controllers[i], FALSE); -} - static LONG sign_extend(ULONG value, const HIDP_VALUE_CAPS *caps) { UINT sign = 1 << (caps->BitSize - 1); @@ -711,9 +692,9 @@ static LRESULT CALLBACK xinput_devnotify_wndproc(HWND hwnd, UINT msg, WPARAM wpa static DWORD WINAPI hid_update_thread_proc(void *param) { - struct xinput_controller *devices[XUSER_MAX_COUNT + 2]; - HANDLE events[XUSER_MAX_COUNT + 2]; - DWORD i, count = 2, ret = WAIT_TIMEOUT; + struct xinput_controller *devices[XUSER_MAX_COUNT + 1]; + HANDLE events[XUSER_MAX_COUNT + 1]; + DWORD i, count = 1, ret = WAIT_TIMEOUT; DEV_BROADCAST_DEVICEINTERFACE_W filter = { .dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE_W), @@ -745,7 +726,7 @@ static DWORD WINAPI hid_update_thread_proc(void *param) { if (ret == count) while (PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)) DispatchMessageW(&msg); if (ret == WAIT_TIMEOUT) update_controller_list(); - if (ret < count - 2) read_controller_state(devices[ret]); + if (ret < count - 1) read_controller_state(devices[ret]); count = 0; for (i = 0; i < XUSER_MAX_COUNT; ++i) @@ -761,23 +742,26 @@ static DWORD WINAPI hid_update_thread_proc(void *param) LeaveCriticalSection(&controllers[i].crit); } events[count++] = update_event; - events[count++] = stop_event; } - while ((ret = MsgWaitForMultipleObjectsEx(count, events, 2000, QS_ALLINPUT, MWMO_ALERTABLE)) < count - 1 || - ret == count || ret == WAIT_TIMEOUT); + while ((ret = MsgWaitForMultipleObjectsEx(count, events, 2000, QS_ALLINPUT, MWMO_ALERTABLE)) <= count || + ret == WAIT_TIMEOUT); + + ERR("wait failed in the update thread, ret %lu, error %lu\n", ret, GetLastError()); UnregisterDeviceNotification(notif); DestroyWindow(hwnd); UnregisterClassW(cls.lpszClassName, xinput_instance); - if (ret != count - 1) ERR("update thread exited unexpectedly, ret %lu\n", ret); - SetEvent(done_event); - return ret; + FreeLibraryAndExitThread(xinput_instance, ret); } static BOOL WINAPI start_update_thread_once( INIT_ONCE *once, void *param, void **context ) { HANDLE thread; + HMODULE module; + + if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (void*)hid_update_thread_proc, &module)) + WARN("Failed to increase module's reference count, error: %lu\n", GetLastError()); steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated"); steam_keyboard_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_KeyboardActivated"); @@ -785,12 +769,6 @@ static BOOL WINAPI start_update_thread_once( INIT_ONCE *once, void *param, void start_event = CreateEventA(NULL, FALSE, FALSE, NULL); if (!start_event) ERR("failed to create start event, error %lu\n", GetLastError()); - stop_event = CreateEventA(NULL, FALSE, FALSE, NULL); - if (!stop_event) ERR("failed to create stop event, error %lu\n", GetLastError()); - - done_event = CreateEventA(NULL, FALSE, FALSE, NULL); - if (!done_event) ERR("failed to create done event, error %lu\n", GetLastError()); - update_event = CreateEventA(NULL, FALSE, FALSE, NULL); if (!update_event) ERR("failed to create update event, error %lu\n", GetLastError()); @@ -838,10 +816,6 @@ BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) xinput_instance = inst; DisableThreadLibraryCalls(inst); break; - case DLL_PROCESS_DETACH: - if (reserved) break; - stop_update_thread(); - break; } return TRUE; } From 520ac239a90989471941389821ea9d29cdc751fa Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Thu, 12 Oct 2023 10:25:02 +0300 Subject: [PATCH 2348/2777] amend! xinput1_3: Hold module reference while the hid thread is running. xinput1_3: Hold module reference while the hid thread is running. We have no means of stopping the thread from DllMain on DLL_PROCESS_DETACH without having a race condition - waiting on the thread itself is not an option due to the loader lock. The best we can do is just never unload the DLL as long as the thread is active which is forever. This fixes crashes in Mighty Switch Force! Collection while controllers are unplugged - the game loads and frees xinput in a loop. (cherry picked from commit 10a0a8eabc5882bf045ca08d4fc4768533e9a8dc) CW-Bug-Id: #22824 From fc55fe75ec58d2ab3fac72763ad821c896e5b276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20K=C3=B6lbl?= Date: Tue, 30 May 2023 23:25:27 +0200 Subject: [PATCH 2349/2777] mf: Clear queued topologies on session shutdown. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Programs might expect objects inside the queued toplogy to be freed, before they eventually call release on the session itself. This fixes reference leaks to stored objects in queued topology nodes, even when IMFMediaSession_Shutdown() was called. Signed-off-by: Bernhard Kölbl (cherry picked from commit bea37208fe2fc0ebff0d3c0fce5f98ce8f98b88b) --- dlls/mf/session.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 0d3ed620a0c..67e054a61bc 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -2264,6 +2264,7 @@ static HRESULT WINAPI mfsession_Shutdown(IMFMediaSession *iface) IMFPresentationClock_Release(session->clock); session->clock = NULL; session_clear_presentation(session); + session_clear_queued_topologies(session); session_submit_simple_command(session, SESSION_CMD_SHUTDOWN); } LeaveCriticalSection(&session->cs); From 2a1301f17302d4540e80e970e6304b09361b2cfa Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Thu, 12 Oct 2023 11:28:45 +0100 Subject: [PATCH 2350/2777] mf: Don't make stream sink shutdown dependent on IMFActivate presence in node. Base on Bernhard's upstream MR: https://gitlab.winehq.org/wine/wine/-/merge_requests/3067 This fixes a media engine leak after it's shut down. --- dlls/mf/session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 67e054a61bc..2b7b4361c61 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -785,7 +785,7 @@ static void session_shutdown_current_topology(struct media_session *session) WARN("Failed to shut down activation object for the sink, hr %#lx.\n", hr); IMFActivate_Release(activate); } - else if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink))) + if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink))) { if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink))) { From 0bf092301e8a82498092bba54ad92ad8a864f32c Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Wed, 11 Oct 2023 18:21:50 +0100 Subject: [PATCH 2351/2777] mf: Don't leak dropped samples. --- dlls/mf/sar.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/dlls/mf/sar.c b/dlls/mf/sar.c index 86af2a34f11..970063497b1 100644 --- a/dlls/mf/sar.c +++ b/dlls/mf/sar.c @@ -1347,13 +1347,6 @@ static HRESULT stream_queue_sample(struct audio_renderer *renderer, IMFSample *s sample_frames = sample_len / renderer->frame_size; - if (!(object = calloc(1, sizeof(*object)))) - return E_OUTOFMEMORY; - - object->type = OBJECT_TYPE_SAMPLE; - object->u.sample.sample = sample; - IMFSample_AddRef(object->u.sample.sample); - if (FAILED(hr = IMFSample_GetSampleTime(sample, &time))) { WARN("Failed to get sample time, hr %#lx.\n", hr); @@ -1372,6 +1365,12 @@ static HRESULT stream_queue_sample(struct audio_renderer *renderer, IMFSample *s FIXME("Dropping sample %p, time %I64u, clocktime %I64u, systime %I64u.\n", sample, time, clocktime, systime); else { + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + object->type = OBJECT_TYPE_SAMPLE; + object->u.sample.sample = sample; + IMFSample_AddRef(object->u.sample.sample); list_add_tail(&renderer->queue, &object->entry); renderer->queued_frames += sample_frames; } From 7940050635c1de9636194b59845e07ee7be49842 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 12 Oct 2023 21:38:46 -0600 Subject: [PATCH 2352/2777] ntdll: HACK: Avoid unitialized Dr7 in RtlRaiseException on x64. CW-Bug-Id: #22848 --- dlls/ntdll/signal_x86_64.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index f41a09f9ca4..3cb6e09736c 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -1553,6 +1553,8 @@ __ASM_GLOBAL_FUNC( RtlRaiseException, "movq 0x4f8(%rsp),%rax\n\t" /* return address */ "movq %rax,0xf8(%rdx)\n\t" /* context->Rip */ "movq %rax,0x10(%rcx)\n\t" /* rec->ExceptionAddress */ + "xor %rax,%rax\n\t" + "movq %rax,0x70(%rdx)\n\t" /* Context->Dr7 */ "movl $1,%r8d\n\t" "movq %gs:(0x30),%rax\n\t" /* Teb */ "movq 0x60(%rax),%rax\n\t" /* Peb */ From bab53884d690cd441774e0a451f7c25b22a92458 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Mon, 12 Jun 2023 10:10:27 +0100 Subject: [PATCH 2353/2777] winepulse: Don't overwrite the result in the insufficient buffer case. Fixes a regression caused by 13fa7a57df0d. (cherry picked from commit 2586652e1674213208f17402f15805730f1d1c8f) --- dlls/winepulse.drv/pulse.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c index a16f0a2f1e1..429b50e6ec2 100644 --- a/dlls/winepulse.drv/pulse.c +++ b/dlls/winepulse.drv/pulse.c @@ -2368,8 +2368,7 @@ static NTSTATUS pulse_get_prop_value(void *args) if (strcmp(params->device, dev->pulse_name)) continue; if (IsEqualPropertyKey(*params->prop, devicepath_key)) { - if (!get_device_path(dev, params)) - break; + get_device_path(dev, params); return STATUS_SUCCESS; } else if (IsEqualGUID(¶ms->prop->fmtid, &PKEY_AudioEndpoint_GUID)) { switch (params->prop->pid) { From b5d37bf371bb9e388daf6c3a84ea9a01ae65f02a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 13 Oct 2023 13:34:32 +0200 Subject: [PATCH 2354/2777] winex11: Forcefully unmap the clipping window when it loses focus. Fixes cursor not being released when alt-tabbing out of an unresponsive foreground window. CW-Bug-Id: #22842 --- dlls/winex11.drv/event.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index a7d4f4a2436..5589b3b39ad 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -1013,7 +1013,13 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) if (event->detail == NotifyPointer) { - if (!hwnd && event->window == x11drv_thread_data()->clip_window) NtUserClipCursor( NULL ); + if (!hwnd && event->window == x11drv_thread_data()->clip_window) + { + NtUserClipCursor( NULL ); + /* NtUserClipCursor will ask the foreground window to ungrab the cursor, but + * it might not be responsive, so unmap the clipping window ourselves too */ + XUnmapWindow( event->display, event->window ); + } return TRUE; } if (!hwnd) return FALSE; From c690b78915f3d03257ef4a2e465dbb68f93ff4bd Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 13 Oct 2023 18:56:48 -0600 Subject: [PATCH 2355/2777] winegstreamer: Add AVDecVideoAcceleration_H264 attribute for h264 decoder MFT. CW-Bug-Id: #22864 --- dlls/mf/tests/transform.c | 3 +++ dlls/winegstreamer/h264_decoder.c | 6 ++++++ include/codecapi.h | 2 ++ 3 files changed, 11 insertions(+) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index a0df24bab6e..2d79881983b 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -44,6 +44,8 @@ #include "initguid.h" +#include "codecapi.h" + DEFINE_GUID(DMOVideoFormat_RGB24,D3DFMT_R8G8B8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); DEFINE_GUID(DMOVideoFormat_RGB32,D3DFMT_X8R8G8B8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); DEFINE_GUID(DMOVideoFormat_RGB555,D3DFMT_X1R5G5B5,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); @@ -3452,6 +3454,7 @@ static void test_h264_decoder(void) ATTR_UINT32(MF_SA_D3D11_AWARE, 1), ATTR_UINT32(MFT_DECODER_EXPOSE_OUTPUT_TYPES_IN_NATIVE_ORDER, 0, .todo = TRUE), /* more H264 decoder specific attributes from CODECAPI */ + ATTR_UINT32(AVDecVideoAcceleration_H264, 1), {0}, }; static const DWORD input_width = 120, input_height = 248; diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 1b1646a9ed3..6a686b93381 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -26,6 +26,10 @@ #include "wine/debug.h" +#include "initguid.h" + +#include "codecapi.h" + WINE_DEFAULT_DEBUG_CHANNEL(mfplat); WINE_DECLARE_DEBUG_CHANNEL(winediag); @@ -887,6 +891,8 @@ HRESULT h264_decoder_create(REFIID riid, void **ret) goto failed; if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, TRUE))) goto failed; + if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &AVDecVideoAcceleration_H264, TRUE))) + goto failed; { const char *sgi; diff --git a/include/codecapi.h b/include/codecapi.h index 9719389b081..a9fe7c9de3f 100644 --- a/include/codecapi.h +++ b/include/codecapi.h @@ -61,4 +61,6 @@ enum eAVEncH264VLevel eAVEncH264VLevel5_2 = 52 }; +DEFINE_GUID(AVDecVideoAcceleration_H264, 0xf7db8a2f, 0x4f48, 0x4ee8, 0xae, 0x31, 0x8b, 0x6e, 0xbe, 0x55, 0x8a, 0xe2); + #endif /* __CODECAPI_H */ From 063a412c986c27bdfc62afa11b4ef63b763d90c4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 13 Oct 2023 20:55:55 -0600 Subject: [PATCH 2356/2777] Revert "secur32: Get rid of schannel free handle list." This reverts commit 513d371c76b45e383a20e05a64c8c75dc52d5b0b. CW-Bug-Id: #22864 --- dlls/secur32/schannel.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c index 8129c17ad17..a1c641cd34e 100644 --- a/dlls/secur32/schannel.c +++ b/dlls/secur32/schannel.c @@ -68,6 +68,7 @@ struct schan_context }; static struct schan_handle *schan_handle_table; +static struct schan_handle *schan_free_handles; static SIZE_T schan_handle_table_size; static SIZE_T schan_handle_count; static SRWLOCK handle_table_lock = SRWLOCK_INIT; @@ -81,17 +82,23 @@ static DWORD config_default_disabled_protocols; static ULONG_PTR schan_alloc_handle(void *object, enum schan_handle_type type) { struct schan_handle *handle; - ULONG_PTR index = SCHAN_INVALID_HANDLE, i; + ULONG_PTR index = SCHAN_INVALID_HANDLE; AcquireSRWLockExclusive(&handle_table_lock); - for (i = 0; i < schan_handle_table_size; ++i) + if (schan_free_handles) { - handle = &schan_handle_table[i]; + /* Use a free handle */ + handle = schan_free_handles; if (handle->type != SCHAN_HANDLE_FREE) - continue; + { + ERR("Handle %p is in the free list, but has type %#x.\n", handle, handle->type); + goto done; + } + index = schan_free_handles - schan_handle_table; + schan_free_handles = handle->object; handle->object = object; handle->type = type; - index = i; + goto done; } if (!(schan_handle_count < schan_handle_table_size)) @@ -139,8 +146,9 @@ static void *schan_free_handle(ULONG_PTR handle_idx, enum schan_handle_type type } object = handle->object; - handle->object = NULL; + handle->object = schan_free_handles; handle->type = SCHAN_HANDLE_FREE; + schan_free_handles = handle; done: ReleaseSRWLockExclusive(&handle_table_lock); From 5b4222030dc2672be18a0ef11e356815a85d6bc2 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 13 Oct 2023 21:55:21 -0600 Subject: [PATCH 2357/2777] winepulse.drv: Change device description to "Pulse Audio". CW-Bug-Id: #22864 --- dlls/winepulse.drv/pulse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c index 429b50e6ec2..b62ce566cc3 100644 --- a/dlls/winepulse.drv/pulse.c +++ b/dlls/winepulse.drv/pulse.c @@ -806,8 +806,8 @@ static NTSTATUS pulse_test_connect(void *args) list_init(&g_phys_speakers); list_init(&g_phys_sources); - pulse_add_device(&g_phys_speakers, NULL, 0, Speakers, 0, "", "PulseAudio"); - pulse_add_device(&g_phys_sources, NULL, 0, Microphone, 0, "", "PulseAudio"); + pulse_add_device(&g_phys_speakers, NULL, 0, Speakers, 0, "", "Pulse Audio"); + pulse_add_device(&g_phys_sources, NULL, 0, Microphone, 0, "", "Pulse Audio"); o = pa_context_get_sink_info_list(pulse_ctx, &pulse_phys_speakers_cb, NULL); if (o) { From 7ed54be62c930d3b8a75a378d44fdef3c6cfe470 Mon Sep 17 00:00:00 2001 From: Georg Lehmann Date: Fri, 6 Oct 2023 19:33:28 +0200 Subject: [PATCH 2358/2777] winevulkan: Update to VK spec version 1.3.267. (cherry picked from commit 17d9841d86b9f5a7863a45cdfc7a9a2153115621) --- dlls/winevulkan/make_vulkan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 73681dcaff1..b08caeb973f 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -65,7 +65,7 @@ from enum import Enum LOGGER = logging.Logger("vulkan") LOGGER.addHandler(logging.StreamHandler()) -VK_XML_VERSION = "1.3.260" +VK_XML_VERSION = "1.3.267" WINE_VK_VERSION = (1, 3) # Filenames to create. From a89fbde2d57c2a04408b87ea8328d390bf5620e8 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 16 Oct 2023 13:36:09 +0300 Subject: [PATCH 2359/2777] winevulkan: Update vk.xml to 1.3.267. --- dlls/winevulkan/vk.xml | 609 +++++++++++++++++++++++++++++++++-------- 1 file changed, 488 insertions(+), 121 deletions(-) diff --git a/dlls/winevulkan/vk.xml b/dlls/winevulkan/vk.xml index 898bd9f967e..a696de6f012 100644 --- a/dlls/winevulkan/vk.xml +++ b/dlls/winevulkan/vk.xml @@ -175,11 +175,11 @@ branch of the member gitlab server. #define VKSC_API_VERSION_1_0 VK_MAKE_API_VERSION(VKSC_API_VARIANT, 1, 0, 0)// Patch version should always be set to 0 // Version of this file -#define VK_HEADER_VERSION 260 +#define VK_HEADER_VERSION 267 // Complete version of this file #define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(0, 1, 3, VK_HEADER_VERSION) // Version of this file -#define VK_HEADER_VERSION 12 +#define VK_HEADER_VERSION 13 // Complete version of this file #define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(VKSC_API_VARIANT, 1, 0, VK_HEADER_VERSION) @@ -190,7 +190,7 @@ branch of the member gitlab server. #ifndef VK_USE_64_BIT_PTR_DEFINES - #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) || (defined(__riscv) && __riscv_xlen == 64) #define VK_USE_64_BIT_PTR_DEFINES 1 #else #define VK_USE_64_BIT_PTR_DEFINES 0 @@ -478,6 +478,7 @@ typedef void* MTLSharedEvent_id; typedef VkFlags VkOpticalFlowUsageFlagsNV; typedef VkFlags VkOpticalFlowSessionCreateFlagsNV; typedef VkFlags VkOpticalFlowExecuteFlagsNV; + typedef VkFlags VkFrameBoundaryFlagsEXT; typedef VkFlags VkPresentScalingFlagsEXT; typedef VkFlags VkPresentGravityFlagsEXT; typedef VkFlags VkShaderCreateFlagsEXT; @@ -775,6 +776,7 @@ typedef void* MTLSharedEvent_id; + @@ -787,6 +789,9 @@ typedef void* MTLSharedEvent_id; + + + WSI extensions @@ -860,6 +865,8 @@ typedef void* MTLSharedEvent_id; + + Enumerated types in the header, but not used by the API @@ -1197,7 +1204,7 @@ typedef void* MTLSharedEvent_id; const void* pNext VkBufferCreateFlags flagsBuffer creation flags VkDeviceSize sizeSpecified in bytes - VkBufferUsageFlags usageBuffer usage flags + VkBufferUsageFlags usageBuffer usage flags VkSharingMode sharingMode uint32_t queueFamilyIndexCount const uint32_t* pQueueFamilyIndices @@ -4196,7 +4203,7 @@ typedef void* MTLSharedEvent_id; const void* pNext VkBool32 conditionalRenderingEnableWhether this secondary command buffer may be executed during an active conditional rendering - + VkStructureType sType void* pNext uint64_t externalFormat @@ -6972,10 +6979,10 @@ typedef void* MTLSharedEvent_id; VkStructureType sType - const void* pNext - uint32_t stdSPSCount + const void* pNext + uint32_t stdSPSCount const StdVideoH264SequenceParameterSet* pStdSPSs - uint32_t stdPPSCount + uint32_t stdPPSCount const StdVideoH264PictureParameterSet* pStdPPSsList of Picture Parameters associated with the spsStd, above @@ -7026,7 +7033,7 @@ typedef void* MTLSharedEvent_id; VkStructureType sType const void* pNext - VkVideoEncodeH264RateControlFlagsEXT flags + VkVideoEncodeH264RateControlFlagsEXT flags uint32_t gopFrameCount uint32_t idrPeriod uint32_t consecutiveBFrameCount @@ -7110,11 +7117,11 @@ typedef void* MTLSharedEvent_id; VkStructureType sType const void* pNext - uint32_t stdVPSCount + uint32_t stdVPSCount const StdVideoH265VideoParameterSet* pStdVPSs - uint32_t stdSPSCount + uint32_t stdSPSCount const StdVideoH265SequenceParameterSet* pStdSPSs - uint32_t stdPPSCount + uint32_t stdPPSCount const StdVideoH265PictureParameterSet* pStdPPSsList of Picture Parameters associated with the spsStd, above @@ -7158,7 +7165,7 @@ typedef void* MTLSharedEvent_id; VkStructureType sType const void* pNext - VkVideoEncodeH265RateControlFlagsEXT flags + VkVideoEncodeH265RateControlFlagsEXT flags uint32_t gopFrameCount uint32_t idrPeriod uint32_t consecutiveBFrameCount @@ -7766,6 +7773,18 @@ typedef void* MTLSharedEvent_id; size_t descriptorOffset uint32_t descriptorSize + + VkStructureType sType + void* pNext + VkBool32 nestedCommandBuffer + VkBool32 nestedCommandBufferRendering + VkBool32 nestedCommandBufferSimultaneousUse + + + VkStructureType sType + void* pNext + uint32_t maxCommandBufferNestingLevel + VkStructureType sType void* pNext @@ -8087,7 +8106,7 @@ typedef void* MTLSharedEvent_id; VkPipelineRobustnessImageBehaviorEXT images - VkStructureType sType + VkStructureType sType void* pNext VkPipelineRobustnessBufferBehaviorEXT defaultRobustnessStorageBuffers VkPipelineRobustnessBufferBehaviorEXT defaultRobustnessUniformBuffers @@ -8301,6 +8320,24 @@ typedef void* MTLSharedEvent_id; void* pNext VkBool32 shaderCoreBuiltins + + VkStructureType sType + const void* pNext + VkFrameBoundaryFlagsEXT flags + uint64_t frameID + uint32_t imageCount + const VkImage* pImages + uint32_t bufferCount + const VkBuffer* pBuffers + uint64_t tagName + size_t tagSize + const void* pTag + + + VkStructureType sType + void* pNext + VkBool32 frameBoundary + VkStructureType sType void* pNext @@ -8381,6 +8418,18 @@ typedef void* MTLSharedEvent_id; void* pNext VkRayTracingInvocationReorderModeNV rayTracingInvocationReorderReorderingHint + + VkStructureType sType + void* pNext + VkBool32 extendedSparseAddressSpace + + + VkStructureType sType + void* pNext + VkDeviceSize extendedSparseAddressSpaceSizeTotal address space available for extended sparse allocations (bytes) + VkImageUsageFlags extendedSparseImageUsageFlagsBitfield of which image usages are supported for extended sparse allocations + VkBufferUsageFlags extendedSparseBufferUsageFlagsBitfield of which buffer usages are supported for extended sparse allocations + VkStructureType sType void* pNext @@ -8475,18 +8524,18 @@ typedef void* MTLSharedEvent_id; const VkSpecializationInfo* pSpecializationInfo - VkStructureType sType - void* pNext - VkBool32 shaderTileImageColorReadAccess - VkBool32 shaderTileImageDepthReadAccess - VkBool32 shaderTileImageStencilReadAccess + VkStructureType sType + void* pNext + VkBool32 shaderTileImageColorReadAccess + VkBool32 shaderTileImageDepthReadAccess + VkBool32 shaderTileImageStencilReadAccess - VkStructureType sType - void* pNext - VkBool32 shaderTileImageCoherentReadAccelerated - VkBool32 shaderTileImageReadSampleFromPixelRateInvocation - VkBool32 shaderTileImageReadFromHelperInvocation + VkStructureType sType + void* pNext + VkBool32 shaderTileImageCoherentReadAccelerated + VkBool32 shaderTileImageReadSampleFromPixelRateInvocation + VkBool32 shaderTileImageReadFromHelperInvocation VkStructureType sType @@ -8593,6 +8642,143 @@ typedef void* MTLSharedEvent_id; VkDeviceOrHostAddressConstAMDX infos uint64_t stride + + VkStructureType sType + void* pNext + VkBool32 cubicRangeClamp + + + VkStructureType sType + void* pNext + VkBool32 ycbcrDegamma + + + VkStructureType sType + void* pNext + VkBool32 enableYDegamma + VkBool32 enableCbCrDegamma + + + VkStructureType sType + void* pNext + VkBool32 selectableCubicWeights + + + VkStructureType sType + const void* pNext + VkCubicFilterWeightsQCOM cubicWeights + + + VkStructureType sType + const void* pNext + VkCubicFilterWeightsQCOM cubicWeights + + + VkStructureType sType + void* pNext + VkBool32 textureBlockMatch2 + + + VkStructureType sType + void* pNext + VkExtent2D maxBlockMatchWindow + + + VkStructureType sType + const void* pNext + VkExtent2D windowExtent + VkBlockMatchWindowCompareModeQCOM windowCompareMode + + + VkStructureType sType + void* pNext + VkBool32 descriptorPoolOverallocation + + + VkStructureType sType + void* pNext + VkLayeredDriverUnderlyingApiMSFT underlyingAPI + + + VkStructureType sType + void* pNext + VkBool32 externalFormatResolve + + + VkStructureType sType + void* pNext + VkBool32 nullColorAttachmentWithExternalFormatResolve + VkChromaLocation externalFormatResolveChromaOffsetX + VkChromaLocation externalFormatResolveChromaOffsetY + + + VkStructureType sType + void* pNext + VkFormat colorAttachmentFormat + + + VkStructureType sType + const void* pNext + VkBool32 lowLatencyMode + VkBool32 lowLatencyBoost + uint32_t minimumIntervalUs + + + VkStructureType sType + const void* pNext + VkSemaphore signalSemaphore + uint64_t value + + + VkStructureType sType + const void* pNext + uint64_t presentID + VkLatencyMarkerNV marker + + + VkStructureType sType + const void* pNext + VkLatencyTimingsFrameReportNV* pTimings + + + VkStructureType sType + const void* pNext + uint64_t presentID + uint64_t inputSampleTimeUs + uint64_t simStartTimeUs + uint64_t simEndTimeUs + uint64_t renderSubmitStartTimeUs + uint64_t renderSubmitEndTimeUs + uint64_t presentStartTimeUs + uint64_t presentEndTimeUs + uint64_t driverStartTimeUs + uint64_t driverEndTimeUs + uint64_t osRenderQueueStartTimeUs + uint64_t osRenderQueueEndTimeUs + uint64_t gpuRenderStartTimeUs + uint64_t gpuRenderEndTimeUs + + + VkStructureType sType + const void* pNext + VkOutOfBandQueueTypeNV queueType + + + VkStructureType sType + const void* pNext + uint64_t presentID + + + VkStructureType sType + const void* pNext + VkBool32 latencyModeEnable + + + VkStructureType sType + const void* pNext + uint32_t presentModeCount + VkPresentModeKHR* pPresentModes + @@ -9806,6 +9992,7 @@ typedef void* MTLSharedEvent_id; + @@ -10236,6 +10423,9 @@ typedef void* MTLSharedEvent_id; + + + @@ -10315,6 +10505,7 @@ typedef void* MTLSharedEvent_id; + @@ -10357,6 +10548,8 @@ typedef void* MTLSharedEvent_id; + + @@ -10473,6 +10666,8 @@ typedef void* MTLSharedEvent_id; + + @@ -10667,6 +10862,38 @@ typedef void* MTLSharedEvent_id; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -11754,7 +11981,7 @@ typedef void* MTLSharedEvent_id; void vkCmdEndRenderPass VkCommandBuffer commandBuffer - + void vkCmdExecuteCommands VkCommandBuffer commandBuffer uint32_t commandBufferCount @@ -14497,11 +14724,11 @@ typedef void* MTLSharedEvent_id; VkShaderModuleIdentifierEXT* pIdentifier - void vkGetImageSubresourceLayout2KHR - VkDevice device - VkImage image - const VkImageSubresource2KHR* pSubresource - VkSubresourceLayout2KHR* pLayout + void vkGetImageSubresourceLayout2KHR + VkDevice device + VkImage image + const VkImageSubresource2KHR* pSubresource + VkSubresourceLayout2KHR* pLayout @@ -14680,6 +14907,36 @@ typedef void* MTLSharedEvent_id; VkDeviceAddress scratch VkDeviceAddress countInfo + + VkResult vkSetLatencySleepModeNV + VkDevice device + VkSwapchainKHR swapchain + const VkLatencySleepModeInfoNV* pSleepModeInfo + + + VkResult vkLatencySleepNV + VkDevice device + VkSwapchainKHR swapchain + const VkLatencySleepInfoNV* pSleepInfo + + + void vkSetLatencyMarkerNV + VkDevice device + VkSwapchainKHR swapchain + const VkSetLatencyMarkerInfoNV* pLatencyMarkerInfo + + + void vkGetLatencyTimingsNV + VkDevice device + VkSwapchainKHR swapchain + uint32_t* pTimingCount + VkGetLatencyMarkerInfoNV* pLatencyMarkerInfo + + + void vkQueueNotifyOutOfBandNV + VkQueue queue + const VkOutOfBandQueueTypeInfoNV* pQueueTypeInfo + @@ -16695,7 +16952,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16739,7 +16996,7 @@ typedef void* MTLSharedEvent_id; - + @@ -16922,7 +17179,7 @@ typedef void* MTLSharedEvent_id; - + @@ -18821,16 +19078,10 @@ typedef void* MTLSharedEvent_id; - + - - - - - - @@ -19043,7 +19294,6 @@ typedef void* MTLSharedEvent_id; - @@ -19920,7 +20170,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20087,13 +20337,13 @@ typedef void* MTLSharedEvent_id; - + - + @@ -20323,7 +20573,7 @@ typedef void* MTLSharedEvent_id; - + @@ -20355,6 +20605,7 @@ typedef void* MTLSharedEvent_id; + @@ -20417,13 +20668,13 @@ typedef void* MTLSharedEvent_id; - + - + @@ -20470,7 +20721,12 @@ typedef void* MTLSharedEvent_id; - + + + + + + @@ -21378,10 +21634,16 @@ typedef void* MTLSharedEvent_id; - + - - + + + + + + + + @@ -21658,9 +21920,6 @@ typedef void* MTLSharedEvent_id; - - - @@ -21802,13 +22061,13 @@ typedef void* MTLSharedEvent_id; - + - + @@ -22098,13 +22357,19 @@ typedef void* MTLSharedEvent_id; - + - - + + + + + + + + - + @@ -22259,7 +22524,7 @@ typedef void* MTLSharedEvent_id; - + @@ -22382,11 +22647,19 @@ typedef void* MTLSharedEvent_id; - + - - - + + + + + + + + + + + @@ -22395,7 +22668,7 @@ typedef void* MTLSharedEvent_id; - + @@ -22433,7 +22706,7 @@ typedef void* MTLSharedEvent_id; - + @@ -22444,8 +22717,8 @@ typedef void* MTLSharedEvent_id; - - + + @@ -22460,43 +22733,46 @@ typedef void* MTLSharedEvent_id; - + - + - + - + - - + + - - + + + + + - + - + - + - - + + @@ -22514,13 +22790,13 @@ typedef void* MTLSharedEvent_id; - - - + + + - - + + @@ -22703,8 +22979,9 @@ typedef void* MTLSharedEvent_id; - - + + + @@ -22808,10 +23085,14 @@ typedef void* MTLSharedEvent_id; - + - - + + + + + + @@ -22846,7 +23127,7 @@ typedef void* MTLSharedEvent_id; - + @@ -22902,13 +23183,38 @@ typedef void* MTLSharedEvent_id; - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -22923,7 +23229,7 @@ typedef void* MTLSharedEvent_id; - + @@ -22934,7 +23240,7 @@ typedef void* MTLSharedEvent_id; - + @@ -23001,31 +23307,52 @@ typedef void* MTLSharedEvent_id; - + - - + + + + + + + + + - + - - + + + + + + + + + - + - - + + + + + + - + - - + + + + + - + @@ -23089,10 +23416,13 @@ typedef void* MTLSharedEvent_id; - + - - + + + + + @@ -23173,12 +23503,40 @@ typedef void* MTLSharedEvent_id; - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -24774,6 +25132,9 @@ typedef void* MTLSharedEvent_id; + + + @@ -24792,6 +25153,9 @@ typedef void* MTLSharedEvent_id; + + + @@ -25251,6 +25615,9 @@ typedef void* MTLSharedEvent_id; + + + @@ -25334,7 +25701,7 @@ typedef void* MTLSharedEvent_id; - + @@ -25430,7 +25797,7 @@ typedef void* MTLSharedEvent_id; - + From bc295b3cf45e8cf1d9c2f2bbd878790ea2bfe43c Mon Sep 17 00:00:00 2001 From: Etaash Mathamsetty Date: Mon, 16 Oct 2023 15:33:54 -0400 Subject: [PATCH 2360/2777] winex11.drv: Ensure initialized thread data in X11DRV_get_ic. --- dlls/winex11.drv/xim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c index 209d63f0402..b4d675dc446 100644 --- a/dlls/winex11.drv/xim.c +++ b/dlls/winex11.drv/xim.c @@ -501,7 +501,7 @@ XIC X11DRV_get_ic( HWND hwnd ) XIC ret; if (!(data = get_win_data( hwnd ))) return 0; - x11drv_thread_data()->last_xic_hwnd = hwnd; + x11drv_init_thread_data()->last_xic_hwnd = hwnd; if (!(ret = data->xic) && (xim = x11drv_thread_data()->xim)) ret = data->xic = xic_create( xim, hwnd, data->whole_window ); release_win_data( data ); From 577ec51b4aef0f90f03d415c5a6ee9abc2231c30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 27 Sep 2023 08:24:58 +0200 Subject: [PATCH 2361/2777] winebus.sys: Append is_gamepad to the device instance id. --- dlls/winebus.sys/main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c index 15898a23d79..d1f9e45cf02 100644 --- a/dlls/winebus.sys/main.c +++ b/dlls/winebus.sys/main.c @@ -190,7 +190,10 @@ static WCHAR *get_instance_id(DEVICE_OBJECT *device) WCHAR *dst; if ((dst = ExAllocatePool(PagedPool, len * sizeof(WCHAR)))) - swprintf(dst, len, L"%i&%s&%x&%i", ext->desc.version, ext->desc.serialnumber, ext->desc.uid, ext->index); + { + swprintf(dst, len, L"%u&%s&%x&%u&%u", ext->desc.version, ext->desc.serialnumber, + ext->desc.uid, ext->index, ext->desc.is_gamepad); + } return dst; } From 27529007237cdbf8c7828cd75b0786e571b912b4 Mon Sep 17 00:00:00 2001 From: Kai Krakow Date: Sat, 2 Sep 2023 23:00:29 +0200 Subject: [PATCH 2362/2777] winebus.sys: Also pass axis and button count to is_hidraw_enabled() This is useful to detect some devices which do not have a well-known PID set. Link: https://github.com/ValveSoftware/Proton/issues/6839#issuecomment-1703856375 --- dlls/winebus.sys/bus_udev.c | 11 +++++------ dlls/winebus.sys/unix_private.h | 2 +- dlls/winebus.sys/unixlib.c | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index d3c4b705968..5da979c6c5a 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -1622,6 +1622,7 @@ static void udev_add_device(struct udev_device *dev, int fd) const char *subsystem; const char *devnode; int bus = 0; + int axes = -1, buttons = -1; if (!(devnode = udev_device_get_devnode(dev))) { @@ -1644,6 +1645,9 @@ static void udev_add_device(struct udev_device *dev, int fd) close(fd); return; } + + axes = count_abs_axis(fd); + buttons = count_buttons(fd, NULL); #endif get_device_subsystem_info(dev, "hid", &desc, &bus); @@ -1697,7 +1701,7 @@ static void udev_add_device(struct udev_device *dev, int fd) memcpy(desc.serialnumber, zeros, sizeof(zeros)); } - if (!is_hidraw_enabled(desc.vid, desc.pid)) + if (!is_hidraw_enabled(desc.vid, desc.pid, axes, buttons)) { TRACE("hidraw %s: deferring %s to a different backend\n", debugstr_a(devnode), debugstr_device_desc(&desc)); close(fd); @@ -1712,12 +1716,7 @@ static void udev_add_device(struct udev_device *dev, int fd) } #ifdef HAS_PROPER_INPUT_HEADER else - { - int axes=0, buttons=0; - axes = count_abs_axis(fd); - buttons = count_buttons(fd, NULL); desc.is_gamepad = (axes == 6 && buttons >= 14); - } #endif TRACE("dev %p, node %s, desc %s.\n", dev, debugstr_a(devnode), debugstr_device_desc(&desc)); diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index 87c3d4ad626..4e2b943e979 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -271,6 +271,6 @@ BOOL is_wine_blacklisted(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_dualshock4_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_dualsense_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_logitech_g920(WORD vid, WORD pid) DECLSPEC_HIDDEN; -BOOL is_hidraw_enabled(WORD vid, WORD pid) DECLSPEC_HIDDEN; +BOOL is_hidraw_enabled(WORD vid, WORD pid, INT axes, INT buttons) DECLSPEC_HIDDEN; #endif /* __WINEBUS_UNIX_PRIVATE_H */ diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c index d4adc78f6ec..cbfc13cf578 100644 --- a/dlls/winebus.sys/unixlib.c +++ b/dlls/winebus.sys/unixlib.c @@ -105,7 +105,7 @@ static BOOL is_fanatec_pedals(WORD vid, WORD pid) return FALSE; } -BOOL is_hidraw_enabled(WORD vid, WORD pid) +BOOL is_hidraw_enabled(WORD vid, WORD pid, INT axes, INT buttons) { const char *enabled = getenv("PROTON_ENABLE_HIDRAW"); char needle[16]; From 229aea4cabda7491936bd9a3c3b286af13f3c666 Mon Sep 17 00:00:00 2001 From: Kai Krakow Date: Tue, 29 Aug 2023 19:09:31 +0200 Subject: [PATCH 2363/2777] winebus.sys: Enable hidraw for VKB Gladiator NXT EVO. These devices ship with 128 buttons by default. For game compatibility, the VKB Windows app can be used to change the HID descriptor to show only 32 buttons and have up to 4 virtual devices instead. These devices can also show up as a mouse or keyboard and send proper HID events for that configuration - not tested with this commit. The Linux input layer gets really confused by these devices as the HID descriptor spans multiple ranges of different device type event codes. Hopefully, winebus.sys hidraw mode can work around this. Also needs udev rules to enable hidraw access. Known limits: - Elite Dangerous: 32 buttons - Star Citizen: 50 buttons - some other games: 64 buttons Signed-off-by: Kai Krakow --- dlls/winebus.sys/unixlib.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c index cbfc13cf578..32c1f9a00d9 100644 --- a/dlls/winebus.sys/unixlib.c +++ b/dlls/winebus.sys/unixlib.c @@ -105,6 +105,19 @@ static BOOL is_fanatec_pedals(WORD vid, WORD pid) return FALSE; } +static BOOL is_vkb_controller(WORD vid, WORD pid, INT buttons) +{ + if (vid != 0x231D) return FALSE; + + /* comes with 128 buttons in the default configuration */ + if (buttons == 128) return TRUE; + + /* if customized, less than 128 buttons may be shown, decide by PID */ + if (pid == 0x0200) return TRUE; /* VKBsim Gladiator EVO Right Grip */ + if (pid == 0x0201) return TRUE; /* VKBsim Gladiator EVO Left Grip */ + return FALSE; +} + BOOL is_hidraw_enabled(WORD vid, WORD pid, INT axes, INT buttons) { const char *enabled = getenv("PROTON_ENABLE_HIDRAW"); @@ -115,6 +128,7 @@ BOOL is_hidraw_enabled(WORD vid, WORD pid, INT axes, INT buttons) if (is_thrustmaster_hotas(vid, pid)) return TRUE; if (is_simucube_wheel(vid, pid)) return TRUE; if (is_fanatec_pedals(vid, pid)) return TRUE; + if (is_vkb_controller(vid, pid, buttons)) return TRUE; sprintf(needle, "0x%04x/0x%04x", vid, pid); if (enabled) return strcasestr(enabled, needle) != NULL; From 2b2f87f7774cb001085b231cfd3c5016f28181b7 Mon Sep 17 00:00:00 2001 From: Kai Krakow Date: Fri, 1 Sep 2023 05:12:21 +0200 Subject: [PATCH 2364/2777] winebus.sys: Enable hidraw for Virpil Constellation ALPHA-R. Fixes: https://github.com/ValveSoftware/Proton/issues/6839 --- dlls/winebus.sys/unixlib.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c index 32c1f9a00d9..1e08f4a1ead 100644 --- a/dlls/winebus.sys/unixlib.c +++ b/dlls/winebus.sys/unixlib.c @@ -118,6 +118,18 @@ static BOOL is_vkb_controller(WORD vid, WORD pid, INT buttons) return FALSE; } +static BOOL is_virpil_controller(WORD vid, WORD pid, INT buttons) +{ + if (vid != 0x3344) return FALSE; + + /* comes with 31 buttons in the default configuration, or 128 max */ + if ((buttons == 31) || (buttons == 128)) return TRUE; + + /* if customized, arbitrary amount of buttons may be shown, decide by PID */ + if (pid == 0x412f) return TRUE; /* Virpil Constellation ALPHA-R */ + return FALSE; +} + BOOL is_hidraw_enabled(WORD vid, WORD pid, INT axes, INT buttons) { const char *enabled = getenv("PROTON_ENABLE_HIDRAW"); @@ -129,6 +141,7 @@ BOOL is_hidraw_enabled(WORD vid, WORD pid, INT axes, INT buttons) if (is_simucube_wheel(vid, pid)) return TRUE; if (is_fanatec_pedals(vid, pid)) return TRUE; if (is_vkb_controller(vid, pid, buttons)) return TRUE; + if (is_virpil_controller(vid, pid, buttons)) return TRUE; sprintf(needle, "0x%04x/0x%04x", vid, pid); if (enabled) return strcasestr(enabled, needle) != NULL; From 969203fe4ee8cf4e1a110433319c7d648ba68d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 17 Oct 2023 09:47:56 +0200 Subject: [PATCH 2365/2777] amend! winex11.drv: Ensure initialized thread data in X11DRV_get_ic. winex11.drv: Ensure initialized thread data in X11DRV_get_ic. Link: https://github.com/ValveSoftware/wine/pull/201 From cd3d3fb7163862bb626d6f690b10a316009779c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 17 Oct 2023 09:48:27 +0200 Subject: [PATCH 2366/2777] amend! winebus.sys: Append is_gamepad to the device instance id. winebus.sys: Append is_gamepad to the device instance id. Link: https://github.com/ValveSoftware/wine/pull/197 From b3d49e939c0f4e584a882dbeb8d8e13cd0e020f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 17 Oct 2023 09:48:33 +0200 Subject: [PATCH 2367/2777] amend! winebus.sys: Also pass axis and button count to is_hidraw_enabled() winebus.sys: Also pass axis and button count to is_hidraw_enabled() This is useful to detect some devices which do not have a well-known PID set. Link: https://github.com/ValveSoftware/Proton/issues/6839#issuecomment-1703856375 Link: https://github.com/ValveSoftware/wine/pull/197 From 244511ac4b97818bac1f68eced9e180eaf17032d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 17 Oct 2023 09:48:38 +0200 Subject: [PATCH 2368/2777] amend! winebus.sys: Enable hidraw for VKB Gladiator NXT EVO. winebus.sys: Enable hidraw for VKB Gladiator NXT EVO. These devices ship with 128 buttons by default. For game compatibility, the VKB Windows app can be used to change the HID descriptor to show only 32 buttons and have up to 4 virtual devices instead. These devices can also show up as a mouse or keyboard and send proper HID events for that configuration - not tested with this commit. The Linux input layer gets really confused by these devices as the HID descriptor spans multiple ranges of different device type event codes. Hopefully, winebus.sys hidraw mode can work around this. Also needs udev rules to enable hidraw access. Known limits: - Elite Dangerous: 32 buttons - Star Citizen: 50 buttons - some other games: 64 buttons Signed-off-by: Kai Krakow Link: https://github.com/ValveSoftware/wine/pull/197 From 221c8e3893b8f1b08a435a2717687543dc2cbb0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 17 Oct 2023 09:48:43 +0200 Subject: [PATCH 2369/2777] amend! winebus.sys: Enable hidraw for Virpil Constellation ALPHA-R. winebus.sys: Enable hidraw for Virpil Constellation ALPHA-R. Fixes: https://github.com/ValveSoftware/Proton/issues/6839 Link: https://github.com/ValveSoftware/wine/pull/197 From 637902dcd157b3f4df4c497de7ac755115c81c99 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 17 Oct 2023 20:11:43 -0600 Subject: [PATCH 2370/2777] wine.inf: Substitute Times New Roman for Verdana. CW-Bug-Id: #22875 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index e31c426ca04..f0395ecc4ca 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -569,6 +569,7 @@ HKLM,%FontsNT%,"Times New Roman (TrueType)",,"times.ttf" HKLM,%FontsNT%,"Webdings (TrueType)",,"webdings.ttf" HKLM,%FontsNT%,"Wingdings (TrueType)",,"wingdings.ttf" HKCU,Software\Wine\Fonts\Replacements,"Palatino Linotype",,"Times New Roman" +HKCU,Software\Wine\Fonts\Replacements,"Verdana",,"Times New Roman" [MCI] HKLM,%Mci32Str%,"AVIVideo",,"mciavi32.dll" From bd91aa348b41b661d5b339181d1ccda13c28fb89 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Wed, 25 Jan 2023 15:20:43 +0100 Subject: [PATCH 2371/2777] advapi32: Bump random buffer size. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=54364 (cherry picked from commit 369e0cfae6052937ef6b90e8c9fe916ea6765d9b) --- dlls/advapi32/crypt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/advapi32/crypt.c b/dlls/advapi32/crypt.c index 22bcf03bba7..c3f927cfb60 100644 --- a/dlls/advapi32/crypt.c +++ b/dlls/advapi32/crypt.c @@ -2400,7 +2400,7 @@ static CRITICAL_SECTION_DEBUG random_debug = }; static CRITICAL_SECTION random_cs = { &random_debug, -1, 0, 0, 0, 0 }; -#define MAX_CPUS 128 +#define MAX_CPUS 256 static char random_buf[sizeof(SYSTEM_INTERRUPT_INFORMATION) * MAX_CPUS]; static ULONG random_len; static ULONG random_pos; From 8b9ee1b7a7da3929ae988e6a44ee48bb22aa1333 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Wed, 18 Oct 2023 18:03:34 +0200 Subject: [PATCH 2372/2777] winegstreamer: Enable new media source for Phantom Doctrine. --- dlls/winegstreamer/mf_handler.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/mf_handler.c b/dlls/winegstreamer/mf_handler.c index bd1bd810c96..0776b424da3 100644 --- a/dlls/winegstreamer/mf_handler.c +++ b/dlls/winegstreamer/mf_handler.c @@ -174,7 +174,8 @@ static HRESULT async_create_object_complete(struct async_create_object *async, if (async->flags & MF_RESOLUTION_MEDIASOURCE) { const char *sgi, *env = getenv("WINE_NEW_MEDIA_SOURCE"); - if (!env && (sgi = getenv("SteamGameId")) && (!strcmp(sgi, "692850"))) env = "1"; + if (!env && (sgi = getenv("SteamGameId")) && + (!strcmp(sgi, "692850") || !strcmp(sgi, "559100"))) env = "1"; if (!async->stream) hr = media_source_create_from_url(async->url, (IMFMediaSource **)&object); From ad7dd630b6c39b7b4c47400d44e5a147a34d8d60 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Thu, 19 Oct 2023 13:40:34 +0100 Subject: [PATCH 2373/2777] Revert "mf: Don't make stream sink shutdown dependent on IMFActivate presence in node." This reverts commit 2a1301f17302d4540e80e970e6304b09361b2cfa. This commit triggers a crash when playing videos in AVPro, reverting and looking for the correct fix for the media engine leak. --- dlls/mf/session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 2b7b4361c61..67e054a61bc 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -785,7 +785,7 @@ static void session_shutdown_current_topology(struct media_session *session) WARN("Failed to shut down activation object for the sink, hr %#lx.\n", hr); IMFActivate_Release(activate); } - if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink))) + else if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink))) { if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink))) { From 08e47ef7ce5f3287bff88480e6d6bb684947b0b0 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 19 Oct 2023 18:46:13 -0600 Subject: [PATCH 2374/2777] ntdll: Define heap block's BLOCK_FLAG_LFH as 0x80. CW-Bug-Id: #22393 --- dlls/ntdll/heap.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 9c1ccb559c0..2ec7ed1c982 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -104,12 +104,12 @@ C_ASSERT( sizeof(struct block) == 8 ); #define BLOCK_FLAG_PREV_FREE 0x02 #define BLOCK_FLAG_FREE_LINK 0x03 #define BLOCK_FLAG_LARGE 0x04 -#define BLOCK_FLAG_LFH 0x08 /* block is handled by the LFH frontend */ -#define BLOCK_FLAG_USER_INFO 0x10 /* user flags up to 0xf0 */ -#define BLOCK_FLAG_USER_MASK 0xf0 +#define BLOCK_FLAG_LFH 0x80 /* block is handled by the LFH frontend */ +#define BLOCK_FLAG_USER_INFO 0x08 /* user flags bits 3-6 */ +#define BLOCK_FLAG_USER_MASK 0x78 -#define BLOCK_USER_FLAGS( heap_flags ) (((heap_flags) >> 4) & BLOCK_FLAG_USER_MASK) -#define HEAP_USER_FLAGS( block_flags ) (((block_flags) & BLOCK_FLAG_USER_MASK) << 4) +#define BLOCK_USER_FLAGS( heap_flags ) (((heap_flags) >> 5) & BLOCK_FLAG_USER_MASK) +#define HEAP_USER_FLAGS( block_flags ) (((block_flags) & BLOCK_FLAG_USER_MASK) << 5) /* entry to link free blocks in free lists */ @@ -1949,7 +1949,7 @@ static NTSTATUS heap_allocate_block_lfh( struct heap *heap, ULONG flags, SIZE_T if ((block = find_free_bin_block( heap, flags, block_size, bin ))) { block_set_type( block, BLOCK_TYPE_USED ); - block_set_flags( block, ~BLOCK_FLAG_LFH, BLOCK_USER_FLAGS( flags ) ); + block_set_flags( block, (BYTE)~BLOCK_FLAG_LFH, BLOCK_USER_FLAGS( flags ) ); block->tail_size = block_size - sizeof(*block) - size; initialize_block( block, 0, size, flags ); mark_block_tail( block, flags ); @@ -1974,7 +1974,7 @@ static NTSTATUS heap_free_block_lfh( struct heap *heap, ULONG flags, struct bloc i = block_get_group_index( block ); valgrind_make_writable( block, sizeof(*block) ); block_set_type( block, BLOCK_TYPE_FREE ); - block_set_flags( block, ~BLOCK_FLAG_LFH, BLOCK_FLAG_FREE ); + block_set_flags( block, (BYTE)~BLOCK_FLAG_LFH, BLOCK_FLAG_FREE ); mark_block_free( block + 1, (char *)block + block_size - (char *)(block + 1), flags ); /* if this was the last used block in a group and GROUP_FLAG_FREE was set */ From 6137349ff137d9380b46731b171ff201a6cff8dd Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 20 Oct 2023 14:03:20 -0600 Subject: [PATCH 2375/2777] dnsapi: Handle IP address as DNS name in DnsQuery_UTF8(). CW-Bug-Id: #22891 --- dlls/dnsapi/query.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/dlls/dnsapi/query.c b/dlls/dnsapi/query.c index 90a3a3e9950..09d2e9c7e62 100644 --- a/dlls/dnsapi/query.c +++ b/dlls/dnsapi/query.c @@ -21,11 +21,15 @@ #include #include "windef.h" #include "winbase.h" +#include "winternl.h" #include "winerror.h" #include "winnls.h" #include "windns.h" #include "nb30.h" #include "ws2def.h" +#include "in6addr.h" +#include "inaddr.h" +#include "ip2string.h" #include "wine/debug.h" #include "dnsapi.h" @@ -169,6 +173,8 @@ DNS_STATUS WINAPI DnsQuery_UTF8( const char *name, WORD type, DWORD options, voi unsigned char answer[4096]; DWORD len = sizeof(answer); struct query_params query_params = { name, type, options, answer, &len }; + DNS_RECORDA *r; + const char *end; TRACE( "(%s, %s, %#lx, %p, %p, %p)\n", debugstr_a(name), debugstr_type( type ), options, servers, result, reserved ); @@ -176,6 +182,39 @@ DNS_STATUS WINAPI DnsQuery_UTF8( const char *name, WORD type, DWORD options, voi if (!name || !result) return ERROR_INVALID_PARAMETER; + if (type == DNS_TYPE_A) + { + struct in_addr addr; + + if (!RtlIpv4StringToAddressA(name, TRUE, &end, &addr) && !*end && (r = calloc(1, sizeof(*r)))) + { + ret = ERROR_SUCCESS; + r->Data.A.IpAddress = addr.s_addr; + r->wDataLength = sizeof(r->Data.A); + } + } + else if (type == DNS_TYPE_AAAA) + { + struct in6_addr addr; + + if (!RtlIpv6StringToAddressA(name, &end, &addr) && !*end && (r = calloc(1, sizeof(*r)))) + { + ret = ERROR_SUCCESS; + memcpy(&r->Data.AAAA.Ip6Address, &addr, sizeof(r->Data.AAAA.Ip6Address)); + r->wDataLength = sizeof(r->Data.AAAA); + } + } + if (!ret) + { + r->wType = type; + r->dwTtl = 604800; + r->pName = strdup(name); + r->Flags.S.Reserved = 0x20; + r->Flags.S.CharSet = DnsCharSetUtf8; + *result = r; + return ret; + } + if ((ret = RESOLV_CALL( set_serverlist, servers ))) return ret; ret = RESOLV_CALL( query, &query_params ); From 740f66635052033d4543f71558b34f847e21fe16 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 24 Oct 2023 12:17:28 -0600 Subject: [PATCH 2376/2777] amd_ags_x64,atiadll,wbemprox,win32u: Bump AMD driver version. --- dlls/amd_ags_x64/amd_ags_x64_main.c | 4 ++-- dlls/atiadlxx/atiadlxx_main.c | 6 +++--- dlls/wbemprox/builtin.c | 4 ++-- dlls/win32u/sysparams.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index ca0fb573e3e..1ee87f77a1e 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -23,8 +23,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(amd_ags); -static const char driver_version[] = "23.10.23.02-230720a-394204C-AMD-Software-Adrenalin-Edition"; -static const char radeon_version[] = "23.8.1"; +static const char driver_version[] = "23.19.02-230831a-396538C-AMD-Software-Adrenalin-Edition"; +static const char radeon_version[] = "23.10.2"; enum amd_ags_version { diff --git a/dlls/atiadlxx/atiadlxx_main.c b/dlls/atiadlxx/atiadlxx_main.c index 8c52dbdc601..8fdd2e55d02 100644 --- a/dlls/atiadlxx/atiadlxx_main.c +++ b/dlls/atiadlxx/atiadlxx_main.c @@ -172,15 +172,15 @@ typedef struct ADLDisplayMap } ADLDisplayMap, *LPADLDisplayMap; static const ADLVersionsInfo version = { - "23.10.23.02-230720a-394204C-AMD-Software-Adrenalin-Edition", + "23.19.02-230831a-396538C-AMD-Software-Adrenalin-Edition", "", "http://support.amd.com/drivers/xml/driver_09_us.xml", }; static const ADLVersionsInfoX2 version2 = { - "23.10.23.02-230720a-394204C-AMD-Software-Adrenalin-Edition", + "23.19.02-230831a-396538C-AMD-Software-Adrenalin-Edition", "", - "23.8.1", + "23.10.2", "http://support.amd.com/drivers/xml/driver_09_us.xml", }; diff --git a/dlls/wbemprox/builtin.c b/dlls/wbemprox/builtin.c index c98f1c6c975..18cea97bfe1 100644 --- a/dlls/wbemprox/builtin.c +++ b/dlls/wbemprox/builtin.c @@ -4161,8 +4161,8 @@ static enum fill_status fill_videocontroller( struct table *table, const struct rec->current_verticalres = vres; rec->description = wcsdup( name ); rec->device_id = L"VideoController1"; - rec->driverdate = L"20230420000000.000000-000"; - rec->driverversion = L"31.0.14051.5006"; + rec->driverdate = L"20230831000000.000000-000"; + rec->driverversion = L"31.0.21902.5"; rec->installeddriver = get_videocontroller_installeddriver( desc.VendorId ); rec->name = wcsdup( name ); rec->pnpdevice_id = get_videocontroller_pnpdeviceid( &desc ); diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 5a0f34fbc32..78eb933cc69 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -1381,7 +1381,7 @@ static void add_gpu( const struct gdi_gpu *gpu, void *param ) break; /* AMD */ case 0x1002: - sprintf( buffer, "31.0.14051.5006" ); + sprintf( buffer, "31.0.21902.5" ); break; /* Nvidia */ case 0x10de: From ee9e5fcb0b27c52f955f2ea435f4117b6efd7ec5 Mon Sep 17 00:00:00 2001 From: Esme Povirk Date: Mon, 23 Oct 2023 10:06:17 -0500 Subject: [PATCH 2377/2777] mscoree: Update Wine Mono to 8.1.0. (cherry picked from commit 9c1ffb545f350743e71cdfcc0dae5e98324d10ee) --- dlls/appwiz.cpl/addons.c | 4 ++-- dlls/mscoree/mscoree_private.h | 2 +- tools/gitlab/test.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/appwiz.cpl/addons.c b/dlls/appwiz.cpl/addons.c index 3f0b8b2c03e..a2145a7fdb8 100644 --- a/dlls/appwiz.cpl/addons.c +++ b/dlls/appwiz.cpl/addons.c @@ -58,10 +58,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl); #define GECKO_SHA "???" #endif -#define MONO_VERSION "8.0.1" +#define MONO_VERSION "8.1.0" #if defined(__i386__) || defined(__x86_64__) #define MONO_ARCH "x86" -#define MONO_SHA "27240085f5b4f8b175ff0479f3d6cc4309b00adbb386c00ba1fddd30f0367976" +#define MONO_SHA "0ed3ec533aef79b2f312155931cf7b1080009ac0c5b4c2bcfeb678ac948e0810" #else #define MONO_ARCH "" #define MONO_SHA "???" diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h index ca8ba343be3..dcbb531770b 100644 --- a/dlls/mscoree/mscoree_private.h +++ b/dlls/mscoree/mscoree_private.h @@ -45,7 +45,7 @@ extern HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version) extern HRESULT assembly_get_vtable_fixups(ASSEMBLY *assembly, VTableFixup **fixups, DWORD *count) DECLSPEC_HIDDEN; extern HRESULT assembly_get_native_entrypoint(ASSEMBLY *assembly, NativeEntryPointFunc *func) DECLSPEC_HIDDEN; -#define WINE_MONO_VERSION "8.0.1" +#define WINE_MONO_VERSION "8.1.0" /* Mono embedding */ typedef struct _MonoDomain MonoDomain; diff --git a/tools/gitlab/test.yml b/tools/gitlab/test.yml index 09387a26439..852ae72d8ef 100644 --- a/tools/gitlab/test.yml +++ b/tools/gitlab/test.yml @@ -7,7 +7,7 @@ variables: GIT_STRATEGY: none GECKO_VER: 2.47.3 - MONO_VER: 8.0.1 + MONO_VER: 8.1.0 cache: - key: wine-gecko-$GECKO_VER paths: From 8855b754068988adab22c50aa8c3a84075c2cd4f Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Wed, 25 Oct 2023 23:24:37 +0300 Subject: [PATCH 2378/2777] HACK: faudio: Support WMA3. Needs to be upstreamed. Helps with METAL GEAR SOLID 3: Snake Eater - Master Collection Version crashing. Transcoding doesn't quite work yet as we seem to lose some caps on the way to protonaudioconverter. --- libs/faudio/src/FAudio.c | 7 ++++++- libs/faudio/src/FAudio_internal.c | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/libs/faudio/src/FAudio.c b/libs/faudio/src/FAudio.c index 559837c410b..7d34b666535 100644 --- a/libs/faudio/src/FAudio.c +++ b/libs/faudio/src/FAudio.c @@ -293,7 +293,8 @@ uint32_t FAudio_CreateSourceVoice( if ( pSourceFormat->wFormatTag == FAUDIO_FORMAT_PCM || pSourceFormat->wFormatTag == FAUDIO_FORMAT_IEEE_FLOAT || - pSourceFormat->wFormatTag == FAUDIO_FORMAT_WMAUDIO2 ) + pSourceFormat->wFormatTag == FAUDIO_FORMAT_WMAUDIO2 || + pSourceFormat->wFormatTag == FAUDIO_FORMAT_WMAUDIO3 ) { FAudioWaveFormatExtensible *fmtex = (FAudioWaveFormatExtensible*) audio->pMalloc( sizeof(FAudioWaveFormatExtensible) @@ -320,6 +321,10 @@ uint32_t FAudio_CreateSourceVoice( { FAudio_memcpy(&fmtex->SubFormat, &DATAFORMAT_SUBTYPE_WMAUDIO2, sizeof(FAudioGUID)); } + else if (pSourceFormat->wFormatTag == FAUDIO_FORMAT_WMAUDIO3) + { + FAudio_memcpy(&fmtex->SubFormat, &DATAFORMAT_SUBTYPE_WMAUDIO3, sizeof(FAudioGUID)); + } (*ppSourceVoice)->src.format = &fmtex->Format; } else if (pSourceFormat->wFormatTag == FAUDIO_FORMAT_MSADPCM) diff --git a/libs/faudio/src/FAudio_internal.c b/libs/faudio/src/FAudio_internal.c index 85a0ca588f0..765b1fa0899 100644 --- a/libs/faudio/src/FAudio_internal.c +++ b/libs/faudio/src/FAudio_internal.c @@ -105,6 +105,7 @@ static const char *get_wformattag_string(const FAudioWaveFormatEx *fmt) FMT_STRING(IEEE_FLOAT) FMT_STRING(XMAUDIO2) FMT_STRING(WMAUDIO2) + FMT_STRING(WMAUDIO3) FMT_STRING(EXTENSIBLE) #undef FMT_STRING return "UNKNOWN!"; From 3ae123564b03cf01b5fab97153d5c698ae8ef101 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 25 Oct 2023 14:23:20 -0600 Subject: [PATCH 2379/2777] shell32: Use SearchPathW() for %l/%L in SHELL_ArgifyW(). CW-Bug-Id: #22879 --- dlls/shell32/shlexec.c | 13 +++++++++---- dlls/shell32/tests/shlexec.c | 27 ++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c index 2d1830ad838..2d869b765d6 100644 --- a/dlls/shell32/shlexec.c +++ b/dlls/shell32/shlexec.c @@ -77,7 +77,7 @@ static BOOL SHELL_ArgifyW(WCHAR* out, int len, const WCHAR* fmt, const WCHAR* lp BOOL found_p1 = FALSE; PWSTR res = out; PCWSTR cmd; - DWORD used = 0; + DWORD size, used = 0; TRACE("%p, %d, %s, %s, %p, %p\n", out, len, debugstr_w(fmt), debugstr_w(lpFile), pidl, args); @@ -164,11 +164,16 @@ static BOOL SHELL_ArgifyW(WCHAR* out, int len, const WCHAR* fmt, const WCHAR* lp case 'l': case 'L': if (lpFile) { - used += lstrlenW(lpFile); + if ((size = SearchPathW(NULL, lpFile, L".exe", ARRAY_SIZE(xlpFile), xlpFile, NULL) + && size <= ARRAY_SIZE(xlpFile))) + cmd = xlpFile; + else + cmd = lpFile; + used += lstrlenW(cmd); if (used < len) { - lstrcpyW(res, lpFile); - res += lstrlenW(lpFile); + lstrcpyW(res, cmd); + res += lstrlenW(cmd); } } found_p1 = TRUE; diff --git a/dlls/shell32/tests/shlexec.c b/dlls/shell32/tests/shlexec.c index b84a96a2434..0ed59215248 100644 --- a/dlls/shell32/tests/shlexec.c +++ b/dlls/shell32/tests/shlexec.c @@ -1624,7 +1624,7 @@ static void test_argify(void) static void test_filename(void) { - char filename[MAX_PATH + 20]; + char filename[MAX_PATH + 20], curdir[MAX_PATH]; const filename_tests_t* test; char* c; INT_PTR rc; @@ -1635,6 +1635,31 @@ static void test_filename(void) return; } + GetCurrentDirectoryA(sizeof(curdir), curdir); + + SetCurrentDirectoryA(tmpdir); + rc=shell_execute("QuotedLowerL", "simple.shlexec", NULL, NULL); + if (rc > 32) + rc=33; + okShell(rc == 33, "failed: rc=%Id err=%lu\n", rc, GetLastError()); + okChildInt("argcA", 5); + okChildString("argvA3", "QuotedLowerL"); + strcpy(filename, tmpdir); + strcat(filename, "\\simple.shlexec"); + okChildPath("argvA4", filename); + + rc=shell_execute("QuotedUpperL", "simple.shlexec", NULL, NULL); + if (rc > 32) + rc=33; + okShell(rc == 33, "failed: rc=%Id err=%lu\n", rc, GetLastError()); + okChildInt("argcA", 5); + okChildString("argvA3", "QuotedUpperL"); + strcpy(filename, tmpdir); + strcat(filename, "\\simple.shlexec"); + okChildPath("argvA4", filename); + + SetCurrentDirectoryA(curdir); + test=filename_tests; while (test->basename) { From a735619cbd73721ec52413a7b66294e95f6805f7 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Fri, 27 Oct 2023 19:35:17 +0100 Subject: [PATCH 2380/2777] mfmediaengine: Be a bit more conservative with locks in engine Shutdown. During engine shutdown we acquire engine lock first, then locks of its constituents (e.g. sample grabbers); whereas normally the order is the other way around (e.g. timer callback -> acquire sample grabber lock -> OnProcessSample callback -> engine lock). This is deadlock prone. With this commit, engine lock is released before we shutdown the inner media session. --- dlls/mfmediaengine/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index bbe7248c145..ed9bd75f797 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -2201,6 +2201,7 @@ static HRESULT WINAPI media_engine_GetVideoAspectRatio(IMFMediaEngineEx *iface, static HRESULT WINAPI media_engine_Shutdown(IMFMediaEngineEx *iface) { struct media_engine *engine = impl_from_IMFMediaEngineEx(iface); + IMFMediaSession *session; HRESULT hr = S_OK; TRACE("%p.\n", iface); @@ -2212,10 +2213,13 @@ static HRESULT WINAPI media_engine_Shutdown(IMFMediaEngineEx *iface) { media_engine_set_flag(engine, FLAGS_ENGINE_SHUT_DOWN, TRUE); media_engine_clear_presentation(engine); - IMFMediaSession_Shutdown(engine->session); + IMFMediaSession_AddRef(engine->session); + session = engine->session; } LeaveCriticalSection(&engine->cs); + IMFMediaSession_Shutdown(session); + IMFMediaSession_Release(session); return hr; } From 7170754230ed10cfc76130d9d2c0e12123dd1577 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Fri, 27 Oct 2023 19:37:03 +0100 Subject: [PATCH 2381/2777] Revert "Revert "mf: Don't make stream sink shutdown dependent on IMFActivate presence in node."" This reverts commit ad7dd630b6c39b7b4c47400d44e5a147a34d8d60. I have identified and fixed the deadlock unveiled by the quoted fix, so reverting the revert. --- dlls/mf/session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 67e054a61bc..2b7b4361c61 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -785,7 +785,7 @@ static void session_shutdown_current_topology(struct media_session *session) WARN("Failed to shut down activation object for the sink, hr %#lx.\n", hr); IMFActivate_Release(activate); } - else if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink))) + if (SUCCEEDED(topology_node_get_object(node, &IID_IMFStreamSink, (void **)&stream_sink))) { if (SUCCEEDED(IMFStreamSink_GetMediaSink(stream_sink, &sink))) { From c701ddda006e3ded4f6a2b5d6d35a33f77f6a0d7 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Fri, 27 Oct 2023 19:48:07 +0100 Subject: [PATCH 2382/2777] amend! Revert "Revert "mf: Don't make stream sink shutdown dependent on IMFActivate presence in node."" Revert "Revert "mf: Don't make stream sink shutdown dependent on IMFActivate presence in node."" This reverts commit ad7dd630b6c39b7b4c47400d44e5a147a34d8d60. I have identified and fixed the deadlock unveiled by the quoted fix, so reverting the revert. CW-Bug-Id: #22798 From b4f03ce16929e49209a98d3a66097afaa6508c87 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Fri, 27 Oct 2023 19:48:40 +0100 Subject: [PATCH 2383/2777] amend! mfmediaengine: Be a bit more conservative with locks in engine Shutdown. mfmediaengine: Be a bit more conservative with locks in engine Shutdown. During engine shutdown we acquire engine lock first, then locks of its constituents (e.g. sample grabbers); whereas normally the order is the other way around (e.g. timer callback -> acquire sample grabber lock -> OnProcessSample callback -> engine lock). This is deadlock prone. With this commit, engine lock is released before we shutdown the inner media session. CW-Bug-Id: #22798 From 1182ef740346c62b76992f425593fa72e23203a7 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 30 Oct 2023 10:48:12 -0600 Subject: [PATCH 2384/2777] win32u: Support DisplayConfigGetDeviceInfo(DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO) based on Gamescope setting. CW-Bug-Id: #22912 --- dlls/win32u/sysparams.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 78eb933cc69..a771b1fbc02 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -6101,11 +6101,36 @@ NTSTATUS WINAPI NtUserDisplayConfigGetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEAD return STATUS_NOT_SUPPORTED; } + case DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO: + { + DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO *info = (DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO *)packet; + const char *env; + + FIXME( "DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO semi-stub.\n" ); + + if (packet->size < sizeof(*info)) + return STATUS_INVALID_PARAMETER; + + info->advancedColorSupported = 0; + info->advancedColorEnabled = 0; + info->wideColorEnforced = 0; + info->advancedColorForceDisabled = 0; + info->colorEncoding = DISPLAYCONFIG_COLOR_ENCODING_RGB; + info->bitsPerColorChannel = 8; + if ((env = getenv("DXVK_HDR")) && *env == '1') + { + TRACE( "HDR is enabled.\n" ); + info->advancedColorSupported = 1; + info->advancedColorEnabled = 1; + info->bitsPerColorChannel = 10; + } + + return STATUS_SUCCESS; + } case DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE: case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE: case DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION: case DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION: - case DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO: case DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE: case DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL: default: From 37babf65d536102e438f6820faa48aa68e0330b4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 30 Oct 2023 17:54:13 -0600 Subject: [PATCH 2385/2777] ntdll: Handle LFH blocks allocated in large blocks in heap_validate_ptr(). Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55842 CW-Bug-Id: #22393 --- dlls/ntdll/heap.c | 62 +++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 2ec7ed1c982..7c69539be52 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -1053,17 +1053,17 @@ static NTSTATUS heap_free_large( struct heap *heap, ULONG flags, struct block *b } -/*********************************************************************** - * find_large_block - */ -static BOOL find_large_block( const struct heap *heap, const struct block *block ) +static ARENA_LARGE *find_arena_large( const struct heap *heap, const struct block *block, BOOL heap_walk ) { ARENA_LARGE *arena; LIST_FOR_EACH_ENTRY( arena, &heap->large_list, ARENA_LARGE, entry ) - if (block == &arena->block) return TRUE; + { + if (contains( &arena->block, arena->block_size, block, 1 )) + return !heap_walk || block == &arena->block ? arena : NULL; + } - return FALSE; + return NULL; } static BOOL validate_large_block( const struct heap *heap, const struct block *block ) @@ -1223,11 +1223,35 @@ static BOOL validate_free_block( const struct heap *heap, const SUBHEAP *subheap static BOOL validate_used_block( const struct heap *heap, const SUBHEAP *subheap, const struct block *block, unsigned int expected_block_type ) { - const char *err = NULL, *base = subheap_base( subheap ), *commit_end = subheap_commit_end( subheap ); + const char *err = NULL, *base = NULL, *commit_end; DWORD flags = heap->flags; const struct block *next; + ARENA_LARGE *arena_large; int i; + if (subheap) + { + base = subheap_base( subheap ); + commit_end = subheap_commit_end( subheap ); + } + else if ((arena_large = find_arena_large( heap, block, FALSE ))) + { + if (!validate_large_block( heap, &arena_large->block )) return FALSE; + if (block == &arena_large->block) return TRUE; + + if (block_get_flags( block ) & BLOCK_FLAG_LFH + && contains( &arena_large->block + 1, arena_large->data_size, block, 1 )) + { + base = (const char *)(&arena_large->block + 1); + commit_end = base + arena_large->data_size; + } + } + if (!base) + { + WARN( "heap %p, ptr %p: block region not found.\n", heap, block + 1 ); + return FALSE; + } + if ((ULONG_PTR)(block + 1) % BLOCK_ALIGN) err = "invalid block BLOCK_ALIGN"; else if (block_get_type( block ) != BLOCK_TYPE_USED && block_get_type( block ) != BLOCK_TYPE_DEAD) @@ -1240,9 +1264,8 @@ static BOOL validate_used_block( const struct heap *heap, const SUBHEAP *subheap err = "invalid block size"; else if (block->tail_size > block_get_size( block ) - sizeof(*block)) err = "invalid block unused size"; - else if ((next = next_block( subheap, block )) && (block_get_flags( next ) & BLOCK_FLAG_PREV_FREE) && - /* LFH blocks do not use BLOCK_FLAG_PREV_FREE or back pointer */ - !(block_get_flags( block ) & BLOCK_FLAG_LFH)) + else if (!(block_get_flags( block ) & BLOCK_FLAG_LFH) /* LFH blocks do not use BLOCK_FLAG_PREV_FREE or back pointer */ + && (next = next_block( subheap, block )) && (block_get_flags( next ) & BLOCK_FLAG_PREV_FREE)) err = "invalid next block flags"; else if (block_get_flags( block ) & BLOCK_FLAG_PREV_FREE) { @@ -1283,20 +1306,8 @@ static BOOL validate_used_block( const struct heap *heap, const SUBHEAP *subheap static BOOL heap_validate_ptr( const struct heap *heap, const void *ptr ) { const struct block *block = (struct block *)ptr - 1; - const SUBHEAP *subheap; - - if (!(subheap = find_subheap( heap, block, FALSE ))) - { - if (!find_large_block( heap, block )) - { - WARN("heap %p, ptr %p: block region not found\n", heap, ptr ); - return FALSE; - } - return validate_large_block( heap, block ); - } - - return validate_used_block( heap, subheap, block, BLOCK_TYPE_USED ); + return validate_used_block( heap, find_subheap( heap, block, FALSE ), block, BLOCK_TYPE_USED ); } static BOOL heap_validate( const struct heap *heap ) @@ -2453,7 +2464,7 @@ static NTSTATUS heap_walk_blocks( const struct heap *heap, const SUBHEAP *subhea static NTSTATUS heap_walk( const struct heap *heap, struct rtl_heap_entry *entry ) { const char *data = entry->lpData; - const ARENA_LARGE *large = NULL; + const ARENA_LARGE *large; const struct block *block; const struct list *next; const SUBHEAP *subheap; @@ -2464,9 +2475,8 @@ static NTSTATUS heap_walk( const struct heap *heap, struct rtl_heap_entry *entry else if (entry->wFlags & RTL_HEAP_ENTRY_BUSY) block = (struct block *)data - 1; else block = (struct block *)(data - sizeof(struct list)) - 1; - if (find_large_block( heap, block )) + if ((large = find_arena_large( heap, block, TRUE ))) { - large = CONTAINING_RECORD( block, ARENA_LARGE, block ); next = &large->entry; } else if ((subheap = find_subheap( heap, block, TRUE ))) From f6c1a78909f93b364aa4f90e77feb30683dee203 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 30 Oct 2023 19:43:51 -0600 Subject: [PATCH 2386/2777] ntdll: Fix pending free block validation in heap_validate() for LFH blocks. CW-Bug-Id: #22393 --- dlls/ntdll/heap.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c index 7c69539be52..70df6815ef1 100644 --- a/dlls/ntdll/heap.c +++ b/dlls/ntdll/heap.c @@ -1346,15 +1346,11 @@ static BOOL heap_validate( const struct heap *heap ) { if (!(block = heap->pending_free[i])) break; - subheap = find_subheap( heap, block, FALSE ); - if (!subheap) + if (!validate_used_block( heap, find_subheap( heap, block, FALSE ), block, BLOCK_TYPE_DEAD )) { - ERR( "heap %p: cannot find valid subheap for delayed freed block %p\n", heap, block ); - if (TRACE_ON(heap)) heap_dump( heap ); + ERR( "heap %p: failed to to validate delayed free block %p\n", heap, block ); return FALSE; } - - if (!validate_used_block( heap, subheap, block, BLOCK_TYPE_DEAD )) return FALSE; } for (; i < MAX_FREE_PENDING; i++) From b289187d81465a2d4c29a125123807bca851231c Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 30 Oct 2023 20:31:58 -0600 Subject: [PATCH 2387/2777] winmm: Fix pszSound allocation in PlaySound_Alloc(). CW-Bug-Id: #22393 --- dlls/winmm/playsound.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dlls/winmm/playsound.c b/dlls/winmm/playsound.c index d844bf9b0ab..314eb7fbe37 100644 --- a/dlls/winmm/playsound.c +++ b/dlls/winmm/playsound.c @@ -233,8 +233,9 @@ static WINE_PLAYSOUND* PlaySound_Alloc(const void* pszSound, HMODULE hmod, else { UNICODE_STRING usBuffer; - RtlCreateUnicodeStringFromAsciiz(&usBuffer, pszSound); - wps->pszSound = usBuffer.Buffer; + if (!RtlCreateUnicodeStringFromAsciiz(&usBuffer, pszSound)) goto oom_error; + wps->pszSound = wcsdup(usBuffer.Buffer); + HeapFree(GetProcessHeap(), 0, usBuffer.Buffer); if (!wps->pszSound) goto oom_error; wps->bAlloc = TRUE; } From 9b1f375674e9e72511b0d045d00a10d49cc57c1f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 30 Oct 2023 22:53:38 -0600 Subject: [PATCH 2388/2777] Revert "winmm: Fix pszSound allocation in PlaySound_Alloc()." This reverts commit b289187d81465a2d4c29a125123807bca851231c. --- dlls/winmm/playsound.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dlls/winmm/playsound.c b/dlls/winmm/playsound.c index 314eb7fbe37..d844bf9b0ab 100644 --- a/dlls/winmm/playsound.c +++ b/dlls/winmm/playsound.c @@ -233,9 +233,8 @@ static WINE_PLAYSOUND* PlaySound_Alloc(const void* pszSound, HMODULE hmod, else { UNICODE_STRING usBuffer; - if (!RtlCreateUnicodeStringFromAsciiz(&usBuffer, pszSound)) goto oom_error; - wps->pszSound = wcsdup(usBuffer.Buffer); - HeapFree(GetProcessHeap(), 0, usBuffer.Buffer); + RtlCreateUnicodeStringFromAsciiz(&usBuffer, pszSound); + wps->pszSound = usBuffer.Buffer; if (!wps->pszSound) goto oom_error; wps->bAlloc = TRUE; } From 0c1e130d6415dce0daa1c3cca72db5601c1860bc Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 31 Oct 2023 17:55:00 -0600 Subject: [PATCH 2389/2777] winex11.drv: fshack: Add optional centered low res modes. CW-Bug-Id: #22802 --- dlls/winex11.drv/fs.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/fs.c b/dlls/winex11.drv/fs.c index 1c135fbebed..c883b8f358e 100644 --- a/dlls/winex11.drv/fs.c +++ b/dlls/winex11.drv/fs.c @@ -248,6 +248,8 @@ static void modes_append( DEVMODEW *modes, UINT *mode_count, UINT *resolutions, if (modes[i].dmBitsPerPel != mode->dmBitsPerPel) continue; if (modes[i].dmDisplayFrequency != mode->dmDisplayFrequency) continue; if (modes[i].dmDisplayOrientation != mode->dmDisplayOrientation) continue; + if ((mode->dmFields & DM_DISPLAYFIXEDOUTPUT) != (modes[i].dmFields & DM_DISPLAYFIXEDOUTPUT)) continue; + if (mode->dmFields & DM_DISPLAYFIXEDOUTPUT && modes[i].dmDisplayFixedOutput != mode->dmDisplayFixedOutput) continue; return; /* The exact mode is already added, nothing to do */ } @@ -259,7 +261,7 @@ static void modes_append( DEVMODEW *modes, UINT *mode_count, UINT *resolutions, } mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | - DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY; + DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | (mode->dmFields & DM_DISPLAYFIXEDOUTPUT); mode->dmSize = sizeof(DEVMODEW); mode->dmDriverExtra = 0; mode->dmDisplayFlags = 0; @@ -274,7 +276,7 @@ static void monitor_get_modes( struct fs_monitor *monitor, DEVMODEW **modes, UIN { UINT i, j, max_count, real_mode_count, resolutions = 0; DEVMODEW *real_modes, *real_mode, mode_host = {0}; - BOOL additional_modes = FALSE, landscape; + BOOL additional_modes = FALSE, center_modes = FALSE, landscape; const char *env; *mode_count = 0; @@ -304,6 +306,11 @@ static void monitor_get_modes( struct fs_monitor *monitor, DEVMODEW **modes, UIN else if ((env = getenv( "SteamAppId" ))) additional_modes = !strcmp( env, "979400" ); + if ((env = getenv( "WINE_CENTER_DISPLAY_MODES" ))) + center_modes = (env[0] != '0'); + else if ((env = getenv( "SteamAppId" ))) + center_modes = !strcmp( env, "359870" ); + /* Linux reports far fewer resolutions than Windows. Add modes that some games may expect. */ for (i = 0; i < ARRAY_SIZE(fs_monitor_sizes); ++i) { @@ -332,6 +339,13 @@ static void monitor_get_modes( struct fs_monitor *monitor, DEVMODEW **modes, UIN mode.dmDisplayFrequency = 60; modes_append( *modes, mode_count, &resolutions, &mode ); } + + if (center_modes && mode.dmPelsWidth != mode_host.dmPelsWidth && mode.dmPelsHeight != mode_host.dmPelsHeight) + { + mode.dmFields |= DM_DISPLAYFIXEDOUTPUT; + mode.dmDisplayFixedOutput = DMDFO_CENTER; + modes_append( *modes, mode_count, &resolutions, &mode ); + } } for (i = 0, real_mode = real_modes; i < real_mode_count; ++i) @@ -340,8 +354,17 @@ static void monitor_get_modes( struct fs_monitor *monitor, DEVMODEW **modes, UIN /* Don't report modes that are larger than the current mode */ if (mode.dmPelsWidth <= mode_host.dmPelsWidth && mode.dmPelsHeight <= mode_host.dmPelsHeight) + { modes_append( *modes, mode_count, &resolutions, &mode ); + if (center_modes && mode.dmPelsWidth != mode_host.dmPelsWidth && mode.dmPelsHeight != mode_host.dmPelsHeight) + { + mode.dmFields |= DM_DISPLAYFIXEDOUTPUT; + mode.dmDisplayFixedOutput = DMDFO_CENTER; + modes_append( *modes, mode_count, &resolutions, &mode ); + } + } + real_mode = NEXT_DEVMODEW(real_mode); } From 14c2a2b8ad37d514f778d19f997af9d45e8f18b4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 2 Nov 2023 10:03:35 -0600 Subject: [PATCH 2390/2777] fixup! winex11.drv: fshack: Add optional centered low res modes. CW-Bug-Id: #22802 --- dlls/winex11.drv/fs.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/dlls/winex11.drv/fs.c b/dlls/winex11.drv/fs.c index c883b8f358e..4113d1eb4e6 100644 --- a/dlls/winex11.drv/fs.c +++ b/dlls/winex11.drv/fs.c @@ -286,7 +286,14 @@ static void monitor_get_modes( struct fs_monitor *monitor, DEVMODEW **modes, UIN /* Fullscreen hack doesn't support changing display orientations */ if (!real_settings_handler.get_modes( monitor->adapter_id, 0, &real_modes, &real_mode_count )) return; + if ((env = getenv( "WINE_CENTER_DISPLAY_MODES" ))) + center_modes = (env[0] != '0'); + else if ((env = getenv( "SteamAppId" ))) + center_modes = !strcmp( env, "359870" ); + max_count = ARRAY_SIZE(fs_monitor_sizes) * DEPTH_COUNT + real_mode_count; + if (center_modes) max_count += ARRAY_SIZE(fs_monitor_sizes) + real_mode_count; + if (!(*modes = calloc( max_count, sizeof(DEVMODEW) ))) { real_settings_handler.free_modes( real_modes ); @@ -306,11 +313,6 @@ static void monitor_get_modes( struct fs_monitor *monitor, DEVMODEW **modes, UIN else if ((env = getenv( "SteamAppId" ))) additional_modes = !strcmp( env, "979400" ); - if ((env = getenv( "WINE_CENTER_DISPLAY_MODES" ))) - center_modes = (env[0] != '0'); - else if ((env = getenv( "SteamAppId" ))) - center_modes = !strcmp( env, "359870" ); - /* Linux reports far fewer resolutions than Windows. Add modes that some games may expect. */ for (i = 0; i < ARRAY_SIZE(fs_monitor_sizes); ++i) { From ea2ee1a6e991d98a00a402ee656fe0b03cad3b9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 18 Oct 2023 14:28:52 +0200 Subject: [PATCH 2391/2777] win32u: Ignore emulated mouse messages on touch-enabled windows. CW-Bug-Id: #22849 --- dlls/win32u/message.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 6a9e77f796c..6284f0452b9 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1639,6 +1639,12 @@ static BOOL process_mouse_message( MSG *msg, UINT hw_id, ULONG_PTR extra_info, H msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt ); SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( msg->hwnd )); + if ((extra_info & 0xffffff00) == 0xff515700 && NtUserIsTouchWindow( msg->hwnd, NULL )) + { + accept_hardware_message( hw_id ); + return FALSE; + } + if ((extra_info & 0xffffff00) != 0xff515700 && enable_mouse_in_pointer) { WORD flags = POINTER_MESSAGE_FLAG_PRIMARY; From 2095aab12e080deec6bfab66d5c2f1da74c5f464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Sep 2023 11:39:32 +0200 Subject: [PATCH 2392/2777] Revert "dmime: Play a sound in IDirectMusicPerformance8 PlaySegmentEx" This reverts commit 54f9d5977c4aa6cde75b9384e8c2e4a4b0afbbde. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/dmime_private.h | 1 - dlls/dmime/performance.c | 25 ++++++------------------- dlls/dmime/segment.c | 6 ------ 3 files changed, 6 insertions(+), 26 deletions(-) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index d09aba02a5c..030aab50094 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -72,7 +72,6 @@ extern void set_audiopath_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffe extern void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*) DECLSPEC_HIDDEN; extern IDirectSound *get_dsound_interface(IDirectMusicPerformance8*) DECLSPEC_HIDDEN; -extern IDirectSoundBuffer *get_segment_buffer(IDirectMusicSegment8 *iface) DECLSPEC_HIDDEN; /***************************************************************************** * Auxiliary definitions diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 03e59e95af3..5578c3e523b 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1043,26 +1043,13 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_PlaySegmentEx(IDirectMusicPer __int64 i64StartTime, IDirectMusicSegmentState **ppSegmentState, IUnknown *pFrom, IUnknown *pAudioPath) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); - IDirectMusicSegment8 *segment; - IDirectSoundBuffer *buffer; - HRESULT hr; - - FIXME("(%p, %p, %p, %p, %ld, 0x%s, %p, %p, %p): semi-stub\n", This, pSource, pwzSegmentName, - pTransition, dwFlags, wine_dbgstr_longlong(i64StartTime), ppSegmentState, pFrom, pAudioPath); - - hr = IUnknown_QueryInterface(pSource, &IID_IDirectMusicSegment8, (void**)&segment); - if (FAILED(hr)) - return hr; - - buffer = get_segment_buffer(segment); - - if (segment) - hr = IDirectSoundBuffer_Play(buffer, 0, 0, 0); + IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); - if (ppSegmentState) - return create_dmsegmentstate(&IID_IDirectMusicSegmentState,(void**)ppSegmentState); - return S_OK; + FIXME("(%p, %p, %p, %p, %ld, 0x%s, %p, %p, %p): stub\n", This, pSource, pwzSegmentName, + pTransition, dwFlags, wine_dbgstr_longlong(i64StartTime), ppSegmentState, pFrom, pAudioPath); + if (ppSegmentState) + return create_dmsegmentstate(&IID_IDirectMusicSegmentState,(void**)ppSegmentState); + return S_OK; } static HRESULT WINAPI IDirectMusicPerformance8Impl_StopEx(IDirectMusicPerformance8 *iface, diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index b21f93bbfc6..0ea0c15c5e0 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -47,12 +47,6 @@ static inline IDirectMusicSegment8Impl *impl_from_IDirectMusicSegment8(IDirectMu return CONTAINING_RECORD(iface, IDirectMusicSegment8Impl, IDirectMusicSegment8_iface); } -IDirectSoundBuffer *get_segment_buffer(IDirectMusicSegment8 *iface) -{ - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - return This->buffer; -} - static HRESULT WINAPI IDirectMusicSegment8Impl_QueryInterface(IDirectMusicSegment8 *iface, REFIID riid, void **ret_iface) { From 0f3347656e5f5002744829499ef6d1a1f762b1e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Sep 2023 11:39:33 +0200 Subject: [PATCH 2393/2777] Revert "dmime: Implement IDirectMusicSegment8 Download" This reverts commit 2e430ec92e2628a563135470348c6190b80fa970. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/dmime_private.h | 2 - dlls/dmime/performance.c | 7 --- dlls/dmime/segment.c | 87 ++------------------------------------ 3 files changed, 3 insertions(+), 93 deletions(-) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 030aab50094..4159abffa99 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -71,8 +71,6 @@ extern void set_audiopath_perf_pointer(IDirectMusicAudioPath*,IDirectMusicPerfor extern void set_audiopath_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*) DECLSPEC_HIDDEN; extern void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*) DECLSPEC_HIDDEN; -extern IDirectSound *get_dsound_interface(IDirectMusicPerformance8*) DECLSPEC_HIDDEN; - /***************************************************************************** * Auxiliary definitions */ diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 5578c3e523b..d69a27540d6 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -252,13 +252,6 @@ static inline IDirectMusicPerformance8Impl *impl_from_IDirectMusicPerformance8(I return CONTAINING_RECORD(iface, IDirectMusicPerformance8Impl, IDirectMusicPerformance8_iface); } -IDirectSound *get_dsound_interface(IDirectMusicPerformance8* iface) -{ - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); - return This->dsound; -} - - /* IDirectMusicPerformance8 IUnknown part: */ static HRESULT WINAPI IDirectMusicPerformance8Impl_QueryInterface(IDirectMusicPerformance8 *iface, REFIID riid, void **ppv) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index 0ea0c15c5e0..6bf9f3abf0c 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -37,7 +37,6 @@ typedef struct IDirectMusicSegment8Impl { PCMWAVEFORMAT wave_format; void *wave_data; int data_size; - IDirectSoundBuffer *buffer; } IDirectMusicSegment8Impl; IDirectMusicSegment8Impl *create_segment(void); @@ -91,8 +90,6 @@ static ULONG WINAPI IDirectMusicSegment8Impl_Release(IDirectMusicSegment8 *iface TRACE("(%p) ref=%ld\n", This, ref); if (!ref) { - if (This->buffer) - IDirectSoundBuffer_Release(This->buffer); if (This->wave_data) free(This->wave_data); @@ -562,87 +559,9 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_Compose(IDirectMusicSegment8 *ifa static HRESULT WINAPI IDirectMusicSegment8Impl_Download(IDirectMusicSegment8 *iface, IUnknown *pAudioPath) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - IDirectMusicPerformance8 *perf; - IDirectMusicAudioPath *audio; - IDirectSound *dsound; - HRESULT hr; - DSBUFFERDESC dsbd = {.dwSize = sizeof(dsbd)}; - void *data; - DWORD size; - DWORD buffer = 0; - - TRACE("(%p, %p)\n", This, pAudioPath); - - if (!pAudioPath) - return E_INVALIDARG; - - if (This->buffer) - { - TRACE("Using Cached buffer\n"); - return S_OK; - } - - /* pAudioPath can either be IDirectMusicAudioPath or IDirectMusicPerformance */ - hr = IUnknown_QueryInterface(pAudioPath, &IID_IDirectMusicPerformance8, (void**)&perf); - if (FAILED(hr)) - { - TRACE("Checking for IDirectMusicAudioPath interface\n"); - hr = IUnknown_QueryInterface(pAudioPath, &IID_IDirectMusicAudioPath, (void**)&audio); - if (FAILED(hr)) - { - WARN("Cannot query for IDirectMusicAudioPath\n"); - return E_INVALIDARG; - } - - IDirectMusicAudioPath_GetObjectInPath(audio, DMUS_PCHANNEL_ALL, DMUS_PATH_PERFORMANCE, buffer, &GUID_NULL, - 0, &IID_IDirectMusicPerformance, (void**)&perf); - IDirectMusicAudioPath_Release(audio); - } - - if (!perf) - { - ERR("Failed to get IDirectMusicPerformance interface\n"); - return E_INVALIDARG; - } - - dsound = get_dsound_interface(perf); - if (!dsound) - { - ERR("Failed get_dsound_interface\n"); - return E_INVALIDARG; - } - - if (This->data_size == 0) - { - FIXME("No wave data skipping\n"); - return S_OK; - } - - dsbd.dwBufferBytes = This->data_size; - dsbd.lpwfxFormat = (WAVEFORMATEX*)&This->wave_format; - - hr = IDirectSound_CreateSoundBuffer(dsound, &dsbd, &This->buffer, NULL); - if (FAILED(hr)) - { - ERR("IDirectSound_CreateSoundBuffer failed 0x%08lx\n", hr); - return E_INVALIDARG; - } - - TRACE("CreateSoundBuffer successful\n"); - - hr = IDirectSoundBuffer_Lock(This->buffer, 0, This->data_size, &data, &size, NULL, 0, 0); - TRACE("IDirectSoundBuffer_Lock hr 0x%08lx\n", hr); - - memcpy(data, This->wave_data, This->data_size); - - hr = IDirectSoundBuffer_Unlock(This->buffer, data, This->data_size, NULL, 0); - TRACE("IDirectSoundBuffer_Unlock hr 0x%08lx\n", hr); - - /*hr = IDirectSoundBuffer_Play(This->buffer, 0, 0, 0); - TRACE("IDirectSoundBuffer_Play hr 0x%08lx\n", hr);*/ - - return S_OK; + IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + FIXME("(%p, %p): stub\n", This, pAudioPath); + return S_OK; } static HRESULT WINAPI IDirectMusicSegment8Impl_Unload(IDirectMusicSegment8 *iface, From 41366ffb10c0e031b1122a3b744012ef8c82e0c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Sep 2023 11:39:35 +0200 Subject: [PATCH 2394/2777] Revert "dmime: Store WAVE data when Loading." This reverts commit 4c6b451318f4b6cd0ff8093a2a334fe46374f02d. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segment.c | 56 ++++---------------------------------------- 1 file changed, 4 insertions(+), 52 deletions(-) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index 6bf9f3abf0c..bf44c5e73b3 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -33,10 +33,6 @@ typedef struct IDirectMusicSegment8Impl { DMUS_IO_SEGMENT_HEADER header; IDirectMusicGraph *pGraph; struct list Tracks; - - PCMWAVEFORMAT wave_format; - void *wave_data; - int data_size; } IDirectMusicSegment8Impl; IDirectMusicSegment8Impl *create_segment(void); @@ -90,9 +86,6 @@ static ULONG WINAPI IDirectMusicSegment8Impl_Release(IDirectMusicSegment8 *iface TRACE("(%p) ref=%ld\n", This, ref); if (!ref) { - if (This->wave_data) - free(This->wave_data); - HeapFree(GetProcessHeap(), 0, This); DMIME_UnlockModule(); } @@ -825,49 +818,6 @@ static inline IDirectMusicSegment8Impl *impl_from_IPersistStream(IPersistStream return CONTAINING_RECORD(iface, IDirectMusicSegment8Impl, dmobj.IPersistStream_iface); } -static HRESULT parse_wave_form(IDirectMusicSegment8Impl *This, IStream *stream, const struct chunk_entry *riff) -{ - HRESULT hr; - struct chunk_entry chunk = {.parent = riff}; - - TRACE("Parsing segment wave in %p: %s\n", stream, debugstr_chunk(riff)); - - while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { - switch (chunk.id) { - case mmioFOURCC('f','m','t',' '): { - if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &This->wave_format, chunk.size))) - return hr; - TRACE("Wave Format tag %d\n", This->wave_format.wf.wFormatTag); - break; - } - case mmioFOURCC('d','a','t','a'): { - TRACE("Wave Data size %lu\n", chunk.size); - This->wave_data = malloc(chunk.size); - This->data_size = chunk.size; - if (!This->wave_data) - return E_OUTOFMEMORY; - if (FAILED(hr = stream_chunk_get_data(stream, &chunk, This->wave_data, chunk.size))) - return hr; - break; - } - case FOURCC_LIST: { - FIXME("Skipping LIST tag\n"); - break; - } - case mmioFOURCC('I','S','F','T'): { - FIXME("Skipping ISFT tag\n"); - break; - } - case mmioFOURCC('f','a','c','t'): { - FIXME("Skipping fact tag\n"); - break; - } - } - } - - return S_OK; -} - static HRESULT WINAPI seg_IPersistStream_Load(IPersistStream *iface, IStream *stream) { IDirectMusicSegment8Impl *This = impl_from_IPersistStream(iface); @@ -897,8 +847,10 @@ static HRESULT WINAPI seg_IPersistStream_Load(IPersistStream *iface, IStream *st if (riff.type == DMUS_FOURCC_SEGMENT_FORM) hr = parse_segment_form(This, stream, &riff); - else - hr = parse_wave_form(This, stream, &riff); + else { + FIXME("WAVE form loading not implemented\n"); + hr = S_OK; + } return hr; } From b5f4c306fa9d5d5b7f940e3e23e498802feb116a Mon Sep 17 00:00:00 2001 From: Michael Stefaniuc Date: Wed, 29 Mar 2023 22:35:32 +0200 Subject: [PATCH 2395/2777] dmsynth: Don't crash when Open() gets a DMUS_PORTPARAMS7. Wrong sizeof check: pointer instead of referenced structure. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53704 (cherry picked from commit 48fdc8e08c4150c74e6c740df82518405125541d) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 121d9aadf35..3631bcfe784 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -163,7 +163,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_Open(IDirectMusicSynth8 *iface, DMU modified = TRUE; params->fShare = FALSE; - if (params->dwSize >= sizeof(params)) { + if (params->dwSize >= sizeof(*params)) { if (params->dwValidParams & DMUS_PORTPARAMS_FEATURES && params->dwFeatures) { if (params->dwFeatures & ~(DMUS_PORT_FEATURE_AUDIOPATH|DMUS_PORT_FEATURE_STREAMING)) { modified = TRUE; From 0c06a734d36ab7e377e4ac623d2a154ff1b8b79b Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 29 Jun 2023 18:17:56 +1000 Subject: [PATCH 2396/2777] dmsynth: Remove DECLSPEC_HIDDEN usage. (cherry picked from commit b1a69eab126332e64860f483d99fee60acedfa8c) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/dmsynth_private.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/dmsynth/dmsynth_private.h b/dlls/dmsynth/dmsynth_private.h index b0e4c66f416..c21a9e84a84 100644 --- a/dlls/dmsynth/dmsynth_private.h +++ b/dlls/dmsynth/dmsynth_private.h @@ -49,8 +49,8 @@ typedef struct IDirectMusicSynthSinkImpl IDirectMusicSynthSinkImpl; /***************************************************************************** * ClassFactory */ -extern HRESULT DMUSIC_CreateDirectMusicSynthImpl(REFIID riid, void **ppobj) DECLSPEC_HIDDEN; -extern HRESULT DMUSIC_CreateDirectMusicSynthSinkImpl(REFIID riid, void **ppobj) DECLSPEC_HIDDEN; +extern HRESULT DMUSIC_CreateDirectMusicSynthImpl(REFIID riid, void **ppobj); +extern HRESULT DMUSIC_CreateDirectMusicSynthSinkImpl(REFIID riid, void **ppobj); /***************************************************************************** * IDirectMusicSynth8Impl implementation structure @@ -83,7 +83,7 @@ struct IDirectMusicSynthSinkImpl { /********************************************************************** * Dll lifetime tracking declaration for dmsynth.dll */ -extern LONG DMSYNTH_refCount DECLSPEC_HIDDEN; +extern LONG DMSYNTH_refCount; static inline void DMSYNTH_LockModule(void) { InterlockedIncrement( &DMSYNTH_refCount ); } static inline void DMSYNTH_UnlockModule(void) { InterlockedDecrement( &DMSYNTH_refCount ); } @@ -106,6 +106,6 @@ typedef struct { #define GE(x) { &x, #x } /* returns name of given GUID */ -extern const char *debugstr_dmguid (const GUID *id) DECLSPEC_HIDDEN; +extern const char *debugstr_dmguid (const GUID *id); #endif /* __WINE_DMSYNTH_PRIVATE_H */ From 603de4d146b6cbbacdbef259af542329ae94d25d Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 29 Jun 2023 18:17:56 +1000 Subject: [PATCH 2397/2777] dmstyle: Remove DECLSPEC_HIDDEN usage. (cherry picked from commit 5a18153fcd398b5becd7ac2309eb97ea68884781) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmstyle/dmobject.h | 50 +++++++++++++++++----------------- dlls/dmstyle/dmstyle_private.h | 16 +++++------ dlls/dmstyle/dmutils.h | 4 +-- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/dlls/dmstyle/dmobject.h b/dlls/dmstyle/dmobject.h index afe721dc824..772be015c80 100644 --- a/dlls/dmstyle/dmobject.h +++ b/dlls/dmstyle/dmobject.h @@ -31,16 +31,16 @@ struct chunk_entry { const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */ }; -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN; -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN; -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) DECLSPEC_HIDDEN; +HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk); +HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk); +HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk); HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size) DECLSPEC_HIDDEN; + unsigned int *count, DWORD elem_size); HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size) DECLSPEC_HIDDEN; + ULONG size); HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size) DECLSPEC_HIDDEN; + ULONG size); static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk) { @@ -71,21 +71,21 @@ struct dmobject { DMUS_OBJECTDESC desc; }; -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk) DECLSPEC_HIDDEN; +void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk); /* Generic IDirectMusicObject methods */ HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface) DECLSPEC_HIDDEN; + void **ret_iface); +ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface); +ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface); HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc); HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc); /* Helper for IDirectMusicObject::ParseDescriptor */ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc, DWORD supported); /* Additional supported flags for dmobj_parsedescriptor. DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */ #define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */ @@ -93,28 +93,28 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, /* 'DMRF' (reference list) helper */ HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj) DECLSPEC_HIDDEN; + IDirectMusicObject **dmobj); /* Generic IPersistStream methods */ HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface) DECLSPEC_HIDDEN; -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) DECLSPEC_HIDDEN; + void **ret_iface); +ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface); +ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface); +HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class); /* IPersistStream methods not implemented in native */ HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, - CLSID *class) DECLSPEC_HIDDEN; -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface) DECLSPEC_HIDDEN; + CLSID *class); +HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface); HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty) DECLSPEC_HIDDEN; + BOOL clear_dirty); HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, - ULARGE_INTEGER *size) DECLSPEC_HIDDEN; + ULARGE_INTEGER *size); /* Debugging helpers */ -const char *debugstr_chunk(const struct chunk_entry *chunk) DECLSPEC_HIDDEN; -const char *debugstr_dmguid(const GUID *id) DECLSPEC_HIDDEN; -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; +const char *debugstr_chunk(const struct chunk_entry *chunk); +const char *debugstr_dmguid(const GUID *id); +void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc); static inline const char *debugstr_fourcc(DWORD fourcc) { diff --git a/dlls/dmstyle/dmstyle_private.h b/dlls/dmstyle/dmstyle_private.h index 0d7ede7f00d..2807e98fe61 100644 --- a/dlls/dmstyle/dmstyle_private.h +++ b/dlls/dmstyle/dmstyle_private.h @@ -44,13 +44,13 @@ /***************************************************************************** * ClassFactory */ -extern HRESULT create_dmstyle(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmauditiontrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmchordtrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmcommandtrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmmotiftrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmmutetrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmstyletrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; +extern HRESULT create_dmstyle(REFIID riid, void **ret_iface); +extern HRESULT create_dmauditiontrack(REFIID riid, void **ret_iface); +extern HRESULT create_dmchordtrack(REFIID riid, void **ret_iface); +extern HRESULT create_dmcommandtrack(REFIID riid, void **ret_iface); +extern HRESULT create_dmmotiftrack(REFIID riid, void **ret_iface); +extern HRESULT create_dmmutetrack(REFIID riid, void **ret_iface); +extern HRESULT create_dmstyletrack(REFIID riid, void **ret_iface); /***************************************************************************** * Auxiliary definitions @@ -64,7 +64,7 @@ typedef struct _DMUS_PRIVATE_COMMAND { /********************************************************************** * Dll lifetime tracking declaration for dmstyle.dll */ -extern LONG DMSTYLE_refCount DECLSPEC_HIDDEN; +extern LONG DMSTYLE_refCount; static inline void DMSTYLE_LockModule(void) { InterlockedIncrement( &DMSTYLE_refCount ); } static inline void DMSTYLE_UnlockModule(void) { InterlockedDecrement( &DMSTYLE_refCount ); } diff --git a/dlls/dmstyle/dmutils.h b/dlls/dmstyle/dmutils.h index dbeb7a2a978..4f50bb0bfce 100644 --- a/dlls/dmstyle/dmutils.h +++ b/dlls/dmstyle/dmutils.h @@ -30,7 +30,7 @@ typedef struct _DMUS_PRIVATE_CHUNK { /** * Parsing utilities */ -extern HRESULT IDirectMusicUtils_IPersistStream_ParseDescGeneric (DMUS_PRIVATE_CHUNK* pChunk, IStream* pStm, LPDMUS_OBJECTDESC pDesc) DECLSPEC_HIDDEN; -extern HRESULT IDirectMusicUtils_IPersistStream_ParseUNFOGeneric (DMUS_PRIVATE_CHUNK* pChunk, IStream* pStm, LPDMUS_OBJECTDESC pDesc) DECLSPEC_HIDDEN; +extern HRESULT IDirectMusicUtils_IPersistStream_ParseDescGeneric (DMUS_PRIVATE_CHUNK* pChunk, IStream* pStm, LPDMUS_OBJECTDESC pDesc); +extern HRESULT IDirectMusicUtils_IPersistStream_ParseUNFOGeneric (DMUS_PRIVATE_CHUNK* pChunk, IStream* pStm, LPDMUS_OBJECTDESC pDesc); #endif /* __WINE_DMUTILS_H */ From 99550b4888ef86539468536e3d336d16d44c2bef Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 29 Jun 2023 18:17:56 +1000 Subject: [PATCH 2398/2777] dmband: Remove DECLSPEC_HIDDEN usage. (cherry picked from commit 63d3eb77e0013bc6439054a61daaa467c65e587f) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/dmband_private.h | 6 ++--- dlls/dmband/dmobject.h | 50 ++++++++++++++++++------------------ dlls/dmband/dmutils.h | 6 ++--- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/dlls/dmband/dmband_private.h b/dlls/dmband/dmband_private.h index b0b26076285..b89dd08dd83 100644 --- a/dlls/dmband/dmband_private.h +++ b/dlls/dmband/dmband_private.h @@ -44,8 +44,8 @@ /***************************************************************************** * ClassFactory */ -extern HRESULT create_dmband(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmbandtrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; +extern HRESULT create_dmband(REFIID riid, void **ret_iface); +extern HRESULT create_dmbandtrack(REFIID riid, void **ret_iface); /***************************************************************************** @@ -77,7 +77,7 @@ typedef struct _DMUS_PRIVATE_BAND { /********************************************************************** * Dll lifetime tracking declaration for dmband.dll */ -extern LONG DMBAND_refCount DECLSPEC_HIDDEN; +extern LONG DMBAND_refCount; static inline void DMBAND_LockModule(void) { InterlockedIncrement( &DMBAND_refCount ); } static inline void DMBAND_UnlockModule(void) { InterlockedDecrement( &DMBAND_refCount ); } diff --git a/dlls/dmband/dmobject.h b/dlls/dmband/dmobject.h index afe721dc824..772be015c80 100644 --- a/dlls/dmband/dmobject.h +++ b/dlls/dmband/dmobject.h @@ -31,16 +31,16 @@ struct chunk_entry { const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */ }; -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN; -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN; -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) DECLSPEC_HIDDEN; +HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk); +HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk); +HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk); HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size) DECLSPEC_HIDDEN; + unsigned int *count, DWORD elem_size); HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size) DECLSPEC_HIDDEN; + ULONG size); HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size) DECLSPEC_HIDDEN; + ULONG size); static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk) { @@ -71,21 +71,21 @@ struct dmobject { DMUS_OBJECTDESC desc; }; -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk) DECLSPEC_HIDDEN; +void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk); /* Generic IDirectMusicObject methods */ HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface) DECLSPEC_HIDDEN; + void **ret_iface); +ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface); +ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface); HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc); HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc); /* Helper for IDirectMusicObject::ParseDescriptor */ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc, DWORD supported); /* Additional supported flags for dmobj_parsedescriptor. DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */ #define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */ @@ -93,28 +93,28 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, /* 'DMRF' (reference list) helper */ HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj) DECLSPEC_HIDDEN; + IDirectMusicObject **dmobj); /* Generic IPersistStream methods */ HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface) DECLSPEC_HIDDEN; -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) DECLSPEC_HIDDEN; + void **ret_iface); +ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface); +ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface); +HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class); /* IPersistStream methods not implemented in native */ HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, - CLSID *class) DECLSPEC_HIDDEN; -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface) DECLSPEC_HIDDEN; + CLSID *class); +HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface); HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty) DECLSPEC_HIDDEN; + BOOL clear_dirty); HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, - ULARGE_INTEGER *size) DECLSPEC_HIDDEN; + ULARGE_INTEGER *size); /* Debugging helpers */ -const char *debugstr_chunk(const struct chunk_entry *chunk) DECLSPEC_HIDDEN; -const char *debugstr_dmguid(const GUID *id) DECLSPEC_HIDDEN; -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; +const char *debugstr_chunk(const struct chunk_entry *chunk); +const char *debugstr_dmguid(const GUID *id); +void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc); static inline const char *debugstr_fourcc(DWORD fourcc) { diff --git a/dlls/dmband/dmutils.h b/dlls/dmband/dmutils.h index 2f13c4b1f44..7f9b98cf310 100644 --- a/dlls/dmband/dmutils.h +++ b/dlls/dmband/dmutils.h @@ -30,8 +30,8 @@ typedef struct _DMUS_PRIVATE_CHUNK { /** * Parsing utilities */ -extern HRESULT IDirectMusicUtils_IPersistStream_ParseDescGeneric (DMUS_PRIVATE_CHUNK* pChunk, IStream* pStm, LPDMUS_OBJECTDESC pDesc) DECLSPEC_HIDDEN; -extern HRESULT IDirectMusicUtils_IPersistStream_ParseUNFOGeneric (DMUS_PRIVATE_CHUNK* pChunk, IStream* pStm, LPDMUS_OBJECTDESC pDesc) DECLSPEC_HIDDEN; -extern HRESULT IDirectMusicUtils_IPersistStream_ParseReference (LPPERSISTSTREAM iface, DMUS_PRIVATE_CHUNK* pChunk, IStream* pStm, IDirectMusicObject** ppObject) DECLSPEC_HIDDEN; +extern HRESULT IDirectMusicUtils_IPersistStream_ParseDescGeneric (DMUS_PRIVATE_CHUNK* pChunk, IStream* pStm, LPDMUS_OBJECTDESC pDesc); +extern HRESULT IDirectMusicUtils_IPersistStream_ParseUNFOGeneric (DMUS_PRIVATE_CHUNK* pChunk, IStream* pStm, LPDMUS_OBJECTDESC pDesc); +extern HRESULT IDirectMusicUtils_IPersistStream_ParseReference (LPPERSISTSTREAM iface, DMUS_PRIVATE_CHUNK* pChunk, IStream* pStm, IDirectMusicObject** ppObject); #endif /* __WINE_DMUTILS_H */ From 0b88731f2936649e3bf360168a0f1c02e921cf4b Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 29 Jun 2023 18:17:57 +1000 Subject: [PATCH 2399/2777] dmcompos: Remove DECLSPEC_HIDDEN usage. (cherry picked from commit abd3a042215986df45b12f0254a3af06eaf81b79) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmcompos/dmcompos_private.h | 10 +++---- dlls/dmcompos/dmobject.h | 50 ++++++++++++++++---------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/dlls/dmcompos/dmcompos_private.h b/dlls/dmcompos/dmcompos_private.h index bd44607d00c..c04d7da6060 100644 --- a/dlls/dmcompos/dmcompos_private.h +++ b/dlls/dmcompos/dmcompos_private.h @@ -44,15 +44,15 @@ /***************************************************************************** * ClassFactory */ -extern HRESULT create_dmchordmap(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmcomposer(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmchordmaptrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmsignposttrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; +extern HRESULT create_dmchordmap(REFIID riid, void **ret_iface); +extern HRESULT create_dmcomposer(REFIID riid, void **ret_iface); +extern HRESULT create_dmchordmaptrack(REFIID riid, void **ret_iface); +extern HRESULT create_dmsignposttrack(REFIID riid, void **ret_iface); /********************************************************************** * Dll lifetime tracking declaration for dmcompos.dll */ -extern LONG DMCOMPOS_refCount DECLSPEC_HIDDEN; +extern LONG DMCOMPOS_refCount; static inline void DMCOMPOS_LockModule(void) { InterlockedIncrement( &DMCOMPOS_refCount ); } static inline void DMCOMPOS_UnlockModule(void) { InterlockedDecrement( &DMCOMPOS_refCount ); } diff --git a/dlls/dmcompos/dmobject.h b/dlls/dmcompos/dmobject.h index afe721dc824..772be015c80 100644 --- a/dlls/dmcompos/dmobject.h +++ b/dlls/dmcompos/dmobject.h @@ -31,16 +31,16 @@ struct chunk_entry { const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */ }; -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN; -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN; -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) DECLSPEC_HIDDEN; +HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk); +HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk); +HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk); HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size) DECLSPEC_HIDDEN; + unsigned int *count, DWORD elem_size); HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size) DECLSPEC_HIDDEN; + ULONG size); HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size) DECLSPEC_HIDDEN; + ULONG size); static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk) { @@ -71,21 +71,21 @@ struct dmobject { DMUS_OBJECTDESC desc; }; -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk) DECLSPEC_HIDDEN; +void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk); /* Generic IDirectMusicObject methods */ HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface) DECLSPEC_HIDDEN; + void **ret_iface); +ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface); +ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface); HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc); HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc); /* Helper for IDirectMusicObject::ParseDescriptor */ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc, DWORD supported); /* Additional supported flags for dmobj_parsedescriptor. DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */ #define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */ @@ -93,28 +93,28 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, /* 'DMRF' (reference list) helper */ HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj) DECLSPEC_HIDDEN; + IDirectMusicObject **dmobj); /* Generic IPersistStream methods */ HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface) DECLSPEC_HIDDEN; -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) DECLSPEC_HIDDEN; + void **ret_iface); +ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface); +ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface); +HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class); /* IPersistStream methods not implemented in native */ HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, - CLSID *class) DECLSPEC_HIDDEN; -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface) DECLSPEC_HIDDEN; + CLSID *class); +HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface); HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty) DECLSPEC_HIDDEN; + BOOL clear_dirty); HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, - ULARGE_INTEGER *size) DECLSPEC_HIDDEN; + ULARGE_INTEGER *size); /* Debugging helpers */ -const char *debugstr_chunk(const struct chunk_entry *chunk) DECLSPEC_HIDDEN; -const char *debugstr_dmguid(const GUID *id) DECLSPEC_HIDDEN; -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; +const char *debugstr_chunk(const struct chunk_entry *chunk); +const char *debugstr_dmguid(const GUID *id); +void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc); static inline const char *debugstr_fourcc(DWORD fourcc) { From de9a93434cb93af0346d3fec207015463fd8917c Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 29 Jun 2023 18:17:57 +1000 Subject: [PATCH 2400/2777] dmusic: Remove DECLSPEC_HIDDEN usage. (cherry picked from commit 82c895fec3638aac103fe8b851945708f75a9341) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/dmobject.h | 50 ++++++++++++++++++------------------ dlls/dmusic/dmusic_private.h | 32 +++++++++++------------ 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/dlls/dmusic/dmobject.h b/dlls/dmusic/dmobject.h index afe721dc824..772be015c80 100644 --- a/dlls/dmusic/dmobject.h +++ b/dlls/dmusic/dmobject.h @@ -31,16 +31,16 @@ struct chunk_entry { const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */ }; -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN; -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN; -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) DECLSPEC_HIDDEN; +HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk); +HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk); +HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk); HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size) DECLSPEC_HIDDEN; + unsigned int *count, DWORD elem_size); HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size) DECLSPEC_HIDDEN; + ULONG size); HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size) DECLSPEC_HIDDEN; + ULONG size); static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk) { @@ -71,21 +71,21 @@ struct dmobject { DMUS_OBJECTDESC desc; }; -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk) DECLSPEC_HIDDEN; +void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk); /* Generic IDirectMusicObject methods */ HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface) DECLSPEC_HIDDEN; + void **ret_iface); +ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface); +ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface); HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc); HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc); /* Helper for IDirectMusicObject::ParseDescriptor */ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc, DWORD supported); /* Additional supported flags for dmobj_parsedescriptor. DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */ #define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */ @@ -93,28 +93,28 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, /* 'DMRF' (reference list) helper */ HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj) DECLSPEC_HIDDEN; + IDirectMusicObject **dmobj); /* Generic IPersistStream methods */ HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface) DECLSPEC_HIDDEN; -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) DECLSPEC_HIDDEN; + void **ret_iface); +ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface); +ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface); +HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class); /* IPersistStream methods not implemented in native */ HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, - CLSID *class) DECLSPEC_HIDDEN; -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface) DECLSPEC_HIDDEN; + CLSID *class); +HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface); HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty) DECLSPEC_HIDDEN; + BOOL clear_dirty); HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, - ULARGE_INTEGER *size) DECLSPEC_HIDDEN; + ULARGE_INTEGER *size); /* Debugging helpers */ -const char *debugstr_chunk(const struct chunk_entry *chunk) DECLSPEC_HIDDEN; -const char *debugstr_dmguid(const GUID *id) DECLSPEC_HIDDEN; -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; +const char *debugstr_chunk(const struct chunk_entry *chunk); +const char *debugstr_dmguid(const GUID *id); +void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc); static inline const char *debugstr_fourcc(DWORD fourcc) { diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 18d3e079b12..1b91f4bac94 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -95,14 +95,14 @@ typedef struct instrument_articulation { */ /* CLSID */ -extern HRESULT DMUSIC_CreateDirectMusicImpl(REFIID riid, void **ret_iface, IUnknown *pUnkOuter) DECLSPEC_HIDDEN; -extern HRESULT DMUSIC_CreateDirectMusicCollectionImpl(REFIID riid, void **ppobj, IUnknown *pUnkOuter) DECLSPEC_HIDDEN; +extern HRESULT DMUSIC_CreateDirectMusicImpl(REFIID riid, void **ret_iface, IUnknown *pUnkOuter); +extern HRESULT DMUSIC_CreateDirectMusicCollectionImpl(REFIID riid, void **ppobj, IUnknown *pUnkOuter); /* Internal */ -extern HRESULT DMUSIC_CreateDirectMusicBufferImpl(LPDMUS_BUFFERDESC desc, LPVOID* ret_iface) DECLSPEC_HIDDEN; -extern HRESULT DMUSIC_CreateDirectMusicDownloadImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) DECLSPEC_HIDDEN; -extern HRESULT DMUSIC_CreateReferenceClockImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) DECLSPEC_HIDDEN; -extern HRESULT DMUSIC_CreateDirectMusicInstrumentImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) DECLSPEC_HIDDEN; +extern HRESULT DMUSIC_CreateDirectMusicBufferImpl(LPDMUS_BUFFERDESC desc, LPVOID* ret_iface); +extern HRESULT DMUSIC_CreateDirectMusicDownloadImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter); +extern HRESULT DMUSIC_CreateReferenceClockImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter); +extern HRESULT DMUSIC_CreateDirectMusicInstrumentImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter); /***************************************************************************** * IDirectMusic8Impl implementation structure @@ -160,11 +160,11 @@ struct IDirectMusicDownloadImpl { /** Internal factory */ extern HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_params, - DMUS_PORTCAPS *port_caps, IDirectMusicPort **port) DECLSPEC_HIDDEN; + DMUS_PORTCAPS *port_caps, IDirectMusicPort **port); extern HRESULT midi_out_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_params, - DMUS_PORTCAPS *port_caps, IDirectMusicPort **port) DECLSPEC_HIDDEN; + DMUS_PORTCAPS *port_caps, IDirectMusicPort **port); extern HRESULT midi_in_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_params, - DMUS_PORTCAPS *port_caps, IDirectMusicPort **port) DECLSPEC_HIDDEN; + DMUS_PORTCAPS *port_caps, IDirectMusicPort **port); /***************************************************************************** * IReferenceClockImpl implementation structure @@ -215,12 +215,12 @@ static inline IDirectMusicInstrumentImpl *impl_from_IDirectMusicInstrument(IDire } /* custom :) */ -extern HRESULT IDirectMusicInstrumentImpl_CustomLoad(IDirectMusicInstrument *iface, IStream *stream) DECLSPEC_HIDDEN; +extern HRESULT IDirectMusicInstrumentImpl_CustomLoad(IDirectMusicInstrument *iface, IStream *stream); /********************************************************************** * Dll lifetime tracking declaration for dmusic.dll */ -extern LONG DMUSIC_refCount DECLSPEC_HIDDEN; +extern LONG DMUSIC_refCount; static inline void DMUSIC_LockModule(void) { InterlockedIncrement( &DMUSIC_refCount ); } static inline void DMUSIC_UnlockModule(void) { InterlockedDecrement( &DMUSIC_refCount ); } @@ -228,7 +228,7 @@ static inline void DMUSIC_UnlockModule(void) { InterlockedDecrement( &DMUSIC_ref /***************************************************************************** * Misc. */ -void dmusic_remove_port(IDirectMusic8Impl *dmusic, IDirectMusicPort *port) DECLSPEC_HIDDEN; +void dmusic_remove_port(IDirectMusic8Impl *dmusic, IDirectMusicPort *port); /* for simpler reading */ typedef struct _DMUS_PRIVATE_CHUNK { @@ -245,13 +245,13 @@ typedef struct { #define FE(x) { x, #x } /* dwPatch from MIDILOCALE */ -extern DWORD MIDILOCALE2Patch (const MIDILOCALE *pLocale) DECLSPEC_HIDDEN; +extern DWORD MIDILOCALE2Patch (const MIDILOCALE *pLocale); /* MIDILOCALE from dwPatch */ -extern void Patch2MIDILOCALE (DWORD dwPatch, LPMIDILOCALE pLocale) DECLSPEC_HIDDEN; +extern void Patch2MIDILOCALE (DWORD dwPatch, LPMIDILOCALE pLocale); /* check whether the given DWORD is even (return 0) or odd (return 1) */ -extern int even_or_odd (DWORD number) DECLSPEC_HIDDEN; +extern int even_or_odd (DWORD number); /* Dump whole DMUS_PORTPARAMS struct */ -extern void dump_DMUS_PORTPARAMS(LPDMUS_PORTPARAMS params) DECLSPEC_HIDDEN; +extern void dump_DMUS_PORTPARAMS(LPDMUS_PORTPARAMS params); #endif /* __WINE_DMUSIC_PRIVATE_H */ From 9d1c070f9b867473f0dd60a5a0008cca088ffc1e Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 29 Jun 2023 18:17:57 +1000 Subject: [PATCH 2401/2777] dmscript: Remove DECLSPEC_HIDDEN usage. (cherry picked from commit 90244981e7d70562b184a29ece6fadbdec234199) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmscript/dmobject.h | 50 ++++++++++++++++---------------- dlls/dmscript/dmscript_private.h | 6 ++-- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/dlls/dmscript/dmobject.h b/dlls/dmscript/dmobject.h index afe721dc824..772be015c80 100644 --- a/dlls/dmscript/dmobject.h +++ b/dlls/dmscript/dmobject.h @@ -31,16 +31,16 @@ struct chunk_entry { const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */ }; -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN; -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN; -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) DECLSPEC_HIDDEN; +HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk); +HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk); +HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk); HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size) DECLSPEC_HIDDEN; + unsigned int *count, DWORD elem_size); HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size) DECLSPEC_HIDDEN; + ULONG size); HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size) DECLSPEC_HIDDEN; + ULONG size); static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk) { @@ -71,21 +71,21 @@ struct dmobject { DMUS_OBJECTDESC desc; }; -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk) DECLSPEC_HIDDEN; +void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk); /* Generic IDirectMusicObject methods */ HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface) DECLSPEC_HIDDEN; + void **ret_iface); +ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface); +ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface); HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc); HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc); /* Helper for IDirectMusicObject::ParseDescriptor */ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc, DWORD supported); /* Additional supported flags for dmobj_parsedescriptor. DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */ #define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */ @@ -93,28 +93,28 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, /* 'DMRF' (reference list) helper */ HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj) DECLSPEC_HIDDEN; + IDirectMusicObject **dmobj); /* Generic IPersistStream methods */ HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface) DECLSPEC_HIDDEN; -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) DECLSPEC_HIDDEN; + void **ret_iface); +ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface); +ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface); +HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class); /* IPersistStream methods not implemented in native */ HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, - CLSID *class) DECLSPEC_HIDDEN; -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface) DECLSPEC_HIDDEN; + CLSID *class); +HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface); HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty) DECLSPEC_HIDDEN; + BOOL clear_dirty); HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, - ULARGE_INTEGER *size) DECLSPEC_HIDDEN; + ULARGE_INTEGER *size); /* Debugging helpers */ -const char *debugstr_chunk(const struct chunk_entry *chunk) DECLSPEC_HIDDEN; -const char *debugstr_dmguid(const GUID *id) DECLSPEC_HIDDEN; -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; +const char *debugstr_chunk(const struct chunk_entry *chunk); +const char *debugstr_dmguid(const GUID *id); +void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc); static inline const char *debugstr_fourcc(DWORD fourcc) { diff --git a/dlls/dmscript/dmscript_private.h b/dlls/dmscript/dmscript_private.h index 3b3a4c86c84..90808d59f00 100644 --- a/dlls/dmscript/dmscript_private.h +++ b/dlls/dmscript/dmscript_private.h @@ -44,14 +44,14 @@ /***************************************************************************** * ClassFactory */ -extern HRESULT DMUSIC_CreateDirectMusicScriptImpl(REFIID riid, void **ppobj, IUnknown *pUnkOuter) DECLSPEC_HIDDEN; +extern HRESULT DMUSIC_CreateDirectMusicScriptImpl(REFIID riid, void **ppobj, IUnknown *pUnkOuter); -extern HRESULT DMUSIC_CreateDirectMusicScriptTrack(REFIID riid, void **ppobj, IUnknown *pUnkOuter) DECLSPEC_HIDDEN; +extern HRESULT DMUSIC_CreateDirectMusicScriptTrack(REFIID riid, void **ppobj, IUnknown *pUnkOuter); /********************************************************************** * Dll lifetime tracking declaration for dmscript.dll */ -extern LONG DMSCRIPT_refCount DECLSPEC_HIDDEN; +extern LONG DMSCRIPT_refCount; static inline void DMSCRIPT_LockModule(void) { InterlockedIncrement( &DMSCRIPT_refCount ); } static inline void DMSCRIPT_UnlockModule(void) { InterlockedDecrement( &DMSCRIPT_refCount ); } From 938080e955d6e595661724953270636cd01986f0 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 29 Jun 2023 18:17:57 +1000 Subject: [PATCH 2402/2777] dswave: Remove DECLSPEC_HIDDEN usage. (cherry picked from commit 860c575e7a8c93c53d4e38c3f0535ab498f59c8d) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dswave/dmobject.h | 50 ++++++++++++++++++------------------ dlls/dswave/dswave_private.h | 4 +-- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/dlls/dswave/dmobject.h b/dlls/dswave/dmobject.h index afe721dc824..772be015c80 100644 --- a/dlls/dswave/dmobject.h +++ b/dlls/dswave/dmobject.h @@ -31,16 +31,16 @@ struct chunk_entry { const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */ }; -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN; -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN; -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) DECLSPEC_HIDDEN; +HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk); +HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk); +HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk); HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size) DECLSPEC_HIDDEN; + unsigned int *count, DWORD elem_size); HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size) DECLSPEC_HIDDEN; + ULONG size); HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size) DECLSPEC_HIDDEN; + ULONG size); static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk) { @@ -71,21 +71,21 @@ struct dmobject { DMUS_OBJECTDESC desc; }; -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk) DECLSPEC_HIDDEN; +void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk); /* Generic IDirectMusicObject methods */ HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface) DECLSPEC_HIDDEN; + void **ret_iface); +ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface); +ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface); HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc); HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc); /* Helper for IDirectMusicObject::ParseDescriptor */ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc, DWORD supported); /* Additional supported flags for dmobj_parsedescriptor. DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */ #define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */ @@ -93,28 +93,28 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, /* 'DMRF' (reference list) helper */ HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj) DECLSPEC_HIDDEN; + IDirectMusicObject **dmobj); /* Generic IPersistStream methods */ HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface) DECLSPEC_HIDDEN; -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) DECLSPEC_HIDDEN; + void **ret_iface); +ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface); +ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface); +HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class); /* IPersistStream methods not implemented in native */ HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, - CLSID *class) DECLSPEC_HIDDEN; -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface) DECLSPEC_HIDDEN; + CLSID *class); +HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface); HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty) DECLSPEC_HIDDEN; + BOOL clear_dirty); HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, - ULARGE_INTEGER *size) DECLSPEC_HIDDEN; + ULARGE_INTEGER *size); /* Debugging helpers */ -const char *debugstr_chunk(const struct chunk_entry *chunk) DECLSPEC_HIDDEN; -const char *debugstr_dmguid(const GUID *id) DECLSPEC_HIDDEN; -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; +const char *debugstr_chunk(const struct chunk_entry *chunk); +const char *debugstr_dmguid(const GUID *id); +void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc); static inline const char *debugstr_fourcc(DWORD fourcc) { diff --git a/dlls/dswave/dswave_private.h b/dlls/dswave/dswave_private.h index dfd8ed6f51c..a7758a970bc 100644 --- a/dlls/dswave/dswave_private.h +++ b/dlls/dswave/dswave_private.h @@ -42,12 +42,12 @@ /***************************************************************************** * ClassFactory */ -extern HRESULT create_dswave(REFIID lpcGUID, void **ret_iface) DECLSPEC_HIDDEN; +extern HRESULT create_dswave(REFIID lpcGUID, void **ret_iface); /********************************************************************** * Dll lifetime tracking declaration for dswave.dll */ -extern LONG DSWAVE_refCount DECLSPEC_HIDDEN; +extern LONG DSWAVE_refCount; static inline void DSWAVE_LockModule(void) { InterlockedIncrement( &DSWAVE_refCount ); } static inline void DSWAVE_UnlockModule(void) { InterlockedDecrement( &DSWAVE_refCount ); } From 3f56ecf10946b354f03d9ed95c01c5b01415c476 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 29 Jun 2023 18:17:57 +1000 Subject: [PATCH 2403/2777] dmime: Remove DECLSPEC_HIDDEN usage. (cherry picked from commit cc59b783162e6f73fcf45f73f8fc6ef319a5258f) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/dmime_private.h | 40 +++++++++++++++--------------- dlls/dmime/dmobject.h | 50 +++++++++++++++++++------------------- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 4159abffa99..7cdc1534866 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -51,25 +51,25 @@ typedef struct IDirectMusicAudioPathImpl IDirectMusicAudioPathImpl; /***************************************************************************** * ClassFactory */ -extern HRESULT create_dmperformance(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmsegment(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmsegmentstate(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmgraph(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmaudiopath(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; - -extern HRESULT create_dmlyricstrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmmarkertrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmparamcontroltrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmsegtriggertrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmseqtrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmsysextrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmtempotrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmtimesigtrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmwavetrack(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; - -extern void set_audiopath_perf_pointer(IDirectMusicAudioPath*,IDirectMusicPerformance8*) DECLSPEC_HIDDEN; -extern void set_audiopath_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*) DECLSPEC_HIDDEN; -extern void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*) DECLSPEC_HIDDEN; +extern HRESULT create_dmperformance(REFIID riid, void **ret_iface); +extern HRESULT create_dmsegment(REFIID riid, void **ret_iface); +extern HRESULT create_dmsegmentstate(REFIID riid, void **ret_iface); +extern HRESULT create_dmgraph(REFIID riid, void **ret_iface); +extern HRESULT create_dmaudiopath(REFIID riid, void **ret_iface); + +extern HRESULT create_dmlyricstrack(REFIID riid, void **ret_iface); +extern HRESULT create_dmmarkertrack(REFIID riid, void **ret_iface); +extern HRESULT create_dmparamcontroltrack(REFIID riid, void **ret_iface); +extern HRESULT create_dmsegtriggertrack(REFIID riid, void **ret_iface); +extern HRESULT create_dmseqtrack(REFIID riid, void **ret_iface); +extern HRESULT create_dmsysextrack(REFIID riid, void **ret_iface); +extern HRESULT create_dmtempotrack(REFIID riid, void **ret_iface); +extern HRESULT create_dmtimesigtrack(REFIID riid, void **ret_iface); +extern HRESULT create_dmwavetrack(REFIID riid, void **ret_iface); + +extern void set_audiopath_perf_pointer(IDirectMusicAudioPath*,IDirectMusicPerformance8*); +extern void set_audiopath_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*); +extern void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*); /***************************************************************************** * Auxiliary definitions @@ -99,7 +99,7 @@ typedef struct _DMUS_PRIVATE_TEMPO_PLAY_STATE { /********************************************************************** * Dll lifetime tracking declaration for dmime.dll */ -extern LONG DMIME_refCount DECLSPEC_HIDDEN; +extern LONG DMIME_refCount; static inline void DMIME_LockModule(void) { InterlockedIncrement( &DMIME_refCount ); } static inline void DMIME_UnlockModule(void) { InterlockedDecrement( &DMIME_refCount ); } diff --git a/dlls/dmime/dmobject.h b/dlls/dmime/dmobject.h index afe721dc824..772be015c80 100644 --- a/dlls/dmime/dmobject.h +++ b/dlls/dmime/dmobject.h @@ -31,16 +31,16 @@ struct chunk_entry { const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */ }; -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN; -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN; -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) DECLSPEC_HIDDEN; +HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk); +HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk); +HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk); HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size) DECLSPEC_HIDDEN; + unsigned int *count, DWORD elem_size); HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size) DECLSPEC_HIDDEN; + ULONG size); HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size) DECLSPEC_HIDDEN; + ULONG size); static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk) { @@ -71,21 +71,21 @@ struct dmobject { DMUS_OBJECTDESC desc; }; -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk) DECLSPEC_HIDDEN; +void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk); /* Generic IDirectMusicObject methods */ HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface) DECLSPEC_HIDDEN; + void **ret_iface); +ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface); +ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface); HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc); HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc); /* Helper for IDirectMusicObject::ParseDescriptor */ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc, DWORD supported); /* Additional supported flags for dmobj_parsedescriptor. DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */ #define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */ @@ -93,28 +93,28 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, /* 'DMRF' (reference list) helper */ HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj) DECLSPEC_HIDDEN; + IDirectMusicObject **dmobj); /* Generic IPersistStream methods */ HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface) DECLSPEC_HIDDEN; -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) DECLSPEC_HIDDEN; + void **ret_iface); +ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface); +ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface); +HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class); /* IPersistStream methods not implemented in native */ HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, - CLSID *class) DECLSPEC_HIDDEN; -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface) DECLSPEC_HIDDEN; + CLSID *class); +HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface); HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty) DECLSPEC_HIDDEN; + BOOL clear_dirty); HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, - ULARGE_INTEGER *size) DECLSPEC_HIDDEN; + ULARGE_INTEGER *size); /* Debugging helpers */ -const char *debugstr_chunk(const struct chunk_entry *chunk) DECLSPEC_HIDDEN; -const char *debugstr_dmguid(const GUID *id) DECLSPEC_HIDDEN; -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; +const char *debugstr_chunk(const struct chunk_entry *chunk); +const char *debugstr_dmguid(const GUID *id); +void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc); static inline const char *debugstr_fourcc(DWORD fourcc) { From 11fa6687b390a8c0cbff74867b028885d021bd0f Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 29 Jun 2023 18:17:57 +1000 Subject: [PATCH 2404/2777] dmloader: Remove DECLSPEC_HIDDEN usage. (cherry picked from commit 3d28f9d362e6d9871747231b210c559536bb6dd4) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmloader/debug.h | 8 ++--- dlls/dmloader/dmloader_private.h | 18 ++++++------ dlls/dmloader/dmobject.h | 50 ++++++++++++++++---------------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/dlls/dmloader/debug.h b/dlls/dmloader/debug.h index 43f48e832c4..b61d17bda62 100644 --- a/dlls/dmloader/debug.h +++ b/dlls/dmloader/debug.h @@ -36,11 +36,11 @@ typedef struct { #define FE(x) { x, #x } /* check whether chunkID is valid dmobject form chunk */ -extern BOOL IS_VALID_DMFORM (FOURCC chunkID) DECLSPEC_HIDDEN; +extern BOOL IS_VALID_DMFORM (FOURCC chunkID); /* translate STREAM_SEEK flag to string */ -extern const char *resolve_STREAM_SEEK (DWORD flag) DECLSPEC_HIDDEN; +extern const char *resolve_STREAM_SEEK (DWORD flag); -extern const char *debugstr_DMUS_IO_CONTAINER_HEADER (LPDMUS_IO_CONTAINER_HEADER pHeader) DECLSPEC_HIDDEN; -extern const char *debugstr_DMUS_IO_CONTAINED_OBJECT_HEADER (LPDMUS_IO_CONTAINED_OBJECT_HEADER pHeader) DECLSPEC_HIDDEN; +extern const char *debugstr_DMUS_IO_CONTAINER_HEADER (LPDMUS_IO_CONTAINER_HEADER pHeader); +extern const char *debugstr_DMUS_IO_CONTAINED_OBJECT_HEADER (LPDMUS_IO_CONTAINED_OBJECT_HEADER pHeader); #endif /* __WINE_DMLOADER_DEBUG_H */ diff --git a/dlls/dmloader/dmloader_private.h b/dlls/dmloader/dmloader_private.h index 47994a48c4e..204c9689ffb 100644 --- a/dlls/dmloader/dmloader_private.h +++ b/dlls/dmloader/dmloader_private.h @@ -45,7 +45,7 @@ #define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) /* dmloader.dll global (for DllCanUnloadNow) */ -extern LONG module_ref DECLSPEC_HIDDEN; +extern LONG module_ref; static inline void lock_module(void) { InterlockedIncrement( &module_ref ); } static inline void unlock_module(void) { InterlockedDecrement( &module_ref ); } @@ -62,11 +62,11 @@ typedef struct IDirectMusicLoaderGenericStream IDirectMusicLoaderGenericStream; /***************************************************************************** * Creation helpers */ -extern HRESULT create_dmloader(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT create_dmcontainer(REFIID riid, void **ret_iface) DECLSPEC_HIDDEN; -extern HRESULT DMUSIC_CreateDirectMusicLoaderFileStream(void **ppobj) DECLSPEC_HIDDEN; -extern HRESULT DMUSIC_CreateDirectMusicLoaderResourceStream(void **ppobj) DECLSPEC_HIDDEN; -extern HRESULT DMUSIC_CreateDirectMusicLoaderGenericStream(void **ppobj) DECLSPEC_HIDDEN; +extern HRESULT create_dmloader(REFIID riid, void **ret_iface); +extern HRESULT create_dmcontainer(REFIID riid, void **ret_iface); +extern HRESULT DMUSIC_CreateDirectMusicLoaderFileStream(void **ppobj); +extern HRESULT DMUSIC_CreateDirectMusicLoaderResourceStream(void **ppobj); +extern HRESULT DMUSIC_CreateDirectMusicLoaderGenericStream(void **ppobj); /***************************************************************************** * IDirectMusicLoaderFileStream implementation structure @@ -85,7 +85,7 @@ struct IDirectMusicLoaderFileStream { }; /* Custom: */ -extern HRESULT WINAPI IDirectMusicLoaderFileStream_Attach (LPSTREAM iface, LPCWSTR wzFile, LPDIRECTMUSICLOADER8 pLoader) DECLSPEC_HIDDEN; +extern HRESULT WINAPI IDirectMusicLoaderFileStream_Attach (LPSTREAM iface, LPCWSTR wzFile, LPDIRECTMUSICLOADER8 pLoader); /***************************************************************************** * IDirectMusicLoaderResourceStream implementation structure @@ -106,7 +106,7 @@ struct IDirectMusicLoaderResourceStream { }; /* Custom: */ -extern HRESULT WINAPI IDirectMusicLoaderResourceStream_Attach (LPSTREAM iface, LPBYTE pbMemData, LONGLONG llMemLength, LONGLONG llPos, LPDIRECTMUSICLOADER8 pLoader) DECLSPEC_HIDDEN; +extern HRESULT WINAPI IDirectMusicLoaderResourceStream_Attach (LPSTREAM iface, LPBYTE pbMemData, LONGLONG llMemLength, LONGLONG llPos, LPDIRECTMUSICLOADER8 pLoader); /***************************************************************************** * IDirectMusicLoaderGenericStream implementation structure @@ -124,7 +124,7 @@ struct IDirectMusicLoaderGenericStream { }; /* Custom: */ -extern HRESULT WINAPI IDirectMusicLoaderGenericStream_Attach (LPSTREAM iface, LPSTREAM pStream, LPDIRECTMUSICLOADER8 pLoader) DECLSPEC_HIDDEN; +extern HRESULT WINAPI IDirectMusicLoaderGenericStream_Attach (LPSTREAM iface, LPSTREAM pStream, LPDIRECTMUSICLOADER8 pLoader); #include "debug.h" diff --git a/dlls/dmloader/dmobject.h b/dlls/dmloader/dmobject.h index afe721dc824..772be015c80 100644 --- a/dlls/dmloader/dmobject.h +++ b/dlls/dmloader/dmobject.h @@ -31,16 +31,16 @@ struct chunk_entry { const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */ }; -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN; -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) DECLSPEC_HIDDEN; -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) DECLSPEC_HIDDEN; +HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk); +HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk); +HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk); HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size) DECLSPEC_HIDDEN; + unsigned int *count, DWORD elem_size); HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size) DECLSPEC_HIDDEN; + ULONG size); HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size) DECLSPEC_HIDDEN; + ULONG size); static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk) { @@ -71,21 +71,21 @@ struct dmobject { DMUS_OBJECTDESC desc; }; -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk) DECLSPEC_HIDDEN; +void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk); /* Generic IDirectMusicObject methods */ HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface) DECLSPEC_HIDDEN; + void **ret_iface); +ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface); +ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface); HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc); HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc); /* Helper for IDirectMusicObject::ParseDescriptor */ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported) DECLSPEC_HIDDEN; + DMUS_OBJECTDESC *desc, DWORD supported); /* Additional supported flags for dmobj_parsedescriptor. DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */ #define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */ @@ -93,28 +93,28 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, /* 'DMRF' (reference list) helper */ HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj) DECLSPEC_HIDDEN; + IDirectMusicObject **dmobj); /* Generic IPersistStream methods */ HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface) DECLSPEC_HIDDEN; -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface) DECLSPEC_HIDDEN; -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) DECLSPEC_HIDDEN; + void **ret_iface); +ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface); +ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface); +HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class); /* IPersistStream methods not implemented in native */ HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, - CLSID *class) DECLSPEC_HIDDEN; -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface) DECLSPEC_HIDDEN; + CLSID *class); +HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface); HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty) DECLSPEC_HIDDEN; + BOOL clear_dirty); HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, - ULARGE_INTEGER *size) DECLSPEC_HIDDEN; + ULARGE_INTEGER *size); /* Debugging helpers */ -const char *debugstr_chunk(const struct chunk_entry *chunk) DECLSPEC_HIDDEN; -const char *debugstr_dmguid(const GUID *id) DECLSPEC_HIDDEN; -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc) DECLSPEC_HIDDEN; +const char *debugstr_chunk(const struct chunk_entry *chunk); +const char *debugstr_dmguid(const GUID *id); +void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc); static inline const char *debugstr_fourcc(DWORD fourcc) { From c4a2aad66f6b3831e2d97fa3f4d519a88224e3a1 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Wed, 3 Aug 2022 16:25:11 +1000 Subject: [PATCH 2405/2777] dmime: Store WAVE data when Loading. (cherry picked from commit 0774873ea26c11757cdf511943c17ec81c6e11c5) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segment.c | 57 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index bf44c5e73b3..c005d506cad 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -33,6 +33,10 @@ typedef struct IDirectMusicSegment8Impl { DMUS_IO_SEGMENT_HEADER header; IDirectMusicGraph *pGraph; struct list Tracks; + + PCMWAVEFORMAT wave_format; + void *wave_data; + int data_size; } IDirectMusicSegment8Impl; IDirectMusicSegment8Impl *create_segment(void); @@ -86,6 +90,9 @@ static ULONG WINAPI IDirectMusicSegment8Impl_Release(IDirectMusicSegment8 *iface TRACE("(%p) ref=%ld\n", This, ref); if (!ref) { + if (This->wave_data) + free(This->wave_data); + HeapFree(GetProcessHeap(), 0, This); DMIME_UnlockModule(); } @@ -818,6 +825,52 @@ static inline IDirectMusicSegment8Impl *impl_from_IPersistStream(IPersistStream return CONTAINING_RECORD(iface, IDirectMusicSegment8Impl, dmobj.IPersistStream_iface); } +static HRESULT parse_wave_form(IDirectMusicSegment8Impl *This, IStream *stream, const struct chunk_entry *riff) +{ + HRESULT hr; + struct chunk_entry chunk = {.parent = riff}; + + TRACE("Parsing segment wave in %p: %s\n", stream, debugstr_chunk(riff)); + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { + switch (chunk.id) { + case mmioFOURCC('f','m','t',' '): { + if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &This->wave_format, + sizeof(This->wave_format))) ) + return hr; + TRACE("Wave Format tag %d\n", This->wave_format.wf.wFormatTag); + break; + } + case mmioFOURCC('d','a','t','a'): { + TRACE("Wave Data size %lu\n", chunk.size); + if (This->wave_data) + ERR("Multiple data streams detected\n"); + This->wave_data = malloc(chunk.size); + This->data_size = chunk.size; + if (!This->wave_data) + return E_OUTOFMEMORY; + if (FAILED(hr = stream_chunk_get_data(stream, &chunk, This->wave_data, chunk.size))) + return hr; + break; + } + case FOURCC_LIST: { + FIXME("Skipping LIST tag\n"); + break; + } + case mmioFOURCC('I','S','F','T'): { + FIXME("Skipping ISFT tag\n"); + break; + } + case mmioFOURCC('f','a','c','t'): { + FIXME("Skipping fact tag\n"); + break; + } + } + } + + return SUCCEEDED(hr) ? S_OK : hr; +} + static HRESULT WINAPI seg_IPersistStream_Load(IPersistStream *iface, IStream *stream) { IDirectMusicSegment8Impl *This = impl_from_IPersistStream(iface); @@ -847,8 +900,10 @@ static HRESULT WINAPI seg_IPersistStream_Load(IPersistStream *iface, IStream *st if (riff.type == DMUS_FOURCC_SEGMENT_FORM) hr = parse_segment_form(This, stream, &riff); + else if(riff.type == mmioFOURCC('W','A','V','E')) + hr = parse_wave_form(This, stream, &riff); else { - FIXME("WAVE form loading not implemented\n"); + FIXME("Unknown type %s\n", debugstr_chunk(&riff)); hr = S_OK; } From 9d3fcefe2b9ca89ae3a42c3ac92a760b5d13af03 Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Tue, 22 Aug 2023 22:28:38 -0600 Subject: [PATCH 2406/2777] dmusic: Use CRT allocation functions. (cherry picked from commit 4ef31ae987b80ae7794c0a72a99e9999efda8a50) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/buffer.c | 10 +++++----- dlls/dmusic/clock.c | 4 ++-- dlls/dmusic/collection.c | 14 +++++++------- dlls/dmusic/dmobject.c | 7 +++---- dlls/dmusic/dmusic.c | 29 +++++++++++------------------ dlls/dmusic/download.c | 4 ++-- dlls/dmusic/instrument.c | 23 ++++++++++------------- dlls/dmusic/port.c | 29 ++++++++++++++--------------- 8 files changed, 54 insertions(+), 66 deletions(-) diff --git a/dlls/dmusic/buffer.c b/dlls/dmusic/buffer.c index c328c15541e..9aaa1a074b4 100644 --- a/dlls/dmusic/buffer.c +++ b/dlls/dmusic/buffer.c @@ -69,8 +69,8 @@ static ULONG WINAPI IDirectMusicBufferImpl_Release(LPDIRECTMUSICBUFFER iface) TRACE("(%p): new ref = %lu\n", iface, ref); if (!ref) { - HeapFree(GetProcessHeap(), 0, This->data); - HeapFree(GetProcessHeap(), 0, This); + free(This->data); + free(This); DMUSIC_UnlockModule(); } @@ -300,7 +300,7 @@ HRESULT DMUSIC_CreateDirectMusicBufferImpl(LPDMUS_BUFFERDESC desc, LPVOID* ret_i *ret_iface = NULL; - dmbuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicBufferImpl)); + dmbuffer = calloc(1, sizeof(IDirectMusicBufferImpl)); if (!dmbuffer) return E_OUTOFMEMORY; @@ -313,9 +313,9 @@ HRESULT DMUSIC_CreateDirectMusicBufferImpl(LPDMUS_BUFFERDESC desc, LPVOID* ret_i dmbuffer->format = desc->guidBufferFormat; dmbuffer->size = (desc->cbBuffer + 3) & ~3; /* Buffer size must be multiple of 4 bytes */ - dmbuffer->data = HeapAlloc(GetProcessHeap(), 0, dmbuffer->size); + dmbuffer->data = malloc(dmbuffer->size); if (!dmbuffer->data) { - HeapFree(GetProcessHeap(), 0, dmbuffer); + free(dmbuffer); return E_OUTOFMEMORY; } diff --git a/dlls/dmusic/clock.c b/dlls/dmusic/clock.c index 97bd05c4524..15a04c844e5 100644 --- a/dlls/dmusic/clock.c +++ b/dlls/dmusic/clock.c @@ -62,7 +62,7 @@ static ULONG WINAPI IReferenceClockImpl_Release(IReferenceClock *iface) TRACE("(%p): new ref = %lu\n", This, ref); if (!ref) { - HeapFree(GetProcessHeap(), 0, This); + free(This); DMUSIC_UnlockModule(); } @@ -126,7 +126,7 @@ HRESULT DMUSIC_CreateReferenceClockImpl(LPCGUID riid, LPVOID* ret_iface, LPUNKNO TRACE("(%s, %p, %p)\n", debugstr_guid(riid), ret_iface, unkouter); - clock = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IReferenceClockImpl)); + clock = calloc(1, sizeof(IReferenceClockImpl)); if (!clock) { *ret_iface = NULL; return E_OUTOFMEMORY; diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 8473c0078ec..0febf9dfd08 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -98,7 +98,7 @@ static ULONG WINAPI IDirectMusicCollectionImpl_Release(IDirectMusicCollection *i TRACE("(%p): new ref = %lu\n", iface, ref); if (!ref) { - HeapFree(GetProcessHeap(), 0, This); + free(This); DMUSIC_UnlockModule(); } @@ -257,7 +257,7 @@ static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface, switch (chunk.fccID) { case FOURCC_COLH: { TRACE_(dmfile)(": collection header chunk\n"); - This->pHeader = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, chunk.dwSize); + This->pHeader = calloc(1, chunk.dwSize); IStream_Read(stream, This->pHeader, chunk.dwSize, NULL); break; } @@ -275,10 +275,10 @@ static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface, } case FOURCC_PTBL: { TRACE_(dmfile)(": pool table chunk\n"); - This->pPoolTable = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(POOLTABLE)); + This->pPoolTable = calloc(1, sizeof(POOLTABLE)); IStream_Read(stream, This->pPoolTable, sizeof(POOLTABLE), NULL); chunk.dwSize -= sizeof(POOLTABLE); - This->pPoolCues = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pPoolTable->cCues * sizeof(POOLCUE)); + This->pPoolCues = calloc(This->pPoolTable->cCues, sizeof(POOLCUE)); IStream_Read(stream, This->pPoolCues, chunk.dwSize, NULL); break; } @@ -320,7 +320,7 @@ static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface, } case mmioFOURCC('I','C','O','P'): { TRACE_(dmfile)(": copyright chunk\n"); - This->szCopyright = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, chunk.dwSize); + This->szCopyright = calloc(1, chunk.dwSize); IStream_Read(stream, This->szCopyright, chunk.dwSize, NULL); if (even_or_odd(chunk.dwSize)) { ListCount[0]++; @@ -387,7 +387,7 @@ static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface, ListCount[1] = 0; switch (chunk.fccID) { case FOURCC_INS: { - LPDMUS_PRIVATE_INSTRUMENTENTRY new_instrument = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_INSTRUMENTENTRY)); + DMUS_PRIVATE_INSTRUMENTENTRY *new_instrument = calloc(1, sizeof(DMUS_PRIVATE_INSTRUMENTENTRY)); TRACE_(dmfile)(": instrument list\n"); /* Only way to create this one... even M$ does it discretely */ DMUSIC_CreateDirectMusicInstrumentImpl(&IID_IDirectMusicInstrument, (void**)&new_instrument->pInstrument, NULL); @@ -531,7 +531,7 @@ HRESULT DMUSIC_CreateDirectMusicCollectionImpl(REFIID lpcGUID, void **ppobj, IUn if (pUnkOuter) return CLASS_E_NOAGGREGATION; - obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicCollectionImpl)); + obj = calloc(1, sizeof(IDirectMusicCollectionImpl)); if (!obj) return E_OUTOFMEMORY; diff --git a/dlls/dmusic/dmobject.c b/dlls/dmusic/dmobject.c index b526b23d031..07d887a376c 100644 --- a/dlls/dmusic/dmobject.c +++ b/dlls/dmusic/dmobject.c @@ -28,7 +28,6 @@ #include "dmusics.h" #include "dmobject.h" #include "wine/debug.h" -#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(dmobj); WINE_DECLARE_DEBUG_CHANNEL(dmfile); @@ -375,7 +374,7 @@ HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) /* Reads chunk data of the form: DWORD - size of array element element[] - Array of elements - The caller needs to heap_free() the array. + The caller needs to free() the array. */ HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, unsigned int *count, DWORD elem_size) @@ -400,10 +399,10 @@ HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, *count = (chunk->size - sizeof(DWORD)) / elem_size; size = *count * elem_size; - if (!(*array = heap_alloc(size))) + if (!(*array = malloc(size))) return E_OUTOFMEMORY; if (FAILED(hr = stream_read(stream, *array, size))) { - heap_free(*array); + free(*array); *array = NULL; return hr; } diff --git a/dlls/dmusic/dmusic.c b/dlls/dmusic/dmusic.c index 3a1824143d7..8fb35e65809 100644 --- a/dlls/dmusic/dmusic.c +++ b/dlls/dmusic/dmusic.c @@ -23,7 +23,6 @@ #include "dmusic_private.h" #include "dmobject.h" -#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(dmusic); @@ -75,7 +74,7 @@ static ULONG WINAPI master_IReferenceClock_Release(IReferenceClock *iface) TRACE("(%p) ref = %lu\n", iface, ref); if (!ref) - heap_free(This); + free(This); return ref; } @@ -136,7 +135,7 @@ static HRESULT master_clock_create(IReferenceClock **clock) TRACE("(%p)\n", clock); - if (!(obj = heap_alloc_zero(sizeof(*obj)))) + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IReferenceClock_iface.lpVtbl = &master_clock_vtbl; @@ -199,9 +198,9 @@ static ULONG WINAPI IDirectMusic8Impl_Release(LPDIRECTMUSIC8 iface) IReferenceClock_Release(This->master_clock); if (This->dsound) IDirectSound_Release(This->dsound); - HeapFree(GetProcessHeap(), 0, This->system_ports); - HeapFree(GetProcessHeap(), 0, This->ports); - HeapFree(GetProcessHeap(), 0, This); + free(This->system_ports); + free(This->ports); + free(This); DMUSIC_UnlockModule(); } @@ -283,12 +282,7 @@ static HRESULT WINAPI IDirectMusic8Impl_CreatePort(LPDIRECTMUSIC8 iface, REFCLSI return hr; } This->num_ports++; - if (!This->ports) - This->ports = HeapAlloc(GetProcessHeap(), 0, - sizeof(*This->ports) * This->num_ports); - else - This->ports = HeapReAlloc(GetProcessHeap(), 0, This->ports, - sizeof(*This->ports) * This->num_ports); + This->ports = realloc(This->ports, sizeof(*This->ports) * This->num_ports); This->ports[This->num_ports - 1] = new_port; *port = new_port; return S_OK; @@ -320,15 +314,14 @@ void dmusic_remove_port(IDirectMusic8Impl *dmusic, IDirectMusicPort *port) } if (!--dmusic->num_ports) { - HeapFree(GetProcessHeap(), 0, dmusic->ports); + free(dmusic->ports); dmusic->ports = NULL; return; } memmove(&dmusic->ports[i], &dmusic->ports[i + 1], (dmusic->num_ports - i) * sizeof(*dmusic->ports)); - dmusic->ports = HeapReAlloc(GetProcessHeap(), 0, dmusic->ports, - sizeof(*dmusic->ports) * dmusic->num_ports); + dmusic->ports = realloc(dmusic->ports, sizeof(*dmusic->ports) * dmusic->num_ports); } static HRESULT WINAPI IDirectMusic8Impl_EnumMasterClock(LPDIRECTMUSIC8 iface, DWORD index, LPDMUS_CLOCKINFO clock_info) @@ -517,7 +510,7 @@ static void create_system_ports_list(IDirectMusic8Impl* object) nb_midi_in = midiInGetNumDevs(); nb_ports = 1 /* midi mapper */ + nb_midi_out + nb_midi_in + 1 /* synth port */; - port = object->system_ports = HeapAlloc(GetProcessHeap(), 0, nb_ports * sizeof(port_info)); + port = object->system_ports = malloc(nb_ports * sizeof(port_info)); if (!object->system_ports) return; @@ -599,7 +592,7 @@ HRESULT DMUSIC_CreateDirectMusicImpl(REFIID riid, void **ret_iface, IUnknown *un if (unkouter) return CLASS_E_NOAGGREGATION; - dmusic = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusic8Impl)); + dmusic = calloc(1, sizeof(IDirectMusic8Impl)); if (!dmusic) return E_OUTOFMEMORY; @@ -607,7 +600,7 @@ HRESULT DMUSIC_CreateDirectMusicImpl(REFIID riid, void **ret_iface, IUnknown *un dmusic->ref = 1; ret = master_clock_create(&dmusic->master_clock); if (FAILED(ret)) { - HeapFree(GetProcessHeap(), 0, dmusic); + free(dmusic); return ret; } diff --git a/dlls/dmusic/download.c b/dlls/dmusic/download.c index 56ee9c7477d..48f0efd5f69 100644 --- a/dlls/dmusic/download.c +++ b/dlls/dmusic/download.c @@ -64,7 +64,7 @@ static ULONG WINAPI IDirectMusicDownloadImpl_Release(IDirectMusicDownload *iface TRACE("(%p): new ref = %lu\n", iface, ref); if (!ref) { - HeapFree(GetProcessHeap(), 0, This); + free(This); DMUSIC_UnlockModule(); } @@ -91,7 +91,7 @@ HRESULT DMUSIC_CreateDirectMusicDownloadImpl(const GUID *guid, void **ret_iface, { IDirectMusicDownloadImpl *download; - download = HeapAlloc(GetProcessHeap(), 0, sizeof(*download)); + download = malloc(sizeof(*download)); if (!download) { *ret_iface = NULL; diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index f90e08b9128..7b7ee3def64 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -77,11 +77,11 @@ static ULONG WINAPI IDirectMusicInstrumentImpl_Release(LPDIRECTMUSICINSTRUMENT i { ULONG i; - HeapFree(GetProcessHeap(), 0, This->regions); + free(This->regions); for (i = 0; i < This->nb_articulations; i++) - HeapFree(GetProcessHeap(), 0, This->articulations->connections); - HeapFree(GetProcessHeap(), 0, This->articulations); - HeapFree(GetProcessHeap(), 0, This); + free(This->articulations->connections); + free(This->articulations); + free(This); DMUSIC_UnlockModule(); } @@ -125,7 +125,7 @@ HRESULT DMUSIC_CreateDirectMusicInstrumentImpl (LPCGUID lpcGUID, LPVOID* ppobj, IDirectMusicInstrumentImpl* dminst; HRESULT hr; - dminst = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicInstrumentImpl)); + dminst = calloc(1, sizeof(IDirectMusicInstrumentImpl)); if (NULL == dminst) { *ppobj = NULL; return E_OUTOFMEMORY; @@ -257,10 +257,7 @@ static HRESULT load_articulation(IDirectMusicInstrumentImpl *This, IStream *stre HRESULT ret; instrument_articulation *articulation; - if (!This->articulations) - This->articulations = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->articulations)); - else - This->articulations = HeapReAlloc(GetProcessHeap(), 0, This->articulations, sizeof(*This->articulations) * (This->nb_articulations + 1)); + This->articulations = realloc(This->articulations, sizeof(*This->articulations) * (This->nb_articulations + 1)); if (!This->articulations) return E_OUTOFMEMORY; @@ -270,14 +267,14 @@ static HRESULT load_articulation(IDirectMusicInstrumentImpl *This, IStream *stre if (FAILED(ret)) return ret; - articulation->connections = HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTION) * articulation->connections_list.cConnections); + articulation->connections = malloc(sizeof(CONNECTION) * articulation->connections_list.cConnections); if (!articulation->connections) return E_OUTOFMEMORY; ret = read_from_stream(stream, articulation->connections, sizeof(CONNECTION) * articulation->connections_list.cConnections); if (FAILED(ret)) { - HeapFree(GetProcessHeap(), 0, articulation->connections); + free(articulation->connections); return ret; } @@ -309,7 +306,7 @@ HRESULT IDirectMusicInstrumentImpl_CustomLoad(IDirectMusicInstrument *iface, ISt return DMUS_E_UNSUPPORTED_STREAM; } - This->regions = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->regions) * This->header.cRegions); + This->regions = malloc(sizeof(*This->regions) * This->header.cRegions); if (!This->regions) return E_OUTOFMEMORY; @@ -438,7 +435,7 @@ HRESULT IDirectMusicInstrumentImpl_CustomLoad(IDirectMusicInstrument *iface, ISt return S_OK; error: - HeapFree(GetProcessHeap(), 0, This->regions); + free(This->regions); This->regions = NULL; return DMUS_E_UNSUPPORTED_STREAM; diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index 8549c62c4b1..518b4fe9666 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -22,7 +22,6 @@ #include #include "dmusic_private.h" #include "dmobject.h" -#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(dmusic); @@ -104,8 +103,8 @@ static ULONG WINAPI IDirectMusicDownloadedInstrumentImpl_Release(LPDIRECTMUSICDO if (!ref) { - HeapFree(GetProcessHeap(), 0, This->data); - HeapFree(GetProcessHeap(), 0, This); + free(This->data); + free(This); DMUSIC_UnlockModule(); } @@ -131,7 +130,7 @@ static HRESULT DMUSIC_CreateDirectMusicDownloadedInstrumentImpl(IDirectMusicDown { IDirectMusicDownloadedInstrumentImpl *object; - object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)); + object = calloc(1, sizeof(*object)); if (!object) { *instrument = NULL; @@ -202,7 +201,7 @@ static ULONG WINAPI synth_port_Release(IDirectMusicPort *iface) IDirectSoundBuffer_Release(This->dsbuffer); if (This->dsound) IDirectSound_Release(This->dsound); - HeapFree(GetProcessHeap(), 0, This); + free(This); } DMUSIC_UnlockModule(); @@ -255,7 +254,7 @@ static HRESULT WINAPI synth_port_DownloadInstrument(IDirectMusicPort *iface, IDi struct synth_port *This = synth_from_IDirectMusicPort(iface); IDirectMusicInstrumentImpl *instrument_object; HRESULT ret; - BOOL free; + BOOL on_heap; HANDLE download; DMUS_DOWNLOADINFO *info; DMUS_OFFSETTABLE *offset_table; @@ -276,7 +275,7 @@ static HRESULT WINAPI synth_port_DownloadInstrument(IDirectMusicPort *iface, IDi nb_regions = instrument_object->header.cRegions; size = sizeof(DMUS_DOWNLOADINFO) + sizeof(ULONG) * (1 + nb_regions) + sizeof(DMUS_INSTRUMENT) + sizeof(DMUS_REGION) * nb_regions; - data = HeapAlloc(GetProcessHeap(), 0, size); + data = malloc(size); if (!data) return E_OUTOFMEMORY; @@ -317,7 +316,7 @@ static HRESULT WINAPI synth_port_DownloadInstrument(IDirectMusicPort *iface, IDi region->WLOOP[0] = instrument_object->regions[i].wave_loop; } - ret = IDirectMusicSynth8_Download(This->synth, &download, (VOID*)data, &free); + ret = IDirectMusicSynth8_Download(This->synth, &download, (void*)data, &on_heap); if (SUCCEEDED(ret)) ret = DMUSIC_CreateDirectMusicDownloadedInstrumentImpl(downloaded_instrument); @@ -331,7 +330,7 @@ static HRESULT WINAPI synth_port_DownloadInstrument(IDirectMusicPort *iface, IDi } *downloaded_instrument = NULL; - HeapFree(GetProcessHeap(), 0, data); + free(data); return E_FAIL; } @@ -349,7 +348,7 @@ static HRESULT WINAPI synth_port_UnloadInstrument(IDirectMusicPort *iface, if (!downloaded_object->downloaded) return DMUS_E_NOT_DOWNLOADED_TO_PORT; - HeapFree(GetProcessHeap(), 0, downloaded_object->data); + free(downloaded_object->data); downloaded_object->data = NULL; downloaded_object->downloaded = FALSE; @@ -779,7 +778,7 @@ HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_param *port = NULL; - obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj)); + obj = calloc(1, sizeof(*obj)); if (!obj) return E_OUTOFMEMORY; @@ -843,7 +842,7 @@ HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_param IDirectMusicSynth_Release(obj->synth); if (obj->synth_sink) IDirectMusicSynthSink_Release(obj->synth_sink); - HeapFree(GetProcessHeap(), 0, obj); + free(obj); return hr; } @@ -902,7 +901,7 @@ static ULONG WINAPI midi_IDirectMusicPort_Release(IDirectMusicPort *iface) if (!ref) { if (This->clock) IReferenceClock_Release(This->clock); - heap_free(This); + free(This); } return ref; @@ -1124,7 +1123,7 @@ static HRESULT midi_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *para struct midi_port *obj; HRESULT hr; - if (!(obj = heap_alloc_zero(sizeof(*obj)))) + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicPort_iface.lpVtbl = &midi_port_vtbl; @@ -1133,7 +1132,7 @@ static HRESULT midi_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *para hr = DMUSIC_CreateReferenceClockImpl(&IID_IReferenceClock, (void **)&obj->clock, NULL); if (hr != S_OK) { - HeapFree(GetProcessHeap(), 0, obj); + free(obj); return hr; } From f221cc47106f87685660583b9178b3596bd6c3d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 24 Aug 2023 11:05:32 +0200 Subject: [PATCH 2407/2777] dmsynth: Remove unnecessary comments. (cherry picked from commit 23b8988464135b3979270ed0993b51f35fc1f718) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 4 ---- dlls/dmsynth/synthsink.c | 3 --- 2 files changed, 7 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 3631bcfe784..2c4a6f04e81 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -36,7 +36,6 @@ static inline IDirectMusicSynth8Impl *impl_from_IDirectMusicSynth8(IDirectMusicS return CONTAINING_RECORD(iface, IDirectMusicSynth8Impl, IDirectMusicSynth8_iface); } -/* IDirectMusicSynth8Impl IUnknown part: */ static HRESULT WINAPI IDirectMusicSynth8Impl_QueryInterface(IDirectMusicSynth8 *iface, REFIID riid, void **ret_iface) { @@ -93,7 +92,6 @@ static ULONG WINAPI IDirectMusicSynth8Impl_Release(IDirectMusicSynth8 *iface) return ref; } -/* IDirectMusicSynth8Impl IDirectMusicSynth part: */ static HRESULT WINAPI IDirectMusicSynth8Impl_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *params) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -542,7 +540,6 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_GetAppend(IDirectMusicSynth8 *iface return S_OK; } -/* IDirectMusicSynth8Impl IDirectMusicSynth8 part: */ static HRESULT WINAPI IDirectMusicSynth8Impl_PlayVoice(IDirectMusicSynth8 *iface, REFERENCE_TIME ref_time, DWORD voice_id, DWORD channel_group, DWORD channel, DWORD dwDLId, LONG prPitch, LONG vrVolume, SAMPLE_TIME stVoiceStart, SAMPLE_TIME stLoopStart, @@ -728,7 +725,6 @@ static const IKsControlVtbl DMSynthImpl_IKsControl_Vtbl = { DMSynthImpl_IKsControl_KsEvent }; -/* for ClassFactory */ HRESULT DMUSIC_CreateDirectMusicSynthImpl(REFIID riid, void **ppobj) { IDirectMusicSynth8Impl *obj; diff --git a/dlls/dmsynth/synthsink.c b/dlls/dmsynth/synthsink.c index a277a05bafb..4354069b274 100644 --- a/dlls/dmsynth/synthsink.c +++ b/dlls/dmsynth/synthsink.c @@ -32,7 +32,6 @@ static inline IDirectMusicSynthSinkImpl *impl_from_IDirectMusicSynthSink(IDirect return CONTAINING_RECORD(iface, IDirectMusicSynthSinkImpl, IDirectMusicSynthSink_iface); } -/* IDirectMusicSynthSinkImpl IUnknown part: */ static HRESULT WINAPI IDirectMusicSynthSinkImpl_QueryInterface(IDirectMusicSynthSink *iface, REFIID riid, void **ret_iface) { @@ -90,7 +89,6 @@ static ULONG WINAPI IDirectMusicSynthSinkImpl_Release(IDirectMusicSynthSink *ifa return ref; } -/* IDirectMusicSynthSinkImpl IDirectMusicSynthSink part: */ static HRESULT WINAPI IDirectMusicSynthSinkImpl_Init(IDirectMusicSynthSink *iface, IDirectMusicSynth *synth) { @@ -297,7 +295,6 @@ static const IKsControlVtbl DMSynthSinkImpl_IKsControl_Vtbl = { DMSynthSinkImpl_IKsControl_KsEvent }; -/* for ClassFactory */ HRESULT DMUSIC_CreateDirectMusicSynthSinkImpl(REFIID riid, void **ret_iface) { IDirectMusicSynthSinkImpl *obj; From 3e498ca0cb31c85aefc6b710dc99fffa7ef4a800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Aug 2023 17:44:17 +0200 Subject: [PATCH 2408/2777] dmsynth: Always return S_FALSE from DllCanUnloadNow. (cherry picked from commit 3b5160c97567ceb13d719219e45972f07f990fbb) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/dmsynth_main.c | 22 ---------------------- dlls/dmsynth/dmsynth_private.h | 7 ------- dlls/dmsynth/synth.c | 2 -- dlls/dmsynth/synthsink.c | 2 -- 4 files changed, 33 deletions(-) diff --git a/dlls/dmsynth/dmsynth_main.c b/dlls/dmsynth/dmsynth_main.c index a5e2e605419..edeaab8474e 100644 --- a/dlls/dmsynth/dmsynth_main.c +++ b/dlls/dmsynth/dmsynth_main.c @@ -25,8 +25,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); -LONG DMSYNTH_refCount = 0; - typedef struct { IClassFactory IClassFactory_iface; HRESULT (*fnCreateInstance)(REFIID riid, void **ppv); @@ -62,15 +60,11 @@ static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID r static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) { - DMSYNTH_LockModule(); - return 2; /* non-heap based object */ } static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) { - DMSYNTH_UnlockModule(); - return 1; /* non-heap based object */ } @@ -90,12 +84,6 @@ static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock) { TRACE("(%d)\n", dolock); - - if (dolock) - DMSYNTH_LockModule(); - else - DMSYNTH_UnlockModule(); - return S_OK; } @@ -111,16 +99,6 @@ static IClassFactoryImpl Synth_CF = {{&classfactory_vtbl}, DMUSIC_CreateDirectMu static IClassFactoryImpl SynthSink_CF = {{&classfactory_vtbl}, DMUSIC_CreateDirectMusicSynthSinkImpl}; -/****************************************************************** - * DllCanUnloadNow (DMSYNTH.@) - * - * - */ -HRESULT WINAPI DllCanUnloadNow(void) -{ - return DMSYNTH_refCount != 0 ? S_FALSE : S_OK; -} - /****************************************************************** * DllGetClassObject (DMSYNTH.@) diff --git a/dlls/dmsynth/dmsynth_private.h b/dlls/dmsynth/dmsynth_private.h index c21a9e84a84..3a3e76dfaf4 100644 --- a/dlls/dmsynth/dmsynth_private.h +++ b/dlls/dmsynth/dmsynth_private.h @@ -80,13 +80,6 @@ struct IDirectMusicSynthSinkImpl { BOOL active; }; -/********************************************************************** - * Dll lifetime tracking declaration for dmsynth.dll - */ -extern LONG DMSYNTH_refCount; -static inline void DMSYNTH_LockModule(void) { InterlockedIncrement( &DMSYNTH_refCount ); } -static inline void DMSYNTH_UnlockModule(void) { InterlockedDecrement( &DMSYNTH_refCount ); } - /***************************************************************************** * Misc. */ diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 2c4a6f04e81..29aff9e988f 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -86,7 +86,6 @@ static ULONG WINAPI IDirectMusicSynth8Impl_Release(IDirectMusicSynth8 *iface) if (This->latency_clock) IReferenceClock_Release(This->latency_clock); HeapFree(GetProcessHeap(), 0, This); - DMSYNTH_UnlockModule(); } return ref; @@ -753,7 +752,6 @@ HRESULT DMUSIC_CreateDirectMusicSynthImpl(REFIID riid, void **ppobj) obj->caps.dwEffectFlags = DMUS_EFFECT_REVERB; lstrcpyW(obj->caps.wszDescription, L"Microsoft Synthesizer"); - DMSYNTH_LockModule(); hr = IDirectMusicSynth8_QueryInterface(&obj->IDirectMusicSynth8_iface, riid, ppobj); IDirectMusicSynth8_Release(&obj->IDirectMusicSynth8_iface); diff --git a/dlls/dmsynth/synthsink.c b/dlls/dmsynth/synthsink.c index 4354069b274..405fe4af1f0 100644 --- a/dlls/dmsynth/synthsink.c +++ b/dlls/dmsynth/synthsink.c @@ -83,7 +83,6 @@ static ULONG WINAPI IDirectMusicSynthSinkImpl_Release(IDirectMusicSynthSink *ifa if (This->master_clock) IReferenceClock_Release(This->master_clock); HeapFree(GetProcessHeap(), 0, This); - DMSYNTH_UnlockModule(); } return ref; @@ -319,7 +318,6 @@ HRESULT DMUSIC_CreateDirectMusicSynthSinkImpl(REFIID riid, void **ret_iface) return hr; } - DMSYNTH_LockModule(); hr = IDirectMusicSynthSink_QueryInterface(&obj->IDirectMusicSynthSink_iface, riid, ret_iface); IDirectMusicSynthSink_Release(&obj->IDirectMusicSynthSink_iface); From c7d8649e162a9a810b14cd08be5c14fa7594dd91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 18 Aug 2023 21:34:24 +0200 Subject: [PATCH 2409/2777] dmsynth: Move IDirectMusicSynthSinkImpl struct to where it is used. (cherry picked from commit da256c4426baff6dafb26c1d524d13b3fc018ac1) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/dmsynth_private.h | 14 -------------- dlls/dmsynth/synthsink.c | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/dlls/dmsynth/dmsynth_private.h b/dlls/dmsynth/dmsynth_private.h index 3a3e76dfaf4..b9f160f000d 100644 --- a/dlls/dmsynth/dmsynth_private.h +++ b/dlls/dmsynth/dmsynth_private.h @@ -44,7 +44,6 @@ * Interfaces */ typedef struct IDirectMusicSynth8Impl IDirectMusicSynth8Impl; -typedef struct IDirectMusicSynthSinkImpl IDirectMusicSynthSinkImpl; /***************************************************************************** * ClassFactory @@ -67,19 +66,6 @@ struct IDirectMusicSynth8Impl { IDirectMusicSynthSink *sink; }; -/***************************************************************************** - * IDirectMusicSynthSinkImpl implementation structure - */ -struct IDirectMusicSynthSinkImpl { - IDirectMusicSynthSink IDirectMusicSynthSink_iface; - IKsControl IKsControl_iface; - LONG ref; - IReferenceClock *latency_clock; - IReferenceClock *master_clock; - IDirectMusicSynth *synth; /* No reference hold! */ - BOOL active; -}; - /***************************************************************************** * Misc. */ diff --git a/dlls/dmsynth/synthsink.c b/dlls/dmsynth/synthsink.c index 405fe4af1f0..3f63e69746c 100644 --- a/dlls/dmsynth/synthsink.c +++ b/dlls/dmsynth/synthsink.c @@ -27,6 +27,20 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); +typedef struct IDirectMusicSynthSinkImpl IDirectMusicSynthSinkImpl; + +struct IDirectMusicSynthSinkImpl +{ + IDirectMusicSynthSink IDirectMusicSynthSink_iface; + IKsControl IKsControl_iface; + LONG ref; + + IReferenceClock *latency_clock; + IReferenceClock *master_clock; + IDirectMusicSynth *synth; /* No reference hold! */ + BOOL active; +}; + static inline IDirectMusicSynthSinkImpl *impl_from_IDirectMusicSynthSink(IDirectMusicSynthSink *iface) { return CONTAINING_RECORD(iface, IDirectMusicSynthSinkImpl, IDirectMusicSynthSink_iface); From c2b6a5b9487a192e047da03a66417a97ad2f987c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 18 Aug 2023 21:49:49 +0200 Subject: [PATCH 2410/2777] dmsynth: Rename IDirectMusicSynthSinkImpl method prefix to synth_sink. (cherry picked from commit 1f7629dc0a22f4304f78e61e9c9330081d7b1449) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synthsink.c | 90 ++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/dlls/dmsynth/synthsink.c b/dlls/dmsynth/synthsink.c index 3f63e69746c..1e72e5d1f1b 100644 --- a/dlls/dmsynth/synthsink.c +++ b/dlls/dmsynth/synthsink.c @@ -46,7 +46,7 @@ static inline IDirectMusicSynthSinkImpl *impl_from_IDirectMusicSynthSink(IDirect return CONTAINING_RECORD(iface, IDirectMusicSynthSinkImpl, IDirectMusicSynthSink_iface); } -static HRESULT WINAPI IDirectMusicSynthSinkImpl_QueryInterface(IDirectMusicSynthSink *iface, +static HRESULT WINAPI synth_sink_QueryInterface(IDirectMusicSynthSink *iface, REFIID riid, void **ret_iface) { IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); @@ -74,7 +74,7 @@ static HRESULT WINAPI IDirectMusicSynthSinkImpl_QueryInterface(IDirectMusicSynth return E_NOINTERFACE; } -static ULONG WINAPI IDirectMusicSynthSinkImpl_AddRef(IDirectMusicSynthSink *iface) +static ULONG WINAPI synth_sink_AddRef(IDirectMusicSynthSink *iface) { IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); ULONG ref = InterlockedIncrement(&This->ref); @@ -84,7 +84,7 @@ static ULONG WINAPI IDirectMusicSynthSinkImpl_AddRef(IDirectMusicSynthSink *ifac return ref; } -static ULONG WINAPI IDirectMusicSynthSinkImpl_Release(IDirectMusicSynthSink *iface) +static ULONG WINAPI synth_sink_Release(IDirectMusicSynthSink *iface) { IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); ULONG ref = InterlockedDecrement(&This->ref); @@ -102,7 +102,7 @@ static ULONG WINAPI IDirectMusicSynthSinkImpl_Release(IDirectMusicSynthSink *ifa return ref; } -static HRESULT WINAPI IDirectMusicSynthSinkImpl_Init(IDirectMusicSynthSink *iface, +static HRESULT WINAPI synth_sink_Init(IDirectMusicSynthSink *iface, IDirectMusicSynth *synth) { IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); @@ -116,7 +116,7 @@ static HRESULT WINAPI IDirectMusicSynthSinkImpl_Init(IDirectMusicSynthSink *ifac return S_OK; } -static HRESULT WINAPI IDirectMusicSynthSinkImpl_SetMasterClock(IDirectMusicSynthSink *iface, +static HRESULT WINAPI synth_sink_SetMasterClock(IDirectMusicSynthSink *iface, IReferenceClock *clock) { IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); @@ -134,7 +134,7 @@ static HRESULT WINAPI IDirectMusicSynthSinkImpl_SetMasterClock(IDirectMusicSynth return S_OK; } -static HRESULT WINAPI IDirectMusicSynthSinkImpl_GetLatencyClock(IDirectMusicSynthSink *iface, +static HRESULT WINAPI synth_sink_GetLatencyClock(IDirectMusicSynthSink *iface, IReferenceClock **clock) { IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); @@ -150,7 +150,7 @@ static HRESULT WINAPI IDirectMusicSynthSinkImpl_GetLatencyClock(IDirectMusicSynt return S_OK; } -static HRESULT WINAPI IDirectMusicSynthSinkImpl_Activate(IDirectMusicSynthSink *iface, +static HRESULT WINAPI synth_sink_Activate(IDirectMusicSynthSink *iface, BOOL enable) { IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); @@ -160,7 +160,7 @@ static HRESULT WINAPI IDirectMusicSynthSinkImpl_Activate(IDirectMusicSynthSink * return S_OK; } -static HRESULT WINAPI IDirectMusicSynthSinkImpl_SampleToRefTime(IDirectMusicSynthSink *iface, +static HRESULT WINAPI synth_sink_SampleToRefTime(IDirectMusicSynthSink *iface, LONGLONG sample_time, REFERENCE_TIME *ref_time) { IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); @@ -170,7 +170,7 @@ static HRESULT WINAPI IDirectMusicSynthSinkImpl_SampleToRefTime(IDirectMusicSynt return S_OK; } -static HRESULT WINAPI IDirectMusicSynthSinkImpl_RefTimeToSample(IDirectMusicSynthSink *iface, +static HRESULT WINAPI synth_sink_RefTimeToSample(IDirectMusicSynthSink *iface, REFERENCE_TIME ref_time, LONGLONG *sample_time) { IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); @@ -180,7 +180,7 @@ static HRESULT WINAPI IDirectMusicSynthSinkImpl_RefTimeToSample(IDirectMusicSynt return S_OK; } -static HRESULT WINAPI IDirectMusicSynthSinkImpl_SetDirectSound(IDirectMusicSynthSink *iface, +static HRESULT WINAPI synth_sink_SetDirectSound(IDirectMusicSynthSink *iface, IDirectSound *dsound, IDirectSoundBuffer *dsound_buffer) { IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); @@ -190,7 +190,7 @@ static HRESULT WINAPI IDirectMusicSynthSinkImpl_SetDirectSound(IDirectMusicSynth return S_OK; } -static HRESULT WINAPI IDirectMusicSynthSinkImpl_GetDesiredBufferSize(IDirectMusicSynthSink *iface, +static HRESULT WINAPI synth_sink_GetDesiredBufferSize(IDirectMusicSynthSink *iface, DWORD *size) { IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); @@ -211,18 +211,19 @@ static HRESULT WINAPI IDirectMusicSynthSinkImpl_GetDesiredBufferSize(IDirectMusi return S_OK; } -static const IDirectMusicSynthSinkVtbl DirectMusicSynthSink_Vtbl = { - IDirectMusicSynthSinkImpl_QueryInterface, - IDirectMusicSynthSinkImpl_AddRef, - IDirectMusicSynthSinkImpl_Release, - IDirectMusicSynthSinkImpl_Init, - IDirectMusicSynthSinkImpl_SetMasterClock, - IDirectMusicSynthSinkImpl_GetLatencyClock, - IDirectMusicSynthSinkImpl_Activate, - IDirectMusicSynthSinkImpl_SampleToRefTime, - IDirectMusicSynthSinkImpl_RefTimeToSample, - IDirectMusicSynthSinkImpl_SetDirectSound, - IDirectMusicSynthSinkImpl_GetDesiredBufferSize +static const IDirectMusicSynthSinkVtbl synth_sink_vtbl = +{ + synth_sink_QueryInterface, + synth_sink_AddRef, + synth_sink_Release, + synth_sink_Init, + synth_sink_SetMasterClock, + synth_sink_GetLatencyClock, + synth_sink_Activate, + synth_sink_SampleToRefTime, + synth_sink_RefTimeToSample, + synth_sink_SetDirectSound, + synth_sink_GetDesiredBufferSize, }; static inline IDirectMusicSynthSinkImpl *impl_from_IKsControl(IKsControl *iface) @@ -230,29 +231,29 @@ static inline IDirectMusicSynthSinkImpl *impl_from_IKsControl(IKsControl *iface) return CONTAINING_RECORD(iface, IDirectMusicSynthSinkImpl, IKsControl_iface); } -static HRESULT WINAPI DMSynthSinkImpl_IKsControl_QueryInterface(IKsControl* iface, REFIID riid, LPVOID *ppobj) +static HRESULT WINAPI synth_sink_control_QueryInterface(IKsControl* iface, REFIID riid, LPVOID *ppobj) { IDirectMusicSynthSinkImpl *This = impl_from_IKsControl(iface); - return IDirectMusicSynthSinkImpl_QueryInterface(&This->IDirectMusicSynthSink_iface, riid, ppobj); + return synth_sink_QueryInterface(&This->IDirectMusicSynthSink_iface, riid, ppobj); } -static ULONG WINAPI DMSynthSinkImpl_IKsControl_AddRef(IKsControl* iface) +static ULONG WINAPI synth_sink_control_AddRef(IKsControl* iface) { IDirectMusicSynthSinkImpl *This = impl_from_IKsControl(iface); - return IDirectMusicSynthSinkImpl_AddRef(&This->IDirectMusicSynthSink_iface); + return synth_sink_AddRef(&This->IDirectMusicSynthSink_iface); } -static ULONG WINAPI DMSynthSinkImpl_IKsControl_Release(IKsControl* iface) +static ULONG WINAPI synth_sink_control_Release(IKsControl* iface) { IDirectMusicSynthSinkImpl *This = impl_from_IKsControl(iface); - return IDirectMusicSynthSinkImpl_Release(&This->IDirectMusicSynthSink_iface); + return synth_sink_Release(&This->IDirectMusicSynthSink_iface); } -static HRESULT WINAPI DMSynthSinkImpl_IKsControl_KsProperty(IKsControl* iface, PKSPROPERTY Property, ULONG PropertyLength, LPVOID PropertyData, - ULONG DataLength, ULONG* BytesReturned) +static HRESULT WINAPI synth_sink_control_KsProperty(IKsControl* iface, PKSPROPERTY Property, + ULONG PropertyLength, LPVOID PropertyData, ULONG DataLength, ULONG* BytesReturned) { TRACE("(%p, %p, %lu, %p, %lu, %p)\n", iface, Property, PropertyLength, PropertyData, DataLength, BytesReturned); @@ -282,16 +283,16 @@ static HRESULT WINAPI DMSynthSinkImpl_IKsControl_KsProperty(IKsControl* iface, P return S_OK; } -static HRESULT WINAPI DMSynthSinkImpl_IKsControl_KsMethod(IKsControl* iface, PKSMETHOD Method, ULONG MethodLength, LPVOID MethodData, - ULONG DataLength, ULONG* BytesReturned) +static HRESULT WINAPI synth_sink_control_KsMethod(IKsControl* iface, PKSMETHOD Method, + ULONG MethodLength, LPVOID MethodData, ULONG DataLength, ULONG* BytesReturned) { FIXME("(%p, %p, %lu, %p, %lu, %p): stub\n", iface, Method, MethodLength, MethodData, DataLength, BytesReturned); return E_NOTIMPL; } -static HRESULT WINAPI DMSynthSinkImpl_IKsControl_KsEvent(IKsControl* iface, PKSEVENT Event, ULONG EventLength, LPVOID EventData, - ULONG DataLength, ULONG* BytesReturned) +static HRESULT WINAPI synth_sink_control_KsEvent(IKsControl* iface, PKSEVENT Event, + ULONG EventLength, LPVOID EventData, ULONG DataLength, ULONG* BytesReturned) { FIXME("(%p, %p, %lu, %p, %lu, %p): stub\n", iface, Event, EventLength, EventData, DataLength, BytesReturned); @@ -299,13 +300,14 @@ static HRESULT WINAPI DMSynthSinkImpl_IKsControl_KsEvent(IKsControl* iface, PKSE } -static const IKsControlVtbl DMSynthSinkImpl_IKsControl_Vtbl = { - DMSynthSinkImpl_IKsControl_QueryInterface, - DMSynthSinkImpl_IKsControl_AddRef, - DMSynthSinkImpl_IKsControl_Release, - DMSynthSinkImpl_IKsControl_KsProperty, - DMSynthSinkImpl_IKsControl_KsMethod, - DMSynthSinkImpl_IKsControl_KsEvent +static const IKsControlVtbl synth_sink_control = +{ + synth_sink_control_QueryInterface, + synth_sink_control_AddRef, + synth_sink_control_Release, + synth_sink_control_KsProperty, + synth_sink_control_KsMethod, + synth_sink_control_KsEvent, }; HRESULT DMUSIC_CreateDirectMusicSynthSinkImpl(REFIID riid, void **ret_iface) @@ -321,8 +323,8 @@ HRESULT DMUSIC_CreateDirectMusicSynthSinkImpl(REFIID riid, void **ret_iface) if (!obj) return E_OUTOFMEMORY; - obj->IDirectMusicSynthSink_iface.lpVtbl = &DirectMusicSynthSink_Vtbl; - obj->IKsControl_iface.lpVtbl = &DMSynthSinkImpl_IKsControl_Vtbl; + obj->IDirectMusicSynthSink_iface.lpVtbl = &synth_sink_vtbl; + obj->IKsControl_iface.lpVtbl = &synth_sink_control; obj->ref = 1; hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, &IID_IReferenceClock, (LPVOID*)&obj->latency_clock); From a90f8715c6fce1d12923428f721b5d2793b98822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 24 Aug 2023 15:29:23 +0200 Subject: [PATCH 2411/2777] dmsynth: Get rid of the IDirectMusicSynthSinkImpl typedef. (cherry picked from commit 1f990e59c002180028979e1b0373ddd7a28216fd) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synthsink.c | 44 +++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/dlls/dmsynth/synthsink.c b/dlls/dmsynth/synthsink.c index 1e72e5d1f1b..29dd524ce89 100644 --- a/dlls/dmsynth/synthsink.c +++ b/dlls/dmsynth/synthsink.c @@ -27,9 +27,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); -typedef struct IDirectMusicSynthSinkImpl IDirectMusicSynthSinkImpl; - -struct IDirectMusicSynthSinkImpl +struct synth_sink { IDirectMusicSynthSink IDirectMusicSynthSink_iface; IKsControl IKsControl_iface; @@ -41,15 +39,15 @@ struct IDirectMusicSynthSinkImpl BOOL active; }; -static inline IDirectMusicSynthSinkImpl *impl_from_IDirectMusicSynthSink(IDirectMusicSynthSink *iface) +static inline struct synth_sink *impl_from_IDirectMusicSynthSink(IDirectMusicSynthSink *iface) { - return CONTAINING_RECORD(iface, IDirectMusicSynthSinkImpl, IDirectMusicSynthSink_iface); + return CONTAINING_RECORD(iface, struct synth_sink, IDirectMusicSynthSink_iface); } static HRESULT WINAPI synth_sink_QueryInterface(IDirectMusicSynthSink *iface, REFIID riid, void **ret_iface) { - IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); + struct synth_sink *This = impl_from_IDirectMusicSynthSink(iface); TRACE("(%p)->(%s, %p)\n", iface, debugstr_dmguid(riid), ret_iface); @@ -76,7 +74,7 @@ static HRESULT WINAPI synth_sink_QueryInterface(IDirectMusicSynthSink *iface, static ULONG WINAPI synth_sink_AddRef(IDirectMusicSynthSink *iface) { - IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); + struct synth_sink *This = impl_from_IDirectMusicSynthSink(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p): new ref = %lu\n", This, ref); @@ -86,7 +84,7 @@ static ULONG WINAPI synth_sink_AddRef(IDirectMusicSynthSink *iface) static ULONG WINAPI synth_sink_Release(IDirectMusicSynthSink *iface) { - IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); + struct synth_sink *This = impl_from_IDirectMusicSynthSink(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p): new ref = %lu\n", This, ref); @@ -105,7 +103,7 @@ static ULONG WINAPI synth_sink_Release(IDirectMusicSynthSink *iface) static HRESULT WINAPI synth_sink_Init(IDirectMusicSynthSink *iface, IDirectMusicSynth *synth) { - IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); + struct synth_sink *This = impl_from_IDirectMusicSynthSink(iface); TRACE("(%p)->(%p)\n", This, synth); @@ -119,7 +117,7 @@ static HRESULT WINAPI synth_sink_Init(IDirectMusicSynthSink *iface, static HRESULT WINAPI synth_sink_SetMasterClock(IDirectMusicSynthSink *iface, IReferenceClock *clock) { - IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); + struct synth_sink *This = impl_from_IDirectMusicSynthSink(iface); TRACE("(%p)->(%p)\n", This, clock); @@ -137,7 +135,7 @@ static HRESULT WINAPI synth_sink_SetMasterClock(IDirectMusicSynthSink *iface, static HRESULT WINAPI synth_sink_GetLatencyClock(IDirectMusicSynthSink *iface, IReferenceClock **clock) { - IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); + struct synth_sink *This = impl_from_IDirectMusicSynthSink(iface); TRACE("(%p)->(%p)\n", iface, clock); @@ -153,7 +151,7 @@ static HRESULT WINAPI synth_sink_GetLatencyClock(IDirectMusicSynthSink *iface, static HRESULT WINAPI synth_sink_Activate(IDirectMusicSynthSink *iface, BOOL enable) { - IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); + struct synth_sink *This = impl_from_IDirectMusicSynthSink(iface); FIXME("(%p)->(%d): stub\n", This, enable); @@ -163,7 +161,7 @@ static HRESULT WINAPI synth_sink_Activate(IDirectMusicSynthSink *iface, static HRESULT WINAPI synth_sink_SampleToRefTime(IDirectMusicSynthSink *iface, LONGLONG sample_time, REFERENCE_TIME *ref_time) { - IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); + struct synth_sink *This = impl_from_IDirectMusicSynthSink(iface); FIXME("(%p)->(0x%s, %p): stub\n", This, wine_dbgstr_longlong(sample_time), ref_time); @@ -173,7 +171,7 @@ static HRESULT WINAPI synth_sink_SampleToRefTime(IDirectMusicSynthSink *iface, static HRESULT WINAPI synth_sink_RefTimeToSample(IDirectMusicSynthSink *iface, REFERENCE_TIME ref_time, LONGLONG *sample_time) { - IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); + struct synth_sink *This = impl_from_IDirectMusicSynthSink(iface); FIXME("(%p)->(0x%s, %p): stub\n", This, wine_dbgstr_longlong(ref_time), sample_time); @@ -183,7 +181,7 @@ static HRESULT WINAPI synth_sink_RefTimeToSample(IDirectMusicSynthSink *iface, static HRESULT WINAPI synth_sink_SetDirectSound(IDirectMusicSynthSink *iface, IDirectSound *dsound, IDirectSoundBuffer *dsound_buffer) { - IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); + struct synth_sink *This = impl_from_IDirectMusicSynthSink(iface); FIXME("(%p)->(%p, %p): stub\n", This, dsound, dsound_buffer); @@ -193,7 +191,7 @@ static HRESULT WINAPI synth_sink_SetDirectSound(IDirectMusicSynthSink *iface, static HRESULT WINAPI synth_sink_GetDesiredBufferSize(IDirectMusicSynthSink *iface, DWORD *size) { - IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface); + struct synth_sink *This = impl_from_IDirectMusicSynthSink(iface); WAVEFORMATEX format; DWORD fmtsize = sizeof(format); @@ -226,28 +224,28 @@ static const IDirectMusicSynthSinkVtbl synth_sink_vtbl = synth_sink_GetDesiredBufferSize, }; -static inline IDirectMusicSynthSinkImpl *impl_from_IKsControl(IKsControl *iface) +static inline struct synth_sink *impl_from_IKsControl(IKsControl *iface) { - return CONTAINING_RECORD(iface, IDirectMusicSynthSinkImpl, IKsControl_iface); + return CONTAINING_RECORD(iface, struct synth_sink, IKsControl_iface); } static HRESULT WINAPI synth_sink_control_QueryInterface(IKsControl* iface, REFIID riid, LPVOID *ppobj) { - IDirectMusicSynthSinkImpl *This = impl_from_IKsControl(iface); + struct synth_sink *This = impl_from_IKsControl(iface); return synth_sink_QueryInterface(&This->IDirectMusicSynthSink_iface, riid, ppobj); } static ULONG WINAPI synth_sink_control_AddRef(IKsControl* iface) { - IDirectMusicSynthSinkImpl *This = impl_from_IKsControl(iface); + struct synth_sink *This = impl_from_IKsControl(iface); return synth_sink_AddRef(&This->IDirectMusicSynthSink_iface); } static ULONG WINAPI synth_sink_control_Release(IKsControl* iface) { - IDirectMusicSynthSinkImpl *This = impl_from_IKsControl(iface); + struct synth_sink *This = impl_from_IKsControl(iface); return synth_sink_Release(&This->IDirectMusicSynthSink_iface); } @@ -312,14 +310,14 @@ static const IKsControlVtbl synth_sink_control = HRESULT DMUSIC_CreateDirectMusicSynthSinkImpl(REFIID riid, void **ret_iface) { - IDirectMusicSynthSinkImpl *obj; + struct synth_sink *obj; HRESULT hr; TRACE("(%s, %p)\n", debugstr_guid(riid), ret_iface); *ret_iface = NULL; - obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicSynthSinkImpl)); + obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct synth_sink)); if (!obj) return E_OUTOFMEMORY; From abe7ee2f0830f0d3dfe98f0624ca4eccd7d33ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 18 Aug 2023 21:34:24 +0200 Subject: [PATCH 2412/2777] dmsynth: Move IDirectMusicSynthImpl struct to where it is used. (cherry picked from commit 68b356142c67343b6a69f0a22a42edf045c0a46d) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/dmsynth_private.h | 20 -------------------- dlls/dmsynth/synth.c | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/dlls/dmsynth/dmsynth_private.h b/dlls/dmsynth/dmsynth_private.h index b9f160f000d..35c87775cf7 100644 --- a/dlls/dmsynth/dmsynth_private.h +++ b/dlls/dmsynth/dmsynth_private.h @@ -40,32 +40,12 @@ #include "dmusics.h" #include "dmksctrl.h" -/***************************************************************************** - * Interfaces - */ -typedef struct IDirectMusicSynth8Impl IDirectMusicSynth8Impl; - /***************************************************************************** * ClassFactory */ extern HRESULT DMUSIC_CreateDirectMusicSynthImpl(REFIID riid, void **ppobj); extern HRESULT DMUSIC_CreateDirectMusicSynthSinkImpl(REFIID riid, void **ppobj); -/***************************************************************************** - * IDirectMusicSynth8Impl implementation structure - */ -struct IDirectMusicSynth8Impl { - IDirectMusicSynth8 IDirectMusicSynth8_iface; - IKsControl IKsControl_iface; - LONG ref; - DMUS_PORTCAPS caps; - DMUS_PORTPARAMS params; - BOOL active; - BOOL open; - IReferenceClock *latency_clock; - IDirectMusicSynthSink *sink; -}; - /***************************************************************************** * Misc. */ diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 29aff9e988f..577cd755393 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -31,6 +31,22 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); +typedef struct IDirectMusicSynth8Impl IDirectMusicSynth8Impl; + +struct IDirectMusicSynth8Impl +{ + IDirectMusicSynth8 IDirectMusicSynth8_iface; + IKsControl IKsControl_iface; + LONG ref; + + DMUS_PORTCAPS caps; + DMUS_PORTPARAMS params; + BOOL active; + BOOL open; + IReferenceClock *latency_clock; + IDirectMusicSynthSink *sink; +}; + static inline IDirectMusicSynth8Impl *impl_from_IDirectMusicSynth8(IDirectMusicSynth8 *iface) { return CONTAINING_RECORD(iface, IDirectMusicSynth8Impl, IDirectMusicSynth8_iface); From ff2c6a1987885fd461789200b84084a9443d6c46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 18 Aug 2023 21:51:42 +0200 Subject: [PATCH 2413/2777] dmsynth: Rename IDirectMusicSynth8Impl method prefix to synth. (cherry picked from commit 011dd289e66b2d1db121ec6e21d2dfe2275b8840) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 146 ++++++++++++++++++++++--------------------- 1 file changed, 74 insertions(+), 72 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 577cd755393..fcb6892cdcd 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -52,7 +52,7 @@ static inline IDirectMusicSynth8Impl *impl_from_IDirectMusicSynth8(IDirectMusicS return CONTAINING_RECORD(iface, IDirectMusicSynth8Impl, IDirectMusicSynth8_iface); } -static HRESULT WINAPI IDirectMusicSynth8Impl_QueryInterface(IDirectMusicSynth8 *iface, REFIID riid, +static HRESULT WINAPI synth_QueryInterface(IDirectMusicSynth8 *iface, REFIID riid, void **ret_iface) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -81,7 +81,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_QueryInterface(IDirectMusicSynth8 * return E_NOINTERFACE; } -static ULONG WINAPI IDirectMusicSynth8Impl_AddRef(IDirectMusicSynth8 *iface) +static ULONG WINAPI synth_AddRef(IDirectMusicSynth8 *iface) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); ULONG ref = InterlockedIncrement(&This->ref); @@ -91,7 +91,7 @@ static ULONG WINAPI IDirectMusicSynth8Impl_AddRef(IDirectMusicSynth8 *iface) return ref; } -static ULONG WINAPI IDirectMusicSynth8Impl_Release(IDirectMusicSynth8 *iface) +static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); ULONG ref = InterlockedDecrement(&This->ref); @@ -107,7 +107,7 @@ static ULONG WINAPI IDirectMusicSynth8Impl_Release(IDirectMusicSynth8 *iface) return ref; } -static HRESULT WINAPI IDirectMusicSynth8Impl_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *params) +static HRESULT WINAPI synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *params) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); BOOL modified = FALSE; @@ -193,7 +193,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_Open(IDirectMusicSynth8 *iface, DMU return modified ? S_FALSE : S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_Close(IDirectMusicSynth8 *iface) +static HRESULT WINAPI synth_Close(IDirectMusicSynth8 *iface) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -207,7 +207,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_Close(IDirectMusicSynth8 *iface) return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_SetNumChannelGroups(IDirectMusicSynth8 *iface, +static HRESULT WINAPI synth_SetNumChannelGroups(IDirectMusicSynth8 *iface, DWORD groups) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -217,7 +217,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_SetNumChannelGroups(IDirectMusicSyn return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_Download(IDirectMusicSynth8 *iface, HANDLE *hDownload, +static HRESULT WINAPI synth_Download(IDirectMusicSynth8 *iface, HANDLE *hDownload, void *data, BOOL *free) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -352,7 +352,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_Download(IDirectMusicSynth8 *iface, return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_Unload(IDirectMusicSynth8 *iface, HANDLE hDownload, +static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE hDownload, HRESULT (CALLBACK *lpFreeHandle)(HANDLE,HANDLE), HANDLE hUserData) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -362,7 +362,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_Unload(IDirectMusicSynth8 *iface, H return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_PlayBuffer(IDirectMusicSynth8 *iface, +static HRESULT WINAPI synth_PlayBuffer(IDirectMusicSynth8 *iface, REFERENCE_TIME rt, BYTE *buffer, DWORD size) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -372,7 +372,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_PlayBuffer(IDirectMusicSynth8 *ifac return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_GetRunningStats(IDirectMusicSynth8 *iface, +static HRESULT WINAPI synth_GetRunningStats(IDirectMusicSynth8 *iface, DMUS_SYNTHSTATS *stats) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -382,7 +382,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_GetRunningStats(IDirectMusicSynth8 return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_GetPortCaps(IDirectMusicSynth8 *iface, +static HRESULT WINAPI synth_GetPortCaps(IDirectMusicSynth8 *iface, DMUS_PORTCAPS *caps) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -397,7 +397,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_GetPortCaps(IDirectMusicSynth8 *ifa return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_SetMasterClock(IDirectMusicSynth8 *iface, +static HRESULT WINAPI synth_SetMasterClock(IDirectMusicSynth8 *iface, IReferenceClock *clock) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -410,7 +410,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_SetMasterClock(IDirectMusicSynth8 * return IDirectMusicSynthSink_SetMasterClock(This->sink, clock); } -static HRESULT WINAPI IDirectMusicSynth8Impl_GetLatencyClock(IDirectMusicSynth8 *iface, +static HRESULT WINAPI synth_GetLatencyClock(IDirectMusicSynth8 *iface, IReferenceClock **clock) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -429,7 +429,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_GetLatencyClock(IDirectMusicSynth8 return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_Activate(IDirectMusicSynth8 *iface, BOOL enable) +static HRESULT WINAPI synth_Activate(IDirectMusicSynth8 *iface, BOOL enable) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); HRESULT hr; @@ -458,7 +458,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_Activate(IDirectMusicSynth8 *iface, return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_SetSynthSink(IDirectMusicSynth8 *iface, +static HRESULT WINAPI synth_SetSynthSink(IDirectMusicSynth8 *iface, IDirectMusicSynthSink *sink) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -486,7 +486,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_SetSynthSink(IDirectMusicSynth8 *if return IDirectMusicSynthSink_GetLatencyClock(sink, &This->latency_clock); } -static HRESULT WINAPI IDirectMusicSynth8Impl_Render(IDirectMusicSynth8 *iface, short *buffer, +static HRESULT WINAPI synth_Render(IDirectMusicSynth8 *iface, short *buffer, DWORD length, LONGLONG position) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -496,7 +496,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_Render(IDirectMusicSynth8 *iface, s return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_SetChannelPriority(IDirectMusicSynth8 *iface, +static HRESULT WINAPI synth_SetChannelPriority(IDirectMusicSynth8 *iface, DWORD channel_group, DWORD channel, DWORD priority) { /* IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); */ @@ -507,7 +507,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_SetChannelPriority(IDirectMusicSynt return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_GetChannelPriority(IDirectMusicSynth8 *iface, +static HRESULT WINAPI synth_GetChannelPriority(IDirectMusicSynth8 *iface, DWORD channel_group, DWORD channel, DWORD *priority) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -517,7 +517,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_GetChannelPriority(IDirectMusicSynt return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_GetFormat(IDirectMusicSynth8 *iface, +static HRESULT WINAPI synth_GetFormat(IDirectMusicSynth8 *iface, WAVEFORMATEX *format, DWORD *size) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -545,7 +545,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_GetFormat(IDirectMusicSynth8 *iface return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_GetAppend(IDirectMusicSynth8 *iface, DWORD *append) +static HRESULT WINAPI synth_GetAppend(IDirectMusicSynth8 *iface, DWORD *append) { TRACE("(%p)->(%p)\n", iface, append); @@ -555,7 +555,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_GetAppend(IDirectMusicSynth8 *iface return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_PlayVoice(IDirectMusicSynth8 *iface, +static HRESULT WINAPI synth_PlayVoice(IDirectMusicSynth8 *iface, REFERENCE_TIME ref_time, DWORD voice_id, DWORD channel_group, DWORD channel, DWORD dwDLId, LONG prPitch, LONG vrVolume, SAMPLE_TIME stVoiceStart, SAMPLE_TIME stLoopStart, SAMPLE_TIME stLoopEnd) @@ -569,7 +569,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_PlayVoice(IDirectMusicSynth8 *iface return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_StopVoice(IDirectMusicSynth8 *iface, +static HRESULT WINAPI synth_StopVoice(IDirectMusicSynth8 *iface, REFERENCE_TIME ref_time, DWORD voice_id) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -579,7 +579,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_StopVoice(IDirectMusicSynth8 *iface return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_GetVoiceState(IDirectMusicSynth8 *iface, +static HRESULT WINAPI synth_GetVoiceState(IDirectMusicSynth8 *iface, DWORD dwVoice[], DWORD cbVoice, DMUS_VOICE_STATE dwVoiceState[]) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -589,7 +589,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_GetVoiceState(IDirectMusicSynth8 *i return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_Refresh(IDirectMusicSynth8 *iface, DWORD download_id, +static HRESULT WINAPI synth_Refresh(IDirectMusicSynth8 *iface, DWORD download_id, DWORD flags) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -599,7 +599,7 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_Refresh(IDirectMusicSynth8 *iface, return S_OK; } -static HRESULT WINAPI IDirectMusicSynth8Impl_AssignChannelToBuses(IDirectMusicSynth8 *iface, +static HRESULT WINAPI synth_AssignChannelToBuses(IDirectMusicSynth8 *iface, DWORD channel_group, DWORD channel, DWORD *pdwBuses, DWORD cBuses) { IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); @@ -609,32 +609,33 @@ static HRESULT WINAPI IDirectMusicSynth8Impl_AssignChannelToBuses(IDirectMusicSy return S_OK; } -static const IDirectMusicSynth8Vtbl DirectMusicSynth8_Vtbl = { - IDirectMusicSynth8Impl_QueryInterface, - IDirectMusicSynth8Impl_AddRef, - IDirectMusicSynth8Impl_Release, - IDirectMusicSynth8Impl_Open, - IDirectMusicSynth8Impl_Close, - IDirectMusicSynth8Impl_SetNumChannelGroups, - IDirectMusicSynth8Impl_Download, - IDirectMusicSynth8Impl_Unload, - IDirectMusicSynth8Impl_PlayBuffer, - IDirectMusicSynth8Impl_GetRunningStats, - IDirectMusicSynth8Impl_GetPortCaps, - IDirectMusicSynth8Impl_SetMasterClock, - IDirectMusicSynth8Impl_GetLatencyClock, - IDirectMusicSynth8Impl_Activate, - IDirectMusicSynth8Impl_SetSynthSink, - IDirectMusicSynth8Impl_Render, - IDirectMusicSynth8Impl_SetChannelPriority, - IDirectMusicSynth8Impl_GetChannelPriority, - IDirectMusicSynth8Impl_GetFormat, - IDirectMusicSynth8Impl_GetAppend, - IDirectMusicSynth8Impl_PlayVoice, - IDirectMusicSynth8Impl_StopVoice, - IDirectMusicSynth8Impl_GetVoiceState, - IDirectMusicSynth8Impl_Refresh, - IDirectMusicSynth8Impl_AssignChannelToBuses +static const IDirectMusicSynth8Vtbl synth_vtbl = +{ + synth_QueryInterface, + synth_AddRef, + synth_Release, + synth_Open, + synth_Close, + synth_SetNumChannelGroups, + synth_Download, + synth_Unload, + synth_PlayBuffer, + synth_GetRunningStats, + synth_GetPortCaps, + synth_SetMasterClock, + synth_GetLatencyClock, + synth_Activate, + synth_SetSynthSink, + synth_Render, + synth_SetChannelPriority, + synth_GetChannelPriority, + synth_GetFormat, + synth_GetAppend, + synth_PlayVoice, + synth_StopVoice, + synth_GetVoiceState, + synth_Refresh, + synth_AssignChannelToBuses, }; static inline IDirectMusicSynth8Impl *impl_from_IKsControl(IKsControl *iface) @@ -642,29 +643,29 @@ static inline IDirectMusicSynth8Impl *impl_from_IKsControl(IKsControl *iface) return CONTAINING_RECORD(iface, IDirectMusicSynth8Impl, IKsControl_iface); } -static HRESULT WINAPI DMSynthImpl_IKsControl_QueryInterface(IKsControl* iface, REFIID riid, LPVOID *ppobj) +static HRESULT WINAPI synth_control_QueryInterface(IKsControl* iface, REFIID riid, LPVOID *ppobj) { IDirectMusicSynth8Impl *This = impl_from_IKsControl(iface); - return IDirectMusicSynth8Impl_QueryInterface(&This->IDirectMusicSynth8_iface, riid, ppobj); + return synth_QueryInterface(&This->IDirectMusicSynth8_iface, riid, ppobj); } -static ULONG WINAPI DMSynthImpl_IKsControl_AddRef(IKsControl* iface) +static ULONG WINAPI synth_control_AddRef(IKsControl* iface) { IDirectMusicSynth8Impl *This = impl_from_IKsControl(iface); - return IDirectMusicSynth8Impl_AddRef(&This->IDirectMusicSynth8_iface); + return synth_AddRef(&This->IDirectMusicSynth8_iface); } -static ULONG WINAPI DMSynthImpl_IKsControl_Release(IKsControl* iface) +static ULONG WINAPI synth_control_Release(IKsControl* iface) { IDirectMusicSynth8Impl *This = impl_from_IKsControl(iface); - return IDirectMusicSynth8Impl_Release(&This->IDirectMusicSynth8_iface); + return synth_Release(&This->IDirectMusicSynth8_iface); } -static HRESULT WINAPI DMSynthImpl_IKsControl_KsProperty(IKsControl* iface, PKSPROPERTY Property, ULONG PropertyLength, LPVOID PropertyData, - ULONG DataLength, ULONG* BytesReturned) +static HRESULT WINAPI synth_control_KsProperty(IKsControl* iface, PKSPROPERTY Property, + ULONG PropertyLength, LPVOID PropertyData, ULONG DataLength, ULONG* BytesReturned) { TRACE("(%p, %p, %lu, %p, %lu, %p)\n", iface, Property, PropertyLength, PropertyData, DataLength, BytesReturned); @@ -714,16 +715,16 @@ static HRESULT WINAPI DMSynthImpl_IKsControl_KsProperty(IKsControl* iface, PKSPR return S_OK; } -static HRESULT WINAPI DMSynthImpl_IKsControl_KsMethod(IKsControl* iface, PKSMETHOD Method, ULONG MethodLength, LPVOID MethodData, - ULONG DataLength, ULONG* BytesReturned) +static HRESULT WINAPI synth_control_KsMethod(IKsControl* iface, PKSMETHOD Method, + ULONG MethodLength, LPVOID MethodData, ULONG DataLength, ULONG* BytesReturned) { FIXME("(%p, %p, %lu, %p, %lu, %p): stub\n", iface, Method, MethodLength, MethodData, DataLength, BytesReturned); return E_NOTIMPL; } -static HRESULT WINAPI DMSynthImpl_IKsControl_KsEvent(IKsControl* iface, PKSEVENT Event, ULONG EventLength, LPVOID EventData, - ULONG DataLength, ULONG* BytesReturned) +static HRESULT WINAPI synth_control_KsEvent(IKsControl* iface, PKSEVENT Event, + ULONG EventLength, LPVOID EventData, ULONG DataLength, ULONG* BytesReturned) { FIXME("(%p, %p, %lu, %p, %lu, %p): stub\n", iface, Event, EventLength, EventData, DataLength, BytesReturned); @@ -731,13 +732,14 @@ static HRESULT WINAPI DMSynthImpl_IKsControl_KsEvent(IKsControl* iface, PKSEVENT } -static const IKsControlVtbl DMSynthImpl_IKsControl_Vtbl = { - DMSynthImpl_IKsControl_QueryInterface, - DMSynthImpl_IKsControl_AddRef, - DMSynthImpl_IKsControl_Release, - DMSynthImpl_IKsControl_KsProperty, - DMSynthImpl_IKsControl_KsMethod, - DMSynthImpl_IKsControl_KsEvent +static const IKsControlVtbl synth_control_vtbl = +{ + synth_control_QueryInterface, + synth_control_AddRef, + synth_control_Release, + synth_control_KsProperty, + synth_control_KsMethod, + synth_control_KsEvent, }; HRESULT DMUSIC_CreateDirectMusicSynthImpl(REFIID riid, void **ppobj) @@ -752,8 +754,8 @@ HRESULT DMUSIC_CreateDirectMusicSynthImpl(REFIID riid, void **ppobj) *ppobj = NULL; return E_OUTOFMEMORY; } - obj->IDirectMusicSynth8_iface.lpVtbl = &DirectMusicSynth8_Vtbl; - obj->IKsControl_iface.lpVtbl = &DMSynthImpl_IKsControl_Vtbl; + obj->IDirectMusicSynth8_iface.lpVtbl = &synth_vtbl; + obj->IKsControl_iface.lpVtbl = &synth_control_vtbl; obj->ref = 1; /* fill in caps */ obj->caps.dwSize = sizeof(DMUS_PORTCAPS); From 8e0a6223125f18d0c11fec7489e4be8bb25a242c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 24 Aug 2023 15:30:25 +0200 Subject: [PATCH 2414/2777] dmsynth: Get rid of the IDirectMusicSynth8Impl typedef. (cherry picked from commit 5e29d14789407a49576ad7be296bbd80b3ff773f) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 68 +++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index fcb6892cdcd..79bf9f3bf92 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -31,9 +31,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); -typedef struct IDirectMusicSynth8Impl IDirectMusicSynth8Impl; - -struct IDirectMusicSynth8Impl +struct synth { IDirectMusicSynth8 IDirectMusicSynth8_iface; IKsControl IKsControl_iface; @@ -47,15 +45,15 @@ struct IDirectMusicSynth8Impl IDirectMusicSynthSink *sink; }; -static inline IDirectMusicSynth8Impl *impl_from_IDirectMusicSynth8(IDirectMusicSynth8 *iface) +static inline struct synth *impl_from_IDirectMusicSynth8(IDirectMusicSynth8 *iface) { - return CONTAINING_RECORD(iface, IDirectMusicSynth8Impl, IDirectMusicSynth8_iface); + return CONTAINING_RECORD(iface, struct synth, IDirectMusicSynth8_iface); } static HRESULT WINAPI synth_QueryInterface(IDirectMusicSynth8 *iface, REFIID riid, void **ret_iface) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); TRACE("(%p)->(%s, %p)\n", iface, debugstr_dmguid(riid), ret_iface); @@ -83,7 +81,7 @@ static HRESULT WINAPI synth_QueryInterface(IDirectMusicSynth8 *iface, REFIID rii static ULONG WINAPI synth_AddRef(IDirectMusicSynth8 *iface) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p): new ref = %lu\n", This, ref); @@ -93,7 +91,7 @@ static ULONG WINAPI synth_AddRef(IDirectMusicSynth8 *iface) static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p): new ref = %lu\n", This, ref); @@ -109,7 +107,7 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) static HRESULT WINAPI synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *params) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); BOOL modified = FALSE; const DMUS_PORTPARAMS def = { .dwValidParams = DMUS_PORTPARAMS_VOICES|DMUS_PORTPARAMS_CHANNELGROUPS| @@ -195,7 +193,7 @@ static HRESULT WINAPI synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *par static HRESULT WINAPI synth_Close(IDirectMusicSynth8 *iface) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); TRACE("(%p)\n", This); @@ -210,7 +208,7 @@ static HRESULT WINAPI synth_Close(IDirectMusicSynth8 *iface) static HRESULT WINAPI synth_SetNumChannelGroups(IDirectMusicSynth8 *iface, DWORD groups) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); FIXME("(%p, %ld): stub\n", This, groups); @@ -220,7 +218,7 @@ static HRESULT WINAPI synth_SetNumChannelGroups(IDirectMusicSynth8 *iface, static HRESULT WINAPI synth_Download(IDirectMusicSynth8 *iface, HANDLE *hDownload, void *data, BOOL *free) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); LPBYTE buffer = data; DMUS_DOWNLOADINFO *info = (DMUS_DOWNLOADINFO*)buffer; ULONG *offsets = ((DMUS_OFFSETTABLE*)(buffer + sizeof(DMUS_DOWNLOADINFO)))->ulOffsetTable; @@ -355,7 +353,7 @@ static HRESULT WINAPI synth_Download(IDirectMusicSynth8 *iface, HANDLE *hDownloa static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE hDownload, HRESULT (CALLBACK *lpFreeHandle)(HANDLE,HANDLE), HANDLE hUserData) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); FIXME("(%p)->(%p, %p, %p): stub\n", This, hDownload, lpFreeHandle, hUserData); @@ -365,7 +363,7 @@ static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE hDownload, static HRESULT WINAPI synth_PlayBuffer(IDirectMusicSynth8 *iface, REFERENCE_TIME rt, BYTE *buffer, DWORD size) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); FIXME("(%p, 0x%s, %p, %lu): stub\n", This, wine_dbgstr_longlong(rt), buffer, size); @@ -375,7 +373,7 @@ static HRESULT WINAPI synth_PlayBuffer(IDirectMusicSynth8 *iface, static HRESULT WINAPI synth_GetRunningStats(IDirectMusicSynth8 *iface, DMUS_SYNTHSTATS *stats) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); FIXME("(%p)->(%p): stub\n", This, stats); @@ -385,7 +383,7 @@ static HRESULT WINAPI synth_GetRunningStats(IDirectMusicSynth8 *iface, static HRESULT WINAPI synth_GetPortCaps(IDirectMusicSynth8 *iface, DMUS_PORTCAPS *caps) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); TRACE("(%p)->(%p)\n", This, caps); @@ -400,7 +398,7 @@ static HRESULT WINAPI synth_GetPortCaps(IDirectMusicSynth8 *iface, static HRESULT WINAPI synth_SetMasterClock(IDirectMusicSynth8 *iface, IReferenceClock *clock) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); TRACE("(%p)->(%p)\n", This, clock); @@ -413,7 +411,7 @@ static HRESULT WINAPI synth_SetMasterClock(IDirectMusicSynth8 *iface, static HRESULT WINAPI synth_GetLatencyClock(IDirectMusicSynth8 *iface, IReferenceClock **clock) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); TRACE("(%p)->(%p)\n", iface, clock); @@ -431,7 +429,7 @@ static HRESULT WINAPI synth_GetLatencyClock(IDirectMusicSynth8 *iface, static HRESULT WINAPI synth_Activate(IDirectMusicSynth8 *iface, BOOL enable) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); HRESULT hr; TRACE("(%p)->(%d)\n", This, enable); @@ -461,7 +459,7 @@ static HRESULT WINAPI synth_Activate(IDirectMusicSynth8 *iface, BOOL enable) static HRESULT WINAPI synth_SetSynthSink(IDirectMusicSynth8 *iface, IDirectMusicSynthSink *sink) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); HRESULT hr; TRACE("(%p)->(%p)\n", iface, sink); @@ -489,7 +487,7 @@ static HRESULT WINAPI synth_SetSynthSink(IDirectMusicSynth8 *iface, static HRESULT WINAPI synth_Render(IDirectMusicSynth8 *iface, short *buffer, DWORD length, LONGLONG position) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); FIXME("(%p, %p, %ld, 0x%s): stub\n", This, buffer, length, wine_dbgstr_longlong(position)); @@ -499,7 +497,7 @@ static HRESULT WINAPI synth_Render(IDirectMusicSynth8 *iface, short *buffer, static HRESULT WINAPI synth_SetChannelPriority(IDirectMusicSynth8 *iface, DWORD channel_group, DWORD channel, DWORD priority) { - /* IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); */ + /* struct synth *This = impl_from_IDirectMusicSynth8(iface); */ /* Silenced because of too many messages - 1000 groups * 16 channels ;=) */ /* FIXME("(%p)->(%ld, %ld, %ld): stub\n", This, channel_group, channel, priority); */ @@ -510,7 +508,7 @@ static HRESULT WINAPI synth_SetChannelPriority(IDirectMusicSynth8 *iface, static HRESULT WINAPI synth_GetChannelPriority(IDirectMusicSynth8 *iface, DWORD channel_group, DWORD channel, DWORD *priority) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); FIXME("(%p, %ld, %ld, %p): stub\n", This, channel_group, channel, priority); @@ -520,7 +518,7 @@ static HRESULT WINAPI synth_GetChannelPriority(IDirectMusicSynth8 *iface, static HRESULT WINAPI synth_GetFormat(IDirectMusicSynth8 *iface, WAVEFORMATEX *format, DWORD *size) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); WAVEFORMATEX fmt; TRACE("(%p, %p, %p)\n", This, format, size); @@ -560,7 +558,7 @@ static HRESULT WINAPI synth_PlayVoice(IDirectMusicSynth8 *iface, LONG prPitch, LONG vrVolume, SAMPLE_TIME stVoiceStart, SAMPLE_TIME stLoopStart, SAMPLE_TIME stLoopEnd) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); FIXME("(%p, 0x%s, %ld, %ld, %ld, %ld, %li, %li, 0x%s, 0x%s, 0x%s): stub\n", This, wine_dbgstr_longlong(ref_time), voice_id, channel_group, channel, dwDLId, prPitch, vrVolume, @@ -572,7 +570,7 @@ static HRESULT WINAPI synth_PlayVoice(IDirectMusicSynth8 *iface, static HRESULT WINAPI synth_StopVoice(IDirectMusicSynth8 *iface, REFERENCE_TIME ref_time, DWORD voice_id) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); FIXME("(%p, 0x%s, %ld): stub\n", This, wine_dbgstr_longlong(ref_time), voice_id); @@ -582,7 +580,7 @@ static HRESULT WINAPI synth_StopVoice(IDirectMusicSynth8 *iface, static HRESULT WINAPI synth_GetVoiceState(IDirectMusicSynth8 *iface, DWORD dwVoice[], DWORD cbVoice, DMUS_VOICE_STATE dwVoiceState[]) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); FIXME("(%p, %p, %ld, %p): stub\n", This, dwVoice, cbVoice, dwVoiceState); @@ -592,7 +590,7 @@ static HRESULT WINAPI synth_GetVoiceState(IDirectMusicSynth8 *iface, static HRESULT WINAPI synth_Refresh(IDirectMusicSynth8 *iface, DWORD download_id, DWORD flags) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); FIXME("(%p, %ld, %ld): stub\n", This, download_id, flags); @@ -602,7 +600,7 @@ static HRESULT WINAPI synth_Refresh(IDirectMusicSynth8 *iface, DWORD download_id static HRESULT WINAPI synth_AssignChannelToBuses(IDirectMusicSynth8 *iface, DWORD channel_group, DWORD channel, DWORD *pdwBuses, DWORD cBuses) { - IDirectMusicSynth8Impl *This = impl_from_IDirectMusicSynth8(iface); + struct synth *This = impl_from_IDirectMusicSynth8(iface); FIXME("(%p, %ld, %ld, %p, %ld): stub\n", This, channel_group, channel, pdwBuses, cBuses); @@ -638,28 +636,28 @@ static const IDirectMusicSynth8Vtbl synth_vtbl = synth_AssignChannelToBuses, }; -static inline IDirectMusicSynth8Impl *impl_from_IKsControl(IKsControl *iface) +static inline struct synth *impl_from_IKsControl(IKsControl *iface) { - return CONTAINING_RECORD(iface, IDirectMusicSynth8Impl, IKsControl_iface); + return CONTAINING_RECORD(iface, struct synth, IKsControl_iface); } static HRESULT WINAPI synth_control_QueryInterface(IKsControl* iface, REFIID riid, LPVOID *ppobj) { - IDirectMusicSynth8Impl *This = impl_from_IKsControl(iface); + struct synth *This = impl_from_IKsControl(iface); return synth_QueryInterface(&This->IDirectMusicSynth8_iface, riid, ppobj); } static ULONG WINAPI synth_control_AddRef(IKsControl* iface) { - IDirectMusicSynth8Impl *This = impl_from_IKsControl(iface); + struct synth *This = impl_from_IKsControl(iface); return synth_AddRef(&This->IDirectMusicSynth8_iface); } static ULONG WINAPI synth_control_Release(IKsControl* iface) { - IDirectMusicSynth8Impl *This = impl_from_IKsControl(iface); + struct synth *This = impl_from_IKsControl(iface); return synth_Release(&This->IDirectMusicSynth8_iface); } @@ -744,7 +742,7 @@ static const IKsControlVtbl synth_control_vtbl = HRESULT DMUSIC_CreateDirectMusicSynthImpl(REFIID riid, void **ppobj) { - IDirectMusicSynth8Impl *obj; + struct synth *obj; HRESULT hr; TRACE("(%s, %p)\n", debugstr_guid(riid), ppobj); From 4342c4860aa864fe6e181ae3e71af01bcbb03623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 29 Aug 2023 15:19:11 +0200 Subject: [PATCH 2415/2777] dmsynth: Use CRT allocation functions. (cherry picked from commit 6dedfec9c323dafe6d6bab33fee68c12606d6466) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 9 +++------ dlls/dmsynth/synthsink.c | 9 +++------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 79bf9f3bf92..fecbe21c2e3 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -99,7 +99,7 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) if (!ref) { if (This->latency_clock) IReferenceClock_Release(This->latency_clock); - HeapFree(GetProcessHeap(), 0, This); + free(This); } return ref; @@ -747,11 +747,8 @@ HRESULT DMUSIC_CreateDirectMusicSynthImpl(REFIID riid, void **ppobj) TRACE("(%s, %p)\n", debugstr_guid(riid), ppobj); - obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj)); - if (NULL == obj) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicSynth8_iface.lpVtbl = &synth_vtbl; obj->IKsControl_iface.lpVtbl = &synth_control_vtbl; obj->ref = 1; diff --git a/dlls/dmsynth/synthsink.c b/dlls/dmsynth/synthsink.c index 29dd524ce89..2200abd93b1 100644 --- a/dlls/dmsynth/synthsink.c +++ b/dlls/dmsynth/synthsink.c @@ -94,7 +94,7 @@ static ULONG WINAPI synth_sink_Release(IDirectMusicSynthSink *iface) IReferenceClock_Release(This->latency_clock); if (This->master_clock) IReferenceClock_Release(This->master_clock); - HeapFree(GetProcessHeap(), 0, This); + free(This); } return ref; @@ -317,10 +317,7 @@ HRESULT DMUSIC_CreateDirectMusicSynthSinkImpl(REFIID riid, void **ret_iface) *ret_iface = NULL; - obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct synth_sink)); - if (!obj) - return E_OUTOFMEMORY; - + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicSynthSink_iface.lpVtbl = &synth_sink_vtbl; obj->IKsControl_iface.lpVtbl = &synth_sink_control; obj->ref = 1; @@ -328,7 +325,7 @@ HRESULT DMUSIC_CreateDirectMusicSynthSinkImpl(REFIID riid, void **ret_iface) hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, &IID_IReferenceClock, (LPVOID*)&obj->latency_clock); if (FAILED(hr)) { - HeapFree(GetProcessHeap(), 0, obj); + free(obj); return hr; } From 51c862389c7e8c06649178c6d147ffa081c41f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 24 Aug 2023 15:59:50 +0200 Subject: [PATCH 2416/2777] dmsynth/tests: Avoid dynamic format string. (cherry picked from commit 40dcb5954bf9ff6161222ce703c6fc60a22c6b53) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/tests/dmsynth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index a8bf65cd73e..77c11dadd27 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -57,7 +57,7 @@ static void test_synth_getformat(IDirectMusicSynth *synth, DMUS_PORTPARAMS *para DWORD size; HRESULT hr; - winetest_push_context(context); + winetest_push_context("%s", context); size = sizeof(format); hr = IDirectMusicSynth_GetFormat(synth, &format, &size); From 7776963d4836290df2c5761bd6415fc9b6ac8fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 10 Aug 2023 16:00:22 +0200 Subject: [PATCH 2417/2777] dmsynth/tests: Import and use a check_interface helper. (cherry picked from commit e477e3e30daf1c78c28c39b1c7948e12f84fce7d) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/tests/dmsynth.c | 72 ++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 41 deletions(-) diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index 77c11dadd27..99b03f63847 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -51,6 +51,27 @@ static ULONG get_refcount(void *iface) return IUnknown_Release(unknown); } +#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) +static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported) +{ + ULONG expect_ref = get_refcount(iface_ptr); + IUnknown *iface = iface_ptr; + HRESULT hr, expected; + IUnknown *unk; + + expected = supported ? S_OK : E_NOINTERFACE; + hr = IUnknown_QueryInterface(iface, iid, (void **)&unk); + ok_(__FILE__, line)(hr == expected, "got hr %#lx, expected %#lx.\n", hr, expected); + if (SUCCEEDED(hr)) + { + LONG ref = get_refcount(unk); + ok_(__FILE__, line)(ref == expect_ref + 1, "got %ld\n", ref); + IUnknown_Release(unk); + ref = get_refcount(iface_ptr); + ok_(__FILE__, line)(ref == expect_ref, "got %ld\n", ref); + } +} + static void test_synth_getformat(IDirectMusicSynth *synth, DMUS_PORTPARAMS *params, const char *context) { WAVEFORMATEX format; @@ -317,9 +338,6 @@ static void test_dmsynth(void) static void test_COM(void) { IDirectMusicSynth8 *dms8 = (IDirectMusicSynth8*)0xdeadbeef; - IKsControl *iksc; - IUnknown *unk; - ULONG refcount; HRESULT hr; /* COM aggregation */ @@ -334,40 +352,23 @@ static void test_COM(void) &IID_IDirectMusicObject, (void**)&dms8); ok(hr == E_NOINTERFACE, "DirectMusicSynth create failed: %#lx, expected E_NOINTERFACE\n", hr); - /* Same refcount for all DirectMusicSynth interfaces */ hr = CoCreateInstance(&CLSID_DirectMusicSynth, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicSynth8, (void**)&dms8); ok(hr == S_OK, "DirectMusicSynth create failed: %#lx, expected S_OK\n", hr); - refcount = IDirectMusicSynth8_AddRef(dms8); - ok(refcount == 2, "refcount == %lu, expected 2\n", refcount); - - hr = IDirectMusicSynth8_QueryInterface(dms8, &IID_IKsControl, (void**)&iksc); - ok(hr == S_OK, "QueryInterface for IID_IKsControl failed: %#lx\n", hr); - refcount = IKsControl_AddRef(iksc); - ok(refcount == 4, "refcount == %lu, expected 4\n", refcount); - IKsControl_Release(iksc); - hr = IDirectMusicSynth8_QueryInterface(dms8, &IID_IUnknown, (void**)&unk); - ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr); - refcount = IUnknown_AddRef(unk); - ok(refcount == 5, "refcount == %lu, expected 5\n", refcount); - IUnknown_Release(unk); + check_interface(dms8, &IID_IUnknown, TRUE); + check_interface(dms8, &IID_IKsControl, TRUE); /* Unsupported interfaces */ - hr = IDirectMusicSynth8_QueryInterface(dms8, &IID_IDirectMusicSynthSink, (void**)&unk); - ok(hr == E_NOINTERFACE, "QueryInterface for IID_IDirectMusicSynthSink failed: %#lx\n", hr); - hr = IDirectMusicSynth8_QueryInterface(dms8, &IID_IReferenceClock, (void**)&unk); - ok(hr == E_NOINTERFACE, "QueryInterface for IID_IReferenceClock failed: %#lx\n", hr); + check_interface(dms8, &IID_IDirectMusicSynthSink, FALSE); + check_interface(dms8, &IID_IReferenceClock, FALSE); - while (IDirectMusicSynth8_Release(dms8)); + IDirectMusicSynth8_Release(dms8); } static void test_COM_synthsink(void) { IDirectMusicSynthSink *dmss = (IDirectMusicSynthSink*)0xdeadbeef; - IKsControl *iksc; - IUnknown *unk; - ULONG refcount; HRESULT hr; /* COM aggregation */ @@ -386,27 +387,16 @@ static void test_COM_synthsink(void) hr = CoCreateInstance(&CLSID_DirectMusicSynthSink, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicSynthSink, (void**)&dmss); ok(hr == S_OK, "DirectMusicSynthSink create failed: %#lx, expected S_OK\n", hr); - refcount = IDirectMusicSynthSink_AddRef(dmss); - ok(refcount == 2, "refcount == %lu, expected 2\n", refcount); - - hr = IDirectMusicSynthSink_QueryInterface(dmss, &IID_IKsControl, (void**)&iksc); - ok(hr == S_OK, "QueryInterface for IID_IKsControl failed: %#lx\n", hr); - refcount = IKsControl_AddRef(iksc); - ok(refcount == 4, "refcount == %lu, expected 4\n", refcount); - IKsControl_Release(iksc); - hr = IDirectMusicSynthSink_QueryInterface(dmss, &IID_IUnknown, (void**)&unk); - ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %#lx\n", hr); - refcount = IUnknown_AddRef(unk); - ok(refcount == 5, "refcount == %lu, expected 5\n", refcount); - IUnknown_Release(unk); + check_interface(dmss, &IID_IUnknown, TRUE); + check_interface(dmss, &IID_IKsControl, TRUE); /* Unsupported interfaces */ - hr = IDirectMusicSynthSink_QueryInterface(dmss, &IID_IReferenceClock, (void**)&unk); - ok(hr == E_NOINTERFACE, "QueryInterface for IID_IReferenceClock failed: %#lx\n", hr); + check_interface(dmss, &IID_IReferenceClock, FALSE); - while (IDirectMusicSynthSink_Release(dmss)); + IDirectMusicSynthSink_Release(dmss); } + START_TEST(dmsynth) { CoInitializeEx(NULL, COINIT_MULTITHREADED); From 624cdd266516e915792ded7c2abd89fd1672fb88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 27 Aug 2023 13:54:19 +0200 Subject: [PATCH 2418/2777] dmsynth/tests: Test DirectMusicSynthSink class in isolation. (cherry picked from commit a2dac48f6c6f75da2f0bb3d7a374b58f2ef9fb45) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/tests/Makefile.in | 2 +- dlls/dmsynth/tests/dmsynth.c | 387 +++++++++++++++++++++++++++++++++ 2 files changed, 388 insertions(+), 1 deletion(-) diff --git a/dlls/dmsynth/tests/Makefile.in b/dlls/dmsynth/tests/Makefile.in index 5f2fce7b8b1..1119bb09ce7 100644 --- a/dlls/dmsynth/tests/Makefile.in +++ b/dlls/dmsynth/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = dmsynth.dll -IMPORTS = oleaut32 ole32 uuid +IMPORTS = oleaut32 ole32 uuid dsound user32 C_SRCS = \ dmsynth.c diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index 99b03f63847..c8976f50e21 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -72,6 +72,217 @@ static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOO } } +struct test_synth +{ + IDirectMusicSynth8 IDirectMusicSynth8_iface; + LONG refcount; +}; + +static HRESULT WINAPI test_synth_QueryInterface(IDirectMusicSynth8 *iface, REFIID riid, void **ret_iface) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static ULONG WINAPI test_synth_AddRef(IDirectMusicSynth8 *iface) +{ + struct test_synth *sink = CONTAINING_RECORD(iface, struct test_synth, IDirectMusicSynth8_iface); + return InterlockedIncrement(&sink->refcount); +} + +static ULONG WINAPI test_synth_Release(IDirectMusicSynth8 *iface) +{ + struct test_synth *sink = CONTAINING_RECORD(iface, struct test_synth, IDirectMusicSynth8_iface); + ULONG ref = InterlockedDecrement(&sink->refcount); + if (!ref) free(sink); + return ref; +} + +static HRESULT WINAPI test_synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *params) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_Close(IDirectMusicSynth8 *iface) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_SetNumChannelGroups(IDirectMusicSynth8 *iface, DWORD groups) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_Download(IDirectMusicSynth8 *iface, HANDLE *handle, void *data, BOOL *can_free) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_Unload(IDirectMusicSynth8 *iface, HANDLE handle, + HRESULT (CALLBACK *free_callback)(HANDLE,HANDLE), HANDLE user_data) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_PlayBuffer(IDirectMusicSynth8 *iface, REFERENCE_TIME time, BYTE *buffer, DWORD size) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_GetRunningStats(IDirectMusicSynth8 *iface, DMUS_SYNTHSTATS *stats) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_GetPortCaps(IDirectMusicSynth8 *iface, DMUS_PORTCAPS *caps) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_SetMasterClock(IDirectMusicSynth8 *iface, IReferenceClock *clock) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_GetLatencyClock(IDirectMusicSynth8 *iface, IReferenceClock **clock) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_Activate(IDirectMusicSynth8 *iface, BOOL enable) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_SetSynthSink(IDirectMusicSynth8 *iface, IDirectMusicSynthSink *sink) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_Render(IDirectMusicSynth8 *iface, short *buffer, DWORD length, LONGLONG position) +{ + return S_OK; +} + +static HRESULT WINAPI test_synth_SetChannelPriority(IDirectMusicSynth8 *iface, DWORD group, DWORD channel, DWORD priority) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_GetChannelPriority(IDirectMusicSynth8 *iface, DWORD group, DWORD channel, DWORD *priority) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_GetFormat(IDirectMusicSynth8 *iface, WAVEFORMATEX *format, DWORD *ext_size) +{ + *ext_size = 0; + memset(format, 0, sizeof(*format)); + format->wFormatTag = WAVE_FORMAT_PCM; + format->nChannels = 2; + format->wBitsPerSample = 16; + format->nSamplesPerSec = 44100; + format->nBlockAlign = format->nChannels * format->wBitsPerSample / 8; + format->nAvgBytesPerSec = format->nSamplesPerSec * format->nBlockAlign; + return S_OK; +} + +static HRESULT WINAPI test_synth_GetAppend(IDirectMusicSynth8 *iface, DWORD *append) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_PlayVoice(IDirectMusicSynth8 *iface, REFERENCE_TIME rt, DWORD voice_id, + DWORD group, DWORD channel, DWORD dlid, LONG pitch, LONG volume, SAMPLE_TIME voice_start, + SAMPLE_TIME loop_start, SAMPLE_TIME loop_end) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_StopVoice(IDirectMusicSynth8 *iface, REFERENCE_TIME rt, DWORD voice_id) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_GetVoiceState(IDirectMusicSynth8 *iface, DWORD voice_buf[], DWORD voice_len, + DMUS_VOICE_STATE voice_state[]) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_Refresh(IDirectMusicSynth8 *iface, DWORD dlid, DWORD flags) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_synth_AssignChannelToBuses(IDirectMusicSynth8 *iface, DWORD group, DWORD channel, + DWORD *buses, DWORD buses_count) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static const IDirectMusicSynth8Vtbl test_synth_vtbl = +{ + test_synth_QueryInterface, + test_synth_AddRef, + test_synth_Release, + test_synth_Open, + test_synth_Close, + test_synth_SetNumChannelGroups, + test_synth_Download, + test_synth_Unload, + test_synth_PlayBuffer, + test_synth_GetRunningStats, + test_synth_GetPortCaps, + test_synth_SetMasterClock, + test_synth_GetLatencyClock, + test_synth_Activate, + test_synth_SetSynthSink, + test_synth_Render, + test_synth_SetChannelPriority, + test_synth_GetChannelPriority, + test_synth_GetFormat, + test_synth_GetAppend, + test_synth_PlayVoice, + test_synth_StopVoice, + test_synth_GetVoiceState, + test_synth_Refresh, + test_synth_AssignChannelToBuses, +}; + +static HRESULT test_synth_create(IDirectMusicSynth8 **out) +{ + struct test_synth *synth; + + *out = NULL; + if (!(synth = calloc(1, sizeof(*synth)))) return E_OUTOFMEMORY; + synth->IDirectMusicSynth8_iface.lpVtbl = &test_synth_vtbl; + synth->refcount = 1; + + *out = &synth->IDirectMusicSynth8_iface; + return S_OK; +} + static void test_synth_getformat(IDirectMusicSynth *synth, DMUS_PORTPARAMS *params, const char *context) { WAVEFORMATEX format; @@ -397,6 +608,181 @@ static void test_COM_synthsink(void) IDirectMusicSynthSink_Release(dmss); } +static void test_IDirectMusicSynthSink(void) +{ + IReferenceClock *latency_clock; + REFERENCE_TIME time, tmp_time; + IDirectMusicSynthSink *sink; + IDirectMusicSynth8 *synth; + IReferenceClock *clock; + IDirectSound *dsound; + IDirectMusic *music; + LONGLONG sample; + HRESULT hr; + DWORD size; + ULONG ref; + + hr = DirectSoundCreate(NULL, &dsound, NULL); + ok(hr == S_OK || broken(hr == DSERR_NODRIVER), "got %#lx\n", hr); + if (broken(hr == DSERR_NODRIVER)) + { + win_skip("Failed to create IDirectSound, skipping tests"); + return; + } + + hr = IDirectSound_SetCooperativeLevel(dsound, GetDesktopWindow(), DSSCL_PRIORITY); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusic, (void **)&music); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusic_GetMasterClock(music, NULL, &clock); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusic_Release(music); + + hr = test_synth_create(&synth); + ok(hr == S_OK, "got %#lx\n", hr); + + + hr = CoCreateInstance(&CLSID_DirectMusicSynthSink, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicSynthSink, (void **)&sink); + ok(hr == S_OK, "got %#lx\n", hr); + + /* sink is not configured */ + hr = IDirectMusicSynthSink_Activate(sink, TRUE); + todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_Activate(sink, FALSE); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicSynthSink_SampleToRefTime(sink, 0, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + time = 0xdeadbeef; + hr = IDirectMusicSynthSink_SampleToRefTime(sink, 10, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 4000, "got %I64d\n", time); + + hr = IDirectMusicSynthSink_RefTimeToSample(sink, 0, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + sample = 0xdeadbeef; + hr = IDirectMusicSynthSink_RefTimeToSample(sink, 4000, &sample); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(sample == 8, "got %I64d\n", sample); + + hr = IDirectMusicSynthSink_GetDesiredBufferSize(sink, &size); + ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + + /* latency clock is available but not usable */ + hr = IDirectMusicSynthSink_GetLatencyClock(sink, NULL); + ok(hr == E_POINTER, "got %#lx\n", hr); + ref = get_refcount(sink); + ok(ref == 1, "got %#lx\n", ref); + hr = IDirectMusicSynthSink_GetLatencyClock(sink, &latency_clock); + ok(hr == S_OK, "got %#lx\n", hr); + ok(latency_clock != clock, "got same clock\n"); + ref = get_refcount(sink); + todo_wine ok(ref == 2, "got %#lx\n", ref); + + hr = IReferenceClock_GetTime(latency_clock, NULL); + todo_wine ok(hr == E_INVALIDARG, "got %#lx\n", hr); + hr = IReferenceClock_GetTime(latency_clock, &time); + todo_wine ok(hr == E_FAIL, "got %#lx\n", hr); + + hr = IDirectMusicSynthSink_Init(sink, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_SetDirectSound(sink, NULL, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_SetDirectSound(sink, dsound, NULL); + todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + + /* Activate requires a synth, dsound and a clock */ + ref = get_refcount(synth); + ok(ref == 1, "got %#lx\n", ref); + hr = IDirectMusicSynthSink_Init(sink, (IDirectMusicSynth *)synth); + ok(hr == S_OK, "got %#lx\n", hr); + ref = get_refcount(synth); + ok(ref == 1, "got %#lx\n", ref); + hr = IDirectMusicSynthSink_GetDesiredBufferSize(sink, &size); + ok(hr == S_OK, "got %#lx\n", hr); + ok(size == 352800, "got %lu\n", size); + hr = IDirectMusicSynthSink_Activate(sink, TRUE); + todo_wine ok(hr == DMUS_E_DSOUND_NOT_SET, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_SetDirectSound(sink, dsound, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_Activate(sink, TRUE); + todo_wine ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_SetMasterClock(sink, clock); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IReferenceClock_GetTime(latency_clock, &time); + todo_wine ok(hr == E_FAIL, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_Activate(sink, TRUE); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_Activate(sink, TRUE); + todo_wine ok(hr == DMUS_E_SYNTHACTIVE, "got %#lx\n", hr); + ref = get_refcount(synth); + ok(ref == 1, "got %#lx\n", ref); + + hr = IDirectMusicSynthSink_GetDesiredBufferSize(sink, &size); + ok(hr == S_OK, "got %#lx\n", hr); + ok(size == 352800, "got %lu\n", size); + + /* conversion functions now use the activation time and master clock */ + hr = IReferenceClock_GetTime(clock, &time); + ok(hr == S_OK, "got %#lx\n", hr); + sample = 0xdeadbeef; + hr = IDirectMusicSynthSink_RefTimeToSample(sink, time, &sample); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(sample <= 3000, "got %I64d\n", sample); + tmp_time = time + 1; + hr = IDirectMusicSynthSink_SampleToRefTime(sink, sample, &tmp_time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(tmp_time <= time, "got %I64d\n", tmp_time - time); + ok(time - tmp_time <= 5000, "got %I64d\n", time - tmp_time); + + /* latency clock now works fine */ + tmp_time = time; + hr = IReferenceClock_GetTime(latency_clock, &tmp_time); + todo_wine_if(hr == S_FALSE) ok(hr == S_OK, "got %#lx\n", hr); + todo_wine_if(tmp_time <= time) ok(tmp_time > time, "got %I64d\n", tmp_time - time); + ok(tmp_time - time <= 2000000, "got %I64d\n", tmp_time - time); + + /* setting the clock while active is fine */ + hr = IDirectMusicSynthSink_SetMasterClock(sink, clock); + ok(hr == S_OK, "got %#lx\n", hr); + + /* removing synth while active is fine */ + hr = IDirectMusicSynthSink_Init(sink, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + ref = get_refcount(synth); + ok(ref == 1, "got %#lx\n", ref); + hr = IDirectMusicSynthSink_Activate(sink, TRUE); + todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + + /* changing dsound while active fails */ + hr = IDirectMusicSynthSink_SetDirectSound(sink, dsound, NULL); + todo_wine ok(hr == DMUS_E_SYNTHACTIVE, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_SetDirectSound(sink, NULL, NULL); + todo_wine ok(hr == DMUS_E_SYNTHACTIVE, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_Activate(sink, FALSE); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_SetDirectSound(sink, NULL, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + + /* SetMasterClock doesn't need the sink to be configured */ + hr = IDirectMusicSynthSink_SetMasterClock(sink, NULL); + ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicSynthSink_SetMasterClock(sink, clock); + ok(hr == S_OK, "got %#lx\n", hr); + + IReferenceClock_Release(latency_clock); + IDirectMusicSynthSink_Release(sink); + + + IDirectMusicSynth8_Release(synth); + IReferenceClock_Release(clock); + + IDirectSound_Release(dsound); +} + START_TEST(dmsynth) { CoInitializeEx(NULL, COINIT_MULTITHREADED); @@ -410,6 +796,7 @@ START_TEST(dmsynth) test_dmsynth(); test_COM(); test_COM_synthsink(); + test_IDirectMusicSynthSink(); CoUninitialize(); } From 5f0196c25b6032ad401c34c47bac167ed93cbe71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 27 Aug 2023 16:17:15 +0200 Subject: [PATCH 2419/2777] dmsynth/tests: Test DirectMusicSynth class in isolation. And more specifically how generating samples with Render works. (cherry picked from commit ce40b4d8fcb08d54df7ada430bc8dfe53392bd23) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/tests/dmsynth.c | 543 +++++++++++++++++++++++++++++++++++ 1 file changed, 543 insertions(+) diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index c8976f50e21..2fd62294df8 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -608,6 +608,548 @@ static void test_COM_synthsink(void) IDirectMusicSynthSink_Release(dmss); } +struct test_sink +{ + IDirectMusicSynthSink IDirectMusicSynthSink_iface; + IReferenceClock IReferenceClock_iface; + LONG refcount; + + IReferenceClock *clock; + IDirectMusicSynth *synth; + REFERENCE_TIME activate_time; + REFERENCE_TIME latency_time; + DWORD written; +}; + +static HRESULT WINAPI test_sink_QueryInterface(IDirectMusicSynthSink *iface, REFIID riid, void **ret_iface) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static ULONG WINAPI test_sink_AddRef(IDirectMusicSynthSink *iface) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + return InterlockedIncrement(&sink->refcount); +} + +static ULONG WINAPI test_sink_Release(IDirectMusicSynthSink *iface) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + ULONG ref = InterlockedDecrement(&sink->refcount); + if (!ref) free(sink); + return ref; +} + +static HRESULT WINAPI test_sink_Init(IDirectMusicSynthSink *iface, IDirectMusicSynth *synth) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + sink->synth = synth; + return S_OK; +} + +static HRESULT WINAPI test_sink_SetMasterClock(IDirectMusicSynthSink *iface, IReferenceClock *clock) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + if (sink->clock) + IReferenceClock_Release(sink->clock); + if ((sink->clock = clock)) + IReferenceClock_AddRef(sink->clock); + return S_OK; +} + +static HRESULT WINAPI test_sink_GetLatencyClock(IDirectMusicSynthSink *iface, IReferenceClock **clock) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + *clock = &sink->IReferenceClock_iface; + IReferenceClock_AddRef(*clock); + return S_OK; +} + +static HRESULT WINAPI test_sink_Activate(IDirectMusicSynthSink *iface, BOOL enable) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + + if (!sink->clock) + return DMUS_E_NO_MASTER_CLOCK; + + IReferenceClock_GetTime(sink->clock, &sink->activate_time); + sink->latency_time = sink->activate_time; + return S_OK; +} + +static HRESULT WINAPI test_sink_SampleToRefTime(IDirectMusicSynthSink *iface, LONGLONG sample, REFERENCE_TIME *time) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + WAVEFORMATEX format; + DWORD format_size = sizeof(format); + HRESULT hr; + + hr = IDirectMusicSynth_GetFormat(sink->synth, &format, &format_size); + ok(hr == S_OK, "got %#lx\n", hr); + + *time = sink->activate_time + ((sample * 10000) / format.nSamplesPerSec) * 1000; + return S_OK; +} + +static HRESULT WINAPI test_sink_RefTimeToSample(IDirectMusicSynthSink *iface, REFERENCE_TIME time, LONGLONG *sample) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + WAVEFORMATEX format; + DWORD format_size = sizeof(format); + HRESULT hr; + + hr = IDirectMusicSynth_GetFormat(sink->synth, &format, &format_size); + ok(hr == S_OK, "got %#lx\n", hr); + + *sample = (((time - sink->activate_time) / 1000) * format.nSamplesPerSec) / 10000; + return S_OK; +} + +static HRESULT WINAPI test_sink_SetDirectSound(IDirectMusicSynthSink *iface, IDirectSound *dsound, + IDirectSoundBuffer *dsound_buffer) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static HRESULT WINAPI test_sink_GetDesiredBufferSize(IDirectMusicSynthSink *iface, DWORD *size) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static const IDirectMusicSynthSinkVtbl test_sink_vtbl = +{ + test_sink_QueryInterface, + test_sink_AddRef, + test_sink_Release, + test_sink_Init, + test_sink_SetMasterClock, + test_sink_GetLatencyClock, + test_sink_Activate, + test_sink_SampleToRefTime, + test_sink_RefTimeToSample, + test_sink_SetDirectSound, + test_sink_GetDesiredBufferSize, +}; + +static HRESULT WINAPI test_sink_latency_clock_QueryInterface(IReferenceClock *iface, REFIID iid, void **out) +{ + ok(0, "unexpected %s\n", __func__); + return E_NOINTERFACE; +} + +static ULONG WINAPI test_sink_latency_clock_AddRef(IReferenceClock *iface) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IReferenceClock_iface); + return IDirectMusicSynthSink_AddRef(&sink->IDirectMusicSynthSink_iface); +} + +static ULONG WINAPI test_sink_latency_clock_Release(IReferenceClock *iface) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IReferenceClock_iface); + return IDirectMusicSynthSink_Release(&sink->IDirectMusicSynthSink_iface); +} + +static HRESULT WINAPI test_sink_latency_clock_GetTime(IReferenceClock *iface, REFERENCE_TIME *time) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IReferenceClock_iface); + *time = sink->latency_time; + return S_OK; +} + +static HRESULT WINAPI test_sink_latency_clock_AdviseTime(IReferenceClock *iface, + REFERENCE_TIME base, REFERENCE_TIME offset, HANDLE event, DWORD *cookie) +{ + ok(0, "unexpected %s\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_sink_latency_clock_AdvisePeriodic(IReferenceClock *iface, + REFERENCE_TIME start, REFERENCE_TIME period, HANDLE semaphore, DWORD *cookie) +{ + ok(0, "unexpected %s\n", __func__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_sink_latency_clock_Unadvise(IReferenceClock *iface, DWORD cookie) +{ + ok(0, "unexpected %s\n", __func__); + return E_NOTIMPL; +} + +static const IReferenceClockVtbl test_sink_latency_clock_vtbl = +{ + test_sink_latency_clock_QueryInterface, + test_sink_latency_clock_AddRef, + test_sink_latency_clock_Release, + test_sink_latency_clock_GetTime, + test_sink_latency_clock_AdviseTime, + test_sink_latency_clock_AdvisePeriodic, + test_sink_latency_clock_Unadvise, +}; + +static HRESULT test_sink_create(IDirectMusicSynthSink **out) +{ + struct test_sink *sink; + + *out = NULL; + if (!(sink = calloc(1, sizeof(*sink)))) return E_OUTOFMEMORY; + sink->IDirectMusicSynthSink_iface.lpVtbl = &test_sink_vtbl; + sink->IReferenceClock_iface.lpVtbl = &test_sink_latency_clock_vtbl; + sink->refcount = 1; + + *out = &sink->IDirectMusicSynthSink_iface; + return S_OK; +} + +static void test_sink_render(IDirectMusicSynthSink *iface, void *buffer, DWORD buffer_size, HANDLE output) +{ + struct test_sink *sink = CONTAINING_RECORD(iface, struct test_sink, IDirectMusicSynthSink_iface); + DWORD written, format_size; + WAVEFORMATEX format; + HRESULT hr; + + format_size = sizeof(format); + hr = IDirectMusicSynth_GetFormat(sink->synth, &format, &format_size); + ok(hr == S_OK, "got %#lx\n", hr); + + memset(buffer, 0, buffer_size); + hr = IDirectMusicSynth_Render(sink->synth, buffer, buffer_size / format.nBlockAlign, sink->written / format.nBlockAlign); + ok(hr == S_OK, "got %#lx\n", hr); + sink->written += buffer_size; + + hr = IDirectMusicSynthSink_SampleToRefTime(iface, sink->written / format.nBlockAlign, &sink->latency_time); + ok(hr == S_OK, "got %#lx\n", hr); + + if (output) + { + BOOL ret = WriteFile(output, buffer, buffer_size, &written, NULL); + ok(!!ret, "WriteFile failed, error %lu.\n", GetLastError()); + } +} + +static void test_IDirectMusicSynth(void) +{ + static const UINT RENDER_ITERATIONS = 8; + + struct wave_download + { + DMUS_DOWNLOADINFO info; + ULONG offsets[2]; + DMUS_WAVE wave; + union + { + DMUS_WAVEDATA wave_data; + struct + { + ULONG size; + BYTE samples[256]; + }; + }; + } wave_download = + { + .info = + { + .dwDLType = DMUS_DOWNLOADINFO_WAVE, + .dwDLId = 1, + .dwNumOffsetTableEntries = 2, + .cbSize = sizeof(struct wave_download), + }, + .offsets = + { + offsetof(struct wave_download, wave), + offsetof(struct wave_download, wave_data), + }, + .wave = + { + .ulWaveDataIdx = 1, + .WaveformatEx = + { + .wFormatTag = WAVE_FORMAT_PCM, + .nChannels = 1, + .wBitsPerSample = 8, + .nSamplesPerSec = 44100, + .nAvgBytesPerSec = 44100, + .nBlockAlign = 1, + }, + }, + .wave_data = + { + .cbSize = sizeof(wave_download.samples), + }, + }; + struct instrument_download + { + DMUS_DOWNLOADINFO info; + ULONG offsets[4]; + DMUS_INSTRUMENT instrument; + DMUS_REGION region; + DMUS_ARTICULATION articulation; + DMUS_ARTICPARAMS artic_params; + } instrument_download = + { + .info = + { + .dwDLType = DMUS_DOWNLOADINFO_INSTRUMENT, + .dwDLId = 2, + .dwNumOffsetTableEntries = 4, + .cbSize = sizeof(struct instrument_download), + }, + .offsets = + { + offsetof(struct instrument_download, instrument), + offsetof(struct instrument_download, region), + offsetof(struct instrument_download, articulation), + offsetof(struct instrument_download, artic_params), + }, + .instrument = + { + .ulPatch = 0, + .ulFirstRegionIdx = 1, + .ulGlobalArtIdx = 2, + }, + .region = + { + .RangeKey = {.usLow = 0, .usHigh = 127}, + .RangeVelocity = {.usLow = 0, .usHigh = 127}, + .fusOptions = F_RGN_OPTION_SELFNONEXCLUSIVE, + .WaveLink = {.ulChannel = 1, .ulTableIndex = 1}, + .WSMP = {.cbSize = sizeof(WSMPL), .usUnityNote = 60, .fulOptions = F_WSMP_NO_TRUNCATION}, + .WLOOP[0] = {.cbSize = sizeof(WLOOP), .ulType = WLOOP_TYPE_FORWARD}, + }, + .articulation = {.ulArt1Idx = 3}, + .artic_params = + { + .VolEG = {.tcAttack = 32768u << 16, .tcDecay = 32768u << 16, .ptSustain = 10000 << 16, .tcRelease = 32768u << 16}, + }, + }; + DMUS_BUFFERDESC buffer_desc = + { + .dwSize = sizeof(DMUS_BUFFERDESC), + .cbBuffer = 4096, + }; + DMUS_PORTPARAMS port_params = + { + .dwSize = sizeof(DMUS_PORTPARAMS), + .dwValidParams = DMUS_PORTPARAMS_AUDIOCHANNELS | DMUS_PORTPARAMS_SAMPLERATE, + .dwAudioChannels = 2, + .dwSampleRate = 44100, + }; + WCHAR temp_path[MAX_PATH], temp_file[MAX_PATH]; + IReferenceClock *latency_clock; + IDirectMusicSynthSink *sink; + IDirectMusicBuffer *buffer; + DWORD format_size, written; + IDirectMusicSynth *synth; + HANDLE wave_file, handle; + IReferenceClock *clock; + BOOL can_free = FALSE; + REFERENCE_TIME time; + WAVEFORMATEX format; + IDirectMusic *music; + short samples[256]; + ULONG i, ref; + HRESULT hr; + DWORD len; + BYTE *raw; + BOOL ret; + + hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusic, (void **)&music); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusic_GetMasterClock(music, NULL, &clock); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = test_sink_create(&sink); + ok(hr == S_OK, "got %#lx\n", hr); + + + hr = CoCreateInstance(&CLSID_DirectMusicSynth, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicSynth, (void **)&synth); + ok(hr == S_OK, "got %#lx\n", hr); + + /* SetNumChannelGroups needs Open */ + hr = IDirectMusicSynth_SetNumChannelGroups(synth, 1); + todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + /* GetFormat needs Open */ + hr = IDirectMusicSynth_GetFormat(synth, NULL, NULL); + ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicSynth_GetFormat(synth, NULL, &format_size); + ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + + /* Open / Close don't need a sink */ + hr = IDirectMusicSynth_Open(synth, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_Open(synth, NULL); + ok(hr == DMUS_E_ALREADYOPEN, "got %#lx\n", hr); + hr = IDirectMusicSynth_SetNumChannelGroups(synth, 1); + ok(hr == S_OK, "got %#lx\n", hr); + format_size = sizeof(format); + hr = IDirectMusicSynth_GetFormat(synth, NULL, &format_size); + ok(hr == S_OK, "got %#lx\n", hr); + ok(format_size == sizeof(format), "got %lu\n", format_size); + hr = IDirectMusicSynth_Close(synth); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_Close(synth); + ok(hr == DMUS_E_ALREADYCLOSED, "got %#lx\n", hr); + + /* GetLatencyClock needs a sink */ + hr = IDirectMusicSynth_GetLatencyClock(synth, NULL); + ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicSynth_GetLatencyClock(synth, &latency_clock); + ok(hr == DMUS_E_NOSYNTHSINK, "got %#lx\n", hr); + + /* Activate needs a sink, synth to be open, and a master clock on the sink */ + hr = IDirectMusicSynth_Open(synth, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_Activate(synth, TRUE); + ok(hr == DMUS_E_NOSYNTHSINK, "got %#lx\n", hr); + hr = IDirectMusicSynth_Activate(synth, FALSE); + todo_wine ok(hr == S_FALSE, "got %#lx\n", hr); + + hr = IDirectMusicSynth_SetSynthSink(synth, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_SetSynthSink(synth, sink); + ok(hr == S_OK, "got %#lx\n", hr); + ref = get_refcount(sink); + todo_wine ok(ref == 2, "got %lu\n", ref); + hr = IDirectMusicSynth_Activate(synth, TRUE); + todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + + /* SetMasterClock does nothing */ + hr = IDirectMusicSynth_SetMasterClock(synth, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicSynth_SetMasterClock(synth, clock); + ok(hr == S_OK, "got %#lx\n", hr); + ref = get_refcount(clock); + todo_wine ok(ref == 1, "got %lu\n", ref); + hr = IDirectMusicSynth_Activate(synth, TRUE); + todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + + /* SetMasterClock needs to be called on the sink */ + hr = IDirectMusicSynthSink_SetMasterClock(sink, clock); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_Activate(synth, TRUE); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_Activate(synth, TRUE); + todo_wine ok(hr == S_FALSE, "got %#lx\n", hr); + + /* Close is fine while active */ + hr = IDirectMusicSynth_Close(synth); + ok(hr == S_OK, "got %#lx\n", hr); + /* Removing the sink is fine while active */ + hr = IDirectMusicSynth_SetSynthSink(synth, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + ref = get_refcount(sink); + ok(ref == 1, "got %lu\n", ref); + + /* but Activate might fail then */ + hr = IDirectMusicSynth_Activate(synth, FALSE); + todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + hr = IDirectMusicSynth_Activate(synth, FALSE); + todo_wine ok(hr == S_FALSE, "got %#lx\n", hr); + + + /* Test generating some samples */ + hr = IDirectMusicSynth_Open(synth, &port_params); + ok(hr == S_OK, "got %#lx\n", hr); + + format_size = sizeof(format); + hr = IDirectMusicSynth_GetFormat(synth, &format, &format_size); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_SetSynthSink(synth, sink); + ok(hr == S_OK, "got %#lx\n", hr); + ref = get_refcount(sink); + todo_wine ok(ref == 2, "got %lu\n", ref); + hr = IDirectMusicSynth_Activate(synth, TRUE); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + + GetTempPathW(MAX_PATH, temp_path); + GetTempFileNameW(temp_path, L"synth", 0, temp_file); + wave_file = CreateFileW(temp_file, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(wave_file != INVALID_HANDLE_VALUE, "CreateFileW failed, error %lu.\n", GetLastError()); + ret = WriteFile(wave_file, "RIFF", 4, &written, NULL); + ok(ret, "WriteFile failed, error %lu.\n", GetLastError()); + format_size = (RENDER_ITERATIONS + 1) * sizeof(samples) + sizeof(format) + 20; + ret = WriteFile(wave_file, &format_size, 4, &written, NULL); + ok(ret, "WriteFile failed, error %lu.\n", GetLastError()); + ret = WriteFile(wave_file, "WAVEfmt ", 8, &written, NULL); + ok(ret, "WriteFile failed, error %lu.\n", GetLastError()); + format_size = sizeof(format); + ret = WriteFile(wave_file, &format_size, 4, &written, NULL); + ok(ret, "WriteFile failed, error %lu.\n", GetLastError()); + ret = WriteFile(wave_file, &format, format_size, &written, NULL); + ok(ret, "WriteFile failed, error %lu.\n", GetLastError()); + ret = WriteFile(wave_file, "data", 4, &written, NULL); + ok(ret, "WriteFile failed, error %lu.\n", GetLastError()); + format_size = (RENDER_ITERATIONS + 1) * sizeof(samples); + ret = WriteFile(wave_file, &format_size, 4, &written, NULL); + ok(ret, "WriteFile failed, error %lu.\n", GetLastError()); + + /* native needs to render at least once before producing samples */ + test_sink_render(sink, samples, sizeof(samples), wave_file); + + for (i = 0; i < ARRAY_SIZE(wave_download.samples); i++) + wave_download.samples[i] = i; + + can_free = 0xdeadbeef; + handle = (HANDLE)0xdeadbeef; + hr = IDirectMusicSynth_Download(synth, &handle, &wave_download, &can_free); + ok(hr == S_OK, "got %#lx\n", hr); + ok(handle != 0, "got %p\n", handle); + todo_wine ok(can_free == FALSE, "got %u\n", can_free); + + can_free = 0xdeadbeef; + handle = (HANDLE)0xdeadbeef; + hr = IDirectMusicSynth_Download(synth, &handle, &instrument_download, &can_free); + ok(hr == S_OK, "got %#lx\n", hr); + ok(handle != 0, "got %p\n", handle); + todo_wine ok(can_free == TRUE, "got %u\n", can_free); + + /* add a MIDI note to a buffer and play it */ + hr = IDirectMusicSynth_GetLatencyClock(synth, &latency_clock); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusic_CreateMusicBuffer(music, &buffer_desc, &buffer, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + /* status = 0x90 (NOTEON / channel 0), key = 0x27 (39), vel = 0x78 (120) */ + hr = IDirectMusicBuffer_PackStructured(buffer, 0, 1, 0x782790); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IReferenceClock_GetTime(latency_clock, &time); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicBuffer_GetRawBufferPtr(buffer, (BYTE **)&raw); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicBuffer_GetUsedBytes(buffer, &len); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_PlayBuffer(synth, time, (BYTE *)raw, len); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicBuffer_Release(buffer); + IReferenceClock_Release(latency_clock); + + for (i = 0; i < RENDER_ITERATIONS; i++) + test_sink_render(sink, samples, sizeof(samples), wave_file); + + CloseHandle(wave_file); + trace("Rendered samples to %s\n", debugstr_w(temp_file)); + + hr = IDirectMusicSynth_Activate(synth, FALSE); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_SetSynthSink(synth, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + ref = get_refcount(sink); + ok(ref == 1, "got %lu\n", ref); + hr = IDirectMusicSynth_Close(synth); + ok(hr == S_OK, "got %#lx\n", hr); + + IDirectMusicSynth_Release(synth); + + + if (strcmp(winetest_platform, "wine")) IDirectMusicSynthSink_Release(sink); + IReferenceClock_Release(clock); + IDirectMusic_Release(music); +} + static void test_IDirectMusicSynthSink(void) { IReferenceClock *latency_clock; @@ -796,6 +1338,7 @@ START_TEST(dmsynth) test_dmsynth(); test_COM(); test_COM_synthsink(); + test_IDirectMusicSynth(); test_IDirectMusicSynthSink(); CoUninitialize(); From 1bb7c629b87f56b50f8f3ffa6cf7d840005147cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 31 Aug 2023 17:58:05 +0200 Subject: [PATCH 2420/2777] include: Fix incorrect IDirectMusicPortDownload_Unload macro. (cherry picked from commit bb9e54808c2a0458d8d76b7c29c257954a3de0e4) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- include/dmusicc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/dmusicc.h b/include/dmusicc.h index cdae16c75bd..94ff184dc9f 100644 --- a/include/dmusicc.h +++ b/include/dmusicc.h @@ -635,7 +635,7 @@ DECLARE_INTERFACE_(IDirectMusicPortDownload,IUnknown) #define IDirectMusicPortDownload_GetDLId(p,a,b) (p)->lpVtbl->GetDLId(p,a,b) #define IDirectMusicPortDownload_GetAppend(p,a) (p)->lpVtbl->GetAppend(p,a) #define IDirectMusicPortDownload_Download(p,a) (p)->lpVtbl->Download(p,a) -#define IDirectMusicPortDownload_Unload(p,a) (p)->lpVtbl->GetBuffer(p,a) +#define IDirectMusicPortDownload_Unload(p,a) (p)->lpVtbl->Unload(p,a) #endif From 090790d6b3e50932706ca892eca0489093ee9916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 31 Aug 2023 17:58:05 +0200 Subject: [PATCH 2421/2777] dmusic/tests: Test IDirectMusic(Port)Download interfaces. (cherry picked from commit d6e1e0efa2802c6c33cdf2cf2f02d8dd05281a28) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/tests/dmusic.c | 148 +++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/dlls/dmusic/tests/dmusic.c b/dlls/dmusic/tests/dmusic.c index 37b517fe0ca..fd012111df0 100644 --- a/dlls/dmusic/tests/dmusic.c +++ b/dlls/dmusic/tests/dmusic.c @@ -947,6 +947,153 @@ static void test_synthport(void) IDirectMusic_Release(dmusic); } +static void test_port_download(void) +{ + struct wave_download + { + DMUS_DOWNLOADINFO info; + ULONG offsets[2]; + DMUS_WAVE wave; + DMUS_WAVEDATA wave_data; + }; + + static void *invalid_ptr = (void *)0xdeadbeef; + IDirectMusicDownload *download, *tmp_download; + struct wave_download *wave_download; + IDirectMusicPortDownload *port; + IDirectMusicPort *tmp_port; + DWORD ids[4], append, size; + IDirectMusic *dmusic; + void *buffer; + HRESULT hr; + + tmp_port = create_synth_port(&dmusic); + hr = IDirectMusicPort_QueryInterface(tmp_port, &IID_IDirectMusicPortDownload, (void **)&port); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicPort_Release(tmp_port); + + /* GetBuffer only works with pre-allocated DLId */ + hr = IDirectMusicPortDownload_GetBuffer(port, 0, NULL); + ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicPortDownload_GetBuffer(port, 0, &download); + todo_wine ok(hr == DMUS_E_INVALID_DOWNLOADID, "got %#lx\n", hr); + hr = IDirectMusicPortDownload_GetBuffer(port, 0xdeadbeef, &download); + todo_wine ok(hr == DMUS_E_INVALID_DOWNLOADID, "got %#lx\n", hr); + + /* AllocateBuffer use the exact requested size */ + hr = IDirectMusicPortDownload_AllocateBuffer(port, 0, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicPortDownload_AllocateBuffer(port, 0, &download); + todo_wine ok(hr == E_INVALIDARG, "got %#lx\n", hr); + + hr = IDirectMusicPortDownload_AllocateBuffer(port, 1, &download); + ok(hr == S_OK, "got %#lx\n", hr); + size = 0xdeadbeef; + buffer = invalid_ptr; + hr = IDirectMusicDownload_GetBuffer(download, (void **)&buffer, &size); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(size == 1, "got %#lx\n", size); + todo_wine ok(buffer != invalid_ptr, "got %p\n", buffer); + IDirectMusicDownload_Release(download); + + /* GetDLId allocates the given number of slots and returns only the first */ + hr = IDirectMusicPortDownload_GetDLId(port, NULL, 0); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicPortDownload_GetDLId(port, ids, 0); + todo_wine ok(hr == E_INVALIDARG, "got %#lx\n", hr); + + memset(ids, 0xcc, sizeof(ids)); + hr = IDirectMusicPortDownload_GetDLId(port, ids, 4); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(ids[0] == 0, "got %#lx\n", ids[0]); + ok(ids[1] == 0xcccccccc, "got %#lx\n", ids[1]); + + /* GetBuffer looks up allocated ids to find downloaded buffers */ + hr = IDirectMusicPortDownload_GetBuffer(port, 2, &download); + todo_wine ok(hr == DMUS_E_NOT_DOWNLOADED_TO_PORT, "got %#lx\n", hr); + + hr = IDirectMusicPortDownload_GetAppend(port, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + append = 0xdeadbeef; + hr = IDirectMusicPortDownload_GetAppend(port, &append); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(append == 2, "got %#lx\n", append); + + /* test Download / Unload on invalid and valid buffers */ + + download = invalid_ptr; + hr = IDirectMusicPortDownload_AllocateBuffer(port, sizeof(struct wave_download), &download); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(download != invalid_ptr, "got %p\n", download); + if (download == invalid_ptr) goto skip_tests; + size = 0xdeadbeef; + wave_download = invalid_ptr; + hr = IDirectMusicDownload_GetBuffer(download, (void **)&wave_download, &size); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(size == sizeof(struct wave_download), "got %#lx\n", size); + todo_wine ok(wave_download != invalid_ptr, "got %p\n", wave_download); + wave_download->info.cbSize = sizeof(struct wave_download); + wave_download->info.dwDLId = 2; + wave_download->info.dwDLType = 0; + wave_download->info.dwNumOffsetTableEntries = 0; + hr = IDirectMusicPortDownload_GetBuffer(port, 2, &tmp_download); + todo_wine ok(hr == DMUS_E_NOT_DOWNLOADED_TO_PORT, "got %#lx\n", hr); + + hr = IDirectMusicPortDownload_Download(port, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicPortDownload_Download(port, download); + todo_wine ok(hr == DMUS_E_UNKNOWNDOWNLOAD, "got %#lx\n", hr); + + wave_download->info.dwDLType = DMUS_DOWNLOADINFO_WAVE; + wave_download->info.dwNumOffsetTableEntries = 2; + wave_download->offsets[0] = offsetof(struct wave_download, wave); + wave_download->offsets[1] = offsetof(struct wave_download, wave_data); + wave_download->wave.WaveformatEx.wFormatTag = WAVE_FORMAT_PCM; + wave_download->wave.WaveformatEx.nChannels = 1; + wave_download->wave.WaveformatEx.nSamplesPerSec = 44100; + wave_download->wave.WaveformatEx.nAvgBytesPerSec = 44100; + wave_download->wave.WaveformatEx.nBlockAlign = 1; + wave_download->wave.WaveformatEx.wBitsPerSample = 8; + wave_download->wave.WaveformatEx.cbSize = 0; + wave_download->wave.ulWaveDataIdx = 1; + wave_download->wave.ulCopyrightIdx = 0; + wave_download->wave.ulFirstExtCkIdx = 0; + wave_download->wave_data.cbSize = 1; + + hr = IDirectMusicPortDownload_Download(port, download); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPortDownload_Download(port, download); + todo_wine ok(hr == DMUS_E_ALREADY_DOWNLOADED, "got %#lx\n", hr); + + tmp_download = invalid_ptr; + hr = IDirectMusicPortDownload_GetBuffer(port, 2, &tmp_download); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(tmp_download == download, "got %p\n", tmp_download); + if (tmp_download != invalid_ptr) IDirectMusicDownload_Release(tmp_download); + + hr = IDirectMusicPortDownload_Unload(port, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicPortDownload_Unload(port, download); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicPortDownload_GetBuffer(port, 2, &tmp_download); + todo_wine ok(hr == DMUS_E_NOT_DOWNLOADED_TO_PORT, "got %#lx\n", hr); + + hr = IDirectMusicPortDownload_Unload(port, download); + ok(hr == S_OK, "got %#lx\n", hr); + + /* DLIds are never released */ + hr = IDirectMusicPortDownload_GetDLId(port, ids, 1); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(ids[0] == 4, "got %#lx\n", ids[0]); + + IDirectMusicDownload_Release(download); + +skip_tests: + IDirectMusicPortDownload_Release(port); + IDirectMusic_Release(dmusic); +} + START_TEST(dmusic) { CoInitializeEx(NULL, COINIT_MULTITHREADED); @@ -967,6 +1114,7 @@ START_TEST(dmusic) test_parsedescriptor(); test_master_clock(); test_synthport(); + test_port_download(); CoUninitialize(); } From 8f215dbc7d99a9c2e0c1953d73aca429b38c9ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 30 Aug 2023 18:48:11 +0200 Subject: [PATCH 2422/2777] dmusic/tests: Test IDirectMusicPort_(Download|Unload)Instrument. (cherry picked from commit 041b468b23f680f1dd867b9a7c8f38c8b2d628de) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/tests/dmusic.c | 240 ++++++++++++++++++++++++++++++++++++- 1 file changed, 234 insertions(+), 6 deletions(-) diff --git a/dlls/dmusic/tests/dmusic.c b/dlls/dmusic/tests/dmusic.c index fd012111df0..6df37e3d63d 100644 --- a/dlls/dmusic/tests/dmusic.c +++ b/dlls/dmusic/tests/dmusic.c @@ -30,6 +30,95 @@ #include "dmusicf.h" #include "dmksctrl.h" +static ULONG get_refcount(void *iface) +{ + IUnknown *unknown = iface; + IUnknown_AddRef(unknown); + return IUnknown_Release(unknown); +} + +#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) +static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported) +{ + ULONG expect_ref = get_refcount(iface_ptr); + IUnknown *iface = iface_ptr; + HRESULT hr, expected; + IUnknown *unk; + + expected = supported ? S_OK : E_NOINTERFACE; + hr = IUnknown_QueryInterface(iface, iid, (void **)&unk); + ok_(__FILE__, line)(hr == expected, "got hr %#lx, expected %#lx.\n", hr, expected); + if (SUCCEEDED(hr)) + { + LONG ref = get_refcount(unk); + ok_(__FILE__, line)(ref == expect_ref + 1, "got %ld\n", ref); + IUnknown_Release(unk); + ref = get_refcount(iface_ptr); + ok_(__FILE__, line)(ref == expect_ref, "got %ld\n", ref); + } +} + +static void stream_begin_chunk(IStream *stream, const char type[5], ULARGE_INTEGER *offset) +{ + static const LARGE_INTEGER zero = {0}; + HRESULT hr; + hr = IStream_Write(stream, type, 4, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, offset); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IStream_Write(stream, "\0\0\0\0", 4, NULL); + ok(hr == S_OK, "got %#lx\n", hr); +} + +static void stream_end_chunk(IStream *stream, ULARGE_INTEGER *offset) +{ + static const LARGE_INTEGER zero = {0}; + ULARGE_INTEGER position; + HRESULT hr; + UINT size; + hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &position); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IStream_Seek(stream, *(LARGE_INTEGER *)offset, STREAM_SEEK_SET, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + size = position.QuadPart - offset->QuadPart - 4; + hr = IStream_Write(stream, &size, 4, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IStream_Seek(stream, *(LARGE_INTEGER *)&position, STREAM_SEEK_SET, NULL); + ok(hr == S_OK, "got %#lx\n", hr); +} + +#define CHUNK_BEGIN(stream, type) \ + do { \ + ULARGE_INTEGER __off; \ + stream_begin_chunk(stream, type, &__off); \ + do + +#define CHUNK_RIFF(stream, form) \ + do { \ + ULARGE_INTEGER __off; \ + stream_begin_chunk(stream, "RIFF", &__off); \ + IStream_Write(stream, form, 4, NULL); \ + do + +#define CHUNK_LIST(stream, form) \ + do { \ + ULARGE_INTEGER __off; \ + stream_begin_chunk(stream, "LIST", &__off); \ + IStream_Write(stream, form, 4, NULL); \ + do + +#define CHUNK_END \ + while (0); \ + stream_end_chunk(stream, &__off); \ + } while (0) + +#define CHUNK_DATA(stream, type, data) \ + CHUNK_BEGIN(stream, type) \ + { \ + IStream_Write((stream), &(data), sizeof(data), NULL); \ + } \ + CHUNK_END + static BOOL compare_time(REFERENCE_TIME x, REFERENCE_TIME y, unsigned int max_diff) { REFERENCE_TIME diff = x > y ? x - y : y - x; @@ -97,12 +186,6 @@ static void test_dmusic(void) IDirectMusic_Release(dmusic); } -static ULONG get_refcount(IDirectSound *iface) -{ - IDirectSound_AddRef(iface); - return IDirectSound_Release(iface); -} - static void test_setdsound(void) { IDirectMusic *dmusic; @@ -1091,6 +1174,150 @@ static void test_port_download(void) skip_tests: IDirectMusicPortDownload_Release(port); +} + +static void test_download_instrument(void) +{ + static const LARGE_INTEGER zero = {0}; + IDirectMusicDownloadedInstrument *downloaded; + IDirectMusicCollection *collection; + IDirectMusicInstrument *instrument; + IPersistStream *persist; + IDirectMusicPort *port; + IDirectMusic *dmusic; + WCHAR name[MAX_PATH]; + IStream *stream; + DWORD patch; + HRESULT hr; + + port = create_synth_port(&dmusic); + + hr = CoCreateInstance(&CLSID_DirectMusicCollection, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicCollection, (void **)&collection); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicCollection_QueryInterface(collection, &IID_IPersistStream, (void **)&persist); + ok(hr == S_OK, "got %#lx\n", hr); + hr = CreateStreamOnHGlobal(0, TRUE, &stream); + ok(hr == S_OK, "got %#lx\n", hr); + + CHUNK_RIFF(stream, "DLS ") + { + DLSHEADER colh = {.cInstruments = 1}; + struct + { + POOLTABLE head; + POOLCUE cues[1]; + } ptbl = + { + .head = {.cbSize = sizeof(POOLTABLE), .cCues = ARRAY_SIZE(ptbl.cues)}, + .cues = {{.ulOffset = 0}}, /* offsets in wvpl */ + }; + + CHUNK_DATA(stream, "colh", colh); + CHUNK_LIST(stream, "lins") + { + CHUNK_LIST(stream, "ins ") + { + INSTHEADER insh = {.cRegions = 1, .Locale = {.ulBank = 0x12, .ulInstrument = 0x34}}; + + CHUNK_DATA(stream, "insh", insh); + CHUNK_LIST(stream, "lrgn") + { + CHUNK_LIST(stream, "rgn ") + { + RGNHEADER rgnh = + { + .RangeKey = {.usLow = 0, .usHigh = 127}, + .RangeVelocity = {.usLow = 1, .usHigh = 127}, + }; + WAVELINK wlnk = {.ulChannel = 1, .ulTableIndex = 0}; + WSMPL wsmp = {.cbSize = sizeof(WSMPL)}; + + CHUNK_DATA(stream, "rgnh", rgnh); + CHUNK_DATA(stream, "wsmp", wsmp); + CHUNK_DATA(stream, "wlnk", wlnk); + } + CHUNK_END; + } + CHUNK_END; + + CHUNK_LIST(stream, "lart") + { + CONNECTIONLIST connections = {.cbSize = sizeof(connections)}; + CHUNK_DATA(stream, "art1", connections); + } + CHUNK_END; + } + CHUNK_END; + } + CHUNK_END; + CHUNK_DATA(stream, "ptbl", ptbl); + CHUNK_LIST(stream, "wvpl") + { + CHUNK_LIST(stream, "wave") + { + WAVEFORMATEX fmt = + { + .wFormatTag = WAVE_FORMAT_PCM, + .nChannels = 1, + .wBitsPerSample = 8, + .nSamplesPerSec = 22050, + .nAvgBytesPerSec = 22050, + .nBlockAlign = 1, + }; + BYTE data[16] = {0}; + + /* native returns DMUS_E_INVALIDOFFSET from DownloadInstrument if data is last */ + CHUNK_DATA(stream, "data", data); + CHUNK_DATA(stream, "fmt ", fmt); + } + CHUNK_END; + } + CHUNK_END; + } + CHUNK_END; + + hr = IStream_Seek(stream, zero, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IPersistStream_Load(persist, stream); + ok(hr == S_OK, "got %#lx\n", hr); + IPersistStream_Release(persist); + IStream_Release(stream); + + patch = 0xdeadbeef; + wcscpy(name, L"DeadBeef"); + hr = IDirectMusicCollection_EnumInstrument(collection, 0, &patch, name, ARRAY_SIZE(name)); + ok(hr == S_OK, "got %#lx\n", hr); + ok(patch == 0x1234, "got %#lx\n", patch); + ok(*name == 0, "got %s\n", debugstr_w(name)); + hr = IDirectMusicCollection_EnumInstrument(collection, 1, &patch, name, ARRAY_SIZE(name)); + ok(hr == S_FALSE, "got %#lx\n", hr); + + hr = IDirectMusicCollection_GetInstrument(collection, 0x1234, &instrument); + ok(hr == S_OK, "got %#lx\n", hr); + + check_interface(instrument, &IID_IDirectMusicObject, FALSE); + check_interface(instrument, &IID_IDirectMusicDownload, FALSE); + check_interface(instrument, &IID_IDirectMusicDownloadedInstrument, FALSE); + + hr = IDirectMusicPort_DownloadInstrument(port, instrument, &downloaded, NULL, 0); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + if (hr != S_OK) goto skip_tests; + + check_interface(downloaded, &IID_IDirectMusicObject, FALSE); + check_interface(downloaded, &IID_IDirectMusicDownload, FALSE); + check_interface(downloaded, &IID_IDirectMusicInstrument, FALSE); + + hr = IDirectMusicPort_UnloadInstrument(port, downloaded); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicDownloadedInstrument_Release(downloaded); + + IDirectMusicInstrument_Release(instrument); + +skip_tests: + IDirectMusicCollection_Release(collection); + IDirectMusicPort_Release(port); IDirectMusic_Release(dmusic); } @@ -1115,6 +1342,7 @@ START_TEST(dmusic) test_master_clock(); test_synthport(); test_port_download(); + test_download_instrument(); CoUninitialize(); } From acf00fa5dcb2555a2991875caff5eaf56ee7030e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Aug 2023 17:45:36 +0200 Subject: [PATCH 2423/2777] dmusic: Always return S_FALSE from DllCanUnloadNow. (cherry picked from commit abc6ecc89dda625a93266851cc8aff4d6626f87b) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/buffer.c | 2 -- dlls/dmusic/clock.c | 2 -- dlls/dmusic/collection.c | 2 -- dlls/dmusic/dmusic.c | 2 -- dlls/dmusic/dmusic_main.c | 21 --------------------- dlls/dmusic/dmusic_private.h | 8 -------- dlls/dmusic/download.c | 2 -- dlls/dmusic/instrument.c | 2 -- dlls/dmusic/port.c | 6 ------ 9 files changed, 47 deletions(-) diff --git a/dlls/dmusic/buffer.c b/dlls/dmusic/buffer.c index 9aaa1a074b4..a2ad137fe4b 100644 --- a/dlls/dmusic/buffer.c +++ b/dlls/dmusic/buffer.c @@ -71,7 +71,6 @@ static ULONG WINAPI IDirectMusicBufferImpl_Release(LPDIRECTMUSICBUFFER iface) if (!ref) { free(This->data); free(This); - DMUSIC_UnlockModule(); } return ref; @@ -319,7 +318,6 @@ HRESULT DMUSIC_CreateDirectMusicBufferImpl(LPDMUS_BUFFERDESC desc, LPVOID* ret_i return E_OUTOFMEMORY; } - DMUSIC_LockModule(); *ret_iface = &dmbuffer->IDirectMusicBuffer_iface; return S_OK; diff --git a/dlls/dmusic/clock.c b/dlls/dmusic/clock.c index 15a04c844e5..19441d3d56f 100644 --- a/dlls/dmusic/clock.c +++ b/dlls/dmusic/clock.c @@ -63,7 +63,6 @@ static ULONG WINAPI IReferenceClockImpl_Release(IReferenceClock *iface) if (!ref) { free(This); - DMUSIC_UnlockModule(); } return ref; @@ -137,7 +136,6 @@ HRESULT DMUSIC_CreateReferenceClockImpl(LPCGUID riid, LPVOID* ret_iface, LPUNKNO clock->rtTime = 0; clock->pClockInfo.dwSize = sizeof (DMUS_CLOCKINFO); - DMUSIC_LockModule(); hr = IReferenceClockImpl_QueryInterface(&clock->IReferenceClock_iface, riid, ret_iface); IReferenceClock_Release(&clock->IReferenceClock_iface); diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 0febf9dfd08..3f1c70b01e3 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -99,7 +99,6 @@ static ULONG WINAPI IDirectMusicCollectionImpl_Release(IDirectMusicCollection *i if (!ref) { free(This); - DMUSIC_UnlockModule(); } return ref; @@ -544,7 +543,6 @@ HRESULT DMUSIC_CreateDirectMusicCollectionImpl(REFIID lpcGUID, void **ppobj, IUn list_init (&obj->Instruments); - DMUSIC_LockModule(); hr = IDirectMusicCollection_QueryInterface(&obj->IDirectMusicCollection_iface, lpcGUID, ppobj); IDirectMusicCollection_Release(&obj->IDirectMusicCollection_iface); diff --git a/dlls/dmusic/dmusic.c b/dlls/dmusic/dmusic.c index 8fb35e65809..d284b32fdd7 100644 --- a/dlls/dmusic/dmusic.c +++ b/dlls/dmusic/dmusic.c @@ -201,7 +201,6 @@ static ULONG WINAPI IDirectMusic8Impl_Release(LPDIRECTMUSIC8 iface) free(This->system_ports); free(This->ports); free(This); - DMUSIC_UnlockModule(); } return ref; @@ -606,7 +605,6 @@ HRESULT DMUSIC_CreateDirectMusicImpl(REFIID riid, void **ret_iface, IUnknown *un create_system_ports_list(dmusic); - DMUSIC_LockModule(); ret = IDirectMusic8Impl_QueryInterface(&dmusic->IDirectMusic8_iface, riid, ret_iface); IDirectMusic8_Release(&dmusic->IDirectMusic8_iface); diff --git a/dlls/dmusic/dmusic_main.c b/dlls/dmusic/dmusic_main.c index 5d4939937a9..509e80f872b 100644 --- a/dlls/dmusic/dmusic_main.c +++ b/dlls/dmusic/dmusic_main.c @@ -39,8 +39,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmusic); -LONG DMUSIC_refCount = 0; - typedef struct { IClassFactory IClassFactory_iface; HRESULT (*fnCreateInstance)(REFIID riid, void **ppv, IUnknown *pUnkOuter); @@ -76,15 +74,11 @@ static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID r static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) { - DMUSIC_LockModule(); - return 2; /* non-heap based object */ } static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) { - DMUSIC_UnlockModule(); - return 1; /* non-heap based object */ } @@ -101,12 +95,6 @@ static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock) { TRACE("(%d)\n", dolock); - - if (dolock) - DMUSIC_LockModule(); - else - DMUSIC_UnlockModule(); - return S_OK; } @@ -122,15 +110,6 @@ static IClassFactoryImpl DirectMusic_CF = {{&classfactory_vtbl}, DMUSIC_CreateDi static IClassFactoryImpl Collection_CF = {{&classfactory_vtbl}, DMUSIC_CreateDirectMusicCollectionImpl}; -/****************************************************************** - * DllCanUnloadNow (DMUSIC.@) - * - * - */ -HRESULT WINAPI DllCanUnloadNow(void) -{ - return DMUSIC_refCount != 0 ? S_FALSE : S_OK; -} /****************************************************************** diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 1b91f4bac94..ffc6aaca539 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -217,14 +217,6 @@ static inline IDirectMusicInstrumentImpl *impl_from_IDirectMusicInstrument(IDire /* custom :) */ extern HRESULT IDirectMusicInstrumentImpl_CustomLoad(IDirectMusicInstrument *iface, IStream *stream); -/********************************************************************** - * Dll lifetime tracking declaration for dmusic.dll - */ -extern LONG DMUSIC_refCount; -static inline void DMUSIC_LockModule(void) { InterlockedIncrement( &DMUSIC_refCount ); } -static inline void DMUSIC_UnlockModule(void) { InterlockedDecrement( &DMUSIC_refCount ); } - - /***************************************************************************** * Misc. */ diff --git a/dlls/dmusic/download.c b/dlls/dmusic/download.c index 48f0efd5f69..095ea23235b 100644 --- a/dlls/dmusic/download.c +++ b/dlls/dmusic/download.c @@ -65,7 +65,6 @@ static ULONG WINAPI IDirectMusicDownloadImpl_Release(IDirectMusicDownload *iface if (!ref) { free(This); - DMUSIC_UnlockModule(); } return ref; @@ -102,6 +101,5 @@ HRESULT DMUSIC_CreateDirectMusicDownloadImpl(const GUID *guid, void **ret_iface, download->ref = 1; *ret_iface = download; - DMUSIC_LockModule(); return S_OK; } diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index 7b7ee3def64..767c4419225 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -82,7 +82,6 @@ static ULONG WINAPI IDirectMusicInstrumentImpl_Release(LPDIRECTMUSICINSTRUMENT i free(This->articulations->connections); free(This->articulations); free(This); - DMUSIC_UnlockModule(); } return ref; @@ -133,7 +132,6 @@ HRESULT DMUSIC_CreateDirectMusicInstrumentImpl (LPCGUID lpcGUID, LPVOID* ppobj, dminst->IDirectMusicInstrument_iface.lpVtbl = &DirectMusicInstrument_Vtbl; dminst->ref = 1; - DMUSIC_LockModule(); hr = IDirectMusicInstrument_QueryInterface(&dminst->IDirectMusicInstrument_iface, lpcGUID, ppobj); IDirectMusicInstrument_Release(&dminst->IDirectMusicInstrument_iface); diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index 518b4fe9666..ccf785d4b74 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -105,7 +105,6 @@ static ULONG WINAPI IDirectMusicDownloadedInstrumentImpl_Release(LPDIRECTMUSICDO { free(This->data); free(This); - DMUSIC_UnlockModule(); } return ref; @@ -141,7 +140,6 @@ static HRESULT DMUSIC_CreateDirectMusicDownloadedInstrumentImpl(IDirectMusicDown object->ref = 1; *instrument = &object->IDirectMusicDownloadedInstrument_iface; - DMUSIC_LockModule(); return S_OK; } @@ -178,8 +176,6 @@ static ULONG WINAPI synth_port_AddRef(IDirectMusicPort *iface) TRACE("(%p): new ref = %lu\n", This, ref); - DMUSIC_LockModule(); - return ref; } @@ -204,8 +200,6 @@ static ULONG WINAPI synth_port_Release(IDirectMusicPort *iface) free(This); } - DMUSIC_UnlockModule(); - return ref; } From be699385a7d5aedcba2c965cb6b0714355f6ed74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 11:16:59 +0200 Subject: [PATCH 2424/2777] dmusic: Simplify and cleanup IDirectMusicDownload constructor. (cherry picked from commit ac25d09955a711aac61bbe30656eef2089e73bc3) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/dmusic_private.h | 3 ++- dlls/dmusic/download.c | 15 +++++---------- dlls/dmusic/port.c | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index ffc6aaca539..1f8c6e227ff 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -100,10 +100,11 @@ extern HRESULT DMUSIC_CreateDirectMusicCollectionImpl(REFIID riid, void **ppobj, /* Internal */ extern HRESULT DMUSIC_CreateDirectMusicBufferImpl(LPDMUS_BUFFERDESC desc, LPVOID* ret_iface); -extern HRESULT DMUSIC_CreateDirectMusicDownloadImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter); extern HRESULT DMUSIC_CreateReferenceClockImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter); extern HRESULT DMUSIC_CreateDirectMusicInstrumentImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter); +extern HRESULT download_create(IDirectMusicDownload **ret_iface); + /***************************************************************************** * IDirectMusic8Impl implementation structure */ diff --git a/dlls/dmusic/download.c b/dlls/dmusic/download.c index 095ea23235b..f7ac8d92ee6 100644 --- a/dlls/dmusic/download.c +++ b/dlls/dmusic/download.c @@ -85,21 +85,16 @@ static const IDirectMusicDownloadVtbl DirectMusicDownload_Vtbl = { IDirectMusicDownloadImpl_GetBuffer }; -/* for ClassFactory */ -HRESULT DMUSIC_CreateDirectMusicDownloadImpl(const GUID *guid, void **ret_iface, IUnknown *unk_outer) +HRESULT download_create(IDirectMusicDownload **ret_iface) { IDirectMusicDownloadImpl *download; - download = malloc(sizeof(*download)); - if (!download) - { - *ret_iface = NULL; - return E_OUTOFMEMORY; - } - + *ret_iface = NULL; + if (!(download = calloc(1, sizeof(*download)))) return E_OUTOFMEMORY; download->IDirectMusicDownload_iface.lpVtbl = &DirectMusicDownload_Vtbl; download->ref = 1; - *ret_iface = download; + TRACE("Created DirectMusicDownload %p\n", download); + *ret_iface = &download->IDirectMusicDownload_iface; return S_OK; } diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index ccf785d4b74..18e290cc897 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -582,7 +582,7 @@ static HRESULT WINAPI synth_port_download_GetBuffer(IDirectMusicPortDownload *if if (!IDMDownload) return E_POINTER; - return DMUSIC_CreateDirectMusicDownloadImpl(&IID_IDirectMusicDownload, (LPVOID*)IDMDownload, NULL); + return download_create(IDMDownload); } static HRESULT WINAPI synth_port_download_AllocateBuffer(IDirectMusicPortDownload *iface, DWORD size, From c134ea2cc887f2546a712ed0411bad81ca444c97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 24 Aug 2023 11:03:57 +0200 Subject: [PATCH 2425/2777] dmusic: Move IDirectMusicDownloadImpl struct to where it is used. (cherry picked from commit f96f53ea85818775d2fcafe63412cb76c71ecb22) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/dmusic_private.h | 12 ------------ dlls/dmusic/download.c | 8 ++++++++ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 1f8c6e227ff..bc8ba5b483c 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -50,7 +50,6 @@ typedef struct IDirectMusic8Impl IDirectMusic8Impl; typedef struct IDirectMusicBufferImpl IDirectMusicBufferImpl; typedef struct IDirectMusicDownloadedInstrumentImpl IDirectMusicDownloadedInstrumentImpl; -typedef struct IDirectMusicDownloadImpl IDirectMusicDownloadImpl; typedef struct IReferenceClockImpl IReferenceClockImpl; typedef struct IDirectMusicInstrumentImpl IDirectMusicInstrumentImpl; @@ -148,17 +147,6 @@ struct IDirectMusicDownloadedInstrumentImpl { void *data; }; -/***************************************************************************** - * IDirectMusicDownloadImpl implementation structure - */ -struct IDirectMusicDownloadImpl { - /* IUnknown fields */ - IDirectMusicDownload IDirectMusicDownload_iface; - LONG ref; - - /* IDirectMusicDownloadImpl fields */ -}; - /** Internal factory */ extern HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_params, DMUS_PORTCAPS *port_caps, IDirectMusicPort **port); diff --git a/dlls/dmusic/download.c b/dlls/dmusic/download.c index f7ac8d92ee6..fc94cac6a68 100644 --- a/dlls/dmusic/download.c +++ b/dlls/dmusic/download.c @@ -23,6 +23,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmusic); +struct IDirectMusicDownloadImpl +{ + IDirectMusicDownload IDirectMusicDownload_iface; + LONG ref; +}; + +typedef struct IDirectMusicDownloadImpl IDirectMusicDownloadImpl; + static inline IDirectMusicDownloadImpl* impl_from_IDirectMusicDownload(IDirectMusicDownload *iface) { return CONTAINING_RECORD(iface, IDirectMusicDownloadImpl, IDirectMusicDownload_iface); From 7a177f8c20fe8fc303f2e90565a551e1ace2b47f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 24 Aug 2023 10:59:27 +0200 Subject: [PATCH 2426/2777] dmusic: Rename IDirectMusicDownloadImpl method prefix to download. (cherry picked from commit 770749491d786da425c0fb6e80460b7f29d5ff66) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/download.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/dlls/dmusic/download.c b/dlls/dmusic/download.c index fc94cac6a68..9c3f0d6b0cd 100644 --- a/dlls/dmusic/download.c +++ b/dlls/dmusic/download.c @@ -23,21 +23,18 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmusic); -struct IDirectMusicDownloadImpl +struct download { IDirectMusicDownload IDirectMusicDownload_iface; LONG ref; }; -typedef struct IDirectMusicDownloadImpl IDirectMusicDownloadImpl; - -static inline IDirectMusicDownloadImpl* impl_from_IDirectMusicDownload(IDirectMusicDownload *iface) +static inline struct download *impl_from_IDirectMusicDownload(IDirectMusicDownload *iface) { - return CONTAINING_RECORD(iface, IDirectMusicDownloadImpl, IDirectMusicDownload_iface); + return CONTAINING_RECORD(iface, struct download, IDirectMusicDownload_iface); } -/* IDirectMusicDownloadImpl IUnknown part: */ -static HRESULT WINAPI IDirectMusicDownloadImpl_QueryInterface(IDirectMusicDownload *iface, REFIID riid, void **ret_iface) +static HRESULT WINAPI download_QueryInterface(IDirectMusicDownload *iface, REFIID riid, void **ret_iface) { TRACE("(%p, %s, %p)\n", iface, debugstr_dmguid(riid), ret_iface); @@ -54,9 +51,9 @@ static HRESULT WINAPI IDirectMusicDownloadImpl_QueryInterface(IDirectMusicDownlo return E_NOINTERFACE; } -static ULONG WINAPI IDirectMusicDownloadImpl_AddRef(IDirectMusicDownload *iface) +static ULONG WINAPI download_AddRef(IDirectMusicDownload *iface) { - IDirectMusicDownloadImpl *This = impl_from_IDirectMusicDownload(iface); + struct download *This = impl_from_IDirectMusicDownload(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p): new ref = %lu\n", iface, ref); @@ -64,9 +61,9 @@ static ULONG WINAPI IDirectMusicDownloadImpl_AddRef(IDirectMusicDownload *iface) return ref; } -static ULONG WINAPI IDirectMusicDownloadImpl_Release(IDirectMusicDownload *iface) +static ULONG WINAPI download_Release(IDirectMusicDownload *iface) { - IDirectMusicDownloadImpl *This = impl_from_IDirectMusicDownload(iface); + struct download *This = impl_from_IDirectMusicDownload(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p): new ref = %lu\n", iface, ref); @@ -78,28 +75,28 @@ static ULONG WINAPI IDirectMusicDownloadImpl_Release(IDirectMusicDownload *iface return ref; } -/* IDirectMusicDownloadImpl IDirectMusicDownload part: */ -static HRESULT WINAPI IDirectMusicDownloadImpl_GetBuffer(IDirectMusicDownload *iface, void **buffer, DWORD *size) +static HRESULT WINAPI download_GetBuffer(IDirectMusicDownload *iface, void **buffer, DWORD *size) { FIXME("(%p, %p, %p): stub\n", iface, buffer, size); return S_OK; } -static const IDirectMusicDownloadVtbl DirectMusicDownload_Vtbl = { - IDirectMusicDownloadImpl_QueryInterface, - IDirectMusicDownloadImpl_AddRef, - IDirectMusicDownloadImpl_Release, - IDirectMusicDownloadImpl_GetBuffer +static const IDirectMusicDownloadVtbl download_vtbl = +{ + download_QueryInterface, + download_AddRef, + download_Release, + download_GetBuffer, }; HRESULT download_create(IDirectMusicDownload **ret_iface) { - IDirectMusicDownloadImpl *download; + struct download *download; *ret_iface = NULL; if (!(download = calloc(1, sizeof(*download)))) return E_OUTOFMEMORY; - download->IDirectMusicDownload_iface.lpVtbl = &DirectMusicDownload_Vtbl; + download->IDirectMusicDownload_iface.lpVtbl = &download_vtbl; download->ref = 1; TRACE("Created DirectMusicDownload %p\n", download); From 57100447bda823a4e2448624d8c2fde26a4cf210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 31 Aug 2023 17:21:09 +0200 Subject: [PATCH 2427/2777] dmusic: Implement synth port IDirectMusicPortDownload_GetDLId. (cherry picked from commit 45f61965dc386f76c139adb358edc780d144a0f1) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/port.c | 12 ++++++++++-- dlls/dmusic/tests/dmusic.c | 8 ++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index 18e290cc897..caae177a3a9 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -40,6 +40,8 @@ struct synth_port { DMUS_PORTPARAMS params; int nrofgroups; DMUSIC_PRIVATE_CHANNEL_GROUP group[1]; + + DWORD next_dlid; }; static inline IDirectMusicDownloadedInstrumentImpl* impl_from_IDirectMusicDownloadedInstrument(IDirectMusicDownloadedInstrument *iface) @@ -595,11 +597,17 @@ static HRESULT WINAPI synth_port_download_AllocateBuffer(IDirectMusicPortDownloa return S_OK; } -static HRESULT WINAPI synth_port_download_GetDLId(IDirectMusicPortDownload *iface, DWORD *start_DLId, DWORD count) +static HRESULT WINAPI synth_port_download_GetDLId(IDirectMusicPortDownload *iface, DWORD *first, DWORD count) { struct synth_port *This = synth_from_IDirectMusicPortDownload(iface); - FIXME("(%p/%p, %p, %lu): stub\n", iface, This, start_DLId, count); + TRACE("(%p/%p, %p, %lu)\n", iface, This, first, count); + + if (!first) return E_POINTER; + if (!count) return E_INVALIDARG; + + *first = This->next_dlid; + This->next_dlid += count; return S_OK; } diff --git a/dlls/dmusic/tests/dmusic.c b/dlls/dmusic/tests/dmusic.c index 6df37e3d63d..05568208fee 100644 --- a/dlls/dmusic/tests/dmusic.c +++ b/dlls/dmusic/tests/dmusic.c @@ -1081,14 +1081,14 @@ static void test_port_download(void) /* GetDLId allocates the given number of slots and returns only the first */ hr = IDirectMusicPortDownload_GetDLId(port, NULL, 0); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); hr = IDirectMusicPortDownload_GetDLId(port, ids, 0); - todo_wine ok(hr == E_INVALIDARG, "got %#lx\n", hr); + ok(hr == E_INVALIDARG, "got %#lx\n", hr); memset(ids, 0xcc, sizeof(ids)); hr = IDirectMusicPortDownload_GetDLId(port, ids, 4); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(ids[0] == 0, "got %#lx\n", ids[0]); + ok(ids[0] == 0, "got %#lx\n", ids[0]); ok(ids[1] == 0xcccccccc, "got %#lx\n", ids[1]); /* GetBuffer looks up allocated ids to find downloaded buffers */ @@ -1168,7 +1168,7 @@ static void test_port_download(void) /* DLIds are never released */ hr = IDirectMusicPortDownload_GetDLId(port, ids, 1); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(ids[0] == 4, "got %#lx\n", ids[0]); + ok(ids[0] == 4, "got %#lx\n", ids[0]); IDirectMusicDownload_Release(download); From 9a795c86d76530014e72040243d3607ec77b4cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 15:55:47 +0200 Subject: [PATCH 2428/2777] dmusic: Implement IDirectMusicPortDownload_AllocateBuffer. (cherry picked from commit 30df87af090801ae3d7d619325f15ddab462d266) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/dmusic_private.h | 2 +- dlls/dmusic/download.c | 17 ++++++++++++++--- dlls/dmusic/port.c | 11 +++++++---- dlls/dmusic/tests/dmusic.c | 16 +++++++--------- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index bc8ba5b483c..1eea2f845cb 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -102,7 +102,7 @@ extern HRESULT DMUSIC_CreateDirectMusicBufferImpl(LPDMUS_BUFFERDESC desc, LPVOID extern HRESULT DMUSIC_CreateReferenceClockImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter); extern HRESULT DMUSIC_CreateDirectMusicInstrumentImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter); -extern HRESULT download_create(IDirectMusicDownload **ret_iface); +extern HRESULT download_create(DWORD size, IDirectMusicDownload **ret_iface); /***************************************************************************** * IDirectMusic8Impl implementation structure diff --git a/dlls/dmusic/download.c b/dlls/dmusic/download.c index 9c3f0d6b0cd..6dac3e1b725 100644 --- a/dlls/dmusic/download.c +++ b/dlls/dmusic/download.c @@ -27,8 +27,13 @@ struct download { IDirectMusicDownload IDirectMusicDownload_iface; LONG ref; + + DWORD size; + BYTE data[]; }; +C_ASSERT(sizeof(struct download) == offsetof(struct download, data[0])); + static inline struct download *impl_from_IDirectMusicDownload(IDirectMusicDownload *iface) { return CONTAINING_RECORD(iface, struct download, IDirectMusicDownload_iface); @@ -77,7 +82,12 @@ static ULONG WINAPI download_Release(IDirectMusicDownload *iface) static HRESULT WINAPI download_GetBuffer(IDirectMusicDownload *iface, void **buffer, DWORD *size) { - FIXME("(%p, %p, %p): stub\n", iface, buffer, size); + struct download *This = impl_from_IDirectMusicDownload(iface); + + TRACE("(%p, %p, %p)\n", iface, buffer, size); + + *buffer = This->data; + *size = This->size; return S_OK; } @@ -90,14 +100,15 @@ static const IDirectMusicDownloadVtbl download_vtbl = download_GetBuffer, }; -HRESULT download_create(IDirectMusicDownload **ret_iface) +HRESULT download_create(DWORD size, IDirectMusicDownload **ret_iface) { struct download *download; *ret_iface = NULL; - if (!(download = calloc(1, sizeof(*download)))) return E_OUTOFMEMORY; + if (!(download = malloc(offsetof(struct download, data[size])))) return E_OUTOFMEMORY; download->IDirectMusicDownload_iface.lpVtbl = &download_vtbl; download->ref = 1; + download->size = size; TRACE("Created DirectMusicDownload %p\n", download); *ret_iface = &download->IDirectMusicDownload_iface; diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index caae177a3a9..9c932420623 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -584,17 +584,20 @@ static HRESULT WINAPI synth_port_download_GetBuffer(IDirectMusicPortDownload *if if (!IDMDownload) return E_POINTER; - return download_create(IDMDownload); + return download_create(0, IDMDownload); } static HRESULT WINAPI synth_port_download_AllocateBuffer(IDirectMusicPortDownload *iface, DWORD size, - IDirectMusicDownload **IDMDownload) + IDirectMusicDownload **download) { struct synth_port *This = synth_from_IDirectMusicPortDownload(iface); - FIXME("(%p/%p, %lu, %p): stub\n", iface, This, size, IDMDownload); + TRACE("(%p/%p, %lu, %p)\n", iface, This, size, download); - return S_OK; + if (!download) return E_POINTER; + if (!size) return E_INVALIDARG; + + return download_create(size, download); } static HRESULT WINAPI synth_port_download_GetDLId(IDirectMusicPortDownload *iface, DWORD *first, DWORD count) diff --git a/dlls/dmusic/tests/dmusic.c b/dlls/dmusic/tests/dmusic.c index 05568208fee..8cfcc11ffd8 100644 --- a/dlls/dmusic/tests/dmusic.c +++ b/dlls/dmusic/tests/dmusic.c @@ -1065,9 +1065,9 @@ static void test_port_download(void) /* AllocateBuffer use the exact requested size */ hr = IDirectMusicPortDownload_AllocateBuffer(port, 0, NULL); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); hr = IDirectMusicPortDownload_AllocateBuffer(port, 0, &download); - todo_wine ok(hr == E_INVALIDARG, "got %#lx\n", hr); + ok(hr == E_INVALIDARG, "got %#lx\n", hr); hr = IDirectMusicPortDownload_AllocateBuffer(port, 1, &download); ok(hr == S_OK, "got %#lx\n", hr); @@ -1075,8 +1075,8 @@ static void test_port_download(void) buffer = invalid_ptr; hr = IDirectMusicDownload_GetBuffer(download, (void **)&buffer, &size); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(size == 1, "got %#lx\n", size); - todo_wine ok(buffer != invalid_ptr, "got %p\n", buffer); + ok(size == 1, "got %#lx\n", size); + ok(buffer != invalid_ptr, "got %p\n", buffer); IDirectMusicDownload_Release(download); /* GetDLId allocates the given number of slots and returns only the first */ @@ -1107,14 +1107,13 @@ static void test_port_download(void) download = invalid_ptr; hr = IDirectMusicPortDownload_AllocateBuffer(port, sizeof(struct wave_download), &download); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(download != invalid_ptr, "got %p\n", download); - if (download == invalid_ptr) goto skip_tests; + ok(download != invalid_ptr, "got %p\n", download); size = 0xdeadbeef; wave_download = invalid_ptr; hr = IDirectMusicDownload_GetBuffer(download, (void **)&wave_download, &size); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(size == sizeof(struct wave_download), "got %#lx\n", size); - todo_wine ok(wave_download != invalid_ptr, "got %p\n", wave_download); + ok(size == sizeof(struct wave_download), "got %#lx\n", size); + ok(wave_download != invalid_ptr, "got %p\n", wave_download); wave_download->info.cbSize = sizeof(struct wave_download); wave_download->info.dwDLId = 2; wave_download->info.dwDLType = 0; @@ -1172,7 +1171,6 @@ static void test_port_download(void) IDirectMusicDownload_Release(download); -skip_tests: IDirectMusicPortDownload_Release(port); } From dfcb8ee21a6f9878deaae9bf9c766a1c10004489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 31 Aug 2023 18:16:00 +0200 Subject: [PATCH 2429/2777] dmusic: Implement IDirectMusicPortDownload_(Download|Unload). (cherry picked from commit 73d1e0663080c4e6020fc7e729e0a0d014ca9d62) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/port.c | 70 ++++++++++++++++++++++++++++++++++---- dlls/dmusic/tests/dmusic.c | 6 ++-- 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index 9c932420623..316af0c4550 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -25,6 +25,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmusic); +struct download_entry +{ + struct list entry; + IDirectMusicDownload *download; + HANDLE handle; + DWORD id; +}; + struct synth_port { IDirectMusicPort IDirectMusicPort_iface; IDirectMusicPortDownload IDirectMusicPortDownload_iface; @@ -41,6 +49,7 @@ struct synth_port { int nrofgroups; DMUSIC_PRIVATE_CHANNEL_GROUP group[1]; + struct list downloads; DWORD next_dlid; }; @@ -190,6 +199,15 @@ static ULONG WINAPI synth_port_Release(IDirectMusicPort *iface) if (!ref) { + struct download_entry *entry, *next; + + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &This->downloads, struct download_entry, entry) + { + list_remove(&entry->entry); + IDirectMusicDownload_Release(entry->download); + free(entry); + } + dmusic_remove_port(This->parent, iface); IDirectMusicSynthSink_Release(This->synth_sink); IDirectMusicSynth_Activate(This->synth, FALSE); @@ -624,22 +642,61 @@ static HRESULT WINAPI synth_port_download_GetAppend(IDirectMusicPortDownload *if return S_OK; } -static HRESULT WINAPI synth_port_download_Download(IDirectMusicPortDownload *iface, IDirectMusicDownload *IDMDownload) +static HRESULT WINAPI synth_port_download_Download(IDirectMusicPortDownload *iface, IDirectMusicDownload *download) { struct synth_port *This = synth_from_IDirectMusicPortDownload(iface); + struct download_entry *entry; + DMUS_DOWNLOADINFO *info; + HANDLE handle; + BOOL can_free; + DWORD size; + HRESULT hr; - FIXME("(%p/%p)->(%p): stub\n", iface, This, IDMDownload); + TRACE("(%p/%p)->(%p)\n", iface, This, download); - return S_OK; + if (!download) return E_POINTER; + + LIST_FOR_EACH_ENTRY(entry, &This->downloads, struct download_entry, entry) + if (entry->download == download) return DMUS_E_ALREADY_DOWNLOADED; + + if (!(entry = malloc(sizeof(*entry)))) return E_OUTOFMEMORY; + if (SUCCEEDED(hr = IDirectMusicDownload_GetBuffer(download, (void **)&info, &size)) + && SUCCEEDED(hr = IDirectMusicSynth_Download(This->synth, &handle, info, &can_free))) + { + entry->download = download; + IDirectMusicDownload_AddRef(download); + entry->id = info->dwDLId; + entry->handle = handle; + list_add_tail(&This->downloads, &entry->entry); + } + + if (FAILED(hr)) free(entry); + return hr; } -static HRESULT WINAPI synth_port_download_Unload(IDirectMusicPortDownload *iface, IDirectMusicDownload *IDMDownload) +static HRESULT WINAPI synth_port_download_Unload(IDirectMusicPortDownload *iface, IDirectMusicDownload *download) { struct synth_port *This = synth_from_IDirectMusicPortDownload(iface); + struct download_entry *entry; + HANDLE handle = 0; - FIXME("(%p/%p)->(%p): stub\n", iface, This, IDMDownload); + TRACE("(%p/%p)->(%p)\n", iface, This, download); - return S_OK; + if (!download) return E_POINTER; + + LIST_FOR_EACH_ENTRY(entry, &This->downloads, struct download_entry, entry) + { + if (entry->download == download) + { + list_remove(&entry->entry); + IDirectMusicDownload_Release(entry->download); + handle = entry->handle; + free(entry); + break; + } + } + + return IDirectMusicSynth_Unload(This->synth, handle, NULL, NULL); } static const IDirectMusicPortDownloadVtbl synth_port_download_vtbl = { @@ -795,6 +852,7 @@ HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_param obj->parent = parent; obj->active = FALSE; obj->params = *port_params; + list_init(&obj->downloads); hr = CoCreateInstance(&CLSID_DirectMusicSynth, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicSynth, (void **)&obj->synth); diff --git a/dlls/dmusic/tests/dmusic.c b/dlls/dmusic/tests/dmusic.c index 8cfcc11ffd8..13716c096e9 100644 --- a/dlls/dmusic/tests/dmusic.c +++ b/dlls/dmusic/tests/dmusic.c @@ -1122,7 +1122,7 @@ static void test_port_download(void) todo_wine ok(hr == DMUS_E_NOT_DOWNLOADED_TO_PORT, "got %#lx\n", hr); hr = IDirectMusicPortDownload_Download(port, NULL); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); hr = IDirectMusicPortDownload_Download(port, download); todo_wine ok(hr == DMUS_E_UNKNOWNDOWNLOAD, "got %#lx\n", hr); @@ -1145,7 +1145,7 @@ static void test_port_download(void) hr = IDirectMusicPortDownload_Download(port, download); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPortDownload_Download(port, download); - todo_wine ok(hr == DMUS_E_ALREADY_DOWNLOADED, "got %#lx\n", hr); + ok(hr == DMUS_E_ALREADY_DOWNLOADED, "got %#lx\n", hr); tmp_download = invalid_ptr; hr = IDirectMusicPortDownload_GetBuffer(port, 2, &tmp_download); @@ -1154,7 +1154,7 @@ static void test_port_download(void) if (tmp_download != invalid_ptr) IDirectMusicDownload_Release(tmp_download); hr = IDirectMusicPortDownload_Unload(port, NULL); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); hr = IDirectMusicPortDownload_Unload(port, download); ok(hr == S_OK, "got %#lx\n", hr); From 7f53cbeac19a04318ca2bb5ee72c1fb26c3a5010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 15:51:09 +0200 Subject: [PATCH 2430/2777] dmusic: Implement IDirectMusicPortDownload_GetBuffer. (cherry picked from commit d3b191503e7316890d630c2fabff16ef01bb63c1) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/port.c | 23 +++++++++++++++++------ dlls/dmusic/tests/dmusic.c | 14 +++++++------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index 316af0c4550..eaf2bb139f1 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -592,17 +592,28 @@ static ULONG WINAPI synth_port_download_Release(IDirectMusicPortDownload *iface) return IDirectMusicPort_Release(&This->IDirectMusicPort_iface); } -static HRESULT WINAPI synth_port_download_GetBuffer(IDirectMusicPortDownload *iface, DWORD DLId, - IDirectMusicDownload **IDMDownload) +static HRESULT WINAPI synth_port_download_GetBuffer(IDirectMusicPortDownload *iface, DWORD id, + IDirectMusicDownload **download) { struct synth_port *This = synth_from_IDirectMusicPortDownload(iface); + struct download_entry *entry; - FIXME("(%p/%p, %lu, %p): stub\n", iface, This, DLId, IDMDownload); + TRACE("(%p/%p, %lu, %p)\n", iface, This, id, download); - if (!IDMDownload) - return E_POINTER; + if (!download) return E_POINTER; + if (id >= This->next_dlid) return DMUS_E_INVALID_DOWNLOADID; + + LIST_FOR_EACH_ENTRY(entry, &This->downloads, struct download_entry, entry) + { + if (entry->id == id) + { + *download = entry->download; + IDirectMusicDownload_AddRef(entry->download); + return S_OK; + } + } - return download_create(0, IDMDownload); + return DMUS_E_NOT_DOWNLOADED_TO_PORT; } static HRESULT WINAPI synth_port_download_AllocateBuffer(IDirectMusicPortDownload *iface, DWORD size, diff --git a/dlls/dmusic/tests/dmusic.c b/dlls/dmusic/tests/dmusic.c index 13716c096e9..a8152822613 100644 --- a/dlls/dmusic/tests/dmusic.c +++ b/dlls/dmusic/tests/dmusic.c @@ -1059,9 +1059,9 @@ static void test_port_download(void) hr = IDirectMusicPortDownload_GetBuffer(port, 0, NULL); ok(hr == E_POINTER, "got %#lx\n", hr); hr = IDirectMusicPortDownload_GetBuffer(port, 0, &download); - todo_wine ok(hr == DMUS_E_INVALID_DOWNLOADID, "got %#lx\n", hr); + ok(hr == DMUS_E_INVALID_DOWNLOADID, "got %#lx\n", hr); hr = IDirectMusicPortDownload_GetBuffer(port, 0xdeadbeef, &download); - todo_wine ok(hr == DMUS_E_INVALID_DOWNLOADID, "got %#lx\n", hr); + ok(hr == DMUS_E_INVALID_DOWNLOADID, "got %#lx\n", hr); /* AllocateBuffer use the exact requested size */ hr = IDirectMusicPortDownload_AllocateBuffer(port, 0, NULL); @@ -1093,7 +1093,7 @@ static void test_port_download(void) /* GetBuffer looks up allocated ids to find downloaded buffers */ hr = IDirectMusicPortDownload_GetBuffer(port, 2, &download); - todo_wine ok(hr == DMUS_E_NOT_DOWNLOADED_TO_PORT, "got %#lx\n", hr); + ok(hr == DMUS_E_NOT_DOWNLOADED_TO_PORT, "got %#lx\n", hr); hr = IDirectMusicPortDownload_GetAppend(port, NULL); todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); @@ -1119,7 +1119,7 @@ static void test_port_download(void) wave_download->info.dwDLType = 0; wave_download->info.dwNumOffsetTableEntries = 0; hr = IDirectMusicPortDownload_GetBuffer(port, 2, &tmp_download); - todo_wine ok(hr == DMUS_E_NOT_DOWNLOADED_TO_PORT, "got %#lx\n", hr); + ok(hr == DMUS_E_NOT_DOWNLOADED_TO_PORT, "got %#lx\n", hr); hr = IDirectMusicPortDownload_Download(port, NULL); ok(hr == E_POINTER, "got %#lx\n", hr); @@ -1150,8 +1150,8 @@ static void test_port_download(void) tmp_download = invalid_ptr; hr = IDirectMusicPortDownload_GetBuffer(port, 2, &tmp_download); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(tmp_download == download, "got %p\n", tmp_download); - if (tmp_download != invalid_ptr) IDirectMusicDownload_Release(tmp_download); + ok(tmp_download == download, "got %p\n", tmp_download); + IDirectMusicDownload_Release(tmp_download); hr = IDirectMusicPortDownload_Unload(port, NULL); ok(hr == E_POINTER, "got %#lx\n", hr); @@ -1159,7 +1159,7 @@ static void test_port_download(void) ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPortDownload_GetBuffer(port, 2, &tmp_download); - todo_wine ok(hr == DMUS_E_NOT_DOWNLOADED_TO_PORT, "got %#lx\n", hr); + ok(hr == DMUS_E_NOT_DOWNLOADED_TO_PORT, "got %#lx\n", hr); hr = IDirectMusicPortDownload_Unload(port, download); ok(hr == S_OK, "got %#lx\n", hr); From 4c9c1e89dbf0e4451c8eaa50ebfb8100a0c110b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 27 Aug 2023 16:30:15 +0200 Subject: [PATCH 2431/2777] dmsynth: Implement IDirectMusicSynthSink_SetDirectSound semi-stub. (cherry picked from commit be2cdd3cb278bd84c95556ed945199c1aa2fe615) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synthsink.c | 13 ++++++++++++- dlls/dmsynth/tests/dmsynth.c | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/dlls/dmsynth/synthsink.c b/dlls/dmsynth/synthsink.c index 2200abd93b1..a6d6276dddf 100644 --- a/dlls/dmsynth/synthsink.c +++ b/dlls/dmsynth/synthsink.c @@ -36,6 +36,7 @@ struct synth_sink IReferenceClock *latency_clock; IReferenceClock *master_clock; IDirectMusicSynth *synth; /* No reference hold! */ + IDirectSound *dsound; BOOL active; }; @@ -183,7 +184,17 @@ static HRESULT WINAPI synth_sink_SetDirectSound(IDirectMusicSynthSink *iface, { struct synth_sink *This = impl_from_IDirectMusicSynthSink(iface); - FIXME("(%p)->(%p, %p): stub\n", This, dsound, dsound_buffer); + TRACE("(%p)->(%p, %p)\n", This, dsound, dsound_buffer); + + if (dsound_buffer) FIXME("Ignoring IDirectSoundBuffer parameter.\n"); + if (This->active) return DMUS_E_SYNTHACTIVE; + + if (This->dsound) IDirectSound_Release(This->dsound); + This->dsound = NULL; + if (!dsound) return S_OK; + + if (!This->synth) return DMUS_E_SYNTHNOTCONFIGURED; + if ((This->dsound = dsound)) IDirectSound_AddRef(This->dsound); return S_OK; } diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index 2fd62294df8..d74b20c9cd4 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -1234,7 +1234,7 @@ static void test_IDirectMusicSynthSink(void) hr = IDirectMusicSynthSink_SetDirectSound(sink, NULL, NULL); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicSynthSink_SetDirectSound(sink, dsound, NULL); - todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); /* Activate requires a synth, dsound and a clock */ ref = get_refcount(synth); From 9ceeeced7c871eef9e0f8c5e48cf622b058b4c8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 27 Aug 2023 16:25:14 +0200 Subject: [PATCH 2432/2777] dmsynth: Avoid leaking master clock references. (cherry picked from commit 48536877fe4501d5dba78ffb2498ee4da2a5f17d) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synthsink.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/dmsynth/synthsink.c b/dlls/dmsynth/synthsink.c index a6d6276dddf..ed1ef6a0027 100644 --- a/dlls/dmsynth/synthsink.c +++ b/dlls/dmsynth/synthsink.c @@ -127,6 +127,7 @@ static HRESULT WINAPI synth_sink_SetMasterClock(IDirectMusicSynthSink *iface, if (This->active) return E_FAIL; + if (This->master_clock) IReferenceClock_Release(This->master_clock); IReferenceClock_AddRef(clock); This->master_clock = clock; From 3935c9cdb6d0884994fa2ec30aaa05b0e478b843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 27 Aug 2023 16:25:25 +0200 Subject: [PATCH 2433/2777] dmsynth: Allow changing master clock while active. (cherry picked from commit 1b3cc0ce49080b0a9a5b920b6210ce006ec46300) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synthsink.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dlls/dmsynth/synthsink.c b/dlls/dmsynth/synthsink.c index ed1ef6a0027..1e6ffa5b51f 100644 --- a/dlls/dmsynth/synthsink.c +++ b/dlls/dmsynth/synthsink.c @@ -124,8 +124,6 @@ static HRESULT WINAPI synth_sink_SetMasterClock(IDirectMusicSynthSink *iface, if (!clock) return E_POINTER; - if (This->active) - return E_FAIL; if (This->master_clock) IReferenceClock_Release(This->master_clock); IReferenceClock_AddRef(clock); From 28866ef5d32ec73a0a4cb10453ce8a6105b19cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 27 Aug 2023 16:32:53 +0200 Subject: [PATCH 2434/2777] dmsynth: Implement IDirectMusicSynthSink_Activate semi-stub. (cherry picked from commit 10da838a785b81d6a09aa6034aceb53f2d0b4798) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synthsink.c | 27 +++++++++++++++++++++++++-- dlls/dmsynth/tests/dmsynth.c | 14 +++++++------- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/dlls/dmsynth/synthsink.c b/dlls/dmsynth/synthsink.c index 1e6ffa5b51f..b525a81d876 100644 --- a/dlls/dmsynth/synthsink.c +++ b/dlls/dmsynth/synthsink.c @@ -37,7 +37,9 @@ struct synth_sink IReferenceClock *master_clock; IDirectMusicSynth *synth; /* No reference hold! */ IDirectSound *dsound; + BOOL active; + REFERENCE_TIME activate_time; }; static inline struct synth_sink *impl_from_IDirectMusicSynthSink(IDirectMusicSynthSink *iface) @@ -45,6 +47,27 @@ static inline struct synth_sink *impl_from_IDirectMusicSynthSink(IDirectMusicSyn return CONTAINING_RECORD(iface, struct synth_sink, IDirectMusicSynthSink_iface); } +static HRESULT synth_sink_activate(struct synth_sink *This) +{ + HRESULT hr; + + if (!This->synth) return DMUS_E_SYNTHNOTCONFIGURED; + if (!This->dsound) return DMUS_E_DSOUND_NOT_SET; + if (!This->master_clock) return DMUS_E_NO_MASTER_CLOCK; + if (This->active) return DMUS_E_SYNTHACTIVE; + + if (FAILED(hr = IReferenceClock_GetTime(This->master_clock, &This->activate_time))) return hr; + + This->active = TRUE; + return S_OK; +} + +static HRESULT synth_sink_deactivate(struct synth_sink *This) +{ + This->active = FALSE; + return S_OK; +} + static HRESULT WINAPI synth_sink_QueryInterface(IDirectMusicSynthSink *iface, REFIID riid, void **ret_iface) { @@ -153,9 +176,9 @@ static HRESULT WINAPI synth_sink_Activate(IDirectMusicSynthSink *iface, { struct synth_sink *This = impl_from_IDirectMusicSynthSink(iface); - FIXME("(%p)->(%d): stub\n", This, enable); + FIXME("(%p)->(%d): semi-stub\n", This, enable); - return S_OK; + return enable ? synth_sink_activate(This) : synth_sink_deactivate(This); } static HRESULT WINAPI synth_sink_SampleToRefTime(IDirectMusicSynthSink *iface, diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index d74b20c9cd4..ffc79f2c24b 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -1192,7 +1192,7 @@ static void test_IDirectMusicSynthSink(void) /* sink is not configured */ hr = IDirectMusicSynthSink_Activate(sink, TRUE); - todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); hr = IDirectMusicSynthSink_Activate(sink, FALSE); ok(hr == S_OK, "got %#lx\n", hr); @@ -1247,11 +1247,11 @@ static void test_IDirectMusicSynthSink(void) ok(hr == S_OK, "got %#lx\n", hr); ok(size == 352800, "got %lu\n", size); hr = IDirectMusicSynthSink_Activate(sink, TRUE); - todo_wine ok(hr == DMUS_E_DSOUND_NOT_SET, "got %#lx\n", hr); + ok(hr == DMUS_E_DSOUND_NOT_SET, "got %#lx\n", hr); hr = IDirectMusicSynthSink_SetDirectSound(sink, dsound, NULL); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicSynthSink_Activate(sink, TRUE); - todo_wine ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr); + ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr); hr = IDirectMusicSynthSink_SetMasterClock(sink, clock); ok(hr == S_OK, "got %#lx\n", hr); hr = IReferenceClock_GetTime(latency_clock, &time); @@ -1259,7 +1259,7 @@ static void test_IDirectMusicSynthSink(void) hr = IDirectMusicSynthSink_Activate(sink, TRUE); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicSynthSink_Activate(sink, TRUE); - todo_wine ok(hr == DMUS_E_SYNTHACTIVE, "got %#lx\n", hr); + ok(hr == DMUS_E_SYNTHACTIVE, "got %#lx\n", hr); ref = get_refcount(synth); ok(ref == 1, "got %#lx\n", ref); @@ -1297,13 +1297,13 @@ static void test_IDirectMusicSynthSink(void) ref = get_refcount(synth); ok(ref == 1, "got %#lx\n", ref); hr = IDirectMusicSynthSink_Activate(sink, TRUE); - todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); /* changing dsound while active fails */ hr = IDirectMusicSynthSink_SetDirectSound(sink, dsound, NULL); - todo_wine ok(hr == DMUS_E_SYNTHACTIVE, "got %#lx\n", hr); + ok(hr == DMUS_E_SYNTHACTIVE, "got %#lx\n", hr); hr = IDirectMusicSynthSink_SetDirectSound(sink, NULL, NULL); - todo_wine ok(hr == DMUS_E_SYNTHACTIVE, "got %#lx\n", hr); + ok(hr == DMUS_E_SYNTHACTIVE, "got %#lx\n", hr); hr = IDirectMusicSynthSink_Activate(sink, FALSE); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicSynthSink_SetDirectSound(sink, NULL, NULL); From 73b20f8a70b4ec79d4c0e2f7c11a2f3875e5cd34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Sep 2023 13:20:07 +0200 Subject: [PATCH 2435/2777] dmsynth: Implement SampleToRefTime and RefTimeToSample. (cherry picked from commit 3610b54bd6df4f653c76b8487458df1db74ccab5) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synthsink.c | 36 ++++++++++++++++++++++++++++++++++-- dlls/dmsynth/tests/dmsynth.c | 14 +++++++------- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/dlls/dmsynth/synthsink.c b/dlls/dmsynth/synthsink.c index b525a81d876..9da462b8074 100644 --- a/dlls/dmsynth/synthsink.c +++ b/dlls/dmsynth/synthsink.c @@ -47,6 +47,25 @@ static inline struct synth_sink *impl_from_IDirectMusicSynthSink(IDirectMusicSyn return CONTAINING_RECORD(iface, struct synth_sink, IDirectMusicSynthSink_iface); } +static void synth_sink_get_format(struct synth_sink *This, WAVEFORMATEX *format) +{ + DWORD size = sizeof(*format); + HRESULT hr; + + format->wFormatTag = WAVE_FORMAT_PCM; + format->nChannels = 2; + format->wBitsPerSample = 16; + format->nSamplesPerSec = 22050; + format->nBlockAlign = format->nChannels * format->wBitsPerSample / 8; + format->nAvgBytesPerSec = format->nSamplesPerSec * format->nBlockAlign; + + if (This->synth) + { + if (FAILED(hr = IDirectMusicSynth_GetFormat(This->synth, format, &size))) + WARN("Failed to get synth buffer format, hr %#lx\n", hr); + } +} + static HRESULT synth_sink_activate(struct synth_sink *This) { HRESULT hr; @@ -185,8 +204,14 @@ static HRESULT WINAPI synth_sink_SampleToRefTime(IDirectMusicSynthSink *iface, LONGLONG sample_time, REFERENCE_TIME *ref_time) { struct synth_sink *This = impl_from_IDirectMusicSynthSink(iface); + WAVEFORMATEX format; + + TRACE("(%p)->(%I64d, %p)\n", This, sample_time, ref_time); + + if (!ref_time) return E_POINTER; - FIXME("(%p)->(0x%s, %p): stub\n", This, wine_dbgstr_longlong(sample_time), ref_time); + synth_sink_get_format(This, &format); + *ref_time = This->activate_time + ((sample_time * 10000) / format.nSamplesPerSec) * 1000; return S_OK; } @@ -195,8 +220,15 @@ static HRESULT WINAPI synth_sink_RefTimeToSample(IDirectMusicSynthSink *iface, REFERENCE_TIME ref_time, LONGLONG *sample_time) { struct synth_sink *This = impl_from_IDirectMusicSynthSink(iface); + WAVEFORMATEX format; + + TRACE("(%p)->(%I64d, %p)\n", This, ref_time, sample_time); + + if (!sample_time) return E_POINTER; - FIXME("(%p)->(0x%s, %p): stub\n", This, wine_dbgstr_longlong(ref_time), sample_time); + synth_sink_get_format(This, &format); + ref_time -= This->activate_time; + *sample_time = ((ref_time / 1000) * format.nSamplesPerSec) / 10000; return S_OK; } diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index ffc79f2c24b..97029c98294 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -1197,18 +1197,18 @@ static void test_IDirectMusicSynthSink(void) ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicSynthSink_SampleToRefTime(sink, 0, NULL); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); time = 0xdeadbeef; hr = IDirectMusicSynthSink_SampleToRefTime(sink, 10, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(time == 4000, "got %I64d\n", time); + ok(time == 4000, "got %I64d\n", time); hr = IDirectMusicSynthSink_RefTimeToSample(sink, 0, NULL); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); sample = 0xdeadbeef; hr = IDirectMusicSynthSink_RefTimeToSample(sink, 4000, &sample); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(sample == 8, "got %I64d\n", sample); + ok(sample == 8, "got %I64d\n", sample); hr = IDirectMusicSynthSink_GetDesiredBufferSize(sink, &size); ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); @@ -1273,12 +1273,12 @@ static void test_IDirectMusicSynthSink(void) sample = 0xdeadbeef; hr = IDirectMusicSynthSink_RefTimeToSample(sink, time, &sample); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(sample <= 3000, "got %I64d\n", sample); + ok(sample <= 3000, "got %I64d\n", sample); tmp_time = time + 1; hr = IDirectMusicSynthSink_SampleToRefTime(sink, sample, &tmp_time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(tmp_time <= time, "got %I64d\n", tmp_time - time); - ok(time - tmp_time <= 5000, "got %I64d\n", time - tmp_time); + ok(tmp_time <= time, "got %I64d\n", tmp_time - time); + ok(time - tmp_time <= 5000, "got %I64d\n", tmp_time); /* latency clock now works fine */ tmp_time = time; From fb5ff13178b0572172521ba3aa4a2efcf93257de Mon Sep 17 00:00:00 2001 From: Francois Gouget Date: Wed, 6 Sep 2023 11:24:29 +0200 Subject: [PATCH 2436/2777] dmsynth/tests: Add the trailing linefeed to a win_skip() message. The missing linefeed was causing the test summary line to be garbled. (cherry picked from commit a6d6f914b3f86a3fe6fd70c65e10eab5a084af83) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/tests/dmsynth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index 97029c98294..a27a101bd07 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -1168,7 +1168,7 @@ static void test_IDirectMusicSynthSink(void) ok(hr == S_OK || broken(hr == DSERR_NODRIVER), "got %#lx\n", hr); if (broken(hr == DSERR_NODRIVER)) { - win_skip("Failed to create IDirectSound, skipping tests"); + win_skip("Failed to create IDirectSound, skipping tests\n"); return; } From 1001164b07ba8f8ffb166fe351a303ffbffb4400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 11:36:10 +0200 Subject: [PATCH 2437/2777] dmsynth: Move constructor parameter checks to class factory. (cherry picked from commit ec2a7a325176c6c8d3278bcaab9bae8418eed880) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/dmsynth_main.c | 28 +++++++++++++++++----------- dlls/dmsynth/dmsynth_private.h | 4 ++-- dlls/dmsynth/synth.c | 16 +++++++--------- dlls/dmsynth/synthsink.c | 14 ++++++-------- 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/dlls/dmsynth/dmsynth_main.c b/dlls/dmsynth/dmsynth_main.c index edeaab8474e..84caeceb472 100644 --- a/dlls/dmsynth/dmsynth_main.c +++ b/dlls/dmsynth/dmsynth_main.c @@ -27,7 +27,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); typedef struct { IClassFactory IClassFactory_iface; - HRESULT (*fnCreateInstance)(REFIID riid, void **ppv); + HRESULT (*create_instance)(IUnknown **ret_iface); } IClassFactoryImpl; /****************************************************************** @@ -68,17 +68,24 @@ static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) return 1; /* non-heap based object */ } -static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, - REFIID riid, void **ppv) +static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *unk_outer, + REFIID riid, void **ret_iface) { - IClassFactoryImpl *This = impl_from_IClassFactory(iface); + IClassFactoryImpl *This = impl_from_IClassFactory(iface); + IUnknown *object; + HRESULT hr; - TRACE ("(%p, %s, %p)\n", pUnkOuter, debugstr_dmguid(riid), ppv); + TRACE("(%p, %s, %p)\n", unk_outer, debugstr_dmguid(riid), ret_iface); - if (pUnkOuter) - return CLASS_E_NOAGGREGATION; + *ret_iface = NULL; + if (unk_outer) return CLASS_E_NOAGGREGATION; + if (SUCCEEDED(hr = This->create_instance(&object))) + { + hr = IUnknown_QueryInterface(object, riid, ret_iface); + IUnknown_Release(object); + } - return This->fnCreateInstance(riid, ppv); + return hr; } static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock) @@ -95,9 +102,8 @@ static const IClassFactoryVtbl classfactory_vtbl = { ClassFactory_LockServer }; -static IClassFactoryImpl Synth_CF = {{&classfactory_vtbl}, DMUSIC_CreateDirectMusicSynthImpl}; -static IClassFactoryImpl SynthSink_CF = {{&classfactory_vtbl}, - DMUSIC_CreateDirectMusicSynthSinkImpl}; +static IClassFactoryImpl Synth_CF = {{&classfactory_vtbl}, synth_create}; +static IClassFactoryImpl SynthSink_CF = {{&classfactory_vtbl}, synth_sink_create}; /****************************************************************** diff --git a/dlls/dmsynth/dmsynth_private.h b/dlls/dmsynth/dmsynth_private.h index 35c87775cf7..529b46ca978 100644 --- a/dlls/dmsynth/dmsynth_private.h +++ b/dlls/dmsynth/dmsynth_private.h @@ -43,8 +43,8 @@ /***************************************************************************** * ClassFactory */ -extern HRESULT DMUSIC_CreateDirectMusicSynthImpl(REFIID riid, void **ppobj); -extern HRESULT DMUSIC_CreateDirectMusicSynthSinkImpl(REFIID riid, void **ppobj); +extern HRESULT synth_create(IUnknown **ret_iface); +extern HRESULT synth_sink_create(IUnknown **ret_iface); /***************************************************************************** * Misc. diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index fecbe21c2e3..91826c076e4 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -740,19 +740,18 @@ static const IKsControlVtbl synth_control_vtbl = synth_control_KsEvent, }; -HRESULT DMUSIC_CreateDirectMusicSynthImpl(REFIID riid, void **ppobj) +HRESULT synth_create(IUnknown **ret_iface) { struct synth *obj; - HRESULT hr; - TRACE("(%s, %p)\n", debugstr_guid(riid), ppobj); + TRACE("(%p)\n", ret_iface); - *ppobj = NULL; + *ret_iface = NULL; if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicSynth8_iface.lpVtbl = &synth_vtbl; obj->IKsControl_iface.lpVtbl = &synth_control_vtbl; obj->ref = 1; - /* fill in caps */ + obj->caps.dwSize = sizeof(DMUS_PORTCAPS); obj->caps.dwFlags = DMUS_PC_DLS | DMUS_PC_SOFTWARESYNTH | DMUS_PC_DIRECTSOUND | DMUS_PC_DLS2 | DMUS_PC_AUDIOPATH | DMUS_PC_WAVE; obj->caps.guidPort = CLSID_DirectMusicSynth; @@ -765,8 +764,7 @@ HRESULT DMUSIC_CreateDirectMusicSynthImpl(REFIID riid, void **ppobj) obj->caps.dwEffectFlags = DMUS_EFFECT_REVERB; lstrcpyW(obj->caps.wszDescription, L"Microsoft Synthesizer"); - hr = IDirectMusicSynth8_QueryInterface(&obj->IDirectMusicSynth8_iface, riid, ppobj); - IDirectMusicSynth8_Release(&obj->IDirectMusicSynth8_iface); - - return hr; + TRACE("Created DirectMusicSynth %p\n", obj); + *ret_iface = (IUnknown *)&obj->IDirectMusicSynth8_iface; + return S_OK; } diff --git a/dlls/dmsynth/synthsink.c b/dlls/dmsynth/synthsink.c index 9da462b8074..2d17a3e56bf 100644 --- a/dlls/dmsynth/synthsink.c +++ b/dlls/dmsynth/synthsink.c @@ -373,29 +373,27 @@ static const IKsControlVtbl synth_sink_control = synth_sink_control_KsEvent, }; -HRESULT DMUSIC_CreateDirectMusicSynthSinkImpl(REFIID riid, void **ret_iface) +HRESULT synth_sink_create(IUnknown **ret_iface) { struct synth_sink *obj; HRESULT hr; - TRACE("(%s, %p)\n", debugstr_guid(riid), ret_iface); + TRACE("(%p)\n", ret_iface); *ret_iface = NULL; - if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicSynthSink_iface.lpVtbl = &synth_sink_vtbl; obj->IKsControl_iface.lpVtbl = &synth_sink_control; obj->ref = 1; - hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, &IID_IReferenceClock, (LPVOID*)&obj->latency_clock); + hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, &IID_IReferenceClock, (void **)&obj->latency_clock); if (FAILED(hr)) { free(obj); return hr; } - hr = IDirectMusicSynthSink_QueryInterface(&obj->IDirectMusicSynthSink_iface, riid, ret_iface); - IDirectMusicSynthSink_Release(&obj->IDirectMusicSynthSink_iface); - - return hr; + TRACE("Created DirectMusicSynthSink %p\n", obj); + *ret_iface = (IUnknown *)&obj->IDirectMusicSynthSink_iface; + return S_OK; } From 13d6d0773faabb23e99c23d2078e5e7301a42396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 13:59:42 +0200 Subject: [PATCH 2438/2777] include: Use IReferenceClock interface from strmif.idl in dmusicc.h. (cherry picked from commit 23b61b0dc876f66ab3c9b9719b7ec425412b043d) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/tests/dmsynth.c | 6 ++--- dlls/dmusic/clock.c | 20 ++++++--------- dlls/dmusic/dmusic.c | 18 ++++++-------- dlls/dmusic/tests/dmusic.c | 6 ++--- include/dmusicc.h | 48 ++++-------------------------------- 5 files changed, 27 insertions(+), 71 deletions(-) diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index a27a101bd07..53e04152bee 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -760,20 +760,20 @@ static HRESULT WINAPI test_sink_latency_clock_GetTime(IReferenceClock *iface, RE } static HRESULT WINAPI test_sink_latency_clock_AdviseTime(IReferenceClock *iface, - REFERENCE_TIME base, REFERENCE_TIME offset, HANDLE event, DWORD *cookie) + REFERENCE_TIME base, REFERENCE_TIME offset, HEVENT event, DWORD_PTR *cookie) { ok(0, "unexpected %s\n", __func__); return E_NOTIMPL; } static HRESULT WINAPI test_sink_latency_clock_AdvisePeriodic(IReferenceClock *iface, - REFERENCE_TIME start, REFERENCE_TIME period, HANDLE semaphore, DWORD *cookie) + REFERENCE_TIME start, REFERENCE_TIME period, HSEMAPHORE semaphore, DWORD_PTR *cookie) { ok(0, "unexpected %s\n", __func__); return E_NOTIMPL; } -static HRESULT WINAPI test_sink_latency_clock_Unadvise(IReferenceClock *iface, DWORD cookie) +static HRESULT WINAPI test_sink_latency_clock_Unadvise(IReferenceClock *iface, DWORD_PTR cookie) { ok(0, "unexpected %s\n", __func__); return E_NOTIMPL; diff --git a/dlls/dmusic/clock.c b/dlls/dmusic/clock.c index 19441d3d56f..7b574dd4432 100644 --- a/dlls/dmusic/clock.c +++ b/dlls/dmusic/clock.c @@ -80,30 +80,26 @@ static HRESULT WINAPI IReferenceClockImpl_GetTime(IReferenceClock *iface, REFERE return S_OK; } -static HRESULT WINAPI IReferenceClockImpl_AdviseTime(IReferenceClock *iface, REFERENCE_TIME baseTime, REFERENCE_TIME streamTime, HANDLE hEvent, DWORD* pdwAdviseCookie) +static HRESULT WINAPI IReferenceClockImpl_AdviseTime(IReferenceClock *iface, REFERENCE_TIME base, + REFERENCE_TIME offset, HEVENT event, DWORD_PTR *cookie) { IReferenceClockImpl *This = impl_from_IReferenceClock(iface); - - FIXME("(%p)->(0x%s, 0x%s, %p, %p): stub\n", This, wine_dbgstr_longlong(baseTime), wine_dbgstr_longlong(streamTime), hEvent, pdwAdviseCookie); - + FIXME("(%p)->(%I64d, %I64d, %#Ix, %p): stub\n", This, base, offset, event, cookie); return S_OK; } -static HRESULT WINAPI IReferenceClockImpl_AdvisePeriodic(IReferenceClock *iface, REFERENCE_TIME startTime, REFERENCE_TIME periodTime, HANDLE hSemaphore, DWORD* pdwAdviseCookie) +static HRESULT WINAPI IReferenceClockImpl_AdvisePeriodic(IReferenceClock *iface, REFERENCE_TIME start, + REFERENCE_TIME period, HSEMAPHORE semaphore, DWORD_PTR *cookie) { IReferenceClockImpl *This = impl_from_IReferenceClock(iface); - - FIXME("(%p)->(0x%s, 0x%s, %p, %p): stub\n", This, wine_dbgstr_longlong(startTime), wine_dbgstr_longlong(periodTime), hSemaphore, pdwAdviseCookie); - + FIXME("(%p)->(%I64d, %I64d, %#Ix, %p): stub\n", This, start, period, semaphore, cookie); return S_OK; } -static HRESULT WINAPI IReferenceClockImpl_Unadvise(IReferenceClock *iface, DWORD dwAdviseCookie) +static HRESULT WINAPI IReferenceClockImpl_Unadvise(IReferenceClock *iface, DWORD_PTR cookie) { IReferenceClockImpl *This = impl_from_IReferenceClock(iface); - - FIXME("(%p, %ld): stub\n", This, dwAdviseCookie); - + FIXME("(%p, %#Ix): stub\n", This, cookie); return S_OK; } diff --git a/dlls/dmusic/dmusic.c b/dlls/dmusic/dmusic.c index d284b32fdd7..970fb28ebd2 100644 --- a/dlls/dmusic/dmusic.c +++ b/dlls/dmusic/dmusic.c @@ -96,25 +96,23 @@ static HRESULT WINAPI master_IReferenceClock_GetTime(IReferenceClock *iface, return hr; } -static HRESULT WINAPI master_IReferenceClock_AdviseTime(IReferenceClock *iface, - REFERENCE_TIME base, REFERENCE_TIME offset, HANDLE event, DWORD *cookie) +static HRESULT WINAPI master_IReferenceClock_AdviseTime(IReferenceClock *iface, REFERENCE_TIME base, + REFERENCE_TIME offset, HEVENT event, DWORD_PTR *cookie) { - TRACE("(%p, %s, %s, %p, %p): method not implemented\n", iface, wine_dbgstr_longlong(base), - wine_dbgstr_longlong(offset), event, cookie); + FIXME("(%p, %I64d, %I64d, %#Ix, %p): stub\n", iface, base, offset, event, cookie); return E_NOTIMPL; } -static HRESULT WINAPI master_IReferenceClock_AdvisePeriodic(IReferenceClock *iface, - REFERENCE_TIME start, REFERENCE_TIME period, HANDLE semaphore, DWORD *cookie) +static HRESULT WINAPI master_IReferenceClock_AdvisePeriodic(IReferenceClock *iface, REFERENCE_TIME start, + REFERENCE_TIME period, HSEMAPHORE semaphore, DWORD_PTR *cookie) { - TRACE("(%p, %s, %s, %p, %p): method not implemented\n", iface, wine_dbgstr_longlong(start), - wine_dbgstr_longlong(period), semaphore, cookie); + FIXME("(%p, %I64d, %I64d, %#Ix, %p): stub\n", iface, start, period, semaphore, cookie); return E_NOTIMPL; } -static HRESULT WINAPI master_IReferenceClock_Unadvise(IReferenceClock *iface, DWORD cookie) +static HRESULT WINAPI master_IReferenceClock_Unadvise(IReferenceClock *iface, DWORD_PTR cookie) { - TRACE("(%p, %#lx): method not implemented\n", iface, cookie); + FIXME("(%p, %#Ix): stub\n", iface, cookie); return E_NOTIMPL; } diff --git a/dlls/dmusic/tests/dmusic.c b/dlls/dmusic/tests/dmusic.c index a8152822613..1561c51df76 100644 --- a/dlls/dmusic/tests/dmusic.c +++ b/dlls/dmusic/tests/dmusic.c @@ -862,7 +862,7 @@ static void test_master_clock(void) LARGE_INTEGER counter, freq; DMUS_CLOCKINFO clock_info; IDirectMusic *dmusic; - DWORD cookie; + DWORD_PTR cookie; HRESULT hr; ULONG ref; GUID guid; @@ -912,10 +912,10 @@ static void test_master_clock(void) ok(time2 - time1 > 80 * 10000, "Expected about %s, but got %s.\n", wine_dbgstr_longlong(time1 + 100 * 10000), wine_dbgstr_longlong(time2)); - hr = IReferenceClock_AdviseTime(clock, 0, 0, NULL, &cookie); + hr = IReferenceClock_AdviseTime(clock, 0, 0, 0, &cookie); ok(hr == E_NOTIMPL, "Got hr %#lx.\n", hr); - hr = IReferenceClock_AdvisePeriodic(clock, 0, 0, NULL, &cookie); + hr = IReferenceClock_AdvisePeriodic(clock, 0, 0, 0, &cookie); ok(hr == E_NOTIMPL, "Got hr %#lx.\n", hr); hr = IReferenceClock_Unadvise(clock, 0); diff --git a/include/dmusicc.h b/include/dmusicc.h index 94ff184dc9f..351f2733ee2 100644 --- a/include/dmusicc.h +++ b/include/dmusicc.h @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -108,8 +109,6 @@ typedef struct IDirectMusicPort *LPDIRECTMUSICPORT; typedef struct IDirectMusicPort IDirectMusicPort8, *LPDIRECTMUSICPORT8; typedef struct IDirectMusicThru *LPDIRECTMUSICTHRU; typedef struct IDirectMusicThru IDirectMusicThru8, *LPDIRECTMUSICTHRU8; -typedef struct IReferenceClock *LPREFERENCECLOCK; - /***************************************************************************** * Typedef definitions @@ -381,7 +380,7 @@ DECLARE_INTERFACE_(IDirectMusic,IUnknown) STDMETHOD(CreateMusicBuffer)(THIS_ LPDMUS_BUFFERDESC pBufferDesc, LPDIRECTMUSICBUFFER *ppBuffer, LPUNKNOWN pUnkOuter) PURE; STDMETHOD(CreatePort)(THIS_ REFCLSID rclsidPort, LPDMUS_PORTPARAMS pPortParams, LPDIRECTMUSICPORT *ppPort, LPUNKNOWN pUnkOuter) PURE; STDMETHOD(EnumMasterClock)(THIS_ DWORD dwIndex, LPDMUS_CLOCKINFO lpClockInfo) PURE; - STDMETHOD(GetMasterClock)(THIS_ LPGUID pguidClock, struct IReferenceClock **ppReferenceClock) PURE; + STDMETHOD(GetMasterClock)(THIS_ LPGUID pguidClock, IReferenceClock **ppReferenceClock) PURE; STDMETHOD(SetMasterClock)(THIS_ REFGUID rguidClock) PURE; STDMETHOD(Activate)(THIS_ BOOL fEnable) PURE; STDMETHOD(GetDefaultPort)(THIS_ LPGUID pguidPort) PURE; @@ -422,13 +421,13 @@ DECLARE_INTERFACE_(IDirectMusic8,IDirectMusic) STDMETHOD(CreateMusicBuffer)(THIS_ LPDMUS_BUFFERDESC pBufferDesc, LPDIRECTMUSICBUFFER *ppBuffer, LPUNKNOWN pUnkOuter) PURE; STDMETHOD(CreatePort)(THIS_ REFCLSID rclsidPort, LPDMUS_PORTPARAMS pPortParams, LPDIRECTMUSICPORT *ppPort, LPUNKNOWN pUnkOuter) PURE; STDMETHOD(EnumMasterClock)(THIS_ DWORD dwIndex, LPDMUS_CLOCKINFO lpClockInfo) PURE; - STDMETHOD(GetMasterClock)(THIS_ LPGUID pguidClock, struct IReferenceClock **ppReferenceClock) PURE; + STDMETHOD(GetMasterClock)(THIS_ LPGUID pguidClock, IReferenceClock **ppReferenceClock) PURE; STDMETHOD(SetMasterClock)(THIS_ REFGUID rguidClock) PURE; STDMETHOD(Activate)(THIS_ BOOL fEnable) PURE; STDMETHOD(GetDefaultPort)(THIS_ LPGUID pguidPort) PURE; STDMETHOD(SetDirectSound)(THIS_ LPDIRECTSOUND pDirectSound, HWND hWnd) PURE; /*** IDirectMusic8 methods ***/ - STDMETHOD(SetExternalMasterClock)(THIS_ struct IReferenceClock *pClock) PURE; + STDMETHOD(SetExternalMasterClock)(THIS_ IReferenceClock *pClock) PURE; }; #undef INTERFACE @@ -655,7 +654,7 @@ DECLARE_INTERFACE_(IDirectMusicPort,IUnknown) STDMETHOD(Read)(THIS_ LPDIRECTMUSICBUFFER pBuffer) PURE; STDMETHOD(DownloadInstrument)(THIS_ IDirectMusicInstrument *pInstrument, IDirectMusicDownloadedInstrument **ppDownloadedInstrument, DMUS_NOTERANGE *pNoteRanges, DWORD dwNumNoteRanges) PURE; STDMETHOD(UnloadInstrument)(THIS_ IDirectMusicDownloadedInstrument *pDownloadedInstrument) PURE; - STDMETHOD(GetLatencyClock)(THIS_ struct IReferenceClock **ppClock) PURE; + STDMETHOD(GetLatencyClock)(THIS_ IReferenceClock **ppClock) PURE; STDMETHOD(GetRunningStats)(THIS_ LPDMUS_SYNTHSTATS pStats) PURE; STDMETHOD(Compact)(THIS) PURE; STDMETHOD(GetCaps)(THIS_ LPDMUS_PORTCAPS pPortCaps) PURE; @@ -720,43 +719,6 @@ DECLARE_INTERFACE_(IDirectMusicThru,IUnknown) #define IDirectMusicThru_ThruChannel(p,a,b,c,d,e) (p)->lpVtbl->ThruChannel(p,a,b,c,d,e) #endif - -#ifndef __IReferenceClock_INTERFACE_DEFINED__ -#define __IReferenceClock_INTERFACE_DEFINED__ -DEFINE_GUID(IID_IReferenceClock,0x56a86897,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70); - -/***************************************************************************** - * IReferenceClock interface - */ -#define INTERFACE IReferenceClock -DECLARE_INTERFACE_(IReferenceClock,IUnknown) -{ - /*** IUnknown methods ***/ - STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; - STDMETHOD_(ULONG,AddRef)(THIS) PURE; - STDMETHOD_(ULONG,Release)(THIS) PURE; - /*** IReferenceClock methods ***/ - STDMETHOD(GetTime)(THIS_ REFERENCE_TIME *pTime) PURE; - STDMETHOD(AdviseTime)(THIS_ REFERENCE_TIME baseTime, REFERENCE_TIME streamTime, HANDLE hEvent, DWORD *pdwAdviseCookie) PURE; - STDMETHOD(AdvisePeriodic)(THIS_ REFERENCE_TIME startTime, REFERENCE_TIME periodTime, HANDLE hSemaphore, DWORD *pdwAdviseCookie) PURE; - STDMETHOD(Unadvise)(THIS_ DWORD dwAdviseCookie) PURE; -}; -#undef INTERFACE - -#if !defined(__cplusplus) || defined(CINTERFACE) -/*** IUnknown methods ***/ -#define IReferenceClock_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) -#define IReferenceClock_AddRef(p) (p)->lpVtbl->AddRef(p) -#define IReferenceClock_Release(p) (p)->lpVtbl->Release(p) -/*** IReferenceClock methods ***/ -#define IReferenceClock_GetTime(p,a) (p)->lpVtbl->GetTime(p,a) -#define IReferenceClock_AdviseTime(p,a,b,c,d) (p)->lpVtbl->AdviseTime(p,a,b,c,d) -#define IReferenceClock_AdvisePeriodic(p,a,b,c,d) (p)->lpVtbl->AdvisePeriodic(p,a,b,c,d) -#define IReferenceClock_Unadvise(p,a) (p)->lpVtbl->Unadvise(p,a) -#endif - -#endif /* __IReferenceClock_INTERFACE_DEFINED__ */ - #ifdef __cplusplus } #endif From 9819152651a9b2b252b2e6763953f1fcedd805fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 6 Sep 2023 08:29:37 +0200 Subject: [PATCH 2439/2777] dmsynth: Implement latency IReferenceClock interface on the sink. (cherry picked from commit 2a1b03ccc35148ae09bb40438613c89f26bb6a56) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synthsink.c | 97 +++++++++++++++++++++++++++++++----- dlls/dmsynth/tests/dmsynth.c | 12 ++--- 2 files changed, 90 insertions(+), 19 deletions(-) diff --git a/dlls/dmsynth/synthsink.c b/dlls/dmsynth/synthsink.c index 2d17a3e56bf..db1fecb8d48 100644 --- a/dlls/dmsynth/synthsink.c +++ b/dlls/dmsynth/synthsink.c @@ -31,15 +31,16 @@ struct synth_sink { IDirectMusicSynthSink IDirectMusicSynthSink_iface; IKsControl IKsControl_iface; + IReferenceClock IReferenceClock_iface; LONG ref; - IReferenceClock *latency_clock; IReferenceClock *master_clock; IDirectMusicSynth *synth; /* No reference hold! */ IDirectSound *dsound; BOOL active; REFERENCE_TIME activate_time; + REFERENCE_TIME latency_time; }; static inline struct synth_sink *impl_from_IDirectMusicSynthSink(IDirectMusicSynthSink *iface) @@ -76,6 +77,7 @@ static HRESULT synth_sink_activate(struct synth_sink *This) if (This->active) return DMUS_E_SYNTHACTIVE; if (FAILED(hr = IReferenceClock_GetTime(This->master_clock, &This->activate_time))) return hr; + This->latency_time = This->activate_time; This->active = TRUE; return S_OK; @@ -133,8 +135,6 @@ static ULONG WINAPI synth_sink_Release(IDirectMusicSynthSink *iface) TRACE("(%p): new ref = %lu\n", This, ref); if (!ref) { - if (This->latency_clock) - IReferenceClock_Release(This->latency_clock); if (This->master_clock) IReferenceClock_Release(This->master_clock); free(This); @@ -184,8 +184,8 @@ static HRESULT WINAPI synth_sink_GetLatencyClock(IDirectMusicSynthSink *iface, if (!clock) return E_POINTER; - *clock = This->latency_clock; - IReferenceClock_AddRef(This->latency_clock); + *clock = &This->IReferenceClock_iface; + IReferenceClock_AddRef(*clock); return S_OK; } @@ -373,10 +373,87 @@ static const IKsControlVtbl synth_sink_control = synth_sink_control_KsEvent, }; +static inline struct synth_sink *impl_from_IReferenceClock(IReferenceClock *iface) +{ + return CONTAINING_RECORD(iface, struct synth_sink, IReferenceClock_iface); +} + +static HRESULT WINAPI latency_clock_QueryInterface(IReferenceClock *iface, REFIID iid, void **out) +{ + TRACE("(%p, %s, %p)\n", iface, debugstr_dmguid(iid), out); + + if (IsEqualIID(iid, &IID_IUnknown) + || IsEqualIID(iid, &IID_IReferenceClock)) + { + IUnknown_AddRef(iface); + *out = iface; + return S_OK; + } + + FIXME("no interface for %s\n", debugstr_dmguid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI latency_clock_AddRef(IReferenceClock *iface) +{ + struct synth_sink *This = impl_from_IReferenceClock(iface); + return IDirectMusicSynthSink_AddRef(&This->IDirectMusicSynthSink_iface); +} + +static ULONG WINAPI latency_clock_Release(IReferenceClock *iface) +{ + struct synth_sink *This = impl_from_IReferenceClock(iface); + return IDirectMusicSynthSink_Release(&This->IDirectMusicSynthSink_iface); +} + +static HRESULT WINAPI latency_clock_GetTime(IReferenceClock *iface, REFERENCE_TIME *time) +{ + struct synth_sink *This = impl_from_IReferenceClock(iface); + + TRACE("(%p, %p)\n", iface, time); + + if (!time) return E_INVALIDARG; + if (!This->active) return E_FAIL; + *time = This->latency_time; + + return S_OK; +} + +static HRESULT WINAPI latency_clock_AdviseTime(IReferenceClock *iface, REFERENCE_TIME base, + REFERENCE_TIME offset, HEVENT event, DWORD_PTR *cookie) +{ + FIXME("(%p, %I64d, %I64d, %#Ix, %p): stub\n", iface, base, offset, event, cookie); + return E_NOTIMPL; +} + +static HRESULT WINAPI latency_clock_AdvisePeriodic(IReferenceClock *iface, REFERENCE_TIME start, + REFERENCE_TIME period, HSEMAPHORE semaphore, DWORD_PTR *cookie) +{ + FIXME("(%p, %I64d, %I64d, %#Ix, %p): stub\n", iface, start, period, semaphore, cookie); + return E_NOTIMPL; +} + +static HRESULT WINAPI latency_clock_Unadvise(IReferenceClock *iface, DWORD_PTR cookie) +{ + FIXME("(%p, %#Ix): stub\n", iface, cookie); + return E_NOTIMPL; +} + +static const IReferenceClockVtbl latency_clock_vtbl = +{ + latency_clock_QueryInterface, + latency_clock_AddRef, + latency_clock_Release, + latency_clock_GetTime, + latency_clock_AdviseTime, + latency_clock_AdvisePeriodic, + latency_clock_Unadvise, +}; + HRESULT synth_sink_create(IUnknown **ret_iface) { struct synth_sink *obj; - HRESULT hr; TRACE("(%p)\n", ret_iface); @@ -384,15 +461,9 @@ HRESULT synth_sink_create(IUnknown **ret_iface) if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicSynthSink_iface.lpVtbl = &synth_sink_vtbl; obj->IKsControl_iface.lpVtbl = &synth_sink_control; + obj->IReferenceClock_iface.lpVtbl = &latency_clock_vtbl; obj->ref = 1; - hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, &IID_IReferenceClock, (void **)&obj->latency_clock); - if (FAILED(hr)) - { - free(obj); - return hr; - } - TRACE("Created DirectMusicSynthSink %p\n", obj); *ret_iface = (IUnknown *)&obj->IDirectMusicSynthSink_iface; return S_OK; diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index 53e04152bee..61bfeda072c 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -1222,12 +1222,12 @@ static void test_IDirectMusicSynthSink(void) ok(hr == S_OK, "got %#lx\n", hr); ok(latency_clock != clock, "got same clock\n"); ref = get_refcount(sink); - todo_wine ok(ref == 2, "got %#lx\n", ref); + ok(ref == 2, "got %#lx\n", ref); hr = IReferenceClock_GetTime(latency_clock, NULL); - todo_wine ok(hr == E_INVALIDARG, "got %#lx\n", hr); + ok(hr == E_INVALIDARG, "got %#lx\n", hr); hr = IReferenceClock_GetTime(latency_clock, &time); - todo_wine ok(hr == E_FAIL, "got %#lx\n", hr); + ok(hr == E_FAIL, "got %#lx\n", hr); hr = IDirectMusicSynthSink_Init(sink, NULL); ok(hr == S_OK, "got %#lx\n", hr); @@ -1255,7 +1255,7 @@ static void test_IDirectMusicSynthSink(void) hr = IDirectMusicSynthSink_SetMasterClock(sink, clock); ok(hr == S_OK, "got %#lx\n", hr); hr = IReferenceClock_GetTime(latency_clock, &time); - todo_wine ok(hr == E_FAIL, "got %#lx\n", hr); + ok(hr == E_FAIL, "got %#lx\n", hr); hr = IDirectMusicSynthSink_Activate(sink, TRUE); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicSynthSink_Activate(sink, TRUE); @@ -1283,8 +1283,8 @@ static void test_IDirectMusicSynthSink(void) /* latency clock now works fine */ tmp_time = time; hr = IReferenceClock_GetTime(latency_clock, &tmp_time); - todo_wine_if(hr == S_FALSE) ok(hr == S_OK, "got %#lx\n", hr); - todo_wine_if(tmp_time <= time) ok(tmp_time > time, "got %I64d\n", tmp_time - time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(tmp_time > time, "got %I64d\n", tmp_time - time); ok(tmp_time - time <= 2000000, "got %I64d\n", tmp_time - time); /* setting the clock while active is fine */ From 5ff1845802d6ebbe517f31f14693afedadc124d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 29 Aug 2023 14:24:00 +0200 Subject: [PATCH 2440/2777] dmsynth: Forward IDirectMusicSynth_GetLatencyClock to the sink. (cherry picked from commit 722262b023e1840abd91f0370930bfd6e7b2e025) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 25 ++++--------------------- dlls/dmsynth/tests/dmsynth.c | 6 +++--- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 91826c076e4..967de01e95c 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -41,7 +41,6 @@ struct synth DMUS_PORTPARAMS params; BOOL active; BOOL open; - IReferenceClock *latency_clock; IDirectMusicSynthSink *sink; }; @@ -96,11 +95,7 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) TRACE("(%p): new ref = %lu\n", This, ref); - if (!ref) { - if (This->latency_clock) - IReferenceClock_Release(This->latency_clock); - free(This); - } + if (!ref) free(This); return ref; } @@ -417,14 +412,10 @@ static HRESULT WINAPI synth_GetLatencyClock(IDirectMusicSynth8 *iface, if (!clock) return E_POINTER; - if (!This->sink) return DMUS_E_NOSYNTHSINK; - *clock = This->latency_clock; - IReferenceClock_AddRef(This->latency_clock); - - return S_OK; + return IDirectMusicSynthSink_GetLatencyClock(This->sink, clock); } static HRESULT WINAPI synth_Activate(IDirectMusicSynth8 *iface, BOOL enable) @@ -460,28 +451,20 @@ static HRESULT WINAPI synth_SetSynthSink(IDirectMusicSynth8 *iface, IDirectMusicSynthSink *sink) { struct synth *This = impl_from_IDirectMusicSynth8(iface); - HRESULT hr; TRACE("(%p)->(%p)\n", iface, sink); if (sink == This->sink) return S_OK; - if (!sink || This->sink) { - /* Disconnect the sink */ - if (This->latency_clock) - IReferenceClock_Release(This->latency_clock); - IDirectMusicSynthSink_Release(This->sink); - } + if (!sink || This->sink) IDirectMusicSynthSink_Release(This->sink); This->sink = sink; if (!sink) return S_OK; IDirectMusicSynthSink_AddRef(This->sink); - if (FAILED(hr = IDirectMusicSynthSink_Init(sink, (IDirectMusicSynth *)iface))) - return hr; - return IDirectMusicSynthSink_GetLatencyClock(sink, &This->latency_clock); + return IDirectMusicSynthSink_Init(sink, (IDirectMusicSynth *)iface); } static HRESULT WINAPI synth_Render(IDirectMusicSynth8 *iface, short *buffer, diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index 61bfeda072c..bdad58abdcf 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -1014,7 +1014,7 @@ static void test_IDirectMusicSynth(void) hr = IDirectMusicSynth_SetSynthSink(synth, sink); ok(hr == S_OK, "got %#lx\n", hr); ref = get_refcount(sink); - todo_wine ok(ref == 2, "got %lu\n", ref); + ok(ref == 2, "got %lu\n", ref); hr = IDirectMusicSynth_Activate(synth, TRUE); todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); @@ -1062,7 +1062,7 @@ static void test_IDirectMusicSynth(void) hr = IDirectMusicSynth_SetSynthSink(synth, sink); ok(hr == S_OK, "got %#lx\n", hr); ref = get_refcount(sink); - todo_wine ok(ref == 2, "got %lu\n", ref); + ok(ref == 2, "got %lu\n", ref); hr = IDirectMusicSynth_Activate(synth, TRUE); todo_wine ok(hr == S_OK, "got %#lx\n", hr); @@ -1145,7 +1145,7 @@ static void test_IDirectMusicSynth(void) IDirectMusicSynth_Release(synth); - if (strcmp(winetest_platform, "wine")) IDirectMusicSynthSink_Release(sink); + IDirectMusicSynthSink_Release(sink); IReferenceClock_Release(clock); IDirectMusic_Release(music); } From b2db3743aa082e3f1b395d7a9a7fb48335e8f1e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 29 Aug 2023 14:28:50 +0200 Subject: [PATCH 2441/2777] dmsynth: Return S_FALSE if IDirectMusicSynth_Activate is no-op. (cherry picked from commit f6deca5932d5bc7d0449f508a99f0b413b697944) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 9 ++------- dlls/dmsynth/tests/dmsynth.c | 4 ++-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 967de01e95c..a63bfe24f7b 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -425,16 +425,11 @@ static HRESULT WINAPI synth_Activate(IDirectMusicSynth8 *iface, BOOL enable) TRACE("(%p)->(%d)\n", This, enable); + if (enable == This->active) return S_FALSE; + if (!This->sink) return DMUS_E_NOSYNTHSINK; - if (enable == This->active) { - if (enable) - return DMUS_E_SYNTHACTIVE; - else - return S_FALSE; - } - if ((hr = IDirectMusicSynthSink_Activate(This->sink, enable)) != S_OK) { if (hr == DMUS_E_SYNTHACTIVE || hr == S_FALSE) WARN("Synth and sink active state out of sync. Fixing.\n"); diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index bdad58abdcf..5d60edd3b01 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -1007,7 +1007,7 @@ static void test_IDirectMusicSynth(void) hr = IDirectMusicSynth_Activate(synth, TRUE); ok(hr == DMUS_E_NOSYNTHSINK, "got %#lx\n", hr); hr = IDirectMusicSynth_Activate(synth, FALSE); - todo_wine ok(hr == S_FALSE, "got %#lx\n", hr); + ok(hr == S_FALSE, "got %#lx\n", hr); hr = IDirectMusicSynth_SetSynthSink(synth, NULL); ok(hr == S_OK, "got %#lx\n", hr); @@ -1034,7 +1034,7 @@ static void test_IDirectMusicSynth(void) hr = IDirectMusicSynth_Activate(synth, TRUE); todo_wine ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicSynth_Activate(synth, TRUE); - todo_wine ok(hr == S_FALSE, "got %#lx\n", hr); + ok(hr == S_FALSE, "got %#lx\n", hr); /* Close is fine while active */ hr = IDirectMusicSynth_Close(synth); From 3cf92b0d0e33e5c0ba7bc6f90a012acf0f6da884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Sep 2023 13:42:41 +0200 Subject: [PATCH 2442/2777] dmsynth: Return DMUS_E_SYNTHNOTCONFIGURED when sink fails to activate. (cherry picked from commit 54ed994ab1cf2b0dae0857c6f7bbf9c04021ddef) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 15 +++++++++------ dlls/dmsynth/tests/dmsynth.c | 8 ++++---- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index a63bfe24f7b..a93b23133f4 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -428,13 +428,16 @@ static HRESULT WINAPI synth_Activate(IDirectMusicSynth8 *iface, BOOL enable) if (enable == This->active) return S_FALSE; if (!This->sink) - return DMUS_E_NOSYNTHSINK; + { + This->active = FALSE; + return enable ? DMUS_E_NOSYNTHSINK : DMUS_E_SYNTHNOTCONFIGURED; + } - if ((hr = IDirectMusicSynthSink_Activate(This->sink, enable)) != S_OK) { - if (hr == DMUS_E_SYNTHACTIVE || hr == S_FALSE) - WARN("Synth and sink active state out of sync. Fixing.\n"); - else - return hr; + if (FAILED(hr = IDirectMusicSynthSink_Activate(This->sink, enable)) + && hr != DMUS_E_SYNTHACTIVE) + { + This->active = FALSE; + return DMUS_E_SYNTHNOTCONFIGURED; } This->active = enable; diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index 5d60edd3b01..46727afe557 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -1016,7 +1016,7 @@ static void test_IDirectMusicSynth(void) ref = get_refcount(sink); ok(ref == 2, "got %lu\n", ref); hr = IDirectMusicSynth_Activate(synth, TRUE); - todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); /* SetMasterClock does nothing */ hr = IDirectMusicSynth_SetMasterClock(synth, NULL); @@ -1047,9 +1047,9 @@ static void test_IDirectMusicSynth(void) /* but Activate might fail then */ hr = IDirectMusicSynth_Activate(synth, FALSE); - todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); hr = IDirectMusicSynth_Activate(synth, FALSE); - todo_wine ok(hr == S_FALSE, "got %#lx\n", hr); + ok(hr == S_FALSE, "got %#lx\n", hr); /* Test generating some samples */ @@ -1064,7 +1064,7 @@ static void test_IDirectMusicSynth(void) ref = get_refcount(sink); ok(ref == 2, "got %lu\n", ref); hr = IDirectMusicSynth_Activate(synth, TRUE); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); GetTempPathW(MAX_PATH, temp_path); GetTempFileNameW(temp_path, L"synth", 0, temp_file); From b01ddcd9ba50d942ad2b344b17e0a3e6de9ccf5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 10:56:55 +0200 Subject: [PATCH 2443/2777] dmusic: Move constructor parameter checks to class factory. (cherry picked from commit ed4327eef2ad178559e7d317caf1e89ecc9f9c86) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 41 ++++++++++++++---------------------- dlls/dmusic/dmusic.c | 20 ++++++------------ dlls/dmusic/dmusic_main.c | 26 +++++++++++++++-------- dlls/dmusic/dmusic_private.h | 4 ++-- 4 files changed, 41 insertions(+), 50 deletions(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 3f1c70b01e3..46939aad65f 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -520,31 +520,22 @@ static const IPersistStreamVtbl persiststream_vtbl = { unimpl_IPersistStream_GetSizeMax }; - -HRESULT DMUSIC_CreateDirectMusicCollectionImpl(REFIID lpcGUID, void **ppobj, IUnknown *pUnkOuter) +HRESULT collection_create(IUnknown **ret_iface) { - IDirectMusicCollectionImpl* obj; - HRESULT hr; - - *ppobj = NULL; - if (pUnkOuter) - return CLASS_E_NOAGGREGATION; - - obj = calloc(1, sizeof(IDirectMusicCollectionImpl)); - if (!obj) - return E_OUTOFMEMORY; - - obj->IDirectMusicCollection_iface.lpVtbl = &DirectMusicCollection_Collection_Vtbl; - obj->ref = 1; - dmobject_init(&obj->dmobj, &CLSID_DirectMusicCollection, - (IUnknown*)&obj->IDirectMusicCollection_iface); - obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl; - obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - - list_init (&obj->Instruments); + IDirectMusicCollectionImpl *obj; - hr = IDirectMusicCollection_QueryInterface(&obj->IDirectMusicCollection_iface, lpcGUID, ppobj); - IDirectMusicCollection_Release(&obj->IDirectMusicCollection_iface); - - return hr; + *ret_iface = NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; + obj->IDirectMusicCollection_iface.lpVtbl = &DirectMusicCollection_Collection_Vtbl; + obj->ref = 1; + dmobject_init(&obj->dmobj, &CLSID_DirectMusicCollection, + (IUnknown *)&obj->IDirectMusicCollection_iface); + obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl; + obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; + + list_init(&obj->Instruments); + + TRACE("Created DirectMusicCollection %p\n", obj); + *ret_iface = (IUnknown *)&obj->IDirectMusicCollection_iface; + return S_OK; } diff --git a/dlls/dmusic/dmusic.c b/dlls/dmusic/dmusic.c index 970fb28ebd2..57a39d1465c 100644 --- a/dlls/dmusic/dmusic.c +++ b/dlls/dmusic/dmusic.c @@ -577,22 +577,15 @@ static void create_system_ports_list(IDirectMusic8Impl* object) object->num_system_ports = nb_ports; } -/* For ClassFactory */ -HRESULT DMUSIC_CreateDirectMusicImpl(REFIID riid, void **ret_iface, IUnknown *unkouter) +HRESULT music_create(IUnknown **ret_iface) { IDirectMusic8Impl *dmusic; HRESULT ret; - TRACE("(%s, %p, %p)\n", debugstr_guid(riid), ret_iface, unkouter); + TRACE("(%p)\n", ret_iface); *ret_iface = NULL; - if (unkouter) - return CLASS_E_NOAGGREGATION; - - dmusic = calloc(1, sizeof(IDirectMusic8Impl)); - if (!dmusic) - return E_OUTOFMEMORY; - + if (!(dmusic = calloc(1, sizeof(*dmusic)))) return E_OUTOFMEMORY; dmusic->IDirectMusic8_iface.lpVtbl = &DirectMusic8_Vtbl; dmusic->ref = 1; ret = master_clock_create(&dmusic->master_clock); @@ -603,8 +596,7 @@ HRESULT DMUSIC_CreateDirectMusicImpl(REFIID riid, void **ret_iface, IUnknown *un create_system_ports_list(dmusic); - ret = IDirectMusic8Impl_QueryInterface(&dmusic->IDirectMusic8_iface, riid, ret_iface); - IDirectMusic8_Release(&dmusic->IDirectMusic8_iface); - - return ret; + TRACE("Created DirectMusic %p\n", dmusic); + *ret_iface = (IUnknown *)&dmusic->IDirectMusic8_iface; + return S_OK; } diff --git a/dlls/dmusic/dmusic_main.c b/dlls/dmusic/dmusic_main.c index 509e80f872b..f0aaca8947a 100644 --- a/dlls/dmusic/dmusic_main.c +++ b/dlls/dmusic/dmusic_main.c @@ -41,7 +41,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmusic); typedef struct { IClassFactory IClassFactory_iface; - HRESULT (*fnCreateInstance)(REFIID riid, void **ppv, IUnknown *pUnkOuter); + HRESULT (*create_instance)(IUnknown **ret_iface); } IClassFactoryImpl; /****************************************************************** @@ -82,14 +82,23 @@ static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) return 1; /* non-heap based object */ } -static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, - REFIID riid, void **ppv) +static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *unk_outer, REFIID riid, void **ret_iface) { - IClassFactoryImpl *This = impl_from_IClassFactory(iface); + IClassFactoryImpl *This = impl_from_IClassFactory(iface); + IUnknown *object; + HRESULT hr; - TRACE ("(%p, %s, %p)\n", pUnkOuter, debugstr_dmguid(riid), ppv); + TRACE("(%p, %s, %p)\n", unk_outer, debugstr_dmguid(riid), ret_iface); - return This->fnCreateInstance(riid, ppv, pUnkOuter); + *ret_iface = NULL; + if (unk_outer) return CLASS_E_NOAGGREGATION; + if (SUCCEEDED(hr = This->create_instance(&object))) + { + hr = IUnknown_QueryInterface(object, riid, ret_iface); + IUnknown_Release(object); + } + + return hr; } static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock) @@ -106,9 +115,8 @@ static const IClassFactoryVtbl classfactory_vtbl = { ClassFactory_LockServer }; -static IClassFactoryImpl DirectMusic_CF = {{&classfactory_vtbl}, DMUSIC_CreateDirectMusicImpl}; -static IClassFactoryImpl Collection_CF = {{&classfactory_vtbl}, - DMUSIC_CreateDirectMusicCollectionImpl}; +static IClassFactoryImpl DirectMusic_CF = {{&classfactory_vtbl}, music_create}; +static IClassFactoryImpl Collection_CF = {{&classfactory_vtbl}, collection_create}; diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 1eea2f845cb..85b64fb0470 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -94,8 +94,8 @@ typedef struct instrument_articulation { */ /* CLSID */ -extern HRESULT DMUSIC_CreateDirectMusicImpl(REFIID riid, void **ret_iface, IUnknown *pUnkOuter); -extern HRESULT DMUSIC_CreateDirectMusicCollectionImpl(REFIID riid, void **ppobj, IUnknown *pUnkOuter); +extern HRESULT music_create(IUnknown **ret_iface); +extern HRESULT collection_create(IUnknown **ret_iface); /* Internal */ extern HRESULT DMUSIC_CreateDirectMusicBufferImpl(LPDMUS_BUFFERDESC desc, LPVOID* ret_iface); From cca1ef228456ac97d7cf248b5d3075ed1c9386ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 6 Sep 2023 09:17:51 +0200 Subject: [PATCH 2444/2777] dmusic: Rename IDirectMusicCollectionImpl method prefix to collection. (cherry picked from commit 150240104224350f586ec88b79a4ec9a420b3f67) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 49 ++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 46939aad65f..2ff53a0fe23 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -54,8 +54,7 @@ static inline IDirectMusicCollectionImpl *impl_from_IPersistStream(IPersistStrea return CONTAINING_RECORD(iface, IDirectMusicCollectionImpl, dmobj.IPersistStream_iface); } -/* IDirectMusicCollectionImpl IUnknown part: */ -static HRESULT WINAPI IDirectMusicCollectionImpl_QueryInterface(IDirectMusicCollection *iface, +static HRESULT WINAPI collection_QueryInterface(IDirectMusicCollection *iface, REFIID riid, void **ret_iface) { IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface); @@ -80,7 +79,7 @@ static HRESULT WINAPI IDirectMusicCollectionImpl_QueryInterface(IDirectMusicColl return S_OK; } -static ULONG WINAPI IDirectMusicCollectionImpl_AddRef(IDirectMusicCollection *iface) +static ULONG WINAPI collection_AddRef(IDirectMusicCollection *iface) { IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface); ULONG ref = InterlockedIncrement(&This->ref); @@ -90,7 +89,7 @@ static ULONG WINAPI IDirectMusicCollectionImpl_AddRef(IDirectMusicCollection *if return ref; } -static ULONG WINAPI IDirectMusicCollectionImpl_Release(IDirectMusicCollection *iface) +static ULONG WINAPI collection_Release(IDirectMusicCollection *iface) { IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface); ULONG ref = InterlockedDecrement(&This->ref); @@ -104,8 +103,7 @@ static ULONG WINAPI IDirectMusicCollectionImpl_Release(IDirectMusicCollection *i return ref; } -/* IDirectMusicCollection Interface follows: */ -static HRESULT WINAPI IDirectMusicCollectionImpl_GetInstrument(IDirectMusicCollection *iface, +static HRESULT WINAPI collection_GetInstrument(IDirectMusicCollection *iface, DWORD patch, IDirectMusicInstrument **instrument) { IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface); @@ -132,7 +130,7 @@ static HRESULT WINAPI IDirectMusicCollectionImpl_GetInstrument(IDirectMusicColle return DMUS_E_INVALIDPATCH; } -static HRESULT WINAPI IDirectMusicCollectionImpl_EnumInstrument(IDirectMusicCollection *iface, +static HRESULT WINAPI collection_EnumInstrument(IDirectMusicCollection *iface, DWORD index, DWORD *patch, LPWSTR name, DWORD name_length) { IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface); @@ -161,16 +159,16 @@ static HRESULT WINAPI IDirectMusicCollectionImpl_EnumInstrument(IDirectMusicColl return S_FALSE; } -static const IDirectMusicCollectionVtbl DirectMusicCollection_Collection_Vtbl = { - IDirectMusicCollectionImpl_QueryInterface, - IDirectMusicCollectionImpl_AddRef, - IDirectMusicCollectionImpl_Release, - IDirectMusicCollectionImpl_GetInstrument, - IDirectMusicCollectionImpl_EnumInstrument +static const IDirectMusicCollectionVtbl collection_vtbl = +{ + collection_QueryInterface, + collection_AddRef, + collection_Release, + collection_GetInstrument, + collection_EnumInstrument, }; -/* IDirectMusicCollectionImpl IDirectMusicObject part: */ -static HRESULT WINAPI col_IDirectMusicObject_ParseDescriptor(IDirectMusicObject *iface, +static HRESULT WINAPI collection_object_ParseDescriptor(IDirectMusicObject *iface, IStream *stream, DMUS_OBJECTDESC *desc) { struct chunk_entry riff = {0}; @@ -201,17 +199,17 @@ static HRESULT WINAPI col_IDirectMusicObject_ParseDescriptor(IDirectMusicObject return S_OK; } -static const IDirectMusicObjectVtbl dmobject_vtbl = { +static const IDirectMusicObjectVtbl collection_object_vtbl = +{ dmobj_IDirectMusicObject_QueryInterface, dmobj_IDirectMusicObject_AddRef, dmobj_IDirectMusicObject_Release, dmobj_IDirectMusicObject_GetDescriptor, dmobj_IDirectMusicObject_SetDescriptor, - col_IDirectMusicObject_ParseDescriptor + collection_object_ParseDescriptor, }; -/* IDirectMusicCollectionImpl IPersistStream part: */ -static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface, +static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream *stream) { IDirectMusicCollectionImpl *This = impl_from_IPersistStream(iface); @@ -509,15 +507,16 @@ static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface, return S_OK; } -static const IPersistStreamVtbl persiststream_vtbl = { +static const IPersistStreamVtbl collection_stream_vtbl = +{ dmobj_IPersistStream_QueryInterface, dmobj_IPersistStream_AddRef, dmobj_IPersistStream_Release, unimpl_IPersistStream_GetClassID, unimpl_IPersistStream_IsDirty, - IPersistStreamImpl_Load, + collection_stream_Load, unimpl_IPersistStream_Save, - unimpl_IPersistStream_GetSizeMax + unimpl_IPersistStream_GetSizeMax, }; HRESULT collection_create(IUnknown **ret_iface) @@ -526,12 +525,12 @@ HRESULT collection_create(IUnknown **ret_iface) *ret_iface = NULL; if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; - obj->IDirectMusicCollection_iface.lpVtbl = &DirectMusicCollection_Collection_Vtbl; + obj->IDirectMusicCollection_iface.lpVtbl = &collection_vtbl; obj->ref = 1; dmobject_init(&obj->dmobj, &CLSID_DirectMusicCollection, (IUnknown *)&obj->IDirectMusicCollection_iface); - obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl; - obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; + obj->dmobj.IDirectMusicObject_iface.lpVtbl = &collection_object_vtbl; + obj->dmobj.IPersistStream_iface.lpVtbl = &collection_stream_vtbl; list_init(&obj->Instruments); From 5043ebf907ddee84bfb730248ec23feccfa77614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 6 Sep 2023 09:19:52 +0200 Subject: [PATCH 2445/2777] dmusic: Get rid of the IDirectMusicCollectionImpl typedef. (cherry picked from commit 849c7a6ae15942c1efb10ef5e81c6191bee918bb) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 56 +++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 2ff53a0fe23..7223aa23bdb 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -24,14 +24,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmusic); WINE_DECLARE_DEBUG_CHANNEL(dmfile); -/***************************************************************************** - * IDirectMusicCollectionImpl implementation - */ -typedef struct IDirectMusicCollectionImpl { +struct collection +{ IDirectMusicCollection IDirectMusicCollection_iface; struct dmobject dmobj; LONG ref; - /* IDirectMusicCollectionImpl fields */ + IStream *pStm; /* stream from which we load collection and later instruments */ LARGE_INTEGER liCollectionPosition; /* offset in a stream where collection was loaded from */ LARGE_INTEGER liWavePoolTablePosition; /* offset in a stream where wave pool table can be found */ @@ -42,22 +40,22 @@ typedef struct IDirectMusicCollectionImpl { POOLCUE *pPoolCues; /* instruments */ struct list Instruments; -} IDirectMusicCollectionImpl; +}; -static inline IDirectMusicCollectionImpl *impl_from_IDirectMusicCollection(IDirectMusicCollection *iface) +static inline struct collection *impl_from_IDirectMusicCollection(IDirectMusicCollection *iface) { - return CONTAINING_RECORD(iface, IDirectMusicCollectionImpl, IDirectMusicCollection_iface); + return CONTAINING_RECORD(iface, struct collection, IDirectMusicCollection_iface); } -static inline IDirectMusicCollectionImpl *impl_from_IPersistStream(IPersistStream *iface) +static inline struct collection *impl_from_IPersistStream(IPersistStream *iface) { - return CONTAINING_RECORD(iface, IDirectMusicCollectionImpl, dmobj.IPersistStream_iface); + return CONTAINING_RECORD(iface, struct collection, dmobj.IPersistStream_iface); } static HRESULT WINAPI collection_QueryInterface(IDirectMusicCollection *iface, REFIID riid, void **ret_iface) { - IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface); + struct collection *This = impl_from_IDirectMusicCollection(iface); TRACE("(%p, %s, %p)\n", iface, debugstr_dmguid(riid), ret_iface); @@ -81,7 +79,7 @@ static HRESULT WINAPI collection_QueryInterface(IDirectMusicCollection *iface, static ULONG WINAPI collection_AddRef(IDirectMusicCollection *iface) { - IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface); + struct collection *This = impl_from_IDirectMusicCollection(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p): new ref = %lu\n", iface, ref); @@ -91,7 +89,7 @@ static ULONG WINAPI collection_AddRef(IDirectMusicCollection *iface) static ULONG WINAPI collection_Release(IDirectMusicCollection *iface) { - IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface); + struct collection *This = impl_from_IDirectMusicCollection(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p): new ref = %lu\n", iface, ref); @@ -106,7 +104,7 @@ static ULONG WINAPI collection_Release(IDirectMusicCollection *iface) static HRESULT WINAPI collection_GetInstrument(IDirectMusicCollection *iface, DWORD patch, IDirectMusicInstrument **instrument) { - IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface); + struct collection *This = impl_from_IDirectMusicCollection(iface); DMUS_PRIVATE_INSTRUMENTENTRY *inst_entry; struct list *list_entry; DWORD inst_patch; @@ -133,7 +131,7 @@ static HRESULT WINAPI collection_GetInstrument(IDirectMusicCollection *iface, static HRESULT WINAPI collection_EnumInstrument(IDirectMusicCollection *iface, DWORD index, DWORD *patch, LPWSTR name, DWORD name_length) { - IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface); + struct collection *This = impl_from_IDirectMusicCollection(iface); DWORD i = 0; DMUS_PRIVATE_INSTRUMENTENTRY *inst_entry; struct list *list_entry; @@ -212,7 +210,7 @@ static const IDirectMusicObjectVtbl collection_object_vtbl = static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream *stream) { - IDirectMusicCollectionImpl *This = impl_from_IPersistStream(iface); + struct collection *This = impl_from_IPersistStream(iface); DMUS_PRIVATE_CHUNK chunk; DWORD StreamSize, StreamCount, ListSize[2], ListCount[2]; LARGE_INTEGER liMove; /* used when skipping chunks */ @@ -521,20 +519,20 @@ static const IPersistStreamVtbl collection_stream_vtbl = HRESULT collection_create(IUnknown **ret_iface) { - IDirectMusicCollectionImpl *obj; + struct collection *collection; *ret_iface = NULL; - if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; - obj->IDirectMusicCollection_iface.lpVtbl = &collection_vtbl; - obj->ref = 1; - dmobject_init(&obj->dmobj, &CLSID_DirectMusicCollection, - (IUnknown *)&obj->IDirectMusicCollection_iface); - obj->dmobj.IDirectMusicObject_iface.lpVtbl = &collection_object_vtbl; - obj->dmobj.IPersistStream_iface.lpVtbl = &collection_stream_vtbl; - - list_init(&obj->Instruments); - - TRACE("Created DirectMusicCollection %p\n", obj); - *ret_iface = (IUnknown *)&obj->IDirectMusicCollection_iface; + if (!(collection = calloc(1, sizeof(*collection)))) return E_OUTOFMEMORY; + collection->IDirectMusicCollection_iface.lpVtbl = &collection_vtbl; + collection->ref = 1; + dmobject_init(&collection->dmobj, &CLSID_DirectMusicCollection, + (IUnknown *)&collection->IDirectMusicCollection_iface); + collection->dmobj.IDirectMusicObject_iface.lpVtbl = &collection_object_vtbl; + collection->dmobj.IPersistStream_iface.lpVtbl = &collection_stream_vtbl; + + list_init(&collection->Instruments); + + TRACE("Created DirectMusicCollection %p\n", collection); + *ret_iface = (IUnknown *)&collection->IDirectMusicCollection_iface; return S_OK; } From f2a64b8941d25800b8c2437bd48f44778823a991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 31 Aug 2023 09:47:12 +0200 Subject: [PATCH 2446/2777] dmusic: Get rid of struct collection liCollectionPosition member. (cherry picked from commit a614527524be0263d6605547a25cab3a176852c8) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 7223aa23bdb..ca0f30db80a 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -31,7 +31,6 @@ struct collection LONG ref; IStream *pStm; /* stream from which we load collection and later instruments */ - LARGE_INTEGER liCollectionPosition; /* offset in a stream where collection was loaded from */ LARGE_INTEGER liWavePoolTablePosition; /* offset in a stream where wave pool table can be found */ CHAR *szCopyright; /* FIXME: should probably be placed somewhere else */ DLSHEADER *pHeader; @@ -214,12 +213,9 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, DMUS_PRIVATE_CHUNK chunk; DWORD StreamSize, StreamCount, ListSize[2], ListCount[2]; LARGE_INTEGER liMove; /* used when skipping chunks */ - ULARGE_INTEGER dlibCollectionPosition, dlibInstrumentPosition, dlibWavePoolPosition; + ULARGE_INTEGER dlibInstrumentPosition, dlibWavePoolPosition; IStream_AddRef(stream); /* add count for later references */ - liMove.QuadPart = 0; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibCollectionPosition); /* store offset, in case it'll be needed later */ - This->liCollectionPosition.QuadPart = dlibCollectionPosition.QuadPart; This->pStm = stream; IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL); From 59832dbd9648d398b45c2f8cc8891f51e803055b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 31 Aug 2023 09:48:05 +0200 Subject: [PATCH 2447/2777] dmusic: Get rid of struct collection liWavePoolTablePosition member. (cherry picked from commit 4a60c0f64fb8f659e02dde5de00e84a1d9cb03af) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index ca0f30db80a..19fc48ce555 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -31,7 +31,6 @@ struct collection LONG ref; IStream *pStm; /* stream from which we load collection and later instruments */ - LARGE_INTEGER liWavePoolTablePosition; /* offset in a stream where wave pool table can be found */ CHAR *szCopyright; /* FIXME: should probably be placed somewhere else */ DLSHEADER *pHeader; /* pool table */ @@ -213,7 +212,7 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, DMUS_PRIVATE_CHUNK chunk; DWORD StreamSize, StreamCount, ListSize[2], ListCount[2]; LARGE_INTEGER liMove; /* used when skipping chunks */ - ULARGE_INTEGER dlibInstrumentPosition, dlibWavePoolPosition; + ULARGE_INTEGER dlibInstrumentPosition; IStream_AddRef(stream); /* add count for later references */ This->pStm = stream; @@ -357,9 +356,6 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, } case FOURCC_WVPL: { TRACE_(dmfile)(": wave pool list (mark & skip)\n"); - liMove.QuadPart = 0; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibWavePoolPosition); /* store position */ - This->liWavePoolTablePosition.QuadPart = dlibWavePoolPosition.QuadPart; liMove.QuadPart = chunk.dwSize - sizeof(FOURCC); IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); break; From 319a33646b83ac648dc9df3514f5ab17ae21c33e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 10:56:55 +0200 Subject: [PATCH 2448/2777] dmusic: Simplify and cleanup IDirectMusicInstrument constructor. (cherry picked from commit d6dc41c2efca6084e3e10619acf8758a273ec86c) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 2 +- dlls/dmusic/dmusic_private.h | 3 ++- dlls/dmusic/instrument.c | 28 +++++++++++----------------- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 19fc48ce555..1331efbd05d 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -377,7 +377,7 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, DMUS_PRIVATE_INSTRUMENTENTRY *new_instrument = calloc(1, sizeof(DMUS_PRIVATE_INSTRUMENTENTRY)); TRACE_(dmfile)(": instrument list\n"); /* Only way to create this one... even M$ does it discretely */ - DMUSIC_CreateDirectMusicInstrumentImpl(&IID_IDirectMusicInstrument, (void**)&new_instrument->pInstrument, NULL); + instrument_create(&new_instrument->pInstrument); { IDirectMusicInstrumentImpl *instrument = impl_from_IDirectMusicInstrument(new_instrument->pInstrument); /* Store offset and length, they will be needed when loading the instrument */ diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 85b64fb0470..2822f4ffb87 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -100,10 +100,11 @@ extern HRESULT collection_create(IUnknown **ret_iface); /* Internal */ extern HRESULT DMUSIC_CreateDirectMusicBufferImpl(LPDMUS_BUFFERDESC desc, LPVOID* ret_iface); extern HRESULT DMUSIC_CreateReferenceClockImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter); -extern HRESULT DMUSIC_CreateDirectMusicInstrumentImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter); extern HRESULT download_create(DWORD size, IDirectMusicDownload **ret_iface); +extern HRESULT instrument_create(IDirectMusicInstrument **ret_iface); + /***************************************************************************** * IDirectMusic8Impl implementation structure */ diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index 767c4419225..3d4d7478be6 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -119,24 +119,18 @@ static const IDirectMusicInstrumentVtbl DirectMusicInstrument_Vtbl = IDirectMusicInstrumentImpl_SetPatch }; -/* for ClassFactory */ -HRESULT DMUSIC_CreateDirectMusicInstrumentImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) { - IDirectMusicInstrumentImpl* dminst; - HRESULT hr; - - dminst = calloc(1, sizeof(IDirectMusicInstrumentImpl)); - if (NULL == dminst) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } - dminst->IDirectMusicInstrument_iface.lpVtbl = &DirectMusicInstrument_Vtbl; - dminst->ref = 1; - - hr = IDirectMusicInstrument_QueryInterface(&dminst->IDirectMusicInstrument_iface, lpcGUID, - ppobj); - IDirectMusicInstrument_Release(&dminst->IDirectMusicInstrument_iface); +HRESULT instrument_create(IDirectMusicInstrument **ret_iface) +{ + IDirectMusicInstrumentImpl *dminst; - return hr; + *ret_iface = NULL; + if (!(dminst = calloc(1, sizeof(*dminst)))) return E_OUTOFMEMORY; + dminst->IDirectMusicInstrument_iface.lpVtbl = &DirectMusicInstrument_Vtbl; + dminst->ref = 1; + + TRACE("Created DirectMusicInstrument %p\n", dminst); + *ret_iface = &dminst->IDirectMusicInstrument_iface; + return S_OK; } static HRESULT read_from_stream(IStream *stream, void *data, ULONG size) From e1c346bbe1c9b898ecb2dfb7c6c4dbfbf0ecdf40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 31 Aug 2023 09:54:45 +0200 Subject: [PATCH 2449/2777] dmusic: Rename IDirectMusicInstrumentImpl method prefix to instrument. (cherry picked from commit 9abd659efdccfa7f29bd715d4f2a44ac0d62a6b6) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 2 +- dlls/dmusic/dmusic_private.h | 3 +-- dlls/dmusic/instrument.c | 28 +++++++++++++--------------- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 1331efbd05d..8ec8cefad95 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -115,7 +115,7 @@ static HRESULT WINAPI collection_GetInstrument(IDirectMusicCollection *iface, if (patch == inst_patch) { *instrument = inst_entry->pInstrument; IDirectMusicInstrument_AddRef(inst_entry->pInstrument); - IDirectMusicInstrumentImpl_CustomLoad(inst_entry->pInstrument, This->pStm); + instrument_load(inst_entry->pInstrument, This->pStm); TRACE(": returning instrument %p\n", *instrument); return S_OK; } diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 2822f4ffb87..8d49c146013 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -204,8 +204,7 @@ static inline IDirectMusicInstrumentImpl *impl_from_IDirectMusicInstrument(IDire return CONTAINING_RECORD(iface, IDirectMusicInstrumentImpl, IDirectMusicInstrument_iface); } -/* custom :) */ -extern HRESULT IDirectMusicInstrumentImpl_CustomLoad(IDirectMusicInstrument *iface, IStream *stream); +extern HRESULT instrument_load(IDirectMusicInstrument *iface, IStream *stream); /***************************************************************************** * Misc. diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index 3d4d7478be6..6a394290ebd 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -25,8 +25,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmusic); static const GUID IID_IDirectMusicInstrumentPRIVATE = { 0xbcb20080, 0xa40c, 0x11d1, { 0x86, 0xbc, 0x00, 0xc0, 0x4f, 0xbf, 0x8f, 0xef } }; -/* IDirectMusicInstrument IUnknown part: */ -static HRESULT WINAPI IDirectMusicInstrumentImpl_QueryInterface(LPDIRECTMUSICINSTRUMENT iface, REFIID riid, LPVOID *ret_iface) +static HRESULT WINAPI instrument_QueryInterface(LPDIRECTMUSICINSTRUMENT iface, REFIID riid, LPVOID *ret_iface) { TRACE("(%p)->(%s, %p)\n", iface, debugstr_dmguid(riid), ret_iface); @@ -56,7 +55,7 @@ static HRESULT WINAPI IDirectMusicInstrumentImpl_QueryInterface(LPDIRECTMUSICINS return E_NOINTERFACE; } -static ULONG WINAPI IDirectMusicInstrumentImpl_AddRef(LPDIRECTMUSICINSTRUMENT iface) +static ULONG WINAPI instrument_AddRef(LPDIRECTMUSICINSTRUMENT iface) { IDirectMusicInstrumentImpl *This = impl_from_IDirectMusicInstrument(iface); ULONG ref = InterlockedIncrement(&This->ref); @@ -66,7 +65,7 @@ static ULONG WINAPI IDirectMusicInstrumentImpl_AddRef(LPDIRECTMUSICINSTRUMENT if return ref; } -static ULONG WINAPI IDirectMusicInstrumentImpl_Release(LPDIRECTMUSICINSTRUMENT iface) +static ULONG WINAPI instrument_Release(LPDIRECTMUSICINSTRUMENT iface) { IDirectMusicInstrumentImpl *This = impl_from_IDirectMusicInstrument(iface); ULONG ref = InterlockedDecrement(&This->ref); @@ -87,8 +86,7 @@ static ULONG WINAPI IDirectMusicInstrumentImpl_Release(LPDIRECTMUSICINSTRUMENT i return ref; } -/* IDirectMusicInstrumentImpl IDirectMusicInstrument part: */ -static HRESULT WINAPI IDirectMusicInstrumentImpl_GetPatch(LPDIRECTMUSICINSTRUMENT iface, DWORD* pdwPatch) +static HRESULT WINAPI instrument_GetPatch(LPDIRECTMUSICINSTRUMENT iface, DWORD* pdwPatch) { IDirectMusicInstrumentImpl *This = impl_from_IDirectMusicInstrument(iface); @@ -99,7 +97,7 @@ static HRESULT WINAPI IDirectMusicInstrumentImpl_GetPatch(LPDIRECTMUSICINSTRUMEN return S_OK; } -static HRESULT WINAPI IDirectMusicInstrumentImpl_SetPatch(LPDIRECTMUSICINSTRUMENT iface, DWORD dwPatch) +static HRESULT WINAPI instrument_SetPatch(LPDIRECTMUSICINSTRUMENT iface, DWORD dwPatch) { IDirectMusicInstrumentImpl *This = impl_from_IDirectMusicInstrument(iface); @@ -110,13 +108,13 @@ static HRESULT WINAPI IDirectMusicInstrumentImpl_SetPatch(LPDIRECTMUSICINSTRUMEN return S_OK; } -static const IDirectMusicInstrumentVtbl DirectMusicInstrument_Vtbl = +static const IDirectMusicInstrumentVtbl instrument_vtbl = { - IDirectMusicInstrumentImpl_QueryInterface, - IDirectMusicInstrumentImpl_AddRef, - IDirectMusicInstrumentImpl_Release, - IDirectMusicInstrumentImpl_GetPatch, - IDirectMusicInstrumentImpl_SetPatch + instrument_QueryInterface, + instrument_AddRef, + instrument_Release, + instrument_GetPatch, + instrument_SetPatch, }; HRESULT instrument_create(IDirectMusicInstrument **ret_iface) @@ -125,7 +123,7 @@ HRESULT instrument_create(IDirectMusicInstrument **ret_iface) *ret_iface = NULL; if (!(dminst = calloc(1, sizeof(*dminst)))) return E_OUTOFMEMORY; - dminst->IDirectMusicInstrument_iface.lpVtbl = &DirectMusicInstrument_Vtbl; + dminst->IDirectMusicInstrument_iface.lpVtbl = &instrument_vtbl; dminst->ref = 1; TRACE("Created DirectMusicInstrument %p\n", dminst); @@ -278,7 +276,7 @@ static HRESULT load_articulation(IDirectMusicInstrumentImpl *This, IStream *stre } /* Function that loads all instrument data and which is called from IDirectMusicCollection_GetInstrument as in native */ -HRESULT IDirectMusicInstrumentImpl_CustomLoad(IDirectMusicInstrument *iface, IStream *stream) +HRESULT instrument_load(IDirectMusicInstrument *iface, IStream *stream) { IDirectMusicInstrumentImpl *This = impl_from_IDirectMusicInstrument(iface); HRESULT hr; From ae06fa871c2acec6c22251300cb483dde8a57cc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 6 Sep 2023 09:21:24 +0200 Subject: [PATCH 2450/2777] dmusic: Get rid of the IDirectMusicInstrumentImpl typedef. (cherry picked from commit 0110dc24462761ba24b6c7bd9539a1232c11480c) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 4 ++-- dlls/dmusic/dmusic_private.h | 14 ++++---------- dlls/dmusic/instrument.c | 26 +++++++++++++------------- dlls/dmusic/port.c | 2 +- 4 files changed, 20 insertions(+), 26 deletions(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 8ec8cefad95..5332adff084 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -140,7 +140,7 @@ static HRESULT WINAPI collection_EnumInstrument(IDirectMusicCollection *iface, LIST_FOR_EACH(list_entry, &This->Instruments) { inst_entry = LIST_ENTRY(list_entry, DMUS_PRIVATE_INSTRUMENTENTRY, entry); if (i == index) { - IDirectMusicInstrumentImpl *instrument = impl_from_IDirectMusicInstrument(inst_entry->pInstrument); + struct instrument *instrument = impl_from_IDirectMusicInstrument(inst_entry->pInstrument); IDirectMusicInstrument_GetPatch(inst_entry->pInstrument, patch); if (name) { length = min(lstrlenW(instrument->wszName), name_length - 1); @@ -379,7 +379,7 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, /* Only way to create this one... even M$ does it discretely */ instrument_create(&new_instrument->pInstrument); { - IDirectMusicInstrumentImpl *instrument = impl_from_IDirectMusicInstrument(new_instrument->pInstrument); + struct instrument *instrument = impl_from_IDirectMusicInstrument(new_instrument->pInstrument); /* Store offset and length, they will be needed when loading the instrument */ liMove.QuadPart = 0; IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibInstrumentPosition); diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 8d49c146013..5c8f6e1abad 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -52,8 +52,6 @@ typedef struct IDirectMusicBufferImpl IDirectMusicBufferImpl; typedef struct IDirectMusicDownloadedInstrumentImpl IDirectMusicDownloadedInstrumentImpl; typedef struct IReferenceClockImpl IReferenceClockImpl; -typedef struct IDirectMusicInstrumentImpl IDirectMusicInstrumentImpl; - /***************************************************************************** * Some stuff to make my life easier :=) */ @@ -178,15 +176,11 @@ typedef struct _DMUS_PRIVATE_POOLCUE { struct list entry; /* for listing elements */ } DMUS_PRIVATE_POOLCUE, *LPDMUS_PRIVATE_POOLCUE; -/***************************************************************************** - * IDirectMusicInstrumentImpl implementation structure - */ -struct IDirectMusicInstrumentImpl { - /* IUnknown fields */ +struct instrument +{ IDirectMusicInstrument IDirectMusicInstrument_iface; LONG ref; - /* IDirectMusicInstrumentImpl fields */ LARGE_INTEGER liInstrumentPosition; /* offset in a stream where instrument chunk can be found */ ULONG length; /* Length of the instrument in the stream */ GUID id; @@ -199,9 +193,9 @@ struct IDirectMusicInstrumentImpl { instrument_articulation *articulations; }; -static inline IDirectMusicInstrumentImpl *impl_from_IDirectMusicInstrument(IDirectMusicInstrument *iface) +static inline struct instrument *impl_from_IDirectMusicInstrument(IDirectMusicInstrument *iface) { - return CONTAINING_RECORD(iface, IDirectMusicInstrumentImpl, IDirectMusicInstrument_iface); + return CONTAINING_RECORD(iface, struct instrument, IDirectMusicInstrument_iface); } extern HRESULT instrument_load(IDirectMusicInstrument *iface, IStream *stream); diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index 6a394290ebd..5677f128060 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -57,7 +57,7 @@ static HRESULT WINAPI instrument_QueryInterface(LPDIRECTMUSICINSTRUMENT iface, R static ULONG WINAPI instrument_AddRef(LPDIRECTMUSICINSTRUMENT iface) { - IDirectMusicInstrumentImpl *This = impl_from_IDirectMusicInstrument(iface); + struct instrument *This = impl_from_IDirectMusicInstrument(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p): new ref = %lu\n", iface, ref); @@ -67,7 +67,7 @@ static ULONG WINAPI instrument_AddRef(LPDIRECTMUSICINSTRUMENT iface) static ULONG WINAPI instrument_Release(LPDIRECTMUSICINSTRUMENT iface) { - IDirectMusicInstrumentImpl *This = impl_from_IDirectMusicInstrument(iface); + struct instrument *This = impl_from_IDirectMusicInstrument(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p): new ref = %lu\n", iface, ref); @@ -88,7 +88,7 @@ static ULONG WINAPI instrument_Release(LPDIRECTMUSICINSTRUMENT iface) static HRESULT WINAPI instrument_GetPatch(LPDIRECTMUSICINSTRUMENT iface, DWORD* pdwPatch) { - IDirectMusicInstrumentImpl *This = impl_from_IDirectMusicInstrument(iface); + struct instrument *This = impl_from_IDirectMusicInstrument(iface); TRACE("(%p)->(%p)\n", This, pdwPatch); @@ -99,7 +99,7 @@ static HRESULT WINAPI instrument_GetPatch(LPDIRECTMUSICINSTRUMENT iface, DWORD* static HRESULT WINAPI instrument_SetPatch(LPDIRECTMUSICINSTRUMENT iface, DWORD dwPatch) { - IDirectMusicInstrumentImpl *This = impl_from_IDirectMusicInstrument(iface); + struct instrument *This = impl_from_IDirectMusicInstrument(iface); TRACE("(%p, %ld): stub\n", This, dwPatch); @@ -119,15 +119,15 @@ static const IDirectMusicInstrumentVtbl instrument_vtbl = HRESULT instrument_create(IDirectMusicInstrument **ret_iface) { - IDirectMusicInstrumentImpl *dminst; + struct instrument *instrument; *ret_iface = NULL; - if (!(dminst = calloc(1, sizeof(*dminst)))) return E_OUTOFMEMORY; - dminst->IDirectMusicInstrument_iface.lpVtbl = &instrument_vtbl; - dminst->ref = 1; + if (!(instrument = calloc(1, sizeof(*instrument)))) return E_OUTOFMEMORY; + instrument->IDirectMusicInstrument_iface.lpVtbl = &instrument_vtbl; + instrument->ref = 1; - TRACE("Created DirectMusicInstrument %p\n", dminst); - *ret_iface = &dminst->IDirectMusicInstrument_iface; + TRACE("Created DirectMusicInstrument %p\n", instrument); + *ret_iface = &instrument->IDirectMusicInstrument_iface; return S_OK; } @@ -172,7 +172,7 @@ static inline HRESULT advance_stream(IStream *stream, ULONG bytes) return ret; } -static HRESULT load_region(IDirectMusicInstrumentImpl *This, IStream *stream, instrument_region *region, ULONG length) +static HRESULT load_region(struct instrument *This, IStream *stream, instrument_region *region, ULONG length) { HRESULT ret; DMUS_PRIVATE_CHUNK chunk; @@ -242,7 +242,7 @@ static HRESULT load_region(IDirectMusicInstrumentImpl *This, IStream *stream, in return S_OK; } -static HRESULT load_articulation(IDirectMusicInstrumentImpl *This, IStream *stream, ULONG length) +static HRESULT load_articulation(struct instrument *This, IStream *stream, ULONG length) { HRESULT ret; instrument_articulation *articulation; @@ -278,7 +278,7 @@ static HRESULT load_articulation(IDirectMusicInstrumentImpl *This, IStream *stre /* Function that loads all instrument data and which is called from IDirectMusicCollection_GetInstrument as in native */ HRESULT instrument_load(IDirectMusicInstrument *iface, IStream *stream) { - IDirectMusicInstrumentImpl *This = impl_from_IDirectMusicInstrument(iface); + struct instrument *This = impl_from_IDirectMusicInstrument(iface); HRESULT hr; DMUS_PRIVATE_CHUNK chunk; ULONG i = 0; diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index eaf2bb139f1..95857ea55ac 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -266,7 +266,7 @@ static HRESULT WINAPI synth_port_DownloadInstrument(IDirectMusicPort *iface, IDi IDirectMusicDownloadedInstrument **downloaded_instrument, DMUS_NOTERANGE *note_ranges, DWORD num_note_ranges) { struct synth_port *This = synth_from_IDirectMusicPort(iface); - IDirectMusicInstrumentImpl *instrument_object; + struct instrument *instrument_object; HRESULT ret; BOOL on_heap; HANDLE download; From 87527b404606126269d7e4c8307a9b535506c6f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 23:47:56 +0200 Subject: [PATCH 2451/2777] dmime/tests: Test IDirectMusicGraph interface with a dummy tool. (cherry picked from commit 881e424683eb1f2493c4d4524e65127a6277a3f4) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 285 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 281 insertions(+), 4 deletions(-) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 8f2bf6f2812..2c84fee05ad 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -27,6 +27,126 @@ #include #include +struct test_tool +{ + IDirectMusicTool IDirectMusicTool_iface; + LONG ref; + + IDirectMusicGraph *graph; +}; + +static struct test_tool *impl_from_IDirectMusicTool(IDirectMusicTool *iface) +{ + return CONTAINING_RECORD(iface, struct test_tool, IDirectMusicTool_iface); +} + +static HRESULT WINAPI test_tool_QueryInterface(IDirectMusicTool *iface, REFIID iid, void **out) +{ + if (IsEqualGUID(iid, &IID_IUnknown) + || IsEqualGUID(iid, &IID_IDirectMusicTool)) + { + IDirectMusicTool_AddRef(iface); + *out = iface; + return S_OK; + } + + ok(IsEqualGUID(iid, &IID_IDirectMusicTool8) || IsEqualGUID(iid, &IID_IPersistStream), + "got iid %s\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_tool_AddRef(IDirectMusicTool *iface) +{ + struct test_tool *tool = impl_from_IDirectMusicTool(iface); + return InterlockedIncrement(&tool->ref); +} + +static ULONG WINAPI test_tool_Release(IDirectMusicTool *iface) +{ + struct test_tool *tool = impl_from_IDirectMusicTool(iface); + ULONG ref = InterlockedDecrement(&tool->ref); + + if (!ref) + { + if (tool->graph) IDirectMusicGraph_Release(tool->graph); + free(tool); + } + + return ref; +} + +static HRESULT WINAPI test_tool_Init(IDirectMusicTool *iface, IDirectMusicGraph *graph) +{ + struct test_tool *tool = impl_from_IDirectMusicTool(iface); + if ((tool->graph = graph)) IDirectMusicGraph_AddRef(tool->graph); + return S_OK; +} + +static HRESULT WINAPI test_tool_GetMsgDeliveryType(IDirectMusicTool *iface, DWORD *type) +{ + *type = DMUS_PMSGF_TOOL_IMMEDIATE; + return S_OK; +} + +static HRESULT WINAPI test_tool_GetMediaTypeArraySize(IDirectMusicTool *iface, DWORD *size) +{ + *size = 0; + return S_OK; +} + +static HRESULT WINAPI test_tool_GetMediaTypes(IDirectMusicTool *iface, DWORD **types, DWORD size) +{ + ok(0, "%#04lx: unexpected %s, types %p, size %lu\n", GetCurrentThreadId(), __func__, types, size); + return S_OK; +} + +static HRESULT WINAPI test_tool_ProcessPMsg(IDirectMusicTool *iface, IDirectMusicPerformance *performance, DMUS_PMSG *msg) +{ + ok(0, "%#04lx: unexpected %s, iface %p, performance %p, msg %p\n", GetCurrentThreadId(), __func__, iface, performance, msg); + return DMUS_S_REQUEUE; +} + +static HRESULT WINAPI test_tool_Flush(IDirectMusicTool *iface, IDirectMusicPerformance *performance, + DMUS_PMSG *msg, REFERENCE_TIME time) +{ + ok(0, "unexpected %s\n", __func__); + return S_OK; +} + +static IDirectMusicToolVtbl test_tool_vtbl = +{ + test_tool_QueryInterface, + test_tool_AddRef, + test_tool_Release, + test_tool_Init, + test_tool_GetMsgDeliveryType, + test_tool_GetMediaTypeArraySize, + test_tool_GetMediaTypes, + test_tool_ProcessPMsg, + test_tool_Flush, +}; + +static HRESULT test_tool_create(IDirectMusicTool **ret_iface) +{ + struct test_tool *tool; + + *ret_iface = NULL; + if (!(tool = calloc(1, sizeof(*tool)))) return E_OUTOFMEMORY; + tool->IDirectMusicTool_iface.lpVtbl = &test_tool_vtbl; + tool->ref = 1; + + *ret_iface = &tool->IDirectMusicTool_iface; + return S_OK; +} + +static HRESULT test_tool_get_graph(IDirectMusicTool *iface, IDirectMusicGraph **graph) +{ + struct test_tool *tool = impl_from_IDirectMusicTool(iface); + if ((*graph = tool->graph)) IDirectMusicGraph_AddRef(tool->graph); + return tool->graph ? S_OK : DMUS_E_NOT_FOUND; +} + static BOOL missing_dmime(void) { IDirectMusicSegment8 *dms; @@ -458,18 +578,20 @@ static void test_audiopathconfig(void) static void test_graph(void) { - IDirectMusicGraph *dmg; + IDirectMusicTool *tool1, *tool2, *tmp_tool; + IDirectMusicGraph *graph, *tmp_graph; IPersistStream *ps; CLSID class = { 0 }; ULARGE_INTEGER size; + DMUS_PMSG msg; HRESULT hr; hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectMusicGraph, (void**)&dmg); + &IID_IDirectMusicGraph, (void**)&graph); ok(hr == S_OK, "DirectMusicGraph create failed: %#lx, expected S_OK\n", hr); /* IPersistStream */ - hr = IDirectMusicGraph_QueryInterface(dmg, &IID_IPersistStream, (void**)&ps); + hr = IDirectMusicGraph_QueryInterface(graph, &IID_IPersistStream, (void**)&ps); ok(hr == S_OK, "QueryInterface for IID_IPersistStream failed: %#lx\n", hr); hr = IPersistStream_GetClassID(ps, &class); ok(hr == S_OK || broken(hr == E_NOTIMPL) /* win2k */, "IPersistStream_GetClassID failed: %#lx\n", hr); @@ -485,7 +607,162 @@ static void test_graph(void) hr = IPersistStream_Save(ps, NULL, TRUE); ok(hr == E_NOTIMPL, "IPersistStream_Save failed: %#lx\n", hr); - while (IDirectMusicGraph_Release(dmg)); + IDirectMusicGraph_Release(graph); + + + hr = test_tool_create(&tool1); + ok(hr == S_OK, "got %#lx\n", hr); + trace("created tool1 %p\n", tool1); + hr = test_tool_create(&tool2); + ok(hr == S_OK, "got %#lx\n", hr); + trace("created tool2 %p\n", tool2); + + hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicGraph, (void **)&graph); + ok(hr == S_OK, "got %#lx\n", hr); + + + hr = IDirectMusicGraph_InsertTool(graph, NULL, NULL, 0, -1); + ok(hr == E_POINTER, "got %#lx\n", hr); + + /* InsertTool initializes the tool */ + hr = IDirectMusicGraph_InsertTool(graph, tool1, NULL, 0, -1); + ok(hr == S_OK, "got %#lx\n", hr); + hr = test_tool_get_graph(tool1, &tmp_graph); + ok(hr == S_OK, "got %#lx\n", hr); + ok(graph == tmp_graph, "got %#lx\n", hr); + IDirectMusicGraph_Release(tmp_graph); + + hr = IDirectMusicGraph_InsertTool(graph, tool2, NULL, 0, 1); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicGraph_GetTool(graph, 0, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicGraph_GetTool(graph, 0, &tmp_tool); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(tool1 == tmp_tool, "got %p\n", tmp_tool); + if (hr == S_OK) IDirectMusicTool_Release(tmp_tool); + hr = IDirectMusicGraph_GetTool(graph, 1, &tmp_tool); + ok(hr == S_OK, "got %#lx\n", hr); + ok(tool2 == tmp_tool, "got %p\n", tmp_tool); + if (hr == S_OK) IDirectMusicTool_Release(tmp_tool); + hr = IDirectMusicGraph_GetTool(graph, 2, &tmp_tool); + ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); + + /* cannot insert the tool twice */ + hr = IDirectMusicGraph_InsertTool(graph, tool1, NULL, 0, -1); + ok(hr == DMUS_E_ALREADY_EXISTS, "got %#lx\n", hr); + + /* test removing the first tool */ + hr = IDirectMusicGraph_RemoveTool(graph, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicGraph_RemoveTool(graph, tool1); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicGraph_RemoveTool(graph, tool1); + todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); + + hr = IDirectMusicGraph_GetTool(graph, 0, &tmp_tool); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(tool2 == tmp_tool, "got %p\n", tmp_tool); + if (hr == S_OK) IDirectMusicTool_Release(tmp_tool); + hr = IDirectMusicGraph_GetTool(graph, 1, &tmp_tool); + todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); + + hr = IDirectMusicGraph_InsertTool(graph, tool1, NULL, 0, -1); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicGraph_GetTool(graph, 0, &tmp_tool); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(tool1 == tmp_tool, "got %p\n", tmp_tool); + if (hr == S_OK) IDirectMusicTool_Release(tmp_tool); + + + /* Test basic IDirectMusicGraph_StampPMsg usage */ + hr = IDirectMusicGraph_StampPMsg(graph, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + memset(&msg, 0, sizeof(msg)); + hr = IDirectMusicGraph_StampPMsg(graph, &msg); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(msg.pGraph == graph, "got %p\n", msg.pGraph); + todo_wine ok(msg.pTool == tool1, "got %p\n", msg.pTool); + + ok(!msg.dwSize, "got %ld\n", msg.dwSize); + ok(!msg.rtTime, "got %I64d\n", msg.rtTime); + ok(!msg.mtTime, "got %ld\n", msg.mtTime); + todo_wine ok(msg.dwFlags == DMUS_PMSGF_TOOL_IMMEDIATE, "got %#lx\n", msg.dwFlags); + ok(!msg.dwPChannel, "got %ld\n", msg.dwPChannel); + ok(!msg.dwVirtualTrackID, "got %ld\n", msg.dwVirtualTrackID); + ok(!msg.dwType, "got %#lx\n", msg.dwType); + ok(!msg.dwVoiceID, "got %ld\n", msg.dwVoiceID); + ok(!msg.dwGroupID, "got %ld\n", msg.dwGroupID); + ok(!msg.punkUser, "got %p\n", msg.punkUser); + + hr = IDirectMusicGraph_StampPMsg(graph, &msg); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(msg.pGraph == graph, "got %p\n", msg.pGraph); + todo_wine ok(msg.pTool == tool2, "got %p\n", msg.pTool); + hr = IDirectMusicGraph_StampPMsg(graph, &msg); + todo_wine ok(hr == DMUS_S_LAST_TOOL, "got %#lx\n", hr); + todo_wine ok(msg.pGraph == graph, "got %p\n", msg.pGraph); + ok(!msg.pTool, "got %p\n", msg.pTool); + hr = IDirectMusicGraph_StampPMsg(graph, &msg); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(msg.pGraph == graph, "got %p\n", msg.pGraph); + todo_wine ok(msg.pTool == tool1, "got %p\n", msg.pTool); + if (msg.pGraph) IDirectMusicGraph_Release(msg.pGraph); + msg.pGraph = NULL; + if (msg.pTool) IDirectMusicGraph_Release(msg.pTool); + msg.pTool = NULL; + + + /* test StampPMsg with the wrong graph or innexistant tools */ + hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicGraph, (void **)&tmp_graph); + ok(hr == S_OK, "got %#lx\n", hr); + + msg.pGraph = tmp_graph; + IDirectMusicGraph_AddRef(msg.pGraph); + msg.pTool = tool1; + IDirectMusicTool_AddRef(msg.pTool); + hr = IDirectMusicGraph_StampPMsg(graph, &msg); + ok(hr == S_OK, "got %#lx\n", hr); + ok(msg.pGraph == tmp_graph, "got %p\n", msg.pGraph); + todo_wine ok(msg.pTool == tool2, "got %p\n", msg.pTool); + if (msg.pGraph) IDirectMusicGraph_Release(msg.pGraph); + msg.pGraph = NULL; + + msg.pGraph = graph; + IDirectMusicGraph_AddRef(msg.pGraph); + hr = IDirectMusicGraph_StampPMsg(tmp_graph, &msg); + todo_wine ok(hr == DMUS_S_LAST_TOOL, "got %#lx\n", hr); + ok(msg.pGraph == graph, "got %p\n", msg.pGraph); + todo_wine ok(msg.pTool == NULL, "got %p\n", msg.pTool); + + msg.pTool = tool2; + IDirectMusicTool_AddRef(msg.pTool); + hr = IDirectMusicGraph_InsertTool(tmp_graph, tool1, NULL, 0, 0); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicGraph_InsertTool(tmp_graph, tool2, NULL, 0, 0); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicGraph_StampPMsg(tmp_graph, &msg); + ok(hr == S_OK, "got %#lx\n", hr); + ok(msg.pGraph == graph, "got %p\n", msg.pGraph); + todo_wine ok(msg.pTool == tool1, "got %p\n", msg.pTool); + if (msg.pGraph) IDirectMusicGraph_Release(msg.pGraph); + msg.pGraph = NULL; + + hr = IDirectMusicGraph_RemoveTool(graph, tool1); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicGraph_StampPMsg(tmp_graph, &msg); + todo_wine ok(hr == DMUS_S_LAST_TOOL, "got %#lx\n", hr); + ok(msg.pGraph == NULL, "got %p\n", msg.pGraph); + todo_wine ok(msg.pTool == NULL, "got %p\n", msg.pTool); + + IDirectMusicGraph_Release(tmp_graph); + + + IDirectMusicGraph_Release(graph); + IDirectMusicTool_Release(tool2); + IDirectMusicTool_Release(tool1); } static void test_segment(void) From 519840b4b38e14f7f0830bd209146738d75cb8a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Sep 2023 08:32:42 +0200 Subject: [PATCH 2452/2777] dmime/tests: Test performance IDirectMusicTool interface. (cherry picked from commit 5efaae40deaf4c33780832bb349fb61e1f5d0123) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 74 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 2c84fee05ad..da1b4b4d8b8 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -27,6 +27,34 @@ #include #include +static ULONG get_refcount(void *iface) +{ + IUnknown *unknown = iface; + IUnknown_AddRef(unknown); + return IUnknown_Release(unknown); +} + +#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) +static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported) +{ + ULONG expect_ref = get_refcount(iface_ptr); + IUnknown *iface = iface_ptr; + HRESULT hr, expected; + IUnknown *unk; + + expected = supported ? S_OK : E_NOINTERFACE; + hr = IUnknown_QueryInterface(iface, iid, (void **)&unk); + ok_(__FILE__, line)(hr == expected, "got hr %#lx, expected %#lx.\n", hr, expected); + if (SUCCEEDED(hr)) + { + LONG ref = get_refcount(unk); + ok_(__FILE__, line)(ref == expect_ref + 1, "got %ld\n", ref); + IUnknown_Release(unk); + ref = get_refcount(iface_ptr); + ok_(__FILE__, line)(ref == expect_ref, "got %ld\n", ref); + } +} + struct test_tool { IDirectMusicTool IDirectMusicTool_iface; @@ -1405,6 +1433,51 @@ static void test_parsedescriptor(void) } } +static void test_performance_tool(void) +{ + IDirectMusicPerformance *performance; + IDirectMusicGraph *graph; + IDirectMusicTool *tool; + DWORD value, types[1]; + DMUS_PMSG msg = {0}; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicPerformance, (void **)&performance); + ok(hr == S_OK, "got %#lx\n", hr); + + check_interface(performance, &IID_IDirectMusicTool8, FALSE); + + hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicTool, (void **)&tool); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + if (hr != S_OK) goto skip_tool; + hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicTool_Init(tool, graph); + ok(hr == E_NOTIMPL, "got %#lx\n", hr); + value = 0xdeadbeef; + hr = IDirectMusicTool_GetMsgDeliveryType(tool, &value); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(value == DMUS_PMSGF_TOOL_IMMEDIATE, "got %#lx\n", value); + value = 0xdeadbeef; + hr = IDirectMusicTool_GetMediaTypeArraySize(tool, &value); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(value == 0, "got %#lx\n", value); + hr = IDirectMusicTool_GetMediaTypes(tool, (DWORD **)&types, 64); + ok(hr == E_NOTIMPL, "got %#lx\n", hr); + hr = IDirectMusicTool_ProcessPMsg(tool, performance, &msg); + todo_wine ok(hr == DMUS_S_FREE, "got %#lx\n", hr); + hr = IDirectMusicTool_Flush(tool, performance, &msg, 0); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + + IDirectMusicGraph_Release(graph); + IDirectMusicTool_Release(tool); + +skip_tool: + IDirectMusicPerformance_Release(performance); +} + START_TEST(dmime) { CoInitialize(NULL); @@ -1428,6 +1501,7 @@ START_TEST(dmime) test_segment_param(); test_track(); test_parsedescriptor(); + test_performance_tool(); CoUninitialize(); } From 57e99ec9b771dc8a795ad8999395bdaa1281b280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Sep 2023 08:29:57 +0200 Subject: [PATCH 2453/2777] dmime/tests: Test performance IDirectMusicGraph interface. (cherry picked from commit cd5c9b800d275ba91899c2ad9a8739bcad0c6be0) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 124 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index da1b4b4d8b8..42eb4b1f47e 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -1478,6 +1478,129 @@ static void test_performance_tool(void) IDirectMusicPerformance_Release(performance); } +static void test_performance_graph(void) +{ + IDirectMusicPerformance *performance; + IDirectMusicGraph *graph, *tmp_graph; + IDirectMusicTool *tool, *tmp_tool; + DMUS_PMSG msg; + HRESULT hr; + + hr = test_tool_create(&tool); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicPerformance, (void **)&performance); + ok(hr == S_OK, "got %#lx\n", hr); + + + /* performance exposes a graph interface but it's not an actual toolgraph */ + hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + if (hr != S_OK) goto skip_graph; + hr = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1); + ok(hr == E_NOTIMPL, "got %#lx\n", hr); + hr = IDirectMusicGraph_GetTool(graph, 0, &tmp_tool); + ok(hr == E_NOTIMPL, "got %#lx\n", hr); + hr = IDirectMusicGraph_RemoveTool(graph, tool); + ok(hr == E_NOTIMPL, "got %#lx\n", hr); + + /* test IDirectMusicGraph_StampPMsg usage */ + hr = IDirectMusicGraph_StampPMsg(graph, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + memset(&msg, 0, sizeof(msg)); + hr = IDirectMusicGraph_StampPMsg(graph, &msg); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(msg.pGraph == NULL, "got %p\n", msg.pGraph); + todo_wine ok(msg.pTool != NULL, "got %p\n", msg.pTool); + if (msg.pTool) check_interface(msg.pTool, &IID_IDirectMusicPerformance, TRUE); + + ok(!msg.dwSize, "got %ld\n", msg.dwSize); + ok(!msg.rtTime, "got %I64d\n", msg.rtTime); + ok(!msg.mtTime, "got %ld\n", msg.mtTime); + todo_wine ok(msg.dwFlags == DMUS_PMSGF_TOOL_QUEUE, "got %#lx\n", msg.dwFlags); + ok(!msg.dwPChannel, "got %ld\n", msg.dwPChannel); + ok(!msg.dwVirtualTrackID, "got %ld\n", msg.dwVirtualTrackID); + ok(!msg.dwType, "got %#lx\n", msg.dwType); + ok(!msg.dwVoiceID, "got %ld\n", msg.dwVoiceID); + ok(!msg.dwGroupID, "got %ld\n", msg.dwGroupID); + ok(!msg.punkUser, "got %p\n", msg.punkUser); + + hr = IDirectMusicGraph_StampPMsg(graph, &msg); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(msg.pGraph == NULL, "got %p\n", msg.pGraph); + todo_wine ok(msg.pTool != NULL, "got %p\n", msg.pTool); + if (msg.pTool) check_interface(msg.pTool, &IID_IDirectMusicPerformance, TRUE); + + if (msg.pTool) IDirectMusicTool_Release(msg.pTool); + msg.pTool = NULL; + + IDirectMusicGraph_Release(graph); + + +skip_graph: + /* performance doesn't have a default embedded toolgraph */ + hr = IDirectMusicPerformance_GetGraph(performance, &graph); + ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); + + + /* test adding a graph to the performance */ + hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicGraph, (void **)&graph); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_SetGraph(performance, graph); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_GetGraph(performance, &tmp_graph); + ok(hr == S_OK, "got %#lx\n", hr); + ok(tmp_graph == graph, "got %p\n", graph); + IDirectMusicGraph_Release(tmp_graph); + + hr = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1); + ok(hr == S_OK, "got %#lx\n", hr); + + IDirectMusicGraph_Release(graph); + + + /* test IDirectMusicGraph_StampPMsg usage */ + hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + if (hr != S_OK) goto skip_graph2; + + memset(&msg, 0, sizeof(msg)); + hr = IDirectMusicGraph_StampPMsg(graph, &msg); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(msg.pGraph == graph, "got %p\n", msg.pGraph); + todo_wine ok(msg.pTool == tool, "got %p\n", msg.pTool); + + ok(!msg.dwSize, "got %ld\n", msg.dwSize); + ok(!msg.rtTime, "got %I64d\n", msg.rtTime); + ok(!msg.mtTime, "got %ld\n", msg.mtTime); + todo_wine ok(msg.dwFlags == DMUS_PMSGF_TOOL_IMMEDIATE, "got %#lx\n", msg.dwFlags); + ok(!msg.dwPChannel, "got %ld\n", msg.dwPChannel); + ok(!msg.dwVirtualTrackID, "got %ld\n", msg.dwVirtualTrackID); + ok(!msg.dwType, "got %#lx\n", msg.dwType); + ok(!msg.dwVoiceID, "got %ld\n", msg.dwVoiceID); + ok(!msg.dwGroupID, "got %ld\n", msg.dwGroupID); + ok(!msg.punkUser, "got %p\n", msg.punkUser); + + hr = IDirectMusicGraph_StampPMsg(graph, &msg); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(msg.pGraph == NULL, "got %p\n", msg.pGraph); + todo_wine ok(msg.pTool != NULL, "got %p\n", msg.pTool); + if (msg.pTool) check_interface(msg.pTool, &IID_IDirectMusicPerformance, TRUE); + + if (msg.pTool) IDirectMusicTool_Release(msg.pTool); + msg.pTool = NULL; + + IDirectMusicGraph_Release(graph); + + +skip_graph2: + IDirectMusicPerformance_Release(performance); + IDirectMusicTool_Release(tool); +} + START_TEST(dmime) { CoInitialize(NULL); @@ -1502,6 +1625,7 @@ START_TEST(dmime) test_track(); test_parsedescriptor(); test_performance_tool(); + test_performance_graph(); CoUninitialize(); } From d4234daf1443a335e7bc83ad218feebe7977b7ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Sep 2023 16:27:17 +0200 Subject: [PATCH 2454/2777] dmime/tests: Test IDirectMusicPerformance time conversion. (cherry picked from commit a874f60cae59f5cda98e6d02acbf1ead343141ae) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 91 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 42eb4b1f47e..7fa832ebfd5 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -1601,6 +1601,96 @@ static void test_performance_graph(void) IDirectMusicTool_Release(tool); } +static void test_performance_time(void) +{ + IDirectMusicPerformance *performance; + REFERENCE_TIME init_time, time; + IReferenceClock *clock; + MUSIC_TIME music_time; + IDirectMusic *dmusic; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicPerformance, (void **)&performance); + ok(hr == S_OK, "got %#lx\n", hr); + + + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 0, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 0, &time); + todo_wine ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr); + todo_wine ok(time == 0, "got %I64d\n", time); + + hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, 0, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + music_time = 0xdeadbeef; + hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, 0, &music_time); + todo_wine ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr); + todo_wine ok(music_time == 0, "got %ld\n", music_time); + + + dmusic = NULL; + hr = IDirectMusicPerformance_Init(performance, &dmusic, NULL, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusic_GetMasterClock(dmusic, NULL, &clock); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusic_Release(dmusic); + hr = IReferenceClock_GetTime(clock, &init_time); + ok(hr == S_OK, "got %#lx\n", hr); + IReferenceClock_Release(clock); + + + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 0, &time); + ok(hr == S_OK, "got %#lx\n", hr); + ok(time - init_time <= 100 * 10000, "got %I64d\n", time - init_time); + init_time = time; + + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time - init_time >= 6505, "got %I64d\n", time - init_time); + ok(time - init_time <= 6515, "got %I64d\n", time - init_time); + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1000, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time - init_time >= 1000 * 6505, "got %I64d\n", time - init_time); + ok(time - init_time <= 1000 * 6515, "got %I64d\n", time - init_time); + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 2000, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time - init_time >= 2000 * 6505, "got %I64d\n", time - init_time); + ok(time - init_time <= 2000 * 6515, "got %I64d\n", time - init_time); + + music_time = 0xdeadbeef; + hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time, &music_time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(music_time == 0, "got %ld\n", music_time); + music_time = 0xdeadbeef; + hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + 1000 * 6510, &music_time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(music_time == 1000, "got %ld\n", music_time); + music_time = 0xdeadbeef; + hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + 2000 * 6510, &music_time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(music_time == 2000, "got %ld\n", music_time); + + time = 0xdeadbeef; + music_time = 0xdeadbeef; + hr = IDirectMusicPerformance_GetTime(performance, &time, &music_time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time - init_time <= 200 * 10000, "got %I64d\n", time - init_time); + todo_wine ok(music_time == (time - init_time) / 6510, "got %ld\n", music_time); + + + hr = IDirectMusicPerformance_CloseDown(performance); + ok(hr == S_OK, "got %#lx\n", hr); + + IDirectMusicPerformance_Release(performance); + +} + START_TEST(dmime) { CoInitialize(NULL); @@ -1626,6 +1716,7 @@ START_TEST(dmime) test_parsedescriptor(); test_performance_tool(); test_performance_graph(); + test_performance_time(); CoUninitialize(); } From b727baa13d280a64678f5078e09050e8364e3bc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Sep 2023 16:27:41 +0200 Subject: [PATCH 2455/2777] dmime/tests: Test IDirectMusicPerformance_*PMsg methods. (cherry picked from commit e80c1d90f1c08c1d2ec2a84949d69ca3219b3d1d) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 124 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 7fa832ebfd5..46751339994 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -1691,6 +1691,129 @@ static void test_performance_time(void) } +static void test_performance_pmsg(void) +{ + IDirectMusicPerformance *performance; + IDirectMusicGraph *graph; + IDirectMusicTool *tool; + DMUS_PMSG *msg, *clone; + REFERENCE_TIME time; + HRESULT hr; + + hr = test_tool_create(&tool); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicPerformance, (void **)&performance); + ok(hr == S_OK, "got %#lx\n", hr); + + + hr = IDirectMusicPerformance_AllocPMsg(performance, 0, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG) - 1, &msg); + ok(hr == E_INVALIDARG, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg); + ok(hr == S_OK, "got %#lx\n", hr); + ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize); + ok(!msg->rtTime, "got %I64d\n", msg->rtTime); + ok(!msg->mtTime, "got %ld\n", msg->mtTime); + ok(!msg->dwFlags, "got %#lx\n", msg->dwFlags); + ok(!msg->dwPChannel, "got %ld\n", msg->dwPChannel); + ok(!msg->dwVirtualTrackID, "got %ld\n", msg->dwVirtualTrackID); + ok(!msg->dwType, "got %#lx\n", msg->dwType); + ok(!msg->dwVoiceID, "got %ld\n", msg->dwVoiceID); + ok(!msg->dwGroupID, "got %ld\n", msg->dwGroupID); + ok(!msg->punkUser, "got %p\n", msg->punkUser); + + hr = IDirectMusicPerformance_SendPMsg(performance, NULL); + ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicPerformance_SendPMsg(performance, msg); + todo_wine ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_FreePMsg(performance, NULL); + ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + + + hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicGraph, (void **)&graph); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_SetGraph(performance, graph); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicGraph_Release(graph); + + hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg); + ok(hr == S_OK, "got %#lx\n", hr); + ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize); + ok(!msg->rtTime, "got %I64d\n", msg->rtTime); + ok(!msg->mtTime, "got %ld\n", msg->mtTime); + ok(!msg->dwFlags, "got %#lx\n", msg->dwFlags); + ok(!msg->dwPChannel, "got %ld\n", msg->dwPChannel); + ok(!msg->dwVirtualTrackID, "got %ld\n", msg->dwVirtualTrackID); + ok(!msg->pTool, "got %p\n", msg->pTool); + ok(!msg->pGraph, "got %p\n", msg->pGraph); + ok(!msg->dwType, "got %#lx\n", msg->dwType); + ok(!msg->dwVoiceID, "got %ld\n", msg->dwVoiceID); + ok(!msg->dwGroupID, "got %ld\n", msg->dwGroupID); + ok(!msg->punkUser, "got %p\n", msg->punkUser); + hr = IDirectMusicPerformance_SendPMsg(performance, msg); + todo_wine ok(hr == E_INVALIDARG, "got %#lx\n", hr); + + hr = IDirectMusicPerformance8_ClonePMsg((IDirectMusicPerformance8 *)performance, msg, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicPerformance8_ClonePMsg((IDirectMusicPerformance8 *)performance, NULL, &clone); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + clone = NULL; + hr = IDirectMusicPerformance8_ClonePMsg((IDirectMusicPerformance8 *)performance, msg, &clone); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(clone != NULL, "got %p\n", clone); + + msg->mtTime = 500; + msg->dwFlags = DMUS_PMSGF_MUSICTIME; + hr = IDirectMusicPerformance_SendPMsg(performance, msg); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_SendPMsg(performance, msg); + ok(hr == DMUS_E_ALREADY_SENT, "got %#lx\n", hr); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == DMUS_E_CANNOT_FREE, "got %#lx\n", hr); + + if (!clone) hr = S_OK; + else hr = IDirectMusicPerformance_FreePMsg(performance, clone); + ok(hr == S_OK, "got %#lx\n", hr); + + + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, msg->mtTime, &time); + ok(hr == S_OK, "got %#lx\n", hr); + ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize); + todo_wine ok(msg->rtTime == time, "got %I64d\n", msg->rtTime); + ok(msg->mtTime == 500, "got %ld\n", msg->mtTime); + todo_wine ok(msg->dwFlags & DMUS_PMSGF_REFTIME, "got %#lx\n", msg->dwFlags); + todo_wine ok(msg->dwFlags & (DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_IMMEDIATE), "got %#lx\n", msg->dwFlags); + ok(!msg->dwPChannel, "got %ld\n", msg->dwPChannel); + ok(!msg->dwVirtualTrackID, "got %ld\n", msg->dwVirtualTrackID); + ok(!msg->pTool, "got %p\n", msg->pTool); + ok(!msg->pGraph, "got %p\n", msg->pGraph); + ok(!msg->dwType, "got %#lx\n", msg->dwType); + ok(!msg->dwVoiceID, "got %ld\n", msg->dwVoiceID); + ok(!msg->dwGroupID, "got %ld\n", msg->dwGroupID); + ok(!msg->punkUser, "got %p\n", msg->punkUser); + + + hr = IDirectMusicPerformance_CloseDown(performance); + ok(hr == S_OK, "got %#lx\n", hr); + + + IDirectMusicPerformance_Release(performance); +} + START_TEST(dmime) { CoInitialize(NULL); @@ -1717,6 +1840,7 @@ START_TEST(dmime) test_performance_tool(); test_performance_graph(); test_performance_time(); + test_performance_pmsg(); CoUninitialize(); } From 12c571c97bee5a5a2767902fbb05c9b3287b9cb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Sep 2023 18:37:02 +0200 Subject: [PATCH 2456/2777] dmime/tests: Test IDirectMusicTool message reception filter. (cherry picked from commit 2ac84e2b94342618bcffb4ab7ba6ec5ee5703f24) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 99 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 91 insertions(+), 8 deletions(-) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 46751339994..a259ea599b8 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -61,6 +61,11 @@ struct test_tool LONG ref; IDirectMusicGraph *graph; + const DWORD *types; + DWORD types_count; + + HANDLE message_event; + DMUS_PMSG *message; }; static struct test_tool *impl_from_IDirectMusicTool(IDirectMusicTool *iface) @@ -98,6 +103,8 @@ static ULONG WINAPI test_tool_Release(IDirectMusicTool *iface) if (!ref) { if (tool->graph) IDirectMusicGraph_Release(tool->graph); + ok(!tool->message, "got %p\n", tool->message); + CloseHandle(tool->message_event); free(tool); } @@ -119,19 +126,35 @@ static HRESULT WINAPI test_tool_GetMsgDeliveryType(IDirectMusicTool *iface, DWOR static HRESULT WINAPI test_tool_GetMediaTypeArraySize(IDirectMusicTool *iface, DWORD *size) { - *size = 0; + struct test_tool *tool = impl_from_IDirectMusicTool(iface); + *size = tool->types_count; return S_OK; } static HRESULT WINAPI test_tool_GetMediaTypes(IDirectMusicTool *iface, DWORD **types, DWORD size) { - ok(0, "%#04lx: unexpected %s, types %p, size %lu\n", GetCurrentThreadId(), __func__, types, size); + struct test_tool *tool = impl_from_IDirectMusicTool(iface); + UINT i; + for (i = 0; i < tool->types_count; i++) (*types)[i] = tool->types[i]; return S_OK; } static HRESULT WINAPI test_tool_ProcessPMsg(IDirectMusicTool *iface, IDirectMusicPerformance *performance, DMUS_PMSG *msg) { - ok(0, "%#04lx: unexpected %s, iface %p, performance %p, msg %p\n", GetCurrentThreadId(), __func__, iface, performance, msg); + struct test_tool *tool = impl_from_IDirectMusicTool(iface); + DMUS_PMSG *clone; + HRESULT hr; + + hr = IDirectMusicPerformance8_ClonePMsg((IDirectMusicPerformance8 *)performance, msg, &clone); + ok(hr == S_OK, "got %#lx\n", hr); + + clone = InterlockedExchangePointer((void **)&tool->message, clone); + ok(!clone, "got %p\n", clone); + SetEvent(tool->message_event); + + hr = IDirectMusicGraph_StampPMsg(msg->pGraph, msg); + ok(hr == S_OK, "got %#lx\n", hr); + return DMUS_S_REQUEUE; } @@ -155,7 +178,8 @@ static IDirectMusicToolVtbl test_tool_vtbl = test_tool_Flush, }; -static HRESULT test_tool_create(IDirectMusicTool **ret_iface) +static HRESULT test_tool_create(const DWORD *types, DWORD types_count, + IDirectMusicTool **ret_iface) { struct test_tool *tool; @@ -164,6 +188,11 @@ static HRESULT test_tool_create(IDirectMusicTool **ret_iface) tool->IDirectMusicTool_iface.lpVtbl = &test_tool_vtbl; tool->ref = 1; + tool->types = types; + tool->types_count = types_count; + tool->message_event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!tool->message_event, "CreateEventW failed, error %lu\n", GetLastError()); + *ret_iface = &tool->IDirectMusicTool_iface; return S_OK; } @@ -175,6 +204,17 @@ static HRESULT test_tool_get_graph(IDirectMusicTool *iface, IDirectMusicGraph ** return tool->graph ? S_OK : DMUS_E_NOT_FOUND; } +static DWORD test_tool_wait_message(IDirectMusicTool *iface, DWORD timeout, DMUS_PMSG **msg) +{ + struct test_tool *tool = impl_from_IDirectMusicTool(iface); + DWORD ret; + + ret = WaitForSingleObject(tool->message_event, timeout); + *msg = InterlockedExchangePointer((void **)&tool->message, NULL); + + return ret; +} + static BOOL missing_dmime(void) { IDirectMusicSegment8 *dms; @@ -638,10 +678,10 @@ static void test_graph(void) IDirectMusicGraph_Release(graph); - hr = test_tool_create(&tool1); + hr = test_tool_create(NULL, 0, &tool1); ok(hr == S_OK, "got %#lx\n", hr); trace("created tool1 %p\n", tool1); - hr = test_tool_create(&tool2); + hr = test_tool_create(NULL, 0, &tool2); ok(hr == S_OK, "got %#lx\n", hr); trace("created tool2 %p\n", tool2); @@ -1486,7 +1526,7 @@ static void test_performance_graph(void) DMUS_PMSG msg; HRESULT hr; - hr = test_tool_create(&tool); + hr = test_tool_create(NULL, 0, &tool); ok(hr == S_OK, "got %#lx\n", hr); hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, @@ -1693,14 +1733,16 @@ static void test_performance_time(void) static void test_performance_pmsg(void) { + static const DWORD message_types[] = {DMUS_PMSGT_MIDI, DMUS_PMSGT_USER}; IDirectMusicPerformance *performance; IDirectMusicGraph *graph; IDirectMusicTool *tool; DMUS_PMSG *msg, *clone; REFERENCE_TIME time; HRESULT hr; + DWORD ret; - hr = test_tool_create(&tool); + hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool); ok(hr == S_OK, "got %#lx\n", hr); hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, @@ -1807,6 +1849,47 @@ static void test_performance_pmsg(void) ok(!msg->punkUser, "got %p\n", msg->punkUser); + /* SendPMsg skips all the tools unless messages are stamped beforehand */ + + hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg); + ok(hr == S_OK, "got %#lx\n", hr); + ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize); + msg->rtTime = time; + msg->dwFlags = DMUS_PMSGF_REFTIME; + msg->dwType = DMUS_PMSGT_USER; + hr = IDirectMusicPerformance_SendPMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 10, &msg); + ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); + ok(!msg, "got %p\n", msg); + + + hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg); + ok(hr == S_OK, "got %#lx\n", hr); + ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize); + msg->rtTime = time; + msg->dwFlags = DMUS_PMSGF_REFTIME; + msg->dwType = DMUS_PMSGT_USER; + + graph = NULL; + hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + if (graph) hr = IDirectMusicGraph_StampPMsg(graph, msg); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + if (graph) IDirectMusicGraph_Release(graph); + + hr = IDirectMusicPerformance_SendPMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 50, &msg); + todo_wine ok(!ret, "got %#lx\n", ret); + todo_wine ok(msg != NULL, "got %p\n", msg); + if (!msg) hr = S_OK; + else hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_CloseDown(performance); ok(hr == S_OK, "got %#lx\n", hr); From 769ee61e45bc5edb15e9529d39838cd30c9cd75e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 7 Sep 2023 10:21:31 +0200 Subject: [PATCH 2457/2777] dmime/tests: Test IDirectMusicTool message reception delay. (cherry picked from commit 5e68fa63944fbea2943de9aa651fb319eac8e613) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 46 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index a259ea599b8..f00b5073b48 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -1733,6 +1733,7 @@ static void test_performance_time(void) static void test_performance_pmsg(void) { + static const DWORD delivery_flags[] = {DMUS_PMSGF_TOOL_IMMEDIATE, DMUS_PMSGF_TOOL_QUEUE, DMUS_PMSGF_TOOL_ATTIME}; static const DWORD message_types[] = {DMUS_PMSGT_MIDI, DMUS_PMSGT_USER}; IDirectMusicPerformance *performance; IDirectMusicGraph *graph; @@ -1741,6 +1742,7 @@ static void test_performance_pmsg(void) REFERENCE_TIME time; HRESULT hr; DWORD ret; + UINT i; hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool); ok(hr == S_OK, "got %#lx\n", hr); @@ -1890,6 +1892,50 @@ static void test_performance_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr); + for (i = 0; i < ARRAY_SIZE(delivery_flags); i++) + { + DWORD duration = 0; + + hr = IDirectMusicPerformance_GetTime(performance, &time, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg); + ok(hr == S_OK, "got %#lx\n", hr); + ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize); + msg->rtTime = time + 150 * 10000; + msg->dwFlags = DMUS_PMSGF_REFTIME; + msg->dwType = DMUS_PMSGT_USER; + + hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + if (!graph) hr = S_OK; + else hr = IDirectMusicGraph_StampPMsg(graph, msg); + ok(hr == S_OK, "got %#lx\n", hr); + if (graph) IDirectMusicGraph_Release(graph); + + msg->dwFlags &= ~(DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME); + msg->dwFlags |= delivery_flags[i]; + + duration -= GetTickCount(); + hr = IDirectMusicPerformance_SendPMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + msg = NULL; + ret = test_tool_wait_message(tool, 1000, &msg); + todo_wine ok(!ret, "got %#lx\n", ret); + todo_wine ok(msg != NULL, "got %p\n", msg); + duration += GetTickCount(); + + if (msg) hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + + switch (delivery_flags[i]) + { + case DMUS_PMSGF_TOOL_IMMEDIATE: todo_wine ok(duration <= 50, "got %lu\n", duration); break; + case DMUS_PMSGF_TOOL_QUEUE: todo_wine ok(duration >= 50 && duration <= 100, "got %lu\n", duration); break; + case DMUS_PMSGF_TOOL_ATTIME: todo_wine ok(duration >= 150 && duration <= 500, "got %lu\n", duration); break; + } + } + + hr = IDirectMusicPerformance_CloseDown(performance); ok(hr == S_OK, "got %#lx\n", hr); From 64696f0f6136b2a44e991f03f1cad67b0449b516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 7 Sep 2023 11:14:35 +0200 Subject: [PATCH 2458/2777] dmsynth/tests: Test IDirectMusicSynth_Unload. (cherry picked from commit 971d7072738f3394aae42fc4ea6b7e1d8b0c938c) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/tests/dmsynth.c | 47 ++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index 46727afe557..e696ca34513 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -830,6 +830,22 @@ static void test_sink_render(IDirectMusicSynthSink *iface, void *buffer, DWORD b } } +static BOOL unload_called; + +static HRESULT CALLBACK test_unload_callback(HANDLE handle, HANDLE user_data) +{ + ok(!!handle, "got %p\n", handle); + ok(user_data == (HANDLE)0xdeadbeef, "got %p\n", user_data); + unload_called = TRUE; + return E_FAIL; +} + +static HRESULT CALLBACK test_unload_no_callback(HANDLE handle, HANDLE user_data) +{ + ok(0, "unexpected %s\n", __func__); + return E_FAIL; +} + static void test_IDirectMusicSynth(void) { static const UINT RENDER_ITERATIONS = 8; @@ -943,7 +959,7 @@ static void test_IDirectMusicSynth(void) IDirectMusicBuffer *buffer; DWORD format_size, written; IDirectMusicSynth *synth; - HANDLE wave_file, handle; + HANDLE wave_file, wave_handle, instrument_handle; IReferenceClock *clock; BOOL can_free = FALSE; REFERENCE_TIME time; @@ -1095,17 +1111,17 @@ static void test_IDirectMusicSynth(void) wave_download.samples[i] = i; can_free = 0xdeadbeef; - handle = (HANDLE)0xdeadbeef; - hr = IDirectMusicSynth_Download(synth, &handle, &wave_download, &can_free); + wave_handle = NULL; + hr = IDirectMusicSynth_Download(synth, &wave_handle, &wave_download, &can_free); ok(hr == S_OK, "got %#lx\n", hr); - ok(handle != 0, "got %p\n", handle); + todo_wine ok(!!wave_handle, "got %p\n", wave_handle); todo_wine ok(can_free == FALSE, "got %u\n", can_free); can_free = 0xdeadbeef; - handle = (HANDLE)0xdeadbeef; - hr = IDirectMusicSynth_Download(synth, &handle, &instrument_download, &can_free); + instrument_handle = NULL; + hr = IDirectMusicSynth_Download(synth, &instrument_handle, &instrument_download, &can_free); ok(hr == S_OK, "got %#lx\n", hr); - ok(handle != 0, "got %p\n", handle); + todo_wine ok(!!instrument_handle, "got %p\n", instrument_handle); todo_wine ok(can_free == TRUE, "got %u\n", can_free); /* add a MIDI note to a buffer and play it */ @@ -1133,15 +1149,32 @@ static void test_IDirectMusicSynth(void) CloseHandle(wave_file); trace("Rendered samples to %s\n", debugstr_w(temp_file)); + hr = IDirectMusicSynth_Activate(synth, FALSE); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicSynth_SetSynthSink(synth, NULL); ok(hr == S_OK, "got %#lx\n", hr); ref = get_refcount(sink); ok(ref == 1, "got %lu\n", ref); + + hr = IDirectMusicSynth_Unload(synth, 0, NULL, NULL); + todo_wine ok(hr == E_FAIL, "got %#lx\n", hr); + hr = IDirectMusicSynth_Unload(synth, (HANDLE)0xdeadbeef, test_unload_no_callback, (HANDLE)0xdeadbeef); + todo_wine ok(hr == E_FAIL, "got %#lx\n", hr); + hr = IDirectMusicSynth_Unload(synth, wave_handle, test_unload_callback, (HANDLE)0xdeadbeef); + ok(hr == S_OK, "got %#lx\n", hr); + ok(!unload_called, "callback called\n"); + hr = IDirectMusicSynth_Unload(synth, instrument_handle, NULL, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(unload_called, "callback not called\n"); + hr = IDirectMusicSynth_Close(synth); ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSynth_Unload(synth, 0, NULL, NULL); + todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + + IDirectMusicSynth_Release(synth); From 54409b2d468a75e44793fce35d97e8f8ce6aaa00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 11:38:09 +0200 Subject: [PATCH 2459/2777] dmusic: Avoid passing invalid handle to IDirectMusicSynth_Unload. (cherry picked from commit 82436b1ee8f7b893b91c7cc6c276a47bba1ee25f) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/port.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index 95857ea55ac..2f8556d149b 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -707,6 +707,7 @@ static HRESULT WINAPI synth_port_download_Unload(IDirectMusicPortDownload *iface } } + if (!handle) return S_OK; return IDirectMusicSynth_Unload(This->synth, handle, NULL, NULL); } From 47bf418f0a6b20815ce1ffdeb1dfc16deba72373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 11:38:09 +0200 Subject: [PATCH 2460/2777] dmsynth: Implement IDirectMusicSynth_(Download|Unload) for instruments. (cherry picked from commit 56fc711a936781837165d14794fa0e9086e9641e) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 229 ++++++++++++++++++----------------- dlls/dmsynth/tests/dmsynth.c | 10 +- 2 files changed, 121 insertions(+), 118 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index a93b23133f4..794e341046a 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -31,6 +31,35 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); +static void dump_dmus_instrument(DMUS_INSTRUMENT *instrument) +{ + TRACE("DMUS_INSTRUMENT:\n"); + TRACE(" - ulPatch = %lu\n", instrument->ulPatch); + TRACE(" - ulFirstRegionIdx = %lu\n", instrument->ulFirstRegionIdx); + TRACE(" - ulGlobalArtIdx = %lu\n", instrument->ulGlobalArtIdx); + TRACE(" - ulFirstExtCkIdx = %lu\n", instrument->ulFirstExtCkIdx); + TRACE(" - ulCopyrightIdx = %lu\n", instrument->ulCopyrightIdx); + TRACE(" - ulFlags = %lu\n", instrument->ulFlags); +} + +struct instrument +{ + struct list entry; + LONG ref; + UINT id; + + UINT patch; + UINT flags; + + struct synth *synth; +}; + +static void instrument_release(struct instrument *instrument) +{ + ULONG ref = InterlockedDecrement(&instrument->ref); + if (!ref) free(instrument); +} + struct synth { IDirectMusicSynth8 IDirectMusicSynth8_iface; @@ -42,6 +71,8 @@ struct synth BOOL active; BOOL open; IDirectMusicSynthSink *sink; + + struct list instruments; }; static inline struct synth *impl_from_IDirectMusicSynth8(IDirectMusicSynth8 *iface) @@ -95,7 +126,19 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) TRACE("(%p): new ref = %lu\n", This, ref); - if (!ref) free(This); + if (!ref) + { + struct instrument *instrument; + void *next; + + LIST_FOR_EACH_ENTRY_SAFE(instrument, next, &This->instruments, struct instrument, entry) + { + list_remove(&instrument->entry); + instrument_release(instrument); + } + + free(This); + } return ref; } @@ -210,134 +253,80 @@ static HRESULT WINAPI synth_SetNumChannelGroups(IDirectMusicSynth8 *iface, return S_OK; } -static HRESULT WINAPI synth_Download(IDirectMusicSynth8 *iface, HANDLE *hDownload, - void *data, BOOL *free) +static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO *info, ULONG *offsets, + BYTE *data, HANDLE *ret_handle) { - struct synth *This = impl_from_IDirectMusicSynth8(iface); - LPBYTE buffer = data; - DMUS_DOWNLOADINFO *info = (DMUS_DOWNLOADINFO*)buffer; - ULONG *offsets = ((DMUS_OFFSETTABLE*)(buffer + sizeof(DMUS_DOWNLOADINFO)))->ulOffsetTable; - LPBYTE object = buffer + sizeof(DMUS_DOWNLOADINFO) + info->dwNumOffsetTableEntries * sizeof(ULONG); - - FIXME("(%p)->(%p, %p, %p): stub\n", This, hDownload, data, free); - - /* FIXME: Currently we only dump data which is very useful to known how native dmusic behave and debug builtin dmusic */ - - if (!hDownload || !free) - return E_POINTER; + DMUS_INSTRUMENT *instrument_info = (DMUS_INSTRUMENT *)(data + offsets[0]); + struct instrument *instrument; if (TRACE_ON(dmsynth)) { - TRACE("Dump DMUS_DOWNLOADINFO struct:\n"); - TRACE(" - dwDLType = %lu\n", info->dwDLType); - TRACE(" - dwDLId = %lu\n", info->dwDLId); - TRACE(" - dwNumOffsetTableEntries = %lu\n", info->dwNumOffsetTableEntries); - TRACE(" - cbSize = %lu\n", info->cbSize); - } + dump_dmus_instrument(instrument_info); - /* The struct should have at least one offset corresponding to the download object itself */ - if (!info->dwNumOffsetTableEntries) - { - FIXME("Offset table is empty\n"); - return DMUS_E_BADOFFSETTABLE; - } - - /* First offset should point to the download object */ - if ((buffer + offsets[0]) != object) - { - FIXME("Object is not at the beginning\n"); - return DMUS_E_BADOFFSETTABLE; + if (instrument_info->ulCopyrightIdx) + { + DMUS_COPYRIGHT *copyright = (DMUS_COPYRIGHT *)(data + offsets[instrument_info->ulCopyrightIdx]); + TRACE("Copyright = '%s'\n", (char *)copyright->byCopyright); + } } - if (info->dwDLType == DMUS_DOWNLOADINFO_INSTRUMENT) - { - FIXME("Download type DMUS_DOWNLOADINFO_INSTRUMENT not yet supported\n"); - } - else if (info->dwDLType == DMUS_DOWNLOADINFO_WAVE) - { - DMUS_WAVE *wave = (DMUS_WAVE*)object; - DMUS_WAVEDATA *wave_data; + if (instrument_info->ulFirstExtCkIdx) FIXME("Instrument extensions not implemented\n"); - TRACE("Processing download type DMUS_DOWNLOADINFO_WAVE\n"); + if (!(instrument = calloc(1, sizeof(*instrument)))) return E_OUTOFMEMORY; + instrument->ref = 1; + instrument->id = info->dwDLId; + instrument->patch = instrument_info->ulPatch; + instrument->flags = instrument_info->ulFlags; + instrument->synth = This; - if (TRACE_ON(dmsynth)) - { - TRACE("Dump DMUS_WAVE struct\n"); - TRACE(" - ulFirstExtCkIdx = %lu\n", wave->ulFirstExtCkIdx); - TRACE(" - ulCopyrightIdx = %lu\n", wave->ulCopyrightIdx); - TRACE(" - ulWaveDataIdx = %lu\n", wave->ulWaveDataIdx); - TRACE(" - WaveformatEx:\n"); - TRACE(" - wFormatTag = %u\n", wave->WaveformatEx.wFormatTag); - TRACE(" - nChannels = %u\n", wave->WaveformatEx.nChannels); - TRACE(" - nSamplesPerSec = %lu\n", wave->WaveformatEx.nSamplesPerSec); - TRACE(" - nAvgBytesPerSec = %lu\n", wave->WaveformatEx.nAvgBytesPerSec); - TRACE(" - nBlockAlign = %u\n", wave->WaveformatEx.nBlockAlign); - TRACE(" - wBitsPerSample = %u\n", wave->WaveformatEx.wBitsPerSample); - TRACE(" - cbSize = %u\n", wave->WaveformatEx.cbSize); - - if (wave->ulCopyrightIdx) - { - DMUS_COPYRIGHT *copyright = (DMUS_COPYRIGHT*)(buffer + offsets[wave->ulCopyrightIdx]); - TRACE("Copyright = '%s'\n", (char*)copyright->byCopyright); - } + list_add_tail(&This->instruments, &instrument->entry); + *ret_handle = instrument; - wave_data = (DMUS_WAVEDATA*)(buffer + offsets[wave->ulWaveDataIdx]); - TRACE("Found %lu bytes of wave data\n", wave_data->cbSize); - } - } - else if (info->dwDLType == DMUS_DOWNLOADINFO_INSTRUMENT2) - { - DMUS_INSTRUMENT *instrument = (DMUS_INSTRUMENT*)object; - ULONG nb_regions = 0; + return S_OK; +} - TRACE("Processing download type DMUS_DOWNLOADINFO_INSTRUMENT2\n"); +static HRESULT WINAPI synth_Download(IDirectMusicSynth8 *iface, HANDLE *ret_handle, void *data, BOOL *ret_free) +{ + struct synth *This = impl_from_IDirectMusicSynth8(iface); + DMUS_DOWNLOADINFO *info = data; + ULONG *offsets = (ULONG *)(info + 1); - if (TRACE_ON(dmsynth)) - { - TRACE("Dump DMUS_INSTRUMENT struct\n"); - TRACE(" - ulPatch = %lu\n", instrument->ulPatch); - TRACE(" - ulFirstRegionIdx = %lu\n", instrument->ulFirstRegionIdx); - TRACE(" - ulGlobalArtIdx = %lu\n", instrument->ulGlobalArtIdx); - TRACE(" - ulFirstExtCkIdx = %lu\n", instrument->ulFirstExtCkIdx); - TRACE(" - ulCopyrightIdx = %lu\n", instrument->ulCopyrightIdx); - TRACE(" - ulFlags = %lu\n", instrument->ulFlags); - - if (instrument->ulCopyrightIdx) - { - DMUS_COPYRIGHT *copyright = (DMUS_COPYRIGHT*)(buffer + offsets[instrument->ulCopyrightIdx]); - TRACE("Copyright = '%s'\n", (char*)copyright->byCopyright); - } - } + FIXME("(%p)->(%p, %p, %p): stub\n", This, ret_handle, data, free); - if (instrument->ulFirstRegionIdx) - { - ULONG region_idx = instrument->ulFirstRegionIdx; + if (!ret_handle || !data || !ret_free) return E_POINTER; + *ret_handle = 0; + *ret_free = TRUE; - while (region_idx) - { - DMUS_REGION *region = (DMUS_REGION*)(buffer + offsets[region_idx]); + if (TRACE_ON(dmsynth)) + { + TRACE("Dump DMUS_DOWNLOADINFO struct:\n"); + TRACE(" - dwDLType = %lu\n", info->dwDLType); + TRACE(" - dwDLId = %lu\n", info->dwDLId); + TRACE(" - dwNumOffsetTableEntries = %lu\n", info->dwNumOffsetTableEntries); + TRACE(" - cbSize = %lu\n", info->cbSize); + } - region_idx = region->ulNextRegionIdx; - nb_regions++; - } - } + if (!info->dwNumOffsetTableEntries) return DMUS_E_BADOFFSETTABLE; + if (((BYTE *)data + offsets[0]) != (BYTE *)(offsets + info->dwNumOffsetTableEntries)) return DMUS_E_BADOFFSETTABLE; - TRACE("Number of regions = %lu\n", nb_regions); - } - else if (info->dwDLType == DMUS_DOWNLOADINFO_WAVEARTICULATION) + switch (info->dwDLType) { + case DMUS_DOWNLOADINFO_INSTRUMENT: + case DMUS_DOWNLOADINFO_INSTRUMENT2: + return synth_download_instrument(This, info, offsets, data, ret_handle); + case DMUS_DOWNLOADINFO_WAVE: + FIXME("Download type DMUS_DOWNLOADINFO_WAVE not yet supported\n"); + return S_OK; + case DMUS_DOWNLOADINFO_WAVEARTICULATION: FIXME("Download type DMUS_DOWNLOADINFO_WAVEARTICULATION not yet supported\n"); - } - else if (info->dwDLType == DMUS_DOWNLOADINFO_STREAMINGWAVE) - { + return E_NOTIMPL; + case DMUS_DOWNLOADINFO_STREAMINGWAVE: FIXME("Download type DMUS_DOWNLOADINFO_STREAMINGWAVE not yet supported\n"); - } - else if (info->dwDLType == DMUS_DOWNLOADINFO_ONESHOTWAVE) - { + return E_NOTIMPL; + case DMUS_DOWNLOADINFO_ONESHOTWAVE: FIXME("Download type DMUS_DOWNLOADINFO_ONESHOTWAVE not yet supported\n"); - } - else - { + return E_NOTIMPL; + default: WARN("Unknown download type %lu\n", info->dwDLType); return DMUS_E_UNKNOWNDOWNLOAD; } @@ -345,14 +334,26 @@ static HRESULT WINAPI synth_Download(IDirectMusicSynth8 *iface, HANDLE *hDownloa return S_OK; } -static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE hDownload, - HRESULT (CALLBACK *lpFreeHandle)(HANDLE,HANDLE), HANDLE hUserData) +static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE handle, + HRESULT (CALLBACK *callback)(HANDLE, HANDLE), HANDLE user_data) { struct synth *This = impl_from_IDirectMusicSynth8(iface); + struct instrument *instrument; - FIXME("(%p)->(%p, %p, %p): stub\n", This, hDownload, lpFreeHandle, hUserData); + TRACE("(%p)->(%p, %p, %p)\n", This, handle, callback, user_data); + if (callback) FIXME("Unload callbacks not implemented\n"); - return S_OK; + LIST_FOR_EACH_ENTRY(instrument, &This->instruments, struct instrument, entry) + { + if (instrument == handle) + { + list_remove(&instrument->entry); + instrument_release(instrument); + return S_OK; + } + } + + return E_FAIL; } static HRESULT WINAPI synth_PlayBuffer(IDirectMusicSynth8 *iface, @@ -745,6 +746,8 @@ HRESULT synth_create(IUnknown **ret_iface) obj->caps.dwEffectFlags = DMUS_EFFECT_REVERB; lstrcpyW(obj->caps.wszDescription, L"Microsoft Synthesizer"); + list_init(&obj->instruments); + TRACE("Created DirectMusicSynth %p\n", obj); *ret_iface = (IUnknown *)&obj->IDirectMusicSynth8_iface; return S_OK; diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index e696ca34513..7120d1e06c2 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -1121,8 +1121,8 @@ static void test_IDirectMusicSynth(void) instrument_handle = NULL; hr = IDirectMusicSynth_Download(synth, &instrument_handle, &instrument_download, &can_free); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(!!instrument_handle, "got %p\n", instrument_handle); - todo_wine ok(can_free == TRUE, "got %u\n", can_free); + ok(!!instrument_handle, "got %p\n", instrument_handle); + ok(can_free == TRUE, "got %u\n", can_free); /* add a MIDI note to a buffer and play it */ hr = IDirectMusicSynth_GetLatencyClock(synth, &latency_clock); @@ -1158,11 +1158,11 @@ static void test_IDirectMusicSynth(void) ok(ref == 1, "got %lu\n", ref); hr = IDirectMusicSynth_Unload(synth, 0, NULL, NULL); - todo_wine ok(hr == E_FAIL, "got %#lx\n", hr); + ok(hr == E_FAIL, "got %#lx\n", hr); hr = IDirectMusicSynth_Unload(synth, (HANDLE)0xdeadbeef, test_unload_no_callback, (HANDLE)0xdeadbeef); - todo_wine ok(hr == E_FAIL, "got %#lx\n", hr); + ok(hr == E_FAIL, "got %#lx\n", hr); hr = IDirectMusicSynth_Unload(synth, wave_handle, test_unload_callback, (HANDLE)0xdeadbeef); - ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); ok(!unload_called, "callback called\n"); hr = IDirectMusicSynth_Unload(synth, instrument_handle, NULL, NULL); ok(hr == S_OK, "got %#lx\n", hr); From 73e39ac60c052929b22618cb39340fa01104cfe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 8 Sep 2023 08:26:01 +0200 Subject: [PATCH 2461/2777] dmsynth: Implement IDirectMusicSynth_(Download|Unload) for waves. (cherry picked from commit 22f85dd9b8b5d6891f2b7bd1027b8dcb6b1e722e) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 120 ++++++++++++++++++++++++++++++++++- dlls/dmsynth/tests/dmsynth.c | 4 +- 2 files changed, 120 insertions(+), 4 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 794e341046a..e6f47b660c5 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -42,6 +42,41 @@ static void dump_dmus_instrument(DMUS_INSTRUMENT *instrument) TRACE(" - ulFlags = %lu\n", instrument->ulFlags); } +static void dump_dmus_wave(DMUS_WAVE *wave) +{ + TRACE("DMUS_WAVE:\n"); + TRACE(" - ulFirstExtCkIdx = %lu\n", wave->ulFirstExtCkIdx); + TRACE(" - ulCopyrightIdx = %lu\n", wave->ulCopyrightIdx); + TRACE(" - ulWaveDataIdx = %lu\n", wave->ulWaveDataIdx); + TRACE(" - WaveformatEx:\n"); + TRACE(" - wFormatTag = %u\n", wave->WaveformatEx.wFormatTag); + TRACE(" - nChannels = %u\n", wave->WaveformatEx.nChannels); + TRACE(" - nSamplesPerSec = %lu\n", wave->WaveformatEx.nSamplesPerSec); + TRACE(" - nAvgBytesPerSec = %lu\n", wave->WaveformatEx.nAvgBytesPerSec); + TRACE(" - nBlockAlign = %u\n", wave->WaveformatEx.nBlockAlign); + TRACE(" - wBitsPerSample = %u\n", wave->WaveformatEx.wBitsPerSample); + TRACE(" - cbSize = %u\n", wave->WaveformatEx.cbSize); +} + +struct wave +{ + struct list entry; + LONG ref; + UINT id; + + WAVEFORMATEX format; + UINT sample_count; + short samples[]; +}; + +C_ASSERT(sizeof(struct wave) == offsetof(struct wave, samples[0])); + +static void wave_release(struct wave *wave) +{ + ULONG ref = InterlockedDecrement(&wave->ref); + if (!ref) free(wave); +} + struct instrument { struct list entry; @@ -73,6 +108,7 @@ struct synth IDirectMusicSynthSink *sink; struct list instruments; + struct list waves; }; static inline struct synth *impl_from_IDirectMusicSynth8(IDirectMusicSynth8 *iface) @@ -129,6 +165,7 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) if (!ref) { struct instrument *instrument; + struct wave *wave; void *next; LIST_FOR_EACH_ENTRY_SAFE(instrument, next, &This->instruments, struct instrument, entry) @@ -137,6 +174,12 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) instrument_release(instrument); } + LIST_FOR_EACH_ENTRY_SAFE(wave, next, &This->waves, struct wave, entry) + { + list_remove(&wave->entry); + wave_release(wave); + } + free(This); } @@ -285,6 +328,68 @@ static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO * return S_OK; } +static HRESULT synth_download_wave(struct synth *This, DMUS_DOWNLOADINFO *info, ULONG *offsets, + BYTE *data, HANDLE *ret_handle) +{ + DMUS_WAVE *wave_info = (DMUS_WAVE *)(data + offsets[0]); + DMUS_WAVEDATA *wave_data = (DMUS_WAVEDATA *)(data + offsets[wave_info->ulWaveDataIdx]); + struct wave *wave; + UINT sample_count; + + if (TRACE_ON(dmsynth)) + { + dump_dmus_wave(wave_info); + + if (wave_info->ulCopyrightIdx) + { + DMUS_COPYRIGHT *copyright = (DMUS_COPYRIGHT *)(data + offsets[wave_info->ulCopyrightIdx]); + TRACE("Copyright = '%s'\n", (char *)copyright->byCopyright); + } + + TRACE("Found %lu bytes of wave data\n", wave_data->cbSize); + } + + if (wave_info->ulFirstExtCkIdx) FIXME("Wave extensions not implemented\n"); + if (wave_info->WaveformatEx.wFormatTag != WAVE_FORMAT_PCM) return DMUS_E_NOTPCM; + + sample_count = wave_data->cbSize / wave_info->WaveformatEx.nBlockAlign; + if (!(wave = calloc(1, offsetof(struct wave, samples[sample_count])))) return E_OUTOFMEMORY; + wave->ref = 1; + wave->id = info->dwDLId; + wave->format = wave_info->WaveformatEx; + wave->sample_count = sample_count; + + if (wave_info->WaveformatEx.nBlockAlign == 1) + { + while (sample_count--) + { + short sample = (wave_data->byData[sample_count] - 0x80) << 8; + wave->samples[sample_count] = sample; + } + } + else if (wave_info->WaveformatEx.nBlockAlign == 2) + { + while (sample_count--) + { + short sample = ((short *)wave_data->byData)[sample_count]; + wave->samples[sample_count] = sample; + } + } + else if (wave_info->WaveformatEx.nBlockAlign == 4) + { + while (sample_count--) + { + short sample = ((UINT *)wave_data->byData)[sample_count] >> 16; + wave->samples[sample_count] = sample; + } + } + + list_add_tail(&This->waves, &wave->entry); + *ret_handle = wave; + + return S_OK; +} + static HRESULT WINAPI synth_Download(IDirectMusicSynth8 *iface, HANDLE *ret_handle, void *data, BOOL *ret_free) { struct synth *This = impl_from_IDirectMusicSynth8(iface); @@ -315,8 +420,7 @@ static HRESULT WINAPI synth_Download(IDirectMusicSynth8 *iface, HANDLE *ret_hand case DMUS_DOWNLOADINFO_INSTRUMENT2: return synth_download_instrument(This, info, offsets, data, ret_handle); case DMUS_DOWNLOADINFO_WAVE: - FIXME("Download type DMUS_DOWNLOADINFO_WAVE not yet supported\n"); - return S_OK; + return synth_download_wave(This, info, offsets, data, ret_handle); case DMUS_DOWNLOADINFO_WAVEARTICULATION: FIXME("Download type DMUS_DOWNLOADINFO_WAVEARTICULATION not yet supported\n"); return E_NOTIMPL; @@ -339,6 +443,7 @@ static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE handle, { struct synth *This = impl_from_IDirectMusicSynth8(iface); struct instrument *instrument; + struct wave *wave; TRACE("(%p)->(%p, %p, %p)\n", This, handle, callback, user_data); if (callback) FIXME("Unload callbacks not implemented\n"); @@ -353,6 +458,16 @@ static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE handle, } } + LIST_FOR_EACH_ENTRY(wave, &This->waves, struct wave, entry) + { + if (wave == handle) + { + list_remove(&wave->entry); + wave_release(wave); + return S_OK; + } + } + return E_FAIL; } @@ -747,6 +862,7 @@ HRESULT synth_create(IUnknown **ret_iface) lstrcpyW(obj->caps.wszDescription, L"Microsoft Synthesizer"); list_init(&obj->instruments); + list_init(&obj->waves); TRACE("Created DirectMusicSynth %p\n", obj); *ret_iface = (IUnknown *)&obj->IDirectMusicSynth8_iface; diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index 7120d1e06c2..51504d68a17 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -1114,7 +1114,7 @@ static void test_IDirectMusicSynth(void) wave_handle = NULL; hr = IDirectMusicSynth_Download(synth, &wave_handle, &wave_download, &can_free); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(!!wave_handle, "got %p\n", wave_handle); + ok(!!wave_handle, "got %p\n", wave_handle); todo_wine ok(can_free == FALSE, "got %u\n", can_free); can_free = 0xdeadbeef; @@ -1162,7 +1162,7 @@ static void test_IDirectMusicSynth(void) hr = IDirectMusicSynth_Unload(synth, (HANDLE)0xdeadbeef, test_unload_no_callback, (HANDLE)0xdeadbeef); ok(hr == E_FAIL, "got %#lx\n", hr); hr = IDirectMusicSynth_Unload(synth, wave_handle, test_unload_callback, (HANDLE)0xdeadbeef); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); ok(!unload_called, "callback called\n"); hr = IDirectMusicSynth_Unload(synth, instrument_handle, NULL, NULL); ok(hr == S_OK, "got %#lx\n", hr); From 4af08dd2d47966f5f5ec4ddf6e5f135712cd5ec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 7 Sep 2023 12:07:59 +0200 Subject: [PATCH 2462/2777] dmsynth: Implement IDirectMusicSynth_Download for instrument regions. (cherry picked from commit 4fa0978394066d10ca3b1015b929ff0febf27f61) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 126 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 1 deletion(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index e6f47b660c5..c3b99063834 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -42,6 +42,40 @@ static void dump_dmus_instrument(DMUS_INSTRUMENT *instrument) TRACE(" - ulFlags = %lu\n", instrument->ulFlags); } +static void dump_dmus_region(DMUS_REGION *region) +{ + UINT i; + + TRACE("DMUS_REGION:\n"); + TRACE(" - RangeKey = %u - %u\n", region->RangeKey.usLow, region->RangeKey.usHigh); + TRACE(" - RangeVelocity = %u - %u\n", region->RangeVelocity.usLow, region->RangeVelocity.usHigh); + TRACE(" - fusOptions = %#x\n", region->fusOptions); + TRACE(" - usKeyGroup = %u\n", region->usKeyGroup); + TRACE(" - ulRegionArtIdx = %lu\n", region->ulRegionArtIdx); + TRACE(" - ulNextRegionIdx = %lu\n", region->ulNextRegionIdx); + TRACE(" - ulFirstExtCkIdx = %lu\n", region->ulFirstExtCkIdx); + TRACE(" - WaveLink:\n"); + TRACE(" - fusOptions = %#x\n", region->WaveLink.fusOptions); + TRACE(" - usPhaseGroup = %u\n", region->WaveLink.usPhaseGroup); + TRACE(" - ulChannel = %lu\n", region->WaveLink.ulChannel); + TRACE(" - ulTableIndex = %lu\n", region->WaveLink.ulTableIndex); + TRACE(" - WSMP:\n"); + TRACE(" - cbSize = %lu\n", region->WSMP.cbSize); + TRACE(" - usUnityNote = %u\n", region->WSMP.usUnityNote); + TRACE(" - sFineTune = %u\n", region->WSMP.sFineTune); + TRACE(" - lAttenuation = %lu\n", region->WSMP.lAttenuation); + TRACE(" - fulOptions = %#lx\n", region->WSMP.fulOptions); + TRACE(" - cSampleLoops = %lu\n", region->WSMP.cSampleLoops); + for (i = 0; i < region->WSMP.cSampleLoops; i++) + { + TRACE(" - WLOOP[%u]:\n", i); + TRACE(" - cbSize = %lu\n", region->WLOOP[i].cbSize); + TRACE(" - ulType = %#lx\n", region->WLOOP[i].ulType); + TRACE(" - ulStart = %lu\n", region->WLOOP[i].ulStart); + TRACE(" - ulLength = %lu\n", region->WLOOP[i].ulLength); + } +} + static void dump_dmus_wave(DMUS_WAVE *wave) { TRACE("DMUS_WAVE:\n"); @@ -71,12 +105,38 @@ struct wave C_ASSERT(sizeof(struct wave) == offsetof(struct wave, samples[0])); +static void wave_addref(struct wave *wave) +{ + InterlockedIncrement(&wave->ref); +} + static void wave_release(struct wave *wave) { ULONG ref = InterlockedDecrement(&wave->ref); if (!ref) free(wave); } +struct region +{ + struct list entry; + + RGNRANGE key_range; + RGNRANGE vel_range; + UINT flags; + UINT group; + + struct wave *wave; + WAVELINK wave_link; + WSMPL wave_sample; + WLOOP wave_loops[]; +}; + +static void region_destroy(struct region *region) +{ + wave_release(region->wave); + free(region); +} + struct instrument { struct list entry; @@ -85,6 +145,7 @@ struct instrument UINT patch; UINT flags; + struct list regions; struct synth *synth; }; @@ -92,7 +153,20 @@ struct instrument static void instrument_release(struct instrument *instrument) { ULONG ref = InterlockedDecrement(&instrument->ref); - if (!ref) free(instrument); + + if (!ref) + { + struct region *region; + void *next; + + LIST_FOR_EACH_ENTRY_SAFE(region, next, &instrument->regions, struct region, entry) + { + list_remove(®ion->entry); + region_destroy(region); + } + + free(instrument); + } } struct synth @@ -296,11 +370,31 @@ static HRESULT WINAPI synth_SetNumChannelGroups(IDirectMusicSynth8 *iface, return S_OK; } +static struct wave *synth_find_wave_from_id(struct synth *This, DWORD id) +{ + struct wave *wave; + + LIST_FOR_EACH_ENTRY(wave, &This->waves, struct wave, entry) + { + if (wave->id == id) + { + wave_addref(wave); + return wave; + } + } + + WARN("Failed to find wave with id %#lx\n", id); + return NULL; +} + static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO *info, ULONG *offsets, BYTE *data, HANDLE *ret_handle) { DMUS_INSTRUMENT *instrument_info = (DMUS_INSTRUMENT *)(data + offsets[0]); struct instrument *instrument; + DMUS_REGION *region_info; + struct region *region; + ULONG index; if (TRACE_ON(dmsynth)) { @@ -320,12 +414,42 @@ static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO * instrument->id = info->dwDLId; instrument->patch = instrument_info->ulPatch; instrument->flags = instrument_info->ulFlags; + list_init(&instrument->regions); instrument->synth = This; + for (index = instrument_info->ulFirstRegionIdx; index; index = region_info->ulNextRegionIdx) + { + region_info = (DMUS_REGION *)(data + offsets[index]); + if (TRACE_ON(dmsynth)) dump_dmus_region(region_info); + if (region_info->ulFirstExtCkIdx) FIXME("Region extensions not implemented\n"); + + if (!(region = calloc(1, offsetof(struct region, wave_loops[region_info->WSMP.cSampleLoops])))) goto error; + region->key_range = region_info->RangeKey; + region->vel_range = region_info->RangeVelocity; + region->flags = region_info->fusOptions; + region->group = region_info->usKeyGroup; + region->wave_link = region_info->WaveLink; + region->wave_sample = region_info->WSMP; + memcpy(region->wave_loops, region_info->WLOOP, region_info->WSMP.cSampleLoops * sizeof(WLOOP)); + + if (!(region->wave = synth_find_wave_from_id(This, region->wave_link.ulTableIndex))) + { + free(region); + instrument_release(instrument); + return DMUS_E_BADWAVELINK; + } + + list_add_tail(&instrument->regions, ®ion->entry); + } + list_add_tail(&This->instruments, &instrument->entry); *ret_handle = instrument; return S_OK; + +error: + instrument_release(instrument); + return E_OUTOFMEMORY; } static HRESULT synth_download_wave(struct synth *This, DMUS_DOWNLOADINFO *info, ULONG *offsets, From 3290edce10ddb0056c4dc6b5dff7ce4333b3da0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 7 Sep 2023 11:46:19 +0200 Subject: [PATCH 2463/2777] dmsynth: Implement IDirectMusicSynth_Download for instrument articulations. (cherry picked from commit 223ba990b1d8914c5ec6a1b57e28e1299ee653a8) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 101 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index c3b99063834..d87afd245e9 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -76,6 +76,26 @@ static void dump_dmus_region(DMUS_REGION *region) } } +static void dump_connectionlist(CONNECTIONLIST *list) +{ + CONNECTION *connections = (CONNECTION *)(list + 1); + UINT i; + + TRACE("CONNECTIONLIST:\n"); + TRACE(" - cbSize = %lu", list->cbSize); + TRACE(" - cConnections = %lu", list->cConnections); + + for (i = 0; i < list->cConnections; i++) + { + TRACE("- CONNECTION[%u]:\n", i); + TRACE(" - usSource = %u\n", connections[i].usSource); + TRACE(" - usControl = %u\n", connections[i].usControl); + TRACE(" - usDestination = %u\n", connections[i].usDestination); + TRACE(" - usTransform = %u\n", connections[i].usTransform); + TRACE(" - lScale = %lu\n", connections[i].lScale); + } +} + static void dump_dmus_wave(DMUS_WAVE *wave) { TRACE("DMUS_WAVE:\n"); @@ -116,6 +136,15 @@ static void wave_release(struct wave *wave) if (!ref) free(wave); } +struct articulation +{ + struct list entry; + CONNECTIONLIST list; + CONNECTION connections[]; +}; + +C_ASSERT(sizeof(struct articulation) == offsetof(struct articulation, connections[0])); + struct region { struct list entry; @@ -125,6 +154,8 @@ struct region UINT flags; UINT group; + struct list articulations; + struct wave *wave; WAVELINK wave_link; WSMPL wave_sample; @@ -133,6 +164,15 @@ struct region static void region_destroy(struct region *region) { + struct articulation *articulation; + void *next; + + LIST_FOR_EACH_ENTRY_SAFE(articulation, next, ®ion->articulations, struct articulation, entry) + { + list_remove(&articulation->entry); + free(articulation); + } + wave_release(region->wave); free(region); } @@ -146,6 +186,7 @@ struct instrument UINT patch; UINT flags; struct list regions; + struct list articulations; struct synth *synth; }; @@ -156,6 +197,7 @@ static void instrument_release(struct instrument *instrument) if (!ref) { + struct articulation *articulation; struct region *region; void *next; @@ -165,6 +207,12 @@ static void instrument_release(struct instrument *instrument) region_destroy(region); } + LIST_FOR_EACH_ENTRY_SAFE(articulation, next, &instrument->articulations, struct articulation, entry) + { + list_remove(&articulation->entry); + free(articulation); + } + free(instrument); } } @@ -370,6 +418,47 @@ static HRESULT WINAPI synth_SetNumChannelGroups(IDirectMusicSynth8 *iface, return S_OK; } +static HRESULT synth_download_articulation2(struct synth *This, ULONG *offsets, BYTE *data, + UINT index, struct list *articulations) +{ + DMUS_ARTICULATION2 *articulation_info; + struct articulation *articulation; + CONNECTION *connections; + CONNECTIONLIST *list; + UINT size; + + for (; index; index = articulation_info->ulNextArtIdx) + { + articulation_info = (DMUS_ARTICULATION2 *)(data + offsets[index]); + list = (CONNECTIONLIST *)(data + offsets[articulation_info->ulArtIdx]); + connections = (CONNECTION *)list + 1; + + if (TRACE_ON(dmsynth)) dump_connectionlist(list); + if (articulation_info->ulFirstExtCkIdx) FIXME("Articulation extensions not implemented\n"); + if (list->cbSize != sizeof(*list)) return DMUS_E_BADARTICULATION; + + size = offsetof(struct articulation, connections[list->cConnections]); + if (!(articulation = calloc(1, size))) return E_OUTOFMEMORY; + articulation->list = *list; + memcpy(articulation->connections, connections, list->cConnections * sizeof(*connections)); + list_add_tail(articulations, &articulation->entry); + } + + return S_OK; +} + +static HRESULT synth_download_articulation(struct synth *This, DMUS_DOWNLOADINFO *info, ULONG *offsets, BYTE *data, + UINT index, struct list *list) +{ + if (info->dwDLType == DMUS_DOWNLOADINFO_INSTRUMENT2) + return synth_download_articulation2(This, offsets, data, index, list); + else + { + FIXME("DMUS_ARTICPARAMS support not implemented\n"); + return S_OK; + } +} + static struct wave *synth_find_wave_from_id(struct synth *This, DWORD id) { struct wave *wave; @@ -415,6 +504,7 @@ static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO * instrument->patch = instrument_info->ulPatch; instrument->flags = instrument_info->ulFlags; list_init(&instrument->regions); + list_init(&instrument->articulations); instrument->synth = This; for (index = instrument_info->ulFirstRegionIdx; index; index = region_info->ulNextRegionIdx) @@ -431,6 +521,7 @@ static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO * region->wave_link = region_info->WaveLink; region->wave_sample = region_info->WSMP; memcpy(region->wave_loops, region_info->WLOOP, region_info->WSMP.cSampleLoops * sizeof(WLOOP)); + list_init(®ion->articulations); if (!(region->wave = synth_find_wave_from_id(This, region->wave_link.ulTableIndex))) { @@ -440,8 +531,16 @@ static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO * } list_add_tail(&instrument->regions, ®ion->entry); + + if (region_info->ulRegionArtIdx && FAILED(synth_download_articulation(This, info, offsets, data, + region_info->ulRegionArtIdx, ®ion->articulations))) + goto error; } + if (FAILED(synth_download_articulation(This, info, offsets, data, + instrument_info->ulGlobalArtIdx, &instrument->articulations))) + goto error; + list_add_tail(&This->instruments, &instrument->entry); *ret_handle = instrument; @@ -520,7 +619,7 @@ static HRESULT WINAPI synth_Download(IDirectMusicSynth8 *iface, HANDLE *ret_hand DMUS_DOWNLOADINFO *info = data; ULONG *offsets = (ULONG *)(info + 1); - FIXME("(%p)->(%p, %p, %p): stub\n", This, ret_handle, data, free); + TRACE("(%p)->(%p, %p, %p)\n", This, ret_handle, data, free); if (!ret_handle || !data || !ret_free) return E_POINTER; *ret_handle = 0; From f03e07f11770ee6d1e507909f366180b20ff4bfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 31 Aug 2023 21:32:06 +0200 Subject: [PATCH 2464/2777] dmusic: Use a struct list for instrument articulations. (cherry picked from commit febe6a78102ad30c425c9fd1ce328fe32f84e35e) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/dmusic_private.h | 9 ++---- dlls/dmusic/instrument.c | 60 ++++++++++++++++++++---------------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 5c8f6e1abad..e643f0a6770 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -82,11 +82,6 @@ typedef struct instrument_region { BOOL loop_present; } instrument_region; -typedef struct instrument_articulation { - CONNECTIONLIST connections_list; - CONNECTION *connections; -} instrument_articulation; - /***************************************************************************** * ClassFactory */ @@ -189,8 +184,8 @@ struct instrument /* instrument data */ BOOL loaded; instrument_region *regions; - ULONG nb_articulations; - instrument_articulation *articulations; + + struct list articulations; }; static inline struct instrument *impl_from_IDirectMusicInstrument(IDirectMusicInstrument *iface) diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index 5677f128060..a65826976f3 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -25,6 +25,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmusic); static const GUID IID_IDirectMusicInstrumentPRIVATE = { 0xbcb20080, 0xa40c, 0x11d1, { 0x86, 0xbc, 0x00, 0xc0, 0x4f, 0xbf, 0x8f, 0xef } }; +struct articulation +{ + struct list entry; + CONNECTIONLIST list; + CONNECTION connections[]; +}; + +C_ASSERT(sizeof(struct articulation) == offsetof(struct articulation, connections[0])); + static HRESULT WINAPI instrument_QueryInterface(LPDIRECTMUSICINSTRUMENT iface, REFIID riid, LPVOID *ret_iface) { TRACE("(%p)->(%s, %p)\n", iface, debugstr_dmguid(riid), ret_iface); @@ -74,12 +83,16 @@ static ULONG WINAPI instrument_Release(LPDIRECTMUSICINSTRUMENT iface) if (!ref) { - ULONG i; + struct articulation *articulation, *next_articulation; free(This->regions); - for (i = 0; i < This->nb_articulations; i++) - free(This->articulations->connections); - free(This->articulations); + + LIST_FOR_EACH_ENTRY_SAFE(articulation, next_articulation, &This->articulations, struct articulation, entry) + { + list_remove(&articulation->entry); + free(articulation); + } + free(This); } @@ -125,6 +138,7 @@ HRESULT instrument_create(IDirectMusicInstrument **ret_iface) if (!(instrument = calloc(1, sizeof(*instrument)))) return E_OUTOFMEMORY; instrument->IDirectMusicInstrument_iface.lpVtbl = &instrument_vtbl; instrument->ref = 1; + list_init(&instrument->articulations); TRACE("Created DirectMusicInstrument %p\n", instrument); *ret_iface = &instrument->IDirectMusicInstrument_iface; @@ -244,35 +258,27 @@ static HRESULT load_region(struct instrument *This, IStream *stream, instrument_ static HRESULT load_articulation(struct instrument *This, IStream *stream, ULONG length) { - HRESULT ret; - instrument_articulation *articulation; - - This->articulations = realloc(This->articulations, sizeof(*This->articulations) * (This->nb_articulations + 1)); - if (!This->articulations) - return E_OUTOFMEMORY; + struct articulation *articulation; + CONNECTIONLIST list; + HRESULT hr; + UINT size; - articulation = &This->articulations[This->nb_articulations]; + if (FAILED(hr = read_from_stream(stream, &list, sizeof(list)))) return hr; + if (list.cbSize != sizeof(list)) return E_INVALIDARG; - ret = read_from_stream(stream, &articulation->connections_list, sizeof(CONNECTIONLIST)); - if (FAILED(ret)) - return ret; - - articulation->connections = malloc(sizeof(CONNECTION) * articulation->connections_list.cConnections); - if (!articulation->connections) - return E_OUTOFMEMORY; + size = offsetof(struct articulation, connections[list.cConnections]); + if (!(articulation = malloc(size))) return E_OUTOFMEMORY; + articulation->list = list; - ret = read_from_stream(stream, articulation->connections, sizeof(CONNECTION) * articulation->connections_list.cConnections); - if (FAILED(ret)) + size = sizeof(CONNECTION) * list.cConnections; + if (FAILED(hr = read_from_stream(stream, articulation->connections, size))) free(articulation); + else { - free(articulation->connections); - return ret; + subtract_bytes(length, sizeof(list) + sizeof(CONNECTION) * list.cConnections); + list_add_tail(&This->articulations, &articulation->entry); } - subtract_bytes(length, sizeof(CONNECTIONLIST) + sizeof(CONNECTION) * articulation->connections_list.cConnections); - - This->nb_articulations++; - - return S_OK; + return hr; } /* Function that loads all instrument data and which is called from IDirectMusicCollection_GetInstrument as in native */ From 0e24083294034010855b0fe15f81948b6b7eec13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 31 Aug 2023 21:36:18 +0200 Subject: [PATCH 2465/2777] dmusic: Use a struct list for instrument regions. (cherry picked from commit 52d3f7ab09f8b4920c71eaa0c385f13f4bf1fa2a) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/dmusic_private.h | 8 +++--- dlls/dmusic/instrument.c | 50 ++++++++++++++++++------------------ dlls/dmusic/port.c | 19 ++++++++------ 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index e643f0a6770..331aa683f4b 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -74,13 +74,15 @@ typedef struct port_info { ULONG device; } port_info; -typedef struct instrument_region { +struct region +{ + struct list entry; RGNHEADER header; WAVELINK wave_link; WSMPL wave_sample; WLOOP wave_loop; BOOL loop_present; -} instrument_region; +}; /***************************************************************************** * ClassFactory @@ -183,9 +185,9 @@ struct instrument WCHAR wszName[DMUS_MAX_NAME]; /* instrument data */ BOOL loaded; - instrument_region *regions; struct list articulations; + struct list regions; }; static inline struct instrument *impl_from_IDirectMusicInstrument(IDirectMusicInstrument *iface) diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index a65826976f3..bcd2ef58265 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -84,8 +84,7 @@ static ULONG WINAPI instrument_Release(LPDIRECTMUSICINSTRUMENT iface) if (!ref) { struct articulation *articulation, *next_articulation; - - free(This->regions); + struct region *region, *next_region; LIST_FOR_EACH_ENTRY_SAFE(articulation, next_articulation, &This->articulations, struct articulation, entry) { @@ -93,6 +92,12 @@ static ULONG WINAPI instrument_Release(LPDIRECTMUSICINSTRUMENT iface) free(articulation); } + LIST_FOR_EACH_ENTRY_SAFE(region, next_region, &This->regions, struct region, entry) + { + list_remove(®ion->entry); + free(region); + } + free(This); } @@ -139,6 +144,7 @@ HRESULT instrument_create(IDirectMusicInstrument **ret_iface) instrument->IDirectMusicInstrument_iface.lpVtbl = &instrument_vtbl; instrument->ref = 1; list_init(&instrument->articulations); + list_init(&instrument->regions); TRACE("Created DirectMusicInstrument %p\n", instrument); *ret_iface = &instrument->IDirectMusicInstrument_iface; @@ -186,18 +192,20 @@ static inline HRESULT advance_stream(IStream *stream, ULONG bytes) return ret; } -static HRESULT load_region(struct instrument *This, IStream *stream, instrument_region *region, ULONG length) +static HRESULT load_region(struct instrument *This, IStream *stream, ULONG length) { + struct region *region; HRESULT ret; DMUS_PRIVATE_CHUNK chunk; - TRACE("(%p, %p, %p, %lu)\n", This, stream, region, length); + TRACE("(%p, %p, %lu)\n", This, stream, length); + + if (!(region = malloc(sizeof(*region)))) return E_OUTOFMEMORY; while (length) { ret = read_from_stream(stream, &chunk, sizeof(chunk)); - if (FAILED(ret)) - return ret; + if (FAILED(ret)) goto failed; length = subtract_bytes(length, sizeof(chunk)); @@ -207,8 +215,7 @@ static HRESULT load_region(struct instrument *This, IStream *stream, instrument_ TRACE("RGNH chunk (region header): %lu bytes\n", chunk.dwSize); ret = read_from_stream(stream, ®ion->header, sizeof(region->header)); - if (FAILED(ret)) - return ret; + if (FAILED(ret)) goto failed; length = subtract_bytes(length, sizeof(region->header)); break; @@ -217,16 +224,14 @@ static HRESULT load_region(struct instrument *This, IStream *stream, instrument_ TRACE("WSMP chunk (wave sample): %lu bytes\n", chunk.dwSize); ret = read_from_stream(stream, ®ion->wave_sample, sizeof(region->wave_sample)); - if (FAILED(ret)) - return ret; + if (FAILED(ret)) goto failed; length = subtract_bytes(length, sizeof(region->wave_sample)); if (!(region->loop_present = (chunk.dwSize != sizeof(region->wave_sample)))) break; ret = read_from_stream(stream, ®ion->wave_loop, sizeof(region->wave_loop)); - if (FAILED(ret)) - return ret; + if (FAILED(ret)) goto failed; length = subtract_bytes(length, sizeof(region->wave_loop)); break; @@ -235,8 +240,7 @@ static HRESULT load_region(struct instrument *This, IStream *stream, instrument_ TRACE("WLNK chunk (wave link): %lu bytes\n", chunk.dwSize); ret = read_from_stream(stream, ®ion->wave_link, sizeof(region->wave_link)); - if (FAILED(ret)) - return ret; + if (FAILED(ret)) goto failed; length = subtract_bytes(length, sizeof(region->wave_link)); break; @@ -245,15 +249,19 @@ static HRESULT load_region(struct instrument *This, IStream *stream, instrument_ TRACE("Unknown chunk %s (skipping): %lu bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize); ret = advance_stream(stream, chunk.dwSize); - if (FAILED(ret)) - return ret; + if (FAILED(ret)) goto failed; length = subtract_bytes(length, chunk.dwSize); break; } } + list_add_tail(&This->regions, ®ion->entry); return S_OK; + +failed: + free(region); + return ret; } static HRESULT load_articulation(struct instrument *This, IStream *stream, ULONG length) @@ -287,7 +295,6 @@ HRESULT instrument_load(IDirectMusicInstrument *iface, IStream *stream) struct instrument *This = impl_from_IDirectMusicInstrument(iface); HRESULT hr; DMUS_PRIVATE_CHUNK chunk; - ULONG i = 0; ULONG length = This->length; TRACE("(%p, %p): offset = 0x%s, length = %lu)\n", This, stream, wine_dbgstr_longlong(This->liInstrumentPosition.QuadPart), This->length); @@ -302,10 +309,6 @@ HRESULT instrument_load(IDirectMusicInstrument *iface, IStream *stream) return DMUS_E_UNSUPPORTED_STREAM; } - This->regions = malloc(sizeof(*This->regions) * This->header.cRegions); - if (!This->regions) - return E_OUTOFMEMORY; - while (length) { hr = read_from_stream(stream, &chunk, sizeof(chunk)); @@ -362,7 +365,7 @@ HRESULT instrument_load(IDirectMusicInstrument *iface, IStream *stream) if (chunk.fccID == FOURCC_RGN) { TRACE("RGN chunk (region): %lu bytes\n", chunk.dwSize); - hr = load_region(This, stream, &This->regions[i++], chunk.dwSize - sizeof(chunk.fccID)); + hr = load_region(This, stream, chunk.dwSize - sizeof(chunk.fccID)); } else { @@ -431,8 +434,5 @@ HRESULT instrument_load(IDirectMusicInstrument *iface, IStream *stream) return S_OK; error: - free(This->regions); - This->regions = NULL; - return DMUS_E_UNSUPPORTED_STREAM; } diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index 2f8556d149b..27e20b1cf81 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -267,6 +267,7 @@ static HRESULT WINAPI synth_port_DownloadInstrument(IDirectMusicPort *iface, IDi { struct synth_port *This = synth_from_IDirectMusicPort(iface); struct instrument *instrument_object; + struct region *instrument_region; HRESULT ret; BOOL on_heap; HANDLE download; @@ -312,22 +313,24 @@ static HRESULT WINAPI synth_port_DownloadInstrument(IDirectMusicPort *iface, IDi instrument_info->ulCopyrightIdx = 0; /* FIXME */ instrument_info->ulFlags = 0; /* FIXME */ - for (i = 0; i < nb_regions; i++) + i = 0; + LIST_FOR_EACH_ENTRY(instrument_region, &instrument_object->regions, struct region, entry) { DMUS_REGION *region = (DMUS_REGION*)(data + offset); offset_table->ulOffsetTable[1 + i] = offset; offset += sizeof(DMUS_REGION); - region->RangeKey = instrument_object->regions[i].header.RangeKey; - region->RangeVelocity = instrument_object->regions[i].header.RangeVelocity; - region->fusOptions = instrument_object->regions[i].header.fusOptions; - region->usKeyGroup = instrument_object->regions[i].header.usKeyGroup; + region->RangeKey = instrument_region->header.RangeKey; + region->RangeVelocity = instrument_region->header.RangeVelocity; + region->fusOptions = instrument_region->header.fusOptions; + region->usKeyGroup = instrument_region->header.usKeyGroup; region->ulRegionArtIdx = 0; /* FIXME */ region->ulNextRegionIdx = i != (nb_regions - 1) ? (i + 2) : 0; region->ulFirstExtCkIdx = 0; /* FIXME */ - region->WaveLink = instrument_object->regions[i].wave_link; - region->WSMP = instrument_object->regions[i].wave_sample; - region->WLOOP[0] = instrument_object->regions[i].wave_loop; + region->WaveLink = instrument_region->wave_link; + region->WSMP = instrument_region->wave_sample; + region->WLOOP[0] = instrument_region->wave_loop; + i++; } ret = IDirectMusicSynth8_Download(This->synth, &download, (void*)data, &on_heap); From 3e77b60f226f905fff6e6276937d8049e15e93b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 31 Aug 2023 10:04:57 +0200 Subject: [PATCH 2466/2777] dmusic: Reset riff chunk type to 0 when it is invalid. (cherry picked from commit 7684880546bf0b7a31aae917b7914ce493b47551) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/dmobject.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/dlls/dmusic/dmobject.c b/dlls/dmusic/dmobject.c index 07d887a376c..a08db8cba58 100644 --- a/dlls/dmusic/dmobject.c +++ b/dlls/dmusic/dmobject.c @@ -338,11 +338,10 @@ HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) } } - if (chunk->id == FOURCC_LIST || chunk->id == FOURCC_RIFF) { - hr = stream_read(stream, &chunk->type, sizeof(FOURCC)); - if (hr != S_OK) - return hr != S_FALSE ? hr : E_FAIL; - } + if (chunk->id != FOURCC_LIST && chunk->id != FOURCC_RIFF) + chunk->type = 0; + else if ((hr = stream_read(stream, &chunk->type, sizeof(FOURCC))) != S_OK) + return hr != S_FALSE ? hr : E_FAIL; TRACE_(dmfile)("Returning %s\n", debugstr_chunk(chunk)); From aba4a2dbba5e559e739fa61f79dc48b732a042bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 7 Sep 2023 09:58:34 +0200 Subject: [PATCH 2467/2777] dmusic: Rewrite instrument lrgn list parsing. (cherry picked from commit 9e9b5d2980c28d1a7c126f3ba59257c7cdd2f9d3) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/dmobject.c | 2 +- dlls/dmusic/dmobject.h | 2 + dlls/dmusic/instrument.c | 176 ++++++++++++++++----------------------- 3 files changed, 77 insertions(+), 103 deletions(-) diff --git a/dlls/dmusic/dmobject.c b/dlls/dmusic/dmobject.c index a08db8cba58..2bef5511851 100644 --- a/dlls/dmusic/dmobject.c +++ b/dlls/dmusic/dmobject.c @@ -287,7 +287,7 @@ const char *debugstr_chunk(const struct chunk_entry *chunk) return wine_dbg_sprintf("%s chunk, %ssize %lu", debugstr_fourcc(chunk->id), type, chunk->size); } -static HRESULT stream_read(IStream *stream, void *data, ULONG size) +HRESULT stream_read(IStream *stream, void *data, ULONG size) { ULONG read; HRESULT hr; diff --git a/dlls/dmusic/dmobject.h b/dlls/dmusic/dmobject.h index 772be015c80..98069de8cc4 100644 --- a/dlls/dmusic/dmobject.h +++ b/dlls/dmusic/dmobject.h @@ -30,7 +30,9 @@ struct chunk_entry { ULARGE_INTEGER offset; /* chunk offset from start of stream */ const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */ }; +#define MAKE_IDTYPE(id, type) (((UINT64)type << 32) | (UINT64)id) +HRESULT stream_read(IStream *stream, void *data, ULONG size); HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk); HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk); HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk); diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index bcd2ef58265..5941042caa1 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -192,98 +192,95 @@ static inline HRESULT advance_stream(IStream *stream, ULONG bytes) return ret; } -static HRESULT load_region(struct instrument *This, IStream *stream, ULONG length) +static HRESULT load_articulation(struct instrument *This, IStream *stream, ULONG length) { - struct region *region; - HRESULT ret; - DMUS_PRIVATE_CHUNK chunk; + struct articulation *articulation; + CONNECTIONLIST list; + HRESULT hr; + UINT size; - TRACE("(%p, %p, %lu)\n", This, stream, length); + if (FAILED(hr = read_from_stream(stream, &list, sizeof(list)))) return hr; + if (list.cbSize != sizeof(list)) return E_INVALIDARG; - if (!(region = malloc(sizeof(*region)))) return E_OUTOFMEMORY; + size = offsetof(struct articulation, connections[list.cConnections]); + if (!(articulation = malloc(size))) return E_OUTOFMEMORY; + articulation->list = list; - while (length) + size = sizeof(CONNECTION) * list.cConnections; + if (FAILED(hr = read_from_stream(stream, articulation->connections, size))) free(articulation); + else { - ret = read_from_stream(stream, &chunk, sizeof(chunk)); - if (FAILED(ret)) goto failed; - - length = subtract_bytes(length, sizeof(chunk)); - - switch (chunk.fccID) - { - case FOURCC_RGNH: - TRACE("RGNH chunk (region header): %lu bytes\n", chunk.dwSize); - - ret = read_from_stream(stream, ®ion->header, sizeof(region->header)); - if (FAILED(ret)) goto failed; - - length = subtract_bytes(length, sizeof(region->header)); - break; - - case FOURCC_WSMP: - TRACE("WSMP chunk (wave sample): %lu bytes\n", chunk.dwSize); - - ret = read_from_stream(stream, ®ion->wave_sample, sizeof(region->wave_sample)); - if (FAILED(ret)) goto failed; - length = subtract_bytes(length, sizeof(region->wave_sample)); - - if (!(region->loop_present = (chunk.dwSize != sizeof(region->wave_sample)))) - break; - - ret = read_from_stream(stream, ®ion->wave_loop, sizeof(region->wave_loop)); - if (FAILED(ret)) goto failed; - - length = subtract_bytes(length, sizeof(region->wave_loop)); - break; + subtract_bytes(length, sizeof(list) + sizeof(CONNECTION) * list.cConnections); + list_add_tail(&This->articulations, &articulation->entry); + } - case FOURCC_WLNK: - TRACE("WLNK chunk (wave link): %lu bytes\n", chunk.dwSize); + return hr; +} - ret = read_from_stream(stream, ®ion->wave_link, sizeof(region->wave_link)); - if (FAILED(ret)) goto failed; +static HRESULT parse_rgn_chunk(struct instrument *This, IStream *stream, struct chunk_entry *parent) +{ + struct chunk_entry chunk = {.parent = parent}; + struct region *region; + HRESULT hr; - length = subtract_bytes(length, sizeof(region->wave_link)); - break; + if (!(region = malloc(sizeof(*region)))) return E_OUTOFMEMORY; - default: - TRACE("Unknown chunk %s (skipping): %lu bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize); + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case FOURCC_RGNH: + hr = stream_chunk_get_data(stream, &chunk, ®ion->header, sizeof(region->header)); + break; + + case FOURCC_WSMP: + if (chunk.size < sizeof(region->wave_sample)) hr = E_INVALIDARG; + else hr = stream_read(stream, ®ion->wave_sample, sizeof(region->wave_sample)); + if (SUCCEEDED(hr) && region->wave_sample.cSampleLoops) + { + if (region->wave_sample.cSampleLoops > 1) FIXME("More than one wave loop is not implemented\n"); + if (chunk.size != sizeof(WSMPL) + region->wave_sample.cSampleLoops * sizeof(WLOOP)) hr = E_INVALIDARG; + else hr = stream_read(stream, ®ion->wave_loop, sizeof(region->wave_loop)); + } + break; - ret = advance_stream(stream, chunk.dwSize); - if (FAILED(ret)) goto failed; + case FOURCC_WLNK: + hr = stream_chunk_get_data(stream, &chunk, ®ion->wave_link, sizeof(region->wave_link)); + break; - length = subtract_bytes(length, chunk.dwSize); - break; + default: + FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; } + + if (FAILED(hr)) break; } - list_add_tail(&This->regions, ®ion->entry); - return S_OK; + if (FAILED(hr)) free(region); + else list_add_tail(&This->regions, ®ion->entry); -failed: - free(region); - return ret; + return hr; } -static HRESULT load_articulation(struct instrument *This, IStream *stream, ULONG length) +static HRESULT parse_lrgn_list(struct instrument *This, IStream *stream, struct chunk_entry *parent) { - struct articulation *articulation; - CONNECTIONLIST list; + struct chunk_entry chunk = {.parent = parent}; HRESULT hr; - UINT size; - if (FAILED(hr = read_from_stream(stream, &list, sizeof(list)))) return hr; - if (list.cbSize != sizeof(list)) return E_INVALIDARG; + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case MAKE_IDTYPE(FOURCC_LIST, FOURCC_RGN): + hr = parse_rgn_chunk(This, stream, &chunk); + break; - size = offsetof(struct articulation, connections[list.cConnections]); - if (!(articulation = malloc(size))) return E_OUTOFMEMORY; - articulation->list = list; + default: + FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } - size = sizeof(CONNECTION) * list.cConnections; - if (FAILED(hr = read_from_stream(stream, articulation->connections, size))) free(articulation); - else - { - subtract_bytes(length, sizeof(list) + sizeof(CONNECTION) * list.cConnections); - list_add_tail(&This->articulations, &articulation->entry); + if (FAILED(hr)) break; } return hr; @@ -344,40 +341,15 @@ HRESULT instrument_load(IDirectMusicInstrument *iface, IStream *stream) switch (chunk.fccID) { case FOURCC_LRGN: + { + static const LARGE_INTEGER zero = {0}; + struct chunk_entry list_chunk = {.id = FOURCC_LIST, .size = chunk.dwSize, .type = chunk.fccID}; TRACE("LRGN chunk (regions list): %lu bytes\n", size); - - while (size) - { - hr = read_from_stream(stream, &chunk, sizeof(chunk)); - if (FAILED(hr)) - goto error; - - if (chunk.fccID != FOURCC_LIST) - { - TRACE("Unknown chunk %s: %lu bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize); - goto error; - } - - hr = read_from_stream(stream, &chunk.fccID, sizeof(chunk.fccID)); - if (FAILED(hr)) - goto error; - - if (chunk.fccID == FOURCC_RGN) - { - TRACE("RGN chunk (region): %lu bytes\n", chunk.dwSize); - hr = load_region(This, stream, chunk.dwSize - sizeof(chunk.fccID)); - } - else - { - TRACE("Unknown chunk %s: %lu bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize); - hr = advance_stream(stream, chunk.dwSize - sizeof(chunk.fccID)); - } - if (FAILED(hr)) - goto error; - - size = subtract_bytes(size, chunk.dwSize + sizeof(chunk)); - } + IStream_Seek(stream, zero, STREAM_SEEK_CUR, &list_chunk.offset); + list_chunk.offset.QuadPart -= 12; + hr = parse_lrgn_list(This, stream, &list_chunk); break; + } case FOURCC_LART: TRACE("LART chunk (articulations list): %lu bytes\n", size); From 0ddbaf41054417568d3f6d71f9dee02978007ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 7 Sep 2023 10:10:40 +0200 Subject: [PATCH 2468/2777] dmusic: Rewrite instrument lart list parsing. (cherry picked from commit b5fd6187198f9b15e2ce3795c6dce798e7f0f3d0) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/instrument.c | 63 ++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index 5941042caa1..1e171048008 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -192,14 +192,16 @@ static inline HRESULT advance_stream(IStream *stream, ULONG bytes) return ret; } -static HRESULT load_articulation(struct instrument *This, IStream *stream, ULONG length) +static HRESULT parse_art1_chunk(struct instrument *This, IStream *stream, struct chunk_entry *chunk) { struct articulation *articulation; CONNECTIONLIST list; HRESULT hr; UINT size; - if (FAILED(hr = read_from_stream(stream, &list, sizeof(list)))) return hr; + if (chunk->size < sizeof(list)) return E_INVALIDARG; + if (FAILED(hr = stream_read(stream, &list, sizeof(list)))) return hr; + if (chunk->size != list.cbSize + sizeof(CONNECTION) * list.cConnections) return E_INVALIDARG; if (list.cbSize != sizeof(list)) return E_INVALIDARG; size = offsetof(struct articulation, connections[list.cConnections]); @@ -207,11 +209,31 @@ static HRESULT load_articulation(struct instrument *This, IStream *stream, ULONG articulation->list = list; size = sizeof(CONNECTION) * list.cConnections; - if (FAILED(hr = read_from_stream(stream, articulation->connections, size))) free(articulation); - else + if (FAILED(hr = stream_read(stream, articulation->connections, size))) free(articulation); + else list_add_tail(&This->articulations, &articulation->entry); + + return hr; +} + +static HRESULT parse_lart_list(struct instrument *This, IStream *stream, struct chunk_entry *parent) +{ + struct chunk_entry chunk = {.parent = parent}; + HRESULT hr; + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { - subtract_bytes(length, sizeof(list) + sizeof(CONNECTION) * list.cConnections); - list_add_tail(&This->articulations, &articulation->entry); + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case FOURCC_ART1: + hr = parse_art1_chunk(This, stream, &chunk); + break; + + default: + FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; } return hr; @@ -352,30 +374,15 @@ HRESULT instrument_load(IDirectMusicInstrument *iface, IStream *stream) } case FOURCC_LART: + { + static const LARGE_INTEGER zero = {0}; + struct chunk_entry list_chunk = {.id = FOURCC_LIST, .size = chunk.dwSize, .type = chunk.fccID}; TRACE("LART chunk (articulations list): %lu bytes\n", size); - - while (size) - { - hr = read_from_stream(stream, &chunk, sizeof(chunk)); - if (FAILED(hr)) - goto error; - - if (chunk.fccID == FOURCC_ART1) - { - TRACE("ART1 chunk (level 1 articulation): %lu bytes\n", chunk.dwSize); - hr = load_articulation(This, stream, chunk.dwSize); - } - else - { - TRACE("Unknown chunk %s: %lu bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize); - hr = advance_stream(stream, chunk.dwSize); - } - if (FAILED(hr)) - goto error; - - size = subtract_bytes(size, chunk.dwSize + sizeof(chunk)); - } + IStream_Seek(stream, zero, STREAM_SEEK_CUR, &list_chunk.offset); + list_chunk.offset.QuadPart -= 12; + hr = parse_lart_list(This, stream, &list_chunk); break; + } default: TRACE("Unknown chunk %s: %lu bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize); From 0a4d8ecb95f447140ca7edaad906a9a3f4a84364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 31 Aug 2023 21:58:49 +0200 Subject: [PATCH 2469/2777] dmusic: Rewrite instrument ins chunk parsing. (cherry picked from commit 01127ce4746d3960241a05db53e73f92d828e3ef) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/instrument.c | 163 +++++++++++---------------------------- 1 file changed, 45 insertions(+), 118 deletions(-) diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index 1e171048008..cbcebcb5902 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -151,47 +151,6 @@ HRESULT instrument_create(IDirectMusicInstrument **ret_iface) return S_OK; } -static HRESULT read_from_stream(IStream *stream, void *data, ULONG size) -{ - ULONG bytes_read; - HRESULT hr; - - hr = IStream_Read(stream, data, size, &bytes_read); - if(FAILED(hr)){ - TRACE("IStream_Read failed: %08lx\n", hr); - return hr; - } - if (bytes_read < size) { - TRACE("Didn't read full chunk: %lu < %lu\n", bytes_read, size); - return E_FAIL; - } - - return S_OK; -} - -static inline DWORD subtract_bytes(DWORD len, DWORD bytes) -{ - if(bytes > len){ - TRACE("Apparent mismatch in chunk lengths? %lu bytes remaining, %lu bytes read\n", len, bytes); - return 0; - } - return len - bytes; -} - -static inline HRESULT advance_stream(IStream *stream, ULONG bytes) -{ - LARGE_INTEGER move; - HRESULT ret; - - move.QuadPart = bytes; - - ret = IStream_Seek(stream, move, STREAM_SEEK_CUR, NULL); - if (FAILED(ret)) - WARN("IStream_Seek failed: %08lx\n", ret); - - return ret; -} - static HRESULT parse_art1_chunk(struct instrument *This, IStream *stream, struct chunk_entry *chunk) { struct articulation *articulation; @@ -308,13 +267,45 @@ static HRESULT parse_lrgn_list(struct instrument *This, IStream *stream, struct return hr; } +static HRESULT parse_ins_chunk(struct instrument *This, IStream *stream, struct chunk_entry *parent) +{ + struct chunk_entry chunk = {.parent = parent}; + HRESULT hr; + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case FOURCC_INSH: + case FOURCC_DLID: + /* Instrument header and id are already set so just skip */ + break; + + case MAKE_IDTYPE(FOURCC_LIST, FOURCC_LRGN): + hr = parse_lrgn_list(This, stream, &chunk); + break; + + case MAKE_IDTYPE(FOURCC_LIST, FOURCC_LART): + hr = parse_lart_list(This, stream, &chunk); + break; + + default: + FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; + } + + return hr; +} + /* Function that loads all instrument data and which is called from IDirectMusicCollection_GetInstrument as in native */ HRESULT instrument_load(IDirectMusicInstrument *iface, IStream *stream) { struct instrument *This = impl_from_IDirectMusicInstrument(iface); + struct chunk_entry chunk = {0}; HRESULT hr; - DMUS_PRIVATE_CHUNK chunk; - ULONG length = This->length; TRACE("(%p, %p): offset = 0x%s, length = %lu)\n", This, stream, wine_dbgstr_longlong(This->liInstrumentPosition.QuadPart), This->length); @@ -328,90 +319,26 @@ HRESULT instrument_load(IDirectMusicInstrument *iface, IStream *stream) return DMUS_E_UNSUPPORTED_STREAM; } - while (length) + if ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { - hr = read_from_stream(stream, &chunk, sizeof(chunk)); - if (FAILED(hr)) - goto error; - - length = subtract_bytes(length, sizeof(chunk) + chunk.dwSize); - - switch (chunk.fccID) + switch (MAKE_IDTYPE(chunk.id, chunk.type)) { - case FOURCC_INSH: - case FOURCC_DLID: - TRACE("Chunk %s: %lu bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize); - - /* Instrument header and id are already set so just skip */ - hr = advance_stream(stream, chunk.dwSize); - if (FAILED(hr)) - goto error; - - break; - - case FOURCC_LIST: { - DWORD size = chunk.dwSize; - - TRACE("LIST chunk: %lu bytes\n", chunk.dwSize); - - hr = read_from_stream(stream, &chunk.fccID, sizeof(chunk.fccID)); - if (FAILED(hr)) - goto error; - - size = subtract_bytes(size, sizeof(chunk.fccID)); - - switch (chunk.fccID) - { - case FOURCC_LRGN: - { - static const LARGE_INTEGER zero = {0}; - struct chunk_entry list_chunk = {.id = FOURCC_LIST, .size = chunk.dwSize, .type = chunk.fccID}; - TRACE("LRGN chunk (regions list): %lu bytes\n", size); - IStream_Seek(stream, zero, STREAM_SEEK_CUR, &list_chunk.offset); - list_chunk.offset.QuadPart -= 12; - hr = parse_lrgn_list(This, stream, &list_chunk); - break; - } - - case FOURCC_LART: - { - static const LARGE_INTEGER zero = {0}; - struct chunk_entry list_chunk = {.id = FOURCC_LIST, .size = chunk.dwSize, .type = chunk.fccID}; - TRACE("LART chunk (articulations list): %lu bytes\n", size); - IStream_Seek(stream, zero, STREAM_SEEK_CUR, &list_chunk.offset); - list_chunk.offset.QuadPart -= 12; - hr = parse_lart_list(This, stream, &list_chunk); - break; - } - - default: - TRACE("Unknown chunk %s: %lu bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize); - - hr = advance_stream(stream, chunk.dwSize - sizeof(chunk.fccID)); - if (FAILED(hr)) - goto error; - - size = subtract_bytes(size, chunk.dwSize - sizeof(chunk.fccID)); - break; - } - break; - } - - default: - TRACE("Unknown chunk %s: %lu bytes\n", debugstr_fourcc(chunk.fccID), chunk.dwSize); - - hr = advance_stream(stream, chunk.dwSize); - if (FAILED(hr)) - goto error; + case MAKE_IDTYPE(FOURCC_LIST, FOURCC_INS): + hr = parse_ins_chunk(This, stream, &chunk); + break; - break; + default: + WARN("Invalid instrument chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + goto error; } } - This->loaded = TRUE; + if (FAILED(hr)) goto error; + This->loaded = TRUE; return S_OK; error: + stream_skip_chunk(stream, &chunk); return DMUS_E_UNSUPPORTED_STREAM; } From cb077a910ee80293088417c97aab046910ca7cbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 7 Sep 2023 10:12:29 +0200 Subject: [PATCH 2470/2777] dmusic: Allocate and parse instruments in a single pass. (cherry picked from commit ff4cb785cbb4f9a5ab2fc16293edc7ea9fb097fc) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 68 +++--------------------------------- dlls/dmusic/dmusic_private.h | 7 +--- dlls/dmusic/instrument.c | 46 +++++++++++++++--------- 3 files changed, 35 insertions(+), 86 deletions(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 5332adff084..cca23870f9d 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -115,7 +115,6 @@ static HRESULT WINAPI collection_GetInstrument(IDirectMusicCollection *iface, if (patch == inst_patch) { *instrument = inst_entry->pInstrument; IDirectMusicInstrument_AddRef(inst_entry->pInstrument); - instrument_load(inst_entry->pInstrument, This->pStm); TRACE(": returning instrument %p\n", *instrument); return S_OK; } @@ -212,7 +211,6 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, DMUS_PRIVATE_CHUNK chunk; DWORD StreamSize, StreamCount, ListSize[2], ListCount[2]; LARGE_INTEGER liMove; /* used when skipping chunks */ - ULARGE_INTEGER dlibInstrumentPosition; IStream_AddRef(stream); /* add count for later references */ This->pStm = stream; @@ -374,68 +372,12 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, ListCount[1] = 0; switch (chunk.fccID) { case FOURCC_INS: { - DMUS_PRIVATE_INSTRUMENTENTRY *new_instrument = calloc(1, sizeof(DMUS_PRIVATE_INSTRUMENTENTRY)); + DMUS_PRIVATE_INSTRUMENTENTRY *entry = calloc(1, sizeof(DMUS_PRIVATE_INSTRUMENTENTRY)); TRACE_(dmfile)(": instrument list\n"); - /* Only way to create this one... even M$ does it discretely */ - instrument_create(&new_instrument->pInstrument); - { - struct instrument *instrument = impl_from_IDirectMusicInstrument(new_instrument->pInstrument); - /* Store offset and length, they will be needed when loading the instrument */ - liMove.QuadPart = 0; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibInstrumentPosition); - instrument->liInstrumentPosition.QuadPart = dlibInstrumentPosition.QuadPart; - instrument->length = ListSize[1]; - do { - IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL); - ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = %#04lx)", debugstr_fourcc(chunk.fccID), chunk.dwSize); - switch (chunk.fccID) { - case FOURCC_INSH: { - TRACE_(dmfile)(": instrument header chunk\n"); - IStream_Read(stream, &instrument->header, chunk.dwSize, NULL); - break; - } - case FOURCC_DLID: { - TRACE_(dmfile)(": DLID (GUID) chunk\n"); - IStream_Read(stream, &instrument->id, chunk.dwSize, NULL); - break; - } - case FOURCC_LIST: { - IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL); - TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID)); - switch (chunk.fccID) { - default: { - TRACE_(dmfile)(": unknown (skipping)\n"); - liMove.QuadPart = chunk.dwSize - sizeof(FOURCC); - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - break; - } - default: { - TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); - liMove.QuadPart = chunk.dwSize; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]); - } while (ListCount[1] < ListSize[1]); - /* DEBUG: dumps whole instrument object tree: */ - if (TRACE_ON(dmusic)) { - TRACE("*** IDirectMusicInstrument (%p) ***\n", instrument); - if (!IsEqualGUID(&instrument->id, &GUID_NULL)) - TRACE(" - GUID = %s\n", debugstr_dmguid(&instrument->id)); - TRACE(" - Instrument header:\n"); - TRACE(" - cRegions: %ld\n", instrument->header.cRegions); - TRACE(" - Locale:\n"); - TRACE(" - ulBank: %ld\n", instrument->header.Locale.ulBank); - TRACE(" - ulInstrument: %ld\n", instrument->header.Locale.ulInstrument); - TRACE(" => dwPatch: %ld\n", MIDILOCALE2Patch(&instrument->header.Locale)); - } - list_add_tail(&This->Instruments, &new_instrument->entry); - } + liMove.QuadPart = -12; + IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); + if (FAILED(instrument_create_from_stream(stream, &entry->pInstrument))) free(entry); + else list_add_tail(&This->Instruments, &entry->entry); break; } } diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 331aa683f4b..fca76105b20 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -98,7 +98,7 @@ extern HRESULT DMUSIC_CreateReferenceClockImpl (LPCGUID lpcGUID, LPVOID* ppobj, extern HRESULT download_create(DWORD size, IDirectMusicDownload **ret_iface); -extern HRESULT instrument_create(IDirectMusicInstrument **ret_iface); +extern HRESULT instrument_create_from_stream(IStream *stream, IDirectMusicInstrument **ret_iface); /***************************************************************************** * IDirectMusic8Impl implementation structure @@ -178,13 +178,10 @@ struct instrument IDirectMusicInstrument IDirectMusicInstrument_iface; LONG ref; - LARGE_INTEGER liInstrumentPosition; /* offset in a stream where instrument chunk can be found */ - ULONG length; /* Length of the instrument in the stream */ GUID id; INSTHEADER header; WCHAR wszName[DMUS_MAX_NAME]; /* instrument data */ - BOOL loaded; struct list articulations; struct list regions; @@ -195,8 +192,6 @@ static inline struct instrument *impl_from_IDirectMusicInstrument(IDirectMusicIn return CONTAINING_RECORD(iface, struct instrument, IDirectMusicInstrument_iface); } -extern HRESULT instrument_load(IDirectMusicInstrument *iface, IStream *stream); - /***************************************************************************** * Misc. */ diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index cbcebcb5902..b62b053c542 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -135,7 +135,7 @@ static const IDirectMusicInstrumentVtbl instrument_vtbl = instrument_SetPatch, }; -HRESULT instrument_create(IDirectMusicInstrument **ret_iface) +static HRESULT instrument_create(IDirectMusicInstrument **ret_iface) { struct instrument *instrument; @@ -277,8 +277,11 @@ static HRESULT parse_ins_chunk(struct instrument *This, IStream *stream, struct switch (MAKE_IDTYPE(chunk.id, chunk.type)) { case FOURCC_INSH: + hr = stream_chunk_get_data(stream, &chunk, &This->header, sizeof(This->header)); + break; + case FOURCC_DLID: - /* Instrument header and id are already set so just skip */ + hr = stream_chunk_get_data(stream, &chunk, &This->id, sizeof(This->id)); break; case MAKE_IDTYPE(FOURCC_LIST, FOURCC_LRGN): @@ -300,24 +303,17 @@ static HRESULT parse_ins_chunk(struct instrument *This, IStream *stream, struct return hr; } -/* Function that loads all instrument data and which is called from IDirectMusicCollection_GetInstrument as in native */ -HRESULT instrument_load(IDirectMusicInstrument *iface, IStream *stream) +HRESULT instrument_create_from_stream(IStream *stream, IDirectMusicInstrument **ret_iface) { - struct instrument *This = impl_from_IDirectMusicInstrument(iface); struct chunk_entry chunk = {0}; + IDirectMusicInstrument *iface; + struct instrument *This; HRESULT hr; - TRACE("(%p, %p): offset = 0x%s, length = %lu)\n", This, stream, wine_dbgstr_longlong(This->liInstrumentPosition.QuadPart), This->length); + TRACE("(%p, %p)\n", stream, ret_iface); - if (This->loaded) - return S_OK; - - hr = IStream_Seek(stream, This->liInstrumentPosition, STREAM_SEEK_SET, NULL); - if (FAILED(hr)) - { - WARN("IStream_Seek failed: %08lx\n", hr); - return DMUS_E_UNSUPPORTED_STREAM; - } + if (FAILED(hr = instrument_create(&iface))) return hr; + This = impl_from_IDirectMusicInstrument(iface); if ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { @@ -329,16 +325,32 @@ HRESULT instrument_load(IDirectMusicInstrument *iface, IStream *stream) default: WARN("Invalid instrument chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); - goto error; + hr = E_INVALIDARG; + break; } } if (FAILED(hr)) goto error; - This->loaded = TRUE; + if (TRACE_ON(dmusic)) + { + TRACE("Created DirectMusicInstrument (%p) ***\n", This); + if (!IsEqualGUID(&This->id, &GUID_NULL)) + TRACE(" - GUID = %s\n", debugstr_dmguid(&This->id)); + TRACE(" - Instrument header:\n"); + TRACE(" - cRegions: %ld\n", This->header.cRegions); + TRACE(" - Locale:\n"); + TRACE(" - ulBank: %ld\n", This->header.Locale.ulBank); + TRACE(" - ulInstrument: %ld\n", This->header.Locale.ulInstrument); + TRACE(" => dwPatch: %ld\n", MIDILOCALE2Patch(&This->header.Locale)); + } + + *ret_iface = iface; return S_OK; error: + IDirectMusicInstrument_Release(iface); + stream_skip_chunk(stream, &chunk); return DMUS_E_UNSUPPORTED_STREAM; } From 857981af5f6ef992925956b7f0076485db6fa6a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 9 Sep 2023 13:27:36 +0200 Subject: [PATCH 2471/2777] dmusic: Cleanup collection instrument iteration loops. (cherry picked from commit 572125edf622d1cf00025e47a2f487ef42b6bb15) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 83 ++++++++++++++++++------------------ dlls/dmusic/dmusic_private.h | 5 --- 2 files changed, 41 insertions(+), 47 deletions(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index cca23870f9d..0b4e23b34f4 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -24,6 +24,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmusic); WINE_DECLARE_DEBUG_CHANNEL(dmfile); +struct instrument_entry +{ + struct list entry; + IDirectMusicInstrument *instrument; +}; + struct collection { IDirectMusicCollection IDirectMusicCollection_iface; @@ -36,8 +42,8 @@ struct collection /* pool table */ POOLTABLE *pPoolTable; POOLCUE *pPoolCues; - /* instruments */ - struct list Instruments; + + struct list instruments; }; static inline struct collection *impl_from_IDirectMusicCollection(IDirectMusicCollection *iface) @@ -103,25 +109,25 @@ static HRESULT WINAPI collection_GetInstrument(IDirectMusicCollection *iface, DWORD patch, IDirectMusicInstrument **instrument) { struct collection *This = impl_from_IDirectMusicCollection(iface); - DMUS_PRIVATE_INSTRUMENTENTRY *inst_entry; - struct list *list_entry; + struct instrument_entry *entry; DWORD inst_patch; + HRESULT hr; TRACE("(%p, %lu, %p)\n", iface, patch, instrument); - LIST_FOR_EACH(list_entry, &This->Instruments) { - inst_entry = LIST_ENTRY(list_entry, DMUS_PRIVATE_INSTRUMENTENTRY, entry); - IDirectMusicInstrument_GetPatch(inst_entry->pInstrument, &inst_patch); - if (patch == inst_patch) { - *instrument = inst_entry->pInstrument; - IDirectMusicInstrument_AddRef(inst_entry->pInstrument); - TRACE(": returning instrument %p\n", *instrument); + LIST_FOR_EACH_ENTRY(entry, &This->instruments, struct instrument_entry, entry) + { + if (FAILED(hr = IDirectMusicInstrument_GetPatch(entry->instrument, &inst_patch))) return hr; + if (patch == inst_patch) + { + *instrument = entry->instrument; + IDirectMusicInstrument_AddRef(entry->instrument); + TRACE(": returning instrument %p\n", entry->instrument); return S_OK; } } TRACE(": instrument not found\n"); - return DMUS_E_INVALIDPATCH; } @@ -129,26 +135,23 @@ static HRESULT WINAPI collection_EnumInstrument(IDirectMusicCollection *iface, DWORD index, DWORD *patch, LPWSTR name, DWORD name_length) { struct collection *This = impl_from_IDirectMusicCollection(iface); - DWORD i = 0; - DMUS_PRIVATE_INSTRUMENTENTRY *inst_entry; - struct list *list_entry; - DWORD length; + struct instrument_entry *entry; + HRESULT hr; TRACE("(%p, %ld, %p, %p, %ld)\n", iface, index, patch, name, name_length); - LIST_FOR_EACH(list_entry, &This->Instruments) { - inst_entry = LIST_ENTRY(list_entry, DMUS_PRIVATE_INSTRUMENTENTRY, entry); - if (i == index) { - struct instrument *instrument = impl_from_IDirectMusicInstrument(inst_entry->pInstrument); - IDirectMusicInstrument_GetPatch(inst_entry->pInstrument, patch); - if (name) { - length = min(lstrlenW(instrument->wszName), name_length - 1); - memcpy(name, instrument->wszName, length * sizeof(WCHAR)); - name[length] = '\0'; - } - return S_OK; + LIST_FOR_EACH_ENTRY(entry, &This->instruments, struct instrument_entry, entry) + { + if (index--) continue; + if (FAILED(hr = IDirectMusicInstrument_GetPatch(entry->instrument, patch))) return hr; + if (name) + { + struct instrument *instrument = impl_from_IDirectMusicInstrument(entry->instrument); + DWORD length = min(lstrlenW(instrument->wszName), name_length - 1); + memcpy(name, instrument->wszName, length * sizeof(WCHAR)); + name[length] = '\0'; } - i++; + return S_OK; } return S_FALSE; @@ -372,12 +375,12 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, ListCount[1] = 0; switch (chunk.fccID) { case FOURCC_INS: { - DMUS_PRIVATE_INSTRUMENTENTRY *entry = calloc(1, sizeof(DMUS_PRIVATE_INSTRUMENTENTRY)); + struct instrument_entry *entry = calloc(1, sizeof(*entry)); TRACE_(dmfile)(": instrument list\n"); liMove.QuadPart = -12; IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); - if (FAILED(instrument_create_from_stream(stream, &entry->pInstrument))) free(entry); - else list_add_tail(&This->Instruments, &entry->entry); + if (FAILED(instrument_create_from_stream(stream, &entry->instrument))) free(entry); + else list_add_tail(&This->instruments, &entry->entry); break; } } @@ -417,10 +420,10 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, /* DEBUG: dumps whole collection object tree: */ - if (TRACE_ON(dmusic)) { - int r = 0; - DMUS_PRIVATE_INSTRUMENTENTRY *tmpEntry; - struct list *listEntry; + if (TRACE_ON(dmusic)) + { + struct instrument_entry *entry; + int i = 0; TRACE("*** IDirectMusicCollection (%p) ***\n", &This->IDirectMusicCollection_iface); dump_DMUS_OBJECTDESC(&This->dmobj.desc); @@ -429,11 +432,8 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, TRACE(" - cInstruments: %ld\n", This->pHeader->cInstruments); TRACE(" - Instruments:\n"); - LIST_FOR_EACH(listEntry, &This->Instruments) { - tmpEntry = LIST_ENTRY( listEntry, DMUS_PRIVATE_INSTRUMENTENTRY, entry ); - TRACE(" - Instrument[%i]: %p\n", r, tmpEntry->pInstrument); - r++; - } + LIST_FOR_EACH_ENTRY(entry, &This->instruments, struct instrument_entry, entry) + TRACE(" - Instrument[%i]: %p\n", i++, entry->instrument); } return S_OK; @@ -463,8 +463,7 @@ HRESULT collection_create(IUnknown **ret_iface) (IUnknown *)&collection->IDirectMusicCollection_iface); collection->dmobj.IDirectMusicObject_iface.lpVtbl = &collection_object_vtbl; collection->dmobj.IPersistStream_iface.lpVtbl = &collection_stream_vtbl; - - list_init(&collection->Instruments); + list_init(&collection->instruments); TRACE("Created DirectMusicCollection %p\n", collection); *ret_iface = (IUnknown *)&collection->IDirectMusicCollection_iface; diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index fca76105b20..b668f2f2559 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -164,11 +164,6 @@ struct IReferenceClockImpl { DMUS_CLOCKINFO pClockInfo; }; -typedef struct _DMUS_PRIVATE_INSTRUMENT_ENTRY { - struct list entry; /* for listing elements */ - IDirectMusicInstrument* pInstrument; -} DMUS_PRIVATE_INSTRUMENTENTRY, *LPDMUS_PRIVATE_INSTRUMENTENTRY; - typedef struct _DMUS_PRIVATE_POOLCUE { struct list entry; /* for listing elements */ } DMUS_PRIVATE_POOLCUE, *LPDMUS_PRIVATE_POOLCUE; From 412a4143836f316f3add05e359e8fc0f17d8dd91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 9 Sep 2023 14:51:56 +0200 Subject: [PATCH 2472/2777] dmusic: Stop leaking instruments on collection release. (cherry picked from commit 4ae866a0a7f65a4a4d2c95c5c98145b02d63528e) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 0b4e23b34f4..2d4a7f855ae 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -98,7 +98,18 @@ static ULONG WINAPI collection_Release(IDirectMusicCollection *iface) TRACE("(%p): new ref = %lu\n", iface, ref); - if (!ref) { + if (!ref) + { + struct instrument_entry *instrument_entry; + void *next; + + LIST_FOR_EACH_ENTRY_SAFE(instrument_entry, next, &This->instruments, struct instrument_entry, entry) + { + list_remove(&instrument_entry->entry); + IDirectMusicInstrument_Release(instrument_entry->instrument); + free(instrument_entry); + } + free(This); } From efa8b7da9113058e9cf1edc00e0f69c72dc2de5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Aug 2023 17:40:22 +0200 Subject: [PATCH 2473/2777] dmime: Always return S_FALSE from DllCanUnloadNow. (cherry picked from commit 6e1e7a88fd5d50dd9852ae6106ddedf5506311bc) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/audiopath.c | 2 -- dlls/dmime/dmime_main.c | 22 ---------------------- dlls/dmime/dmime_private.h | 7 ------- dlls/dmime/graph.c | 2 -- dlls/dmime/lyricstrack.c | 2 -- dlls/dmime/markertrack.c | 2 -- dlls/dmime/paramcontroltrack.c | 2 -- dlls/dmime/performance.c | 4 ---- dlls/dmime/segment.c | 3 --- dlls/dmime/segmentstate.c | 4 ---- dlls/dmime/segtriggertrack.c | 2 -- dlls/dmime/seqtrack.c | 2 -- dlls/dmime/sysextrack.c | 2 -- dlls/dmime/tempotrack.c | 2 -- dlls/dmime/timesigtrack.c | 2 -- dlls/dmime/wavetrack.c | 2 -- 16 files changed, 62 deletions(-) diff --git a/dlls/dmime/audiopath.c b/dlls/dmime/audiopath.c index 0857ed77c48..0d7df17bba6 100644 --- a/dlls/dmime/audiopath.c +++ b/dlls/dmime/audiopath.c @@ -96,7 +96,6 @@ static ULONG WINAPI IDirectMusicAudioPathImpl_AddRef (IDirectMusicAudioPath *ifa TRACE("(%p): ref=%ld\n", This, ref); - DMIME_LockModule(); return ref; } @@ -116,7 +115,6 @@ static ULONG WINAPI IDirectMusicAudioPathImpl_Release (IDirectMusicAudioPath *if HeapFree(GetProcessHeap(), 0, This); } - DMIME_UnlockModule(); return ref; } diff --git a/dlls/dmime/dmime_main.c b/dlls/dmime/dmime_main.c index c24cf944af5..c0aa4e31cfb 100644 --- a/dlls/dmime/dmime_main.c +++ b/dlls/dmime/dmime_main.c @@ -38,8 +38,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmime); -LONG DMIME_refCount = 0; - typedef struct { IClassFactory IClassFactory_iface; HRESULT (*fnCreateInstance)(REFIID riid, void **ret_iface); @@ -75,15 +73,11 @@ static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID r static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) { - DMIME_LockModule(); - return 2; /* non-heap based object */ } static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) { - DMIME_UnlockModule(); - return 1; /* non-heap based object */ } @@ -103,12 +97,6 @@ static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock) { TRACE("(%d)\n", dolock); - - if (dolock) - DMIME_LockModule(); - else - DMIME_UnlockModule(); - return S_OK; } @@ -136,16 +124,6 @@ static IClassFactoryImpl SegTriggerTrack_CF = {{&classfactory_vtbl}, create_dmse static IClassFactoryImpl AudioPath_CF = {{&classfactory_vtbl}, create_dmaudiopath}; static IClassFactoryImpl WaveTrack_CF = {{&classfactory_vtbl}, create_dmwavetrack}; -/****************************************************************** - * DllCanUnloadNow (DMIME.1) - * - * - */ -HRESULT WINAPI DllCanUnloadNow(void) -{ - return DMIME_refCount != 0 ? S_FALSE : S_OK; -} - /****************************************************************** * DllGetClassObject (DMIME.@) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 7cdc1534866..6102fd5ec2f 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -96,13 +96,6 @@ typedef struct _DMUS_PRIVATE_TEMPO_PLAY_STATE { DWORD dummy; } DMUS_PRIVATE_TEMPO_PLAY_STATE, *LPDMUS_PRIVATE_TEMPO_PLAY_STATE; -/********************************************************************** - * Dll lifetime tracking declaration for dmime.dll - */ -extern LONG DMIME_refCount; -static inline void DMIME_LockModule(void) { InterlockedIncrement( &DMIME_refCount ); } -static inline void DMIME_UnlockModule(void) { InterlockedDecrement( &DMIME_refCount ); } - /***************************************************************************** * Misc. */ diff --git a/dlls/dmime/graph.c b/dlls/dmime/graph.c index 6cb719025c1..8b0fb246a74 100644 --- a/dlls/dmime/graph.c +++ b/dlls/dmime/graph.c @@ -75,7 +75,6 @@ static ULONG WINAPI DirectMusicGraph_AddRef(IDirectMusicGraph *iface) TRACE("(%p): %ld\n", This, ref); - DMIME_LockModule(); return ref; } @@ -89,7 +88,6 @@ static ULONG WINAPI DirectMusicGraph_Release(IDirectMusicGraph *iface) if (ref == 0) HeapFree(GetProcessHeap(), 0, This); - DMIME_UnlockModule(); return ref; } diff --git a/dlls/dmime/lyricstrack.c b/dlls/dmime/lyricstrack.c index 4983fe99a2d..ea4529fb4c7 100644 --- a/dlls/dmime/lyricstrack.c +++ b/dlls/dmime/lyricstrack.c @@ -84,7 +84,6 @@ static ULONG WINAPI lyrics_track_Release(IDirectMusicTrack8 *iface) if (!ref) { HeapFree(GetProcessHeap(), 0, This); - DMIME_UnlockModule(); } return ref; @@ -359,7 +358,6 @@ HRESULT create_dmlyricstrack(REFIID lpcGUID, void **ppobj) (IUnknown *)&track->IDirectMusicTrack8_iface); track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - DMIME_LockModule(); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); diff --git a/dlls/dmime/markertrack.c b/dlls/dmime/markertrack.c index 7749d9abb08..8be2b937d1b 100644 --- a/dlls/dmime/markertrack.c +++ b/dlls/dmime/markertrack.c @@ -78,7 +78,6 @@ static ULONG WINAPI IDirectMusicTrackImpl_Release(IDirectMusicTrack *iface) if (!ref) { HeapFree(GetProcessHeap(), 0, This); - DMIME_UnlockModule(); } return ref; @@ -237,7 +236,6 @@ HRESULT create_dmmarkertrack(REFIID lpcGUID, void **ppobj) (IUnknown *)&track->IDirectMusicTrack_iface); track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - DMIME_LockModule(); hr = IDirectMusicTrack_QueryInterface(&track->IDirectMusicTrack_iface, lpcGUID, ppobj); IDirectMusicTrack_Release(&track->IDirectMusicTrack_iface); diff --git a/dlls/dmime/paramcontroltrack.c b/dlls/dmime/paramcontroltrack.c index 641fd73baa3..d6f3844f60c 100644 --- a/dlls/dmime/paramcontroltrack.c +++ b/dlls/dmime/paramcontroltrack.c @@ -79,7 +79,6 @@ static ULONG WINAPI paramcontrol_track_Release(IDirectMusicTrack8 *iface) if (!ref) { HeapFree(GetProcessHeap(), 0, This); - DMIME_UnlockModule(); } return ref; @@ -273,7 +272,6 @@ HRESULT create_dmparamcontroltrack(REFIID lpcGUID, void **ppobj) (IUnknown *)&track->IDirectMusicTrack8_iface); track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - DMIME_LockModule(); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index d69a27540d6..5e80a0d1b54 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -278,8 +278,6 @@ static ULONG WINAPI IDirectMusicPerformance8Impl_AddRef(IDirectMusicPerformance8 TRACE("(%p): ref=%ld\n", This, ref); - DMIME_LockModule(); - return ref; } @@ -297,8 +295,6 @@ static ULONG WINAPI IDirectMusicPerformance8Impl_Release(IDirectMusicPerformance HeapFree(GetProcessHeap(), 0, This); } - DMIME_UnlockModule(); - return ref; } diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index c005d506cad..457b6678759 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -94,7 +94,6 @@ static ULONG WINAPI IDirectMusicSegment8Impl_Release(IDirectMusicSegment8 *iface free(This->wave_data); HeapFree(GetProcessHeap(), 0, This); - DMIME_UnlockModule(); } return ref; @@ -935,8 +934,6 @@ IDirectMusicSegment8Impl *create_segment(void) obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; list_init (&obj->Tracks); - DMIME_LockModule(); - return obj; } diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index 21544fad773..a67079a2daf 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -63,8 +63,6 @@ static ULONG WINAPI DirectMusicSegmentState8_AddRef(IDirectMusicSegmentState8 *i TRACE("(%p): %ld\n", This, ref); - DMIME_LockModule(); - return ref; } @@ -78,8 +76,6 @@ static ULONG WINAPI DirectMusicSegmentState8_Release(IDirectMusicSegmentState8 * if (ref == 0) HeapFree(GetProcessHeap(), 0, This); - DMIME_UnlockModule(); - return ref; } diff --git a/dlls/dmime/segtriggertrack.c b/dlls/dmime/segtriggertrack.c index 1b7fc6d951c..a04561450f6 100644 --- a/dlls/dmime/segtriggertrack.c +++ b/dlls/dmime/segtriggertrack.c @@ -102,7 +102,6 @@ static ULONG WINAPI segment_track_Release(IDirectMusicTrack8 *iface) } heap_free(This); - DMIME_UnlockModule(); } return ref; @@ -399,7 +398,6 @@ HRESULT create_dmsegtriggertrack(REFIID lpcGUID, void **ppobj) track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; list_init(&track->Items); - DMIME_LockModule(); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); diff --git a/dlls/dmime/seqtrack.c b/dlls/dmime/seqtrack.c index 743be10e5c6..2fae8bd5dc1 100644 --- a/dlls/dmime/seqtrack.c +++ b/dlls/dmime/seqtrack.c @@ -79,7 +79,6 @@ static ULONG WINAPI sequence_track_Release(IDirectMusicTrack8 *iface) if (!ref) { HeapFree(GetProcessHeap(), 0, This); - DMIME_UnlockModule(); } return ref; @@ -273,7 +272,6 @@ HRESULT create_dmseqtrack(REFIID lpcGUID, void **ppobj) (IUnknown *)&track->IDirectMusicTrack8_iface); track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - DMIME_LockModule(); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); diff --git a/dlls/dmime/sysextrack.c b/dlls/dmime/sysextrack.c index d3ff9a051b8..ed44ba50a48 100644 --- a/dlls/dmime/sysextrack.c +++ b/dlls/dmime/sysextrack.c @@ -79,7 +79,6 @@ static ULONG WINAPI sysex_track_Release(IDirectMusicTrack8 *iface) if (!ref) { HeapFree(GetProcessHeap(), 0, This); - DMIME_UnlockModule(); } return ref; @@ -272,7 +271,6 @@ HRESULT create_dmsysextrack(REFIID lpcGUID, void **ppobj) (IUnknown *)&track->IDirectMusicTrack8_iface); track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - DMIME_LockModule(); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); diff --git a/dlls/dmime/tempotrack.c b/dlls/dmime/tempotrack.c index a3cbffc341a..2bfac9ba059 100644 --- a/dlls/dmime/tempotrack.c +++ b/dlls/dmime/tempotrack.c @@ -87,7 +87,6 @@ static ULONG WINAPI tempo_track_Release(IDirectMusicTrack8 *iface) if (!ref) { heap_free(This->items); heap_free(This); - DMIME_UnlockModule(); } return ref; @@ -386,7 +385,6 @@ HRESULT create_dmtempotrack(REFIID lpcGUID, void **ppobj) (IUnknown *)&track->IDirectMusicTrack8_iface); track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - DMIME_LockModule(); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); diff --git a/dlls/dmime/timesigtrack.c b/dlls/dmime/timesigtrack.c index 1f4c0dbf187..3e16895eddf 100644 --- a/dlls/dmime/timesigtrack.c +++ b/dlls/dmime/timesigtrack.c @@ -88,7 +88,6 @@ static ULONG WINAPI IDirectMusicTrackImpl_Release(IDirectMusicTrack *iface) if (!ref) { heap_free(This->items); HeapFree(GetProcessHeap(), 0, This); - DMIME_UnlockModule(); } return ref; @@ -301,7 +300,6 @@ HRESULT create_dmtimesigtrack(REFIID lpcGUID, void **ppobj) (IUnknown *)&track->IDirectMusicTrack_iface); track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - DMIME_LockModule(); hr = IDirectMusicTrack_QueryInterface(&track->IDirectMusicTrack_iface, lpcGUID, ppobj); IDirectMusicTrack_Release(&track->IDirectMusicTrack_iface); diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c index d87d16fcdab..b532ace3ce9 100644 --- a/dlls/dmime/wavetrack.c +++ b/dlls/dmime/wavetrack.c @@ -113,7 +113,6 @@ static ULONG WINAPI wave_track_Release(IDirectMusicTrack8 *iface) } heap_free(This); - DMIME_UnlockModule(); } return ref; @@ -488,7 +487,6 @@ HRESULT create_dmwavetrack(REFIID lpcGUID, void **ppobj) track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; list_init(&track->parts); - DMIME_LockModule(); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); From 1653fb1f28db857bd1017d7cf0d8f2a31ad701d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 21:29:38 +0200 Subject: [PATCH 2474/2777] dmime: Use CRT allocation functions. (cherry picked from commit 0feb0cda7498c7fd1c658782eb9ff1f2966204a5) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/audiopath.c | 9 +++------ dlls/dmime/dmobject.c | 8 +++----- dlls/dmime/graph.c | 11 +++-------- dlls/dmime/lyricstrack.c | 9 +++------ dlls/dmime/markertrack.c | 9 +++------ dlls/dmime/paramcontroltrack.c | 9 +++------ dlls/dmime/performance.c | 28 ++++++++++------------------ dlls/dmime/segment.c | 18 +++++++++--------- dlls/dmime/segmentstate.c | 9 ++------- dlls/dmime/segtriggertrack.c | 18 ++++++------------ dlls/dmime/seqtrack.c | 9 +++------ dlls/dmime/sysextrack.c | 9 +++------ dlls/dmime/tempotrack.c | 19 ++++++------------- dlls/dmime/timesigtrack.c | 12 ++++-------- dlls/dmime/wavetrack.c | 24 +++++++++--------------- 15 files changed, 70 insertions(+), 131 deletions(-) diff --git a/dlls/dmime/audiopath.c b/dlls/dmime/audiopath.c index 0d7df17bba6..013939f9dfa 100644 --- a/dlls/dmime/audiopath.c +++ b/dlls/dmime/audiopath.c @@ -112,7 +112,7 @@ static ULONG WINAPI IDirectMusicAudioPathImpl_Release (IDirectMusicAudioPath *if if (This->pDSBuffer) IDirectSoundBuffer_Release(This->pDSBuffer); This->pPerf = NULL; - HeapFree(GetProcessHeap(), 0, This); + free(This); } return ref; @@ -328,11 +328,8 @@ HRESULT create_dmaudiopath(REFIID riid, void **ppobj) IDirectMusicAudioPathImpl* obj; HRESULT hr; - obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicAudioPathImpl)); - if (NULL == obj) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicAudioPath_iface.lpVtbl = &DirectMusicAudioPathVtbl; obj->ref = 1; dmobject_init(&obj->dmobj, &CLSID_DirectMusicAudioPathConfig, diff --git a/dlls/dmime/dmobject.c b/dlls/dmime/dmobject.c index b526b23d031..e080211dd11 100644 --- a/dlls/dmime/dmobject.c +++ b/dlls/dmime/dmobject.c @@ -28,7 +28,6 @@ #include "dmusics.h" #include "dmobject.h" #include "wine/debug.h" -#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(dmobj); WINE_DECLARE_DEBUG_CHANNEL(dmfile); @@ -375,7 +374,7 @@ HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) /* Reads chunk data of the form: DWORD - size of array element element[] - Array of elements - The caller needs to heap_free() the array. + The caller needs to free() the array. */ HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, unsigned int *count, DWORD elem_size) @@ -400,10 +399,9 @@ HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, *count = (chunk->size - sizeof(DWORD)) / elem_size; size = *count * elem_size; - if (!(*array = heap_alloc(size))) - return E_OUTOFMEMORY; + if (!(*array = malloc(size))) return E_OUTOFMEMORY; if (FAILED(hr = stream_read(stream, *array, size))) { - heap_free(*array); + free(*array); *array = NULL; return hr; } diff --git a/dlls/dmime/graph.c b/dlls/dmime/graph.c index 8b0fb246a74..8ac037e43bc 100644 --- a/dlls/dmime/graph.c +++ b/dlls/dmime/graph.c @@ -85,8 +85,7 @@ static ULONG WINAPI DirectMusicGraph_Release(IDirectMusicGraph *iface) TRACE("(%p): %ld\n", This, ref); - if (ref == 0) - HeapFree(GetProcessHeap(), 0, This); + if (!ref) free(This); return ref; } @@ -127,7 +126,7 @@ static HRESULT WINAPI DirectMusicGraph_InsertTool(IDirectMusicGraph *iface, IDir } ++This->num_tools; - pNewTool = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_GRAPH_TOOL)); + pNewTool = calloc(1, sizeof(*pNewTool)); pNewTool->pTool = pTool; pNewTool->dwIndex = lIndex; IDirectMusicTool8_AddRef(pTool); @@ -255,11 +254,7 @@ HRESULT create_dmgraph(REFIID riid, void **ret_iface) HRESULT hr; *ret_iface = NULL; - - obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicGraphImpl)); - if (!obj) - return E_OUTOFMEMORY; - + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicGraph_iface.lpVtbl = &DirectMusicGraphVtbl; obj->ref = 1; dmobject_init(&obj->dmobj, &CLSID_DirectMusicGraph, (IUnknown *)&obj->IDirectMusicGraph_iface); diff --git a/dlls/dmime/lyricstrack.c b/dlls/dmime/lyricstrack.c index ea4529fb4c7..a1b299e9a7c 100644 --- a/dlls/dmime/lyricstrack.c +++ b/dlls/dmime/lyricstrack.c @@ -83,7 +83,7 @@ static ULONG WINAPI lyrics_track_Release(IDirectMusicTrack8 *iface) TRACE("(%p) ref=%ld\n", This, ref); if (!ref) { - HeapFree(GetProcessHeap(), 0, This); + free(This); } return ref; @@ -347,11 +347,8 @@ HRESULT create_dmlyricstrack(REFIID lpcGUID, void **ppobj) IDirectMusicLyricsTrack *track; HRESULT hr; - track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicLyricsTrack, diff --git a/dlls/dmime/markertrack.c b/dlls/dmime/markertrack.c index 8be2b937d1b..460e708bc5d 100644 --- a/dlls/dmime/markertrack.c +++ b/dlls/dmime/markertrack.c @@ -77,7 +77,7 @@ static ULONG WINAPI IDirectMusicTrackImpl_Release(IDirectMusicTrack *iface) TRACE("(%p) ref=%ld\n", This, ref); if (!ref) { - HeapFree(GetProcessHeap(), 0, This); + free(This); } return ref; @@ -225,11 +225,8 @@ HRESULT create_dmmarkertrack(REFIID lpcGUID, void **ppobj) IDirectMusicMarkerTrack *track; HRESULT hr; - track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack_iface.lpVtbl = &dmtrack_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicMarkerTrack, diff --git a/dlls/dmime/paramcontroltrack.c b/dlls/dmime/paramcontroltrack.c index d6f3844f60c..9d32484bfd7 100644 --- a/dlls/dmime/paramcontroltrack.c +++ b/dlls/dmime/paramcontroltrack.c @@ -78,7 +78,7 @@ static ULONG WINAPI paramcontrol_track_Release(IDirectMusicTrack8 *iface) TRACE("(%p) ref=%ld\n", This, ref); if (!ref) { - HeapFree(GetProcessHeap(), 0, This); + free(This); } return ref; @@ -261,11 +261,8 @@ HRESULT create_dmparamcontroltrack(REFIID lpcGUID, void **ppobj) IDirectMusicParamControlTrack *track; HRESULT hr; - track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicParamControlTrack, diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 5e80a0d1b54..a1acc6d97cc 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -19,7 +19,6 @@ */ #include "dmime_private.h" -#include "wine/heap.h" #include "wine/rbtree.h" #include "dmobject.h" @@ -133,15 +132,15 @@ static DWORD WINAPI ProcessMsgThread(LPVOID lpParam) { for (it = This->imm_head; NULL != it; ) { it_next = it->next; - cur = ProceedMsg(This, it); - HeapFree(GetProcessHeap(), 0, cur); + cur = ProceedMsg(This, it); + free(cur); it = it_next; } for (it = This->head; NULL != it && it->rtItemTime < rtCurTime + dwDec; ) { it_next = it->next; cur = ProceedMsg(This, it); - HeapFree(GetProcessHeap(), 0, cur); + free(cur); it = it_next; } if (NULL != it) { @@ -215,7 +214,7 @@ static void pchannel_block_free(struct wine_rb_entry *entry, void *context) { struct pchannel_block *b = WINE_RB_ENTRY_VALUE(entry, struct pchannel_block, entry); - heap_free(b); + free(b); } static struct pchannel_block *pchannel_block_set(struct wine_rb_tree *tree, DWORD block_num, @@ -231,8 +230,7 @@ static struct pchannel_block *pchannel_block_set(struct wine_rb_tree *tree, DWOR if (only_set_new) return block; } else { - if (!(block = heap_alloc(sizeof(*block)))) - return NULL; + if (!(block = malloc(sizeof(*block)))) return NULL; block->block_num = block_num; } @@ -292,7 +290,7 @@ static ULONG WINAPI IDirectMusicPerformance8Impl_Release(IDirectMusicPerformance wine_rb_destroy(&This->pchannels, pchannel_block_free, NULL); This->safe.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->safe); - HeapFree(GetProcessHeap(), 0, This); + free(This); } return ref; @@ -501,10 +499,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_AllocPMsg(IDirectMusicPerform if (NULL == ppPMSG) { return E_POINTER; } - pItem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb - sizeof(DMUS_PMSG) + sizeof(DMUS_PMSGItem)); - if (NULL == pItem) { - return E_OUTOFMEMORY; - } + if (!(pItem = calloc(1, cb - sizeof(DMUS_PMSG) + sizeof(DMUS_PMSGItem)))) return E_OUTOFMEMORY; pItem->pMsg.dwSize = cb; *ppPMSG = DMUS_ItemToPMSG(pItem); return S_OK; @@ -540,7 +535,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_FreePMsg(IDirectMusicPerforma if (pPMSG->punkUser) IUnknown_Release(pPMSG->punkUser); - HeapFree(GetProcessHeap(), 0, pItem); + free(pItem); return S_OK; } @@ -1286,11 +1281,8 @@ HRESULT create_dmperformance(REFIID lpcGUID, void **ppobj) TRACE("(%s, %p)\n", debugstr_guid(lpcGUID), ppobj); - obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicPerformance8Impl)); - if (NULL == obj) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicPerformance8_iface.lpVtbl = &DirectMusicPerformance8_Vtbl; obj->ref = 0; /* will be inited by QueryInterface */ obj->pDefaultPath = NULL; diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index 457b6678759..39a5333fbbb 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -93,7 +93,7 @@ static ULONG WINAPI IDirectMusicSegment8Impl_Release(IDirectMusicSegment8 *iface if (This->wave_data) free(This->wave_data); - HeapFree(GetProcessHeap(), 0, This); + free(This); } return ref; @@ -266,9 +266,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_InsertTrack(IDirectMusicSegment8 } } - pNewSegTrack = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_SEGMENT_TRACK)); - if (NULL == pNewSegTrack) - return E_OUTOFMEMORY; + if (!(pNewSegTrack = calloc(1, sizeof(*pNewSegTrack)))) return E_OUTOFMEMORY; pNewSegTrack->dwGroupBits = group; pNewSegTrack->pTrack = pTrack; @@ -296,7 +294,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_RemoveTrack(IDirectMusicSegment8 list_remove(&pIt->entry); IDirectMusicTrack_Init(pIt->pTrack, NULL); IDirectMusicTrack_Release(pIt->pTrack); - HeapFree(GetProcessHeap(), 0, pIt); + free(pIt); return S_OK; } @@ -445,13 +443,16 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_Clone(IDirectMusicSegment8 *iface LIST_FOR_EACH_ENTRY(track_item, &This->Tracks, DMUS_PRIVATE_SEGMENT_TRACK, entry) { if (SUCCEEDED(hr = IDirectMusicTrack_Clone(track_item->pTrack, start, end, &track))) { - if ((cloned_item = HeapAlloc(GetProcessHeap(), 0, sizeof(*cloned_item)))) { + if ((cloned_item = malloc(sizeof(*cloned_item)))) + { cloned_item->dwGroupBits = track_item->dwGroupBits; cloned_item->flags = track_item->flags; cloned_item->pTrack = track; list_add_tail(&clone->Tracks, &cloned_item->entry); continue; - } else { + } + else + { IDirectMusicTrack_Release(track); } } @@ -924,8 +925,7 @@ IDirectMusicSegment8Impl *create_segment(void) { IDirectMusicSegment8Impl *obj; - if (!(obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj)))) - return NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return NULL; obj->IDirectMusicSegment8_iface.lpVtbl = &dmsegment8_vtbl; obj->ref = 1; diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index a67079a2daf..1a0b63419f0 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -73,8 +73,7 @@ static ULONG WINAPI DirectMusicSegmentState8_Release(IDirectMusicSegmentState8 * TRACE("(%p): %ld\n", This, ref); - if (ref == 0) - HeapFree(GetProcessHeap(), 0, This); + if (!ref) free(This); return ref; } @@ -146,11 +145,7 @@ HRESULT create_dmsegmentstate(REFIID riid, void **ret_iface) HRESULT hr; *ret_iface = NULL; - - obj = HeapAlloc (GetProcessHeap(), 0, sizeof(IDirectMusicSegmentState8Impl)); - if (!obj) - return E_OUTOFMEMORY; - + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicSegmentState8_iface.lpVtbl = &DirectMusicSegmentState8Vtbl; obj->ref = 1; diff --git a/dlls/dmime/segtriggertrack.c b/dlls/dmime/segtriggertrack.c index a04561450f6..dc29ede4963 100644 --- a/dlls/dmime/segtriggertrack.c +++ b/dlls/dmime/segtriggertrack.c @@ -21,8 +21,6 @@ #include "dmime_private.h" #include "dmobject.h" -#include "wine/heap.h" - WINE_DEFAULT_DEBUG_CHANNEL(dmime); /***************************************************************************** @@ -98,10 +96,10 @@ static ULONG WINAPI segment_track_Release(IDirectMusicTrack8 *iface) if (item->dmobj) IDirectMusicObject_Release(item->dmobj); - heap_free(item); + free(item); } - heap_free(This); + free(This); } return ref; @@ -274,8 +272,7 @@ static HRESULT parse_segment_item(IDirectMusicSegTriggerTrack *This, IStream *st /* First chunk is a header */ if (stream_get_chunk(stream, &chunk) != S_OK || chunk.id != DMUS_FOURCC_SEGMENTITEM_CHUNK) return DMUS_E_TRACK_HDR_NOT_FIRST_CK; - if (!(item = heap_alloc_zero(sizeof(*item)))) - return E_OUTOFMEMORY; + if (!(item = calloc(1, sizeof(*item)))) return E_OUTOFMEMORY; hr = stream_chunk_get_data(stream, &chunk, &item->header, sizeof(DMUS_IO_SEGMENT_ITEM_HEADER)); if (FAILED(hr)) goto error; @@ -311,7 +308,7 @@ static HRESULT parse_segment_item(IDirectMusicSegTriggerTrack *This, IStream *st return S_OK; error: - heap_free(item); + free(item); return hr; } @@ -386,11 +383,8 @@ HRESULT create_dmsegtriggertrack(REFIID lpcGUID, void **ppobj) IDirectMusicSegTriggerTrack *track; HRESULT hr; - track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicSegTriggerTrack, diff --git a/dlls/dmime/seqtrack.c b/dlls/dmime/seqtrack.c index 2fae8bd5dc1..0e496a5131c 100644 --- a/dlls/dmime/seqtrack.c +++ b/dlls/dmime/seqtrack.c @@ -78,7 +78,7 @@ static ULONG WINAPI sequence_track_Release(IDirectMusicTrack8 *iface) TRACE("(%p) ref=%ld\n", This, ref); if (!ref) { - HeapFree(GetProcessHeap(), 0, This); + free(This); } return ref; @@ -261,11 +261,8 @@ HRESULT create_dmseqtrack(REFIID lpcGUID, void **ppobj) IDirectMusicSeqTrack *track; HRESULT hr; - track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicSeqTrack, diff --git a/dlls/dmime/sysextrack.c b/dlls/dmime/sysextrack.c index ed44ba50a48..f9c71abf08a 100644 --- a/dlls/dmime/sysextrack.c +++ b/dlls/dmime/sysextrack.c @@ -78,7 +78,7 @@ static ULONG WINAPI sysex_track_Release(IDirectMusicTrack8 *iface) TRACE("(%p) ref=%ld\n", This, ref); if (!ref) { - HeapFree(GetProcessHeap(), 0, This); + free(This); } return ref; @@ -260,11 +260,8 @@ HRESULT create_dmsysextrack(REFIID lpcGUID, void **ppobj) IDirectMusicSysExTrack *track; HRESULT hr; - track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicSysExTrack, diff --git a/dlls/dmime/tempotrack.c b/dlls/dmime/tempotrack.c index 2bfac9ba059..6704448b71e 100644 --- a/dlls/dmime/tempotrack.c +++ b/dlls/dmime/tempotrack.c @@ -21,8 +21,6 @@ #include "dmime_private.h" #include "dmobject.h" -#include "wine/heap.h" - WINE_DEFAULT_DEBUG_CHANNEL(dmime); WINE_DECLARE_DEBUG_CHANNEL(dmfile); @@ -85,8 +83,8 @@ static ULONG WINAPI tempo_track_Release(IDirectMusicTrack8 *iface) TRACE("(%p) ref=%ld\n", This, ref); if (!ref) { - heap_free(This->items); - heap_free(This); + free(This->items); + free(This); } return ref; @@ -109,9 +107,7 @@ static HRESULT WINAPI tempo_track_InitPlay(IDirectMusicTrack8 *iface, FIXME("(%p, %p, %p, %p, %ld, %ld): semi-stub\n", This, pSegmentState, pPerformance, ppStateData, dwVirtualTrack8ID, dwFlags); - pState = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_TEMPO_PLAY_STATE)); - if (NULL == pState) - return E_OUTOFMEMORY; + if (!(pState = calloc(1, sizeof(*pState)))) return E_OUTOFMEMORY; /** TODO real fill useful data */ pState->dummy = 0; @@ -131,7 +127,7 @@ static HRESULT WINAPI tempo_track_EndPlay(IDirectMusicTrack8 *iface, void *pStat return E_POINTER; } /** TODO real clean up */ - HeapFree(GetProcessHeap(), 0, pState); + free(pState); return S_OK; } @@ -374,11 +370,8 @@ HRESULT create_dmtempotrack(REFIID lpcGUID, void **ppobj) IDirectMusicTempoTrack *track; HRESULT hr; - track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicTempoTrack, diff --git a/dlls/dmime/timesigtrack.c b/dlls/dmime/timesigtrack.c index 3e16895eddf..e98807b7503 100644 --- a/dlls/dmime/timesigtrack.c +++ b/dlls/dmime/timesigtrack.c @@ -19,7 +19,6 @@ #include "dmime_private.h" #include "dmobject.h" -#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); @@ -86,8 +85,8 @@ static ULONG WINAPI IDirectMusicTrackImpl_Release(IDirectMusicTrack *iface) TRACE("(%p) ref=%ld\n", This, ref); if (!ref) { - heap_free(This->items); - HeapFree(GetProcessHeap(), 0, This); + free(This->items); + free(This); } return ref; @@ -289,11 +288,8 @@ HRESULT create_dmtimesigtrack(REFIID lpcGUID, void **ppobj) IDirectMusicTimeSigTrack *track; HRESULT hr; - track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack_iface.lpVtbl = &dmtack_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicTimeSigTrack, diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c index b532ace3ce9..4150ea3bcd2 100644 --- a/dlls/dmime/wavetrack.c +++ b/dlls/dmime/wavetrack.c @@ -19,7 +19,6 @@ #include "dmime_private.h" #include "dmobject.h" -#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); @@ -107,12 +106,12 @@ static ULONG WINAPI wave_track_Release(IDirectMusicTrack8 *iface) list_remove(&item->entry); if (item->object) IDirectMusicObject_Release(item->object); - heap_free(item); + free(item); } - heap_free(part); + free(part); } - heap_free(This); + free(This); } return ref; @@ -323,8 +322,7 @@ static HRESULT parse_wave_item(struct wave_part *part, IStream *stream, struct c if (wave.id != FOURCC_LIST || wave.type != DMUS_FOURCC_WAVE_LIST) return DMUS_E_UNSUPPORTED_STREAM; - if (!(item = heap_alloc_zero(sizeof(*item)))) - return E_OUTOFMEMORY; + if (!(item = calloc(1, sizeof(*item)))) return E_OUTOFMEMORY; /* Wave item header chunk */ if (FAILED(hr = stream_next_chunk(stream, &chunk))) @@ -366,7 +364,7 @@ static HRESULT parse_wave_item(struct wave_part *part, IStream *stream, struct c return S_OK; error: - heap_free(item); + free(item); return hr; } @@ -383,8 +381,7 @@ static HRESULT parse_wave_part(IDirectMusicWaveTrack *This, IStream *stream, if (chunk.id != DMUS_FOURCC_WAVEPART_CHUNK) return DMUS_E_UNSUPPORTED_STREAM; - if (!(part = heap_alloc_zero(sizeof(*part)))) - return E_OUTOFMEMORY; + if (!(part = calloc(1, sizeof(*part)))) return E_OUTOFMEMORY; list_init(&part->items); if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &part->header, sizeof(part->header)))) { @@ -414,7 +411,7 @@ static HRESULT parse_wave_part(IDirectMusicWaveTrack *This, IStream *stream, return S_OK; error: - heap_free(part); + free(part); return hr; } @@ -475,11 +472,8 @@ HRESULT create_dmwavetrack(REFIID lpcGUID, void **ppobj) IDirectMusicWaveTrack *track; HRESULT hr; - track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicWaveTrack, From a338edcc53557d4152750f6f5f86b1a94007f574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 13:19:25 +0200 Subject: [PATCH 2475/2777] dmime: Use the correct interface methods. (cherry picked from commit 2dc15d394374ac2a29c482d8e74994ab903bd849) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/graph.c | 4 ++-- dlls/dmime/performance.c | 2 +- dlls/dmime/tests/dmime.c | 8 ++++---- dlls/dmime/tests/performance.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dlls/dmime/graph.c b/dlls/dmime/graph.c index 8ac037e43bc..159923b6a70 100644 --- a/dlls/dmime/graph.c +++ b/dlls/dmime/graph.c @@ -129,8 +129,8 @@ static HRESULT WINAPI DirectMusicGraph_InsertTool(IDirectMusicGraph *iface, IDir pNewTool = calloc(1, sizeof(*pNewTool)); pNewTool->pTool = pTool; pNewTool->dwIndex = lIndex; - IDirectMusicTool8_AddRef(pTool); - IDirectMusicTool8_Init(pTool, iface); + IDirectMusicTool_AddRef(pTool); + IDirectMusicTool_Init(pTool, iface); list_add_tail (pPrevEntry->next, &pNewTool->entry); #if 0 diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index a1acc6d97cc..f6eb53e365f 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -879,7 +879,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_CloseDown(IDirectMusicPerform This->dsound = NULL; } if (This->dmusic) { - IDirectMusic_SetDirectSound(This->dmusic, NULL, NULL); + IDirectMusic8_SetDirectSound(This->dmusic, NULL, NULL); IDirectMusic8_Release(This->dmusic); This->dmusic = NULL; } diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index f00b5073b48..e95a1c02427 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -223,7 +223,7 @@ static BOOL missing_dmime(void) if (hr == S_OK && dms) { - IDirectMusicSegment_Release(dms); + IDirectMusicSegment8_Release(dms); return FALSE; } return TRUE; @@ -1015,7 +1015,7 @@ static void expect_getparam(IDirectMusicTrack *track, REFGUID type, const char * HRESULT hr; char buf[64] = { 0 }; - hr = IDirectMusicTrack8_GetParam(track, type, 0, NULL, buf); + hr = IDirectMusicTrack_GetParam(track, type, 0, NULL, buf); ok(hr == expect, "GetParam(%s) failed: %#lx, expected %#lx\n", name, hr, expect); } @@ -1025,7 +1025,7 @@ static void expect_setparam(IDirectMusicTrack *track, REFGUID type, const char * HRESULT hr; char buf[64] = { 0 }; - hr = IDirectMusicTrack8_SetParam(track, type, 0, buf); + hr = IDirectMusicTrack_SetParam(track, type, 0, buf); ok(hr == expect, "SetParam(%s) failed: %#lx, expected %#lx\n", name, hr, expect); } @@ -1103,7 +1103,7 @@ static void test_track(void) /* IDirectMusicTrack */ if (class[i].has_params != ~0) { for (j = 0; j < ARRAY_SIZE(param_types); j++) { - hr = IDirectMusicTrack8_IsParamSupported(dmt, param_types[j].type); + hr = IDirectMusicTrack_IsParamSupported(dmt, param_types[j].type); if (class[i].has_params & (1 << j)) { ok(hr == S_OK, "IsParamSupported(%s) failed: %#lx, expected S_OK\n", param_types[j].name, hr); diff --git a/dlls/dmime/tests/performance.c b/dlls/dmime/tests/performance.c index 100d8e40be0..4af91fc3130 100644 --- a/dlls/dmime/tests/performance.c +++ b/dlls/dmime/tests/performance.c @@ -334,7 +334,7 @@ static void test_createport(void) ok(hr == S_OK, "CloseDown failed: %#lx\n", hr); IDirectMusic_Release(music); - IDirectMusicPerformance_Release(perf); + IDirectMusicPerformance8_Release(perf); } static void test_pchannel(void) From f7c3e92b9d5902d13aaa5fa15ca02541305c20ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 21:36:44 +0200 Subject: [PATCH 2476/2777] dmime: Fix indentation in DirectMusicPerformance class constructor. (cherry picked from commit 698605ce41616a7777100a75fefaeba62eed8354) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index f6eb53e365f..cd3d800e267 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1275,24 +1275,28 @@ static const IDirectMusicPerformance8Vtbl DirectMusicPerformance8_Vtbl = { }; /* for ClassFactory */ -HRESULT create_dmperformance(REFIID lpcGUID, void **ppobj) +HRESULT create_dmperformance(REFIID iid, void **ret_iface) { - IDirectMusicPerformance8Impl *obj; + IDirectMusicPerformance8Impl *obj; + HRESULT hr; - TRACE("(%s, %p)\n", debugstr_guid(lpcGUID), ppobj); + TRACE("(%s, %p)\n", debugstr_guid(iid), ret_iface); - *ppobj = NULL; + *ret_iface = NULL; if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; - obj->IDirectMusicPerformance8_iface.lpVtbl = &DirectMusicPerformance8_Vtbl; - obj->ref = 0; /* will be inited by QueryInterface */ - obj->pDefaultPath = NULL; - InitializeCriticalSection(&obj->safe); - obj->safe.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectMusicPerformance8Impl*->safe"); - wine_rb_init(&obj->pchannels, pchannel_block_compare); - - obj->rtLatencyTime = 100; /* 100 ms TO FIX */ - obj->dwBumperLength = 50; /* 50 ms default */ - obj->dwPrepareTime = 1000; /* 1000 ms default */ - return IDirectMusicPerformance8Impl_QueryInterface(&obj->IDirectMusicPerformance8_iface, - lpcGUID, ppobj); + obj->IDirectMusicPerformance8_iface.lpVtbl = &DirectMusicPerformance8_Vtbl; + obj->ref = 1; + + obj->pDefaultPath = NULL; + InitializeCriticalSection(&obj->safe); + obj->safe.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectMusicPerformance8Impl*->safe"); + wine_rb_init(&obj->pchannels, pchannel_block_compare); + + obj->rtLatencyTime = 100; /* 100 ms TO FIX */ + obj->dwBumperLength = 50; /* 50 ms default */ + obj->dwPrepareTime = 1000; /* 1000 ms default */ + + hr = IDirectMusicPerformance8_QueryInterface(&obj->IDirectMusicPerformance8_iface, iid, ret_iface); + IDirectMusicPerformance_Release(&obj->IDirectMusicPerformance8_iface); + return hr; } From d2a0c8d99f83504fc185fbc543c6e0d66af50a7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 21:37:26 +0200 Subject: [PATCH 2477/2777] dmime: Rename IDirectMusicPerformance8Impl method prefix to performance. (cherry picked from commit 52f7ae49326e97fd197521df5f296d3be7c90f25) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 286 ++++++++++++++++++--------------------- 1 file changed, 129 insertions(+), 157 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index cd3d800e267..7617b92309d 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -251,8 +251,7 @@ static inline IDirectMusicPerformance8Impl *impl_from_IDirectMusicPerformance8(I } /* IDirectMusicPerformance8 IUnknown part: */ -static HRESULT WINAPI IDirectMusicPerformance8Impl_QueryInterface(IDirectMusicPerformance8 *iface, - REFIID riid, void **ppv) +static HRESULT WINAPI performance_QueryInterface(IDirectMusicPerformance8 *iface, REFIID riid, void **ppv) { TRACE("(%p, %s,%p)\n", iface, debugstr_dmguid(riid), ppv); @@ -269,7 +268,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_QueryInterface(IDirectMusicPe return E_NOINTERFACE; } -static ULONG WINAPI IDirectMusicPerformance8Impl_AddRef(IDirectMusicPerformance8 *iface) +static ULONG WINAPI performance_AddRef(IDirectMusicPerformance8 *iface) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); ULONG ref = InterlockedIncrement(&This->ref); @@ -279,7 +278,7 @@ static ULONG WINAPI IDirectMusicPerformance8Impl_AddRef(IDirectMusicPerformance8 return ref; } -static ULONG WINAPI IDirectMusicPerformance8Impl_Release(IDirectMusicPerformance8 *iface) +static ULONG WINAPI performance_Release(IDirectMusicPerformance8 *iface) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); ULONG ref = InterlockedDecrement(&This->ref); @@ -297,8 +296,8 @@ static ULONG WINAPI IDirectMusicPerformance8Impl_Release(IDirectMusicPerformance } /* IDirectMusicPerformanceImpl IDirectMusicPerformance Interface part: */ -static HRESULT WINAPI IDirectMusicPerformance8Impl_Init(IDirectMusicPerformance8 *iface, - IDirectMusic **dmusic, IDirectSound *dsound, HWND hwnd) +static HRESULT WINAPI performance_Init(IDirectMusicPerformance8 *iface, IDirectMusic **dmusic, + IDirectSound *dsound, HWND hwnd) { TRACE("(%p, %p, %p, %p)\n", iface, dmusic, dsound, hwnd); @@ -306,9 +305,8 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_Init(IDirectMusicPerformance8 0, NULL); } -static HRESULT WINAPI IDirectMusicPerformance8Impl_PlaySegment(IDirectMusicPerformance8 *iface, - IDirectMusicSegment *pSegment, DWORD dwFlags, __int64 i64StartTime, - IDirectMusicSegmentState **ppSegmentState) +static HRESULT WINAPI performance_PlaySegment(IDirectMusicPerformance8 *iface, IDirectMusicSegment *pSegment, + DWORD dwFlags, __int64 i64StartTime, IDirectMusicSegmentState **ppSegmentState) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -319,9 +317,8 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_PlaySegment(IDirectMusicPerfo return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_Stop(IDirectMusicPerformance8 *iface, - IDirectMusicSegment *pSegment, IDirectMusicSegmentState *pSegmentState, MUSIC_TIME mtTime, - DWORD dwFlags) +static HRESULT WINAPI performance_Stop(IDirectMusicPerformance8 *iface, IDirectMusicSegment *pSegment, + IDirectMusicSegmentState *pSegmentState, MUSIC_TIME mtTime, DWORD dwFlags) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -329,7 +326,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_Stop(IDirectMusicPerformance8 return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_GetSegmentState(IDirectMusicPerformance8 *iface, +static HRESULT WINAPI performance_GetSegmentState(IDirectMusicPerformance8 *iface, IDirectMusicSegmentState **ppSegmentState, MUSIC_TIME mtTime) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -338,8 +335,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_GetSegmentState(IDirectMusicP return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_SetPrepareTime(IDirectMusicPerformance8 *iface, - DWORD dwMilliSeconds) +static HRESULT WINAPI performance_SetPrepareTime(IDirectMusicPerformance8 *iface, DWORD dwMilliSeconds) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -348,8 +344,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_SetPrepareTime(IDirectMusicPe return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_GetPrepareTime(IDirectMusicPerformance8 *iface, - DWORD *pdwMilliSeconds) +static HRESULT WINAPI performance_GetPrepareTime(IDirectMusicPerformance8 *iface, DWORD *pdwMilliSeconds) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -361,8 +356,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_GetPrepareTime(IDirectMusicPe return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_SetBumperLength(IDirectMusicPerformance8 *iface, - DWORD dwMilliSeconds) +static HRESULT WINAPI performance_SetBumperLength(IDirectMusicPerformance8 *iface, DWORD dwMilliSeconds) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -371,8 +365,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_SetBumperLength(IDirectMusicP return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_GetBumperLength(IDirectMusicPerformance8 *iface, - DWORD *pdwMilliSeconds) +static HRESULT WINAPI performance_GetBumperLength(IDirectMusicPerformance8 *iface, DWORD *pdwMilliSeconds) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -384,8 +377,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_GetBumperLength(IDirectMusicP return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_SendPMsg(IDirectMusicPerformance8 *iface, - DMUS_PMSG *pPMSG) +static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *pPMSG) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); DMUS_PMSGItem* pItem = NULL; @@ -436,7 +428,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_SendPMsg(IDirectMusicPerforma return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_MusicToReferenceTime(IDirectMusicPerformance8 *iface, +static HRESULT WINAPI performance_MusicToReferenceTime(IDirectMusicPerformance8 *iface, MUSIC_TIME mtTime, REFERENCE_TIME *prtTime) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -445,7 +437,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_MusicToReferenceTime(IDirectM return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_ReferenceToMusicTime(IDirectMusicPerformance8 *iface, +static HRESULT WINAPI performance_ReferenceToMusicTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME rtTime, MUSIC_TIME *pmtTime) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -454,7 +446,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_ReferenceToMusicTime(IDirectM return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_IsPlaying(IDirectMusicPerformance8 *iface, +static HRESULT WINAPI performance_IsPlaying(IDirectMusicPerformance8 *iface, IDirectMusicSegment *pSegment, IDirectMusicSegmentState *pSegState) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -463,8 +455,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_IsPlaying(IDirectMusicPerform return S_FALSE; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_GetTime(IDirectMusicPerformance8 *iface, - REFERENCE_TIME *prtNow, MUSIC_TIME *pmtNow) +static HRESULT WINAPI performance_GetTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME *prtNow, MUSIC_TIME *pmtNow) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); HRESULT hr = S_OK; @@ -485,8 +476,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_GetTime(IDirectMusicPerforman return hr; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_AllocPMsg(IDirectMusicPerformance8 *iface, - ULONG cb, DMUS_PMSG **ppPMSG) +static HRESULT WINAPI performance_AllocPMsg(IDirectMusicPerformance8 *iface, ULONG cb, DMUS_PMSG **ppPMSG) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); DMUS_PMSGItem* pItem = NULL; @@ -505,8 +495,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_AllocPMsg(IDirectMusicPerform return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_FreePMsg(IDirectMusicPerformance8 *iface, - DMUS_PMSG *pPMSG) +static HRESULT WINAPI performance_FreePMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *pPMSG) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); DMUS_PMSGItem* pItem = NULL; @@ -539,8 +528,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_FreePMsg(IDirectMusicPerforma return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_GetGraph(IDirectMusicPerformance8 *iface, - IDirectMusicGraph **graph) +static HRESULT WINAPI performance_GetGraph(IDirectMusicPerformance8 *iface, IDirectMusicGraph **graph) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -557,8 +545,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_GetGraph(IDirectMusicPerforma return *graph ? S_OK : DMUS_E_NOT_FOUND; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_SetGraph(IDirectMusicPerformance8 *iface, - IDirectMusicGraph *pGraph) +static HRESULT WINAPI performance_SetGraph(IDirectMusicPerformance8 *iface, IDirectMusicGraph *pGraph) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -575,7 +562,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_SetGraph(IDirectMusicPerforma return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_SetNotificationHandle(IDirectMusicPerformance8 *iface, +static HRESULT WINAPI performance_SetNotificationHandle(IDirectMusicPerformance8 *iface, HANDLE hNotification, REFERENCE_TIME rtMinimum) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -590,7 +577,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_SetNotificationHandle(IDirect return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_GetNotificationPMsg(IDirectMusicPerformance8 *iface, +static HRESULT WINAPI performance_GetNotificationPMsg(IDirectMusicPerformance8 *iface, DMUS_NOTIFICATION_PMSG **ppNotificationPMsg) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -606,8 +593,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_GetNotificationPMsg(IDirectMu /*return S_OK;*/ } -static HRESULT WINAPI IDirectMusicPerformance8Impl_AddNotificationType(IDirectMusicPerformance8 *iface, - REFGUID rguidNotificationType) +static HRESULT WINAPI performance_AddNotificationType(IDirectMusicPerformance8 *iface, REFGUID rguidNotificationType) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -615,8 +601,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_AddNotificationType(IDirectMu return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_RemoveNotificationType(IDirectMusicPerformance8 *iface, - REFGUID rguidNotificationType) +static HRESULT WINAPI performance_RemoveNotificationType(IDirectMusicPerformance8 *iface, REFGUID rguidNotificationType) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -646,8 +631,7 @@ static HRESULT perf_dmport_create(IDirectMusicPerformance8Impl *perf, DMUS_PORTP return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_AddPort(IDirectMusicPerformance8 *iface, - IDirectMusicPort *port) +static HRESULT WINAPI performance_AddPort(IDirectMusicPerformance8 *iface, IDirectMusicPort *port) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -674,8 +658,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_AddPort(IDirectMusicPerforman return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_RemovePort(IDirectMusicPerformance8 *iface, - IDirectMusicPort *pPort) +static HRESULT WINAPI performance_RemovePort(IDirectMusicPerformance8 *iface, IDirectMusicPort *pPort) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -684,7 +667,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_RemovePort(IDirectMusicPerfor return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_AssignPChannelBlock(IDirectMusicPerformance8 *iface, +static HRESULT WINAPI performance_AssignPChannelBlock(IDirectMusicPerformance8 *iface, DWORD block_num, IDirectMusicPort *port, DWORD group) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -701,8 +684,8 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_AssignPChannelBlock(IDirectMu return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_AssignPChannel(IDirectMusicPerformance8 *iface, - DWORD pchannel, IDirectMusicPort *port, DWORD group, DWORD channel) +static HRESULT WINAPI performance_AssignPChannel(IDirectMusicPerformance8 *iface, DWORD pchannel, + IDirectMusicPort *port, DWORD group, DWORD channel) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); struct pchannel_block *block; @@ -721,8 +704,8 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_AssignPChannel(IDirectMusicPe return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_PChannelInfo(IDirectMusicPerformance8 *iface, - DWORD pchannel, IDirectMusicPort **port, DWORD *group, DWORD *channel) +static HRESULT WINAPI performance_PChannelInfo(IDirectMusicPerformance8 *iface, DWORD pchannel, + IDirectMusicPort **port, DWORD *group, DWORD *channel) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); struct pchannel_block *block; @@ -749,7 +732,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_PChannelInfo(IDirectMusicPerf return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_DownloadInstrument(IDirectMusicPerformance8 *iface, +static HRESULT WINAPI performance_DownloadInstrument(IDirectMusicPerformance8 *iface, IDirectMusicInstrument *pInst, DWORD dwPChannel, IDirectMusicDownloadedInstrument **ppDownInst, DMUS_NOTERANGE *pNoteRanges, DWORD dwNumNoteRanges, IDirectMusicPort **ppPort, DWORD *pdwGroup, DWORD *pdwMChannel) @@ -760,8 +743,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_DownloadInstrument(IDirectMus return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_Invalidate(IDirectMusicPerformance8 *iface, - MUSIC_TIME mtTime, DWORD dwFlags) +static HRESULT WINAPI performance_Invalidate(IDirectMusicPerformance8 *iface, MUSIC_TIME mtTime, DWORD dwFlags) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -769,9 +751,8 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_Invalidate(IDirectMusicPerfor return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_GetParam(IDirectMusicPerformance8 *iface, - REFGUID rguidType, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, - MUSIC_TIME *pmtNext, void *pParam) +static HRESULT WINAPI performance_GetParam(IDirectMusicPerformance8 *iface, REFGUID rguidType, + DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, MUSIC_TIME *pmtNext, void *pParam) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -779,8 +760,8 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_GetParam(IDirectMusicPerforma return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_SetParam(IDirectMusicPerformance8 *iface, - REFGUID rguidType, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, void *pParam) +static HRESULT WINAPI performance_SetParam(IDirectMusicPerformance8 *iface, REFGUID rguidType, + DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, void *pParam) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -788,8 +769,8 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_SetParam(IDirectMusicPerforma return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_GetGlobalParam(IDirectMusicPerformance8 *iface, - REFGUID rguidType, void *pParam, DWORD dwSize) +static HRESULT WINAPI performance_GetGlobalParam(IDirectMusicPerformance8 *iface, REFGUID rguidType, + void *pParam, DWORD dwSize) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -807,8 +788,8 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_GetGlobalParam(IDirectMusicPe return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_SetGlobalParam(IDirectMusicPerformance8 *iface, - REFGUID rguidType, void *pParam, DWORD dwSize) +static HRESULT WINAPI performance_SetGlobalParam(IDirectMusicPerformance8 *iface, REFGUID rguidType, + void *pParam, DWORD dwSize) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -834,8 +815,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_SetGlobalParam(IDirectMusicPe return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_GetLatencyTime(IDirectMusicPerformance8 *iface, - REFERENCE_TIME *prtTime) +static HRESULT WINAPI performance_GetLatencyTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME *prtTime) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -844,8 +824,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_GetLatencyTime(IDirectMusicPe return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_GetQueueTime(IDirectMusicPerformance8 *iface, - REFERENCE_TIME *prtTime) +static HRESULT WINAPI performance_GetQueueTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME *prtTime) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -854,8 +833,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_GetQueueTime(IDirectMusicPerf return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_AdjustTime(IDirectMusicPerformance8 *iface, - REFERENCE_TIME rtAmount) +static HRESULT WINAPI performance_AdjustTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME rtAmount) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -863,7 +841,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_AdjustTime(IDirectMusicPerfor return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_CloseDown(IDirectMusicPerformance8 *iface) +static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -886,7 +864,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_CloseDown(IDirectMusicPerform return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_GetResolvedTime(IDirectMusicPerformance8 *iface, +static HRESULT WINAPI performance_GetResolvedTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME rtTime, REFERENCE_TIME *prtResolved, DWORD dwTimeResolveFlags) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -896,9 +874,8 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_GetResolvedTime(IDirectMusicP return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_MIDIToMusic(IDirectMusicPerformance8 *iface, - BYTE bMIDIValue, DMUS_CHORD_KEY *pChord, BYTE bPlayMode, BYTE bChordLevel, - WORD *pwMusicValue) +static HRESULT WINAPI performance_MIDIToMusic(IDirectMusicPerformance8 *iface, BYTE bMIDIValue, + DMUS_CHORD_KEY *pChord, BYTE bPlayMode, BYTE bChordLevel, WORD *pwMusicValue) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -906,9 +883,8 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_MIDIToMusic(IDirectMusicPerfo return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_MusicToMIDI(IDirectMusicPerformance8 *iface, - WORD wMusicValue, DMUS_CHORD_KEY *pChord, BYTE bPlayMode, BYTE bChordLevel, - BYTE *pbMIDIValue) +static HRESULT WINAPI performance_MusicToMIDI(IDirectMusicPerformance8 *iface, WORD wMusicValue, + DMUS_CHORD_KEY *pChord, BYTE bPlayMode, BYTE bChordLevel, BYTE *pbMIDIValue) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -916,9 +892,8 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_MusicToMIDI(IDirectMusicPerfo return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_TimeToRhythm(IDirectMusicPerformance8 *iface, - MUSIC_TIME mtTime, DMUS_TIMESIGNATURE *pTimeSig, WORD *pwMeasure, BYTE *pbBeat, - BYTE *pbGrid, short *pnOffset) +static HRESULT WINAPI performance_TimeToRhythm(IDirectMusicPerformance8 *iface, MUSIC_TIME mtTime, + DMUS_TIMESIGNATURE *pTimeSig, WORD *pwMeasure, BYTE *pbBeat, BYTE *pbGrid, short *pnOffset) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -926,9 +901,8 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_TimeToRhythm(IDirectMusicPerf return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_RhythmToTime(IDirectMusicPerformance8 *iface, - WORD wMeasure, BYTE bBeat, BYTE bGrid, short nOffset, DMUS_TIMESIGNATURE *pTimeSig, - MUSIC_TIME *pmtTime) +static HRESULT WINAPI performance_RhythmToTime(IDirectMusicPerformance8 *iface, WORD wMeasure, + BYTE bBeat, BYTE bGrid, short nOffset, DMUS_TIMESIGNATURE *pTimeSig, MUSIC_TIME *pmtTime) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -937,9 +911,9 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_RhythmToTime(IDirectMusicPerf } /* IDirectMusicPerformance8 Interface part follow: */ -static HRESULT WINAPI IDirectMusicPerformance8Impl_InitAudio(IDirectMusicPerformance8 *iface, - IDirectMusic **dmusic, IDirectSound **dsound, HWND hwnd, DWORD default_path_type, - DWORD num_channels, DWORD flags, DMUS_AUDIOPARAMS *params) +static HRESULT WINAPI performance_InitAudio(IDirectMusicPerformance8 *iface, IDirectMusic **dmusic, + IDirectSound **dsound, HWND hwnd, DWORD default_path_type, DWORD num_channels, DWORD flags, + DMUS_AUDIOPARAMS *params) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); HRESULT hr = S_OK; @@ -1022,10 +996,9 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_InitAudio(IDirectMusicPerform return hr; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_PlaySegmentEx(IDirectMusicPerformance8 *iface, - IUnknown *pSource, WCHAR *pwzSegmentName, IUnknown *pTransition, DWORD dwFlags, - __int64 i64StartTime, IDirectMusicSegmentState **ppSegmentState, IUnknown *pFrom, - IUnknown *pAudioPath) +static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, IUnknown *pSource, + WCHAR *pwzSegmentName, IUnknown *pTransition, DWORD dwFlags, __int64 i64StartTime, + IDirectMusicSegmentState **ppSegmentState, IUnknown *pFrom, IUnknown *pAudioPath) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -1036,8 +1009,8 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_PlaySegmentEx(IDirectMusicPer return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_StopEx(IDirectMusicPerformance8 *iface, - IUnknown *pObjectToStop, __int64 i64StopTime, DWORD dwFlags) +static HRESULT WINAPI performance_StopEx(IDirectMusicPerformance8 *iface, IUnknown *pObjectToStop, + __int64 i64StopTime, DWORD dwFlags) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -1046,8 +1019,8 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_StopEx(IDirectMusicPerformanc return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_ClonePMsg(IDirectMusicPerformance8 *iface, - DMUS_PMSG *pSourcePMSG, DMUS_PMSG **ppCopyPMSG) +static HRESULT WINAPI performance_ClonePMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *pSourcePMSG, + DMUS_PMSG **ppCopyPMSG) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -1055,7 +1028,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_ClonePMsg(IDirectMusicPerform return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_CreateAudioPath(IDirectMusicPerformance8 *iface, +static HRESULT WINAPI performance_CreateAudioPath(IDirectMusicPerformance8 *iface, IUnknown *pSourceConfig, BOOL fActivate, IDirectMusicAudioPath **ppNewPath) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -1077,7 +1050,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_CreateAudioPath(IDirectMusicP return IDirectMusicAudioPath_Activate(*ppNewPath, fActivate); } -static HRESULT WINAPI IDirectMusicPerformance8Impl_CreateStandardAudioPath(IDirectMusicPerformance8 *iface, +static HRESULT WINAPI performance_CreateStandardAudioPath(IDirectMusicPerformance8 *iface, DWORD dwType, DWORD pchannel_count, BOOL fActivate, IDirectMusicAudioPath **ppNewPath) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -1171,8 +1144,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_CreateStandardAudioPath(IDire return IDirectMusicAudioPath_Activate(*ppNewPath, fActivate); } -static HRESULT WINAPI IDirectMusicPerformance8Impl_SetDefaultAudioPath(IDirectMusicPerformance8 *iface, - IDirectMusicAudioPath *pAudioPath) +static HRESULT WINAPI performance_SetDefaultAudioPath(IDirectMusicPerformance8 *iface, IDirectMusicAudioPath *pAudioPath) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -1191,7 +1163,7 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_SetDefaultAudioPath(IDirectMu return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_GetDefaultAudioPath(IDirectMusicPerformance8 *iface, +static HRESULT WINAPI performance_GetDefaultAudioPath(IDirectMusicPerformance8 *iface, IDirectMusicAudioPath **ppAudioPath) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -1207,9 +1179,8 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_GetDefaultAudioPath(IDirectMu return S_OK; } -static HRESULT WINAPI IDirectMusicPerformance8Impl_GetParamEx(IDirectMusicPerformance8 *iface, - REFGUID rguidType, DWORD dwTrackID, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, - MUSIC_TIME *pmtNext, void *pParam) +static HRESULT WINAPI performance_GetParamEx(IDirectMusicPerformance8 *iface, REFGUID rguidType, DWORD dwTrackID, + DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, MUSIC_TIME *pmtNext, void *pParam) { IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); @@ -1218,60 +1189,61 @@ static HRESULT WINAPI IDirectMusicPerformance8Impl_GetParamEx(IDirectMusicPerfor return S_OK; } -static const IDirectMusicPerformance8Vtbl DirectMusicPerformance8_Vtbl = { - IDirectMusicPerformance8Impl_QueryInterface, - IDirectMusicPerformance8Impl_AddRef, - IDirectMusicPerformance8Impl_Release, - IDirectMusicPerformance8Impl_Init, - IDirectMusicPerformance8Impl_PlaySegment, - IDirectMusicPerformance8Impl_Stop, - IDirectMusicPerformance8Impl_GetSegmentState, - IDirectMusicPerformance8Impl_SetPrepareTime, - IDirectMusicPerformance8Impl_GetPrepareTime, - IDirectMusicPerformance8Impl_SetBumperLength, - IDirectMusicPerformance8Impl_GetBumperLength, - IDirectMusicPerformance8Impl_SendPMsg, - IDirectMusicPerformance8Impl_MusicToReferenceTime, - IDirectMusicPerformance8Impl_ReferenceToMusicTime, - IDirectMusicPerformance8Impl_IsPlaying, - IDirectMusicPerformance8Impl_GetTime, - IDirectMusicPerformance8Impl_AllocPMsg, - IDirectMusicPerformance8Impl_FreePMsg, - IDirectMusicPerformance8Impl_GetGraph, - IDirectMusicPerformance8Impl_SetGraph, - IDirectMusicPerformance8Impl_SetNotificationHandle, - IDirectMusicPerformance8Impl_GetNotificationPMsg, - IDirectMusicPerformance8Impl_AddNotificationType, - IDirectMusicPerformance8Impl_RemoveNotificationType, - IDirectMusicPerformance8Impl_AddPort, - IDirectMusicPerformance8Impl_RemovePort, - IDirectMusicPerformance8Impl_AssignPChannelBlock, - IDirectMusicPerformance8Impl_AssignPChannel, - IDirectMusicPerformance8Impl_PChannelInfo, - IDirectMusicPerformance8Impl_DownloadInstrument, - IDirectMusicPerformance8Impl_Invalidate, - IDirectMusicPerformance8Impl_GetParam, - IDirectMusicPerformance8Impl_SetParam, - IDirectMusicPerformance8Impl_GetGlobalParam, - IDirectMusicPerformance8Impl_SetGlobalParam, - IDirectMusicPerformance8Impl_GetLatencyTime, - IDirectMusicPerformance8Impl_GetQueueTime, - IDirectMusicPerformance8Impl_AdjustTime, - IDirectMusicPerformance8Impl_CloseDown, - IDirectMusicPerformance8Impl_GetResolvedTime, - IDirectMusicPerformance8Impl_MIDIToMusic, - IDirectMusicPerformance8Impl_MusicToMIDI, - IDirectMusicPerformance8Impl_TimeToRhythm, - IDirectMusicPerformance8Impl_RhythmToTime, - IDirectMusicPerformance8Impl_InitAudio, - IDirectMusicPerformance8Impl_PlaySegmentEx, - IDirectMusicPerformance8Impl_StopEx, - IDirectMusicPerformance8Impl_ClonePMsg, - IDirectMusicPerformance8Impl_CreateAudioPath, - IDirectMusicPerformance8Impl_CreateStandardAudioPath, - IDirectMusicPerformance8Impl_SetDefaultAudioPath, - IDirectMusicPerformance8Impl_GetDefaultAudioPath, - IDirectMusicPerformance8Impl_GetParamEx +static const IDirectMusicPerformance8Vtbl performance_vtbl = +{ + performance_QueryInterface, + performance_AddRef, + performance_Release, + performance_Init, + performance_PlaySegment, + performance_Stop, + performance_GetSegmentState, + performance_SetPrepareTime, + performance_GetPrepareTime, + performance_SetBumperLength, + performance_GetBumperLength, + performance_SendPMsg, + performance_MusicToReferenceTime, + performance_ReferenceToMusicTime, + performance_IsPlaying, + performance_GetTime, + performance_AllocPMsg, + performance_FreePMsg, + performance_GetGraph, + performance_SetGraph, + performance_SetNotificationHandle, + performance_GetNotificationPMsg, + performance_AddNotificationType, + performance_RemoveNotificationType, + performance_AddPort, + performance_RemovePort, + performance_AssignPChannelBlock, + performance_AssignPChannel, + performance_PChannelInfo, + performance_DownloadInstrument, + performance_Invalidate, + performance_GetParam, + performance_SetParam, + performance_GetGlobalParam, + performance_SetGlobalParam, + performance_GetLatencyTime, + performance_GetQueueTime, + performance_AdjustTime, + performance_CloseDown, + performance_GetResolvedTime, + performance_MIDIToMusic, + performance_MusicToMIDI, + performance_TimeToRhythm, + performance_RhythmToTime, + performance_InitAudio, + performance_PlaySegmentEx, + performance_StopEx, + performance_ClonePMsg, + performance_CreateAudioPath, + performance_CreateStandardAudioPath, + performance_SetDefaultAudioPath, + performance_GetDefaultAudioPath, + performance_GetParamEx, }; /* for ClassFactory */ @@ -1284,7 +1256,7 @@ HRESULT create_dmperformance(REFIID iid, void **ret_iface) *ret_iface = NULL; if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; - obj->IDirectMusicPerformance8_iface.lpVtbl = &DirectMusicPerformance8_Vtbl; + obj->IDirectMusicPerformance8_iface.lpVtbl = &performance_vtbl; obj->ref = 1; obj->pDefaultPath = NULL; From ff04d09b5e58f22c44be7738e9e3de7869fda90b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 21:45:31 +0200 Subject: [PATCH 2478/2777] dmime: Get rid of IDirectMusicPerformance8Impl typedef. (cherry picked from commit c927967a7623921b8f2eaa946b72342d4ec81b5d) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 125 ++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 62 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 7617b92309d..d6f7e76686e 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -34,7 +34,8 @@ struct pchannel_block { struct wine_rb_entry entry; }; -typedef struct IDirectMusicPerformance8Impl { +struct performance +{ IDirectMusicPerformance8 IDirectMusicPerformance8_iface; LONG ref; IDirectMusic8 *dmusic; @@ -47,7 +48,7 @@ typedef struct IDirectMusicPerformance8Impl { long lMasterVolume; /* performance channels */ struct wine_rb_tree pchannels; - /* IDirectMusicPerformance8Impl fields */ + IDirectMusicAudioPath *pDefaultPath; HANDLE hNotification; REFERENCE_TIME rtMinimum; @@ -62,7 +63,7 @@ typedef struct IDirectMusicPerformance8Impl { CRITICAL_SECTION safe; struct DMUS_PMSGItem *head; struct DMUS_PMSGItem *imm_head; -} IDirectMusicPerformance8Impl; +}; typedef struct DMUS_PMSGItem DMUS_PMSGItem; struct DMUS_PMSGItem { @@ -92,7 +93,7 @@ struct DMUS_PMSGItem { #define PROCESSMSG_ADD (WM_APP + 4) -static DMUS_PMSGItem* ProceedMsg(IDirectMusicPerformance8Impl* This, DMUS_PMSGItem* cur) { +static DMUS_PMSGItem* ProceedMsg(struct performance *This, DMUS_PMSGItem* cur) { if (cur->pMsg.dwType == DMUS_PMSGT_NOTIFICATION) { SetEvent(This->hNotification); } @@ -109,7 +110,7 @@ static DMUS_PMSGItem* ProceedMsg(IDirectMusicPerformance8Impl* This, DMUS_PMSGIt } static DWORD WINAPI ProcessMsgThread(LPVOID lpParam) { - IDirectMusicPerformance8Impl* This = lpParam; + struct performance *This = lpParam; DWORD timeOut = INFINITE; MSG msg; HRESULT hr; @@ -183,7 +184,7 @@ static DWORD WINAPI ProcessMsgThread(LPVOID lpParam) { return 0; } -static BOOL PostMessageToProcessMsgThread(IDirectMusicPerformance8Impl* This, UINT iMsg) { +static BOOL PostMessageToProcessMsgThread(struct performance *This, UINT iMsg) { if (FALSE == This->procThreadTicStarted && PROCESSMSG_EXIT != iMsg) { BOOL res; This->procThread = CreateThread(NULL, 0, ProcessMsgThread, This, 0, &This->procThreadId); @@ -245,9 +246,9 @@ static struct pchannel_block *pchannel_block_set(struct wine_rb_tree *tree, DWOR return block; } -static inline IDirectMusicPerformance8Impl *impl_from_IDirectMusicPerformance8(IDirectMusicPerformance8 *iface) +static inline struct performance *impl_from_IDirectMusicPerformance8(IDirectMusicPerformance8 *iface) { - return CONTAINING_RECORD(iface, IDirectMusicPerformance8Impl, IDirectMusicPerformance8_iface); + return CONTAINING_RECORD(iface, struct performance, IDirectMusicPerformance8_iface); } /* IDirectMusicPerformance8 IUnknown part: */ @@ -270,7 +271,7 @@ static HRESULT WINAPI performance_QueryInterface(IDirectMusicPerformance8 *iface static ULONG WINAPI performance_AddRef(IDirectMusicPerformance8 *iface) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p): ref=%ld\n", This, ref); @@ -280,7 +281,7 @@ static ULONG WINAPI performance_AddRef(IDirectMusicPerformance8 *iface) static ULONG WINAPI performance_Release(IDirectMusicPerformance8 *iface) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p): ref=%ld\n", This, ref); @@ -308,7 +309,7 @@ static HRESULT WINAPI performance_Init(IDirectMusicPerformance8 *iface, IDirectM static HRESULT WINAPI performance_PlaySegment(IDirectMusicPerformance8 *iface, IDirectMusicSegment *pSegment, DWORD dwFlags, __int64 i64StartTime, IDirectMusicSegmentState **ppSegmentState) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %p, %ld, 0x%s, %p): stub\n", This, pSegment, dwFlags, wine_dbgstr_longlong(i64StartTime), ppSegmentState); @@ -320,7 +321,7 @@ static HRESULT WINAPI performance_PlaySegment(IDirectMusicPerformance8 *iface, I static HRESULT WINAPI performance_Stop(IDirectMusicPerformance8 *iface, IDirectMusicSegment *pSegment, IDirectMusicSegmentState *pSegmentState, MUSIC_TIME mtTime, DWORD dwFlags) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %p, %p, %ld, %ld): stub\n", This, pSegment, pSegmentState, mtTime, dwFlags); return S_OK; @@ -329,7 +330,7 @@ static HRESULT WINAPI performance_Stop(IDirectMusicPerformance8 *iface, IDirectM static HRESULT WINAPI performance_GetSegmentState(IDirectMusicPerformance8 *iface, IDirectMusicSegmentState **ppSegmentState, MUSIC_TIME mtTime) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p,%p, %ld): stub\n", This, ppSegmentState, mtTime); return S_OK; @@ -337,7 +338,7 @@ static HRESULT WINAPI performance_GetSegmentState(IDirectMusicPerformance8 *ifac static HRESULT WINAPI performance_SetPrepareTime(IDirectMusicPerformance8 *iface, DWORD dwMilliSeconds) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); TRACE("(%p, %ld)\n", This, dwMilliSeconds); This->dwPrepareTime = dwMilliSeconds; @@ -346,7 +347,7 @@ static HRESULT WINAPI performance_SetPrepareTime(IDirectMusicPerformance8 *iface static HRESULT WINAPI performance_GetPrepareTime(IDirectMusicPerformance8 *iface, DWORD *pdwMilliSeconds) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); TRACE("(%p, %p)\n", This, pdwMilliSeconds); if (NULL == pdwMilliSeconds) { @@ -358,7 +359,7 @@ static HRESULT WINAPI performance_GetPrepareTime(IDirectMusicPerformance8 *iface static HRESULT WINAPI performance_SetBumperLength(IDirectMusicPerformance8 *iface, DWORD dwMilliSeconds) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); TRACE("(%p, %ld)\n", This, dwMilliSeconds); This->dwBumperLength = dwMilliSeconds; @@ -367,7 +368,7 @@ static HRESULT WINAPI performance_SetBumperLength(IDirectMusicPerformance8 *ifac static HRESULT WINAPI performance_GetBumperLength(IDirectMusicPerformance8 *iface, DWORD *pdwMilliSeconds) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); TRACE("(%p, %p)\n", This, pdwMilliSeconds); if (NULL == pdwMilliSeconds) { @@ -379,7 +380,7 @@ static HRESULT WINAPI performance_GetBumperLength(IDirectMusicPerformance8 *ifac static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *pPMSG) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); DMUS_PMSGItem* pItem = NULL; DMUS_PMSGItem* it = NULL; DMUS_PMSGItem* prev_it = NULL; @@ -431,7 +432,7 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS static HRESULT WINAPI performance_MusicToReferenceTime(IDirectMusicPerformance8 *iface, MUSIC_TIME mtTime, REFERENCE_TIME *prtTime) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %ld, %p): stub\n", This, mtTime, prtTime); return S_OK; @@ -440,7 +441,7 @@ static HRESULT WINAPI performance_MusicToReferenceTime(IDirectMusicPerformance8 static HRESULT WINAPI performance_ReferenceToMusicTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME rtTime, MUSIC_TIME *pmtTime) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, 0x%s, %p): stub\n", This, wine_dbgstr_longlong(rtTime), pmtTime); return S_OK; @@ -449,7 +450,7 @@ static HRESULT WINAPI performance_ReferenceToMusicTime(IDirectMusicPerformance8 static HRESULT WINAPI performance_IsPlaying(IDirectMusicPerformance8 *iface, IDirectMusicSegment *pSegment, IDirectMusicSegmentState *pSegState) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %p, %p): stub\n", This, pSegment, pSegState); return S_FALSE; @@ -457,7 +458,7 @@ static HRESULT WINAPI performance_IsPlaying(IDirectMusicPerformance8 *iface, static HRESULT WINAPI performance_GetTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME *prtNow, MUSIC_TIME *pmtNow) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); HRESULT hr = S_OK; REFERENCE_TIME rtCur = 0; @@ -478,7 +479,7 @@ static HRESULT WINAPI performance_GetTime(IDirectMusicPerformance8 *iface, REFER static HRESULT WINAPI performance_AllocPMsg(IDirectMusicPerformance8 *iface, ULONG cb, DMUS_PMSG **ppPMSG) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); DMUS_PMSGItem* pItem = NULL; FIXME("(%p, %ld, %p): stub\n", This, cb, ppPMSG); @@ -497,7 +498,7 @@ static HRESULT WINAPI performance_AllocPMsg(IDirectMusicPerformance8 *iface, ULO static HRESULT WINAPI performance_FreePMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *pPMSG) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); DMUS_PMSGItem* pItem = NULL; FIXME("(%p, %p): stub\n", This, pPMSG); @@ -530,7 +531,7 @@ static HRESULT WINAPI performance_FreePMsg(IDirectMusicPerformance8 *iface, DMUS static HRESULT WINAPI performance_GetGraph(IDirectMusicPerformance8 *iface, IDirectMusicGraph **graph) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); TRACE("(%p, %p)\n", This, graph); @@ -547,7 +548,7 @@ static HRESULT WINAPI performance_GetGraph(IDirectMusicPerformance8 *iface, IDir static HRESULT WINAPI performance_SetGraph(IDirectMusicPerformance8 *iface, IDirectMusicGraph *pGraph) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %p): to check\n", This, pGraph); @@ -565,7 +566,7 @@ static HRESULT WINAPI performance_SetGraph(IDirectMusicPerformance8 *iface, IDir static HRESULT WINAPI performance_SetNotificationHandle(IDirectMusicPerformance8 *iface, HANDLE hNotification, REFERENCE_TIME rtMinimum) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); TRACE("(%p, %p, 0x%s)\n", This, hNotification, wine_dbgstr_longlong(rtMinimum)); @@ -580,7 +581,7 @@ static HRESULT WINAPI performance_SetNotificationHandle(IDirectMusicPerformance8 static HRESULT WINAPI performance_GetNotificationPMsg(IDirectMusicPerformance8 *iface, DMUS_NOTIFICATION_PMSG **ppNotificationPMsg) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %p): stub\n", This, ppNotificationPMsg); if (NULL == ppNotificationPMsg) { @@ -595,7 +596,7 @@ static HRESULT WINAPI performance_GetNotificationPMsg(IDirectMusicPerformance8 * static HRESULT WINAPI performance_AddNotificationType(IDirectMusicPerformance8 *iface, REFGUID rguidNotificationType) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType)); return S_OK; @@ -603,13 +604,13 @@ static HRESULT WINAPI performance_AddNotificationType(IDirectMusicPerformance8 * static HRESULT WINAPI performance_RemoveNotificationType(IDirectMusicPerformance8 *iface, REFGUID rguidNotificationType) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType)); return S_OK; } -static HRESULT perf_dmport_create(IDirectMusicPerformance8Impl *perf, DMUS_PORTPARAMS *params) +static HRESULT perf_dmport_create(struct performance *perf, DMUS_PORTPARAMS *params) { IDirectMusicPort *port; GUID guid; @@ -633,7 +634,7 @@ static HRESULT perf_dmport_create(IDirectMusicPerformance8Impl *perf, DMUS_PORTP static HRESULT WINAPI performance_AddPort(IDirectMusicPerformance8 *iface, IDirectMusicPort *port) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %p): semi-stub\n", This, port); @@ -660,7 +661,7 @@ static HRESULT WINAPI performance_AddPort(IDirectMusicPerformance8 *iface, IDire static HRESULT WINAPI performance_RemovePort(IDirectMusicPerformance8 *iface, IDirectMusicPort *pPort) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %p): stub\n", This, pPort); IDirectMusicPort_Release (pPort); @@ -670,7 +671,7 @@ static HRESULT WINAPI performance_RemovePort(IDirectMusicPerformance8 *iface, ID static HRESULT WINAPI performance_AssignPChannelBlock(IDirectMusicPerformance8 *iface, DWORD block_num, IDirectMusicPort *port, DWORD group) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %ld, %p, %ld): semi-stub\n", This, block_num, port, group); @@ -687,7 +688,7 @@ static HRESULT WINAPI performance_AssignPChannelBlock(IDirectMusicPerformance8 * static HRESULT WINAPI performance_AssignPChannel(IDirectMusicPerformance8 *iface, DWORD pchannel, IDirectMusicPort *port, DWORD group, DWORD channel) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); struct pchannel_block *block; FIXME("(%p)->(%ld, %p, %ld, %ld) semi-stub\n", This, pchannel, port, group, channel); @@ -707,7 +708,7 @@ static HRESULT WINAPI performance_AssignPChannel(IDirectMusicPerformance8 *iface static HRESULT WINAPI performance_PChannelInfo(IDirectMusicPerformance8 *iface, DWORD pchannel, IDirectMusicPort **port, DWORD *group, DWORD *channel) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); struct pchannel_block *block; struct wine_rb_entry *entry; DWORD block_num = pchannel / 16; @@ -737,7 +738,7 @@ static HRESULT WINAPI performance_DownloadInstrument(IDirectMusicPerformance8 *i IDirectMusicDownloadedInstrument **ppDownInst, DMUS_NOTERANGE *pNoteRanges, DWORD dwNumNoteRanges, IDirectMusicPort **ppPort, DWORD *pdwGroup, DWORD *pdwMChannel) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %p, %ld, %p, %p, %ld, %p, %p, %p): stub\n", This, pInst, dwPChannel, ppDownInst, pNoteRanges, dwNumNoteRanges, ppPort, pdwGroup, pdwMChannel); return S_OK; @@ -745,7 +746,7 @@ static HRESULT WINAPI performance_DownloadInstrument(IDirectMusicPerformance8 *i static HRESULT WINAPI performance_Invalidate(IDirectMusicPerformance8 *iface, MUSIC_TIME mtTime, DWORD dwFlags) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %ld, %ld): stub\n", This, mtTime, dwFlags); return S_OK; @@ -754,7 +755,7 @@ static HRESULT WINAPI performance_Invalidate(IDirectMusicPerformance8 *iface, MU static HRESULT WINAPI performance_GetParam(IDirectMusicPerformance8 *iface, REFGUID rguidType, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, MUSIC_TIME *pmtNext, void *pParam) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %s, %ld, %ld, %ld, %p, %p): stub\n", This, debugstr_dmguid(rguidType), dwGroupBits, dwIndex, mtTime, pmtNext, pParam); return S_OK; @@ -763,7 +764,7 @@ static HRESULT WINAPI performance_GetParam(IDirectMusicPerformance8 *iface, REFG static HRESULT WINAPI performance_SetParam(IDirectMusicPerformance8 *iface, REFGUID rguidType, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, void *pParam) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %s, %ld, %ld, %ld, %p): stub\n", This, debugstr_dmguid(rguidType), dwGroupBits, dwIndex, mtTime, pParam); return S_OK; @@ -772,7 +773,7 @@ static HRESULT WINAPI performance_SetParam(IDirectMusicPerformance8 *iface, REFG static HRESULT WINAPI performance_GetGlobalParam(IDirectMusicPerformance8 *iface, REFGUID rguidType, void *pParam, DWORD dwSize) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); TRACE("(%p, %s, %p, %ld): stub\n", This, debugstr_dmguid(rguidType), pParam, dwSize); @@ -791,7 +792,7 @@ static HRESULT WINAPI performance_GetGlobalParam(IDirectMusicPerformance8 *iface static HRESULT WINAPI performance_SetGlobalParam(IDirectMusicPerformance8 *iface, REFGUID rguidType, void *pParam, DWORD dwSize) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); TRACE("(%p, %s, %p, %ld)\n", This, debugstr_dmguid(rguidType), pParam, dwSize); @@ -817,7 +818,7 @@ static HRESULT WINAPI performance_SetGlobalParam(IDirectMusicPerformance8 *iface static HRESULT WINAPI performance_GetLatencyTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME *prtTime) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); TRACE("(%p, %p): stub\n", This, prtTime); *prtTime = This->rtLatencyTime; @@ -827,7 +828,7 @@ static HRESULT WINAPI performance_GetLatencyTime(IDirectMusicPerformance8 *iface static HRESULT WINAPI performance_GetQueueTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME *prtTime) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %p): stub\n", This, prtTime); return S_OK; @@ -835,7 +836,7 @@ static HRESULT WINAPI performance_GetQueueTime(IDirectMusicPerformance8 *iface, static HRESULT WINAPI performance_AdjustTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME rtAmount) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, 0x%s): stub\n", This, wine_dbgstr_longlong(rtAmount)); return S_OK; @@ -843,7 +844,7 @@ static HRESULT WINAPI performance_AdjustTime(IDirectMusicPerformance8 *iface, RE static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p): semi-stub\n", This); @@ -867,7 +868,7 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) static HRESULT WINAPI performance_GetResolvedTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME rtTime, REFERENCE_TIME *prtResolved, DWORD dwTimeResolveFlags) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, 0x%s, %p, %ld): stub\n", This, wine_dbgstr_longlong(rtTime), prtResolved, dwTimeResolveFlags); @@ -877,7 +878,7 @@ static HRESULT WINAPI performance_GetResolvedTime(IDirectMusicPerformance8 *ifac static HRESULT WINAPI performance_MIDIToMusic(IDirectMusicPerformance8 *iface, BYTE bMIDIValue, DMUS_CHORD_KEY *pChord, BYTE bPlayMode, BYTE bChordLevel, WORD *pwMusicValue) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %d, %p, %d, %d, %p): stub\n", This, bMIDIValue, pChord, bPlayMode, bChordLevel, pwMusicValue); return S_OK; @@ -886,7 +887,7 @@ static HRESULT WINAPI performance_MIDIToMusic(IDirectMusicPerformance8 *iface, B static HRESULT WINAPI performance_MusicToMIDI(IDirectMusicPerformance8 *iface, WORD wMusicValue, DMUS_CHORD_KEY *pChord, BYTE bPlayMode, BYTE bChordLevel, BYTE *pbMIDIValue) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %d, %p, %d, %d, %p): stub\n", This, wMusicValue, pChord, bPlayMode, bChordLevel, pbMIDIValue); return S_OK; @@ -895,7 +896,7 @@ static HRESULT WINAPI performance_MusicToMIDI(IDirectMusicPerformance8 *iface, W static HRESULT WINAPI performance_TimeToRhythm(IDirectMusicPerformance8 *iface, MUSIC_TIME mtTime, DMUS_TIMESIGNATURE *pTimeSig, WORD *pwMeasure, BYTE *pbBeat, BYTE *pbGrid, short *pnOffset) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %ld, %p, %p, %p, %p, %p): stub\n", This, mtTime, pTimeSig, pwMeasure, pbBeat, pbGrid, pnOffset); return S_OK; @@ -904,7 +905,7 @@ static HRESULT WINAPI performance_TimeToRhythm(IDirectMusicPerformance8 *iface, static HRESULT WINAPI performance_RhythmToTime(IDirectMusicPerformance8 *iface, WORD wMeasure, BYTE bBeat, BYTE bGrid, short nOffset, DMUS_TIMESIGNATURE *pTimeSig, MUSIC_TIME *pmtTime) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %d, %d, %d, %i, %p, %p): stub\n", This, wMeasure, bBeat, bGrid, nOffset, pTimeSig, pmtTime); return S_OK; @@ -915,7 +916,7 @@ static HRESULT WINAPI performance_InitAudio(IDirectMusicPerformance8 *iface, IDi IDirectSound **dsound, HWND hwnd, DWORD default_path_type, DWORD num_channels, DWORD flags, DMUS_AUDIOPARAMS *params) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); HRESULT hr = S_OK; TRACE("(%p, %p, %p, %p, %lx, %lu, %lx, %p)\n", This, dmusic, dsound, hwnd, default_path_type, @@ -1000,7 +1001,7 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, WCHAR *pwzSegmentName, IUnknown *pTransition, DWORD dwFlags, __int64 i64StartTime, IDirectMusicSegmentState **ppSegmentState, IUnknown *pFrom, IUnknown *pAudioPath) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %p, %p, %p, %ld, 0x%s, %p, %p, %p): stub\n", This, pSource, pwzSegmentName, pTransition, dwFlags, wine_dbgstr_longlong(i64StartTime), ppSegmentState, pFrom, pAudioPath); @@ -1012,7 +1013,7 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, static HRESULT WINAPI performance_StopEx(IDirectMusicPerformance8 *iface, IUnknown *pObjectToStop, __int64 i64StopTime, DWORD dwFlags) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %p, 0x%s, %ld): stub\n", This, pObjectToStop, wine_dbgstr_longlong(i64StopTime), dwFlags); @@ -1022,7 +1023,7 @@ static HRESULT WINAPI performance_StopEx(IDirectMusicPerformance8 *iface, IUnkno static HRESULT WINAPI performance_ClonePMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *pSourcePMSG, DMUS_PMSG **ppCopyPMSG) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %p, %p): stub\n", This, pSourcePMSG, ppCopyPMSG); return S_OK; @@ -1031,7 +1032,7 @@ static HRESULT WINAPI performance_ClonePMsg(IDirectMusicPerformance8 *iface, DMU static HRESULT WINAPI performance_CreateAudioPath(IDirectMusicPerformance8 *iface, IUnknown *pSourceConfig, BOOL fActivate, IDirectMusicAudioPath **ppNewPath) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); IDirectMusicAudioPath *pPath; FIXME("(%p, %p, %d, %p): stub\n", This, pSourceConfig, fActivate, ppNewPath); @@ -1053,7 +1054,7 @@ static HRESULT WINAPI performance_CreateAudioPath(IDirectMusicPerformance8 *ifac static HRESULT WINAPI performance_CreateStandardAudioPath(IDirectMusicPerformance8 *iface, DWORD dwType, DWORD pchannel_count, BOOL fActivate, IDirectMusicAudioPath **ppNewPath) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); IDirectMusicAudioPath *pPath; DSBUFFERDESC desc; WAVEFORMATEX format; @@ -1146,7 +1147,7 @@ static HRESULT WINAPI performance_CreateStandardAudioPath(IDirectMusicPerformanc static HRESULT WINAPI performance_SetDefaultAudioPath(IDirectMusicPerformance8 *iface, IDirectMusicAudioPath *pAudioPath) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %p): semi-stub\n", This, pAudioPath); @@ -1166,7 +1167,7 @@ static HRESULT WINAPI performance_SetDefaultAudioPath(IDirectMusicPerformance8 * static HRESULT WINAPI performance_GetDefaultAudioPath(IDirectMusicPerformance8 *iface, IDirectMusicAudioPath **ppAudioPath) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %p): semi-stub (%p)\n", This, ppAudioPath, This->pDefaultPath); @@ -1182,7 +1183,7 @@ static HRESULT WINAPI performance_GetDefaultAudioPath(IDirectMusicPerformance8 * static HRESULT WINAPI performance_GetParamEx(IDirectMusicPerformance8 *iface, REFGUID rguidType, DWORD dwTrackID, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, MUSIC_TIME *pmtNext, void *pParam) { - IDirectMusicPerformance8Impl *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); FIXME("(%p, %s, %ld, %ld, %ld, %ld, %p, %p): stub\n", This, debugstr_dmguid(rguidType), dwTrackID, dwGroupBits, dwIndex, mtTime, pmtNext, pParam); @@ -1249,7 +1250,7 @@ static const IDirectMusicPerformance8Vtbl performance_vtbl = /* for ClassFactory */ HRESULT create_dmperformance(REFIID iid, void **ret_iface) { - IDirectMusicPerformance8Impl *obj; + struct performance *obj; HRESULT hr; TRACE("(%s, %p)\n", debugstr_guid(iid), ret_iface); @@ -1261,7 +1262,7 @@ HRESULT create_dmperformance(REFIID iid, void **ret_iface) obj->pDefaultPath = NULL; InitializeCriticalSection(&obj->safe); - obj->safe.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectMusicPerformance8Impl*->safe"); + obj->safe.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": performance->safe"); wine_rb_init(&obj->pchannels, pchannel_block_compare); obj->rtLatencyTime = 100; /* 100 ms TO FIX */ From 66785e1d7555c5947e0a65729c4ea4561cf52633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 21:59:03 +0200 Subject: [PATCH 2479/2777] dmime: Fix indentation in IDirectMusicPerformance_QueryInterface. (cherry picked from commit e5ae7f90eebc5618385afaf539157be8110a8512) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index d6f7e76686e..a185716761d 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -252,21 +252,23 @@ static inline struct performance *impl_from_IDirectMusicPerformance8(IDirectMusi } /* IDirectMusicPerformance8 IUnknown part: */ -static HRESULT WINAPI performance_QueryInterface(IDirectMusicPerformance8 *iface, REFIID riid, void **ppv) +static HRESULT WINAPI performance_QueryInterface(IDirectMusicPerformance8 *iface, REFIID riid, void **ret_iface) { - TRACE("(%p, %s,%p)\n", iface, debugstr_dmguid(riid), ppv); - - if (IsEqualIID (riid, &IID_IUnknown) || - IsEqualIID (riid, &IID_IDirectMusicPerformance) || - IsEqualIID (riid, &IID_IDirectMusicPerformance2) || - IsEqualIID (riid, &IID_IDirectMusicPerformance8)) { - *ppv = iface; - IUnknown_AddRef(iface); - return S_OK; - } + TRACE("(%p, %s, %p)\n", iface, debugstr_dmguid(riid), ret_iface); + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDirectMusicPerformance) + || IsEqualGUID(riid, &IID_IDirectMusicPerformance2) + || IsEqualGUID(riid, &IID_IDirectMusicPerformance8)) + { + *ret_iface = iface; + IUnknown_AddRef(iface); + return S_OK; + } - WARN("(%p, %s,%p): not found\n", iface, debugstr_dmguid(riid), ppv); - return E_NOINTERFACE; + *ret_iface = NULL; + WARN("(%p, %s, %p): not found\n", iface, debugstr_dmguid(riid), ret_iface); + return E_NOINTERFACE; } static ULONG WINAPI performance_AddRef(IDirectMusicPerformance8 *iface) From 21ebd922191dfc889e1456e75b990f0497ebcb18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 21:50:46 +0200 Subject: [PATCH 2480/2777] dmime: Add a IDirectMusicGraph interface to the performance. (cherry picked from commit 2e25af4fd3e7cd618b2080502c429446e35d4666) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 74 ++++++++++++++++++++++++++++++++++ dlls/dmime/tests/dmime.c | 22 ++++------ dlls/dmime/tests/performance.c | 2 +- 3 files changed, 83 insertions(+), 15 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index a185716761d..887d9a7bf16 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -37,6 +37,7 @@ struct pchannel_block { struct performance { IDirectMusicPerformance8 IDirectMusicPerformance8_iface; + IDirectMusicGraph IDirectMusicGraph_iface; LONG ref; IDirectMusic8 *dmusic; IDirectSound *dsound; @@ -254,6 +255,8 @@ static inline struct performance *impl_from_IDirectMusicPerformance8(IDirectMusi /* IDirectMusicPerformance8 IUnknown part: */ static HRESULT WINAPI performance_QueryInterface(IDirectMusicPerformance8 *iface, REFIID riid, void **ret_iface) { + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + TRACE("(%p, %s, %p)\n", iface, debugstr_dmguid(riid), ret_iface); if (IsEqualGUID(riid, &IID_IUnknown) @@ -266,6 +269,13 @@ static HRESULT WINAPI performance_QueryInterface(IDirectMusicPerformance8 *iface return S_OK; } + if (IsEqualGUID(riid, &IID_IDirectMusicGraph)) + { + *ret_iface = &This->IDirectMusicGraph_iface; + IDirectMusicGraph_AddRef(&This->IDirectMusicGraph_iface); + return S_OK; + } + *ret_iface = NULL; WARN("(%p, %s, %p): not found\n", iface, debugstr_dmguid(riid), ret_iface); return E_NOINTERFACE; @@ -1249,6 +1259,69 @@ static const IDirectMusicPerformance8Vtbl performance_vtbl = performance_GetParamEx, }; +static inline struct performance *impl_from_IDirectMusicGraph(IDirectMusicGraph *iface) +{ + return CONTAINING_RECORD(iface, struct performance, IDirectMusicGraph_iface); +} + +static HRESULT WINAPI performance_graph_QueryInterface(IDirectMusicGraph *iface, REFIID riid, void **ret_iface) +{ + struct performance *This = impl_from_IDirectMusicGraph(iface); + return IDirectMusicPerformance8_QueryInterface(&This->IDirectMusicPerformance8_iface, riid, ret_iface); +} + +static ULONG WINAPI performance_graph_AddRef(IDirectMusicGraph *iface) +{ + struct performance *This = impl_from_IDirectMusicGraph(iface); + return IDirectMusicPerformance8_AddRef(&This->IDirectMusicPerformance8_iface); +} + +static ULONG WINAPI performance_graph_Release(IDirectMusicGraph *iface) +{ + struct performance *This = impl_from_IDirectMusicGraph(iface); + return IDirectMusicPerformance8_Release(&This->IDirectMusicPerformance8_iface); +} + +static HRESULT WINAPI performance_graph_StampPMsg(IDirectMusicGraph *iface, DMUS_PMSG *msg) +{ + struct performance *This = impl_from_IDirectMusicGraph(iface); + FIXME("(%p, %p): stub\n", This, msg); + return E_NOTIMPL; +} + +static HRESULT WINAPI performance_graph_InsertTool(IDirectMusicGraph *iface, IDirectMusicTool *tool, + DWORD *channels, DWORD channels_count, LONG index) +{ + struct performance *This = impl_from_IDirectMusicGraph(iface); + FIXME("(%p, %p, %p, %lu, %ld): stub\n", This, tool, channels, channels_count, index); + return E_NOTIMPL; +} + +static HRESULT WINAPI performance_graph_GetTool(IDirectMusicGraph *iface, DWORD index, IDirectMusicTool **tool) +{ + struct performance *This = impl_from_IDirectMusicGraph(iface); + FIXME("(%p, %lu, %p): stub\n", This, index, tool); + return E_NOTIMPL; +} + +static HRESULT WINAPI performance_graph_RemoveTool(IDirectMusicGraph *iface, IDirectMusicTool *tool) +{ + struct performance *This = impl_from_IDirectMusicGraph(iface); + FIXME("(%p, %p): stub\n", This, tool); + return E_NOTIMPL; +} + +static const IDirectMusicGraphVtbl performance_graph_vtbl = +{ + performance_graph_QueryInterface, + performance_graph_AddRef, + performance_graph_Release, + performance_graph_StampPMsg, + performance_graph_InsertTool, + performance_graph_GetTool, + performance_graph_RemoveTool, +}; + /* for ClassFactory */ HRESULT create_dmperformance(REFIID iid, void **ret_iface) { @@ -1260,6 +1333,7 @@ HRESULT create_dmperformance(REFIID iid, void **ret_iface) *ret_iface = NULL; if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicPerformance8_iface.lpVtbl = &performance_vtbl; + obj->IDirectMusicGraph_iface.lpVtbl = &performance_graph_vtbl; obj->ref = 1; obj->pDefaultPath = NULL; diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index e95a1c02427..6dcb2b820c9 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -1536,8 +1536,7 @@ static void test_performance_graph(void) /* performance exposes a graph interface but it's not an actual toolgraph */ hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - if (hr != S_OK) goto skip_graph; + ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1); ok(hr == E_NOTIMPL, "got %#lx\n", hr); hr = IDirectMusicGraph_GetTool(graph, 0, &tmp_tool); @@ -1578,7 +1577,6 @@ static void test_performance_graph(void) IDirectMusicGraph_Release(graph); -skip_graph: /* performance doesn't have a default embedded toolgraph */ hr = IDirectMusicPerformance_GetGraph(performance, &graph); ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); @@ -1604,8 +1602,7 @@ static void test_performance_graph(void) /* test IDirectMusicGraph_StampPMsg usage */ hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - if (hr != S_OK) goto skip_graph2; + ok(hr == S_OK, "got %#lx\n", hr); memset(&msg, 0, sizeof(msg)); hr = IDirectMusicGraph_StampPMsg(graph, &msg); @@ -1636,7 +1633,6 @@ static void test_performance_graph(void) IDirectMusicGraph_Release(graph); -skip_graph2: IDirectMusicPerformance_Release(performance); IDirectMusicTool_Release(tool); } @@ -1874,12 +1870,11 @@ static void test_performance_pmsg(void) msg->dwFlags = DMUS_PMSGF_REFTIME; msg->dwType = DMUS_PMSGT_USER; - graph = NULL; hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicGraph_StampPMsg(graph, msg); todo_wine ok(hr == S_OK, "got %#lx\n", hr); - if (graph) hr = IDirectMusicGraph_StampPMsg(graph, msg); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - if (graph) IDirectMusicGraph_Release(graph); + IDirectMusicGraph_Release(graph); hr = IDirectMusicPerformance_SendPMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); @@ -1906,11 +1901,10 @@ static void test_performance_pmsg(void) msg->dwType = DMUS_PMSGT_USER; hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - if (!graph) hr = S_OK; - else hr = IDirectMusicGraph_StampPMsg(graph, msg); ok(hr == S_OK, "got %#lx\n", hr); - if (graph) IDirectMusicGraph_Release(graph); + hr = IDirectMusicGraph_StampPMsg(graph, msg); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicGraph_Release(graph); msg->dwFlags &= ~(DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME); msg->dwFlags |= delivery_flags[i]; diff --git a/dlls/dmime/tests/performance.c b/dlls/dmime/tests/performance.c index 4af91fc3130..5cb91a78387 100644 --- a/dlls/dmime/tests/performance.c +++ b/dlls/dmime/tests/performance.c @@ -627,7 +627,7 @@ static void test_performance_graph(void) ok(graph2 == NULL, "unexpected pointer.\n"); hr = IDirectMusicPerformance8_QueryInterface(perf, &IID_IDirectMusicGraph, (void**)&graph); - todo_wine ok(hr == S_OK, "Failed: %#lx\n", hr); + ok(hr == S_OK, "Failed: %#lx\n", hr); if (graph) IDirectMusicGraph_Release(graph); From 4e0ce65150c5009ad2bba5d88ccea57c8590878e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 21:56:20 +0200 Subject: [PATCH 2481/2777] dmime: Add a IDirectMusicTool interface to the performance. (cherry picked from commit 428eb3e87c863fd391f2b5b91a8d67036cd21120) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 89 ++++++++++++++++++++++++++++++++++++++++ dlls/dmime/tests/dmime.c | 6 +-- 2 files changed, 91 insertions(+), 4 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 887d9a7bf16..1f8de0837d5 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -38,6 +38,7 @@ struct performance { IDirectMusicPerformance8 IDirectMusicPerformance8_iface; IDirectMusicGraph IDirectMusicGraph_iface; + IDirectMusicTool IDirectMusicTool_iface; LONG ref; IDirectMusic8 *dmusic; IDirectSound *dsound; @@ -276,6 +277,13 @@ static HRESULT WINAPI performance_QueryInterface(IDirectMusicPerformance8 *iface return S_OK; } + if (IsEqualGUID(riid, &IID_IDirectMusicTool)) + { + *ret_iface = &This->IDirectMusicTool_iface; + IDirectMusicTool_AddRef(&This->IDirectMusicTool_iface); + return S_OK; + } + *ret_iface = NULL; WARN("(%p, %s, %p): not found\n", iface, debugstr_dmguid(riid), ret_iface); return E_NOINTERFACE; @@ -1322,6 +1330,86 @@ static const IDirectMusicGraphVtbl performance_graph_vtbl = performance_graph_RemoveTool, }; +static inline struct performance *impl_from_IDirectMusicTool(IDirectMusicTool *iface) +{ + return CONTAINING_RECORD(iface, struct performance, IDirectMusicTool_iface); +} + +static HRESULT WINAPI performance_tool_QueryInterface(IDirectMusicTool *iface, REFIID riid, void **ret_iface) +{ + struct performance *This = impl_from_IDirectMusicTool(iface); + return IDirectMusicPerformance8_QueryInterface(&This->IDirectMusicPerformance8_iface, riid, ret_iface); +} + +static ULONG WINAPI performance_tool_AddRef(IDirectMusicTool *iface) +{ + struct performance *This = impl_from_IDirectMusicTool(iface); + return IDirectMusicPerformance8_AddRef(&This->IDirectMusicPerformance8_iface); +} + +static ULONG WINAPI performance_tool_Release(IDirectMusicTool *iface) +{ + struct performance *This = impl_from_IDirectMusicTool(iface); + return IDirectMusicPerformance8_Release(&This->IDirectMusicPerformance8_iface); +} + +static HRESULT WINAPI performance_tool_Init(IDirectMusicTool *iface, IDirectMusicGraph *graph) +{ + struct performance *This = impl_from_IDirectMusicTool(iface); + FIXME("(%p, %p): stub\n", This, graph); + return E_NOTIMPL; +} + +static HRESULT WINAPI performance_tool_GetMsgDeliveryType(IDirectMusicTool *iface, DWORD *type) +{ + struct performance *This = impl_from_IDirectMusicTool(iface); + FIXME("(%p, %p): stub\n", This, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI performance_tool_GetMediaTypeArraySize(IDirectMusicTool *iface, DWORD *size) +{ + struct performance *This = impl_from_IDirectMusicTool(iface); + FIXME("(%p, %p): stub\n", This, size); + return E_NOTIMPL; +} + +static HRESULT WINAPI performance_tool_GetMediaTypes(IDirectMusicTool *iface, DWORD **types, DWORD size) +{ + struct performance *This = impl_from_IDirectMusicTool(iface); + FIXME("(%p, %p, %lu): stub\n", This, types, size); + return E_NOTIMPL; +} + +static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, + IDirectMusicPerformance *performance, DMUS_PMSG *msg) +{ + struct performance *This = impl_from_IDirectMusicTool(iface); + FIXME("(%p, %p, %p): stub\n", This, performance, msg); + return E_NOTIMPL; +} + +static HRESULT WINAPI performance_tool_Flush(IDirectMusicTool *iface, + IDirectMusicPerformance *performance, DMUS_PMSG *msg, REFERENCE_TIME time) +{ + struct performance *This = impl_from_IDirectMusicTool(iface); + FIXME("(%p, %p, %p, %I64d): stub\n", This, performance, msg, time); + return E_NOTIMPL; +} + +static const IDirectMusicToolVtbl performance_tool_vtbl = +{ + performance_tool_QueryInterface, + performance_tool_AddRef, + performance_tool_Release, + performance_tool_Init, + performance_tool_GetMsgDeliveryType, + performance_tool_GetMediaTypeArraySize, + performance_tool_GetMediaTypes, + performance_tool_ProcessPMsg, + performance_tool_Flush, +}; + /* for ClassFactory */ HRESULT create_dmperformance(REFIID iid, void **ret_iface) { @@ -1334,6 +1422,7 @@ HRESULT create_dmperformance(REFIID iid, void **ret_iface) if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicPerformance8_iface.lpVtbl = &performance_vtbl; obj->IDirectMusicGraph_iface.lpVtbl = &performance_graph_vtbl; + obj->IDirectMusicTool_iface.lpVtbl = &performance_tool_vtbl; obj->ref = 1; obj->pDefaultPath = NULL; diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 6dcb2b820c9..0aeed24b200 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -1489,10 +1489,9 @@ static void test_performance_tool(void) check_interface(performance, &IID_IDirectMusicTool8, FALSE); hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicTool, (void **)&tool); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - if (hr != S_OK) goto skip_tool; + ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicTool_Init(tool, graph); ok(hr == E_NOTIMPL, "got %#lx\n", hr); @@ -1514,7 +1513,6 @@ static void test_performance_tool(void) IDirectMusicGraph_Release(graph); IDirectMusicTool_Release(tool); -skip_tool: IDirectMusicPerformance_Release(performance); } From 4e3cf4620ada9ba50405dc3768e5a29f387a64d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Aug 2023 17:51:00 +0200 Subject: [PATCH 2482/2777] dmband: Always return S_FALSE from DllCanUnloadNow. (cherry picked from commit c3ebc387f38815748bbc1b01199baa9ea44eb04a) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/band.c | 2 -- dlls/dmband/bandtrack.c | 2 -- dlls/dmband/dmband_main.c | 22 ---------------------- dlls/dmband/dmband_private.h | 8 -------- 4 files changed, 34 deletions(-) diff --git a/dlls/dmband/band.c b/dlls/dmband/band.c index d71863a1f9d..907377ebed5 100644 --- a/dlls/dmband/band.c +++ b/dlls/dmband/band.c @@ -83,7 +83,6 @@ static ULONG WINAPI IDirectMusicBandImpl_Release(IDirectMusicBand *iface) if (!ref) { HeapFree(GetProcessHeap(), 0, This); - DMBAND_UnlockModule(); } return ref; @@ -527,7 +526,6 @@ HRESULT create_dmband(REFIID lpcGUID, void **ppobj) obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; list_init (&obj->Instruments); - DMBAND_LockModule(); hr = IDirectMusicBand_QueryInterface(&obj->IDirectMusicBand_iface, lpcGUID, ppobj); IDirectMusicBand_Release(&obj->IDirectMusicBand_iface); diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index 0142b5b5188..25aca207612 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -82,7 +82,6 @@ static ULONG WINAPI band_track_Release(IDirectMusicTrack8 *iface) if (!ref) { HeapFree(GetProcessHeap(), 0, This); - DMBAND_UnlockModule(); } return ref; @@ -650,7 +649,6 @@ HRESULT create_dmbandtrack(REFIID lpcGUID, void **ppobj) track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; list_init (&track->Bands); - DMBAND_LockModule(); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); diff --git a/dlls/dmband/dmband_main.c b/dlls/dmband/dmband_main.c index c08f8b0a087..c032a931f31 100644 --- a/dlls/dmband/dmband_main.c +++ b/dlls/dmband/dmband_main.c @@ -23,8 +23,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmband); -LONG DMBAND_refCount = 0; - typedef struct { IClassFactory IClassFactory_iface; HRESULT (*fnCreateInstance)(REFIID riid, void **ret_iface); @@ -60,15 +58,11 @@ static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID r static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) { - DMBAND_LockModule(); - return 2; /* non-heap based object */ } static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) { - DMBAND_UnlockModule(); - return 1; /* non-heap based object */ } @@ -90,12 +84,6 @@ static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock) { TRACE("(%d)\n", dolock); - - if (dolock) - DMBAND_LockModule(); - else - DMBAND_UnlockModule(); - return S_OK; } @@ -110,16 +98,6 @@ static const IClassFactoryVtbl classfactory_vtbl = { static IClassFactoryImpl Band_CF = {{&classfactory_vtbl}, create_dmband}; static IClassFactoryImpl BandTrack_CF = {{&classfactory_vtbl}, create_dmbandtrack}; -/****************************************************************** - * DllCanUnloadNow (DMBAND.@) - * - * - */ -HRESULT WINAPI DllCanUnloadNow(void) -{ - return DMBAND_refCount != 0 ? S_FALSE : S_OK; -} - /****************************************************************** * DllGetClassObject (DMBAND.@) diff --git a/dlls/dmband/dmband_private.h b/dlls/dmband/dmband_private.h index b89dd08dd83..0b1807eaf93 100644 --- a/dlls/dmband/dmband_private.h +++ b/dlls/dmband/dmband_private.h @@ -73,14 +73,6 @@ typedef struct _DMUS_PRIVATE_BAND { IDirectMusicBand *band; } DMUS_PRIVATE_BAND, *LPDMUS_PRIVATE_BAND; - -/********************************************************************** - * Dll lifetime tracking declaration for dmband.dll - */ -extern LONG DMBAND_refCount; -static inline void DMBAND_LockModule(void) { InterlockedIncrement( &DMBAND_refCount ); } -static inline void DMBAND_UnlockModule(void) { InterlockedDecrement( &DMBAND_refCount ); } - /***************************************************************************** * Misc. */ From d01f25ad6b98fbe40146cd28444ec614d3177f2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 9 Sep 2023 09:16:50 +0200 Subject: [PATCH 2483/2777] dmband: Use CRT allocation functions. (cherry picked from commit b60ee21fb2d657d2bf848925dfb8464bca6f0d9f) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/band.c | 20 +++++--------------- dlls/dmband/bandtrack.c | 18 +++++------------- dlls/dmband/dmobject.c | 7 +++---- 3 files changed, 13 insertions(+), 32 deletions(-) diff --git a/dlls/dmband/band.c b/dlls/dmband/band.c index 907377ebed5..02e3573bab9 100644 --- a/dlls/dmband/band.c +++ b/dlls/dmband/band.c @@ -81,9 +81,7 @@ static ULONG WINAPI IDirectMusicBandImpl_Release(IDirectMusicBand *iface) TRACE("(%p) ref=%ld\n", This, ref); - if (!ref) { - HeapFree(GetProcessHeap(), 0, This); - } + if (!ref) free(This); return ref; } @@ -277,11 +275,7 @@ static HRESULT parse_instrument(IDirectMusicBandImpl *This, DMUS_PRIVATE_CHUNK * /* * @TODO insert pNewInstrument into This */ - pNewInstrument = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_INSTRUMENT)); - if (NULL == pNewInstrument) { - ERR(": no more memory\n"); - return E_OUTOFMEMORY; - } + if (!(pNewInstrument = calloc(1, sizeof(*pNewInstrument)))) return E_OUTOFMEMORY; memcpy(&pNewInstrument->pInstrument, &inst, sizeof(DMUS_IO_INSTRUMENT)); pNewInstrument->ppReferenceCollection = NULL; if (NULL != pObject) { @@ -289,8 +283,7 @@ static HRESULT parse_instrument(IDirectMusicBandImpl *This, DMUS_PRIVATE_CHUNK * hr = IDirectMusicObject_QueryInterface (pObject, &IID_IDirectMusicCollection, (void**) &pCol); if (FAILED(hr)) { ERR(": failed to get IDirectMusicCollection Interface from DMObject\n"); - HeapFree(GetProcessHeap(), 0, pNewInstrument); - + free(pNewInstrument); return hr; } pNewInstrument->ppReferenceCollection = pCol; @@ -514,11 +507,8 @@ HRESULT create_dmband(REFIID lpcGUID, void **ppobj) IDirectMusicBandImpl* obj; HRESULT hr; - obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicBandImpl)); - if (NULL == obj) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicBand_iface.lpVtbl = &dmband_vtbl; obj->ref = 1; dmobject_init(&obj->dmobj, &CLSID_DirectMusicBand, (IUnknown *)&obj->IDirectMusicBand_iface); diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index 25aca207612..bdb9344b064 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -80,9 +80,7 @@ static ULONG WINAPI band_track_Release(IDirectMusicTrack8 *iface) TRACE("(%p) ref=%ld\n", This, ref); - if (!ref) { - HeapFree(GetProcessHeap(), 0, This); - } + if (!ref) free(This); return ref; } @@ -344,11 +342,8 @@ static HRESULT load_band(IDirectMusicBandTrack *This, IStream *pClonedStream, * @TODO insert pBand into This */ if (SUCCEEDED(hr)) { - LPDMUS_PRIVATE_BAND pNewBand = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_BAND)); - if (NULL == pNewBand) { - ERR(": no more memory\n"); - return E_OUTOFMEMORY; - } + LPDMUS_PRIVATE_BAND pNewBand; + if (!(pNewBand = calloc(1, sizeof(*pNewBand)))) return E_OUTOFMEMORY; pNewBand->BandHeader = *pHeader; pNewBand->band = *ppBand; IDirectMusicBand_AddRef(*ppBand); @@ -637,11 +632,8 @@ HRESULT create_dmbandtrack(REFIID lpcGUID, void **ppobj) IDirectMusicBandTrack *track; HRESULT hr; - track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicBandTrack, diff --git a/dlls/dmband/dmobject.c b/dlls/dmband/dmobject.c index b526b23d031..07d887a376c 100644 --- a/dlls/dmband/dmobject.c +++ b/dlls/dmband/dmobject.c @@ -28,7 +28,6 @@ #include "dmusics.h" #include "dmobject.h" #include "wine/debug.h" -#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(dmobj); WINE_DECLARE_DEBUG_CHANNEL(dmfile); @@ -375,7 +374,7 @@ HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) /* Reads chunk data of the form: DWORD - size of array element element[] - Array of elements - The caller needs to heap_free() the array. + The caller needs to free() the array. */ HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, unsigned int *count, DWORD elem_size) @@ -400,10 +399,10 @@ HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, *count = (chunk->size - sizeof(DWORD)) / elem_size; size = *count * elem_size; - if (!(*array = heap_alloc(size))) + if (!(*array = malloc(size))) return E_OUTOFMEMORY; if (FAILED(hr = stream_read(stream, *array, size))) { - heap_free(*array); + free(*array); *array = NULL; return hr; } From 8d133674ab8568050c5f601de80c7758dc58f649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 30 Aug 2023 19:57:16 +0200 Subject: [PATCH 2484/2777] dmband: Use PARENTSRC with dmusic. (cherry picked from commit 649de392194c83841b2e6f0c03a34c3b370ebf2a) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/Makefile.in | 1 + dlls/dmband/dmobject.c | 732 ---------------------------------------- dlls/dmband/dmobject.h | 124 ------- 3 files changed, 1 insertion(+), 856 deletions(-) delete mode 100644 dlls/dmband/dmobject.c delete mode 100644 dlls/dmband/dmobject.h diff --git a/dlls/dmband/Makefile.in b/dlls/dmband/Makefile.in index 6fa1502f6b0..ef6b6a44c60 100644 --- a/dlls/dmband/Makefile.in +++ b/dlls/dmband/Makefile.in @@ -1,5 +1,6 @@ MODULE = dmband.dll IMPORTS = dxguid uuid ole32 advapi32 +PARENTSRC = ../dmusic C_SRCS = \ band.c \ diff --git a/dlls/dmband/dmobject.c b/dlls/dmband/dmobject.c deleted file mode 100644 index 07d887a376c..00000000000 --- a/dlls/dmband/dmobject.c +++ /dev/null @@ -1,732 +0,0 @@ -/* - * Base IDirectMusicObject Implementation - * Keep in sync with the master in dlls/dmusic/dmobject.c - * - * Copyright (C) 2003-2004 Rok Mandeljc - * Copyright (C) 2014 Michael Stefaniuc - * - * This program 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 program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define COBJMACROS -#include -#include "objbase.h" -#include "dmusici.h" -#include "dmusicf.h" -#include "dmusics.h" -#include "dmobject.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dmobj); -WINE_DECLARE_DEBUG_CHANNEL(dmfile); - -/* Debugging helpers */ -const char *debugstr_dmguid(const GUID *id) { - unsigned int i; -#define X(guid) { &guid, #guid } - static const struct { - const GUID *guid; - const char *name; - } guids[] = { - /* CLSIDs */ - X(CLSID_AudioVBScript), - X(CLSID_DirectMusic), - X(CLSID_DirectMusicAudioPathConfig), - X(CLSID_DirectMusicAuditionTrack), - X(CLSID_DirectMusicBand), - X(CLSID_DirectMusicBandTrack), - X(CLSID_DirectMusicChordMapTrack), - X(CLSID_DirectMusicChordMap), - X(CLSID_DirectMusicChordTrack), - X(CLSID_DirectMusicCollection), - X(CLSID_DirectMusicCommandTrack), - X(CLSID_DirectMusicComposer), - X(CLSID_DirectMusicContainer), - X(CLSID_DirectMusicGraph), - X(CLSID_DirectMusicLoader), - X(CLSID_DirectMusicLyricsTrack), - X(CLSID_DirectMusicMarkerTrack), - X(CLSID_DirectMusicMelodyFormulationTrack), - X(CLSID_DirectMusicMotifTrack), - X(CLSID_DirectMusicMuteTrack), - X(CLSID_DirectMusicParamControlTrack), - X(CLSID_DirectMusicPatternTrack), - X(CLSID_DirectMusicPerformance), - X(CLSID_DirectMusicScript), - X(CLSID_DirectMusicScriptAutoImpSegment), - X(CLSID_DirectMusicScriptAutoImpPerformance), - X(CLSID_DirectMusicScriptAutoImpSegmentState), - X(CLSID_DirectMusicScriptAutoImpAudioPathConfig), - X(CLSID_DirectMusicScriptAutoImpAudioPath), - X(CLSID_DirectMusicScriptAutoImpSong), - X(CLSID_DirectMusicScriptSourceCodeLoader), - X(CLSID_DirectMusicScriptTrack), - X(CLSID_DirectMusicSection), - X(CLSID_DirectMusicSegment), - X(CLSID_DirectMusicSegmentState), - X(CLSID_DirectMusicSegmentTriggerTrack), - X(CLSID_DirectMusicSegTriggerTrack), - X(CLSID_DirectMusicSeqTrack), - X(CLSID_DirectMusicSignPostTrack), - X(CLSID_DirectMusicSong), - X(CLSID_DirectMusicStyle), - X(CLSID_DirectMusicStyleTrack), - X(CLSID_DirectMusicSynth), - X(CLSID_DirectMusicSynthSink), - X(CLSID_DirectMusicSysExTrack), - X(CLSID_DirectMusicTemplate), - X(CLSID_DirectMusicTempoTrack), - X(CLSID_DirectMusicTimeSigTrack), - X(CLSID_DirectMusicWaveTrack), - X(CLSID_DirectSoundWave), - /* IIDs */ - X(IID_IDirectMusic), - X(IID_IDirectMusic2), - X(IID_IDirectMusic8), - X(IID_IDirectMusicAudioPath), - X(IID_IDirectMusicBand), - X(IID_IDirectMusicBuffer), - X(IID_IDirectMusicChordMap), - X(IID_IDirectMusicCollection), - X(IID_IDirectMusicComposer), - X(IID_IDirectMusicContainer), - X(IID_IDirectMusicDownload), - X(IID_IDirectMusicDownloadedInstrument), - X(IID_IDirectMusicGetLoader), - X(IID_IDirectMusicGraph), - X(IID_IDirectMusicInstrument), - X(IID_IDirectMusicLoader), - X(IID_IDirectMusicLoader8), - X(IID_IDirectMusicObject), - X(IID_IDirectMusicPatternTrack), - X(IID_IDirectMusicPerformance), - X(IID_IDirectMusicPerformance2), - X(IID_IDirectMusicPerformance8), - X(IID_IDirectMusicPort), - X(IID_IDirectMusicPortDownload), - X(IID_IDirectMusicScript), - X(IID_IDirectMusicSegment), - X(IID_IDirectMusicSegment2), - X(IID_IDirectMusicSegment8), - X(IID_IDirectMusicSegmentState), - X(IID_IDirectMusicSegmentState8), - X(IID_IDirectMusicStyle), - X(IID_IDirectMusicStyle8), - X(IID_IDirectMusicSynth), - X(IID_IDirectMusicSynth8), - X(IID_IDirectMusicSynthSink), - X(IID_IDirectMusicThru), - X(IID_IDirectMusicTool), - X(IID_IDirectMusicTool8), - X(IID_IDirectMusicTrack), - X(IID_IDirectMusicTrack8), - X(IID_IUnknown), - X(IID_IPersistStream), - X(IID_IStream), - X(IID_IClassFactory), - /* GUIDs */ - X(GUID_DirectMusicAllTypes), - X(GUID_NOTIFICATION_CHORD), - X(GUID_NOTIFICATION_COMMAND), - X(GUID_NOTIFICATION_MEASUREANDBEAT), - X(GUID_NOTIFICATION_PERFORMANCE), - X(GUID_NOTIFICATION_RECOMPOSE), - X(GUID_NOTIFICATION_SEGMENT), - X(GUID_BandParam), - X(GUID_ChordParam), - X(GUID_CommandParam), - X(GUID_CommandParam2), - X(GUID_CommandParamNext), - X(GUID_IDirectMusicBand), - X(GUID_IDirectMusicChordMap), - X(GUID_IDirectMusicStyle), - X(GUID_MuteParam), - X(GUID_Play_Marker), - X(GUID_RhythmParam), - X(GUID_TempoParam), - X(GUID_TimeSignature), - X(GUID_Valid_Start_Time), - X(GUID_Clear_All_Bands), - X(GUID_ConnectToDLSCollection), - X(GUID_Disable_Auto_Download), - X(GUID_DisableTempo), - X(GUID_DisableTimeSig), - X(GUID_Download), - X(GUID_DownloadToAudioPath), - X(GUID_Enable_Auto_Download), - X(GUID_EnableTempo), - X(GUID_EnableTimeSig), - X(GUID_IgnoreBankSelectForGM), - X(GUID_SeedVariations), - X(GUID_StandardMIDIFile), - X(GUID_Unload), - X(GUID_UnloadFromAudioPath), - X(GUID_Variations), - X(GUID_PerfMasterTempo), - X(GUID_PerfMasterVolume), - X(GUID_PerfMasterGrooveLevel), - X(GUID_PerfAutoDownload), - X(GUID_DefaultGMCollection), - X(GUID_Synth_Default), - X(GUID_Buffer_Reverb), - X(GUID_Buffer_EnvReverb), - X(GUID_Buffer_Stereo), - X(GUID_Buffer_3D_Dry), - X(GUID_Buffer_Mono), - X(GUID_DMUS_PROP_GM_Hardware), - X(GUID_DMUS_PROP_GS_Capable), - X(GUID_DMUS_PROP_GS_Hardware), - X(GUID_DMUS_PROP_DLS1), - X(GUID_DMUS_PROP_DLS2), - X(GUID_DMUS_PROP_Effects), - X(GUID_DMUS_PROP_INSTRUMENT2), - X(GUID_DMUS_PROP_LegacyCaps), - X(GUID_DMUS_PROP_MemorySize), - X(GUID_DMUS_PROP_SampleMemorySize), - X(GUID_DMUS_PROP_SamplePlaybackRate), - X(GUID_DMUS_PROP_SetSynthSink), - X(GUID_DMUS_PROP_SinkUsesDSound), - X(GUID_DMUS_PROP_SynthSink_DSOUND), - X(GUID_DMUS_PROP_SynthSink_WAVE), - X(GUID_DMUS_PROP_Volume), - X(GUID_DMUS_PROP_WavesReverb), - X(GUID_DMUS_PROP_WriteLatency), - X(GUID_DMUS_PROP_WritePeriod), - X(GUID_DMUS_PROP_XG_Capable), - X(GUID_DMUS_PROP_XG_Hardware) - }; -#undef X - - if (!id) - return "(null)"; - - for (i = 0; i < ARRAY_SIZE(guids); i++) - if (IsEqualGUID(id, guids[i].guid)) - return guids[i].name; - - return debugstr_guid(id); -} - -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc) -{ - if (!desc || !TRACE_ON(dmfile)) - return; - - TRACE_(dmfile)("DMUS_OBJECTDESC (%p):", desc); - TRACE_(dmfile)(" - dwSize = %lu\n", desc->dwSize); - -#define X(flag) if (desc->dwValidData & flag) TRACE_(dmfile)(#flag " ") - TRACE_(dmfile)(" - dwValidData = %#08lx ( ", desc->dwValidData); - X(DMUS_OBJ_OBJECT); - X(DMUS_OBJ_CLASS); - X(DMUS_OBJ_NAME); - X(DMUS_OBJ_CATEGORY); - X(DMUS_OBJ_FILENAME); - X(DMUS_OBJ_FULLPATH); - X(DMUS_OBJ_URL); - X(DMUS_OBJ_VERSION); - X(DMUS_OBJ_DATE); - X(DMUS_OBJ_LOADED); - X(DMUS_OBJ_MEMORY); - X(DMUS_OBJ_STREAM); - TRACE_(dmfile)(")\n"); -#undef X - - if (desc->dwValidData & DMUS_OBJ_CLASS) - TRACE_(dmfile)(" - guidClass = %s\n", debugstr_dmguid(&desc->guidClass)); - if (desc->dwValidData & DMUS_OBJ_OBJECT) - TRACE_(dmfile)(" - guidObject = %s\n", debugstr_guid(&desc->guidObject)); - - if (desc->dwValidData & DMUS_OBJ_DATE) { - SYSTEMTIME time; - FileTimeToSystemTime(&desc->ftDate, &time); - TRACE_(dmfile)(" - ftDate = \'%04u-%02u-%02u %02u:%02u:%02u\'\n", - time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond); - } - if (desc->dwValidData & DMUS_OBJ_VERSION) - TRACE_(dmfile)(" - vVersion = \'%u,%u,%u,%u\'\n", - HIWORD(desc->vVersion.dwVersionMS), LOWORD(desc->vVersion.dwVersionMS), - HIWORD(desc->vVersion.dwVersionLS), LOWORD(desc->vVersion.dwVersionLS)); - if (desc->dwValidData & DMUS_OBJ_NAME) - TRACE_(dmfile)(" - wszName = %s\n", debugstr_w(desc->wszName)); - if (desc->dwValidData & DMUS_OBJ_CATEGORY) - TRACE_(dmfile)(" - wszCategory = %s\n", debugstr_w(desc->wszCategory)); - if (desc->dwValidData & DMUS_OBJ_FILENAME) - TRACE_(dmfile)(" - wszFileName = %s\n", debugstr_w(desc->wszFileName)); - if (desc->dwValidData & DMUS_OBJ_MEMORY) - TRACE_(dmfile)(" - llMemLength = 0x%s - pbMemData = %p\n", - wine_dbgstr_longlong(desc->llMemLength), desc->pbMemData); - if (desc->dwValidData & DMUS_OBJ_STREAM) - TRACE_(dmfile)(" - pStream = %p\n", desc->pStream); -} - - -/* RIFF format parsing */ -#define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD)) - -const char *debugstr_chunk(const struct chunk_entry *chunk) -{ - const char *type = ""; - - if (!chunk) - return "(null)"; - if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST) - type = wine_dbg_sprintf("type %s, ", debugstr_fourcc(chunk->type)); - return wine_dbg_sprintf("%s chunk, %ssize %lu", debugstr_fourcc(chunk->id), type, chunk->size); -} - -static HRESULT stream_read(IStream *stream, void *data, ULONG size) -{ - ULONG read; - HRESULT hr; - - hr = IStream_Read(stream, data, size, &read); - if (FAILED(hr)) - TRACE_(dmfile)("IStream_Read failed: %#lx\n", hr); - else if (!read && read < size) { - /* All or nothing: Handle a partial read due to end of stream as an error */ - TRACE_(dmfile)("Short read: %lu < %lu\n", read, size); - return E_FAIL; - } - - return hr; -} - -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) -{ - static const LARGE_INTEGER zero; - ULONGLONG ck_end = 0, p_end = 0; - HRESULT hr; - - hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &chunk->offset); - if (FAILED(hr)) - return hr; - assert(!(chunk->offset.QuadPart & 1)); - if (chunk->parent) { - p_end = chunk->parent->offset.QuadPart + CHUNK_HDR_SIZE + ((chunk->parent->size + 1) & ~1); - if (chunk->offset.QuadPart == p_end) - return S_FALSE; - ck_end = chunk->offset.QuadPart + CHUNK_HDR_SIZE; - if (ck_end > p_end) { - WARN_(dmfile)("No space for sub-chunk header in parent chunk: ends at offset %s > %s\n", - wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end)); - return E_FAIL; - } - } - - hr = stream_read(stream, chunk, CHUNK_HDR_SIZE); - if (hr != S_OK) - return hr; - if (chunk->parent) { - ck_end += (chunk->size + 1) & ~1; - if (ck_end > p_end) { - WARN_(dmfile)("No space for sub-chunk data in parent chunk: ends at offset %s > %s\n", - wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end)); - return E_FAIL; - } - } - - if (chunk->id == FOURCC_LIST || chunk->id == FOURCC_RIFF) { - hr = stream_read(stream, &chunk->type, sizeof(FOURCC)); - if (hr != S_OK) - return hr != S_FALSE ? hr : E_FAIL; - } - - TRACE_(dmfile)("Returning %s\n", debugstr_chunk(chunk)); - - return S_OK; -} - -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER end; - - end.QuadPart = (chunk->offset.QuadPart + CHUNK_HDR_SIZE + chunk->size + 1) & ~(ULONGLONG)1; - - return IStream_Seek(stream, end, STREAM_SEEK_SET, NULL); -} - -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) -{ - HRESULT hr; - - if (chunk->id) { - hr = stream_skip_chunk(stream, chunk); - if (FAILED(hr)) - return hr; - } - - return stream_get_chunk(stream, chunk); -} - -/* Reads chunk data of the form: - DWORD - size of array element - element[] - Array of elements - The caller needs to free() the array. -*/ -HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size) -{ - DWORD size; - HRESULT hr; - - *array = NULL; - *count = 0; - - if (chunk->size < sizeof(DWORD)) { - WARN_(dmfile)("%s: Too short to read element size\n", debugstr_chunk(chunk)); - return E_FAIL; - } - if (FAILED(hr = stream_read(stream, &size, sizeof(DWORD)))) - return hr; - if (size != elem_size) { - WARN_(dmfile)("%s: Array element size mismatch: got %lu, expected %lu\n", - debugstr_chunk(chunk), size, elem_size); - return DMUS_E_UNSUPPORTED_STREAM; - } - - *count = (chunk->size - sizeof(DWORD)) / elem_size; - size = *count * elem_size; - if (!(*array = malloc(size))) - return E_OUTOFMEMORY; - if (FAILED(hr = stream_read(stream, *array, size))) { - free(*array); - *array = NULL; - return hr; - } - - if (chunk->size > size + sizeof(DWORD)) { - WARN_(dmfile)("%s: Extraneous data at end of array\n", debugstr_chunk(chunk)); - stream_skip_chunk(stream, chunk); - return S_FALSE; - } - return S_OK; -} - -HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size) -{ - if (chunk->size != size) { - WARN_(dmfile)("Chunk %s (size %lu, offset %s) doesn't contains the expected data size %lu\n", - debugstr_fourcc(chunk->id), chunk->size, - wine_dbgstr_longlong(chunk->offset.QuadPart), size); - return E_FAIL; - } - return stream_read(stream, data, size); -} - -HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size) -{ - ULONG len; - HRESULT hr; - - hr = IStream_Read(stream, str, min(chunk->size, size), &len); - if (FAILED(hr)) - return hr; - - /* Don't assume the string is properly zero terminated */ - str[min(len, size - 1)] = 0; - - if (len < chunk->size) - return S_FALSE; - return S_OK; -} - - - -/* Generic IDirectMusicObject methods */ -static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface) -{ - return CONTAINING_RECORD(iface, struct dmobject, IDirectMusicObject_iface); -} - -HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); -} - -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_AddRef(This->outer_unk); -} - -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_Release(This->outer_unk); -} - -HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - - TRACE("(%p/%p)->(%p)\n", iface, This, desc); - - if (!desc) - return E_POINTER; - - memcpy(desc, &This->desc, This->desc.dwSize); - - return S_OK; -} - -HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - HRESULT ret = S_OK; - - TRACE("(%p, %p)\n", iface, desc); - - if (!desc) - return E_POINTER; - - /* Immutable property */ - if (desc->dwValidData & DMUS_OBJ_CLASS) - { - desc->dwValidData &= ~DMUS_OBJ_CLASS; - ret = S_FALSE; - } - /* Set only valid fields */ - if (desc->dwValidData & DMUS_OBJ_OBJECT) - This->desc.guidObject = desc->guidObject; - if (desc->dwValidData & DMUS_OBJ_NAME) - lstrcpynW(This->desc.wszName, desc->wszName, DMUS_MAX_NAME); - if (desc->dwValidData & DMUS_OBJ_CATEGORY) - lstrcpynW(This->desc.wszCategory, desc->wszCategory, DMUS_MAX_CATEGORY); - if (desc->dwValidData & DMUS_OBJ_FILENAME) - lstrcpynW(This->desc.wszFileName, desc->wszFileName, DMUS_MAX_FILENAME); - if (desc->dwValidData & DMUS_OBJ_VERSION) - This->desc.vVersion = desc->vVersion; - if (desc->dwValidData & DMUS_OBJ_DATE) - This->desc.ftDate = desc->ftDate; - if (desc->dwValidData & DMUS_OBJ_MEMORY) { - This->desc.llMemLength = desc->llMemLength; - memcpy(This->desc.pbMemData, desc->pbMemData, desc->llMemLength); - } - if (desc->dwValidData & DMUS_OBJ_STREAM) - IStream_Clone(desc->pStream, &This->desc.pStream); - - This->desc.dwValidData |= desc->dwValidData; - - return ret; -} - -/* Helper for IDirectMusicObject::ParseDescriptor */ -static inline void info_get_name(IStream *stream, const struct chunk_entry *info, - DMUS_OBJECTDESC *desc) -{ - struct chunk_entry chunk = {.parent = info}; - char name[DMUS_MAX_NAME]; - ULONG len; - HRESULT hr = E_FAIL; - - while (stream_next_chunk(stream, &chunk) == S_OK) - if (chunk.id == mmioFOURCC('I','N','A','M')) - hr = IStream_Read(stream, name, min(chunk.size, sizeof(name)), &len); - - if (SUCCEEDED(hr)) { - len = MultiByteToWideChar(CP_ACP, 0, name, len, desc->wszName, sizeof(desc->wszName)); - desc->wszName[min(len, sizeof(desc->wszName) - 1)] = 0; - desc->dwValidData |= DMUS_OBJ_NAME; - } -} - -static inline void unfo_get_name(IStream *stream, const struct chunk_entry *unfo, - DMUS_OBJECTDESC *desc, BOOL inam) -{ - struct chunk_entry chunk = {.parent = unfo}; - - while (stream_next_chunk(stream, &chunk) == S_OK) - if (chunk.id == DMUS_FOURCC_UNAM_CHUNK || (inam && chunk.id == mmioFOURCC('I','N','A','M'))) - if (stream_chunk_get_wstr(stream, &chunk, desc->wszName, sizeof(desc->wszName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_NAME; -} - -HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported) -{ - struct chunk_entry chunk = {.parent = riff}; - HRESULT hr; - - TRACE("Looking for %#lx in %p: %s\n", supported, stream, debugstr_chunk(riff)); - - desc->dwValidData = 0; - desc->dwSize = sizeof(*desc); - - while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { - switch (chunk.id) { - case DMUS_FOURCC_CATEGORY_CHUNK: - if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk, - desc->wszCategory, sizeof(desc->wszCategory)) == S_OK) - desc->dwValidData |= DMUS_OBJ_CATEGORY; - break; - case DMUS_FOURCC_DATE_CHUNK: - if ((supported & DMUS_OBJ_DATE) && stream_chunk_get_data(stream, &chunk, - &desc->ftDate, sizeof(desc->ftDate)) == S_OK) - desc->dwValidData |= DMUS_OBJ_DATE; - break; - case DMUS_FOURCC_FILE_CHUNK: - if ((supported & DMUS_OBJ_FILENAME) && stream_chunk_get_wstr(stream, &chunk, - desc->wszFileName, sizeof(desc->wszFileName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_FILENAME; - break; - case DMUS_FOURCC_GUID_CHUNK: - if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk, - &desc->guidObject, sizeof(desc->guidObject)) == S_OK) - desc->dwValidData |= DMUS_OBJ_OBJECT; - break; - case DMUS_FOURCC_NAME_CHUNK: - if ((supported & DMUS_OBJ_NAME) && stream_chunk_get_wstr(stream, &chunk, - desc->wszName, sizeof(desc->wszName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_NAME; - break; - case DMUS_FOURCC_VERSION_CHUNK: - if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk, - &desc->vVersion, sizeof(desc->vVersion)) == S_OK) - desc->dwValidData |= DMUS_OBJ_VERSION; - break; - case FOURCC_LIST: - if (chunk.type == DMUS_FOURCC_UNFO_LIST && (supported & DMUS_OBJ_NAME)) - unfo_get_name(stream, &chunk, desc, supported & DMUS_OBJ_NAME_INAM); - else if (chunk.type == DMUS_FOURCC_INFO_LIST && (supported & DMUS_OBJ_NAME_INFO)) - info_get_name(stream, &chunk, desc); - break; - } - } - TRACE("Found %#lx\n", desc->dwValidData); - - return hr; -} - -HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj) -{ - struct chunk_entry chunk = {.parent = list}; - IDirectMusicGetLoader *getloader; - IDirectMusicLoader *loader; - DMUS_OBJECTDESC desc; - DMUS_IO_REFERENCE reference; - HRESULT hr; - - if (FAILED(hr = stream_next_chunk(stream, &chunk))) - return hr; - if (chunk.id != DMUS_FOURCC_REF_CHUNK) - return DMUS_E_UNSUPPORTED_STREAM; - - if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &reference, sizeof(reference)))) { - WARN("Failed to read data of %s\n", debugstr_chunk(&chunk)); - return hr; - } - TRACE("REFERENCE guidClassID %s, dwValidData %#lx\n", debugstr_dmguid(&reference.guidClassID), - reference.dwValidData); - - if (FAILED(hr = dmobj_parsedescriptor(stream, list, &desc, reference.dwValidData))) - return hr; - desc.guidClass = reference.guidClassID; - desc.dwValidData |= DMUS_OBJ_CLASS; - dump_DMUS_OBJECTDESC(&desc); - - if (FAILED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getloader))) - return hr; - hr = IDirectMusicGetLoader_GetLoader(getloader, &loader); - IDirectMusicGetLoader_Release(getloader); - if (FAILED(hr)) - return hr; - - hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicObject, (void**)dmobj); - IDirectMusicLoader_Release(loader); - - return hr; -} - -/* Generic IPersistStream methods */ -static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface) -{ - return CONTAINING_RECORD(iface, struct dmobject, IPersistStream_iface); -} - -HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); -} - -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_AddRef(This->outer_unk); -} - -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_Release(This->outer_unk); -} - -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - - TRACE("(%p, %p)\n", This, class); - - if (!class) - return E_POINTER; - - *class = This->desc.guidClass; - - return S_OK; -} - -/* IPersistStream methods not implemented in native */ -HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) -{ - TRACE("(%p, %p): method not implemented\n", iface, class); - return E_NOTIMPL; -} - -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface) -{ - TRACE("(%p): method not implemented, always returning S_FALSE\n", iface); - return S_FALSE; -} - -HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty) -{ - TRACE("(%p, %p, %d): method not implemented\n", iface, stream, clear_dirty); - return E_NOTIMPL; -} - -HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, ULARGE_INTEGER *size) -{ - TRACE("(%p, %p): method not implemented\n", iface, size); - return E_NOTIMPL; -} - - -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk) -{ - dmobj->outer_unk = outer_unk; - dmobj->desc.dwSize = sizeof(dmobj->desc); - dmobj->desc.dwValidData = DMUS_OBJ_CLASS; - dmobj->desc.guidClass = *class; -} diff --git a/dlls/dmband/dmobject.h b/dlls/dmband/dmobject.h deleted file mode 100644 index 772be015c80..00000000000 --- a/dlls/dmband/dmobject.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Base IDirectMusicObject Implementation - * Keep in sync with the master in dlls/dmusic/dmobject.h - * - * Copyright (C) 2014 Michael Stefaniuc - * - * This program 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 program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "wine/debug.h" - -/* RIFF stream parsing */ -struct chunk_entry; -struct chunk_entry { - FOURCC id; - DWORD size; - FOURCC type; /* valid only for LIST and RIFF chunks */ - ULARGE_INTEGER offset; /* chunk offset from start of stream */ - const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */ -}; - -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk); -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk); -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk); - -HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size); -HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size); -HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size); - -static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER offset; - - offset.QuadPart = chunk->offset.QuadPart + sizeof(FOURCC) + sizeof(DWORD); - if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST) - offset.QuadPart += sizeof(FOURCC); - - return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); -} - -static inline HRESULT stream_reset_chunk_start(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER offset; - - offset.QuadPart = chunk->offset.QuadPart; - - return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); -} - - -/* IDirectMusicObject base object */ -struct dmobject { - IDirectMusicObject IDirectMusicObject_iface; - IPersistStream IPersistStream_iface; - IUnknown *outer_unk; - DMUS_OBJECTDESC desc; -}; - -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk); - -/* Generic IDirectMusicObject methods */ -HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface); -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface); -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface); -HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc); -HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc); - -/* Helper for IDirectMusicObject::ParseDescriptor */ -HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported); -/* Additional supported flags for dmobj_parsedescriptor. - DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */ -#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */ -#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */ - -/* 'DMRF' (reference list) helper */ -HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj); - -/* Generic IPersistStream methods */ -HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface); -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface); -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface); -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class); - -/* IPersistStream methods not implemented in native */ -HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, - CLSID *class); -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface); -HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty); -HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, - ULARGE_INTEGER *size); - -/* Debugging helpers */ -const char *debugstr_chunk(const struct chunk_entry *chunk); -const char *debugstr_dmguid(const GUID *id); -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc); - -static inline const char *debugstr_fourcc(DWORD fourcc) -{ - if (!fourcc) return "''"; - return wine_dbg_sprintf("'%c%c%c%c'", (char)(fourcc), (char)(fourcc >> 8), - (char)(fourcc >> 16), (char)(fourcc >> 24)); -} From 443a8c653ba7c460d71da780bb83e69bfad8c31f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Aug 2023 17:36:49 +0200 Subject: [PATCH 2485/2777] dswave: Always return S_FALSE from DllCanUnloadNow. (cherry picked from commit 65f25a150fe19eb883cae89327960d63a22afab5) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dswave/dswave.c | 2 -- dlls/dswave/dswave_main.c | 23 ----------------------- dlls/dswave/dswave_private.h | 7 ------- 3 files changed, 32 deletions(-) diff --git a/dlls/dswave/dswave.c b/dlls/dswave/dswave.c index e6d85d738fe..8e06fc8d13d 100644 --- a/dlls/dswave/dswave.c +++ b/dlls/dswave/dswave.c @@ -86,7 +86,6 @@ static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface) if (!ref) { HeapFree(GetProcessHeap(), 0, This); - DSWAVE_UnlockModule(); } return ref; @@ -191,7 +190,6 @@ HRESULT create_dswave(REFIID lpcGUID, void **ppobj) obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl; obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - DSWAVE_LockModule(); hr = IUnknown_QueryInterface(&obj->IUnknown_iface, lpcGUID, ppobj); IUnknown_Release(&obj->IUnknown_iface); return hr; diff --git a/dlls/dswave/dswave_main.c b/dlls/dswave/dswave_main.c index 81dcc73de85..f2ce7bb950f 100644 --- a/dlls/dswave/dswave_main.c +++ b/dlls/dswave/dswave_main.c @@ -39,8 +39,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(dswave); -LONG DSWAVE_refCount = 0; - typedef struct { IClassFactory IClassFactory_iface; } IClassFactoryImpl; @@ -70,15 +68,11 @@ static HRESULT WINAPI WaveCF_QueryInterface(IClassFactory * iface, REFIID riid, static ULONG WINAPI WaveCF_AddRef(IClassFactory * iface) { - DSWAVE_LockModule(); - return 2; /* non-heap based object */ } static ULONG WINAPI WaveCF_Release(IClassFactory * iface) { - DSWAVE_UnlockModule(); - return 1; /* non-heap based object */ } @@ -98,12 +92,6 @@ static HRESULT WINAPI WaveCF_CreateInstance(IClassFactory * iface, IUnknown *out static HRESULT WINAPI WaveCF_LockServer(IClassFactory * iface, BOOL dolock) { TRACE("(%d)\n", dolock); - - if (dolock) - DSWAVE_LockModule(); - else - DSWAVE_UnlockModule(); - return S_OK; } @@ -117,17 +105,6 @@ static const IClassFactoryVtbl WaveCF_Vtbl = { static IClassFactoryImpl Wave_CF = {{&WaveCF_Vtbl}}; -/****************************************************************** - * DllCanUnloadNow (DSWAVE.@) - * - * - */ -HRESULT WINAPI DllCanUnloadNow(void) -{ - return DSWAVE_refCount != 0 ? S_FALSE : S_OK; -} - - /****************************************************************** * DllGetClassObject (DSWAVE.@) * diff --git a/dlls/dswave/dswave_private.h b/dlls/dswave/dswave_private.h index a7758a970bc..50406c676c1 100644 --- a/dlls/dswave/dswave_private.h +++ b/dlls/dswave/dswave_private.h @@ -44,11 +44,4 @@ */ extern HRESULT create_dswave(REFIID lpcGUID, void **ret_iface); -/********************************************************************** - * Dll lifetime tracking declaration for dswave.dll - */ -extern LONG DSWAVE_refCount; -static inline void DSWAVE_LockModule(void) { InterlockedIncrement( &DSWAVE_refCount ); } -static inline void DSWAVE_UnlockModule(void) { InterlockedDecrement( &DSWAVE_refCount ); } - #endif /* __WINE_DSWAVE_PRIVATE_H */ From 18b16714dd30f69c18a5b311071abbf584a1b702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 9 Sep 2023 09:30:46 +0200 Subject: [PATCH 2486/2777] dswave: Use CRT allocation functions. (cherry picked from commit 8bcaec25529104d1e53fdd1242cb5ae211db411e) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dswave/dswave.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/dlls/dswave/dswave.c b/dlls/dswave/dswave.c index 8e06fc8d13d..5bdd83dfa2c 100644 --- a/dlls/dswave/dswave.c +++ b/dlls/dswave/dswave.c @@ -84,9 +84,7 @@ static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface) TRACE("(%p) ref=%ld\n", This, ref); - if (!ref) { - HeapFree(GetProcessHeap(), 0, This); - } + if (!ref) free(This); return ref; } @@ -179,11 +177,8 @@ HRESULT create_dswave(REFIID lpcGUID, void **ppobj) IDirectMusicWaveImpl *obj; HRESULT hr; - obj = HeapAlloc(GetProcessHeap(), 0, sizeof(IDirectMusicWaveImpl)); - if (!obj) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IUnknown_iface.lpVtbl = &unknown_vtbl; obj->ref = 1; dmobject_init(&obj->dmobj, &CLSID_DirectSoundWave, &obj->IUnknown_iface); From 8dbadb832c66c3925801879aaa0cdcb415cb9a2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 30 Aug 2023 19:52:16 +0200 Subject: [PATCH 2487/2777] dswave: Use PARENTSRC with dmusic. (cherry picked from commit b27a036eaf9ca599e24d840f4b3aa0dab9a0040a) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dswave/Makefile.in | 1 + dlls/dswave/dmobject.c | 733 ---------------------------------------- dlls/dswave/dmobject.h | 124 ------- 3 files changed, 1 insertion(+), 857 deletions(-) delete mode 100644 dlls/dswave/dmobject.c delete mode 100644 dlls/dswave/dmobject.h diff --git a/dlls/dswave/Makefile.in b/dlls/dswave/Makefile.in index 9a08518397b..99b1e3ff9dc 100644 --- a/dlls/dswave/Makefile.in +++ b/dlls/dswave/Makefile.in @@ -1,5 +1,6 @@ MODULE = dswave.dll IMPORTS = dxguid uuid ole32 advapi32 +PARENTSRC = ../dmusic C_SRCS = \ dmobject.c \ diff --git a/dlls/dswave/dmobject.c b/dlls/dswave/dmobject.c deleted file mode 100644 index b526b23d031..00000000000 --- a/dlls/dswave/dmobject.c +++ /dev/null @@ -1,733 +0,0 @@ -/* - * Base IDirectMusicObject Implementation - * Keep in sync with the master in dlls/dmusic/dmobject.c - * - * Copyright (C) 2003-2004 Rok Mandeljc - * Copyright (C) 2014 Michael Stefaniuc - * - * This program 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 program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define COBJMACROS -#include -#include "objbase.h" -#include "dmusici.h" -#include "dmusicf.h" -#include "dmusics.h" -#include "dmobject.h" -#include "wine/debug.h" -#include "wine/heap.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dmobj); -WINE_DECLARE_DEBUG_CHANNEL(dmfile); - -/* Debugging helpers */ -const char *debugstr_dmguid(const GUID *id) { - unsigned int i; -#define X(guid) { &guid, #guid } - static const struct { - const GUID *guid; - const char *name; - } guids[] = { - /* CLSIDs */ - X(CLSID_AudioVBScript), - X(CLSID_DirectMusic), - X(CLSID_DirectMusicAudioPathConfig), - X(CLSID_DirectMusicAuditionTrack), - X(CLSID_DirectMusicBand), - X(CLSID_DirectMusicBandTrack), - X(CLSID_DirectMusicChordMapTrack), - X(CLSID_DirectMusicChordMap), - X(CLSID_DirectMusicChordTrack), - X(CLSID_DirectMusicCollection), - X(CLSID_DirectMusicCommandTrack), - X(CLSID_DirectMusicComposer), - X(CLSID_DirectMusicContainer), - X(CLSID_DirectMusicGraph), - X(CLSID_DirectMusicLoader), - X(CLSID_DirectMusicLyricsTrack), - X(CLSID_DirectMusicMarkerTrack), - X(CLSID_DirectMusicMelodyFormulationTrack), - X(CLSID_DirectMusicMotifTrack), - X(CLSID_DirectMusicMuteTrack), - X(CLSID_DirectMusicParamControlTrack), - X(CLSID_DirectMusicPatternTrack), - X(CLSID_DirectMusicPerformance), - X(CLSID_DirectMusicScript), - X(CLSID_DirectMusicScriptAutoImpSegment), - X(CLSID_DirectMusicScriptAutoImpPerformance), - X(CLSID_DirectMusicScriptAutoImpSegmentState), - X(CLSID_DirectMusicScriptAutoImpAudioPathConfig), - X(CLSID_DirectMusicScriptAutoImpAudioPath), - X(CLSID_DirectMusicScriptAutoImpSong), - X(CLSID_DirectMusicScriptSourceCodeLoader), - X(CLSID_DirectMusicScriptTrack), - X(CLSID_DirectMusicSection), - X(CLSID_DirectMusicSegment), - X(CLSID_DirectMusicSegmentState), - X(CLSID_DirectMusicSegmentTriggerTrack), - X(CLSID_DirectMusicSegTriggerTrack), - X(CLSID_DirectMusicSeqTrack), - X(CLSID_DirectMusicSignPostTrack), - X(CLSID_DirectMusicSong), - X(CLSID_DirectMusicStyle), - X(CLSID_DirectMusicStyleTrack), - X(CLSID_DirectMusicSynth), - X(CLSID_DirectMusicSynthSink), - X(CLSID_DirectMusicSysExTrack), - X(CLSID_DirectMusicTemplate), - X(CLSID_DirectMusicTempoTrack), - X(CLSID_DirectMusicTimeSigTrack), - X(CLSID_DirectMusicWaveTrack), - X(CLSID_DirectSoundWave), - /* IIDs */ - X(IID_IDirectMusic), - X(IID_IDirectMusic2), - X(IID_IDirectMusic8), - X(IID_IDirectMusicAudioPath), - X(IID_IDirectMusicBand), - X(IID_IDirectMusicBuffer), - X(IID_IDirectMusicChordMap), - X(IID_IDirectMusicCollection), - X(IID_IDirectMusicComposer), - X(IID_IDirectMusicContainer), - X(IID_IDirectMusicDownload), - X(IID_IDirectMusicDownloadedInstrument), - X(IID_IDirectMusicGetLoader), - X(IID_IDirectMusicGraph), - X(IID_IDirectMusicInstrument), - X(IID_IDirectMusicLoader), - X(IID_IDirectMusicLoader8), - X(IID_IDirectMusicObject), - X(IID_IDirectMusicPatternTrack), - X(IID_IDirectMusicPerformance), - X(IID_IDirectMusicPerformance2), - X(IID_IDirectMusicPerformance8), - X(IID_IDirectMusicPort), - X(IID_IDirectMusicPortDownload), - X(IID_IDirectMusicScript), - X(IID_IDirectMusicSegment), - X(IID_IDirectMusicSegment2), - X(IID_IDirectMusicSegment8), - X(IID_IDirectMusicSegmentState), - X(IID_IDirectMusicSegmentState8), - X(IID_IDirectMusicStyle), - X(IID_IDirectMusicStyle8), - X(IID_IDirectMusicSynth), - X(IID_IDirectMusicSynth8), - X(IID_IDirectMusicSynthSink), - X(IID_IDirectMusicThru), - X(IID_IDirectMusicTool), - X(IID_IDirectMusicTool8), - X(IID_IDirectMusicTrack), - X(IID_IDirectMusicTrack8), - X(IID_IUnknown), - X(IID_IPersistStream), - X(IID_IStream), - X(IID_IClassFactory), - /* GUIDs */ - X(GUID_DirectMusicAllTypes), - X(GUID_NOTIFICATION_CHORD), - X(GUID_NOTIFICATION_COMMAND), - X(GUID_NOTIFICATION_MEASUREANDBEAT), - X(GUID_NOTIFICATION_PERFORMANCE), - X(GUID_NOTIFICATION_RECOMPOSE), - X(GUID_NOTIFICATION_SEGMENT), - X(GUID_BandParam), - X(GUID_ChordParam), - X(GUID_CommandParam), - X(GUID_CommandParam2), - X(GUID_CommandParamNext), - X(GUID_IDirectMusicBand), - X(GUID_IDirectMusicChordMap), - X(GUID_IDirectMusicStyle), - X(GUID_MuteParam), - X(GUID_Play_Marker), - X(GUID_RhythmParam), - X(GUID_TempoParam), - X(GUID_TimeSignature), - X(GUID_Valid_Start_Time), - X(GUID_Clear_All_Bands), - X(GUID_ConnectToDLSCollection), - X(GUID_Disable_Auto_Download), - X(GUID_DisableTempo), - X(GUID_DisableTimeSig), - X(GUID_Download), - X(GUID_DownloadToAudioPath), - X(GUID_Enable_Auto_Download), - X(GUID_EnableTempo), - X(GUID_EnableTimeSig), - X(GUID_IgnoreBankSelectForGM), - X(GUID_SeedVariations), - X(GUID_StandardMIDIFile), - X(GUID_Unload), - X(GUID_UnloadFromAudioPath), - X(GUID_Variations), - X(GUID_PerfMasterTempo), - X(GUID_PerfMasterVolume), - X(GUID_PerfMasterGrooveLevel), - X(GUID_PerfAutoDownload), - X(GUID_DefaultGMCollection), - X(GUID_Synth_Default), - X(GUID_Buffer_Reverb), - X(GUID_Buffer_EnvReverb), - X(GUID_Buffer_Stereo), - X(GUID_Buffer_3D_Dry), - X(GUID_Buffer_Mono), - X(GUID_DMUS_PROP_GM_Hardware), - X(GUID_DMUS_PROP_GS_Capable), - X(GUID_DMUS_PROP_GS_Hardware), - X(GUID_DMUS_PROP_DLS1), - X(GUID_DMUS_PROP_DLS2), - X(GUID_DMUS_PROP_Effects), - X(GUID_DMUS_PROP_INSTRUMENT2), - X(GUID_DMUS_PROP_LegacyCaps), - X(GUID_DMUS_PROP_MemorySize), - X(GUID_DMUS_PROP_SampleMemorySize), - X(GUID_DMUS_PROP_SamplePlaybackRate), - X(GUID_DMUS_PROP_SetSynthSink), - X(GUID_DMUS_PROP_SinkUsesDSound), - X(GUID_DMUS_PROP_SynthSink_DSOUND), - X(GUID_DMUS_PROP_SynthSink_WAVE), - X(GUID_DMUS_PROP_Volume), - X(GUID_DMUS_PROP_WavesReverb), - X(GUID_DMUS_PROP_WriteLatency), - X(GUID_DMUS_PROP_WritePeriod), - X(GUID_DMUS_PROP_XG_Capable), - X(GUID_DMUS_PROP_XG_Hardware) - }; -#undef X - - if (!id) - return "(null)"; - - for (i = 0; i < ARRAY_SIZE(guids); i++) - if (IsEqualGUID(id, guids[i].guid)) - return guids[i].name; - - return debugstr_guid(id); -} - -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc) -{ - if (!desc || !TRACE_ON(dmfile)) - return; - - TRACE_(dmfile)("DMUS_OBJECTDESC (%p):", desc); - TRACE_(dmfile)(" - dwSize = %lu\n", desc->dwSize); - -#define X(flag) if (desc->dwValidData & flag) TRACE_(dmfile)(#flag " ") - TRACE_(dmfile)(" - dwValidData = %#08lx ( ", desc->dwValidData); - X(DMUS_OBJ_OBJECT); - X(DMUS_OBJ_CLASS); - X(DMUS_OBJ_NAME); - X(DMUS_OBJ_CATEGORY); - X(DMUS_OBJ_FILENAME); - X(DMUS_OBJ_FULLPATH); - X(DMUS_OBJ_URL); - X(DMUS_OBJ_VERSION); - X(DMUS_OBJ_DATE); - X(DMUS_OBJ_LOADED); - X(DMUS_OBJ_MEMORY); - X(DMUS_OBJ_STREAM); - TRACE_(dmfile)(")\n"); -#undef X - - if (desc->dwValidData & DMUS_OBJ_CLASS) - TRACE_(dmfile)(" - guidClass = %s\n", debugstr_dmguid(&desc->guidClass)); - if (desc->dwValidData & DMUS_OBJ_OBJECT) - TRACE_(dmfile)(" - guidObject = %s\n", debugstr_guid(&desc->guidObject)); - - if (desc->dwValidData & DMUS_OBJ_DATE) { - SYSTEMTIME time; - FileTimeToSystemTime(&desc->ftDate, &time); - TRACE_(dmfile)(" - ftDate = \'%04u-%02u-%02u %02u:%02u:%02u\'\n", - time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond); - } - if (desc->dwValidData & DMUS_OBJ_VERSION) - TRACE_(dmfile)(" - vVersion = \'%u,%u,%u,%u\'\n", - HIWORD(desc->vVersion.dwVersionMS), LOWORD(desc->vVersion.dwVersionMS), - HIWORD(desc->vVersion.dwVersionLS), LOWORD(desc->vVersion.dwVersionLS)); - if (desc->dwValidData & DMUS_OBJ_NAME) - TRACE_(dmfile)(" - wszName = %s\n", debugstr_w(desc->wszName)); - if (desc->dwValidData & DMUS_OBJ_CATEGORY) - TRACE_(dmfile)(" - wszCategory = %s\n", debugstr_w(desc->wszCategory)); - if (desc->dwValidData & DMUS_OBJ_FILENAME) - TRACE_(dmfile)(" - wszFileName = %s\n", debugstr_w(desc->wszFileName)); - if (desc->dwValidData & DMUS_OBJ_MEMORY) - TRACE_(dmfile)(" - llMemLength = 0x%s - pbMemData = %p\n", - wine_dbgstr_longlong(desc->llMemLength), desc->pbMemData); - if (desc->dwValidData & DMUS_OBJ_STREAM) - TRACE_(dmfile)(" - pStream = %p\n", desc->pStream); -} - - -/* RIFF format parsing */ -#define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD)) - -const char *debugstr_chunk(const struct chunk_entry *chunk) -{ - const char *type = ""; - - if (!chunk) - return "(null)"; - if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST) - type = wine_dbg_sprintf("type %s, ", debugstr_fourcc(chunk->type)); - return wine_dbg_sprintf("%s chunk, %ssize %lu", debugstr_fourcc(chunk->id), type, chunk->size); -} - -static HRESULT stream_read(IStream *stream, void *data, ULONG size) -{ - ULONG read; - HRESULT hr; - - hr = IStream_Read(stream, data, size, &read); - if (FAILED(hr)) - TRACE_(dmfile)("IStream_Read failed: %#lx\n", hr); - else if (!read && read < size) { - /* All or nothing: Handle a partial read due to end of stream as an error */ - TRACE_(dmfile)("Short read: %lu < %lu\n", read, size); - return E_FAIL; - } - - return hr; -} - -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) -{ - static const LARGE_INTEGER zero; - ULONGLONG ck_end = 0, p_end = 0; - HRESULT hr; - - hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &chunk->offset); - if (FAILED(hr)) - return hr; - assert(!(chunk->offset.QuadPart & 1)); - if (chunk->parent) { - p_end = chunk->parent->offset.QuadPart + CHUNK_HDR_SIZE + ((chunk->parent->size + 1) & ~1); - if (chunk->offset.QuadPart == p_end) - return S_FALSE; - ck_end = chunk->offset.QuadPart + CHUNK_HDR_SIZE; - if (ck_end > p_end) { - WARN_(dmfile)("No space for sub-chunk header in parent chunk: ends at offset %s > %s\n", - wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end)); - return E_FAIL; - } - } - - hr = stream_read(stream, chunk, CHUNK_HDR_SIZE); - if (hr != S_OK) - return hr; - if (chunk->parent) { - ck_end += (chunk->size + 1) & ~1; - if (ck_end > p_end) { - WARN_(dmfile)("No space for sub-chunk data in parent chunk: ends at offset %s > %s\n", - wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end)); - return E_FAIL; - } - } - - if (chunk->id == FOURCC_LIST || chunk->id == FOURCC_RIFF) { - hr = stream_read(stream, &chunk->type, sizeof(FOURCC)); - if (hr != S_OK) - return hr != S_FALSE ? hr : E_FAIL; - } - - TRACE_(dmfile)("Returning %s\n", debugstr_chunk(chunk)); - - return S_OK; -} - -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER end; - - end.QuadPart = (chunk->offset.QuadPart + CHUNK_HDR_SIZE + chunk->size + 1) & ~(ULONGLONG)1; - - return IStream_Seek(stream, end, STREAM_SEEK_SET, NULL); -} - -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) -{ - HRESULT hr; - - if (chunk->id) { - hr = stream_skip_chunk(stream, chunk); - if (FAILED(hr)) - return hr; - } - - return stream_get_chunk(stream, chunk); -} - -/* Reads chunk data of the form: - DWORD - size of array element - element[] - Array of elements - The caller needs to heap_free() the array. -*/ -HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size) -{ - DWORD size; - HRESULT hr; - - *array = NULL; - *count = 0; - - if (chunk->size < sizeof(DWORD)) { - WARN_(dmfile)("%s: Too short to read element size\n", debugstr_chunk(chunk)); - return E_FAIL; - } - if (FAILED(hr = stream_read(stream, &size, sizeof(DWORD)))) - return hr; - if (size != elem_size) { - WARN_(dmfile)("%s: Array element size mismatch: got %lu, expected %lu\n", - debugstr_chunk(chunk), size, elem_size); - return DMUS_E_UNSUPPORTED_STREAM; - } - - *count = (chunk->size - sizeof(DWORD)) / elem_size; - size = *count * elem_size; - if (!(*array = heap_alloc(size))) - return E_OUTOFMEMORY; - if (FAILED(hr = stream_read(stream, *array, size))) { - heap_free(*array); - *array = NULL; - return hr; - } - - if (chunk->size > size + sizeof(DWORD)) { - WARN_(dmfile)("%s: Extraneous data at end of array\n", debugstr_chunk(chunk)); - stream_skip_chunk(stream, chunk); - return S_FALSE; - } - return S_OK; -} - -HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size) -{ - if (chunk->size != size) { - WARN_(dmfile)("Chunk %s (size %lu, offset %s) doesn't contains the expected data size %lu\n", - debugstr_fourcc(chunk->id), chunk->size, - wine_dbgstr_longlong(chunk->offset.QuadPart), size); - return E_FAIL; - } - return stream_read(stream, data, size); -} - -HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size) -{ - ULONG len; - HRESULT hr; - - hr = IStream_Read(stream, str, min(chunk->size, size), &len); - if (FAILED(hr)) - return hr; - - /* Don't assume the string is properly zero terminated */ - str[min(len, size - 1)] = 0; - - if (len < chunk->size) - return S_FALSE; - return S_OK; -} - - - -/* Generic IDirectMusicObject methods */ -static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface) -{ - return CONTAINING_RECORD(iface, struct dmobject, IDirectMusicObject_iface); -} - -HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); -} - -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_AddRef(This->outer_unk); -} - -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_Release(This->outer_unk); -} - -HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - - TRACE("(%p/%p)->(%p)\n", iface, This, desc); - - if (!desc) - return E_POINTER; - - memcpy(desc, &This->desc, This->desc.dwSize); - - return S_OK; -} - -HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - HRESULT ret = S_OK; - - TRACE("(%p, %p)\n", iface, desc); - - if (!desc) - return E_POINTER; - - /* Immutable property */ - if (desc->dwValidData & DMUS_OBJ_CLASS) - { - desc->dwValidData &= ~DMUS_OBJ_CLASS; - ret = S_FALSE; - } - /* Set only valid fields */ - if (desc->dwValidData & DMUS_OBJ_OBJECT) - This->desc.guidObject = desc->guidObject; - if (desc->dwValidData & DMUS_OBJ_NAME) - lstrcpynW(This->desc.wszName, desc->wszName, DMUS_MAX_NAME); - if (desc->dwValidData & DMUS_OBJ_CATEGORY) - lstrcpynW(This->desc.wszCategory, desc->wszCategory, DMUS_MAX_CATEGORY); - if (desc->dwValidData & DMUS_OBJ_FILENAME) - lstrcpynW(This->desc.wszFileName, desc->wszFileName, DMUS_MAX_FILENAME); - if (desc->dwValidData & DMUS_OBJ_VERSION) - This->desc.vVersion = desc->vVersion; - if (desc->dwValidData & DMUS_OBJ_DATE) - This->desc.ftDate = desc->ftDate; - if (desc->dwValidData & DMUS_OBJ_MEMORY) { - This->desc.llMemLength = desc->llMemLength; - memcpy(This->desc.pbMemData, desc->pbMemData, desc->llMemLength); - } - if (desc->dwValidData & DMUS_OBJ_STREAM) - IStream_Clone(desc->pStream, &This->desc.pStream); - - This->desc.dwValidData |= desc->dwValidData; - - return ret; -} - -/* Helper for IDirectMusicObject::ParseDescriptor */ -static inline void info_get_name(IStream *stream, const struct chunk_entry *info, - DMUS_OBJECTDESC *desc) -{ - struct chunk_entry chunk = {.parent = info}; - char name[DMUS_MAX_NAME]; - ULONG len; - HRESULT hr = E_FAIL; - - while (stream_next_chunk(stream, &chunk) == S_OK) - if (chunk.id == mmioFOURCC('I','N','A','M')) - hr = IStream_Read(stream, name, min(chunk.size, sizeof(name)), &len); - - if (SUCCEEDED(hr)) { - len = MultiByteToWideChar(CP_ACP, 0, name, len, desc->wszName, sizeof(desc->wszName)); - desc->wszName[min(len, sizeof(desc->wszName) - 1)] = 0; - desc->dwValidData |= DMUS_OBJ_NAME; - } -} - -static inline void unfo_get_name(IStream *stream, const struct chunk_entry *unfo, - DMUS_OBJECTDESC *desc, BOOL inam) -{ - struct chunk_entry chunk = {.parent = unfo}; - - while (stream_next_chunk(stream, &chunk) == S_OK) - if (chunk.id == DMUS_FOURCC_UNAM_CHUNK || (inam && chunk.id == mmioFOURCC('I','N','A','M'))) - if (stream_chunk_get_wstr(stream, &chunk, desc->wszName, sizeof(desc->wszName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_NAME; -} - -HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported) -{ - struct chunk_entry chunk = {.parent = riff}; - HRESULT hr; - - TRACE("Looking for %#lx in %p: %s\n", supported, stream, debugstr_chunk(riff)); - - desc->dwValidData = 0; - desc->dwSize = sizeof(*desc); - - while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { - switch (chunk.id) { - case DMUS_FOURCC_CATEGORY_CHUNK: - if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk, - desc->wszCategory, sizeof(desc->wszCategory)) == S_OK) - desc->dwValidData |= DMUS_OBJ_CATEGORY; - break; - case DMUS_FOURCC_DATE_CHUNK: - if ((supported & DMUS_OBJ_DATE) && stream_chunk_get_data(stream, &chunk, - &desc->ftDate, sizeof(desc->ftDate)) == S_OK) - desc->dwValidData |= DMUS_OBJ_DATE; - break; - case DMUS_FOURCC_FILE_CHUNK: - if ((supported & DMUS_OBJ_FILENAME) && stream_chunk_get_wstr(stream, &chunk, - desc->wszFileName, sizeof(desc->wszFileName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_FILENAME; - break; - case DMUS_FOURCC_GUID_CHUNK: - if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk, - &desc->guidObject, sizeof(desc->guidObject)) == S_OK) - desc->dwValidData |= DMUS_OBJ_OBJECT; - break; - case DMUS_FOURCC_NAME_CHUNK: - if ((supported & DMUS_OBJ_NAME) && stream_chunk_get_wstr(stream, &chunk, - desc->wszName, sizeof(desc->wszName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_NAME; - break; - case DMUS_FOURCC_VERSION_CHUNK: - if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk, - &desc->vVersion, sizeof(desc->vVersion)) == S_OK) - desc->dwValidData |= DMUS_OBJ_VERSION; - break; - case FOURCC_LIST: - if (chunk.type == DMUS_FOURCC_UNFO_LIST && (supported & DMUS_OBJ_NAME)) - unfo_get_name(stream, &chunk, desc, supported & DMUS_OBJ_NAME_INAM); - else if (chunk.type == DMUS_FOURCC_INFO_LIST && (supported & DMUS_OBJ_NAME_INFO)) - info_get_name(stream, &chunk, desc); - break; - } - } - TRACE("Found %#lx\n", desc->dwValidData); - - return hr; -} - -HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj) -{ - struct chunk_entry chunk = {.parent = list}; - IDirectMusicGetLoader *getloader; - IDirectMusicLoader *loader; - DMUS_OBJECTDESC desc; - DMUS_IO_REFERENCE reference; - HRESULT hr; - - if (FAILED(hr = stream_next_chunk(stream, &chunk))) - return hr; - if (chunk.id != DMUS_FOURCC_REF_CHUNK) - return DMUS_E_UNSUPPORTED_STREAM; - - if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &reference, sizeof(reference)))) { - WARN("Failed to read data of %s\n", debugstr_chunk(&chunk)); - return hr; - } - TRACE("REFERENCE guidClassID %s, dwValidData %#lx\n", debugstr_dmguid(&reference.guidClassID), - reference.dwValidData); - - if (FAILED(hr = dmobj_parsedescriptor(stream, list, &desc, reference.dwValidData))) - return hr; - desc.guidClass = reference.guidClassID; - desc.dwValidData |= DMUS_OBJ_CLASS; - dump_DMUS_OBJECTDESC(&desc); - - if (FAILED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getloader))) - return hr; - hr = IDirectMusicGetLoader_GetLoader(getloader, &loader); - IDirectMusicGetLoader_Release(getloader); - if (FAILED(hr)) - return hr; - - hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicObject, (void**)dmobj); - IDirectMusicLoader_Release(loader); - - return hr; -} - -/* Generic IPersistStream methods */ -static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface) -{ - return CONTAINING_RECORD(iface, struct dmobject, IPersistStream_iface); -} - -HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); -} - -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_AddRef(This->outer_unk); -} - -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_Release(This->outer_unk); -} - -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - - TRACE("(%p, %p)\n", This, class); - - if (!class) - return E_POINTER; - - *class = This->desc.guidClass; - - return S_OK; -} - -/* IPersistStream methods not implemented in native */ -HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) -{ - TRACE("(%p, %p): method not implemented\n", iface, class); - return E_NOTIMPL; -} - -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface) -{ - TRACE("(%p): method not implemented, always returning S_FALSE\n", iface); - return S_FALSE; -} - -HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty) -{ - TRACE("(%p, %p, %d): method not implemented\n", iface, stream, clear_dirty); - return E_NOTIMPL; -} - -HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, ULARGE_INTEGER *size) -{ - TRACE("(%p, %p): method not implemented\n", iface, size); - return E_NOTIMPL; -} - - -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk) -{ - dmobj->outer_unk = outer_unk; - dmobj->desc.dwSize = sizeof(dmobj->desc); - dmobj->desc.dwValidData = DMUS_OBJ_CLASS; - dmobj->desc.guidClass = *class; -} diff --git a/dlls/dswave/dmobject.h b/dlls/dswave/dmobject.h deleted file mode 100644 index 772be015c80..00000000000 --- a/dlls/dswave/dmobject.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Base IDirectMusicObject Implementation - * Keep in sync with the master in dlls/dmusic/dmobject.h - * - * Copyright (C) 2014 Michael Stefaniuc - * - * This program 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 program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "wine/debug.h" - -/* RIFF stream parsing */ -struct chunk_entry; -struct chunk_entry { - FOURCC id; - DWORD size; - FOURCC type; /* valid only for LIST and RIFF chunks */ - ULARGE_INTEGER offset; /* chunk offset from start of stream */ - const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */ -}; - -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk); -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk); -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk); - -HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size); -HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size); -HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size); - -static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER offset; - - offset.QuadPart = chunk->offset.QuadPart + sizeof(FOURCC) + sizeof(DWORD); - if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST) - offset.QuadPart += sizeof(FOURCC); - - return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); -} - -static inline HRESULT stream_reset_chunk_start(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER offset; - - offset.QuadPart = chunk->offset.QuadPart; - - return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); -} - - -/* IDirectMusicObject base object */ -struct dmobject { - IDirectMusicObject IDirectMusicObject_iface; - IPersistStream IPersistStream_iface; - IUnknown *outer_unk; - DMUS_OBJECTDESC desc; -}; - -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk); - -/* Generic IDirectMusicObject methods */ -HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface); -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface); -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface); -HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc); -HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc); - -/* Helper for IDirectMusicObject::ParseDescriptor */ -HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported); -/* Additional supported flags for dmobj_parsedescriptor. - DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */ -#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */ -#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */ - -/* 'DMRF' (reference list) helper */ -HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj); - -/* Generic IPersistStream methods */ -HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface); -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface); -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface); -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class); - -/* IPersistStream methods not implemented in native */ -HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, - CLSID *class); -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface); -HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty); -HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, - ULARGE_INTEGER *size); - -/* Debugging helpers */ -const char *debugstr_chunk(const struct chunk_entry *chunk); -const char *debugstr_dmguid(const GUID *id); -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc); - -static inline const char *debugstr_fourcc(DWORD fourcc) -{ - if (!fourcc) return "''"; - return wine_dbg_sprintf("'%c%c%c%c'", (char)(fourcc), (char)(fourcc >> 8), - (char)(fourcc >> 16), (char)(fourcc >> 24)); -} From 25a69ccbc1ff27058bd5f796f075dec4486282fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Aug 2023 17:43:30 +0200 Subject: [PATCH 2488/2777] dmstyle: Awlays return S_FALSE from DllCanUnloadNow. (cherry picked from commit 994bcb48421c94949eed9f931aeae965dad2a9a9) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmstyle/auditiontrack.c | 2 -- dlls/dmstyle/chordtrack.c | 2 -- dlls/dmstyle/commandtrack.c | 2 -- dlls/dmstyle/dmstyle_main.c | 21 --------------------- dlls/dmstyle/dmstyle_private.h | 7 ------- dlls/dmstyle/motiftrack.c | 2 -- dlls/dmstyle/mutetrack.c | 2 -- dlls/dmstyle/style.c | 2 -- dlls/dmstyle/styletrack.c | 2 -- 9 files changed, 42 deletions(-) diff --git a/dlls/dmstyle/auditiontrack.c b/dlls/dmstyle/auditiontrack.c index 0bf1c818f6c..f324d18cecc 100644 --- a/dlls/dmstyle/auditiontrack.c +++ b/dlls/dmstyle/auditiontrack.c @@ -79,7 +79,6 @@ static ULONG WINAPI audition_track_Release(IDirectMusicTrack8 *iface) if (!ref) { HeapFree(GetProcessHeap(), 0, This); - DMSTYLE_UnlockModule(); } return ref; @@ -332,7 +331,6 @@ HRESULT create_dmauditiontrack(REFIID lpcGUID, void **ppobj) (IUnknown *)&track->IDirectMusicTrack8_iface); track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - DMSTYLE_LockModule(); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); diff --git a/dlls/dmstyle/chordtrack.c b/dlls/dmstyle/chordtrack.c index fdaecac1240..01511963a40 100644 --- a/dlls/dmstyle/chordtrack.c +++ b/dlls/dmstyle/chordtrack.c @@ -82,7 +82,6 @@ static ULONG WINAPI chord_track_Release(IDirectMusicTrack8 *iface) if (!ref) { HeapFree(GetProcessHeap(), 0, This); - DMSTYLE_UnlockModule(); } return ref; @@ -431,7 +430,6 @@ HRESULT create_dmchordtrack(REFIID lpcGUID, void **ppobj) (IUnknown *)&track->IDirectMusicTrack8_iface); track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - DMSTYLE_LockModule(); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); diff --git a/dlls/dmstyle/commandtrack.c b/dlls/dmstyle/commandtrack.c index 32e0bbe8c0d..02b32bc41e6 100644 --- a/dlls/dmstyle/commandtrack.c +++ b/dlls/dmstyle/commandtrack.c @@ -81,7 +81,6 @@ static ULONG WINAPI command_track_Release(IDirectMusicTrack8 *iface) if (!ref) { HeapFree(GetProcessHeap(), 0, This); - DMSTYLE_UnlockModule(); } return ref; @@ -385,7 +384,6 @@ HRESULT create_dmcommandtrack(REFIID lpcGUID, void **ppobj) track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; list_init (&track->Commands); - DMSTYLE_LockModule(); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); diff --git a/dlls/dmstyle/dmstyle_main.c b/dlls/dmstyle/dmstyle_main.c index 8f951ece5ae..9d96ab3930e 100644 --- a/dlls/dmstyle/dmstyle_main.c +++ b/dlls/dmstyle/dmstyle_main.c @@ -37,8 +37,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmstyle); -LONG DMSTYLE_refCount = 0; - typedef struct { IClassFactory IClassFactory_iface; HRESULT (*fnCreateInstance)(REFIID riid, void **ret_iface); @@ -81,15 +79,11 @@ static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID r static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) { - DMSTYLE_LockModule(); - return 2; /* non-heap based object */ } static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) { - DMSTYLE_UnlockModule(); - return 1; /* non-heap based object */ } @@ -111,12 +105,6 @@ static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock) { TRACE("(%d)\n", dolock); - - if (dolock) - DMSTYLE_LockModule(); - else - DMSTYLE_UnlockModule(); - return S_OK; } @@ -137,15 +125,6 @@ static IClassFactoryImpl MotifTrack_CF = {{&classfactory_vtbl}, create_dmmotiftr static IClassFactoryImpl AuditionTrack_CF = {{&classfactory_vtbl}, create_dmauditiontrack}; static IClassFactoryImpl MuteTrack_CF = {{&classfactory_vtbl}, create_dmmutetrack}; -/****************************************************************** - * DllCanUnloadNow (DMSTYLE.1) - * - * - */ -HRESULT WINAPI DllCanUnloadNow(void) { - return DMSTYLE_refCount != 0 ? S_FALSE : S_OK; -} - /****************************************************************** * DllGetClassObject (DMSTYLE.@) diff --git a/dlls/dmstyle/dmstyle_private.h b/dlls/dmstyle/dmstyle_private.h index 2807e98fe61..5237368b44e 100644 --- a/dlls/dmstyle/dmstyle_private.h +++ b/dlls/dmstyle/dmstyle_private.h @@ -61,13 +61,6 @@ typedef struct _DMUS_PRIVATE_COMMAND { IDirectMusicCollection* ppReferenceCollection; } DMUS_PRIVATE_COMMAND, *LPDMUS_PRIVATE_COMMAND; -/********************************************************************** - * Dll lifetime tracking declaration for dmstyle.dll - */ -extern LONG DMSTYLE_refCount; -static inline void DMSTYLE_LockModule(void) { InterlockedIncrement( &DMSTYLE_refCount ); } -static inline void DMSTYLE_UnlockModule(void) { InterlockedDecrement( &DMSTYLE_refCount ); } - /***************************************************************************** * Misc. */ diff --git a/dlls/dmstyle/motiftrack.c b/dlls/dmstyle/motiftrack.c index 5efe90706e0..93bfd821e56 100644 --- a/dlls/dmstyle/motiftrack.c +++ b/dlls/dmstyle/motiftrack.c @@ -79,7 +79,6 @@ static ULONG WINAPI motif_track_Release(IDirectMusicTrack8 *iface) if (!ref) { HeapFree(GetProcessHeap(), 0, This); - DMSTYLE_UnlockModule(); } return ref; @@ -304,7 +303,6 @@ HRESULT create_dmmotiftrack(REFIID lpcGUID, void **ppobj) (IUnknown *)&track->IDirectMusicTrack8_iface); track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - DMSTYLE_LockModule(); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); diff --git a/dlls/dmstyle/mutetrack.c b/dlls/dmstyle/mutetrack.c index 2248d7151dd..3f632709397 100644 --- a/dlls/dmstyle/mutetrack.c +++ b/dlls/dmstyle/mutetrack.c @@ -79,7 +79,6 @@ static ULONG WINAPI mute_track_Release(IDirectMusicTrack8 *iface) if (!ref) { HeapFree(GetProcessHeap(), 0, This); - DMSTYLE_UnlockModule(); } return ref; @@ -313,7 +312,6 @@ HRESULT create_dmmutetrack(REFIID lpcGUID, void **ppobj) (IUnknown *)&track->IDirectMusicTrack8_iface); track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - DMSTYLE_LockModule(); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); diff --git a/dlls/dmstyle/style.c b/dlls/dmstyle/style.c index ae939f8b738..e2c3f812330 100644 --- a/dlls/dmstyle/style.c +++ b/dlls/dmstyle/style.c @@ -127,7 +127,6 @@ static ULONG WINAPI IDirectMusicStyle8Impl_Release(IDirectMusicStyle8 *iface) heap_free(motif); } heap_free(This); - DMSTYLE_UnlockModule(); } return ref; @@ -991,7 +990,6 @@ HRESULT create_dmstyle(REFIID lpcGUID, void **ppobj) list_init(&obj->bands); list_init(&obj->motifs); - DMSTYLE_LockModule(); hr = IDirectMusicStyle8_QueryInterface(&obj->IDirectMusicStyle8_iface, lpcGUID, ppobj); IDirectMusicStyle8_Release(&obj->IDirectMusicStyle8_iface); diff --git a/dlls/dmstyle/styletrack.c b/dlls/dmstyle/styletrack.c index 83b03807ddf..3618483749c 100644 --- a/dlls/dmstyle/styletrack.c +++ b/dlls/dmstyle/styletrack.c @@ -96,7 +96,6 @@ static ULONG WINAPI style_track_Release(IDirectMusicTrack8 *iface) } heap_free(This); - DMSTYLE_UnlockModule(); } return ref; @@ -403,7 +402,6 @@ HRESULT create_dmstyletrack(REFIID lpcGUID, void **ppobj) track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; list_init (&track->Items); - DMSTYLE_LockModule(); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); From ac6b31e8af906645db1cbe7f9d7517b37118dfd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 9 Sep 2023 09:27:19 +0200 Subject: [PATCH 2489/2777] dmstyle: Use CRT allocation functions. (cherry picked from commit d18ec193de842e80b4ca1ab01cb217f782329675) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmstyle/auditiontrack.c | 11 +++-------- dlls/dmstyle/chordtrack.c | 11 +++-------- dlls/dmstyle/commandtrack.c | 13 ++++--------- dlls/dmstyle/dmobject.c | 7 +++---- dlls/dmstyle/motiftrack.c | 11 +++-------- dlls/dmstyle/mutetrack.c | 11 +++-------- dlls/dmstyle/style.c | 34 +++++++++------------------------- dlls/dmstyle/styletrack.c | 11 +++-------- 8 files changed, 31 insertions(+), 78 deletions(-) diff --git a/dlls/dmstyle/auditiontrack.c b/dlls/dmstyle/auditiontrack.c index f324d18cecc..e7615f53278 100644 --- a/dlls/dmstyle/auditiontrack.c +++ b/dlls/dmstyle/auditiontrack.c @@ -77,9 +77,7 @@ static ULONG WINAPI audition_track_Release(IDirectMusicTrack8 *iface) TRACE("(%p) ref=%ld\n", This, ref); - if (!ref) { - HeapFree(GetProcessHeap(), 0, This); - } + if (!ref) free(This); return ref; } @@ -320,11 +318,8 @@ HRESULT create_dmauditiontrack(REFIID lpcGUID, void **ppobj) IDirectMusicAuditionTrack *track; HRESULT hr; - track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicAuditionTrack, diff --git a/dlls/dmstyle/chordtrack.c b/dlls/dmstyle/chordtrack.c index 01511963a40..50eb4e7a5ca 100644 --- a/dlls/dmstyle/chordtrack.c +++ b/dlls/dmstyle/chordtrack.c @@ -80,9 +80,7 @@ static ULONG WINAPI chord_track_Release(IDirectMusicTrack8 *iface) TRACE("(%p) ref=%ld\n", This, ref); - if (!ref) { - HeapFree(GetProcessHeap(), 0, This); - } + if (!ref) free(This); return ref; } @@ -419,11 +417,8 @@ HRESULT create_dmchordtrack(REFIID lpcGUID, void **ppobj) IDirectMusicChordTrack *track; HRESULT hr; - track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicChordTrack, diff --git a/dlls/dmstyle/commandtrack.c b/dlls/dmstyle/commandtrack.c index 02b32bc41e6..17bb1e442bc 100644 --- a/dlls/dmstyle/commandtrack.c +++ b/dlls/dmstyle/commandtrack.c @@ -79,9 +79,7 @@ static ULONG WINAPI command_track_Release(IDirectMusicTrack8 *iface) TRACE("(%p) ref=%ld\n", This, ref); - if (!ref) { - HeapFree(GetProcessHeap(), 0, This); - } + if (!ref) free(This); return ref; } @@ -302,7 +300,7 @@ static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface, IStream *pS nrCommands = chunkSize/dwSizeOfStruct; /* and this is the number of commands */ /* load each command separately in new entry */ for (count = 0; count < nrCommands; count++) { - LPDMUS_PRIVATE_COMMAND pNewCommand = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_COMMAND)); + LPDMUS_PRIVATE_COMMAND pNewCommand = calloc(1, sizeof(*pNewCommand)); IStream_Read (pStm, &pNewCommand->pCommand, dwSizeOfStruct, NULL); list_add_tail (&This->Commands, &pNewCommand->entry); } @@ -372,11 +370,8 @@ HRESULT create_dmcommandtrack(REFIID lpcGUID, void **ppobj) IDirectMusicCommandTrack *track; HRESULT hr; - track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicCommandTrack, diff --git a/dlls/dmstyle/dmobject.c b/dlls/dmstyle/dmobject.c index b526b23d031..07d887a376c 100644 --- a/dlls/dmstyle/dmobject.c +++ b/dlls/dmstyle/dmobject.c @@ -28,7 +28,6 @@ #include "dmusics.h" #include "dmobject.h" #include "wine/debug.h" -#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(dmobj); WINE_DECLARE_DEBUG_CHANNEL(dmfile); @@ -375,7 +374,7 @@ HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) /* Reads chunk data of the form: DWORD - size of array element element[] - Array of elements - The caller needs to heap_free() the array. + The caller needs to free() the array. */ HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, unsigned int *count, DWORD elem_size) @@ -400,10 +399,10 @@ HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, *count = (chunk->size - sizeof(DWORD)) / elem_size; size = *count * elem_size; - if (!(*array = heap_alloc(size))) + if (!(*array = malloc(size))) return E_OUTOFMEMORY; if (FAILED(hr = stream_read(stream, *array, size))) { - heap_free(*array); + free(*array); *array = NULL; return hr; } diff --git a/dlls/dmstyle/motiftrack.c b/dlls/dmstyle/motiftrack.c index 93bfd821e56..9788a92e0e1 100644 --- a/dlls/dmstyle/motiftrack.c +++ b/dlls/dmstyle/motiftrack.c @@ -77,9 +77,7 @@ static ULONG WINAPI motif_track_Release(IDirectMusicTrack8 *iface) TRACE("(%p) ref=%ld\n", This, ref); - if (!ref) { - HeapFree(GetProcessHeap(), 0, This); - } + if (!ref) free(This); return ref; } @@ -292,11 +290,8 @@ HRESULT create_dmmotiftrack(REFIID lpcGUID, void **ppobj) IDirectMusicMotifTrack *track; HRESULT hr; - track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicMotifTrack, diff --git a/dlls/dmstyle/mutetrack.c b/dlls/dmstyle/mutetrack.c index 3f632709397..d6b28a16c72 100644 --- a/dlls/dmstyle/mutetrack.c +++ b/dlls/dmstyle/mutetrack.c @@ -77,9 +77,7 @@ static ULONG WINAPI mute_track_Release(IDirectMusicTrack8 *iface) TRACE("(%p) ref=%ld\n", This, ref); - if (!ref) { - HeapFree(GetProcessHeap(), 0, This); - } + if (!ref) free(This); return ref; } @@ -301,11 +299,8 @@ HRESULT create_dmmutetrack(REFIID lpcGUID, void **ppobj) IDirectMusicMuteTrack *track; HRESULT hr; - track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicMuteTrack, diff --git a/dlls/dmstyle/style.c b/dlls/dmstyle/style.c index e2c3f812330..781c371e623 100644 --- a/dlls/dmstyle/style.c +++ b/dlls/dmstyle/style.c @@ -20,7 +20,6 @@ #include "dmstyle_private.h" #include "dmobject.h" -#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(dmstyle); WINE_DECLARE_DEBUG_CHANNEL(dmfile); @@ -116,17 +115,17 @@ static ULONG WINAPI IDirectMusicStyle8Impl_Release(IDirectMusicStyle8 *iface) list_remove(&band->entry); if (band->pBand) IDirectMusicBand_Release(band->pBand); - heap_free(band); + free(band); } LIST_FOR_EACH_ENTRY_SAFE(motif, motif2, &This->motifs, struct style_motif, entry) { list_remove(&motif->entry); LIST_FOR_EACH_ENTRY_SAFE(item, item2, &motif->Items, struct style_partref_item, entry) { list_remove(&item->entry); - heap_free(item); + free(item); } - heap_free(motif); + free(motif); } - heap_free(This); + free(This); } return ref; @@ -405,11 +404,7 @@ static HRESULT parse_part_ref_list(DMUS_PRIVATE_CHUNK *pChunk, IStream *pStm, switch (Chunk.fccID) { case DMUS_FOURCC_PARTREF_CHUNK: { TRACE_(dmfile)(": PartRef chunk\n"); - pNewItem = heap_alloc_zero(sizeof(*pNewItem)); - if (!pNewItem) { - ERR(": no more memory\n"); - return E_OUTOFMEMORY; - } + if (!(pNewItem = calloc(1, sizeof(*pNewItem)))) return E_OUTOFMEMORY; hr = IStream_Read (pStm, &pNewItem->part_ref, sizeof(DMUS_IO_PARTREF), NULL); /*TRACE_(dmfile)(" - sizeof %lu\n", sizeof(DMUS_IO_PARTREF));*/ list_add_tail (&pNewMotif->Items, &pNewItem->entry); @@ -630,11 +625,7 @@ static HRESULT parse_pattern_list(IDirectMusicStyle8Impl *This, DMUS_PRIVATE_CHU case DMUS_FOURCC_PATTERN_CHUNK: { TRACE_(dmfile)(": Pattern chunk\n"); /** alloc new motif entry */ - pNewMotif = heap_alloc_zero(sizeof(*pNewMotif)); - if (NULL == pNewMotif) { - ERR(": no more memory\n"); - return E_OUTOFMEMORY; - } + if (!(pNewMotif = calloc(1, sizeof(*pNewMotif)))) return E_OUTOFMEMORY; list_add_tail(&This->motifs, &pNewMotif->entry); IStream_Read (pStm, &pNewMotif->pattern, Chunk.dwSize, NULL); @@ -826,11 +817,7 @@ static HRESULT parse_style_form(IDirectMusicStyle8Impl *This, DMUS_PRIVATE_CHUNK return hr; } - pNewBand = heap_alloc_zero(sizeof(*pNewBand)); - if (NULL == pNewBand) { - ERR(": no more memory\n"); - return E_OUTOFMEMORY; - } + if (!(pNewBand = calloc(1, sizeof(*pNewBand)))) return E_OUTOFMEMORY; pNewBand->pBand = pBand; IDirectMusicBand_AddRef(pBand); list_add_tail(&This->bands, &pNewBand->entry); @@ -977,11 +964,8 @@ HRESULT create_dmstyle(REFIID lpcGUID, void **ppobj) IDirectMusicStyle8Impl* obj; HRESULT hr; - obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicStyle8Impl)); - if (NULL == obj) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicStyle8_iface.lpVtbl = &dmstyle8_vtbl; obj->ref = 1; dmobject_init(&obj->dmobj, &CLSID_DirectMusicStyle, (IUnknown *)&obj->IDirectMusicStyle8_iface); diff --git a/dlls/dmstyle/styletrack.c b/dlls/dmstyle/styletrack.c index 3618483749c..700b8a1ea1a 100644 --- a/dlls/dmstyle/styletrack.c +++ b/dlls/dmstyle/styletrack.c @@ -20,8 +20,6 @@ #include "dmstyle_private.h" #include "dmobject.h" -#include "wine/heap.h" - WINE_DEFAULT_DEBUG_CHANNEL(dmstyle); /***************************************************************************** @@ -95,7 +93,7 @@ static ULONG WINAPI style_track_Release(IDirectMusicTrack8 *iface) free(item); } - heap_free(This); + free(This); } return ref; @@ -390,11 +388,8 @@ HRESULT create_dmstyletrack(REFIID lpcGUID, void **ppobj) IDirectMusicStyleTrack *track; HRESULT hr; - track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicStyleTrack, From 6b8a8a60aa7321d4cd66f87c6d5dd77ebbdf61c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 30 Aug 2023 19:53:42 +0200 Subject: [PATCH 2490/2777] dmstyle: Use PARENTSRC with dmusic. (cherry picked from commit 31980e74501b39490d20782bd36693ae2370668f) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmstyle/Makefile.in | 1 + dlls/dmstyle/dmobject.c | 732 --------------------------------------- dlls/dmstyle/dmobject.h | 124 ------- 3 files changed, 1 insertion(+), 856 deletions(-) delete mode 100644 dlls/dmstyle/dmobject.c delete mode 100644 dlls/dmstyle/dmobject.h diff --git a/dlls/dmstyle/Makefile.in b/dlls/dmstyle/Makefile.in index a95a524d473..8a6897ca4ca 100644 --- a/dlls/dmstyle/Makefile.in +++ b/dlls/dmstyle/Makefile.in @@ -1,5 +1,6 @@ MODULE = dmstyle.dll IMPORTS = dxguid uuid ole32 advapi32 +PARENTSRC = ../dmusic C_SRCS = \ auditiontrack.c \ diff --git a/dlls/dmstyle/dmobject.c b/dlls/dmstyle/dmobject.c deleted file mode 100644 index 07d887a376c..00000000000 --- a/dlls/dmstyle/dmobject.c +++ /dev/null @@ -1,732 +0,0 @@ -/* - * Base IDirectMusicObject Implementation - * Keep in sync with the master in dlls/dmusic/dmobject.c - * - * Copyright (C) 2003-2004 Rok Mandeljc - * Copyright (C) 2014 Michael Stefaniuc - * - * This program 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 program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define COBJMACROS -#include -#include "objbase.h" -#include "dmusici.h" -#include "dmusicf.h" -#include "dmusics.h" -#include "dmobject.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dmobj); -WINE_DECLARE_DEBUG_CHANNEL(dmfile); - -/* Debugging helpers */ -const char *debugstr_dmguid(const GUID *id) { - unsigned int i; -#define X(guid) { &guid, #guid } - static const struct { - const GUID *guid; - const char *name; - } guids[] = { - /* CLSIDs */ - X(CLSID_AudioVBScript), - X(CLSID_DirectMusic), - X(CLSID_DirectMusicAudioPathConfig), - X(CLSID_DirectMusicAuditionTrack), - X(CLSID_DirectMusicBand), - X(CLSID_DirectMusicBandTrack), - X(CLSID_DirectMusicChordMapTrack), - X(CLSID_DirectMusicChordMap), - X(CLSID_DirectMusicChordTrack), - X(CLSID_DirectMusicCollection), - X(CLSID_DirectMusicCommandTrack), - X(CLSID_DirectMusicComposer), - X(CLSID_DirectMusicContainer), - X(CLSID_DirectMusicGraph), - X(CLSID_DirectMusicLoader), - X(CLSID_DirectMusicLyricsTrack), - X(CLSID_DirectMusicMarkerTrack), - X(CLSID_DirectMusicMelodyFormulationTrack), - X(CLSID_DirectMusicMotifTrack), - X(CLSID_DirectMusicMuteTrack), - X(CLSID_DirectMusicParamControlTrack), - X(CLSID_DirectMusicPatternTrack), - X(CLSID_DirectMusicPerformance), - X(CLSID_DirectMusicScript), - X(CLSID_DirectMusicScriptAutoImpSegment), - X(CLSID_DirectMusicScriptAutoImpPerformance), - X(CLSID_DirectMusicScriptAutoImpSegmentState), - X(CLSID_DirectMusicScriptAutoImpAudioPathConfig), - X(CLSID_DirectMusicScriptAutoImpAudioPath), - X(CLSID_DirectMusicScriptAutoImpSong), - X(CLSID_DirectMusicScriptSourceCodeLoader), - X(CLSID_DirectMusicScriptTrack), - X(CLSID_DirectMusicSection), - X(CLSID_DirectMusicSegment), - X(CLSID_DirectMusicSegmentState), - X(CLSID_DirectMusicSegmentTriggerTrack), - X(CLSID_DirectMusicSegTriggerTrack), - X(CLSID_DirectMusicSeqTrack), - X(CLSID_DirectMusicSignPostTrack), - X(CLSID_DirectMusicSong), - X(CLSID_DirectMusicStyle), - X(CLSID_DirectMusicStyleTrack), - X(CLSID_DirectMusicSynth), - X(CLSID_DirectMusicSynthSink), - X(CLSID_DirectMusicSysExTrack), - X(CLSID_DirectMusicTemplate), - X(CLSID_DirectMusicTempoTrack), - X(CLSID_DirectMusicTimeSigTrack), - X(CLSID_DirectMusicWaveTrack), - X(CLSID_DirectSoundWave), - /* IIDs */ - X(IID_IDirectMusic), - X(IID_IDirectMusic2), - X(IID_IDirectMusic8), - X(IID_IDirectMusicAudioPath), - X(IID_IDirectMusicBand), - X(IID_IDirectMusicBuffer), - X(IID_IDirectMusicChordMap), - X(IID_IDirectMusicCollection), - X(IID_IDirectMusicComposer), - X(IID_IDirectMusicContainer), - X(IID_IDirectMusicDownload), - X(IID_IDirectMusicDownloadedInstrument), - X(IID_IDirectMusicGetLoader), - X(IID_IDirectMusicGraph), - X(IID_IDirectMusicInstrument), - X(IID_IDirectMusicLoader), - X(IID_IDirectMusicLoader8), - X(IID_IDirectMusicObject), - X(IID_IDirectMusicPatternTrack), - X(IID_IDirectMusicPerformance), - X(IID_IDirectMusicPerformance2), - X(IID_IDirectMusicPerformance8), - X(IID_IDirectMusicPort), - X(IID_IDirectMusicPortDownload), - X(IID_IDirectMusicScript), - X(IID_IDirectMusicSegment), - X(IID_IDirectMusicSegment2), - X(IID_IDirectMusicSegment8), - X(IID_IDirectMusicSegmentState), - X(IID_IDirectMusicSegmentState8), - X(IID_IDirectMusicStyle), - X(IID_IDirectMusicStyle8), - X(IID_IDirectMusicSynth), - X(IID_IDirectMusicSynth8), - X(IID_IDirectMusicSynthSink), - X(IID_IDirectMusicThru), - X(IID_IDirectMusicTool), - X(IID_IDirectMusicTool8), - X(IID_IDirectMusicTrack), - X(IID_IDirectMusicTrack8), - X(IID_IUnknown), - X(IID_IPersistStream), - X(IID_IStream), - X(IID_IClassFactory), - /* GUIDs */ - X(GUID_DirectMusicAllTypes), - X(GUID_NOTIFICATION_CHORD), - X(GUID_NOTIFICATION_COMMAND), - X(GUID_NOTIFICATION_MEASUREANDBEAT), - X(GUID_NOTIFICATION_PERFORMANCE), - X(GUID_NOTIFICATION_RECOMPOSE), - X(GUID_NOTIFICATION_SEGMENT), - X(GUID_BandParam), - X(GUID_ChordParam), - X(GUID_CommandParam), - X(GUID_CommandParam2), - X(GUID_CommandParamNext), - X(GUID_IDirectMusicBand), - X(GUID_IDirectMusicChordMap), - X(GUID_IDirectMusicStyle), - X(GUID_MuteParam), - X(GUID_Play_Marker), - X(GUID_RhythmParam), - X(GUID_TempoParam), - X(GUID_TimeSignature), - X(GUID_Valid_Start_Time), - X(GUID_Clear_All_Bands), - X(GUID_ConnectToDLSCollection), - X(GUID_Disable_Auto_Download), - X(GUID_DisableTempo), - X(GUID_DisableTimeSig), - X(GUID_Download), - X(GUID_DownloadToAudioPath), - X(GUID_Enable_Auto_Download), - X(GUID_EnableTempo), - X(GUID_EnableTimeSig), - X(GUID_IgnoreBankSelectForGM), - X(GUID_SeedVariations), - X(GUID_StandardMIDIFile), - X(GUID_Unload), - X(GUID_UnloadFromAudioPath), - X(GUID_Variations), - X(GUID_PerfMasterTempo), - X(GUID_PerfMasterVolume), - X(GUID_PerfMasterGrooveLevel), - X(GUID_PerfAutoDownload), - X(GUID_DefaultGMCollection), - X(GUID_Synth_Default), - X(GUID_Buffer_Reverb), - X(GUID_Buffer_EnvReverb), - X(GUID_Buffer_Stereo), - X(GUID_Buffer_3D_Dry), - X(GUID_Buffer_Mono), - X(GUID_DMUS_PROP_GM_Hardware), - X(GUID_DMUS_PROP_GS_Capable), - X(GUID_DMUS_PROP_GS_Hardware), - X(GUID_DMUS_PROP_DLS1), - X(GUID_DMUS_PROP_DLS2), - X(GUID_DMUS_PROP_Effects), - X(GUID_DMUS_PROP_INSTRUMENT2), - X(GUID_DMUS_PROP_LegacyCaps), - X(GUID_DMUS_PROP_MemorySize), - X(GUID_DMUS_PROP_SampleMemorySize), - X(GUID_DMUS_PROP_SamplePlaybackRate), - X(GUID_DMUS_PROP_SetSynthSink), - X(GUID_DMUS_PROP_SinkUsesDSound), - X(GUID_DMUS_PROP_SynthSink_DSOUND), - X(GUID_DMUS_PROP_SynthSink_WAVE), - X(GUID_DMUS_PROP_Volume), - X(GUID_DMUS_PROP_WavesReverb), - X(GUID_DMUS_PROP_WriteLatency), - X(GUID_DMUS_PROP_WritePeriod), - X(GUID_DMUS_PROP_XG_Capable), - X(GUID_DMUS_PROP_XG_Hardware) - }; -#undef X - - if (!id) - return "(null)"; - - for (i = 0; i < ARRAY_SIZE(guids); i++) - if (IsEqualGUID(id, guids[i].guid)) - return guids[i].name; - - return debugstr_guid(id); -} - -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc) -{ - if (!desc || !TRACE_ON(dmfile)) - return; - - TRACE_(dmfile)("DMUS_OBJECTDESC (%p):", desc); - TRACE_(dmfile)(" - dwSize = %lu\n", desc->dwSize); - -#define X(flag) if (desc->dwValidData & flag) TRACE_(dmfile)(#flag " ") - TRACE_(dmfile)(" - dwValidData = %#08lx ( ", desc->dwValidData); - X(DMUS_OBJ_OBJECT); - X(DMUS_OBJ_CLASS); - X(DMUS_OBJ_NAME); - X(DMUS_OBJ_CATEGORY); - X(DMUS_OBJ_FILENAME); - X(DMUS_OBJ_FULLPATH); - X(DMUS_OBJ_URL); - X(DMUS_OBJ_VERSION); - X(DMUS_OBJ_DATE); - X(DMUS_OBJ_LOADED); - X(DMUS_OBJ_MEMORY); - X(DMUS_OBJ_STREAM); - TRACE_(dmfile)(")\n"); -#undef X - - if (desc->dwValidData & DMUS_OBJ_CLASS) - TRACE_(dmfile)(" - guidClass = %s\n", debugstr_dmguid(&desc->guidClass)); - if (desc->dwValidData & DMUS_OBJ_OBJECT) - TRACE_(dmfile)(" - guidObject = %s\n", debugstr_guid(&desc->guidObject)); - - if (desc->dwValidData & DMUS_OBJ_DATE) { - SYSTEMTIME time; - FileTimeToSystemTime(&desc->ftDate, &time); - TRACE_(dmfile)(" - ftDate = \'%04u-%02u-%02u %02u:%02u:%02u\'\n", - time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond); - } - if (desc->dwValidData & DMUS_OBJ_VERSION) - TRACE_(dmfile)(" - vVersion = \'%u,%u,%u,%u\'\n", - HIWORD(desc->vVersion.dwVersionMS), LOWORD(desc->vVersion.dwVersionMS), - HIWORD(desc->vVersion.dwVersionLS), LOWORD(desc->vVersion.dwVersionLS)); - if (desc->dwValidData & DMUS_OBJ_NAME) - TRACE_(dmfile)(" - wszName = %s\n", debugstr_w(desc->wszName)); - if (desc->dwValidData & DMUS_OBJ_CATEGORY) - TRACE_(dmfile)(" - wszCategory = %s\n", debugstr_w(desc->wszCategory)); - if (desc->dwValidData & DMUS_OBJ_FILENAME) - TRACE_(dmfile)(" - wszFileName = %s\n", debugstr_w(desc->wszFileName)); - if (desc->dwValidData & DMUS_OBJ_MEMORY) - TRACE_(dmfile)(" - llMemLength = 0x%s - pbMemData = %p\n", - wine_dbgstr_longlong(desc->llMemLength), desc->pbMemData); - if (desc->dwValidData & DMUS_OBJ_STREAM) - TRACE_(dmfile)(" - pStream = %p\n", desc->pStream); -} - - -/* RIFF format parsing */ -#define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD)) - -const char *debugstr_chunk(const struct chunk_entry *chunk) -{ - const char *type = ""; - - if (!chunk) - return "(null)"; - if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST) - type = wine_dbg_sprintf("type %s, ", debugstr_fourcc(chunk->type)); - return wine_dbg_sprintf("%s chunk, %ssize %lu", debugstr_fourcc(chunk->id), type, chunk->size); -} - -static HRESULT stream_read(IStream *stream, void *data, ULONG size) -{ - ULONG read; - HRESULT hr; - - hr = IStream_Read(stream, data, size, &read); - if (FAILED(hr)) - TRACE_(dmfile)("IStream_Read failed: %#lx\n", hr); - else if (!read && read < size) { - /* All or nothing: Handle a partial read due to end of stream as an error */ - TRACE_(dmfile)("Short read: %lu < %lu\n", read, size); - return E_FAIL; - } - - return hr; -} - -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) -{ - static const LARGE_INTEGER zero; - ULONGLONG ck_end = 0, p_end = 0; - HRESULT hr; - - hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &chunk->offset); - if (FAILED(hr)) - return hr; - assert(!(chunk->offset.QuadPart & 1)); - if (chunk->parent) { - p_end = chunk->parent->offset.QuadPart + CHUNK_HDR_SIZE + ((chunk->parent->size + 1) & ~1); - if (chunk->offset.QuadPart == p_end) - return S_FALSE; - ck_end = chunk->offset.QuadPart + CHUNK_HDR_SIZE; - if (ck_end > p_end) { - WARN_(dmfile)("No space for sub-chunk header in parent chunk: ends at offset %s > %s\n", - wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end)); - return E_FAIL; - } - } - - hr = stream_read(stream, chunk, CHUNK_HDR_SIZE); - if (hr != S_OK) - return hr; - if (chunk->parent) { - ck_end += (chunk->size + 1) & ~1; - if (ck_end > p_end) { - WARN_(dmfile)("No space for sub-chunk data in parent chunk: ends at offset %s > %s\n", - wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end)); - return E_FAIL; - } - } - - if (chunk->id == FOURCC_LIST || chunk->id == FOURCC_RIFF) { - hr = stream_read(stream, &chunk->type, sizeof(FOURCC)); - if (hr != S_OK) - return hr != S_FALSE ? hr : E_FAIL; - } - - TRACE_(dmfile)("Returning %s\n", debugstr_chunk(chunk)); - - return S_OK; -} - -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER end; - - end.QuadPart = (chunk->offset.QuadPart + CHUNK_HDR_SIZE + chunk->size + 1) & ~(ULONGLONG)1; - - return IStream_Seek(stream, end, STREAM_SEEK_SET, NULL); -} - -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) -{ - HRESULT hr; - - if (chunk->id) { - hr = stream_skip_chunk(stream, chunk); - if (FAILED(hr)) - return hr; - } - - return stream_get_chunk(stream, chunk); -} - -/* Reads chunk data of the form: - DWORD - size of array element - element[] - Array of elements - The caller needs to free() the array. -*/ -HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size) -{ - DWORD size; - HRESULT hr; - - *array = NULL; - *count = 0; - - if (chunk->size < sizeof(DWORD)) { - WARN_(dmfile)("%s: Too short to read element size\n", debugstr_chunk(chunk)); - return E_FAIL; - } - if (FAILED(hr = stream_read(stream, &size, sizeof(DWORD)))) - return hr; - if (size != elem_size) { - WARN_(dmfile)("%s: Array element size mismatch: got %lu, expected %lu\n", - debugstr_chunk(chunk), size, elem_size); - return DMUS_E_UNSUPPORTED_STREAM; - } - - *count = (chunk->size - sizeof(DWORD)) / elem_size; - size = *count * elem_size; - if (!(*array = malloc(size))) - return E_OUTOFMEMORY; - if (FAILED(hr = stream_read(stream, *array, size))) { - free(*array); - *array = NULL; - return hr; - } - - if (chunk->size > size + sizeof(DWORD)) { - WARN_(dmfile)("%s: Extraneous data at end of array\n", debugstr_chunk(chunk)); - stream_skip_chunk(stream, chunk); - return S_FALSE; - } - return S_OK; -} - -HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size) -{ - if (chunk->size != size) { - WARN_(dmfile)("Chunk %s (size %lu, offset %s) doesn't contains the expected data size %lu\n", - debugstr_fourcc(chunk->id), chunk->size, - wine_dbgstr_longlong(chunk->offset.QuadPart), size); - return E_FAIL; - } - return stream_read(stream, data, size); -} - -HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size) -{ - ULONG len; - HRESULT hr; - - hr = IStream_Read(stream, str, min(chunk->size, size), &len); - if (FAILED(hr)) - return hr; - - /* Don't assume the string is properly zero terminated */ - str[min(len, size - 1)] = 0; - - if (len < chunk->size) - return S_FALSE; - return S_OK; -} - - - -/* Generic IDirectMusicObject methods */ -static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface) -{ - return CONTAINING_RECORD(iface, struct dmobject, IDirectMusicObject_iface); -} - -HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); -} - -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_AddRef(This->outer_unk); -} - -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_Release(This->outer_unk); -} - -HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - - TRACE("(%p/%p)->(%p)\n", iface, This, desc); - - if (!desc) - return E_POINTER; - - memcpy(desc, &This->desc, This->desc.dwSize); - - return S_OK; -} - -HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - HRESULT ret = S_OK; - - TRACE("(%p, %p)\n", iface, desc); - - if (!desc) - return E_POINTER; - - /* Immutable property */ - if (desc->dwValidData & DMUS_OBJ_CLASS) - { - desc->dwValidData &= ~DMUS_OBJ_CLASS; - ret = S_FALSE; - } - /* Set only valid fields */ - if (desc->dwValidData & DMUS_OBJ_OBJECT) - This->desc.guidObject = desc->guidObject; - if (desc->dwValidData & DMUS_OBJ_NAME) - lstrcpynW(This->desc.wszName, desc->wszName, DMUS_MAX_NAME); - if (desc->dwValidData & DMUS_OBJ_CATEGORY) - lstrcpynW(This->desc.wszCategory, desc->wszCategory, DMUS_MAX_CATEGORY); - if (desc->dwValidData & DMUS_OBJ_FILENAME) - lstrcpynW(This->desc.wszFileName, desc->wszFileName, DMUS_MAX_FILENAME); - if (desc->dwValidData & DMUS_OBJ_VERSION) - This->desc.vVersion = desc->vVersion; - if (desc->dwValidData & DMUS_OBJ_DATE) - This->desc.ftDate = desc->ftDate; - if (desc->dwValidData & DMUS_OBJ_MEMORY) { - This->desc.llMemLength = desc->llMemLength; - memcpy(This->desc.pbMemData, desc->pbMemData, desc->llMemLength); - } - if (desc->dwValidData & DMUS_OBJ_STREAM) - IStream_Clone(desc->pStream, &This->desc.pStream); - - This->desc.dwValidData |= desc->dwValidData; - - return ret; -} - -/* Helper for IDirectMusicObject::ParseDescriptor */ -static inline void info_get_name(IStream *stream, const struct chunk_entry *info, - DMUS_OBJECTDESC *desc) -{ - struct chunk_entry chunk = {.parent = info}; - char name[DMUS_MAX_NAME]; - ULONG len; - HRESULT hr = E_FAIL; - - while (stream_next_chunk(stream, &chunk) == S_OK) - if (chunk.id == mmioFOURCC('I','N','A','M')) - hr = IStream_Read(stream, name, min(chunk.size, sizeof(name)), &len); - - if (SUCCEEDED(hr)) { - len = MultiByteToWideChar(CP_ACP, 0, name, len, desc->wszName, sizeof(desc->wszName)); - desc->wszName[min(len, sizeof(desc->wszName) - 1)] = 0; - desc->dwValidData |= DMUS_OBJ_NAME; - } -} - -static inline void unfo_get_name(IStream *stream, const struct chunk_entry *unfo, - DMUS_OBJECTDESC *desc, BOOL inam) -{ - struct chunk_entry chunk = {.parent = unfo}; - - while (stream_next_chunk(stream, &chunk) == S_OK) - if (chunk.id == DMUS_FOURCC_UNAM_CHUNK || (inam && chunk.id == mmioFOURCC('I','N','A','M'))) - if (stream_chunk_get_wstr(stream, &chunk, desc->wszName, sizeof(desc->wszName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_NAME; -} - -HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported) -{ - struct chunk_entry chunk = {.parent = riff}; - HRESULT hr; - - TRACE("Looking for %#lx in %p: %s\n", supported, stream, debugstr_chunk(riff)); - - desc->dwValidData = 0; - desc->dwSize = sizeof(*desc); - - while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { - switch (chunk.id) { - case DMUS_FOURCC_CATEGORY_CHUNK: - if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk, - desc->wszCategory, sizeof(desc->wszCategory)) == S_OK) - desc->dwValidData |= DMUS_OBJ_CATEGORY; - break; - case DMUS_FOURCC_DATE_CHUNK: - if ((supported & DMUS_OBJ_DATE) && stream_chunk_get_data(stream, &chunk, - &desc->ftDate, sizeof(desc->ftDate)) == S_OK) - desc->dwValidData |= DMUS_OBJ_DATE; - break; - case DMUS_FOURCC_FILE_CHUNK: - if ((supported & DMUS_OBJ_FILENAME) && stream_chunk_get_wstr(stream, &chunk, - desc->wszFileName, sizeof(desc->wszFileName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_FILENAME; - break; - case DMUS_FOURCC_GUID_CHUNK: - if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk, - &desc->guidObject, sizeof(desc->guidObject)) == S_OK) - desc->dwValidData |= DMUS_OBJ_OBJECT; - break; - case DMUS_FOURCC_NAME_CHUNK: - if ((supported & DMUS_OBJ_NAME) && stream_chunk_get_wstr(stream, &chunk, - desc->wszName, sizeof(desc->wszName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_NAME; - break; - case DMUS_FOURCC_VERSION_CHUNK: - if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk, - &desc->vVersion, sizeof(desc->vVersion)) == S_OK) - desc->dwValidData |= DMUS_OBJ_VERSION; - break; - case FOURCC_LIST: - if (chunk.type == DMUS_FOURCC_UNFO_LIST && (supported & DMUS_OBJ_NAME)) - unfo_get_name(stream, &chunk, desc, supported & DMUS_OBJ_NAME_INAM); - else if (chunk.type == DMUS_FOURCC_INFO_LIST && (supported & DMUS_OBJ_NAME_INFO)) - info_get_name(stream, &chunk, desc); - break; - } - } - TRACE("Found %#lx\n", desc->dwValidData); - - return hr; -} - -HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj) -{ - struct chunk_entry chunk = {.parent = list}; - IDirectMusicGetLoader *getloader; - IDirectMusicLoader *loader; - DMUS_OBJECTDESC desc; - DMUS_IO_REFERENCE reference; - HRESULT hr; - - if (FAILED(hr = stream_next_chunk(stream, &chunk))) - return hr; - if (chunk.id != DMUS_FOURCC_REF_CHUNK) - return DMUS_E_UNSUPPORTED_STREAM; - - if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &reference, sizeof(reference)))) { - WARN("Failed to read data of %s\n", debugstr_chunk(&chunk)); - return hr; - } - TRACE("REFERENCE guidClassID %s, dwValidData %#lx\n", debugstr_dmguid(&reference.guidClassID), - reference.dwValidData); - - if (FAILED(hr = dmobj_parsedescriptor(stream, list, &desc, reference.dwValidData))) - return hr; - desc.guidClass = reference.guidClassID; - desc.dwValidData |= DMUS_OBJ_CLASS; - dump_DMUS_OBJECTDESC(&desc); - - if (FAILED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getloader))) - return hr; - hr = IDirectMusicGetLoader_GetLoader(getloader, &loader); - IDirectMusicGetLoader_Release(getloader); - if (FAILED(hr)) - return hr; - - hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicObject, (void**)dmobj); - IDirectMusicLoader_Release(loader); - - return hr; -} - -/* Generic IPersistStream methods */ -static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface) -{ - return CONTAINING_RECORD(iface, struct dmobject, IPersistStream_iface); -} - -HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); -} - -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_AddRef(This->outer_unk); -} - -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_Release(This->outer_unk); -} - -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - - TRACE("(%p, %p)\n", This, class); - - if (!class) - return E_POINTER; - - *class = This->desc.guidClass; - - return S_OK; -} - -/* IPersistStream methods not implemented in native */ -HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) -{ - TRACE("(%p, %p): method not implemented\n", iface, class); - return E_NOTIMPL; -} - -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface) -{ - TRACE("(%p): method not implemented, always returning S_FALSE\n", iface); - return S_FALSE; -} - -HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty) -{ - TRACE("(%p, %p, %d): method not implemented\n", iface, stream, clear_dirty); - return E_NOTIMPL; -} - -HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, ULARGE_INTEGER *size) -{ - TRACE("(%p, %p): method not implemented\n", iface, size); - return E_NOTIMPL; -} - - -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk) -{ - dmobj->outer_unk = outer_unk; - dmobj->desc.dwSize = sizeof(dmobj->desc); - dmobj->desc.dwValidData = DMUS_OBJ_CLASS; - dmobj->desc.guidClass = *class; -} diff --git a/dlls/dmstyle/dmobject.h b/dlls/dmstyle/dmobject.h deleted file mode 100644 index 772be015c80..00000000000 --- a/dlls/dmstyle/dmobject.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Base IDirectMusicObject Implementation - * Keep in sync with the master in dlls/dmusic/dmobject.h - * - * Copyright (C) 2014 Michael Stefaniuc - * - * This program 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 program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "wine/debug.h" - -/* RIFF stream parsing */ -struct chunk_entry; -struct chunk_entry { - FOURCC id; - DWORD size; - FOURCC type; /* valid only for LIST and RIFF chunks */ - ULARGE_INTEGER offset; /* chunk offset from start of stream */ - const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */ -}; - -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk); -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk); -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk); - -HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size); -HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size); -HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size); - -static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER offset; - - offset.QuadPart = chunk->offset.QuadPart + sizeof(FOURCC) + sizeof(DWORD); - if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST) - offset.QuadPart += sizeof(FOURCC); - - return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); -} - -static inline HRESULT stream_reset_chunk_start(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER offset; - - offset.QuadPart = chunk->offset.QuadPart; - - return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); -} - - -/* IDirectMusicObject base object */ -struct dmobject { - IDirectMusicObject IDirectMusicObject_iface; - IPersistStream IPersistStream_iface; - IUnknown *outer_unk; - DMUS_OBJECTDESC desc; -}; - -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk); - -/* Generic IDirectMusicObject methods */ -HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface); -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface); -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface); -HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc); -HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc); - -/* Helper for IDirectMusicObject::ParseDescriptor */ -HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported); -/* Additional supported flags for dmobj_parsedescriptor. - DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */ -#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */ -#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */ - -/* 'DMRF' (reference list) helper */ -HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj); - -/* Generic IPersistStream methods */ -HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface); -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface); -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface); -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class); - -/* IPersistStream methods not implemented in native */ -HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, - CLSID *class); -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface); -HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty); -HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, - ULARGE_INTEGER *size); - -/* Debugging helpers */ -const char *debugstr_chunk(const struct chunk_entry *chunk); -const char *debugstr_dmguid(const GUID *id); -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc); - -static inline const char *debugstr_fourcc(DWORD fourcc) -{ - if (!fourcc) return "''"; - return wine_dbg_sprintf("'%c%c%c%c'", (char)(fourcc), (char)(fourcc >> 8), - (char)(fourcc >> 16), (char)(fourcc >> 24)); -} From b983e6c43f70e010b4caa65b42090b2d24672f43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 22:18:52 +0200 Subject: [PATCH 2491/2777] dmime: Remove FIXME from performance IDirectMusicGraph methods. (cherry picked from commit 4cb46f1bed7a08838b70626b5dd2248a9f81cb67) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 1f8de0837d5..fee3590c19f 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1301,21 +1301,21 @@ static HRESULT WINAPI performance_graph_InsertTool(IDirectMusicGraph *iface, IDi DWORD *channels, DWORD channels_count, LONG index) { struct performance *This = impl_from_IDirectMusicGraph(iface); - FIXME("(%p, %p, %p, %lu, %ld): stub\n", This, tool, channels, channels_count, index); + TRACE("(%p, %p, %p, %lu, %ld)\n", This, tool, channels, channels_count, index); return E_NOTIMPL; } static HRESULT WINAPI performance_graph_GetTool(IDirectMusicGraph *iface, DWORD index, IDirectMusicTool **tool) { struct performance *This = impl_from_IDirectMusicGraph(iface); - FIXME("(%p, %lu, %p): stub\n", This, index, tool); + TRACE("(%p, %lu, %p)\n", This, index, tool); return E_NOTIMPL; } static HRESULT WINAPI performance_graph_RemoveTool(IDirectMusicGraph *iface, IDirectMusicTool *tool) { struct performance *This = impl_from_IDirectMusicGraph(iface); - FIXME("(%p, %p): stub\n", This, tool); + TRACE("(%p, %p)\n", This, tool); return E_NOTIMPL; } From 13fea6ebab1838abc8d442b77ef3507798a84b5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 22:11:54 +0200 Subject: [PATCH 2492/2777] dmime: Implement some performance IDirectMusicTool methods. (cherry picked from commit 1e70dbcfc2630bc6e7d8b7cdc297c345269c6aec) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 14 ++++++++------ dlls/dmime/tests/dmime.c | 8 ++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index fee3590c19f..4085f70cc77 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1356,28 +1356,30 @@ static ULONG WINAPI performance_tool_Release(IDirectMusicTool *iface) static HRESULT WINAPI performance_tool_Init(IDirectMusicTool *iface, IDirectMusicGraph *graph) { struct performance *This = impl_from_IDirectMusicTool(iface); - FIXME("(%p, %p): stub\n", This, graph); + TRACE("(%p, %p)\n", This, graph); return E_NOTIMPL; } static HRESULT WINAPI performance_tool_GetMsgDeliveryType(IDirectMusicTool *iface, DWORD *type) { struct performance *This = impl_from_IDirectMusicTool(iface); - FIXME("(%p, %p): stub\n", This, type); - return E_NOTIMPL; + TRACE("(%p, %p)\n", This, type); + *type = DMUS_PMSGF_TOOL_IMMEDIATE; + return S_OK; } static HRESULT WINAPI performance_tool_GetMediaTypeArraySize(IDirectMusicTool *iface, DWORD *size) { struct performance *This = impl_from_IDirectMusicTool(iface); - FIXME("(%p, %p): stub\n", This, size); - return E_NOTIMPL; + TRACE("(%p, %p)\n", This, size); + *size = 0; + return S_OK; } static HRESULT WINAPI performance_tool_GetMediaTypes(IDirectMusicTool *iface, DWORD **types, DWORD size) { struct performance *This = impl_from_IDirectMusicTool(iface); - FIXME("(%p, %p, %lu): stub\n", This, types, size); + TRACE("(%p, %p, %lu)\n", This, types, size); return E_NOTIMPL; } diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 0aeed24b200..3d9eb188fed 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -1497,12 +1497,12 @@ static void test_performance_tool(void) ok(hr == E_NOTIMPL, "got %#lx\n", hr); value = 0xdeadbeef; hr = IDirectMusicTool_GetMsgDeliveryType(tool, &value); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(value == DMUS_PMSGF_TOOL_IMMEDIATE, "got %#lx\n", value); + ok(hr == S_OK, "got %#lx\n", hr); + ok(value == DMUS_PMSGF_TOOL_IMMEDIATE, "got %#lx\n", value); value = 0xdeadbeef; hr = IDirectMusicTool_GetMediaTypeArraySize(tool, &value); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(value == 0, "got %#lx\n", value); + ok(hr == S_OK, "got %#lx\n", hr); + ok(value == 0, "got %#lx\n", value); hr = IDirectMusicTool_GetMediaTypes(tool, (DWORD **)&types, 64); ok(hr == E_NOTIMPL, "got %#lx\n", hr); hr = IDirectMusicTool_ProcessPMsg(tool, performance, &msg); From db3ce2eef48a3dd488068726417f10a429810317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 22:27:39 +0200 Subject: [PATCH 2493/2777] dmime: Rewrite IDirectMusicGraph tools iteration. (cherry picked from commit d8bce981d7f320987f32f57168614245314932d1) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/dmime_private.h | 6 -- dlls/dmime/graph.c | 118 ++++++++++++++++++++----------------- dlls/dmime/tests/dmime.c | 22 +++---- 3 files changed, 76 insertions(+), 70 deletions(-) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 6102fd5ec2f..28b0afc9af8 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -86,12 +86,6 @@ typedef struct _DMUS_PRIVATE_TEMPO_ITEM { DMUS_IO_TEMPO_ITEM item; } DMUS_PRIVATE_TEMPO_ITEM, *LPDMUS_PRIVATE_TEMPO_ITEM; -typedef struct _DMUS_PRIVATE_GRAPH_TOOL { - struct list entry; /* for listing elements */ - DWORD dwIndex; - IDirectMusicTool* pTool; -} DMUS_PRIVATE_GRAPH_TOOL, *LPDMUS_PRIVATE_GRAPH_TOOL; - typedef struct _DMUS_PRIVATE_TEMPO_PLAY_STATE { DWORD dummy; } DMUS_PRIVATE_TEMPO_PLAY_STATE, *LPDMUS_PRIVATE_TEMPO_PLAY_STATE; diff --git a/dlls/dmime/graph.c b/dlls/dmime/graph.c index 159923b6a70..20d614b95ff 100644 --- a/dlls/dmime/graph.c +++ b/dlls/dmime/graph.c @@ -22,12 +22,18 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmime); +struct tool_entry +{ + struct list entry; + IDirectMusicTool *tool; +}; + struct IDirectMusicGraphImpl { IDirectMusicGraph IDirectMusicGraph_iface; struct dmobject dmobj; LONG ref; - WORD num_tools; - struct list Tools; + + struct list tools; }; static inline IDirectMusicGraphImpl *impl_from_IDirectMusicGraph(IDirectMusicGraph *iface) @@ -85,7 +91,19 @@ static ULONG WINAPI DirectMusicGraph_Release(IDirectMusicGraph *iface) TRACE("(%p): %ld\n", This, ref); - if (!ref) free(This); + if (!ref) + { + struct tool_entry *entry, *next; + + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &This->tools, struct tool_entry, entry) + { + list_remove(&entry->entry); + IDirectMusicTool_Release(entry->tool); + free(entry); + } + + free(This); + } return ref; } @@ -97,80 +115,74 @@ static HRESULT WINAPI DirectMusicGraph_StampPMsg(IDirectMusicGraph *iface, DMUS_ return S_OK; } -static HRESULT WINAPI DirectMusicGraph_InsertTool(IDirectMusicGraph *iface, IDirectMusicTool* pTool, DWORD* pdwPChannels, DWORD cPChannels, LONG lIndex) +static HRESULT WINAPI DirectMusicGraph_InsertTool(IDirectMusicGraph *iface, IDirectMusicTool *tool, + DWORD *channels, DWORD channel_count, LONG index) { IDirectMusicGraphImpl *This = impl_from_IDirectMusicGraph(iface); - struct list* pEntry = NULL; - struct list* pPrevEntry = NULL; - LPDMUS_PRIVATE_GRAPH_TOOL pIt = NULL; - LPDMUS_PRIVATE_GRAPH_TOOL pNewTool = NULL; - - FIXME("(%p, %p, %p, %ld, %li): use of pdwPChannels\n", This, pTool, pdwPChannels, cPChannels, lIndex); - - if (!pTool) - return E_POINTER; + struct tool_entry *entry, *next; - if (lIndex < 0) - lIndex = This->num_tools + lIndex; + TRACE("(%p, %p, %p, %ld, %li)\n", This, tool, channels, channel_count, index); - pPrevEntry = &This->Tools; - LIST_FOR_EACH(pEntry, &This->Tools) - { - pIt = LIST_ENTRY(pEntry, DMUS_PRIVATE_GRAPH_TOOL, entry); - if (pIt->dwIndex == lIndex) - return DMUS_E_ALREADY_EXISTS; + if (!tool) return E_POINTER; - if (pIt->dwIndex > lIndex) - break ; - pPrevEntry = pEntry; + LIST_FOR_EACH_ENTRY(next, &This->tools, struct tool_entry, entry) + { + if (next->tool == tool) return DMUS_E_ALREADY_EXISTS; + if (index-- <= 0) break; } - ++This->num_tools; - pNewTool = calloc(1, sizeof(*pNewTool)); - pNewTool->pTool = pTool; - pNewTool->dwIndex = lIndex; - IDirectMusicTool_AddRef(pTool); - IDirectMusicTool_Init(pTool, iface); - list_add_tail (pPrevEntry->next, &pNewTool->entry); - -#if 0 - DWORD dwNum = 0; - IDirectMusicTool8_GetMediaTypes(pTool, &dwNum); -#endif + if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY; + entry->tool = tool; + IDirectMusicTool_AddRef(tool); + IDirectMusicTool_Init(tool, iface); + list_add_before(&next->entry, &entry->entry); - return DS_OK; + return S_OK; } -static HRESULT WINAPI DirectMusicGraph_GetTool(IDirectMusicGraph *iface, DWORD dwIndex, IDirectMusicTool** ppTool) +static HRESULT WINAPI DirectMusicGraph_GetTool(IDirectMusicGraph *iface, DWORD index, IDirectMusicTool **ret_tool) { IDirectMusicGraphImpl *This = impl_from_IDirectMusicGraph(iface); - struct list* pEntry = NULL; - LPDMUS_PRIVATE_GRAPH_TOOL pIt = NULL; + struct tool_entry *entry; + + TRACE("(%p, %ld, %p)\n", This, index, ret_tool); - TRACE("(%p, %ld, %p)\n", This, dwIndex, ppTool); + if (!ret_tool) return E_POINTER; - LIST_FOR_EACH (pEntry, &This->Tools) + LIST_FOR_EACH_ENTRY(entry, &This->tools, struct tool_entry, entry) { - pIt = LIST_ENTRY(pEntry, DMUS_PRIVATE_GRAPH_TOOL, entry); - if (pIt->dwIndex == dwIndex) + if (!index--) { - *ppTool = pIt->pTool; - if (*ppTool) - IDirectMusicTool_AddRef(*ppTool); + *ret_tool = entry->tool; + IDirectMusicTool_AddRef(entry->tool); return S_OK; } - if (pIt->dwIndex > dwIndex) - break ; } return DMUS_E_NOT_FOUND; } -static HRESULT WINAPI DirectMusicGraph_RemoveTool(IDirectMusicGraph *iface, IDirectMusicTool* pTool) +static HRESULT WINAPI DirectMusicGraph_RemoveTool(IDirectMusicGraph *iface, IDirectMusicTool *tool) { IDirectMusicGraphImpl *This = impl_from_IDirectMusicGraph(iface); - FIXME("(%p, %p): stub\n", This, pTool); - return S_OK; + struct tool_entry *entry; + + TRACE("(%p, %p)\n", This, tool); + + if (!tool) return E_POINTER; + + LIST_FOR_EACH_ENTRY(entry, &This->tools, struct tool_entry, entry) + { + if (entry->tool == tool) + { + list_remove(&entry->entry); + IDirectMusicTool_Release(entry->tool); + free(entry); + return S_OK; + } + } + + return DMUS_E_NOT_FOUND; } static const IDirectMusicGraphVtbl DirectMusicGraphVtbl = @@ -260,7 +272,7 @@ HRESULT create_dmgraph(REFIID riid, void **ret_iface) dmobject_init(&obj->dmobj, &CLSID_DirectMusicGraph, (IUnknown *)&obj->IDirectMusicGraph_iface); obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl; obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - list_init(&obj->Tools); + list_init(&obj->tools); hr = IDirectMusicGraph_QueryInterface(&obj->IDirectMusicGraph_iface, riid, ret_iface); IDirectMusicGraph_Release(&obj->IDirectMusicGraph_iface); diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 3d9eb188fed..605830149e7 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -705,10 +705,10 @@ static void test_graph(void) ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicGraph_GetTool(graph, 0, NULL); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); hr = IDirectMusicGraph_GetTool(graph, 0, &tmp_tool); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(tool1 == tmp_tool, "got %p\n", tmp_tool); + ok(hr == S_OK, "got %#lx\n", hr); + ok(tool1 == tmp_tool, "got %p\n", tmp_tool); if (hr == S_OK) IDirectMusicTool_Release(tmp_tool); hr = IDirectMusicGraph_GetTool(graph, 1, &tmp_tool); ok(hr == S_OK, "got %#lx\n", hr); @@ -723,24 +723,24 @@ static void test_graph(void) /* test removing the first tool */ hr = IDirectMusicGraph_RemoveTool(graph, NULL); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); hr = IDirectMusicGraph_RemoveTool(graph, tool1); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicGraph_RemoveTool(graph, tool1); - todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); + ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); hr = IDirectMusicGraph_GetTool(graph, 0, &tmp_tool); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); ok(tool2 == tmp_tool, "got %p\n", tmp_tool); if (hr == S_OK) IDirectMusicTool_Release(tmp_tool); hr = IDirectMusicGraph_GetTool(graph, 1, &tmp_tool); - todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); + ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); hr = IDirectMusicGraph_InsertTool(graph, tool1, NULL, 0, -1); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicGraph_GetTool(graph, 0, &tmp_tool); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(tool1 == tmp_tool, "got %p\n", tmp_tool); + ok(hr == S_OK, "got %#lx\n", hr); + ok(tool1 == tmp_tool, "got %p\n", tmp_tool); if (hr == S_OK) IDirectMusicTool_Release(tmp_tool); @@ -810,7 +810,7 @@ static void test_graph(void) hr = IDirectMusicGraph_InsertTool(tmp_graph, tool1, NULL, 0, 0); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicGraph_InsertTool(tmp_graph, tool2, NULL, 0, 0); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicGraph_StampPMsg(tmp_graph, &msg); ok(hr == S_OK, "got %#lx\n", hr); ok(msg.pGraph == graph, "got %p\n", msg.pGraph); From b8e0a4f667a7385eeeb7b463b48c1c623754576e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 12 Sep 2023 10:06:57 +0200 Subject: [PATCH 2494/2777] dmime: Rename DirectMusicGraph method prefix to graph. (cherry picked from commit fec9d2c22e534996a2c48069cb990b7452cdc89e) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/graph.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/dlls/dmime/graph.c b/dlls/dmime/graph.c index 20d614b95ff..2e548690a96 100644 --- a/dlls/dmime/graph.c +++ b/dlls/dmime/graph.c @@ -46,7 +46,7 @@ static inline IDirectMusicGraphImpl *impl_from_IPersistStream(IPersistStream *if return CONTAINING_RECORD(iface, IDirectMusicGraphImpl, dmobj.IPersistStream_iface); } -static HRESULT WINAPI DirectMusicGraph_QueryInterface(IDirectMusicGraph *iface, REFIID riid, void **ret_iface) +static HRESULT WINAPI graph_QueryInterface(IDirectMusicGraph *iface, REFIID riid, void **ret_iface) { IDirectMusicGraphImpl *This = impl_from_IDirectMusicGraph(iface); @@ -74,7 +74,7 @@ static HRESULT WINAPI DirectMusicGraph_QueryInterface(IDirectMusicGraph *iface, return E_NOINTERFACE; } -static ULONG WINAPI DirectMusicGraph_AddRef(IDirectMusicGraph *iface) +static ULONG WINAPI graph_AddRef(IDirectMusicGraph *iface) { IDirectMusicGraphImpl *This = impl_from_IDirectMusicGraph(iface); ULONG ref = InterlockedIncrement(&This->ref); @@ -84,7 +84,7 @@ static ULONG WINAPI DirectMusicGraph_AddRef(IDirectMusicGraph *iface) return ref; } -static ULONG WINAPI DirectMusicGraph_Release(IDirectMusicGraph *iface) +static ULONG WINAPI graph_Release(IDirectMusicGraph *iface) { IDirectMusicGraphImpl *This = impl_from_IDirectMusicGraph(iface); ULONG ref = InterlockedDecrement(&This->ref); @@ -108,14 +108,14 @@ static ULONG WINAPI DirectMusicGraph_Release(IDirectMusicGraph *iface) return ref; } -static HRESULT WINAPI DirectMusicGraph_StampPMsg(IDirectMusicGraph *iface, DMUS_PMSG *msg) +static HRESULT WINAPI graph_StampPMsg(IDirectMusicGraph *iface, DMUS_PMSG *msg) { IDirectMusicGraphImpl *This = impl_from_IDirectMusicGraph(iface); FIXME("(%p, %p): stub\n", This, msg); return S_OK; } -static HRESULT WINAPI DirectMusicGraph_InsertTool(IDirectMusicGraph *iface, IDirectMusicTool *tool, +static HRESULT WINAPI graph_InsertTool(IDirectMusicGraph *iface, IDirectMusicTool *tool, DWORD *channels, DWORD channel_count, LONG index) { IDirectMusicGraphImpl *This = impl_from_IDirectMusicGraph(iface); @@ -140,7 +140,7 @@ static HRESULT WINAPI DirectMusicGraph_InsertTool(IDirectMusicGraph *iface, IDir return S_OK; } -static HRESULT WINAPI DirectMusicGraph_GetTool(IDirectMusicGraph *iface, DWORD index, IDirectMusicTool **ret_tool) +static HRESULT WINAPI graph_GetTool(IDirectMusicGraph *iface, DWORD index, IDirectMusicTool **ret_tool) { IDirectMusicGraphImpl *This = impl_from_IDirectMusicGraph(iface); struct tool_entry *entry; @@ -162,7 +162,7 @@ static HRESULT WINAPI DirectMusicGraph_GetTool(IDirectMusicGraph *iface, DWORD i return DMUS_E_NOT_FOUND; } -static HRESULT WINAPI DirectMusicGraph_RemoveTool(IDirectMusicGraph *iface, IDirectMusicTool *tool) +static HRESULT WINAPI graph_RemoveTool(IDirectMusicGraph *iface, IDirectMusicTool *tool) { IDirectMusicGraphImpl *This = impl_from_IDirectMusicGraph(iface); struct tool_entry *entry; @@ -185,15 +185,15 @@ static HRESULT WINAPI DirectMusicGraph_RemoveTool(IDirectMusicGraph *iface, IDir return DMUS_E_NOT_FOUND; } -static const IDirectMusicGraphVtbl DirectMusicGraphVtbl = +static const IDirectMusicGraphVtbl graph_vtbl = { - DirectMusicGraph_QueryInterface, - DirectMusicGraph_AddRef, - DirectMusicGraph_Release, - DirectMusicGraph_StampPMsg, - DirectMusicGraph_InsertTool, - DirectMusicGraph_GetTool, - DirectMusicGraph_RemoveTool + graph_QueryInterface, + graph_AddRef, + graph_Release, + graph_StampPMsg, + graph_InsertTool, + graph_GetTool, + graph_RemoveTool, }; static HRESULT WINAPI graph_IDirectMusicObject_ParseDescriptor(IDirectMusicObject *iface, @@ -267,7 +267,7 @@ HRESULT create_dmgraph(REFIID riid, void **ret_iface) *ret_iface = NULL; if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; - obj->IDirectMusicGraph_iface.lpVtbl = &DirectMusicGraphVtbl; + obj->IDirectMusicGraph_iface.lpVtbl = &graph_vtbl; obj->ref = 1; dmobject_init(&obj->dmobj, &CLSID_DirectMusicGraph, (IUnknown *)&obj->IDirectMusicGraph_iface); obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl; From b8a7401b3d4938a6286b9562bb59eb34f473eba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 22:37:56 +0200 Subject: [PATCH 2495/2777] dmime: Get rid of the IDirectMusicGraphImpl typedef. (cherry picked from commit 5d97483f2252bd37db0762b94af8843c1ba01262) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/audiopath.c | 12 ++++++------ dlls/dmime/dmime_private.h | 1 - dlls/dmime/graph.c | 37 +++++++++++++++++++------------------ 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/dlls/dmime/audiopath.c b/dlls/dmime/audiopath.c index 013939f9dfa..aef48a5d2db 100644 --- a/dlls/dmime/audiopath.c +++ b/dlls/dmime/audiopath.c @@ -158,11 +158,11 @@ static HRESULT WINAPI IDirectMusicAudioPathImpl_GetObjectInPath (IDirectMusicAud { if (IsEqualIID (iidInterface, &IID_IDirectMusicGraph)) { if (NULL == This->pToolGraph) { - IDirectMusicGraphImpl* pGraph; + IDirectMusicGraph* pGraph; hr = create_dmgraph(&IID_IDirectMusicGraph, (void**)&pGraph); if (FAILED(hr)) return hr; - This->pToolGraph = (IDirectMusicGraph*) pGraph; + This->pToolGraph = pGraph; } *ppObject = This->pToolGraph; IDirectMusicGraph_AddRef((LPDIRECTMUSICGRAPH) *ppObject); @@ -191,14 +191,14 @@ static HRESULT WINAPI IDirectMusicAudioPathImpl_GetObjectInPath (IDirectMusicAud IDirectMusicGraph* pPerfoGraph = NULL; IDirectMusicPerformance8_GetGraph(This->pPerf, &pPerfoGraph); if (NULL == pPerfoGraph) { - IDirectMusicGraphImpl* pGraph = NULL; + IDirectMusicGraph* pGraph = NULL; hr = create_dmgraph(&IID_IDirectMusicGraph, (void**)&pGraph); if (FAILED(hr)) return hr; - IDirectMusicPerformance8_SetGraph(This->pPerf, (IDirectMusicGraph*) pGraph); + IDirectMusicPerformance8_SetGraph(This->pPerf, pGraph); /* we need release as SetGraph do an AddRef */ - IDirectMusicGraph_Release((LPDIRECTMUSICGRAPH) pGraph); - pPerfoGraph = (LPDIRECTMUSICGRAPH) pGraph; + IDirectMusicGraph_Release(pGraph); + pPerfoGraph = pGraph; } *ppObject = pPerfoGraph; return S_OK; diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 28b0afc9af8..be0c463339f 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -45,7 +45,6 @@ /***************************************************************************** * Interfaces */ -typedef struct IDirectMusicGraphImpl IDirectMusicGraphImpl; typedef struct IDirectMusicAudioPathImpl IDirectMusicAudioPathImpl; /***************************************************************************** diff --git a/dlls/dmime/graph.c b/dlls/dmime/graph.c index 2e548690a96..1e6f16b6be0 100644 --- a/dlls/dmime/graph.c +++ b/dlls/dmime/graph.c @@ -28,27 +28,28 @@ struct tool_entry IDirectMusicTool *tool; }; -struct IDirectMusicGraphImpl { - IDirectMusicGraph IDirectMusicGraph_iface; - struct dmobject dmobj; - LONG ref; +struct graph +{ + IDirectMusicGraph IDirectMusicGraph_iface; + struct dmobject dmobj; + LONG ref; - struct list tools; + struct list tools; }; -static inline IDirectMusicGraphImpl *impl_from_IDirectMusicGraph(IDirectMusicGraph *iface) +static inline struct graph *impl_from_IDirectMusicGraph(IDirectMusicGraph *iface) { - return CONTAINING_RECORD(iface, IDirectMusicGraphImpl, IDirectMusicGraph_iface); + return CONTAINING_RECORD(iface, struct graph, IDirectMusicGraph_iface); } -static inline IDirectMusicGraphImpl *impl_from_IPersistStream(IPersistStream *iface) +static inline struct graph *impl_from_IPersistStream(IPersistStream *iface) { - return CONTAINING_RECORD(iface, IDirectMusicGraphImpl, dmobj.IPersistStream_iface); + return CONTAINING_RECORD(iface, struct graph, dmobj.IPersistStream_iface); } static HRESULT WINAPI graph_QueryInterface(IDirectMusicGraph *iface, REFIID riid, void **ret_iface) { - IDirectMusicGraphImpl *This = impl_from_IDirectMusicGraph(iface); + struct graph *This = impl_from_IDirectMusicGraph(iface); TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ret_iface); @@ -76,7 +77,7 @@ static HRESULT WINAPI graph_QueryInterface(IDirectMusicGraph *iface, REFIID riid static ULONG WINAPI graph_AddRef(IDirectMusicGraph *iface) { - IDirectMusicGraphImpl *This = impl_from_IDirectMusicGraph(iface); + struct graph *This = impl_from_IDirectMusicGraph(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p): %ld\n", This, ref); @@ -86,7 +87,7 @@ static ULONG WINAPI graph_AddRef(IDirectMusicGraph *iface) static ULONG WINAPI graph_Release(IDirectMusicGraph *iface) { - IDirectMusicGraphImpl *This = impl_from_IDirectMusicGraph(iface); + struct graph *This = impl_from_IDirectMusicGraph(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p): %ld\n", This, ref); @@ -110,7 +111,7 @@ static ULONG WINAPI graph_Release(IDirectMusicGraph *iface) static HRESULT WINAPI graph_StampPMsg(IDirectMusicGraph *iface, DMUS_PMSG *msg) { - IDirectMusicGraphImpl *This = impl_from_IDirectMusicGraph(iface); + struct graph *This = impl_from_IDirectMusicGraph(iface); FIXME("(%p, %p): stub\n", This, msg); return S_OK; } @@ -118,7 +119,7 @@ static HRESULT WINAPI graph_StampPMsg(IDirectMusicGraph *iface, DMUS_PMSG *msg) static HRESULT WINAPI graph_InsertTool(IDirectMusicGraph *iface, IDirectMusicTool *tool, DWORD *channels, DWORD channel_count, LONG index) { - IDirectMusicGraphImpl *This = impl_from_IDirectMusicGraph(iface); + struct graph *This = impl_from_IDirectMusicGraph(iface); struct tool_entry *entry, *next; TRACE("(%p, %p, %p, %ld, %li)\n", This, tool, channels, channel_count, index); @@ -142,7 +143,7 @@ static HRESULT WINAPI graph_InsertTool(IDirectMusicGraph *iface, IDirectMusicToo static HRESULT WINAPI graph_GetTool(IDirectMusicGraph *iface, DWORD index, IDirectMusicTool **ret_tool) { - IDirectMusicGraphImpl *This = impl_from_IDirectMusicGraph(iface); + struct graph *This = impl_from_IDirectMusicGraph(iface); struct tool_entry *entry; TRACE("(%p, %ld, %p)\n", This, index, ret_tool); @@ -164,7 +165,7 @@ static HRESULT WINAPI graph_GetTool(IDirectMusicGraph *iface, DWORD index, IDire static HRESULT WINAPI graph_RemoveTool(IDirectMusicGraph *iface, IDirectMusicTool *tool) { - IDirectMusicGraphImpl *This = impl_from_IDirectMusicGraph(iface); + struct graph *This = impl_from_IDirectMusicGraph(iface); struct tool_entry *entry; TRACE("(%p, %p)\n", This, tool); @@ -240,7 +241,7 @@ static const IDirectMusicObjectVtbl dmobject_vtbl = { static HRESULT WINAPI graph_IPersistStream_Load(IPersistStream *iface, IStream *stream) { - IDirectMusicGraphImpl *This = impl_from_IPersistStream(iface); + struct graph *This = impl_from_IPersistStream(iface); FIXME("(%p, %p): Loading not implemented yet\n", This, stream); @@ -262,7 +263,7 @@ static const IPersistStreamVtbl persiststream_vtbl = { /* for ClassFactory */ HRESULT create_dmgraph(REFIID riid, void **ret_iface) { - IDirectMusicGraphImpl* obj; + struct graph *obj; HRESULT hr; *ret_iface = NULL; From 409487672b9d3d3b8603933478473661770a1594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 22:41:39 +0200 Subject: [PATCH 2496/2777] dmime: Implement IDirectMusicGraph_StampPMsg. (cherry picked from commit 98db0c753aa4478d2ae7efdee3e3286ee02a9518) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/graph.c | 29 ++++++++++++++++++++++++++++- dlls/dmime/tests/dmime.c | 38 +++++++++++++++++++------------------- 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/dlls/dmime/graph.c b/dlls/dmime/graph.c index 1e6f16b6be0..44996b0303e 100644 --- a/dlls/dmime/graph.c +++ b/dlls/dmime/graph.c @@ -112,7 +112,34 @@ static ULONG WINAPI graph_Release(IDirectMusicGraph *iface) static HRESULT WINAPI graph_StampPMsg(IDirectMusicGraph *iface, DMUS_PMSG *msg) { struct graph *This = impl_from_IDirectMusicGraph(iface); - FIXME("(%p, %p): stub\n", This, msg); + struct tool_entry *entry, *next, *first; + + TRACE("(%p, %p)\n", This, msg); + + if (!msg) return E_POINTER; + + first = LIST_ENTRY(This->tools.next, struct tool_entry, entry); + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &This->tools, struct tool_entry, entry) + if (entry->tool == msg->pTool) break; + if (&entry->entry == &This->tools) next = first; + + if (msg->pTool) + { + IDirectMusicTool_Release(msg->pTool); + msg->pTool = NULL; + } + + if (&next->entry == &This->tools) return DMUS_S_LAST_TOOL; + + if (!msg->pGraph) + { + msg->pGraph = iface; + IDirectMusicGraph_AddRef(msg->pGraph); + } + + msg->pTool = next->tool; + IDirectMusicTool_AddRef(msg->pTool); + return S_OK; } diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 605830149e7..c9c613a40c5 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -746,12 +746,12 @@ static void test_graph(void) /* Test basic IDirectMusicGraph_StampPMsg usage */ hr = IDirectMusicGraph_StampPMsg(graph, NULL); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); memset(&msg, 0, sizeof(msg)); hr = IDirectMusicGraph_StampPMsg(graph, &msg); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(msg.pGraph == graph, "got %p\n", msg.pGraph); - todo_wine ok(msg.pTool == tool1, "got %p\n", msg.pTool); + ok(msg.pGraph == graph, "got %p\n", msg.pGraph); + ok(msg.pTool == tool1, "got %p\n", msg.pTool); ok(!msg.dwSize, "got %ld\n", msg.dwSize); ok(!msg.rtTime, "got %I64d\n", msg.rtTime); @@ -766,19 +766,19 @@ static void test_graph(void) hr = IDirectMusicGraph_StampPMsg(graph, &msg); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(msg.pGraph == graph, "got %p\n", msg.pGraph); - todo_wine ok(msg.pTool == tool2, "got %p\n", msg.pTool); + ok(msg.pGraph == graph, "got %p\n", msg.pGraph); + ok(msg.pTool == tool2, "got %p\n", msg.pTool); hr = IDirectMusicGraph_StampPMsg(graph, &msg); - todo_wine ok(hr == DMUS_S_LAST_TOOL, "got %#lx\n", hr); - todo_wine ok(msg.pGraph == graph, "got %p\n", msg.pGraph); + ok(hr == DMUS_S_LAST_TOOL, "got %#lx\n", hr); + ok(msg.pGraph == graph, "got %p\n", msg.pGraph); ok(!msg.pTool, "got %p\n", msg.pTool); hr = IDirectMusicGraph_StampPMsg(graph, &msg); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(msg.pGraph == graph, "got %p\n", msg.pGraph); - todo_wine ok(msg.pTool == tool1, "got %p\n", msg.pTool); - if (msg.pGraph) IDirectMusicGraph_Release(msg.pGraph); + ok(msg.pGraph == graph, "got %p\n", msg.pGraph); + ok(msg.pTool == tool1, "got %p\n", msg.pTool); + IDirectMusicGraph_Release(msg.pGraph); msg.pGraph = NULL; - if (msg.pTool) IDirectMusicGraph_Release(msg.pTool); + IDirectMusicGraph_Release(msg.pTool); msg.pTool = NULL; @@ -794,16 +794,16 @@ static void test_graph(void) hr = IDirectMusicGraph_StampPMsg(graph, &msg); ok(hr == S_OK, "got %#lx\n", hr); ok(msg.pGraph == tmp_graph, "got %p\n", msg.pGraph); - todo_wine ok(msg.pTool == tool2, "got %p\n", msg.pTool); - if (msg.pGraph) IDirectMusicGraph_Release(msg.pGraph); + ok(msg.pTool == tool2, "got %p\n", msg.pTool); + IDirectMusicGraph_Release(msg.pGraph); msg.pGraph = NULL; msg.pGraph = graph; IDirectMusicGraph_AddRef(msg.pGraph); hr = IDirectMusicGraph_StampPMsg(tmp_graph, &msg); - todo_wine ok(hr == DMUS_S_LAST_TOOL, "got %#lx\n", hr); + ok(hr == DMUS_S_LAST_TOOL, "got %#lx\n", hr); ok(msg.pGraph == graph, "got %p\n", msg.pGraph); - todo_wine ok(msg.pTool == NULL, "got %p\n", msg.pTool); + ok(msg.pTool == NULL, "got %p\n", msg.pTool); msg.pTool = tool2; IDirectMusicTool_AddRef(msg.pTool); @@ -814,16 +814,16 @@ static void test_graph(void) hr = IDirectMusicGraph_StampPMsg(tmp_graph, &msg); ok(hr == S_OK, "got %#lx\n", hr); ok(msg.pGraph == graph, "got %p\n", msg.pGraph); - todo_wine ok(msg.pTool == tool1, "got %p\n", msg.pTool); - if (msg.pGraph) IDirectMusicGraph_Release(msg.pGraph); + ok(msg.pTool == tool1, "got %p\n", msg.pTool); + IDirectMusicGraph_Release(msg.pGraph); msg.pGraph = NULL; hr = IDirectMusicGraph_RemoveTool(graph, tool1); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicGraph_StampPMsg(tmp_graph, &msg); - todo_wine ok(hr == DMUS_S_LAST_TOOL, "got %#lx\n", hr); + ok(hr == DMUS_S_LAST_TOOL, "got %#lx\n", hr); ok(msg.pGraph == NULL, "got %p\n", msg.pGraph); - todo_wine ok(msg.pTool == NULL, "got %p\n", msg.pTool); + ok(msg.pTool == NULL, "got %p\n", msg.pTool); IDirectMusicGraph_Release(tmp_graph); From a672db3a6162bf11fbb2259099e6b9bf06f38505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 22:58:08 +0200 Subject: [PATCH 2497/2777] dmime: Implement performance IDirectMusicGraph_StampPMsg. (cherry picked from commit 09dc4a3f1739c2184695138a4c82b20954046c0c) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 33 +++++++++++++++++++++++++++++++-- dlls/dmime/tests/dmime.c | 34 +++++++++++++++++----------------- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 4085f70cc77..904008954a2 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1293,8 +1293,37 @@ static ULONG WINAPI performance_graph_Release(IDirectMusicGraph *iface) static HRESULT WINAPI performance_graph_StampPMsg(IDirectMusicGraph *iface, DMUS_PMSG *msg) { struct performance *This = impl_from_IDirectMusicGraph(iface); - FIXME("(%p, %p): stub\n", This, msg); - return E_NOTIMPL; + HRESULT hr; + + TRACE("(%p, %p)\n", This, msg); + + if (!msg) return E_POINTER; + + /* FIXME: Implement segment and audio path graphs support */ + if (!This->pToolGraph) hr = DMUS_S_LAST_TOOL; + else if (FAILED(hr = IDirectMusicGraph_StampPMsg(This->pToolGraph, msg))) return hr; + + if (msg->pGraph) + { + IDirectMusicTool_Release(msg->pGraph); + msg->pGraph = NULL; + } + + if (hr == DMUS_S_LAST_TOOL) + { + if (msg->pTool) IDirectMusicTool_Release(msg->pTool); + msg->pTool = &This->IDirectMusicTool_iface; + IDirectMusicTool_AddRef(msg->pTool); + return S_OK; + } + + if (SUCCEEDED(hr)) + { + msg->pGraph = &This->IDirectMusicGraph_iface; + IDirectMusicTool_AddRef(msg->pGraph); + } + + return hr; } static HRESULT WINAPI performance_graph_InsertTool(IDirectMusicGraph *iface, IDirectMusicTool *tool, diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index c9c613a40c5..17f11daf5ac 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -1544,13 +1544,13 @@ static void test_performance_graph(void) /* test IDirectMusicGraph_StampPMsg usage */ hr = IDirectMusicGraph_StampPMsg(graph, NULL); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); memset(&msg, 0, sizeof(msg)); hr = IDirectMusicGraph_StampPMsg(graph, &msg); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); ok(msg.pGraph == NULL, "got %p\n", msg.pGraph); - todo_wine ok(msg.pTool != NULL, "got %p\n", msg.pTool); - if (msg.pTool) check_interface(msg.pTool, &IID_IDirectMusicPerformance, TRUE); + ok(msg.pTool != NULL, "got %p\n", msg.pTool); + check_interface(msg.pTool, &IID_IDirectMusicPerformance, TRUE); ok(!msg.dwSize, "got %ld\n", msg.dwSize); ok(!msg.rtTime, "got %I64d\n", msg.rtTime); @@ -1564,12 +1564,12 @@ static void test_performance_graph(void) ok(!msg.punkUser, "got %p\n", msg.punkUser); hr = IDirectMusicGraph_StampPMsg(graph, &msg); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); ok(msg.pGraph == NULL, "got %p\n", msg.pGraph); - todo_wine ok(msg.pTool != NULL, "got %p\n", msg.pTool); - if (msg.pTool) check_interface(msg.pTool, &IID_IDirectMusicPerformance, TRUE); + ok(msg.pTool != NULL, "got %p\n", msg.pTool); + check_interface(msg.pTool, &IID_IDirectMusicPerformance, TRUE); - if (msg.pTool) IDirectMusicTool_Release(msg.pTool); + IDirectMusicTool_Release(msg.pTool); msg.pTool = NULL; IDirectMusicGraph_Release(graph); @@ -1604,9 +1604,9 @@ static void test_performance_graph(void) memset(&msg, 0, sizeof(msg)); hr = IDirectMusicGraph_StampPMsg(graph, &msg); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(msg.pGraph == graph, "got %p\n", msg.pGraph); - todo_wine ok(msg.pTool == tool, "got %p\n", msg.pTool); + ok(hr == S_OK, "got %#lx\n", hr); + ok(msg.pGraph == graph, "got %p\n", msg.pGraph); + ok(msg.pTool == tool, "got %p\n", msg.pTool); ok(!msg.dwSize, "got %ld\n", msg.dwSize); ok(!msg.rtTime, "got %I64d\n", msg.rtTime); @@ -1620,12 +1620,12 @@ static void test_performance_graph(void) ok(!msg.punkUser, "got %p\n", msg.punkUser); hr = IDirectMusicGraph_StampPMsg(graph, &msg); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); ok(msg.pGraph == NULL, "got %p\n", msg.pGraph); - todo_wine ok(msg.pTool != NULL, "got %p\n", msg.pTool); - if (msg.pTool) check_interface(msg.pTool, &IID_IDirectMusicPerformance, TRUE); + ok(msg.pTool != NULL, "got %p\n", msg.pTool); + check_interface(msg.pTool, &IID_IDirectMusicPerformance, TRUE); - if (msg.pTool) IDirectMusicTool_Release(msg.pTool); + IDirectMusicTool_Release(msg.pTool); msg.pTool = NULL; IDirectMusicGraph_Release(graph); @@ -1871,7 +1871,7 @@ static void test_performance_pmsg(void) hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicGraph_StampPMsg(graph, msg); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); IDirectMusicGraph_Release(graph); hr = IDirectMusicPerformance_SendPMsg(performance, msg); @@ -1901,7 +1901,7 @@ static void test_performance_pmsg(void) hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicGraph_StampPMsg(graph, msg); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); IDirectMusicGraph_Release(graph); msg->dwFlags &= ~(DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME); From 7b287ed0220cab219366b72ad1bd67e2a5fc6c54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 12 Sep 2023 10:11:38 +0200 Subject: [PATCH 2498/2777] dmime: Set the tool delivery type on the messages flags. (cherry picked from commit 1f84523800671046076aac142babea56c9a1b79d) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/graph.c | 11 +++++++++++ dlls/dmime/performance.c | 4 ++++ dlls/dmime/tests/dmime.c | 6 +++--- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/dlls/dmime/graph.c b/dlls/dmime/graph.c index 44996b0303e..d8f6bb88701 100644 --- a/dlls/dmime/graph.c +++ b/dlls/dmime/graph.c @@ -26,6 +26,7 @@ struct tool_entry { struct list entry; IDirectMusicTool *tool; + DWORD delivery; }; struct graph @@ -111,6 +112,7 @@ static ULONG WINAPI graph_Release(IDirectMusicGraph *iface) static HRESULT WINAPI graph_StampPMsg(IDirectMusicGraph *iface, DMUS_PMSG *msg) { + const DWORD delivery_flags = DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME; struct graph *This = impl_from_IDirectMusicGraph(iface); struct tool_entry *entry, *next, *first; @@ -140,6 +142,9 @@ static HRESULT WINAPI graph_StampPMsg(IDirectMusicGraph *iface, DMUS_PMSG *msg) msg->pTool = next->tool; IDirectMusicTool_AddRef(msg->pTool); + msg->dwFlags &= ~delivery_flags; + msg->dwFlags |= next->delivery; + return S_OK; } @@ -148,6 +153,7 @@ static HRESULT WINAPI graph_InsertTool(IDirectMusicGraph *iface, IDirectMusicToo { struct graph *This = impl_from_IDirectMusicGraph(iface); struct tool_entry *entry, *next; + HRESULT hr; TRACE("(%p, %p, %p, %ld, %li)\n", This, tool, channels, channel_count, index); @@ -163,6 +169,11 @@ static HRESULT WINAPI graph_InsertTool(IDirectMusicGraph *iface, IDirectMusicToo entry->tool = tool; IDirectMusicTool_AddRef(tool); IDirectMusicTool_Init(tool, iface); + if (FAILED(hr = IDirectMusicTool_GetMsgDeliveryType(tool, &entry->delivery))) + { + WARN("Failed to get delivery type from tool %p, hr %#lx\n", tool, hr); + entry->delivery = DMUS_PMSGF_TOOL_IMMEDIATE; + } list_add_before(&next->entry, &entry->entry); return S_OK; diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 904008954a2..d277c5de043 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1311,6 +1311,10 @@ static HRESULT WINAPI performance_graph_StampPMsg(IDirectMusicGraph *iface, DMUS if (hr == DMUS_S_LAST_TOOL) { + const DWORD delivery_flags = DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME; + msg->dwFlags &= ~delivery_flags; + msg->dwFlags |= DMUS_PMSGF_TOOL_QUEUE; + if (msg->pTool) IDirectMusicTool_Release(msg->pTool); msg->pTool = &This->IDirectMusicTool_iface; IDirectMusicTool_AddRef(msg->pTool); diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 17f11daf5ac..e178960b18f 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -756,7 +756,7 @@ static void test_graph(void) ok(!msg.dwSize, "got %ld\n", msg.dwSize); ok(!msg.rtTime, "got %I64d\n", msg.rtTime); ok(!msg.mtTime, "got %ld\n", msg.mtTime); - todo_wine ok(msg.dwFlags == DMUS_PMSGF_TOOL_IMMEDIATE, "got %#lx\n", msg.dwFlags); + ok(msg.dwFlags == DMUS_PMSGF_TOOL_IMMEDIATE, "got %#lx\n", msg.dwFlags); ok(!msg.dwPChannel, "got %ld\n", msg.dwPChannel); ok(!msg.dwVirtualTrackID, "got %ld\n", msg.dwVirtualTrackID); ok(!msg.dwType, "got %#lx\n", msg.dwType); @@ -1555,7 +1555,7 @@ static void test_performance_graph(void) ok(!msg.dwSize, "got %ld\n", msg.dwSize); ok(!msg.rtTime, "got %I64d\n", msg.rtTime); ok(!msg.mtTime, "got %ld\n", msg.mtTime); - todo_wine ok(msg.dwFlags == DMUS_PMSGF_TOOL_QUEUE, "got %#lx\n", msg.dwFlags); + ok(msg.dwFlags == DMUS_PMSGF_TOOL_QUEUE, "got %#lx\n", msg.dwFlags); ok(!msg.dwPChannel, "got %ld\n", msg.dwPChannel); ok(!msg.dwVirtualTrackID, "got %ld\n", msg.dwVirtualTrackID); ok(!msg.dwType, "got %#lx\n", msg.dwType); @@ -1611,7 +1611,7 @@ static void test_performance_graph(void) ok(!msg.dwSize, "got %ld\n", msg.dwSize); ok(!msg.rtTime, "got %I64d\n", msg.rtTime); ok(!msg.mtTime, "got %ld\n", msg.mtTime); - todo_wine ok(msg.dwFlags == DMUS_PMSGF_TOOL_IMMEDIATE, "got %#lx\n", msg.dwFlags); + ok(msg.dwFlags == DMUS_PMSGF_TOOL_IMMEDIATE, "got %#lx\n", msg.dwFlags); ok(!msg.dwPChannel, "got %ld\n", msg.dwPChannel); ok(!msg.dwVirtualTrackID, "got %ld\n", msg.dwVirtualTrackID); ok(!msg.dwType, "got %#lx\n", msg.dwType); From fa8cb4189781eb83939763d672be8664eff15c35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Aug 2023 17:38:20 +0200 Subject: [PATCH 2499/2777] dmcompos: Always return S_FALSE from DllCanUnloadNow. (cherry picked from commit 7d94983c735b9fd960ac6ad9d1618f1183f5d703) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmcompos/chordmap.c | 2 -- dlls/dmcompos/chordmaptrack.c | 2 -- dlls/dmcompos/composer.c | 2 -- dlls/dmcompos/dmcompos_main.c | 21 --------------------- dlls/dmcompos/dmcompos_private.h | 7 ------- dlls/dmcompos/signposttrack.c | 2 -- 6 files changed, 36 deletions(-) diff --git a/dlls/dmcompos/chordmap.c b/dlls/dmcompos/chordmap.c index adc17402f39..86134451846 100644 --- a/dlls/dmcompos/chordmap.c +++ b/dlls/dmcompos/chordmap.c @@ -81,7 +81,6 @@ static ULONG WINAPI IDirectMusicChordMapImpl_Release(IDirectMusicChordMap *iface if (!ref) { HeapFree(GetProcessHeap(), 0, This); - DMCOMPOS_UnlockModule(); } return ref; @@ -326,7 +325,6 @@ HRESULT create_dmchordmap(REFIID lpcGUID, void **ppobj) obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl; obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - DMCOMPOS_LockModule(); hr = IDirectMusicChordMap_QueryInterface(&obj->IDirectMusicChordMap_iface, lpcGUID, ppobj); IDirectMusicChordMap_Release(&obj->IDirectMusicChordMap_iface); diff --git a/dlls/dmcompos/chordmaptrack.c b/dlls/dmcompos/chordmaptrack.c index 66517340d70..35c64aab4a6 100644 --- a/dlls/dmcompos/chordmaptrack.c +++ b/dlls/dmcompos/chordmaptrack.c @@ -79,7 +79,6 @@ static ULONG WINAPI chordmap_track_Release(IDirectMusicTrack8 *iface) if (!ref) { HeapFree(GetProcessHeap(), 0, This); - DMCOMPOS_UnlockModule(); } return ref; @@ -301,7 +300,6 @@ HRESULT create_dmchordmaptrack(REFIID lpcGUID, void **ppobj) (IUnknown *)&track->IDirectMusicTrack8_iface); track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - DMCOMPOS_LockModule(); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); diff --git a/dlls/dmcompos/composer.c b/dlls/dmcompos/composer.c index a2a58396ee5..47e12358201 100644 --- a/dlls/dmcompos/composer.c +++ b/dlls/dmcompos/composer.c @@ -69,7 +69,6 @@ static ULONG WINAPI IDirectMusicComposerImpl_Release(IDirectMusicComposer *iface if (ref == 0) { HeapFree(GetProcessHeap(), 0, This); - DMCOMPOS_UnlockModule(); } return ref; @@ -183,7 +182,6 @@ HRESULT create_dmcomposer(REFIID riid, void **ret_iface) obj->IDirectMusicComposer_iface.lpVtbl = &dmcomposer_vtbl; obj->ref = 1; - DMCOMPOS_LockModule(); hr = IDirectMusicComposer_QueryInterface(&obj->IDirectMusicComposer_iface, riid, ret_iface); IDirectMusicComposer_Release(&obj->IDirectMusicComposer_iface); diff --git a/dlls/dmcompos/dmcompos_main.c b/dlls/dmcompos/dmcompos_main.c index dff77aa4d32..f7b5755683e 100644 --- a/dlls/dmcompos/dmcompos_main.c +++ b/dlls/dmcompos/dmcompos_main.c @@ -38,8 +38,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmcompos); -LONG DMCOMPOS_refCount = 0; - typedef struct { IClassFactory IClassFactory_iface; HRESULT (*fnCreateInstance)(REFIID riid, void **ret_iface); @@ -82,15 +80,11 @@ static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID r static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) { - DMCOMPOS_LockModule(); - return 2; /* non-heap based object */ } static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) { - DMCOMPOS_UnlockModule(); - return 1; /* non-heap based object */ } @@ -112,12 +106,6 @@ static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock) { TRACE("(%d)\n", dolock); - - if (dolock) - DMCOMPOS_LockModule(); - else - DMCOMPOS_UnlockModule(); - return S_OK; } @@ -135,15 +123,6 @@ static IClassFactoryImpl ChordMapTrack_CF = {{&classfactory_vtbl}, create_dmchor static IClassFactoryImpl Template_CF = {{&classfactory_vtbl}, create_direct_music_template}; static IClassFactoryImpl SignPostTrack_CF = {{&classfactory_vtbl}, create_dmsignposttrack}; -/****************************************************************** - * DllCanUnloadNow (DMCOMPOS.@) - * - * - */ -HRESULT WINAPI DllCanUnloadNow(void) { - return DMCOMPOS_refCount != 0 ? S_FALSE : S_OK; -} - /****************************************************************** * DllGetClassObject (DMCOMPOS.@) diff --git a/dlls/dmcompos/dmcompos_private.h b/dlls/dmcompos/dmcompos_private.h index c04d7da6060..928b5a5a993 100644 --- a/dlls/dmcompos/dmcompos_private.h +++ b/dlls/dmcompos/dmcompos_private.h @@ -49,11 +49,4 @@ extern HRESULT create_dmcomposer(REFIID riid, void **ret_iface); extern HRESULT create_dmchordmaptrack(REFIID riid, void **ret_iface); extern HRESULT create_dmsignposttrack(REFIID riid, void **ret_iface); -/********************************************************************** - * Dll lifetime tracking declaration for dmcompos.dll - */ -extern LONG DMCOMPOS_refCount; -static inline void DMCOMPOS_LockModule(void) { InterlockedIncrement( &DMCOMPOS_refCount ); } -static inline void DMCOMPOS_UnlockModule(void) { InterlockedDecrement( &DMCOMPOS_refCount ); } - #endif /* __WINE_DMCOMPOS_PRIVATE_H */ diff --git a/dlls/dmcompos/signposttrack.c b/dlls/dmcompos/signposttrack.c index 249f37b7711..23ed67acebe 100644 --- a/dlls/dmcompos/signposttrack.c +++ b/dlls/dmcompos/signposttrack.c @@ -79,7 +79,6 @@ static ULONG WINAPI signpost_track_Release(IDirectMusicTrack8 *iface) if (!ref) { HeapFree(GetProcessHeap(), 0, This); - DMCOMPOS_UnlockModule(); } return ref; @@ -289,7 +288,6 @@ HRESULT create_dmsignposttrack(REFIID lpcGUID, void **ppobj) (IUnknown *)&track->IDirectMusicTrack8_iface); track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - DMCOMPOS_LockModule(); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); From b2d6d7dc650a9d55dfe721842983b2d68d938d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 9 Sep 2023 09:19:08 +0200 Subject: [PATCH 2500/2777] dmcompos: Use CRT allocation functions. (cherry picked from commit 8a02434cf022f5e3644faee8329337ffe1cedaed) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmcompos/chordmap.c | 33 ++++++++++++++------------------- dlls/dmcompos/chordmaptrack.c | 11 +++-------- dlls/dmcompos/composer.c | 11 +++-------- dlls/dmcompos/dmobject.c | 7 +++---- dlls/dmcompos/signposttrack.c | 11 +++-------- 5 files changed, 26 insertions(+), 47 deletions(-) diff --git a/dlls/dmcompos/chordmap.c b/dlls/dmcompos/chordmap.c index 86134451846..2ddddd3fd57 100644 --- a/dlls/dmcompos/chordmap.c +++ b/dlls/dmcompos/chordmap.c @@ -79,9 +79,7 @@ static ULONG WINAPI IDirectMusicChordMapImpl_Release(IDirectMusicChordMap *iface TRACE("(%p) ref=%ld\n", This, ref); - if (!ref) { - HeapFree(GetProcessHeap(), 0, This); - } + if (!ref) free(This); return ref; } @@ -310,23 +308,20 @@ static const IPersistStreamVtbl persiststream_vtbl = { /* for ClassFactory */ HRESULT create_dmchordmap(REFIID lpcGUID, void **ppobj) { - IDirectMusicChordMapImpl* obj; - HRESULT hr; + IDirectMusicChordMapImpl* obj; + HRESULT hr; - obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicChordMapImpl)); - if (NULL == obj) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } - obj->IDirectMusicChordMap_iface.lpVtbl = &dmchordmap_vtbl; - obj->ref = 1; - dmobject_init(&obj->dmobj, &CLSID_DirectMusicChordMap, - (IUnknown *)&obj->IDirectMusicChordMap_iface); - obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl; - obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; + *ppobj = NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; + obj->IDirectMusicChordMap_iface.lpVtbl = &dmchordmap_vtbl; + obj->ref = 1; + dmobject_init(&obj->dmobj, &CLSID_DirectMusicChordMap, + (IUnknown *)&obj->IDirectMusicChordMap_iface); + obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl; + obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - hr = IDirectMusicChordMap_QueryInterface(&obj->IDirectMusicChordMap_iface, lpcGUID, ppobj); - IDirectMusicChordMap_Release(&obj->IDirectMusicChordMap_iface); + hr = IDirectMusicChordMap_QueryInterface(&obj->IDirectMusicChordMap_iface, lpcGUID, ppobj); + IDirectMusicChordMap_Release(&obj->IDirectMusicChordMap_iface); - return hr; + return hr; } diff --git a/dlls/dmcompos/chordmaptrack.c b/dlls/dmcompos/chordmaptrack.c index 35c64aab4a6..36079ef177a 100644 --- a/dlls/dmcompos/chordmaptrack.c +++ b/dlls/dmcompos/chordmaptrack.c @@ -77,9 +77,7 @@ static ULONG WINAPI chordmap_track_Release(IDirectMusicTrack8 *iface) TRACE("(%p) ref=%ld\n", This, ref); - if (!ref) { - HeapFree(GetProcessHeap(), 0, This); - } + if (!ref) free(This); return ref; } @@ -289,11 +287,8 @@ HRESULT create_dmchordmaptrack(REFIID lpcGUID, void **ppobj) IDirectMusicChordMapTrack* track; HRESULT hr; - track = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicChordMapTrack, diff --git a/dlls/dmcompos/composer.c b/dlls/dmcompos/composer.c index 47e12358201..3451f2d4203 100644 --- a/dlls/dmcompos/composer.c +++ b/dlls/dmcompos/composer.c @@ -67,9 +67,7 @@ static ULONG WINAPI IDirectMusicComposerImpl_Release(IDirectMusicComposer *iface TRACE("(%p) ref=%ld\n", This, ref); - if (ref == 0) { - HeapFree(GetProcessHeap(), 0, This); - } + if (!ref) free(This); return ref; } @@ -174,11 +172,8 @@ HRESULT create_dmcomposer(REFIID riid, void **ret_iface) IDirectMusicComposerImpl *obj; HRESULT hr; - obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj)); - if (!obj) { - *ret_iface = NULL; - return E_OUTOFMEMORY; - } + *ret_iface = NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicComposer_iface.lpVtbl = &dmcomposer_vtbl; obj->ref = 1; diff --git a/dlls/dmcompos/dmobject.c b/dlls/dmcompos/dmobject.c index b526b23d031..07d887a376c 100644 --- a/dlls/dmcompos/dmobject.c +++ b/dlls/dmcompos/dmobject.c @@ -28,7 +28,6 @@ #include "dmusics.h" #include "dmobject.h" #include "wine/debug.h" -#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(dmobj); WINE_DECLARE_DEBUG_CHANNEL(dmfile); @@ -375,7 +374,7 @@ HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) /* Reads chunk data of the form: DWORD - size of array element element[] - Array of elements - The caller needs to heap_free() the array. + The caller needs to free() the array. */ HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, unsigned int *count, DWORD elem_size) @@ -400,10 +399,10 @@ HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, *count = (chunk->size - sizeof(DWORD)) / elem_size; size = *count * elem_size; - if (!(*array = heap_alloc(size))) + if (!(*array = malloc(size))) return E_OUTOFMEMORY; if (FAILED(hr = stream_read(stream, *array, size))) { - heap_free(*array); + free(*array); *array = NULL; return hr; } diff --git a/dlls/dmcompos/signposttrack.c b/dlls/dmcompos/signposttrack.c index 23ed67acebe..eccf87a4893 100644 --- a/dlls/dmcompos/signposttrack.c +++ b/dlls/dmcompos/signposttrack.c @@ -77,9 +77,7 @@ static ULONG WINAPI signpost_track_Release(IDirectMusicTrack8 *iface) TRACE("(%p) ref=%ld\n", This, ref); - if (!ref) { - HeapFree(GetProcessHeap(), 0, This); - } + if (!ref) free(This); return ref; } @@ -277,11 +275,8 @@ HRESULT create_dmsignposttrack(REFIID lpcGUID, void **ppobj) IDirectMusicSignPostTrack *track; HRESULT hr; - track = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicSignPostTrack, From 8479b3a1dc5e3cde53db700b82dbc0c0ba50946c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 30 Aug 2023 19:56:53 +0200 Subject: [PATCH 2501/2777] dmcompos: Use PARENTSRC with dmusic. (cherry picked from commit 6798b73452f84d31c936cf48417b3df10bfacab0) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmcompos/Makefile.in | 1 + dlls/dmcompos/dmobject.c | 732 -------------------------------------- dlls/dmcompos/dmobject.h | 124 ------- 3 files changed, 1 insertion(+), 856 deletions(-) delete mode 100644 dlls/dmcompos/dmobject.c delete mode 100644 dlls/dmcompos/dmobject.h diff --git a/dlls/dmcompos/Makefile.in b/dlls/dmcompos/Makefile.in index d1e9b5e5b45..af5f2134152 100644 --- a/dlls/dmcompos/Makefile.in +++ b/dlls/dmcompos/Makefile.in @@ -1,5 +1,6 @@ MODULE = dmcompos.dll IMPORTS = dxguid uuid ole32 advapi32 +PARENTSRC = ../dmusic C_SRCS = \ chordmap.c \ diff --git a/dlls/dmcompos/dmobject.c b/dlls/dmcompos/dmobject.c deleted file mode 100644 index 07d887a376c..00000000000 --- a/dlls/dmcompos/dmobject.c +++ /dev/null @@ -1,732 +0,0 @@ -/* - * Base IDirectMusicObject Implementation - * Keep in sync with the master in dlls/dmusic/dmobject.c - * - * Copyright (C) 2003-2004 Rok Mandeljc - * Copyright (C) 2014 Michael Stefaniuc - * - * This program 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 program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define COBJMACROS -#include -#include "objbase.h" -#include "dmusici.h" -#include "dmusicf.h" -#include "dmusics.h" -#include "dmobject.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dmobj); -WINE_DECLARE_DEBUG_CHANNEL(dmfile); - -/* Debugging helpers */ -const char *debugstr_dmguid(const GUID *id) { - unsigned int i; -#define X(guid) { &guid, #guid } - static const struct { - const GUID *guid; - const char *name; - } guids[] = { - /* CLSIDs */ - X(CLSID_AudioVBScript), - X(CLSID_DirectMusic), - X(CLSID_DirectMusicAudioPathConfig), - X(CLSID_DirectMusicAuditionTrack), - X(CLSID_DirectMusicBand), - X(CLSID_DirectMusicBandTrack), - X(CLSID_DirectMusicChordMapTrack), - X(CLSID_DirectMusicChordMap), - X(CLSID_DirectMusicChordTrack), - X(CLSID_DirectMusicCollection), - X(CLSID_DirectMusicCommandTrack), - X(CLSID_DirectMusicComposer), - X(CLSID_DirectMusicContainer), - X(CLSID_DirectMusicGraph), - X(CLSID_DirectMusicLoader), - X(CLSID_DirectMusicLyricsTrack), - X(CLSID_DirectMusicMarkerTrack), - X(CLSID_DirectMusicMelodyFormulationTrack), - X(CLSID_DirectMusicMotifTrack), - X(CLSID_DirectMusicMuteTrack), - X(CLSID_DirectMusicParamControlTrack), - X(CLSID_DirectMusicPatternTrack), - X(CLSID_DirectMusicPerformance), - X(CLSID_DirectMusicScript), - X(CLSID_DirectMusicScriptAutoImpSegment), - X(CLSID_DirectMusicScriptAutoImpPerformance), - X(CLSID_DirectMusicScriptAutoImpSegmentState), - X(CLSID_DirectMusicScriptAutoImpAudioPathConfig), - X(CLSID_DirectMusicScriptAutoImpAudioPath), - X(CLSID_DirectMusicScriptAutoImpSong), - X(CLSID_DirectMusicScriptSourceCodeLoader), - X(CLSID_DirectMusicScriptTrack), - X(CLSID_DirectMusicSection), - X(CLSID_DirectMusicSegment), - X(CLSID_DirectMusicSegmentState), - X(CLSID_DirectMusicSegmentTriggerTrack), - X(CLSID_DirectMusicSegTriggerTrack), - X(CLSID_DirectMusicSeqTrack), - X(CLSID_DirectMusicSignPostTrack), - X(CLSID_DirectMusicSong), - X(CLSID_DirectMusicStyle), - X(CLSID_DirectMusicStyleTrack), - X(CLSID_DirectMusicSynth), - X(CLSID_DirectMusicSynthSink), - X(CLSID_DirectMusicSysExTrack), - X(CLSID_DirectMusicTemplate), - X(CLSID_DirectMusicTempoTrack), - X(CLSID_DirectMusicTimeSigTrack), - X(CLSID_DirectMusicWaveTrack), - X(CLSID_DirectSoundWave), - /* IIDs */ - X(IID_IDirectMusic), - X(IID_IDirectMusic2), - X(IID_IDirectMusic8), - X(IID_IDirectMusicAudioPath), - X(IID_IDirectMusicBand), - X(IID_IDirectMusicBuffer), - X(IID_IDirectMusicChordMap), - X(IID_IDirectMusicCollection), - X(IID_IDirectMusicComposer), - X(IID_IDirectMusicContainer), - X(IID_IDirectMusicDownload), - X(IID_IDirectMusicDownloadedInstrument), - X(IID_IDirectMusicGetLoader), - X(IID_IDirectMusicGraph), - X(IID_IDirectMusicInstrument), - X(IID_IDirectMusicLoader), - X(IID_IDirectMusicLoader8), - X(IID_IDirectMusicObject), - X(IID_IDirectMusicPatternTrack), - X(IID_IDirectMusicPerformance), - X(IID_IDirectMusicPerformance2), - X(IID_IDirectMusicPerformance8), - X(IID_IDirectMusicPort), - X(IID_IDirectMusicPortDownload), - X(IID_IDirectMusicScript), - X(IID_IDirectMusicSegment), - X(IID_IDirectMusicSegment2), - X(IID_IDirectMusicSegment8), - X(IID_IDirectMusicSegmentState), - X(IID_IDirectMusicSegmentState8), - X(IID_IDirectMusicStyle), - X(IID_IDirectMusicStyle8), - X(IID_IDirectMusicSynth), - X(IID_IDirectMusicSynth8), - X(IID_IDirectMusicSynthSink), - X(IID_IDirectMusicThru), - X(IID_IDirectMusicTool), - X(IID_IDirectMusicTool8), - X(IID_IDirectMusicTrack), - X(IID_IDirectMusicTrack8), - X(IID_IUnknown), - X(IID_IPersistStream), - X(IID_IStream), - X(IID_IClassFactory), - /* GUIDs */ - X(GUID_DirectMusicAllTypes), - X(GUID_NOTIFICATION_CHORD), - X(GUID_NOTIFICATION_COMMAND), - X(GUID_NOTIFICATION_MEASUREANDBEAT), - X(GUID_NOTIFICATION_PERFORMANCE), - X(GUID_NOTIFICATION_RECOMPOSE), - X(GUID_NOTIFICATION_SEGMENT), - X(GUID_BandParam), - X(GUID_ChordParam), - X(GUID_CommandParam), - X(GUID_CommandParam2), - X(GUID_CommandParamNext), - X(GUID_IDirectMusicBand), - X(GUID_IDirectMusicChordMap), - X(GUID_IDirectMusicStyle), - X(GUID_MuteParam), - X(GUID_Play_Marker), - X(GUID_RhythmParam), - X(GUID_TempoParam), - X(GUID_TimeSignature), - X(GUID_Valid_Start_Time), - X(GUID_Clear_All_Bands), - X(GUID_ConnectToDLSCollection), - X(GUID_Disable_Auto_Download), - X(GUID_DisableTempo), - X(GUID_DisableTimeSig), - X(GUID_Download), - X(GUID_DownloadToAudioPath), - X(GUID_Enable_Auto_Download), - X(GUID_EnableTempo), - X(GUID_EnableTimeSig), - X(GUID_IgnoreBankSelectForGM), - X(GUID_SeedVariations), - X(GUID_StandardMIDIFile), - X(GUID_Unload), - X(GUID_UnloadFromAudioPath), - X(GUID_Variations), - X(GUID_PerfMasterTempo), - X(GUID_PerfMasterVolume), - X(GUID_PerfMasterGrooveLevel), - X(GUID_PerfAutoDownload), - X(GUID_DefaultGMCollection), - X(GUID_Synth_Default), - X(GUID_Buffer_Reverb), - X(GUID_Buffer_EnvReverb), - X(GUID_Buffer_Stereo), - X(GUID_Buffer_3D_Dry), - X(GUID_Buffer_Mono), - X(GUID_DMUS_PROP_GM_Hardware), - X(GUID_DMUS_PROP_GS_Capable), - X(GUID_DMUS_PROP_GS_Hardware), - X(GUID_DMUS_PROP_DLS1), - X(GUID_DMUS_PROP_DLS2), - X(GUID_DMUS_PROP_Effects), - X(GUID_DMUS_PROP_INSTRUMENT2), - X(GUID_DMUS_PROP_LegacyCaps), - X(GUID_DMUS_PROP_MemorySize), - X(GUID_DMUS_PROP_SampleMemorySize), - X(GUID_DMUS_PROP_SamplePlaybackRate), - X(GUID_DMUS_PROP_SetSynthSink), - X(GUID_DMUS_PROP_SinkUsesDSound), - X(GUID_DMUS_PROP_SynthSink_DSOUND), - X(GUID_DMUS_PROP_SynthSink_WAVE), - X(GUID_DMUS_PROP_Volume), - X(GUID_DMUS_PROP_WavesReverb), - X(GUID_DMUS_PROP_WriteLatency), - X(GUID_DMUS_PROP_WritePeriod), - X(GUID_DMUS_PROP_XG_Capable), - X(GUID_DMUS_PROP_XG_Hardware) - }; -#undef X - - if (!id) - return "(null)"; - - for (i = 0; i < ARRAY_SIZE(guids); i++) - if (IsEqualGUID(id, guids[i].guid)) - return guids[i].name; - - return debugstr_guid(id); -} - -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc) -{ - if (!desc || !TRACE_ON(dmfile)) - return; - - TRACE_(dmfile)("DMUS_OBJECTDESC (%p):", desc); - TRACE_(dmfile)(" - dwSize = %lu\n", desc->dwSize); - -#define X(flag) if (desc->dwValidData & flag) TRACE_(dmfile)(#flag " ") - TRACE_(dmfile)(" - dwValidData = %#08lx ( ", desc->dwValidData); - X(DMUS_OBJ_OBJECT); - X(DMUS_OBJ_CLASS); - X(DMUS_OBJ_NAME); - X(DMUS_OBJ_CATEGORY); - X(DMUS_OBJ_FILENAME); - X(DMUS_OBJ_FULLPATH); - X(DMUS_OBJ_URL); - X(DMUS_OBJ_VERSION); - X(DMUS_OBJ_DATE); - X(DMUS_OBJ_LOADED); - X(DMUS_OBJ_MEMORY); - X(DMUS_OBJ_STREAM); - TRACE_(dmfile)(")\n"); -#undef X - - if (desc->dwValidData & DMUS_OBJ_CLASS) - TRACE_(dmfile)(" - guidClass = %s\n", debugstr_dmguid(&desc->guidClass)); - if (desc->dwValidData & DMUS_OBJ_OBJECT) - TRACE_(dmfile)(" - guidObject = %s\n", debugstr_guid(&desc->guidObject)); - - if (desc->dwValidData & DMUS_OBJ_DATE) { - SYSTEMTIME time; - FileTimeToSystemTime(&desc->ftDate, &time); - TRACE_(dmfile)(" - ftDate = \'%04u-%02u-%02u %02u:%02u:%02u\'\n", - time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond); - } - if (desc->dwValidData & DMUS_OBJ_VERSION) - TRACE_(dmfile)(" - vVersion = \'%u,%u,%u,%u\'\n", - HIWORD(desc->vVersion.dwVersionMS), LOWORD(desc->vVersion.dwVersionMS), - HIWORD(desc->vVersion.dwVersionLS), LOWORD(desc->vVersion.dwVersionLS)); - if (desc->dwValidData & DMUS_OBJ_NAME) - TRACE_(dmfile)(" - wszName = %s\n", debugstr_w(desc->wszName)); - if (desc->dwValidData & DMUS_OBJ_CATEGORY) - TRACE_(dmfile)(" - wszCategory = %s\n", debugstr_w(desc->wszCategory)); - if (desc->dwValidData & DMUS_OBJ_FILENAME) - TRACE_(dmfile)(" - wszFileName = %s\n", debugstr_w(desc->wszFileName)); - if (desc->dwValidData & DMUS_OBJ_MEMORY) - TRACE_(dmfile)(" - llMemLength = 0x%s - pbMemData = %p\n", - wine_dbgstr_longlong(desc->llMemLength), desc->pbMemData); - if (desc->dwValidData & DMUS_OBJ_STREAM) - TRACE_(dmfile)(" - pStream = %p\n", desc->pStream); -} - - -/* RIFF format parsing */ -#define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD)) - -const char *debugstr_chunk(const struct chunk_entry *chunk) -{ - const char *type = ""; - - if (!chunk) - return "(null)"; - if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST) - type = wine_dbg_sprintf("type %s, ", debugstr_fourcc(chunk->type)); - return wine_dbg_sprintf("%s chunk, %ssize %lu", debugstr_fourcc(chunk->id), type, chunk->size); -} - -static HRESULT stream_read(IStream *stream, void *data, ULONG size) -{ - ULONG read; - HRESULT hr; - - hr = IStream_Read(stream, data, size, &read); - if (FAILED(hr)) - TRACE_(dmfile)("IStream_Read failed: %#lx\n", hr); - else if (!read && read < size) { - /* All or nothing: Handle a partial read due to end of stream as an error */ - TRACE_(dmfile)("Short read: %lu < %lu\n", read, size); - return E_FAIL; - } - - return hr; -} - -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) -{ - static const LARGE_INTEGER zero; - ULONGLONG ck_end = 0, p_end = 0; - HRESULT hr; - - hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &chunk->offset); - if (FAILED(hr)) - return hr; - assert(!(chunk->offset.QuadPart & 1)); - if (chunk->parent) { - p_end = chunk->parent->offset.QuadPart + CHUNK_HDR_SIZE + ((chunk->parent->size + 1) & ~1); - if (chunk->offset.QuadPart == p_end) - return S_FALSE; - ck_end = chunk->offset.QuadPart + CHUNK_HDR_SIZE; - if (ck_end > p_end) { - WARN_(dmfile)("No space for sub-chunk header in parent chunk: ends at offset %s > %s\n", - wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end)); - return E_FAIL; - } - } - - hr = stream_read(stream, chunk, CHUNK_HDR_SIZE); - if (hr != S_OK) - return hr; - if (chunk->parent) { - ck_end += (chunk->size + 1) & ~1; - if (ck_end > p_end) { - WARN_(dmfile)("No space for sub-chunk data in parent chunk: ends at offset %s > %s\n", - wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end)); - return E_FAIL; - } - } - - if (chunk->id == FOURCC_LIST || chunk->id == FOURCC_RIFF) { - hr = stream_read(stream, &chunk->type, sizeof(FOURCC)); - if (hr != S_OK) - return hr != S_FALSE ? hr : E_FAIL; - } - - TRACE_(dmfile)("Returning %s\n", debugstr_chunk(chunk)); - - return S_OK; -} - -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER end; - - end.QuadPart = (chunk->offset.QuadPart + CHUNK_HDR_SIZE + chunk->size + 1) & ~(ULONGLONG)1; - - return IStream_Seek(stream, end, STREAM_SEEK_SET, NULL); -} - -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) -{ - HRESULT hr; - - if (chunk->id) { - hr = stream_skip_chunk(stream, chunk); - if (FAILED(hr)) - return hr; - } - - return stream_get_chunk(stream, chunk); -} - -/* Reads chunk data of the form: - DWORD - size of array element - element[] - Array of elements - The caller needs to free() the array. -*/ -HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size) -{ - DWORD size; - HRESULT hr; - - *array = NULL; - *count = 0; - - if (chunk->size < sizeof(DWORD)) { - WARN_(dmfile)("%s: Too short to read element size\n", debugstr_chunk(chunk)); - return E_FAIL; - } - if (FAILED(hr = stream_read(stream, &size, sizeof(DWORD)))) - return hr; - if (size != elem_size) { - WARN_(dmfile)("%s: Array element size mismatch: got %lu, expected %lu\n", - debugstr_chunk(chunk), size, elem_size); - return DMUS_E_UNSUPPORTED_STREAM; - } - - *count = (chunk->size - sizeof(DWORD)) / elem_size; - size = *count * elem_size; - if (!(*array = malloc(size))) - return E_OUTOFMEMORY; - if (FAILED(hr = stream_read(stream, *array, size))) { - free(*array); - *array = NULL; - return hr; - } - - if (chunk->size > size + sizeof(DWORD)) { - WARN_(dmfile)("%s: Extraneous data at end of array\n", debugstr_chunk(chunk)); - stream_skip_chunk(stream, chunk); - return S_FALSE; - } - return S_OK; -} - -HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size) -{ - if (chunk->size != size) { - WARN_(dmfile)("Chunk %s (size %lu, offset %s) doesn't contains the expected data size %lu\n", - debugstr_fourcc(chunk->id), chunk->size, - wine_dbgstr_longlong(chunk->offset.QuadPart), size); - return E_FAIL; - } - return stream_read(stream, data, size); -} - -HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size) -{ - ULONG len; - HRESULT hr; - - hr = IStream_Read(stream, str, min(chunk->size, size), &len); - if (FAILED(hr)) - return hr; - - /* Don't assume the string is properly zero terminated */ - str[min(len, size - 1)] = 0; - - if (len < chunk->size) - return S_FALSE; - return S_OK; -} - - - -/* Generic IDirectMusicObject methods */ -static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface) -{ - return CONTAINING_RECORD(iface, struct dmobject, IDirectMusicObject_iface); -} - -HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); -} - -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_AddRef(This->outer_unk); -} - -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_Release(This->outer_unk); -} - -HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - - TRACE("(%p/%p)->(%p)\n", iface, This, desc); - - if (!desc) - return E_POINTER; - - memcpy(desc, &This->desc, This->desc.dwSize); - - return S_OK; -} - -HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - HRESULT ret = S_OK; - - TRACE("(%p, %p)\n", iface, desc); - - if (!desc) - return E_POINTER; - - /* Immutable property */ - if (desc->dwValidData & DMUS_OBJ_CLASS) - { - desc->dwValidData &= ~DMUS_OBJ_CLASS; - ret = S_FALSE; - } - /* Set only valid fields */ - if (desc->dwValidData & DMUS_OBJ_OBJECT) - This->desc.guidObject = desc->guidObject; - if (desc->dwValidData & DMUS_OBJ_NAME) - lstrcpynW(This->desc.wszName, desc->wszName, DMUS_MAX_NAME); - if (desc->dwValidData & DMUS_OBJ_CATEGORY) - lstrcpynW(This->desc.wszCategory, desc->wszCategory, DMUS_MAX_CATEGORY); - if (desc->dwValidData & DMUS_OBJ_FILENAME) - lstrcpynW(This->desc.wszFileName, desc->wszFileName, DMUS_MAX_FILENAME); - if (desc->dwValidData & DMUS_OBJ_VERSION) - This->desc.vVersion = desc->vVersion; - if (desc->dwValidData & DMUS_OBJ_DATE) - This->desc.ftDate = desc->ftDate; - if (desc->dwValidData & DMUS_OBJ_MEMORY) { - This->desc.llMemLength = desc->llMemLength; - memcpy(This->desc.pbMemData, desc->pbMemData, desc->llMemLength); - } - if (desc->dwValidData & DMUS_OBJ_STREAM) - IStream_Clone(desc->pStream, &This->desc.pStream); - - This->desc.dwValidData |= desc->dwValidData; - - return ret; -} - -/* Helper for IDirectMusicObject::ParseDescriptor */ -static inline void info_get_name(IStream *stream, const struct chunk_entry *info, - DMUS_OBJECTDESC *desc) -{ - struct chunk_entry chunk = {.parent = info}; - char name[DMUS_MAX_NAME]; - ULONG len; - HRESULT hr = E_FAIL; - - while (stream_next_chunk(stream, &chunk) == S_OK) - if (chunk.id == mmioFOURCC('I','N','A','M')) - hr = IStream_Read(stream, name, min(chunk.size, sizeof(name)), &len); - - if (SUCCEEDED(hr)) { - len = MultiByteToWideChar(CP_ACP, 0, name, len, desc->wszName, sizeof(desc->wszName)); - desc->wszName[min(len, sizeof(desc->wszName) - 1)] = 0; - desc->dwValidData |= DMUS_OBJ_NAME; - } -} - -static inline void unfo_get_name(IStream *stream, const struct chunk_entry *unfo, - DMUS_OBJECTDESC *desc, BOOL inam) -{ - struct chunk_entry chunk = {.parent = unfo}; - - while (stream_next_chunk(stream, &chunk) == S_OK) - if (chunk.id == DMUS_FOURCC_UNAM_CHUNK || (inam && chunk.id == mmioFOURCC('I','N','A','M'))) - if (stream_chunk_get_wstr(stream, &chunk, desc->wszName, sizeof(desc->wszName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_NAME; -} - -HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported) -{ - struct chunk_entry chunk = {.parent = riff}; - HRESULT hr; - - TRACE("Looking for %#lx in %p: %s\n", supported, stream, debugstr_chunk(riff)); - - desc->dwValidData = 0; - desc->dwSize = sizeof(*desc); - - while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { - switch (chunk.id) { - case DMUS_FOURCC_CATEGORY_CHUNK: - if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk, - desc->wszCategory, sizeof(desc->wszCategory)) == S_OK) - desc->dwValidData |= DMUS_OBJ_CATEGORY; - break; - case DMUS_FOURCC_DATE_CHUNK: - if ((supported & DMUS_OBJ_DATE) && stream_chunk_get_data(stream, &chunk, - &desc->ftDate, sizeof(desc->ftDate)) == S_OK) - desc->dwValidData |= DMUS_OBJ_DATE; - break; - case DMUS_FOURCC_FILE_CHUNK: - if ((supported & DMUS_OBJ_FILENAME) && stream_chunk_get_wstr(stream, &chunk, - desc->wszFileName, sizeof(desc->wszFileName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_FILENAME; - break; - case DMUS_FOURCC_GUID_CHUNK: - if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk, - &desc->guidObject, sizeof(desc->guidObject)) == S_OK) - desc->dwValidData |= DMUS_OBJ_OBJECT; - break; - case DMUS_FOURCC_NAME_CHUNK: - if ((supported & DMUS_OBJ_NAME) && stream_chunk_get_wstr(stream, &chunk, - desc->wszName, sizeof(desc->wszName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_NAME; - break; - case DMUS_FOURCC_VERSION_CHUNK: - if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk, - &desc->vVersion, sizeof(desc->vVersion)) == S_OK) - desc->dwValidData |= DMUS_OBJ_VERSION; - break; - case FOURCC_LIST: - if (chunk.type == DMUS_FOURCC_UNFO_LIST && (supported & DMUS_OBJ_NAME)) - unfo_get_name(stream, &chunk, desc, supported & DMUS_OBJ_NAME_INAM); - else if (chunk.type == DMUS_FOURCC_INFO_LIST && (supported & DMUS_OBJ_NAME_INFO)) - info_get_name(stream, &chunk, desc); - break; - } - } - TRACE("Found %#lx\n", desc->dwValidData); - - return hr; -} - -HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj) -{ - struct chunk_entry chunk = {.parent = list}; - IDirectMusicGetLoader *getloader; - IDirectMusicLoader *loader; - DMUS_OBJECTDESC desc; - DMUS_IO_REFERENCE reference; - HRESULT hr; - - if (FAILED(hr = stream_next_chunk(stream, &chunk))) - return hr; - if (chunk.id != DMUS_FOURCC_REF_CHUNK) - return DMUS_E_UNSUPPORTED_STREAM; - - if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &reference, sizeof(reference)))) { - WARN("Failed to read data of %s\n", debugstr_chunk(&chunk)); - return hr; - } - TRACE("REFERENCE guidClassID %s, dwValidData %#lx\n", debugstr_dmguid(&reference.guidClassID), - reference.dwValidData); - - if (FAILED(hr = dmobj_parsedescriptor(stream, list, &desc, reference.dwValidData))) - return hr; - desc.guidClass = reference.guidClassID; - desc.dwValidData |= DMUS_OBJ_CLASS; - dump_DMUS_OBJECTDESC(&desc); - - if (FAILED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getloader))) - return hr; - hr = IDirectMusicGetLoader_GetLoader(getloader, &loader); - IDirectMusicGetLoader_Release(getloader); - if (FAILED(hr)) - return hr; - - hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicObject, (void**)dmobj); - IDirectMusicLoader_Release(loader); - - return hr; -} - -/* Generic IPersistStream methods */ -static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface) -{ - return CONTAINING_RECORD(iface, struct dmobject, IPersistStream_iface); -} - -HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); -} - -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_AddRef(This->outer_unk); -} - -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_Release(This->outer_unk); -} - -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - - TRACE("(%p, %p)\n", This, class); - - if (!class) - return E_POINTER; - - *class = This->desc.guidClass; - - return S_OK; -} - -/* IPersistStream methods not implemented in native */ -HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) -{ - TRACE("(%p, %p): method not implemented\n", iface, class); - return E_NOTIMPL; -} - -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface) -{ - TRACE("(%p): method not implemented, always returning S_FALSE\n", iface); - return S_FALSE; -} - -HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty) -{ - TRACE("(%p, %p, %d): method not implemented\n", iface, stream, clear_dirty); - return E_NOTIMPL; -} - -HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, ULARGE_INTEGER *size) -{ - TRACE("(%p, %p): method not implemented\n", iface, size); - return E_NOTIMPL; -} - - -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk) -{ - dmobj->outer_unk = outer_unk; - dmobj->desc.dwSize = sizeof(dmobj->desc); - dmobj->desc.dwValidData = DMUS_OBJ_CLASS; - dmobj->desc.guidClass = *class; -} diff --git a/dlls/dmcompos/dmobject.h b/dlls/dmcompos/dmobject.h deleted file mode 100644 index 772be015c80..00000000000 --- a/dlls/dmcompos/dmobject.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Base IDirectMusicObject Implementation - * Keep in sync with the master in dlls/dmusic/dmobject.h - * - * Copyright (C) 2014 Michael Stefaniuc - * - * This program 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 program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "wine/debug.h" - -/* RIFF stream parsing */ -struct chunk_entry; -struct chunk_entry { - FOURCC id; - DWORD size; - FOURCC type; /* valid only for LIST and RIFF chunks */ - ULARGE_INTEGER offset; /* chunk offset from start of stream */ - const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */ -}; - -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk); -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk); -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk); - -HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size); -HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size); -HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size); - -static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER offset; - - offset.QuadPart = chunk->offset.QuadPart + sizeof(FOURCC) + sizeof(DWORD); - if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST) - offset.QuadPart += sizeof(FOURCC); - - return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); -} - -static inline HRESULT stream_reset_chunk_start(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER offset; - - offset.QuadPart = chunk->offset.QuadPart; - - return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); -} - - -/* IDirectMusicObject base object */ -struct dmobject { - IDirectMusicObject IDirectMusicObject_iface; - IPersistStream IPersistStream_iface; - IUnknown *outer_unk; - DMUS_OBJECTDESC desc; -}; - -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk); - -/* Generic IDirectMusicObject methods */ -HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface); -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface); -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface); -HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc); -HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc); - -/* Helper for IDirectMusicObject::ParseDescriptor */ -HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported); -/* Additional supported flags for dmobj_parsedescriptor. - DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */ -#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */ -#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */ - -/* 'DMRF' (reference list) helper */ -HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj); - -/* Generic IPersistStream methods */ -HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface); -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface); -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface); -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class); - -/* IPersistStream methods not implemented in native */ -HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, - CLSID *class); -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface); -HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty); -HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, - ULARGE_INTEGER *size); - -/* Debugging helpers */ -const char *debugstr_chunk(const struct chunk_entry *chunk); -const char *debugstr_dmguid(const GUID *id); -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc); - -static inline const char *debugstr_fourcc(DWORD fourcc) -{ - if (!fourcc) return "''"; - return wine_dbg_sprintf("'%c%c%c%c'", (char)(fourcc), (char)(fourcc >> 8), - (char)(fourcc >> 16), (char)(fourcc >> 24)); -} From 10b5af4c2749820b4289294901e274d393d37e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Aug 2023 17:41:58 +0200 Subject: [PATCH 2502/2777] dmloader: Always return S_FALSE from DllCanUnloadNow. (cherry picked from commit 30e5892c98cc3b7aa0754b542cb19e14d28ac5c2) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmloader/container.c | 3 --- dlls/dmloader/dmloader_main.c | 21 --------------------- dlls/dmloader/dmloader_private.h | 5 ----- dlls/dmloader/loader.c | 3 --- 4 files changed, 32 deletions(-) diff --git a/dlls/dmloader/container.c b/dlls/dmloader/container.c index f2b284e1cb3..747c2a07341 100644 --- a/dlls/dmloader/container.c +++ b/dlls/dmloader/container.c @@ -137,7 +137,6 @@ static ULONG WINAPI IDirectMusicContainerImpl_Release(IDirectMusicContainer *ifa if (This->pStream) destroy_dmcontainer(This); HeapFree(GetProcessHeap(), 0, This); - unlock_module(); } return ref; @@ -666,8 +665,6 @@ HRESULT create_dmcontainer(REFIID lpcGUID, void **ppobj) obj->pContainedObjects = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct list)); list_init (obj->pContainedObjects); - lock_module(); - hr = IDirectMusicContainer_QueryInterface(&obj->IDirectMusicContainer_iface, lpcGUID, ppobj); IDirectMusicContainer_Release(&obj->IDirectMusicContainer_iface); diff --git a/dlls/dmloader/dmloader_main.c b/dlls/dmloader/dmloader_main.c index 512e6102d86..96d841e2b2d 100644 --- a/dlls/dmloader/dmloader_main.c +++ b/dlls/dmloader/dmloader_main.c @@ -36,8 +36,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmloader); -LONG module_ref = 0; - typedef struct { IClassFactory IClassFactory_iface; HRESULT (*fnCreateInstance)(REFIID riid, void **ppv); @@ -73,15 +71,11 @@ static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID r static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) { - lock_module(); - return 2; /* non-heap based object */ } static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) { - unlock_module(); - return 1; /* non-heap based object */ } @@ -103,12 +97,6 @@ static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock) { TRACE("(%d)\n", dolock); - - if (dolock) - lock_module(); - else - unlock_module(); - return S_OK; } @@ -123,15 +111,6 @@ static const IClassFactoryVtbl classfactory_vtbl = { static IClassFactoryImpl dm_loader_CF = {{&classfactory_vtbl}, create_dmloader}; static IClassFactoryImpl dm_container_CF = {{&classfactory_vtbl}, create_dmcontainer}; -/****************************************************************** - * DllCanUnloadNow (DMLOADER.@) - */ -HRESULT WINAPI DllCanUnloadNow (void) -{ - TRACE("() ref=%ld\n", module_ref); - - return module_ref ? S_FALSE : S_OK; -} /****************************************************************** * DllGetClassObject (DMLOADER.@) diff --git a/dlls/dmloader/dmloader_private.h b/dlls/dmloader/dmloader_private.h index 204c9689ffb..0aea1ba8499 100644 --- a/dlls/dmloader/dmloader_private.h +++ b/dlls/dmloader/dmloader_private.h @@ -44,11 +44,6 @@ #define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) -/* dmloader.dll global (for DllCanUnloadNow) */ -extern LONG module_ref; -static inline void lock_module(void) { InterlockedIncrement( &module_ref ); } -static inline void unlock_module(void) { InterlockedDecrement( &module_ref ); } - /***************************************************************************** * Interfaces */ diff --git a/dlls/dmloader/loader.c b/dlls/dmloader/loader.c index 6c4b29ab5ea..f303f93baaa 100644 --- a/dlls/dmloader/loader.c +++ b/dlls/dmloader/loader.c @@ -157,7 +157,6 @@ static ULONG WINAPI IDirectMusicLoaderImpl_Release(IDirectMusicLoader8 *iface) for (i = 0; i < ARRAY_SIZE(classes); i++) HeapFree(GetProcessHeap(), 0, This->search_paths[i]); HeapFree(GetProcessHeap(), 0, This); - unlock_module(); } return ref; @@ -940,7 +939,5 @@ HRESULT create_dmloader(REFIID lpcGUID, void **ppobj) dls->bInvalidDefaultDLS = TRUE; } - lock_module(); - return IDirectMusicLoader_QueryInterface(&obj->IDirectMusicLoader8_iface, lpcGUID, ppobj); } From 5a24dac427dfb206df69d660ad0889c703362d3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 9 Sep 2023 09:22:04 +0200 Subject: [PATCH 2503/2777] dmloader: Use CRT allocation functions. (cherry picked from commit 307b13bcf56f28f8e891c1b8d1bbf26d4ec4d2df) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmloader/container.c | 33 +++++++++++++++------------------ dlls/dmloader/dmobject.c | 7 +++---- dlls/dmloader/loader.c | 19 ++++++++----------- dlls/dmloader/loaderstream.c | 28 +++++++++++----------------- 4 files changed, 37 insertions(+), 50 deletions(-) diff --git a/dlls/dmloader/container.c b/dlls/dmloader/container.c index 747c2a07341..66049e68907 100644 --- a/dlls/dmloader/container.c +++ b/dlls/dmloader/container.c @@ -136,7 +136,7 @@ static ULONG WINAPI IDirectMusicContainerImpl_Release(IDirectMusicContainer *ifa if (!ref) { if (This->pStream) destroy_dmcontainer(This); - HeapFree(GetProcessHeap(), 0, This); + free(This); } return ref; @@ -388,7 +388,7 @@ static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface, IStream *pS case DMUS_FOURCC_CONTAINED_OBJECT_LIST: { LPWINE_CONTAINER_ENTRY pNewEntry; TRACE_(dmfile)(": contained object list\n"); - pNewEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(WINE_CONTAINER_ENTRY)); + pNewEntry = calloc(1, sizeof(*pNewEntry)); DM_STRUCT_INIT(&pNewEntry->Desc); do { IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); @@ -397,7 +397,7 @@ static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface, IStream *pS switch (Chunk.fccID) { case DMUS_FOURCC_CONTAINED_ALIAS_CHUNK: { TRACE_(dmfile)(": alias chunk\n"); - pNewEntry->wszAlias = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize); + pNewEntry->wszAlias = calloc(1, Chunk.dwSize); IStream_Read (pStm, pNewEntry->wszAlias, Chunk.dwSize, NULL); TRACE_(dmfile)(": alias: %s\n", debugstr_w(pNewEntry->wszAlias)); break; @@ -649,24 +649,21 @@ static const IPersistStreamVtbl persiststream_vtbl = { HRESULT create_dmcontainer(REFIID lpcGUID, void **ppobj) { IDirectMusicContainerImpl* obj; - HRESULT hr; + HRESULT hr; - obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicContainerImpl)); - if (NULL == obj) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } - obj->IDirectMusicContainer_iface.lpVtbl = &dmcontainer_vtbl; - obj->ref = 1; - dmobject_init(&obj->dmobj, &CLSID_DirectMusicContainer, - (IUnknown*)&obj->IDirectMusicContainer_iface); - obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl; - obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; + *ppobj = NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; + obj->IDirectMusicContainer_iface.lpVtbl = &dmcontainer_vtbl; + obj->ref = 1; + dmobject_init(&obj->dmobj, &CLSID_DirectMusicContainer, + (IUnknown*)&obj->IDirectMusicContainer_iface); + obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl; + obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; obj->pContainedObjects = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(struct list)); list_init (obj->pContainedObjects); - hr = IDirectMusicContainer_QueryInterface(&obj->IDirectMusicContainer_iface, lpcGUID, ppobj); - IDirectMusicContainer_Release(&obj->IDirectMusicContainer_iface); + hr = IDirectMusicContainer_QueryInterface(&obj->IDirectMusicContainer_iface, lpcGUID, ppobj); + IDirectMusicContainer_Release(&obj->IDirectMusicContainer_iface); - return hr; + return hr; } diff --git a/dlls/dmloader/dmobject.c b/dlls/dmloader/dmobject.c index b526b23d031..07d887a376c 100644 --- a/dlls/dmloader/dmobject.c +++ b/dlls/dmloader/dmobject.c @@ -28,7 +28,6 @@ #include "dmusics.h" #include "dmobject.h" #include "wine/debug.h" -#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(dmobj); WINE_DECLARE_DEBUG_CHANNEL(dmfile); @@ -375,7 +374,7 @@ HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) /* Reads chunk data of the form: DWORD - size of array element element[] - Array of elements - The caller needs to heap_free() the array. + The caller needs to free() the array. */ HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, unsigned int *count, DWORD elem_size) @@ -400,10 +399,10 @@ HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, *count = (chunk->size - sizeof(DWORD)) / elem_size; size = *count * elem_size; - if (!(*array = heap_alloc(size))) + if (!(*array = malloc(size))) return E_OUTOFMEMORY; if (FAILED(hr = stream_read(stream, *array, size))) { - heap_free(*array); + free(*array); *array = NULL; return hr; } diff --git a/dlls/dmloader/loader.c b/dlls/dmloader/loader.c index f303f93baaa..7b1fb8d04a5 100644 --- a/dlls/dmloader/loader.c +++ b/dlls/dmloader/loader.c @@ -155,8 +155,8 @@ static ULONG WINAPI IDirectMusicLoaderImpl_Release(IDirectMusicLoader8 *iface) IDirectMusicLoader8_ClearCache(iface, &GUID_DirectMusicAllTypes); for (i = 0; i < ARRAY_SIZE(classes); i++) - HeapFree(GetProcessHeap(), 0, This->search_paths[i]); - HeapFree(GetProcessHeap(), 0, This); + free(This->search_paths[i]); + free(This); } return ref; @@ -427,7 +427,7 @@ static HRESULT WINAPI IDirectMusicLoaderImpl_GetObject(IDirectMusicLoader8 *ifac bCache = is_cache_enabled(This, &pDesc->guidClass); if (bCache) { if (!pObjectEntry) { - pObjectEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(*pObjectEntry)); + pObjectEntry = calloc(1, sizeof(*pObjectEntry)); DM_STRUCT_INIT(&pObjectEntry->Desc); DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc); pObjectEntry->pObject = pObject; @@ -566,7 +566,7 @@ static HRESULT WINAPI IDirectMusicLoaderImpl_SetObject(IDirectMusicLoader8 *ifac TRACE(": adding alias entry with following info:\n"); if (TRACE_ON(dmloader)) dump_DMUS_OBJECTDESC(pDesc); - pNewEntry = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(*pNewEntry)); + pNewEntry = calloc(1, sizeof(*pNewEntry)); /* use this function instead of pure memcpy due to streams (memcpy just copies pointer), which is basically used further by app that called SetDescriptor... better safety than exception */ DMUSIC_CopyDescriptor (&pNewEntry->Desc, pDesc); @@ -601,7 +601,7 @@ static HRESULT WINAPI IDirectMusicLoaderImpl_SetSearchDirectory(IDirectMusicLoad return S_OK; if (!This->search_paths[index]) - This->search_paths[index] = HeapAlloc(GetProcessHeap(), 0, MAX_PATH); + This->search_paths[index] = malloc(MAX_PATH); else if (!wcsncmp(This->search_paths[index], path, MAX_PATH)) return S_FALSE; @@ -743,7 +743,7 @@ static HRESULT WINAPI IDirectMusicLoaderImpl_ClearCache(IDirectMusicLoader8 *ifa /* basically, wrap to ReleaseObject for each object found */ IDirectMusicLoader8_ReleaseObject(iface, obj->pObject); list_remove(&obj->entry); - HeapFree(GetProcessHeap(), 0, obj); + free(obj); } } @@ -910,11 +910,8 @@ HRESULT create_dmloader(REFIID lpcGUID, void **ppobj) struct list *pEntry; TRACE("(%s, %p)\n", debugstr_dmguid(lpcGUID), ppobj); - obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderImpl)); - if (NULL == obj) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + *ppobj = NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicLoader8_iface.lpVtbl = &DirectMusicLoader_Loader_Vtbl; obj->ref = 0; /* Will be inited with QueryInterface */ list_init(&obj->cache); diff --git a/dlls/dmloader/loaderstream.c b/dlls/dmloader/loaderstream.c index 38862c0fec7..c2c5105a5e9 100644 --- a/dlls/dmloader/loaderstream.c +++ b/dlls/dmloader/loaderstream.c @@ -122,7 +122,7 @@ static ULONG WINAPI IDirectMusicLoaderFileStream_IStream_Release (LPSTREAM iface if (dwRef == 0) { if (This->hFile) IDirectMusicLoaderFileStream_Detach (iface); - HeapFree (GetProcessHeap(), 0, This); + free(This); } return dwRef; @@ -292,11 +292,9 @@ HRESULT DMUSIC_CreateDirectMusicLoaderFileStream (void** ppobj) { IDirectMusicLoaderFileStream *obj; TRACE("(%p)\n", ppobj); - obj = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderFileStream)); - if (NULL == obj) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + + *ppobj = NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->StreamVtbl = &DirectMusicLoaderFileStream_Stream_Vtbl; obj->GetLoaderVtbl = &DirectMusicLoaderFileStream_GetLoader_Vtbl; obj->dwRef = 0; /* will be inited with QueryInterface */ @@ -369,7 +367,7 @@ static ULONG WINAPI IDirectMusicLoaderResourceStream_IStream_Release (LPSTREAM i TRACE("(%p): ReleaseRef to %ld\n", This, dwRef); if (dwRef == 0) { IDirectMusicLoaderResourceStream_Detach (iface); - HeapFree (GetProcessHeap(), 0, This); + free(This); } return dwRef; @@ -549,11 +547,9 @@ HRESULT DMUSIC_CreateDirectMusicLoaderResourceStream (void** ppobj) { IDirectMusicLoaderResourceStream *obj; TRACE("(%p)\n", ppobj); - obj = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderResourceStream)); - if (NULL == obj) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + + *ppobj = NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->StreamVtbl = &DirectMusicLoaderResourceStream_Stream_Vtbl; obj->GetLoaderVtbl = &DirectMusicLoaderResourceStream_GetLoader_Vtbl; obj->dwRef = 0; /* will be inited with QueryInterface */ @@ -801,11 +797,9 @@ HRESULT DMUSIC_CreateDirectMusicLoaderGenericStream (void** ppobj) { IDirectMusicLoaderGenericStream *obj; TRACE("(%p)\n", ppobj); - obj = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(IDirectMusicLoaderGenericStream)); - if (NULL == obj) { - *ppobj = NULL; - return E_OUTOFMEMORY; - } + + *ppobj = NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->StreamVtbl = &DirectMusicLoaderGenericStream_Stream_Vtbl; obj->GetLoaderVtbl = &DirectMusicLoaderGenericStream_GetLoader_Vtbl; obj->dwRef = 0; /* will be inited with QueryInterface */ From b67fc987a8483b64f5dedd1ebc739015192503ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 30 Aug 2023 19:55:51 +0200 Subject: [PATCH 2504/2777] dmloader: Use PARENTSRC with dmusic. (cherry picked from commit da8a8bbf9a7747f99d50beecfeea012067b2925b) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmloader/Makefile.in | 1 + dlls/dmloader/dmobject.c | 732 -------------------------------------- dlls/dmloader/dmobject.h | 124 ------- 3 files changed, 1 insertion(+), 856 deletions(-) delete mode 100644 dlls/dmloader/dmobject.c delete mode 100644 dlls/dmloader/dmobject.h diff --git a/dlls/dmloader/Makefile.in b/dlls/dmloader/Makefile.in index 4aa80c6dfb3..a8d3698ab6c 100644 --- a/dlls/dmloader/Makefile.in +++ b/dlls/dmloader/Makefile.in @@ -1,5 +1,6 @@ MODULE = dmloader.dll IMPORTS = dxguid uuid ole32 advapi32 +PARENTSRC = ../dmusic C_SRCS = \ container.c \ diff --git a/dlls/dmloader/dmobject.c b/dlls/dmloader/dmobject.c deleted file mode 100644 index 07d887a376c..00000000000 --- a/dlls/dmloader/dmobject.c +++ /dev/null @@ -1,732 +0,0 @@ -/* - * Base IDirectMusicObject Implementation - * Keep in sync with the master in dlls/dmusic/dmobject.c - * - * Copyright (C) 2003-2004 Rok Mandeljc - * Copyright (C) 2014 Michael Stefaniuc - * - * This program 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 program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define COBJMACROS -#include -#include "objbase.h" -#include "dmusici.h" -#include "dmusicf.h" -#include "dmusics.h" -#include "dmobject.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dmobj); -WINE_DECLARE_DEBUG_CHANNEL(dmfile); - -/* Debugging helpers */ -const char *debugstr_dmguid(const GUID *id) { - unsigned int i; -#define X(guid) { &guid, #guid } - static const struct { - const GUID *guid; - const char *name; - } guids[] = { - /* CLSIDs */ - X(CLSID_AudioVBScript), - X(CLSID_DirectMusic), - X(CLSID_DirectMusicAudioPathConfig), - X(CLSID_DirectMusicAuditionTrack), - X(CLSID_DirectMusicBand), - X(CLSID_DirectMusicBandTrack), - X(CLSID_DirectMusicChordMapTrack), - X(CLSID_DirectMusicChordMap), - X(CLSID_DirectMusicChordTrack), - X(CLSID_DirectMusicCollection), - X(CLSID_DirectMusicCommandTrack), - X(CLSID_DirectMusicComposer), - X(CLSID_DirectMusicContainer), - X(CLSID_DirectMusicGraph), - X(CLSID_DirectMusicLoader), - X(CLSID_DirectMusicLyricsTrack), - X(CLSID_DirectMusicMarkerTrack), - X(CLSID_DirectMusicMelodyFormulationTrack), - X(CLSID_DirectMusicMotifTrack), - X(CLSID_DirectMusicMuteTrack), - X(CLSID_DirectMusicParamControlTrack), - X(CLSID_DirectMusicPatternTrack), - X(CLSID_DirectMusicPerformance), - X(CLSID_DirectMusicScript), - X(CLSID_DirectMusicScriptAutoImpSegment), - X(CLSID_DirectMusicScriptAutoImpPerformance), - X(CLSID_DirectMusicScriptAutoImpSegmentState), - X(CLSID_DirectMusicScriptAutoImpAudioPathConfig), - X(CLSID_DirectMusicScriptAutoImpAudioPath), - X(CLSID_DirectMusicScriptAutoImpSong), - X(CLSID_DirectMusicScriptSourceCodeLoader), - X(CLSID_DirectMusicScriptTrack), - X(CLSID_DirectMusicSection), - X(CLSID_DirectMusicSegment), - X(CLSID_DirectMusicSegmentState), - X(CLSID_DirectMusicSegmentTriggerTrack), - X(CLSID_DirectMusicSegTriggerTrack), - X(CLSID_DirectMusicSeqTrack), - X(CLSID_DirectMusicSignPostTrack), - X(CLSID_DirectMusicSong), - X(CLSID_DirectMusicStyle), - X(CLSID_DirectMusicStyleTrack), - X(CLSID_DirectMusicSynth), - X(CLSID_DirectMusicSynthSink), - X(CLSID_DirectMusicSysExTrack), - X(CLSID_DirectMusicTemplate), - X(CLSID_DirectMusicTempoTrack), - X(CLSID_DirectMusicTimeSigTrack), - X(CLSID_DirectMusicWaveTrack), - X(CLSID_DirectSoundWave), - /* IIDs */ - X(IID_IDirectMusic), - X(IID_IDirectMusic2), - X(IID_IDirectMusic8), - X(IID_IDirectMusicAudioPath), - X(IID_IDirectMusicBand), - X(IID_IDirectMusicBuffer), - X(IID_IDirectMusicChordMap), - X(IID_IDirectMusicCollection), - X(IID_IDirectMusicComposer), - X(IID_IDirectMusicContainer), - X(IID_IDirectMusicDownload), - X(IID_IDirectMusicDownloadedInstrument), - X(IID_IDirectMusicGetLoader), - X(IID_IDirectMusicGraph), - X(IID_IDirectMusicInstrument), - X(IID_IDirectMusicLoader), - X(IID_IDirectMusicLoader8), - X(IID_IDirectMusicObject), - X(IID_IDirectMusicPatternTrack), - X(IID_IDirectMusicPerformance), - X(IID_IDirectMusicPerformance2), - X(IID_IDirectMusicPerformance8), - X(IID_IDirectMusicPort), - X(IID_IDirectMusicPortDownload), - X(IID_IDirectMusicScript), - X(IID_IDirectMusicSegment), - X(IID_IDirectMusicSegment2), - X(IID_IDirectMusicSegment8), - X(IID_IDirectMusicSegmentState), - X(IID_IDirectMusicSegmentState8), - X(IID_IDirectMusicStyle), - X(IID_IDirectMusicStyle8), - X(IID_IDirectMusicSynth), - X(IID_IDirectMusicSynth8), - X(IID_IDirectMusicSynthSink), - X(IID_IDirectMusicThru), - X(IID_IDirectMusicTool), - X(IID_IDirectMusicTool8), - X(IID_IDirectMusicTrack), - X(IID_IDirectMusicTrack8), - X(IID_IUnknown), - X(IID_IPersistStream), - X(IID_IStream), - X(IID_IClassFactory), - /* GUIDs */ - X(GUID_DirectMusicAllTypes), - X(GUID_NOTIFICATION_CHORD), - X(GUID_NOTIFICATION_COMMAND), - X(GUID_NOTIFICATION_MEASUREANDBEAT), - X(GUID_NOTIFICATION_PERFORMANCE), - X(GUID_NOTIFICATION_RECOMPOSE), - X(GUID_NOTIFICATION_SEGMENT), - X(GUID_BandParam), - X(GUID_ChordParam), - X(GUID_CommandParam), - X(GUID_CommandParam2), - X(GUID_CommandParamNext), - X(GUID_IDirectMusicBand), - X(GUID_IDirectMusicChordMap), - X(GUID_IDirectMusicStyle), - X(GUID_MuteParam), - X(GUID_Play_Marker), - X(GUID_RhythmParam), - X(GUID_TempoParam), - X(GUID_TimeSignature), - X(GUID_Valid_Start_Time), - X(GUID_Clear_All_Bands), - X(GUID_ConnectToDLSCollection), - X(GUID_Disable_Auto_Download), - X(GUID_DisableTempo), - X(GUID_DisableTimeSig), - X(GUID_Download), - X(GUID_DownloadToAudioPath), - X(GUID_Enable_Auto_Download), - X(GUID_EnableTempo), - X(GUID_EnableTimeSig), - X(GUID_IgnoreBankSelectForGM), - X(GUID_SeedVariations), - X(GUID_StandardMIDIFile), - X(GUID_Unload), - X(GUID_UnloadFromAudioPath), - X(GUID_Variations), - X(GUID_PerfMasterTempo), - X(GUID_PerfMasterVolume), - X(GUID_PerfMasterGrooveLevel), - X(GUID_PerfAutoDownload), - X(GUID_DefaultGMCollection), - X(GUID_Synth_Default), - X(GUID_Buffer_Reverb), - X(GUID_Buffer_EnvReverb), - X(GUID_Buffer_Stereo), - X(GUID_Buffer_3D_Dry), - X(GUID_Buffer_Mono), - X(GUID_DMUS_PROP_GM_Hardware), - X(GUID_DMUS_PROP_GS_Capable), - X(GUID_DMUS_PROP_GS_Hardware), - X(GUID_DMUS_PROP_DLS1), - X(GUID_DMUS_PROP_DLS2), - X(GUID_DMUS_PROP_Effects), - X(GUID_DMUS_PROP_INSTRUMENT2), - X(GUID_DMUS_PROP_LegacyCaps), - X(GUID_DMUS_PROP_MemorySize), - X(GUID_DMUS_PROP_SampleMemorySize), - X(GUID_DMUS_PROP_SamplePlaybackRate), - X(GUID_DMUS_PROP_SetSynthSink), - X(GUID_DMUS_PROP_SinkUsesDSound), - X(GUID_DMUS_PROP_SynthSink_DSOUND), - X(GUID_DMUS_PROP_SynthSink_WAVE), - X(GUID_DMUS_PROP_Volume), - X(GUID_DMUS_PROP_WavesReverb), - X(GUID_DMUS_PROP_WriteLatency), - X(GUID_DMUS_PROP_WritePeriod), - X(GUID_DMUS_PROP_XG_Capable), - X(GUID_DMUS_PROP_XG_Hardware) - }; -#undef X - - if (!id) - return "(null)"; - - for (i = 0; i < ARRAY_SIZE(guids); i++) - if (IsEqualGUID(id, guids[i].guid)) - return guids[i].name; - - return debugstr_guid(id); -} - -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc) -{ - if (!desc || !TRACE_ON(dmfile)) - return; - - TRACE_(dmfile)("DMUS_OBJECTDESC (%p):", desc); - TRACE_(dmfile)(" - dwSize = %lu\n", desc->dwSize); - -#define X(flag) if (desc->dwValidData & flag) TRACE_(dmfile)(#flag " ") - TRACE_(dmfile)(" - dwValidData = %#08lx ( ", desc->dwValidData); - X(DMUS_OBJ_OBJECT); - X(DMUS_OBJ_CLASS); - X(DMUS_OBJ_NAME); - X(DMUS_OBJ_CATEGORY); - X(DMUS_OBJ_FILENAME); - X(DMUS_OBJ_FULLPATH); - X(DMUS_OBJ_URL); - X(DMUS_OBJ_VERSION); - X(DMUS_OBJ_DATE); - X(DMUS_OBJ_LOADED); - X(DMUS_OBJ_MEMORY); - X(DMUS_OBJ_STREAM); - TRACE_(dmfile)(")\n"); -#undef X - - if (desc->dwValidData & DMUS_OBJ_CLASS) - TRACE_(dmfile)(" - guidClass = %s\n", debugstr_dmguid(&desc->guidClass)); - if (desc->dwValidData & DMUS_OBJ_OBJECT) - TRACE_(dmfile)(" - guidObject = %s\n", debugstr_guid(&desc->guidObject)); - - if (desc->dwValidData & DMUS_OBJ_DATE) { - SYSTEMTIME time; - FileTimeToSystemTime(&desc->ftDate, &time); - TRACE_(dmfile)(" - ftDate = \'%04u-%02u-%02u %02u:%02u:%02u\'\n", - time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond); - } - if (desc->dwValidData & DMUS_OBJ_VERSION) - TRACE_(dmfile)(" - vVersion = \'%u,%u,%u,%u\'\n", - HIWORD(desc->vVersion.dwVersionMS), LOWORD(desc->vVersion.dwVersionMS), - HIWORD(desc->vVersion.dwVersionLS), LOWORD(desc->vVersion.dwVersionLS)); - if (desc->dwValidData & DMUS_OBJ_NAME) - TRACE_(dmfile)(" - wszName = %s\n", debugstr_w(desc->wszName)); - if (desc->dwValidData & DMUS_OBJ_CATEGORY) - TRACE_(dmfile)(" - wszCategory = %s\n", debugstr_w(desc->wszCategory)); - if (desc->dwValidData & DMUS_OBJ_FILENAME) - TRACE_(dmfile)(" - wszFileName = %s\n", debugstr_w(desc->wszFileName)); - if (desc->dwValidData & DMUS_OBJ_MEMORY) - TRACE_(dmfile)(" - llMemLength = 0x%s - pbMemData = %p\n", - wine_dbgstr_longlong(desc->llMemLength), desc->pbMemData); - if (desc->dwValidData & DMUS_OBJ_STREAM) - TRACE_(dmfile)(" - pStream = %p\n", desc->pStream); -} - - -/* RIFF format parsing */ -#define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD)) - -const char *debugstr_chunk(const struct chunk_entry *chunk) -{ - const char *type = ""; - - if (!chunk) - return "(null)"; - if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST) - type = wine_dbg_sprintf("type %s, ", debugstr_fourcc(chunk->type)); - return wine_dbg_sprintf("%s chunk, %ssize %lu", debugstr_fourcc(chunk->id), type, chunk->size); -} - -static HRESULT stream_read(IStream *stream, void *data, ULONG size) -{ - ULONG read; - HRESULT hr; - - hr = IStream_Read(stream, data, size, &read); - if (FAILED(hr)) - TRACE_(dmfile)("IStream_Read failed: %#lx\n", hr); - else if (!read && read < size) { - /* All or nothing: Handle a partial read due to end of stream as an error */ - TRACE_(dmfile)("Short read: %lu < %lu\n", read, size); - return E_FAIL; - } - - return hr; -} - -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) -{ - static const LARGE_INTEGER zero; - ULONGLONG ck_end = 0, p_end = 0; - HRESULT hr; - - hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &chunk->offset); - if (FAILED(hr)) - return hr; - assert(!(chunk->offset.QuadPart & 1)); - if (chunk->parent) { - p_end = chunk->parent->offset.QuadPart + CHUNK_HDR_SIZE + ((chunk->parent->size + 1) & ~1); - if (chunk->offset.QuadPart == p_end) - return S_FALSE; - ck_end = chunk->offset.QuadPart + CHUNK_HDR_SIZE; - if (ck_end > p_end) { - WARN_(dmfile)("No space for sub-chunk header in parent chunk: ends at offset %s > %s\n", - wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end)); - return E_FAIL; - } - } - - hr = stream_read(stream, chunk, CHUNK_HDR_SIZE); - if (hr != S_OK) - return hr; - if (chunk->parent) { - ck_end += (chunk->size + 1) & ~1; - if (ck_end > p_end) { - WARN_(dmfile)("No space for sub-chunk data in parent chunk: ends at offset %s > %s\n", - wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end)); - return E_FAIL; - } - } - - if (chunk->id == FOURCC_LIST || chunk->id == FOURCC_RIFF) { - hr = stream_read(stream, &chunk->type, sizeof(FOURCC)); - if (hr != S_OK) - return hr != S_FALSE ? hr : E_FAIL; - } - - TRACE_(dmfile)("Returning %s\n", debugstr_chunk(chunk)); - - return S_OK; -} - -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER end; - - end.QuadPart = (chunk->offset.QuadPart + CHUNK_HDR_SIZE + chunk->size + 1) & ~(ULONGLONG)1; - - return IStream_Seek(stream, end, STREAM_SEEK_SET, NULL); -} - -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) -{ - HRESULT hr; - - if (chunk->id) { - hr = stream_skip_chunk(stream, chunk); - if (FAILED(hr)) - return hr; - } - - return stream_get_chunk(stream, chunk); -} - -/* Reads chunk data of the form: - DWORD - size of array element - element[] - Array of elements - The caller needs to free() the array. -*/ -HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size) -{ - DWORD size; - HRESULT hr; - - *array = NULL; - *count = 0; - - if (chunk->size < sizeof(DWORD)) { - WARN_(dmfile)("%s: Too short to read element size\n", debugstr_chunk(chunk)); - return E_FAIL; - } - if (FAILED(hr = stream_read(stream, &size, sizeof(DWORD)))) - return hr; - if (size != elem_size) { - WARN_(dmfile)("%s: Array element size mismatch: got %lu, expected %lu\n", - debugstr_chunk(chunk), size, elem_size); - return DMUS_E_UNSUPPORTED_STREAM; - } - - *count = (chunk->size - sizeof(DWORD)) / elem_size; - size = *count * elem_size; - if (!(*array = malloc(size))) - return E_OUTOFMEMORY; - if (FAILED(hr = stream_read(stream, *array, size))) { - free(*array); - *array = NULL; - return hr; - } - - if (chunk->size > size + sizeof(DWORD)) { - WARN_(dmfile)("%s: Extraneous data at end of array\n", debugstr_chunk(chunk)); - stream_skip_chunk(stream, chunk); - return S_FALSE; - } - return S_OK; -} - -HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size) -{ - if (chunk->size != size) { - WARN_(dmfile)("Chunk %s (size %lu, offset %s) doesn't contains the expected data size %lu\n", - debugstr_fourcc(chunk->id), chunk->size, - wine_dbgstr_longlong(chunk->offset.QuadPart), size); - return E_FAIL; - } - return stream_read(stream, data, size); -} - -HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size) -{ - ULONG len; - HRESULT hr; - - hr = IStream_Read(stream, str, min(chunk->size, size), &len); - if (FAILED(hr)) - return hr; - - /* Don't assume the string is properly zero terminated */ - str[min(len, size - 1)] = 0; - - if (len < chunk->size) - return S_FALSE; - return S_OK; -} - - - -/* Generic IDirectMusicObject methods */ -static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface) -{ - return CONTAINING_RECORD(iface, struct dmobject, IDirectMusicObject_iface); -} - -HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); -} - -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_AddRef(This->outer_unk); -} - -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_Release(This->outer_unk); -} - -HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - - TRACE("(%p/%p)->(%p)\n", iface, This, desc); - - if (!desc) - return E_POINTER; - - memcpy(desc, &This->desc, This->desc.dwSize); - - return S_OK; -} - -HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - HRESULT ret = S_OK; - - TRACE("(%p, %p)\n", iface, desc); - - if (!desc) - return E_POINTER; - - /* Immutable property */ - if (desc->dwValidData & DMUS_OBJ_CLASS) - { - desc->dwValidData &= ~DMUS_OBJ_CLASS; - ret = S_FALSE; - } - /* Set only valid fields */ - if (desc->dwValidData & DMUS_OBJ_OBJECT) - This->desc.guidObject = desc->guidObject; - if (desc->dwValidData & DMUS_OBJ_NAME) - lstrcpynW(This->desc.wszName, desc->wszName, DMUS_MAX_NAME); - if (desc->dwValidData & DMUS_OBJ_CATEGORY) - lstrcpynW(This->desc.wszCategory, desc->wszCategory, DMUS_MAX_CATEGORY); - if (desc->dwValidData & DMUS_OBJ_FILENAME) - lstrcpynW(This->desc.wszFileName, desc->wszFileName, DMUS_MAX_FILENAME); - if (desc->dwValidData & DMUS_OBJ_VERSION) - This->desc.vVersion = desc->vVersion; - if (desc->dwValidData & DMUS_OBJ_DATE) - This->desc.ftDate = desc->ftDate; - if (desc->dwValidData & DMUS_OBJ_MEMORY) { - This->desc.llMemLength = desc->llMemLength; - memcpy(This->desc.pbMemData, desc->pbMemData, desc->llMemLength); - } - if (desc->dwValidData & DMUS_OBJ_STREAM) - IStream_Clone(desc->pStream, &This->desc.pStream); - - This->desc.dwValidData |= desc->dwValidData; - - return ret; -} - -/* Helper for IDirectMusicObject::ParseDescriptor */ -static inline void info_get_name(IStream *stream, const struct chunk_entry *info, - DMUS_OBJECTDESC *desc) -{ - struct chunk_entry chunk = {.parent = info}; - char name[DMUS_MAX_NAME]; - ULONG len; - HRESULT hr = E_FAIL; - - while (stream_next_chunk(stream, &chunk) == S_OK) - if (chunk.id == mmioFOURCC('I','N','A','M')) - hr = IStream_Read(stream, name, min(chunk.size, sizeof(name)), &len); - - if (SUCCEEDED(hr)) { - len = MultiByteToWideChar(CP_ACP, 0, name, len, desc->wszName, sizeof(desc->wszName)); - desc->wszName[min(len, sizeof(desc->wszName) - 1)] = 0; - desc->dwValidData |= DMUS_OBJ_NAME; - } -} - -static inline void unfo_get_name(IStream *stream, const struct chunk_entry *unfo, - DMUS_OBJECTDESC *desc, BOOL inam) -{ - struct chunk_entry chunk = {.parent = unfo}; - - while (stream_next_chunk(stream, &chunk) == S_OK) - if (chunk.id == DMUS_FOURCC_UNAM_CHUNK || (inam && chunk.id == mmioFOURCC('I','N','A','M'))) - if (stream_chunk_get_wstr(stream, &chunk, desc->wszName, sizeof(desc->wszName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_NAME; -} - -HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported) -{ - struct chunk_entry chunk = {.parent = riff}; - HRESULT hr; - - TRACE("Looking for %#lx in %p: %s\n", supported, stream, debugstr_chunk(riff)); - - desc->dwValidData = 0; - desc->dwSize = sizeof(*desc); - - while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { - switch (chunk.id) { - case DMUS_FOURCC_CATEGORY_CHUNK: - if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk, - desc->wszCategory, sizeof(desc->wszCategory)) == S_OK) - desc->dwValidData |= DMUS_OBJ_CATEGORY; - break; - case DMUS_FOURCC_DATE_CHUNK: - if ((supported & DMUS_OBJ_DATE) && stream_chunk_get_data(stream, &chunk, - &desc->ftDate, sizeof(desc->ftDate)) == S_OK) - desc->dwValidData |= DMUS_OBJ_DATE; - break; - case DMUS_FOURCC_FILE_CHUNK: - if ((supported & DMUS_OBJ_FILENAME) && stream_chunk_get_wstr(stream, &chunk, - desc->wszFileName, sizeof(desc->wszFileName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_FILENAME; - break; - case DMUS_FOURCC_GUID_CHUNK: - if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk, - &desc->guidObject, sizeof(desc->guidObject)) == S_OK) - desc->dwValidData |= DMUS_OBJ_OBJECT; - break; - case DMUS_FOURCC_NAME_CHUNK: - if ((supported & DMUS_OBJ_NAME) && stream_chunk_get_wstr(stream, &chunk, - desc->wszName, sizeof(desc->wszName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_NAME; - break; - case DMUS_FOURCC_VERSION_CHUNK: - if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk, - &desc->vVersion, sizeof(desc->vVersion)) == S_OK) - desc->dwValidData |= DMUS_OBJ_VERSION; - break; - case FOURCC_LIST: - if (chunk.type == DMUS_FOURCC_UNFO_LIST && (supported & DMUS_OBJ_NAME)) - unfo_get_name(stream, &chunk, desc, supported & DMUS_OBJ_NAME_INAM); - else if (chunk.type == DMUS_FOURCC_INFO_LIST && (supported & DMUS_OBJ_NAME_INFO)) - info_get_name(stream, &chunk, desc); - break; - } - } - TRACE("Found %#lx\n", desc->dwValidData); - - return hr; -} - -HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj) -{ - struct chunk_entry chunk = {.parent = list}; - IDirectMusicGetLoader *getloader; - IDirectMusicLoader *loader; - DMUS_OBJECTDESC desc; - DMUS_IO_REFERENCE reference; - HRESULT hr; - - if (FAILED(hr = stream_next_chunk(stream, &chunk))) - return hr; - if (chunk.id != DMUS_FOURCC_REF_CHUNK) - return DMUS_E_UNSUPPORTED_STREAM; - - if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &reference, sizeof(reference)))) { - WARN("Failed to read data of %s\n", debugstr_chunk(&chunk)); - return hr; - } - TRACE("REFERENCE guidClassID %s, dwValidData %#lx\n", debugstr_dmguid(&reference.guidClassID), - reference.dwValidData); - - if (FAILED(hr = dmobj_parsedescriptor(stream, list, &desc, reference.dwValidData))) - return hr; - desc.guidClass = reference.guidClassID; - desc.dwValidData |= DMUS_OBJ_CLASS; - dump_DMUS_OBJECTDESC(&desc); - - if (FAILED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getloader))) - return hr; - hr = IDirectMusicGetLoader_GetLoader(getloader, &loader); - IDirectMusicGetLoader_Release(getloader); - if (FAILED(hr)) - return hr; - - hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicObject, (void**)dmobj); - IDirectMusicLoader_Release(loader); - - return hr; -} - -/* Generic IPersistStream methods */ -static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface) -{ - return CONTAINING_RECORD(iface, struct dmobject, IPersistStream_iface); -} - -HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); -} - -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_AddRef(This->outer_unk); -} - -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_Release(This->outer_unk); -} - -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - - TRACE("(%p, %p)\n", This, class); - - if (!class) - return E_POINTER; - - *class = This->desc.guidClass; - - return S_OK; -} - -/* IPersistStream methods not implemented in native */ -HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) -{ - TRACE("(%p, %p): method not implemented\n", iface, class); - return E_NOTIMPL; -} - -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface) -{ - TRACE("(%p): method not implemented, always returning S_FALSE\n", iface); - return S_FALSE; -} - -HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty) -{ - TRACE("(%p, %p, %d): method not implemented\n", iface, stream, clear_dirty); - return E_NOTIMPL; -} - -HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, ULARGE_INTEGER *size) -{ - TRACE("(%p, %p): method not implemented\n", iface, size); - return E_NOTIMPL; -} - - -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk) -{ - dmobj->outer_unk = outer_unk; - dmobj->desc.dwSize = sizeof(dmobj->desc); - dmobj->desc.dwValidData = DMUS_OBJ_CLASS; - dmobj->desc.guidClass = *class; -} diff --git a/dlls/dmloader/dmobject.h b/dlls/dmloader/dmobject.h deleted file mode 100644 index 772be015c80..00000000000 --- a/dlls/dmloader/dmobject.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Base IDirectMusicObject Implementation - * Keep in sync with the master in dlls/dmusic/dmobject.h - * - * Copyright (C) 2014 Michael Stefaniuc - * - * This program 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 program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "wine/debug.h" - -/* RIFF stream parsing */ -struct chunk_entry; -struct chunk_entry { - FOURCC id; - DWORD size; - FOURCC type; /* valid only for LIST and RIFF chunks */ - ULARGE_INTEGER offset; /* chunk offset from start of stream */ - const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */ -}; - -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk); -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk); -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk); - -HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size); -HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size); -HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size); - -static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER offset; - - offset.QuadPart = chunk->offset.QuadPart + sizeof(FOURCC) + sizeof(DWORD); - if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST) - offset.QuadPart += sizeof(FOURCC); - - return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); -} - -static inline HRESULT stream_reset_chunk_start(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER offset; - - offset.QuadPart = chunk->offset.QuadPart; - - return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); -} - - -/* IDirectMusicObject base object */ -struct dmobject { - IDirectMusicObject IDirectMusicObject_iface; - IPersistStream IPersistStream_iface; - IUnknown *outer_unk; - DMUS_OBJECTDESC desc; -}; - -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk); - -/* Generic IDirectMusicObject methods */ -HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface); -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface); -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface); -HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc); -HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc); - -/* Helper for IDirectMusicObject::ParseDescriptor */ -HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported); -/* Additional supported flags for dmobj_parsedescriptor. - DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */ -#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */ -#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */ - -/* 'DMRF' (reference list) helper */ -HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj); - -/* Generic IPersistStream methods */ -HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface); -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface); -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface); -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class); - -/* IPersistStream methods not implemented in native */ -HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, - CLSID *class); -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface); -HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty); -HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, - ULARGE_INTEGER *size); - -/* Debugging helpers */ -const char *debugstr_chunk(const struct chunk_entry *chunk); -const char *debugstr_dmguid(const GUID *id); -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc); - -static inline const char *debugstr_fourcc(DWORD fourcc) -{ - if (!fourcc) return "''"; - return wine_dbg_sprintf("'%c%c%c%c'", (char)(fourcc), (char)(fourcc >> 8), - (char)(fourcc >> 16), (char)(fourcc >> 24)); -} From 8407827a6e0ba8fe2c1b697d10e4d82d77565260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 22 Aug 2023 17:42:13 +0200 Subject: [PATCH 2505/2777] dmscript: Always return S_FALSE from DllCanUnloadNow. (cherry picked from commit b02b32f9b7eef9c5ed88ef60886f3b64954b5a47) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmscript/dmscript_main.c | 22 ---------------------- dlls/dmscript/dmscript_private.h | 7 ------- dlls/dmscript/script.c | 2 -- dlls/dmscript/scripttrack.c | 2 -- 4 files changed, 33 deletions(-) diff --git a/dlls/dmscript/dmscript_main.c b/dlls/dmscript/dmscript_main.c index f6785176aec..db5f163b829 100644 --- a/dlls/dmscript/dmscript_main.c +++ b/dlls/dmscript/dmscript_main.c @@ -38,8 +38,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmscript); -LONG DMSCRIPT_refCount = 0; - typedef struct { IClassFactory IClassFactory_iface; HRESULT (*fnCreateInstance)(REFIID riid, void **ppv, IUnknown *pUnkOuter); @@ -82,15 +80,11 @@ static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID r static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) { - DMSCRIPT_LockModule(); - return 2; /* non-heap based object */ } static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) { - DMSCRIPT_UnlockModule(); - return 1; /* non-heap based object */ } @@ -107,12 +101,6 @@ static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock) { TRACE("(%d)\n", dolock); - - if (dolock) - DMSCRIPT_LockModule(); - else - DMSCRIPT_UnlockModule(); - return S_OK; } @@ -140,16 +128,6 @@ static IClassFactoryImpl ScriptAutoImplAudioPath_CF = {{&classfactory_vtbl}, create_unimpl_instance}; static IClassFactoryImpl ScriptAutoImplSong_CF = {{&classfactory_vtbl}, create_unimpl_instance}; -/****************************************************************** - * DllCanUnloadNow (DMSCRIPT.@) - * - * - */ -HRESULT WINAPI DllCanUnloadNow(void) -{ - return DMSCRIPT_refCount != 0 ? S_FALSE : S_OK; -} - /****************************************************************** * DllGetClassObject (DMSCRIPT.@) diff --git a/dlls/dmscript/dmscript_private.h b/dlls/dmscript/dmscript_private.h index 90808d59f00..f715c083523 100644 --- a/dlls/dmscript/dmscript_private.h +++ b/dlls/dmscript/dmscript_private.h @@ -48,13 +48,6 @@ extern HRESULT DMUSIC_CreateDirectMusicScriptImpl(REFIID riid, void **ppobj, IUn extern HRESULT DMUSIC_CreateDirectMusicScriptTrack(REFIID riid, void **ppobj, IUnknown *pUnkOuter); -/********************************************************************** - * Dll lifetime tracking declaration for dmscript.dll - */ -extern LONG DMSCRIPT_refCount; -static inline void DMSCRIPT_LockModule(void) { InterlockedIncrement( &DMSCRIPT_refCount ); } -static inline void DMSCRIPT_UnlockModule(void) { InterlockedDecrement( &DMSCRIPT_refCount ); } - /***************************************************************************** * Misc. */ diff --git a/dlls/dmscript/script.c b/dlls/dmscript/script.c index 375eebf69aa..dbfcdca7d83 100644 --- a/dlls/dmscript/script.c +++ b/dlls/dmscript/script.c @@ -94,7 +94,6 @@ static ULONG WINAPI IDirectMusicScriptImpl_Release(IDirectMusicScript *iface) HeapFree(GetProcessHeap(), 0, This->pwzLanguage); HeapFree(GetProcessHeap(), 0, This->pwzSource); HeapFree(GetProcessHeap(), 0, This); - DMSCRIPT_UnlockModule(); } return ref; @@ -508,7 +507,6 @@ HRESULT DMUSIC_CreateDirectMusicScriptImpl(REFIID lpcGUID, void **ppobj, IUnknow obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl; obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - DMSCRIPT_LockModule(); hr = IDirectMusicScript_QueryInterface(&obj->IDirectMusicScript_iface, lpcGUID, ppobj); IDirectMusicScript_Release(&obj->IDirectMusicScript_iface); diff --git a/dlls/dmscript/scripttrack.c b/dlls/dmscript/scripttrack.c index fbe454c09e5..92dd6d15ec6 100644 --- a/dlls/dmscript/scripttrack.c +++ b/dlls/dmscript/scripttrack.c @@ -86,7 +86,6 @@ static ULONG WINAPI script_track_Release(IDirectMusicTrack8 *iface) if (!ref) { HeapFree(GetProcessHeap(), 0, This); - DMSCRIPT_UnlockModule(); } return ref; @@ -338,7 +337,6 @@ HRESULT DMUSIC_CreateDirectMusicScriptTrack(REFIID riid, void **ret_iface, IUnkn track->desc.guidClass = CLSID_DirectMusicScriptTrack; track->ref = 1; - DMSCRIPT_LockModule(); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, riid, ret_iface); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); From 5cb988122b5f0b594d70d568d25ffe1accb11341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 9 Sep 2023 09:23:38 +0200 Subject: [PATCH 2506/2777] dmscript: Use CRT allocation functions. (cherry picked from commit f49b5ca85ec4bae5272ee102aa129a85a20dfd78) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmscript/dmobject.c | 7 +++---- dlls/dmscript/script.c | 27 ++++++++++++--------------- dlls/dmscript/scripttrack.c | 9 ++------- 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/dlls/dmscript/dmobject.c b/dlls/dmscript/dmobject.c index b526b23d031..07d887a376c 100644 --- a/dlls/dmscript/dmobject.c +++ b/dlls/dmscript/dmobject.c @@ -28,7 +28,6 @@ #include "dmusics.h" #include "dmobject.h" #include "wine/debug.h" -#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(dmobj); WINE_DECLARE_DEBUG_CHANNEL(dmfile); @@ -375,7 +374,7 @@ HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) /* Reads chunk data of the form: DWORD - size of array element element[] - Array of elements - The caller needs to heap_free() the array. + The caller needs to free() the array. */ HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, unsigned int *count, DWORD elem_size) @@ -400,10 +399,10 @@ HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, *count = (chunk->size - sizeof(DWORD)) / elem_size; size = *count * elem_size; - if (!(*array = heap_alloc(size))) + if (!(*array = malloc(size))) return E_OUTOFMEMORY; if (FAILED(hr = stream_read(stream, *array, size))) { - heap_free(*array); + free(*array); *array = NULL; return hr; } diff --git a/dlls/dmscript/script.c b/dlls/dmscript/script.c index dbfcdca7d83..01d4bcd0290 100644 --- a/dlls/dmscript/script.c +++ b/dlls/dmscript/script.c @@ -89,11 +89,11 @@ static ULONG WINAPI IDirectMusicScriptImpl_Release(IDirectMusicScript *iface) TRACE("(%p) ref=%ld\n", This, ref); if (!ref) { - HeapFree(GetProcessHeap(), 0, This->pHeader); - HeapFree(GetProcessHeap(), 0, This->pVersion); - HeapFree(GetProcessHeap(), 0, This->pwzLanguage); - HeapFree(GetProcessHeap(), 0, This->pwzSource); - HeapFree(GetProcessHeap(), 0, This); + free(This->pHeader); + free(This->pVersion); + free(This->pwzLanguage); + free(This->pwzSource); + free(This); } return ref; @@ -275,36 +275,36 @@ static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface, IStream *pS switch (Chunk.fccID) { case DMUS_FOURCC_SCRIPT_CHUNK: { TRACE_(dmfile)(": script header chunk\n"); - This->pHeader = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize); + This->pHeader = calloc(1, Chunk.dwSize); IStream_Read (pStm, This->pHeader, Chunk.dwSize, NULL); break; } case DMUS_FOURCC_SCRIPTVERSION_CHUNK: { TRACE_(dmfile)(": script version chunk\n"); - This->pVersion = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize); + This->pVersion = calloc(1, Chunk.dwSize); IStream_Read (pStm, This->pVersion, Chunk.dwSize, NULL); TRACE_(dmfile)("version: 0x%08lx.0x%08lx\n", This->pVersion->dwVersionMS, This->pVersion->dwVersionLS); break; } case DMUS_FOURCC_SCRIPTLANGUAGE_CHUNK: { TRACE_(dmfile)(": script language chunk\n"); - This->pwzLanguage = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize); + This->pwzLanguage = calloc(1, Chunk.dwSize); IStream_Read (pStm, This->pwzLanguage, Chunk.dwSize, NULL); TRACE_(dmfile)("using language: %s\n", debugstr_w(This->pwzLanguage)); break; } case DMUS_FOURCC_SCRIPTSOURCE_CHUNK: { TRACE_(dmfile)(": script source chunk\n"); - This->pwzSource = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize); + This->pwzSource = calloc(1, Chunk.dwSize); IStream_Read (pStm, This->pwzSource, Chunk.dwSize, NULL); if (TRACE_ON(dmscript)) { int count = WideCharToMultiByte(CP_ACP, 0, This->pwzSource, -1, NULL, 0, NULL, NULL); - LPSTR str = HeapAlloc(GetProcessHeap (), 0, count); + LPSTR str = malloc(count); WideCharToMultiByte(CP_ACP, 0, This->pwzSource, -1, str, count, NULL, NULL); str[count-1] = '\n'; TRACE("source:\n"); fwrite( str, 1, count, stderr ); - HeapFree(GetProcessHeap(), 0, str); + free(str); } break; } @@ -497,10 +497,7 @@ HRESULT DMUSIC_CreateDirectMusicScriptImpl(REFIID lpcGUID, void **ppobj, IUnknow if (pUnkOuter) return CLASS_E_NOAGGREGATION; - obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicScriptImpl)); - if (!obj) - return E_OUTOFMEMORY; - + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicScript_iface.lpVtbl = &dmscript_vtbl; obj->ref = 1; dmobject_init(&obj->dmobj, &CLSID_DirectMusicScript, (IUnknown*)&obj->IDirectMusicScript_iface); diff --git a/dlls/dmscript/scripttrack.c b/dlls/dmscript/scripttrack.c index 92dd6d15ec6..74d45afacbe 100644 --- a/dlls/dmscript/scripttrack.c +++ b/dlls/dmscript/scripttrack.c @@ -84,9 +84,7 @@ static ULONG WINAPI script_track_Release(IDirectMusicTrack8 *iface) TRACE("(%p) ref=%ld\n", This, ref); - if (!ref) { - HeapFree(GetProcessHeap(), 0, This); - } + if (!ref) free(This); return ref; } @@ -326,10 +324,7 @@ HRESULT DMUSIC_CreateDirectMusicScriptTrack(REFIID riid, void **ret_iface, IUnkn if (pUnkOuter) return CLASS_E_NOAGGREGATION; - track = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*track)); - if (!track) - return E_OUTOFMEMORY; - + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; track->IPersistStream_iface.lpVtbl = &persist_vtbl; track->desc.dwSize = sizeof(track->desc); From 76d73716194377488f1257ac8e794f8c5ab96859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 30 Aug 2023 19:55:16 +0200 Subject: [PATCH 2507/2777] dmscript: Use PARENTSRC with dmusic. (cherry picked from commit d6f049e8a59a606c82a747e896735826eb6052e7) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmscript/Makefile.in | 1 + dlls/dmscript/dmobject.c | 732 -------------------------------------- dlls/dmscript/dmobject.h | 124 ------- 3 files changed, 1 insertion(+), 856 deletions(-) delete mode 100644 dlls/dmscript/dmobject.c delete mode 100644 dlls/dmscript/dmobject.h diff --git a/dlls/dmscript/Makefile.in b/dlls/dmscript/Makefile.in index 55107e116c9..9eac24c2d86 100644 --- a/dlls/dmscript/Makefile.in +++ b/dlls/dmscript/Makefile.in @@ -1,5 +1,6 @@ MODULE = dmscript.dll IMPORTS = dxguid uuid ole32 advapi32 +PARENTSRC = ../dmusic C_SRCS = \ dmobject.c \ diff --git a/dlls/dmscript/dmobject.c b/dlls/dmscript/dmobject.c deleted file mode 100644 index 07d887a376c..00000000000 --- a/dlls/dmscript/dmobject.c +++ /dev/null @@ -1,732 +0,0 @@ -/* - * Base IDirectMusicObject Implementation - * Keep in sync with the master in dlls/dmusic/dmobject.c - * - * Copyright (C) 2003-2004 Rok Mandeljc - * Copyright (C) 2014 Michael Stefaniuc - * - * This program 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 program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define COBJMACROS -#include -#include "objbase.h" -#include "dmusici.h" -#include "dmusicf.h" -#include "dmusics.h" -#include "dmobject.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dmobj); -WINE_DECLARE_DEBUG_CHANNEL(dmfile); - -/* Debugging helpers */ -const char *debugstr_dmguid(const GUID *id) { - unsigned int i; -#define X(guid) { &guid, #guid } - static const struct { - const GUID *guid; - const char *name; - } guids[] = { - /* CLSIDs */ - X(CLSID_AudioVBScript), - X(CLSID_DirectMusic), - X(CLSID_DirectMusicAudioPathConfig), - X(CLSID_DirectMusicAuditionTrack), - X(CLSID_DirectMusicBand), - X(CLSID_DirectMusicBandTrack), - X(CLSID_DirectMusicChordMapTrack), - X(CLSID_DirectMusicChordMap), - X(CLSID_DirectMusicChordTrack), - X(CLSID_DirectMusicCollection), - X(CLSID_DirectMusicCommandTrack), - X(CLSID_DirectMusicComposer), - X(CLSID_DirectMusicContainer), - X(CLSID_DirectMusicGraph), - X(CLSID_DirectMusicLoader), - X(CLSID_DirectMusicLyricsTrack), - X(CLSID_DirectMusicMarkerTrack), - X(CLSID_DirectMusicMelodyFormulationTrack), - X(CLSID_DirectMusicMotifTrack), - X(CLSID_DirectMusicMuteTrack), - X(CLSID_DirectMusicParamControlTrack), - X(CLSID_DirectMusicPatternTrack), - X(CLSID_DirectMusicPerformance), - X(CLSID_DirectMusicScript), - X(CLSID_DirectMusicScriptAutoImpSegment), - X(CLSID_DirectMusicScriptAutoImpPerformance), - X(CLSID_DirectMusicScriptAutoImpSegmentState), - X(CLSID_DirectMusicScriptAutoImpAudioPathConfig), - X(CLSID_DirectMusicScriptAutoImpAudioPath), - X(CLSID_DirectMusicScriptAutoImpSong), - X(CLSID_DirectMusicScriptSourceCodeLoader), - X(CLSID_DirectMusicScriptTrack), - X(CLSID_DirectMusicSection), - X(CLSID_DirectMusicSegment), - X(CLSID_DirectMusicSegmentState), - X(CLSID_DirectMusicSegmentTriggerTrack), - X(CLSID_DirectMusicSegTriggerTrack), - X(CLSID_DirectMusicSeqTrack), - X(CLSID_DirectMusicSignPostTrack), - X(CLSID_DirectMusicSong), - X(CLSID_DirectMusicStyle), - X(CLSID_DirectMusicStyleTrack), - X(CLSID_DirectMusicSynth), - X(CLSID_DirectMusicSynthSink), - X(CLSID_DirectMusicSysExTrack), - X(CLSID_DirectMusicTemplate), - X(CLSID_DirectMusicTempoTrack), - X(CLSID_DirectMusicTimeSigTrack), - X(CLSID_DirectMusicWaveTrack), - X(CLSID_DirectSoundWave), - /* IIDs */ - X(IID_IDirectMusic), - X(IID_IDirectMusic2), - X(IID_IDirectMusic8), - X(IID_IDirectMusicAudioPath), - X(IID_IDirectMusicBand), - X(IID_IDirectMusicBuffer), - X(IID_IDirectMusicChordMap), - X(IID_IDirectMusicCollection), - X(IID_IDirectMusicComposer), - X(IID_IDirectMusicContainer), - X(IID_IDirectMusicDownload), - X(IID_IDirectMusicDownloadedInstrument), - X(IID_IDirectMusicGetLoader), - X(IID_IDirectMusicGraph), - X(IID_IDirectMusicInstrument), - X(IID_IDirectMusicLoader), - X(IID_IDirectMusicLoader8), - X(IID_IDirectMusicObject), - X(IID_IDirectMusicPatternTrack), - X(IID_IDirectMusicPerformance), - X(IID_IDirectMusicPerformance2), - X(IID_IDirectMusicPerformance8), - X(IID_IDirectMusicPort), - X(IID_IDirectMusicPortDownload), - X(IID_IDirectMusicScript), - X(IID_IDirectMusicSegment), - X(IID_IDirectMusicSegment2), - X(IID_IDirectMusicSegment8), - X(IID_IDirectMusicSegmentState), - X(IID_IDirectMusicSegmentState8), - X(IID_IDirectMusicStyle), - X(IID_IDirectMusicStyle8), - X(IID_IDirectMusicSynth), - X(IID_IDirectMusicSynth8), - X(IID_IDirectMusicSynthSink), - X(IID_IDirectMusicThru), - X(IID_IDirectMusicTool), - X(IID_IDirectMusicTool8), - X(IID_IDirectMusicTrack), - X(IID_IDirectMusicTrack8), - X(IID_IUnknown), - X(IID_IPersistStream), - X(IID_IStream), - X(IID_IClassFactory), - /* GUIDs */ - X(GUID_DirectMusicAllTypes), - X(GUID_NOTIFICATION_CHORD), - X(GUID_NOTIFICATION_COMMAND), - X(GUID_NOTIFICATION_MEASUREANDBEAT), - X(GUID_NOTIFICATION_PERFORMANCE), - X(GUID_NOTIFICATION_RECOMPOSE), - X(GUID_NOTIFICATION_SEGMENT), - X(GUID_BandParam), - X(GUID_ChordParam), - X(GUID_CommandParam), - X(GUID_CommandParam2), - X(GUID_CommandParamNext), - X(GUID_IDirectMusicBand), - X(GUID_IDirectMusicChordMap), - X(GUID_IDirectMusicStyle), - X(GUID_MuteParam), - X(GUID_Play_Marker), - X(GUID_RhythmParam), - X(GUID_TempoParam), - X(GUID_TimeSignature), - X(GUID_Valid_Start_Time), - X(GUID_Clear_All_Bands), - X(GUID_ConnectToDLSCollection), - X(GUID_Disable_Auto_Download), - X(GUID_DisableTempo), - X(GUID_DisableTimeSig), - X(GUID_Download), - X(GUID_DownloadToAudioPath), - X(GUID_Enable_Auto_Download), - X(GUID_EnableTempo), - X(GUID_EnableTimeSig), - X(GUID_IgnoreBankSelectForGM), - X(GUID_SeedVariations), - X(GUID_StandardMIDIFile), - X(GUID_Unload), - X(GUID_UnloadFromAudioPath), - X(GUID_Variations), - X(GUID_PerfMasterTempo), - X(GUID_PerfMasterVolume), - X(GUID_PerfMasterGrooveLevel), - X(GUID_PerfAutoDownload), - X(GUID_DefaultGMCollection), - X(GUID_Synth_Default), - X(GUID_Buffer_Reverb), - X(GUID_Buffer_EnvReverb), - X(GUID_Buffer_Stereo), - X(GUID_Buffer_3D_Dry), - X(GUID_Buffer_Mono), - X(GUID_DMUS_PROP_GM_Hardware), - X(GUID_DMUS_PROP_GS_Capable), - X(GUID_DMUS_PROP_GS_Hardware), - X(GUID_DMUS_PROP_DLS1), - X(GUID_DMUS_PROP_DLS2), - X(GUID_DMUS_PROP_Effects), - X(GUID_DMUS_PROP_INSTRUMENT2), - X(GUID_DMUS_PROP_LegacyCaps), - X(GUID_DMUS_PROP_MemorySize), - X(GUID_DMUS_PROP_SampleMemorySize), - X(GUID_DMUS_PROP_SamplePlaybackRate), - X(GUID_DMUS_PROP_SetSynthSink), - X(GUID_DMUS_PROP_SinkUsesDSound), - X(GUID_DMUS_PROP_SynthSink_DSOUND), - X(GUID_DMUS_PROP_SynthSink_WAVE), - X(GUID_DMUS_PROP_Volume), - X(GUID_DMUS_PROP_WavesReverb), - X(GUID_DMUS_PROP_WriteLatency), - X(GUID_DMUS_PROP_WritePeriod), - X(GUID_DMUS_PROP_XG_Capable), - X(GUID_DMUS_PROP_XG_Hardware) - }; -#undef X - - if (!id) - return "(null)"; - - for (i = 0; i < ARRAY_SIZE(guids); i++) - if (IsEqualGUID(id, guids[i].guid)) - return guids[i].name; - - return debugstr_guid(id); -} - -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc) -{ - if (!desc || !TRACE_ON(dmfile)) - return; - - TRACE_(dmfile)("DMUS_OBJECTDESC (%p):", desc); - TRACE_(dmfile)(" - dwSize = %lu\n", desc->dwSize); - -#define X(flag) if (desc->dwValidData & flag) TRACE_(dmfile)(#flag " ") - TRACE_(dmfile)(" - dwValidData = %#08lx ( ", desc->dwValidData); - X(DMUS_OBJ_OBJECT); - X(DMUS_OBJ_CLASS); - X(DMUS_OBJ_NAME); - X(DMUS_OBJ_CATEGORY); - X(DMUS_OBJ_FILENAME); - X(DMUS_OBJ_FULLPATH); - X(DMUS_OBJ_URL); - X(DMUS_OBJ_VERSION); - X(DMUS_OBJ_DATE); - X(DMUS_OBJ_LOADED); - X(DMUS_OBJ_MEMORY); - X(DMUS_OBJ_STREAM); - TRACE_(dmfile)(")\n"); -#undef X - - if (desc->dwValidData & DMUS_OBJ_CLASS) - TRACE_(dmfile)(" - guidClass = %s\n", debugstr_dmguid(&desc->guidClass)); - if (desc->dwValidData & DMUS_OBJ_OBJECT) - TRACE_(dmfile)(" - guidObject = %s\n", debugstr_guid(&desc->guidObject)); - - if (desc->dwValidData & DMUS_OBJ_DATE) { - SYSTEMTIME time; - FileTimeToSystemTime(&desc->ftDate, &time); - TRACE_(dmfile)(" - ftDate = \'%04u-%02u-%02u %02u:%02u:%02u\'\n", - time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond); - } - if (desc->dwValidData & DMUS_OBJ_VERSION) - TRACE_(dmfile)(" - vVersion = \'%u,%u,%u,%u\'\n", - HIWORD(desc->vVersion.dwVersionMS), LOWORD(desc->vVersion.dwVersionMS), - HIWORD(desc->vVersion.dwVersionLS), LOWORD(desc->vVersion.dwVersionLS)); - if (desc->dwValidData & DMUS_OBJ_NAME) - TRACE_(dmfile)(" - wszName = %s\n", debugstr_w(desc->wszName)); - if (desc->dwValidData & DMUS_OBJ_CATEGORY) - TRACE_(dmfile)(" - wszCategory = %s\n", debugstr_w(desc->wszCategory)); - if (desc->dwValidData & DMUS_OBJ_FILENAME) - TRACE_(dmfile)(" - wszFileName = %s\n", debugstr_w(desc->wszFileName)); - if (desc->dwValidData & DMUS_OBJ_MEMORY) - TRACE_(dmfile)(" - llMemLength = 0x%s - pbMemData = %p\n", - wine_dbgstr_longlong(desc->llMemLength), desc->pbMemData); - if (desc->dwValidData & DMUS_OBJ_STREAM) - TRACE_(dmfile)(" - pStream = %p\n", desc->pStream); -} - - -/* RIFF format parsing */ -#define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD)) - -const char *debugstr_chunk(const struct chunk_entry *chunk) -{ - const char *type = ""; - - if (!chunk) - return "(null)"; - if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST) - type = wine_dbg_sprintf("type %s, ", debugstr_fourcc(chunk->type)); - return wine_dbg_sprintf("%s chunk, %ssize %lu", debugstr_fourcc(chunk->id), type, chunk->size); -} - -static HRESULT stream_read(IStream *stream, void *data, ULONG size) -{ - ULONG read; - HRESULT hr; - - hr = IStream_Read(stream, data, size, &read); - if (FAILED(hr)) - TRACE_(dmfile)("IStream_Read failed: %#lx\n", hr); - else if (!read && read < size) { - /* All or nothing: Handle a partial read due to end of stream as an error */ - TRACE_(dmfile)("Short read: %lu < %lu\n", read, size); - return E_FAIL; - } - - return hr; -} - -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) -{ - static const LARGE_INTEGER zero; - ULONGLONG ck_end = 0, p_end = 0; - HRESULT hr; - - hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &chunk->offset); - if (FAILED(hr)) - return hr; - assert(!(chunk->offset.QuadPart & 1)); - if (chunk->parent) { - p_end = chunk->parent->offset.QuadPart + CHUNK_HDR_SIZE + ((chunk->parent->size + 1) & ~1); - if (chunk->offset.QuadPart == p_end) - return S_FALSE; - ck_end = chunk->offset.QuadPart + CHUNK_HDR_SIZE; - if (ck_end > p_end) { - WARN_(dmfile)("No space for sub-chunk header in parent chunk: ends at offset %s > %s\n", - wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end)); - return E_FAIL; - } - } - - hr = stream_read(stream, chunk, CHUNK_HDR_SIZE); - if (hr != S_OK) - return hr; - if (chunk->parent) { - ck_end += (chunk->size + 1) & ~1; - if (ck_end > p_end) { - WARN_(dmfile)("No space for sub-chunk data in parent chunk: ends at offset %s > %s\n", - wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end)); - return E_FAIL; - } - } - - if (chunk->id == FOURCC_LIST || chunk->id == FOURCC_RIFF) { - hr = stream_read(stream, &chunk->type, sizeof(FOURCC)); - if (hr != S_OK) - return hr != S_FALSE ? hr : E_FAIL; - } - - TRACE_(dmfile)("Returning %s\n", debugstr_chunk(chunk)); - - return S_OK; -} - -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER end; - - end.QuadPart = (chunk->offset.QuadPart + CHUNK_HDR_SIZE + chunk->size + 1) & ~(ULONGLONG)1; - - return IStream_Seek(stream, end, STREAM_SEEK_SET, NULL); -} - -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) -{ - HRESULT hr; - - if (chunk->id) { - hr = stream_skip_chunk(stream, chunk); - if (FAILED(hr)) - return hr; - } - - return stream_get_chunk(stream, chunk); -} - -/* Reads chunk data of the form: - DWORD - size of array element - element[] - Array of elements - The caller needs to free() the array. -*/ -HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size) -{ - DWORD size; - HRESULT hr; - - *array = NULL; - *count = 0; - - if (chunk->size < sizeof(DWORD)) { - WARN_(dmfile)("%s: Too short to read element size\n", debugstr_chunk(chunk)); - return E_FAIL; - } - if (FAILED(hr = stream_read(stream, &size, sizeof(DWORD)))) - return hr; - if (size != elem_size) { - WARN_(dmfile)("%s: Array element size mismatch: got %lu, expected %lu\n", - debugstr_chunk(chunk), size, elem_size); - return DMUS_E_UNSUPPORTED_STREAM; - } - - *count = (chunk->size - sizeof(DWORD)) / elem_size; - size = *count * elem_size; - if (!(*array = malloc(size))) - return E_OUTOFMEMORY; - if (FAILED(hr = stream_read(stream, *array, size))) { - free(*array); - *array = NULL; - return hr; - } - - if (chunk->size > size + sizeof(DWORD)) { - WARN_(dmfile)("%s: Extraneous data at end of array\n", debugstr_chunk(chunk)); - stream_skip_chunk(stream, chunk); - return S_FALSE; - } - return S_OK; -} - -HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size) -{ - if (chunk->size != size) { - WARN_(dmfile)("Chunk %s (size %lu, offset %s) doesn't contains the expected data size %lu\n", - debugstr_fourcc(chunk->id), chunk->size, - wine_dbgstr_longlong(chunk->offset.QuadPart), size); - return E_FAIL; - } - return stream_read(stream, data, size); -} - -HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size) -{ - ULONG len; - HRESULT hr; - - hr = IStream_Read(stream, str, min(chunk->size, size), &len); - if (FAILED(hr)) - return hr; - - /* Don't assume the string is properly zero terminated */ - str[min(len, size - 1)] = 0; - - if (len < chunk->size) - return S_FALSE; - return S_OK; -} - - - -/* Generic IDirectMusicObject methods */ -static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface) -{ - return CONTAINING_RECORD(iface, struct dmobject, IDirectMusicObject_iface); -} - -HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); -} - -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_AddRef(This->outer_unk); -} - -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_Release(This->outer_unk); -} - -HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - - TRACE("(%p/%p)->(%p)\n", iface, This, desc); - - if (!desc) - return E_POINTER; - - memcpy(desc, &This->desc, This->desc.dwSize); - - return S_OK; -} - -HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - HRESULT ret = S_OK; - - TRACE("(%p, %p)\n", iface, desc); - - if (!desc) - return E_POINTER; - - /* Immutable property */ - if (desc->dwValidData & DMUS_OBJ_CLASS) - { - desc->dwValidData &= ~DMUS_OBJ_CLASS; - ret = S_FALSE; - } - /* Set only valid fields */ - if (desc->dwValidData & DMUS_OBJ_OBJECT) - This->desc.guidObject = desc->guidObject; - if (desc->dwValidData & DMUS_OBJ_NAME) - lstrcpynW(This->desc.wszName, desc->wszName, DMUS_MAX_NAME); - if (desc->dwValidData & DMUS_OBJ_CATEGORY) - lstrcpynW(This->desc.wszCategory, desc->wszCategory, DMUS_MAX_CATEGORY); - if (desc->dwValidData & DMUS_OBJ_FILENAME) - lstrcpynW(This->desc.wszFileName, desc->wszFileName, DMUS_MAX_FILENAME); - if (desc->dwValidData & DMUS_OBJ_VERSION) - This->desc.vVersion = desc->vVersion; - if (desc->dwValidData & DMUS_OBJ_DATE) - This->desc.ftDate = desc->ftDate; - if (desc->dwValidData & DMUS_OBJ_MEMORY) { - This->desc.llMemLength = desc->llMemLength; - memcpy(This->desc.pbMemData, desc->pbMemData, desc->llMemLength); - } - if (desc->dwValidData & DMUS_OBJ_STREAM) - IStream_Clone(desc->pStream, &This->desc.pStream); - - This->desc.dwValidData |= desc->dwValidData; - - return ret; -} - -/* Helper for IDirectMusicObject::ParseDescriptor */ -static inline void info_get_name(IStream *stream, const struct chunk_entry *info, - DMUS_OBJECTDESC *desc) -{ - struct chunk_entry chunk = {.parent = info}; - char name[DMUS_MAX_NAME]; - ULONG len; - HRESULT hr = E_FAIL; - - while (stream_next_chunk(stream, &chunk) == S_OK) - if (chunk.id == mmioFOURCC('I','N','A','M')) - hr = IStream_Read(stream, name, min(chunk.size, sizeof(name)), &len); - - if (SUCCEEDED(hr)) { - len = MultiByteToWideChar(CP_ACP, 0, name, len, desc->wszName, sizeof(desc->wszName)); - desc->wszName[min(len, sizeof(desc->wszName) - 1)] = 0; - desc->dwValidData |= DMUS_OBJ_NAME; - } -} - -static inline void unfo_get_name(IStream *stream, const struct chunk_entry *unfo, - DMUS_OBJECTDESC *desc, BOOL inam) -{ - struct chunk_entry chunk = {.parent = unfo}; - - while (stream_next_chunk(stream, &chunk) == S_OK) - if (chunk.id == DMUS_FOURCC_UNAM_CHUNK || (inam && chunk.id == mmioFOURCC('I','N','A','M'))) - if (stream_chunk_get_wstr(stream, &chunk, desc->wszName, sizeof(desc->wszName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_NAME; -} - -HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported) -{ - struct chunk_entry chunk = {.parent = riff}; - HRESULT hr; - - TRACE("Looking for %#lx in %p: %s\n", supported, stream, debugstr_chunk(riff)); - - desc->dwValidData = 0; - desc->dwSize = sizeof(*desc); - - while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { - switch (chunk.id) { - case DMUS_FOURCC_CATEGORY_CHUNK: - if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk, - desc->wszCategory, sizeof(desc->wszCategory)) == S_OK) - desc->dwValidData |= DMUS_OBJ_CATEGORY; - break; - case DMUS_FOURCC_DATE_CHUNK: - if ((supported & DMUS_OBJ_DATE) && stream_chunk_get_data(stream, &chunk, - &desc->ftDate, sizeof(desc->ftDate)) == S_OK) - desc->dwValidData |= DMUS_OBJ_DATE; - break; - case DMUS_FOURCC_FILE_CHUNK: - if ((supported & DMUS_OBJ_FILENAME) && stream_chunk_get_wstr(stream, &chunk, - desc->wszFileName, sizeof(desc->wszFileName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_FILENAME; - break; - case DMUS_FOURCC_GUID_CHUNK: - if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk, - &desc->guidObject, sizeof(desc->guidObject)) == S_OK) - desc->dwValidData |= DMUS_OBJ_OBJECT; - break; - case DMUS_FOURCC_NAME_CHUNK: - if ((supported & DMUS_OBJ_NAME) && stream_chunk_get_wstr(stream, &chunk, - desc->wszName, sizeof(desc->wszName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_NAME; - break; - case DMUS_FOURCC_VERSION_CHUNK: - if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk, - &desc->vVersion, sizeof(desc->vVersion)) == S_OK) - desc->dwValidData |= DMUS_OBJ_VERSION; - break; - case FOURCC_LIST: - if (chunk.type == DMUS_FOURCC_UNFO_LIST && (supported & DMUS_OBJ_NAME)) - unfo_get_name(stream, &chunk, desc, supported & DMUS_OBJ_NAME_INAM); - else if (chunk.type == DMUS_FOURCC_INFO_LIST && (supported & DMUS_OBJ_NAME_INFO)) - info_get_name(stream, &chunk, desc); - break; - } - } - TRACE("Found %#lx\n", desc->dwValidData); - - return hr; -} - -HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj) -{ - struct chunk_entry chunk = {.parent = list}; - IDirectMusicGetLoader *getloader; - IDirectMusicLoader *loader; - DMUS_OBJECTDESC desc; - DMUS_IO_REFERENCE reference; - HRESULT hr; - - if (FAILED(hr = stream_next_chunk(stream, &chunk))) - return hr; - if (chunk.id != DMUS_FOURCC_REF_CHUNK) - return DMUS_E_UNSUPPORTED_STREAM; - - if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &reference, sizeof(reference)))) { - WARN("Failed to read data of %s\n", debugstr_chunk(&chunk)); - return hr; - } - TRACE("REFERENCE guidClassID %s, dwValidData %#lx\n", debugstr_dmguid(&reference.guidClassID), - reference.dwValidData); - - if (FAILED(hr = dmobj_parsedescriptor(stream, list, &desc, reference.dwValidData))) - return hr; - desc.guidClass = reference.guidClassID; - desc.dwValidData |= DMUS_OBJ_CLASS; - dump_DMUS_OBJECTDESC(&desc); - - if (FAILED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getloader))) - return hr; - hr = IDirectMusicGetLoader_GetLoader(getloader, &loader); - IDirectMusicGetLoader_Release(getloader); - if (FAILED(hr)) - return hr; - - hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicObject, (void**)dmobj); - IDirectMusicLoader_Release(loader); - - return hr; -} - -/* Generic IPersistStream methods */ -static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface) -{ - return CONTAINING_RECORD(iface, struct dmobject, IPersistStream_iface); -} - -HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); -} - -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_AddRef(This->outer_unk); -} - -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_Release(This->outer_unk); -} - -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - - TRACE("(%p, %p)\n", This, class); - - if (!class) - return E_POINTER; - - *class = This->desc.guidClass; - - return S_OK; -} - -/* IPersistStream methods not implemented in native */ -HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) -{ - TRACE("(%p, %p): method not implemented\n", iface, class); - return E_NOTIMPL; -} - -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface) -{ - TRACE("(%p): method not implemented, always returning S_FALSE\n", iface); - return S_FALSE; -} - -HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty) -{ - TRACE("(%p, %p, %d): method not implemented\n", iface, stream, clear_dirty); - return E_NOTIMPL; -} - -HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, ULARGE_INTEGER *size) -{ - TRACE("(%p, %p): method not implemented\n", iface, size); - return E_NOTIMPL; -} - - -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk) -{ - dmobj->outer_unk = outer_unk; - dmobj->desc.dwSize = sizeof(dmobj->desc); - dmobj->desc.dwValidData = DMUS_OBJ_CLASS; - dmobj->desc.guidClass = *class; -} diff --git a/dlls/dmscript/dmobject.h b/dlls/dmscript/dmobject.h deleted file mode 100644 index 772be015c80..00000000000 --- a/dlls/dmscript/dmobject.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Base IDirectMusicObject Implementation - * Keep in sync with the master in dlls/dmusic/dmobject.h - * - * Copyright (C) 2014 Michael Stefaniuc - * - * This program 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 program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "wine/debug.h" - -/* RIFF stream parsing */ -struct chunk_entry; -struct chunk_entry { - FOURCC id; - DWORD size; - FOURCC type; /* valid only for LIST and RIFF chunks */ - ULARGE_INTEGER offset; /* chunk offset from start of stream */ - const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */ -}; - -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk); -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk); -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk); - -HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size); -HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size); -HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size); - -static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER offset; - - offset.QuadPart = chunk->offset.QuadPart + sizeof(FOURCC) + sizeof(DWORD); - if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST) - offset.QuadPart += sizeof(FOURCC); - - return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); -} - -static inline HRESULT stream_reset_chunk_start(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER offset; - - offset.QuadPart = chunk->offset.QuadPart; - - return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); -} - - -/* IDirectMusicObject base object */ -struct dmobject { - IDirectMusicObject IDirectMusicObject_iface; - IPersistStream IPersistStream_iface; - IUnknown *outer_unk; - DMUS_OBJECTDESC desc; -}; - -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk); - -/* Generic IDirectMusicObject methods */ -HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface); -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface); -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface); -HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc); -HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc); - -/* Helper for IDirectMusicObject::ParseDescriptor */ -HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported); -/* Additional supported flags for dmobj_parsedescriptor. - DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */ -#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */ -#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */ - -/* 'DMRF' (reference list) helper */ -HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj); - -/* Generic IPersistStream methods */ -HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface); -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface); -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface); -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class); - -/* IPersistStream methods not implemented in native */ -HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, - CLSID *class); -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface); -HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty); -HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, - ULARGE_INTEGER *size); - -/* Debugging helpers */ -const char *debugstr_chunk(const struct chunk_entry *chunk); -const char *debugstr_dmguid(const GUID *id); -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc); - -static inline const char *debugstr_fourcc(DWORD fourcc) -{ - if (!fourcc) return "''"; - return wine_dbg_sprintf("'%c%c%c%c'", (char)(fourcc), (char)(fourcc >> 8), - (char)(fourcc >> 16), (char)(fourcc >> 24)); -} From 60db04402c784743dbb34b4496171040d228307e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 30 Aug 2023 19:56:28 +0200 Subject: [PATCH 2508/2777] dmime: Use PARENTSRC with dmusic. (cherry picked from commit aeea45946abee7bb673c12c24bd6b590dcb98c72) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/Makefile.in | 1 + dlls/dmime/dmobject.c | 731 ----------------------------------------- dlls/dmime/dmobject.h | 124 ------- 3 files changed, 1 insertion(+), 855 deletions(-) delete mode 100644 dlls/dmime/dmobject.c delete mode 100644 dlls/dmime/dmobject.h diff --git a/dlls/dmime/Makefile.in b/dlls/dmime/Makefile.in index 51d1492585f..ef4d0b9bee4 100644 --- a/dlls/dmime/Makefile.in +++ b/dlls/dmime/Makefile.in @@ -1,5 +1,6 @@ MODULE = dmime.dll IMPORTS = dxguid uuid dsound ole32 user32 advapi32 +PARENTSRC = ../dmusic C_SRCS = \ audiopath.c \ diff --git a/dlls/dmime/dmobject.c b/dlls/dmime/dmobject.c deleted file mode 100644 index e080211dd11..00000000000 --- a/dlls/dmime/dmobject.c +++ /dev/null @@ -1,731 +0,0 @@ -/* - * Base IDirectMusicObject Implementation - * Keep in sync with the master in dlls/dmusic/dmobject.c - * - * Copyright (C) 2003-2004 Rok Mandeljc - * Copyright (C) 2014 Michael Stefaniuc - * - * This program 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 program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define COBJMACROS -#include -#include "objbase.h" -#include "dmusici.h" -#include "dmusicf.h" -#include "dmusics.h" -#include "dmobject.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dmobj); -WINE_DECLARE_DEBUG_CHANNEL(dmfile); - -/* Debugging helpers */ -const char *debugstr_dmguid(const GUID *id) { - unsigned int i; -#define X(guid) { &guid, #guid } - static const struct { - const GUID *guid; - const char *name; - } guids[] = { - /* CLSIDs */ - X(CLSID_AudioVBScript), - X(CLSID_DirectMusic), - X(CLSID_DirectMusicAudioPathConfig), - X(CLSID_DirectMusicAuditionTrack), - X(CLSID_DirectMusicBand), - X(CLSID_DirectMusicBandTrack), - X(CLSID_DirectMusicChordMapTrack), - X(CLSID_DirectMusicChordMap), - X(CLSID_DirectMusicChordTrack), - X(CLSID_DirectMusicCollection), - X(CLSID_DirectMusicCommandTrack), - X(CLSID_DirectMusicComposer), - X(CLSID_DirectMusicContainer), - X(CLSID_DirectMusicGraph), - X(CLSID_DirectMusicLoader), - X(CLSID_DirectMusicLyricsTrack), - X(CLSID_DirectMusicMarkerTrack), - X(CLSID_DirectMusicMelodyFormulationTrack), - X(CLSID_DirectMusicMotifTrack), - X(CLSID_DirectMusicMuteTrack), - X(CLSID_DirectMusicParamControlTrack), - X(CLSID_DirectMusicPatternTrack), - X(CLSID_DirectMusicPerformance), - X(CLSID_DirectMusicScript), - X(CLSID_DirectMusicScriptAutoImpSegment), - X(CLSID_DirectMusicScriptAutoImpPerformance), - X(CLSID_DirectMusicScriptAutoImpSegmentState), - X(CLSID_DirectMusicScriptAutoImpAudioPathConfig), - X(CLSID_DirectMusicScriptAutoImpAudioPath), - X(CLSID_DirectMusicScriptAutoImpSong), - X(CLSID_DirectMusicScriptSourceCodeLoader), - X(CLSID_DirectMusicScriptTrack), - X(CLSID_DirectMusicSection), - X(CLSID_DirectMusicSegment), - X(CLSID_DirectMusicSegmentState), - X(CLSID_DirectMusicSegmentTriggerTrack), - X(CLSID_DirectMusicSegTriggerTrack), - X(CLSID_DirectMusicSeqTrack), - X(CLSID_DirectMusicSignPostTrack), - X(CLSID_DirectMusicSong), - X(CLSID_DirectMusicStyle), - X(CLSID_DirectMusicStyleTrack), - X(CLSID_DirectMusicSynth), - X(CLSID_DirectMusicSynthSink), - X(CLSID_DirectMusicSysExTrack), - X(CLSID_DirectMusicTemplate), - X(CLSID_DirectMusicTempoTrack), - X(CLSID_DirectMusicTimeSigTrack), - X(CLSID_DirectMusicWaveTrack), - X(CLSID_DirectSoundWave), - /* IIDs */ - X(IID_IDirectMusic), - X(IID_IDirectMusic2), - X(IID_IDirectMusic8), - X(IID_IDirectMusicAudioPath), - X(IID_IDirectMusicBand), - X(IID_IDirectMusicBuffer), - X(IID_IDirectMusicChordMap), - X(IID_IDirectMusicCollection), - X(IID_IDirectMusicComposer), - X(IID_IDirectMusicContainer), - X(IID_IDirectMusicDownload), - X(IID_IDirectMusicDownloadedInstrument), - X(IID_IDirectMusicGetLoader), - X(IID_IDirectMusicGraph), - X(IID_IDirectMusicInstrument), - X(IID_IDirectMusicLoader), - X(IID_IDirectMusicLoader8), - X(IID_IDirectMusicObject), - X(IID_IDirectMusicPatternTrack), - X(IID_IDirectMusicPerformance), - X(IID_IDirectMusicPerformance2), - X(IID_IDirectMusicPerformance8), - X(IID_IDirectMusicPort), - X(IID_IDirectMusicPortDownload), - X(IID_IDirectMusicScript), - X(IID_IDirectMusicSegment), - X(IID_IDirectMusicSegment2), - X(IID_IDirectMusicSegment8), - X(IID_IDirectMusicSegmentState), - X(IID_IDirectMusicSegmentState8), - X(IID_IDirectMusicStyle), - X(IID_IDirectMusicStyle8), - X(IID_IDirectMusicSynth), - X(IID_IDirectMusicSynth8), - X(IID_IDirectMusicSynthSink), - X(IID_IDirectMusicThru), - X(IID_IDirectMusicTool), - X(IID_IDirectMusicTool8), - X(IID_IDirectMusicTrack), - X(IID_IDirectMusicTrack8), - X(IID_IUnknown), - X(IID_IPersistStream), - X(IID_IStream), - X(IID_IClassFactory), - /* GUIDs */ - X(GUID_DirectMusicAllTypes), - X(GUID_NOTIFICATION_CHORD), - X(GUID_NOTIFICATION_COMMAND), - X(GUID_NOTIFICATION_MEASUREANDBEAT), - X(GUID_NOTIFICATION_PERFORMANCE), - X(GUID_NOTIFICATION_RECOMPOSE), - X(GUID_NOTIFICATION_SEGMENT), - X(GUID_BandParam), - X(GUID_ChordParam), - X(GUID_CommandParam), - X(GUID_CommandParam2), - X(GUID_CommandParamNext), - X(GUID_IDirectMusicBand), - X(GUID_IDirectMusicChordMap), - X(GUID_IDirectMusicStyle), - X(GUID_MuteParam), - X(GUID_Play_Marker), - X(GUID_RhythmParam), - X(GUID_TempoParam), - X(GUID_TimeSignature), - X(GUID_Valid_Start_Time), - X(GUID_Clear_All_Bands), - X(GUID_ConnectToDLSCollection), - X(GUID_Disable_Auto_Download), - X(GUID_DisableTempo), - X(GUID_DisableTimeSig), - X(GUID_Download), - X(GUID_DownloadToAudioPath), - X(GUID_Enable_Auto_Download), - X(GUID_EnableTempo), - X(GUID_EnableTimeSig), - X(GUID_IgnoreBankSelectForGM), - X(GUID_SeedVariations), - X(GUID_StandardMIDIFile), - X(GUID_Unload), - X(GUID_UnloadFromAudioPath), - X(GUID_Variations), - X(GUID_PerfMasterTempo), - X(GUID_PerfMasterVolume), - X(GUID_PerfMasterGrooveLevel), - X(GUID_PerfAutoDownload), - X(GUID_DefaultGMCollection), - X(GUID_Synth_Default), - X(GUID_Buffer_Reverb), - X(GUID_Buffer_EnvReverb), - X(GUID_Buffer_Stereo), - X(GUID_Buffer_3D_Dry), - X(GUID_Buffer_Mono), - X(GUID_DMUS_PROP_GM_Hardware), - X(GUID_DMUS_PROP_GS_Capable), - X(GUID_DMUS_PROP_GS_Hardware), - X(GUID_DMUS_PROP_DLS1), - X(GUID_DMUS_PROP_DLS2), - X(GUID_DMUS_PROP_Effects), - X(GUID_DMUS_PROP_INSTRUMENT2), - X(GUID_DMUS_PROP_LegacyCaps), - X(GUID_DMUS_PROP_MemorySize), - X(GUID_DMUS_PROP_SampleMemorySize), - X(GUID_DMUS_PROP_SamplePlaybackRate), - X(GUID_DMUS_PROP_SetSynthSink), - X(GUID_DMUS_PROP_SinkUsesDSound), - X(GUID_DMUS_PROP_SynthSink_DSOUND), - X(GUID_DMUS_PROP_SynthSink_WAVE), - X(GUID_DMUS_PROP_Volume), - X(GUID_DMUS_PROP_WavesReverb), - X(GUID_DMUS_PROP_WriteLatency), - X(GUID_DMUS_PROP_WritePeriod), - X(GUID_DMUS_PROP_XG_Capable), - X(GUID_DMUS_PROP_XG_Hardware) - }; -#undef X - - if (!id) - return "(null)"; - - for (i = 0; i < ARRAY_SIZE(guids); i++) - if (IsEqualGUID(id, guids[i].guid)) - return guids[i].name; - - return debugstr_guid(id); -} - -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc) -{ - if (!desc || !TRACE_ON(dmfile)) - return; - - TRACE_(dmfile)("DMUS_OBJECTDESC (%p):", desc); - TRACE_(dmfile)(" - dwSize = %lu\n", desc->dwSize); - -#define X(flag) if (desc->dwValidData & flag) TRACE_(dmfile)(#flag " ") - TRACE_(dmfile)(" - dwValidData = %#08lx ( ", desc->dwValidData); - X(DMUS_OBJ_OBJECT); - X(DMUS_OBJ_CLASS); - X(DMUS_OBJ_NAME); - X(DMUS_OBJ_CATEGORY); - X(DMUS_OBJ_FILENAME); - X(DMUS_OBJ_FULLPATH); - X(DMUS_OBJ_URL); - X(DMUS_OBJ_VERSION); - X(DMUS_OBJ_DATE); - X(DMUS_OBJ_LOADED); - X(DMUS_OBJ_MEMORY); - X(DMUS_OBJ_STREAM); - TRACE_(dmfile)(")\n"); -#undef X - - if (desc->dwValidData & DMUS_OBJ_CLASS) - TRACE_(dmfile)(" - guidClass = %s\n", debugstr_dmguid(&desc->guidClass)); - if (desc->dwValidData & DMUS_OBJ_OBJECT) - TRACE_(dmfile)(" - guidObject = %s\n", debugstr_guid(&desc->guidObject)); - - if (desc->dwValidData & DMUS_OBJ_DATE) { - SYSTEMTIME time; - FileTimeToSystemTime(&desc->ftDate, &time); - TRACE_(dmfile)(" - ftDate = \'%04u-%02u-%02u %02u:%02u:%02u\'\n", - time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond); - } - if (desc->dwValidData & DMUS_OBJ_VERSION) - TRACE_(dmfile)(" - vVersion = \'%u,%u,%u,%u\'\n", - HIWORD(desc->vVersion.dwVersionMS), LOWORD(desc->vVersion.dwVersionMS), - HIWORD(desc->vVersion.dwVersionLS), LOWORD(desc->vVersion.dwVersionLS)); - if (desc->dwValidData & DMUS_OBJ_NAME) - TRACE_(dmfile)(" - wszName = %s\n", debugstr_w(desc->wszName)); - if (desc->dwValidData & DMUS_OBJ_CATEGORY) - TRACE_(dmfile)(" - wszCategory = %s\n", debugstr_w(desc->wszCategory)); - if (desc->dwValidData & DMUS_OBJ_FILENAME) - TRACE_(dmfile)(" - wszFileName = %s\n", debugstr_w(desc->wszFileName)); - if (desc->dwValidData & DMUS_OBJ_MEMORY) - TRACE_(dmfile)(" - llMemLength = 0x%s - pbMemData = %p\n", - wine_dbgstr_longlong(desc->llMemLength), desc->pbMemData); - if (desc->dwValidData & DMUS_OBJ_STREAM) - TRACE_(dmfile)(" - pStream = %p\n", desc->pStream); -} - - -/* RIFF format parsing */ -#define CHUNK_HDR_SIZE (sizeof(FOURCC) + sizeof(DWORD)) - -const char *debugstr_chunk(const struct chunk_entry *chunk) -{ - const char *type = ""; - - if (!chunk) - return "(null)"; - if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST) - type = wine_dbg_sprintf("type %s, ", debugstr_fourcc(chunk->type)); - return wine_dbg_sprintf("%s chunk, %ssize %lu", debugstr_fourcc(chunk->id), type, chunk->size); -} - -static HRESULT stream_read(IStream *stream, void *data, ULONG size) -{ - ULONG read; - HRESULT hr; - - hr = IStream_Read(stream, data, size, &read); - if (FAILED(hr)) - TRACE_(dmfile)("IStream_Read failed: %#lx\n", hr); - else if (!read && read < size) { - /* All or nothing: Handle a partial read due to end of stream as an error */ - TRACE_(dmfile)("Short read: %lu < %lu\n", read, size); - return E_FAIL; - } - - return hr; -} - -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk) -{ - static const LARGE_INTEGER zero; - ULONGLONG ck_end = 0, p_end = 0; - HRESULT hr; - - hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &chunk->offset); - if (FAILED(hr)) - return hr; - assert(!(chunk->offset.QuadPart & 1)); - if (chunk->parent) { - p_end = chunk->parent->offset.QuadPart + CHUNK_HDR_SIZE + ((chunk->parent->size + 1) & ~1); - if (chunk->offset.QuadPart == p_end) - return S_FALSE; - ck_end = chunk->offset.QuadPart + CHUNK_HDR_SIZE; - if (ck_end > p_end) { - WARN_(dmfile)("No space for sub-chunk header in parent chunk: ends at offset %s > %s\n", - wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end)); - return E_FAIL; - } - } - - hr = stream_read(stream, chunk, CHUNK_HDR_SIZE); - if (hr != S_OK) - return hr; - if (chunk->parent) { - ck_end += (chunk->size + 1) & ~1; - if (ck_end > p_end) { - WARN_(dmfile)("No space for sub-chunk data in parent chunk: ends at offset %s > %s\n", - wine_dbgstr_longlong(ck_end), wine_dbgstr_longlong(p_end)); - return E_FAIL; - } - } - - if (chunk->id == FOURCC_LIST || chunk->id == FOURCC_RIFF) { - hr = stream_read(stream, &chunk->type, sizeof(FOURCC)); - if (hr != S_OK) - return hr != S_FALSE ? hr : E_FAIL; - } - - TRACE_(dmfile)("Returning %s\n", debugstr_chunk(chunk)); - - return S_OK; -} - -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER end; - - end.QuadPart = (chunk->offset.QuadPart + CHUNK_HDR_SIZE + chunk->size + 1) & ~(ULONGLONG)1; - - return IStream_Seek(stream, end, STREAM_SEEK_SET, NULL); -} - -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk) -{ - HRESULT hr; - - if (chunk->id) { - hr = stream_skip_chunk(stream, chunk); - if (FAILED(hr)) - return hr; - } - - return stream_get_chunk(stream, chunk); -} - -/* Reads chunk data of the form: - DWORD - size of array element - element[] - Array of elements - The caller needs to free() the array. -*/ -HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size) -{ - DWORD size; - HRESULT hr; - - *array = NULL; - *count = 0; - - if (chunk->size < sizeof(DWORD)) { - WARN_(dmfile)("%s: Too short to read element size\n", debugstr_chunk(chunk)); - return E_FAIL; - } - if (FAILED(hr = stream_read(stream, &size, sizeof(DWORD)))) - return hr; - if (size != elem_size) { - WARN_(dmfile)("%s: Array element size mismatch: got %lu, expected %lu\n", - debugstr_chunk(chunk), size, elem_size); - return DMUS_E_UNSUPPORTED_STREAM; - } - - *count = (chunk->size - sizeof(DWORD)) / elem_size; - size = *count * elem_size; - if (!(*array = malloc(size))) return E_OUTOFMEMORY; - if (FAILED(hr = stream_read(stream, *array, size))) { - free(*array); - *array = NULL; - return hr; - } - - if (chunk->size > size + sizeof(DWORD)) { - WARN_(dmfile)("%s: Extraneous data at end of array\n", debugstr_chunk(chunk)); - stream_skip_chunk(stream, chunk); - return S_FALSE; - } - return S_OK; -} - -HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size) -{ - if (chunk->size != size) { - WARN_(dmfile)("Chunk %s (size %lu, offset %s) doesn't contains the expected data size %lu\n", - debugstr_fourcc(chunk->id), chunk->size, - wine_dbgstr_longlong(chunk->offset.QuadPart), size); - return E_FAIL; - } - return stream_read(stream, data, size); -} - -HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size) -{ - ULONG len; - HRESULT hr; - - hr = IStream_Read(stream, str, min(chunk->size, size), &len); - if (FAILED(hr)) - return hr; - - /* Don't assume the string is properly zero terminated */ - str[min(len, size - 1)] = 0; - - if (len < chunk->size) - return S_FALSE; - return S_OK; -} - - - -/* Generic IDirectMusicObject methods */ -static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface) -{ - return CONTAINING_RECORD(iface, struct dmobject, IDirectMusicObject_iface); -} - -HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); -} - -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_AddRef(This->outer_unk); -} - -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - return IUnknown_Release(This->outer_unk); -} - -HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - - TRACE("(%p/%p)->(%p)\n", iface, This, desc); - - if (!desc) - return E_POINTER; - - memcpy(desc, &This->desc, This->desc.dwSize); - - return S_OK; -} - -HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc) -{ - struct dmobject *This = impl_from_IDirectMusicObject(iface); - HRESULT ret = S_OK; - - TRACE("(%p, %p)\n", iface, desc); - - if (!desc) - return E_POINTER; - - /* Immutable property */ - if (desc->dwValidData & DMUS_OBJ_CLASS) - { - desc->dwValidData &= ~DMUS_OBJ_CLASS; - ret = S_FALSE; - } - /* Set only valid fields */ - if (desc->dwValidData & DMUS_OBJ_OBJECT) - This->desc.guidObject = desc->guidObject; - if (desc->dwValidData & DMUS_OBJ_NAME) - lstrcpynW(This->desc.wszName, desc->wszName, DMUS_MAX_NAME); - if (desc->dwValidData & DMUS_OBJ_CATEGORY) - lstrcpynW(This->desc.wszCategory, desc->wszCategory, DMUS_MAX_CATEGORY); - if (desc->dwValidData & DMUS_OBJ_FILENAME) - lstrcpynW(This->desc.wszFileName, desc->wszFileName, DMUS_MAX_FILENAME); - if (desc->dwValidData & DMUS_OBJ_VERSION) - This->desc.vVersion = desc->vVersion; - if (desc->dwValidData & DMUS_OBJ_DATE) - This->desc.ftDate = desc->ftDate; - if (desc->dwValidData & DMUS_OBJ_MEMORY) { - This->desc.llMemLength = desc->llMemLength; - memcpy(This->desc.pbMemData, desc->pbMemData, desc->llMemLength); - } - if (desc->dwValidData & DMUS_OBJ_STREAM) - IStream_Clone(desc->pStream, &This->desc.pStream); - - This->desc.dwValidData |= desc->dwValidData; - - return ret; -} - -/* Helper for IDirectMusicObject::ParseDescriptor */ -static inline void info_get_name(IStream *stream, const struct chunk_entry *info, - DMUS_OBJECTDESC *desc) -{ - struct chunk_entry chunk = {.parent = info}; - char name[DMUS_MAX_NAME]; - ULONG len; - HRESULT hr = E_FAIL; - - while (stream_next_chunk(stream, &chunk) == S_OK) - if (chunk.id == mmioFOURCC('I','N','A','M')) - hr = IStream_Read(stream, name, min(chunk.size, sizeof(name)), &len); - - if (SUCCEEDED(hr)) { - len = MultiByteToWideChar(CP_ACP, 0, name, len, desc->wszName, sizeof(desc->wszName)); - desc->wszName[min(len, sizeof(desc->wszName) - 1)] = 0; - desc->dwValidData |= DMUS_OBJ_NAME; - } -} - -static inline void unfo_get_name(IStream *stream, const struct chunk_entry *unfo, - DMUS_OBJECTDESC *desc, BOOL inam) -{ - struct chunk_entry chunk = {.parent = unfo}; - - while (stream_next_chunk(stream, &chunk) == S_OK) - if (chunk.id == DMUS_FOURCC_UNAM_CHUNK || (inam && chunk.id == mmioFOURCC('I','N','A','M'))) - if (stream_chunk_get_wstr(stream, &chunk, desc->wszName, sizeof(desc->wszName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_NAME; -} - -HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported) -{ - struct chunk_entry chunk = {.parent = riff}; - HRESULT hr; - - TRACE("Looking for %#lx in %p: %s\n", supported, stream, debugstr_chunk(riff)); - - desc->dwValidData = 0; - desc->dwSize = sizeof(*desc); - - while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { - switch (chunk.id) { - case DMUS_FOURCC_CATEGORY_CHUNK: - if ((supported & DMUS_OBJ_CATEGORY) && stream_chunk_get_wstr(stream, &chunk, - desc->wszCategory, sizeof(desc->wszCategory)) == S_OK) - desc->dwValidData |= DMUS_OBJ_CATEGORY; - break; - case DMUS_FOURCC_DATE_CHUNK: - if ((supported & DMUS_OBJ_DATE) && stream_chunk_get_data(stream, &chunk, - &desc->ftDate, sizeof(desc->ftDate)) == S_OK) - desc->dwValidData |= DMUS_OBJ_DATE; - break; - case DMUS_FOURCC_FILE_CHUNK: - if ((supported & DMUS_OBJ_FILENAME) && stream_chunk_get_wstr(stream, &chunk, - desc->wszFileName, sizeof(desc->wszFileName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_FILENAME; - break; - case DMUS_FOURCC_GUID_CHUNK: - if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk, - &desc->guidObject, sizeof(desc->guidObject)) == S_OK) - desc->dwValidData |= DMUS_OBJ_OBJECT; - break; - case DMUS_FOURCC_NAME_CHUNK: - if ((supported & DMUS_OBJ_NAME) && stream_chunk_get_wstr(stream, &chunk, - desc->wszName, sizeof(desc->wszName)) == S_OK) - desc->dwValidData |= DMUS_OBJ_NAME; - break; - case DMUS_FOURCC_VERSION_CHUNK: - if ((supported & DMUS_OBJ_VERSION) && stream_chunk_get_data(stream, &chunk, - &desc->vVersion, sizeof(desc->vVersion)) == S_OK) - desc->dwValidData |= DMUS_OBJ_VERSION; - break; - case FOURCC_LIST: - if (chunk.type == DMUS_FOURCC_UNFO_LIST && (supported & DMUS_OBJ_NAME)) - unfo_get_name(stream, &chunk, desc, supported & DMUS_OBJ_NAME_INAM); - else if (chunk.type == DMUS_FOURCC_INFO_LIST && (supported & DMUS_OBJ_NAME_INFO)) - info_get_name(stream, &chunk, desc); - break; - } - } - TRACE("Found %#lx\n", desc->dwValidData); - - return hr; -} - -HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj) -{ - struct chunk_entry chunk = {.parent = list}; - IDirectMusicGetLoader *getloader; - IDirectMusicLoader *loader; - DMUS_OBJECTDESC desc; - DMUS_IO_REFERENCE reference; - HRESULT hr; - - if (FAILED(hr = stream_next_chunk(stream, &chunk))) - return hr; - if (chunk.id != DMUS_FOURCC_REF_CHUNK) - return DMUS_E_UNSUPPORTED_STREAM; - - if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &reference, sizeof(reference)))) { - WARN("Failed to read data of %s\n", debugstr_chunk(&chunk)); - return hr; - } - TRACE("REFERENCE guidClassID %s, dwValidData %#lx\n", debugstr_dmguid(&reference.guidClassID), - reference.dwValidData); - - if (FAILED(hr = dmobj_parsedescriptor(stream, list, &desc, reference.dwValidData))) - return hr; - desc.guidClass = reference.guidClassID; - desc.dwValidData |= DMUS_OBJ_CLASS; - dump_DMUS_OBJECTDESC(&desc); - - if (FAILED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getloader))) - return hr; - hr = IDirectMusicGetLoader_GetLoader(getloader, &loader); - IDirectMusicGetLoader_Release(getloader); - if (FAILED(hr)) - return hr; - - hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicObject, (void**)dmobj); - IDirectMusicLoader_Release(loader); - - return hr; -} - -/* Generic IPersistStream methods */ -static inline struct dmobject *impl_from_IPersistStream(IPersistStream *iface) -{ - return CONTAINING_RECORD(iface, struct dmobject, IPersistStream_iface); -} - -HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_QueryInterface(This->outer_unk, riid, ret_iface); -} - -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_AddRef(This->outer_unk); -} - -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - return IUnknown_Release(This->outer_unk); -} - -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) -{ - struct dmobject *This = impl_from_IPersistStream(iface); - - TRACE("(%p, %p)\n", This, class); - - if (!class) - return E_POINTER; - - *class = This->desc.guidClass; - - return S_OK; -} - -/* IPersistStream methods not implemented in native */ -HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class) -{ - TRACE("(%p, %p): method not implemented\n", iface, class); - return E_NOTIMPL; -} - -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface) -{ - TRACE("(%p): method not implemented, always returning S_FALSE\n", iface); - return S_FALSE; -} - -HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty) -{ - TRACE("(%p, %p, %d): method not implemented\n", iface, stream, clear_dirty); - return E_NOTIMPL; -} - -HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, ULARGE_INTEGER *size) -{ - TRACE("(%p, %p): method not implemented\n", iface, size); - return E_NOTIMPL; -} - - -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk) -{ - dmobj->outer_unk = outer_unk; - dmobj->desc.dwSize = sizeof(dmobj->desc); - dmobj->desc.dwValidData = DMUS_OBJ_CLASS; - dmobj->desc.guidClass = *class; -} diff --git a/dlls/dmime/dmobject.h b/dlls/dmime/dmobject.h deleted file mode 100644 index 772be015c80..00000000000 --- a/dlls/dmime/dmobject.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Base IDirectMusicObject Implementation - * Keep in sync with the master in dlls/dmusic/dmobject.h - * - * Copyright (C) 2014 Michael Stefaniuc - * - * This program 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 program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "wine/debug.h" - -/* RIFF stream parsing */ -struct chunk_entry; -struct chunk_entry { - FOURCC id; - DWORD size; - FOURCC type; /* valid only for LIST and RIFF chunks */ - ULARGE_INTEGER offset; /* chunk offset from start of stream */ - const struct chunk_entry *parent; /* enclosing RIFF or LIST chunk */ -}; - -HRESULT stream_get_chunk(IStream *stream, struct chunk_entry *chunk); -HRESULT stream_next_chunk(IStream *stream, struct chunk_entry *chunk); -HRESULT stream_skip_chunk(IStream *stream, const struct chunk_entry *chunk); - -HRESULT stream_chunk_get_array(IStream *stream, const struct chunk_entry *chunk, void **array, - unsigned int *count, DWORD elem_size); -HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, void *data, - ULONG size); -HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, - ULONG size); - -static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER offset; - - offset.QuadPart = chunk->offset.QuadPart + sizeof(FOURCC) + sizeof(DWORD); - if (chunk->id == FOURCC_RIFF || chunk->id == FOURCC_LIST) - offset.QuadPart += sizeof(FOURCC); - - return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); -} - -static inline HRESULT stream_reset_chunk_start(IStream *stream, const struct chunk_entry *chunk) -{ - LARGE_INTEGER offset; - - offset.QuadPart = chunk->offset.QuadPart; - - return IStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); -} - - -/* IDirectMusicObject base object */ -struct dmobject { - IDirectMusicObject IDirectMusicObject_iface; - IPersistStream IPersistStream_iface; - IUnknown *outer_unk; - DMUS_OBJECTDESC desc; -}; - -void dmobject_init(struct dmobject *dmobj, const GUID *class, IUnknown *outer_unk); - -/* Generic IDirectMusicObject methods */ -HRESULT WINAPI dmobj_IDirectMusicObject_QueryInterface(IDirectMusicObject *iface, REFIID riid, - void **ret_iface); -ULONG WINAPI dmobj_IDirectMusicObject_AddRef(IDirectMusicObject *iface); -ULONG WINAPI dmobj_IDirectMusicObject_Release(IDirectMusicObject *iface); -HRESULT WINAPI dmobj_IDirectMusicObject_GetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc); -HRESULT WINAPI dmobj_IDirectMusicObject_SetDescriptor(IDirectMusicObject *iface, - DMUS_OBJECTDESC *desc); - -/* Helper for IDirectMusicObject::ParseDescriptor */ -HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, - DMUS_OBJECTDESC *desc, DWORD supported); -/* Additional supported flags for dmobj_parsedescriptor. - DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */ -#define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */ -#define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */ - -/* 'DMRF' (reference list) helper */ -HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, - IDirectMusicObject **dmobj); - -/* Generic IPersistStream methods */ -HRESULT WINAPI dmobj_IPersistStream_QueryInterface(IPersistStream *iface, REFIID riid, - void **ret_iface); -ULONG WINAPI dmobj_IPersistStream_AddRef(IPersistStream *iface); -ULONG WINAPI dmobj_IPersistStream_Release(IPersistStream *iface); -HRESULT WINAPI dmobj_IPersistStream_GetClassID(IPersistStream *iface, CLSID *class); - -/* IPersistStream methods not implemented in native */ -HRESULT WINAPI unimpl_IPersistStream_GetClassID(IPersistStream *iface, - CLSID *class); -HRESULT WINAPI unimpl_IPersistStream_IsDirty(IPersistStream *iface); -HRESULT WINAPI unimpl_IPersistStream_Save(IPersistStream *iface, IStream *stream, - BOOL clear_dirty); -HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, - ULARGE_INTEGER *size); - -/* Debugging helpers */ -const char *debugstr_chunk(const struct chunk_entry *chunk); -const char *debugstr_dmguid(const GUID *id); -void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc); - -static inline const char *debugstr_fourcc(DWORD fourcc) -{ - if (!fourcc) return "''"; - return wine_dbg_sprintf("'%c%c%c%c'", (char)(fourcc), (char)(fourcc >> 8), - (char)(fourcc >> 16), (char)(fourcc >> 24)); -} From 33c9a7ed55f46e4b7e9b2bacb382ef0bc555ff58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 14 Sep 2023 12:24:35 +0200 Subject: [PATCH 2509/2777] dmime: Rewrite IDirectMusicPerformance8_GetTime. (cherry picked from commit d407b3ca52cc5afdb6beee13672a06ca2e57d042) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 46 ++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index d277c5de043..5ae8941cd76 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -60,11 +60,12 @@ struct performance /** Message Processing */ HANDLE procThread; DWORD procThreadId; - REFERENCE_TIME procThreadStartTime; BOOL procThreadTicStarted; CRITICAL_SECTION safe; struct DMUS_PMSGItem *head; struct DMUS_PMSGItem *imm_head; + + IReferenceClock *master_clock; }; typedef struct DMUS_PMSGItem DMUS_PMSGItem; @@ -476,25 +477,21 @@ static HRESULT WINAPI performance_IsPlaying(IDirectMusicPerformance8 *iface, return S_FALSE; } -static HRESULT WINAPI performance_GetTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME *prtNow, MUSIC_TIME *pmtNow) +static HRESULT WINAPI performance_GetTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME *time, MUSIC_TIME *music_time) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); - HRESULT hr = S_OK; - REFERENCE_TIME rtCur = 0; + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + REFERENCE_TIME now; + HRESULT hr; - /*TRACE("(%p, %p, %p)\n", This, prtNow, pmtNow); */ - if (This->procThreadTicStarted) { - rtCur = ((REFERENCE_TIME) GetTickCount() * 10000) - This->procThreadStartTime; - } else { - /*return DMUS_E_NO_MASTER_CLOCK;*/ - } - if (NULL != prtNow) { - *prtNow = rtCur; - } - if (NULL != pmtNow) { - hr = IDirectMusicPerformance8_ReferenceToMusicTime(iface, rtCur, pmtNow); - } - return hr; + TRACE("(%p, %p, %p)\n", iface, time, music_time); + + if (!This->master_clock) return DMUS_E_NO_MASTER_CLOCK; + if (FAILED(hr = IReferenceClock_GetTime(This->master_clock, &now))) return hr; + + if (time) *time = now; + if (music_time) hr = IDirectMusicPerformance8_ReferenceToMusicTime(iface, now, music_time); + + return hr; } static HRESULT WINAPI performance_AllocPMsg(IDirectMusicPerformance8 *iface, ULONG cb, DMUS_PMSG **ppPMSG) @@ -873,6 +870,11 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) This->procThreadTicStarted = FALSE; CloseHandle(This->procThread); } + if (This->master_clock) + { + IReferenceClock_Release(This->master_clock); + This->master_clock = NULL; + } if (This->dsound) { IDirectSound_Release(This->dsound); This->dsound = NULL; @@ -955,6 +957,9 @@ static HRESULT WINAPI performance_InitAudio(IDirectMusicPerformance8 *iface, IDi IDirectMusic8_AddRef(This->dmusic); } + if (FAILED(hr = IDirectMusic_GetMasterClock(This->dmusic, NULL, &This->master_clock))) + goto error; + if (!dsound || !*dsound) { hr = DirectSoundCreate8(NULL, (IDirectSound8 **)&This->dsound, NULL); if (FAILED(hr)) @@ -1006,6 +1011,11 @@ static HRESULT WINAPI performance_InitAudio(IDirectMusicPerformance8 *iface, IDi return S_OK; error: + if (This->master_clock) + { + IReferenceClock_Release(This->master_clock); + This->master_clock = NULL; + } if (This->dsound) { IDirectSound_Release(This->dsound); This->dsound = NULL; From f19139c953f7209fbb8be3ce9e5c1ffbae44a82d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 14 Sep 2023 12:28:17 +0200 Subject: [PATCH 2510/2777] dmime: Implement MusicToReferenceTime and ReferenceToMusicTime. (cherry picked from commit 52ae3fada0baa400936997ce3dfb997ddbe03dab) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 40 ++++++++++++++++++++++++++++++++-------- dlls/dmime/tests/dmime.c | 28 ++++++++++++++-------------- 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 5ae8941cd76..7ce8ccb0d84 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -66,6 +66,7 @@ struct performance struct DMUS_PMSGItem *imm_head; IReferenceClock *master_clock; + REFERENCE_TIME init_time; }; typedef struct DMUS_PMSGItem DMUS_PMSGItem; @@ -451,21 +452,41 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS } static HRESULT WINAPI performance_MusicToReferenceTime(IDirectMusicPerformance8 *iface, - MUSIC_TIME mtTime, REFERENCE_TIME *prtTime) + MUSIC_TIME music_time, REFERENCE_TIME *time) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); - FIXME("(%p, %ld, %p): stub\n", This, mtTime, prtTime); - return S_OK; + FIXME("(%p, %ld, %p): semi-stub\n", This, music_time, time); + + if (!time) return E_POINTER; + *time = 0; + + if (!This->master_clock) return DMUS_E_NO_MASTER_CLOCK; + + /* FIXME: This should be (music_time * 60) / (DMUS_PPQ * tempo) + * but it gives innacurate results */ + *time = This->init_time + (music_time * 6510); + + return S_OK; } static HRESULT WINAPI performance_ReferenceToMusicTime(IDirectMusicPerformance8 *iface, - REFERENCE_TIME rtTime, MUSIC_TIME *pmtTime) + REFERENCE_TIME time, MUSIC_TIME *music_time) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); - FIXME("(%p, 0x%s, %p): stub\n", This, wine_dbgstr_longlong(rtTime), pmtTime); - return S_OK; + FIXME("(%p, %I64d, %p): semi-stub\n", This, time, music_time); + + if (!music_time) return E_POINTER; + *music_time = 0; + + if (!This->master_clock) return DMUS_E_NO_MASTER_CLOCK; + + /* FIXME: This should be (time * DMUS_PPQ * tempo) / 60 + * but it gives innacurate results */ + *music_time = (time - This->init_time) / 6510; + + return S_OK; } static HRESULT WINAPI performance_IsPlaying(IDirectMusicPerformance8 *iface, @@ -1006,6 +1027,9 @@ static HRESULT WINAPI performance_InitAudio(IDirectMusicPerformance8 *iface, IDi *dmusic = (IDirectMusic *)This->dmusic; IDirectMusic_AddRef(*dmusic); } + + if (FAILED(hr = IDirectMusicPerformance8_GetTime(iface, &This->init_time, NULL))) return hr; + PostMessageToProcessMsgThread(This, PROCESSMSG_START); return S_OK; diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index e178960b18f..8999d5564db 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -1650,18 +1650,18 @@ static void test_performance_time(void) hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 0, NULL); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 0, &time); - todo_wine ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr); - todo_wine ok(time == 0, "got %I64d\n", time); + ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr); + ok(time == 0, "got %I64d\n", time); hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, 0, NULL); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); music_time = 0xdeadbeef; hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, 0, &music_time); - todo_wine ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr); - todo_wine ok(music_time == 0, "got %ld\n", music_time); + ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr); + ok(music_time == 0, "got %ld\n", music_time); dmusic = NULL; @@ -1684,38 +1684,38 @@ static void test_performance_time(void) time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(time - init_time >= 6505, "got %I64d\n", time - init_time); + ok(time - init_time >= 6505, "got %I64d\n", time - init_time); ok(time - init_time <= 6515, "got %I64d\n", time - init_time); time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1000, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(time - init_time >= 1000 * 6505, "got %I64d\n", time - init_time); + ok(time - init_time >= 1000 * 6505, "got %I64d\n", time - init_time); ok(time - init_time <= 1000 * 6515, "got %I64d\n", time - init_time); time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 2000, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(time - init_time >= 2000 * 6505, "got %I64d\n", time - init_time); + ok(time - init_time >= 2000 * 6505, "got %I64d\n", time - init_time); ok(time - init_time <= 2000 * 6515, "got %I64d\n", time - init_time); music_time = 0xdeadbeef; hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time, &music_time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(music_time == 0, "got %ld\n", music_time); + ok(music_time == 0, "got %ld\n", music_time); music_time = 0xdeadbeef; hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + 1000 * 6510, &music_time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(music_time == 1000, "got %ld\n", music_time); + ok(music_time == 1000, "got %ld\n", music_time); music_time = 0xdeadbeef; hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + 2000 * 6510, &music_time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(music_time == 2000, "got %ld\n", music_time); + ok(music_time == 2000, "got %ld\n", music_time); time = 0xdeadbeef; music_time = 0xdeadbeef; hr = IDirectMusicPerformance_GetTime(performance, &time, &music_time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(time - init_time <= 200 * 10000, "got %I64d\n", time - init_time); - todo_wine ok(music_time == (time - init_time) / 6510, "got %ld\n", music_time); + ok(time - init_time <= 200 * 10000, "got %I64d\n", time - init_time); + ok(music_time == (time - init_time) / 6510, "got %ld\n", music_time); hr = IDirectMusicPerformance_CloseDown(performance); From f5fa4b6a150480a06588e6876a0cdc667bfee245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Sep 2023 10:44:16 +0200 Subject: [PATCH 2511/2777] dmime: Cleanup IDirectMusicPerformance_AllocPMsg. (cherry picked from commit 9d600ce191ffcf3af374142a7b3a8654b67aa8d5) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 27 ++++++++++++--------------- dlls/dmime/tests/dmime.c | 2 +- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 7ce8ccb0d84..7cf446d9816 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -81,7 +81,6 @@ struct DMUS_PMSGItem { }; #define DMUS_PMSGToItem(pMSG) ((DMUS_PMSGItem*) (((unsigned char*) pPMSG) - offsetof(DMUS_PMSGItem, pMsg))) -#define DMUS_ItemToPMSG(pItem) (&(pItem->pMsg)) #define DMUS_ItemRemoveFromQueue(This,pItem) \ {\ if (pItem->prev) pItem->prev->next = pItem->next;\ @@ -515,23 +514,21 @@ static HRESULT WINAPI performance_GetTime(IDirectMusicPerformance8 *iface, REFER return hr; } -static HRESULT WINAPI performance_AllocPMsg(IDirectMusicPerformance8 *iface, ULONG cb, DMUS_PMSG **ppPMSG) +static HRESULT WINAPI performance_AllocPMsg(IDirectMusicPerformance8 *iface, ULONG size, DMUS_PMSG **msg) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); - DMUS_PMSGItem* pItem = NULL; + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + DMUS_PMSGItem *message; - FIXME("(%p, %ld, %p): stub\n", This, cb, ppPMSG); + TRACE("(%p, %ld, %p)\n", This, size, msg); - if (sizeof(DMUS_PMSG) > cb) { - return E_INVALIDARG; - } - if (NULL == ppPMSG) { - return E_POINTER; - } - if (!(pItem = calloc(1, cb - sizeof(DMUS_PMSG) + sizeof(DMUS_PMSGItem)))) return E_OUTOFMEMORY; - pItem->pMsg.dwSize = cb; - *ppPMSG = DMUS_ItemToPMSG(pItem); - return S_OK; + if (!msg) return E_POINTER; + if (size < sizeof(DMUS_PMSG)) return E_INVALIDARG; + + if (!(message = calloc(1, size - sizeof(DMUS_PMSG) + sizeof(DMUS_PMSGItem)))) return E_OUTOFMEMORY; + message->pMsg.dwSize = size; + *msg = &message->pMsg; + + return S_OK; } static HRESULT WINAPI performance_FreePMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *pPMSG) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 8999d5564db..5a1d5c9733e 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -1747,7 +1747,7 @@ static void test_performance_pmsg(void) hr = IDirectMusicPerformance_AllocPMsg(performance, 0, NULL); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG) - 1, &msg); ok(hr == E_INVALIDARG, "got %#lx\n", hr); From c699f0b07188d3bdcfad47d3237426b8532ae78c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Sep 2023 10:45:43 +0200 Subject: [PATCH 2512/2777] dmime: Cleanup IDirectMusicPerformance_FreePMsg. (cherry picked from commit 4adeeb72d3e023bcefe0adebff9565ca45a8a1a9) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 47 +++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 7cf446d9816..bcb7faa405e 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -80,7 +80,7 @@ struct DMUS_PMSGItem { DMUS_PMSG pMsg; }; -#define DMUS_PMSGToItem(pMSG) ((DMUS_PMSGItem*) (((unsigned char*) pPMSG) - offsetof(DMUS_PMSGItem, pMsg))) +#define DMUS_PMSGToItem(pMSG) ((DMUS_PMSGItem *)(((unsigned char *)pMSG) - offsetof(DMUS_PMSGItem, pMsg))) #define DMUS_ItemRemoveFromQueue(This,pItem) \ {\ if (pItem->prev) pItem->prev->next = pItem->next;\ @@ -531,37 +531,30 @@ static HRESULT WINAPI performance_AllocPMsg(IDirectMusicPerformance8 *iface, ULO return S_OK; } -static HRESULT WINAPI performance_FreePMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *pPMSG) +static HRESULT WINAPI performance_FreePMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *msg) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); - DMUS_PMSGItem* pItem = NULL; - - FIXME("(%p, %p): stub\n", This, pPMSG); - - if (NULL == pPMSG) { - return E_POINTER; - } - pItem = DMUS_PMSGToItem(pPMSG); - if (pItem->bInUse) { - /** prevent for freeing PMsg in queue (ie to be processed) */ - return DMUS_E_CANNOT_FREE; - } - /** now we can remove it safely */ - EnterCriticalSection(&This->safe); - DMUS_ItemRemoveFromQueue( This, pItem ); - LeaveCriticalSection(&This->safe); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + DMUS_PMSGItem *message; + HRESULT hr; - if (pPMSG->pTool) - IDirectMusicTool_Release(pPMSG->pTool); + TRACE("(%p, %p)\n", This, msg); - if (pPMSG->pGraph) - IDirectMusicGraph_Release(pPMSG->pGraph); + if (!msg) return E_POINTER; + message = DMUS_PMSGToItem(msg); - if (pPMSG->punkUser) - IUnknown_Release(pPMSG->punkUser); + EnterCriticalSection(&This->safe); + hr = message->bInUse ? DMUS_E_CANNOT_FREE : S_OK; + LeaveCriticalSection(&This->safe); - free(pItem); - return S_OK; + if (SUCCEEDED(hr)) + { + if (msg->pTool) IDirectMusicTool_Release(msg->pTool); + if (msg->pGraph) IDirectMusicGraph_Release(msg->pGraph); + if (msg->punkUser) IUnknown_Release(msg->punkUser); + free(message); + } + + return hr; } static HRESULT WINAPI performance_GetGraph(IDirectMusicPerformance8 *iface, IDirectMusicGraph **graph) From e835ae78f4d1eecb09916d8374b49519a12b2897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Sep 2023 10:52:17 +0200 Subject: [PATCH 2513/2777] dmime: Cleanup IDirectMusicPerformance_SendPMsg. (cherry picked from commit 0c4e1e435243f1eff77ef8dc05008d7e3228cc0d) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 99 +++++++++++++++++++++------------------- dlls/dmime/tests/dmime.c | 8 ++-- 2 files changed, 57 insertions(+), 50 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index bcb7faa405e..d08f72d8d1f 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -399,55 +399,62 @@ static HRESULT WINAPI performance_GetBumperLength(IDirectMusicPerformance8 *ifac return S_OK; } -static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *pPMSG) +static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *msg) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); - DMUS_PMSGItem* pItem = NULL; - DMUS_PMSGItem* it = NULL; - DMUS_PMSGItem* prev_it = NULL; - DMUS_PMSGItem** queue = NULL; + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + DMUS_PMSGItem *message; + DMUS_PMSGItem *it = NULL; + DMUS_PMSGItem *prev_it = NULL; + DMUS_PMSGItem **queue; + HRESULT hr; - FIXME("(%p, %p): stub\n", This, pPMSG); - - if (NULL == pPMSG) { - return E_POINTER; - } - pItem = DMUS_PMSGToItem(pPMSG); - if (pItem->bInUse) { - return DMUS_E_ALREADY_SENT; - } - - /* TODO: Valid Flags */ - /* TODO: DMUS_PMSGF_MUSICTIME */ - pItem->rtItemTime = pPMSG->rtTime; - - if (pPMSG->dwFlags & DMUS_PMSGF_TOOL_IMMEDIATE) { - queue = &This->imm_head; - } else { - queue = &This->head; - } + FIXME("(%p, %p): semi-stub\n", This, msg); - EnterCriticalSection(&This->safe); - for (it = *queue; NULL != it && it->rtItemTime < pItem->rtItemTime; it = it->next) { - prev_it = it; - } - if (NULL == prev_it) { - pItem->prev = NULL; - if (NULL != *queue) pItem->next = (*queue)->next; - /*assert( NULL == pItem->next->prev );*/ - if (NULL != pItem->next) pItem->next->prev = pItem; - *queue = pItem; - } else { - pItem->prev = prev_it; - pItem->next = prev_it->next; - prev_it->next = pItem; - if (NULL != pItem->next) pItem->next->prev = pItem; - } - LeaveCriticalSection(&This->safe); - - /** now in use, prevent from stupid Frees */ - pItem->bInUse = TRUE; - return S_OK; + if (!msg) return E_POINTER; + if (!This->dmusic) return DMUS_E_NO_MASTER_CLOCK; + if (!(msg->dwFlags & (DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_REFTIME))) return E_INVALIDARG; + + if (msg->dwFlags & DMUS_PMSGF_TOOL_IMMEDIATE) queue = &This->imm_head; + else queue = &This->head; + + message = DMUS_PMSGToItem(msg); + + EnterCriticalSection(&This->safe); + + if (message->bInUse) + hr = DMUS_E_ALREADY_SENT; + else + { + /* TODO: Valid Flags */ + /* TODO: DMUS_PMSGF_MUSICTIME */ + message->rtItemTime = msg->rtTime; + + for (it = *queue; NULL != it && it->rtItemTime < message->rtItemTime; it = it->next) + prev_it = it; + + if (!prev_it) + { + message->prev = NULL; + if (*queue) message->next = (*queue)->next; + /*assert( NULL == message->next->prev );*/ + if (message->next) message->next->prev = message; + *queue = message; + } + else + { + message->prev = prev_it; + message->next = prev_it->next; + prev_it->next = message; + if (message->next) message->next->prev = message; + } + + message->bInUse = TRUE; + hr = S_OK; + } + + LeaveCriticalSection(&This->safe); + + return hr; } static HRESULT WINAPI performance_MusicToReferenceTime(IDirectMusicPerformance8 *iface, diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 5a1d5c9733e..f5d64498abb 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -1767,12 +1767,12 @@ static void test_performance_pmsg(void) hr = IDirectMusicPerformance_SendPMsg(performance, NULL); ok(hr == E_POINTER, "got %#lx\n", hr); hr = IDirectMusicPerformance_SendPMsg(performance, msg); - todo_wine ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr); + ok(hr == DMUS_E_NO_MASTER_CLOCK, "got %#lx\n", hr); hr = IDirectMusicPerformance_FreePMsg(performance, NULL); ok(hr == E_POINTER, "got %#lx\n", hr); hr = IDirectMusicPerformance_FreePMsg(performance, msg); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0); @@ -1802,7 +1802,7 @@ static void test_performance_pmsg(void) ok(!msg->dwGroupID, "got %ld\n", msg->dwGroupID); ok(!msg->punkUser, "got %p\n", msg->punkUser); hr = IDirectMusicPerformance_SendPMsg(performance, msg); - todo_wine ok(hr == E_INVALIDARG, "got %#lx\n", hr); + ok(hr == E_INVALIDARG, "got %#lx\n", hr); hr = IDirectMusicPerformance8_ClonePMsg((IDirectMusicPerformance8 *)performance, msg, NULL); todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); @@ -1816,7 +1816,7 @@ static void test_performance_pmsg(void) msg->mtTime = 500; msg->dwFlags = DMUS_PMSGF_MUSICTIME; hr = IDirectMusicPerformance_SendPMsg(performance, msg); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPerformance_SendPMsg(performance, msg); ok(hr == DMUS_E_ALREADY_SENT, "got %#lx\n", hr); hr = IDirectMusicPerformance_FreePMsg(performance, msg); From 99d5abb15df6577872522ba6b574e67739eea91a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Sep 2023 19:20:59 +0200 Subject: [PATCH 2514/2777] dmime: Implement IDirectMusicPerformance8_ClonePMsg. (cherry picked from commit 4b787aa9b3ff97fcf0a0527e0aeffb2aba6c3b5e) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 19 ++++++++++++++----- dlls/dmime/tests/dmime.c | 9 ++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index d08f72d8d1f..b3fd4851d45 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1071,13 +1071,22 @@ static HRESULT WINAPI performance_StopEx(IDirectMusicPerformance8 *iface, IUnkno return S_OK; } -static HRESULT WINAPI performance_ClonePMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *pSourcePMSG, - DMUS_PMSG **ppCopyPMSG) +static HRESULT WINAPI performance_ClonePMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *msg, DMUS_PMSG **clone) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + HRESULT hr; - FIXME("(%p, %p, %p): stub\n", This, pSourcePMSG, ppCopyPMSG); - return S_OK; + TRACE("(%p, %p, %p)\n", This, msg, clone); + + if (!msg || !clone) return E_POINTER; + if (FAILED(hr = IDirectMusicPerformance8_AllocPMsg(iface, msg->dwSize, clone))) return hr; + + memcpy(*clone, msg, msg->dwSize); + if (msg->pTool) IDirectMusicTool_AddRef(msg->pTool); + if (msg->pGraph) IDirectMusicGraph_AddRef(msg->pGraph); + if (msg->punkUser) IUnknown_AddRef(msg->punkUser); + + return S_OK; } static HRESULT WINAPI performance_CreateAudioPath(IDirectMusicPerformance8 *iface, diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index f5d64498abb..26efdd4c72f 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -1805,13 +1805,13 @@ static void test_performance_pmsg(void) ok(hr == E_INVALIDARG, "got %#lx\n", hr); hr = IDirectMusicPerformance8_ClonePMsg((IDirectMusicPerformance8 *)performance, msg, NULL); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); hr = IDirectMusicPerformance8_ClonePMsg((IDirectMusicPerformance8 *)performance, NULL, &clone); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); clone = NULL; hr = IDirectMusicPerformance8_ClonePMsg((IDirectMusicPerformance8 *)performance, msg, &clone); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(clone != NULL, "got %p\n", clone); + ok(clone != NULL, "got %p\n", clone); msg->mtTime = 500; msg->dwFlags = DMUS_PMSGF_MUSICTIME; @@ -1822,8 +1822,7 @@ static void test_performance_pmsg(void) hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == DMUS_E_CANNOT_FREE, "got %#lx\n", hr); - if (!clone) hr = S_OK; - else hr = IDirectMusicPerformance_FreePMsg(performance, clone); + hr = IDirectMusicPerformance_FreePMsg(performance, clone); ok(hr == S_OK, "got %#lx\n", hr); From 350ed2e02af2f92947d4f8ded1884f6b64b24a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 9 Sep 2023 13:42:29 +0200 Subject: [PATCH 2515/2777] dmusic: Rewrite collection lins list parsing. (cherry picked from commit bb2a8312b129a0270f5fc74bc53217edff895772) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/buffer.c | 1 - dlls/dmusic/clock.c | 1 - dlls/dmusic/collection.c | 67 ++++++++++++++++++------------------ dlls/dmusic/dmusic.c | 1 - dlls/dmusic/dmusic_main.c | 1 - dlls/dmusic/dmusic_private.h | 5 ++- dlls/dmusic/download.c | 1 - dlls/dmusic/instrument.c | 28 +++------------ dlls/dmusic/port.c | 1 - 9 files changed, 43 insertions(+), 63 deletions(-) diff --git a/dlls/dmusic/buffer.c b/dlls/dmusic/buffer.c index a2ad137fe4b..7f6087fcaaf 100644 --- a/dlls/dmusic/buffer.c +++ b/dlls/dmusic/buffer.c @@ -20,7 +20,6 @@ */ #include "dmusic_private.h" -#include "dmobject.h" #include "initguid.h" #include "dmksctrl.h" diff --git a/dlls/dmusic/clock.c b/dlls/dmusic/clock.c index 7b574dd4432..35df27056fb 100644 --- a/dlls/dmusic/clock.c +++ b/dlls/dmusic/clock.c @@ -19,7 +19,6 @@ */ #include "dmusic_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmusic); diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 2d4a7f855ae..acd85768cec 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -19,7 +19,6 @@ */ #include "dmusic_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmusic); WINE_DECLARE_DEBUG_CHANNEL(dmfile); @@ -177,6 +176,34 @@ static const IDirectMusicCollectionVtbl collection_vtbl = collection_EnumInstrument, }; +static HRESULT parse_lins_list(struct collection *This, IStream *stream, struct chunk_entry *parent) +{ + struct chunk_entry chunk = {.parent = parent}; + struct instrument_entry *entry; + HRESULT hr; + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case MAKE_IDTYPE(FOURCC_LIST, FOURCC_INS): + if (!(entry = malloc(sizeof(*entry)))) return E_OUTOFMEMORY; + hr = instrument_create_from_chunk(stream, &chunk, &entry->instrument); + if (SUCCEEDED(hr)) list_add_tail(&This->instruments, &entry->entry); + else free(entry); + break; + + default: + FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; + } + + return hr; +} + static HRESULT WINAPI collection_object_ParseDescriptor(IDirectMusicObject *iface, IStream *stream, DMUS_OBJECTDESC *desc) { @@ -373,39 +400,13 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, break; } case FOURCC_LINS: { + struct chunk_entry lins_chunk = {.id = FOURCC_LIST, .size = chunk.dwSize, .type = chunk.fccID}; TRACE_(dmfile)(": instruments list\n"); - do { - IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL); - ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = %#04lx)", debugstr_fourcc(chunk.fccID), chunk.dwSize); - switch (chunk.fccID) { - case FOURCC_LIST: { - IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL); - TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID)); - ListSize[1] = chunk.dwSize - sizeof(FOURCC); - ListCount[1] = 0; - switch (chunk.fccID) { - case FOURCC_INS: { - struct instrument_entry *entry = calloc(1, sizeof(*entry)); - TRACE_(dmfile)(": instrument list\n"); - liMove.QuadPart = -12; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); - if (FAILED(instrument_create_from_stream(stream, &entry->instrument))) free(entry); - else list_add_tail(&This->instruments, &entry->entry); - break; - } - } - break; - } - default: { - TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); - liMove.QuadPart = chunk.dwSize; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]); - } while (ListCount[0] < ListSize[0]); + liMove.QuadPart = 0; + IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &lins_chunk.offset); + lins_chunk.offset.QuadPart -= 12; + parse_lins_list(This, stream, &lins_chunk); + stream_skip_chunk(stream, &lins_chunk); break; } default: { diff --git a/dlls/dmusic/dmusic.c b/dlls/dmusic/dmusic.c index 57a39d1465c..822c35ba616 100644 --- a/dlls/dmusic/dmusic.c +++ b/dlls/dmusic/dmusic.c @@ -22,7 +22,6 @@ #include #include "dmusic_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmusic); diff --git a/dlls/dmusic/dmusic_main.c b/dlls/dmusic/dmusic_main.c index f0aaca8947a..52607e1d936 100644 --- a/dlls/dmusic/dmusic_main.c +++ b/dlls/dmusic/dmusic_main.c @@ -35,7 +35,6 @@ #include "dmusici.h" #include "dmusic_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmusic); diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index b668f2f2559..57aca4e8ea7 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -44,6 +44,8 @@ #include "dmusics.h" #include "dmksctrl.h" +#include "dmobject.h" + /***************************************************************************** * Interfaces */ @@ -98,7 +100,8 @@ extern HRESULT DMUSIC_CreateReferenceClockImpl (LPCGUID lpcGUID, LPVOID* ppobj, extern HRESULT download_create(DWORD size, IDirectMusicDownload **ret_iface); -extern HRESULT instrument_create_from_stream(IStream *stream, IDirectMusicInstrument **ret_iface); +extern HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent, + IDirectMusicInstrument **ret_iface); /***************************************************************************** * IDirectMusic8Impl implementation structure diff --git a/dlls/dmusic/download.c b/dlls/dmusic/download.c index 6dac3e1b725..008e52edbfd 100644 --- a/dlls/dmusic/download.c +++ b/dlls/dmusic/download.c @@ -19,7 +19,6 @@ */ #include "dmusic_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmusic); diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index b62b053c542..aacbe6e8c88 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -19,7 +19,6 @@ */ #include "dmusic_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmusic); @@ -303,9 +302,9 @@ static HRESULT parse_ins_chunk(struct instrument *This, IStream *stream, struct return hr; } -HRESULT instrument_create_from_stream(IStream *stream, IDirectMusicInstrument **ret_iface) +HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent, + IDirectMusicInstrument **ret_iface) { - struct chunk_entry chunk = {0}; IDirectMusicInstrument *iface; struct instrument *This; HRESULT hr; @@ -315,23 +314,12 @@ HRESULT instrument_create_from_stream(IStream *stream, IDirectMusicInstrument ** if (FAILED(hr = instrument_create(&iface))) return hr; This = impl_from_IDirectMusicInstrument(iface); - if ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + if (FAILED(hr = parse_ins_chunk(This, stream, parent))) { - switch (MAKE_IDTYPE(chunk.id, chunk.type)) - { - case MAKE_IDTYPE(FOURCC_LIST, FOURCC_INS): - hr = parse_ins_chunk(This, stream, &chunk); - break; - - default: - WARN("Invalid instrument chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); - hr = E_INVALIDARG; - break; - } + IDirectMusicInstrument_Release(iface); + return DMUS_E_UNSUPPORTED_STREAM; } - if (FAILED(hr)) goto error; - if (TRACE_ON(dmusic)) { TRACE("Created DirectMusicInstrument (%p) ***\n", This); @@ -347,10 +335,4 @@ HRESULT instrument_create_from_stream(IStream *stream, IDirectMusicInstrument ** *ret_iface = iface; return S_OK; - -error: - IDirectMusicInstrument_Release(iface); - - stream_skip_chunk(stream, &chunk); - return DMUS_E_UNSUPPORTED_STREAM; } diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index 27e20b1cf81..7e3fa5a67eb 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -21,7 +21,6 @@ #include #include "dmusic_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmusic); From ceccff5b3bccba04587fed6115299fb9396c23d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 22:21:53 +0200 Subject: [PATCH 2516/2777] dmusic: Rewrite collection ptbl chunk parsing. (cherry picked from commit af79bf4f226456f12025ac25156275f24dbc27bd) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 46 +++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index acd85768cec..4d690f597db 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -29,6 +29,14 @@ struct instrument_entry IDirectMusicInstrument *instrument; }; +struct pool +{ + POOLTABLE table; + POOLCUE cues[]; +}; + +C_ASSERT(sizeof(struct pool) == offsetof(struct pool, cues[0])); + struct collection { IDirectMusicCollection IDirectMusicCollection_iface; @@ -38,10 +46,8 @@ struct collection IStream *pStm; /* stream from which we load collection and later instruments */ CHAR *szCopyright; /* FIXME: should probably be placed somewhere else */ DLSHEADER *pHeader; - /* pool table */ - POOLTABLE *pPoolTable; - POOLCUE *pPoolCues; + struct pool *pool; struct list instruments; }; @@ -204,6 +210,29 @@ static HRESULT parse_lins_list(struct collection *This, IStream *stream, struct return hr; } +static HRESULT parse_ptbl_chunk(struct collection *This, IStream *stream, struct chunk_entry *chunk) +{ + struct pool *pool; + POOLTABLE table; + HRESULT hr; + UINT size; + + if (chunk->size < sizeof(table)) return E_INVALIDARG; + if (FAILED(hr = stream_read(stream, &table, sizeof(table)))) return hr; + if (chunk->size != table.cbSize + sizeof(POOLCUE) * table.cCues) return E_INVALIDARG; + if (table.cbSize != sizeof(table)) return E_INVALIDARG; + + size = offsetof(struct pool, cues[table.cCues]); + if (!(pool = malloc(size))) return E_OUTOFMEMORY; + pool->table = table; + + size = sizeof(POOLCUE) * table.cCues; + if (FAILED(hr = stream_read(stream, pool->cues, size))) free(pool); + else This->pool = pool; + + return hr; +} + static HRESULT WINAPI collection_object_ParseDescriptor(IDirectMusicObject *iface, IStream *stream, DMUS_OBJECTDESC *desc) { @@ -303,12 +332,13 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, break; } case FOURCC_PTBL: { + struct chunk_entry ptbl_chunk = {.id = FOURCC_LIST, .size = chunk.dwSize, .type = chunk.fccID}; TRACE_(dmfile)(": pool table chunk\n"); - This->pPoolTable = calloc(1, sizeof(POOLTABLE)); - IStream_Read(stream, This->pPoolTable, sizeof(POOLTABLE), NULL); - chunk.dwSize -= sizeof(POOLTABLE); - This->pPoolCues = calloc(This->pPoolTable->cCues, sizeof(POOLCUE)); - IStream_Read(stream, This->pPoolCues, chunk.dwSize, NULL); + liMove.QuadPart = 0; + IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &ptbl_chunk.offset); + ptbl_chunk.offset.QuadPart -= 12; + parse_ptbl_chunk(This, stream, &ptbl_chunk); + stream_skip_chunk(stream, &ptbl_chunk); break; } case FOURCC_LIST: { From 079524db870cc3b83dd301fa89cf9052c1792bff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 22:19:45 +0200 Subject: [PATCH 2517/2777] dmusic: Rewrite collection INFO list parsing. (cherry picked from commit 866d4998ed0a917e6906167ae6985c793d1d88c4) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 109 ++++++----------------------------- dlls/dmusic/dmobject.c | 7 +++ dlls/dmusic/dmobject.h | 1 + dlls/dmusic/dmusic_main.c | 5 -- dlls/dmusic/dmusic_private.h | 2 - 5 files changed, 25 insertions(+), 99 deletions(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 4d690f597db..168a49fa8c0 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -44,7 +44,6 @@ struct collection LONG ref; IStream *pStm; /* stream from which we load collection and later instruments */ - CHAR *szCopyright; /* FIXME: should probably be placed somewhere else */ DLSHEADER *pHeader; struct pool *pool; @@ -277,9 +276,10 @@ static const IDirectMusicObjectVtbl collection_object_vtbl = static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream *stream) { + struct chunk_entry dls_chunk = {0}; struct collection *This = impl_from_IPersistStream(iface); DMUS_PRIVATE_CHUNK chunk; - DWORD StreamSize, StreamCount, ListSize[2], ListCount[2]; + DWORD StreamSize, StreamCount; LARGE_INTEGER liMove; /* used when skipping chunks */ IStream_AddRef(stream); /* add count for later references */ @@ -307,6 +307,21 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, return E_FAIL; } + dls_chunk.id = FOURCC_RIFF; + dls_chunk.size = chunk.dwSize; + dls_chunk.type = chunk.fccID; + liMove.QuadPart = 0; + IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dls_chunk.offset); + dls_chunk.offset.QuadPart -= 12; + if (FAILED(dmobj_parsedescriptor(stream, &dls_chunk, &This->dmobj.desc, + DMUS_OBJ_NAME_INFO|DMUS_OBJ_VERSION|DMUS_OBJ_OBJECT|DMUS_OBJ_GUID_DLID))) + { + liMove.QuadPart = StreamSize; + IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */ + return E_FAIL; + } + stream_reset_chunk_data(stream, &dls_chunk); + TRACE_(dmfile)(": collection form\n"); do { IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL); @@ -319,18 +334,6 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream_Read(stream, This->pHeader, chunk.dwSize, NULL); break; } - case FOURCC_DLID: { - TRACE_(dmfile)(": DLID (GUID) chunk\n"); - This->dmobj.desc.dwValidData |= DMUS_OBJ_OBJECT; - IStream_Read(stream, &This->dmobj.desc.guidObject, chunk.dwSize, NULL); - break; - } - case FOURCC_VERS: { - TRACE_(dmfile)(": version chunk\n"); - This->dmobj.desc.dwValidData |= DMUS_OBJ_VERSION; - IStream_Read(stream, &This->dmobj.desc.vVersion, chunk.dwSize, NULL); - break; - } case FOURCC_PTBL: { struct chunk_entry ptbl_chunk = {.id = FOURCC_LIST, .size = chunk.dwSize, .type = chunk.fccID}; TRACE_(dmfile)(": pool table chunk\n"); @@ -344,85 +347,7 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, case FOURCC_LIST: { IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL); TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID)); - ListSize[0] = chunk.dwSize - sizeof(FOURCC); - ListCount[0] = 0; switch (chunk.fccID) { - case DMUS_FOURCC_INFO_LIST: { - TRACE_(dmfile)(": INFO list\n"); - do { - IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL); - ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = %#04lx)", debugstr_fourcc(chunk.fccID), chunk.dwSize); - switch (chunk.fccID) { - case mmioFOURCC('I','N','A','M'): { - CHAR szName[DMUS_MAX_NAME]; - TRACE_(dmfile)(": name chunk\n"); - This->dmobj.desc.dwValidData |= DMUS_OBJ_NAME; - IStream_Read(stream, szName, chunk.dwSize, NULL); - MultiByteToWideChar(CP_ACP, 0, szName, -1, This->dmobj.desc.wszName, DMUS_MAX_NAME); - if (even_or_odd(chunk.dwSize)) { - ListCount[0]++; - liMove.QuadPart = 1; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); - } - break; - } - case mmioFOURCC('I','A','R','T'): { - TRACE_(dmfile)(": artist chunk (ignored)\n"); - if (even_or_odd(chunk.dwSize)) { - ListCount[0]++; - chunk.dwSize++; - } - liMove.QuadPart = chunk.dwSize; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); - break; - } - case mmioFOURCC('I','C','O','P'): { - TRACE_(dmfile)(": copyright chunk\n"); - This->szCopyright = calloc(1, chunk.dwSize); - IStream_Read(stream, This->szCopyright, chunk.dwSize, NULL); - if (even_or_odd(chunk.dwSize)) { - ListCount[0]++; - liMove.QuadPart = 1; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); - } - break; - } - case mmioFOURCC('I','S','B','J'): { - TRACE_(dmfile)(": subject chunk (ignored)\n"); - if (even_or_odd(chunk.dwSize)) { - ListCount[0]++; - chunk.dwSize++; - } - liMove.QuadPart = chunk.dwSize; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); - break; - } - case mmioFOURCC('I','C','M','T'): { - TRACE_(dmfile)(": comment chunk (ignored)\n"); - if (even_or_odd(chunk.dwSize)) { - ListCount[0]++; - chunk.dwSize++; - } - liMove.QuadPart = chunk.dwSize; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); - break; - } - default: { - TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); - if (even_or_odd(chunk.dwSize)) { - ListCount[0]++; - chunk.dwSize++; - } - liMove.QuadPart = chunk.dwSize; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]); - } while (ListCount[0] < ListSize[0]); - break; - } case FOURCC_WVPL: { TRACE_(dmfile)(": wave pool list (mark & skip)\n"); liMove.QuadPart = chunk.dwSize - sizeof(FOURCC); diff --git a/dlls/dmusic/dmobject.c b/dlls/dmusic/dmobject.c index 2bef5511851..3007aceef3e 100644 --- a/dlls/dmusic/dmobject.c +++ b/dlls/dmusic/dmobject.c @@ -587,7 +587,14 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, desc->wszFileName, sizeof(desc->wszFileName)) == S_OK) desc->dwValidData |= DMUS_OBJ_FILENAME; break; + case FOURCC_DLID: + if (!(supported & DMUS_OBJ_GUID_DLID)) break; + if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk, + &desc->guidObject, sizeof(desc->guidObject)) == S_OK) + desc->dwValidData |= DMUS_OBJ_OBJECT; + break; case DMUS_FOURCC_GUID_CHUNK: + if ((supported & DMUS_OBJ_GUID_DLID)) break; if ((supported & DMUS_OBJ_OBJECT) && stream_chunk_get_data(stream, &chunk, &desc->guidObject, sizeof(desc->guidObject)) == S_OK) desc->dwValidData |= DMUS_OBJ_OBJECT; diff --git a/dlls/dmusic/dmobject.h b/dlls/dmusic/dmobject.h index 98069de8cc4..ae06935dfea 100644 --- a/dlls/dmusic/dmobject.h +++ b/dlls/dmusic/dmobject.h @@ -92,6 +92,7 @@ HRESULT dmobj_parsedescriptor(IStream *stream, const struct chunk_entry *riff, DMUS_OBJ_NAME is 'UNAM' chunk in UNFO list */ #define DMUS_OBJ_NAME_INAM 0x1000 /* 'INAM' chunk in UNFO list */ #define DMUS_OBJ_NAME_INFO 0x2000 /* 'INAM' chunk in INFO list */ +#define DMUS_OBJ_GUID_DLID 0x4000 /* 'dlid' chunk instead of 'guid' */ /* 'DMRF' (reference list) helper */ HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, diff --git a/dlls/dmusic/dmusic_main.c b/dlls/dmusic/dmusic_main.c index 52607e1d936..eabf9f131b9 100644 --- a/dlls/dmusic/dmusic_main.c +++ b/dlls/dmusic/dmusic_main.c @@ -165,11 +165,6 @@ void Patch2MIDILOCALE (DWORD dwPatch, LPMIDILOCALE pLocale) { pLocale->ulBank |= (dwPatch & F_INSTRUMENT_DRUMS); /* get drum bit */ } -/* check whether the given DWORD is even (return 0) or odd (return 1) */ -int even_or_odd (DWORD number) { - return (number & 0x1); /* basically, check if bit 0 is set ;) */ -} - /* generic flag-dumping function */ static const char* debugstr_flags (DWORD flags, const flag_info* names, size_t num_names){ char buffer[128] = "", *ptr = &buffer[0]; diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 57aca4e8ea7..3e184fa86da 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -214,8 +214,6 @@ extern DWORD MIDILOCALE2Patch (const MIDILOCALE *pLocale); /* MIDILOCALE from dwPatch */ extern void Patch2MIDILOCALE (DWORD dwPatch, LPMIDILOCALE pLocale); -/* check whether the given DWORD is even (return 0) or odd (return 1) */ -extern int even_or_odd (DWORD number); /* Dump whole DMUS_PORTPARAMS struct */ extern void dump_DMUS_PORTPARAMS(LPDMUS_PORTPARAMS params); From f9203a224aea09023c0a5d4b123601b9ce9e2e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 14 Sep 2023 13:13:22 +0200 Subject: [PATCH 2518/2777] dmusic: Rewrite collection DLS chunk parsing. (cherry picked from commit d30f914de624f395e9adca7200c48d1fc0b62bac) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 176 +++++++++++++---------------------- dlls/dmusic/dmusic_private.h | 6 -- 2 files changed, 63 insertions(+), 119 deletions(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 168a49fa8c0..f26806a1afb 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -21,7 +21,6 @@ #include "dmusic_private.h" WINE_DEFAULT_DEBUG_CHANNEL(dmusic); -WINE_DECLARE_DEBUG_CHANNEL(dmfile); struct instrument_entry { @@ -43,9 +42,7 @@ struct collection struct dmobject dmobj; LONG ref; - IStream *pStm; /* stream from which we load collection and later instruments */ - DLSHEADER *pHeader; - + DLSHEADER header; struct pool *pool; struct list instruments; }; @@ -232,6 +229,49 @@ static HRESULT parse_ptbl_chunk(struct collection *This, IStream *stream, struct return hr; } +static HRESULT parse_dls_chunk(struct collection *This, IStream *stream, struct chunk_entry *parent) +{ + struct chunk_entry chunk = {.parent = parent}; + HRESULT hr; + + if (FAILED(hr = dmobj_parsedescriptor(stream, parent, &This->dmobj.desc, + DMUS_OBJ_NAME_INFO|DMUS_OBJ_VERSION|DMUS_OBJ_OBJECT|DMUS_OBJ_GUID_DLID)) + || FAILED(hr = stream_reset_chunk_data(stream, parent))) + return hr; + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case FOURCC_DLID: + case FOURCC_VERS: + case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_INFO_LIST): + /* already parsed by dmobj_parsedescriptor */ + break; + + case FOURCC_COLH: + hr = stream_chunk_get_data(stream, &chunk, &This->header, sizeof(This->header)); + break; + + case FOURCC_PTBL: + hr = parse_ptbl_chunk(This, stream, &chunk); + break; + + case MAKE_IDTYPE(FOURCC_LIST, FOURCC_LINS): + hr = parse_lins_list(This, stream, &chunk); + break; + + default: + FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; + } + + return hr; +} + static HRESULT WINAPI collection_object_ParseDescriptor(IDirectMusicObject *iface, IStream *stream, DMUS_OBJECTDESC *desc) { @@ -273,121 +313,30 @@ static const IDirectMusicObjectVtbl collection_object_vtbl = collection_object_ParseDescriptor, }; -static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, - IStream *stream) +static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream *stream) { - struct chunk_entry dls_chunk = {0}; struct collection *This = impl_from_IPersistStream(iface); - DMUS_PRIVATE_CHUNK chunk; - DWORD StreamSize, StreamCount; - LARGE_INTEGER liMove; /* used when skipping chunks */ - - IStream_AddRef(stream); /* add count for later references */ - This->pStm = stream; - - IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL); - TRACE_(dmfile)(": %s chunk (size = %#04lx)", debugstr_fourcc(chunk.fccID), chunk.dwSize); - - if (chunk.fccID != FOURCC_RIFF) { - TRACE_(dmfile)(": unexpected chunk; loading failed)\n"); - liMove.QuadPart = chunk.dwSize; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */ - return E_FAIL; - } + struct chunk_entry chunk = {0}; + HRESULT hr; - IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL); - TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(chunk.fccID)); - StreamSize = chunk.dwSize - sizeof(FOURCC); - StreamCount = 0; + TRACE("(%p, %p)\n", This, stream); - if (chunk.fccID != FOURCC_DLS) { - TRACE_(dmfile)(": unexpected chunk; loading failed)\n"); - liMove.QuadPart = StreamSize; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */ - return E_FAIL; - } - - dls_chunk.id = FOURCC_RIFF; - dls_chunk.size = chunk.dwSize; - dls_chunk.type = chunk.fccID; - liMove.QuadPart = 0; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dls_chunk.offset); - dls_chunk.offset.QuadPart -= 12; - if (FAILED(dmobj_parsedescriptor(stream, &dls_chunk, &This->dmobj.desc, - DMUS_OBJ_NAME_INFO|DMUS_OBJ_VERSION|DMUS_OBJ_OBJECT|DMUS_OBJ_GUID_DLID))) + if ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { - liMove.QuadPart = StreamSize; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */ - return E_FAIL; - } - stream_reset_chunk_data(stream, &dls_chunk); - - TRACE_(dmfile)(": collection form\n"); - do { - IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL); - StreamCount += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = %#04lx)", debugstr_fourcc(chunk.fccID), chunk.dwSize); - switch (chunk.fccID) { - case FOURCC_COLH: { - TRACE_(dmfile)(": collection header chunk\n"); - This->pHeader = calloc(1, chunk.dwSize); - IStream_Read(stream, This->pHeader, chunk.dwSize, NULL); - break; - } - case FOURCC_PTBL: { - struct chunk_entry ptbl_chunk = {.id = FOURCC_LIST, .size = chunk.dwSize, .type = chunk.fccID}; - TRACE_(dmfile)(": pool table chunk\n"); - liMove.QuadPart = 0; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &ptbl_chunk.offset); - ptbl_chunk.offset.QuadPart -= 12; - parse_ptbl_chunk(This, stream, &ptbl_chunk); - stream_skip_chunk(stream, &ptbl_chunk); - break; - } - case FOURCC_LIST: { - IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL); - TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID)); - switch (chunk.fccID) { - case FOURCC_WVPL: { - TRACE_(dmfile)(": wave pool list (mark & skip)\n"); - liMove.QuadPart = chunk.dwSize - sizeof(FOURCC); - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); - break; - } - case FOURCC_LINS: { - struct chunk_entry lins_chunk = {.id = FOURCC_LIST, .size = chunk.dwSize, .type = chunk.fccID}; - TRACE_(dmfile)(": instruments list\n"); - liMove.QuadPart = 0; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &lins_chunk.offset); - lins_chunk.offset.QuadPart -= 12; - parse_lins_list(This, stream, &lins_chunk); - stream_skip_chunk(stream, &lins_chunk); - break; - } - default: { - TRACE_(dmfile)(": unknown (skipping)\n"); - liMove.QuadPart = chunk.dwSize - sizeof(FOURCC); - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - break; - } - default: { - TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); - liMove.QuadPart = chunk.dwSize; - IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - TRACE_(dmfile)(": StreamCount = %ld < StreamSize = %ld\n", StreamCount, StreamSize); - } while (StreamCount < StreamSize); - - TRACE_(dmfile)(": reading finished\n"); + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case MAKE_IDTYPE(FOURCC_RIFF, FOURCC_DLS): + hr = parse_dls_chunk(This, stream, &chunk); + break; + default: + WARN("Invalid collection chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + hr = DMUS_E_UNSUPPORTED_STREAM; + break; + } + } - /* DEBUG: dumps whole collection object tree: */ - if (TRACE_ON(dmusic)) + if (SUCCEEDED(hr) && TRACE_ON(dmusic)) { struct instrument_entry *entry; int i = 0; @@ -396,13 +345,14 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, dump_DMUS_OBJECTDESC(&This->dmobj.desc); TRACE(" - Collection header:\n"); - TRACE(" - cInstruments: %ld\n", This->pHeader->cInstruments); + TRACE(" - cInstruments: %ld\n", This->header.cInstruments); TRACE(" - Instruments:\n"); LIST_FOR_EACH_ENTRY(entry, &This->instruments, struct instrument_entry, entry) TRACE(" - Instrument[%i]: %p\n", i++, entry->instrument); } + stream_skip_chunk(stream, &chunk); return S_OK; } diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 3e184fa86da..b160b0031b6 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -195,12 +195,6 @@ static inline struct instrument *impl_from_IDirectMusicInstrument(IDirectMusicIn */ void dmusic_remove_port(IDirectMusic8Impl *dmusic, IDirectMusicPort *port); -/* for simpler reading */ -typedef struct _DMUS_PRIVATE_CHUNK { - FOURCC fccID; /* FOURCC ID of the chunk */ - DWORD dwSize; /* size of the chunk */ -} DMUS_PRIVATE_CHUNK, *LPDMUS_PRIVATE_CHUNK; - /* used for generic dumping (copied from ddraw) */ typedef struct { DWORD val; From 809ba6256c72ad3017f045e04b412ab7166f7bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 12 Sep 2023 09:50:27 +0200 Subject: [PATCH 2519/2777] dmusic: Parse instrument name from INFO list. (cherry picked from commit 3fa399b145408b1aecf1d00e001f12a6191d32ac) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 11 +++-------- dlls/dmusic/dmusic_private.h | 5 +---- dlls/dmusic/instrument.c | 17 +++++++++++------ 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index f26806a1afb..cbcdabb37c1 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -25,6 +25,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmusic); struct instrument_entry { struct list entry; + DMUS_OBJECTDESC desc; IDirectMusicInstrument *instrument; }; @@ -156,13 +157,7 @@ static HRESULT WINAPI collection_EnumInstrument(IDirectMusicCollection *iface, { if (index--) continue; if (FAILED(hr = IDirectMusicInstrument_GetPatch(entry->instrument, patch))) return hr; - if (name) - { - struct instrument *instrument = impl_from_IDirectMusicInstrument(entry->instrument); - DWORD length = min(lstrlenW(instrument->wszName), name_length - 1); - memcpy(name, instrument->wszName, length * sizeof(WCHAR)); - name[length] = '\0'; - } + if (name) lstrcpynW(name, entry->desc.wszName, name_length); return S_OK; } @@ -190,7 +185,7 @@ static HRESULT parse_lins_list(struct collection *This, IStream *stream, struct { case MAKE_IDTYPE(FOURCC_LIST, FOURCC_INS): if (!(entry = malloc(sizeof(*entry)))) return E_OUTOFMEMORY; - hr = instrument_create_from_chunk(stream, &chunk, &entry->instrument); + hr = instrument_create_from_chunk(stream, &chunk, &entry->desc, &entry->instrument); if (SUCCEEDED(hr)) list_add_tail(&This->instruments, &entry->entry); else free(entry); break; diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index b160b0031b6..73b872c4f9f 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -101,7 +101,7 @@ extern HRESULT DMUSIC_CreateReferenceClockImpl (LPCGUID lpcGUID, LPVOID* ppobj, extern HRESULT download_create(DWORD size, IDirectMusicDownload **ret_iface); extern HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent, - IDirectMusicInstrument **ret_iface); + DMUS_OBJECTDESC *desc, IDirectMusicInstrument **ret_iface); /***************************************************************************** * IDirectMusic8Impl implementation structure @@ -176,10 +176,7 @@ struct instrument IDirectMusicInstrument IDirectMusicInstrument_iface; LONG ref; - GUID id; INSTHEADER header; - WCHAR wszName[DMUS_MAX_NAME]; - /* instrument data */ struct list articulations; struct list regions; diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index aacbe6e8c88..dbbfd6f0c78 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -266,11 +266,16 @@ static HRESULT parse_lrgn_list(struct instrument *This, IStream *stream, struct return hr; } -static HRESULT parse_ins_chunk(struct instrument *This, IStream *stream, struct chunk_entry *parent) +static HRESULT parse_ins_chunk(struct instrument *This, IStream *stream, struct chunk_entry *parent, + DMUS_OBJECTDESC *desc) { struct chunk_entry chunk = {.parent = parent}; HRESULT hr; + if (FAILED(hr = dmobj_parsedescriptor(stream, parent, desc, DMUS_OBJ_NAME_INFO|DMUS_OBJ_GUID_DLID)) + || FAILED(hr = stream_reset_chunk_data(stream, parent))) + return hr; + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { switch (MAKE_IDTYPE(chunk.id, chunk.type)) @@ -280,7 +285,8 @@ static HRESULT parse_ins_chunk(struct instrument *This, IStream *stream, struct break; case FOURCC_DLID: - hr = stream_chunk_get_data(stream, &chunk, &This->id, sizeof(This->id)); + case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_INFO_LIST): + /* already parsed by dmobj_parsedescriptor */ break; case MAKE_IDTYPE(FOURCC_LIST, FOURCC_LRGN): @@ -303,7 +309,7 @@ static HRESULT parse_ins_chunk(struct instrument *This, IStream *stream, struct } HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent, - IDirectMusicInstrument **ret_iface) + DMUS_OBJECTDESC *desc, IDirectMusicInstrument **ret_iface) { IDirectMusicInstrument *iface; struct instrument *This; @@ -314,7 +320,7 @@ HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent if (FAILED(hr = instrument_create(&iface))) return hr; This = impl_from_IDirectMusicInstrument(iface); - if (FAILED(hr = parse_ins_chunk(This, stream, parent))) + if (FAILED(hr = parse_ins_chunk(This, stream, parent, desc))) { IDirectMusicInstrument_Release(iface); return DMUS_E_UNSUPPORTED_STREAM; @@ -323,14 +329,13 @@ HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent if (TRACE_ON(dmusic)) { TRACE("Created DirectMusicInstrument (%p) ***\n", This); - if (!IsEqualGUID(&This->id, &GUID_NULL)) - TRACE(" - GUID = %s\n", debugstr_dmguid(&This->id)); TRACE(" - Instrument header:\n"); TRACE(" - cRegions: %ld\n", This->header.cRegions); TRACE(" - Locale:\n"); TRACE(" - ulBank: %ld\n", This->header.Locale.ulBank); TRACE(" - ulInstrument: %ld\n", This->header.Locale.ulInstrument); TRACE(" => dwPatch: %ld\n", MIDILOCALE2Patch(&This->header.Locale)); + if (desc->dwValidData & DMUS_OBJ_OBJECT) TRACE(" - guid: %s\n", debugstr_dmguid(&desc->guidObject)); } *ret_iface = iface; From 0d77823997c1df9e3c77a4007c149bf75b245d58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 12 Sep 2023 09:53:37 +0200 Subject: [PATCH 2520/2777] dmusic: Add more parsed instruments traces. (cherry picked from commit f71315c8494575698634062cfad4f5d84fd230a1) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/instrument.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index dbbfd6f0c78..025bba940e5 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -328,14 +328,38 @@ HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent if (TRACE_ON(dmusic)) { - TRACE("Created DirectMusicInstrument (%p) ***\n", This); - TRACE(" - Instrument header:\n"); - TRACE(" - cRegions: %ld\n", This->header.cRegions); - TRACE(" - Locale:\n"); - TRACE(" - ulBank: %ld\n", This->header.Locale.ulBank); - TRACE(" - ulInstrument: %ld\n", This->header.Locale.ulInstrument); - TRACE(" => dwPatch: %ld\n", MIDILOCALE2Patch(&This->header.Locale)); + struct region *region; + UINT i; + + TRACE("Created DirectMusicInstrument %p\n", This); + TRACE(" - header:\n"); + TRACE(" - regions: %ld\n", This->header.cRegions); + TRACE(" - locale: {bank: %#lx, instrument: %#lx} (patch %#lx)\n", + This->header.Locale.ulBank, This->header.Locale.ulInstrument, + MIDILOCALE2Patch(&This->header.Locale)); if (desc->dwValidData & DMUS_OBJ_OBJECT) TRACE(" - guid: %s\n", debugstr_dmguid(&desc->guidObject)); + if (desc->dwValidData & DMUS_OBJ_NAME) TRACE(" - name: %s\n", debugstr_w(desc->wszName)); + + TRACE(" - regions:\n"); + LIST_FOR_EACH_ENTRY(region, &This->regions, struct region, entry) + { + TRACE(" - region:\n"); + TRACE(" - header: {key: %u - %u, vel: %u - %u, options: %#x, group: %#x}\n", + region->header.RangeKey.usLow, region->header.RangeKey.usHigh, + region->header.RangeVelocity.usLow, region->header.RangeVelocity.usHigh, + region->header.fusOptions, region->header.usKeyGroup); + TRACE(" - wave_link: {options: %#x, group: %u, channel: %lu, index: %lu}\n", + region->wave_link.fusOptions, region->wave_link.usPhaseGroup, + region->wave_link.ulChannel, region->wave_link.ulTableIndex); + TRACE(" - wave_sample: {size: %lu, unity_note: %u, fine_tune: %d, attenuation: %ld, options: %#lx, loops: %lu}\n", + region->wave_sample.cbSize, region->wave_sample.usUnityNote, + region->wave_sample.sFineTune, region->wave_sample.lAttenuation, + region->wave_sample.fulOptions, region->wave_sample.cSampleLoops); + for (i = 0; i < region->wave_sample.cSampleLoops; i++) + TRACE(" - wave_loop[%u]: {size: %lu, type: %lu, start: %lu, length: %lu}\n", i, + region->wave_loop.cbSize, region->wave_loop.ulType, + region->wave_loop.ulStart, region->wave_loop.ulLength); + } } *ret_iface = iface; From 129a2b97d54aca5c25ee61bf91599d6f1432ceb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 15 Sep 2023 11:27:46 +0200 Subject: [PATCH 2521/2777] dmusic: Avoid swallowing collection Load failures. (cherry picked from commit 0cb208cec2f03cef0e42d98f238fe126abc941d0) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index cbcdabb37c1..5d6b533d649 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -331,7 +331,9 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream *str } } - if (SUCCEEDED(hr) && TRACE_ON(dmusic)) + if (FAILED(hr)) return hr; + + if (TRACE_ON(dmusic)) { struct instrument_entry *entry; int i = 0; From f2a3616e4485064b8622a1320b7378c829a9812f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 9 Sep 2023 14:06:32 +0200 Subject: [PATCH 2522/2777] dmusic: Rewrite downloading instrument to port. (cherry picked from commit 120a743c96c9632eb37ff6b8f5ccfb199ffb764b) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/dmusic_private.h | 43 +-------- dlls/dmusic/instrument.c | 174 +++++++++++++++++++++++++++++++++++ dlls/dmusic/port.c | 172 +--------------------------------- 3 files changed, 180 insertions(+), 209 deletions(-) diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 73b872c4f9f..9eac6feaa2c 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -51,7 +51,6 @@ */ typedef struct IDirectMusic8Impl IDirectMusic8Impl; typedef struct IDirectMusicBufferImpl IDirectMusicBufferImpl; -typedef struct IDirectMusicDownloadedInstrumentImpl IDirectMusicDownloadedInstrumentImpl; typedef struct IReferenceClockImpl IReferenceClockImpl; /***************************************************************************** @@ -76,16 +75,6 @@ typedef struct port_info { ULONG device; } port_info; -struct region -{ - struct list entry; - RGNHEADER header; - WAVELINK wave_link; - WSMPL wave_sample; - WLOOP wave_loop; - BOOL loop_present; -}; - /***************************************************************************** * ClassFactory */ @@ -102,6 +91,9 @@ extern HRESULT download_create(DWORD size, IDirectMusicDownload **ret_iface); extern HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent, DMUS_OBJECTDESC *desc, IDirectMusicInstrument **ret_iface); +extern HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicPortDownload *port, + IDirectMusicDownloadedInstrument **downloaded); +extern HRESULT instrument_unload_from_port(IDirectMusicDownloadedInstrument *iface, IDirectMusicPortDownload *port); /***************************************************************************** * IDirectMusic8Impl implementation structure @@ -133,19 +125,6 @@ struct IDirectMusicBufferImpl { REFERENCE_TIME start_time; }; -/***************************************************************************** - * IDirectMusicDownloadedInstrumentImpl implementation structure - */ -struct IDirectMusicDownloadedInstrumentImpl { - /* IUnknown fields */ - IDirectMusicDownloadedInstrument IDirectMusicDownloadedInstrument_iface; - LONG ref; - - /* IDirectMusicDownloadedInstrumentImpl fields */ - BOOL downloaded; - void *data; -}; - /** Internal factory */ extern HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_params, DMUS_PORTCAPS *port_caps, IDirectMusicPort **port); @@ -171,22 +150,6 @@ typedef struct _DMUS_PRIVATE_POOLCUE { struct list entry; /* for listing elements */ } DMUS_PRIVATE_POOLCUE, *LPDMUS_PRIVATE_POOLCUE; -struct instrument -{ - IDirectMusicInstrument IDirectMusicInstrument_iface; - LONG ref; - - INSTHEADER header; - - struct list articulations; - struct list regions; -}; - -static inline struct instrument *impl_from_IDirectMusicInstrument(IDirectMusicInstrument *iface) -{ - return CONTAINING_RECORD(iface, struct instrument, IDirectMusicInstrument_iface); -} - /***************************************************************************** * Misc. */ diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index 025bba940e5..24b3c0305f8 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -33,6 +33,33 @@ struct articulation C_ASSERT(sizeof(struct articulation) == offsetof(struct articulation, connections[0])); +struct region +{ + struct list entry; + RGNHEADER header; + WAVELINK wave_link; + WSMPL wave_sample; + WLOOP wave_loop; + BOOL loop_present; +}; + +struct instrument +{ + IDirectMusicInstrument IDirectMusicInstrument_iface; + IDirectMusicDownloadedInstrument IDirectMusicDownloadedInstrument_iface; + LONG ref; + + INSTHEADER header; + IDirectMusicDownload *download; + struct list articulations; + struct list regions; +}; + +static inline struct instrument *impl_from_IDirectMusicInstrument(IDirectMusicInstrument *iface) +{ + return CONTAINING_RECORD(iface, struct instrument, IDirectMusicInstrument_iface); +} + static HRESULT WINAPI instrument_QueryInterface(LPDIRECTMUSICINSTRUMENT iface, REFIID riid, LPVOID *ret_iface) { TRACE("(%p)->(%s, %p)\n", iface, debugstr_dmguid(riid), ret_iface); @@ -134,6 +161,46 @@ static const IDirectMusicInstrumentVtbl instrument_vtbl = instrument_SetPatch, }; +static inline struct instrument* impl_from_IDirectMusicDownloadedInstrument(IDirectMusicDownloadedInstrument *iface) +{ + return CONTAINING_RECORD(iface, struct instrument, IDirectMusicDownloadedInstrument_iface); +} + +static HRESULT WINAPI downloaded_instrument_QueryInterface(IDirectMusicDownloadedInstrument *iface, REFIID riid, VOID **ret_iface) +{ + TRACE("(%p, %s, %p)\n", iface, debugstr_dmguid(riid), ret_iface); + + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicDownloadedInstrument)) + { + IDirectMusicDownloadedInstrument_AddRef(iface); + *ret_iface = iface; + return S_OK; + } + + WARN("(%p, %s, %p): not found\n", iface, debugstr_dmguid(riid), ret_iface); + + return E_NOINTERFACE; +} + +static ULONG WINAPI downloaded_instrument_AddRef(IDirectMusicDownloadedInstrument *iface) +{ + struct instrument *This = impl_from_IDirectMusicDownloadedInstrument(iface); + return IDirectMusicInstrument_AddRef(&This->IDirectMusicInstrument_iface); +} + +static ULONG WINAPI downloaded_instrument_Release(IDirectMusicDownloadedInstrument *iface) +{ + struct instrument *This = impl_from_IDirectMusicDownloadedInstrument(iface); + return IDirectMusicInstrument_Release(&This->IDirectMusicInstrument_iface); +} + +static const IDirectMusicDownloadedInstrumentVtbl downloaded_instrument_vtbl = +{ + downloaded_instrument_QueryInterface, + downloaded_instrument_AddRef, + downloaded_instrument_Release, +}; + static HRESULT instrument_create(IDirectMusicInstrument **ret_iface) { struct instrument *instrument; @@ -141,6 +208,7 @@ static HRESULT instrument_create(IDirectMusicInstrument **ret_iface) *ret_iface = NULL; if (!(instrument = calloc(1, sizeof(*instrument)))) return E_OUTOFMEMORY; instrument->IDirectMusicInstrument_iface.lpVtbl = &instrument_vtbl; + instrument->IDirectMusicDownloadedInstrument_iface.lpVtbl = &downloaded_instrument_vtbl; instrument->ref = 1; list_init(&instrument->articulations); list_init(&instrument->regions); @@ -365,3 +433,109 @@ HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent *ret_iface = iface; return S_OK; } + +struct download_buffer +{ + DMUS_DOWNLOADINFO info; + ULONG offsets[]; +}; + +C_ASSERT(sizeof(struct download_buffer) == offsetof(struct download_buffer, offsets[0])); + +HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicPortDownload *port, + IDirectMusicDownloadedInstrument **downloaded) +{ + struct instrument *This = impl_from_IDirectMusicInstrument(iface); + struct download_buffer *buffer; + IDirectMusicDownload *download; + DWORD size, offset_count; + struct region *region; + HRESULT hr; + + if (This->download) goto done; + + size = sizeof(DMUS_DOWNLOADINFO); + size += sizeof(ULONG) + sizeof(DMUS_INSTRUMENT); + offset_count = 1; + + LIST_FOR_EACH_ENTRY(region, &This->regions, struct region, entry) + { + size += sizeof(ULONG) + sizeof(DMUS_REGION); + offset_count++; + } + + if (FAILED(hr = IDirectMusicPortDownload_AllocateBuffer(port, size, &download))) return hr; + + if (SUCCEEDED(hr = IDirectMusicDownload_GetBuffer(download, (void **)&buffer, &size)) + && SUCCEEDED(hr = IDirectMusicPortDownload_GetDLId(port, &buffer->info.dwDLId, 1))) + { + BYTE *ptr = (BYTE *)&buffer->offsets[offset_count]; + DMUS_INSTRUMENT *dmus_instrument; + DMUS_REGION *dmus_region = NULL; + UINT index = 0; + + buffer->info.dwDLType = DMUS_DOWNLOADINFO_INSTRUMENT2; + buffer->info.dwNumOffsetTableEntries = offset_count; + buffer->info.cbSize = size; + + buffer->offsets[index++] = ptr - (BYTE *)buffer; + dmus_instrument = (DMUS_INSTRUMENT *)ptr; + ptr += sizeof(DMUS_INSTRUMENT); + + dmus_instrument->ulPatch = MIDILOCALE2Patch(&This->header.Locale); + dmus_instrument->ulFirstRegionIdx = 0; + dmus_instrument->ulCopyrightIdx = 0; + dmus_instrument->ulGlobalArtIdx = 0; + + LIST_FOR_EACH_ENTRY(region, &This->regions, struct region, entry) + { + if (dmus_region) dmus_region->ulNextRegionIdx = index; + else dmus_instrument->ulFirstRegionIdx = index; + + buffer->offsets[index++] = ptr - (BYTE *)buffer; + dmus_region = (DMUS_REGION *)ptr; + ptr += sizeof(DMUS_REGION); + + dmus_region->RangeKey = region->header.RangeKey; + dmus_region->RangeVelocity = region->header.RangeVelocity; + dmus_region->fusOptions = region->header.fusOptions; + dmus_region->usKeyGroup = region->header.usKeyGroup; + dmus_region->ulRegionArtIdx = 0; + dmus_region->ulNextRegionIdx = 0; + dmus_region->ulFirstExtCkIdx = 0; + dmus_region->WaveLink = region->wave_link; + dmus_region->WSMP = region->wave_sample; + dmus_region->WLOOP[0] = region->wave_loop; + } + + if (FAILED(hr = IDirectMusicPortDownload_Download(port, download))) goto failed; + } + + This->download = download; + +done: + *downloaded = &This->IDirectMusicDownloadedInstrument_iface; + IDirectMusicDownloadedInstrument_AddRef(*downloaded); + return S_OK; + +failed: + WARN("Failed to download instrument to port, hr %#lx\n", hr); + IDirectMusicDownload_Release(download); + return hr; +} + +HRESULT instrument_unload_from_port(IDirectMusicDownloadedInstrument *iface, IDirectMusicPortDownload *port) +{ + struct instrument *This = impl_from_IDirectMusicDownloadedInstrument(iface); + HRESULT hr; + + if (!This->download) return DMUS_E_NOT_DOWNLOADED_TO_PORT; + + if (FAILED(hr = IDirectMusicPortDownload_Unload(port, This->download))) + WARN("Failed to unload instrument download buffer, hr %#lx\n", hr); + + IDirectMusicDownload_Release(This->download); + This->download = NULL; + + return hr; +} diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index 7e3fa5a67eb..0eff1c5cb02 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -52,11 +52,6 @@ struct synth_port { DWORD next_dlid; }; -static inline IDirectMusicDownloadedInstrumentImpl* impl_from_IDirectMusicDownloadedInstrument(IDirectMusicDownloadedInstrument *iface) -{ - return CONTAINING_RECORD(iface, IDirectMusicDownloadedInstrumentImpl, IDirectMusicDownloadedInstrument_iface); -} - static inline struct synth_port *synth_from_IDirectMusicPort(IDirectMusicPort *iface) { return CONTAINING_RECORD(iface, struct synth_port, IDirectMusicPort_iface); @@ -77,83 +72,6 @@ static inline struct synth_port *synth_from_IKsControl(IKsControl *iface) return CONTAINING_RECORD(iface, struct synth_port, IKsControl_iface); } -/* IDirectMusicDownloadedInstrument IUnknown part follows: */ -static HRESULT WINAPI IDirectMusicDownloadedInstrumentImpl_QueryInterface(IDirectMusicDownloadedInstrument *iface, REFIID riid, VOID **ret_iface) -{ - TRACE("(%p, %s, %p)\n", iface, debugstr_dmguid(riid), ret_iface); - - if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicDownloadedInstrument)) - { - IDirectMusicDownloadedInstrument_AddRef(iface); - *ret_iface = iface; - return S_OK; - } - - WARN("(%p, %s, %p): not found\n", iface, debugstr_dmguid(riid), ret_iface); - - return E_NOINTERFACE; -} - -static ULONG WINAPI IDirectMusicDownloadedInstrumentImpl_AddRef(LPDIRECTMUSICDOWNLOADEDINSTRUMENT iface) -{ - IDirectMusicDownloadedInstrumentImpl *This = impl_from_IDirectMusicDownloadedInstrument(iface); - ULONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p): new ref = %lu\n", iface, ref); - - return ref; -} - -static ULONG WINAPI IDirectMusicDownloadedInstrumentImpl_Release(LPDIRECTMUSICDOWNLOADEDINSTRUMENT iface) -{ - IDirectMusicDownloadedInstrumentImpl *This = impl_from_IDirectMusicDownloadedInstrument(iface); - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p): new ref = %lu\n", iface, ref); - - if (!ref) - { - free(This->data); - free(This); - } - - return ref; -} - -static const IDirectMusicDownloadedInstrumentVtbl DirectMusicDownloadedInstrument_Vtbl = { - IDirectMusicDownloadedInstrumentImpl_QueryInterface, - IDirectMusicDownloadedInstrumentImpl_AddRef, - IDirectMusicDownloadedInstrumentImpl_Release -}; - -static inline IDirectMusicDownloadedInstrumentImpl* unsafe_impl_from_IDirectMusicDownloadedInstrument(IDirectMusicDownloadedInstrument *iface) -{ - if (!iface) - return NULL; - assert(iface->lpVtbl == &DirectMusicDownloadedInstrument_Vtbl); - - return impl_from_IDirectMusicDownloadedInstrument(iface); -} - -static HRESULT DMUSIC_CreateDirectMusicDownloadedInstrumentImpl(IDirectMusicDownloadedInstrument **instrument) -{ - IDirectMusicDownloadedInstrumentImpl *object; - - object = calloc(1, sizeof(*object)); - if (!object) - { - *instrument = NULL; - return E_OUTOFMEMORY; - } - - object->IDirectMusicDownloadedInstrument_iface.lpVtbl = &DirectMusicDownloadedInstrument_Vtbl; - object->ref = 1; - - *instrument = &object->IDirectMusicDownloadedInstrument_iface; - - return S_OK; -} - static HRESULT WINAPI synth_port_QueryInterface(IDirectMusicPort *iface, REFIID riid, void **ret_iface) { struct synth_port *This = synth_from_IDirectMusicPort(iface); @@ -265,110 +183,26 @@ static HRESULT WINAPI synth_port_DownloadInstrument(IDirectMusicPort *iface, IDi IDirectMusicDownloadedInstrument **downloaded_instrument, DMUS_NOTERANGE *note_ranges, DWORD num_note_ranges) { struct synth_port *This = synth_from_IDirectMusicPort(iface); - struct instrument *instrument_object; - struct region *instrument_region; - HRESULT ret; - BOOL on_heap; - HANDLE download; - DMUS_DOWNLOADINFO *info; - DMUS_OFFSETTABLE *offset_table; - DMUS_INSTRUMENT *instrument_info; - BYTE *data; - ULONG offset; - ULONG nb_regions; - ULONG size; - ULONG i; TRACE("(%p, %p, %p, %p, %ld)\n", iface, instrument, downloaded_instrument, note_ranges, num_note_ranges); if (!instrument || !downloaded_instrument || (num_note_ranges && !note_ranges)) return E_POINTER; - instrument_object = impl_from_IDirectMusicInstrument(instrument); - - nb_regions = instrument_object->header.cRegions; - size = sizeof(DMUS_DOWNLOADINFO) + sizeof(ULONG) * (1 + nb_regions) + sizeof(DMUS_INSTRUMENT) + sizeof(DMUS_REGION) * nb_regions; - - data = malloc(size); - if (!data) - return E_OUTOFMEMORY; - - info = (DMUS_DOWNLOADINFO*)data; - offset_table = (DMUS_OFFSETTABLE*)(data + sizeof(DMUS_DOWNLOADINFO)); - offset = sizeof(DMUS_DOWNLOADINFO) + sizeof(ULONG) * (1 + nb_regions); - - info->dwDLType = DMUS_DOWNLOADINFO_INSTRUMENT2; - info->dwDLId = 0; - info->dwNumOffsetTableEntries = 1 + instrument_object->header.cRegions; - info->cbSize = size; - - offset_table->ulOffsetTable[0] = offset; - instrument_info = (DMUS_INSTRUMENT*)(data + offset); - offset += sizeof(DMUS_INSTRUMENT); - instrument_info->ulPatch = MIDILOCALE2Patch(&instrument_object->header.Locale); - instrument_info->ulFirstRegionIdx = 1; - instrument_info->ulGlobalArtIdx = 0; /* FIXME */ - instrument_info->ulFirstExtCkIdx = 0; /* FIXME */ - instrument_info->ulCopyrightIdx = 0; /* FIXME */ - instrument_info->ulFlags = 0; /* FIXME */ - - i = 0; - LIST_FOR_EACH_ENTRY(instrument_region, &instrument_object->regions, struct region, entry) - { - DMUS_REGION *region = (DMUS_REGION*)(data + offset); - - offset_table->ulOffsetTable[1 + i] = offset; - offset += sizeof(DMUS_REGION); - region->RangeKey = instrument_region->header.RangeKey; - region->RangeVelocity = instrument_region->header.RangeVelocity; - region->fusOptions = instrument_region->header.fusOptions; - region->usKeyGroup = instrument_region->header.usKeyGroup; - region->ulRegionArtIdx = 0; /* FIXME */ - region->ulNextRegionIdx = i != (nb_regions - 1) ? (i + 2) : 0; - region->ulFirstExtCkIdx = 0; /* FIXME */ - region->WaveLink = instrument_region->wave_link; - region->WSMP = instrument_region->wave_sample; - region->WLOOP[0] = instrument_region->wave_loop; - i++; - } - - ret = IDirectMusicSynth8_Download(This->synth, &download, (void*)data, &on_heap); - - if (SUCCEEDED(ret)) - ret = DMUSIC_CreateDirectMusicDownloadedInstrumentImpl(downloaded_instrument); - - if (SUCCEEDED(ret)) - { - IDirectMusicDownloadedInstrumentImpl *downloaded_object = impl_from_IDirectMusicDownloadedInstrument(*downloaded_instrument); - - downloaded_object->data = data; - downloaded_object->downloaded = TRUE; - } - - *downloaded_instrument = NULL; - free(data); - - return E_FAIL; + return instrument_download_to_port(instrument, &This->IDirectMusicPortDownload_iface, downloaded_instrument); } static HRESULT WINAPI synth_port_UnloadInstrument(IDirectMusicPort *iface, IDirectMusicDownloadedInstrument *downloaded_instrument) { - IDirectMusicDownloadedInstrumentImpl *downloaded_object = unsafe_impl_from_IDirectMusicDownloadedInstrument(downloaded_instrument); + struct synth_port *This = synth_from_IDirectMusicPort(iface); TRACE("(%p, %p)\n", iface, downloaded_instrument); if (!downloaded_instrument) return E_POINTER; - if (!downloaded_object->downloaded) - return DMUS_E_NOT_DOWNLOADED_TO_PORT; - - free(downloaded_object->data); - downloaded_object->data = NULL; - downloaded_object->downloaded = FALSE; - - return S_OK; + return instrument_unload_from_port(downloaded_instrument, &This->IDirectMusicPortDownload_iface); } static HRESULT WINAPI synth_port_GetLatencyClock(IDirectMusicPort *iface, IReferenceClock **clock) From 1f52551b014c5c8539c3866346c018edf4a3f431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 31 Aug 2023 13:20:17 +0200 Subject: [PATCH 2523/2777] dmusic: Parse collection wave table. (cherry picked from commit 2f5608efd1e4e8be0a67f69d5d7885ea4b2603b3) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 60 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 5d6b533d649..3bcca3c4b8a 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -37,6 +37,12 @@ struct pool C_ASSERT(sizeof(struct pool) == offsetof(struct pool, cues[0])); +struct wave_entry +{ + struct list entry; + DWORD offset; +}; + struct collection { IDirectMusicCollection IDirectMusicCollection_iface; @@ -46,6 +52,7 @@ struct collection DLSHEADER header; struct pool *pool; struct list instruments; + struct list waves; }; static inline struct collection *impl_from_IDirectMusicCollection(IDirectMusicCollection *iface) @@ -103,6 +110,7 @@ static ULONG WINAPI collection_Release(IDirectMusicCollection *iface) if (!ref) { struct instrument_entry *instrument_entry; + struct wave_entry *wave_entry; void *next; LIST_FOR_EACH_ENTRY_SAFE(instrument_entry, next, &This->instruments, struct instrument_entry, entry) @@ -112,6 +120,12 @@ static ULONG WINAPI collection_Release(IDirectMusicCollection *iface) free(instrument_entry); } + LIST_FOR_EACH_ENTRY_SAFE(wave_entry, next, &This->waves, struct wave_entry, entry) + { + list_remove(&wave_entry->entry); + free(wave_entry); + } + free(This); } @@ -201,6 +215,33 @@ static HRESULT parse_lins_list(struct collection *This, IStream *stream, struct return hr; } +static HRESULT parse_wvpl_list(struct collection *This, IStream *stream, struct chunk_entry *parent) +{ + struct chunk_entry chunk = {.parent = parent}; + struct wave_entry *entry; + HRESULT hr; + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case MAKE_IDTYPE(FOURCC_LIST, FOURCC_wave): + if (!(entry = malloc(sizeof(*entry)))) return E_OUTOFMEMORY; + entry->offset = chunk.offset.QuadPart - parent->offset.QuadPart - 12; + list_add_tail(&This->waves, &entry->entry); + break; + + default: + FIXME("Skipping unknown chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; + } + + return hr; +} + static HRESULT parse_ptbl_chunk(struct collection *This, IStream *stream, struct chunk_entry *chunk) { struct pool *pool; @@ -256,6 +297,10 @@ static HRESULT parse_dls_chunk(struct collection *This, IStream *stream, struct hr = parse_lins_list(This, stream, &chunk); break; + case MAKE_IDTYPE(FOURCC_LIST, FOURCC_WVPL): + hr = parse_wvpl_list(This, stream, &chunk); + break; + default: FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); break; @@ -336,6 +381,7 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream *str if (TRACE_ON(dmusic)) { struct instrument_entry *entry; + struct wave_entry *wave_entry; int i = 0; TRACE("*** IDirectMusicCollection (%p) ***\n", &This->IDirectMusicCollection_iface); @@ -346,7 +392,18 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream *str TRACE(" - Instruments:\n"); LIST_FOR_EACH_ENTRY(entry, &This->instruments, struct instrument_entry, entry) - TRACE(" - Instrument[%i]: %p\n", i++, entry->instrument); + { + TRACE(" - Instrument[%i]: %p\n", i, entry->instrument); + i++; + } + + TRACE(" - cues: size %lu\n", This->pool->table.cbSize); + for (i = 0; i < This->pool->table.cCues; i++) + TRACE(" - index: %u, offset: %lu\n", i, This->pool->cues[i].ulOffset); + + TRACE(" - waves:\n"); + LIST_FOR_EACH_ENTRY(wave_entry, &This->waves, struct wave_entry, entry) + TRACE(" - offset: %lu\n", wave_entry->offset); } stream_skip_chunk(stream, &chunk); @@ -378,6 +435,7 @@ HRESULT collection_create(IUnknown **ret_iface) collection->dmobj.IDirectMusicObject_iface.lpVtbl = &collection_object_vtbl; collection->dmobj.IPersistStream_iface.lpVtbl = &collection_stream_vtbl; list_init(&collection->instruments); + list_init(&collection->waves); TRACE("Created DirectMusicCollection %p\n", collection); *ret_iface = (IUnknown *)&collection->IDirectMusicCollection_iface; From a7be1447c32c6e480c6130ed1f2928cc801012a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 15 Sep 2023 09:00:54 +0200 Subject: [PATCH 2524/2777] dmusic: Parse collection wave lists. (cherry picked from commit 82d1794cd49d1aedb652f7c6a07886d5178b5156) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/Makefile.in | 3 +- dlls/dmusic/collection.c | 14 ++- dlls/dmusic/dmusic_private.h | 2 + dlls/dmusic/wave.c | 214 +++++++++++++++++++++++++++++++++++ 4 files changed, 228 insertions(+), 5 deletions(-) create mode 100644 dlls/dmusic/wave.c diff --git a/dlls/dmusic/Makefile.in b/dlls/dmusic/Makefile.in index a8955a2ab42..d9438af0d18 100644 --- a/dlls/dmusic/Makefile.in +++ b/dlls/dmusic/Makefile.in @@ -10,7 +10,8 @@ C_SRCS = \ dmusic_main.c \ download.c \ instrument.c \ - port.c + port.c \ + wave.c IDL_SRCS = dmusic.idl diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 3bcca3c4b8a..1c36f0b202d 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -40,6 +40,7 @@ C_ASSERT(sizeof(struct pool) == offsetof(struct pool, cues[0])); struct wave_entry { struct list entry; + IUnknown *wave; DWORD offset; }; @@ -123,6 +124,7 @@ static ULONG WINAPI collection_Release(IDirectMusicCollection *iface) LIST_FOR_EACH_ENTRY_SAFE(wave_entry, next, &This->waves, struct wave_entry, entry) { list_remove(&wave_entry->entry); + IDirectMusicInstrument_Release(wave_entry->wave); free(wave_entry); } @@ -227,8 +229,12 @@ static HRESULT parse_wvpl_list(struct collection *This, IStream *stream, struct { case MAKE_IDTYPE(FOURCC_LIST, FOURCC_wave): if (!(entry = malloc(sizeof(*entry)))) return E_OUTOFMEMORY; - entry->offset = chunk.offset.QuadPart - parent->offset.QuadPart - 12; - list_add_tail(&This->waves, &entry->entry); + if (FAILED(hr = wave_create_from_chunk(stream, &chunk, &entry->wave))) free(entry); + else + { + entry->offset = chunk.offset.QuadPart - parent->offset.QuadPart - 12; + list_add_tail(&This->waves, &entry->entry); + } break; default: @@ -397,13 +403,13 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream *str i++; } - TRACE(" - cues: size %lu\n", This->pool->table.cbSize); + TRACE(" - cues:\n"); for (i = 0; i < This->pool->table.cCues; i++) TRACE(" - index: %u, offset: %lu\n", i, This->pool->cues[i].ulOffset); TRACE(" - waves:\n"); LIST_FOR_EACH_ENTRY(wave_entry, &This->waves, struct wave_entry, entry) - TRACE(" - offset: %lu\n", wave_entry->offset); + TRACE(" - offset: %lu, wave %p\n", wave_entry->offset, wave_entry->wave); } stream_skip_chunk(stream, &chunk); diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 9eac6feaa2c..84fdc5167a0 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -95,6 +95,8 @@ extern HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirec IDirectMusicDownloadedInstrument **downloaded); extern HRESULT instrument_unload_from_port(IDirectMusicDownloadedInstrument *iface, IDirectMusicPortDownload *port); +extern HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnknown **out); + /***************************************************************************** * IDirectMusic8Impl implementation structure */ diff --git a/dlls/dmusic/wave.c b/dlls/dmusic/wave.c new file mode 100644 index 00000000000..cda895484cb --- /dev/null +++ b/dlls/dmusic/wave.c @@ -0,0 +1,214 @@ +/* + * Copyright 2023 Rémi Bernon for CodeWeavers + * + * This program 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 program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "dmusic_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dmusic); + +struct sample +{ + WSMPL head; + WLOOP loops[]; +}; + +C_ASSERT(sizeof(struct sample) == offsetof(struct sample, loops[0])); + +struct wave +{ + IUnknown IUnknown_iface; + LONG ref; + + struct sample *sample; + WAVEFORMATEX *format; + UINT data_size; + void *data; +}; + +static inline struct wave *impl_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct wave, IUnknown_iface); +} + +static HRESULT WINAPI wave_QueryInterface(IUnknown *iface, REFIID riid, void **ret_iface) +{ + struct wave *This = impl_from_IUnknown(iface); + + TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface); + + if (IsEqualIID(riid, &IID_IUnknown)) + { + *ret_iface = &This->IUnknown_iface; + IUnknown_AddRef(&This->IUnknown_iface); + return S_OK; + } + + WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ret_iface); + *ret_iface = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI wave_AddRef(IUnknown *iface) +{ + struct wave *This = impl_from_IUnknown(iface); + LONG ref = InterlockedIncrement(&This->ref); + TRACE("(%p) ref=%ld\n", This, ref); + return ref; +} + +static ULONG WINAPI wave_Release(IUnknown *iface) +{ + struct wave *This = impl_from_IUnknown(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + if (!ref) + { + free(This->format); + free(This->data); + free(This->sample); + free(This); + } + + return ref; +} + +static const IUnknownVtbl unknown_vtbl = +{ + wave_QueryInterface, + wave_AddRef, + wave_Release, +}; + +static HRESULT wave_create(IUnknown **ret_iface) +{ + struct wave *obj; + + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; + obj->IUnknown_iface.lpVtbl = &unknown_vtbl; + obj->ref = 1; + + *ret_iface = &obj->IUnknown_iface; + return S_OK; +} + +static HRESULT parse_wsmp_chunk(struct wave *This, IStream *stream, struct chunk_entry *chunk) +{ + struct sample *sample; + WSMPL wsmpl; + HRESULT hr; + UINT size; + + if (chunk->size < sizeof(wsmpl)) return E_INVALIDARG; + if (FAILED(hr = stream_read(stream, &wsmpl, sizeof(wsmpl)))) return hr; + if (chunk->size != wsmpl.cbSize + sizeof(WLOOP) * wsmpl.cSampleLoops) return E_INVALIDARG; + if (wsmpl.cbSize != sizeof(wsmpl)) return E_INVALIDARG; + if (wsmpl.cSampleLoops > 1) FIXME("Not implemented: found more than one wave loop\n"); + + size = offsetof(struct sample, loops[wsmpl.cSampleLoops]); + if (!(sample = malloc(size))) return E_OUTOFMEMORY; + sample->head = wsmpl; + + size = sizeof(WLOOP) * wsmpl.cSampleLoops; + if (FAILED(hr = stream_read(stream, sample->loops, size))) free(sample); + else This->sample = sample; + + return hr; +} + +static HRESULT parse_wave_chunk(struct wave *This, IStream *stream, struct chunk_entry *parent) +{ + struct chunk_entry chunk = {.parent = parent}; + HRESULT hr; + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case mmioFOURCC('f','m','t',' '): + if (!(This->format = malloc(chunk.size))) return E_OUTOFMEMORY; + hr = stream_chunk_get_data(stream, &chunk, This->format, chunk.size); + break; + + case mmioFOURCC('d','a','t','a'): + if (!(This->data = malloc(chunk.size))) return E_OUTOFMEMORY; + hr = stream_chunk_get_data(stream, &chunk, This->data, chunk.size); + if (SUCCEEDED(hr)) This->data_size = chunk.size; + break; + + case FOURCC_WSMP: + hr = parse_wsmp_chunk(This, stream, &chunk); + break; + + default: + FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; + } + + return hr; +} + +HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnknown **ret_iface) +{ + struct wave *This; + IUnknown *iface; + HRESULT hr; + + TRACE("(%p, %p, %p)\n", stream, parent, ret_iface); + + if (FAILED(hr = wave_create(&iface))) return hr; + This = impl_from_IUnknown(iface); + + if (FAILED(hr = parse_wave_chunk(This, stream, parent))) + { + IUnknown_Release(iface); + return DMUS_E_UNSUPPORTED_STREAM; + } + + if (TRACE_ON(dmusic)) + { + UINT i; + + TRACE("*** Created DirectMusicWave %p\n", This); + TRACE(" - format: %p\n", This->format); + if (This->format) + { + TRACE(" - wFormatTag: %u\n", This->format->wFormatTag); + TRACE(" - nChannels: %u\n", This->format->nChannels); + TRACE(" - nSamplesPerSec: %lu\n", This->format->nSamplesPerSec); + TRACE(" - nAvgBytesPerSec: %lu\n", This->format->nAvgBytesPerSec); + TRACE(" - nBlockAlign: %u\n", This->format->nBlockAlign); + TRACE(" - wBitsPerSample: %u\n", This->format->wBitsPerSample); + TRACE(" - cbSize: %u\n", This->format->cbSize); + } + TRACE(" - sample: {size: %lu, unity_note: %u, fine_tune: %d, attenuation: %ld, options: %#lx, loops: %lu}\n", + This->sample->head.cbSize, This->sample->head.usUnityNote, + This->sample->head.sFineTune, This->sample->head.lAttenuation, + This->sample->head.fulOptions, This->sample->head.cSampleLoops); + for (i = 0; i < This->sample->head.cSampleLoops; i++) + TRACE(" - loops[%u]: {size: %lu, type: %lu, start: %lu, length: %lu}\n", i, + This->sample->loops[i].cbSize, This->sample->loops[i].ulType, + This->sample->loops[i].ulStart, This->sample->loops[i].ulLength); + } + + *ret_iface = iface; + return S_OK; +} From 0091c0c03470ff707206d13b0c79bf1d4ce91ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 15 Sep 2023 09:21:05 +0200 Subject: [PATCH 2525/2777] dmusic: Keep an internal ref on the instrument's collection. (cherry picked from commit f54b0a5a9bf00de6643b9ea038532c1b2ff4952e) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 21 +++++++++++++++++++-- dlls/dmusic/dmusic_private.h | 6 +++++- dlls/dmusic/instrument.c | 11 +++++++---- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 1c36f0b202d..cfe7589485d 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -48,6 +48,7 @@ struct collection { IDirectMusicCollection IDirectMusicCollection_iface; struct dmobject dmobj; + LONG internal_ref; LONG ref; DLSHEADER header; @@ -56,6 +57,21 @@ struct collection struct list waves; }; +extern void collection_internal_addref(struct collection *collection) +{ + ULONG ref = InterlockedIncrement( &collection->internal_ref ); + TRACE( "collection %p, internal ref %lu.\n", collection, ref ); +} + +extern void collection_internal_release(struct collection *collection) +{ + ULONG ref = InterlockedDecrement( &collection->internal_ref ); + TRACE( "collection %p, internal ref %lu.\n", collection, ref ); + + if (!ref) + free(collection); +} + static inline struct collection *impl_from_IDirectMusicCollection(IDirectMusicCollection *iface) { return CONTAINING_RECORD(iface, struct collection, IDirectMusicCollection_iface); @@ -128,7 +144,7 @@ static ULONG WINAPI collection_Release(IDirectMusicCollection *iface) free(wave_entry); } - free(This); + collection_internal_release(This); } return ref; @@ -201,7 +217,7 @@ static HRESULT parse_lins_list(struct collection *This, IStream *stream, struct { case MAKE_IDTYPE(FOURCC_LIST, FOURCC_INS): if (!(entry = malloc(sizeof(*entry)))) return E_OUTOFMEMORY; - hr = instrument_create_from_chunk(stream, &chunk, &entry->desc, &entry->instrument); + hr = instrument_create_from_chunk(stream, &chunk, This, &entry->desc, &entry->instrument); if (SUCCEEDED(hr)) list_add_tail(&This->instruments, &entry->entry); else free(entry); break; @@ -435,6 +451,7 @@ HRESULT collection_create(IUnknown **ret_iface) *ret_iface = NULL; if (!(collection = calloc(1, sizeof(*collection)))) return E_OUTOFMEMORY; collection->IDirectMusicCollection_iface.lpVtbl = &collection_vtbl; + collection->internal_ref = 1; collection->ref = 1; dmobject_init(&collection->dmobj, &CLSID_DirectMusicCollection, (IUnknown *)&collection->IDirectMusicCollection_iface); diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 84fdc5167a0..316e7743ecb 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -79,6 +79,10 @@ typedef struct port_info { * ClassFactory */ +struct collection; +extern void collection_internal_addref(struct collection *collection); +extern void collection_internal_release(struct collection *collection); + /* CLSID */ extern HRESULT music_create(IUnknown **ret_iface); extern HRESULT collection_create(IUnknown **ret_iface); @@ -90,7 +94,7 @@ extern HRESULT DMUSIC_CreateReferenceClockImpl (LPCGUID lpcGUID, LPVOID* ppobj, extern HRESULT download_create(DWORD size, IDirectMusicDownload **ret_iface); extern HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent, - DMUS_OBJECTDESC *desc, IDirectMusicInstrument **ret_iface); + struct collection *collection, DMUS_OBJECTDESC *desc, IDirectMusicInstrument **ret_iface); extern HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicPortDownload *port, IDirectMusicDownloadedInstrument **downloaded); extern HRESULT instrument_unload_from_port(IDirectMusicDownloadedInstrument *iface, IDirectMusicPortDownload *port); diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index 24b3c0305f8..b79e7671c5b 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -51,6 +51,7 @@ struct instrument INSTHEADER header; IDirectMusicDownload *download; + struct collection *collection; struct list articulations; struct list regions; }; @@ -124,6 +125,7 @@ static ULONG WINAPI instrument_Release(LPDIRECTMUSICINSTRUMENT iface) free(region); } + collection_internal_release(This->collection); free(This); } @@ -201,7 +203,7 @@ static const IDirectMusicDownloadedInstrumentVtbl downloaded_instrument_vtbl = downloaded_instrument_Release, }; -static HRESULT instrument_create(IDirectMusicInstrument **ret_iface) +static HRESULT instrument_create(struct collection *collection, IDirectMusicInstrument **ret_iface) { struct instrument *instrument; @@ -210,6 +212,7 @@ static HRESULT instrument_create(IDirectMusicInstrument **ret_iface) instrument->IDirectMusicInstrument_iface.lpVtbl = &instrument_vtbl; instrument->IDirectMusicDownloadedInstrument_iface.lpVtbl = &downloaded_instrument_vtbl; instrument->ref = 1; + collection_internal_addref((instrument->collection = collection)); list_init(&instrument->articulations); list_init(&instrument->regions); @@ -377,15 +380,15 @@ static HRESULT parse_ins_chunk(struct instrument *This, IStream *stream, struct } HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent, - DMUS_OBJECTDESC *desc, IDirectMusicInstrument **ret_iface) + struct collection *collection, DMUS_OBJECTDESC *desc, IDirectMusicInstrument **ret_iface) { IDirectMusicInstrument *iface; struct instrument *This; HRESULT hr; - TRACE("(%p, %p)\n", stream, ret_iface); + TRACE("(%p, %p, %p, %p, %p)\n", stream, parent, collection, desc, ret_iface); - if (FAILED(hr = instrument_create(&iface))) return hr; + if (FAILED(hr = instrument_create(collection, &iface))) return hr; This = impl_from_IDirectMusicInstrument(iface); if (FAILED(hr = parse_ins_chunk(This, stream, parent, desc))) From af66137343eed8fe7571a6720d4d3cf0c30929f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 9 Sep 2023 14:06:32 +0200 Subject: [PATCH 2526/2777] dmusic: Implement downloading wave to port. (cherry picked from commit d32fb707ad30fad9e13d4609e4347dab55ec8a8b) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 21 ++++++++++++++++++ dlls/dmusic/dmusic_private.h | 2 ++ dlls/dmusic/instrument.c | 33 +++++++++++++++++++++++++++ dlls/dmusic/tests/dmusic.c | 4 +--- dlls/dmusic/wave.c | 43 ++++++++++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 3 deletions(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index cfe7589485d..b7c11dacb77 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -72,6 +72,27 @@ extern void collection_internal_release(struct collection *collection) free(collection); } +extern HRESULT collection_get_wave(struct collection *collection, DWORD index, IUnknown **out) +{ + struct wave_entry *wave_entry; + DWORD offset; + + if (index >= collection->pool->table.cCues) return E_INVALIDARG; + offset = collection->pool->cues[index].ulOffset; + + LIST_FOR_EACH_ENTRY(wave_entry, &collection->waves, struct wave_entry, entry) + { + if (offset == wave_entry->offset) + { + *out = wave_entry->wave; + IUnknown_AddRef(wave_entry->wave); + return S_OK; + } + } + + return E_FAIL; +} + static inline struct collection *impl_from_IDirectMusicCollection(IDirectMusicCollection *iface) { return CONTAINING_RECORD(iface, struct collection, IDirectMusicCollection_iface); diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 316e7743ecb..08d84ff83e1 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -82,6 +82,7 @@ typedef struct port_info { struct collection; extern void collection_internal_addref(struct collection *collection); extern void collection_internal_release(struct collection *collection); +extern HRESULT collection_get_wave(struct collection *collection, DWORD index, IUnknown **out); /* CLSID */ extern HRESULT music_create(IUnknown **ret_iface); @@ -100,6 +101,7 @@ extern HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirec extern HRESULT instrument_unload_from_port(IDirectMusicDownloadedInstrument *iface, IDirectMusicPortDownload *port); extern HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnknown **out); +extern HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, DWORD *id); /***************************************************************************** * IDirectMusic8Impl implementation structure diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index b79e7671c5b..663e2112a06 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -453,6 +453,7 @@ HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicP IDirectMusicDownload *download; DWORD size, offset_count; struct region *region; + IUnknown *wave; HRESULT hr; if (This->download) goto done; @@ -509,6 +510,13 @@ HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicP dmus_region->WaveLink = region->wave_link; dmus_region->WSMP = region->wave_sample; dmus_region->WLOOP[0] = region->wave_loop; + + if (SUCCEEDED(hr = collection_get_wave(This->collection, region->wave_link.ulTableIndex, &wave))) + { + hr = wave_download_to_port(wave, port, &dmus_region->WaveLink.ulTableIndex); + IUnknown_Release(wave); + } + if (FAILED(hr)) goto failed; } if (FAILED(hr = IDirectMusicPortDownload_Download(port, download))) goto failed; @@ -530,12 +538,37 @@ HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicP HRESULT instrument_unload_from_port(IDirectMusicDownloadedInstrument *iface, IDirectMusicPortDownload *port) { struct instrument *This = impl_from_IDirectMusicDownloadedInstrument(iface); + struct download_buffer *buffer; + DWORD size; HRESULT hr; if (!This->download) return DMUS_E_NOT_DOWNLOADED_TO_PORT; if (FAILED(hr = IDirectMusicPortDownload_Unload(port, This->download))) WARN("Failed to unload instrument download buffer, hr %#lx\n", hr); + else if (SUCCEEDED(hr = IDirectMusicDownload_GetBuffer(This->download, (void **)&buffer, &size))) + { + IDirectMusicDownload *wave_download; + DMUS_INSTRUMENT *instrument; + BYTE *ptr = (BYTE *)buffer; + DMUS_REGION *region; + UINT index; + + instrument = (DMUS_INSTRUMENT *)(ptr + buffer->offsets[0]); + for (index = instrument->ulFirstRegionIdx; index; index = region->ulNextRegionIdx) + { + region = (DMUS_REGION *)(ptr + buffer->offsets[index]); + + if (FAILED(hr = IDirectMusicPortDownload_GetBuffer(port, region->WaveLink.ulTableIndex, &wave_download))) + WARN("Failed to get wave download with id %#lx, hr %#lx\n", region->WaveLink.ulTableIndex, hr); + else + { + if (FAILED(hr = IDirectMusicPortDownload_Unload(port, wave_download))) + WARN("Failed to unload wave download buffer, hr %#lx\n", hr); + IDirectMusicDownload_Release(wave_download); + } + } + } IDirectMusicDownload_Release(This->download); This->download = NULL; diff --git a/dlls/dmusic/tests/dmusic.c b/dlls/dmusic/tests/dmusic.c index 1561c51df76..879a6f800cd 100644 --- a/dlls/dmusic/tests/dmusic.c +++ b/dlls/dmusic/tests/dmusic.c @@ -1300,8 +1300,7 @@ static void test_download_instrument(void) check_interface(instrument, &IID_IDirectMusicDownloadedInstrument, FALSE); hr = IDirectMusicPort_DownloadInstrument(port, instrument, &downloaded, NULL, 0); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - if (hr != S_OK) goto skip_tests; + ok(hr == S_OK, "got %#lx\n", hr); check_interface(downloaded, &IID_IDirectMusicObject, FALSE); check_interface(downloaded, &IID_IDirectMusicDownload, FALSE); @@ -1313,7 +1312,6 @@ static void test_download_instrument(void) IDirectMusicInstrument_Release(instrument); -skip_tests: IDirectMusicCollection_Release(collection); IDirectMusicPort_Release(port); IDirectMusic_Release(dmusic); diff --git a/dlls/dmusic/wave.c b/dlls/dmusic/wave.c index cda895484cb..08146db0d1c 100644 --- a/dlls/dmusic/wave.c +++ b/dlls/dmusic/wave.c @@ -212,3 +212,46 @@ HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnk *ret_iface = iface; return S_OK; } + +HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, DWORD *id) +{ + struct download_buffer + { + DMUS_DOWNLOADINFO info; + ULONG offsets[2]; + DMUS_WAVE wave; + DMUS_WAVEDATA data; + } *buffer; + + struct wave *This = impl_from_IUnknown(iface); + DWORD size = offsetof(struct download_buffer, data.byData[This->data_size]); + IDirectMusicDownload *download; + HRESULT hr; + + if (FAILED(hr = IDirectMusicPortDownload_AllocateBuffer(port, size, &download))) return hr; + + if (SUCCEEDED(hr = IDirectMusicDownload_GetBuffer(download, (void **)&buffer, &size)) + && SUCCEEDED(hr = IDirectMusicPortDownload_GetDLId(port, &buffer->info.dwDLId, 1))) + { + buffer->info.dwDLType = DMUS_DOWNLOADINFO_WAVE; + buffer->info.dwNumOffsetTableEntries = 2; + buffer->info.cbSize = size; + + buffer->offsets[0] = offsetof(struct download_buffer, wave); + buffer->offsets[1] = offsetof(struct download_buffer, data); + + buffer->wave.WaveformatEx = *This->format; + buffer->wave.ulWaveDataIdx = 1; + buffer->wave.ulCopyrightIdx = 0; + buffer->wave.ulFirstExtCkIdx = 0; + + buffer->data.cbSize = This->data_size; + memcpy(buffer->data.byData, This->data, This->data_size); + + if (SUCCEEDED(hr = IDirectMusicPortDownload_Download(port, download))) *id = buffer->info.dwDLId; + else WARN("Failed to download wave to port, hr %#lx\n", hr); + } + + IDirectMusicDownload_Release(download); + return hr; +} From 29c950ba9d42d579eae2895dae685955addea709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 15 Sep 2023 09:02:57 +0200 Subject: [PATCH 2527/2777] dmusic: Parse instrument regions articulation lists. (cherry picked from commit a788bf9641b6ed1ae0744e44aee8ae952ac1b212) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/instrument.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index 663e2112a06..a15a8d4e84f 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -36,6 +36,7 @@ C_ASSERT(sizeof(struct articulation) == offsetof(struct articulation, connection struct region { struct list entry; + struct list articulations; RGNHEADER header; WAVELINK wave_link; WSMPL wave_sample; @@ -121,6 +122,13 @@ static ULONG WINAPI instrument_Release(LPDIRECTMUSICINSTRUMENT iface) LIST_FOR_EACH_ENTRY_SAFE(region, next_region, &This->regions, struct region, entry) { + LIST_FOR_EACH_ENTRY_SAFE(articulation, next_articulation, ®ion->articulations, + struct articulation, entry) + { + list_remove(&articulation->entry); + free(articulation); + } + list_remove(®ion->entry); free(region); } @@ -221,7 +229,8 @@ static HRESULT instrument_create(struct collection *collection, IDirectMusicInst return S_OK; } -static HRESULT parse_art1_chunk(struct instrument *This, IStream *stream, struct chunk_entry *chunk) +static HRESULT parse_art1_chunk(struct instrument *This, IStream *stream, struct chunk_entry *chunk, + struct list *articulations) { struct articulation *articulation; CONNECTIONLIST list; @@ -239,12 +248,13 @@ static HRESULT parse_art1_chunk(struct instrument *This, IStream *stream, struct size = sizeof(CONNECTION) * list.cConnections; if (FAILED(hr = stream_read(stream, articulation->connections, size))) free(articulation); - else list_add_tail(&This->articulations, &articulation->entry); + else list_add_tail(articulations, &articulation->entry); return hr; } -static HRESULT parse_lart_list(struct instrument *This, IStream *stream, struct chunk_entry *parent) +static HRESULT parse_lart_list(struct instrument *This, IStream *stream, struct chunk_entry *parent, + struct list *articulations) { struct chunk_entry chunk = {.parent = parent}; HRESULT hr; @@ -254,7 +264,7 @@ static HRESULT parse_lart_list(struct instrument *This, IStream *stream, struct switch (MAKE_IDTYPE(chunk.id, chunk.type)) { case FOURCC_ART1: - hr = parse_art1_chunk(This, stream, &chunk); + hr = parse_art1_chunk(This, stream, &chunk, articulations); break; default: @@ -275,6 +285,7 @@ static HRESULT parse_rgn_chunk(struct instrument *This, IStream *stream, struct HRESULT hr; if (!(region = malloc(sizeof(*region)))) return E_OUTOFMEMORY; + list_init(®ion->articulations); while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { @@ -299,6 +310,10 @@ static HRESULT parse_rgn_chunk(struct instrument *This, IStream *stream, struct hr = stream_chunk_get_data(stream, &chunk, ®ion->wave_link, sizeof(region->wave_link)); break; + case MAKE_IDTYPE(FOURCC_LIST, FOURCC_LART): + hr = parse_lart_list(This, stream, &chunk, ®ion->articulations); + break; + default: FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); break; @@ -365,7 +380,7 @@ static HRESULT parse_ins_chunk(struct instrument *This, IStream *stream, struct break; case MAKE_IDTYPE(FOURCC_LIST, FOURCC_LART): - hr = parse_lart_list(This, stream, &chunk); + hr = parse_lart_list(This, stream, &chunk, &This->articulations); break; default: From e468659046b859473dba23c6a68a2dc790bfcafd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 9 Sep 2023 14:06:32 +0200 Subject: [PATCH 2528/2777] dmusic: Implement instrument articulation downloads. (cherry picked from commit 5626be6bb8b22d6fd476ad8c5f7e236f5d1b4ff2) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/instrument.c | 56 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index a15a8d4e84f..8ce3c0bc979 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -452,6 +452,39 @@ HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent return S_OK; } +static void write_articulation_download(struct list *articulations, ULONG *offsets, + BYTE **ptr, UINT index, DWORD *first, UINT *end) +{ + DMUS_ARTICULATION2 *dmus_articulation2 = NULL; + struct articulation *articulation; + CONNECTIONLIST *list; + UINT size; + + LIST_FOR_EACH_ENTRY(articulation, articulations, struct articulation, entry) + { + if (dmus_articulation2) dmus_articulation2->ulNextArtIdx = index; + else *first = index; + + offsets[index++] = sizeof(DMUS_DOWNLOADINFO) + *ptr - (BYTE *)offsets; + dmus_articulation2 = (DMUS_ARTICULATION2 *)*ptr; + (*ptr) += sizeof(DMUS_ARTICULATION2); + + dmus_articulation2->ulArtIdx = index; + dmus_articulation2->ulFirstExtCkIdx = 0; + dmus_articulation2->ulNextArtIdx = 0; + + size = articulation->list.cConnections * sizeof(CONNECTION); + offsets[index++] = sizeof(DMUS_DOWNLOADINFO) + *ptr - (BYTE *)offsets; + list = (CONNECTIONLIST *)*ptr; + (*ptr) += sizeof(CONNECTIONLIST) + size; + + *list = articulation->list; + memcpy(list + 1, articulation->connections, size); + } + + *end = index; +} + struct download_buffer { DMUS_DOWNLOADINFO info; @@ -464,6 +497,7 @@ HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicP IDirectMusicDownloadedInstrument **downloaded) { struct instrument *This = impl_from_IDirectMusicInstrument(iface); + struct articulation *articulation; struct download_buffer *buffer; IDirectMusicDownload *download; DWORD size, offset_count; @@ -477,10 +511,26 @@ HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicP size += sizeof(ULONG) + sizeof(DMUS_INSTRUMENT); offset_count = 1; + LIST_FOR_EACH_ENTRY(articulation, &This->articulations, struct articulation, entry) + { + size += sizeof(ULONG) + sizeof(DMUS_ARTICULATION2); + size += sizeof(ULONG) + sizeof(CONNECTIONLIST); + size += articulation->list.cConnections * sizeof(CONNECTION); + offset_count += 2; + } + LIST_FOR_EACH_ENTRY(region, &This->regions, struct region, entry) { size += sizeof(ULONG) + sizeof(DMUS_REGION); offset_count++; + + LIST_FOR_EACH_ENTRY(articulation, ®ion->articulations, struct articulation, entry) + { + size += sizeof(ULONG) + sizeof(DMUS_ARTICULATION2); + size += sizeof(ULONG) + sizeof(CONNECTIONLIST); + size += articulation->list.cConnections * sizeof(CONNECTION); + offset_count += 2; + } } if (FAILED(hr = IDirectMusicPortDownload_AllocateBuffer(port, size, &download))) return hr; @@ -506,6 +556,9 @@ HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicP dmus_instrument->ulCopyrightIdx = 0; dmus_instrument->ulGlobalArtIdx = 0; + write_articulation_download(&This->articulations, buffer->offsets, &ptr, index, + &dmus_instrument->ulGlobalArtIdx, &index); + LIST_FOR_EACH_ENTRY(region, &This->regions, struct region, entry) { if (dmus_region) dmus_region->ulNextRegionIdx = index; @@ -532,6 +585,9 @@ HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicP IUnknown_Release(wave); } if (FAILED(hr)) goto failed; + + write_articulation_download(®ion->articulations, buffer->offsets, &ptr, index, + &dmus_region->ulRegionArtIdx, &index); } if (FAILED(hr = IDirectMusicPortDownload_Download(port, download))) goto failed; From d598a729ce05ed1d4199fc4f00a8738c506894e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 13 Sep 2023 08:56:13 +0200 Subject: [PATCH 2529/2777] dmime/tests: Test that SendPMsg also converts reference time. And avoid checking a possibly freed message. (cherry picked from commit eedde528096aca8aa69b8c0c3b27084df79551f8) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 109 +++++++++++++++++++++++++++------------ 1 file changed, 77 insertions(+), 32 deletions(-) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 26efdd4c72f..00cbd045bd8 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -1730,9 +1730,10 @@ static void test_performance_pmsg(void) static const DWORD delivery_flags[] = {DMUS_PMSGF_TOOL_IMMEDIATE, DMUS_PMSGF_TOOL_QUEUE, DMUS_PMSGF_TOOL_ATTIME}; static const DWORD message_types[] = {DMUS_PMSGT_MIDI, DMUS_PMSGT_USER}; IDirectMusicPerformance *performance; - IDirectMusicGraph *graph; + IDirectMusicGraph *graph, *performance_graph; IDirectMusicTool *tool; DMUS_PMSG *msg, *clone; + MUSIC_TIME music_time; REFERENCE_TIME time; HRESULT hr; DWORD ret; @@ -1744,6 +1745,8 @@ static void test_performance_pmsg(void) hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicPerformance, (void **)&performance); ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&performance_graph); + ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPerformance_AllocPMsg(performance, 0, NULL); @@ -1826,6 +1829,40 @@ static void test_performance_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr); + /* SendPMsg skips all the tools unless messages are stamped beforehand */ + + hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg); + ok(hr == S_OK, "got %#lx\n", hr); + ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize); + msg->mtTime = 0; + msg->dwFlags = DMUS_PMSGF_MUSICTIME; + msg->dwType = DMUS_PMSGT_USER; + hr = IDirectMusicPerformance_SendPMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 10, &msg); + ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); + ok(!msg, "got %p\n", msg); + + + /* SendPMsg converts music time to reference time if it is missing */ + + hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg); + ok(hr == S_OK, "got %#lx\n", hr); + ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize); + msg->mtTime = 500; + msg->dwFlags = DMUS_PMSGF_MUSICTIME; + msg->dwType = DMUS_PMSGT_USER; + hr = IDirectMusicGraph_StampPMsg(performance_graph, msg); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_SendPMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 50, &msg); + todo_wine ok(!ret, "got %#lx\n", ret); + todo_wine ok(msg != NULL, "got %p\n", msg); + if (!msg) goto skip_rtime; + time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, msg->mtTime, &time); ok(hr == S_OK, "got %#lx\n", hr); @@ -1833,32 +1870,26 @@ static void test_performance_pmsg(void) todo_wine ok(msg->rtTime == time, "got %I64d\n", msg->rtTime); ok(msg->mtTime == 500, "got %ld\n", msg->mtTime); todo_wine ok(msg->dwFlags & DMUS_PMSGF_REFTIME, "got %#lx\n", msg->dwFlags); + todo_wine ok(msg->dwFlags & DMUS_PMSGF_MUSICTIME, "got %#lx\n", msg->dwFlags); todo_wine ok(msg->dwFlags & (DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_IMMEDIATE), "got %#lx\n", msg->dwFlags); ok(!msg->dwPChannel, "got %ld\n", msg->dwPChannel); ok(!msg->dwVirtualTrackID, "got %ld\n", msg->dwVirtualTrackID); - ok(!msg->pTool, "got %p\n", msg->pTool); - ok(!msg->pGraph, "got %p\n", msg->pGraph); - ok(!msg->dwType, "got %#lx\n", msg->dwType); + ok(msg->pTool == tool, "got %p\n", msg->pTool); + ok(msg->pGraph == performance_graph, "got %p\n", msg->pGraph); + ok(msg->dwType == DMUS_PMSGT_USER, "got %#lx\n", msg->dwType); ok(!msg->dwVoiceID, "got %ld\n", msg->dwVoiceID); ok(!msg->dwGroupID, "got %ld\n", msg->dwGroupID); ok(!msg->punkUser, "got %p\n", msg->punkUser); - - /* SendPMsg skips all the tools unless messages are stamped beforehand */ - - hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg); - ok(hr == S_OK, "got %#lx\n", hr); - ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize); - msg->rtTime = time; - msg->dwFlags = DMUS_PMSGF_REFTIME; - msg->dwType = DMUS_PMSGT_USER; - hr = IDirectMusicPerformance_SendPMsg(performance, msg); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); - ret = test_tool_wait_message(tool, 10, &msg); - ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); - ok(!msg, "got %p\n", msg); +skip_rtime: + /* SendPMsg converts reference time to music time if it is missing */ + + hr = IDirectMusicPerformance_GetTime(performance, &time, &music_time); + ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(DMUS_PMSG), &msg); ok(hr == S_OK, "got %#lx\n", hr); @@ -1866,24 +1897,39 @@ static void test_performance_pmsg(void) msg->rtTime = time; msg->dwFlags = DMUS_PMSGF_REFTIME; msg->dwType = DMUS_PMSGT_USER; - - hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph); + hr = IDirectMusicGraph_StampPMsg(performance_graph, msg); ok(hr == S_OK, "got %#lx\n", hr); - hr = IDirectMusicGraph_StampPMsg(graph, msg); - ok(hr == S_OK, "got %#lx\n", hr); - IDirectMusicGraph_Release(graph); - hr = IDirectMusicPerformance_SendPMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 50, &msg); todo_wine ok(!ret, "got %#lx\n", ret); todo_wine ok(msg != NULL, "got %p\n", msg); - if (!msg) hr = S_OK; - else hr = IDirectMusicPerformance_FreePMsg(performance, msg); + if (!msg) goto skip_mtime; + + music_time = 0xdeadbeef; + hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, msg->rtTime, &music_time); + ok(hr == S_OK, "got %#lx\n", hr); + ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize); + todo_wine ok(msg->rtTime == time, "got %I64d\n", msg->rtTime); + todo_wine ok(msg->mtTime == music_time, "got %ld\n", msg->mtTime); + todo_wine ok(msg->dwFlags & DMUS_PMSGF_REFTIME, "got %#lx\n", msg->dwFlags); + todo_wine ok(msg->dwFlags & DMUS_PMSGF_MUSICTIME, "got %#lx\n", msg->dwFlags); + todo_wine ok(msg->dwFlags & (DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_IMMEDIATE), "got %#lx\n", msg->dwFlags); + ok(!msg->dwPChannel, "got %ld\n", msg->dwPChannel); + ok(!msg->dwVirtualTrackID, "got %ld\n", msg->dwVirtualTrackID); + ok(msg->pTool == tool, "got %p\n", msg->pTool); + ok(msg->pGraph == performance_graph, "got %p\n", msg->pGraph); + ok(msg->dwType == DMUS_PMSGT_USER, "got %#lx\n", msg->dwType); + ok(!msg->dwVoiceID, "got %ld\n", msg->dwVoiceID); + ok(!msg->dwGroupID, "got %ld\n", msg->dwGroupID); + ok(!msg->punkUser, "got %p\n", msg->punkUser); + + hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); +skip_mtime: for (i = 0; i < ARRAY_SIZE(delivery_flags); i++) { DWORD duration = 0; @@ -1896,12 +1942,8 @@ static void test_performance_pmsg(void) msg->rtTime = time + 150 * 10000; msg->dwFlags = DMUS_PMSGF_REFTIME; msg->dwType = DMUS_PMSGT_USER; - - hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph); - ok(hr == S_OK, "got %#lx\n", hr); - hr = IDirectMusicGraph_StampPMsg(graph, msg); + hr = IDirectMusicGraph_StampPMsg(performance_graph, msg); ok(hr == S_OK, "got %#lx\n", hr); - IDirectMusicGraph_Release(graph); msg->dwFlags &= ~(DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME); msg->dwFlags |= delivery_flags[i]; @@ -1921,8 +1963,8 @@ static void test_performance_pmsg(void) switch (delivery_flags[i]) { case DMUS_PMSGF_TOOL_IMMEDIATE: todo_wine ok(duration <= 50, "got %lu\n", duration); break; - case DMUS_PMSGF_TOOL_QUEUE: todo_wine ok(duration >= 50 && duration <= 100, "got %lu\n", duration); break; - case DMUS_PMSGF_TOOL_ATTIME: todo_wine ok(duration >= 150 && duration <= 500, "got %lu\n", duration); break; + case DMUS_PMSGF_TOOL_QUEUE: todo_wine ok(duration >= 50 && duration <= 125, "got %lu\n", duration); break; + case DMUS_PMSGF_TOOL_ATTIME: todo_wine ok(duration >= 125 && duration <= 500, "got %lu\n", duration); break; } } @@ -1931,7 +1973,10 @@ static void test_performance_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicGraph_Release(performance_graph); + IDirectMusicPerformance_Release(performance); + IDirectMusicTool_Release(tool); } START_TEST(dmime) From 433c5fc5a10e4256843c2681c1dad69a304547cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Sep 2023 11:03:39 +0200 Subject: [PATCH 2530/2777] dmime: Convert DMUS_PMSG music and reference times in SendPMsg. (cherry picked from commit 6cd1c4e64aa0c9bd82b1b307f40edfc1ea4258f6) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index b3fd4851d45..c2681c4b150 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -74,7 +74,6 @@ struct DMUS_PMSGItem { DMUS_PMSGItem* next; DMUS_PMSGItem* prev; - REFERENCE_TIME rtItemTime; BOOL bInUse; DWORD cb; DMUS_PMSG pMsg; @@ -141,14 +140,14 @@ static DWORD WINAPI ProcessMsgThread(LPVOID lpParam) { it = it_next; } - for (it = This->head; NULL != it && it->rtItemTime < rtCurTime + dwDec; ) { + for (it = This->head; NULL != it && it->pMsg.rtTime < rtCurTime + dwDec; ) { it_next = it->next; cur = ProceedMsg(This, it); free(cur); it = it_next; } if (NULL != it) { - timeOut = ( it->rtItemTime - rtCurTime ) + This->rtLatencyTime; + timeOut = ( it->pMsg.rtTime - rtCurTime ) + This->rtLatencyTime; } outrefresh: @@ -425,11 +424,22 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS hr = DMUS_E_ALREADY_SENT; else { - /* TODO: Valid Flags */ - /* TODO: DMUS_PMSGF_MUSICTIME */ - message->rtItemTime = msg->rtTime; + if (!(msg->dwFlags & DMUS_PMSGF_MUSICTIME)) + { + if (FAILED(hr = IDirectMusicPerformance8_ReferenceToMusicTime(iface, + msg->rtTime, &msg->mtTime))) + goto done; + msg->dwFlags |= DMUS_PMSGF_MUSICTIME; + } + if (!(msg->dwFlags & DMUS_PMSGF_REFTIME)) + { + if (FAILED(hr = IDirectMusicPerformance8_MusicToReferenceTime(iface, + msg->mtTime, &msg->rtTime))) + goto done; + msg->dwFlags |= DMUS_PMSGF_REFTIME; + } - for (it = *queue; NULL != it && it->rtItemTime < message->rtItemTime; it = it->next) + for (it = *queue; NULL != it && it->pMsg.rtTime < message->pMsg.rtTime; it = it->next) prev_it = it; if (!prev_it) @@ -452,6 +462,7 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS hr = S_OK; } +done: LeaveCriticalSection(&This->safe); return hr; From 5eccbcc905cb7f5541bfc192fa4630153890a9f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Sep 2023 10:55:52 +0200 Subject: [PATCH 2531/2777] dmime: Get rid of the DMUS_PMSGItem typedef. (cherry picked from commit 419ab9284ab10627a0d068a0846b7c79e2fb1b3c) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 43 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index c2681c4b150..786ad817cd4 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -62,24 +62,24 @@ struct performance DWORD procThreadId; BOOL procThreadTicStarted; CRITICAL_SECTION safe; - struct DMUS_PMSGItem *head; - struct DMUS_PMSGItem *imm_head; + struct message *head; + struct message *imm_head; IReferenceClock *master_clock; REFERENCE_TIME init_time; }; -typedef struct DMUS_PMSGItem DMUS_PMSGItem; -struct DMUS_PMSGItem { - DMUS_PMSGItem* next; - DMUS_PMSGItem* prev; +struct message +{ + struct message *next; + struct message *prev; - BOOL bInUse; - DWORD cb; - DMUS_PMSG pMsg; + BOOL bInUse; + DWORD cb; + DMUS_PMSG pMsg; }; -#define DMUS_PMSGToItem(pMSG) ((DMUS_PMSGItem *)(((unsigned char *)pMSG) - offsetof(DMUS_PMSGItem, pMsg))) +#define DMUS_PMSGToItem(pMSG) ((struct message *)(((unsigned char *)pMSG) - offsetof(struct message, pMsg))) #define DMUS_ItemRemoveFromQueue(This,pItem) \ {\ if (pItem->prev) pItem->prev->next = pItem->next;\ @@ -95,7 +95,8 @@ struct DMUS_PMSGItem { #define PROCESSMSG_ADD (WM_APP + 4) -static DMUS_PMSGItem* ProceedMsg(struct performance *This, DMUS_PMSGItem* cur) { +static struct message *ProceedMsg(struct performance *This, struct message *cur) +{ if (cur->pMsg.dwType == DMUS_PMSGT_NOTIFICATION) { SetEvent(This->hNotification); } @@ -117,9 +118,9 @@ static DWORD WINAPI ProcessMsgThread(LPVOID lpParam) { MSG msg; HRESULT hr; REFERENCE_TIME rtCurTime; - DMUS_PMSGItem* it = NULL; - DMUS_PMSGItem* cur = NULL; - DMUS_PMSGItem* it_next = NULL; + struct message *it = NULL; + struct message *cur = NULL; + struct message *it_next = NULL; while (TRUE) { DWORD dwDec = This->rtLatencyTime + This->dwBumperLength; @@ -401,10 +402,10 @@ static HRESULT WINAPI performance_GetBumperLength(IDirectMusicPerformance8 *ifac static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *msg) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); - DMUS_PMSGItem *message; - DMUS_PMSGItem *it = NULL; - DMUS_PMSGItem *prev_it = NULL; - DMUS_PMSGItem **queue; + struct message *message; + struct message *it = NULL; + struct message *prev_it = NULL; + struct message **queue; HRESULT hr; FIXME("(%p, %p): semi-stub\n", This, msg); @@ -535,14 +536,14 @@ static HRESULT WINAPI performance_GetTime(IDirectMusicPerformance8 *iface, REFER static HRESULT WINAPI performance_AllocPMsg(IDirectMusicPerformance8 *iface, ULONG size, DMUS_PMSG **msg) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); - DMUS_PMSGItem *message; + struct message *message; TRACE("(%p, %ld, %p)\n", This, size, msg); if (!msg) return E_POINTER; if (size < sizeof(DMUS_PMSG)) return E_INVALIDARG; - if (!(message = calloc(1, size - sizeof(DMUS_PMSG) + sizeof(DMUS_PMSGItem)))) return E_OUTOFMEMORY; + if (!(message = calloc(1, size - sizeof(DMUS_PMSG) + sizeof(struct message)))) return E_OUTOFMEMORY; message->pMsg.dwSize = size; *msg = &message->pMsg; @@ -552,7 +553,7 @@ static HRESULT WINAPI performance_AllocPMsg(IDirectMusicPerformance8 *iface, ULO static HRESULT WINAPI performance_FreePMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *msg) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); - DMUS_PMSGItem *message; + struct message *message; HRESULT hr; TRACE("(%p, %p)\n", This, msg); From 7f1192f64d5631874fc3681b566037c6b759c106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Sep 2023 18:24:32 +0200 Subject: [PATCH 2532/2777] dmime: Use a struct list to keep performance messages. (cherry picked from commit db9758fb4e064b46fcb17f6d13f4a6cfa7c525b6) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 79 +++++++++++++--------------------------- 1 file changed, 26 insertions(+), 53 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 786ad817cd4..b3d821d90bc 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -62,8 +62,8 @@ struct performance DWORD procThreadId; BOOL procThreadTicStarted; CRITICAL_SECTION safe; - struct message *head; - struct message *imm_head; + struct list immediate_messages; + struct list queued_messages; IReferenceClock *master_clock; REFERENCE_TIME init_time; @@ -71,23 +71,13 @@ struct performance struct message { - struct message *next; - struct message *prev; - + struct list entry; BOOL bInUse; DWORD cb; DMUS_PMSG pMsg; }; #define DMUS_PMSGToItem(pMSG) ((struct message *)(((unsigned char *)pMSG) - offsetof(struct message, pMsg))) -#define DMUS_ItemRemoveFromQueue(This,pItem) \ -{\ - if (pItem->prev) pItem->prev->next = pItem->next;\ - if (pItem->next) pItem->next->prev = pItem->prev;\ - if (This->head == pItem) This->head = pItem->next;\ - if (This->imm_head == pItem) This->imm_head = pItem->next;\ - pItem->bInUse = FALSE;\ -} #define PROCESSMSG_START (WM_APP + 0) #define PROCESSMSG_EXIT (WM_APP + 1) @@ -100,7 +90,8 @@ static struct message *ProceedMsg(struct performance *This, struct message *cur) if (cur->pMsg.dwType == DMUS_PMSGT_NOTIFICATION) { SetEvent(This->hNotification); } - DMUS_ItemRemoveFromQueue(This, cur); + list_remove(&cur->entry); + cur->bInUse = FALSE; switch (cur->pMsg.dwType) { case DMUS_PMSGT_WAVE: case DMUS_PMSGT_TEMPO: @@ -118,9 +109,8 @@ static DWORD WINAPI ProcessMsgThread(LPVOID lpParam) { MSG msg; HRESULT hr; REFERENCE_TIME rtCurTime; - struct message *it = NULL; + struct message *message, *next; struct message *cur = NULL; - struct message *it_next = NULL; while (TRUE) { DWORD dwDec = This->rtLatencyTime + This->dwBumperLength; @@ -134,21 +124,18 @@ static DWORD WINAPI ProcessMsgThread(LPVOID lpParam) { goto outrefresh; } - for (it = This->imm_head; NULL != it; ) { - it_next = it->next; - cur = ProceedMsg(This, it); - free(cur); - it = it_next; + LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->immediate_messages, struct message, entry) + { + cur = ProceedMsg(This, message); + free(cur); } - for (it = This->head; NULL != it && it->pMsg.rtTime < rtCurTime + dwDec; ) { - it_next = it->next; - cur = ProceedMsg(This, it); - free(cur); - it = it_next; - } - if (NULL != it) { - timeOut = ( it->pMsg.rtTime - rtCurTime ) + This->rtLatencyTime; + LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->queued_messages, struct message, entry) + { + timeOut = (message->pMsg.rtTime - rtCurTime) + This->rtLatencyTime; + if (message->pMsg.rtTime >= rtCurTime + dwDec) break; + cur = ProceedMsg(This, message); + free(cur); } outrefresh: @@ -402,10 +389,8 @@ static HRESULT WINAPI performance_GetBumperLength(IDirectMusicPerformance8 *ifac static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *msg) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); - struct message *message; - struct message *it = NULL; - struct message *prev_it = NULL; - struct message **queue; + struct message *message, *next; + struct list *queue; HRESULT hr; FIXME("(%p, %p): semi-stub\n", This, msg); @@ -414,8 +399,8 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS if (!This->dmusic) return DMUS_E_NO_MASTER_CLOCK; if (!(msg->dwFlags & (DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_REFTIME))) return E_INVALIDARG; - if (msg->dwFlags & DMUS_PMSGF_TOOL_IMMEDIATE) queue = &This->imm_head; - else queue = &This->head; + if (msg->dwFlags & DMUS_PMSGF_TOOL_IMMEDIATE) queue = &This->immediate_messages; + else queue = &This->queued_messages; message = DMUS_PMSGToItem(msg); @@ -440,24 +425,9 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS msg->dwFlags |= DMUS_PMSGF_REFTIME; } - for (it = *queue; NULL != it && it->pMsg.rtTime < message->pMsg.rtTime; it = it->next) - prev_it = it; - - if (!prev_it) - { - message->prev = NULL; - if (*queue) message->next = (*queue)->next; - /*assert( NULL == message->next->prev );*/ - if (message->next) message->next->prev = message; - *queue = message; - } - else - { - message->prev = prev_it; - message->next = prev_it->next; - prev_it->next = message; - if (message->next) message->next->prev = message; - } + LIST_FOR_EACH_ENTRY(next, queue, struct message, entry) + if (next->pMsg.rtTime >= message->pMsg.rtTime) break; + list_add_before(&next->entry, &message->entry); message->bInUse = TRUE; hr = S_OK; @@ -1517,6 +1487,9 @@ HRESULT create_dmperformance(REFIID iid, void **ret_iface) obj->safe.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": performance->safe"); wine_rb_init(&obj->pchannels, pchannel_block_compare); + list_init(&obj->immediate_messages); + list_init(&obj->queued_messages); + obj->rtLatencyTime = 100; /* 100 ms TO FIX */ obj->dwBumperLength = 50; /* 50 ms default */ obj->dwPrepareTime = 1000; /* 1000 ms default */ From cd74a8d3c7337553f6b7d3f04bd65c628754a629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Sep 2023 18:27:10 +0200 Subject: [PATCH 2533/2777] dmime: Remove unnecessary struct message members. (cherry picked from commit 61ebdbcbbdf997b0971527f68571500245d687c3) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index b3d821d90bc..77089d51709 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -72,8 +72,6 @@ struct performance struct message { struct list entry; - BOOL bInUse; - DWORD cb; DMUS_PMSG pMsg; }; @@ -91,7 +89,7 @@ static struct message *ProceedMsg(struct performance *This, struct message *cur) SetEvent(This->hNotification); } list_remove(&cur->entry); - cur->bInUse = FALSE; + list_init(&cur->entry); switch (cur->pMsg.dwType) { case DMUS_PMSGT_WAVE: case DMUS_PMSGT_TEMPO: @@ -406,7 +404,7 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS EnterCriticalSection(&This->safe); - if (message->bInUse) + if (!list_empty(&message->entry)) hr = DMUS_E_ALREADY_SENT; else { @@ -429,7 +427,6 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS if (next->pMsg.rtTime >= message->pMsg.rtTime) break; list_add_before(&next->entry, &message->entry); - message->bInUse = TRUE; hr = S_OK; } @@ -515,6 +512,7 @@ static HRESULT WINAPI performance_AllocPMsg(IDirectMusicPerformance8 *iface, ULO if (!(message = calloc(1, size - sizeof(DMUS_PMSG) + sizeof(struct message)))) return E_OUTOFMEMORY; message->pMsg.dwSize = size; + list_init(&message->entry); *msg = &message->pMsg; return S_OK; @@ -532,7 +530,7 @@ static HRESULT WINAPI performance_FreePMsg(IDirectMusicPerformance8 *iface, DMUS message = DMUS_PMSGToItem(msg); EnterCriticalSection(&This->safe); - hr = message->bInUse ? DMUS_E_CANNOT_FREE : S_OK; + hr = !list_empty(&message->entry) ? DMUS_E_CANNOT_FREE : S_OK; LeaveCriticalSection(&This->safe); if (SUCCEEDED(hr)) From fe890c79c27a59ee5669cd4fa042ba0a7ec95e3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Sep 2023 18:27:38 +0200 Subject: [PATCH 2534/2777] dmime: Rename DMUS_PMSGToItem to message_from_DMUS_PMSG. (cherry picked from commit 0a93c69b13f4c6a16f5a5bac40b5844d40504070) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 77089d51709..4c79a22091c 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -72,10 +72,13 @@ struct performance struct message { struct list entry; - DMUS_PMSG pMsg; + DMUS_PMSG msg; }; -#define DMUS_PMSGToItem(pMSG) ((struct message *)(((unsigned char *)pMSG) - offsetof(struct message, pMsg))) +static inline struct message *message_from_DMUS_PMSG(DMUS_PMSG *msg) +{ + return msg ? CONTAINING_RECORD(msg, struct message, msg) : NULL; +} #define PROCESSMSG_START (WM_APP + 0) #define PROCESSMSG_EXIT (WM_APP + 1) @@ -85,17 +88,17 @@ struct message static struct message *ProceedMsg(struct performance *This, struct message *cur) { - if (cur->pMsg.dwType == DMUS_PMSGT_NOTIFICATION) { + if (cur->msg.dwType == DMUS_PMSGT_NOTIFICATION) { SetEvent(This->hNotification); } list_remove(&cur->entry); list_init(&cur->entry); - switch (cur->pMsg.dwType) { + switch (cur->msg.dwType) { case DMUS_PMSGT_WAVE: case DMUS_PMSGT_TEMPO: case DMUS_PMSGT_STOP: default: - FIXME("Unhandled PMsg Type: %#lx\n", cur->pMsg.dwType); + FIXME("Unhandled PMsg Type: %#lx\n", cur->msg.dwType); break; } return cur; @@ -130,8 +133,8 @@ static DWORD WINAPI ProcessMsgThread(LPVOID lpParam) { LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->queued_messages, struct message, entry) { - timeOut = (message->pMsg.rtTime - rtCurTime) + This->rtLatencyTime; - if (message->pMsg.rtTime >= rtCurTime + dwDec) break; + timeOut = (message->msg.rtTime - rtCurTime) + This->rtLatencyTime; + if (message->msg.rtTime >= rtCurTime + dwDec) break; cur = ProceedMsg(This, message); free(cur); } @@ -393,15 +396,13 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS FIXME("(%p, %p): semi-stub\n", This, msg); - if (!msg) return E_POINTER; + if (!(message = message_from_DMUS_PMSG(msg))) return E_POINTER; if (!This->dmusic) return DMUS_E_NO_MASTER_CLOCK; if (!(msg->dwFlags & (DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_REFTIME))) return E_INVALIDARG; if (msg->dwFlags & DMUS_PMSGF_TOOL_IMMEDIATE) queue = &This->immediate_messages; else queue = &This->queued_messages; - message = DMUS_PMSGToItem(msg); - EnterCriticalSection(&This->safe); if (!list_empty(&message->entry)) @@ -424,7 +425,7 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS } LIST_FOR_EACH_ENTRY(next, queue, struct message, entry) - if (next->pMsg.rtTime >= message->pMsg.rtTime) break; + if (next->msg.rtTime >= message->msg.rtTime) break; list_add_before(&next->entry, &message->entry); hr = S_OK; @@ -511,9 +512,9 @@ static HRESULT WINAPI performance_AllocPMsg(IDirectMusicPerformance8 *iface, ULO if (size < sizeof(DMUS_PMSG)) return E_INVALIDARG; if (!(message = calloc(1, size - sizeof(DMUS_PMSG) + sizeof(struct message)))) return E_OUTOFMEMORY; - message->pMsg.dwSize = size; + message->msg.dwSize = size; list_init(&message->entry); - *msg = &message->pMsg; + *msg = &message->msg; return S_OK; } @@ -526,8 +527,7 @@ static HRESULT WINAPI performance_FreePMsg(IDirectMusicPerformance8 *iface, DMUS TRACE("(%p, %p)\n", This, msg); - if (!msg) return E_POINTER; - message = DMUS_PMSGToItem(msg); + if (!(message = message_from_DMUS_PMSG(msg))) return E_POINTER; EnterCriticalSection(&This->safe); hr = !list_empty(&message->entry) ? DMUS_E_CANNOT_FREE : S_OK; From 16f7c3c1f1abaeb2624bb34c94a9bf4815f3cd68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 13 Sep 2023 09:05:37 +0200 Subject: [PATCH 2535/2777] dmime: Pass the DMUS_PMSG through the performance graph. (cherry picked from commit 5f0474009ea7dd57b289685471228d6b53d07ec2) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 203 ++++++++++++++++++++++----------------- dlls/dmime/tests/dmime.c | 42 ++++---- 2 files changed, 133 insertions(+), 112 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 4c79a22091c..d8624427423 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -62,11 +62,10 @@ struct performance DWORD procThreadId; BOOL procThreadTicStarted; CRITICAL_SECTION safe; - struct list immediate_messages; - struct list queued_messages; IReferenceClock *master_clock; REFERENCE_TIME init_time; + struct list messages; }; struct message @@ -80,99 +79,109 @@ static inline struct message *message_from_DMUS_PMSG(DMUS_PMSG *msg) return msg ? CONTAINING_RECORD(msg, struct message, msg) : NULL; } +static HRESULT performance_process_message(struct performance *This, DMUS_PMSG *msg, DWORD *timeout) +{ + static const DWORD delivery_flags = DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME; + IDirectMusicPerformance *performance = (IDirectMusicPerformance *)&This->IDirectMusicPerformance8_iface; + HRESULT hr; + + do + { + REFERENCE_TIME current, offset = 0; + IDirectMusicTool *tool; + + if (FAILED(hr = IDirectMusicPerformance_GetTime(performance, ¤t, NULL))) return hr; + if (!(tool = msg->pTool)) tool = &This->IDirectMusicTool_iface; + + switch (msg->dwFlags & delivery_flags) + { + default: + WARN("No delivery flag found for message %p\n", msg); + /* fallthrough */ + case DMUS_PMSGF_TOOL_IMMEDIATE: + hr = IDirectMusicTool_ProcessPMsg(tool, performance, msg); + break; + case DMUS_PMSGF_TOOL_QUEUE: + offset = This->dwBumperLength * 10000; + /* fallthrough */ + case DMUS_PMSGF_TOOL_ATTIME: + if (msg->rtTime >= offset && msg->rtTime - offset >= current) + { + if (timeout) *timeout = (msg->rtTime - offset - current) / 10000; + return DMUS_S_REQUEUE; + } + + hr = IDirectMusicTool_ProcessPMsg(tool, performance, msg); + break; + } + } while (hr == DMUS_S_REQUEUE); + + if (hr == DMUS_S_FREE) hr = IDirectMusicPerformance_FreePMsg(performance, msg); + if (FAILED(hr)) WARN("Failed to process message, hr %#lx\n", hr); + return hr; +} + #define PROCESSMSG_START (WM_APP + 0) #define PROCESSMSG_EXIT (WM_APP + 1) #define PROCESSMSG_REMOVE (WM_APP + 2) #define PROCESSMSG_ADD (WM_APP + 4) +static DWORD WINAPI ProcessMsgThread(LPVOID lpParam) +{ + struct performance *This = lpParam; + DWORD timeout = INFINITE; + MSG msg; + HRESULT hr; + struct message *message, *next; -static struct message *ProceedMsg(struct performance *This, struct message *cur) -{ - if (cur->msg.dwType == DMUS_PMSGT_NOTIFICATION) { - SetEvent(This->hNotification); - } - list_remove(&cur->entry); - list_init(&cur->entry); - switch (cur->msg.dwType) { - case DMUS_PMSGT_WAVE: - case DMUS_PMSGT_TEMPO: - case DMUS_PMSGT_STOP: - default: - FIXME("Unhandled PMsg Type: %#lx\n", cur->msg.dwType); - break; - } - return cur; -} + while (TRUE) + { + if (timeout > 0) MsgWaitForMultipleObjects(0, NULL, FALSE, timeout, QS_POSTMESSAGE | QS_SENDMESSAGE | QS_TIMER); + timeout = INFINITE; -static DWORD WINAPI ProcessMsgThread(LPVOID lpParam) { - struct performance *This = lpParam; - DWORD timeOut = INFINITE; - MSG msg; - HRESULT hr; - REFERENCE_TIME rtCurTime; - struct message *message, *next; - struct message *cur = NULL; + EnterCriticalSection(&This->safe); - while (TRUE) { - DWORD dwDec = This->rtLatencyTime + This->dwBumperLength; + LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->messages, struct message, entry) + { + list_remove(&message->entry); + list_init(&message->entry); - if (timeOut > 0) MsgWaitForMultipleObjects(0, NULL, FALSE, timeOut, QS_POSTMESSAGE|QS_SENDMESSAGE|QS_TIMER); - timeOut = INFINITE; + hr = performance_process_message(This, &message->msg, &timeout); + if (hr == DMUS_S_REQUEUE) list_add_before(&next->entry, &message->entry); + if (hr != S_OK) break; + } - EnterCriticalSection(&This->safe); - hr = IDirectMusicPerformance8_GetTime(&This->IDirectMusicPerformance8_iface, &rtCurTime, NULL); - if (FAILED(hr)) { - goto outrefresh; - } - - LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->immediate_messages, struct message, entry) - { - cur = ProceedMsg(This, message); - free(cur); - } + LeaveCriticalSection(&This->safe); - LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->queued_messages, struct message, entry) - { - timeOut = (message->msg.rtTime - rtCurTime) + This->rtLatencyTime; - if (message->msg.rtTime >= rtCurTime + dwDec) break; - cur = ProceedMsg(This, message); - free(cur); - } + while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) + { + /** if hwnd we suppose that is a windows event ... */ + if (NULL != msg.hwnd) + { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + else + { + switch (msg.message) + { + case WM_QUIT: + case PROCESSMSG_EXIT: goto outofthread; + case PROCESSMSG_START: break; + case PROCESSMSG_ADD: break; + case PROCESSMSG_REMOVE: break; + default: ERR("Unhandled message %u. Critical Path\n", msg.message); break; + } + } + } -outrefresh: - LeaveCriticalSection(&This->safe); - - while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) { - /** if hwnd we suppose that is a windows event ... */ - if (NULL != msg.hwnd) { - TranslateMessage(&msg); - DispatchMessageA(&msg); - } else { - switch (msg.message) { - case WM_QUIT: - case PROCESSMSG_EXIT: - goto outofthread; - case PROCESSMSG_START: - break; - case PROCESSMSG_ADD: - break; - case PROCESSMSG_REMOVE: - break; - default: - ERR("Unhandled message %u. Critical Path\n", msg.message); - break; - } - } + /** here we should run a little of current AudioPath */ } - /** here we should run a little of current AudioPath */ - - } - outofthread: - TRACE("(%p): Exiting\n", This); - - return 0; + TRACE("(%p): Exiting\n", This); + + return 0; } static BOOL PostMessageToProcessMsgThread(struct performance *This, UINT iMsg) { @@ -389,9 +398,9 @@ static HRESULT WINAPI performance_GetBumperLength(IDirectMusicPerformance8 *ifac static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS_PMSG *msg) { + const DWORD delivery_flags = DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME; struct performance *This = impl_from_IDirectMusicPerformance8(iface); struct message *message, *next; - struct list *queue; HRESULT hr; FIXME("(%p, %p): semi-stub\n", This, msg); @@ -400,15 +409,13 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS if (!This->dmusic) return DMUS_E_NO_MASTER_CLOCK; if (!(msg->dwFlags & (DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_REFTIME))) return E_INVALIDARG; - if (msg->dwFlags & DMUS_PMSGF_TOOL_IMMEDIATE) queue = &This->immediate_messages; - else queue = &This->queued_messages; - EnterCriticalSection(&This->safe); if (!list_empty(&message->entry)) hr = DMUS_E_ALREADY_SENT; else { + if (!(msg->dwFlags & delivery_flags)) msg->dwFlags |= DMUS_PMSGF_TOOL_IMMEDIATE; if (!(msg->dwFlags & DMUS_PMSGF_MUSICTIME)) { if (FAILED(hr = IDirectMusicPerformance8_ReferenceToMusicTime(iface, @@ -424,9 +431,16 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS msg->dwFlags |= DMUS_PMSGF_REFTIME; } - LIST_FOR_EACH_ENTRY(next, queue, struct message, entry) + if (msg->dwFlags & DMUS_PMSGF_TOOL_IMMEDIATE) + { + hr = performance_process_message(This, &message->msg, NULL); + if (hr != DMUS_S_REQUEUE) goto done; + } + + LIST_FOR_EACH_ENTRY(next, &This->messages, struct message, entry) if (next->msg.rtTime >= message->msg.rtTime) break; list_add_before(&next->entry, &message->entry); + PostThreadMessageW(This->procThreadId, PROCESSMSG_ADD, 0, 0); hr = S_OK; } @@ -1440,8 +1454,20 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, IDirectMusicPerformance *performance, DMUS_PMSG *msg) { struct performance *This = impl_from_IDirectMusicTool(iface); - FIXME("(%p, %p, %p): stub\n", This, performance, msg); - return E_NOTIMPL; + + FIXME("(%p, %p, %p): semi-stub\n", This, performance, msg); + + switch (msg->dwType) + { + case DMUS_PMSGT_NOTIFICATION: + SetEvent(This->hNotification); + /* fallthrough */ + default: + FIXME("Unhandled message type %#lx\n", msg->dwType); + break; + } + + return DMUS_S_FREE; } static HRESULT WINAPI performance_tool_Flush(IDirectMusicTool *iface, @@ -1485,8 +1511,7 @@ HRESULT create_dmperformance(REFIID iid, void **ret_iface) obj->safe.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": performance->safe"); wine_rb_init(&obj->pchannels, pchannel_block_compare); - list_init(&obj->immediate_messages); - list_init(&obj->queued_messages); + list_init(&obj->messages); obj->rtLatencyTime = 100; /* 100 ms TO FIX */ obj->dwBumperLength = 50; /* 50 ms default */ diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 00cbd045bd8..89be2c32019 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -1506,7 +1506,7 @@ static void test_performance_tool(void) hr = IDirectMusicTool_GetMediaTypes(tool, (DWORD **)&types, 64); ok(hr == E_NOTIMPL, "got %#lx\n", hr); hr = IDirectMusicTool_ProcessPMsg(tool, performance, &msg); - todo_wine ok(hr == DMUS_S_FREE, "got %#lx\n", hr); + ok(hr == DMUS_S_FREE, "got %#lx\n", hr); hr = IDirectMusicTool_Flush(tool, performance, &msg, 0); todo_wine ok(hr == S_OK, "got %#lx\n", hr); @@ -1859,19 +1859,18 @@ static void test_performance_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 50, &msg); - todo_wine ok(!ret, "got %#lx\n", ret); - todo_wine ok(msg != NULL, "got %p\n", msg); - if (!msg) goto skip_rtime; + ok(!ret, "got %#lx\n", ret); + ok(msg != NULL, "got %p\n", msg); time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, msg->mtTime, &time); ok(hr == S_OK, "got %#lx\n", hr); ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize); - todo_wine ok(msg->rtTime == time, "got %I64d\n", msg->rtTime); + ok(msg->rtTime == time, "got %I64d\n", msg->rtTime); ok(msg->mtTime == 500, "got %ld\n", msg->mtTime); - todo_wine ok(msg->dwFlags & DMUS_PMSGF_REFTIME, "got %#lx\n", msg->dwFlags); - todo_wine ok(msg->dwFlags & DMUS_PMSGF_MUSICTIME, "got %#lx\n", msg->dwFlags); - todo_wine ok(msg->dwFlags & (DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_IMMEDIATE), "got %#lx\n", msg->dwFlags); + ok(msg->dwFlags & DMUS_PMSGF_REFTIME, "got %#lx\n", msg->dwFlags); + ok(msg->dwFlags & DMUS_PMSGF_MUSICTIME, "got %#lx\n", msg->dwFlags); + ok(msg->dwFlags & (DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_IMMEDIATE), "got %#lx\n", msg->dwFlags); ok(!msg->dwPChannel, "got %ld\n", msg->dwPChannel); ok(!msg->dwVirtualTrackID, "got %ld\n", msg->dwVirtualTrackID); ok(msg->pTool == tool, "got %p\n", msg->pTool); @@ -1885,7 +1884,6 @@ static void test_performance_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr); -skip_rtime: /* SendPMsg converts reference time to music time if it is missing */ hr = IDirectMusicPerformance_GetTime(performance, &time, &music_time); @@ -1903,19 +1901,18 @@ static void test_performance_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 50, &msg); - todo_wine ok(!ret, "got %#lx\n", ret); - todo_wine ok(msg != NULL, "got %p\n", msg); - if (!msg) goto skip_mtime; + ok(!ret, "got %#lx\n", ret); + ok(msg != NULL, "got %p\n", msg); music_time = 0xdeadbeef; hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, msg->rtTime, &music_time); ok(hr == S_OK, "got %#lx\n", hr); ok(msg->dwSize == sizeof(DMUS_PMSG), "got %ld\n", msg->dwSize); - todo_wine ok(msg->rtTime == time, "got %I64d\n", msg->rtTime); - todo_wine ok(msg->mtTime == music_time, "got %ld\n", msg->mtTime); - todo_wine ok(msg->dwFlags & DMUS_PMSGF_REFTIME, "got %#lx\n", msg->dwFlags); - todo_wine ok(msg->dwFlags & DMUS_PMSGF_MUSICTIME, "got %#lx\n", msg->dwFlags); - todo_wine ok(msg->dwFlags & (DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_IMMEDIATE), "got %#lx\n", msg->dwFlags); + ok(msg->rtTime == time, "got %I64d\n", msg->rtTime); + ok(msg->mtTime == music_time, "got %ld\n", msg->mtTime); + ok(msg->dwFlags & DMUS_PMSGF_REFTIME, "got %#lx\n", msg->dwFlags); + ok(msg->dwFlags & DMUS_PMSGF_MUSICTIME, "got %#lx\n", msg->dwFlags); + ok(msg->dwFlags & (DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_IMMEDIATE), "got %#lx\n", msg->dwFlags); ok(!msg->dwPChannel, "got %ld\n", msg->dwPChannel); ok(!msg->dwVirtualTrackID, "got %ld\n", msg->dwVirtualTrackID); ok(msg->pTool == tool, "got %p\n", msg->pTool); @@ -1929,7 +1926,6 @@ static void test_performance_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr); -skip_mtime: for (i = 0; i < ARRAY_SIZE(delivery_flags); i++) { DWORD duration = 0; @@ -1953,8 +1949,8 @@ static void test_performance_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr); msg = NULL; ret = test_tool_wait_message(tool, 1000, &msg); - todo_wine ok(!ret, "got %#lx\n", ret); - todo_wine ok(msg != NULL, "got %p\n", msg); + ok(!ret, "got %#lx\n", ret); + ok(msg != NULL, "got %p\n", msg); duration += GetTickCount(); if (msg) hr = IDirectMusicPerformance_FreePMsg(performance, msg); @@ -1962,9 +1958,9 @@ static void test_performance_pmsg(void) switch (delivery_flags[i]) { - case DMUS_PMSGF_TOOL_IMMEDIATE: todo_wine ok(duration <= 50, "got %lu\n", duration); break; - case DMUS_PMSGF_TOOL_QUEUE: todo_wine ok(duration >= 50 && duration <= 125, "got %lu\n", duration); break; - case DMUS_PMSGF_TOOL_ATTIME: todo_wine ok(duration >= 125 && duration <= 500, "got %lu\n", duration); break; + case DMUS_PMSGF_TOOL_IMMEDIATE: ok(duration <= 50, "got %lu\n", duration); break; + case DMUS_PMSGF_TOOL_QUEUE: ok(duration >= 50 && duration <= 125, "got %lu\n", duration); break; + case DMUS_PMSGF_TOOL_ATTIME: ok(duration >= 125 && duration <= 500, "got %lu\n", duration); break; } } From eb336421c63daa262e57be492acba4fbd1205c2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 13:41:13 +0200 Subject: [PATCH 2536/2777] dmband: Rename IDirectMusicBandImpl prefix to band. (cherry picked from commit be0085238e510d4c8de8a874b218c533ab55638c) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/band.c | 53 +++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/dlls/dmband/band.c b/dlls/dmband/band.c index 02e3573bab9..eb662f732ca 100644 --- a/dlls/dmband/band.c +++ b/dlls/dmband/band.c @@ -39,8 +39,7 @@ static inline IDirectMusicBandImpl *impl_from_IDirectMusicBand(IDirectMusicBand return CONTAINING_RECORD(iface, IDirectMusicBandImpl, IDirectMusicBand_iface); } -/* DirectMusicBandImpl IDirectMusicBand part: */ -static HRESULT WINAPI IDirectMusicBandImpl_QueryInterface(IDirectMusicBand *iface, REFIID riid, +static HRESULT WINAPI band_QueryInterface(IDirectMusicBand *iface, REFIID riid, void **ret_iface) { IDirectMusicBandImpl *This = impl_from_IDirectMusicBand(iface); @@ -64,7 +63,7 @@ static HRESULT WINAPI IDirectMusicBandImpl_QueryInterface(IDirectMusicBand *ifac return S_OK; } -static ULONG WINAPI IDirectMusicBandImpl_AddRef(IDirectMusicBand *iface) +static ULONG WINAPI band_AddRef(IDirectMusicBand *iface) { IDirectMusicBandImpl *This = impl_from_IDirectMusicBand(iface); LONG ref = InterlockedIncrement(&This->ref); @@ -74,7 +73,7 @@ static ULONG WINAPI IDirectMusicBandImpl_AddRef(IDirectMusicBand *iface) return ref; } -static ULONG WINAPI IDirectMusicBandImpl_Release(IDirectMusicBand *iface) +static ULONG WINAPI band_Release(IDirectMusicBand *iface) { IDirectMusicBandImpl *This = impl_from_IDirectMusicBand(iface); LONG ref = InterlockedDecrement(&This->ref); @@ -86,7 +85,7 @@ static ULONG WINAPI IDirectMusicBandImpl_Release(IDirectMusicBand *iface) return ref; } -static HRESULT WINAPI IDirectMusicBandImpl_CreateSegment(IDirectMusicBand *iface, +static HRESULT WINAPI band_CreateSegment(IDirectMusicBand *iface, IDirectMusicSegment **segment) { IDirectMusicBandImpl *This = impl_from_IDirectMusicBand(iface); @@ -110,7 +109,7 @@ static HRESULT WINAPI IDirectMusicBandImpl_CreateSegment(IDirectMusicBand *iface return hr; } -static HRESULT WINAPI IDirectMusicBandImpl_Download(IDirectMusicBand *iface, +static HRESULT WINAPI band_Download(IDirectMusicBand *iface, IDirectMusicPerformance *pPerformance) { IDirectMusicBandImpl *This = impl_from_IDirectMusicBand(iface); @@ -118,7 +117,7 @@ static HRESULT WINAPI IDirectMusicBandImpl_Download(IDirectMusicBand *iface, return S_OK; } -static HRESULT WINAPI IDirectMusicBandImpl_Unload(IDirectMusicBand *iface, +static HRESULT WINAPI band_Unload(IDirectMusicBand *iface, IDirectMusicPerformance *pPerformance) { IDirectMusicBandImpl *This = impl_from_IDirectMusicBand(iface); @@ -126,17 +125,17 @@ static HRESULT WINAPI IDirectMusicBandImpl_Unload(IDirectMusicBand *iface, return S_OK; } -static const IDirectMusicBandVtbl dmband_vtbl = { - IDirectMusicBandImpl_QueryInterface, - IDirectMusicBandImpl_AddRef, - IDirectMusicBandImpl_Release, - IDirectMusicBandImpl_CreateSegment, - IDirectMusicBandImpl_Download, - IDirectMusicBandImpl_Unload +static const IDirectMusicBandVtbl band_vtbl = +{ + band_QueryInterface, + band_AddRef, + band_Release, + band_CreateSegment, + band_Download, + band_Unload, }; -/* IDirectMusicBandImpl IDirectMusicObject part: */ -static HRESULT WINAPI band_IDirectMusicObject_ParseDescriptor(IDirectMusicObject *iface, +static HRESULT WINAPI band_object_ParseDescriptor(IDirectMusicObject *iface, IStream *stream, DMUS_OBJECTDESC *desc) { struct chunk_entry riff = {0}; @@ -175,18 +174,18 @@ static HRESULT WINAPI band_IDirectMusicObject_ParseDescriptor(IDirectMusicObject return S_OK; } -static const IDirectMusicObjectVtbl dmobject_vtbl = { +static const IDirectMusicObjectVtbl band_object_vtbl = +{ dmobj_IDirectMusicObject_QueryInterface, dmobj_IDirectMusicObject_AddRef, dmobj_IDirectMusicObject_Release, dmobj_IDirectMusicObject_GetDescriptor, dmobj_IDirectMusicObject_SetDescriptor, - band_IDirectMusicObject_ParseDescriptor + band_object_ParseDescriptor, }; #define DMUS_IO_INSTRUMENT_DX7_SIZE offsetof(DMUS_IO_INSTRUMENT, nPitchBendRange) -/* IDirectMusicBandImpl IPersistStream part: */ static HRESULT parse_instrument(IDirectMusicBandImpl *This, DMUS_PRIVATE_CHUNK *pChunk, IStream *pStm) { @@ -447,7 +446,7 @@ static inline IDirectMusicBandImpl *impl_from_IPersistStream(IPersistStream *ifa return CONTAINING_RECORD(iface, IDirectMusicBandImpl, dmobj.IPersistStream_iface); } -static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface, IStream *pStm) +static HRESULT WINAPI band_persist_stream_Load(IPersistStream *iface, IStream *pStm) { IDirectMusicBandImpl *This = impl_from_IPersistStream(iface); DMUS_PRIVATE_CHUNK Chunk; @@ -490,18 +489,18 @@ static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface, IStream *pS return S_OK; } -static const IPersistStreamVtbl persiststream_vtbl = { +static const IPersistStreamVtbl band_persist_stream_vtbl = +{ dmobj_IPersistStream_QueryInterface, dmobj_IPersistStream_AddRef, dmobj_IPersistStream_Release, unimpl_IPersistStream_GetClassID, unimpl_IPersistStream_IsDirty, - IPersistStreamImpl_Load, + band_persist_stream_Load, unimpl_IPersistStream_Save, - unimpl_IPersistStream_GetSizeMax + unimpl_IPersistStream_GetSizeMax, }; -/* for ClassFactory */ HRESULT create_dmband(REFIID lpcGUID, void **ppobj) { IDirectMusicBandImpl* obj; @@ -509,11 +508,11 @@ HRESULT create_dmband(REFIID lpcGUID, void **ppobj) *ppobj = NULL; if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; - obj->IDirectMusicBand_iface.lpVtbl = &dmband_vtbl; + obj->IDirectMusicBand_iface.lpVtbl = &band_vtbl; obj->ref = 1; dmobject_init(&obj->dmobj, &CLSID_DirectMusicBand, (IUnknown *)&obj->IDirectMusicBand_iface); - obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl; - obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; + obj->dmobj.IDirectMusicObject_iface.lpVtbl = &band_object_vtbl; + obj->dmobj.IPersistStream_iface.lpVtbl = &band_persist_stream_vtbl; list_init (&obj->Instruments); hr = IDirectMusicBand_QueryInterface(&obj->IDirectMusicBand_iface, lpcGUID, ppobj); From 63e960b0e286ca4406cda8e3772960b01703fb12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 13:42:05 +0200 Subject: [PATCH 2537/2777] dmband: Get rid of the IDirectMusicBandImpl typedef. (cherry picked from commit d3c5fe89f9cac1e059b803700899c7bbefcac40f) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/band.c | 39 ++++++++++++++++++--------------------- dlls/dmband/bandtrack.c | 3 +-- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/dlls/dmband/band.c b/dlls/dmband/band.c index eb662f732ca..bbf8c93a067 100644 --- a/dlls/dmband/band.c +++ b/dlls/dmband/band.c @@ -23,26 +23,23 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmband); WINE_DECLARE_DEBUG_CHANNEL(dmfile); - -/***************************************************************************** - * IDirectMusicBandImpl implementation - */ -typedef struct IDirectMusicBandImpl { +struct band +{ IDirectMusicBand IDirectMusicBand_iface; struct dmobject dmobj; LONG ref; struct list Instruments; -} IDirectMusicBandImpl; +}; -static inline IDirectMusicBandImpl *impl_from_IDirectMusicBand(IDirectMusicBand *iface) +static inline struct band *impl_from_IDirectMusicBand(IDirectMusicBand *iface) { - return CONTAINING_RECORD(iface, IDirectMusicBandImpl, IDirectMusicBand_iface); + return CONTAINING_RECORD(iface, struct band, IDirectMusicBand_iface); } static HRESULT WINAPI band_QueryInterface(IDirectMusicBand *iface, REFIID riid, void **ret_iface) { - IDirectMusicBandImpl *This = impl_from_IDirectMusicBand(iface); + struct band *This = impl_from_IDirectMusicBand(iface); TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface); @@ -65,7 +62,7 @@ static HRESULT WINAPI band_QueryInterface(IDirectMusicBand *iface, REFIID riid, static ULONG WINAPI band_AddRef(IDirectMusicBand *iface) { - IDirectMusicBandImpl *This = impl_from_IDirectMusicBand(iface); + struct band *This = impl_from_IDirectMusicBand(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); @@ -75,7 +72,7 @@ static ULONG WINAPI band_AddRef(IDirectMusicBand *iface) static ULONG WINAPI band_Release(IDirectMusicBand *iface) { - IDirectMusicBandImpl *This = impl_from_IDirectMusicBand(iface); + struct band *This = impl_from_IDirectMusicBand(iface); LONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); @@ -88,7 +85,7 @@ static ULONG WINAPI band_Release(IDirectMusicBand *iface) static HRESULT WINAPI band_CreateSegment(IDirectMusicBand *iface, IDirectMusicSegment **segment) { - IDirectMusicBandImpl *This = impl_from_IDirectMusicBand(iface); + struct band *This = impl_from_IDirectMusicBand(iface); HRESULT hr; DMUS_BAND_PARAM bandparam; @@ -112,7 +109,7 @@ static HRESULT WINAPI band_CreateSegment(IDirectMusicBand *iface, static HRESULT WINAPI band_Download(IDirectMusicBand *iface, IDirectMusicPerformance *pPerformance) { - IDirectMusicBandImpl *This = impl_from_IDirectMusicBand(iface); + struct band *This = impl_from_IDirectMusicBand(iface); FIXME("(%p, %p): stub\n", This, pPerformance); return S_OK; } @@ -120,7 +117,7 @@ static HRESULT WINAPI band_Download(IDirectMusicBand *iface, static HRESULT WINAPI band_Unload(IDirectMusicBand *iface, IDirectMusicPerformance *pPerformance) { - IDirectMusicBandImpl *This = impl_from_IDirectMusicBand(iface); + struct band *This = impl_from_IDirectMusicBand(iface); FIXME("(%p, %p): stub\n", This, pPerformance); return S_OK; } @@ -186,7 +183,7 @@ static const IDirectMusicObjectVtbl band_object_vtbl = #define DMUS_IO_INSTRUMENT_DX7_SIZE offsetof(DMUS_IO_INSTRUMENT, nPitchBendRange) -static HRESULT parse_instrument(IDirectMusicBandImpl *This, DMUS_PRIVATE_CHUNK *pChunk, +static HRESULT parse_instrument(struct band *This, DMUS_PRIVATE_CHUNK *pChunk, IStream *pStm) { DMUS_PRIVATE_CHUNK Chunk; @@ -293,7 +290,7 @@ static HRESULT parse_instrument(IDirectMusicBandImpl *This, DMUS_PRIVATE_CHUNK * return S_OK; } -static HRESULT parse_instruments_list(IDirectMusicBandImpl *This, DMUS_PRIVATE_CHUNK *pChunk, +static HRESULT parse_instruments_list(struct band *This, DMUS_PRIVATE_CHUNK *pChunk, IStream *pStm) { HRESULT hr; @@ -348,7 +345,7 @@ static HRESULT parse_instruments_list(IDirectMusicBandImpl *This, DMUS_PRIVATE_C return S_OK; } -static HRESULT parse_band_form(IDirectMusicBandImpl *This, DMUS_PRIVATE_CHUNK *pChunk, +static HRESULT parse_band_form(struct band *This, DMUS_PRIVATE_CHUNK *pChunk, IStream *pStm) { HRESULT hr = E_FAIL; @@ -441,14 +438,14 @@ static HRESULT parse_band_form(IDirectMusicBandImpl *This, DMUS_PRIVATE_CHUNK *p return S_OK; } -static inline IDirectMusicBandImpl *impl_from_IPersistStream(IPersistStream *iface) +static inline struct band *impl_from_IPersistStream(IPersistStream *iface) { - return CONTAINING_RECORD(iface, IDirectMusicBandImpl, dmobj.IPersistStream_iface); + return CONTAINING_RECORD(iface, struct band, dmobj.IPersistStream_iface); } static HRESULT WINAPI band_persist_stream_Load(IPersistStream *iface, IStream *pStm) { - IDirectMusicBandImpl *This = impl_from_IPersistStream(iface); + struct band *This = impl_from_IPersistStream(iface); DMUS_PRIVATE_CHUNK Chunk; LARGE_INTEGER liMove; HRESULT hr; @@ -503,7 +500,7 @@ static const IPersistStreamVtbl band_persist_stream_vtbl = HRESULT create_dmband(REFIID lpcGUID, void **ppobj) { - IDirectMusicBandImpl* obj; + struct band* obj; HRESULT hr; *ppobj = NULL; diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index bdb9344b064..bf494d39df2 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -1,5 +1,4 @@ -/* IDirectMusicBandTrack Implementation - * +/* * Copyright (C) 2003-2004 Rok Mandeljc * * This program is free software; you can redistribute it and/or From 4d95067a5447c0f480472bb96abdfadf2373bba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 13:44:12 +0200 Subject: [PATCH 2538/2777] dmband: Get rid of the IDirectMusicBandTrack typedef. (cherry picked from commit 696e8c12087989be82c0c23f7c4c70d8f59ff65e) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/bandtrack.c | 101 +++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 52 deletions(-) diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index bf494d39df2..53515bc8690 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -22,27 +22,24 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmband); WINE_DECLARE_DEBUG_CHANNEL(dmfile); -/***************************************************************************** - * IDirectMusicBandTrack implementation - */ -typedef struct IDirectMusicBandTrack { +struct band_track +{ IDirectMusicTrack8 IDirectMusicTrack8_iface; struct dmobject dmobj; /* IPersistStream only */ LONG ref; DMUS_IO_BAND_TRACK_HEADER header; struct list Bands; -} IDirectMusicBandTrack; +}; -/* IDirectMusicBandTrack IDirectMusicTrack8 part: */ -static inline IDirectMusicBandTrack *impl_from_IDirectMusicTrack8(IDirectMusicTrack8 *iface) +static inline struct band_track *impl_from_IDirectMusicTrack8(IDirectMusicTrack8 *iface) { - return CONTAINING_RECORD(iface, IDirectMusicBandTrack, IDirectMusicTrack8_iface); + return CONTAINING_RECORD(iface, struct band_track, IDirectMusicTrack8_iface); } static HRESULT WINAPI band_track_QueryInterface(IDirectMusicTrack8 *iface, REFIID riid, void **ret_iface) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); + struct band_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface); @@ -64,7 +61,7 @@ static HRESULT WINAPI band_track_QueryInterface(IDirectMusicTrack8 *iface, REFII static ULONG WINAPI band_track_AddRef(IDirectMusicTrack8 *iface) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); + struct band_track *This = impl_from_IDirectMusicTrack8(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); @@ -74,7 +71,7 @@ static ULONG WINAPI band_track_AddRef(IDirectMusicTrack8 *iface) static ULONG WINAPI band_track_Release(IDirectMusicTrack8 *iface) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); + struct band_track *This = impl_from_IDirectMusicTrack8(iface); LONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); @@ -86,16 +83,16 @@ static ULONG WINAPI band_track_Release(IDirectMusicTrack8 *iface) static HRESULT WINAPI band_track_Init(IDirectMusicTrack8 *iface, IDirectMusicSegment *pSegment) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); - FIXME("(%p, %p): stub\n", This, pSegment); - return S_OK; + struct band_track *This = impl_from_IDirectMusicTrack8(iface); + FIXME("(%p, %p): stub\n", This, pSegment); + return S_OK; } static HRESULT WINAPI band_track_InitPlay(IDirectMusicTrack8 *iface, IDirectMusicSegmentState *segment_state, IDirectMusicPerformance *performance, void **state_data, DWORD virtual_track8id, DWORD flags) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); + struct band_track *This = impl_from_IDirectMusicTrack8(iface); FIXME("(%p, %p, %p, %p, %ld, %lx): stub\n", This, segment_state, performance, state_data, virtual_track8id, flags); @@ -104,9 +101,9 @@ static HRESULT WINAPI band_track_InitPlay(IDirectMusicTrack8 *iface, static HRESULT WINAPI band_track_EndPlay(IDirectMusicTrack8 *iface, void *pStateData) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); - FIXME("(%p, %p): stub\n", This, pStateData); - return S_OK; + struct band_track *This = impl_from_IDirectMusicTrack8(iface); + FIXME("(%p, %p): stub\n", This, pStateData); + return S_OK; } static HRESULT WINAPI band_track_Play(IDirectMusicTrack8 *iface, void *state_data, @@ -114,7 +111,7 @@ static HRESULT WINAPI band_track_Play(IDirectMusicTrack8 *iface, void *state_dat IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state, DWORD virtual_id) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); + struct band_track *This = impl_from_IDirectMusicTrack8(iface); FIXME("(%p, %p, %ld, %ld, %ld, %lx, %p, %p, %ld): semi-stub\n", This, state_data, mtStart, mtEnd, mtOffset, flags, performance, segment_state, virtual_id); @@ -131,7 +128,7 @@ static HRESULT WINAPI band_track_Play(IDirectMusicTrack8 *iface, void *state_dat static HRESULT WINAPI band_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time, MUSIC_TIME *next, void *param) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); + struct band_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s, %ld, %p, %p)\n", This, debugstr_dmguid(type), time, next, param); @@ -148,7 +145,7 @@ static HRESULT WINAPI band_track_GetParam(IDirectMusicTrack8 *iface, REFGUID typ static HRESULT WINAPI band_track_SetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time, void *param) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); + struct band_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s, %ld, %p)\n", This, debugstr_dmguid(type), time, param); @@ -183,7 +180,7 @@ static HRESULT WINAPI band_track_SetParam(IDirectMusicTrack8 *iface, REFGUID typ static HRESULT WINAPI band_track_IsParamSupported(IDirectMusicTrack8 *iface, REFGUID rguidType) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); + struct band_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s)\n", This, debugstr_dmguid(rguidType)); @@ -211,7 +208,7 @@ static HRESULT WINAPI band_track_IsParamSupported(IDirectMusicTrack8 *iface, REF static HRESULT WINAPI band_track_AddNotificationType(IDirectMusicTrack8 *iface, REFGUID notiftype) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); + struct band_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype)); return E_NOTIMPL; @@ -220,7 +217,7 @@ static HRESULT WINAPI band_track_AddNotificationType(IDirectMusicTrack8 *iface, static HRESULT WINAPI band_track_RemoveNotificationType(IDirectMusicTrack8 *iface, REFGUID notiftype) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); + struct band_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype)); return E_NOTIMPL; @@ -229,9 +226,9 @@ static HRESULT WINAPI band_track_RemoveNotificationType(IDirectMusicTrack8 *ifac static HRESULT WINAPI band_track_Clone(IDirectMusicTrack8 *iface, MUSIC_TIME mtStart, MUSIC_TIME mtEnd, IDirectMusicTrack **ppTrack) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); - FIXME("(%p, %ld, %ld, %p): stub\n", This, mtStart, mtEnd, ppTrack); - return S_OK; + struct band_track *This = impl_from_IDirectMusicTrack8(iface); + FIXME("(%p, %ld, %ld, %p): stub\n", This, mtStart, mtEnd, ppTrack); + return S_OK; } static HRESULT WINAPI band_track_PlayEx(IDirectMusicTrack8 *iface, void *state_data, @@ -239,7 +236,7 @@ static HRESULT WINAPI band_track_PlayEx(IDirectMusicTrack8 *iface, void *state_d IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state, DWORD virtual_id) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); + struct band_track *This = impl_from_IDirectMusicTrack8(iface); FIXME("(%p, %p, 0x%s, 0x%s, 0x%s, %lx, %p, %p, %ld): stub\n", This, state_data, wine_dbgstr_longlong(rtStart), wine_dbgstr_longlong(rtEnd), wine_dbgstr_longlong(rtOffset), flags, performance, segment_state, virtual_id); @@ -251,7 +248,7 @@ static HRESULT WINAPI band_track_GetParamEx(IDirectMusicTrack8 *iface, REFGUID rguidType, REFERENCE_TIME rtTime, REFERENCE_TIME *rtNext, void *param, void *state_data, DWORD flags) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); + struct band_track *This = impl_from_IDirectMusicTrack8(iface); FIXME("(%p, %s, 0x%s, %p, %p, %p, %lx): stub\n", This, debugstr_dmguid(rguidType), wine_dbgstr_longlong(rtTime), rtNext, param, state_data, flags); @@ -262,7 +259,7 @@ static HRESULT WINAPI band_track_GetParamEx(IDirectMusicTrack8 *iface, static HRESULT WINAPI band_track_SetParamEx(IDirectMusicTrack8 *iface, REFGUID rguidType, REFERENCE_TIME rtTime, void *param, void *state_data, DWORD flags) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); + struct band_track *This = impl_from_IDirectMusicTrack8(iface); FIXME("(%p, %s, 0x%s, %p, %p, %lx): stub\n", This, debugstr_dmguid(rguidType), wine_dbgstr_longlong(rtTime), param, state_data, flags); @@ -273,7 +270,7 @@ static HRESULT WINAPI band_track_SetParamEx(IDirectMusicTrack8 *iface, REFGUID r static HRESULT WINAPI band_track_Compose(IDirectMusicTrack8 *iface, IUnknown *context, DWORD trackgroup, IDirectMusicTrack **track) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); + struct band_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %p, %ld, %p): method not implemented\n", This, context, trackgroup, track); return E_NOTIMPL; @@ -283,12 +280,13 @@ static HRESULT WINAPI band_track_Join(IDirectMusicTrack8 *iface, IDirectMusicTra MUSIC_TIME mtJoin, IUnknown *pContext, DWORD dwTrackGroup, IDirectMusicTrack **ppResultTrack) { - IDirectMusicBandTrack *This = impl_from_IDirectMusicTrack8(iface); - FIXME("(%p, %p, %ld, %p, %ld, %p): stub\n", This, pNewTrack, mtJoin, pContext, dwTrackGroup, ppResultTrack); - return S_OK; + struct band_track *This = impl_from_IDirectMusicTrack8(iface); + FIXME("(%p, %p, %ld, %p, %ld, %p): stub\n", This, pNewTrack, mtJoin, pContext, dwTrackGroup, ppResultTrack); + return S_OK; } -static const IDirectMusicTrack8Vtbl dmtrack8_vtbl = { +static const IDirectMusicTrack8Vtbl band_track_vtbl = +{ band_track_QueryInterface, band_track_AddRef, band_track_Release, @@ -306,11 +304,10 @@ static const IDirectMusicTrack8Vtbl dmtrack8_vtbl = { band_track_GetParamEx, band_track_SetParamEx, band_track_Compose, - band_track_Join + band_track_Join, }; -/* IDirectMusicBandTrack IPersistStream part: */ -static HRESULT load_band(IDirectMusicBandTrack *This, IStream *pClonedStream, +static HRESULT load_band(struct band_track *This, IStream *pClonedStream, IDirectMusicBand **ppBand, DMUS_PRIVATE_BAND_ITEM_HEADER *pHeader) { HRESULT hr = E_FAIL; @@ -352,7 +349,7 @@ static HRESULT load_band(IDirectMusicBandTrack *This, IStream *pClonedStream, return S_OK; } -static HRESULT parse_bands_list(IDirectMusicBandTrack *This, DMUS_PRIVATE_CHUNK *pChunk, +static HRESULT parse_bands_list(struct band_track *This, DMUS_PRIVATE_CHUNK *pChunk, IStream *pStm) { HRESULT hr = E_FAIL; @@ -475,7 +472,7 @@ static HRESULT parse_bands_list(IDirectMusicBandTrack *This, DMUS_PRIVATE_CHUNK return S_OK; } -static HRESULT parse_bandtrack_form(IDirectMusicBandTrack *This, DMUS_PRIVATE_CHUNK *pChunk, +static HRESULT parse_bandtrack_form(struct band_track *This, DMUS_PRIVATE_CHUNK *pChunk, IStream *pStm) { HRESULT hr = E_FAIL; @@ -566,14 +563,14 @@ static HRESULT parse_bandtrack_form(IDirectMusicBandTrack *This, DMUS_PRIVATE_CH return S_OK; } -static inline IDirectMusicBandTrack *impl_from_IPersistStream(IPersistStream *iface) +static inline struct band_track *impl_from_IPersistStream(IPersistStream *iface) { - return CONTAINING_RECORD(iface, IDirectMusicBandTrack, dmobj.IPersistStream_iface); + return CONTAINING_RECORD(iface, struct band_track, dmobj.IPersistStream_iface); } -static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface, IStream *pStm) +static HRESULT WINAPI band_track_persist_stream_Load(IPersistStream *iface, IStream *pStm) { - IDirectMusicBandTrack *This = impl_from_IPersistStream(iface); + struct band_track *This = impl_from_IPersistStream(iface); DMUS_PRIVATE_CHUNK Chunk; LARGE_INTEGER liMove; HRESULT hr; @@ -614,30 +611,30 @@ static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface, IStream *pS return S_OK; } -static const IPersistStreamVtbl persiststream_vtbl = { +static const IPersistStreamVtbl band_track_persist_stream_vtbl = +{ dmobj_IPersistStream_QueryInterface, dmobj_IPersistStream_AddRef, dmobj_IPersistStream_Release, dmobj_IPersistStream_GetClassID, unimpl_IPersistStream_IsDirty, - IPersistStreamImpl_Load, + band_track_persist_stream_Load, unimpl_IPersistStream_Save, - unimpl_IPersistStream_GetSizeMax + unimpl_IPersistStream_GetSizeMax, }; /* for ClassFactory */ HRESULT create_dmbandtrack(REFIID lpcGUID, void **ppobj) { - IDirectMusicBandTrack *track; + struct band_track *track; HRESULT hr; *ppobj = NULL; if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; - track->IDirectMusicTrack8_iface.lpVtbl = &dmtrack8_vtbl; + track->IDirectMusicTrack8_iface.lpVtbl = &band_track_vtbl; track->ref = 1; - dmobject_init(&track->dmobj, &CLSID_DirectMusicBandTrack, - (IUnknown *)&track->IDirectMusicTrack8_iface); - track->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; + dmobject_init(&track->dmobj, &CLSID_DirectMusicBandTrack, (IUnknown *)&track->IDirectMusicTrack8_iface); + track->dmobj.IPersistStream_iface.lpVtbl = &band_track_persist_stream_vtbl; list_init (&track->Bands); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); From 737073a9f41c1c13caa8b07c3dd47f1f582d470e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 14:40:22 +0200 Subject: [PATCH 2539/2777] dmband: Avoid leaking bands on band track Release. (cherry picked from commit 7fb9afea1a15735ded07bbb65056218a4d0e40da) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/bandtrack.c | 45 ++++++++++++++++++++++++++++-------- dlls/dmband/dmband_private.h | 6 ----- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index 53515bc8690..1a3cde5f1db 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -22,13 +22,26 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmband); WINE_DECLARE_DEBUG_CHANNEL(dmfile); +struct band_entry +{ + struct list entry; + DMUS_PRIVATE_BAND_ITEM_HEADER head; + IDirectMusicBand *band; +}; + +static void band_entry_destroy(struct band_entry *entry) +{ + IDirectMusicTrack_Release(entry->band); + free(entry); +} + struct band_track { IDirectMusicTrack8 IDirectMusicTrack8_iface; struct dmobject dmobj; /* IPersistStream only */ LONG ref; DMUS_IO_BAND_TRACK_HEADER header; - struct list Bands; + struct list bands; }; static inline struct band_track *impl_from_IDirectMusicTrack8(IDirectMusicTrack8 *iface) @@ -76,7 +89,18 @@ static ULONG WINAPI band_track_Release(IDirectMusicTrack8 *iface) TRACE("(%p) ref=%ld\n", This, ref); - if (!ref) free(This); + if (!ref) + { + struct band_entry *entry, *next; + + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &This->bands, struct band_entry, entry) + { + list_remove(&entry->entry); + band_entry_destroy(entry); + } + + free(This); + } return ref; } @@ -337,13 +361,14 @@ static HRESULT load_band(struct band_track *This, IStream *pClonedStream, /* * @TODO insert pBand into This */ - if (SUCCEEDED(hr)) { - LPDMUS_PRIVATE_BAND pNewBand; - if (!(pNewBand = calloc(1, sizeof(*pNewBand)))) return E_OUTOFMEMORY; - pNewBand->BandHeader = *pHeader; - pNewBand->band = *ppBand; - IDirectMusicBand_AddRef(*ppBand); - list_add_tail (&This->Bands, &pNewBand->entry); + if (SUCCEEDED(hr)) + { + struct band_entry *entry; + if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY; + entry->head = *pHeader; + entry->band = *ppBand; + IDirectMusicBand_AddRef(*ppBand); + list_add_tail(&This->bands, &entry->entry); } return S_OK; @@ -635,7 +660,7 @@ HRESULT create_dmbandtrack(REFIID lpcGUID, void **ppobj) track->ref = 1; dmobject_init(&track->dmobj, &CLSID_DirectMusicBandTrack, (IUnknown *)&track->IDirectMusicTrack8_iface); track->dmobj.IPersistStream_iface.lpVtbl = &band_track_persist_stream_vtbl; - list_init (&track->Bands); + list_init(&track->bands); hr = IDirectMusicTrack8_QueryInterface(&track->IDirectMusicTrack8_iface, lpcGUID, ppobj); IDirectMusicTrack8_Release(&track->IDirectMusicTrack8_iface); diff --git a/dlls/dmband/dmband_private.h b/dlls/dmband/dmband_private.h index 0b1807eaf93..f4d2bbbbc8e 100644 --- a/dlls/dmband/dmband_private.h +++ b/dlls/dmband/dmband_private.h @@ -67,12 +67,6 @@ typedef struct _DMUS_PRIVATE_INSTRUMENT { IDirectMusicCollection* ppReferenceCollection; } DMUS_PRIVATE_INSTRUMENT, *LPDMUS_PRIVATE_INSTRUMENT; -typedef struct _DMUS_PRIVATE_BAND { - struct list entry; /* for listing elements */ - DMUS_PRIVATE_BAND_ITEM_HEADER BandHeader; - IDirectMusicBand *band; -} DMUS_PRIVATE_BAND, *LPDMUS_PRIVATE_BAND; - /***************************************************************************** * Misc. */ From b8db784bd2e0efcf86742d0da0f07f851fa28af8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 17:23:57 +0200 Subject: [PATCH 2540/2777] dmband: Avoid leaking collection on band release. (cherry picked from commit 9d390da9647db915744bacfda162f0ce7dbea9ae) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/band.c | 40 ++++++++++++++++++++++++++++-------- dlls/dmband/dmband_private.h | 6 ------ 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/dlls/dmband/band.c b/dlls/dmband/band.c index bbf8c93a067..102e58fe39b 100644 --- a/dlls/dmband/band.c +++ b/dlls/dmband/band.c @@ -23,12 +23,25 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmband); WINE_DECLARE_DEBUG_CHANNEL(dmfile); +struct instrument_entry +{ + struct list entry; + DMUS_IO_INSTRUMENT instrument; + IDirectMusicCollection *collection; +}; + +static void instrument_entry_destroy(struct instrument_entry *entry) +{ + if (entry->collection) IDirectMusicCollection_Release(entry->collection); + free(entry); +} + struct band { IDirectMusicBand IDirectMusicBand_iface; struct dmobject dmobj; LONG ref; - struct list Instruments; + struct list instruments; }; static inline struct band *impl_from_IDirectMusicBand(IDirectMusicBand *iface) @@ -77,7 +90,18 @@ static ULONG WINAPI band_Release(IDirectMusicBand *iface) TRACE("(%p) ref=%ld\n", This, ref); - if (!ref) free(This); + if (!ref) + { + struct instrument_entry *entry, *next; + + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &This->instruments, struct instrument_entry, entry) + { + list_remove(&entry->entry); + instrument_entry_destroy(entry); + } + + free(This); + } return ref; } @@ -192,7 +216,7 @@ static HRESULT parse_instrument(struct band *This, DMUS_PRIVATE_CHUNK *pChunk, HRESULT hr; DMUS_IO_INSTRUMENT inst; - LPDMUS_PRIVATE_INSTRUMENT pNewInstrument; + struct instrument_entry *pNewInstrument; IDirectMusicObject* pObject = NULL; if (pChunk->fccID != DMUS_FOURCC_INSTRUMENT_LIST) { @@ -272,8 +296,8 @@ static HRESULT parse_instrument(struct band *This, DMUS_PRIVATE_CHUNK *pChunk, * @TODO insert pNewInstrument into This */ if (!(pNewInstrument = calloc(1, sizeof(*pNewInstrument)))) return E_OUTOFMEMORY; - memcpy(&pNewInstrument->pInstrument, &inst, sizeof(DMUS_IO_INSTRUMENT)); - pNewInstrument->ppReferenceCollection = NULL; + memcpy(&pNewInstrument->instrument, &inst, sizeof(DMUS_IO_INSTRUMENT)); + pNewInstrument->collection = NULL; if (NULL != pObject) { IDirectMusicCollection* pCol = NULL; hr = IDirectMusicObject_QueryInterface (pObject, &IID_IDirectMusicCollection, (void**) &pCol); @@ -282,10 +306,10 @@ static HRESULT parse_instrument(struct band *This, DMUS_PRIVATE_CHUNK *pChunk, free(pNewInstrument); return hr; } - pNewInstrument->ppReferenceCollection = pCol; + pNewInstrument->collection = pCol; IDirectMusicObject_Release(pObject); } - list_add_tail (&This->Instruments, &pNewInstrument->entry); + list_add_tail(&This->instruments, &pNewInstrument->entry); return S_OK; } @@ -510,7 +534,7 @@ HRESULT create_dmband(REFIID lpcGUID, void **ppobj) dmobject_init(&obj->dmobj, &CLSID_DirectMusicBand, (IUnknown *)&obj->IDirectMusicBand_iface); obj->dmobj.IDirectMusicObject_iface.lpVtbl = &band_object_vtbl; obj->dmobj.IPersistStream_iface.lpVtbl = &band_persist_stream_vtbl; - list_init (&obj->Instruments); + list_init(&obj->instruments); hr = IDirectMusicBand_QueryInterface(&obj->IDirectMusicBand_iface, lpcGUID, ppobj); IDirectMusicBand_Release(&obj->IDirectMusicBand_iface); diff --git a/dlls/dmband/dmband_private.h b/dlls/dmband/dmband_private.h index f4d2bbbbc8e..da6f0fa302f 100644 --- a/dlls/dmband/dmband_private.h +++ b/dlls/dmband/dmband_private.h @@ -61,12 +61,6 @@ typedef struct _DMUS_PRIVATE_BAND_ITEM_HEADER { MUSIC_TIME lBandTimePhysical; } DMUS_PRIVATE_BAND_ITEM_HEADER; -typedef struct _DMUS_PRIVATE_INSTRUMENT { - struct list entry; /* for listing elements */ - DMUS_IO_INSTRUMENT pInstrument; - IDirectMusicCollection* ppReferenceCollection; -} DMUS_PRIVATE_INSTRUMENT, *LPDMUS_PRIVATE_INSTRUMENT; - /***************************************************************************** * Misc. */ From cd6d538dea54d417302583541297bc00578f5377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 17:24:30 +0200 Subject: [PATCH 2541/2777] dmband: Rewrite band lbin list parsing. (cherry picked from commit dfcb827318b17b2b166b523c8d655b981ab930d3) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/band.c | 180 +++++++++++++++++---------------------------- 1 file changed, 69 insertions(+), 111 deletions(-) diff --git a/dlls/dmband/band.c b/dlls/dmband/band.c index 102e58fe39b..fa6fd35580e 100644 --- a/dlls/dmband/band.c +++ b/dlls/dmband/band.c @@ -156,6 +156,70 @@ static const IDirectMusicBandVtbl band_vtbl = band_Unload, }; +static HRESULT parse_lbin_list(struct band *This, IStream *stream, struct chunk_entry *parent) +{ + struct chunk_entry chunk = {.parent = parent}; + IDirectMusicCollection *collection = NULL; + struct instrument_entry *entry; + DMUS_IO_INSTRUMENT inst = {0}; + HRESULT hr; + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case DMUS_FOURCC_INSTRUMENT_CHUNK: + { + UINT size = sizeof(inst); + + if (chunk.size == offsetof(DMUS_IO_INSTRUMENT, nPitchBendRange)) size = chunk.size; + if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &inst, size))) break; + TRACE_(dmfile)(" - dwPatch: %lu\n", inst.dwPatch); + TRACE_(dmfile)(" - dwAssignPatch: %lu\n", inst.dwAssignPatch); + TRACE_(dmfile)(" - dwNoteRanges[0]: %lu\n", inst.dwNoteRanges[0]); + TRACE_(dmfile)(" - dwNoteRanges[1]: %lu\n", inst.dwNoteRanges[1]); + TRACE_(dmfile)(" - dwNoteRanges[2]: %lu\n", inst.dwNoteRanges[2]); + TRACE_(dmfile)(" - dwNoteRanges[3]: %lu\n", inst.dwNoteRanges[3]); + TRACE_(dmfile)(" - dwPChannel: %lu\n", inst.dwPChannel); + TRACE_(dmfile)(" - dwFlags: %lx\n", inst.dwFlags); + TRACE_(dmfile)(" - bPan: %u\n", inst.bPan); + TRACE_(dmfile)(" - bVolume: %u\n", inst.bVolume); + TRACE_(dmfile)(" - nTranspose: %d\n", inst.nTranspose); + TRACE_(dmfile)(" - dwChannelPriority: %lu\n", inst.dwChannelPriority); + TRACE_(dmfile)(" - nPitchBendRange: %d\n", inst.nPitchBendRange); + break; + } + + case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_REF_LIST): + { + IDirectMusicObject *object; + + if (FAILED(hr = dmobj_parsereference(stream, &chunk, &object))) break; + TRACE_(dmfile)(" - object: %p\n", object); + + hr = IDirectMusicObject_QueryInterface(object, &IID_IDirectMusicCollection, (void **)&collection); + IDirectMusicObject_Release(object); + break; + } + + default: + FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; + } + + if (FAILED(hr)) return hr; + + if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY; + memcpy(&entry->instrument, &inst, sizeof(DMUS_IO_INSTRUMENT)); + entry->collection = collection; + list_add_tail(&This->instruments, &entry->entry); + + return hr; +} + static HRESULT WINAPI band_object_ParseDescriptor(IDirectMusicObject *iface, IStream *stream, DMUS_OBJECTDESC *desc) { @@ -205,115 +269,6 @@ static const IDirectMusicObjectVtbl band_object_vtbl = band_object_ParseDescriptor, }; -#define DMUS_IO_INSTRUMENT_DX7_SIZE offsetof(DMUS_IO_INSTRUMENT, nPitchBendRange) - -static HRESULT parse_instrument(struct band *This, DMUS_PRIVATE_CHUNK *pChunk, - IStream *pStm) -{ - DMUS_PRIVATE_CHUNK Chunk; - DWORD ListSize[3], ListCount[3]; - LARGE_INTEGER liMove; /* used when skipping chunks */ - HRESULT hr; - - DMUS_IO_INSTRUMENT inst; - struct instrument_entry *pNewInstrument; - IDirectMusicObject* pObject = NULL; - - if (pChunk->fccID != DMUS_FOURCC_INSTRUMENT_LIST) { - ERR_(dmfile)(": %s chunk should be an INSTRUMENT list\n", debugstr_fourcc (pChunk->fccID)); - return E_FAIL; - } - - ListSize[0] = pChunk->dwSize - sizeof(FOURCC); - ListCount[0] = 0; - - do { - IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); - ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); - switch (Chunk.fccID) { - case DMUS_FOURCC_INSTRUMENT_CHUNK: { - TRACE_(dmfile)(": Instrument chunk\n"); - if (Chunk.dwSize != sizeof(DMUS_IO_INSTRUMENT) && Chunk.dwSize != DMUS_IO_INSTRUMENT_DX7_SIZE) { - ERR_(dmfile)("unexpected size %ld\n", Chunk.dwSize); - return E_FAIL; - } - IStream_Read (pStm, &inst, Chunk.dwSize, NULL); - if (Chunk.dwSize != sizeof(DMUS_IO_INSTRUMENT)) - inst.nPitchBendRange = 0; - - TRACE_(dmfile)(" - dwPatch: %lu\n", inst.dwPatch); - TRACE_(dmfile)(" - dwAssignPatch: %lu\n", inst.dwAssignPatch); - TRACE_(dmfile)(" - dwNoteRanges[0]: %lu\n", inst.dwNoteRanges[0]); - TRACE_(dmfile)(" - dwNoteRanges[1]: %lu\n", inst.dwNoteRanges[1]); - TRACE_(dmfile)(" - dwNoteRanges[2]: %lu\n", inst.dwNoteRanges[2]); - TRACE_(dmfile)(" - dwNoteRanges[3]: %lu\n", inst.dwNoteRanges[3]); - TRACE_(dmfile)(" - dwPChannel: %lu\n", inst.dwPChannel); - TRACE_(dmfile)(" - dwFlags: %lx\n", inst.dwFlags); - TRACE_(dmfile)(" - bPan: %u\n", inst.bPan); - TRACE_(dmfile)(" - bVolume: %u\n", inst.bVolume); - TRACE_(dmfile)(" - nTranspose: %d\n", inst.nTranspose); - TRACE_(dmfile)(" - dwChannelPriority: %lu\n", inst.dwChannelPriority); - TRACE_(dmfile)(" - nPitchBendRange: %d\n", inst.nPitchBendRange); - break; - } - case FOURCC_LIST: { - IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL); - TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID)); - ListSize[1] = Chunk.dwSize - sizeof(FOURCC); - ListCount[1] = 0; - switch (Chunk.fccID) { - case DMUS_FOURCC_REF_LIST: { - FIXME_(dmfile)(": DMRF (DM References) list\n"); - hr = IDirectMusicUtils_IPersistStream_ParseReference(&This->dmobj.IPersistStream_iface, - &Chunk, pStm, &pObject); - if (FAILED(hr)) { - ERR(": could not load Reference\n"); - return hr; - } - break; - } - default: { - TRACE_(dmfile)(": unknown (skipping)\n"); - liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC); - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - break; - } - default: { - TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]); - } while (ListCount[0] < ListSize[0]); - - /* - * @TODO insert pNewInstrument into This - */ - if (!(pNewInstrument = calloc(1, sizeof(*pNewInstrument)))) return E_OUTOFMEMORY; - memcpy(&pNewInstrument->instrument, &inst, sizeof(DMUS_IO_INSTRUMENT)); - pNewInstrument->collection = NULL; - if (NULL != pObject) { - IDirectMusicCollection* pCol = NULL; - hr = IDirectMusicObject_QueryInterface (pObject, &IID_IDirectMusicCollection, (void**) &pCol); - if (FAILED(hr)) { - ERR(": failed to get IDirectMusicCollection Interface from DMObject\n"); - free(pNewInstrument); - return hr; - } - pNewInstrument->collection = pCol; - IDirectMusicObject_Release(pObject); - } - list_add_tail(&This->instruments, &pNewInstrument->entry); - - return S_OK; -} - static HRESULT parse_instruments_list(struct band *This, DMUS_PRIVATE_CHUNK *pChunk, IStream *pStm) { @@ -342,9 +297,12 @@ static HRESULT parse_instruments_list(struct band *This, DMUS_PRIVATE_CHUNK *pCh ListCount[1] = 0; switch (Chunk.fccID) { case DMUS_FOURCC_INSTRUMENT_LIST: { + static const LARGE_INTEGER zero = {0}; + struct chunk_entry chunk = {FOURCC_LIST, .size = Chunk.dwSize, .type = Chunk.fccID}; TRACE_(dmfile)(": Instrument list\n"); - hr = parse_instrument(This, &Chunk, pStm); - if (FAILED(hr)) return hr; + IStream_Seek(pStm, zero, STREAM_SEEK_CUR, &chunk.offset); + chunk.offset.QuadPart -= 12; + if (FAILED(hr = parse_lbin_list(This, pStm, &chunk))) return hr; break; } default: { From eb2e46eb41bacfccbe10524fa676c4836c48b28a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 18:14:13 +0200 Subject: [PATCH 2542/2777] dmband: Rewrite band lbil list parsing. (cherry picked from commit ba69ffeff4b63a91e9b4116523945a811257507f) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/band.c | 88 +++++++++++++++------------------------------- 1 file changed, 29 insertions(+), 59 deletions(-) diff --git a/dlls/dmband/band.c b/dlls/dmband/band.c index fa6fd35580e..6ed31075f42 100644 --- a/dlls/dmband/band.c +++ b/dlls/dmband/band.c @@ -220,6 +220,30 @@ static HRESULT parse_lbin_list(struct band *This, IStream *stream, struct chunk_ return hr; } +static HRESULT parse_lbil_list(struct band *This, IStream *stream, struct chunk_entry *parent) +{ + struct chunk_entry chunk = {.parent = parent}; + HRESULT hr; + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_INSTRUMENT_LIST): + hr = parse_lbin_list(This, stream, &chunk); + break; + + default: + FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; + } + + return hr; +} + static HRESULT WINAPI band_object_ParseDescriptor(IDirectMusicObject *iface, IStream *stream, DMUS_OBJECTDESC *desc) { @@ -269,64 +293,6 @@ static const IDirectMusicObjectVtbl band_object_vtbl = band_object_ParseDescriptor, }; -static HRESULT parse_instruments_list(struct band *This, DMUS_PRIVATE_CHUNK *pChunk, - IStream *pStm) -{ - HRESULT hr; - DMUS_PRIVATE_CHUNK Chunk; - DWORD ListSize[3], ListCount[3]; - LARGE_INTEGER liMove; /* used when skipping chunks */ - - if (pChunk->fccID != DMUS_FOURCC_INSTRUMENTS_LIST) { - ERR_(dmfile)(": %s chunk should be an INSTRUMENTS list\n", debugstr_fourcc (pChunk->fccID)); - return E_FAIL; - } - - ListSize[0] = pChunk->dwSize - sizeof(FOURCC); - ListCount[0] = 0; - - do { - IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); - ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); - switch (Chunk.fccID) { - case FOURCC_LIST: { - IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL); - TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID)); - ListSize[1] = Chunk.dwSize - sizeof(FOURCC); - ListCount[1] = 0; - switch (Chunk.fccID) { - case DMUS_FOURCC_INSTRUMENT_LIST: { - static const LARGE_INTEGER zero = {0}; - struct chunk_entry chunk = {FOURCC_LIST, .size = Chunk.dwSize, .type = Chunk.fccID}; - TRACE_(dmfile)(": Instrument list\n"); - IStream_Seek(pStm, zero, STREAM_SEEK_CUR, &chunk.offset); - chunk.offset.QuadPart -= 12; - if (FAILED(hr = parse_lbin_list(This, pStm, &chunk))) return hr; - break; - } - default: { - TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); - liMove.QuadPart = ListSize[1]; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - break; - } - default: { - TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]); - } while (ListCount[0] < ListSize[0]); - - return S_OK; -} - static HRESULT parse_band_form(struct band *This, DMUS_PRIVATE_CHUNK *pChunk, IStream *pStm) { @@ -392,8 +358,12 @@ static HRESULT parse_band_form(struct band *This, DMUS_PRIVATE_CHUNK *pChunk, break; } case DMUS_FOURCC_INSTRUMENTS_LIST: { + static const LARGE_INTEGER zero = {0}; + struct chunk_entry chunk = {FOURCC_LIST, .size = Chunk.dwSize, .type = Chunk.fccID}; TRACE_(dmfile)(": INSTRUMENTS list\n"); - hr = parse_instruments_list(This, &Chunk, pStm); + IStream_Seek(pStm, zero, STREAM_SEEK_CUR, &chunk.offset); + chunk.offset.QuadPart -= 12; + hr = parse_lbil_list(This, pStm, &chunk); if (FAILED(hr)) return hr; break; } From 5890feb58907716e3b8cc11bf02f86e814c51455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 18:14:41 +0200 Subject: [PATCH 2543/2777] dmband: Rewrite band dmbd chunk parsing. (cherry picked from commit b2f1e97813a509221a3a4caa931393f899d1f0c4) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/band.c | 138 +++++++++++++-------------------------------- 1 file changed, 40 insertions(+), 98 deletions(-) diff --git a/dlls/dmband/band.c b/dlls/dmband/band.c index 6ed31075f42..b732595f19d 100644 --- a/dlls/dmband/band.c +++ b/dlls/dmband/band.c @@ -244,6 +244,41 @@ static HRESULT parse_lbil_list(struct band *This, IStream *stream, struct chunk_ return hr; } +static HRESULT parse_dmbd_chunk(struct band *This, IStream *stream, struct chunk_entry *parent) +{ + struct chunk_entry chunk = {.parent = parent}; + HRESULT hr; + + if (FAILED(hr = dmobj_parsedescriptor(stream, parent, &This->dmobj.desc, + DMUS_OBJ_OBJECT|DMUS_OBJ_NAME|DMUS_OBJ_NAME_INAM|DMUS_OBJ_CATEGORY|DMUS_OBJ_VERSION)) + || FAILED(hr = stream_reset_chunk_data(stream, parent))) + return hr; + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case DMUS_FOURCC_GUID_CHUNK: + case DMUS_FOURCC_VERSION_CHUNK: + case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_UNFO_LIST): + /* already parsed by dmobj_parsedescriptor */ + break; + + case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_INSTRUMENTS_LIST): + hr = parse_lbil_list(This, stream, &chunk); + break; + + default: + FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; + } + + return hr; +} + static HRESULT WINAPI band_object_ParseDescriptor(IDirectMusicObject *iface, IStream *stream, DMUS_OBJECTDESC *desc) { @@ -293,103 +328,6 @@ static const IDirectMusicObjectVtbl band_object_vtbl = band_object_ParseDescriptor, }; -static HRESULT parse_band_form(struct band *This, DMUS_PRIVATE_CHUNK *pChunk, - IStream *pStm) -{ - HRESULT hr = E_FAIL; - DMUS_PRIVATE_CHUNK Chunk; - DWORD StreamSize, StreamCount, ListSize[3], ListCount[3]; - LARGE_INTEGER liMove; /* used when skipping chunks */ - - GUID tmp_guid; - - if (pChunk->fccID != DMUS_FOURCC_BAND_FORM) { - ERR_(dmfile)(": %s chunk should be a BAND form\n", debugstr_fourcc (pChunk->fccID)); - return E_FAIL; - } - - StreamSize = pChunk->dwSize - sizeof(FOURCC); - StreamCount = 0; - - do { - IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); - StreamCount += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); - - hr = IDirectMusicUtils_IPersistStream_ParseDescGeneric(&Chunk, pStm, &This->dmobj.desc); - if (FAILED(hr)) return hr; - - if (hr == S_FALSE) { - switch (Chunk.fccID) { - case DMUS_FOURCC_GUID_CHUNK: { - TRACE_(dmfile)(": GUID\n"); - IStream_Read (pStm, &tmp_guid, sizeof(GUID), NULL); - TRACE_(dmfile)(" - guid: %s\n", debugstr_dmguid(&tmp_guid)); - break; - } - case FOURCC_LIST: { - IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL); - TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID)); - ListSize[0] = Chunk.dwSize - sizeof(FOURCC); - ListCount[0] = 0; - switch (Chunk.fccID) { - case DMUS_FOURCC_UNFO_LIST: { - TRACE_(dmfile)(": UNFO list\n"); - do { - IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); - ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); - - hr = IDirectMusicUtils_IPersistStream_ParseUNFOGeneric(&Chunk, pStm, &This->dmobj.desc); - if (FAILED(hr)) return hr; - - if (hr == S_FALSE) { - switch (Chunk.fccID) { - default: { - TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - } - TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]); - } while (ListCount[0] < ListSize[0]); - break; - } - case DMUS_FOURCC_INSTRUMENTS_LIST: { - static const LARGE_INTEGER zero = {0}; - struct chunk_entry chunk = {FOURCC_LIST, .size = Chunk.dwSize, .type = Chunk.fccID}; - TRACE_(dmfile)(": INSTRUMENTS list\n"); - IStream_Seek(pStm, zero, STREAM_SEEK_CUR, &chunk.offset); - chunk.offset.QuadPart -= 12; - hr = parse_lbil_list(This, pStm, &chunk); - if (FAILED(hr)) return hr; - break; - } - default: { - TRACE_(dmfile)(": unknown (skipping)\n"); - liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC); - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - break; - } - default: { - TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - } - TRACE_(dmfile)(": StreamCount[0] = %ld < StreamSize[0] = %ld\n", StreamCount, StreamSize); - } while (StreamCount < StreamSize); - - return S_OK; -} - static inline struct band *impl_from_IPersistStream(IPersistStream *iface) { return CONTAINING_RECORD(iface, struct band, dmobj.IPersistStream_iface); @@ -412,8 +350,12 @@ static HRESULT WINAPI band_persist_stream_Load(IPersistStream *iface, IStream *p TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); switch (Chunk.fccID) { case DMUS_FOURCC_BAND_FORM: { + static const LARGE_INTEGER zero = {0}; + struct chunk_entry chunk = {FOURCC_LIST, .size = Chunk.dwSize, .type = Chunk.fccID}; TRACE_(dmfile)(": Band form\n"); - hr = parse_band_form(This, &Chunk, pStm); + IStream_Seek(pStm, zero, STREAM_SEEK_CUR, &chunk.offset); + chunk.offset.QuadPart -= 12; + hr = parse_dmbd_chunk(This, pStm, &chunk); if (FAILED(hr)) return hr; break; } From b6da1f9fc62770ab557143ab275f957a49cc6529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 17:37:39 +0200 Subject: [PATCH 2544/2777] dmband: Rewrite band IPersistStream_Load. (cherry picked from commit 94c1dd8a6e69425319bb3145c592e8e5846cd9e9) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/band.c | 117 ++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 60 deletions(-) diff --git a/dlls/dmband/band.c b/dlls/dmband/band.c index b732595f19d..d91775681bb 100644 --- a/dlls/dmband/band.c +++ b/dlls/dmband/band.c @@ -21,7 +21,24 @@ #include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmband); -WINE_DECLARE_DEBUG_CHANNEL(dmfile); + +void dump_DMUS_IO_INSTRUMENT(DMUS_IO_INSTRUMENT *inst) +{ + TRACE("DMUS_IO_INSTRUMENT: %p\n", inst); + TRACE(" - dwPatch: %lu\n", inst->dwPatch); + TRACE(" - dwAssignPatch: %lu\n", inst->dwAssignPatch); + TRACE(" - dwNoteRanges[0]: %lu\n", inst->dwNoteRanges[0]); + TRACE(" - dwNoteRanges[1]: %lu\n", inst->dwNoteRanges[1]); + TRACE(" - dwNoteRanges[2]: %lu\n", inst->dwNoteRanges[2]); + TRACE(" - dwNoteRanges[3]: %lu\n", inst->dwNoteRanges[3]); + TRACE(" - dwPChannel: %lu\n", inst->dwPChannel); + TRACE(" - dwFlags: %lx\n", inst->dwFlags); + TRACE(" - bPan: %u\n", inst->bPan); + TRACE(" - bVolume: %u\n", inst->bVolume); + TRACE(" - nTranspose: %d\n", inst->nTranspose); + TRACE(" - dwChannelPriority: %lu\n", inst->dwChannelPriority); + TRACE(" - nPitchBendRange: %d\n", inst->nPitchBendRange); +} struct instrument_entry { @@ -171,32 +188,15 @@ static HRESULT parse_lbin_list(struct band *This, IStream *stream, struct chunk_ case DMUS_FOURCC_INSTRUMENT_CHUNK: { UINT size = sizeof(inst); - if (chunk.size == offsetof(DMUS_IO_INSTRUMENT, nPitchBendRange)) size = chunk.size; if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &inst, size))) break; - TRACE_(dmfile)(" - dwPatch: %lu\n", inst.dwPatch); - TRACE_(dmfile)(" - dwAssignPatch: %lu\n", inst.dwAssignPatch); - TRACE_(dmfile)(" - dwNoteRanges[0]: %lu\n", inst.dwNoteRanges[0]); - TRACE_(dmfile)(" - dwNoteRanges[1]: %lu\n", inst.dwNoteRanges[1]); - TRACE_(dmfile)(" - dwNoteRanges[2]: %lu\n", inst.dwNoteRanges[2]); - TRACE_(dmfile)(" - dwNoteRanges[3]: %lu\n", inst.dwNoteRanges[3]); - TRACE_(dmfile)(" - dwPChannel: %lu\n", inst.dwPChannel); - TRACE_(dmfile)(" - dwFlags: %lx\n", inst.dwFlags); - TRACE_(dmfile)(" - bPan: %u\n", inst.bPan); - TRACE_(dmfile)(" - bVolume: %u\n", inst.bVolume); - TRACE_(dmfile)(" - nTranspose: %d\n", inst.nTranspose); - TRACE_(dmfile)(" - dwChannelPriority: %lu\n", inst.dwChannelPriority); - TRACE_(dmfile)(" - nPitchBendRange: %d\n", inst.nPitchBendRange); break; } case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_REF_LIST): { IDirectMusicObject *object; - if (FAILED(hr = dmobj_parsereference(stream, &chunk, &object))) break; - TRACE_(dmfile)(" - object: %p\n", object); - hr = IDirectMusicObject_QueryInterface(object, &IID_IDirectMusicCollection, (void **)&collection); IDirectMusicObject_Release(object); break; @@ -333,51 +333,48 @@ static inline struct band *impl_from_IPersistStream(IPersistStream *iface) return CONTAINING_RECORD(iface, struct band, dmobj.IPersistStream_iface); } -static HRESULT WINAPI band_persist_stream_Load(IPersistStream *iface, IStream *pStm) +static HRESULT WINAPI band_persist_stream_Load(IPersistStream *iface, IStream *stream) { - struct band *This = impl_from_IPersistStream(iface); - DMUS_PRIVATE_CHUNK Chunk; - LARGE_INTEGER liMove; - HRESULT hr; - - TRACE("(%p,%p): loading\n", This, pStm); - - IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); - TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); - switch (Chunk.fccID) { - case FOURCC_RIFF: { - IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL); - TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); - switch (Chunk.fccID) { - case DMUS_FOURCC_BAND_FORM: { - static const LARGE_INTEGER zero = {0}; - struct chunk_entry chunk = {FOURCC_LIST, .size = Chunk.dwSize, .type = Chunk.fccID}; - TRACE_(dmfile)(": Band form\n"); - IStream_Seek(pStm, zero, STREAM_SEEK_CUR, &chunk.offset); - chunk.offset.QuadPart -= 12; - hr = parse_dmbd_chunk(This, pStm, &chunk); - if (FAILED(hr)) return hr; - break; - } - default: { - TRACE_(dmfile)(": unexpected chunk; loading failed)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - return E_FAIL; + struct band *This = impl_from_IPersistStream(iface); + struct chunk_entry chunk = {0}; + HRESULT hr; + + TRACE("%p, %p\n", iface, stream); + + if ((hr = stream_get_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case MAKE_IDTYPE(FOURCC_RIFF, DMUS_FOURCC_BAND_FORM): + hr = parse_dmbd_chunk(This, stream, &chunk); + break; + + default: + WARN("Invalid band chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + hr = DMUS_E_UNSUPPORTED_STREAM; + break; + } } + + if (FAILED(hr)) return hr; + + if (TRACE_ON(dmband)) + { + struct instrument_entry *entry; + + TRACE("Loaded IDirectMusicBand %p\n", This); + dump_DMUS_OBJECTDESC(&This->dmobj.desc); + + TRACE(" - Instruments:\n"); + LIST_FOR_EACH_ENTRY(entry, &This->instruments, struct instrument_entry, entry) + { + dump_DMUS_IO_INSTRUMENT(&entry->instrument); + TRACE(" - collection: %p\n", entry->collection); + } } - TRACE_(dmfile)(": reading finished\n"); - break; - } - default: { - TRACE_(dmfile)(": unexpected chunk; loading failed)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */ - return E_FAIL; - } - } - - return S_OK; + + stream_skip_chunk(stream, &chunk); + return S_OK; } static const IPersistStreamVtbl band_persist_stream_vtbl = From 8f6652107f86aca51be8010ee2c002c50bdf3947 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 13:47:50 +0200 Subject: [PATCH 2545/2777] dmime: Rename IDirectMusicSegment8Impl method prefix to segment. (cherry picked from commit 3ff263deba21e043360546ce7c0c0feb95558e0c) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segment.c | 199 +++++++++++++++++++------------------------ 1 file changed, 88 insertions(+), 111 deletions(-) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index 39a5333fbbb..f86e4a2bb5f 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -39,15 +39,14 @@ typedef struct IDirectMusicSegment8Impl { int data_size; } IDirectMusicSegment8Impl; -IDirectMusicSegment8Impl *create_segment(void); +static IDirectMusicSegment8Impl *segment_create(void); static inline IDirectMusicSegment8Impl *impl_from_IDirectMusicSegment8(IDirectMusicSegment8 *iface) { return CONTAINING_RECORD(iface, IDirectMusicSegment8Impl, IDirectMusicSegment8_iface); } -static HRESULT WINAPI IDirectMusicSegment8Impl_QueryInterface(IDirectMusicSegment8 *iface, - REFIID riid, void **ret_iface) +static HRESULT WINAPI segment_QueryInterface(IDirectMusicSegment8 *iface, REFIID riid, void **ret_iface) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); @@ -72,7 +71,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_QueryInterface(IDirectMusicSegmen return S_OK; } -static ULONG WINAPI IDirectMusicSegment8Impl_AddRef(IDirectMusicSegment8 *iface) +static ULONG WINAPI segment_AddRef(IDirectMusicSegment8 *iface) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); LONG ref = InterlockedIncrement(&This->ref); @@ -82,7 +81,7 @@ static ULONG WINAPI IDirectMusicSegment8Impl_AddRef(IDirectMusicSegment8 *iface) return ref; } -static ULONG WINAPI IDirectMusicSegment8Impl_Release(IDirectMusicSegment8 *iface) +static ULONG WINAPI segment_Release(IDirectMusicSegment8 *iface) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); LONG ref = InterlockedDecrement(&This->ref); @@ -99,8 +98,7 @@ static ULONG WINAPI IDirectMusicSegment8Impl_Release(IDirectMusicSegment8 *iface return ref; } -static HRESULT WINAPI IDirectMusicSegment8Impl_GetLength(IDirectMusicSegment8 *iface, - MUSIC_TIME *pmtLength) +static HRESULT WINAPI segment_GetLength(IDirectMusicSegment8 *iface, MUSIC_TIME *pmtLength) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); @@ -112,8 +110,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_GetLength(IDirectMusicSegment8 *i return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_SetLength(IDirectMusicSegment8 *iface, - MUSIC_TIME mtLength) +static HRESULT WINAPI segment_SetLength(IDirectMusicSegment8 *iface, MUSIC_TIME mtLength) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); @@ -122,8 +119,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_SetLength(IDirectMusicSegment8 *i return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_GetRepeats(IDirectMusicSegment8 *iface, - DWORD *pdwRepeats) +static HRESULT WINAPI segment_GetRepeats(IDirectMusicSegment8 *iface, DWORD *pdwRepeats) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); @@ -135,8 +131,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_GetRepeats(IDirectMusicSegment8 * return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_SetRepeats(IDirectMusicSegment8 *iface, - DWORD dwRepeats) +static HRESULT WINAPI segment_SetRepeats(IDirectMusicSegment8 *iface, DWORD dwRepeats) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); @@ -145,8 +140,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_SetRepeats(IDirectMusicSegment8 * return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_GetDefaultResolution(IDirectMusicSegment8 *iface, - DWORD *pdwResolution) +static HRESULT WINAPI segment_GetDefaultResolution(IDirectMusicSegment8 *iface, DWORD *pdwResolution) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); @@ -158,8 +152,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_GetDefaultResolution(IDirectMusic return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_SetDefaultResolution(IDirectMusicSegment8 *iface, - DWORD dwResolution) +static HRESULT WINAPI segment_SetDefaultResolution(IDirectMusicSegment8 *iface, DWORD dwResolution) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); @@ -168,8 +161,8 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_SetDefaultResolution(IDirectMusic return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_GetTrack(IDirectMusicSegment8 *iface, - REFGUID rguidType, DWORD dwGroupBits, DWORD dwIndex, IDirectMusicTrack **ppTrack) +static HRESULT WINAPI segment_GetTrack(IDirectMusicSegment8 *iface, REFGUID rguidType, + DWORD dwGroupBits, DWORD dwIndex, IDirectMusicTrack **ppTrack) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); CLSID pIt_clsid; @@ -217,8 +210,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_GetTrack(IDirectMusicSegment8 *if return DMUS_E_NOT_FOUND; } -static HRESULT WINAPI IDirectMusicSegment8Impl_GetTrackGroup(IDirectMusicSegment8 *iface, - IDirectMusicTrack *pTrack, DWORD *pdwGroupBits) +static HRESULT WINAPI segment_GetTrackGroup(IDirectMusicSegment8 *iface, IDirectMusicTrack *pTrack, DWORD *pdwGroupBits) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); struct list* pEntry = NULL; @@ -242,8 +234,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_GetTrackGroup(IDirectMusicSegment return DMUS_E_NOT_FOUND; } -static HRESULT WINAPI IDirectMusicSegment8Impl_InsertTrack(IDirectMusicSegment8 *iface, - IDirectMusicTrack *pTrack, DWORD group) +static HRESULT WINAPI segment_InsertTrack(IDirectMusicSegment8 *iface, IDirectMusicTrack *pTrack, DWORD group) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); DWORD i = 0; @@ -277,8 +268,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_InsertTrack(IDirectMusicSegment8 return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_RemoveTrack(IDirectMusicSegment8 *iface, - IDirectMusicTrack *pTrack) +static HRESULT WINAPI segment_RemoveTrack(IDirectMusicSegment8 *iface, IDirectMusicTrack *pTrack) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); struct list* pEntry = NULL; @@ -303,7 +293,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_RemoveTrack(IDirectMusicSegment8 return S_FALSE; } -static HRESULT WINAPI IDirectMusicSegment8Impl_InitPlay(IDirectMusicSegment8 *iface, +static HRESULT WINAPI segment_InitPlay(IDirectMusicSegment8 *iface, IDirectMusicSegmentState **ppSegState, IDirectMusicPerformance *pPerformance, DWORD dwFlags) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); @@ -321,8 +311,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_InitPlay(IDirectMusicSegment8 *if return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_GetGraph(IDirectMusicSegment8 *iface, - IDirectMusicGraph **ppGraph) +static HRESULT WINAPI segment_GetGraph(IDirectMusicSegment8 *iface, IDirectMusicGraph **ppGraph) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); @@ -342,8 +331,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_GetGraph(IDirectMusicSegment8 *if return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_SetGraph(IDirectMusicSegment8 *iface, - IDirectMusicGraph *pGraph) +static HRESULT WINAPI segment_SetGraph(IDirectMusicSegment8 *iface, IDirectMusicGraph *pGraph) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); @@ -358,24 +346,22 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_SetGraph(IDirectMusicSegment8 *if return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_AddNotificationType(IDirectMusicSegment8 *iface, - REFGUID rguidNotificationType) +static HRESULT WINAPI segment_AddNotificationType(IDirectMusicSegment8 *iface, REFGUID rguidNotificationType) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType)); return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_RemoveNotificationType(IDirectMusicSegment8 *iface, - REFGUID rguidNotificationType) +static HRESULT WINAPI segment_RemoveNotificationType(IDirectMusicSegment8 *iface, REFGUID rguidNotificationType) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType)); return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_GetParam(IDirectMusicSegment8 *iface, REFGUID type, - DWORD group, DWORD index, MUSIC_TIME time, MUSIC_TIME *next, void *param) +static HRESULT WINAPI segment_GetParam(IDirectMusicSegment8 *iface, REFGUID type, DWORD group, + DWORD index, MUSIC_TIME time, MUSIC_TIME *next, void *param) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); IDirectMusicTrack *track; @@ -390,8 +376,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_GetParam(IDirectMusicSegment8 *if /* Index is relative to the search pattern: group bits and supported param type */ for (i = 0, count = 0; i < DMUS_SEG_ANYTRACK && count <= index; i++) { - if (FAILED(IDirectMusicSegment8Impl_GetTrack(iface, &GUID_NULL, group, i, &track))) - break; + if (FAILED(segment_GetTrack(iface, &GUID_NULL, group, i, &track))) break; if (FAILED(IDirectMusicTrack_IsParamSupported(track, type))) continue; if (index == count || index == DMUS_SEG_ANYTRACK) @@ -408,15 +393,15 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_GetParam(IDirectMusicSegment8 *if return hr; } -static HRESULT WINAPI IDirectMusicSegment8Impl_SetParam(IDirectMusicSegment8 *iface, - REFGUID rguidType, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, void *pParam) +static HRESULT WINAPI segment_SetParam(IDirectMusicSegment8 *iface, REFGUID rguidType, + DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, void *pParam) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); FIXME("(%p, %s, %#lx, %ld, %ld, %p): stub\n", This, debugstr_dmguid(rguidType), dwGroupBits, dwIndex, mtTime, pParam); return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_Clone(IDirectMusicSegment8 *iface, MUSIC_TIME start, MUSIC_TIME end, +static HRESULT WINAPI segment_Clone(IDirectMusicSegment8 *iface, MUSIC_TIME start, MUSIC_TIME end, IDirectMusicSegment **segment) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); @@ -431,7 +416,8 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_Clone(IDirectMusicSegment8 *iface if (!segment) return E_POINTER; - if (!(clone = create_segment())) { + if (!(clone = segment_create())) + { *segment = NULL; return E_OUTOFMEMORY; } @@ -465,8 +451,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_Clone(IDirectMusicSegment8 *iface return track_clone_fail ? S_FALSE : S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_SetStartPoint(IDirectMusicSegment8 *iface, - MUSIC_TIME mtStart) +static HRESULT WINAPI segment_SetStartPoint(IDirectMusicSegment8 *iface, MUSIC_TIME mtStart) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); @@ -478,8 +463,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_SetStartPoint(IDirectMusicSegment return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_GetStartPoint(IDirectMusicSegment8 *iface, - MUSIC_TIME *pmtStart) +static HRESULT WINAPI segment_GetStartPoint(IDirectMusicSegment8 *iface, MUSIC_TIME *pmtStart) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); @@ -491,8 +475,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_GetStartPoint(IDirectMusicSegment return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_SetLoopPoints(IDirectMusicSegment8 *iface, - MUSIC_TIME start, MUSIC_TIME end) +static HRESULT WINAPI segment_SetLoopPoints(IDirectMusicSegment8 *iface, MUSIC_TIME start, MUSIC_TIME end) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); @@ -508,8 +491,7 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_SetLoopPoints(IDirectMusicSegment return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_GetLoopPoints(IDirectMusicSegment8 *iface, - MUSIC_TIME *pmtStart, MUSIC_TIME *pmtEnd) +static HRESULT WINAPI segment_GetLoopPoints(IDirectMusicSegment8 *iface, MUSIC_TIME *pmtStart, MUSIC_TIME *pmtEnd) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); @@ -522,93 +504,86 @@ static HRESULT WINAPI IDirectMusicSegment8Impl_GetLoopPoints(IDirectMusicSegment return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_SetPChannelsUsed(IDirectMusicSegment8 *iface, - DWORD dwNumPChannels, DWORD *paPChannels) +static HRESULT WINAPI segment_SetPChannelsUsed(IDirectMusicSegment8 *iface, DWORD dwNumPChannels, DWORD *paPChannels) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); FIXME("(%p, %ld, %p): stub\n", This, dwNumPChannels, paPChannels); return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_SetTrackConfig(IDirectMusicSegment8 *iface, - REFGUID rguidTrackClassID, DWORD dwGroupBits, DWORD dwIndex, DWORD dwFlagsOn, - DWORD dwFlagsOff) +static HRESULT WINAPI segment_SetTrackConfig(IDirectMusicSegment8 *iface, REFGUID rguidTrackClassID, + DWORD dwGroupBits, DWORD dwIndex, DWORD dwFlagsOn, DWORD dwFlagsOff) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); FIXME("(%p, %s, %#lx, %ld, %ld, %ld): stub\n", This, debugstr_dmguid(rguidTrackClassID), dwGroupBits, dwIndex, dwFlagsOn, dwFlagsOff); return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_GetAudioPathConfig(IDirectMusicSegment8 *iface, - IUnknown **ppAudioPathConfig) +static HRESULT WINAPI segment_GetAudioPathConfig(IDirectMusicSegment8 *iface, IUnknown **ppAudioPathConfig) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); FIXME("(%p, %p): stub\n", This, ppAudioPathConfig); return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_Compose(IDirectMusicSegment8 *iface, - MUSIC_TIME mtTime, IDirectMusicSegment *pFromSegment, IDirectMusicSegment *pToSegment, - IDirectMusicSegment **ppComposedSegment) +static HRESULT WINAPI segment_Compose(IDirectMusicSegment8 *iface, MUSIC_TIME mtTime, + IDirectMusicSegment *pFromSegment, IDirectMusicSegment *pToSegment, IDirectMusicSegment **ppComposedSegment) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); FIXME("(%p, %ld, %p, %p, %p): stub\n", This, mtTime, pFromSegment, pToSegment, ppComposedSegment); return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_Download(IDirectMusicSegment8 *iface, - IUnknown *pAudioPath) +static HRESULT WINAPI segment_Download(IDirectMusicSegment8 *iface, IUnknown *pAudioPath) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); FIXME("(%p, %p): stub\n", This, pAudioPath); return S_OK; } -static HRESULT WINAPI IDirectMusicSegment8Impl_Unload(IDirectMusicSegment8 *iface, - IUnknown *pAudioPath) +static HRESULT WINAPI segment_Unload(IDirectMusicSegment8 *iface, IUnknown *pAudioPath) { IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); FIXME("(%p, %p): stub\n", This, pAudioPath); return S_OK; } -static const IDirectMusicSegment8Vtbl dmsegment8_vtbl = { - IDirectMusicSegment8Impl_QueryInterface, - IDirectMusicSegment8Impl_AddRef, - IDirectMusicSegment8Impl_Release, - IDirectMusicSegment8Impl_GetLength, - IDirectMusicSegment8Impl_SetLength, - IDirectMusicSegment8Impl_GetRepeats, - IDirectMusicSegment8Impl_SetRepeats, - IDirectMusicSegment8Impl_GetDefaultResolution, - IDirectMusicSegment8Impl_SetDefaultResolution, - IDirectMusicSegment8Impl_GetTrack, - IDirectMusicSegment8Impl_GetTrackGroup, - IDirectMusicSegment8Impl_InsertTrack, - IDirectMusicSegment8Impl_RemoveTrack, - IDirectMusicSegment8Impl_InitPlay, - IDirectMusicSegment8Impl_GetGraph, - IDirectMusicSegment8Impl_SetGraph, - IDirectMusicSegment8Impl_AddNotificationType, - IDirectMusicSegment8Impl_RemoveNotificationType, - IDirectMusicSegment8Impl_GetParam, - IDirectMusicSegment8Impl_SetParam, - IDirectMusicSegment8Impl_Clone, - IDirectMusicSegment8Impl_SetStartPoint, - IDirectMusicSegment8Impl_GetStartPoint, - IDirectMusicSegment8Impl_SetLoopPoints, - IDirectMusicSegment8Impl_GetLoopPoints, - IDirectMusicSegment8Impl_SetPChannelsUsed, - IDirectMusicSegment8Impl_SetTrackConfig, - IDirectMusicSegment8Impl_GetAudioPathConfig, - IDirectMusicSegment8Impl_Compose, - IDirectMusicSegment8Impl_Download, - IDirectMusicSegment8Impl_Unload +static const IDirectMusicSegment8Vtbl segment_vtbl = +{ + segment_QueryInterface, + segment_AddRef, + segment_Release, + segment_GetLength, + segment_SetLength, + segment_GetRepeats, + segment_SetRepeats, + segment_GetDefaultResolution, + segment_SetDefaultResolution, + segment_GetTrack, + segment_GetTrackGroup, + segment_InsertTrack, + segment_RemoveTrack, + segment_InitPlay, + segment_GetGraph, + segment_SetGraph, + segment_AddNotificationType, + segment_RemoveNotificationType, + segment_GetParam, + segment_SetParam, + segment_Clone, + segment_SetStartPoint, + segment_GetStartPoint, + segment_SetLoopPoints, + segment_GetLoopPoints, + segment_SetPChannelsUsed, + segment_SetTrackConfig, + segment_GetAudioPathConfig, + segment_Compose, + segment_Download, + segment_Unload, }; -/* IDirectMusicSegment8Impl IDirectMusicObject part: */ -static HRESULT WINAPI seg_IDirectMusicObject_ParseDescriptor(IDirectMusicObject *iface, - IStream *stream, DMUS_OBJECTDESC *desc) +static HRESULT WINAPI segment_object_ParseDescriptor(IDirectMusicObject *iface, IStream *stream, DMUS_OBJECTDESC *desc) { struct chunk_entry riff = {0}; DWORD supported = DMUS_OBJ_OBJECT | DMUS_OBJ_VERSION; @@ -643,16 +618,16 @@ static HRESULT WINAPI seg_IDirectMusicObject_ParseDescriptor(IDirectMusicObject return S_OK; } -static const IDirectMusicObjectVtbl dmobject_vtbl = { +static const IDirectMusicObjectVtbl segment_object_vtbl = +{ dmobj_IDirectMusicObject_QueryInterface, dmobj_IDirectMusicObject_AddRef, dmobj_IDirectMusicObject_Release, dmobj_IDirectMusicObject_GetDescriptor, dmobj_IDirectMusicObject_SetDescriptor, - seg_IDirectMusicObject_ParseDescriptor + segment_object_ParseDescriptor, }; -/* IDirectMusicSegment8Impl IPersistStream part: */ static HRESULT parse_track_form(IDirectMusicSegment8Impl *This, IStream *stream, const struct chunk_entry *riff) { @@ -871,7 +846,7 @@ static HRESULT parse_wave_form(IDirectMusicSegment8Impl *This, IStream *stream, return SUCCEEDED(hr) ? S_OK : hr; } -static HRESULT WINAPI seg_IPersistStream_Load(IPersistStream *iface, IStream *stream) +static HRESULT WINAPI segment_persist_stream_Load(IPersistStream *iface, IStream *stream) { IDirectMusicSegment8Impl *This = impl_from_IPersistStream(iface); struct chunk_entry riff = {0}; @@ -910,28 +885,29 @@ static HRESULT WINAPI seg_IPersistStream_Load(IPersistStream *iface, IStream *st return hr; } -static const IPersistStreamVtbl persiststream_vtbl = { +static const IPersistStreamVtbl segment_persist_stream_vtbl = +{ dmobj_IPersistStream_QueryInterface, dmobj_IPersistStream_AddRef, dmobj_IPersistStream_Release, dmobj_IPersistStream_GetClassID, unimpl_IPersistStream_IsDirty, - seg_IPersistStream_Load, + segment_persist_stream_Load, unimpl_IPersistStream_Save, - unimpl_IPersistStream_GetSizeMax + unimpl_IPersistStream_GetSizeMax, }; -IDirectMusicSegment8Impl *create_segment(void) +IDirectMusicSegment8Impl *segment_create(void) { IDirectMusicSegment8Impl *obj; if (!(obj = calloc(1, sizeof(*obj)))) return NULL; - obj->IDirectMusicSegment8_iface.lpVtbl = &dmsegment8_vtbl; + obj->IDirectMusicSegment8_iface.lpVtbl = &segment_vtbl; obj->ref = 1; dmobject_init(&obj->dmobj, &CLSID_DirectMusicSegment, (IUnknown *)&obj->IDirectMusicSegment8_iface); - obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl; - obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; + obj->dmobj.IDirectMusicObject_iface.lpVtbl = &segment_object_vtbl; + obj->dmobj.IPersistStream_iface.lpVtbl = &segment_persist_stream_vtbl; list_init (&obj->Tracks); return obj; @@ -943,7 +919,8 @@ HRESULT create_dmsegment(REFIID guid, void **ret_iface) IDirectMusicSegment8Impl *obj; HRESULT hr; - if (!(obj = create_segment())) { + if (!(obj = segment_create())) + { *ret_iface = NULL; return E_OUTOFMEMORY; } From ff4b8d1fd6005fa59bd08529fa0cfd9a06e051a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 13:59:56 +0200 Subject: [PATCH 2546/2777] dmime: Use one-liners for segment parameter checks. (cherry picked from commit d2cdb9cfa2b770e7348c75dee62008c34884aa3a) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segment.c | 202 ++++++++++++++++++++----------------------- 1 file changed, 95 insertions(+), 107 deletions(-) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index f86e4a2bb5f..7dd21731f6f 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -98,67 +98,71 @@ static ULONG WINAPI segment_Release(IDirectMusicSegment8 *iface) return ref; } -static HRESULT WINAPI segment_GetLength(IDirectMusicSegment8 *iface, MUSIC_TIME *pmtLength) +static HRESULT WINAPI segment_GetLength(IDirectMusicSegment8 *iface, MUSIC_TIME *length) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - TRACE("(%p, %p)\n", This, pmtLength); - if (NULL == pmtLength) { - return E_POINTER; - } - *pmtLength = This->header.mtLength; - return S_OK; + TRACE("(%p, %p)\n", This, length); + + if (!length) return E_POINTER; + *length = This->header.mtLength; + + return S_OK; } -static HRESULT WINAPI segment_SetLength(IDirectMusicSegment8 *iface, MUSIC_TIME mtLength) +static HRESULT WINAPI segment_SetLength(IDirectMusicSegment8 *iface, MUSIC_TIME length) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - TRACE("(%p, %ld)\n", This, mtLength); - This->header.mtLength = mtLength; - return S_OK; + TRACE("(%p, %ld)\n", This, length); + + This->header.mtLength = length; + + return S_OK; } -static HRESULT WINAPI segment_GetRepeats(IDirectMusicSegment8 *iface, DWORD *pdwRepeats) +static HRESULT WINAPI segment_GetRepeats(IDirectMusicSegment8 *iface, DWORD *repeats) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - TRACE("(%p, %p)\n", This, pdwRepeats); - if (NULL == pdwRepeats) { - return E_POINTER; - } - *pdwRepeats = This->header.dwRepeats; - return S_OK; + TRACE("(%p, %p)\n", This, repeats); + + if (!repeats) return E_POINTER; + *repeats = This->header.dwRepeats; + + return S_OK; } -static HRESULT WINAPI segment_SetRepeats(IDirectMusicSegment8 *iface, DWORD dwRepeats) +static HRESULT WINAPI segment_SetRepeats(IDirectMusicSegment8 *iface, DWORD repeats) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - TRACE("(%p, %ld)\n", This, dwRepeats); - This->header.dwRepeats = dwRepeats; - return S_OK; + TRACE("(%p, %ld)\n", This, repeats); + This->header.dwRepeats = repeats; + + return S_OK; } -static HRESULT WINAPI segment_GetDefaultResolution(IDirectMusicSegment8 *iface, DWORD *pdwResolution) +static HRESULT WINAPI segment_GetDefaultResolution(IDirectMusicSegment8 *iface, DWORD *resolution) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - TRACE("(%p, %p)\n", This, pdwResolution); - if (NULL == pdwResolution) { - return E_POINTER; - } - *pdwResolution = This->header.dwResolution; - return S_OK; + TRACE("(%p, %p)\n", This, resolution); + + if (!resolution) return E_POINTER; + *resolution = This->header.dwResolution; + + return S_OK; } -static HRESULT WINAPI segment_SetDefaultResolution(IDirectMusicSegment8 *iface, DWORD dwResolution) +static HRESULT WINAPI segment_SetDefaultResolution(IDirectMusicSegment8 *iface, DWORD resolution) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - TRACE("(%p, %ld)\n", This, dwResolution); - This->header.dwResolution = dwResolution; - return S_OK; + TRACE("(%p, %ld)\n", This, resolution); + This->header.dwResolution = resolution; + + return S_OK; } static HRESULT WINAPI segment_GetTrack(IDirectMusicSegment8 *iface, REFGUID rguidType, @@ -294,56 +298,43 @@ static HRESULT WINAPI segment_RemoveTrack(IDirectMusicSegment8 *iface, IDirectMu } static HRESULT WINAPI segment_InitPlay(IDirectMusicSegment8 *iface, - IDirectMusicSegmentState **ppSegState, IDirectMusicPerformance *pPerformance, DWORD dwFlags) + IDirectMusicSegmentState **state, IDirectMusicPerformance *performance, DWORD flags) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - HRESULT hr; + IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + HRESULT hr; - FIXME("(%p, %p, %p, %ld): semi-stub\n", This, ppSegState, pPerformance, dwFlags); - if (NULL == ppSegState) { - return E_POINTER; - } - hr = create_dmsegmentstate(&IID_IDirectMusicSegmentState,(void**) ppSegState); - if (FAILED(hr)) { - return hr; - } - /* TODO: DMUS_SEGF_FLAGS */ - return S_OK; + FIXME("(%p, %p, %p, %ld): semi-stub\n", This, state, performance, flags); + + if (!state) return E_POINTER; + if (FAILED(hr = create_dmsegmentstate(&IID_IDirectMusicSegmentState, (void **)state))) return hr; + + /* TODO: DMUS_SEGF_FLAGS */ + return S_OK; } -static HRESULT WINAPI segment_GetGraph(IDirectMusicSegment8 *iface, IDirectMusicGraph **ppGraph) +static HRESULT WINAPI segment_GetGraph(IDirectMusicSegment8 *iface, IDirectMusicGraph **graph) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %p): semi-stub\n", This, ppGraph); - if (NULL == ppGraph) { - return E_POINTER; - } - if (NULL == This->pGraph) { - return DMUS_E_NOT_FOUND; - } - /** - * should return This, as seen in msdn - * "...The segment object implements IDirectMusicGraph directly..." - */ - *ppGraph = This->pGraph; - IDirectMusicGraph_AddRef(This->pGraph); - return S_OK; + FIXME("(%p, %p): semi-stub\n", This, graph); + + if (!graph) return E_POINTER; + if (!(*graph = This->pGraph)) return DMUS_E_NOT_FOUND; + IDirectMusicGraph_AddRef(This->pGraph); + + return S_OK; } -static HRESULT WINAPI segment_SetGraph(IDirectMusicSegment8 *iface, IDirectMusicGraph *pGraph) +static HRESULT WINAPI segment_SetGraph(IDirectMusicSegment8 *iface, IDirectMusicGraph *graph) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %p): to complete\n", This, pGraph); - if (NULL != This->pGraph) { - IDirectMusicGraph_Release(This->pGraph); - } - This->pGraph = pGraph; - if (NULL != This->pGraph) { - IDirectMusicGraph_AddRef(This->pGraph); - } - return S_OK; + FIXME("(%p, %p): to complete\n", This, graph); + + if (This->pGraph) IDirectMusicGraph_Release(This->pGraph); + if ((This->pGraph = graph)) IDirectMusicGraph_AddRef(This->pGraph); + + return S_OK; } static HRESULT WINAPI segment_AddNotificationType(IDirectMusicSegment8 *iface, REFGUID rguidNotificationType) @@ -451,28 +442,27 @@ static HRESULT WINAPI segment_Clone(IDirectMusicSegment8 *iface, MUSIC_TIME star return track_clone_fail ? S_FALSE : S_OK; } -static HRESULT WINAPI segment_SetStartPoint(IDirectMusicSegment8 *iface, MUSIC_TIME mtStart) +static HRESULT WINAPI segment_SetStartPoint(IDirectMusicSegment8 *iface, MUSIC_TIME start) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - TRACE("(%p, %ld)\n", This, mtStart); - if (mtStart >= This->header.mtLength) { - return DMUS_E_OUT_OF_RANGE; - } - This->header.mtPlayStart = mtStart; - return S_OK; + TRACE("(%p, %ld)\n", This, start); + + if (start >= This->header.mtLength) return DMUS_E_OUT_OF_RANGE; + This->header.mtPlayStart = start; + + return S_OK; } -static HRESULT WINAPI segment_GetStartPoint(IDirectMusicSegment8 *iface, MUSIC_TIME *pmtStart) +static HRESULT WINAPI segment_GetStartPoint(IDirectMusicSegment8 *iface, MUSIC_TIME *start) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - TRACE("(%p, %p)\n", This, pmtStart); - if (NULL == pmtStart) { - return E_POINTER; - } - *pmtStart = This->header.mtPlayStart; - return S_OK; + TRACE("(%p, %p)\n", This, start); + if (!start) return E_POINTER; + *start = This->header.mtPlayStart; + + return S_OK; } static HRESULT WINAPI segment_SetLoopPoints(IDirectMusicSegment8 *iface, MUSIC_TIME start, MUSIC_TIME end) @@ -481,27 +471,25 @@ static HRESULT WINAPI segment_SetLoopPoints(IDirectMusicSegment8 *iface, MUSIC_T TRACE("(%p, %ld, %ld)\n", This, start, end); - if ((end || start) && - (start >= This->header.mtLength || end > This->header.mtLength || start > end)) + if ((end || start) && (start >= This->header.mtLength || end > This->header.mtLength || start > end)) return DMUS_E_OUT_OF_RANGE; - This->header.mtLoopStart = start; This->header.mtLoopEnd = end; return S_OK; } -static HRESULT WINAPI segment_GetLoopPoints(IDirectMusicSegment8 *iface, MUSIC_TIME *pmtStart, MUSIC_TIME *pmtEnd) +static HRESULT WINAPI segment_GetLoopPoints(IDirectMusicSegment8 *iface, MUSIC_TIME *start, MUSIC_TIME *end) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - TRACE("(%p, %p, %p)\n", This, pmtStart, pmtEnd); - if (NULL == pmtStart || NULL == pmtEnd) { - return E_POINTER; - } - *pmtStart = This->header.mtLoopStart; - *pmtEnd = This->header.mtLoopEnd; - return S_OK; + TRACE("(%p, %p, %p)\n", This, start, end); + + if (!start || !end) return E_POINTER; + *start = This->header.mtLoopStart; + *end = This->header.mtLoopEnd; + + return S_OK; } static HRESULT WINAPI segment_SetPChannelsUsed(IDirectMusicSegment8 *iface, DWORD dwNumPChannels, DWORD *paPChannels) From 2f5ab3ebfee677a85cfd0c46f484cdd1488e4bee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 14:03:02 +0200 Subject: [PATCH 2547/2777] dmime: Get rid of the IDirectMusicSegmentImpl typedef. (cherry picked from commit 6699becf522f2aa2bf7e508d290996e02620e7fd) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segment.c | 140 +++++++++++++++++++++---------------------- 1 file changed, 68 insertions(+), 72 deletions(-) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index 7dd21731f6f..fd042842272 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -23,10 +23,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmime); -/***************************************************************************** - * IDirectMusicSegmentImpl implementation - */ -typedef struct IDirectMusicSegment8Impl { +struct segment +{ IDirectMusicSegment8 IDirectMusicSegment8_iface; struct dmobject dmobj; LONG ref; @@ -37,18 +35,18 @@ typedef struct IDirectMusicSegment8Impl { PCMWAVEFORMAT wave_format; void *wave_data; int data_size; -} IDirectMusicSegment8Impl; +}; -static IDirectMusicSegment8Impl *segment_create(void); +static struct segment *segment_create(void); -static inline IDirectMusicSegment8Impl *impl_from_IDirectMusicSegment8(IDirectMusicSegment8 *iface) +static inline struct segment *impl_from_IDirectMusicSegment8(IDirectMusicSegment8 *iface) { - return CONTAINING_RECORD(iface, IDirectMusicSegment8Impl, IDirectMusicSegment8_iface); + return CONTAINING_RECORD(iface, struct segment, IDirectMusicSegment8_iface); } static HRESULT WINAPI segment_QueryInterface(IDirectMusicSegment8 *iface, REFIID riid, void **ret_iface) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface); @@ -73,7 +71,7 @@ static HRESULT WINAPI segment_QueryInterface(IDirectMusicSegment8 *iface, REFIID static ULONG WINAPI segment_AddRef(IDirectMusicSegment8 *iface) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); @@ -83,7 +81,7 @@ static ULONG WINAPI segment_AddRef(IDirectMusicSegment8 *iface) static ULONG WINAPI segment_Release(IDirectMusicSegment8 *iface) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); LONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); @@ -100,7 +98,7 @@ static ULONG WINAPI segment_Release(IDirectMusicSegment8 *iface) static HRESULT WINAPI segment_GetLength(IDirectMusicSegment8 *iface, MUSIC_TIME *length) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); TRACE("(%p, %p)\n", This, length); @@ -112,7 +110,7 @@ static HRESULT WINAPI segment_GetLength(IDirectMusicSegment8 *iface, MUSIC_TIME static HRESULT WINAPI segment_SetLength(IDirectMusicSegment8 *iface, MUSIC_TIME length) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); TRACE("(%p, %ld)\n", This, length); @@ -123,7 +121,7 @@ static HRESULT WINAPI segment_SetLength(IDirectMusicSegment8 *iface, MUSIC_TIME static HRESULT WINAPI segment_GetRepeats(IDirectMusicSegment8 *iface, DWORD *repeats) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); TRACE("(%p, %p)\n", This, repeats); @@ -135,7 +133,7 @@ static HRESULT WINAPI segment_GetRepeats(IDirectMusicSegment8 *iface, DWORD *rep static HRESULT WINAPI segment_SetRepeats(IDirectMusicSegment8 *iface, DWORD repeats) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); TRACE("(%p, %ld)\n", This, repeats); This->header.dwRepeats = repeats; @@ -145,7 +143,7 @@ static HRESULT WINAPI segment_SetRepeats(IDirectMusicSegment8 *iface, DWORD repe static HRESULT WINAPI segment_GetDefaultResolution(IDirectMusicSegment8 *iface, DWORD *resolution) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); TRACE("(%p, %p)\n", This, resolution); @@ -157,7 +155,7 @@ static HRESULT WINAPI segment_GetDefaultResolution(IDirectMusicSegment8 *iface, static HRESULT WINAPI segment_SetDefaultResolution(IDirectMusicSegment8 *iface, DWORD resolution) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); TRACE("(%p, %ld)\n", This, resolution); This->header.dwResolution = resolution; @@ -168,7 +166,7 @@ static HRESULT WINAPI segment_SetDefaultResolution(IDirectMusicSegment8 *iface, static HRESULT WINAPI segment_GetTrack(IDirectMusicSegment8 *iface, REFGUID rguidType, DWORD dwGroupBits, DWORD dwIndex, IDirectMusicTrack **ppTrack) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); CLSID pIt_clsid; struct list* pEntry = NULL; LPDMUS_PRIVATE_SEGMENT_TRACK pIt = NULL; @@ -216,7 +214,7 @@ static HRESULT WINAPI segment_GetTrack(IDirectMusicSegment8 *iface, REFGUID rgui static HRESULT WINAPI segment_GetTrackGroup(IDirectMusicSegment8 *iface, IDirectMusicTrack *pTrack, DWORD *pdwGroupBits) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); struct list* pEntry = NULL; LPDMUS_PRIVATE_SEGMENT_TRACK pIt = NULL; @@ -240,7 +238,7 @@ static HRESULT WINAPI segment_GetTrackGroup(IDirectMusicSegment8 *iface, IDirect static HRESULT WINAPI segment_InsertTrack(IDirectMusicSegment8 *iface, IDirectMusicTrack *pTrack, DWORD group) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); DWORD i = 0; struct list* pEntry = NULL; LPDMUS_PRIVATE_SEGMENT_TRACK pIt = NULL; @@ -274,7 +272,7 @@ static HRESULT WINAPI segment_InsertTrack(IDirectMusicSegment8 *iface, IDirectMu static HRESULT WINAPI segment_RemoveTrack(IDirectMusicSegment8 *iface, IDirectMusicTrack *pTrack) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); struct list* pEntry = NULL; LPDMUS_PRIVATE_SEGMENT_TRACK pIt = NULL; @@ -300,7 +298,7 @@ static HRESULT WINAPI segment_RemoveTrack(IDirectMusicSegment8 *iface, IDirectMu static HRESULT WINAPI segment_InitPlay(IDirectMusicSegment8 *iface, IDirectMusicSegmentState **state, IDirectMusicPerformance *performance, DWORD flags) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); HRESULT hr; FIXME("(%p, %p, %p, %ld): semi-stub\n", This, state, performance, flags); @@ -314,7 +312,7 @@ static HRESULT WINAPI segment_InitPlay(IDirectMusicSegment8 *iface, static HRESULT WINAPI segment_GetGraph(IDirectMusicSegment8 *iface, IDirectMusicGraph **graph) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); FIXME("(%p, %p): semi-stub\n", This, graph); @@ -327,7 +325,7 @@ static HRESULT WINAPI segment_GetGraph(IDirectMusicSegment8 *iface, IDirectMusic static HRESULT WINAPI segment_SetGraph(IDirectMusicSegment8 *iface, IDirectMusicGraph *graph) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); FIXME("(%p, %p): to complete\n", This, graph); @@ -339,22 +337,22 @@ static HRESULT WINAPI segment_SetGraph(IDirectMusicSegment8 *iface, IDirectMusic static HRESULT WINAPI segment_AddNotificationType(IDirectMusicSegment8 *iface, REFGUID rguidNotificationType) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType)); - return S_OK; + struct segment *This = impl_from_IDirectMusicSegment8(iface); + FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType)); + return S_OK; } static HRESULT WINAPI segment_RemoveNotificationType(IDirectMusicSegment8 *iface, REFGUID rguidNotificationType) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType)); - return S_OK; + struct segment *This = impl_from_IDirectMusicSegment8(iface); + FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType)); + return S_OK; } static HRESULT WINAPI segment_GetParam(IDirectMusicSegment8 *iface, REFGUID type, DWORD group, DWORD index, MUSIC_TIME time, MUSIC_TIME *next, void *param) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); IDirectMusicTrack *track; unsigned int i, count; HRESULT hr = DMUS_E_TRACK_NOT_FOUND; @@ -387,16 +385,17 @@ static HRESULT WINAPI segment_GetParam(IDirectMusicSegment8 *iface, REFGUID type static HRESULT WINAPI segment_SetParam(IDirectMusicSegment8 *iface, REFGUID rguidType, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, void *pParam) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %s, %#lx, %ld, %ld, %p): stub\n", This, debugstr_dmguid(rguidType), dwGroupBits, dwIndex, mtTime, pParam); - return S_OK; + struct segment *This = impl_from_IDirectMusicSegment8(iface); + FIXME("(%p, %s, %#lx, %ld, %ld, %p): stub\n", This, debugstr_dmguid(rguidType), dwGroupBits, + dwIndex, mtTime, pParam); + return S_OK; } static HRESULT WINAPI segment_Clone(IDirectMusicSegment8 *iface, MUSIC_TIME start, MUSIC_TIME end, IDirectMusicSegment **segment) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - IDirectMusicSegment8Impl *clone; + struct segment *This = impl_from_IDirectMusicSegment8(iface); + struct segment *clone; IDirectMusicTrack *track; DMUS_PRIVATE_SEGMENT_TRACK *track_item, *cloned_item; HRESULT hr; @@ -444,7 +443,7 @@ static HRESULT WINAPI segment_Clone(IDirectMusicSegment8 *iface, MUSIC_TIME star static HRESULT WINAPI segment_SetStartPoint(IDirectMusicSegment8 *iface, MUSIC_TIME start) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); TRACE("(%p, %ld)\n", This, start); @@ -456,7 +455,7 @@ static HRESULT WINAPI segment_SetStartPoint(IDirectMusicSegment8 *iface, MUSIC_T static HRESULT WINAPI segment_GetStartPoint(IDirectMusicSegment8 *iface, MUSIC_TIME *start) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); TRACE("(%p, %p)\n", This, start); if (!start) return E_POINTER; @@ -467,7 +466,7 @@ static HRESULT WINAPI segment_GetStartPoint(IDirectMusicSegment8 *iface, MUSIC_T static HRESULT WINAPI segment_SetLoopPoints(IDirectMusicSegment8 *iface, MUSIC_TIME start, MUSIC_TIME end) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); TRACE("(%p, %ld, %ld)\n", This, start, end); @@ -481,7 +480,7 @@ static HRESULT WINAPI segment_SetLoopPoints(IDirectMusicSegment8 *iface, MUSIC_T static HRESULT WINAPI segment_GetLoopPoints(IDirectMusicSegment8 *iface, MUSIC_TIME *start, MUSIC_TIME *end) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); + struct segment *This = impl_from_IDirectMusicSegment8(iface); TRACE("(%p, %p, %p)\n", This, start, end); @@ -494,46 +493,47 @@ static HRESULT WINAPI segment_GetLoopPoints(IDirectMusicSegment8 *iface, MUSIC_T static HRESULT WINAPI segment_SetPChannelsUsed(IDirectMusicSegment8 *iface, DWORD dwNumPChannels, DWORD *paPChannels) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %ld, %p): stub\n", This, dwNumPChannels, paPChannels); - return S_OK; + struct segment *This = impl_from_IDirectMusicSegment8(iface); + FIXME("(%p, %ld, %p): stub\n", This, dwNumPChannels, paPChannels); + return S_OK; } static HRESULT WINAPI segment_SetTrackConfig(IDirectMusicSegment8 *iface, REFGUID rguidTrackClassID, DWORD dwGroupBits, DWORD dwIndex, DWORD dwFlagsOn, DWORD dwFlagsOff) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %s, %#lx, %ld, %ld, %ld): stub\n", This, debugstr_dmguid(rguidTrackClassID), dwGroupBits, dwIndex, dwFlagsOn, dwFlagsOff); - return S_OK; + struct segment *This = impl_from_IDirectMusicSegment8(iface); + FIXME("(%p, %s, %#lx, %ld, %ld, %ld): stub\n", This, debugstr_dmguid(rguidTrackClassID), + dwGroupBits, dwIndex, dwFlagsOn, dwFlagsOff); + return S_OK; } static HRESULT WINAPI segment_GetAudioPathConfig(IDirectMusicSegment8 *iface, IUnknown **ppAudioPathConfig) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %p): stub\n", This, ppAudioPathConfig); - return S_OK; + struct segment *This = impl_from_IDirectMusicSegment8(iface); + FIXME("(%p, %p): stub\n", This, ppAudioPathConfig); + return S_OK; } static HRESULT WINAPI segment_Compose(IDirectMusicSegment8 *iface, MUSIC_TIME mtTime, IDirectMusicSegment *pFromSegment, IDirectMusicSegment *pToSegment, IDirectMusicSegment **ppComposedSegment) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %ld, %p, %p, %p): stub\n", This, mtTime, pFromSegment, pToSegment, ppComposedSegment); - return S_OK; + struct segment *This = impl_from_IDirectMusicSegment8(iface); + FIXME("(%p, %ld, %p, %p, %p): stub\n", This, mtTime, pFromSegment, pToSegment, ppComposedSegment); + return S_OK; } static HRESULT WINAPI segment_Download(IDirectMusicSegment8 *iface, IUnknown *pAudioPath) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %p): stub\n", This, pAudioPath); - return S_OK; + struct segment *This = impl_from_IDirectMusicSegment8(iface); + FIXME("(%p, %p): stub\n", This, pAudioPath); + return S_OK; } static HRESULT WINAPI segment_Unload(IDirectMusicSegment8 *iface, IUnknown *pAudioPath) { - IDirectMusicSegment8Impl *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %p): stub\n", This, pAudioPath); - return S_OK; + struct segment *This = impl_from_IDirectMusicSegment8(iface); + FIXME("(%p, %p): stub\n", This, pAudioPath); + return S_OK; } static const IDirectMusicSegment8Vtbl segment_vtbl = @@ -616,8 +616,7 @@ static const IDirectMusicObjectVtbl segment_object_vtbl = segment_object_ParseDescriptor, }; -static HRESULT parse_track_form(IDirectMusicSegment8Impl *This, IStream *stream, - const struct chunk_entry *riff) +static HRESULT parse_track_form(struct segment *This, IStream *stream, const struct chunk_entry *riff) { struct chunk_entry chunk = {.parent = riff}; IDirectMusicTrack *track = NULL; @@ -699,8 +698,7 @@ static HRESULT parse_track_form(IDirectMusicSegment8Impl *This, IStream *stream, return hr; } -static HRESULT parse_track_list(IDirectMusicSegment8Impl *This, IStream *stream, - const struct chunk_entry *trkl) +static HRESULT parse_track_list(struct segment *This, IStream *stream, const struct chunk_entry *trkl) { struct chunk_entry chunk = {.parent = trkl}; HRESULT hr; @@ -742,8 +740,7 @@ static inline void dump_segment_header(DMUS_IO_SEGMENT_HEADER *h, DWORD size) } } -static HRESULT parse_segment_form(IDirectMusicSegment8Impl *This, IStream *stream, - const struct chunk_entry *riff) +static HRESULT parse_segment_form(struct segment *This, IStream *stream, const struct chunk_entry *riff) { struct chunk_entry chunk = {.parent = riff}; HRESULT hr; @@ -783,12 +780,12 @@ static HRESULT parse_segment_form(IDirectMusicSegment8Impl *This, IStream *strea return SUCCEEDED(hr) ? S_OK : hr; } -static inline IDirectMusicSegment8Impl *impl_from_IPersistStream(IPersistStream *iface) +static inline struct segment *impl_from_IPersistStream(IPersistStream *iface) { - return CONTAINING_RECORD(iface, IDirectMusicSegment8Impl, dmobj.IPersistStream_iface); + return CONTAINING_RECORD(iface, struct segment, dmobj.IPersistStream_iface); } -static HRESULT parse_wave_form(IDirectMusicSegment8Impl *This, IStream *stream, const struct chunk_entry *riff) +static HRESULT parse_wave_form(struct segment *This, IStream *stream, const struct chunk_entry *riff) { HRESULT hr; struct chunk_entry chunk = {.parent = riff}; @@ -836,7 +833,7 @@ static HRESULT parse_wave_form(IDirectMusicSegment8Impl *This, IStream *stream, static HRESULT WINAPI segment_persist_stream_Load(IPersistStream *iface, IStream *stream) { - IDirectMusicSegment8Impl *This = impl_from_IPersistStream(iface); + struct segment *This = impl_from_IPersistStream(iface); struct chunk_entry riff = {0}; HRESULT hr; @@ -885,12 +882,11 @@ static const IPersistStreamVtbl segment_persist_stream_vtbl = unimpl_IPersistStream_GetSizeMax, }; -IDirectMusicSegment8Impl *segment_create(void) +static struct segment *segment_create(void) { - IDirectMusicSegment8Impl *obj; + struct segment *obj; if (!(obj = calloc(1, sizeof(*obj)))) return NULL; - obj->IDirectMusicSegment8_iface.lpVtbl = &segment_vtbl; obj->ref = 1; dmobject_init(&obj->dmobj, &CLSID_DirectMusicSegment, (IUnknown *)&obj->IDirectMusicSegment8_iface); @@ -904,7 +900,7 @@ IDirectMusicSegment8Impl *segment_create(void) /* for ClassFactory */ HRESULT create_dmsegment(REFIID guid, void **ret_iface) { - IDirectMusicSegment8Impl *obj; + struct segment *obj; HRESULT hr; if (!(obj = segment_create())) From 29e885aa327440342194f5fe2a0306ff68638841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 14:25:56 +0200 Subject: [PATCH 2548/2777] dmime: Avoid leaking tracks in IDirectMusicSegment_Release. (cherry picked from commit c0b52aa3a7c64fa42c87d595dd2d5d88c28aa9a7) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/dmime_private.h | 7 ---- dlls/dmime/segment.c | 69 ++++++++++++++++++++++++++------------ 2 files changed, 48 insertions(+), 28 deletions(-) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index be0c463339f..eacde4b46be 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -73,13 +73,6 @@ extern void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath*,IDirectSo /***************************************************************************** * Auxiliary definitions */ -typedef struct _DMUS_PRIVATE_SEGMENT_TRACK { - struct list entry; /* for listing elements */ - DWORD dwGroupBits; - DWORD flags; - IDirectMusicTrack* pTrack; -} DMUS_PRIVATE_SEGMENT_TRACK, *LPDMUS_PRIVATE_SEGMENT_TRACK; - typedef struct _DMUS_PRIVATE_TEMPO_ITEM { struct list entry; /* for listing elements */ DMUS_IO_TEMPO_ITEM item; diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index fd042842272..1ecc7c9566c 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -23,6 +23,25 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmime); +struct track_entry +{ + struct list entry; + DWORD dwGroupBits; + DWORD flags; + IDirectMusicTrack *pTrack; +}; + +static void track_entry_destroy(struct track_entry *entry) +{ + HRESULT hr; + + if (FAILED(hr = IDirectMusicTrack_Init(entry->pTrack, NULL))) + WARN("Failed to de-init track %p, hr %#lx\n", entry->pTrack, hr); + IDirectMusicTrack_Release(entry->pTrack); + + free(entry); +} + struct segment { IDirectMusicSegment8 IDirectMusicSegment8_iface; @@ -30,7 +49,7 @@ struct segment LONG ref; DMUS_IO_SEGMENT_HEADER header; IDirectMusicGraph *pGraph; - struct list Tracks; + struct list tracks; PCMWAVEFORMAT wave_format; void *wave_data; @@ -87,6 +106,14 @@ static ULONG WINAPI segment_Release(IDirectMusicSegment8 *iface) TRACE("(%p) ref=%ld\n", This, ref); if (!ref) { + struct track_entry *entry, *next; + + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &This->tracks, struct track_entry, entry) + { + list_remove(&entry->entry); + track_entry_destroy(entry); + } + if (This->wave_data) free(This->wave_data); @@ -169,7 +196,7 @@ static HRESULT WINAPI segment_GetTrack(IDirectMusicSegment8 *iface, REFGUID rgui struct segment *This = impl_from_IDirectMusicSegment8(iface); CLSID pIt_clsid; struct list* pEntry = NULL; - LPDMUS_PRIVATE_SEGMENT_TRACK pIt = NULL; + struct track_entry *pIt = NULL; IPersistStream* pCLSIDStream = NULL; HRESULT hr = S_OK; @@ -179,8 +206,8 @@ static HRESULT WINAPI segment_GetTrack(IDirectMusicSegment8 *iface, REFGUID rgui return E_POINTER; } - LIST_FOR_EACH (pEntry, &This->Tracks) { - pIt = LIST_ENTRY(pEntry, DMUS_PRIVATE_SEGMENT_TRACK, entry); + LIST_FOR_EACH (pEntry, &This->tracks) { + pIt = LIST_ENTRY(pEntry, struct track_entry, entry); TRACE(" - %p -> %#lx,%p\n", pIt, pIt->dwGroupBits, pIt->pTrack); if (0xFFFFFFFF != dwGroupBits && 0 == (pIt->dwGroupBits & dwGroupBits)) continue ; if (FALSE == IsEqualGUID(&GUID_NULL, rguidType)) { @@ -216,7 +243,7 @@ static HRESULT WINAPI segment_GetTrackGroup(IDirectMusicSegment8 *iface, IDirect { struct segment *This = impl_from_IDirectMusicSegment8(iface); struct list* pEntry = NULL; - LPDMUS_PRIVATE_SEGMENT_TRACK pIt = NULL; + struct track_entry *pIt = NULL; TRACE("(%p, %p, %p)\n", This, pTrack, pdwGroupBits); @@ -224,8 +251,8 @@ static HRESULT WINAPI segment_GetTrackGroup(IDirectMusicSegment8 *iface, IDirect return E_POINTER; } - LIST_FOR_EACH (pEntry, &This->Tracks) { - pIt = LIST_ENTRY(pEntry, DMUS_PRIVATE_SEGMENT_TRACK, entry); + LIST_FOR_EACH (pEntry, &This->tracks) { + pIt = LIST_ENTRY(pEntry, struct track_entry, entry); TRACE(" - %p -> %#lx, %p\n", pIt, pIt->dwGroupBits, pIt->pTrack); if (NULL != pIt && pIt->pTrack == pTrack) { *pdwGroupBits = pIt->dwGroupBits; @@ -241,17 +268,17 @@ static HRESULT WINAPI segment_InsertTrack(IDirectMusicSegment8 *iface, IDirectMu struct segment *This = impl_from_IDirectMusicSegment8(iface); DWORD i = 0; struct list* pEntry = NULL; - LPDMUS_PRIVATE_SEGMENT_TRACK pIt = NULL; - LPDMUS_PRIVATE_SEGMENT_TRACK pNewSegTrack = NULL; + struct track_entry *pIt = NULL; + struct track_entry *pNewSegTrack = NULL; TRACE("(%p, %p, %#lx)\n", This, pTrack, group); if (!group) return E_INVALIDARG; - LIST_FOR_EACH (pEntry, &This->Tracks) { + LIST_FOR_EACH (pEntry, &This->tracks) { i++; - pIt = LIST_ENTRY(pEntry, DMUS_PRIVATE_SEGMENT_TRACK, entry); + pIt = LIST_ENTRY(pEntry, struct track_entry, entry); TRACE(" - #%lu: %p -> %#lx, %p\n", i, pIt, pIt->dwGroupBits, pIt->pTrack); if (NULL != pIt && pIt->pTrack == pTrack) { ERR("(%p, %p): track is already in list\n", This, pTrack); @@ -265,7 +292,7 @@ static HRESULT WINAPI segment_InsertTrack(IDirectMusicSegment8 *iface, IDirectMu pNewSegTrack->pTrack = pTrack; IDirectMusicTrack_Init(pTrack, (IDirectMusicSegment *)iface); IDirectMusicTrack_AddRef(pTrack); - list_add_tail (&This->Tracks, &pNewSegTrack->entry); + list_add_tail (&This->tracks, &pNewSegTrack->entry); return S_OK; } @@ -274,12 +301,12 @@ static HRESULT WINAPI segment_RemoveTrack(IDirectMusicSegment8 *iface, IDirectMu { struct segment *This = impl_from_IDirectMusicSegment8(iface); struct list* pEntry = NULL; - LPDMUS_PRIVATE_SEGMENT_TRACK pIt = NULL; + struct track_entry *pIt = NULL; TRACE("(%p, %p)\n", This, pTrack); - LIST_FOR_EACH (pEntry, &This->Tracks) { - pIt = LIST_ENTRY(pEntry, DMUS_PRIVATE_SEGMENT_TRACK, entry); + LIST_FOR_EACH (pEntry, &This->tracks) { + pIt = LIST_ENTRY(pEntry, struct track_entry, entry); if (pIt->pTrack == pTrack) { TRACE("(%p, %p): track in list\n", This, pTrack); @@ -397,7 +424,7 @@ static HRESULT WINAPI segment_Clone(IDirectMusicSegment8 *iface, MUSIC_TIME star struct segment *This = impl_from_IDirectMusicSegment8(iface); struct segment *clone; IDirectMusicTrack *track; - DMUS_PRIVATE_SEGMENT_TRACK *track_item, *cloned_item; + struct track_entry *track_item, *cloned_item; HRESULT hr; BOOL track_clone_fail = FALSE; @@ -417,14 +444,14 @@ static HRESULT WINAPI segment_Clone(IDirectMusicSegment8 *iface, MUSIC_TIME star if (clone->pGraph) IDirectMusicGraph_AddRef(clone->pGraph); - LIST_FOR_EACH_ENTRY(track_item, &This->Tracks, DMUS_PRIVATE_SEGMENT_TRACK, entry) { + LIST_FOR_EACH_ENTRY(track_item, &This->tracks, struct track_entry, entry) { if (SUCCEEDED(hr = IDirectMusicTrack_Clone(track_item->pTrack, start, end, &track))) { if ((cloned_item = malloc(sizeof(*cloned_item)))) { cloned_item->dwGroupBits = track_item->dwGroupBits; cloned_item->flags = track_item->flags; cloned_item->pTrack = track; - list_add_tail(&clone->Tracks, &cloned_item->entry); + list_add_tail(&clone->tracks, &cloned_item->entry); continue; } else @@ -625,7 +652,7 @@ static HRESULT parse_track_form(struct segment *This, IStream *stream, const str DMUS_IO_TRACK_HEADER thdr; DMUS_IO_TRACK_EXTRAS_HEADER txhdr = {0}; HRESULT hr; - DMUS_PRIVATE_SEGMENT_TRACK *item; + struct track_entry *item; TRACE("Parsing track form in %p: %s\n", stream, debugstr_chunk(riff)); @@ -685,7 +712,7 @@ static HRESULT parse_track_form(struct segment *This, IStream *stream, const str if (FAILED(hr)) goto done; - item = LIST_ENTRY(list_tail(&This->Tracks), DMUS_PRIVATE_SEGMENT_TRACK, entry); + item = LIST_ENTRY(list_tail(&This->tracks), struct track_entry, entry); item->flags = txhdr.dwFlags; done: @@ -892,7 +919,7 @@ static struct segment *segment_create(void) dmobject_init(&obj->dmobj, &CLSID_DirectMusicSegment, (IUnknown *)&obj->IDirectMusicSegment8_iface); obj->dmobj.IDirectMusicObject_iface.lpVtbl = &segment_object_vtbl; obj->dmobj.IPersistStream_iface.lpVtbl = &segment_persist_stream_vtbl; - list_init (&obj->Tracks); + list_init(&obj->tracks); return obj; } From 62c8ff66fb0d0d78e7f39d6378c087f2f1a14f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 15 Sep 2023 11:09:31 +0200 Subject: [PATCH 2549/2777] dmime: Rewrite segment IDirectMusicSegment_GetTrack. (cherry picked from commit a713797597b90b0da425f92f7451f06fd497a975) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segment.c | 68 +++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 38 deletions(-) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index 1ecc7c9566c..fc219554588 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -190,52 +190,44 @@ static HRESULT WINAPI segment_SetDefaultResolution(IDirectMusicSegment8 *iface, return S_OK; } -static HRESULT WINAPI segment_GetTrack(IDirectMusicSegment8 *iface, REFGUID rguidType, - DWORD dwGroupBits, DWORD dwIndex, IDirectMusicTrack **ppTrack) +static HRESULT WINAPI segment_GetTrack(IDirectMusicSegment8 *iface, REFGUID type, DWORD group, + DWORD index, IDirectMusicTrack **ret_track) { struct segment *This = impl_from_IDirectMusicSegment8(iface); - CLSID pIt_clsid; - struct list* pEntry = NULL; - struct track_entry *pIt = NULL; - IPersistStream* pCLSIDStream = NULL; + struct track_entry *entry; HRESULT hr = S_OK; - TRACE("(%p, %s, %#lx, %#lx, %p)\n", This, debugstr_dmguid(rguidType), dwGroupBits, dwIndex, ppTrack); + TRACE("(%p, %s, %#lx, %#lx, %p)\n", This, debugstr_dmguid(type), group, index, ret_track); - if (NULL == ppTrack) { - return E_POINTER; - } + if (!ret_track) return E_POINTER; - LIST_FOR_EACH (pEntry, &This->tracks) { - pIt = LIST_ENTRY(pEntry, struct track_entry, entry); - TRACE(" - %p -> %#lx,%p\n", pIt, pIt->dwGroupBits, pIt->pTrack); - if (0xFFFFFFFF != dwGroupBits && 0 == (pIt->dwGroupBits & dwGroupBits)) continue ; - if (FALSE == IsEqualGUID(&GUID_NULL, rguidType)) { - /** - * it rguidType is not null we must check if CLSIDs are equal - * and the unique way to get it is using IPersistStream Interface - */ - hr = IDirectMusicTrack_QueryInterface(pIt->pTrack, &IID_IPersistStream, (void**) &pCLSIDStream); - if (FAILED(hr)) { - ERR("(%p): object %p don't implement IPersistStream Interface. Expect a crash (critical problem)\n", This, pIt->pTrack); - continue ; + LIST_FOR_EACH_ENTRY(entry, &This->tracks, struct track_entry, entry) + { + if (group != -1 && !(entry->dwGroupBits & group)) continue; + + if (!IsEqualGUID(&GUID_NULL, type)) + { + CLSID entry_type = GUID_NULL; + IPersistStream *persist; + + if (SUCCEEDED(hr = IDirectMusicTrack_QueryInterface(entry->pTrack, &IID_IPersistStream, (void **)&persist))) + { + hr = IPersistStream_GetClassID(persist, &entry_type); + if (SUCCEEDED(hr)) TRACE(" - %p -> %s\n", entry, debugstr_dmguid(&entry_type)); + IPersistStream_Release(persist); + } + + if (!IsEqualGUID(&entry_type, type)) continue; } - hr = IPersistStream_GetClassID(pCLSIDStream, &pIt_clsid); - IPersistStream_Release(pCLSIDStream); pCLSIDStream = NULL; - if (FAILED(hr)) { - ERR("(%p): non-implemented GetClassID for object %p\n", This, pIt->pTrack); - continue ; + + if (!index--) + { + *ret_track = entry->pTrack; + IDirectMusicTrack_AddRef(entry->pTrack); + return S_OK; } - TRACE(" - %p -> %s\n", pIt, debugstr_dmguid(&pIt_clsid)); - if (FALSE == IsEqualGUID(&pIt_clsid, rguidType)) continue ; - } - if (0 == dwIndex) { - *ppTrack = pIt->pTrack; - IDirectMusicTrack_AddRef(*ppTrack); - return S_OK; - } - --dwIndex; - } + } + return DMUS_E_NOT_FOUND; } From b8bf4d7233ca74be192c7ad1427f1b2571c0efdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 15 Sep 2023 11:11:52 +0200 Subject: [PATCH 2550/2777] dmime: Rewrite segment IDirectMusicSegment_GetTrackGroup. (cherry picked from commit d045eae8b7383fdccfd870bad4c70892b2518e50) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segment.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index fc219554588..367e526d659 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -231,25 +231,22 @@ static HRESULT WINAPI segment_GetTrack(IDirectMusicSegment8 *iface, REFGUID type return DMUS_E_NOT_FOUND; } -static HRESULT WINAPI segment_GetTrackGroup(IDirectMusicSegment8 *iface, IDirectMusicTrack *pTrack, DWORD *pdwGroupBits) +static HRESULT WINAPI segment_GetTrackGroup(IDirectMusicSegment8 *iface, IDirectMusicTrack *track, DWORD *ret_group) { struct segment *This = impl_from_IDirectMusicSegment8(iface); - struct list* pEntry = NULL; - struct track_entry *pIt = NULL; + struct track_entry *entry; - TRACE("(%p, %p, %p)\n", This, pTrack, pdwGroupBits); + TRACE("(%p, %p, %p)\n", This, track, ret_group); - if (NULL == pdwGroupBits) { - return E_POINTER; - } + if (!ret_group) return E_POINTER; - LIST_FOR_EACH (pEntry, &This->tracks) { - pIt = LIST_ENTRY(pEntry, struct track_entry, entry); - TRACE(" - %p -> %#lx, %p\n", pIt, pIt->dwGroupBits, pIt->pTrack); - if (NULL != pIt && pIt->pTrack == pTrack) { - *pdwGroupBits = pIt->dwGroupBits; - return S_OK; - } + LIST_FOR_EACH_ENTRY(entry, &This->tracks, struct track_entry, entry) + { + if (entry->pTrack == track) + { + *ret_group = entry->dwGroupBits; + return S_OK; + } } return DMUS_E_NOT_FOUND; From 2c3e98486b4a69c68fd571551bc04378afb4deb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 15 Sep 2023 11:11:52 +0200 Subject: [PATCH 2551/2777] dmime: Rewrite segment IDirectMusicSegment_InsertTrack. (cherry picked from commit f04976e01da864249884350fec55657cbb39c23e) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segment.c | 49 ++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index 367e526d659..a1126fe3d5f 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -252,38 +252,37 @@ static HRESULT WINAPI segment_GetTrackGroup(IDirectMusicSegment8 *iface, IDirect return DMUS_E_NOT_FOUND; } -static HRESULT WINAPI segment_InsertTrack(IDirectMusicSegment8 *iface, IDirectMusicTrack *pTrack, DWORD group) +static HRESULT segment_append_track(struct segment *This, IDirectMusicTrack *track, DWORD group, DWORD flags) { - struct segment *This = impl_from_IDirectMusicSegment8(iface); - DWORD i = 0; - struct list* pEntry = NULL; - struct track_entry *pIt = NULL; - struct track_entry *pNewSegTrack = NULL; + struct track_entry *entry; + HRESULT hr; - TRACE("(%p, %p, %#lx)\n", This, pTrack, group); + if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY; + entry->dwGroupBits = group; + entry->flags = flags; + entry->pTrack = track; + IDirectMusicTrack_AddRef(track); - if (!group) - return E_INVALIDARG; + hr = IDirectMusicTrack_Init(track, (IDirectMusicSegment *)&This->IDirectMusicSegment8_iface); + if (FAILED(hr)) track_entry_destroy(entry); + else list_add_tail(&This->tracks, &entry->entry); - LIST_FOR_EACH (pEntry, &This->tracks) { - i++; - pIt = LIST_ENTRY(pEntry, struct track_entry, entry); - TRACE(" - #%lu: %p -> %#lx, %p\n", i, pIt, pIt->dwGroupBits, pIt->pTrack); - if (NULL != pIt && pIt->pTrack == pTrack) { - ERR("(%p, %p): track is already in list\n", This, pTrack); - return E_FAIL; - } - } + return hr; +} + +static HRESULT WINAPI segment_InsertTrack(IDirectMusicSegment8 *iface, IDirectMusicTrack *track, DWORD group) +{ + struct segment *This = impl_from_IDirectMusicSegment8(iface); + struct track_entry *entry; + + TRACE("(%p, %p, %#lx)\n", This, track, group); - if (!(pNewSegTrack = calloc(1, sizeof(*pNewSegTrack)))) return E_OUTOFMEMORY; + if (!group) return E_INVALIDARG; - pNewSegTrack->dwGroupBits = group; - pNewSegTrack->pTrack = pTrack; - IDirectMusicTrack_Init(pTrack, (IDirectMusicSegment *)iface); - IDirectMusicTrack_AddRef(pTrack); - list_add_tail (&This->tracks, &pNewSegTrack->entry); + LIST_FOR_EACH_ENTRY(entry, &This->tracks, struct track_entry, entry) + if (entry->pTrack == track) return E_FAIL; - return S_OK; + return segment_append_track(This, track, group, 0); } static HRESULT WINAPI segment_RemoveTrack(IDirectMusicSegment8 *iface, IDirectMusicTrack *pTrack) From b7ec719c7e687c797751eaf38e4acdc1feb59f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 15 Sep 2023 11:14:08 +0200 Subject: [PATCH 2552/2777] dmime: Rewrite segment IDirectMusicSegment_RemoveTrack. (cherry picked from commit 0bdc248cfe292590de87817d40efe4f5931e1499) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segment.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index a1126fe3d5f..8b5f12243d9 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -285,29 +285,24 @@ static HRESULT WINAPI segment_InsertTrack(IDirectMusicSegment8 *iface, IDirectMu return segment_append_track(This, track, group, 0); } -static HRESULT WINAPI segment_RemoveTrack(IDirectMusicSegment8 *iface, IDirectMusicTrack *pTrack) +static HRESULT WINAPI segment_RemoveTrack(IDirectMusicSegment8 *iface, IDirectMusicTrack *track) { - struct segment *This = impl_from_IDirectMusicSegment8(iface); - struct list* pEntry = NULL; - struct track_entry *pIt = NULL; - - TRACE("(%p, %p)\n", This, pTrack); - - LIST_FOR_EACH (pEntry, &This->tracks) { - pIt = LIST_ENTRY(pEntry, struct track_entry, entry); - if (pIt->pTrack == pTrack) { - TRACE("(%p, %p): track in list\n", This, pTrack); - - list_remove(&pIt->entry); - IDirectMusicTrack_Init(pIt->pTrack, NULL); - IDirectMusicTrack_Release(pIt->pTrack); - free(pIt); - - return S_OK; + struct segment *This = impl_from_IDirectMusicSegment8(iface); + struct track_entry *entry; + + TRACE("(%p, %p)\n", This, track); + + LIST_FOR_EACH_ENTRY(entry, &This->tracks, struct track_entry, entry) + { + if (entry->pTrack == track) + { + list_remove(&entry->entry); + track_entry_destroy(entry); + return S_OK; + } } - } - - return S_FALSE; + + return S_FALSE; } static HRESULT WINAPI segment_InitPlay(IDirectMusicSegment8 *iface, From 2e0aa241907c303e433903757f6343a9714bba44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 15 Sep 2023 11:14:08 +0200 Subject: [PATCH 2553/2777] dmime: Use segment_append_track in Clone and parse_track_form. (cherry picked from commit a4c1dec89d84ff95f97da8e0dee5f9622d99a42e) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segment.c | 46 +++++++++++--------------------------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index 8b5f12243d9..a72ec786623 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -407,14 +407,12 @@ static HRESULT WINAPI segment_Clone(IDirectMusicSegment8 *iface, MUSIC_TIME star struct segment *This = impl_from_IDirectMusicSegment8(iface); struct segment *clone; IDirectMusicTrack *track; - struct track_entry *track_item, *cloned_item; - HRESULT hr; - BOOL track_clone_fail = FALSE; + struct track_entry *entry; + HRESULT hr = S_OK; TRACE("(%p, %ld, %ld, %p)\n", This, start, end, segment); - if (!segment) - return E_POINTER; + if (!segment) return E_POINTER; if (!(clone = segment_create())) { @@ -423,32 +421,16 @@ static HRESULT WINAPI segment_Clone(IDirectMusicSegment8 *iface, MUSIC_TIME star } clone->header = This->header; - clone->pGraph = This->pGraph; - if (clone->pGraph) - IDirectMusicGraph_AddRef(clone->pGraph); - - LIST_FOR_EACH_ENTRY(track_item, &This->tracks, struct track_entry, entry) { - if (SUCCEEDED(hr = IDirectMusicTrack_Clone(track_item->pTrack, start, end, &track))) { - if ((cloned_item = malloc(sizeof(*cloned_item)))) - { - cloned_item->dwGroupBits = track_item->dwGroupBits; - cloned_item->flags = track_item->flags; - cloned_item->pTrack = track; - list_add_tail(&clone->tracks, &cloned_item->entry); - continue; - } - else - { - IDirectMusicTrack_Release(track); - } - } - WARN("Failed to clone track %p: %#lx\n", track_item->pTrack, hr); - track_clone_fail = TRUE; + if ((clone->pGraph = This->pGraph)) IDirectMusicGraph_AddRef(clone->pGraph); + + LIST_FOR_EACH_ENTRY(entry, &This->tracks, struct track_entry, entry) + { + if (FAILED(hr = IDirectMusicTrack_Clone(entry->pTrack, start, end, &track))) break; + if (FAILED(hr = segment_append_track(clone, track, entry->dwGroupBits, entry->flags))) break; } *segment = (IDirectMusicSegment *)&clone->IDirectMusicSegment8_iface; - - return track_clone_fail ? S_FALSE : S_OK; + return FAILED(hr) ? S_FALSE : S_OK; } static HRESULT WINAPI segment_SetStartPoint(IDirectMusicSegment8 *iface, MUSIC_TIME start) @@ -635,7 +617,6 @@ static HRESULT parse_track_form(struct segment *This, IStream *stream, const str DMUS_IO_TRACK_HEADER thdr; DMUS_IO_TRACK_EXTRAS_HEADER txhdr = {0}; HRESULT hr; - struct track_entry *item; TRACE("Parsing track form in %p: %s\n", stream, debugstr_chunk(riff)); @@ -691,12 +672,7 @@ static HRESULT parse_track_form(struct segment *This, IStream *stream, const str if (FAILED(hr)) goto done; - hr = IDirectMusicSegment8_InsertTrack(&This->IDirectMusicSegment8_iface, track, thdr.dwGroup); - if (FAILED(hr)) - goto done; - - item = LIST_ENTRY(list_tail(&This->tracks), struct track_entry, entry); - item->flags = txhdr.dwFlags; + hr = segment_append_track(This, track, thdr.dwGroup, txhdr.dwFlags); done: if (ps) From d07c26e53a1e60e8f24dc1b0cc16df2e6d386473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 19 Sep 2023 15:43:03 +0200 Subject: [PATCH 2554/2777] dmime/tests: Add some DMUS_NOTIFICATION_PMSG tests. (cherry picked from commit b1bf0f0296da6b1df5b5f58c9b232db730d93464) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 284 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 277 insertions(+), 7 deletions(-) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 89be2c32019..e011488d126 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -64,10 +64,30 @@ struct test_tool const DWORD *types; DWORD types_count; + SRWLOCK lock; HANDLE message_event; - DMUS_PMSG *message; + DMUS_PMSG *messages[32]; + UINT message_count; }; +static DMUS_PMSG *test_tool_push_msg(struct test_tool *tool, DMUS_PMSG *msg) +{ + AcquireSRWLockExclusive(&tool->lock); + ok(tool->message_count < ARRAY_SIZE(tool->messages), + "got %u messages\n", tool->message_count + 1); + if (tool->message_count < ARRAY_SIZE(tool->messages)) + { + memmove(tool->messages + 1, tool->messages, + tool->message_count * sizeof(*tool->messages)); + tool->messages[0] = msg; + tool->message_count++; + msg = NULL; + } + ReleaseSRWLockExclusive(&tool->lock); + + return msg; +} + static struct test_tool *impl_from_IDirectMusicTool(IDirectMusicTool *iface) { return CONTAINING_RECORD(iface, struct test_tool, IDirectMusicTool_iface); @@ -103,7 +123,7 @@ static ULONG WINAPI test_tool_Release(IDirectMusicTool *iface) if (!ref) { if (tool->graph) IDirectMusicGraph_Release(tool->graph); - ok(!tool->message, "got %p\n", tool->message); + ok(!tool->message_count, "got %p\n", &tool->message_count); CloseHandle(tool->message_event); free(tool); } @@ -147,8 +167,7 @@ static HRESULT WINAPI test_tool_ProcessPMsg(IDirectMusicTool *iface, IDirectMusi hr = IDirectMusicPerformance8_ClonePMsg((IDirectMusicPerformance8 *)performance, msg, &clone); ok(hr == S_OK, "got %#lx\n", hr); - - clone = InterlockedExchangePointer((void **)&tool->message, clone); + clone = test_tool_push_msg(tool, clone); ok(!clone, "got %p\n", clone); SetEvent(tool->message_event); @@ -207,10 +226,23 @@ static HRESULT test_tool_get_graph(IDirectMusicTool *iface, IDirectMusicGraph ** static DWORD test_tool_wait_message(IDirectMusicTool *iface, DWORD timeout, DMUS_PMSG **msg) { struct test_tool *tool = impl_from_IDirectMusicTool(iface); - DWORD ret; + DWORD ret = WAIT_FAILED; + + do + { + AcquireSRWLockExclusive(&tool->lock); + if (!tool->message_count) + *msg = NULL; + else + { + UINT index = --tool->message_count; + *msg = tool->messages[index]; + tool->messages[index] = NULL; + } + ReleaseSRWLockExclusive(&tool->lock); - ret = WaitForSingleObject(tool->message_event, timeout); - *msg = InterlockedExchangePointer((void **)&tool->message, NULL); + if (*msg) return 0; + } while (!(ret = WaitForSingleObject(tool->message_event, timeout))); return ret; } @@ -1975,6 +2007,243 @@ static void test_performance_pmsg(void) IDirectMusicTool_Release(tool); } +#define check_dmus_notification_pmsg(a, b, c) check_dmus_notification_pmsg_(__LINE__, a, b, c) +static void check_dmus_notification_pmsg_(int line, DMUS_NOTIFICATION_PMSG *msg, + const GUID *type, DWORD option) +{ + ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_NOTIFICATION, + "got dwType %#lx\n", msg->dwType); + ok_(__FILE__, line)(IsEqualGUID(&msg->guidNotificationType, type), + "got guidNotificationType %s\n", debugstr_guid(&msg->guidNotificationType)); + ok_(__FILE__, line)(msg->dwNotificationOption == option, + "got dwNotificationOption %#lx\n", msg->dwNotificationOption); + ok_(__FILE__, line)(!msg->dwField1, "got dwField1 %lu\n", msg->dwField1); + ok_(__FILE__, line)(!msg->dwField2, "got dwField2 %lu\n", msg->dwField2); + + if (!IsEqualGUID(&msg->guidNotificationType, &GUID_NOTIFICATION_SEGMENT)) + ok_(__FILE__, line)(!msg->punkUser, "got punkUser %p\n", msg->punkUser); + else + { + check_interface_(line, msg->punkUser, &IID_IDirectMusicSegmentState, TRUE); + check_interface_(line, msg->punkUser, &IID_IDirectMusicSegmentState8, TRUE); + } +} + +static void test_notification_pmsg(void) +{ + static const DWORD message_types[] = + { + DMUS_PMSGT_DIRTY, + DMUS_PMSGT_NOTIFICATION, + DMUS_PMSGT_WAVE, + }; + IDirectMusicPerformance *performance; + DMUS_NOTIFICATION_PMSG *notif; + IDirectMusicSegment *segment; + IDirectMusicGraph *graph; + IDirectMusicTool *tool; + DMUS_PMSG *msg; + HRESULT hr; + DWORD ret; + + hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicPerformance, (void **)&performance); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicGraph, (void **)&graph); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_SetGraph(performance, graph); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicGraph_Release(graph); + + hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + + hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicSegment, (void **)&segment); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicSegment8_Download((IDirectMusicSegment8 *)segment, (IUnknown *)performance); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSegment8_Unload((IDirectMusicSegment8 *)segment, (IUnknown *)performance); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 500, &msg); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, &msg); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 100, &msg); + ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); + ok(!msg, "got %p\n", msg); + + + /* AddNotificationType is necessary to receive notification messages */ + + hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_PERFORMANCE); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTARTED); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, &msg); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, &msg); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTOPPED); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 100, &msg); + ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); + ok(!msg, "got %p\n", msg); + + IDirectMusicSegment_Release(segment); + + hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_PERFORMANCE); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); + ok(hr == S_OK, "got %#lx\n", hr); + + + /* notification messages are also queued for direct access */ + + hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + if (hr == S_OK) + { + check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTARTED); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); + ok(hr == S_OK, "got %#lx\n", hr); + } + + hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + if (hr == S_OK) + { + check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); + ok(hr == S_OK, "got %#lx\n", hr); + } + + hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + if (hr == S_OK) + { + check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); + ok(hr == S_OK, "got %#lx\n", hr); + } + + hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + if (hr == S_OK) + { + check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); + ok(hr == S_OK, "got %#lx\n", hr); + } + + hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + if (hr == S_OK) + { + check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTOPPED); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); + ok(hr == S_OK, "got %#lx\n", hr); + } + + hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); + ok(hr == S_FALSE, "got %#lx\n", hr); + + + hr = IDirectMusicPerformance_CloseDown(performance); + ok(hr == S_OK, "got %#lx\n", hr); + + IDirectMusicPerformance_Release(performance); + IDirectMusicTool_Release(tool); +} + START_TEST(dmime) { CoInitialize(NULL); @@ -2002,6 +2271,7 @@ START_TEST(dmime) test_performance_graph(); test_performance_time(); test_performance_pmsg(); + test_notification_pmsg(); CoUninitialize(); } From 16cda9a3d27d092802bf849eb51ce04867463cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 19 Sep 2023 17:28:30 +0200 Subject: [PATCH 2555/2777] dmime/tests: Test wave segments and DMUS_WAVE_PMSG. (cherry picked from commit c04e686ad5801b581b43ca58926692075eb39e89) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/Makefile.in | 2 + dlls/dmime/tests/dmime.c | 168 +++++++++++++++++++++++++++++++++++ dlls/dmime/tests/resource.rc | 23 +++++ dlls/dmime/tests/test.wav | Bin 0 -> 4488 bytes 4 files changed, 193 insertions(+) create mode 100644 dlls/dmime/tests/resource.rc create mode 100644 dlls/dmime/tests/test.wav diff --git a/dlls/dmime/tests/Makefile.in b/dlls/dmime/tests/Makefile.in index f4c47038e54..2491f9ff1b8 100644 --- a/dlls/dmime/tests/Makefile.in +++ b/dlls/dmime/tests/Makefile.in @@ -4,3 +4,5 @@ IMPORTS = user32 ole32 dsound C_SRCS = \ dmime.c \ performance.c + +RC_SRCS = resource.rc diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index e011488d126..e76949e71c7 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -55,6 +55,28 @@ static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOO } } +static void load_resource(const WCHAR *name, WCHAR *filename) +{ + static WCHAR path[MAX_PATH]; + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + GetTempPathW(ARRAY_SIZE(path), path); + GetTempFileNameW(path, name, 0, filename); + + file = CreateFileW(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "failed to create %s, error %lu\n", debugstr_w(filename), GetLastError()); + + res = FindResourceW(NULL, name, (const WCHAR *)RT_RCDATA); + ok(res != 0, "couldn't find resource\n"); + ptr = LockResource(LoadResource(GetModuleHandleW(NULL ), res )); + WriteFile(file, ptr, SizeofResource(GetModuleHandleW(NULL ), res ), &written, NULL); + ok(written == SizeofResource(GetModuleHandleW(NULL ), res ), "couldn't write resource\n"); + CloseHandle(file); +} + struct test_tool { IDirectMusicTool IDirectMusicTool_iface; @@ -2244,6 +2266,151 @@ static void test_notification_pmsg(void) IDirectMusicTool_Release(tool); } +static void test_wave_pmsg(void) +{ + static const DWORD message_types[] = + { + DMUS_PMSGT_DIRTY, + DMUS_PMSGT_WAVE, + }; + IDirectMusicPerformance *performance; + IDirectMusicSegment *segment; + IDirectMusicLoader8 *loader; + IDirectMusicGraph *graph; + WCHAR test_wav[MAX_PATH]; + IDirectMusicTool *tool; + DMUS_WAVE_PMSG *wave; + MUSIC_TIME length; + DMUS_PMSG *msg; + HRESULT hr; + DWORD ret; + + hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicPerformance, (void **)&performance); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicGraph, (void **)&graph); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_SetGraph(performance, graph); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicGraph_Release(graph); + + hr = IDirectMusicPerformance8_InitAudio((IDirectMusicPerformance8 *)performance, NULL, NULL, NULL, + DMUS_APATH_SHARED_STEREOPLUSREVERB, 64, DMUS_AUDIOF_ALL, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + + + load_resource(L"test.wav", test_wav); + + hr = CoCreateInstance(&CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicLoader8, (void **)&loader); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicLoader8_LoadObjectFromFile(loader, &CLSID_DirectMusicSegment, + &IID_IDirectMusicSegment, test_wav, (void **)&segment); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicLoader8_Release(loader); + + + length = 0xdeadbeef; + hr = IDirectMusicSegment_GetLength(segment, &length); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(length == 1, "got %lu\n", length); + + + /* without Download, no DMUS_PMSGT_WAVE is sent */ + + hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 500, &msg); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %p\n", msg); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, &msg); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %p\n", msg); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 100, &msg); + ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); + ok(!msg, "got %p\n", msg); + + + /* a single DMUS_PMSGT_WAVE message is sent with punkUser set */ + + hr = IDirectMusicSegment8_Download((IDirectMusicSegment8 *)segment, (IUnknown *)performance); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 500, &msg); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %p\n", msg); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&wave); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + ok(wave->dwType == DMUS_PMSGT_WAVE, "got %p\n", wave); + ok(!!wave->punkUser, "got %p\n", wave->punkUser); + ok(wave->rtStartOffset == 0, "got %I64d\n", wave->rtStartOffset); + ok(wave->rtDuration == 1000000, "got %I64d\n", wave->rtDuration); + ok(wave->lOffset == 0, "got %lu\n", wave->lOffset); + ok(wave->lVolume == 0, "got %lu\n", wave->lVolume); + ok(wave->lPitch == 0, "got %lu\n", wave->lPitch); + ok(wave->bFlags == 0, "got %#x\n", wave->bFlags); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)wave); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, &msg); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %p\n", msg); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + } + + hr = IDirectMusicSegment8_Unload((IDirectMusicSegment8 *)segment, (IUnknown *)performance); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 100, &msg); + ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); + ok(!msg, "got %p\n", msg); + + + IDirectMusicSegment_Release(segment); + + + hr = IDirectMusicPerformance_CloseDown(performance); + ok(hr == S_OK, "got %#lx\n", hr); + + IDirectMusicPerformance_Release(performance); + IDirectMusicTool_Release(tool); +} + START_TEST(dmime) { CoInitialize(NULL); @@ -2272,6 +2439,7 @@ START_TEST(dmime) test_performance_time(); test_performance_pmsg(); test_notification_pmsg(); + test_wave_pmsg(); CoUninitialize(); } diff --git a/dlls/dmime/tests/resource.rc b/dlls/dmime/tests/resource.rc new file mode 100644 index 00000000000..d49b647b934 --- /dev/null +++ b/dlls/dmime/tests/resource.rc @@ -0,0 +1,23 @@ +/* + * Copyright 2023 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 + */ + +#include "windef.h" + +/* ffmpeg -f lavfi -i "sine=frequency=600" -t 0.1 -ar 44100 -f wav -acodec pcm_u8 test.wav */ +/* @makedep: test.wav */ +test.wav RCDATA test.wav diff --git a/dlls/dmime/tests/test.wav b/dlls/dmime/tests/test.wav new file mode 100644 index 0000000000000000000000000000000000000000..51d23936196da1a0452c78713c8af819259d225e GIT binary patch literal 4488 zcmWIYbaQJEWMBw)40BD(Em06)U|?VbLYFlRV9dzC!QkT=93ll2_w;k~_Y8Im;RCXL z63fy|&GbwR^b8FQ8B!8U60LxyG&DA~w6?W(c6Imk^!D}jLqT6(Z%=nuXGeQmYjaa$ zeO*m;Rb_cuX-RQWQDFfL6c!d0mz0*3S5#Kl)YdmNHMg|2cYsVnGN`|=7h+OdYfE!u zLtSl6Rb>Ulq(Zn!AcH_ARa910*VfgKI%zbNM$^)0jvFnPMvKbP3T3p~9c`R|TVA8> dC3y36v{gCU_8#q_jCPtvyOyIJ@PQhp007ieqznK6 literal 0 HcmV?d00001 From ab87518c536226a36c2e04f31cfa666852e48669 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 19 Sep 2023 15:43:03 +0200 Subject: [PATCH 2556/2777] dmime/tests: Test sequence track and DMUS_NOTE_PMSG. (cherry picked from commit 47c299ce17ff0c4f37df128302292658cb7499da) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 261 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 261 insertions(+) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index e76949e71c7..9173297abb7 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -77,6 +77,81 @@ static void load_resource(const WCHAR *name, WCHAR *filename) CloseHandle(file); } +static void stream_begin_chunk(IStream *stream, const char type[5], ULARGE_INTEGER *offset) +{ + static const LARGE_INTEGER zero = {0}; + HRESULT hr; + hr = IStream_Write(stream, type, 4, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, offset); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IStream_Write(stream, "\0\0\0\0", 4, NULL); + ok(hr == S_OK, "got %#lx\n", hr); +} + +static void stream_end_chunk(IStream *stream, ULARGE_INTEGER *offset) +{ + static const LARGE_INTEGER zero = {0}; + ULARGE_INTEGER position; + HRESULT hr; + UINT size; + hr = IStream_Seek(stream, zero, STREAM_SEEK_CUR, &position); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IStream_Seek(stream, *(LARGE_INTEGER *)offset, STREAM_SEEK_SET, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + size = position.QuadPart - offset->QuadPart - 4; + hr = IStream_Write(stream, &size, 4, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IStream_Seek(stream, *(LARGE_INTEGER *)&position, STREAM_SEEK_SET, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IStream_Write(stream, &zero, (position.QuadPart & 1), NULL); + ok(hr == S_OK, "got %#lx\n", hr); +} + +#define CHUNK_BEGIN(stream, type) \ + do { \ + ULARGE_INTEGER __off; \ + IStream *__stream = (stream); \ + stream_begin_chunk(stream, type, &__off); \ + do + +#define CHUNK_RIFF(stream, form) \ + do { \ + ULARGE_INTEGER __off; \ + IStream *__stream = (stream); \ + stream_begin_chunk(stream, "RIFF", &__off); \ + IStream_Write(stream, form, 4, NULL); \ + do + +#define CHUNK_LIST(stream, form) \ + do { \ + ULARGE_INTEGER __off; \ + IStream *__stream = (stream); \ + stream_begin_chunk(stream, "LIST", &__off); \ + IStream_Write(stream, form, 4, NULL); \ + do + +#define CHUNK_END \ + while (0); \ + stream_end_chunk(__stream, &__off); \ + } while (0) + +#define CHUNK_DATA(stream, type, data) \ + CHUNK_BEGIN(stream, type) \ + { \ + IStream_Write((stream), &(data), sizeof(data), NULL); \ + } \ + CHUNK_END + +#define CHUNK_ARRAY(stream, type, items) \ + CHUNK_BEGIN(stream, type) \ + { \ + UINT __size = sizeof(*(items)); \ + IStream_Write((stream), &__size, 4, NULL); \ + IStream_Write((stream), &(items), sizeof(items), NULL); \ + } \ + CHUNK_END + struct test_tool { IDirectMusicTool IDirectMusicTool_iface; @@ -2411,6 +2486,191 @@ static void test_wave_pmsg(void) IDirectMusicTool_Release(tool); } +#define check_dmus_note_pmsg(a, b, c, d, e, f) check_dmus_note_pmsg_(__LINE__, a, b, c, d, e, f) +static void check_dmus_note_pmsg_(int line, DMUS_NOTE_PMSG *msg, MUSIC_TIME time, UINT chan, + UINT duration, UINT key, UINT vel) +{ + ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %lu\n", msg->dwSize); + ok_(__FILE__, line)(!!msg->rtTime, "got rtTime %I64u\n", msg->rtTime); + ok_(__FILE__, line)(abs(msg->mtTime - time) < 10, "got mtTime %lu\n", msg->mtTime); + ok_(__FILE__, line)(msg->dwPChannel == chan, "got dwPChannel %lu\n", msg->dwPChannel); + ok_(__FILE__, line)(!!msg->dwVirtualTrackID, "got dwVirtualTrackID %lu\n", msg->dwVirtualTrackID); + ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_NOTE, "got %#lx\n", msg->dwType); + ok_(__FILE__, line)(!msg->dwVoiceID, "got dwVoiceID %lu\n", msg->dwVoiceID); + ok_(__FILE__, line)(msg->dwGroupID == 1, "got dwGroupID %lu\n", msg->dwGroupID); + ok_(__FILE__, line)(!msg->punkUser, "got punkUser %p\n", msg->punkUser); + ok_(__FILE__, line)(msg->mtDuration == duration, "got mtDuration %lu\n", msg->mtDuration); + ok_(__FILE__, line)(msg->wMusicValue == key, "got wMusicValue %u\n", msg->wMusicValue); + ok_(__FILE__, line)(!msg->wMeasure, "got wMeasure %u\n", msg->wMeasure); + /* FIXME: ok_(__FILE__, line)(!msg->nOffset, "got nOffset %u\n", msg->nOffset); */ + /* FIXME: ok_(__FILE__, line)(!msg->bBeat, "got bBeat %u\n", msg->bBeat); */ + /* FIXME: ok_(__FILE__, line)(!msg->bGrid, "got bGrid %u\n", msg->bGrid); */ + ok_(__FILE__, line)(msg->bVelocity == vel, "got bVelocity %u\n", msg->bVelocity); + ok_(__FILE__, line)(msg->bFlags == 1, "got bFlags %#x\n", msg->bFlags); + ok_(__FILE__, line)(!msg->bTimeRange, "got bTimeRange %u\n", msg->bTimeRange); + ok_(__FILE__, line)(!msg->bDurRange, "got bDurRange %u\n", msg->bDurRange); + ok_(__FILE__, line)(!msg->bVelRange, "got bVelRange %u\n", msg->bVelRange); + ok_(__FILE__, line)(!msg->bPlayModeFlags, "got bPlayModeFlags %#x\n", msg->bPlayModeFlags); + ok_(__FILE__, line)(!msg->bSubChordLevel, "got bSubChordLevel %u\n", msg->bSubChordLevel); + ok_(__FILE__, line)(msg->bMidiValue == key, "got bMidiValue %u\n", msg->bMidiValue); + ok_(__FILE__, line)(!msg->cTranspose, "got cTranspose %u\n", msg->cTranspose); +} + +static void test_sequence_track(void) +{ + static const DWORD message_types[] = + { + DMUS_PMSGT_MIDI, + DMUS_PMSGT_NOTE, + DMUS_PMSGT_CURVE, + DMUS_PMSGT_DIRTY, + }; + static const LARGE_INTEGER zero = {0}; + IDirectMusicPerformance *performance; + IDirectMusicSegment *segment; + IDirectMusicGraph *graph; + IDirectMusicTrack *track; + IPersistStream *persist; + IDirectMusicTool *tool; + DMUS_NOTE_PMSG *note; + IStream *stream; + DMUS_PMSG *msg; + HRESULT hr; + DWORD ret; + + hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicPerformance, (void **)&performance); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicGraph, (void **)&graph); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_SetGraph(performance, graph); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicGraph_Release(graph); + + + /* create a segment and load a simple RIFF stream */ + + hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicSegment, (void **)&segment); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicSegment_QueryInterface(segment, &IID_IPersistStream, (void **)&persist); + ok(hr == S_OK, "got %#lx\n", hr); + hr = CreateStreamOnHGlobal(0, TRUE, &stream); + ok(hr == S_OK, "got %#lx\n", hr); + + CHUNK_RIFF(stream, "DMSG") + { + /* set a non-zero segment length, or nothing will be played */ + DMUS_IO_SEGMENT_HEADER head = {.mtLength = 2000}; + CHUNK_DATA(stream, "segh", head); + CHUNK_DATA(stream, "guid", CLSID_DirectMusicSegment); + } + CHUNK_END; + + hr = IStream_Seek(stream, zero, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IPersistStream_Load(persist, stream); + ok(hr == S_OK, "got %#lx\n", hr); + IPersistStream_Release(persist); + IStream_Release(stream); + + + /* add a sequence track to our segment */ + + hr = CoCreateInstance(&CLSID_DirectMusicSeqTrack, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicTrack, (void **)&track); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicSegment_QueryInterface(track, &IID_IPersistStream, (void **)&persist); + ok(hr == S_OK, "got %#lx\n", hr); + hr = CreateStreamOnHGlobal(0, TRUE, &stream); + ok(hr == S_OK, "got %#lx\n", hr); + + CHUNK_BEGIN(stream, "seqt") + { + DMUS_IO_SEQ_ITEM items[] = + { + {.mtTime = 0, .mtDuration = 500, .dwPChannel = 0, .bStatus = 0x90, .bByte1 = 60, .bByte2 = 120}, + {.mtTime = 1000, .mtDuration = 200, .dwPChannel = 1, .bStatus = 0x90, .bByte1 = 50, .bByte2 = 100}, + }; + CHUNK_ARRAY(stream, "evtl", items); + } + CHUNK_END; + + hr = IStream_Seek(stream, zero, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IPersistStream_Load(persist, stream); + ok(hr == S_OK, "got %#lx\n", hr); + IPersistStream_Release(persist); + IStream_Release(stream); + + hr = IDirectMusicSegment_InsertTrack(segment, (IDirectMusicTrack *)track, 1); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicTrack_Release(track); + + + /* now play the segment, and check produced messages */ + + hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0x800, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 500, &msg); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬e); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + check_dmus_note_pmsg(note, 0, 0, 500, 60, 120); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)note); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬e); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + check_dmus_note_pmsg(note, 1000, 1, 200, 50, 100); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)note); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, &msg); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + } + + IDirectMusicSegment_Release(segment); + + + hr = IDirectMusicPerformance_CloseDown(performance); + ok(hr == S_OK, "got %#lx\n", hr); + + IDirectMusicPerformance_Release(performance); + IDirectMusicTool_Release(tool); +} + START_TEST(dmime) { CoInitialize(NULL); @@ -2440,6 +2700,7 @@ START_TEST(dmime) test_performance_pmsg(); test_notification_pmsg(); test_wave_pmsg(); + test_sequence_track(); CoUninitialize(); } From 605eec2435b0611cbe52565e5bb48d75575e283c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 19 Sep 2023 19:16:35 +0200 Subject: [PATCH 2557/2777] dmime/tests: Test band track and DMUS_PATCH_PMSG. (cherry picked from commit 4ea18f87cc2e4184a30d0ee01885811b3d9deb5f) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 483 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 483 insertions(+) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 9173297abb7..1266c5d053b 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -344,6 +344,213 @@ static DWORD test_tool_wait_message(IDirectMusicTool *iface, DWORD timeout, DMUS return ret; } +struct test_loader_stream +{ + IStream IStream_iface; + IDirectMusicGetLoader IDirectMusicGetLoader_iface; + LONG ref; + + IStream *stream; + IDirectMusicLoader *loader; +}; + +static struct test_loader_stream *impl_from_IStream(IStream *iface) +{ + return CONTAINING_RECORD(iface, struct test_loader_stream, IStream_iface); +} + +static HRESULT WINAPI test_loader_stream_QueryInterface(IStream *iface, REFIID iid, void **out) +{ + struct test_loader_stream *impl = impl_from_IStream(iface); + + if (IsEqualGUID(iid, &IID_IUnknown) + || IsEqualGUID(iid, &IID_IStream)) + { + IStream_AddRef(&impl->IStream_iface); + *out = &impl->IStream_iface; + return S_OK; + } + + if (IsEqualGUID(iid, &IID_IDirectMusicGetLoader)) + { + IDirectMusicGetLoader_AddRef(&impl->IDirectMusicGetLoader_iface); + *out = &impl->IDirectMusicGetLoader_iface; + return S_OK; + } + + ok(IsEqualGUID(iid, &IID_IStream), + "got iid %s\n", debugstr_guid(iid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_loader_stream_AddRef(IStream *iface) +{ + struct test_loader_stream *impl = impl_from_IStream(iface); + return InterlockedIncrement(&impl->ref); +} + +static ULONG WINAPI test_loader_stream_Release(IStream *iface) +{ + struct test_loader_stream *impl = impl_from_IStream(iface); + ULONG ref = InterlockedDecrement(&impl->ref); + + if (!ref) + { + IDirectMusicLoader_Release(impl->loader); + IStream_Release(impl->stream); + free(impl); + } + + return ref; +} + +static HRESULT WINAPI test_loader_stream_Read(IStream *iface, void *data, ULONG size, ULONG *ret_size) +{ + struct test_loader_stream *impl = impl_from_IStream(iface); + return IStream_Read(impl->stream, data, size, ret_size); +} + +static HRESULT WINAPI test_loader_stream_Write(IStream *iface, const void *data, ULONG size, ULONG *ret_size) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_loader_stream_Seek(IStream *iface, LARGE_INTEGER offset, DWORD method, ULARGE_INTEGER *ret_offset) +{ + struct test_loader_stream *impl = impl_from_IStream(iface); + return IStream_Seek(impl->stream, offset, method, ret_offset); +} + +static HRESULT WINAPI test_loader_stream_SetSize(IStream *iface, ULARGE_INTEGER size) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_loader_stream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size, + ULARGE_INTEGER *read_size, ULARGE_INTEGER *write_size) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_loader_stream_Commit(IStream *iface, DWORD flags) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_loader_stream_Revert(IStream *iface) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_loader_stream_LockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD type) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_loader_stream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD type) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_loader_stream_Stat(IStream *iface, STATSTG *stat, DWORD flags) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_loader_stream_Clone(IStream *iface, IStream **out) +{ + ok(0, "Unexpected call.\n"); + return E_NOTIMPL; +} + +static const IStreamVtbl test_loader_stream_vtbl = +{ + test_loader_stream_QueryInterface, + test_loader_stream_AddRef, + test_loader_stream_Release, + test_loader_stream_Read, + test_loader_stream_Write, + test_loader_stream_Seek, + test_loader_stream_SetSize, + test_loader_stream_CopyTo, + test_loader_stream_Commit, + test_loader_stream_Revert, + test_loader_stream_LockRegion, + test_loader_stream_UnlockRegion, + test_loader_stream_Stat, + test_loader_stream_Clone, +}; + +static struct test_loader_stream *impl_from_IDirectMusicGetLoader(IDirectMusicGetLoader *iface) +{ + return CONTAINING_RECORD(iface, struct test_loader_stream, IDirectMusicGetLoader_iface); +} + +static HRESULT WINAPI test_loader_stream_getter_QueryInterface(IDirectMusicGetLoader *iface, REFIID iid, void **out) +{ + struct test_loader_stream *impl = impl_from_IDirectMusicGetLoader(iface); + return IStream_QueryInterface(&impl->IStream_iface, iid, out); +} + +static ULONG WINAPI test_loader_stream_getter_AddRef(IDirectMusicGetLoader *iface) +{ + struct test_loader_stream *impl = impl_from_IDirectMusicGetLoader(iface); + return IStream_AddRef(&impl->IStream_iface); +} + +static ULONG WINAPI test_loader_stream_getter_Release(IDirectMusicGetLoader *iface) +{ + struct test_loader_stream *impl = impl_from_IDirectMusicGetLoader(iface); + return IStream_Release(&impl->IStream_iface); +} + +static HRESULT WINAPI test_loader_stream_getter_GetLoader(IDirectMusicGetLoader *iface, IDirectMusicLoader **ret_loader) +{ + struct test_loader_stream *impl = impl_from_IDirectMusicGetLoader(iface); + + *ret_loader = impl->loader; + IDirectMusicLoader_AddRef(impl->loader); + + return S_OK; +} + +static const IDirectMusicGetLoaderVtbl test_loader_stream_getter_vtbl = +{ + test_loader_stream_getter_QueryInterface, + test_loader_stream_getter_AddRef, + test_loader_stream_getter_Release, + test_loader_stream_getter_GetLoader, +}; + +static HRESULT test_loader_stream_create(IStream *stream, IDirectMusicLoader *loader, + IStream **ret_iface) +{ + struct test_loader_stream *obj; + + *ret_iface = NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; + obj->IStream_iface.lpVtbl = &test_loader_stream_vtbl; + obj->IDirectMusicGetLoader_iface.lpVtbl = &test_loader_stream_getter_vtbl; + obj->ref = 1; + + obj->stream = stream; + IStream_AddRef(stream); + obj->loader = loader; + IDirectMusicLoader_AddRef(loader); + + *ret_iface = &obj->IStream_iface; + return S_OK; +} + static BOOL missing_dmime(void) { IDirectMusicSegment8 *dms; @@ -2671,6 +2878,281 @@ static void test_sequence_track(void) IDirectMusicTool_Release(tool); } +#define check_dmus_patch_pmsg(a, b, c, d, e) check_dmus_patch_pmsg_(__LINE__, a, b, c, d, e) +static void check_dmus_patch_pmsg_(int line, DMUS_PATCH_PMSG *msg, MUSIC_TIME time, UINT chan, + UINT bank, UINT patch) +{ + ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %lu\n", msg->dwSize); + ok_(__FILE__, line)(msg->rtTime != 0, "got rtTime %I64u\n", msg->rtTime); + ok_(__FILE__, line)(abs(msg->mtTime - time) < 10, "got mtTime %lu\n", msg->mtTime); + ok_(__FILE__, line)(msg->dwPChannel == chan, "got dwPChannel %lu\n", msg->dwPChannel); + ok_(__FILE__, line)(!!msg->dwVirtualTrackID, "got dwVirtualTrackID %lu\n", msg->dwVirtualTrackID); + ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_PATCH, "got %#lx\n", msg->dwType); + ok_(__FILE__, line)(!msg->dwVoiceID, "got dwVoiceID %lu\n", msg->dwVoiceID); + ok_(__FILE__, line)(msg->dwGroupID == 1, "got dwGroupID %lu\n", msg->dwGroupID); + ok_(__FILE__, line)(!msg->punkUser, "got punkUser %p\n", msg->punkUser); + ok_(__FILE__, line)(msg->byInstrument == patch, "got byInstrument %u\n", msg->byInstrument); + ok_(__FILE__, line)(msg->byMSB == bank >> 8, "got byMSB %u\n", msg->byMSB); + ok_(__FILE__, line)(msg->byLSB == (bank & 0xff), "got byLSB %u\n", msg->byLSB); +} + +static void test_band_track_play(void) +{ + static const DWORD message_types[] = + { + DMUS_PMSGT_MIDI, + DMUS_PMSGT_NOTE, + DMUS_PMSGT_SYSEX, + DMUS_PMSGT_NOTIFICATION, + DMUS_PMSGT_TEMPO, + DMUS_PMSGT_CURVE, + DMUS_PMSGT_TIMESIG, + DMUS_PMSGT_PATCH, + DMUS_PMSGT_TRANSPOSE, + DMUS_PMSGT_CHANNEL_PRIORITY, + DMUS_PMSGT_STOP, + DMUS_PMSGT_DIRTY, + DMUS_PMSGT_WAVE, + DMUS_PMSGT_LYRIC, + DMUS_PMSGT_SCRIPTLYRIC, + DMUS_PMSGT_USER, + }; + DMUS_OBJECTDESC desc = + { + .dwSize = sizeof(DMUS_OBJECTDESC), + .dwValidData = DMUS_OBJ_OBJECT | DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH, + .guidClass = CLSID_DirectMusicCollection, + .guidObject = GUID_DefaultGMCollection, + .wszFileName = L"C:\\windows\\system32\\drivers\\gm.dls", + }; + static const LARGE_INTEGER zero = {0}; + IDirectMusicPerformance *performance; + IStream *stream, *loader_stream; + IDirectMusicSegment *segment; + IDirectMusicLoader *loader; + IDirectMusicGraph *graph; + IDirectMusicTrack *track; + IPersistStream *persist; + IDirectMusicTool *tool; + DMUS_PATCH_PMSG *patch; + DMUS_PMSG *msg; + HRESULT hr; + DWORD ret; + + hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicPerformance, (void **)&performance); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicGraph, (void **)&graph); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_SetGraph(performance, graph); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicGraph_Release(graph); + + + /* create a segment and load a simple RIFF stream */ + + hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicSegment, (void **)&segment); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicSegment_QueryInterface(segment, &IID_IPersistStream, (void **)&persist); + ok(hr == S_OK, "got %#lx\n", hr); + hr = CreateStreamOnHGlobal(0, TRUE, &stream); + ok(hr == S_OK, "got %#lx\n", hr); + + CHUNK_RIFF(stream, "DMSG") + { + /* set a non-zero segment length, or nothing will be played */ + DMUS_IO_SEGMENT_HEADER head = {.mtLength = 2000}; + CHUNK_DATA(stream, "segh", head); + CHUNK_DATA(stream, "guid", CLSID_DirectMusicSegment); + } + CHUNK_END; + + hr = IStream_Seek(stream, zero, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IPersistStream_Load(persist, stream); + ok(hr == S_OK, "got %#lx\n", hr); + IPersistStream_Release(persist); + IStream_Release(stream); + + + /* add a sequence track to our segment */ + + hr = CoCreateInstance(&CLSID_DirectMusicBandTrack, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicTrack, (void **)&track); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicSegment_QueryInterface(track, &IID_IPersistStream, (void **)&persist); + ok(hr == S_OK, "got %#lx\n", hr); + hr = CreateStreamOnHGlobal(0, TRUE, &stream); + ok(hr == S_OK, "got %#lx\n", hr); + + CHUNK_RIFF(stream, "DMBT") + { + DMUS_IO_BAND_TRACK_HEADER head = {.bAutoDownload = TRUE}; + + CHUNK_DATA(stream, "bdth", head); + CHUNK_LIST(stream, "lbdl") + { + CHUNK_LIST(stream, "lbnd") + { + DMUS_IO_BAND_ITEM_HEADER head = {.lBandTime = 0}; + CHUNK_DATA(stream, "bdih", head); + + CHUNK_RIFF(stream, "DMBD") + { + GUID guid = CLSID_DirectMusicBand; + CHUNK_DATA(stream, "guid", guid); + + CHUNK_LIST(stream, "lbil") + { + CHUNK_LIST(stream, "lbin") + { + DMUS_IO_INSTRUMENT head = {.dwPatch = 1, .dwPChannel = 1, .dwFlags = DMUS_IO_INST_PATCH}; + CHUNK_DATA(stream, "bins", head); + } + CHUNK_END; + } + CHUNK_END; + } + CHUNK_END; + } + CHUNK_END; + + CHUNK_LIST(stream, "lbnd") + { + DMUS_IO_BAND_ITEM_HEADER head = {.lBandTime = 1000}; + CHUNK_DATA(stream, "bdih", head); + + CHUNK_RIFF(stream, "DMBD") + { + GUID guid = CLSID_DirectMusicBand; + CHUNK_DATA(stream, "guid", guid); + + CHUNK_LIST(stream, "lbil") + { + CHUNK_LIST(stream, "lbin") + { + DMUS_IO_INSTRUMENT head = {.dwPatch = 2, .dwPChannel = 1, .dwFlags = DMUS_IO_INST_PATCH}; + CHUNK_DATA(stream, "bins", head); + } + CHUNK_END; + + CHUNK_LIST(stream, "lbin") + { + DMUS_IO_INSTRUMENT head = {.dwPatch = 3, .dwPChannel = 2, .dwFlags = DMUS_IO_INST_PATCH}; + CHUNK_DATA(stream, "bins", head); + } + CHUNK_END; + } + CHUNK_END; + } + CHUNK_END; + } + CHUNK_END; + } + CHUNK_END; + } + CHUNK_END; + + hr = IStream_Seek(stream, zero, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + + /* band track requires the stream to implement IDirectMusicGetLoader */ + + hr = CoCreateInstance(&CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicLoader8, (void **)&loader); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicLoader_SetObject(loader, &desc); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + + hr = test_loader_stream_create(stream, loader, &loader_stream); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicLoader8_Release(loader); + + hr = IPersistStream_Load(persist, loader_stream); + ok(hr == S_OK, "got %#lx\n", hr); + IStream_Release(loader_stream); + + IPersistStream_Release(persist); + IStream_Release(stream); + + hr = IDirectMusicSegment_InsertTrack(segment, (IDirectMusicTrack *)track, 1); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicTrack_Release(track); + + + /* now play the segment, and check produced messages */ + + hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0x800, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 500, &msg); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&patch); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + check_dmus_patch_pmsg(patch, 0, 1, 0, 1); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)patch); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&patch); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + check_dmus_patch_pmsg(patch, 1000, 2, 0, 3); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)patch); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&patch); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + check_dmus_patch_pmsg(patch, 1000, 1, 0, 2); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)patch); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, &msg); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + } + + IDirectMusicSegment_Release(segment); + + + hr = IDirectMusicPerformance_CloseDown(performance); + ok(hr == S_OK, "got %#lx\n", hr); + + IDirectMusicPerformance_Release(performance); + IDirectMusicTool_Release(tool); +} + START_TEST(dmime) { CoInitialize(NULL); @@ -2701,6 +3183,7 @@ START_TEST(dmime) test_notification_pmsg(); test_wave_pmsg(); test_sequence_track(); + test_band_track_play(); CoUninitialize(); } From 07b1ffc70e1cd9b2bf8155c02076ea9f234c0231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 19 Sep 2023 17:28:30 +0200 Subject: [PATCH 2558/2777] dmusic/tests: Fixup chunk alignment in steam_end_chunk. (cherry picked from commit b6f1a1a186c270b5643bfcc910be37663b30c98d) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/tests/dmusic.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dlls/dmusic/tests/dmusic.c b/dlls/dmusic/tests/dmusic.c index 879a6f800cd..6210cb05e6c 100644 --- a/dlls/dmusic/tests/dmusic.c +++ b/dlls/dmusic/tests/dmusic.c @@ -85,17 +85,21 @@ static void stream_end_chunk(IStream *stream, ULARGE_INTEGER *offset) ok(hr == S_OK, "got %#lx\n", hr); hr = IStream_Seek(stream, *(LARGE_INTEGER *)&position, STREAM_SEEK_SET, NULL); ok(hr == S_OK, "got %#lx\n", hr); + hr = IStream_Write(stream, &zero, (position.QuadPart & 1), NULL); + ok(hr == S_OK, "got %#lx\n", hr); } #define CHUNK_BEGIN(stream, type) \ do { \ ULARGE_INTEGER __off; \ + IStream *__stream = (stream); \ stream_begin_chunk(stream, type, &__off); \ do #define CHUNK_RIFF(stream, form) \ do { \ ULARGE_INTEGER __off; \ + IStream *__stream = (stream); \ stream_begin_chunk(stream, "RIFF", &__off); \ IStream_Write(stream, form, 4, NULL); \ do @@ -103,13 +107,14 @@ static void stream_end_chunk(IStream *stream, ULARGE_INTEGER *offset) #define CHUNK_LIST(stream, form) \ do { \ ULARGE_INTEGER __off; \ + IStream *__stream = (stream); \ stream_begin_chunk(stream, "LIST", &__off); \ IStream_Write(stream, form, 4, NULL); \ do #define CHUNK_END \ while (0); \ - stream_end_chunk(stream, &__off); \ + stream_end_chunk(__stream, &__off); \ } while (0) #define CHUNK_DATA(stream, type, data) \ From 59a3e12010f98c16ef796f366283307262983893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 23:00:56 +0200 Subject: [PATCH 2559/2777] dmusic: Keep the original instrument patch in the entry. (cherry picked from commit ecb38bf1c9202f8621583dd41db7945c3523081b) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 10 ++++------ dlls/dmusic/tests/dmusic.c | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index b7c11dacb77..1074c4e2868 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -25,6 +25,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmusic); struct instrument_entry { struct list entry; + DWORD patch; DMUS_OBJECTDESC desc; IDirectMusicInstrument *instrument; }; @@ -176,15 +177,12 @@ static HRESULT WINAPI collection_GetInstrument(IDirectMusicCollection *iface, { struct collection *This = impl_from_IDirectMusicCollection(iface); struct instrument_entry *entry; - DWORD inst_patch; - HRESULT hr; TRACE("(%p, %lu, %p)\n", iface, patch, instrument); LIST_FOR_EACH_ENTRY(entry, &This->instruments, struct instrument_entry, entry) { - if (FAILED(hr = IDirectMusicInstrument_GetPatch(entry->instrument, &inst_patch))) return hr; - if (patch == inst_patch) + if (patch == entry->patch) { *instrument = entry->instrument; IDirectMusicInstrument_AddRef(entry->instrument); @@ -202,14 +200,13 @@ static HRESULT WINAPI collection_EnumInstrument(IDirectMusicCollection *iface, { struct collection *This = impl_from_IDirectMusicCollection(iface); struct instrument_entry *entry; - HRESULT hr; TRACE("(%p, %ld, %p, %p, %ld)\n", iface, index, patch, name, name_length); LIST_FOR_EACH_ENTRY(entry, &This->instruments, struct instrument_entry, entry) { if (index--) continue; - if (FAILED(hr = IDirectMusicInstrument_GetPatch(entry->instrument, patch))) return hr; + *patch = entry->patch; if (name) lstrcpynW(name, entry->desc.wszName, name_length); return S_OK; } @@ -239,6 +236,7 @@ static HRESULT parse_lins_list(struct collection *This, IStream *stream, struct case MAKE_IDTYPE(FOURCC_LIST, FOURCC_INS): if (!(entry = malloc(sizeof(*entry)))) return E_OUTOFMEMORY; hr = instrument_create_from_chunk(stream, &chunk, This, &entry->desc, &entry->instrument); + if (SUCCEEDED(hr)) hr = IDirectMusicInstrument_GetPatch(entry->instrument, &entry->patch); if (SUCCEEDED(hr)) list_add_tail(&This->instruments, &entry->entry); else free(entry); break; diff --git a/dlls/dmusic/tests/dmusic.c b/dlls/dmusic/tests/dmusic.c index 6210cb05e6c..703251bb9da 100644 --- a/dlls/dmusic/tests/dmusic.c +++ b/dlls/dmusic/tests/dmusic.c @@ -1184,7 +1184,7 @@ static void test_download_instrument(void) static const LARGE_INTEGER zero = {0}; IDirectMusicDownloadedInstrument *downloaded; IDirectMusicCollection *collection; - IDirectMusicInstrument *instrument; + IDirectMusicInstrument *instrument, *tmp_instrument; IPersistStream *persist; IDirectMusicPort *port; IDirectMusic *dmusic; @@ -1299,6 +1299,22 @@ static void test_download_instrument(void) hr = IDirectMusicCollection_GetInstrument(collection, 0x1234, &instrument); ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicInstrument_GetPatch(instrument, &patch); + ok(hr == S_OK, "got %#lx\n", hr); + ok(patch == 0x1234, "got %#lx\n", patch); + hr = IDirectMusicInstrument_SetPatch(instrument, 0x4321); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicInstrument_GetPatch(instrument, &patch); + ok(hr == S_OK, "got %#lx\n", hr); + ok(patch == 0x4321, "got %#lx\n", patch); + + hr = IDirectMusicCollection_GetInstrument(collection, 0x1234, &tmp_instrument); + ok(hr == S_OK, "got %#lx\n", hr); + ok(instrument == tmp_instrument, "got %p\n", tmp_instrument); + hr = IDirectMusicInstrument_GetPatch(tmp_instrument, &patch); + ok(hr == S_OK, "got %#lx\n", hr); + ok(patch == 0x4321, "got %#lx\n", patch); + IDirectMusicInstrument_Release(tmp_instrument); check_interface(instrument, &IID_IDirectMusicObject, FALSE); check_interface(instrument, &IID_IDirectMusicDownload, FALSE); From a09555418450a3e74aa363868a1f8aa5a0d9e9b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 19:23:22 +0200 Subject: [PATCH 2560/2777] dmband: Rewrite band track lbdl/lbnd lists parsing. (cherry picked from commit 9276aec695b59ace9ea0ed2491e138593158e255) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/bandtrack.c | 238 ++++++++++++----------------------- dlls/dmband/dmband_private.h | 14 --- 2 files changed, 83 insertions(+), 169 deletions(-) diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index 1a3cde5f1db..4bcf6cd8bfe 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -25,7 +25,7 @@ WINE_DECLARE_DEBUG_CHANNEL(dmfile); struct band_entry { struct list entry; - DMUS_PRIVATE_BAND_ITEM_HEADER head; + DMUS_IO_BAND_ITEM_HEADER2 head; IDirectMusicBand *band; }; @@ -331,170 +331,94 @@ static const IDirectMusicTrack8Vtbl band_track_vtbl = band_track_Join, }; -static HRESULT load_band(struct band_track *This, IStream *pClonedStream, - IDirectMusicBand **ppBand, DMUS_PRIVATE_BAND_ITEM_HEADER *pHeader) +static HRESULT parse_lbnd_list(struct band_track *This, IStream *stream, struct chunk_entry *parent) { - HRESULT hr = E_FAIL; - IPersistStream* pPersistStream = NULL; - - hr = CoCreateInstance (&CLSID_DirectMusicBand, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicBand, (LPVOID*) ppBand); - if (FAILED(hr)) { - ERR(": could not create object\n"); - return hr; - } - /* acquire PersistStream interface */ - hr = IDirectMusicBand_QueryInterface (*ppBand, &IID_IPersistStream, (LPVOID*) &pPersistStream); - if (FAILED(hr)) { - ERR(": could not acquire IPersistStream\n"); - return hr; - } - /* load */ - hr = IPersistStream_Load (pPersistStream, pClonedStream); - if (FAILED(hr)) { - ERR(": failed to load object\n"); - return hr; - } - - /* release all loading-related stuff */ - IPersistStream_Release (pPersistStream); - - /* - * @TODO insert pBand into This - */ - if (SUCCEEDED(hr)) - { - struct band_entry *entry; - if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY; - entry->head = *pHeader; - entry->band = *ppBand; - IDirectMusicBand_AddRef(*ppBand); - list_add_tail(&This->bands, &entry->entry); - } + struct chunk_entry chunk = {.parent = parent}; + DMUS_IO_BAND_ITEM_HEADER2 header2; + struct band_entry *entry; + IDirectMusicBand *band; + HRESULT hr; - return S_OK; -} + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case DMUS_FOURCC_BANDITEM_CHUNK: + { + DMUS_IO_BAND_ITEM_HEADER header; -static HRESULT parse_bands_list(struct band_track *This, DMUS_PRIVATE_CHUNK *pChunk, - IStream *pStm) -{ - HRESULT hr = E_FAIL; - DMUS_PRIVATE_CHUNK Chunk; - DWORD StreamSize, ListSize[3], ListCount[3]; - LARGE_INTEGER liMove; /* used when skipping chunks */ + if (SUCCEEDED(hr = stream_chunk_get_data(stream, &chunk, &header, sizeof(header)))) + { + header2.lBandTimeLogical = header.lBandTime; + header2.lBandTimePhysical = header.lBandTime; + } - IDirectMusicBand* pBand = NULL; - DMUS_PRIVATE_BAND_ITEM_HEADER header; + break; + } - memset(&header, 0, sizeof header); + case DMUS_FOURCC_BANDITEM_CHUNK2: + hr = stream_chunk_get_data(stream, &chunk, &header2, sizeof(header2)); + break; - if (pChunk->fccID != DMUS_FOURCC_BANDS_LIST) { - ERR_(dmfile)(": %s chunk should be a BANDS list\n", debugstr_fourcc (pChunk->fccID)); - return E_FAIL; - } + case MAKE_IDTYPE(FOURCC_RIFF, DMUS_FOURCC_BAND_FORM): + { + IPersistStream *persist; - ListSize[0] = pChunk->dwSize - sizeof(FOURCC); - ListCount[0] = 0; + if (FAILED(hr = CoCreateInstance(&CLSID_DirectMusicBand, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicBand, (void **)&band))) + break; - do { - IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); - ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); - switch (Chunk.fccID) { - case FOURCC_LIST: { - IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL); - TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID)); - ListSize[1] = Chunk.dwSize - sizeof(FOURCC); - ListCount[1] = 0; - do { - IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); - ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); - switch (Chunk.fccID) { - case DMUS_FOURCC_BANDITEM_CHUNK: { - DMUS_IO_BAND_ITEM_HEADER tmp_header; - TRACE_(dmfile)(": Band Item chunk v1\n"); - - IStream_Read (pStm, &tmp_header, sizeof(DMUS_IO_BAND_ITEM_HEADER), NULL); - TRACE_(dmfile)(" - lBandTime: %lu\n", tmp_header.lBandTime); - - header.dwVersion = 1; - header.lBandTime = tmp_header.lBandTime; - break; - } - case DMUS_FOURCC_BANDITEM_CHUNK2: { - DMUS_IO_BAND_ITEM_HEADER2 tmp_header2; - TRACE_(dmfile)(": Band Item chunk v2\n"); - - IStream_Read (pStm, &tmp_header2, sizeof(DMUS_IO_BAND_ITEM_HEADER2), NULL); - TRACE_(dmfile)(" - lBandTimeLogical: %lu\n", tmp_header2.lBandTimeLogical); - TRACE_(dmfile)(" - lBandTimePhysical: %lu\n", tmp_header2.lBandTimePhysical); - - header.dwVersion = 2; - header.lBandTimeLogical = tmp_header2.lBandTimeLogical; - header.lBandTimePhysical = tmp_header2.lBandTimePhysical; - break; - } - case FOURCC_RIFF: { - IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL); - TRACE_(dmfile)(": RIFF chunk of type %s\n", debugstr_fourcc(Chunk.fccID)); - StreamSize = Chunk.dwSize - sizeof(FOURCC); - switch (Chunk.fccID) { - case DMUS_FOURCC_BAND_FORM: { - ULARGE_INTEGER liOrigPos; - TRACE_(dmfile)(": BAND RIFF\n"); - - liMove.QuadPart = 0; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, &liOrigPos); - - liMove.QuadPart -= sizeof(FOURCC) + (sizeof(FOURCC)+sizeof(DWORD)); - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - - hr = load_band(This, pStm, &pBand, &header); - if (FAILED(hr)) { - ERR(": could not load track\n"); - return hr; - } - liMove.QuadPart = (LONGLONG)liOrigPos.QuadPart; - IStream_Seek (pStm, liMove, STREAM_SEEK_SET, NULL); - - IDirectMusicTrack_Release(pBand); pBand = NULL; /* now we can release at as it inserted */ - - /** now safe move the cursor */ - liMove.QuadPart = StreamSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - default: { - TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); - liMove.QuadPart = StreamSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - break; - } - default: { - TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - TRACE_(dmfile)(": ListCount[1] = %ld < ListSize[1] = %ld\n", ListCount[1], ListSize[1]); - } while (ListCount[1] < ListSize[1]); - break; - } - default: { - TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; + if (SUCCEEDED(hr = IDirectMusicBand_QueryInterface(band, &IID_IPersistStream, (void **)&persist))) + { + if (SUCCEEDED(hr = stream_reset_chunk_start(stream, &chunk))) + hr = IPersistStream_Load(persist, stream); + IPersistStream_Release(persist); + } + + break; + } + + default: + FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; } + + if (FAILED(hr)) return hr; + + if (!(entry = calloc(1, sizeof(*entry)))) return E_OUTOFMEMORY; + entry->head = header2; + entry->band = band; + IDirectMusicBand_AddRef(band); + list_add_tail(&This->bands, &entry->entry); + + return S_OK; +} + +static HRESULT parse_lbdl_list(struct band_track *This, IStream *stream, struct chunk_entry *parent) +{ + struct chunk_entry chunk = {.parent = parent}; + HRESULT hr; + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_BAND_LIST): + hr = parse_lbnd_list(This, stream, &chunk); + break; + + default: + FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; } - TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]); - } while (ListCount[0] < ListSize[0]); - return S_OK; + return S_OK; } static HRESULT parse_bandtrack_form(struct band_track *This, DMUS_PRIVATE_CHUNK *pChunk, @@ -560,8 +484,12 @@ static HRESULT parse_bandtrack_form(struct band_track *This, DMUS_PRIVATE_CHUNK break; } case DMUS_FOURCC_BANDS_LIST: { + static const LARGE_INTEGER zero = {0}; + struct chunk_entry chunk = {FOURCC_LIST, .size = Chunk.dwSize, .type = Chunk.fccID}; TRACE_(dmfile)(": TRACK list\n"); - hr = parse_bands_list(This, &Chunk, pStm); + IStream_Seek(pStm, zero, STREAM_SEEK_CUR, &chunk.offset); + chunk.offset.QuadPart -= 12; + hr = parse_lbdl_list(This, pStm, &chunk); if (FAILED(hr)) return hr; break; } diff --git a/dlls/dmband/dmband_private.h b/dlls/dmband/dmband_private.h index da6f0fa302f..40516fac49b 100644 --- a/dlls/dmband/dmband_private.h +++ b/dlls/dmband/dmband_private.h @@ -47,20 +47,6 @@ extern HRESULT create_dmband(REFIID riid, void **ret_iface); extern HRESULT create_dmbandtrack(REFIID riid, void **ret_iface); - -/***************************************************************************** - * Auxiliary definitions - */ -/* i don't like M$'s idea about two different band item headers, so behold: universal one */ -typedef struct _DMUS_PRIVATE_BAND_ITEM_HEADER { - DWORD dwVersion; /* 1 or 2 */ - /* v.1 */ - MUSIC_TIME lBandTime; - /* v.2 */ - MUSIC_TIME lBandTimeLogical; - MUSIC_TIME lBandTimePhysical; -} DMUS_PRIVATE_BAND_ITEM_HEADER; - /***************************************************************************** * Misc. */ From 206c0fcb3756098b9e0c3f37864204f52134d049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 19:28:15 +0200 Subject: [PATCH 2561/2777] dmband: Rewrite band track DBMT chunk parsing. (cherry picked from commit 48f276f8360afaf4fd80a8ca432b500d1feaac94) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/bandtrack.c | 122 ++++++++++++---------------------------- 1 file changed, 35 insertions(+), 87 deletions(-) diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index 4bcf6cd8bfe..ae240ee448f 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -421,99 +421,43 @@ static HRESULT parse_lbdl_list(struct band_track *This, IStream *stream, struct return S_OK; } -static HRESULT parse_bandtrack_form(struct band_track *This, DMUS_PRIVATE_CHUNK *pChunk, - IStream *pStm) +static HRESULT parse_dmbt_chunk(struct band_track *This, IStream *stream, struct chunk_entry *parent) { - HRESULT hr = E_FAIL; - DMUS_PRIVATE_CHUNK Chunk; - DWORD StreamSize, StreamCount, ListSize[3], ListCount[3]; - LARGE_INTEGER liMove; /* used when skipping chunks */ + struct chunk_entry chunk = {.parent = parent}; + HRESULT hr; - if (pChunk->fccID != DMUS_FOURCC_BANDTRACK_FORM) { - ERR_(dmfile)(": %s chunk should be a BANDTRACK form\n", debugstr_fourcc (pChunk->fccID)); - return E_FAIL; - } + if (FAILED(hr = dmobj_parsedescriptor(stream, parent, &This->dmobj.desc, + DMUS_OBJ_OBJECT|DMUS_OBJ_NAME|DMUS_OBJ_NAME_INAM|DMUS_OBJ_VERSION)) + || FAILED(hr = stream_reset_chunk_data(stream, parent))) + return hr; - StreamSize = pChunk->dwSize - sizeof(FOURCC); - StreamCount = 0; + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case DMUS_FOURCC_GUID_CHUNK: + case DMUS_FOURCC_VERSION_CHUNK: + case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_UNFO_LIST): + /* already parsed by dmobj_parsedescriptor */ + break; - do { - IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); - StreamCount += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); - - hr = IDirectMusicUtils_IPersistStream_ParseDescGeneric(&Chunk, pStm, &This->dmobj.desc); - if (FAILED(hr)) return hr; + case DMUS_FOURCC_BANDTRACK_CHUNK: + hr = stream_chunk_get_data(stream, &chunk, &This->header, sizeof(This->header)); + break; - if (hr == S_FALSE) { - switch (Chunk.fccID) { - case DMUS_FOURCC_BANDTRACK_CHUNK: { - TRACE_(dmfile)(": BandTrack chunk\n"); - IStream_Read (pStm, &This->header, sizeof(DMUS_IO_BAND_TRACK_HEADER), NULL); - TRACE_(dmfile)(" - bAutoDownload: %u\n", This->header.bAutoDownload); - break; - } - case FOURCC_LIST: { - IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL); - TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID)); - ListSize[0] = Chunk.dwSize - sizeof(FOURCC); - ListCount[0] = 0; - switch (Chunk.fccID) { - case DMUS_FOURCC_UNFO_LIST: { - TRACE_(dmfile)(": UNFO list\n"); - do { - IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); - ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize; - TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); - - hr = IDirectMusicUtils_IPersistStream_ParseUNFOGeneric(&Chunk, pStm, &This->dmobj.desc); - if (FAILED(hr)) return hr; - - if (hr == S_FALSE) { - switch (Chunk.fccID) { - default: { - TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - } - TRACE_(dmfile)(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]); - } while (ListCount[0] < ListSize[0]); - break; - } - case DMUS_FOURCC_BANDS_LIST: { - static const LARGE_INTEGER zero = {0}; - struct chunk_entry chunk = {FOURCC_LIST, .size = Chunk.dwSize, .type = Chunk.fccID}; - TRACE_(dmfile)(": TRACK list\n"); - IStream_Seek(pStm, zero, STREAM_SEEK_CUR, &chunk.offset); - chunk.offset.QuadPart -= 12; - hr = parse_lbdl_list(This, pStm, &chunk); - if (FAILED(hr)) return hr; - break; - } - default: { - TRACE_(dmfile)(": unknown (skipping)\n"); - liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC); - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - break; - } - default: { - TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } + case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_BANDS_LIST): + hr = parse_lbdl_list(This, stream, &chunk); + break; + + default: + FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; } - TRACE_(dmfile)(": StreamCount[0] = %ld < StreamSize[0] = %ld\n", StreamCount, StreamSize); - } while (StreamCount < StreamSize); - return S_OK; + return hr; } static inline struct band_track *impl_from_IPersistStream(IPersistStream *iface) @@ -538,8 +482,12 @@ static HRESULT WINAPI band_track_persist_stream_Load(IPersistStream *iface, IStr TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); switch (Chunk.fccID) { case DMUS_FOURCC_BANDTRACK_FORM: { + static const LARGE_INTEGER zero = {0}; + struct chunk_entry chunk = {FOURCC_LIST, .size = Chunk.dwSize, .type = Chunk.fccID}; TRACE_(dmfile)(": Band track form\n"); - hr = parse_bandtrack_form(This, &Chunk, pStm); + IStream_Seek(pStm, zero, STREAM_SEEK_CUR, &chunk.offset); + chunk.offset.QuadPart -= 12; + hr = parse_dmbt_chunk(This, pStm, &chunk); if (FAILED(hr)) return hr; break; } From c98f60b8c881c2814d02cbc62a135ff242154591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 19:29:56 +0200 Subject: [PATCH 2562/2777] dmband: Rewrite band track IPersistStream_Load. (cherry picked from commit a955339b3c00012f799ad53bdcaed6ee0491c2da) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/Makefile.in | 3 +- dlls/dmband/bandtrack.c | 85 +++++++------- dlls/dmband/dmband_main.c | 1 + dlls/dmband/dmband_private.h | 6 - dlls/dmband/dmutils.c | 219 ----------------------------------- dlls/dmband/dmutils.h | 37 ------ 6 files changed, 45 insertions(+), 306 deletions(-) delete mode 100644 dlls/dmband/dmutils.c delete mode 100644 dlls/dmband/dmutils.h diff --git a/dlls/dmband/Makefile.in b/dlls/dmband/Makefile.in index ef6b6a44c60..2c6a59dad4c 100644 --- a/dlls/dmband/Makefile.in +++ b/dlls/dmband/Makefile.in @@ -6,8 +6,7 @@ C_SRCS = \ band.c \ bandtrack.c \ dmband_main.c \ - dmobject.c \ - dmutils.c + dmobject.c IDL_SRCS = dmband.idl diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index ae240ee448f..ab12e1f1355 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -20,7 +20,6 @@ #include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmband); -WINE_DECLARE_DEBUG_CHANNEL(dmfile); struct band_entry { @@ -465,51 +464,53 @@ static inline struct band_track *impl_from_IPersistStream(IPersistStream *iface) return CONTAINING_RECORD(iface, struct band_track, dmobj.IPersistStream_iface); } -static HRESULT WINAPI band_track_persist_stream_Load(IPersistStream *iface, IStream *pStm) +static HRESULT WINAPI band_track_persist_stream_Load(IPersistStream *iface, IStream *stream) { - struct band_track *This = impl_from_IPersistStream(iface); - DMUS_PRIVATE_CHUNK Chunk; - LARGE_INTEGER liMove; - HRESULT hr; - - TRACE("(%p, %p): Loading\n", This, pStm); - - IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); - TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); - switch (Chunk.fccID) { - case FOURCC_RIFF: { - IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL); - TRACE_(dmfile)(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); - switch (Chunk.fccID) { - case DMUS_FOURCC_BANDTRACK_FORM: { - static const LARGE_INTEGER zero = {0}; - struct chunk_entry chunk = {FOURCC_LIST, .size = Chunk.dwSize, .type = Chunk.fccID}; - TRACE_(dmfile)(": Band track form\n"); - IStream_Seek(pStm, zero, STREAM_SEEK_CUR, &chunk.offset); - chunk.offset.QuadPart -= 12; - hr = parse_dmbt_chunk(This, pStm, &chunk); - if (FAILED(hr)) return hr; - break; - } - default: { - TRACE_(dmfile)(": unexpected chunk; loading failed)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - return E_FAIL; + struct band_track *This = impl_from_IPersistStream(iface); + struct chunk_entry chunk = {0}; + HRESULT hr; + + TRACE("(%p, %p)\n", This, stream); + + if ((hr = stream_get_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case MAKE_IDTYPE(FOURCC_RIFF, DMUS_FOURCC_BANDTRACK_FORM): + hr = parse_dmbt_chunk(This, stream, &chunk); + break; + + default: + WARN("Invalid band track chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + hr = DMUS_E_UNSUPPORTED_STREAM; + break; + } } + + if (FAILED(hr)) return hr; + + if (TRACE_ON(dmband)) + { + struct band_entry *entry; + int i = 0; + + TRACE("Loaded DirectMusicBandTrack %p\n", This); + dump_DMUS_OBJECTDESC(&This->dmobj.desc); + + TRACE(" - header:\n"); + TRACE(" - bAutoDownload: %u\n", This->header.bAutoDownload); + + TRACE(" - bands:\n"); + LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry) + { + TRACE(" - band[%u]: %p\n", i++, entry->band); + TRACE(" - lBandTimeLogical: %ld\n", entry->head.lBandTimeLogical); + TRACE(" - lBandTimePhysical: %ld\n", entry->head.lBandTimePhysical); + } } - TRACE_(dmfile)(": reading finished\n"); - break; - } - default: { - TRACE_(dmfile)(": unexpected chunk; loading failed)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */ - return E_FAIL; - } - } - return S_OK; + stream_skip_chunk(stream, &chunk); + return S_OK; } static const IPersistStreamVtbl band_track_persist_stream_vtbl = diff --git a/dlls/dmband/dmband_main.c b/dlls/dmband/dmband_main.c index c032a931f31..55f979e3fbc 100644 --- a/dlls/dmband/dmband_main.c +++ b/dlls/dmband/dmband_main.c @@ -17,6 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "initguid.h" #include "dmband_private.h" #include "rpcproxy.h" #include "dmobject.h" diff --git a/dlls/dmband/dmband_private.h b/dlls/dmband/dmband_private.h index 40516fac49b..444fe5ccf55 100644 --- a/dlls/dmband/dmband_private.h +++ b/dlls/dmband/dmband_private.h @@ -47,10 +47,4 @@ extern HRESULT create_dmband(REFIID riid, void **ret_iface); extern HRESULT create_dmbandtrack(REFIID riid, void **ret_iface); -/***************************************************************************** - * Misc. - */ - -#include "dmutils.h" - #endif /* __WINE_DMBAND_PRIVATE_H */ diff --git a/dlls/dmband/dmutils.c b/dlls/dmband/dmutils.c deleted file mode 100644 index 01cec0f4c64..00000000000 --- a/dlls/dmband/dmutils.c +++ /dev/null @@ -1,219 +0,0 @@ -/* Debug and Helper Functions - * - * Copyright (C) 2004 Rok Mandeljc - * Copyright (C) 2004 Raphael Junqueira - * - * This program 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 program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define COBJMACROS - - -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "winnt.h" -#include "wingdi.h" -#include "winuser.h" - -#include "wine/debug.h" -#include "objbase.h" - -#include "initguid.h" -#include "dmusici.h" -#include "dmusicf.h" -#include "dmusics.h" - -#include "dmutils.h" -#include "dmobject.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dmfile); - -HRESULT IDirectMusicUtils_IPersistStream_ParseDescGeneric (DMUS_PRIVATE_CHUNK* pChunk, IStream* pStm, LPDMUS_OBJECTDESC pDesc) { - - switch (pChunk->fccID) { - case DMUS_FOURCC_GUID_CHUNK: { - TRACE(": GUID chunk\n"); - pDesc->dwValidData |= DMUS_OBJ_OBJECT; - IStream_Read (pStm, &pDesc->guidObject, pChunk->dwSize, NULL); - break; - } - case DMUS_FOURCC_DATE_CHUNK: { - TRACE(": file date chunk\n"); - pDesc->dwValidData |= DMUS_OBJ_DATE; - IStream_Read (pStm, &pDesc->ftDate, pChunk->dwSize, NULL); - break; - } - case DMUS_FOURCC_NAME_CHUNK: { - TRACE(": name chunk\n"); - pDesc->dwValidData |= DMUS_OBJ_NAME; - IStream_Read (pStm, pDesc->wszName, pChunk->dwSize, NULL); - break; - } - case DMUS_FOURCC_FILE_CHUNK: { - TRACE(": file name chunk\n"); - pDesc->dwValidData |= DMUS_OBJ_FILENAME; - IStream_Read (pStm, pDesc->wszFileName, pChunk->dwSize, NULL); - break; - } - case DMUS_FOURCC_VERSION_CHUNK: { - TRACE(": version chunk\n"); - pDesc->dwValidData |= DMUS_OBJ_VERSION; - IStream_Read (pStm, &pDesc->vVersion, pChunk->dwSize, NULL); - break; - } - case DMUS_FOURCC_CATEGORY_CHUNK: { - TRACE(": category chunk\n"); - pDesc->dwValidData |= DMUS_OBJ_CATEGORY; - IStream_Read (pStm, pDesc->wszCategory, pChunk->dwSize, NULL); - break; - } - default: - /* not handled */ - return S_FALSE; - } - - return S_OK; -} - -HRESULT IDirectMusicUtils_IPersistStream_ParseUNFOGeneric (DMUS_PRIVATE_CHUNK* pChunk, IStream* pStm, LPDMUS_OBJECTDESC pDesc) { - - LARGE_INTEGER liMove; /* used when skipping chunks */ - - /** - * don't ask me why, but M$ puts INFO elements in UNFO list sometimes - * (though strings seem to be valid unicode) - */ - switch (pChunk->fccID) { - - case mmioFOURCC('I','N','A','M'): - case DMUS_FOURCC_UNAM_CHUNK: { - TRACE(": name chunk\n"); - pDesc->dwValidData |= DMUS_OBJ_NAME; - IStream_Read (pStm, pDesc->wszName, pChunk->dwSize, NULL); - TRACE(" - wszName: %s\n", debugstr_w(pDesc->wszName)); - break; - } - - case mmioFOURCC('I','A','R','T'): - case DMUS_FOURCC_UART_CHUNK: { - TRACE(": artist chunk (ignored)\n"); - liMove.QuadPart = pChunk->dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - case mmioFOURCC('I','C','O','P'): - case DMUS_FOURCC_UCOP_CHUNK: { - TRACE(": copyright chunk (ignored)\n"); - liMove.QuadPart = pChunk->dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - case mmioFOURCC('I','S','B','J'): - case DMUS_FOURCC_USBJ_CHUNK: { - TRACE(": subject chunk (ignored)\n"); - liMove.QuadPart = pChunk->dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - case mmioFOURCC('I','C','M','T'): - case DMUS_FOURCC_UCMT_CHUNK: { - TRACE(": comment chunk (ignored)\n"); - liMove.QuadPart = pChunk->dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - default: - /* not handled */ - return S_FALSE; - } - - return S_OK; -} - -HRESULT IDirectMusicUtils_IPersistStream_ParseReference (LPPERSISTSTREAM iface, DMUS_PRIVATE_CHUNK* pChunk, IStream* pStm, IDirectMusicObject** ppObject) { - DMUS_PRIVATE_CHUNK Chunk; - DWORD ListSize[3], ListCount[3]; - LARGE_INTEGER liMove; /* used when skipping chunks */ - HRESULT hr; - - DMUS_IO_REFERENCE ref; - DMUS_OBJECTDESC ref_desc; - - memset(&ref, 0, sizeof(ref)); - memset(&ref_desc, 0, sizeof(ref_desc)); - - if (pChunk->fccID != DMUS_FOURCC_REF_LIST) { - ERR_(dmfile)(": %s chunk should be a REF list\n", debugstr_fourcc (pChunk->fccID)); - return E_FAIL; - } - - ListSize[0] = pChunk->dwSize - sizeof(FOURCC); - ListCount[0] = 0; - - do { - IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL); - ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize; - TRACE(": %s chunk (size = %ld)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize); - - hr = IDirectMusicUtils_IPersistStream_ParseDescGeneric(&Chunk, pStm, &ref_desc); - if (FAILED(hr)) return hr; - - if (hr == S_FALSE) { - switch (Chunk.fccID) { - case DMUS_FOURCC_REF_CHUNK: { - TRACE(": Reference chunk\n"); - if (Chunk.dwSize != sizeof(DMUS_IO_REFERENCE)) return E_FAIL; - IStream_Read (pStm, &ref, sizeof(DMUS_IO_REFERENCE), NULL); - TRACE(" - guidClassID: %s\n", debugstr_dmguid(&ref.guidClassID)); - TRACE(" - dwValidData: %lu\n", ref.dwValidData); - break; - } - default: { - TRACE(": unknown chunk (irrelevant & skipping)\n"); - liMove.QuadPart = Chunk.dwSize; - IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); - break; - } - } - } - TRACE(": ListCount[0] = %ld < ListSize[0] = %ld\n", ListCount[0], ListSize[0]); - } while (ListCount[0] < ListSize[0]); - - ref_desc.dwValidData |= DMUS_OBJ_CLASS; - ref_desc.guidClass = ref.guidClassID; - - TRACE("** DM Reference Begin of Load ***\n"); - TRACE("With Desc:\n"); - dump_DMUS_OBJECTDESC(&ref_desc); - - { - LPDIRECTMUSICGETLOADER pGetLoader = NULL; - LPDIRECTMUSICLOADER pLoader = NULL; - - IStream_QueryInterface (pStm, &IID_IDirectMusicGetLoader, (LPVOID*)&pGetLoader); - IDirectMusicGetLoader_GetLoader (pGetLoader, &pLoader); - IDirectMusicGetLoader_Release (pGetLoader); - - hr = IDirectMusicLoader_GetObject (pLoader, &ref_desc, &IID_IDirectMusicObject, (LPVOID*)ppObject); - IDirectMusicLoader_Release (pLoader); /* release loader */ - } - TRACE("** DM Reference End of Load ***\n"); - - return hr; -} diff --git a/dlls/dmband/dmutils.h b/dlls/dmband/dmutils.h deleted file mode 100644 index 7f9b98cf310..00000000000 --- a/dlls/dmband/dmutils.h +++ /dev/null @@ -1,37 +0,0 @@ -/* Debug and Helper Functions - * - * Copyright (C) 2003-2004 Rok Mandeljc - * Copyright (C) 2003-2004 Raphael Junqueira - * - * This program 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 program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#ifndef __WINE_DMUTILS_H -#define __WINE_DMUTILS_H - -/* for simpler reading */ -typedef struct _DMUS_PRIVATE_CHUNK { - FOURCC fccID; /* FOURCC ID of the chunk */ - DWORD dwSize; /* size of the chunk */ -} DMUS_PRIVATE_CHUNK, *LPDMUS_PRIVATE_CHUNK; - -/** - * Parsing utilities - */ -extern HRESULT IDirectMusicUtils_IPersistStream_ParseDescGeneric (DMUS_PRIVATE_CHUNK* pChunk, IStream* pStm, LPDMUS_OBJECTDESC pDesc); -extern HRESULT IDirectMusicUtils_IPersistStream_ParseUNFOGeneric (DMUS_PRIVATE_CHUNK* pChunk, IStream* pStm, LPDMUS_OBJECTDESC pDesc); -extern HRESULT IDirectMusicUtils_IPersistStream_ParseReference (LPPERSISTSTREAM iface, DMUS_PRIVATE_CHUNK* pChunk, IStream* pStm, IDirectMusicObject** ppObject); - -#endif /* __WINE_DMUTILS_H */ From e306168e3feb46e7ef98d6f81c758917e0026913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 15 Sep 2023 11:45:59 +0200 Subject: [PATCH 2563/2777] dmime: Get rid of the IDirectMusicSeqTrack typedef. (cherry picked from commit d3742ab843ba26ac4c41f526d54af8b1ce8176f1) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/seqtrack.c | 54 ++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/dlls/dmime/seqtrack.c b/dlls/dmime/seqtrack.c index 0e496a5131c..16483c85457 100644 --- a/dlls/dmime/seqtrack.c +++ b/dlls/dmime/seqtrack.c @@ -1,5 +1,4 @@ -/* IDirectMusicSeqTrack Implementation - * +/* * Copyright (C) 2003-2004 Rok Mandeljc * * This program is free software; you can redistribute it and/or @@ -22,25 +21,22 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmime); -/***************************************************************************** - * IDirectMusicSeqTrack implementation - */ -typedef struct IDirectMusicSeqTrack { +struct sequence_track +{ IDirectMusicTrack8 IDirectMusicTrack8_iface; struct dmobject dmobj; /* IPersistStream only */ LONG ref; -} IDirectMusicSeqTrack; +}; -/* IDirectMusicSeqTrack IDirectMusicTrack8 part: */ -static inline IDirectMusicSeqTrack *impl_from_IDirectMusicTrack8(IDirectMusicTrack8 *iface) +static inline struct sequence_track *impl_from_IDirectMusicTrack8(IDirectMusicTrack8 *iface) { - return CONTAINING_RECORD(iface, IDirectMusicSeqTrack, IDirectMusicTrack8_iface); + return CONTAINING_RECORD(iface, struct sequence_track, IDirectMusicTrack8_iface); } static HRESULT WINAPI sequence_track_QueryInterface(IDirectMusicTrack8 *iface, REFIID riid, void **ret_iface) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface); @@ -62,7 +58,7 @@ static HRESULT WINAPI sequence_track_QueryInterface(IDirectMusicTrack8 *iface, R static ULONG WINAPI sequence_track_AddRef(IDirectMusicTrack8 *iface) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); @@ -72,7 +68,7 @@ static ULONG WINAPI sequence_track_AddRef(IDirectMusicTrack8 *iface) static ULONG WINAPI sequence_track_Release(IDirectMusicTrack8 *iface) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); LONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); @@ -86,7 +82,7 @@ static ULONG WINAPI sequence_track_Release(IDirectMusicTrack8 *iface) static HRESULT WINAPI sequence_track_Init(IDirectMusicTrack8 *iface, IDirectMusicSegment *pSegment) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); FIXME("(%p, %p): stub\n", This, pSegment); return S_OK; } @@ -95,14 +91,14 @@ static HRESULT WINAPI sequence_track_InitPlay(IDirectMusicTrack8 *iface, IDirectMusicSegmentState *pSegmentState, IDirectMusicPerformance *pPerformance, void **ppStateData, DWORD dwVirtualTrack8ID, DWORD dwFlags) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); FIXME("(%p, %p, %p, %p, %ld, %ld): stub\n", This, pSegmentState, pPerformance, ppStateData, dwVirtualTrack8ID, dwFlags); return S_OK; } static HRESULT WINAPI sequence_track_EndPlay(IDirectMusicTrack8 *iface, void *pStateData) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); FIXME("(%p, %p): stub\n", This, pStateData); return S_OK; } @@ -111,7 +107,7 @@ static HRESULT WINAPI sequence_track_Play(IDirectMusicTrack8 *iface, void *pStat MUSIC_TIME mtStart, MUSIC_TIME mtEnd, MUSIC_TIME mtOffset, DWORD dwFlags, IDirectMusicPerformance *pPerf, IDirectMusicSegmentState *pSegSt, DWORD dwVirtualID) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); FIXME("(%p, %p, %ld, %ld, %ld, %ld, %p, %p, %ld): stub\n", This, pStateData, mtStart, mtEnd, mtOffset, dwFlags, pPerf, pSegSt, dwVirtualID); return S_OK; } @@ -119,7 +115,7 @@ static HRESULT WINAPI sequence_track_Play(IDirectMusicTrack8 *iface, void *pStat static HRESULT WINAPI sequence_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time, MUSIC_TIME *next, void *param) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s, %ld, %p, %p): method not implemented\n", This, debugstr_dmguid(type), time, next, param); @@ -129,7 +125,7 @@ static HRESULT WINAPI sequence_track_GetParam(IDirectMusicTrack8 *iface, REFGUID static HRESULT WINAPI sequence_track_SetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time, void *param) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s, %ld, %p): method not implemented\n", This, debugstr_dmguid(type), time, param); return E_NOTIMPL; @@ -137,7 +133,7 @@ static HRESULT WINAPI sequence_track_SetParam(IDirectMusicTrack8 *iface, REFGUID static HRESULT WINAPI sequence_track_IsParamSupported(IDirectMusicTrack8 *iface, REFGUID type) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(type)); return E_NOTIMPL; @@ -146,7 +142,7 @@ static HRESULT WINAPI sequence_track_IsParamSupported(IDirectMusicTrack8 *iface, static HRESULT WINAPI sequence_track_AddNotificationType(IDirectMusicTrack8 *iface, REFGUID notiftype) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype)); return E_NOTIMPL; @@ -155,7 +151,7 @@ static HRESULT WINAPI sequence_track_AddNotificationType(IDirectMusicTrack8 *ifa static HRESULT WINAPI sequence_track_RemoveNotificationType(IDirectMusicTrack8 *iface, REFGUID notiftype) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype)); return E_NOTIMPL; @@ -164,7 +160,7 @@ static HRESULT WINAPI sequence_track_RemoveNotificationType(IDirectMusicTrack8 * static HRESULT WINAPI sequence_track_Clone(IDirectMusicTrack8 *iface, MUSIC_TIME mtStart, MUSIC_TIME mtEnd, IDirectMusicTrack **ppTrack) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); FIXME("(%p, %ld, %ld, %p): stub\n", This, mtStart, mtEnd, ppTrack); return S_OK; } @@ -173,7 +169,7 @@ static HRESULT WINAPI sequence_track_PlayEx(IDirectMusicTrack8 *iface, void *pSt REFERENCE_TIME rtStart, REFERENCE_TIME rtEnd, REFERENCE_TIME rtOffset, DWORD dwFlags, IDirectMusicPerformance *pPerf, IDirectMusicSegmentState *pSegSt, DWORD dwVirtualID) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); FIXME("(%p, %p, 0x%s, 0x%s, 0x%s, %ld, %p, %p, %ld): stub\n", This, pStateData, wine_dbgstr_longlong(rtStart), wine_dbgstr_longlong(rtEnd), wine_dbgstr_longlong(rtOffset), dwFlags, pPerf, pSegSt, dwVirtualID); return S_OK; @@ -182,7 +178,7 @@ static HRESULT WINAPI sequence_track_PlayEx(IDirectMusicTrack8 *iface, void *pSt static HRESULT WINAPI sequence_track_GetParamEx(IDirectMusicTrack8 *iface, REFGUID type, REFERENCE_TIME time, REFERENCE_TIME *next, void *param, void *state, DWORD flags) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s, %s, %p, %p, %p, %lx): method not implemented\n", This, debugstr_dmguid(type), wine_dbgstr_longlong(time), next, param, state, flags); @@ -192,7 +188,7 @@ static HRESULT WINAPI sequence_track_GetParamEx(IDirectMusicTrack8 *iface, REFGU static HRESULT WINAPI sequence_track_SetParamEx(IDirectMusicTrack8 *iface, REFGUID type, REFERENCE_TIME time, void *param, void *state, DWORD flags) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s, %s, %p, %p, %lx): method not implemented\n", This, debugstr_dmguid(type), wine_dbgstr_longlong(time), param, state, flags); @@ -202,7 +198,7 @@ static HRESULT WINAPI sequence_track_SetParamEx(IDirectMusicTrack8 *iface, REFGU static HRESULT WINAPI sequence_track_Compose(IDirectMusicTrack8 *iface, IUnknown *context, DWORD trackgroup, IDirectMusicTrack **track) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %p, %ld, %p): method not implemented\n", This, context, trackgroup, track); return E_NOTIMPL; @@ -211,7 +207,7 @@ static HRESULT WINAPI sequence_track_Compose(IDirectMusicTrack8 *iface, IUnknown static HRESULT WINAPI sequence_track_Join(IDirectMusicTrack8 *iface, IDirectMusicTrack *newtrack, MUSIC_TIME join, IUnknown *context, DWORD trackgroup, IDirectMusicTrack **resulttrack) { - IDirectMusicSeqTrack *This = impl_from_IDirectMusicTrack8(iface); + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %p, %ld, %p, %ld, %p): method not implemented\n", This, newtrack, join, context, trackgroup, resulttrack); return E_NOTIMPL; @@ -258,7 +254,7 @@ static const IPersistStreamVtbl persiststream_vtbl = { /* for ClassFactory */ HRESULT create_dmseqtrack(REFIID lpcGUID, void **ppobj) { - IDirectMusicSeqTrack *track; + struct sequence_track *track; HRESULT hr; *ppobj = NULL; From 3931ff22a67f8ed3ba32606854ade670522dfc61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 15 Sep 2023 11:46:23 +0200 Subject: [PATCH 2564/2777] dmime: Implement DirectMusicSeqTrack IPersistStream_Load. (cherry picked from commit 27ab696752294f6b847515fe0bd905d448d26e64) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/seqtrack.c | 132 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 2 deletions(-) diff --git a/dlls/dmime/seqtrack.c b/dlls/dmime/seqtrack.c index 16483c85457..ae2f002da92 100644 --- a/dlls/dmime/seqtrack.c +++ b/dlls/dmime/seqtrack.c @@ -26,6 +26,12 @@ struct sequence_track IDirectMusicTrack8 IDirectMusicTrack8_iface; struct dmobject dmobj; /* IPersistStream only */ LONG ref; + + DMUS_IO_SEQ_ITEM *items; + unsigned int count; + + DMUS_IO_CURVE_ITEM *curve_items; + unsigned int curve_count; }; static inline struct sequence_track *impl_from_IDirectMusicTrack8(IDirectMusicTrack8 *iface) @@ -234,10 +240,132 @@ static const IDirectMusicTrack8Vtbl dmtrack8_vtbl = { sequence_track_Join }; +static HRESULT parse_curl_list(struct sequence_track *This, IStream *stream, struct chunk_entry *chunk) +{ + HRESULT hr; + UINT i; + + if (FAILED(hr = stream_chunk_get_array(stream, chunk, (void **)&This->curve_items, + &This->curve_count, sizeof(*This->curve_items)))) + { + /* try again with the older DMUS_IO_CURVE_ITEM size */ + UINT size = offsetof(DMUS_IO_CURVE_ITEM, wParamType); + BYTE *buffer; + + if (FAILED(hr = stream_reset_chunk_data(stream, chunk))) return hr; + if (FAILED(hr = stream_chunk_get_array(stream, chunk, (void **)&buffer, + &This->curve_count, size))) + return hr; + + if (!(This->curve_items = calloc(This->curve_count, sizeof(*This->curve_items)))) return E_OUTOFMEMORY; + for (i = 0; i < This->curve_count; i++) memcpy(This->curve_items + i, buffer + size * i, size); + free(buffer); + } + + return S_OK; +} + +static HRESULT parse_seqt_chunk(struct sequence_track *This, IStream *stream, struct chunk_entry *parent) +{ + struct chunk_entry chunk = {.parent = parent}; + HRESULT hr; + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case DMUS_FOURCC_SEQ_LIST: + hr = stream_chunk_get_array(stream, &chunk, (void **)&This->items, + &This->count, sizeof(*This->items)); + break; + + case DMUS_FOURCC_CURVE_LIST: + hr = parse_curl_list(This, stream, &chunk); + break; + + default: + FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; + } + + return hr; +} + +static inline struct sequence_track *impl_from_IPersistStream(IPersistStream *iface) +{ + return CONTAINING_RECORD(iface, struct sequence_track, dmobj.IPersistStream_iface); +} + static HRESULT WINAPI track_IPersistStream_Load(IPersistStream *iface, IStream *stream) { - FIXME(": Loading not implemented yet\n"); - return S_OK; + struct sequence_track *This = impl_from_IPersistStream(iface); + struct chunk_entry chunk = {0}; + HRESULT hr; + + TRACE("(%p, %p)\n", This, stream); + + if ((hr = stream_get_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case DMUS_FOURCC_SEQ_TRACK: + hr = parse_seqt_chunk(This, stream, &chunk); + break; + + default: + WARN("Invalid seq track chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + hr = DMUS_E_UNSUPPORTED_STREAM; + break; + } + } + + if (FAILED(hr)) return hr; + + if (TRACE_ON(dmime)) + { + UINT i; + + TRACE("Loaded DirectMusicSeqTrack %p\n", This); + + TRACE("- %u items:\n", This->count); + for (i = 0; i < This->count; i++) + { + TRACE(" - DMUS_IO_SEQ_ITEM[%u]\n", i); + TRACE(" - mtTime: %ld\n", This->items[i].mtTime); + TRACE(" - mtDuration: %ld\n", This->items[i].mtDuration); + TRACE(" - dwPChannel: %ld\n", This->items[i].dwPChannel); + TRACE(" - nOffset: %d\n", This->items[i].nOffset); + TRACE(" - bStatus: %d\n", This->items[i].bStatus); + TRACE(" - bByte1: %#x\n", This->items[i].bByte1); + TRACE(" - bByte2: %#x\n", This->items[i].bByte2); + } + + TRACE("- %u curves:\n", This->curve_count); + for (i = 0; i < This->curve_count; i++) + { + TRACE(" - DMUS_IO_CURVE_ITEM[%u]\n", i); + TRACE(" - mtStart: %ld\n", This->curve_items[i].mtStart); + TRACE(" - mtDuration: %ld\n", This->curve_items[i].mtDuration); + TRACE(" - mtResetDuration: %ld\n", This->curve_items[i].mtResetDuration); + TRACE(" - dwPChannel: %ld\n", This->curve_items[i].dwPChannel); + TRACE(" - nOffset: %d\n", This->curve_items[i].nOffset); + TRACE(" - nStartValue: %d\n", This->curve_items[i].nStartValue); + TRACE(" - nEndValue: %d\n", This->curve_items[i].nEndValue); + TRACE(" - nResetValue: %d\n", This->curve_items[i].nResetValue); + TRACE(" - bType: %d\n", This->curve_items[i].bType); + TRACE(" - bCurveShape: %d\n", This->curve_items[i].bCurveShape); + TRACE(" - bCCData: %d\n", This->curve_items[i].bCCData); + TRACE(" - bFlags: %d\n", This->curve_items[i].bFlags); + TRACE(" - wParamType: %d\n", This->curve_items[i].wParamType); + TRACE(" - wMergeIndex: %d\n", This->curve_items[i].wMergeIndex); + } + } + + stream_skip_chunk(stream, &chunk); + return S_OK; } static const IPersistStreamVtbl persiststream_vtbl = { From 585b9f93463924d3417915c01851cba62a908f3f Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 12 Jul 2023 15:47:09 +0200 Subject: [PATCH 2565/2777] dmloader: Use nameless unions/structs. (cherry picked from commit e0dd29fffe8df167de6cec219722ee3e8d776471) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmloader/loaderstream.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/dlls/dmloader/loaderstream.c b/dlls/dmloader/loaderstream.c index c2c5105a5e9..5d6c5ad3e25 100644 --- a/dlls/dmloader/loaderstream.c +++ b/dlls/dmloader/loaderstream.c @@ -44,8 +44,6 @@ * - Rok Mandeljc; 24. April, 2004 */ -#define NONAMELESSUNION - #include "dmloader_private.h" WINE_DEFAULT_DEBUG_CHANNEL(dmloader); @@ -149,10 +147,10 @@ static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Seek (LPSTREAM iface, if (This->hFile == INVALID_HANDLE_VALUE) return E_FAIL; - liNewPos.u.HighPart = dlibMove.u.HighPart; - liNewPos.u.LowPart = SetFilePointer (This->hFile, dlibMove.u.LowPart, &liNewPos.u.HighPart, dwOrigin); + liNewPos.HighPart = dlibMove.HighPart; + liNewPos.LowPart = SetFilePointer (This->hFile, dlibMove.LowPart, &liNewPos.HighPart, dwOrigin); - if (liNewPos.u.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) return E_FAIL; + if (liNewPos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) return E_FAIL; if (plibNewPosition) plibNewPosition->QuadPart = liNewPos.QuadPart; return S_OK; From a3ab3363a3a03d104fe81ef71a897e139738cabf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 21 Sep 2023 08:05:11 +0200 Subject: [PATCH 2566/2777] dmloader: Rename IDirectMusicLoaderImpl method prefix to loader. (cherry picked from commit 464c1a8f72524af8a4947e6f80e8032a77bf7477) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmloader/loader.c | 72 ++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/dlls/dmloader/loader.c b/dlls/dmloader/loader.c index 7b1fb8d04a5..c5801ed32fd 100644 --- a/dlls/dmloader/loader.c +++ b/dlls/dmloader/loader.c @@ -111,12 +111,7 @@ static HRESULT DMUSIC_CopyDescriptor(DMUS_OBJECTDESC *pDst, DMUS_OBJECTDESC *pSr return S_OK; } -/***************************************************************************** - * IDirectMusicLoaderImpl implementation - */ -/* IUnknown/IDirectMusicLoader(8) part: */ - -static HRESULT WINAPI IDirectMusicLoaderImpl_QueryInterface(IDirectMusicLoader8 *iface, REFIID riid, void **ppobj) +static HRESULT WINAPI loader_QueryInterface(IDirectMusicLoader8 *iface, REFIID riid, void **ppobj) { IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); @@ -133,7 +128,7 @@ static HRESULT WINAPI IDirectMusicLoaderImpl_QueryInterface(IDirectMusicLoader8 return E_NOINTERFACE; } -static ULONG WINAPI IDirectMusicLoaderImpl_AddRef(IDirectMusicLoader8 *iface) +static ULONG WINAPI loader_AddRef(IDirectMusicLoader8 *iface) { IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); ULONG ref = InterlockedIncrement(&This->ref); @@ -143,7 +138,7 @@ static ULONG WINAPI IDirectMusicLoaderImpl_AddRef(IDirectMusicLoader8 *iface) return ref; } -static ULONG WINAPI IDirectMusicLoaderImpl_Release(IDirectMusicLoader8 *iface) +static ULONG WINAPI loader_Release(IDirectMusicLoader8 *iface) { IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); ULONG ref = InterlockedDecrement(&This->ref); @@ -251,7 +246,7 @@ static struct cache_entry *find_cache_object(IDirectMusicLoaderImpl *This, DMUS_ return NULL; } -static HRESULT WINAPI IDirectMusicLoaderImpl_GetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDESC *pDesc, REFIID riid, void **ppv) +static HRESULT WINAPI loader_GetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDESC *pDesc, REFIID riid, void **ppv) { IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); HRESULT result = S_OK; @@ -451,7 +446,7 @@ static HRESULT WINAPI IDirectMusicLoaderImpl_GetObject(IDirectMusicLoader8 *ifac return result; } -static HRESULT WINAPI IDirectMusicLoaderImpl_SetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDESC *pDesc) +static HRESULT WINAPI loader_SetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDESC *pDesc) { IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); LPSTREAM pStream; @@ -575,7 +570,7 @@ static HRESULT WINAPI IDirectMusicLoaderImpl_SetObject(IDirectMusicLoader8 *ifac return S_OK; } -static HRESULT WINAPI IDirectMusicLoaderImpl_SetSearchDirectory(IDirectMusicLoader8 *iface, +static HRESULT WINAPI loader_SetSearchDirectory(IDirectMusicLoader8 *iface, REFGUID class, WCHAR *path, BOOL clear) { IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); @@ -610,7 +605,7 @@ static HRESULT WINAPI IDirectMusicLoaderImpl_SetSearchDirectory(IDirectMusicLoad return S_OK; } -static HRESULT WINAPI IDirectMusicLoaderImpl_ScanDirectory(IDirectMusicLoader8 *iface, REFGUID rguidClass, WCHAR *pwzFileExtension, WCHAR *pwzScanFileName) +static HRESULT WINAPI loader_ScanDirectory(IDirectMusicLoader8 *iface, REFGUID rguidClass, WCHAR *pwzFileExtension, WCHAR *pwzScanFileName) { IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); WIN32_FIND_DATAW FileData; @@ -669,7 +664,7 @@ static HRESULT WINAPI IDirectMusicLoaderImpl_ScanDirectory(IDirectMusicLoader8 * } while (1); } -static HRESULT WINAPI IDirectMusicLoaderImpl_CacheObject(IDirectMusicLoader8 *iface, +static HRESULT WINAPI loader_CacheObject(IDirectMusicLoader8 *iface, IDirectMusicObject *object) { IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); @@ -699,7 +694,7 @@ static HRESULT WINAPI IDirectMusicLoaderImpl_CacheObject(IDirectMusicLoader8 *if return DMUS_E_LOADER_OBJECTNOTFOUND; } -static HRESULT WINAPI IDirectMusicLoaderImpl_ReleaseObject(IDirectMusicLoader8 *iface, +static HRESULT WINAPI loader_ReleaseObject(IDirectMusicLoader8 *iface, IDirectMusicObject *object) { IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); @@ -730,7 +725,7 @@ static HRESULT WINAPI IDirectMusicLoaderImpl_ReleaseObject(IDirectMusicLoader8 * return S_FALSE; } -static HRESULT WINAPI IDirectMusicLoaderImpl_ClearCache(IDirectMusicLoader8 *iface, REFGUID class) +static HRESULT WINAPI loader_ClearCache(IDirectMusicLoader8 *iface, REFGUID class) { IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); struct cache_entry *obj, *obj2; @@ -750,7 +745,7 @@ static HRESULT WINAPI IDirectMusicLoaderImpl_ClearCache(IDirectMusicLoader8 *ifa return S_OK; } -static HRESULT WINAPI IDirectMusicLoaderImpl_EnableCache(IDirectMusicLoader8 *iface, REFGUID class, +static HRESULT WINAPI loader_EnableCache(IDirectMusicLoader8 *iface, REFGUID class, BOOL enable) { IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); @@ -780,7 +775,7 @@ static HRESULT WINAPI IDirectMusicLoaderImpl_EnableCache(IDirectMusicLoader8 *if return S_OK; } -static HRESULT WINAPI IDirectMusicLoaderImpl_EnumObject(IDirectMusicLoader8 *iface, REFGUID rguidClass, DWORD dwIndex, DMUS_OBJECTDESC *pDesc) +static HRESULT WINAPI loader_EnumObject(IDirectMusicLoader8 *iface, REFGUID rguidClass, DWORD dwIndex, DMUS_OBJECTDESC *pDesc) { IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); DWORD dwCount = 0; @@ -808,12 +803,12 @@ static HRESULT WINAPI IDirectMusicLoaderImpl_EnumObject(IDirectMusicLoader8 *ifa return S_FALSE; } -static void WINAPI IDirectMusicLoaderImpl_CollectGarbage(IDirectMusicLoader8 *iface) +static void WINAPI loader_CollectGarbage(IDirectMusicLoader8 *iface) { FIXME("(%p)->(): stub\n", iface); } -static HRESULT WINAPI IDirectMusicLoaderImpl_ReleaseObjectByUnknown(IDirectMusicLoader8 *iface, IUnknown *pObject) +static HRESULT WINAPI loader_ReleaseObjectByUnknown(IDirectMusicLoader8 *iface, IUnknown *pObject) { IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); HRESULT result; @@ -835,13 +830,13 @@ static HRESULT WINAPI IDirectMusicLoaderImpl_ReleaseObjectByUnknown(IDirectMusic return result; } -static HRESULT WINAPI IDirectMusicLoaderImpl_LoadObjectFromFile(IDirectMusicLoader8 *iface, REFGUID rguidClassID, REFIID iidInterfaceID, WCHAR *pwzFilePath, void **ppObject) +static HRESULT WINAPI loader_LoadObjectFromFile(IDirectMusicLoader8 *iface, REFGUID rguidClassID, REFIID iidInterfaceID, WCHAR *pwzFilePath, void **ppObject) { IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); DMUS_OBJECTDESC ObjDesc; WCHAR wszLoaderSearchPath[MAX_PATH]; - TRACE("(%p, %s, %s, %s, %p): wrapping to IDirectMusicLoaderImpl_GetObject\n", This, debugstr_dmguid(rguidClassID), debugstr_dmguid(iidInterfaceID), debugstr_w(pwzFilePath), ppObject); + TRACE("(%p, %s, %s, %s, %p): wrapping to loader_GetObject\n", This, debugstr_dmguid(rguidClassID), debugstr_dmguid(iidInterfaceID), debugstr_w(pwzFilePath), ppObject); DM_STRUCT_INIT(&ObjDesc); ObjDesc.dwValidData = DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_CLASS; /* I believe I've read somewhere in MSDN that this function requires either full path or relative path */ @@ -866,22 +861,23 @@ static HRESULT WINAPI IDirectMusicLoaderImpl_LoadObjectFromFile(IDirectMusicLoad return IDirectMusicLoader_GetObject(iface, &ObjDesc, iidInterfaceID, ppObject); } -static const IDirectMusicLoader8Vtbl DirectMusicLoader_Loader_Vtbl = { - IDirectMusicLoaderImpl_QueryInterface, - IDirectMusicLoaderImpl_AddRef, - IDirectMusicLoaderImpl_Release, - IDirectMusicLoaderImpl_GetObject, - IDirectMusicLoaderImpl_SetObject, - IDirectMusicLoaderImpl_SetSearchDirectory, - IDirectMusicLoaderImpl_ScanDirectory, - IDirectMusicLoaderImpl_CacheObject, - IDirectMusicLoaderImpl_ReleaseObject, - IDirectMusicLoaderImpl_ClearCache, - IDirectMusicLoaderImpl_EnableCache, - IDirectMusicLoaderImpl_EnumObject, - IDirectMusicLoaderImpl_CollectGarbage, - IDirectMusicLoaderImpl_ReleaseObjectByUnknown, - IDirectMusicLoaderImpl_LoadObjectFromFile +static const IDirectMusicLoader8Vtbl loader_vtbl = +{ + loader_QueryInterface, + loader_AddRef, + loader_Release, + loader_GetObject, + loader_SetObject, + loader_SetSearchDirectory, + loader_ScanDirectory, + loader_CacheObject, + loader_ReleaseObject, + loader_ClearCache, + loader_EnableCache, + loader_EnumObject, + loader_CollectGarbage, + loader_ReleaseObjectByUnknown, + loader_LoadObjectFromFile, }; /* help function for DMUSIC_SetDefaultDLS */ @@ -912,7 +908,7 @@ HRESULT create_dmloader(REFIID lpcGUID, void **ppobj) TRACE("(%s, %p)\n", debugstr_dmguid(lpcGUID), ppobj); *ppobj = NULL; if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; - obj->IDirectMusicLoader8_iface.lpVtbl = &DirectMusicLoader_Loader_Vtbl; + obj->IDirectMusicLoader8_iface.lpVtbl = &loader_vtbl; obj->ref = 0; /* Will be inited with QueryInterface */ list_init(&obj->cache); /* Caching is enabled by default for all classes */ From dd7310dbecfc825461313ca054bcc5e3c205400e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 21 Sep 2023 08:05:59 +0200 Subject: [PATCH 2567/2777] dmloader: Get rid of the IDirectMusicLoaderImpl typedef. (cherry picked from commit 177158210d9d3d654c06121f742a68fb4b8f0b44) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmloader/loader.c | 48 ++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/dlls/dmloader/loader.c b/dlls/dmloader/loader.c index c5801ed32fd..9c3a73e9612 100644 --- a/dlls/dmloader/loader.c +++ b/dlls/dmloader/loader.c @@ -1,6 +1,4 @@ /* - * IDirectMusicLoaderImpl - * * Copyright (C) 2003-2004 Rok Mandeljc * * This program is free software; you can redistribute it and/or @@ -45,18 +43,18 @@ struct cache_entry { BOOL bInvalidDefaultDLS; /* workaround for enabling caching of "faulty" default dls collection */ }; -typedef struct IDirectMusicLoaderImpl { +struct loader +{ IDirectMusicLoader8 IDirectMusicLoader8_iface; LONG ref; WCHAR *search_paths[ARRAY_SIZE(classes)]; unsigned int cache_class; struct list cache; -} IDirectMusicLoaderImpl; - +}; -static inline IDirectMusicLoaderImpl* impl_from_IDirectMusicLoader8(IDirectMusicLoader8 *iface) +static inline struct loader *impl_from_IDirectMusicLoader8(IDirectMusicLoader8 *iface) { - return CONTAINING_RECORD(iface, IDirectMusicLoaderImpl, IDirectMusicLoader8_iface); + return CONTAINING_RECORD(iface, struct loader, IDirectMusicLoader8_iface); } static int index_from_class(REFCLSID class) @@ -70,12 +68,12 @@ static int index_from_class(REFCLSID class) return -1; } -static inline BOOL is_cache_enabled(IDirectMusicLoaderImpl *This, REFCLSID class) +static inline BOOL is_cache_enabled(struct loader *This, REFCLSID class) { return !!(This->cache_class & 1 << index_from_class(class)); } -static void get_search_path(IDirectMusicLoaderImpl *This, REFGUID class, WCHAR *path) +static void get_search_path(struct loader *This, REFGUID class, WCHAR *path) { int index = index_from_class(class); @@ -113,7 +111,7 @@ static HRESULT DMUSIC_CopyDescriptor(DMUS_OBJECTDESC *pDst, DMUS_OBJECTDESC *pSr static HRESULT WINAPI loader_QueryInterface(IDirectMusicLoader8 *iface, REFIID riid, void **ppobj) { - IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); + struct loader *This = impl_from_IDirectMusicLoader8(iface); TRACE("(%p, %s, %p)\n",This, debugstr_dmguid(riid), ppobj); if (IsEqualIID (riid, &IID_IUnknown) || @@ -130,7 +128,7 @@ static HRESULT WINAPI loader_QueryInterface(IDirectMusicLoader8 *iface, REFIID r static ULONG WINAPI loader_AddRef(IDirectMusicLoader8 *iface) { - IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); + struct loader *This = impl_from_IDirectMusicLoader8(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p)->(): new ref = %lu\n", iface, ref); @@ -140,7 +138,7 @@ static ULONG WINAPI loader_AddRef(IDirectMusicLoader8 *iface) static ULONG WINAPI loader_Release(IDirectMusicLoader8 *iface) { - IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); + struct loader *This = impl_from_IDirectMusicLoader8(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p)->(): new ref = %lu\n", iface, ref); @@ -157,7 +155,7 @@ static ULONG WINAPI loader_Release(IDirectMusicLoader8 *iface) return ref; } -static struct cache_entry *find_cache_object(IDirectMusicLoaderImpl *This, DMUS_OBJECTDESC *desc) +static struct cache_entry *find_cache_object(struct loader *This, DMUS_OBJECTDESC *desc) { struct cache_entry *existing; @@ -248,7 +246,7 @@ static struct cache_entry *find_cache_object(IDirectMusicLoaderImpl *This, DMUS_ static HRESULT WINAPI loader_GetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDESC *pDesc, REFIID riid, void **ppv) { - IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); + struct loader *This = impl_from_IDirectMusicLoader8(iface); HRESULT result = S_OK; HRESULT ret = S_OK; /* used at the end of function, to determine whether everything went OK */ struct cache_entry *pExistingEntry, *pObjectEntry = NULL; @@ -448,7 +446,7 @@ static HRESULT WINAPI loader_GetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE static HRESULT WINAPI loader_SetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDESC *pDesc) { - IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); + struct loader *This = impl_from_IDirectMusicLoader8(iface); LPSTREAM pStream; LPDIRECTMUSICOBJECT pObject; DMUS_OBJECTDESC Desc; @@ -573,7 +571,7 @@ static HRESULT WINAPI loader_SetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE static HRESULT WINAPI loader_SetSearchDirectory(IDirectMusicLoader8 *iface, REFGUID class, WCHAR *path, BOOL clear) { - IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); + struct loader *This = impl_from_IDirectMusicLoader8(iface); int index = index_from_class(class); DWORD attr; @@ -607,7 +605,7 @@ static HRESULT WINAPI loader_SetSearchDirectory(IDirectMusicLoader8 *iface, static HRESULT WINAPI loader_ScanDirectory(IDirectMusicLoader8 *iface, REFGUID rguidClass, WCHAR *pwzFileExtension, WCHAR *pwzScanFileName) { - IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); + struct loader *This = impl_from_IDirectMusicLoader8(iface); WIN32_FIND_DATAW FileData; HANDLE hSearch; WCHAR wszSearchString[MAX_PATH]; @@ -667,7 +665,7 @@ static HRESULT WINAPI loader_ScanDirectory(IDirectMusicLoader8 *iface, REFGUID r static HRESULT WINAPI loader_CacheObject(IDirectMusicLoader8 *iface, IDirectMusicObject *object) { - IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); + struct loader *This = impl_from_IDirectMusicLoader8(iface); DMUS_OBJECTDESC desc; struct cache_entry *entry; @@ -697,7 +695,7 @@ static HRESULT WINAPI loader_CacheObject(IDirectMusicLoader8 *iface, static HRESULT WINAPI loader_ReleaseObject(IDirectMusicLoader8 *iface, IDirectMusicObject *object) { - IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); + struct loader *This = impl_from_IDirectMusicLoader8(iface); DMUS_OBJECTDESC desc; struct cache_entry *entry; @@ -727,7 +725,7 @@ static HRESULT WINAPI loader_ReleaseObject(IDirectMusicLoader8 *iface, static HRESULT WINAPI loader_ClearCache(IDirectMusicLoader8 *iface, REFGUID class) { - IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); + struct loader *This = impl_from_IDirectMusicLoader8(iface); struct cache_entry *obj, *obj2; TRACE("(%p, %s)\n", This, debugstr_dmguid(class)); @@ -748,7 +746,7 @@ static HRESULT WINAPI loader_ClearCache(IDirectMusicLoader8 *iface, REFGUID clas static HRESULT WINAPI loader_EnableCache(IDirectMusicLoader8 *iface, REFGUID class, BOOL enable) { - IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); + struct loader *This = impl_from_IDirectMusicLoader8(iface); BOOL current; TRACE("(%p, %s, %d)\n", This, debugstr_dmguid(class), enable); @@ -777,7 +775,7 @@ static HRESULT WINAPI loader_EnableCache(IDirectMusicLoader8 *iface, REFGUID cla static HRESULT WINAPI loader_EnumObject(IDirectMusicLoader8 *iface, REFGUID rguidClass, DWORD dwIndex, DMUS_OBJECTDESC *pDesc) { - IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); + struct loader *This = impl_from_IDirectMusicLoader8(iface); DWORD dwCount = 0; struct cache_entry *pObjectEntry; TRACE("(%p, %s, %ld, %p)\n", This, debugstr_dmguid(rguidClass), dwIndex, pDesc); @@ -810,7 +808,7 @@ static void WINAPI loader_CollectGarbage(IDirectMusicLoader8 *iface) static HRESULT WINAPI loader_ReleaseObjectByUnknown(IDirectMusicLoader8 *iface, IUnknown *pObject) { - IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); + struct loader *This = impl_from_IDirectMusicLoader8(iface); HRESULT result; LPDIRECTMUSICOBJECT pObjectInterface; @@ -832,7 +830,7 @@ static HRESULT WINAPI loader_ReleaseObjectByUnknown(IDirectMusicLoader8 *iface, static HRESULT WINAPI loader_LoadObjectFromFile(IDirectMusicLoader8 *iface, REFGUID rguidClassID, REFIID iidInterfaceID, WCHAR *pwzFilePath, void **ppObject) { - IDirectMusicLoaderImpl *This = impl_from_IDirectMusicLoader8(iface); + struct loader *This = impl_from_IDirectMusicLoader8(iface); DMUS_OBJECTDESC ObjDesc; WCHAR wszLoaderSearchPath[MAX_PATH]; @@ -900,7 +898,7 @@ static HRESULT DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH]) { /* for ClassFactory */ HRESULT create_dmloader(REFIID lpcGUID, void **ppobj) { - IDirectMusicLoaderImpl *obj; + struct loader *obj; DMUS_OBJECTDESC Desc; struct cache_entry *dls; struct list *pEntry; From 590808c9c5585e6130c141cdfeb81baf7171701c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 21 Sep 2023 08:07:56 +0200 Subject: [PATCH 2568/2777] dmloader: Initialize ref to 1, and release after QueryInterface. (cherry picked from commit 7d33a77b567614ed53b4f028b79a0ea5a656e5a3) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmloader/loader.c | 70 ++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/dlls/dmloader/loader.c b/dlls/dmloader/loader.c index 9c3a73e9612..3d51b65c335 100644 --- a/dlls/dmloader/loader.c +++ b/dlls/dmloader/loader.c @@ -898,37 +898,41 @@ static HRESULT DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH]) { /* for ClassFactory */ HRESULT create_dmloader(REFIID lpcGUID, void **ppobj) { - struct loader *obj; - DMUS_OBJECTDESC Desc; - struct cache_entry *dls; - struct list *pEntry; - - TRACE("(%s, %p)\n", debugstr_dmguid(lpcGUID), ppobj); - *ppobj = NULL; - if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; - obj->IDirectMusicLoader8_iface.lpVtbl = &loader_vtbl; - obj->ref = 0; /* Will be inited with QueryInterface */ - list_init(&obj->cache); - /* Caching is enabled by default for all classes */ - obj->cache_class = ~0; - - /* set default DLS collection (via SetObject... so that loading via DMUS_OBJ_OBJECT is possible) */ - DM_STRUCT_INIT(&Desc); - Desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_OBJECT; - Desc.guidClass = CLSID_DirectMusicCollection; - Desc.guidObject = GUID_DefaultGMCollection; - DMUSIC_GetDefaultGMPath (Desc.wszFileName); - IDirectMusicLoader_SetObject(&obj->IDirectMusicLoader8_iface, &Desc); - /* and now the workaroundTM for "invalid" default DLS; basically, - my tests showed that if GUID chunk is present in default DLS - collection, loader treats it as "invalid" and returns - DMUS_E_LOADER_NOFILENAME for all requests for it; basically, we check - if out input guidObject was overwritten */ - pEntry = list_head(&obj->cache); - dls = LIST_ENTRY(pEntry, struct cache_entry, entry); - if (!IsEqualGUID(&Desc.guidObject, &GUID_DefaultGMCollection)) { - dls->bInvalidDefaultDLS = TRUE; - } - - return IDirectMusicLoader_QueryInterface(&obj->IDirectMusicLoader8_iface, lpcGUID, ppobj); + struct loader *obj; + DMUS_OBJECTDESC Desc; + struct cache_entry *dls; + struct list *pEntry; + HRESULT hr; + + TRACE("(%s, %p)\n", debugstr_dmguid(lpcGUID), ppobj); + + *ppobj = NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; + obj->IDirectMusicLoader8_iface.lpVtbl = &loader_vtbl; + obj->ref = 1; + list_init(&obj->cache); + /* Caching is enabled by default for all classes */ + obj->cache_class = ~0; + + /* set default DLS collection (via SetObject... so that loading via DMUS_OBJ_OBJECT is possible) */ + DM_STRUCT_INIT(&Desc); + Desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_OBJECT; + Desc.guidClass = CLSID_DirectMusicCollection; + Desc.guidObject = GUID_DefaultGMCollection; + DMUSIC_GetDefaultGMPath(Desc.wszFileName); + IDirectMusicLoader_SetObject(&obj->IDirectMusicLoader8_iface, &Desc); + + /* and now the workaroundTM for "invalid" default DLS; basically, + my tests showed that if GUID chunk is present in default DLS + collection, loader treats it as "invalid" and returns + DMUS_E_LOADER_NOFILENAME for all requests for it; basically, we check + if out input guidObject was overwritten */ + pEntry = list_head(&obj->cache); + dls = LIST_ENTRY(pEntry, struct cache_entry, entry); + if (!IsEqualGUID(&Desc.guidObject, &GUID_DefaultGMCollection)) + dls->bInvalidDefaultDLS = TRUE; + + hr = IDirectMusicLoader_QueryInterface(&obj->IDirectMusicLoader8_iface, lpcGUID, ppobj); + IDirectMusicLoader_Release(&obj->IDirectMusicLoader8_iface); + return hr; } From 5a6d6d3055512aa9c622a18b04dcf795dce0bebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 20 Sep 2023 11:02:15 +0200 Subject: [PATCH 2569/2777] dmloader: Introduce a new loader_stream_create helper. (cherry picked from commit 975f262986fd41c1c83c8da1c3cd3ca64105f2d3) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmloader/dmloader_private.h | 18 +- dlls/dmloader/loader.c | 51 ++-- dlls/dmloader/loaderstream.c | 383 ++++++++++++++++++++----------- 3 files changed, 289 insertions(+), 163 deletions(-) diff --git a/dlls/dmloader/dmloader_private.h b/dlls/dmloader/dmloader_private.h index 0aea1ba8499..bd5777f54f1 100644 --- a/dlls/dmloader/dmloader_private.h +++ b/dlls/dmloader/dmloader_private.h @@ -69,18 +69,15 @@ extern HRESULT DMUSIC_CreateDirectMusicLoaderGenericStream(void **ppobj); struct IDirectMusicLoaderFileStream { /* VTABLEs */ const IStreamVtbl *StreamVtbl; - const IDirectMusicGetLoaderVtbl *GetLoaderVtbl; /* reference counter */ LONG dwRef; /* file */ WCHAR wzFileName[MAX_PATH]; /* for clone */ HANDLE hFile; - /* loader */ - LPDIRECTMUSICLOADER8 pLoader; }; /* Custom: */ -extern HRESULT WINAPI IDirectMusicLoaderFileStream_Attach (LPSTREAM iface, LPCWSTR wzFile, LPDIRECTMUSICLOADER8 pLoader); +extern HRESULT WINAPI IDirectMusicLoaderFileStream_Attach(LPSTREAM iface, LPCWSTR wzFile); /***************************************************************************** * IDirectMusicLoaderResourceStream implementation structure @@ -88,7 +85,6 @@ extern HRESULT WINAPI IDirectMusicLoaderFileStream_Attach (LPSTREAM iface, LPCWS struct IDirectMusicLoaderResourceStream { /* IUnknown fields */ const IStreamVtbl *StreamVtbl; - const IDirectMusicGetLoaderVtbl *GetLoaderVtbl; /* reference counter */ LONG dwRef; /* data */ @@ -96,12 +92,11 @@ struct IDirectMusicLoaderResourceStream { LONGLONG llMemLength; /* current position */ LONGLONG llPos; - /* loader */ - LPDIRECTMUSICLOADER8 pLoader; }; /* Custom: */ -extern HRESULT WINAPI IDirectMusicLoaderResourceStream_Attach (LPSTREAM iface, LPBYTE pbMemData, LONGLONG llMemLength, LONGLONG llPos, LPDIRECTMUSICLOADER8 pLoader); +extern HRESULT WINAPI IDirectMusicLoaderResourceStream_Attach(LPSTREAM iface, LPBYTE pbMemData, + LONGLONG llMemLength, LONGLONG llPos); /***************************************************************************** * IDirectMusicLoaderGenericStream implementation structure @@ -109,17 +104,16 @@ extern HRESULT WINAPI IDirectMusicLoaderResourceStream_Attach (LPSTREAM iface, L struct IDirectMusicLoaderGenericStream { /* IUnknown fields */ const IStreamVtbl *StreamVtbl; - const IDirectMusicGetLoaderVtbl *GetLoaderVtbl; /* reference counter */ LONG dwRef; /* stream */ LPSTREAM pStream; - /* loader */ - LPDIRECTMUSICLOADER8 pLoader; }; /* Custom: */ -extern HRESULT WINAPI IDirectMusicLoaderGenericStream_Attach (LPSTREAM iface, LPSTREAM pStream, LPDIRECTMUSICLOADER8 pLoader); +extern HRESULT WINAPI IDirectMusicLoaderGenericStream_Attach(LPSTREAM iface, LPSTREAM pStream); + +extern HRESULT loader_stream_create(IDirectMusicLoader *loader, IStream *stream, IStream **ret_iface); #include "debug.h" diff --git a/dlls/dmloader/loader.c b/dlls/dmloader/loader.c index 3d51b65c335..a0683307f8f 100644 --- a/dlls/dmloader/loader.c +++ b/dlls/dmloader/loader.c @@ -256,8 +256,10 @@ static HRESULT WINAPI loader_GetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE LPDIRECTMUSICOBJECT pObject; DMUS_OBJECTDESC GotDesc; BOOL bCache; + IStream *loader_stream; + HRESULT hr; - TRACE("(%p)->(%p, %s, %p)\n", This, pDesc, debugstr_dmguid(riid), ppv); + TRACE("(%p)->(%p, %s, %p)\n", This, pDesc, debugstr_dmguid(riid), ppv); if (TRACE_ON(dmloader)) dump_DMUS_OBJECTDESC(pDesc); @@ -329,8 +331,9 @@ static HRESULT WINAPI loader_GetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE ERR(": could not create file stream\n"); return result; } - result = IDirectMusicLoaderFileStream_Attach (pStream, wszFileName, iface); - if (FAILED(result)) { + result = IDirectMusicLoaderFileStream_Attach(pStream, wszFileName); + if (FAILED(result)) + { ERR(": could not attach stream to file\n"); IStream_Release (pStream); return result; @@ -345,8 +348,9 @@ static HRESULT WINAPI loader_GetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE ERR(": could not create resource stream\n"); return result; } - result = IDirectMusicLoaderResourceStream_Attach (pStream, pDesc->pbMemData, pDesc->llMemLength, 0, iface); - if (FAILED(result)) { + result = IDirectMusicLoaderResourceStream_Attach(pStream, pDesc->pbMemData, pDesc->llMemLength, 0); + if (FAILED(result)) + { ERR(": could not attach stream to resource\n"); IStream_Release (pStream); return result; @@ -361,8 +365,9 @@ static HRESULT WINAPI loader_GetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE ERR(": could not create generic stream\n"); return result; } - result = IDirectMusicLoaderGenericStream_Attach (pStream, pDesc->pStream, iface); - if (FAILED(result)) { + result = IDirectMusicLoaderGenericStream_Attach(pStream, pDesc->pStream); + if (FAILED(result)) + { ERR(": failed to attach stream\n"); IStream_Release (pStream); return result; @@ -373,7 +378,12 @@ static HRESULT WINAPI loader_GetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE return DMUS_E_LOADER_NOFILENAME; /* test shows this is returned */ } - /* create object */ + if (FAILED(hr = loader_stream_create((IDirectMusicLoader *)iface, pStream, &loader_stream))) + return hr; + IStream_Release(pStream); + pStream = loader_stream; + + /* create object */ result = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject); if (FAILED(result)) { IStream_Release(pStream); @@ -451,7 +461,8 @@ static HRESULT WINAPI loader_SetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE LPDIRECTMUSICOBJECT pObject; DMUS_OBJECTDESC Desc; struct cache_entry *pObjectEntry, *pNewEntry; - HRESULT hr; + IStream *loader_stream; + HRESULT hr; TRACE("(%p)->(%p)\n", This, pDesc); @@ -480,8 +491,9 @@ static HRESULT WINAPI loader_SetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE return DMUS_E_LOADER_FAILEDOPEN; } /* attach stream */ - hr = IDirectMusicLoaderFileStream_Attach (pStream, wszFileName, iface); - if (FAILED(hr)) { + hr = IDirectMusicLoaderFileStream_Attach(pStream, wszFileName); + if (FAILED(hr)) + { ERR(": could not attach stream to file %s, make sure it exists\n", debugstr_w(wszFileName)); IStream_Release (pStream); return DMUS_E_LOADER_FAILEDOPEN; @@ -495,8 +507,9 @@ static HRESULT WINAPI loader_SetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE return DMUS_E_LOADER_FAILEDOPEN; } /* attach stream */ - hr = IDirectMusicLoaderGenericStream_Attach (pStream, pDesc->pStream, iface); - if (FAILED(hr)) { + hr = IDirectMusicLoaderGenericStream_Attach(pStream, pDesc->pStream); + if (FAILED(hr)) + { ERR(": could not attach stream\n"); IStream_Release (pStream); return DMUS_E_LOADER_FAILEDOPEN; @@ -510,8 +523,9 @@ static HRESULT WINAPI loader_SetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE return DMUS_E_LOADER_FAILEDOPEN; } /* attach stream */ - hr = IDirectMusicLoaderResourceStream_Attach (pStream, pDesc->pbMemData, pDesc->llMemLength, 0, iface); - if (FAILED(hr)) { + hr = IDirectMusicLoaderResourceStream_Attach(pStream, pDesc->pbMemData, pDesc->llMemLength, 0); + if (FAILED(hr)) + { ERR(": could not attach stream to resource\n"); IStream_Release (pStream); return DMUS_E_LOADER_FAILEDOPEN; @@ -522,7 +536,12 @@ static HRESULT WINAPI loader_SetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE return DMUS_E_LOADER_FAILEDOPEN; } - /* create object */ + if (FAILED(hr = loader_stream_create((IDirectMusicLoader *)iface, pStream, &loader_stream))) + return hr; + IStream_Release(pStream); + pStream = loader_stream; + + /* create object */ hr = CoCreateInstance (&pDesc->guidClass, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicObject, (LPVOID*)&pObject); if (FAILED(hr)) { IStream_Release(pStream); diff --git a/dlls/dmloader/loaderstream.c b/dlls/dmloader/loaderstream.c index 5d6c5ad3e25..3e01d423483 100644 --- a/dlls/dmloader/loaderstream.c +++ b/dlls/dmloader/loaderstream.c @@ -49,12 +49,244 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmloader); WINE_DECLARE_DEBUG_CHANNEL(dmfileraw); +struct loader_stream +{ + IStream IStream_iface; + IDirectMusicGetLoader IDirectMusicGetLoader_iface; + LONG ref; + + IStream *stream; + IDirectMusicLoader *loader; +}; + +static struct loader_stream *impl_from_IStream(IStream *iface) +{ + return CONTAINING_RECORD(iface, struct loader_stream, IStream_iface); +} + +static HRESULT WINAPI loader_stream_QueryInterface(IStream *iface, REFIID riid, void **ret_iface) +{ + struct loader_stream *This = impl_from_IStream(iface); + + TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface); + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IStream)) + { + IStream_AddRef(&This->IStream_iface); + *ret_iface = &This->IStream_iface; + return S_OK; + } + + if (IsEqualGUID(riid, &IID_IDirectMusicGetLoader)) + { + IDirectMusicGetLoader_AddRef(&This->IDirectMusicGetLoader_iface); + *ret_iface = &This->IDirectMusicGetLoader_iface; + return S_OK; + } + + WARN("(%p, %s, %p): not found\n", iface, debugstr_dmguid(riid), ret_iface); + *ret_iface = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI loader_stream_AddRef(IStream *iface) +{ + struct loader_stream *This = impl_from_IStream(iface); + ULONG ref = InterlockedIncrement(&This->ref); + TRACE("(%p): new ref = %lu\n", This, ref); + return ref; +} + +static ULONG WINAPI loader_stream_Release(IStream *iface) +{ + struct loader_stream *This = impl_from_IStream(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p): new ref = %lu\n", This, ref); + + if (!ref) + { + IDirectMusicLoader_Release(This->loader); + IStream_Release(This->stream); + free(This); + } + + return ref; +} + +static HRESULT WINAPI loader_stream_Read(IStream *iface, void *data, ULONG size, ULONG *ret_size) +{ + struct loader_stream *This = impl_from_IStream(iface); + TRACE("(%p, %p, %#lx, %p)\n", This, data, size, ret_size); + return IStream_Read(This->stream, data, size, ret_size); +} + +static HRESULT WINAPI loader_stream_Write(IStream *iface, const void *data, ULONG size, ULONG *ret_size) +{ + struct loader_stream *This = impl_from_IStream(iface); + FIXME("(%p): stub\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI loader_stream_Seek(IStream *iface, LARGE_INTEGER offset, DWORD method, ULARGE_INTEGER *ret_offset) +{ + struct loader_stream *This = impl_from_IStream(iface); + TRACE("(%p, %I64d, %#lx, %p)\n", This, offset.QuadPart, method, ret_offset); + return IStream_Seek(This->stream, offset, method, ret_offset); +} + +static HRESULT WINAPI loader_stream_SetSize(IStream *iface, ULARGE_INTEGER size) +{ + struct loader_stream *This = impl_from_IStream(iface); + FIXME("(%p): stub\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI loader_stream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size, + ULARGE_INTEGER *read_size, ULARGE_INTEGER *write_size) +{ + struct loader_stream *This = impl_from_IStream(iface); + FIXME("(%p): stub\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI loader_stream_Commit(IStream *iface, DWORD flags) +{ + struct loader_stream *This = impl_from_IStream(iface); + FIXME("(%p): stub\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI loader_stream_Revert(IStream *iface) +{ + struct loader_stream *This = impl_from_IStream(iface); + FIXME("(%p): stub\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI loader_stream_LockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD type) +{ + struct loader_stream *This = impl_from_IStream(iface); + FIXME("(%p): stub\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI loader_stream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, + ULARGE_INTEGER size, DWORD type) +{ + struct loader_stream *This = impl_from_IStream(iface); + FIXME("(%p): stub\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI loader_stream_Stat(IStream *iface, STATSTG *stat, DWORD flags) +{ + struct loader_stream *This = impl_from_IStream(iface); + FIXME("(%p): stub\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI loader_stream_Clone(IStream *iface, IStream **ret_iface) +{ + struct loader_stream *This = impl_from_IStream(iface); + IStream *stream; + HRESULT hr; + + TRACE("(%p, %p)\n", This, ret_iface); + + if (SUCCEEDED(hr = IStream_Clone(This->stream, &stream))) + { + hr = loader_stream_create(This->loader, stream, ret_iface); + IStream_Release(stream); + } + + return hr; +} + +static const IStreamVtbl loader_stream_vtbl = +{ + loader_stream_QueryInterface, + loader_stream_AddRef, + loader_stream_Release, + loader_stream_Read, + loader_stream_Write, + loader_stream_Seek, + loader_stream_SetSize, + loader_stream_CopyTo, + loader_stream_Commit, + loader_stream_Revert, + loader_stream_LockRegion, + loader_stream_UnlockRegion, + loader_stream_Stat, + loader_stream_Clone, +}; + +static struct loader_stream *impl_from_IDirectMusicGetLoader(IDirectMusicGetLoader *iface) +{ + return CONTAINING_RECORD(iface, struct loader_stream, IDirectMusicGetLoader_iface); +} + +static HRESULT WINAPI loader_stream_getter_QueryInterface(IDirectMusicGetLoader *iface, REFIID iid, void **out) +{ + struct loader_stream *This = impl_from_IDirectMusicGetLoader(iface); + return IStream_QueryInterface(&This->IStream_iface, iid, out); +} + +static ULONG WINAPI loader_stream_getter_AddRef(IDirectMusicGetLoader *iface) +{ + struct loader_stream *This = impl_from_IDirectMusicGetLoader(iface); + return IStream_AddRef(&This->IStream_iface); +} + +static ULONG WINAPI loader_stream_getter_Release(IDirectMusicGetLoader *iface) +{ + struct loader_stream *This = impl_from_IDirectMusicGetLoader(iface); + return IStream_Release(&This->IStream_iface); +} + +static HRESULT WINAPI loader_stream_getter_GetLoader(IDirectMusicGetLoader *iface, IDirectMusicLoader **ret_loader) +{ + struct loader_stream *This = impl_from_IDirectMusicGetLoader(iface); + + TRACE("(%p, %p)\n", This, ret_loader); + + *ret_loader = This->loader; + IDirectMusicLoader_AddRef(This->loader); + return S_OK; +} + +static const IDirectMusicGetLoaderVtbl loader_stream_getter_vtbl = +{ + loader_stream_getter_QueryInterface, + loader_stream_getter_AddRef, + loader_stream_getter_Release, + loader_stream_getter_GetLoader, +}; + +HRESULT loader_stream_create(IDirectMusicLoader *loader, IStream *stream, + IStream **ret_iface) +{ + struct loader_stream *obj; + + *ret_iface = NULL; + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; + obj->IStream_iface.lpVtbl = &loader_stream_vtbl; + obj->IDirectMusicGetLoader_iface.lpVtbl = &loader_stream_getter_vtbl; + obj->ref = 1; + + obj->stream = stream; + IStream_AddRef(stream); + obj->loader = loader; + IDirectMusicLoader_AddRef(loader); + + *ret_iface = &obj->IStream_iface; + return S_OK; +} + static ULONG WINAPI IDirectMusicLoaderFileStream_IStream_AddRef (LPSTREAM iface); -static ULONG WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface); -static ULONG WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface); static ULONG WINAPI IDirectMusicLoaderResourceStream_IStream_AddRef (LPSTREAM iface); static ULONG WINAPI IDirectMusicLoaderGenericStream_IStream_AddRef (LPSTREAM iface); -static ULONG WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface); /***************************************************************************** @@ -69,9 +301,10 @@ static void IDirectMusicLoaderFileStream_Detach (LPSTREAM iface) { This->wzFileName[0] = '\0'; } -HRESULT WINAPI IDirectMusicLoaderFileStream_Attach (LPSTREAM iface, LPCWSTR wzFile, LPDIRECTMUSICLOADER8 pLoader) { - ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); - TRACE("(%p, %s, %p)\n", This, debugstr_w(wzFile), pLoader); +HRESULT WINAPI IDirectMusicLoaderFileStream_Attach(LPSTREAM iface, LPCWSTR wzFile) +{ + ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); + TRACE("(%p, %s)\n", This, debugstr_w(wzFile)); IDirectMusicLoaderFileStream_Detach (iface); This->hFile = CreateFileW (wzFile, (GENERIC_READ | GENERIC_WRITE), (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (This->hFile == INVALID_HANDLE_VALUE) { @@ -79,7 +312,6 @@ HRESULT WINAPI IDirectMusicLoaderFileStream_Attach (LPSTREAM iface, LPCWSTR wzFi return DMUS_E_LOADER_FAILEDOPEN; } /* create IDirectMusicGetLoader */ - This->pLoader = pLoader; lstrcpynW (This->wzFileName, wzFile, MAX_PATH); TRACE(": succeeded\n"); return S_OK; @@ -96,10 +328,6 @@ static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_QueryInterface (LPSTR *ppobj = &This->StreamVtbl; IDirectMusicLoaderFileStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl); return S_OK; - } else if (IsEqualIID (riid, &IID_IDirectMusicGetLoader)) { - *ppobj = &This->GetLoaderVtbl; - IDirectMusicLoaderFileStream_IDirectMusicGetLoader_AddRef ((LPDIRECTMUSICGETLOADER)&This->GetLoaderVtbl); - return S_OK; } WARN(": not found\n"); @@ -166,8 +394,9 @@ static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Clone (LPSTREAM iface if (FAILED(result)) return result; if (This->hFile != INVALID_HANDLE_VALUE) { ULARGE_INTEGER ullCurrentPosition; - result = IDirectMusicLoaderFileStream_Attach (pOther, This->wzFileName, This->pLoader); - if (SUCCEEDED(result)) { + result = IDirectMusicLoaderFileStream_Attach(pOther, This->wzFileName); + if (SUCCEEDED(result)) + { LARGE_INTEGER liZero; liZero.QuadPart = 0; result = IDirectMusicLoaderFileStream_IStream_Seek (iface, liZero, STREAM_SEEK_CUR, &ullCurrentPosition); /* get current position in current stream */ @@ -253,39 +482,6 @@ static const IStreamVtbl DirectMusicLoaderFileStream_Stream_Vtbl = { IDirectMusicLoaderFileStream_IStream_Clone }; -/* IDirectMusicGetLoader part: */ -static HRESULT WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj) { - ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface); - return IDirectMusicLoaderFileStream_IStream_QueryInterface ((LPSTREAM)&This->StreamVtbl, riid, ppobj); -} - -static ULONG WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface) { - ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface); - return IDirectMusicLoaderFileStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl); -} - -static ULONG WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface) { - ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface); - return IDirectMusicLoaderFileStream_IStream_Release ((LPSTREAM)&This->StreamVtbl); -} - -static HRESULT WINAPI IDirectMusicLoaderFileStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader) { - ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, GetLoaderVtbl, iface); - - TRACE("(%p, %p)\n", This, ppLoader); - *ppLoader = (LPDIRECTMUSICLOADER)This->pLoader; - IDirectMusicLoader8_AddRef ((LPDIRECTMUSICLOADER8)*ppLoader); - - return S_OK; -} - -static const IDirectMusicGetLoaderVtbl DirectMusicLoaderFileStream_GetLoader_Vtbl = { - IDirectMusicLoaderFileStream_IDirectMusicGetLoader_QueryInterface, - IDirectMusicLoaderFileStream_IDirectMusicGetLoader_AddRef, - IDirectMusicLoaderFileStream_IDirectMusicGetLoader_Release, - IDirectMusicLoaderFileStream_IDirectMusicGetLoader_GetLoader -}; - HRESULT DMUSIC_CreateDirectMusicLoaderFileStream (void** ppobj) { IDirectMusicLoaderFileStream *obj; @@ -294,7 +490,6 @@ HRESULT DMUSIC_CreateDirectMusicLoaderFileStream (void** ppobj) { *ppobj = NULL; if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->StreamVtbl = &DirectMusicLoaderFileStream_Stream_Vtbl; - obj->GetLoaderVtbl = &DirectMusicLoaderFileStream_GetLoader_Vtbl; obj->dwRef = 0; /* will be inited with QueryInterface */ return IDirectMusicLoaderFileStream_IStream_QueryInterface ((LPSTREAM)&obj->StreamVtbl, &IID_IStream, ppobj); @@ -314,10 +509,10 @@ static void IDirectMusicLoaderResourceStream_Detach (LPSTREAM iface) { This->llMemLength = 0; } -HRESULT WINAPI IDirectMusicLoaderResourceStream_Attach (LPSTREAM iface, LPBYTE pbMemData, LONGLONG llMemLength, LONGLONG llPos, LPDIRECTMUSICLOADER8 pLoader) { +HRESULT WINAPI IDirectMusicLoaderResourceStream_Attach (LPSTREAM iface, LPBYTE pbMemData, LONGLONG llMemLength, LONGLONG llPos) { ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, StreamVtbl, iface); - TRACE("(%p, %p, %s, %s, %p)\n", This, pbMemData, wine_dbgstr_longlong(llMemLength), wine_dbgstr_longlong(llPos), pLoader); + TRACE("(%p, %p, %s, %s)\n", This, pbMemData, wine_dbgstr_longlong(llMemLength), wine_dbgstr_longlong(llPos)); if (!pbMemData || !llMemLength) { WARN(": invalid pbMemData or llMemLength\n"); return E_FAIL; @@ -326,7 +521,6 @@ HRESULT WINAPI IDirectMusicLoaderResourceStream_Attach (LPSTREAM iface, LPBYTE p This->pbMemData = pbMemData; This->llMemLength = llMemLength; This->llPos = llPos; - This->pLoader = pLoader; return S_OK; } @@ -342,10 +536,6 @@ static HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_QueryInterface (L *ppobj = &This->StreamVtbl; IDirectMusicLoaderResourceStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl); return S_OK; - } else if (IsEqualIID (riid, &IID_IDirectMusicGetLoader)) { - *ppobj = &This->GetLoaderVtbl; - IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_AddRef ((LPDIRECTMUSICGETLOADER)&This->GetLoaderVtbl); - return S_OK; } WARN(": not found\n"); @@ -444,7 +634,7 @@ static HRESULT WINAPI IDirectMusicLoaderResourceStream_IStream_Clone (LPSTREAM i result = DMUSIC_CreateDirectMusicLoaderResourceStream ((LPVOID*)&pOther); if (FAILED(result)) return result; - IDirectMusicLoaderResourceStream_Attach (pOther, This->pbMemData, This->llMemLength, This->llPos, This->pLoader); + IDirectMusicLoaderResourceStream_Attach (pOther, This->pbMemData, This->llMemLength, This->llPos); TRACE(": succeeded\n"); *ppstm = pOther; @@ -508,39 +698,6 @@ static const IStreamVtbl DirectMusicLoaderResourceStream_Stream_Vtbl = { IDirectMusicLoaderResourceStream_IStream_Clone }; -/* IDirectMusicGetLoader part: */ -static HRESULT WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj) { - ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, GetLoaderVtbl, iface); - return IDirectMusicLoaderResourceStream_IStream_QueryInterface ((LPSTREAM)&This->StreamVtbl, riid, ppobj); -} - -static ULONG WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface) { - ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, GetLoaderVtbl, iface); - return IDirectMusicLoaderResourceStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl); -} - -static ULONG WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface) { - ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, GetLoaderVtbl, iface); - return IDirectMusicLoaderResourceStream_IStream_Release ((LPSTREAM)&This->StreamVtbl); -} - -static HRESULT WINAPI IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader) { - ICOM_THIS_MULTI(IDirectMusicLoaderResourceStream, GetLoaderVtbl, iface); - - TRACE("(%p, %p)\n", This, ppLoader); - *ppLoader = (LPDIRECTMUSICLOADER)This->pLoader; - IDirectMusicLoader8_AddRef ((LPDIRECTMUSICLOADER8)*ppLoader); - - return S_OK; -} - -static const IDirectMusicGetLoaderVtbl DirectMusicLoaderResourceStream_GetLoader_Vtbl = { - IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_QueryInterface, - IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_AddRef, - IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_Release, - IDirectMusicLoaderResourceStream_IDirectMusicGetLoader_GetLoader -}; - HRESULT DMUSIC_CreateDirectMusicLoaderResourceStream (void** ppobj) { IDirectMusicLoaderResourceStream *obj; @@ -549,7 +706,6 @@ HRESULT DMUSIC_CreateDirectMusicLoaderResourceStream (void** ppobj) { *ppobj = NULL; if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->StreamVtbl = &DirectMusicLoaderResourceStream_Stream_Vtbl; - obj->GetLoaderVtbl = &DirectMusicLoaderResourceStream_GetLoader_Vtbl; obj->dwRef = 0; /* will be inited with QueryInterface */ return IDirectMusicLoaderResourceStream_IStream_QueryInterface ((LPSTREAM)&obj->StreamVtbl, &IID_IStream, ppobj); @@ -569,22 +725,17 @@ static void IDirectMusicLoaderGenericStream_Detach (LPSTREAM iface) { This->pStream = NULL; } -HRESULT WINAPI IDirectMusicLoaderGenericStream_Attach (LPSTREAM iface, LPSTREAM pStream, LPDIRECTMUSICLOADER8 pLoader) { +HRESULT WINAPI IDirectMusicLoaderGenericStream_Attach (LPSTREAM iface, LPSTREAM pStream) { ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); - TRACE("(%p, %p, %p)\n", This, pStream, pLoader); + TRACE("(%p, %p)\n", This, pStream); if (!pStream) { WARN(": invalid pStream\n"); return E_FAIL; } - if (!pLoader) { - WARN(": invalid pLoader\n"); - return E_FAIL; - } IDirectMusicLoaderGenericStream_Detach (iface); IStream_Clone (pStream, &This->pStream); - This->pLoader = pLoader; return S_OK; } @@ -600,10 +751,6 @@ static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_QueryInterface (LP *ppobj = &This->StreamVtbl; IDirectMusicLoaderGenericStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl); return S_OK; - } else if (IsEqualIID (riid, &IID_IDirectMusicGetLoader)) { - *ppobj = &This->GetLoaderVtbl; - IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef ((LPDIRECTMUSICGETLOADER)&This->GetLoaderVtbl); - return S_OK; } WARN(": not found\n"); @@ -662,7 +809,7 @@ static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Clone (LPSTREAM if IStream_Release(pOther); return E_FAIL; } - IDirectMusicLoaderGenericStream_Attach (pOther, pLowLevel, This->pLoader); + IDirectMusicLoaderGenericStream_Attach (pOther, pLowLevel); TRACE(": succeeded\n"); *ppstm = pOther; @@ -758,39 +905,6 @@ static const IStreamVtbl DirectMusicLoaderGenericStream_Stream_Vtbl = { IDirectMusicLoaderGenericStream_IStream_Clone }; -/* IDirectMusicGetLoader part: */ -static HRESULT WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_QueryInterface (LPDIRECTMUSICGETLOADER iface, REFIID riid, void** ppobj) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface); - return IDirectMusicLoaderGenericStream_IStream_QueryInterface ((LPSTREAM)&This->StreamVtbl, riid, ppobj); -} - -static ULONG WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef (LPDIRECTMUSICGETLOADER iface) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface); - return IDirectMusicLoaderGenericStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl); -} - -static ULONG WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_Release (LPDIRECTMUSICGETLOADER iface) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface); - return IDirectMusicLoaderGenericStream_IStream_Release ((LPSTREAM)&This->StreamVtbl); -} - -static HRESULT WINAPI IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_GetLoader (LPDIRECTMUSICGETLOADER iface, IDirectMusicLoader **ppLoader) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, GetLoaderVtbl, iface); - - TRACE("(%p, %p)\n", This, ppLoader); - *ppLoader = (LPDIRECTMUSICLOADER)This->pLoader; - IDirectMusicLoader8_AddRef ((LPDIRECTMUSICLOADER8)*ppLoader); - - return S_OK; -} - -static const IDirectMusicGetLoaderVtbl DirectMusicLoaderGenericStream_GetLoader_Vtbl = { - IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_QueryInterface, - IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_AddRef, - IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_Release, - IDirectMusicLoaderGenericStream_IDirectMusicGetLoader_GetLoader -}; - HRESULT DMUSIC_CreateDirectMusicLoaderGenericStream (void** ppobj) { IDirectMusicLoaderGenericStream *obj; @@ -799,7 +913,6 @@ HRESULT DMUSIC_CreateDirectMusicLoaderGenericStream (void** ppobj) { *ppobj = NULL; if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->StreamVtbl = &DirectMusicLoaderGenericStream_Stream_Vtbl; - obj->GetLoaderVtbl = &DirectMusicLoaderGenericStream_GetLoader_Vtbl; obj->dwRef = 0; /* will be inited with QueryInterface */ return IDirectMusicLoaderGenericStream_IStream_QueryInterface ((LPSTREAM)&obj->StreamVtbl, &IID_IStream, ppobj); From d9af43cae42a44c704ed59a71e16fd741f98a758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 20 Sep 2023 11:22:14 +0200 Subject: [PATCH 2570/2777] dmloader: Get rid of the custom generic stream wrapper. (cherry picked from commit 196aa81738b0cde2b06f2c3f474c9a940fe98f6c) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmloader/dmloader_private.h | 16 --- dlls/dmloader/loader.c | 53 +++----- dlls/dmloader/loaderstream.c | 208 ------------------------------- 3 files changed, 16 insertions(+), 261 deletions(-) diff --git a/dlls/dmloader/dmloader_private.h b/dlls/dmloader/dmloader_private.h index bd5777f54f1..87fcf087bc0 100644 --- a/dlls/dmloader/dmloader_private.h +++ b/dlls/dmloader/dmloader_private.h @@ -61,7 +61,6 @@ extern HRESULT create_dmloader(REFIID riid, void **ret_iface); extern HRESULT create_dmcontainer(REFIID riid, void **ret_iface); extern HRESULT DMUSIC_CreateDirectMusicLoaderFileStream(void **ppobj); extern HRESULT DMUSIC_CreateDirectMusicLoaderResourceStream(void **ppobj); -extern HRESULT DMUSIC_CreateDirectMusicLoaderGenericStream(void **ppobj); /***************************************************************************** * IDirectMusicLoaderFileStream implementation structure @@ -98,21 +97,6 @@ struct IDirectMusicLoaderResourceStream { extern HRESULT WINAPI IDirectMusicLoaderResourceStream_Attach(LPSTREAM iface, LPBYTE pbMemData, LONGLONG llMemLength, LONGLONG llPos); -/***************************************************************************** - * IDirectMusicLoaderGenericStream implementation structure - */ -struct IDirectMusicLoaderGenericStream { - /* IUnknown fields */ - const IStreamVtbl *StreamVtbl; - /* reference counter */ - LONG dwRef; - /* stream */ - LPSTREAM pStream; -}; - -/* Custom: */ -extern HRESULT WINAPI IDirectMusicLoaderGenericStream_Attach(LPSTREAM iface, LPSTREAM pStream); - extern HRESULT loader_stream_create(IDirectMusicLoader *loader, IStream *stream, IStream **ret_iface); #include "debug.h" diff --git a/dlls/dmloader/loader.c b/dlls/dmloader/loader.c index a0683307f8f..ef1a8c3dfe0 100644 --- a/dlls/dmloader/loader.c +++ b/dlls/dmloader/loader.c @@ -356,27 +356,17 @@ static HRESULT WINAPI loader_GetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE return result; } } - else if (pDesc->dwValidData & DMUS_OBJ_STREAM) { - /* load object from stream */ - TRACE(": loading from stream\n"); - /* create universal stream and associate it with given one */ - result = DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pStream); - if (FAILED(result)) { - ERR(": could not create generic stream\n"); - return result; - } - result = IDirectMusicLoaderGenericStream_Attach(pStream, pDesc->pStream); - if (FAILED(result)) - { - ERR(": failed to attach stream\n"); - IStream_Release (pStream); - return result; - } - } else { - /* nowhere to load from */ - FIXME(": unknown/unsupported way of loading\n"); - return DMUS_E_LOADER_NOFILENAME; /* test shows this is returned */ - } + else if (pDesc->dwValidData & DMUS_OBJ_STREAM) + { + pStream = pDesc->pStream; + IStream_AddRef(pStream); + } + else + { + /* nowhere to load from */ + FIXME(": unknown/unsupported way of loading\n"); + return DMUS_E_LOADER_NOFILENAME; /* test shows this is returned */ + } if (FAILED(hr = loader_stream_create((IDirectMusicLoader *)iface, pStream, &loader_stream))) return hr; @@ -499,22 +489,11 @@ static HRESULT WINAPI loader_SetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE return DMUS_E_LOADER_FAILEDOPEN; } } - else if (pDesc->dwValidData & DMUS_OBJ_STREAM) { - /* create stream */ - hr = DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pStream); - if (FAILED(hr)) { - ERR(": could not create generic stream\n"); - return DMUS_E_LOADER_FAILEDOPEN; - } - /* attach stream */ - hr = IDirectMusicLoaderGenericStream_Attach(pStream, pDesc->pStream); - if (FAILED(hr)) - { - ERR(": could not attach stream\n"); - IStream_Release (pStream); - return DMUS_E_LOADER_FAILEDOPEN; - } - } + else if (pDesc->dwValidData & DMUS_OBJ_STREAM) + { + pStream = pDesc->pStream; + IStream_AddRef(pStream); + } else if (pDesc->dwValidData & DMUS_OBJ_MEMORY) { /* create stream */ hr = DMUSIC_CreateDirectMusicLoaderResourceStream ((LPVOID*)&pStream); diff --git a/dlls/dmloader/loaderstream.c b/dlls/dmloader/loaderstream.c index 3e01d423483..5b7862c16f8 100644 --- a/dlls/dmloader/loaderstream.c +++ b/dlls/dmloader/loaderstream.c @@ -286,7 +286,6 @@ HRESULT loader_stream_create(IDirectMusicLoader *loader, IStream *stream, static ULONG WINAPI IDirectMusicLoaderFileStream_IStream_AddRef (LPSTREAM iface); static ULONG WINAPI IDirectMusicLoaderResourceStream_IStream_AddRef (LPSTREAM iface); -static ULONG WINAPI IDirectMusicLoaderGenericStream_IStream_AddRef (LPSTREAM iface); /***************************************************************************** @@ -710,210 +709,3 @@ HRESULT DMUSIC_CreateDirectMusicLoaderResourceStream (void** ppobj) { return IDirectMusicLoaderResourceStream_IStream_QueryInterface ((LPSTREAM)&obj->StreamVtbl, &IID_IStream, ppobj); } - - -/***************************************************************************** - * IDirectMusicLoaderGenericStream implementation - */ -/* Custom : */ - -static void IDirectMusicLoaderGenericStream_Detach (LPSTREAM iface) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); - - if (This->pStream) - IStream_Release (This->pStream); - This->pStream = NULL; -} - -HRESULT WINAPI IDirectMusicLoaderGenericStream_Attach (LPSTREAM iface, LPSTREAM pStream) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); - - TRACE("(%p, %p)\n", This, pStream); - if (!pStream) { - WARN(": invalid pStream\n"); - return E_FAIL; - } - - IDirectMusicLoaderGenericStream_Detach (iface); - IStream_Clone (pStream, &This->pStream); - - return S_OK; -} - - -/* IUnknown/IStream part: */ -static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); - - TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj); - if (IsEqualIID (riid, &IID_IUnknown) || - IsEqualIID (riid, &IID_IStream)) { - *ppobj = &This->StreamVtbl; - IDirectMusicLoaderGenericStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl); - return S_OK; - } - - WARN(": not found\n"); - return E_NOINTERFACE; -} - -static ULONG WINAPI IDirectMusicLoaderGenericStream_IStream_AddRef (LPSTREAM iface) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); - TRACE("(%p): AddRef from %ld\n", This, This->dwRef); - return InterlockedIncrement (&This->dwRef); -} - -static ULONG WINAPI IDirectMusicLoaderGenericStream_IStream_Release (LPSTREAM iface) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); - - DWORD dwRef = InterlockedDecrement (&This->dwRef); - TRACE("(%p): ReleaseRef to %ld\n", This, dwRef); - if (dwRef == 0) { - IDirectMusicLoaderGenericStream_Detach (iface); - HeapFree (GetProcessHeap(), 0, This); - } - - return dwRef; -} - -static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Read (LPSTREAM iface, void* pv, ULONG cb, ULONG* pcbRead) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); - - TRACE_(dmfileraw)("(%p, %p, %#lx, %p): redirecting to low-level stream\n", This, pv, cb, pcbRead); - if (!This->pStream) - return E_FAIL; - - return IStream_Read (This->pStream, pv, cb, pcbRead); -} - -static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); - TRACE_(dmfileraw)("(%p, %s, %s, %p): redirecting to low-level stream\n", This, wine_dbgstr_longlong(dlibMove.QuadPart), resolve_STREAM_SEEK(dwOrigin), plibNewPosition); - if (!This->pStream) - return E_FAIL; - - return IStream_Seek (This->pStream, dlibMove, dwOrigin, plibNewPosition); -} - -static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Clone (LPSTREAM iface, IStream** ppstm) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); - LPSTREAM pOther = NULL; - LPSTREAM pLowLevel = NULL; - HRESULT result; - - TRACE("(%p, %p)\n", iface, ppstm); - result = DMUSIC_CreateDirectMusicLoaderGenericStream ((LPVOID*)&pOther); - if (FAILED(result)) return result; - - if (FAILED(IStream_Clone (This->pStream, &pLowLevel))) { - IStream_Release(pOther); - return E_FAIL; - } - IDirectMusicLoaderGenericStream_Attach (pOther, pLowLevel); - - TRACE(": succeeded\n"); - *ppstm = pOther; - return S_OK; -} - -static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); - TRACE_(dmfileraw)("(%p, %p, %#lx, %p): redirecting to low-level stream\n", This, pv, cb, pcbWritten); - if (!This->pStream) - return E_FAIL; - - return IStream_Write (This->pStream, pv, cb, pcbWritten); -} - -static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); - TRACE("(%p, %s): redirecting to low-level stream\n", This, wine_dbgstr_longlong(libNewSize.QuadPart)); - if (!This->pStream) - return E_FAIL; - - return IStream_SetSize (This->pStream, libNewSize); -} - -static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); - TRACE("(%p, %p, %s, %p, %p): redirecting to low-level stream\n", This, pstm, wine_dbgstr_longlong(cb.QuadPart), pcbRead, pcbWritten); - if (!This->pStream) - return E_FAIL; - - return IStream_CopyTo (This->pStream, pstm, cb, pcbRead, pcbWritten); -} - -static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); - TRACE("(%p, %#lx): redirecting to low-level stream\n", This, grfCommitFlags); - if (!This->pStream) - return E_FAIL; - - return IStream_Commit (This->pStream, grfCommitFlags); -} - -static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Revert (LPSTREAM iface) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); - TRACE("(%p): redirecting to low-level stream\n", This); - if (!This->pStream) - return E_FAIL; - - return IStream_Revert (This->pStream); -} - -static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); - TRACE("(%p, %s, %s, %#lx): redirecting to low-level stream\n", This, wine_dbgstr_longlong(libOffset.QuadPart), wine_dbgstr_longlong(cb.QuadPart), dwLockType); - if (!This->pStream) - return E_FAIL; - - return IStream_LockRegion (This->pStream, libOffset, cb, dwLockType); -} - -static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); - TRACE("(%p, %s, %s, %#lx): redirecting to low-level stream\n", This, wine_dbgstr_longlong(libOffset.QuadPart), wine_dbgstr_longlong(cb.QuadPart), dwLockType); - if (!This->pStream) - return E_FAIL; - - return IStream_UnlockRegion (This->pStream, libOffset, cb, dwLockType); -} - -static HRESULT WINAPI IDirectMusicLoaderGenericStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag) { - ICOM_THIS_MULTI(IDirectMusicLoaderGenericStream, StreamVtbl, iface); - TRACE("(%p, %p, %#lx): redirecting to low-level stream\n", This, pstatstg, grfStatFlag); - if (!This->pStream) - return E_FAIL; - - return IStream_Stat (This->pStream, pstatstg, grfStatFlag); -} - -static const IStreamVtbl DirectMusicLoaderGenericStream_Stream_Vtbl = { - IDirectMusicLoaderGenericStream_IStream_QueryInterface, - IDirectMusicLoaderGenericStream_IStream_AddRef, - IDirectMusicLoaderGenericStream_IStream_Release, - IDirectMusicLoaderGenericStream_IStream_Read, - IDirectMusicLoaderGenericStream_IStream_Write, - IDirectMusicLoaderGenericStream_IStream_Seek, - IDirectMusicLoaderGenericStream_IStream_SetSize, - IDirectMusicLoaderGenericStream_IStream_CopyTo, - IDirectMusicLoaderGenericStream_IStream_Commit, - IDirectMusicLoaderGenericStream_IStream_Revert, - IDirectMusicLoaderGenericStream_IStream_LockRegion, - IDirectMusicLoaderGenericStream_IStream_UnlockRegion, - IDirectMusicLoaderGenericStream_IStream_Stat, - IDirectMusicLoaderGenericStream_IStream_Clone -}; - -HRESULT DMUSIC_CreateDirectMusicLoaderGenericStream (void** ppobj) { - IDirectMusicLoaderGenericStream *obj; - - TRACE("(%p)\n", ppobj); - - *ppobj = NULL; - if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; - obj->StreamVtbl = &DirectMusicLoaderGenericStream_Stream_Vtbl; - obj->dwRef = 0; /* will be inited with QueryInterface */ - - return IDirectMusicLoaderGenericStream_IStream_QueryInterface ((LPSTREAM)&obj->StreamVtbl, &IID_IStream, ppobj); -} From 5b9859b99f2218f6b6da3dbe9eca2dc7fe7dd89e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 28 Sep 2023 08:20:46 +0200 Subject: [PATCH 2571/2777] dmime/tests: Remove some duplicated tests. These are now more extensively tested in dmime/tests/dmime.c. (cherry picked from commit ed2eebf2f5b9390f5edad605860a61851ba15623) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/performance.c | 147 --------------------------------- 1 file changed, 147 deletions(-) diff --git a/dlls/dmime/tests/performance.c b/dlls/dmime/tests/performance.c index 5cb91a78387..6a8efcdf28a 100644 --- a/dlls/dmime/tests/performance.c +++ b/dlls/dmime/tests/performance.c @@ -489,151 +489,6 @@ static void test_COM(void) ok (refcount == 0, "refcount == %lu, expected 0\n", refcount); } -static void test_notification_type(void) -{ - static unsigned char rifffile[8+4+8+16+8+256] = "RIFF\x24\x01\x00\x00WAVE" /* header: 4 ("WAVE") + (8 + 16) (format segment) + (8 + 256) (data segment) = 0x124 */ - "fmt \x10\x00\x00\x00\x01\x00\x20\x00\xAC\x44\x00\x00\x10\xB1\x02\x00\x04\x00\x10\x00" /* format segment: PCM, 2 chan, 44100 Hz, 16 bits */ - "data\x00\x01\x00\x00"; /* 256 byte data segment (silence) */ - - IDirectMusicPerformance8 *perf; - IDirectMusic *music = NULL; - IDirectMusicSegment8 *prime_segment8; - IDirectMusicSegment8 *segment8 = NULL; - IDirectMusicLoader8 *loader; - IDirectMusicAudioPath8 *path; - IDirectMusicSegmentState *state; - IDirectSound *dsound = NULL; - HRESULT hr; - DWORD result; - HANDLE messages; - DMUS_NOTIFICATION_PMSG *msg; - BOOL found_end = FALSE; - DMUS_OBJECTDESC desc = {0}; - - hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, - CLSCTX_INPROC_SERVER, &IID_IDirectMusicPerformance8, (void**)&perf); - ok(hr == S_OK, "CoCreateInstance failed: %#lx\n", hr); - - hr = IDirectMusicPerformance8_InitAudio(perf, &music, &dsound, NULL, DMUS_APATH_DYNAMIC_STEREO, 64, DMUS_AUDIOF_ALL, NULL); - ok(music != NULL, "Didn't get IDirectMusic pointer\n"); - ok(dsound != NULL, "Didn't get IDirectSound pointer\n"); - - hr = CoCreateInstance(&CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusicLoader8, (void**)&loader); - ok(hr == S_OK, "CoCreateInstance failed: %#lx\n", hr); - - messages = CreateEventA( NULL, FALSE, FALSE, NULL ); - - hr = IDirectMusicPerformance8_AddNotificationType(perf, &GUID_NOTIFICATION_SEGMENT); - ok(hr == S_OK, "Failed: %#lx\n", hr); - - hr = IDirectMusicPerformance8_SetNotificationHandle(perf, messages, 0); - ok(hr == S_OK, "Failed: %#lx\n", hr); - - hr = IDirectMusicPerformance8_GetDefaultAudioPath(perf, &path); - ok(hr == S_OK, "Failed: %#lx\n", hr); - ok(path != NULL, "Didn't get IDirectMusicAudioPath pointer\n"); - - desc.dwSize = sizeof(DMUS_OBJECTDESC); - desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_MEMORY; - desc.guidClass = CLSID_DirectMusicSegment; - desc.pbMemData = rifffile; - desc.llMemLength = sizeof(rifffile); - hr = IDirectMusicLoader8_GetObject(loader, &desc, &IID_IDirectMusicSegment8, (void**)&prime_segment8); - ok(hr == S_OK, "Failed: %#lx\n", hr); - ok(prime_segment8 != NULL, "Didn't get IDirectMusicSegment pointer\n"); - - hr = IDirectMusicSegment8_Download(prime_segment8, (IUnknown*)path); - ok(hr == S_OK, "Download failed: %#lx\n", hr); - - hr = IDirectMusicPerformance8_PlaySegmentEx(perf, (IUnknown*)prime_segment8, - NULL, NULL, DMUS_SEGF_SECONDARY, 0, &state, NULL, (IUnknown*)path); - ok(hr == S_OK, "PlaySegmentEx failed: %#lx\n", hr); - ok(state != NULL, "Didn't get IDirectMusicSegmentState pointer\n"); - - while (!found_end) { - result = WaitForSingleObject(messages, 500); - todo_wine ok(result == WAIT_OBJECT_0, "Failed: %ld\n", result); - if (result != WAIT_OBJECT_0) - break; - - msg = NULL; - hr = IDirectMusicPerformance8_GetNotificationPMsg(perf, &msg); - ok(hr == S_OK, "Failed: %#lx\n", hr); - ok(msg != NULL, "Unexpected NULL pointer\n"); - if (FAILED(hr) || !msg) - break; - - trace("Notification: %ld\n", msg->dwNotificationOption); - - if (msg->dwNotificationOption == DMUS_NOTIFICATION_SEGEND || - msg->dwNotificationOption == DMUS_NOTIFICATION_SEGALMOSTEND) { - ok(msg->punkUser != NULL, "Unexpected NULL pointer\n"); - if (msg->punkUser) { - IDirectMusicSegmentState8 *segmentstate; - IDirectMusicSegment *segment; - - hr = IUnknown_QueryInterface(msg->punkUser, &IID_IDirectMusicSegmentState8, (void**)&segmentstate); - ok(hr == S_OK, "Failed: %#lx\n", hr); - - hr = IDirectMusicSegmentState8_GetSegment(segmentstate, &segment); - ok(hr == S_OK, "Failed: %#lx\n", hr); - if (FAILED(hr)) { - IDirectMusicSegmentState8_Release(segmentstate); - break; - } - - hr = IDirectMusicSegment_QueryInterface(segment, &IID_IDirectMusicSegment8, (void**)&segment8); - ok(hr == S_OK, "Failed: %#lx\n", hr); - - found_end = TRUE; - - IDirectMusicSegment_Release(segment); - IDirectMusicSegmentState8_Release(segmentstate); - } - } - - IDirectMusicPerformance8_FreePMsg(perf, (DMUS_PMSG*)msg); - } - todo_wine ok(prime_segment8 == segment8, "Wrong end segment\n"); - todo_wine ok(found_end, "Didn't receive DMUS_NOTIFICATION_SEGEND message\n"); - - CloseHandle(messages); - - if(segment8) - IDirectMusicSegment8_Release(segment8); - IDirectSound_Release(dsound); - IDirectMusicSegmentState_Release(state); - IDirectMusicAudioPath_Release(path); - IDirectMusicLoader8_Release(loader); - IDirectMusic_Release(music); - IDirectMusicPerformance8_Release(perf); -} - -static void test_performance_graph(void) -{ - HRESULT hr; - IDirectMusicPerformance8 *perf; - IDirectMusicGraph *graph = NULL, *graph2; - - create_performance(&perf, NULL, NULL, FALSE); - hr = IDirectMusicPerformance8_Init(perf, NULL, NULL, NULL); - ok(hr == S_OK, "Init failed: %#lx\n", hr); - - hr = IDirectMusicPerformance8_GetGraph(perf, NULL); - ok(hr == E_POINTER, "Failed: %#lx\n", hr); - - hr = IDirectMusicPerformance8_GetGraph(perf, &graph2); - ok(hr == DMUS_E_NOT_FOUND, "Failed: %#lx\n", hr); - ok(graph2 == NULL, "unexpected pointer.\n"); - - hr = IDirectMusicPerformance8_QueryInterface(perf, &IID_IDirectMusicGraph, (void**)&graph); - ok(hr == S_OK, "Failed: %#lx\n", hr); - - if (graph) - IDirectMusicGraph_Release(graph); - destroy_performance(perf, NULL, NULL); -} - START_TEST( performance ) { HRESULT hr; @@ -653,8 +508,6 @@ START_TEST( performance ) test_COM(); test_createport(); test_pchannel(); - test_notification_type(); - test_performance_graph(); CoUninitialize(); } From 8c01b5f067867b985f694cd1f93b4f1666f69a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 28 Sep 2023 08:25:39 +0200 Subject: [PATCH 2572/2777] dmime/tests: Move performance tests into dmime.c. (cherry picked from commit de27d59a8a71919f22f6e69b673588fdb43daac8) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/Makefile.in | 3 +- dlls/dmime/tests/dmime.c | 458 +++++++++++++++++++++++++++++ dlls/dmime/tests/performance.c | 513 --------------------------------- 3 files changed, 459 insertions(+), 515 deletions(-) delete mode 100644 dlls/dmime/tests/performance.c diff --git a/dlls/dmime/tests/Makefile.in b/dlls/dmime/tests/Makefile.in index 2491f9ff1b8..f07cdf835e9 100644 --- a/dlls/dmime/tests/Makefile.in +++ b/dlls/dmime/tests/Makefile.in @@ -2,7 +2,6 @@ TESTDLL = dmime.dll IMPORTS = user32 ole32 dsound C_SRCS = \ - dmime.c \ - performance.c + dmime.c RC_SRCS = resource.rc diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 1266c5d053b..12056f15376 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -21,12 +21,16 @@ #include #include #include +#include #include #include #include #include #include +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); +DEFINE_GUID(GUID_Bunk,0xFFFFFFFF,0xFFFF,0xFFFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF); + static ULONG get_refcount(void *iface) { IUnknown *unknown = iface; @@ -551,6 +555,43 @@ static HRESULT test_loader_stream_create(IStream *stream, IDirectMusicLoader *lo return S_OK; } +static void create_performance(IDirectMusicPerformance8 **performance, IDirectMusic **dmusic, + IDirectSound **dsound, BOOL set_cooplevel) +{ + HRESULT hr; + + hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicPerformance8, (void **)performance); + ok(hr == S_OK, "DirectMusicPerformance create failed: %#lx\n", hr); + if (dmusic) { + hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic8, + (void **)dmusic); + ok(hr == S_OK, "DirectMusic create failed: %#lx\n", hr); + } + if (dsound) { + hr = DirectSoundCreate8(NULL, (IDirectSound8 **)dsound, NULL); + ok(hr == S_OK, "DirectSoundCreate failed: %#lx\n", hr); + if (set_cooplevel) { + hr = IDirectSound_SetCooperativeLevel(*dsound, GetForegroundWindow(), DSSCL_PRIORITY); + ok(hr == S_OK, "SetCooperativeLevel failed: %#lx\n", hr); + } + } +} + +static void destroy_performance(IDirectMusicPerformance8 *performance, IDirectMusic *dmusic, + IDirectSound *dsound) +{ + HRESULT hr; + + hr = IDirectMusicPerformance8_CloseDown(performance); + ok(hr == S_OK, "CloseDown failed: %#lx\n", hr); + IDirectMusicPerformance8_Release(performance); + if (dmusic) + IDirectMusic_Release(dmusic); + if (dsound) + IDirectSound_Release(dsound); +} + static BOOL missing_dmime(void) { IDirectMusicSegment8 *dms; @@ -945,6 +986,49 @@ static void test_COM_track(void) } } +static void test_COM_performance(void) +{ + IDirectMusicPerformance *dmp = (IDirectMusicPerformance*)0xdeadbeef; + IDirectMusicPerformance *dmp2; + IDirectMusicPerformance8 *dmp8; + ULONG refcount; + HRESULT hr; + + /* COM aggregation */ + hr = CoCreateInstance(&CLSID_DirectMusicPerformance, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER, + &IID_IUnknown, (void**)&dmp); + ok(hr == CLASS_E_NOAGGREGATION, + "DirectMusicPerformance create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr); + ok(!dmp, "dmp = %p\n", dmp); + + /* Invalid RIID */ + hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicObject, (void**)&dmp); + ok(hr == E_NOINTERFACE, "DirectMusicPerformance create failed: %#lx, expected E_NOINTERFACE\n", hr); + + /* Same refcount */ + hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicPerformance, (void**)&dmp); + ok(hr == S_OK, "DirectMusicPerformance create failed: %#lx, expected S_OK\n", hr); + refcount = IDirectMusicPerformance_AddRef(dmp); + ok (refcount == 2, "refcount == %lu, expected 2\n", refcount); + hr = IDirectMusicPerformance_QueryInterface(dmp, &IID_IDirectMusicPerformance2, (void**)&dmp2); + ok(hr == S_OK, "QueryInterface for IID_IDirectMusicPerformance2 failed: %#lx\n", hr); + IDirectMusicPerformance_AddRef(dmp); + refcount = IDirectMusicPerformance_Release(dmp); + ok (refcount == 3, "refcount == %lu, expected 3\n", refcount); + hr = IDirectMusicPerformance_QueryInterface(dmp, &IID_IDirectMusicPerformance8, (void**)&dmp8); + ok(hr == S_OK, "QueryInterface for IID_IDirectMusicPerformance8 failed: %#lx\n", hr); + refcount = IDirectMusicPerformance_Release(dmp); + ok (refcount == 3, "refcount == %lu, expected 3\n", refcount); + refcount = IDirectMusicPerformance8_Release(dmp8); + ok (refcount == 2, "refcount == %lu, expected 2\n", refcount); + refcount = IDirectMusicPerformance_Release(dmp2); + ok (refcount == 1, "refcount == %lu, expected 1\n", refcount); + refcount = IDirectMusicPerformance_Release(dmp); + ok (refcount == 0, "refcount == %lu, expected 0\n", refcount); +} + static void test_audiopathconfig(void) { IDirectMusicObject *dmo; @@ -1809,6 +1893,376 @@ static void test_parsedescriptor(void) } } +static void test_performance_InitAudio(void) +{ + IDirectMusicPerformance8 *performance; + IDirectMusic *dmusic; + IDirectSound *dsound; + IDirectMusicPort *port; + IDirectMusicAudioPath *path; + DWORD channel, group; + HRESULT hr; + ULONG ref; + + hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicPerformance8, (void **)&performance); + if (hr != S_OK) { + win_skip("Cannot create DirectMusicPerformance object (%lx)\n", hr); + CoUninitialize(); + return; + } + + dsound = NULL; + hr = IDirectMusicPerformance8_InitAudio(performance, NULL, &dsound, NULL, + DMUS_APATH_SHARED_STEREOPLUSREVERB, 128, DMUS_AUDIOF_ALL, NULL); + if (hr != S_OK) { + IDirectMusicPerformance8_Release(performance); + win_skip("InitAudio failed (%lx)\n", hr); + return; + } + + hr = IDirectMusicPerformance8_PChannelInfo(performance, 128, &port, NULL, NULL); + ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx\n", hr); + hr = IDirectMusicPerformance8_PChannelInfo(performance, 127, &port, NULL, NULL); + ok(hr == S_OK, "PChannelInfo failed, got %#lx\n", hr); + IDirectMusicPort_Release(port); + port = NULL; + hr = IDirectMusicPerformance8_PChannelInfo(performance, 0, &port, NULL, NULL); + ok(hr == S_OK, "PChannelInfo failed, got %#lx\n", hr); + ok(port != NULL, "IDirectMusicPort not set\n"); + hr = IDirectMusicPerformance8_AssignPChannel(performance, 0, port, 0, 0); + todo_wine ok(hr == DMUS_E_AUDIOPATHS_IN_USE, "AssignPChannel failed (%#lx)\n", hr); + hr = IDirectMusicPerformance8_AssignPChannelBlock(performance, 0, port, 0); + todo_wine ok(hr == DMUS_E_AUDIOPATHS_IN_USE, "AssignPChannelBlock failed (%#lx)\n", hr); + IDirectMusicPort_Release(port); + + hr = IDirectMusicPerformance8_GetDefaultAudioPath(performance, &path); + ok(hr == S_OK, "Failed to call GetDefaultAudioPath (%lx)\n", hr); + if (hr == S_OK) + IDirectMusicAudioPath_Release(path); + + hr = IDirectMusicPerformance8_CloseDown(performance); + ok(hr == S_OK, "Failed to call CloseDown (%lx)\n", hr); + + IDirectMusicPerformance8_Release(performance); + + /* Auto generated dmusic and dsound */ + create_performance(&performance, NULL, NULL, FALSE); + hr = IDirectMusicPerformance8_InitAudio(performance, NULL, NULL, NULL, 0, 64, 0, NULL); + ok(hr == S_OK, "InitAudio failed: %#lx\n", hr); + hr = IDirectMusicPerformance8_PChannelInfo(performance, 0, &port, NULL, NULL); + ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx\n", hr); + destroy_performance(performance, NULL, NULL); + + /* Refcounts for auto generated dmusic and dsound */ + create_performance(&performance, NULL, NULL, FALSE); + dmusic = NULL; + dsound = NULL; + hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, &dsound, NULL, 0, 64, 0, NULL); + ok(hr == S_OK, "InitAudio failed: %#lx\n", hr); + ref = get_refcount(dsound); + ok(ref == 3, "dsound ref count got %ld expected 3\n", ref); + ref = get_refcount(dmusic); + ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref); + destroy_performance(performance, NULL, NULL); + + /* dsound without SetCooperativeLevel() */ + create_performance(&performance, NULL, &dsound, FALSE); + hr = IDirectMusicPerformance8_InitAudio(performance, NULL, &dsound, NULL, 0, 0, 0, NULL); + todo_wine ok(hr == DSERR_PRIOLEVELNEEDED, "InitAudio failed: %#lx\n", hr); + destroy_performance(performance, NULL, dsound); + + /* Using the wrong CLSID_DirectSound */ + create_performance(&performance, NULL, NULL, FALSE); + hr = DirectSoundCreate(NULL, &dsound, NULL); + ok(hr == S_OK, "DirectSoundCreate failed: %#lx\n", hr); + hr = IDirectMusicPerformance8_InitAudio(performance, NULL, &dsound, NULL, 0, 0, 0, NULL); + todo_wine ok(hr == E_NOINTERFACE, "InitAudio failed: %#lx\n", hr); + destroy_performance(performance, NULL, dsound); + + /* Init() works with just a CLSID_DirectSound */ + create_performance(&performance, NULL, NULL, FALSE); + hr = DirectSoundCreate(NULL, &dsound, NULL); + ok(hr == S_OK, "DirectSoundCreate failed: %#lx\n", hr); + hr = IDirectSound_SetCooperativeLevel(dsound, GetForegroundWindow(), DSSCL_PRIORITY); + ok(hr == S_OK, "SetCooperativeLevel failed: %#lx\n", hr); + hr = IDirectMusicPerformance8_Init(performance, NULL, dsound, NULL); + ok(hr == S_OK, "Init failed: %#lx\n", hr); + destroy_performance(performance, NULL, dsound); + + /* Init() followed by InitAudio() */ + create_performance(&performance, NULL, &dsound, TRUE); + hr = IDirectMusicPerformance8_Init(performance, NULL, dsound, NULL); + ok(hr == S_OK, "Init failed: %#lx\n", hr); + hr = IDirectMusicPerformance8_InitAudio(performance, NULL, &dsound, NULL, 0, 0, 0, NULL); + ok(hr == DMUS_E_ALREADY_INITED, "InitAudio failed: %#lx\n", hr); + destroy_performance(performance, NULL, dsound); + + /* Provided dmusic and dsound */ + create_performance(&performance, &dmusic, &dsound, TRUE); + hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, &dsound, NULL, 0, 64, 0, NULL); + ok(hr == S_OK, "InitAudio failed: %#lx\n", hr); + ref = get_refcount(dsound); + todo_wine ok(ref == 2, "dsound ref count got %ld expected 2\n", ref); + ref = get_refcount(dmusic); + ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref); + destroy_performance(performance, dmusic, dsound); + + /* Provided dmusic initialized with SetDirectSound */ + create_performance(&performance, &dmusic, &dsound, TRUE); + hr = IDirectMusic_SetDirectSound(dmusic, dsound, NULL); + ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr); + ref = get_refcount(dsound); + ok(ref == 2, "dsound ref count got %ld expected 2\n", ref); + hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, NULL, NULL, 0, 64, 0, NULL); + ok(hr == S_OK, "InitAudio failed: %#lx\n", hr); + ref = get_refcount(dsound); + todo_wine ok(ref == 2, "dsound ref count got %ld expected 2\n", ref); + ref = get_refcount(dmusic); + ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref); + destroy_performance(performance, dmusic, dsound); + + /* Provided dmusic and dsound, dmusic initialized with SetDirectSound */ + create_performance(&performance, &dmusic, &dsound, TRUE); + hr = IDirectMusic_SetDirectSound(dmusic, dsound, NULL); + ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr); + ref = get_refcount(dsound); + ok(ref == 2, "dsound ref count got %ld expected 2\n", ref); + hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, &dsound, NULL, 0, 64, 0, NULL); + ok(hr == S_OK, "InitAudio failed: %#lx\n", hr); + ref = get_refcount(dsound); + ok(ref == 3, "dsound ref count got %ld expected 3\n", ref); + ref = get_refcount(dmusic); + ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref); + destroy_performance(performance, dmusic, dsound); + + /* InitAudio with perf channel count not a multiple of 16 rounds up */ + create_performance(&performance, NULL, NULL, TRUE); + hr = IDirectMusicPerformance8_InitAudio(performance, NULL, NULL, NULL, + DMUS_APATH_SHARED_STEREOPLUSREVERB, 29, DMUS_AUDIOF_ALL, NULL); + ok(hr == S_OK, "InitAudio failed: %#lx\n", hr); + hr = IDirectMusicPerformance8_PChannelInfo(performance, 31, &port, &group, &channel); + ok(hr == S_OK && group == 2 && channel == 15, + "PChannelInfo failed, got %#lx, %lu, %lu\n", hr, group, channel); + hr = IDirectMusicPerformance8_PChannelInfo(performance, 32, &port, NULL, NULL); + ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx\n", hr); + destroy_performance(performance, NULL, NULL); +} + +static void test_performance_createport(void) +{ + IDirectMusicPerformance8 *perf; + IDirectMusic *music = NULL; + IDirectMusicPort *port = NULL; + DMUS_PORTCAPS portcaps; + DMUS_PORTPARAMS portparams; + DWORD i; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, + CLSCTX_INPROC_SERVER, &IID_IDirectMusicPerformance8, (void**)&perf); + ok(hr == S_OK, "CoCreateInstance failed: %#lx\n", hr); + + hr = IDirectMusicPerformance8_Init(perf, &music, NULL, NULL); + ok(hr == S_OK, "Init failed: %#lx\n", hr); + ok(music != NULL, "Didn't get IDirectMusic pointer\n"); + + i = 0; + while(1){ + portcaps.dwSize = sizeof(portcaps); + + hr = IDirectMusic_EnumPort(music, i, &portcaps); + ok(hr == S_OK || hr == S_FALSE || (i == 0 && hr == E_INVALIDARG), "EnumPort failed: %#lx\n", hr); + if(hr != S_OK) + break; + + ok(portcaps.dwSize == sizeof(portcaps), "Got unexpected portcaps struct size: %lu\n", portcaps.dwSize); + trace("portcaps(%lu).dwFlags: %#lx\n", i, portcaps.dwFlags); + trace("portcaps(%lu).guidPort: %s\n", i, wine_dbgstr_guid(&portcaps.guidPort)); + trace("portcaps(%lu).dwClass: %#lx\n", i, portcaps.dwClass); + trace("portcaps(%lu).dwType: %#lx\n", i, portcaps.dwType); + trace("portcaps(%lu).dwMemorySize: %#lx\n", i, portcaps.dwMemorySize); + trace("portcaps(%lu).dwMaxChannelGroups: %lu\n", i, portcaps.dwMaxChannelGroups); + trace("portcaps(%lu).dwMaxVoices: %lu\n", i, portcaps.dwMaxVoices); + trace("portcaps(%lu).dwMaxAudioChannels: %lu\n", i, portcaps.dwMaxAudioChannels); + trace("portcaps(%lu).dwEffectFlags: %#lx\n", i, portcaps.dwEffectFlags); + trace("portcaps(%lu).wszDescription: %s\n", i, wine_dbgstr_w(portcaps.wszDescription)); + + ++i; + } + + if(i == 0){ + win_skip("No ports available, skipping tests\n"); + return; + } + + portparams.dwSize = sizeof(portparams); + + /* dwValidParams == 0 -> S_OK, filled struct */ + portparams.dwValidParams = 0; + hr = IDirectMusic_CreatePort(music, &CLSID_DirectMusicSynth, &portparams, &port, NULL); + ok(hr == S_OK, "CreatePort failed: %#lx\n", hr); + ok(port != NULL, "Didn't get IDirectMusicPort pointer\n"); + ok(portparams.dwValidParams, "portparams struct was not filled in\n"); + IDirectMusicPort_Release(port); + port = NULL; + + /* dwValidParams != 0, invalid param -> S_FALSE, filled struct */ + portparams.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS; + portparams.dwChannelGroups = 0; + hr = IDirectMusic_CreatePort(music, &CLSID_DirectMusicSynth, &portparams, &port, NULL); + todo_wine ok(hr == S_FALSE, "CreatePort failed: %#lx\n", hr); + ok(port != NULL, "Didn't get IDirectMusicPort pointer\n"); + ok(portparams.dwValidParams, "portparams struct was not filled in\n"); + IDirectMusicPort_Release(port); + port = NULL; + + /* dwValidParams != 0, valid params -> S_OK */ + hr = IDirectMusic_CreatePort(music, &CLSID_DirectMusicSynth, &portparams, &port, NULL); + ok(hr == S_OK, "CreatePort failed: %#lx\n", hr); + ok(port != NULL, "Didn't get IDirectMusicPort pointer\n"); + IDirectMusicPort_Release(port); + port = NULL; + + /* GUID_NULL succeeds */ + portparams.dwValidParams = 0; + hr = IDirectMusic_CreatePort(music, &GUID_NULL, &portparams, &port, NULL); + ok(hr == S_OK, "CreatePort failed: %#lx\n", hr); + ok(port != NULL, "Didn't get IDirectMusicPort pointer\n"); + ok(portparams.dwValidParams, "portparams struct was not filled in\n"); + IDirectMusicPort_Release(port); + port = NULL; + + /* null GUID fails */ + portparams.dwValidParams = 0; + hr = IDirectMusic_CreatePort(music, NULL, &portparams, &port, NULL); + ok(hr == E_POINTER, "CreatePort failed: %#lx\n", hr); + ok(port == NULL, "Get IDirectMusicPort pointer? %p\n", port); + ok(portparams.dwValidParams == 0, "portparams struct was filled in?\n"); + + /* garbage GUID fails */ + portparams.dwValidParams = 0; + hr = IDirectMusic_CreatePort(music, &GUID_Bunk, &portparams, &port, NULL); + ok(hr == E_NOINTERFACE, "CreatePort failed: %#lx\n", hr); + ok(port == NULL, "Get IDirectMusicPort pointer? %p\n", port); + ok(portparams.dwValidParams == 0, "portparams struct was filled in?\n"); + + hr = IDirectMusicPerformance8_CloseDown(perf); + ok(hr == S_OK, "CloseDown failed: %#lx\n", hr); + + IDirectMusic_Release(music); + IDirectMusicPerformance8_Release(perf); +} + +static void test_performance_pchannel(void) +{ + IDirectMusicPerformance8 *perf; + IDirectMusicPort *port = NULL, *port2; + DWORD channel, group; + unsigned int i; + HRESULT hr; + + create_performance(&perf, NULL, NULL, TRUE); + hr = IDirectMusicPerformance8_Init(perf, NULL, NULL, NULL); + ok(hr == S_OK, "Init failed: %#lx\n", hr); + hr = IDirectMusicPerformance8_PChannelInfo(perf, 0, &port, NULL, NULL); + ok(hr == E_INVALIDARG && !port, "PChannelInfo failed, got %#lx, %p\n", hr, port); + + /* Add default port. Sets PChannels 0-15 to the corresponding channels in group 1 */ + hr = IDirectMusicPerformance8_AddPort(perf, NULL); + ok(hr == S_OK, "AddPort of default port failed: %#lx\n", hr); + hr = IDirectMusicPerformance8_PChannelInfo(perf, 0, NULL, NULL, NULL); + ok(hr == S_OK, "PChannelInfo failed, got %#lx\n", hr); + hr = IDirectMusicPerformance8_PChannelInfo(perf, 0, &port, NULL, NULL); + ok(hr == S_OK && port, "PChannelInfo failed, got %#lx, %p\n", hr, port); + for (i = 1; i < 16; i++) { + hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, &group, &channel); + ok(hr == S_OK && port == port2 && group == 1 && channel == i, + "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel); + IDirectMusicPort_Release(port2); + } + + /* Unset PChannels fail to retrieve */ + hr = IDirectMusicPerformance8_PChannelInfo(perf, 16, &port2, NULL, NULL); + ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx, %p\n", hr, port); + hr = IDirectMusicPerformance8_PChannelInfo(perf, MAXDWORD - 16, &port2, NULL, NULL); + ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx, %p\n", hr, port); + + /* Channel group 0 can be set just fine */ + hr = IDirectMusicPerformance8_AssignPChannel(perf, 0, port, 0, 0); + ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr); + hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, 0, port, 0); + ok(hr == S_OK, "AssignPChannelBlock failed, got %#lx\n", hr); + for (i = 1; i < 16; i++) { + hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, &group, &channel); + ok(hr == S_OK && port == port2 && group == 0 && channel == i, + "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel); + IDirectMusicPort_Release(port2); + } + + /* Last PChannel Block can be set only individually but not read */ + hr = IDirectMusicPerformance8_AssignPChannel(perf, MAXDWORD, port, 0, 3); + ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr); + port2 = (IDirectMusicPort *)0xdeadbeef; + hr = IDirectMusicPerformance8_PChannelInfo(perf, MAXDWORD, &port2, NULL, NULL); + todo_wine ok(hr == E_INVALIDARG && port2 == (IDirectMusicPort *)0xdeadbeef, + "PChannelInfo failed, got %#lx, %p\n", hr, port2); + hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, MAXDWORD, port, 0); + ok(hr == E_INVALIDARG, "AssignPChannelBlock failed, got %#lx\n", hr); + hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, MAXDWORD / 16, port, 1); + todo_wine ok(hr == E_INVALIDARG, "AssignPChannelBlock failed, got %#lx\n", hr); + for (i = MAXDWORD - 15; i < MAXDWORD; i++) { + hr = IDirectMusicPerformance8_AssignPChannel(perf, i, port, 0, 0); + ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr); + hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, NULL, NULL); + todo_wine ok(hr == E_INVALIDARG && port2 == (IDirectMusicPort *)0xdeadbeef, + "PChannelInfo failed, got %#lx, %p\n", hr, port2); + } + + /* Second to last PChannel Block can be set only individually and read */ + hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, MAXDWORD / 16 - 1, port, 1); + todo_wine ok(hr == E_INVALIDARG, "AssignPChannelBlock failed, got %#lx\n", hr); + for (i = MAXDWORD - 31; i < MAXDWORD - 15; i++) { + hr = IDirectMusicPerformance8_AssignPChannel(perf, i, port, 1, 7); + ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr); + hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, &group, &channel); + ok(hr == S_OK && port2 == port && group == 1 && channel == 7, + "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel); + IDirectMusicPort_Release(port2); + } + + /* Third to last PChannel Block behaves normal */ + hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, MAXDWORD / 16 - 2, port, 0); + ok(hr == S_OK, "AssignPChannelBlock failed, got %#lx\n", hr); + for (i = MAXDWORD - 47; i < MAXDWORD - 31; i++) { + hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, &group, &channel); + ok(hr == S_OK && port2 == port && group == 0 && channel == i % 16, + "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel); + IDirectMusicPort_Release(port2); + } + + /* One PChannel set in a Block, rest is initialized too */ + hr = IDirectMusicPerformance8_AssignPChannel(perf, 4711, port, 1, 13); + ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr); + hr = IDirectMusicPerformance8_PChannelInfo(perf, 4711, &port2, &group, &channel); + ok(hr == S_OK && port2 == port && group == 1 && channel == 13, + "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel); + IDirectMusicPort_Release(port2); + group = channel = 0xdeadbeef; + hr = IDirectMusicPerformance8_PChannelInfo(perf, 4712, &port2, &group, &channel); + ok(hr == S_OK && port2 == port && group == 0 && channel == 8, + "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel); + IDirectMusicPort_Release(port2); + group = channel = 0xdeadbeef; + hr = IDirectMusicPerformance8_PChannelInfo(perf, 4719, &port2, &group, &channel); + ok(hr == S_OK && port2 == port && group == 0 && channel == 15, + "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel); + IDirectMusicPort_Release(port2); + + IDirectMusicPort_Release(port); + destroy_performance(perf, NULL, NULL); +} + static void test_performance_tool(void) { IDirectMusicPerformance *performance; @@ -3169,6 +3623,7 @@ START_TEST(dmime) test_COM_segment(); test_COM_segmentstate(); test_COM_track(); + test_COM_performance(); test_audiopathconfig(); test_graph(); test_segment(); @@ -3176,6 +3631,9 @@ START_TEST(dmime) test_segment_param(); test_track(); test_parsedescriptor(); + test_performance_InitAudio(); + test_performance_createport(); + test_performance_pchannel(); test_performance_tool(); test_performance_graph(); test_performance_time(); diff --git a/dlls/dmime/tests/performance.c b/dlls/dmime/tests/performance.c deleted file mode 100644 index 6a8efcdf28a..00000000000 --- a/dlls/dmime/tests/performance.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Unit test suite for IDirectMusicPerformance - * - * Copyright 2010 Austin Lund - * - * 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 - */ - -#define COBJMACROS - -#include -#include -#include -#include -#include - -#include - -DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); -DEFINE_GUID(GUID_Bunk,0xFFFFFFFF,0xFFFF,0xFFFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF); - -static void create_performance(IDirectMusicPerformance8 **performance, IDirectMusic **dmusic, - IDirectSound **dsound, BOOL set_cooplevel) -{ - HRESULT hr; - - hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectMusicPerformance8, (void **)performance); - ok(hr == S_OK, "DirectMusicPerformance create failed: %#lx\n", hr); - if (dmusic) { - hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic8, - (void **)dmusic); - ok(hr == S_OK, "DirectMusic create failed: %#lx\n", hr); - } - if (dsound) { - hr = DirectSoundCreate8(NULL, (IDirectSound8 **)dsound, NULL); - ok(hr == S_OK, "DirectSoundCreate failed: %#lx\n", hr); - if (set_cooplevel) { - hr = IDirectSound_SetCooperativeLevel(*dsound, GetForegroundWindow(), DSSCL_PRIORITY); - ok(hr == S_OK, "SetCooperativeLevel failed: %#lx\n", hr); - } - } -} - -static void destroy_performance(IDirectMusicPerformance8 *performance, IDirectMusic *dmusic, - IDirectSound *dsound) -{ - HRESULT hr; - - hr = IDirectMusicPerformance8_CloseDown(performance); - ok(hr == S_OK, "CloseDown failed: %#lx\n", hr); - IDirectMusicPerformance8_Release(performance); - if (dmusic) - IDirectMusic_Release(dmusic); - if (dsound) - IDirectSound_Release(dsound); -} - -static ULONG get_refcount(void *iface) -{ - IUnknown *unknown = iface; - IUnknown_AddRef(unknown); - return IUnknown_Release(unknown); -} - -static HRESULT test_InitAudio(void) -{ - IDirectMusicPerformance8 *performance; - IDirectMusic *dmusic; - IDirectSound *dsound; - IDirectMusicPort *port; - IDirectMusicAudioPath *path; - DWORD channel, group; - HRESULT hr; - ULONG ref; - - hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectMusicPerformance8, (void **)&performance); - if (hr != S_OK) { - skip("Cannot create DirectMusicPerformance object (%lx)\n", hr); - CoUninitialize(); - return hr; - } - - dsound = NULL; - hr = IDirectMusicPerformance8_InitAudio(performance, NULL, &dsound, NULL, - DMUS_APATH_SHARED_STEREOPLUSREVERB, 128, DMUS_AUDIOF_ALL, NULL); - if (hr != S_OK) { - IDirectMusicPerformance8_Release(performance); - return hr; - } - - hr = IDirectMusicPerformance8_PChannelInfo(performance, 128, &port, NULL, NULL); - ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx\n", hr); - hr = IDirectMusicPerformance8_PChannelInfo(performance, 127, &port, NULL, NULL); - ok(hr == S_OK, "PChannelInfo failed, got %#lx\n", hr); - IDirectMusicPort_Release(port); - port = NULL; - hr = IDirectMusicPerformance8_PChannelInfo(performance, 0, &port, NULL, NULL); - ok(hr == S_OK, "PChannelInfo failed, got %#lx\n", hr); - ok(port != NULL, "IDirectMusicPort not set\n"); - hr = IDirectMusicPerformance8_AssignPChannel(performance, 0, port, 0, 0); - todo_wine ok(hr == DMUS_E_AUDIOPATHS_IN_USE, "AssignPChannel failed (%#lx)\n", hr); - hr = IDirectMusicPerformance8_AssignPChannelBlock(performance, 0, port, 0); - todo_wine ok(hr == DMUS_E_AUDIOPATHS_IN_USE, "AssignPChannelBlock failed (%#lx)\n", hr); - IDirectMusicPort_Release(port); - - hr = IDirectMusicPerformance8_GetDefaultAudioPath(performance, &path); - ok(hr == S_OK, "Failed to call GetDefaultAudioPath (%lx)\n", hr); - if (hr == S_OK) - IDirectMusicAudioPath_Release(path); - - hr = IDirectMusicPerformance8_CloseDown(performance); - ok(hr == S_OK, "Failed to call CloseDown (%lx)\n", hr); - - IDirectMusicPerformance8_Release(performance); - - /* Auto generated dmusic and dsound */ - create_performance(&performance, NULL, NULL, FALSE); - hr = IDirectMusicPerformance8_InitAudio(performance, NULL, NULL, NULL, 0, 64, 0, NULL); - ok(hr == S_OK, "InitAudio failed: %#lx\n", hr); - hr = IDirectMusicPerformance8_PChannelInfo(performance, 0, &port, NULL, NULL); - ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx\n", hr); - destroy_performance(performance, NULL, NULL); - - /* Refcounts for auto generated dmusic and dsound */ - create_performance(&performance, NULL, NULL, FALSE); - dmusic = NULL; - dsound = NULL; - hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, &dsound, NULL, 0, 64, 0, NULL); - ok(hr == S_OK, "InitAudio failed: %#lx\n", hr); - ref = get_refcount(dsound); - ok(ref == 3, "dsound ref count got %ld expected 3\n", ref); - ref = get_refcount(dmusic); - ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref); - destroy_performance(performance, NULL, NULL); - - /* dsound without SetCooperativeLevel() */ - create_performance(&performance, NULL, &dsound, FALSE); - hr = IDirectMusicPerformance8_InitAudio(performance, NULL, &dsound, NULL, 0, 0, 0, NULL); - todo_wine ok(hr == DSERR_PRIOLEVELNEEDED, "InitAudio failed: %#lx\n", hr); - destroy_performance(performance, NULL, dsound); - - /* Using the wrong CLSID_DirectSound */ - create_performance(&performance, NULL, NULL, FALSE); - hr = DirectSoundCreate(NULL, &dsound, NULL); - ok(hr == S_OK, "DirectSoundCreate failed: %#lx\n", hr); - hr = IDirectMusicPerformance8_InitAudio(performance, NULL, &dsound, NULL, 0, 0, 0, NULL); - todo_wine ok(hr == E_NOINTERFACE, "InitAudio failed: %#lx\n", hr); - destroy_performance(performance, NULL, dsound); - - /* Init() works with just a CLSID_DirectSound */ - create_performance(&performance, NULL, NULL, FALSE); - hr = DirectSoundCreate(NULL, &dsound, NULL); - ok(hr == S_OK, "DirectSoundCreate failed: %#lx\n", hr); - hr = IDirectSound_SetCooperativeLevel(dsound, GetForegroundWindow(), DSSCL_PRIORITY); - ok(hr == S_OK, "SetCooperativeLevel failed: %#lx\n", hr); - hr = IDirectMusicPerformance8_Init(performance, NULL, dsound, NULL); - ok(hr == S_OK, "Init failed: %#lx\n", hr); - destroy_performance(performance, NULL, dsound); - - /* Init() followed by InitAudio() */ - create_performance(&performance, NULL, &dsound, TRUE); - hr = IDirectMusicPerformance8_Init(performance, NULL, dsound, NULL); - ok(hr == S_OK, "Init failed: %#lx\n", hr); - hr = IDirectMusicPerformance8_InitAudio(performance, NULL, &dsound, NULL, 0, 0, 0, NULL); - ok(hr == DMUS_E_ALREADY_INITED, "InitAudio failed: %#lx\n", hr); - destroy_performance(performance, NULL, dsound); - - /* Provided dmusic and dsound */ - create_performance(&performance, &dmusic, &dsound, TRUE); - hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, &dsound, NULL, 0, 64, 0, NULL); - ok(hr == S_OK, "InitAudio failed: %#lx\n", hr); - ref = get_refcount(dsound); - todo_wine ok(ref == 2, "dsound ref count got %ld expected 2\n", ref); - ref = get_refcount(dmusic); - ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref); - destroy_performance(performance, dmusic, dsound); - - /* Provided dmusic initialized with SetDirectSound */ - create_performance(&performance, &dmusic, &dsound, TRUE); - hr = IDirectMusic_SetDirectSound(dmusic, dsound, NULL); - ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr); - ref = get_refcount(dsound); - ok(ref == 2, "dsound ref count got %ld expected 2\n", ref); - hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, NULL, NULL, 0, 64, 0, NULL); - ok(hr == S_OK, "InitAudio failed: %#lx\n", hr); - ref = get_refcount(dsound); - todo_wine ok(ref == 2, "dsound ref count got %ld expected 2\n", ref); - ref = get_refcount(dmusic); - ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref); - destroy_performance(performance, dmusic, dsound); - - /* Provided dmusic and dsound, dmusic initialized with SetDirectSound */ - create_performance(&performance, &dmusic, &dsound, TRUE); - hr = IDirectMusic_SetDirectSound(dmusic, dsound, NULL); - ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr); - ref = get_refcount(dsound); - ok(ref == 2, "dsound ref count got %ld expected 2\n", ref); - hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, &dsound, NULL, 0, 64, 0, NULL); - ok(hr == S_OK, "InitAudio failed: %#lx\n", hr); - ref = get_refcount(dsound); - ok(ref == 3, "dsound ref count got %ld expected 3\n", ref); - ref = get_refcount(dmusic); - ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref); - destroy_performance(performance, dmusic, dsound); - - /* InitAudio with perf channel count not a multiple of 16 rounds up */ - create_performance(&performance, NULL, NULL, TRUE); - hr = IDirectMusicPerformance8_InitAudio(performance, NULL, NULL, NULL, - DMUS_APATH_SHARED_STEREOPLUSREVERB, 29, DMUS_AUDIOF_ALL, NULL); - ok(hr == S_OK, "InitAudio failed: %#lx\n", hr); - hr = IDirectMusicPerformance8_PChannelInfo(performance, 31, &port, &group, &channel); - ok(hr == S_OK && group == 2 && channel == 15, - "PChannelInfo failed, got %#lx, %lu, %lu\n", hr, group, channel); - hr = IDirectMusicPerformance8_PChannelInfo(performance, 32, &port, NULL, NULL); - ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx\n", hr); - destroy_performance(performance, NULL, NULL); - - return S_OK; -} - -static void test_createport(void) -{ - IDirectMusicPerformance8 *perf; - IDirectMusic *music = NULL; - IDirectMusicPort *port = NULL; - DMUS_PORTCAPS portcaps; - DMUS_PORTPARAMS portparams; - DWORD i; - HRESULT hr; - - hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, - CLSCTX_INPROC_SERVER, &IID_IDirectMusicPerformance8, (void**)&perf); - ok(hr == S_OK, "CoCreateInstance failed: %#lx\n", hr); - - hr = IDirectMusicPerformance8_Init(perf, &music, NULL, NULL); - ok(hr == S_OK, "Init failed: %#lx\n", hr); - ok(music != NULL, "Didn't get IDirectMusic pointer\n"); - - i = 0; - while(1){ - portcaps.dwSize = sizeof(portcaps); - - hr = IDirectMusic_EnumPort(music, i, &portcaps); - ok(hr == S_OK || hr == S_FALSE || (i == 0 && hr == E_INVALIDARG), "EnumPort failed: %#lx\n", hr); - if(hr != S_OK) - break; - - ok(portcaps.dwSize == sizeof(portcaps), "Got unexpected portcaps struct size: %lu\n", portcaps.dwSize); - trace("portcaps(%lu).dwFlags: %#lx\n", i, portcaps.dwFlags); - trace("portcaps(%lu).guidPort: %s\n", i, wine_dbgstr_guid(&portcaps.guidPort)); - trace("portcaps(%lu).dwClass: %#lx\n", i, portcaps.dwClass); - trace("portcaps(%lu).dwType: %#lx\n", i, portcaps.dwType); - trace("portcaps(%lu).dwMemorySize: %#lx\n", i, portcaps.dwMemorySize); - trace("portcaps(%lu).dwMaxChannelGroups: %lu\n", i, portcaps.dwMaxChannelGroups); - trace("portcaps(%lu).dwMaxVoices: %lu\n", i, portcaps.dwMaxVoices); - trace("portcaps(%lu).dwMaxAudioChannels: %lu\n", i, portcaps.dwMaxAudioChannels); - trace("portcaps(%lu).dwEffectFlags: %#lx\n", i, portcaps.dwEffectFlags); - trace("portcaps(%lu).wszDescription: %s\n", i, wine_dbgstr_w(portcaps.wszDescription)); - - ++i; - } - - if(i == 0){ - win_skip("No ports available, skipping tests\n"); - return; - } - - portparams.dwSize = sizeof(portparams); - - /* dwValidParams == 0 -> S_OK, filled struct */ - portparams.dwValidParams = 0; - hr = IDirectMusic_CreatePort(music, &CLSID_DirectMusicSynth, &portparams, &port, NULL); - ok(hr == S_OK, "CreatePort failed: %#lx\n", hr); - ok(port != NULL, "Didn't get IDirectMusicPort pointer\n"); - ok(portparams.dwValidParams, "portparams struct was not filled in\n"); - IDirectMusicPort_Release(port); - port = NULL; - - /* dwValidParams != 0, invalid param -> S_FALSE, filled struct */ - portparams.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS; - portparams.dwChannelGroups = 0; - hr = IDirectMusic_CreatePort(music, &CLSID_DirectMusicSynth, &portparams, &port, NULL); - todo_wine ok(hr == S_FALSE, "CreatePort failed: %#lx\n", hr); - ok(port != NULL, "Didn't get IDirectMusicPort pointer\n"); - ok(portparams.dwValidParams, "portparams struct was not filled in\n"); - IDirectMusicPort_Release(port); - port = NULL; - - /* dwValidParams != 0, valid params -> S_OK */ - hr = IDirectMusic_CreatePort(music, &CLSID_DirectMusicSynth, &portparams, &port, NULL); - ok(hr == S_OK, "CreatePort failed: %#lx\n", hr); - ok(port != NULL, "Didn't get IDirectMusicPort pointer\n"); - IDirectMusicPort_Release(port); - port = NULL; - - /* GUID_NULL succeeds */ - portparams.dwValidParams = 0; - hr = IDirectMusic_CreatePort(music, &GUID_NULL, &portparams, &port, NULL); - ok(hr == S_OK, "CreatePort failed: %#lx\n", hr); - ok(port != NULL, "Didn't get IDirectMusicPort pointer\n"); - ok(portparams.dwValidParams, "portparams struct was not filled in\n"); - IDirectMusicPort_Release(port); - port = NULL; - - /* null GUID fails */ - portparams.dwValidParams = 0; - hr = IDirectMusic_CreatePort(music, NULL, &portparams, &port, NULL); - ok(hr == E_POINTER, "CreatePort failed: %#lx\n", hr); - ok(port == NULL, "Get IDirectMusicPort pointer? %p\n", port); - ok(portparams.dwValidParams == 0, "portparams struct was filled in?\n"); - - /* garbage GUID fails */ - portparams.dwValidParams = 0; - hr = IDirectMusic_CreatePort(music, &GUID_Bunk, &portparams, &port, NULL); - ok(hr == E_NOINTERFACE, "CreatePort failed: %#lx\n", hr); - ok(port == NULL, "Get IDirectMusicPort pointer? %p\n", port); - ok(portparams.dwValidParams == 0, "portparams struct was filled in?\n"); - - hr = IDirectMusicPerformance8_CloseDown(perf); - ok(hr == S_OK, "CloseDown failed: %#lx\n", hr); - - IDirectMusic_Release(music); - IDirectMusicPerformance8_Release(perf); -} - -static void test_pchannel(void) -{ - IDirectMusicPerformance8 *perf; - IDirectMusicPort *port = NULL, *port2; - DWORD channel, group; - unsigned int i; - HRESULT hr; - - create_performance(&perf, NULL, NULL, TRUE); - hr = IDirectMusicPerformance8_Init(perf, NULL, NULL, NULL); - ok(hr == S_OK, "Init failed: %#lx\n", hr); - hr = IDirectMusicPerformance8_PChannelInfo(perf, 0, &port, NULL, NULL); - ok(hr == E_INVALIDARG && !port, "PChannelInfo failed, got %#lx, %p\n", hr, port); - - /* Add default port. Sets PChannels 0-15 to the corresponding channels in group 1 */ - hr = IDirectMusicPerformance8_AddPort(perf, NULL); - ok(hr == S_OK, "AddPort of default port failed: %#lx\n", hr); - hr = IDirectMusicPerformance8_PChannelInfo(perf, 0, NULL, NULL, NULL); - ok(hr == S_OK, "PChannelInfo failed, got %#lx\n", hr); - hr = IDirectMusicPerformance8_PChannelInfo(perf, 0, &port, NULL, NULL); - ok(hr == S_OK && port, "PChannelInfo failed, got %#lx, %p\n", hr, port); - for (i = 1; i < 16; i++) { - hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, &group, &channel); - ok(hr == S_OK && port == port2 && group == 1 && channel == i, - "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel); - IDirectMusicPort_Release(port2); - } - - /* Unset PChannels fail to retrieve */ - hr = IDirectMusicPerformance8_PChannelInfo(perf, 16, &port2, NULL, NULL); - ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx, %p\n", hr, port); - hr = IDirectMusicPerformance8_PChannelInfo(perf, MAXDWORD - 16, &port2, NULL, NULL); - ok(hr == E_INVALIDARG, "PChannelInfo failed, got %#lx, %p\n", hr, port); - - /* Channel group 0 can be set just fine */ - hr = IDirectMusicPerformance8_AssignPChannel(perf, 0, port, 0, 0); - ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr); - hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, 0, port, 0); - ok(hr == S_OK, "AssignPChannelBlock failed, got %#lx\n", hr); - for (i = 1; i < 16; i++) { - hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, &group, &channel); - ok(hr == S_OK && port == port2 && group == 0 && channel == i, - "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel); - IDirectMusicPort_Release(port2); - } - - /* Last PChannel Block can be set only individually but not read */ - hr = IDirectMusicPerformance8_AssignPChannel(perf, MAXDWORD, port, 0, 3); - ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr); - port2 = (IDirectMusicPort *)0xdeadbeef; - hr = IDirectMusicPerformance8_PChannelInfo(perf, MAXDWORD, &port2, NULL, NULL); - todo_wine ok(hr == E_INVALIDARG && port2 == (IDirectMusicPort *)0xdeadbeef, - "PChannelInfo failed, got %#lx, %p\n", hr, port2); - hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, MAXDWORD, port, 0); - ok(hr == E_INVALIDARG, "AssignPChannelBlock failed, got %#lx\n", hr); - hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, MAXDWORD / 16, port, 1); - todo_wine ok(hr == E_INVALIDARG, "AssignPChannelBlock failed, got %#lx\n", hr); - for (i = MAXDWORD - 15; i < MAXDWORD; i++) { - hr = IDirectMusicPerformance8_AssignPChannel(perf, i, port, 0, 0); - ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr); - hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, NULL, NULL); - todo_wine ok(hr == E_INVALIDARG && port2 == (IDirectMusicPort *)0xdeadbeef, - "PChannelInfo failed, got %#lx, %p\n", hr, port2); - } - - /* Second to last PChannel Block can be set only individually and read */ - hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, MAXDWORD / 16 - 1, port, 1); - todo_wine ok(hr == E_INVALIDARG, "AssignPChannelBlock failed, got %#lx\n", hr); - for (i = MAXDWORD - 31; i < MAXDWORD - 15; i++) { - hr = IDirectMusicPerformance8_AssignPChannel(perf, i, port, 1, 7); - ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr); - hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, &group, &channel); - ok(hr == S_OK && port2 == port && group == 1 && channel == 7, - "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel); - IDirectMusicPort_Release(port2); - } - - /* Third to last PChannel Block behaves normal */ - hr = IDirectMusicPerformance8_AssignPChannelBlock(perf, MAXDWORD / 16 - 2, port, 0); - ok(hr == S_OK, "AssignPChannelBlock failed, got %#lx\n", hr); - for (i = MAXDWORD - 47; i < MAXDWORD - 31; i++) { - hr = IDirectMusicPerformance8_PChannelInfo(perf, i, &port2, &group, &channel); - ok(hr == S_OK && port2 == port && group == 0 && channel == i % 16, - "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel); - IDirectMusicPort_Release(port2); - } - - /* One PChannel set in a Block, rest is initialized too */ - hr = IDirectMusicPerformance8_AssignPChannel(perf, 4711, port, 1, 13); - ok(hr == S_OK, "AssignPChannel failed, got %#lx\n", hr); - hr = IDirectMusicPerformance8_PChannelInfo(perf, 4711, &port2, &group, &channel); - ok(hr == S_OK && port2 == port && group == 1 && channel == 13, - "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel); - IDirectMusicPort_Release(port2); - group = channel = 0xdeadbeef; - hr = IDirectMusicPerformance8_PChannelInfo(perf, 4712, &port2, &group, &channel); - ok(hr == S_OK && port2 == port && group == 0 && channel == 8, - "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel); - IDirectMusicPort_Release(port2); - group = channel = 0xdeadbeef; - hr = IDirectMusicPerformance8_PChannelInfo(perf, 4719, &port2, &group, &channel); - ok(hr == S_OK && port2 == port && group == 0 && channel == 15, - "PChannelInfo failed, got %#lx, %p, %lu, %lu\n", hr, port2, group, channel); - IDirectMusicPort_Release(port2); - - IDirectMusicPort_Release(port); - destroy_performance(perf, NULL, NULL); -} - -static void test_COM(void) -{ - IDirectMusicPerformance *dmp = (IDirectMusicPerformance*)0xdeadbeef; - IDirectMusicPerformance *dmp2; - IDirectMusicPerformance8 *dmp8; - ULONG refcount; - HRESULT hr; - - /* COM aggregation */ - hr = CoCreateInstance(&CLSID_DirectMusicPerformance, (IUnknown *)0xdeadbeef, CLSCTX_INPROC_SERVER, - &IID_IUnknown, (void**)&dmp); - ok(hr == CLASS_E_NOAGGREGATION, - "DirectMusicPerformance create failed: %#lx, expected CLASS_E_NOAGGREGATION\n", hr); - ok(!dmp, "dmp = %p\n", dmp); - - /* Invalid RIID */ - hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectMusicObject, (void**)&dmp); - ok(hr == E_NOINTERFACE, "DirectMusicPerformance create failed: %#lx, expected E_NOINTERFACE\n", hr); - - /* Same refcount */ - hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectMusicPerformance, (void**)&dmp); - ok(hr == S_OK, "DirectMusicPerformance create failed: %#lx, expected S_OK\n", hr); - refcount = IDirectMusicPerformance_AddRef(dmp); - ok (refcount == 2, "refcount == %lu, expected 2\n", refcount); - hr = IDirectMusicPerformance_QueryInterface(dmp, &IID_IDirectMusicPerformance2, (void**)&dmp2); - ok(hr == S_OK, "QueryInterface for IID_IDirectMusicPerformance2 failed: %#lx\n", hr); - IDirectMusicPerformance_AddRef(dmp); - refcount = IDirectMusicPerformance_Release(dmp); - ok (refcount == 3, "refcount == %lu, expected 3\n", refcount); - hr = IDirectMusicPerformance_QueryInterface(dmp, &IID_IDirectMusicPerformance8, (void**)&dmp8); - ok(hr == S_OK, "QueryInterface for IID_IDirectMusicPerformance8 failed: %#lx\n", hr); - refcount = IDirectMusicPerformance_Release(dmp); - ok (refcount == 3, "refcount == %lu, expected 3\n", refcount); - refcount = IDirectMusicPerformance8_Release(dmp8); - ok (refcount == 2, "refcount == %lu, expected 2\n", refcount); - refcount = IDirectMusicPerformance_Release(dmp2); - ok (refcount == 1, "refcount == %lu, expected 1\n", refcount); - refcount = IDirectMusicPerformance_Release(dmp); - ok (refcount == 0, "refcount == %lu, expected 0\n", refcount); -} - -START_TEST( performance ) -{ - HRESULT hr; - - hr = CoInitialize(NULL); - if (FAILED(hr)) { - skip("Cannot initialize COM (%lx)\n", hr); - return; - } - - hr = test_InitAudio(); - if (hr != S_OK) { - skip("InitAudio failed (%lx)\n", hr); - return; - } - - test_COM(); - test_createport(); - test_pchannel(); - - CoUninitialize(); -} From 716f939bb466c2c817801c449c0011cc6bf5447f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 28 Sep 2023 08:26:45 +0200 Subject: [PATCH 2573/2777] dmime/tests: Test performance Init with a created port. Final Fantasy VIII does this, more or less, and needs Init to succeed. (cherry picked from commit 3400e41d5cca6a2eb869fad7cf2fc68680a1b11a) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 12056f15376..f016af2f9e6 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -1895,6 +1895,12 @@ static void test_parsedescriptor(void) static void test_performance_InitAudio(void) { + DMUS_PORTPARAMS params = + { + .dwSize = sizeof(params), + .dwValidParams = DMUS_PORTPARAMS_EFFECTS, + .dwEffectFlags = 1, + }; IDirectMusicPerformance8 *performance; IDirectMusic *dmusic; IDirectSound *dsound; @@ -2036,6 +2042,20 @@ static void test_performance_InitAudio(void) ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref); destroy_performance(performance, dmusic, dsound); + /* Provided dmusic and dsound, dmusic initialized with SetDirectSound, port created and activated */ + create_performance(&performance, &dmusic, &dsound, TRUE); + hr = IDirectMusic_SetDirectSound(dmusic, dsound, NULL); + ok(hr == S_OK, "SetDirectSound failed: %#lx\n", hr); + hr = IDirectMusic_CreatePort(dmusic, &CLSID_DirectMusicSynth, ¶ms, &port, NULL); + ok(hr == S_OK, "CreatePort failed: %#lx\n", hr); + hr = IDirectMusicPort_Activate(port, TRUE); + ok(hr == S_OK, "Activate failed: %#lx\n", hr); + hr = IDirectMusicPort_SetNumChannelGroups(port, 1); + ok(hr == S_OK, "SetNumChannelGroups failed: %#lx\n", hr); + hr = IDirectMusicPerformance8_Init(performance, &dmusic, dsound, 0); + todo_wine ok(hr == S_OK, "Init failed: %#lx\n", hr); + destroy_performance(performance, dmusic, dsound); + /* InitAudio with perf channel count not a multiple of 16 rounds up */ create_performance(&performance, NULL, NULL, TRUE); hr = IDirectMusicPerformance8_InitAudio(performance, NULL, NULL, NULL, From 82f2221efc23f3e76a297028683d96a362a4c8ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Sep 2023 19:10:17 +0200 Subject: [PATCH 2574/2777] dmime: Set the port direct sound before activating it. (cherry picked from commit 50b09dcf11b2939a5702104b6726d10ad44df43b) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index d8624427423..e2d070b0fbe 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -651,10 +651,14 @@ static HRESULT perf_dmport_create(struct performance *perf, DMUS_PORTPARAMS *par if (FAILED(hr = IDirectMusic8_CreatePort(perf->dmusic, &guid, params, &port, NULL))) return hr; - if (FAILED(hr = IDirectMusicPort_Activate(port, TRUE))) { + + if (FAILED(hr = IDirectMusicPort_SetDirectSound(port, perf->dsound, NULL)) + || FAILED(hr = IDirectMusicPort_Activate(port, TRUE))) + { IDirectMusicPort_Release(port); return hr; } + for (i = 0; i < params->dwChannelGroups; i++) pchannel_block_set(&perf->pchannels, i, port, i + 1, FALSE); From 46ed61299ed21c00894d524e1e4b3a791ee7248a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Sep 2023 18:49:40 +0200 Subject: [PATCH 2575/2777] dmime: Initialize performance in Init rather than InitAudio. (cherry picked from commit 9788fb6911ab56186c95edd6fe487f48ab98e118) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 148 ++++++++++++++++++++------------------- dlls/dmime/tests/dmime.c | 6 +- 2 files changed, 79 insertions(+), 75 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index e2d070b0fbe..a8c2016802c 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -40,10 +40,9 @@ struct performance IDirectMusicGraph IDirectMusicGraph_iface; IDirectMusicTool IDirectMusicTool_iface; LONG ref; - IDirectMusic8 *dmusic; + IDirectMusic *dmusic; IDirectSound *dsound; IDirectMusicGraph *pToolGraph; - DMUS_AUDIOPARAMS params; BOOL fAutoDownload; char cMasterGrooveLevel; float fMasterTempo; @@ -314,14 +313,74 @@ static ULONG WINAPI performance_Release(IDirectMusicPerformance8 *iface) return ref; } -/* IDirectMusicPerformanceImpl IDirectMusicPerformance Interface part: */ +static HRESULT performance_init_dsound(struct performance *This, HWND hwnd) +{ + IDirectSound *dsound; + HRESULT hr; + + if (FAILED(hr = DirectSoundCreate(NULL, &dsound, NULL))) return hr; + + if (!hwnd) hwnd = GetForegroundWindow(); + hr = IDirectSound_SetCooperativeLevel(dsound, hwnd, DSSCL_PRIORITY); + + if (SUCCEEDED(hr)) This->dsound = dsound; + else IDirectSound_Release(dsound); + + return hr; +} + +static HRESULT performance_init_dmusic(struct performance *This, IDirectSound *dsound) +{ + IDirectMusic *dmusic; + HRESULT hr; + + if (FAILED(hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusic8, (void **)&dmusic))) + return hr; + + hr = IDirectMusic_SetDirectSound(dmusic, dsound, NULL); + + if (SUCCEEDED(hr)) This->dmusic = dmusic; + else IDirectSound_Release(dmusic); + + return hr; +} + static HRESULT WINAPI performance_Init(IDirectMusicPerformance8 *iface, IDirectMusic **dmusic, IDirectSound *dsound, HWND hwnd) { + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + HRESULT hr; + TRACE("(%p, %p, %p, %p)\n", iface, dmusic, dsound, hwnd); - return IDirectMusicPerformance8_InitAudio(iface, dmusic, dsound ? &dsound : NULL, hwnd, 0, 0, - 0, NULL); + if (This->dmusic) return DMUS_E_ALREADY_INITED; + + if ((This->dsound = dsound)) IDirectMusic8_AddRef(This->dsound); + else if (FAILED(hr = performance_init_dsound(This, hwnd))) return hr; + + if (dmusic && (This->dmusic = *dmusic)) IDirectMusic_AddRef(This->dmusic); + else if (FAILED(hr = performance_init_dmusic(This, This->dsound))) + { + IDirectMusicPerformance_CloseDown(iface); + return hr; + } + + if (FAILED(hr = IDirectMusic_GetMasterClock(This->dmusic, NULL, &This->master_clock)) + || FAILED(hr = IDirectMusicPerformance8_GetTime(iface, &This->init_time, NULL))) + { + IDirectMusicPerformance_CloseDown(iface); + return hr; + } + + PostMessageToProcessMsgThread(This, PROCESSMSG_START); + + if (dmusic && !*dmusic) + { + *dmusic = This->dmusic; + IDirectMusic_AddRef(*dmusic); + } + return S_OK; } static HRESULT WINAPI performance_PlaySegment(IDirectMusicPerformance8 *iface, IDirectMusicSegment *pSegment, @@ -900,6 +959,7 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) IDirectMusic8_Release(This->dmusic); This->dmusic = NULL; } + return S_OK; } @@ -960,57 +1020,21 @@ static HRESULT WINAPI performance_InitAudio(IDirectMusicPerformance8 *iface, IDi TRACE("(%p, %p, %p, %p, %lx, %lu, %lx, %p)\n", This, dmusic, dsound, hwnd, default_path_type, num_channels, flags, params); - if (This->dmusic) - return DMUS_E_ALREADY_INITED; - - if (!dmusic || !*dmusic) { - hr = CoCreateInstance(&CLSID_DirectMusic, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectMusic8, - (void **)&This->dmusic); - if (FAILED(hr)) - return hr; - } else { - This->dmusic = (IDirectMusic8 *)*dmusic; - IDirectMusic8_AddRef(This->dmusic); - } - - if (FAILED(hr = IDirectMusic_GetMasterClock(This->dmusic, NULL, &This->master_clock))) - goto error; + if (flags) FIXME("flags parameter not used\n"); + if (params) FIXME("params parameter not used\n"); - if (!dsound || !*dsound) { - hr = DirectSoundCreate8(NULL, (IDirectSound8 **)&This->dsound, NULL); - if (FAILED(hr)) - goto error; - hr = IDirectSound_SetCooperativeLevel(This->dsound, hwnd ? hwnd : GetForegroundWindow(), - DSSCL_PRIORITY); - if (FAILED(hr)) - goto error; - } else { - This->dsound = *dsound; - IDirectSound_AddRef(This->dsound); - } + if (FAILED(hr = IDirectMusicPerformance8_Init(iface, dmusic && *dmusic ? dmusic : NULL, + dsound ? *dsound : NULL, hwnd))) + return hr; - hr = IDirectMusic8_SetDirectSound(This->dmusic, This->dsound, NULL); - if (FAILED(hr)) - goto error; - - if (!params) { - This->params.dwSize = sizeof(DMUS_AUDIOPARAMS); - This->params.fInitNow = FALSE; - This->params.dwValidData = DMUS_AUDIOPARAMS_FEATURES | DMUS_AUDIOPARAMS_VOICES | - DMUS_AUDIOPARAMS_SAMPLERATE | DMUS_AUDIOPARAMS_DEFAULTSYNTH; - This->params.dwVoices = 64; - This->params.dwSampleRate = 22050; - This->params.dwFeatures = flags; - This->params.clsidDefaultSynth = CLSID_DirectMusicSynthSink; - } else - This->params = *params; - - if (default_path_type) { + if (default_path_type) + { hr = IDirectMusicPerformance8_CreateStandardAudioPath(iface, default_path_type, num_channels, FALSE, &This->pDefaultPath); - if (FAILED(hr)) { - IDirectMusic8_SetDirectSound(This->dmusic, NULL, NULL); - goto error; + if (FAILED(hr)) + { + IDirectMusicPerformance_CloseDown(iface); + return hr; } } @@ -1023,27 +1047,7 @@ static HRESULT WINAPI performance_InitAudio(IDirectMusicPerformance8 *iface, IDi IDirectMusic_AddRef(*dmusic); } - if (FAILED(hr = IDirectMusicPerformance8_GetTime(iface, &This->init_time, NULL))) return hr; - - PostMessageToProcessMsgThread(This, PROCESSMSG_START); - return S_OK; - -error: - if (This->master_clock) - { - IReferenceClock_Release(This->master_clock); - This->master_clock = NULL; - } - if (This->dsound) { - IDirectSound_Release(This->dsound); - This->dsound = NULL; - } - if (This->dmusic) { - IDirectMusic8_Release(This->dmusic); - This->dmusic = NULL; - } - return hr; } static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, IUnknown *pSource, diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index f016af2f9e6..c1043fe90f3 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -2009,7 +2009,7 @@ static void test_performance_InitAudio(void) hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, &dsound, NULL, 0, 64, 0, NULL); ok(hr == S_OK, "InitAudio failed: %#lx\n", hr); ref = get_refcount(dsound); - todo_wine ok(ref == 2, "dsound ref count got %ld expected 2\n", ref); + ok(ref == 2, "dsound ref count got %ld expected 2\n", ref); ref = get_refcount(dmusic); ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref); destroy_performance(performance, dmusic, dsound); @@ -2023,7 +2023,7 @@ static void test_performance_InitAudio(void) hr = IDirectMusicPerformance8_InitAudio(performance, &dmusic, NULL, NULL, 0, 64, 0, NULL); ok(hr == S_OK, "InitAudio failed: %#lx\n", hr); ref = get_refcount(dsound); - todo_wine ok(ref == 2, "dsound ref count got %ld expected 2\n", ref); + ok(ref == 2, "dsound ref count got %ld expected 2\n", ref); ref = get_refcount(dmusic); ok(ref == 2, "dmusic ref count got %ld expected 2\n", ref); destroy_performance(performance, dmusic, dsound); @@ -2053,7 +2053,7 @@ static void test_performance_InitAudio(void) hr = IDirectMusicPort_SetNumChannelGroups(port, 1); ok(hr == S_OK, "SetNumChannelGroups failed: %#lx\n", hr); hr = IDirectMusicPerformance8_Init(performance, &dmusic, dsound, 0); - todo_wine ok(hr == S_OK, "Init failed: %#lx\n", hr); + ok(hr == S_OK, "Init failed: %#lx\n", hr); destroy_performance(performance, dmusic, dsound); /* InitAudio with perf channel count not a multiple of 16 rounds up */ From 0ac7c6c0ba62bf7f9a6b9c75179df88c3ffe12ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Sep 2023 18:49:40 +0200 Subject: [PATCH 2576/2777] dmime: Return DMUS_E_AUDIOPATHS_IN_USE when audio paths are in use. (cherry picked from commit 0fb4e5ec479bc7424c3818d51884387b15e90e52) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 28 ++++++++++++++++------------ dlls/dmime/tests/dmime.c | 4 ++-- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index a8c2016802c..7b606998616 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -50,6 +50,7 @@ struct performance /* performance channels */ struct wine_rb_tree pchannels; + BOOL audio_paths_enabled; IDirectMusicAudioPath *pDefaultPath; HANDLE hNotification; REFERENCE_TIME rtMinimum; @@ -730,8 +731,8 @@ static HRESULT WINAPI performance_AddPort(IDirectMusicPerformance8 *iface, IDire FIXME("(%p, %p): semi-stub\n", This, port); - if (!This->dmusic) - return DMUS_E_NOT_INIT; + if (!This->dmusic) return DMUS_E_NOT_INIT; + if (This->audio_paths_enabled) return DMUS_E_AUDIOPATHS_IN_USE; if (!port) { DMUS_PORTPARAMS params = { @@ -753,11 +754,13 @@ static HRESULT WINAPI performance_AddPort(IDirectMusicPerformance8 *iface, IDire static HRESULT WINAPI performance_RemovePort(IDirectMusicPerformance8 *iface, IDirectMusicPort *pPort) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); - FIXME("(%p, %p): stub\n", This, pPort); - IDirectMusicPort_Release (pPort); - return S_OK; + if (This->audio_paths_enabled) return DMUS_E_AUDIOPATHS_IN_USE; + + FIXME("(%p, %p): stub\n", This, pPort); + IDirectMusicPort_Release(pPort); + return S_OK; } static HRESULT WINAPI performance_AssignPChannelBlock(IDirectMusicPerformance8 *iface, @@ -767,10 +770,9 @@ static HRESULT WINAPI performance_AssignPChannelBlock(IDirectMusicPerformance8 * FIXME("(%p, %ld, %p, %ld): semi-stub\n", This, block_num, port, group); - if (!port) - return E_POINTER; - if (block_num > MAXDWORD / 16) - return E_INVALIDARG; + if (!port) return E_POINTER; + if (block_num > MAXDWORD / 16) return E_INVALIDARG; + if (This->audio_paths_enabled) return DMUS_E_AUDIOPATHS_IN_USE; pchannel_block_set(&This->pchannels, block_num, port, group, FALSE); @@ -785,8 +787,8 @@ static HRESULT WINAPI performance_AssignPChannel(IDirectMusicPerformance8 *iface FIXME("(%p)->(%ld, %p, %ld, %ld) semi-stub\n", This, pchannel, port, group, channel); - if (!port) - return E_POINTER; + if (!port) return E_POINTER; + if (This->audio_paths_enabled) return DMUS_E_AUDIOPATHS_IN_USE; block = pchannel_block_set(&This->pchannels, pchannel / 16, port, 0, TRUE); if (block) { @@ -959,6 +961,7 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) IDirectMusic8_Release(This->dmusic); This->dmusic = NULL; } + This->audio_paths_enabled = FALSE; return S_OK; } @@ -1027,6 +1030,7 @@ static HRESULT WINAPI performance_InitAudio(IDirectMusicPerformance8 *iface, IDi dsound ? *dsound : NULL, hwnd))) return hr; + This->audio_paths_enabled = TRUE; if (default_path_type) { hr = IDirectMusicPerformance8_CreateStandardAudioPath(iface, default_path_type, diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index c1043fe90f3..119bfc74fc5 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -1937,9 +1937,9 @@ static void test_performance_InitAudio(void) ok(hr == S_OK, "PChannelInfo failed, got %#lx\n", hr); ok(port != NULL, "IDirectMusicPort not set\n"); hr = IDirectMusicPerformance8_AssignPChannel(performance, 0, port, 0, 0); - todo_wine ok(hr == DMUS_E_AUDIOPATHS_IN_USE, "AssignPChannel failed (%#lx)\n", hr); + ok(hr == DMUS_E_AUDIOPATHS_IN_USE, "AssignPChannel failed (%#lx)\n", hr); hr = IDirectMusicPerformance8_AssignPChannelBlock(performance, 0, port, 0); - todo_wine ok(hr == DMUS_E_AUDIOPATHS_IN_USE, "AssignPChannelBlock failed (%#lx)\n", hr); + ok(hr == DMUS_E_AUDIOPATHS_IN_USE, "AssignPChannelBlock failed (%#lx)\n", hr); IDirectMusicPort_Release(port); hr = IDirectMusicPerformance8_GetDefaultAudioPath(performance, &path); From 27ea1ff2a01ad1ece1857ef3f193b5beb07cc297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Sep 2023 19:08:34 +0200 Subject: [PATCH 2577/2777] dmime: Return DMUS_E_AUDIOPATH_INACTIVE when audio paths are not enabled. (cherry picked from commit 9e0487c4cc36cdbf915d35222c875d23f54958ae) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 102 ++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 55 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 7b606998616..bdb7475370a 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1096,45 +1096,41 @@ static HRESULT WINAPI performance_ClonePMsg(IDirectMusicPerformance8 *iface, DMU } static HRESULT WINAPI performance_CreateAudioPath(IDirectMusicPerformance8 *iface, - IUnknown *pSourceConfig, BOOL fActivate, IDirectMusicAudioPath **ppNewPath) + IUnknown *pSourceConfig, BOOL fActivate, IDirectMusicAudioPath **ret_iface) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); - IDirectMusicAudioPath *pPath; + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + IDirectMusicAudioPath *pPath; - FIXME("(%p, %p, %d, %p): stub\n", This, pSourceConfig, fActivate, ppNewPath); + FIXME("(%p, %p, %d, %p): stub\n", This, pSourceConfig, fActivate, ret_iface); - if (NULL == ppNewPath) { - return E_POINTER; - } + if (!ret_iface) return E_POINTER; + if (!This->audio_paths_enabled) return DMUS_E_AUDIOPATH_INACTIVE; - create_dmaudiopath(&IID_IDirectMusicAudioPath, (void**)&pPath); - set_audiopath_perf_pointer(pPath, iface); + create_dmaudiopath(&IID_IDirectMusicAudioPath, (void **)&pPath); + set_audiopath_perf_pointer(pPath, iface); - /** TODO */ - - *ppNewPath = pPath; - - return IDirectMusicAudioPath_Activate(*ppNewPath, fActivate); + /** TODO */ + *ret_iface = pPath; + return IDirectMusicAudioPath_Activate(*ret_iface, fActivate); } static HRESULT WINAPI performance_CreateStandardAudioPath(IDirectMusicPerformance8 *iface, - DWORD dwType, DWORD pchannel_count, BOOL fActivate, IDirectMusicAudioPath **ppNewPath) + DWORD dwType, DWORD pchannel_count, BOOL fActivate, IDirectMusicAudioPath **ret_iface) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); - IDirectMusicAudioPath *pPath; - DSBUFFERDESC desc; - WAVEFORMATEX format; - DMUS_PORTPARAMS params = {0}; - IDirectSoundBuffer *buffer, *primary_buffer; - HRESULT hr = S_OK; + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + IDirectMusicAudioPath *pPath; + DSBUFFERDESC desc; + WAVEFORMATEX format; + DMUS_PORTPARAMS params = {0}; + IDirectSoundBuffer *buffer, *primary_buffer; + HRESULT hr = S_OK; - FIXME("(%p)->(%ld, %ld, %d, %p): semi-stub\n", This, dwType, pchannel_count, fActivate, ppNewPath); + FIXME("(%p)->(%ld, %ld, %d, %p): semi-stub\n", This, dwType, pchannel_count, fActivate, ret_iface); - if (NULL == ppNewPath) { - return E_POINTER; - } + if (!ret_iface) return E_POINTER; + if (!This->audio_paths_enabled) return DMUS_E_AUDIOPATH_INACTIVE; - *ppNewPath = NULL; + *ret_iface = NULL; /* Secondary buffer description */ memset(&format, 0, sizeof(format)); @@ -1204,46 +1200,42 @@ static HRESULT WINAPI performance_CreateStandardAudioPath(IDirectMusicPerformanc set_audiopath_dsound_buffer(pPath, buffer); set_audiopath_primary_dsound_buffer(pPath, primary_buffer); - *ppNewPath = pPath; - - TRACE(" returning IDirectMusicAudioPath interface at %p.\n", *ppNewPath); - - return IDirectMusicAudioPath_Activate(*ppNewPath, fActivate); + *ret_iface = pPath; + TRACE(" returning IDirectMusicAudioPath interface at %p.\n", *ret_iface); + return IDirectMusicAudioPath_Activate(*ret_iface, fActivate); } -static HRESULT WINAPI performance_SetDefaultAudioPath(IDirectMusicPerformance8 *iface, IDirectMusicAudioPath *pAudioPath) +static HRESULT WINAPI performance_SetDefaultAudioPath(IDirectMusicPerformance8 *iface, IDirectMusicAudioPath *audio_path) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); - FIXME("(%p, %p): semi-stub\n", This, pAudioPath); + FIXME("(%p, %p): semi-stub\n", This, audio_path); - if (This->pDefaultPath) { - IDirectMusicAudioPath_Release(This->pDefaultPath); - This->pDefaultPath = NULL; - } - This->pDefaultPath = pAudioPath; - if (This->pDefaultPath) { - IDirectMusicAudioPath_AddRef(This->pDefaultPath); - set_audiopath_perf_pointer(This->pDefaultPath, iface); - } + if (!This->audio_paths_enabled) return DMUS_E_AUDIOPATH_INACTIVE; - return S_OK; + if (This->pDefaultPath) IDirectMusicAudioPath_Release(This->pDefaultPath); + if ((This->pDefaultPath = audio_path)) + { + IDirectMusicAudioPath_AddRef(This->pDefaultPath); + set_audiopath_perf_pointer(This->pDefaultPath, iface); + } + + return S_OK; } static HRESULT WINAPI performance_GetDefaultAudioPath(IDirectMusicPerformance8 *iface, - IDirectMusicAudioPath **ppAudioPath) + IDirectMusicAudioPath **ret_iface) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); - FIXME("(%p, %p): semi-stub (%p)\n", This, ppAudioPath, This->pDefaultPath); + FIXME("(%p, %p): semi-stub (%p)\n", This, ret_iface, This->pDefaultPath); - if (NULL != This->pDefaultPath) { - *ppAudioPath = This->pDefaultPath; - IDirectMusicAudioPath_AddRef(*ppAudioPath); - } else { - *ppAudioPath = NULL; - } - return S_OK; + if (!ret_iface) return E_POINTER; + if (!This->audio_paths_enabled) return DMUS_E_AUDIOPATH_INACTIVE; + + if ((*ret_iface = This->pDefaultPath)) IDirectMusicAudioPath_AddRef(*ret_iface); + + return S_OK; } static HRESULT WINAPI performance_GetParamEx(IDirectMusicPerformance8 *iface, REFGUID rguidType, DWORD dwTrackID, From 198f5b7c6a64354917412b283f0b569bb5c84568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 21 Sep 2023 08:03:31 +0200 Subject: [PATCH 2578/2777] dmloader: Use a simpler file stream implementation. (cherry picked from commit 1ffc47b5e69b6377244c7df51e3de9a6d02082e9) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmloader/dmloader_private.h | 18 +- dlls/dmloader/loader.c | 105 ++++------ dlls/dmloader/loaderstream.c | 335 ++++++++++++++----------------- 3 files changed, 189 insertions(+), 269 deletions(-) diff --git a/dlls/dmloader/dmloader_private.h b/dlls/dmloader/dmloader_private.h index 87fcf087bc0..c590040389b 100644 --- a/dlls/dmloader/dmloader_private.h +++ b/dlls/dmloader/dmloader_private.h @@ -59,25 +59,8 @@ typedef struct IDirectMusicLoaderGenericStream IDirectMusicLoaderGenericStream; */ extern HRESULT create_dmloader(REFIID riid, void **ret_iface); extern HRESULT create_dmcontainer(REFIID riid, void **ret_iface); -extern HRESULT DMUSIC_CreateDirectMusicLoaderFileStream(void **ppobj); extern HRESULT DMUSIC_CreateDirectMusicLoaderResourceStream(void **ppobj); -/***************************************************************************** - * IDirectMusicLoaderFileStream implementation structure - */ -struct IDirectMusicLoaderFileStream { - /* VTABLEs */ - const IStreamVtbl *StreamVtbl; - /* reference counter */ - LONG dwRef; - /* file */ - WCHAR wzFileName[MAX_PATH]; /* for clone */ - HANDLE hFile; -}; - -/* Custom: */ -extern HRESULT WINAPI IDirectMusicLoaderFileStream_Attach(LPSTREAM iface, LPCWSTR wzFile); - /***************************************************************************** * IDirectMusicLoaderResourceStream implementation structure */ @@ -98,6 +81,7 @@ extern HRESULT WINAPI IDirectMusicLoaderResourceStream_Attach(LPSTREAM iface, LP LONGLONG llMemLength, LONGLONG llPos); extern HRESULT loader_stream_create(IDirectMusicLoader *loader, IStream *stream, IStream **ret_iface); +extern HRESULT file_stream_create(const WCHAR *path, IStream **ret_iface); #include "debug.h" diff --git a/dlls/dmloader/loader.c b/dlls/dmloader/loader.c index ef1a8c3dfe0..9c97f47e5f7 100644 --- a/dlls/dmloader/loader.c +++ b/dlls/dmloader/loader.c @@ -305,40 +305,29 @@ static HRESULT WINAPI loader_GetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE TRACE(": no cache/alias entry found for requested object\n"); } - if (pDesc->dwValidData & DMUS_OBJ_URL) { - TRACE(": loading from URLs not supported yet\n"); - return DMUS_E_LOADER_FORMATNOTSUPPORTED; - } - else if (pDesc->dwValidData & DMUS_OBJ_FILENAME) { - /* load object from file */ - /* generate filename; if it's full path, don't add search - directory path, otherwise do */ - WCHAR wszFileName[MAX_PATH]; - - if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) { - lstrcpyW(wszFileName, pDesc->wszFileName); - } else { - WCHAR *p; - get_search_path(This, &pDesc->guidClass, wszFileName); - p = wszFileName + lstrlenW(wszFileName); - if (p > wszFileName && p[-1] != '\\') *p++ = '\\'; - lstrcpyW(p, pDesc->wszFileName); - } - TRACE(": loading from file (%s)\n", debugstr_w(wszFileName)); - /* create stream and associate it with file */ - result = DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pStream); - if (FAILED(result)) { - ERR(": could not create file stream\n"); - return result; - } - result = IDirectMusicLoaderFileStream_Attach(pStream, wszFileName); - if (FAILED(result)) - { - ERR(": could not attach stream to file\n"); - IStream_Release (pStream); - return result; - } - } + if (pDesc->dwValidData & DMUS_OBJ_URL) + { + TRACE(": loading from URLs not supported yet\n"); + return DMUS_E_LOADER_FORMATNOTSUPPORTED; + } + else if (pDesc->dwValidData & DMUS_OBJ_FILENAME) + { + WCHAR file_name[MAX_PATH]; + + if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) + lstrcpyW(file_name, pDesc->wszFileName); + else + { + WCHAR *p; + get_search_path(This, &pDesc->guidClass, file_name); + p = file_name + lstrlenW(file_name); + if (p > file_name && p[-1] != '\\') *p++ = '\\'; + lstrcpyW(p, pDesc->wszFileName); + } + + TRACE(": loading from file (%s)\n", debugstr_w(file_name)); + if (FAILED(hr = file_stream_create(file_name, &pStream))) return hr; + } else if (pDesc->dwValidData & DMUS_OBJ_MEMORY) { /* load object from resource */ TRACE(": loading from resource\n"); @@ -363,9 +352,8 @@ static HRESULT WINAPI loader_GetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE } else { - /* nowhere to load from */ FIXME(": unknown/unsupported way of loading\n"); - return DMUS_E_LOADER_NOFILENAME; /* test shows this is returned */ + return DMUS_E_LOADER_NOFILENAME; } if (FAILED(hr = loader_stream_create((IDirectMusicLoader *)iface, pStream, &loader_stream))) @@ -459,36 +447,23 @@ static HRESULT WINAPI loader_SetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE if (TRACE_ON(dmloader)) dump_DMUS_OBJECTDESC(pDesc); - /* create stream and load additional info from it */ - if (pDesc->dwValidData & DMUS_OBJ_FILENAME) { - /* generate filename; if it's full path, don't add search - directory path, otherwise do */ - WCHAR wszFileName[MAX_PATH]; + if (pDesc->dwValidData & DMUS_OBJ_FILENAME) + { + WCHAR file_name[MAX_PATH]; - if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) { - lstrcpyW(wszFileName, pDesc->wszFileName); - } else { - WCHAR *p; - get_search_path(This, &pDesc->guidClass, wszFileName); - p = wszFileName + lstrlenW(wszFileName); - if (p > wszFileName && p[-1] != '\\') *p++ = '\\'; - lstrcpyW(p, pDesc->wszFileName); - } - /* create stream */ - hr = DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pStream); - if (FAILED(hr)) { - ERR(": could not create file stream\n"); - return DMUS_E_LOADER_FAILEDOPEN; - } - /* attach stream */ - hr = IDirectMusicLoaderFileStream_Attach(pStream, wszFileName); - if (FAILED(hr)) - { - ERR(": could not attach stream to file %s, make sure it exists\n", debugstr_w(wszFileName)); - IStream_Release (pStream); - return DMUS_E_LOADER_FAILEDOPEN; - } - } + if (pDesc->dwValidData & DMUS_OBJ_FULLPATH) + lstrcpyW(file_name, pDesc->wszFileName); + else + { + WCHAR *p; + get_search_path(This, &pDesc->guidClass, file_name); + p = file_name + lstrlenW(file_name); + if (p > file_name && p[-1] != '\\') *p++ = '\\'; + lstrcpyW(p, pDesc->wszFileName); + } + + if (FAILED(hr = file_stream_create(file_name, &pStream))) return hr; + } else if (pDesc->dwValidData & DMUS_OBJ_STREAM) { pStream = pDesc->pStream; diff --git a/dlls/dmloader/loaderstream.c b/dlls/dmloader/loaderstream.c index 5b7862c16f8..80e9f91e77a 100644 --- a/dlls/dmloader/loaderstream.c +++ b/dlls/dmloader/loaderstream.c @@ -1,8 +1,6 @@ -/* IDirectMusicLoaderFileStream - * IDirectMusicLoaderResourceStream - * IDirectMusicLoaderGenericStream - * +/* * Copyright (C) 2003-2004 Rok Mandeljc + * Copyright 2023 Rémi Bernon for CodeWeavers * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,31 +17,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ - -/* SIDE NOTES: - * After extensive testing and structure dumping I came to a conclusion that - * DirectMusic as in present state implements three types of streams: - * 1. IDirectMusicLoaderFileStream: stream that was most obvious, since - * it's used for loading from files; it is sort of wrapper around - * CreateFile, ReadFile, WriteFile and SetFilePointer and it supports - * both read and write - * 2. IDirectMusicLoaderResourceStream: a stream that had to exist, since - * according to MSDN, IDirectMusicLoader supports loading from resource - * as well; in this case, data is represented as a big chunk of bytes, - * from which we "read" (copy) data and keep the trace of our position; - * it supports read only - * 3. IDirectMusicLoaderGenericStream: this one was the most problematic, - * since I thought it was URL-related; besides, there's no obvious need - * for it, since input streams can simply be cloned, lest loading from - * stream is requested; but if one really thinks about it, input stream - * could be none of 1. or 2.; in this case, a wrapper that offers - * IDirectMusicGetLoader interface would be nice, and this is what this - * stream is; as such, all functions are supported, as long as underlying - * ("low-level") stream supports them - * - * - Rok Mandeljc; 24. April, 2004 -*/ - #include "dmloader_private.h" WINE_DEFAULT_DEBUG_CHANNEL(dmloader); @@ -284,216 +257,204 @@ HRESULT loader_stream_create(IDirectMusicLoader *loader, IStream *stream, return S_OK; } -static ULONG WINAPI IDirectMusicLoaderFileStream_IStream_AddRef (LPSTREAM iface); -static ULONG WINAPI IDirectMusicLoaderResourceStream_IStream_AddRef (LPSTREAM iface); - +struct file_stream +{ + IStream IStream_iface; + LONG ref; -/***************************************************************************** - * IDirectMusicLoaderFileStream implementation - */ -/* Custom : */ + WCHAR path[MAX_PATH]; + HANDLE file; +}; -static void IDirectMusicLoaderFileStream_Detach (LPSTREAM iface) { - ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); - TRACE("(%p)\n", This); - if (This->hFile != INVALID_HANDLE_VALUE) CloseHandle(This->hFile); - This->wzFileName[0] = '\0'; +static struct file_stream *file_stream_from_IStream(IStream *iface) +{ + return CONTAINING_RECORD(iface, struct file_stream, IStream_iface); } -HRESULT WINAPI IDirectMusicLoaderFileStream_Attach(LPSTREAM iface, LPCWSTR wzFile) +static HRESULT WINAPI file_stream_QueryInterface(IStream *iface, REFIID riid, void **ret_iface) { - ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); - TRACE("(%p, %s)\n", This, debugstr_w(wzFile)); - IDirectMusicLoaderFileStream_Detach (iface); - This->hFile = CreateFileW (wzFile, (GENERIC_READ | GENERIC_WRITE), (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (This->hFile == INVALID_HANDLE_VALUE) { - WARN(": failed\n"); - return DMUS_E_LOADER_FAILEDOPEN; - } - /* create IDirectMusicGetLoader */ - lstrcpynW (This->wzFileName, wzFile, MAX_PATH); - TRACE(": succeeded\n"); - return S_OK; -} + struct file_stream *This = file_stream_from_IStream(iface); + TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface); -/* IUnknown/IStream part: */ -static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_QueryInterface (LPSTREAM iface, REFIID riid, void** ppobj) { - ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); - - TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj); - if (IsEqualIID (riid, &IID_IUnknown) || - IsEqualIID (riid, &IID_IStream)) { - *ppobj = &This->StreamVtbl; - IDirectMusicLoaderFileStream_IStream_AddRef ((LPSTREAM)&This->StreamVtbl); - return S_OK; - } + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IStream)) + { + IStream_AddRef(&This->IStream_iface); + *ret_iface = &This->IStream_iface; + return S_OK; + } - WARN(": not found\n"); - return E_NOINTERFACE; + WARN("(%p, %s, %p): not found\n", iface, debugstr_dmguid(riid), ret_iface); + *ret_iface = NULL; + return E_NOINTERFACE; } -static ULONG WINAPI IDirectMusicLoaderFileStream_IStream_AddRef (LPSTREAM iface) { - ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); - TRACE("(%p): AddRef from %ld\n", This, This->dwRef); - return InterlockedIncrement (&This->dwRef); +static ULONG WINAPI file_stream_AddRef(IStream *iface) +{ + struct file_stream *This = file_stream_from_IStream(iface); + ULONG ref = InterlockedIncrement(&This->ref); + TRACE("(%p): new ref = %lu\n", This, ref); + return ref; } -static ULONG WINAPI IDirectMusicLoaderFileStream_IStream_Release (LPSTREAM iface) { - ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); - - DWORD dwRef = InterlockedDecrement (&This->dwRef); - TRACE("(%p): ReleaseRef to %ld\n", This, dwRef); - if (dwRef == 0) { - if (This->hFile) - IDirectMusicLoaderFileStream_Detach (iface); - free(This); - } - - return dwRef; -} +static ULONG WINAPI file_stream_Release(IStream *iface) +{ + struct file_stream *This = file_stream_from_IStream(iface); + ULONG ref = InterlockedDecrement(&This->ref); -static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Read (LPSTREAM iface, void* pv, ULONG cb, ULONG* pcbRead) { - ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); - ULONG cbRead; - - TRACE_(dmfileraw)("(%p, %p, %#lx, %p)\n", This, pv, cb, pcbRead); - if (This->hFile == INVALID_HANDLE_VALUE) return E_FAIL; - if (pcbRead == NULL) pcbRead = &cbRead; - if (!ReadFile (This->hFile, pv, cb, pcbRead, NULL) || *pcbRead != cb) return E_FAIL; - - TRACE_(dmfileraw)(": data (size = %#lx): %s\n", *pcbRead, debugstr_an(pv, *pcbRead)); - return S_OK; + TRACE("(%p): new ref = %lu\n", This, ref); + + if (!ref) + { + CloseHandle(This->file); + free(This); + } + + return ref; } -static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Seek (LPSTREAM iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) { - ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); - LARGE_INTEGER liNewPos; - - TRACE_(dmfileraw)("(%p, %s, %s, %p)\n", This, wine_dbgstr_longlong(dlibMove.QuadPart), resolve_STREAM_SEEK(dwOrigin), plibNewPosition); +static HRESULT WINAPI file_stream_Read(IStream *iface, void *data, ULONG size, ULONG *ret_size) +{ + struct file_stream *This = file_stream_from_IStream(iface); + DWORD dummy; - if (This->hFile == INVALID_HANDLE_VALUE) return E_FAIL; + TRACE("(%p, %p, %#lx, %p)\n", This, data, size, ret_size); - liNewPos.HighPart = dlibMove.HighPart; - liNewPos.LowPart = SetFilePointer (This->hFile, dlibMove.LowPart, &liNewPos.HighPart, dwOrigin); + if (!ret_size) ret_size = &dummy; + if (!ReadFile(This->file, data, size, ret_size, NULL)) return HRESULT_FROM_WIN32(GetLastError()); + return *ret_size == size ? S_OK : S_FALSE; +} - if (liNewPos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) return E_FAIL; - if (plibNewPosition) plibNewPosition->QuadPart = liNewPos.QuadPart; - - return S_OK; +static HRESULT WINAPI file_stream_Write(IStream *iface, const void *data, ULONG size, ULONG *ret_size) +{ + struct file_stream *This = file_stream_from_IStream(iface); + FIXME("(%p): stub\n", This); + return E_NOTIMPL; } -static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Clone (LPSTREAM iface, IStream** ppstm) { - ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); - LPSTREAM pOther = NULL; - HRESULT result; +static HRESULT WINAPI file_stream_Seek(IStream *iface, LARGE_INTEGER offset, DWORD method, ULARGE_INTEGER *ret_offset) +{ + struct file_stream *This = file_stream_from_IStream(iface); + DWORD position; - TRACE("(%p, %p)\n", iface, ppstm); - result = DMUSIC_CreateDirectMusicLoaderFileStream ((LPVOID*)&pOther); - if (FAILED(result)) return result; - if (This->hFile != INVALID_HANDLE_VALUE) { - ULARGE_INTEGER ullCurrentPosition; - result = IDirectMusicLoaderFileStream_Attach(pOther, This->wzFileName); - if (SUCCEEDED(result)) - { - LARGE_INTEGER liZero; - liZero.QuadPart = 0; - result = IDirectMusicLoaderFileStream_IStream_Seek (iface, liZero, STREAM_SEEK_CUR, &ullCurrentPosition); /* get current position in current stream */ - } - if (SUCCEEDED(result)) { - LARGE_INTEGER liNewPosition; - liNewPosition.QuadPart = ullCurrentPosition.QuadPart; - result = IDirectMusicLoaderFileStream_IStream_Seek (pOther, liNewPosition, STREAM_SEEK_SET, &ullCurrentPosition); - } - if (FAILED(result)) { - TRACE(": failed\n"); - IDirectMusicLoaderFileStream_IStream_Release (pOther); - return result; - } - } - TRACE(": succeeded\n"); - *ppstm = pOther; - return S_OK; -} + TRACE("(%p, %I64d, %#lx, %p)\n", This, offset.QuadPart, method, ret_offset); -static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Write (LPSTREAM iface, const void* pv, ULONG cb, ULONG* pcbWritten) { - ICOM_THIS_MULTI(IDirectMusicLoaderFileStream, StreamVtbl, iface); - ULONG cbWrite; - - TRACE_(dmfileraw)("(%p, %p, %#lx, %p)\n", This, pv, cb, pcbWritten); - if (This->hFile == INVALID_HANDLE_VALUE) return E_FAIL; - if (pcbWritten == NULL) pcbWritten = &cbWrite; - if (!WriteFile (This->hFile, pv, cb, pcbWritten, NULL) || *pcbWritten != cb) return E_FAIL; - - TRACE_(dmfileraw)(": data (size = %#lx): %s\n", *pcbWritten, debugstr_an(pv, *pcbWritten)); + position = SetFilePointer(This->file, offset.u.LowPart, NULL, method); + if (position == INVALID_SET_FILE_POINTER) return HRESULT_FROM_WIN32(GetLastError()); + if (ret_offset) ret_offset->QuadPart = position; return S_OK; } -static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_SetSize (LPSTREAM iface, ULARGE_INTEGER libNewSize) { - ERR(": should not be needed\n"); +static HRESULT WINAPI file_stream_SetSize(IStream *iface, ULARGE_INTEGER size) +{ + struct file_stream *This = file_stream_from_IStream(iface); + FIXME("(%p): stub\n", This); return E_NOTIMPL; } -static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_CopyTo (LPSTREAM iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) { - ERR(": should not be needed\n"); +static HRESULT WINAPI file_stream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size, + ULARGE_INTEGER *read_size, ULARGE_INTEGER *write_size) +{ + struct file_stream *This = file_stream_from_IStream(iface); + FIXME("(%p): stub\n", This); return E_NOTIMPL; } -static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Commit (LPSTREAM iface, DWORD grfCommitFlags) { - ERR(": should not be needed\n"); +static HRESULT WINAPI file_stream_Commit(IStream *iface, DWORD flags) +{ + struct file_stream *This = file_stream_from_IStream(iface); + FIXME("(%p): stub\n", This); return E_NOTIMPL; } -static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Revert (LPSTREAM iface) { - ERR(": should not be needed\n"); +static HRESULT WINAPI file_stream_Revert(IStream *iface) +{ + struct file_stream *This = file_stream_from_IStream(iface); + FIXME("(%p): stub\n", This); return E_NOTIMPL; } -static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_LockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { - ERR(": should not be needed\n"); +static HRESULT WINAPI file_stream_LockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, DWORD type) +{ + struct file_stream *This = file_stream_from_IStream(iface); + FIXME("(%p): stub\n", This); return E_NOTIMPL; } -static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_UnlockRegion (LPSTREAM iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { - ERR(": should not be needed\n"); +static HRESULT WINAPI file_stream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, + ULARGE_INTEGER size, DWORD type) +{ + struct file_stream *This = file_stream_from_IStream(iface); + FIXME("(%p): stub\n", This); return E_NOTIMPL; } -static HRESULT WINAPI IDirectMusicLoaderFileStream_IStream_Stat (LPSTREAM iface, STATSTG* pstatstg, DWORD grfStatFlag) { - ERR(": should not be needed\n"); +static HRESULT WINAPI file_stream_Stat(IStream *iface, STATSTG *stat, DWORD flags) +{ + struct file_stream *This = file_stream_from_IStream(iface); + FIXME("(%p): stub\n", This); return E_NOTIMPL; } -static const IStreamVtbl DirectMusicLoaderFileStream_Stream_Vtbl = { - IDirectMusicLoaderFileStream_IStream_QueryInterface, - IDirectMusicLoaderFileStream_IStream_AddRef, - IDirectMusicLoaderFileStream_IStream_Release, - IDirectMusicLoaderFileStream_IStream_Read, - IDirectMusicLoaderFileStream_IStream_Write, - IDirectMusicLoaderFileStream_IStream_Seek, - IDirectMusicLoaderFileStream_IStream_SetSize, - IDirectMusicLoaderFileStream_IStream_CopyTo, - IDirectMusicLoaderFileStream_IStream_Commit, - IDirectMusicLoaderFileStream_IStream_Revert, - IDirectMusicLoaderFileStream_IStream_LockRegion, - IDirectMusicLoaderFileStream_IStream_UnlockRegion, - IDirectMusicLoaderFileStream_IStream_Stat, - IDirectMusicLoaderFileStream_IStream_Clone -}; +static HRESULT WINAPI file_stream_Clone(IStream *iface, IStream **ret_iface) +{ + struct file_stream *This = file_stream_from_IStream(iface); + HRESULT hr; -HRESULT DMUSIC_CreateDirectMusicLoaderFileStream (void** ppobj) { - IDirectMusicLoaderFileStream *obj; + TRACE("(%p, %p)\n", This, ret_iface); - TRACE("(%p)\n", ppobj); + if (SUCCEEDED(hr = file_stream_create(This->path, ret_iface))) + { + LARGE_INTEGER position = {0}; + position.LowPart = SetFilePointer(This->file, 0, NULL, SEEK_CUR); + hr = IStream_Seek(*ret_iface, position, SEEK_SET, NULL); + } - *ppobj = NULL; - if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; - obj->StreamVtbl = &DirectMusicLoaderFileStream_Stream_Vtbl; - obj->dwRef = 0; /* will be inited with QueryInterface */ + return hr; +} - return IDirectMusicLoaderFileStream_IStream_QueryInterface ((LPSTREAM)&obj->StreamVtbl, &IID_IStream, ppobj); +static const IStreamVtbl file_stream_vtbl = +{ + file_stream_QueryInterface, + file_stream_AddRef, + file_stream_Release, + file_stream_Read, + file_stream_Write, + file_stream_Seek, + file_stream_SetSize, + file_stream_CopyTo, + file_stream_Commit, + file_stream_Revert, + file_stream_LockRegion, + file_stream_UnlockRegion, + file_stream_Stat, + file_stream_Clone, +}; + +HRESULT file_stream_create(const WCHAR *path, IStream **ret_iface) +{ + struct file_stream *stream; + + *ret_iface = NULL; + if (!(stream = calloc(1, sizeof(*stream)))) return E_OUTOFMEMORY; + stream->IStream_iface.lpVtbl = &file_stream_vtbl; + stream->ref = 1; + + wcscpy(stream->path, path); + stream->file = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (stream->file == INVALID_HANDLE_VALUE) + { + free(stream); + return DMUS_E_LOADER_FAILEDOPEN; + } + + *ret_iface = &stream->IStream_iface; + return S_OK; } +static ULONG WINAPI IDirectMusicLoaderResourceStream_IStream_AddRef (LPSTREAM iface); /***************************************************************************** * IDirectMusicLoaderResourceStream implementation From 58804a7454e3406f843d6ecbc48703a25b92f42a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 20 Sep 2023 10:32:33 +0200 Subject: [PATCH 2579/2777] dmusic/tests: Test default gm.dls sound font instruments. (cherry picked from commit 767c5ddbf9bd2dc50442c5ba9e7eceffcd28c2fd) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/tests/dmusic.c | 300 +++++++++++++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) diff --git a/dlls/dmusic/tests/dmusic.c b/dlls/dmusic/tests/dmusic.c index 703251bb9da..0e0ff7e609a 100644 --- a/dlls/dmusic/tests/dmusic.c +++ b/dlls/dmusic/tests/dmusic.c @@ -1338,6 +1338,305 @@ static void test_download_instrument(void) IDirectMusic_Release(dmusic); } +struct result +{ + DWORD patch; + WCHAR name[DMUS_MAX_NAME]; +}; + +static int __cdecl result_cmp(const void *a, const void *b) +{ + const struct result *ra = a, *rb = b; + if (ra->patch != rb->patch) return ra->patch < rb->patch ? -1 : 1; + return wcscmp(ra->name, rb->name); +} + +static void test_default_gm_collection(void) +{ + DMUS_OBJECTDESC desc = + { + .dwSize = sizeof(DMUS_OBJECTDESC), + .dwValidData = DMUS_OBJ_OBJECT | DMUS_OBJ_CLASS, + .guidClass = CLSID_DirectMusicCollection, + .guidObject = GUID_DefaultGMCollection, + }; + struct result expected[] = + { + { 0, L"Piano 1 "}, + { 0x1, L"Piano 2 "}, + { 0x2, L"Piano 3 "}, + { 0x3, L"Honky-tonk "}, + { 0x4, L"E.Piano 1 "}, + { 0x5, L"E.Piano 2 "}, + { 0x6, L"Harpsichord "}, + { 0x7, L"Clav. "}, + { 0x8, L"Celesta "}, + { 0x9, L"Glockenspiel"}, + { 0xa, L"Music Box "}, + { 0xb, L"Vibraphone "}, + { 0xc, L"Marimba "}, + { 0xd, L"Xylophone "}, + { 0xe, L"Tubular-bell"}, + { 0xf, L"Santur "}, + { 0x10, L"Organ 1 "}, + { 0x11, L"Organ 2 "}, + { 0x12, L"Organ 3 "}, + { 0x13, L"Church Org.1"}, + { 0x14, L"Reed Organ "}, + { 0x15, L"Accordion Fr"}, + { 0x16, L"Harmonica "}, + { 0x17, L"Bandoneon "}, + { 0x18, L"Nylon-str.Gt"}, + { 0x19, L"Steel-str.Gt"}, + { 0x1a, L"Jazz Gt. "}, + { 0x1b, L"Clean Gt. "}, + { 0x1c, L"Muted Gt. "}, + { 0x1d, L"Overdrive Gt"}, + { 0x1e, L"DistortionGt"}, + { 0x1f, L"Gt.Harmonics"}, + { 0x20, L"Acoustic Bs."}, + { 0x21, L"Fingered Bs."}, + { 0x22, L"Picked Bs. "}, + { 0x23, L"Fretless Bs."}, + { 0x24, L"Slap Bass 1 "}, + { 0x25, L"Slap Bass 2 "}, + { 0x26, L"Synth Bass 1"}, + { 0x27, L"Synth Bass 2"}, + { 0x28, L"Violin "}, + { 0x29, L"Viola "}, + { 0x2a, L"Cello "}, + { 0x2b, L"Contrabass "}, + { 0x2c, L"Tremolo Str "}, + { 0x2d, L"PizzicatoStr"}, + { 0x2e, L"Harp "}, + { 0x2f, L"Timpani "}, + { 0x30, L"Strings "}, + { 0x31, L"Slow Strings"}, + { 0x32, L"Syn.Strings1"}, + { 0x33, L"Syn.Strings2"}, + { 0x34, L"Choir Aahs "}, + { 0x35, L"Voice Oohs "}, + { 0x36, L"SynVox "}, + { 0x37, L"OrchestraHit"}, + { 0x38, L"Trumpet "}, + { 0x39, L"Trombone "}, + { 0x3a, L"Tuba "}, + { 0x3b, L"MutedTrumpet"}, + { 0x3c, L"French Horns"}, + { 0x3d, L"Brass 1 "}, + { 0x3e, L"Synth Brass1"}, + { 0x3f, L"Synth Brass2"}, + { 0x40, L"Soprano Sax "}, + { 0x41, L"Alto Sax "}, + { 0x42, L"Tenor Sax "}, + { 0x43, L"Baritone Sax"}, + { 0x44, L"Oboe "}, + { 0x45, L"English Horn"}, + { 0x46, L"Bassoon "}, + { 0x47, L"Clarinet "}, + { 0x48, L"Piccolo "}, + { 0x49, L"Flute "}, + { 0x4a, L"Recorder "}, + { 0x4b, L"Pan Flute "}, + { 0x4c, L"Bottle Blow "}, + { 0x4d, L"Shakuhachi "}, + { 0x4e, L"Whistle "}, + { 0x4f, L"Ocarina "}, + { 0x50, L"Square Wave "}, + { 0x51, L"Saw Wave "}, + { 0x52, L"Syn.Calliope"}, + { 0x53, L"Chiffer Lead"}, + { 0x54, L"Charang "}, + { 0x55, L"Solo Vox "}, + { 0x56, L"5th Saw Wave"}, + { 0x57, L"Bass & Lead "}, + { 0x58, L"Fantasia "}, + { 0x59, L"Warm Pad "}, + { 0x5a, L"Polysynth "}, + { 0x5b, L"Space Voice "}, + { 0x5c, L"Bowed Glass "}, + { 0x5d, L"Metal Pad "}, + { 0x5e, L"Halo Pad "}, + { 0x5f, L"Sweep Pad "}, + { 0x60, L"Ice Rain "}, + { 0x61, L"Soundtrack "}, + { 0x62, L"Crystal "}, + { 0x63, L"Atmosphere "}, + { 0x64, L"Brightness "}, + { 0x65, L"Goblin "}, + { 0x66, L"Echo Drops "}, + { 0x67, L"Star Theme "}, + { 0x68, L"Sitar "}, + { 0x69, L"Banjo "}, + { 0x6a, L"Shamisen "}, + { 0x6b, L"Koto "}, + { 0x6c, L"Kalimba "}, + { 0x6d, L"Bagpipe "}, + { 0x6e, L"Fiddle "}, + { 0x6f, L"Shanai "}, + { 0x70, L"Tinkle Bell "}, + { 0x71, L"Agogo "}, + { 0x72, L"Steel Drums "}, + { 0x73, L"Woodblock "}, + { 0x74, L"Taiko "}, + { 0x75, L"Melo. Tom 1 "}, + { 0x76, L"Synth Drum "}, + { 0x77, L"Reverse Cym."}, + { 0x78, L"Gt.FretNoise"}, + { 0x79, L"Breath Noise"}, + { 0x7a, L"Seashore "}, + { 0x7b, L"Bird "}, + { 0x7c, L"Telephone 1 "}, + { 0x7d, L"Helicopter "}, + { 0x7e, L"Applause "}, + { 0x7f, L"Gun Shot "}, + { 0x10026, L"SynthBass101"}, + { 0x10039, L"Trombone 2 "}, + { 0x1003c, L"Fr.Horn 2 "}, + { 0x10050, L"Square "}, + { 0x10051, L"Saw "}, + { 0x10062, L"Syn Mallet "}, + { 0x10066, L"Echo Bell "}, + { 0x10068, L"Sitar 2 "}, + { 0x10078, L"Gt.Cut Noise"}, + { 0x10079, L"Fl.Key Click"}, + { 0x1007a, L"Rain "}, + { 0x1007b, L"Dog "}, + { 0x1007c, L"Telephone 2 "}, + { 0x1007d, L"Car-Engine "}, + { 0x1007e, L"Laughing "}, + { 0x1007f, L"Machine Gun "}, + { 0x20066, L"Echo Pan "}, + { 0x20078, L"String Slap "}, + { 0x2007a, L"Thunder "}, + { 0x2007b, L"Horse-Gallop"}, + { 0x2007c, L"DoorCreaking"}, + { 0x2007d, L"Car-Stop "}, + { 0x2007e, L"Screaming "}, + { 0x2007f, L"Lasergun "}, + { 0x3007a, L"Wind "}, + { 0x3007b, L"Bird 2 "}, + { 0x3007c, L"Door "}, + { 0x3007d, L"Car-Pass "}, + { 0x3007e, L"Punch "}, + { 0x3007f, L"Explosion "}, + { 0x4007a, L"Stream "}, + { 0x4007c, L"Scratch "}, + { 0x4007d, L"Car-Crash "}, + { 0x4007e, L"Heart Beat "}, + { 0x5007a, L"Bubble "}, + { 0x5007c, L"Wind Chimes "}, + { 0x5007d, L"Siren "}, + { 0x5007e, L"Footsteps "}, + { 0x6007d, L"Train "}, + { 0x7007d, L"Jetplane "}, + { 0x80000, L"Piano 1 "}, + { 0x80001, L"Piano 2 "}, + { 0x80002, L"Piano 3 "}, + { 0x80003, L"Honky-tonk "}, + { 0x80004, L"Detuned EP 1"}, + { 0x80005, L"Detuned EP 2"}, + { 0x80006, L"Coupled Hps."}, + { 0x8000b, L"Vibraphone "}, + { 0x8000c, L"Marimba "}, + { 0x8000e, L"Church Bell "}, + { 0x80010, L"Detuned Or.1"}, + { 0x80011, L"Detuned Or.2"}, + { 0x80013, L"Church Org.2"}, + { 0x80015, L"Accordion It"}, + { 0x80018, L"Ukulele "}, + { 0x80019, L"12-str.Gt "}, + { 0x8001a, L"Hawaiian Gt."}, + { 0x8001b, L"Chorus Gt. "}, + { 0x8001c, L"Funk Gt. "}, + { 0x8001e, L"Feedback Gt."}, + { 0x8001f, L"Gt. Feedback"}, + { 0x80026, L"Synth Bass 3"}, + { 0x80027, L"Synth Bass 4"}, + { 0x80028, L"Slow Violin "}, + { 0x80030, L"Orchestra "}, + { 0x80032, L"Syn.Strings3"}, + { 0x8003d, L"Brass 2 "}, + { 0x8003e, L"Synth Brass3"}, + { 0x8003f, L"Synth Brass4"}, + { 0x80050, L"Sine Wave "}, + { 0x80051, L"Doctor Solo "}, + { 0x8006b, L"Taisho Koto "}, + { 0x80073, L"Castanets "}, + { 0x80074, L"Concert BD "}, + { 0x80075, L"Melo. Tom 2 "}, + { 0x80076, L"808 Tom "}, + { 0x8007d, L"Starship "}, + { 0x9000e, L"Carillon "}, + { 0x90076, L"Elec Perc. "}, + { 0x9007d, L"Burst Noise "}, + { 0x100000, L"Piano 1d "}, + { 0x100004, L"E.Piano 1v "}, + { 0x100005, L"E.Piano 2v "}, + { 0x100006, L"Harpsichord "}, + { 0x100010, L"60's Organ 1"}, + { 0x100013, L"Church Org.3"}, + { 0x100018, L"Nylon Gt.o "}, + { 0x100019, L"Mandolin "}, + { 0x10001c, L"Funk Gt.2 "}, + { 0x100027, L"Rubber Bass "}, + { 0x10003e, L"AnalogBrass1"}, + { 0x10003f, L"AnalogBrass2"}, + { 0x180004, L"60's E.Piano"}, + { 0x180006, L"Harpsi.o "}, + { 0x200010, L"Organ 4 "}, + { 0x200011, L"Organ 5 "}, + { 0x200018, L"Nylon Gt.2 "}, + { 0x200034, L"Choir Aahs 2"}, + {0x80000000, L"Standard "}, + {0x80000008, L"Room "}, + {0x80000010, L"Power "}, + {0x80000018, L"Electronic "}, + {0x80000019, L"TR-808 "}, + {0x80000020, L"Jazz "}, + {0x80000028, L"Brush "}, + {0x80000030, L"Orchestra "}, + {0x80000038, L"SFX "}, + }, results[ARRAY_SIZE(expected) + 1]; + IDirectMusicCollection *collection; + IDirectMusicLoader *loader; + HRESULT hr; + DWORD i; + + hr = CoCreateInstance(&CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicLoader, (void**)&loader); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicCollection, (void **)&collection); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + + for (i = 0; hr == S_OK && i < ARRAY_SIZE(results); i++) + { + results[i].patch = 0xdeadbeef; + wcscpy(results[i].name, L"DeadBeef"); + hr = IDirectMusicCollection_EnumInstrument(collection, i, &results[i].patch, + results[i].name, ARRAY_SIZE(results[i].name)); + } + if (hr == S_FALSE) i--; + todo_wine ok(hr == S_FALSE, "got %#lx\n", hr); + todo_wine ok(i > 0, "got %lu\n", i); + todo_wine ok(i == ARRAY_SIZE(expected), "got %lu\n", i); + + qsort(results, i, sizeof(*results), result_cmp); + + while (i--) + { + winetest_push_context("%lu", i); + trace("got %#lx %s\n", results[i].patch, debugstr_w(results[i].name)); + ok(results[i].patch == expected[i].patch, "got %#lx\n", results[i].patch); + /* system soundfont names are not very predictable, let's not check them */ + winetest_pop_context(); + } + + if (hr == S_FALSE) IDirectMusicCollection_Release(collection); + IDirectMusicLoader_Release(loader); +} + START_TEST(dmusic) { CoInitializeEx(NULL, COINIT_MULTITHREADED); @@ -1360,6 +1659,7 @@ START_TEST(dmusic) test_synthport(); test_port_download(); test_download_instrument(); + test_default_gm_collection(); CoUninitialize(); } From e93e53a064b99efb7483665c609537c9a67cfffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 26 Sep 2023 08:22:38 +0200 Subject: [PATCH 2580/2777] dmloader: Remove invalid default DLS collection check. (cherry picked from commit 49c6e57d95d6f7d7647b132ea658ef0705b27d1d) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmloader/loader.c | 54 +++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/dlls/dmloader/loader.c b/dlls/dmloader/loader.c index 9c97f47e5f7..d15c99f6fb6 100644 --- a/dlls/dmloader/loader.c +++ b/dlls/dmloader/loader.c @@ -40,7 +40,6 @@ struct cache_entry { struct list entry; DMUS_OBJECTDESC Desc; IDirectMusicObject *pObject; - BOOL bInvalidDefaultDLS; /* workaround for enabling caching of "faulty" default dls collection */ }; struct loader @@ -276,12 +275,6 @@ static HRESULT WINAPI loader_GetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE TRACE(": looking if we have object in the cache or if it can be found via alias\n"); pExistingEntry = find_cache_object(This, pDesc); if (pExistingEntry) { - - if (pExistingEntry->bInvalidDefaultDLS) { - TRACE(": found faulty default DLS collection... enabling M$ compliant behaviour\n"); - return DMUS_E_LOADER_NOFILENAME; - } - if (pExistingEntry->Desc.dwValidData & DMUS_OBJ_LOADED) { TRACE(": already loaded\n"); return IDirectMusicObject_QueryInterface(pExistingEntry->pObject, riid, ppv); @@ -404,23 +397,26 @@ static HRESULT WINAPI loader_GetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE IStream_Release (pStream); IPersistStream_Release (pPersistStream); - /* add object to cache/overwrite existing info (if cache is enabled) */ - bCache = is_cache_enabled(This, &pDesc->guidClass); - if (bCache) { - if (!pObjectEntry) { + /* add object to cache/overwrite existing info (if cache is enabled) */ + bCache = is_cache_enabled(This, &pDesc->guidClass); + if (!bCache) TRACE(": caching disabled\n"); + else + { + if (!pObjectEntry) + { pObjectEntry = calloc(1, sizeof(*pObjectEntry)); - DM_STRUCT_INIT(&pObjectEntry->Desc); - DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc); - pObjectEntry->pObject = pObject; - pObjectEntry->bInvalidDefaultDLS = FALSE; - list_add_head(&This->cache, &pObjectEntry->entry); - } else { - DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc); - pObjectEntry->pObject = pObject; - pObjectEntry->bInvalidDefaultDLS = FALSE; - } - TRACE(": filled in cache entry\n"); - } else TRACE(": caching disabled\n"); + DM_STRUCT_INIT(&pObjectEntry->Desc); + DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc); + pObjectEntry->pObject = pObject; + list_add_head(&This->cache, &pObjectEntry->entry); + } + else + { + DMUSIC_CopyDescriptor (&pObjectEntry->Desc, &GotDesc); + pObjectEntry->pObject = pObject; + } + TRACE(": filled in cache entry\n"); + } result = IDirectMusicObject_QueryInterface (pObject, riid, ppv); if (!bCache) IDirectMusicObject_Release (pObject); /* since loader's reference is not needed */ @@ -873,8 +869,6 @@ HRESULT create_dmloader(REFIID lpcGUID, void **ppobj) { struct loader *obj; DMUS_OBJECTDESC Desc; - struct cache_entry *dls; - struct list *pEntry; HRESULT hr; TRACE("(%s, %p)\n", debugstr_dmguid(lpcGUID), ppobj); @@ -895,16 +889,6 @@ HRESULT create_dmloader(REFIID lpcGUID, void **ppobj) DMUSIC_GetDefaultGMPath(Desc.wszFileName); IDirectMusicLoader_SetObject(&obj->IDirectMusicLoader8_iface, &Desc); - /* and now the workaroundTM for "invalid" default DLS; basically, - my tests showed that if GUID chunk is present in default DLS - collection, loader treats it as "invalid" and returns - DMUS_E_LOADER_NOFILENAME for all requests for it; basically, we check - if out input guidObject was overwritten */ - pEntry = list_head(&obj->cache); - dls = LIST_ENTRY(pEntry, struct cache_entry, entry); - if (!IsEqualGUID(&Desc.guidObject, &GUID_DefaultGMCollection)) - dls->bInvalidDefaultDLS = TRUE; - hr = IDirectMusicLoader_QueryInterface(&obj->IDirectMusicLoader8_iface, lpcGUID, ppobj); IDirectMusicLoader_Release(&obj->IDirectMusicLoader8_iface); return hr; From f8513fab0cf225744b0970a4d247802e270f448f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 26 Sep 2023 15:12:45 +0200 Subject: [PATCH 2581/2777] dmloader: Add fallbacks if the configured GMFilePath doesn't exist. (cherry picked from commit 8e881787fc542355e8a9422590fdbbb334f63450) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmloader/loader.c | 67 ++++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 15 deletions(-) diff --git a/dlls/dmloader/loader.c b/dlls/dmloader/loader.c index d15c99f6fb6..78b9790dff3 100644 --- a/dlls/dmloader/loader.c +++ b/dlls/dmloader/loader.c @@ -20,6 +20,32 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmloader); +static const WCHAR *system_default_gm_paths[] = +{ + L"/usr/share/sounds/sf2/default-GM.sf2", + L"/usr/share/soundfonts/default.sf2", +}; + +static HRESULT get_system_default_gm_path(WCHAR *path, UINT max_len) +{ + UINT i; + + for (i = 0; i < ARRAY_SIZE(system_default_gm_paths); i++) + { + swprintf(path, max_len, L"\\??\\unix%s", system_default_gm_paths[i]); + if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES) break; + } + + if (i < ARRAY_SIZE(system_default_gm_paths)) + { + WARN("Using system %s for the default collection\n", debugstr_w(path)); + return S_OK; + } + + ERR("Unable to find system path, default collection will not be available\n"); + return DMUS_E_LOADER_FAILEDOPEN; +} + static const GUID *classes[] = { &GUID_DirectMusicAllTypes, /* Keep as first */ &CLSID_DirectMusicAudioPathConfig, @@ -458,6 +484,13 @@ static HRESULT WINAPI loader_SetObject(IDirectMusicLoader8 *iface, DMUS_OBJECTDE lstrcpyW(p, pDesc->wszFileName); } + if (!wcsicmp(file_name, L"C:\\windows\\system32\\drivers\\gm.dls") + && GetFileAttributesW(file_name) == INVALID_FILE_ATTRIBUTES) + { + hr = get_system_default_gm_path(file_name, ARRAY_SIZE(file_name)); + if (FAILED(hr)) return hr; + } + if (FAILED(hr = file_stream_create(file_name, &pStream))) return hr; } else if (pDesc->dwValidData & DMUS_OBJ_STREAM) @@ -847,21 +880,24 @@ static const IDirectMusicLoader8Vtbl loader_vtbl = loader_LoadObjectFromFile, }; -/* help function for DMUSIC_SetDefaultDLS */ -static HRESULT DMUSIC_GetDefaultGMPath (WCHAR wszPath[MAX_PATH]) { - HKEY hkDM; - DWORD returnType, sizeOfReturnBuffer = MAX_PATH; - char szPath[MAX_PATH]; +static HRESULT get_default_gm_path(WCHAR *path, DWORD max_len) +{ + DWORD ret; + HKEY hkey; + + if (!(ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\DirectMusic" , 0, KEY_READ, &hkey))) + { + DWORD type, size = max_len * sizeof(WCHAR); + ret = RegQueryValueExW(hkey, L"GMFilePath", NULL, &type, (BYTE *)path, &size); + RegCloseKey(hkey); - if ((RegOpenKeyExA (HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectMusic" , 0, KEY_READ, &hkDM) != ERROR_SUCCESS) || - (RegQueryValueExA (hkDM, "GMFilePath", NULL, &returnType, (LPBYTE) szPath, &sizeOfReturnBuffer) != ERROR_SUCCESS)) { - WARN(": registry entry missing\n" ); - return E_FAIL; - } - /* FIXME: Check return types to ensure we're interpreting data right */ - MultiByteToWideChar (CP_ACP, 0, szPath, -1, wszPath, MAX_PATH); + if (!ret && GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES) return S_OK; + } - return S_OK; + if (!ret) WARN("Failed to find %s, using system fallbacks\n", debugstr_w(path)); + else WARN("Failed to open GMFilePath registry key, using system fallbacks\n"); + + return get_system_default_gm_path(path, max_len); } /* for ClassFactory */ @@ -886,8 +922,9 @@ HRESULT create_dmloader(REFIID lpcGUID, void **ppobj) Desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH | DMUS_OBJ_OBJECT; Desc.guidClass = CLSID_DirectMusicCollection; Desc.guidObject = GUID_DefaultGMCollection; - DMUSIC_GetDefaultGMPath(Desc.wszFileName); - IDirectMusicLoader_SetObject(&obj->IDirectMusicLoader8_iface, &Desc); + if (SUCCEEDED(hr = get_default_gm_path(Desc.wszFileName, ARRAY_SIZE(Desc.wszFileName)))) + hr = IDirectMusicLoader_SetObject(&obj->IDirectMusicLoader8_iface, &Desc); + if (FAILED(hr)) WARN("Failed to load the default collection, hr %#lx\n", hr); hr = IDirectMusicLoader_QueryInterface(&obj->IDirectMusicLoader8_iface, lpcGUID, ppobj); IDirectMusicLoader_Release(&obj->IDirectMusicLoader8_iface); From 8c978eeaa9774edfd8127d6330ba2e6e79c3ff85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 22 Sep 2023 20:56:17 +0200 Subject: [PATCH 2582/2777] dmusic: Avoid leaking articulations when freeing regions. (cherry picked from commit 2a1fd9851c33fae7d8cc3b6ef63e9bf8a0effe4f) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/instrument.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index 8ce3c0bc979..54ce7508ee4 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -44,6 +44,19 @@ struct region BOOL loop_present; }; +static void region_destroy(struct region *region) +{ + struct articulation *articulation, *next; + + LIST_FOR_EACH_ENTRY_SAFE(articulation, next, ®ion->articulations, struct articulation, entry) + { + list_remove(&articulation->entry); + free(articulation); + } + + free(region); +} + struct instrument { IDirectMusicInstrument IDirectMusicInstrument_iface; @@ -122,15 +135,8 @@ static ULONG WINAPI instrument_Release(LPDIRECTMUSICINSTRUMENT iface) LIST_FOR_EACH_ENTRY_SAFE(region, next_region, &This->regions, struct region, entry) { - LIST_FOR_EACH_ENTRY_SAFE(articulation, next_articulation, ®ion->articulations, - struct articulation, entry) - { - list_remove(&articulation->entry); - free(articulation); - } - list_remove(®ion->entry); - free(region); + region_destroy(region); } collection_internal_release(This->collection); @@ -322,7 +328,7 @@ static HRESULT parse_rgn_chunk(struct instrument *This, IStream *stream, struct if (FAILED(hr)) break; } - if (FAILED(hr)) free(region); + if (FAILED(hr)) region_destroy(region); else list_add_tail(&This->regions, ®ion->entry); return hr; From 6bdd3ff8c3c776b64be655a92207b6b8a5d3ee32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 26 Sep 2023 08:28:19 +0200 Subject: [PATCH 2583/2777] dmusic: Avoid crashing in traces if wave doesn't have a WSMPL. (cherry picked from commit 182338bab26cdfd904336c0a0508537ad8e62d47) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/wave.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/dlls/dmusic/wave.c b/dlls/dmusic/wave.c index 08146db0d1c..6637612596a 100644 --- a/dlls/dmusic/wave.c +++ b/dlls/dmusic/wave.c @@ -199,14 +199,17 @@ HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnk TRACE(" - wBitsPerSample: %u\n", This->format->wBitsPerSample); TRACE(" - cbSize: %u\n", This->format->cbSize); } - TRACE(" - sample: {size: %lu, unity_note: %u, fine_tune: %d, attenuation: %ld, options: %#lx, loops: %lu}\n", - This->sample->head.cbSize, This->sample->head.usUnityNote, - This->sample->head.sFineTune, This->sample->head.lAttenuation, - This->sample->head.fulOptions, This->sample->head.cSampleLoops); - for (i = 0; i < This->sample->head.cSampleLoops; i++) - TRACE(" - loops[%u]: {size: %lu, type: %lu, start: %lu, length: %lu}\n", i, - This->sample->loops[i].cbSize, This->sample->loops[i].ulType, - This->sample->loops[i].ulStart, This->sample->loops[i].ulLength); + if (This->sample) + { + TRACE(" - sample: {size: %lu, unity_note: %u, fine_tune: %d, attenuation: %ld, options: %#lx, loops: %lu}\n", + This->sample->head.cbSize, This->sample->head.usUnityNote, + This->sample->head.sFineTune, This->sample->head.lAttenuation, + This->sample->head.fulOptions, This->sample->head.cSampleLoops); + for (i = 0; i < This->sample->head.cSampleLoops; i++) + TRACE(" - loops[%u]: {size: %lu, type: %lu, start: %lu, length: %lu}\n", i, + This->sample->loops[i].cbSize, This->sample->loops[i].ulType, + This->sample->loops[i].ulStart, This->sample->loops[i].ulLength); + } } *ret_iface = iface; From 4b46c1f4c8627d0aed9b824aa31924f5cdb22661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 21 Sep 2023 09:11:55 +0200 Subject: [PATCH 2584/2777] dmusic: Implement SoundFont2 collection parsing. (cherry picked from commit b733a46adae2af03d364bac9a0ecfd83390d25d3) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 2 +- dlls/dmusic/collection.c | 249 +++++++++++++++++++++++++++- dlls/dmusic/soundfont.h | 323 +++++++++++++++++++++++++++++++++++++ dlls/dmusic/tests/dmusic.c | 6 +- 4 files changed, 574 insertions(+), 6 deletions(-) create mode 100644 dlls/dmusic/soundfont.h diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 119bfc74fc5..57879f52069 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3546,7 +3546,7 @@ static void test_band_track_play(void) &IID_IDirectMusicLoader8, (void **)&loader); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicLoader_SetObject(loader, &desc); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); hr = test_loader_stream_create(stream, loader, &loader_stream); ok(hr == S_OK, "got %#lx\n", hr); diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index 1074c4e2868..feda1cbf8a9 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -19,6 +19,7 @@ */ #include "dmusic_private.h" +#include "soundfont.h" WINE_DEFAULT_DEBUG_CHANNEL(dmusic); @@ -353,6 +354,246 @@ static HRESULT parse_dls_chunk(struct collection *This, IStream *stream, struct return hr; } +static HRESULT parse_sdta_list(struct collection *This, IStream *stream, struct chunk_entry *parent, + struct soundfont *soundfont) +{ + struct chunk_entry chunk = {.parent = parent}; + HRESULT hr; + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case mmioFOURCC('s','m','p','l'): + if (soundfont->sdta) return E_INVALIDARG; + if (!(soundfont->sdta = malloc(chunk.size))) return E_OUTOFMEMORY; + hr = stream_chunk_get_data(stream, &chunk, soundfont->sdta, chunk.size); + break; + + default: + FIXME("Skipping unknown chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; + } + + return hr; +} + +static HRESULT parse_pdta_list(struct collection *This, IStream *stream, struct chunk_entry *parent, + struct soundfont *soundfont) +{ + struct chunk_entry chunk = {.parent = parent}; + HRESULT hr; + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case mmioFOURCC('p','h','d','r'): + if (soundfont->phdr) return E_INVALIDARG; + if (!(soundfont->phdr = malloc(chunk.size))) return E_OUTOFMEMORY; + hr = stream_chunk_get_data(stream, &chunk, soundfont->phdr, chunk.size); + soundfont->preset_count = chunk.size / sizeof(*soundfont->phdr) - 1; + break; + + case mmioFOURCC('p','b','a','g'): + if (soundfont->pbag) return E_INVALIDARG; + if (!(soundfont->pbag = malloc(chunk.size))) return E_OUTOFMEMORY; + hr = stream_chunk_get_data(stream, &chunk, soundfont->pbag, chunk.size); + break; + + case mmioFOURCC('p','m','o','d'): + if (soundfont->pmod) return E_INVALIDARG; + if (!(soundfont->pmod = malloc(chunk.size))) return E_OUTOFMEMORY; + hr = stream_chunk_get_data(stream, &chunk, soundfont->pmod, chunk.size); + break; + + case mmioFOURCC('p','g','e','n'): + if (soundfont->pgen) return E_INVALIDARG; + if (!(soundfont->pgen = malloc(chunk.size))) return E_OUTOFMEMORY; + hr = stream_chunk_get_data(stream, &chunk, soundfont->pgen, chunk.size); + break; + + case mmioFOURCC('i','n','s','t'): + if (soundfont->inst) return E_INVALIDARG; + if (!(soundfont->inst = malloc(chunk.size))) return E_OUTOFMEMORY; + hr = stream_chunk_get_data(stream, &chunk, soundfont->inst, chunk.size); + soundfont->instrument_count = chunk.size / sizeof(*soundfont->inst) - 1; + break; + + case mmioFOURCC('i','b','a','g'): + if (soundfont->ibag) return E_INVALIDARG; + if (!(soundfont->ibag = malloc(chunk.size))) return E_OUTOFMEMORY; + hr = stream_chunk_get_data(stream, &chunk, soundfont->ibag, chunk.size); + break; + + case mmioFOURCC('i','m','o','d'): + if (soundfont->imod) return E_INVALIDARG; + if (!(soundfont->imod = malloc(chunk.size))) return E_OUTOFMEMORY; + hr = stream_chunk_get_data(stream, &chunk, soundfont->imod, chunk.size); + break; + + case mmioFOURCC('i','g','e','n'): + if (soundfont->igen) return E_INVALIDARG; + if (!(soundfont->igen = malloc(chunk.size))) return E_OUTOFMEMORY; + hr = stream_chunk_get_data(stream, &chunk, soundfont->igen, chunk.size); + break; + + case mmioFOURCC('s','h','d','r'): + if (soundfont->shdr) return E_INVALIDARG; + if (!(soundfont->shdr = malloc(chunk.size))) return E_OUTOFMEMORY; + hr = stream_chunk_get_data(stream, &chunk, soundfont->shdr, chunk.size); + soundfont->sample_count = chunk.size / sizeof(*soundfont->shdr) - 1; + break; + + default: + FIXME("Skipping unknown chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; + } + + return hr; +} + +static HRESULT parse_sfbk_chunk(struct collection *This, IStream *stream, struct chunk_entry *parent) +{ + struct chunk_entry chunk = {.parent = parent}; + struct soundfont soundfont = {0}; + UINT i, j, k; + HRESULT hr; + + if (FAILED(hr = dmobj_parsedescriptor(stream, parent, &This->dmobj.desc, + DMUS_OBJ_NAME_INFO|DMUS_OBJ_VERSION|DMUS_OBJ_OBJECT|DMUS_OBJ_GUID_DLID)) + || FAILED(hr = stream_reset_chunk_data(stream, parent))) + return hr; + + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case MAKE_IDTYPE(FOURCC_LIST, DMUS_FOURCC_INFO_LIST): + /* already parsed by dmobj_parsedescriptor */ + break; + + case MAKE_IDTYPE(FOURCC_LIST, mmioFOURCC('s','d','t','a')): + hr = parse_sdta_list(This, stream, &chunk, &soundfont); + break; + + case MAKE_IDTYPE(FOURCC_LIST, mmioFOURCC('p','d','t','a')): + hr = parse_pdta_list(This, stream, &chunk, &soundfont); + break; + + default: + FIXME("Ignoring chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + break; + } + + if (FAILED(hr)) break; + } + + if (SUCCEEDED(hr)) + { + TRACE("presets:\n"); + for (i = 0; i < soundfont.preset_count; i++) + { + struct sf_preset *preset = soundfont.phdr + i; + + TRACE("preset[%u]:\n", i); + TRACE(" - name: %s\n", debugstr_a(preset->name)); + TRACE(" - preset: %u\n", preset->preset); + TRACE(" - bank: %u\n", preset->bank); + TRACE(" - preset_bag_ndx: %u\n", preset->bag_ndx); + TRACE(" - library: %lu\n", preset->library); + TRACE(" - genre: %lu\n", preset->genre); + TRACE(" - morphology: %#lx\n", preset->morphology); + + for (j = preset->bag_ndx; j < (preset + 1)->bag_ndx; j++) + { + struct sf_bag *bag = soundfont.pbag + j; + TRACE(" - bag[%u]:\n", j); + TRACE(" - gen_ndx: %u\n", bag->gen_ndx); + TRACE(" - mod_ndx: %u\n", bag->mod_ndx); + + for (k = bag->gen_ndx; k < (bag + 1)->gen_ndx; k++) + { + struct sf_gen *gen = soundfont.pgen + k; + TRACE(" - gen[%u]: %s\n", k, debugstr_sf_gen(gen)); + } + + for (k = bag->mod_ndx; k < (bag + 1)->mod_ndx; k++) + { + struct sf_mod *mod = soundfont.pmod + k; + TRACE(" - mod[%u]: %s\n", k, debugstr_sf_mod(mod)); + } + } + } + + TRACE("instruments:\n"); + for (i = 0; i < soundfont.instrument_count; i++) + { + struct sf_instrument *instrument = soundfont.inst + i; + TRACE("instrument[%u]:\n", i); + TRACE(" - name: %s\n", debugstr_a(instrument->name)); + TRACE(" - bag_ndx: %u\n", instrument->bag_ndx); + + for (j = instrument->bag_ndx; j < (instrument + 1)->bag_ndx; j++) + { + struct sf_bag *bag = soundfont.ibag + j; + TRACE(" - bag[%u]:\n", j); + TRACE(" - wGenNdx: %u\n", bag->gen_ndx); + TRACE(" - wModNdx: %u\n", bag->mod_ndx); + + for (k = bag->gen_ndx; k < (bag + 1)->gen_ndx; k++) + { + struct sf_gen *gen = soundfont.igen + k; + TRACE(" - gen[%u]: %s\n", k, debugstr_sf_gen(gen)); + } + + for (k = bag->mod_ndx; k < (bag + 1)->mod_ndx; k++) + { + struct sf_mod *mod = soundfont.imod + k; + TRACE(" - mod[%u]: %s\n", k, debugstr_sf_mod(mod)); + } + } + } + + TRACE("samples:\n"); + for (i = 0; i < soundfont.sample_count; i++) + { + struct sf_sample *sample = soundfont.shdr + i; + + TRACE("sample[%u]:\n", i); + TRACE(" - name: %s\n", debugstr_a(sample->name)); + TRACE(" - start: %lu\n", sample->start); + TRACE(" - end: %lu\n", sample->end); + TRACE(" - start_loop: %lu\n", sample->start_loop); + TRACE(" - end_loop: %lu\n", sample->end_loop); + TRACE(" - sample_rate: %lu\n", sample->sample_rate); + TRACE(" - original_key: %u\n", sample->original_key); + TRACE(" - correction: %d\n", sample->correction); + TRACE(" - sample_link: %#x\n", sample->sample_link); + TRACE(" - sample_type: %#x\n", sample->sample_type); + } + } + + free(soundfont.phdr); + free(soundfont.pbag); + free(soundfont.pmod); + free(soundfont.pgen); + free(soundfont.inst); + free(soundfont.ibag); + free(soundfont.imod); + free(soundfont.igen); + free(soundfont.shdr); + free(soundfont.sdta); + + return hr; +} + static HRESULT WINAPI collection_object_ParseDescriptor(IDirectMusicObject *iface, IStream *stream, DMUS_OBJECTDESC *desc) { @@ -366,7 +607,7 @@ static HRESULT WINAPI collection_object_ParseDescriptor(IDirectMusicObject *ifac if ((hr = stream_get_chunk(stream, &riff)) != S_OK) return hr; - if (riff.id != FOURCC_RIFF || riff.type != FOURCC_DLS) { + if (riff.id != FOURCC_RIFF || (riff.type != FOURCC_DLS && riff.type != mmioFOURCC('s','f','b','k'))) { TRACE("loading failed: unexpected %s\n", debugstr_chunk(&riff)); stream_skip_chunk(stream, &riff); return DMUS_E_NOTADLSCOL; @@ -410,6 +651,10 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream *str hr = parse_dls_chunk(This, stream, &chunk); break; + case MAKE_IDTYPE(FOURCC_RIFF, mmioFOURCC('s','f','b','k')): + hr = parse_sfbk_chunk(This, stream, &chunk); + break; + default: WARN("Invalid collection chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); hr = DMUS_E_UNSUPPORTED_STREAM; @@ -439,7 +684,7 @@ static HRESULT WINAPI collection_stream_Load(IPersistStream *iface, IStream *str } TRACE(" - cues:\n"); - for (i = 0; i < This->pool->table.cCues; i++) + for (i = 0; This->pool && i < This->pool->table.cCues; i++) TRACE(" - index: %u, offset: %lu\n", i, This->pool->cues[i].ulOffset); TRACE(" - waves:\n"); diff --git a/dlls/dmusic/soundfont.h b/dlls/dmusic/soundfont.h new file mode 100644 index 00000000000..ac71ba7909a --- /dev/null +++ b/dlls/dmusic/soundfont.h @@ -0,0 +1,323 @@ +/* + * Copyright 2023 Rémi Bernon for CodeWeavers + * + * This program 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 program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "stdarg.h" +#include "stddef.h" + +#include "windef.h" +#include "winbase.h" + +#include "wine/debug.h" + +#include + +/* SoundFont 2.04 data structures, from http://www.synthfont.com/sfspec24.pdf */ + +struct sf_range +{ + BYTE low; + BYTE high; +}; + +union sf_amount +{ + struct sf_range range; + WORD value; +}; + +C_ASSERT(sizeof(union sf_amount) == 2); + +enum +{ + SF_SAMPLE_MONO = 1, + SF_SAMPLE_RIGHT = 2, + SF_SAMPLE_LEFT = 4, + SF_SAMPLE_LINKED = 8, + SF_SAMPLE_ROM_MONO = 0x8001, + SF_SAMPLE_ROM_RIGHT = 0x8002, + SF_SAMPLE_ROM_LEFT = 0x8004, + SF_SAMPLE_ROM_LINKED = 0x8008, +}; +typedef WORD sf_sample_type; + +enum +{ + SF_GEN_START_ADDRS_OFFSET = 0, + SF_GEN_END_ADDRS_OFFSET = 1, + SF_GEN_STARTLOOP_ADDRS_OFFSET = 2, + SF_GEN_ENDLOOP_ADDRS_OFFSET = 3, + SF_GEN_START_ADDRS_COARSE_OFFSET = 4, + SF_GEN_MOD_LFO_TO_PITCH = 5, + SF_GEN_VIB_LFO_TO_PITCH = 6, + SF_GEN_MOD_ENV_TO_PITCH = 7, + SF_GEN_INITIAL_FILTER_FC = 8, + SF_GEN_INITIAL_FILTER_Q = 9, + SF_GEN_MOD_LFO_TO_FILTER_FC = 10, + SF_GEN_MOD_ENV_TO_FILTER_FC = 11, + SF_GEN_END_ADDRS_COARSE_OFFSET = 12, + SF_GEN_MOD_LFO_TO_VOLUME = 13, + + SF_GEN_CHORUS_EFFECTS_SEND = 15, + SF_GEN_REVERB_EFFECTS_SEND = 16, + SF_GEN_PAN = 17, + + SF_GEN_DELAY_MOD_LFO = 21, + SF_GEN_FREQ_MOD_LFO = 22, + SF_GEN_DELAY_VIB_LFO = 23, + SF_GEN_FREQ_VIB_LFO = 24, + SF_GEN_DELAY_MOD_ENV = 25, + SF_GEN_ATTACK_MOD_ENV = 26, + SF_GEN_HOLD_MOD_ENV = 27, + SF_GEN_DECAY_MOD_ENV = 28, + SF_GEN_SUSTAIN_MOD_ENV = 29, + SF_GEN_RELEASE_MOD_ENV = 30, + SF_GEN_KEYNUM_TO_MOD_ENV_HOLD = 31, + SF_GEN_KEYNUM_TO_MOD_ENV_DECAY = 32, + SF_GEN_DELAY_VOL_ENV = 33, + SF_GEN_ATTACK_VOL_ENV = 34, + SF_GEN_HOLD_VOL_ENV = 35, + SF_GEN_DECAY_VOL_ENV = 36, + SF_GEN_SUSTAIN_VOL_ENV = 37, + SF_GEN_RELEASE_VOL_ENV = 38, + SF_GEN_KEYNUM_TO_VOL_ENV_HOLD = 39, + SF_GEN_KEYNUM_TO_VOL_ENV_DECAY = 40, + SF_GEN_INSTRUMENT = 41, + + SF_GEN_KEY_RANGE = 43, + SF_GEN_VEL_RANGE = 44, + SF_GEN_STARTLOOP_ADDRS_COARSE_OFFSET = 45, + SF_GEN_KEYNUM = 46, + SF_GEN_VELOCITY = 47, + SF_GEN_INITIAL_ATTENUATION = 48, + + SF_GEN_ENDLOOP_ADDRS_COARSE_OFFSET = 50, + SF_GEN_COARSE_TUNE = 51, + SF_GEN_FINE_TUNE = 52, + SF_GEN_SAMPLE_ID = 53, + SF_GEN_SAMPLE_MODES = 54, + + SF_GEN_SCALE_TUNING = 56, + SF_GEN_EXCLUSIVE_CLASS = 57, + SF_GEN_OVERRIDING_ROOT_KEY = 58, + + SF_GEN_END_OPER = 60, +}; +typedef WORD sf_generator; + +static inline const char *debugstr_sf_generator(sf_generator oper) +{ + switch (oper) + { + case SF_GEN_START_ADDRS_OFFSET: return "start_addrs_offset"; + case SF_GEN_END_ADDRS_OFFSET: return "end_addrs_offset"; + case SF_GEN_STARTLOOP_ADDRS_OFFSET: return "startloop_addrs_offset"; + case SF_GEN_ENDLOOP_ADDRS_OFFSET: return "endloop_addrs_offset"; + case SF_GEN_START_ADDRS_COARSE_OFFSET: return "start_addrs_coarse_offset"; + case SF_GEN_MOD_LFO_TO_PITCH: return "mod_lfo_to_pitch"; + case SF_GEN_VIB_LFO_TO_PITCH: return "vib_lfo_to_pitch"; + case SF_GEN_MOD_ENV_TO_PITCH: return "mod_env_to_pitch"; + case SF_GEN_INITIAL_FILTER_FC: return "initial_filter_fc"; + case SF_GEN_INITIAL_FILTER_Q: return "initial_filter_q"; + case SF_GEN_MOD_LFO_TO_FILTER_FC: return "mod_lfo_to_filter_fc"; + case SF_GEN_MOD_ENV_TO_FILTER_FC: return "mod_env_to_filter_fc"; + case SF_GEN_END_ADDRS_COARSE_OFFSET: return "end_addrs_coarse_offset"; + case SF_GEN_MOD_LFO_TO_VOLUME: return "mod_lfo_to_volume"; + case SF_GEN_CHORUS_EFFECTS_SEND: return "chorus_effects_send"; + case SF_GEN_REVERB_EFFECTS_SEND: return "reverb_effects_send"; + case SF_GEN_PAN: return "pan"; + case SF_GEN_DELAY_MOD_LFO: return "delay_mod_lfo"; + case SF_GEN_FREQ_MOD_LFO: return "freq_mod_lfo"; + case SF_GEN_DELAY_VIB_LFO: return "delay_vib_lfo"; + case SF_GEN_FREQ_VIB_LFO: return "freq_vib_lfo"; + case SF_GEN_DELAY_MOD_ENV: return "delay_mod_env"; + case SF_GEN_ATTACK_MOD_ENV: return "attack_mod_env"; + case SF_GEN_HOLD_MOD_ENV: return "hold_mod_env"; + case SF_GEN_DECAY_MOD_ENV: return "decay_mod_env"; + case SF_GEN_SUSTAIN_MOD_ENV: return "sustain_mod_env"; + case SF_GEN_RELEASE_MOD_ENV: return "release_mod_env"; + case SF_GEN_KEYNUM_TO_MOD_ENV_HOLD: return "keynum_to_mod_env_hold"; + case SF_GEN_KEYNUM_TO_MOD_ENV_DECAY: return "keynum_to_mod_env_decay"; + case SF_GEN_DELAY_VOL_ENV: return "delay_vol_env"; + case SF_GEN_ATTACK_VOL_ENV: return "attack_vol_env"; + case SF_GEN_HOLD_VOL_ENV: return "hold_vol_env"; + case SF_GEN_DECAY_VOL_ENV: return "decay_vol_env"; + case SF_GEN_SUSTAIN_VOL_ENV: return "sustain_vol_env"; + case SF_GEN_RELEASE_VOL_ENV: return "release_vol_env"; + case SF_GEN_KEYNUM_TO_VOL_ENV_HOLD: return "keynum_to_vol_env_hold"; + case SF_GEN_KEYNUM_TO_VOL_ENV_DECAY: return "keynum_to_vol_env_decay"; + case SF_GEN_INSTRUMENT: return "instrument"; + case SF_GEN_KEY_RANGE: return "key_range"; + case SF_GEN_VEL_RANGE: return "vel_range"; + case SF_GEN_STARTLOOP_ADDRS_COARSE_OFFSET: return "startloop_addrs_coarse_offset"; + case SF_GEN_KEYNUM: return "keynum"; + case SF_GEN_VELOCITY: return "velocity"; + case SF_GEN_INITIAL_ATTENUATION: return "initial_attenuation"; + case SF_GEN_ENDLOOP_ADDRS_COARSE_OFFSET: return "endloop_addrs_coarse_offset"; + case SF_GEN_COARSE_TUNE: return "coarse_tune"; + case SF_GEN_FINE_TUNE: return "fine_tune"; + case SF_GEN_SAMPLE_ID: return "sample_id"; + case SF_GEN_SAMPLE_MODES: return "sample_modes"; + case SF_GEN_SCALE_TUNING: return "scale_tuning"; + case SF_GEN_EXCLUSIVE_CLASS: return "exclusive_class"; + case SF_GEN_OVERRIDING_ROOT_KEY: return "overriding_root_key"; + case SF_GEN_END_OPER: return "end_oper"; + } + + return wine_dbg_sprintf("%u", oper); +} + +enum +{ + /* sf_modulator is a set of flags ored together */ + + SF_MOD_CTRL_GEN_NONE = 0, + SF_MOD_CTRL_GEN_VELOCITY = 0x2, + SF_MOD_CTRL_GEN_KEY = 0x3, + SF_MOD_CTRL_GEN_POLY_PRESSURE = 0xa, + SF_MOD_CTRL_GEN_CHAN_PRESSURE = 0xd, + SF_MOD_CTRL_GEN_PITCH_WHEEL = 0xe, + SF_MOD_CTRL_GEN_PITCH_WHEEL_SENSITIVITY = 0x10, + SF_MOD_CTRL_GEN_LINK = 0x7f, + + SF_MOD_CTRL_GEN = 0 << 7, + SF_MOD_CTRL_MIDI = 1 << 7, /* with LSB: MIDI CC */ + + SF_MOD_DIR_INCREASING = 0 << 8, + SF_MOD_DIR_DECREASING = 1 << 8, + + SF_MOD_POL_UNIPOLAR = 0 << 9, + SF_MOD_POL_BIPOLAR = 1 << 9, + + SF_MOD_SRC_LINEAR = 0 << 10, + SF_MOD_SRC_CONCAVE = 1 << 10, + SF_MOD_SRC_CONVEX = 2 << 10, + SF_MOD_SRC_SWITCH = 3 << 10, +}; +typedef WORD sf_modulator; + +enum +{ + SF_TRAN_LINEAR = 0, + SF_TRAN_ABSOLUTE = 2, +}; +typedef WORD sf_transform; + +struct sf_preset /* */ +{ + char name[20]; + WORD preset; + WORD bank; + WORD bag_ndx; + DWORD library; + DWORD genre; + DWORD morphology; +}; + +C_ASSERT(sizeof(struct sf_preset) == 38); + +struct sf_bag /* / */ +{ + WORD gen_ndx; + WORD mod_ndx; +}; + +C_ASSERT(sizeof(struct sf_bag) == 4); + +struct sf_mod /* / */ +{ + sf_modulator src_mod; + sf_generator dest_gen; + SHORT amount; + sf_modulator amount_src_mod; + sf_transform transform; +}; + +C_ASSERT(sizeof(struct sf_mod) == 10); + +static inline const char *debugstr_sf_mod(struct sf_mod *mod) +{ + const char *dest_name = debugstr_sf_generator(mod->dest_gen); + return wine_dbg_sprintf("%#x x %#x -> %s: %d (%#x)", mod->src_mod, mod->amount_src_mod, dest_name, mod->amount, mod->transform); +} + +struct sf_gen /* / */ +{ + sf_generator oper; + union sf_amount amount; +}; + +C_ASSERT(sizeof(struct sf_gen) == 4); + +static inline const char *debugstr_sf_gen(struct sf_gen *gen) +{ + const char *name = debugstr_sf_generator(gen->oper); + + switch (gen->oper) + { + case SF_GEN_KEY_RANGE: + case SF_GEN_VEL_RANGE: + return wine_dbg_sprintf("%s: %u-%u", name, gen->amount.range.low, gen->amount.range.high); + default: + return wine_dbg_sprintf("%s: %u", name, gen->amount.value); + } +} + +struct sf_instrument /* */ +{ + char name[20]; + WORD bag_ndx; +}; + +C_ASSERT(sizeof(struct sf_instrument) == 22); + +struct sf_sample /* */ +{ + char name[20]; + DWORD start; + DWORD end; + DWORD start_loop; + DWORD end_loop; + DWORD sample_rate; + BYTE original_key; + char correction; + WORD sample_link; + sf_sample_type sample_type; +}; + +C_ASSERT(sizeof(struct sf_sample) == 46); + +#include + +struct soundfont +{ + UINT preset_count; + struct sf_preset *phdr; + struct sf_bag *pbag; + struct sf_mod *pmod; + struct sf_gen *pgen; + + UINT instrument_count; + struct sf_instrument *inst; + struct sf_bag *ibag; + struct sf_mod *imod; + struct sf_gen *igen; + + UINT sample_count; + struct sf_sample *shdr; + BYTE *sdta; +}; diff --git a/dlls/dmusic/tests/dmusic.c b/dlls/dmusic/tests/dmusic.c index 0e0ff7e609a..cf0faaa5b87 100644 --- a/dlls/dmusic/tests/dmusic.c +++ b/dlls/dmusic/tests/dmusic.c @@ -1608,7 +1608,7 @@ static void test_default_gm_collection(void) ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicCollection, (void **)&collection); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); for (i = 0; hr == S_OK && i < ARRAY_SIZE(results); i++) { @@ -1618,7 +1618,7 @@ static void test_default_gm_collection(void) results[i].name, ARRAY_SIZE(results[i].name)); } if (hr == S_FALSE) i--; - todo_wine ok(hr == S_FALSE, "got %#lx\n", hr); + ok(hr == S_FALSE, "got %#lx\n", hr); todo_wine ok(i > 0, "got %lu\n", i); todo_wine ok(i == ARRAY_SIZE(expected), "got %lu\n", i); @@ -1633,7 +1633,7 @@ static void test_default_gm_collection(void) winetest_pop_context(); } - if (hr == S_FALSE) IDirectMusicCollection_Release(collection); + IDirectMusicCollection_Release(collection); IDirectMusicLoader_Release(loader); } From 6b0b3f71054d8f5d6bffec0c4df2918d71865db2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 21 Sep 2023 09:05:55 +0200 Subject: [PATCH 2585/2777] dmusic: Implement SoundFont2 wave sample parsing. (cherry picked from commit 215a55d603bdaf501aae1df1db328131a314b443) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 23 +++++++++++ dlls/dmusic/dmusic_private.h | 2 + dlls/dmusic/wave.c | 80 ++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index feda1cbf8a9..a7d9d666e6c 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -580,6 +580,29 @@ static HRESULT parse_sfbk_chunk(struct collection *This, IStream *stream, struct } } + if (SUCCEEDED(hr)) + { + UINT size = offsetof(struct pool, cues[soundfont.sample_count]); + if (!(This->pool = calloc(1, size))) return E_OUTOFMEMORY; + This->pool->table.cbSize = sizeof(This->pool->table); + } + + for (i = 0; SUCCEEDED(hr) && i < soundfont.sample_count; i++) + { + struct wave_entry *entry; + + if (!(entry = malloc(sizeof(*entry)))) return E_OUTOFMEMORY; + hr = wave_create_from_soundfont(&soundfont, i, &entry->wave); + if (FAILED(hr)) free(entry); + else + { + entry->offset = i; + This->pool->table.cCues++; + This->pool->cues[i].ulOffset = i; + list_add_tail(&This->waves, &entry->entry); + } + } + free(soundfont.phdr); free(soundfont.pbag); free(soundfont.pmod); diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 08d84ff83e1..d40de3da909 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -94,12 +94,14 @@ extern HRESULT DMUSIC_CreateReferenceClockImpl (LPCGUID lpcGUID, LPVOID* ppobj, extern HRESULT download_create(DWORD size, IDirectMusicDownload **ret_iface); +struct soundfont; extern HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent, struct collection *collection, DMUS_OBJECTDESC *desc, IDirectMusicInstrument **ret_iface); extern HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicPortDownload *port, IDirectMusicDownloadedInstrument **downloaded); extern HRESULT instrument_unload_from_port(IDirectMusicDownloadedInstrument *iface, IDirectMusicPortDownload *port); +extern HRESULT wave_create_from_soundfont(struct soundfont *soundfont, UINT index, IUnknown **out); extern HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnknown **out); extern HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, DWORD *id); diff --git a/dlls/dmusic/wave.c b/dlls/dmusic/wave.c index 6637612596a..40a8c9e129f 100644 --- a/dlls/dmusic/wave.c +++ b/dlls/dmusic/wave.c @@ -17,6 +17,7 @@ */ #include "dmusic_private.h" +#include "soundfont.h" WINE_DEFAULT_DEBUG_CHANNEL(dmusic); @@ -216,6 +217,85 @@ HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnk return S_OK; } +HRESULT wave_create_from_soundfont(struct soundfont *soundfont, UINT index, IUnknown **ret_iface) +{ + struct sf_sample *sf_sample = soundfont->shdr + index; + struct sample *sample = NULL; + WAVEFORMATEX *format = NULL; + HRESULT hr = E_OUTOFMEMORY; + UINT data_size, offset; + struct wave *This; + void *data = NULL; + IUnknown *iface; + + TRACE("(%p, %u, %p)\n", soundfont, index, ret_iface); + + if (sf_sample->sample_link) FIXME("Stereo sample not supported\n"); + + if (!(format = calloc(1, sizeof(*format)))) goto failed; + format->wFormatTag = WAVE_FORMAT_PCM; + format->nChannels = 1; + format->wBitsPerSample = 16; + format->nSamplesPerSec = sf_sample->sample_rate; + format->nBlockAlign = format->wBitsPerSample * format->nChannels / 8; + format->nAvgBytesPerSec = format->nBlockAlign * format->nSamplesPerSec; + + if (!(sample = calloc(1, offsetof(struct sample, loops[1])))) goto failed; + sample->head.cbSize = sizeof(sample->head); + sample->head.cSampleLoops = 1; + sample->loops[0].ulStart = sf_sample->start_loop - sf_sample->start; + sample->loops[0].ulLength = sf_sample->end_loop - sf_sample->start_loop; + + data_size = sf_sample->end - sf_sample->start; + if (!(data = malloc(data_size * format->nBlockAlign))) goto failed; + offset = sf_sample->start * format->nBlockAlign / format->nChannels; + memcpy(data, soundfont->sdta + offset, data_size); + + if (FAILED(hr = wave_create(&iface))) goto failed; + + This = impl_from_IUnknown(iface); + This->format = format; + This->sample = sample; + This->data_size = data_size; + This->data = data; + + if (TRACE_ON(dmusic)) + { + UINT i; + + TRACE("*** Created DirectMusicWave %p\n", This); + TRACE(" - format: %p\n", This->format); + if (This->format) + { + TRACE(" - wFormatTag: %u\n", This->format->wFormatTag); + TRACE(" - nChannels: %u\n", This->format->nChannels); + TRACE(" - nSamplesPerSec: %lu\n", This->format->nSamplesPerSec); + TRACE(" - nAvgBytesPerSec: %lu\n", This->format->nAvgBytesPerSec); + TRACE(" - nBlockAlign: %u\n", This->format->nBlockAlign); + TRACE(" - wBitsPerSample: %u\n", This->format->wBitsPerSample); + TRACE(" - cbSize: %u\n", This->format->cbSize); + } + + TRACE(" - sample: {size: %lu, unity_note: %u, fine_tune: %d, attenuation: %ld, options: %#lx, loops: %lu}\n", + This->sample->head.cbSize, This->sample->head.usUnityNote, + This->sample->head.sFineTune, This->sample->head.lAttenuation, + This->sample->head.fulOptions, This->sample->head.cSampleLoops); + for (i = 0; i < This->sample->head.cSampleLoops; i++) + TRACE(" - loops[%u]: {size: %lu, type: %lu, start: %lu, length: %lu}\n", i, + This->sample->loops[i].cbSize, This->sample->loops[i].ulType, + This->sample->loops[i].ulStart, This->sample->loops[i].ulLength); + } + + *ret_iface = iface; + return S_OK; + +failed: + free(data); + free(sample); + free(format); + return hr; +} + HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, DWORD *id) { struct download_buffer From 5fcafc29fc7a775379763c9f9024b2f2b0985da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 21 Sep 2023 09:13:43 +0200 Subject: [PATCH 2586/2777] dmusic: Implement SoundFont2 instrument parsing. (cherry picked from commit 086e114f05e89a9b670b9ef738b017f3d65004d8) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/collection.c | 11 ++ dlls/dmusic/dmusic_private.h | 2 + dlls/dmusic/instrument.c | 239 +++++++++++++++++++++++++++++++++++ dlls/dmusic/tests/dmusic.c | 3 +- 4 files changed, 254 insertions(+), 1 deletion(-) diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index a7d9d666e6c..bf21d3148e3 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -580,6 +580,17 @@ static HRESULT parse_sfbk_chunk(struct collection *This, IStream *stream, struct } } + for (i = 0; SUCCEEDED(hr) && i < soundfont.preset_count; i++) + { + struct instrument_entry *entry; + + if (!(entry = malloc(sizeof(*entry)))) return E_OUTOFMEMORY; + hr = instrument_create_from_soundfont(&soundfont, i, This, &entry->desc, &entry->instrument); + if (SUCCEEDED(hr)) hr = IDirectMusicInstrument_GetPatch(entry->instrument, &entry->patch); + if (SUCCEEDED(hr)) list_add_tail(&This->instruments, &entry->entry); + else free(entry); + } + if (SUCCEEDED(hr)) { UINT size = offsetof(struct pool, cues[soundfont.sample_count]); diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index d40de3da909..f67bc5c4b2f 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -95,6 +95,8 @@ extern HRESULT DMUSIC_CreateReferenceClockImpl (LPCGUID lpcGUID, LPVOID* ppobj, extern HRESULT download_create(DWORD size, IDirectMusicDownload **ret_iface); struct soundfont; +extern HRESULT instrument_create_from_soundfont(struct soundfont *soundfont, UINT index, + struct collection *collection, DMUS_OBJECTDESC *desc, IDirectMusicInstrument **ret_iface); extern HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent, struct collection *collection, DMUS_OBJECTDESC *desc, IDirectMusicInstrument **ret_iface); extern HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicPortDownload *port, diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index 54ce7508ee4..7a0f8a2f1eb 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -19,11 +19,21 @@ */ #include "dmusic_private.h" +#include "soundfont.h" +#include "dls2.h" WINE_DEFAULT_DEBUG_CHANNEL(dmusic); static const GUID IID_IDirectMusicInstrumentPRIVATE = { 0xbcb20080, 0xa40c, 0x11d1, { 0x86, 0xbc, 0x00, 0xc0, 0x4f, 0xbf, 0x8f, 0xef } }; +#define CONN_SRC_CC2 0x0082 +#define CONN_SRC_RPN0 0x0100 + +#define CONN_TRN_BIPOLAR (1<<4) +#define CONN_TRN_INVERT (1<<5) + +#define CONN_TRANSFORM(src, ctrl, dst) (((src) & 0x3f) << 10) | (((ctrl) & 0x3f) << 4) | ((dst) & 0xf) + struct articulation { struct list entry; @@ -458,6 +468,235 @@ HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent return S_OK; } +struct sf_generators +{ + union sf_amount amount[SF_GEN_END_OPER]; +}; + +static const struct sf_generators SF_DEFAULT_GENERATORS = +{ + .amount = + { + [SF_GEN_INITIAL_FILTER_FC] = {.value = 13500}, + [SF_GEN_DELAY_MOD_LFO] = {.value = -12000}, + [SF_GEN_DELAY_VIB_LFO] = {.value = -12000}, + [SF_GEN_DELAY_MOD_ENV] = {.value = -12000}, + [SF_GEN_ATTACK_MOD_ENV] = {.value = -12000}, + [SF_GEN_HOLD_MOD_ENV] = {.value = -12000}, + [SF_GEN_DECAY_MOD_ENV] = {.value = -12000}, + [SF_GEN_RELEASE_MOD_ENV] = {.value = -12000}, + [SF_GEN_DELAY_VOL_ENV] = {.value = -12000}, + [SF_GEN_ATTACK_VOL_ENV] = {.value = -12000}, + [SF_GEN_HOLD_VOL_ENV] = {.value = -12000}, + [SF_GEN_DECAY_VOL_ENV] = {.value = -12000}, + [SF_GEN_RELEASE_VOL_ENV] = {.value = -12000}, + [SF_GEN_KEY_RANGE] = {.range = {.low = 0, .high = 127}}, + [SF_GEN_VEL_RANGE] = {.range = {.low = 0, .high = 127}}, + [SF_GEN_KEYNUM] = {.value = -1}, + [SF_GEN_VELOCITY] = {.value = -1}, + [SF_GEN_SCALE_TUNING] = {.value = 100}, + [SF_GEN_OVERRIDING_ROOT_KEY] = {.value = -1}, + } +}; + +static BOOL parse_soundfont_generators(struct soundfont *soundfont, UINT index, + struct sf_generators *preset_generators, struct sf_generators *generators) +{ + struct sf_bag *bag = (preset_generators ? soundfont->ibag : soundfont->pbag) + index; + struct sf_gen *gen, *gens = preset_generators ? soundfont->igen : soundfont->pgen; + + for (gen = gens + bag->gen_ndx; gen < gens + (bag + 1)->gen_ndx; gen++) + { + switch (gen->oper) + { + case SF_GEN_START_ADDRS_OFFSET: + case SF_GEN_END_ADDRS_OFFSET: + case SF_GEN_STARTLOOP_ADDRS_OFFSET: + case SF_GEN_ENDLOOP_ADDRS_OFFSET: + case SF_GEN_START_ADDRS_COARSE_OFFSET: + case SF_GEN_END_ADDRS_COARSE_OFFSET: + case SF_GEN_STARTLOOP_ADDRS_COARSE_OFFSET: + case SF_GEN_KEYNUM: + case SF_GEN_VELOCITY: + case SF_GEN_ENDLOOP_ADDRS_COARSE_OFFSET: + case SF_GEN_SAMPLE_MODES: + case SF_GEN_EXCLUSIVE_CLASS: + case SF_GEN_OVERRIDING_ROOT_KEY: + if (preset_generators) generators->amount[gen->oper] = gen->amount; + else WARN("Ignoring invalid preset generator %s\n", debugstr_sf_gen(gen)); + break; + + case SF_GEN_INSTRUMENT: + if (!preset_generators) generators->amount[gen->oper] = gen->amount; + else WARN("Ignoring invalid instrument generator %s\n", debugstr_sf_gen(gen)); + /* should always be the last generator */ + return FALSE; + + case SF_GEN_SAMPLE_ID: + if (preset_generators) generators->amount[gen->oper] = gen->amount; + else WARN("Ignoring invalid preset generator %s\n", debugstr_sf_gen(gen)); + /* should always be the last generator */ + return FALSE; + + default: + generators->amount[gen->oper] = gen->amount; + if (preset_generators) generators->amount[gen->oper].value += preset_generators->amount[gen->oper].value; + break; + } + } + + return TRUE; +} + +static HRESULT instrument_add_soundfont_region(struct instrument *This, struct soundfont *soundfont, + struct sf_generators *generators) +{ + UINT start_loop, end_loop, unity_note, sample_index = generators->amount[SF_GEN_SAMPLE_ID].value; + struct sf_sample *sample = soundfont->shdr + sample_index; + struct region *region; + + if (!(region = calloc(1, sizeof(*region)))) return E_OUTOFMEMORY; + list_init(®ion->articulations); + + region->header.RangeKey.usLow = generators->amount[SF_GEN_KEY_RANGE].range.low; + region->header.RangeKey.usHigh = generators->amount[SF_GEN_KEY_RANGE].range.high; + region->header.RangeVelocity.usLow = generators->amount[SF_GEN_VEL_RANGE].range.low; + region->header.RangeVelocity.usHigh = generators->amount[SF_GEN_VEL_RANGE].range.high; + + region->wave_link.ulTableIndex = sample_index; + + unity_note = generators->amount[SF_GEN_OVERRIDING_ROOT_KEY].value; + if (unity_note == -1) unity_note = sample->original_key; + region->wave_sample.usUnityNote = unity_note; + region->wave_sample.sFineTune = generators->amount[SF_GEN_FINE_TUNE].value; + region->wave_sample.lAttenuation = sample->correction; + + start_loop = generators->amount[SF_GEN_STARTLOOP_ADDRS_OFFSET].value; + end_loop = generators->amount[SF_GEN_ENDLOOP_ADDRS_OFFSET].value; + if (start_loop || end_loop) + { + region->loop_present = TRUE; + region->wave_sample.cSampleLoops = 1; + region->wave_loop.ulStart = start_loop; + region->wave_loop.ulLength = end_loop - start_loop; + } + + list_add_tail(&This->regions, ®ion->entry); + This->header.cRegions++; + return S_OK; +} + +static HRESULT instrument_add_soundfont_instrument(struct instrument *This, struct soundfont *soundfont, + UINT index, struct sf_generators *preset_generators) +{ + struct sf_generators global_generators = SF_DEFAULT_GENERATORS; + struct sf_instrument *instrument = soundfont->inst + index; + UINT i = instrument->bag_ndx; + HRESULT hr = S_OK; + + for (i = instrument->bag_ndx; SUCCEEDED(hr) && i < (instrument + 1)->bag_ndx; i++) + { + struct sf_generators generators = global_generators; + + if (parse_soundfont_generators(soundfont, i, preset_generators, &generators)) + { + if (i > instrument->bag_ndx) + WARN("Ignoring instrument zone without a sample id\n"); + else + global_generators = generators; + continue; + } + + hr = instrument_add_soundfont_region(This, soundfont, &generators); + } + + return hr; +} + +HRESULT instrument_create_from_soundfont(struct soundfont *soundfont, UINT index, + struct collection *collection, DMUS_OBJECTDESC *desc, IDirectMusicInstrument **ret_iface) +{ + struct sf_preset *preset = soundfont->phdr + index; + struct sf_generators global_generators = {0}; + IDirectMusicInstrument *iface; + struct instrument *This; + HRESULT hr; + UINT i; + + TRACE("(%p, %u, %p, %p, %p)\n", soundfont, index, collection, desc, ret_iface); + + if (FAILED(hr = instrument_create(collection, &iface))) return hr; + This = impl_from_IDirectMusicInstrument(iface); + + This->header.Locale.ulBank = (preset->bank & 0x7f) | ((preset->bank << 1) & 0x7f00); + This->header.Locale.ulInstrument = preset->preset; + MultiByteToWideChar(CP_ACP, 0, preset->name, strlen(preset->name) + 1, + desc->wszName, sizeof(desc->wszName)); + + for (i = preset->bag_ndx; SUCCEEDED(hr) && i < (preset + 1)->bag_ndx; i++) + { + struct sf_generators generators = global_generators; + UINT instrument; + + if (parse_soundfont_generators(soundfont, i, NULL, &generators)) + { + if (i > preset->bag_ndx) + WARN("Ignoring preset zone without an instrument\n"); + else + global_generators = generators; + continue; + } + + instrument = generators.amount[SF_GEN_INSTRUMENT].value; + hr = instrument_add_soundfont_instrument(This, soundfont, instrument, &generators); + } + + if (FAILED(hr)) + { + IDirectMusicInstrument_Release(iface); + return hr; + } + + if (TRACE_ON(dmusic)) + { + struct region *region; + UINT i; + + TRACE("Created DirectMusicInstrument %p\n", This); + TRACE(" - header:\n"); + TRACE(" - regions: %ld\n", This->header.cRegions); + TRACE(" - locale: {bank: %#lx, instrument: %#lx} (patch %#lx)\n", + This->header.Locale.ulBank, This->header.Locale.ulInstrument, + MIDILOCALE2Patch(&This->header.Locale)); + if (desc->dwValidData & DMUS_OBJ_OBJECT) TRACE(" - guid: %s\n", debugstr_dmguid(&desc->guidObject)); + if (desc->dwValidData & DMUS_OBJ_NAME) TRACE(" - name: %s\n", debugstr_w(desc->wszName)); + + TRACE(" - regions:\n"); + LIST_FOR_EACH_ENTRY(region, &This->regions, struct region, entry) + { + TRACE(" - region:\n"); + TRACE(" - header: {key: %u - %u, vel: %u - %u, options: %#x, group: %#x}\n", + region->header.RangeKey.usLow, region->header.RangeKey.usHigh, + region->header.RangeVelocity.usLow, region->header.RangeVelocity.usHigh, + region->header.fusOptions, region->header.usKeyGroup); + TRACE(" - wave_link: {options: %#x, group: %u, channel: %lu, index: %lu}\n", + region->wave_link.fusOptions, region->wave_link.usPhaseGroup, + region->wave_link.ulChannel, region->wave_link.ulTableIndex); + TRACE(" - wave_sample: {size: %lu, unity_note: %u, fine_tune: %d, attenuation: %ld, options: %#lx, loops: %lu}\n", + region->wave_sample.cbSize, region->wave_sample.usUnityNote, + region->wave_sample.sFineTune, region->wave_sample.lAttenuation, + region->wave_sample.fulOptions, region->wave_sample.cSampleLoops); + for (i = 0; i < region->wave_sample.cSampleLoops; i++) + TRACE(" - wave_loop[%u]: {size: %lu, type: %lu, start: %lu, length: %lu}\n", i, + region->wave_loop.cbSize, region->wave_loop.ulType, + region->wave_loop.ulStart, region->wave_loop.ulLength); + } + } + + *ret_iface = iface; + return S_OK; +} + static void write_articulation_download(struct list *articulations, ULONG *offsets, BYTE **ptr, UINT index, DWORD *first, UINT *end) { diff --git a/dlls/dmusic/tests/dmusic.c b/dlls/dmusic/tests/dmusic.c index cf0faaa5b87..51a6b0d8774 100644 --- a/dlls/dmusic/tests/dmusic.c +++ b/dlls/dmusic/tests/dmusic.c @@ -1619,7 +1619,7 @@ static void test_default_gm_collection(void) } if (hr == S_FALSE) i--; ok(hr == S_FALSE, "got %#lx\n", hr); - todo_wine ok(i > 0, "got %lu\n", i); + ok(i > 0, "got %lu\n", i); todo_wine ok(i == ARRAY_SIZE(expected), "got %lu\n", i); qsort(results, i, sizeof(*results), result_cmp); @@ -1628,6 +1628,7 @@ static void test_default_gm_collection(void) { winetest_push_context("%lu", i); trace("got %#lx %s\n", results[i].patch, debugstr_w(results[i].name)); + todo_wine_if(expected[i].patch >= 128) ok(results[i].patch == expected[i].patch, "got %#lx\n", results[i].patch); /* system soundfont names are not very predictable, let's not check them */ winetest_pop_context(); From 50b95d0b792565e20634f39a083c6446d55a2210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 21 Sep 2023 12:25:35 +0200 Subject: [PATCH 2587/2777] dmime/tests: Add some tests for GUID_ConnectToDLSCollection. (cherry picked from commit 0d3b83c021455654aa02ccd05ef56a8d3e63ef5f) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 46 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 57879f52069..f69e42d2fec 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3627,6 +3627,51 @@ static void test_band_track_play(void) IDirectMusicTool_Release(tool); } +static void test_connect_to_collection(void) +{ + IDirectMusicCollection *collection; + IDirectMusicSegment *segment; + IDirectMusicTrack *track; + void *param; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_DirectMusicCollection, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicCollection, (void **)&collection); + ok(hr == S_OK, "got %#lx\n", hr); + hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicSegment, (void **)&segment); + ok(hr == S_OK, "got %#lx\n", hr); + hr = CoCreateInstance(&CLSID_DirectMusicBandTrack, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicTrack, (void **)&track); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicSegment_InsertTrack(segment, track, 1); + ok(hr == S_OK, "got %#lx\n", hr); + + /* it is possible to connect the band track to another collection, but not to disconnect it */ + hr = IDirectMusicTrack_IsParamSupported(track, &GUID_ConnectToDLSCollection); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicTrack_SetParam(track, &GUID_ConnectToDLSCollection, 0, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicTrack_SetParam(track, &GUID_ConnectToDLSCollection, 0, collection); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicTrack_GetParam(track, &GUID_ConnectToDLSCollection, 0, NULL, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicTrack_GetParam(track, &GUID_ConnectToDLSCollection, 0, NULL, ¶m); + ok(hr == DMUS_E_GET_UNSUPPORTED, "got %#lx\n", hr); + + hr = IDirectMusicSegment_SetParam(segment, &GUID_ConnectToDLSCollection, -1, DMUS_SEG_ALLTRACKS, 0, NULL); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicSegment_SetParam(segment, &GUID_ConnectToDLSCollection, -1, DMUS_SEG_ALLTRACKS, 0, collection); + ok(hr == S_OK, "got %#lx\n", hr); + + IDirectMusicTrack_Release(track); + IDirectMusicSegment_Release(segment); + IDirectMusicCollection_Release(collection); +} + START_TEST(dmime) { CoInitialize(NULL); @@ -3662,6 +3707,7 @@ START_TEST(dmime) test_wave_pmsg(); test_sequence_track(); test_band_track_play(); + test_connect_to_collection(); CoUninitialize(); } From 6e1d37eb9764f1bf4907924eec2ce045ffd4292c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 29 Sep 2023 09:02:56 +0200 Subject: [PATCH 2588/2777] dmime/tests: Test segment state and playing a custom track. (cherry picked from commit 406f1783a926b0ff404e897650739a9fcaecb2df) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 443 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 443 insertions(+) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index f69e42d2fec..cfd58b8b229 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -555,6 +555,228 @@ static HRESULT test_loader_stream_create(IStream *stream, IDirectMusicLoader *lo return S_OK; } +struct test_track +{ + /* Implementing IDirectMusicTrack8 will cause native to call PlayEx */ + IDirectMusicTrack IDirectMusicTrack_iface; + LONG ref; + + DWORD data; + BOOL inserted; + BOOL initialized; + BOOL downloaded; + BOOL playing; + HANDLE playing_event; +}; + +#define check_track_state(track, state, value) \ + do \ + { \ + DWORD ret = impl_from_IDirectMusicTrack(track)->state; \ + ok(ret == (value), "got %#lx\n", ret); \ + } while (0); + +static inline struct test_track *impl_from_IDirectMusicTrack(IDirectMusicTrack *iface) +{ + return CONTAINING_RECORD(iface, struct test_track, IDirectMusicTrack_iface); +} + +static HRESULT WINAPI test_track_QueryInterface(IDirectMusicTrack *iface, REFIID riid, + void **ret_iface) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + + if (IsEqualIID(riid, &IID_IUnknown) + || IsEqualIID(riid, &IID_IDirectMusicTrack)) + { + *ret_iface = &This->IDirectMusicTrack_iface; + IDirectMusicTrack_AddRef(&This->IDirectMusicTrack_iface); + return S_OK; + } + + ok(IsEqualGUID(riid, &IID_IDirectMusicTrack8) || IsEqualGUID(riid, &IID_IPersistStream), + "unexpected %s %p %s\n", __func__, This, debugstr_guid(riid)); + *ret_iface = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI test_track_AddRef(IDirectMusicTrack *iface) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI test_track_Release(IDirectMusicTrack *iface) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + if (!ref) + { + CloseHandle(This->playing_event); + free(This); + } + + return ref; +} + +static HRESULT WINAPI test_track_Init(IDirectMusicTrack *iface, IDirectMusicSegment *segment) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + This->inserted = TRUE; + return S_OK; +} + +static HRESULT WINAPI test_track_InitPlay(IDirectMusicTrack *iface, IDirectMusicSegmentState *segment_state, + IDirectMusicPerformance *performance, void **state_data, DWORD track_id, DWORD segment_flags) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + + ok(!!segment_state, "got %p\n", segment_state); + ok(!!performance, "got %p\n", performance); + ok(!!state_data, "got %p\n", state_data); + ok(!!track_id, "got %lu\n", track_id); + ok(!segment_flags, "got %#lx\n", segment_flags); + This->initialized = TRUE; + + *state_data = &This->data; + return S_OK; +} + +static HRESULT WINAPI test_track_EndPlay(IDirectMusicTrack *iface, void *state_data) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + + ok(state_data == &This->data, "got %p\n", state_data); + This->playing = FALSE; + + return S_OK; +} + +static HRESULT WINAPI test_track_Play(IDirectMusicTrack *iface, void *state_data, + MUSIC_TIME start_time, MUSIC_TIME end_time, MUSIC_TIME time_offset, DWORD segment_flags, + IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state, DWORD track_id) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + + ok(state_data == &This->data, "got %p\n", state_data); + ok(start_time == 50, "got %lu\n", start_time); + ok(end_time == 100, "got %lu\n", end_time); + ok(time_offset < 0, "got %lu\n", time_offset); + ok(segment_flags == (DMUS_TRACKF_DIRTY|DMUS_TRACKF_START|DMUS_TRACKF_SEEK), + "got %#lx\n", segment_flags); + ok(!!performance, "got %p\n", performance); + ok(!!segment_state, "got %p\n", segment_state); + ok(!!track_id, "got %lu\n", track_id); + This->playing = TRUE; + SetEvent(This->playing_event); + + return S_OK; +} + +static HRESULT WINAPI test_track_GetParam(IDirectMusicTrack *iface, REFGUID type, MUSIC_TIME time, + MUSIC_TIME *next, void *param) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + ok(0, "unexpected %s %p\n", __func__, This); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_track_SetParam(IDirectMusicTrack *iface, REFGUID type, MUSIC_TIME time, void *param) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + + if (IsEqualGUID(type, &GUID_DownloadToAudioPath)) + { + This->downloaded = TRUE; + return S_OK; + } + + if (IsEqualGUID(type, &GUID_UnloadFromAudioPath)) + { + This->downloaded = FALSE; + return S_OK; + } + + ok(0, "unexpected %s %p %s %lu %p\n", __func__, This, debugstr_guid(type), time, param); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_track_IsParamSupported(IDirectMusicTrack *iface, REFGUID type) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + + if (IsEqualGUID(type, &GUID_DownloadToAudioPath)) return S_OK; + if (IsEqualGUID(type, &GUID_UnloadFromAudioPath)) return S_OK; + if (IsEqualGUID(type, &GUID_TimeSignature)) return DMUS_E_TYPE_UNSUPPORTED; + if (IsEqualGUID(type, &GUID_TempoParam)) return DMUS_E_TYPE_UNSUPPORTED; + + ok(broken(type->Data1 == 0xe8dbd832), /* native also checks some unknown parameter */ + "unexpected %s %p %s\n", __func__, This, debugstr_guid(type)); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_track_AddNotificationType(IDirectMusicTrack *iface, REFGUID type) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + ok(0, "unexpected %s %p\n", __func__, This); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_track_RemoveNotificationType(IDirectMusicTrack *iface, REFGUID type) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + ok(0, "unexpected %s %p\n", __func__, This); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_track_Clone(IDirectMusicTrack *iface, MUSIC_TIME start_time, + MUSIC_TIME end_time, IDirectMusicTrack **ret_track) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + ok(0, "unexpected %s %p\n", __func__, This); + return E_NOTIMPL; +} + +static const IDirectMusicTrackVtbl test_track_vtbl = +{ + test_track_QueryInterface, + test_track_AddRef, + test_track_Release, + test_track_Init, + test_track_InitPlay, + test_track_EndPlay, + test_track_Play, + test_track_GetParam, + test_track_SetParam, + test_track_IsParamSupported, + test_track_AddNotificationType, + test_track_RemoveNotificationType, + test_track_Clone, +}; + +static HRESULT test_track_create(IDirectMusicTrack **ret_iface) +{ + struct test_track *track; + + *ret_iface = NULL; + if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; + track->IDirectMusicTrack_iface.lpVtbl = &test_track_vtbl; + track->ref = 1; + + track->playing_event = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(!!track->playing_event, "CreateEventW failed, error %lu\n", GetLastError()); + + *ret_iface = &track->IDirectMusicTrack_iface; + return S_OK; +} + +static DWORD test_track_wait_playing(IDirectMusicTrack *iface, DWORD timeout) +{ + struct test_track *This = impl_from_IDirectMusicTrack(iface); + return WaitForSingleObject(This->playing_event, timeout); +} + static void create_performance(IDirectMusicPerformance8 **performance, IDirectMusic **dmusic, IDirectSound **dsound, BOOL set_cooplevel) { @@ -3672,6 +3894,226 @@ static void test_connect_to_collection(void) IDirectMusicCollection_Release(collection); } +static void test_segment_state(void) +{ + static const DWORD message_types[] = + { + DMUS_PMSGT_DIRTY, + DMUS_PMSGT_NOTIFICATION, + DMUS_PMSGT_WAVE, + }; + IDirectMusicSegmentState *state, *tmp_state; + IDirectMusicSegment *segment, *tmp_segment; + IDirectMusicPerformance *performance; + IDirectMusicTrack *track; + IDirectMusicGraph *graph; + IDirectMusicTool *tool; + DWORD value, ret; + MUSIC_TIME time; + HRESULT hr; + + hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool); + ok(hr == S_OK, "got %#lx\n", hr); + hr = test_track_create(&track); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicPerformance, (void **)&performance); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicGraph, (void **)&graph); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_SetGraph(performance, graph); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicGraph_Release(graph); + + + hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicSegment, (void **)&segment); + ok(hr == S_OK, "got %#lx\n", hr); + + check_track_state(track, inserted, FALSE); + hr = IDirectMusicSegment_InsertTrack(segment, track, 1); + ok(hr == S_OK, "got %#lx\n", hr); + check_track_state(track, inserted, TRUE); + + check_track_state(track, downloaded, FALSE); + hr = IDirectMusicSegment8_Download((IDirectMusicSegment8 *)segment, (IUnknown *)performance); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine check_track_state(track, downloaded, TRUE); + hr = IDirectMusicSegment8_Unload((IDirectMusicSegment8 *)segment, (IUnknown *)performance); + ok(hr == S_OK, "got %#lx\n", hr); + check_track_state(track, downloaded, FALSE); + + + /* by default the segment length is 1 */ + + time = 0xdeadbeef; + hr = IDirectMusicSegment_GetLength(segment, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 1, "got %lu\n", time); + hr = IDirectMusicSegment_SetStartPoint(segment, 50); + ok(hr == DMUS_E_OUT_OF_RANGE, "got %#lx\n", hr); + hr = IDirectMusicSegment_SetRepeats(segment, 10); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSegment_SetLoopPoints(segment, 10, 70); + ok(hr == DMUS_E_OUT_OF_RANGE, "got %#lx\n", hr); + + /* Setting a larger length will cause PlayEx to be called multiple times, + * as native splits the segment into chunks and play each chunk separately */ + hr = IDirectMusicSegment_SetLength(segment, 100); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSegment_SetStartPoint(segment, 50); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSegment_SetRepeats(segment, 0); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSegment_SetLoopPoints(segment, 0, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + + /* InitPlay returns a dummy segment state */ + + state = (void *)0xdeadbeef; + hr = IDirectMusicSegment_InitPlay(segment, &state, performance, 0); + ok(hr == S_OK, "got %#lx\n", hr); + ok(state != NULL, "got %p\n", state); + ok(state != (void *)0xdeadbeef, "got %p\n", state); + check_track_state(track, initialized, FALSE); + + tmp_segment = (void *)0xdeadbeef; + hr = IDirectMusicSegmentState_GetSegment(state, &tmp_segment); + todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); + todo_wine ok(tmp_segment == NULL, "got %p\n", tmp_segment); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetStartPoint(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 0, "got %#lx\n", time); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetRepeats(state, &value); + ok(hr == S_OK, "got %#lx\n", hr); + ok(time == 0xdeadbeef, "got %#lx\n", time); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetStartTime(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == -1, "got %#lx\n", time); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetSeek(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 0, "got %#lx\n", time); + + + /* PlaySegment returns a different, genuine segment state */ + + hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + check_track_state(track, downloaded, FALSE); + check_track_state(track, initialized, FALSE); + check_track_state(track, playing, FALSE); + + tmp_state = state; + state = (void *)0xdeadbeef; + hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 20, &state); + ok(hr == S_OK, "got %#lx\n", hr); + ok(state != NULL, "got %p\n", state); + ok(state != (void *)0xdeadbeef, "got %p\n", state); + ok(state != tmp_state, "got %p\n", state); + IDirectMusicSegmentState_Release(tmp_state); + + check_track_state(track, downloaded, FALSE); + todo_wine check_track_state(track, initialized, TRUE); + + + /* The track can be removed from the segment */ + hr = IDirectMusicSegment_RemoveTrack(segment, track); + ok(hr == S_OK, "got %#lx\n", hr); + + + /* This might be timing dependent and if PlaySegment is already + * late, the tracks are played synchronously and right away. + */ + check_track_state(track, playing, FALSE); + + ret = test_track_wait_playing(track, 50); + todo_wine ok(ret == 0, "got %#lx\n", ret); + + + tmp_segment = (void *)0xdeadbeef; + hr = IDirectMusicSegmentState_GetSegment(state, &tmp_segment); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(tmp_segment == segment, "got %p\n", tmp_segment); + if (tmp_segment != (void *)0xdeadbeef) IDirectMusicSegment_Release(tmp_segment); + + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetStartPoint(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 50, "got %lu\n", time); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetRepeats(state, &value); + ok(hr == S_OK, "got %#lx\n", hr); + ok(time == 0xdeadbeef, "got %#lx\n", time); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetStartTime(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 20, "got %#lx\n", time); + time = 0xdeadbeef; + + /* The seek value is also dependent on whether the tracks are playing. + * It is initially 0, then start_point right before playing, then length. + */ + hr = IDirectMusicSegmentState_GetSeek(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 100, "got %#lx\n", time); + + /* changing the segment values doesn't change the segment state */ + + hr = IDirectMusicSegment_SetStartPoint(segment, 0); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSegment_SetRepeats(segment, 10); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSegment_SetLoopPoints(segment, 50, 70); + ok(hr == S_OK, "got %#lx\n", hr); + + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetStartPoint(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 50, "got %#lx\n", time); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetRepeats(state, &value); + ok(hr == S_OK, "got %#lx\n", hr); + ok(time == 0xdeadbeef, "got %#lx\n", time); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetStartTime(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 20, "got %#lx\n", time); + time = 0xdeadbeef; + hr = IDirectMusicSegmentState_GetSeek(state, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(time == 100, "got %#lx\n", time); + + IDirectMusicSegment_Release(segment); + + + check_track_state(track, downloaded, FALSE); + todo_wine check_track_state(track, initialized, TRUE); + todo_wine check_track_state(track, playing, TRUE); + + hr = IDirectMusicPerformance_CloseDown(performance); + ok(hr == S_OK, "got %#lx\n", hr); + + check_track_state(track, downloaded, FALSE); + todo_wine check_track_state(track, initialized, TRUE); + check_track_state(track, playing, FALSE); + + + IDirectMusicPerformance_Release(performance); + IDirectMusicTrack_Release(track); + IDirectMusicTool_Release(tool); +} + START_TEST(dmime) { CoInitialize(NULL); @@ -3708,6 +4150,7 @@ START_TEST(dmime) test_sequence_track(); test_band_track_play(); test_connect_to_collection(); + test_segment_state(); CoUninitialize(); } From 4c7e2a4e1edabf6de548cb298c3a4c36b8a221fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 6 Sep 2023 09:54:12 +0200 Subject: [PATCH 2589/2777] dmime: Implement IDirectMusicSegment_SetParam. (cherry picked from commit 8645d9eb4e97c7347405a51518b6a31b0ac7deef) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segment.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index a72ec786623..bc52931f667 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -392,12 +392,28 @@ static HRESULT WINAPI segment_GetParam(IDirectMusicSegment8 *iface, REFGUID type return hr; } -static HRESULT WINAPI segment_SetParam(IDirectMusicSegment8 *iface, REFGUID rguidType, - DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, void *pParam) +static HRESULT WINAPI segment_SetParam(IDirectMusicSegment8 *iface, REFGUID type, + DWORD group, DWORD index, MUSIC_TIME music_time, void *param) { struct segment *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %s, %#lx, %ld, %ld, %p): stub\n", This, debugstr_dmguid(rguidType), dwGroupBits, - dwIndex, mtTime, pParam); + struct track_entry *entry; + HRESULT hr; + + TRACE("(%p, %s, %#lx, %ld, %ld, %p)\n", This, debugstr_dmguid(type), group, + index, music_time, param); + + LIST_FOR_EACH_ENTRY(entry, &This->tracks, struct track_entry, entry) + { + if (group != -1 && !(group & entry->dwGroupBits)) continue; + if (index != DMUS_SEG_ALLTRACKS && index--) continue; + + hr = IDirectMusicTrack_IsParamSupported(entry->pTrack, type); + if (hr == DMUS_E_TYPE_UNSUPPORTED) continue; + + hr = IDirectMusicTrack_SetParam(entry->pTrack, type, music_time, param); + if (FAILED(hr)) break; + } + return S_OK; } From b8a957c0670d9a1bd44ae3bcab4e865c69247852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 21 Sep 2023 12:08:42 +0200 Subject: [PATCH 2590/2777] dmband: Implement band track GUID_ConnectToDLSCollection parameter. (cherry picked from commit 92985253e757202cc24b2ed933e099f44e936c93) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/band.c | 26 ++++++++++++++++++++++ dlls/dmband/bandtrack.c | 7 +++++- dlls/dmband/dmband_private.h | 2 ++ dlls/dmusic/dmobject.c | 43 +++++++++++++++++++++++++----------- dlls/dmusic/dmobject.h | 3 +++ 5 files changed, 67 insertions(+), 14 deletions(-) diff --git a/dlls/dmband/band.c b/dlls/dmband/band.c index d91775681bb..361df5f8986 100644 --- a/dlls/dmband/band.c +++ b/dlls/dmband/band.c @@ -59,6 +59,7 @@ struct band struct dmobject dmobj; LONG ref; struct list instruments; + IDirectMusicCollection *collection; }; static inline struct band *impl_from_IDirectMusicBand(IDirectMusicBand *iface) @@ -117,6 +118,7 @@ static ULONG WINAPI band_Release(IDirectMusicBand *iface) instrument_entry_destroy(entry); } + if (This->collection) IDirectMusicCollection_Release(This->collection); free(This); } @@ -336,11 +338,23 @@ static inline struct band *impl_from_IPersistStream(IPersistStream *iface) static HRESULT WINAPI band_persist_stream_Load(IPersistStream *iface, IStream *stream) { struct band *This = impl_from_IPersistStream(iface); + DMUS_OBJECTDESC default_desc = + { + .dwSize = sizeof(DMUS_OBJECTDESC), + .dwValidData = DMUS_OBJ_OBJECT | DMUS_OBJ_CLASS, + .guidClass = CLSID_DirectMusicCollection, + .guidObject = GUID_DefaultGMCollection, + }; struct chunk_entry chunk = {0}; HRESULT hr; TRACE("%p, %p\n", iface, stream); + if (This->collection) IDirectMusicCollection_Release(This->collection); + if (FAILED(hr = stream_get_object(stream, &default_desc, &IID_IDirectMusicCollection, + (void **)&This->collection))) + WARN("Failed to load default collection from loader, hr %#lx\n", hr); + if ((hr = stream_get_chunk(stream, &chunk)) == S_OK) { switch (MAKE_IDTYPE(chunk.id, chunk.type)) @@ -408,3 +422,15 @@ HRESULT create_dmband(REFIID lpcGUID, void **ppobj) return hr; } + +HRESULT band_connect_to_collection(IDirectMusicBand *iface, IDirectMusicCollection *collection) +{ + struct band *This = impl_from_IDirectMusicBand(iface); + + TRACE("%p, %p\n", iface, collection); + + if (This->collection) IDirectMusicCollection_Release(This->collection); + if ((This->collection = collection)) IDirectMusicCollection_AddRef(This->collection); + + return S_OK; +} diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index ab12e1f1355..45dc7ace86a 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -182,7 +182,12 @@ static HRESULT WINAPI band_track_SetParam(IDirectMusicTrack8 *iface, REFGUID typ else if (IsEqualGUID(type, &GUID_Clear_All_Bands)) FIXME("GUID_Clear_All_Bands not handled yet\n"); else if (IsEqualGUID(type, &GUID_ConnectToDLSCollection)) - FIXME("GUID_ConnectToDLSCollection not handled yet\n"); + { + struct band_entry *entry; + + LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry) + band_connect_to_collection(entry->band, param); + } else if (IsEqualGUID(type, &GUID_Disable_Auto_Download)) FIXME("GUID_Disable_Auto_Download not handled yet\n"); else if (IsEqualGUID(type, &GUID_Download)) diff --git a/dlls/dmband/dmband_private.h b/dlls/dmband/dmband_private.h index 444fe5ccf55..a12b9f8cc82 100644 --- a/dlls/dmband/dmband_private.h +++ b/dlls/dmband/dmband_private.h @@ -47,4 +47,6 @@ extern HRESULT create_dmband(REFIID riid, void **ret_iface); extern HRESULT create_dmbandtrack(REFIID riid, void **ret_iface); +extern HRESULT band_connect_to_collection(IDirectMusicBand *iface, IDirectMusicCollection *collection); + #endif /* __WINE_DMBAND_PRIVATE_H */ diff --git a/dlls/dmusic/dmobject.c b/dlls/dmusic/dmobject.c index 3007aceef3e..8cb4719c4e6 100644 --- a/dlls/dmusic/dmobject.c +++ b/dlls/dmusic/dmobject.c @@ -444,6 +444,35 @@ HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, return S_OK; } +HRESULT stream_get_loader(IStream *stream, IDirectMusicLoader **ret_loader) +{ + IDirectMusicGetLoader *getter; + HRESULT hr; + + if (SUCCEEDED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getter))) + { + hr = IDirectMusicGetLoader_GetLoader(getter, ret_loader); + IDirectMusicGetLoader_Release(getter); + } + + if (FAILED(hr)) *ret_loader = NULL; + return hr; +} + +HRESULT stream_get_object(IStream *stream, DMUS_OBJECTDESC *desc, REFIID iid, void **ret_iface) +{ + IDirectMusicLoader *loader; + HRESULT hr; + + if (SUCCEEDED(hr = stream_get_loader(stream, &loader))) + { + hr = IDirectMusicLoader_GetObject(loader, desc, iid, (void **)ret_iface); + IDirectMusicLoader_Release(loader); + } + + if (FAILED(hr)) *ret_iface = NULL; + return hr; +} /* Generic IDirectMusicObject methods */ @@ -626,8 +655,6 @@ HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, IDirectMusicObject **dmobj) { struct chunk_entry chunk = {.parent = list}; - IDirectMusicGetLoader *getloader; - IDirectMusicLoader *loader; DMUS_OBJECTDESC desc; DMUS_IO_REFERENCE reference; HRESULT hr; @@ -650,17 +677,7 @@ HRESULT dmobj_parsereference(IStream *stream, const struct chunk_entry *list, desc.dwValidData |= DMUS_OBJ_CLASS; dump_DMUS_OBJECTDESC(&desc); - if (FAILED(hr = IStream_QueryInterface(stream, &IID_IDirectMusicGetLoader, (void**)&getloader))) - return hr; - hr = IDirectMusicGetLoader_GetLoader(getloader, &loader); - IDirectMusicGetLoader_Release(getloader); - if (FAILED(hr)) - return hr; - - hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicObject, (void**)dmobj); - IDirectMusicLoader_Release(loader); - - return hr; + return stream_get_object(stream, &desc, &IID_IDirectMusicObject, (void **)dmobj); } /* Generic IPersistStream methods */ diff --git a/dlls/dmusic/dmobject.h b/dlls/dmusic/dmobject.h index ae06935dfea..82ac05f31b9 100644 --- a/dlls/dmusic/dmobject.h +++ b/dlls/dmusic/dmobject.h @@ -44,6 +44,9 @@ HRESULT stream_chunk_get_data(IStream *stream, const struct chunk_entry *chunk, HRESULT stream_chunk_get_wstr(IStream *stream, const struct chunk_entry *chunk, WCHAR *str, ULONG size); +HRESULT stream_get_loader(IStream *stream, IDirectMusicLoader **ret_loader); +HRESULT stream_get_object(IStream *stream, DMUS_OBJECTDESC *desc, REFIID riid, void **ret_iface); + static inline HRESULT stream_reset_chunk_data(IStream *stream, const struct chunk_entry *chunk) { LARGE_INTEGER offset; From b96e71d9657d6f73f343edf03f807bf62c9aa043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 26 Sep 2023 09:35:50 +0200 Subject: [PATCH 2591/2777] dmime: Implement IDirectMusicSegment_(Download|Unload). (cherry picked from commit 17f68bfabf5ca35e8483d69bd4b5a88f5e636723) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segment.c | 12 ++++++------ dlls/dmime/tests/dmime.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index bc52931f667..af7729f34b9 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -530,18 +530,18 @@ static HRESULT WINAPI segment_Compose(IDirectMusicSegment8 *iface, MUSIC_TIME mt return S_OK; } -static HRESULT WINAPI segment_Download(IDirectMusicSegment8 *iface, IUnknown *pAudioPath) +static HRESULT WINAPI segment_Download(IDirectMusicSegment8 *iface, IUnknown *audio_path) { struct segment *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %p): stub\n", This, pAudioPath); - return S_OK; + TRACE("(%p, %p)\n", This, audio_path); + return IDirectMusicSegment8_SetParam(iface, &GUID_DownloadToAudioPath, -1, DMUS_SEG_ALLTRACKS, 0, audio_path); } -static HRESULT WINAPI segment_Unload(IDirectMusicSegment8 *iface, IUnknown *pAudioPath) +static HRESULT WINAPI segment_Unload(IDirectMusicSegment8 *iface, IUnknown *audio_path) { struct segment *This = impl_from_IDirectMusicSegment8(iface); - FIXME("(%p, %p): stub\n", This, pAudioPath); - return S_OK; + TRACE("(%p, %p)\n", This, audio_path); + return IDirectMusicSegment8_SetParam(iface, &GUID_UnloadFromAudioPath, -1, DMUS_SEG_ALLTRACKS, 0, audio_path); } static const IDirectMusicSegment8Vtbl segment_vtbl = diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index cfd58b8b229..ea5a972dc80 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3943,7 +3943,7 @@ static void test_segment_state(void) check_track_state(track, downloaded, FALSE); hr = IDirectMusicSegment8_Download((IDirectMusicSegment8 *)segment, (IUnknown *)performance); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine check_track_state(track, downloaded, TRUE); + check_track_state(track, downloaded, TRUE); hr = IDirectMusicSegment8_Unload((IDirectMusicSegment8 *)segment, (IUnknown *)performance); ok(hr == S_OK, "got %#lx\n", hr); check_track_state(track, downloaded, FALSE); From 0adc2e8a74cdae49b011d8cdddc49a8f5f1943ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 21 Sep 2023 11:41:36 +0200 Subject: [PATCH 2592/2777] dmband: Implement IDirectMusicBand_(Download|Unload). (cherry picked from commit 0ad7b553490a5e04a9494ddc07335c857cd0d4ef) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/band.c | 70 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 9 deletions(-) diff --git a/dlls/dmband/band.c b/dlls/dmband/band.c index 361df5f8986..4b3c053c586 100644 --- a/dlls/dmband/band.c +++ b/dlls/dmband/band.c @@ -45,10 +45,30 @@ struct instrument_entry struct list entry; DMUS_IO_INSTRUMENT instrument; IDirectMusicCollection *collection; + + IDirectMusicDownloadedInstrument *download; + IDirectMusicPort *download_port; }; +static HRESULT instrument_entry_unload(struct instrument_entry *entry) +{ + HRESULT hr; + + if (!entry->download) return S_OK; + + if (FAILED(hr = IDirectMusicPort_UnloadInstrument(entry->download_port, entry->download))) + WARN("Failed to unload entry instrument, hr %#lx\n", hr); + IDirectMusicDownloadedInstrument_Release(entry->download); + entry->download = NULL; + IDirectMusicPort_Release(entry->download_port); + entry->download_port = NULL; + + return hr; +} + static void instrument_entry_destroy(struct instrument_entry *entry) { + instrument_entry_unload(entry); if (entry->collection) IDirectMusicCollection_Release(entry->collection); free(entry); } @@ -150,19 +170,51 @@ static HRESULT WINAPI band_CreateSegment(IDirectMusicBand *iface, } static HRESULT WINAPI band_Download(IDirectMusicBand *iface, - IDirectMusicPerformance *pPerformance) + IDirectMusicPerformance *performance) { - struct band *This = impl_from_IDirectMusicBand(iface); - FIXME("(%p, %p): stub\n", This, pPerformance); - return S_OK; + struct band *This = impl_from_IDirectMusicBand(iface); + struct instrument_entry *entry; + HRESULT hr = S_OK; + + TRACE("(%p, %p)\n", This, performance); + + LIST_FOR_EACH_ENTRY(entry, &This->instruments, struct instrument_entry, entry) + { + IDirectMusicCollection *collection; + IDirectMusicInstrument *instrument; + + if (FAILED(hr = instrument_entry_unload(entry))) break; + if (!(collection = entry->collection) && !(collection = This->collection)) continue; + + if (SUCCEEDED(hr = IDirectMusicCollection_GetInstrument(collection, entry->instrument.dwPatch, &instrument))) + { + hr = IDirectMusicPerformance_DownloadInstrument(performance, instrument, entry->instrument.dwPChannel, + &entry->download, NULL, 0, &entry->download_port, NULL, NULL); + IDirectMusicInstrument_Release(instrument); + } + + if (FAILED(hr)) break; + } + + if (FAILED(hr)) WARN("Failed to download instruments, hr %#lx\n", hr); + return hr; } -static HRESULT WINAPI band_Unload(IDirectMusicBand *iface, - IDirectMusicPerformance *pPerformance) +static HRESULT WINAPI band_Unload(IDirectMusicBand *iface, IDirectMusicPerformance *performance) { - struct band *This = impl_from_IDirectMusicBand(iface); - FIXME("(%p, %p): stub\n", This, pPerformance); - return S_OK; + struct band *This = impl_from_IDirectMusicBand(iface); + struct instrument_entry *entry; + HRESULT hr = S_OK; + + TRACE("(%p, %p)\n", This, performance); + + if (performance) FIXME("performance parameter not implemented\n"); + + LIST_FOR_EACH_ENTRY(entry, &This->instruments, struct instrument_entry, entry) + if (FAILED(hr = instrument_entry_unload(entry))) break; + + if (FAILED(hr)) WARN("Failed to unload instruments, hr %#lx\n", hr); + return hr; } static const IDirectMusicBandVtbl band_vtbl = From d963859faf01f6921421514331d66b35e6227eb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 21 Sep 2023 12:08:42 +0200 Subject: [PATCH 2593/2777] dmband: Implement band track GUID_UnloadFromAudioPath parameter. (cherry picked from commit 52a38dc41fde3d3636c10c49f1896807b244313f) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/bandtrack.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index 45dc7ace86a..b808faaf567 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -201,7 +201,13 @@ static HRESULT WINAPI band_track_SetParam(IDirectMusicTrack8 *iface, REFGUID typ else if (IsEqualGUID(type, &GUID_StandardMIDIFile)) FIXME("GUID_StandardMIDIFile not handled yet\n"); else if (IsEqualGUID(type, &GUID_UnloadFromAudioPath)) - FIXME("GUID_UnloadFromAudioPath not handled yet\n"); + { + struct band_entry *entry; + HRESULT hr; + + LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry) + if (FAILED(hr = IDirectMusicBand_Unload(entry->band, NULL))) break; + } return S_OK; } From 0e5088cf61703083a035966c9bceec45cedc3252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 21 Sep 2023 12:08:42 +0200 Subject: [PATCH 2594/2777] dmband: Implement band track GUID_DownloadToAudioPath parameter. (cherry picked from commit 96b0bdd7b59b2c5c52b2b9a05d629cc2596cef5a) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/bandtrack.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index b808faaf567..845345a9fa2 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -193,7 +193,32 @@ static HRESULT WINAPI band_track_SetParam(IDirectMusicTrack8 *iface, REFGUID typ else if (IsEqualGUID(type, &GUID_Download)) FIXME("GUID_Download not handled yet\n"); else if (IsEqualGUID(type, &GUID_DownloadToAudioPath)) - FIXME("GUID_DownloadToAudioPath not handled yet\n"); + { + IDirectMusicPerformance *performance; + IDirectMusicAudioPath *audio_path; + IUnknown *object = param; + struct band_entry *entry; + HRESULT hr; + + if (FAILED(hr = IDirectMusicAudioPath_QueryInterface(object, &IID_IDirectMusicPerformance8, (void **)&performance)) + && SUCCEEDED(hr = IDirectMusicAudioPath_QueryInterface(object, &IID_IDirectMusicAudioPath, (void **)&audio_path))) + { + hr = IDirectMusicAudioPath_GetObjectInPath(audio_path, DMUS_PCHANNEL_ALL, DMUS_PATH_PERFORMANCE, 0, + &GUID_All_Objects, 0, &IID_IDirectMusicPerformance8, (void **)&performance); + IDirectMusicAudioPath_Release(audio_path); + } + + if (FAILED(hr)) + { + WARN("Failed to get IDirectMusicPerformance from param %p\n", param); + return hr; + } + + LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry) + if (FAILED(hr = IDirectMusicBand_Download(entry->band, performance))) break; + + IDirectMusicPerformance_Release(performance); + } else if (IsEqualGUID(type, &GUID_Enable_Auto_Download)) FIXME("GUID_Enable_Auto_Download not handled yet\n"); else if (IsEqualGUID(type, &GUID_IDirectMusicBand)) From de6cdb5ec2bb6027a0ea103168c3938475f19a93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 6 Sep 2023 09:54:22 +0200 Subject: [PATCH 2595/2777] dmime: Implement IDirectMusicPerformance_DownloadInstrument. (cherry picked from commit 3c4d83609e16ad326685f01e7245684d7f526225) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index bdb7475370a..111d7c60568 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -828,14 +828,24 @@ static HRESULT WINAPI performance_PChannelInfo(IDirectMusicPerformance8 *iface, } static HRESULT WINAPI performance_DownloadInstrument(IDirectMusicPerformance8 *iface, - IDirectMusicInstrument *pInst, DWORD dwPChannel, - IDirectMusicDownloadedInstrument **ppDownInst, DMUS_NOTERANGE *pNoteRanges, - DWORD dwNumNoteRanges, IDirectMusicPort **ppPort, DWORD *pdwGroup, DWORD *pdwMChannel) + IDirectMusicInstrument *instrument, DWORD port_channel, + IDirectMusicDownloadedInstrument **downloaded, DMUS_NOTERANGE *note_ranges, + DWORD note_range_count, IDirectMusicPort **port, DWORD *group, DWORD *music_channel) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + IDirectMusicPort *tmp_port = NULL; + HRESULT hr; - FIXME("(%p, %p, %ld, %p, %p, %ld, %p, %p, %p): stub\n", This, pInst, dwPChannel, ppDownInst, pNoteRanges, dwNumNoteRanges, ppPort, pdwGroup, pdwMChannel); - return S_OK; + TRACE("(%p, %p, %ld, %p, %p, %ld, %p, %p, %p)\n", This, instrument, port_channel, downloaded, + note_ranges, note_range_count, port, group, music_channel); + + if (!port) port = &tmp_port; + if (FAILED(hr = IDirectMusicPerformance_PChannelInfo(iface, port_channel, port, group, music_channel))) + return hr; + + hr = IDirectMusicPort_DownloadInstrument(*port, instrument, downloaded, note_ranges, note_range_count); + if (tmp_port) IDirectMusicPort_Release(tmp_port); + return hr; } static HRESULT WINAPI performance_Invalidate(IDirectMusicPerformance8 *iface, MUSIC_TIME mtTime, DWORD dwFlags) From b050c53078293709ab099d5e638c386c4f6ccd96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 22 Sep 2023 09:30:08 +0200 Subject: [PATCH 2596/2777] dmime: Rename DirectMusicSegmentState8 method prefix to segment_state. (cherry picked from commit 939162b674049a3e5a2266384e35aa52244deb1e) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segmentstate.c | 49 +++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index 1a0b63419f0..3a5eee72a57 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -32,7 +32,7 @@ static inline IDirectMusicSegmentState8Impl *impl_from_IDirectMusicSegmentState8 return CONTAINING_RECORD(iface, IDirectMusicSegmentState8Impl, IDirectMusicSegmentState8_iface); } -static HRESULT WINAPI DirectMusicSegmentState8_QueryInterface(IDirectMusicSegmentState8 *iface, REFIID riid, void **ppobj) +static HRESULT WINAPI segment_state_QueryInterface(IDirectMusicSegmentState8 *iface, REFIID riid, void **ppobj) { IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); @@ -56,7 +56,7 @@ static HRESULT WINAPI DirectMusicSegmentState8_QueryInterface(IDirectMusicSegmen return E_NOINTERFACE; } -static ULONG WINAPI DirectMusicSegmentState8_AddRef(IDirectMusicSegmentState8 *iface) +static ULONG WINAPI segment_state_AddRef(IDirectMusicSegmentState8 *iface) { IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); ULONG ref = InterlockedIncrement(&This->ref); @@ -66,7 +66,7 @@ static ULONG WINAPI DirectMusicSegmentState8_AddRef(IDirectMusicSegmentState8 *i return ref; } -static ULONG WINAPI DirectMusicSegmentState8_Release(IDirectMusicSegmentState8 *iface) +static ULONG WINAPI segment_state_Release(IDirectMusicSegmentState8 *iface) { IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); ULONG ref = InterlockedDecrement(&This->ref); @@ -78,64 +78,69 @@ static ULONG WINAPI DirectMusicSegmentState8_Release(IDirectMusicSegmentState8 * return ref; } -static HRESULT WINAPI DirectMusicSegmentState8_GetRepeats(IDirectMusicSegmentState8 *iface, DWORD* pdwRepeats) +static HRESULT WINAPI segment_state_GetRepeats(IDirectMusicSegmentState8 *iface, DWORD *pdwRepeats) { IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); FIXME("(%p, %p): stub\n", This, pdwRepeats); return S_OK; } -static HRESULT WINAPI DirectMusicSegmentState8_GetSegment(IDirectMusicSegmentState8 *iface, IDirectMusicSegment** ppSegment) +static HRESULT WINAPI segment_state_GetSegment(IDirectMusicSegmentState8 *iface, IDirectMusicSegment **ppSegment) { IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); FIXME("(%p, %p): stub\n", This, ppSegment); return S_OK; } -static HRESULT WINAPI DirectMusicSegmentState8_GetStartTime(IDirectMusicSegmentState8 *iface, MUSIC_TIME* pmtStart) +static HRESULT WINAPI segment_state_GetStartTime(IDirectMusicSegmentState8 *iface, MUSIC_TIME *pmtStart) { IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); FIXME("(%p, %p): stub\n", This, pmtStart); return S_OK; } -static HRESULT WINAPI DirectMusicSegmentState8_GetSeek(IDirectMusicSegmentState8 *iface, MUSIC_TIME* pmtSeek) +static HRESULT WINAPI segment_state_GetSeek(IDirectMusicSegmentState8 *iface, MUSIC_TIME *pmtSeek) { IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); FIXME("(%p, %p): stub\n", This, pmtSeek); return S_OK; } -static HRESULT WINAPI DirectMusicSegmentState8_GetStartPoint(IDirectMusicSegmentState8 *iface, MUSIC_TIME* pmtStart) +static HRESULT WINAPI segment_state_GetStartPoint(IDirectMusicSegmentState8 *iface, MUSIC_TIME *pmtStart) { IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); FIXME("(%p, %p): stub\n", This, pmtStart); return S_OK; } -static HRESULT WINAPI DirectMusicSegmentState8_SetTrackConfig(IDirectMusicSegmentState8 *iface, REFGUID rguidTrackClassID, DWORD dwGroupBits, DWORD dwIndex, DWORD dwFlagsOn, DWORD dwFlagsOff) { +static HRESULT WINAPI segment_state_SetTrackConfig(IDirectMusicSegmentState8 *iface, + REFGUID rguidTrackClassID, DWORD dwGroupBits, DWORD dwIndex, DWORD dwFlagsOn, DWORD dwFlagsOff) +{ IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); FIXME("(%p, %s, %ld, %ld, %ld, %ld): stub\n", This, debugstr_dmguid(rguidTrackClassID), dwGroupBits, dwIndex, dwFlagsOn, dwFlagsOff); return S_OK; } -static HRESULT WINAPI DirectMusicSegmentState8_GetObjectInPath(IDirectMusicSegmentState8 *iface, DWORD dwPChannel, DWORD dwStage, DWORD dwBuffer, REFGUID guidObject, DWORD dwIndex, REFGUID iidInterface, void** ppObject) { +static HRESULT WINAPI segment_state_GetObjectInPath(IDirectMusicSegmentState8 *iface, DWORD dwPChannel, + DWORD dwStage, DWORD dwBuffer, REFGUID guidObject, DWORD dwIndex, REFGUID iidInterface, void **ppObject) +{ IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); FIXME("(%p, %ld, %ld, %ld, %s, %ld, %s, %p): stub\n", This, dwPChannel, dwStage, dwBuffer, debugstr_dmguid(guidObject), dwIndex, debugstr_dmguid(iidInterface), ppObject); return S_OK; } -static const IDirectMusicSegmentState8Vtbl DirectMusicSegmentState8Vtbl = { - DirectMusicSegmentState8_QueryInterface, - DirectMusicSegmentState8_AddRef, - DirectMusicSegmentState8_Release, - DirectMusicSegmentState8_GetRepeats, - DirectMusicSegmentState8_GetSegment, - DirectMusicSegmentState8_GetStartTime, - DirectMusicSegmentState8_GetSeek, - DirectMusicSegmentState8_GetStartPoint, - DirectMusicSegmentState8_SetTrackConfig, - DirectMusicSegmentState8_GetObjectInPath +static const IDirectMusicSegmentState8Vtbl segment_state_vtbl = +{ + segment_state_QueryInterface, + segment_state_AddRef, + segment_state_Release, + segment_state_GetRepeats, + segment_state_GetSegment, + segment_state_GetStartTime, + segment_state_GetSeek, + segment_state_GetStartPoint, + segment_state_SetTrackConfig, + segment_state_GetObjectInPath, }; /* for ClassFactory */ @@ -146,7 +151,7 @@ HRESULT create_dmsegmentstate(REFIID riid, void **ret_iface) *ret_iface = NULL; if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; - obj->IDirectMusicSegmentState8_iface.lpVtbl = &DirectMusicSegmentState8Vtbl; + obj->IDirectMusicSegmentState8_iface.lpVtbl = &segment_state_vtbl; obj->ref = 1; hr = IDirectMusicSegmentState8_QueryInterface(&obj->IDirectMusicSegmentState8_iface, riid, ret_iface); From 3d5361d80cc01d452d90e0180d75c5ef1f1f555d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 22 Sep 2023 11:28:43 +0200 Subject: [PATCH 2597/2777] dmime: Get rid of the IDirectMusicSegmentState8Impl typedef. (cherry picked from commit 94386b4fbafcaf7b0dd1871a20c447d17c53d5c0) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segmentstate.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index 3a5eee72a57..b49308369ac 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -1,5 +1,4 @@ -/* IDirectMusicSegmentState8 Implementation - * +/* * Copyright (C) 2003-2004 Rok Mandeljc * * This program is free software; you can redistribute it and/or @@ -22,19 +21,20 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmime); -typedef struct IDirectMusicSegmentState8Impl { +struct segment_state +{ IDirectMusicSegmentState8 IDirectMusicSegmentState8_iface; LONG ref; -} IDirectMusicSegmentState8Impl; +}; -static inline IDirectMusicSegmentState8Impl *impl_from_IDirectMusicSegmentState8(IDirectMusicSegmentState8 *iface) +static inline struct segment_state *impl_from_IDirectMusicSegmentState8(IDirectMusicSegmentState8 *iface) { - return CONTAINING_RECORD(iface, IDirectMusicSegmentState8Impl, IDirectMusicSegmentState8_iface); + return CONTAINING_RECORD(iface, struct segment_state, IDirectMusicSegmentState8_iface); } static HRESULT WINAPI segment_state_QueryInterface(IDirectMusicSegmentState8 *iface, REFIID riid, void **ppobj) { - IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); + struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj); @@ -58,7 +58,7 @@ static HRESULT WINAPI segment_state_QueryInterface(IDirectMusicSegmentState8 *if static ULONG WINAPI segment_state_AddRef(IDirectMusicSegmentState8 *iface) { - IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); + struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); ULONG ref = InterlockedIncrement(&This->ref); TRACE("(%p): %ld\n", This, ref); @@ -68,7 +68,7 @@ static ULONG WINAPI segment_state_AddRef(IDirectMusicSegmentState8 *iface) static ULONG WINAPI segment_state_Release(IDirectMusicSegmentState8 *iface) { - IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); + struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); ULONG ref = InterlockedDecrement(&This->ref); TRACE("(%p): %ld\n", This, ref); @@ -80,35 +80,35 @@ static ULONG WINAPI segment_state_Release(IDirectMusicSegmentState8 *iface) static HRESULT WINAPI segment_state_GetRepeats(IDirectMusicSegmentState8 *iface, DWORD *pdwRepeats) { - IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); + struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); FIXME("(%p, %p): stub\n", This, pdwRepeats); return S_OK; } static HRESULT WINAPI segment_state_GetSegment(IDirectMusicSegmentState8 *iface, IDirectMusicSegment **ppSegment) { - IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); + struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); FIXME("(%p, %p): stub\n", This, ppSegment); return S_OK; } static HRESULT WINAPI segment_state_GetStartTime(IDirectMusicSegmentState8 *iface, MUSIC_TIME *pmtStart) { - IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); + struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); FIXME("(%p, %p): stub\n", This, pmtStart); return S_OK; } static HRESULT WINAPI segment_state_GetSeek(IDirectMusicSegmentState8 *iface, MUSIC_TIME *pmtSeek) { - IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); + struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); FIXME("(%p, %p): stub\n", This, pmtSeek); return S_OK; } static HRESULT WINAPI segment_state_GetStartPoint(IDirectMusicSegmentState8 *iface, MUSIC_TIME *pmtStart) { - IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); + struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); FIXME("(%p, %p): stub\n", This, pmtStart); return S_OK; } @@ -116,7 +116,7 @@ static HRESULT WINAPI segment_state_GetStartPoint(IDirectMusicSegmentState8 *ifa static HRESULT WINAPI segment_state_SetTrackConfig(IDirectMusicSegmentState8 *iface, REFGUID rguidTrackClassID, DWORD dwGroupBits, DWORD dwIndex, DWORD dwFlagsOn, DWORD dwFlagsOff) { - IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); + struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); FIXME("(%p, %s, %ld, %ld, %ld, %ld): stub\n", This, debugstr_dmguid(rguidTrackClassID), dwGroupBits, dwIndex, dwFlagsOn, dwFlagsOff); return S_OK; } @@ -124,7 +124,7 @@ static HRESULT WINAPI segment_state_SetTrackConfig(IDirectMusicSegmentState8 *if static HRESULT WINAPI segment_state_GetObjectInPath(IDirectMusicSegmentState8 *iface, DWORD dwPChannel, DWORD dwStage, DWORD dwBuffer, REFGUID guidObject, DWORD dwIndex, REFGUID iidInterface, void **ppObject) { - IDirectMusicSegmentState8Impl *This = impl_from_IDirectMusicSegmentState8(iface); + struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); FIXME("(%p, %ld, %ld, %ld, %s, %ld, %s, %p): stub\n", This, dwPChannel, dwStage, dwBuffer, debugstr_dmguid(guidObject), dwIndex, debugstr_dmguid(iidInterface), ppObject); return S_OK; } @@ -146,7 +146,7 @@ static const IDirectMusicSegmentState8Vtbl segment_state_vtbl = /* for ClassFactory */ HRESULT create_dmsegmentstate(REFIID riid, void **ret_iface) { - IDirectMusicSegmentState8Impl* obj; + struct segment_state *obj; HRESULT hr; *ret_iface = NULL; From a7852664809a6a9e489655c507af5f5589e3e7ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 22 Sep 2023 11:29:00 +0200 Subject: [PATCH 2598/2777] dmime: Implement some segment state default values. (cherry picked from commit c6e6f87a898817ac13e49685f0bacdd9b17518a6) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segmentstate.c | 30 +++++++++++++++++++----------- dlls/dmime/tests/dmime.c | 14 +++++++------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index b49308369ac..655940311b3 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -78,38 +78,46 @@ static ULONG WINAPI segment_state_Release(IDirectMusicSegmentState8 *iface) return ref; } -static HRESULT WINAPI segment_state_GetRepeats(IDirectMusicSegmentState8 *iface, DWORD *pdwRepeats) +static HRESULT WINAPI segment_state_GetRepeats(IDirectMusicSegmentState8 *iface, DWORD *repeats) { struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); - FIXME("(%p, %p): stub\n", This, pdwRepeats); + FIXME("(%p, %p): semi-stub\n", This, repeats); return S_OK; } -static HRESULT WINAPI segment_state_GetSegment(IDirectMusicSegmentState8 *iface, IDirectMusicSegment **ppSegment) +static HRESULT WINAPI segment_state_GetSegment(IDirectMusicSegmentState8 *iface, IDirectMusicSegment **segment) { struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); - FIXME("(%p, %p): stub\n", This, ppSegment); - return S_OK; + + FIXME("(%p, %p): semi-stub\n", This, segment); + + *segment = NULL; + return DMUS_E_NOT_FOUND; } -static HRESULT WINAPI segment_state_GetStartTime(IDirectMusicSegmentState8 *iface, MUSIC_TIME *pmtStart) +static HRESULT WINAPI segment_state_GetStartTime(IDirectMusicSegmentState8 *iface, MUSIC_TIME *start_time) { struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); - FIXME("(%p, %p): stub\n", This, pmtStart); + FIXME("(%p, %p): semi-stub\n", This, start_time); + *start_time = -1; return S_OK; } -static HRESULT WINAPI segment_state_GetSeek(IDirectMusicSegmentState8 *iface, MUSIC_TIME *pmtSeek) +static HRESULT WINAPI segment_state_GetSeek(IDirectMusicSegmentState8 *iface, MUSIC_TIME *seek_time) { struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); - FIXME("(%p, %p): stub\n", This, pmtSeek); + FIXME("(%p, %p): semi-stub\n", This, seek_time); + *seek_time = 0; return S_OK; } -static HRESULT WINAPI segment_state_GetStartPoint(IDirectMusicSegmentState8 *iface, MUSIC_TIME *pmtStart) +static HRESULT WINAPI segment_state_GetStartPoint(IDirectMusicSegmentState8 *iface, MUSIC_TIME *start_time) { struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); - FIXME("(%p, %p): stub\n", This, pmtStart); + + FIXME("(%p, %p): semi-stub\n", This, start_time); + + *start_time = 0; return S_OK; } diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index ea5a972dc80..e7113d2bb5c 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3985,12 +3985,12 @@ static void test_segment_state(void) tmp_segment = (void *)0xdeadbeef; hr = IDirectMusicSegmentState_GetSegment(state, &tmp_segment); - todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); - todo_wine ok(tmp_segment == NULL, "got %p\n", tmp_segment); + ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); + ok(tmp_segment == NULL, "got %p\n", tmp_segment); time = 0xdeadbeef; hr = IDirectMusicSegmentState_GetStartPoint(state, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(time == 0, "got %#lx\n", time); + ok(time == 0, "got %#lx\n", time); time = 0xdeadbeef; hr = IDirectMusicSegmentState_GetRepeats(state, &value); ok(hr == S_OK, "got %#lx\n", hr); @@ -3998,11 +3998,11 @@ static void test_segment_state(void) time = 0xdeadbeef; hr = IDirectMusicSegmentState_GetStartTime(state, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(time == -1, "got %#lx\n", time); + ok(time == -1, "got %#lx\n", time); time = 0xdeadbeef; hr = IDirectMusicSegmentState_GetSeek(state, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(time == 0, "got %#lx\n", time); + ok(time == 0, "got %#lx\n", time); /* PlaySegment returns a different, genuine segment state */ @@ -4043,9 +4043,9 @@ static void test_segment_state(void) tmp_segment = (void *)0xdeadbeef; hr = IDirectMusicSegmentState_GetSegment(state, &tmp_segment); - ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); todo_wine ok(tmp_segment == segment, "got %p\n", tmp_segment); - if (tmp_segment != (void *)0xdeadbeef) IDirectMusicSegment_Release(tmp_segment); + if (tmp_segment) IDirectMusicSegment_Release(tmp_segment); time = 0xdeadbeef; hr = IDirectMusicSegmentState_GetStartPoint(state, &time); From 270f6c5dafec31df8013936e99c41e2764f95a7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 26 Sep 2023 08:42:49 +0200 Subject: [PATCH 2599/2777] dmime: Redirect IDirectMusicPerformance_PlaySegment to PlaySegmentEx. (cherry picked from commit 9cb0142632da119b0d808d21fec0f29b9baaef9b) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 111d7c60568..e590db88997 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -384,16 +384,15 @@ static HRESULT WINAPI performance_Init(IDirectMusicPerformance8 *iface, IDirectM return S_OK; } -static HRESULT WINAPI performance_PlaySegment(IDirectMusicPerformance8 *iface, IDirectMusicSegment *pSegment, - DWORD dwFlags, __int64 i64StartTime, IDirectMusicSegmentState **ppSegmentState) +static HRESULT WINAPI performance_PlaySegment(IDirectMusicPerformance8 *iface, IDirectMusicSegment *segment, + DWORD segment_flags, INT64 start_time, IDirectMusicSegmentState **ret_state) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); - FIXME("(%p, %p, %ld, 0x%s, %p): stub\n", This, pSegment, dwFlags, - wine_dbgstr_longlong(i64StartTime), ppSegmentState); - if (ppSegmentState) - return create_dmsegmentstate(&IID_IDirectMusicSegmentState,(void**)ppSegmentState); - return S_OK; + TRACE("(%p, %p, %ld, %I64d, %p)\n", This, segment, segment_flags, start_time, ret_state); + + return IDirectMusicPerformance8_PlaySegmentEx(iface, (IUnknown *)segment, NULL, NULL, + segment_flags, start_time, ret_state, NULL, NULL); } static HRESULT WINAPI performance_Stop(IDirectMusicPerformance8 *iface, IDirectMusicSegment *pSegment, From 81080d8c95f2a0e759a5f5a14e934b31d49ab235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 3 Oct 2023 11:37:11 +0200 Subject: [PATCH 2600/2777] dmime: Introduce a new segment_state_create constructor. (cherry picked from commit 45d1c00eeaf833e64767a43241612d0411f86493) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/dmime_private.h | 3 +++ dlls/dmime/performance.c | 36 ++++++++++++++++++------- dlls/dmime/segmentstate.c | 55 +++++++++++++++++++++++++++++++------- dlls/dmime/tests/dmime.c | 14 +++++----- 4 files changed, 83 insertions(+), 25 deletions(-) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index eacde4b46be..c35c52eb066 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -70,6 +70,9 @@ extern void set_audiopath_perf_pointer(IDirectMusicAudioPath*,IDirectMusicPerfor extern void set_audiopath_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*); extern void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*); +extern HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, + IDirectMusicSegmentState **ret_iface); + /***************************************************************************** * Auxiliary definitions */ diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index e590db88997..9f293358ca6 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1063,17 +1063,35 @@ static HRESULT WINAPI performance_InitAudio(IDirectMusicPerformance8 *iface, IDi return S_OK; } -static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, IUnknown *pSource, - WCHAR *pwzSegmentName, IUnknown *pTransition, DWORD dwFlags, __int64 i64StartTime, - IDirectMusicSegmentState **ppSegmentState, IUnknown *pFrom, IUnknown *pAudioPath) +static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, IUnknown *source, + WCHAR *segment_name, IUnknown *transition, DWORD segment_flags, INT64 start_time, + IDirectMusicSegmentState **segment_state, IUnknown *from, IUnknown *audio_path) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + IDirectMusicSegmentState *state; + IDirectMusicSegment *segment; + HRESULT hr; - FIXME("(%p, %p, %p, %p, %ld, 0x%s, %p, %p, %p): stub\n", This, pSource, pwzSegmentName, - pTransition, dwFlags, wine_dbgstr_longlong(i64StartTime), ppSegmentState, pFrom, pAudioPath); - if (ppSegmentState) - return create_dmsegmentstate(&IID_IDirectMusicSegmentState,(void**)ppSegmentState); - return S_OK; + FIXME("(%p, %p, %s, %p, %#lx, %I64d, %p, %p, %p): stub\n", This, source, debugstr_w(segment_name), + transition, segment_flags, start_time, segment_state, from, audio_path); + + if (FAILED(hr = IUnknown_QueryInterface(source, &IID_IDirectMusicSegment, (void **)&segment))) + return hr; + if (FAILED(hr = segment_state_create((IDirectMusicSegment *)segment, start_time, &state))) + { + IDirectMusicSegment_Release(segment); + return hr; + } + + if (segment_state) + { + *segment_state = state; + IDirectMusicSegmentState_AddRef(state); + } + + IDirectMusicSegmentState_Release(state); + IDirectMusicSegment_Release(segment); + return hr; } static HRESULT WINAPI performance_StopEx(IDirectMusicPerformance8 *iface, IUnknown *pObjectToStop, diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index 655940311b3..1a09bed5dd3 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -25,6 +25,10 @@ struct segment_state { IDirectMusicSegmentState8 IDirectMusicSegmentState8_iface; LONG ref; + + IDirectMusicSegment *segment; + MUSIC_TIME start_point; + MUSIC_TIME start_time; }; static inline struct segment_state *impl_from_IDirectMusicSegmentState8(IDirectMusicSegmentState8 *iface) @@ -73,7 +77,11 @@ static ULONG WINAPI segment_state_Release(IDirectMusicSegmentState8 *iface) TRACE("(%p): %ld\n", This, ref); - if (!ref) free(This); + if (!ref) + { + if (This->segment) IDirectMusicSegment_Release(This->segment); + free(This); + } return ref; } @@ -89,17 +97,21 @@ static HRESULT WINAPI segment_state_GetSegment(IDirectMusicSegmentState8 *iface, { struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); - FIXME("(%p, %p): semi-stub\n", This, segment); + TRACE("(%p, %p)\n", This, segment); - *segment = NULL; - return DMUS_E_NOT_FOUND; + if (!(*segment = This->segment)) return DMUS_E_NOT_FOUND; + + IDirectMusicSegment_AddRef(This->segment); + return S_OK; } static HRESULT WINAPI segment_state_GetStartTime(IDirectMusicSegmentState8 *iface, MUSIC_TIME *start_time) { struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); - FIXME("(%p, %p): semi-stub\n", This, start_time); - *start_time = -1; + + TRACE("(%p, %p)\n", This, start_time); + + *start_time = This->start_time; return S_OK; } @@ -111,13 +123,13 @@ static HRESULT WINAPI segment_state_GetSeek(IDirectMusicSegmentState8 *iface, MU return S_OK; } -static HRESULT WINAPI segment_state_GetStartPoint(IDirectMusicSegmentState8 *iface, MUSIC_TIME *start_time) +static HRESULT WINAPI segment_state_GetStartPoint(IDirectMusicSegmentState8 *iface, MUSIC_TIME *start_point) { struct segment_state *This = impl_from_IDirectMusicSegmentState8(iface); - FIXME("(%p, %p): semi-stub\n", This, start_time); + TRACE("(%p, %p)\n", This, start_point); - *start_time = 0; + *start_point = This->start_point; return S_OK; } @@ -161,8 +173,33 @@ HRESULT create_dmsegmentstate(REFIID riid, void **ret_iface) if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; obj->IDirectMusicSegmentState8_iface.lpVtbl = &segment_state_vtbl; obj->ref = 1; + obj->start_time = -1; + TRACE("Created IDirectMusicSegmentState %p\n", obj); hr = IDirectMusicSegmentState8_QueryInterface(&obj->IDirectMusicSegmentState8_iface, riid, ret_iface); IDirectMusicSegmentState8_Release(&obj->IDirectMusicSegmentState8_iface); return hr; } + +HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, + IDirectMusicSegmentState **ret_iface) +{ + IDirectMusicSegmentState *iface; + struct segment_state *This; + HRESULT hr; + + TRACE("(%p, %lu, %p)\n", segment, start_time, ret_iface); + + if (FAILED(hr = create_dmsegmentstate(&IID_IDirectMusicSegmentState, (void **)&iface))) return hr; + This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); + + This->segment = segment; + IDirectMusicSegment_AddRef(This->segment); + + This->start_time = start_time; + hr = IDirectMusicSegment_GetStartPoint(segment, &This->start_point); + + if (SUCCEEDED(hr)) *ret_iface = iface; + else IDirectMusicSegmentState_Release(iface); + return hr; +} diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index e7113d2bb5c..87d938a9015 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -4043,14 +4043,14 @@ static void test_segment_state(void) tmp_segment = (void *)0xdeadbeef; hr = IDirectMusicSegmentState_GetSegment(state, &tmp_segment); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(tmp_segment == segment, "got %p\n", tmp_segment); - if (tmp_segment) IDirectMusicSegment_Release(tmp_segment); + ok(hr == S_OK, "got %#lx\n", hr); + ok(tmp_segment == segment, "got %p\n", tmp_segment); + IDirectMusicSegment_Release(tmp_segment); time = 0xdeadbeef; hr = IDirectMusicSegmentState_GetStartPoint(state, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(time == 50, "got %lu\n", time); + ok(time == 50, "got %lu\n", time); time = 0xdeadbeef; hr = IDirectMusicSegmentState_GetRepeats(state, &value); ok(hr == S_OK, "got %#lx\n", hr); @@ -4058,7 +4058,7 @@ static void test_segment_state(void) time = 0xdeadbeef; hr = IDirectMusicSegmentState_GetStartTime(state, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(time == 20, "got %#lx\n", time); + ok(time == 20, "got %#lx\n", time); time = 0xdeadbeef; /* The seek value is also dependent on whether the tracks are playing. @@ -4080,7 +4080,7 @@ static void test_segment_state(void) time = 0xdeadbeef; hr = IDirectMusicSegmentState_GetStartPoint(state, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(time == 50, "got %#lx\n", time); + ok(time == 50, "got %#lx\n", time); time = 0xdeadbeef; hr = IDirectMusicSegmentState_GetRepeats(state, &value); ok(hr == S_OK, "got %#lx\n", hr); @@ -4088,7 +4088,7 @@ static void test_segment_state(void) time = 0xdeadbeef; hr = IDirectMusicSegmentState_GetStartTime(state, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(time == 20, "got %#lx\n", time); + ok(time == 20, "got %#lx\n", time); time = 0xdeadbeef; hr = IDirectMusicSegmentState_GetSeek(state, &time); ok(hr == S_OK, "got %#lx\n", hr); From aaae04e676225123c6a3be00cc126aaba3614919 Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Wed, 4 Oct 2023 23:31:22 -0600 Subject: [PATCH 2601/2777] mfplat: Rename debugstr_fourcc to mf_debugstr_fourcc. (cherry picked from commit ae77ddafb02dbffe32631c925826c9c70de9b7f1) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/mfplat/buffer.c | 2 +- dlls/mfplat/mediatype.c | 4 ++-- dlls/mfplat/mfplat_private.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index 3850efa594c..b7f32f12cdc 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -1643,7 +1643,7 @@ HRESULT WINAPI MFCreateAlignedMemoryBuffer(DWORD max_length, DWORD alignment, IM */ HRESULT WINAPI MFCreate2DMediaBuffer(DWORD width, DWORD height, DWORD fourcc, BOOL bottom_up, IMFMediaBuffer **buffer) { - TRACE("%lu, %lu, %s, %d, %p.\n", width, height, debugstr_fourcc(fourcc), bottom_up, buffer); + TRACE("%lu, %lu, %s, %d, %p.\n", width, height, mf_debugstr_fourcc(fourcc), bottom_up, buffer); return create_2d_buffer(width, height, fourcc, bottom_up, buffer); } diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 374024d8190..99fe4d1c733 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -2761,7 +2761,7 @@ HRESULT WINAPI MFGetStrideForBitmapInfoHeader(DWORD fourcc, DWORD width, LONG *s struct uncompressed_video_format *format; GUID subtype; - TRACE("%s, %lu, %p.\n", debugstr_fourcc(fourcc), width, stride); + TRACE("%s, %lu, %p.\n", mf_debugstr_fourcc(fourcc), width, stride); memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype)); subtype.Data1 = fourcc; @@ -2831,7 +2831,7 @@ HRESULT WINAPI MFGetPlaneSize(DWORD fourcc, DWORD width, DWORD height, DWORD *si unsigned int stride; GUID subtype; - TRACE("%s, %lu, %lu, %p.\n", debugstr_fourcc(fourcc), width, height, size); + TRACE("%s, %lu, %lu, %p.\n", mf_debugstr_fourcc(fourcc), width, height, size); memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype)); subtype.Data1 = fourcc; diff --git a/dlls/mfplat/mfplat_private.h b/dlls/mfplat/mfplat_private.h index 8418c8eb2ef..8c7dc73dab1 100644 --- a/dlls/mfplat/mfplat_private.h +++ b/dlls/mfplat/mfplat_private.h @@ -150,7 +150,7 @@ static inline const char *debugstr_propvar(const PROPVARIANT *v) } } -static inline const char *debugstr_fourcc(DWORD format) +static inline const char *mf_debugstr_fourcc(DWORD format) { static const struct format_name { From 47008b074390a709848ab868ffb412b1324f57fe Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Wed, 4 Oct 2023 23:32:04 -0600 Subject: [PATCH 2602/2777] winecoreaudio: Rename wine_dbgstr_fourcc to coreaudio_dbgstr_fourcc. (cherry picked from commit b490890d2de2042de5ff883f2ab0e2ad987f4bf5) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/winecoreaudio.drv/coreaudio.h | 2 +- dlls/winecoreaudio.drv/coremidi.c | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/dlls/winecoreaudio.drv/coreaudio.h b/dlls/winecoreaudio.drv/coreaudio.h index e04043c4010..687bad54b55 100644 --- a/dlls/winecoreaudio.drv/coreaudio.h +++ b/dlls/winecoreaudio.drv/coreaudio.h @@ -23,7 +23,7 @@ #include "wine/debug.h" /* fourcc is in native order, where MSB is the first character. */ -static inline const char* wine_dbgstr_fourcc(INT32 fourcc) +static inline const char* coreaudio_dbgstr_fourcc(INT32 fourcc) { char buf[4] = { (char) (fourcc >> 24), (char) (fourcc >> 16), (char) (fourcc >> 8), (char) fourcc }; diff --git a/dlls/winecoreaudio.drv/coremidi.c b/dlls/winecoreaudio.drv/coremidi.c index c9b377f68b0..37cf859a913 100644 --- a/dlls/winecoreaudio.drv/coremidi.c +++ b/dlls/winecoreaudio.drv/coremidi.c @@ -448,7 +448,7 @@ static BOOL synth_unit_create_default(AUGraph *graph, AudioUnit *synth) sc = NewAUGraph(graph); if (sc != noErr) { - ERR("NewAUGraph return %s\n", wine_dbgstr_fourcc(sc)); + ERR("NewAUGraph return %s\n", coreaudio_dbgstr_fourcc(sc)); return FALSE; } @@ -463,7 +463,7 @@ static BOOL synth_unit_create_default(AUGraph *graph, AudioUnit *synth) sc = AUGraphAddNode(*graph, &desc, &synth_node); if (sc != noErr) { - ERR("AUGraphAddNode cannot create synthNode : %s\n", wine_dbgstr_fourcc(sc)); + ERR("AUGraphAddNode cannot create synthNode : %s\n", coreaudio_dbgstr_fourcc(sc)); return FALSE; } @@ -474,14 +474,14 @@ static BOOL synth_unit_create_default(AUGraph *graph, AudioUnit *synth) sc = AUGraphAddNode(*graph, &desc, &out_node); if (sc != noErr) { - ERR("AUGraphAddNode cannot create outNode %s\n", wine_dbgstr_fourcc(sc)); + ERR("AUGraphAddNode cannot create outNode %s\n", coreaudio_dbgstr_fourcc(sc)); return FALSE; } sc = AUGraphOpen(*graph); if (sc != noErr) { - ERR("AUGraphOpen returns %s\n", wine_dbgstr_fourcc(sc)); + ERR("AUGraphOpen returns %s\n", coreaudio_dbgstr_fourcc(sc)); return FALSE; } @@ -490,7 +490,7 @@ static BOOL synth_unit_create_default(AUGraph *graph, AudioUnit *synth) if (sc != noErr) { ERR("AUGraphConnectNodeInput cannot connect synthNode to outNode : %s\n", - wine_dbgstr_fourcc(sc)); + coreaudio_dbgstr_fourcc(sc)); return FALSE; } @@ -498,7 +498,7 @@ static BOOL synth_unit_create_default(AUGraph *graph, AudioUnit *synth) sc = AUGraphNodeInfo(*graph, synth_node, 0, synth); if (sc != noErr) { - ERR("AUGraphNodeInfo return %s\n", wine_dbgstr_fourcc(sc)); + ERR("AUGraphNodeInfo return %s\n", coreaudio_dbgstr_fourcc(sc)); return FALSE; } @@ -512,14 +512,14 @@ static BOOL synth_unit_init(AudioUnit synth, AUGraph graph) sc = AUGraphInitialize(graph); if (sc != noErr) { - ERR("AUGraphInitialize(%p) returns %s\n", graph, wine_dbgstr_fourcc(sc)); + ERR("AUGraphInitialize(%p) returns %s\n", graph, coreaudio_dbgstr_fourcc(sc)); return FALSE; } sc = AUGraphStart(graph); if (sc != noErr) { - ERR("AUGraphStart(%p) returns %s\n", graph, wine_dbgstr_fourcc(sc)); + ERR("AUGraphStart(%p) returns %s\n", graph, coreaudio_dbgstr_fourcc(sc)); return FALSE; } @@ -533,14 +533,14 @@ static BOOL synth_unit_close(AUGraph graph) sc = AUGraphStop(graph); if (sc != noErr) { - ERR("AUGraphStop(%p) returns %s\n", graph, wine_dbgstr_fourcc(sc)); + ERR("AUGraphStop(%p) returns %s\n", graph, coreaudio_dbgstr_fourcc(sc)); return FALSE; } sc = DisposeAUGraph(graph); if (sc != noErr) { - ERR("DisposeAUGraph(%p) returns %s\n", graph, wine_dbgstr_fourcc(sc)); + ERR("DisposeAUGraph(%p) returns %s\n", graph, coreaudio_dbgstr_fourcc(sc)); return FALSE; } @@ -686,7 +686,7 @@ static UINT midi_out_data(WORD dev_id, UINT data) sc = MusicDeviceMIDIEvent(dest->synth, bytes[0], bytes[1], bytes[2], 0); if (sc != noErr) { - ERR("MusicDeviceMIDIEvent returns %s\n", wine_dbgstr_fourcc(sc)); + ERR("MusicDeviceMIDIEvent returns %s\n", coreaudio_dbgstr_fourcc(sc)); return MMSYSERR_ERROR; } } @@ -739,7 +739,7 @@ static UINT midi_out_long_data(WORD dev_id, MIDIHDR *hdr, UINT hdr_size, struct sc = MusicDeviceSysEx(dest->synth, (const UInt8 *)hdr->lpData, hdr->dwBufferLength); if (sc != noErr) { - ERR("MusicDeviceSysEx returns %s\n", wine_dbgstr_fourcc(sc)); + ERR("MusicDeviceSysEx returns %s\n", coreaudio_dbgstr_fourcc(sc)); return MMSYSERR_ERROR; } } From 143f9d145d186eeecb63fdbfd96b4601f6d0d88f Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Mon, 2 Oct 2023 21:38:30 -0600 Subject: [PATCH 2603/2777] include: Introduce wine_dbgstr_fourcc and debugstr_fourcc. (cherry picked from commit 8b20c588012421ba8750bbeb886135266d14205d) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/d3dxof/parsing.c | 9 --------- dlls/dmusic/dmobject.h | 7 ------- include/wine/debug.h | 11 +++++++++++ libs/strmbase/mediatype.c | 8 -------- 4 files changed, 11 insertions(+), 24 deletions(-) diff --git a/dlls/d3dxof/parsing.c b/dlls/d3dxof/parsing.c index c853060dea1..c020df46bf7 100644 --- a/dlls/d3dxof/parsing.c +++ b/dlls/d3dxof/parsing.c @@ -81,15 +81,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3dxof_parsing); #define CLSIDFMT "<%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X>" -/* FOURCC to string conversion for debug messages */ -static const char *debugstr_fourcc(DWORD fourcc) -{ - if (!fourcc) return "'null'"; - return wine_dbg_sprintf ("\'%c%c%c%c\'", - (char)(fourcc), (char)(fourcc >> 8), - (char)(fourcc >> 16), (char)(fourcc >> 24)); -} - static const char* get_primitive_string(DWORD token) { switch(token) diff --git a/dlls/dmusic/dmobject.h b/dlls/dmusic/dmobject.h index 82ac05f31b9..bab96c77724 100644 --- a/dlls/dmusic/dmobject.h +++ b/dlls/dmusic/dmobject.h @@ -121,10 +121,3 @@ HRESULT WINAPI unimpl_IPersistStream_GetSizeMax(IPersistStream *iface, const char *debugstr_chunk(const struct chunk_entry *chunk); const char *debugstr_dmguid(const GUID *id); void dump_DMUS_OBJECTDESC(DMUS_OBJECTDESC *desc); - -static inline const char *debugstr_fourcc(DWORD fourcc) -{ - if (!fourcc) return "''"; - return wine_dbg_sprintf("'%c%c%c%c'", (char)(fourcc), (char)(fourcc >> 8), - (char)(fourcc >> 16), (char)(fourcc >> 24)); -} diff --git a/include/wine/debug.h b/include/wine/debug.h index c20924818dd..c282f52a3b6 100644 --- a/include/wine/debug.h +++ b/include/wine/debug.h @@ -315,6 +315,16 @@ static inline const char *wine_dbgstr_guid( const GUID *id ) id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] ); } +static inline const char *wine_dbgstr_fourcc( unsigned int fourcc ) +{ + char str[4] = { fourcc, fourcc >> 8, fourcc >> 16, fourcc >> 24 }; + if (!fourcc) + return "''"; + if (isprint( str[0] ) && isprint( str[1] ) && isprint( str[2] ) && isprint( str[3] )) + return wine_dbg_sprintf( "'%4s'", str ); + return wine_dbg_sprintf( "0x%08x", fourcc ); +} + static inline const char *wine_dbgstr_point( const POINT *pt ) { if (!pt) return "(null)"; @@ -495,6 +505,7 @@ static inline const char *wine_dbgstr_variant( const VARIANT *v ) static inline const char *debugstr_an( const char * s, int n ) { return wine_dbgstr_an( s, n ); } static inline const char *debugstr_wn( const WCHAR *s, int n ) { return wine_dbgstr_wn( s, n ); } static inline const char *debugstr_guid( const struct _GUID *id ) { return wine_dbgstr_guid(id); } +static inline const char *debugstr_fourcc( unsigned int cc ) { return wine_dbgstr_fourcc( cc ); } static inline const char *debugstr_a( const char *s ) { return wine_dbgstr_an( s, -1 ); } static inline const char *debugstr_w( const WCHAR *s ) { return wine_dbgstr_wn( s, -1 ); } diff --git a/libs/strmbase/mediatype.c b/libs/strmbase/mediatype.c index 33af6f2e636..5c157be521d 100644 --- a/libs/strmbase/mediatype.c +++ b/libs/strmbase/mediatype.c @@ -55,14 +55,6 @@ static const char *strmbase_debugstr_guid(const GUID *guid) return debugstr_guid(guid); } -static const char *debugstr_fourcc(DWORD fourcc) -{ - char str[4] = {fourcc, fourcc >> 8, fourcc >> 16, fourcc >> 24}; - if (isprint(str[0]) && isprint(str[1]) && isprint(str[2]) && isprint(str[3])) - return wine_dbgstr_an(str, 4); - return wine_dbg_sprintf("%#lx", fourcc); -} - void strmbase_dump_media_type(const AM_MEDIA_TYPE *mt) { if (!TRACE_ON(quartz) || !mt) return; From 1e74d47887228dac5d3772260eb08366882a5f88 Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Mon, 2 Oct 2023 21:38:30 -0600 Subject: [PATCH 2604/2777] comctl32: Use the debugstr_fourcc function instead of reimplementing it. (cherry picked from commit 6159a50127d928b1831fb0233271ce583ef3f1b0) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/comctl32/animate.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/dlls/comctl32/animate.c b/dlls/comctl32/animate.c index f4d848fef91..721379f329c 100644 --- a/dlls/comctl32/animate.c +++ b/dlls/comctl32/animate.c @@ -534,14 +534,8 @@ static BOOL ANIMATE_GetAviInfo(ANIMATE_INFO *infoPtr) mmioRead(infoPtr->hMMio, (LPSTR)&infoPtr->ash, sizeof(infoPtr->ash)); - TRACE("ash.fccType='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr->ash.fccType)), - HIBYTE(LOWORD(infoPtr->ash.fccType)), - LOBYTE(HIWORD(infoPtr->ash.fccType)), - HIBYTE(HIWORD(infoPtr->ash.fccType))); - TRACE("ash.fccHandler='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr->ash.fccHandler)), - HIBYTE(LOWORD(infoPtr->ash.fccHandler)), - LOBYTE(HIWORD(infoPtr->ash.fccHandler)), - HIBYTE(HIWORD(infoPtr->ash.fccHandler))); + TRACE("ash.fccType=%s\n", debugstr_fourcc(infoPtr->ash.fccType)); + TRACE("ash.fccHandler=%s\n", debugstr_fourcc(infoPtr->ash.fccHandler)); TRACE("ash.dwFlags=%ld\n", infoPtr->ash.dwFlags); TRACE("ash.wPriority=%d\n", infoPtr->ash.wPriority); TRACE("ash.wLanguage=%d\n", infoPtr->ash.wLanguage); From b6fb91bbe0be5fbdb398a28022ee965b430b1c48 Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Mon, 2 Oct 2023 21:38:30 -0600 Subject: [PATCH 2605/2777] mciavi32: Use the debugstr_fourcc function instead of reimplementing it. (cherry picked from commit 6da1c970a455843073f58b57f30dc0267e4f9f58) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/mciavi32/mmoutput.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/dlls/mciavi32/mmoutput.c b/dlls/mciavi32/mmoutput.c index ec2751e6d9a..dffdbc9de37 100644 --- a/dlls/mciavi32/mmoutput.c +++ b/dlls/mciavi32/mmoutput.c @@ -28,15 +28,9 @@ static BOOL MCIAVI_GetInfoAudio(WINE_MCIAVI* wma, const MMCKINFO* mmckList, MMCK { MMCKINFO mmckInfo; - TRACE("ash.fccType='%c%c%c%c'\n", LOBYTE(LOWORD(wma->ash_audio.fccType)), - HIBYTE(LOWORD(wma->ash_audio.fccType)), - LOBYTE(HIWORD(wma->ash_audio.fccType)), - HIBYTE(HIWORD(wma->ash_audio.fccType))); + TRACE("ash.fccType=%s\n", debugstr_fourcc(wma->ash_audio.fccType)); if (wma->ash_audio.fccHandler) /* not all streams specify a handler */ - TRACE("ash.fccHandler='%c%c%c%c'\n", LOBYTE(LOWORD(wma->ash_audio.fccHandler)), - HIBYTE(LOWORD(wma->ash_audio.fccHandler)), - LOBYTE(HIWORD(wma->ash_audio.fccHandler)), - HIBYTE(HIWORD(wma->ash_audio.fccHandler))); + TRACE("ash.fccHandler=%s\n", debugstr_fourcc(wma->ash_audio.fccHandler)); else TRACE("ash.fccHandler=0, no handler specified\n"); TRACE("ash.dwFlags=%ld\n", wma->ash_audio.dwFlags); @@ -89,14 +83,8 @@ static BOOL MCIAVI_GetInfoVideo(WINE_MCIAVI* wma, const MMCKINFO* mmckList, MMCK { MMCKINFO mmckInfo; - TRACE("ash.fccType='%c%c%c%c'\n", LOBYTE(LOWORD(wma->ash_video.fccType)), - HIBYTE(LOWORD(wma->ash_video.fccType)), - LOBYTE(HIWORD(wma->ash_video.fccType)), - HIBYTE(HIWORD(wma->ash_video.fccType))); - TRACE("ash.fccHandler='%c%c%c%c'\n", LOBYTE(LOWORD(wma->ash_video.fccHandler)), - HIBYTE(LOWORD(wma->ash_video.fccHandler)), - LOBYTE(HIWORD(wma->ash_video.fccHandler)), - HIBYTE(HIWORD(wma->ash_video.fccHandler))); + TRACE("ash.fccType=%s\n", debugstr_fourcc(wma->ash_video.fccType)); + TRACE("ash.fccHandler=%s\n", debugstr_fourcc(wma->ash_video.fccHandler)); TRACE("ash.dwFlags=%ld\n", wma->ash_video.dwFlags); TRACE("ash.wPriority=%d\n", wma->ash_video.wPriority); TRACE("ash.wLanguage=%d\n", wma->ash_video.wLanguage); From edfd69d7a939f7f83941fc547c224d4370404edd Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Mon, 2 Oct 2023 21:38:30 -0600 Subject: [PATCH 2606/2777] msvfw32: Use the debugstr_fourcc function instead of reimplementing it. (cherry picked from commit 4c07f221073d798cec79fb48d3bd6161860fbdc1) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/msvfw32/msvideo_main.c | 48 ++++++++++++++----------------------- 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/dlls/msvfw32/msvideo_main.c b/dlls/msvfw32/msvideo_main.c index 8620f00920d..25eb1dc36d5 100644 --- a/dlls/msvfw32/msvideo_main.c +++ b/dlls/msvfw32/msvideo_main.c @@ -57,18 +57,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvideo); (str)[3] = HIBYTE(HIWORD(fcc)); \ } while(0) -static inline const char *wine_dbgstr_fcc( DWORD fcc ) -{ - char fcc_str[5]; - fourcc_to_string(fcc_str, fcc); - fcc_str[4] = '\0'; - /* Last byte may be ' ' in some cases like "DIB " */ - if (isalnum(fcc_str[0]) && isalnum(fcc_str[1]) && isalnum(fcc_str[2]) - && (isalnum(fcc_str[3]) || isspace(fcc_str[3]))) - return wine_dbg_sprintf("%s", fcc_str); - return wine_dbg_sprintf("0x%08lx", fcc); -} - static const char *wine_dbgstr_icerr( int ret ) { const char *str; @@ -277,7 +265,7 @@ BOOL VFWAPI ICInfo(DWORD type, DWORD handler, ICINFO *info) HKEY key; TRACE("type %s, handler %s, info %p.\n", - wine_dbgstr_fcc(type), wine_dbgstr_fcc(handler), info); + debugstr_fourcc(type), debugstr_fourcc(handler), info); memset(info, 0, sizeof(*info)); info->dwSize = sizeof(*info); @@ -337,7 +325,7 @@ BOOL VFWAPI ICInfo(DWORD type, DWORD handler, ICINFO *info) info->fccType = type; info->fccHandler = handler; - WARN("No driver found for codec %s.%s.\n", wine_dbgstr_fcc(type), wine_dbgstr_fcc(handler)); + WARN("No driver found for codec %s.%s.\n", debugstr_fourcc(type), debugstr_fourcc(handler)); return FALSE; } @@ -351,7 +339,7 @@ BOOL VFWAPI ICInstall(DWORD type, DWORD handler, LPARAM lparam, char *desc, UINT struct reg_driver *driver; TRACE("type %s, handler %s, lparam %#Ix, desc %s, flags %#x.\n", - wine_dbgstr_fcc(type), wine_dbgstr_fcc(handler), lparam, debugstr_a(desc), flags); + debugstr_fourcc(type), debugstr_fourcc(handler), lparam, debugstr_a(desc), flags); LIST_FOR_EACH_ENTRY(driver, ®_driver_list, struct reg_driver, entry) { @@ -406,7 +394,7 @@ BOOL VFWAPI ICRemove(DWORD type, DWORD handler, UINT flags) LONG res; TRACE("type %s, handler %s, flags %#x.\n", - wine_dbgstr_fcc(type), wine_dbgstr_fcc(handler), flags); + debugstr_fourcc(type), debugstr_fourcc(handler), flags); LIST_FOR_EACH_ENTRY(driver, ®_driver_list, struct reg_driver, entry) { @@ -447,7 +435,7 @@ HIC VFWAPI ICOpen(DWORD fccType, DWORD fccHandler, UINT wMode) struct reg_driver *driver; HDRVR hdrv = NULL; - TRACE("(%s,%s,0x%08x)\n", wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), wMode); + TRACE("(%s,%s,0x%08x)\n", debugstr_fourcc(fccType), debugstr_fourcc(fccHandler), wMode); if (!fccHandler) /* No specific handler, return the first valid for wMode */ { @@ -464,7 +452,7 @@ HIC VFWAPI ICOpen(DWORD fccType, DWORD fccHandler, UINT wMode) if (local != 0) { TRACE("Returning %s as default handler for %s\n", - wine_dbgstr_fcc(info.fccHandler), wine_dbgstr_fcc(fccType)); + debugstr_fourcc(info.fccHandler), debugstr_fourcc(fccType)); return local; } } @@ -538,7 +526,7 @@ HIC VFWAPI ICOpenFunction(DWORD fccType, DWORD fccHandler, UINT wMode, DRIVERPRO WINE_HIC* whic; TRACE("(%s,%s,%d,%p)\n", - wine_dbgstr_fcc(fccType), wine_dbgstr_fcc(fccHandler), wMode, lpfnHandler); + debugstr_fourcc(fccType), debugstr_fourcc(fccHandler), wMode, lpfnHandler); icopen.dwSize = sizeof(ICOPEN); icopen.fccType = fccType; @@ -639,7 +627,7 @@ HIC VFWAPI ICLocate(DWORD type, DWORD handler, BITMAPINFOHEADER *in, DWORD i; TRACE("type %s, handler %s, in %p, out %p, mode %u.\n", - wine_dbgstr_fcc(type), wine_dbgstr_fcc(handler), in, out, mode); + debugstr_fourcc(type), debugstr_fourcc(handler), in, out, mode); switch (mode) { @@ -663,8 +651,8 @@ HIC VFWAPI ICLocate(DWORD type, DWORD handler, BITMAPINFOHEADER *in, { if (!ICSendMessage(hic, msg, (DWORD_PTR)in, (DWORD_PTR)out)) { - TRACE("Found codec %s.%s.\n", wine_dbgstr_fcc(type), - wine_dbgstr_fcc(handler)); + TRACE("Found codec %s.%s.\n", debugstr_fourcc(type), + debugstr_fourcc(handler)); return hic; } ICClose(hic); @@ -676,8 +664,8 @@ HIC VFWAPI ICLocate(DWORD type, DWORD handler, BITMAPINFOHEADER *in, { if (!ICSendMessage(hic, msg, (DWORD_PTR)in, (DWORD_PTR)out)) { - TRACE("Found codec %s.%s.\n", wine_dbgstr_fcc(info.fccType), - wine_dbgstr_fcc(info.fccHandler)); + TRACE("Found codec %s.%s.\n", debugstr_fourcc(info.fccType), + debugstr_fourcc(info.fccHandler)); return hic; } ICClose(hic); @@ -688,7 +676,7 @@ HIC VFWAPI ICLocate(DWORD type, DWORD handler, BITMAPINFOHEADER *in, return ICLocate(ICTYPE_VIDEO, handler, in, out, mode); WARN("Could not find a driver for codec %s.%s.\n", - wine_dbgstr_fcc(type), wine_dbgstr_fcc(handler)); + debugstr_fourcc(type), debugstr_fourcc(handler)); return 0; } @@ -887,7 +875,7 @@ static BOOL enum_compressors(HWND list, COMPVARS *pcv, BOOL enum_all) if (ICCompressQuery(hic, pcv->lpbiIn, NULL) != ICERR_OK) { TRACE("fccHandler %s doesn't support input DIB format %ld\n", - wine_dbgstr_fcc(icinfo.fccHandler), pcv->lpbiIn->bmiHeader.biCompression); + debugstr_fourcc(icinfo.fccHandler), pcv->lpbiIn->bmiHeader.biCompression); ICClose(hic); continue; } @@ -1581,12 +1569,12 @@ BOOL VFWAPI ICSeqCompressFrameStart(PCOMPVARS pc, LPBITMAPINFO lpbiIn) TRACE("Input: %lux%lu, fcc %s, bpp %u, size %lu\n", pc->lpbiIn->bmiHeader.biWidth, pc->lpbiIn->bmiHeader.biHeight, - wine_dbgstr_fcc(pc->lpbiIn->bmiHeader.biCompression), + debugstr_fourcc(pc->lpbiIn->bmiHeader.biCompression), pc->lpbiIn->bmiHeader.biBitCount, pc->lpbiIn->bmiHeader.biSizeImage); TRACE("Output: %lux%lu, fcc %s, bpp %u, size %lu\n", pc->lpbiOut->bmiHeader.biWidth, pc->lpbiOut->bmiHeader.biHeight, - wine_dbgstr_fcc(pc->lpbiOut->bmiHeader.biCompression), + debugstr_fourcc(pc->lpbiOut->bmiHeader.biCompression), pc->lpbiOut->bmiHeader.biBitCount, pc->lpbiOut->bmiHeader.biSizeImage); @@ -1606,8 +1594,8 @@ BOOL VFWAPI ICSeqCompressFrameStart(PCOMPVARS pc, LPBITMAPINFO lpbiIn) "\thandler: %s\n" "\tin/out: %p/%p\n" "\tkey/data/quality: %li/%li/%li\n", - pc->cbSize, pc->dwFlags, pc->hic, wine_dbgstr_fcc(pc->fccType), - wine_dbgstr_fcc(pc->fccHandler), pc->lpbiIn, pc->lpbiOut, pc->lKey, + pc->cbSize, pc->dwFlags, pc->hic, debugstr_fourcc(pc->fccType), + debugstr_fourcc(pc->fccHandler), pc->lpbiIn, pc->lpbiOut, pc->lKey, pc->lDataRate, pc->lQ); ret = ICSendMessage(pc->hic, ICM_COMPRESS_BEGIN, (DWORD_PTR)pc->lpbiIn, (DWORD_PTR)pc->lpbiOut); From dc5feb5341cbdde71ae90c97f2b5c9c4f96cb9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 6 Oct 2023 16:15:08 +0200 Subject: [PATCH 2607/2777] dmime/tests: Tests interaction between CloseDown and notifications. (cherry picked from commit b201cf1bcaa30cb0019023316607e72e8bd66ad2) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 87d938a9015..c892f25c884 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3107,6 +3107,8 @@ static void test_notification_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); + todo_wine ok(hr == S_FALSE, "got %#lx\n", hr); hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, NULL); ok(hr == S_OK, "got %#lx\n", hr); @@ -3178,8 +3180,6 @@ static void test_notification_pmsg(void) ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); ok(!msg, "got %p\n", msg); - IDirectMusicSegment_Release(segment); - hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_PERFORMANCE); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); @@ -3237,8 +3237,34 @@ static void test_notification_pmsg(void) ok(hr == S_FALSE, "got %#lx\n", hr); + /* RemoveNotificationType returns S_FALSE if already removed */ + + hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_PERFORMANCE); + todo_wine ok(hr == S_FALSE, "got %#lx\n", hr); + + + /* CloseDown removes all notifications and notification messages */ + + hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); + ok(hr == S_OK, "got %#lx\n", hr); + } + hr = IDirectMusicPerformance_CloseDown(performance); ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); + todo_wine ok(hr == S_FALSE, "got %#lx\n", hr); + IDirectMusicSegment_Release(segment); + IDirectMusicPerformance_Release(performance); IDirectMusicTool_Release(tool); From 9c48164a20426f107d0f6b0a51cad674acaf7125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 21 Sep 2023 13:54:32 +0200 Subject: [PATCH 2608/2777] dmime: Keep messages with the same time ordered. (cherry picked from commit 299698140a7b7ce8e3868d934ab4553eb2219418) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 9f293358ca6..a5655f4b2df 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -497,7 +497,7 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS } LIST_FOR_EACH_ENTRY(next, &This->messages, struct message, entry) - if (next->msg.rtTime >= message->msg.rtTime) break; + if (next->msg.rtTime > message->msg.rtTime) break; list_add_before(&next->entry, &message->entry); PostThreadMessageW(This->procThreadId, PROCESSMSG_ADD, 0, 0); From ed520422603d517eb58b6943f0e8c09b67c9d58b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 6 Oct 2023 15:28:05 +0200 Subject: [PATCH 2609/2777] dmime: Free all pending messages after CloseDown. (cherry picked from commit ac832b97aeb639d178fdea4986a83c7f935fd9b8) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index a5655f4b2df..5c3e1f17a97 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -948,6 +948,8 @@ static HRESULT WINAPI performance_AdjustTime(IDirectMusicPerformance8 *iface, RE static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct message *message, *next; + HRESULT hr; FIXME("(%p): semi-stub\n", This); @@ -956,6 +958,16 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) This->procThreadTicStarted = FALSE; CloseHandle(This->procThread); } + + LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->messages, struct message, entry) + { + list_remove(&message->entry); + list_init(&message->entry); + + if (FAILED(hr = IDirectMusicPerformance8_FreePMsg(iface, &message->msg))) + WARN("Failed to free message %p, hr %#lx\n", message, hr); + } + if (This->master_clock) { IReferenceClock_Release(This->master_clock); From fa2dae5391ecb04dd98743c9a0a78f6a710e9cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 22 Sep 2023 18:49:16 +0200 Subject: [PATCH 2610/2777] dmime: Send DMUS_PMSGT_DIRTY messages from the performance. (cherry picked from commit 664caf6ed70a31c0e3f0a71e7523dece921a202c) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 37 ++++++++++++++++++-- dlls/dmime/tests/dmime.c | 73 ++++++++++++++-------------------------- 2 files changed, 61 insertions(+), 49 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 5c3e1f17a97..0215b19a23c 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -204,6 +204,27 @@ static BOOL PostMessageToProcessMsgThread(struct performance *This, UINT iMsg) { return PostThreadMessageA(This->procThreadId, iMsg, 0, 0); } +static HRESULT performance_send_dirty_pmsg(struct performance *This, MUSIC_TIME music_time) +{ + IDirectMusicPerformance8 *performance = &This->IDirectMusicPerformance8_iface; + IDirectMusicGraph *graph = &This->IDirectMusicGraph_iface; + DMUS_PMSG *msg; + HRESULT hr; + + if (FAILED(hr = IDirectMusicPerformance8_AllocPMsg(performance, sizeof(*msg), &msg))) + return hr; + + msg->mtTime = music_time; + msg->dwFlags = DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_QUEUE; + msg->dwType = DMUS_PMSGT_DIRTY; + + if (FAILED(hr = IDirectMusicGraph_StampPMsg(graph, msg)) + || FAILED(hr = IDirectMusicPerformance8_SendPMsg(performance, msg))) + IDirectMusicPerformance8_FreePMsg(performance, msg); + + return hr; +} + static int pchannel_block_compare(const void *key, const struct wine_rb_entry *entry) { const struct pchannel_block *b = WINE_RB_ENTRY_VALUE(entry, const struct pchannel_block, entry); @@ -1082,20 +1103,32 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, struct performance *This = impl_from_IDirectMusicPerformance8(iface); IDirectMusicSegmentState *state; IDirectMusicSegment *segment; + MUSIC_TIME length; HRESULT hr; FIXME("(%p, %p, %s, %p, %#lx, %I64d, %p, %p, %p): stub\n", This, source, debugstr_w(segment_name), transition, segment_flags, start_time, segment_state, from, audio_path); + /* NOTE: The time is in music time unless the DMUS_SEGF_REFTIME flag is set. */ + if (segment_flags) FIXME("flags %#lx not implemented\n", segment_flags); + if (start_time) FIXME("start_time %I64d not implemented\n", start_time); + if (FAILED(hr = IUnknown_QueryInterface(source, &IID_IDirectMusicSegment, (void **)&segment))) return hr; - if (FAILED(hr = segment_state_create((IDirectMusicSegment *)segment, start_time, &state))) + if (FAILED(hr = segment_state_create(segment, start_time, &state))) { IDirectMusicSegment_Release(segment); return hr; } - if (segment_state) + hr = IDirectMusicSegment_GetLength(segment, &length); + if (SUCCEEDED(hr)) + hr = performance_send_dirty_pmsg(This, start_time); + + if (SUCCEEDED(hr)) + hr = performance_send_dirty_pmsg(This, start_time + length); + + if (SUCCEEDED(hr) && segment_state) { *segment_state = state; IDirectMusicSegmentState_AddRef(state); diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index c892f25c884..2b7f08eef7a 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3079,22 +3079,16 @@ static void test_notification_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 500, &msg); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, &msg); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); hr = IDirectMusicPerformance_FreePMsg(performance, msg); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - } + ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 100, &msg); ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); @@ -3114,22 +3108,22 @@ static void test_notification_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) + ok(!ret, "got %#lx\n", ret); + if (notif->dwType == DMUS_PMSGT_NOTIFICATION) { check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTARTED); + } hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) + ok(!ret, "got %#lx\n", ret); + if (notif->dwType == DMUS_PMSGT_NOTIFICATION) { check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART); + } hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, &msg); todo_wine ok(!ret, "got %#lx\n", ret); @@ -3251,13 +3245,13 @@ static void test_notification_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) + ok(!ret, "got %#lx\n", ret); + if (notif->dwType == DMUS_PMSGT_NOTIFICATION) { check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART); + } hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - } hr = IDirectMusicPerformance_CloseDown(performance); ok(hr == S_OK, "got %#lx\n", hr); @@ -3333,22 +3327,16 @@ static void test_wave_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 500, &msg); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %p\n", msg); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, &msg); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %p\n", msg); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 100, &msg); ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); @@ -3364,17 +3352,14 @@ static void test_wave_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 500, &msg); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %p\n", msg); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&wave); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) + ok(!ret, "got %#lx\n", ret); + if (wave->dwType == DMUS_PMSGT_WAVE) { ok(wave->dwType == DMUS_PMSGT_WAVE, "got %p\n", wave); ok(!!wave->punkUser, "got %p\n", wave->punkUser); @@ -3384,9 +3369,9 @@ static void test_wave_pmsg(void) ok(wave->lVolume == 0, "got %lu\n", wave->lVolume); ok(wave->lPitch == 0, "got %lu\n", wave->lPitch); ok(wave->bFlags == 0, "got %#x\n", wave->bFlags); + } hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)wave); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, &msg); todo_wine ok(!ret, "got %#lx\n", ret); @@ -3555,22 +3540,19 @@ static void test_sequence_track(void) ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 500, &msg); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬e); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) + ok(!ret, "got %#lx\n", ret); + if (note->dwType == DMUS_PMSGT_NOTE) { check_dmus_note_pmsg(note, 0, 0, 500, 60, 120); + } hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)note); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬e); todo_wine ok(!ret, "got %#lx\n", ret); @@ -3821,22 +3803,19 @@ static void test_band_track_play(void) ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 500, &msg); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&patch); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) + ok(!ret, "got %#lx\n", ret); + if (patch->dwType == DMUS_PMSGT_PATCH) { check_dmus_patch_pmsg(patch, 0, 1, 0, 1); + } hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)patch); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&patch); todo_wine ok(!ret, "got %#lx\n", ret); From 39f140be8f5e323f06c387a3442e5ae647069cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 7 Oct 2023 10:48:36 +0200 Subject: [PATCH 2611/2777] dmime: Send DMUS_PMSGT_NOTIFICATION messages from the performance. Keeping the segment state referenced until its playback ends. (cherry picked from commit 3de1bc035ede848b5661da7d4ad8af5220a5ae28) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 72 +++++++++++++++++++++++++++++++++++----- dlls/dmime/tests/dmime.c | 34 +++---------------- 2 files changed, 69 insertions(+), 37 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 0215b19a23c..40a78bc40ce 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -66,6 +66,9 @@ struct performance IReferenceClock *master_clock; REFERENCE_TIME init_time; struct list messages; + + BOOL notification_performance; + BOOL notification_segment; }; struct message @@ -225,6 +228,32 @@ static HRESULT performance_send_dirty_pmsg(struct performance *This, MUSIC_TIME return hr; } +static HRESULT performance_send_notification_pmsg(struct performance *This, MUSIC_TIME music_time, BOOL stamp, + GUID type, DWORD option, IUnknown *object) +{ + IDirectMusicPerformance8 *performance = &This->IDirectMusicPerformance8_iface; + IDirectMusicGraph *graph = &This->IDirectMusicGraph_iface; + DMUS_NOTIFICATION_PMSG *msg; + HRESULT hr; + + if (FAILED(hr = IDirectMusicPerformance8_AllocPMsg(performance, sizeof(*msg), (DMUS_PMSG **)&msg))) + return hr; + + msg->mtTime = music_time; + msg->dwFlags = DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_QUEUE; + msg->dwType = DMUS_PMSGT_NOTIFICATION; + if ((msg->punkUser = object)) IUnknown_AddRef(object); + msg->guidNotificationType = type; + msg->dwNotificationOption = option; + + /* only stamp the message if notifications are enabled, otherwise send them directly to the output tool */ + if ((stamp && FAILED(hr = IDirectMusicGraph_StampPMsg(graph, (DMUS_PMSG *)msg))) + || FAILED(hr = IDirectMusicPerformance8_SendPMsg(performance, (DMUS_PMSG *)msg))) + IDirectMusicPerformance8_FreePMsg(performance, (DMUS_PMSG *)msg); + + return hr; +} + static int pchannel_block_compare(const void *key, const struct wine_rb_entry *entry) { const struct pchannel_block *b = WINE_RB_ENTRY_VALUE(entry, const struct pchannel_block, entry); @@ -703,20 +732,32 @@ static HRESULT WINAPI performance_GetNotificationPMsg(IDirectMusicPerformance8 * /*return S_OK;*/ } -static HRESULT WINAPI performance_AddNotificationType(IDirectMusicPerformance8 *iface, REFGUID rguidNotificationType) +static HRESULT WINAPI performance_AddNotificationType(IDirectMusicPerformance8 *iface, REFGUID type) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); - FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType)); - return S_OK; + FIXME("(%p, %s): stub\n", This, debugstr_dmguid(type)); + + if (IsEqualGUID(type, &GUID_NOTIFICATION_PERFORMANCE)) + This->notification_performance = TRUE; + if (IsEqualGUID(type, &GUID_NOTIFICATION_SEGMENT)) + This->notification_segment = TRUE; + + return S_OK; } -static HRESULT WINAPI performance_RemoveNotificationType(IDirectMusicPerformance8 *iface, REFGUID rguidNotificationType) +static HRESULT WINAPI performance_RemoveNotificationType(IDirectMusicPerformance8 *iface, REFGUID type) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); - FIXME("(%p, %s): stub\n", This, debugstr_dmguid(rguidNotificationType)); - return S_OK; + FIXME("(%p, %s): stub\n", This, debugstr_dmguid(type)); + + if (IsEqualGUID(type, &GUID_NOTIFICATION_PERFORMANCE)) + This->notification_performance = FALSE; + if (IsEqualGUID(type, &GUID_NOTIFICATION_SEGMENT)) + This->notification_segment = FALSE; + + return S_OK; } static HRESULT perf_dmport_create(struct performance *perf, DMUS_PORTPARAMS *params) @@ -1122,11 +1163,26 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, } hr = IDirectMusicSegment_GetLength(segment, &length); + if (SUCCEEDED(hr)) + hr = performance_send_notification_pmsg(This, start_time, This->notification_performance, + GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTARTED, NULL); + if (SUCCEEDED(hr)) + hr = performance_send_notification_pmsg(This, start_time, This->notification_segment, + GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART, (IUnknown *)state); if (SUCCEEDED(hr)) hr = performance_send_dirty_pmsg(This, start_time); + if (SUCCEEDED(hr)) + hr = performance_send_notification_pmsg(This, start_time + length, This->notification_segment, + GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND, (IUnknown *)state); + if (SUCCEEDED(hr)) + hr = performance_send_notification_pmsg(This, start_time + length, This->notification_segment, + GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND, (IUnknown *)state); if (SUCCEEDED(hr)) hr = performance_send_dirty_pmsg(This, start_time + length); + if (SUCCEEDED(hr)) + hr = performance_send_notification_pmsg(This, start_time + length, This->notification_performance, + GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTOPPED, NULL); if (SUCCEEDED(hr) && segment_state) { diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 2b7f08eef7a..c8c330860a8 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3109,66 +3109,45 @@ static void test_notification_pmsg(void) ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); ok(!ret, "got %#lx\n", ret); - if (notif->dwType == DMUS_PMSGT_NOTIFICATION) - { check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTARTED); - } hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); ok(!ret, "got %#lx\n", ret); - if (notif->dwType == DMUS_PMSGT_NOTIFICATION) - { check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART); - } hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 500, &msg); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, &msg); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTOPPED); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 100, &msg); ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); @@ -3246,10 +3225,7 @@ static void test_notification_pmsg(void) ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); ok(!ret, "got %#lx\n", ret); - if (notif->dwType == DMUS_PMSGT_NOTIFICATION) - { check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART); - } hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); From 43887db1235679877c8dff7e9fb97c48f891b465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 6 Oct 2023 15:55:13 +0200 Subject: [PATCH 2612/2777] dmime: Implement IDirectMusicPerformance_GetNotificationPMsg. (cherry picked from commit 7a678903fbe9b384e97b23bc8cb73c9239616054) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 108 ++++++++++++++++++++++++++++++--------- dlls/dmime/tests/dmime.c | 31 +++-------- 2 files changed, 93 insertions(+), 46 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 40a78bc40ce..3d53d754d11 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -52,8 +52,6 @@ struct performance BOOL audio_paths_enabled; IDirectMusicAudioPath *pDefaultPath; - HANDLE hNotification; - REFERENCE_TIME rtMinimum; REFERENCE_TIME rtLatencyTime; DWORD dwBumperLength; DWORD dwPrepareTime; @@ -67,6 +65,9 @@ struct performance REFERENCE_TIME init_time; struct list messages; + struct list notifications; + REFERENCE_TIME notification_timeout; + HANDLE notification_event; BOOL notification_performance; BOOL notification_segment; }; @@ -702,62 +703,84 @@ static HRESULT WINAPI performance_SetGraph(IDirectMusicPerformance8 *iface, IDir } static HRESULT WINAPI performance_SetNotificationHandle(IDirectMusicPerformance8 *iface, - HANDLE hNotification, REFERENCE_TIME rtMinimum) + HANDLE notification_event, REFERENCE_TIME minimum_time) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); - TRACE("(%p, %p, 0x%s)\n", This, hNotification, wine_dbgstr_longlong(rtMinimum)); + TRACE("(%p, %p, %I64d)\n", This, notification_event, minimum_time); + + This->notification_event = notification_event; + if (minimum_time) + This->notification_timeout = minimum_time; + else if (!This->notification_timeout) + This->notification_timeout = 20000000; /* 2 seconds */ - This->hNotification = hNotification; - if (rtMinimum) - This->rtMinimum = rtMinimum; - else if (!This->rtMinimum) - This->rtMinimum = 20000000; /* 2 seconds */ return S_OK; } static HRESULT WINAPI performance_GetNotificationPMsg(IDirectMusicPerformance8 *iface, - DMUS_NOTIFICATION_PMSG **ppNotificationPMsg) + DMUS_NOTIFICATION_PMSG **ret_msg) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct list *entry; - FIXME("(%p, %p): stub\n", This, ppNotificationPMsg); - if (NULL == ppNotificationPMsg) { - return E_POINTER; - } - - + TRACE("(%p, %p)\n", This, ret_msg); + + if (!ret_msg) return E_POINTER; - return S_FALSE; - /*return S_OK;*/ + EnterCriticalSection(&This->safe); + if ((entry = list_head(&This->notifications))) + { + struct message *message = LIST_ENTRY(entry, struct message, entry); + list_remove(&message->entry); + list_init(&message->entry); + *ret_msg = (DMUS_NOTIFICATION_PMSG *)&message->msg; + } + LeaveCriticalSection(&This->safe); + + return entry ? S_OK : S_FALSE; } static HRESULT WINAPI performance_AddNotificationType(IDirectMusicPerformance8 *iface, REFGUID type) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); + HRESULT hr = S_OK; FIXME("(%p, %s): stub\n", This, debugstr_dmguid(type)); if (IsEqualGUID(type, &GUID_NOTIFICATION_PERFORMANCE)) + { + hr = This->notification_performance ? S_FALSE : S_OK; This->notification_performance = TRUE; + } if (IsEqualGUID(type, &GUID_NOTIFICATION_SEGMENT)) + { + hr = This->notification_segment ? S_FALSE : S_OK; This->notification_segment = TRUE; + } - return S_OK; + return hr; } static HRESULT WINAPI performance_RemoveNotificationType(IDirectMusicPerformance8 *iface, REFGUID type) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); + HRESULT hr = S_FALSE; FIXME("(%p, %s): stub\n", This, debugstr_dmguid(type)); if (IsEqualGUID(type, &GUID_NOTIFICATION_PERFORMANCE)) + { + hr = This->notification_performance ? S_OK : S_FALSE; This->notification_performance = FALSE; + } if (IsEqualGUID(type, &GUID_NOTIFICATION_SEGMENT)) + { + hr = This->notification_segment ? S_OK : S_FALSE; This->notification_segment = FALSE; + } - return S_OK; + return hr; } static HRESULT perf_dmport_create(struct performance *perf, DMUS_PORTPARAMS *params) @@ -1021,6 +1044,9 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) CloseHandle(This->procThread); } + This->notification_performance = FALSE; + This->notification_segment = FALSE; + LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->messages, struct message, entry) { list_remove(&message->entry); @@ -1030,6 +1056,15 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) WARN("Failed to free message %p, hr %#lx\n", message, hr); } + LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->notifications, struct message, entry) + { + list_remove(&message->entry); + list_init(&message->entry); + + if (FAILED(hr = IDirectMusicPerformance8_FreePMsg(iface, &message->msg))) + WARN("Failed to free message %p, hr %#lx\n", message, hr); + } + if (This->master_clock) { IReferenceClock_Release(This->master_clock); @@ -1586,14 +1621,40 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, IDirectMusicPerformance *performance, DMUS_PMSG *msg) { struct performance *This = impl_from_IDirectMusicTool(iface); + struct message *message = message_from_DMUS_PMSG(msg); FIXME("(%p, %p, %p): semi-stub\n", This, performance, msg); switch (msg->dwType) { case DMUS_PMSGT_NOTIFICATION: - SetEvent(This->hNotification); - /* fallthrough */ + { + DMUS_NOTIFICATION_PMSG *notif = (DMUS_NOTIFICATION_PMSG *)msg; + struct message *previous; + BOOL enabled = FALSE; + HRESULT hr; + + if (IsEqualGUID(¬if->guidNotificationType, &GUID_NOTIFICATION_PERFORMANCE)) + enabled = This->notification_performance; + if (IsEqualGUID(¬if->guidNotificationType, &GUID_NOTIFICATION_SEGMENT)) + enabled = This->notification_segment; + if (!enabled) return DMUS_S_FREE; + + list_add_tail(&This->notifications, &message->entry); + + /* discard old notification messages */ + do + { + previous = LIST_ENTRY(list_head(&This->notifications), struct message, entry); + if (message->msg.rtTime - previous->msg.rtTime <= This->notification_timeout) break; + list_remove(&previous->entry); + list_init(&previous->entry); + } while (SUCCEEDED(hr = IDirectMusicPerformance_FreePMsg(performance, &previous->msg))); + + SetEvent(This->notification_event); + return S_OK; + } + default: FIXME("Unhandled message type %#lx\n", msg->dwType); break; @@ -1644,6 +1705,7 @@ HRESULT create_dmperformance(REFIID iid, void **ret_iface) wine_rb_init(&obj->pchannels, pchannel_block_compare); list_init(&obj->messages); + list_init(&obj->notifications); obj->rtLatencyTime = 100; /* 100 ms TO FIX */ obj->dwBumperLength = 50; /* 50 ms default */ diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index c8c330860a8..f9143176594 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3102,7 +3102,7 @@ static void test_notification_pmsg(void) hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); - todo_wine ok(hr == S_FALSE, "got %#lx\n", hr); + ok(hr == S_FALSE, "got %#lx\n", hr); hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, NULL); ok(hr == S_OK, "got %#lx\n", hr); @@ -3162,49 +3162,34 @@ static void test_notification_pmsg(void) /* notification messages are also queued for direct access */ hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - if (hr == S_OK) - { + ok(hr == S_OK, "got %#lx\n", hr); check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTARTED); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - } hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - if (hr == S_OK) - { + ok(hr == S_OK, "got %#lx\n", hr); check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - } hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - if (hr == S_OK) - { + ok(hr == S_OK, "got %#lx\n", hr); check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - } hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - if (hr == S_OK) - { + ok(hr == S_OK, "got %#lx\n", hr); check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - } hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - if (hr == S_OK) - { + ok(hr == S_OK, "got %#lx\n", hr); check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTOPPED); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - } hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); ok(hr == S_FALSE, "got %#lx\n", hr); @@ -3213,7 +3198,7 @@ static void test_notification_pmsg(void) /* RemoveNotificationType returns S_FALSE if already removed */ hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_PERFORMANCE); - todo_wine ok(hr == S_FALSE, "got %#lx\n", hr); + ok(hr == S_FALSE, "got %#lx\n", hr); /* CloseDown removes all notifications and notification messages */ @@ -3232,7 +3217,7 @@ static void test_notification_pmsg(void) hr = IDirectMusicPerformance_CloseDown(performance); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); - todo_wine ok(hr == S_FALSE, "got %#lx\n", hr); + ok(hr == S_FALSE, "got %#lx\n", hr); IDirectMusicSegment_Release(segment); From 8835c213a5b107e597fbf8b0468c92845a682d55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 22 Sep 2023 17:30:51 +0200 Subject: [PATCH 2613/2777] dmime: Call IDirectMusicTrack_(Init|End)Play from the segment state. (cherry picked from commit 3e19ca928e8479edce9f9484dc841d08edbdf5f8) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/dmime_private.h | 4 +- dlls/dmime/performance.c | 21 +++++++- dlls/dmime/segmentstate.c | 98 +++++++++++++++++++++++++++++++++++++- dlls/dmime/tests/dmime.c | 14 +++--- 4 files changed, 125 insertions(+), 12 deletions(-) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index c35c52eb066..e67797def30 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -71,7 +71,9 @@ extern void set_audiopath_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffe extern void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*); extern HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, - IDirectMusicSegmentState **ret_iface); + IDirectMusicPerformance *performance, IDirectMusicSegmentState **ret_iface); +extern HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance *performance); +extern HRESULT segment_state_end_play(IDirectMusicSegmentState *iface); /***************************************************************************** * Auxiliary definitions diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 3d53d754d11..7d077db16cb 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1052,7 +1052,14 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) list_remove(&message->entry); list_init(&message->entry); - if (FAILED(hr = IDirectMusicPerformance8_FreePMsg(iface, &message->msg))) + /* process notifications to end any pending segment states */ + if (message->msg.dwType == DMUS_PMSGT_NOTIFICATION) + hr = IDirectMusicTool_ProcessPMsg(&This->IDirectMusicTool_iface, + (IDirectMusicPerformance *)iface, &message->msg); + else + hr = DMUS_S_FREE; + + if (hr == DMUS_S_FREE && FAILED(hr = IDirectMusicPerformance8_FreePMsg(iface, &message->msg))) WARN("Failed to free message %p, hr %#lx\n", message, hr); } @@ -1191,7 +1198,7 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, if (FAILED(hr = IUnknown_QueryInterface(source, &IID_IDirectMusicSegment, (void **)&segment))) return hr; - if (FAILED(hr = segment_state_create(segment, start_time, &state))) + if (FAILED(hr = segment_state_create(segment, start_time, (IDirectMusicPerformance *)iface, &state))) { IDirectMusicSegment_Release(segment); return hr; @@ -1207,6 +1214,9 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, if (SUCCEEDED(hr)) hr = performance_send_dirty_pmsg(This, start_time); + if (SUCCEEDED(hr)) + hr = segment_state_play(state, (IDirectMusicPerformance *)iface); + if (SUCCEEDED(hr)) hr = performance_send_notification_pmsg(This, start_time + length, This->notification_segment, GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND, (IUnknown *)state); @@ -1634,6 +1644,13 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, BOOL enabled = FALSE; HRESULT hr; + if (IsEqualGUID(¬if->guidNotificationType, &GUID_NOTIFICATION_SEGMENT) + && notif->dwNotificationOption == DMUS_NOTIFICATION_SEGEND) + { + if (FAILED(hr = segment_state_end_play((IDirectMusicSegmentState *)notif->punkUser))) + WARN("Failed to end segment state %p, hr %#lx\n", notif->punkUser, hr); + } + if (IsEqualGUID(¬if->guidNotificationType, &GUID_NOTIFICATION_PERFORMANCE)) enabled = This->notification_performance; if (IsEqualGUID(¬if->guidNotificationType, &GUID_NOTIFICATION_SEGMENT)) diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index 1a09bed5dd3..de47d85e9b8 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -21,14 +21,39 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmime); +static DWORD next_track_id; + +struct track_entry +{ + struct list entry; + + IDirectMusicTrack *track; + void *state_data; + DWORD track_id; +}; + +static void track_entry_destroy(struct track_entry *entry) +{ + HRESULT hr; + + if (FAILED(hr = IDirectMusicTrack_EndPlay(entry->track, entry->state_data))) + WARN("track %p EndPlay failed, hr %#lx\n", entry->track, hr); + + IDirectMusicTrack_Release(entry->track); + free(entry); +} + struct segment_state { IDirectMusicSegmentState8 IDirectMusicSegmentState8_iface; LONG ref; IDirectMusicSegment *segment; - MUSIC_TIME start_point; MUSIC_TIME start_time; + MUSIC_TIME start_point; + MUSIC_TIME end_point; + + struct list tracks; }; static inline struct segment_state *impl_from_IDirectMusicSegmentState8(IDirectMusicSegmentState8 *iface) @@ -79,6 +104,7 @@ static ULONG WINAPI segment_state_Release(IDirectMusicSegmentState8 *iface) if (!ref) { + segment_state_end_play((IDirectMusicSegmentState *)iface); if (This->segment) IDirectMusicSegment_Release(This->segment); free(This); } @@ -174,6 +200,7 @@ HRESULT create_dmsegmentstate(REFIID riid, void **ret_iface) obj->IDirectMusicSegmentState8_iface.lpVtbl = &segment_state_vtbl; obj->ref = 1; obj->start_time = -1; + list_init(&obj->tracks); TRACE("Created IDirectMusicSegmentState %p\n", obj); hr = IDirectMusicSegmentState8_QueryInterface(&obj->IDirectMusicSegmentState8_iface, riid, ret_iface); @@ -182,11 +209,13 @@ HRESULT create_dmsegmentstate(REFIID riid, void **ret_iface) } HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, - IDirectMusicSegmentState **ret_iface) + IDirectMusicPerformance *performance, IDirectMusicSegmentState **ret_iface) { IDirectMusicSegmentState *iface; struct segment_state *This; + IDirectMusicTrack *track; HRESULT hr; + UINT i; TRACE("(%p, %lu, %p)\n", segment, start_time, ret_iface); @@ -198,8 +227,73 @@ HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time This->start_time = start_time; hr = IDirectMusicSegment_GetStartPoint(segment, &This->start_point); + if (SUCCEEDED(hr)) hr = IDirectMusicSegment_GetLength(segment, &This->end_point); + + for (i = 0; SUCCEEDED(hr); i++) + { + DWORD track_id = ++next_track_id; + struct track_entry *entry; + + if ((hr = IDirectMusicSegment_GetTrack(segment, &GUID_NULL, -1, i, &track)) != S_OK) + { + if (hr == DMUS_E_NOT_FOUND) hr = S_OK; + break; + } + + if (!(entry = malloc(sizeof(*entry)))) + hr = E_OUTOFMEMORY; + else if (SUCCEEDED(hr = IDirectMusicTrack_InitPlay(track, iface, performance, + &entry->state_data, track_id, 0))) + { + entry->track = track; + entry->track_id = track_id; + list_add_tail(&This->tracks, &entry->entry); + } + + if (FAILED(hr)) + { + WARN("Failed to initialize track %p, hr %#lx\n", track, hr); + IDirectMusicTrack_Release(track); + free(entry); + } + } if (SUCCEEDED(hr)) *ret_iface = iface; else IDirectMusicSegmentState_Release(iface); return hr; } + +HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance *performance) +{ + struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); + DWORD track_flags = DMUS_TRACKF_DIRTY | DMUS_TRACKF_START | DMUS_TRACKF_SEEK; + MUSIC_TIME start_time = This->start_point, end_time = This->end_point; + struct track_entry *entry; + HRESULT hr = S_OK; + + LIST_FOR_EACH_ENTRY(entry, &This->tracks, struct track_entry, entry) + { + if (FAILED(hr = IDirectMusicTrack_Play(entry->track, entry->state_data, start_time, + end_time, 0, track_flags, performance, iface, entry->track_id))) + { + WARN("Failed to play track %p, hr %#lx\n", entry->track, hr); + break; + } + } + + return hr; +} + +HRESULT segment_state_end_play(IDirectMusicSegmentState *iface) +{ + struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); + struct track_entry *entry, *next; + + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &This->tracks, struct track_entry, entry) + { + list_remove(&entry->entry); + track_entry_destroy(entry); + } + + return S_OK; +} diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index f9143176594..cb35ef64ead 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -662,7 +662,7 @@ static HRESULT WINAPI test_track_Play(IDirectMusicTrack *iface, void *state_data ok(state_data == &This->data, "got %p\n", state_data); ok(start_time == 50, "got %lu\n", start_time); ok(end_time == 100, "got %lu\n", end_time); - ok(time_offset < 0, "got %lu\n", time_offset); + todo_wine ok(time_offset < 0, "got %lu\n", time_offset); ok(segment_flags == (DMUS_TRACKF_DIRTY|DMUS_TRACKF_START|DMUS_TRACKF_SEEK), "got %#lx\n", segment_flags); ok(!!performance, "got %p\n", performance); @@ -3990,7 +3990,7 @@ static void test_segment_state(void) IDirectMusicSegmentState_Release(tmp_state); check_track_state(track, downloaded, FALSE); - todo_wine check_track_state(track, initialized, TRUE); + check_track_state(track, initialized, TRUE); /* The track can be removed from the segment */ @@ -4001,10 +4001,10 @@ static void test_segment_state(void) /* This might be timing dependent and if PlaySegment is already * late, the tracks are played synchronously and right away. */ - check_track_state(track, playing, FALSE); + todo_wine check_track_state(track, playing, FALSE); ret = test_track_wait_playing(track, 50); - todo_wine ok(ret == 0, "got %#lx\n", ret); + ok(ret == 0, "got %#lx\n", ret); tmp_segment = (void *)0xdeadbeef; @@ -4064,14 +4064,14 @@ static void test_segment_state(void) check_track_state(track, downloaded, FALSE); - todo_wine check_track_state(track, initialized, TRUE); - todo_wine check_track_state(track, playing, TRUE); + check_track_state(track, initialized, TRUE); + check_track_state(track, playing, TRUE); hr = IDirectMusicPerformance_CloseDown(performance); ok(hr == S_OK, "got %#lx\n", hr); check_track_state(track, downloaded, FALSE); - todo_wine check_track_state(track, initialized, TRUE); + check_track_state(track, initialized, TRUE); check_track_state(track, playing, FALSE); From 316137339769bb0a0dec4ca16e2b1f303b5a4a54 Mon Sep 17 00:00:00 2001 From: Francois Gouget Date: Fri, 6 Oct 2023 09:37:47 +0200 Subject: [PATCH 2614/2777] dmsynth: Add a trailing linefeed to TRACE() messages. (cherry picked from commit 622daeaf89a08a6073fbb2202b57e64e305d5213) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index d87afd245e9..c36196c0407 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -82,8 +82,8 @@ static void dump_connectionlist(CONNECTIONLIST *list) UINT i; TRACE("CONNECTIONLIST:\n"); - TRACE(" - cbSize = %lu", list->cbSize); - TRACE(" - cConnections = %lu", list->cConnections); + TRACE(" - cbSize = %lu\n", list->cbSize); + TRACE(" - cConnections = %lu\n", list->cConnections); for (i = 0; i < list->cConnections; i++) { From 5f565bdfd92230c9a7bc7a097d0a61204546eff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 3 Oct 2023 15:13:28 +0200 Subject: [PATCH 2615/2777] dmime/tests: Queue the message before calling SendPMsg twice. (cherry picked from commit d0c3a0e03d557498195a70693003deae5b3e4588) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index cb35ef64ead..e390f86f1bf 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -2849,7 +2849,7 @@ static void test_performance_pmsg(void) ok(clone != NULL, "got %p\n", clone); msg->mtTime = 500; - msg->dwFlags = DMUS_PMSGF_MUSICTIME; + msg->dwFlags = DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_QUEUE; hr = IDirectMusicPerformance_SendPMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPerformance_SendPMsg(performance, msg); From cd7ee3318fafa9aab250a7eff3be05180c518d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 10 Oct 2023 23:45:10 +0200 Subject: [PATCH 2616/2777] dmsynth: Import and use FluidSynth 2.3.3. (cherry picked from commit f768d6b31bebc35fbaf751d0cd57c8bd302a8d60) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- configure.ac | 11 + dlls/dmsynth/Makefile.in | 3 +- dlls/dmsynth/synth.c | 11 + libs/fluidsynth/AUTHORS | 157 + libs/fluidsynth/COPYING.md | 7 + libs/fluidsynth/Makefile.in | 42 + libs/fluidsynth/config.h | 271 + libs/fluidsynth/fluid_conv_tables.inc.h | 3915 ++++++++ libs/fluidsynth/fluid_rvoice_dsp_tables.inc.h | 4109 ++++++++ libs/fluidsynth/glib.c | 106 + libs/fluidsynth/glib.h | 107 + libs/fluidsynth/include/fluidsynth.h | 125 + libs/fluidsynth/include/fluidsynth/audio.h | 155 + libs/fluidsynth/include/fluidsynth/event.h | 143 + libs/fluidsynth/include/fluidsynth/gen.h | 133 + libs/fluidsynth/include/fluidsynth/ladspa.h | 68 + libs/fluidsynth/include/fluidsynth/log.h | 97 + libs/fluidsynth/include/fluidsynth/midi.h | 295 + libs/fluidsynth/include/fluidsynth/misc.h | 77 + libs/fluidsynth/include/fluidsynth/mod.h | 104 + libs/fluidsynth/include/fluidsynth/seq.h | 92 + libs/fluidsynth/include/fluidsynth/seqbind.h | 44 + libs/fluidsynth/include/fluidsynth/settings.h | 194 + libs/fluidsynth/include/fluidsynth/sfont.h | 362 + libs/fluidsynth/include/fluidsynth/shell.h | 150 + libs/fluidsynth/include/fluidsynth/synth.h | 552 ++ libs/fluidsynth/include/fluidsynth/types.h | 85 + libs/fluidsynth/include/fluidsynth/version.h | 47 + libs/fluidsynth/include/fluidsynth/voice.h | 76 + libs/fluidsynth/src/bindings/fluid_ladspa.h | 36 + libs/fluidsynth/src/midi/fluid_midi.c | 2851 ++++++ libs/fluidsynth/src/midi/fluid_midi.h | 384 + libs/fluidsynth/src/midi/fluid_midi_router.h | 32 + libs/fluidsynth/src/rvoice/fluid_adsr_env.c | 38 + libs/fluidsynth/src/rvoice/fluid_adsr_env.h | 166 + libs/fluidsynth/src/rvoice/fluid_chorus.c | 1071 +++ libs/fluidsynth/src/rvoice/fluid_chorus.h | 80 + libs/fluidsynth/src/rvoice/fluid_iir_filter.c | 418 + libs/fluidsynth/src/rvoice/fluid_iir_filter.h | 74 + libs/fluidsynth/src/rvoice/fluid_lfo.c | 17 + libs/fluidsynth/src/rvoice/fluid_lfo.h | 74 + libs/fluidsynth/src/rvoice/fluid_phase.h | 113 + libs/fluidsynth/src/rvoice/fluid_rev.c | 1523 +++ libs/fluidsynth/src/rvoice/fluid_rev.h | 91 + libs/fluidsynth/src/rvoice/fluid_rvoice.c | 935 ++ libs/fluidsynth/src/rvoice/fluid_rvoice.h | 231 + libs/fluidsynth/src/rvoice/fluid_rvoice_dsp.c | 636 ++ .../src/rvoice/fluid_rvoice_event.c | 202 + .../src/rvoice/fluid_rvoice_event.h | 114 + .../src/rvoice/fluid_rvoice_mixer.c | 1727 ++++ .../src/rvoice/fluid_rvoice_mixer.h | 87 + libs/fluidsynth/src/sfloader/fluid_defsfont.c | 2372 +++++ libs/fluidsynth/src/sfloader/fluid_defsfont.h | 232 + .../fluidsynth/src/sfloader/fluid_instpatch.h | 14 + .../src/sfloader/fluid_samplecache.c | 313 + .../src/sfloader/fluid_samplecache.h | 37 + libs/fluidsynth/src/sfloader/fluid_sffile.c | 2527 +++++ libs/fluidsynth/src/sfloader/fluid_sffile.h | 194 + libs/fluidsynth/src/sfloader/fluid_sfont.c | 850 ++ libs/fluidsynth/src/sfloader/fluid_sfont.h | 189 + libs/fluidsynth/src/synth/fluid_chan.c | 732 ++ libs/fluidsynth/src/synth/fluid_chan.h | 276 + libs/fluidsynth/src/synth/fluid_event.c | 863 ++ libs/fluidsynth/src/synth/fluid_event.h | 65 + libs/fluidsynth/src/synth/fluid_gen.c | 133 + libs/fluidsynth/src/synth/fluid_gen.h | 67 + libs/fluidsynth/src/synth/fluid_mod.c | 880 ++ libs/fluidsynth/src/synth/fluid_mod.h | 54 + libs/fluidsynth/src/synth/fluid_synth.c | 8445 +++++++++++++++++ libs/fluidsynth/src/synth/fluid_synth.h | 263 + .../src/synth/fluid_synth_monopoly.c | 722 ++ libs/fluidsynth/src/synth/fluid_tuning.c | 190 + libs/fluidsynth/src/synth/fluid_tuning.h | 69 + libs/fluidsynth/src/synth/fluid_voice.c | 2051 ++++ libs/fluidsynth/src/synth/fluid_voice.h | 198 + libs/fluidsynth/src/utils/fluid_conv.c | 333 + libs/fluidsynth/src/utils/fluid_conv.h | 40 + libs/fluidsynth/src/utils/fluid_conv_tables.h | 41 + libs/fluidsynth/src/utils/fluid_hash.c | 1407 +++ libs/fluidsynth/src/utils/fluid_hash.h | 130 + libs/fluidsynth/src/utils/fluid_list.c | 337 + libs/fluidsynth/src/utils/fluid_list.h | 63 + libs/fluidsynth/src/utils/fluid_ringbuffer.c | 90 + libs/fluidsynth/src/utils/fluid_ringbuffer.h | 133 + libs/fluidsynth/src/utils/fluid_settings.c | 2004 ++++ libs/fluidsynth/src/utils/fluid_settings.h | 65 + libs/fluidsynth/src/utils/fluid_sys.c | 1803 ++++ libs/fluidsynth/src/utils/fluid_sys.h | 794 ++ libs/fluidsynth/src/utils/fluidsynth_priv.h | 331 + 89 files changed, 51744 insertions(+), 1 deletion(-) create mode 100644 libs/fluidsynth/AUTHORS create mode 100644 libs/fluidsynth/COPYING.md create mode 100644 libs/fluidsynth/Makefile.in create mode 100644 libs/fluidsynth/config.h create mode 100644 libs/fluidsynth/fluid_conv_tables.inc.h create mode 100644 libs/fluidsynth/fluid_rvoice_dsp_tables.inc.h create mode 100644 libs/fluidsynth/glib.c create mode 100644 libs/fluidsynth/glib.h create mode 100644 libs/fluidsynth/include/fluidsynth.h create mode 100644 libs/fluidsynth/include/fluidsynth/audio.h create mode 100644 libs/fluidsynth/include/fluidsynth/event.h create mode 100644 libs/fluidsynth/include/fluidsynth/gen.h create mode 100644 libs/fluidsynth/include/fluidsynth/ladspa.h create mode 100644 libs/fluidsynth/include/fluidsynth/log.h create mode 100644 libs/fluidsynth/include/fluidsynth/midi.h create mode 100644 libs/fluidsynth/include/fluidsynth/misc.h create mode 100644 libs/fluidsynth/include/fluidsynth/mod.h create mode 100644 libs/fluidsynth/include/fluidsynth/seq.h create mode 100644 libs/fluidsynth/include/fluidsynth/seqbind.h create mode 100644 libs/fluidsynth/include/fluidsynth/settings.h create mode 100644 libs/fluidsynth/include/fluidsynth/sfont.h create mode 100644 libs/fluidsynth/include/fluidsynth/shell.h create mode 100644 libs/fluidsynth/include/fluidsynth/synth.h create mode 100644 libs/fluidsynth/include/fluidsynth/types.h create mode 100644 libs/fluidsynth/include/fluidsynth/version.h create mode 100644 libs/fluidsynth/include/fluidsynth/voice.h create mode 100644 libs/fluidsynth/src/bindings/fluid_ladspa.h create mode 100644 libs/fluidsynth/src/midi/fluid_midi.c create mode 100644 libs/fluidsynth/src/midi/fluid_midi.h create mode 100644 libs/fluidsynth/src/midi/fluid_midi_router.h create mode 100644 libs/fluidsynth/src/rvoice/fluid_adsr_env.c create mode 100644 libs/fluidsynth/src/rvoice/fluid_adsr_env.h create mode 100644 libs/fluidsynth/src/rvoice/fluid_chorus.c create mode 100644 libs/fluidsynth/src/rvoice/fluid_chorus.h create mode 100644 libs/fluidsynth/src/rvoice/fluid_iir_filter.c create mode 100644 libs/fluidsynth/src/rvoice/fluid_iir_filter.h create mode 100644 libs/fluidsynth/src/rvoice/fluid_lfo.c create mode 100644 libs/fluidsynth/src/rvoice/fluid_lfo.h create mode 100644 libs/fluidsynth/src/rvoice/fluid_phase.h create mode 100644 libs/fluidsynth/src/rvoice/fluid_rev.c create mode 100644 libs/fluidsynth/src/rvoice/fluid_rev.h create mode 100644 libs/fluidsynth/src/rvoice/fluid_rvoice.c create mode 100644 libs/fluidsynth/src/rvoice/fluid_rvoice.h create mode 100644 libs/fluidsynth/src/rvoice/fluid_rvoice_dsp.c create mode 100644 libs/fluidsynth/src/rvoice/fluid_rvoice_event.c create mode 100644 libs/fluidsynth/src/rvoice/fluid_rvoice_event.h create mode 100644 libs/fluidsynth/src/rvoice/fluid_rvoice_mixer.c create mode 100644 libs/fluidsynth/src/rvoice/fluid_rvoice_mixer.h create mode 100644 libs/fluidsynth/src/sfloader/fluid_defsfont.c create mode 100644 libs/fluidsynth/src/sfloader/fluid_defsfont.h create mode 100644 libs/fluidsynth/src/sfloader/fluid_instpatch.h create mode 100644 libs/fluidsynth/src/sfloader/fluid_samplecache.c create mode 100644 libs/fluidsynth/src/sfloader/fluid_samplecache.h create mode 100644 libs/fluidsynth/src/sfloader/fluid_sffile.c create mode 100644 libs/fluidsynth/src/sfloader/fluid_sffile.h create mode 100644 libs/fluidsynth/src/sfloader/fluid_sfont.c create mode 100644 libs/fluidsynth/src/sfloader/fluid_sfont.h create mode 100644 libs/fluidsynth/src/synth/fluid_chan.c create mode 100644 libs/fluidsynth/src/synth/fluid_chan.h create mode 100644 libs/fluidsynth/src/synth/fluid_event.c create mode 100644 libs/fluidsynth/src/synth/fluid_event.h create mode 100644 libs/fluidsynth/src/synth/fluid_gen.c create mode 100644 libs/fluidsynth/src/synth/fluid_gen.h create mode 100644 libs/fluidsynth/src/synth/fluid_mod.c create mode 100644 libs/fluidsynth/src/synth/fluid_mod.h create mode 100644 libs/fluidsynth/src/synth/fluid_synth.c create mode 100644 libs/fluidsynth/src/synth/fluid_synth.h create mode 100644 libs/fluidsynth/src/synth/fluid_synth_monopoly.c create mode 100644 libs/fluidsynth/src/synth/fluid_tuning.c create mode 100644 libs/fluidsynth/src/synth/fluid_tuning.h create mode 100644 libs/fluidsynth/src/synth/fluid_voice.c create mode 100644 libs/fluidsynth/src/synth/fluid_voice.h create mode 100644 libs/fluidsynth/src/utils/fluid_conv.c create mode 100644 libs/fluidsynth/src/utils/fluid_conv.h create mode 100644 libs/fluidsynth/src/utils/fluid_conv_tables.h create mode 100644 libs/fluidsynth/src/utils/fluid_hash.c create mode 100644 libs/fluidsynth/src/utils/fluid_hash.h create mode 100644 libs/fluidsynth/src/utils/fluid_list.c create mode 100644 libs/fluidsynth/src/utils/fluid_list.h create mode 100644 libs/fluidsynth/src/utils/fluid_ringbuffer.c create mode 100644 libs/fluidsynth/src/utils/fluid_ringbuffer.h create mode 100644 libs/fluidsynth/src/utils/fluid_settings.c create mode 100644 libs/fluidsynth/src/utils/fluid_settings.h create mode 100644 libs/fluidsynth/src/utils/fluid_sys.c create mode 100644 libs/fluidsynth/src/utils/fluid_sys.h create mode 100644 libs/fluidsynth/src/utils/fluidsynth_priv.h diff --git a/configure.ac b/configure.ac index c58fced1539..360d4ec5e25 100644 --- a/configure.ac +++ b/configure.ac @@ -1029,6 +1029,15 @@ then WINE_NOTICE([FAudio ${notice_platform}MinGW development files not found (or too old); using bundled version.]) fi + WINE_MINGW_PACKAGE_FLAGS(FLUIDSYNTH,[fluidsynth],[-lfluidsynth], + [WINE_CHECK_MINGW_HEADER(fluidsynth.h, + [WINE_CHECK_MINGW_LIB(fluidsynth,new_fluid_synth,[:],[FLUIDSYNTH_PE_CFLAGS=""; FLUIDSYNTH_PE_LIBS=""],[$FLUIDSYNTH_PE_LIBS])], + [FLUIDSYNTH_PE_CFLAGS=""; FLUIDSYNTH_PE_LIBS=""])]) + if test "x$FLUIDSYNTH_PE_LIBS" = "x" + then + WINE_NOTICE([Fluidsynth ${notice_platform}MinGW development files not found (or too old); using bundled version.]) + fi + WINE_MINGW_PACKAGE_FLAGS(JPEG,[libjpeg],, [WINE_CHECK_MINGW_HEADER(jpeglib.h, [WINE_CHECK_MINGW_LIB(jpeg,jpeg_start_decompress,[:],[JPEG_PE_CFLAGS=""; JPEG_PE_LIBS=""],[$JPEG_PE_LIBS])], @@ -1139,6 +1148,7 @@ then fi WINE_EXTLIB_FLAGS(FAUDIO, faudio, "faudio mfplat mfreadwrite mfuuid propsys", "-I\$(top_srcdir)/libs/faudio/include") +WINE_EXTLIB_FLAGS(FLUIDSYNTH, fluidsynth, "fluidsynth", "-I\$(top_srcdir)/libs/fluidsynth/include") WINE_EXTLIB_FLAGS(GSM, gsm, gsm, "-I\$(top_srcdir)/libs/gsm/inc") WINE_EXTLIB_FLAGS(JPEG, jpeg, jpeg, "-I\$(top_srcdir)/libs/jpeg") WINE_EXTLIB_FLAGS(JXR, jxr, jxr, "-I\$(top_srcdir)/libs/jxr/jxrgluelib -I\$(top_srcdir)/libs/jxr/image/sys") @@ -3328,6 +3338,7 @@ WINE_CONFIG_MAKEFILE(libs/dxerr8) WINE_CONFIG_MAKEFILE(libs/dxerr9) WINE_CONFIG_MAKEFILE(libs/dxguid) WINE_CONFIG_MAKEFILE(libs/faudio) +WINE_CONFIG_MAKEFILE(libs/fluidsynth) WINE_CONFIG_MAKEFILE(libs/gsm) WINE_CONFIG_MAKEFILE(libs/jpeg) WINE_CONFIG_MAKEFILE(libs/jxr) diff --git a/dlls/dmsynth/Makefile.in b/dlls/dmsynth/Makefile.in index 276597db5ad..7c6d2db721b 100644 --- a/dlls/dmsynth/Makefile.in +++ b/dlls/dmsynth/Makefile.in @@ -1,5 +1,6 @@ MODULE = dmsynth.dll -IMPORTS = dxguid uuid ole32 advapi32 +IMPORTS = $(FLUIDSYNTH_PE_LIBS) dxguid uuid ole32 advapi32 user32 +EXTRAINCL = $(FLUIDSYNTH_PE_CFLAGS) C_SRCS = \ dmsynth_main.c \ diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index c36196c0407..2b5a0905685 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -29,6 +29,8 @@ #include "dmsynth_private.h" +#include + WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); static void dump_dmus_instrument(DMUS_INSTRUMENT *instrument) @@ -231,6 +233,8 @@ struct synth struct list instruments; struct list waves; + + fluid_settings_t *fluid_settings; }; static inline struct synth *impl_from_IDirectMusicSynth8(IDirectMusicSynth8 *iface) @@ -302,6 +306,7 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) wave_release(wave); } + delete_fluid_settings(This->fluid_settings); free(This); } @@ -1087,7 +1092,13 @@ HRESULT synth_create(IUnknown **ret_iface) list_init(&obj->instruments); list_init(&obj->waves); + if (!(obj->fluid_settings = new_fluid_settings())) goto failed; + TRACE("Created DirectMusicSynth %p\n", obj); *ret_iface = (IUnknown *)&obj->IDirectMusicSynth8_iface; return S_OK; + +failed: + free(obj); + return E_OUTOFMEMORY; } diff --git a/libs/fluidsynth/AUTHORS b/libs/fluidsynth/AUTHORS new file mode 100644 index 00000000000..151b7073355 --- /dev/null +++ b/libs/fluidsynth/AUTHORS @@ -0,0 +1,157 @@ +[:Team:] +Current development team + +Tom Moebert + + +Former development team + +Josh Green +Pedro Lopez-Cabanillas +David Henningsson + + +[:Idea:] + +* Samuel Bianchini, Peter Hanappe and Johnathan Lee + + +[:Development:] + +Many people contributed to FluidSynth, sent suggestions or bug +fixes. The project was started by Peter Hanappe who is the main +author. Josh Green is the current maintainer. Below you'll find a +summary of contributions. + + +* Peter Hanappe. Initiated the project. files: stuck his nose in all + files. + +* Josh Green is the former maintainer and contributed a lot of code + directly or indirectly through the Swami and Smurf code base. + The SoundFont loader is completely based on his code. He also wrote + the alsa sequencer driver. He made many changes and bug fixes, + but above all, he's one of the driving forces behind the synthesizer. + He also created the current FluidSynth graphic logo with Blender + (the blue waves with FluidSynth letters partially submerged). + +* Markus Nentwig (re-)designed the resonant filter, the chorus, the + LADSPA subsystem, the MIDI router, optimized for SSE, made many + changes and bug fixes and got the synthesizer to actually work. Most + importantly, he used it on stage to make music. + +* S. Christian Collins did much testing of FluidSynth in regards to + EMU10K1 compatibility and provided many synthesis fixes in that regard. + +* Stephane Letz from Grame wrote most of the MidiShare driver, all of + the PortAudio driver, ported iiwusynth to MacOS X, and sent in many + fixes. files: iiwu_midishare.c, iiwu_portaudio.c + +* Antoine Schmitt added the sequencer support, support for sample + loading (RAM Sfont), developed the + MacroMedia Director Xtra, and send in many many bug reports. Thanks + to Antoine, the synthesizer finds its way to multi-media + developers. files: in bindings/director/ and iiwu_seq.{c,h}, + iiwu_event.{c,h}, iiwu_event_priv.h, iiwu_seqbind.{c,h}, + iiwu_ramsfont.{c,h} + +* Bob Ham added the code for "bank select" MIDI messages and send code + to define the synth's ALSA sequencer client name. files: + iiwu_midi.c, iiwu_alsa.c, iiwusynth.c, iiwusynth.h. + +* Tim Goetze sent many patches and implemented the all_notes_off. He + also sent his code for the new ALSA driver. files: iiwu_synth.c, + iiwu_chan.c, iiwu_voice.c, iiwu_alsa.c + +* Norbert Schnell from Ircam's jMax Team wrote most of the jMax/FTS + interface in a record time. He also pointed me to the technique of + using a lookup table for the interpolation coefficients. file: + iiwu_fts.c, iiwu_synth.c + +* The initial alsa driver was based on the jMax alsa driver by + Francois Dechelle and his Real-time Team at Ircam + (https://www.ircam.fr/jmax). The jMax code was based upon Ardour's + alsa_device.cc by Paul Barton-Davis. file: iiwu_alsa.c + +* Code was borrowed from the glib library to the smurf files. The goal was + to make iiwusynth independent from any library for maximum + portability. + +* David Henningsson added code for fast rendering of MIDI files, + rewrote the thread safety for 1.1.2, and fixed many bugs. + +* The midi device uses code from jMax's alsarawmidi.c file and from + Smurf's midi_alsaraw.c by Josh Green. file: iiwu_alsa.c + +* The reverb algorithm was written by Jezar + (https://www.dreampoint.co.uk). His code is public domain. The code + was translated to C by Peter Hanappe. file: iiwu_synth.c + +* The original code for the chorus effect was written by Juergen + Mueller and sundry contributors. + +* Bob Ham added LADCCA support. + +* Ebrahim Mayat made big efforts for compiling and running FluidSynth + on MacOS X. He also wrote the README-OSX file. + +* Martin Uddén's midi package was used. His files are integrated into + the iiwu_midi file. Martin Uddén file: + iiwu_midi.c + +* Ken Ellinwood send in a patch to add bank offsets to SoundFonts. An + adapted version was integrated in the source code. files: + fluid_cmd.c, fluidsynth/synth.h, fluid_synth.c. + +* Some interpolation algorithms were used that were found in + the music-dsp archives (http://www.smartelectronix.com/musicdsp). + They were written by Joshua Scholar and others. file: iiwu_synth.c + +* Macros to {increment,decrement} the 64-bit fixed point phase were + borrowed from Mozilla's macros to handle the Long-long type (64-bit + signed integer type). Mozilla NSPR library, www.mozilla.org. file: + iiwu_phase.h + +* KO Myung-Hun for OS/2 support with Dart audio driver. + +* Pedro Lopez-Cabanillas wrote the CoreMIDI driver for MacOSX, the CMake based + build system, revised the doxygen documentation, sequencer examples, fixes. + +* Matt Giuca improved the midi player by letting it load midi files from RAM, + and by making it handle EOT events. + +* Tom Moebert (fluidsynth's maintainer since Jun 2017) cleaned up and refactored + fluidsynth's API and revised its documentation, added support for 24 bit sample + soundfonts, added support for DLS soundfonts, fixed various bugs, implemented + unit tests and CI builds for Windows, Linux, MacOSX and BSD. + +* Fabian Greffrath added initial support of vorbis-compressed sf3 sound fonts. + +* Growing list of individuals who contributed bug fixes, corrections and minor features: +Nicolas Boulicault for ALSA sequencer midi.portname setting. +Werner Schweer +Dave Philips +Anthony Green +Jake Commander +Fernando Pablo Lopez-Lezcano +Raoul Bonisch +Sergey Pavlishin +Eric Van Buggenhaut +Ken Ellinwood +Takashi Iwai +Bob Ham +Gerald Pye +Rui Nuno Capela +Frieder Bürzele +Henri Manson +Mihail Zenkov +Paul Millar +Nick Daly +David Hilvert +Bernat Arlandis i Mañó +Sven Meier +Marcus Weseloh +Jean-jacques Ceresa +Vladimir Davidovich +Tamás Korodi +Evan Miller diff --git a/libs/fluidsynth/COPYING.md b/libs/fluidsynth/COPYING.md new file mode 100644 index 00000000000..5934164a2f9 --- /dev/null +++ b/libs/fluidsynth/COPYING.md @@ -0,0 +1,7 @@ +The source code for FluidSynth is distributed under the terms of the +[GNU Lesser General Public License](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html), +see the [LICENSE](https://github.com/FluidSynth/fluidsynth/blob/master/LICENSE) file. + +To better understand the conditions how FluidSynth can be used in +e.g. commercial or closed-source projects, please refer to the +[LicensingFAQ in our wiki](https://github.com/FluidSynth/fluidsynth/wiki/LicensingFAQ). diff --git a/libs/fluidsynth/Makefile.in b/libs/fluidsynth/Makefile.in new file mode 100644 index 00000000000..489d296754b --- /dev/null +++ b/libs/fluidsynth/Makefile.in @@ -0,0 +1,42 @@ +EXTLIB = libfluidsynth.a +EXTRADEFS = -DNDEBUG -DWITH_PROFILING +EXTRAINCL = -I$(srcdir)/src \ + -I$(srcdir)/src/bindings \ + -I$(srcdir)/src/drivers \ + -I$(srcdir)/src/midi \ + -I$(srcdir)/src/rvoice \ + -I$(srcdir)/src/sfloader \ + -I$(srcdir)/src/synth \ + -I$(srcdir)/src/utils \ + $(FLUIDSYNTH_PE_CFLAGS) + +C_SRCS = \ + glib.c \ + src/midi/fluid_midi.c \ + src/rvoice/fluid_adsr_env.c \ + src/rvoice/fluid_chorus.c \ + src/rvoice/fluid_iir_filter.c \ + src/rvoice/fluid_lfo.c \ + src/rvoice/fluid_rev.c \ + src/rvoice/fluid_rvoice.c \ + src/rvoice/fluid_rvoice_dsp.c \ + src/rvoice/fluid_rvoice_event.c \ + src/rvoice/fluid_rvoice_mixer.c \ + src/sfloader/fluid_defsfont.c \ + src/sfloader/fluid_samplecache.c \ + src/sfloader/fluid_sffile.c \ + src/sfloader/fluid_sfont.c \ + src/synth/fluid_chan.c \ + src/synth/fluid_event.c \ + src/synth/fluid_gen.c \ + src/synth/fluid_mod.c \ + src/synth/fluid_synth.c \ + src/synth/fluid_synth_monopoly.c \ + src/synth/fluid_tuning.c \ + src/synth/fluid_voice.c \ + src/utils/fluid_conv.c \ + src/utils/fluid_hash.c \ + src/utils/fluid_list.c \ + src/utils/fluid_ringbuffer.c \ + src/utils/fluid_settings.c \ + src/utils/fluid_sys.c diff --git a/libs/fluidsynth/config.h b/libs/fluidsynth/config.h new file mode 100644 index 00000000000..2170ad098ed --- /dev/null +++ b/libs/fluidsynth/config.h @@ -0,0 +1,271 @@ +#ifndef CONFIG_H +#define CONFIG_H + +/* Define to enable ALSA driver */ +/* #undef ALSA_SUPPORT TRUE */ + +/* Define to activate sound output to files */ +/* #undef AUFILE_SUPPORT 1 */ + +/* whether or not we are supporting CoreAudio */ +/* #undef COREAUDIO_SUPPORT */ + +/* whether or not we are supporting CoreMIDI */ +/* #undef COREMIDI_SUPPORT */ + +/* whether or not we are supporting DART */ +/* #undef DART_SUPPORT */ + +/* Define if building for Mac OS X Darwin */ +/* #undef DARWIN */ + +/* Define if D-Bus support is enabled */ +/* #undef DBUS_SUPPORT 1 */ + +/* Soundfont to load automatically in some use cases */ +/* #undef DEFAULT_SOUNDFONT "/usr/local/share/soundfonts/default.sf2" */ + +/* Define to enable FPE checks */ +/* #undef FPE_CHECK */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ARPA_INET_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_FCNTL_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_IO_H 1 + +/* whether or not we are supporting lash */ +/* #undef HAVE_LASH */ + +/* Define if systemd support is enabled */ +/* #undef SYSTEMD_SUPPORT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_SOUNDCARD_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACHINE_SOUNDCARD_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MATH_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETINET_IN_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NETINET_TCP_H */ + +/* Define if compiling the mixer with multi-thread support */ +#define ENABLE_MIXER_THREADS 1 + +/* Define if compiling with openMP to enable parallel audio rendering */ +/* #undef HAVE_OPENMP */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_PTHREAD_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STRINGS_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_MMAN_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SOCKET_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SOUNDCARD_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_TIME_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_UNISTD_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_GETOPT_H */ + +/* Define to 1 if you have the inet_ntop() function. */ +/* #undef HAVE_INETNTOP */ + +/* Define to enable JACK driver */ +/* #undef JACK_SUPPORT */ + +/* Define to enable PipeWire driver */ +/* #undef PIPEWIRE_SUPPORT */ + +/* Include the LADSPA Fx unit */ +/* #undef LADSPA */ + +/* Define to enable IPV6 support */ +/* #undef IPV6_SUPPORT */ + +/* Define to enable network support */ +/* #undef NETWORK_SUPPORT */ + +/* Defined when fluidsynth is build in an automated environment, where no MSVC++ Runtime Debug Assertion dialogs should pop up */ +#define NO_GUI 1 + +/* libinstpatch for DLS and GIG */ +/* #undef LIBINSTPATCH_SUPPORT */ + +/* libsndfile has ogg vorbis support */ +/* #undef LIBSNDFILE_HASVORBIS */ + +/* Define to enable libsndfile support */ +/* #undef LIBSNDFILE_SUPPORT */ + +/* Define to enable MidiShare driver */ +/* #undef MIDISHARE_SUPPORT */ + +/* Define if using the MinGW32 environment */ +#define MINGW32 1 + +/* Define to enable OSS driver */ +/* #undef OSS_SUPPORT */ + +/* Define to enable OPENSLES driver */ +/* #undef OPENSLES_SUPPORT */ + +/* Define to enable Oboe driver */ +/* #undef OBOE_SUPPORT */ + +/* Name of package */ +#define PACKAGE "fluidsynth" + +/* Define to the address where bug reports for this package should be sent. */ +/* #undef PACKAGE_BUGREPORT */ + +/* Define to the full name of this package. */ +/* #undef PACKAGE_NAME */ + +/* Define to the full name and version of this package. */ +/* #undef PACKAGE_STRING */ + +/* Define to the one symbol short name of this package. */ +/* #undef PACKAGE_TARNAME */ + +/* Define to the version of this package. */ +/* #undef PACKAGE_VERSION */ + +/* Define to enable PortAudio driver */ +/* #undef PORTAUDIO_SUPPORT */ + +/* Define to enable PulseAudio driver */ +/* #undef PULSE_SUPPORT */ + +/* Define to enable DirectSound driver */ +/* #undef DSOUND_SUPPORT 1 */ + +/* Define to enable Windows WASAPI driver */ +/* #undef WASAPI_SUPPORT 1 */ + +/* Define to enable Windows WaveOut driver */ +/* #undef WAVEOUT_SUPPORT 1 */ + +/* Define to enable Windows MIDI driver */ +/* #undef WINMIDI_SUPPORT */ + +/* Define to enable SDL2 audio driver */ +/* #undef SDL2_SUPPORT */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Soundfont to load for unit testing */ +/* #undef TEST_SOUNDFONT */ + +/* Soundfont to load for UTF-8 unit testing */ +/* #undef TEST_SOUNDFONT_UTF8_1 */ +/* #undef TEST_SOUNDFONT_UTF8_2 */ +/* #undef TEST_MIDI_UTF8 */ + +/* SF3 Soundfont to load for unit testing */ +/* #undef TEST_SOUNDFONT_SF3 */ + +/* Define to enable SIGFPE assertions */ +/* #undef TRAP_ON_FPE */ + +/* Define to do all DSP in single floating point precision */ +/* #undef WITH_FLOAT */ + +/* Define to profile the DSP code */ +/* #undef WITH_PROFILING */ + +/* Define to use the readline library for line editing */ +/* #undef READLINE_SUPPORT */ + +/* Define if the compiler supports VLA */ +#define SUPPORTS_VLA 1 + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to 1 if you have the sinf() function. */ +#define HAVE_SINF 1 + +/* Define to 1 if you have the cosf() function. */ +#define HAVE_COSF 1 + +/* Define to 1 if you have the fabsf() function. */ +#define HAVE_FABSF 1 + +/* Define to 1 if you have the powf() function. */ +#define HAVE_POWF 1 + +/* Define to 1 if you have the sqrtf() function. */ +#define HAVE_SQRTF 1 + +/* Define to 1 if you have the logf() function. */ +#define HAVE_LOGF 1 + +/* Define to 1 if you have the socklen_t type. */ +/* #undef HAVE_SOCKLEN_T */ + +#endif /* CONFIG_H */ diff --git a/libs/fluidsynth/fluid_conv_tables.inc.h b/libs/fluidsynth/fluid_conv_tables.inc.h new file mode 100644 index 00000000000..51575e86598 --- /dev/null +++ b/libs/fluidsynth/fluid_conv_tables.inc.h @@ -0,0 +1,3915 @@ +/* THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT. */ + +static const fluid_real_t fluid_ct2hz_tab[1200] = { + 6.875000000000000e+00, /* 0 */ + 6.878972302857565e+00, /* 1 */ + 6.882946900870038e+00, /* 2 */ + 6.886923795363534e+00, /* 3 */ + 6.890902987664938e+00, /* 4 */ + 6.894884479101899e+00, /* 5 */ + 6.898868271002832e+00, /* 6 */ + 6.902854364696921e+00, /* 7 */ + 6.906842761514119e+00, /* 8 */ + 6.910833462785147e+00, /* 9 */ + 6.914826469841493e+00, /* 10 */ + 6.918821784015415e+00, /* 11 */ + 6.922819406639942e+00, /* 12 */ + 6.926819339048873e+00, /* 13 */ + 6.930821582576776e+00, /* 14 */ + 6.934826138558993e+00, /* 15 */ + 6.938833008331635e+00, /* 16 */ + 6.942842193231585e+00, /* 17 */ + 6.946853694596501e+00, /* 18 */ + 6.950867513764811e+00, /* 19 */ + 6.954883652075717e+00, /* 20 */ + 6.958902110869197e+00, /* 21 */ + 6.962922891485999e+00, /* 22 */ + 6.966945995267650e+00, /* 23 */ + 6.970971423556450e+00, /* 24 */ + 6.974999177695475e+00, /* 25 */ + 6.979029259028576e+00, /* 26 */ + 6.983061668900382e+00, /* 27 */ + 6.987096408656298e+00, /* 28 */ + 6.991133479642508e+00, /* 29 */ + 6.995172883205969e+00, /* 30 */ + 6.999214620694422e+00, /* 31 */ + 7.003258693456385e+00, /* 32 */ + 7.007305102841153e+00, /* 33 */ + 7.011353850198804e+00, /* 34 */ + 7.015404936880191e+00, /* 35 */ + 7.019458364236954e+00, /* 36 */ + 7.023514133621508e+00, /* 37 */ + 7.027572246387055e+00, /* 38 */ + 7.031632703887573e+00, /* 39 */ + 7.035695507477827e+00, /* 40 */ + 7.039760658513363e+00, /* 41 */ + 7.043828158350510e+00, /* 42 */ + 7.047898008346380e+00, /* 43 */ + 7.051970209858872e+00, /* 44 */ + 7.056044764246666e+00, /* 45 */ + 7.060121672869229e+00, /* 46 */ + 7.064200937086813e+00, /* 47 */ + 7.068282558260457e+00, /* 48 */ + 7.072366537751985e+00, /* 49 */ + 7.076452876924008e+00, /* 50 */ + 7.080541577139924e+00, /* 51 */ + 7.084632639763921e+00, /* 52 */ + 7.088726066160973e+00, /* 53 */ + 7.092821857696842e+00, /* 54 */ + 7.096920015738083e+00, /* 55 */ + 7.101020541652035e+00, /* 56 */ + 7.105123436806832e+00, /* 57 */ + 7.109228702571396e+00, /* 58 */ + 7.113336340315441e+00, /* 59 */ + 7.117446351409471e+00, /* 60 */ + 7.121558737224782e+00, /* 61 */ + 7.125673499133464e+00, /* 62 */ + 7.129790638508400e+00, /* 63 */ + 7.133910156723263e+00, /* 64 */ + 7.138032055152522e+00, /* 65 */ + 7.142156335171443e+00, /* 66 */ + 7.146282998156079e+00, /* 67 */ + 7.150412045483285e+00, /* 68 */ + 7.154543478530709e+00, /* 69 */ + 7.158677298676793e+00, /* 70 */ + 7.162813507300782e+00, /* 71 */ + 7.166952105782710e+00, /* 72 */ + 7.171093095503412e+00, /* 73 */ + 7.175236477844522e+00, /* 74 */ + 7.179382254188470e+00, /* 75 */ + 7.183530425918486e+00, /* 76 */ + 7.187680994418599e+00, /* 77 */ + 7.191833961073638e+00, /* 78 */ + 7.195989327269232e+00, /* 79 */ + 7.200147094391808e+00, /* 80 */ + 7.204307263828600e+00, /* 81 */ + 7.208469836967637e+00, /* 82 */ + 7.212634815197754e+00, /* 83 */ + 7.216802199908588e+00, /* 84 */ + 7.220971992490576e+00, /* 85 */ + 7.225144194334964e+00, /* 86 */ + 7.229318806833796e+00, /* 87 */ + 7.233495831379925e+00, /* 88 */ + 7.237675269367005e+00, /* 89 */ + 7.241857122189496e+00, /* 90 */ + 7.246041391242668e+00, /* 91 */ + 7.250228077922589e+00, /* 92 */ + 7.254417183626143e+00, /* 93 */ + 7.258608709751013e+00, /* 94 */ + 7.262802657695695e+00, /* 95 */ + 7.266999028859490e+00, /* 96 */ + 7.271197824642510e+00, /* 97 */ + 7.275399046445672e+00, /* 98 */ + 7.279602695670708e+00, /* 99 */ + 7.283808773720155e+00, /* 100 */ + 7.288017281997362e+00, /* 101 */ + 7.292228221906491e+00, /* 102 */ + 7.296441594852512e+00, /* 103 */ + 7.300657402241209e+00, /* 104 */ + 7.304875645479175e+00, /* 105 */ + 7.309096325973822e+00, /* 106 */ + 7.313319445133367e+00, /* 107 */ + 7.317545004366849e+00, /* 108 */ + 7.321773005084116e+00, /* 109 */ + 7.326003448695830e+00, /* 110 */ + 7.330236336613471e+00, /* 111 */ + 7.334471670249333e+00, /* 112 */ + 7.338709451016527e+00, /* 113 */ + 7.342949680328980e+00, /* 114 */ + 7.347192359601434e+00, /* 115 */ + 7.351437490249451e+00, /* 116 */ + 7.355685073689412e+00, /* 117 */ + 7.359935111338512e+00, /* 118 */ + 7.364187604614767e+00, /* 119 */ + 7.368442554937015e+00, /* 120 */ + 7.372699963724910e+00, /* 121 */ + 7.376959832398928e+00, /* 122 */ + 7.381222162380364e+00, /* 123 */ + 7.385486955091339e+00, /* 124 */ + 7.389754211954788e+00, /* 125 */ + 7.394023934394475e+00, /* 126 */ + 7.398296123834983e+00, /* 127 */ + 7.402570781701721e+00, /* 128 */ + 7.406847909420918e+00, /* 129 */ + 7.411127508419629e+00, /* 130 */ + 7.415409580125734e+00, /* 131 */ + 7.419694125967937e+00, /* 132 */ + 7.423981147375768e+00, /* 133 */ + 7.428270645779583e+00, /* 134 */ + 7.432562622610564e+00, /* 135 */ + 7.436857079300720e+00, /* 136 */ + 7.441154017282888e+00, /* 137 */ + 7.445453437990733e+00, /* 138 */ + 7.449755342858746e+00, /* 139 */ + 7.454059733322251e+00, /* 140 */ + 7.458366610817398e+00, /* 141 */ + 7.462675976781168e+00, /* 142 */ + 7.466987832651371e+00, /* 143 */ + 7.471302179866649e+00, /* 144 */ + 7.475619019866476e+00, /* 145 */ + 7.479938354091158e+00, /* 146 */ + 7.484260183981829e+00, /* 147 */ + 7.488584510980460e+00, /* 148 */ + 7.492911336529853e+00, /* 149 */ + 7.497240662073646e+00, /* 150 */ + 7.501572489056309e+00, /* 151 */ + 7.505906818923147e+00, /* 152 */ + 7.510243653120298e+00, /* 153 */ + 7.514582993094741e+00, /* 154 */ + 7.518924840294288e+00, /* 155 */ + 7.523269196167584e+00, /* 156 */ + 7.527616062164117e+00, /* 157 */ + 7.531965439734210e+00, /* 158 */ + 7.536317330329021e+00, /* 159 */ + 7.540671735400553e+00, /* 160 */ + 7.545028656401643e+00, /* 161 */ + 7.549388094785967e+00, /* 162 */ + 7.553750052008045e+00, /* 163 */ + 7.558114529523233e+00, /* 164 */ + 7.562481528787732e+00, /* 165 */ + 7.566851051258580e+00, /* 166 */ + 7.571223098393661e+00, /* 167 */ + 7.575597671651699e+00, /* 168 */ + 7.579974772492260e+00, /* 169 */ + 7.584354402375757e+00, /* 170 */ + 7.588736562763443e+00, /* 171 */ + 7.593121255117417e+00, /* 172 */ + 7.597508480900622e+00, /* 173 */ + 7.601898241576849e+00, /* 174 */ + 7.606290538610729e+00, /* 175 */ + 7.610685373467746e+00, /* 176 */ + 7.615082747614226e+00, /* 177 */ + 7.619482662517345e+00, /* 178 */ + 7.623885119645124e+00, /* 179 */ + 7.628290120466435e+00, /* 180 */ + 7.632697666450996e+00, /* 181 */ + 7.637107759069377e+00, /* 182 */ + 7.641520399792996e+00, /* 183 */ + 7.645935590094122e+00, /* 184 */ + 7.650353331445872e+00, /* 185 */ + 7.654773625322218e+00, /* 186 */ + 7.659196473197983e+00, /* 187 */ + 7.663621876548839e+00, /* 188 */ + 7.668049836851313e+00, /* 189 */ + 7.672480355582785e+00, /* 190 */ + 7.676913434221489e+00, /* 191 */ + 7.681349074246512e+00, /* 192 */ + 7.685787277137797e+00, /* 193 */ + 7.690228044376139e+00, /* 194 */ + 7.694671377443195e+00, /* 195 */ + 7.699117277821469e+00, /* 196 */ + 7.703565746994330e+00, /* 197 */ + 7.708016786445998e+00, /* 198 */ + 7.712470397661556e+00, /* 199 */ + 7.716926582126939e+00, /* 200 */ + 7.721385341328946e+00, /* 201 */ + 7.725846676755233e+00, /* 202 */ + 7.730310589894314e+00, /* 203 */ + 7.734777082235564e+00, /* 204 */ + 7.739246155269221e+00, /* 205 */ + 7.743717810486381e+00, /* 206 */ + 7.748192049379002e+00, /* 207 */ + 7.752668873439905e+00, /* 208 */ + 7.757148284162773e+00, /* 209 */ + 7.761630283042153e+00, /* 210 */ + 7.766114871573452e+00, /* 211 */ + 7.770602051252947e+00, /* 212 */ + 7.775091823577775e+00, /* 213 */ + 7.779584190045939e+00, /* 214 */ + 7.784079152156307e+00, /* 215 */ + 7.788576711408616e+00, /* 216 */ + 7.793076869303465e+00, /* 217 */ + 7.797579627342324e+00, /* 218 */ + 7.802084987027528e+00, /* 219 */ + 7.806592949862282e+00, /* 220 */ + 7.811103517350658e+00, /* 221 */ + 7.815616690997596e+00, /* 222 */ + 7.820132472308910e+00, /* 223 */ + 7.824650862791279e+00, /* 224 */ + 7.829171863952255e+00, /* 225 */ + 7.833695477300261e+00, /* 226 */ + 7.838221704344591e+00, /* 227 */ + 7.842750546595412e+00, /* 228 */ + 7.847282005563763e+00, /* 229 */ + 7.851816082761554e+00, /* 230 */ + 7.856352779701573e+00, /* 231 */ + 7.860892097897477e+00, /* 232 */ + 7.865434038863802e+00, /* 233 */ + 7.869978604115957e+00, /* 234 */ + 7.874525795170227e+00, /* 235 */ + 7.879075613543772e+00, /* 236 */ + 7.883628060754630e+00, /* 237 */ + 7.888183138321715e+00, /* 238 */ + 7.892740847764820e+00, /* 239 */ + 7.897301190604615e+00, /* 240 */ + 7.901864168362650e+00, /* 241 */ + 7.906429782561352e+00, /* 242 */ + 7.910998034724029e+00, /* 243 */ + 7.915568926374869e+00, /* 244 */ + 7.920142459038940e+00, /* 245 */ + 7.924718634242192e+00, /* 246 */ + 7.929297453511457e+00, /* 247 */ + 7.933878918374448e+00, /* 248 */ + 7.938463030359761e+00, /* 249 */ + 7.943049790996877e+00, /* 250 */ + 7.947639201816158e+00, /* 251 */ + 7.952231264348852e+00, /* 252 */ + 7.956825980127089e+00, /* 253 */ + 7.961423350683890e+00, /* 254 */ + 7.966023377553156e+00, /* 255 */ + 7.970626062269677e+00, /* 256 */ + 7.975231406369129e+00, /* 257 */ + 7.979839411388076e+00, /* 258 */ + 7.984450078863969e+00, /* 259 */ + 7.989063410335147e+00, /* 260 */ + 7.993679407340840e+00, /* 261 */ + 7.998298071421166e+00, /* 262 */ + 8.002919404117131e+00, /* 263 */ + 8.007543406970633e+00, /* 264 */ + 8.012170081524465e+00, /* 265 */ + 8.016799429322301e+00, /* 266 */ + 8.021431451908718e+00, /* 267 */ + 8.026066150829180e+00, /* 268 */ + 8.030703527630045e+00, /* 269 */ + 8.035343583858563e+00, /* 270 */ + 8.039986321062880e+00, /* 271 */ + 8.044631740792035e+00, /* 272 */ + 8.049279844595961e+00, /* 273 */ + 8.053930634025493e+00, /* 274 */ + 8.058584110632353e+00, /* 275 */ + 8.063240275969166e+00, /* 276 */ + 8.067899131589453e+00, /* 277 */ + 8.072560679047628e+00, /* 278 */ + 8.077224919899010e+00, /* 279 */ + 8.081891855699810e+00, /* 280 */ + 8.086561488007144e+00, /* 281 */ + 8.091233818379026e+00, /* 282 */ + 8.095908848374366e+00, /* 283 */ + 8.100586579552981e+00, /* 284 */ + 8.105267013475586e+00, /* 285 */ + 8.109950151703798e+00, /* 286 */ + 8.114635995800136e+00, /* 287 */ + 8.119324547328022e+00, /* 288 */ + 8.124015807851780e+00, /* 289 */ + 8.128709778936644e+00, /* 290 */ + 8.133406462148743e+00, /* 291 */ + 8.138105859055118e+00, /* 292 */ + 8.142807971223712e+00, /* 293 */ + 8.147512800223376e+00, /* 294 */ + 8.152220347623867e+00, /* 295 */ + 8.156930614995847e+00, /* 296 */ + 8.161643603910887e+00, /* 297 */ + 8.166359315941468e+00, /* 298 */ + 8.171077752660976e+00, /* 299 */ + 8.175798915643707e+00, /* 300 */ + 8.180522806464868e+00, /* 301 */ + 8.185249426700578e+00, /* 302 */ + 8.189978777927859e+00, /* 303 */ + 8.194710861724653e+00, /* 304 */ + 8.199445679669807e+00, /* 305 */ + 8.204183233343088e+00, /* 306 */ + 8.208923524325167e+00, /* 307 */ + 8.213666554197633e+00, /* 308 */ + 8.218412324542989e+00, /* 309 */ + 8.223160836944650e+00, /* 310 */ + 8.227912092986951e+00, /* 311 */ + 8.232666094255135e+00, /* 312 */ + 8.237422842335365e+00, /* 313 */ + 8.242182338814722e+00, /* 314 */ + 8.246944585281200e+00, /* 315 */ + 8.251709583323716e+00, /* 316 */ + 8.256477334532098e+00, /* 317 */ + 8.261247840497099e+00, /* 318 */ + 8.266021102810386e+00, /* 319 */ + 8.270797123064552e+00, /* 320 */ + 8.275575902853102e+00, /* 321 */ + 8.280357443770470e+00, /* 322 */ + 8.285141747412004e+00, /* 323 */ + 8.289928815373978e+00, /* 324 */ + 8.294718649253587e+00, /* 325 */ + 8.299511250648951e+00, /* 326 */ + 8.304306621159110e+00, /* 327 */ + 8.309104762384029e+00, /* 328 */ + 8.313905675924600e+00, /* 329 */ + 8.318709363382636e+00, /* 330 */ + 8.323515826360879e+00, /* 331 */ + 8.328325066462993e+00, /* 332 */ + 8.333137085293574e+00, /* 333 */ + 8.337951884458139e+00, /* 334 */ + 8.342769465563139e+00, /* 335 */ + 8.347589830215947e+00, /* 336 */ + 8.352412980024869e+00, /* 337 */ + 8.357238916599140e+00, /* 338 */ + 8.362067641548924e+00, /* 339 */ + 8.366899156485312e+00, /* 340 */ + 8.371733463020332e+00, /* 341 */ + 8.376570562766940e+00, /* 342 */ + 8.381410457339022e+00, /* 343 */ + 8.386253148351402e+00, /* 344 */ + 8.391098637419832e+00, /* 345 */ + 8.395946926161001e+00, /* 346 */ + 8.400798016192528e+00, /* 347 */ + 8.405651909132970e+00, /* 348 */ + 8.410508606601821e+00, /* 349 */ + 8.415368110219505e+00, /* 350 */ + 8.420230421607386e+00, /* 351 */ + 8.425095542387766e+00, /* 352 */ + 8.429963474183879e+00, /* 353 */ + 8.434834218619903e+00, /* 354 */ + 8.439707777320951e+00, /* 355 */ + 8.444584151913077e+00, /* 356 */ + 8.449463344023272e+00, /* 357 */ + 8.454345355279468e+00, /* 358 */ + 8.459230187310540e+00, /* 359 */ + 8.464117841746299e+00, /* 360 */ + 8.469008320217505e+00, /* 361 */ + 8.473901624355852e+00, /* 362 */ + 8.478797755793982e+00, /* 363 */ + 8.483696716165481e+00, /* 364 */ + 8.488598507104875e+00, /* 365 */ + 8.493503130247639e+00, /* 366 */ + 8.498410587230186e+00, /* 367 */ + 8.503320879689882e+00, /* 368 */ + 8.508234009265037e+00, /* 369 */ + 8.513149977594903e+00, /* 370 */ + 8.518068786319684e+00, /* 371 */ + 8.522990437080532e+00, /* 372 */ + 8.527914931519545e+00, /* 373 */ + 8.532842271279769e+00, /* 374 */ + 8.537772458005202e+00, /* 375 */ + 8.542705493340792e+00, /* 376 */ + 8.547641378932433e+00, /* 377 */ + 8.552580116426974e+00, /* 378 */ + 8.557521707472215e+00, /* 379 */ + 8.562466153716908e+00, /* 380 */ + 8.567413456810757e+00, /* 381 */ + 8.572363618404419e+00, /* 382 */ + 8.577316640149505e+00, /* 383 */ + 8.582272523698583e+00, /* 384 */ + 8.587231270705169e+00, /* 385 */ + 8.592192882823742e+00, /* 386 */ + 8.597157361709733e+00, /* 387 */ + 8.602124709019529e+00, /* 388 */ + 8.607094926410477e+00, /* 389 */ + 8.612068015540880e+00, /* 390 */ + 8.617043978069995e+00, /* 391 */ + 8.622022815658045e+00, /* 392 */ + 8.627004529966209e+00, /* 393 */ + 8.631989122656625e+00, /* 394 */ + 8.636976595392392e+00, /* 395 */ + 8.641966949837570e+00, /* 396 */ + 8.646960187657180e+00, /* 397 */ + 8.651956310517207e+00, /* 398 */ + 8.656955320084593e+00, /* 399 */ + 8.661957218027252e+00, /* 400 */ + 8.666962006014057e+00, /* 401 */ + 8.671969685714840e+00, /* 402 */ + 8.676980258800409e+00, /* 403 */ + 8.681993726942528e+00, /* 404 */ + 8.687010091813930e+00, /* 405 */ + 8.692029355088316e+00, /* 406 */ + 8.697051518440352e+00, /* 407 */ + 8.702076583545674e+00, /* 408 */ + 8.707104552080883e+00, /* 409 */ + 8.712135425723552e+00, /* 410 */ + 8.717169206152221e+00, /* 411 */ + 8.722205895046399e+00, /* 412 */ + 8.727245494086567e+00, /* 413 */ + 8.732288004954178e+00, /* 414 */ + 8.737333429331656e+00, /* 415 */ + 8.742381768902394e+00, /* 416 */ + 8.747433025350762e+00, /* 417 */ + 8.752487200362102e+00, /* 418 */ + 8.757544295622727e+00, /* 419 */ + 8.762604312819928e+00, /* 420 */ + 8.767667253641967e+00, /* 421 */ + 8.772733119778087e+00, /* 422 */ + 8.777801912918500e+00, /* 423 */ + 8.782873634754402e+00, /* 424 */ + 8.787948286977960e+00, /* 425 */ + 8.793025871282323e+00, /* 426 */ + 8.798106389361616e+00, /* 427 */ + 8.803189842910941e+00, /* 428 */ + 8.808276233626385e+00, /* 429 */ + 8.813365563205011e+00, /* 430 */ + 8.818457833344864e+00, /* 431 */ + 8.823553045744966e+00, /* 432 */ + 8.828651202105329e+00, /* 433 */ + 8.833752304126937e+00, /* 434 */ + 8.838856353511767e+00, /* 435 */ + 8.843963351962772e+00, /* 436 */ + 8.849073301183891e+00, /* 437 */ + 8.854186202880051e+00, /* 438 */ + 8.859302058757157e+00, /* 439 */ + 8.864420870522107e+00, /* 440 */ + 8.869542639882781e+00, /* 441 */ + 8.874667368548046e+00, /* 442 */ + 8.879795058227758e+00, /* 443 */ + 8.884925710632759e+00, /* 444 */ + 8.890059327474882e+00, /* 445 */ + 8.895195910466947e+00, /* 446 */ + 8.900335461322765e+00, /* 447 */ + 8.905477981757135e+00, /* 448 */ + 8.910623473485851e+00, /* 449 */ + 8.915771938225692e+00, /* 450 */ + 8.920923377694434e+00, /* 451 */ + 8.926077793610846e+00, /* 452 */ + 8.931235187694687e+00, /* 453 */ + 8.936395561666711e+00, /* 454 */ + 8.941558917248665e+00, /* 455 */ + 8.946725256163294e+00, /* 456 */ + 8.951894580134335e+00, /* 457 */ + 8.957066890886521e+00, /* 458 */ + 8.962242190145584e+00, /* 459 */ + 8.967420479638255e+00, /* 460 */ + 8.972601761092255e+00, /* 461 */ + 8.977786036236310e+00, /* 462 */ + 8.982973306800142e+00, /* 463 */ + 8.988163574514473e+00, /* 464 */ + 8.993356841111027e+00, /* 465 */ + 8.998553108322524e+00, /* 466 */ + 9.003752377882689e+00, /* 467 */ + 9.008954651526247e+00, /* 468 */ + 9.014159930988928e+00, /* 469 */ + 9.019368218007461e+00, /* 470 */ + 9.024579514319580e+00, /* 471 */ + 9.029793821664024e+00, /* 472 */ + 9.035011141780535e+00, /* 473 */ + 9.040231476409861e+00, /* 474 */ + 9.045454827293758e+00, /* 475 */ + 9.050681196174985e+00, /* 476 */ + 9.055910584797308e+00, /* 477 */ + 9.061142994905502e+00, /* 478 */ + 9.066378428245352e+00, /* 479 */ + 9.071616886563648e+00, /* 480 */ + 9.076858371608191e+00, /* 481 */ + 9.082102885127791e+00, /* 482 */ + 9.087350428872268e+00, /* 483 */ + 9.092601004592458e+00, /* 484 */ + 9.097854614040202e+00, /* 485 */ + 9.103111258968356e+00, /* 486 */ + 9.108370941130788e+00, /* 487 */ + 9.113633662282384e+00, /* 488 */ + 9.118899424179036e+00, /* 489 */ + 9.124168228577656e+00, /* 490 */ + 9.129440077236168e+00, /* 491 */ + 9.134714971913517e+00, /* 492 */ + 9.139992914369659e+00, /* 493 */ + 9.145273906365567e+00, /* 494 */ + 9.150557949663234e+00, /* 495 */ + 9.155845046025673e+00, /* 496 */ + 9.161135197216907e+00, /* 497 */ + 9.166428405001991e+00, /* 498 */ + 9.171724671146988e+00, /* 499 */ + 9.177023997418987e+00, /* 500 */ + 9.182326385586098e+00, /* 501 */ + 9.187631837417451e+00, /* 502 */ + 9.192940354683200e+00, /* 503 */ + 9.198251939154520e+00, /* 504 */ + 9.203566592603611e+00, /* 505 */ + 9.208884316803697e+00, /* 506 */ + 9.214205113529024e+00, /* 507 */ + 9.219528984554865e+00, /* 508 */ + 9.224855931657519e+00, /* 509 */ + 9.230185956614312e+00, /* 510 */ + 9.235519061203593e+00, /* 511 */ + 9.240855247204744e+00, /* 512 */ + 9.246194516398171e+00, /* 513 */ + 9.251536870565310e+00, /* 514 */ + 9.256882311488630e+00, /* 515 */ + 9.262230840951620e+00, /* 516 */ + 9.267582460738812e+00, /* 517 */ + 9.272937172635757e+00, /* 518 */ + 9.278294978429049e+00, /* 519 */ + 9.283655879906306e+00, /* 520 */ + 9.289019878856182e+00, /* 521 */ + 9.294386977068365e+00, /* 522 */ + 9.299757176333575e+00, /* 523 */ + 9.305130478443569e+00, /* 524 */ + 9.310506885191138e+00, /* 525 */ + 9.315886398370107e+00, /* 526 */ + 9.321269019775343e+00, /* 527 */ + 9.326654751202744e+00, /* 528 */ + 9.332043594449249e+00, /* 529 */ + 9.337435551312835e+00, /* 530 */ + 9.342830623592516e+00, /* 531 */ + 9.348228813088346e+00, /* 532 */ + 9.353630121601423e+00, /* 533 */ + 9.359034550933879e+00, /* 534 */ + 9.364442102888894e+00, /* 535 */ + 9.369852779270683e+00, /* 536 */ + 9.375266581884510e+00, /* 537 */ + 9.380683512536677e+00, /* 538 */ + 9.386103573034532e+00, /* 539 */ + 9.391526765186470e+00, /* 540 */ + 9.396953090801922e+00, /* 541 */ + 9.402382551691376e+00, /* 542 */ + 9.407815149666359e+00, /* 543 */ + 9.413250886539444e+00, /* 544 */ + 9.418689764124254e+00, /* 545 */ + 9.424131784235461e+00, /* 546 */ + 9.429576948688782e+00, /* 547 */ + 9.435025259300986e+00, /* 548 */ + 9.440476717889890e+00, /* 549 */ + 9.445931326274362e+00, /* 550 */ + 9.451389086274322e+00, /* 551 */ + 9.456849999710737e+00, /* 552 */ + 9.462314068405634e+00, /* 553 */ + 9.467781294182085e+00, /* 554 */ + 9.473251678864221e+00, /* 555 */ + 9.478725224277222e+00, /* 556 */ + 9.484201932247325e+00, /* 557 */ + 9.489681804601826e+00, /* 558 */ + 9.495164843169070e+00, /* 559 */ + 9.500651049778460e+00, /* 560 */ + 9.506140426260462e+00, /* 561 */ + 9.511632974446592e+00, /* 562 */ + 9.517128696169429e+00, /* 563 */ + 9.522627593262607e+00, /* 564 */ + 9.528129667560824e+00, /* 565 */ + 9.533634920899836e+00, /* 566 */ + 9.539143355116456e+00, /* 567 */ + 9.544654972048564e+00, /* 568 */ + 9.550169773535101e+00, /* 569 */ + 9.555687761416067e+00, /* 570 */ + 9.561208937532529e+00, /* 571 */ + 9.566733303726613e+00, /* 572 */ + 9.572260861841515e+00, /* 573 */ + 9.577791613721493e+00, /* 574 */ + 9.583325561211870e+00, /* 575 */ + 9.588862706159038e+00, /* 576 */ + 9.594403050410451e+00, /* 577 */ + 9.599946595814636e+00, /* 578 */ + 9.605493344221186e+00, /* 579 */ + 9.611043297480759e+00, /* 580 */ + 9.616596457445088e+00, /* 581 */ + 9.622152825966971e+00, /* 582 */ + 9.627712404900283e+00, /* 583 */ + 9.633275196099962e+00, /* 584 */ + 9.638841201422023e+00, /* 585 */ + 9.644410422723555e+00, /* 586 */ + 9.649982861862712e+00, /* 587 */ + 9.655558520698731e+00, /* 588 */ + 9.661137401091917e+00, /* 589 */ + 9.666719504903652e+00, /* 590 */ + 9.672304833996394e+00, /* 591 */ + 9.677893390233677e+00, /* 592 */ + 9.683485175480111e+00, /* 593 */ + 9.689080191601384e+00, /* 594 */ + 9.694678440464259e+00, /* 595 */ + 9.700279923936582e+00, /* 596 */ + 9.705884643887279e+00, /* 597 */ + 9.711492602186349e+00, /* 598 */ + 9.717103800704876e+00, /* 599 */ + 9.722718241315029e+00, /* 600 */ + 9.728335925890050e+00, /* 601 */ + 9.733956856304269e+00, /* 602 */ + 9.739581034433099e+00, /* 603 */ + 9.745208462153036e+00, /* 604 */ + 9.750839141341658e+00, /* 605 */ + 9.756473073877629e+00, /* 606 */ + 9.762110261640702e+00, /* 607 */ + 9.767750706511709e+00, /* 608 */ + 9.773394410372575e+00, /* 609 */ + 9.779041375106310e+00, /* 610 */ + 9.784691602597013e+00, /* 611 */ + 9.790345094729869e+00, /* 612 */ + 9.796001853391154e+00, /* 613 */ + 9.801661880468235e+00, /* 614 */ + 9.807325177849568e+00, /* 615 */ + 9.812991747424702e+00, /* 616 */ + 9.818661591084274e+00, /* 617 */ + 9.824334710720015e+00, /* 618 */ + 9.830011108224751e+00, /* 619 */ + 9.835690785492401e+00, /* 620 */ + 9.841373744417977e+00, /* 621 */ + 9.847059986897586e+00, /* 622 */ + 9.852749514828432e+00, /* 623 */ + 9.858442330108813e+00, /* 624 */ + 9.864138434638127e+00, /* 625 */ + 9.869837830316865e+00, /* 626 */ + 9.875540519046620e+00, /* 627 */ + 9.881246502730082e+00, /* 628 */ + 9.886955783271041e+00, /* 629 */ + 9.892668362574387e+00, /* 630 */ + 9.898384242546111e+00, /* 631 */ + 9.904103425093302e+00, /* 632 */ + 9.909825912124154e+00, /* 633 */ + 9.915551705547966e+00, /* 634 */ + 9.921280807275133e+00, /* 635 */ + 9.927013219217161e+00, /* 636 */ + 9.932748943286656e+00, /* 637 */ + 9.938487981397330e+00, /* 638 */ + 9.944230335464004e+00, /* 639 */ + 9.949976007402599e+00, /* 640 */ + 9.955724999130149e+00, /* 641 */ + 9.961477312564792e+00, /* 642 */ + 9.967232949625776e+00, /* 643 */ + 9.972991912233459e+00, /* 644 */ + 9.978754202309304e+00, /* 645 */ + 9.984519821775887e+00, /* 646 */ + 9.990288772556898e+00, /* 647 */ + 9.996061056577135e+00, /* 648 */ + 1.000183667576251e+01, /* 649 */ + 1.000761563204004e+01, /* 650 */ + 1.001339792733786e+01, /* 651 */ + 1.001918356358524e+01, /* 652 */ + 1.002497254271253e+01, /* 653 */ + 1.003076486665121e+01, /* 654 */ + 1.003656053733387e+01, /* 655 */ + 1.004235955669425e+01, /* 656 */ + 1.004816192666716e+01, /* 657 */ + 1.005396764918855e+01, /* 658 */ + 1.005977672619549e+01, /* 659 */ + 1.006558915962617e+01, /* 660 */ + 1.007140495141990e+01, /* 661 */ + 1.007722410351709e+01, /* 662 */ + 1.008304661785931e+01, /* 663 */ + 1.008887249638921e+01, /* 664 */ + 1.009470174105059e+01, /* 665 */ + 1.010053435378837e+01, /* 666 */ + 1.010637033654859e+01, /* 667 */ + 1.011220969127841e+01, /* 668 */ + 1.011805241992611e+01, /* 669 */ + 1.012389852444111e+01, /* 670 */ + 1.012974800677396e+01, /* 671 */ + 1.013560086887632e+01, /* 672 */ + 1.014145711270099e+01, /* 673 */ + 1.014731674020188e+01, /* 674 */ + 1.015317975333406e+01, /* 675 */ + 1.015904615405370e+01, /* 676 */ + 1.016491594431812e+01, /* 677 */ + 1.017078912608576e+01, /* 678 */ + 1.017666570131619e+01, /* 679 */ + 1.018254567197013e+01, /* 680 */ + 1.018842904000941e+01, /* 681 */ + 1.019431580739701e+01, /* 682 */ + 1.020020597609703e+01, /* 683 */ + 1.020609954807471e+01, /* 684 */ + 1.021199652529644e+01, /* 685 */ + 1.021789690972973e+01, /* 686 */ + 1.022380070334324e+01, /* 687 */ + 1.022970790810674e+01, /* 688 */ + 1.023561852599116e+01, /* 689 */ + 1.024153255896858e+01, /* 690 */ + 1.024745000901219e+01, /* 691 */ + 1.025337087809634e+01, /* 692 */ + 1.025929516819652e+01, /* 693 */ + 1.026522288128936e+01, /* 694 */ + 1.027115401935261e+01, /* 695 */ + 1.027708858436520e+01, /* 696 */ + 1.028302657830718e+01, /* 697 */ + 1.028896800315975e+01, /* 698 */ + 1.029491286090526e+01, /* 699 */ + 1.030086115352719e+01, /* 700 */ + 1.030681288301017e+01, /* 701 */ + 1.031276805134000e+01, /* 702 */ + 1.031872666050360e+01, /* 703 */ + 1.032468871248905e+01, /* 704 */ + 1.033065420928557e+01, /* 705 */ + 1.033662315288354e+01, /* 706 */ + 1.034259554527449e+01, /* 707 */ + 1.034857138845109e+01, /* 708 */ + 1.035455068440717e+01, /* 709 */ + 1.036053343513771e+01, /* 710 */ + 1.036651964263884e+01, /* 711 */ + 1.037250930890785e+01, /* 712 */ + 1.037850243594318e+01, /* 713 */ + 1.038449902574443e+01, /* 714 */ + 1.039049908031233e+01, /* 715 */ + 1.039650260164880e+01, /* 716 */ + 1.040250959175691e+01, /* 717 */ + 1.040852005264086e+01, /* 718 */ + 1.041453398630604e+01, /* 719 */ + 1.042055139475899e+01, /* 720 */ + 1.042657228000739e+01, /* 721 */ + 1.043259664406012e+01, /* 722 */ + 1.043862448892718e+01, /* 723 */ + 1.044465581661974e+01, /* 724 */ + 1.045069062915016e+01, /* 725 */ + 1.045672892853194e+01, /* 726 */ + 1.046277071677973e+01, /* 727 */ + 1.046881599590938e+01, /* 728 */ + 1.047486476793787e+01, /* 729 */ + 1.048091703488336e+01, /* 730 */ + 1.048697279876519e+01, /* 731 */ + 1.049303206160384e+01, /* 732 */ + 1.049909482542098e+01, /* 733 */ + 1.050516109223943e+01, /* 734 */ + 1.051123086408320e+01, /* 735 */ + 1.051730414297744e+01, /* 736 */ + 1.052338093094850e+01, /* 737 */ + 1.052946123002388e+01, /* 738 */ + 1.053554504223227e+01, /* 739 */ + 1.054163236960350e+01, /* 740 */ + 1.054772321416862e+01, /* 741 */ + 1.055381757795981e+01, /* 742 */ + 1.055991546301045e+01, /* 743 */ + 1.056601687135509e+01, /* 744 */ + 1.057212180502944e+01, /* 745 */ + 1.057823026607040e+01, /* 746 */ + 1.058434225651606e+01, /* 747 */ + 1.059045777840566e+01, /* 748 */ + 1.059657683377963e+01, /* 749 */ + 1.060269942467959e+01, /* 750 */ + 1.060882555314833e+01, /* 751 */ + 1.061495522122981e+01, /* 752 */ + 1.062108843096918e+01, /* 753 */ + 1.062722518441279e+01, /* 754 */ + 1.063336548360814e+01, /* 755 */ + 1.063950933060393e+01, /* 756 */ + 1.064565672745005e+01, /* 757 */ + 1.065180767619755e+01, /* 758 */ + 1.065796217889870e+01, /* 759 */ + 1.066412023760692e+01, /* 760 */ + 1.067028185437685e+01, /* 761 */ + 1.067644703126430e+01, /* 762 */ + 1.068261577032625e+01, /* 763 */ + 1.068878807362090e+01, /* 764 */ + 1.069496394320763e+01, /* 765 */ + 1.070114338114700e+01, /* 766 */ + 1.070732638950076e+01, /* 767 */ + 1.071351297033187e+01, /* 768 */ + 1.071970312570447e+01, /* 769 */ + 1.072589685768389e+01, /* 770 */ + 1.073209416833664e+01, /* 771 */ + 1.073829505973047e+01, /* 772 */ + 1.074449953393427e+01, /* 773 */ + 1.075070759301816e+01, /* 774 */ + 1.075691923905345e+01, /* 775 */ + 1.076313447411263e+01, /* 776 */ + 1.076935330026941e+01, /* 777 */ + 1.077557571959869e+01, /* 778 */ + 1.078180173417656e+01, /* 779 */ + 1.078803134608032e+01, /* 780 */ + 1.079426455738847e+01, /* 781 */ + 1.080050137018071e+01, /* 782 */ + 1.080674178653793e+01, /* 783 */ + 1.081298580854224e+01, /* 784 */ + 1.081923343827694e+01, /* 785 */ + 1.082548467782655e+01, /* 786 */ + 1.083173952927677e+01, /* 787 */ + 1.083799799471452e+01, /* 788 */ + 1.084426007622793e+01, /* 789 */ + 1.085052577590632e+01, /* 790 */ + 1.085679509584024e+01, /* 791 */ + 1.086306803812144e+01, /* 792 */ + 1.086934460484285e+01, /* 793 */ + 1.087562479809866e+01, /* 794 */ + 1.088190861998423e+01, /* 795 */ + 1.088819607259615e+01, /* 796 */ + 1.089448715803220e+01, /* 797 */ + 1.090078187839141e+01, /* 798 */ + 1.090708023577399e+01, /* 799 */ + 1.091338223228137e+01, /* 800 */ + 1.091968787001621e+01, /* 801 */ + 1.092599715108236e+01, /* 802 */ + 1.093231007758490e+01, /* 803 */ + 1.093862665163013e+01, /* 804 */ + 1.094494687532556e+01, /* 805 */ + 1.095127075077993e+01, /* 806 */ + 1.095759828010317e+01, /* 807 */ + 1.096392946540646e+01, /* 808 */ + 1.097026430880218e+01, /* 809 */ + 1.097660281240394e+01, /* 810 */ + 1.098294497832656e+01, /* 811 */ + 1.098929080868611e+01, /* 812 */ + 1.099564030559985e+01, /* 813 */ + 1.100199347118628e+01, /* 814 */ + 1.100835030756511e+01, /* 815 */ + 1.101471081685730e+01, /* 816 */ + 1.102107500118502e+01, /* 817 */ + 1.102744286267166e+01, /* 818 */ + 1.103381440344184e+01, /* 819 */ + 1.104018962562143e+01, /* 820 */ + 1.104656853133749e+01, /* 821 */ + 1.105295112271833e+01, /* 822 */ + 1.105933740189350e+01, /* 823 */ + 1.106572737099377e+01, /* 824 */ + 1.107212103215112e+01, /* 825 */ + 1.107851838749881e+01, /* 826 */ + 1.108491943917128e+01, /* 827 */ + 1.109132418930424e+01, /* 828 */ + 1.109773264003461e+01, /* 829 */ + 1.110414479350058e+01, /* 830 */ + 1.111056065184153e+01, /* 831 */ + 1.111698021719810e+01, /* 832 */ + 1.112340349171218e+01, /* 833 */ + 1.112983047752687e+01, /* 834 */ + 1.113626117678652e+01, /* 835 */ + 1.114269559163672e+01, /* 836 */ + 1.114913372422430e+01, /* 837 */ + 1.115557557669733e+01, /* 838 */ + 1.116202115120513e+01, /* 839 */ + 1.116847044989824e+01, /* 840 */ + 1.117492347492846e+01, /* 841 */ + 1.118138022844883e+01, /* 842 */ + 1.118784071261362e+01, /* 843 */ + 1.119430492957838e+01, /* 844 */ + 1.120077288149986e+01, /* 845 */ + 1.120724457053610e+01, /* 846 */ + 1.121371999884635e+01, /* 847 */ + 1.122019916859113e+01, /* 848 */ + 1.122668208193219e+01, /* 849 */ + 1.123316874103256e+01, /* 850 */ + 1.123965914805649e+01, /* 851 */ + 1.124615330516949e+01, /* 852 */ + 1.125265121453833e+01, /* 853 */ + 1.125915287833101e+01, /* 854 */ + 1.126565829871680e+01, /* 855 */ + 1.127216747786624e+01, /* 856 */ + 1.127868041795107e+01, /* 857 */ + 1.128519712114435e+01, /* 858 */ + 1.129171758962035e+01, /* 859 */ + 1.129824182555462e+01, /* 860 */ + 1.130476983112394e+01, /* 861 */ + 1.131130160850638e+01, /* 862 */ + 1.131783715988125e+01, /* 863 */ + 1.132437648742913e+01, /* 864 */ + 1.133091959333184e+01, /* 865 */ + 1.133746647977249e+01, /* 866 */ + 1.134401714893542e+01, /* 867 */ + 1.135057160300625e+01, /* 868 */ + 1.135712984417187e+01, /* 869 */ + 1.136369187462041e+01, /* 870 */ + 1.137025769654129e+01, /* 871 */ + 1.137682731212518e+01, /* 872 */ + 1.138340072356401e+01, /* 873 */ + 1.138997793305099e+01, /* 874 */ + 1.139655894278060e+01, /* 875 */ + 1.140314375494857e+01, /* 876 */ + 1.140973237175192e+01, /* 877 */ + 1.141632479538892e+01, /* 878 */ + 1.142292102805911e+01, /* 879 */ + 1.142952107196333e+01, /* 880 */ + 1.143612492930366e+01, /* 881 */ + 1.144273260228346e+01, /* 882 */ + 1.144934409310737e+01, /* 883 */ + 1.145595940398131e+01, /* 884 */ + 1.146257853711245e+01, /* 885 */ + 1.146920149470925e+01, /* 886 */ + 1.147582827898146e+01, /* 887 */ + 1.148245889214008e+01, /* 888 */ + 1.148909333639740e+01, /* 889 */ + 1.149573161396700e+01, /* 890 */ + 1.150237372706373e+01, /* 891 */ + 1.150901967790370e+01, /* 892 */ + 1.151566946870432e+01, /* 893 */ + 1.152232310168429e+01, /* 894 */ + 1.152898057906358e+01, /* 895 */ + 1.153564190306344e+01, /* 896 */ + 1.154230707590640e+01, /* 897 */ + 1.154897609981630e+01, /* 898 */ + 1.155564897701822e+01, /* 899 */ + 1.156232570973857e+01, /* 900 */ + 1.156900630020503e+01, /* 901 */ + 1.157569075064656e+01, /* 902 */ + 1.158237906329340e+01, /* 903 */ + 1.158907124037712e+01, /* 904 */ + 1.159576728413052e+01, /* 905 */ + 1.160246719678775e+01, /* 906 */ + 1.160917098058420e+01, /* 907 */ + 1.161587863775658e+01, /* 908 */ + 1.162259017054289e+01, /* 909 */ + 1.162930558118242e+01, /* 910 */ + 1.163602487191574e+01, /* 911 */ + 1.164274804498475e+01, /* 912 */ + 1.164947510263260e+01, /* 913 */ + 1.165620604710378e+01, /* 914 */ + 1.166294088064403e+01, /* 915 */ + 1.166967960550044e+01, /* 916 */ + 1.167642222392135e+01, /* 917 */ + 1.168316873815644e+01, /* 918 */ + 1.168991915045666e+01, /* 919 */ + 1.169667346307427e+01, /* 920 */ + 1.170343167826283e+01, /* 921 */ + 1.171019379827721e+01, /* 922 */ + 1.171695982537358e+01, /* 923 */ + 1.172372976180941e+01, /* 924 */ + 1.173050360984346e+01, /* 925 */ + 1.173728137173583e+01, /* 926 */ + 1.174406304974791e+01, /* 927 */ + 1.175084864614237e+01, /* 928 */ + 1.175763816318322e+01, /* 929 */ + 1.176443160313578e+01, /* 930 */ + 1.177122896826666e+01, /* 931 */ + 1.177803026084377e+01, /* 932 */ + 1.178483548313637e+01, /* 933 */ + 1.179164463741501e+01, /* 934 */ + 1.179845772595153e+01, /* 935 */ + 1.180527475101911e+01, /* 936 */ + 1.181209571489225e+01, /* 937 */ + 1.181892061984674e+01, /* 938 */ + 1.182574946815969e+01, /* 939 */ + 1.183258226210954e+01, /* 940 */ + 1.183941900397603e+01, /* 941 */ + 1.184625969604024e+01, /* 942 */ + 1.185310434058453e+01, /* 943 */ + 1.185995293989262e+01, /* 944 */ + 1.186680549624953e+01, /* 945 */ + 1.187366201194159e+01, /* 946 */ + 1.188052248925647e+01, /* 947 */ + 1.188738693048315e+01, /* 948 */ + 1.189425533791194e+01, /* 949 */ + 1.190112771383447e+01, /* 950 */ + 1.190800406054369e+01, /* 951 */ + 1.191488438033388e+01, /* 952 */ + 1.192176867550065e+01, /* 953 */ + 1.192865694834093e+01, /* 954 */ + 1.193554920115298e+01, /* 955 */ + 1.194244543623637e+01, /* 956 */ + 1.194934565589204e+01, /* 957 */ + 1.195624986242221e+01, /* 958 */ + 1.196315805813046e+01, /* 959 */ + 1.197007024532171e+01, /* 960 */ + 1.197698642630218e+01, /* 961 */ + 1.198390660337945e+01, /* 962 */ + 1.199083077886241e+01, /* 963 */ + 1.199775895506131e+01, /* 964 */ + 1.200469113428772e+01, /* 965 */ + 1.201162731885455e+01, /* 966 */ + 1.201856751107603e+01, /* 967 */ + 1.202551171326775e+01, /* 968 */ + 1.203245992774663e+01, /* 969 */ + 1.203941215683092e+01, /* 970 */ + 1.204636840284023e+01, /* 971 */ + 1.205332866809548e+01, /* 972 */ + 1.206029295491897e+01, /* 973 */ + 1.206726126563430e+01, /* 974 */ + 1.207423360256643e+01, /* 975 */ + 1.208120996804169e+01, /* 976 */ + 1.208819036438771e+01, /* 977 */ + 1.209517479393349e+01, /* 978 */ + 1.210216325900937e+01, /* 979 */ + 1.210915576194704e+01, /* 980 */ + 1.211615230507953e+01, /* 981 */ + 1.212315289074123e+01, /* 982 */ + 1.213015752126786e+01, /* 983 */ + 1.213716619899651e+01, /* 984 */ + 1.214417892626560e+01, /* 985 */ + 1.215119570541492e+01, /* 986 */ + 1.215821653878560e+01, /* 987 */ + 1.216524142872013e+01, /* 988 */ + 1.217227037756235e+01, /* 989 */ + 1.217930338765746e+01, /* 990 */ + 1.218634046135199e+01, /* 991 */ + 1.219338160099387e+01, /* 992 */ + 1.220042680893234e+01, /* 993 */ + 1.220747608751803e+01, /* 994 */ + 1.221452943910292e+01, /* 995 */ + 1.222158686604034e+01, /* 996 */ + 1.222864837068499e+01, /* 997 */ + 1.223571395539292e+01, /* 998 */ + 1.224278362252155e+01, /* 999 */ + 1.224985737442966e+01, /* 1000 */ + 1.225693521347741e+01, /* 1001 */ + 1.226401714202627e+01, /* 1002 */ + 1.227110316243915e+01, /* 1003 */ + 1.227819327708026e+01, /* 1004 */ + 1.228528748831521e+01, /* 1005 */ + 1.229238579851096e+01, /* 1006 */ + 1.229948821003587e+01, /* 1007 */ + 1.230659472525962e+01, /* 1008 */ + 1.231370534655330e+01, /* 1009 */ + 1.232082007628935e+01, /* 1010 */ + 1.232793891684158e+01, /* 1011 */ + 1.233506187058518e+01, /* 1012 */ + 1.234218893989671e+01, /* 1013 */ + 1.234932012715410e+01, /* 1014 */ + 1.235645543473665e+01, /* 1015 */ + 1.236359486502506e+01, /* 1016 */ + 1.237073842040136e+01, /* 1017 */ + 1.237788610324901e+01, /* 1018 */ + 1.238503791595280e+01, /* 1019 */ + 1.239219386089892e+01, /* 1020 */ + 1.239935394047494e+01, /* 1021 */ + 1.240651815706980e+01, /* 1022 */ + 1.241368651307384e+01, /* 1023 */ + 1.242085901087876e+01, /* 1024 */ + 1.242803565287764e+01, /* 1025 */ + 1.243521644146496e+01, /* 1026 */ + 1.244240137903658e+01, /* 1027 */ + 1.244959046798973e+01, /* 1028 */ + 1.245678371072304e+01, /* 1029 */ + 1.246398110963652e+01, /* 1030 */ + 1.247118266713156e+01, /* 1031 */ + 1.247838838561096e+01, /* 1032 */ + 1.248559826747888e+01, /* 1033 */ + 1.249281231514089e+01, /* 1034 */ + 1.250003053100394e+01, /* 1035 */ + 1.250725291747637e+01, /* 1036 */ + 1.251447947696792e+01, /* 1037 */ + 1.252171021188970e+01, /* 1038 */ + 1.252894512465425e+01, /* 1039 */ + 1.253618421767548e+01, /* 1040 */ + 1.254342749336869e+01, /* 1041 */ + 1.255067495415059e+01, /* 1042 */ + 1.255792660243928e+01, /* 1043 */ + 1.256518244065426e+01, /* 1044 */ + 1.257244247121641e+01, /* 1045 */ + 1.257970669654805e+01, /* 1046 */ + 1.258697511907285e+01, /* 1047 */ + 1.259424774121592e+01, /* 1048 */ + 1.260152456540375e+01, /* 1049 */ + 1.260880559406423e+01, /* 1050 */ + 1.261609082962667e+01, /* 1051 */ + 1.262338027452177e+01, /* 1052 */ + 1.263067393118164e+01, /* 1053 */ + 1.263797180203979e+01, /* 1054 */ + 1.264527388953115e+01, /* 1055 */ + 1.265258019609203e+01, /* 1056 */ + 1.265989072416018e+01, /* 1057 */ + 1.266720547617473e+01, /* 1058 */ + 1.267452445457624e+01, /* 1059 */ + 1.268184766180666e+01, /* 1060 */ + 1.268917510030938e+01, /* 1061 */ + 1.269650677252918e+01, /* 1062 */ + 1.270384268091225e+01, /* 1063 */ + 1.271118282790620e+01, /* 1064 */ + 1.271852721596007e+01, /* 1065 */ + 1.272587584752428e+01, /* 1066 */ + 1.273322872505070e+01, /* 1067 */ + 1.274058585099260e+01, /* 1068 */ + 1.274794722780466e+01, /* 1069 */ + 1.275531285794301e+01, /* 1070 */ + 1.276268274386515e+01, /* 1071 */ + 1.277005688803004e+01, /* 1072 */ + 1.277743529289805e+01, /* 1073 */ + 1.278481796093098e+01, /* 1074 */ + 1.279220489459201e+01, /* 1075 */ + 1.279959609634581e+01, /* 1076 */ + 1.280699156865842e+01, /* 1077 */ + 1.281439131399733e+01, /* 1078 */ + 1.282179533483144e+01, /* 1079 */ + 1.282920363363110e+01, /* 1080 */ + 1.283661621286807e+01, /* 1081 */ + 1.284403307501554e+01, /* 1082 */ + 1.285145422254812e+01, /* 1083 */ + 1.285887965794188e+01, /* 1084 */ + 1.286630938367429e+01, /* 1085 */ + 1.287374340222427e+01, /* 1086 */ + 1.288118171607215e+01, /* 1087 */ + 1.288862432769973e+01, /* 1088 */ + 1.289607123959020e+01, /* 1089 */ + 1.290352245422822e+01, /* 1090 */ + 1.291097797409987e+01, /* 1091 */ + 1.291843780169266e+01, /* 1092 */ + 1.292590193949556e+01, /* 1093 */ + 1.293337038999896e+01, /* 1094 */ + 1.294084315569469e+01, /* 1095 */ + 1.294832023907602e+01, /* 1096 */ + 1.295580164263767e+01, /* 1097 */ + 1.296328736887579e+01, /* 1098 */ + 1.297077742028798e+01, /* 1099 */ + 1.297827179937329e+01, /* 1100 */ + 1.298577050863218e+01, /* 1101 */ + 1.299327355056660e+01, /* 1102 */ + 1.300078092767991e+01, /* 1103 */ + 1.300829264247694e+01, /* 1104 */ + 1.301580869746396e+01, /* 1105 */ + 1.302332909514868e+01, /* 1106 */ + 1.303085383804027e+01, /* 1107 */ + 1.303838292864934e+01, /* 1108 */ + 1.304591636948796e+01, /* 1109 */ + 1.305345416306964e+01, /* 1110 */ + 1.306099631190936e+01, /* 1111 */ + 1.306854281852353e+01, /* 1112 */ + 1.307609368543003e+01, /* 1113 */ + 1.308364891514820e+01, /* 1114 */ + 1.309120851019883e+01, /* 1115 */ + 1.309877247310414e+01, /* 1116 */ + 1.310634080638785e+01, /* 1117 */ + 1.311391351257511e+01, /* 1118 */ + 1.312149059419255e+01, /* 1119 */ + 1.312907205376823e+01, /* 1120 */ + 1.313665789383170e+01, /* 1121 */ + 1.314424811691396e+01, /* 1122 */ + 1.315184272554746e+01, /* 1123 */ + 1.315944172226614e+01, /* 1124 */ + 1.316704510960539e+01, /* 1125 */ + 1.317465289010205e+01, /* 1126 */ + 1.318226506629446e+01, /* 1127 */ + 1.318988164072239e+01, /* 1128 */ + 1.319750261592710e+01, /* 1129 */ + 1.320512799445131e+01, /* 1130 */ + 1.321275777883922e+01, /* 1131 */ + 1.322039197163648e+01, /* 1132 */ + 1.322803057539023e+01, /* 1133 */ + 1.323567359264908e+01, /* 1134 */ + 1.324332102596310e+01, /* 1135 */ + 1.325097287788384e+01, /* 1136 */ + 1.325862915096432e+01, /* 1137 */ + 1.326628984775905e+01, /* 1138 */ + 1.327395497082400e+01, /* 1139 */ + 1.328162452271663e+01, /* 1140 */ + 1.328929850599585e+01, /* 1141 */ + 1.329697692322209e+01, /* 1142 */ + 1.330465977695723e+01, /* 1143 */ + 1.331234706976464e+01, /* 1144 */ + 1.332003880420917e+01, /* 1145 */ + 1.332773498285714e+01, /* 1146 */ + 1.333543560827638e+01, /* 1147 */ + 1.334314068303618e+01, /* 1148 */ + 1.335085020970733e+01, /* 1149 */ + 1.335856419086208e+01, /* 1150 */ + 1.336628262907420e+01, /* 1151 */ + 1.337400552691893e+01, /* 1152 */ + 1.338173288697299e+01, /* 1153 */ + 1.338946471181460e+01, /* 1154 */ + 1.339720100402347e+01, /* 1155 */ + 1.340494176618080e+01, /* 1156 */ + 1.341268700086928e+01, /* 1157 */ + 1.342043671067309e+01, /* 1158 */ + 1.342819089817790e+01, /* 1159 */ + 1.343594956597088e+01, /* 1160 */ + 1.344371271664070e+01, /* 1161 */ + 1.345148035277751e+01, /* 1162 */ + 1.345925247697298e+01, /* 1163 */ + 1.346702909182024e+01, /* 1164 */ + 1.347481019991397e+01, /* 1165 */ + 1.348259580385030e+01, /* 1166 */ + 1.349038590622688e+01, /* 1167 */ + 1.349818050964288e+01, /* 1168 */ + 1.350597961669893e+01, /* 1169 */ + 1.351378322999720e+01, /* 1170 */ + 1.352159135214135e+01, /* 1171 */ + 1.352940398573654e+01, /* 1172 */ + 1.353722113338944e+01, /* 1173 */ + 1.354504279770823e+01, /* 1174 */ + 1.355286898130258e+01, /* 1175 */ + 1.356069968678369e+01, /* 1176 */ + 1.356853491676425e+01, /* 1177 */ + 1.357637467385848e+01, /* 1178 */ + 1.358421896068210e+01, /* 1179 */ + 1.359206777985232e+01, /* 1180 */ + 1.359992113398790e+01, /* 1181 */ + 1.360777902570909e+01, /* 1182 */ + 1.361564145763767e+01, /* 1183 */ + 1.362350843239690e+01, /* 1184 */ + 1.363137995261160e+01, /* 1185 */ + 1.363925602090809e+01, /* 1186 */ + 1.364713663991418e+01, /* 1187 */ + 1.365502181225924e+01, /* 1188 */ + 1.366291154057414e+01, /* 1189 */ + 1.367080582749128e+01, /* 1190 */ + 1.367870467564455e+01, /* 1191 */ + 1.368660808766940e+01, /* 1192 */ + 1.369451606620278e+01, /* 1193 */ + 1.370242861388318e+01, /* 1194 */ + 1.371034573335060e+01, /* 1195 */ + 1.371826742724657e+01, /* 1196 */ + 1.372619369821415e+01, /* 1197 */ + 1.373412454889792e+01, /* 1198 */ + 1.374205998194399e+01, /* 1199 */ +}; + +static const fluid_real_t fluid_cb2amp_tab[1441] = { + 1.000000000000000e+00, /* 0 */ + 9.885530946569389e-01, /* 1 */ + 9.772372209558107e-01, /* 2 */ + 9.660508789898133e-01, /* 3 */ + 9.549925860214360e-01, /* 4 */ + 9.440608762859234e-01, /* 5 */ + 9.332543007969910e-01, /* 6 */ + 9.225714271547631e-01, /* 7 */ + 9.120108393559098e-01, /* 8 */ + 9.015711376059569e-01, /* 9 */ + 8.912509381337456e-01, /* 10 */ + 8.810488730080140e-01, /* 11 */ + 8.709635899560806e-01, /* 12 */ + 8.609937521846006e-01, /* 13 */ + 8.511380382023764e-01, /* 14 */ + 8.413951416451951e-01, /* 15 */ + 8.317637711026710e-01, /* 16 */ + 8.222426499470712e-01, /* 17 */ + 8.128305161640993e-01, /* 18 */ + 8.035261221856173e-01, /* 19 */ + 7.943282347242815e-01, /* 20 */ + 7.852356346100717e-01, /* 21 */ + 7.762471166286917e-01, /* 22 */ + 7.673614893618189e-01, /* 23 */ + 7.585775750291838e-01, /* 24 */ + 7.498942093324559e-01, /* 25 */ + 7.413102413009175e-01, /* 26 */ + 7.328245331389041e-01, /* 27 */ + 7.244359600749901e-01, /* 28 */ + 7.161434102129021e-01, /* 29 */ + 7.079457843841379e-01, /* 30 */ + 6.998419960022735e-01, /* 31 */ + 6.918309709189365e-01, /* 32 */ + 6.839116472814293e-01, /* 33 */ + 6.760829753919818e-01, /* 34 */ + 6.683439175686146e-01, /* 35 */ + 6.606934480075960e-01, /* 36 */ + 6.531305526474723e-01, /* 37 */ + 6.456542290346555e-01, /* 38 */ + 6.382634861905487e-01, /* 39 */ + 6.309573444801932e-01, /* 40 */ + 6.237348354824193e-01, /* 41 */ + 6.165950018614822e-01, /* 42 */ + 6.095368972401691e-01, /* 43 */ + 6.025595860743578e-01, /* 44 */ + 5.956621435290105e-01, /* 45 */ + 5.888436553555889e-01, /* 46 */ + 5.821032177708714e-01, /* 47 */ + 5.754399373371569e-01, /* 48 */ + 5.688529308438415e-01, /* 49 */ + 5.623413251903491e-01, /* 50 */ + 5.559042572704036e-01, /* 51 */ + 5.495408738576245e-01, /* 52 */ + 5.432503314924332e-01, /* 53 */ + 5.370317963702528e-01, /* 54 */ + 5.308844442309884e-01, /* 55 */ + 5.248074602497727e-01, /* 56 */ + 5.188000389289611e-01, /* 57 */ + 5.128613839913648e-01, /* 58 */ + 5.069907082747044e-01, /* 59 */ + 5.011872336272722e-01, /* 60 */ + 4.954501908047902e-01, /* 61 */ + 4.897788193684462e-01, /* 62 */ + 4.841723675840993e-01, /* 63 */ + 4.786300923226384e-01, /* 64 */ + 4.731512589614805e-01, /* 65 */ + 4.677351412871982e-01, /* 66 */ + 4.623810213992603e-01, /* 67 */ + 4.570881896148750e-01, /* 68 */ + 4.518559443749224e-01, /* 69 */ + 4.466835921509631e-01, /* 70 */ + 4.415704473533125e-01, /* 71 */ + 4.365158322401660e-01, /* 72 */ + 4.315190768277652e-01, /* 73 */ + 4.265795188015927e-01, /* 74 */ + 4.216965034285822e-01, /* 75 */ + 4.168693834703354e-01, /* 76 */ + 4.120975190973302e-01, /* 77 */ + 4.073802778041127e-01, /* 78 */ + 4.027170343254591e-01, /* 79 */ + 3.981071705534973e-01, /* 80 */ + 3.935500754557775e-01, /* 81 */ + 3.890451449942806e-01, /* 82 */ + 3.845917820453535e-01, /* 83 */ + 3.801893963205612e-01, /* 84 */ + 3.758374042884441e-01, /* 85 */ + 3.715352290971725e-01, /* 86 */ + 3.672823004980846e-01, /* 87 */ + 3.630780547701014e-01, /* 88 */ + 3.589219346450052e-01, /* 89 */ + 3.548133892335755e-01, /* 90 */ + 3.507518739525680e-01, /* 91 */ + 3.467368504525317e-01, /* 92 */ + 3.427677865464503e-01, /* 93 */ + 3.388441561392025e-01, /* 94 */ + 3.349654391578277e-01, /* 95 */ + 3.311311214825911e-01, /* 96 */ + 3.273406948788382e-01, /* 97 */ + 3.235936569296283e-01, /* 98 */ + 3.198895109691398e-01, /* 99 */ + 3.162277660168379e-01, /* 100 */ + 3.126079367123955e-01, /* 101 */ + 3.090295432513591e-01, /* 102 */ + 3.054921113215513e-01, /* 103 */ + 3.019951720402016e-01, /* 104 */ + 2.985382618917959e-01, /* 105 */ + 2.951209226666386e-01, /* 106 */ + 2.917427014001167e-01, /* 107 */ + 2.884031503126606e-01, /* 108 */ + 2.851018267503909e-01, /* 109 */ + 2.818382931264454e-01, /* 110 */ + 2.786121168629770e-01, /* 111 */ + 2.754228703338166e-01, /* 112 */ + 2.722701308077912e-01, /* 113 */ + 2.691534803926915e-01, /* 114 */ + 2.660725059798810e-01, /* 115 */ + 2.630267991895382e-01, /* 116 */ + 2.600159563165272e-01, /* 117 */ + 2.570395782768864e-01, /* 118 */ + 2.540972705549305e-01, /* 119 */ + 2.511886431509580e-01, /* 120 */ + 2.483133105295570e-01, /* 121 */ + 2.454708915685030e-01, /* 122 */ + 2.426610095082415e-01, /* 123 */ + 2.398832919019490e-01, /* 124 */ + 2.371373705661655e-01, /* 125 */ + 2.344228815319922e-01, /* 126 */ + 2.317394649968479e-01, /* 127 */ + 2.290867652767773e-01, /* 128 */ + 2.264644307593060e-01, /* 129 */ + 2.238721138568339e-01, /* 130 */ + 2.213094709605638e-01, /* 131 */ + 2.187761623949553e-01, /* 132 */ + 2.162718523727020e-01, /* 133 */ + 2.137962089502232e-01, /* 134 */ + 2.113489039836647e-01, /* 135 */ + 2.089296130854039e-01, /* 136 */ + 2.065380155810529e-01, /* 137 */ + 2.041737944669529e-01, /* 138 */ + 2.018366363681561e-01, /* 139 */ + 1.995262314968880e-01, /* 140 */ + 1.972422736114854e-01, /* 141 */ + 1.949844599758045e-01, /* 142 */ + 1.927524913190936e-01, /* 143 */ + 1.905460717963247e-01, /* 144 */ + 1.883649089489801e-01, /* 145 */ + 1.862087136662867e-01, /* 146 */ + 1.840772001468956e-01, /* 147 */ + 1.819700858609983e-01, /* 148 */ + 1.798870915128788e-01, /* 149 */ + 1.778279410038923e-01, /* 150 */ + 1.757923613958693e-01, /* 151 */ + 1.737800828749375e-01, /* 152 */ + 1.717908387157588e-01, /* 153 */ + 1.698243652461744e-01, /* 154 */ + 1.678804018122560e-01, /* 155 */ + 1.659586907437561e-01, /* 156 */ + 1.640589773199539e-01, /* 157 */ + 1.621810097358930e-01, /* 158 */ + 1.603245390690042e-01, /* 159 */ + 1.584893192461113e-01, /* 160 */ + 1.566751070108149e-01, /* 161 */ + 1.548816618912481e-01, /* 162 */ + 1.531087461682030e-01, /* 163 */ + 1.513561248436208e-01, /* 164 */ + 1.496235656094433e-01, /* 165 */ + 1.479108388168207e-01, /* 166 */ + 1.462177174456718e-01, /* 167 */ + 1.445439770745927e-01, /* 168 */ + 1.428893958511103e-01, /* 169 */ + 1.412537544622754e-01, /* 170 */ + 1.396368361055938e-01, /* 171 */ + 1.380384264602885e-01, /* 172 */ + 1.364583136588925e-01, /* 173 */ + 1.348962882591654e-01, /* 174 */ + 1.333521432163324e-01, /* 175 */ + 1.318256738556407e-01, /* 176 */ + 1.303166778452299e-01, /* 177 */ + 1.288249551693134e-01, /* 178 */ + 1.273503081016662e-01, /* 179 */ + 1.258925411794167e-01, /* 180 */ + 1.244514611771385e-01, /* 181 */ + 1.230268770812381e-01, /* 182 */ + 1.216186000646368e-01, /* 183 */ + 1.202264434617413e-01, /* 184 */ + 1.188502227437018e-01, /* 185 */ + 1.174897554939529e-01, /* 186 */ + 1.161448613840343e-01, /* 187 */ + 1.148153621496883e-01, /* 188 */ + 1.135010815672315e-01, /* 189 */ + 1.122018454301963e-01, /* 190 */ + 1.109174815262401e-01, /* 191 */ + 1.096478196143185e-01, /* 192 */ + 1.083926914021204e-01, /* 193 */ + 1.071519305237606e-01, /* 194 */ + 1.059253725177289e-01, /* 195 */ + 1.047128548050899e-01, /* 196 */ + 1.035142166679344e-01, /* 197 */ + 1.023292992280754e-01, /* 198 */ + 1.011579454259899e-01, /* 199 */ + 1.000000000000000e-01, /* 200 */ + 9.885530946569389e-02, /* 201 */ + 9.772372209558107e-02, /* 202 */ + 9.660508789898134e-02, /* 203 */ + 9.549925860214359e-02, /* 204 */ + 9.440608762859234e-02, /* 205 */ + 9.332543007969911e-02, /* 206 */ + 9.225714271547632e-02, /* 207 */ + 9.120108393559097e-02, /* 208 */ + 9.015711376059569e-02, /* 209 */ + 8.912509381337455e-02, /* 210 */ + 8.810488730080140e-02, /* 211 */ + 8.709635899560807e-02, /* 212 */ + 8.609937521846006e-02, /* 213 */ + 8.511380382023764e-02, /* 214 */ + 8.413951416451951e-02, /* 215 */ + 8.317637711026710e-02, /* 216 */ + 8.222426499470711e-02, /* 217 */ + 8.128305161640992e-02, /* 218 */ + 8.035261221856173e-02, /* 219 */ + 7.943282347242815e-02, /* 220 */ + 7.852356346100718e-02, /* 221 */ + 7.762471166286918e-02, /* 222 */ + 7.673614893618190e-02, /* 223 */ + 7.585775750291837e-02, /* 224 */ + 7.498942093324558e-02, /* 225 */ + 7.413102413009175e-02, /* 226 */ + 7.328245331389041e-02, /* 227 */ + 7.244359600749900e-02, /* 228 */ + 7.161434102129020e-02, /* 229 */ + 7.079457843841379e-02, /* 230 */ + 6.998419960022735e-02, /* 231 */ + 6.918309709189364e-02, /* 232 */ + 6.839116472814294e-02, /* 233 */ + 6.760829753919818e-02, /* 234 */ + 6.683439175686146e-02, /* 235 */ + 6.606934480075960e-02, /* 236 */ + 6.531305526474723e-02, /* 237 */ + 6.456542290346555e-02, /* 238 */ + 6.382634861905487e-02, /* 239 */ + 6.309573444801933e-02, /* 240 */ + 6.237348354824192e-02, /* 241 */ + 6.165950018614821e-02, /* 242 */ + 6.095368972401691e-02, /* 243 */ + 6.025595860743577e-02, /* 244 */ + 5.956621435290105e-02, /* 245 */ + 5.888436553555890e-02, /* 246 */ + 5.821032177708714e-02, /* 247 */ + 5.754399373371569e-02, /* 248 */ + 5.688529308438414e-02, /* 249 */ + 5.623413251903491e-02, /* 250 */ + 5.559042572704036e-02, /* 251 */ + 5.495408738576246e-02, /* 252 */ + 5.432503314924332e-02, /* 253 */ + 5.370317963702528e-02, /* 254 */ + 5.308844442309883e-02, /* 255 */ + 5.248074602497726e-02, /* 256 */ + 5.188000389289611e-02, /* 257 */ + 5.128613839913648e-02, /* 258 */ + 5.069907082747044e-02, /* 259 */ + 5.011872336272723e-02, /* 260 */ + 4.954501908047902e-02, /* 261 */ + 4.897788193684462e-02, /* 262 */ + 4.841723675840993e-02, /* 263 */ + 4.786300923226383e-02, /* 264 */ + 4.731512589614805e-02, /* 265 */ + 4.677351412871982e-02, /* 266 */ + 4.623810213992603e-02, /* 267 */ + 4.570881896148751e-02, /* 268 */ + 4.518559443749224e-02, /* 269 */ + 4.466835921509631e-02, /* 270 */ + 4.415704473533125e-02, /* 271 */ + 4.365158322401660e-02, /* 272 */ + 4.315190768277652e-02, /* 273 */ + 4.265795188015926e-02, /* 274 */ + 4.216965034285822e-02, /* 275 */ + 4.168693834703354e-02, /* 276 */ + 4.120975190973302e-02, /* 277 */ + 4.073802778041127e-02, /* 278 */ + 4.027170343254591e-02, /* 279 */ + 3.981071705534973e-02, /* 280 */ + 3.935500754557775e-02, /* 281 */ + 3.890451449942806e-02, /* 282 */ + 3.845917820453536e-02, /* 283 */ + 3.801893963205612e-02, /* 284 */ + 3.758374042884442e-02, /* 285 */ + 3.715352290971725e-02, /* 286 */ + 3.672823004980846e-02, /* 287 */ + 3.630780547701013e-02, /* 288 */ + 3.589219346450052e-02, /* 289 */ + 3.548133892335754e-02, /* 290 */ + 3.507518739525680e-02, /* 291 */ + 3.467368504525317e-02, /* 292 */ + 3.427677865464503e-02, /* 293 */ + 3.388441561392026e-02, /* 294 */ + 3.349654391578277e-02, /* 295 */ + 3.311311214825911e-02, /* 296 */ + 3.273406948788382e-02, /* 297 */ + 3.235936569296283e-02, /* 298 */ + 3.198895109691398e-02, /* 299 */ + 3.162277660168379e-02, /* 300 */ + 3.126079367123955e-02, /* 301 */ + 3.090295432513590e-02, /* 302 */ + 3.054921113215513e-02, /* 303 */ + 3.019951720402016e-02, /* 304 */ + 2.985382618917960e-02, /* 305 */ + 2.951209226666386e-02, /* 306 */ + 2.917427014001167e-02, /* 307 */ + 2.884031503126606e-02, /* 308 */ + 2.851018267503909e-02, /* 309 */ + 2.818382931264454e-02, /* 310 */ + 2.786121168629770e-02, /* 311 */ + 2.754228703338166e-02, /* 312 */ + 2.722701308077912e-02, /* 313 */ + 2.691534803926916e-02, /* 314 */ + 2.660725059798810e-02, /* 315 */ + 2.630267991895382e-02, /* 316 */ + 2.600159563165272e-02, /* 317 */ + 2.570395782768864e-02, /* 318 */ + 2.540972705549305e-02, /* 319 */ + 2.511886431509580e-02, /* 320 */ + 2.483133105295570e-02, /* 321 */ + 2.454708915685030e-02, /* 322 */ + 2.426610095082415e-02, /* 323 */ + 2.398832919019490e-02, /* 324 */ + 2.371373705661655e-02, /* 325 */ + 2.344228815319922e-02, /* 326 */ + 2.317394649968479e-02, /* 327 */ + 2.290867652767773e-02, /* 328 */ + 2.264644307593060e-02, /* 329 */ + 2.238721138568340e-02, /* 330 */ + 2.213094709605638e-02, /* 331 */ + 2.187761623949553e-02, /* 332 */ + 2.162718523727020e-02, /* 333 */ + 2.137962089502232e-02, /* 334 */ + 2.113489039836647e-02, /* 335 */ + 2.089296130854040e-02, /* 336 */ + 2.065380155810529e-02, /* 337 */ + 2.041737944669529e-02, /* 338 */ + 2.018366363681561e-02, /* 339 */ + 1.995262314968880e-02, /* 340 */ + 1.972422736114854e-02, /* 341 */ + 1.949844599758045e-02, /* 342 */ + 1.927524913190936e-02, /* 343 */ + 1.905460717963247e-02, /* 344 */ + 1.883649089489800e-02, /* 345 */ + 1.862087136662868e-02, /* 346 */ + 1.840772001468956e-02, /* 347 */ + 1.819700858609984e-02, /* 348 */ + 1.798870915128788e-02, /* 349 */ + 1.778279410038923e-02, /* 350 */ + 1.757923613958693e-02, /* 351 */ + 1.737800828749375e-02, /* 352 */ + 1.717908387157588e-02, /* 353 */ + 1.698243652461744e-02, /* 354 */ + 1.678804018122560e-02, /* 355 */ + 1.659586907437561e-02, /* 356 */ + 1.640589773199539e-02, /* 357 */ + 1.621810097358930e-02, /* 358 */ + 1.603245390690041e-02, /* 359 */ + 1.584893192461113e-02, /* 360 */ + 1.566751070108149e-02, /* 361 */ + 1.548816618912481e-02, /* 362 */ + 1.531087461682030e-02, /* 363 */ + 1.513561248436208e-02, /* 364 */ + 1.496235656094433e-02, /* 365 */ + 1.479108388168207e-02, /* 366 */ + 1.462177174456718e-02, /* 367 */ + 1.445439770745928e-02, /* 368 */ + 1.428893958511103e-02, /* 369 */ + 1.412537544622754e-02, /* 370 */ + 1.396368361055938e-02, /* 371 */ + 1.380384264602885e-02, /* 372 */ + 1.364583136588924e-02, /* 373 */ + 1.348962882591654e-02, /* 374 */ + 1.333521432163324e-02, /* 375 */ + 1.318256738556407e-02, /* 376 */ + 1.303166778452299e-02, /* 377 */ + 1.288249551693134e-02, /* 378 */ + 1.273503081016662e-02, /* 379 */ + 1.258925411794167e-02, /* 380 */ + 1.244514611771385e-02, /* 381 */ + 1.230268770812382e-02, /* 382 */ + 1.216186000646368e-02, /* 383 */ + 1.202264434617413e-02, /* 384 */ + 1.188502227437018e-02, /* 385 */ + 1.174897554939529e-02, /* 386 */ + 1.161448613840343e-02, /* 387 */ + 1.148153621496883e-02, /* 388 */ + 1.135010815672315e-02, /* 389 */ + 1.122018454301963e-02, /* 390 */ + 1.109174815262401e-02, /* 391 */ + 1.096478196143185e-02, /* 392 */ + 1.083926914021204e-02, /* 393 */ + 1.071519305237606e-02, /* 394 */ + 1.059253725177289e-02, /* 395 */ + 1.047128548050900e-02, /* 396 */ + 1.035142166679344e-02, /* 397 */ + 1.023292992280754e-02, /* 398 */ + 1.011579454259899e-02, /* 399 */ + 1.000000000000000e-02, /* 400 */ + 9.885530946569389e-03, /* 401 */ + 9.772372209558107e-03, /* 402 */ + 9.660508789898133e-03, /* 403 */ + 9.549925860214359e-03, /* 404 */ + 9.440608762859234e-03, /* 405 */ + 9.332543007969910e-03, /* 406 */ + 9.225714271547631e-03, /* 407 */ + 9.120108393559097e-03, /* 408 */ + 9.015711376059568e-03, /* 409 */ + 8.912509381337455e-03, /* 410 */ + 8.810488730080140e-03, /* 411 */ + 8.709635899560806e-03, /* 412 */ + 8.609937521846007e-03, /* 413 */ + 8.511380382023764e-03, /* 414 */ + 8.413951416451950e-03, /* 415 */ + 8.317637711026711e-03, /* 416 */ + 8.222426499470711e-03, /* 417 */ + 8.128305161640993e-03, /* 418 */ + 8.035261221856172e-03, /* 419 */ + 7.943282347242816e-03, /* 420 */ + 7.852356346100717e-03, /* 421 */ + 7.762471166286917e-03, /* 422 */ + 7.673614893618189e-03, /* 423 */ + 7.585775750291838e-03, /* 424 */ + 7.498942093324558e-03, /* 425 */ + 7.413102413009175e-03, /* 426 */ + 7.328245331389041e-03, /* 427 */ + 7.244359600749901e-03, /* 428 */ + 7.161434102129020e-03, /* 429 */ + 7.079457843841380e-03, /* 430 */ + 6.998419960022735e-03, /* 431 */ + 6.918309709189364e-03, /* 432 */ + 6.839116472814293e-03, /* 433 */ + 6.760829753919818e-03, /* 434 */ + 6.683439175686146e-03, /* 435 */ + 6.606934480075960e-03, /* 436 */ + 6.531305526474723e-03, /* 437 */ + 6.456542290346555e-03, /* 438 */ + 6.382634861905487e-03, /* 439 */ + 6.309573444801933e-03, /* 440 */ + 6.237348354824193e-03, /* 441 */ + 6.165950018614821e-03, /* 442 */ + 6.095368972401692e-03, /* 443 */ + 6.025595860743578e-03, /* 444 */ + 5.956621435290105e-03, /* 445 */ + 5.888436553555890e-03, /* 446 */ + 5.821032177708714e-03, /* 447 */ + 5.754399373371569e-03, /* 448 */ + 5.688529308438415e-03, /* 449 */ + 5.623413251903491e-03, /* 450 */ + 5.559042572704035e-03, /* 451 */ + 5.495408738576246e-03, /* 452 */ + 5.432503314924332e-03, /* 453 */ + 5.370317963702527e-03, /* 454 */ + 5.308844442309883e-03, /* 455 */ + 5.248074602497726e-03, /* 456 */ + 5.188000389289611e-03, /* 457 */ + 5.128613839913649e-03, /* 458 */ + 5.069907082747044e-03, /* 459 */ + 5.011872336272723e-03, /* 460 */ + 4.954501908047903e-03, /* 461 */ + 4.897788193684462e-03, /* 462 */ + 4.841723675840993e-03, /* 463 */ + 4.786300923226384e-03, /* 464 */ + 4.731512589614805e-03, /* 465 */ + 4.677351412871982e-03, /* 466 */ + 4.623810213992603e-03, /* 467 */ + 4.570881896148750e-03, /* 468 */ + 4.518559443749223e-03, /* 469 */ + 4.466835921509631e-03, /* 470 */ + 4.415704473533125e-03, /* 471 */ + 4.365158322401659e-03, /* 472 */ + 4.315190768277652e-03, /* 473 */ + 4.265795188015927e-03, /* 474 */ + 4.216965034285823e-03, /* 475 */ + 4.168693834703354e-03, /* 476 */ + 4.120975190973302e-03, /* 477 */ + 4.073802778041128e-03, /* 478 */ + 4.027170343254591e-03, /* 479 */ + 3.981071705534973e-03, /* 480 */ + 3.935500754557775e-03, /* 481 */ + 3.890451449942806e-03, /* 482 */ + 3.845917820453536e-03, /* 483 */ + 3.801893963205612e-03, /* 484 */ + 3.758374042884442e-03, /* 485 */ + 3.715352290971725e-03, /* 486 */ + 3.672823004980846e-03, /* 487 */ + 3.630780547701014e-03, /* 488 */ + 3.589219346450052e-03, /* 489 */ + 3.548133892335755e-03, /* 490 */ + 3.507518739525680e-03, /* 491 */ + 3.467368504525316e-03, /* 492 */ + 3.427677865464504e-03, /* 493 */ + 3.388441561392026e-03, /* 494 */ + 3.349654391578276e-03, /* 495 */ + 3.311311214825911e-03, /* 496 */ + 3.273406948788382e-03, /* 497 */ + 3.235936569296282e-03, /* 498 */ + 3.198895109691398e-03, /* 499 */ + 3.162277660168379e-03, /* 500 */ + 3.126079367123955e-03, /* 501 */ + 3.090295432513590e-03, /* 502 */ + 3.054921113215513e-03, /* 503 */ + 3.019951720402016e-03, /* 504 */ + 2.985382618917960e-03, /* 505 */ + 2.951209226666386e-03, /* 506 */ + 2.917427014001167e-03, /* 507 */ + 2.884031503126606e-03, /* 508 */ + 2.851018267503909e-03, /* 509 */ + 2.818382931264454e-03, /* 510 */ + 2.786121168629770e-03, /* 511 */ + 2.754228703338166e-03, /* 512 */ + 2.722701308077912e-03, /* 513 */ + 2.691534803926916e-03, /* 514 */ + 2.660725059798810e-03, /* 515 */ + 2.630267991895382e-03, /* 516 */ + 2.600159563165272e-03, /* 517 */ + 2.570395782768864e-03, /* 518 */ + 2.540972705549305e-03, /* 519 */ + 2.511886431509580e-03, /* 520 */ + 2.483133105295570e-03, /* 521 */ + 2.454708915685030e-03, /* 522 */ + 2.426610095082416e-03, /* 523 */ + 2.398832919019490e-03, /* 524 */ + 2.371373705661655e-03, /* 525 */ + 2.344228815319922e-03, /* 526 */ + 2.317394649968479e-03, /* 527 */ + 2.290867652767773e-03, /* 528 */ + 2.264644307593060e-03, /* 529 */ + 2.238721138568339e-03, /* 530 */ + 2.213094709605638e-03, /* 531 */ + 2.187761623949552e-03, /* 532 */ + 2.162718523727020e-03, /* 533 */ + 2.137962089502232e-03, /* 534 */ + 2.113489039836647e-03, /* 535 */ + 2.089296130854039e-03, /* 536 */ + 2.065380155810529e-03, /* 537 */ + 2.041737944669529e-03, /* 538 */ + 2.018366363681561e-03, /* 539 */ + 1.995262314968880e-03, /* 540 */ + 1.972422736114854e-03, /* 541 */ + 1.949844599758045e-03, /* 542 */ + 1.927524913190936e-03, /* 543 */ + 1.905460717963247e-03, /* 544 */ + 1.883649089489801e-03, /* 545 */ + 1.862087136662868e-03, /* 546 */ + 1.840772001468956e-03, /* 547 */ + 1.819700858609984e-03, /* 548 */ + 1.798870915128788e-03, /* 549 */ + 1.778279410038923e-03, /* 550 */ + 1.757923613958693e-03, /* 551 */ + 1.737800828749375e-03, /* 552 */ + 1.717908387157588e-03, /* 553 */ + 1.698243652461744e-03, /* 554 */ + 1.678804018122560e-03, /* 555 */ + 1.659586907437561e-03, /* 556 */ + 1.640589773199539e-03, /* 557 */ + 1.621810097358930e-03, /* 558 */ + 1.603245390690041e-03, /* 559 */ + 1.584893192461113e-03, /* 560 */ + 1.566751070108149e-03, /* 561 */ + 1.548816618912481e-03, /* 562 */ + 1.531087461682030e-03, /* 563 */ + 1.513561248436208e-03, /* 564 */ + 1.496235656094433e-03, /* 565 */ + 1.479108388168207e-03, /* 566 */ + 1.462177174456718e-03, /* 567 */ + 1.445439770745928e-03, /* 568 */ + 1.428893958511103e-03, /* 569 */ + 1.412537544622754e-03, /* 570 */ + 1.396368361055938e-03, /* 571 */ + 1.380384264602885e-03, /* 572 */ + 1.364583136588925e-03, /* 573 */ + 1.348962882591654e-03, /* 574 */ + 1.333521432163324e-03, /* 575 */ + 1.318256738556407e-03, /* 576 */ + 1.303166778452299e-03, /* 577 */ + 1.288249551693134e-03, /* 578 */ + 1.273503081016662e-03, /* 579 */ + 1.258925411794167e-03, /* 580 */ + 1.244514611771385e-03, /* 581 */ + 1.230268770812381e-03, /* 582 */ + 1.216186000646368e-03, /* 583 */ + 1.202264434617413e-03, /* 584 */ + 1.188502227437018e-03, /* 585 */ + 1.174897554939529e-03, /* 586 */ + 1.161448613840343e-03, /* 587 */ + 1.148153621496883e-03, /* 588 */ + 1.135010815672315e-03, /* 589 */ + 1.122018454301963e-03, /* 590 */ + 1.109174815262401e-03, /* 591 */ + 1.096478196143185e-03, /* 592 */ + 1.083926914021204e-03, /* 593 */ + 1.071519305237606e-03, /* 594 */ + 1.059253725177289e-03, /* 595 */ + 1.047128548050900e-03, /* 596 */ + 1.035142166679344e-03, /* 597 */ + 1.023292992280754e-03, /* 598 */ + 1.011579454259898e-03, /* 599 */ + 1.000000000000000e-03, /* 600 */ + 9.885530946569388e-04, /* 601 */ + 9.772372209558107e-04, /* 602 */ + 9.660508789898134e-04, /* 603 */ + 9.549925860214359e-04, /* 604 */ + 9.440608762859234e-04, /* 605 */ + 9.332543007969911e-04, /* 606 */ + 9.225714271547631e-04, /* 607 */ + 9.120108393559097e-04, /* 608 */ + 9.015711376059569e-04, /* 609 */ + 8.912509381337455e-04, /* 610 */ + 8.810488730080141e-04, /* 611 */ + 8.709635899560806e-04, /* 612 */ + 8.609937521846006e-04, /* 613 */ + 8.511380382023765e-04, /* 614 */ + 8.413951416451951e-04, /* 615 */ + 8.317637711026710e-04, /* 616 */ + 8.222426499470711e-04, /* 617 */ + 8.128305161640993e-04, /* 618 */ + 8.035261221856172e-04, /* 619 */ + 7.943282347242815e-04, /* 620 */ + 7.852356346100718e-04, /* 621 */ + 7.762471166286917e-04, /* 622 */ + 7.673614893618189e-04, /* 623 */ + 7.585775750291837e-04, /* 624 */ + 7.498942093324559e-04, /* 625 */ + 7.413102413009175e-04, /* 626 */ + 7.328245331389041e-04, /* 627 */ + 7.244359600749900e-04, /* 628 */ + 7.161434102129020e-04, /* 629 */ + 7.079457843841379e-04, /* 630 */ + 6.998419960022735e-04, /* 631 */ + 6.918309709189364e-04, /* 632 */ + 6.839116472814293e-04, /* 633 */ + 6.760829753919818e-04, /* 634 */ + 6.683439175686146e-04, /* 635 */ + 6.606934480075960e-04, /* 636 */ + 6.531305526474723e-04, /* 637 */ + 6.456542290346556e-04, /* 638 */ + 6.382634861905487e-04, /* 639 */ + 6.309573444801932e-04, /* 640 */ + 6.237348354824193e-04, /* 641 */ + 6.165950018614822e-04, /* 642 */ + 6.095368972401691e-04, /* 643 */ + 6.025595860743578e-04, /* 644 */ + 5.956621435290105e-04, /* 645 */ + 5.888436553555889e-04, /* 646 */ + 5.821032177708714e-04, /* 647 */ + 5.754399373371570e-04, /* 648 */ + 5.688529308438415e-04, /* 649 */ + 5.623413251903491e-04, /* 650 */ + 5.559042572704036e-04, /* 651 */ + 5.495408738576246e-04, /* 652 */ + 5.432503314924332e-04, /* 653 */ + 5.370317963702527e-04, /* 654 */ + 5.308844442309884e-04, /* 655 */ + 5.248074602497726e-04, /* 656 */ + 5.188000389289611e-04, /* 657 */ + 5.128613839913648e-04, /* 658 */ + 5.069907082747043e-04, /* 659 */ + 5.011872336272723e-04, /* 660 */ + 4.954501908047902e-04, /* 661 */ + 4.897788193684462e-04, /* 662 */ + 4.841723675840993e-04, /* 663 */ + 4.786300923226383e-04, /* 664 */ + 4.731512589614805e-04, /* 665 */ + 4.677351412871982e-04, /* 666 */ + 4.623810213992603e-04, /* 667 */ + 4.570881896148750e-04, /* 668 */ + 4.518559443749224e-04, /* 669 */ + 4.466835921509631e-04, /* 670 */ + 4.415704473533125e-04, /* 671 */ + 4.365158322401659e-04, /* 672 */ + 4.315190768277652e-04, /* 673 */ + 4.265795188015927e-04, /* 674 */ + 4.216965034285822e-04, /* 675 */ + 4.168693834703354e-04, /* 676 */ + 4.120975190973302e-04, /* 677 */ + 4.073802778041127e-04, /* 678 */ + 4.027170343254591e-04, /* 679 */ + 3.981071705534972e-04, /* 680 */ + 3.935500754557775e-04, /* 681 */ + 3.890451449942806e-04, /* 682 */ + 3.845917820453535e-04, /* 683 */ + 3.801893963205612e-04, /* 684 */ + 3.758374042884442e-04, /* 685 */ + 3.715352290971725e-04, /* 686 */ + 3.672823004980847e-04, /* 687 */ + 3.630780547701013e-04, /* 688 */ + 3.589219346450052e-04, /* 689 */ + 3.548133892335755e-04, /* 690 */ + 3.507518739525680e-04, /* 691 */ + 3.467368504525316e-04, /* 692 */ + 3.427677865464504e-04, /* 693 */ + 3.388441561392026e-04, /* 694 */ + 3.349654391578277e-04, /* 695 */ + 3.311311214825911e-04, /* 696 */ + 3.273406948788382e-04, /* 697 */ + 3.235936569296283e-04, /* 698 */ + 3.198895109691398e-04, /* 699 */ + 3.162277660168379e-04, /* 700 */ + 3.126079367123955e-04, /* 701 */ + 3.090295432513590e-04, /* 702 */ + 3.054921113215513e-04, /* 703 */ + 3.019951720402016e-04, /* 704 */ + 2.985382618917959e-04, /* 705 */ + 2.951209226666386e-04, /* 706 */ + 2.917427014001167e-04, /* 707 */ + 2.884031503126606e-04, /* 708 */ + 2.851018267503909e-04, /* 709 */ + 2.818382931264454e-04, /* 710 */ + 2.786121168629771e-04, /* 711 */ + 2.754228703338166e-04, /* 712 */ + 2.722701308077912e-04, /* 713 */ + 2.691534803926916e-04, /* 714 */ + 2.660725059798809e-04, /* 715 */ + 2.630267991895382e-04, /* 716 */ + 2.600159563165272e-04, /* 717 */ + 2.570395782768864e-04, /* 718 */ + 2.540972705549305e-04, /* 719 */ + 2.511886431509580e-04, /* 720 */ + 2.483133105295570e-04, /* 721 */ + 2.454708915685030e-04, /* 722 */ + 2.426610095082416e-04, /* 723 */ + 2.398832919019490e-04, /* 724 */ + 2.371373705661655e-04, /* 725 */ + 2.344228815319922e-04, /* 726 */ + 2.317394649968479e-04, /* 727 */ + 2.290867652767773e-04, /* 728 */ + 2.264644307593060e-04, /* 729 */ + 2.238721138568340e-04, /* 730 */ + 2.213094709605638e-04, /* 731 */ + 2.187761623949553e-04, /* 732 */ + 2.162718523727020e-04, /* 733 */ + 2.137962089502232e-04, /* 734 */ + 2.113489039836647e-04, /* 735 */ + 2.089296130854040e-04, /* 736 */ + 2.065380155810529e-04, /* 737 */ + 2.041737944669529e-04, /* 738 */ + 2.018366363681561e-04, /* 739 */ + 1.995262314968880e-04, /* 740 */ + 1.972422736114854e-04, /* 741 */ + 1.949844599758045e-04, /* 742 */ + 1.927524913190936e-04, /* 743 */ + 1.905460717963247e-04, /* 744 */ + 1.883649089489800e-04, /* 745 */ + 1.862087136662868e-04, /* 746 */ + 1.840772001468956e-04, /* 747 */ + 1.819700858609983e-04, /* 748 */ + 1.798870915128788e-04, /* 749 */ + 1.778279410038923e-04, /* 750 */ + 1.757923613958693e-04, /* 751 */ + 1.737800828749376e-04, /* 752 */ + 1.717908387157588e-04, /* 753 */ + 1.698243652461744e-04, /* 754 */ + 1.678804018122560e-04, /* 755 */ + 1.659586907437561e-04, /* 756 */ + 1.640589773199539e-04, /* 757 */ + 1.621810097358930e-04, /* 758 */ + 1.603245390690042e-04, /* 759 */ + 1.584893192461113e-04, /* 760 */ + 1.566751070108149e-04, /* 761 */ + 1.548816618912481e-04, /* 762 */ + 1.531087461682030e-04, /* 763 */ + 1.513561248436208e-04, /* 764 */ + 1.496235656094433e-04, /* 765 */ + 1.479108388168207e-04, /* 766 */ + 1.462177174456718e-04, /* 767 */ + 1.445439770745927e-04, /* 768 */ + 1.428893958511103e-04, /* 769 */ + 1.412537544622754e-04, /* 770 */ + 1.396368361055938e-04, /* 771 */ + 1.380384264602885e-04, /* 772 */ + 1.364583136588925e-04, /* 773 */ + 1.348962882591654e-04, /* 774 */ + 1.333521432163324e-04, /* 775 */ + 1.318256738556407e-04, /* 776 */ + 1.303166778452299e-04, /* 777 */ + 1.288249551693134e-04, /* 778 */ + 1.273503081016662e-04, /* 779 */ + 1.258925411794167e-04, /* 780 */ + 1.244514611771385e-04, /* 781 */ + 1.230268770812382e-04, /* 782 */ + 1.216186000646368e-04, /* 783 */ + 1.202264434617413e-04, /* 784 */ + 1.188502227437018e-04, /* 785 */ + 1.174897554939530e-04, /* 786 */ + 1.161448613840343e-04, /* 787 */ + 1.148153621496883e-04, /* 788 */ + 1.135010815672315e-04, /* 789 */ + 1.122018454301963e-04, /* 790 */ + 1.109174815262401e-04, /* 791 */ + 1.096478196143185e-04, /* 792 */ + 1.083926914021204e-04, /* 793 */ + 1.071519305237606e-04, /* 794 */ + 1.059253725177289e-04, /* 795 */ + 1.047128548050899e-04, /* 796 */ + 1.035142166679344e-04, /* 797 */ + 1.023292992280754e-04, /* 798 */ + 1.011579454259898e-04, /* 799 */ + 1.000000000000000e-04, /* 800 */ + 9.885530946569389e-05, /* 801 */ + 9.772372209558107e-05, /* 802 */ + 9.660508789898133e-05, /* 803 */ + 9.549925860214359e-05, /* 804 */ + 9.440608762859233e-05, /* 805 */ + 9.332543007969910e-05, /* 806 */ + 9.225714271547631e-05, /* 807 */ + 9.120108393559098e-05, /* 808 */ + 9.015711376059569e-05, /* 809 */ + 8.912509381337455e-05, /* 810 */ + 8.810488730080140e-05, /* 811 */ + 8.709635899560807e-05, /* 812 */ + 8.609937521846007e-05, /* 813 */ + 8.511380382023765e-05, /* 814 */ + 8.413951416451952e-05, /* 815 */ + 8.317637711026710e-05, /* 816 */ + 8.222426499470712e-05, /* 817 */ + 8.128305161640992e-05, /* 818 */ + 8.035261221856173e-05, /* 819 */ + 7.943282347242815e-05, /* 820 */ + 7.852356346100718e-05, /* 821 */ + 7.762471166286918e-05, /* 822 */ + 7.673614893618189e-05, /* 823 */ + 7.585775750291837e-05, /* 824 */ + 7.498942093324559e-05, /* 825 */ + 7.413102413009175e-05, /* 826 */ + 7.328245331389041e-05, /* 827 */ + 7.244359600749901e-05, /* 828 */ + 7.161434102129020e-05, /* 829 */ + 7.079457843841379e-05, /* 830 */ + 6.998419960022735e-05, /* 831 */ + 6.918309709189365e-05, /* 832 */ + 6.839116472814293e-05, /* 833 */ + 6.760829753919818e-05, /* 834 */ + 6.683439175686147e-05, /* 835 */ + 6.606934480075961e-05, /* 836 */ + 6.531305526474724e-05, /* 837 */ + 6.456542290346555e-05, /* 838 */ + 6.382634861905487e-05, /* 839 */ + 6.309573444801932e-05, /* 840 */ + 6.237348354824193e-05, /* 841 */ + 6.165950018614821e-05, /* 842 */ + 6.095368972401692e-05, /* 843 */ + 6.025595860743577e-05, /* 844 */ + 5.956621435290105e-05, /* 845 */ + 5.888436553555889e-05, /* 846 */ + 5.821032177708714e-05, /* 847 */ + 5.754399373371569e-05, /* 848 */ + 5.688529308438414e-05, /* 849 */ + 5.623413251903491e-05, /* 850 */ + 5.559042572704036e-05, /* 851 */ + 5.495408738576245e-05, /* 852 */ + 5.432503314924332e-05, /* 853 */ + 5.370317963702527e-05, /* 854 */ + 5.308844442309884e-05, /* 855 */ + 5.248074602497726e-05, /* 856 */ + 5.188000389289611e-05, /* 857 */ + 5.128613839913649e-05, /* 858 */ + 5.069907082747044e-05, /* 859 */ + 5.011872336272723e-05, /* 860 */ + 4.954501908047902e-05, /* 861 */ + 4.897788193684462e-05, /* 862 */ + 4.841723675840994e-05, /* 863 */ + 4.786300923226384e-05, /* 864 */ + 4.731512589614805e-05, /* 865 */ + 4.677351412871982e-05, /* 866 */ + 4.623810213992603e-05, /* 867 */ + 4.570881896148750e-05, /* 868 */ + 4.518559443749224e-05, /* 869 */ + 4.466835921509631e-05, /* 870 */ + 4.415704473533125e-05, /* 871 */ + 4.365158322401660e-05, /* 872 */ + 4.315190768277652e-05, /* 873 */ + 4.265795188015926e-05, /* 874 */ + 4.216965034285822e-05, /* 875 */ + 4.168693834703354e-05, /* 876 */ + 4.120975190973302e-05, /* 877 */ + 4.073802778041127e-05, /* 878 */ + 4.027170343254591e-05, /* 879 */ + 3.981071705534972e-05, /* 880 */ + 3.935500754557775e-05, /* 881 */ + 3.890451449942806e-05, /* 882 */ + 3.845917820453536e-05, /* 883 */ + 3.801893963205612e-05, /* 884 */ + 3.758374042884442e-05, /* 885 */ + 3.715352290971725e-05, /* 886 */ + 3.672823004980847e-05, /* 887 */ + 3.630780547701013e-05, /* 888 */ + 3.589219346450052e-05, /* 889 */ + 3.548133892335755e-05, /* 890 */ + 3.507518739525680e-05, /* 891 */ + 3.467368504525316e-05, /* 892 */ + 3.427677865464504e-05, /* 893 */ + 3.388441561392026e-05, /* 894 */ + 3.349654391578277e-05, /* 895 */ + 3.311311214825911e-05, /* 896 */ + 3.273406948788382e-05, /* 897 */ + 3.235936569296283e-05, /* 898 */ + 3.198895109691398e-05, /* 899 */ + 3.162277660168380e-05, /* 900 */ + 3.126079367123955e-05, /* 901 */ + 3.090295432513591e-05, /* 902 */ + 3.054921113215513e-05, /* 903 */ + 3.019951720402016e-05, /* 904 */ + 2.985382618917960e-05, /* 905 */ + 2.951209226666386e-05, /* 906 */ + 2.917427014001167e-05, /* 907 */ + 2.884031503126606e-05, /* 908 */ + 2.851018267503909e-05, /* 909 */ + 2.818382931264454e-05, /* 910 */ + 2.786121168629771e-05, /* 911 */ + 2.754228703338166e-05, /* 912 */ + 2.722701308077912e-05, /* 913 */ + 2.691534803926916e-05, /* 914 */ + 2.660725059798809e-05, /* 915 */ + 2.630267991895382e-05, /* 916 */ + 2.600159563165272e-05, /* 917 */ + 2.570395782768864e-05, /* 918 */ + 2.540972705549305e-05, /* 919 */ + 2.511886431509580e-05, /* 920 */ + 2.483133105295570e-05, /* 921 */ + 2.454708915685030e-05, /* 922 */ + 2.426610095082415e-05, /* 923 */ + 2.398832919019490e-05, /* 924 */ + 2.371373705661655e-05, /* 925 */ + 2.344228815319922e-05, /* 926 */ + 2.317394649968478e-05, /* 927 */ + 2.290867652767773e-05, /* 928 */ + 2.264644307593060e-05, /* 929 */ + 2.238721138568340e-05, /* 930 */ + 2.213094709605638e-05, /* 931 */ + 2.187761623949553e-05, /* 932 */ + 2.162718523727020e-05, /* 933 */ + 2.137962089502232e-05, /* 934 */ + 2.113489039836647e-05, /* 935 */ + 2.089296130854040e-05, /* 936 */ + 2.065380155810529e-05, /* 937 */ + 2.041737944669529e-05, /* 938 */ + 2.018366363681561e-05, /* 939 */ + 1.995262314968880e-05, /* 940 */ + 1.972422736114854e-05, /* 941 */ + 1.949844599758045e-05, /* 942 */ + 1.927524913190936e-05, /* 943 */ + 1.905460717963247e-05, /* 944 */ + 1.883649089489800e-05, /* 945 */ + 1.862087136662867e-05, /* 946 */ + 1.840772001468956e-05, /* 947 */ + 1.819700858609983e-05, /* 948 */ + 1.798870915128788e-05, /* 949 */ + 1.778279410038923e-05, /* 950 */ + 1.757923613958692e-05, /* 951 */ + 1.737800828749375e-05, /* 952 */ + 1.717908387157588e-05, /* 953 */ + 1.698243652461744e-05, /* 954 */ + 1.678804018122560e-05, /* 955 */ + 1.659586907437560e-05, /* 956 */ + 1.640589773199539e-05, /* 957 */ + 1.621810097358930e-05, /* 958 */ + 1.603245390690041e-05, /* 959 */ + 1.584893192461113e-05, /* 960 */ + 1.566751070108149e-05, /* 961 */ + 1.548816618912481e-05, /* 962 */ + 1.531087461682030e-05, /* 963 */ + 1.513561248436208e-05, /* 964 */ + 1.496235656094433e-05, /* 965 */ + 1.479108388168207e-05, /* 966 */ + 1.462177174456718e-05, /* 967 */ + 1.445439770745928e-05, /* 968 */ + 1.428893958511103e-05, /* 969 */ + 1.412537544622754e-05, /* 970 */ + 1.396368361055938e-05, /* 971 */ + 1.380384264602885e-05, /* 972 */ + 1.364583136588924e-05, /* 973 */ + 1.348962882591654e-05, /* 974 */ + 1.333521432163324e-05, /* 975 */ + 1.318256738556407e-05, /* 976 */ + 1.303166778452299e-05, /* 977 */ + 1.288249551693134e-05, /* 978 */ + 1.273503081016662e-05, /* 979 */ + 1.258925411794167e-05, /* 980 */ + 1.244514611771385e-05, /* 981 */ + 1.230268770812382e-05, /* 982 */ + 1.216186000646368e-05, /* 983 */ + 1.202264434617413e-05, /* 984 */ + 1.188502227437018e-05, /* 985 */ + 1.174897554939530e-05, /* 986 */ + 1.161448613840343e-05, /* 987 */ + 1.148153621496883e-05, /* 988 */ + 1.135010815672315e-05, /* 989 */ + 1.122018454301964e-05, /* 990 */ + 1.109174815262401e-05, /* 991 */ + 1.096478196143185e-05, /* 992 */ + 1.083926914021204e-05, /* 993 */ + 1.071519305237606e-05, /* 994 */ + 1.059253725177289e-05, /* 995 */ + 1.047128548050900e-05, /* 996 */ + 1.035142166679344e-05, /* 997 */ + 1.023292992280754e-05, /* 998 */ + 1.011579454259898e-05, /* 999 */ + 1.000000000000000e-05, /* 1000 */ + 9.885530946569389e-06, /* 1001 */ + 9.772372209558108e-06, /* 1002 */ + 9.660508789898134e-06, /* 1003 */ + 9.549925860214359e-06, /* 1004 */ + 9.440608762859234e-06, /* 1005 */ + 9.332543007969911e-06, /* 1006 */ + 9.225714271547632e-06, /* 1007 */ + 9.120108393559098e-06, /* 1008 */ + 9.015711376059568e-06, /* 1009 */ + 8.912509381337456e-06, /* 1010 */ + 8.810488730080140e-06, /* 1011 */ + 8.709635899560806e-06, /* 1012 */ + 8.609937521846006e-06, /* 1013 */ + 8.511380382023765e-06, /* 1014 */ + 8.413951416451952e-06, /* 1015 */ + 8.317637711026709e-06, /* 1016 */ + 8.222426499470711e-06, /* 1017 */ + 8.128305161640993e-06, /* 1018 */ + 8.035261221856173e-06, /* 1019 */ + 7.943282347242815e-06, /* 1020 */ + 7.852356346100718e-06, /* 1021 */ + 7.762471166286918e-06, /* 1022 */ + 7.673614893618189e-06, /* 1023 */ + 7.585775750291837e-06, /* 1024 */ + 7.498942093324558e-06, /* 1025 */ + 7.413102413009175e-06, /* 1026 */ + 7.328245331389041e-06, /* 1027 */ + 7.244359600749901e-06, /* 1028 */ + 7.161434102129020e-06, /* 1029 */ + 7.079457843841379e-06, /* 1030 */ + 6.998419960022735e-06, /* 1031 */ + 6.918309709189365e-06, /* 1032 */ + 6.839116472814293e-06, /* 1033 */ + 6.760829753919818e-06, /* 1034 */ + 6.683439175686146e-06, /* 1035 */ + 6.606934480075960e-06, /* 1036 */ + 6.531305526474723e-06, /* 1037 */ + 6.456542290346555e-06, /* 1038 */ + 6.382634861905487e-06, /* 1039 */ + 6.309573444801932e-06, /* 1040 */ + 6.237348354824192e-06, /* 1041 */ + 6.165950018614822e-06, /* 1042 */ + 6.095368972401692e-06, /* 1043 */ + 6.025595860743577e-06, /* 1044 */ + 5.956621435290104e-06, /* 1045 */ + 5.888436553555889e-06, /* 1046 */ + 5.821032177708714e-06, /* 1047 */ + 5.754399373371569e-06, /* 1048 */ + 5.688529308438415e-06, /* 1049 */ + 5.623413251903491e-06, /* 1050 */ + 5.559042572704035e-06, /* 1051 */ + 5.495408738576246e-06, /* 1052 */ + 5.432503314924332e-06, /* 1053 */ + 5.370317963702528e-06, /* 1054 */ + 5.308844442309884e-06, /* 1055 */ + 5.248074602497726e-06, /* 1056 */ + 5.188000389289611e-06, /* 1057 */ + 5.128613839913649e-06, /* 1058 */ + 5.069907082747044e-06, /* 1059 */ + 5.011872336272722e-06, /* 1060 */ + 4.954501908047903e-06, /* 1061 */ + 4.897788193684462e-06, /* 1062 */ + 4.841723675840994e-06, /* 1063 */ + 4.786300923226383e-06, /* 1064 */ + 4.731512589614805e-06, /* 1065 */ + 4.677351412871982e-06, /* 1066 */ + 4.623810213992603e-06, /* 1067 */ + 4.570881896148750e-06, /* 1068 */ + 4.518559443749223e-06, /* 1069 */ + 4.466835921509631e-06, /* 1070 */ + 4.415704473533125e-06, /* 1071 */ + 4.365158322401660e-06, /* 1072 */ + 4.315190768277652e-06, /* 1073 */ + 4.265795188015927e-06, /* 1074 */ + 4.216965034285822e-06, /* 1075 */ + 4.168693834703354e-06, /* 1076 */ + 4.120975190973302e-06, /* 1077 */ + 4.073802778041127e-06, /* 1078 */ + 4.027170343254591e-06, /* 1079 */ + 3.981071705534973e-06, /* 1080 */ + 3.935500754557774e-06, /* 1081 */ + 3.890451449942806e-06, /* 1082 */ + 3.845917820453536e-06, /* 1083 */ + 3.801893963205612e-06, /* 1084 */ + 3.758374042884442e-06, /* 1085 */ + 3.715352290971725e-06, /* 1086 */ + 3.672823004980847e-06, /* 1087 */ + 3.630780547701013e-06, /* 1088 */ + 3.589219346450052e-06, /* 1089 */ + 3.548133892335755e-06, /* 1090 */ + 3.507518739525680e-06, /* 1091 */ + 3.467368504525316e-06, /* 1092 */ + 3.427677865464503e-06, /* 1093 */ + 3.388441561392025e-06, /* 1094 */ + 3.349654391578277e-06, /* 1095 */ + 3.311311214825911e-06, /* 1096 */ + 3.273406948788382e-06, /* 1097 */ + 3.235936569296283e-06, /* 1098 */ + 3.198895109691398e-06, /* 1099 */ + 3.162277660168379e-06, /* 1100 */ + 3.126079367123955e-06, /* 1101 */ + 3.090295432513591e-06, /* 1102 */ + 3.054921113215513e-06, /* 1103 */ + 3.019951720402016e-06, /* 1104 */ + 2.985382618917960e-06, /* 1105 */ + 2.951209226666386e-06, /* 1106 */ + 2.917427014001167e-06, /* 1107 */ + 2.884031503126606e-06, /* 1108 */ + 2.851018267503909e-06, /* 1109 */ + 2.818382931264454e-06, /* 1110 */ + 2.786121168629770e-06, /* 1111 */ + 2.754228703338166e-06, /* 1112 */ + 2.722701308077913e-06, /* 1113 */ + 2.691534803926916e-06, /* 1114 */ + 2.660725059798810e-06, /* 1115 */ + 2.630267991895382e-06, /* 1116 */ + 2.600159563165272e-06, /* 1117 */ + 2.570395782768864e-06, /* 1118 */ + 2.540972705549305e-06, /* 1119 */ + 2.511886431509580e-06, /* 1120 */ + 2.483133105295570e-06, /* 1121 */ + 2.454708915685031e-06, /* 1122 */ + 2.426610095082416e-06, /* 1123 */ + 2.398832919019491e-06, /* 1124 */ + 2.371373705661655e-06, /* 1125 */ + 2.344228815319922e-06, /* 1126 */ + 2.317394649968478e-06, /* 1127 */ + 2.290867652767773e-06, /* 1128 */ + 2.264644307593060e-06, /* 1129 */ + 2.238721138568340e-06, /* 1130 */ + 2.213094709605638e-06, /* 1131 */ + 2.187761623949553e-06, /* 1132 */ + 2.162718523727020e-06, /* 1133 */ + 2.137962089502232e-06, /* 1134 */ + 2.113489039836647e-06, /* 1135 */ + 2.089296130854039e-06, /* 1136 */ + 2.065380155810529e-06, /* 1137 */ + 2.041737944669529e-06, /* 1138 */ + 2.018366363681561e-06, /* 1139 */ + 1.995262314968880e-06, /* 1140 */ + 1.972422736114854e-06, /* 1141 */ + 1.949844599758045e-06, /* 1142 */ + 1.927524913190936e-06, /* 1143 */ + 1.905460717963247e-06, /* 1144 */ + 1.883649089489801e-06, /* 1145 */ + 1.862087136662868e-06, /* 1146 */ + 1.840772001468956e-06, /* 1147 */ + 1.819700858609983e-06, /* 1148 */ + 1.798870915128788e-06, /* 1149 */ + 1.778279410038923e-06, /* 1150 */ + 1.757923613958693e-06, /* 1151 */ + 1.737800828749375e-06, /* 1152 */ + 1.717908387157588e-06, /* 1153 */ + 1.698243652461744e-06, /* 1154 */ + 1.678804018122560e-06, /* 1155 */ + 1.659586907437561e-06, /* 1156 */ + 1.640589773199539e-06, /* 1157 */ + 1.621810097358930e-06, /* 1158 */ + 1.603245390690041e-06, /* 1159 */ + 1.584893192461113e-06, /* 1160 */ + 1.566751070108149e-06, /* 1161 */ + 1.548816618912481e-06, /* 1162 */ + 1.531087461682030e-06, /* 1163 */ + 1.513561248436208e-06, /* 1164 */ + 1.496235656094434e-06, /* 1165 */ + 1.479108388168207e-06, /* 1166 */ + 1.462177174456718e-06, /* 1167 */ + 1.445439770745928e-06, /* 1168 */ + 1.428893958511103e-06, /* 1169 */ + 1.412537544622754e-06, /* 1170 */ + 1.396368361055938e-06, /* 1171 */ + 1.380384264602885e-06, /* 1172 */ + 1.364583136588924e-06, /* 1173 */ + 1.348962882591654e-06, /* 1174 */ + 1.333521432163324e-06, /* 1175 */ + 1.318256738556407e-06, /* 1176 */ + 1.303166778452299e-06, /* 1177 */ + 1.288249551693134e-06, /* 1178 */ + 1.273503081016662e-06, /* 1179 */ + 1.258925411794167e-06, /* 1180 */ + 1.244514611771385e-06, /* 1181 */ + 1.230268770812382e-06, /* 1182 */ + 1.216186000646368e-06, /* 1183 */ + 1.202264434617413e-06, /* 1184 */ + 1.188502227437018e-06, /* 1185 */ + 1.174897554939530e-06, /* 1186 */ + 1.161448613840343e-06, /* 1187 */ + 1.148153621496883e-06, /* 1188 */ + 1.135010815672315e-06, /* 1189 */ + 1.122018454301963e-06, /* 1190 */ + 1.109174815262401e-06, /* 1191 */ + 1.096478196143185e-06, /* 1192 */ + 1.083926914021203e-06, /* 1193 */ + 1.071519305237606e-06, /* 1194 */ + 1.059253725177289e-06, /* 1195 */ + 1.047128548050900e-06, /* 1196 */ + 1.035142166679344e-06, /* 1197 */ + 1.023292992280754e-06, /* 1198 */ + 1.011579454259898e-06, /* 1199 */ + 1.000000000000000e-06, /* 1200 */ + 9.885530946569389e-07, /* 1201 */ + 9.772372209558107e-07, /* 1202 */ + 9.660508789898133e-07, /* 1203 */ + 9.549925860214360e-07, /* 1204 */ + 9.440608762859233e-07, /* 1205 */ + 9.332543007969910e-07, /* 1206 */ + 9.225714271547632e-07, /* 1207 */ + 9.120108393559097e-07, /* 1208 */ + 9.015711376059569e-07, /* 1209 */ + 8.912509381337455e-07, /* 1210 */ + 8.810488730080140e-07, /* 1211 */ + 8.709635899560807e-07, /* 1212 */ + 8.609937521846007e-07, /* 1213 */ + 8.511380382023765e-07, /* 1214 */ + 8.413951416451951e-07, /* 1215 */ + 8.317637711026710e-07, /* 1216 */ + 8.222426499470711e-07, /* 1217 */ + 8.128305161640992e-07, /* 1218 */ + 8.035261221856172e-07, /* 1219 */ + 7.943282347242815e-07, /* 1220 */ + 7.852356346100718e-07, /* 1221 */ + 7.762471166286918e-07, /* 1222 */ + 7.673614893618189e-07, /* 1223 */ + 7.585775750291838e-07, /* 1224 */ + 7.498942093324558e-07, /* 1225 */ + 7.413102413009175e-07, /* 1226 */ + 7.328245331389040e-07, /* 1227 */ + 7.244359600749901e-07, /* 1228 */ + 7.161434102129020e-07, /* 1229 */ + 7.079457843841379e-07, /* 1230 */ + 6.998419960022735e-07, /* 1231 */ + 6.918309709189365e-07, /* 1232 */ + 6.839116472814294e-07, /* 1233 */ + 6.760829753919818e-07, /* 1234 */ + 6.683439175686146e-07, /* 1235 */ + 6.606934480075960e-07, /* 1236 */ + 6.531305526474723e-07, /* 1237 */ + 6.456542290346555e-07, /* 1238 */ + 6.382634861905487e-07, /* 1239 */ + 6.309573444801933e-07, /* 1240 */ + 6.237348354824193e-07, /* 1241 */ + 6.165950018614822e-07, /* 1242 */ + 6.095368972401692e-07, /* 1243 */ + 6.025595860743577e-07, /* 1244 */ + 5.956621435290105e-07, /* 1245 */ + 5.888436553555889e-07, /* 1246 */ + 5.821032177708714e-07, /* 1247 */ + 5.754399373371570e-07, /* 1248 */ + 5.688529308438414e-07, /* 1249 */ + 5.623413251903490e-07, /* 1250 */ + 5.559042572704035e-07, /* 1251 */ + 5.495408738576246e-07, /* 1252 */ + 5.432503314924332e-07, /* 1253 */ + 5.370317963702528e-07, /* 1254 */ + 5.308844442309884e-07, /* 1255 */ + 5.248074602497726e-07, /* 1256 */ + 5.188000389289611e-07, /* 1257 */ + 5.128613839913648e-07, /* 1258 */ + 5.069907082747044e-07, /* 1259 */ + 5.011872336272723e-07, /* 1260 */ + 4.954501908047903e-07, /* 1261 */ + 4.897788193684462e-07, /* 1262 */ + 4.841723675840993e-07, /* 1263 */ + 4.786300923226383e-07, /* 1264 */ + 4.731512589614805e-07, /* 1265 */ + 4.677351412871982e-07, /* 1266 */ + 4.623810213992603e-07, /* 1267 */ + 4.570881896148751e-07, /* 1268 */ + 4.518559443749224e-07, /* 1269 */ + 4.466835921509631e-07, /* 1270 */ + 4.415704473533125e-07, /* 1271 */ + 4.365158322401660e-07, /* 1272 */ + 4.315190768277652e-07, /* 1273 */ + 4.265795188015926e-07, /* 1274 */ + 4.216965034285823e-07, /* 1275 */ + 4.168693834703354e-07, /* 1276 */ + 4.120975190973302e-07, /* 1277 */ + 4.073802778041127e-07, /* 1278 */ + 4.027170343254591e-07, /* 1279 */ + 3.981071705534972e-07, /* 1280 */ + 3.935500754557775e-07, /* 1281 */ + 3.890451449942806e-07, /* 1282 */ + 3.845917820453536e-07, /* 1283 */ + 3.801893963205612e-07, /* 1284 */ + 3.758374042884442e-07, /* 1285 */ + 3.715352290971725e-07, /* 1286 */ + 3.672823004980847e-07, /* 1287 */ + 3.630780547701014e-07, /* 1288 */ + 3.589219346450052e-07, /* 1289 */ + 3.548133892335755e-07, /* 1290 */ + 3.507518739525680e-07, /* 1291 */ + 3.467368504525316e-07, /* 1292 */ + 3.427677865464503e-07, /* 1293 */ + 3.388441561392025e-07, /* 1294 */ + 3.349654391578277e-07, /* 1295 */ + 3.311311214825911e-07, /* 1296 */ + 3.273406948788382e-07, /* 1297 */ + 3.235936569296283e-07, /* 1298 */ + 3.198895109691398e-07, /* 1299 */ + 3.162277660168379e-07, /* 1300 */ + 3.126079367123955e-07, /* 1301 */ + 3.090295432513590e-07, /* 1302 */ + 3.054921113215513e-07, /* 1303 */ + 3.019951720402016e-07, /* 1304 */ + 2.985382618917960e-07, /* 1305 */ + 2.951209226666386e-07, /* 1306 */ + 2.917427014001167e-07, /* 1307 */ + 2.884031503126606e-07, /* 1308 */ + 2.851018267503909e-07, /* 1309 */ + 2.818382931264454e-07, /* 1310 */ + 2.786121168629770e-07, /* 1311 */ + 2.754228703338166e-07, /* 1312 */ + 2.722701308077912e-07, /* 1313 */ + 2.691534803926916e-07, /* 1314 */ + 2.660725059798809e-07, /* 1315 */ + 2.630267991895382e-07, /* 1316 */ + 2.600159563165272e-07, /* 1317 */ + 2.570395782768864e-07, /* 1318 */ + 2.540972705549305e-07, /* 1319 */ + 2.511886431509580e-07, /* 1320 */ + 2.483133105295570e-07, /* 1321 */ + 2.454708915685030e-07, /* 1322 */ + 2.426610095082416e-07, /* 1323 */ + 2.398832919019490e-07, /* 1324 */ + 2.371373705661655e-07, /* 1325 */ + 2.344228815319922e-07, /* 1326 */ + 2.317394649968478e-07, /* 1327 */ + 2.290867652767773e-07, /* 1328 */ + 2.264644307593060e-07, /* 1329 */ + 2.238721138568340e-07, /* 1330 */ + 2.213094709605638e-07, /* 1331 */ + 2.187761623949553e-07, /* 1332 */ + 2.162718523727020e-07, /* 1333 */ + 2.137962089502232e-07, /* 1334 */ + 2.113489039836647e-07, /* 1335 */ + 2.089296130854040e-07, /* 1336 */ + 2.065380155810529e-07, /* 1337 */ + 2.041737944669529e-07, /* 1338 */ + 2.018366363681561e-07, /* 1339 */ + 1.995262314968880e-07, /* 1340 */ + 1.972422736114854e-07, /* 1341 */ + 1.949844599758045e-07, /* 1342 */ + 1.927524913190936e-07, /* 1343 */ + 1.905460717963247e-07, /* 1344 */ + 1.883649089489800e-07, /* 1345 */ + 1.862087136662867e-07, /* 1346 */ + 1.840772001468956e-07, /* 1347 */ + 1.819700858609983e-07, /* 1348 */ + 1.798870915128788e-07, /* 1349 */ + 1.778279410038923e-07, /* 1350 */ + 1.757923613958693e-07, /* 1351 */ + 1.737800828749375e-07, /* 1352 */ + 1.717908387157588e-07, /* 1353 */ + 1.698243652461744e-07, /* 1354 */ + 1.678804018122560e-07, /* 1355 */ + 1.659586907437561e-07, /* 1356 */ + 1.640589773199539e-07, /* 1357 */ + 1.621810097358930e-07, /* 1358 */ + 1.603245390690041e-07, /* 1359 */ + 1.584893192461114e-07, /* 1360 */ + 1.566751070108149e-07, /* 1361 */ + 1.548816618912481e-07, /* 1362 */ + 1.531087461682030e-07, /* 1363 */ + 1.513561248436208e-07, /* 1364 */ + 1.496235656094433e-07, /* 1365 */ + 1.479108388168207e-07, /* 1366 */ + 1.462177174456718e-07, /* 1367 */ + 1.445439770745928e-07, /* 1368 */ + 1.428893958511103e-07, /* 1369 */ + 1.412537544622754e-07, /* 1370 */ + 1.396368361055938e-07, /* 1371 */ + 1.380384264602885e-07, /* 1372 */ + 1.364583136588925e-07, /* 1373 */ + 1.348962882591654e-07, /* 1374 */ + 1.333521432163324e-07, /* 1375 */ + 1.318256738556407e-07, /* 1376 */ + 1.303166778452299e-07, /* 1377 */ + 1.288249551693134e-07, /* 1378 */ + 1.273503081016662e-07, /* 1379 */ + 1.258925411794167e-07, /* 1380 */ + 1.244514611771385e-07, /* 1381 */ + 1.230268770812381e-07, /* 1382 */ + 1.216186000646368e-07, /* 1383 */ + 1.202264434617413e-07, /* 1384 */ + 1.188502227437018e-07, /* 1385 */ + 1.174897554939530e-07, /* 1386 */ + 1.161448613840343e-07, /* 1387 */ + 1.148153621496883e-07, /* 1388 */ + 1.135010815672315e-07, /* 1389 */ + 1.122018454301963e-07, /* 1390 */ + 1.109174815262401e-07, /* 1391 */ + 1.096478196143185e-07, /* 1392 */ + 1.083926914021204e-07, /* 1393 */ + 1.071519305237606e-07, /* 1394 */ + 1.059253725177289e-07, /* 1395 */ + 1.047128548050900e-07, /* 1396 */ + 1.035142166679344e-07, /* 1397 */ + 1.023292992280754e-07, /* 1398 */ + 1.011579454259898e-07, /* 1399 */ + 1.000000000000000e-07, /* 1400 */ + 9.885530946569389e-08, /* 1401 */ + 9.772372209558107e-08, /* 1402 */ + 9.660508789898134e-08, /* 1403 */ + 9.549925860214360e-08, /* 1404 */ + 9.440608762859234e-08, /* 1405 */ + 9.332543007969910e-08, /* 1406 */ + 9.225714271547632e-08, /* 1407 */ + 9.120108393559098e-08, /* 1408 */ + 9.015711376059569e-08, /* 1409 */ + 8.912509381337455e-08, /* 1410 */ + 8.810488730080140e-08, /* 1411 */ + 8.709635899560806e-08, /* 1412 */ + 8.609937521846006e-08, /* 1413 */ + 8.511380382023765e-08, /* 1414 */ + 8.413951416451951e-08, /* 1415 */ + 8.317637711026710e-08, /* 1416 */ + 8.222426499470712e-08, /* 1417 */ + 8.128305161640992e-08, /* 1418 */ + 8.035261221856172e-08, /* 1419 */ + 7.943282347242815e-08, /* 1420 */ + 7.852356346100718e-08, /* 1421 */ + 7.762471166286917e-08, /* 1422 */ + 7.673614893618189e-08, /* 1423 */ + 7.585775750291838e-08, /* 1424 */ + 7.498942093324559e-08, /* 1425 */ + 7.413102413009175e-08, /* 1426 */ + 7.328245331389041e-08, /* 1427 */ + 7.244359600749901e-08, /* 1428 */ + 7.161434102129020e-08, /* 1429 */ + 7.079457843841380e-08, /* 1430 */ + 6.998419960022735e-08, /* 1431 */ + 6.918309709189365e-08, /* 1432 */ + 6.839116472814293e-08, /* 1433 */ + 6.760829753919818e-08, /* 1434 */ + 6.683439175686146e-08, /* 1435 */ + 6.606934480075960e-08, /* 1436 */ + 6.531305526474724e-08, /* 1437 */ + 6.456542290346556e-08, /* 1438 */ + 6.382634861905487e-08, /* 1439 */ + 6.309573444801932e-08, /* 1440 */ +}; + +static const fluid_real_t fluid_concave_tab[128] = { + 0.000000000000000e+00, /* 0 */ + 1.430489932664151e-03, /* 1 */ + 2.872378311625187e-03, /* 2 */ + 4.325848247384080e-03, /* 3 */ + 5.791087298566222e-03, /* 4 */ + 7.268287617170264e-03, /* 5 */ + 8.757646099794491e-03, /* 6 */ + 1.025936454513835e-02, /* 7 */ + 1.177364981809421e-02, /* 8 */ + 1.330071402076312e-02, /* 9 */ + 1.484077467074801e-02, /* 10 */ + 1.639405488709933e-02, /* 11 */ + 1.796078358431049e-02, /* 12 */ + 1.954119567478511e-02, /* 13 */ + 2.113553228022381e-02, /* 14 */ + 2.274404095240635e-02, /* 15 */ + 2.436697590387476e-02, /* 16 */ + 2.600459824905492e-02, /* 17 */ + 2.765717625638884e-02, /* 18 */ + 2.932498561208631e-02, /* 19 */ + 3.100830969614467e-02, /* 20 */ + 3.270743987132776e-02, /* 21 */ + 3.442267578584116e-02, /* 22 */ + 3.615432569049021e-02, /* 23 */ + 3.790270677116027e-02, /* 24 */ + 3.966814549751637e-02, /* 25 */ + 4.145097798888095e-02, /* 26 */ + 4.325155039831535e-02, /* 27 */ + 4.507021931600289e-02, /* 28 */ + 4.690735219310917e-02, /* 29 */ + 4.876332778738000e-02, /* 30 */ + 5.063853663182852e-02, /* 31 */ + 5.253338152796212e-02, /* 32 */ + 5.444827806510758e-02, /* 33 */ + 5.638365516750905e-02, /* 34 */ + 5.833995567100066e-02, /* 35 */ + 6.031763693119302e-02, /* 36 */ + 6.231717146526333e-02, /* 37 */ + 6.433904762960170e-02, /* 38 */ + 6.638377033574509e-02, /* 39 */ + 6.845186180722430e-02, /* 40 */ + 7.054386238016214e-02, /* 41 */ + 7.266033135069339e-02, /* 42 */ + 7.480184787253133e-02, /* 43 */ + 7.696901190828456e-02, /* 44 */ + 7.916244523843340e-02, /* 45 */ + 8.138279253221128e-02, /* 46 */ + 8.363072248500553e-02, /* 47 */ + 8.590692902729809e-02, /* 48 */ + 8.821213261061518e-02, /* 49 */ + 9.054708157644790e-02, /* 50 */ + 9.291255361465228e-02, /* 51 */ + 9.530935731844033e-02, /* 52 */ + 9.773833384374193e-02, /* 53 */ + 1.002003586814587e-01, /* 54 */ + 1.026963435519535e-01, /* 55 */ + 1.052272384320340e-01, /* 56 */ + 1.077940337257083e-01, /* 57 */ + 1.103977625911256e-01, /* 58 */ + 1.130395034373835e-01, /* 59 */ + 1.157203826063043e-01, /* 60 */ + 1.184415772558701e-01, /* 61 */ + 1.212043184637922e-01, /* 62 */ + 1.240098945716957e-01, /* 63 */ + 1.268596547926563e-01, /* 64 */ + 1.297550131073762e-01, /* 65 */ + 1.326974524771624e-01, /* 66 */ + 1.356885294051305e-01, /* 67 */ + 1.387298788807553e-01, /* 68 */ + 1.418232197470915e-01, /* 69 */ + 1.449703605347773e-01, /* 70 */ + 1.481732058123985e-01, /* 71 */ + 1.514337631090471e-01, /* 72 */ + 1.547541504720785e-01, /* 73 */ + 1.581366047313199e-01, /* 74 */ + 1.615834905504824e-01, /* 75 */ + 1.650973103575085e-01, /* 76 */ + 1.686807152583075e-01, /* 77 */ + 1.723365170531013e-01, /* 78 */ + 1.760677014918207e-01, /* 79 */ + 1.798774429250997e-01, /* 80 */ + 1.837691205309928e-01, /* 81 */ + 1.877463363252555e-01, /* 82 */ + 1.918129351957372e-01, /* 83 */ + 1.959730272401543e-01, /* 84 */ + 2.002310127325235e-01, /* 85 */ + 2.045916100984256e-01, /* 86 */ + 2.090598873449977e-01, /* 87 */ + 2.136412974706073e-01, /* 88 */ + 2.183417184746445e-01, /* 89 */ + 2.231674987037341e-01, /* 90 */ + 2.281255084119456e-01, /* 91 */ + 2.332231985857005e-01, /* 92 */ + 2.384686682973757e-01, /* 93 */ + 2.438707421158622e-01, /* 94 */ + 2.494390594316878e-01, /* 95 */ + 2.551841779673684e-01, /* 96 */ + 2.611176942651227e-01, /* 97 */ + 2.672523846070836e-01, /* 98 */ + 2.736023706723907e-01, /* 99 */ + 2.801833153320706e-01, /* 100 */ + 2.870126554104745e-01, /* 101 */ + 2.941098801182996e-01, /* 102 */ + 3.014968663518128e-01, /* 103 */ + 3.091982853909850e-01, /* 104 */ + 3.172421000557294e-01, /* 105 */ + 3.256601775925156e-01, /* 106 */ + 3.344890522049898e-01, /* 107 */ + 3.437708833346366e-01, /* 108 */ + 3.535546732719378e-01, /* 109 */ + 3.638978331573678e-01, /* 110 */ + 3.748682242916800e-01, /* 111 */ + 3.865468591251148e-01, /* 112 */ + 3.990315355323828e-01, /* 113 */ + 4.124418202704667e-01, /* 114 */ + 4.269260312118050e-01, /* 115 */ + 4.426712649157216e-01, /* 116 */ + 4.599182170649820e-01, /* 117 */ + 4.789838381319300e-01, /* 118 */ + 5.002973891516721e-01, /* 119 */ + 5.244607003923749e-01, /* 120 */ + 5.523551960717972e-01, /* 121 */ + 5.853473819249742e-01, /* 122 */ + 6.257265540116643e-01, /* 123 */ + 6.777843609317893e-01, /* 124 */ + 7.511557188716564e-01, /* 125 */ + 8.765848837316486e-01, /* 126 */ + 1.000000000000000e+00, /* 127 */ +}; + +static const fluid_real_t fluid_convex_tab[128] = { + 0.000000000000000e+00, /* 0 */ + 1.234151162683514e-01, /* 1 */ + 2.488442811283435e-01, /* 2 */ + 3.222156390682107e-01, /* 3 */ + 3.742734459883357e-01, /* 4 */ + 4.146526180750258e-01, /* 5 */ + 4.476448039282029e-01, /* 6 */ + 4.755392996076250e-01, /* 7 */ + 4.997026108483278e-01, /* 8 */ + 5.210161618680701e-01, /* 9 */ + 5.400817829350180e-01, /* 10 */ + 5.573287350842785e-01, /* 11 */ + 5.730739687881951e-01, /* 12 */ + 5.875581797295333e-01, /* 13 */ + 6.009684644676172e-01, /* 14 */ + 6.134531408748852e-01, /* 15 */ + 6.251317757083200e-01, /* 16 */ + 6.361021668426321e-01, /* 17 */ + 6.464453267280622e-01, /* 18 */ + 6.562291166653634e-01, /* 19 */ + 6.655109477950102e-01, /* 20 */ + 6.743398224074844e-01, /* 21 */ + 6.827578999442706e-01, /* 22 */ + 6.908017146090151e-01, /* 23 */ + 6.985031336481872e-01, /* 24 */ + 7.058901198817004e-01, /* 25 */ + 7.129873445895255e-01, /* 26 */ + 7.198166846679294e-01, /* 27 */ + 7.263976293276093e-01, /* 28 */ + 7.327476153929163e-01, /* 29 */ + 7.388823057348773e-01, /* 30 */ + 7.448158220326316e-01, /* 31 */ + 7.505609405683121e-01, /* 32 */ + 7.561292578841378e-01, /* 33 */ + 7.615313317026243e-01, /* 34 */ + 7.667768014142995e-01, /* 35 */ + 7.718744915880543e-01, /* 36 */ + 7.768325012962659e-01, /* 37 */ + 7.816582815253555e-01, /* 38 */ + 7.863587025293927e-01, /* 39 */ + 7.909401126550023e-01, /* 40 */ + 7.954083899015745e-01, /* 41 */ + 7.997689872674765e-01, /* 42 */ + 8.040269727598457e-01, /* 43 */ + 8.081870648042627e-01, /* 44 */ + 8.122536636747445e-01, /* 45 */ + 8.162308794690072e-01, /* 46 */ + 8.201225570749002e-01, /* 47 */ + 8.239322985081793e-01, /* 48 */ + 8.276634829468987e-01, /* 49 */ + 8.313192847416925e-01, /* 50 */ + 8.349026896424915e-01, /* 51 */ + 8.384165094495176e-01, /* 52 */ + 8.418633952686800e-01, /* 53 */ + 8.452458495279215e-01, /* 54 */ + 8.485662368909529e-01, /* 55 */ + 8.518267941876015e-01, /* 56 */ + 8.550296394652227e-01, /* 57 */ + 8.581767802529086e-01, /* 58 */ + 8.612701211192447e-01, /* 59 */ + 8.643114705948695e-01, /* 60 */ + 8.673025475228375e-01, /* 61 */ + 8.702449868926238e-01, /* 62 */ + 8.731403452073437e-01, /* 63 */ + 8.759901054283044e-01, /* 64 */ + 8.787956815362078e-01, /* 65 */ + 8.815584227441299e-01, /* 66 */ + 8.842796173936956e-01, /* 67 */ + 8.869604965626164e-01, /* 68 */ + 8.896022374088743e-01, /* 69 */ + 8.922059662742917e-01, /* 70 */ + 8.947727615679660e-01, /* 71 */ + 8.973036564480465e-01, /* 72 */ + 8.997996413185413e-01, /* 73 */ + 9.022616661562580e-01, /* 74 */ + 9.046906426815596e-01, /* 75 */ + 9.070874463853477e-01, /* 76 */ + 9.094529184235521e-01, /* 77 */ + 9.117878673893848e-01, /* 78 */ + 9.140930709727019e-01, /* 79 */ + 9.163692775149945e-01, /* 80 */ + 9.186172074677887e-01, /* 81 */ + 9.208375547615666e-01, /* 82 */ + 9.230309880917155e-01, /* 83 */ + 9.251981521274687e-01, /* 84 */ + 9.273396686493066e-01, /* 85 */ + 9.294561376198379e-01, /* 86 */ + 9.315481381927757e-01, /* 87 */ + 9.336162296642549e-01, /* 88 */ + 9.356609523703983e-01, /* 89 */ + 9.376828285347367e-01, /* 90 */ + 9.396823630688069e-01, /* 91 */ + 9.416600443289993e-01, /* 92 */ + 9.436163448324909e-01, /* 93 */ + 9.455517219348925e-01, /* 94 */ + 9.474666184720378e-01, /* 95 */ + 9.493614633681715e-01, /* 96 */ + 9.512366722126200e-01, /* 97 */ + 9.530926478068908e-01, /* 98 */ + 9.549297806839971e-01, /* 99 */ + 9.567484496016846e-01, /* 100 */ + 9.585490220111190e-01, /* 101 */ + 9.603318545024836e-01, /* 102 */ + 9.620972932288397e-01, /* 103 */ + 9.638456743095097e-01, /* 104 */ + 9.655773242141589e-01, /* 105 */ + 9.672925601286723e-01, /* 106 */ + 9.689916903038553e-01, /* 107 */ + 9.706750143879137e-01, /* 108 */ + 9.723428237436111e-01, /* 109 */ + 9.739954017509451e-01, /* 110 */ + 9.756330240961253e-01, /* 111 */ + 9.772559590475937e-01, /* 112 */ + 9.788644677197762e-01, /* 113 */ + 9.804588043252149e-01, /* 114 */ + 9.820392164156895e-01, /* 115 */ + 9.836059451129007e-01, /* 116 */ + 9.851592253292520e-01, /* 117 */ + 9.866992859792368e-01, /* 118 */ + 9.882263501819057e-01, /* 119 */ + 9.897406354548617e-01, /* 120 */ + 9.912423539002055e-01, /* 121 */ + 9.927317123828298e-01, /* 122 */ + 9.942089127014337e-01, /* 123 */ + 9.956741517526159e-01, /* 124 */ + 9.971276216883748e-01, /* 125 */ + 9.985695100673359e-01, /* 126 */ + 1.000000000000000e+00, /* 127 */ +}; + +static const fluid_real_t fluid_pan_tab[1002] = { + 0.000000000000000e+00, /* 0 */ + 1.569226455665206e-03, /* 1 */ + 3.138449047152344e-03, /* 2 */ + 4.707663910292860e-03, /* 3 */ + 6.276867180937232e-03, /* 4 */ + 7.846054994964486e-03, /* 5 */ + 9.415223488291704e-03, /* 6 */ + 1.098436879688355e-02, /* 7 */ + 1.255348705676178e-02, /* 8 */ + 1.412257440401476e-02, /* 9 */ + 1.569162697480695e-02, /* 10 */ + 1.726064090538850e-02, /* 11 */ + 1.882961233210465e-02, /* 12 */ + 2.039853739140535e-02, /* 13 */ + 2.196741221985471e-02, /* 14 */ + 2.353623295414053e-02, /* 15 */ + 2.510499573108383e-02, /* 16 */ + 2.667369668764832e-02, /* 17 */ + 2.824233196094998e-02, /* 18 */ + 2.981089768826650e-02, /* 19 */ + 3.137939000704683e-02, /* 20 */ + 3.294780505492070e-02, /* 21 */ + 3.451613896970813e-02, /* 22 */ + 3.608438788942888e-02, /* 23 */ + 3.765254795231206e-02, /* 24 */ + 3.922061529680555e-02, /* 25 */ + 4.078858606158557e-02, /* 26 */ + 4.235645638556616e-02, /* 27 */ + 4.392422240790868e-02, /* 28 */ + 4.549188026803134e-02, /* 29 */ + 4.705942610561871e-02, /* 30 */ + 4.862685606063118e-02, /* 31 */ + 5.019416627331453e-02, /* 32 */ + 5.176135288420938e-02, /* 33 */ + 5.332841203416073e-02, /* 34 */ + 5.489533986432744e-02, /* 35 */ + 5.646213251619175e-02, /* 36 */ + 5.802878613156876e-02, /* 37 */ + 5.959529685261596e-02, /* 38 */ + 6.116166082184270e-02, /* 39 */ + 6.272787418211971e-02, /* 40 */ + 6.429393307668860e-02, /* 41 */ + 6.585983364917131e-02, /* 42 */ + 6.742557204357968e-02, /* 43 */ + 6.899114440432493e-02, /* 44 */ + 7.055654687622705e-02, /* 45 */ + 7.212177560452446e-02, /* 46 */ + 7.368682673488337e-02, /* 47 */ + 7.525169641340737e-02, /* 48 */ + 7.681638078664681e-02, /* 49 */ + 7.838087600160838e-02, /* 50 */ + 7.994517820576458e-02, /* 51 */ + 8.150928354706316e-02, /* 52 */ + 8.307318817393668e-02, /* 53 */ + 8.463688823531192e-02, /* 54 */ + 8.620037988061939e-02, /* 55 */ + 8.776365925980288e-02, /* 56 */ + 8.932672252332881e-02, /* 57 */ + 9.088956582219582e-02, /* 58 */ + 9.245218530794418e-02, /* 59 */ + 9.401457713266531e-02, /* 60 */ + 9.557673744901124e-02, /* 61 */ + 9.713866241020409e-02, /* 62 */ + 9.870034817004553e-02, /* 63 */ + 1.002617908829262e-01, /* 64 */ + 1.018229867038354e-01, /* 65 */ + 1.033839317883702e-01, /* 66 */ + 1.049446222927451e-01, /* 67 */ + 1.065050543738018e-01, /* 68 */ + 1.080652241890180e-01, /* 69 */ + 1.096251278965173e-01, /* 70 */ + 1.111847616550789e-01, /* 71 */ + 1.127441216241462e-01, /* 72 */ + 1.143032039638373e-01, /* 73 */ + 1.158620048349536e-01, /* 74 */ + 1.174205203989899e-01, /* 75 */ + 1.189787468181433e-01, /* 76 */ + 1.205366802553230e-01, /* 77 */ + 1.220943168741599e-01, /* 78 */ + 1.236516528390153e-01, /* 79 */ + 1.252086843149914e-01, /* 80 */ + 1.267654074679397e-01, /* 81 */ + 1.283218184644714e-01, /* 82 */ + 1.298779134719661e-01, /* 83 */ + 1.314336886585815e-01, /* 84 */ + 1.329891401932629e-01, /* 85 */ + 1.345442642457527e-01, /* 86 */ + 1.360990569865997e-01, /* 87 */ + 1.376535145871682e-01, /* 88 */ + 1.392076332196483e-01, /* 89 */ + 1.407614090570644e-01, /* 90 */ + 1.423148382732851e-01, /* 91 */ + 1.438679170430328e-01, /* 92 */ + 1.454206415418926e-01, /* 93 */ + 1.469730079463220e-01, /* 94 */ + 1.485250124336605e-01, /* 95 */ + 1.500766511821384e-01, /* 96 */ + 1.516279203708872e-01, /* 97 */ + 1.531788161799479e-01, /* 98 */ + 1.547293347902812e-01, /* 99 */ + 1.562794723837767e-01, /* 100 */ + 1.578292251432621e-01, /* 101 */ + 1.593785892525127e-01, /* 102 */ + 1.609275608962610e-01, /* 103 */ + 1.624761362602058e-01, /* 104 */ + 1.640243115310219e-01, /* 105 */ + 1.655720828963691e-01, /* 106 */ + 1.671194465449020e-01, /* 107 */ + 1.686663986662791e-01, /* 108 */ + 1.702129354511722e-01, /* 109 */ + 1.717590530912760e-01, /* 110 */ + 1.733047477793173e-01, /* 111 */ + 1.748500157090643e-01, /* 112 */ + 1.763948530753363e-01, /* 113 */ + 1.779392560740125e-01, /* 114 */ + 1.794832209020421e-01, /* 115 */ + 1.810267437574530e-01, /* 116 */ + 1.825698208393617e-01, /* 117 */ + 1.841124483479821e-01, /* 118 */ + 1.856546224846354e-01, /* 119 */ + 1.871963394517592e-01, /* 120 */ + 1.887375954529167e-01, /* 121 */ + 1.902783866928064e-01, /* 122 */ + 1.918187093772711e-01, /* 123 */ + 1.933585597133076e-01, /* 124 */ + 1.948979339090757e-01, /* 125 */ + 1.964368281739078e-01, /* 126 */ + 1.979752387183178e-01, /* 127 */ + 1.995131617540112e-01, /* 128 */ + 2.010505934938938e-01, /* 129 */ + 2.025875301520809e-01, /* 130 */ + 2.041239679439075e-01, /* 131 */ + 2.056599030859366e-01, /* 132 */ + 2.071953317959691e-01, /* 133 */ + 2.087302502930529e-01, /* 134 */ + 2.102646547974925e-01, /* 135 */ + 2.117985415308578e-01, /* 136 */ + 2.133319067159940e-01, /* 137 */ + 2.148647465770304e-01, /* 138 */ + 2.163970573393899e-01, /* 139 */ + 2.179288352297983e-01, /* 140 */ + 2.194600764762938e-01, /* 141 */ + 2.209907773082357e-01, /* 142 */ + 2.225209339563144e-01, /* 143 */ + 2.240505426525601e-01, /* 144 */ + 2.255795996303523e-01, /* 145 */ + 2.271081011244294e-01, /* 146 */ + 2.286360433708974e-01, /* 147 */ + 2.301634226072393e-01, /* 148 */ + 2.316902350723250e-01, /* 149 */ + 2.332164770064195e-01, /* 150 */ + 2.347421446511931e-01, /* 151 */ + 2.362672342497300e-01, /* 152 */ + 2.377917420465381e-01, /* 153 */ + 2.393156642875578e-01, /* 154 */ + 2.408389972201713e-01, /* 155 */ + 2.423617370932123e-01, /* 156 */ + 2.438838801569746e-01, /* 157 */ + 2.454054226632218e-01, /* 158 */ + 2.469263608651961e-01, /* 159 */ + 2.484466910176281e-01, /* 160 */ + 2.499664093767456e-01, /* 161 */ + 2.514855122002828e-01, /* 162 */ + 2.530039957474898e-01, /* 163 */ + 2.545218562791415e-01, /* 164 */ + 2.560390900575471e-01, /* 165 */ + 2.575556933465591e-01, /* 166 */ + 2.590716624115826e-01, /* 167 */ + 2.605869935195844e-01, /* 168 */ + 2.621016829391022e-01, /* 169 */ + 2.636157269402540e-01, /* 170 */ + 2.651291217947471e-01, /* 171 */ + 2.666418637758871e-01, /* 172 */ + 2.681539491585876e-01, /* 173 */ + 2.696653742193788e-01, /* 174 */ + 2.711761352364170e-01, /* 175 */ + 2.726862284894938e-01, /* 176 */ + 2.741956502600449e-01, /* 177 */ + 2.757043968311598e-01, /* 178 */ + 2.772124644875906e-01, /* 179 */ + 2.787198495157609e-01, /* 180 */ + 2.802265482037756e-01, /* 181 */ + 2.817325568414297e-01, /* 182 */ + 2.832378717202171e-01, /* 183 */ + 2.847424891333405e-01, /* 184 */ + 2.862464053757197e-01, /* 185 */ + 2.877496167440013e-01, /* 186 */ + 2.892521195365677e-01, /* 187 */ + 2.907539100535459e-01, /* 188 */ + 2.922549845968172e-01, /* 189 */ + 2.937553394700257e-01, /* 190 */ + 2.952549709785878e-01, /* 191 */ + 2.967538754297011e-01, /* 192 */ + 2.982520491323535e-01, /* 193 */ + 2.997494883973326e-01, /* 194 */ + 3.012461895372343e-01, /* 195 */ + 3.027421488664720e-01, /* 196 */ + 3.042373627012863e-01, /* 197 */ + 3.057318273597529e-01, /* 198 */ + 3.072255391617928e-01, /* 199 */ + 3.087184944291808e-01, /* 200 */ + 3.102106894855545e-01, /* 201 */ + 3.117021206564237e-01, /* 202 */ + 3.131927842691789e-01, /* 203 */ + 3.146826766531011e-01, /* 204 */ + 3.161717941393703e-01, /* 205 */ + 3.176601330610745e-01, /* 206 */ + 3.191476897532191e-01, /* 207 */ + 3.206344605527355e-01, /* 208 */ + 3.221204417984906e-01, /* 209 */ + 3.236056298312954e-01, /* 210 */ + 3.250900209939143e-01, /* 211 */ + 3.265736116310736e-01, /* 212 */ + 3.280563980894714e-01, /* 213 */ + 3.295383767177856e-01, /* 214 */ + 3.310195438666838e-01, /* 215 */ + 3.324998958888314e-01, /* 216 */ + 3.339794291389013e-01, /* 217 */ + 3.354581399735826e-01, /* 218 */ + 3.369360247515896e-01, /* 219 */ + 3.384130798336704e-01, /* 220 */ + 3.398893015826167e-01, /* 221 */ + 3.413646863632719e-01, /* 222 */ + 3.428392305425407e-01, /* 223 */ + 3.443129304893974e-01, /* 224 */ + 3.457857825748955e-01, /* 225 */ + 3.472577831721762e-01, /* 226 */ + 3.487289286564775e-01, /* 227 */ + 3.501992154051431e-01, /* 228 */ + 3.516686397976314e-01, /* 229 */ + 3.531371982155241e-01, /* 230 */ + 3.546048870425356e-01, /* 231 */ + 3.560717026645214e-01, /* 232 */ + 3.575376414694875e-01, /* 233 */ + 3.590026998475987e-01, /* 234 */ + 3.604668741911882e-01, /* 235 */ + 3.619301608947658e-01, /* 236 */ + 3.633925563550274e-01, /* 237 */ + 3.648540569708633e-01, /* 238 */ + 3.663146591433675e-01, /* 239 */ + 3.677743592758461e-01, /* 240 */ + 3.692331537738269e-01, /* 241 */ + 3.706910390450675e-01, /* 242 */ + 3.721480114995644e-01, /* 243 */ + 3.736040675495622e-01, /* 244 */ + 3.750592036095618e-01, /* 245 */ + 3.765134160963297e-01, /* 246 */ + 3.779667014289065e-01, /* 247 */ + 3.794190560286163e-01, /* 248 */ + 3.808704763190747e-01, /* 249 */ + 3.823209587261981e-01, /* 250 */ + 3.837704996782126e-01, /* 251 */ + 3.852190956056624e-01, /* 252 */ + 3.866667429414188e-01, /* 253 */ + 3.881134381206892e-01, /* 254 */ + 3.895591775810255e-01, /* 255 */ + 3.910039577623329e-01, /* 256 */ + 3.924477751068791e-01, /* 257 */ + 3.938906260593025e-01, /* 258 */ + 3.953325070666214e-01, /* 259 */ + 3.967734145782425e-01, /* 260 */ + 3.982133450459696e-01, /* 261 */ + 3.996522949240126e-01, /* 262 */ + 4.010902606689959e-01, /* 263 */ + 4.025272387399675e-01, /* 264 */ + 4.039632255984075e-01, /* 265 */ + 4.053982177082366e-01, /* 266 */ + 4.068322115358254e-01, /* 267 */ + 4.082652035500025e-01, /* 268 */ + 4.096971902220634e-01, /* 269 */ + 4.111281680257793e-01, /* 270 */ + 4.125581334374058e-01, /* 271 */ + 4.139870829356915e-01, /* 272 */ + 4.154150130018864e-01, /* 273 */ + 4.168419201197511e-01, /* 274 */ + 4.182678007755651e-01, /* 275 */ + 4.196926514581356e-01, /* 276 */ + 4.211164686588058e-01, /* 277 */ + 4.225392488714641e-01, /* 278 */ + 4.239609885925524e-01, /* 279 */ + 4.253816843210749e-01, /* 280 */ + 4.268013325586062e-01, /* 281 */ + 4.282199298093007e-01, /* 282 */ + 4.296374725799008e-01, /* 283 */ + 4.310539573797453e-01, /* 284 */ + 4.324693807207784e-01, /* 285 */ + 4.338837391175581e-01, /* 286 */ + 4.352970290872648e-01, /* 287 */ + 4.367092471497098e-01, /* 288 */ + 4.381203898273440e-01, /* 289 */ + 4.395304536452664e-01, /* 290 */ + 4.409394351312327e-01, /* 291 */ + 4.423473308156637e-01, /* 292 */ + 4.437541372316541e-01, /* 293 */ + 4.451598509149808e-01, /* 294 */ + 4.465644684041115e-01, /* 295 */ + 4.479679862402133e-01, /* 296 */ + 4.493704009671613e-01, /* 297 */ + 4.507717091315467e-01, /* 298 */ + 4.521719072826857e-01, /* 299 */ + 4.535709919726280e-01, /* 300 */ + 4.549689597561650e-01, /* 301 */ + 4.563658071908386e-01, /* 302 */ + 4.577615308369494e-01, /* 303 */ + 4.591561272575653e-01, /* 304 */ + 4.605495930185300e-01, /* 305 */ + 4.619419246884716e-01, /* 306 */ + 4.633331188388105e-01, /* 307 */ + 4.647231720437685e-01, /* 308 */ + 4.661120808803769e-01, /* 309 */ + 4.674998419284848e-01, /* 310 */ + 4.688864517707680e-01, /* 311 */ + 4.702719069927368e-01, /* 312 */ + 4.716562041827449e-01, /* 313 */ + 4.730393399319976e-01, /* 314 */ + 4.744213108345603e-01, /* 315 */ + 4.758021134873666e-01, /* 316 */ + 4.771817444902270e-01, /* 317 */ + 4.785602004458372e-01, /* 318 */ + 4.799374779597863e-01, /* 319 */ + 4.813135736405654e-01, /* 320 */ + 4.826884840995759e-01, /* 321 */ + 4.840622059511374e-01, /* 322 */ + 4.854347358124969e-01, /* 323 */ + 4.868060703038363e-01, /* 324 */ + 4.881762060482813e-01, /* 325 */ + 4.895451396719092e-01, /* 326 */ + 4.909128678037579e-01, /* 327 */ + 4.922793870758333e-01, /* 328 */ + 4.936446941231185e-01, /* 329 */ + 4.950087855835814e-01, /* 330 */ + 4.963716580981834e-01, /* 331 */ + 4.977333083108875e-01, /* 332 */ + 4.990937328686666e-01, /* 333 */ + 5.004529284215117e-01, /* 334 */ + 5.018108916224401e-01, /* 335 */ + 5.031676191275039e-01, /* 336 */ + 5.045231075957979e-01, /* 337 */ + 5.058773536894682e-01, /* 338 */ + 5.072303540737202e-01, /* 339 */ + 5.085821054168265e-01, /* 340 */ + 5.099326043901359e-01, /* 341 */ + 5.112818476680807e-01, /* 342 */ + 5.126298319281856e-01, /* 343 */ + 5.139765538510755e-01, /* 344 */ + 5.153220101204837e-01, /* 345 */ + 5.166661974232605e-01, /* 346 */ + 5.180091124493803e-01, /* 347 */ + 5.193507518919511e-01, /* 348 */ + 5.206911124472217e-01, /* 349 */ + 5.220301908145902e-01, /* 350 */ + 5.233679836966120e-01, /* 351 */ + 5.247044877990080e-01, /* 352 */ + 5.260396998306727e-01, /* 353 */ + 5.273736165036822e-01, /* 354 */ + 5.287062345333027e-01, /* 355 */ + 5.300375506379977e-01, /* 356 */ + 5.313675615394372e-01, /* 357 */ + 5.326962639625050e-01, /* 358 */ + 5.340236546353070e-01, /* 359 */ + 5.353497302891792e-01, /* 360 */ + 5.366744876586959e-01, /* 361 */ + 5.379979234816776e-01, /* 362 */ + 5.393200344991992e-01, /* 363 */ + 5.406408174555976e-01, /* 364 */ + 5.419602690984802e-01, /* 365 */ + 5.432783861787328e-01, /* 366 */ + 5.445951654505273e-01, /* 367 */ + 5.459106036713303e-01, /* 368 */ + 5.472246976019102e-01, /* 369 */ + 5.485374440063460e-01, /* 370 */ + 5.498488396520349e-01, /* 371 */ + 5.511588813097004e-01, /* 372 */ + 5.524675657533998e-01, /* 373 */ + 5.537748897605330e-01, /* 374 */ + 5.550808501118496e-01, /* 375 */ + 5.563854435914573e-01, /* 376 */ + 5.576886669868294e-01, /* 377 */ + 5.589905170888135e-01, /* 378 */ + 5.602909906916385e-01, /* 379 */ + 5.615900845929231e-01, /* 380 */ + 5.628877955936834e-01, /* 381 */ + 5.641841204983408e-01, /* 382 */ + 5.654790561147299e-01, /* 383 */ + 5.667725992541067e-01, /* 384 */ + 5.680647467311558e-01, /* 385 */ + 5.693554953639987e-01, /* 386 */ + 5.706448419742013e-01, /* 387 */ + 5.719327833867824e-01, /* 388 */ + 5.732193164302208e-01, /* 389 */ + 5.745044379364633e-01, /* 390 */ + 5.757881447409327e-01, /* 391 */ + 5.770704336825352e-01, /* 392 */ + 5.783513016036690e-01, /* 393 */ + 5.796307453502310e-01, /* 394 */ + 5.809087617716252e-01, /* 395 */ + 5.821853477207707e-01, /* 396 */ + 5.834605000541085e-01, /* 397 */ + 5.847342156316105e-01, /* 398 */ + 5.860064913167862e-01, /* 399 */ + 5.872773239766905e-01, /* 400 */ + 5.885467104819324e-01, /* 401 */ + 5.898146477066816e-01, /* 402 */ + 5.910811325286766e-01, /* 403 */ + 5.923461618292324e-01, /* 404 */ + 5.936097324932486e-01, /* 405 */ + 5.948718414092160e-01, /* 406 */ + 5.961324854692254e-01, /* 407 */ + 5.973916615689745e-01, /* 408 */ + 5.986493666077760e-01, /* 409 */ + 5.999055974885650e-01, /* 410 */ + 6.011603511179066e-01, /* 411 */ + 6.024136244060035e-01, /* 412 */ + 6.036654142667041e-01, /* 413 */ + 6.049157176175093e-01, /* 414 */ + 6.061645313795805e-01, /* 415 */ + 6.074118524777475e-01, /* 416 */ + 6.086576778405154e-01, /* 417 */ + 6.099020044000728e-01, /* 418 */ + 6.111448290922987e-01, /* 419 */ + 6.123861488567709e-01, /* 420 */ + 6.136259606367725e-01, /* 421 */ + 6.148642613793004e-01, /* 422 */ + 6.161010480350722e-01, /* 423 */ + 6.173363175585338e-01, /* 424 */ + 6.185700669078673e-01, /* 425 */ + 6.198022930449979e-01, /* 426 */ + 6.210329929356019e-01, /* 427 */ + 6.222621635491136e-01, /* 428 */ + 6.234898018587335e-01, /* 429 */ + 6.247159048414351e-01, /* 430 */ + 6.259404694779729e-01, /* 431 */ + 6.271634927528890e-01, /* 432 */ + 6.283849716545215e-01, /* 433 */ + 6.296049031750114e-01, /* 434 */ + 6.308232843103100e-01, /* 435 */ + 6.320401120601865e-01, /* 436 */ + 6.332553834282351e-01, /* 437 */ + 6.344690954218827e-01, /* 438 */ + 6.356812450523961e-01, /* 439 */ + 6.368918293348892e-01, /* 440 */ + 6.381008452883308e-01, /* 441 */ + 6.393082899355514e-01, /* 442 */ + 6.405141603032511e-01, /* 443 */ + 6.417184534220064e-01, /* 444 */ + 6.429211663262777e-01, /* 445 */ + 6.441222960544168e-01, /* 446 */ + 6.453218396486741e-01, /* 447 */ + 6.465197941552053e-01, /* 448 */ + 6.477161566240798e-01, /* 449 */ + 6.489109241092871e-01, /* 450 */ + 6.501040936687442e-01, /* 451 */ + 6.512956623643031e-01, /* 452 */ + 6.524856272617580e-01, /* 453 */ + 6.536739854308520e-01, /* 454 */ + 6.548607339452850e-01, /* 455 */ + 6.560458698827208e-01, /* 456 */ + 6.572293903247938e-01, /* 457 */ + 6.584112923571166e-01, /* 458 */ + 6.595915730692873e-01, /* 459 */ + 6.607702295548961e-01, /* 460 */ + 6.619472589115332e-01, /* 461 */ + 6.631226582407952e-01, /* 462 */ + 6.642964246482929e-01, /* 463 */ + 6.654685552436579e-01, /* 464 */ + 6.666390471405501e-01, /* 465 */ + 6.678078974566646e-01, /* 466 */ + 6.689751033137388e-01, /* 467 */ + 6.701406618375595e-01, /* 468 */ + 6.713045701579703e-01, /* 469 */ + 6.724668254088779e-01, /* 470 */ + 6.736274247282602e-01, /* 471 */ + 6.747863652581724e-01, /* 472 */ + 6.759436441447543e-01, /* 473 */ + 6.770992585382379e-01, /* 474 */ + 6.782532055929538e-01, /* 475 */ + 6.794054824673382e-01, /* 476 */ + 6.805560863239402e-01, /* 477 */ + 6.817050143294286e-01, /* 478 */ + 6.828522636545991e-01, /* 479 */ + 6.839978314743810e-01, /* 480 */ + 6.851417149678442e-01, /* 481 */ + 6.862839113182062e-01, /* 482 */ + 6.874244177128394e-01, /* 483 */ + 6.885632313432770e-01, /* 484 */ + 6.897003494052213e-01, /* 485 */ + 6.908357690985494e-01, /* 486 */ + 6.919694876273208e-01, /* 487 */ + 6.931015021997841e-01, /* 488 */ + 6.942318100283835e-01, /* 489 */ + 6.953604083297665e-01, /* 490 */ + 6.964872943247901e-01, /* 491 */ + 6.976124652385276e-01, /* 492 */ + 6.987359183002758e-01, /* 493 */ + 6.998576507435618e-01, /* 494 */ + 7.009776598061495e-01, /* 495 */ + 7.020959427300464e-01, /* 496 */ + 7.032124967615111e-01, /* 497 */ + 7.043273191510590e-01, /* 498 */ + 7.054404071534700e-01, /* 499 */ + 7.065517580277947e-01, /* 500 */ + 7.076613690373614e-01, /* 501 */ + 7.087692374497827e-01, /* 502 */ + 7.098753605369623e-01, /* 503 */ + 7.109797355751019e-01, /* 504 */ + 7.120823598447074e-01, /* 505 */ + 7.131832306305962e-01, /* 506 */ + 7.142823452219036e-01, /* 507 */ + 7.153797009120892e-01, /* 508 */ + 7.164752949989442e-01, /* 509 */ + 7.175691247845974e-01, /* 510 */ + 7.186611875755224e-01, /* 511 */ + 7.197514806825439e-01, /* 512 */ + 7.208400014208443e-01, /* 513 */ + 7.219267471099703e-01, /* 514 */ + 7.230117150738400e-01, /* 515 */ + 7.240949026407488e-01, /* 516 */ + 7.251763071433764e-01, /* 517 */ + 7.262559259187933e-01, /* 518 */ + 7.273337563084670e-01, /* 519 */ + 7.284097956582691e-01, /* 520 */ + 7.294840413184817e-01, /* 521 */ + 7.305564906438036e-01, /* 522 */ + 7.316271409933570e-01, /* 523 */ + 7.326959897306943e-01, /* 524 */ + 7.337630342238040e-01, /* 525 */ + 7.348282718451178e-01, /* 526 */ + 7.358916999715164e-01, /* 527 */ + 7.369533159843368e-01, /* 528 */ + 7.380131172693778e-01, /* 529 */ + 7.390711012169073e-01, /* 530 */ + 7.401272652216682e-01, /* 531 */ + 7.411816066828849e-01, /* 532 */ + 7.422341230042699e-01, /* 533 */ + 7.432848115940299e-01, /* 534 */ + 7.443336698648725e-01, /* 535 */ + 7.453806952340122e-01, /* 536 */ + 7.464258851231773e-01, /* 537 */ + 7.474692369586156e-01, /* 538 */ + 7.485107481711011e-01, /* 539 */ + 7.495504161959405e-01, /* 540 */ + 7.505882384729792e-01, /* 541 */ + 7.516242124466075e-01, /* 542 */ + 7.526583355657674e-01, /* 543 */ + 7.536906052839586e-01, /* 544 */ + 7.547210190592443e-01, /* 545 */ + 7.557495743542583e-01, /* 546 */ + 7.567762686362108e-01, /* 547 */ + 7.578010993768947e-01, /* 548 */ + 7.588240640526916e-01, /* 549 */ + 7.598451601445788e-01, /* 550 */ + 7.608643851381341e-01, /* 551 */ + 7.618817365235437e-01, /* 552 */ + 7.628972117956068e-01, /* 553 */ + 7.639108084537428e-01, /* 554 */ + 7.649225240019972e-01, /* 555 */ + 7.659323559490476e-01, /* 556 */ + 7.669403018082099e-01, /* 557 */ + 7.679463590974444e-01, /* 558 */ + 7.689505253393620e-01, /* 559 */ + 7.699527980612303e-01, /* 560 */ + 7.709531747949796e-01, /* 561 */ + 7.719516530772089e-01, /* 562 */ + 7.729482304491924e-01, /* 563 */ + 7.739429044568850e-01, /* 564 */ + 7.749356726509284e-01, /* 565 */ + 7.759265325866578e-01, /* 566 */ + 7.769154818241071e-01, /* 567 */ + 7.779025179280153e-01, /* 568 */ + 7.788876384678325e-01, /* 569 */ + 7.798708410177257e-01, /* 570 */ + 7.808521231565851e-01, /* 571 */ + 7.818314824680298e-01, /* 572 */ + 7.828089165404135e-01, /* 573 */ + 7.837844229668313e-01, /* 574 */ + 7.847579993451246e-01, /* 575 */ + 7.857296432778876e-01, /* 576 */ + 7.866993523724733e-01, /* 577 */ + 7.876671242409992e-01, /* 578 */ + 7.886329565003528e-01, /* 579 */ + 7.895968467721981e-01, /* 580 */ + 7.905587926829811e-01, /* 581 */ + 7.915187918639360e-01, /* 582 */ + 7.924768419510904e-01, /* 583 */ + 7.934329405852717e-01, /* 584 */ + 7.943870854121126e-01, /* 585 */ + 7.953392740820571e-01, /* 586 */ + 7.962895042503660e-01, /* 587 */ + 7.972377735771232e-01, /* 588 */ + 7.981840797272409e-01, /* 589 */ + 7.991284203704654e-01, /* 590 */ + 8.000707931813833e-01, /* 591 */ + 8.010111958394268e-01, /* 592 */ + 8.019496260288795e-01, /* 593 */ + 8.028860814388824e-01, /* 594 */ + 8.038205597634391e-01, /* 595 */ + 8.047530587014217e-01, /* 596 */ + 8.056835759565766e-01, /* 597 */ + 8.066121092375300e-01, /* 598 */ + 8.075386562577938e-01, /* 599 */ + 8.084632147357704e-01, /* 600 */ + 8.093857823947597e-01, /* 601 */ + 8.103063569629634e-01, /* 602 */ + 8.112249361734913e-01, /* 603 */ + 8.121415177643669e-01, /* 604 */ + 8.130560994785324e-01, /* 605 */ + 8.139686790638551e-01, /* 606 */ + 8.148792542731320e-01, /* 607 */ + 8.157878228640961e-01, /* 608 */ + 8.166943825994217e-01, /* 609 */ + 8.175989312467298e-01, /* 610 */ + 8.185014665785935e-01, /* 611 */ + 8.194019863725437e-01, /* 612 */ + 8.203004884110747e-01, /* 613 */ + 8.211969704816493e-01, /* 614 */ + 8.220914303767043e-01, /* 615 */ + 8.229838658936564e-01, /* 616 */ + 8.238742748349069e-01, /* 617 */ + 8.247626550078477e-01, /* 618 */ + 8.256490042248665e-01, /* 619 */ + 8.265333203033521e-01, /* 620 */ + 8.274156010656999e-01, /* 621 */ + 8.282958443393171e-01, /* 622 */ + 8.291740479566283e-01, /* 623 */ + 8.300502097550806e-01, /* 624 */ + 8.309243275771491e-01, /* 625 */ + 8.317963992703420e-01, /* 626 */ + 8.326664226872064e-01, /* 627 */ + 8.335343956853326e-01, /* 628 */ + 8.344003161273608e-01, /* 629 */ + 8.352641818809847e-01, /* 630 */ + 8.361259908189583e-01, /* 631 */ + 8.369857408191002e-01, /* 632 */ + 8.378434297642989e-01, /* 633 */ + 8.386990555425186e-01, /* 634 */ + 8.395526160468036e-01, /* 635 */ + 8.404041091752841e-01, /* 636 */ + 8.412535328311811e-01, /* 637 */ + 8.421008849228117e-01, /* 638 */ + 8.429461633635940e-01, /* 639 */ + 8.437893660720525e-01, /* 640 */ + 8.446304909718232e-01, /* 641 */ + 8.454695359916585e-01, /* 642 */ + 8.463064990654326e-01, /* 643 */ + 8.471413781321465e-01, /* 644 */ + 8.479741711359327e-01, /* 645 */ + 8.488048760260607e-01, /* 646 */ + 8.496334907569423e-01, /* 647 */ + 8.504600132881356e-01, /* 648 */ + 8.512844415843511e-01, /* 649 */ + 8.521067736154565e-01, /* 650 */ + 8.529270073564810e-01, /* 651 */ + 8.537451407876209e-01, /* 652 */ + 8.545611718942447e-01, /* 653 */ + 8.553750986668979e-01, /* 654 */ + 8.561869191013073e-01, /* 655 */ + 8.569966311983869e-01, /* 656 */ + 8.578042329642425e-01, /* 657 */ + 8.586097224101764e-01, /* 658 */ + 8.594130975526924e-01, /* 659 */ + 8.602143564135006e-01, /* 660 */ + 8.610134970195229e-01, /* 661 */ + 8.618105174028966e-01, /* 662 */ + 8.626054156009807e-01, /* 663 */ + 8.633981896563595e-01, /* 664 */ + 8.641888376168482e-01, /* 665 */ + 8.649773575354974e-01, /* 666 */ + 8.657637474705979e-01, /* 667 */ + 8.665480054856857e-01, /* 668 */ + 8.673301296495464e-01, /* 669 */ + 8.681101180362202e-01, /* 670 */ + 8.688879687250065e-01, /* 671 */ + 8.696636798004691e-01, /* 672 */ + 8.704372493524400e-01, /* 673 */ + 8.712086754760252e-01, /* 674 */ + 8.719779562716083e-01, /* 675 */ + 8.727450898448561e-01, /* 676 */ + 8.735100743067228e-01, /* 677 */ + 8.742729077734545e-01, /* 678 */ + 8.750335883665944e-01, /* 679 */ + 8.757921142129869e-01, /* 680 */ + 8.765484834447824e-01, /* 681 */ + 8.773026941994420e-01, /* 682 */ + 8.780547446197419e-01, /* 683 */ + 8.788046328537781e-01, /* 684 */ + 8.795523570549709e-01, /* 685 */ + 8.802979153820697e-01, /* 686 */ + 8.810413059991569e-01, /* 687 */ + 8.817825270756531e-01, /* 688 */ + 8.825215767863213e-01, /* 689 */ + 8.832584533112713e-01, /* 690 */ + 8.839931548359646e-01, /* 691 */ + 8.847256795512183e-01, /* 692 */ + 8.854560256532099e-01, /* 693 */ + 8.861841913434817e-01, /* 694 */ + 8.869101748289453e-01, /* 695 */ + 8.876339743218858e-01, /* 696 */ + 8.883555880399664e-01, /* 697 */ + 8.890750142062326e-01, /* 698 */ + 8.897922510491166e-01, /* 699 */ + 8.905072968024423e-01, /* 700 */ + 8.912201497054284e-01, /* 701 */ + 8.919308080026938e-01, /* 702 */ + 8.926392699442616e-01, /* 703 */ + 8.933455337855631e-01, /* 704 */ + 8.940495977874426e-01, /* 705 */ + 8.947514602161615e-01, /* 706 */ + 8.954511193434023e-01, /* 707 */ + 8.961485734462731e-01, /* 708 */ + 8.968438208073118e-01, /* 709 */ + 8.975368597144907e-01, /* 710 */ + 8.982276884612198e-01, /* 711 */ + 8.989163053463520e-01, /* 712 */ + 8.996027086741867e-01, /* 713 */ + 9.002868967544739e-01, /* 714 */ + 9.009688679024191e-01, /* 715 */ + 9.016486204386864e-01, /* 716 */ + 9.023261526894035e-01, /* 717 */ + 9.030014629861653e-01, /* 718 */ + 9.036745496660386e-01, /* 719 */ + 9.043454110715651e-01, /* 720 */ + 9.050140455507668e-01, /* 721 */ + 9.056804514571491e-01, /* 722 */ + 9.063446271497057e-01, /* 723 */ + 9.070065709929211e-01, /* 724 */ + 9.076662813567770e-01, /* 725 */ + 9.083237566167539e-01, /* 726 */ + 9.089789951538368e-01, /* 727 */ + 9.096319953545183e-01, /* 728 */ + 9.102827556108030e-01, /* 729 */ + 9.109312743202110e-01, /* 730 */ + 9.115775498857827e-01, /* 731 */ + 9.122215807160815e-01, /* 732 */ + 9.128633652251990e-01, /* 733 */ + 9.135029018327580e-01, /* 734 */ + 9.141401889639166e-01, /* 735 */ + 9.147752250493725e-01, /* 736 */ + 9.154080085253663e-01, /* 737 */ + 9.160385378336857e-01, /* 738 */ + 9.166668114216692e-01, /* 739 */ + 9.172928277422099e-01, /* 740 */ + 9.179165852537593e-01, /* 741 */ + 9.185380824203315e-01, /* 742 */ + 9.191573177115061e-01, /* 743 */ + 9.197742896024330e-01, /* 744 */ + 9.203889965738354e-01, /* 745 */ + 9.210014371120140e-01, /* 746 */ + 9.216116097088501e-01, /* 747 */ + 9.222195128618103e-01, /* 748 */ + 9.228251450739493e-01, /* 749 */ + 9.234285048539139e-01, /* 750 */ + 9.240295907159470e-01, /* 751 */ + 9.246284011798909e-01, /* 752 */ + 9.252249347711905e-01, /* 753 */ + 9.258191900208981e-01, /* 754 */ + 9.264111654656760e-01, /* 755 */ + 9.270008596478005e-01, /* 756 */ + 9.275882711151657e-01, /* 757 */ + 9.281733984212863e-01, /* 758 */ + 9.287562401253023e-01, /* 759 */ + 9.293367947919815e-01, /* 760 */ + 9.299150609917235e-01, /* 761 */ + 9.304910373005634e-01, /* 762 */ + 9.310647223001750e-01, /* 763 */ + 9.316361145778743e-01, /* 764 */ + 9.322052127266233e-01, /* 765 */ + 9.327720153450327e-01, /* 766 */ + 9.333365210373668e-01, /* 767 */ + 9.338987284135449e-01, /* 768 */ + 9.344586360891468e-01, /* 769 */ + 9.350162426854148e-01, /* 770 */ + 9.355715468292575e-01, /* 771 */ + 9.361245471532534e-01, /* 772 */ + 9.366752422956540e-01, /* 773 */ + 9.372236309003873e-01, /* 774 */ + 9.377697116170610e-01, /* 775 */ + 9.383134831009662e-01, /* 776 */ + 9.388549440130799e-01, /* 777 */ + 9.393940930200693e-01, /* 778 */ + 9.399309287942944e-01, /* 779 */ + 9.404654500138115e-01, /* 780 */ + 9.409976553623765e-01, /* 781 */ + 9.415275435294478e-01, /* 782 */ + 9.420551132101902e-01, /* 783 */ + 9.425803631054773e-01, /* 784 */ + 9.431032919218956e-01, /* 785 */ + 9.436238983717468e-01, /* 786 */ + 9.441421811730513e-01, /* 787 */ + 9.446581390495518e-01, /* 788 */ + 9.451717707307158e-01, /* 789 */ + 9.456830749517390e-01, /* 790 */ + 9.461920504535486e-01, /* 791 */ + 9.466986959828059e-01, /* 792 */ + 9.472030102919100e-01, /* 793 */ + 9.477049921390005e-01, /* 794 */ + 9.482046402879605e-01, /* 795 */ + 9.487019535084197e-01, /* 796 */ + 9.491969305757577e-01, /* 797 */ + 9.496895702711068e-01, /* 798 */ + 9.501798713813550e-01, /* 799 */ + 9.506678326991488e-01, /* 800 */ + 9.511534530228968e-01, /* 801 */ + 9.516367311567716e-01, /* 802 */ + 9.521176659107141e-01, /* 803 */ + 9.525962561004352e-01, /* 804 */ + 9.530725005474194e-01, /* 805 */ + 9.535463980789276e-01, /* 806 */ + 9.540179475279997e-01, /* 807 */ + 9.544871477334580e-01, /* 808 */ + 9.549539975399095e-01, /* 809 */ + 9.554184957977490e-01, /* 810 */ + 9.558806413631620e-01, /* 811 */ + 9.563404330981276e-01, /* 812 */ + 9.567978698704207e-01, /* 813 */ + 9.572529505536158e-01, /* 814 */ + 9.577056740270887e-01, /* 815 */ + 9.581560391760202e-01, /* 816 */ + 9.586040448913981e-01, /* 817 */ + 9.590496900700202e-01, /* 818 */ + 9.594929736144974e-01, /* 819 */ + 9.599338944332557e-01, /* 820 */ + 9.603724514405396e-01, /* 821 */ + 9.608086435564140e-01, /* 822 */ + 9.612424697067677e-01, /* 823 */ + 9.616739288233154e-01, /* 824 */ + 9.621030198436005e-01, /* 825 */ + 9.625297417109979e-01, /* 826 */ + 9.629540933747166e-01, /* 827 */ + 9.633760737898017e-01, /* 828 */ + 9.637956819171380e-01, /* 829 */ + 9.642129167234518e-01, /* 830 */ + 9.646277771813133e-01, /* 831 */ + 9.650402622691399e-01, /* 832 */ + 9.654503709711981e-01, /* 833 */ + 9.658581022776063e-01, /* 834 */ + 9.662634551843370e-01, /* 835 */ + 9.666664286932195e-01, /* 836 */ + 9.670670218119425e-01, /* 837 */ + 9.674652335540560e-01, /* 838 */ + 9.678610629389744e-01, /* 839 */ + 9.682545089919784e-01, /* 840 */ + 9.686455707442176e-01, /* 841 */ + 9.690342472327130e-01, /* 842 */ + 9.694205375003593e-01, /* 843 */ + 9.698044405959267e-01, /* 844 */ + 9.701859555740645e-01, /* 845 */ + 9.705650814953021e-01, /* 846 */ + 9.709418174260520e-01, /* 847 */ + 9.713161624386123e-01, /* 848 */ + 9.716881156111683e-01, /* 849 */ + 9.720576760277954e-01, /* 850 */ + 9.724248427784608e-01, /* 851 */ + 9.727896149590264e-01, /* 852 */ + 9.731519916712503e-01, /* 853 */ + 9.735119720227898e-01, /* 854 */ + 9.738695551272029e-01, /* 855 */ + 9.742247401039505e-01, /* 856 */ + 9.745775260783994e-01, /* 857 */ + 9.749279121818236e-01, /* 858 */ + 9.752758975514066e-01, /* 859 */ + 9.756214813302438e-01, /* 860 */ + 9.759646626673444e-01, /* 861 */ + 9.763054407176336e-01, /* 862 */ + 9.766438146419546e-01, /* 863 */ + 9.769797836070706e-01, /* 864 */ + 9.773133467856671e-01, /* 865 */ + 9.776445033563537e-01, /* 866 */ + 9.779732525036661e-01, /* 867 */ + 9.782995934180686e-01, /* 868 */ + 9.786235252959552e-01, /* 869 */ + 9.789450473396526e-01, /* 870 */ + 9.792641587574211e-01, /* 871 */ + 9.795808587634576e-01, /* 872 */ + 9.798951465778968e-01, /* 873 */ + 9.802070214268133e-01, /* 874 */ + 9.805164825422236e-01, /* 875 */ + 9.808235291620881e-01, /* 876 */ + 9.811281605303128e-01, /* 877 */ + 9.814303758967510e-01, /* 878 */ + 9.817301745172056e-01, /* 879 */ + 9.820275556534303e-01, /* 880 */ + 9.823225185731322e-01, /* 881 */ + 9.826150625499731e-01, /* 882 */ + 9.829051868635711e-01, /* 883 */ + 9.831928907995030e-01, /* 884 */ + 9.834781736493055e-01, /* 885 */ + 9.837610347104772e-01, /* 886 */ + 9.840414732864804e-01, /* 887 */ + 9.843194886867427e-01, /* 888 */ + 9.845950802266584e-01, /* 889 */ + 9.848682472275909e-01, /* 890 */ + 9.851389890168738e-01, /* 891 */ + 9.854073049278126e-01, /* 892 */ + 9.856731942996866e-01, /* 893 */ + 9.859366564777504e-01, /* 894 */ + 9.861976908132354e-01, /* 895 */ + 9.864562966633516e-01, /* 896 */ + 9.867124733912889e-01, /* 897 */ + 9.869662203662192e-01, /* 898 */ + 9.872175369632971e-01, /* 899 */ + 9.874664225636623e-01, /* 900 */ + 9.877128765544410e-01, /* 901 */ + 9.879568983287464e-01, /* 902 */ + 9.881984872856817e-01, /* 903 */ + 9.884376428303405e-01, /* 904 */ + 9.886743643738087e-01, /* 905 */ + 9.889086513331659e-01, /* 906 */ + 9.891405031314865e-01, /* 907 */ + 9.893699191978420e-01, /* 908 */ + 9.895968989673012e-01, /* 909 */ + 9.898214418809327e-01, /* 910 */ + 9.900435473858056e-01, /* 911 */ + 9.902632149349908e-01, /* 912 */ + 9.904804439875632e-01, /* 913 */ + 9.906952340086018e-01, /* 914 */ + 9.909075844691920e-01, /* 915 */ + 9.911174948464266e-01, /* 916 */ + 9.913249646234069e-01, /* 917 */ + 9.915299932892441e-01, /* 918 */ + 9.917325803390605e-01, /* 919 */ + 9.919327252739911e-01, /* 920 */ + 9.921304276011843e-01, /* 921 */ + 9.923256868338034e-01, /* 922 */ + 9.925185024910277e-01, /* 923 */ + 9.927088740980540e-01, /* 924 */ + 9.928968011860971e-01, /* 925 */ + 9.930822832923918e-01, /* 926 */ + 9.932653199601933e-01, /* 927 */ + 9.934459107387786e-01, /* 928 */ + 9.936240551834480e-01, /* 929 */ + 9.937997528555254e-01, /* 930 */ + 9.939730033223599e-01, /* 931 */ + 9.941438061573271e-01, /* 932 */ + 9.943121609398295e-01, /* 933 */ + 9.944780672552980e-01, /* 934 */ + 9.946415246951927e-01, /* 935 */ + 9.948025328570040e-01, /* 936 */ + 9.949610913442537e-01, /* 937 */ + 9.951171997664957e-01, /* 938 */ + 9.952708577393173e-01, /* 939 */ + 9.954220648843398e-01, /* 940 */ + 9.955708208292197e-01, /* 941 */ + 9.957171252076493e-01, /* 942 */ + 9.958609776593582e-01, /* 943 */ + 9.960023778301135e-01, /* 944 */ + 9.961413253717212e-01, /* 945 */ + 9.962778199420265e-01, /* 946 */ + 9.964118612049152e-01, /* 947 */ + 9.965434488303145e-01, /* 948 */ + 9.966725824941932e-01, /* 949 */ + 9.967992618785633e-01, /* 950 */ + 9.969234866714800e-01, /* 951 */ + 9.970452565670431e-01, /* 952 */ + 9.971645712653977e-01, /* 953 */ + 9.972814304727343e-01, /* 954 */ + 9.973958339012905e-01, /* 955 */ + 9.975077812693507e-01, /* 956 */ + 9.976172723012476e-01, /* 957 */ + 9.977243067273625e-01, /* 958 */ + 9.978288842841259e-01, /* 959 */ + 9.979310047140184e-01, /* 960 */ + 9.980306677655713e-01, /* 961 */ + 9.981278731933668e-01, /* 962 */ + 9.982226207580394e-01, /* 963 */ + 9.983149102262756e-01, /* 964 */ + 9.984047413708150e-01, /* 965 */ + 9.984921139704509e-01, /* 966 */ + 9.985770278100307e-01, /* 967 */ + 9.986594826804561e-01, /* 968 */ + 9.987394783786845e-01, /* 969 */ + 9.988170147077284e-01, /* 970 */ + 9.988920914766568e-01, /* 971 */ + 9.989647085005952e-01, /* 972 */ + 9.990348656007260e-01, /* 973 */ + 9.991025626042892e-01, /* 974 */ + 9.991677993445829e-01, /* 975 */ + 9.992305756609632e-01, /* 976 */ + 9.992908913988453e-01, /* 977 */ + 9.993487464097032e-01, /* 978 */ + 9.994041405510704e-01, /* 979 */ + 9.994570736865406e-01, /* 980 */ + 9.995075456857671e-01, /* 981 */ + 9.995555564244639e-01, /* 982 */ + 9.996011057844061e-01, /* 983 */ + 9.996441936534295e-01, /* 984 */ + 9.996848199254315e-01, /* 985 */ + 9.997229845003707e-01, /* 986 */ + 9.997586872842681e-01, /* 987 */ + 9.997919281892065e-01, /* 988 */ + 9.998227071333310e-01, /* 989 */ + 9.998510240408494e-01, /* 990 */ + 9.998768788420320e-01, /* 991 */ + 9.999002714732120e-01, /* 992 */ + 9.999212018767858e-01, /* 993 */ + 9.999396700012126e-01, /* 994 */ + 9.999556758010154e-01, /* 995 */ + 9.999692192367803e-01, /* 996 */ + 9.999803002751568e-01, /* 997 */ + 9.999889188888583e-01, /* 998 */ + 9.999950750566616e-01, /* 999 */ + 9.999987687634074e-01, /* 1000 */ + 1.000000000000000e+00, /* 1001 */ +}; diff --git a/libs/fluidsynth/fluid_rvoice_dsp_tables.inc.h b/libs/fluidsynth/fluid_rvoice_dsp_tables.inc.h new file mode 100644 index 00000000000..062eaac5935 --- /dev/null +++ b/libs/fluidsynth/fluid_rvoice_dsp_tables.inc.h @@ -0,0 +1,4109 @@ +/* THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT. */ + +static const fluid_real_t interp_coeff_linear[256][2] = { + { + 1.000000000000000e+00, /* 0 */ + 0.000000000000000e+00, /* 1 */ + }, { + 9.960937500000000e-01, /* 2 */ + 3.906250000000000e-03, /* 3 */ + }, { + 9.921875000000000e-01, /* 4 */ + 7.812500000000000e-03, /* 5 */ + }, { + 9.882812500000000e-01, /* 6 */ + 1.171875000000000e-02, /* 7 */ + }, { + 9.843750000000000e-01, /* 8 */ + 1.562500000000000e-02, /* 9 */ + }, { + 9.804687500000000e-01, /* 10 */ + 1.953125000000000e-02, /* 11 */ + }, { + 9.765625000000000e-01, /* 12 */ + 2.343750000000000e-02, /* 13 */ + }, { + 9.726562500000000e-01, /* 14 */ + 2.734375000000000e-02, /* 15 */ + }, { + 9.687500000000000e-01, /* 16 */ + 3.125000000000000e-02, /* 17 */ + }, { + 9.648437500000000e-01, /* 18 */ + 3.515625000000000e-02, /* 19 */ + }, { + 9.609375000000000e-01, /* 20 */ + 3.906250000000000e-02, /* 21 */ + }, { + 9.570312500000000e-01, /* 22 */ + 4.296875000000000e-02, /* 23 */ + }, { + 9.531250000000000e-01, /* 24 */ + 4.687500000000000e-02, /* 25 */ + }, { + 9.492187500000000e-01, /* 26 */ + 5.078125000000000e-02, /* 27 */ + }, { + 9.453125000000000e-01, /* 28 */ + 5.468750000000000e-02, /* 29 */ + }, { + 9.414062500000000e-01, /* 30 */ + 5.859375000000000e-02, /* 31 */ + }, { + 9.375000000000000e-01, /* 32 */ + 6.250000000000000e-02, /* 33 */ + }, { + 9.335937500000000e-01, /* 34 */ + 6.640625000000000e-02, /* 35 */ + }, { + 9.296875000000000e-01, /* 36 */ + 7.031250000000000e-02, /* 37 */ + }, { + 9.257812500000000e-01, /* 38 */ + 7.421875000000000e-02, /* 39 */ + }, { + 9.218750000000000e-01, /* 40 */ + 7.812500000000000e-02, /* 41 */ + }, { + 9.179687500000000e-01, /* 42 */ + 8.203125000000000e-02, /* 43 */ + }, { + 9.140625000000000e-01, /* 44 */ + 8.593750000000000e-02, /* 45 */ + }, { + 9.101562500000000e-01, /* 46 */ + 8.984375000000000e-02, /* 47 */ + }, { + 9.062500000000000e-01, /* 48 */ + 9.375000000000000e-02, /* 49 */ + }, { + 9.023437500000000e-01, /* 50 */ + 9.765625000000000e-02, /* 51 */ + }, { + 8.984375000000000e-01, /* 52 */ + 1.015625000000000e-01, /* 53 */ + }, { + 8.945312500000000e-01, /* 54 */ + 1.054687500000000e-01, /* 55 */ + }, { + 8.906250000000000e-01, /* 56 */ + 1.093750000000000e-01, /* 57 */ + }, { + 8.867187500000000e-01, /* 58 */ + 1.132812500000000e-01, /* 59 */ + }, { + 8.828125000000000e-01, /* 60 */ + 1.171875000000000e-01, /* 61 */ + }, { + 8.789062500000000e-01, /* 62 */ + 1.210937500000000e-01, /* 63 */ + }, { + 8.750000000000000e-01, /* 64 */ + 1.250000000000000e-01, /* 65 */ + }, { + 8.710937500000000e-01, /* 66 */ + 1.289062500000000e-01, /* 67 */ + }, { + 8.671875000000000e-01, /* 68 */ + 1.328125000000000e-01, /* 69 */ + }, { + 8.632812500000000e-01, /* 70 */ + 1.367187500000000e-01, /* 71 */ + }, { + 8.593750000000000e-01, /* 72 */ + 1.406250000000000e-01, /* 73 */ + }, { + 8.554687500000000e-01, /* 74 */ + 1.445312500000000e-01, /* 75 */ + }, { + 8.515625000000000e-01, /* 76 */ + 1.484375000000000e-01, /* 77 */ + }, { + 8.476562500000000e-01, /* 78 */ + 1.523437500000000e-01, /* 79 */ + }, { + 8.437500000000000e-01, /* 80 */ + 1.562500000000000e-01, /* 81 */ + }, { + 8.398437500000000e-01, /* 82 */ + 1.601562500000000e-01, /* 83 */ + }, { + 8.359375000000000e-01, /* 84 */ + 1.640625000000000e-01, /* 85 */ + }, { + 8.320312500000000e-01, /* 86 */ + 1.679687500000000e-01, /* 87 */ + }, { + 8.281250000000000e-01, /* 88 */ + 1.718750000000000e-01, /* 89 */ + }, { + 8.242187500000000e-01, /* 90 */ + 1.757812500000000e-01, /* 91 */ + }, { + 8.203125000000000e-01, /* 92 */ + 1.796875000000000e-01, /* 93 */ + }, { + 8.164062500000000e-01, /* 94 */ + 1.835937500000000e-01, /* 95 */ + }, { + 8.125000000000000e-01, /* 96 */ + 1.875000000000000e-01, /* 97 */ + }, { + 8.085937500000000e-01, /* 98 */ + 1.914062500000000e-01, /* 99 */ + }, { + 8.046875000000000e-01, /* 100 */ + 1.953125000000000e-01, /* 101 */ + }, { + 8.007812500000000e-01, /* 102 */ + 1.992187500000000e-01, /* 103 */ + }, { + 7.968750000000000e-01, /* 104 */ + 2.031250000000000e-01, /* 105 */ + }, { + 7.929687500000000e-01, /* 106 */ + 2.070312500000000e-01, /* 107 */ + }, { + 7.890625000000000e-01, /* 108 */ + 2.109375000000000e-01, /* 109 */ + }, { + 7.851562500000000e-01, /* 110 */ + 2.148437500000000e-01, /* 111 */ + }, { + 7.812500000000000e-01, /* 112 */ + 2.187500000000000e-01, /* 113 */ + }, { + 7.773437500000000e-01, /* 114 */ + 2.226562500000000e-01, /* 115 */ + }, { + 7.734375000000000e-01, /* 116 */ + 2.265625000000000e-01, /* 117 */ + }, { + 7.695312500000000e-01, /* 118 */ + 2.304687500000000e-01, /* 119 */ + }, { + 7.656250000000000e-01, /* 120 */ + 2.343750000000000e-01, /* 121 */ + }, { + 7.617187500000000e-01, /* 122 */ + 2.382812500000000e-01, /* 123 */ + }, { + 7.578125000000000e-01, /* 124 */ + 2.421875000000000e-01, /* 125 */ + }, { + 7.539062500000000e-01, /* 126 */ + 2.460937500000000e-01, /* 127 */ + }, { + 7.500000000000000e-01, /* 128 */ + 2.500000000000000e-01, /* 129 */ + }, { + 7.460937500000000e-01, /* 130 */ + 2.539062500000000e-01, /* 131 */ + }, { + 7.421875000000000e-01, /* 132 */ + 2.578125000000000e-01, /* 133 */ + }, { + 7.382812500000000e-01, /* 134 */ + 2.617187500000000e-01, /* 135 */ + }, { + 7.343750000000000e-01, /* 136 */ + 2.656250000000000e-01, /* 137 */ + }, { + 7.304687500000000e-01, /* 138 */ + 2.695312500000000e-01, /* 139 */ + }, { + 7.265625000000000e-01, /* 140 */ + 2.734375000000000e-01, /* 141 */ + }, { + 7.226562500000000e-01, /* 142 */ + 2.773437500000000e-01, /* 143 */ + }, { + 7.187500000000000e-01, /* 144 */ + 2.812500000000000e-01, /* 145 */ + }, { + 7.148437500000000e-01, /* 146 */ + 2.851562500000000e-01, /* 147 */ + }, { + 7.109375000000000e-01, /* 148 */ + 2.890625000000000e-01, /* 149 */ + }, { + 7.070312500000000e-01, /* 150 */ + 2.929687500000000e-01, /* 151 */ + }, { + 7.031250000000000e-01, /* 152 */ + 2.968750000000000e-01, /* 153 */ + }, { + 6.992187500000000e-01, /* 154 */ + 3.007812500000000e-01, /* 155 */ + }, { + 6.953125000000000e-01, /* 156 */ + 3.046875000000000e-01, /* 157 */ + }, { + 6.914062500000000e-01, /* 158 */ + 3.085937500000000e-01, /* 159 */ + }, { + 6.875000000000000e-01, /* 160 */ + 3.125000000000000e-01, /* 161 */ + }, { + 6.835937500000000e-01, /* 162 */ + 3.164062500000000e-01, /* 163 */ + }, { + 6.796875000000000e-01, /* 164 */ + 3.203125000000000e-01, /* 165 */ + }, { + 6.757812500000000e-01, /* 166 */ + 3.242187500000000e-01, /* 167 */ + }, { + 6.718750000000000e-01, /* 168 */ + 3.281250000000000e-01, /* 169 */ + }, { + 6.679687500000000e-01, /* 170 */ + 3.320312500000000e-01, /* 171 */ + }, { + 6.640625000000000e-01, /* 172 */ + 3.359375000000000e-01, /* 173 */ + }, { + 6.601562500000000e-01, /* 174 */ + 3.398437500000000e-01, /* 175 */ + }, { + 6.562500000000000e-01, /* 176 */ + 3.437500000000000e-01, /* 177 */ + }, { + 6.523437500000000e-01, /* 178 */ + 3.476562500000000e-01, /* 179 */ + }, { + 6.484375000000000e-01, /* 180 */ + 3.515625000000000e-01, /* 181 */ + }, { + 6.445312500000000e-01, /* 182 */ + 3.554687500000000e-01, /* 183 */ + }, { + 6.406250000000000e-01, /* 184 */ + 3.593750000000000e-01, /* 185 */ + }, { + 6.367187500000000e-01, /* 186 */ + 3.632812500000000e-01, /* 187 */ + }, { + 6.328125000000000e-01, /* 188 */ + 3.671875000000000e-01, /* 189 */ + }, { + 6.289062500000000e-01, /* 190 */ + 3.710937500000000e-01, /* 191 */ + }, { + 6.250000000000000e-01, /* 192 */ + 3.750000000000000e-01, /* 193 */ + }, { + 6.210937500000000e-01, /* 194 */ + 3.789062500000000e-01, /* 195 */ + }, { + 6.171875000000000e-01, /* 196 */ + 3.828125000000000e-01, /* 197 */ + }, { + 6.132812500000000e-01, /* 198 */ + 3.867187500000000e-01, /* 199 */ + }, { + 6.093750000000000e-01, /* 200 */ + 3.906250000000000e-01, /* 201 */ + }, { + 6.054687500000000e-01, /* 202 */ + 3.945312500000000e-01, /* 203 */ + }, { + 6.015625000000000e-01, /* 204 */ + 3.984375000000000e-01, /* 205 */ + }, { + 5.976562500000000e-01, /* 206 */ + 4.023437500000000e-01, /* 207 */ + }, { + 5.937500000000000e-01, /* 208 */ + 4.062500000000000e-01, /* 209 */ + }, { + 5.898437500000000e-01, /* 210 */ + 4.101562500000000e-01, /* 211 */ + }, { + 5.859375000000000e-01, /* 212 */ + 4.140625000000000e-01, /* 213 */ + }, { + 5.820312500000000e-01, /* 214 */ + 4.179687500000000e-01, /* 215 */ + }, { + 5.781250000000000e-01, /* 216 */ + 4.218750000000000e-01, /* 217 */ + }, { + 5.742187500000000e-01, /* 218 */ + 4.257812500000000e-01, /* 219 */ + }, { + 5.703125000000000e-01, /* 220 */ + 4.296875000000000e-01, /* 221 */ + }, { + 5.664062500000000e-01, /* 222 */ + 4.335937500000000e-01, /* 223 */ + }, { + 5.625000000000000e-01, /* 224 */ + 4.375000000000000e-01, /* 225 */ + }, { + 5.585937500000000e-01, /* 226 */ + 4.414062500000000e-01, /* 227 */ + }, { + 5.546875000000000e-01, /* 228 */ + 4.453125000000000e-01, /* 229 */ + }, { + 5.507812500000000e-01, /* 230 */ + 4.492187500000000e-01, /* 231 */ + }, { + 5.468750000000000e-01, /* 232 */ + 4.531250000000000e-01, /* 233 */ + }, { + 5.429687500000000e-01, /* 234 */ + 4.570312500000000e-01, /* 235 */ + }, { + 5.390625000000000e-01, /* 236 */ + 4.609375000000000e-01, /* 237 */ + }, { + 5.351562500000000e-01, /* 238 */ + 4.648437500000000e-01, /* 239 */ + }, { + 5.312500000000000e-01, /* 240 */ + 4.687500000000000e-01, /* 241 */ + }, { + 5.273437500000000e-01, /* 242 */ + 4.726562500000000e-01, /* 243 */ + }, { + 5.234375000000000e-01, /* 244 */ + 4.765625000000000e-01, /* 245 */ + }, { + 5.195312500000000e-01, /* 246 */ + 4.804687500000000e-01, /* 247 */ + }, { + 5.156250000000000e-01, /* 248 */ + 4.843750000000000e-01, /* 249 */ + }, { + 5.117187500000000e-01, /* 250 */ + 4.882812500000000e-01, /* 251 */ + }, { + 5.078125000000000e-01, /* 252 */ + 4.921875000000000e-01, /* 253 */ + }, { + 5.039062500000000e-01, /* 254 */ + 4.960937500000000e-01, /* 255 */ + }, { + 5.000000000000000e-01, /* 256 */ + 5.000000000000000e-01, /* 257 */ + }, { + 4.960937500000000e-01, /* 258 */ + 5.039062500000000e-01, /* 259 */ + }, { + 4.921875000000000e-01, /* 260 */ + 5.078125000000000e-01, /* 261 */ + }, { + 4.882812500000000e-01, /* 262 */ + 5.117187500000000e-01, /* 263 */ + }, { + 4.843750000000000e-01, /* 264 */ + 5.156250000000000e-01, /* 265 */ + }, { + 4.804687500000000e-01, /* 266 */ + 5.195312500000000e-01, /* 267 */ + }, { + 4.765625000000000e-01, /* 268 */ + 5.234375000000000e-01, /* 269 */ + }, { + 4.726562500000000e-01, /* 270 */ + 5.273437500000000e-01, /* 271 */ + }, { + 4.687500000000000e-01, /* 272 */ + 5.312500000000000e-01, /* 273 */ + }, { + 4.648437500000000e-01, /* 274 */ + 5.351562500000000e-01, /* 275 */ + }, { + 4.609375000000000e-01, /* 276 */ + 5.390625000000000e-01, /* 277 */ + }, { + 4.570312500000000e-01, /* 278 */ + 5.429687500000000e-01, /* 279 */ + }, { + 4.531250000000000e-01, /* 280 */ + 5.468750000000000e-01, /* 281 */ + }, { + 4.492187500000000e-01, /* 282 */ + 5.507812500000000e-01, /* 283 */ + }, { + 4.453125000000000e-01, /* 284 */ + 5.546875000000000e-01, /* 285 */ + }, { + 4.414062500000000e-01, /* 286 */ + 5.585937500000000e-01, /* 287 */ + }, { + 4.375000000000000e-01, /* 288 */ + 5.625000000000000e-01, /* 289 */ + }, { + 4.335937500000000e-01, /* 290 */ + 5.664062500000000e-01, /* 291 */ + }, { + 4.296875000000000e-01, /* 292 */ + 5.703125000000000e-01, /* 293 */ + }, { + 4.257812500000000e-01, /* 294 */ + 5.742187500000000e-01, /* 295 */ + }, { + 4.218750000000000e-01, /* 296 */ + 5.781250000000000e-01, /* 297 */ + }, { + 4.179687500000000e-01, /* 298 */ + 5.820312500000000e-01, /* 299 */ + }, { + 4.140625000000000e-01, /* 300 */ + 5.859375000000000e-01, /* 301 */ + }, { + 4.101562500000000e-01, /* 302 */ + 5.898437500000000e-01, /* 303 */ + }, { + 4.062500000000000e-01, /* 304 */ + 5.937500000000000e-01, /* 305 */ + }, { + 4.023437500000000e-01, /* 306 */ + 5.976562500000000e-01, /* 307 */ + }, { + 3.984375000000000e-01, /* 308 */ + 6.015625000000000e-01, /* 309 */ + }, { + 3.945312500000000e-01, /* 310 */ + 6.054687500000000e-01, /* 311 */ + }, { + 3.906250000000000e-01, /* 312 */ + 6.093750000000000e-01, /* 313 */ + }, { + 3.867187500000000e-01, /* 314 */ + 6.132812500000000e-01, /* 315 */ + }, { + 3.828125000000000e-01, /* 316 */ + 6.171875000000000e-01, /* 317 */ + }, { + 3.789062500000000e-01, /* 318 */ + 6.210937500000000e-01, /* 319 */ + }, { + 3.750000000000000e-01, /* 320 */ + 6.250000000000000e-01, /* 321 */ + }, { + 3.710937500000000e-01, /* 322 */ + 6.289062500000000e-01, /* 323 */ + }, { + 3.671875000000000e-01, /* 324 */ + 6.328125000000000e-01, /* 325 */ + }, { + 3.632812500000000e-01, /* 326 */ + 6.367187500000000e-01, /* 327 */ + }, { + 3.593750000000000e-01, /* 328 */ + 6.406250000000000e-01, /* 329 */ + }, { + 3.554687500000000e-01, /* 330 */ + 6.445312500000000e-01, /* 331 */ + }, { + 3.515625000000000e-01, /* 332 */ + 6.484375000000000e-01, /* 333 */ + }, { + 3.476562500000000e-01, /* 334 */ + 6.523437500000000e-01, /* 335 */ + }, { + 3.437500000000000e-01, /* 336 */ + 6.562500000000000e-01, /* 337 */ + }, { + 3.398437500000000e-01, /* 338 */ + 6.601562500000000e-01, /* 339 */ + }, { + 3.359375000000000e-01, /* 340 */ + 6.640625000000000e-01, /* 341 */ + }, { + 3.320312500000000e-01, /* 342 */ + 6.679687500000000e-01, /* 343 */ + }, { + 3.281250000000000e-01, /* 344 */ + 6.718750000000000e-01, /* 345 */ + }, { + 3.242187500000000e-01, /* 346 */ + 6.757812500000000e-01, /* 347 */ + }, { + 3.203125000000000e-01, /* 348 */ + 6.796875000000000e-01, /* 349 */ + }, { + 3.164062500000000e-01, /* 350 */ + 6.835937500000000e-01, /* 351 */ + }, { + 3.125000000000000e-01, /* 352 */ + 6.875000000000000e-01, /* 353 */ + }, { + 3.085937500000000e-01, /* 354 */ + 6.914062500000000e-01, /* 355 */ + }, { + 3.046875000000000e-01, /* 356 */ + 6.953125000000000e-01, /* 357 */ + }, { + 3.007812500000000e-01, /* 358 */ + 6.992187500000000e-01, /* 359 */ + }, { + 2.968750000000000e-01, /* 360 */ + 7.031250000000000e-01, /* 361 */ + }, { + 2.929687500000000e-01, /* 362 */ + 7.070312500000000e-01, /* 363 */ + }, { + 2.890625000000000e-01, /* 364 */ + 7.109375000000000e-01, /* 365 */ + }, { + 2.851562500000000e-01, /* 366 */ + 7.148437500000000e-01, /* 367 */ + }, { + 2.812500000000000e-01, /* 368 */ + 7.187500000000000e-01, /* 369 */ + }, { + 2.773437500000000e-01, /* 370 */ + 7.226562500000000e-01, /* 371 */ + }, { + 2.734375000000000e-01, /* 372 */ + 7.265625000000000e-01, /* 373 */ + }, { + 2.695312500000000e-01, /* 374 */ + 7.304687500000000e-01, /* 375 */ + }, { + 2.656250000000000e-01, /* 376 */ + 7.343750000000000e-01, /* 377 */ + }, { + 2.617187500000000e-01, /* 378 */ + 7.382812500000000e-01, /* 379 */ + }, { + 2.578125000000000e-01, /* 380 */ + 7.421875000000000e-01, /* 381 */ + }, { + 2.539062500000000e-01, /* 382 */ + 7.460937500000000e-01, /* 383 */ + }, { + 2.500000000000000e-01, /* 384 */ + 7.500000000000000e-01, /* 385 */ + }, { + 2.460937500000000e-01, /* 386 */ + 7.539062500000000e-01, /* 387 */ + }, { + 2.421875000000000e-01, /* 388 */ + 7.578125000000000e-01, /* 389 */ + }, { + 2.382812500000000e-01, /* 390 */ + 7.617187500000000e-01, /* 391 */ + }, { + 2.343750000000000e-01, /* 392 */ + 7.656250000000000e-01, /* 393 */ + }, { + 2.304687500000000e-01, /* 394 */ + 7.695312500000000e-01, /* 395 */ + }, { + 2.265625000000000e-01, /* 396 */ + 7.734375000000000e-01, /* 397 */ + }, { + 2.226562500000000e-01, /* 398 */ + 7.773437500000000e-01, /* 399 */ + }, { + 2.187500000000000e-01, /* 400 */ + 7.812500000000000e-01, /* 401 */ + }, { + 2.148437500000000e-01, /* 402 */ + 7.851562500000000e-01, /* 403 */ + }, { + 2.109375000000000e-01, /* 404 */ + 7.890625000000000e-01, /* 405 */ + }, { + 2.070312500000000e-01, /* 406 */ + 7.929687500000000e-01, /* 407 */ + }, { + 2.031250000000000e-01, /* 408 */ + 7.968750000000000e-01, /* 409 */ + }, { + 1.992187500000000e-01, /* 410 */ + 8.007812500000000e-01, /* 411 */ + }, { + 1.953125000000000e-01, /* 412 */ + 8.046875000000000e-01, /* 413 */ + }, { + 1.914062500000000e-01, /* 414 */ + 8.085937500000000e-01, /* 415 */ + }, { + 1.875000000000000e-01, /* 416 */ + 8.125000000000000e-01, /* 417 */ + }, { + 1.835937500000000e-01, /* 418 */ + 8.164062500000000e-01, /* 419 */ + }, { + 1.796875000000000e-01, /* 420 */ + 8.203125000000000e-01, /* 421 */ + }, { + 1.757812500000000e-01, /* 422 */ + 8.242187500000000e-01, /* 423 */ + }, { + 1.718750000000000e-01, /* 424 */ + 8.281250000000000e-01, /* 425 */ + }, { + 1.679687500000000e-01, /* 426 */ + 8.320312500000000e-01, /* 427 */ + }, { + 1.640625000000000e-01, /* 428 */ + 8.359375000000000e-01, /* 429 */ + }, { + 1.601562500000000e-01, /* 430 */ + 8.398437500000000e-01, /* 431 */ + }, { + 1.562500000000000e-01, /* 432 */ + 8.437500000000000e-01, /* 433 */ + }, { + 1.523437500000000e-01, /* 434 */ + 8.476562500000000e-01, /* 435 */ + }, { + 1.484375000000000e-01, /* 436 */ + 8.515625000000000e-01, /* 437 */ + }, { + 1.445312500000000e-01, /* 438 */ + 8.554687500000000e-01, /* 439 */ + }, { + 1.406250000000000e-01, /* 440 */ + 8.593750000000000e-01, /* 441 */ + }, { + 1.367187500000000e-01, /* 442 */ + 8.632812500000000e-01, /* 443 */ + }, { + 1.328125000000000e-01, /* 444 */ + 8.671875000000000e-01, /* 445 */ + }, { + 1.289062500000000e-01, /* 446 */ + 8.710937500000000e-01, /* 447 */ + }, { + 1.250000000000000e-01, /* 448 */ + 8.750000000000000e-01, /* 449 */ + }, { + 1.210937500000000e-01, /* 450 */ + 8.789062500000000e-01, /* 451 */ + }, { + 1.171875000000000e-01, /* 452 */ + 8.828125000000000e-01, /* 453 */ + }, { + 1.132812500000000e-01, /* 454 */ + 8.867187500000000e-01, /* 455 */ + }, { + 1.093750000000000e-01, /* 456 */ + 8.906250000000000e-01, /* 457 */ + }, { + 1.054687500000000e-01, /* 458 */ + 8.945312500000000e-01, /* 459 */ + }, { + 1.015625000000000e-01, /* 460 */ + 8.984375000000000e-01, /* 461 */ + }, { + 9.765625000000000e-02, /* 462 */ + 9.023437500000000e-01, /* 463 */ + }, { + 9.375000000000000e-02, /* 464 */ + 9.062500000000000e-01, /* 465 */ + }, { + 8.984375000000000e-02, /* 466 */ + 9.101562500000000e-01, /* 467 */ + }, { + 8.593750000000000e-02, /* 468 */ + 9.140625000000000e-01, /* 469 */ + }, { + 8.203125000000000e-02, /* 470 */ + 9.179687500000000e-01, /* 471 */ + }, { + 7.812500000000000e-02, /* 472 */ + 9.218750000000000e-01, /* 473 */ + }, { + 7.421875000000000e-02, /* 474 */ + 9.257812500000000e-01, /* 475 */ + }, { + 7.031250000000000e-02, /* 476 */ + 9.296875000000000e-01, /* 477 */ + }, { + 6.640625000000000e-02, /* 478 */ + 9.335937500000000e-01, /* 479 */ + }, { + 6.250000000000000e-02, /* 480 */ + 9.375000000000000e-01, /* 481 */ + }, { + 5.859375000000000e-02, /* 482 */ + 9.414062500000000e-01, /* 483 */ + }, { + 5.468750000000000e-02, /* 484 */ + 9.453125000000000e-01, /* 485 */ + }, { + 5.078125000000000e-02, /* 486 */ + 9.492187500000000e-01, /* 487 */ + }, { + 4.687500000000000e-02, /* 488 */ + 9.531250000000000e-01, /* 489 */ + }, { + 4.296875000000000e-02, /* 490 */ + 9.570312500000000e-01, /* 491 */ + }, { + 3.906250000000000e-02, /* 492 */ + 9.609375000000000e-01, /* 493 */ + }, { + 3.515625000000000e-02, /* 494 */ + 9.648437500000000e-01, /* 495 */ + }, { + 3.125000000000000e-02, /* 496 */ + 9.687500000000000e-01, /* 497 */ + }, { + 2.734375000000000e-02, /* 498 */ + 9.726562500000000e-01, /* 499 */ + }, { + 2.343750000000000e-02, /* 500 */ + 9.765625000000000e-01, /* 501 */ + }, { + 1.953125000000000e-02, /* 502 */ + 9.804687500000000e-01, /* 503 */ + }, { + 1.562500000000000e-02, /* 504 */ + 9.843750000000000e-01, /* 505 */ + }, { + 1.171875000000000e-02, /* 506 */ + 9.882812500000000e-01, /* 507 */ + }, { + 7.812500000000000e-03, /* 508 */ + 9.921875000000000e-01, /* 509 */ + }, { + 3.906250000000000e-03, /* 510 */ + 9.960937500000000e-01, /* 511 */ + } +}; + +static const fluid_real_t interp_coeff[256][4] = { + { + -0.000000000000000e+00, /* 0 */ + 1.000000000000000e+00, /* 1 */ + 0.000000000000000e+00, /* 2 */ + -0.000000000000000e+00, /* 3 */ + }, { + -1.937896013259888e-03, /* 4 */ + 9.999619424343109e-01, /* 5 */ + 1.983553171157837e-03, /* 6 */ + -7.599592208862305e-06, /* 7 */ + }, { + -3.845453262329102e-03, /* 8 */ + 9.998481273651123e-01, /* 9 */ + 4.027605056762695e-03, /* 10 */ + -3.027915954589844e-05, /* 11 */ + }, { + -5.722850561141968e-03, /* 12 */ + 9.996590912342072e-01, /* 13 */ + 6.131619215011597e-03, /* 14 */ + -6.785988807678223e-05, /* 15 */ + }, { + -7.570266723632812e-03, /* 16 */ + 9.993953704833984e-01, /* 17 */ + 8.295059204101562e-03, /* 18 */ + -1.201629638671875e-04, /* 19 */ + }, { + -9.387880563735962e-03, /* 20 */ + 9.990575015544891e-01, /* 21 */ + 1.051738858222961e-02, /* 22 */ + -1.870095729827881e-04, /* 23 */ + }, { + -1.117587089538574e-02, /* 24 */ + 9.986460208892822e-01, /* 25 */ + 1.279807090759277e-02, /* 26 */ + -2.682209014892578e-04, /* 27 */ + }, { + -1.293441653251648e-02, /* 28 */ + 9.981614649295807e-01, /* 29 */ + 1.513656973838806e-02, /* 30 */ + -3.636181354522705e-04, /* 31 */ + }, { + -1.466369628906250e-02, /* 32 */ + 9.976043701171875e-01, /* 33 */ + 1.753234863281250e-02, /* 34 */ + -4.730224609375000e-04, /* 35 */ + }, { + -1.636388897895813e-02, /* 36 */ + 9.969752728939056e-01, /* 37 */ + 1.998487114906311e-02, /* 38 */ + -5.962550640106201e-04, /* 39 */ + }, { + -1.803517341613770e-02, /* 40 */ + 9.962747097015381e-01, /* 41 */ + 2.249360084533691e-02, /* 42 */ + -7.331371307373047e-04, /* 43 */ + }, { + -1.967772841453552e-02, /* 44 */ + 9.955032169818878e-01, /* 45 */ + 2.505800127983093e-02, /* 46 */ + -8.834898471832275e-04, /* 47 */ + }, { + -2.129173278808594e-02, /* 48 */ + 9.946613311767578e-01, /* 49 */ + 2.767753601074219e-02, /* 50 */ + -1.047134399414062e-03, /* 51 */ + }, { + -2.287736535072327e-02, /* 52 */ + 9.937495887279510e-01, /* 53 */ + 3.035166859626770e-02, /* 54 */ + -1.223891973495483e-03, /* 55 */ + }, { + -2.443480491638184e-02, /* 56 */ + 9.927685260772705e-01, /* 57 */ + 3.307986259460449e-02, /* 58 */ + -1.413583755493164e-03, /* 59 */ + }, { + -2.596423029899597e-02, /* 60 */ + 9.917186796665192e-01, /* 61 */ + 3.586158156394958e-02, /* 62 */ + -1.616030931472778e-03, /* 63 */ + }, { + -2.746582031250000e-02, /* 64 */ + 9.906005859375000e-01, /* 65 */ + 3.869628906250000e-02, /* 66 */ + -1.831054687500000e-03, /* 67 */ + }, { + -2.893975377082825e-02, /* 68 */ + 9.894147813320160e-01, /* 69 */ + 4.158344864845276e-02, /* 70 */ + -2.058476209640503e-03, /* 71 */ + }, { + -3.038620948791504e-02, /* 72 */ + 9.881618022918701e-01, /* 73 */ + 4.452252388000488e-02, /* 74 */ + -2.298116683959961e-03, /* 75 */ + }, { + -3.180536627769470e-02, /* 76 */ + 9.868421852588654e-01, /* 77 */ + 4.751297831535339e-02, /* 78 */ + -2.549797296524048e-03, /* 79 */ + }, { + -3.319740295410156e-02, /* 80 */ + 9.854564666748047e-01, /* 81 */ + 5.055427551269531e-02, /* 82 */ + -2.813339233398438e-03, /* 83 */ + }, { + -3.456249833106995e-02, /* 84 */ + 9.840051829814911e-01, /* 85 */ + 5.364587903022766e-02, /* 86 */ + -3.088563680648804e-03, /* 87 */ + }, { + -3.590083122253418e-02, /* 88 */ + 9.824888706207275e-01, /* 89 */ + 5.678725242614746e-02, /* 90 */ + -3.375291824340820e-03, /* 91 */ + }, { + -3.721258044242859e-02, /* 92 */ + 9.809080660343170e-01, /* 93 */ + 5.997785925865173e-02, /* 94 */ + -3.673344850540161e-03, /* 95 */ + }, { + -3.849792480468750e-02, /* 96 */ + 9.792633056640625e-01, /* 97 */ + 6.321716308593750e-02, /* 98 */ + -3.982543945312500e-03, /* 99 */ + }, { + -3.975704312324524e-02, /* 100 */ + 9.775551259517670e-01, /* 101 */ + 6.650462746620178e-02, /* 102 */ + -4.302710294723511e-03, /* 103 */ + }, { + -4.099011421203613e-02, /* 104 */ + 9.757840633392334e-01, /* 105 */ + 6.983971595764160e-02, /* 106 */ + -4.633665084838867e-03, /* 107 */ + }, { + -4.219731688499451e-02, /* 108 */ + 9.739506542682648e-01, /* 109 */ + 7.322189211845398e-02, /* 110 */ + -4.975229501724243e-03, /* 111 */ + }, { + -4.337882995605469e-02, /* 112 */ + 9.720554351806641e-01, /* 113 */ + 7.665061950683594e-02, /* 114 */ + -5.327224731445312e-03, /* 115 */ + }, { + -4.453483223915100e-02, /* 116 */ + 9.700989425182343e-01, /* 117 */ + 8.012536168098450e-02, /* 118 */ + -5.689471960067749e-03, /* 119 */ + }, { + -4.566550254821777e-02, /* 120 */ + 9.680817127227783e-01, /* 121 */ + 8.364558219909668e-02, /* 122 */ + -6.061792373657227e-03, /* 123 */ + }, { + -4.677101969718933e-02, /* 124 */ + 9.660042822360992e-01, /* 125 */ + 8.721074461936951e-02, /* 126 */ + -6.444007158279419e-03, /* 127 */ + }, { + -4.785156250000000e-02, /* 128 */ + 9.638671875000000e-01, /* 129 */ + 9.082031250000000e-02, /* 130 */ + -6.835937500000000e-03, /* 131 */ + }, { + -4.890730977058411e-02, /* 132 */ + 9.616709649562836e-01, /* 133 */ + 9.447374939918518e-02, /* 134 */ + -7.237404584884644e-03, /* 135 */ + }, { + -4.993844032287598e-02, /* 136 */ + 9.594161510467529e-01, /* 137 */ + 9.817051887512207e-02, /* 138 */ + -7.648229598999023e-03, /* 139 */ + }, { + -5.094513297080994e-02, /* 140 */ + 9.571032822132111e-01, /* 141 */ + 1.019100844860077e-01, /* 142 */ + -8.068233728408813e-03, /* 143 */ + }, { + -5.192756652832031e-02, /* 144 */ + 9.547328948974609e-01, /* 145 */ + 1.056919097900391e-01, /* 146 */ + -8.497238159179688e-03, /* 147 */ + }, { + -5.288591980934143e-02, /* 148 */ + 9.523055255413055e-01, /* 149 */ + 1.095154583454132e-01, /* 150 */ + -8.935064077377319e-03, /* 151 */ + }, { + -5.382037162780762e-02, /* 152 */ + 9.498217105865479e-01, /* 153 */ + 1.133801937103271e-01, /* 154 */ + -9.381532669067383e-03, /* 155 */ + }, { + -5.473110079765320e-02, /* 156 */ + 9.472819864749908e-01, /* 157 */ + 1.172855794429779e-01, /* 158 */ + -9.836465120315552e-03, /* 159 */ + }, { + -5.561828613281250e-02, /* 160 */ + 9.446868896484375e-01, /* 161 */ + 1.212310791015625e-01, /* 162 */ + -1.029968261718750e-02, /* 163 */ + }, { + -5.648210644721985e-02, /* 164 */ + 9.420369565486908e-01, /* 165 */ + 1.252161562442780e-01, /* 166 */ + -1.077100634574890e-02, /* 167 */ + }, { + -5.732274055480957e-02, /* 168 */ + 9.393327236175537e-01, /* 169 */ + 1.292402744293213e-01, /* 170 */ + -1.125025749206543e-02, /* 171 */ + }, { + -5.814036726951599e-02, /* 172 */ + 9.365747272968292e-01, /* 173 */ + 1.333028972148895e-01, /* 174 */ + -1.173725724220276e-02, /* 175 */ + }, { + -5.893516540527344e-02, /* 176 */ + 9.337635040283203e-01, /* 177 */ + 1.374034881591797e-01, /* 178 */ + -1.223182678222656e-02, /* 179 */ + }, { + -5.970731377601624e-02, /* 180 */ + 9.308995902538300e-01, /* 181 */ + 1.415415108203888e-01, /* 182 */ + -1.273378729820251e-02, /* 183 */ + }, { + -6.045699119567871e-02, /* 184 */ + 9.279835224151611e-01, /* 185 */ + 1.457164287567139e-01, /* 186 */ + -1.324295997619629e-02, /* 187 */ + }, { + -6.118437647819519e-02, /* 188 */ + 9.250158369541168e-01, /* 189 */ + 1.499277055263519e-01, /* 190 */ + -1.375916600227356e-02, /* 191 */ + }, { + -6.188964843750000e-02, /* 192 */ + 9.219970703125000e-01, /* 193 */ + 1.541748046875000e-01, /* 194 */ + -1.428222656250000e-02, /* 195 */ + }, { + -6.257298588752747e-02, /* 196 */ + 9.189277589321136e-01, /* 197 */ + 1.584571897983551e-01, /* 198 */ + -1.481196284294128e-02, /* 199 */ + }, { + -6.323456764221191e-02, /* 200 */ + 9.158084392547607e-01, /* 201 */ + 1.627743244171143e-01, /* 202 */ + -1.534819602966309e-02, /* 203 */ + }, { + -6.387457251548767e-02, /* 204 */ + 9.126396477222443e-01, /* 205 */ + 1.671256721019745e-01, /* 206 */ + -1.589074730873108e-02, /* 207 */ + }, { + -6.449317932128906e-02, /* 208 */ + 9.094219207763672e-01, /* 209 */ + 1.715106964111328e-01, /* 210 */ + -1.643943786621094e-02, /* 211 */ + }, { + -6.509056687355042e-02, /* 212 */ + 9.061557948589325e-01, /* 213 */ + 1.759288609027863e-01, /* 214 */ + -1.699408888816833e-02, /* 215 */ + }, { + -6.566691398620605e-02, /* 216 */ + 9.028418064117432e-01, /* 217 */ + 1.803796291351318e-01, /* 218 */ + -1.755452156066895e-02, /* 219 */ + }, { + -6.622239947319031e-02, /* 220 */ + 8.994804918766022e-01, /* 221 */ + 1.848624646663666e-01, /* 222 */ + -1.812055706977844e-02, /* 223 */ + }, { + -6.675720214843750e-02, /* 224 */ + 8.960723876953125e-01, /* 225 */ + 1.893768310546875e-01, /* 226 */ + -1.869201660156250e-02, /* 227 */ + }, { + -6.727150082588196e-02, /* 228 */ + 8.926180303096771e-01, /* 229 */ + 1.939221918582916e-01, /* 230 */ + -1.926872134208679e-02, /* 231 */ + }, { + -6.776547431945801e-02, /* 232 */ + 8.891179561614990e-01, /* 233 */ + 1.984980106353760e-01, /* 234 */ + -1.985049247741699e-02, /* 235 */ + }, { + -6.823930144309998e-02, /* 236 */ + 8.855727016925812e-01, /* 237 */ + 2.031037509441376e-01, /* 238 */ + -2.043715119361877e-02, /* 239 */ + }, { + -6.869316101074219e-02, /* 240 */ + 8.819828033447266e-01, /* 241 */ + 2.077388763427734e-01, /* 242 */ + -2.102851867675781e-02, /* 243 */ + }, { + -6.912723183631897e-02, /* 244 */ + 8.783487975597382e-01, /* 245 */ + 2.124028503894806e-01, /* 246 */ + -2.162441611289978e-02, /* 247 */ + }, { + -6.954169273376465e-02, /* 248 */ + 8.746712207794189e-01, /* 249 */ + 2.170951366424561e-01, /* 250 */ + -2.222466468811035e-02, /* 251 */ + }, { + -6.993672251701355e-02, /* 252 */ + 8.709506094455719e-01, /* 253 */ + 2.218151986598969e-01, /* 254 */ + -2.282908558845520e-02, /* 255 */ + }, { + -7.031250000000000e-02, /* 256 */ + 8.671875000000000e-01, /* 257 */ + 2.265625000000000e-01, /* 258 */ + -2.343750000000000e-02, /* 259 */ + }, { + -7.066920399665833e-02, /* 260 */ + 8.633824288845062e-01, /* 261 */ + 2.313365042209625e-01, /* 262 */ + -2.404972910881042e-02, /* 263 */ + }, { + -7.100701332092285e-02, /* 264 */ + 8.595359325408936e-01, /* 265 */ + 2.361366748809814e-01, /* 266 */ + -2.466559410095215e-02, /* 267 */ + }, { + -7.132610678672791e-02, /* 268 */ + 8.556485474109650e-01, /* 269 */ + 2.409624755382538e-01, /* 270 */ + -2.528491616249084e-02, /* 271 */ + }, { + -7.162666320800781e-02, /* 272 */ + 8.517208099365234e-01, /* 273 */ + 2.458133697509766e-01, /* 274 */ + -2.590751647949219e-02, /* 275 */ + }, { + -7.190886139869690e-02, /* 276 */ + 8.477532565593719e-01, /* 277 */ + 2.506888210773468e-01, /* 278 */ + -2.653321623802185e-02, /* 279 */ + }, { + -7.217288017272949e-02, /* 280 */ + 8.437464237213135e-01, /* 281 */ + 2.555882930755615e-01, /* 282 */ + -2.716183662414551e-02, /* 283 */ + }, { + -7.241889834403992e-02, /* 284 */ + 8.397008478641510e-01, /* 285 */ + 2.605112493038177e-01, /* 286 */ + -2.779319882392883e-02, /* 287 */ + }, { + -7.264709472656250e-02, /* 288 */ + 8.356170654296875e-01, /* 289 */ + 2.654571533203125e-01, /* 290 */ + -2.842712402343750e-02, /* 291 */ + }, { + -7.285764813423157e-02, /* 292 */ + 8.314956128597260e-01, /* 293 */ + 2.704254686832428e-01, /* 294 */ + -2.906343340873718e-02, /* 295 */ + }, { + -7.305073738098145e-02, /* 296 */ + 8.273370265960693e-01, /* 297 */ + 2.754156589508057e-01, /* 298 */ + -2.970194816589355e-02, /* 299 */ + }, { + -7.322654128074646e-02, /* 300 */ + 8.231418430805206e-01, /* 301 */ + 2.804271876811981e-01, /* 302 */ + -3.034248948097229e-02, /* 303 */ + }, { + -7.338523864746094e-02, /* 304 */ + 8.189105987548828e-01, /* 305 */ + 2.854595184326172e-01, /* 306 */ + -3.098487854003906e-02, /* 307 */ + }, { + -7.352700829505920e-02, /* 308 */ + 8.146438300609589e-01, /* 309 */ + 2.905121147632599e-01, /* 310 */ + -3.162893652915955e-02, /* 311 */ + }, { + -7.365202903747559e-02, /* 312 */ + 8.103420734405518e-01, /* 313 */ + 2.955844402313232e-01, /* 314 */ + -3.227448463439941e-02, /* 315 */ + }, { + -7.376047968864441e-02, /* 316 */ + 8.060058653354645e-01, /* 317 */ + 3.006759583950043e-01, /* 318 */ + -3.292134404182434e-02, /* 319 */ + }, { + -7.385253906250000e-02, /* 320 */ + 8.016357421875000e-01, /* 321 */ + 3.057861328125000e-01, /* 322 */ + -3.356933593750000e-02, /* 323 */ + }, { + -7.392838597297668e-02, /* 324 */ + 7.972322404384613e-01, /* 325 */ + 3.109144270420074e-01, /* 326 */ + -3.421828150749207e-02, /* 327 */ + }, { + -7.398819923400879e-02, /* 328 */ + 7.927958965301514e-01, /* 329 */ + 3.160603046417236e-01, /* 330 */ + -3.486800193786621e-02, /* 331 */ + }, { + -7.403215765953064e-02, /* 332 */ + 7.883272469043732e-01, /* 333 */ + 3.212232291698456e-01, /* 334 */ + -3.551831841468811e-02, /* 335 */ + }, { + -7.406044006347656e-02, /* 336 */ + 7.838268280029297e-01, /* 337 */ + 3.264026641845703e-01, /* 338 */ + -3.616905212402344e-02, /* 339 */ + }, { + -7.407322525978088e-02, /* 340 */ + 7.792951762676239e-01, /* 341 */ + 3.315980732440948e-01, /* 342 */ + -3.682002425193787e-02, /* 343 */ + }, { + -7.407069206237793e-02, /* 344 */ + 7.747328281402588e-01, /* 345 */ + 3.368089199066162e-01, /* 346 */ + -3.747105598449707e-02, /* 347 */ + }, { + -7.405301928520203e-02, /* 348 */ + 7.701403200626373e-01, /* 349 */ + 3.420346677303314e-01, /* 350 */ + -3.812196850776672e-02, /* 351 */ + }, { + -7.402038574218750e-02, /* 352 */ + 7.655181884765625e-01, /* 353 */ + 3.472747802734375e-01, /* 354 */ + -3.877258300781250e-02, /* 355 */ + }, { + -7.397297024726868e-02, /* 356 */ + 7.608669698238373e-01, /* 357 */ + 3.525287210941315e-01, /* 358 */ + -3.942272067070007e-02, /* 359 */ + }, { + -7.391095161437988e-02, /* 360 */ + 7.561872005462646e-01, /* 361 */ + 3.577959537506104e-01, /* 362 */ + -4.007220268249512e-02, /* 363 */ + }, { + -7.383450865745544e-02, /* 364 */ + 7.514794170856476e-01, /* 365 */ + 3.630759418010712e-01, /* 366 */ + -4.072085022926331e-02, /* 367 */ + }, { + -7.374382019042969e-02, /* 368 */ + 7.467441558837891e-01, /* 369 */ + 3.683681488037109e-01, /* 370 */ + -4.136848449707031e-02, /* 371 */ + }, { + -7.363906502723694e-02, /* 372 */ + 7.419819533824921e-01, /* 373 */ + 3.736720383167267e-01, /* 374 */ + -4.201492667198181e-02, /* 375 */ + }, { + -7.352042198181152e-02, /* 376 */ + 7.371933460235596e-01, /* 377 */ + 3.789870738983154e-01, /* 378 */ + -4.265999794006348e-02, /* 379 */ + }, { + -7.338806986808777e-02, /* 380 */ + 7.323788702487946e-01, /* 381 */ + 3.843127191066742e-01, /* 382 */ + -4.330351948738098e-02, /* 383 */ + }, { + -7.324218750000000e-02, /* 384 */ + 7.275390625000000e-01, /* 385 */ + 3.896484375000000e-01, /* 386 */ + -4.394531250000000e-02, /* 387 */ + }, { + -7.308295369148254e-02, /* 388 */ + 7.226744592189789e-01, /* 389 */ + 3.949936926364899e-01, /* 390 */ + -4.458519816398621e-02, /* 391 */ + }, { + -7.291054725646973e-02, /* 392 */ + 7.177855968475342e-01, /* 393 */ + 4.003479480743408e-01, /* 394 */ + -4.522299766540527e-02, /* 395 */ + }, { + -7.272514700889587e-02, /* 396 */ + 7.128730118274689e-01, /* 397 */ + 4.057106673717499e-01, /* 398 */ + -4.585853219032288e-02, /* 399 */ + }, { + -7.252693176269531e-02, /* 400 */ + 7.079372406005859e-01, /* 401 */ + 4.110813140869141e-01, /* 402 */ + -4.649162292480469e-02, /* 403 */ + }, { + -7.231608033180237e-02, /* 404 */ + 7.029788196086884e-01, /* 405 */ + 4.164593517780304e-01, /* 406 */ + -4.712209105491638e-02, /* 407 */ + }, { + -7.209277153015137e-02, /* 408 */ + 6.979982852935791e-01, /* 409 */ + 4.218442440032959e-01, /* 410 */ + -4.774975776672363e-02, /* 411 */ + }, { + -7.185718417167664e-02, /* 412 */ + 6.929961740970612e-01, /* 413 */ + 4.272354543209076e-01, /* 414 */ + -4.837444424629211e-02, /* 415 */ + }, { + -7.160949707031250e-02, /* 416 */ + 6.879730224609375e-01, /* 417 */ + 4.326324462890625e-01, /* 418 */ + -4.899597167968750e-02, /* 419 */ + }, { + -7.134988903999329e-02, /* 420 */ + 6.829293668270111e-01, /* 421 */ + 4.380346834659576e-01, /* 422 */ + -4.961416125297546e-02, /* 423 */ + }, { + -7.107853889465332e-02, /* 424 */ + 6.778657436370850e-01, /* 425 */ + 4.434416294097900e-01, /* 426 */ + -5.022883415222168e-02, /* 427 */ + }, { + -7.079562544822693e-02, /* 428 */ + 6.727826893329620e-01, /* 429 */ + 4.488527476787567e-01, /* 430 */ + -5.083981156349182e-02, /* 431 */ + }, { + -7.050132751464844e-02, /* 432 */ + 6.676807403564453e-01, /* 433 */ + 4.542675018310547e-01, /* 434 */ + -5.144691467285156e-02, /* 435 */ + }, { + -7.019582390785217e-02, /* 436 */ + 6.625604331493378e-01, /* 437 */ + 4.596853554248810e-01, /* 438 */ + -5.204996466636658e-02, /* 439 */ + }, { + -6.987929344177246e-02, /* 440 */ + 6.574223041534424e-01, /* 441 */ + 4.651057720184326e-01, /* 442 */ + -5.264878273010254e-02, /* 443 */ + }, { + -6.955191493034363e-02, /* 444 */ + 6.522668898105621e-01, /* 445 */ + 4.705282151699066e-01, /* 446 */ + -5.324319005012512e-02, /* 447 */ + }, { + -6.921386718750000e-02, /* 448 */ + 6.470947265625000e-01, /* 449 */ + 4.759521484375000e-01, /* 450 */ + -5.383300781250000e-02, /* 451 */ + }, { + -6.886532902717590e-02, /* 452 */ + 6.419063508510590e-01, /* 453 */ + 4.813770353794098e-01, /* 454 */ + -5.441805720329285e-02, /* 455 */ + }, { + -6.850647926330566e-02, /* 456 */ + 6.367022991180420e-01, /* 457 */ + 4.868023395538330e-01, /* 458 */ + -5.499815940856934e-02, /* 459 */ + }, { + -6.813749670982361e-02, /* 460 */ + 6.314831078052521e-01, /* 461 */ + 4.922275245189667e-01, /* 462 */ + -5.557313561439514e-02, /* 463 */ + }, { + -6.775856018066406e-02, /* 464 */ + 6.262493133544922e-01, /* 465 */ + 4.976520538330078e-01, /* 466 */ + -5.614280700683594e-02, /* 467 */ + }, { + -6.736984848976135e-02, /* 468 */ + 6.210014522075653e-01, /* 469 */ + 5.030753910541534e-01, /* 470 */ + -5.670699477195740e-02, /* 471 */ + }, { + -6.697154045104980e-02, /* 472 */ + 6.157400608062744e-01, /* 473 */ + 5.084969997406006e-01, /* 474 */ + -5.726552009582520e-02, /* 475 */ + }, { + -6.656381487846375e-02, /* 476 */ + 6.104656755924225e-01, /* 477 */ + 5.139163434505463e-01, /* 478 */ + -5.781820416450500e-02, /* 479 */ + }, { + -6.614685058593750e-02, /* 480 */ + 6.051788330078125e-01, /* 481 */ + 5.193328857421875e-01, /* 482 */ + -5.836486816406250e-02, /* 483 */ + }, { + -6.572082638740540e-02, /* 484 */ + 5.998800694942474e-01, /* 485 */ + 5.247460901737213e-01, /* 486 */ + -5.890533328056335e-02, /* 487 */ + }, { + -6.528592109680176e-02, /* 488 */ + 5.945699214935303e-01, /* 489 */ + 5.301554203033447e-01, /* 490 */ + -5.943942070007324e-02, /* 491 */ + }, { + -6.484231352806091e-02, /* 492 */ + 5.892489254474640e-01, /* 493 */ + 5.355603396892548e-01, /* 494 */ + -5.996695160865784e-02, /* 495 */ + }, { + -6.439018249511719e-02, /* 496 */ + 5.839176177978516e-01, /* 497 */ + 5.409603118896484e-01, /* 498 */ + -6.048774719238281e-02, /* 499 */ + }, { + -6.392970681190491e-02, /* 500 */ + 5.785765349864960e-01, /* 501 */ + 5.463548004627228e-01, /* 502 */ + -6.100162863731384e-02, /* 503 */ + }, { + -6.346106529235840e-02, /* 504 */ + 5.732262134552002e-01, /* 505 */ + 5.517432689666748e-01, /* 506 */ + -6.150841712951660e-02, /* 507 */ + }, { + -6.298443675041199e-02, /* 508 */ + 5.678671896457672e-01, /* 509 */ + 5.571251809597015e-01, /* 510 */ + -6.200793385505676e-02, /* 511 */ + }, { + -6.250000000000000e-02, /* 512 */ + 5.625000000000000e-01, /* 513 */ + 5.625000000000000e-01, /* 514 */ + -6.250000000000000e-02, /* 515 */ + }, { + -6.200793385505676e-02, /* 516 */ + 5.571251809597015e-01, /* 517 */ + 5.678671896457672e-01, /* 518 */ + -6.298443675041199e-02, /* 519 */ + }, { + -6.150841712951660e-02, /* 520 */ + 5.517432689666748e-01, /* 521 */ + 5.732262134552002e-01, /* 522 */ + -6.346106529235840e-02, /* 523 */ + }, { + -6.100162863731384e-02, /* 524 */ + 5.463548004627228e-01, /* 525 */ + 5.785765349864960e-01, /* 526 */ + -6.392970681190491e-02, /* 527 */ + }, { + -6.048774719238281e-02, /* 528 */ + 5.409603118896484e-01, /* 529 */ + 5.839176177978516e-01, /* 530 */ + -6.439018249511719e-02, /* 531 */ + }, { + -5.996695160865784e-02, /* 532 */ + 5.355603396892548e-01, /* 533 */ + 5.892489254474640e-01, /* 534 */ + -6.484231352806091e-02, /* 535 */ + }, { + -5.943942070007324e-02, /* 536 */ + 5.301554203033447e-01, /* 537 */ + 5.945699214935303e-01, /* 538 */ + -6.528592109680176e-02, /* 539 */ + }, { + -5.890533328056335e-02, /* 540 */ + 5.247460901737213e-01, /* 541 */ + 5.998800694942474e-01, /* 542 */ + -6.572082638740540e-02, /* 543 */ + }, { + -5.836486816406250e-02, /* 544 */ + 5.193328857421875e-01, /* 545 */ + 6.051788330078125e-01, /* 546 */ + -6.614685058593750e-02, /* 547 */ + }, { + -5.781820416450500e-02, /* 548 */ + 5.139163434505463e-01, /* 549 */ + 6.104656755924225e-01, /* 550 */ + -6.656381487846375e-02, /* 551 */ + }, { + -5.726552009582520e-02, /* 552 */ + 5.084969997406006e-01, /* 553 */ + 6.157400608062744e-01, /* 554 */ + -6.697154045104980e-02, /* 555 */ + }, { + -5.670699477195740e-02, /* 556 */ + 5.030753910541534e-01, /* 557 */ + 6.210014522075653e-01, /* 558 */ + -6.736984848976135e-02, /* 559 */ + }, { + -5.614280700683594e-02, /* 560 */ + 4.976520538330078e-01, /* 561 */ + 6.262493133544922e-01, /* 562 */ + -6.775856018066406e-02, /* 563 */ + }, { + -5.557313561439514e-02, /* 564 */ + 4.922275245189667e-01, /* 565 */ + 6.314831078052521e-01, /* 566 */ + -6.813749670982361e-02, /* 567 */ + }, { + -5.499815940856934e-02, /* 568 */ + 4.868023395538330e-01, /* 569 */ + 6.367022991180420e-01, /* 570 */ + -6.850647926330566e-02, /* 571 */ + }, { + -5.441805720329285e-02, /* 572 */ + 4.813770353794098e-01, /* 573 */ + 6.419063508510590e-01, /* 574 */ + -6.886532902717590e-02, /* 575 */ + }, { + -5.383300781250000e-02, /* 576 */ + 4.759521484375000e-01, /* 577 */ + 6.470947265625000e-01, /* 578 */ + -6.921386718750000e-02, /* 579 */ + }, { + -5.324319005012512e-02, /* 580 */ + 4.705282151699066e-01, /* 581 */ + 6.522668898105621e-01, /* 582 */ + -6.955191493034363e-02, /* 583 */ + }, { + -5.264878273010254e-02, /* 584 */ + 4.651057720184326e-01, /* 585 */ + 6.574223041534424e-01, /* 586 */ + -6.987929344177246e-02, /* 587 */ + }, { + -5.204996466636658e-02, /* 588 */ + 4.596853554248810e-01, /* 589 */ + 6.625604331493378e-01, /* 590 */ + -7.019582390785217e-02, /* 591 */ + }, { + -5.144691467285156e-02, /* 592 */ + 4.542675018310547e-01, /* 593 */ + 6.676807403564453e-01, /* 594 */ + -7.050132751464844e-02, /* 595 */ + }, { + -5.083981156349182e-02, /* 596 */ + 4.488527476787567e-01, /* 597 */ + 6.727826893329620e-01, /* 598 */ + -7.079562544822693e-02, /* 599 */ + }, { + -5.022883415222168e-02, /* 600 */ + 4.434416294097900e-01, /* 601 */ + 6.778657436370850e-01, /* 602 */ + -7.107853889465332e-02, /* 603 */ + }, { + -4.961416125297546e-02, /* 604 */ + 4.380346834659576e-01, /* 605 */ + 6.829293668270111e-01, /* 606 */ + -7.134988903999329e-02, /* 607 */ + }, { + -4.899597167968750e-02, /* 608 */ + 4.326324462890625e-01, /* 609 */ + 6.879730224609375e-01, /* 610 */ + -7.160949707031250e-02, /* 611 */ + }, { + -4.837444424629211e-02, /* 612 */ + 4.272354543209076e-01, /* 613 */ + 6.929961740970612e-01, /* 614 */ + -7.185718417167664e-02, /* 615 */ + }, { + -4.774975776672363e-02, /* 616 */ + 4.218442440032959e-01, /* 617 */ + 6.979982852935791e-01, /* 618 */ + -7.209277153015137e-02, /* 619 */ + }, { + -4.712209105491638e-02, /* 620 */ + 4.164593517780304e-01, /* 621 */ + 7.029788196086884e-01, /* 622 */ + -7.231608033180237e-02, /* 623 */ + }, { + -4.649162292480469e-02, /* 624 */ + 4.110813140869141e-01, /* 625 */ + 7.079372406005859e-01, /* 626 */ + -7.252693176269531e-02, /* 627 */ + }, { + -4.585853219032288e-02, /* 628 */ + 4.057106673717499e-01, /* 629 */ + 7.128730118274689e-01, /* 630 */ + -7.272514700889587e-02, /* 631 */ + }, { + -4.522299766540527e-02, /* 632 */ + 4.003479480743408e-01, /* 633 */ + 7.177855968475342e-01, /* 634 */ + -7.291054725646973e-02, /* 635 */ + }, { + -4.458519816398621e-02, /* 636 */ + 3.949936926364899e-01, /* 637 */ + 7.226744592189789e-01, /* 638 */ + -7.308295369148254e-02, /* 639 */ + }, { + -4.394531250000000e-02, /* 640 */ + 3.896484375000000e-01, /* 641 */ + 7.275390625000000e-01, /* 642 */ + -7.324218750000000e-02, /* 643 */ + }, { + -4.330351948738098e-02, /* 644 */ + 3.843127191066742e-01, /* 645 */ + 7.323788702487946e-01, /* 646 */ + -7.338806986808777e-02, /* 647 */ + }, { + -4.265999794006348e-02, /* 648 */ + 3.789870738983154e-01, /* 649 */ + 7.371933460235596e-01, /* 650 */ + -7.352042198181152e-02, /* 651 */ + }, { + -4.201492667198181e-02, /* 652 */ + 3.736720383167267e-01, /* 653 */ + 7.419819533824921e-01, /* 654 */ + -7.363906502723694e-02, /* 655 */ + }, { + -4.136848449707031e-02, /* 656 */ + 3.683681488037109e-01, /* 657 */ + 7.467441558837891e-01, /* 658 */ + -7.374382019042969e-02, /* 659 */ + }, { + -4.072085022926331e-02, /* 660 */ + 3.630759418010712e-01, /* 661 */ + 7.514794170856476e-01, /* 662 */ + -7.383450865745544e-02, /* 663 */ + }, { + -4.007220268249512e-02, /* 664 */ + 3.577959537506104e-01, /* 665 */ + 7.561872005462646e-01, /* 666 */ + -7.391095161437988e-02, /* 667 */ + }, { + -3.942272067070007e-02, /* 668 */ + 3.525287210941315e-01, /* 669 */ + 7.608669698238373e-01, /* 670 */ + -7.397297024726868e-02, /* 671 */ + }, { + -3.877258300781250e-02, /* 672 */ + 3.472747802734375e-01, /* 673 */ + 7.655181884765625e-01, /* 674 */ + -7.402038574218750e-02, /* 675 */ + }, { + -3.812196850776672e-02, /* 676 */ + 3.420346677303314e-01, /* 677 */ + 7.701403200626373e-01, /* 678 */ + -7.405301928520203e-02, /* 679 */ + }, { + -3.747105598449707e-02, /* 680 */ + 3.368089199066162e-01, /* 681 */ + 7.747328281402588e-01, /* 682 */ + -7.407069206237793e-02, /* 683 */ + }, { + -3.682002425193787e-02, /* 684 */ + 3.315980732440948e-01, /* 685 */ + 7.792951762676239e-01, /* 686 */ + -7.407322525978088e-02, /* 687 */ + }, { + -3.616905212402344e-02, /* 688 */ + 3.264026641845703e-01, /* 689 */ + 7.838268280029297e-01, /* 690 */ + -7.406044006347656e-02, /* 691 */ + }, { + -3.551831841468811e-02, /* 692 */ + 3.212232291698456e-01, /* 693 */ + 7.883272469043732e-01, /* 694 */ + -7.403215765953064e-02, /* 695 */ + }, { + -3.486800193786621e-02, /* 696 */ + 3.160603046417236e-01, /* 697 */ + 7.927958965301514e-01, /* 698 */ + -7.398819923400879e-02, /* 699 */ + }, { + -3.421828150749207e-02, /* 700 */ + 3.109144270420074e-01, /* 701 */ + 7.972322404384613e-01, /* 702 */ + -7.392838597297668e-02, /* 703 */ + }, { + -3.356933593750000e-02, /* 704 */ + 3.057861328125000e-01, /* 705 */ + 8.016357421875000e-01, /* 706 */ + -7.385253906250000e-02, /* 707 */ + }, { + -3.292134404182434e-02, /* 708 */ + 3.006759583950043e-01, /* 709 */ + 8.060058653354645e-01, /* 710 */ + -7.376047968864441e-02, /* 711 */ + }, { + -3.227448463439941e-02, /* 712 */ + 2.955844402313232e-01, /* 713 */ + 8.103420734405518e-01, /* 714 */ + -7.365202903747559e-02, /* 715 */ + }, { + -3.162893652915955e-02, /* 716 */ + 2.905121147632599e-01, /* 717 */ + 8.146438300609589e-01, /* 718 */ + -7.352700829505920e-02, /* 719 */ + }, { + -3.098487854003906e-02, /* 720 */ + 2.854595184326172e-01, /* 721 */ + 8.189105987548828e-01, /* 722 */ + -7.338523864746094e-02, /* 723 */ + }, { + -3.034248948097229e-02, /* 724 */ + 2.804271876811981e-01, /* 725 */ + 8.231418430805206e-01, /* 726 */ + -7.322654128074646e-02, /* 727 */ + }, { + -2.970194816589355e-02, /* 728 */ + 2.754156589508057e-01, /* 729 */ + 8.273370265960693e-01, /* 730 */ + -7.305073738098145e-02, /* 731 */ + }, { + -2.906343340873718e-02, /* 732 */ + 2.704254686832428e-01, /* 733 */ + 8.314956128597260e-01, /* 734 */ + -7.285764813423157e-02, /* 735 */ + }, { + -2.842712402343750e-02, /* 736 */ + 2.654571533203125e-01, /* 737 */ + 8.356170654296875e-01, /* 738 */ + -7.264709472656250e-02, /* 739 */ + }, { + -2.779319882392883e-02, /* 740 */ + 2.605112493038177e-01, /* 741 */ + 8.397008478641510e-01, /* 742 */ + -7.241889834403992e-02, /* 743 */ + }, { + -2.716183662414551e-02, /* 744 */ + 2.555882930755615e-01, /* 745 */ + 8.437464237213135e-01, /* 746 */ + -7.217288017272949e-02, /* 747 */ + }, { + -2.653321623802185e-02, /* 748 */ + 2.506888210773468e-01, /* 749 */ + 8.477532565593719e-01, /* 750 */ + -7.190886139869690e-02, /* 751 */ + }, { + -2.590751647949219e-02, /* 752 */ + 2.458133697509766e-01, /* 753 */ + 8.517208099365234e-01, /* 754 */ + -7.162666320800781e-02, /* 755 */ + }, { + -2.528491616249084e-02, /* 756 */ + 2.409624755382538e-01, /* 757 */ + 8.556485474109650e-01, /* 758 */ + -7.132610678672791e-02, /* 759 */ + }, { + -2.466559410095215e-02, /* 760 */ + 2.361366748809814e-01, /* 761 */ + 8.595359325408936e-01, /* 762 */ + -7.100701332092285e-02, /* 763 */ + }, { + -2.404972910881042e-02, /* 764 */ + 2.313365042209625e-01, /* 765 */ + 8.633824288845062e-01, /* 766 */ + -7.066920399665833e-02, /* 767 */ + }, { + -2.343750000000000e-02, /* 768 */ + 2.265625000000000e-01, /* 769 */ + 8.671875000000000e-01, /* 770 */ + -7.031250000000000e-02, /* 771 */ + }, { + -2.282908558845520e-02, /* 772 */ + 2.218151986598969e-01, /* 773 */ + 8.709506094455719e-01, /* 774 */ + -6.993672251701355e-02, /* 775 */ + }, { + -2.222466468811035e-02, /* 776 */ + 2.170951366424561e-01, /* 777 */ + 8.746712207794189e-01, /* 778 */ + -6.954169273376465e-02, /* 779 */ + }, { + -2.162441611289978e-02, /* 780 */ + 2.124028503894806e-01, /* 781 */ + 8.783487975597382e-01, /* 782 */ + -6.912723183631897e-02, /* 783 */ + }, { + -2.102851867675781e-02, /* 784 */ + 2.077388763427734e-01, /* 785 */ + 8.819828033447266e-01, /* 786 */ + -6.869316101074219e-02, /* 787 */ + }, { + -2.043715119361877e-02, /* 788 */ + 2.031037509441376e-01, /* 789 */ + 8.855727016925812e-01, /* 790 */ + -6.823930144309998e-02, /* 791 */ + }, { + -1.985049247741699e-02, /* 792 */ + 1.984980106353760e-01, /* 793 */ + 8.891179561614990e-01, /* 794 */ + -6.776547431945801e-02, /* 795 */ + }, { + -1.926872134208679e-02, /* 796 */ + 1.939221918582916e-01, /* 797 */ + 8.926180303096771e-01, /* 798 */ + -6.727150082588196e-02, /* 799 */ + }, { + -1.869201660156250e-02, /* 800 */ + 1.893768310546875e-01, /* 801 */ + 8.960723876953125e-01, /* 802 */ + -6.675720214843750e-02, /* 803 */ + }, { + -1.812055706977844e-02, /* 804 */ + 1.848624646663666e-01, /* 805 */ + 8.994804918766022e-01, /* 806 */ + -6.622239947319031e-02, /* 807 */ + }, { + -1.755452156066895e-02, /* 808 */ + 1.803796291351318e-01, /* 809 */ + 9.028418064117432e-01, /* 810 */ + -6.566691398620605e-02, /* 811 */ + }, { + -1.699408888816833e-02, /* 812 */ + 1.759288609027863e-01, /* 813 */ + 9.061557948589325e-01, /* 814 */ + -6.509056687355042e-02, /* 815 */ + }, { + -1.643943786621094e-02, /* 816 */ + 1.715106964111328e-01, /* 817 */ + 9.094219207763672e-01, /* 818 */ + -6.449317932128906e-02, /* 819 */ + }, { + -1.589074730873108e-02, /* 820 */ + 1.671256721019745e-01, /* 821 */ + 9.126396477222443e-01, /* 822 */ + -6.387457251548767e-02, /* 823 */ + }, { + -1.534819602966309e-02, /* 824 */ + 1.627743244171143e-01, /* 825 */ + 9.158084392547607e-01, /* 826 */ + -6.323456764221191e-02, /* 827 */ + }, { + -1.481196284294128e-02, /* 828 */ + 1.584571897983551e-01, /* 829 */ + 9.189277589321136e-01, /* 830 */ + -6.257298588752747e-02, /* 831 */ + }, { + -1.428222656250000e-02, /* 832 */ + 1.541748046875000e-01, /* 833 */ + 9.219970703125000e-01, /* 834 */ + -6.188964843750000e-02, /* 835 */ + }, { + -1.375916600227356e-02, /* 836 */ + 1.499277055263519e-01, /* 837 */ + 9.250158369541168e-01, /* 838 */ + -6.118437647819519e-02, /* 839 */ + }, { + -1.324295997619629e-02, /* 840 */ + 1.457164287567139e-01, /* 841 */ + 9.279835224151611e-01, /* 842 */ + -6.045699119567871e-02, /* 843 */ + }, { + -1.273378729820251e-02, /* 844 */ + 1.415415108203888e-01, /* 845 */ + 9.308995902538300e-01, /* 846 */ + -5.970731377601624e-02, /* 847 */ + }, { + -1.223182678222656e-02, /* 848 */ + 1.374034881591797e-01, /* 849 */ + 9.337635040283203e-01, /* 850 */ + -5.893516540527344e-02, /* 851 */ + }, { + -1.173725724220276e-02, /* 852 */ + 1.333028972148895e-01, /* 853 */ + 9.365747272968292e-01, /* 854 */ + -5.814036726951599e-02, /* 855 */ + }, { + -1.125025749206543e-02, /* 856 */ + 1.292402744293213e-01, /* 857 */ + 9.393327236175537e-01, /* 858 */ + -5.732274055480957e-02, /* 859 */ + }, { + -1.077100634574890e-02, /* 860 */ + 1.252161562442780e-01, /* 861 */ + 9.420369565486908e-01, /* 862 */ + -5.648210644721985e-02, /* 863 */ + }, { + -1.029968261718750e-02, /* 864 */ + 1.212310791015625e-01, /* 865 */ + 9.446868896484375e-01, /* 866 */ + -5.561828613281250e-02, /* 867 */ + }, { + -9.836465120315552e-03, /* 868 */ + 1.172855794429779e-01, /* 869 */ + 9.472819864749908e-01, /* 870 */ + -5.473110079765320e-02, /* 871 */ + }, { + -9.381532669067383e-03, /* 872 */ + 1.133801937103271e-01, /* 873 */ + 9.498217105865479e-01, /* 874 */ + -5.382037162780762e-02, /* 875 */ + }, { + -8.935064077377319e-03, /* 876 */ + 1.095154583454132e-01, /* 877 */ + 9.523055255413055e-01, /* 878 */ + -5.288591980934143e-02, /* 879 */ + }, { + -8.497238159179688e-03, /* 880 */ + 1.056919097900391e-01, /* 881 */ + 9.547328948974609e-01, /* 882 */ + -5.192756652832031e-02, /* 883 */ + }, { + -8.068233728408813e-03, /* 884 */ + 1.019100844860077e-01, /* 885 */ + 9.571032822132111e-01, /* 886 */ + -5.094513297080994e-02, /* 887 */ + }, { + -7.648229598999023e-03, /* 888 */ + 9.817051887512207e-02, /* 889 */ + 9.594161510467529e-01, /* 890 */ + -4.993844032287598e-02, /* 891 */ + }, { + -7.237404584884644e-03, /* 892 */ + 9.447374939918518e-02, /* 893 */ + 9.616709649562836e-01, /* 894 */ + -4.890730977058411e-02, /* 895 */ + }, { + -6.835937500000000e-03, /* 896 */ + 9.082031250000000e-02, /* 897 */ + 9.638671875000000e-01, /* 898 */ + -4.785156250000000e-02, /* 899 */ + }, { + -6.444007158279419e-03, /* 900 */ + 8.721074461936951e-02, /* 901 */ + 9.660042822360992e-01, /* 902 */ + -4.677101969718933e-02, /* 903 */ + }, { + -6.061792373657227e-03, /* 904 */ + 8.364558219909668e-02, /* 905 */ + 9.680817127227783e-01, /* 906 */ + -4.566550254821777e-02, /* 907 */ + }, { + -5.689471960067749e-03, /* 908 */ + 8.012536168098450e-02, /* 909 */ + 9.700989425182343e-01, /* 910 */ + -4.453483223915100e-02, /* 911 */ + }, { + -5.327224731445312e-03, /* 912 */ + 7.665061950683594e-02, /* 913 */ + 9.720554351806641e-01, /* 914 */ + -4.337882995605469e-02, /* 915 */ + }, { + -4.975229501724243e-03, /* 916 */ + 7.322189211845398e-02, /* 917 */ + 9.739506542682648e-01, /* 918 */ + -4.219731688499451e-02, /* 919 */ + }, { + -4.633665084838867e-03, /* 920 */ + 6.983971595764160e-02, /* 921 */ + 9.757840633392334e-01, /* 922 */ + -4.099011421203613e-02, /* 923 */ + }, { + -4.302710294723511e-03, /* 924 */ + 6.650462746620178e-02, /* 925 */ + 9.775551259517670e-01, /* 926 */ + -3.975704312324524e-02, /* 927 */ + }, { + -3.982543945312500e-03, /* 928 */ + 6.321716308593750e-02, /* 929 */ + 9.792633056640625e-01, /* 930 */ + -3.849792480468750e-02, /* 931 */ + }, { + -3.673344850540161e-03, /* 932 */ + 5.997785925865173e-02, /* 933 */ + 9.809080660343170e-01, /* 934 */ + -3.721258044242859e-02, /* 935 */ + }, { + -3.375291824340820e-03, /* 936 */ + 5.678725242614746e-02, /* 937 */ + 9.824888706207275e-01, /* 938 */ + -3.590083122253418e-02, /* 939 */ + }, { + -3.088563680648804e-03, /* 940 */ + 5.364587903022766e-02, /* 941 */ + 9.840051829814911e-01, /* 942 */ + -3.456249833106995e-02, /* 943 */ + }, { + -2.813339233398438e-03, /* 944 */ + 5.055427551269531e-02, /* 945 */ + 9.854564666748047e-01, /* 946 */ + -3.319740295410156e-02, /* 947 */ + }, { + -2.549797296524048e-03, /* 948 */ + 4.751297831535339e-02, /* 949 */ + 9.868421852588654e-01, /* 950 */ + -3.180536627769470e-02, /* 951 */ + }, { + -2.298116683959961e-03, /* 952 */ + 4.452252388000488e-02, /* 953 */ + 9.881618022918701e-01, /* 954 */ + -3.038620948791504e-02, /* 955 */ + }, { + -2.058476209640503e-03, /* 956 */ + 4.158344864845276e-02, /* 957 */ + 9.894147813320160e-01, /* 958 */ + -2.893975377082825e-02, /* 959 */ + }, { + -1.831054687500000e-03, /* 960 */ + 3.869628906250000e-02, /* 961 */ + 9.906005859375000e-01, /* 962 */ + -2.746582031250000e-02, /* 963 */ + }, { + -1.616030931472778e-03, /* 964 */ + 3.586158156394958e-02, /* 965 */ + 9.917186796665192e-01, /* 966 */ + -2.596423029899597e-02, /* 967 */ + }, { + -1.413583755493164e-03, /* 968 */ + 3.307986259460449e-02, /* 969 */ + 9.927685260772705e-01, /* 970 */ + -2.443480491638184e-02, /* 971 */ + }, { + -1.223891973495483e-03, /* 972 */ + 3.035166859626770e-02, /* 973 */ + 9.937495887279510e-01, /* 974 */ + -2.287736535072327e-02, /* 975 */ + }, { + -1.047134399414062e-03, /* 976 */ + 2.767753601074219e-02, /* 977 */ + 9.946613311767578e-01, /* 978 */ + -2.129173278808594e-02, /* 979 */ + }, { + -8.834898471832275e-04, /* 980 */ + 2.505800127983093e-02, /* 981 */ + 9.955032169818878e-01, /* 982 */ + -1.967772841453552e-02, /* 983 */ + }, { + -7.331371307373047e-04, /* 984 */ + 2.249360084533691e-02, /* 985 */ + 9.962747097015381e-01, /* 986 */ + -1.803517341613770e-02, /* 987 */ + }, { + -5.962550640106201e-04, /* 988 */ + 1.998487114906311e-02, /* 989 */ + 9.969752728939056e-01, /* 990 */ + -1.636388897895813e-02, /* 991 */ + }, { + -4.730224609375000e-04, /* 992 */ + 1.753234863281250e-02, /* 993 */ + 9.976043701171875e-01, /* 994 */ + -1.466369628906250e-02, /* 995 */ + }, { + -3.636181354522705e-04, /* 996 */ + 1.513656973838806e-02, /* 997 */ + 9.981614649295807e-01, /* 998 */ + -1.293441653251648e-02, /* 999 */ + }, { + -2.682209014892578e-04, /* 1000 */ + 1.279807090759277e-02, /* 1001 */ + 9.986460208892822e-01, /* 1002 */ + -1.117587089538574e-02, /* 1003 */ + }, { + -1.870095729827881e-04, /* 1004 */ + 1.051738858222961e-02, /* 1005 */ + 9.990575015544891e-01, /* 1006 */ + -9.387880563735962e-03, /* 1007 */ + }, { + -1.201629638671875e-04, /* 1008 */ + 8.295059204101562e-03, /* 1009 */ + 9.993953704833984e-01, /* 1010 */ + -7.570266723632812e-03, /* 1011 */ + }, { + -6.785988807678223e-05, /* 1012 */ + 6.131619215011597e-03, /* 1013 */ + 9.996590912342072e-01, /* 1014 */ + -5.722850561141968e-03, /* 1015 */ + }, { + -3.027915954589844e-05, /* 1016 */ + 4.027605056762695e-03, /* 1017 */ + 9.998481273651123e-01, /* 1018 */ + -3.845453262329102e-03, /* 1019 */ + }, { + -7.599592208862305e-06, /* 1020 */ + 1.983553171157837e-03, /* 1021 */ + 9.999619424343109e-01, /* 1022 */ + -1.937896013259888e-03, /* 1023 */ + } +}; + +static const fluid_real_t sinc_table7[256][7] = { + { + 2.375620125729980e-02, /* 0 */ + -1.290049686942476e-01, /* 1 */ + 5.998790953453343e-01, /* 2 */ + 6.103020511314905e-01, /* 3 */ + -1.304058543975903e-01, /* 4 */ + 2.418010665366927e-02, /* 5 */ + -2.798064002790454e-07, /* 6 */ + }, { + 2.354065170871666e-02, /* 7 */ + -1.282805558938982e-01, /* 8 */ + 5.946483199408858e-01, /* 9 */ + 6.154931623267351e-01, /* 10 */ + -1.310817379215285e-01, /* 11 */ + 2.438827747279956e-02, /* 12 */ + -1.120220972351802e-06, /* 13 */ + }, { + 2.332282679065955e-02, /* 14 */ + -1.275405562274653e-01, /* 15 */ + 5.894053926563386e-01, /* 16 */ + 6.206699834160688e-01, /* 17 */ + -1.317408559206581e-01, /* 18 */ + 2.459380290371239e-02, /* 19 */ + -2.522356622734990e-06, /* 20 */ + }, { + 2.310281775655174e-02, /* 21 */ + -1.267852645808413e-01, /* 22 */ + 5.841508484795060e-01, /* 23 */ + 6.258319806421593e-01, /* 24 */ + -1.323829141999531e-01, /* 25 */ + 2.479658928687493e-02, /* 26 */ + -4.486817393493708e-06, /* 27 */ + }, { + 2.288071532172811e-02, /* 28 */ + -1.260149758298408e-01, /* 29 */ + 5.788852224239674e-01, /* 30 */ + 6.309786207146856e-01, /* 31 */ + -1.330076188523975e-01, /* 32 */ + 2.499654254034837e-02, /* 33 */ + -7.013696123785544e-06, /* 34 */ + }, { + 2.265660964514263e-02, /* 35 */ + -1.252299847913509e-01, /* 36 */ + 5.736090494558752e-01, /* 37 */ + 6.361093708841161e-01, /* 38 */ + -1.336146763094198e-01, /* 39 */ + 2.519356818002896e-02, /* 40 */ + -1.010257230258042e-05, /* 41 */ + }, { + 2.243059031136537e-02, /* 42 */ + -1.244305861747393e-01, /* 43 */ + 5.683228644208926e-01, /* 44 */ + 6.412236990155202e-01, /* 45 */ + -1.342037933915221e-01, /* 46 */ + 2.538757134015553e-02, /* 47 */ + -1.375251011368080e-05, /* 48 */ + }, { + 2.220274631287172e-02, /* 49 */ + -1.236170745335310e-01, /* 50 */ + 5.630272019712755e-01, /* 51 */ + 6.463210736624057e-01, /* 52 */ + -1.347746773590917e-01, /* 53 */ + 2.557845679407980e-02, /* 54 */ + -1.796205667443242e-05, /* 55 */ + }, { + 2.197316603262602e-02, /* 56 */ + -1.227897442173580e-01, /* 57 */ + 5.577225964931086e-01, /* 58 */ + 6.514009641405650e-01, /* 59 */ + -1.353270359633906e-01, /* 60 */ + 2.576612897529643e-02, /* 61 */ + -2.272924046911682e-05, /* 62 */ + }, { + 2.174193722696236e-02, /* 63 */ + -1.219488893241928e-01, /* 64 */ + 5.524095820337069e-01, /* 65 */ + 6.564628406019232e-01, /* 66 */ + -1.358605774977103e-01, /* 67 */ + 2.595049199872917e-02, /* 68 */ + -2.805156997831240e-05, /* 69 */ + }, { + 2.150914700876424e-02, /* 70 */ + -1.210948036528713e-01, /* 71 */ + 5.470886922291980e-01, /* 72 */ + 6.615061741083712e-01, /* 73 */ + -1.363750108486864e-01, /* 74 */ + 2.613144968226988e-02, /* 75 */ + -3.392603250514114e-05, /* 76 */ + }, { + 2.127488183094605e-02, /* 77 */ + -1.202277806559141e-01, /* 78 */ + 5.417604602322907e-01, /* 79 */ + 6.665304367055752e-01, /* 80 */ + -1.368700455477614e-01, /* 81 */ + 2.630890556856650e-02, /* 82 */ + -4.034909319948082e-05, /* 83 */ + }, { + 2.103922747023789e-02, /* 84 */ + -1.193481133926526e-01, /* 85 */ + 5.364254186402488e-01, /* 86 */ + 6.715351014967476e-01, /* 87 */ + -1.373453918227895e-01, /* 88 */ + 2.648276294705649e-02, /* 89 */ + -4.731669428110093e-05, /* 90 */ + }, { + 2.080226901127631e-02, /* 91 */ + -1.184560944826678e-01, /* 92 */ + 5.310840994230748e-01, /* 93 */ + 6.765196427163698e-01, /* 94 */ + -1.378007606497726e-01, /* 95 */ + 2.665292487624222e-02, /* 96 */ + -5.482425446254296e-05, /* 97 */ + }, { + 2.056409083100217e-02, /* 98 */ + -1.175520160595501e-01, /* 99 */ + 5.257370338519197e-01, /* 100 */ + 6.814835358038533e-01, /* 101 */ + -1.382358638047184e-01, /* 102 */ + 2.681929420620386e-02, /* 103 */ + -6.286666857267136e-05, /* 104 */ + }, { + 2.032477658336845e-02, /* 105 */ + -1.166361697249849e-01, /* 106 */ + 5.203847524277286e-01, /* 107 */ + 6.864262574771270e-01, /* 108 */ + -1.386504139156142e-01, /* 109 */ + 2.698177360134680e-02, /* 110 */ + -7.143830738156712e-05, /* 111 */ + }, { + 2.008440918435909e-02, /* 112 */ + -1.157088465031742e-01, /* 113 */ + 5.150277848101327e-01, /* 114 */ + 6.913472858061384e-01, /* 115 */ + -1.390441245145027e-01, /* 116 */ + 2.714026556337870e-02, /* 117 */ + -8.053301762762107e-05, /* 118 */ + }, { + 1.984307079732106e-02, /* 119 */ + -1.147703367955984e-01, /* 120 */ + 5.096666597466010e-01, /* 121 */ + 6.962461002862578e-01, /* 122 */ + -1.394167100896560e-01, /* 123 */ + 2.729467245451285e-02, /* 124 */ + -9.014412224732896e-05, /* 125 */ + }, { + 1.960084281861067e-02, /* 126 */ + -1.138209303361282e-01, /* 127 */ + 5.043019050018616e-01, /* 128 */ + 7.011221819115717e-01, /* 129 */ + -1.397678861378340e-01, /* 130 */ + 2.744489652089330e-02, /* 131 */ + -1.002644208085391e-04, /* 132 */ + }, { + 1.935780586355643e-02, /* 133 */ + -1.128609161464899e-01, /* 134 */ + 4.989340472876037e-01, /* 135 */ + 7.059750132480542e-01, /* 136 */ + -1.400973692166212e-01, /* 137 */ + 2.759083991623796e-02, /* 138 */ + -1.108861901476344e-04, /* 139 */ + }, { + 1.911403975273935e-02, /* 140 */ + -1.118905824920952e-01, /* 141 */ + 4.935636121924722e-01, /* 142 */ + 7.108040785066047e-01, /* 143 */ + -1.404048769968304e-01, /* 144 */ + 2.773240472569498e-02, /* 145 */ + -1.220011852110915e-04, /* 146 */ + }, { + 1.886962349859249e-02, /* 147 */ + -1.109102168382377e-01, /* 148 */ + 4.881911241123659e-01, /* 149 */ + 7.156088636159380e-01, /* 150 */ + -1.406901283149657e-01, /* 151 */ + 2.786949298990845e-02, /* 152 */ + -1.336006401019428e-04, /* 153 */ + }, { + 1.862463529232039e-02, /* 154 */ + -1.099201058066671e-01, /* 155 */ + 4.828171061810496e-01, /* 156 */ + 7.203888562953171e-01, /* 157 */ + -1.409528432257348e-01, /* 158 */ + 2.800200672928881e-02, /* 159 */ + -1.456752693314445e-04, /* 160 */ + }, { + 1.837915249114045e-02, /* 161 */ + -1.089205351325436e-01, /* 162 */ + 4.774420802010910e-01, /* 163 */ + 7.251435461271148e-01, /* 164 */ + -1.411927430545998e-01, /* 165 */ + 2.812984796848375e-02, /* 166 */ + -1.582152692763085e-04, /* 167 */ + }, { + 1.813325160584695e-02, /* 168 */ + -1.079117896217818e-01, /* 169 */ + 4.720665665751356e-01, /* 170 */ + 7.298724246291924e-01, /* 171 */ + -1.414095504503600e-01, /* 172 */ + 2.825291876104482e-02, /* 173 */ + -1.712103198416544e-04, /* 174 */ + }, { + 1.788700828869835e-02, /* 175 */ + -1.068941531087891e-01, /* 176 */ + 4.666910842375266e-01, /* 177 */ + 7.345749853270843e-01, /* 178 */ + -1.416029894377547e-01, /* 179 */ + 2.837112121428517e-02, /* 180 */ + -1.846495863300355e-04, /* 181 */ + }, { + 1.764049732162978e-02, /* 182 */ + -1.058679084146052e-01, /* 183 */ + 4.613161505862837e-01, /* 184 */ + 7.392507238259753e-01, /* 185 */ + -1.417727854700776e-01, /* 186 */ + 2.848435751432410e-02, /* 187 */ + -1.985217215164836e-04, /* 188 */ + }, { + 1.739379260479069e-02, /* 189 */ + -1.048333373054486e-01, /* 190 */ + 4.559422814154492e-01, /* 191 */ + 7.438991378824603e-01, /* 192 */ + -1.419186654817930e-01, /* 193 */ + 2.859252995131316e-02, /* 194 */ + -2.128148679298167e-04, /* 195 */ + }, { + 1.714696714540915e-02, /* 196 */ + -1.037907204516760e-01, /* 197 */ + 4.505699908478140e-01, /* 198 */ + 7.485197274760710e-01, /* 199 */ + -1.420403579411441e-01, /* 200 */ + 2.869554094483946e-02, /* 201 */ + -2.275166603400509e-04, /* 202 */ + }, { + 1.690009304698279e-02, /* 203 */ + -1.027403373871614e-01, /* 204 */ + 4.451997912680325e-01, /* 205 */ + 7.531119948805626e-01, /* 206 */ + -1.421375929027446e-01, /* 207 */ + 2.879329306950119e-02, /* 208 */ + -2.426142284520608e-04, /* 209 */ + }, { + 1.665324149879781e-02, /* 210 */ + -1.016824664690990e-01, /* 211 */ + 4.398321932561375e-01, /* 212 */ + 7.576754447349440e-01, /* 213 */ + -1.422101020601427e-01, /* 214 */ + 2.888568908065016e-02, /* 215 */ + -2.580941998051696e-04, /* 216 */ + }, { + 1.640648276577594e-02, /* 217 */ + -1.006173848382378e-01, /* 218 */ + 4.344677055214644e-01, /* 219 */ + 7.622095841142430e-01, /* 220 */ + -1.422576187983489e-01, /* 221 */ + 2.897263194029685e-02, /* 222 */ + -2.739427028786713e-04, /* 223 */ + }, { + 1.615988617865028e-02, /* 224 */ + -9.954536837955191e-02, /* 225 */ + 4.291068348369969e-01, /* 226 */ + 7.667139225999916e-01, /* 227 */ + -1.422798782463173e-01, /* 228 */ + 2.905402484317260e-02, /* 229 */ + -2.901453704029424e-04, /* 230 */ + }, { + 1.591352012446994e-02, /* 231 */ + -9.846669168335127e-02, /* 232 */ + 4.237500859741424e-01, /* 233 */ + 7.711879723504229e-01, /* 234 */ + -1.422766173293711e-01, /* 235 */ + 2.912977124294393e-02, /* 236 */ + -3.066873428758958e-04, /* 237 */ + }, { + 1.566745203743416e-02, /* 238 */ + -9.738162800684201e-02, /* 239 */ + 4.183979616379481e-01, /* 240 */ + 7.756312481703652e-01, /* 241 */ + -1.422475748215626e-01, /* 242 */ + 2.919977487857369e-02, /* 243 */ + -3.235532722844501e-04, /* 244 */ + }, { + 1.542174839005620e-02, /* 245 */ + -9.629044923613632e-02, /* 246 */ + 4.130509624027673e-01, /* 247 */ + 7.800432675808223e-01, /* 248 */ + -1.421924913979572e-01, /* 249 */ + 2.926393980082415e-02, /* 250 */ + -3.407273260304884e-04, /* 251 */ + }, { + 1.517647468465644e-02, /* 252 */ + -9.519342584872197e-02, /* 253 */ + 4.077095866483865e-01, /* 254 */ + 7.844235508882289e-01, /* 255 */ + -1.421111096868331e-01, /* 256 */ + 2.932217039889637e-02, /* 257 */ + -3.581931910609877e-04, /* 258 */ + }, { + 1.493169544518567e-02, /* 259 */ + -9.409082687639277e-02, /* 260 */ + 4.023743304966226e-01, /* 261 */ + 7.887716212533704e-01, /* 262 */ + -1.420031743217853e-01, /* 263 */ + 2.937437142720069e-02, /* 264 */ + -3.759340782016456e-04, /* 265 */ + }, { + 1.468747420937781e-02, /* 266 */ + -9.298291986864780e-02, /* 267 */ + 3.970456877483993e-01, /* 268 */ + 7.930870047599514e-01, /* 269 */ + -1.418684319937252e-01, /* 270 */ + 2.942044803225294e-02, /* 271 */ + -3.939327266934505e-04, /* 272 */ + }, { + 1.444387352123256e-02, /* 273 */ + -9.186997085656183e-02, /* 274 */ + 3.917241498213130e-01, /* 275 */ + 7.973692304828067e-01, /* 276 */ + -1.417066315027663e-01, /* 277 */ + 2.946030577969092e-02, /* 278 */ + -4.121714089315939e-04, /* 279 */ + }, { + 1.420095492382687e-02, /* 280 */ + -9.075224431713386e-02, /* 281 */ + 3.864102056876984e-01, /* 282 */ + 8.016178305557399e-01, /* 283 */ + -1.415175238099844e-01, /* 284 */ + 2.949385068140553e-02, /* 285 */ + -4.306319354058826e-04, /* 286 */ + }, { + 1.395877895245621e-02, /* 287 */ + -8.963000313811628e-02, /* 288 */ + 3.811043418132007e-01, /* 289 */ + 8.058323402389781e-01, /* 290 */ + -1.413008620890449e-01, /* 291 */ + 2.952098922278122e-02, /* 292 */ + -4.492956598419907e-04, /* 293 */ + }, { + 1.371740512810407e-02, /* 294 */ + -8.850350858333141e-02, /* 295 */ + 3.758070420958670e-01, /* 296 */ + 8.100122979862356e-01, /* 297 */ + -1.410564017776856e-01, /* 298 */ + 2.954162839003991e-02, /* 299 */ + -4.681434845426153e-04, /* 300 */ + }, { + 1.347689195124034e-02, /* 301 */ + -8.737302025847754e-02, /* 302 */ + 3.705187878057628e-01, /* 303 */ + 8.141572455113678e-01, /* 304 */ + -1.407839006290460e-01, /* 305 */ + 2.955567569768274e-02, /* 306 */ + -4.871558659276469e-04, /* 307 */ + }, { + 1.323729689594689e-02, /* 308 */ + -8.623879607743025e-02, /* 309 */ + 3.652400575251253e-01, /* 310 */ + 8.182667278546104e-01, /* 311 */ + -1.404831187628331e-01, /* 312 */ + 2.956303921602418e-02, /* 313 */ + -5.063128202724816e-04, /* 314 */ + }, { + 1.299867640437090e-02, /* 315 */ + -8.510109222904338e-02, /* 316 */ + 3.599713270890607e-01, /* 317 */ + 8.223402934483920e-01, /* 318 */ + -1.401538187163136e-01, /* 319 */ + 2.956362759881255e-02, /* 320 */ + -5.255939296432825e-04, /* 321 */ + }, { + 1.276108588150466e-02, /* 322 */ + -8.396016314445182e-02, /* 323 */ + 3.547130695267950e-01, /* 324 */ + 8.263774941827043e-01, /* 325 */ + -1.397957654951237e-01, /* 326 */ + 2.955735011093100e-02, /* 327 */ + -5.449783480282249e-04, /* 328 */ + }, { + 1.252457969029095e-02, /* 329 */ + -8.281626146488272e-02, /* 330 */ + 3.494657550034874e-01, /* 331 */ + 8.303778854700258e-01, /* 332 */ + -1.394087266238854e-01, /* 333 */ + 2.954411665617338e-02, /* 334 */ + -5.644448076635753e-04, /* 335 */ + }, { + 1.228921114705370e-02, /* 336 */ + -8.166963800997633e-02, /* 337 */ + 3.442298507626138e-01, /* 338 */ + 8.343410263097801e-01, /* 339 */ + -1.389924721966199e-01, /* 340 */ + 2.952383780508903e-02, /* 341 */ + -5.839716255532901e-04, /* 342 */ + }, { + 1.205503251725260e-02, /* 343 */ + -8.052054174662254e-02, /* 344 */ + 3.390058210689310e-01, /* 345 */ + 8.382664793523271e-01, /* 346 */ + -1.385467749269494e-01, /* 347 */ + 2.949642482289040e-02, /* 348 */ + -6.035367101809801e-04, /* 349 */ + }, { + 1.182209501156100e-02, /* 350 */ + -7.936921975831460e-02, /* 351 */ + 3.337941271520264e-01, /* 352 */ + 8.421538109624669e-01, /* 353 */ + -1.380714101980755e-01, /* 354 */ + 2.946178969741759e-02, /* 355 */ + -6.231175684128511e-04, /* 356 */ + }, { + 1.159044878226562e-02, /* 357 */ + -7.821591721502538e-02, /* 358 */ + 3.285952271504655e-01, /* 359 */ + 8.460025912824529e-01, /* 360 */ + -1.375661561125266e-01, /* 361 */ + 2.941984516715388e-02, /* 362 */ + -6.426913125902382e-04, /* 363 */ + }, { + 1.136014291998739e-02, /* 364 */ + -7.706087734360774e-02, /* 365 */ + 3.234095760565429e-01, /* 366 */ + 8.498123942944995e-01, /* 367 */ + -1.370307935416629e-01, /* 368 */ + 2.937050474928606e-02, /* 369 */ + -6.622346678102776e-04, /* 370 */ + }, { + 1.113122545072202e-02, /* 371 */ + -7.590434139872407e-02, /* 372 */ + 3.182376256616457e-01, /* 373 */ + 8.535827978827749e-01, /* 374 */ + -1.364651061749298e-01, /* 375 */ + 2.931368276780341e-02, /* 376 */ + -6.817239793932266e-04, /* 377 */ + }, { + 1.090374333319907e-02, /* 378 */ + -7.474654863430663e-02, /* 379 */ + 3.130798245022357e-01, /* 380 */ + 8.573133838948686e-01, /* 381 */ + -1.358688805688508e-01, /* 382 */ + 2.924929438162952e-02, /* 383 */ + -7.011352205348302e-04, /* 384 */ + }, { + 1.067774245655789e-02, /* 385 */ + -7.358773627555218e-02, /* 386 */ + 3.079366178064618e-01, /* 387 */ + 8.610037382027232e-01, /* 388 */ + -1.352419061957486e-01, /* 389 */ + 2.917725561278015e-02, /* 390 */ + -7.204440001421441e-04, /* 391 */ + }, { + 1.045326763833955e-02, /* 392 */ + -7.242813949145467e-02, /* 393 */ + 3.028084474414053e-01, /* 394 */ + 8.646534507630197e-01, /* 395 */ + -1.345839754921861e-01, /* 396 */ + 2.909748337454149e-02, /* 397 */ + -7.396255708510786e-04, /* 398 */ + }, { + 1.023036262279292e-02, /* 399 */ + -7.126799136787691e-02, /* 400 */ + 2.976957518609703e-01, /* 401 */ + 8.682621156770067e-01, /* 402 */ + -1.338948839071171e-01, /* 403 */ + 2.900989549966232e-02, /* 404 */ + -7.586548372239626e-04, /* 405 */ + }, { + 1.000907007949311e-02, /* 406 */ + -7.010752288116626e-02, /* 407 */ + 2.925989660544231e-01, /* 408 */ + 8.718293312497631e-01, /* 409 */ + -1.331744299497369e-01, /* 410 */ + 2.891441076855387e-02, /* 411 */ + -7.775063641252938e-04, /* 412 */ + }, { + 9.789431602271271e-03, /* 413 */ + -6.894696287231404e-02, /* 414 */ + 2.875185214955909e-01, /* 415 */ + 8.753547000488832e-01, /* 416 */ + -1.324224152370240e-01, /* 417 */ + 2.881094893749082e-02, /* 418 */ + -7.961543852738185e-04, /* 419 */ + }, { + 9.571487708453395e-03, /* 420 */ + -6.778653802166430e-02, /* 421 */ + 2.824548460927230e-01, /* 422 */ + 8.788378289625756e-01, /* 423 */ + -1.316386445409620e-01, /* 424 */ + 2.869943076680737e-02, /* 425 */ + -8.145728119690237e-04, /* 426 */ + }, { + 9.355277838406877e-03, /* 427 */ + -6.662647282417096e-02, /* 428 */ + 2.774083641390264e-01, /* 429 */ + 8.822783292571661e-01, /* 430 */ + -1.308229258354336e-01, /* 431 */ + 2.857977804908198e-02, /* 432 */ + -8.327352419900550e-04, /* 433 */ + }, { + 9.140840355392437e-03, /* 434 */ + -6.546698956520861e-02, /* 435 */ + 2.723794962638790e-01, /* 436 */ + 8.856758166339943e-01, /* 437 */ + -1.299750703427760e-01, /* 438 */ + 2.845191363730427e-02, /* 439 */ + -8.506149686650558e-04, /* 440 */ + }, { + 8.928212545720045e-03, /* 441 */ + -6.430830829693616e-02, /* 442 */ + 2.673686593847286e-01, /* 443 */ + 8.890299112856920e-01, /* 444 */ + -1.290948925799897e-01, /* 445 */ + 2.831576147301751e-02, /* 446 */ + -8.681849901087664e-04, /* 447 */ + }, { + 8.717430619206452e-03, /* 448 */ + -6.315064681521791e-02, /* 449 */ + 2.623762666596838e-01, /* 450 */ + 8.923402379518393e-01, /* 451 */ + -1.281822104045887e-01, /* 452 */ + 2.817124661443064e-02, /* 453 */ + -8.854180186263388e-04, /* 454 */ + }, { + 8.508529709932666e-03, /* 455 */ + -6.199422063710185e-02, /* 456 */ + 2.574027274408040e-01, /* 457 */ + 8.956064259739822e-01, /* 458 */ + -1.272368450600864e-01, /* 459 */ + 2.801829526449300e-02, /* 460 */ + -9.022864902810273e-04, /* 461 */ + }, { + 8.301543877298635e-03, /* 462 */ + -6.083924297885757e-02, /* 463 */ + 2.524484472280946e-01, /* 464 */ + 8.988281093500092e-01, /* 465 */ + -1.262586212211042e-01, /* 466 */ + 2.785683479892532e-02, /* 467 */ + -9.187625746236699e-04, /* 468 */ + }, { + 8.096506107373698e-03, /* 469 */ + -5.968592473457642e-02, /* 470 */ + 2.475138276242130e-01, /* 471 */ + 9.020049267878701e-01, /* 472 */ + -1.252473670380959e-01, /* 473 */ + 2.768679379420070e-02, /* 474 */ + -9.348181845814541e-04, /* 475 */ + }, { + 7.893448314540197e-03, /* 476 */ + -5.853447445533320e-02, /* 477 */ + 2.425992662898926e-01, /* 478 */ + 9.051365217586359e-01, /* 479 */ + -1.242029141816779e-01, /* 480 */ + 2.750810205546858e-02, /* 481 */ + -9.504249865037702e-04, /* 482 */ + }, { + 7.692401343427691e-03, /* 483 */ + -5.738509832891316e-02, /* 484 */ + 2.377051569000891e-01, /* 485 */ + 9.082225425488828e-01, /* 486 */ + -1.231250978865554e-01, /* 487 */ + 2.732069064441559e-02, /* 488 */ + -9.655544103626029e-04, /* 489 */ + }, { + 7.493394971135955e-03, /* 490 */ + -5.623800016010321e-02, /* 491 */ + 2.328318891008579e-01, /* 492 */ + 9.112626423123993e-01, /* 493 */ + -1.220137569950366e-01, /* 494 */ + 2.712449190705641e-02, /* 495 */ + -9.801776601050557e-04, /* 496 */ + }, { + 7.296457909743918e-03, /* 497 */ + -5.509338135155091e-02, /* 498 */ + 2.279798484669641e-01, /* 499 */ + 9.142564791211991e-01, /* 500 */ + -1.208687340001249e-01, /* 501 */ + 2.691943950144822e-02, /* 502 */ + -9.942657241554641e-04, /* 503 */ + }, { + 7.101617809102288e-03, /* 504 */ + -5.395144088518943e-02, /* 505 */ + 2.231494164602341e-01, /* 506 */ + 9.172037160158394e-01, /* 507 */ + -1.196898750881803e-01, /* 508 */ + 2.670546842532187e-02, /* 509 */ + -1.007789386064493e-03, /* 510 */ + }, { + 6.908901259906972e-03, /* 511 */ + -5.281237530423245e-02, /* 512 */ + 2.183409703886530e-01, /* 513 */ + 9.201040210550299e-01, /* 514 */ + -1.184770301811412e-01, /* 515 */ + 2.648251504362370e-02, /* 516 */ + -1.020719235302619e-03, /* 517 */ + }, { + 6.718333797051150e-03, /* 518 */ + -5.167637869573667e-02, /* 519 */ + 2.135548833662130e-01, /* 520 */ + 9.229570673645258e-01, /* 521 */ + -1.172300529782974e-01, /* 522 */ + 2.625051711596052e-02, /* 523 */ + -1.033025678195301e-03, /* 524 */ + }, { + 6.529939903253073e-03, /* 525 */ + -5.054364267373540e-02, /* 526 */ + 2.087915242735169e-01, /* 527 */ + 9.257625331852983e-01, /* 528 */ + -1.159488009976052e-01, /* 529 */ + 2.600941382394202e-02, /* 530 */ + -1.044678948997064e-03, /* 531 */ + }, { + 6.343743012956645e-03, /* 532 */ + -4.941435636294156e-02, /* 533 */ + 2.040512577191446e-01, /* 534 */ + 9.285201019209733e-01, /* 535 */ + -1.146331356165368e-01, /* 536 */ + 2.575914579841332e-02, /* 537 */ + -1.055649121101780e-03, /* 538 */ + }, { + 6.159765516502505e-03, /* 539 */ + -4.828870638302148e-02, /* 540 */ + 1.993344440017834e-01, /* 541 */ + 9.312294621845263e-01, /* 542 */ + -1.132829221124536e-01, /* 543 */ + 2.549965514657118e-02, /* 544 */ + -1.065906118386268e-03, /* 545 */ + }, { + 5.978028764566336e-03, /* 546 */ + -4.716687683344033e-02, /* 547 */ + 1.946414390731309e-01, /* 548 */ + 9.338903078442332e-01, /* 549 */ + -1.118980297024964e-01, /* 550 */ + 2.523088547895752e-02, /* 551 */ + -1.075419726684316e-03, /* 552 */ + }, { + 5.798553072861818e-03, /* 553 */ + -4.604904927887769e-02, /* 554 */ + 1.899725945015709e-01, /* 555 */ + 9.365023380688623e-01, /* 556 */ + -1.104783315829824e-01, /* 557 */ + 2.495278193632289e-02, /* 558 */ + -1.084159605388224e-03, /* 559 */ + }, { + 5.621357727104864e-03, /* 560 */ + -4.493540273521546e-02, /* 561 */ + 1.853282574366316e-01, /* 562 */ + 9.390652573721028e-01, /* 563 */ + -1.090237049683018e-01, /* 564 */ + 2.466529121635406e-02, /* 565 */ + -1.092095299174878e-03, /* 566 */ + }, { + 5.446460988236670e-03, /* 567 */ + -4.382611365609584e-02, /* 568 */ + 1.807087705742239e-01, /* 569 */ + 9.415787756562223e-01, /* 570 */ + -1.075340311293039e-01, /* 571 */ + 2.436836160025825e-02, /* 572 */ + -1.099196249853307e-03, /* 573 */ + }, { + 5.273880097902076e-03, /* 574 */ + -4.272135592005138e-02, /* 575 */ + 1.761144721226713e-01, /* 576 */ + 9.440426082549445e-01, /* 577 */ + -1.060091954311663e-01, /* 578 */ + 2.406194297919816e-02, /* 579 */ + -1.105431808330667e-03, /* 580 */ + }, { + 5.103631284180478e-03, /* 581 */ + -4.162130081820462e-02, /* 582 */ + 1.715456957695286e-01, /* 583 */ + 9.464564759755407e-01, /* 584 */ + -1.044490873707362e-01, /* 585 */ + 2.374598688057016e-02, /* 586 */ + -1.110771246693530e-03, /* 587 */ + }, { + 4.935729767565705e-03, /* 588 */ + -4.052611704253924e-02, /* 589 */ + 1.670027706491982e-01, /* 590 */ + 9.488201051401287e-01, /* 591 */ + -1.028536006133390e-01, /* 592 */ + 2.342044649412001e-02, /* 593 */ + -1.115183770401296e-03, /* 594 */ + }, { + 4.770189767192131e-03, /* 595 */ + -3.943597067473980e-02, /* 596 */ + 1.624860213113444e-01, /* 597 */ + 9.511332276261677e-01, /* 598 */ + -1.012226330290420e-01, /* 599 */ + 2.308527669788855e-02, /* 600 */ + -1.118638530588553e-03, /* 601 */ + }, { + 4.607024507303565e-03, /* 602 */ + -3.835102517560170e-02, /* 603 */ + 1.579957676901108e-01, /* 604 */ + 9.533955809061508e-01, /* 605 */ + -9.955608672836883e-02, /* 606 */ + 2.274043408398138e-02, /* 607 */ + -1.121104636473070e-03, /* 608 */ + }, { + 4.446246223961389e-03, /* 609 */ + -3.727144137500895e-02, /* 610 */ + 1.535323250741442e-01, /* 611 */ + 9.556069080864779e-01, /* 612 */ + -9.785386809745342e-02, /* 613 */ + 2.238587698415551e-02, /* 614 */ + -1.122551167866203e-03, /* 615 */ + }, { + 4.287866171989037e-03, /* 616 */ + -3.619737746247935e-02, /* 617 */ + 1.490960040774270e-01, /* 618 */ + 9.577669579455091e-01, /* 619 */ + -9.611588783262809e-02, /* 620 */ + 2.202156549521620e-02, /* 621 */ + -1.122947187782295e-03, /* 622 */ + }, { + 4.131894632149082e-03, /* 623 */ + -3.512898897827717e-02, /* 624 */ + 1.446871106109222e-01, /* 625 */ + 9.598754849707929e-01, /* 626 */ + -9.434206097443590e-02, /* 627 */ + 2.164746150421816e-02, /* 628 */ + -1.122261755143747e-03, /* 629 */ + }, { + 3.978340918549750e-03, /* 630 */ + -3.406642880509015e-02, /* 631 */ + 1.403059458550339e-01, /* 632 */ + 9.619322493954562e-01, /* 633 */ + -9.253230694106100e-02, /* 634 */ + 2.126352871346326e-02, /* 635 */ + -1.120463937578314e-03, /* 636 */ + }, { + 3.827213386276986e-03, /* 637 */ + -3.300984716027202e-02, /* 638 */ + 1.359528062328858e-01, /* 639 */ + 9.639370172337561e-01, /* 640 */ + -9.068654956116820e-02, /* 641 */ + 2.086973266528943e-02, /* 642 */ + -1.117522824305172e-03, /* 643 */ + }, { + 3.678519439249078e-03, /* 644 */ + -3.195939158864695e-02, /* 645 */ + 1.316279833844193e-01, /* 646 */ + 9.658895603157857e-01, /* 647 */ + -8.880471710614442e-02, /* 648 */ + 2.046604076664311e-02, /* 649 */ + -1.113407539106230e-03, /* 650 */ + }, { + 3.532265538289867e-03, /* 651 */ + -3.091520695587671e-02, /* 652 */ + 1.273317641413156e-01, /* 653 */ + 9.677896563213259e-01, /* 654 */ + -8.688674232173496e-02, /* 655 */ + 2.005242231342951e-02, /* 656 */ + -1.108087253379183e-03, /* 657 */ + }, { + 3.388457209417186e-03, /* 658 */ + -2.987743544238687e-02, /* 659 */ + 1.230644305027427e-01, /* 660 */ + 9.696370888128401e-01, /* 661 */ + -8.493256245906648e-02, /* 662 */ + 1.962884851463336e-02, /* 663 */ + -1.101531199268716e-03, /* 664 */ + }, { + 3.247099052342608e-03, /* 665 */ + -2.884621653785256e-02, /* 666 */ + 1.188262596119302e-01, /* 667 */ + 9.714316472676046e-01, /* 668 */ + -8.294211930504999e-02, /* 669 */ + 1.919529251620448e-02, /* 670 */ + -1.093708682872210e-03, /* 671 */ + }, { + 3.108194749179169e-03, /* 672 */ + -2.782168703623990e-02, /* 673 */ + 1.146175237335723e-01, /* 674 */ + 9.731731271089683e-01, /* 675 */ + -8.091535921215573e-02, /* 676 */ + 1.875172942470069e-02, /* 677 */ + -1.084589097516370e-03, /* 678 */ + }, { + 2.971747073353185e-03, /* 679 */ + -2.680398103140338e-02, /* 680 */ + 1.104384902320638e-01, /* 681 */ + 9.748613297367402e-01, /* 682 */ + -7.885223312755388e-02, /* 683 */ + 1.829813633068257e-02, /* 684 */ + -1.074141937101013e-03, /* 685 */ + }, { + 2.837757898716223e-03, /* 686 */ + -2.579322991323553e-02, /* 687 */ + 1.062894215505674e-01, /* 688 */ + 9.764960625566944e-01, /* 689 */ + -7.675269662161305e-02, /* 690 */ + 1.783449233185286e-02, /* 691 */ + -1.062336809506350e-03, /* 692 */ + }, { + 2.706228208853840e-03, /* 693 */ + -2.478956236436741e-02, /* 694 */ + 1.021705751909168e-01, /* 695 */ + 9.780771390091908e-01, /* 696 */ + -7.461670991575037e-02, /* 697 */ + 1.736077855593420e-02, /* 698 */ + -1.049143450059986e-03, /* 699 */ + }, { + 2.577158106586916e-03, /* 700 */ + -2.379310435741876e-02, /* 701 */ + 9.808220369435408e-02, /* 702 */ + 9.796043785969055e-01, /* 703 */ + -7.244423790962552e-02, /* 704 */ + 1.687697818327941e-02, /* 705 */ + -1.034531735059858e-03, /* 706 */ + }, { + 2.450546823661987e-03, /* 707 */ + -2.280397915279337e-02, /* 708 */ + 9.402455462310588e-02, /* 709 */ + 9.810776069116667e-01, /* 710 */ + -7.023525020767289e-02, /* 711 */ + 1.638307646920682e-02, /* 712 */ + -1.018471695349289e-03, /* 713 */ + }, { + 2.326392730626404e-03, /* 714 */ + -2.182230729701992e-02, /* 715 */ + 8.999787054279679e-02, /* 716 */ + 9.824966556603907e-01, /* 717 */ + -6.798972114496460e-02, /* 718 */ + 1.587906076605559e-02, /* 719 */ + -1.000933529940309e-03, /* 720 */ + }, { + 2.204693346884742e-03, /* 721 */ + -2.084820662163316e-02, /* 722 */ + 8.600238900570113e-02, /* 723 */ + 9.838613626901140e-01, /* 724 */ + -6.570762981239750e-02, /* 725 */ + 1.536492054495343e-02, /* 726 */ + -9.818876196813738e-04, /* 727 */ + }, { + 2.085445350932246e-03, /* 728 */ + -1.988179224259554e-02, /* 729 */ + 8.203834253483586e-02, /* 730 */ + 9.851715720121177e-01, /* 731 */ + -6.338896008119892e-02, /* 732 */ + 1.484064741729164e-02, /* 733 */ + -9.613045409655687e-04, /* 734 */ + }, { + 1.968644590761548e-03, /* 735 */ + -1.892317656025402e-02, /* 736 */ + 7.810595860889319e-02, /* 737 */ + 9.864271338251378e-01, /* 738 */ + -6.103370062674356e-02, /* 739 */ + 1.430623515590003e-02, /* 740 */ + -9.391550794753652e-04, /* 741 */ + }, { + 1.854286094438386e-03, /* 742 */ + -1.797246925983164e-02, /* 743 */ + 7.420545964801417e-02, /* 744 */ + 9.876279045376605e-01, /* 745 */ + -5.864184495167603e-02, /* 746 */ + 1.376167971591675e-02, /* 747 */ + -9.154102439599487e-04, /* 748 */ + }, { + 1.742364080842615e-03, /* 749 */ + -1.702977731244917e-02, /* 750 */ + 7.033706300040359e-02, /* 751 */ + 9.887737467892981e-01, /* 752 */ + -5.621339140833288e-02, /* 753 */ + 1.320697925534576e-02, /* 754 */ + -8.900412800411573e-04, /* 755 */ + }, { + 1.632871970570320e-03, /* 756 */ + -1.609520497667476e-02, /* 757 */ + 6.650098092978608e-02, /* 758 */ + 9.898645294712379e-01, /* 759 */ + -5.374834322045772e-02, /* 760 */ + 1.264213415529629e-02, /* 761 */ + -8.630196840440353e-04, /* 762 */ + }, { + 1.525802396992804e-03, /* 763 */ + -1.516885380059888e-02, /* 764 */ + 6.269742060370384e-02, /* 765 */ + 9.909001277457663e-01, /* 766 */ + -5.124670850420399e-02, /* 767 */ + 1.206714703989862e-02, /* 768 */ + -8.343172168478687e-04, /* 769 */ + }, { + 1.421147217468663e-03, /* 770 */ + -1.425082262442998e-02, /* 771 */ + 5.892658408265536e-02, /* 772 */ + 9.918804230648608e-01, /* 773 */ + -4.870850028841950e-02, /* 774 */ + 1.148202279588897e-02, /* 775 */ + -8.039059177537709e-04, /* 776 */ + }, { + 1.318897524704578e-03, /* 777 */ + -1.334120758360962e-02, /* 778 */ + 5.518866831007525e-02, /* 779 */ + 9.928053031878483e-01, /* 780 */ + -4.613373653420693e-02, /* 781 */ + 1.088676859185900e-02, /* 782 */ + -7.717581183646440e-04, /* 783 */ + }, { + 1.219043658260877e-03, /* 784 */ + -1.244010211244157e-02, /* 785 */ + 5.148386510315437e-02, /* 786 */ + 9.936746621981263e-01, /* 787 */ + -4.352244015375482e-02, /* 788 */ + 1.028139389716235e-02, /* 789 */ + -7.378464564734607e-04, /* 790 */ + }, { + 1.121575216197463e-03, /* 791 */ + -1.154759694823357e-02, /* 792 */ + 4.781236114450060e-02, /* 793 */ + 9.944884005189432e-01, /* 794 */ + -4.087463902843420e-02, /* 795 */ + 9.665910500473909e-03, /* 796 */ + -7.021438899556850e-04, /* 797 */ + }, { + 1.026481066856231e-03, /* 798 */ + -1.066378013594614e-02, /* 799 */ + 4.417433797463730e-02, /* 800 */ + 9.952464249282380e-01, /* 801 */ + -3.819036602615411e-02, /* 802 */ + 9.040332527994370e-03, /* 803 */ + -6.646237106617679e-04, /* 804 */ + }, { + 9.337493607755644e-04, /* 805 */ + -9.788737033346933e-03, /* 806 */ + 4.056997198534163e-02, /* 807 */ + 9.959486485725322e-01, /* 808 */ + -3.546965901797275e-02, /* 809 */ + 8.404676461295810e-03, /* 810 */ + -6.252595583054893e-04, /* 811 */ + }, { + 8.433675427328470e-04, /* 812 */ + -8.922550316664762e-03, /* 813 */ + 3.699943441381923e-02, /* 814 */ + 9.965949909798753e-01, /* 815 */ + -3.271256089395777e-02, /* 816 */ + 7.758961154800972e-03, /* 817 */ + -5.840254343440151e-04, /* 818 */ + }, { + 7.553223639105668e-04, /* 819 */ + -8.065299986741607e-03, /* 820 */ + 3.346289133771520e-02, /* 821 */ + 9.971853780718406e-01, /* 822 */ + -2.991911957829145e-02, /* 823 */ + 7.103207852892033e-03, /* 824 */ + -5.408957158454127e-04, /* 825 */ + }, { + 6.695998941820378e-04, /* 826 */ + -7.217063375677063e-03, /* 827 */ + 2.996050367095970e-02, /* 828 */ + 9.977197421745680e-01, /* 829 */ + -2.708938804361575e-02, /* 830 */ + 6.437440206642007e-03, /* 831 */ + -4.958451693394876e-04, /* 832 */ + }, { + 5.861855345123588e-04, /* 833 */ + -6.377915153961920e-03, /* 834 */ + 2.649242716044695e-02, /* 835 */ + 9.981980220288543e-01, /* 836 */ + -2.422342432461263e-02, /* 837 */ + 5.761684290163624e-03, /* 838 */ + -4.488489646476928e-04, /* 839 */ + }, { + 5.050640294702417e-04, /* 840 */ + -5.547927338097411e-03, /* 841 */ + 2.305881238354565e-02, /* 842 */ + 9.986201627992864e-01, /* 843 */ + -2.132129153081513e-02, /* 844 */ + 5.075968616570653e-03, /* 845 */ + -3.998826886878056e-04, /* 846 */ + }, { + 4.262194798466813e-04, /* 847 */ + -4.727169298694500e-03, /* 848 */ + 1.965980474643937e-02, /* 849 */ + 9.989861160824184e-01, /* 850 */ + -1.838305785864478e-02, /* 851 */ + 4.380324153544939e-03, /* 852 */ + -3.489223592492433e-04, /* 853 */ + }, { + 3.496353553759901e-04, /* 854 */ + -3.915707769050846e-03, /* 855 */ + 1.629554448329466e-02, /* 856 */ + 9.992958399139888e-01, /* 857 */ + -1.540879660267084e-02, /* 858 */ + 3.674784338505265e-03, /* 859 */ + -2.959444387346577e-04, /* 860 */ + }, { + 2.752945075550529e-04, /* 861 */ + -3.113606854199215e-03, /* 862 */ + 1.296616665625557e-02, /* 863 */ + 9.995492987751797e-01, /* 864 */ + -1.239858616608813e-02, /* 865 */ + 2.959385093371052e-03, /* 866 */ + -2.409258478636185e-04, /* 867 */ + }, { + 2.031791825563283e-04, /* 868 */ + -2.320928040424877e-03, /* 869 */ + 9.671801156260738e-03, /* 870 */ + 9.997464635979135e-01, /* 871 */ + -9.352510070407542e-03, /* 872 */ + 2.234164838917225e-03, /* 873 */ + -1.838439793339892e-04, /* 874 */ + }, { + 1.332710342305255e-04, /* 875 */ + -1.537730205245651e-03, /* 876 */ + 6.412572704682764e-03, /* 877 */ + 9.998873117691878e-01, /* 878 */ + -6.270656964357692e-03, /* 879 */ + 1.499164508713334e-03, /* 880 */ + -1.246767114368607e-04, /* 881 */ + }, { + 6.555113719447324e-05, /* 882 */ + -7.640696278518945e-04, /* 883 */ + 3.188600855785918e-03, /* 884 */ + 9.999718271344488e-01, /* 885 */ + -3.153120631992235e-03, /* 886 */ + 7.544275626434484e-04, /* 887 */ + -6.340242162062585e-05, /* 888 */ + }, { + 1.930201848426478e-18, /* 889 */ + -1.515373497812483e-17, /* 890 */ + 3.164321107994089e-17, /* 891 */ + 1.000000000000000e+00, /* 892 */ + 3.164321107994089e-17, /* 893 */ + -1.515373497812483e-17, /* 894 */ + 1.930201848426478e-18, /* 895 */ + }, { + -6.340242162062585e-05, /* 896 */ + 7.544275626434484e-04, /* 897 */ + -3.153120631992235e-03, /* 898 */ + 9.999718271344488e-01, /* 899 */ + 3.188600855785918e-03, /* 900 */ + -7.640696278518945e-04, /* 901 */ + 6.555113719447324e-05, /* 902 */ + }, { + -1.246767114368607e-04, /* 903 */ + 1.499164508713334e-03, /* 904 */ + -6.270656964357692e-03, /* 905 */ + 9.998873117691878e-01, /* 906 */ + 6.412572704682764e-03, /* 907 */ + -1.537730205245651e-03, /* 908 */ + 1.332710342305255e-04, /* 909 */ + }, { + -1.838439793339892e-04, /* 910 */ + 2.234164838917225e-03, /* 911 */ + -9.352510070407542e-03, /* 912 */ + 9.997464635979135e-01, /* 913 */ + 9.671801156260738e-03, /* 914 */ + -2.320928040424877e-03, /* 915 */ + 2.031791825563283e-04, /* 916 */ + }, { + -2.409258478636185e-04, /* 917 */ + 2.959385093371052e-03, /* 918 */ + -1.239858616608813e-02, /* 919 */ + 9.995492987751797e-01, /* 920 */ + 1.296616665625557e-02, /* 921 */ + -3.113606854199215e-03, /* 922 */ + 2.752945075550529e-04, /* 923 */ + }, { + -2.959444387346577e-04, /* 924 */ + 3.674784338505265e-03, /* 925 */ + -1.540879660267084e-02, /* 926 */ + 9.992958399139888e-01, /* 927 */ + 1.629554448329466e-02, /* 928 */ + -3.915707769050846e-03, /* 929 */ + 3.496353553759901e-04, /* 930 */ + }, { + -3.489223592492433e-04, /* 931 */ + 4.380324153544939e-03, /* 932 */ + -1.838305785864478e-02, /* 933 */ + 9.989861160824184e-01, /* 934 */ + 1.965980474643937e-02, /* 935 */ + -4.727169298694500e-03, /* 936 */ + 4.262194798466813e-04, /* 937 */ + }, { + -3.998826886878056e-04, /* 938 */ + 5.075968616570653e-03, /* 939 */ + -2.132129153081513e-02, /* 940 */ + 9.986201627992864e-01, /* 941 */ + 2.305881238354565e-02, /* 942 */ + -5.547927338097411e-03, /* 943 */ + 5.050640294702417e-04, /* 944 */ + }, { + -4.488489646476928e-04, /* 945 */ + 5.761684290163624e-03, /* 946 */ + -2.422342432461263e-02, /* 947 */ + 9.981980220288543e-01, /* 948 */ + 2.649242716044695e-02, /* 949 */ + -6.377915153961920e-03, /* 950 */ + 5.861855345123588e-04, /* 951 */ + }, { + -4.958451693394876e-04, /* 952 */ + 6.437440206642007e-03, /* 953 */ + -2.708938804361575e-02, /* 954 */ + 9.977197421745680e-01, /* 955 */ + 2.996050367095970e-02, /* 956 */ + -7.217063375677063e-03, /* 957 */ + 6.695998941820378e-04, /* 958 */ + }, { + -5.408957158454127e-04, /* 959 */ + 7.103207852892033e-03, /* 960 */ + -2.991911957829145e-02, /* 961 */ + 9.971853780718406e-01, /* 962 */ + 3.346289133771520e-02, /* 963 */ + -8.065299986741607e-03, /* 964 */ + 7.553223639105668e-04, /* 965 */ + }, { + -5.840254343440151e-04, /* 966 */ + 7.758961154800972e-03, /* 967 */ + -3.271256089395777e-02, /* 968 */ + 9.965949909798753e-01, /* 969 */ + 3.699943441381923e-02, /* 970 */ + -8.922550316664762e-03, /* 971 */ + 8.433675427328470e-04, /* 972 */ + }, { + -6.252595583054893e-04, /* 973 */ + 8.404676461295810e-03, /* 974 */ + -3.546965901797275e-02, /* 975 */ + 9.959486485725322e-01, /* 976 */ + 4.056997198534163e-02, /* 977 */ + -9.788737033346933e-03, /* 978 */ + 9.337493607755644e-04, /* 979 */ + }, { + -6.646237106617679e-04, /* 980 */ + 9.040332527994370e-03, /* 981 */ + -3.819036602615411e-02, /* 982 */ + 9.952464249282380e-01, /* 983 */ + 4.417433797463730e-02, /* 984 */ + -1.066378013594614e-02, /* 985 */ + 1.026481066856231e-03, /* 986 */ + }, { + -7.021438899556850e-04, /* 987 */ + 9.665910500473909e-03, /* 988 */ + -4.087463902843420e-02, /* 989 */ + 9.944884005189432e-01, /* 990 */ + 4.781236114450060e-02, /* 991 */ + -1.154759694823357e-02, /* 992 */ + 1.121575216197463e-03, /* 993 */ + }, { + -7.378464564734607e-04, /* 994 */ + 1.028139389716235e-02, /* 995 */ + -4.352244015375482e-02, /* 996 */ + 9.936746621981263e-01, /* 997 */ + 5.148386510315437e-02, /* 998 */ + -1.244010211244157e-02, /* 999 */ + 1.219043658260877e-03, /* 1000 */ + }, { + -7.717581183646440e-04, /* 1001 */ + 1.088676859185900e-02, /* 1002 */ + -4.613373653420693e-02, /* 1003 */ + 9.928053031878483e-01, /* 1004 */ + 5.518866831007525e-02, /* 1005 */ + -1.334120758360962e-02, /* 1006 */ + 1.318897524704578e-03, /* 1007 */ + }, { + -8.039059177537709e-04, /* 1008 */ + 1.148202279588897e-02, /* 1009 */ + -4.870850028841950e-02, /* 1010 */ + 9.918804230648608e-01, /* 1011 */ + 5.892658408265536e-02, /* 1012 */ + -1.425082262442998e-02, /* 1013 */ + 1.421147217468663e-03, /* 1014 */ + }, { + -8.343172168478687e-04, /* 1015 */ + 1.206714703989862e-02, /* 1016 */ + -5.124670850420399e-02, /* 1017 */ + 9.909001277457663e-01, /* 1018 */ + 6.269742060370384e-02, /* 1019 */ + -1.516885380059888e-02, /* 1020 */ + 1.525802396992804e-03, /* 1021 */ + }, { + -8.630196840440353e-04, /* 1022 */ + 1.264213415529629e-02, /* 1023 */ + -5.374834322045772e-02, /* 1024 */ + 9.898645294712379e-01, /* 1025 */ + 6.650098092978608e-02, /* 1026 */ + -1.609520497667476e-02, /* 1027 */ + 1.632871970570320e-03, /* 1028 */ + }, { + -8.900412800411573e-04, /* 1029 */ + 1.320697925534576e-02, /* 1030 */ + -5.621339140833288e-02, /* 1031 */ + 9.887737467892981e-01, /* 1032 */ + 7.033706300040359e-02, /* 1033 */ + -1.702977731244917e-02, /* 1034 */ + 1.742364080842615e-03, /* 1035 */ + }, { + -9.154102439599487e-04, /* 1036 */ + 1.376167971591675e-02, /* 1037 */ + -5.864184495167603e-02, /* 1038 */ + 9.876279045376605e-01, /* 1039 */ + 7.420545964801417e-02, /* 1040 */ + -1.797246925983164e-02, /* 1041 */ + 1.854286094438386e-03, /* 1042 */ + }, { + -9.391550794753652e-04, /* 1043 */ + 1.430623515590003e-02, /* 1044 */ + -6.103370062674356e-02, /* 1045 */ + 9.864271338251378e-01, /* 1046 */ + 7.810595860889319e-02, /* 1047 */ + -1.892317656025402e-02, /* 1048 */ + 1.968644590761548e-03, /* 1049 */ + }, { + -9.613045409655687e-04, /* 1050 */ + 1.484064741729164e-02, /* 1051 */ + -6.338896008119892e-02, /* 1052 */ + 9.851715720121177e-01, /* 1053 */ + 8.203834253483586e-02, /* 1054 */ + -1.988179224259554e-02, /* 1055 */ + 2.085445350932246e-03, /* 1056 */ + }, { + -9.818876196813738e-04, /* 1057 */ + 1.536492054495343e-02, /* 1058 */ + -6.570762981239750e-02, /* 1059 */ + 9.838613626901140e-01, /* 1060 */ + 8.600238900570113e-02, /* 1061 */ + -2.084820662163316e-02, /* 1062 */ + 2.204693346884742e-03, /* 1063 */ + }, { + -1.000933529940309e-03, /* 1064 */ + 1.587906076605559e-02, /* 1065 */ + -6.798972114496460e-02, /* 1066 */ + 9.824966556603907e-01, /* 1067 */ + 8.999787054279679e-02, /* 1068 */ + -2.182230729701992e-02, /* 1069 */ + 2.326392730626404e-03, /* 1070 */ + }, { + -1.018471695349289e-03, /* 1071 */ + 1.638307646920682e-02, /* 1072 */ + -7.023525020767289e-02, /* 1073 */ + 9.810776069116667e-01, /* 1074 */ + 9.402455462310588e-02, /* 1075 */ + -2.280397915279337e-02, /* 1076 */ + 2.450546823661987e-03, /* 1077 */ + }, { + -1.034531735059858e-03, /* 1078 */ + 1.687697818327941e-02, /* 1079 */ + -7.244423790962552e-02, /* 1080 */ + 9.796043785969055e-01, /* 1081 */ + 9.808220369435408e-02, /* 1082 */ + -2.379310435741876e-02, /* 1083 */ + 2.577158106586916e-03, /* 1084 */ + }, { + -1.049143450059986e-03, /* 1085 */ + 1.736077855593420e-02, /* 1086 */ + -7.461670991575037e-02, /* 1087 */ + 9.780771390091908e-01, /* 1088 */ + 1.021705751909168e-01, /* 1089 */ + -2.478956236436741e-02, /* 1090 */ + 2.706228208853840e-03, /* 1091 */ + }, { + -1.062336809506350e-03, /* 1092 */ + 1.783449233185286e-02, /* 1093 */ + -7.675269662161305e-02, /* 1094 */ + 9.764960625566944e-01, /* 1095 */ + 1.062894215505674e-01, /* 1096 */ + -2.579322991323553e-02, /* 1097 */ + 2.837757898716223e-03, /* 1098 */ + }, { + -1.074141937101013e-03, /* 1099 */ + 1.829813633068257e-02, /* 1100 */ + -7.885223312755388e-02, /* 1101 */ + 9.748613297367402e-01, /* 1102 */ + 1.104384902320638e-01, /* 1103 */ + -2.680398103140338e-02, /* 1104 */ + 2.971747073353185e-03, /* 1105 */ + }, { + -1.084589097516370e-03, /* 1106 */ + 1.875172942470069e-02, /* 1107 */ + -8.091535921215573e-02, /* 1108 */ + 9.731731271089683e-01, /* 1109 */ + 1.146175237335723e-01, /* 1110 */ + -2.782168703623990e-02, /* 1111 */ + 3.108194749179169e-03, /* 1112 */ + }, { + -1.093708682872210e-03, /* 1113 */ + 1.919529251620448e-02, /* 1114 */ + -8.294211930504999e-02, /* 1115 */ + 9.714316472676046e-01, /* 1116 */ + 1.188262596119302e-01, /* 1117 */ + -2.884621653785256e-02, /* 1118 */ + 3.247099052342608e-03, /* 1119 */ + }, { + -1.101531199268716e-03, /* 1120 */ + 1.962884851463336e-02, /* 1121 */ + -8.493256245906648e-02, /* 1122 */ + 9.696370888128401e-01, /* 1123 */ + 1.230644305027427e-01, /* 1124 */ + -2.987743544238687e-02, /* 1125 */ + 3.388457209417186e-03, /* 1126 */ + }, { + -1.108087253379183e-03, /* 1127 */ + 2.005242231342951e-02, /* 1128 */ + -8.688674232173496e-02, /* 1129 */ + 9.677896563213259e-01, /* 1130 */ + 1.273317641413156e-01, /* 1131 */ + -3.091520695587671e-02, /* 1132 */ + 3.532265538289867e-03, /* 1133 */ + }, { + -1.113407539106230e-03, /* 1134 */ + 2.046604076664311e-02, /* 1135 */ + -8.880471710614442e-02, /* 1136 */ + 9.658895603157857e-01, /* 1137 */ + 1.316279833844193e-01, /* 1138 */ + -3.195939158864695e-02, /* 1139 */ + 3.678519439249078e-03, /* 1140 */ + }, { + -1.117522824305172e-03, /* 1141 */ + 2.086973266528943e-02, /* 1142 */ + -9.068654956116820e-02, /* 1143 */ + 9.639370172337561e-01, /* 1144 */ + 1.359528062328858e-01, /* 1145 */ + -3.300984716027202e-02, /* 1146 */ + 3.827213386276986e-03, /* 1147 */ + }, { + -1.120463937578314e-03, /* 1148 */ + 2.126352871346326e-02, /* 1149 */ + -9.253230694106100e-02, /* 1150 */ + 9.619322493954562e-01, /* 1151 */ + 1.403059458550339e-01, /* 1152 */ + -3.406642880509015e-02, /* 1153 */ + 3.978340918549750e-03, /* 1154 */ + }, { + -1.122261755143747e-03, /* 1155 */ + 2.164746150421816e-02, /* 1156 */ + -9.434206097443590e-02, /* 1157 */ + 9.598754849707929e-01, /* 1158 */ + 1.446871106109222e-01, /* 1159 */ + -3.512898897827717e-02, /* 1160 */ + 4.131894632149082e-03, /* 1161 */ + }, { + -1.122947187782295e-03, /* 1162 */ + 2.202156549521620e-02, /* 1163 */ + -9.611588783262809e-02, /* 1164 */ + 9.577669579455091e-01, /* 1165 */ + 1.490960040774270e-01, /* 1166 */ + -3.619737746247935e-02, /* 1167 */ + 4.287866171989037e-03, /* 1168 */ + }, { + -1.122551167866203e-03, /* 1169 */ + 2.238587698415551e-02, /* 1170 */ + -9.785386809745342e-02, /* 1171 */ + 9.556069080864779e-01, /* 1172 */ + 1.535323250741442e-01, /* 1173 */ + -3.727144137500895e-02, /* 1174 */ + 4.446246223961389e-03, /* 1175 */ + }, { + -1.121104636473070e-03, /* 1176 */ + 2.274043408398138e-02, /* 1177 */ + -9.955608672836883e-02, /* 1178 */ + 9.533955809061508e-01, /* 1179 */ + 1.579957676901108e-01, /* 1180 */ + -3.835102517560170e-02, /* 1181 */ + 4.607024507303565e-03, /* 1182 */ + }, { + -1.118638530588553e-03, /* 1183 */ + 2.308527669788855e-02, /* 1184 */ + -1.012226330290420e-01, /* 1185 */ + 9.511332276261677e-01, /* 1186 */ + 1.624860213113444e-01, /* 1187 */ + -3.943597067473980e-02, /* 1188 */ + 4.770189767192131e-03, /* 1189 */ + }, { + -1.115183770401296e-03, /* 1190 */ + 2.342044649412001e-02, /* 1191 */ + -1.028536006133390e-01, /* 1192 */ + 9.488201051401287e-01, /* 1193 */ + 1.670027706491982e-01, /* 1194 */ + -4.052611704253924e-02, /* 1195 */ + 4.935729767565705e-03, /* 1196 */ + }, { + -1.110771246693530e-03, /* 1197 */ + 2.374598688057016e-02, /* 1198 */ + -1.044490873707362e-01, /* 1199 */ + 9.464564759755407e-01, /* 1200 */ + 1.715456957695286e-01, /* 1201 */ + -4.162130081820462e-02, /* 1202 */ + 5.103631284180478e-03, /* 1203 */ + }, { + -1.105431808330667e-03, /* 1204 */ + 2.406194297919816e-02, /* 1205 */ + -1.060091954311663e-01, /* 1206 */ + 9.440426082549445e-01, /* 1207 */ + 1.761144721226713e-01, /* 1208 */ + -4.272135592005138e-02, /* 1209 */ + 5.273880097902076e-03, /* 1210 */ + }, { + -1.099196249853307e-03, /* 1211 */ + 2.436836160025825e-02, /* 1212 */ + -1.075340311293039e-01, /* 1213 */ + 9.415787756562223e-01, /* 1214 */ + 1.807087705742239e-01, /* 1215 */ + -4.382611365609584e-02, /* 1216 */ + 5.446460988236670e-03, /* 1217 */ + }, { + -1.092095299174878e-03, /* 1218 */ + 2.466529121635406e-02, /* 1219 */ + -1.090237049683018e-01, /* 1220 */ + 9.390652573721028e-01, /* 1221 */ + 1.853282574366316e-01, /* 1222 */ + -4.493540273521546e-02, /* 1223 */ + 5.621357727104864e-03, /* 1224 */ + }, { + -1.084159605388224e-03, /* 1225 */ + 2.495278193632289e-02, /* 1226 */ + -1.104783315829824e-01, /* 1227 */ + 9.365023380688623e-01, /* 1228 */ + 1.899725945015709e-01, /* 1229 */ + -4.604904927887769e-02, /* 1230 */ + 5.798553072861818e-03, /* 1231 */ + }, { + -1.075419726684316e-03, /* 1232 */ + 2.523088547895752e-02, /* 1233 */ + -1.118980297024964e-01, /* 1234 */ + 9.338903078442332e-01, /* 1235 */ + 1.946414390731309e-01, /* 1236 */ + -4.716687683344033e-02, /* 1237 */ + 5.978028764566336e-03, /* 1238 */ + }, { + -1.065906118386268e-03, /* 1239 */ + 2.549965514657118e-02, /* 1240 */ + -1.132829221124536e-01, /* 1241 */ + 9.312294621845263e-01, /* 1242 */ + 1.993344440017834e-01, /* 1243 */ + -4.828870638302148e-02, /* 1244 */ + 6.159765516502505e-03, /* 1245 */ + }, { + -1.055649121101780e-03, /* 1246 */ + 2.575914579841332e-02, /* 1247 */ + -1.146331356165368e-01, /* 1248 */ + 9.285201019209733e-01, /* 1249 */ + 2.040512577191446e-01, /* 1250 */ + -4.941435636294156e-02, /* 1251 */ + 6.343743012956645e-03, /* 1252 */ + }, { + -1.044678948997064e-03, /* 1253 */ + 2.600941382394202e-02, /* 1254 */ + -1.159488009976052e-01, /* 1255 */ + 9.257625331852983e-01, /* 1256 */ + 2.087915242735169e-01, /* 1257 */ + -5.054364267373540e-02, /* 1258 */ + 6.529939903253073e-03, /* 1259 */ + }, { + -1.033025678195301e-03, /* 1260 */ + 2.625051711596052e-02, /* 1261 */ + -1.172300529782974e-01, /* 1262 */ + 9.229570673645258e-01, /* 1263 */ + 2.135548833662130e-01, /* 1264 */ + -5.167637869573667e-02, /* 1265 */ + 6.718333797051150e-03, /* 1266 */ + }, { + -1.020719235302619e-03, /* 1267 */ + 2.648251504362370e-02, /* 1268 */ + -1.184770301811412e-01, /* 1269 */ + 9.201040210550299e-01, /* 1270 */ + 2.183409703886530e-01, /* 1271 */ + -5.281237530423245e-02, /* 1272 */ + 6.908901259906972e-03, /* 1273 */ + }, { + -1.007789386064493e-03, /* 1274 */ + 2.670546842532187e-02, /* 1275 */ + -1.196898750881803e-01, /* 1276 */ + 9.172037160158394e-01, /* 1277 */ + 2.231494164602341e-01, /* 1278 */ + -5.395144088518943e-02, /* 1279 */ + 7.101617809102288e-03, /* 1280 */ + }, { + -9.942657241554641e-04, /* 1281 */ + 2.691943950144822e-02, /* 1282 */ + -1.208687340001249e-01, /* 1283 */ + 9.142564791211991e-01, /* 1284 */ + 2.279798484669641e-01, /* 1285 */ + -5.509338135155091e-02, /* 1286 */ + 7.296457909743918e-03, /* 1287 */ + }, { + -9.801776601050557e-04, /* 1288 */ + 2.712449190705641e-02, /* 1289 */ + -1.220137569950366e-01, /* 1290 */ + 9.112626423123993e-01, /* 1291 */ + 2.328318891008579e-01, /* 1292 */ + -5.623800016010321e-02, /* 1293 */ + 7.493394971135955e-03, /* 1294 */ + }, { + -9.655544103626029e-04, /* 1295 */ + 2.732069064441559e-02, /* 1296 */ + -1.231250978865554e-01, /* 1297 */ + 9.082225425488828e-01, /* 1298 */ + 2.377051569000891e-01, /* 1299 */ + -5.738509832891316e-02, /* 1300 */ + 7.692401343427691e-03, /* 1301 */ + }, { + -9.504249865037702e-04, /* 1302 */ + 2.750810205546858e-02, /* 1303 */ + -1.242029141816779e-01, /* 1304 */ + 9.051365217586359e-01, /* 1305 */ + 2.425992662898926e-01, /* 1306 */ + -5.853447445533320e-02, /* 1307 */ + 7.893448314540197e-03, /* 1308 */ + }, { + -9.348181845814541e-04, /* 1309 */ + 2.768679379420070e-02, /* 1310 */ + -1.252473670380959e-01, /* 1311 */ + 9.020049267878701e-01, /* 1312 */ + 2.475138276242130e-01, /* 1313 */ + -5.968592473457642e-02, /* 1314 */ + 8.096506107373698e-03, /* 1315 */ + }, { + -9.187625746236699e-04, /* 1316 */ + 2.785683479892532e-02, /* 1317 */ + -1.262586212211042e-01, /* 1318 */ + 8.988281093500092e-01, /* 1319 */ + 2.524484472280946e-01, /* 1320 */ + -6.083924297885757e-02, /* 1321 */ + 8.301543877298635e-03, /* 1322 */ + }, { + -9.022864902810273e-04, /* 1323 */ + 2.801829526449300e-02, /* 1324 */ + -1.272368450600864e-01, /* 1325 */ + 8.956064259739822e-01, /* 1326 */ + 2.574027274408040e-01, /* 1327 */ + -6.199422063710185e-02, /* 1328 */ + 8.508529709932666e-03, /* 1329 */ + }, { + -8.854180186263388e-04, /* 1330 */ + 2.817124661443064e-02, /* 1331 */ + -1.281822104045887e-01, /* 1332 */ + 8.923402379518393e-01, /* 1333 */ + 2.623762666596838e-01, /* 1334 */ + -6.315064681521791e-02, /* 1335 */ + 8.717430619206452e-03, /* 1336 */ + }, { + -8.681849901087664e-04, /* 1337 */ + 2.831576147301751e-02, /* 1338 */ + -1.290948925799897e-01, /* 1339 */ + 8.890299112856920e-01, /* 1340 */ + 2.673686593847286e-01, /* 1341 */ + -6.430830829693616e-02, /* 1342 */ + 8.928212545720045e-03, /* 1343 */ + }, { + -8.506149686650558e-04, /* 1344 */ + 2.845191363730427e-02, /* 1345 */ + -1.299750703427760e-01, /* 1346 */ + 8.856758166339943e-01, /* 1347 */ + 2.723794962638790e-01, /* 1348 */ + -6.546698956520861e-02, /* 1349 */ + 9.140840355392437e-03, /* 1350 */ + }, { + -8.327352419900550e-04, /* 1351 */ + 2.857977804908198e-02, /* 1352 */ + -1.308229258354336e-01, /* 1353 */ + 8.822783292571661e-01, /* 1354 */ + 2.774083641390264e-01, /* 1355 */ + -6.662647282417096e-02, /* 1356 */ + 9.355277838406877e-03, /* 1357 */ + }, { + -8.145728119690237e-04, /* 1358 */ + 2.869943076680737e-02, /* 1359 */ + -1.316386445409620e-01, /* 1360 */ + 8.788378289625756e-01, /* 1361 */ + 2.824548460927230e-01, /* 1362 */ + -6.778653802166430e-02, /* 1363 */ + 9.571487708453395e-03, /* 1364 */ + }, { + -7.961543852738185e-04, /* 1365 */ + 2.881094893749082e-02, /* 1366 */ + -1.324224152370240e-01, /* 1367 */ + 8.753547000488832e-01, /* 1368 */ + 2.875185214955909e-01, /* 1369 */ + -6.894696287231404e-02, /* 1370 */ + 9.789431602271271e-03, /* 1371 */ + }, { + -7.775063641252938e-04, /* 1372 */ + 2.891441076855387e-02, /* 1373 */ + -1.331744299497369e-01, /* 1374 */ + 8.718293312497631e-01, /* 1375 */ + 2.925989660544231e-01, /* 1376 */ + -7.010752288116626e-02, /* 1377 */ + 1.000907007949311e-02, /* 1378 */ + }, { + -7.586548372239626e-04, /* 1379 */ + 2.900989549966232e-02, /* 1380 */ + -1.338948839071171e-01, /* 1381 */ + 8.682621156770067e-01, /* 1382 */ + 2.976957518609703e-01, /* 1383 */ + -7.126799136787691e-02, /* 1384 */ + 1.023036262279292e-02, /* 1385 */ + }, { + -7.396255708510786e-04, /* 1386 */ + 2.909748337454149e-02, /* 1387 */ + -1.345839754921861e-01, /* 1388 */ + 8.646534507630197e-01, /* 1389 */ + 3.028084474414053e-01, /* 1390 */ + -7.242813949145467e-02, /* 1391 */ + 1.045326763833955e-02, /* 1392 */ + }, { + -7.204440001421441e-04, /* 1393 */ + 2.917725561278015e-02, /* 1394 */ + -1.352419061957486e-01, /* 1395 */ + 8.610037382027232e-01, /* 1396 */ + 3.079366178064618e-01, /* 1397 */ + -7.358773627555218e-02, /* 1398 */ + 1.067774245655789e-02, /* 1399 */ + }, { + -7.011352205348302e-04, /* 1400 */ + 2.924929438162952e-02, /* 1401 */ + -1.358688805688508e-01, /* 1402 */ + 8.573133838948686e-01, /* 1403 */ + 3.130798245022357e-01, /* 1404 */ + -7.474654863430663e-02, /* 1405 */ + 1.090374333319907e-02, /* 1406 */ + }, { + -6.817239793932266e-04, /* 1407 */ + 2.931368276780341e-02, /* 1408 */ + -1.364651061749298e-01, /* 1409 */ + 8.535827978827749e-01, /* 1410 */ + 3.182376256616457e-01, /* 1411 */ + -7.590434139872407e-02, /* 1412 */ + 1.113122545072202e-02, /* 1413 */ + }, { + -6.622346678102776e-04, /* 1414 */ + 2.937050474928606e-02, /* 1415 */ + -1.370307935416629e-01, /* 1416 */ + 8.498123942944995e-01, /* 1417 */ + 3.234095760565429e-01, /* 1418 */ + -7.706087734360774e-02, /* 1419 */ + 1.136014291998739e-02, /* 1420 */ + }, { + -6.426913125902382e-04, /* 1421 */ + 2.941984516715388e-02, /* 1422 */ + -1.375661561125266e-01, /* 1423 */ + 8.460025912824529e-01, /* 1424 */ + 3.285952271504655e-01, /* 1425 */ + -7.821591721502538e-02, /* 1426 */ + 1.159044878226562e-02, /* 1427 */ + }, { + -6.231175684128511e-04, /* 1428 */ + 2.946178969741759e-02, /* 1429 */ + -1.380714101980755e-01, /* 1430 */ + 8.421538109624669e-01, /* 1431 */ + 3.337941271520264e-01, /* 1432 */ + -7.936921975831460e-02, /* 1433 */ + 1.182209501156100e-02, /* 1434 */ + }, { + -6.035367101809801e-04, /* 1435 */ + 2.949642482289040e-02, /* 1436 */ + -1.385467749269494e-01, /* 1437 */ + 8.382664793523271e-01, /* 1438 */ + 3.390058210689310e-01, /* 1439 */ + -8.052054174662254e-02, /* 1440 */ + 1.205503251725260e-02, /* 1441 */ + }, { + -5.839716255532901e-04, /* 1442 */ + 2.952383780508903e-02, /* 1443 */ + -1.389924721966199e-01, /* 1444 */ + 8.343410263097801e-01, /* 1445 */ + 3.442298507626138e-01, /* 1446 */ + -8.166963800997633e-02, /* 1447 */ + 1.228921114705370e-02, /* 1448 */ + }, { + -5.644448076635753e-04, /* 1449 */ + 2.954411665617338e-02, /* 1450 */ + -1.394087266238854e-01, /* 1451 */ + 8.303778854700258e-01, /* 1452 */ + 3.494657550034874e-01, /* 1453 */ + -8.281626146488272e-02, /* 1454 */ + 1.252457969029095e-02, /* 1455 */ + }, { + -5.449783480282249e-04, /* 1456 */ + 2.955735011093100e-02, /* 1457 */ + -1.397957654951237e-01, /* 1458 */ + 8.263774941827043e-01, /* 1459 */ + 3.547130695267950e-01, /* 1460 */ + -8.396016314445182e-02, /* 1461 */ + 1.276108588150466e-02, /* 1462 */ + }, { + -5.255939296432825e-04, /* 1463 */ + 2.956362759881255e-02, /* 1464 */ + -1.401538187163136e-01, /* 1465 */ + 8.223402934483920e-01, /* 1466 */ + 3.599713270890607e-01, /* 1467 */ + -8.510109222904338e-02, /* 1468 */ + 1.299867640437090e-02, /* 1469 */ + }, { + -5.063128202724816e-04, /* 1470 */ + 2.956303921602418e-02, /* 1471 */ + -1.404831187628331e-01, /* 1472 */ + 8.182667278546104e-01, /* 1473 */ + 3.652400575251253e-01, /* 1474 */ + -8.623879607743025e-02, /* 1475 */ + 1.323729689594689e-02, /* 1476 */ + }, { + -4.871558659276469e-04, /* 1477 */ + 2.955567569768274e-02, /* 1478 */ + -1.407839006290460e-01, /* 1479 */ + 8.141572455113678e-01, /* 1480 */ + 3.705187878057628e-01, /* 1481 */ + -8.737302025847754e-02, /* 1482 */ + 1.347689195124034e-02, /* 1483 */ + }, { + -4.681434845426153e-04, /* 1484 */ + 2.954162839003991e-02, /* 1485 */ + -1.410564017776856e-01, /* 1486 */ + 8.100122979862356e-01, /* 1487 */ + 3.758070420958670e-01, /* 1488 */ + -8.850350858333141e-02, /* 1489 */ + 1.371740512810407e-02, /* 1490 */ + }, { + -4.492956598419907e-04, /* 1491 */ + 2.952098922278122e-02, /* 1492 */ + -1.413008620890449e-01, /* 1493 */ + 8.058323402389781e-01, /* 1494 */ + 3.811043418132007e-01, /* 1495 */ + -8.963000313811628e-02, /* 1496 */ + 1.395877895245621e-02, /* 1497 */ + }, { + -4.306319354058826e-04, /* 1498 */ + 2.949385068140553e-02, /* 1499 */ + -1.415175238099844e-01, /* 1500 */ + 8.016178305557399e-01, /* 1501 */ + 3.864102056876984e-01, /* 1502 */ + -9.075224431713386e-02, /* 1503 */ + 1.420095492382687e-02, /* 1504 */ + }, { + -4.121714089315939e-04, /* 1505 */ + 2.946030577969092e-02, /* 1506 */ + -1.417066315027663e-01, /* 1507 */ + 7.973692304828067e-01, /* 1508 */ + 3.917241498213130e-01, /* 1509 */ + -9.186997085656183e-02, /* 1510 */ + 1.444387352123256e-02, /* 1511 */ + }, { + -3.939327266934505e-04, /* 1512 */ + 2.942044803225294e-02, /* 1513 */ + -1.418684319937252e-01, /* 1514 */ + 7.930870047599514e-01, /* 1515 */ + 3.970456877483993e-01, /* 1516 */ + -9.298291986864780e-02, /* 1517 */ + 1.468747420937781e-02, /* 1518 */ + }, { + -3.759340782016456e-04, /* 1519 */ + 2.937437142720069e-02, /* 1520 */ + -1.420031743217853e-01, /* 1521 */ + 7.887716212533704e-01, /* 1522 */ + 4.023743304966226e-01, /* 1523 */ + -9.409082687639277e-02, /* 1524 */ + 1.493169544518567e-02, /* 1525 */ + }, { + -3.581931910609877e-04, /* 1526 */ + 2.932217039889637e-02, /* 1527 */ + -1.421111096868331e-01, /* 1528 */ + 7.844235508882289e-01, /* 1529 */ + 4.077095866483865e-01, /* 1530 */ + -9.519342584872197e-02, /* 1531 */ + 1.517647468465644e-02, /* 1532 */ + }, { + -3.407273260304884e-04, /* 1533 */ + 2.926393980082415e-02, /* 1534 */ + -1.421924913979572e-01, /* 1535 */ + 7.800432675808223e-01, /* 1536 */ + 4.130509624027673e-01, /* 1537 */ + -9.629044923613632e-02, /* 1538 */ + 1.542174839005620e-02, /* 1539 */ + }, { + -3.235532722844501e-04, /* 1540 */ + 2.919977487857369e-02, /* 1541 */ + -1.422475748215626e-01, /* 1542 */ + 7.756312481703652e-01, /* 1543 */ + 4.183979616379481e-01, /* 1544 */ + -9.738162800684201e-02, /* 1545 */ + 1.566745203743416e-02, /* 1546 */ + }, { + -3.066873428758958e-04, /* 1547 */ + 2.912977124294393e-02, /* 1548 */ + -1.422766173293711e-01, /* 1549 */ + 7.711879723504229e-01, /* 1550 */ + 4.237500859741424e-01, /* 1551 */ + -9.846669168335127e-02, /* 1552 */ + 1.591352012446994e-02, /* 1553 */ + }, { + -2.901453704029424e-04, /* 1554 */ + 2.905402484317260e-02, /* 1555 */ + -1.422798782463173e-01, /* 1556 */ + 7.667139225999916e-01, /* 1557 */ + 4.291068348369969e-01, /* 1558 */ + -9.954536837955191e-02, /* 1559 */ + 1.615988617865028e-02, /* 1560 */ + }, { + -2.739427028786713e-04, /* 1561 */ + 2.897263194029685e-02, /* 1562 */ + -1.422576187983489e-01, /* 1563 */ + 7.622095841142430e-01, /* 1564 */ + 4.344677055214644e-01, /* 1565 */ + -1.006173848382378e-01, /* 1566 */ + 1.640648276577594e-02, /* 1567 */ + }, { + -2.580941998051696e-04, /* 1568 */ + 2.888568908065016e-02, /* 1569 */ + -1.422101020601427e-01, /* 1570 */ + 7.576754447349440e-01, /* 1571 */ + 4.398321932561375e-01, /* 1572 */ + -1.016824664690990e-01, /* 1573 */ + 1.665324149879781e-02, /* 1574 */ + }, { + -2.426142284520608e-04, /* 1575 */ + 2.879329306950119e-02, /* 1576 */ + -1.421375929027446e-01, /* 1577 */ + 7.531119948805626e-01, /* 1578 */ + 4.451997912680325e-01, /* 1579 */ + -1.027403373871614e-01, /* 1580 */ + 1.690009304698279e-02, /* 1581 */ + }, { + -2.275166603400509e-04, /* 1582 */ + 2.869554094483946e-02, /* 1583 */ + -1.420403579411441e-01, /* 1584 */ + 7.485197274760710e-01, /* 1585 */ + 4.505699908478140e-01, /* 1586 */ + -1.037907204516760e-01, /* 1587 */ + 1.714696714540915e-02, /* 1588 */ + }, { + -2.128148679298167e-04, /* 1589 */ + 2.859252995131316e-02, /* 1590 */ + -1.419186654817930e-01, /* 1591 */ + 7.438991378824603e-01, /* 1592 */ + 4.559422814154492e-01, /* 1593 */ + -1.048333373054486e-01, /* 1594 */ + 1.739379260479069e-02, /* 1595 */ + }, { + -1.985217215164836e-04, /* 1596 */ + 2.848435751432410e-02, /* 1597 */ + -1.417727854700776e-01, /* 1598 */ + 7.392507238259753e-01, /* 1599 */ + 4.613161505862837e-01, /* 1600 */ + -1.058679084146052e-01, /* 1601 */ + 1.764049732162978e-02, /* 1602 */ + }, { + -1.846495863300355e-04, /* 1603 */ + 2.837112121428517e-02, /* 1604 */ + -1.416029894377547e-01, /* 1605 */ + 7.345749853270843e-01, /* 1606 */ + 4.666910842375266e-01, /* 1607 */ + -1.068941531087891e-01, /* 1608 */ + 1.788700828869835e-02, /* 1609 */ + }, { + -1.712103198416544e-04, /* 1610 */ + 2.825291876104482e-02, /* 1611 */ + -1.414095504503600e-01, /* 1612 */ + 7.298724246291924e-01, /* 1613 */ + 4.720665665751356e-01, /* 1614 */ + -1.079117896217818e-01, /* 1615 */ + 1.813325160584695e-02, /* 1616 */ + }, { + -1.582152692763085e-04, /* 1617 */ + 2.812984796848375e-02, /* 1618 */ + -1.411927430545998e-01, /* 1619 */ + 7.251435461271148e-01, /* 1620 */ + 4.774420802010910e-01, /* 1621 */ + -1.089205351325436e-01, /* 1622 */ + 1.837915249114045e-02, /* 1623 */ + }, { + -1.456752693314445e-04, /* 1624 */ + 2.800200672928881e-02, /* 1625 */ + -1.409528432257348e-01, /* 1626 */ + 7.203888562953171e-01, /* 1627 */ + 4.828171061810496e-01, /* 1628 */ + -1.099201058066671e-01, /* 1629 */ + 1.862463529232039e-02, /* 1630 */ + }, { + -1.336006401019428e-04, /* 1631 */ + 2.786949298990845e-02, /* 1632 */ + -1.406901283149657e-01, /* 1633 */ + 7.156088636159380e-01, /* 1634 */ + 4.881911241123659e-01, /* 1635 */ + -1.109102168382377e-01, /* 1636 */ + 1.886962349859249e-02, /* 1637 */ + }, { + -1.220011852110915e-04, /* 1638 */ + 2.773240472569498e-02, /* 1639 */ + -1.404048769968304e-01, /* 1640 */ + 7.108040785066047e-01, /* 1641 */ + 4.935636121924722e-01, /* 1642 */ + -1.118905824920952e-01, /* 1643 */ + 1.911403975273935e-02, /* 1644 */ + }, { + -1.108861901476344e-04, /* 1645 */ + 2.759083991623796e-02, /* 1646 */ + -1.400973692166212e-01, /* 1647 */ + 7.059750132480542e-01, /* 1648 */ + 4.989340472876037e-01, /* 1649 */ + -1.128609161464899e-01, /* 1650 */ + 1.935780586355643e-02, /* 1651 */ + }, { + -1.002644208085391e-04, /* 1652 */ + 2.744489652089330e-02, /* 1653 */ + -1.397678861378340e-01, /* 1654 */ + 7.011221819115717e-01, /* 1655 */ + 5.043019050018616e-01, /* 1656 */ + -1.138209303361282e-01, /* 1657 */ + 1.960084281861067e-02, /* 1658 */ + }, { + -9.014412224732896e-05, /* 1659 */ + 2.729467245451285e-02, /* 1660 */ + -1.394167100896560e-01, /* 1661 */ + 6.962461002862578e-01, /* 1662 */ + 5.096666597466010e-01, /* 1663 */ + -1.147703367955984e-01, /* 1664 */ + 1.984307079732106e-02, /* 1665 */ + }, { + -8.053301762762107e-05, /* 1666 */ + 2.714026556337870e-02, /* 1667 */ + -1.390441245145027e-01, /* 1668 */ + 6.913472858061384e-01, /* 1669 */ + 5.150277848101327e-01, /* 1670 */ + -1.157088465031742e-01, /* 1671 */ + 2.008440918435909e-02, /* 1672 */ + }, { + -7.143830738156712e-05, /* 1673 */ + 2.698177360134680e-02, /* 1674 */ + -1.386504139156142e-01, /* 1675 */ + 6.864262574771270e-01, /* 1676 */ + 5.203847524277286e-01, /* 1677 */ + -1.166361697249849e-01, /* 1678 */ + 2.032477658336845e-02, /* 1679 */ + }, { + -6.286666857267136e-05, /* 1680 */ + 2.681929420620386e-02, /* 1681 */ + -1.382358638047184e-01, /* 1682 */ + 6.814835358038533e-01, /* 1683 */ + 5.257370338519197e-01, /* 1684 */ + -1.175520160595501e-01, /* 1685 */ + 2.056409083100217e-02, /* 1686 */ + }, { + -5.482425446254296e-05, /* 1687 */ + 2.665292487624222e-02, /* 1688 */ + -1.378007606497726e-01, /* 1689 */ + 6.765196427163698e-01, /* 1690 */ + 5.310840994230748e-01, /* 1691 */ + -1.184560944826678e-01, /* 1692 */ + 2.080226901127631e-02, /* 1693 */ + }, { + -4.731669428110093e-05, /* 1694 */ + 2.648276294705649e-02, /* 1695 */ + -1.373453918227895e-01, /* 1696 */ + 6.715351014967476e-01, /* 1697 */ + 5.364254186402488e-01, /* 1698 */ + -1.193481133926526e-01, /* 1699 */ + 2.103922747023789e-02, /* 1700 */ + }, { + -4.034909319948082e-05, /* 1701 */ + 2.630890556856650e-02, /* 1702 */ + -1.368700455477614e-01, /* 1703 */ + 6.665304367055752e-01, /* 1704 */ + 5.417604602322907e-01, /* 1705 */ + -1.202277806559141e-01, /* 1706 */ + 2.127488183094605e-02, /* 1707 */ + }, { + -3.392603250514114e-05, /* 1708 */ + 2.613144968226988e-02, /* 1709 */ + -1.363750108486864e-01, /* 1710 */ + 6.615061741083712e-01, /* 1711 */ + 5.470886922291980e-01, /* 1712 */ + -1.210948036528713e-01, /* 1713 */ + 2.150914700876424e-02, /* 1714 */ + }, { + -2.805156997831240e-05, /* 1715 */ + 2.595049199872917e-02, /* 1716 */ + -1.358605774977103e-01, /* 1717 */ + 6.564628406019232e-01, /* 1718 */ + 5.524095820337069e-01, /* 1719 */ + -1.219488893241928e-01, /* 1720 */ + 2.174193722696236e-02, /* 1721 */ + }, { + -2.272924046911682e-05, /* 1722 */ + 2.576612897529643e-02, /* 1723 */ + -1.353270359633906e-01, /* 1724 */ + 6.514009641405650e-01, /* 1725 */ + 5.577225964931086e-01, /* 1726 */ + -1.227897442173580e-01, /* 1727 */ + 2.197316603262602e-02, /* 1728 */ + }, { + -1.796205667443242e-05, /* 1729 */ + 2.557845679407980e-02, /* 1730 */ + -1.347746773590917e-01, /* 1731 */ + 6.463210736624057e-01, /* 1732 */ + 5.630272019712755e-01, /* 1733 */ + -1.236170745335310e-01, /* 1734 */ + 2.220274631287172e-02, /* 1735 */ + }, { + -1.375251011368080e-05, /* 1736 */ + 2.538757134015553e-02, /* 1737 */ + -1.342037933915221e-01, /* 1738 */ + 6.412236990155202e-01, /* 1739 */ + 5.683228644208926e-01, /* 1740 */ + -1.244305861747393e-01, /* 1741 */ + 2.243059031136537e-02, /* 1742 */ + }, { + -1.010257230258042e-05, /* 1743 */ + 2.519356818002896e-02, /* 1744 */ + -1.336146763094198e-01, /* 1745 */ + 6.361093708841161e-01, /* 1746 */ + 5.736090494558752e-01, /* 1747 */ + -1.252299847913509e-01, /* 1748 */ + 2.265660964514263e-02, /* 1749 */ + }, { + -7.013696123785544e-06, /* 1750 */ + 2.499654254034837e-02, /* 1751 */ + -1.330076188523975e-01, /* 1752 */ + 6.309786207146856e-01, /* 1753 */ + 5.788852224239674e-01, /* 1754 */ + -1.260149758298408e-01, /* 1755 */ + 2.288071532172811e-02, /* 1756 */ + }, { + -4.486817393493708e-06, /* 1757 */ + 2.479658928687493e-02, /* 1758 */ + -1.323829141999531e-01, /* 1759 */ + 6.258319806421593e-01, /* 1760 */ + 5.841508484795060e-01, /* 1761 */ + -1.267852645808413e-01, /* 1762 */ + 2.310281775655174e-02, /* 1763 */ + }, { + -2.522356622734990e-06, /* 1764 */ + 2.459380290371239e-02, /* 1765 */ + -1.317408559206581e-01, /* 1766 */ + 6.206699834160688e-01, /* 1767 */ + 5.894053926563386e-01, /* 1768 */ + -1.275405562274653e-01, /* 1769 */ + 2.332282679065955e-02, /* 1770 */ + }, { + -1.120220972351802e-06, /* 1771 */ + 2.438827747279956e-02, /* 1772 */ + -1.310817379215285e-01, /* 1773 */ + 6.154931623267351e-01, /* 1774 */ + 5.946483199408858e-01, /* 1775 */ + -1.282805558938982e-01, /* 1776 */ + 2.354065170871666e-02, /* 1777 */ + }, { + -2.798064002790454e-07, /* 1778 */ + 2.418010665366927e-02, /* 1779 */ + -1.304058543975903e-01, /* 1780 */ + 6.103020511314905e-01, /* 1781 */ + 5.998790953453343e-01, /* 1782 */ + -1.290049686942476e-01, /* 1783 */ + 2.375620125729980e-02, /* 1784 */ + }, { + -0.000000000000000e+00, /* 1785 */ + 2.396938366347660e-02, /* 1786 */ + -1.297134997816453e-01, /* 1787 */ + 6.050971839809485e-01, /* 1788 */ + 6.050971839809485e-01, /* 1789 */ + -1.297134997816453e-01, /* 1790 */ + 2.396938366347660e-02, /* 1791 */ + } +}; diff --git a/libs/fluidsynth/glib.c b/libs/fluidsynth/glib.c new file mode 100644 index 00000000000..cd938a4fb6b --- /dev/null +++ b/libs/fluidsynth/glib.c @@ -0,0 +1,106 @@ +/* + * Copyright 2023 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 + */ + +#include + +int g_vsnprintf( char *buffer, size_t size, const char *format, va_list args ) +{ + int ret = _vsnprintf( buffer, size - 1, format, args ); + if (ret >= 0 && ret < size) buffer[ret] = 0; + else buffer[0] = 0; + return ret; +} + +int g_snprintf( char *buffer, size_t size, const char *format, ... ) +{ + va_list args; + int ret; + + va_start( args, format ); + ret = g_vsnprintf( buffer, size, format, args ); + va_end( args ); + + return ret; +} + +double g_get_monotonic_time(void) +{ + static LARGE_INTEGER frequency = {0}; + LARGE_INTEGER counter; + + if (!frequency.QuadPart) QueryPerformanceFrequency( &frequency ); + QueryPerformanceCounter( &counter ); + + return counter.QuadPart * 1000000.0 / frequency.QuadPart; /* time in micros */ +} + +void g_usleep( unsigned int micros ) +{ + Sleep( micros / 1000 ); +} + +static DWORD CALLBACK g_thread_wrapper( void *args ) +{ + GThread *thread = args; + gpointer ret = thread->func( thread->data ); + if (!InterlockedDecrement( &thread->ref )) free( thread ); + return (UINT_PTR)ret; +} + +GThread *g_thread_try_new( const char *name, GThreadFunc func, gpointer data, GError **err ) +{ + GThread *thread; + + if (!(thread = calloc( 1, sizeof(*thread) ))) return NULL; + thread->ref = 2; + thread->func = func; + thread->data = data; + + if (!(thread->handle = CreateThread( NULL, 0, g_thread_wrapper, thread, 0, NULL ))) + { + free( thread ); + return NULL; + } + + return thread; +} + +void g_thread_unref( GThread *thread ) +{ + CloseHandle( thread->handle ); + if (!InterlockedDecrement( &thread->ref )) free( thread ); +} + +void g_thread_join( GThread *thread ) +{ + WaitForSingleObject( thread->handle, INFINITE ); + g_thread_unref( thread ); +} + +void g_clear_error( GError **error ) +{ + *error = NULL; +} + +int g_file_test( const char *path, int test ) +{ + DWORD attrs = GetFileAttributesA( path ); + if (test == G_FILE_TEST_EXISTS) return attrs != INVALID_FILE_ATTRIBUTES; + if (test == G_FILE_TEST_IS_REGULAR) return attrs == FILE_ATTRIBUTE_NORMAL; + return 0; +} diff --git a/libs/fluidsynth/glib.h b/libs/fluidsynth/glib.h new file mode 100644 index 00000000000..722173d825a --- /dev/null +++ b/libs/fluidsynth/glib.h @@ -0,0 +1,107 @@ +/* + * Copyright 2023 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 + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#define GLIB_CHECK_VERSION(x, y, z) ((x) < GLIB_MAJOR_VERSION || ((x) == GLIB_MAJOR_VERSION && (y) <= GLIB_MINOR_VERSION)) +#define GLIB_MAJOR_VERSION 2 +#define GLIB_MINOR_VERSION 54 + +#define G_BYTE_ORDER 1234 +#define G_BIG_ENDIAN 4321 +#define GINT32_FROM_LE(val) ((INT32)(val)) +#define GINT16_FROM_LE(val) ((INT16)(val)) + +#define G_UNLIKELY(expr) (expr) +#define G_LIKELY(expr) (expr) + +#define g_return_val_if_fail( cond, val ) do { if (!(cond)) return (val); } while (0) + +typedef void *gpointer; +typedef gpointer (*GThreadFunc)( gpointer data ); + +typedef struct _stat64 GStatBuf; +#define g_stat _stat64 + +typedef struct +{ + const char *message; +} GError; + +typedef struct +{ + LONG ref; + HANDLE handle; + GThreadFunc func; + gpointer data; +} GThread; + +extern int g_vsnprintf( char *buffer, size_t size, const char *format, va_list args ) __WINE_CRT_PRINTF_ATTR(3, 0); +extern int g_snprintf( char *buffer, size_t size, const char *format, ... ) __WINE_CRT_PRINTF_ATTR(3, 4); + +extern double g_get_monotonic_time(void); +extern void g_usleep( unsigned int micros ); + +extern GThread *g_thread_try_new( const char *name, GThreadFunc func, gpointer data, GError **err ); +extern void g_thread_unref( GThread *thread ); +extern void g_thread_join( GThread *thread ); +extern void g_clear_error( GError **error ); + +#define G_FILE_TEST_EXISTS 1 +#define G_FILE_TEST_IS_REGULAR 2 + +extern int g_file_test( const char *path, int test ); + +#define g_new( type, count ) calloc( (count), sizeof(type) ) +static void g_free( void *ptr ) { free( ptr ); } + +typedef SRWLOCK GMutex; +static void g_mutex_init( GMutex *mutex ) {} +static void g_mutex_clear( GMutex *mutex ) {} +static void g_mutex_lock( GMutex *mutex ) { AcquireSRWLockExclusive( mutex ); } +static void g_mutex_unlock( GMutex *mutex ) { ReleaseSRWLockExclusive( mutex ); } + +typedef CRITICAL_SECTION GRecMutex; +static void g_rec_mutex_init( GRecMutex *mutex ) { InitializeCriticalSection( mutex ); } +static void g_rec_mutex_clear( GRecMutex *mutex ) { DeleteCriticalSection( mutex ); } +static void g_rec_mutex_lock( GRecMutex *mutex ) { EnterCriticalSection( mutex ); } +static void g_rec_mutex_unlock( GRecMutex *mutex ) { LeaveCriticalSection( mutex ); } + +typedef CONDITION_VARIABLE GCond; +static void g_cond_init( GCond *cond ) {} +static void g_cond_clear( GCond *cond ) {} +static void g_cond_signal( GCond *cond ) { WakeConditionVariable( cond ); } +static void g_cond_broadcast( GCond *cond ) { WakeAllConditionVariable( cond ); } +static void g_cond_wait( GCond *cond, GMutex *mutex ) { SleepConditionVariableSRW( cond, mutex, INFINITE, 0 ); } + +static void g_atomic_int_inc( int *ptr ) { InterlockedIncrement( (LONG *)ptr ); } +static int g_atomic_int_add( int *ptr, int val ) { return InterlockedAdd( (LONG *)ptr, val ) - 1; } +static int g_atomic_int_get( int *ptr ) { return ReadAcquire( (LONG *)ptr ); } +static void g_atomic_int_set( int *ptr, int val ) { InterlockedExchange( (LONG *)ptr, val ); } +static int g_atomic_int_dec_and_test( int *ptr, int val ) { return !InterlockedAdd( (LONG *)ptr, -val ); } +static int g_atomic_int_compare_and_exchange( int *ptr, int cmp, int val ) { return InterlockedCompareExchange( (LONG *)ptr, val, cmp ) == cmp; } diff --git a/libs/fluidsynth/include/fluidsynth.h b/libs/fluidsynth/include/fluidsynth.h new file mode 100644 index 00000000000..5577072ccaf --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth.h @@ -0,0 +1,125 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_H +#define _FLUIDSYNTH_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define BUILD_SHARED_LIBS 0 + +#if (BUILD_SHARED_LIBS == 0) + #define FLUIDSYNTH_API // building static lib? no visibility control then +#elif defined(WIN32) + #if defined(FLUIDSYNTH_NOT_A_DLL) + #define FLUIDSYNTH_API + #elif defined(FLUIDSYNTH_DLL_EXPORTS) + #define FLUIDSYNTH_API __declspec(dllexport) + #else + #define FLUIDSYNTH_API __declspec(dllimport) + #endif + +#elif defined(MACOS9) +#define FLUIDSYNTH_API __declspec(export) + +#elif defined(__OS2__) +#define FLUIDSYNTH_API __declspec(dllexport) + +#elif defined(__GNUC__) +#define FLUIDSYNTH_API __attribute__ ((visibility ("default"))) + +#else +#define FLUIDSYNTH_API + +#endif + +#if 1 /* Wine-specific code */ +# define FLUID_DEPRECATED +#else /* Wine-specific code */ +#if defined(__GNUC__) || defined(__clang__) +# define FLUID_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) && _MSC_VER > 1200 +# define FLUID_DEPRECATED __declspec(deprecated) +#else +# define FLUID_DEPRECATED +#endif +#endif /* Wine-specific code */ + + +/** + * @file fluidsynth.h + * @brief FluidSynth is a real-time synthesizer designed for SoundFont(R) files. + * + * This is the header of the fluidsynth library and contains the + * synthesizer's public API. + * + * Depending on how you want to use or extend the synthesizer you + * will need different API functions. You probably do not need all + * of them. Here is what you might want to do: + * + * - Embedded synthesizer: create a new synthesizer and send MIDI + * events to it. The sound goes directly to the audio output of + * your system. + * + * - Plugin synthesizer: create a synthesizer and send MIDI events + * but pull the audio back into your application. + * + * - SoundFont plugin: create a new type of "SoundFont" and allow + * the synthesizer to load your type of SoundFonts. + * + * - MIDI input: Create a MIDI handler to read the MIDI input on your + * machine and send the MIDI events directly to the synthesizer. + * + * - MIDI files: Open MIDI files and send the MIDI events to the + * synthesizer. + * + * - Command lines: You can send textual commands to the synthesizer. + * + * SoundFont(R) is a registered trademark of E-mu Systems, Inc. + */ + +#include "fluidsynth/types.h" +#include "fluidsynth/settings.h" +#include "fluidsynth/synth.h" +#include "fluidsynth/shell.h" +#include "fluidsynth/sfont.h" +#include "fluidsynth/audio.h" +#include "fluidsynth/event.h" +#include "fluidsynth/midi.h" +#include "fluidsynth/seq.h" +#include "fluidsynth/seqbind.h" +#include "fluidsynth/log.h" +#include "fluidsynth/misc.h" +#include "fluidsynth/mod.h" +#include "fluidsynth/gen.h" +#include "fluidsynth/voice.h" +#include "fluidsynth/version.h" +#include "fluidsynth/ladspa.h" + + +#ifdef __cplusplus +} +#endif + +#endif /* _FLUIDSYNTH_H */ diff --git a/libs/fluidsynth/include/fluidsynth/audio.h b/libs/fluidsynth/include/fluidsynth/audio.h new file mode 100644 index 00000000000..1c12ff792cc --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth/audio.h @@ -0,0 +1,155 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_AUDIO_H +#define _FLUIDSYNTH_AUDIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup audio_output Audio Output + * + * Functions for managing audio drivers and file renderers. + * + * The file renderer is used for fast rendering of MIDI files to + * audio files. The audio drivers are a high-level interface to + * connect the synthesizer with external audio sinks or to render + * real-time audio to files. + */ + +/** + * @defgroup audio_driver Audio Driver + * @ingroup audio_output + * + * Functions for managing audio drivers. + * + * Defines functions for creating audio driver output. Use + * new_fluid_audio_driver() to create a new audio driver for a given synth + * and configuration settings. + * + * The function new_fluid_audio_driver2() can be + * used if custom audio processing is desired before the audio is sent to the + * audio driver (although it is not as efficient). + * + * @sa @ref CreatingAudioDriver + * + * @{ + */ + +/** + * Callback function type used with new_fluid_audio_driver2() to allow for + * custom user audio processing before the audio is sent to the driver. + * + * @param data The user data parameter as passed to new_fluid_audio_driver2(). + * @param len Count of audio frames to synthesize. + * @param nfx Count of arrays in \c fx. + * @param fx Array of buffers to store effects audio to. Buffers may alias with buffers of \c out. + * @param nout Count of arrays in \c out. + * @param out Array of buffers to store (dry) audio to. Buffers may alias with buffers of \c fx. + * @return Should return #FLUID_OK on success, #FLUID_FAILED if an error occurred. + * + * This function is responsible for rendering audio to the buffers. + * The buffers passed to this function are allocated and owned by the respective + * audio driver and are only valid during that specific call (do not cache them). + * The buffers have already been zeroed-out. + * For further details please refer to fluid_synth_process(). + * + * @parblock + * @note Whereas fluid_synth_process() allows aliasing buffers, there is the guarantee that @p out + * and @p fx buffers provided by fluidsynth's audio drivers never alias. This prevents downstream + * applications from e.g. applying a custom effect accidentally to the same buffer multiple times. + * @endparblock + * + * @parblock + * @note Also note that the Jack driver is currently the only driver that has dedicated @p fx buffers + * (but only if \setting{audio_jack_multi} is true). All other drivers do not provide @p fx buffers. + * In this case, users are encouraged to mix the effects into the provided dry buffers when calling + * fluid_synth_process(). + * @code{.cpp} +int myCallback(void *, int len, int nfx, float *fx[], int nout, float *out[]) +{ + int ret; + if(nfx == 0) + { + float *fxb[4] = {out[0], out[1], out[0], out[1]}; + ret = fluid_synth_process(synth, len, sizeof(fxb) / sizeof(fxb[0]), fxb, nout, out); + } + else + { + ret = fluid_synth_process(synth, len, nfx, fx, nout, out); + } + // ... client-code ... + return ret; +} + * @endcode + * For other possible use-cases refer to \ref fluidsynth_process.c . + * @endparblock + */ +typedef int (*fluid_audio_func_t)(void *data, int len, + int nfx, float *fx[], + int nout, float *out[]); + +/** @startlifecycle{Audio Driver} */ +FLUIDSYNTH_API fluid_audio_driver_t *new_fluid_audio_driver(fluid_settings_t *settings, + fluid_synth_t *synth); + +FLUIDSYNTH_API fluid_audio_driver_t *new_fluid_audio_driver2(fluid_settings_t *settings, + fluid_audio_func_t func, + void *data); + +FLUIDSYNTH_API void delete_fluid_audio_driver(fluid_audio_driver_t *driver); +/** @endlifecycle */ + +FLUIDSYNTH_API int fluid_audio_driver_register(const char **adrivers); +/** @} */ + +/** + * @defgroup file_renderer File Renderer + * @ingroup audio_output + * + * Functions for managing file renderers and triggering the rendering. + * + * The file renderer is only used to render a MIDI file to audio as fast + * as possible. Please see \ref FileRenderer for a full example. + * + * If you are looking for a way to write audio generated + * from real-time events (for example from an external sequencer or a MIDI controller) to a file, + * please have a look at the \c file \ref audio_driver instead. + * + * + * @{ + */ + +/** @startlifecycle{File Renderer} */ +FLUIDSYNTH_API fluid_file_renderer_t *new_fluid_file_renderer(fluid_synth_t *synth); +FLUIDSYNTH_API void delete_fluid_file_renderer(fluid_file_renderer_t *dev); +/** @endlifecycle */ + +FLUIDSYNTH_API int fluid_file_renderer_process_block(fluid_file_renderer_t *dev); +FLUIDSYNTH_API int fluid_file_set_encoding_quality(fluid_file_renderer_t *dev, double q); +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FLUIDSYNTH_AUDIO_H */ diff --git a/libs/fluidsynth/include/fluidsynth/event.h b/libs/fluidsynth/include/fluidsynth/event.h new file mode 100644 index 00000000000..e46084f0e40 --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth/event.h @@ -0,0 +1,143 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_EVENT_H +#define _FLUIDSYNTH_EVENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup sequencer_events Sequencer Events + * @ingroup sequencer + * + * Create, modify, query and destroy sequencer events. + * + * @{ + */ + +/** + * Sequencer event type enumeration. + */ +enum fluid_seq_event_type +{ + FLUID_SEQ_NOTE = 0, /**< Note event with duration */ + FLUID_SEQ_NOTEON, /**< Note on event */ + FLUID_SEQ_NOTEOFF, /**< Note off event */ + FLUID_SEQ_ALLSOUNDSOFF, /**< All sounds off event */ + FLUID_SEQ_ALLNOTESOFF, /**< All notes off event */ + FLUID_SEQ_BANKSELECT, /**< Bank select message */ + FLUID_SEQ_PROGRAMCHANGE, /**< Program change message */ + FLUID_SEQ_PROGRAMSELECT, /**< Program select message */ + FLUID_SEQ_PITCHBEND, /**< Pitch bend message */ + FLUID_SEQ_PITCHWHEELSENS, /**< Pitch wheel sensitivity set message @since 1.1.0 was misspelled previously */ + FLUID_SEQ_MODULATION, /**< Modulation controller event */ + FLUID_SEQ_SUSTAIN, /**< Sustain controller event */ + FLUID_SEQ_CONTROLCHANGE, /**< MIDI control change event */ + FLUID_SEQ_PAN, /**< Stereo pan set event */ + FLUID_SEQ_VOLUME, /**< Volume set event */ + FLUID_SEQ_REVERBSEND, /**< Reverb send set event */ + FLUID_SEQ_CHORUSSEND, /**< Chorus send set event */ + FLUID_SEQ_TIMER, /**< Timer event (useful for giving a callback at a certain time) */ + FLUID_SEQ_CHANNELPRESSURE, /**< Channel aftertouch event @since 1.1.0 */ + FLUID_SEQ_KEYPRESSURE, /**< Polyphonic aftertouch event @since 2.0.0 */ + FLUID_SEQ_SYSTEMRESET, /**< System reset event @since 1.1.0 */ + FLUID_SEQ_UNREGISTERING, /**< Called when a sequencer client is being unregistered. @since 1.1.0 */ + FLUID_SEQ_SCALE, /**< Sets a new time scale for the sequencer @since 2.2.0 */ + FLUID_SEQ_LASTEVENT /**< @internal Defines the count of events enums @warning This symbol + is not part of the public API and ABI stability guarantee and + may change at any time! */ +}; + +/* Event alloc/free */ +/** @startlifecycle{Sequencer Event} */ +FLUIDSYNTH_API fluid_event_t *new_fluid_event(void); +FLUIDSYNTH_API void delete_fluid_event(fluid_event_t *evt); +/** @endlifecycle */ + +/* Initializing events */ +FLUIDSYNTH_API void fluid_event_set_source(fluid_event_t *evt, fluid_seq_id_t src); +FLUIDSYNTH_API void fluid_event_set_dest(fluid_event_t *evt, fluid_seq_id_t dest); + +/* Timer events */ +FLUIDSYNTH_API void fluid_event_timer(fluid_event_t *evt, void *data); + +/* Note events */ +FLUIDSYNTH_API void fluid_event_note(fluid_event_t *evt, int channel, + short key, short vel, + unsigned int duration); + +FLUIDSYNTH_API void fluid_event_noteon(fluid_event_t *evt, int channel, short key, short vel); +FLUIDSYNTH_API void fluid_event_noteoff(fluid_event_t *evt, int channel, short key); +FLUIDSYNTH_API void fluid_event_all_sounds_off(fluid_event_t *evt, int channel); +FLUIDSYNTH_API void fluid_event_all_notes_off(fluid_event_t *evt, int channel); + +/* Instrument selection */ +FLUIDSYNTH_API void fluid_event_bank_select(fluid_event_t *evt, int channel, short bank_num); +FLUIDSYNTH_API void fluid_event_program_change(fluid_event_t *evt, int channel, int preset_num); +FLUIDSYNTH_API void fluid_event_program_select(fluid_event_t *evt, int channel, unsigned int sfont_id, short bank_num, short preset_num); + +/* Real-time generic instrument controllers */ +FLUIDSYNTH_API +void fluid_event_control_change(fluid_event_t *evt, int channel, short control, int val); + +/* Real-time instrument controllers shortcuts */ +FLUIDSYNTH_API void fluid_event_pitch_bend(fluid_event_t *evt, int channel, int val); +FLUIDSYNTH_API void fluid_event_pitch_wheelsens(fluid_event_t *evt, int channel, int val); +FLUIDSYNTH_API void fluid_event_modulation(fluid_event_t *evt, int channel, int val); +FLUIDSYNTH_API void fluid_event_sustain(fluid_event_t *evt, int channel, int val); +FLUIDSYNTH_API void fluid_event_pan(fluid_event_t *evt, int channel, int val); +FLUIDSYNTH_API void fluid_event_volume(fluid_event_t *evt, int channel, int val); +FLUIDSYNTH_API void fluid_event_reverb_send(fluid_event_t *evt, int channel, int val); +FLUIDSYNTH_API void fluid_event_chorus_send(fluid_event_t *evt, int channel, int val); + +FLUIDSYNTH_API void fluid_event_key_pressure(fluid_event_t *evt, int channel, short key, int val); +FLUIDSYNTH_API void fluid_event_channel_pressure(fluid_event_t *evt, int channel, int val); +FLUIDSYNTH_API void fluid_event_system_reset(fluid_event_t *evt); + +/* Only when unregistering clients */ +FLUIDSYNTH_API void fluid_event_unregistering(fluid_event_t *evt); + +FLUIDSYNTH_API void fluid_event_scale(fluid_event_t *evt, double new_scale); +FLUIDSYNTH_API int fluid_event_from_midi_event(fluid_event_t *, const fluid_midi_event_t *); + +/* Accessing event data */ +FLUIDSYNTH_API int fluid_event_get_type(fluid_event_t *evt); +FLUIDSYNTH_API fluid_seq_id_t fluid_event_get_source(fluid_event_t *evt); +FLUIDSYNTH_API fluid_seq_id_t fluid_event_get_dest(fluid_event_t *evt); +FLUIDSYNTH_API int fluid_event_get_channel(fluid_event_t *evt); +FLUIDSYNTH_API short fluid_event_get_key(fluid_event_t *evt); +FLUIDSYNTH_API short fluid_event_get_velocity(fluid_event_t *evt); +FLUIDSYNTH_API short fluid_event_get_control(fluid_event_t *evt); +FLUIDSYNTH_API int fluid_event_get_value(fluid_event_t *evt); +FLUIDSYNTH_API int fluid_event_get_program(fluid_event_t *evt); +FLUIDSYNTH_API void *fluid_event_get_data(fluid_event_t *evt); +FLUIDSYNTH_API unsigned int fluid_event_get_duration(fluid_event_t *evt); +FLUIDSYNTH_API short fluid_event_get_bank(fluid_event_t *evt); +FLUIDSYNTH_API int fluid_event_get_pitch(fluid_event_t *evt); +FLUIDSYNTH_API double fluid_event_get_scale(fluid_event_t *evt); +FLUIDSYNTH_API unsigned int fluid_event_get_sfont_id(fluid_event_t *evt); +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif /* _FLUIDSYNTH_EVENT_H */ diff --git a/libs/fluidsynth/include/fluidsynth/gen.h b/libs/fluidsynth/include/fluidsynth/gen.h new file mode 100644 index 00000000000..5a61e0bffda --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth/gen.h @@ -0,0 +1,133 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_GEN_H +#define _FLUIDSYNTH_GEN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup generators SoundFont Generators + * @ingroup soundfonts + * + * Functions and defines for SoundFont generator effects. + * + * @{ + */ + +/** + * Generator (effect) numbers (Soundfont 2.01 specifications section 8.1.3) + */ +enum fluid_gen_type +{ + GEN_STARTADDROFS, /**< Sample start address offset (0-32767) */ + GEN_ENDADDROFS, /**< Sample end address offset (-32767-0) */ + GEN_STARTLOOPADDROFS, /**< Sample loop start address offset (-32767-32767) */ + GEN_ENDLOOPADDROFS, /**< Sample loop end address offset (-32767-32767) */ + GEN_STARTADDRCOARSEOFS, /**< Sample start address coarse offset (X 32768) */ + GEN_MODLFOTOPITCH, /**< Modulation LFO to pitch */ + GEN_VIBLFOTOPITCH, /**< Vibrato LFO to pitch */ + GEN_MODENVTOPITCH, /**< Modulation envelope to pitch */ + GEN_FILTERFC, /**< Filter cutoff */ + GEN_FILTERQ, /**< Filter Q */ + GEN_MODLFOTOFILTERFC, /**< Modulation LFO to filter cutoff */ + GEN_MODENVTOFILTERFC, /**< Modulation envelope to filter cutoff */ + GEN_ENDADDRCOARSEOFS, /**< Sample end address coarse offset (X 32768) */ + GEN_MODLFOTOVOL, /**< Modulation LFO to volume */ + GEN_UNUSED1, /**< Unused */ + GEN_CHORUSSEND, /**< Chorus send amount */ + GEN_REVERBSEND, /**< Reverb send amount */ + GEN_PAN, /**< Stereo panning */ + GEN_UNUSED2, /**< Unused */ + GEN_UNUSED3, /**< Unused */ + GEN_UNUSED4, /**< Unused */ + GEN_MODLFODELAY, /**< Modulation LFO delay */ + GEN_MODLFOFREQ, /**< Modulation LFO frequency */ + GEN_VIBLFODELAY, /**< Vibrato LFO delay */ + GEN_VIBLFOFREQ, /**< Vibrato LFO frequency */ + GEN_MODENVDELAY, /**< Modulation envelope delay */ + GEN_MODENVATTACK, /**< Modulation envelope attack */ + GEN_MODENVHOLD, /**< Modulation envelope hold */ + GEN_MODENVDECAY, /**< Modulation envelope decay */ + GEN_MODENVSUSTAIN, /**< Modulation envelope sustain */ + GEN_MODENVRELEASE, /**< Modulation envelope release */ + GEN_KEYTOMODENVHOLD, /**< Key to modulation envelope hold */ + GEN_KEYTOMODENVDECAY, /**< Key to modulation envelope decay */ + GEN_VOLENVDELAY, /**< Volume envelope delay */ + GEN_VOLENVATTACK, /**< Volume envelope attack */ + GEN_VOLENVHOLD, /**< Volume envelope hold */ + GEN_VOLENVDECAY, /**< Volume envelope decay */ + GEN_VOLENVSUSTAIN, /**< Volume envelope sustain */ + GEN_VOLENVRELEASE, /**< Volume envelope release */ + GEN_KEYTOVOLENVHOLD, /**< Key to volume envelope hold */ + GEN_KEYTOVOLENVDECAY, /**< Key to volume envelope decay */ + GEN_INSTRUMENT, /**< Instrument ID (shouldn't be set by user) */ + GEN_RESERVED1, /**< Reserved */ + GEN_KEYRANGE, /**< MIDI note range */ + GEN_VELRANGE, /**< MIDI velocity range */ + GEN_STARTLOOPADDRCOARSEOFS, /**< Sample start loop address coarse offset (X 32768) */ + GEN_KEYNUM, /**< Fixed MIDI note number */ + GEN_VELOCITY, /**< Fixed MIDI velocity value */ + GEN_ATTENUATION, /**< Initial volume attenuation */ + GEN_RESERVED2, /**< Reserved */ + GEN_ENDLOOPADDRCOARSEOFS, /**< Sample end loop address coarse offset (X 32768) */ + GEN_COARSETUNE, /**< Coarse tuning */ + GEN_FINETUNE, /**< Fine tuning */ + GEN_SAMPLEID, /**< Sample ID (shouldn't be set by user) */ + GEN_SAMPLEMODE, /**< Sample mode flags */ + GEN_RESERVED3, /**< Reserved */ + GEN_SCALETUNE, /**< Scale tuning */ + GEN_EXCLUSIVECLASS, /**< Exclusive class number */ + GEN_OVERRIDEROOTKEY, /**< Sample root note override */ + + /** + * Initial Pitch + * + * @note This is not "standard" SoundFont generator, because it is not + * mentioned in the list of generators in the SF2 specifications. + * It is used by FluidSynth internally to compute the nominal pitch of + * a note on note-on event. By nature it shouldn't be allowed to be modulated, + * however the specification defines a default modulator having "Initial Pitch" + * as destination (cf. SF2.01 page 57 section 8.4.10 MIDI Pitch Wheel to Initial Pitch). + * Thus it is impossible to cancel this default modulator, which would be required + * to let the MIDI Pitch Wheel controller modulate a different generator. + * In order to provide this flexibility, FluidSynth >= 2.1.0 uses a default modulator + * "Pitch Wheel to Fine Tune", rather than Initial Pitch. The same "compromise" can + * be found on the Audigy 2 ZS for instance. + */ + GEN_PITCH, + + GEN_CUSTOM_BALANCE, /**< Balance @note Not a real SoundFont generator */ + /* non-standard generator for an additional custom high- or low-pass filter */ + GEN_CUSTOM_FILTERFC, /**< Custom filter cutoff frequency */ + GEN_CUSTOM_FILTERQ, /**< Custom filter Q */ + + GEN_LAST /**< @internal Value defines the count of generators (#fluid_gen_type) + @warning This symbol is not part of the public API and ABI + stability guarantee and may change at any time! */ +}; +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif /* _FLUIDSYNTH_GEN_H */ diff --git a/libs/fluidsynth/include/fluidsynth/ladspa.h b/libs/fluidsynth/include/fluidsynth/ladspa.h new file mode 100644 index 00000000000..24cbd6f650f --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth/ladspa.h @@ -0,0 +1,68 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_LADSPA_H +#define _FLUIDSYNTH_LADSPA_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup ladspa Effect - LADSPA + * @ingroup synth + * + * Functions for configuring the LADSPA effects unit + * + * This header defines useful functions for programmatically manipulating the ladspa + * effects unit of the synth that can be retrieved via fluid_synth_get_ladspa_fx(). + * + * Using any of those functions requires fluidsynth to be compiled with LADSPA support. + * Else all of those functions are useless dummies. + * + * @{ + */ +FLUIDSYNTH_API int fluid_ladspa_is_active(fluid_ladspa_fx_t *fx); +FLUIDSYNTH_API int fluid_ladspa_activate(fluid_ladspa_fx_t *fx); +FLUIDSYNTH_API int fluid_ladspa_deactivate(fluid_ladspa_fx_t *fx); +FLUIDSYNTH_API int fluid_ladspa_reset(fluid_ladspa_fx_t *fx); +FLUIDSYNTH_API int fluid_ladspa_check(fluid_ladspa_fx_t *fx, char *err, int err_size); + +FLUIDSYNTH_API int fluid_ladspa_host_port_exists(fluid_ladspa_fx_t *fx, const char *name); + +FLUIDSYNTH_API int fluid_ladspa_add_buffer(fluid_ladspa_fx_t *fx, const char *name); +FLUIDSYNTH_API int fluid_ladspa_buffer_exists(fluid_ladspa_fx_t *fx, const char *name); + +FLUIDSYNTH_API int fluid_ladspa_add_effect(fluid_ladspa_fx_t *fx, const char *effect_name, + const char *lib_name, const char *plugin_name); +FLUIDSYNTH_API int fluid_ladspa_effect_can_mix(fluid_ladspa_fx_t *fx, const char *name); +FLUIDSYNTH_API int fluid_ladspa_effect_set_mix(fluid_ladspa_fx_t *fx, const char *name, int mix, float gain); +FLUIDSYNTH_API int fluid_ladspa_effect_port_exists(fluid_ladspa_fx_t *fx, const char *effect_name, const char *port_name); +FLUIDSYNTH_API int fluid_ladspa_effect_set_control(fluid_ladspa_fx_t *fx, const char *effect_name, + const char *port_name, float val); +FLUIDSYNTH_API int fluid_ladspa_effect_link(fluid_ladspa_fx_t *fx, const char *effect_name, + const char *port_name, const char *name); +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FLUIDSYNTH_LADSPA_H */ diff --git a/libs/fluidsynth/include/fluidsynth/log.h b/libs/fluidsynth/include/fluidsynth/log.h new file mode 100644 index 00000000000..ab5911e011c --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth/log.h @@ -0,0 +1,97 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_LOG_H +#define _FLUIDSYNTH_LOG_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @defgroup logging Logging + * + * Logging interface + * + * The default logging function of the fluidsynth prints its messages to the + * stderr. The synthesizer uses five level of messages: #FLUID_PANIC, + * #FLUID_ERR, #FLUID_WARN, #FLUID_INFO, and #FLUID_DBG. + * + * A client application can install a new log function to handle the messages + * differently. In the following example, the application sets a callback + * function to display #FLUID_PANIC messages in a dialog, and ignores all other + * messages by setting the log function to NULL: + * + * @code + * fluid_set_log_function(FLUID_PANIC, show_dialog, (void*) root_window); + * fluid_set_log_function(FLUID_ERR, NULL, NULL); + * fluid_set_log_function(FLUID_WARN, NULL, NULL); + * fluid_set_log_function(FLUID_DBG, NULL, NULL); + * @endcode + * + * @note The logging configuration is global and not tied to a specific + * synthesizer instance. That means that all synthesizer instances created in + * the same process share the same logging configuration. + * + * @{ + */ + +/** + * FluidSynth log levels. + */ +enum fluid_log_level +{ + FLUID_PANIC, /**< The synth can't function correctly any more */ + FLUID_ERR, /**< Serious error occurred */ + FLUID_WARN, /**< Warning */ + FLUID_INFO, /**< Verbose informational messages */ + FLUID_DBG, /**< Debugging messages */ + LAST_LOG_LEVEL /**< @internal This symbol is not part of the public API and ABI + stability guarantee and may change at any time! */ +}; + +/** + * Log function handler callback type used by fluid_set_log_function(). + * + * @param level Log level (#fluid_log_level) + * @param message Log message text + * @param data User data pointer supplied to fluid_set_log_function(). + */ +typedef void (*fluid_log_function_t)(int level, const char *message, void *data); + +FLUIDSYNTH_API +fluid_log_function_t fluid_set_log_function(int level, fluid_log_function_t fun, void *data); + +FLUIDSYNTH_API void fluid_default_log_function(int level, const char *message, void *data); + +FLUIDSYNTH_API int fluid_log(int level, const char *fmt, ...) +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) +__attribute__ ((format (printf, 2, 3))) +#endif +; +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FLUIDSYNTH_LOG_H */ diff --git a/libs/fluidsynth/include/fluidsynth/midi.h b/libs/fluidsynth/include/fluidsynth/midi.h new file mode 100644 index 00000000000..044eeebd9a7 --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth/midi.h @@ -0,0 +1,295 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_MIDI_H +#define _FLUIDSYNTH_MIDI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup midi_input MIDI Input + * + * MIDI Input Subsystem + * + * There are multiple ways to send MIDI events to the synthesizer. They can come + * from MIDI files, from external MIDI sequencers or raw MIDI event sources, + * can be modified via MIDI routers and also generated manually. + * + * The interface connecting all sources and sinks of MIDI events in libfluidsynth + * is \ref handle_midi_event_func_t. + * + * @{ + */ + +/** + * Generic callback function for MIDI event handler. + * + * @param data User defined data pointer + * @param event The MIDI event + * @return Should return #FLUID_OK on success, #FLUID_FAILED otherwise + * + * This callback is used to pass MIDI events + * - from \ref midi_player, \ref midi_router or \ref midi_driver + * - to \ref midi_router via fluid_midi_router_handle_midi_event() + * - or to \ref synth via fluid_synth_handle_midi_event(). + * + * Additionally, there is a translation layer to pass MIDI events to + * a \ref sequencer via fluid_sequencer_add_midi_event_to_buffer(). + */ +typedef int (*handle_midi_event_func_t)(void *data, fluid_midi_event_t *event); + +/** + * Generic callback function fired once by MIDI tick change. + * + * @param data User defined data pointer + * @param tick The current (zero-based) tick, which triggered the callback + * @return Should return #FLUID_OK on success, #FLUID_FAILED otherwise + * + * This callback is fired at a constant rate depending on the current BPM and PPQ. + * e.g. for PPQ = 192 and BPM = 140 the callback is fired 192 * 140 times per minute (448/sec). + * + * It can be used to sync external elements with the beat, + * or stop / loop the song on a given tick. + * Ticks being BPM-dependent, you can manipulate values such as bars or beats, + * without having to care about BPM. + * + * For example, this callback loops the song whenever it reaches the 5th bar : + * + * @code{.cpp} +int handle_tick(void *data, int tick) +{ + fluid_player_t *player = (fluid_player_t *)data; + int ppq = 192; // From MIDI header + int beatsPerBar = 4; // From the song's time signature + int loopBar = 5; + int loopTick = (loopBar - 1) * ppq * beatsPerBar; + + if (tick == loopTick) + { + return fluid_player_seek(player, 0); + } + + return FLUID_OK; +} + * @endcode + */ +typedef int (*handle_midi_tick_func_t)(void *data, int tick); +/** @} */ + +/** + * @defgroup midi_events MIDI Events + * @ingroup midi_input + * + * Functions to create, modify, query and delete MIDI events. + * + * These functions are intended to be used in MIDI routers and other filtering + * and processing functions in the MIDI event path. If you want to simply + * send MIDI messages to the synthesizer, you can use the more convenient + * \ref midi_messages interface. + * + * @{ + */ +/** @startlifecycle{MIDI Event} */ +FLUIDSYNTH_API fluid_midi_event_t *new_fluid_midi_event(void); +FLUIDSYNTH_API void delete_fluid_midi_event(fluid_midi_event_t *event); +/** @endlifecycle */ + +FLUIDSYNTH_API int fluid_midi_event_set_type(fluid_midi_event_t *evt, int type); +FLUIDSYNTH_API int fluid_midi_event_get_type(const fluid_midi_event_t *evt); +FLUIDSYNTH_API int fluid_midi_event_set_channel(fluid_midi_event_t *evt, int chan); +FLUIDSYNTH_API int fluid_midi_event_get_channel(const fluid_midi_event_t *evt); +FLUIDSYNTH_API int fluid_midi_event_get_key(const fluid_midi_event_t *evt); +FLUIDSYNTH_API int fluid_midi_event_set_key(fluid_midi_event_t *evt, int key); +FLUIDSYNTH_API int fluid_midi_event_get_velocity(const fluid_midi_event_t *evt); +FLUIDSYNTH_API int fluid_midi_event_set_velocity(fluid_midi_event_t *evt, int vel); +FLUIDSYNTH_API int fluid_midi_event_get_control(const fluid_midi_event_t *evt); +FLUIDSYNTH_API int fluid_midi_event_set_control(fluid_midi_event_t *evt, int ctrl); +FLUIDSYNTH_API int fluid_midi_event_get_value(const fluid_midi_event_t *evt); +FLUIDSYNTH_API int fluid_midi_event_set_value(fluid_midi_event_t *evt, int val); +FLUIDSYNTH_API int fluid_midi_event_get_program(const fluid_midi_event_t *evt); +FLUIDSYNTH_API int fluid_midi_event_set_program(fluid_midi_event_t *evt, int val); +FLUIDSYNTH_API int fluid_midi_event_get_pitch(const fluid_midi_event_t *evt); +FLUIDSYNTH_API int fluid_midi_event_set_pitch(fluid_midi_event_t *evt, int val); +FLUIDSYNTH_API int fluid_midi_event_set_sysex(fluid_midi_event_t *evt, void *data, + int size, int dynamic); +FLUIDSYNTH_API int fluid_midi_event_set_text(fluid_midi_event_t *evt, + void *data, int size, int dynamic); +FLUIDSYNTH_API int fluid_midi_event_get_text(fluid_midi_event_t *evt, + void **data, int *size); +FLUIDSYNTH_API int fluid_midi_event_set_lyrics(fluid_midi_event_t *evt, + void *data, int size, int dynamic); +FLUIDSYNTH_API int fluid_midi_event_get_lyrics(fluid_midi_event_t *evt, + void **data, int *size); +/** @} */ + +/** + * @defgroup midi_router MIDI Router + * @ingroup midi_input + * + * Rule based transformation and filtering of MIDI events. + * + * @{ + */ + +/** + * MIDI router rule type. + * + * @since 1.1.0 + */ +typedef enum +{ + FLUID_MIDI_ROUTER_RULE_NOTE, /**< MIDI note rule */ + FLUID_MIDI_ROUTER_RULE_CC, /**< MIDI controller rule */ + FLUID_MIDI_ROUTER_RULE_PROG_CHANGE, /**< MIDI program change rule */ + FLUID_MIDI_ROUTER_RULE_PITCH_BEND, /**< MIDI pitch bend rule */ + FLUID_MIDI_ROUTER_RULE_CHANNEL_PRESSURE, /**< MIDI channel pressure rule */ + FLUID_MIDI_ROUTER_RULE_KEY_PRESSURE, /**< MIDI key pressure rule */ + FLUID_MIDI_ROUTER_RULE_COUNT /**< @internal Total count of rule types. This symbol + is not part of the public API and ABI stability + guarantee and may change at any time!*/ +} fluid_midi_router_rule_type; + + +/** @startlifecycle{MIDI Router} */ +FLUIDSYNTH_API fluid_midi_router_t *new_fluid_midi_router(fluid_settings_t *settings, + handle_midi_event_func_t handler, + void *event_handler_data); +FLUIDSYNTH_API void delete_fluid_midi_router(fluid_midi_router_t *handler); +/** @endlifecycle */ + +FLUIDSYNTH_API int fluid_midi_router_set_default_rules(fluid_midi_router_t *router); +FLUIDSYNTH_API int fluid_midi_router_clear_rules(fluid_midi_router_t *router); +FLUIDSYNTH_API int fluid_midi_router_add_rule(fluid_midi_router_t *router, + fluid_midi_router_rule_t *rule, int type); + + +/** @startlifecycle{MIDI Router Rule} */ +FLUIDSYNTH_API fluid_midi_router_rule_t *new_fluid_midi_router_rule(void); +FLUIDSYNTH_API void delete_fluid_midi_router_rule(fluid_midi_router_rule_t *rule); +/** @endlifecycle */ + +FLUIDSYNTH_API void fluid_midi_router_rule_set_chan(fluid_midi_router_rule_t *rule, + int min, int max, float mul, int add); +FLUIDSYNTH_API void fluid_midi_router_rule_set_param1(fluid_midi_router_rule_t *rule, + int min, int max, float mul, int add); +FLUIDSYNTH_API void fluid_midi_router_rule_set_param2(fluid_midi_router_rule_t *rule, + int min, int max, float mul, int add); +FLUIDSYNTH_API int fluid_midi_router_handle_midi_event(void *data, fluid_midi_event_t *event); +FLUIDSYNTH_API int fluid_midi_dump_prerouter(void *data, fluid_midi_event_t *event); +FLUIDSYNTH_API int fluid_midi_dump_postrouter(void *data, fluid_midi_event_t *event); +/** @} */ + +/** + * @defgroup midi_driver MIDI Driver + * @ingroup midi_input + * + * Functions for managing MIDI drivers. + * + * The available MIDI drivers depend on your platform. See \ref settings_midi for all + * available configuration options. + * + * To create a MIDI driver, you need to specify a source for the MIDI events to be + * forwarded to via the \ref fluid_midi_event_t callback. Normally this will be + * either a \ref midi_router via fluid_midi_router_handle_midi_event() or the synthesizer + * via fluid_synth_handle_midi_event(). + * + * But you can also write your own handler function that preprocesses the events and + * forwards them on to the router or synthesizer instead. + * + * @{ + */ + +/** @startlifecycle{MIDI Driver} */ +FLUIDSYNTH_API +fluid_midi_driver_t *new_fluid_midi_driver(fluid_settings_t *settings, + handle_midi_event_func_t handler, + void *event_handler_data); + +FLUIDSYNTH_API void delete_fluid_midi_driver(fluid_midi_driver_t *driver); +/** @endlifecycle */ + +/** @} */ + +/** + * @defgroup midi_player MIDI File Player + * @ingroup midi_input + * + * Parse standard MIDI files and emit MIDI events. + * + * @{ + */ + +/** + * MIDI File Player status enum. + * @since 1.1.0 + */ +enum fluid_player_status +{ + FLUID_PLAYER_READY, /**< Player is ready */ + FLUID_PLAYER_PLAYING, /**< Player is currently playing */ + FLUID_PLAYER_STOPPING, /**< Player is stopping, but hasn't finished yet (currently unused) */ + FLUID_PLAYER_DONE /**< Player is finished playing */ +}; + +/** + * MIDI File Player tempo enum. + * @since 2.2.0 + */ +enum fluid_player_set_tempo_type +{ + FLUID_PLAYER_TEMPO_INTERNAL, /**< Use midi file tempo set in midi file (120 bpm by default). Multiplied by a factor */ + FLUID_PLAYER_TEMPO_EXTERNAL_BPM, /**< Set player tempo in bpm, supersede midi file tempo */ + FLUID_PLAYER_TEMPO_EXTERNAL_MIDI, /**< Set player tempo in us per quarter note, supersede midi file tempo */ + FLUID_PLAYER_TEMPO_NBR /**< @internal Value defines the count of player tempo type (#fluid_player_set_tempo_type) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */ +}; + +/** @startlifecycle{MIDI File Player} */ +FLUIDSYNTH_API fluid_player_t *new_fluid_player(fluid_synth_t *synth); +FLUIDSYNTH_API void delete_fluid_player(fluid_player_t *player); +/** @endlifecycle */ + +FLUIDSYNTH_API int fluid_player_add(fluid_player_t *player, const char *midifile); +FLUIDSYNTH_API int fluid_player_add_mem(fluid_player_t *player, const void *buffer, size_t len); +FLUIDSYNTH_API int fluid_player_play(fluid_player_t *player); +FLUIDSYNTH_API int fluid_player_stop(fluid_player_t *player); +FLUIDSYNTH_API int fluid_player_join(fluid_player_t *player); +FLUIDSYNTH_API int fluid_player_set_loop(fluid_player_t *player, int loop); +FLUIDSYNTH_API int fluid_player_set_tempo(fluid_player_t *player, int tempo_type, double tempo); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_player_set_midi_tempo(fluid_player_t *player, int tempo); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_player_set_bpm(fluid_player_t *player, int bpm); +FLUIDSYNTH_API int fluid_player_set_playback_callback(fluid_player_t *player, handle_midi_event_func_t handler, void *handler_data); +FLUIDSYNTH_API int fluid_player_set_tick_callback(fluid_player_t *player, handle_midi_tick_func_t handler, void *handler_data); + +FLUIDSYNTH_API int fluid_player_get_status(fluid_player_t *player); +FLUIDSYNTH_API int fluid_player_get_current_tick(fluid_player_t *player); +FLUIDSYNTH_API int fluid_player_get_total_ticks(fluid_player_t *player); +FLUIDSYNTH_API int fluid_player_get_bpm(fluid_player_t *player); +FLUIDSYNTH_API int fluid_player_get_division(fluid_player_t *player); +FLUIDSYNTH_API int fluid_player_get_midi_tempo(fluid_player_t *player); +FLUIDSYNTH_API int fluid_player_seek(fluid_player_t *player, int ticks); +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FLUIDSYNTH_MIDI_H */ diff --git a/libs/fluidsynth/include/fluidsynth/misc.h b/libs/fluidsynth/include/fluidsynth/misc.h new file mode 100644 index 00000000000..f60bf61e014 --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth/misc.h @@ -0,0 +1,77 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_MISC_H +#define _FLUIDSYNTH_MISC_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @defgroup misc Miscellaneous + * + * Miscellaneous utility functions and defines + * + * @{ + */ + +/** + * Value that indicates success, used by most libfluidsynth functions. + * + * @note This was not publicly defined prior to libfluidsynth 1.1.0. When + * writing code which should also be compatible with older versions, something + * like the following can be used: + * + * @code + * #include + * + * #ifndef FLUID_OK + * #define FLUID_OK (0) + * #define FLUID_FAILED (-1) + * #endif + * @endcode + * + * @since 1.1.0 + */ +#define FLUID_OK (0) + +/** + * Value that indicates failure, used by most libfluidsynth functions. + * + * @note See #FLUID_OK for more details. + * + * @since 1.1.0 + */ +#define FLUID_FAILED (-1) + + +FLUIDSYNTH_API int fluid_is_soundfont(const char *filename); +FLUIDSYNTH_API int fluid_is_midifile(const char *filename); +FLUIDSYNTH_API void fluid_free(void* ptr); +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FLUIDSYNTH_MISC_H */ diff --git a/libs/fluidsynth/include/fluidsynth/mod.h b/libs/fluidsynth/include/fluidsynth/mod.h new file mode 100644 index 00000000000..55f23579b97 --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth/mod.h @@ -0,0 +1,104 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_MOD_H +#define _FLUIDSYNTH_MOD_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup modulators SoundFont Modulators + * @ingroup soundfonts + * + * SoundFont modulator functions and constants. + * + * @{ + */ + +/** + * Flags defining the polarity, mapping function and type of a modulator source. + * Compare with SoundFont 2.04 PDF section 8.2. + * + * Note: Bit values do not correspond to the SoundFont spec! Also note that + * #FLUID_MOD_GC and #FLUID_MOD_CC are in the flags field instead of the source field. + */ +enum fluid_mod_flags +{ + FLUID_MOD_POSITIVE = 0, /**< Mapping function is positive */ + FLUID_MOD_NEGATIVE = 1, /**< Mapping function is negative */ + FLUID_MOD_UNIPOLAR = 0, /**< Mapping function is unipolar */ + FLUID_MOD_BIPOLAR = 2, /**< Mapping function is bipolar */ + FLUID_MOD_LINEAR = 0, /**< Linear mapping function */ + FLUID_MOD_CONCAVE = 4, /**< Concave mapping function */ + FLUID_MOD_CONVEX = 8, /**< Convex mapping function */ + FLUID_MOD_SWITCH = 12, /**< Switch (on/off) mapping function */ + FLUID_MOD_GC = 0, /**< General controller source type (#fluid_mod_src) */ + FLUID_MOD_CC = 16, /**< MIDI CC controller (source will be a MIDI CC number) */ + + FLUID_MOD_SIN = 0x80, /**< Custom non-standard sinus mapping function */ +}; + +/** + * General controller (if #FLUID_MOD_GC in flags). This + * corresponds to SoundFont 2.04 PDF section 8.2.1 + */ +enum fluid_mod_src +{ + FLUID_MOD_NONE = 0, /**< No source controller */ + FLUID_MOD_VELOCITY = 2, /**< MIDI note-on velocity */ + FLUID_MOD_KEY = 3, /**< MIDI note-on note number */ + FLUID_MOD_KEYPRESSURE = 10, /**< MIDI key pressure */ + FLUID_MOD_CHANNELPRESSURE = 13, /**< MIDI channel pressure */ + FLUID_MOD_PITCHWHEEL = 14, /**< Pitch wheel */ + FLUID_MOD_PITCHWHEELSENS = 16 /**< Pitch wheel sensitivity */ +}; + +/** @startlifecycle{Modulator} */ +FLUIDSYNTH_API fluid_mod_t *new_fluid_mod(void); +FLUIDSYNTH_API void delete_fluid_mod(fluid_mod_t *mod); +/** @endlifecycle */ + +FLUIDSYNTH_API size_t fluid_mod_sizeof(void); + +FLUIDSYNTH_API void fluid_mod_set_source1(fluid_mod_t *mod, int src, int flags); +FLUIDSYNTH_API void fluid_mod_set_source2(fluid_mod_t *mod, int src, int flags); +FLUIDSYNTH_API void fluid_mod_set_dest(fluid_mod_t *mod, int dst); +FLUIDSYNTH_API void fluid_mod_set_amount(fluid_mod_t *mod, double amount); + +FLUIDSYNTH_API int fluid_mod_get_source1(const fluid_mod_t *mod); +FLUIDSYNTH_API int fluid_mod_get_flags1(const fluid_mod_t *mod); +FLUIDSYNTH_API int fluid_mod_get_source2(const fluid_mod_t *mod); +FLUIDSYNTH_API int fluid_mod_get_flags2(const fluid_mod_t *mod); +FLUIDSYNTH_API int fluid_mod_get_dest(const fluid_mod_t *mod); +FLUIDSYNTH_API double fluid_mod_get_amount(const fluid_mod_t *mod); + +FLUIDSYNTH_API int fluid_mod_test_identity(const fluid_mod_t *mod1, const fluid_mod_t *mod2); +FLUIDSYNTH_API int fluid_mod_has_source(const fluid_mod_t *mod, int cc, int ctrl); +FLUIDSYNTH_API int fluid_mod_has_dest(const fluid_mod_t *mod, int gen); + +FLUIDSYNTH_API void fluid_mod_clone(fluid_mod_t *mod, const fluid_mod_t *src); +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif /* _FLUIDSYNTH_MOD_H */ diff --git a/libs/fluidsynth/include/fluidsynth/seq.h b/libs/fluidsynth/include/fluidsynth/seq.h new file mode 100644 index 00000000000..cdcc959010f --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth/seq.h @@ -0,0 +1,92 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_SEQ_H +#define _FLUIDSYNTH_SEQ_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup sequencer MIDI Sequencer + * + * MIDI event sequencer. + * + * The MIDI sequencer can be used to play MIDI events in a more flexible way than + * using the MIDI file player, which expects the events to be stored as + * Standard MIDI Files. Using the sequencer, you can provide the events one by + * one, with an optional timestamp for scheduling. + * + * @{ + */ + +/** + * Event callback prototype for destination clients. + * + * @param time Current sequencer tick value (see fluid_sequencer_get_tick()). + * @param event The event being received + * @param seq The sequencer instance + * @param data User defined data registered with the client + * + * @note @p time may not be of the same tick value as the scheduled event! In fact, depending on + * the sequencer's scale and the synth's sample-rate, @p time may be a few ticks too late. Although this + * itself is inaudible, it is important to consider, + * when you use this callback for enqueuing additional events over and over again with + * fluid_sequencer_send_at(): If you enqueue new events with a relative tick value you might introduce + * a timing error, which causes your sequence to sound e.g. slower than it's supposed to be. If this is + * your use-case, make sure to enqueue events with an absolute tick value. + */ +typedef void (*fluid_event_callback_t)(unsigned int time, fluid_event_t *event, + fluid_sequencer_t *seq, void *data); + + +/** @startlifecycle{MIDI Sequencer} */ +FLUID_DEPRECATED FLUIDSYNTH_API fluid_sequencer_t *new_fluid_sequencer(void); +FLUIDSYNTH_API fluid_sequencer_t *new_fluid_sequencer2(int use_system_timer); +FLUIDSYNTH_API void delete_fluid_sequencer(fluid_sequencer_t *seq); +/** @endlifecycle */ + +FLUIDSYNTH_API int fluid_sequencer_get_use_system_timer(fluid_sequencer_t *seq); +FLUIDSYNTH_API +fluid_seq_id_t fluid_sequencer_register_client(fluid_sequencer_t *seq, const char *name, + fluid_event_callback_t callback, void *data); +FLUIDSYNTH_API void fluid_sequencer_unregister_client(fluid_sequencer_t *seq, fluid_seq_id_t id); +FLUIDSYNTH_API int fluid_sequencer_count_clients(fluid_sequencer_t *seq); +FLUIDSYNTH_API fluid_seq_id_t fluid_sequencer_get_client_id(fluid_sequencer_t *seq, int index); +FLUIDSYNTH_API char *fluid_sequencer_get_client_name(fluid_sequencer_t *seq, fluid_seq_id_t id); +FLUIDSYNTH_API int fluid_sequencer_client_is_dest(fluid_sequencer_t *seq, fluid_seq_id_t id); +FLUIDSYNTH_API void fluid_sequencer_process(fluid_sequencer_t *seq, unsigned int msec); +FLUIDSYNTH_API void fluid_sequencer_send_now(fluid_sequencer_t *seq, fluid_event_t *evt); +FLUIDSYNTH_API +int fluid_sequencer_send_at(fluid_sequencer_t *seq, fluid_event_t *evt, + unsigned int time, int absolute); +FLUIDSYNTH_API +void fluid_sequencer_remove_events(fluid_sequencer_t *seq, fluid_seq_id_t source, fluid_seq_id_t dest, int type); +FLUIDSYNTH_API unsigned int fluid_sequencer_get_tick(fluid_sequencer_t *seq); +FLUIDSYNTH_API void fluid_sequencer_set_time_scale(fluid_sequencer_t *seq, double scale); +FLUIDSYNTH_API double fluid_sequencer_get_time_scale(fluid_sequencer_t *seq); +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FLUIDSYNTH_SEQ_H */ diff --git a/libs/fluidsynth/include/fluidsynth/seqbind.h b/libs/fluidsynth/include/fluidsynth/seqbind.h new file mode 100644 index 00000000000..876a2b419b0 --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth/seqbind.h @@ -0,0 +1,44 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_SEQBIND_H +#define _FLUIDSYNTH_SEQBIND_H + +#include "seq.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup sequencer + * + * @{ + */ +FLUIDSYNTH_API +fluid_seq_id_t fluid_sequencer_register_fluidsynth(fluid_sequencer_t *seq, fluid_synth_t *synth); +FLUIDSYNTH_API +int fluid_sequencer_add_midi_event_to_buffer(void *data, fluid_midi_event_t *event); +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif /* _FLUIDSYNTH_SEQBIND_H */ diff --git a/libs/fluidsynth/include/fluidsynth/settings.h b/libs/fluidsynth/include/fluidsynth/settings.h new file mode 100644 index 00000000000..78db7dc32b9 --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth/settings.h @@ -0,0 +1,194 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_SETTINGS_H +#define _FLUIDSYNTH_SETTINGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup settings Settings + * + * Functions for settings management + * + * To create a synthesizer object you will have to specify its + * settings. These settings are stored in a fluid_settings_t object. + * @code + * void + * my_synthesizer () + * { + * fluid_settings_t *settings; + * fluid_synth_t *synth; + * fluid_audio_driver_t *adriver; + * + * settings = new_fluid_settings (); + * fluid_settings_setstr(settings, "audio.driver", "alsa"); + * // ... change settings ... + * synth = new_fluid_synth (settings); + * adriver = new_fluid_audio_driver (settings, synth); + * // ... + * } + * @endcode + * @sa @ref CreatingSettings + * + * @{ + */ + +/** + * Hint FLUID_HINT_BOUNDED_BELOW indicates that the LowerBound field + * of the FLUID_PortRangeHint should be considered meaningful. The + * value in this field should be considered the (inclusive) lower + * bound of the valid range. If FLUID_HINT_SAMPLE_RATE is also + * specified then the value of LowerBound should be multiplied by the + * sample rate. + */ +#define FLUID_HINT_BOUNDED_BELOW 0x1 + +/** Hint FLUID_HINT_BOUNDED_ABOVE indicates that the UpperBound field + of the FLUID_PortRangeHint should be considered meaningful. The + value in this field should be considered the (inclusive) upper + bound of the valid range. If FLUID_HINT_SAMPLE_RATE is also + specified then the value of UpperBound should be multiplied by the + sample rate. */ +#define FLUID_HINT_BOUNDED_ABOVE 0x2 + +/** + * Hint FLUID_HINT_TOGGLED indicates that the data item should be + * considered a Boolean toggle. Data less than or equal to zero should + * be considered `off' or `false,' and data above zero should be + * considered `on' or `true.' FLUID_HINT_TOGGLED may not be used in + * conjunction with any other hint. + */ +#define FLUID_HINT_TOGGLED 0x4 + +#define FLUID_HINT_OPTIONLIST 0x02 /**< Setting is a list of string options */ + + +/** + * Settings type + * + * Each setting has a defined type: numeric (double), integer, string or a + * set of values. The type of each setting can be retrieved using the + * function fluid_settings_get_type() + */ +enum fluid_types_enum +{ + FLUID_NO_TYPE = -1, /**< Undefined type */ + FLUID_NUM_TYPE, /**< Numeric (double) */ + FLUID_INT_TYPE, /**< Integer */ + FLUID_STR_TYPE, /**< String */ + FLUID_SET_TYPE /**< Set of values */ +}; + +/** @startlifecycle{Settings} */ +FLUIDSYNTH_API fluid_settings_t *new_fluid_settings(void); +FLUIDSYNTH_API void delete_fluid_settings(fluid_settings_t *settings); +/** @endlifecycle */ + +FLUIDSYNTH_API +int fluid_settings_get_type(fluid_settings_t *settings, const char *name); + +FLUIDSYNTH_API +int fluid_settings_get_hints(fluid_settings_t *settings, const char *name, int *val); + +FLUIDSYNTH_API +int fluid_settings_is_realtime(fluid_settings_t *settings, const char *name); + +FLUIDSYNTH_API +int fluid_settings_setstr(fluid_settings_t *settings, const char *name, const char *str); + +FLUIDSYNTH_API +int fluid_settings_copystr(fluid_settings_t *settings, const char *name, char *str, int len); + +FLUIDSYNTH_API +int fluid_settings_dupstr(fluid_settings_t *settings, const char *name, char **str); + +FLUIDSYNTH_API +int fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char **def); + +FLUIDSYNTH_API +int fluid_settings_str_equal(fluid_settings_t *settings, const char *name, const char *value); + +FLUIDSYNTH_API +int fluid_settings_setnum(fluid_settings_t *settings, const char *name, double val); + +FLUIDSYNTH_API +int fluid_settings_getnum(fluid_settings_t *settings, const char *name, double *val); + +FLUIDSYNTH_API +int fluid_settings_getnum_default(fluid_settings_t *settings, const char *name, double *val); + +FLUIDSYNTH_API +int fluid_settings_getnum_range(fluid_settings_t *settings, const char *name, + double *min, double *max); + +FLUIDSYNTH_API +int fluid_settings_setint(fluid_settings_t *settings, const char *name, int val); + +FLUIDSYNTH_API +int fluid_settings_getint(fluid_settings_t *settings, const char *name, int *val); + +FLUIDSYNTH_API +int fluid_settings_getint_default(fluid_settings_t *settings, const char *name, int *val); + +FLUIDSYNTH_API +int fluid_settings_getint_range(fluid_settings_t *settings, const char *name, + int *min, int *max); + +/** + * Callback function type used with fluid_settings_foreach_option() + * + * @param data User defined data pointer + * @param name Setting name + * @param option A string option for this setting (iterates through the list) + */ +typedef void (*fluid_settings_foreach_option_t)(void *data, const char *name, const char *option); + +FLUIDSYNTH_API +void fluid_settings_foreach_option(fluid_settings_t *settings, + const char *name, void *data, + fluid_settings_foreach_option_t func); +FLUIDSYNTH_API +int fluid_settings_option_count(fluid_settings_t *settings, const char *name); +FLUIDSYNTH_API char *fluid_settings_option_concat(fluid_settings_t *settings, + const char *name, + const char *separator); + +/** + * Callback function type used with fluid_settings_foreach() + * + * @param data User defined data pointer + * @param name Setting name + * @param type Setting type (#fluid_types_enum) + */ +typedef void (*fluid_settings_foreach_t)(void *data, const char *name, int type); + +FLUIDSYNTH_API +void fluid_settings_foreach(fluid_settings_t *settings, void *data, + fluid_settings_foreach_t func); +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FLUIDSYNTH_SETTINGS_H */ diff --git a/libs/fluidsynth/include/fluidsynth/sfont.h b/libs/fluidsynth/include/fluidsynth/sfont.h new file mode 100644 index 00000000000..6d0fd4c7a3e --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth/sfont.h @@ -0,0 +1,362 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_SFONT_H +#define _FLUIDSYNTH_SFONT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup soundfonts SoundFonts + * + * SoundFont related functions + * + * This part of the API contains functions, defines and types that are mostly + * only used by internal or custom SoundFont loaders or client code that + * modifies loaded presets, SoundFonts or voices directly. + */ + +/** + * @defgroup soundfont_loader SoundFont Loader + * @ingroup soundfonts + * + * Create custom SoundFont loaders + * + * It is possible to add new SoundFont loaders to the + * synthesizer. This API allows for virtual SoundFont files to be loaded + * and synthesized, which may not actually be SoundFont files, as long as they + * can be represented by the SoundFont synthesis model. + * + * To add a new SoundFont loader to the synthesizer, call + * fluid_synth_add_sfloader() and pass a pointer to an + * #fluid_sfloader_t instance created by new_fluid_sfloader(). + * On creation, you must specify a callback function \p load + * that will be called for every file attempting to load it and + * if successful returns a #fluid_sfont_t instance, or NULL if it fails. + * + * The #fluid_sfont_t structure contains a callback to obtain the + * name of the SoundFont. It contains two functions to iterate + * though the contained presets, and one function to obtain a + * preset corresponding to a bank and preset number. This + * function should return a #fluid_preset_t instance. + * + * The #fluid_preset_t instance contains some functions to obtain + * information from the preset (name, bank, number). The most + * important callback is the noteon function. The noteon function + * is called by fluidsynth internally and + * should call fluid_synth_alloc_voice() for every sample that has + * to be played. fluid_synth_alloc_voice() expects a pointer to a + * #fluid_sample_t instance and returns a pointer to the opaque + * #fluid_voice_t structure. To set or increment the values of a + * generator, use fluid_voice_gen_set() or fluid_voice_gen_incr(). When you are + * finished initializing the voice call fluid_voice_start() to + * start playing the synthesis voice. + * + * @{ + */ + +/** + * Some notification enums for presets and samples. + */ +enum +{ + FLUID_PRESET_SELECTED, /**< Preset selected notify */ + FLUID_PRESET_UNSELECTED, /**< Preset unselected notify */ + FLUID_SAMPLE_DONE, /**< Sample no longer needed notify */ + FLUID_PRESET_PIN, /**< Request to pin preset samples to cache */ + FLUID_PRESET_UNPIN /**< Request to unpin preset samples from cache */ +}; + +/** + * Indicates the type of a sample used by the _fluid_sample_t::sampletype field. + * + * This enum corresponds to the \c SFSampleLink enum in the SoundFont spec. + * One \c flag may be bit-wise OR-ed with one \c value. + */ +enum fluid_sample_type +{ + FLUID_SAMPLETYPE_MONO = 0x1, /**< Value used for mono samples */ + FLUID_SAMPLETYPE_RIGHT = 0x2, /**< Value used for right samples of a stereo pair */ + FLUID_SAMPLETYPE_LEFT = 0x4, /**< Value used for left samples of a stereo pair */ + FLUID_SAMPLETYPE_LINKED = 0x8, /**< Value used for linked sample, which is currently not supported */ + FLUID_SAMPLETYPE_OGG_VORBIS = 0x10, /**< Flag used for Ogg Vorbis compressed samples (non-standard compliant extension) as found in the program "sftools" developed by Werner Schweer from MuseScore @since 1.1.7 */ + FLUID_SAMPLETYPE_ROM = 0x8000 /**< Flag that indicates ROM samples, causing the sample to be ignored */ +}; + + +/** + * Method to load an instrument file (does not actually need to be a real file name, + * could be another type of string identifier that the \a loader understands). + * + * @param loader SoundFont loader + * @param filename File name or other string identifier + * @return The loaded instrument file (SoundFont) or NULL if an error occurred. + */ +typedef fluid_sfont_t *(*fluid_sfloader_load_t)(fluid_sfloader_t *loader, const char *filename); + +/** + * The free method should free the memory allocated for a fluid_sfloader_t instance in + * addition to any private data. + * + * @param loader SoundFont loader + * + * Any custom user provided cleanup function must ultimately call + * delete_fluid_sfloader() to ensure proper cleanup of the #fluid_sfloader_t struct. If no private data + * needs to be freed, setting this to delete_fluid_sfloader() is sufficient. + * + */ +typedef void (*fluid_sfloader_free_t)(fluid_sfloader_t *loader); + + +/** @startlifecycle{SoundFont Loader} */ +FLUIDSYNTH_API fluid_sfloader_t *new_fluid_sfloader(fluid_sfloader_load_t load, fluid_sfloader_free_t free); +FLUIDSYNTH_API void delete_fluid_sfloader(fluid_sfloader_t *loader); + +FLUIDSYNTH_API fluid_sfloader_t *new_fluid_defsfloader(fluid_settings_t *settings); +/** @endlifecycle */ + +/** + * Opens the file or memory indicated by \c filename in binary read mode. + * + * @return returns a file handle on success, NULL otherwise + * + * \c filename matches the string provided during the fluid_synth_sfload() call. + */ +typedef void *(* fluid_sfloader_callback_open_t)(const char *filename); + +/** + * Reads \c count bytes to the specified buffer \c buf. + * + * @return returns #FLUID_OK if exactly \c count bytes were successfully read, else returns #FLUID_FAILED and leaves \a buf unmodified. + */ +typedef int (* fluid_sfloader_callback_read_t)(void *buf, fluid_long_long_t count, void *handle); + +/** + * Same purpose and behaviour as fseek. + * + * @param origin either \c SEEK_SET, \c SEEK_CUR or \c SEEK_END + * @return returns #FLUID_OK if the seek was successfully performed while not seeking beyond a buffer or file, #FLUID_FAILED otherwise + */ +typedef int (* fluid_sfloader_callback_seek_t)(void *handle, fluid_long_long_t offset, int origin); + +/** + * Closes the handle returned by #fluid_sfloader_callback_open_t and frees used resources. + * + * @return returns #FLUID_OK on success, #FLUID_FAILED on error + */ +typedef int (* fluid_sfloader_callback_close_t)(void *handle); + +/** @return returns current file offset or #FLUID_FAILED on error */ +typedef fluid_long_long_t (* fluid_sfloader_callback_tell_t)(void *handle); + + +FLUIDSYNTH_API int fluid_sfloader_set_callbacks(fluid_sfloader_t *loader, + fluid_sfloader_callback_open_t open, + fluid_sfloader_callback_read_t read, + fluid_sfloader_callback_seek_t seek, + fluid_sfloader_callback_tell_t tell, + fluid_sfloader_callback_close_t close); + +FLUIDSYNTH_API int fluid_sfloader_set_data(fluid_sfloader_t *loader, void *data); +FLUIDSYNTH_API void *fluid_sfloader_get_data(fluid_sfloader_t *loader); + + + +/** + * Method to return the name of a virtual SoundFont. + * + * @param sfont Virtual SoundFont + * @return The name of the virtual SoundFont. + */ +typedef const char *(*fluid_sfont_get_name_t)(fluid_sfont_t *sfont); + +/** + * Get a virtual SoundFont preset by bank and program numbers. + * + * @param sfont Virtual SoundFont + * @param bank MIDI bank number (0-16383) + * @param prenum MIDI preset number (0-127) + * @return Should return an allocated virtual preset or NULL if it could not + * be found. + */ +typedef fluid_preset_t *(*fluid_sfont_get_preset_t)(fluid_sfont_t *sfont, int bank, int prenum); + +/** + * Start virtual SoundFont preset iteration method. + * + * @param sfont Virtual SoundFont + * + * Starts/re-starts virtual preset iteration in a SoundFont. + */ +typedef void (*fluid_sfont_iteration_start_t)(fluid_sfont_t *sfont); + +/** + * Virtual SoundFont preset iteration function. + * + * @param sfont Virtual SoundFont + * @return NULL when no more presets are available, otherwise the a pointer to the current preset + * + * Returns preset information to the caller. The returned buffer is only valid until a subsequent + * call to this function. + */ +typedef fluid_preset_t *(*fluid_sfont_iteration_next_t)(fluid_sfont_t *sfont); + +/** + * Method to free a virtual SoundFont bank. + * + * @param sfont Virtual SoundFont to free. + * @return Should return 0 when it was able to free all resources or non-zero + * if some of the samples could not be freed because they are still in use, + * in which case the free will be tried again later, until success. + * + * Any custom user provided cleanup function must ultimately call + * delete_fluid_sfont() to ensure proper cleanup of the #fluid_sfont_t struct. If no private data + * needs to be freed, setting this to delete_fluid_sfont() is sufficient. + */ +typedef int (*fluid_sfont_free_t)(fluid_sfont_t *sfont); + + +/** @startlifecycle{SoundFont} */ +FLUIDSYNTH_API fluid_sfont_t *new_fluid_sfont(fluid_sfont_get_name_t get_name, + fluid_sfont_get_preset_t get_preset, + fluid_sfont_iteration_start_t iter_start, + fluid_sfont_iteration_next_t iter_next, + fluid_sfont_free_t free); + +FLUIDSYNTH_API int delete_fluid_sfont(fluid_sfont_t *sfont); +/** @endlifecycle */ + +FLUIDSYNTH_API int fluid_sfont_set_data(fluid_sfont_t *sfont, void *data); +FLUIDSYNTH_API void *fluid_sfont_get_data(fluid_sfont_t *sfont); + +FLUIDSYNTH_API int fluid_sfont_get_id(fluid_sfont_t *sfont); +FLUIDSYNTH_API const char *fluid_sfont_get_name(fluid_sfont_t *sfont); +FLUIDSYNTH_API fluid_preset_t *fluid_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum); +FLUIDSYNTH_API void fluid_sfont_iteration_start(fluid_sfont_t *sfont); +FLUIDSYNTH_API fluid_preset_t *fluid_sfont_iteration_next(fluid_sfont_t *sfont); + +/** + * Method to get a virtual SoundFont preset name. + * + * @param preset Virtual SoundFont preset + * @return Should return the name of the preset. The returned string must be + * valid for the duration of the virtual preset (or the duration of the + * SoundFont, in the case of preset iteration). + */ +typedef const char *(*fluid_preset_get_name_t)(fluid_preset_t *preset); + +/** + * Method to get a virtual SoundFont preset MIDI bank number. + * + * @param preset Virtual SoundFont preset + * @param return The bank number of the preset + */ +typedef int (*fluid_preset_get_banknum_t)(fluid_preset_t *preset); + +/** + * Method to get a virtual SoundFont preset MIDI program number. + * + * @param preset Virtual SoundFont preset + * @param return The program number of the preset + */ +typedef int (*fluid_preset_get_num_t)(fluid_preset_t *preset); + +/** + * Method to handle a noteon event (synthesize the instrument). + * + * @param preset Virtual SoundFont preset + * @param synth Synthesizer instance + * @param chan MIDI channel number of the note on event + * @param key MIDI note number (0-127) + * @param vel MIDI velocity (0-127) + * @return #FLUID_OK on success (0) or #FLUID_FAILED (-1) otherwise + * + * This method may be called from within synthesis context and therefore + * should be as efficient as possible and not perform any operations considered + * bad for realtime audio output (memory allocations and other OS calls). + * + * Call fluid_synth_alloc_voice() for every sample that has + * to be played. fluid_synth_alloc_voice() expects a pointer to a + * #fluid_sample_t structure and returns a pointer to the opaque + * #fluid_voice_t structure. To set or increment the values of a + * generator, use fluid_voice_gen_set() or fluid_voice_gen_incr(). When you are + * finished initializing the voice call fluid_voice_start() to + * start playing the synthesis voice. Starting with FluidSynth 1.1.0 all voices + * created will be started at the same time. + */ +typedef int (*fluid_preset_noteon_t)(fluid_preset_t *preset, fluid_synth_t *synth, int chan, int key, int vel); + +/** + * Method to free a virtual SoundFont preset. + * + * @param preset Virtual SoundFont preset + * @return Should return 0 + * + * Any custom user provided cleanup function must ultimately call + * delete_fluid_preset() to ensure proper cleanup of the #fluid_preset_t struct. If no private data + * needs to be freed, setting this to delete_fluid_preset() is sufficient. + */ +typedef void (*fluid_preset_free_t)(fluid_preset_t *preset); + +/** @startlifecycle{Preset} */ +FLUIDSYNTH_API fluid_preset_t *new_fluid_preset(fluid_sfont_t *parent_sfont, + fluid_preset_get_name_t get_name, + fluid_preset_get_banknum_t get_bank, + fluid_preset_get_num_t get_num, + fluid_preset_noteon_t noteon, + fluid_preset_free_t free); +FLUIDSYNTH_API void delete_fluid_preset(fluid_preset_t *preset); +/** @endlifecycle */ + +FLUIDSYNTH_API int fluid_preset_set_data(fluid_preset_t *preset, void *data); +FLUIDSYNTH_API void *fluid_preset_get_data(fluid_preset_t *preset); + +FLUIDSYNTH_API const char *fluid_preset_get_name(fluid_preset_t *preset); +FLUIDSYNTH_API int fluid_preset_get_banknum(fluid_preset_t *preset); +FLUIDSYNTH_API int fluid_preset_get_num(fluid_preset_t *preset); +FLUIDSYNTH_API fluid_sfont_t *fluid_preset_get_sfont(fluid_preset_t *preset); + +/** @startlifecycle{Sample} */ +FLUIDSYNTH_API fluid_sample_t *new_fluid_sample(void); +FLUIDSYNTH_API void delete_fluid_sample(fluid_sample_t *sample); +/** @endlifecycle */ + +FLUIDSYNTH_API size_t fluid_sample_sizeof(void); + +FLUIDSYNTH_API int fluid_sample_set_name(fluid_sample_t *sample, const char *name); +FLUIDSYNTH_API int fluid_sample_set_sound_data(fluid_sample_t *sample, + short *data, + char *data24, + unsigned int nbframes, + unsigned int sample_rate, + short copy_data); + +FLUIDSYNTH_API int fluid_sample_set_loop(fluid_sample_t *sample, unsigned int loop_start, unsigned int loop_end); +FLUIDSYNTH_API int fluid_sample_set_pitch(fluid_sample_t *sample, int root_key, int fine_tune); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FLUIDSYNTH_SFONT_H */ diff --git a/libs/fluidsynth/include/fluidsynth/shell.h b/libs/fluidsynth/include/fluidsynth/shell.h new file mode 100644 index 00000000000..5eed0878a5c --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth/shell.h @@ -0,0 +1,150 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_SHELL_H +#define _FLUIDSYNTH_SHELL_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @defgroup command_interface Command Interface + * + * Control and configuration interface + * + * The command interface allows you to send textual commands to + * the synthesizer, to parse a command file, or to read commands + * from the stdin or other input streams (like a TCP socket). + * + * For a full list of available commands, type \c help in the + * \ref command_shell or send the same command via a command handler. + * Further documentation can be found at + * https://github.com/FluidSynth/fluidsynth/wiki/UserManual#shell-commands + * + * @{ + */ +FLUIDSYNTH_API fluid_istream_t fluid_get_stdin(void); +FLUIDSYNTH_API fluid_ostream_t fluid_get_stdout(void); +FLUIDSYNTH_API char *fluid_get_userconf(char *buf, int len); +FLUIDSYNTH_API char *fluid_get_sysconf(char *buf, int len); +/** @} */ + + +/** + * @defgroup command_handler Command Handler + * @ingroup command_interface + * @brief Handles text commands and reading of configuration files + * + * @{ + */ + +/** @startlifecycle{Command Handler} */ +FLUIDSYNTH_API +fluid_cmd_handler_t *new_fluid_cmd_handler(fluid_synth_t *synth, fluid_midi_router_t *router); + +FLUIDSYNTH_API +fluid_cmd_handler_t *new_fluid_cmd_handler2(fluid_settings_t *settings, fluid_synth_t *synth, + fluid_midi_router_t *router, fluid_player_t *player); + +FLUIDSYNTH_API +void delete_fluid_cmd_handler(fluid_cmd_handler_t *handler); +/** @endlifecycle */ + +FLUIDSYNTH_API +void fluid_cmd_handler_set_synth(fluid_cmd_handler_t *handler, fluid_synth_t *synth); + +FLUIDSYNTH_API +int fluid_command(fluid_cmd_handler_t *handler, const char *cmd, fluid_ostream_t out); + +FLUIDSYNTH_API +int fluid_source(fluid_cmd_handler_t *handler, const char *filename); +/** @} */ + + +/** + * @defgroup command_shell Command Shell + * @ingroup command_interface + * + * Interactive shell to control and configure a synthesizer instance. + * + * If you need a platform independent way to get the standard input + * and output streams, use fluid_get_stdin() and fluid_get_stdout(). + * + * For a full list of available commands, type \c help in the shell. + * + * @{ + */ + +/** @startlifecycle{Command Shell} */ +FLUIDSYNTH_API +fluid_shell_t *new_fluid_shell(fluid_settings_t *settings, fluid_cmd_handler_t *handler, + fluid_istream_t in, fluid_ostream_t out, int thread); + +FLUIDSYNTH_API +void fluid_usershell(fluid_settings_t *settings, fluid_cmd_handler_t *handler); + +FLUIDSYNTH_API void delete_fluid_shell(fluid_shell_t *shell); +/** @endlifecycle */ + +/** @} */ + + +/** + * @defgroup command_server Command Server + * @ingroup command_interface + * + * TCP socket server for a command handler. + * + * The socket server will open the TCP port set by \ref settings_shell_port + * (default 9800) and starts a new thread and \ref command_handler for each + * incoming connection. + * + * @note The server is only available if libfluidsynth has been compiled + * with network support (enable-network). Without network support, all related + * functions will return FLUID_FAILED or NULL. + * + * @{ + */ + +/** @startlifecycle{Command Server} */ +FLUIDSYNTH_API +fluid_server_t *new_fluid_server(fluid_settings_t *settings, + fluid_synth_t *synth, fluid_midi_router_t *router); + +FLUIDSYNTH_API +fluid_server_t *new_fluid_server2(fluid_settings_t *settings, + fluid_synth_t *synth, fluid_midi_router_t *router, + fluid_player_t *player); + +FLUIDSYNTH_API void delete_fluid_server(fluid_server_t *server); + +FLUIDSYNTH_API int fluid_server_join(fluid_server_t *server); +/** @endlifecycle */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FLUIDSYNTH_SHELL_H */ diff --git a/libs/fluidsynth/include/fluidsynth/synth.h b/libs/fluidsynth/include/fluidsynth/synth.h new file mode 100644 index 00000000000..84861ebd648 --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth/synth.h @@ -0,0 +1,552 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_SYNTH_H +#define _FLUIDSYNTH_SYNTH_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @defgroup synth Synthesizer + * + * SoundFont synthesizer + * + * You create a new synthesizer with new_fluid_synth() and you destroy + * it with delete_fluid_synth(). Use the fluid_settings_t structure to specify + * the synthesizer characteristics. + * + * You have to load a SoundFont in order to hear any sound. For that + * you use the fluid_synth_sfload() function. + * + * You can use the audio driver functions to open + * the audio device and create a background audio thread. + * + * The API for sending MIDI events is probably what you expect: + * fluid_synth_noteon(), fluid_synth_noteoff(), ... + * + * @{ + */ + +/** @startlifecycle{Synthesizer} */ +FLUIDSYNTH_API fluid_synth_t *new_fluid_synth(fluid_settings_t *settings); +FLUIDSYNTH_API void delete_fluid_synth(fluid_synth_t *synth); +/** @endlifecycle */ + +FLUIDSYNTH_API double fluid_synth_get_cpu_load(fluid_synth_t *synth); +FLUID_DEPRECATED FLUIDSYNTH_API const char *fluid_synth_error(fluid_synth_t *synth); +/** @} */ + +/** + * @defgroup midi_messages MIDI Channel Messages + * @ingroup synth + * + * The MIDI channel message functions are mostly directly named after their + * counterpart MIDI messages. They are a high-level interface to controlling + * the synthesizer, playing notes and changing note and channel parameters. + * + * @{ + */ +FLUIDSYNTH_API int fluid_synth_noteon(fluid_synth_t *synth, int chan, int key, int vel); +FLUIDSYNTH_API int fluid_synth_noteoff(fluid_synth_t *synth, int chan, int key); +FLUIDSYNTH_API int fluid_synth_cc(fluid_synth_t *synth, int chan, int ctrl, int val); +FLUIDSYNTH_API int fluid_synth_get_cc(fluid_synth_t *synth, int chan, int ctrl, int *pval); +FLUIDSYNTH_API int fluid_synth_sysex(fluid_synth_t *synth, const char *data, int len, + char *response, int *response_len, int *handled, int dryrun); +FLUIDSYNTH_API int fluid_synth_pitch_bend(fluid_synth_t *synth, int chan, int val); +FLUIDSYNTH_API int fluid_synth_get_pitch_bend(fluid_synth_t *synth, int chan, int *ppitch_bend); +FLUIDSYNTH_API int fluid_synth_pitch_wheel_sens(fluid_synth_t *synth, int chan, int val); +FLUIDSYNTH_API int fluid_synth_get_pitch_wheel_sens(fluid_synth_t *synth, int chan, int *pval); +FLUIDSYNTH_API int fluid_synth_program_change(fluid_synth_t *synth, int chan, int program); +FLUIDSYNTH_API int fluid_synth_channel_pressure(fluid_synth_t *synth, int chan, int val); +FLUIDSYNTH_API int fluid_synth_key_pressure(fluid_synth_t *synth, int chan, int key, int val); +FLUIDSYNTH_API int fluid_synth_bank_select(fluid_synth_t *synth, int chan, int bank); +FLUIDSYNTH_API int fluid_synth_sfont_select(fluid_synth_t *synth, int chan, int sfont_id); +FLUIDSYNTH_API +int fluid_synth_program_select(fluid_synth_t *synth, int chan, int sfont_id, + int bank_num, int preset_num); +FLUIDSYNTH_API int +fluid_synth_program_select_by_sfont_name(fluid_synth_t *synth, int chan, + const char *sfont_name, int bank_num, + int preset_num); +FLUIDSYNTH_API +int fluid_synth_get_program(fluid_synth_t *synth, int chan, int *sfont_id, + int *bank_num, int *preset_num); +FLUIDSYNTH_API int fluid_synth_unset_program(fluid_synth_t *synth, int chan); +FLUIDSYNTH_API int fluid_synth_program_reset(fluid_synth_t *synth); +FLUIDSYNTH_API int fluid_synth_system_reset(fluid_synth_t *synth); + +FLUIDSYNTH_API int fluid_synth_all_notes_off(fluid_synth_t *synth, int chan); +FLUIDSYNTH_API int fluid_synth_all_sounds_off(fluid_synth_t *synth, int chan); + +FLUIDSYNTH_API int fluid_synth_set_gen(fluid_synth_t *synth, int chan, + int param, float value); +FLUIDSYNTH_API float fluid_synth_get_gen(fluid_synth_t *synth, int chan, int param); +/** @} MIDI Channel Messages */ + + +/** + * @defgroup voice_control Synthesis Voice Control + * @ingroup synth + * + * Low-level access to synthesis voices. + * + * @{ + */ +FLUIDSYNTH_API int fluid_synth_start(fluid_synth_t *synth, unsigned int id, + fluid_preset_t *preset, int audio_chan, + int midi_chan, int key, int vel); +FLUIDSYNTH_API int fluid_synth_stop(fluid_synth_t *synth, unsigned int id); + +FLUIDSYNTH_API fluid_voice_t *fluid_synth_alloc_voice(fluid_synth_t *synth, + fluid_sample_t *sample, + int channum, int key, int vel); +FLUIDSYNTH_API void fluid_synth_start_voice(fluid_synth_t *synth, fluid_voice_t *voice); +FLUIDSYNTH_API void fluid_synth_get_voicelist(fluid_synth_t *synth, + fluid_voice_t *buf[], int bufsize, int ID); +/** @} Voice Control */ + + +/** + * @defgroup soundfont_management SoundFont Management + * @ingroup synth + * + * Functions to load and unload SoundFonts. + * + * @{ + */ +FLUIDSYNTH_API +int fluid_synth_sfload(fluid_synth_t *synth, const char *filename, int reset_presets); +FLUIDSYNTH_API int fluid_synth_sfreload(fluid_synth_t *synth, int id); +FLUIDSYNTH_API int fluid_synth_sfunload(fluid_synth_t *synth, int id, int reset_presets); +FLUIDSYNTH_API int fluid_synth_add_sfont(fluid_synth_t *synth, fluid_sfont_t *sfont); +FLUIDSYNTH_API int fluid_synth_remove_sfont(fluid_synth_t *synth, fluid_sfont_t *sfont); +FLUIDSYNTH_API int fluid_synth_sfcount(fluid_synth_t *synth); +FLUIDSYNTH_API fluid_sfont_t *fluid_synth_get_sfont(fluid_synth_t *synth, unsigned int num); +FLUIDSYNTH_API fluid_sfont_t *fluid_synth_get_sfont_by_id(fluid_synth_t *synth, int id); +FLUIDSYNTH_API fluid_sfont_t *fluid_synth_get_sfont_by_name(fluid_synth_t *synth, + const char *name); +FLUIDSYNTH_API int fluid_synth_set_bank_offset(fluid_synth_t *synth, int sfont_id, int offset); +FLUIDSYNTH_API int fluid_synth_get_bank_offset(fluid_synth_t *synth, int sfont_id); +/** @} Soundfont Management */ + + +/** + * @defgroup reverb_effect Effect - Reverb + * @ingroup synth + * + * Functions for configuring the built-in reverb effect + * + * @{ + */ +FLUID_DEPRECATED FLUIDSYNTH_API void fluid_synth_set_reverb_on(fluid_synth_t *synth, int on); +FLUIDSYNTH_API int fluid_synth_reverb_on(fluid_synth_t *synth, int fx_group, int on); + +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb(fluid_synth_t *synth, double roomsize, + double damping, double width, double level); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb_roomsize(fluid_synth_t *synth, double roomsize); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb_damp(fluid_synth_t *synth, double damping); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb_width(fluid_synth_t *synth, double width); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb_level(fluid_synth_t *synth, double level); + +FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_reverb_roomsize(fluid_synth_t *synth); +FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_reverb_damp(fluid_synth_t *synth); +FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_reverb_level(fluid_synth_t *synth); +FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_reverb_width(fluid_synth_t *synth); + +FLUIDSYNTH_API int fluid_synth_set_reverb_group_roomsize(fluid_synth_t *synth, int fx_group, double roomsize); +FLUIDSYNTH_API int fluid_synth_set_reverb_group_damp(fluid_synth_t *synth, int fx_group, double damping); +FLUIDSYNTH_API int fluid_synth_set_reverb_group_width(fluid_synth_t *synth, int fx_group, double width); +FLUIDSYNTH_API int fluid_synth_set_reverb_group_level(fluid_synth_t *synth, int fx_group, double level); + +FLUIDSYNTH_API int fluid_synth_get_reverb_group_roomsize(fluid_synth_t *synth, int fx_group, double *roomsize); +FLUIDSYNTH_API int fluid_synth_get_reverb_group_damp(fluid_synth_t *synth, int fx_group, double *damping); +FLUIDSYNTH_API int fluid_synth_get_reverb_group_width(fluid_synth_t *synth, int fx_group, double *width); +FLUIDSYNTH_API int fluid_synth_get_reverb_group_level(fluid_synth_t *synth, int fx_group, double *level); + /** @} Reverb */ + + +/** + * @defgroup chorus_effect Effect - Chorus + * @ingroup synth + * + * Functions for configuring the built-in chorus effect + * + * @{ + */ + +/** + * Chorus modulation waveform type. + */ +enum fluid_chorus_mod +{ + FLUID_CHORUS_MOD_SINE = 0, /**< Sine wave chorus modulation */ + FLUID_CHORUS_MOD_TRIANGLE = 1 /**< Triangle wave chorus modulation */ +}; + + +FLUID_DEPRECATED FLUIDSYNTH_API void fluid_synth_set_chorus_on(fluid_synth_t *synth, int on); +FLUIDSYNTH_API int fluid_synth_chorus_on(fluid_synth_t *synth, int fx_group, int on); + +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus(fluid_synth_t *synth, int nr, double level, + double speed, double depth_ms, int type); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_nr(fluid_synth_t *synth, int nr); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_level(fluid_synth_t *synth, double level); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_speed(fluid_synth_t *synth, double speed); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_depth(fluid_synth_t *synth, double depth_ms); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_type(fluid_synth_t *synth, int type); + +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_get_chorus_nr(fluid_synth_t *synth); +FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_chorus_level(fluid_synth_t *synth); +FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_chorus_speed(fluid_synth_t *synth); +FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_chorus_depth(fluid_synth_t *synth); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_get_chorus_type(fluid_synth_t *synth); /* see fluid_chorus_mod */ + +FLUIDSYNTH_API int fluid_synth_set_chorus_group_nr(fluid_synth_t *synth, int fx_group, int nr); +FLUIDSYNTH_API int fluid_synth_set_chorus_group_level(fluid_synth_t *synth, int fx_group, double level); +FLUIDSYNTH_API int fluid_synth_set_chorus_group_speed(fluid_synth_t *synth, int fx_group, double speed); +FLUIDSYNTH_API int fluid_synth_set_chorus_group_depth(fluid_synth_t *synth, int fx_group, double depth_ms); +FLUIDSYNTH_API int fluid_synth_set_chorus_group_type(fluid_synth_t *synth, int fx_group, int type); + +FLUIDSYNTH_API int fluid_synth_get_chorus_group_nr(fluid_synth_t *synth, int fx_group, int *nr); +FLUIDSYNTH_API int fluid_synth_get_chorus_group_level(fluid_synth_t *synth, int fx_group, double *level); +FLUIDSYNTH_API int fluid_synth_get_chorus_group_speed(fluid_synth_t *synth, int fx_group, double *speed); +FLUIDSYNTH_API int fluid_synth_get_chorus_group_depth(fluid_synth_t *synth, int fx_group, double *depth_ms); +FLUIDSYNTH_API int fluid_synth_get_chorus_group_type(fluid_synth_t *synth, int fx_group, int *type); +/** @} Chorus */ + +/** + * @defgroup synthesis_params Synthesis Parameters + * @ingroup synth + * + * Functions to control and query synthesis parameters like gain and + * polyphony count. + * + * @{ + */ +FLUIDSYNTH_API int fluid_synth_count_midi_channels(fluid_synth_t *synth); +FLUIDSYNTH_API int fluid_synth_count_audio_channels(fluid_synth_t *synth); +FLUIDSYNTH_API int fluid_synth_count_audio_groups(fluid_synth_t *synth); +FLUIDSYNTH_API int fluid_synth_count_effects_channels(fluid_synth_t *synth); +FLUIDSYNTH_API int fluid_synth_count_effects_groups(fluid_synth_t *synth); + +FLUID_DEPRECATED FLUIDSYNTH_API void fluid_synth_set_sample_rate(fluid_synth_t *synth, float sample_rate); +FLUIDSYNTH_API void fluid_synth_set_gain(fluid_synth_t *synth, float gain); +FLUIDSYNTH_API float fluid_synth_get_gain(fluid_synth_t *synth); +FLUIDSYNTH_API int fluid_synth_set_polyphony(fluid_synth_t *synth, int polyphony); +FLUIDSYNTH_API int fluid_synth_get_polyphony(fluid_synth_t *synth); +FLUIDSYNTH_API int fluid_synth_get_active_voice_count(fluid_synth_t *synth); +FLUIDSYNTH_API int fluid_synth_get_internal_bufsize(fluid_synth_t *synth); + +FLUIDSYNTH_API +int fluid_synth_set_interp_method(fluid_synth_t *synth, int chan, int interp_method); + +/** + * Synthesis interpolation method. + */ +enum fluid_interp +{ + FLUID_INTERP_NONE = 0, /**< No interpolation: Fastest, but questionable audio quality */ + FLUID_INTERP_LINEAR = 1, /**< Straight-line interpolation: A bit slower, reasonable audio quality */ + FLUID_INTERP_4THORDER = 4, /**< Fourth-order interpolation, good quality, the default */ + FLUID_INTERP_7THORDER = 7, /**< Seventh-order interpolation */ + + FLUID_INTERP_DEFAULT = FLUID_INTERP_4THORDER, /**< Default interpolation method */ + FLUID_INTERP_HIGHEST = FLUID_INTERP_7THORDER, /**< Highest interpolation method */ +}; + +/** + * Enum used with fluid_synth_add_default_mod() to specify how to handle duplicate modulators. + */ +enum fluid_synth_add_mod +{ + FLUID_SYNTH_OVERWRITE, /**< Overwrite any existing matching modulator */ + FLUID_SYNTH_ADD, /**< Sum up modulator amounts */ +}; + +FLUIDSYNTH_API int fluid_synth_add_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod, int mode); +FLUIDSYNTH_API int fluid_synth_remove_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod); +/** @} Synthesis Parameters */ + + +/** + * @defgroup tuning MIDI Tuning + * @ingroup synth + * + * The functions in this section implement the MIDI Tuning Standard interface. + * + * @{ + */ +FLUIDSYNTH_API +int fluid_synth_activate_key_tuning(fluid_synth_t *synth, int bank, int prog, + const char *name, const double *pitch, int apply); +FLUIDSYNTH_API +int fluid_synth_activate_octave_tuning(fluid_synth_t *synth, int bank, int prog, + const char *name, const double *pitch, int apply); +FLUIDSYNTH_API +int fluid_synth_tune_notes(fluid_synth_t *synth, int bank, int prog, + int len, const int *keys, const double *pitch, int apply); +FLUIDSYNTH_API +int fluid_synth_activate_tuning(fluid_synth_t *synth, int chan, int bank, int prog, + int apply); +FLUIDSYNTH_API +int fluid_synth_deactivate_tuning(fluid_synth_t *synth, int chan, int apply); +FLUIDSYNTH_API void fluid_synth_tuning_iteration_start(fluid_synth_t *synth); +FLUIDSYNTH_API +int fluid_synth_tuning_iteration_next(fluid_synth_t *synth, int *bank, int *prog); +FLUIDSYNTH_API int fluid_synth_tuning_dump(fluid_synth_t *synth, int bank, int prog, + char *name, int len, double *pitch); +/** @} MIDI Tuning */ + + +/** + * @defgroup audio_rendering Audio Rendering + * @ingroup synth + * + * The functions in this section can be used to render audio directly to + * memory buffers. They are used internally by the \ref audio_driver and \ref file_renderer, + * but can also be used manually for custom processing of the rendered audio. + * + * @note Please note that all following functions block during rendering. If your goal is to + * render real-time audio, ensure that you call these functions from a high-priority + * thread with little to no other duties other than calling the rendering functions. + * + * @warning + * If a concurrently running thread calls any other sound affecting synth function + * (e.g. fluid_synth_noteon(), fluid_synth_cc(), etc.) it is unspecified whether the event triggered by such a call + * will be effective in the recently synthesized audio. While this is inaudible when only requesting small chunks from the + * synth with every call (cf. fluid_synth_get_internal_bufsize()), it will become evident when requesting larger sample chunks: + * With larger sample chunks it will get harder for the synth to react on those spontaneously occurring events in time + * (like events received from a MIDI driver, or directly made synth API calls). + * In those real-time scenarios, prefer requesting smaller + * sample chunks from the synth with each call, to avoid poor quantization of your events in the synthesized audio. + * This issue is not applicable when using the MIDI player or sequencer for event dispatching. Also + * refer to the documentation of \setting{audio_period-size}. + * + * @{ + */ +FLUIDSYNTH_API int fluid_synth_write_s16(fluid_synth_t *synth, int len, + void *lout, int loff, int lincr, + void *rout, int roff, int rincr); +FLUIDSYNTH_API int fluid_synth_write_float(fluid_synth_t *synth, int len, + void *lout, int loff, int lincr, + void *rout, int roff, int rincr); +FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_nwrite_float(fluid_synth_t *synth, int len, + float **left, float **right, + float **fx_left, float **fx_right); +FLUIDSYNTH_API int fluid_synth_process(fluid_synth_t *synth, int len, + int nfx, float *fx[], + int nout, float *out[]); +/** @} Audio Rendering */ + + +/** + * @defgroup iir_filter Effect - IIR Filter + * @ingroup synth + * + * Functions for configuring the built-in IIR filter effect + * + * @{ + */ + +/** + * Specifies the type of filter to use for the custom IIR filter + */ +enum fluid_iir_filter_type +{ + FLUID_IIR_DISABLED = 0, /**< Custom IIR filter is not operating */ + FLUID_IIR_LOWPASS, /**< Custom IIR filter is operating as low-pass filter */ + FLUID_IIR_HIGHPASS, /**< Custom IIR filter is operating as high-pass filter */ + FLUID_IIR_LAST /**< @internal Value defines the count of filter types (#fluid_iir_filter_type) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */ +}; + +/** + * Specifies optional settings to use for the custom IIR filter. Can be bitwise ORed. + */ +enum fluid_iir_filter_flags +{ + FLUID_IIR_Q_LINEAR = 1 << 0, /**< The Soundfont spec requires the filter Q to be interpreted in dB. If this flag is set the filter Q is instead assumed to be in a linear range */ + FLUID_IIR_Q_ZERO_OFF = 1 << 1, /**< If this flag the filter is switched off if Q == 0 (prior to any transformation) */ + FLUID_IIR_NO_GAIN_AMP = 1 << 2 /**< The Soundfont spec requires to correct the gain of the filter depending on the filter's Q. If this flag is set the filter gain will not be corrected. */ +}; + +FLUIDSYNTH_API int fluid_synth_set_custom_filter(fluid_synth_t *, int type, int flags); +/** @} IIR Filter */ + + + + +/** + * @defgroup channel_setup MIDI Channel Setup + * @ingroup synth + * + * The functions in this section provide interfaces to change the channel type + * and to configure basic channels, legato and portamento setups. + * + * @{ + */ + +/** @name Channel Type + * @{ + */ + +/** + * The midi channel type used by fluid_synth_set_channel_type() + */ +enum fluid_midi_channel_type +{ + CHANNEL_TYPE_MELODIC = 0, /**< Melodic midi channel */ + CHANNEL_TYPE_DRUM = 1 /**< Drum midi channel */ +}; + +FLUIDSYNTH_API int fluid_synth_set_channel_type(fluid_synth_t *synth, int chan, int type); +/** @} Channel Type */ + + +/** @name Basic Channel Mode + * @{ + */ + +/** + * Channel mode bits OR-ed together so that it matches with the midi spec: poly omnion (0), mono omnion (1), poly omnioff (2), mono omnioff (3) + */ +enum fluid_channel_mode_flags +{ + FLUID_CHANNEL_POLY_OFF = 0x01, /**< if flag is set, the basic channel is in mono on state, if not set poly is on */ + FLUID_CHANNEL_OMNI_OFF = 0x02, /**< if flag is set, the basic channel is in omni off state, if not set omni is on */ +}; + +/** + * Indicates the mode a basic channel is set to + */ +enum fluid_basic_channel_modes +{ + FLUID_CHANNEL_MODE_MASK = (FLUID_CHANNEL_OMNI_OFF | FLUID_CHANNEL_POLY_OFF), /**< Mask Poly and Omni bits of #fluid_channel_mode_flags, usually only used internally */ + FLUID_CHANNEL_MODE_OMNION_POLY = FLUID_CHANNEL_MODE_MASK & (~FLUID_CHANNEL_OMNI_OFF & ~FLUID_CHANNEL_POLY_OFF), /**< corresponds to MIDI mode 0 */ + FLUID_CHANNEL_MODE_OMNION_MONO = FLUID_CHANNEL_MODE_MASK & (~FLUID_CHANNEL_OMNI_OFF & FLUID_CHANNEL_POLY_OFF), /**< corresponds to MIDI mode 1 */ + FLUID_CHANNEL_MODE_OMNIOFF_POLY = FLUID_CHANNEL_MODE_MASK & (FLUID_CHANNEL_OMNI_OFF & ~FLUID_CHANNEL_POLY_OFF), /**< corresponds to MIDI mode 2 */ + FLUID_CHANNEL_MODE_OMNIOFF_MONO = FLUID_CHANNEL_MODE_MASK & (FLUID_CHANNEL_OMNI_OFF | FLUID_CHANNEL_POLY_OFF), /**< corresponds to MIDI mode 3 */ + FLUID_CHANNEL_MODE_LAST /**< @internal Value defines the count of basic channel modes (#fluid_basic_channel_modes) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */ +}; + +FLUIDSYNTH_API int fluid_synth_reset_basic_channel(fluid_synth_t *synth, int chan); + +FLUIDSYNTH_API int fluid_synth_get_basic_channel(fluid_synth_t *synth, int chan, + int *basic_chan_out, + int *mode_chan_out, + int *basic_val_out); +FLUIDSYNTH_API int fluid_synth_set_basic_channel(fluid_synth_t *synth, int chan, int mode, int val); + +/** @} Basic Channel Mode */ + +/** @name Legato Mode + * @{ + */ + +/** + * Indicates the legato mode a channel is set to + * n1,n2,n3,.. is a legato passage. n1 is the first note, and n2,n3,n4 are played legato with previous note. */ +enum fluid_channel_legato_mode +{ + FLUID_CHANNEL_LEGATO_MODE_RETRIGGER, /**< Mode 0 - Release previous note, start a new note */ + FLUID_CHANNEL_LEGATO_MODE_MULTI_RETRIGGER, /**< Mode 1 - On contiguous notes retrigger in attack section using current value, shape attack using current dynamic and make use of previous voices if any */ + FLUID_CHANNEL_LEGATO_MODE_LAST /**< @internal Value defines the count of legato modes (#fluid_channel_legato_mode) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */ +}; + +FLUIDSYNTH_API int fluid_synth_set_legato_mode(fluid_synth_t *synth, int chan, int legatomode); +FLUIDSYNTH_API int fluid_synth_get_legato_mode(fluid_synth_t *synth, int chan, int *legatomode); +/** @} Legato Mode */ + +/** @name Portamento Mode + * @{ + */ + +/** + * Indicates the portamento mode a channel is set to + */ +enum fluid_channel_portamento_mode +{ + FLUID_CHANNEL_PORTAMENTO_MODE_EACH_NOTE, /**< Mode 0 - Portamento on each note (staccato or legato) */ + FLUID_CHANNEL_PORTAMENTO_MODE_LEGATO_ONLY, /**< Mode 1 - Portamento only on legato note */ + FLUID_CHANNEL_PORTAMENTO_MODE_STACCATO_ONLY, /**< Mode 2 - Portamento only on staccato note */ + FLUID_CHANNEL_PORTAMENTO_MODE_LAST /**< @internal Value defines the count of portamento modes + @warning This symbol is not part of the public API and ABI + stability guarantee and may change at any time! */ +}; + +FLUIDSYNTH_API int fluid_synth_set_portamento_mode(fluid_synth_t *synth, + int chan, int portamentomode); +FLUIDSYNTH_API int fluid_synth_get_portamento_mode(fluid_synth_t *synth, + int chan, int *portamentomode); +/** @} Portamento Mode */ + +/**@name Breath Mode + * @{ + */ + +/** + * Indicates the breath mode a channel is set to + */ +enum fluid_channel_breath_flags +{ + FLUID_CHANNEL_BREATH_POLY = 0x10, /**< when channel is poly, this flag indicates that the default velocity to initial attenuation modulator is replaced by a breath to initial attenuation modulator */ + FLUID_CHANNEL_BREATH_MONO = 0x20, /**< when channel is mono, this flag indicates that the default velocity to initial attenuation modulator is replaced by a breath modulator */ + FLUID_CHANNEL_BREATH_SYNC = 0x40, /**< when channel is mono, this flag indicates that the breath controller(MSB)triggers noteon/noteoff on the running note */ +}; + +FLUIDSYNTH_API int fluid_synth_set_breath_mode(fluid_synth_t *synth, + int chan, int breathmode); +FLUIDSYNTH_API int fluid_synth_get_breath_mode(fluid_synth_t *synth, + int chan, int *breathmode); +/** @} Breath Mode */ +/** @} MIDI Channel Setup */ + + +/** @ingroup settings */ +FLUIDSYNTH_API fluid_settings_t *fluid_synth_get_settings(fluid_synth_t *synth); + +/** @ingroup soundfont_loader */ +FLUIDSYNTH_API void fluid_synth_add_sfloader(fluid_synth_t *synth, fluid_sfloader_t *loader); + +/** @ingroup soundfont_loader */ +FLUIDSYNTH_API fluid_preset_t *fluid_synth_get_channel_preset(fluid_synth_t *synth, int chan); + +/** @ingroup midi_input */ +FLUIDSYNTH_API int fluid_synth_handle_midi_event(void *data, fluid_midi_event_t *event); + +/** @ingroup soundfonts */ +FLUIDSYNTH_API +int fluid_synth_pin_preset(fluid_synth_t *synth, int sfont_id, int bank_num, int preset_num); + +/** @ingroup soundfonts */ +FLUIDSYNTH_API +int fluid_synth_unpin_preset(fluid_synth_t *synth, int sfont_id, int bank_num, int preset_num); + +/** @ingroup ladspa */ +FLUIDSYNTH_API fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth); + +#ifdef __cplusplus +} +#endif + +#endif /* _FLUIDSYNTH_SYNTH_H */ diff --git a/libs/fluidsynth/include/fluidsynth/types.h b/libs/fluidsynth/include/fluidsynth/types.h new file mode 100644 index 00000000000..9c2aaadacaa --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth/types.h @@ -0,0 +1,85 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_TYPES_H +#define _FLUIDSYNTH_TYPES_H + + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @defgroup Types Types + * @brief Type declarations + * + * @{ + */ + +typedef struct _fluid_hashtable_t fluid_settings_t; /**< Configuration settings instance */ +typedef struct _fluid_synth_t fluid_synth_t; /**< Synthesizer instance */ +typedef struct _fluid_voice_t fluid_voice_t; /**< Synthesis voice instance */ +typedef struct _fluid_sfloader_t fluid_sfloader_t; /**< SoundFont loader plugin */ +typedef struct _fluid_sfont_t fluid_sfont_t; /**< SoundFont */ +typedef struct _fluid_preset_t fluid_preset_t; /**< SoundFont preset */ +typedef struct _fluid_sample_t fluid_sample_t; /**< SoundFont sample */ +typedef struct _fluid_mod_t fluid_mod_t; /**< SoundFont modulator */ +typedef struct _fluid_audio_driver_t fluid_audio_driver_t; /**< Audio driver instance */ +typedef struct _fluid_file_renderer_t fluid_file_renderer_t; /**< Audio file renderer instance */ +typedef struct _fluid_player_t fluid_player_t; /**< MIDI player instance */ +typedef struct _fluid_midi_event_t fluid_midi_event_t; /**< MIDI event */ +typedef struct _fluid_midi_driver_t fluid_midi_driver_t; /**< MIDI driver instance */ +typedef struct _fluid_midi_router_t fluid_midi_router_t; /**< MIDI router instance */ +typedef struct _fluid_midi_router_rule_t fluid_midi_router_rule_t; /**< MIDI router rule */ +typedef struct _fluid_hashtable_t fluid_cmd_hash_t; /**< Command handler hash table */ +typedef struct _fluid_shell_t fluid_shell_t; /**< Command shell */ +typedef struct _fluid_server_t fluid_server_t; /**< TCP/IP shell server instance */ +typedef struct _fluid_event_t fluid_event_t; /**< Sequencer event */ +typedef struct _fluid_sequencer_t fluid_sequencer_t; /**< Sequencer instance */ +typedef struct _fluid_ramsfont_t fluid_ramsfont_t; /**< RAM SoundFont */ +typedef struct _fluid_rampreset_t fluid_rampreset_t; /**< RAM SoundFont preset */ +typedef struct _fluid_cmd_handler_t fluid_cmd_handler_t; /**< Shell Command Handler */ +typedef struct _fluid_ladspa_fx_t fluid_ladspa_fx_t; /**< LADSPA effects instance */ +typedef struct _fluid_file_callbacks_t fluid_file_callbacks_t; /**< Callback struct to perform custom file loading of soundfonts */ + +typedef int fluid_istream_t; /**< Input stream descriptor */ +typedef int fluid_ostream_t; /**< Output stream descriptor */ + +typedef short fluid_seq_id_t; /**< Unique client IDs used by the sequencer and #fluid_event_t, obtained by fluid_sequencer_register_client() and fluid_sequencer_register_fluidsynth() */ + +#if defined(_MSC_VER) && (_MSC_VER < 1800) +typedef __int64 fluid_long_long_t; // even on 32bit windows +#else +/** + * A typedef for C99's type long long, which is at least 64-bit wide, as guaranteed by the C99. + * @p __int64 will be used as replacement for VisualStudio 2010 and older. + */ +typedef long long fluid_long_long_t; +#endif + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FLUIDSYNTH_TYPES_H */ diff --git a/libs/fluidsynth/include/fluidsynth/version.h b/libs/fluidsynth/include/fluidsynth/version.h new file mode 100644 index 00000000000..2de6e9fbf4d --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth/version.h @@ -0,0 +1,47 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_VERSION_H +#define _FLUIDSYNTH_VERSION_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup misc + * + * @{ + */ +#define FLUIDSYNTH_VERSION "2.3.3" /**< String constant of libfluidsynth version. */ +#define FLUIDSYNTH_VERSION_MAJOR 2 /**< libfluidsynth major version integer constant. */ +#define FLUIDSYNTH_VERSION_MINOR 3 /**< libfluidsynth minor version integer constant. */ +#define FLUIDSYNTH_VERSION_MICRO 3 /**< libfluidsynth micro version integer constant. */ + +FLUIDSYNTH_API void fluid_version(int *major, int *minor, int *micro); +FLUIDSYNTH_API char* fluid_version_str(void); +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FLUIDSYNTH_VERSION_H */ diff --git a/libs/fluidsynth/include/fluidsynth/voice.h b/libs/fluidsynth/include/fluidsynth/voice.h new file mode 100644 index 00000000000..44f31e5fe18 --- /dev/null +++ b/libs/fluidsynth/include/fluidsynth/voice.h @@ -0,0 +1,76 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUIDSYNTH_VOICE_H +#define _FLUIDSYNTH_VOICE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup voices Voice Manipulation + * @ingroup soundfonts + * + * Synthesis voice manipulation functions. + * + * The interface to the synthesizer's voices. + * Examples on using them can be found in the source code of the default SoundFont + * loader (fluid_defsfont.c). + * + * Most of these functions should only be called from within synthesis context, + * such as the SoundFont loader's noteon method. + * + * @{ + */ + +/** + * Enum used with fluid_voice_add_mod() to specify how to handle duplicate modulators. + */ +enum fluid_voice_add_mod +{ + FLUID_VOICE_OVERWRITE, /**< Overwrite any existing matching modulator */ + FLUID_VOICE_ADD, /**< Add (sum) modulator amounts */ + FLUID_VOICE_DEFAULT /**< For default modulators only, no need to check for duplicates */ +}; + +FLUIDSYNTH_API void fluid_voice_add_mod(fluid_voice_t *voice, fluid_mod_t *mod, int mode); +FLUIDSYNTH_API float fluid_voice_gen_get(fluid_voice_t *voice, int gen); +FLUIDSYNTH_API void fluid_voice_gen_set(fluid_voice_t *voice, int gen, float val); +FLUIDSYNTH_API void fluid_voice_gen_incr(fluid_voice_t *voice, int gen, float val); + +FLUIDSYNTH_API unsigned int fluid_voice_get_id(const fluid_voice_t *voice); +FLUIDSYNTH_API int fluid_voice_get_channel(const fluid_voice_t *voice); +FLUIDSYNTH_API int fluid_voice_get_key(const fluid_voice_t *voice); +FLUIDSYNTH_API int fluid_voice_get_actual_key(const fluid_voice_t *voice); +FLUIDSYNTH_API int fluid_voice_get_velocity(const fluid_voice_t *voice); +FLUIDSYNTH_API int fluid_voice_get_actual_velocity(const fluid_voice_t *voice); +FLUIDSYNTH_API int fluid_voice_is_playing(const fluid_voice_t *voice); +FLUIDSYNTH_API int fluid_voice_is_on(const fluid_voice_t *voice); +FLUIDSYNTH_API int fluid_voice_is_sustained(const fluid_voice_t *voice); +FLUIDSYNTH_API int fluid_voice_is_sostenuto(const fluid_voice_t *voice); +FLUIDSYNTH_API int fluid_voice_optimize_sample(fluid_sample_t *s); +FLUIDSYNTH_API void fluid_voice_update_param(fluid_voice_t *voice, int gen); +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif /* _FLUIDSYNTH_VOICE_H */ diff --git a/libs/fluidsynth/src/bindings/fluid_ladspa.h b/libs/fluidsynth/src/bindings/fluid_ladspa.h new file mode 100644 index 00000000000..80952d51ea9 --- /dev/null +++ b/libs/fluidsynth/src/bindings/fluid_ladspa.h @@ -0,0 +1,36 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUID_LADSPA_H +#define _FLUID_LADSPA_H + +#include "fluid_sys.h" + +fluid_ladspa_fx_t *new_fluid_ladspa_fx(fluid_real_t sample_rate, int buffer_size); +void delete_fluid_ladspa_fx(fluid_ladspa_fx_t *fx); + +int fluid_ladspa_set_sample_rate(fluid_ladspa_fx_t *fx, fluid_real_t sample_rate); + +void fluid_ladspa_run(fluid_ladspa_fx_t *fx, int block_count, int block_size); + +int fluid_ladspa_add_host_ports(fluid_ladspa_fx_t *fx, const char *prefix, + int num_buffers, fluid_real_t buffers[], int buf_stride); + +#endif /* _FLUID_LADSPA_H */ diff --git a/libs/fluidsynth/src/midi/fluid_midi.c b/libs/fluidsynth/src/midi/fluid_midi.c new file mode 100644 index 00000000000..6ea0216cfb3 --- /dev/null +++ b/libs/fluidsynth/src/midi/fluid_midi.c @@ -0,0 +1,2851 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include "fluid_midi.h" +#include "fluid_sys.h" +#include "fluid_synth.h" +#include "fluid_settings.h" + + +static int fluid_midi_event_length(unsigned char event); +static int fluid_isasciistring(char *s); +static long fluid_getlength(const unsigned char *s); + + +/* Read the entire contents of a file into memory, allocating enough memory + * for the file, and returning the length and the buffer. + * Note: This rewinds the file to the start before reading. + * Returns NULL if there was an error reading or allocating memory. + */ +typedef FILE *fluid_file; +static char *fluid_file_read_full(fluid_file fp, size_t *length); +static void fluid_midi_event_set_sysex_LOCAL(fluid_midi_event_t *evt, int type, void *data, int size, int dynamic); +static void fluid_midi_event_get_sysex_LOCAL(fluid_midi_event_t *evt, void **data, int *size); +#define READ_FULL_INITIAL_BUFLEN 1024 + +static fluid_track_t *new_fluid_track(int num); +static void delete_fluid_track(fluid_track_t *track); +static int fluid_track_set_name(fluid_track_t *track, char *name); +static int fluid_track_add_event(fluid_track_t *track, fluid_midi_event_t *evt); +static fluid_midi_event_t *fluid_track_next_event(fluid_track_t *track); +static int fluid_track_get_duration(fluid_track_t *track); +static int fluid_track_reset(fluid_track_t *track); + +static int fluid_player_add_track(fluid_player_t *player, fluid_track_t *track); +static int fluid_player_callback(void *data, unsigned int msec); +static int fluid_player_reset(fluid_player_t *player); +static int fluid_player_load(fluid_player_t *player, fluid_playlist_item *item); +static void fluid_player_advancefile(fluid_player_t *player); +static void fluid_player_playlist_load(fluid_player_t *player, unsigned int msec); +static void fluid_player_update_tempo(fluid_player_t *player); + +static fluid_midi_file *new_fluid_midi_file(const char *buffer, size_t length); +static void delete_fluid_midi_file(fluid_midi_file *mf); +static int fluid_midi_file_read_mthd(fluid_midi_file *midifile); +static int fluid_midi_file_load_tracks(fluid_midi_file *midifile, fluid_player_t *player); +static int fluid_midi_file_read_track(fluid_midi_file *mf, fluid_player_t *player, int num); +static int fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track); +static int fluid_midi_file_read_varlen(fluid_midi_file *mf); +static int fluid_midi_file_getc(fluid_midi_file *mf); +static int fluid_midi_file_push(fluid_midi_file *mf, int c); +static int fluid_midi_file_read(fluid_midi_file *mf, void *buf, int len); +static int fluid_midi_file_skip(fluid_midi_file *mf, int len); +static int fluid_midi_file_eof(fluid_midi_file *mf); +static int fluid_midi_file_read_tracklen(fluid_midi_file *mf); +static int fluid_midi_file_eot(fluid_midi_file *mf); +static int fluid_midi_file_get_division(fluid_midi_file *midifile); + + +/*************************************************************** + * + * MIDIFILE + */ + +/** + * Check if a file is a MIDI file. + * @param filename Path to the file to check + * @return TRUE if it could be a MIDI file, FALSE otherwise + * + * The current implementation only checks for the "MThd" header in the file. + * It is useful only to distinguish between SoundFont and MIDI files. + */ +int fluid_is_midifile(const char *filename) +{ + FILE *fp; + uint32_t id; + int retcode = FALSE; + + do + { + if((fp = fluid_file_open(filename, NULL)) == NULL) + { + return retcode; + } + + if(FLUID_FREAD(&id, sizeof(id), 1, fp) != 1) + { + break; + } + + retcode = (id == FLUID_FOURCC('M', 'T', 'h', 'd')); + } + while(0); + + FLUID_FCLOSE(fp); + + return retcode; +} + +/** + * Return a new MIDI file handle for parsing an already-loaded MIDI file. + * @internal + * @param buffer Pointer to full contents of MIDI file (borrows the pointer). + * The caller must not free buffer until after the fluid_midi_file is deleted. + * @param length Size of the buffer in bytes. + * @return New MIDI file handle or NULL on error. + */ +fluid_midi_file * +new_fluid_midi_file(const char *buffer, size_t length) +{ + fluid_midi_file *mf; + + if(length > INT_MAX) + { + FLUID_LOG(FLUID_ERR, "Refusing to open a MIDI file which is bigger than 2GiB"); + return NULL; + } + + mf = FLUID_NEW(fluid_midi_file); + if(mf == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + FLUID_MEMSET(mf, 0, sizeof(fluid_midi_file)); + + mf->c = -1; + mf->running_status = -1; + + mf->buffer = buffer; + mf->buf_len = (int)length; + mf->buf_pos = 0; + mf->eof = FALSE; + + if(fluid_midi_file_read_mthd(mf) != FLUID_OK) + { + FLUID_FREE(mf); + return NULL; + } + + return mf; +} + +static char * +fluid_file_read_full(fluid_file fp, size_t *length) +{ + size_t buflen; + char *buffer; + size_t n; + + /* Work out the length of the file in advance */ + if(FLUID_FSEEK(fp, 0, SEEK_END) != 0) + { + FLUID_LOG(FLUID_ERR, "File load: Could not seek within file"); + return NULL; + } + + buflen = ftell(fp); + + if(FLUID_FSEEK(fp, 0, SEEK_SET) != 0) + { + FLUID_LOG(FLUID_ERR, "File load: Could not seek within file"); + return NULL; + } + + FLUID_LOG(FLUID_DBG, "File load: Allocating %lu bytes", (unsigned long)buflen); + buffer = FLUID_MALLOC(buflen); + + if(buffer == NULL) + { + FLUID_LOG(FLUID_PANIC, "Out of memory"); + return NULL; + } + + n = FLUID_FREAD(buffer, 1, buflen, fp); + + if(n != buflen) + { + FLUID_LOG(FLUID_ERR, "Only read %lu bytes; expected %lu", (unsigned long)n, + (unsigned long)buflen); + FLUID_FREE(buffer); + return NULL; + }; + + *length = n; + + return buffer; +} + +/** + * Delete a MIDI file handle. + * @internal + * @param mf MIDI file handle to close and free. + */ +void +delete_fluid_midi_file(fluid_midi_file *mf) +{ + fluid_return_if_fail(mf != NULL); + + FLUID_FREE(mf); +} + +/* + * Gets the next byte in a MIDI file, taking into account previous running status. + * + * returns -1 if EOF or read error + */ +int +fluid_midi_file_getc(fluid_midi_file *mf) +{ + unsigned char c; + + if(mf->c >= 0) + { + c = mf->c; + mf->c = -1; + } + else + { + if(mf->buf_pos >= mf->buf_len) + { + mf->eof = TRUE; + return -1; + } + + c = mf->buffer[mf->buf_pos++]; + mf->trackpos++; + } + + return (int) c; +} + +/* + * Saves a byte to be returned the next time fluid_midi_file_getc() is called, + * when it is necessary according to running status. + */ +int +fluid_midi_file_push(fluid_midi_file *mf, int c) +{ + mf->c = c; + return FLUID_OK; +} + +/* + * fluid_midi_file_read + */ +int +fluid_midi_file_read(fluid_midi_file *mf, void *buf, int len) +{ + int num = len < mf->buf_len - mf->buf_pos + ? len : mf->buf_len - mf->buf_pos; + + if(num != len) + { + mf->eof = TRUE; + } + + if(num < 0) + { + num = 0; + } + + /* Note: Read bytes, even if there aren't enough, but only increment + * trackpos if successful (emulates old behaviour of fluid_midi_file_read) + */ + FLUID_MEMCPY(buf, mf->buffer + mf->buf_pos, num); + mf->buf_pos += num; + + if(num == len) + { + mf->trackpos += num; + } + +#if DEBUG + else + { + FLUID_LOG(FLUID_DBG, "Could not read the requested number of bytes"); + } + +#endif + return (num != len) ? FLUID_FAILED : FLUID_OK; +} + +/* + * fluid_midi_file_skip + */ +int +fluid_midi_file_skip(fluid_midi_file *mf, int skip) +{ + int new_pos = mf->buf_pos + skip; + + /* Mimic the behaviour of fseek: Error to seek past the start of file, but + * OK to seek past end (this just puts it into the EOF state). */ + if(new_pos < 0) + { + FLUID_LOG(FLUID_ERR, "Failed to seek position in file"); + return FLUID_FAILED; + } + + /* Clear the EOF flag, even if moved past the end of the file (this is + * consistent with the behaviour of fseek). */ + mf->eof = FALSE; + mf->buf_pos = new_pos; + return FLUID_OK; +} + +/* + * fluid_midi_file_eof + */ +int fluid_midi_file_eof(fluid_midi_file *mf) +{ + /* Note: This does not simply test whether the file read pointer is past + * the end of the file. It mimics the behaviour of feof by actually + * testing the stateful EOF condition, which is set to TRUE if getc or + * fread have attempted to read past the end (but not if they have + * precisely reached the end), but reset to FALSE upon a successful seek. + */ + return mf->eof; +} + +/* + * fluid_midi_file_read_mthd + */ +int +fluid_midi_file_read_mthd(fluid_midi_file *mf) +{ + char mthd[14]; + + if(fluid_midi_file_read(mf, mthd, sizeof(mthd)) != FLUID_OK) + { + return FLUID_FAILED; + } + + if((FLUID_STRNCMP(mthd, "MThd", 4) != 0) || (mthd[7] != 6) + || (mthd[9] > 2)) + { + FLUID_LOG(FLUID_ERR, + "Doesn't look like a MIDI file: invalid MThd header"); + return FLUID_FAILED; + } + + mf->type = mthd[9]; + mf->ntracks = (unsigned) mthd[11]; + mf->ntracks += (unsigned int)(mthd[10]) << 16; + + if((signed char)mthd[12] < 0) + { + mf->uses_smpte = 1; + mf->smpte_fps = -(signed char)mthd[12]; + mf->smpte_res = (unsigned) mthd[13]; + FLUID_LOG(FLUID_ERR, "File uses SMPTE timing -- Not implemented yet"); + return FLUID_FAILED; + } + else + { + mf->uses_smpte = 0; + mf->division = ((unsigned)mthd[12] << 8) | ((unsigned)mthd[13] & 0xff); + FLUID_LOG(FLUID_DBG, "Division=%d", mf->division); + } + + return FLUID_OK; +} + +/* + * fluid_midi_file_load_tracks + */ +int +fluid_midi_file_load_tracks(fluid_midi_file *mf, fluid_player_t *player) +{ + int i; + + for(i = 0; i < mf->ntracks; i++) + { + if(fluid_midi_file_read_track(mf, player, i) != FLUID_OK) + { + return FLUID_FAILED; + } + } + + return FLUID_OK; +} + +/* + * fluid_isasciistring + */ +int +fluid_isasciistring(char *s) +{ + /* From ctype.h */ +#define fluid_isascii(c) (((c) & ~0x7f) == 0) + + size_t i, len = FLUID_STRLEN(s); + + for(i = 0; i < len; i++) + { + if(!fluid_isascii(s[i])) + { + return 0; + } + } + + return 1; + +#undef fluid_isascii +} + +/* + * fluid_getlength + */ +long +fluid_getlength(const unsigned char *s) +{ + long i = 0; + i = s[3] | (s[2] << 8) | (s[1] << 16) | (s[0] << 24); + return i; +} + +/* + * fluid_midi_file_read_tracklen + */ +int +fluid_midi_file_read_tracklen(fluid_midi_file *mf) +{ + unsigned char length[5]; + + if(fluid_midi_file_read(mf, length, 4) != FLUID_OK) + { + return FLUID_FAILED; + } + + mf->tracklen = fluid_getlength(length); + mf->trackpos = 0; + mf->eot = 0; + return FLUID_OK; +} + +/* + * fluid_midi_file_eot + */ +int +fluid_midi_file_eot(fluid_midi_file *mf) +{ +#if DEBUG + + if(mf->trackpos > mf->tracklen) + { + printf("track overrun: %d > %d\n", mf->trackpos, mf->tracklen); + } + +#endif + return mf->eot || (mf->trackpos >= mf->tracklen); +} + +/* + * fluid_midi_file_read_track + */ +int +fluid_midi_file_read_track(fluid_midi_file *mf, fluid_player_t *player, int num) +{ + fluid_track_t *track; + unsigned char id[5], length[5]; + int found_track = 0; + int skip; + + if(fluid_midi_file_read(mf, id, 4) != FLUID_OK) + { + return FLUID_FAILED; + } + + id[4] = '\0'; + mf->dtime = 0; + + while(!found_track) + { + + if(fluid_isasciistring((char *) id) == 0) + { + FLUID_LOG(FLUID_ERR, + "A non-ascii track header found, corrupt file"); + return FLUID_FAILED; + + } + else if(FLUID_STRCMP((char *) id, "MTrk") == 0) + { + + found_track = 1; + + if(fluid_midi_file_read_tracklen(mf) != FLUID_OK) + { + return FLUID_FAILED; + } + + track = new_fluid_track(num); + + if(track == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FLUID_FAILED; + } + + while(!fluid_midi_file_eot(mf)) + { + if(fluid_midi_file_read_event(mf, track) != FLUID_OK) + { + delete_fluid_track(track); + return FLUID_FAILED; + } + } + + /* Skip remaining track data, if any */ + if(mf->trackpos < mf->tracklen) + { + if(fluid_midi_file_skip(mf, mf->tracklen - mf->trackpos) != FLUID_OK) + { + delete_fluid_track(track); + return FLUID_FAILED; + } + } + + if(fluid_player_add_track(player, track) != FLUID_OK) + { + delete_fluid_track(track); + return FLUID_FAILED; + } + + } + else + { + found_track = 0; + + if(fluid_midi_file_read(mf, length, 4) != FLUID_OK) + { + return FLUID_FAILED; + } + + skip = fluid_getlength(length); + + /* fseek(mf->fp, skip, SEEK_CUR); */ + if(fluid_midi_file_skip(mf, skip) != FLUID_OK) + { + return FLUID_FAILED; + } + } + } + + if(fluid_midi_file_eof(mf)) + { + FLUID_LOG(FLUID_ERR, "Unexpected end of file"); + return FLUID_FAILED; + } + + return FLUID_OK; +} + +/* + * fluid_midi_file_read_varlen + */ +int +fluid_midi_file_read_varlen(fluid_midi_file *mf) +{ + int i; + int c; + mf->varlen = 0; + + for(i = 0;; i++) + { + if(i == 4) + { + FLUID_LOG(FLUID_ERR, "Invalid variable length number"); + return FLUID_FAILED; + } + + c = fluid_midi_file_getc(mf); + + if(c < 0) + { + FLUID_LOG(FLUID_ERR, "Unexpected end of file"); + return FLUID_FAILED; + } + + if(c & 0x80) + { + mf->varlen |= (int)(c & 0x7F); + mf->varlen <<= 7; + } + else + { + mf->varlen += c; + break; + } + } + + return FLUID_OK; +} + +/* + * fluid_midi_file_read_event + */ +int +fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track) +{ + int status; + int type; + int tempo; + unsigned char *metadata = NULL; + unsigned char *dyn_buf = NULL; + unsigned char static_buf[256]; + int nominator, denominator, clocks, notes; + fluid_midi_event_t *evt; + int channel = 0; + int param1 = 0; + int param2 = 0; + int size; + + /* read the delta-time of the event */ + if(fluid_midi_file_read_varlen(mf) != FLUID_OK) + { + return FLUID_FAILED; + } + + mf->dtime += mf->varlen; + + /* read the status byte */ + status = fluid_midi_file_getc(mf); + + if(status < 0) + { + FLUID_LOG(FLUID_ERR, "Unexpected end of file"); + return FLUID_FAILED; + } + + /* not a valid status byte: use the running status instead */ + if((status & 0x80) == 0) + { + if((mf->running_status & 0x80) == 0) + { + FLUID_LOG(FLUID_ERR, "Undefined status and invalid running status"); + return FLUID_FAILED; + } + + fluid_midi_file_push(mf, status); + status = mf->running_status; + } + + /* check what message we have */ + + mf->running_status = status; + + if(status == MIDI_SYSEX) /* system exclusif */ + { + /* read the length of the message */ + if(fluid_midi_file_read_varlen(mf) != FLUID_OK) + { + return FLUID_FAILED; + } + + if(mf->varlen) + { + FLUID_LOG(FLUID_DBG, "%s: %d: alloc metadata, len = %d", __FILE__, + __LINE__, mf->varlen); + metadata = FLUID_MALLOC(mf->varlen + 1); + + if(metadata == NULL) + { + FLUID_LOG(FLUID_PANIC, "Out of memory"); + return FLUID_FAILED; + } + + /* read the data of the message */ + if(fluid_midi_file_read(mf, metadata, mf->varlen) != FLUID_OK) + { + FLUID_FREE(metadata); + return FLUID_FAILED; + } + + evt = new_fluid_midi_event(); + + if(evt == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + FLUID_FREE(metadata); + return FLUID_FAILED; + } + + evt->dtime = mf->dtime; + size = mf->varlen; + + if(metadata[mf->varlen - 1] == MIDI_EOX) + { + size--; + } + + /* Add SYSEX event and indicate that its dynamically allocated and should be freed with event */ + fluid_midi_event_set_sysex(evt, metadata, size, TRUE); + fluid_track_add_event(track, evt); + mf->dtime = 0; + } + + return FLUID_OK; + + } + else if(status == MIDI_META_EVENT) /* meta events */ + { + + int result = FLUID_OK; + + /* get the type of the meta message */ + type = fluid_midi_file_getc(mf); + + if(type < 0) + { + FLUID_LOG(FLUID_ERR, "Unexpected end of file"); + return FLUID_FAILED; + } + + /* get the length of the data part */ + if(fluid_midi_file_read_varlen(mf) != FLUID_OK) + { + return FLUID_FAILED; + } + + if(mf->varlen < 255) + { + metadata = &static_buf[0]; + } + else + { + FLUID_LOG(FLUID_DBG, "%s: %d: alloc metadata, len = %d", __FILE__, + __LINE__, mf->varlen); + dyn_buf = FLUID_MALLOC(mf->varlen + 1); + + if(dyn_buf == NULL) + { + FLUID_LOG(FLUID_PANIC, "Out of memory"); + return FLUID_FAILED; + } + + metadata = dyn_buf; + } + + /* read the data */ + if(mf->varlen) + { + if(fluid_midi_file_read(mf, metadata, mf->varlen) != FLUID_OK) + { + if(dyn_buf) + { + FLUID_FREE(dyn_buf); + } + + return FLUID_FAILED; + } + } + + /* handle meta data */ + switch(type) + { + + case MIDI_COPYRIGHT: + metadata[mf->varlen] = 0; + break; + + case MIDI_TRACK_NAME: + metadata[mf->varlen] = 0; + fluid_track_set_name(track, (char *) metadata); + break; + + case MIDI_INST_NAME: + metadata[mf->varlen] = 0; + break; + + case MIDI_LYRIC: + case MIDI_TEXT: + { + void *tmp; + int size = mf->varlen + 1; + + /* NULL terminate strings for safety */ + metadata[size - 1] = '\0'; + + evt = new_fluid_midi_event(); + + if(evt == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + result = FLUID_FAILED; + break; + } + + evt->dtime = mf->dtime; + + tmp = FLUID_MALLOC(size); + + if(tmp == NULL) + { + FLUID_LOG(FLUID_PANIC, "Out of memory"); + delete_fluid_midi_event(evt); + evt = NULL; + result = FLUID_FAILED; + break; + } + + FLUID_MEMCPY(tmp, metadata, size); + + fluid_midi_event_set_sysex_LOCAL(evt, type, tmp, size, TRUE); + fluid_track_add_event(track, evt); + mf->dtime = 0; + } + break; + + case MIDI_MARKER: + break; + + case MIDI_CUE_POINT: + break; /* don't care much for text events */ + + case MIDI_EOT: + if(mf->varlen != 0) + { + FLUID_LOG(FLUID_ERR, "Invalid length for EndOfTrack event"); + result = FLUID_FAILED; + break; + } + + mf->eot = 1; + evt = new_fluid_midi_event(); + + if(evt == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + result = FLUID_FAILED; + break; + } + + evt->dtime = mf->dtime; + evt->type = MIDI_EOT; + fluid_track_add_event(track, evt); + mf->dtime = 0; + break; + + case MIDI_SET_TEMPO: + if(mf->varlen != 3) + { + FLUID_LOG(FLUID_ERR, + "Invalid length for SetTempo meta event"); + result = FLUID_FAILED; + break; + } + + tempo = (metadata[0] << 16) + (metadata[1] << 8) + metadata[2]; + evt = new_fluid_midi_event(); + + if(evt == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + result = FLUID_FAILED; + break; + } + + evt->dtime = mf->dtime; + evt->type = MIDI_SET_TEMPO; + evt->channel = 0; + evt->param1 = tempo; + evt->param2 = 0; + fluid_track_add_event(track, evt); + mf->dtime = 0; + break; + + case MIDI_SMPTE_OFFSET: + if(mf->varlen != 5) + { + FLUID_LOG(FLUID_ERR, + "Invalid length for SMPTE Offset meta event"); + result = FLUID_FAILED; + break; + } + + break; /* we don't use smtp */ + + case MIDI_TIME_SIGNATURE: + if(mf->varlen != 4) + { + FLUID_LOG(FLUID_ERR, + "Invalid length for TimeSignature meta event"); + result = FLUID_FAILED; + break; + } + + nominator = metadata[0]; + denominator = pow(2.0, (double) metadata[1]); + clocks = metadata[2]; + notes = metadata[3]; + + FLUID_LOG(FLUID_DBG, + "signature=%d/%d, metronome=%d, 32nd-notes=%d", + nominator, denominator, clocks, notes); + + break; + + case MIDI_KEY_SIGNATURE: + if(mf->varlen != 2) + { + FLUID_LOG(FLUID_ERR, + "Invalid length for KeySignature meta event"); + result = FLUID_FAILED; + break; + } + + /* We don't care about key signatures anyway */ + /* sf = metadata[0]; + mi = metadata[1]; */ + break; + + case MIDI_SEQUENCER_EVENT: + break; + + default: + break; + } + + if(dyn_buf) + { + FLUID_LOG(FLUID_DBG, "%s: %d: free metadata", __FILE__, __LINE__); + FLUID_FREE(dyn_buf); + } + + return result; + + } + else /* channel messages */ + { + + type = status & 0xf0; + channel = status & 0x0f; + + /* all channel message have at least 1 byte of associated data */ + if((param1 = fluid_midi_file_getc(mf)) < 0) + { + FLUID_LOG(FLUID_ERR, "Unexpected end of file"); + return FLUID_FAILED; + } + + switch(type) + { + + case NOTE_ON: + if((param2 = fluid_midi_file_getc(mf)) < 0) + { + FLUID_LOG(FLUID_ERR, "Unexpected end of file"); + return FLUID_FAILED; + } + + break; + + case NOTE_OFF: + if((param2 = fluid_midi_file_getc(mf)) < 0) + { + FLUID_LOG(FLUID_ERR, "Unexpected end of file"); + return FLUID_FAILED; + } + + break; + + case KEY_PRESSURE: + if((param2 = fluid_midi_file_getc(mf)) < 0) + { + FLUID_LOG(FLUID_ERR, "Unexpected end of file"); + return FLUID_FAILED; + } + + break; + + case CONTROL_CHANGE: + if((param2 = fluid_midi_file_getc(mf)) < 0) + { + FLUID_LOG(FLUID_ERR, "Unexpected end of file"); + return FLUID_FAILED; + } + + break; + + case PROGRAM_CHANGE: + break; + + case CHANNEL_PRESSURE: + break; + + case PITCH_BEND: + if((param2 = fluid_midi_file_getc(mf)) < 0) + { + FLUID_LOG(FLUID_ERR, "Unexpected end of file"); + return FLUID_FAILED; + } + + param1 = ((param2 & 0x7f) << 7) | (param1 & 0x7f); + param2 = 0; + break; + + default: + /* Can't possibly happen !? */ + FLUID_LOG(FLUID_ERR, "Unrecognized MIDI event"); + return FLUID_FAILED; + } + + evt = new_fluid_midi_event(); + + if(evt == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FLUID_FAILED; + } + + evt->dtime = mf->dtime; + evt->type = type; + evt->channel = channel; + evt->param1 = param1; + evt->param2 = param2; + fluid_track_add_event(track, evt); + mf->dtime = 0; + } + + return FLUID_OK; +} + +/* + * fluid_midi_file_get_division + */ +int +fluid_midi_file_get_division(fluid_midi_file *midifile) +{ + return midifile->division; +} + +/****************************************************** + * + * fluid_track_t + */ + +/** + * Create a MIDI event structure. + * @return New MIDI event structure or NULL when out of memory. + */ +fluid_midi_event_t * +new_fluid_midi_event() +{ + fluid_midi_event_t *evt; + evt = FLUID_NEW(fluid_midi_event_t); + + if(evt == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + evt->dtime = 0; + evt->type = 0; + evt->channel = 0; + evt->param1 = 0; + evt->param2 = 0; + evt->next = NULL; + evt->paramptr = NULL; + return evt; +} + +/** + * Delete MIDI event structure. + * @param evt MIDI event structure + */ +void +delete_fluid_midi_event(fluid_midi_event_t *evt) +{ + fluid_midi_event_t *temp; + fluid_return_if_fail(evt != NULL); + + while(evt) + { + temp = evt->next; + + /* Dynamic SYSEX event? - free (param2 indicates if dynamic) */ + if((evt->type == MIDI_SYSEX || (evt-> type == MIDI_TEXT) || (evt->type == MIDI_LYRIC)) && + evt->paramptr && evt->param2) + { + FLUID_FREE(evt->paramptr); + } + + FLUID_FREE(evt); + evt = temp; + } +} + +/** + * Get the event type field of a MIDI event structure. + * @param evt MIDI event structure + * @return Event type field (MIDI status byte without channel) + */ +int +fluid_midi_event_get_type(const fluid_midi_event_t *evt) +{ + return evt->type; +} + +/** + * Set the event type field of a MIDI event structure. + * @param evt MIDI event structure + * @param type Event type field (MIDI status byte without channel) + * @return Always returns #FLUID_OK + */ +int +fluid_midi_event_set_type(fluid_midi_event_t *evt, int type) +{ + evt->type = type; + return FLUID_OK; +} + +/** + * Get the channel field of a MIDI event structure. + * @param evt MIDI event structure + * @return Channel field + */ +int +fluid_midi_event_get_channel(const fluid_midi_event_t *evt) +{ + return evt->channel; +} + +/** + * Set the channel field of a MIDI event structure. + * @param evt MIDI event structure + * @param chan MIDI channel field + * @return Always returns #FLUID_OK + */ +int +fluid_midi_event_set_channel(fluid_midi_event_t *evt, int chan) +{ + evt->channel = chan; + return FLUID_OK; +} + +/** + * Get the key field of a MIDI event structure. + * @param evt MIDI event structure + * @return MIDI note number (0-127) + */ +int +fluid_midi_event_get_key(const fluid_midi_event_t *evt) +{ + return evt->param1; +} + +/** + * Set the key field of a MIDI event structure. + * @param evt MIDI event structure + * @param v MIDI note number (0-127) + * @return Always returns #FLUID_OK + */ +int +fluid_midi_event_set_key(fluid_midi_event_t *evt, int v) +{ + evt->param1 = v; + return FLUID_OK; +} + +/** + * Get the velocity field of a MIDI event structure. + * @param evt MIDI event structure + * @return MIDI velocity number (0-127) + */ +int +fluid_midi_event_get_velocity(const fluid_midi_event_t *evt) +{ + return evt->param2; +} + +/** + * Set the velocity field of a MIDI event structure. + * @param evt MIDI event structure + * @param v MIDI velocity value + * @return Always returns #FLUID_OK + */ +int +fluid_midi_event_set_velocity(fluid_midi_event_t *evt, int v) +{ + evt->param2 = v; + return FLUID_OK; +} + +/** + * Get the control number of a MIDI event structure. + * @param evt MIDI event structure + * @return MIDI control number + */ +int +fluid_midi_event_get_control(const fluid_midi_event_t *evt) +{ + return evt->param1; +} + +/** + * Set the control field of a MIDI event structure. + * @param evt MIDI event structure + * @param v MIDI control number + * @return Always returns #FLUID_OK + */ +int +fluid_midi_event_set_control(fluid_midi_event_t *evt, int v) +{ + evt->param1 = v; + return FLUID_OK; +} + +/** + * Get the value field from a MIDI event structure. + * @param evt MIDI event structure + * @return Value field + */ +int +fluid_midi_event_get_value(const fluid_midi_event_t *evt) +{ + return evt->param2; +} + +/** + * Set the value field of a MIDI event structure. + * @param evt MIDI event structure + * @param v Value to assign + * @return Always returns #FLUID_OK + */ +int +fluid_midi_event_set_value(fluid_midi_event_t *evt, int v) +{ + evt->param2 = v; + return FLUID_OK; +} + +/** + * Get the program field of a MIDI event structure. + * @param evt MIDI event structure + * @return MIDI program number (0-127) + */ +int +fluid_midi_event_get_program(const fluid_midi_event_t *evt) +{ + return evt->param1; +} + +/** + * Set the program field of a MIDI event structure. + * @param evt MIDI event structure + * @param val MIDI program number (0-127) + * @return Always returns #FLUID_OK + */ +int +fluid_midi_event_set_program(fluid_midi_event_t *evt, int val) +{ + evt->param1 = val; + return FLUID_OK; +} + +/** + * Get the pitch field of a MIDI event structure. + * @param evt MIDI event structure + * @return Pitch value (14 bit value, 0-16383, 8192 is center) + */ +int +fluid_midi_event_get_pitch(const fluid_midi_event_t *evt) +{ + return evt->param1; +} + +/** + * Set the pitch field of a MIDI event structure. + * @param evt MIDI event structure + * @param val Pitch value (14 bit value, 0-16383, 8192 is center) + * @return Always returns FLUID_OK + */ +int +fluid_midi_event_set_pitch(fluid_midi_event_t *evt, int val) +{ + evt->param1 = val; + return FLUID_OK; +} + +/** + * Assign sysex data to a MIDI event structure. + * @param evt MIDI event structure + * @param data Pointer to SYSEX data + * @param size Size of SYSEX data in bytes + * @param dynamic TRUE if the SYSEX data has been dynamically allocated and + * should be freed when the event is freed (only applies if event gets destroyed + * with delete_fluid_midi_event()) + * @return Always returns #FLUID_OK + */ +int +fluid_midi_event_set_sysex(fluid_midi_event_t *evt, void *data, int size, int dynamic) +{ + fluid_midi_event_set_sysex_LOCAL(evt, MIDI_SYSEX, data, size, dynamic); + return FLUID_OK; +} + +/** + * Assign text data to a MIDI event structure. + * @param evt MIDI event structure + * @param data Pointer to text data + * @param size Size of text data in bytes + * @param dynamic TRUE if the data has been dynamically allocated and + * should be freed when the event is freed via delete_fluid_midi_event() + * @return Always returns #FLUID_OK + * + * @since 2.0.0 + */ +int +fluid_midi_event_set_text(fluid_midi_event_t *evt, void *data, int size, int dynamic) +{ + fluid_midi_event_set_sysex_LOCAL(evt, MIDI_TEXT, data, size, dynamic); + return FLUID_OK; +} + +/** + * Get the text of a MIDI event structure. + * @param evt MIDI event structure + * @param data Pointer to return text data on. + * @param size Pointer to return text size on. + * @return Returns #FLUID_OK if \p data and \p size previously set by + * fluid_midi_event_set_text() have been successfully retrieved. + * Else #FLUID_FAILED is returned and \p data and \p size are not changed. + * @since 2.0.3 + */ +int fluid_midi_event_get_text(fluid_midi_event_t *evt, void **data, int *size) +{ + fluid_return_val_if_fail(evt != NULL, FLUID_FAILED); + fluid_return_val_if_fail(evt->type == MIDI_TEXT, FLUID_FAILED); + + fluid_midi_event_get_sysex_LOCAL(evt, data, size); + return FLUID_OK; +} + +/** + * Assign lyric data to a MIDI event structure. + * @param evt MIDI event structure + * @param data Pointer to lyric data + * @param size Size of lyric data in bytes + * @param dynamic TRUE if the data has been dynamically allocated and + * should be freed when the event is freed via delete_fluid_midi_event() + * @return Always returns #FLUID_OK + * + * @since 2.0.0 + */ +int +fluid_midi_event_set_lyrics(fluid_midi_event_t *evt, void *data, int size, int dynamic) +{ + fluid_midi_event_set_sysex_LOCAL(evt, MIDI_LYRIC, data, size, dynamic); + return FLUID_OK; +} + +/** + * Get the lyric of a MIDI event structure. + * @param evt MIDI event structure + * @param data Pointer to return lyric data on. + * @param size Pointer to return lyric size on. + * @return Returns #FLUID_OK if \p data and \p size previously set by + * fluid_midi_event_set_lyrics() have been successfully retrieved. + * Else #FLUID_FAILED is returned and \p data and \p size are not changed. + * @since 2.0.3 + */ +int fluid_midi_event_get_lyrics(fluid_midi_event_t *evt, void **data, int *size) +{ + fluid_return_val_if_fail(evt != NULL, FLUID_FAILED); + fluid_return_val_if_fail(evt->type == MIDI_LYRIC, FLUID_FAILED); + + fluid_midi_event_get_sysex_LOCAL(evt, data, size); + return FLUID_OK; +} + +static void fluid_midi_event_set_sysex_LOCAL(fluid_midi_event_t *evt, int type, void *data, int size, int dynamic) +{ + evt->type = type; + evt->paramptr = data; + evt->param1 = size; + evt->param2 = dynamic; +} + +static void fluid_midi_event_get_sysex_LOCAL(fluid_midi_event_t *evt, void **data, int *size) +{ + if(data) + { + *data = evt->paramptr; + } + + if(size) + { + *size = evt->param1; + } +} + +/****************************************************** + * + * fluid_track_t + */ + +/* + * new_fluid_track + */ +fluid_track_t * +new_fluid_track(int num) +{ + fluid_track_t *track; + track = FLUID_NEW(fluid_track_t); + + if(track == NULL) + { + return NULL; + } + + track->name = NULL; + track->num = num; + track->first = NULL; + track->cur = NULL; + track->last = NULL; + track->ticks = 0; + return track; +} + +/* + * delete_fluid_track + */ +void +delete_fluid_track(fluid_track_t *track) +{ + fluid_return_if_fail(track != NULL); + + FLUID_FREE(track->name); + delete_fluid_midi_event(track->first); + FLUID_FREE(track); +} + +/* + * fluid_track_set_name + */ +int +fluid_track_set_name(fluid_track_t *track, char *name) +{ + size_t len; + + if(track->name != NULL) + { + FLUID_FREE(track->name); + } + + if(name == NULL) + { + track->name = NULL; + return FLUID_OK; + } + + len = FLUID_STRLEN(name); + track->name = FLUID_MALLOC(len + 1); + + if(track->name == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FLUID_FAILED; + } + + FLUID_STRCPY(track->name, name); + return FLUID_OK; +} + +/* + * fluid_track_get_duration + */ +int +fluid_track_get_duration(fluid_track_t *track) +{ + int time = 0; + fluid_midi_event_t *evt = track->first; + + while(evt != NULL) + { + time += evt->dtime; + evt = evt->next; + } + + return time; +} + +/* + * fluid_track_add_event + */ +int +fluid_track_add_event(fluid_track_t *track, fluid_midi_event_t *evt) +{ + evt->next = NULL; + + if(track->first == NULL) + { + track->first = evt; + track->cur = evt; + track->last = evt; + } + else + { + track->last->next = evt; + track->last = evt; + } + + return FLUID_OK; +} + +/* + * fluid_track_next_event + */ +fluid_midi_event_t * +fluid_track_next_event(fluid_track_t *track) +{ + if(track->cur != NULL) + { + track->cur = track->cur->next; + } + + return track->cur; +} + +/* + * fluid_track_reset + */ +int +fluid_track_reset(fluid_track_t *track) +{ + track->ticks = 0; + track->cur = track->first; + return FLUID_OK; +} + +/* + * fluid_track_send_events + */ +static void +fluid_track_send_events(fluid_track_t *track, + fluid_synth_t *synth, + fluid_player_t *player, + unsigned int ticks, + int seek_ticks + ) +{ + fluid_midi_event_t *event; + int seeking = seek_ticks >= 0; + + if(seeking) + { + ticks = seek_ticks; /* update target ticks */ + + if(track->ticks > ticks) + { + fluid_track_reset(track); /* reset track if seeking backwards */ + } + } + + while(1) + { + + event = track->cur; + + if(event == NULL) + { + return; + } + + /* printf("track=%02d\tticks=%05u\ttrack=%05u\tdtime=%05u\tnext=%05u\n", */ + /* track->num, */ + /* ticks, */ + /* track->ticks, */ + /* event->dtime, */ + /* track->ticks + event->dtime); */ + + if(track->ticks + event->dtime > ticks) + { + return; + } + + track->ticks += event->dtime; + + if(!player || event->type == MIDI_EOT) + { + /* don't send EOT events to the callback */ + } + else if(seeking && track->ticks != ticks && (event->type == NOTE_ON || event->type == NOTE_OFF)) + { + /* skip on/off messages */ + } + else + { + if(player->playback_callback) + { + player->playback_callback(player->playback_userdata, event); + if(event->type == NOTE_ON && event->param2 != 0 && !player->channel_isplaying[event->channel]) + { + player->channel_isplaying[event->channel] = TRUE; + } + } + } + + if(event->type == MIDI_SET_TEMPO && player != NULL) + { + /* memorize the tempo change value coming from the MIDI file */ + fluid_atomic_int_set(&player->miditempo, event->param1); + fluid_player_update_tempo(player); + } + + fluid_track_next_event(track); + + } +} + +/****************************************************** + * + * fluid_player + */ +static void +fluid_player_handle_reset_synth(void *data, const char *name, int value) +{ + fluid_player_t *player = data; + fluid_return_if_fail(player != NULL); + + player->reset_synth_between_songs = value; +} + +/** + * Create a new MIDI player. + * @param synth Fluid synthesizer instance to create player for + * @return New MIDI player instance or NULL on error (out of memory) + */ +fluid_player_t * +new_fluid_player(fluid_synth_t *synth) +{ + int i; + fluid_player_t *player; + player = FLUID_NEW(fluid_player_t); + + if(player == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + fluid_atomic_int_set(&player->status, FLUID_PLAYER_READY); + fluid_atomic_int_set(&player->stopping, 0); + player->loop = 1; + player->ntracks = 0; + + for(i = 0; i < MAX_NUMBER_OF_TRACKS; i++) + { + player->track[i] = NULL; + } + + player->synth = synth; + player->system_timer = NULL; + player->sample_timer = NULL; + player->playlist = NULL; + player->currentfile = NULL; + player->division = 0; + + /* internal tempo (from MIDI file) in micro seconds per quarter note */ + player->sync_mode = 1; /* the player follows internal tempo change */ + player->miditempo = 500000; + /* external tempo in micro seconds per quarter note */ + player->exttempo = 500000; + /* tempo multiplier */ + player->multempo = 1.0F; + + player->deltatime = 4.0; + player->cur_msec = 0; + player->cur_ticks = 0; + player->end_msec = -1; + player->end_pedals_disabled = 0; + player->last_callback_ticks = -1; + fluid_atomic_int_set(&player->seek_ticks, -1); + fluid_player_set_playback_callback(player, fluid_synth_handle_midi_event, synth); + fluid_player_set_tick_callback(player, NULL, NULL); + player->use_system_timer = fluid_settings_str_equal(synth->settings, + "player.timing-source", "system"); + if(player->use_system_timer) + { + player->system_timer = new_fluid_timer((int) player->deltatime, + fluid_player_callback, player, TRUE, FALSE, TRUE); + + if(player->system_timer == NULL) + { + goto err; + } + } + else + { + player->sample_timer = new_fluid_sample_timer(player->synth, + fluid_player_callback, player); + + if(player->sample_timer == NULL) + { + goto err; + } + } + + fluid_settings_getint(synth->settings, "player.reset-synth", &i); + fluid_player_handle_reset_synth(player, NULL, i); + + fluid_settings_callback_int(synth->settings, "player.reset-synth", + fluid_player_handle_reset_synth, player); + + return player; + +err: + delete_fluid_player(player); + return NULL; +} + +/** + * Delete a MIDI player instance. + * @param player MIDI player instance + * @warning Do not call when the synthesizer associated to this \p player renders audio, + * i.e. an audio driver is running or any other synthesizer thread concurrently calls + * fluid_synth_process() or fluid_synth_nwrite_float() or fluid_synth_write_*() ! + */ +void +delete_fluid_player(fluid_player_t *player) +{ + fluid_list_t *q; + fluid_playlist_item *pi; + + fluid_return_if_fail(player != NULL); + + fluid_settings_callback_int(player->synth->settings, "player.reset-synth", + NULL, NULL); + + fluid_player_stop(player); + fluid_player_reset(player); + + delete_fluid_timer(player->system_timer); + delete_fluid_sample_timer(player->synth, player->sample_timer); + + while(player->playlist != NULL) + { + q = player->playlist->next; + pi = (fluid_playlist_item *) player->playlist->data; + FLUID_FREE(pi->filename); + FLUID_FREE(pi->buffer); + FLUID_FREE(pi); + delete1_fluid_list(player->playlist); + player->playlist = q; + } + + FLUID_FREE(player); +} + +/** + * Registers settings related to the MIDI player + */ +void +fluid_player_settings(fluid_settings_t *settings) +{ + /* player.timing-source can be either "system" (use system timer) + or "sample" (use timer based on number of written samples) */ + fluid_settings_register_str(settings, "player.timing-source", "sample", 0); + fluid_settings_add_option(settings, "player.timing-source", "sample"); + fluid_settings_add_option(settings, "player.timing-source", "system"); + + /* Selects whether the player should reset the synth between songs, or not. */ + fluid_settings_register_int(settings, "player.reset-synth", 1, 0, 1, FLUID_HINT_TOGGLED); +} + + +int +fluid_player_reset(fluid_player_t *player) +{ + int i; + + for(i = 0; i < MAX_NUMBER_OF_TRACKS; i++) + { + if(player->track[i] != NULL) + { + delete_fluid_track(player->track[i]); + player->track[i] = NULL; + } + } + + for(i = 0; i < MAX_NUMBER_OF_CHANNELS; i++) + { + player->channel_isplaying[i] = FALSE; + } + + /* player->current_file = NULL; */ + /* player->status = FLUID_PLAYER_READY; */ + /* player->loop = 1; */ + player->ntracks = 0; + player->division = 0; + player->miditempo = 500000; + player->deltatime = 4.0; + return 0; +} + +/* + * fluid_player_add_track + */ +int +fluid_player_add_track(fluid_player_t *player, fluid_track_t *track) +{ + if(player->ntracks < MAX_NUMBER_OF_TRACKS) + { + player->track[player->ntracks++] = track; + return FLUID_OK; + } + else + { + return FLUID_FAILED; + } +} + +/** + * Change the MIDI callback function. + * + * @param player MIDI player instance + * @param handler Pointer to callback function + * @param handler_data Parameter sent to the callback function + * @returns FLUID_OK + * + * This is usually set to fluid_synth_handle_midi_event(), but can optionally + * be changed to a user-defined function instead, for intercepting all MIDI + * messages sent to the synth. You can also use a midi router as the callback + * function to modify the MIDI messages before sending them to the synth. + * + * @since 1.1.4 + */ +int +fluid_player_set_playback_callback(fluid_player_t *player, + handle_midi_event_func_t handler, void *handler_data) +{ + player->playback_callback = handler; + player->playback_userdata = handler_data; + return FLUID_OK; +} + +/** + * Add a listener function for every MIDI tick change. + * + * @param player MIDI player instance + * @param handler Pointer to callback function + * @param handler_data Opaque parameter to be sent to the callback function + * @returns #FLUID_OK + * + * This callback is not set by default, but can optionally + * be changed to a user-defined function for intercepting all MIDI + * tick changes and react to them with precision. + * + * @since 2.2.0 + */ +int +fluid_player_set_tick_callback(fluid_player_t *player, handle_midi_tick_func_t handler, void *handler_data) +{ + player->tick_callback = handler; + player->tick_userdata = handler_data; + return FLUID_OK; +} + +/** + * Add a MIDI file to a player queue. + * @param player MIDI player instance + * @param midifile File name of the MIDI file to add + * @return #FLUID_OK or #FLUID_FAILED + */ +int +fluid_player_add(fluid_player_t *player, const char *midifile) +{ + fluid_playlist_item *pi = FLUID_MALLOC(sizeof(fluid_playlist_item)); + char *f = FLUID_STRDUP(midifile); + + if(!pi || !f) + { + FLUID_FREE(pi); + FLUID_FREE(f); + FLUID_LOG(FLUID_PANIC, "Out of memory"); + return FLUID_FAILED; + } + + pi->filename = f; + pi->buffer = NULL; + pi->buffer_len = 0; + player->playlist = fluid_list_append(player->playlist, pi); + return FLUID_OK; +} + +/** + * Add a MIDI file to a player queue, from a buffer in memory. + * @param player MIDI player instance + * @param buffer Pointer to memory containing the bytes of a complete MIDI + * file. The data is copied, so the caller may free or modify it immediately + * without affecting the playlist. + * @param len Length of the buffer, in bytes. + * @return #FLUID_OK or #FLUID_FAILED + */ +int +fluid_player_add_mem(fluid_player_t *player, const void *buffer, size_t len) +{ + /* Take a copy of the buffer, so the caller can free immediately. */ + fluid_playlist_item *pi = FLUID_MALLOC(sizeof(fluid_playlist_item)); + void *buf_copy = FLUID_MALLOC(len); + + if(!pi || !buf_copy) + { + FLUID_FREE(pi); + FLUID_FREE(buf_copy); + FLUID_LOG(FLUID_PANIC, "Out of memory"); + return FLUID_FAILED; + } + + FLUID_MEMCPY(buf_copy, buffer, len); + pi->filename = NULL; + pi->buffer = buf_copy; + pi->buffer_len = len; + player->playlist = fluid_list_append(player->playlist, pi); + return FLUID_OK; +} + +/* + * fluid_player_load + */ +int +fluid_player_load(fluid_player_t *player, fluid_playlist_item *item) +{ + fluid_midi_file *midifile; + char *buffer; + size_t buffer_length; + int buffer_owned; + + if(item->filename != NULL) + { + fluid_file fp; + /* This file is specified by filename; load the file from disk */ + FLUID_LOG(FLUID_DBG, "%s: %d: Loading midifile %s", __FILE__, __LINE__, + item->filename); + /* Read the entire contents of the file into the buffer */ + fp = FLUID_FOPEN(item->filename, "rb"); + + if(fp == NULL) + { + FLUID_LOG(FLUID_ERR, "Couldn't open the MIDI file"); + return FLUID_FAILED; + } + + buffer = fluid_file_read_full(fp, &buffer_length); + + FLUID_FCLOSE(fp); + + if(buffer == NULL) + { + return FLUID_FAILED; + } + + buffer_owned = 1; + } + else + { + /* This file is specified by a pre-loaded buffer; load from memory */ + FLUID_LOG(FLUID_DBG, "%s: %d: Loading midifile from memory (%p)", + __FILE__, __LINE__, item->buffer); + buffer = (char *) item->buffer; + buffer_length = item->buffer_len; + /* Do not free the buffer (it is owned by the playlist) */ + buffer_owned = 0; + } + + midifile = new_fluid_midi_file(buffer, buffer_length); + + if(midifile == NULL) + { + if(buffer_owned) + { + FLUID_FREE(buffer); + } + + return FLUID_FAILED; + } + + player->division = fluid_midi_file_get_division(midifile); + fluid_player_update_tempo(player); // Update deltatime + /*FLUID_LOG(FLUID_DBG, "quarter note division=%d\n", player->division); */ + + if(fluid_midi_file_load_tracks(midifile, player) != FLUID_OK) + { + if(buffer_owned) + { + FLUID_FREE(buffer); + } + + delete_fluid_midi_file(midifile); + return FLUID_FAILED; + } + + delete_fluid_midi_file(midifile); + + if(buffer_owned) + { + FLUID_FREE(buffer); + } + + return FLUID_OK; +} + +void +fluid_player_advancefile(fluid_player_t *player) +{ + if(player->playlist == NULL) + { + return; /* No files to play */ + } + + if(player->currentfile != NULL) + { + player->currentfile = fluid_list_next(player->currentfile); + } + + if(player->currentfile == NULL) + { + if(player->loop == 0) + { + return; /* We're done playing */ + } + + if(player->loop > 0) + { + player->loop--; + } + + player->currentfile = player->playlist; + } +} + +void +fluid_player_playlist_load(fluid_player_t *player, unsigned int msec) +{ + fluid_playlist_item *current_playitem; + int i; + + do + { + fluid_player_advancefile(player); + + if(player->currentfile == NULL) + { + /* Failed to find next song, probably since we're finished */ + fluid_atomic_int_set(&player->status, FLUID_PLAYER_DONE); + return; + } + + fluid_player_reset(player); + current_playitem = (fluid_playlist_item *) player->currentfile->data; + } + while(fluid_player_load(player, current_playitem) != FLUID_OK); + + /* Successfully loaded midi file */ + + player->begin_msec = msec; + player->start_msec = msec; + player->start_ticks = 0; + player->cur_ticks = 0; + + for(i = 0; i < player->ntracks; i++) + { + if(player->track[i] != NULL) + { + fluid_track_reset(player->track[i]); + } + } +} + +/* + * fluid_player_callback + */ +int +fluid_player_callback(void *data, unsigned int msec) +{ + int i; + int loadnextfile; + int status = FLUID_PLAYER_DONE; + fluid_midi_event_t mute_event; + fluid_player_t *player; + fluid_synth_t *synth; + player = (fluid_player_t *) data; + synth = player->synth; + + loadnextfile = player->currentfile == NULL ? 1 : 0; + + fluid_midi_event_set_type(&mute_event, CONTROL_CHANGE); + mute_event.param1 = ALL_SOUND_OFF; + mute_event.param2 = 1; + + if(fluid_player_get_status(player) != FLUID_PLAYER_PLAYING) + { + if(fluid_atomic_int_get(&player->stopping)) + { + for(i = 0; i < synth->midi_channels; i++) + { + if(player->channel_isplaying[i]) + { + fluid_midi_event_set_channel(&mute_event, i); + player->playback_callback(player->playback_userdata, &mute_event); + player->channel_isplaying[i] = FALSE; + } + } + fluid_atomic_int_set(&player->stopping, 0); + } + return 1; + } + do + { + float deltatime; + int seek_ticks; + + if(loadnextfile) + { + loadnextfile = 0; + fluid_player_playlist_load(player, msec); + + if(player->currentfile == NULL) + { + return 0; + } + } + + if(msec < player->cur_msec) + { + // overflow of fluid_synth_get_ticks() + FLUID_LOG(FLUID_ERR, "The maximum playback duration has been reached. Terminating player!"); + fluid_player_stop(player); + fluid_player_seek(player, 0); + player->cur_ticks = 0; + return 0; + } + + player->cur_msec = msec; + deltatime = fluid_atomic_float_get(&player->deltatime); + player->cur_ticks = (player->start_ticks + + (int)((double)(player->cur_msec - player->start_msec) + / deltatime + 0.5)); /* 0.5 to average overall error when casting */ + + seek_ticks = fluid_atomic_int_get(&player->seek_ticks); + if(seek_ticks >= 0) + { + for(i = 0; i < synth->midi_channels; i++) + { + if(player->channel_isplaying[i]) + { + fluid_midi_event_set_channel(&mute_event, i); + player->playback_callback(player->playback_userdata, &mute_event); + player->channel_isplaying[i] = FALSE; + } + } + } + + for(i = 0; i < player->ntracks; i++) + { + fluid_track_send_events(player->track[i], synth, player, player->cur_ticks, seek_ticks); + if(!fluid_track_eot(player->track[i])) + { + status = FLUID_PLAYER_PLAYING; + } + } + + if(seek_ticks >= 0) + { + player->start_ticks = seek_ticks; /* tick position of last tempo value (which is now) */ + player->cur_ticks = seek_ticks; + player->begin_msec = msec; /* only used to calculate the duration of playing */ + player->start_msec = msec; /* should be the (synth)-time of the last tempo change */ + fluid_atomic_int_set(&player->seek_ticks, -1); /* clear seek_ticks */ + } + + if(fluid_list_next(player->currentfile) == NULL && player->loop == 0) + { + /* Once we've run out of MIDI events, keep playing until no voices are active */ + if(status == FLUID_PLAYER_DONE && fluid_synth_get_active_voice_count(player->synth) > 0) + { + /* The first time we notice we've run out of MIDI events but there are still active voices, disable all hold pedals */ + if(!player->end_pedals_disabled) + { + for(i = 0; i < synth->midi_channels; i++) + { + fluid_synth_cc(player->synth, i, SUSTAIN_SWITCH, 0); + fluid_synth_cc(player->synth, i, SOSTENUTO_SWITCH, 0); + } + + player->end_pedals_disabled = 1; + } + + status = FLUID_PLAYER_PLAYING; + } + + /* Once no voices are active, if end_msec hasn't been scheduled, schedule it so we wait for reverb, etc to finish */ + if(status == FLUID_PLAYER_DONE && player->end_msec < 0) + { + player->end_msec = msec + FLUID_PLAYER_STOP_GRACE_MS; + } + /* If end_msec has been scheduled and is in the future, keep playing */ + if (player->end_msec >= 0 && msec < (unsigned int) player->end_msec) + { + status = FLUID_PLAYER_PLAYING; + } + } + + /* Once there's no reason to keep playing, we're actually done */ + if(status == FLUID_PLAYER_DONE) + { + FLUID_LOG(FLUID_DBG, "%s: %d: Duration=%.3f sec", __FILE__, + __LINE__, (msec - player->begin_msec) / 1000.0); + + if(player->reset_synth_between_songs) + { + fluid_synth_system_reset(player->synth); + } + + loadnextfile = 1; + } + + if (player->tick_callback != NULL && player->last_callback_ticks != player->cur_ticks) { + player->tick_callback(player->tick_userdata, player->cur_ticks); + player->last_callback_ticks = player->cur_ticks; + } + } + while(loadnextfile); + + /* do not update the status if the player has been stopped already */ + fluid_atomic_int_compare_and_exchange(&player->status, FLUID_PLAYER_PLAYING, status); + + return 1; +} + +/** + * Activates play mode for a MIDI player if not already playing. + * @param player MIDI player instance + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * + * If the list of files added to the player has completed its requested number of loops, + * the playlist will be restarted from the beginning with a loop count of 1. + */ +int +fluid_player_play(fluid_player_t *player) +{ + if(fluid_player_get_status(player) == FLUID_PLAYER_PLAYING || + player->playlist == NULL) + { + return FLUID_OK; + } + + if(!player->use_system_timer) + { + fluid_sample_timer_reset(player->synth, player->sample_timer); + } + + /* If we're at the end of the playlist and there are no loops left, loop once */ + if(player->currentfile == NULL && player->loop == 0) + { + player->loop = 1; + } + + player->end_msec = -1; + player->end_pedals_disabled = 0; + + fluid_atomic_int_set(&player->status, FLUID_PLAYER_PLAYING); + + return FLUID_OK; +} + +/** + * Pauses the MIDI playback. + * + * @param player MIDI player instance + * @return Always returns #FLUID_OK + * + * It will not rewind to the beginning of the file, use fluid_player_seek() for this purpose. + */ +int +fluid_player_stop(fluid_player_t *player) +{ + fluid_atomic_int_set(&player->status, FLUID_PLAYER_DONE); + fluid_atomic_int_set(&player->stopping, 1); + fluid_player_seek(player, fluid_player_get_current_tick(player)); + return FLUID_OK; +} + +/** + * Get MIDI player status. + * @param player MIDI player instance + * @return Player status (#fluid_player_status) + * @since 1.1.0 + */ +int +fluid_player_get_status(fluid_player_t *player) +{ + return fluid_atomic_int_get(&player->status); +} + +/** + * Seek in the currently playing file. + * + * @param player MIDI player instance + * @param ticks the position to seek to in the current file + * @return #FLUID_FAILED if ticks is negative or after the latest tick of the file + * [or, since 2.1.3, if another seek operation is currently in progress], + * #FLUID_OK otherwise. + * + * The actual seek will be performed when the synth calls back the player (i.e. a few + * levels above the player's callback set with fluid_player_set_playback_callback()). + * If the player's status is #FLUID_PLAYER_PLAYING and a previous seek operation has + * not been completed yet, #FLUID_FAILED is returned. + * + * @since 2.0.0 + */ +int fluid_player_seek(fluid_player_t *player, int ticks) +{ + if(ticks < 0 || (fluid_player_get_status(player) != FLUID_PLAYER_READY && ticks > fluid_player_get_total_ticks(player))) + { + return FLUID_FAILED; + } + + if(fluid_player_get_status(player) == FLUID_PLAYER_PLAYING) + { + if(fluid_atomic_int_compare_and_exchange(&player->seek_ticks, -1, ticks)) + { + // new seek position has been set, as no previous seek was in progress + return FLUID_OK; + } + } + else + { + // If the player is not currently playing, a new seek position can be set at any time. This allows + // the user to do: + // fluid_player_stop(); + // fluid_player_seek(0); // to beginning + fluid_atomic_int_set(&player->seek_ticks, ticks); + return FLUID_OK; + } + + // a previous seek is still in progress or hasn't been processed yet + return FLUID_FAILED; +} + + +/** + * Enable looping of a MIDI player + * + * @param player MIDI player instance + * @param loop Times left to loop the playlist. -1 means loop infinitely. + * @return Always returns #FLUID_OK + * + * For example, if you want to loop the playlist twice, set loop to 2 + * and call this function before you start the player. + * + * @since 1.1.0 + */ +int fluid_player_set_loop(fluid_player_t *player, int loop) +{ + player->loop = loop; + return FLUID_OK; +} + +/** + * update the MIDI player internal deltatime dependent of actual tempo. + * @param player MIDI player instance + */ +static void fluid_player_update_tempo(fluid_player_t *player) +{ + int tempo; /* tempo in micro seconds by quarter note */ + float deltatime; + + /* do nothing if the division is still unknown to avoid a div by zero */ + if(player->division == 0) + { + return; + } + + if(fluid_atomic_int_get(&player->sync_mode)) + { + /* take internal tempo from MIDI file */ + tempo = fluid_atomic_int_get(&player->miditempo); + /* compute deltattime (in ms) from current tempo and apply tempo multiplier */ + deltatime = (float)tempo / (float)player->division / (float)1000.0; + deltatime /= fluid_atomic_float_get(&player->multempo); /* multiply tempo */ + } + else + { + /* take external tempo */ + tempo = fluid_atomic_int_get(&player->exttempo); + /* compute deltattime (in ms) from current tempo */ + deltatime = (float)tempo / (float)player->division / (float)1000.0; + } + + fluid_atomic_float_set(&player->deltatime, deltatime); + + player->start_msec = player->cur_msec; + player->start_ticks = player->cur_ticks; + + FLUID_LOG(FLUID_DBG, + "tempo=%d, tick time=%f msec, cur time=%d msec, cur tick=%d", + tempo, player->deltatime, player->cur_msec, player->cur_ticks); + +} + +/** + * Set the tempo of a MIDI player. + * The player can be controlled by internal tempo coming from MIDI file tempo + * change or controlled by external tempo expressed in BPM or in micro seconds + * per quarter note. + * + * @param player MIDI player instance. Must be a valid pointer. + * @param tempo_type Must a be value of #fluid_player_set_tempo_type and indicates the + * meaning of tempo value and how the player will be controlled, see below. + * @param tempo Tempo value or multiplier. + * + * #FLUID_PLAYER_TEMPO_INTERNAL, the player will be controlled by internal + * MIDI file tempo changes. If there are no tempo change in the MIDI file a default + * value of 120 bpm is used. The @c tempo parameter is used as a multiplier factor + * that must be in the range (0.001 to 1000). + * For example, if the current MIDI file tempo is 120 bpm and the multiplier + * value is 0.5 then this tempo will be slowed down to 60 bpm. + * At creation, the player is set to be controlled by internal tempo with a + * multiplier factor set to 1.0. + * + * #FLUID_PLAYER_TEMPO_EXTERNAL_BPM, the player will be controlled by the + * external tempo value provided by the tempo parameter in bpm + * (i.e in quarter notes per minute) which must be in the range (1 to 60000000). + * + * #FLUID_PLAYER_TEMPO_EXTERNAL_MIDI, similar as FLUID_PLAYER_TEMPO_EXTERNAL_BPM, + * but the tempo parameter value is in micro seconds per quarter note which + * must be in the range (1 to 60000000). + * Using micro seconds per quarter note is convenient when the tempo value is + * derived from MIDI clock realtime messages. + * + * @note When the player is controlled by an external tempo + * (#FLUID_PLAYER_TEMPO_EXTERNAL_BPM or #FLUID_PLAYER_TEMPO_EXTERNAL_MIDI) it + * continues to memorize the most recent internal tempo change coming from the + * MIDI file so that next call to fluid_player_set_tempo() with + * #FLUID_PLAYER_TEMPO_INTERNAL will set the player to follow this internal + * tempo. + * + * @warning If the function is called when no MIDI file is loaded or currently playing, it + * would have caused a division by zero in fluidsynth 2.2.7 and earlier. Starting with 2.2.8, the + * new tempo change will be stashed and applied later. + * + * @return #FLUID_OK if success or #FLUID_FAILED otherwise (incorrect parameters). + * @since 2.2.0 + */ +int fluid_player_set_tempo(fluid_player_t *player, int tempo_type, double tempo) +{ + fluid_return_val_if_fail(player != NULL, FLUID_FAILED); + fluid_return_val_if_fail(tempo_type >= FLUID_PLAYER_TEMPO_INTERNAL, FLUID_FAILED); + fluid_return_val_if_fail(tempo_type < FLUID_PLAYER_TEMPO_NBR, FLUID_FAILED); + + switch(tempo_type) + { + /* set the player to be driven by internal tempo coming from MIDI file */ + case FLUID_PLAYER_TEMPO_INTERNAL: + /* check if the multiplier is in correct range */ + fluid_return_val_if_fail(tempo >= MIN_TEMPO_MULTIPLIER, FLUID_FAILED); + fluid_return_val_if_fail(tempo <= MAX_TEMPO_MULTIPLIER, FLUID_FAILED); + + /* set the tempo multiplier */ + fluid_atomic_float_set(&player->multempo, (float)tempo); + fluid_atomic_int_set(&player->sync_mode, 1); /* set internal mode */ + break; + + /* set the player to be driven by external tempo */ + case FLUID_PLAYER_TEMPO_EXTERNAL_BPM: /* value in bpm */ + case FLUID_PLAYER_TEMPO_EXTERNAL_MIDI: /* value in us/quarter note */ + /* check if tempo is in correct range */ + fluid_return_val_if_fail(tempo >= MIN_TEMPO_VALUE, FLUID_FAILED); + fluid_return_val_if_fail(tempo <= MAX_TEMPO_VALUE, FLUID_FAILED); + + /* set the tempo value */ + if(tempo_type == FLUID_PLAYER_TEMPO_EXTERNAL_BPM) + { + tempo = 60000000L / tempo; /* convert tempo in us/quarter note */ + } + fluid_atomic_int_set(&player->exttempo, (int)tempo); + fluid_atomic_int_set(&player->sync_mode, 0); /* set external mode */ + break; + + default: /* shouldn't happen */ + break; + } + + /* update deltatime depending of current tempo */ + fluid_player_update_tempo(player); + + return FLUID_OK; +} + +/** + * Set the tempo of a MIDI player. + * @param player MIDI player instance + * @param tempo Tempo to set playback speed to (in microseconds per quarter note, as per MIDI file spec) + * @return Always returns #FLUID_OK + * @note Tempo change events contained in the MIDI file can override the specified tempo at any time! + * @deprecated Use fluid_player_set_tempo() instead. + */ +int fluid_player_set_midi_tempo(fluid_player_t *player, int tempo) +{ + player->miditempo = tempo; + + fluid_player_update_tempo(player); + return FLUID_OK; +} + +/** + * Set the tempo of a MIDI player in beats per minute. + * @param player MIDI player instance + * @param bpm Tempo in beats per minute + * @return Always returns #FLUID_OK + * @note Tempo change events contained in the MIDI file can override the specified BPM at any time! + * @deprecated Use fluid_player_set_tempo() instead. + */ +int fluid_player_set_bpm(fluid_player_t *player, int bpm) +{ + if(bpm <= 0) + { + return FLUID_FAILED; /* to avoid a division by 0 */ + } + + return fluid_player_set_midi_tempo(player, 60000000L / bpm); +} + +/** + * Wait for a MIDI player until the playback has been stopped. + * @param player MIDI player instance + * @return Always #FLUID_OK + * + * @warning The player may still be used by a concurrently running synth context. Hence it is + * not safe to immediately delete the player afterwards. Also refer to delete_fluid_player(). + */ +int +fluid_player_join(fluid_player_t *player) +{ + while(fluid_player_get_status(player) != FLUID_PLAYER_DONE) + { + fluid_msleep(10); + } + return FLUID_OK; +} + +/** + * Get the number of tempo ticks passed. + * @param player MIDI player instance + * @return The number of tempo ticks passed + * @since 1.1.7 + */ +int fluid_player_get_current_tick(fluid_player_t *player) +{ + return player->cur_ticks; +} + +/** + * Looks through all available MIDI tracks and gets the absolute tick of the very last event to play. + * @param player MIDI player instance + * @return Total tick count of the sequence + * @since 1.1.7 + */ +int fluid_player_get_total_ticks(fluid_player_t *player) +{ + int i; + int maxTicks = 0; + + for(i = 0; i < player->ntracks; i++) + { + if(player->track[i] != NULL) + { + int ticks = fluid_track_get_duration(player->track[i]); + + if(ticks > maxTicks) + { + maxTicks = ticks; + } + } + } + + return maxTicks; +} + +/** + * Get the tempo currently used by a MIDI player. + * The player can be controlled by internal tempo coming from MIDI file tempo + * change or controlled by external tempo see fluid_player_set_tempo(). + * @param player MIDI player instance. Must be a valid pointer. + * @return MIDI player tempo in BPM or FLUID_FAILED if error. + * @since 1.1.7 + */ +int fluid_player_get_bpm(fluid_player_t *player) +{ + + int midi_tempo = fluid_player_get_midi_tempo(player); + + if(midi_tempo > 0) + { + midi_tempo = 60000000L / midi_tempo; /* convert in bpm */ + } + + return midi_tempo; +} + +/** + * Get the division currently used by a MIDI player. + * The player can be controlled by internal tempo coming from MIDI file tempo + * change or controlled by external tempo see fluid_player_set_tempo(). + * @param player MIDI player instance. Must be a valid pointer. + * @return MIDI player division or FLUID_FAILED if error. + * @since 2.3.2 + */ +int fluid_player_get_division(fluid_player_t *player) +{ + return player->division; +} + +/** + * Get the tempo currently used by a MIDI player. + * The player can be controlled by internal tempo coming from MIDI file tempo + * change or controlled by external tempo see fluid_player_set_tempo(). + + * @param player MIDI player instance. Must be a valid pointer. + * @return Tempo of the MIDI player (in microseconds per quarter note, as per + * MIDI file spec) or FLUID_FAILED if error. + * @since 1.1.7 + */ +int fluid_player_get_midi_tempo(fluid_player_t *player) +{ + int midi_tempo; /* value to return */ + + fluid_return_val_if_fail(player != NULL, FLUID_FAILED); + + midi_tempo = fluid_atomic_int_get(&player->exttempo); + /* look if the player is internally synced */ + if(fluid_atomic_int_get(&player->sync_mode)) + { + midi_tempo = (int)((float)fluid_atomic_int_get(&player->miditempo)/ + fluid_atomic_float_get(&player->multempo)); + } + + return midi_tempo; +} + +/************************************************************************ + * MIDI PARSER + * + */ + +/* + * new_fluid_midi_parser + */ +fluid_midi_parser_t * +new_fluid_midi_parser() +{ + fluid_midi_parser_t *parser; + parser = FLUID_NEW(fluid_midi_parser_t); + + if(parser == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + parser->status = 0; /* As long as the status is 0, the parser won't do anything -> no need to initialize all the fields. */ + return parser; +} + +/* + * delete_fluid_midi_parser + */ +void +delete_fluid_midi_parser(fluid_midi_parser_t *parser) +{ + fluid_return_if_fail(parser != NULL); + + FLUID_FREE(parser); +} + +/** + * Parse a MIDI stream one character at a time. + * @param parser Parser instance + * @param c Next character in MIDI stream + * @return A parsed MIDI event or NULL if none. Event is internal and should + * not be modified or freed and is only valid until next call to this function. + * @internal Do not expose this function to the public API. It would allow downstream + * apps to abuse fluidsynth as midi parser, e.g. feeding it with rawmidi and pull out + * the needed midi information using the getter functions of fluid_midi_event_t. + * This parser however is incomplete as it e.g. only provides a limited buffer to + * store and process SYSEX data (i.e. doesn't allow arbitrary lengths) + */ +fluid_midi_event_t * +fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c) +{ + fluid_midi_event_t *event; + + /* Real-time messages (0xF8-0xFF) can occur anywhere, even in the middle + * of another message. */ + if(c >= 0xF8) + { + parser->event.type = c; + parser->status = 0; /* clear the status */ + return &parser->event; + } + + /* Status byte? - If previous message not yet complete, it is discarded (re-sync). */ + if(c & 0x80) + { + /* Any status byte terminates SYSEX messages (not just 0xF7) */ + if(parser->status == MIDI_SYSEX && parser->nr_bytes > 0) + { + event = &parser->event; + fluid_midi_event_set_sysex(event, parser->data, parser->nr_bytes, + FALSE); + } + else + { + event = NULL; + } + + if(c < 0xF0) /* Voice category message? */ + { + parser->channel = c & 0x0F; + parser->status = c & 0xF0; + + /* The event consumes x bytes of data... (subtract 1 for the status byte) */ + parser->nr_bytes_total = fluid_midi_event_length(parser->status) + - 1; + + parser->nr_bytes = 0; /* 0 bytes read so far */ + } + else if(c == MIDI_SYSEX) + { + parser->status = MIDI_SYSEX; + parser->nr_bytes = 0; + } + else + { + parser->status = 0; /* Discard other system messages (0xF1-0xF7) */ + } + + return event; /* Return SYSEX event or NULL */ + } + + /* Data/parameter byte */ + + /* Discard data bytes for events we don't care about */ + if(parser->status == 0) + { + return NULL; + } + + /* Max data size exceeded? (SYSEX messages only really) */ + if(parser->nr_bytes == FLUID_MIDI_PARSER_MAX_DATA_SIZE) + { + parser->status = 0; /* Discard the rest of the message */ + return NULL; + } + + /* Store next byte */ + parser->data[parser->nr_bytes++] = c; + + /* Do we still need more data to get this event complete? */ + if(parser->status == MIDI_SYSEX || parser->nr_bytes < parser->nr_bytes_total) + { + return NULL; + } + + /* Event is complete, return it. + * Running status byte MIDI feature is also handled here. */ + parser->event.type = parser->status; + parser->event.channel = parser->channel; + parser->nr_bytes = 0; /* Reset data size, in case there are additional running status messages */ + + switch(parser->status) + { + case NOTE_OFF: + case NOTE_ON: + case KEY_PRESSURE: + case CONTROL_CHANGE: + case PROGRAM_CHANGE: + case CHANNEL_PRESSURE: + parser->event.param1 = parser->data[0]; /* For example key number */ + parser->event.param2 = parser->data[1]; /* For example velocity */ + break; + + case PITCH_BEND: + /* Pitch-bend is transmitted with 14-bit precision. */ + parser->event.param1 = (parser->data[1] << 7) | parser->data[0]; + break; + + default: /* Unlikely */ + return NULL; + } + + return &parser->event; +} + +/* Purpose: + * Returns the length of a MIDI message. */ +static int +fluid_midi_event_length(unsigned char event) +{ + switch(event & 0xF0) + { + case NOTE_OFF: + case NOTE_ON: + case KEY_PRESSURE: + case CONTROL_CHANGE: + case PITCH_BEND: + return 3; + + case PROGRAM_CHANGE: + case CHANNEL_PRESSURE: + return 2; + } + + switch(event) + { + case MIDI_TIME_CODE: + case MIDI_SONG_SELECT: + case 0xF4: + case 0xF5: + return 2; + + case MIDI_TUNE_REQUEST: + return 1; + + case MIDI_SONG_POSITION: + return 3; + } + + return 1; +} diff --git a/libs/fluidsynth/src/midi/fluid_midi.h b/libs/fluidsynth/src/midi/fluid_midi.h new file mode 100644 index 00000000000..bd3b4e8a1b1 --- /dev/null +++ b/libs/fluidsynth/src/midi/fluid_midi.h @@ -0,0 +1,384 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUID_MIDI_H +#define _FLUID_MIDI_H + +#include "fluidsynth_priv.h" +#include "fluid_sys.h" +#include "fluid_list.h" + +typedef struct _fluid_midi_parser_t fluid_midi_parser_t; + +fluid_midi_parser_t *new_fluid_midi_parser(void); +void delete_fluid_midi_parser(fluid_midi_parser_t *parser); +fluid_midi_event_t *fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c); + + +/*************************************************************** + * + * CONSTANTS & ENUM + */ + + +#define MAX_NUMBER_OF_TRACKS 128 +#define MAX_NUMBER_OF_CHANNELS 16 + +enum fluid_midi_event_type +{ + /* channel messages */ + NOTE_OFF = 0x80, + NOTE_ON = 0x90, + KEY_PRESSURE = 0xa0, + CONTROL_CHANGE = 0xb0, + PROGRAM_CHANGE = 0xc0, + CHANNEL_PRESSURE = 0xd0, + PITCH_BEND = 0xe0, + /* system exclusive */ + MIDI_SYSEX = 0xf0, + /* system common - never in midi files */ + MIDI_TIME_CODE = 0xf1, + MIDI_SONG_POSITION = 0xf2, + MIDI_SONG_SELECT = 0xf3, + MIDI_TUNE_REQUEST = 0xf6, + MIDI_EOX = 0xf7, + /* system real-time - never in midi files */ + MIDI_SYNC = 0xf8, + MIDI_TICK = 0xf9, + MIDI_START = 0xfa, + MIDI_CONTINUE = 0xfb, + MIDI_STOP = 0xfc, + MIDI_ACTIVE_SENSING = 0xfe, + MIDI_SYSTEM_RESET = 0xff, + /* meta event - for midi files only */ + MIDI_META_EVENT = 0xff +}; + +enum fluid_midi_control_change +{ + BANK_SELECT_MSB = 0x00, + MODULATION_MSB = 0x01, + BREATH_MSB = 0x02, + FOOT_MSB = 0x04, + PORTAMENTO_TIME_MSB = 0x05, + DATA_ENTRY_MSB = 0x06, + VOLUME_MSB = 0x07, + BALANCE_MSB = 0x08, + PAN_MSB = 0x0A, + EXPRESSION_MSB = 0x0B, + EFFECTS1_MSB = 0x0C, + EFFECTS2_MSB = 0x0D, + GPC1_MSB = 0x10, /* general purpose controller */ + GPC2_MSB = 0x11, + GPC3_MSB = 0x12, + GPC4_MSB = 0x13, + BANK_SELECT_LSB = 0x20, + MODULATION_WHEEL_LSB = 0x21, + BREATH_LSB = 0x22, + FOOT_LSB = 0x24, + PORTAMENTO_TIME_LSB = 0x25, + DATA_ENTRY_LSB = 0x26, + VOLUME_LSB = 0x27, + BALANCE_LSB = 0x28, + PAN_LSB = 0x2A, + EXPRESSION_LSB = 0x2B, + EFFECTS1_LSB = 0x2C, + EFFECTS2_LSB = 0x2D, + GPC1_LSB = 0x30, + GPC2_LSB = 0x31, + GPC3_LSB = 0x32, + GPC4_LSB = 0x33, + SUSTAIN_SWITCH = 0x40, + PORTAMENTO_SWITCH = 0x41, + SOSTENUTO_SWITCH = 0x42, + SOFT_PEDAL_SWITCH = 0x43, + LEGATO_SWITCH = 0x44, + HOLD2_SWITCH = 0x45, + SOUND_CTRL1 = 0x46, + SOUND_CTRL2 = 0x47, + SOUND_CTRL3 = 0x48, + SOUND_CTRL4 = 0x49, + SOUND_CTRL5 = 0x4A, + SOUND_CTRL6 = 0x4B, + SOUND_CTRL7 = 0x4C, + SOUND_CTRL8 = 0x4D, + SOUND_CTRL9 = 0x4E, + SOUND_CTRL10 = 0x4F, + GPC5 = 0x50, + GPC6 = 0x51, + GPC7 = 0x52, + GPC8 = 0x53, + PORTAMENTO_CTRL = 0x54, + EFFECTS_DEPTH1 = 0x5B, + EFFECTS_DEPTH2 = 0x5C, + EFFECTS_DEPTH3 = 0x5D, + EFFECTS_DEPTH4 = 0x5E, + EFFECTS_DEPTH5 = 0x5F, + DATA_ENTRY_INCR = 0x60, + DATA_ENTRY_DECR = 0x61, + NRPN_LSB = 0x62, + NRPN_MSB = 0x63, + RPN_LSB = 0x64, + RPN_MSB = 0x65, + ALL_SOUND_OFF = 0x78, + ALL_CTRL_OFF = 0x79, + LOCAL_CONTROL = 0x7A, + ALL_NOTES_OFF = 0x7B, + OMNI_OFF = 0x7C, + OMNI_ON = 0x7D, + POLY_OFF = 0x7E, + POLY_ON = 0x7F +}; + +/* General MIDI RPN event numbers (LSB, MSB = 0) */ +enum midi_rpn_event +{ + RPN_PITCH_BEND_RANGE = 0x00, + RPN_CHANNEL_FINE_TUNE = 0x01, + RPN_CHANNEL_COARSE_TUNE = 0x02, + RPN_TUNING_PROGRAM_CHANGE = 0x03, + RPN_TUNING_BANK_SELECT = 0x04, + RPN_MODULATION_DEPTH_RANGE = 0x05 +}; + +enum midi_meta_event +{ + MIDI_TEXT = 0x01, + MIDI_COPYRIGHT = 0x02, + MIDI_TRACK_NAME = 0x03, + MIDI_INST_NAME = 0x04, + MIDI_LYRIC = 0x05, + MIDI_MARKER = 0x06, + MIDI_CUE_POINT = 0x07, + MIDI_EOT = 0x2f, + MIDI_SET_TEMPO = 0x51, + MIDI_SMPTE_OFFSET = 0x54, + MIDI_TIME_SIGNATURE = 0x58, + MIDI_KEY_SIGNATURE = 0x59, + MIDI_SEQUENCER_EVENT = 0x7f +}; + +/* MIDI SYSEX useful manufacturer values */ +enum midi_sysex_manuf +{ + MIDI_SYSEX_MANUF_ROLAND = 0x41, /**< Roland manufacturer ID */ + MIDI_SYSEX_MANUF_YAMAHA = 0x43, + MIDI_SYSEX_UNIV_NON_REALTIME = 0x7E, /**< Universal non realtime message */ + MIDI_SYSEX_UNIV_REALTIME = 0x7F /**< Universal realtime message */ +}; + +#define MIDI_SYSEX_DEVICE_ID_ALL 0x7F /**< Device ID used in SYSEX messages to indicate all devices */ + +/* SYSEX sub-ID #1 which follows device ID */ +#define MIDI_SYSEX_MIDI_TUNING_ID 0x08 /**< Sysex sub-ID #1 for MIDI tuning messages */ +#define MIDI_SYSEX_GM_ID 0x09 /**< Sysex sub-ID #1 for General MIDI messages */ +#define MIDI_SYSEX_GS_ID 0x42 /**< Model ID (GS) serving as sub-ID #1 for GS messages*/ +#define MIDI_SYSEX_XG_ID 0x4C /**< Model ID (XG) serving as sub-ID #1 for XG messages*/ + +/** + * SYSEX tuning message IDs. + */ +enum midi_sysex_tuning_msg_id +{ + MIDI_SYSEX_TUNING_BULK_DUMP_REQ = 0x00, /**< Bulk tuning dump request (non-realtime) */ + MIDI_SYSEX_TUNING_BULK_DUMP = 0x01, /**< Bulk tuning dump response (non-realtime) */ + MIDI_SYSEX_TUNING_NOTE_TUNE = 0x02, /**< Tuning note change message (realtime) */ + MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK = 0x03, /**< Bulk tuning dump request (with bank, non-realtime) */ + MIDI_SYSEX_TUNING_BULK_DUMP_BANK = 0x04, /**< Bulk tuning dump response (with bank, non-realtime) */ + MIDI_SYSEX_TUNING_OCTAVE_DUMP_1BYTE = 0x05, /**< Octave tuning dump using 1 byte values (non-realtime) */ + MIDI_SYSEX_TUNING_OCTAVE_DUMP_2BYTE = 0x06, /**< Octave tuning dump using 2 byte values (non-realtime) */ + MIDI_SYSEX_TUNING_NOTE_TUNE_BANK = 0x07, /**< Tuning note change message (with bank, realtime/non-realtime) */ + MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE = 0x08, /**< Octave tuning message using 1 byte values (realtime/non-realtime) */ + MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE = 0x09 /**< Octave tuning message using 2 byte values (realtime/non-realtime) */ +}; + +/* General MIDI sub-ID #2 */ +#define MIDI_SYSEX_GM_ON 0x01 /**< Enable GM mode */ +#define MIDI_SYSEX_GM_OFF 0x02 /**< Disable GM mode */ +#define MIDI_SYSEX_GM2_ON 0x03 /**< Enable GM2 mode */ +#define MIDI_SYSEX_GS_DT1 0x12 /**< GS DT1 command */ + +enum fluid_driver_status +{ + FLUID_MIDI_READY, + FLUID_MIDI_LISTENING, + FLUID_MIDI_DONE +}; + +/*************************************************************** + * + * TYPE DEFINITIONS & FUNCTION DECLARATIONS + */ + +/* + * fluid_midi_event_t + */ +struct _fluid_midi_event_t +{ + fluid_midi_event_t *next; /* Link to next event */ + void *paramptr; /* Pointer parameter (for SYSEX data), size is stored to param1, param2 indicates if pointer should be freed (dynamic if TRUE) */ + unsigned int dtime; /* Delay (ticks) between this and previous event. midi tracks. */ + unsigned int param1; /* First parameter */ + unsigned int param2; /* Second parameter */ + unsigned char type; /* MIDI event type */ + unsigned char channel; /* MIDI channel */ +}; + + +/* + * fluid_track_t + */ +struct _fluid_track_t +{ + char *name; + int num; + fluid_midi_event_t *first; + fluid_midi_event_t *cur; + fluid_midi_event_t *last; + unsigned int ticks; +}; + +typedef struct _fluid_track_t fluid_track_t; + +#define fluid_track_eot(track) ((track)->cur == NULL) + + +/* + * fluid_playlist_item + * Used as the `data' elements of the fluid_player.playlist. + * Represents either a filename or a pre-loaded memory buffer. + * Exactly one of `filename' and `buffer' is non-NULL. + */ +typedef struct +{ + char *filename; /** Name of file (owned); NULL if data pre-loaded */ + void *buffer; /** The MIDI file data (owned); NULL if filename */ + size_t buffer_len; /** Number of bytes in buffer; 0 if filename */ +} fluid_playlist_item; + +/* range of tempo values */ +#define MIN_TEMPO_VALUE (1.0f) +#define MAX_TEMPO_VALUE (60000000.0f) +/* range of tempo multiplier values */ +#define MIN_TEMPO_MULTIPLIER (0.001f) +#define MAX_TEMPO_MULTIPLIER (1000.0f) + +/* + * fluid_player + */ +struct _fluid_player_t +{ + fluid_atomic_int_t status; + fluid_atomic_int_t stopping; /* Flag for sending all_notes_off when player is stopped */ + int ntracks; + fluid_track_t *track[MAX_NUMBER_OF_TRACKS]; + fluid_synth_t *synth; + fluid_timer_t *system_timer; + fluid_sample_timer_t *sample_timer; + + int loop; /* -1 = loop infinitely, otherwise times left to loop the playlist */ + fluid_list_t *playlist; /* List of fluid_playlist_item* objects */ + fluid_list_t *currentfile; /* points to an item in files, or NULL if not playing */ + + char use_system_timer; /* if zero, use sample timers, otherwise use system clock timer */ + char reset_synth_between_songs; /* 1 if system reset should be sent to the synth between songs. */ + fluid_atomic_int_t seek_ticks; /* new position in tempo ticks (midi ticks) for seeking */ + int start_ticks; /* the number of tempo ticks passed at the last tempo change */ + int cur_ticks; /* the number of tempo ticks passed */ + int last_callback_ticks; /* the last tick number that was passed to player->tick_callback */ + int begin_msec; /* the time (msec) of the beginning of the file */ + int start_msec; /* the start time of the last tempo change */ + unsigned int cur_msec; /* the current time */ + int end_msec; /* when >=0, playback is extended until this time (for, e.g., reverb) */ + char end_pedals_disabled; /* 1 once the pedals have been released after the last midi event, 0 otherwise */ + /* sync mode: indicates the tempo mode the player is driven by (see fluid_player_set_tempo()): + 1, the player is driven by internal tempo (miditempo). This is the default. + 0, the player is driven by external tempo (exttempo) + */ + int sync_mode; + /* miditempo: internal tempo coming from MIDI file tempo change events + (in micro seconds per quarter note) + */ + int miditempo; /* as indicated by MIDI SetTempo: n 24th of a usec per midi-clock. bravo! */ + /* exttempo: external tempo set by fluid_player_set_tempo() (in micro seconds per quarter note) */ + int exttempo; + /* multempo: tempo multiplier set by fluid_player_set_tempo() */ + float multempo; + float deltatime; /* milliseconds per midi tick. depends on current tempo mode (see sync_mode) */ + unsigned int division; + + handle_midi_event_func_t playback_callback; /* function fired on each midi event as it is played */ + void *playback_userdata; /* pointer to user-defined data passed to playback_callback function */ + handle_midi_tick_func_t tick_callback; /* function fired on each tick change */ + void *tick_userdata; /* pointer to user-defined data passed to tick_callback function */ + + int channel_isplaying[MAX_NUMBER_OF_CHANNELS]; /* flags indicating channels on which notes have played */ +}; + +#define FLUID_PLAYER_STOP_GRACE_MS 2000 + +void fluid_player_settings(fluid_settings_t *settings); + + +/* + * fluid_midi_file + */ +typedef struct +{ + const char *buffer; /* Entire contents of MIDI file (borrowed) */ + int buf_len; /* Length of buffer, in bytes */ + int buf_pos; /* Current read position in contents buffer */ + int eof; /* The "end of file" condition */ + int running_status; + int c; + int type; + int ntracks; + int uses_smpte; + unsigned int smpte_fps; + unsigned int smpte_res; + unsigned int division; /* If uses_SMPTE == 0 then division is + ticks per beat (quarter-note) */ + double tempo; /* Beats per second (SI rules =) */ + int tracklen; + int trackpos; + int eot; + int varlen; + int dtime; +} fluid_midi_file; + + + +#define FLUID_MIDI_PARSER_MAX_DATA_SIZE 1024 /**< Maximum size of MIDI parameters/data (largest is SYSEX data) */ + +/* + * fluid_midi_parser_t + */ +struct _fluid_midi_parser_t +{ + unsigned char status; /* Identifies the type of event, that is currently received ('Noteon', 'Pitch Bend' etc). */ + unsigned char channel; /* The channel of the event that is received (in case of a channel event) */ + unsigned int nr_bytes; /* How many bytes have been read for the current event? */ + unsigned int nr_bytes_total; /* How many bytes does the current event type include? */ + unsigned char data[FLUID_MIDI_PARSER_MAX_DATA_SIZE]; /* The parameters or SYSEX data */ + fluid_midi_event_t event; /* The event, that is returned to the MIDI driver. */ +}; + + +#endif /* _FLUID_MIDI_H */ diff --git a/libs/fluidsynth/src/midi/fluid_midi_router.h b/libs/fluidsynth/src/midi/fluid_midi_router.h new file mode 100644 index 00000000000..5a5068d5ea9 --- /dev/null +++ b/libs/fluidsynth/src/midi/fluid_midi_router.h @@ -0,0 +1,32 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +/* Author: Markus Nentwig, nentwig@users.sourceforge.net + */ + +#ifndef _FLUID_MIDIROUTER_H +#define _FLUID_MIDIROUTER_H + +#include "fluidsynth_priv.h" +#include "fluid_midi.h" +#include "fluid_sys.h" + + +#endif diff --git a/libs/fluidsynth/src/rvoice/fluid_adsr_env.c b/libs/fluidsynth/src/rvoice/fluid_adsr_env.c new file mode 100644 index 00000000000..4b37754cb01 --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_adsr_env.c @@ -0,0 +1,38 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include "fluid_adsr_env.h" + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_adsr_env_set_data) +{ + fluid_adsr_env_t *env = obj; + fluid_adsr_env_section_t section = param[0].i; + unsigned int count = param[1].i; + fluid_real_t coeff = param[2].real; + fluid_real_t increment = param[3].real; + fluid_real_t min = param[4].real; + fluid_real_t max = param[5].real; + + env->data[section].count = count; + env->data[section].coeff = coeff; + env->data[section].increment = increment; + env->data[section].min = min; + env->data[section].max = max; +} diff --git a/libs/fluidsynth/src/rvoice/fluid_adsr_env.h b/libs/fluidsynth/src/rvoice/fluid_adsr_env.h new file mode 100644 index 00000000000..92c8fcd24c0 --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_adsr_env.h @@ -0,0 +1,166 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUID_ADSR_ENVELOPE_H +#define _FLUID_ADSR_ENVELOPE_H + +#include "fluidsynth_priv.h" +#include "fluid_sys.h" + +/* + * envelope data + */ +struct _fluid_env_data_t +{ + unsigned int count; + fluid_real_t coeff; + fluid_real_t increment; + fluid_real_t min; + fluid_real_t max; +}; + +/* Indices for envelope tables */ +enum fluid_voice_envelope_index +{ + FLUID_VOICE_ENVDELAY, + FLUID_VOICE_ENVATTACK, + FLUID_VOICE_ENVHOLD, + FLUID_VOICE_ENVDECAY, + FLUID_VOICE_ENVSUSTAIN, + FLUID_VOICE_ENVRELEASE, + FLUID_VOICE_ENVFINISHED, + FLUID_VOICE_ENVLAST +}; + +typedef enum fluid_voice_envelope_index fluid_adsr_env_section_t; + +typedef struct _fluid_adsr_env_t fluid_adsr_env_t; + +struct _fluid_adsr_env_t +{ + fluid_env_data_t data[FLUID_VOICE_ENVLAST]; + unsigned int count; + fluid_real_t val; /* the current value of the envelope */ + fluid_adsr_env_section_t section; +}; + +/* For performance, all functions are inlined */ + +static FLUID_INLINE void +fluid_adsr_env_calc(fluid_adsr_env_t *env) +{ + fluid_env_data_t *env_data; + fluid_real_t x; + + env_data = &env->data[env->section]; + + /* skip to the next section of the envelope if necessary */ + while(env->count >= env_data->count) + { + // If we're switching envelope stages from decay to sustain, force the value to be the end value of the previous stage + // Hmm, should this only apply to volenv? It was so before refactoring, so keep it for now. [DH] + // No, must apply to both, otherwise some voices may sound detuned. [TM] (https://github.com/FluidSynth/fluidsynth/issues/1059) + if(env->section == FLUID_VOICE_ENVDECAY) + { + env->val = env_data->min * env_data->coeff; + } + + env_data = &env->data[++env->section]; + env->count = 0; + } + + /* calculate the envelope value and check for valid range */ + x = env_data->coeff * env->val + env_data->increment; + + if(x < env_data->min) + { + x = env_data->min; + env->section++; + env->count = 0; + } + else if(x > env_data->max) + { + x = env_data->max; + env->section++; + env->count = 0; + } + else + { + env->count++; + } + + env->val = x; +} + +/* This one cannot be inlined since it is referenced in + the event queue */ +DECLARE_FLUID_RVOICE_FUNCTION(fluid_adsr_env_set_data); + +static FLUID_INLINE void +fluid_adsr_env_reset(fluid_adsr_env_t *env) +{ + env->count = 0; + env->section = FLUID_VOICE_ENVDELAY; + env->val = 0.0f; +} + +static FLUID_INLINE fluid_real_t +fluid_adsr_env_get_val(fluid_adsr_env_t *env) +{ + return env->val; +} + +static FLUID_INLINE void +fluid_adsr_env_set_val(fluid_adsr_env_t *env, fluid_real_t val) +{ + env->val = val; +} + +static FLUID_INLINE fluid_adsr_env_section_t +fluid_adsr_env_get_section(fluid_adsr_env_t *env) +{ + return env->section; +} + +static FLUID_INLINE void +fluid_adsr_env_set_section(fluid_adsr_env_t *env, + fluid_adsr_env_section_t section) +{ + env->section = section; + env->count = 0; +} + +/* Used for determining which voice to kill. + Returns max amplitude from now, and forward in time. +*/ +static FLUID_INLINE fluid_real_t +fluid_adsr_env_get_max_val(fluid_adsr_env_t *env) +{ + if(env->section > FLUID_VOICE_ENVATTACK) + { + return env->val * 1000; + } + else + { + return env->data[FLUID_VOICE_ENVATTACK].max; + } +} + +#endif diff --git a/libs/fluidsynth/src/rvoice/fluid_chorus.c b/libs/fluidsynth/src/rvoice/fluid_chorus.c new file mode 100644 index 00000000000..c80dc9e98c1 --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_chorus.c @@ -0,0 +1,1071 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe, Markus Nentwig and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +/* + based on a chorus implementation made by Juergen Mueller And Sundry Contributors in 1998 + + CHANGES + + - Adapted for fluidsynth, Peter Hanappe, March 2002 + + - Variable delay line implementation using bandlimited + interpolation, code reorganization: Markus Nentwig May 2002 + + - Complete rewrite using lfo computed on the fly, first order all-pass + interpolator and adding stereo unit: Jean-Jacques Ceresa, Jul 2019 + */ + + +/* + * Chorus effect. + * + * Flow diagram scheme for n delays ( 1 <= n <= MAX_CHORUS ): + * + * ________ + * direct signal (not implemented) >-->| | + * _________ | | + * mono | | | | + * input ---+---->| delay 1 |-------------------------->| Stereo |---> right + * | |_________| | | output + * | /|\ | Unit | + * : | | | + * : +-----------------+ |(width) | + * : | Delay control 1 |<-+ | | + * : +-----------------+ | | |---> left + * | _________ | | | output + * | | | | | | + * +---->| delay n |-------------------------->| | + * |_________| | | | + * /|\ | |________| + * | | +--------------+ /|\ + * +-----------------+ | |mod depth (ms)| | + * | Delay control n |<-*--|lfo speed (Hz)| gain-out + * +-----------------+ +--------------+ + * + * + * The delay i is controlled by a sine or triangle modulation i ( 1 <= i <= n). + * + * The chorus unit process a monophonic input signal and produces stereo output + * controlled by WIDTH macro. + * Actually WIDTH is fixed to maximum value. But in the future, we could add a + * setting (e.g "synth.chorus.width") allowing the user to get a gradually stereo + * effect from minimum (monophonic) to maximum stereo effect. + * + * Delays lines are implemented using only one line for all chorus blocks. + * Each chorus block has it own lfo (sinus/triangle). Each lfo are out of phase + * to produce uncorrelated signal at the output of the delay line (this simulates + * the presence of individual line for each block). Each lfo modulates the length + * of the line using a depth modulation value and lfo frequency value common to + * all lfos. + * + * LFO modulators are computed on the fly, instead of using lfo lookup table. + * The advantages are: + * - Avoiding a lost of 608272 memory bytes when lfo speed is low (0.3Hz). + * - Allows to diminish the lfo speed lower limit to 0.1Hz instead of 0.3Hz. + * A speed of 0.1 is interesting for chorus. Using a lookuptable for 0.1Hz + * would require too much memory (1824816 bytes). + * - Interpolation make use of first order all-pass interpolator instead of + * bandlimited interpolation. + * - Although lfo modulator is computed on the fly, cpu load is lower than + * using lfo lookup table with bandlimited interpolator. + */ + +#include "fluid_chorus.h" +#include "fluid_sys.h" + + +/*------------------------------------------------------------------------------------- + Private +--------------------------------------------------------------------------------------*/ +// #define DEBUG_PRINT // allows message to be printed on the console. + +#define MAX_CHORUS 99 /* number maximum of block */ +#define MAX_LEVEL 10 /* max output level */ +#define MIN_SPEED_HZ 0.1 /* min lfo frequency (Hz) */ +#define MAX_SPEED_HZ 5 /* max lfo frequency (Hz) */ + +/* WIDTH [0..10] value define a stereo separation between left and right. + When 0, the output is monophonic. When > 0 , the output is stereophonic. + Actually WIDTH is fixed to maximum value. But in the future we could add a setting to + allow a gradually stereo effect from minimum (monophonic) to maximum stereo effect. +*/ +#define WIDTH 10 + +/* SCALE_WET_WIDTH is a compensation weight factor to get an output + amplitude (wet) rather independent of the width setting. + 0: the output amplitude is fully dependent on the width setting. + >0: the output amplitude is less dependent on the width setting. + With a SCALE_WET_WIDTH of 0.2 the output amplitude is rather + independent of width setting (see fluid_chorus_set()). + */ +#define SCALE_WET_WIDTH 0.2f +#define SCALE_WET 1.0f + +#define MAX_SAMPLES 2048 /* delay length in sample (46.4 ms at sample rate: 44100Hz).*/ +#define LOW_MOD_DEPTH 176 /* low mod_depth/2 in samples */ +#define HIGH_MOD_DEPTH MAX_SAMPLES/2 /* high mod_depth in sample */ +#define RANGE_MOD_DEPTH (HIGH_MOD_DEPTH - LOW_MOD_DEPTH) + +/* Important min max values for MOD_RATE */ +/* mod rate define the rate at which the modulator is updated. Examples + 50: the modulator is updated every 50 samples (less cpu cycles expensive). + 1: the modulator is updated every sample (more cpu cycles expensive). +*/ +/* MOD_RATE acceptable for max lfo speed (5Hz) and max modulation depth (46.6 ms) */ +#define LOW_MOD_RATE 5 /* MOD_RATE acceptable for low modulation depth (8 ms) */ +#define HIGH_MOD_RATE 4 /* MOD_RATE acceptable for max modulation depth (46.6 ms) */ + /* and max lfo speed (5 Hz) */ +#define RANGE_MOD_RATE (HIGH_MOD_RATE - LOW_MOD_RATE) + +/* some chorus cpu_load measurement dependent of modulation rate: mod_rate + (number of chorus blocks: 2) + + No stero unit: + mod_rate | chorus cpu load(%) | one voice cpu load (%) + ---------------------------------------------------- + 50 | 0.204 | + 5 | 0.256 | 0.169 + 1 | 0.417 | + + With stero unit: + mod_rate | chorus cpu load(%) | one voice cpu load (%) + ---------------------------------------------------- + 50 | 0.220 | + 5 | 0.274 | 0.169 + 1 | 0.465 | + +*/ + +/* + Number of samples to add to the desired length of the delay line. This + allows to take account of rounding error interpolation when using large + modulation depth. + 1 is sufficient for max modulation depth (46.6 ms) and max lfo speed (5 Hz). +*/ +//#define INTERP_SAMPLES_NBR 0 +#define INTERP_SAMPLES_NBR 1 + + +/*----------------------------------------------------------------------------- + Sinusoidal modulator +-----------------------------------------------------------------------------*/ +/* modulator */ +typedef struct +{ + fluid_real_t a1; /* Coefficient: a1 = 2 * cos(w) */ + fluid_real_t buffer1; /* buffer1 */ + fluid_real_t buffer2; /* buffer2 */ + fluid_real_t reset_buffer2;/* reset value of buffer2 */ +} sinus_modulator; + +/*----------------------------------------------------------------------------- + Triangle modulator +-----------------------------------------------------------------------------*/ +typedef struct +{ + fluid_real_t freq; /* Osc. Frequency (in Hertz) */ + fluid_real_t val; /* internal current value */ + fluid_real_t inc; /* increment value */ +} triang_modulator; + +/*----------------------------------------------------------------------------- + modulator +-----------------------------------------------------------------------------*/ +typedef struct +{ + /*-------------*/ + int line_out; /* current line out position for this modulator */ + /*-------------*/ + sinus_modulator sinus; /* sinus lfo */ + triang_modulator triang; /* triangle lfo */ + /*-------------------------*/ + /* first order All-Pass interpolator members */ + fluid_real_t frac_pos_mod; /* fractional position part between samples */ + /* previous value used when interpolating using fractional */ + fluid_real_t buffer; +} modulator; + +/* Private data for SKEL file */ +struct _fluid_chorus_t +{ + int type; + fluid_real_t depth_ms; + fluid_real_t level; + fluid_real_t speed_Hz; + int number_blocks; + fluid_real_t sample_rate; + + /* width control: 0 monophonic, > 0 more stereophonic */ + fluid_real_t width; + fluid_real_t wet1, wet2; + + fluid_real_t *line; /* buffer line */ + int size; /* effective internal size (in samples) */ + + int line_in; /* line in position */ + + /* center output position members */ + fluid_real_t center_pos_mod; /* center output position modulated by modulator */ + int mod_depth; /* modulation depth (in samples) */ + + /* variable rate control of center output position */ + int index_rate; /* index rate to know when to update center_pos_mod */ + int mod_rate; /* rate at which center_pos_mod is updated */ + + /* modulator member */ + modulator mod[MAX_CHORUS]; /* sinus/triangle modulator */ +}; + +/*----------------------------------------------------------------------------- + Sets the frequency of sinus oscillator. + + @param mod pointer on modulator structure. + @param freq frequency of the oscillator in Hz. + @param sample_rate sample rate on audio output in Hz. + @param phase initial phase of the oscillator in degree (0 to 360). +-----------------------------------------------------------------------------*/ +static void set_sinus_frequency(sinus_modulator *mod, + float freq, float sample_rate, float phase) +{ + fluid_real_t w = 2 * FLUID_M_PI * freq / sample_rate; /* initial angle */ + fluid_real_t a; + + mod->a1 = 2 * FLUID_COS(w); + + a = (2 * FLUID_M_PI / 360) * phase; + + mod->buffer2 = FLUID_SIN(a - w); /* y(n-1) = sin(-initial angle) */ + mod->buffer1 = FLUID_SIN(a); /* y(n) = sin(initial phase) */ + mod->reset_buffer2 = FLUID_SIN(FLUID_M_PI / 2 - w); /* reset value for PI/2 */ +} + +/*----------------------------------------------------------------------------- + Gets current value of sinus modulator: + y(n) = a1 . y(n-1) - y(n-2) + out = a1 . buffer1 - buffer2 + + @param mod pointer on modulator structure. + @return current value of the modulator sine wave. +-----------------------------------------------------------------------------*/ +static FLUID_INLINE fluid_real_t get_mod_sinus(sinus_modulator *mod) +{ + fluid_real_t out; + out = mod->a1 * mod->buffer1 - mod->buffer2; + mod->buffer2 = mod->buffer1; + + if(out >= 1.0f) /* reset in case of instability near PI/2 */ + { + out = 1.0f; /* forces output to the right value */ + mod->buffer2 = mod->reset_buffer2; + } + + if(out <= -1.0f) /* reset in case of instability near -PI/2 */ + { + out = -1.0f; /* forces output to the right value */ + mod->buffer2 = - mod->reset_buffer2; + } + + mod->buffer1 = out; + return out; +} + +/*----------------------------------------------------------------------------- + Set the frequency of triangular oscillator + The frequency is converted in a slope value. + The initial value is set according to frac_phase which is a position + in the period relative to the beginning of the period. + For example: 0 is the beginning of the period, 1/4 is at 1/4 of the period + relative to the beginning. + + @param mod pointer on modulator structure. + @param freq frequency of the oscillator in Hz. + @param sample_rate sample rate on audio output in Hz. + @param frac_phase initial phase (see comment above). +-----------------------------------------------------------------------------*/ +static void set_triangle_frequency(triang_modulator *mod, float freq, + float sample_rate, float frac_phase) +{ + fluid_real_t ns_period; /* period in numbers of sample */ + + if(freq <= 0.0) + { + freq = 0.5f; + } + + mod->freq = freq; + + ns_period = sample_rate / freq; + + /* the slope of a triangular osc (0 up to +1 down to -1 up to 0....) is equivalent + to the slope of a saw osc (0 -> +4) */ + mod->inc = 4 / ns_period; /* positive slope */ + + /* The initial value and the sign of the slope depend of initial phase: + initial value = = (ns_period * frac_phase) * slope + */ + mod->val = ns_period * frac_phase * mod->inc; + + if(1.0 <= mod->val && mod->val < 3.0) + { + mod->val = 2.0 - mod->val; /* 1.0 down to -1.0 */ + mod->inc = -mod->inc; /* negative slope */ + } + else if(3.0 <= mod->val) + { + mod->val = mod->val - 4.0; /* -1.0 up to +1.0. */ + } + + /* else val < 1.0 */ +} + +/*----------------------------------------------------------------------------- + Get current value of triangular oscillator + y(n) = y(n-1) + dy + + @param mod pointer on triang_modulator structure. + @return current value. +-----------------------------------------------------------------------------*/ +static FLUID_INLINE fluid_real_t get_mod_triang(triang_modulator *mod) +{ + mod->val = mod->val + mod->inc ; + + if(mod->val >= 1.0) + { + mod->inc = -mod->inc; + return 1.0; + } + + if(mod->val <= -1.0) + { + mod->inc = -mod->inc; + return -1.0; + } + + return mod->val; +} +/*----------------------------------------------------------------------------- + Reads the sample value out of the modulated delay line. + + @param chorus pointer on chorus unit. + @param mod pointer on modulator structure. + @return current value. +-----------------------------------------------------------------------------*/ +static FLUID_INLINE fluid_real_t get_mod_delay(fluid_chorus_t *chorus, + modulator *mod) +{ + fluid_real_t out_index; /* new modulated index position */ + int int_out_index; /* integer part of out_index */ + fluid_real_t out; /* value to return */ + + /* Checks if the modulator must be updated (every mod_rate samples). */ + /* Important: center_pos_mod must be used immediately for the + first sample. So, mdl->index_rate must be initialized + to mdl->mod_rate (new_mod_delay_line()) */ + + if(chorus->index_rate >= chorus->mod_rate) + { + /* out_index = center position (center_pos_mod) + sinus waweform */ + if(chorus->type == FLUID_CHORUS_MOD_SINE) + { + out_index = chorus->center_pos_mod + + get_mod_sinus(&mod->sinus) * chorus->mod_depth; + } + else + { + out_index = chorus->center_pos_mod + + get_mod_triang(&mod->triang) * chorus->mod_depth; + } + + /* extracts integer part in int_out_index */ + if(out_index >= 0.0f) + { + int_out_index = (int)out_index; /* current integer part */ + + /* forces read index (line_out) with integer modulation value */ + /* Boundary check and circular motion as needed */ + if((mod->line_out = int_out_index) >= chorus->size) + { + mod->line_out -= chorus->size; + } + } + else /* negative */ + { + int_out_index = (int)(out_index - 1); /* previous integer part */ + /* forces read index (line_out) with integer modulation value */ + /* circular motion as needed */ + mod->line_out = int_out_index + chorus->size; + } + + /* extracts fractionnal part. (it will be used when interpolating + between line_out and line_out +1) and memorize it. + Memorizing is necessary for modulation rate above 1 */ + mod->frac_pos_mod = out_index - int_out_index; + } + + /* First order all-pass interpolation ----------------------------------*/ + /* https://ccrma.stanford.edu/~jos/pasp/First_Order_Allpass_Interpolation.html */ + /* begins interpolation: read current sample */ + out = chorus->line[mod->line_out]; + + /* updates line_out to the next sample. + Boundary check and circular motion as needed */ + if(++mod->line_out >= chorus->size) + { + mod->line_out -= chorus->size; + } + + /* Fractional interpolation between next sample (at next position) and + previous output added to current sample. + */ + out += mod->frac_pos_mod * (chorus->line[mod->line_out] - mod->buffer); + mod->buffer = out; /* memorizes current output */ + return out; +} + +/*----------------------------------------------------------------------------- + Push a sample val into the delay line + + @param dl delay line to push value into. + @param val the value to push into dl. +-----------------------------------------------------------------------------*/ +#define push_in_delay_line(dl, val) \ +{\ + dl->line[dl->line_in] = val;\ + /* Incrementation and circular motion if necessary */\ + if(++dl->line_in >= dl->size) dl->line_in -= dl->size;\ +}\ + +/*----------------------------------------------------------------------------- + Initialize : mod_rate, center_pos_mod, and index rate + + center_pos_mod is initialized so that the delay between center_pos_mod and + line_in is: mod_depth + INTERP_SAMPLES_NBR. + + @param chorus pointer on chorus unit. +-----------------------------------------------------------------------------*/ +static void set_center_position(fluid_chorus_t *chorus) +{ + int center; + + /* Sets the modulation rate. This rate defines how often + the center position (center_pos_mod ) is modulated . + The value is expressed in samples. The default value is 1 that means that + center_pos_mod is updated at every sample. + For example with a value of 2, the center position position will be + updated only one time every 2 samples only. + */ + chorus->mod_rate = LOW_MOD_RATE; /* default modulation rate */ + + /* compensate mod rate for high modulation depth */ + if(chorus->mod_depth > LOW_MOD_DEPTH) + { + int delta_mod_depth = (chorus->mod_depth - LOW_MOD_DEPTH); + chorus->mod_rate += (delta_mod_depth * RANGE_MOD_RATE) / RANGE_MOD_DEPTH; + } + + /* Initializes the modulated center position (center_pos_mod) so that: + - the delay between center_pos_mod and line_in is: + mod_depth + INTERP_SAMPLES_NBR. + */ + center = chorus->line_in - (INTERP_SAMPLES_NBR + chorus->mod_depth); + + if(center < 0) + { + center += chorus->size; + } + + chorus->center_pos_mod = (fluid_real_t)center; + + /* index rate to control when to update center_pos_mod */ + /* Important: must be set to get center_pos_mod immediately used for the + reading of first sample (see get_mod_delay()) */ + chorus->index_rate = chorus->mod_rate; +} + +/*----------------------------------------------------------------------------- + Update internal parameters dependent of sample rate. + - mod_depth. + - mod_rate, center_pos_mod, and index rate. + - modulators frequency. + + @param chorus, pointer on chorus unit. +-----------------------------------------------------------------------------*/ +static void update_parameters_from_sample_rate(fluid_chorus_t *chorus) +{ + int i; + + /* initialize modulation depth (peak to peak) (in samples) */ + /* convert modulation depth in ms to sample number */ + chorus->mod_depth = (int)(chorus->depth_ms / 1000.0 + * chorus->sample_rate); + + /* the delay line is fixed. So we reduce mod_depth (if necessary) */ + if(chorus->mod_depth > MAX_SAMPLES) + { + FLUID_LOG(FLUID_WARN, "chorus: Too high depth. Setting it to max (%d).", + MAX_SAMPLES); + chorus->mod_depth = MAX_SAMPLES; + /* set depth_ms to maximum to avoid spamming console with above warning */ + chorus->depth_ms = (chorus->mod_depth * 1000) / chorus->sample_rate; + } + + chorus->mod_depth /= 2; /* amplitude is peak to peek / 2 */ +#ifdef DEBUG_PRINT + printf("depth_ms:%f, depth_samples/2:%d\n", chorus->depth_ms, chorus->mod_depth); +#endif + + /* Initializes the modulated center position: + mod_rate, center_pos_mod, and index rate. + */ + set_center_position(chorus); /* must be called before set_xxxx_frequency() */ +#ifdef DEBUG_PRINT + printf("mod_rate:%d\n", chorus->mod_rate); +#endif + + /* initialize modulator frequency */ + for(i = 0; i < chorus->number_blocks; i++) + { + set_sinus_frequency(&chorus->mod[i].sinus, + chorus->speed_Hz * chorus->mod_rate, + chorus->sample_rate, + /* phase offset between modulators waveform */ + (float)((360.0f / (float) chorus->number_blocks) * i)); + + set_triangle_frequency(&chorus->mod[i].triang, + chorus->speed_Hz * chorus->mod_rate, + chorus->sample_rate, + /* phase offset between modulators waveform */ + (float)i / chorus->number_blocks); + } +} + +/*----------------------------------------------------------------------------- + Modulated delay line initialization. + + Sets the length line ( alloc delay samples). + Remark: the function sets the internal size according to the length delay_length. + The size is augmented by INTERP_SAMPLES_NBR to take account of interpolation. + + @param chorus, pointer on chorus unit. + @param delay_length the length of the delay line in samples. + @return FLUID_OK if success , FLUID_FAILED if memory error. + + Return FLUID_OK if success, FLUID_FAILED if memory error. +-----------------------------------------------------------------------------*/ +static int new_mod_delay_line(fluid_chorus_t *chorus, int delay_length) +{ + /*-----------------------------------------------------------------------*/ + /* checks parameter */ + if(delay_length < 1) + { + return FLUID_FAILED; + } + + chorus->mod_depth = 0; + /*----------------------------------------------------------------------- + allocates delay_line and initialize members: - line, size, line_in... + */ + /* total size of the line: size = INTERP_SAMPLES_NBR + delay_length */ + chorus->size = delay_length + INTERP_SAMPLES_NBR; + chorus->line = FLUID_ARRAY(fluid_real_t, chorus->size); + + if(! chorus->line) + { + return FLUID_FAILED; + } + + /* clears the buffer: + - delay line + - interpolator member: buffer, frac_pos_mod + */ + fluid_chorus_reset(chorus); + + /* Initializes line_in to the start of the buffer */ + chorus->line_in = 0; + /*------------------------------------------------------------------------ + Initializes modulation members: + - modulation rate (the speed at which center_pos_mod is modulated: mod_rate + - modulated center position: center_pos_mod + - index rate to know when to update center_pos_mod:index_rate + -------------------------------------------------------------------------*/ + /* Initializes the modulated center position: + mod_rate, center_pos_mod, and index rate + */ + set_center_position(chorus); + + return FLUID_OK; +} + +/*----------------------------------------------------------------------------- + API +------------------------------------------------------------------------------*/ +/** + * Create the chorus unit. Once created the chorus have no parameters set, so + * fluid_chorus_set() must be called at least one time after calling + * new_fluid_chorus(). + * + * @param sample_rate, audio sample rate in Hz. + * @return pointer on chorus unit. + */ +fluid_chorus_t * +new_fluid_chorus(fluid_real_t sample_rate) +{ + fluid_chorus_t *chorus; + + chorus = FLUID_NEW(fluid_chorus_t); + + if(chorus == NULL) + { + FLUID_LOG(FLUID_PANIC, "chorus: Out of memory"); + return NULL; + } + + FLUID_MEMSET(chorus, 0, sizeof(fluid_chorus_t)); + + chorus->sample_rate = sample_rate; + +#ifdef DEBUG_PRINT + printf("fluid_chorus_t:%d bytes\n", sizeof(fluid_chorus_t)); + printf("fluid_real_t:%d bytes\n", sizeof(fluid_real_t)); +#endif + +#ifdef DEBUG_PRINT + printf("NEW_MOD\n"); +#endif + + if(new_mod_delay_line(chorus, MAX_SAMPLES) == FLUID_FAILED) + { + delete_fluid_chorus(chorus); + return NULL; + } + + return chorus; +} + +/** + * Delete the chorus unit. + * @param chorus pointer on chorus unit returned by new_fluid_chorus(). + */ +void +delete_fluid_chorus(fluid_chorus_t *chorus) +{ + fluid_return_if_fail(chorus != NULL); + + FLUID_FREE(chorus->line); + FLUID_FREE(chorus); +} + +/** + * Clear the internal delay line and associate filter. + * @param chorus pointer on chorus unit returned by new_fluid_chorus(). + */ +void +fluid_chorus_reset(fluid_chorus_t *chorus) +{ + int i; + unsigned int u; + + /* reset delay line */ + for(i = 0; i < chorus->size; i++) + { + chorus->line[i] = 0; + } + + /* reset modulators's allpass filter */ + for(u = 0; u < FLUID_N_ELEMENTS(chorus->mod); u++) + { + /* initializes 1st order All-Pass interpolator members */ + chorus->mod[u].buffer = 0; /* previous delay sample value */ + chorus->mod[u].frac_pos_mod = 0; /* fractional position (between consecutives sample) */ + } +} + +/** + * Set one or more chorus parameters. + * + * @param chorus Chorus instance. + * @param set Flags indicating which chorus parameters to set (#fluid_chorus_set_t). + * @param nr Chorus voice count (0-99, CPU time consumption proportional to + * this value). + * @param level Chorus level (0.0-10.0). + * @param speed Chorus speed in Hz (0.1-5.0). + * @param depth_ms Chorus depth (max value depends on synth sample rate, + * 0.0-21.0 is safe for sample rate values up to 96KHz). + * @param type Chorus waveform type (#fluid_chorus_mod). + */ +void +fluid_chorus_set(fluid_chorus_t *chorus, int set, int nr, fluid_real_t level, + fluid_real_t speed, fluid_real_t depth_ms, int type) +{ + if(set & FLUID_CHORUS_SET_NR) /* number of block */ + { + chorus->number_blocks = nr; + } + + if(set & FLUID_CHORUS_SET_LEVEL) /* output level */ + { + chorus->level = level; + } + + if(set & FLUID_CHORUS_SET_SPEED) /* lfo frequency (in Hz) */ + { + chorus->speed_Hz = speed; + } + + if(set & FLUID_CHORUS_SET_DEPTH) /* modulation depth (in ms) */ + { + chorus->depth_ms = depth_ms; + } + + if(set & FLUID_CHORUS_SET_TYPE) /* lfo shape (sinus, triangle) */ + { + chorus->type = type; + } + + /* check min , max parameters */ + if(chorus->number_blocks < 0) + { + FLUID_LOG(FLUID_WARN, "chorus: number blocks must be >=0! Setting value to 0."); + chorus->number_blocks = 0; + } + else if(chorus->number_blocks > MAX_CHORUS) + { + FLUID_LOG(FLUID_WARN, "chorus: number blocks larger than max. allowed! Setting value to %d.", + MAX_CHORUS); + chorus->number_blocks = MAX_CHORUS; + } + + if(chorus->speed_Hz < MIN_SPEED_HZ) + { + FLUID_LOG(FLUID_WARN, "chorus: speed is too low (min %f)! Setting value to min.", + (double) MIN_SPEED_HZ); + chorus->speed_Hz = MIN_SPEED_HZ; + } + else if(chorus->speed_Hz > MAX_SPEED_HZ) + { + FLUID_LOG(FLUID_WARN, "chorus: speed must be below %f Hz! Setting value to max.", + (double) MAX_SPEED_HZ); + chorus->speed_Hz = MAX_SPEED_HZ; + } + + if(chorus->depth_ms < 0.0) + { + FLUID_LOG(FLUID_WARN, "chorus: depth must be positive! Setting value to 0."); + chorus->depth_ms = 0.0; + } + + if(chorus->level < 0.0) + { + FLUID_LOG(FLUID_WARN, "chorus: level must be positive! Setting value to 0."); + chorus->level = 0.0; + } + else if(chorus->level > MAX_LEVEL) + { + FLUID_LOG(FLUID_WARN, "chorus: level must be < 10. A reasonable level is << 1! " + "Setting it to 0.1."); + chorus->level = 0.1; + } + + /* update parameters dependent of sample rate */ + update_parameters_from_sample_rate(chorus); + +#ifdef DEBUG_PRINT + printf("lfo type:%d\n", chorus->type); + printf("speed_Hz:%f\n", chorus->speed_Hz); +#endif + + /* Initialize the lfo waveform */ + if((chorus->type != FLUID_CHORUS_MOD_SINE) && + (chorus->type != FLUID_CHORUS_MOD_TRIANGLE)) + { + FLUID_LOG(FLUID_WARN, "chorus: Unknown modulation type. Using sinewave."); + chorus->type = FLUID_CHORUS_MOD_SINE; + } + +#ifdef DEBUG_PRINT + + if(chorus->type == FLUID_CHORUS_MOD_SINE) + { + printf("lfo: sinus\n"); + } + else + { + printf("lfo: triangle\n"); + } + + printf("nr:%d\n", chorus->number_blocks); +#endif + + /* Recalculate internal values after parameters change */ + + /* + Note: + Actually WIDTH is fixed to maximum value. But in the future we could add a setting + "synth.chorus.width" to allow a gradually stereo effect from minimum (monophonic) to + maximum stereo effect. + If this setting will be added, remove the following instruction. + */ + chorus->width = WIDTH; + { + /* The stereo amplitude equation (wet1 and wet2 below) have a + tendency to produce high amplitude with high width values ( 1 < width < 10). + This results in an unwanted noisy output clipped by the audio card. + To avoid this dependency, we divide by (1 + chorus->width * SCALE_WET_WIDTH) + Actually, with a SCALE_WET_WIDTH of 0.2, (regardless of level setting), + the output amplitude (wet) seems rather independent of width setting */ + + fluid_real_t wet = chorus->level * SCALE_WET ; + + /* wet1 and wet2 are used by the stereo effect controlled by the width setting + for producing a stereo ouptput from a monophonic chorus signal. + Please see the note above about a side effect tendency */ + + if(chorus->number_blocks > 1) + { + wet = wet / (1.0f + chorus->width * SCALE_WET_WIDTH); + chorus->wet1 = wet * (chorus->width / 2.0f + 0.5f); + chorus->wet2 = wet * ((1.0f - chorus->width) / 2.0f); +#ifdef DEBUG_PRINT + printf("width:%f\n", chorus->width); + + if(chorus->width > 0) + { + printf("nr > 1, width > 0 => out stereo\n"); + } + else + { + printf("nr > 1, width:0 =>out mono\n"); + } + +#endif + } + else + { + /* only one chorus block */ + if(chorus->width == 0.0) + { + /* wet1 and wet2 should make stereo output monomophic */ + chorus->wet1 = chorus->wet2 = wet; + } + else + { + /* for width > 0, wet1 and wet2 should make stereo output stereo + with only one block. This will only possible by inverting + the unique signal on each left and right output. + Note however that with only one block, it isn't possible to + have a graduate width effect */ + chorus->wet1 = wet; + chorus->wet2 = -wet; /* inversion */ + } + +#ifdef DEBUG_PRINT + printf("width:%f\n", chorus->width); + + if(chorus->width != 0) + { + printf("one block, width > 0 => out stereo\n"); + } + else + { + printf("one block, width:0 => out mono\n"); + } + +#endif + } + } +} + +/* +* Applies a sample rate change on the chorus. +* Note that while the chorus is used by calling any fluid_chorus_processXXX() +* function, calling fluid_chorus_samplerate_change() isn't multi task safe. +* To deal properly with this issue follow the steps: +* 1) Stop chorus processing (i.e disable calling to any fluid_chorus_processXXX(). +* chorus functions. +* 2) Change sample rate by calling fluid_chorus_samplerate_change(). +* 3) Restart chorus processing (i.e enabling calling any fluid_chorus_processXXX() +* chorus functions. +* +* Another solution is to substitute step (2): +* 2.1) delete the chorus by calling delete_fluid_chorus(). +* 2.2) create the chorus by calling new_fluid_chorus(). +* +* @param chorus pointer on the chorus. +* @param sample_rate new sample rate value. +*/ +void +fluid_chorus_samplerate_change(fluid_chorus_t *chorus, fluid_real_t sample_rate) +{ + chorus->sample_rate = sample_rate; + + /* update parameters dependent of sample rate */ + update_parameters_from_sample_rate(chorus); +} + +/** + * Process chorus by mixing the result in output buffer. + * @param chorus pointer on chorus unit returned by new_fluid_chorus(). + * @param in, pointer on monophonic input buffer of FLUID_BUFSIZE samples. + * @param left_out, right_out, pointers on stereo output buffers of + * FLUID_BUFSIZE samples. + */ +void fluid_chorus_processmix(fluid_chorus_t *chorus, const fluid_real_t *in, + fluid_real_t *left_out, fluid_real_t *right_out) +{ + int sample_index; + int i; + fluid_real_t d_out[2]; /* output stereo Left and Right */ + + /* foreach sample, process output sample then input sample */ + for(sample_index = 0; sample_index < FLUID_BUFSIZE; sample_index++) + { + fluid_real_t out; /* block output */ + + d_out[0] = d_out[1] = 0.0f; /* clear stereo unit input */ + +#if 0 + /* Debug: Listen to the chorus signal only */ + left_out[sample_index] = 0; + right_out[sample_index] = 0; +#endif + + ++chorus->index_rate; /* modulator rate */ + + /* foreach chorus block, process output sample */ + for(i = 0; i < chorus->number_blocks; i++) + { + /* get sample from the output of modulated delay line */ + out = get_mod_delay(chorus, &chorus->mod[i]); + + /* accumulate out into stereo unit input */ + d_out[i & 1] += out; + } + + /* update modulator index rate and output center position */ + if(chorus->index_rate >= chorus->mod_rate) + { + chorus->index_rate = 0; /* clear modulator index rate */ + + /* updates center position (center_pos_mod) to the next position + specified by modulation rate */ + if((chorus->center_pos_mod += chorus->mod_rate) >= chorus->size) + { + chorus->center_pos_mod -= chorus->size; + } + } + + /* Adjust stereo input level in case of number_blocks odd: + In those case, d_out[1] level is lower than d_out[0], so we need to + add out value to d_out[1] to have d_out[0] and d_out[1] balanced. + */ + if((i & 1) && i > 2) // i = 3,5,7... + { + d_out[1] += out ; + } + + /* Write the current input sample into the circular buffer. + * Note that 'in' may be aliased with 'left_out'. Hence this must be done + * before "processing stereo unit" (below). This ensures input buffer + * not being overwritten by stereo unit output. + */ + push_in_delay_line(chorus, in[sample_index]); + + /* process stereo unit */ + /* Add the chorus stereo unit d_out to left and right output */ + left_out[sample_index] += d_out[0] * chorus->wet1 + d_out[1] * chorus->wet2; + right_out[sample_index] += d_out[1] * chorus->wet1 + d_out[0] * chorus->wet2; + } +} + +/** + * Process chorus by putting the result in output buffer (no mixing). + * @param chorus pointer on chorus unit returned by new_fluid_chorus(). + * @param in, pointer on monophonic input buffer of FLUID_BUFSIZE samples. + * @param left_out, right_out, pointers on stereo output buffers of + * FLUID_BUFSIZE samples. + */ +/* Duplication of code ... (replaces sample data instead of mixing) */ +void fluid_chorus_processreplace(fluid_chorus_t *chorus, const fluid_real_t *in, + fluid_real_t *left_out, fluid_real_t *right_out) +{ + int sample_index; + int i; + fluid_real_t d_out[2]; /* output stereo Left and Right */ + + /* foreach sample, process output sample then input sample */ + for(sample_index = 0; sample_index < FLUID_BUFSIZE; sample_index++) + { + fluid_real_t out; /* block output */ + + d_out[0] = d_out[1] = 0.0f; /* clear stereo unit input */ + +#if 0 + /* Debug: Listen to the chorus signal only */ + left_out[sample_index] = 0; + right_out[sample_index] = 0; +#endif + + ++chorus->index_rate; /* modulator rate */ + + /* foreach chorus block, process output sample */ + for(i = 0; i < chorus->number_blocks; i++) + { + /* get sample from the output of modulated delay line */ + out = get_mod_delay(chorus, &chorus->mod[i]); + + /* accumulate out into stereo unit input */ + d_out[i & 1] += out; + } + + /* update modulator index rate and output center position */ + if(chorus->index_rate >= chorus->mod_rate) + { + chorus->index_rate = 0; /* clear modulator index rate */ + + /* updates center position (center_pos_mod) to the next position + specified by modulation rate */ + if((chorus->center_pos_mod += chorus->mod_rate) >= chorus->size) + { + chorus->center_pos_mod -= chorus->size; + } + } + + /* Adjust stereo input level in case of number_blocks odd: + In those case, d_out[1] level is lower than d_out[0], so we need to + add out value to d_out[1] to have d_out[0] and d_out[1] balanced. + */ + if((i & 1) && i > 2) // i = 3,5,7... + { + d_out[1] += out ; + } + + /* Write the current input sample into the circular buffer. + * Note that 'in' may be aliased with 'left_out'. Hence this must be done + * before "processing stereo unit" (below). This ensures input buffer + * not being overwritten by stereo unit output. + */ + push_in_delay_line(chorus, in[sample_index]); + + /* process stereo unit */ + /* store the chorus stereo unit d_out to left and right output */ + left_out[sample_index] = d_out[0] * chorus->wet1 + d_out[1] * chorus->wet2; + right_out[sample_index] = d_out[1] * chorus->wet1 + d_out[0] * chorus->wet2; + } +} diff --git a/libs/fluidsynth/src/rvoice/fluid_chorus.h b/libs/fluidsynth/src/rvoice/fluid_chorus.h new file mode 100644 index 00000000000..c6d247fa5f3 --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_chorus.h @@ -0,0 +1,80 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#ifndef _FLUID_CHORUS_H +#define _FLUID_CHORUS_H + +#include "fluidsynth_priv.h" + + +typedef struct _fluid_chorus_t fluid_chorus_t; + +/* enum describing each chorus parameter */ +enum fluid_chorus_param +{ + FLUID_CHORUS_NR, /**< number of delay line */ + FLUID_CHORUS_LEVEL, /**< output level */ + FLUID_CHORUS_SPEED, /**< lfo frequency */ + FLUID_CHORUS_DEPTH, /**< modulation depth */ + FLUID_CHORUS_TYPE, /**< type of waveform */ + FLUID_CHORUS_PARAM_LAST /* number of enum fluid_chorus_param */ +}; + +/* return a bit flag from param: 2^param */ +#define FLUID_CHORPARAM_TO_SETFLAG(param) (1 << param) + +/** Flags for fluid_chorus_set() */ +typedef enum +{ + FLUID_CHORUS_SET_NR = FLUID_CHORPARAM_TO_SETFLAG(FLUID_CHORUS_NR), + FLUID_CHORUS_SET_LEVEL = FLUID_CHORPARAM_TO_SETFLAG(FLUID_CHORUS_LEVEL), + FLUID_CHORUS_SET_SPEED = FLUID_CHORPARAM_TO_SETFLAG(FLUID_CHORUS_SPEED), + FLUID_CHORUS_SET_DEPTH = FLUID_CHORPARAM_TO_SETFLAG(FLUID_CHORUS_DEPTH), + FLUID_CHORUS_SET_TYPE = FLUID_CHORPARAM_TO_SETFLAG(FLUID_CHORUS_TYPE), + + /** Value for fluid_chorus_set() which sets all chorus parameters. */ + FLUID_CHORUS_SET_ALL = FLUID_CHORUS_SET_NR + | FLUID_CHORUS_SET_LEVEL + | FLUID_CHORUS_SET_SPEED + | FLUID_CHORUS_SET_DEPTH + | FLUID_CHORUS_SET_TYPE, +} fluid_chorus_set_t; + +/* + * chorus + */ +fluid_chorus_t *new_fluid_chorus(fluid_real_t sample_rate); +void delete_fluid_chorus(fluid_chorus_t *chorus); +void fluid_chorus_reset(fluid_chorus_t *chorus); + +void fluid_chorus_set(fluid_chorus_t *chorus, int set, int nr, fluid_real_t level, + fluid_real_t speed, fluid_real_t depth_ms, int type); +void +fluid_chorus_samplerate_change(fluid_chorus_t *chorus, fluid_real_t sample_rate); + +void fluid_chorus_processmix(fluid_chorus_t *chorus, const fluid_real_t *in, + fluid_real_t *left_out, fluid_real_t *right_out); +void fluid_chorus_processreplace(fluid_chorus_t *chorus, const fluid_real_t *in, + fluid_real_t *left_out, fluid_real_t *right_out); + + + +#endif /* _FLUID_CHORUS_H */ diff --git a/libs/fluidsynth/src/rvoice/fluid_iir_filter.c b/libs/fluidsynth/src/rvoice/fluid_iir_filter.c new file mode 100644 index 00000000000..764fcf4abd8 --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_iir_filter.c @@ -0,0 +1,418 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include "fluid_iir_filter.h" +#include "fluid_sys.h" +#include "fluid_conv.h" + +/** + * Applies a low- or high-pass filter with variable cutoff frequency and quality factor + * for a given biquad transfer function: + * b0 + b1*z^-1 + b2*z^-2 + * H(z) = ------------------------ + * a0 + a1*z^-1 + a2*z^-2 + * + * Also modifies filter state accordingly. + * @param iir_filter Filter parameter + * @param dsp_buf Pointer to the synthesized audio data + * @param count Count of samples in dsp_buf + */ +/* + * Variable description: + * - dsp_a1, dsp_a2: Filter coefficients for the the previously filtered output signal + * - dsp_b0, dsp_b1, dsp_b2: Filter coefficients for input signal + * - coefficients normalized to a0 + * + * A couple of variables are used internally, their results are discarded: + * - dsp_i: Index through the output buffer + * - dsp_centernode: delay line for the IIR filter + * - dsp_hist1: same + * - dsp_hist2: same + */ +void +fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, + fluid_real_t *dsp_buf, int count) +{ + if(iir_filter->type == FLUID_IIR_DISABLED || iir_filter->q_lin == 0) + { + return; + } + else + { + /* IIR filter sample history */ + fluid_real_t dsp_hist1 = iir_filter->hist1; + fluid_real_t dsp_hist2 = iir_filter->hist2; + + /* IIR filter coefficients */ + fluid_real_t dsp_a1 = iir_filter->a1; + fluid_real_t dsp_a2 = iir_filter->a2; + fluid_real_t dsp_b02 = iir_filter->b02; + fluid_real_t dsp_b1 = iir_filter->b1; + int dsp_filter_coeff_incr_count = iir_filter->filter_coeff_incr_count; + + fluid_real_t dsp_centernode; + int dsp_i; + + /* filter (implement the voice filter according to SoundFont standard) */ + + /* Check for denormal number (too close to zero). */ + if(FLUID_FABS(dsp_hist1) < 1e-20f) + { + dsp_hist1 = 0.0f; /* FIXME JMG - Is this even needed? */ + } + + /* Two versions of the filter loop. One, while the filter is + * changing towards its new setting. The other, if the filter + * doesn't change. + */ + + if(dsp_filter_coeff_incr_count > 0) + { + fluid_real_t dsp_a1_incr = iir_filter->a1_incr; + fluid_real_t dsp_a2_incr = iir_filter->a2_incr; + fluid_real_t dsp_b02_incr = iir_filter->b02_incr; + fluid_real_t dsp_b1_incr = iir_filter->b1_incr; + + + /* Increment is added to each filter coefficient filter_coeff_incr_count times. */ + for(dsp_i = 0; dsp_i < count; dsp_i++) + { + /* The filter is implemented in Direct-II form. */ + dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2; + dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1; + dsp_hist2 = dsp_hist1; + dsp_hist1 = dsp_centernode; + + if(dsp_filter_coeff_incr_count-- > 0) + { + fluid_real_t old_b02 = dsp_b02; + dsp_a1 += dsp_a1_incr; + dsp_a2 += dsp_a2_incr; + dsp_b02 += dsp_b02_incr; + dsp_b1 += dsp_b1_incr; + + /* Compensate history to avoid the filter going havoc with large frequency changes */ + if(iir_filter->compensate_incr && FLUID_FABS(dsp_b02) > 0.001f) + { + fluid_real_t compensate = old_b02 / dsp_b02; + dsp_hist1 *= compensate; + dsp_hist2 *= compensate; + } + } + } /* for dsp_i */ + } + else /* The filter parameters are constant. This is duplicated to save time. */ + { + for(dsp_i = 0; dsp_i < count; dsp_i++) + { + /* The filter is implemented in Direct-II form. */ + dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2; + dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1; + dsp_hist2 = dsp_hist1; + dsp_hist1 = dsp_centernode; + } + } + + iir_filter->hist1 = dsp_hist1; + iir_filter->hist2 = dsp_hist2; + iir_filter->a1 = dsp_a1; + iir_filter->a2 = dsp_a2; + iir_filter->b02 = dsp_b02; + iir_filter->b1 = dsp_b1; + iir_filter->filter_coeff_incr_count = dsp_filter_coeff_incr_count; + + fluid_check_fpe("voice_filter"); + } +} + + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_init) +{ + fluid_iir_filter_t *iir_filter = obj; + enum fluid_iir_filter_type type = param[0].i; + enum fluid_iir_filter_flags flags = param[1].i; + + iir_filter->type = type; + iir_filter->flags = flags; + + if(type != FLUID_IIR_DISABLED) + { + fluid_iir_filter_reset(iir_filter); + } +} + +void +fluid_iir_filter_reset(fluid_iir_filter_t *iir_filter) +{ + iir_filter->hist1 = 0; + iir_filter->hist2 = 0; + iir_filter->last_fres = -1.; + iir_filter->q_lin = 0; + iir_filter->filter_startup = 1; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_fres) +{ + fluid_iir_filter_t *iir_filter = obj; + fluid_real_t fres = param[0].real; + + iir_filter->fres = fres; + iir_filter->last_fres = -1.; +} + +static fluid_real_t fluid_iir_filter_q_from_dB(fluid_real_t q_dB) +{ + /* The generator contains 'centibels' (1/10 dB) => divide by 10 to + * obtain dB */ + q_dB /= 10.0f; + + /* Range: SF2.01 section 8.1.3 # 8 (convert from cB to dB => /10) */ + fluid_clip(q_dB, 0.0f, 96.0f); + + /* Short version: Modify the Q definition in a way, that a Q of 0 + * dB leads to no resonance hump in the freq. response. + * + * Long version: From SF2.01, page 39, item 9 (initialFilterQ): + * "The gain at the cutoff frequency may be less than zero when + * zero is specified". Assume q_dB=0 / q_lin=1: If we would leave + * q as it is, then this results in a 3 dB hump slightly below + * fc. At fc, the gain is exactly the DC gain (0 dB). What is + * (probably) meant here is that the filter does not show a + * resonance hump for q_dB=0. In this case, the corresponding + * q_lin is 1/sqrt(2)=0.707. The filter should have 3 dB of + * attenuation at fc now. In this case Q_dB is the height of the + * resonance peak not over the DC gain, but over the frequency + * response of a non-resonant filter. This idea is implemented as + * follows: */ + q_dB -= 3.01f; + + /* The 'sound font' Q is defined in dB. The filter needs a linear + q. Convert. */ + return FLUID_POW(10.0f, q_dB / 20.0f); +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_q) +{ + fluid_iir_filter_t *iir_filter = obj; + fluid_real_t q = param[0].real; + int flags = iir_filter->flags; + + if(flags & FLUID_IIR_Q_ZERO_OFF && q <= 0.0) + { + q = 0; + } + else if(flags & FLUID_IIR_Q_LINEAR) + { + /* q is linear (only for user-defined filter) + * increase to avoid Q being somewhere between zero and one, + * which results in some strange amplified lowpass signal + */ + q++; + } + else + { + q = fluid_iir_filter_q_from_dB(q); + } + + iir_filter->q_lin = q; + iir_filter->filter_gain = 1.0; + + if(!(flags & FLUID_IIR_NO_GAIN_AMP)) + { + /* SF 2.01 page 59: + * + * The SoundFont specs ask for a gain reduction equal to half the + * height of the resonance peak (Q). For example, for a 10 dB + * resonance peak, the gain is reduced by 5 dB. This is done by + * multiplying the total gain with sqrt(1/Q). `Sqrt' divides dB + * by 2 (100 lin = 40 dB, 10 lin = 20 dB, 3.16 lin = 10 dB etc) + * The gain is later factored into the 'b' coefficients + * (numerator of the filter equation). This gain factor depends + * only on Q, so this is the right place to calculate it. + */ + iir_filter->filter_gain /= FLUID_SQRT(q); + } + + /* The synthesis loop will have to recalculate the filter coefficients. */ + iir_filter->last_fres = -1.; +} + +static FLUID_INLINE void +fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t *iir_filter, + int transition_samples, + fluid_real_t output_rate) +{ + /* FLUID_IIR_Q_LINEAR may switch the filter off by setting Q==0 */ + if(iir_filter->q_lin == 0) + { + return; + } + else + { + /* + * Those equations from Robert Bristow-Johnson's `Cookbook + * formulae for audio EQ biquad filter coefficients', obtained + * from Harmony-central.com / Computer / Programming. They are + * the result of the bilinear transform on an analogue filter + * prototype. To quote, `BLT frequency warping has been taken + * into account for both significant frequency relocation and for + * bandwidth readjustment'. */ + + fluid_real_t omega = (fluid_real_t)(2.0 * M_PI) * + (iir_filter->last_fres / output_rate); + fluid_real_t sin_coeff = FLUID_SIN(omega); + fluid_real_t cos_coeff = FLUID_COS(omega); + fluid_real_t alpha_coeff = sin_coeff / (2.0f * iir_filter->q_lin); + fluid_real_t a0_inv = 1.0f / (1.0f + alpha_coeff); + + /* Calculate the filter coefficients. All coefficients are + * normalized by a0. Think of `a1' as `a1/a0'. + * + * Here a couple of multiplications are saved by reusing common expressions. + * The original equations should be: + * iir_filter->b0=(1.-cos_coeff)*a0_inv*0.5*iir_filter->filter_gain; + * iir_filter->b1=(1.-cos_coeff)*a0_inv*iir_filter->filter_gain; + * iir_filter->b2=(1.-cos_coeff)*a0_inv*0.5*iir_filter->filter_gain; */ + + /* "a" coeffs are same for all 3 available filter types */ + fluid_real_t a1_temp = -2.0f * cos_coeff * a0_inv; + fluid_real_t a2_temp = (1.0f - alpha_coeff) * a0_inv; + + fluid_real_t b02_temp, b1_temp; + + switch(iir_filter->type) + { + case FLUID_IIR_HIGHPASS: + b1_temp = (1.0f + cos_coeff) * a0_inv * iir_filter->filter_gain; + + /* both b0 -and- b2 */ + b02_temp = b1_temp * 0.5f; + + b1_temp *= -1.0f; + break; + + case FLUID_IIR_LOWPASS: + b1_temp = (1.0f - cos_coeff) * a0_inv * iir_filter->filter_gain; + + /* both b0 -and- b2 */ + b02_temp = b1_temp * 0.5f; + break; + + default: + /* filter disabled, should never get here */ + return; + } + + iir_filter->compensate_incr = 0; + + if(iir_filter->filter_startup || (transition_samples == 0)) + { + /* The filter is calculated, because the voice was started up. + * In this case set the filter coefficients without delay. + */ + iir_filter->a1 = a1_temp; + iir_filter->a2 = a2_temp; + iir_filter->b02 = b02_temp; + iir_filter->b1 = b1_temp; + iir_filter->filter_coeff_incr_count = 0; + iir_filter->filter_startup = 0; +// printf("Setting initial filter coefficients.\n"); + } + else + { + + /* The filter frequency is changed. Calculate an increment + * factor, so that the new setting is reached after one buffer + * length. x_incr is added to the current value FLUID_BUFSIZE + * times. The length is arbitrarily chosen. Longer than one + * buffer will sacrifice some performance, though. Note: If + * the filter is still too 'grainy', then increase this number + * at will. + */ + + iir_filter->a1_incr = (a1_temp - iir_filter->a1) / transition_samples; + iir_filter->a2_incr = (a2_temp - iir_filter->a2) / transition_samples; + iir_filter->b02_incr = (b02_temp - iir_filter->b02) / transition_samples; + iir_filter->b1_incr = (b1_temp - iir_filter->b1) / transition_samples; + + if(FLUID_FABS(iir_filter->b02) > 0.0001f) + { + fluid_real_t quota = b02_temp / iir_filter->b02; + iir_filter->compensate_incr = quota < 0.5f || quota > 2.f; + } + + /* Have to add the increments filter_coeff_incr_count times. */ + iir_filter->filter_coeff_incr_count = transition_samples; + } + + fluid_check_fpe("voice_write filter calculation"); + } +} + + +void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter, + fluid_real_t output_rate, + fluid_real_t fres_mod) +{ + fluid_real_t fres; + + /* calculate the frequency of the resonant filter in Hz */ + fres = fluid_ct2hz(iir_filter->fres + fres_mod); + + /* FIXME - Still potential for a click during turn on, can we interpolate + between 20khz cutoff and 0 Q? */ + + /* I removed the optimization of turning the filter off when the + * resonance frequency is above the maximum frequency. Instead, the + * filter frequency is set to a maximum of 0.45 times the sampling + * rate. For a 44100 kHz sampling rate, this amounts to 19845 + * Hz. The reason is that there were problems with anti-aliasing when the + * synthesizer was run at lower sampling rates. Thanks to Stephan + * Tassart for pointing me to this bug. By turning the filter on and + * clipping the maximum filter frequency at 0.45*srate, the filter + * is used as an anti-aliasing filter. */ + + if(fres > 0.45f * output_rate) + { + fres = 0.45f * output_rate; + } + else if(fres < 5.f) + { + fres = 5.f; + } + + /* if filter enabled and there is a significant frequency change.. */ + if(iir_filter->type != FLUID_IIR_DISABLED && FLUID_FABS(fres - iir_filter->last_fres) > 0.01f) + { + /* The filter coefficients have to be recalculated (filter + * parameters have changed). Recalculation for various reasons is + * forced by setting last_fres to -1. The flag filter_startup + * indicates, that the DSP loop runs for the first time, in this + * case, the filter is set directly, instead of smoothly fading + * between old and new settings. */ + iir_filter->last_fres = fres; + fluid_iir_filter_calculate_coefficients(iir_filter, FLUID_BUFSIZE, + output_rate); + } + + + fluid_check_fpe("voice_write DSP coefficients"); + +} diff --git a/libs/fluidsynth/src/rvoice/fluid_iir_filter.h b/libs/fluidsynth/src/rvoice/fluid_iir_filter.h new file mode 100644 index 00000000000..571027897eb --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_iir_filter.h @@ -0,0 +1,74 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUID_IIR_FILTER_H +#define _FLUID_IIR_FILTER_H + +#include "fluidsynth_priv.h" + +typedef struct _fluid_iir_filter_t fluid_iir_filter_t; + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_init); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_fres); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_q); + +void fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, + fluid_real_t *dsp_buf, int dsp_buf_count); + +void fluid_iir_filter_reset(fluid_iir_filter_t *iir_filter); + +void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter, + fluid_real_t output_rate, + fluid_real_t fres_mod); + +/* We can't do information hiding here, as fluid_voice_t includes the struct + without a pointer. */ +struct _fluid_iir_filter_t +{ + enum fluid_iir_filter_type type; /* specifies the type of this filter */ + enum fluid_iir_filter_flags flags; /* additional flags to customize this filter */ + + /* filter coefficients */ + /* The coefficients are normalized to a0. */ + /* b0 and b2 are identical => b02 */ + fluid_real_t b02; /* b0 / a0 */ + fluid_real_t b1; /* b1 / a0 */ + fluid_real_t a1; /* a0 / a0 */ + fluid_real_t a2; /* a1 / a0 */ + + fluid_real_t b02_incr; + fluid_real_t b1_incr; + fluid_real_t a1_incr; + fluid_real_t a2_incr; + int filter_coeff_incr_count; + int compensate_incr; /* Flag: If set, must compensate history */ + fluid_real_t hist1, hist2; /* Sample history for the IIR filter */ + int filter_startup; /* Flag: If set, the filter will be set directly. + Else it changes smoothly. */ + + fluid_real_t fres; /* the resonance frequency, in cents (not absolute cents) */ + fluid_real_t last_fres; /* Current resonance frequency of the IIR filter */ + /* Serves as a flag: A deviation between fres and last_fres */ + /* indicates, that the filter has to be recalculated. */ + fluid_real_t q_lin; /* the q-factor on a linear scale */ + fluid_real_t filter_gain; /* Gain correction factor, depends on q */ +}; + +#endif diff --git a/libs/fluidsynth/src/rvoice/fluid_lfo.c b/libs/fluidsynth/src/rvoice/fluid_lfo.c new file mode 100644 index 00000000000..ae21cdd0f72 --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_lfo.c @@ -0,0 +1,17 @@ +#include "fluid_lfo.h" + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_lfo_set_incr) +{ + fluid_lfo_t *lfo = obj; + fluid_real_t increment = param[0].real; + + lfo->increment = increment; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_lfo_set_delay) +{ + fluid_lfo_t *lfo = obj; + unsigned int delay = param[0].i; + + lfo->delay = delay; +} diff --git a/libs/fluidsynth/src/rvoice/fluid_lfo.h b/libs/fluidsynth/src/rvoice/fluid_lfo.h new file mode 100644 index 00000000000..9a439498213 --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_lfo.h @@ -0,0 +1,74 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUID_LFO_H +#define _FLUID_LFO_H + +#include "fluid_sys.h" + +typedef struct _fluid_lfo_t fluid_lfo_t; + +struct _fluid_lfo_t +{ + fluid_real_t val; /* the current value of the LFO */ + unsigned int delay; /* the delay of the lfo in samples */ + fluid_real_t increment; /* the lfo frequency is converted to a per-buffer increment */ +}; + +static FLUID_INLINE void +fluid_lfo_reset(fluid_lfo_t *lfo) +{ + lfo->val = 0.0f; +} + +// These two cannot be inlined since they're used by event_dispatch +DECLARE_FLUID_RVOICE_FUNCTION(fluid_lfo_set_incr); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_lfo_set_delay); + +static FLUID_INLINE fluid_real_t +fluid_lfo_get_val(fluid_lfo_t *lfo) +{ + return lfo->val; +} + +static FLUID_INLINE void +fluid_lfo_calc(fluid_lfo_t *lfo, unsigned int cur_delay) +{ + if(cur_delay < lfo->delay) + { + return; + } + + lfo->val += lfo->increment; + + if(lfo->val > (fluid_real_t) 1.0) + { + lfo->increment = -lfo->increment; + lfo->val = (fluid_real_t) 2.0 - lfo->val; + } + else if(lfo->val < (fluid_real_t) -1.0) + { + lfo->increment = -lfo->increment; + lfo->val = (fluid_real_t) -2.0 - lfo->val; + } + +} + +#endif diff --git a/libs/fluidsynth/src/rvoice/fluid_phase.h b/libs/fluidsynth/src/rvoice/fluid_phase.h new file mode 100644 index 00000000000..44df6b249fc --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_phase.h @@ -0,0 +1,113 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#ifndef _FLUID_PHASE_H +#define _FLUID_PHASE_H + +/* + * phase + */ + +#define FLUID_INTERP_BITS 8 +#define FLUID_INTERP_BITS_MASK 0xff000000 +#define FLUID_INTERP_BITS_SHIFT 24 + + +#define FLUID_FRACT_MAX ((double)4294967296.0) + +/* fluid_phase_t +* Purpose: +* Playing pointer for voice playback +* +* When a sample is played back at a different pitch, the playing pointer in the +* source sample will not advance exactly one sample per output sample. +* This playing pointer is implemented using fluid_phase_t. +* It is a 64 bit number. The higher 32 bits contain the 'index' (number of +* the current sample), the lower 32 bits the fractional part. +*/ +typedef uint64_t fluid_phase_t; + +/* Purpose: + * Set a to b. + * a: fluid_phase_t + * b: fluid_phase_t + */ +#define fluid_phase_set(a,b) a=b; + +#define fluid_phase_set_int(a, b) ((a) = ((uint64_t)(b)) << 32) + +/* Purpose: + * Sets the phase a to a phase increment given in b. + * For example, assume b is 0.9. After setting a to it, adding a to + * the playing pointer will advance it by 0.9 samples. */ +#define fluid_phase_set_float(a, b) \ + (a) = (((uint64_t)(b)) << 32) \ + | (uint32_t) (((double)(b) - (int)(b)) * (double)FLUID_FRACT_MAX) + +/* create a fluid_phase_t from an index and a fraction value */ +#define fluid_phase_from_index_fract(index, fract) \ + ((((uint64_t)(index)) << 32) + (fract)) + +/* Purpose: + * Return the index and the fractional part, respectively. */ +#define fluid_phase_index(_x) \ + ((unsigned int)((_x) >> 32)) +#define fluid_phase_fract(_x) \ + ((uint32_t)((_x) & 0xFFFFFFFF)) + +/* Get the phase index with fractional rounding */ +#define fluid_phase_index_round(_x) \ + ((unsigned int)(((_x) + 0x80000000) >> 32)) + + +/* Purpose: + * Takes the fractional part of the argument phase and + * calculates the corresponding position in the interpolation table. + * The fractional position of the playing pointer is calculated with a quite high + * resolution (32 bits). It would be unpractical to keep a set of interpolation + * coefficients for each possible fractional part... + */ +#define fluid_phase_fract_to_tablerow(_x) \ + ((unsigned int)(fluid_phase_fract(_x) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT) + +#define fluid_phase_double(_x) \ + ((double)(fluid_phase_index(_x)) + ((double)fluid_phase_fract(_x) / FLUID_FRACT_MAX)) + +/* Purpose: + * Advance a by a step of b (both are fluid_phase_t). + */ +#define fluid_phase_incr(a, b) a += b + +/* Purpose: + * Subtract b from a (both are fluid_phase_t). + */ +#define fluid_phase_decr(a, b) a -= b + +/* Purpose: + * Subtract b samples from a. + */ +#define fluid_phase_sub_int(a, b) ((a) -= (uint64_t)(b) << 32) + +/* Purpose: + * Creates the expression a.index++. */ +#define fluid_phase_index_plusplus(a) (((a) += 0x100000000LL) + +#endif /* _FLUID_PHASE_H */ diff --git a/libs/fluidsynth/src/rvoice/fluid_rev.c b/libs/fluidsynth/src/rvoice/fluid_rev.c new file mode 100644 index 00000000000..11bc760832a --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_rev.c @@ -0,0 +1,1523 @@ +/****************************************************************************** + * FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + * + * FDN REVERB + * + * Freeverb used by fluidsynth (v.1.1.10 and previous) is based on + * Schroeder-Moorer reverberator: + * https://ccrma.stanford.edu/~jos/pasp/Freeverb.html + * + * This FDN reverberation is based on jot FDN reverberator. + * https://ccrma.stanford.edu/~jos/Reverb/FDN_Late_Reverberation.html + * Like Freeverb it is a late reverb which is convenient for Fluidsynth. + * + * + * .-------------------. + * .-----------------| | + * | - | Feedback | + * | .--------------| Matrix | + * | | |___________________| + * | | /|\ /|\ + * \|/ | .---------. .-------. | - | .------. + * .->+ ---->| Delay 0 |-|L.P.F 0|--*-------->| |-> out + * .---------. | | |_________| |_______| | | | left + * |Tone | | | - - | |Stereo| + * In ->|corrector|--* | - - | | unit | + * mono |_________| | \|/ .---------. .-------. | | |-> out + * ---->+ ->| Delay 7 |-|L.P.F 7|--------*-->| | right + * |_________| |_______| |______| + * /|\ /|\ /|\ /|\ + * | | | | + * roomsize --/ | width --/ | + * damp ------/ level ------/ + * + * It takes a monophonic input and produces a stereo output. + * + * The parameters are the same than for Freeverb. + * Also the default response of these parameters are the same than for Freeverb: + * - roomsize (0 to 1): control the reverb time from 0.7 to 12.5 s. + * This reverberation time is ofen called T60DC. + * + * - damp (0 to 1): controls the reverb time frequency dependency. + * This controls the reverb time for the frequency sample rate/2 + * + * When 0, the reverb time for high frequencies is the same as + * for DC frequency. + * When > 0, high frequencies have less reverb time than lower frequencies. + * + * - width (0 to 100): controls the left/right output separation. + * When 0, there are no separation and the signal on left and right. + * output is the same. This sounds like a monophonic signal. + * When 100, the separation between left and right is maximum. + * + * - level (0 to 1), controls the output level reverberation. + * + * This FDN reverb produces a better quality reverberation tail than Freeverb with + * far less ringing by using modulated delay lines that help to cancel + * the building of a lot of resonances in the reverberation tail even when + * using only 8 delays lines (NBR_DELAYS = 8) (default). + * + * The frequency density (often called "modal density" is one property that + * contributes to sound quality. Although 8 lines give good result, using 12 delays + * lines brings the overall frequency density quality a bit higher. + * This quality augmentation is noticeable particularly when using long reverb time + * (roomsize = 1) on solo instrument with long release time. Of course the cpu load + * augmentation is +50% relatively to 8 lines. + * + * As a general rule the reverberation tail quality is easier to perceive by ear + * when using: + * - percussive instruments (i.e piano and others). + * - long reverb time (roomsize = 1). + * - no damping (damp = 0). + * - Using headphone. Avoid using loud speaker, you will be quickly misguided by the + * natural reverberation of the room in which you are. + * + * The cpu load for 8 lines is a bit lower than for freeverb (- 3%), + * but higher for 12 lines (+ 41%). + * + * + * The memory consumption is less than for freeverb + * (see the results table below). + * + * Two macros are usable at compiler time: + * - NBR_DELAYS: number of delay lines. 8 (default) or 12. + * - ROOMSIZE_RESPONSE_LINEAR: allows to choose an alternate response of + * roomsize parameter. + * When this macro is not defined (the default), roomsize has the same + * response that Freeverb, that is: + * - roomsize (0 to 1) controls concave reverb time (0.7 to 12.5 s). + * + * When this macro is defined, roomsize behaves linearly: + * - roomsize (0 to 1) controls reverb time linearly (0.7 to 12.5 s). + * This linear response is convenient when using GUI controls. + * + * -------------------------------------------------------------------------- + * Compare table: + * Note: the cpu load in % are relative each to other. These values are + * given by the fluidsynth profile commands. + * -------------------------------------------------------------------------- + * reverb | NBR_DELAYS | Performances | memory size | quality + * | | (cpu_load: %) | (bytes)(see note) | + * ========================================================================== + * freeverb | 2 x 8 comb | 0.670 % | 204616 | ringing + * | 2 x 4 all-pass | | | + * ----------|--------------------------------------------------------------- + * FDN | 8 | 0.650 % | 112480 | far less + * modulated | |(feeverb - 3%) | (56% freeverb) | ringing + * |--------------------------------------------------------------- + * | 12 | 0.942 % | 168720 | best than + * | |(freeverb + 41%) | (82 %freeverb) | 8 lines + *--------------------------------------------------------------------------- + * + * Note: + * Values in this column is the memory consumption for sample rate <= 44100Hz. + * For sample rate > 44100Hz , multiply these values by (sample rate / 44100Hz). + * For example: for sample rate 96000Hz, the memory consumed is 244760 bytes + * + *---------------------------------------------------------------------------- + * 'Denormalise' method to avoid loss of performance. + * -------------------------------------------------- + * According to music-dsp thread 'Denormalise', Pentium processors + * have a hardware 'feature', that is of interest here, related to + * numeric underflow. We have a recursive filter. The output decays + * exponentially, if the input stops. So the numbers get smaller and + * smaller... At some point, they reach 'denormal' level. This will + * lead to drastic spikes in the CPU load. The effect was reproduced + * with the reverb - sometimes the average load over 10 s doubles!!. + * + * The 'undenormalise' macro fixes the problem: As soon as the number + * is close enough to denormal level, the macro forces the number to + * 0.0f. The original macro is: + * + * #define undenormalise(sample) if(((*(unsigned int*)&sample)&0x7f800000)==0) sample=0.0f + * + * This will zero out a number when it reaches the denormal level. + * Advantage: Maximum dynamic range Disadvantage: We'll have to check + * every sample, expensive. The alternative macro comes from a later + * mail from Jon Watte. It will zap a number before it reaches + * denormal level. Jon suggests to run it once per block instead of + * every sample. + */ + +/* Denormalising part II: + * + * Another method fixes the problem cheaper: Use a small DC-offset in + * the filter calculations. Now the signals converge not against 0, + * but against the offset. The constant offset is invisible from the + * outside world (i.e. it does not appear at the output. There is a + * very small turn-on transient response, which should not cause + * problems. + */ +#include "fluid_rev.h" +#include "fluid_sys.h" + +/*---------------------------------------------------------------------------- + Configuration macros at compiler time. + + 3 macros are usable at compiler time: + - NBR_DELAYs: number of delay lines. 8 (default) or 12. + - ROOMSIZE_RESPONSE_LINEAR: allows to choose an alternate response for + roomsize parameter. + - DENORMALISING enable denormalising handling. +-----------------------------------------------------------------------------*/ +//#define INFOS_PRINT /* allows message to be printed on the console. */ + +/* Number of delay lines (must be only 8 or 12) + 8 is the default. + 12 produces a better quality but is +50% cpu expensive. +*/ +#define NBR_DELAYS 8 /* default*/ + +/* response curve of parameter roomsize */ +/* + The default response is the same as Freeverb: + - roomsize (0 to 1) controls concave reverb time (0.7 to 12.5 s). + + when ROOMSIZE_RESPONSE_LINEAR is defined, the response is: + - roomsize (0 to 1) controls reverb time linearly (0.7 to 12.5 s). +*/ +//#define ROOMSIZE_RESPONSE_LINEAR + +/* DENORMALISING enable denormalising handling */ +#define DENORMALISING + +#ifdef DENORMALISING +#define DC_OFFSET 1e-8f +#else +#define DC_OFFSET 0.0f +#endif + +/*---------------------------------------------------------------------------- + Initial internal reverb settings (at reverb creation time) +-----------------------------------------------------------------------------*/ +/* SCALE_WET_WIDTH is a compensation weight factor to get an output + amplitude (wet) rather independent of the width setting. + 0: the output amplitude is fully dependent on the width setting. + >0: the output amplitude is less dependent on the width setting. + With a SCALE_WET_WIDTH of 0.2 the output amplitude is rather + independent of width setting (see fluid_revmodel_update()). + */ +#define SCALE_WET_WIDTH 0.2f + +/* It is best to inject the input signal less ofen. This contributes to obtain +a flatter response on comb filter. So the input gain is set to 0.1 rather 1.0. */ +#define FIXED_GAIN 0.1f /* input gain */ + +/* SCALE_WET is adjusted to 5.0 to get internal output level equivalent to freeverb */ +#define SCALE_WET 5.0f /* scale output gain */ + +/*---------------------------------------------------------------------------- + Internal FDN late reverb settings +-----------------------------------------------------------------------------*/ + +/*-- Reverberation time settings ---------------------------------- + MIN_DC_REV_TIME est defined egal to the minimum value of freeverb: + MAX_DC_REV_TIME est defined egal to the maximum value of freeverb: + T60DC is computed from gi and the longest delay line in freeverb: L8 = 1617 + T60 = -3 * Li * T / log10(gi) + T60 = -3 * Li * / (log10(gi) * sr) + + - Li: length of comb filter delay line. + - sr: sample rate. + - gi: the feedback gain. + + The minimum value for freeverb correspond to gi = 0.7. + with Mi = 1617, sr at 44100 Hz, and gi = 0.7 => MIN_DC_REV_TIME = 0.7 s + + The maximum value for freeverb correspond to gi = 0.98. + with Mi = 1617, sr at 44100 Hz, and gi = 0.98 => MAX_DC_REV_TIME = 12.5 s +*/ + +#define MIN_DC_REV_TIME 0.7f /* minimum T60DC reverb time: seconds */ +#define MAX_DC_REV_TIME 12.5f /* maximumm T60DC time in seconds */ +#define RANGE_REV_TIME (MAX_DC_REV_TIME - MIN_DC_REV_TIME) + +/* macro to compute internal reverberation time versus roomsize parameter */ +#define GET_DC_REV_TIME(roomsize) (MIN_DC_REV_TIME + RANGE_REV_TIME * roomsize) + +/*-- Modulation related settings ----------------------------------*/ +/* For many instruments, the range for MOD_FREQ and MOD_DEPTH should be: + + MOD_DEPTH: [3..6] (in samples). + MOD_FREQ: [0.5 ..2.0] (in Hz). + + Values below the lower limits are often not sufficient to cancel unwanted + "ringing"(resonant frequency). + Values above upper limits augment the unwanted "chorus". + + With NBR_DELAYS to 8: + MOD_DEPTH must be >= 4 to cancel the unwanted "ringing".[4..6]. + With NBR_DELAYS to 12: + MOD_DEPTH to 3 is sufficient to cancel the unwanted "ringing".[3..6] +*/ +#define MOD_DEPTH 4 /* modulation depth (samples)*/ +#define MOD_RATE 50 /* modulation rate (samples)*/ +#define MOD_FREQ 1.0f /* modulation frequency (Hz) */ +/* + Number of samples to add to the desired length of a delay line. This + allow to take account of modulation interpolation. + 1 is sufficient with MOD_DEPTH equal to 4. +*/ +#define INTERP_SAMPLES_NBR 1 + +/* phase offset between modulators waveform */ +#define MOD_PHASE (360.0f/(float) NBR_DELAYS) + +#if (NBR_DELAYS == 8) + #define DELAY_L0 601 + #define DELAY_L1 691 + #define DELAY_L2 773 + #define DELAY_L3 839 + #define DELAY_L4 919 + #define DELAY_L5 997 + #define DELAY_L6 1061 + #define DELAY_L7 1129 +#elif (NBR_DELAYS == 12) + #define DELAY_L0 601 + #define DELAY_L1 691 + #define DELAY_L2 773 + #define DELAY_L3 839 + #define DELAY_L4 919 + #define DELAY_L5 997 + #define DELAY_L6 1061 + #define DELAY_L7 1093 + #define DELAY_L8 1129 + #define DELAY_L9 1151 + #define DELAY_L10 1171 + #define DELAY_L11 1187 +#endif + + +/*---------------------------------------------------------------------------*/ +/* The FDN late feed back matrix: A + T + A = P - 2 / N * u * u + N N N N + + N: the matrix dimension (i.e NBR_DELAYS). + P: permutation matrix. + u: is a column vector of 1. + +*/ +#define FDN_MATRIX_FACTOR (fluid_real_t)(-2.0 / NBR_DELAYS) + +/*---------------------------------------------------------------------------- + Internal FDN late structures and static functions +-----------------------------------------------------------------------------*/ + + +/*----------------------------------------------------------------------------- + Delay absorbent low pass filter +-----------------------------------------------------------------------------*/ +typedef struct +{ + fluid_real_t buffer; + fluid_real_t b0, a1; /* filter coefficients */ +} fdn_delay_lpf; + +/*----------------------------------------------------------------------------- + Sets coefficients for delay absorbent low pass filter. + @param lpf pointer on low pass filter structure. + @param b0,a1 coefficients. +-----------------------------------------------------------------------------*/ +static void set_fdn_delay_lpf(fdn_delay_lpf *lpf, + fluid_real_t b0, fluid_real_t a1) +{ + lpf->b0 = b0; + lpf->a1 = a1; +} + +/*----------------------------------------------------------------------------- + Process delay absorbent low pass filter. + @param mod_delay modulated delay line. + @param in, input sample. + @param out output sample. +-----------------------------------------------------------------------------*/ +/* process low pass damping filter (input, output, delay) */ +#define process_damping_filter(in,out,mod_delay) \ +{\ + out = in * mod_delay->dl.damping.b0 - mod_delay->dl.damping.buffer * \ + mod_delay->dl.damping.a1;\ + mod_delay->dl.damping.buffer = out;\ +}\ + + +/*----------------------------------------------------------------------------- + Delay line : + The delay line is composed of the line plus an absorbent low pass filter + to get frequency dependent reverb time. +-----------------------------------------------------------------------------*/ +typedef struct +{ + fluid_real_t *line; /* buffer line */ + int size; /* effective internal size (in samples) */ + /*-------------*/ + int line_in; /* line in position */ + int line_out; /* line out position */ + /*-------------*/ + fdn_delay_lpf damping; /* damping low pass filter */ +} delay_line; + + +/*----------------------------------------------------------------------------- + Clears a delay line to DC_OFFSET float value. + @param dl pointer on delay line structure +-----------------------------------------------------------------------------*/ +static void clear_delay_line(delay_line *dl) +{ + int i; + + for(i = 0; i < dl->size; i++) + { + dl->line[i] = DC_OFFSET; + } +} + +/*----------------------------------------------------------------------------- + Push a sample val into the delay line +-----------------------------------------------------------------------------*/ +#define push_in_delay_line(dl, val) \ +{\ + dl->line[dl->line_in] = val;\ + /* Incrementation and circular motion if necessary */\ + if(++dl->line_in >= dl->size) dl->line_in -= dl->size;\ +}\ + +/*----------------------------------------------------------------------------- + Modulator for modulated delay line +-----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------- + Sinusoidal modulator +-----------------------------------------------------------------------------*/ +/* modulator are integrated in modulated delay line */ +typedef struct +{ + fluid_real_t a1; /* Coefficient: a1 = 2 * cos(w) */ + fluid_real_t buffer1; /* buffer1 */ + fluid_real_t buffer2; /* buffer2 */ + fluid_real_t reset_buffer2;/* reset value of buffer2 */ +} sinus_modulator; + +/*----------------------------------------------------------------------------- + Sets the frequency of sinus oscillator. + + @param mod pointer on modulator structure. + @param freq frequency of the oscillator in Hz. + @param sample_rate sample rate on audio output in Hz. + @param phase initial phase of the oscillator in degree (0 to 360). +-----------------------------------------------------------------------------*/ +static void set_mod_frequency(sinus_modulator *mod, + float freq, float sample_rate, float phase) +{ + fluid_real_t w = 2 * FLUID_M_PI * freq / sample_rate; /* initial angle */ + fluid_real_t a; + + mod->a1 = 2 * FLUID_COS(w); + + a = (2 * FLUID_M_PI / 360) * phase; + + mod->buffer2 = FLUID_SIN(a - w); /* y(n-1) = sin(-initial angle) */ + mod->buffer1 = FLUID_SIN(a); /* y(n) = sin(initial phase) */ + mod->reset_buffer2 = FLUID_SIN(FLUID_M_PI / 2 - w); /* reset value for PI/2 */ +} + +/*----------------------------------------------------------------------------- + Gets current value of sinus modulator: + y(n) = a1 . y(n-1) - y(n-2) + out = a1 . buffer1 - buffer2 + + @param pointer on modulator structure. + @return current value of the modulator sine wave. +-----------------------------------------------------------------------------*/ +static FLUID_INLINE fluid_real_t get_mod_sinus(sinus_modulator *mod) +{ + fluid_real_t out; + out = mod->a1 * mod->buffer1 - mod->buffer2; + mod->buffer2 = mod->buffer1; + + if(out >= 1.0f) /* reset in case of instability near PI/2 */ + { + out = 1.0f; /* forces output to the right value */ + mod->buffer2 = mod->reset_buffer2; + } + + if(out <= -1.0f) /* reset in case of instability near -PI/2 */ + { + out = -1.0f; /* forces output to the right value */ + mod->buffer2 = - mod->reset_buffer2; + } + + mod->buffer1 = out; + return out; +} + +/*----------------------------------------------------------------------------- + Modulated delay line. The line is composed of: + - the delay line with its damping low pass filter. + - the sinusoidal modulator. + - center output position modulated by the modulator. + - variable rate control of center output position. + - first order All-Pass interpolator. +-----------------------------------------------------------------------------*/ +typedef struct +{ + /* delay line with damping low pass filter member */ + delay_line dl; /* delayed line */ + /*---------------------------*/ + /* Sinusoidal modulator member */ + sinus_modulator mod; /* sinus modulator */ + /*-------------------------*/ + /* center output position members */ + fluid_real_t center_pos_mod; /* center output position modulated by modulator */ + int mod_depth; /* modulation depth (in samples) */ + /*-------------------------*/ + /* variable rate control of center output position */ + int index_rate; /* index rate to know when to update center_pos_mod */ + int mod_rate; /* rate at which center_pos_mod is updated */ + /*-------------------------*/ + /* first order All-Pass interpolator members */ + fluid_real_t frac_pos_mod; /* fractional position part between samples) */ + /* previous value used when interpolating using fractional */ + fluid_real_t buffer; +} mod_delay_line; + +/*----------------------------------------------------------------------------- + Return norminal delay length + + @param mdl, pointer on modulated delay line. +-----------------------------------------------------------------------------*/ +static int get_mod_delay_line_length(mod_delay_line *mdl) +{ + return (mdl->dl.size - mdl->mod_depth - INTERP_SAMPLES_NBR); +} + +/*----------------------------------------------------------------------------- + Reads the sample value out of the modulated delay line. + @param mdl, pointer on modulated delay line. + @return the sample value. +-----------------------------------------------------------------------------*/ +static FLUID_INLINE fluid_real_t get_mod_delay(mod_delay_line *mdl) +{ + fluid_real_t out_index; /* new modulated index position */ + int int_out_index; /* integer part of out_index */ + fluid_real_t out; /* value to return */ + + /* Checks if the modulator must be updated (every mod_rate samples). */ + /* Important: center_pos_mod must be used immediately for the + first sample. So, mdl->index_rate must be initialized + to mdl->mod_rate (set_mod_delay_line()) */ + + if(++mdl->index_rate >= mdl->mod_rate) + { + mdl->index_rate = 0; + + /* out_index = center position (center_pos_mod) + sinus waweform */ + out_index = mdl->center_pos_mod + + get_mod_sinus(&mdl->mod) * mdl->mod_depth; + + /* extracts integer part in int_out_index */ + if(out_index >= 0.0f) + { + int_out_index = (int)out_index; /* current integer part */ + + /* forces read index (line_out) with integer modulation value */ + /* Boundary check and circular motion as needed */ + if((mdl->dl.line_out = int_out_index) >= mdl->dl.size) + { + mdl->dl.line_out -= mdl->dl.size; + } + } + else /* negative */ + { + int_out_index = (int)(out_index - 1); /* previous integer part */ + /* forces read index (line_out) with integer modulation value */ + /* circular motion as needed */ + mdl->dl.line_out = int_out_index + mdl->dl.size; + } + + /* extracts fractionnal part. (it will be used when interpolating + between line_out and line_out +1) and memorize it. + Memorizing is necessary for modulation rate above 1 */ + mdl->frac_pos_mod = out_index - int_out_index; + + /* updates center position (center_pos_mod) to the next position + specified by modulation rate */ + if((mdl->center_pos_mod += mdl->mod_rate) >= mdl->dl.size) + { + mdl->center_pos_mod -= mdl->dl.size; + } + } + + /* First order all-pass interpolation ----------------------------------*/ + /* https://ccrma.stanford.edu/~jos/pasp/First_Order_Allpass_Interpolation.html */ + /* begins interpolation: read current sample */ + out = mdl->dl.line[mdl->dl.line_out]; + + /* updates line_out to the next sample. + Boundary check and circular motion as needed */ + if(++mdl->dl.line_out >= mdl->dl.size) + { + mdl->dl.line_out -= mdl->dl.size; + } + + /* Fractional interpolation between next sample (at next position) and + previous output added to current sample. + */ + out += mdl->frac_pos_mod * (mdl->dl.line[mdl->dl.line_out] - mdl->buffer); + mdl->buffer = out; /* memorizes current output */ + return out; +} + +/*----------------------------------------------------------------------------- + Late structure +-----------------------------------------------------------------------------*/ +struct _fluid_late +{ + fluid_real_t samplerate; /* sample rate */ + fluid_real_t sample_rate_max; /* sample rate maximum */ + /*----- High pass tone corrector -------------------------------------*/ + fluid_real_t tone_buffer; + fluid_real_t b1, b2; + /*----- Modulated delay lines lines ----------------------------------*/ + mod_delay_line mod_delay_lines[NBR_DELAYS]; + /*-----------------------------------------------------------------------*/ + /* Output coefficients for separate Left and right stereo outputs */ + fluid_real_t out_left_gain[NBR_DELAYS]; /* Left delay lines' output gains */ + fluid_real_t out_right_gain[NBR_DELAYS];/* Right delay lines' output gains*/ +}; + +typedef struct _fluid_late fluid_late; +/*----------------------------------------------------------------------------- + fluidsynth reverb structure +-----------------------------------------------------------------------------*/ +struct _fluid_revmodel_t +{ + /* reverb parameters */ + fluid_real_t roomsize; /* acting on reverb time */ + fluid_real_t damp; /* acting on frequency dependent reverb time */ + fluid_real_t level, wet1, wet2; /* output level */ + fluid_real_t width; /* width stereo separation */ + + /* fdn reverberation structure */ + fluid_late late; +}; + +/*----------------------------------------------------------------------------- + Updates Reverb time and absorbent filters coefficients from parameters: + + @param late pointer on late structure. + @param roomsize (0 to 1): acting on reverb time. + @param damping (0 to 1): acting on absorbent damping filter. + + Design formulas: + https://ccrma.stanford.edu/~jos/Reverb/First_Order_Delay_Filter_Design.html + https://ccrma.stanford.edu/~jos/Reverb/Tonal_Correction_Filter.html +-----------------------------------------------------------------------------*/ +static void update_rev_time_damping(fluid_late *late, + fluid_real_t roomsize, fluid_real_t damp) +{ + int i; + fluid_real_t sample_period = 1 / late->samplerate; /* Sampling period */ + int delay_length; /* delay length */ + fluid_real_t dc_rev_time; /* Reverb time at 0 Hz (in seconds) */ + + fluid_real_t alpha, alpha2; + + /*-------------------------------------------- + Computes dc_rev_time and alpha + ----------------------------------------------*/ + { + fluid_real_t gi_tmp, ai_tmp; +#ifdef ROOMSIZE_RESPONSE_LINEAR + /* roomsize parameter behave linearly: + * - roomsize (0 to 1) controls reverb time linearly (0.7 to 10 s). + * This linear response is convenient when using GUI controls. + */ + /*----------------------------------------- + Computes dc_rev_time + ------------------------------------------*/ + dc_rev_time = GET_DC_REV_TIME(roomsize); + delay_length = get_mod_delay_line_length(&late->mod_delay_lines[NBR_DELAYS - 1]); + /* computes gi_tmp from dc_rev_time using relation E2 */ + gi_tmp = FLUID_POW(10, -3 * delay_length * + sample_period / dc_rev_time); /* E2 */ +#else + /* roomsize parameters have the same response that Freeverb, that is: + * - roomsize (0 to 1) controls concave reverb time (0.7 to 10 s). + */ + { + /*----------------------------------------- + Computes dc_rev_time + ------------------------------------------*/ + fluid_real_t gi_min, gi_max; + + /* values gi_min et gi_max are computed using E2 for the line with + maximum delay */ + delay_length = get_mod_delay_line_length(&late->mod_delay_lines[NBR_DELAYS - 1]); + gi_max = FLUID_POW(10, (-3 * delay_length / MAX_DC_REV_TIME) * + sample_period); /* E2 */ + gi_min = FLUID_POW(10, (-3 * delay_length / MIN_DC_REV_TIME) * + sample_period); /* E2 */ + /* gi = f(roomsize, gi_max, gi_min) */ + gi_tmp = gi_min + roomsize * (gi_max - gi_min); + /* Computes T60DC from gi using inverse of relation E2.*/ + dc_rev_time = -3 * FLUID_M_LN10 * delay_length * sample_period / FLUID_LOGF(gi_tmp); + } +#endif /* ROOMSIZE_RESPONSE_LINEAR */ + /*-------------------------------------------- + Computes alpha + ----------------------------------------------*/ + /* Computes alpha from damp,ai_tmp,gi_tmp using relation R */ + /* - damp (0 to 1) controls concave reverb time for fs/2 frequency (T60DC to 0) */ + ai_tmp = 1.0f * damp; + + /* Preserve the square of R */ + alpha2 = 1.f / (1.f - ai_tmp / ((20.f / 80.f) * FLUID_LOGF(gi_tmp))); + + alpha = FLUID_SQRT(alpha2); /* R */ + } + + /* updates tone corrector coefficients b1,b2 from alpha */ + { + /* + Beta = (1 - alpha) / (1 + alpha) + b1 = 1/(1-beta) + b2 = beta * b1 + */ + fluid_real_t beta = (1 - alpha) / (1 + alpha); + late->b1 = 1 / (1 - beta); + late->b2 = beta * late->b1; + late->tone_buffer = 0.0f; + } + + /* updates damping coefficients of all lines (gi , ai) from dc_rev_time, alpha */ + for(i = 0; i < NBR_DELAYS; i++) + { + fluid_real_t gi, ai; + + /* delay length */ + delay_length = get_mod_delay_line_length(&late->mod_delay_lines[i]); + + /* iir low pass filter gain */ + gi = FLUID_POW(10, -3 * delay_length * sample_period / dc_rev_time); + + /* iir low pass filter feedback gain */ + ai = (20.f / 80.f) * FLUID_LOGF(gi) * (1.f - 1.f / alpha2); + + /* b0 = gi * (1 - ai), a1 = - ai */ + set_fdn_delay_lpf(&late->mod_delay_lines[i].dl.damping, + gi * (1.f - ai), -ai); + } +} + +/*----------------------------------------------------------------------------- + Updates stereo coefficients + @param late pointer on late structure + @param wet level integrated in stereo coefficients. +-----------------------------------------------------------------------------*/ +static void update_stereo_coefficient(fluid_late *late, fluid_real_t wet1) +{ + int i; + fluid_real_t wet; + + for(i = 0; i < NBR_DELAYS; i++) + { + /* delay lines output gains vectors Left and Right + + L R + 0 | 1 1| + 1 |-1 1| + 2 | 1 -1| + 3 |-1 -1| + + 4 | 1 1| + 5 |-1 1| + stereo gain = 6 | 1 -1| + 7 |-1 -1| + + 8 | 1 1| + 9 |-1 1| + 10| 1 -1| + 11|-1 -1| + */ + + /* for left line: 00, ,02, ,04, ,06, ,08, ,10, ,12,... left_gain = +1 */ + /* for left line: ,01, ,03, ,05, ,07, ,09, ,11,... left_gain = -1 */ + wet = wet1; + if(i & 1) + { + wet = -wet1; + } + late->out_left_gain[i] = wet; + + /* for right line: 00,01, ,04,05, ,08,09, ,12,13 right_gain = +1 */ + /* for right line: ,02 ,03, ,06,07, ,10,11,... right_gain = -1 */ + wet = wet1; + if(i & 2) + { + wet = -wet1; + } + late->out_right_gain[i] = wet; + } +} + +/*----------------------------------------------------------------------------- + fluid_late destructor. + @param late pointer on late structure. +-----------------------------------------------------------------------------*/ +static void delete_fluid_rev_late(fluid_late *late) +{ + int i; + fluid_return_if_fail(late != NULL); + + /* free the delay lines */ + for(i = 0; i < NBR_DELAYS; i++) + { + FLUID_FREE(late->mod_delay_lines[i].dl.line); + } +} + + +/* Nominal delay lines length table (in samples) */ +static const int nom_delay_length[NBR_DELAYS] = +{ + DELAY_L0, DELAY_L1, DELAY_L2, DELAY_L3, + DELAY_L4, DELAY_L5, DELAY_L6, DELAY_L7, +#if (NBR_DELAYS == 12) + DELAY_L8, DELAY_L9, DELAY_L10, DELAY_L11 +#endif +}; + +/* + 1)"modal density" is one property that contributes to the quality of the reverb tail. + The more is the modal density, the less are unwanted resonant frequencies + build during the decay time: modal density = total delay / sample rate. + + Delay line's length given by static table delay_length[] are nominal + to get minimum modal density of 0.15 at sample rate 44100Hz. + Here we set length_factor to 2 to multiply this nominal modal + density by 2. This leads to a default modal density of 0.15 * 2 = 0.3 for + sample rate <= 44100. + + For sample rate > 44100, length_factor is multiplied by + sample_rate / 44100. This ensures that the default modal density keeps inchanged. + (Without this compensation, the default modal density would be diminished for + new sample rate change above 44100Hz). + + 2)Modulated delay line contributes to diminish resonnant frequencies (often called "ringing"). + Modulation depth (mod_depth) is set to nominal value of MOD_DEPTH at sample rate 44100Hz. + For sample rate > 44100, mod_depth is multiplied by sample_rate / 44100. This ensures + that the effect of modulated delay line remains inchanged. +*/ +static void compensate_from_sample_rate(fluid_real_t sample_rate, + fluid_real_t *mod_depth, + fluid_real_t *length_factor) +{ + *mod_depth = MOD_DEPTH; + *length_factor = 2.0f; + if(sample_rate > 44100.0f) + { + fluid_real_t sample_rate_factor = sample_rate/44100.0f; + *length_factor *= sample_rate_factor; + *mod_depth *= sample_rate_factor; + } +} + +/*----------------------------------------------------------------------------- + Creates all modulated lines. + @param late, pointer on the fnd late reverb to initialize. + @param sample_rate_max, the maximum audio sample rate expected. + @return FLUID_OK if success, FLUID_FAILED otherwise. +-----------------------------------------------------------------------------*/ +static int create_mod_delay_lines(fluid_late *late, + fluid_real_t sample_rate_max) +{ + int i; + + fluid_real_t mod_depth, length_factor; + + /* compute mod_depth, length factor */ + compensate_from_sample_rate(sample_rate_max, &mod_depth, &length_factor); + + late->sample_rate_max = sample_rate_max; + +#ifdef INFOS_PRINT // allows message to be printed on the console. + printf("length_factor:%f, mod_depth:%f\n", length_factor, mod_depth); + /* Print: modal density and total memory bytes */ + { + int i; + int total_delay = 0; /* total delay in samples */ + for (i = 0; i < NBR_DELAYS; i++) + { + int length = (length_factor * nom_delay_length[i]) + + mod_depth + INTERP_SAMPLES_NBR; + total_delay += length; + } + + /* modal density and total memory bytes */ + printf("modal density:%f, total delay:%d, total memory:%d bytes\n", + total_delay / sample_rate_max ,total_delay , + total_delay * sizeof(fluid_real_t)); + } +#endif + + for(i = 0; i < NBR_DELAYS; i++) /* for each delay line */ + { + int delay_length = nom_delay_length[i] * length_factor; + mod_delay_line *mdl = &late->mod_delay_lines[i]; + + /*-------------------------------------------------------------------*/ + /* checks parameter */ + if(delay_length < 1) + { + return FLUID_FAILED; + } + + /* limits mod_depth to the requested delay length */ + if(mod_depth >= delay_length) + { + FLUID_LOG(FLUID_INFO, + "fdn reverb: modulation depth has been limited"); + mod_depth = delay_length - 1; + } + + /*--------------------------------------------------------------------- + allocates delay lines + */ + + /* real size of the line in use (in samples): + size = INTERP_SAMPLES_NBR + mod_depth + delay_length */ + mdl->dl.size = delay_length + mod_depth + INTERP_SAMPLES_NBR; + mdl->dl.line = FLUID_ARRAY(fluid_real_t, mdl->dl.size); + + if(! mdl->dl.line) + { + return FLUID_FAILED; + } + } + return FLUID_OK; +} + +/*----------------------------------------------------------------------------- + Initialize all modulated lines. + @param late, pointer on the fnd late reverb to initialize. + @param sample_rate, the audio sample rate. + @return FLUID_OK if success, FLUID_FAILED otherwise. +-----------------------------------------------------------------------------*/ +static void initialize_mod_delay_lines(fluid_late *late, fluid_real_t sample_rate) +{ + int i; + fluid_real_t mod_depth, length_factor; + + /* update delay line parameter dependent of sample rate */ + late->samplerate = sample_rate; + + /* compute mod_depth, length factor */ + compensate_from_sample_rate(sample_rate, &mod_depth, &length_factor); + + for(i = 0; i < NBR_DELAYS; i++) /* for each delay line */ + { + mod_delay_line *mdl = &late->mod_delay_lines[i]; + int delay_length = nom_delay_length[i] * length_factor; + + /* limits mod_depth to the requested delay length */ + if(mod_depth >= delay_length) + { + mod_depth = delay_length - 1; + } + + mdl->mod_depth = mod_depth; + + clear_delay_line(&mdl->dl); /* clears the buffer */ + + /* Initializes line_in to the start of the buffer */ + mdl->dl.line_in = 0; + + /* Initializes line_out index INTERP_SAMPLES_NBR samples after + line_in so that the delay between line_out and line_in is: + mod_depth + delay_length + */ + mdl->dl.line_out = mdl->dl.line_in + INTERP_SAMPLES_NBR; + + /* Damping low pass filter ------------------------------------------*/ + mdl->dl.damping.buffer = 0; + + /*--------------------------------------------------------------------- + Initializes modulation members: + - modulated center position: center_pos_mod + - modulation rate (the speed at which center_pos_mod is modulated: mod_rate + - index rate to know when to update center_pos_mod:index_rate + - interpolator member: buffer, frac_pos_mod + ---------------------------------------------------------------------*/ + /* Initializes the modulated center position (center_pos_mod) so that: + - the delay between line_out and center_pos_mod is mod_depth. + - the delay between center_pos_mod and line_in is delay_length. + */ + mdl->center_pos_mod = (fluid_real_t) INTERP_SAMPLES_NBR + mod_depth; + + /* Sets the modulation rate. This rate defines how often + the center position (center_pos_mod ) is modulated . + The value is expressed in samples. The default value is 1 that means that + center_pos_mod is updated at every sample. + For example with a value of 2, the center position position will be + updated only one time every 2 samples only. + */ + if(MOD_RATE < 1 || MOD_RATE > mdl->dl.size) + { + FLUID_LOG(FLUID_INFO, "fdn reverb: modulation rate is out of range"); + mdl->mod_rate = 1; /* default modulation rate: every one sample */ + } + else + { + mdl->mod_rate = MOD_RATE; + } + + /* index rate to control when to update center_pos_mod. + Important: must be set to get center_pos_mod immediately used for + the reading of first sample (see get_mod_delay()) + */ + mdl->index_rate = mdl->mod_rate; + + /* initializes first order All-Pass interpolator members */ + mdl->buffer = 0; /* previous delay sample value */ + mdl->frac_pos_mod = 0; /* frac. position (between consecutives sample) */ + + + /* Sets local Modulators parameters: frequency and phase. + Each modulateur are shifted of MOD_PHASE degree + */ + set_mod_frequency(&mdl->mod, + MOD_FREQ * MOD_RATE, + sample_rate, + (float)(MOD_PHASE * i)); + } +} + +/* + Clears the delay lines. + + @param rev pointer on the reverb. +*/ +static void +fluid_revmodel_init(fluid_revmodel_t *rev) +{ + int i; + + /* clears all the delay lines */ + for(i = 0; i < NBR_DELAYS; i ++) + { + clear_delay_line(&rev->late.mod_delay_lines[i].dl); + } +} + + +/* + updates internal parameters. + + @param rev pointer on the reverb. +*/ +static void +fluid_revmodel_update(fluid_revmodel_t *rev) +{ + /* Recalculate internal values after parameters change */ + + /* The stereo amplitude equation (wet1 and wet2 below) have a + tendency to produce high amplitude with high width values ( 1 < width < 100). + This results in an unwanted noisy output clipped by the audio card. + To avoid this dependency, we divide by (1 + rev->width * SCALE_WET_WIDTH) + Actually, with a SCALE_WET_WIDTH of 0.2, (regardless of level setting), + the output amplitude (wet) seems rather independent of width setting */ + fluid_real_t wet = (rev->level * SCALE_WET) / + (1.0f + rev->width * SCALE_WET_WIDTH); + + /* wet1 and wet2 are used by the stereo effect controlled by the width setting + for producing a stereo ouptput from a monophonic reverb signal. + Please see the note above about a side effect tendency */ + + rev->wet1 = wet * (rev->width / 2.0f + 0.5f); + rev->wet2 = wet * ((1.0f - rev->width) / 2.0f); + + /* integrates wet1 in stereo coefficient (this will save one multiply) */ + update_stereo_coefficient(&rev->late, rev->wet1); + + if(rev->wet1 > 0.0f) + { + rev->wet2 /= rev->wet1; + } + + /* Reverberation time and damping */ + update_rev_time_damping(&rev->late, rev->roomsize, rev->damp); +} + +/*---------------------------------------------------------------------------- + Reverb API +-----------------------------------------------------------------------------*/ +/* +* Creates a reverb. Once created the reverb have no parameters set, so +* fluid_revmodel_set() must be called at least one time after calling +* new_fluid_revmodel(). +* +* @param sample_rate_max maximum sample rate expected in Hz. +* +* @param sample_rate actual sample rate needed in Hz. +* @return pointer on the new reverb or NULL if memory error. +* Reverb API. +*/ +fluid_revmodel_t * +new_fluid_revmodel(fluid_real_t sample_rate_max, fluid_real_t sample_rate) +{ + fluid_revmodel_t *rev; + + if(sample_rate <= 0) + { + return NULL; + } + + rev = FLUID_NEW(fluid_revmodel_t); + + if(rev == NULL) + { + return NULL; + } + + FLUID_MEMSET(&rev->late, 0, sizeof(fluid_late)); + + /*-------------------------------------------------------------------------- + Create fdn late reverb. + */ + + /* update minimum value for sample_rate_max */ + if(sample_rate > sample_rate_max) + { + sample_rate_max = sample_rate; + } + + /*-------------------------------------------------------------------------- + Allocate the modulated delay lines + */ + if(create_mod_delay_lines(&rev->late, sample_rate_max) == FLUID_FAILED) + { + delete_fluid_revmodel(rev); + return NULL; + } + + /*-------------------------------------------------------------------------- + Initialize the fdn reverb + */ + /* Initialize all modulated lines. */ + initialize_mod_delay_lines(&rev->late, sample_rate); + + return rev; +} + +/* +* free the reverb. +* Note that while the reverb is used by calling any fluid_revmodel_processXXX() +* function, calling delete_fluid_revmodel() isn't multi task safe because +* delay line are freed. To deal properly with this issue follow the steps: +* +* 1) Stop reverb processing (i.e disable calling of any fluid_revmodel_processXXX(). +* reverb functions. +* 2) Delete the reverb by calling delete_fluid_revmodel(). +* +* @param rev pointer on reverb to free. +* Reverb API. +*/ +void +delete_fluid_revmodel(fluid_revmodel_t *rev) +{ + fluid_return_if_fail(rev != NULL); + delete_fluid_rev_late(&rev->late); + FLUID_FREE(rev); +} + +/* +* Sets one or more reverb parameters. Note this must be called at least one +* time after calling new_fluid_revmodel() and before any call to +* fluid_revmodel_processXXX() and fluid_revmodel_samplerate_change(). +* +* Note that while the reverb is used by calling any fluid_revmodel_processXXX() +* function, calling fluid_revmodel_set() could produce audible clics. +* If this is a problem, optionally call fluid_revmodel_reset() before calling +* fluid_revmodel_set(). +* +* @param rev Reverb instance. +* @param set One or more flags from #fluid_revmodel_set_t indicating what +* parameters to set (#FLUID_REVMODEL_SET_ALL to set all parameters). +* @param roomsize Reverb room size. +* @param damping Reverb damping. +* @param width Reverb width. +* @param level Reverb level. +* +* Reverb API. +*/ +void +fluid_revmodel_set(fluid_revmodel_t *rev, int set, fluid_real_t roomsize, + fluid_real_t damping, fluid_real_t width, fluid_real_t level) +{ + fluid_return_if_fail(rev != NULL); + + /*-----------------------------------*/ + if(set & FLUID_REVMODEL_SET_ROOMSIZE) + { + fluid_clip(roomsize, 0.0f, 1.0f); + rev->roomsize = roomsize; + } + + /*-----------------------------------*/ + if(set & FLUID_REVMODEL_SET_DAMPING) + { + fluid_clip(damping, 0.0f, 1.0f); + rev->damp = damping; + } + + /*-----------------------------------*/ + if(set & FLUID_REVMODEL_SET_WIDTH) + { + rev->width = width; + } + + /*-----------------------------------*/ + if(set & FLUID_REVMODEL_SET_LEVEL) + { + fluid_clip(level, 0.0f, 1.0f); + rev->level = level; + } + + /* updates internal parameters */ + fluid_revmodel_update(rev); +} + +/* +* Applies a sample rate change on the reverb. +* fluid_revmodel_set() must be called at least one time before calling +* this function. +* +* Note that while the reverb is used by calling any fluid_revmodel_processXXX() +* function, calling fluid_revmodel_samplerate_change() isn't multi task safe. +* To deal properly with this issue follow the steps: +* 1) Stop reverb processing (i.e disable calling of any fluid_revmodel_processXXX(). +* reverb functions. +* Optionally, call fluid_revmodel_reset() to damp the reverb. +* 2) Change sample rate by calling fluid_revmodel_samplerate_change(). +* 3) Restart reverb processing (i.e enabling calling of any fluid_revmodel_processXXX() +* reverb functions. +* +* Another solution is to substitute step (2): +* 2.1) delete the reverb by calling delete_fluid_revmodel(). +* 2.2) create the reverb by calling new_fluid_revmodel(). +* +* The best solution would be that this function be called only by the same task +* calling fluid_revmodel_processXXX(). +* +* @param rev the reverb. +* @param sample_rate new sample rate value. Must be <= sample_rate_max +* @return FLUID_OK if success, FLUID_FAILED if new sample rate is greater +* then the maximumum sample rate set at creation time. The reverb will +* continue to work but with possible lost of quality. +* If this is a problem, the caller should follow steps 2.1 and 2.2. +* Reverb API. +*/ +int +fluid_revmodel_samplerate_change(fluid_revmodel_t *rev, fluid_real_t sample_rate) +{ + int status = FLUID_OK; + + fluid_return_val_if_fail(rev != NULL, FLUID_FAILED); + + if(sample_rate > rev->late.sample_rate_max) + { + FLUID_LOG(FLUID_WARN, + "fdn reverb: sample rate %.0f Hz is deduced to %.0f Hz\n", + sample_rate, rev->late.sample_rate_max); + + /* Reduce sample rate to the maximum value set at creation time. + The reverb will continue to work with possible lost of quality. + */ + sample_rate = rev->late.sample_rate_max; + status = FLUID_FAILED; + } + + /* Initialize all modulated lines according to sample rate change. */ + initialize_mod_delay_lines(&rev->late, sample_rate); + + /* updates damping filter coefficients according to sample rate change */ + update_rev_time_damping(&rev->late, rev->roomsize, rev->damp); + + return status; +} + +/* +* Damps the reverb by clearing the delay lines. +* @param rev the reverb. +* +* Reverb API. +*/ +void +fluid_revmodel_reset(fluid_revmodel_t *rev) +{ + fluid_return_if_fail(rev != NULL); + + fluid_revmodel_init(rev); +} + +/*----------------------------------------------------------------------------- +* fdn reverb process replace. +* @param rev pointer on reverb. +* @param in monophonic buffer input (FLUID_BUFSIZE sample). +* @param left_out stereo left processed output (FLUID_BUFSIZE sample). +* @param right_out stereo right processed output (FLUID_BUFSIZE sample). +* +* The processed reverb is replacing anything there in out. +* Reverb API. +-----------------------------------------------------------------------------*/ +void +fluid_revmodel_processreplace(fluid_revmodel_t *rev, const fluid_real_t *in, + fluid_real_t *left_out, fluid_real_t *right_out) +{ + int i, k; + + fluid_real_t xn; /* mono input x(n) */ + fluid_real_t out_tone_filter; /* tone corrector output */ + fluid_real_t out_left, out_right; /* output stereo Left and Right */ + fluid_real_t matrix_factor; /* partial matrix computation */ + fluid_real_t delay_out_s; /* sample */ + fluid_real_t delay_out[NBR_DELAYS]; /* Line output + damper output */ + + for(k = 0; k < FLUID_BUFSIZE; k++) + { + /* stereo output */ + out_left = out_right = 0; + +#ifdef DENORMALISING + /* Input is adjusted by DC_OFFSET. */ + xn = (in[k]) * FIXED_GAIN + DC_OFFSET; +#else + xn = (in[k]) * FIXED_GAIN; +#endif + + /*-------------------------------------------------------------------- + tone correction. + */ + out_tone_filter = xn * rev->late.b1 - rev->late.b2 * rev->late.tone_buffer; + rev->late.tone_buffer = xn; + xn = out_tone_filter; + /*-------------------------------------------------------------------- + process feedback delayed network: + - xn is the input signal. + - before inserting in the line input we first we get the delay lines + output, filter them and compute output in delay_out[]. + - also matrix_factor is computed (to simplify further matrix product) + ---------------------------------------------------------------------*/ + /* We begin with the modulated output delay line + damping filter */ + matrix_factor = 0; + + for(i = 0; i < NBR_DELAYS; i++) + { + mod_delay_line *mdl = &rev->late.mod_delay_lines[i]; + /* get current modulated output */ + delay_out_s = get_mod_delay(mdl); + + /* process low pass damping filter + (input:delay_out_s, output:delay_out_s) */ + process_damping_filter(delay_out_s, delay_out_s, mdl); + + /* Result in delay_out[], and matrix_factor. + These will be of use later during input line process */ + delay_out[i] = delay_out_s; /* result in delay_out[] */ + matrix_factor += delay_out_s; /* result in matrix_factor */ + + /* Process stereo output */ + /* stereo left = left + out_left_gain * delay_out */ + out_left += rev->late.out_left_gain[i] * delay_out_s; + /* stereo right= right+ out_right_gain * delay_out */ + out_right += rev->late.out_right_gain[i] * delay_out_s; + } + + /* now we process the input delay line.Each input is a combination of + - xn: input signal + - delay_out[] the output of a delay line given by a permutation matrix P + - and matrix_factor. + This computes: in_delay_line = xn + (delay_out[] * matrix A) with + an algorithm equivalent but faster than using a product with matrix A. + */ + /* matrix_factor = output sum * (-2.0)/N */ + matrix_factor *= FDN_MATRIX_FACTOR; + matrix_factor += xn; /* adds reverb input signal */ + + for(i = 1; i < NBR_DELAYS; i++) + { + /* delay_in[i-1] = delay_out[i] + matrix_factor */ + delay_line *dl = &rev->late.mod_delay_lines[i - 1].dl; + push_in_delay_line(dl, delay_out[i] + matrix_factor); + } + + /* last line input (NB_DELAY-1) */ + /* delay_in[0] = delay_out[NB_DELAY -1] + matrix_factor */ + { + delay_line *dl = &rev->late.mod_delay_lines[NBR_DELAYS - 1].dl; + push_in_delay_line(dl, delay_out[0] + matrix_factor); + } + + /*-------------------------------------------------------------------*/ +#ifdef DENORMALISING + /* Removes the DC offset */ + out_left -= DC_OFFSET; + out_right -= DC_OFFSET; +#endif + + /* Calculates stereo output REPLACING anything already there: */ + /* + left_out[k] = out_left * rev->wet1 + out_right * rev->wet2; + right_out[k] = out_right * rev->wet1 + out_left * rev->wet2; + + As wet1 is integrated in stereo coefficient wet 1 is now + integrated in out_left and out_right, so we simplify previous + relation by suppression of one multiply as this: + + left_out[k] = out_left + out_right * rev->wet2; + right_out[k] = out_right + out_left * rev->wet2; + */ + left_out[k] = out_left + out_right * rev->wet2; + right_out[k] = out_right + out_left * rev->wet2; + } +} + + +/*----------------------------------------------------------------------------- +* fdn reverb process mix. +* @param rev pointer on reverb. +* @param in monophonic buffer input (FLUID_BUFSIZE samples). +* @param left_out stereo left processed output (FLUID_BUFSIZE samples). +* @param right_out stereo right processed output (FLUID_BUFSIZE samples). +* +* The processed reverb is mixed in out with samples already there in out. +* Reverb API. +-----------------------------------------------------------------------------*/ +void fluid_revmodel_processmix(fluid_revmodel_t *rev, const fluid_real_t *in, + fluid_real_t *left_out, fluid_real_t *right_out) +{ + int i, k; + + fluid_real_t xn; /* mono input x(n) */ + fluid_real_t out_tone_filter; /* tone corrector output */ + fluid_real_t out_left, out_right; /* output stereo Left and Right */ + fluid_real_t matrix_factor; /* partial matrix term */ + fluid_real_t delay_out_s; /* sample */ + fluid_real_t delay_out[NBR_DELAYS]; /* Line output + damper output */ + + for(k = 0; k < FLUID_BUFSIZE; k++) + { + /* stereo output */ + out_left = out_right = 0; +#ifdef DENORMALISING + /* Input is adjusted by DC_OFFSET. */ + xn = (in[k]) * FIXED_GAIN + DC_OFFSET; +#else + xn = (in[k]) * FIXED_GAIN; +#endif + + /*-------------------------------------------------------------------- + tone correction + */ + out_tone_filter = xn * rev->late.b1 - rev->late.b2 * rev->late.tone_buffer; + rev->late.tone_buffer = xn; + xn = out_tone_filter; + /*-------------------------------------------------------------------- + process feedback delayed network: + - xn is the input signal. + - before inserting in the line input we first we get the delay lines + output, filter them and compute output in local delay_out[]. + - also matrix_factor is computed (to simplify further matrix product). + ---------------------------------------------------------------------*/ + /* We begin with the modulated output delay line + damping filter */ + matrix_factor = 0; + + for(i = 0; i < NBR_DELAYS; i++) + { + mod_delay_line *mdl = &rev->late.mod_delay_lines[i]; + /* get current modulated output */ + delay_out_s = get_mod_delay(mdl); + + /* process low pass damping filter + (input:delay_out_s, output:delay_out_s) */ + process_damping_filter(delay_out_s, delay_out_s, mdl); + + /* Result in delay_out[], and matrix_factor. + These will be of use later during input line process */ + delay_out[i] = delay_out_s; /* result in delay_out[] */ + matrix_factor += delay_out_s; /* result in matrix_factor */ + + /* Process stereo output */ + /* stereo left = left + out_left_gain * delay_out */ + out_left += rev->late.out_left_gain[i] * delay_out_s; + /* stereo right= right+ out_right_gain * delay_out */ + out_right += rev->late.out_right_gain[i] * delay_out_s; + } + + /* now we process the input delay line. Each input is a combination of: + - xn: input signal + - delay_out[] the output of a delay line given by a permutation matrix P + - and matrix_factor. + This computes: in_delay_line = xn + (delay_out[] * matrix A) with + an algorithm equivalent but faster than using a product with matrix A. + */ + /* matrix_factor = output sum * (-2.0)/N */ + matrix_factor *= FDN_MATRIX_FACTOR; + matrix_factor += xn; /* adds reverb input signal */ + + for(i = 1; i < NBR_DELAYS; i++) + { + /* delay_in[i-1] = delay_out[i] + matrix_factor */ + delay_line *dl = &rev->late.mod_delay_lines[i - 1].dl; + push_in_delay_line(dl, delay_out[i] + matrix_factor); + } + + /* last line input (NB_DELAY-1) */ + /* delay_in[0] = delay_out[NB_DELAY -1] + matrix_factor */ + { + delay_line *dl = &rev->late.mod_delay_lines[NBR_DELAYS - 1].dl; + push_in_delay_line(dl, delay_out[0] + matrix_factor); + } + + /*-------------------------------------------------------------------*/ +#ifdef DENORMALISING + /* Removes the DC offset */ + out_left -= DC_OFFSET; + out_right -= DC_OFFSET; +#endif + /* Calculates stereo output MIXING anything already there: */ + /* + left_out[k] += out_left * rev->wet1 + out_right * rev->wet2; + right_out[k] += out_right * rev->wet1 + out_left * rev->wet2; + + As wet1 is integrated in stereo coefficient wet 1 is now + integrated in out_left and out_right, so we simplify previous + relation by suppression of one multiply as this: + + left_out[k] += out_left + out_right * rev->wet2; + right_out[k] += out_right + out_left * rev->wet2; + */ + left_out[k] += out_left + out_right * rev->wet2; + right_out[k] += out_right + out_left * rev->wet2; + } +} diff --git a/libs/fluidsynth/src/rvoice/fluid_rev.h b/libs/fluidsynth/src/rvoice/fluid_rev.h new file mode 100644 index 00000000000..35c9cf664f8 --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_rev.h @@ -0,0 +1,91 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#ifndef _FLUID_REV_H +#define _FLUID_REV_H + +#include "fluidsynth_priv.h" + +typedef struct _fluid_revmodel_t fluid_revmodel_t; + +/* enum describing each reverb parameter */ +enum fluid_reverb_param +{ + FLUID_REVERB_ROOMSIZE, /**< reverb time */ + FLUID_REVERB_DAMP, /**< high frequency damping */ + FLUID_REVERB_WIDTH, /**< stereo width */ + FLUID_REVERB_LEVEL, /**< output level */ + FLUID_REVERB_PARAM_LAST /* number of enum fluid_reverb_param */ +}; + +/* return a bit flag from param: 2^param */ +#define FLUID_REVPARAM_TO_SETFLAG(param) (1 << param) + +/** Flags for fluid_revmodel_set() */ +typedef enum +{ + FLUID_REVMODEL_SET_ROOMSIZE = FLUID_REVPARAM_TO_SETFLAG(FLUID_REVERB_ROOMSIZE), + FLUID_REVMODEL_SET_DAMPING = FLUID_REVPARAM_TO_SETFLAG(FLUID_REVERB_DAMP), + FLUID_REVMODEL_SET_WIDTH = FLUID_REVPARAM_TO_SETFLAG(FLUID_REVERB_WIDTH), + FLUID_REVMODEL_SET_LEVEL = FLUID_REVPARAM_TO_SETFLAG(FLUID_REVERB_LEVEL), + + /** Value for fluid_revmodel_set() which sets all reverb parameters. */ + FLUID_REVMODEL_SET_ALL = FLUID_REVMODEL_SET_LEVEL + | FLUID_REVMODEL_SET_WIDTH + | FLUID_REVMODEL_SET_DAMPING + | FLUID_REVMODEL_SET_ROOMSIZE, +} fluid_revmodel_set_t; + +/* + * reverb preset + */ +typedef struct _fluid_revmodel_presets_t +{ + const char *name; + fluid_real_t roomsize; + fluid_real_t damp; + fluid_real_t width; + fluid_real_t level; +} fluid_revmodel_presets_t; + + +/* + * reverb + */ +fluid_revmodel_t * +new_fluid_revmodel(fluid_real_t sample_rate_max, fluid_real_t sample_rate); + +void delete_fluid_revmodel(fluid_revmodel_t *rev); + +void fluid_revmodel_processmix(fluid_revmodel_t *rev, const fluid_real_t *in, + fluid_real_t *left_out, fluid_real_t *right_out); + +void fluid_revmodel_processreplace(fluid_revmodel_t *rev, const fluid_real_t *in, + fluid_real_t *left_out, fluid_real_t *right_out); + +void fluid_revmodel_reset(fluid_revmodel_t *rev); + +void fluid_revmodel_set(fluid_revmodel_t *rev, int set, fluid_real_t roomsize, + fluid_real_t damping, fluid_real_t width, fluid_real_t level); + +int fluid_revmodel_samplerate_change(fluid_revmodel_t *rev, fluid_real_t sample_rate); + +#endif /* _FLUID_REV_H */ diff --git a/libs/fluidsynth/src/rvoice/fluid_rvoice.c b/libs/fluidsynth/src/rvoice/fluid_rvoice.c new file mode 100644 index 00000000000..3972176f1e4 --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_rvoice.c @@ -0,0 +1,935 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include "fluid_rvoice.h" +#include "fluid_conv.h" +#include "fluid_sys.h" + + +static void fluid_rvoice_noteoff_LOCAL(fluid_rvoice_t *voice, unsigned int min_ticks); + +/** + * @return -1 if voice is quiet, 0 if voice has finished, 1 otherwise + */ +static FLUID_INLINE int +fluid_rvoice_calc_amp(fluid_rvoice_t *voice) +{ + fluid_real_t target_amp; /* target amplitude */ + + if(fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVDELAY) + { + return -1; /* The volume amplitude is in hold phase. No sound is produced. */ + } + + if(fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVATTACK) + { + /* the envelope is in the attack section: ramp linearly to max value. + * A positive modlfo_to_vol should increase volume (negative attenuation). + */ + target_amp = fluid_cb2amp(voice->dsp.attenuation) + * fluid_cb2amp(fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol) + * fluid_adsr_env_get_val(&voice->envlfo.volenv); + } + else + { + fluid_real_t amplitude_that_reaches_noise_floor; + fluid_real_t amp_max; + + target_amp = fluid_cb2amp(voice->dsp.attenuation) + * fluid_cb2amp(FLUID_PEAK_ATTENUATION * (1.0f - fluid_adsr_env_get_val(&voice->envlfo.volenv)) + + fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol); + + /* We turn off a voice, if the volume has dropped low enough. */ + + /* A voice can be turned off, when an estimate for the volume + * (upper bound) falls below that volume, that will drop the + * sample below the noise floor. + */ + + /* If the loop amplitude is known, we can use it if the voice loop is within + * the sample loop + */ + + /* Is the playing pointer already in the loop? */ + if(voice->dsp.has_looped) + { + amplitude_that_reaches_noise_floor = voice->dsp.amplitude_that_reaches_noise_floor_loop; + } + else + { + amplitude_that_reaches_noise_floor = voice->dsp.amplitude_that_reaches_noise_floor_nonloop; + } + + /* voice->attenuation_min is a lower boundary for the attenuation + * now and in the future (possibly 0 in the worst case). Now the + * amplitude of sample and volenv cannot exceed amp_max (since + * volenv_val can only drop): + */ + + amp_max = fluid_cb2amp(voice->dsp.min_attenuation_cB) * + fluid_adsr_env_get_val(&voice->envlfo.volenv); + + /* And if amp_max is already smaller than the known amplitude, + * which will attenuate the sample below the noise floor, then we + * can safely turn off the voice. Duh. */ + if(amp_max < amplitude_that_reaches_noise_floor) + { + return 0; + } + } + + /* Volume increment to go from voice->amp to target_amp in FLUID_BUFSIZE steps */ + voice->dsp.amp_incr = (target_amp - voice->dsp.amp) / FLUID_BUFSIZE; + + fluid_check_fpe("voice_write amplitude calculation"); + + /* no volume and not changing? - No need to process */ + if((voice->dsp.amp == 0.0f) && (voice->dsp.amp_incr == 0.0f)) + { + return -1; + } + + return 1; +} + + +/* these should be the absolute minimum that FluidSynth can deal with */ +#define FLUID_MIN_LOOP_SIZE 2 +#define FLUID_MIN_LOOP_PAD 0 + +#define FLUID_SAMPLESANITY_CHECK (1 << 0) +#define FLUID_SAMPLESANITY_STARTUP (1 << 1) + +/* Purpose: + * + * Make sure, that sample start / end point and loop points are in + * proper order. When starting up, calculate the initial phase. + * TODO: Investigate whether this can be moved from rvoice to voice. + */ +static void +fluid_rvoice_check_sample_sanity(fluid_rvoice_t *voice) +{ + int min_index_nonloop = (int) voice->dsp.sample->start; + int max_index_nonloop = (int) voice->dsp.sample->end; + + /* make sure we have enough samples surrounding the loop */ + int min_index_loop = (int) voice->dsp.sample->start + FLUID_MIN_LOOP_PAD; + int max_index_loop = (int) voice->dsp.sample->end - FLUID_MIN_LOOP_PAD + 1; /* 'end' is last valid sample, loopend can be + 1 */ + fluid_check_fpe("voice_check_sample_sanity start"); + +#if 0 + printf("Sample from %i to %i\n", voice->dsp.sample->start, voice->dsp.sample->end); + printf("Sample loop from %i %i\n", voice->dsp.sample->loopstart, voice->dsp.sample->loopend); + printf("Playback from %i to %i\n", voice->dsp.start, voice->dsp.end); + printf("Playback loop from %i to %i\n", voice->dsp.loopstart, voice->dsp.loopend); +#endif + + /* Keep the start point within the sample data */ + if(voice->dsp.start < min_index_nonloop) + { + voice->dsp.start = min_index_nonloop; + } + else if(voice->dsp.start > max_index_nonloop) + { + voice->dsp.start = max_index_nonloop; + } + + /* Keep the end point within the sample data */ + if(voice->dsp.end < min_index_nonloop) + { + voice->dsp.end = min_index_nonloop; + } + else if(voice->dsp.end > max_index_nonloop) + { + voice->dsp.end = max_index_nonloop; + } + + /* Keep start and end point in the right order */ + if(voice->dsp.start > voice->dsp.end) + { + int temp = voice->dsp.start; + voice->dsp.start = voice->dsp.end; + voice->dsp.end = temp; + /*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of start / end points!"); */ + } + + /* Zero length? */ + if(voice->dsp.start == voice->dsp.end) + { + fluid_rvoice_voiceoff(voice, NULL); + return; + } + + if((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE) + || (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE)) + { + /* Keep the loop start point within the sample data */ + if(voice->dsp.loopstart < min_index_loop) + { + voice->dsp.loopstart = min_index_loop; + } + else if(voice->dsp.loopstart > max_index_loop) + { + voice->dsp.loopstart = max_index_loop; + } + + /* Keep the loop end point within the sample data */ + if(voice->dsp.loopend < min_index_loop) + { + voice->dsp.loopend = min_index_loop; + } + else if(voice->dsp.loopend > max_index_loop) + { + voice->dsp.loopend = max_index_loop; + } + + /* Keep loop start and end point in the right order */ + if(voice->dsp.loopstart > voice->dsp.loopend) + { + int temp = voice->dsp.loopstart; + voice->dsp.loopstart = voice->dsp.loopend; + voice->dsp.loopend = temp; + /*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of loop points!"); */ + } + + /* Loop too short? Then don't loop. */ + if(voice->dsp.loopend < voice->dsp.loopstart + FLUID_MIN_LOOP_SIZE) + { + voice->dsp.samplemode = FLUID_UNLOOPED; + } + + /* The loop points may have changed. Obtain a new estimate for the loop volume. */ + /* Is the voice loop within the sample loop? */ + if((int)voice->dsp.loopstart >= (int)voice->dsp.sample->loopstart + && (int)voice->dsp.loopend <= (int)voice->dsp.sample->loopend) + { + /* Is there a valid peak amplitude available for the loop, and can we use it? */ + if(voice->dsp.sample->amplitude_that_reaches_noise_floor_is_valid && voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE) + { + voice->dsp.amplitude_that_reaches_noise_floor_loop = voice->dsp.sample->amplitude_that_reaches_noise_floor / voice->dsp.synth_gain; + } + else + { + /* Worst case */ + voice->dsp.amplitude_that_reaches_noise_floor_loop = voice->dsp.amplitude_that_reaches_noise_floor_nonloop; + }; + }; + + } /* if sample mode is looped */ + + /* Run startup specific code (only once, when the voice is started) */ + if(voice->dsp.check_sample_sanity_flag & FLUID_SAMPLESANITY_STARTUP) + { + if(max_index_loop - min_index_loop < FLUID_MIN_LOOP_SIZE) + { + if((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE) + || (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE)) + { + voice->dsp.samplemode = FLUID_UNLOOPED; + } + } + + /* Set the initial phase of the voice (using the result from the + start offset modulators). */ + fluid_phase_set_int(voice->dsp.phase, voice->dsp.start); + } /* if startup */ + + /* Is this voice run in loop mode, or does it run straight to the + end of the waveform data? */ + if(((voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE) && + (fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE)) + || (voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE)) + { + /* Yes, it will loop as soon as it reaches the loop point. In + * this case we must prevent, that the playback pointer (phase) + * happens to end up beyond the 2nd loop point, because the + * point has moved. The DSP algorithm is unable to cope with + * that situation. So if the phase is beyond the 2nd loop + * point, set it to the start of the loop. No way to avoid some + * noise here. Note: If the sample pointer ends up -before the + * first loop point- instead, then the DSP loop will just play + * the sample, enter the loop and proceed as expected => no + * actions required. + */ + int index_in_sample = fluid_phase_index(voice->dsp.phase); + + if(index_in_sample >= voice->dsp.loopend) + { + /* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Phase after 2nd loop point!"); */ + fluid_phase_set_int(voice->dsp.phase, voice->dsp.loopstart); + } + } + + /* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Sample from %i to %i, loop from %i to %i", voice->dsp.start, voice->dsp.end, voice->dsp.loopstart, voice->dsp.loopend); */ + + /* Sample sanity has been assured. Don't check again, until some + sample parameter is changed by modulation. */ + voice->dsp.check_sample_sanity_flag = 0; +#if 0 + printf("Sane? playback loop from %i to %i\n", voice->dsp.loopstart, voice->dsp.loopend); +#endif + fluid_check_fpe("voice_check_sample_sanity"); +} + + +/** + * Synthesize a voice to a buffer. + * + * @param voice rvoice to synthesize + * @param dsp_buf Audio buffer to synthesize to (#FLUID_BUFSIZE in length) + * @return Count of samples written to dsp_buf. (-1 means voice is currently + * quiet, 0 .. #FLUID_BUFSIZE-1 means voice finished.) + * + * Panning, reverb and chorus are processed separately. The dsp interpolation + * routine is in (fluid_rvoice_dsp.c). + */ +int +fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf) +{ + int ticks = voice->envlfo.ticks; + int count, is_looping; + fluid_real_t modenv_val; + + /******************* sample sanity check **********/ + + if(!voice->dsp.sample) + { + return 0; + } + + if(voice->dsp.check_sample_sanity_flag) + { + fluid_rvoice_check_sample_sanity(voice); + } + + /******************* noteoff check ****************/ + + if(voice->envlfo.noteoff_ticks != 0 && + voice->envlfo.ticks >= voice->envlfo.noteoff_ticks) + { + fluid_rvoice_noteoff_LOCAL(voice, 0); + } + + voice->envlfo.ticks += FLUID_BUFSIZE; + + /******************* vol env **********************/ + + fluid_adsr_env_calc(&voice->envlfo.volenv); + fluid_check_fpe("voice_write vol env"); + + if(fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVFINISHED) + { + return 0; + } + + /******************* mod env **********************/ + + fluid_adsr_env_calc(&voice->envlfo.modenv); + fluid_check_fpe("voice_write mod env"); + + /******************* lfo **********************/ + + fluid_lfo_calc(&voice->envlfo.modlfo, ticks); + fluid_check_fpe("voice_write mod LFO"); + fluid_lfo_calc(&voice->envlfo.viblfo, ticks); + fluid_check_fpe("voice_write vib LFO"); + + /******************* amplitude **********************/ + + count = fluid_rvoice_calc_amp(voice); + + if(count <= 0) + { + return count; /* return -1 if voice is quiet, 0 if voice has finished */ + } + + /******************* phase **********************/ + + /* SF2.04 section 8.1.2 #26: + * attack of modEnv is convex ?!? + */ + modenv_val = (fluid_adsr_env_get_section(&voice->envlfo.modenv) == FLUID_VOICE_ENVATTACK) + ? fluid_convex(127 * fluid_adsr_env_get_val(&voice->envlfo.modenv)) + : fluid_adsr_env_get_val(&voice->envlfo.modenv); + /* Calculate the number of samples, that the DSP loop advances + * through the original waveform with each step in the output + * buffer. It is the ratio between the frequencies of original + * waveform and output waveform.*/ + voice->dsp.phase_incr = fluid_ct2hz_real(voice->dsp.pitch + + voice->dsp.pitchoffset + + fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_pitch + + fluid_lfo_get_val(&voice->envlfo.viblfo) * voice->envlfo.viblfo_to_pitch + + modenv_val * voice->envlfo.modenv_to_pitch) + / voice->dsp.root_pitch_hz; + + /******************* portamento ****************/ + /* pitchoffset is updated if enabled. + Pitchoffset will be added to dsp pitch at next phase calculation time */ + + /* In most cases portamento will be disabled. Thus first verify that portamento is + * enabled before updating pitchoffset and before disabling portamento when necessary, + * in order to keep the performance loss at minimum. + * If the algorithm would first update pitchoffset and then verify if portamento + * needs to be disabled, there would be a significant performance drop on a x87 FPU + */ + if(voice->dsp.pitchinc > 0.0f) + { + /* portamento is enabled, so update pitchoffset */ + voice->dsp.pitchoffset += voice->dsp.pitchinc; + + /* when pitchoffset reaches 0.0f, portamento is disabled */ + if(voice->dsp.pitchoffset > 0.0f) + { + voice->dsp.pitchoffset = voice->dsp.pitchinc = 0.0f; + } + } + else if(voice->dsp.pitchinc < 0.0f) + { + /* portamento is enabled, so update pitchoffset */ + voice->dsp.pitchoffset += voice->dsp.pitchinc; + + /* when pitchoffset reaches 0.0f, portamento is disabled */ + if(voice->dsp.pitchoffset < 0.0f) + { + voice->dsp.pitchoffset = voice->dsp.pitchinc = 0.0f; + } + } + + fluid_check_fpe("voice_write phase calculation"); + + /* if phase_incr is not advancing, set it to the minimum fraction value (prevent stuckage) */ + if(voice->dsp.phase_incr == 0) + { + voice->dsp.phase_incr = 1; + } + + /* voice is currently looping? */ + is_looping = voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE + || (voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE + && fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE); + + /*********************** run the dsp chain ************************ + * The sample is mixed with the output buffer. + * The buffer has to be filled from 0 to FLUID_BUFSIZE-1. + * Depending on the position in the loop and the loop size, this + * may require several runs. */ + + switch(voice->dsp.interp_method) + { + case FLUID_INTERP_NONE: + count = fluid_rvoice_dsp_interpolate_none(&voice->dsp, dsp_buf, is_looping); + break; + + case FLUID_INTERP_LINEAR: + count = fluid_rvoice_dsp_interpolate_linear(&voice->dsp, dsp_buf, is_looping); + break; + + case FLUID_INTERP_4THORDER: + default: + count = fluid_rvoice_dsp_interpolate_4th_order(&voice->dsp, dsp_buf, is_looping); + break; + + case FLUID_INTERP_7THORDER: + count = fluid_rvoice_dsp_interpolate_7th_order(&voice->dsp, dsp_buf, is_looping); + break; + } + + fluid_check_fpe("voice_write interpolation"); + + if(count == 0) + { + return count; + } + + /*************** resonant filter ******************/ + + fluid_iir_filter_calc(&voice->resonant_filter, voice->dsp.output_rate, + fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_fc + + modenv_val * voice->envlfo.modenv_to_fc); + + fluid_iir_filter_apply(&voice->resonant_filter, dsp_buf, count); + + /* additional custom filter - only uses the fixed modulator, no lfos... */ + fluid_iir_filter_calc(&voice->resonant_custom_filter, voice->dsp.output_rate, 0); + fluid_iir_filter_apply(&voice->resonant_custom_filter, dsp_buf, count); + + return count; +} + +/** + * Initialize buffers up to (and including) bufnum + */ +static int +fluid_rvoice_buffers_check_bufnum(fluid_rvoice_buffers_t *buffers, unsigned int bufnum) +{ + unsigned int i; + + if(bufnum < buffers->count) + { + return FLUID_OK; + } + + if(bufnum >= FLUID_RVOICE_MAX_BUFS) + { + return FLUID_FAILED; + } + + for(i = buffers->count; i <= bufnum; i++) + { + buffers->bufs[i].target_amp = 0.0f; + buffers->bufs[i].current_amp = 0.0f; + } + + buffers->count = bufnum + 1; + return FLUID_OK; +} + + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_amp) +{ + fluid_rvoice_buffers_t *buffers = obj; + unsigned int bufnum = param[0].i; + fluid_real_t value = param[1].real; + + if(fluid_rvoice_buffers_check_bufnum(buffers, bufnum) != FLUID_OK) + { + return; + } + + buffers->bufs[bufnum].target_amp = value; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_mapping) +{ + fluid_rvoice_buffers_t *buffers = obj; + unsigned int bufnum = param[0].i; + int mapping = param[1].i; + + if(fluid_rvoice_buffers_check_bufnum(buffers, bufnum) != FLUID_OK) + { + return; + } + + buffers->bufs[bufnum].mapping = mapping; +} + + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_reset) +{ + fluid_rvoice_t *voice = obj; + + voice->dsp.has_looped = 0; + voice->envlfo.ticks = 0; + voice->envlfo.noteoff_ticks = 0; + voice->dsp.amp = 0.0f; /* The last value of the volume envelope, used to + calculate the volume increment during + processing */ + + /* legato initialization */ + voice->dsp.pitchoffset = 0.0; /* portamento initialization */ + voice->dsp.pitchinc = 0.0; + + /* mod env initialization*/ + fluid_adsr_env_reset(&voice->envlfo.modenv); + + /* vol env initialization */ + fluid_adsr_env_reset(&voice->envlfo.volenv); + + /* Fixme: Retrieve from any other existing + voice on this channel to keep LFOs in + unison? */ + fluid_lfo_reset(&voice->envlfo.viblfo); + fluid_lfo_reset(&voice->envlfo.modlfo); + + /* Clear sample history in filter */ + fluid_iir_filter_reset(&voice->resonant_filter); + fluid_iir_filter_reset(&voice->resonant_custom_filter); + + /* Force setting of the phase at the first DSP loop run + * This cannot be done earlier, because it depends on modulators. + [DH] Is that comment really true? */ + voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_STARTUP; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_noteoff) +{ + fluid_rvoice_t *rvoice = obj; + unsigned int min_ticks = param[0].i; + + fluid_rvoice_noteoff_LOCAL(rvoice, min_ticks); +} + +static void +fluid_rvoice_noteoff_LOCAL(fluid_rvoice_t *voice, unsigned int min_ticks) +{ + if(min_ticks > voice->envlfo.ticks) + { + /* Delay noteoff */ + voice->envlfo.noteoff_ticks = min_ticks; + return; + } + + voice->envlfo.noteoff_ticks = 0; + + if(fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVATTACK) + { + /* A voice is turned off during the attack section of the volume + * envelope. The attack section ramps up linearly with + * amplitude. The other sections use logarithmic scaling. Calculate new + * volenv_val to achieve equivalent amplitude during the release phase + * for seamless volume transition. + */ + if(fluid_adsr_env_get_val(&voice->envlfo.volenv) > 0) + { + fluid_real_t lfo = fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol; + fluid_real_t amp = fluid_adsr_env_get_val(&voice->envlfo.volenv) * fluid_cb2amp(lfo); + fluid_real_t env_value = - (((-200.f / FLUID_M_LN10) * FLUID_LOGF(amp) - lfo) / FLUID_PEAK_ATTENUATION - 1); + fluid_clip(env_value, 0.0f, 1.0f); + fluid_adsr_env_set_val(&voice->envlfo.volenv, env_value); + } + } + + if(fluid_adsr_env_get_section(&voice->envlfo.modenv) == FLUID_VOICE_ENVATTACK) + { + /* A voice is turned off during the attack section of the modulation + * envelope. The attack section use convex scaling with pitch and filter + * frequency cutoff (see fluid_rvoice_write(): modenv_val = fluid_convex(127 * modenv.val) + * The other sections use linear scaling: modenv_val = modenv.val + * + * Calculate new modenv.val to achieve equivalent modenv_val during the release phase + * for seamless pitch and filter frequency cutoff transition. + */ + if(fluid_adsr_env_get_val(&voice->envlfo.modenv) > 0) + { + fluid_real_t env_value = fluid_convex(127 * fluid_adsr_env_get_val(&voice->envlfo.modenv)); + fluid_clip(env_value, 0.0, 1.0); + fluid_adsr_env_set_val(&voice->envlfo.modenv, env_value); + } + } + + fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVRELEASE); + fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVRELEASE); +} + +/** + * skips to Attack section + * + * Updates vol and attack data + * Correction on volume val to achieve equivalent amplitude at noteOn legato + * + * @param voice the synthesis voice to be updated +*/ +static FLUID_INLINE void fluid_rvoice_local_retrigger_attack(fluid_rvoice_t *voice) +{ + /* skips to Attack section */ + /* Once in Attack section, current count must be reset, to be sure + that the section will be not be prematurely finished. */ + fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVATTACK); + { + /* Correction on volume val to achieve equivalent amplitude at noteOn legato */ + fluid_env_data_t *env_data; + fluid_real_t peak = fluid_cb2amp(voice->dsp.attenuation); + fluid_real_t prev_peak = fluid_cb2amp(voice->dsp.prev_attenuation); + voice->envlfo.volenv.val = (voice->envlfo.volenv.val * prev_peak) / peak; + /* Correction on slope direction for Attack section */ + env_data = &voice->envlfo.volenv.data[FLUID_VOICE_ENVATTACK]; + + if(voice->envlfo.volenv.val <= 1.0f) + { + /* slope attack for legato note needs to be positive from val up to 1 */ + env_data->increment = 1.0f / env_data->count; + env_data->min = -1.0f; + env_data->max = 1.0f; + } + else + { + /* slope attack for legato note needs to be negative: from val down to 1 */ + env_data->increment = -voice->envlfo.volenv.val / env_data->count; + env_data->min = 1.0f; + env_data->max = voice->envlfo.volenv.val; + } + } +} + +/** + * Used by legato Mode : multi_retrigger + * see fluid_synth_noteon_mono_legato_multi_retrigger() + * @param voice the synthesis voice to be updated +*/ +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_multi_retrigger_attack) +{ + fluid_rvoice_t *voice = obj; + int section; /* volume or modulation section */ + + /*------------------------------------------------------------------------- + Section skip for volume envelope + --------------------------------------------------------------------------*/ + section = fluid_adsr_env_get_section(&voice->envlfo.volenv); + if(section >= FLUID_VOICE_ENVHOLD) + { + /* DECAY, SUSTAIN,RELEASE section use logarithmic scaling. Calculates new + volenv_val to achieve equivalent amplitude during the attack phase + for seamless volume transition. */ + fluid_real_t amp_cb, env_value; + amp_cb = FLUID_PEAK_ATTENUATION * + (1.0f - fluid_adsr_env_get_val(&voice->envlfo.volenv)); + env_value = fluid_cb2amp(amp_cb); /* a bit of optimization */ + fluid_clip(env_value, 0.0, 1.0); + fluid_adsr_env_set_val(&voice->envlfo.volenv, env_value); + /* next, skips to Attack section */ + } + + /* skips to Attack section from any section */ + /* Update vol and attack data */ + fluid_rvoice_local_retrigger_attack(voice); + + /*------------------------------------------------------------------------- + Section skip for modulation envelope + --------------------------------------------------------------------------*/ + section = fluid_adsr_env_get_section(&voice->envlfo.modenv); + if(section >= FLUID_VOICE_ENVHOLD) + { + /* DECAY, SUSTAIN,RELEASE section use linear scaling. + Since v 2.1 , as recommended by soundfont 2.01/2.4 spec, ATTACK section + uses convex shape (see fluid_rvoice_write() - fluid_convex()). + Calculate new modenv value (new_value) for seamless attack transition. + Here we need the inverse of fluid_convex() function defined as: + new_value = pow(10, (1 - current_val) . FLUID_PEAK_ATTENUATION / -200 . 2.0) + For performance reason we use fluid_cb2amp(Val) = pow(10, val/-200) with + val = (1 - current_val) . FLUID_PEAK_ATTENUATION / 2.0 + */ + fluid_real_t new_value; /* new modenv value */ + new_value = fluid_cb2amp((1.0f - fluid_adsr_env_get_val(&voice->envlfo.modenv)) + * FLUID_PEAK_ATTENUATION / 2.0); + fluid_clip(new_value, 0.0, 1.0); + fluid_adsr_env_set_val(&voice->envlfo.modenv, new_value); + } + /* Skips from any section to ATTACK section */ + fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVATTACK); +} + +/** + * sets the portamento dsp parameters: dsp.pitchoffset, dsp.pitchinc + * @param voice rvoice to set portamento. + * @param countinc increment count number. + * @param pitchoffset pitch offset to apply to voice dsp.pitch. + * + * Notes: + * 1) To get continuous portamento between consecutive noteOn (n1,n2,n3...), + * pitchoffset is accumulated in current dsp pitchoffset. + * 2) And to get constant portamento duration, dsp pitch increment is updated. +*/ +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_portamento) +{ + fluid_rvoice_t *voice = obj; + unsigned int countinc = param[0].i; + fluid_real_t pitchoffset = param[1].real; + + if(countinc) + { + voice->dsp.pitchoffset += pitchoffset; + voice->dsp.pitchinc = - voice->dsp.pitchoffset / countinc; + } + + /* Then during the voice processing (in fluid_rvoice_write()), + dsp.pitchoffset will be incremented by dsp pitchinc. */ +} + + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_output_rate) +{ + fluid_rvoice_t *voice = obj; + fluid_real_t value = param[0].real; + + voice->dsp.output_rate = value; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_interp_method) +{ + fluid_rvoice_t *voice = obj; + int value = param[0].i; + + voice->dsp.interp_method = value; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_root_pitch_hz) +{ + fluid_rvoice_t *voice = obj; + fluid_real_t value = param[0].real; + + voice->dsp.root_pitch_hz = value; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_pitch) +{ + fluid_rvoice_t *voice = obj; + fluid_real_t value = param[0].real; + + voice->dsp.pitch = value; +} + + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_attenuation) +{ + fluid_rvoice_t *voice = obj; + fluid_real_t value = param[0].real; + + voice->dsp.prev_attenuation = voice->dsp.attenuation; + voice->dsp.attenuation = value; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_min_attenuation_cB) +{ + fluid_rvoice_t *voice = obj; + fluid_real_t value = param[0].real; + + voice->dsp.min_attenuation_cB = value; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_viblfo_to_pitch) +{ + fluid_rvoice_t *voice = obj; + fluid_real_t value = param[0].real; + + voice->envlfo.viblfo_to_pitch = value; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_pitch) +{ + fluid_rvoice_t *voice = obj; + fluid_real_t value = param[0].real; + + voice->envlfo.modlfo_to_pitch = value; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_vol) +{ + fluid_rvoice_t *voice = obj; + fluid_real_t value = param[0].real; + + voice->envlfo.modlfo_to_vol = value; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_fc) +{ + fluid_rvoice_t *voice = obj; + fluid_real_t value = param[0].real; + + voice->envlfo.modlfo_to_fc = value; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modenv_to_fc) +{ + fluid_rvoice_t *voice = obj; + fluid_real_t value = param[0].real; + + voice->envlfo.modenv_to_fc = value; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modenv_to_pitch) +{ + fluid_rvoice_t *voice = obj; + fluid_real_t value = param[0].real; + + voice->envlfo.modenv_to_pitch = value; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_synth_gain) +{ + fluid_rvoice_t *voice = obj; + fluid_real_t value = param[0].real; + + voice->dsp.synth_gain = value; + + /* For a looped sample, this value will be overwritten as soon as the + * loop parameters are initialized (they may depend on modulators). + * This value can be kept, it is a worst-case estimate. + */ + voice->dsp.amplitude_that_reaches_noise_floor_nonloop = FLUID_NOISE_FLOOR / value; + voice->dsp.amplitude_that_reaches_noise_floor_loop = FLUID_NOISE_FLOOR / value; + voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_start) +{ + fluid_rvoice_t *voice = obj; + int value = param[0].i; + + voice->dsp.start = value; + voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_end) +{ + fluid_rvoice_t *voice = obj; + int value = param[0].i; + + voice->dsp.end = value; + voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_loopstart) +{ + fluid_rvoice_t *voice = obj; + int value = param[0].i; + + voice->dsp.loopstart = value; + voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_loopend) +{ + fluid_rvoice_t *voice = obj; + int value = param[0].i; + + voice->dsp.loopend = value; + voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_samplemode) +{ + fluid_rvoice_t *voice = obj; + enum fluid_loop value = param[0].i; + + voice->dsp.samplemode = value; + voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_CHECK; +} + + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_sample) +{ + fluid_rvoice_t *voice = obj; + fluid_sample_t *value = param[0].ptr; + + voice->dsp.sample = value; + + if(value) + { + voice->dsp.check_sample_sanity_flag |= FLUID_SAMPLESANITY_STARTUP; + } +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_voiceoff) +{ + fluid_rvoice_t *voice = obj; + + fluid_adsr_env_set_section(&voice->envlfo.volenv, FLUID_VOICE_ENVFINISHED); + fluid_adsr_env_set_section(&voice->envlfo.modenv, FLUID_VOICE_ENVFINISHED); +} diff --git a/libs/fluidsynth/src/rvoice/fluid_rvoice.h b/libs/fluidsynth/src/rvoice/fluid_rvoice.h new file mode 100644 index 00000000000..610afd72529 --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_rvoice.h @@ -0,0 +1,231 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#ifndef _FLUID_RVOICE_H +#define _FLUID_RVOICE_H + +#include "fluidsynth_priv.h" +#include "fluid_iir_filter.h" +#include "fluid_adsr_env.h" +#include "fluid_lfo.h" +#include "fluid_phase.h" +#include "fluid_sfont.h" + +typedef struct _fluid_rvoice_envlfo_t fluid_rvoice_envlfo_t; +typedef struct _fluid_rvoice_dsp_t fluid_rvoice_dsp_t; +typedef struct _fluid_rvoice_buffers_t fluid_rvoice_buffers_t; +typedef struct _fluid_rvoice_t fluid_rvoice_t; + +/* Smallest amplitude that can be perceived (full scale is +/- 0.5) + * 16 bits => 96+4=100 dB dynamic range => 0.00001 + * 24 bits => 144-4 = 140 dB dynamic range => 1.e-7 + * 1.e-7 * 2 == 2.e-7 :) + */ +#define FLUID_NOISE_FLOOR ((fluid_real_t)2.e-7) + +enum fluid_loop +{ + FLUID_UNLOOPED = 0, + FLUID_LOOP_DURING_RELEASE = 1, + FLUID_NOTUSED = 2, + FLUID_LOOP_UNTIL_RELEASE = 3 +}; + +/* + * rvoice ticks-based parameters + * These parameters must be updated even if the voice is currently quiet. + */ +struct _fluid_rvoice_envlfo_t +{ + /* Note-off minimum length */ + unsigned int ticks; + unsigned int noteoff_ticks; + + /* vol env */ + fluid_adsr_env_t volenv; + + /* mod env */ + fluid_adsr_env_t modenv; + fluid_real_t modenv_to_fc; + fluid_real_t modenv_to_pitch; + + /* mod lfo */ + fluid_lfo_t modlfo; + fluid_real_t modlfo_to_fc; + fluid_real_t modlfo_to_pitch; + fluid_real_t modlfo_to_vol; + + /* vib lfo */ + fluid_lfo_t viblfo; + fluid_real_t viblfo_to_pitch; +}; + +/* + * rvoice parameters needed for dsp interpolation + */ +struct _fluid_rvoice_dsp_t +{ + /* interpolation method, as in fluid_interp in fluidsynth.h */ + enum fluid_interp interp_method; + enum fluid_loop samplemode; + + /* Flag that is set as soon as the first loop is completed. */ + char has_looped; + + /* Flag that initiates, that sample-related parameters have to be checked. */ + char check_sample_sanity_flag; + + fluid_sample_t *sample; + + /* sample and loop start and end points (offset in sample memory). */ + int start; + int end; + int loopstart; + int loopend; /* Note: first point following the loop (superimposed on loopstart) */ + + /* Stuff needed for portamento calculations */ + fluid_real_t pitchoffset; /* the portamento range in midicents */ + fluid_real_t pitchinc; /* the portamento increment in midicents */ + + /* Stuff needed for phase calculations */ + + fluid_real_t pitch; /* the pitch in midicents */ + fluid_real_t root_pitch_hz; + fluid_real_t output_rate; + + /* Stuff needed for amplitude calculations */ + + fluid_real_t attenuation; /* the attenuation in centibels */ + fluid_real_t prev_attenuation; /* the previous attenuation in centibels + used by fluid_rvoice_multi_retrigger_attack() */ + fluid_real_t min_attenuation_cB; /* Estimate on the smallest possible attenuation + * during the lifetime of the voice */ + fluid_real_t amplitude_that_reaches_noise_floor_nonloop; + fluid_real_t amplitude_that_reaches_noise_floor_loop; + fluid_real_t synth_gain; /* master gain */ + + /* Dynamic input to the interpolator below */ + + fluid_real_t amp; /* current linear amplitude */ + fluid_real_t amp_incr; /* amplitude increment value for the next FLUID_BUFSIZE samples */ + + fluid_phase_t phase; /* the phase (current sample offset) of the sample wave */ + fluid_real_t phase_incr; /* the phase increment for the next FLUID_BUFSIZE samples */ +}; + +/* Currently left, right, reverb, chorus. To be changed if we + ever add surround positioning, or stereo reverb/chorus */ +#define FLUID_RVOICE_MAX_BUFS (4) + +/* + * rvoice mixer-related parameters + */ +struct _fluid_rvoice_buffers_t +{ + unsigned int count; /* Number of records in "bufs" */ + struct + { + /* the actual, linearly interpolated amplitude with which the dsp sample should be mixed into the buf */ + fluid_real_t current_amp; + + /* the desired amplitude [...] mixed into the buf (directly set by e.g. rapidly changing PAN events) */ + fluid_real_t target_amp; + + /* Mapping to mixdown buffer index */ + int mapping; + } bufs[FLUID_RVOICE_MAX_BUFS]; +}; + + +/* + * Hard real-time parameters needed to synthesize a voice + */ +struct _fluid_rvoice_t +{ + fluid_rvoice_envlfo_t envlfo; + fluid_rvoice_dsp_t dsp; + fluid_iir_filter_t resonant_filter; /* IIR resonant dsp filter */ + fluid_iir_filter_t resonant_custom_filter; /* optional custom/general-purpose IIR resonant filter */ + fluid_rvoice_buffers_t buffers; +}; + + +int fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf); + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_amp); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_mapping); + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_noteoff); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_voiceoff); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_reset); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_multi_retrigger_attack); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_portamento); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_output_rate); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_interp_method); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_root_pitch_hz); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_pitch); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_attenuation); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_min_attenuation_cB); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_viblfo_to_pitch); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_pitch); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_vol); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_fc); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modenv_to_fc); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modenv_to_pitch); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_synth_gain); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_start); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_end); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_loopstart); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_loopend); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_samplemode); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_sample); + +/* defined in fluid_rvoice_dsp.c */ +void fluid_rvoice_dsp_config(void); +int fluid_rvoice_dsp_interpolate_none(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping); +int fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping); +int fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping); +int fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping); + + +/* + * Combines the most significant 16 bit part of a sample with a potentially present + * least sig. 8 bit part in order to create a 24 bit sample. + */ +static FLUID_INLINE int32_t +fluid_rvoice_get_sample(const short int *dsp_msb, const char *dsp_lsb, unsigned int idx) +{ + /* cast sample to unsigned type, so we can safely shift and bitwise or + * without relying on undefined behaviour (should never happen anyway ofc...) */ + uint32_t msb = (uint32_t)dsp_msb[idx]; + uint8_t lsb = 0U; + + /* most soundfonts have 16 bit samples, assume that it's unlikely we + * experience 24 bit samples here */ + if(FLUID_UNLIKELY(dsp_lsb != NULL)) + { + lsb = (uint8_t)dsp_lsb[idx]; + } + + return (int32_t)((msb << 8) | lsb); +} + +#endif diff --git a/libs/fluidsynth/src/rvoice/fluid_rvoice_dsp.c b/libs/fluidsynth/src/rvoice/fluid_rvoice_dsp.c new file mode 100644 index 00000000000..b43a0f19077 --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_rvoice_dsp.c @@ -0,0 +1,636 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include "fluid_sys.h" +#include "fluid_phase.h" +#include "fluid_rvoice.h" +#include "fluid_rvoice_dsp_tables.inc.h" + +/* Purpose: + * + * Interpolates audio data (obtains values between the samples of the original + * waveform data). + * + * Variables loaded from the voice structure (assigned in fluid_rvoice_write()): + * - dsp_data: Pointer to the original waveform data + * - dsp_phase: The position in the original waveform data. + * This has an integer and a fractional part (between samples). + * - dsp_phase_incr: For each output sample, the position in the original + * waveform advances by dsp_phase_incr. This also has an integer + * part and a fractional part. + * If a sample is played at root pitch (no pitch change), + * dsp_phase_incr is integer=1 and fractional=0. + * - dsp_amp: The current amplitude envelope value. + * - dsp_amp_incr: The changing rate of the amplitude envelope. + * + * A couple of variables are used internally, their results are discarded: + * - dsp_i: Index through the output buffer + * - dsp_buf: Output buffer of floating point values (FLUID_BUFSIZE in length) + */ + +/* Interpolation (find a value between two samples of the original waveform) */ + +static FLUID_INLINE fluid_real_t +fluid_rvoice_get_float_sample(const short int *dsp_msb, const char *dsp_lsb, unsigned int idx) +{ + int32_t sample = fluid_rvoice_get_sample(dsp_msb, dsp_lsb, idx); + return (fluid_real_t)sample; +} + +/* No interpolation. Just take the sample, which is closest to + * the playback pointer. Questionable quality, but very + * efficient. */ +int +fluid_rvoice_dsp_interpolate_none(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +{ + fluid_phase_t dsp_phase = voice->phase; + fluid_phase_t dsp_phase_incr; + short int *dsp_data = voice->sample->data; + char *dsp_data24 = voice->sample->data24; + fluid_real_t dsp_amp = voice->amp; + fluid_real_t dsp_amp_incr = voice->amp_incr; + unsigned int dsp_i = 0; + unsigned int dsp_phase_index; + unsigned int end_index; + + /* Convert playback "speed" floating point value to phase index/fract */ + fluid_phase_set_float(dsp_phase_incr, voice->phase_incr); + + end_index = looping ? voice->loopend - 1 : voice->end; + + while(1) + { + dsp_phase_index = fluid_phase_index_round(dsp_phase); /* round to nearest point */ + + /* interpolate sequence of sample points */ + for(; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++) + { + dsp_buf[dsp_i] = dsp_amp * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index); + + /* increment phase and amplitude */ + fluid_phase_incr(dsp_phase, dsp_phase_incr); + dsp_phase_index = fluid_phase_index_round(dsp_phase); /* round to nearest point */ + dsp_amp += dsp_amp_incr; + } + + /* break out if not looping (buffer may not be full) */ + if(!looping) + { + break; + } + + /* go back to loop start */ + if(dsp_phase_index > end_index) + { + fluid_phase_sub_int(dsp_phase, voice->loopend - voice->loopstart); + voice->has_looped = 1; + } + + /* break out if filled buffer */ + if(dsp_i >= FLUID_BUFSIZE) + { + break; + } + } + + voice->phase = dsp_phase; + voice->amp = dsp_amp; + + return (dsp_i); +} + +/* Straight line interpolation. + * Returns number of samples processed (usually FLUID_BUFSIZE but could be + * smaller if end of sample occurs). + */ +int +fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +{ + fluid_phase_t dsp_phase = voice->phase; + fluid_phase_t dsp_phase_incr; + short int *dsp_data = voice->sample->data; + char *dsp_data24 = voice->sample->data24; + fluid_real_t dsp_amp = voice->amp; + fluid_real_t dsp_amp_incr = voice->amp_incr; + unsigned int dsp_i = 0; + unsigned int dsp_phase_index; + unsigned int end_index; + fluid_real_t point; + const fluid_real_t *FLUID_RESTRICT coeffs; + + /* Convert playback "speed" floating point value to phase index/fract */ + fluid_phase_set_float(dsp_phase_incr, voice->phase_incr); + + /* last index before 2nd interpolation point must be specially handled */ + end_index = (looping ? voice->loopend - 1 : voice->end) - 1; + + /* 2nd interpolation point to use at end of loop or sample */ + if(looping) + { + point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart); /* loop start */ + } + else + { + point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->end); /* duplicate end for samples no longer looping */ + } + + while(1) + { + dsp_phase_index = fluid_phase_index(dsp_phase); + + /* interpolate the sequence of sample points */ + for(; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++) + { + coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow(dsp_phase)]; + dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1)); + + /* increment phase and amplitude */ + fluid_phase_incr(dsp_phase, dsp_phase_incr); + dsp_phase_index = fluid_phase_index(dsp_phase); + dsp_amp += dsp_amp_incr; + } + + /* break out if buffer filled */ + if(dsp_i >= FLUID_BUFSIZE) + { + break; + } + + end_index++; /* we're now interpolating the last point */ + + /* interpolate within last point */ + for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++) + { + coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow(dsp_phase)]; + dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[1] * point); + + /* increment phase and amplitude */ + fluid_phase_incr(dsp_phase, dsp_phase_incr); + dsp_phase_index = fluid_phase_index(dsp_phase); + dsp_amp += dsp_amp_incr; /* increment amplitude */ + } + + if(!looping) + { + break; /* break out if not looping (end of sample) */ + } + + /* go back to loop start (if past */ + if(dsp_phase_index > end_index) + { + fluid_phase_sub_int(dsp_phase, voice->loopend - voice->loopstart); + voice->has_looped = 1; + } + + /* break out if filled buffer */ + if(dsp_i >= FLUID_BUFSIZE) + { + break; + } + + end_index--; /* set end back to second to last sample point */ + } + + voice->phase = dsp_phase; + voice->amp = dsp_amp; + + return (dsp_i); +} + +/* 4th order (cubic) interpolation. + * Returns number of samples processed (usually FLUID_BUFSIZE but could be + * smaller if end of sample occurs). + */ +int +fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +{ + fluid_phase_t dsp_phase = voice->phase; + fluid_phase_t dsp_phase_incr; + short int *dsp_data = voice->sample->data; + char *dsp_data24 = voice->sample->data24; + fluid_real_t dsp_amp = voice->amp; + fluid_real_t dsp_amp_incr = voice->amp_incr; + unsigned int dsp_i = 0; + unsigned int dsp_phase_index; + unsigned int start_index, end_index; + fluid_real_t start_point, end_point1, end_point2; + const fluid_real_t *FLUID_RESTRICT coeffs; + + /* Convert playback "speed" floating point value to phase index/fract */ + fluid_phase_set_float(dsp_phase_incr, voice->phase_incr); + + /* last index before 4th interpolation point must be specially handled */ + end_index = (looping ? voice->loopend - 1 : voice->end) - 2; + + if(voice->has_looped) /* set start_index and start point if looped or not */ + { + start_index = voice->loopstart; + start_point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 1); /* last point in loop (wrap around) */ + } + else + { + start_index = voice->start; + start_point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->start); /* just duplicate the point */ + } + + /* get points off the end (loop start if looping, duplicate point if end) */ + if(looping) + { + end_point1 = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart); + end_point2 = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart + 1); + } + else + { + end_point1 = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->end); + end_point2 = end_point1; + } + + while(1) + { + dsp_phase_index = fluid_phase_index(dsp_phase); + + /* interpolate first sample point (start or loop start) if needed */ + for(; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++) + { + coeffs = interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)]; + dsp_buf[dsp_i] = dsp_amp * + (coeffs[0] * start_point + + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) + + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2)); + + /* increment phase and amplitude */ + fluid_phase_incr(dsp_phase, dsp_phase_incr); + dsp_phase_index = fluid_phase_index(dsp_phase); + dsp_amp += dsp_amp_incr; + } + + /* interpolate the sequence of sample points */ + for(; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++) + { + coeffs = interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)]; + dsp_buf[dsp_i] = dsp_amp * + (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) + + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2)); + + /* increment phase and amplitude */ + fluid_phase_incr(dsp_phase, dsp_phase_incr); + dsp_phase_index = fluid_phase_index(dsp_phase); + dsp_amp += dsp_amp_incr; + } + + /* break out if buffer filled */ + if(dsp_i >= FLUID_BUFSIZE) + { + break; + } + + end_index++; /* we're now interpolating the 2nd to last point */ + + /* interpolate within 2nd to last point */ + for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++) + { + coeffs = interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)]; + dsp_buf[dsp_i] = dsp_amp * + (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) + + coeffs[3] * end_point1); + + /* increment phase and amplitude */ + fluid_phase_incr(dsp_phase, dsp_phase_incr); + dsp_phase_index = fluid_phase_index(dsp_phase); + dsp_amp += dsp_amp_incr; + } + + end_index++; /* we're now interpolating the last point */ + + /* interpolate within the last point */ + for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++) + { + coeffs = interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)]; + dsp_buf[dsp_i] = dsp_amp * + (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[2] * end_point1 + + coeffs[3] * end_point2); + + /* increment phase and amplitude */ + fluid_phase_incr(dsp_phase, dsp_phase_incr); + dsp_phase_index = fluid_phase_index(dsp_phase); + dsp_amp += dsp_amp_incr; + } + + if(!looping) + { + break; /* break out if not looping (end of sample) */ + } + + /* go back to loop start */ + if(dsp_phase_index > end_index) + { + fluid_phase_sub_int(dsp_phase, voice->loopend - voice->loopstart); + + if(!voice->has_looped) + { + voice->has_looped = 1; + start_index = voice->loopstart; + start_point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 1); + } + } + + /* break out if filled buffer */ + if(dsp_i >= FLUID_BUFSIZE) + { + break; + } + + end_index -= 2; /* set end back to third to last sample point */ + } + + voice->phase = dsp_phase; + voice->amp = dsp_amp; + + return (dsp_i); +} + +/* 7th order interpolation. + * Returns number of samples processed (usually FLUID_BUFSIZE but could be + * smaller if end of sample occurs). + */ +int +fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping) +{ + fluid_phase_t dsp_phase = voice->phase; + fluid_phase_t dsp_phase_incr; + short int *dsp_data = voice->sample->data; + char *dsp_data24 = voice->sample->data24; + fluid_real_t dsp_amp = voice->amp; + fluid_real_t dsp_amp_incr = voice->amp_incr; + unsigned int dsp_i = 0; + unsigned int dsp_phase_index; + unsigned int start_index, end_index; + fluid_real_t start_points[3], end_points[3]; + const fluid_real_t *FLUID_RESTRICT coeffs; + + /* Convert playback "speed" floating point value to phase index/fract */ + fluid_phase_set_float(dsp_phase_incr, voice->phase_incr); + + /* add 1/2 sample to dsp_phase since 7th order interpolation is centered on + * the 4th sample point */ + fluid_phase_incr(dsp_phase, (fluid_phase_t)0x80000000); + + /* last index before 7th interpolation point must be specially handled */ + end_index = (looping ? voice->loopend - 1 : voice->end) - 3; + + if(voice->has_looped) /* set start_index and start point if looped or not */ + { + start_index = voice->loopstart; + start_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 1); + start_points[1] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 2); + start_points[2] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 3); + } + else + { + start_index = voice->start; + start_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->start); /* just duplicate the start point */ + start_points[1] = start_points[0]; + start_points[2] = start_points[0]; + } + + /* get the 3 points off the end (loop start if looping, duplicate point if end) */ + if(looping) + { + end_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart); + end_points[1] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart + 1); + end_points[2] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart + 2); + } + else + { + end_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->end); + end_points[1] = end_points[0]; + end_points[2] = end_points[0]; + } + + while(1) + { + dsp_phase_index = fluid_phase_index(dsp_phase); + + /* interpolate first sample point (start or loop start) if needed */ + for(; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++) + { + coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)]; + + dsp_buf[dsp_i] = dsp_amp + * (coeffs[0] * start_points[2] + + coeffs[1] * start_points[1] + + coeffs[2] * start_points[0] + + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) + + coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2) + + coeffs[6] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 3)); + + /* increment phase and amplitude */ + fluid_phase_incr(dsp_phase, dsp_phase_incr); + dsp_phase_index = fluid_phase_index(dsp_phase); + dsp_amp += dsp_amp_incr; + } + + start_index++; + + /* interpolate 2nd to first sample point (start or loop start) if needed */ + for(; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++) + { + coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)]; + + dsp_buf[dsp_i] = dsp_amp + * (coeffs[0] * start_points[1] + + coeffs[1] * start_points[0] + + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) + + coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2) + + coeffs[6] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 3)); + + /* increment phase and amplitude */ + fluid_phase_incr(dsp_phase, dsp_phase_incr); + dsp_phase_index = fluid_phase_index(dsp_phase); + dsp_amp += dsp_amp_incr; + } + + start_index++; + + /* interpolate 3rd to first sample point (start or loop start) if needed */ + for(; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++) + { + coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)]; + + dsp_buf[dsp_i] = dsp_amp + * (coeffs[0] * start_points[0] + + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 2) + + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) + + coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2) + + coeffs[6] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 3)); + + /* increment phase and amplitude */ + fluid_phase_incr(dsp_phase, dsp_phase_incr); + dsp_phase_index = fluid_phase_index(dsp_phase); + dsp_amp += dsp_amp_incr; + } + + start_index -= 2; /* set back to original start index */ + + + /* interpolate the sequence of sample points */ + for(; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++) + { + coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)]; + + dsp_buf[dsp_i] = dsp_amp + * (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 3) + + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 2) + + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) + + coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2) + + coeffs[6] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 3)); + + /* increment phase and amplitude */ + fluid_phase_incr(dsp_phase, dsp_phase_incr); + dsp_phase_index = fluid_phase_index(dsp_phase); + dsp_amp += dsp_amp_incr; + } + + /* break out if buffer filled */ + if(dsp_i >= FLUID_BUFSIZE) + { + break; + } + + end_index++; /* we're now interpolating the 3rd to last point */ + + /* interpolate within 3rd to last point */ + for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++) + { + coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)]; + + dsp_buf[dsp_i] = dsp_amp + * (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 3) + + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 2) + + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) + + coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 2) + + coeffs[6] * end_points[0]); + + /* increment phase and amplitude */ + fluid_phase_incr(dsp_phase, dsp_phase_incr); + dsp_phase_index = fluid_phase_index(dsp_phase); + dsp_amp += dsp_amp_incr; + } + + end_index++; /* we're now interpolating the 2nd to last point */ + + /* interpolate within 2nd to last point */ + for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++) + { + coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)]; + + dsp_buf[dsp_i] = dsp_amp + * (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 3) + + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 2) + + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index + 1) + + coeffs[5] * end_points[0] + + coeffs[6] * end_points[1]); + + /* increment phase and amplitude */ + fluid_phase_incr(dsp_phase, dsp_phase_incr); + dsp_phase_index = fluid_phase_index(dsp_phase); + dsp_amp += dsp_amp_incr; + } + + end_index++; /* we're now interpolating the last point */ + + /* interpolate within last point */ + for(; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++) + { + coeffs = sinc_table7[fluid_phase_fract_to_tablerow(dsp_phase)]; + + dsp_buf[dsp_i] = dsp_amp + * (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 3) + + coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 2) + + coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index - 1) + + coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index) + + coeffs[4] * end_points[0] + + coeffs[5] * end_points[1] + + coeffs[6] * end_points[2]); + + /* increment phase and amplitude */ + fluid_phase_incr(dsp_phase, dsp_phase_incr); + dsp_phase_index = fluid_phase_index(dsp_phase); + dsp_amp += dsp_amp_incr; + } + + if(!looping) + { + break; /* break out if not looping (end of sample) */ + } + + /* go back to loop start */ + if(dsp_phase_index > end_index) + { + fluid_phase_sub_int(dsp_phase, voice->loopend - voice->loopstart); + + if(!voice->has_looped) + { + voice->has_looped = 1; + start_index = voice->loopstart; + start_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 1); + start_points[1] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 2); + start_points[2] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 3); + } + } + + /* break out if filled buffer */ + if(dsp_i >= FLUID_BUFSIZE) + { + break; + } + + end_index -= 3; /* set end back to 4th to last sample point */ + } + + /* sub 1/2 sample from dsp_phase since 7th order interpolation is centered on + * the 4th sample point (correct back to real value) */ + fluid_phase_decr(dsp_phase, (fluid_phase_t)0x80000000); + + voice->phase = dsp_phase; + voice->amp = dsp_amp; + + return (dsp_i); +} diff --git a/libs/fluidsynth/src/rvoice/fluid_rvoice_event.c b/libs/fluidsynth/src/rvoice/fluid_rvoice_event.c new file mode 100644 index 00000000000..e60115f3617 --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_rvoice_event.c @@ -0,0 +1,202 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include "fluid_rvoice_event.h" +#include "fluid_rvoice.h" +#include "fluid_rvoice_mixer.h" +#include "fluid_iir_filter.h" +#include "fluid_lfo.h" +#include "fluid_adsr_env.h" + +static int fluid_rvoice_eventhandler_push_LOCAL(fluid_rvoice_eventhandler_t *handler, const fluid_rvoice_event_t *src_event); + +static FLUID_INLINE void +fluid_rvoice_event_dispatch(fluid_rvoice_event_t *event) +{ + event->method(event->object, event->param); +} + + +/** + * In order to be able to push more than one event atomically, + * use push for all events, then use flush to commit them to the + * queue. If threadsafe is false, all events are processed immediately. */ +int +fluid_rvoice_eventhandler_push_int_real(fluid_rvoice_eventhandler_t *handler, + fluid_rvoice_function_t method, void *object, int intparam, + fluid_real_t realparam) +{ + fluid_rvoice_event_t local_event; + + local_event.method = method; + local_event.object = object; + local_event.param[0].i = intparam; + local_event.param[1].real = realparam; + + return fluid_rvoice_eventhandler_push_LOCAL(handler, &local_event); +} + +int +fluid_rvoice_eventhandler_push(fluid_rvoice_eventhandler_t *handler, fluid_rvoice_function_t method, void *object, fluid_rvoice_param_t param[MAX_EVENT_PARAMS]) +{ + fluid_rvoice_event_t local_event; + + local_event.method = method; + local_event.object = object; + FLUID_MEMCPY(&local_event.param, param, sizeof(*param) * MAX_EVENT_PARAMS); + + return fluid_rvoice_eventhandler_push_LOCAL(handler, &local_event); +} + +int +fluid_rvoice_eventhandler_push_ptr(fluid_rvoice_eventhandler_t *handler, + fluid_rvoice_function_t method, void *object, void *ptr) +{ + fluid_rvoice_event_t local_event; + + local_event.method = method; + local_event.object = object; + local_event.param[0].ptr = ptr; + + return fluid_rvoice_eventhandler_push_LOCAL(handler, &local_event); +} + +static int fluid_rvoice_eventhandler_push_LOCAL(fluid_rvoice_eventhandler_t *handler, const fluid_rvoice_event_t *src_event) +{ + fluid_rvoice_event_t *event; + int old_queue_stored = fluid_atomic_int_add(&handler->queue_stored, 1); + + event = fluid_ringbuffer_get_inptr(handler->queue, old_queue_stored); + + if(event == NULL) + { + fluid_atomic_int_add(&handler->queue_stored, -1); + FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing synth.polyphony!"); + return FLUID_FAILED; // Buffer full... + } + + FLUID_MEMCPY(event, src_event, sizeof(*event)); + + return FLUID_OK; +} + + +void +fluid_rvoice_eventhandler_finished_voice_callback(fluid_rvoice_eventhandler_t *eventhandler, fluid_rvoice_t *rvoice) +{ + fluid_rvoice_t **vptr = fluid_ringbuffer_get_inptr(eventhandler->finished_voices, 0); + + if(vptr == NULL) + { + return; // Buffer full + } + + *vptr = rvoice; + fluid_ringbuffer_next_inptr(eventhandler->finished_voices, 1); +} + +fluid_rvoice_eventhandler_t * +new_fluid_rvoice_eventhandler(int queuesize, + int finished_voices_size, int bufs, int fx_bufs, int fx_units, + fluid_real_t sample_rate_max, fluid_real_t sample_rate, + int extra_threads, int prio) +{ + fluid_rvoice_eventhandler_t *eventhandler = FLUID_NEW(fluid_rvoice_eventhandler_t); + + if(eventhandler == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + eventhandler->mixer = NULL; + eventhandler->queue = NULL; + eventhandler->finished_voices = NULL; + + fluid_atomic_int_set(&eventhandler->queue_stored, 0); + + eventhandler->finished_voices = new_fluid_ringbuffer(finished_voices_size, + sizeof(fluid_rvoice_t *)); + + if(eventhandler->finished_voices == NULL) + { + goto error_recovery; + } + + eventhandler->queue = new_fluid_ringbuffer(queuesize, sizeof(fluid_rvoice_event_t)); + + if(eventhandler->queue == NULL) + { + goto error_recovery; + } + + eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, fx_units, + sample_rate_max, sample_rate, eventhandler, extra_threads, prio); + + if(eventhandler->mixer == NULL) + { + goto error_recovery; + } + + return eventhandler; + +error_recovery: + delete_fluid_rvoice_eventhandler(eventhandler); + return NULL; +} + +int +fluid_rvoice_eventhandler_dispatch_count(fluid_rvoice_eventhandler_t *handler) +{ + return fluid_ringbuffer_get_count(handler->queue); +} + + +/** + * Call fluid_rvoice_event_dispatch for all events in queue + * @return number of events dispatched + */ +int +fluid_rvoice_eventhandler_dispatch_all(fluid_rvoice_eventhandler_t *handler) +{ + fluid_rvoice_event_t *event; + int result = 0; + + while(NULL != (event = fluid_ringbuffer_get_outptr(handler->queue))) + { + fluid_rvoice_event_dispatch(event); + result++; + fluid_ringbuffer_next_outptr(handler->queue); + } + + return result; +} + + +void +delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t *handler) +{ + fluid_return_if_fail(handler != NULL); + + delete_fluid_rvoice_mixer(handler->mixer); + delete_fluid_ringbuffer(handler->queue); + delete_fluid_ringbuffer(handler->finished_voices); + FLUID_FREE(handler); +} diff --git a/libs/fluidsynth/src/rvoice/fluid_rvoice_event.h b/libs/fluidsynth/src/rvoice/fluid_rvoice_event.h new file mode 100644 index 00000000000..225e9069e13 --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_rvoice_event.h @@ -0,0 +1,114 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#ifndef _FLUID_RVOICE_EVENT_H +#define _FLUID_RVOICE_EVENT_H + +#include "fluidsynth_priv.h" +#include "fluid_rvoice_mixer.h" +#include "fluid_ringbuffer.h" + +typedef struct _fluid_rvoice_event_t fluid_rvoice_event_t; + +struct _fluid_rvoice_event_t +{ + fluid_rvoice_function_t method; + void *object; + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; +}; + +/* + * Bridge between the renderer thread and the midi state thread. + * fluid_rvoice_eventhandler_fetch_all() can be called in parallel + * with fluid_rvoice_eventhandler_push/flush() + */ +struct _fluid_rvoice_eventhandler_t +{ + fluid_ringbuffer_t *queue; /**< List of fluid_rvoice_event_t */ + fluid_atomic_int_t queue_stored; /**< Extras pushed but not flushed */ + fluid_ringbuffer_t *finished_voices; /**< return queue from handler, list of fluid_rvoice_t* */ + fluid_rvoice_mixer_t *mixer; +}; + +fluid_rvoice_eventhandler_t *new_fluid_rvoice_eventhandler( + int queuesize, int finished_voices_size, int bufs, + int fx_bufs, int fx_units, fluid_real_t sample_rate_max, fluid_real_t sample_rate, int, int); + +void delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t *); + +int fluid_rvoice_eventhandler_dispatch_all(fluid_rvoice_eventhandler_t *); +int fluid_rvoice_eventhandler_dispatch_count(fluid_rvoice_eventhandler_t *); +void fluid_rvoice_eventhandler_finished_voice_callback(fluid_rvoice_eventhandler_t *eventhandler, + fluid_rvoice_t *rvoice); + +static FLUID_INLINE void +fluid_rvoice_eventhandler_flush(fluid_rvoice_eventhandler_t *handler) +{ + int queue_stored = fluid_atomic_int_get(&handler->queue_stored); + + if(queue_stored > 0) + { + fluid_atomic_int_set(&handler->queue_stored, 0); + fluid_ringbuffer_next_inptr(handler->queue, queue_stored); + } +} + +/** + * @return next finished voice, or NULL if nothing in queue + */ +static FLUID_INLINE fluid_rvoice_t * +fluid_rvoice_eventhandler_get_finished_voice(fluid_rvoice_eventhandler_t *handler) +{ + void *result = fluid_ringbuffer_get_outptr(handler->finished_voices); + + if(result == NULL) + { + return NULL; + } + + result = * (fluid_rvoice_t **) result; + fluid_ringbuffer_next_outptr(handler->finished_voices); + return result; +} + + +int fluid_rvoice_eventhandler_push_int_real(fluid_rvoice_eventhandler_t *handler, + fluid_rvoice_function_t method, void *object, int intparam, + fluid_real_t realparam); + +int fluid_rvoice_eventhandler_push_ptr(fluid_rvoice_eventhandler_t *handler, + fluid_rvoice_function_t method, void *object, void *ptr); + +int fluid_rvoice_eventhandler_push(fluid_rvoice_eventhandler_t *handler, + fluid_rvoice_function_t method, void *object, + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]); + +static FLUID_INLINE void +fluid_rvoice_eventhandler_add_rvoice(fluid_rvoice_eventhandler_t *handler, + fluid_rvoice_t *rvoice) +{ + fluid_rvoice_eventhandler_push_ptr(handler, fluid_rvoice_mixer_add_voice, + handler->mixer, rvoice); +} + + + +#endif diff --git a/libs/fluidsynth/src/rvoice/fluid_rvoice_mixer.c b/libs/fluidsynth/src/rvoice/fluid_rvoice_mixer.c new file mode 100644 index 00000000000..490c7fb360d --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_rvoice_mixer.c @@ -0,0 +1,1727 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include "fluid_rvoice_mixer.h" +#include "fluid_rvoice.h" +#include "fluid_sys.h" +#include "fluid_rev.h" +#include "fluid_chorus.h" +#include "fluid_ladspa.h" +#include "fluid_synth.h" + + +// If less than x voices, the thread overhead is larger than the gain, +// so don't activate the thread(s). +#define VOICES_PER_THREAD 8 + +typedef struct _fluid_mixer_buffers_t fluid_mixer_buffers_t; + +struct _fluid_mixer_buffers_t +{ + fluid_rvoice_mixer_t *mixer; /**< Owner of object */ +#if ENABLE_MIXER_THREADS + fluid_thread_t *thread; /**< Thread object */ + fluid_atomic_int_t ready; /**< Atomic: buffers are ready for mixing */ +#endif + + fluid_rvoice_t **finished_voices; /* List of voices who have finished */ + int finished_voice_count; + + fluid_real_t *local_buf; + + int buf_count; + int fx_buf_count; + + /** buffer to store the left part of a stereo channel to. + * Specifically a two dimensional array, containing \c buf_count sample buffers + * (i.e. for each synth.audio-groups), of which each contains + * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT audio items (=samples) + * @note Each sample buffer is aligned to the FLUID_DEFAULT_ALIGNMENT + * boundary provided that this pointer points to an aligned buffer. + * So make sure to access the sample buffer by first aligning this + * pointer using fluid_align_ptr() + */ + fluid_real_t *left_buf; + + /** dito, but for right part of a stereo channel */ + fluid_real_t *right_buf; + + /** buffer to store the left part of a stereo effects channel to. + * Specifically a two dimensional array, containing \c fx_buf_count buffers + * (i.e. for each synth.effects-channels), of which each buffer contains + * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT audio items (=samples) + */ + fluid_real_t *fx_left_buf; + fluid_real_t *fx_right_buf; +}; + +typedef struct _fluid_mixer_fx_t fluid_mixer_fx_t; + +struct _fluid_mixer_fx_t +{ + fluid_revmodel_t *reverb; /**< Reverb unit */ + /* reverb shadow parameters here will be returned if queried */ + double reverb_param[FLUID_REVERB_PARAM_LAST]; + int reverb_on; /* reverb on/off */ + + fluid_chorus_t *chorus; /**< Chorus unit */ + /* chorus shadow parameters here will be returned if queried */ + double chorus_param[FLUID_CHORUS_PARAM_LAST]; + int chorus_on; /* chorus on/off */ +}; + +struct _fluid_rvoice_mixer_t +{ + fluid_mixer_fx_t *fx; + + fluid_mixer_buffers_t buffers; /**< Used by mixer only: own buffers */ + fluid_rvoice_eventhandler_t *eventhandler; + + fluid_rvoice_t **rvoices; /**< Read-only: Voices array, sorted so that all nulls are last */ + int polyphony; /**< Read-only: Length of voices array */ + int active_voices; /**< Read-only: Number of non-null voices */ + int current_blockcount; /**< Read-only: how many blocks to process this time */ + int fx_units; + int with_reverb; /**< Should the synth use the built-in reverb unit? */ + int with_chorus; /**< Should the synth use the built-in chorus unit? */ + int mix_fx_to_out; /**< Should the effects be mixed in with the primary output? */ + +#ifdef LADSPA + fluid_ladspa_fx_t *ladspa_fx; /**< Used by mixer only: Effects unit for LADSPA support. Never created or freed */ +#endif + +#if ENABLE_MIXER_THREADS +// int sleeping_threads; /**< Atomic: number of threads currently asleep */ +// int active_threads; /**< Atomic: number of threads in the thread loop */ + fluid_atomic_int_t threads_should_terminate; /**< Atomic: Set to TRUE when threads should terminate */ + fluid_atomic_int_t current_rvoice; /**< Atomic: for the threads to know next voice to */ + fluid_cond_t *wakeup_threads; /**< Signalled when the threads should wake up */ + fluid_cond_mutex_t *wakeup_threads_m; /**< wakeup_threads mutex companion */ + fluid_cond_t *thread_ready; /**< Signalled from thread, when the thread has a buffer ready for mixing */ + fluid_cond_mutex_t *thread_ready_m; /**< thread_ready mutex companion */ + + int thread_count; /**< Number of extra mixer threads for multi-core rendering */ + fluid_mixer_buffers_t *threads; /**< Array of mixer threads (thread_count in length) */ +#endif +}; + +#if ENABLE_MIXER_THREADS +static void delete_rvoice_mixer_threads(fluid_rvoice_mixer_t *mixer); +static int fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t *mixer, int thread_count, int prio_level); +#endif + +static FLUID_INLINE void +fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t *mixer, int current_blockcount) +{ + // Making those variables const causes gcc to fail with "variable is predetermined ‘shared’ for ‘shared’". + // Not explicitly marking them shared makes it fail for clang and MSVC... + /*const*/ int fx_channels_per_unit = mixer->buffers.fx_buf_count / mixer->fx_units; + /*const*/ int dry_count = mixer->buffers.buf_count; /* dry buffers count */ + /*const*/ int mix_fx_to_out = mixer->mix_fx_to_out; /* get mix_fx_to_out mode */ + + void (*reverb_process_func)(fluid_revmodel_t *rev, const fluid_real_t *in, fluid_real_t *left_out, fluid_real_t *right_out); + void (*chorus_process_func)(fluid_chorus_t *chorus, const fluid_real_t *in, fluid_real_t *left_out, fluid_real_t *right_out); + + fluid_real_t *out_rev_l, *out_rev_r, *out_ch_l, *out_ch_r; + + // all dry unprocessed mono input is stored in the left channel + fluid_real_t *in_rev = fluid_align_ptr(mixer->buffers.fx_left_buf, FLUID_DEFAULT_ALIGNMENT); + fluid_real_t *in_ch = in_rev; + + fluid_profile_ref_var(prof_ref); + +#ifdef LADSPA + + /* Run the signal through the LADSPA Fx unit. The buffers have already been + * set up in fluid_rvoice_mixer_set_ladspa. */ + if(mixer->ladspa_fx) + { + fluid_ladspa_run(mixer->ladspa_fx, current_blockcount, FLUID_BUFSIZE); + fluid_check_fpe("LADSPA"); + } + +#endif + + if(mix_fx_to_out) + { + // mix effects to first stereo channel + out_ch_l = out_rev_l = fluid_align_ptr(mixer->buffers.left_buf, FLUID_DEFAULT_ALIGNMENT); + out_ch_r = out_rev_r = fluid_align_ptr(mixer->buffers.right_buf, FLUID_DEFAULT_ALIGNMENT); + + reverb_process_func = fluid_revmodel_processmix; + chorus_process_func = fluid_chorus_processmix; + } + else + { + // replace effects into respective stereo effects channel + out_ch_l = out_rev_l = fluid_align_ptr(mixer->buffers.fx_left_buf, FLUID_DEFAULT_ALIGNMENT); + out_ch_r = out_rev_r = fluid_align_ptr(mixer->buffers.fx_right_buf, FLUID_DEFAULT_ALIGNMENT); + + reverb_process_func = fluid_revmodel_processreplace; + chorus_process_func = fluid_chorus_processreplace; + } + + if(mixer->with_reverb || mixer->with_chorus) + { +#if ENABLE_MIXER_THREADS && !defined(WITH_PROFILING) + int fx_mixer_threads = mixer->fx_units; + fluid_clip(fx_mixer_threads, 1, mixer->thread_count + 1); + #pragma omp parallel default(none) shared(mixer, reverb_process_func, chorus_process_func, dry_count, current_blockcount, mix_fx_to_out, fx_channels_per_unit) firstprivate(in_rev, in_ch, out_rev_l, out_rev_r, out_ch_l, out_ch_r) num_threads(fx_mixer_threads) +#endif + { + int i, f; + int buf_idx; /* buffer index */ + int samp_idx; /* sample index in buffer */ + int dry_idx = 0; /* dry buffer index */ + int sample_count; /* sample count to process */ + if(mixer->with_reverb) + { +#if ENABLE_MIXER_THREADS && !defined(WITH_PROFILING) + #pragma omp for schedule(static) +#endif + for(f = 0; f < mixer->fx_units; f++) + { + if(!mixer->fx[f].reverb_on) + { + continue; /* this reverb unit is disabled */ + } + + buf_idx = f * fx_channels_per_unit + SYNTH_REVERB_CHANNEL; + samp_idx = buf_idx * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE; + sample_count = current_blockcount * FLUID_BUFSIZE; + + /* in mix mode, map fx out_rev at index f to a dry buffer at index dry_idx */ + if(mix_fx_to_out) + { + /* dry buffer mapping, should be done more flexible in the future */ + dry_idx = (f % dry_count) * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE; + } + + for(i = 0; i < sample_count; i += FLUID_BUFSIZE, samp_idx += FLUID_BUFSIZE) + { + reverb_process_func(mixer->fx[f].reverb, + &in_rev[samp_idx], + mix_fx_to_out ? &out_rev_l[dry_idx + i] : &out_rev_l[samp_idx], + mix_fx_to_out ? &out_rev_r[dry_idx + i] : &out_rev_r[samp_idx]); + } + } // implicit omp barrier - required, because out_rev_l aliases with out_ch_l + + fluid_profile(FLUID_PROF_ONE_BLOCK_REVERB, prof_ref, 0, + current_blockcount * FLUID_BUFSIZE); + } + + if(mixer->with_chorus) + { +#if ENABLE_MIXER_THREADS && !defined(WITH_PROFILING) + #pragma omp for schedule(static) +#endif + for(f = 0; f < mixer->fx_units; f++) + { + if(!mixer->fx[f].chorus_on) + { + continue; /* this chorus unit is disabled */ + } + + buf_idx = f * fx_channels_per_unit + SYNTH_CHORUS_CHANNEL; + samp_idx = buf_idx * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE; + sample_count = current_blockcount * FLUID_BUFSIZE; + + /* in mix mode, map fx out_ch at index f to a dry buffer at index dry_idx */ + if(mix_fx_to_out) + { + /* dry buffer mapping, should be done more flexible in the future */ + dry_idx = (f % dry_count) * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE; + } + + for(i = 0; i < sample_count; i += FLUID_BUFSIZE, samp_idx += FLUID_BUFSIZE) + { + chorus_process_func(mixer->fx[f].chorus, + &in_ch [samp_idx], + mix_fx_to_out ? &out_ch_l[dry_idx + i] : &out_ch_l[samp_idx], + mix_fx_to_out ? &out_ch_r[dry_idx + i] : &out_ch_r[samp_idx]); + } + } + + fluid_profile(FLUID_PROF_ONE_BLOCK_CHORUS, prof_ref, 0, + current_blockcount * FLUID_BUFSIZE); + } + } + } +} + +/** + * Glue to get fluid_rvoice_buffers_mix what it wants + * Note: Make sure outbufs has 2 * (buf_count + fx_buf_count) elements before calling + */ +static FLUID_INLINE int +fluid_mixer_buffers_prepare(fluid_mixer_buffers_t *buffers, fluid_real_t **outbufs) +{ + fluid_real_t *base_ptr; + int i; + const int fx_channels_per_unit = buffers->fx_buf_count / buffers->mixer->fx_units; + const int offset = buffers->buf_count * 2; + int with_reverb = buffers->mixer->with_reverb; + int with_chorus = buffers->mixer->with_chorus; + + /* Set up the reverb and chorus buffers only when the effect is enabled or + * when LADSPA is active. Nonexisting buffers are detected in the DSP loop. + * Not sending the effect signals saves some time in that case. */ +#ifdef LADSPA + int with_ladspa = (buffers->mixer->ladspa_fx != NULL); + with_reverb = (with_reverb | with_ladspa); + with_chorus = (with_chorus | with_ladspa); +#endif + + // all the dry, non-processed mono audio for effects is to be stored in the left buffers + base_ptr = fluid_align_ptr(buffers->fx_left_buf, FLUID_DEFAULT_ALIGNMENT); + + for(i = 0; i < buffers->mixer->fx_units; i++) + { + int fx_idx = i * fx_channels_per_unit; + + outbufs[offset + fx_idx + SYNTH_REVERB_CHANNEL] = + (with_reverb) + ? &base_ptr[(fx_idx + SYNTH_REVERB_CHANNEL) * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT] + : NULL; + + outbufs[offset + fx_idx + SYNTH_CHORUS_CHANNEL] = + (with_chorus) + ? &base_ptr[(fx_idx + SYNTH_CHORUS_CHANNEL) * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT] + : NULL; + } + + /* The output associated with a MIDI channel is wrapped around + * using the number of audio groups as modulo divider. This is + * typically the number of output channels on the 'sound card', + * as long as the LADSPA Fx unit is not used. In case of LADSPA + * unit, think of it as subgroups on a mixer. + * + * For example: Assume that the number of groups is set to 2. + * Then MIDI channel 1, 3, 5, 7 etc. go to output 1, channels 2, + * 4, 6, 8 etc to output 2. Or assume 3 groups: Then MIDI + * channels 1, 4, 7, 10 etc go to output 1; 2, 5, 8, 11 etc to + * output 2, 3, 6, 9, 12 etc to output 3. + */ + base_ptr = fluid_align_ptr(buffers->left_buf, FLUID_DEFAULT_ALIGNMENT); + + for(i = 0; i < buffers->buf_count; i++) + { + outbufs[i * 2] = &base_ptr[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT]; + } + + base_ptr = fluid_align_ptr(buffers->right_buf, FLUID_DEFAULT_ALIGNMENT); + + for(i = 0; i < buffers->buf_count; i++) + { + outbufs[i * 2 + 1] = &base_ptr[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT]; + } + + return offset + buffers->fx_buf_count; +} + + +static FLUID_INLINE void +fluid_finish_rvoice(fluid_mixer_buffers_t *buffers, fluid_rvoice_t *rvoice) +{ + if(buffers->finished_voice_count < buffers->mixer->polyphony) + { + buffers->finished_voices[buffers->finished_voice_count++] = rvoice; + } + else + { + FLUID_LOG(FLUID_ERR, "Exceeded finished voices array, try increasing polyphony"); + } +} + +static void +fluid_mixer_buffer_process_finished_voices(fluid_mixer_buffers_t *buffers) +{ + int i, j; + + for(i = 0; i < buffers->finished_voice_count; i++) + { + fluid_rvoice_t *v = buffers->finished_voices[i]; + int av = buffers->mixer->active_voices; + + for(j = 0; j < av; j++) + { + if(v == buffers->mixer->rvoices[j]) + { + av--; + + /* Pack the array */ + if(j < av) + { + buffers->mixer->rvoices[j] = buffers->mixer->rvoices[av]; + } + } + } + + buffers->mixer->active_voices = av; + + fluid_rvoice_eventhandler_finished_voice_callback(buffers->mixer->eventhandler, v); + } + + buffers->finished_voice_count = 0; +} + +static FLUID_INLINE void fluid_rvoice_mixer_process_finished_voices(fluid_rvoice_mixer_t *mixer) +{ +#if ENABLE_MIXER_THREADS + int i; + + for(i = 0; i < mixer->thread_count; i++) + { + fluid_mixer_buffer_process_finished_voices(&mixer->threads[i]); + } + +#endif + fluid_mixer_buffer_process_finished_voices(&mixer->buffers); +} + + +static FLUID_INLINE fluid_real_t * +get_dest_buf(fluid_rvoice_buffers_t *buffers, int index, + fluid_real_t **dest_bufs, int dest_bufcount) +{ + int j = buffers->bufs[index].mapping; + + if(j >= dest_bufcount || j < 0) + { + return NULL; + } + + return dest_bufs[j]; +} + +/** + * Mix samples down from internal dsp_buf to output buffers + * + * @param buffers Destination buffer(s) + * @param dsp_buf Mono sample source + * @param start_block starting sample in dsp_buf + * @param sample_count number of samples to mix following \c start_block + * @param dest_bufs Array of buffers to mixdown to + * @param dest_bufcount Length of dest_bufs (i.e count of buffers) + */ +static void +fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t *buffers, + const fluid_real_t *FLUID_RESTRICT dsp_buf, + int start_block, int sample_count, + fluid_real_t **dest_bufs, int dest_bufcount) +{ + /* buffers count to mixdown to */ + int bufcount = buffers->count; + int i, dsp_i; + + /* if there is nothing to mix, return immediately */ + if(sample_count <= 0 || dest_bufcount <= 0) + { + return; + } + + FLUID_ASSERT((uintptr_t)dsp_buf % FLUID_DEFAULT_ALIGNMENT == 0); + FLUID_ASSERT((uintptr_t)(&dsp_buf[start_block * FLUID_BUFSIZE]) % FLUID_DEFAULT_ALIGNMENT == 0); + + /* mixdown for each buffer */ + for(i = 0; i < bufcount; i++) + { + fluid_real_t *FLUID_RESTRICT buf = get_dest_buf(buffers, i, dest_bufs, dest_bufcount); + fluid_real_t target_amp = buffers->bufs[i].target_amp; + fluid_real_t current_amp = buffers->bufs[i].current_amp; + fluid_real_t amp_incr; + + if(buf == NULL || (current_amp == 0.0f && target_amp == 0.0f)) + { + continue; + } + + amp_incr = (target_amp - current_amp) / FLUID_BUFSIZE; + + FLUID_ASSERT((uintptr_t)buf % FLUID_DEFAULT_ALIGNMENT == 0); + + /* Mixdown sample_count samples in the current buffer buf + * + * For the first FLUID_BUFSIZE samples, we linearly interpolate the buffers amplitude to + * avoid clicks/pops when rapidly changing the channels panning (issue 768). + * + * We could have squashed this into one single loop by using an if clause within the loop body. + * But it seems like having two separate loops is easier for compilers to understand, and therefore + * auto-vectorizing the loops. + */ + if(sample_count < FLUID_BUFSIZE) + { + // scalar loop variant, the voice will have finished afterwards + for(dsp_i = 0; dsp_i < sample_count; dsp_i++) + { + buf[start_block * FLUID_BUFSIZE + dsp_i] += current_amp * dsp_buf[start_block * FLUID_BUFSIZE + dsp_i]; + current_amp += amp_incr; + } + } + else + { + // here goes the vectorizable loop + #pragma omp simd aligned(dsp_buf,buf:FLUID_DEFAULT_ALIGNMENT) + for(dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i++) + { + // We cannot simply increment current_amp by amp_incr during every iteration, as this would create a dependency and prevent vectorization. + buf[start_block * FLUID_BUFSIZE + dsp_i] += (current_amp + amp_incr * dsp_i) * dsp_buf[start_block * FLUID_BUFSIZE + dsp_i]; + } + + // we have reached the target_amp + if(target_amp > 0) + { + /* Note, that this loop could be unrolled by FLUID_BUFSIZE elements */ + #pragma omp simd aligned(dsp_buf,buf:FLUID_DEFAULT_ALIGNMENT) + for(dsp_i = FLUID_BUFSIZE; dsp_i < sample_count; dsp_i++) + { + // Index by blocks (not by samples) to let the compiler know that we always start accessing + // buf and dsp_buf at the FLUID_BUFSIZE*sizeof(fluid_real_t) byte boundary and never somewhere + // in between. + // A good compiler should understand: Aha, so I don't need to add a peel loop when vectorizing + // this loop. Great. + buf[start_block * FLUID_BUFSIZE + dsp_i] += target_amp * dsp_buf[start_block * FLUID_BUFSIZE + dsp_i]; + } + } + } + + buffers->bufs[i].current_amp = target_amp; + } +} + +/** + * Synthesize one voice and add to buffer. + * NOTE: If return value is less than blockcount*FLUID_BUFSIZE, that means + * voice has been finished, removed and possibly replaced with another voice. + */ +static FLUID_INLINE void +fluid_mixer_buffers_render_one(fluid_mixer_buffers_t *buffers, + fluid_rvoice_t *rvoice, fluid_real_t **dest_bufs, + unsigned int dest_bufcount, fluid_real_t *src_buf, int blockcount) +{ + int i, total_samples = 0, last_block_mixed = 0; + + for(i = 0; i < blockcount; i++) + { + /* render one block in src_buf */ + int s = fluid_rvoice_write(rvoice, &src_buf[FLUID_BUFSIZE * i]); + + if(s == -1) + { + /* the voice is silent, mix back all the previously rendered sound */ + fluid_rvoice_buffers_mix(&rvoice->buffers, src_buf, last_block_mixed, + total_samples - (last_block_mixed * FLUID_BUFSIZE), + dest_bufs, dest_bufcount); + + last_block_mixed = i + 1; /* future block start index to mix from */ + total_samples += FLUID_BUFSIZE; /* accumulate samples count rendered */ + } + else + { + /* the voice wasn't quiet. Some samples have been rendered [0..FLUID_BUFSIZE] */ + total_samples += s; + + if(s < FLUID_BUFSIZE) + { + /* voice has finished */ + break; + } + } + } + + /* Now mix the remaining blocks from last_block_mixed to total_sample */ + fluid_rvoice_buffers_mix(&rvoice->buffers, src_buf, last_block_mixed, + total_samples - (last_block_mixed * FLUID_BUFSIZE), + dest_bufs, dest_bufcount); + + if(total_samples < blockcount * FLUID_BUFSIZE) + { + /* voice has finished */ + fluid_finish_rvoice(buffers, rvoice); + } +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_add_voice) +{ + int i; + fluid_rvoice_mixer_t *mixer = obj; + fluid_rvoice_t *voice = param[0].ptr; + + if(mixer->active_voices < mixer->polyphony) + { + mixer->rvoices[mixer->active_voices++] = voice; + return; // success + } + + /* See if any voices just finished, if so, take its place. + This can happen in voice overflow conditions. */ + for(i = 0; i < mixer->active_voices; i++) + { + if(mixer->rvoices[i] == voice) + { + FLUID_LOG(FLUID_ERR, "Internal error: Trying to replace an existing rvoice in fluid_rvoice_mixer_add_voice?!"); + return; + } + + if(mixer->rvoices[i]->envlfo.volenv.section == FLUID_VOICE_ENVFINISHED) + { + fluid_finish_rvoice(&mixer->buffers, mixer->rvoices[i]); + mixer->rvoices[i] = voice; + return; // success + } + } + + /* This should never happen */ + FLUID_LOG(FLUID_ERR, "Trying to exceed polyphony in fluid_rvoice_mixer_add_voice"); +} + +static int +fluid_mixer_buffers_update_polyphony(fluid_mixer_buffers_t *buffers, int value) +{ + void *newptr; + + if(buffers->finished_voice_count > value) + { + return FLUID_FAILED; + } + + newptr = FLUID_REALLOC(buffers->finished_voices, value * sizeof(fluid_rvoice_t *)); + + if(newptr == NULL && value > 0) + { + return FLUID_FAILED; + } + + buffers->finished_voices = newptr; + return FLUID_OK; +} + +/** + * Update polyphony - max number of voices (NOTE: not hard real-time capable) + * @return FLUID_OK or FLUID_FAILED + */ +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_polyphony) +{ + void *newptr; + fluid_rvoice_mixer_t *handler = obj; + int value = param[0].i; + + if(handler->active_voices > value) + { + return /*FLUID_FAILED*/; + } + + newptr = FLUID_REALLOC(handler->rvoices, value * sizeof(fluid_rvoice_t *)); + + if(newptr == NULL) + { + return /*FLUID_FAILED*/; + } + + handler->rvoices = newptr; + + if(fluid_mixer_buffers_update_polyphony(&handler->buffers, value) + == FLUID_FAILED) + { + return /*FLUID_FAILED*/; + } + +#if ENABLE_MIXER_THREADS + { + int i; + + for(i = 0; i < handler->thread_count; i++) + { + if(fluid_mixer_buffers_update_polyphony(&handler->threads[i], value) + == FLUID_FAILED) + { + return /*FLUID_FAILED*/; + } + } + } +#endif + + handler->polyphony = value; + /*return FLUID_OK*/; +} + + +static void +fluid_render_loop_singlethread(fluid_rvoice_mixer_t *mixer, int blockcount) +{ + int i; + FLUID_DECLARE_VLA(fluid_real_t *, bufs, + mixer->buffers.buf_count * 2 + mixer->buffers.fx_buf_count * 2); + int bufcount = fluid_mixer_buffers_prepare(&mixer->buffers, bufs); + + fluid_real_t *local_buf = fluid_align_ptr(mixer->buffers.local_buf, FLUID_DEFAULT_ALIGNMENT); + + fluid_profile_ref_var(prof_ref); + + for(i = 0; i < mixer->active_voices; i++) + { + fluid_mixer_buffers_render_one(&mixer->buffers, mixer->rvoices[i], bufs, + bufcount, local_buf, blockcount); + fluid_profile(FLUID_PROF_ONE_BLOCK_VOICE, prof_ref, 1, + blockcount * FLUID_BUFSIZE); + } +} + +static FLUID_INLINE void +fluid_mixer_buffers_zero(fluid_mixer_buffers_t *buffers, int current_blockcount) +{ + int i, size = current_blockcount * FLUID_BUFSIZE * sizeof(fluid_real_t); + + /* TODO: Optimize by only zero out the buffers we actually use later on. */ + int buf_count = buffers->buf_count, fx_buf_count = buffers->fx_buf_count; + + fluid_real_t *FLUID_RESTRICT buf_l = fluid_align_ptr(buffers->left_buf, FLUID_DEFAULT_ALIGNMENT); + fluid_real_t *FLUID_RESTRICT buf_r = fluid_align_ptr(buffers->right_buf, FLUID_DEFAULT_ALIGNMENT); + + for(i = 0; i < buf_count; i++) + { + FLUID_MEMSET(&buf_l[i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE], 0, size); + FLUID_MEMSET(&buf_r[i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE], 0, size); + } + + buf_l = fluid_align_ptr(buffers->fx_left_buf, FLUID_DEFAULT_ALIGNMENT); + buf_r = fluid_align_ptr(buffers->fx_right_buf, FLUID_DEFAULT_ALIGNMENT); + + for(i = 0; i < fx_buf_count; i++) + { + FLUID_MEMSET(&buf_l[i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE], 0, size); + FLUID_MEMSET(&buf_r[i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE], 0, size); + } +} + +static int +fluid_mixer_buffers_init(fluid_mixer_buffers_t *buffers, fluid_rvoice_mixer_t *mixer) +{ + static const int samplecount = FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT; + + buffers->mixer = mixer; + buffers->buf_count = mixer->buffers.buf_count; + buffers->fx_buf_count = mixer->buffers.fx_buf_count; + + /* Local mono voice buf */ + buffers->local_buf = FLUID_ARRAY_ALIGNED(fluid_real_t, samplecount, FLUID_DEFAULT_ALIGNMENT); + + /* Left and right audio buffers */ + + buffers->left_buf = FLUID_ARRAY_ALIGNED(fluid_real_t, buffers->buf_count * samplecount, FLUID_DEFAULT_ALIGNMENT); + buffers->right_buf = FLUID_ARRAY_ALIGNED(fluid_real_t, buffers->buf_count * samplecount, FLUID_DEFAULT_ALIGNMENT); + + if((buffers->local_buf == NULL) || (buffers->left_buf == NULL) || (buffers->right_buf == NULL)) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return 0; + } + + /* Effects audio buffers */ + + buffers->fx_left_buf = FLUID_ARRAY_ALIGNED(fluid_real_t, buffers->fx_buf_count * samplecount, FLUID_DEFAULT_ALIGNMENT); + buffers->fx_right_buf = FLUID_ARRAY_ALIGNED(fluid_real_t, buffers->fx_buf_count * samplecount, FLUID_DEFAULT_ALIGNMENT); + + if((buffers->fx_left_buf == NULL) || (buffers->fx_right_buf == NULL)) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return 0; + } + + buffers->finished_voices = NULL; + + if(fluid_mixer_buffers_update_polyphony(buffers, mixer->polyphony) + == FLUID_FAILED) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return 0; + } + + return 1; +} + +/** + * Note: Not hard real-time capable (calls malloc) + */ +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_samplerate) +{ + fluid_rvoice_mixer_t *mixer = obj; + fluid_real_t samplerate = param[1].real; // because fluid_synth_update_mixer() puts real into arg2 + + int i; + + for(i = 0; i < mixer->fx_units; i++) + { + if(mixer->fx[i].chorus) + { + fluid_chorus_samplerate_change(mixer->fx[i].chorus, samplerate); + } + + if(mixer->fx[i].reverb) + { + fluid_revmodel_samplerate_change(mixer->fx[i].reverb, samplerate); + + /* + fluid_revmodel_samplerate_change() shouldn't fail if the reverb was created + with sample_rate_max set to the maximum sample rate indicated in the settings. + If this condition isn't respected, the reverb will continue to work but with + lost of quality. + */ + } + } + +#if LADSPA + + if(mixer->ladspa_fx != NULL) + { + fluid_ladspa_set_sample_rate(mixer->ladspa_fx, samplerate); + } + +#endif +} + + +/** + * @param buf_count number of primary stereo buffers + * @param fx_buf_count number of stereo effect buffers + */ +fluid_rvoice_mixer_t * +new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int fx_units, + fluid_real_t sample_rate_max, + fluid_real_t sample_rate, + fluid_rvoice_eventhandler_t *evthandler, + int extra_threads, int prio) +{ + int i; + fluid_rvoice_mixer_t *mixer = FLUID_NEW(fluid_rvoice_mixer_t); + + if(mixer == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + FLUID_MEMSET(mixer, 0, sizeof(fluid_rvoice_mixer_t)); + mixer->eventhandler = evthandler; + mixer->fx_units = fx_units; + mixer->buffers.buf_count = buf_count; + mixer->buffers.fx_buf_count = fx_buf_count * fx_units; + + /* allocate the reverb module */ + mixer->fx = FLUID_ARRAY(fluid_mixer_fx_t, fx_units); + + if(mixer->fx == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + goto error_recovery; + } + + FLUID_MEMSET(mixer->fx, 0, fx_units * sizeof(*mixer->fx)); + + for(i = 0; i < fx_units; i++) + { + /* create reverb and chorus units */ + mixer->fx[i].reverb = new_fluid_revmodel(sample_rate_max, sample_rate); + mixer->fx[i].chorus = new_fluid_chorus(sample_rate); + + if(mixer->fx[i].reverb == NULL || mixer->fx[i].chorus == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + goto error_recovery; + } + } + + if(!fluid_mixer_buffers_init(&mixer->buffers, mixer)) + { + goto error_recovery; + } + +#if ENABLE_MIXER_THREADS + mixer->thread_ready = new_fluid_cond(); + mixer->wakeup_threads = new_fluid_cond(); + mixer->thread_ready_m = new_fluid_cond_mutex(); + mixer->wakeup_threads_m = new_fluid_cond_mutex(); + + if(!mixer->thread_ready || !mixer->wakeup_threads || + !mixer->thread_ready_m || !mixer->wakeup_threads_m) + { + goto error_recovery; + } + + if(fluid_rvoice_mixer_set_threads(mixer, extra_threads, prio) != FLUID_OK) + { + goto error_recovery; + } + +#endif + + return mixer; + +error_recovery: + delete_fluid_rvoice_mixer(mixer); + return NULL; +} + +static void +fluid_mixer_buffers_free(fluid_mixer_buffers_t *buffers) +{ + FLUID_FREE(buffers->finished_voices); + + /* free all the sample buffers */ + FLUID_FREE(buffers->local_buf); + FLUID_FREE(buffers->left_buf); + FLUID_FREE(buffers->right_buf); + FLUID_FREE(buffers->fx_left_buf); + FLUID_FREE(buffers->fx_right_buf); +} + +void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *mixer) +{ + int i; + + fluid_return_if_fail(mixer != NULL); + +#if ENABLE_MIXER_THREADS + delete_rvoice_mixer_threads(mixer); + + if(mixer->thread_ready) + { + delete_fluid_cond(mixer->thread_ready); + } + + if(mixer->wakeup_threads) + { + delete_fluid_cond(mixer->wakeup_threads); + } + + if(mixer->thread_ready_m) + { + delete_fluid_cond_mutex(mixer->thread_ready_m); + } + + if(mixer->wakeup_threads_m) + { + delete_fluid_cond_mutex(mixer->wakeup_threads_m); + } + +#endif + fluid_mixer_buffers_free(&mixer->buffers); + + + for(i = 0; i < mixer->fx_units; i++) + { + if(mixer->fx[i].reverb) + { + delete_fluid_revmodel(mixer->fx[i].reverb); + } + + if(mixer->fx[i].chorus) + { + delete_fluid_chorus(mixer->fx[i].chorus); + } + } + + FLUID_FREE(mixer->fx); + FLUID_FREE(mixer->rvoices); + FLUID_FREE(mixer); +} + +#ifdef LADSPA +/** + * Set a LADSPS fx instance to be used by the mixer and assign the mixer buffers + * as LADSPA host buffers with sensible names */ +void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t *mixer, + fluid_ladspa_fx_t *ladspa_fx, int audio_groups) +{ + mixer->ladspa_fx = ladspa_fx; + + if(ladspa_fx == NULL) + { + return; + } + else + { + fluid_real_t *main_l = fluid_align_ptr(mixer->buffers.left_buf, FLUID_DEFAULT_ALIGNMENT); + fluid_real_t *main_r = fluid_align_ptr(mixer->buffers.right_buf, FLUID_DEFAULT_ALIGNMENT); + + fluid_real_t *rev = fluid_align_ptr(mixer->buffers.fx_left_buf, FLUID_DEFAULT_ALIGNMENT); + fluid_real_t *chor = rev; + + rev = &rev[SYNTH_REVERB_CHANNEL * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT]; + chor = &chor[SYNTH_CHORUS_CHANNEL * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT]; + + fluid_ladspa_add_host_ports(ladspa_fx, "Main:L", audio_groups, + main_l, + FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT); + + fluid_ladspa_add_host_ports(ladspa_fx, "Main:R", audio_groups, + main_r, + FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT); + + fluid_ladspa_add_host_ports(ladspa_fx, "Reverb:Send", 1, + rev, + FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT); + + fluid_ladspa_add_host_ports(ladspa_fx, "Chorus:Send", 1, + chor, + FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT); + } +} +#endif + +/** + * set one or more reverb shadow parameters for one fx group. + * These parameters will be returned if queried. + * (see fluid_rvoice_mixer_reverb_get_param()) + * + * @param mixer that contains all fx units. + * @param fx_group index of the fx group to which parameters must be set. + * must be in the range [-1..mixer->fx_units[. If -1 the changes are applied to + * all fx units. + * @param set Flags indicating which parameters should be set (#fluid_revmodel_set_t) + * @param values table of parameters values. + */ +void +fluid_rvoice_mixer_set_reverb_full(const fluid_rvoice_mixer_t *mixer, + int fx_group, int set, const double values[]) +{ + fluid_mixer_fx_t *fx = mixer->fx; + int nr_units = mixer->fx_units; + + if(fx_group >= 0) /* apply parameters to this fx group only */ + { + nr_units = fx_group + 1; + } + else /* apply parameters to all fx groups */ + { + fx_group = 0; + } + + for(; fx_group < nr_units; fx_group++) + { + int param; + + for(param = 0; param < FLUID_REVERB_PARAM_LAST; param++) + { + if(set & FLUID_REVPARAM_TO_SETFLAG(param)) + { + fx[fx_group].reverb_param[param] = values[param]; + } + } + } +} + +/** + * get one reverb shadow parameter for one fx group. + * (see fluid_rvoice_mixer_set_reverb_full()) + * + * @param mixer that contains all fx group units. + * @param fx_group index of the fx group to get parameter from. + * must be in the range [0..mixer->fx_units[. + * @param enum indicating the parameter to get. + * FLUID_REVERB_ROOMSIZE, reverb room size value. + * FLUID_REVERB_DAMP, reverb damping value. + * FLUID_REVERB_WIDTH, reverb width value. + * FLUID_REVERB_LEVEL, reverb level value. + * @return value. + */ +double +fluid_rvoice_mixer_reverb_get_param(const fluid_rvoice_mixer_t *mixer, + int fx_group, int param) +{ + return mixer->fx[fx_group].reverb_param[param]; +} + +/** + * set one or more chorus shadow parameters for one fx group. + * These parameters will be returned if queried. + * (see fluid_rvoice_mixer_chorus_get_param()) + * + * @param mixer that contains all fx units. + * @param fx_group index of the fx group to which parameters must be set. + * must be in the range [-1..mixer->fx_units[. If -1 the changes are applied + * to all fx group. + * Keep in mind, that the needed CPU time is proportional to 'nr'. + * @param set Flags indicating which parameters to set (#fluid_chorus_set_t) + * @param values table of pararameters. + */ +void +fluid_rvoice_mixer_set_chorus_full(const fluid_rvoice_mixer_t *mixer, + int fx_group, int set, const double values[]) +{ + fluid_mixer_fx_t *fx = mixer->fx; + int nr_units = mixer->fx_units; + + if(fx_group >= 0) /* apply parameters to this group fx only */ + { + nr_units = fx_group + 1; + } + else /* apply parameters to all fx units*/ + { + fx_group = 0; + } + + for(; fx_group < nr_units; fx_group++) + { + int param; + + for(param = 0; param < FLUID_CHORUS_PARAM_LAST; param++) + { + if(set & FLUID_CHORPARAM_TO_SETFLAG(param)) + { + fx[fx_group].chorus_param[param] = values[param]; + } + } + } +} + +/** + * get one chorus shadow parameter for one fx group. + * (see fluid_rvoice_mixer_set_chorus_full()) + * + * @param mixer that contains all fx groups units. + * @param fx_group index of the fx group to get parameter from. + * must be in the range [0..mixer->fx_units[. + * @param get Flags indicating which parameter to get (#fluid_chorus_set_t) + * @return the parameter value (0.0 is returned if error) + */ +double +fluid_rvoice_mixer_chorus_get_param(const fluid_rvoice_mixer_t *mixer, + int fx_group, int param) +{ + return mixer->fx[fx_group].chorus_param[param]; +} + +/* @deprecated: use fluid_rvoice_mixer_reverb_enable instead */ +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_enabled) +{ + fluid_rvoice_mixer_t *mixer = obj; + int on = param[0].i; + + mixer->with_reverb = on; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reverb_enable) +{ + fluid_rvoice_mixer_t *mixer = obj; + int fx_group = param[0].i; /* reverb fx group index */ + int on = param[1].i; /* on/off */ + + int nr_units = mixer->fx_units; + + /* does on/off must be applied only to fx group at index fx_group ? */ + if(fx_group >= 0) + { + mixer->fx[fx_group].reverb_on = on; + } + /* on/off must be applied to all fx groups */ + else + { + for(fx_group = 0; fx_group < nr_units; fx_group++) + { + mixer->fx[fx_group].reverb_on = on; + } + } + + /* set with_reverb if at least one reverb unit is on */ + for(fx_group = 0; fx_group < nr_units; fx_group++) + { + on = mixer->fx[fx_group].reverb_on; + + if(on) + { + break; + } + } + + mixer->with_reverb = on; +} + +/* @deprecated: use fluid_rvoice_mixer_chorus_enable instead */ +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_enabled) +{ + fluid_rvoice_mixer_t *mixer = obj; + int on = param[0].i; + mixer->with_chorus = on; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_chorus_enable) +{ + fluid_rvoice_mixer_t *mixer = obj; + int fx_group = param[0].i; /* chorus fx group index */ + int on = param[1].i; /* on/off */ + + int nr_units = mixer->fx_units; + + /* does on/off must be applied only to fx group at index fx_group ? */ + if(fx_group >= 0) + { + mixer->fx[fx_group].chorus_on = on; + } + /* on/off must be applied to all fx groups */ + else + { + for(fx_group = 0; fx_group < nr_units; fx_group++) + { + mixer->fx[fx_group].chorus_on = on; + } + } + + /* set with_chorus if at least one chorus unit is on */ + for(fx_group = 0; fx_group < nr_units; fx_group++) + { + on = mixer->fx[fx_group].chorus_on; + + if(on) + { + break; + } + } + + mixer->with_chorus = on; +} + +void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t *mixer, int on) +{ + mixer->mix_fx_to_out = on; +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_params) +{ + fluid_rvoice_mixer_t *mixer = obj; + int i = param[0].i; + int set = param[1].i; + int nr = param[2].i; + fluid_real_t level = param[3].real; + fluid_real_t speed = param[4].real; + fluid_real_t depth_ms = param[5].real; + int type = param[6].i; + + int nr_units = mixer->fx_units; + + /* does parameters must be applied only to fx group i ? */ + if(i >= 0) + { + nr_units = i + 1; + } + else + { + i = 0; /* parameters must be applied to all fx groups */ + } + + while(i < nr_units) + { + fluid_chorus_set(mixer->fx[i++].chorus, set, nr, level, speed, depth_ms, type); + } +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_params) +{ + fluid_rvoice_mixer_t *mixer = obj; + int i = param[0].i; /* fx group index */ + int set = param[1].i; + fluid_real_t roomsize = param[2].real; + fluid_real_t damping = param[3].real; + fluid_real_t width = param[4].real; + fluid_real_t level = param[5].real; + + int nr_units = mixer->fx_units; + + /* does parameters change should be applied only to fx group i ? */ + if(i >= 0) + { + nr_units = i + 1; /* parameters change must be applied to fx groups i */ + } + else + { + i = 0; /* parameters change must be applied to all fx groups */ + } + + while(i < nr_units) + { + fluid_revmodel_set(mixer->fx[i++].reverb, set, roomsize, damping, width, level); + } +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_reverb) +{ + fluid_rvoice_mixer_t *mixer = obj; + int i; + + for(i = 0; i < mixer->fx_units; i++) + { + fluid_revmodel_reset(mixer->fx[i].reverb); + } +} + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_chorus) +{ + fluid_rvoice_mixer_t *mixer = obj; + int i; + + for(i = 0; i < mixer->fx_units; i++) + { + fluid_chorus_reset(mixer->fx[i].chorus); + } +} + +int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t *mixer, + fluid_real_t **left, fluid_real_t **right) +{ + *left = fluid_align_ptr(mixer->buffers.left_buf, FLUID_DEFAULT_ALIGNMENT); + *right = fluid_align_ptr(mixer->buffers.right_buf, FLUID_DEFAULT_ALIGNMENT); + return mixer->buffers.buf_count; +} + +int fluid_rvoice_mixer_get_fx_bufs(fluid_rvoice_mixer_t *mixer, + fluid_real_t **fx_left, fluid_real_t **fx_right) +{ + *fx_left = fluid_align_ptr(mixer->buffers.fx_left_buf, FLUID_DEFAULT_ALIGNMENT); + *fx_right = fluid_align_ptr(mixer->buffers.fx_right_buf, FLUID_DEFAULT_ALIGNMENT); + return mixer->buffers.fx_buf_count; +} + +int fluid_rvoice_mixer_get_bufcount(fluid_rvoice_mixer_t *mixer) +{ + return FLUID_MIXER_MAX_BUFFERS_DEFAULT; +} + +#if WITH_PROFILING +int fluid_rvoice_mixer_get_active_voices(fluid_rvoice_mixer_t *mixer) +{ + return mixer->active_voices; +} +#endif + +#if ENABLE_MIXER_THREADS + +static FLUID_INLINE fluid_rvoice_t * +fluid_mixer_get_mt_rvoice(fluid_rvoice_mixer_t *mixer) +{ + int i = fluid_atomic_int_exchange_and_add(&mixer->current_rvoice, 1); + + if(i >= mixer->active_voices) + { + return NULL; + } + + return mixer->rvoices[i]; +} + +#define THREAD_BUF_PROCESSING 0 +#define THREAD_BUF_VALID 1 +#define THREAD_BUF_NODATA 2 +#define THREAD_BUF_TERMINATE 3 + +/* Core thread function (processes voices in parallel to primary synthesis thread) */ +static fluid_thread_return_t +fluid_mixer_thread_func(void *data) +{ + fluid_mixer_buffers_t *buffers = data; + fluid_rvoice_mixer_t *mixer = buffers->mixer; + int hasValidData = 0; + FLUID_DECLARE_VLA(fluid_real_t *, bufs, buffers->buf_count * 2 + buffers->fx_buf_count * 2); + int bufcount = 0; + int current_blockcount = 0; + fluid_real_t *local_buf = fluid_align_ptr(buffers->local_buf, FLUID_DEFAULT_ALIGNMENT); + + while(!fluid_atomic_int_get(&mixer->threads_should_terminate)) + { + fluid_rvoice_t *rvoice = fluid_mixer_get_mt_rvoice(mixer); + + if(rvoice == NULL) + { + // if no voices: signal rendered buffers, sleep + fluid_atomic_int_set(&buffers->ready, hasValidData ? THREAD_BUF_VALID : THREAD_BUF_NODATA); + fluid_cond_mutex_lock(mixer->thread_ready_m); + fluid_cond_signal(mixer->thread_ready); + fluid_cond_mutex_unlock(mixer->thread_ready_m); + + fluid_cond_mutex_lock(mixer->wakeup_threads_m); + + while(1) + { + int j = fluid_atomic_int_get(&buffers->ready); + + if(j == THREAD_BUF_PROCESSING || j == THREAD_BUF_TERMINATE) + { + break; + } + + fluid_cond_wait(mixer->wakeup_threads, mixer->wakeup_threads_m); + } + + fluid_cond_mutex_unlock(mixer->wakeup_threads_m); + + hasValidData = 0; + } + else + { + // else: if buffer is not zeroed, zero buffers + if(!hasValidData) + { + // blockcount may have changed, since thread was put to sleep + current_blockcount = mixer->current_blockcount; + fluid_mixer_buffers_zero(buffers, current_blockcount); + bufcount = fluid_mixer_buffers_prepare(buffers, bufs); + hasValidData = 1; + } + + // then render voice to buffers + fluid_mixer_buffers_render_one(buffers, rvoice, bufs, bufcount, local_buf, current_blockcount); + } + } + + return FLUID_THREAD_RETURN_VALUE; +} + +static void +fluid_mixer_buffers_mix(fluid_mixer_buffers_t *dst, fluid_mixer_buffers_t *src, int current_blockcount) +{ + int i, j; + int scount = current_blockcount * FLUID_BUFSIZE; + int minbuf; + fluid_real_t *FLUID_RESTRICT base_src; + fluid_real_t *FLUID_RESTRICT base_dst; + + minbuf = dst->buf_count; + + if(minbuf > src->buf_count) + { + minbuf = src->buf_count; + } + + base_src = fluid_align_ptr(src->left_buf, FLUID_DEFAULT_ALIGNMENT); + base_dst = fluid_align_ptr(dst->left_buf, FLUID_DEFAULT_ALIGNMENT); + + for(i = 0; i < minbuf; i++) + { + #pragma omp simd aligned(base_dst,base_src:FLUID_DEFAULT_ALIGNMENT) + + for(j = 0; j < scount; j++) + { + int dsp_i = i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + j; + base_dst[dsp_i] += base_src[dsp_i]; + } + } + + base_src = fluid_align_ptr(src->right_buf, FLUID_DEFAULT_ALIGNMENT); + base_dst = fluid_align_ptr(dst->right_buf, FLUID_DEFAULT_ALIGNMENT); + + for(i = 0; i < minbuf; i++) + { + #pragma omp simd aligned(base_dst,base_src:FLUID_DEFAULT_ALIGNMENT) + + for(j = 0; j < scount; j++) + { + int dsp_i = i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + j; + base_dst[dsp_i] += base_src[dsp_i]; + } + } + + minbuf = dst->fx_buf_count; + + if(minbuf > src->fx_buf_count) + { + minbuf = src->fx_buf_count; + } + + base_src = fluid_align_ptr(src->fx_left_buf, FLUID_DEFAULT_ALIGNMENT); + base_dst = fluid_align_ptr(dst->fx_left_buf, FLUID_DEFAULT_ALIGNMENT); + + for(i = 0; i < minbuf; i++) + { + #pragma omp simd aligned(base_dst,base_src:FLUID_DEFAULT_ALIGNMENT) + + for(j = 0; j < scount; j++) + { + int dsp_i = i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + j; + base_dst[dsp_i] += base_src[dsp_i]; + } + } + + base_src = fluid_align_ptr(src->fx_right_buf, FLUID_DEFAULT_ALIGNMENT); + base_dst = fluid_align_ptr(dst->fx_right_buf, FLUID_DEFAULT_ALIGNMENT); + + for(i = 0; i < minbuf; i++) + { + #pragma omp simd aligned(base_dst,base_src:FLUID_DEFAULT_ALIGNMENT) + + for(j = 0; j < scount; j++) + { + int dsp_i = i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + j; + base_dst[dsp_i] += base_src[dsp_i]; + } + } +} + + +/** + * Go through all threads and see if someone is finished for mixing + */ +static int +fluid_mixer_mix_in(fluid_rvoice_mixer_t *mixer, int extra_threads, int current_blockcount) +{ + int i, result, hasmixed; + + do + { + hasmixed = 0; + result = 0; + + for(i = 0; i < extra_threads; i++) + { + int j = fluid_atomic_int_get(&mixer->threads[i].ready); + + switch(j) + { + case THREAD_BUF_PROCESSING: + result = 1; + break; + + case THREAD_BUF_VALID: + fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_NODATA); + fluid_mixer_buffers_mix(&mixer->buffers, &mixer->threads[i], current_blockcount); + hasmixed = 1; + break; + } + } + } + while(hasmixed); + + return result; +} + +static void +fluid_render_loop_multithread(fluid_rvoice_mixer_t *mixer, int current_blockcount) +{ + int i, bufcount; + fluid_real_t *local_buf = fluid_align_ptr(mixer->buffers.local_buf, FLUID_DEFAULT_ALIGNMENT); + + FLUID_DECLARE_VLA(fluid_real_t *, bufs, + mixer->buffers.buf_count * 2 + mixer->buffers.fx_buf_count * 2); + // How many threads should we start this time? + int extra_threads = mixer->active_voices / VOICES_PER_THREAD; + + if(extra_threads > mixer->thread_count) + { + extra_threads = mixer->thread_count; + } + + if(extra_threads == 0) + { + // No extra threads? No thread overhead! + fluid_render_loop_singlethread(mixer, current_blockcount); + return; + } + + bufcount = fluid_mixer_buffers_prepare(&mixer->buffers, bufs); + + // Prepare voice list + fluid_cond_mutex_lock(mixer->wakeup_threads_m); + fluid_atomic_int_set(&mixer->current_rvoice, 0); + + for(i = 0; i < extra_threads; i++) + { + fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_PROCESSING); + } + + // Signal threads to wake up + fluid_cond_broadcast(mixer->wakeup_threads); + fluid_cond_mutex_unlock(mixer->wakeup_threads_m); + + // If thread is finished, mix it in + while(fluid_mixer_mix_in(mixer, extra_threads, current_blockcount)) + { + // Otherwise get a voice and render it + fluid_rvoice_t *rvoice = fluid_mixer_get_mt_rvoice(mixer); + + if(rvoice != NULL) + { + fluid_profile_ref_var(prof_ref); + fluid_mixer_buffers_render_one(&mixer->buffers, rvoice, bufs, bufcount, local_buf, current_blockcount); + fluid_profile(FLUID_PROF_ONE_BLOCK_VOICE, prof_ref, 1, + current_blockcount * FLUID_BUFSIZE); + //test++; + } + else + { + // If no voices, wait for mixes. Make sure one is still processing to avoid deadlock + int is_processing = 0; + //waits++; + fluid_cond_mutex_lock(mixer->thread_ready_m); + + for(i = 0; i < extra_threads; i++) + { + if(fluid_atomic_int_get(&mixer->threads[i].ready) == + THREAD_BUF_PROCESSING) + { + is_processing = 1; + } + } + + if(is_processing) + { + fluid_cond_wait(mixer->thread_ready, mixer->thread_ready_m); + } + + fluid_cond_mutex_unlock(mixer->thread_ready_m); + } + } + + //FLUID_LOG(FLUID_DBG, "Blockcount: %d, mixed %d of %d voices myself, waits = %d", + // current_blockcount, test, mixer->active_voices, waits); +} + +static void delete_rvoice_mixer_threads(fluid_rvoice_mixer_t *mixer) +{ + int i; + + // if no threads have been created yet (e.g. because a previous error prevented creation of threads + // mutexes and condition variables), skip terminating threads + if(mixer->thread_count != 0) + { + fluid_atomic_int_set(&mixer->threads_should_terminate, 1); + // Signal threads to wake up + fluid_cond_mutex_lock(mixer->wakeup_threads_m); + + for(i = 0; i < mixer->thread_count; i++) + { + fluid_atomic_int_set(&mixer->threads[i].ready, THREAD_BUF_TERMINATE); + } + + fluid_cond_broadcast(mixer->wakeup_threads); + fluid_cond_mutex_unlock(mixer->wakeup_threads_m); + + for(i = 0; i < mixer->thread_count; i++) + { + if(mixer->threads[i].thread) + { + fluid_thread_join(mixer->threads[i].thread); + delete_fluid_thread(mixer->threads[i].thread); + } + + fluid_mixer_buffers_free(&mixer->threads[i]); + } + } + + FLUID_FREE(mixer->threads); + mixer->thread_count = 0; + mixer->threads = NULL; +} + +/** + * Update amount of extra mixer threads. + * @param thread_count Number of extra mixer threads for multi-core rendering + * @param prio_level real-time prio level for the extra mixer threads + */ +static int fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t *mixer, int thread_count, int prio_level) +{ + char name[16]; + int i; + + // Kill all existing threads first + if(mixer->thread_count) + { + delete_rvoice_mixer_threads(mixer); + } + + if(thread_count == 0) + { + return FLUID_OK; + } + + // Now prepare the new threads + fluid_atomic_int_set(&mixer->threads_should_terminate, 0); + mixer->threads = FLUID_ARRAY(fluid_mixer_buffers_t, thread_count); + + if(mixer->threads == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FLUID_FAILED; + } + + FLUID_MEMSET(mixer->threads, 0, thread_count * sizeof(fluid_mixer_buffers_t)); + mixer->thread_count = thread_count; + + for(i = 0; i < thread_count; i++) + { + fluid_mixer_buffers_t *b = &mixer->threads[i]; + + if(!fluid_mixer_buffers_init(b, mixer)) + { + return FLUID_FAILED; + } + + fluid_atomic_int_set(&b->ready, THREAD_BUF_NODATA); + FLUID_SNPRINTF(name, sizeof(name), "mixer%d", i); + b->thread = new_fluid_thread(name, fluid_mixer_thread_func, b, prio_level, 0); + + if(!b->thread) + { + return FLUID_FAILED; + } + } + + return FLUID_OK; +} +#endif + +/** + * Synthesize audio into buffers + * @param blockcount number of blocks to render, each having FLUID_BUFSIZE samples + * @return number of blocks rendered + */ +int +fluid_rvoice_mixer_render(fluid_rvoice_mixer_t *mixer, int blockcount) +{ + fluid_profile_ref_var(prof_ref); + + mixer->current_blockcount = blockcount; + + // Zero buffers + fluid_mixer_buffers_zero(&mixer->buffers, blockcount); + fluid_profile(FLUID_PROF_ONE_BLOCK_CLEAR, prof_ref, mixer->active_voices, + blockcount * FLUID_BUFSIZE); + +#if ENABLE_MIXER_THREADS + + if(mixer->thread_count > 0) + { + fluid_render_loop_multithread(mixer, blockcount); + } + else +#endif + { + fluid_render_loop_singlethread(mixer, blockcount); + } + + fluid_profile(FLUID_PROF_ONE_BLOCK_VOICES, prof_ref, mixer->active_voices, + blockcount * FLUID_BUFSIZE); + + + // Process reverb & chorus + fluid_rvoice_mixer_process_fx(mixer, blockcount); + + // Call the callback and pack active voice array + fluid_rvoice_mixer_process_finished_voices(mixer); + + return blockcount; +} diff --git a/libs/fluidsynth/src/rvoice/fluid_rvoice_mixer.h b/libs/fluidsynth/src/rvoice/fluid_rvoice_mixer.h new file mode 100644 index 00000000000..afedc16a789 --- /dev/null +++ b/libs/fluidsynth/src/rvoice/fluid_rvoice_mixer.h @@ -0,0 +1,87 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#ifndef _FLUID_RVOICE_MIXER_H +#define _FLUID_RVOICE_MIXER_H + +#include "fluidsynth_priv.h" +#include "fluid_rvoice.h" +#include "fluid_ladspa.h" + +typedef struct _fluid_rvoice_mixer_t fluid_rvoice_mixer_t; + +int fluid_rvoice_mixer_render(fluid_rvoice_mixer_t *mixer, int blockcount); +int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t *mixer, + fluid_real_t **left, fluid_real_t **right); +int fluid_rvoice_mixer_get_fx_bufs(fluid_rvoice_mixer_t *mixer, + fluid_real_t **fx_left, fluid_real_t **fx_right); +int fluid_rvoice_mixer_get_bufcount(fluid_rvoice_mixer_t *mixer); +#if WITH_PROFILING +int fluid_rvoice_mixer_get_active_voices(fluid_rvoice_mixer_t *mixer); +#endif +fluid_rvoice_mixer_t *new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int fx_units, + fluid_real_t sample_rate_max, fluid_real_t sample_rate, + fluid_rvoice_eventhandler_t *, int, int); + +void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *); + +void +fluid_rvoice_mixer_set_reverb_full(const fluid_rvoice_mixer_t *mixer, + int fx_group, int set, const double values[]); + +double +fluid_rvoice_mixer_reverb_get_param(const fluid_rvoice_mixer_t *mixer, + int fx_group, int param); +void +fluid_rvoice_mixer_set_chorus_full(const fluid_rvoice_mixer_t *mixer, + int fx_group, int set, const double values[]); +double +fluid_rvoice_mixer_chorus_get_param(const fluid_rvoice_mixer_t *mixer, + int fx_group, int param); + + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_add_voice); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_samplerate); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_polyphony); + +/* @deprecated */ +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_enabled); +/* @deprecated */ +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_enabled); + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reverb_enable); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_chorus_enable); + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_params); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_params); + +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_reverb); +DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_chorus); + + + +void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t *mixer, int on); +#ifdef LADSPA +void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t *mixer, + fluid_ladspa_fx_t *ladspa_fx, int audio_groups); +#endif + +#endif diff --git a/libs/fluidsynth/src/sfloader/fluid_defsfont.c b/libs/fluidsynth/src/sfloader/fluid_defsfont.c new file mode 100644 index 00000000000..c1a5917940c --- /dev/null +++ b/libs/fluidsynth/src/sfloader/fluid_defsfont.c @@ -0,0 +1,2372 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * SoundFont file loading code borrowed from Smurf SoundFont Editor + * Copyright (C) 1999-2001 Josh Green + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#include "fluid_defsfont.h" +#include "fluid_sfont.h" +#include "fluid_sys.h" +#include "fluid_synth.h" +#include "fluid_samplecache.h" +#include "fluid_chan.h" + +/* EMU8k/10k hardware applies this factor to initial attenuation generator values set at preset and + * instrument level in a soundfont. We apply this factor when loading the generator values to stay + * compatible as most existing soundfonts expect exactly this (strange, non-standard) behaviour. */ +#define EMU_ATTENUATION_FACTOR (0.4f) + +/* Dynamic sample loading functions */ +static int pin_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset); +static int unpin_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset); +static int load_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset); +static int unload_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset); +static void unload_sample(fluid_sample_t *sample); +static int dynamic_samples_preset_notify(fluid_preset_t *preset, int reason, int chan); +static int dynamic_samples_sample_notify(fluid_sample_t *sample, int reason); +static int fluid_preset_zone_create_voice_zones(fluid_preset_zone_t *preset_zone); +static fluid_inst_t *find_inst_by_idx(fluid_defsfont_t *defsfont, int idx); + + +/*************************************************************** + * + * SFONT LOADER + */ + +/** + * Creates a default soundfont2 loader that can be used with fluid_synth_add_sfloader(). + * By default every synth instance has an initial default soundfont loader instance. + * Calling this function is usually only necessary to load a soundfont from memory, by providing custom callback functions via fluid_sfloader_set_callbacks(). + * + * @param settings A settings instance obtained by new_fluid_settings() + * @return A default soundfont2 loader struct + */ +fluid_sfloader_t *new_fluid_defsfloader(fluid_settings_t *settings) +{ + fluid_sfloader_t *loader; + fluid_return_val_if_fail(settings != NULL, NULL); + + loader = new_fluid_sfloader(fluid_defsfloader_load, delete_fluid_sfloader); + + if(loader == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + fluid_sfloader_set_data(loader, settings); + + return loader; +} + +fluid_sfont_t *fluid_defsfloader_load(fluid_sfloader_t *loader, const char *filename) +{ + fluid_defsfont_t *defsfont; + fluid_sfont_t *sfont; + + defsfont = new_fluid_defsfont(fluid_sfloader_get_data(loader)); + + if(defsfont == NULL) + { + return NULL; + } + + sfont = new_fluid_sfont(fluid_defsfont_sfont_get_name, + fluid_defsfont_sfont_get_preset, + fluid_defsfont_sfont_iteration_start, + fluid_defsfont_sfont_iteration_next, + fluid_defsfont_sfont_delete); + + if(sfont == NULL) + { + delete_fluid_defsfont(defsfont); + return NULL; + } + + fluid_sfont_set_data(sfont, defsfont); + + defsfont->sfont = sfont; + + if(fluid_defsfont_load(defsfont, &loader->file_callbacks, filename) == FLUID_FAILED) + { + fluid_defsfont_sfont_delete(sfont); + return NULL; + } + + return sfont; +} + + + +/*************************************************************** + * + * PUBLIC INTERFACE + */ + +int fluid_defsfont_sfont_delete(fluid_sfont_t *sfont) +{ + if(delete_fluid_defsfont(fluid_sfont_get_data(sfont)) != FLUID_OK) + { + return -1; + } + + delete_fluid_sfont(sfont); + return 0; +} + +const char *fluid_defsfont_sfont_get_name(fluid_sfont_t *sfont) +{ + return fluid_defsfont_get_name(fluid_sfont_get_data(sfont)); +} + +fluid_preset_t * +fluid_defsfont_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum) +{ + return fluid_defsfont_get_preset(fluid_sfont_get_data(sfont), bank, prenum); +} + +void fluid_defsfont_sfont_iteration_start(fluid_sfont_t *sfont) +{ + fluid_defsfont_iteration_start(fluid_sfont_get_data(sfont)); +} + +fluid_preset_t *fluid_defsfont_sfont_iteration_next(fluid_sfont_t *sfont) +{ + return fluid_defsfont_iteration_next(fluid_sfont_get_data(sfont)); +} + +void fluid_defpreset_preset_delete(fluid_preset_t *preset) +{ + fluid_defsfont_t *defsfont; + fluid_defpreset_t *defpreset; + + defsfont = fluid_sfont_get_data(preset->sfont); + defpreset = fluid_preset_get_data(preset); + + if(defsfont) + { + defsfont->preset = fluid_list_remove(defsfont->preset, defpreset); + } + + delete_fluid_defpreset(defpreset); + delete_fluid_preset(preset); +} + +const char *fluid_defpreset_preset_get_name(fluid_preset_t *preset) +{ + return fluid_defpreset_get_name(fluid_preset_get_data(preset)); +} + +int fluid_defpreset_preset_get_banknum(fluid_preset_t *preset) +{ + return fluid_defpreset_get_banknum(fluid_preset_get_data(preset)); +} + +int fluid_defpreset_preset_get_num(fluid_preset_t *preset) +{ + return fluid_defpreset_get_num(fluid_preset_get_data(preset)); +} + +int fluid_defpreset_preset_noteon(fluid_preset_t *preset, fluid_synth_t *synth, + int chan, int key, int vel) +{ + return fluid_defpreset_noteon(fluid_preset_get_data(preset), synth, chan, key, vel); +} + + +/*************************************************************** + * + * SFONT + */ + +/* + * new_fluid_defsfont + */ +fluid_defsfont_t *new_fluid_defsfont(fluid_settings_t *settings) +{ + fluid_defsfont_t *defsfont; + + defsfont = FLUID_NEW(fluid_defsfont_t); + + if(defsfont == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + FLUID_MEMSET(defsfont, 0, sizeof(*defsfont)); + + fluid_settings_getint(settings, "synth.lock-memory", &defsfont->mlock); + fluid_settings_getint(settings, "synth.dynamic-sample-loading", &defsfont->dynamic_samples); + + return defsfont; +} + +/* + * delete_fluid_defsfont + */ +int delete_fluid_defsfont(fluid_defsfont_t *defsfont) +{ + fluid_list_t *list; + fluid_preset_t *preset; + fluid_sample_t *sample; + + fluid_return_val_if_fail(defsfont != NULL, FLUID_OK); + + /* If we use dynamic sample loading, make sure we unpin any + * pinned presets before removing this soundfont */ + if(defsfont->dynamic_samples) + { + for(list = defsfont->preset; list; list = fluid_list_next(list)) + { + preset = (fluid_preset_t *)fluid_list_get(list); + unpin_preset_samples(defsfont, preset); + } + } + + /* Check that no samples are currently used */ + for(list = defsfont->sample; list; list = fluid_list_next(list)) + { + sample = (fluid_sample_t *) fluid_list_get(list); + + if(sample->refcount != 0) + { + return FLUID_FAILED; + } + } + + if(defsfont->filename != NULL) + { + FLUID_FREE(defsfont->filename); + } + + for(list = defsfont->sample; list; list = fluid_list_next(list)) + { + sample = (fluid_sample_t *) fluid_list_get(list); + + /* If the sample data pointer is different to the sampledata chunk of + * the soundfont, then the sample has been loaded individually (SF3) + * and needs to be unloaded explicitly. This is safe even if using + * dynamic sample loading, as the sample_unload mechanism sets + * sample->data to NULL after unload. */ + if ((sample->data != NULL) && (sample->data != defsfont->sampledata)) + { + fluid_samplecache_unload(sample->data); + } + delete_fluid_sample(sample); + } + + if(defsfont->sample) + { + delete_fluid_list(defsfont->sample); + } + + if(defsfont->sampledata != NULL) + { + fluid_samplecache_unload(defsfont->sampledata); + } + + for(list = defsfont->preset; list; list = fluid_list_next(list)) + { + preset = (fluid_preset_t *)fluid_list_get(list); + fluid_defpreset_preset_delete(preset); + } + + delete_fluid_list(defsfont->preset); + + for(list = defsfont->inst; list; list = fluid_list_next(list)) + { + delete_fluid_inst(fluid_list_get(list)); + } + + delete_fluid_list(defsfont->inst); + + FLUID_FREE(defsfont); + return FLUID_OK; +} + +/* + * fluid_defsfont_get_name + */ +const char *fluid_defsfont_get_name(fluid_defsfont_t *defsfont) +{ + return defsfont->filename; +} + +/* Load sample data for a single sample from the Soundfont file. + * Returns FLUID_OK on error, otherwise FLUID_FAILED + */ +int fluid_defsfont_load_sampledata(fluid_defsfont_t *defsfont, SFData *sfdata, fluid_sample_t *sample) +{ + int num_samples; + unsigned int source_end = sample->source_end; + + /* For uncompressed samples we want to include the 46 zero sample word area following each sample + * in the Soundfont. Otherwise samples with loopend > end, which we have decided not to correct, would + * be corrected after all in fluid_sample_sanitize_loop */ + if(!(sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS)) + { + source_end += 46; /* Length of zero sample word after each sample, according to SF specs */ + + /* Safeguard against Soundfonts that are not quite valid and don't include 46 sample words after the + * last sample */ + if(source_end >= (defsfont->samplesize / sizeof(short))) + { + source_end = defsfont->samplesize / sizeof(short); + } + } + + num_samples = fluid_samplecache_load( + sfdata, sample->source_start, source_end, sample->sampletype, + defsfont->mlock, &sample->data, &sample->data24); + + if(num_samples < 0) + { + return FLUID_FAILED; + } + + if(num_samples == 0) + { + sample->start = sample->end = 0; + sample->loopstart = sample->loopend = 0; + return FLUID_OK; + } + + /* Ogg Vorbis samples already have loop pointers relative to the individual decompressed sample, + * but SF2 samples are relative to sample chunk start, so they need to be adjusted */ + if(!(sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS)) + { + sample->loopstart = sample->source_loopstart - sample->source_start; + sample->loopend = sample->source_loopend - sample->source_start; + } + + /* As we've just loaded an individual sample into it's own buffer, we need to adjust the start + * and end pointers */ + sample->start = 0; + sample->end = num_samples - 1; + + return FLUID_OK; +} + +/* Loads the sample data for all samples from the Soundfont file. For SF2 files, it loads the data in + * one large block. For SF3 files, each compressed sample gets loaded individually. + * Returns FLUID_OK on success, otherwise FLUID_FAILED + */ +int fluid_defsfont_load_all_sampledata(fluid_defsfont_t *defsfont, SFData *sfdata) +{ + fluid_list_t *list; + fluid_sample_t *sample; + int sf3_file = (sfdata->version.major == 3); + int sample_parsing_result = FLUID_OK; + int invalid_loops_were_sanitized = FALSE; + + /* For SF2 files, we load the sample data in one large block */ + if(!sf3_file) + { + int read_samples; + int num_samples = sfdata->samplesize / sizeof(short); + + read_samples = fluid_samplecache_load(sfdata, 0, num_samples - 1, 0, defsfont->mlock, + &defsfont->sampledata, &defsfont->sample24data); + + if(read_samples != num_samples) + { + FLUID_LOG(FLUID_ERR, "Attempted to read %d words of sample data, but got %d instead", + num_samples, read_samples); + return FLUID_FAILED; + } + } + + #pragma omp parallel + #pragma omp single + for(list = defsfont->sample; list; list = fluid_list_next(list)) + { + sample = fluid_list_get(list); + + if(sf3_file) + { + /* SF3 samples get loaded individually, as most (or all) of them are in Ogg Vorbis format + * anyway */ + #pragma omp task firstprivate(sample,sfdata,defsfont) shared(sample_parsing_result, invalid_loops_were_sanitized) default(none) + { + if(fluid_defsfont_load_sampledata(defsfont, sfdata, sample) == FLUID_FAILED) + { + #pragma omp critical + { + FLUID_LOG(FLUID_ERR, "Failed to load sample '%s'", sample->name); + sample_parsing_result = FLUID_FAILED; + } + } + else + { + int modified = fluid_sample_sanitize_loop(sample, (sample->end + 1) * sizeof(short)); + if(modified) + { + #pragma omp critical + { + invalid_loops_were_sanitized = TRUE; + } + } + fluid_voice_optimize_sample(sample); + } + } + } + else + { + #pragma omp task firstprivate(sample, defsfont) shared(invalid_loops_were_sanitized) default(none) + { + int modified; + /* Data pointers of SF2 samples point to large sample data block loaded above */ + sample->data = defsfont->sampledata; + sample->data24 = defsfont->sample24data; + modified = fluid_sample_sanitize_loop(sample, defsfont->samplesize); + if(modified) + { + #pragma omp critical + { + invalid_loops_were_sanitized = TRUE; + } + } + fluid_voice_optimize_sample(sample); + } + } + } + + if(invalid_loops_were_sanitized) + { + FLUID_LOG(FLUID_WARN, + "Some invalid sample loops were sanitized! If you experience audible glitches, " + "start fluidsynth in verbose mode for detailed information."); + } + + return sample_parsing_result; +} + +/* + * fluid_defsfont_load + */ +int fluid_defsfont_load(fluid_defsfont_t *defsfont, const fluid_file_callbacks_t *fcbs, const char *file) +{ + SFData *sfdata; + fluid_list_t *p; + SFPreset *sfpreset; + SFSample *sfsample; + fluid_sample_t *sample; + fluid_defpreset_t *defpreset = NULL; + + defsfont->filename = FLUID_STRDUP(file); + + if(defsfont->filename == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FLUID_FAILED; + } + + defsfont->fcbs = fcbs; + + /* The actual loading is done in the sfont and sffile files */ + sfdata = fluid_sffile_open(file, fcbs); + + if(sfdata == NULL) + { + /* error message already printed */ + return FLUID_FAILED; + } + + if(fluid_sffile_parse_presets(sfdata) == FLUID_FAILED) + { + FLUID_LOG(FLUID_ERR, "Couldn't parse presets from soundfont file"); + goto err_exit; + } + + /* Keep track of the position and size of the sample data because + it's loaded separately (and might be unoaded/reloaded in future) */ + defsfont->samplepos = sfdata->samplepos; + defsfont->samplesize = sfdata->samplesize; + defsfont->sample24pos = sfdata->sample24pos; + defsfont->sample24size = sfdata->sample24size; + + /* Create all samples from sample headers */ + p = sfdata->sample; + + while(p != NULL) + { + sfsample = (SFSample *)fluid_list_get(p); + + sample = new_fluid_sample(); + + if(sample == NULL) + { + goto err_exit; + } + + if(fluid_sample_import_sfont(sample, sfsample, defsfont) == FLUID_OK) + { + fluid_defsfont_add_sample(defsfont, sample); + } + else + { + delete_fluid_sample(sample); + sample = NULL; + } + + /* Store reference to FluidSynth sample in SFSample for later IZone fixups */ + sfsample->fluid_sample = sample; + + p = fluid_list_next(p); + } + + /* If dynamic sample loading is disabled, load all samples in the Soundfont */ + if(!defsfont->dynamic_samples) + { + if(fluid_defsfont_load_all_sampledata(defsfont, sfdata) == FLUID_FAILED) + { + FLUID_LOG(FLUID_ERR, "Unable to load all sample data"); + goto err_exit; + } + } + + /* Load all the presets */ + p = sfdata->preset; + + while(p != NULL) + { + sfpreset = (SFPreset *)fluid_list_get(p); + defpreset = new_fluid_defpreset(); + + if(defpreset == NULL) + { + goto err_exit; + } + + if(fluid_defpreset_import_sfont(defpreset, sfpreset, defsfont, sfdata) != FLUID_OK) + { + goto err_exit; + } + + if(fluid_defsfont_add_preset(defsfont, defpreset) == FLUID_FAILED) + { + goto err_exit; + } + + p = fluid_list_next(p); + } + + fluid_sffile_close(sfdata); + + return FLUID_OK; + +err_exit: + fluid_sffile_close(sfdata); + delete_fluid_defpreset(defpreset); + return FLUID_FAILED; +} + +/* fluid_defsfont_add_sample + * + * Add a sample to the SoundFont + */ +int fluid_defsfont_add_sample(fluid_defsfont_t *defsfont, fluid_sample_t *sample) +{ + defsfont->sample = fluid_list_prepend(defsfont->sample, sample); + return FLUID_OK; +} + +/* fluid_defsfont_add_preset + * + * Add a preset to the SoundFont + */ +int fluid_defsfont_add_preset(fluid_defsfont_t *defsfont, fluid_defpreset_t *defpreset) +{ + fluid_preset_t *preset; + + preset = new_fluid_preset(defsfont->sfont, + fluid_defpreset_preset_get_name, + fluid_defpreset_preset_get_banknum, + fluid_defpreset_preset_get_num, + fluid_defpreset_preset_noteon, + fluid_defpreset_preset_delete); + + if(preset == NULL) + { + return FLUID_FAILED; + } + + if(defsfont->dynamic_samples) + { + preset->notify = dynamic_samples_preset_notify; + } + + fluid_preset_set_data(preset, defpreset); + + defsfont->preset = fluid_list_append(defsfont->preset, preset); + + return FLUID_OK; +} + +/* + * fluid_defsfont_get_preset + */ +fluid_preset_t *fluid_defsfont_get_preset(fluid_defsfont_t *defsfont, int bank, int num) +{ + fluid_preset_t *preset; + fluid_list_t *list; + + for(list = defsfont->preset; list != NULL; list = fluid_list_next(list)) + { + preset = (fluid_preset_t *)fluid_list_get(list); + + if((fluid_preset_get_banknum(preset) == bank) && (fluid_preset_get_num(preset) == num)) + { + return preset; + } + } + + return NULL; +} + +/* + * fluid_defsfont_iteration_start + */ +void fluid_defsfont_iteration_start(fluid_defsfont_t *defsfont) +{ + defsfont->preset_iter_cur = defsfont->preset; +} + +/* + * fluid_defsfont_iteration_next + */ +fluid_preset_t *fluid_defsfont_iteration_next(fluid_defsfont_t *defsfont) +{ + fluid_preset_t *preset = (fluid_preset_t *)fluid_list_get(defsfont->preset_iter_cur); + + defsfont->preset_iter_cur = fluid_list_next(defsfont->preset_iter_cur); + + return preset; +} + +/*************************************************************** + * + * PRESET + */ + +/* + * new_fluid_defpreset + */ +fluid_defpreset_t * +new_fluid_defpreset(void) +{ + fluid_defpreset_t *defpreset = FLUID_NEW(fluid_defpreset_t); + + if(defpreset == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + defpreset->next = NULL; + defpreset->name[0] = 0; + defpreset->bank = 0; + defpreset->num = 0; + defpreset->global_zone = NULL; + defpreset->zone = NULL; + defpreset->pinned = FALSE; + return defpreset; +} + +/* + * delete_fluid_defpreset + */ +void +delete_fluid_defpreset(fluid_defpreset_t *defpreset) +{ + fluid_preset_zone_t *zone; + + fluid_return_if_fail(defpreset != NULL); + + delete_fluid_preset_zone(defpreset->global_zone); + defpreset->global_zone = NULL; + + zone = defpreset->zone; + + while(zone != NULL) + { + defpreset->zone = zone->next; + delete_fluid_preset_zone(zone); + zone = defpreset->zone; + } + + FLUID_FREE(defpreset); +} + +int +fluid_defpreset_get_banknum(fluid_defpreset_t *defpreset) +{ + return defpreset->bank; +} + +int +fluid_defpreset_get_num(fluid_defpreset_t *defpreset) +{ + return defpreset->num; +} + +const char * +fluid_defpreset_get_name(fluid_defpreset_t *defpreset) +{ + return defpreset->name; +} + +/* + * fluid_defpreset_next + */ +fluid_defpreset_t * +fluid_defpreset_next(fluid_defpreset_t *defpreset) +{ + return defpreset->next; +} + +/* + * Adds global and local modulators list to the voice. This is done in 2 steps: + * - Step 1: Local modulators replace identical global modulators. + * - Step 2: global + local modulators are added to the voice using mode. + * + * Instrument zone list (local/global) must be added using FLUID_VOICE_OVERWRITE. + * Preset zone list (local/global) must be added using FLUID_VOICE_ADD. + * + * @param voice voice instance. + * @param global_mod global list of modulators. + * @param local_mod local list of modulators. + * @param mode Determines how to handle an existing identical modulator. + * #FLUID_VOICE_ADD to add (offset) the modulator amounts, + * #FLUID_VOICE_OVERWRITE to replace the modulator, +*/ +static void +fluid_defpreset_noteon_add_mod_to_voice(fluid_voice_t *voice, + fluid_mod_t *global_mod, fluid_mod_t *local_mod, + int mode) +{ + fluid_mod_t *mod; + /* list for 'sorting' global/local modulators */ + fluid_mod_t *mod_list[FLUID_NUM_MOD]; + int mod_list_count, i; + + /* identity_limit_count is the modulator upper limit number to handle with + * existing identical modulators. + * When identity_limit_count is below the actual number of modulators, this + * will restrict identity check to this upper limit, + * This is useful when we know by advance that there is no duplicate with + * modulators at index above this limit. This avoid wasting cpu cycles at + * noteon. + */ + int identity_limit_count; + + /* Step 1: Local modulators replace identical global modulators. */ + + /* local (instrument zone/preset zone), modulators: Put them all into a list. */ + mod_list_count = 0; + + while(local_mod) + { + /* As modulators number in local_mod list was limited to FLUID_NUM_MOD at + soundfont loading time (fluid_limit_mod_list()), here we don't need + to check if mod_list is full. + */ + mod_list[mod_list_count++] = local_mod; + local_mod = local_mod->next; + } + + /* global (instrument zone/preset zone), modulators. + * Replace modulators with the same definition in the global list: + * (Instrument zone: SF 2.01 page 69, 'bullet' 8) + * (Preset zone: SF 2.01 page 69, second-last bullet). + * + * mod_list contains local modulators. Now we know that there + * is no global modulator identical to another global modulator (this has + * been checked at soundfont loading time). So global modulators + * are only checked against local modulators number. + */ + + /* Restrict identity check to the number of local modulators */ + identity_limit_count = mod_list_count; + + while(global_mod) + { + /* 'Identical' global modulators are ignored. + * SF2.01 section 9.5.1 + * page 69, 'bullet' 3 defines 'identical'. */ + + for(i = 0; i < identity_limit_count; i++) + { + if(fluid_mod_test_identity(global_mod, mod_list[i])) + { + break; + } + } + + /* Finally add the new modulator to the list. */ + if(i >= identity_limit_count) + { + /* Although local_mod and global_mod lists was limited to + FLUID_NUM_MOD at soundfont loading time, it is possible that + local + global modulators exceeds FLUID_NUM_MOD. + So, checks if mod_list_count reaches the limit. + */ + if(mod_list_count >= FLUID_NUM_MOD) + { + /* mod_list is full, we silently forget this modulator and + next global modulators. When mod_list will be added to the + voice, a warning will be displayed if the voice list is full. + (see fluid_voice_add_mod_local()). + */ + break; + } + + mod_list[mod_list_count++] = global_mod; + } + + global_mod = global_mod->next; + } + + /* Step 2: global + local modulators are added to the voice using mode. */ + + /* + * mod_list contains local and global modulators, we know that: + * - there is no global modulator identical to another global modulator, + * - there is no local modulator identical to another local modulator, + * So these local/global modulators are only checked against + * actual number of voice modulators. + */ + + /* Restrict identity check to the actual number of voice modulators */ + /* Actual number of voice modulators : defaults + [instruments] */ + identity_limit_count = voice->mod_count; + + for(i = 0; i < mod_list_count; i++) + { + + mod = mod_list[i]; + /* in mode FLUID_VOICE_OVERWRITE disabled instruments modulators CANNOT be skipped. */ + /* in mode FLUID_VOICE_ADD disabled preset modulators can be skipped. */ + + if((mode == FLUID_VOICE_OVERWRITE) || (mod->amount != 0)) + { + /* Instrument modulators -supersede- existing (default) modulators. + SF 2.01 page 69, 'bullet' 6 */ + + /* Preset modulators -add- to existing instrument modulators. + SF2.01 page 70 first bullet on page */ + fluid_voice_add_mod_local(voice, mod, mode, identity_limit_count); + } + } +} + +/* + * fluid_defpreset_noteon + */ +int +fluid_defpreset_noteon(fluid_defpreset_t *defpreset, fluid_synth_t *synth, int chan, int key, int vel) +{ + fluid_preset_zone_t *preset_zone, *global_preset_zone; + fluid_inst_t *inst; + fluid_inst_zone_t *inst_zone, *global_inst_zone; + fluid_voice_zone_t *voice_zone; + fluid_list_t *list; + fluid_voice_t *voice; + int tuned_key; + int i; + + /* For detuned channels it might be better to use another key for Soundfont sample selection + * giving better approximations for the pitch than the original key. + * Example: play key 60 on 6370 Hz => use tuned key 64 for sample selection + * + * This feature is only enabled for melodic channels. + * For drum channels we always select Soundfont samples by key numbers. + */ + + if(synth->channel[chan]->channel_type == CHANNEL_TYPE_MELODIC) + { + tuned_key = (int)(fluid_channel_get_key_pitch(synth->channel[chan], key) / 100.0f + 0.5f); + } + else + { + tuned_key = key; + } + + global_preset_zone = fluid_defpreset_get_global_zone(defpreset); + + /* run thru all the zones of this preset */ + preset_zone = fluid_defpreset_get_zone(defpreset); + + while(preset_zone != NULL) + { + + /* check if the note falls into the key and velocity range of this + preset */ + if(fluid_zone_inside_range(&preset_zone->range, tuned_key, vel)) + { + + inst = fluid_preset_zone_get_inst(preset_zone); + global_inst_zone = fluid_inst_get_global_zone(inst); + + /* run thru all the zones of this instrument that could start a voice */ + for(list = preset_zone->voice_zone; list != NULL; list = fluid_list_next(list)) + { + voice_zone = fluid_list_get(list); + + /* check if the instrument zone is ignored and the note falls into + the key and velocity range of this instrument zone. + An instrument zone must be ignored when its voice is already running + played by a legato passage (see fluid_synth_noteon_monopoly_legato()) */ + if(fluid_zone_inside_range(&voice_zone->range, tuned_key, vel)) + { + + inst_zone = voice_zone->inst_zone; + + /* this is a good zone. allocate a new synthesis process and initialize it */ + voice = fluid_synth_alloc_voice_LOCAL(synth, inst_zone->sample, chan, key, vel, &voice_zone->range); + + if(voice == NULL) + { + return FLUID_FAILED; + } + + + /* Instrument level, generators */ + + for(i = 0; i < GEN_LAST; i++) + { + + /* SF 2.01 section 9.4 'bullet' 4: + * + * A generator in a local instrument zone supersedes a + * global instrument zone generator. Both cases supersede + * the default generator -> voice_gen_set */ + + if(inst_zone->gen[i].flags) + { + fluid_voice_gen_set(voice, i, inst_zone->gen[i].val); + + } + else if((global_inst_zone != NULL) && (global_inst_zone->gen[i].flags)) + { + fluid_voice_gen_set(voice, i, global_inst_zone->gen[i].val); + + } + else + { + /* The generator has not been defined in this instrument. + * Do nothing, leave it at the default. + */ + } + + } /* for all generators */ + + /* Adds instrument zone modulators (global and local) to the voice.*/ + fluid_defpreset_noteon_add_mod_to_voice(voice, + /* global instrument modulators */ + global_inst_zone ? global_inst_zone->mod : NULL, + inst_zone->mod, /* local instrument modulators */ + FLUID_VOICE_OVERWRITE); /* mode */ + + /* Preset level, generators */ + + for(i = 0; i < GEN_LAST; i++) + { + + /* SF 2.01 section 8.5 page 58: If some generators are + encountered at preset level, they should be ignored. + However this check is not necessary when the soundfont + loader has ignored invalid preset generators. + Actually load_pgen()has ignored these invalid preset + generators: + GEN_STARTADDROFS, GEN_ENDADDROFS, + GEN_STARTLOOPADDROFS, GEN_ENDLOOPADDROFS, + GEN_STARTADDRCOARSEOFS,GEN_ENDADDRCOARSEOFS, + GEN_STARTLOOPADDRCOARSEOFS, + GEN_KEYNUM, GEN_VELOCITY, + GEN_ENDLOOPADDRCOARSEOFS, + GEN_SAMPLEMODE, GEN_EXCLUSIVECLASS,GEN_OVERRIDEROOTKEY + */ + + /* SF 2.01 section 9.4 'bullet' 9: A generator in a + * local preset zone supersedes a global preset zone + * generator. The effect is -added- to the destination + * summing node -> voice_gen_incr */ + + if(preset_zone->gen[i].flags) + { + fluid_voice_gen_incr(voice, i, preset_zone->gen[i].val); + } + else if((global_preset_zone != NULL) && global_preset_zone->gen[i].flags) + { + fluid_voice_gen_incr(voice, i, global_preset_zone->gen[i].val); + } + else + { + /* The generator has not been defined in this preset + * Do nothing, leave it unchanged. + */ + } + } /* for all generators */ + + /* Adds preset zone modulators (global and local) to the voice.*/ + fluid_defpreset_noteon_add_mod_to_voice(voice, + /* global preset modulators */ + global_preset_zone ? global_preset_zone->mod : NULL, + preset_zone->mod, /* local preset modulators */ + FLUID_VOICE_ADD); /* mode */ + + /* add the synthesis process to the synthesis loop. */ + fluid_synth_start_voice(synth, voice); + + /* Store the ID of the first voice that was created by this noteon event. + * Exclusive class may only terminate older voices. + * That avoids killing voices, which have just been created. + * (a noteon event can create several voice processes with the same exclusive + * class - for example when using stereo samples) + */ + } + } + } + + preset_zone = fluid_preset_zone_next(preset_zone); + } + + return FLUID_OK; +} + +/* + * fluid_defpreset_set_global_zone + */ +int +fluid_defpreset_set_global_zone(fluid_defpreset_t *defpreset, fluid_preset_zone_t *zone) +{ + defpreset->global_zone = zone; + return FLUID_OK; +} + +/* + * fluid_defpreset_import_sfont + */ +int +fluid_defpreset_import_sfont(fluid_defpreset_t *defpreset, + SFPreset *sfpreset, + fluid_defsfont_t *defsfont, + SFData *sfdata) +{ + fluid_list_t *p; + SFZone *sfzone; + fluid_preset_zone_t *zone; + int count; + char zone_name[256]; + + if(FLUID_STRLEN(sfpreset->name) > 0) + { + FLUID_STRCPY(defpreset->name, sfpreset->name); + } + else + { + FLUID_SNPRINTF(defpreset->name, sizeof(defpreset->name), "Bank%d,Pre%d", sfpreset->bank, sfpreset->prenum); + } + + defpreset->bank = sfpreset->bank; + defpreset->num = sfpreset->prenum; + p = sfpreset->zone; + count = 0; + + while(p != NULL) + { + sfzone = (SFZone *)fluid_list_get(p); + FLUID_SNPRINTF(zone_name, sizeof(zone_name), "pz:%s/%d", defpreset->name, count); + zone = new_fluid_preset_zone(zone_name); + + if(zone == NULL) + { + return FLUID_FAILED; + } + + if(fluid_preset_zone_import_sfont(zone, defpreset->global_zone, sfzone, defsfont, sfdata) != FLUID_OK) + { + delete_fluid_preset_zone(zone); + return FLUID_FAILED; + } + + if((count == 0) && (fluid_preset_zone_get_inst(zone) == NULL)) + { + fluid_defpreset_set_global_zone(defpreset, zone); + } + else if(fluid_defpreset_add_zone(defpreset, zone) != FLUID_OK) + { + delete_fluid_preset_zone(zone); + return FLUID_FAILED; + } + + p = fluid_list_next(p); + count++; + } + + return FLUID_OK; +} + +/* + * fluid_defpreset_add_zone + */ +int +fluid_defpreset_add_zone(fluid_defpreset_t *defpreset, fluid_preset_zone_t *zone) +{ + if(defpreset->zone == NULL) + { + zone->next = NULL; + defpreset->zone = zone; + } + else + { + zone->next = defpreset->zone; + defpreset->zone = zone; + } + + return FLUID_OK; +} + +/* + * fluid_defpreset_get_zone + */ +fluid_preset_zone_t * +fluid_defpreset_get_zone(fluid_defpreset_t *defpreset) +{ + return defpreset->zone; +} + +/* + * fluid_defpreset_get_global_zone + */ +fluid_preset_zone_t * +fluid_defpreset_get_global_zone(fluid_defpreset_t *defpreset) +{ + return defpreset->global_zone; +} + +/*************************************************************** + * + * PRESET_ZONE + */ + +/* + * fluid_preset_zone_next + */ +fluid_preset_zone_t * +fluid_preset_zone_next(fluid_preset_zone_t *zone) +{ + return zone->next; +} + +/* + * new_fluid_preset_zone + */ +fluid_preset_zone_t * +new_fluid_preset_zone(char *name) +{ + fluid_preset_zone_t *zone = NULL; + zone = FLUID_NEW(fluid_preset_zone_t); + + if(zone == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + zone->next = NULL; + zone->voice_zone = NULL; + zone->name = FLUID_STRDUP(name); + + if(zone->name == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + FLUID_FREE(zone); + return NULL; + } + + zone->inst = NULL; + zone->range.keylo = 0; + zone->range.keyhi = 128; + zone->range.vello = 0; + zone->range.velhi = 128; + zone->range.ignore = FALSE; + + /* Flag all generators as unused (default, they will be set when they are found + * in the sound font). + * This also sets the generator values to default, but that is of no concern here.*/ + fluid_gen_init(&zone->gen[0], NULL); + zone->mod = NULL; /* list of modulators */ + return zone; +} + +/* + * delete list of modulators. + */ +void delete_fluid_list_mod(fluid_mod_t *mod) +{ + fluid_mod_t *tmp; + + while(mod) /* delete the modulators */ + { + tmp = mod; + mod = mod->next; + delete_fluid_mod(tmp); + } +} + +/* + * delete_fluid_preset_zone + */ +void +delete_fluid_preset_zone(fluid_preset_zone_t *zone) +{ + fluid_list_t *list; + + fluid_return_if_fail(zone != NULL); + + delete_fluid_list_mod(zone->mod); + + for(list = zone->voice_zone; list != NULL; list = fluid_list_next(list)) + { + FLUID_FREE(fluid_list_get(list)); + } + + delete_fluid_list(zone->voice_zone); + + FLUID_FREE(zone->name); + FLUID_FREE(zone); +} + +static int fluid_preset_zone_create_voice_zones(fluid_preset_zone_t *preset_zone) +{ + fluid_inst_zone_t *inst_zone; + fluid_sample_t *sample; + fluid_voice_zone_t *voice_zone; + fluid_zone_range_t *irange; + fluid_zone_range_t *prange = &preset_zone->range; + + fluid_return_val_if_fail(preset_zone->inst != NULL, FLUID_FAILED); + + inst_zone = fluid_inst_get_zone(preset_zone->inst); + + while(inst_zone != NULL) + { + + /* We only create voice ranges for zones that could actually start a voice, + * i.e. that have a sample and don't point to ROM */ + sample = fluid_inst_zone_get_sample(inst_zone); + + if((sample == NULL) || fluid_sample_in_rom(sample)) + { + inst_zone = fluid_inst_zone_next(inst_zone); + continue; + } + + voice_zone = FLUID_NEW(fluid_voice_zone_t); + + if(voice_zone == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FLUID_FAILED; + } + + voice_zone->inst_zone = inst_zone; + + irange = &inst_zone->range; + + voice_zone->range.keylo = (prange->keylo > irange->keylo) ? prange->keylo : irange->keylo; + voice_zone->range.keyhi = (prange->keyhi < irange->keyhi) ? prange->keyhi : irange->keyhi; + voice_zone->range.vello = (prange->vello > irange->vello) ? prange->vello : irange->vello; + voice_zone->range.velhi = (prange->velhi < irange->velhi) ? prange->velhi : irange->velhi; + voice_zone->range.ignore = FALSE; + + preset_zone->voice_zone = fluid_list_append(preset_zone->voice_zone, voice_zone); + + inst_zone = fluid_inst_zone_next(inst_zone); + } + + return FLUID_OK; +} + +/** + * Checks if modulator mod is identical to another modulator in the list + * (specs SF 2.0X 7.4, 7.8). + * @param mod, modulator list. + * @param name, if not NULL, pointer on a string displayed as warning. + * @return TRUE if mod is identical to another modulator, FALSE otherwise. + */ +static int +fluid_zone_is_mod_identical(fluid_mod_t *mod, char *name) +{ + fluid_mod_t *next = mod->next; + + while(next) + { + /* is mod identical to next ? */ + if(fluid_mod_test_identity(mod, next)) + { + if(name) + { + FLUID_LOG(FLUID_WARN, "Ignoring identical modulator %s", name); + } + + return TRUE; + } + + next = next->next; + } + + return FALSE; +} + +/** + * Limits the number of modulators in a modulator list. + * This is appropriate to internal synthesizer modulators tables + * which have a fixed size (FLUID_NUM_MOD). + * + * @param zone_name, zone name + * @param list_mod, address of pointer on modulator list. + */ +static void fluid_limit_mod_list(char *zone_name, fluid_mod_t **list_mod) +{ + int mod_idx = 0; /* modulator index */ + fluid_mod_t *prev_mod = NULL; /* previous modulator in list_mod */ + fluid_mod_t *mod = *list_mod; /* first modulator in list_mod */ + + while(mod) + { + if((mod_idx + 1) > FLUID_NUM_MOD) + { + /* truncation of list_mod */ + if(mod_idx) + { + prev_mod->next = NULL; + } + else + { + *list_mod = NULL; + } + + delete_fluid_list_mod(mod); + FLUID_LOG(FLUID_WARN, "%s, modulators count limited to %d", zone_name, + FLUID_NUM_MOD); + break; + } + + mod_idx++; + prev_mod = mod; + mod = mod->next; + } +} + +/** + * Checks and remove invalid modulators from a zone modulators list. + * - checks valid modulator sources (specs SF 2.01 7.4, 7.8, 8.2.1). + * - checks identical modulators in the list (specs SF 2.01 7.4, 7.8). + * @param zone_name, zone name. + * @param list_mod, address of pointer on modulators list. + */ +static void +fluid_zone_check_mod(char *zone_name, fluid_mod_t **list_mod) +{ + fluid_mod_t *prev_mod = NULL; /* previous modulator in list_mod */ + fluid_mod_t *mod = *list_mod; /* first modulator in list_mod */ + int mod_idx = 0; /* modulator index */ + + while(mod) + { + char zone_mod_name[256]; + fluid_mod_t *next = mod->next; + + /* prepare modulator name: zonename/#modulator */ + FLUID_SNPRINTF(zone_mod_name, sizeof(zone_mod_name), "%s/mod%d", zone_name, mod_idx); + + /* has mod invalid sources ? */ + if(!fluid_mod_check_sources(mod, zone_mod_name) + /* or is mod identical to any following modulator ? */ + || fluid_zone_is_mod_identical(mod, zone_mod_name)) + { + /* the modulator is useless so we remove it */ + if(prev_mod) + { + prev_mod->next = next; + } + else + { + *list_mod = next; + } + + delete_fluid_mod(mod); /* freeing */ + } + else + { + prev_mod = mod; + } + + mod = next; + mod_idx++; + } + + /* limits the size of modulators list */ + fluid_limit_mod_list(zone_name, list_mod); +} + +/* + * fluid_zone_gen_import_sfont + * Imports generators from sfzone to gen and range. + * @param gen, pointer on destination generators table. + * @param range, pointer on destination range generators. + * @param sfzone, pointer on soundfont zone generators. + */ +static void +fluid_zone_gen_import_sfont(fluid_gen_t *gen, fluid_zone_range_t *range, fluid_zone_range_t *global_range, SFZone *sfzone) +{ + fluid_list_t *r; + SFGen *sfgen; + + if(global_range != NULL) + { + // All zones are initialized with the default range of 0-127. However, local zones should be superseded by + // the range of their global zone in case that local zone lacks a GEN_KEYRANGE or GEN_VELRANGE + // (see issue #1250). + range->keylo = global_range->keylo; + range->keyhi = global_range->keyhi; + range->vello = global_range->vello; + range->velhi = global_range->velhi; + } + + for(r = sfzone->gen; r != NULL;) + { + sfgen = (SFGen *)fluid_list_get(r); + + switch(sfgen->id) + { + case GEN_KEYRANGE: + range->keylo = sfgen->amount.range.lo; + range->keyhi = sfgen->amount.range.hi; + break; + + case GEN_VELRANGE: + range->vello = sfgen->amount.range.lo; + range->velhi = sfgen->amount.range.hi; + break; + + case GEN_ATTENUATION: + /* EMU8k/10k hardware applies a scale factor to initial attenuation generator values set at + * preset and instrument level */ + gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword * EMU_ATTENUATION_FACTOR; + gen[sfgen->id].flags = GEN_SET; + break; + + case GEN_INSTRUMENT: + case GEN_SAMPLEID: + gen[sfgen->id].val = (fluid_real_t) sfgen->amount.uword; + gen[sfgen->id].flags = GEN_SET; + break; + + default: + gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword; + gen[sfgen->id].flags = GEN_SET; + break; + } + + r = fluid_list_next(r); + } +} + +/* + * fluid_zone_mod_source_import_sfont + * Imports source information from sf_source to src and flags. + * @param src, pointer on destination modulator source. + * @param flags, pointer on destination modulator flags. + * @param sf_source, soundfont modulator source. + * @return return TRUE if success, FALSE if source type is unknown. + */ +static int +fluid_zone_mod_source_import_sfont(unsigned char *src, unsigned char *flags, unsigned short sf_source) +{ + int type; + unsigned char flags_dest; /* destination flags */ + + /* sources */ + *src = sf_source & 127; /* index of source, seven-bit value, SF2.01 section 8.2, page 50 */ + + /* Bit 7: CC flag SF 2.01 section 8.2.1 page 50*/ + flags_dest = 0; + + if(sf_source & (1 << 7)) + { + flags_dest |= FLUID_MOD_CC; + } + else + { + flags_dest |= FLUID_MOD_GC; + } + + /* Bit 8: D flag SF 2.01 section 8.2.2 page 51*/ + if(sf_source & (1 << 8)) + { + flags_dest |= FLUID_MOD_NEGATIVE; + } + else + { + flags_dest |= FLUID_MOD_POSITIVE; + } + + /* Bit 9: P flag SF 2.01 section 8.2.3 page 51*/ + if(sf_source & (1 << 9)) + { + flags_dest |= FLUID_MOD_BIPOLAR; + } + else + { + flags_dest |= FLUID_MOD_UNIPOLAR; + } + + /* modulator source types: SF2.01 section 8.2.1 page 52 */ + type = sf_source >> 10; + type &= 63; /* type is a 6-bit value */ + + if(type == 0) + { + flags_dest |= FLUID_MOD_LINEAR; + } + else if(type == 1) + { + flags_dest |= FLUID_MOD_CONCAVE; + } + else if(type == 2) + { + flags_dest |= FLUID_MOD_CONVEX; + } + else if(type == 3) + { + flags_dest |= FLUID_MOD_SWITCH; + } + else + { + *flags = flags_dest; + /* This shouldn't happen - unknown type! */ + return FALSE; + } + + *flags = flags_dest; + return TRUE; +} + +/* + * fluid_zone_mod_import_sfont + * Imports modulators from sfzone to modulators list mod. + * @param zone_name, zone name. + * @param mod, address of pointer on modulators list to return. + * @param sfzone, pointer on soundfont zone. + * @return FLUID_OK if success, FLUID_FAILED otherwise. + */ +static int +fluid_zone_mod_import_sfont(char *zone_name, fluid_mod_t **mod, SFZone *sfzone) +{ + fluid_list_t *r; + int count; + + /* Import the modulators (only SF2.1 and higher) */ + for(count = 0, r = sfzone->mod; r != NULL; count++) + { + + SFMod *mod_src = (SFMod *)fluid_list_get(r); + fluid_mod_t *mod_dest = new_fluid_mod(); + + if(mod_dest == NULL) + { + return FLUID_FAILED; + } + + mod_dest->next = NULL; /* pointer to next modulator, this is the end of the list now.*/ + + /* *** Amount *** */ + mod_dest->amount = mod_src->amount; + + /* *** Source *** */ + if(!fluid_zone_mod_source_import_sfont(&mod_dest->src1, &mod_dest->flags1, mod_src->src)) + { + /* This shouldn't happen - unknown type! + * Deactivate the modulator by setting the amount to 0. */ + mod_dest->amount = 0; + } + + /* Note: When primary source input (src1) is set to General Controller 'No Controller', + output will be forced to 0.0 at synthesis time (see fluid_mod_get_value()). + That means that the minimum value of the modulator will be always 0.0. + We need to force amount value to 0 to ensure a correct evaluation of the minimum + value later (see fluid_voice_get_lower_boundary_for_attenuation()). + */ + if(((mod_dest->flags1 & FLUID_MOD_CC) == FLUID_MOD_GC) && + (mod_dest->src1 == FLUID_MOD_NONE)) + { + mod_dest->amount = 0; + } + + /* *** Dest *** */ + mod_dest->dest = mod_src->dest; /* index of controlled generator */ + + /* *** Amount source *** */ + if(!fluid_zone_mod_source_import_sfont(&mod_dest->src2, &mod_dest->flags2, mod_src->amtsrc)) + { + /* This shouldn't happen - unknown type! + * Deactivate the modulator by setting the amount to 0. */ + mod_dest->amount = 0; + } + /* Note: When secondary source input (src2) is set to General Controller 'No Controller', + output will be forced to +1.0 at synthesis time (see fluid_mod_get_value()). + That means that this source will behave unipolar only. We need to force the + unipolar flag to ensure to ensure a correct evaluation of the minimum + value later (see fluid_voice_get_lower_boundary_for_attenuation()). + */ + if(((mod_dest->flags2 & FLUID_MOD_CC) == FLUID_MOD_GC) && + (mod_dest->src2 == FLUID_MOD_NONE)) + { + mod_dest->flags2 &= ~FLUID_MOD_BIPOLAR; + } + + /* *** Transform *** */ + /* SF2.01 only uses the 'linear' transform (0). + * Deactivate the modulator by setting the amount to 0 in any other case. + */ + if(mod_src->trans != 0) + { + mod_dest->amount = 0; + } + + /* Store the new modulator in the zone The order of modulators + * will make a difference, at least in an instrument context: The + * second modulator overwrites the first one, if they only differ + * in amount. */ + if(count == 0) + { + *mod = mod_dest; + } + else + { + fluid_mod_t *last_mod = *mod; + + /* Find the end of the list */ + while(last_mod->next != NULL) + { + last_mod = last_mod->next; + } + + last_mod->next = mod_dest; + } + + r = fluid_list_next(r); + } /* foreach modulator */ + + /* checks and removes invalid modulators in modulators list*/ + fluid_zone_check_mod(zone_name, mod); + return FLUID_OK; +} + +/* + * fluid_preset_zone_import_sfont + */ +int +fluid_preset_zone_import_sfont(fluid_preset_zone_t *zone, fluid_preset_zone_t *global_zone, SFZone *sfzone, fluid_defsfont_t *defsfont, SFData *sfdata) +{ + /* import the generators */ + fluid_zone_gen_import_sfont(zone->gen, &zone->range, global_zone ? &global_zone->range : NULL, sfzone); + + if(zone->gen[GEN_INSTRUMENT].flags == GEN_SET) + { + int inst_idx = (int) zone->gen[GEN_INSTRUMENT].val; + + zone->inst = find_inst_by_idx(defsfont, inst_idx); + + if(zone->inst == NULL) + { + zone->inst = fluid_inst_import_sfont(inst_idx, defsfont, sfdata); + } + + if(zone->inst == NULL) + { + + FLUID_LOG(FLUID_ERR, "Preset zone %s: Invalid instrument reference", + zone->name); + return FLUID_FAILED; + } + + if(fluid_preset_zone_create_voice_zones(zone) == FLUID_FAILED) + { + return FLUID_FAILED; + } + + /* We don't need this generator anymore */ + zone->gen[GEN_INSTRUMENT].flags = GEN_UNUSED; + } + + /* Import the modulators (only SF2.1 and higher) */ + return fluid_zone_mod_import_sfont(zone->name, &zone->mod, sfzone); +} + +/* + * fluid_preset_zone_get_inst + */ +fluid_inst_t * +fluid_preset_zone_get_inst(fluid_preset_zone_t *zone) +{ + return zone->inst; +} + + +/*************************************************************** + * + * INST + */ + +/* + * new_fluid_inst + */ +fluid_inst_t * +new_fluid_inst() +{ + fluid_inst_t *inst = FLUID_NEW(fluid_inst_t); + + if(inst == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + inst->name[0] = 0; + inst->global_zone = NULL; + inst->zone = NULL; + return inst; +} + +/* + * delete_fluid_inst + */ +void +delete_fluid_inst(fluid_inst_t *inst) +{ + fluid_inst_zone_t *zone; + + fluid_return_if_fail(inst != NULL); + + delete_fluid_inst_zone(inst->global_zone); + inst->global_zone = NULL; + + zone = inst->zone; + + while(zone != NULL) + { + inst->zone = zone->next; + delete_fluid_inst_zone(zone); + zone = inst->zone; + } + + FLUID_FREE(inst); +} + +/* + * fluid_inst_set_global_zone + */ +int +fluid_inst_set_global_zone(fluid_inst_t *inst, fluid_inst_zone_t *zone) +{ + inst->global_zone = zone; + return FLUID_OK; +} + +/* + * fluid_inst_import_sfont + */ +fluid_inst_t * +fluid_inst_import_sfont(int inst_idx, fluid_defsfont_t *defsfont, SFData *sfdata) +{ + fluid_list_t *p; + fluid_list_t *inst_list; + fluid_inst_t *inst; + SFZone *sfzone; + SFInst *sfinst; + fluid_inst_zone_t *inst_zone; + char zone_name[256]; + int count; + + for (inst_list = sfdata->inst; inst_list; inst_list = fluid_list_next(inst_list)) + { + sfinst = fluid_list_get(inst_list); + if (sfinst->idx == inst_idx) + { + break; + } + } + if (inst_list == NULL) + { + return NULL; + } + + inst = (fluid_inst_t *) new_fluid_inst(); + + if(inst == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + inst->source_idx = sfinst->idx; + + p = sfinst->zone; + + if(FLUID_STRLEN(sfinst->name) > 0) + { + FLUID_STRCPY(inst->name, sfinst->name); + } + else + { + FLUID_STRCPY(inst->name, ""); + } + + count = 0; + + while(p != NULL) + { + + sfzone = (SFZone *)fluid_list_get(p); + /* instrument zone name */ + FLUID_SNPRINTF(zone_name, sizeof(zone_name), "iz:%s/%d", inst->name, count); + + inst_zone = new_fluid_inst_zone(zone_name); + if(inst_zone == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + goto error; + } + + if(fluid_inst_zone_import_sfont(inst_zone, inst->global_zone, sfzone, defsfont, sfdata) != FLUID_OK) + { + FLUID_LOG(FLUID_ERR, "fluid_inst_zone_import_sfont() failed for instrument %s", inst->name); + delete_fluid_inst_zone(inst_zone); + goto error; + } + + if((count == 0) && (fluid_inst_zone_get_sample(inst_zone) == NULL)) + { + fluid_inst_set_global_zone(inst, inst_zone); + + } + else if(fluid_inst_add_zone(inst, inst_zone) != FLUID_OK) + { + FLUID_LOG(FLUID_ERR, "fluid_inst_add_zone() failed for instrument %s", inst->name); + delete_fluid_inst_zone(inst_zone); + goto error; + } + + p = fluid_list_next(p); + count++; + } + + defsfont->inst = fluid_list_append(defsfont->inst, inst); + return inst; + +error: + delete_fluid_inst(inst); + return NULL; +} + +/* + * fluid_inst_add_zone + */ +int +fluid_inst_add_zone(fluid_inst_t *inst, fluid_inst_zone_t *zone) +{ + if(inst->zone == NULL) + { + zone->next = NULL; + inst->zone = zone; + } + else + { + zone->next = inst->zone; + inst->zone = zone; + } + + return FLUID_OK; +} + +/* + * fluid_inst_get_zone + */ +fluid_inst_zone_t * +fluid_inst_get_zone(fluid_inst_t *inst) +{ + return inst->zone; +} + +/* + * fluid_inst_get_global_zone + */ +fluid_inst_zone_t * +fluid_inst_get_global_zone(fluid_inst_t *inst) +{ + return inst->global_zone; +} + +/*************************************************************** + * + * INST_ZONE + */ + +/* + * new_fluid_inst_zone + */ +fluid_inst_zone_t * +new_fluid_inst_zone(char *name) +{ + fluid_inst_zone_t *zone = NULL; + zone = FLUID_NEW(fluid_inst_zone_t); + + if(zone == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + zone->next = NULL; + zone->name = FLUID_STRDUP(name); + + if(zone->name == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + FLUID_FREE(zone); + return NULL; + } + + zone->sample = NULL; + zone->range.keylo = 0; + zone->range.keyhi = 128; + zone->range.vello = 0; + zone->range.velhi = 128; + zone->range.ignore = FALSE; + /* Flag the generators as unused. + * This also sets the generator values to default, but they will be overwritten anyway, if used.*/ + fluid_gen_init(&zone->gen[0], NULL); + zone->mod = NULL; /* list of modulators */ + return zone; +} + +/* + * delete_fluid_inst_zone + */ +void +delete_fluid_inst_zone(fluid_inst_zone_t *zone) +{ + fluid_return_if_fail(zone != NULL); + + delete_fluid_list_mod(zone->mod); + + FLUID_FREE(zone->name); + FLUID_FREE(zone); +} + +/* + * fluid_inst_zone_next + */ +fluid_inst_zone_t * +fluid_inst_zone_next(fluid_inst_zone_t *zone) +{ + return zone->next; +} + +/* + * fluid_inst_zone_import_sfont + */ +int +fluid_inst_zone_import_sfont(fluid_inst_zone_t *inst_zone, fluid_inst_zone_t *global_inst_zone, SFZone *sfzone, fluid_defsfont_t *defsfont, SFData *sfdata) +{ + /* import the generators */ + fluid_zone_gen_import_sfont(inst_zone->gen, &inst_zone->range, global_inst_zone ? &global_inst_zone->range : NULL, sfzone); + + /* FIXME */ + /* if (zone->gen[GEN_EXCLUSIVECLASS].flags == GEN_SET) { */ + /* FLUID_LOG(FLUID_DBG, "ExclusiveClass=%d\n", (int) zone->gen[GEN_EXCLUSIVECLASS].val); */ + /* } */ + + if (inst_zone->gen[GEN_SAMPLEID].flags == GEN_SET) + { + fluid_list_t *list; + SFSample *sfsample; + int sample_idx = (int) inst_zone->gen[GEN_SAMPLEID].val; + + /* find the SFSample by index */ + for(list = sfdata->sample; list; list = fluid_list_next(list)) + { + sfsample = fluid_list_get(list); + if (sfsample->idx == sample_idx) + { + break; + } + } + if (list == NULL) + { + FLUID_LOG(FLUID_ERR, "Instrument zone '%s': Invalid sample reference", + inst_zone->name); + return FLUID_FAILED; + } + + inst_zone->sample = sfsample->fluid_sample; + + /* we don't need this generator anymore, mark it as unused */ + inst_zone->gen[GEN_SAMPLEID].flags = GEN_UNUSED; + } + + /* Import the modulators (only SF2.1 and higher) */ + return fluid_zone_mod_import_sfont(inst_zone->name, &inst_zone->mod, sfzone); +} + +/* + * fluid_inst_zone_get_sample + */ +fluid_sample_t * +fluid_inst_zone_get_sample(fluid_inst_zone_t *zone) +{ + return zone->sample; +} + + +int +fluid_zone_inside_range(fluid_zone_range_t *range, int key, int vel) +{ + /* ignoreInstrumentZone is set in mono legato playing */ + int ignore_zone = range->ignore; + + /* Reset the 'ignore' request */ + range->ignore = FALSE; + + return !ignore_zone && ((range->keylo <= key) && + (range->keyhi >= key) && + (range->vello <= vel) && + (range->velhi >= vel)); +} + +/*************************************************************** + * + * SAMPLE + */ + +/* + * fluid_sample_in_rom + */ +int +fluid_sample_in_rom(fluid_sample_t *sample) +{ + return (sample->sampletype & FLUID_SAMPLETYPE_ROM); +} + + +/* + * fluid_sample_import_sfont + */ +int +fluid_sample_import_sfont(fluid_sample_t *sample, SFSample *sfsample, fluid_defsfont_t *defsfont) +{ + FLUID_STRCPY(sample->name, sfsample->name); + + sample->source_start = sfsample->start; + sample->source_end = (sfsample->end > 0) ? sfsample->end - 1 : 0; /* marks last sample, contrary to SF spec. */ + sample->source_loopstart = sfsample->loopstart; + sample->source_loopend = sfsample->loopend; + + sample->start = sample->source_start; + sample->end = sample->source_end; + sample->loopstart = sample->source_loopstart; + sample->loopend = sample->source_loopend; + sample->samplerate = sfsample->samplerate; + sample->origpitch = sfsample->origpitch; + sample->pitchadj = sfsample->pitchadj; + sample->sampletype = sfsample->sampletype; + + if(defsfont->dynamic_samples) + { + sample->notify = dynamic_samples_sample_notify; + } + + if(fluid_sample_validate(sample, defsfont->samplesize) == FLUID_FAILED) + { + return FLUID_FAILED; + } + + return FLUID_OK; +} + +/* Called if a sample is no longer used by a voice. Used by dynamic sample loading + * to unload a sample that is not used by any loaded presets anymore but couldn't + * be unloaded straight away because it was still in use by a voice. */ +static int dynamic_samples_sample_notify(fluid_sample_t *sample, int reason) +{ + if(reason == FLUID_SAMPLE_DONE && sample->preset_count == 0) + { + unload_sample(sample); + } + + return FLUID_OK; +} + +/* Called if a preset has been selected for or unselected from a channel. Used by + * dynamic sample loading to load and unload samples on demand. */ +static int dynamic_samples_preset_notify(fluid_preset_t *preset, int reason, int chan) +{ + fluid_defsfont_t *defsfont; + + if(reason == FLUID_PRESET_SELECTED) + { + FLUID_LOG(FLUID_DBG, "Selected preset '%s' on channel %d", fluid_preset_get_name(preset), chan); + defsfont = fluid_sfont_get_data(preset->sfont); + return load_preset_samples(defsfont, preset); + } + + if(reason == FLUID_PRESET_UNSELECTED) + { + FLUID_LOG(FLUID_DBG, "Deselected preset '%s' from channel %d", fluid_preset_get_name(preset), chan); + defsfont = fluid_sfont_get_data(preset->sfont); + return unload_preset_samples(defsfont, preset); + } + + if(reason == FLUID_PRESET_PIN) + { + defsfont = fluid_sfont_get_data(preset->sfont); + return pin_preset_samples(defsfont, preset); + } + + if(reason == FLUID_PRESET_UNPIN) + { + defsfont = fluid_sfont_get_data(preset->sfont); + return unpin_preset_samples(defsfont, preset); + } + + return FLUID_OK; +} + + +static int pin_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset) +{ + fluid_defpreset_t *defpreset; + + defpreset = fluid_preset_get_data(preset); + if (defpreset->pinned) + { + return FLUID_OK; + } + + FLUID_LOG(FLUID_DBG, "Pinning preset '%s'", fluid_preset_get_name(preset)); + + if(load_preset_samples(defsfont, preset) == FLUID_FAILED) + { + return FLUID_FAILED; + } + + defpreset->pinned = TRUE; + + return FLUID_OK; +} + + +static int unpin_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset) +{ + fluid_defpreset_t *defpreset; + + defpreset = fluid_preset_get_data(preset); + if (!defpreset->pinned) + { + return FLUID_OK; + } + + FLUID_LOG(FLUID_DBG, "Unpinning preset '%s'", fluid_preset_get_name(preset)); + + if(unload_preset_samples(defsfont, preset) == FLUID_FAILED) + { + return FLUID_FAILED; + } + + defpreset->pinned = FALSE; + + return FLUID_OK; +} + + +/* Walk through all samples used by the passed in preset and make sure that the + * sample data is loaded for each sample. Used by dynamic sample loading. */ +static int load_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset) +{ + fluid_defpreset_t *defpreset; + fluid_preset_zone_t *preset_zone; + fluid_inst_t *inst; + fluid_inst_zone_t *inst_zone; + fluid_sample_t *sample; + SFData *sffile = NULL; + + defpreset = fluid_preset_get_data(preset); + preset_zone = fluid_defpreset_get_zone(defpreset); + + while(preset_zone != NULL) + { + inst = fluid_preset_zone_get_inst(preset_zone); + inst_zone = fluid_inst_get_zone(inst); + + while(inst_zone != NULL) + { + sample = fluid_inst_zone_get_sample(inst_zone); + + if((sample != NULL) && (sample->start != sample->end)) + { + sample->preset_count++; + + /* If this is the first time this sample has been selected, + * load the sampledata */ + if(sample->preset_count == 1) + { + /* Make sure we have an open Soundfont file. Do this here + * to avoid having to open the file if no loading is necessary + * for a preset */ + if(sffile == NULL) + { + sffile = fluid_sffile_open(defsfont->filename, defsfont->fcbs); + + if(sffile == NULL) + { + FLUID_LOG(FLUID_ERR, "Unable to open Soundfont file"); + return FLUID_FAILED; + } + } + + if(fluid_defsfont_load_sampledata(defsfont, sffile, sample) == FLUID_OK) + { + fluid_sample_sanitize_loop(sample, (sample->end + 1) * sizeof(short)); + fluid_voice_optimize_sample(sample); + } + else + { + FLUID_LOG(FLUID_ERR, "Unable to load sample '%s', disabling", sample->name); + sample->start = sample->end = 0; + } + } + } + + inst_zone = fluid_inst_zone_next(inst_zone); + } + + preset_zone = fluid_preset_zone_next(preset_zone); + } + + if(sffile != NULL) + { + fluid_sffile_close(sffile); + } + + return FLUID_OK; +} + +/* Walk through all samples used by the passed in preset and unload the sample data + * of each sample that is not used by any selected preset anymore. Used by dynamic + * sample loading. */ +static int unload_preset_samples(fluid_defsfont_t *defsfont, fluid_preset_t *preset) +{ + fluid_defpreset_t *defpreset; + fluid_preset_zone_t *preset_zone; + fluid_inst_t *inst; + fluid_inst_zone_t *inst_zone; + fluid_sample_t *sample; + + defpreset = fluid_preset_get_data(preset); + preset_zone = fluid_defpreset_get_zone(defpreset); + + while(preset_zone != NULL) + { + inst = fluid_preset_zone_get_inst(preset_zone); + inst_zone = fluid_inst_get_zone(inst); + + while(inst_zone != NULL) + { + sample = fluid_inst_zone_get_sample(inst_zone); + + if((sample != NULL) && (sample->preset_count > 0)) + { + sample->preset_count--; + + /* If the sample is not used by any preset or used by a + * sounding voice, unload it from the sample cache. If it's + * still in use by a voice, dynamic_samples_sample_notify will + * take care of unloading the sample as soon as the voice is + * finished with it (but only on the next API call). */ + if(sample->preset_count == 0 && sample->refcount == 0) + { + unload_sample(sample); + } + } + + inst_zone = fluid_inst_zone_next(inst_zone); + } + + preset_zone = fluid_preset_zone_next(preset_zone); + } + + return FLUID_OK; +} + +/* Unload an unused sample from the samplecache */ +static void unload_sample(fluid_sample_t *sample) +{ + fluid_return_if_fail(sample != NULL); + fluid_return_if_fail(sample->data != NULL); + fluid_return_if_fail(sample->preset_count == 0); + fluid_return_if_fail(sample->refcount == 0); + + FLUID_LOG(FLUID_DBG, "Unloading sample '%s'", sample->name); + + if(fluid_samplecache_unload(sample->data) == FLUID_FAILED) + { + FLUID_LOG(FLUID_ERR, "Unable to unload sample '%s'", sample->name); + } + else + { + sample->data = NULL; + sample->data24 = NULL; + } +} + +static fluid_inst_t *find_inst_by_idx(fluid_defsfont_t *defsfont, int idx) +{ + fluid_list_t *list; + fluid_inst_t *inst; + + for(list = defsfont->inst; list != NULL; list = fluid_list_next(list)) + { + inst = fluid_list_get(list); + + if(inst->source_idx == idx) + { + return inst; + } + } + + return NULL; +} diff --git a/libs/fluidsynth/src/sfloader/fluid_defsfont.h b/libs/fluidsynth/src/sfloader/fluid_defsfont.h new file mode 100644 index 00000000000..d67068955d7 --- /dev/null +++ b/libs/fluidsynth/src/sfloader/fluid_defsfont.h @@ -0,0 +1,232 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * SoundFont loading code borrowed from Smurf SoundFont Editor by Josh Green + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#ifndef _FLUID_DEFSFONT_H +#define _FLUID_DEFSFONT_H + + +#include "fluidsynth.h" +#include "fluidsynth_priv.h" +#include "fluid_sffile.h" +#include "fluid_list.h" +#include "fluid_mod.h" +#include "fluid_gen.h" + + + +/*-----------------------------------sfont.h----------------------------*/ + +#define SF_SAMPMODES_LOOP 1 +#define SF_SAMPMODES_UNROLL 2 + +#define SF_MIN_SAMPLERATE 400 +#define SF_MAX_SAMPLERATE 50000 + +#define SF_MIN_SAMPLE_LENGTH 32 + +/*************************************************************** + * + * FORWARD DECLARATIONS + */ +typedef struct _fluid_defsfont_t fluid_defsfont_t; +typedef struct _fluid_defpreset_t fluid_defpreset_t; +typedef struct _fluid_preset_zone_t fluid_preset_zone_t; +typedef struct _fluid_inst_t fluid_inst_t; +typedef struct _fluid_inst_zone_t fluid_inst_zone_t; /**< Soundfont Instrument Zone */ +typedef struct _fluid_voice_zone_t fluid_voice_zone_t; + +/* defines the velocity and key range for a zone */ +struct _fluid_zone_range_t +{ + int keylo; + int keyhi; + int vello; + int velhi; + unsigned char ignore; /* set to TRUE for legato playing to ignore this range zone */ +}; + +/* Stored on a preset zone to keep track of the inst zones that could start a voice + * and their combined preset zone/instument zone ranges */ +struct _fluid_voice_zone_t +{ + fluid_inst_zone_t *inst_zone; + fluid_zone_range_t range; +}; + +/* + + Public interface + + */ + +fluid_sfont_t *fluid_defsfloader_load(fluid_sfloader_t *loader, const char *filename); + + +int fluid_defsfont_sfont_delete(fluid_sfont_t *sfont); +const char *fluid_defsfont_sfont_get_name(fluid_sfont_t *sfont); +fluid_preset_t *fluid_defsfont_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum); +void fluid_defsfont_sfont_iteration_start(fluid_sfont_t *sfont); +fluid_preset_t *fluid_defsfont_sfont_iteration_next(fluid_sfont_t *sfont); + + +void fluid_defpreset_preset_delete(fluid_preset_t *preset); +const char *fluid_defpreset_preset_get_name(fluid_preset_t *preset); +int fluid_defpreset_preset_get_banknum(fluid_preset_t *preset); +int fluid_defpreset_preset_get_num(fluid_preset_t *preset); +int fluid_defpreset_preset_noteon(fluid_preset_t *preset, fluid_synth_t *synth, int chan, int key, int vel); + +int fluid_zone_inside_range(fluid_zone_range_t *zone_range, int key, int vel); + +/* + * fluid_defsfont_t + */ +struct _fluid_defsfont_t +{ + const fluid_file_callbacks_t *fcbs; /* the file callbacks used to load this Soundfont */ + char *filename; /* the filename of this soundfont */ + unsigned int samplepos; /* the position in the file at which the sample data starts */ + unsigned int samplesize; /* the size of the sample data in bytes */ + short *sampledata; /* the sample data, loaded in ram */ + + unsigned int sample24pos; /* position within sffd of the sm24 chunk, set to zero if no 24 bit sample support */ + unsigned int sample24size; /* length within sffd of the sm24 chunk */ + char *sample24data; /* if not NULL, the least significant byte of the 24bit sample data, loaded in ram */ + + fluid_sfont_t *sfont; /* pointer to parent sfont */ + fluid_list_t *sample; /* the samples in this soundfont */ + fluid_list_t *preset; /* the presets of this soundfont */ + fluid_list_t *inst; /* the instruments of this soundfont */ + int mlock; /* Should we try memlock (avoid swapping)? */ + int dynamic_samples; /* Enables dynamic sample loading if set */ + + fluid_list_t *preset_iter_cur; /* the current preset in the iteration */ +}; + + +fluid_defsfont_t *new_fluid_defsfont(fluid_settings_t *settings); +int delete_fluid_defsfont(fluid_defsfont_t *defsfont); +int fluid_defsfont_load(fluid_defsfont_t *defsfont, const fluid_file_callbacks_t *file_callbacks, const char *file); +const char *fluid_defsfont_get_name(fluid_defsfont_t *defsfont); +fluid_preset_t *fluid_defsfont_get_preset(fluid_defsfont_t *defsfont, int bank, int prenum); +void fluid_defsfont_iteration_start(fluid_defsfont_t *defsfont); +fluid_preset_t *fluid_defsfont_iteration_next(fluid_defsfont_t *defsfont); +int fluid_defsfont_load_sampledata(fluid_defsfont_t *defsfont, SFData *sfdata, fluid_sample_t *sample); +int fluid_defsfont_load_all_sampledata(fluid_defsfont_t *defsfont, SFData *sfdata); + +int fluid_defsfont_add_sample(fluid_defsfont_t *defsfont, fluid_sample_t *sample); +int fluid_defsfont_add_preset(fluid_defsfont_t *defsfont, fluid_defpreset_t *defpreset); + + +/* + * fluid_preset_t + */ +struct _fluid_defpreset_t +{ + fluid_defpreset_t *next; + char name[21]; /* the name of the preset */ + unsigned int bank; /* the bank number */ + unsigned int num; /* the preset number */ + fluid_preset_zone_t *global_zone; /* the global zone of the preset */ + fluid_preset_zone_t *zone; /* the chained list of preset zones */ + int pinned; /* preset samples pinned to sample cache? */ +}; + +fluid_defpreset_t *new_fluid_defpreset(void); +void delete_fluid_defpreset(fluid_defpreset_t *defpreset); +fluid_defpreset_t *fluid_defpreset_next(fluid_defpreset_t *defpreset); +int fluid_defpreset_import_sfont(fluid_defpreset_t *defpreset, SFPreset *sfpreset, fluid_defsfont_t *defsfont, SFData *sfdata); +int fluid_defpreset_set_global_zone(fluid_defpreset_t *defpreset, fluid_preset_zone_t *zone); +int fluid_defpreset_add_zone(fluid_defpreset_t *defpreset, fluid_preset_zone_t *zone); +fluid_preset_zone_t *fluid_defpreset_get_zone(fluid_defpreset_t *defpreset); +fluid_preset_zone_t *fluid_defpreset_get_global_zone(fluid_defpreset_t *defpreset); +int fluid_defpreset_get_banknum(fluid_defpreset_t *defpreset); +int fluid_defpreset_get_num(fluid_defpreset_t *defpreset); +const char *fluid_defpreset_get_name(fluid_defpreset_t *defpreset); +int fluid_defpreset_noteon(fluid_defpreset_t *defpreset, fluid_synth_t *synth, int chan, int key, int vel); + +/* + * fluid_preset_zone + */ +struct _fluid_preset_zone_t +{ + fluid_preset_zone_t *next; + char *name; + fluid_inst_t *inst; + fluid_list_t *voice_zone; + fluid_zone_range_t range; + fluid_gen_t gen[GEN_LAST]; + fluid_mod_t *mod; /* List of modulators */ +}; + +fluid_preset_zone_t *new_fluid_preset_zone(char *name); +void delete_fluid_list_mod(fluid_mod_t *mod); +void delete_fluid_preset_zone(fluid_preset_zone_t *zone); +fluid_preset_zone_t *fluid_preset_zone_next(fluid_preset_zone_t *zone); +int fluid_preset_zone_import_sfont(fluid_preset_zone_t *zone, fluid_preset_zone_t *global_zone, SFZone *sfzone, fluid_defsfont_t *defssfont, SFData *sfdata); +fluid_inst_t *fluid_preset_zone_get_inst(fluid_preset_zone_t *zone); + +/* + * fluid_inst_t + */ +struct _fluid_inst_t +{ + char name[21]; + int source_idx; /* Index of instrument in source Soundfont */ + fluid_inst_zone_t *global_zone; + fluid_inst_zone_t *zone; +}; + +fluid_inst_t *new_fluid_inst(void); +fluid_inst_t *fluid_inst_import_sfont(int inst_idx, fluid_defsfont_t *defsfont, SFData *sfdata); +void delete_fluid_inst(fluid_inst_t *inst); +int fluid_inst_set_global_zone(fluid_inst_t *inst, fluid_inst_zone_t *zone); +int fluid_inst_add_zone(fluid_inst_t *inst, fluid_inst_zone_t *zone); +fluid_inst_zone_t *fluid_inst_get_zone(fluid_inst_t *inst); +fluid_inst_zone_t *fluid_inst_get_global_zone(fluid_inst_t *inst); + +/* + * fluid_inst_zone_t + */ +struct _fluid_inst_zone_t +{ + fluid_inst_zone_t *next; + char *name; + fluid_sample_t *sample; + fluid_zone_range_t range; + fluid_gen_t gen[GEN_LAST]; + fluid_mod_t *mod; /* List of modulators */ +}; + + +fluid_inst_zone_t *new_fluid_inst_zone(char *name); +void delete_fluid_inst_zone(fluid_inst_zone_t *zone); +fluid_inst_zone_t *fluid_inst_zone_next(fluid_inst_zone_t *zone); +int fluid_inst_zone_import_sfont(fluid_inst_zone_t *inst_zone, fluid_inst_zone_t *global_inst_zone, SFZone *sfzone, fluid_defsfont_t *defsfont, SFData *sfdata); +fluid_sample_t *fluid_inst_zone_get_sample(fluid_inst_zone_t *zone); + + +int fluid_sample_import_sfont(fluid_sample_t *sample, SFSample *sfsample, fluid_defsfont_t *defsfont); +int fluid_sample_in_rom(fluid_sample_t *sample); + + +#endif /* _FLUID_SFONT_H */ diff --git a/libs/fluidsynth/src/sfloader/fluid_instpatch.h b/libs/fluidsynth/src/sfloader/fluid_instpatch.h new file mode 100644 index 00000000000..c1838750ab7 --- /dev/null +++ b/libs/fluidsynth/src/sfloader/fluid_instpatch.h @@ -0,0 +1,14 @@ + +#ifndef _FLUID_INSTPATCH_H +#define _FLUID_INSTPATCH_H + +#include "fluid_sfont.h" +#include "fluid_settings.h" + +void fluid_instpatch_init(void); +void fluid_instpatch_deinit(void); +fluid_sfloader_t *new_fluid_instpatch_loader(fluid_settings_t *settings); + +int fluid_instpatch_supports_multi_init(void); + +#endif // _FLUID_INSTPATCH_H diff --git a/libs/fluidsynth/src/sfloader/fluid_samplecache.c b/libs/fluidsynth/src/sfloader/fluid_samplecache.c new file mode 100644 index 00000000000..64e9e9e7091 --- /dev/null +++ b/libs/fluidsynth/src/sfloader/fluid_samplecache.c @@ -0,0 +1,313 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * SoundFont file loading code borrowed from Smurf SoundFont Editor + * Copyright (C) 1999-2001 Josh Green + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +/* CACHED SAMPLE DATA LOADER + * + * This is a wrapper around fluid_sffile_read_sample_data that attempts to cache the read + * data across all FluidSynth instances in a global (process-wide) list. + */ + +#include "fluid_samplecache.h" +#include "fluid_sys.h" +#include "fluid_list.h" + + +typedef struct _fluid_samplecache_entry_t fluid_samplecache_entry_t; + +struct _fluid_samplecache_entry_t +{ + /* The following members all form the cache key */ + char *filename; + time_t modification_time; + unsigned int sf_samplepos; + unsigned int sf_samplesize; + unsigned int sf_sample24pos; + unsigned int sf_sample24size; + unsigned int sample_start; + unsigned int sample_end; + int sample_type; + /* End of cache key members */ + + short *sample_data; + char *sample_data24; + int sample_count; + + int num_references; + int mlocked; +}; + +static fluid_list_t *samplecache_list = NULL; +static fluid_mutex_t samplecache_mutex = FLUID_MUTEX_INIT; + +static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf, unsigned int sample_start, + unsigned int sample_end, int sample_type, time_t mtime); +static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf, unsigned int sample_start, + unsigned int sample_end, int sample_type, time_t mtime); +static void delete_samplecache_entry(fluid_samplecache_entry_t *entry); + +static int fluid_get_file_modification_time(char *filename, time_t *modification_time); + + +/* PUBLIC INTERFACE */ + +int fluid_samplecache_load(SFData *sf, + unsigned int sample_start, unsigned int sample_end, int sample_type, + int try_mlock, short **sample_data, char **sample_data24) +{ + fluid_samplecache_entry_t *entry; + int ret; + time_t mtime; + + fluid_mutex_lock(samplecache_mutex); + + if(fluid_get_file_modification_time(sf->fname, &mtime) == FLUID_FAILED) + { + mtime = 0; + } + + entry = get_samplecache_entry(sf, sample_start, sample_end, sample_type, mtime); + + if(entry == NULL) + { + fluid_mutex_unlock(samplecache_mutex); + entry = new_samplecache_entry(sf, sample_start, sample_end, sample_type, mtime); + + if(entry == NULL) + { + ret = -1; + goto unlock_exit; + } + + fluid_mutex_lock(samplecache_mutex); + samplecache_list = fluid_list_prepend(samplecache_list, entry); + } + fluid_mutex_unlock(samplecache_mutex); + + if(try_mlock && !entry->mlocked) + { + /* Lock the memory to disable paging. It's okay if this fails. It + * probably means that the user doesn't have the required permission. */ + if(fluid_mlock(entry->sample_data, entry->sample_count * sizeof(short)) == 0) + { + if(entry->sample_data24 != NULL) + { + entry->mlocked = (fluid_mlock(entry->sample_data24, entry->sample_count) == 0); + } + else + { + entry->mlocked = TRUE; + } + + if(!entry->mlocked) + { + fluid_munlock(entry->sample_data, entry->sample_count * sizeof(short)); + FLUID_LOG(FLUID_WARN, "Failed to pin the sample data to RAM; swapping is possible."); + } + } + } + + entry->num_references++; + *sample_data = entry->sample_data; + *sample_data24 = entry->sample_data24; + ret = entry->sample_count; + +unlock_exit: + return ret; +} + +int fluid_samplecache_unload(const short *sample_data) +{ + fluid_list_t *entry_list; + fluid_samplecache_entry_t *entry; + int ret; + + fluid_mutex_lock(samplecache_mutex); + + entry_list = samplecache_list; + + while(entry_list) + { + entry = (fluid_samplecache_entry_t *)fluid_list_get(entry_list); + + if(sample_data == entry->sample_data) + { + entry->num_references--; + + if(entry->num_references == 0) + { + if(entry->mlocked) + { + fluid_munlock(entry->sample_data, entry->sample_count * sizeof(short)); + + if(entry->sample_data24 != NULL) + { + fluid_munlock(entry->sample_data24, entry->sample_count); + } + } + + samplecache_list = fluid_list_remove(samplecache_list, entry); + delete_samplecache_entry(entry); + } + + ret = FLUID_OK; + goto unlock_exit; + } + + entry_list = fluid_list_next(entry_list); + } + + FLUID_LOG(FLUID_ERR, "Trying to free sample data not found in cache."); + ret = FLUID_FAILED; + +unlock_exit: + fluid_mutex_unlock(samplecache_mutex); + return ret; +} + + +/* Private functions */ +static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf, + unsigned int sample_start, + unsigned int sample_end, + int sample_type, + time_t mtime) +{ + fluid_samplecache_entry_t *entry; + + entry = FLUID_NEW(fluid_samplecache_entry_t); + + if(entry == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + FLUID_MEMSET(entry, 0, sizeof(*entry)); + + entry->filename = FLUID_STRDUP(sf->fname); + + if(entry->filename == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + goto error_exit; + } + + entry->sf_samplepos = sf->samplepos; + entry->sf_samplesize = sf->samplesize; + entry->sf_sample24pos = sf->sample24pos; + entry->sf_sample24size = sf->sample24size; + entry->sample_start = sample_start; + entry->sample_end = sample_end; + entry->sample_type = sample_type; + entry->modification_time = mtime; + + entry->sample_count = fluid_sffile_read_sample_data(sf, sample_start, sample_end, sample_type, + &entry->sample_data, &entry->sample_data24); + + if(entry->sample_count < 0) + { + goto error_exit; + } + + return entry; + +error_exit: + delete_samplecache_entry(entry); + return NULL; +} + +static void delete_samplecache_entry(fluid_samplecache_entry_t *entry) +{ + fluid_return_if_fail(entry != NULL); + + FLUID_FREE(entry->filename); + FLUID_FREE(entry->sample_data); + FLUID_FREE(entry->sample_data24); + FLUID_FREE(entry); +} + +static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf, + unsigned int sample_start, + unsigned int sample_end, + int sample_type, + time_t mtime) +{ + fluid_list_t *entry_list; + fluid_samplecache_entry_t *entry; + + entry_list = samplecache_list; + + while(entry_list) + { + entry = (fluid_samplecache_entry_t *)fluid_list_get(entry_list); + + if((FLUID_STRCMP(sf->fname, entry->filename) == 0) && + (mtime == entry->modification_time) && + (sf->samplepos == entry->sf_samplepos) && + (sf->samplesize == entry->sf_samplesize) && + (sf->sample24pos == entry->sf_sample24pos) && + (sf->sample24size == entry->sf_sample24size) && + (sample_start == entry->sample_start) && + (sample_end == entry->sample_end) && + (sample_type == entry->sample_type)) + { + return entry; + } + + entry_list = fluid_list_next(entry_list); + } + + return NULL; +} + +static int fluid_get_file_modification_time(char *filename, time_t *modification_time) +{ + fluid_stat_buf_t buf; + + if(fluid_stat(filename, &buf)) + { + return FLUID_FAILED; + } + + *modification_time = buf.st_mtime; + return FLUID_OK; +} + + +/* Only used for tests */ +int fluid_samplecache_count_entries(void) +{ + fluid_list_t *entry; + int count = 0; + + fluid_mutex_lock(samplecache_mutex); + + for(entry = samplecache_list; entry != NULL; entry = fluid_list_next(entry)) + { + count++; + } + + fluid_mutex_unlock(samplecache_mutex); + + return count; +} diff --git a/libs/fluidsynth/src/sfloader/fluid_samplecache.h b/libs/fluidsynth/src/sfloader/fluid_samplecache.h new file mode 100644 index 00000000000..de6206ba7de --- /dev/null +++ b/libs/fluidsynth/src/sfloader/fluid_samplecache.h @@ -0,0 +1,37 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#ifndef _FLUID_SAMPLECACHE_H +#define _FLUID_SAMPLECACHE_H + +#include "fluid_sfont.h" +#include "fluid_sffile.h" + +int fluid_samplecache_load(SFData *sf, + unsigned int sample_start, unsigned int sample_end, int sample_type, + int try_mlock, short **data, char **data24); + +int fluid_samplecache_unload(const short *sample_data); + +/* Only used for tests */ +int fluid_samplecache_count_entries(void); + +#endif /* _FLUID_SAMPLECACHE_H */ diff --git a/libs/fluidsynth/src/sfloader/fluid_sffile.c b/libs/fluidsynth/src/sfloader/fluid_sffile.c new file mode 100644 index 00000000000..96d06ceae6c --- /dev/null +++ b/libs/fluidsynth/src/sfloader/fluid_sffile.c @@ -0,0 +1,2527 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * SoundFont file loading code borrowed from Smurf SoundFont Editor + * Copyright (C) 1999-2001 Josh Green + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#include "fluid_sffile.h" +#include "fluid_sfont.h" +#include "fluid_sys.h" + +#if LIBSNDFILE_SUPPORT +#include +#endif + +#if LIBINSTPATCH_SUPPORT +#include +#endif + +/*=================================sfload.c======================== + Borrowed from Smurf SoundFont Editor by Josh Green + =================================================================*/ + +/* FOURCC definitions */ +#define RIFF_FCC FLUID_FOURCC('R','I','F','F') +#define LIST_FCC FLUID_FOURCC('L','I','S','T') +#define SFBK_FCC FLUID_FOURCC('s','f','b','k') +#define INFO_FCC FLUID_FOURCC('I','N','F','O') +#define SDTA_FCC FLUID_FOURCC('s','d','t','a') +#define PDTA_FCC FLUID_FOURCC('p','d','t','a') /* info/sample/preset */ + +#define IFIL_FCC FLUID_FOURCC('i','f','i','l') +#define ISNG_FCC FLUID_FOURCC('i','s','n','g') +#define INAM_FCC FLUID_FOURCC('I','N','A','M') +#define IROM_FCC FLUID_FOURCC('i','r','o','m') /* info ids (1st byte of info strings) */ +#define IVER_FCC FLUID_FOURCC('i','v','e','r') +#define ICRD_FCC FLUID_FOURCC('I','C','R','D') +#define IENG_FCC FLUID_FOURCC('I','E','N','G') +#define IPRD_FCC FLUID_FOURCC('I','P','R','D') /* more info ids */ +#define ICOP_FCC FLUID_FOURCC('I','C','O','P') +#define ICMT_FCC FLUID_FOURCC('I','C','M','T') +#define ISFT_FCC FLUID_FOURCC('I','S','F','T') /* and yet more info ids */ + +#define SNAM_FCC FLUID_FOURCC('s','n','a','m') +#define SMPL_FCC FLUID_FOURCC('s','m','p','l') /* sample ids */ +#define PHDR_FCC FLUID_FOURCC('p','h','d','r') +#define PBAG_FCC FLUID_FOURCC('p','b','a','g') +#define PMOD_FCC FLUID_FOURCC('p','m','o','d') +#define PGEN_FCC FLUID_FOURCC('p','g','e','n') /* preset ids */ +#define IHDR_FCC FLUID_FOURCC('i','n','s','t') +#define IBAG_FCC FLUID_FOURCC('i','b','a','g') +#define IMOD_FCC FLUID_FOURCC('i','m','o','d') +#define IGEN_FCC FLUID_FOURCC('i','g','e','n') /* instrument ids */ +#define SHDR_FCC FLUID_FOURCC('s','h','d','r') /* sample info */ +#define SM24_FCC FLUID_FOURCC('s','m','2','4') + +/* Set when the FCC code is unknown */ +#define UNKN_ID FLUID_N_ELEMENTS(idlist) + +/* + * This declares a uint32_t array containing the SF2 chunk identifiers. + */ +static const uint32_t idlist[] = +{ + RIFF_FCC, + LIST_FCC, + SFBK_FCC, + INFO_FCC, + SDTA_FCC, + PDTA_FCC, + + IFIL_FCC, + ISNG_FCC, + INAM_FCC, + IROM_FCC, + IVER_FCC, + ICRD_FCC, + IENG_FCC, + IPRD_FCC, + ICOP_FCC, + ICMT_FCC, + ISFT_FCC, + + SNAM_FCC, + SMPL_FCC, + PHDR_FCC, + PBAG_FCC, + PMOD_FCC, + PGEN_FCC, + IHDR_FCC, + IBAG_FCC, + IMOD_FCC, + IGEN_FCC, + SHDR_FCC, + SM24_FCC +}; + +static const unsigned short invalid_inst_gen[] = +{ + GEN_UNUSED1, + GEN_UNUSED2, + GEN_UNUSED3, + GEN_UNUSED4, + GEN_RESERVED1, + GEN_RESERVED2, + GEN_RESERVED3, + GEN_INSTRUMENT, +}; + +static const unsigned short invalid_preset_gen[] = +{ + GEN_STARTADDROFS, + GEN_ENDADDROFS, + GEN_STARTLOOPADDROFS, + GEN_ENDLOOPADDROFS, + GEN_STARTADDRCOARSEOFS, + GEN_ENDADDRCOARSEOFS, + GEN_STARTLOOPADDRCOARSEOFS, + GEN_KEYNUM, + GEN_VELOCITY, + GEN_ENDLOOPADDRCOARSEOFS, + GEN_SAMPLEMODE, + GEN_EXCLUSIVECLASS, + GEN_OVERRIDEROOTKEY, + GEN_SAMPLEID, +}; + + +/* sfont file chunk sizes */ +#define SF_PHDR_SIZE (38) +#define SF_BAG_SIZE (4) +#define SF_MOD_SIZE (10) +#define SF_GEN_SIZE (4) +#define SF_IHDR_SIZE (22) +#define SF_SHDR_SIZE (46) + + +#define READCHUNK(sf, var) \ + do \ + { \ + if (sf->fcbs->fread(var, 8, sf->sffd) == FLUID_FAILED) \ + return FALSE; \ + ((SFChunk *)(var))->size = FLUID_LE32TOH(((SFChunk *)(var))->size); \ + } while (0) + +#define READD(sf, var) \ + do \ + { \ + uint32_t _temp; \ + if (sf->fcbs->fread(&_temp, 4, sf->sffd) == FLUID_FAILED) \ + return FALSE; \ + var = FLUID_LE32TOH(_temp); \ + } while (0) + +#define READW(sf, var) \ + do \ + { \ + uint16_t _temp; \ + if (sf->fcbs->fread(&_temp, 2, sf->sffd) == FLUID_FAILED) \ + return FALSE; \ + var = FLUID_LE16TOH(_temp); \ + } while (0) + +#define READID(sf, var) \ + do \ + { \ + if (sf->fcbs->fread(var, 4, sf->sffd) == FLUID_FAILED) \ + return FALSE; \ + } while (0) + +#define READSTR(sf, var) \ + do \ + { \ + if (sf->fcbs->fread(var, 20, sf->sffd) == FLUID_FAILED) \ + return FALSE; \ + (*var)[20] = '\0'; \ + } while (0) + +#define READB(sf, var) \ + do \ + { \ + if (sf->fcbs->fread(&var, 1, sf->sffd) == FLUID_FAILED) \ + return FALSE; \ + } while (0) + +#define FSKIP(sf, size) \ + do \ + { \ + if (sf->fcbs->fseek(sf->sffd, size, SEEK_CUR) == FLUID_FAILED) \ + return FALSE; \ + } while (0) + +#define FSKIPW(sf) \ + do \ + { \ + if (sf->fcbs->fseek(sf->sffd, 2, SEEK_CUR) == FLUID_FAILED) \ + return FALSE; \ + } while (0) + +/* removes and advances a fluid_list_t pointer */ +#define SLADVREM(list, item) \ + do \ + { \ + fluid_list_t *_temp = item; \ + item = fluid_list_next(item); \ + list = fluid_list_remove_link(list, _temp); \ + delete1_fluid_list(_temp); \ + } while (0) + + +static int load_header(SFData *sf); +static int load_body(SFData *sf); +static int process_info(SFData *sf, int size); +static int process_sdta(SFData *sf, unsigned int size); +static int process_pdta(SFData *sf, int size); +static int load_phdr(SFData *sf, unsigned int size); +static int load_pbag(SFData *sf, int size); +static int load_pmod(SFData *sf, int size); +static int load_ihdr(SFData *sf, unsigned int size); +static int load_ibag(SFData *sf, int size); +static int load_imod(SFData *sf, int size); +static int load_shdr(SFData *sf, unsigned int size); + +static int chunkid(uint32_t id); +static int read_listchunk(SFData *sf, SFChunk *chunk); +static int pdtahelper(SFData *sf, unsigned int expid, unsigned int reclen, SFChunk *chunk, int *size); +static int preset_compare_func(const void *a, const void *b); +static fluid_list_t *find_gen_by_id(int gen, fluid_list_t *genlist); +static int valid_inst_genid(unsigned short genid); +static int valid_preset_genid(unsigned short genid); + +static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data); +static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int end, short **data, char **data24); + +/** + * Check if a file is a SoundFont file. + * + * @param filename Path to the file to check + * @return TRUE if it could be a SF2, SF3 or DLS file, FALSE otherwise + * + * If fluidsynth was built with DLS support, this function will also identify DLS files. + * + * @note This function only checks whether header(s) in the RIFF chunk are present. + * A call to fluid_synth_sfload() might still fail. + */ +int fluid_is_soundfont(const char *filename) +{ + FILE *fp; + uint32_t fcc; + int retcode = FALSE; + const char* err_msg; + + do + { + if((fp = fluid_file_open(filename, &err_msg)) == NULL) + { + FLUID_LOG(FLUID_ERR, "fluid_is_soundfont(): fopen() failed: '%s'", err_msg); + return retcode; + } + + if(FLUID_FREAD(&fcc, sizeof(fcc), 1, fp) != 1) + { + FLUID_LOG(FLUID_ERR, "fluid_is_soundfont(): failed to read RIFF chunk id."); + break; + } + + if(fcc != RIFF_FCC) + { + FLUID_LOG(FLUID_ERR, "fluid_is_soundfont(): expected RIFF chunk id '0x%04X' but got '0x%04X'.", (unsigned int) RIFF_FCC, (unsigned int)fcc); + break; + } + + if(FLUID_FSEEK(fp, 4, SEEK_CUR)) + { + FLUID_LOG(FLUID_ERR, "fluid_is_soundfont(): cannot seek +4 bytes."); + break; + } + + if(FLUID_FREAD(&fcc, sizeof(fcc), 1, fp) != 1) + { + FLUID_LOG(FLUID_ERR, "fluid_is_soundfont(): failed to read SFBK chunk id."); + break; + } + + retcode = (fcc == SFBK_FCC); + if(retcode) + { + break; // seems to be SF2, stop here + } +#ifdef LIBINSTPATCH_SUPPORT + else + { + IpatchFileHandle *fhandle = ipatch_file_identify_open(filename, NULL); + if(fhandle != NULL) + { + retcode = (ipatch_file_identify(fhandle->file, NULL) == IPATCH_TYPE_DLS_FILE); + ipatch_file_close(fhandle); + } + } +#endif + } + while(0); + + FLUID_FCLOSE(fp); + + return retcode; +} + +/* + * Open a SoundFont file and parse it's contents into a SFData structure. + * + * @param fname filename + * @param fcbs file callback structure + * @return the partially parsed SoundFont as SFData structure or NULL on error + */ +SFData *fluid_sffile_open(const char *fname, const fluid_file_callbacks_t *fcbs) +{ + SFData *sf; + fluid_long_long_t fsize = 0; + + if(!(sf = FLUID_NEW(SFData))) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + FLUID_MEMSET(sf, 0, sizeof(SFData)); + + fluid_rec_mutex_init(sf->mtx); + sf->fcbs = fcbs; + + if((sf->sffd = fcbs->fopen(fname)) == NULL) + { + FLUID_LOG(FLUID_ERR, "Unable to open file '%s'", fname); + goto error_exit; + } + + sf->fname = FLUID_STRDUP(fname); + + if(sf->fname == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + goto error_exit; + } + + /* get size of file by seeking to end */ + if(fcbs->fseek(sf->sffd, 0L, SEEK_END) == FLUID_FAILED) + { + FLUID_LOG(FLUID_ERR, "Seek to end of file failed"); + goto error_exit; + } + + if((fsize = fcbs->ftell(sf->sffd)) == FLUID_FAILED) + { + FLUID_LOG(FLUID_ERR, "Get end of file position failed"); + goto error_exit; + } + + sf->filesize = fsize; + + if(fcbs->fseek(sf->sffd, 0, SEEK_SET) == FLUID_FAILED) + { + FLUID_LOG(FLUID_ERR, "Rewind to start of file failed"); + goto error_exit; + } + + if(!load_header(sf)) + { + goto error_exit; + } + + return sf; + +error_exit: + fluid_sffile_close(sf); + return NULL; +} + +/* + * Parse all preset information from the soundfont + * + * @return FLUID_OK on success, otherwise FLUID_FAILED + */ +int fluid_sffile_parse_presets(SFData *sf) +{ + if(!load_body(sf)) + { + return FLUID_FAILED; + } + + return FLUID_OK; +} + +/* Load sample data from the soundfont file + * + * This function will always return the sample data in WAV format. If the sample_type specifies an + * Ogg Vorbis compressed sample, it will be decompressed automatically before returning. + * + * @param sf SFData instance + * @param sample_start index of first sample point in Soundfont sample chunk + * @param sample_end index of last sample point in Soundfont sample chunk + * @param sample_type type of the sample in Soundfont + * @param data pointer to sample data pointer, will point to loaded sample data on success + * @param data24 pointer to 24-bit sample data pointer if 24-bit data present, will point to loaded + * 24-bit sample data on success or NULL if no 24-bit data is present in file + * + * @return The number of sample words in returned buffers or -1 on failure + */ +int fluid_sffile_read_sample_data(SFData *sf, unsigned int sample_start, unsigned int sample_end, + int sample_type, short **data, char **data24) +{ + int num_samples; + + if(sample_type & FLUID_SAMPLETYPE_OGG_VORBIS) + { + num_samples = fluid_sffile_read_vorbis(sf, sample_start, sample_end, data); + } + else + { + num_samples = fluid_sffile_read_wav(sf, sample_start, sample_end, data, data24); + } + + return num_samples; +} + +/* + * Close a SoundFont file and free the SFData structure. + * + * @param sf pointer to SFData structure + * @param fcbs file callback structure + */ +void fluid_sffile_close(SFData *sf) +{ + fluid_list_t *entry; + SFPreset *preset; + SFInst *inst; + + fluid_rec_mutex_destroy(sf->mtx); + if(sf->sffd) + { + sf->fcbs->fclose(sf->sffd); + } + + FLUID_FREE(sf->fname); + + entry = sf->info; + + while(entry) + { + FLUID_FREE(fluid_list_get(entry)); + entry = fluid_list_next(entry); + } + + delete_fluid_list(sf->info); + + entry = sf->preset; + + while(entry) + { + preset = (SFPreset *)fluid_list_get(entry); + delete_preset(preset); + entry = fluid_list_next(entry); + } + + delete_fluid_list(sf->preset); + + entry = sf->inst; + + while(entry) + { + inst = (SFInst *)fluid_list_get(entry); + delete_inst(inst); + entry = fluid_list_next(entry); + } + + delete_fluid_list(sf->inst); + + entry = sf->sample; + + while(entry) + { + FLUID_FREE(fluid_list_get(entry)); + entry = fluid_list_next(entry); + } + + delete_fluid_list(sf->sample); + + FLUID_FREE(sf); +} + + +/* + * Private functions + */ + +/* sound font file load functions */ +static int chunkid(uint32_t id) +{ + unsigned int i; + + for(i = 0; i < FLUID_N_ELEMENTS(idlist); i++) + { + if(idlist[i] == id) + { + break; + } + } + + /* Return chunk id or UNKN_ID if not found */ + return i; +} + +static int load_header(SFData *sf) +{ + SFChunk chunk; + + READCHUNK(sf, &chunk); /* load RIFF chunk */ + + if(chunk.id != RIFF_FCC) + { + /* error if not RIFF */ + FLUID_LOG(FLUID_ERR, "Not a RIFF file"); + return FALSE; + } + + READID(sf, &chunk.id); /* load file ID */ + + if(chunk.id != SFBK_FCC) + { + /* error if not SFBK_ID */ + FLUID_LOG(FLUID_ERR, "Not a SoundFont file"); + return FALSE; + } + + if(chunk.size != sf->filesize - 8) + { + FLUID_LOG(FLUID_ERR, "SoundFont file size mismatch"); + return FALSE; + } + + /* Process INFO block */ + if(!read_listchunk(sf, &chunk)) + { + return FALSE; + } + + if(chunk.id != INFO_FCC) + { + FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting INFO chunk"); + return FALSE; + } + + if(!process_info(sf, chunk.size)) + { + return FALSE; + } + + /* Process sample chunk */ + if(!read_listchunk(sf, &chunk)) + { + return FALSE; + } + + if(chunk.id != SDTA_FCC) + { + FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting SAMPLE chunk"); + return FALSE; + } + + if(!process_sdta(sf, chunk.size)) + { + return FALSE; + } + + /* process HYDRA chunk */ + if(!read_listchunk(sf, &chunk)) + { + return FALSE; + } + + if(chunk.id != PDTA_FCC) + { + FLUID_LOG(FLUID_ERR, "Invalid ID found when expecting HYDRA chunk"); + return FALSE; + } + + sf->hydrapos = sf->fcbs->ftell(sf->sffd); + sf->hydrasize = chunk.size; + + return TRUE; +} + +static int load_body(SFData *sf) +{ + if(sf->fcbs->fseek(sf->sffd, sf->hydrapos, SEEK_SET) == FLUID_FAILED) + { + FLUID_LOG(FLUID_ERR, "Failed to seek to HYDRA position"); + return FALSE; + } + + if(!process_pdta(sf, sf->hydrasize)) + { + return FALSE; + } + + /* sort preset list by bank, preset # */ + sf->preset = fluid_list_sort(sf->preset, preset_compare_func); + + return TRUE; +} + +static int read_listchunk(SFData *sf, SFChunk *chunk) +{ + READCHUNK(sf, chunk); /* read list chunk */ + + if(chunk->id != LIST_FCC) /* error if ! list chunk */ + { + FLUID_LOG(FLUID_ERR, "Invalid chunk id in level 0 parse"); + return FALSE; + } + + READID(sf, &chunk->id); /* read id string */ + chunk->size -= 4; + return TRUE; +} + +static int process_info(SFData *sf, int size) +{ + SFChunk chunk; + union + { + char *chr; + uint32_t *fcc; + } item; + unsigned short ver; + + while(size > 0) + { + READCHUNK(sf, &chunk); + size -= 8; + + if(chunk.id == IFIL_FCC) + { + /* sound font version chunk? */ + if(chunk.size != 4) + { + FLUID_LOG(FLUID_ERR, "Sound font version info chunk has invalid size"); + return FALSE; + } + + READW(sf, ver); + sf->version.major = ver; + READW(sf, ver); + sf->version.minor = ver; + + if(sf->version.major < 2) + { + FLUID_LOG(FLUID_ERR, "Sound font version is %d.%d which is not" + " supported, convert to version 2.0x", + sf->version.major, sf->version.minor); + return FALSE; + } + + if(sf->version.major == 3) + { +#if !LIBSNDFILE_SUPPORT + FLUID_LOG(FLUID_WARN, + "Sound font version is %d.%d but fluidsynth was compiled without" + " support for (v3.x)", + sf->version.major, sf->version.minor); + return FALSE; +#endif + } + else if(sf->version.major > 2) + { + FLUID_LOG(FLUID_WARN, + "Sound font version is %d.%d which is newer than" + " what this version of fluidsynth was designed for (v2.0x)", + sf->version.major, sf->version.minor); + return FALSE; + } + } + else if(chunk.id == IVER_FCC) + { + /* ROM version chunk? */ + if(chunk.size != 4) + { + FLUID_LOG(FLUID_ERR, "ROM version info chunk has invalid size"); + return FALSE; + } + + READW(sf, ver); + sf->romver.major = ver; + READW(sf, ver); + sf->romver.minor = ver; + } + else if(chunkid(chunk.id) != UNKN_ID) + { + if((chunk.id != ICMT_FCC && chunk.size > 256) || (chunk.size > 65536) || (chunk.size % 2)) + { + FLUID_LOG(FLUID_ERR, "INFO sub chunk %.4s has invalid chunk size of %d bytes", + (char*)&chunk.id, chunk.size); + return FALSE; + } + + /* alloc for chunk fcc and da chunk */ + if(!(item.fcc = FLUID_MALLOC(chunk.size + sizeof(uint32_t) + 1))) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FALSE; + } + + /* attach to INFO list, fluid_sffile_close will cleanup if FAIL occurs */ + sf->info = fluid_list_append(sf->info, item.fcc); + + /* save chunk fcc and update pointer to data value */ + *item.fcc++ = chunk.id; + + if(sf->fcbs->fread(item.chr, chunk.size, sf->sffd) == FLUID_FAILED) + { + return FALSE; + } + + /* force terminate info item */ + item.chr[chunk.size] = '\0'; + } + else + { + FLUID_LOG(FLUID_ERR, "Invalid chunk id in INFO chunk"); + return FALSE; + } + + size -= chunk.size; + } + + if(size < 0) + { + FLUID_LOG(FLUID_ERR, "INFO chunk size mismatch"); + return FALSE; + } + + return TRUE; +} + +static int process_sdta(SFData *sf, unsigned int size) +{ + SFChunk chunk; + + if(size == 0) + { + return TRUE; /* no sample data? */ + } + + /* read sub chunk */ + READCHUNK(sf, &chunk); + size -= 8; + + if(chunk.id != SMPL_FCC) + { + FLUID_LOG(FLUID_ERR, "Expected SMPL chunk found invalid id instead"); + return FALSE; + } + + /* SDTA chunk may also contain sm24 chunk for 24 bit samples + * (not yet supported), only an error if SMPL chunk size is + * greater than SDTA. */ + if(chunk.size > size) + { + FLUID_LOG(FLUID_ERR, "SDTA chunk size mismatch"); + return FALSE; + } + + /* sample data follows */ + sf->samplepos = sf->fcbs->ftell(sf->sffd); + + /* used to check validity of sample headers */ + sf->samplesize = chunk.size; + + FSKIP(sf, chunk.size); + size -= chunk.size; + + if(sf->version.major >= 2 && sf->version.minor >= 4) + { + /* any chance to find another chunk here? */ + if(size > 8) + { + /* read sub chunk */ + READCHUNK(sf, &chunk); + size -= 8; + + if(chunk.id == SM24_FCC) + { + int sm24size, sdtahalfsize; + + FLUID_LOG(FLUID_DBG, "Found SM24 chunk"); + + if(chunk.size > size) + { + FLUID_LOG(FLUID_WARN, "SM24 exceeds SDTA chunk, ignoring SM24"); + goto ret; // no error + } + + sdtahalfsize = sf->samplesize / 2; + /* + 1 byte in the case that half the size of smpl chunk is an odd value */ + sdtahalfsize += sdtahalfsize % 2; + sm24size = chunk.size; + + if(sdtahalfsize != sm24size) + { + FLUID_LOG(FLUID_WARN, "SM24 not equal to half the size of SMPL chunk (0x%X != " + "0x%X), ignoring SM24", + sm24size, sdtahalfsize); + goto ret; // no error + } + + /* sample data24 follows */ + sf->sample24pos = sf->fcbs->ftell(sf->sffd); + sf->sample24size = sm24size; + } + } + } + +ret: + FSKIP(sf, size); + + return TRUE; +} + +static int pdtahelper(SFData *sf, unsigned int expid, unsigned int reclen, SFChunk *chunk, int *size) +{ + READCHUNK(sf, chunk); + *size -= 8; + + if(chunk->id != expid) + { + FLUID_LOG(FLUID_ERR, "Expected PDTA sub-chunk '%.4s' found invalid id instead", (char*)&expid); + return FALSE; + } + + if(chunk->size % reclen) /* valid chunk size? */ + { + FLUID_LOG(FLUID_ERR, "'%.4s' chunk size is not a multiple of %d bytes", (char*)&expid, reclen); + return FALSE; + } + + if((*size -= chunk->size) < 0) + { + FLUID_LOG(FLUID_ERR, "'%.4s' chunk size exceeds remaining PDTA chunk size", (char*)&expid); + return FALSE; + } + + return TRUE; +} + +static int process_pdta(SFData *sf, int size) +{ + SFChunk chunk; + + if(!pdtahelper(sf, PHDR_FCC, SF_PHDR_SIZE, &chunk, &size)) + { + return FALSE; + } + + if(!load_phdr(sf, chunk.size)) + { + return FALSE; + } + + if(!pdtahelper(sf, PBAG_FCC, SF_BAG_SIZE, &chunk, &size)) + { + return FALSE; + } + + if(!load_pbag(sf, chunk.size)) + { + return FALSE; + } + + if(!pdtahelper(sf, PMOD_FCC, SF_MOD_SIZE, &chunk, &size)) + { + return FALSE; + } + + if(!load_pmod(sf, chunk.size)) + { + return FALSE; + } + + if(!pdtahelper(sf, PGEN_FCC, SF_GEN_SIZE, &chunk, &size)) + { + return FALSE; + } + + if(!load_pgen(sf, chunk.size)) + { + return FALSE; + } + + if(!pdtahelper(sf, IHDR_FCC, SF_IHDR_SIZE, &chunk, &size)) + { + return FALSE; + } + + if(!load_ihdr(sf, chunk.size)) + { + return FALSE; + } + + if(!pdtahelper(sf, IBAG_FCC, SF_BAG_SIZE, &chunk, &size)) + { + return FALSE; + } + + if(!load_ibag(sf, chunk.size)) + { + return FALSE; + } + + if(!pdtahelper(sf, IMOD_FCC, SF_MOD_SIZE, &chunk, &size)) + { + return FALSE; + } + + if(!load_imod(sf, chunk.size)) + { + return FALSE; + } + + if(!pdtahelper(sf, IGEN_FCC, SF_GEN_SIZE, &chunk, &size)) + { + return FALSE; + } + + if(!load_igen(sf, chunk.size)) + { + return FALSE; + } + + if(!pdtahelper(sf, SHDR_FCC, SF_SHDR_SIZE, &chunk, &size)) + { + return FALSE; + } + + if(!load_shdr(sf, chunk.size)) + { + return FALSE; + } + + return TRUE; +} + +/* preset header loader */ +static int load_phdr(SFData *sf, unsigned int size) +{ + unsigned int i; + int i2; + SFPreset *preset, *prev_preset = NULL; + unsigned short pbag_idx, prev_pbag_idx = 0; + + if(size % SF_PHDR_SIZE || size == 0) + { + FLUID_LOG(FLUID_ERR, "Preset header chunk size is invalid"); + return FALSE; + } + + i = size / SF_PHDR_SIZE - 1; + + if(i == 0) + { + /* at least one preset + term record */ + FLUID_LOG(FLUID_WARN, "File contains no presets"); + FSKIP(sf, SF_PHDR_SIZE); + return TRUE; + } + + for(; i > 0; i--) + { + /* load all preset headers */ + if((preset = FLUID_NEW(SFPreset)) == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FALSE; + } + + sf->preset = fluid_list_append(sf->preset, preset); + preset->zone = NULL; /* In case of failure, fluid_sffile_close can cleanup */ + READSTR(sf, &preset->name); /* possible read failure ^ */ + READW(sf, preset->prenum); + READW(sf, preset->bank); + READW(sf, pbag_idx); + FSKIP(sf, 4); /* library ignored */ + FSKIP(sf, 4); /* genre ignored */ + FSKIP(sf, 4); /* morphology ignored */ + + if(prev_preset) + { + /* not first preset? */ + if(pbag_idx < prev_pbag_idx) + { + FLUID_LOG(FLUID_ERR, "Preset header indices not monotonic"); + return FALSE; + } + + i2 = pbag_idx - prev_pbag_idx; + + while(i2--) + { + prev_preset->zone = fluid_list_prepend(prev_preset->zone, NULL); + } + } + else if(pbag_idx > 0) /* 1st preset, warn if ofs >0 */ + { + FLUID_LOG(FLUID_WARN, "%d preset zones not referenced, discarding", pbag_idx); + } + + prev_preset = preset; /* update preset ptr */ + prev_pbag_idx = pbag_idx; + } + + FSKIP(sf, 24); + READW(sf, pbag_idx); /* Read terminal generator index */ + FSKIP(sf, 12); + + if(pbag_idx < prev_pbag_idx) + { + FLUID_LOG(FLUID_ERR, "Preset header indices not monotonic"); + return FALSE; + } + + i2 = pbag_idx - prev_pbag_idx; + + while(i2--) + { + prev_preset->zone = fluid_list_prepend(prev_preset->zone, NULL); + } + + return TRUE; +} + +/* preset bag loader */ +static int load_pbag(SFData *sf, int size) +{ + fluid_list_t *preset_list; + fluid_list_t *zone_list; + SFZone *z, *pz = NULL; + unsigned short genndx, modndx; + unsigned short pgenndx = 0, pmodndx = 0; + unsigned short i; + + if(size % SF_BAG_SIZE || size == 0) /* size is multiple of SF_BAG_SIZE? */ + { + FLUID_LOG(FLUID_ERR, "Preset bag chunk size is invalid"); + return FALSE; + } + + preset_list = sf->preset; + + /* traverse through presets */ + while(preset_list) + { + zone_list = ((SFPreset *)(preset_list->data))->zone; + + /* traverse preset's zones */ + while(zone_list) + { + if((size -= SF_BAG_SIZE) < 0) + { + FLUID_LOG(FLUID_ERR, "Preset bag chunk size mismatch"); + return FALSE; + } + + if((z = FLUID_NEW(SFZone)) == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FALSE; + } + + zone_list->data = z; + z->gen = NULL; /* Init gen and mod before possible failure, */ + z->mod = NULL; /* to ensure proper cleanup (fluid_sffile_close) */ + READW(sf, genndx); /* possible read failure ^ */ + READW(sf, modndx); + + if(pz) + { + /* if not first zone */ + if(genndx < pgenndx) + { + FLUID_LOG(FLUID_ERR, "Preset bag generator indices not monotonic"); + return FALSE; + } + + if(modndx < pmodndx) + { + FLUID_LOG(FLUID_ERR, "Preset bag modulator indices not monotonic"); + return FALSE; + } + + i = genndx - pgenndx; + + while(i--) + { + pz->gen = fluid_list_prepend(pz->gen, NULL); + } + + i = modndx - pmodndx; + + while(i--) + { + pz->mod = fluid_list_prepend(pz->mod, NULL); + } + } + + pz = z; /* update previous zone ptr */ + pgenndx = genndx; /* update previous zone gen index */ + pmodndx = modndx; /* update previous zone mod index */ + zone_list = fluid_list_next(zone_list); + } + + preset_list = fluid_list_next(preset_list); + } + + size -= SF_BAG_SIZE; + + if(size != 0) + { + FLUID_LOG(FLUID_ERR, "Preset bag chunk size mismatch"); + return FALSE; + } + + READW(sf, genndx); + READW(sf, modndx); + + if(!pz) + { + if(genndx > 0) + { + FLUID_LOG(FLUID_WARN, "No preset generators and terminal index not 0"); + } + + if(modndx > 0) + { + FLUID_LOG(FLUID_WARN, "No preset modulators and terminal index not 0"); + } + + return TRUE; + } + + if(genndx < pgenndx) + { + FLUID_LOG(FLUID_ERR, "Preset bag generator indices not monotonic"); + return FALSE; + } + + if(modndx < pmodndx) + { + FLUID_LOG(FLUID_ERR, "Preset bag modulator indices not monotonic"); + return FALSE; + } + + i = genndx - pgenndx; + + while(i--) + { + pz->gen = fluid_list_prepend(pz->gen, NULL); + } + + i = modndx - pmodndx; + + while(i--) + { + pz->mod = fluid_list_prepend(pz->mod, NULL); + } + + return TRUE; +} + +/* preset modulator loader */ +static int load_pmod(SFData *sf, int size) +{ + fluid_list_t *preset_list; + fluid_list_t *zone_list; + fluid_list_t *mod_list; + SFMod *m; + + preset_list = sf->preset; + + while(preset_list) + { + /* traverse through all presets */ + zone_list = ((SFPreset *)(preset_list->data))->zone; + + while(zone_list) + { + /* traverse this preset's zones */ + mod_list = ((SFZone *)(zone_list->data))->mod; + + while(mod_list) + { + /* load zone's modulators */ + if((size -= SF_MOD_SIZE) < 0) + { + FLUID_LOG(FLUID_ERR, "Preset modulator chunk size mismatch"); + return FALSE; + } + + if((m = FLUID_NEW(SFMod)) == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FALSE; + } + + mod_list->data = m; + READW(sf, m->src); + READW(sf, m->dest); + READW(sf, m->amount); + READW(sf, m->amtsrc); + READW(sf, m->trans); + mod_list = fluid_list_next(mod_list); + } + + zone_list = fluid_list_next(zone_list); + } + + preset_list = fluid_list_next(preset_list); + } + + /* + If there isn't even a terminal record + Hmmm, the specs say there should be one, but.. + */ + if(size == 0) + { + return TRUE; + } + + size -= SF_MOD_SIZE; + + if(size != 0) + { + FLUID_LOG(FLUID_ERR, "Preset modulator chunk size mismatch"); + return FALSE; + } + + FSKIP(sf, SF_MOD_SIZE); /* terminal mod */ + + return TRUE; +} + +/* ------------------------------------------------------------------- + * preset generator loader + * generator (per preset) loading rules: + * Zones with no generators or modulators shall be annihilated + * Global zone must be 1st zone, discard additional ones (instrumentless zones) + * + * generator (per zone) loading rules (in order of decreasing precedence): + * KeyRange is 1st in list (if exists), else discard + * if a VelRange exists only preceded by a KeyRange, else discard + * if a generator follows an instrument discard it + * if a duplicate generator exists replace previous one + * ------------------------------------------------------------------- */ +int load_pgen(SFData *sf, int size) +{ + fluid_list_t *dup; + fluid_list_t *preset_list; + fluid_list_t *zone_list; + fluid_list_t *gen_list; + SFZone *zone; + SFGen *g; + SFPreset *preset; + SFGenAmount genval; + unsigned short genid; + int level, skip, drop, discarded; + + preset_list = sf->preset; + + while(preset_list) + { + preset = fluid_list_get(preset_list); + + /* traverse through all presets */ + discarded = FALSE; + zone_list = preset->zone; + + /* traverse preset's zones */ + while(zone_list) + { + zone = fluid_list_get(zone_list); + level = 0; + gen_list = zone->gen; + + while(gen_list) + { + /* load zone's generators */ + dup = NULL; + skip = FALSE; + drop = FALSE; + + if((size -= SF_GEN_SIZE) < 0) + { + FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch"); + return FALSE; + } + + READW(sf, genid); + + if(genid == GEN_KEYRANGE) + { + /* nothing precedes */ + if(level == 0) + { + level = 1; + READB(sf, genval.range.lo); + READB(sf, genval.range.hi); + } + else + { + skip = TRUE; + } + } + else if(genid == GEN_VELRANGE) + { + /* only KeyRange precedes */ + if(level <= 1) + { + level = 2; + READB(sf, genval.range.lo); + READB(sf, genval.range.hi); + } + else + { + skip = TRUE; + } + } + else if(genid == GEN_INSTRUMENT) + { + /* inst is last gen */ + level = 3; + READW(sf, genval.uword); + } + else + { + level = 2; + + if(valid_preset_genid(genid)) + { + /* generator valid? */ + READW(sf, genval.sword); + dup = find_gen_by_id(genid, zone->gen); + } + else + { + skip = TRUE; + } + } + + if(!skip) + { + if(!dup) + { + /* if gen ! dup alloc new */ + if((g = FLUID_NEW(SFGen)) == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FALSE; + } + + gen_list->data = g; + g->id = genid; + } + else + { + g = (SFGen *)(dup->data); /* ptr to orig gen */ + drop = TRUE; + } + + g->amount = genval; + } + else + { + /* Skip this generator */ + discarded = TRUE; + drop = TRUE; + FSKIPW(sf); + } + + if(!drop) + { + gen_list = fluid_list_next(gen_list); /* next gen */ + } + else + { + SLADVREM(zone->gen, gen_list); /* drop place holder */ + } + + /* GEN_INSTRUMENT should be the last generator */ + if (level == 3) + { + break; + } + + } /* generator loop */ + + /* Anything below level 3 means it's a global zone. The global zone + * should always be the first zone in the list, so discard any + * other global zones we encounter */ + if(level < 3 && (zone_list != preset->zone)) + { + /* advance to next zone before deleting the current list element */ + zone_list = fluid_list_next(zone_list); + + FLUID_LOG(FLUID_WARN, "Preset '%s': Discarding invalid global zone", + preset->name); + preset->zone = fluid_list_remove(preset->zone, zone); + delete_zone(zone); + + /* we have already advanced the zone_list pointer, so continue with next zone */ + continue; + } + + /* All remaining generators are invalid and should be discarded + * (because they come after an instrument generator) */ + while(gen_list) + { + discarded = TRUE; + + if((size -= SF_GEN_SIZE) < 0) + { + FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch"); + return FALSE; + } + + FSKIP(sf, SF_GEN_SIZE); + SLADVREM(zone->gen, gen_list); + } + + zone_list = fluid_list_next(zone_list); + } + + if(discarded) + { + FLUID_LOG(FLUID_WARN, + "Preset '%s': Some invalid generators were discarded", + preset->name); + } + + preset_list = fluid_list_next(preset_list); + } + + /* in case there isn't a terminal record */ + if(size == 0) + { + return TRUE; + } + + size -= SF_GEN_SIZE; + + if(size != 0) + { + FLUID_LOG(FLUID_ERR, "Preset generator chunk size mismatch"); + return FALSE; + } + + FSKIP(sf, SF_GEN_SIZE); /* terminal gen */ + + return TRUE; +} + +/* instrument header loader */ +static int load_ihdr(SFData *sf, unsigned int size) +{ + unsigned int i; + int i2; + SFInst *inst, *prev_inst = NULL; /* ptr to current & previous instrument */ + unsigned short zndx, pzndx = 0; + + if(size % SF_IHDR_SIZE || size == 0) /* chunk size is valid? */ + { + FLUID_LOG(FLUID_ERR, "Instrument header has invalid size"); + return FALSE; + } + + size = size / SF_IHDR_SIZE - 1; + + if(size == 0) + { + /* at least one preset + term record */ + FLUID_LOG(FLUID_WARN, "File contains no instruments"); + FSKIP(sf, SF_IHDR_SIZE); + return TRUE; + } + + for(i = 0; i < size; i++) + { + /* load all instrument headers */ + if((inst = FLUID_NEW(SFInst)) == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FALSE; + } + + sf->inst = fluid_list_append(sf->inst, inst); + inst->zone = NULL; /* For proper cleanup if fail (fluid_sffile_close) */ + inst->idx = i; + READSTR(sf, &inst->name); /* Possible read failure ^ */ + READW(sf, zndx); + + if(prev_inst) + { + /* not first instrument? */ + if(zndx < pzndx) + { + FLUID_LOG(FLUID_ERR, "Instrument header indices not monotonic"); + return FALSE; + } + + i2 = zndx - pzndx; + + while(i2--) + { + prev_inst->zone = fluid_list_prepend(prev_inst->zone, NULL); + } + } + else if(zndx > 0) /* 1st inst, warn if ofs >0 */ + { + FLUID_LOG(FLUID_WARN, "%d instrument zones not referenced, discarding", zndx); + } + + pzndx = zndx; + prev_inst = inst; /* update instrument ptr */ + } + + FSKIP(sf, 20); + READW(sf, zndx); + + if(zndx < pzndx) + { + FLUID_LOG(FLUID_ERR, "Instrument header indices not monotonic"); + return FALSE; + } + + i2 = zndx - pzndx; + + while(i2--) + { + prev_inst->zone = fluid_list_prepend(prev_inst->zone, NULL); + } + + return TRUE; +} + +/* instrument bag loader */ +static int load_ibag(SFData *sf, int size) +{ + fluid_list_t *inst_list; + fluid_list_t *zone_list; + SFZone *z, *pz = NULL; + unsigned short genndx, modndx, pgenndx = 0, pmodndx = 0; + int i; + + if(size % SF_BAG_SIZE || size == 0) /* size is multiple of SF_BAG_SIZE? */ + { + FLUID_LOG(FLUID_ERR, "Instrument bag chunk size is invalid"); + return FALSE; + } + + inst_list = sf->inst; + + while(inst_list) + { + /* traverse through inst */ + zone_list = ((SFInst *)(inst_list->data))->zone; + + while(zone_list) + { + /* load this inst's zones */ + if((size -= SF_BAG_SIZE) < 0) + { + FLUID_LOG(FLUID_ERR, "Instrument bag chunk size mismatch"); + return FALSE; + } + + if((z = FLUID_NEW(SFZone)) == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FALSE; + } + + zone_list->data = z; + z->gen = NULL; /* In case of failure, */ + z->mod = NULL; /* fluid_sffile_close can clean up */ + READW(sf, genndx); /* READW = possible read failure */ + READW(sf, modndx); + + if(pz) + { + /* if not first zone */ + if(genndx < pgenndx) + { + FLUID_LOG(FLUID_ERR, "Instrument generator indices not monotonic"); + return FALSE; + } + + if(modndx < pmodndx) + { + FLUID_LOG(FLUID_ERR, "Instrument modulator indices not monotonic"); + return FALSE; + } + + i = genndx - pgenndx; + + while(i--) + { + pz->gen = fluid_list_prepend(pz->gen, NULL); + } + + i = modndx - pmodndx; + + while(i--) + { + pz->mod = fluid_list_prepend(pz->mod, NULL); + } + } + + pz = z; /* update previous zone ptr */ + pgenndx = genndx; + pmodndx = modndx; + zone_list = fluid_list_next(zone_list); + } + + inst_list = fluid_list_next(inst_list); + } + + size -= SF_BAG_SIZE; + + if(size != 0) + { + FLUID_LOG(FLUID_ERR, "Instrument chunk size mismatch"); + return FALSE; + } + + READW(sf, genndx); + READW(sf, modndx); + + if(!pz) + { + /* in case that all are no zoners */ + if(genndx > 0) + { + FLUID_LOG(FLUID_WARN, "No instrument generators and terminal index not 0"); + } + + if(modndx > 0) + { + FLUID_LOG(FLUID_WARN, "No instrument modulators and terminal index not 0"); + } + + return TRUE; + } + + if(genndx < pgenndx) + { + FLUID_LOG(FLUID_ERR, "Instrument generator indices not monotonic"); + return FALSE; + } + + if(modndx < pmodndx) + { + FLUID_LOG(FLUID_ERR, "Instrument modulator indices not monotonic"); + return FALSE; + } + + i = genndx - pgenndx; + + while(i--) + { + pz->gen = fluid_list_prepend(pz->gen, NULL); + } + + i = modndx - pmodndx; + + while(i--) + { + pz->mod = fluid_list_prepend(pz->mod, NULL); + } + + return TRUE; +} + +/* instrument modulator loader */ +static int load_imod(SFData *sf, int size) +{ + fluid_list_t *inst_list; + fluid_list_t *zone_list; + fluid_list_t *mod_list; + SFMod *m; + + inst_list = sf->inst; + + while(inst_list) + { + /* traverse through all inst */ + zone_list = ((SFInst *)(inst_list->data))->zone; + + while(zone_list) + { + /* traverse this inst's zones */ + mod_list = ((SFZone *)(zone_list->data))->mod; + + while(mod_list) + { + /* load zone's modulators */ + if((size -= SF_MOD_SIZE) < 0) + { + FLUID_LOG(FLUID_ERR, "Instrument modulator chunk size mismatch"); + return FALSE; + } + + if((m = FLUID_NEW(SFMod)) == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FALSE; + } + + mod_list->data = m; + READW(sf, m->src); + READW(sf, m->dest); + READW(sf, m->amount); + READW(sf, m->amtsrc); + READW(sf, m->trans); + mod_list = fluid_list_next(mod_list); + } + + zone_list = fluid_list_next(zone_list); + } + + inst_list = fluid_list_next(inst_list); + } + + /* + If there isn't even a terminal record + Hmmm, the specs say there should be one, but.. + */ + if(size == 0) + { + return TRUE; + } + + size -= SF_MOD_SIZE; + + if(size != 0) + { + FLUID_LOG(FLUID_ERR, "Instrument modulator chunk size mismatch"); + return FALSE; + } + + FSKIP(sf, SF_MOD_SIZE); /* terminal mod */ + + return TRUE; +} + +/* load instrument generators (see load_pgen for loading rules) */ +int load_igen(SFData *sf, int size) +{ + fluid_list_t *dup; + fluid_list_t *inst_list; + fluid_list_t *zone_list; + fluid_list_t *gen_list; + SFZone *zone; + SFGen *g; + SFInst *inst; + SFGenAmount genval; + unsigned short genid; + int level, skip, drop, discarded; + + inst_list = sf->inst; + + /* traverse through all instruments */ + while(inst_list) + { + inst = fluid_list_get(inst_list); + + discarded = FALSE; + zone_list = inst->zone; + + /* traverse this instrument's zones */ + while(zone_list) + { + zone = fluid_list_get(zone_list); + + level = 0; + gen_list = zone->gen; + + while(gen_list) + { + /* load zone's generators */ + dup = NULL; + skip = FALSE; + drop = FALSE; + + if((size -= SF_GEN_SIZE) < 0) + { + FLUID_LOG(FLUID_ERR, "IGEN chunk size mismatch"); + return FALSE; + } + + READW(sf, genid); + + if(genid == GEN_KEYRANGE) + { + /* nothing precedes */ + if(level == 0) + { + level = 1; + READB(sf, genval.range.lo); + READB(sf, genval.range.hi); + } + else + { + skip = TRUE; + } + } + else if(genid == GEN_VELRANGE) + { + /* only KeyRange precedes */ + if(level <= 1) + { + level = 2; + READB(sf, genval.range.lo); + READB(sf, genval.range.hi); + } + else + { + skip = TRUE; + } + } + else if(genid == GEN_SAMPLEID) + { + /* sample is last gen */ + level = 3; + READW(sf, genval.uword); + } + else + { + level = 2; + + if(valid_inst_genid(genid)) + { + /* gen valid? */ + READW(sf, genval.sword); + dup = find_gen_by_id(genid, zone->gen); + } + else + { + skip = TRUE; + } + } + + if(!skip) + { + if(!dup) + { + /* if gen ! dup alloc new */ + if((g = FLUID_NEW(SFGen)) == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FALSE; + } + + gen_list->data = g; + g->id = genid; + } + else + { + g = (SFGen *)(dup->data); + drop = TRUE; + } + + g->amount = genval; + } + else + { + /* skip this generator */ + discarded = TRUE; + drop = TRUE; + FSKIPW(sf); + } + + if(!drop) + { + gen_list = fluid_list_next(gen_list); /* next gen */ + } + else + { + SLADVREM(zone->gen, gen_list); + } + + /* GEN_SAMPLEID should be last generator */ + if (level == 3) + { + break; + } + + } /* generator loop */ + + /* Anything below level 3 means it's a global zone. The global zone + * should always be the first zone in the list, so discard any + * other global zones we encounter */ + if(level < 3 && (zone_list != inst->zone)) + { + /* advance to next zone before deleting the current list element */ + zone_list = fluid_list_next(zone_list); + + FLUID_LOG(FLUID_WARN, "Instrument '%s': Discarding invalid global zone", + inst->name); + inst->zone = fluid_list_remove(inst->zone, zone); + delete_zone(zone); + + /* we have already advanced the zone_list pointer, so continue with next zone */ + continue; + } + + /* All remaining generators must be invalid and should be discarded + * (because they come after a sampleid generator) */ + while(gen_list) + { + discarded = TRUE; + + if((size -= SF_GEN_SIZE) < 0) + { + FLUID_LOG(FLUID_ERR, "Instrument generator chunk size mismatch"); + return FALSE; + } + + FSKIP(sf, SF_GEN_SIZE); + SLADVREM(zone->gen, gen_list); + } + + zone_list = fluid_list_next(zone_list); /* next zone */ + } + + if(discarded) + { + FLUID_LOG(FLUID_WARN, + "Instrument '%s': Some invalid generators were discarded", + inst->name); + } + + inst_list = fluid_list_next(inst_list); + } + + /* for those non-terminal record cases, grr! */ + if(size == 0) + { + return TRUE; + } + + size -= SF_GEN_SIZE; + + if(size != 0) + { + FLUID_LOG(FLUID_ERR, "IGEN chunk size mismatch"); + return FALSE; + } + + FSKIP(sf, SF_GEN_SIZE); /* terminal gen */ + + return TRUE; +} + +/* sample header loader */ +static int load_shdr(SFData *sf, unsigned int size) +{ + unsigned int i; + SFSample *p; + + if(size % SF_SHDR_SIZE || size == 0) /* size is multiple of SHDR size? */ + { + FLUID_LOG(FLUID_ERR, "Sample header has invalid size"); + return FALSE; + } + + size = size / SF_SHDR_SIZE - 1; + + if(size == 0) + { + /* at least one sample + term record? */ + FLUID_LOG(FLUID_WARN, "File contains no samples"); + FSKIP(sf, SF_SHDR_SIZE); + return TRUE; + } + + /* load all sample headers */ + for(i = 0; i < size; i++) + { + if((p = FLUID_NEW(SFSample)) == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FALSE; + } + p->idx = i; + + sf->sample = fluid_list_prepend(sf->sample, p); + READSTR(sf, &p->name); + READD(sf, p->start); + READD(sf, p->end); + READD(sf, p->loopstart); + READD(sf, p->loopend); + READD(sf, p->samplerate); + READB(sf, p->origpitch); + READB(sf, p->pitchadj); + FSKIPW(sf); /* skip sample link */ + READW(sf, p->sampletype); + } + + FSKIP(sf, SF_SHDR_SIZE); /* skip terminal shdr */ + + return TRUE; +} + +void delete_preset(SFPreset *preset) +{ + fluid_list_t *entry; + SFZone *zone; + + if(!preset) + { + return; + } + + entry = preset->zone; + + while(entry) + { + zone = (SFZone *)fluid_list_get(entry); + delete_zone(zone); + entry = fluid_list_next(entry); + } + + delete_fluid_list(preset->zone); + + FLUID_FREE(preset); +} + +void delete_inst(SFInst *inst) +{ + fluid_list_t *entry; + SFZone *zone; + + if(!inst) + { + return; + } + + entry = inst->zone; + + while(entry) + { + zone = (SFZone *)fluid_list_get(entry); + delete_zone(zone); + entry = fluid_list_next(entry); + } + + delete_fluid_list(inst->zone); + + FLUID_FREE(inst); +} + + +/* Free all elements of a zone (Preset or Instrument) */ +void delete_zone(SFZone *zone) +{ + fluid_list_t *entry; + + if(!zone) + { + return; + } + + entry = zone->gen; + + while(entry) + { + FLUID_FREE(fluid_list_get(entry)); + entry = fluid_list_next(entry); + } + + delete_fluid_list(zone->gen); + + entry = zone->mod; + + while(entry) + { + FLUID_FREE(fluid_list_get(entry)); + entry = fluid_list_next(entry); + } + + delete_fluid_list(zone->mod); + + FLUID_FREE(zone); +} + +/* preset sort function, first by bank, then by preset # */ +static int preset_compare_func(const void *a, const void *b) +{ + int aval, bval; + + aval = (int)(((const SFPreset *)a)->bank) << 16 | ((const SFPreset *)a)->prenum; + bval = (int)(((const SFPreset *)b)->bank) << 16 | ((const SFPreset *)b)->prenum; + + return (aval - bval); +} + +/* Find a generator by its id in the passed in list. + * + * @return pointer to SFGen if found, otherwise NULL + */ +static fluid_list_t *find_gen_by_id(int gen, fluid_list_t *genlist) +{ + /* is generator in gen list? */ + fluid_list_t *p; + + p = genlist; + + while(p) + { + if(p->data == NULL) + { + return NULL; + } + + if(gen == ((SFGen *)p->data)->id) + { + break; + } + + p = fluid_list_next(p); + } + + return p; +} + +/* check validity of instrument generator */ +static int valid_inst_genid(unsigned short genid) +{ + size_t i; + + /* OVERRIDEROOTKEY is the last official generator, everything + * following it are generators internal to FluidSynth and will + * never appear in a SoundFont file. */ + if(genid > GEN_OVERRIDEROOTKEY) + { + return FALSE; + } + + for(i = 0; i < FLUID_N_ELEMENTS(invalid_inst_gen); i++) + { + if (invalid_inst_gen[i] == genid) + { + return FALSE; + } + } + + return TRUE; +} + +/* check validity of preset generator */ +static int valid_preset_genid(unsigned short genid) +{ + size_t i; + + if(!valid_inst_genid(genid)) + { + return FALSE; + } + + for(i = 0; i < FLUID_N_ELEMENTS(invalid_preset_gen); i++) + { + if (invalid_preset_gen[i] == genid) + { + return FALSE; + } + } + + return TRUE; +} + + +static int fluid_sffile_read_wav(SFData *sf, unsigned int start, unsigned int end, short **data, char **data24) +{ + short *loaded_data = NULL; + char *loaded_data24 = NULL; + unsigned int num_samples; + + fluid_return_val_if_fail((end + 1) > start , -1); + + num_samples = (end + 1) - start; + + if((start * sizeof(short) > sf->samplesize) || (end * sizeof(short) > sf->samplesize)) + { + FLUID_LOG(FLUID_ERR, "Sample offsets exceed sample data chunk"); + goto error_exit; + } + + /* Load 16-bit sample data */ + if(sf->fcbs->fseek(sf->sffd, sf->samplepos + (start * sizeof(short)), SEEK_SET) == FLUID_FAILED) + { + FLUID_LOG(FLUID_ERR, "Failed to seek to sample position"); + goto error_exit; + } + + loaded_data = FLUID_ARRAY(short, num_samples); + + if(loaded_data == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + goto error_exit; + } + + if(sf->fcbs->fread(loaded_data, num_samples * sizeof(short), sf->sffd) == FLUID_FAILED) + { +#if FLUID_VERSION_CHECK(FLUIDSYNTH_VERSION_MAJOR, FLUIDSYNTH_VERSION_MINOR, FLUIDSYNTH_VERSION_MICRO) < FLUID_VERSION_CHECK(2,2,0) + if((int)(num_samples * sizeof(short)) < 0) + { + FLUID_LOG(FLUID_INFO, + "This SoundFont seems to be bigger than 2GB, which is not supported in this version of fluidsynth. " + "You need to use at least fluidsynth 2.2.0"); + } +#endif + FLUID_LOG(FLUID_ERR, "Failed to read sample data"); + goto error_exit; + } + + /* If this machine is big endian, byte swap the 16 bit samples */ + if(FLUID_IS_BIG_ENDIAN) + { + unsigned int i; + + for(i = 0; i < num_samples; i++) + { + loaded_data[i] = FLUID_LE16TOH(loaded_data[i]); + } + } + + *data = loaded_data; + + /* Optionally load additional 8 bit sample data for 24-bit support. Any failures while loading + * the 24-bit sample data will be logged as errors but won't prevent the sample reading to + * fail, as sound output is still possible with the 16-bit sample data. */ + if(sf->sample24pos) + { + if((start > sf->sample24size) || (end > sf->sample24size)) + { + FLUID_LOG(FLUID_ERR, "Sample offsets exceed 24-bit sample data chunk"); + goto error24_exit; + } + + if(sf->fcbs->fseek(sf->sffd, sf->sample24pos + start, SEEK_SET) == FLUID_FAILED) + { + FLUID_LOG(FLUID_ERR, "Failed to seek position for 24-bit sample data in data file"); + goto error24_exit; + } + + loaded_data24 = FLUID_ARRAY(char, num_samples); + + if(loaded_data24 == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory reading 24-bit sample data"); + goto error24_exit; + } + + if(sf->fcbs->fread(loaded_data24, num_samples, sf->sffd) == FLUID_FAILED) + { + FLUID_LOG(FLUID_ERR, "Failed to read 24-bit sample data"); + goto error24_exit; + } + } + + *data24 = loaded_data24; + + return num_samples; + +error24_exit: + FLUID_LOG(FLUID_WARN, "Ignoring 24-bit sample data, sound quality might suffer"); + FLUID_FREE(loaded_data24); + *data24 = NULL; + return num_samples; + +error_exit: + FLUID_FREE(loaded_data); + FLUID_FREE(loaded_data24); + return -1; +} + + +/* Ogg Vorbis loading and decompression */ +#if LIBSNDFILE_SUPPORT + +/* Virtual file access routines to allow loading individually compressed + * samples from the Soundfont sample data chunk using the file callbacks + * passing in during opening of the file */ +typedef struct _sfvio_data_t +{ + SFData *sffile; + sf_count_t start; /* start byte offset of compressed data */ + sf_count_t end; /* end byte offset of compressed data */ + sf_count_t offset; /* current virtual file offset from start byte offset */ + +} sfvio_data_t; + +static sf_count_t sfvio_get_filelen(void *user_data) +{ + sfvio_data_t *data = user_data; + + return (data->end + 1) - data->start; +} + +static sf_count_t sfvio_seek(sf_count_t offset, int whence, void *user_data) +{ + sfvio_data_t *data = user_data; + SFData *sf = data->sffile; + sf_count_t new_offset; + + switch(whence) + { + case SEEK_SET: + new_offset = offset; + break; + + case SEEK_CUR: + new_offset = data->offset + offset; + break; + + case SEEK_END: + new_offset = sfvio_get_filelen(user_data) + offset; + break; + + default: + goto fail; /* proper error handling not possible?? */ + } + + new_offset += data->start; + fluid_rec_mutex_lock(sf->mtx); + if (data->start <= new_offset && new_offset <= data->end && + sf->fcbs->fseek(sf->sffd, new_offset, SEEK_SET) != FLUID_FAILED) + { + data->offset = new_offset - data->start; + } + fluid_rec_mutex_unlock(sf->mtx); + +fail: + return data->offset; +} + +static sf_count_t sfvio_read(void *ptr, sf_count_t count, void *user_data) +{ + sfvio_data_t *data = user_data; + SFData *sf = data->sffile; + sf_count_t remain; + + remain = sfvio_get_filelen(user_data) - data->offset; + + if(count > remain) + { + count = remain; + } + + if(count == 0) + { + return count; + } + + fluid_rec_mutex_lock(sf->mtx); + if (sf->fcbs->fseek(sf->sffd, data->start + data->offset, SEEK_SET) == FLUID_FAILED) + { + FLUID_LOG(FLUID_ERR, "This should never happen: fseek failed in sfvoid_read()"); + count = 0; + } + else + { + if (sf->fcbs->fread(ptr, count, sf->sffd) == FLUID_FAILED) + { + FLUID_LOG(FLUID_ERR, "Failed to read compressed sample data"); + count = 0; + } + } + fluid_rec_mutex_unlock(sf->mtx); + + data->offset += count; + + return count; +} + +static sf_count_t sfvio_tell(void *user_data) +{ + sfvio_data_t *data = user_data; + + return data->offset; +} + +/** + * Read Ogg Vorbis compressed data from the Soundfont and decompress it, returning the number of samples + * in the decompressed WAV. Only 16-bit mono samples are supported. + * + * Note that this function takes byte indices for start and end source data. The sample headers in SF3 + * files use byte indices, so those pointers can be passed directly to this function. + * + * This function uses a virtual file structure in order to read the Ogg Vorbis + * data from arbitrary locations in the source file. + */ +static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data) +{ + SNDFILE *sndfile; + SF_INFO sfinfo; + SF_VIRTUAL_IO sfvio = + { + sfvio_get_filelen, + sfvio_seek, + sfvio_read, + NULL, + sfvio_tell + }; + sfvio_data_t sfdata; + short *wav_data = NULL; + + if((start_byte > sf->samplesize) || (end_byte > sf->samplesize)) + { + FLUID_LOG(FLUID_ERR, "Ogg Vorbis data offsets exceed sample data chunk"); + return -1; + } + + // Initialize file position indicator and SF_INFO structure + sfdata.sffile = sf; + sfdata.start = sf->samplepos + start_byte; + sfdata.end = sf->samplepos + end_byte; + sfdata.offset = -1; + + /* Seek to sfdata.start, the beginning of Ogg Vorbis data in Soundfont */ + sfvio_seek(0, SEEK_SET, &sfdata); + if (sfdata.offset != 0) + { + FLUID_LOG(FLUID_ERR, "Failed to seek to compressed sample position"); + return -1; + } + + FLUID_MEMSET(&sfinfo, 0, sizeof(sfinfo)); + + // Open sample as a virtual file + sndfile = sf_open_virtual(&sfvio, SFM_READ, &sfinfo, &sfdata); + + if(!sndfile) + { + FLUID_LOG(FLUID_ERR, "sf_open_virtual(): %s", sf_strerror(sndfile)); + return -1; + } + + // Empty sample + if(sfinfo.frames <= 0 || sfinfo.channels <= 0) + { + FLUID_LOG(FLUID_DBG, "Empty decompressed sample"); + *data = NULL; + sf_close(sndfile); + return 0; + } + + // Mono sample + if(sfinfo.channels != 1) + { + FLUID_LOG(FLUID_DBG, "Unsupported channel count %d in ogg sample", sfinfo.channels); + goto error_exit; + } + + if((sfinfo.format & SF_FORMAT_OGG) == 0) + { + FLUID_LOG(FLUID_WARN, "OGG sample is not OGG compressed, this is not officially supported"); + } + + wav_data = FLUID_ARRAY(short, sfinfo.frames * sfinfo.channels); + + if(!wav_data) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + goto error_exit; + } + + /* Automatically decompresses the Ogg Vorbis data to 16-bit PCM */ + if(sf_readf_short(sndfile, wav_data, sfinfo.frames) < sfinfo.frames) + { + FLUID_LOG(FLUID_DBG, "Decompression failed!"); + FLUID_LOG(FLUID_ERR, "sf_readf_short(): %s", sf_strerror(sndfile)); + goto error_exit; + } + + sf_close(sndfile); + + *data = wav_data; + + return sfinfo.frames; + +error_exit: + FLUID_FREE(wav_data); + sf_close(sndfile); + return -1; +} +#else +static int fluid_sffile_read_vorbis(SFData *sf, unsigned int start_byte, unsigned int end_byte, short **data) +{ + return -1; +} +#endif diff --git a/libs/fluidsynth/src/sfloader/fluid_sffile.h b/libs/fluidsynth/src/sfloader/fluid_sffile.h new file mode 100644 index 00000000000..5275c6252bc --- /dev/null +++ b/libs/fluidsynth/src/sfloader/fluid_sffile.h @@ -0,0 +1,194 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * SoundFont loading code borrowed from Smurf SoundFont Editor by Josh Green + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#ifndef _FLUID_SFFILE_H +#define _FLUID_SFFILE_H + + +#include "fluid_gen.h" +#include "fluid_list.h" +#include "fluid_mod.h" +#include "fluidsynth.h" +#include "fluid_sys.h" + + +/* Sound Font structure defines */ + +/* Forward declarations */ +typedef union _SFGenAmount SFGenAmount; +typedef struct _SFVersion SFVersion; +typedef struct _SFMod SFMod; +typedef struct _SFGen SFGen; +typedef struct _SFZone SFZone; +typedef struct _SFSample SFSample; +typedef struct _SFInst SFInst; +typedef struct _SFPreset SFPreset; +typedef struct _SFData SFData; +typedef struct _SFChunk SFChunk; + + +struct _SFVersion +{ + /* version structure */ + unsigned short major; + unsigned short minor; +}; + +struct _SFMod +{ + /* Modulator structure */ + unsigned short src; /* source modulator */ + unsigned short dest; /* destination generator */ + signed short amount; /* signed, degree of modulation */ + unsigned short amtsrc; /* second source controls amnt of first */ + unsigned short trans; /* transform applied to source */ +}; + +union _SFGenAmount /* Generator amount structure */ +{ + signed short sword; /* signed 16 bit value */ + unsigned short uword; /* unsigned 16 bit value */ + struct + { + unsigned char lo; /* low value for ranges */ + unsigned char hi; /* high value for ranges */ + } range; +}; + +struct _SFGen +{ + /* Generator structure */ + unsigned short id; /* generator ID */ + SFGenAmount amount; /* generator value */ +}; + +struct _SFZone +{ + /* Sample/instrument zone structure */ + fluid_list_t *gen; /* list of generators */ + fluid_list_t *mod; /* list of modulators */ +}; + +struct _SFSample +{ + /* Sample structure */ + char name[21]; /* Name of sample */ + int idx; /* Index of this instrument in the Soundfont */ + unsigned int start; /* Offset in sample area to start of sample */ + unsigned int end; /* Offset from start to end of sample, + this is the last point of the + sample, the SF spec has this as the + 1st point after, corrected on + load/save */ + unsigned int loopstart; /* Offset from start to start of loop */ + unsigned int loopend; /* Offset from start to end of loop, + marks the first point after loop, + whose sample value is ideally + equivalent to loopstart */ + unsigned int samplerate; /* Sample rate recorded at */ + unsigned char origpitch; /* root midi key number */ + signed char pitchadj; /* pitch correction in cents */ + unsigned short sampletype; /* 1 mono,2 right,4 left,linked 8,0x8000=ROM */ + fluid_sample_t *fluid_sample; /* Imported sample (fixed up in fluid_defsfont_load) */ +}; + +struct _SFInst +{ + /* Instrument structure */ + char name[21]; /* Name of instrument */ + int idx; /* Index of this instrument in the Soundfont */ + fluid_list_t *zone; /* list of instrument zones */ +}; + +struct _SFPreset +{ + /* Preset structure */ + char name[21]; /* preset name */ + unsigned short prenum; /* preset number */ + unsigned short bank; /* bank number */ + fluid_list_t *zone; /* list of preset zones */ +}; + +/* NOTE: sffd is also used to determine if sound font is new (NULL) */ +struct _SFData +{ + /* Sound font data structure */ + SFVersion version; /* sound font version */ + SFVersion romver; /* ROM version */ + + unsigned int filesize; + + unsigned int samplepos; /* position within sffd of the sample chunk */ + unsigned int samplesize; /* length within sffd of the sample chunk */ + + unsigned int sample24pos; /* position within sffd of the sm24 chunk, set to zero if no 24 bit + sample support */ + unsigned int sample24size; /* length within sffd of the sm24 chunk */ + + unsigned int hydrapos; + unsigned int hydrasize; + + char *fname; /* file name */ + FILE *sffd; /* loaded sfont file descriptor */ + const fluid_file_callbacks_t *fcbs; /* file callbacks used to read this file */ + + fluid_rec_mutex_t mtx; /* this mutex can be used to synchronize calls to fcbs when using multiple threads (e.g. SF3 loading) */ + + fluid_list_t *info; /* linked list of info strings (1st byte is ID) */ + fluid_list_t *preset; /* linked list of preset info */ + fluid_list_t *inst; /* linked list of instrument info */ + fluid_list_t *sample; /* linked list of sample info */ +}; + +/* functions */ + + +/*-----------------------------------sffile.h----------------------------*/ +/* + File structures and routines (used to be in sffile.h) +*/ + +/* sfont file data structures */ +struct _SFChunk +{ + /* RIFF file chunk structure */ + unsigned int id; /* chunk id */ + unsigned int size; /* size of the following chunk */ +}; + +/* Public functions */ +SFData *fluid_sffile_open(const char *fname, const fluid_file_callbacks_t *fcbs); +void fluid_sffile_close(SFData *sf); +int fluid_sffile_parse_presets(SFData *sf); +int fluid_sffile_read_sample_data(SFData *sf, unsigned int sample_start, unsigned int sample_end, + int sample_type, short **data, char **data24); + + +/* extern only for unit test purposes */ +int load_igen(SFData *sf, int size); +int load_pgen(SFData *sf, int size); +void delete_preset(SFPreset *preset); +void delete_inst(SFInst *inst); +void delete_zone(SFZone *zone); + +#endif /* _FLUID_SFFILE_H */ diff --git a/libs/fluidsynth/src/sfloader/fluid_sfont.c b/libs/fluidsynth/src/sfloader/fluid_sfont.c new file mode 100644 index 00000000000..00423c00356 --- /dev/null +++ b/libs/fluidsynth/src/sfloader/fluid_sfont.c @@ -0,0 +1,850 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include "fluid_sfont.h" +#include "fluid_sys.h" + + +void *default_fopen(const char *path) +{ + const char* msg; + FILE* handle = fluid_file_open(path, &msg); + + if(handle == NULL) + { + FLUID_LOG(FLUID_ERR, "fluid_sfloader_load(): Failed to open '%s': %s", path, msg); + } + + return handle; +} + +int default_fclose(void *handle) +{ + return FLUID_FCLOSE((FILE *)handle) == 0 ? FLUID_OK : FLUID_FAILED; +} + +fluid_long_long_t default_ftell(void *handle) +{ + return FLUID_FTELL((FILE *)handle); +} + +#ifdef _WIN32 +#define FLUID_PRIi64 "I64d" +#else +#define FLUID_PRIi64 "lld" +#endif + +int safe_fread(void *buf, fluid_long_long_t count, void *fd) +{ + if(FLUID_FREAD(buf, (size_t)count, 1, (FILE *)fd) != 1) + { + if(feof((FILE *)fd)) + { + FLUID_LOG(FLUID_ERR, "EOF while attempting to read %" FLUID_PRIi64 " bytes", count); + } + else + { + FLUID_LOG(FLUID_ERR, "File read failed"); + } + + return FLUID_FAILED; + } + + return FLUID_OK; +} + +int safe_fseek(void *fd, fluid_long_long_t ofs, int whence) +{ + if(FLUID_FSEEK((FILE *)fd, ofs, whence) != 0) + { + FLUID_LOG(FLUID_ERR, "File seek failed with offset = %" FLUID_PRIi64 " and whence = %d", ofs, whence); + return FLUID_FAILED; + } + + return FLUID_OK; +} + +#undef FLUID_PRIi64 + +/** + * Creates a new SoundFont loader. + * + * @param load Pointer to a function that provides a #fluid_sfont_t (see #fluid_sfloader_load_t). + * @param free Pointer to a function that destroys this instance (see #fluid_sfloader_free_t). + * Unless any private data needs to be freed it is sufficient to set this to delete_fluid_sfloader(). + * + * @return the SoundFont loader instance on success, NULL otherwise. + */ +fluid_sfloader_t *new_fluid_sfloader(fluid_sfloader_load_t load, fluid_sfloader_free_t free) +{ + fluid_sfloader_t *loader; + + fluid_return_val_if_fail(load != NULL, NULL); + fluid_return_val_if_fail(free != NULL, NULL); + + loader = FLUID_NEW(fluid_sfloader_t); + + if(loader == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + FLUID_MEMSET(loader, 0, sizeof(*loader)); + + loader->load = load; + loader->free = free; + fluid_sfloader_set_callbacks(loader, + default_fopen, + safe_fread, + safe_fseek, + default_ftell, + default_fclose); + + return loader; +} + +/** + * Frees a SoundFont loader created with new_fluid_sfloader(). + * + * @param loader The SoundFont loader instance to free. + */ +void delete_fluid_sfloader(fluid_sfloader_t *loader) +{ + fluid_return_if_fail(loader != NULL); + + FLUID_FREE(loader); +} + +/** + * Specify private data to be used by #fluid_sfloader_load_t. + * + * @param loader The SoundFont loader instance. + * @param data The private data to store. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int fluid_sfloader_set_data(fluid_sfloader_t *loader, void *data) +{ + fluid_return_val_if_fail(loader != NULL, FLUID_FAILED); + + loader->data = data; + return FLUID_OK; +} + +/** + * Obtain private data previously set with fluid_sfloader_set_data(). + * + * @param loader The SoundFont loader instance. + * @return The private data or NULL if none explicitly set before. + */ +void *fluid_sfloader_get_data(fluid_sfloader_t *loader) +{ + fluid_return_val_if_fail(loader != NULL, NULL); + + return loader->data; +} + +/** + * Set custom callbacks to be used upon soundfont loading. + * + * @param loader The SoundFont loader instance. + * @param open A function implementing #fluid_sfloader_callback_open_t. + * @param read A function implementing #fluid_sfloader_callback_read_t. + * @param seek A function implementing #fluid_sfloader_callback_seek_t. + * @param tell A function implementing #fluid_sfloader_callback_tell_t. + * @param close A function implementing #fluid_sfloader_callback_close_t. + * @return #FLUID_OK if the callbacks have been successfully set, #FLUID_FAILED otherwise. + * + * Useful for loading a soundfont from memory, see \a doc/fluidsynth_sfload_mem.c as an example. + * + */ +int fluid_sfloader_set_callbacks(fluid_sfloader_t *loader, + fluid_sfloader_callback_open_t open, + fluid_sfloader_callback_read_t read, + fluid_sfloader_callback_seek_t seek, + fluid_sfloader_callback_tell_t tell, + fluid_sfloader_callback_close_t close) +{ + fluid_file_callbacks_t *cb; + + fluid_return_val_if_fail(loader != NULL, FLUID_FAILED); + fluid_return_val_if_fail(open != NULL, FLUID_FAILED); + fluid_return_val_if_fail(read != NULL, FLUID_FAILED); + fluid_return_val_if_fail(seek != NULL, FLUID_FAILED); + fluid_return_val_if_fail(tell != NULL, FLUID_FAILED); + fluid_return_val_if_fail(close != NULL, FLUID_FAILED); + + cb = &loader->file_callbacks; + + cb->fopen = open; + cb->fread = read; + cb->fseek = seek; + cb->ftell = tell; + cb->fclose = close; + + // NOTE: if we ever make the instpatch loader public, this may return FLUID_FAILED + return FLUID_OK; +} + +/** + * Creates a new virtual SoundFont instance structure. + * + * @param get_name A function implementing #fluid_sfont_get_name_t. + * @param get_preset A function implementing #fluid_sfont_get_preset_t. + * @param iter_start A function implementing #fluid_sfont_iteration_start_t, or NULL if preset iteration not needed. + * @param iter_next A function implementing #fluid_sfont_iteration_next_t, or NULL if preset iteration not needed. + * @param free A function implementing #fluid_sfont_free_t. + * @return The soundfont instance on success or NULL otherwise. + */ +fluid_sfont_t *new_fluid_sfont(fluid_sfont_get_name_t get_name, + fluid_sfont_get_preset_t get_preset, + fluid_sfont_iteration_start_t iter_start, + fluid_sfont_iteration_next_t iter_next, + fluid_sfont_free_t free) +{ + fluid_sfont_t *sfont; + + fluid_return_val_if_fail(get_name != NULL, NULL); + fluid_return_val_if_fail(get_preset != NULL, NULL); + fluid_return_val_if_fail(free != NULL, NULL); + + sfont = FLUID_NEW(fluid_sfont_t); + + if(sfont == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + FLUID_MEMSET(sfont, 0, sizeof(*sfont)); + + sfont->get_name = get_name; + sfont->get_preset = get_preset; + sfont->iteration_start = iter_start; + sfont->iteration_next = iter_next; + sfont->free = free; + + return sfont; +} + +/** + * Set private data to use with a SoundFont instance. + * + * @param sfont The SoundFont instance. + * @param data The private data to store. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int fluid_sfont_set_data(fluid_sfont_t *sfont, void *data) +{ + fluid_return_val_if_fail(sfont != NULL, FLUID_FAILED); + + sfont->data = data; + return FLUID_OK; +} + +/** + * Retrieve the private data of a SoundFont instance. + * + * @param sfont The SoundFont instance. + * @return The private data or NULL if none explicitly set before. + */ +void *fluid_sfont_get_data(fluid_sfont_t *sfont) +{ + fluid_return_val_if_fail(sfont != NULL, NULL); + + return sfont->data; +} + +/** + * Retrieve the unique ID of a SoundFont instance. + * + * @param sfont The SoundFont instance. + * @return The SoundFont ID. + */ +int fluid_sfont_get_id(fluid_sfont_t *sfont) +{ + return sfont->id; +} + +/** + * Retrieve the name of a SoundFont instance. + * + * @param sfont The SoundFont instance. + * @return The name of the SoundFont. + */ +const char *fluid_sfont_get_name(fluid_sfont_t *sfont) +{ + return sfont->get_name(sfont); +} + +/** + * Retrieve the preset assigned the a SoundFont instance for the given bank and preset number. + * + * @param sfont The SoundFont instance. + * @param bank bank number of the preset + * @param prenum program number of the preset + * @return The preset instance or NULL if none found. + */ +fluid_preset_t *fluid_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum) +{ + return sfont->get_preset(sfont, bank, prenum); +} + + +/** + * Starts / re-starts virtual preset iteration in a SoundFont. + * + * @param sfont Virtual SoundFont instance + */ +void fluid_sfont_iteration_start(fluid_sfont_t *sfont) +{ + fluid_return_if_fail(sfont != NULL); + fluid_return_if_fail(sfont->iteration_start != NULL); + + sfont->iteration_start(sfont); +} + +/** + * Virtual SoundFont preset iteration function. + * + * Returns preset information to the caller and advances the + * internal iteration state to the next preset for subsequent calls. + * @param sfont The SoundFont instance. + * @return NULL when no more presets are available, otherwise the a pointer to the current preset + */ +fluid_preset_t *fluid_sfont_iteration_next(fluid_sfont_t *sfont) +{ + fluid_return_val_if_fail(sfont != NULL, NULL); + fluid_return_val_if_fail(sfont->iteration_next != NULL, NULL); + + return sfont->iteration_next(sfont); +} + +/** + * Destroys a SoundFont instance created with new_fluid_sfont(). + * + * @param sfont The SoundFont instance to destroy. + * @return Always returns 0. + * + * Implements #fluid_sfont_free_t. + * + */ +int delete_fluid_sfont(fluid_sfont_t *sfont) +{ + fluid_return_val_if_fail(sfont != NULL, 0); + + FLUID_FREE(sfont); + return 0; +} + +/** + * Create a virtual SoundFont preset instance. + * + * @param parent_sfont The SoundFont instance this preset shall belong to + * @param get_name A function implementing #fluid_preset_get_name_t + * @param get_bank A function implementing #fluid_preset_get_banknum_t + * @param get_num A function implementing #fluid_preset_get_num_t + * @param noteon A function implementing #fluid_preset_noteon_t + * @param free A function implementing #fluid_preset_free_t + * @return The preset instance on success, NULL otherwise. + */ +fluid_preset_t *new_fluid_preset(fluid_sfont_t *parent_sfont, + fluid_preset_get_name_t get_name, + fluid_preset_get_banknum_t get_bank, + fluid_preset_get_num_t get_num, + fluid_preset_noteon_t noteon, + fluid_preset_free_t free) +{ + fluid_preset_t *preset; + + fluid_return_val_if_fail(parent_sfont != NULL, NULL); + fluid_return_val_if_fail(get_name != NULL, NULL); + fluid_return_val_if_fail(get_bank != NULL, NULL); + fluid_return_val_if_fail(get_num != NULL, NULL); + fluid_return_val_if_fail(noteon != NULL, NULL); + fluid_return_val_if_fail(free != NULL, NULL); + + preset = FLUID_NEW(fluid_preset_t); + + if(preset == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + FLUID_MEMSET(preset, 0, sizeof(*preset)); + + preset->sfont = parent_sfont; + preset->get_name = get_name; + preset->get_banknum = get_bank; + preset->get_num = get_num; + preset->noteon = noteon; + preset->free = free; + + return preset; +} + +/** + * Set private data to use with a SoundFont preset instance. + * + * @param preset The SoundFont preset instance. + * @param data The private data to store. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int fluid_preset_set_data(fluid_preset_t *preset, void *data) +{ + fluid_return_val_if_fail(preset != NULL, FLUID_FAILED); + + preset->data = data; + return FLUID_OK; +} + +/** + * Retrieve the private data of a SoundFont preset instance. + * + * @param preset The SoundFont preset instance. + * @return The private data or NULL if none explicitly set before. + */ +void *fluid_preset_get_data(fluid_preset_t *preset) +{ + fluid_return_val_if_fail(preset != NULL, NULL); + + return preset->data; +} + +/** + * Retrieves the presets name by executing the \p get_name function + * provided on its creation. + * + * @param preset The SoundFont preset instance. + * @return Pointer to a NULL-terminated string containing the presets name. + */ +const char *fluid_preset_get_name(fluid_preset_t *preset) +{ + return preset->get_name(preset); +} + +/** + * Retrieves the presets bank number by executing the \p get_bank function + * provided on its creation. + * + * @param preset The SoundFont preset instance. + * @return The bank number of \p preset. + */ +int fluid_preset_get_banknum(fluid_preset_t *preset) +{ + return preset->get_banknum(preset); +} + +/** + * Retrieves the presets (instrument) number by executing the \p get_num function + * provided on its creation. + * + * @param preset The SoundFont preset instance. + * @return The number of \p preset. + */ +int fluid_preset_get_num(fluid_preset_t *preset) +{ + return preset->get_num(preset); +} + +/** + * Retrieves the presets parent SoundFont instance. + * + * @param preset The SoundFont preset instance. + * @return The parent SoundFont of \p preset. + */ +fluid_sfont_t *fluid_preset_get_sfont(fluid_preset_t *preset) +{ + return preset->sfont; +} + +/** + * Destroys a SoundFont preset instance created with new_fluid_preset(). + * + * @param preset The SoundFont preset instance to destroy. + * + * Implements #fluid_preset_free_t. + * + */ +void delete_fluid_preset(fluid_preset_t *preset) +{ + fluid_return_if_fail(preset != NULL); + + FLUID_FREE(preset); +} + +/** + * Create a new sample instance. + * + * @return The sample on success, NULL otherwise. + */ +fluid_sample_t * +new_fluid_sample() +{ + fluid_sample_t *sample = NULL; + + sample = FLUID_NEW(fluid_sample_t); + + if(sample == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + FLUID_MEMSET(sample, 0, sizeof(*sample)); + + return sample; +} + +/** + * Destroy a sample instance previously created with new_fluid_sample(). + * + * @param sample The sample to destroy. + */ +void +delete_fluid_sample(fluid_sample_t *sample) +{ + fluid_return_if_fail(sample != NULL); + + if(sample->auto_free) + { + FLUID_FREE(sample->data); + FLUID_FREE(sample->data24); + } + + FLUID_FREE(sample); +} + +/** + * Returns the size of the fluid_sample_t structure. + * + * @return Size of fluid_sample_t in bytes + * + * Useful in low latency scenarios e.g. to allocate a pool of samples. + * + * @note It is recommend to zero initialize the memory before using the object. + * + * @warning Do NOT allocate samples on the stack and assign them to a voice! + */ +size_t fluid_sample_sizeof() +{ + return sizeof(fluid_sample_t); +} + +/** + * Set the name of a SoundFont sample. + * + * @param sample SoundFont sample + * @param name Name to assign to sample (20 chars in length + zero terminator) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int fluid_sample_set_name(fluid_sample_t *sample, const char *name) +{ + fluid_return_val_if_fail(sample != NULL, FLUID_FAILED); + fluid_return_val_if_fail(name != NULL, FLUID_FAILED); + + FLUID_STRNCPY(sample->name, name, sizeof(sample->name)); + return FLUID_OK; +} + +/** + * Assign sample data to a SoundFont sample. + * + * @param sample SoundFont sample + * @param data Buffer containing 16 bit (mono-)audio sample data + * @param data24 If not NULL, pointer to the least significant byte counterparts of each sample data point in order to create 24 bit audio samples + * @param nbframes Number of samples in \a data + * @param sample_rate Sampling rate of the sample data + * @param copy_data TRUE to copy the sample data (and automatically free it upon delete_fluid_sample()), FALSE to use it directly (and not free it) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * + * @note If \a copy_data is FALSE, data should have 8 unused frames at start + * and 8 unused frames at the end and \a nbframes should be >=48 + */ +int +fluid_sample_set_sound_data(fluid_sample_t *sample, + short *data, + char *data24, + unsigned int nbframes, + unsigned int sample_rate, + short copy_data + ) +{ + /* the number of samples before the start and after the end */ +#define SAMPLE_LOOP_MARGIN 8U + + fluid_return_val_if_fail(sample != NULL, FLUID_FAILED); + fluid_return_val_if_fail(data != NULL, FLUID_FAILED); + fluid_return_val_if_fail(nbframes != 0, FLUID_FAILED); + + /* in case we already have some data */ + if((sample->data != NULL || sample->data24 != NULL) && sample->auto_free) + { + FLUID_FREE(sample->data); + FLUID_FREE(sample->data24); + } + + sample->data = NULL; + sample->data24 = NULL; + + if(copy_data) + { + unsigned int storedNbFrames; + + /* nbframes should be >= 48 (SoundFont specs) */ + storedNbFrames = nbframes; + + if(storedNbFrames < 48) + { + storedNbFrames = 48; + } + + storedNbFrames += 2 * SAMPLE_LOOP_MARGIN; + + sample->data = FLUID_ARRAY(short, storedNbFrames); + + if(sample->data == NULL) + { + goto error_rec; + } + + FLUID_MEMSET(sample->data, 0, storedNbFrames * sizeof(short)); + FLUID_MEMCPY(sample->data + SAMPLE_LOOP_MARGIN, data, nbframes * sizeof(short)); + + if(data24 != NULL) + { + sample->data24 = FLUID_ARRAY(char, storedNbFrames); + + if(sample->data24 == NULL) + { + goto error_rec; + } + + FLUID_MEMSET(sample->data24, 0, storedNbFrames); + FLUID_MEMCPY(sample->data24 + SAMPLE_LOOP_MARGIN, data24, nbframes * sizeof(char)); + } + + /* pointers */ + /* all from the start of data */ + sample->start = SAMPLE_LOOP_MARGIN; + sample->end = SAMPLE_LOOP_MARGIN + nbframes - 1; + } + else + { + /* we cannot assure the SAMPLE_LOOP_MARGIN */ + sample->data = data; + sample->data24 = data24; + sample->start = 0; + sample->end = nbframes - 1; + } + + sample->samplerate = sample_rate; + sample->sampletype = FLUID_SAMPLETYPE_MONO; + sample->auto_free = copy_data; + + return FLUID_OK; + +error_rec: + FLUID_LOG(FLUID_ERR, "Out of memory"); + FLUID_FREE(sample->data); + FLUID_FREE(sample->data24); + sample->data = NULL; + sample->data24 = NULL; + return FLUID_FAILED; + +#undef SAMPLE_LOOP_MARGIN +} + +/** + * Set the loop of a sample. + * + * @param sample SoundFont sample + * @param loop_start Start sample index of the loop. + * @param loop_end End index of the loop (must be a valid sample as it marks the last sample to be played). + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int fluid_sample_set_loop(fluid_sample_t *sample, unsigned int loop_start, unsigned int loop_end) +{ + fluid_return_val_if_fail(sample != NULL, FLUID_FAILED); + + sample->loopstart = loop_start; + sample->loopend = loop_end; + + return FLUID_OK; +} + +/** + * Set the pitch of a sample. + * + * @param sample SoundFont sample + * @param root_key Root MIDI note of sample (0-127) + * @param fine_tune Fine tune in cents + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int fluid_sample_set_pitch(fluid_sample_t *sample, int root_key, int fine_tune) +{ + fluid_return_val_if_fail(sample != NULL, FLUID_FAILED); + fluid_return_val_if_fail(0 <= root_key && root_key <= 127, FLUID_FAILED); + + sample->origpitch = root_key; + sample->pitchadj = fine_tune; + + return FLUID_OK; +} + + +/** + * Validate parameters of a sample + * + */ +int fluid_sample_validate(fluid_sample_t *sample, unsigned int buffer_size) +{ +#define EXCLUSIVE_FLAGS (FLUID_SAMPLETYPE_MONO | FLUID_SAMPLETYPE_RIGHT | FLUID_SAMPLETYPE_LEFT) + static const unsigned int supported_flags = EXCLUSIVE_FLAGS | FLUID_SAMPLETYPE_LINKED | FLUID_SAMPLETYPE_OGG_VORBIS | FLUID_SAMPLETYPE_ROM; + + /* ROM samples are unusable for us by definition */ + if(sample->sampletype & FLUID_SAMPLETYPE_ROM) + { + FLUID_LOG(FLUID_WARN, "Sample '%s': ROM sample ignored", sample->name); + return FLUID_FAILED; + } + + if(sample->sampletype & ~supported_flags) + { + FLUID_LOG(FLUID_WARN, "Sample '%s' has unknown flags, possibly using an unsupported compression; sample ignored", sample->name); + return FLUID_FAILED; + } + + if((sample->sampletype & EXCLUSIVE_FLAGS) & ((sample->sampletype & EXCLUSIVE_FLAGS) - 1)) + { + FLUID_LOG(FLUID_INFO, "Sample '%s' should be either mono or left or right; using it anyway", sample->name); + } + + if((sample->sampletype & FLUID_SAMPLETYPE_LINKED) && (sample->sampletype & EXCLUSIVE_FLAGS)) + { + FLUID_LOG(FLUID_INFO, "Linked sample '%s' should not be mono, left or right at the same time; using it anyway", sample->name); + } + + if((sample->sampletype & EXCLUSIVE_FLAGS) == 0) + { + FLUID_LOG(FLUID_INFO, "Sample '%s' has no flags set, assuming mono", sample->name); + sample->sampletype = FLUID_SAMPLETYPE_MONO; + } + + /* Ogg vorbis compressed samples in the SF3 format use byte indices for + * sample start and end pointers before decompression. Standard SF2 samples + * use sample word indices for all pointers, so use half the buffer_size + * for validation. */ + if(!(sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS)) + { + if(buffer_size % 2) + { + FLUID_LOG(FLUID_WARN, "Sample '%s': invalid buffer size", sample->name); + return FLUID_FAILED; + } + + buffer_size /= 2; + } + + if((sample->end > buffer_size) || (sample->start >= sample->end)) + { + FLUID_LOG(FLUID_WARN, "Sample '%s': invalid start/end file positions", sample->name); + return FLUID_FAILED; + } + + return FLUID_OK; +#undef EXCLUSIVE_FLAGS +} + +/* Check the sample loop pointers and optionally convert them to something + * usable in case they are broken. Return a boolean indicating if the pointers + * have been modified, so the user can be notified of possible audio glitches. + */ +int fluid_sample_sanitize_loop(fluid_sample_t *sample, unsigned int buffer_size) +{ + int modified = FALSE; + unsigned int max_end = buffer_size / 2; + /* In fluid_sample_t the sample end pointer points to the last sample, not + * to the data word after the last sample. FIXME: why? */ + unsigned int sample_end = sample->end + 1; + + if(sample->loopstart == sample->loopend) + { + /* Some SoundFonts disable loops by setting loopstart = loopend. While + * technically invalid, we decided to accept those samples anyway. + * Before fluidsynth 2.2.5 we've set those indices to zero, as this + * change was believed to be inaudible. This turned out to be an + * incorrect assumption, as the loop points may still be modified by + * loop offset modulators afterwards. + */ + if(sample->loopstart != sample->start) + { + // Many soundfonts set loopstart == loopend == sample->start to disabled to loop. + // Only report cases where it's not equal to the sample->start, to avoid spam. + FLUID_LOG(FLUID_DBG, "Sample '%s': zero length loop detected: loopstart == loopend == '%d', sample start '%d', using it anyway", + sample->name, sample->loopstart, sample->start); + } + } + else if(sample->loopstart > sample->loopend) + { + unsigned int tmp; + + /* If loop start and end are reversed, try to swap them around and + * continue validation */ + FLUID_LOG(FLUID_DBG, "Sample '%s': reversed loop pointers '%d' - '%d', trying to fix", + sample->name, sample->loopstart, sample->loopend); + tmp = sample->loopstart; + sample->loopstart = sample->loopend; + sample->loopend = tmp; + modified = TRUE; + } + + /* The SoundFont 2.4 spec defines the loopstart index as the first sample + * point of the loop while loopend is the first point AFTER the last sample + * of the loop. However we cannot be sure whether any of loopend or end is + * correct. Hours of thinking through this have concluded that it would be + * best practice to mangle with loops as little as necessary by only making + * sure the pointers are within sample->start to max_end. Incorrect + * soundfont shall preferably fail loudly. */ + if((sample->loopstart < sample->start) || (sample->loopstart > max_end)) + { + FLUID_LOG(FLUID_DBG, "Sample '%s': invalid loop start '%d', setting to sample start '%d'", + sample->name, sample->loopstart, sample->start); + sample->loopstart = sample->start; + modified = TRUE; + } + + if((sample->loopend < sample->start) || (sample->loopend > max_end)) + { + FLUID_LOG(FLUID_DBG, "Sample '%s': invalid loop end '%d', setting to sample end '%d'", + sample->name, sample->loopend, sample_end); + sample->loopend = sample_end; + modified = TRUE; + } + + if((sample->loopstart > sample_end) || (sample->loopend > sample_end)) + { + FLUID_LOG(FLUID_DBG, "Sample '%s': loop range '%d - %d' after sample end '%d', using it anyway", + sample->name, sample->loopstart, sample->loopend, sample_end); + } + + return modified; +} diff --git a/libs/fluidsynth/src/sfloader/fluid_sfont.h b/libs/fluidsynth/src/sfloader/fluid_sfont.h new file mode 100644 index 00000000000..9a42c02eb19 --- /dev/null +++ b/libs/fluidsynth/src/sfloader/fluid_sfont.h @@ -0,0 +1,189 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#ifndef _PRIV_FLUID_SFONT_H +#define _PRIV_FLUID_SFONT_H + +#include "fluidsynth.h" + +int fluid_sample_validate(fluid_sample_t *sample, unsigned int max_end); +int fluid_sample_sanitize_loop(fluid_sample_t *sample, unsigned int max_end); + +/* + * Utility macros to access soundfonts, presets, and samples + */ + +#define fluid_sfloader_delete(_loader) { if ((_loader) && (_loader)->free) (*(_loader)->free)(_loader); } +#define fluid_sfloader_load(_loader, _filename) (*(_loader)->load)(_loader, _filename) + + +#define fluid_sfont_delete_internal(_sf) ( ((_sf) && (_sf)->free)? (*(_sf)->free)(_sf) : 0) + + +#define fluid_preset_delete_internal(_preset) \ + { if ((_preset) && (_preset)->free) { (*(_preset)->free)(_preset); }} + +#define fluid_preset_noteon(_preset,_synth,_ch,_key,_vel) \ + (*(_preset)->noteon)(_preset,_synth,_ch,_key,_vel) + +#define fluid_preset_notify(_preset,_reason,_chan) \ + ( ((_preset) && (_preset)->notify) ? (*(_preset)->notify)(_preset,_reason,_chan) : FLUID_OK ) + + +#define fluid_sample_incr_ref(_sample) { (_sample)->refcount++; } + +#define fluid_sample_decr_ref(_sample) \ + (_sample)->refcount--; \ + if (((_sample)->refcount == 0) && ((_sample)->notify)) \ + (*(_sample)->notify)(_sample, FLUID_SAMPLE_DONE); + + + +/** + * File callback structure to enable custom soundfont loading (e.g. from memory). + */ +struct _fluid_file_callbacks_t +{ + fluid_sfloader_callback_open_t fopen; + fluid_sfloader_callback_read_t fread; + fluid_sfloader_callback_seek_t fseek; + fluid_sfloader_callback_close_t fclose; + fluid_sfloader_callback_tell_t ftell; +}; + +/** + * SoundFont loader structure. + */ +struct _fluid_sfloader_t +{ + void *data; /**< User defined data pointer used by _fluid_sfloader_t::load() */ + + /** Callback structure specifying file operations used during soundfont loading to allow custom loading, such as from memory */ + fluid_file_callbacks_t file_callbacks; + + fluid_sfloader_free_t free; + + fluid_sfloader_load_t load; +}; + +/** + * Virtual SoundFont instance structure. + */ +struct _fluid_sfont_t +{ + void *data; /**< User defined data */ + int id; /**< SoundFont ID */ + int refcount; /**< SoundFont reference count (1 if no presets referencing it) */ + int bankofs; /**< Bank offset */ + + fluid_sfont_free_t free; + + fluid_sfont_get_name_t get_name; + + fluid_sfont_get_preset_t get_preset; + + fluid_sfont_iteration_start_t iteration_start; + + fluid_sfont_iteration_next_t iteration_next; +}; + +/** + * Virtual SoundFont preset. + */ +struct _fluid_preset_t +{ + void *data; /**< User supplied data */ + fluid_sfont_t *sfont; /**< Parent virtual SoundFont */ + + fluid_preset_free_t free; + + fluid_preset_get_name_t get_name; + + fluid_preset_get_banknum_t get_banknum; + + fluid_preset_get_num_t get_num; + + fluid_preset_noteon_t noteon; + + /** + * Virtual SoundFont preset notify method. + * @param preset Virtual SoundFont preset + * @param reason #FLUID_PRESET_SELECTED or #FLUID_PRESET_UNSELECTED + * @param chan MIDI channel number + * @return Should return #FLUID_OK + * + * Implement this optional method if the preset needs to be notified about + * preset select and unselect events. + * + * This method may be called from within synthesis context and therefore + * should be as efficient as possible and not perform any operations considered + * bad for realtime audio output (memory allocations and other OS calls). + */ + int (*notify)(fluid_preset_t *preset, int reason, int chan); +}; + +/** + * Virtual SoundFont sample. + */ +struct _fluid_sample_t +{ + char name[21]; /**< Sample name */ + + /* The following four sample pointers store the original pointers from the Soundfont + * file. They are never changed after loading and are used to re-create the + * actual sample pointers after a sample has been unloaded and loaded again. The + * actual sample pointers get modified during loading for SF3 (compressed) samples + * and individually loaded SF2 samples. */ + unsigned int source_start; + unsigned int source_end; + unsigned int source_loopstart; + unsigned int source_loopend; + + unsigned int start; /**< Start index */ + unsigned int end; /**< End index, index of last valid sample point (contrary to SF spec) */ + unsigned int loopstart; /**< Loop start index */ + unsigned int loopend; /**< Loop end index, first point following the loop (superimposed on loopstart) */ + + unsigned int samplerate; /**< Sample rate */ + int origpitch; /**< Original pitch (MIDI note number, 0-127) */ + int pitchadj; /**< Fine pitch adjustment (+/- 99 cents) */ + int sampletype; /**< Specifies the type of this sample as indicated by the #fluid_sample_type enum */ + int auto_free; /**< TRUE if _fluid_sample_t::data and _fluid_sample_t::data24 should be freed upon sample destruction */ + short *data; /**< Pointer to the sample's 16 bit PCM data */ + char *data24; /**< If not NULL, pointer to the least significant byte counterparts of each sample data point in order to create 24 bit audio samples */ + + int amplitude_that_reaches_noise_floor_is_valid; /**< Indicates if \a amplitude_that_reaches_noise_floor is valid (TRUE), set to FALSE initially to calculate. */ + double amplitude_that_reaches_noise_floor; /**< The amplitude at which the sample's loop will be below the noise floor. For voice off optimization, calculated automatically. */ + + unsigned int refcount; /**< Count of voices using this sample */ + int preset_count; /**< Count of selected presets using this sample (used for dynamic sample loading) */ + + /** + * Implement this function to receive notification when sample is no longer used. + * @param sample Virtual SoundFont sample + * @param reason #FLUID_SAMPLE_DONE only currently + * @return Should return #FLUID_OK + */ + int (*notify)(fluid_sample_t *sample, int reason); +}; + + +#endif /* _PRIV_FLUID_SFONT_H */ diff --git a/libs/fluidsynth/src/synth/fluid_chan.c b/libs/fluidsynth/src/synth/fluid_chan.c new file mode 100644 index 00000000000..0f2eecb44e0 --- /dev/null +++ b/libs/fluidsynth/src/synth/fluid_chan.c @@ -0,0 +1,732 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include "fluid_chan.h" +#include "fluid_mod.h" +#include "fluid_synth.h" +#include "fluid_sfont.h" + +/* Field shift amounts for sfont_bank_prog bit field integer */ +#define PROG_SHIFTVAL 0 +#define BANK_SHIFTVAL 8 +#define SFONT_SHIFTVAL 22 + +/* Field mask values for sfont_bank_prog bit field integer */ +#define PROG_MASKVAL 0x000000FF /* Bit 7 is used to indicate unset state */ +#define BANK_MASKVAL 0x003FFF00 +#define BANKLSB_MASKVAL 0x00007F00 +#define BANKMSB_MASKVAL 0x003F8000 +#define SFONT_MASKVAL 0xFFC00000 + + +static void fluid_channel_init(fluid_channel_t *chan); + + +fluid_channel_t * +new_fluid_channel(fluid_synth_t *synth, int num) +{ + fluid_channel_t *chan; + + chan = FLUID_NEW(fluid_channel_t); + + if(chan == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + chan->synth = synth; + chan->channum = num; + chan->preset = NULL; + chan->tuning = NULL; + + fluid_channel_init(chan); + fluid_channel_init_ctrl(chan, 0); + + return chan; +} + +static void +fluid_channel_init(fluid_channel_t *chan) +{ + fluid_preset_t *newpreset; + int i, prognum, banknum; + + chan->sostenuto_orderid = 0; + /*--- Init poly/mono modes variables --------------------------------------*/ + chan->mode = 0; + chan->mode_val = 0; + + /* monophonic list initialization */ + for(i = 0; i < FLUID_CHANNEL_SIZE_MONOLIST; i++) + { + chan->monolist[i].next = i + 1; + } + + chan->monolist[FLUID_CHANNEL_SIZE_MONOLIST - 1].next = 0; /* ending element chained to the 1st */ + chan->i_last = chan->n_notes = 0; /* clears the list */ + chan->i_first = chan->monolist[chan->i_last].next; /* first note index in the list */ + fluid_channel_clear_prev_note(chan); /* Mark previous note invalid */ + /*---*/ + chan->key_mono_sustained = INVALID_NOTE; /* No previous mono note sustained */ + chan->legatomode = FLUID_CHANNEL_LEGATO_MODE_MULTI_RETRIGGER; /* Default mode */ + chan->portamentomode = FLUID_CHANNEL_PORTAMENTO_MODE_LEGATO_ONLY; /* Default mode */ + /*--- End of poly/mono initialization --------------------------------------*/ + + chan->channel_type = (chan->channum == 9) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC; + prognum = 0; + banknum = (chan->channel_type == CHANNEL_TYPE_DRUM) ? DRUM_INST_BANK : 0; + + chan->sfont_bank_prog = 0 << SFONT_SHIFTVAL | banknum << BANK_SHIFTVAL + | prognum << PROG_SHIFTVAL; + + newpreset = fluid_synth_find_preset(chan->synth, banknum, prognum); + fluid_channel_set_preset(chan, newpreset); + + chan->interp_method = FLUID_INTERP_DEFAULT; + chan->tuning_bank = 0; + chan->tuning_prog = 0; + chan->nrpn_select = 0; + chan->nrpn_active = 0; + + if(chan->tuning) + { + fluid_tuning_unref(chan->tuning, 1); + chan->tuning = NULL; + } +} + +/* + @param is_all_ctrl_off if nonzero, only resets some controllers, according to + https://www.midi.org/techspecs/rp15.php +*/ +void +fluid_channel_init_ctrl(fluid_channel_t *chan, int is_all_ctrl_off) +{ + int i; + + chan->channel_pressure = 0; + chan->pitch_bend = 0x2000; /* Range is 0x4000, pitch bend wheel starts in centered position */ + + for(i = 0; i < GEN_LAST; i++) + { + chan->gen[i] = 0.0f; + } + + if(is_all_ctrl_off) + { + for(i = 0; i < ALL_SOUND_OFF; i++) + { + if(i >= EFFECTS_DEPTH1 && i <= EFFECTS_DEPTH5) + { + continue; + } + + if(i >= SOUND_CTRL1 && i <= SOUND_CTRL10) + { + continue; + } + + if(i == BANK_SELECT_MSB || i == BANK_SELECT_LSB || i == VOLUME_MSB || + i == VOLUME_LSB || i == PAN_MSB || i == PAN_LSB || + i == BALANCE_MSB || i == BALANCE_LSB + ) + { + continue; + } + + fluid_channel_set_cc(chan, i, 0); + } + } + else + { + for(i = 0; i < 128; i++) + { + fluid_channel_set_cc(chan, i, 0); + } + + chan->previous_cc_breath = 0;/* Reset previous breath */ + } + /* Unconditionally clear PTC receive (issue #1050) */ + fluid_channel_clear_portamento(chan); + + /* Reset polyphonic key pressure on all voices */ + for(i = 0; i < 128; i++) + { + fluid_channel_set_key_pressure(chan, i, 0); + } + + /* Set RPN controllers to NULL state */ + fluid_channel_set_cc(chan, RPN_LSB, 127); + fluid_channel_set_cc(chan, RPN_MSB, 127); + + /* Set NRPN controllers to NULL state */ + fluid_channel_set_cc(chan, NRPN_LSB, 127); + fluid_channel_set_cc(chan, NRPN_MSB, 127); + + /* Expression (MSB & LSB) */ + fluid_channel_set_cc(chan, EXPRESSION_MSB, 127); + fluid_channel_set_cc(chan, EXPRESSION_LSB, 127); + + if(!is_all_ctrl_off) + { + + chan->pitch_wheel_sensitivity = 2; /* two semi-tones */ + + /* Just like panning, a value of 64 indicates no change for sound ctrls */ + for(i = SOUND_CTRL1; i <= SOUND_CTRL10; i++) + { + fluid_channel_set_cc(chan, i, 64); + } + + /* Volume / initial attenuation (MSB & LSB) */ + fluid_channel_set_cc(chan, VOLUME_MSB, 100); + fluid_channel_set_cc(chan, VOLUME_LSB, 0); + + /* Pan (MSB & LSB) */ + fluid_channel_set_cc(chan, PAN_MSB, 64); + fluid_channel_set_cc(chan, PAN_LSB, 0); + + /* Balance (MSB & LSB) */ + fluid_channel_set_cc(chan, BALANCE_MSB, 64); + fluid_channel_set_cc(chan, BALANCE_LSB, 0); + + /* Reverb */ + /* fluid_channel_set_cc (chan, EFFECTS_DEPTH1, 40); */ + /* Note: although XG standard specifies the default amount of reverb to + be 40, most people preferred having it at zero. + See https://lists.gnu.org/archive/html/fluid-dev/2009-07/msg00016.html */ + } +} + +/* Only called by delete_fluid_synth(), so no need to queue a preset free event */ +void +delete_fluid_channel(fluid_channel_t *chan) +{ + fluid_return_if_fail(chan != NULL); + + FLUID_FREE(chan); +} + +void +fluid_channel_reset(fluid_channel_t *chan) +{ + fluid_channel_init(chan); + fluid_channel_init_ctrl(chan, 0); +} + +/* Should only be called from synthesis context */ +int +fluid_channel_set_preset(fluid_channel_t *chan, fluid_preset_t *preset) +{ + fluid_sfont_t *sfont; + + if(chan->preset == preset) + { + return FLUID_OK; + } + + if(chan->preset) + { + sfont = chan->preset->sfont; + sfont->refcount--; + } + + fluid_preset_notify(chan->preset, FLUID_PRESET_UNSELECTED, chan->channum); + + chan->preset = preset; + + if(preset) + { + sfont = preset->sfont; + sfont->refcount++; + } + + fluid_preset_notify(preset, FLUID_PRESET_SELECTED, chan->channum); + + return FLUID_OK; +} + +/* Set SoundFont ID, MIDI bank and/or program. Use -1 to use current value. */ +void +fluid_channel_set_sfont_bank_prog(fluid_channel_t *chan, int sfontnum, + int banknum, int prognum) +{ + int oldval, newval, oldmask; + + newval = ((sfontnum != -1) ? sfontnum << SFONT_SHIFTVAL : 0) + | ((banknum != -1) ? banknum << BANK_SHIFTVAL : 0) + | ((prognum != -1) ? prognum << PROG_SHIFTVAL : 0); + + oldmask = ((sfontnum != -1) ? 0 : SFONT_MASKVAL) + | ((banknum != -1) ? 0 : BANK_MASKVAL) + | ((prognum != -1) ? 0 : PROG_MASKVAL); + + oldval = chan->sfont_bank_prog; + newval = (newval & ~oldmask) | (oldval & oldmask); + chan->sfont_bank_prog = newval; +} + +/* Set bank LSB 7 bits */ +void +fluid_channel_set_bank_lsb(fluid_channel_t *chan, int banklsb) +{ + int oldval, newval, style; + + style = chan->synth->bank_select; + + if(style == FLUID_BANK_STYLE_GM || + style == FLUID_BANK_STYLE_GS) + { + return; /* ignored */ + } + + oldval = chan->sfont_bank_prog; + + if(style == FLUID_BANK_STYLE_XG) + { + newval = (oldval & ~BANK_MASKVAL) | (banklsb << BANK_SHIFTVAL); + } + else /* style == FLUID_BANK_STYLE_MMA */ + { + newval = (oldval & ~BANKLSB_MASKVAL) | (banklsb << BANK_SHIFTVAL); + } + + chan->sfont_bank_prog = newval; +} + +/* Set bank MSB 7 bits */ +void +fluid_channel_set_bank_msb(fluid_channel_t *chan, int bankmsb) +{ + int oldval, newval, style; + + style = chan->synth->bank_select; + + if(style == FLUID_BANK_STYLE_XG) + { + /* XG bank, do drum-channel auto-switch */ + /* The number "120" was based on several keyboards having drums at 120 - 127, + reference: https://lists.nongnu.org/archive/html/fluid-dev/2011-02/msg00003.html */ + chan->channel_type = (120 <= bankmsb) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC; + return; + } + + if(style == FLUID_BANK_STYLE_GM || + chan->channel_type == CHANNEL_TYPE_DRUM) + { + return; /* ignored */ + } + + oldval = chan->sfont_bank_prog; + + if(style == FLUID_BANK_STYLE_GS) + { + newval = (oldval & ~BANK_MASKVAL) | (bankmsb << BANK_SHIFTVAL); + } + else /* style == FLUID_BANK_STYLE_MMA */ + { + newval = (oldval & ~BANKMSB_MASKVAL) | (bankmsb << (BANK_SHIFTVAL + 7)); + } + + chan->sfont_bank_prog = newval; + +} + +/* Get SoundFont ID, MIDI bank and/or program. Use NULL to ignore a value. */ +void +fluid_channel_get_sfont_bank_prog(fluid_channel_t *chan, int *sfont, + int *bank, int *prog) +{ + int sfont_bank_prog; + + sfont_bank_prog = chan->sfont_bank_prog; + + if(sfont) + { + *sfont = (sfont_bank_prog & SFONT_MASKVAL) >> SFONT_SHIFTVAL; + } + + if(bank) + { + *bank = (sfont_bank_prog & BANK_MASKVAL) >> BANK_SHIFTVAL; + } + + if(prog) + { + *prog = (sfont_bank_prog & PROG_MASKVAL) >> PROG_SHIFTVAL; + } +} + +/** + * Compute the pitch for a key after applying Fluidsynth's tuning functionality + * and channel coarse/fine tunings. + * @param chan fluid_channel_t + * @param key MIDI note number (0-127) + * @return the pitch of the key + */ +fluid_real_t fluid_channel_get_key_pitch(fluid_channel_t *chan, int key) +{ + if(chan->tuning) + { + return fluid_tuning_get_pitch(chan->tuning, key) + + 100.0f * fluid_channel_get_gen(chan, GEN_COARSETUNE) + + fluid_channel_get_gen(chan, GEN_FINETUNE); + } + else + { + return key * 100.0f; + } +} + +/** + * Updates legato/ staccato playing state + * The function is called: + * - on noteon before adding a note into the monolist. + * - on noteoff after removing a note out of the monolist. + * @param chan fluid_channel_t. +*/ +static void +fluid_channel_update_legato_staccato_state(fluid_channel_t *chan) +{ + /* Updates legato/ staccato playing state */ + if(chan->n_notes) + { + chan->mode |= FLUID_CHANNEL_LEGATO_PLAYING; /* Legato state */ + } + else + { + chan->mode &= ~ FLUID_CHANNEL_LEGATO_PLAYING; /* Staccato state */ + } +} + +/** + * Adds a note into the monophonic list. The function is part of the legato + * detector. fluid_channel_add_monolist() is intended to be called by + * fluid_synth_noteon_mono_LOCAL(). + * + * When a note is added at noteOn each element is use in the forward direction + * and indexed by i_last variable. + * + * @param chan fluid_channel_t. + * @param key MIDI note number (0-127). + * @param vel MIDI velocity (0-127, 0=noteoff). + * @param onenote. When 1 the function adds the note but the monophonic list + * keeps only one note (used on noteOn poly). + * Note: i_last index keeps a trace of the most recent note added. + * prev_note keeps a trace of the note prior i_last note. + * FLUID_CHANNEL_LEGATO_PLAYING bit keeps trace of legato/staccato playing state. + * + * More information in FluidPolyMono-0004.pdf chapter 4 (Appendices). +*/ +void +fluid_channel_add_monolist(fluid_channel_t *chan, unsigned char key, + unsigned char vel, unsigned char onenote) +{ + unsigned char i_last = chan->i_last; + /* Updates legato/ staccato playing state */ + fluid_channel_update_legato_staccato_state(chan); + + if(chan->n_notes) + { + /* keeps trace of the note prior last note */ + chan->prev_note = chan->monolist[i_last].note; + } + + /* moves i_last forward before writing new note */ + i_last = chan->monolist[i_last].next; + chan->i_last = i_last; /* now ilast indexes the last note */ + chan->monolist[i_last].note = key; /* we save note and velocity */ + chan->monolist[i_last].vel = vel; + + if(onenote) + { + /* clears monolist before one note addition */ + chan->i_first = i_last; + chan->n_notes = 0; + } + + if(chan->n_notes < FLUID_CHANNEL_SIZE_MONOLIST) + { + chan->n_notes++; /* updates n_notes */ + } + else + { + /* The end of buffer is reach. So circular motion for i_first */ + /* i_first index is moved forward */ + chan->i_first = chan->monolist[i_last].next; + } +} + +/** + * Searching a note in the monophonic list. The function is part of the legato + * detector. fluid_channel_search_monolist() is intended to be called by + * fluid_synth_noteoff_mono_LOCAL(). + * + * The search starts from the first note in the list indexed by i_first + + * @param chan fluid_channel_t. + * @param key MIDI note number (0-127) to search. + * @param i_prev pointer on returned index of the note prior the note to search. + * @return index of the note if find, FLUID_FAILED otherwise. + * + */ +int +fluid_channel_search_monolist(fluid_channel_t *chan, unsigned char key, int *i_prev) +{ + short n = chan->n_notes; /* number of notes in monophonic list */ + short j, i = chan->i_first; /* searching starts from i_first included */ + + for(j = 0 ; j < n ; j++) + { + if(chan->monolist[i].note == key) + { + if(i == chan->i_first) + { + /* tracking index of the previous note (i_prev) */ + for(j = chan->i_last ; n < FLUID_CHANNEL_SIZE_MONOLIST; n++) + { + j = chan->monolist[j].next; + } + + * i_prev = j; /* returns index of the previous note */ + } + + return i; /* returns index of the note to search */ + } + + * i_prev = i; /* tracking index of the previous note (i_prev) */ + i = chan->monolist[i].next; /* next element */ + } + + return FLUID_FAILED; /* not found */ +} + +/** + * removes a note from the monophonic list. The function is part of + * the legato detector. + * fluid_channel_remove_monolist() is intended to be called by + * fluid_synth_noteoff_mono_LOCAL(). + * + * When a note is removed at noteOff the element concerned is fast unlinked + * and relinked after the i_last element. + * + * @param chan fluid_channel_t. + * @param + * i, index of the note to remove. If i is invalid or the list is + * empty, the function do nothing and returns FLUID_FAILED. + * @param + * On input, i_prev is a pointer on index of the note previous i. + * On output i_prev is a pointer on index of the note previous i if i is the last note + * in the list,FLUID_FAILED otherwise. When the returned index is valid it means + * a legato detection on noteoff. + * + * Note: the following variables in Channel keeps trace of the situation. + * - i_last index keeps a trace of the most recent note played even if + * the list is empty. + * - prev_note keeps a trace of the note removed if it is i_last. + * - FLUID_CHANNEL_LEGATO_PLAYING bit keeps a trace of legato/staccato playing state. + * + * More information in FluidPolyMono-0004.pdf chapter 4 (Appendices). + */ +void +fluid_channel_remove_monolist(fluid_channel_t *chan, int i, int *i_prev) +{ + unsigned char i_last = chan->i_last; + + /* checks if index is valid */ + if(i < 0 || i >= FLUID_CHANNEL_SIZE_MONOLIST || !chan->n_notes) + { + * i_prev = FLUID_FAILED; + } + + /* The element is about to be removed and inserted between i_last and next */ + /* Note: when i is egal to i_last or egal to i_first, removing/inserting + isn't necessary */ + if(i == i_last) + { + /* Removing/Inserting isn't necessary */ + /* keeps trace of the note prior last note */ + chan->prev_note = chan->monolist[i_last].note; + /* moves i_last backward to the previous */ + chan->i_last = *i_prev; /* i_last index is moved backward */ + } + else + { + /* i is before i_last */ + if(i == chan->i_first) + { + /* Removing/inserting isn't necessary */ + /* i_first index is moved forward to the next element*/ + chan->i_first = chan->monolist[i].next; + } + else + { + /* i is between i_first and i_last */ + /* Unlinks element i and inserts after i_last */ + chan->monolist[* i_prev].next = chan->monolist[i].next; /* unlinks i */ + /*inserts i after i_last */ + chan->monolist[i].next = chan->monolist[i_last].next; + chan->monolist[i_last].next = i; + } + + * i_prev = FLUID_FAILED; + } + + chan->n_notes--; /* updates the number of note in the list */ + /* Updates legato/ staccato playing state */ + fluid_channel_update_legato_staccato_state(chan); +} + +/** + * On noteOff on a polyphonic channel,the monophonic list is fully flushed. + * + * @param chan fluid_channel_t. + * Note: i_last index keeps a trace of the most recent note played even if + * the list is empty. + * prev_note keeps a trace of the note i_last . + * FLUID_CHANNEL_LEGATO_PLAYING bit keeps a trace of legato/staccato playing. + */ +void fluid_channel_clear_monolist(fluid_channel_t *chan) +{ + /* keeps trace off the most recent note played */ + chan->prev_note = chan->monolist[chan->i_last].note; + + /* flushes the monolist */ + chan->i_first = chan->monolist[chan->i_last].next; + chan->n_notes = 0; + /* Update legato/ sataccato playing state */ + chan->mode &= ~ FLUID_CHANNEL_LEGATO_PLAYING; /* Staccato state */ +} + +/** + * On noteOn on a polyphonic channel,adds the note into the monophonic list + * keeping only this note. + * @param + * chan fluid_channel_t. + * key, vel, note and velocity added in the monolist + * Note: i_last index keeps a trace of the most recent note inserted. + * prev_note keeps a trace of the note prior i_last note. + * FLUID_CHANNEL_LEGATO_PLAYING bit keeps trace of legato/staccato playing. + */ +void fluid_channel_set_onenote_monolist(fluid_channel_t *chan, unsigned char key, + unsigned char vel) +{ + fluid_channel_add_monolist(chan, key, vel, 1); +} + +/** + * The function changes the state (Valid/Invalid) of the previous note played in + * a staccato manner (fluid_channel_prev_note()). + * When potamento mode 'each note' or 'staccato only' is selected, on next + * noteOn a portamento will be started from the most recent note played + * staccato. + * It will be possible that it isn't appropriate. To give the musician the + * possibility to choose a portamento from this note , prev_note will be forced + * to invalid state on noteOff if portamento pedal is Off. + * + * The function is intended to be called when the following event occurs: + * - On noteOff (in poly or mono mode), to mark prev_note invalid. + * - On Portamento Off(in poly or mono mode), to mark prev_note invalid. + * @param chan fluid_channel_t. + */ +void fluid_channel_invalid_prev_note_staccato(fluid_channel_t *chan) +{ + /* checks if the playing is staccato */ + if(!(chan->mode & FLUID_CHANNEL_LEGATO_PLAYING)) + { + + /* checks if portamento pedal is off */ + if(! fluid_channel_portamento(chan)) + { + /* forces prev_note invalid */ + fluid_channel_clear_prev_note(chan); + } + } + + /* else prev_note still remains valid for next fromkey portamento */ +} + +/** + * The function handles poly/mono commutation on legato pedal On/Off. + * @param chan fluid_channel_t. + * @param value, value of the CC legato. + */ +void fluid_channel_cc_legato(fluid_channel_t *chan, int value) +{ + /* Special handling of the monophonic list */ + if(!(chan->mode & FLUID_CHANNEL_POLY_OFF) && chan->n_notes) /* The monophonic list have notes */ + { + if(value < 64) /* legato is released */ + { + /* returns from monophonic to polyphonic with notes in the monophonic list */ + + /* The monophonic list is flushed keeping last note only + Note: i_last index keeps a trace of the most recent note played. + prev_note keeps a trace of the note i_last. + FLUID_CHANNEL_LEGATO_PLAYING bit keeps trace of legato/staccato playing. + */ + chan->i_first = chan->i_last; + chan->n_notes = 1; + } + else /* legato is depressed */ + { + /* Inters in monophonic from polyphonic with note in monophonic list */ + /* Stops the running note to remain coherent with Breath Sync mode */ + if((chan->mode & FLUID_CHANNEL_BREATH_SYNC) && !fluid_channel_breath_msb(chan)) + { + fluid_synth_noteoff_monopoly(chan->synth, chan->channum, + fluid_channel_last_note(chan), 1); + } + } + } +} + +/** + * The function handles CC Breath On/Off detection. When a channel is in + * Breath Sync mode and in monophonic playing, the breath controller allows + * to trigger noteon/noteoff note when the musician starts to breath (noteon) and + * stops to breath (noteoff). + * @param chan fluid_channel_t. + * @param value, value of the CC Breath.. + */ +void fluid_channel_cc_breath_note_on_off(fluid_channel_t *chan, int value) +{ + if((chan->mode & FLUID_CHANNEL_BREATH_SYNC) && fluid_channel_is_playing_mono(chan) && + (chan->n_notes)) + { + /* The monophonic list isn't empty */ + if((value > 0) && (chan->previous_cc_breath == 0)) + { + /* CC Breath On detection */ + fluid_synth_noteon_mono_staccato(chan->synth, chan->channum, + fluid_channel_last_note(chan), + fluid_channel_last_vel(chan)); + } + else if((value == 0) && (chan->previous_cc_breath > 0)) + { + /* CC Breath Off detection */ + fluid_synth_noteoff_monopoly(chan->synth, chan->channum, + fluid_channel_last_note(chan), 1); + } + } + + chan->previous_cc_breath = value; +} diff --git a/libs/fluidsynth/src/synth/fluid_chan.h b/libs/fluidsynth/src/synth/fluid_chan.h new file mode 100644 index 00000000000..96eb02e37f5 --- /dev/null +++ b/libs/fluidsynth/src/synth/fluid_chan.h @@ -0,0 +1,276 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUID_CHAN_H +#define _FLUID_CHAN_H + +#include "fluidsynth_priv.h" +#include "fluid_midi.h" +#include "fluid_tuning.h" + +/* The mononophonic list is part of the legato detector for monophonic mode */ +/* see fluid_synth_monopoly.c about a description of the legato detector device */ +/* Size of the monophonic list + - 1 is the minimum. it allows playing legato passage of any number + of notes on noteon only. + - Size above 1 allows playing legato on noteon but also on noteOff. + This allows the musician to play fast trills. + This feature is particularly usful when the MIDI input device is a keyboard. + Choosing a size of 10 is sufficient (because most musicians have only 10 + fingers when playing a monophonic instrument). +*/ +#define FLUID_CHANNEL_SIZE_MONOLIST 10 + +/* + + The monophonic list + +------------------------------------------------+ + | +----+ +----+ +----+ +----+ | + | |note| |note| |note| |note| | + +--->|vel |-->|vel |-->....-->|vel |-->|vel |----+ + +----+ +----+ +----+ +----+ + /|\ /|\ + | | + i_first i_last + + The monophonic list is a circular buffer of FLUID_CHANNEL_SIZE_MONOLIST elements. + Each element is linked forward at initialisation time. + - when a note is added at noteOn (see fluid_channel_add_monolist()) each + element is use in the forward direction and indexed by i_last variable. + - when a note is removed at noteOff (see fluid_channel_remove_monolist()), + the element concerned is fast unlinked and relinked after the i_last element. + + The most recent note added is indexed by i_last. + The most ancient note added is the first note indexed by i_first. i_first is + moving in the forward direction in a circular manner. + +*/ +struct mononote +{ + unsigned char next; /* next note */ + unsigned char note; /* note */ + unsigned char vel; /* velocity */ +}; + +/* + * fluid_channel_t + * + * Mutual exclusion notes (as of 1.1.2): + * None - everything should have been synchronized by the synth. + */ +struct _fluid_channel_t +{ + fluid_synth_t *synth; /**< Parent synthesizer instance */ + int channum; /**< MIDI channel number */ + + /* Poly Mono variables see macro access description */ + int mode; /**< Poly Mono mode */ + int mode_val; /**< number of channel in basic channel group */ + + /* monophonic list - legato detector */ + unsigned char i_first; /**< First note index */ + unsigned char i_last; /**< most recent note index since the most recent add */ + unsigned char prev_note; /**< previous note of the most recent add/remove */ + unsigned char n_notes; /**< actual number of notes in the list */ + struct mononote monolist[FLUID_CHANNEL_SIZE_MONOLIST]; /**< monophonic list */ + + unsigned char key_mono_sustained; /**< previous sustained monophonic note */ + unsigned char previous_cc_breath; /**< Previous Breath */ + enum fluid_channel_legato_mode legatomode; /**< legato mode */ + enum fluid_channel_portamento_mode portamentomode; /**< portamento mode */ + /*- End of Poly/mono variables description */ + + unsigned char cc[128]; /**< MIDI controller values from [0;127] */ + unsigned char key_pressure[128]; /**< MIDI polyphonic key pressure from [0;127] */ + + /* Drum channel flag, CHANNEL_TYPE_MELODIC, or CHANNEL_TYPE_DRUM. */ + enum fluid_midi_channel_type channel_type; + enum fluid_interp interp_method; /**< Interpolation method (enum fluid_interp) */ + + unsigned char channel_pressure; /**< MIDI channel pressure from [0;127] */ + unsigned char pitch_wheel_sensitivity; /**< Current pitch wheel sensitivity */ + short pitch_bend; /**< Current pitch bend value */ + /* Sostenuto order id gives the order of SostenutoOn event. + * This value is useful to known when the sostenuto pedal is depressed + * (before or after a key note). We need to compare SostenutoOrderId with voice id. + */ + unsigned int sostenuto_orderid; + + int tuning_bank; /**< Current tuning bank number */ + int tuning_prog; /**< Current tuning program number */ + fluid_tuning_t *tuning; /**< Micro tuning */ + + fluid_preset_t *preset; /**< Selected preset */ + int sfont_bank_prog; /**< SoundFont ID (bit 21-31), bank (bit 7-20), program (bit 0-6) */ + + /* NRPN system */ + enum fluid_gen_type nrpn_select; /* Generator ID of SoundFont NRPN message */ + char nrpn_active; /* 1 if data entry CCs are for NRPN, 0 if RPN */ + + /* The values of the generators, set by NRPN messages, or by + * fluid_synth_set_gen(), are cached in the channel so they can be + * applied to future notes. They are copied to a voice's generators + * in fluid_voice_init(), which calls fluid_gen_init(). */ + fluid_real_t gen[GEN_LAST]; +}; + +fluid_channel_t *new_fluid_channel(fluid_synth_t *synth, int num); +void fluid_channel_init_ctrl(fluid_channel_t *chan, int is_all_ctrl_off); +void delete_fluid_channel(fluid_channel_t *chan); +void fluid_channel_reset(fluid_channel_t *chan); +int fluid_channel_set_preset(fluid_channel_t *chan, fluid_preset_t *preset); +void fluid_channel_set_sfont_bank_prog(fluid_channel_t *chan, int sfont, + int bank, int prog); +void fluid_channel_set_bank_lsb(fluid_channel_t *chan, int banklsb); +void fluid_channel_set_bank_msb(fluid_channel_t *chan, int bankmsb); +void fluid_channel_get_sfont_bank_prog(fluid_channel_t *chan, int *sfont, + int *bank, int *prog); +fluid_real_t fluid_channel_get_key_pitch(fluid_channel_t *chan, int key); + +#define fluid_channel_get_preset(chan) ((chan)->preset) +#define fluid_channel_set_cc(chan, num, val) \ + ((chan)->cc[num] = (val)) +#define fluid_channel_get_cc(chan, num) \ + ((chan)->cc[num]) +#define fluid_channel_get_key_pressure(chan, key) \ + ((chan)->key_pressure[key]) +#define fluid_channel_set_key_pressure(chan, key, val) \ + ((chan)->key_pressure[key] = (val)) +#define fluid_channel_get_channel_pressure(chan) \ + ((chan)->channel_pressure) +#define fluid_channel_set_channel_pressure(chan, val) \ + ((chan)->channel_pressure = (val)) +#define fluid_channel_get_pitch_bend(chan) \ + ((chan)->pitch_bend) +#define fluid_channel_set_pitch_bend(chan, val) \ + ((chan)->pitch_bend = (val)) +#define fluid_channel_get_pitch_wheel_sensitivity(chan) \ + ((chan)->pitch_wheel_sensitivity) +#define fluid_channel_set_pitch_wheel_sensitivity(chan, val) \ + ((chan)->pitch_wheel_sensitivity = (val)) +#define fluid_channel_get_num(chan) ((chan)->channum) +#define fluid_channel_set_interp_method(chan, new_method) \ + ((chan)->interp_method = (new_method)) +#define fluid_channel_get_interp_method(chan) \ + ((chan)->interp_method); +#define fluid_channel_set_tuning(_c, _t) { (_c)->tuning = _t; } +#define fluid_channel_has_tuning(_c) ((_c)->tuning != NULL) +#define fluid_channel_get_tuning(_c) ((_c)->tuning) +#define fluid_channel_get_tuning_bank(chan) \ + ((chan)->tuning_bank) +#define fluid_channel_set_tuning_bank(chan, bank) \ + ((chan)->tuning_bank = (bank)) +#define fluid_channel_get_tuning_prog(chan) \ + ((chan)->tuning_prog) +#define fluid_channel_set_tuning_prog(chan, prog) \ + ((chan)->tuning_prog = (prog)) +#define fluid_channel_portamentotime(_c) \ + ((_c)->cc[PORTAMENTO_TIME_MSB] * 128 + (_c)->cc[PORTAMENTO_TIME_LSB]) +#define fluid_channel_portamento(_c) ((_c)->cc[PORTAMENTO_SWITCH] >= 64) +#define fluid_channel_breath_msb(_c) ((_c)->cc[BREATH_MSB] > 0) +#define fluid_channel_clear_portamento(_c) ((_c)->cc[PORTAMENTO_CTRL] = INVALID_NOTE) +#define fluid_channel_legato(_c) ((_c)->cc[LEGATO_SWITCH] >= 64) +#define fluid_channel_sustained(_c) ((_c)->cc[SUSTAIN_SWITCH] >= 64) +#define fluid_channel_sostenuto(_c) ((_c)->cc[SOSTENUTO_SWITCH] >= 64) +#define fluid_channel_set_gen(_c, _n, _v) { (_c)->gen[_n] = _v; } +#define fluid_channel_get_gen(_c, _n) ((_c)->gen[_n]) +#define fluid_channel_get_min_note_length_ticks(chan) \ + ((chan)->synth->min_note_length_ticks) + +/* Macros interface to poly/mono mode variables */ +#define MASK_BASICCHANINFOS (FLUID_CHANNEL_MODE_MASK|FLUID_CHANNEL_BASIC|FLUID_CHANNEL_ENABLED) +/* Set the basic channel infos for a MIDI basic channel */ +#define fluid_channel_set_basic_channel_info(chan,Infos) \ + (chan->mode = (chan->mode & ~MASK_BASICCHANINFOS) | (Infos & MASK_BASICCHANINFOS)) +/* Reset the basic channel infos for a MIDI basic channel */ +#define fluid_channel_reset_basic_channel_info(chan) (chan->mode &= ~MASK_BASICCHANINFOS) + +/* Macros interface to breath variables */ +#define FLUID_CHANNEL_BREATH_MASK (FLUID_CHANNEL_BREATH_POLY|FLUID_CHANNEL_BREATH_MONO|FLUID_CHANNEL_BREATH_SYNC) +/* Set the breath infos for a MIDI channel */ +#define fluid_channel_set_breath_info(chan,BreathInfos) \ +(chan->mode = (chan->mode & ~FLUID_CHANNEL_BREATH_MASK) | (BreathInfos & FLUID_CHANNEL_BREATH_MASK)) +/* Get the breath infos for a MIDI channel */ +#define fluid_channel_get_breath_info(chan) (chan->mode & FLUID_CHANNEL_BREATH_MASK) + +/* Returns true when channel is mono or legato is on */ +#define fluid_channel_is_playing_mono(chan) ((chan->mode & FLUID_CHANNEL_POLY_OFF) ||\ + fluid_channel_legato(chan)) + +/* Macros interface to monophonic list variables */ +#define INVALID_NOTE (255) +/* Returns true when a note is a valid note */ +#define fluid_channel_is_valid_note(n) (n != INVALID_NOTE) +/* Marks prev_note as invalid. */ +#define fluid_channel_clear_prev_note(chan) (chan->prev_note = INVALID_NOTE) + +/* Returns the most recent note from i_last entry of the monophonic list */ +#define fluid_channel_last_note(chan) (chan->monolist[chan->i_last].note) + +/* Returns the most recent velocity from i_last entry of the monophonic list */ +#define fluid_channel_last_vel(chan) (chan->monolist[chan->i_last].vel) + +/* + prev_note is used to determine fromkey_portamento as well as + fromkey_legato (see fluid_synth_get_fromkey_portamento_legato()). + + prev_note is updated on noteOn/noteOff mono by the legato detector as this: + - On noteOn mono, before adding a new note into the monolist,the most + recent note in the list (i.e at i_last position) is kept in prev_note. + - Similarly, on noteOff mono , before removing a note out of the monolist, + the most recent note (i.e those at i_last position) is kept in prev_note. +*/ +#define fluid_channel_prev_note(chan) (chan->prev_note) + +/* Interface to poly/mono mode variables */ +enum fluid_channel_mode_flags_internal +{ + FLUID_CHANNEL_BASIC = 0x04, /**< if flag set the corresponding midi channel is a basic channel */ + FLUID_CHANNEL_ENABLED = 0x08, /**< if flag set the corresponding midi channel is enabled, else disabled, i.e. channel ignores any MIDI messages */ + + /* + FLUID_CHANNEL_LEGATO_PLAYING bit of channel mode keeps trace of the legato /staccato + state playing. + FLUID_CHANNEL_LEGATO_PLAYING bit is updated on noteOn/noteOff mono by the legato detector: + - On noteOn, before inserting a new note into the monolist. + - On noteOff, after removing a note out of the monolist. + + - On noteOn, this state is used by fluid_synth_noteon_mono_LOCAL() + to play the current note legato or staccato. + - On noteOff, this state is used by fluid_synth_noteoff_mono_LOCAL() + to play the current noteOff legato with the most recent note. + */ + /* bit7, 1: means legato playing , 0: means staccato playing */ + FLUID_CHANNEL_LEGATO_PLAYING = 0x80 +}; + +/* End of interface to monophonic list variables */ + +void fluid_channel_add_monolist(fluid_channel_t *chan, unsigned char key, unsigned char vel, unsigned char onenote); +int fluid_channel_search_monolist(fluid_channel_t *chan, unsigned char key, int *i_prev); +void fluid_channel_remove_monolist(fluid_channel_t *chan, int i, int *i_prev); +void fluid_channel_clear_monolist(fluid_channel_t *chan); +void fluid_channel_set_onenote_monolist(fluid_channel_t *chan, unsigned char key, unsigned char vel); +void fluid_channel_invalid_prev_note_staccato(fluid_channel_t *chan); +void fluid_channel_cc_legato(fluid_channel_t *chan, int value); +void fluid_channel_cc_breath_note_on_off(fluid_channel_t *chan, int value); + + +#endif /* _FLUID_CHAN_H */ diff --git a/libs/fluidsynth/src/synth/fluid_event.c b/libs/fluidsynth/src/synth/fluid_event.c new file mode 100644 index 00000000000..48b781bd7bc --- /dev/null +++ b/libs/fluidsynth/src/synth/fluid_event.c @@ -0,0 +1,863 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +/* + 2002 : API design by Peter Hanappe and Antoine Schmitt + August 2002 : Implementation by Antoine Schmitt as@gratin.org + as part of the infiniteCD author project + http://www.infiniteCD.org/ + Oct4.2002 : AS : corrected bug in heap allocation, that caused a crash during sequencer free. +*/ + + +#include "fluid_event.h" +#include "fluidsynth_priv.h" +#include "fluid_midi.h" + +/*************************************************************** + * + * SEQUENCER EVENTS + */ + +/* Event alloc/free */ + +void +fluid_event_clear(fluid_event_t *evt) +{ + FLUID_MEMSET(evt, 0, sizeof(fluid_event_t)); + + // by default, no type + evt->dest = -1; + evt->src = -1; + evt->type = -1; + evt->id = -1; +} + +/** + * Create a new sequencer event structure. + * @return New sequencer event structure or NULL if out of memory + */ +fluid_event_t * +new_fluid_event() +{ + fluid_event_t *evt; + + evt = FLUID_NEW(fluid_event_t); + + if(evt == NULL) + { + FLUID_LOG(FLUID_PANIC, "event: Out of memory\n"); + return NULL; + } + + fluid_event_clear(evt); + + return(evt); +} + +/** + * Delete a sequencer event structure. + * @param evt Sequencer event structure created by new_fluid_event(). + */ +void +delete_fluid_event(fluid_event_t *evt) +{ + fluid_return_if_fail(evt != NULL); + + FLUID_FREE(evt); +} + +/** + * Set the time field of a sequencer event. + * @internal + * @param evt Sequencer event structure + * @param time Time value to assign + */ +void +fluid_event_set_time(fluid_event_t *evt, unsigned int time) +{ + evt->time = time; +} + +void +fluid_event_set_id(fluid_event_t *evt, fluid_note_id_t id) +{ + evt->id = id; +} + +/** + * Set source of a sequencer event. \c src must be a unique sequencer ID or -1 if not set. + * @param evt Sequencer event structure + * @param src Unique sequencer ID + */ +void +fluid_event_set_source(fluid_event_t *evt, fluid_seq_id_t src) +{ + evt->src = src; +} + +/** + * Set destination of this sequencer event, i.e. the sequencer client this event will be sent to. \c dest must be a unique sequencer ID. + * @param evt Sequencer event structure + * @param dest The destination unique sequencer ID + */ +void +fluid_event_set_dest(fluid_event_t *evt, fluid_seq_id_t dest) +{ + evt->dest = dest; +} + +/** + * Set a sequencer event to be a timer event. + * @param evt Sequencer event structure + * @param data User supplied data pointer + */ +void +fluid_event_timer(fluid_event_t *evt, void *data) +{ + evt->type = FLUID_SEQ_TIMER; + evt->data = data; +} + +/** + * Set a sequencer event to be a note on event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param key MIDI note number (0-127) + * @param vel MIDI velocity value (0-127) + * @note Since fluidsynth 2.2.2, this function will give you a #FLUID_SEQ_NOTEOFF when + * called with @p vel being zero. + */ +void +fluid_event_noteon(fluid_event_t *evt, int channel, short key, short vel) +{ + if(vel == 0) + { + fluid_event_noteoff(evt, channel, key); + return; + } + + evt->type = FLUID_SEQ_NOTEON; + evt->channel = channel; + evt->key = key; + evt->vel = vel; +} + +/** + * Set a sequencer event to be a note off event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param key MIDI note number (0-127) + */ +void +fluid_event_noteoff(fluid_event_t *evt, int channel, short key) +{ + evt->type = FLUID_SEQ_NOTEOFF; + evt->channel = channel; + evt->key = key; +} + +/** + * Set a sequencer event to be a note duration event. + * + * Before fluidsynth 2.2.0, this event type was naively implemented when used in conjunction with fluid_sequencer_register_fluidsynth(), + * because it simply enqueued a fluid_event_noteon() and fluid_event_noteoff(). + * A handling for overlapping notes was not implemented. Starting with 2.2.0, this changes: If a fluid_event_note() is already playing, + * while another fluid_event_note() arrives on the same @c channel and @c key, the earlier event will be canceled. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param key MIDI note number (0-127) + * @param vel MIDI velocity value (1-127) + * @param duration Duration of note in the time scale used by the sequencer + * + * @note The application should decide whether to use only Notes with duration, or separate NoteOn and NoteOff events. + * @warning Calling this function with @p vel or @p duration being zero results in undefined behavior! + */ +void +fluid_event_note(fluid_event_t *evt, int channel, short key, short vel, unsigned int duration) +{ + evt->type = FLUID_SEQ_NOTE; + evt->channel = channel; + evt->key = key; + evt->vel = vel; + evt->duration = duration; +} + +/** + * Set a sequencer event to be an all sounds off event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + */ +void +fluid_event_all_sounds_off(fluid_event_t *evt, int channel) +{ + evt->type = FLUID_SEQ_ALLSOUNDSOFF; + evt->channel = channel; +} + +/** + * Set a sequencer event to be a all notes off event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + */ +void +fluid_event_all_notes_off(fluid_event_t *evt, int channel) +{ + evt->type = FLUID_SEQ_ALLNOTESOFF; + evt->channel = channel; +} + +/** + * Set a sequencer event to be a bank select event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param bank_num MIDI bank number (0-16383) + */ +void +fluid_event_bank_select(fluid_event_t *evt, int channel, short bank_num) +{ + evt->type = FLUID_SEQ_BANKSELECT; + evt->channel = channel; + evt->control = bank_num; +} + +/** + * Set a sequencer event to be a program change event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param val MIDI program number (0-127) + */ +void +fluid_event_program_change(fluid_event_t *evt, int channel, int val) +{ + evt->type = FLUID_SEQ_PROGRAMCHANGE; + evt->channel = channel; + evt->value = val; +} + +/** + * Set a sequencer event to be a program select event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param sfont_id SoundFont ID number + * @param bank_num MIDI bank number (0-16383) + * @param preset_num MIDI preset number (0-127) + */ +void +fluid_event_program_select(fluid_event_t *evt, int channel, + unsigned int sfont_id, short bank_num, short preset_num) +{ + evt->type = FLUID_SEQ_PROGRAMSELECT; + evt->channel = channel; + evt->duration = sfont_id; + evt->value = preset_num; + evt->control = bank_num; +} + +/** + * Set a sequencer event to be a pitch bend event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param pitch MIDI pitch bend value (0-16383, 8192 = no bend) + */ +void +fluid_event_pitch_bend(fluid_event_t *evt, int channel, int pitch) +{ + evt->type = FLUID_SEQ_PITCHBEND; + evt->channel = channel; + + if(pitch < 0) + { + pitch = 0; + } + + if(pitch > 16383) + { + pitch = 16383; + } + + evt->pitch = pitch; +} + +/** + * Set a sequencer event to be a pitch wheel sensitivity event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param value MIDI pitch wheel sensitivity value in semitones + */ +void +fluid_event_pitch_wheelsens(fluid_event_t *evt, int channel, int value) +{ + evt->type = FLUID_SEQ_PITCHWHEELSENS; + evt->channel = channel; + evt->value = value; +} + +/** + * Set a sequencer event to be a modulation event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param val MIDI modulation value (0-127) + */ +void +fluid_event_modulation(fluid_event_t *evt, int channel, int val) +{ + evt->type = FLUID_SEQ_MODULATION; + evt->channel = channel; + + if(val < 0) + { + val = 0; + } + + if(val > 127) + { + val = 127; + } + + evt->value = val; +} + +/** + * Set a sequencer event to be a MIDI sustain event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param val MIDI sustain value (0-127) + */ +void +fluid_event_sustain(fluid_event_t *evt, int channel, int val) +{ + evt->type = FLUID_SEQ_SUSTAIN; + evt->channel = channel; + + if(val < 0) + { + val = 0; + } + + if(val > 127) + { + val = 127; + } + + evt->value = val; +} + +/** + * Set a sequencer event to be a MIDI control change event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param control MIDI control number (0-127) + * @param val MIDI control value (0-127) + */ +void +fluid_event_control_change(fluid_event_t *evt, int channel, short control, int val) +{ + evt->type = FLUID_SEQ_CONTROLCHANGE; + evt->channel = channel; + evt->control = control; + evt->value = val; +} + +/** + * Set a sequencer event to be a stereo pan event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param val MIDI panning value (0-127, 0=left, 64 = middle, 127 = right) + */ +void +fluid_event_pan(fluid_event_t *evt, int channel, int val) +{ + evt->type = FLUID_SEQ_PAN; + evt->channel = channel; + + if(val < 0) + { + val = 0; + } + + if(val > 127) + { + val = 127; + } + + evt->value = val; +} + +/** + * Set a sequencer event to be a volume event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param val Volume value (0-127) + */ +void +fluid_event_volume(fluid_event_t *evt, int channel, int val) +{ + evt->type = FLUID_SEQ_VOLUME; + evt->channel = channel; + + if(val < 0) + { + val = 0; + } + + if(val > 127) + { + val = 127; + } + + evt->value = val; +} + +/** + * Set a sequencer event to be a reverb send event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param val Reverb amount (0-127) + */ +void +fluid_event_reverb_send(fluid_event_t *evt, int channel, int val) +{ + evt->type = FLUID_SEQ_REVERBSEND; + evt->channel = channel; + + if(val < 0) + { + val = 0; + } + + if(val > 127) + { + val = 127; + } + + evt->value = val; +} + +/** + * Set a sequencer event to be a chorus send event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param val Chorus amount (0-127) + */ +void +fluid_event_chorus_send(fluid_event_t *evt, int channel, int val) +{ + evt->type = FLUID_SEQ_CHORUSSEND; + evt->channel = channel; + + if(val < 0) + { + val = 0; + } + + if(val > 127) + { + val = 127; + } + + evt->value = val; +} + + +/** + * Set a sequencer event to be an unregistering event. + * @param evt Sequencer event structure + * @since 1.1.0 + */ +void +fluid_event_unregistering(fluid_event_t *evt) +{ + evt->type = FLUID_SEQ_UNREGISTERING; +} + +/** + * Set a sequencer event to be a scale change event. + * Useful for scheduling tempo changes. + * @param evt Sequencer event structure + * @param new_scale The new time scale to apply to the sequencer, see fluid_sequencer_set_time_scale() + * @since 2.2.0 + */ +void +fluid_event_scale(fluid_event_t *evt, double new_scale) +{ + evt->type = FLUID_SEQ_SCALE; + evt->scale = new_scale; +} + +/** + * Set a sequencer event to be a channel-wide aftertouch event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param val Aftertouch amount (0-127) + * @since 1.1.0 + */ +void +fluid_event_channel_pressure(fluid_event_t *evt, int channel, int val) +{ + evt->type = FLUID_SEQ_CHANNELPRESSURE; + evt->channel = channel; + + if(val < 0) + { + val = 0; + } + + if(val > 127) + { + val = 127; + } + + evt->value = val; +} + +/** + * Set a sequencer event to be a polyphonic aftertouch event. + * @param evt Sequencer event structure + * @param channel MIDI channel number + * @param key MIDI note number (0-127) + * @param val Aftertouch amount (0-127) + * @since 2.0.0 + */ +void +fluid_event_key_pressure(fluid_event_t *evt, int channel, short key, int val) +{ + evt->type = FLUID_SEQ_KEYPRESSURE; + evt->channel = channel; + + if(key < 0) + { + key = 0; + } + + if(key > 127) + { + key = 127; + } + + if(val < 0) + { + val = 0; + } + + if(val > 127) + { + val = 127; + } + + evt->key = key; + evt->value = val; +} + +/** + * Set a sequencer event to be a midi system reset event. + * @param evt Sequencer event structure + * @since 1.1.0 + */ +void +fluid_event_system_reset(fluid_event_t *evt) +{ + evt->type = FLUID_SEQ_SYSTEMRESET; +} + +/** + * Transforms an incoming MIDI event (from a MIDI driver or MIDI router) to a + * sequencer event. + * + * @param evt Sequencer event structure + * @param event MIDI event + * @return #FLUID_OK or #FLUID_FAILED + * + * @note This function copies the fields of the MIDI event into the provided + * sequencer event. Calling applications must create the sequencer event and set + * additional fields such as the source and destination of the sequencer event. + * + * @code{.cpp} + * // ... get MIDI event, e.g. using player_callback() + * + * // Send MIDI event to sequencer to play + * fluid_event_t *evt = new_fluid_event(); + * fluid_event_set_source(evt, -1); + * fluid_event_set_dest(evt, seqid); + * fluid_event_from_midi_event(evt, event); + * fluid_sequencer_send_at(sequencer, evt, 50, 0); // relative time + * delete_fluid_event(evt); + * @endcode + * + * @since 2.2.7 + */ +int fluid_event_from_midi_event(fluid_event_t *evt, const fluid_midi_event_t *event) +{ + int chan; + fluid_return_val_if_fail(event != NULL, FLUID_FAILED); + + chan = fluid_midi_event_get_channel(event); + + switch (fluid_midi_event_get_type(event)) + { + case NOTE_OFF: + fluid_event_noteoff(evt, chan, (short)fluid_midi_event_get_key(event)); + break; + + case NOTE_ON: + fluid_event_noteon(evt, + fluid_midi_event_get_channel(event), + (short)fluid_midi_event_get_key(event), + (short)fluid_midi_event_get_velocity(event)); + break; + + case CONTROL_CHANGE: + fluid_event_control_change(evt, + chan, + (short)fluid_midi_event_get_control(event), + (short)fluid_midi_event_get_value(event)); + break; + + case PROGRAM_CHANGE: + fluid_event_program_change(evt, chan, (short)fluid_midi_event_get_program(event)); + break; + + case PITCH_BEND: + fluid_event_pitch_bend(evt, chan, fluid_midi_event_get_pitch(event)); + break; + + case CHANNEL_PRESSURE: + fluid_event_channel_pressure(evt, chan, (short)fluid_midi_event_get_program(event)); + break; + + case KEY_PRESSURE: + fluid_event_key_pressure(evt, + chan, + (short)fluid_midi_event_get_key(event), + (short)fluid_midi_event_get_value(event)); + break; + + case MIDI_SYSTEM_RESET: + fluid_event_system_reset(evt); + break; + + default: /* Not yet implemented */ + return FLUID_FAILED; + } + + return FLUID_OK; +} + +/* + * Accessing event data + */ + +/** + * Get the event type (#fluid_seq_event_type) field from a sequencer event structure. + * @param evt Sequencer event structure + * @return Event type (#fluid_seq_event_type). + */ +int fluid_event_get_type(fluid_event_t *evt) +{ + return evt->type; +} + +/** + * @internal + * Get the time field from a sequencer event structure. + * @param evt Sequencer event structure + * @return Time value + */ +unsigned int fluid_event_get_time(fluid_event_t *evt) +{ + return evt->time; +} + +/** + * @internal + * Get the time field from a sequencer event structure. + * @param evt Sequencer event structure + * @return Time value + */ +fluid_note_id_t fluid_event_get_id(fluid_event_t *evt) +{ + return evt->id; +} + +/** + * Get the source sequencer client from a sequencer event structure. + * @param evt Sequencer event structure + * @return source field of the sequencer event + */ +fluid_seq_id_t fluid_event_get_source(fluid_event_t *evt) +{ + return evt->src; +} + +/** + * Get the dest sequencer client from a sequencer event structure. + * @param evt Sequencer event structure + * @return dest field of the sequencer event + */ +fluid_seq_id_t fluid_event_get_dest(fluid_event_t *evt) +{ + return evt->dest; +} + +/** + * Get the MIDI channel field from a sequencer event structure. + * @param evt Sequencer event structure + * @return MIDI zero-based channel number + */ +int fluid_event_get_channel(fluid_event_t *evt) +{ + return evt->channel; +} + +/** + * Get the MIDI note field from a sequencer event structure. + * @param evt Sequencer event structure + * @return MIDI note number (0-127) + */ +short fluid_event_get_key(fluid_event_t *evt) +{ + return evt->key; +} + +/** + * Get the MIDI velocity field from a sequencer event structure. + * @param evt Sequencer event structure + * @return MIDI velocity value (0-127) + */ +short fluid_event_get_velocity(fluid_event_t *evt) + +{ + return evt->vel; +} + +/** + * Get the MIDI control number field from a sequencer event structure. + * @param evt Sequencer event structure + * @return MIDI control number (0-127) + */ +short fluid_event_get_control(fluid_event_t *evt) +{ + return evt->control; +} + +/** + * Get the value field from a sequencer event structure. + * @param evt Sequencer event structure + * @return Value field of event. + * + * The Value field is used by the following event types: + * #FLUID_SEQ_PROGRAMCHANGE, #FLUID_SEQ_PROGRAMSELECT (preset_num), + * #FLUID_SEQ_PITCHWHEELSENS, #FLUID_SEQ_MODULATION, #FLUID_SEQ_SUSTAIN, + * #FLUID_SEQ_CONTROLCHANGE, #FLUID_SEQ_PAN, #FLUID_SEQ_VOLUME, + * #FLUID_SEQ_REVERBSEND, #FLUID_SEQ_CHORUSSEND. + */ +int fluid_event_get_value(fluid_event_t *evt) +{ + return evt->value; +} + +/** + * Get the data field from a sequencer event structure. + * @param evt Sequencer event structure + * @return Data field of event. + * + * Used by the #FLUID_SEQ_TIMER event type. + */ +void *fluid_event_get_data(fluid_event_t *evt) +{ + return evt->data; +} + +/** + * Get the duration field from a sequencer event structure. + * @param evt Sequencer event structure + * @return Note duration value in the time scale used by the sequencer (by default milliseconds) + * + * Used by the #FLUID_SEQ_NOTE event type. + */ +unsigned int fluid_event_get_duration(fluid_event_t *evt) +{ + return evt->duration; +} + +/** + * Get the MIDI bank field from a sequencer event structure. + * @param evt Sequencer event structure + * @return MIDI bank number (0-16383) + * + * Used by the #FLUID_SEQ_BANKSELECT and #FLUID_SEQ_PROGRAMSELECT + * event types. + */ +short fluid_event_get_bank(fluid_event_t *evt) +{ + return evt->control; +} + +/** + * Get the pitch field from a sequencer event structure. + * @param evt Sequencer event structure + * @return MIDI pitch bend pitch value (0-16383, 8192 = no bend) + * + * Used by the #FLUID_SEQ_PITCHBEND event type. + */ +int fluid_event_get_pitch(fluid_event_t *evt) +{ + return evt->pitch; +} + +/** + * Get the MIDI program field from a sequencer event structure. + * @param evt Sequencer event structure + * @return MIDI program number (0-127) + * + * Used by the #FLUID_SEQ_PROGRAMCHANGE and #FLUID_SEQ_PROGRAMSELECT + * event types. + */ +int +fluid_event_get_program(fluid_event_t *evt) +{ + return evt->value; +} + +/** + * Get the SoundFont ID field from a sequencer event structure. + * @param evt Sequencer event structure + * @return SoundFont identifier value. + * + * Used by the #FLUID_SEQ_PROGRAMSELECT event type. + */ +unsigned int +fluid_event_get_sfont_id(fluid_event_t *evt) +{ + return evt->duration; +} + +/** + * Gets time scale field from a sequencer event structure. + * @param evt Sequencer event structure + * @return SoundFont identifier value. + * + * Used by the #FLUID_SEQ_SCALE event type. + */ +double fluid_event_get_scale(fluid_event_t *evt) +{ + return evt->scale; +} diff --git a/libs/fluidsynth/src/synth/fluid_event.h b/libs/fluidsynth/src/synth/fluid_event.h new file mode 100644 index 00000000000..4a0cca5d93d --- /dev/null +++ b/libs/fluidsynth/src/synth/fluid_event.h @@ -0,0 +1,65 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#ifndef _FLUID_EVENT_PRIV_H +#define _FLUID_EVENT_PRIV_H + +#include "fluidsynth.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int fluid_note_id_t; + +/* Private data for event */ +/* ?? should be optimized in size, using unions */ +struct _fluid_event_t +{ + unsigned int time; + int type; + fluid_seq_id_t src; + fluid_seq_id_t dest; + int channel; + short key; + short vel; + short control; + int value; + fluid_note_id_t id; + int pitch; + unsigned int duration; + double scale; + void *data; +}; + +unsigned int fluid_event_get_time(fluid_event_t *evt); +void fluid_event_set_time(fluid_event_t *evt, unsigned int time); + +fluid_note_id_t fluid_event_get_id(fluid_event_t *evt); +void fluid_event_set_id(fluid_event_t *evt, fluid_note_id_t id); + +void fluid_event_clear(fluid_event_t *evt); + +#ifdef __cplusplus +} +#endif + +#endif /* _FLUID_EVENT_PRIV_H */ diff --git a/libs/fluidsynth/src/synth/fluid_gen.c b/libs/fluidsynth/src/synth/fluid_gen.c new file mode 100644 index 00000000000..2ce2b0f74b5 --- /dev/null +++ b/libs/fluidsynth/src/synth/fluid_gen.c @@ -0,0 +1,133 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#include "fluid_gen.h" +#include "fluid_chan.h" + + +#define _GEN(_name) GEN_ ## _name, #_name + + +/* See SFSpec21 $8.1.3 */ +static const fluid_gen_info_t fluid_gen_info[] = +{ + /* number/name init nrpn-scale min max def */ + { _GEN(STARTADDROFS), 1, 1, 0.0f, 1e10f, 0.0f }, + { _GEN(ENDADDROFS), 1, 1, -1e10f, 0.0f, 0.0f }, + { _GEN(STARTLOOPADDROFS), 1, 1, -1e10f, 1e10f, 0.0f }, + { _GEN(ENDLOOPADDROFS), 1, 1, -1e10f, 1e10f, 0.0f }, + { _GEN(STARTADDRCOARSEOFS), 0, 1, 0.0f, 1e10f, 0.0f }, + { _GEN(MODLFOTOPITCH), 1, 2, -12000.0f, 12000.0f, 0.0f }, + { _GEN(VIBLFOTOPITCH), 1, 2, -12000.0f, 12000.0f, 0.0f }, + { _GEN(MODENVTOPITCH), 1, 2, -12000.0f, 12000.0f, 0.0f }, + { _GEN(FILTERFC), 1, 2, 1500.0f, 13500.0f, 13500.0f }, + { _GEN(FILTERQ), 1, 1, 0.0f, 960.0f, 0.0f }, + { _GEN(MODLFOTOFILTERFC), 1, 2, -12000.0f, 12000.0f, 0.0f }, + { _GEN(MODENVTOFILTERFC), 1, 2, -12000.0f, 12000.0f, 0.0f }, + { _GEN(ENDADDRCOARSEOFS), 0, 1, -1e10f, 0.0f, 0.0f }, + { _GEN(MODLFOTOVOL), 1, 1, -960.0f, 960.0f, 0.0f }, + { _GEN(UNUSED1), 0, 0, 0.0f, 0.0f, 0.0f }, + { _GEN(CHORUSSEND), 1, 1, 0.0f, 1000.0f, 0.0f }, + { _GEN(REVERBSEND), 1, 1, 0.0f, 1000.0f, 0.0f }, + { _GEN(PAN), 1, 1, -500.0f, 500.0f, 0.0f }, + { _GEN(UNUSED2), 0, 0, 0.0f, 0.0f, 0.0f }, + { _GEN(UNUSED3), 0, 0, 0.0f, 0.0f, 0.0f }, + { _GEN(UNUSED4), 0, 0, 0.0f, 0.0f, 0.0f }, + { _GEN(MODLFODELAY), 1, 2, -12000.0f, 5000.0f, -12000.0f }, + { _GEN(MODLFOFREQ), 1, 4, -16000.0f, 4500.0f, 0.0f }, + { _GEN(VIBLFODELAY), 1, 2, -12000.0f, 5000.0f, -12000.0f }, + { _GEN(VIBLFOFREQ), 1, 4, -16000.0f, 4500.0f, 0.0f }, + { _GEN(MODENVDELAY), 1, 2, -12000.0f, 5000.0f, -12000.0f }, + { _GEN(MODENVATTACK), 1, 2, -12000.0f, 8000.0f, -12000.0f }, + { _GEN(MODENVHOLD), 1, 2, -12000.0f, 5000.0f, -12000.0f }, + { _GEN(MODENVDECAY), 1, 2, -12000.0f, 8000.0f, -12000.0f }, + { _GEN(MODENVSUSTAIN), 0, 1, 0.0f, 1000.0f, 0.0f }, + { _GEN(MODENVRELEASE), 1, 2, -12000.0f, 8000.0f, -12000.0f }, + { _GEN(KEYTOMODENVHOLD), 0, 1, -1200.0f, 1200.0f, 0.0f }, + { _GEN(KEYTOMODENVDECAY), 0, 1, -1200.0f, 1200.0f, 0.0f }, + { _GEN(VOLENVDELAY), 1, 2, -12000.0f, 5000.0f, -12000.0f }, + { _GEN(VOLENVATTACK), 1, 2, -12000.0f, 8000.0f, -12000.0f }, + { _GEN(VOLENVHOLD), 1, 2, -12000.0f, 5000.0f, -12000.0f }, + { _GEN(VOLENVDECAY), 1, 2, -12000.0f, 8000.0f, -12000.0f }, + { _GEN(VOLENVSUSTAIN), 0, 1, 0.0f, 1440.0f, 0.0f }, + { _GEN(VOLENVRELEASE), 1, 2, -12000.0f, 8000.0f, -12000.0f }, + { _GEN(KEYTOVOLENVHOLD), 0, 1, -1200.0f, 1200.0f, 0.0f }, + { _GEN(KEYTOVOLENVDECAY), 0, 1, -1200.0f, 1200.0f, 0.0f }, + { _GEN(INSTRUMENT), 0, 0, 0.0f, 0.0f, 0.0f }, + { _GEN(RESERVED1), 0, 0, 0.0f, 0.0f, 0.0f }, + { _GEN(KEYRANGE), 0, 0, 0.0f, 127.0f, 0.0f }, + { _GEN(VELRANGE), 0, 0, 0.0f, 127.0f, 0.0f }, + { _GEN(STARTLOOPADDRCOARSEOFS), 0, 1, -1e10f, 1e10f, 0.0f }, + { _GEN(KEYNUM), 1, 0, 0.0f, 127.0f, -1.0f }, + { _GEN(VELOCITY), 1, 1, 0.0f, 127.0f, -1.0f }, + { _GEN(ATTENUATION), 1, 1, 0.0f, 1440.0f, 0.0f }, + { _GEN(RESERVED2), 0, 0, 0.0f, 0.0f, 0.0f }, + { _GEN(ENDLOOPADDRCOARSEOFS), 0, 1, -1e10f, 1e10f, 0.0f }, + { _GEN(COARSETUNE), 0, 1, -120.0f, 120.0f, 0.0f }, + { _GEN(FINETUNE), 0, 1, -99.0f, 99.0f, 0.0f }, + { _GEN(SAMPLEID), 0, 0, 0.0f, 0.0f, 0.0f }, + { _GEN(SAMPLEMODE), 0, 0, 0.0f, 0.0f, 0.0f }, + { _GEN(RESERVED3), 0, 0, 0.0f, 0.0f, 0.0f }, + { _GEN(SCALETUNE), 0, 1, 0.0f, 1200.0f, 100.0f }, + { _GEN(EXCLUSIVECLASS), 0, 0, 0.0f, 0.0f, 0.0f }, + { _GEN(OVERRIDEROOTKEY), 1, 0, 0.0f, 127.0f, -1.0f }, + { _GEN(PITCH), 1, 0, 0.0f, 127.0f, 0.0f }, + { _GEN(CUSTOM_BALANCE), 1, 0, -960.0f, 960.0f, 0.0f }, + { _GEN(CUSTOM_FILTERFC), 1, 2, 0.0f, 22050.0f, 0.0f }, + { _GEN(CUSTOM_FILTERQ), 1, 1, 0.0f, 960.0f, 0.0f } +}; + +/* fluid_gen_init + * + * Set an array of generators to their initial value + */ +void +fluid_gen_init(fluid_gen_t *gen, fluid_channel_t *channel) +{ + int i; + + for(i = 0; i < GEN_LAST; i++) + { + gen[i].flags = GEN_UNUSED; + gen[i].mod = 0.0; + gen[i].nrpn = (channel == NULL) ? 0.0 : fluid_channel_get_gen(channel, i); + gen[i].val = fluid_gen_info[i].def; + } +} + +fluid_real_t fluid_gen_scale(int gen, float value) +{ + return (fluid_gen_info[gen].min + + value * (fluid_gen_info[gen].max - fluid_gen_info[gen].min)); +} + +fluid_real_t fluid_gen_scale_nrpn(int gen, int data) +{ + data = data - 8192; + fluid_clip(data, -8192, 8192); + return (fluid_real_t)(data * fluid_gen_info[gen].nrpn_scale); +} + + +const char *fluid_gen_name(int gen) +{ + return fluid_gen_info[gen].name; +} diff --git a/libs/fluidsynth/src/synth/fluid_gen.h b/libs/fluidsynth/src/synth/fluid_gen.h new file mode 100644 index 00000000000..b87e8d8a8c6 --- /dev/null +++ b/libs/fluidsynth/src/synth/fluid_gen.h @@ -0,0 +1,67 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#ifndef _FLUID_GEN_H +#define _FLUID_GEN_H + +#include "fluidsynth_priv.h" + +typedef struct _fluid_gen_info_t +{ + char num; /* Generator number */ + char *name; + char init; /* Does the generator need to be initialized (not used) */ + char nrpn_scale; /* The scale to convert from NRPN (cfr. fluid_gen_map_nrpn()) */ + float min; /* The minimum value */ + float max; /* The maximum value */ + float def; /* The default value (cfr. fluid_gen_init()) */ +} fluid_gen_info_t; + +/* + * SoundFont generator structure. + */ +typedef struct _fluid_gen_t +{ + unsigned char flags; /**< Is the generator set or not (#fluid_gen_flags) */ + double val; /**< The nominal value */ + double mod; /**< Change by modulators */ + double nrpn; /**< Change by NRPN messages */ +} fluid_gen_t; + +/* + * Enum value for 'flags' field of #fluid_gen_t (not really flags). + */ +enum fluid_gen_flags +{ + GEN_UNUSED, /**< Generator value is not set */ + GEN_SET, /**< Generator value is set */ +}; + +#define fluid_gen_set_mod(_gen, _val) { (_gen)->mod = (double) (_val); } +#define fluid_gen_set_nrpn(_gen, _val) { (_gen)->nrpn = (double) (_val); } + +fluid_real_t fluid_gen_scale(int gen, float value); +fluid_real_t fluid_gen_scale_nrpn(int gen, int nrpn); +void fluid_gen_init(fluid_gen_t *gen, fluid_channel_t *channel); +const char *fluid_gen_name(int gen); + + +#endif /* _FLUID_GEN_H */ diff --git a/libs/fluidsynth/src/synth/fluid_mod.c b/libs/fluidsynth/src/synth/fluid_mod.c new file mode 100644 index 00000000000..88e3ba3532b --- /dev/null +++ b/libs/fluidsynth/src/synth/fluid_mod.c @@ -0,0 +1,880 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include "fluid_mod.h" +#include "fluid_chan.h" +#include "fluid_voice.h" + +/** + * Clone the modulators destination, sources, flags and amount. + * + * @param mod the modulator to store the copy to + * @param src the source modulator to retrieve the information from + * + * @note The \c next member of \c mod will be left unchanged. + */ +void +fluid_mod_clone(fluid_mod_t *mod, const fluid_mod_t *src) +{ + mod->dest = src->dest; + mod->src1 = src->src1; + mod->flags1 = src->flags1; + mod->src2 = src->src2; + mod->flags2 = src->flags2; + mod->amount = src->amount; +} + +/** + * Set a modulator's primary source controller and flags. + * + * @param mod The modulator instance + * @param src Modulator source (#fluid_mod_src or a MIDI controller number) + * @param flags Flags determining mapping function and whether the source + * controller is a general controller (#FLUID_MOD_GC) or a MIDI CC controller + * (#FLUID_MOD_CC), see #fluid_mod_flags. + */ +void +fluid_mod_set_source1(fluid_mod_t *mod, int src, int flags) +{ + mod->src1 = src; + mod->flags1 = flags; +} + +/** + * Set a modulator's secondary source controller and flags. + * + * @param mod The modulator instance + * @param src Modulator source (#fluid_mod_src or a MIDI controller number) + * @param flags Flags determining mapping function and whether the source + * controller is a general controller (#FLUID_MOD_GC) or a MIDI CC controller + * (#FLUID_MOD_CC), see #fluid_mod_flags. + */ +void +fluid_mod_set_source2(fluid_mod_t *mod, int src, int flags) +{ + mod->src2 = src; + mod->flags2 = flags; +} + +/** + * Set the destination effect of a modulator. + * + * @param mod The modulator instance + * @param dest Destination generator (#fluid_gen_type) + */ +void +fluid_mod_set_dest(fluid_mod_t *mod, int dest) +{ + mod->dest = dest; +} + +/** + * Set the scale amount of a modulator. + * + * @param mod The modulator instance + * @param amount Scale amount to assign + */ +void +fluid_mod_set_amount(fluid_mod_t *mod, double amount) +{ + mod->amount = (double) amount; +} + +/** + * Get the primary source value from a modulator. + * + * @param mod The modulator instance + * @return The primary source value (#fluid_mod_src or a MIDI CC controller value). + */ +int +fluid_mod_get_source1(const fluid_mod_t *mod) +{ + return mod->src1; +} + +/** + * Get primary source flags from a modulator. + * + * @param mod The modulator instance + * @return The primary source flags (#fluid_mod_flags). + */ +int +fluid_mod_get_flags1(const fluid_mod_t *mod) +{ + return mod->flags1; +} + +/** + * Get the secondary source value from a modulator. + * + * @param mod The modulator instance + * @return The secondary source value (#fluid_mod_src or a MIDI CC controller value). + */ +int +fluid_mod_get_source2(const fluid_mod_t *mod) +{ + return mod->src2; +} + +/** + * Get secondary source flags from a modulator. + * + * @param mod The modulator instance + * @return The secondary source flags (#fluid_mod_flags). + */ +int +fluid_mod_get_flags2(const fluid_mod_t *mod) +{ + return mod->flags2; +} + +/** + * Get destination effect from a modulator. + * + * @param mod The modulator instance + * @return Destination generator (#fluid_gen_type) + */ +int +fluid_mod_get_dest(const fluid_mod_t *mod) +{ + return mod->dest; +} + +/** + * Get the scale amount from a modulator. + * + * @param mod The modulator instance + * @return Scale amount + */ +double +fluid_mod_get_amount(const fluid_mod_t *mod) +{ + return (double) mod->amount; +} + +/* + * retrieves the initial value from the given source of the modulator + */ +static fluid_real_t +fluid_mod_get_source_value(const unsigned char mod_src, + const unsigned char mod_flags, + fluid_real_t *range, + const fluid_voice_t *voice + ) +{ + const fluid_channel_t *chan = voice->channel; + fluid_real_t val; + + if(mod_flags & FLUID_MOD_CC) + { + val = fluid_channel_get_cc(chan, mod_src); + + if(mod_src == PORTAMENTO_CTRL) + { + // an invalid portamento fromkey should be treated as 0 when it's actually used for moulating + if(!fluid_channel_is_valid_note(val)) + { + val = 0; + } + } + } + else + { + switch(mod_src) + { + case FLUID_MOD_NONE: /* SF 2.01 8.2.1 item 0: src enum=0 => value is 1 */ + val = *range; + break; + + case FLUID_MOD_VELOCITY: + val = fluid_voice_get_actual_velocity(voice); + break; + + case FLUID_MOD_KEY: + val = fluid_voice_get_actual_key(voice); + break; + + case FLUID_MOD_KEYPRESSURE: + val = fluid_channel_get_key_pressure(chan, voice->key); + break; + + case FLUID_MOD_CHANNELPRESSURE: + val = fluid_channel_get_channel_pressure(chan); + break; + + case FLUID_MOD_PITCHWHEEL: + val = fluid_channel_get_pitch_bend(chan); + *range = 0x4000; + break; + + case FLUID_MOD_PITCHWHEELSENS: + val = fluid_channel_get_pitch_wheel_sensitivity(chan); + break; + + default: + FLUID_LOG(FLUID_ERR, "Unknown modulator source '%d', disabling modulator.", mod_src); + val = 0.0; + } + } + + return val; +} + +/** + * transforms the initial value retrieved by \c fluid_mod_get_source_value into [0.0;1.0] + */ +static fluid_real_t +fluid_mod_transform_source_value(fluid_real_t val, unsigned char mod_flags, const fluid_real_t range) +{ + /* normalized value, i.e. usually in the range [0;1] */ + const fluid_real_t val_norm = val / range; + + /* we could also only switch case the lower nibble of mod_flags, however + * this would keep us from adding further mod types in the future + * + * instead just remove the flag(s) we already took care of + */ + mod_flags &= ~FLUID_MOD_CC; + + switch(mod_flags/* & 0x0f*/) + { + case FLUID_MOD_LINEAR | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* =0 */ + val = val_norm; + break; + + case FLUID_MOD_LINEAR | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* =1 */ + val = 1.0f - val_norm; + break; + + case FLUID_MOD_LINEAR | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* =2 */ + val = -1.0f + 2.0f * val_norm; + break; + + case FLUID_MOD_LINEAR | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =3 */ + val = 1.0f - 2.0f * val_norm; + break; + + case FLUID_MOD_CONCAVE | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* =4 */ + val = fluid_concave(127 * (val_norm)); + break; + + case FLUID_MOD_CONCAVE | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* =5 */ + val = fluid_concave(127 * (1.0f - val_norm)); + break; + + case FLUID_MOD_CONCAVE | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* =6 */ + val = (val_norm > 0.5f) ? fluid_concave(127 * 2 * (val_norm - 0.5f)) + : -fluid_concave(127 * 2 * (0.5f - val_norm)); + break; + + case FLUID_MOD_CONCAVE | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =7 */ + val = (val_norm > 0.5f) ? -fluid_concave(127 * 2 * (val_norm - 0.5f)) + : fluid_concave(127 * 2 * (0.5f - val_norm)); + break; + + case FLUID_MOD_CONVEX | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* =8 */ + val = fluid_convex(127 * (val_norm)); + break; + + case FLUID_MOD_CONVEX | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* =9 */ + val = fluid_convex(127 * (1.0f - val_norm)); + break; + + case FLUID_MOD_CONVEX | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* =10 */ + val = (val_norm > 0.5f) ? fluid_convex(127 * 2 * (val_norm - 0.5f)) + : -fluid_convex(127 * 2 * (0.5f - val_norm)); + break; + + case FLUID_MOD_CONVEX | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =11 */ + val = (val_norm > 0.5f) ? -fluid_convex(127 * 2 * (val_norm - 0.5f)) + : fluid_convex(127 * 2 * (0.5f - val_norm)); + break; + + case FLUID_MOD_SWITCH | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* =12 */ + val = (val_norm >= 0.5f) ? 1.0f : 0.0f; + break; + + case FLUID_MOD_SWITCH | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* =13 */ + val = (val_norm >= 0.5f) ? 0.0f : 1.0f; + break; + + case FLUID_MOD_SWITCH | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* =14 */ + val = (val_norm >= 0.5f) ? 1.0f : -1.0f; + break; + + case FLUID_MOD_SWITCH | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =15 */ + val = (val_norm >= 0.5f) ? -1.0f : 1.0f; + break; + + /* + * MIDI CCs only have a resolution of 7 bits. The closer val_norm gets to 1, + * the less will be the resulting change of the sinus. When using this sin() + * for scaling the cutoff frequency, there will be no audible difference between + * MIDI CCs 118 to 127. To avoid this waste of CCs multiply with 0.87 + * (at least for unipolar) which makes sin() never get to 1.0 but to 0.98 which + * is close enough. + */ + case FLUID_MOD_SIN | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* custom sin(x) */ + val = FLUID_SIN((FLUID_M_PI / 2.0f * 0.87f) * val_norm); + break; + + case FLUID_MOD_SIN | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* custom */ + val = FLUID_SIN((FLUID_M_PI / 2.0f * 0.87f) * (1.0f - val_norm)); + break; + + case FLUID_MOD_SIN | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* custom */ + val = (val_norm > 0.5f) ? FLUID_SIN(FLUID_M_PI * (val_norm - 0.5f)) + : -FLUID_SIN(FLUID_M_PI * (0.5f - val_norm)); + break; + + case FLUID_MOD_SIN | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* custom */ + val = (val_norm > 0.5f) ? -FLUID_SIN(FLUID_M_PI * (val_norm - 0.5f)) + : FLUID_SIN(FLUID_M_PI * (0.5f - val_norm)); + break; + + default: + FLUID_LOG(FLUID_ERR, "Unknown modulator type '%d', disabling modulator.", mod_flags); + val = 0.0f; + break; + } + + return val; +} + +/* + * fluid_mod_get_value. + * Computes and return modulator output following SF2.01 + * (See SoundFont Modulator Controller Model Chapter 9.5). + * + * Output = Transform(Amount * Map(primary source input) * Map(secondary source input)) + * + * Notes: + * 1)fluid_mod_get_value, ignores the Transform operator. The result is: + * + * Output = Amount * Map(primary source input) * Map(secondary source input) + * + * 2)When primary source input (src1) is set to General Controller 'No Controller', + * output is forced to 0. + * + * 3)When secondary source input (src2) is set to General Controller 'No Controller', + * output is forced to +1.0 + */ +fluid_real_t +fluid_mod_get_value(fluid_mod_t *mod, fluid_voice_t *voice) +{ + extern fluid_mod_t default_vel2filter_mod; + + fluid_real_t v1 = 0.0, v2 = 1.0; + /* The wording of the default modulators refers to a range of 127/128. + * And the table in section 9.5.3 suggests, that this mapping should be applied + * to all unipolar and bipolar mappings respectively. + * + * Thinking about this further, this is actually pretty clever, as this is properly + * addresses MIDI Recommended Practice (RP-036) Default Pan Formula + * "Since MIDI controller values range from 0 to 127, the exact center + * of the range, 63.5, cannot be represented." + * + * When changing the overall range to 127/128 however, the "middle pan" value of 64 + * can be correctly represented. + */ + fluid_real_t range1 = 128.0, range2 = 128.0; + + /* 'special treatment' for default controller + * + * Reference: SF2.01 section 8.4.2 + * + * The GM default controller 'vel-to-filter cut off' is not clearly + * defined: If implemented according to the specs, the filter + * frequency jumps between vel=63 and vel=64. To maintain + * compatibility with existing sound fonts, the implementation is + * 'hardcoded', it is impossible to implement using only one + * modulator otherwise. + * + * I assume here, that the 'intention' of the paragraph is one + * octave (1200 cents) filter frequency shift between vel=127 and + * vel=64. 'amount' is (-2400), at least as long as the controller + * is set to default. + * + * Further, the 'appearance' of the modulator (source enumerator, + * destination enumerator, flags etc) is different from that + * described in section 8.4.2, but it matches the definition used in + * several SF2.1 sound fonts (where it is used only to turn it off). + * */ + if(fluid_mod_test_identity(mod, &default_vel2filter_mod)) + { +// S. Christian Collins' mod, to stop forcing velocity based filtering + /* + if (voice->vel < 64){ + return (fluid_real_t) mod->amount / 2.0; + } else { + return (fluid_real_t) mod->amount * (127 - voice->vel) / 127; + } + */ + return 0; // (fluid_real_t) mod->amount / 2.0; + } + +// end S. Christian Collins' mod + + /* get the initial value of the first source */ + if(mod->src1 > 0) + { + v1 = fluid_mod_get_source_value(mod->src1, mod->flags1, &range1, voice); + + /* transform the input value */ + v1 = fluid_mod_transform_source_value(v1, mod->flags1, range1); + } + /* When primary source input (src1) is set to General Controller 'No Controller', + output is forced to 0.0 + */ + else + { + return 0.0; + } + + /* no need to go further */ + if(v1 == 0.0f) + { + return 0.0f; + } + + /* get the second input source */ + if(mod->src2 > 0) + { + v2 = fluid_mod_get_source_value(mod->src2, mod->flags2, &range2, voice); + + /* transform the second input value */ + v2 = fluid_mod_transform_source_value(v2, mod->flags2, range2); + } + /* When secondary source input (src2) is set to General Controller 'No Controller', + output is forced to +1.0 + */ + else + { + v2 = 1.0f; + } + + /* it's as simple as that: */ + return (fluid_real_t) mod->amount * v1 * v2; +} + +/** + * Create a new uninitialized modulator structure. + * + * @return New allocated modulator or NULL if out of memory + */ +fluid_mod_t * +new_fluid_mod() +{ + fluid_mod_t *mod = FLUID_NEW(fluid_mod_t); + + if(mod == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + return mod; +} + +/** + * Free a modulator structure. + * + * @param mod Modulator to free + */ +void +delete_fluid_mod(fluid_mod_t *mod) +{ + FLUID_FREE(mod); +} + +/** + * Returns the size of the fluid_mod_t structure. + * + * @return Size of fluid_mod_t in bytes + * + * Useful in low latency scenarios e.g. to allocate a modulator on the stack. + */ +size_t fluid_mod_sizeof() +{ + return sizeof(fluid_mod_t); +} + +/** + * Checks if modulator with source 1 other than CC is FLUID_MOD_NONE. + * + * @param mod, modulator. + * @return TRUE if modulator source 1 other than cc is FLUID_MOD_NONE, FALSE otherwise. + */ +static int +fluid_mod_is_src1_none(const fluid_mod_t *mod) +{ + return(((mod->flags1 & FLUID_MOD_CC) == 0) && (mod->src1 == FLUID_MOD_NONE)); +} + +/** + * Checks if modulators source other than CC source is invalid. + * + * @param mod, modulator. + * @param src1_select, source input selection to check. + * 1 to check src1 source. + * 0 to check src2 source. + * @return FALSE if selected modulator source other than cc is invalid, TRUE otherwise. + * + * (specs SF 2.01 7.4, 7.8, 8.2.1) + */ +static int +fluid_mod_check_non_cc_source(const fluid_mod_t *mod, unsigned char src1_select) +{ + unsigned char flags, src; + + if(src1_select) + { + flags = mod->flags1; + src = mod->src1; + } + else + { + flags = mod->flags2; + src = mod->src2; + } + + return(((flags & FLUID_MOD_CC) != 0) /* src is a CC */ + /* SF2.01 section 8.2.1: Constant value */ + || ((src == FLUID_MOD_NONE) + || (src == FLUID_MOD_VELOCITY) /* Note-on velocity */ + || (src == FLUID_MOD_KEY) /* Note-on key number */ + || (src == FLUID_MOD_KEYPRESSURE) /* Poly pressure */ + || (src == FLUID_MOD_CHANNELPRESSURE) /* Channel pressure */ + || (src == FLUID_MOD_PITCHWHEEL) /* Pitch wheel */ + || (src == FLUID_MOD_PITCHWHEELSENS) /* Pitch wheel sensitivity */ + )); +} + +/** + * Checks if modulator CC source is invalid (specs SF 2.01 7.4, 7.8, 8.2.1). + * + * @param mod, modulator. + * @src1_select, source input selection: + * 1 to check src1 source or + * 0 to check src2 source. + * @return FALSE if selected modulator's source CC is invalid, TRUE otherwise. + */ +static int +fluid_mod_check_cc_source(const fluid_mod_t *mod, unsigned char src1_select) +{ + unsigned char flags, src; + + if(src1_select) + { + flags = mod->flags1; + src = mod->src1; + } + else + { + flags = mod->flags2; + src = mod->src2; + } + + return(((flags & FLUID_MOD_CC) == 0) /* src is non CC */ + || ((src != BANK_SELECT_MSB) + && (src != BANK_SELECT_LSB) + && (src != DATA_ENTRY_MSB) + && (src != DATA_ENTRY_LSB) + /* is src not NRPN_LSB, NRPN_MSB, RPN_LSB, RPN_MSB */ + && ((src < NRPN_LSB) || (RPN_MSB < src)) + /* is src not ALL_SOUND_OFF, ALL_CTRL_OFF, LOCAL_CONTROL, ALL_NOTES_OFF ? */ + /* is src not OMNI_OFF, OMNI_ON, POLY_OFF, POLY_ON ? */ + && (src < ALL_SOUND_OFF) + /* CC lsb shouldn't allowed to modulate (spec SF 2.01 - 8.2.1) + However, as long fluidsynth will use only CC 7 bits resolution, + it is safe to ignore these SF recommendations on CC receive. + See explanations in fluid_synth_cc_LOCAL() */ + /* uncomment next line to forbid CC lsb */ + /* && ((src < 32) || (63 < src)) */ + )); +} + +/** + * Checks valid modulator sources (specs SF 2.01 7.4, 7.8, 8.2.1) + * + * @param mod, modulator. + * @param name,if not NULL, pointer on a string displayed as a warning. + * @return TRUE if modulator sources src1, src2 are valid, FALSE otherwise. + */ +int fluid_mod_check_sources(const fluid_mod_t *mod, char *name) +{ + static const char invalid_non_cc_src[] = + "Invalid modulator, using non-CC source %s.src%d=%d"; + static const char invalid_cc_src[] = + "Invalid modulator, using CC source %s.src%d=%d"; + static const char src1_is_none[] = + "Modulator with source 1 none %s.src1=%d"; + + /* checks valid non cc sources */ + if(!fluid_mod_check_non_cc_source(mod, 1)) /* check src1 */ + { + if(name) + { + FLUID_LOG(FLUID_WARN, invalid_non_cc_src, name, 1, mod->src1); + } + + return FALSE; + } + + /* + When src1 is non CC source FLUID_MOD_NONE, the modulator is valid but + the output of this modulator will be forced to 0 at synthesis time. + Also this modulator cannot be used to overwrite a default modulator (as + there is no default modulator with src1 source equal to FLUID_MOD_NONE). + Consequently it is useful to return FALSE to indicate this modulator + being useless. It will be removed later with others invalid modulators. + */ + if(fluid_mod_is_src1_none(mod)) + { + if(name) + { + FLUID_LOG(FLUID_WARN, src1_is_none, name, mod->src1); + } + + return FALSE; + } + + if(!fluid_mod_check_non_cc_source(mod, 0)) /* check src2 */ + { + if(name) + { + FLUID_LOG(FLUID_WARN, invalid_non_cc_src, name, 2, mod->src2); + } + + return FALSE; + } + + /* checks valid cc sources */ + if(!fluid_mod_check_cc_source(mod, 1)) /* check src1 */ + { + if(name) + { + FLUID_LOG(FLUID_WARN, invalid_cc_src, name, 1, mod->src1); + } + + return FALSE; + } + + if(!fluid_mod_check_cc_source(mod, 0)) /* check src2 */ + { + if(name) + { + FLUID_LOG(FLUID_WARN, invalid_cc_src, name, 2, mod->src2); + } + + return FALSE; + } + + return TRUE; +} + +/** + * Checks if two modulators are identical in sources, flags and destination. + * + * @param mod1 First modulator + * @param mod2 Second modulator + * @return TRUE if identical, FALSE otherwise + * + * SF2.01 section 9.5.1 page 69, 'bullet' 3 defines 'identical'. + */ +int +fluid_mod_test_identity(const fluid_mod_t *mod1, const fluid_mod_t *mod2) +{ + return mod1->dest == mod2->dest + && mod1->src1 == mod2->src1 + && mod1->src2 == mod2->src2 + && mod1->flags1 == mod2->flags1 + && mod1->flags2 == mod2->flags2; +} + +/** + * Check if the modulator has the given source. + * + * @param mod The modulator instance + * @param cc Boolean value indicating if ctrl is a CC controller or not + * @param ctrl The source to check for (if \c cc == FALSE : a value of type #fluid_mod_src, else the value of the MIDI CC to check for) + * + * @return TRUE if the modulator has the given source, FALSE otherwise. + */ +int fluid_mod_has_source(const fluid_mod_t *mod, int cc, int ctrl) +{ + return + ( + ( + ((mod->src1 == ctrl) && ((mod->flags1 & FLUID_MOD_CC) != 0) && (cc != 0)) + || ((mod->src1 == ctrl) && ((mod->flags1 & FLUID_MOD_CC) == 0) && (cc == 0)) + ) + || + ( + ((mod->src2 == ctrl) && ((mod->flags2 & FLUID_MOD_CC) != 0) && (cc != 0)) + || ((mod->src2 == ctrl) && ((mod->flags2 & FLUID_MOD_CC) == 0) && (cc == 0)) + ) + ); +} + +/** + * Check if the modulator has the given destination. + * + * @param mod The modulator instance + * @param gen The destination generator of type #fluid_gen_type to check for + * @return TRUE if the modulator has the given destination, FALSE otherwise. + */ +int fluid_mod_has_dest(const fluid_mod_t *mod, int gen) +{ + return mod->dest == gen; +} + + +/* debug function: Prints the contents of a modulator */ +#ifdef DEBUG +void fluid_dump_modulator(fluid_mod_t *mod) +{ + int src1 = mod->src1; + int dest = mod->dest; + int src2 = mod->src2; + int flags1 = mod->flags1; + int flags2 = mod->flags2; + fluid_real_t amount = (fluid_real_t)mod->amount; + + printf("Src: "); + + if(flags1 & FLUID_MOD_CC) + { + printf("MIDI CC=%i", src1); + } + else + { + switch(src1) + { + case FLUID_MOD_NONE: + printf("None"); + break; + + case FLUID_MOD_VELOCITY: + printf("note-on velocity"); + break; + + case FLUID_MOD_KEY: + printf("Key nr"); + break; + + case FLUID_MOD_KEYPRESSURE: + printf("Poly pressure"); + break; + + case FLUID_MOD_CHANNELPRESSURE: + printf("Chan pressure"); + break; + + case FLUID_MOD_PITCHWHEEL: + printf("Pitch Wheel"); + break; + + case FLUID_MOD_PITCHWHEELSENS: + printf("Pitch Wheel sens"); + break; + + default: + printf("(unknown: %i)", src1); + }; /* switch src1 */ + }; /* if not CC */ + + if(flags1 & FLUID_MOD_NEGATIVE) + { + printf("- "); + } + else + { + printf("+ "); + }; + + if(flags1 & FLUID_MOD_BIPOLAR) + { + printf("bip "); + } + else + { + printf("unip "); + }; + + printf("-> "); + + switch(dest) + { + case GEN_FILTERQ: + printf("Q"); + break; + + case GEN_FILTERFC: + printf("fc"); + break; + + case GEN_CUSTOM_FILTERQ: + printf("custom-Q"); + break; + + case GEN_CUSTOM_FILTERFC: + printf("custom-fc"); + break; + + case GEN_VIBLFOTOPITCH: + printf("VibLFO-to-pitch"); + break; + + case GEN_MODENVTOPITCH: + printf("ModEnv-to-pitch"); + break; + + case GEN_MODLFOTOPITCH: + printf("ModLFO-to-pitch"); + break; + + case GEN_CHORUSSEND: + printf("Chorus send"); + break; + + case GEN_REVERBSEND: + printf("Reverb send"); + break; + + case GEN_PAN: + printf("pan"); + break; + + case GEN_CUSTOM_BALANCE: + printf("balance"); + break; + + case GEN_ATTENUATION: + printf("att"); + break; + + default: + printf("dest %i", dest); + }; /* switch dest */ + + printf(", amount %f flags %i src2 %i flags2 %i\n", amount, flags1, src2, flags2); +}; +#endif diff --git a/libs/fluidsynth/src/synth/fluid_mod.h b/libs/fluidsynth/src/synth/fluid_mod.h new file mode 100644 index 00000000000..3e7661741f9 --- /dev/null +++ b/libs/fluidsynth/src/synth/fluid_mod.h @@ -0,0 +1,54 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUID_MOD_H +#define _FLUID_MOD_H + +#include "fluidsynth_priv.h" +#include "fluid_conv.h" + +/* + * Modulator structure. See SoundFont 2.04 PDF section 8.2. + */ +struct _fluid_mod_t +{ + unsigned char dest; /**< Destination generator to control */ + unsigned char src1; /**< Source controller 1 */ + unsigned char flags1; /**< Source controller 1 flags */ + unsigned char src2; /**< Source controller 2 */ + unsigned char flags2; /**< Source controller 2 flags */ + double amount; /**< Multiplier amount */ + /* The 'next' field allows to link modulators into a list. It is + * not used in fluid_voice.c, there each voice allocates memory for a + * fixed number of modulators. Since there may be a huge number of + * different zones, this is more efficient. + */ + fluid_mod_t *next; +}; + +fluid_real_t fluid_mod_get_value(fluid_mod_t *mod, fluid_voice_t *voice); +int fluid_mod_check_sources(const fluid_mod_t *mod, char *name); + +#ifdef DEBUG +void fluid_dump_modulator(fluid_mod_t *mod); +#endif + + +#endif /* _FLUID_MOD_H */ diff --git a/libs/fluidsynth/src/synth/fluid_synth.c b/libs/fluidsynth/src/synth/fluid_synth.c new file mode 100644 index 00000000000..3b83e3d8b73 --- /dev/null +++ b/libs/fluidsynth/src/synth/fluid_synth.c @@ -0,0 +1,8445 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include "fluid_synth.h" +#include "fluid_sys.h" +#include "fluid_chan.h" +#include "fluid_tuning.h" +#include "fluid_settings.h" +#include "fluid_sfont.h" +#include "fluid_defsfont.h" +#include "fluid_instpatch.h" + +#ifdef TRAP_ON_FPE +#define _GNU_SOURCE +#include + +/* seems to not be declared in fenv.h */ +extern int feenableexcept(int excepts); +#endif + +#define FLUID_API_RETURN(return_value) \ + do { fluid_synth_api_exit(synth); \ + return return_value; } while (0) + +#define FLUID_API_RETURN_IF_CHAN_DISABLED(return_value) \ + do { if (FLUID_LIKELY(synth->channel[chan]->mode & FLUID_CHANNEL_ENABLED)) \ + {} \ + else \ + { FLUID_API_RETURN(return_value); } \ + } while (0) + +#define FLUID_API_ENTRY_CHAN(fail_value) \ + fluid_return_val_if_fail (synth != NULL, fail_value); \ + fluid_return_val_if_fail (chan >= 0, fail_value); \ + fluid_synth_api_enter(synth); \ + if (chan >= synth->midi_channels) { \ + FLUID_API_RETURN(fail_value); \ + } \ + +static void fluid_synth_init(void); +static void fluid_synth_api_enter(fluid_synth_t *synth); +static void fluid_synth_api_exit(fluid_synth_t *synth); + +static int fluid_synth_noteon_LOCAL(fluid_synth_t *synth, int chan, int key, + int vel); +static int fluid_synth_noteoff_LOCAL(fluid_synth_t *synth, int chan, int key); +static int fluid_synth_cc_LOCAL(fluid_synth_t *synth, int channum, int num); +static int fluid_synth_sysex_midi_tuning(fluid_synth_t *synth, const char *data, + int len, char *response, + int *response_len, int avail_response, + int *handled, int dryrun); +static int fluid_synth_sysex_gs_dt1(fluid_synth_t *synth, const char *data, + int len, char *response, + int *response_len, int avail_response, + int *handled, int dryrun); +static int fluid_synth_sysex_xg(fluid_synth_t *synth, const char *data, + int len, char *response, + int *response_len, int avail_response, + int *handled, int dryrun); +int fluid_synth_all_notes_off_LOCAL(fluid_synth_t *synth, int chan); +static int fluid_synth_all_sounds_off_LOCAL(fluid_synth_t *synth, int chan); +static int fluid_synth_system_reset_LOCAL(fluid_synth_t *synth); +static int fluid_synth_modulate_voices_LOCAL(fluid_synth_t *synth, int chan, + int is_cc, int ctrl); +static int fluid_synth_modulate_voices_all_LOCAL(fluid_synth_t *synth, int chan); +static int fluid_synth_update_channel_pressure_LOCAL(fluid_synth_t *synth, int channum); +static int fluid_synth_update_key_pressure_LOCAL(fluid_synth_t *synth, int chan, int key); +static int fluid_synth_update_pitch_bend_LOCAL(fluid_synth_t *synth, int chan); +static int fluid_synth_update_pitch_wheel_sens_LOCAL(fluid_synth_t *synth, int chan); +static int fluid_synth_set_preset(fluid_synth_t *synth, int chan, + fluid_preset_t *preset); +static int fluid_synth_reverb_get_param(fluid_synth_t *synth, int fx_group, + int param, double *value); +static int fluid_synth_chorus_get_param(fluid_synth_t *synth, int fx_group, + int param, double *value); + +static fluid_preset_t * +fluid_synth_get_preset(fluid_synth_t *synth, int sfontnum, + int banknum, int prognum); +static fluid_preset_t * +fluid_synth_get_preset_by_sfont_name(fluid_synth_t *synth, const char *sfontname, + int banknum, int prognum); + +static void fluid_synth_update_presets(fluid_synth_t *synth); +static void fluid_synth_update_gain_LOCAL(fluid_synth_t *synth); +static int fluid_synth_update_polyphony_LOCAL(fluid_synth_t *synth, int new_polyphony); +static void init_dither(void); +static FLUID_INLINE int16_t round_clip_to_i16(float x); +static int fluid_synth_render_blocks(fluid_synth_t *synth, int blockcount); + +static fluid_voice_t *fluid_synth_free_voice_by_kill_LOCAL(fluid_synth_t *synth); +static void fluid_synth_kill_by_exclusive_class_LOCAL(fluid_synth_t *synth, + fluid_voice_t *new_voice); +static int fluid_synth_sfunload_callback(void *data, unsigned int msec); +static fluid_tuning_t *fluid_synth_get_tuning(fluid_synth_t *synth, + int bank, int prog); +static int fluid_synth_replace_tuning_LOCK(fluid_synth_t *synth, + fluid_tuning_t *tuning, + int bank, int prog, int apply); +static void fluid_synth_replace_tuning_LOCAL(fluid_synth_t *synth, + fluid_tuning_t *old_tuning, + fluid_tuning_t *new_tuning, + int apply, int unref_new); +static void fluid_synth_update_voice_tuning_LOCAL(fluid_synth_t *synth, + fluid_channel_t *channel); +static int fluid_synth_set_tuning_LOCAL(fluid_synth_t *synth, int chan, + fluid_tuning_t *tuning, int apply); +static void fluid_synth_set_gen_LOCAL(fluid_synth_t *synth, int chan, + int param, float value); +static void fluid_synth_stop_LOCAL(fluid_synth_t *synth, unsigned int id); + + +static int fluid_synth_set_important_channels(fluid_synth_t *synth, const char *channels); + + +/* Callback handlers for real-time settings */ +static void fluid_synth_handle_gain(void *data, const char *name, double value); +static void fluid_synth_handle_polyphony(void *data, const char *name, int value); +static void fluid_synth_handle_device_id(void *data, const char *name, int value); +static void fluid_synth_handle_overflow(void *data, const char *name, double value); +static void fluid_synth_handle_important_channels(void *data, const char *name, + const char *value); +static void fluid_synth_handle_reverb_chorus_num(void *data, const char *name, double value); +static void fluid_synth_handle_reverb_chorus_int(void *data, const char *name, int value); + + +static void fluid_synth_reset_basic_channel_LOCAL(fluid_synth_t *synth, int chan, int nbr_chan); +static int fluid_synth_check_next_basic_channel(fluid_synth_t *synth, int basicchan, int mode, int val); +static void fluid_synth_set_basic_channel_LOCAL(fluid_synth_t *synth, int basicchan, int mode, int val); + +/*************************************************************** + * + * GLOBAL + */ + +/* has the synth module been initialized? */ +/* fluid_atomic_int_t may be anything, so init with {0} to catch most cases */ +static fluid_atomic_int_t fluid_synth_initialized = {0}; + +/* default modulators + * SF2.01 page 52 ff: + * + * There is a set of predefined default modulators. They have to be + * explicitly overridden by the sound font in order to turn them off. + */ + +static fluid_mod_t default_vel2att_mod; /* SF2.01 section 8.4.1 */ +/*not static */ fluid_mod_t default_vel2filter_mod; /* SF2.01 section 8.4.2 */ +static fluid_mod_t default_at2viblfo_mod; /* SF2.01 section 8.4.3 */ +static fluid_mod_t default_mod2viblfo_mod; /* SF2.01 section 8.4.4 */ +static fluid_mod_t default_att_mod; /* SF2.01 section 8.4.5 */ +static fluid_mod_t default_pan_mod; /* SF2.01 section 8.4.6 */ +static fluid_mod_t default_expr_mod; /* SF2.01 section 8.4.7 */ +static fluid_mod_t default_reverb_mod; /* SF2.01 section 8.4.8 */ +static fluid_mod_t default_chorus_mod; /* SF2.01 section 8.4.9 */ +static fluid_mod_t default_pitch_bend_mod; /* SF2.01 section 8.4.10 */ +static fluid_mod_t custom_balance_mod; /* Non-standard modulator */ + + +/* custom_breath2att_modulator is not a default modulator specified in SF +it is intended to replace default_vel2att_mod on demand using +API fluid_set_breath_mode() or command shell setbreathmode. +*/ +static fluid_mod_t custom_breath2att_mod; + +/* reverb presets */ +static const fluid_revmodel_presets_t revmodel_preset[] = +{ + /* name */ /* roomsize */ /* damp */ /* width */ /* level */ + { "Test 1", 0.2f, 0.0f, 0.5f, 0.9f }, + { "Test 2", 0.4f, 0.2f, 0.5f, 0.8f }, + { "Test 3", 0.6f, 0.4f, 0.5f, 0.7f }, + { "Test 4", 0.8f, 0.7f, 0.5f, 0.6f }, + { "Test 5", 0.8f, 1.0f, 0.5f, 0.5f }, +}; + + +/*************************************************************** + * + * INITIALIZATION & UTILITIES + */ + +void fluid_synth_settings(fluid_settings_t *settings) +{ + fluid_settings_register_int(settings, "synth.verbose", 0, 0, 1, FLUID_HINT_TOGGLED); + + fluid_settings_register_int(settings, "synth.reverb.active", 1, 0, 1, FLUID_HINT_TOGGLED); + fluid_settings_register_num(settings, "synth.reverb.room-size", FLUID_REVERB_DEFAULT_ROOMSIZE, 0.0f, 1.0f, 0); + fluid_settings_register_num(settings, "synth.reverb.damp", FLUID_REVERB_DEFAULT_DAMP, 0.0f, 1.0f, 0); + fluid_settings_register_num(settings, "synth.reverb.width", FLUID_REVERB_DEFAULT_WIDTH, 0.0f, 100.0f, 0); + fluid_settings_register_num(settings, "synth.reverb.level", FLUID_REVERB_DEFAULT_LEVEL, 0.0f, 1.0f, 0); + + fluid_settings_register_int(settings, "synth.chorus.active", 1, 0, 1, FLUID_HINT_TOGGLED); + fluid_settings_register_int(settings, "synth.chorus.nr", FLUID_CHORUS_DEFAULT_N, 0, 99, 0); + fluid_settings_register_num(settings, "synth.chorus.level", FLUID_CHORUS_DEFAULT_LEVEL, 0.0f, 10.0f, 0); + fluid_settings_register_num(settings, "synth.chorus.speed", FLUID_CHORUS_DEFAULT_SPEED, 0.1f, 5.0f, 0); + fluid_settings_register_num(settings, "synth.chorus.depth", FLUID_CHORUS_DEFAULT_DEPTH, 0.0f, 256.0f, 0); + + fluid_settings_register_int(settings, "synth.ladspa.active", 0, 0, 1, FLUID_HINT_TOGGLED); + fluid_settings_register_int(settings, "synth.lock-memory", 1, 0, 1, FLUID_HINT_TOGGLED); + fluid_settings_register_str(settings, "midi.portname", "", 0); + +#ifdef DEFAULT_SOUNDFONT + fluid_settings_register_str(settings, "synth.default-soundfont", DEFAULT_SOUNDFONT, 0); +#endif + + fluid_settings_register_int(settings, "synth.polyphony", 256, 1, 65535, 0); + fluid_settings_register_int(settings, "synth.midi-channels", 16, 16, 256, 0); + fluid_settings_register_num(settings, "synth.gain", 0.2f, 0.0f, 10.0f, 0); + fluid_settings_register_int(settings, "synth.audio-channels", 1, 1, 128, 0); + fluid_settings_register_int(settings, "synth.audio-groups", 1, 1, 128, 0); + fluid_settings_register_int(settings, "synth.effects-channels", 2, 2, 2, 0); + fluid_settings_register_int(settings, "synth.effects-groups", 1, 1, 128, 0); + fluid_settings_register_num(settings, "synth.sample-rate", 44100.0f, 8000.0f, 96000.0f, 0); + fluid_settings_register_int(settings, "synth.device-id", 0, 0, 127, 0); +#ifdef ENABLE_MIXER_THREADS + fluid_settings_register_int(settings, "synth.cpu-cores", 1, 1, 256, 0); +#else + fluid_settings_register_int(settings, "synth.cpu-cores", 1, 1, 1, 0); +#endif + + fluid_settings_register_int(settings, "synth.min-note-length", 10, 0, 65535, 0); + + fluid_settings_register_int(settings, "synth.threadsafe-api", 1, 0, 1, FLUID_HINT_TOGGLED); + + fluid_settings_register_num(settings, "synth.overflow.percussion", 4000, -10000, 10000, 0); + fluid_settings_register_num(settings, "synth.overflow.sustained", -1000, -10000, 10000, 0); + fluid_settings_register_num(settings, "synth.overflow.released", -2000, -10000, 10000, 0); + fluid_settings_register_num(settings, "synth.overflow.age", 1000, -10000, 10000, 0); + fluid_settings_register_num(settings, "synth.overflow.volume", 500, -10000, 10000, 0); + fluid_settings_register_num(settings, "synth.overflow.important", 5000, -50000, 50000, 0); + fluid_settings_register_str(settings, "synth.overflow.important-channels", "", 0); + + fluid_settings_register_str(settings, "synth.midi-bank-select", "gs", 0); + fluid_settings_add_option(settings, "synth.midi-bank-select", "gm"); + fluid_settings_add_option(settings, "synth.midi-bank-select", "gs"); + fluid_settings_add_option(settings, "synth.midi-bank-select", "xg"); + fluid_settings_add_option(settings, "synth.midi-bank-select", "mma"); + + fluid_settings_register_int(settings, "synth.dynamic-sample-loading", 0, 0, 1, FLUID_HINT_TOGGLED); +} + +/** + * Get FluidSynth runtime version. + * @param major Location to store major number + * @param minor Location to store minor number + * @param micro Location to store micro number + */ +void fluid_version(int *major, int *minor, int *micro) +{ + *major = FLUIDSYNTH_VERSION_MAJOR; + *minor = FLUIDSYNTH_VERSION_MINOR; + *micro = FLUIDSYNTH_VERSION_MICRO; +} + +/** + * Get FluidSynth runtime version as a string. + * @return FluidSynth version string, which is internal and should not be + * modified or freed. + */ +char * +fluid_version_str(void) +{ + return FLUIDSYNTH_VERSION; +} + +/* + * void fluid_synth_init + * + * Does all the initialization for this module. + */ +static void +fluid_synth_init(void) +{ +#ifdef TRAP_ON_FPE + #if !defined(__GLIBC__) && defined(__linux__) + #warning "Trap on FPE is only supported when using glibc!" + #else + /* Turn on floating point exception traps */ + feenableexcept(FE_DIVBYZERO | FE_OVERFLOW | FE_INVALID); + #endif +#endif + + init_dither(); + + /* custom_breath2att_mod is not a default modulator specified in SF2.01. + it is intended to replace default_vel2att_mod on demand using + API fluid_set_breath_mode() or command shell setbreathmode. + */ + fluid_mod_set_source1(&custom_breath2att_mod, /* The modulator we are programming here */ + BREATH_MSB, /* Source. breath MSB corresponds to 2. */ + FLUID_MOD_CC /* MIDI continuous controller */ + | FLUID_MOD_CONCAVE /* Curve shape. Corresponds to 'type=1' */ + | FLUID_MOD_UNIPOLAR /* Polarity. Corresponds to 'P=0' */ + | FLUID_MOD_NEGATIVE /* Direction. Corresponds to 'D=1' */ + ); + fluid_mod_set_source2(&custom_breath2att_mod, 0, 0); /* No 2nd source */ + fluid_mod_set_dest(&custom_breath2att_mod, GEN_ATTENUATION); /* Target: Initial attenuation */ + fluid_mod_set_amount(&custom_breath2att_mod, FLUID_PEAK_ATTENUATION); /* Modulation amount: 960 */ + + /* SF2.01 page 53 section 8.4.1: MIDI Note-On Velocity to Initial Attenuation */ + fluid_mod_set_source1(&default_vel2att_mod, /* The modulator we are programming here */ + FLUID_MOD_VELOCITY, /* Source. VELOCITY corresponds to 'index=2'. */ + FLUID_MOD_GC /* Not a MIDI continuous controller */ + | FLUID_MOD_CONCAVE /* Curve shape. Corresponds to 'type=1' */ + | FLUID_MOD_UNIPOLAR /* Polarity. Corresponds to 'P=0' */ + | FLUID_MOD_NEGATIVE /* Direction. Corresponds to 'D=1' */ + ); + fluid_mod_set_source2(&default_vel2att_mod, 0, 0); /* No 2nd source */ + fluid_mod_set_dest(&default_vel2att_mod, GEN_ATTENUATION); /* Target: Initial attenuation */ + fluid_mod_set_amount(&default_vel2att_mod, FLUID_PEAK_ATTENUATION); /* Modulation amount: 960 */ + + + + /* SF2.01 page 53 section 8.4.2: MIDI Note-On Velocity to Filter Cutoff + * Have to make a design decision here. The specs don't make any sense this way or another. + * One sound font, 'Kingston Piano', which has been praised for its quality, tries to + * override this modulator with an amount of 0 and positive polarity (instead of what + * the specs say, D=1) for the secondary source. + * So if we change the polarity to 'positive', one of the best free sound fonts works... + */ + fluid_mod_set_source1(&default_vel2filter_mod, FLUID_MOD_VELOCITY, /* Index=2 */ + FLUID_MOD_GC /* CC=0 */ + | FLUID_MOD_LINEAR /* type=0 */ + | FLUID_MOD_UNIPOLAR /* P=0 */ + | FLUID_MOD_NEGATIVE /* D=1 */ + ); + fluid_mod_set_source2(&default_vel2filter_mod, FLUID_MOD_VELOCITY, /* Index=2 */ + FLUID_MOD_GC /* CC=0 */ + | FLUID_MOD_SWITCH /* type=3 */ + | FLUID_MOD_UNIPOLAR /* P=0 */ + // do not remove | FLUID_MOD_NEGATIVE /* D=1 */ + | FLUID_MOD_POSITIVE /* D=0 */ + ); + fluid_mod_set_dest(&default_vel2filter_mod, GEN_FILTERFC); /* Target: Initial filter cutoff */ + fluid_mod_set_amount(&default_vel2filter_mod, -2400); + + + + /* SF2.01 page 53 section 8.4.3: MIDI Channel pressure to Vibrato LFO pitch depth */ + fluid_mod_set_source1(&default_at2viblfo_mod, FLUID_MOD_CHANNELPRESSURE, /* Index=13 */ + FLUID_MOD_GC /* CC=0 */ + | FLUID_MOD_LINEAR /* type=0 */ + | FLUID_MOD_UNIPOLAR /* P=0 */ + | FLUID_MOD_POSITIVE /* D=0 */ + ); + fluid_mod_set_source2(&default_at2viblfo_mod, 0, 0); /* no second source */ + fluid_mod_set_dest(&default_at2viblfo_mod, GEN_VIBLFOTOPITCH); /* Target: Vib. LFO => pitch */ + fluid_mod_set_amount(&default_at2viblfo_mod, 50); + + + + /* SF2.01 page 53 section 8.4.4: Mod wheel (Controller 1) to Vibrato LFO pitch depth */ + fluid_mod_set_source1(&default_mod2viblfo_mod, MODULATION_MSB, /* Index=1 */ + FLUID_MOD_CC /* CC=1 */ + | FLUID_MOD_LINEAR /* type=0 */ + | FLUID_MOD_UNIPOLAR /* P=0 */ + | FLUID_MOD_POSITIVE /* D=0 */ + ); + fluid_mod_set_source2(&default_mod2viblfo_mod, 0, 0); /* no second source */ + fluid_mod_set_dest(&default_mod2viblfo_mod, GEN_VIBLFOTOPITCH); /* Target: Vib. LFO => pitch */ + fluid_mod_set_amount(&default_mod2viblfo_mod, 50); + + + + /* SF2.01 page 55 section 8.4.5: MIDI continuous controller 7 to initial attenuation*/ + fluid_mod_set_source1(&default_att_mod, VOLUME_MSB, /* index=7 */ + FLUID_MOD_CC /* CC=1 */ + | FLUID_MOD_CONCAVE /* type=1 */ + | FLUID_MOD_UNIPOLAR /* P=0 */ + | FLUID_MOD_NEGATIVE /* D=1 */ + ); + fluid_mod_set_source2(&default_att_mod, 0, 0); /* No second source */ + fluid_mod_set_dest(&default_att_mod, GEN_ATTENUATION); /* Target: Initial attenuation */ + fluid_mod_set_amount(&default_att_mod, FLUID_PEAK_ATTENUATION); /* Amount: 960 */ + + + + /* SF2.01 page 55 section 8.4.6 MIDI continuous controller 10 to Pan Position */ + fluid_mod_set_source1(&default_pan_mod, PAN_MSB, /* index=10 */ + FLUID_MOD_CC /* CC=1 */ + | FLUID_MOD_LINEAR /* type=0 */ + | FLUID_MOD_BIPOLAR /* P=1 */ + | FLUID_MOD_POSITIVE /* D=0 */ + ); + fluid_mod_set_source2(&default_pan_mod, 0, 0); /* No second source */ + fluid_mod_set_dest(&default_pan_mod, GEN_PAN); /* Target: pan */ + /* Amount: 500. The SF specs $8.4.6, p. 55 says: "Amount = 1000 + tenths of a percent". The center value (64) corresponds to 50%, + so it follows that amount = 50% x 1000/% = 500. */ + fluid_mod_set_amount(&default_pan_mod, 500.0); + + + /* SF2.01 page 55 section 8.4.7: MIDI continuous controller 11 to initial attenuation*/ + fluid_mod_set_source1(&default_expr_mod, EXPRESSION_MSB, /* index=11 */ + FLUID_MOD_CC /* CC=1 */ + | FLUID_MOD_CONCAVE /* type=1 */ + | FLUID_MOD_UNIPOLAR /* P=0 */ + | FLUID_MOD_NEGATIVE /* D=1 */ + ); + fluid_mod_set_source2(&default_expr_mod, 0, 0); /* No second source */ + fluid_mod_set_dest(&default_expr_mod, GEN_ATTENUATION); /* Target: Initial attenuation */ + fluid_mod_set_amount(&default_expr_mod, FLUID_PEAK_ATTENUATION); /* Amount: 960 */ + + + + /* SF2.01 page 55 section 8.4.8: MIDI continuous controller 91 to Reverb send */ + fluid_mod_set_source1(&default_reverb_mod, EFFECTS_DEPTH1, /* index=91 */ + FLUID_MOD_CC /* CC=1 */ + | FLUID_MOD_LINEAR /* type=0 */ + | FLUID_MOD_UNIPOLAR /* P=0 */ + | FLUID_MOD_POSITIVE /* D=0 */ + ); + fluid_mod_set_source2(&default_reverb_mod, 0, 0); /* No second source */ + fluid_mod_set_dest(&default_reverb_mod, GEN_REVERBSEND); /* Target: Reverb send */ + fluid_mod_set_amount(&default_reverb_mod, 200); /* Amount: 200 ('tenths of a percent') */ + + + + /* SF2.01 page 55 section 8.4.9: MIDI continuous controller 93 to Chorus send */ + fluid_mod_set_source1(&default_chorus_mod, EFFECTS_DEPTH3, /* index=93 */ + FLUID_MOD_CC /* CC=1 */ + | FLUID_MOD_LINEAR /* type=0 */ + | FLUID_MOD_UNIPOLAR /* P=0 */ + | FLUID_MOD_POSITIVE /* D=0 */ + ); + fluid_mod_set_source2(&default_chorus_mod, 0, 0); /* No second source */ + fluid_mod_set_dest(&default_chorus_mod, GEN_CHORUSSEND); /* Target: Chorus */ + fluid_mod_set_amount(&default_chorus_mod, 200); /* Amount: 200 ('tenths of a percent') */ + + + + /* SF2.01 page 57 section 8.4.10 MIDI Pitch Wheel to Initial Pitch ... */ + /* Initial Pitch is not a "standard" generator, because it isn't mentioned in the + list of generators in the SF2 specifications. That's why destination Initial Pitch + is replaced here by fine tune generator. + */ + fluid_mod_set_source1(&default_pitch_bend_mod, FLUID_MOD_PITCHWHEEL, /* Index=14 */ + FLUID_MOD_GC /* CC =0 */ + | FLUID_MOD_LINEAR /* type=0 */ + | FLUID_MOD_BIPOLAR /* P=1 */ + | FLUID_MOD_POSITIVE /* D=0 */ + ); + fluid_mod_set_source2(&default_pitch_bend_mod, FLUID_MOD_PITCHWHEELSENS, /* Index = 16 */ + FLUID_MOD_GC /* CC=0 */ + | FLUID_MOD_LINEAR /* type=0 */ + | FLUID_MOD_UNIPOLAR /* P=0 */ + | FLUID_MOD_POSITIVE /* D=0 */ + ); + /* Also see the comment in gen.h about GEN_PITCH */ + fluid_mod_set_dest(&default_pitch_bend_mod, GEN_FINETUNE); /* Destination: Fine Tune */ + fluid_mod_set_amount(&default_pitch_bend_mod, 12700.0); /* Amount: 12700 cents */ + + + /* Non-standard MIDI continuous controller 8 to channel stereo balance */ + fluid_mod_set_source1(&custom_balance_mod, BALANCE_MSB, /* Index=8 */ + FLUID_MOD_CC /* CC=1 */ + | FLUID_MOD_CONCAVE /* type=1 */ + | FLUID_MOD_BIPOLAR /* P=1 */ + | FLUID_MOD_POSITIVE /* D=0 */ + ); + fluid_mod_set_source2(&custom_balance_mod, 0, 0); + fluid_mod_set_dest(&custom_balance_mod, GEN_CUSTOM_BALANCE); /* Destination: stereo balance */ + /* Amount: 96 dB of attenuation (on the opposite channel) */ + fluid_mod_set_amount(&custom_balance_mod, FLUID_PEAK_ATTENUATION); /* Amount: 960 */ + +#if defined(LIBINSTPATCH_SUPPORT) + /* defer libinstpatch init to fluid_instpatch.c to avoid #include "libinstpatch.h" */ + if(!fluid_instpatch_supports_multi_init()) + { + fluid_instpatch_init(); + } +#endif +} + +static FLUID_INLINE unsigned int fluid_synth_get_ticks(fluid_synth_t *synth) +{ + return fluid_atomic_int_get(&synth->ticks_since_start); +} + +static FLUID_INLINE void fluid_synth_add_ticks(fluid_synth_t *synth, int val) +{ + fluid_atomic_int_add(&synth->ticks_since_start, val); +} + + +/*************************************************************** + * FLUID SAMPLE TIMERS + * Timers that use written audio data as timing reference + */ +struct _fluid_sample_timer_t +{ + fluid_sample_timer_t *next; /* Single linked list of timers */ + unsigned long starttick; + fluid_timer_callback_t callback; + void *data; + int isfinished; +}; + +/* + * fluid_sample_timer_process - called when synth->ticks is updated + */ +static void fluid_sample_timer_process(fluid_synth_t *synth) +{ + fluid_sample_timer_t *st; + long msec; + int cont; + unsigned int ticks = fluid_synth_get_ticks(synth); + + for(st = synth->sample_timers; st; st = st->next) + { + if(st->isfinished) + { + continue; + } + + msec = (long)(1000.0 * ((double)(ticks - st->starttick)) / synth->sample_rate); + cont = (*st->callback)(st->data, msec); + + if(cont == 0) + { + st->isfinished = 1; + } + } +} + +fluid_sample_timer_t *new_fluid_sample_timer(fluid_synth_t *synth, fluid_timer_callback_t callback, void *data) +{ + fluid_sample_timer_t *result = FLUID_NEW(fluid_sample_timer_t); + + if(result == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + fluid_sample_timer_reset(synth, result); + result->data = data; + result->callback = callback; + result->next = synth->sample_timers; + synth->sample_timers = result; + return result; +} + +void delete_fluid_sample_timer(fluid_synth_t *synth, fluid_sample_timer_t *timer) +{ + fluid_sample_timer_t **ptr; + fluid_return_if_fail(synth != NULL); + fluid_return_if_fail(timer != NULL); + + ptr = &synth->sample_timers; + + while(*ptr) + { + if(*ptr == timer) + { + *ptr = timer->next; + FLUID_FREE(timer); + return; + } + + ptr = &((*ptr)->next); + } +} + +void fluid_sample_timer_reset(fluid_synth_t *synth, fluid_sample_timer_t *timer) +{ + timer->starttick = fluid_synth_get_ticks(synth); + timer->isfinished = 0; +} + +/*************************************************************** + * + * FLUID SYNTH + */ + +static FLUID_INLINE void +fluid_synth_update_mixer(fluid_synth_t *synth, fluid_rvoice_function_t method, int intparam, + fluid_real_t realparam) +{ + fluid_return_if_fail(synth != NULL && synth->eventhandler != NULL); + fluid_return_if_fail(synth->eventhandler->mixer != NULL); + fluid_rvoice_eventhandler_push_int_real(synth->eventhandler, method, + synth->eventhandler->mixer, + intparam, realparam); +} + +static FLUID_INLINE unsigned int fluid_synth_get_min_note_length_LOCAL(fluid_synth_t *synth) +{ + int i; + fluid_settings_getint(synth->settings, "synth.min-note-length", &i); + return (unsigned int)(i * synth->sample_rate / 1000.0f); +} + +/** + * Create new FluidSynth instance. + * @param settings Configuration parameters to use (used directly). + * @return New FluidSynth instance or NULL on error + * + * @note The @p settings parameter is used directly, but the synth does not take ownership of it. + * Hence, the caller is responsible for freeing it, when no longer needed. + * Further note that you may modify FluidSettings of the + * @p settings instance. However, only those FluidSettings marked as 'realtime' will + * affect the synth immediately. See the \ref fluidsettings for more details. + * + * @warning The @p settings object should only be used by a single synth at a time. I.e. creating + * multiple synth instances with a single @p settings object causes undefined behavior. Once the + * "single synth" has been deleted, you may use the @p settings object again for another synth. + */ +fluid_synth_t * +new_fluid_synth(fluid_settings_t *settings) +{ + fluid_synth_t *synth; + fluid_sfloader_t *loader; + char *important_channels; + int i, prio_level = 0; + int with_ladspa = 0; + double sample_rate_min, sample_rate_max; + + /* initialize all the conversion tables and other stuff */ + if(fluid_atomic_int_compare_and_exchange(&fluid_synth_initialized, 0, 1)) + { + fluid_synth_init(); + } + + /* allocate a new synthesizer object */ + synth = FLUID_NEW(fluid_synth_t); + + if(synth == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + FLUID_MEMSET(synth, 0, sizeof(fluid_synth_t)); + +#if defined(LIBINSTPATCH_SUPPORT) + if(fluid_instpatch_supports_multi_init()) + { + fluid_instpatch_init(); + } +#endif + + fluid_rec_mutex_init(synth->mutex); + fluid_settings_getint(settings, "synth.threadsafe-api", &synth->use_mutex); + synth->public_api_count = 0; + + synth->settings = settings; + + fluid_settings_getint(settings, "synth.reverb.active", &synth->with_reverb); + fluid_settings_getint(settings, "synth.chorus.active", &synth->with_chorus); + fluid_settings_getint(settings, "synth.verbose", &synth->verbose); + + fluid_settings_getint(settings, "synth.polyphony", &synth->polyphony); + fluid_settings_getnum(settings, "synth.sample-rate", &synth->sample_rate); + fluid_settings_getnum_range(settings, "synth.sample-rate", &sample_rate_min, &sample_rate_max); + fluid_settings_getint(settings, "synth.midi-channels", &synth->midi_channels); + fluid_settings_getint(settings, "synth.audio-channels", &synth->audio_channels); + fluid_settings_getint(settings, "synth.audio-groups", &synth->audio_groups); + fluid_settings_getint(settings, "synth.effects-channels", &synth->effects_channels); + fluid_settings_getint(settings, "synth.effects-groups", &synth->effects_groups); + fluid_settings_getnum_float(settings, "synth.gain", &synth->gain); + fluid_settings_getint(settings, "synth.device-id", &synth->device_id); + fluid_settings_getint(settings, "synth.cpu-cores", &synth->cores); + + fluid_settings_getnum_float(settings, "synth.overflow.percussion", &synth->overflow.percussion); + fluid_settings_getnum_float(settings, "synth.overflow.released", &synth->overflow.released); + fluid_settings_getnum_float(settings, "synth.overflow.sustained", &synth->overflow.sustained); + fluid_settings_getnum_float(settings, "synth.overflow.volume", &synth->overflow.volume); + fluid_settings_getnum_float(settings, "synth.overflow.age", &synth->overflow.age); + fluid_settings_getnum_float(settings, "synth.overflow.important", &synth->overflow.important); + + /* register the callbacks */ + fluid_settings_callback_num(settings, "synth.gain", + fluid_synth_handle_gain, synth); + fluid_settings_callback_int(settings, "synth.polyphony", + fluid_synth_handle_polyphony, synth); + fluid_settings_callback_int(settings, "synth.device-id", + fluid_synth_handle_device_id, synth); + fluid_settings_callback_num(settings, "synth.overflow.percussion", + fluid_synth_handle_overflow, synth); + fluid_settings_callback_num(settings, "synth.overflow.sustained", + fluid_synth_handle_overflow, synth); + fluid_settings_callback_num(settings, "synth.overflow.released", + fluid_synth_handle_overflow, synth); + fluid_settings_callback_num(settings, "synth.overflow.age", + fluid_synth_handle_overflow, synth); + fluid_settings_callback_num(settings, "synth.overflow.volume", + fluid_synth_handle_overflow, synth); + fluid_settings_callback_num(settings, "synth.overflow.important", + fluid_synth_handle_overflow, synth); + fluid_settings_callback_str(settings, "synth.overflow.important-channels", + fluid_synth_handle_important_channels, synth); + fluid_settings_callback_num(settings, "synth.reverb.room-size", + fluid_synth_handle_reverb_chorus_num, synth); + fluid_settings_callback_num(settings, "synth.reverb.damp", + fluid_synth_handle_reverb_chorus_num, synth); + fluid_settings_callback_num(settings, "synth.reverb.width", + fluid_synth_handle_reverb_chorus_num, synth); + fluid_settings_callback_num(settings, "synth.reverb.level", + fluid_synth_handle_reverb_chorus_num, synth); + fluid_settings_callback_int(settings, "synth.reverb.active", + fluid_synth_handle_reverb_chorus_int, synth); + fluid_settings_callback_int(settings, "synth.chorus.active", + fluid_synth_handle_reverb_chorus_int, synth); + fluid_settings_callback_int(settings, "synth.chorus.nr", + fluid_synth_handle_reverb_chorus_int, synth); + fluid_settings_callback_num(settings, "synth.chorus.level", + fluid_synth_handle_reverb_chorus_num, synth); + fluid_settings_callback_num(settings, "synth.chorus.depth", + fluid_synth_handle_reverb_chorus_num, synth); + fluid_settings_callback_num(settings, "synth.chorus.speed", + fluid_synth_handle_reverb_chorus_num, synth); + + /* do some basic sanity checking on the settings */ + + if(synth->midi_channels % 16 != 0) + { + int n = synth->midi_channels / 16; + synth->midi_channels = (n + 1) * 16; + fluid_settings_setint(settings, "synth.midi-channels", synth->midi_channels); + FLUID_LOG(FLUID_WARN, "Requested number of MIDI channels is not a multiple of 16. " + "I'll increase the number of channels to the next multiple."); + } + + if(synth->audio_channels < 1) + { + FLUID_LOG(FLUID_WARN, "Requested number of audio channels is smaller than 1. " + "Changing this setting to 1."); + synth->audio_channels = 1; + } + else if(synth->audio_channels > 128) + { + FLUID_LOG(FLUID_WARN, "Requested number of audio channels is too big (%d). " + "Limiting this setting to 128.", synth->audio_channels); + synth->audio_channels = 128; + } + + if(synth->audio_groups < 1) + { + FLUID_LOG(FLUID_WARN, "Requested number of audio groups is smaller than 1. " + "Changing this setting to 1."); + synth->audio_groups = 1; + } + else if(synth->audio_groups > 128) + { + FLUID_LOG(FLUID_WARN, "Requested number of audio groups is too big (%d). " + "Limiting this setting to 128.", synth->audio_groups); + synth->audio_groups = 128; + } + + if(synth->effects_channels < 2) + { + FLUID_LOG(FLUID_WARN, "Invalid number of effects channels (%d)." + "Setting effects channels to 2.", synth->effects_channels); + synth->effects_channels = 2; + } + + /* + number of buffers rendered by the mixer is determined by synth->audio_groups. + audio from MIDI channel is rendered, mapped and mixed in these buffers. + + Typically synth->audio_channels is only used by audio driver and should be set + to the same value that synth->audio_groups. In some situation using LADSPA, + it is best to diminish audio-channels so that the driver will be able to pass + the audio to audio devices in the case these devices have a limited number of + audio channels. + + audio-channels must not be greater then audio-groups, otherwise these + audio output above audio-groups will not be rendered by the mixeur. + */ + if(synth->audio_channels > synth->audio_groups) + { + synth->audio_channels = synth->audio_groups; + fluid_settings_setint(settings, "synth.audio-channels", synth->audio_channels); + FLUID_LOG(FLUID_WARN, "Requested audio-channels to high. " + "Limiting this setting to audio-groups."); + } + + if(fluid_settings_dupstr(settings, "synth.overflow.important-channels", + &important_channels) == FLUID_OK) + { + if(fluid_synth_set_important_channels(synth, important_channels) != FLUID_OK) + { + FLUID_LOG(FLUID_WARN, "Failed to set overflow important channels"); + } + + FLUID_FREE(important_channels); + } + + /* as soon as the synth is created it starts playing. */ + synth->state = FLUID_SYNTH_PLAYING; + + synth->fromkey_portamento = INVALID_NOTE; /* disable portamento */ + + fluid_atomic_int_set(&synth->ticks_since_start, 0); + synth->tuning = NULL; + fluid_private_init(synth->tuning_iter); + + /* Initialize multi-core variables if multiple cores enabled */ + if(synth->cores > 1) + { + fluid_settings_getint(synth->settings, "audio.realtime-prio", &prio_level); + } + + /* Allocate event queue for rvoice mixer */ + /* In an overflow situation, a new voice takes about 50 spaces in the queue! */ + synth->eventhandler = new_fluid_rvoice_eventhandler(synth->polyphony * 64, + synth->polyphony, synth->audio_groups, + synth->effects_channels, synth->effects_groups, + (fluid_real_t)sample_rate_max, synth->sample_rate, + synth->cores - 1, prio_level); + + if(synth->eventhandler == NULL) + { + goto error_recovery; + } + + /* Setup the list of default modulators. + * Needs to happen after eventhandler has been set up, as fluid_synth_enter_api is called in the process */ + synth->default_mod = NULL; + fluid_synth_add_default_mod(synth, &default_vel2att_mod, FLUID_SYNTH_ADD); + fluid_synth_add_default_mod(synth, &default_vel2filter_mod, FLUID_SYNTH_ADD); + fluid_synth_add_default_mod(synth, &default_at2viblfo_mod, FLUID_SYNTH_ADD); + fluid_synth_add_default_mod(synth, &default_mod2viblfo_mod, FLUID_SYNTH_ADD); + fluid_synth_add_default_mod(synth, &default_att_mod, FLUID_SYNTH_ADD); + fluid_synth_add_default_mod(synth, &default_pan_mod, FLUID_SYNTH_ADD); + fluid_synth_add_default_mod(synth, &default_expr_mod, FLUID_SYNTH_ADD); + fluid_synth_add_default_mod(synth, &default_reverb_mod, FLUID_SYNTH_ADD); + fluid_synth_add_default_mod(synth, &default_chorus_mod, FLUID_SYNTH_ADD); + fluid_synth_add_default_mod(synth, &default_pitch_bend_mod, FLUID_SYNTH_ADD); + fluid_synth_add_default_mod(synth, &custom_balance_mod, FLUID_SYNTH_ADD); + + /* Create and initialize the Fx unit.*/ + fluid_settings_getint(settings, "synth.ladspa.active", &with_ladspa); + + if(with_ladspa) + { +#ifdef LADSPA + synth->ladspa_fx = new_fluid_ladspa_fx(synth->sample_rate, + FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE); + + if(synth->ladspa_fx == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + goto error_recovery; + } + + fluid_rvoice_mixer_set_ladspa(synth->eventhandler->mixer, synth->ladspa_fx, + synth->audio_groups); +#else /* LADSPA */ + FLUID_LOG(FLUID_WARN, "FluidSynth has not been compiled with LADSPA support"); +#endif /* LADSPA */ + } + + /* allocate and add the dls sfont loader */ +#ifdef LIBINSTPATCH_SUPPORT + loader = new_fluid_instpatch_loader(settings); + + if(loader == NULL) + { + FLUID_LOG(FLUID_WARN, "Failed to create the instpatch SoundFont loader"); + } + else + { + fluid_synth_add_sfloader(synth, loader); + } +#endif + + /* allocate and add the default sfont loader */ + loader = new_fluid_defsfloader(settings); + + if(loader == NULL) + { + FLUID_LOG(FLUID_WARN, "Failed to create the default SoundFont loader"); + } + else + { + fluid_synth_add_sfloader(synth, loader); + } + + /* allocate all channel objects */ + synth->channel = FLUID_ARRAY(fluid_channel_t *, synth->midi_channels); + + if(synth->channel == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + goto error_recovery; + } + + FLUID_MEMSET(synth->channel, 0, synth->midi_channels * sizeof(*synth->channel)); + for(i = 0; i < synth->midi_channels; i++) + { + synth->channel[i] = new_fluid_channel(synth, i); + + if(synth->channel[i] == NULL) + { + goto error_recovery; + } + } + + /* allocate all synthesis processes */ + synth->nvoice = synth->polyphony; + synth->voice = FLUID_ARRAY(fluid_voice_t *, synth->nvoice); + + if(synth->voice == NULL) + { + goto error_recovery; + } + + FLUID_MEMSET(synth->voice, 0, synth->nvoice * sizeof(*synth->voice)); + for(i = 0; i < synth->nvoice; i++) + { + synth->voice[i] = new_fluid_voice(synth->eventhandler, synth->sample_rate); + + if(synth->voice[i] == NULL) + { + goto error_recovery; + } + } + + /* sets a default basic channel */ + /* Sets one basic channel: basic channel 0, mode 0 (Omni On - Poly) */ + /* (i.e all channels are polyphonic) */ + /* Must be called after channel objects allocation */ + fluid_synth_set_basic_channel_LOCAL(synth, 0, FLUID_CHANNEL_MODE_OMNION_POLY, + synth->midi_channels); + + synth->min_note_length_ticks = fluid_synth_get_min_note_length_LOCAL(synth); + + + fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_polyphony, + synth->polyphony, 0.0f); + fluid_synth_reverb_on(synth, -1, synth->with_reverb); + fluid_synth_chorus_on(synth, -1, synth->with_chorus); + + synth->cur = FLUID_BUFSIZE; + synth->curmax = 0; + synth->dither_index = 0; + + { + double values[FLUID_REVERB_PARAM_LAST]; + + fluid_settings_getnum(settings, "synth.reverb.room-size", &values[FLUID_REVERB_ROOMSIZE]); + fluid_settings_getnum(settings, "synth.reverb.damp", &values[FLUID_REVERB_DAMP]); + fluid_settings_getnum(settings, "synth.reverb.width", &values[FLUID_REVERB_WIDTH]); + fluid_settings_getnum(settings, "synth.reverb.level", &values[FLUID_REVERB_LEVEL]); + + fluid_synth_set_reverb_full(synth, -1, FLUID_REVMODEL_SET_ALL, values); + } + + { + double values[FLUID_CHORUS_PARAM_LAST]; + + fluid_settings_getint(settings, "synth.chorus.nr", &i); + values[FLUID_CHORUS_NR] = (double)i; + fluid_settings_getnum(settings, "synth.chorus.level", &values[FLUID_CHORUS_LEVEL]); + fluid_settings_getnum(settings, "synth.chorus.speed", &values[FLUID_CHORUS_SPEED]); + fluid_settings_getnum(settings, "synth.chorus.depth", &values[FLUID_CHORUS_DEPTH]); + values[FLUID_CHORUS_TYPE] = (double)FLUID_CHORUS_DEFAULT_TYPE; + + fluid_synth_set_chorus_full(synth, -1, FLUID_CHORUS_SET_ALL, values); + } + + + synth->bank_select = FLUID_BANK_STYLE_GS; + + if(fluid_settings_str_equal(settings, "synth.midi-bank-select", "gm")) + { + synth->bank_select = FLUID_BANK_STYLE_GM; + } + else if(fluid_settings_str_equal(settings, "synth.midi-bank-select", "gs")) + { + synth->bank_select = FLUID_BANK_STYLE_GS; + } + else if(fluid_settings_str_equal(settings, "synth.midi-bank-select", "xg")) + { + synth->bank_select = FLUID_BANK_STYLE_XG; + } + else if(fluid_settings_str_equal(settings, "synth.midi-bank-select", "mma")) + { + synth->bank_select = FLUID_BANK_STYLE_MMA; + } + + fluid_synth_process_event_queue(synth); + + /* FIXME */ + synth->start = fluid_curtime(); + + return synth; + +error_recovery: + delete_fluid_synth(synth); + return NULL; +} + + +/** + * Delete a FluidSynth instance. + * @param synth FluidSynth instance to delete + * + * @note Other users of a synthesizer instance, such as audio and MIDI drivers, + * should be deleted prior to freeing the FluidSynth instance. + */ +void +delete_fluid_synth(fluid_synth_t *synth) +{ + int i, k; + fluid_list_t *list; + fluid_sfont_t *sfont; + fluid_sfloader_t *loader; + + fluid_return_if_fail(synth != NULL); + + fluid_profiling_print(); + + /* unregister all real-time settings callback, to avoid a use-after-free when changing those settings after + * this synth has been deleted*/ + + fluid_settings_callback_num(synth->settings, "synth.gain", + NULL, NULL); + fluid_settings_callback_int(synth->settings, "synth.polyphony", + NULL, NULL); + fluid_settings_callback_int(synth->settings, "synth.device-id", + NULL, NULL); + fluid_settings_callback_num(synth->settings, "synth.overflow.percussion", + NULL, NULL); + fluid_settings_callback_num(synth->settings, "synth.overflow.sustained", + NULL, NULL); + fluid_settings_callback_num(synth->settings, "synth.overflow.released", + NULL, NULL); + fluid_settings_callback_num(synth->settings, "synth.overflow.age", + NULL, NULL); + fluid_settings_callback_num(synth->settings, "synth.overflow.volume", + NULL, NULL); + fluid_settings_callback_num(synth->settings, "synth.overflow.important", + NULL, NULL); + fluid_settings_callback_str(synth->settings, "synth.overflow.important-channels", + NULL, NULL); + fluid_settings_callback_num(synth->settings, "synth.reverb.room-size", + NULL, NULL); + fluid_settings_callback_num(synth->settings, "synth.reverb.damp", + NULL, NULL); + fluid_settings_callback_num(synth->settings, "synth.reverb.width", + NULL, NULL); + fluid_settings_callback_num(synth->settings, "synth.reverb.level", + NULL, NULL); + fluid_settings_callback_int(synth->settings, "synth.reverb.active", + NULL, NULL); + fluid_settings_callback_int(synth->settings, "synth.chorus.active", + NULL, NULL); + fluid_settings_callback_int(synth->settings, "synth.chorus.nr", + NULL, NULL); + fluid_settings_callback_num(synth->settings, "synth.chorus.level", + NULL, NULL); + fluid_settings_callback_num(synth->settings, "synth.chorus.depth", + NULL, NULL); + fluid_settings_callback_num(synth->settings, "synth.chorus.speed", + NULL, NULL); + + /* turn off all voices, needed to unload SoundFont data */ + if(synth->voice != NULL) + { + for(i = 0; i < synth->nvoice; i++) + { + fluid_voice_t *voice = synth->voice[i]; + + if(!voice) + { + continue; + } + + /* WARNING: A this point we must ensure that the reference counter + of any soundfont sample owned by any rvoice belonging to the voice + are correctly decremented. This is the contrary part to + to fluid_voice_init() where the sample's reference counter is + incremented. + */ + fluid_voice_unlock_rvoice(voice); + fluid_voice_overflow_rvoice_finished(voice); + + if(fluid_voice_is_playing(voice)) + { + fluid_voice_off(voice); + /* If we only use fluid_voice_off(voice) it will trigger a delayed + * fluid_voice_stop(voice) via fluid_synth_check_finished_voices(). + * But here, we are deleting the fluid_synth_t instance so + * fluid_voice_stop() will be never triggered resulting in + * SoundFont data never unloaded (i.e a serious memory leak). + * So, fluid_voice_stop() must be explicitly called to insure + * unloading SoundFont data + */ + fluid_voice_stop(voice); + } + } + } + + /* also unset all presets for clean SoundFont unload */ + if(synth->channel != NULL) + { + for(i = 0; i < synth->midi_channels; i++) + { + if(synth->channel[i] != NULL) + { + fluid_channel_set_preset(synth->channel[i], NULL); + } + } + } + + delete_fluid_rvoice_eventhandler(synth->eventhandler); + + /* delete all the SoundFonts */ + for(list = synth->sfont; list; list = fluid_list_next(list)) + { + sfont = fluid_list_get(list); + fluid_sfont_delete_internal(sfont); + } + + delete_fluid_list(synth->sfont); + + /* delete all the SoundFont loaders */ + + for(list = synth->loaders; list; list = fluid_list_next(list)) + { + loader = (fluid_sfloader_t *) fluid_list_get(list); + fluid_sfloader_delete(loader); + } + + delete_fluid_list(synth->loaders); + + /* wait for and delete all the lazy sfont unloading timers */ + + for(list = synth->fonts_to_be_unloaded; list; list = fluid_list_next(list)) + { + fluid_timer_t* timer = fluid_list_get(list); + // explicitly join to wait for the unload really to happen + fluid_timer_join(timer); + // delete_fluid_timer alone would stop the timer, even if it had not unloaded the soundfont yet + delete_fluid_timer(timer); + } + + delete_fluid_list(synth->fonts_to_be_unloaded); + + if(synth->channel != NULL) + { + for(i = 0; i < synth->midi_channels; i++) + { + delete_fluid_channel(synth->channel[i]); + } + + FLUID_FREE(synth->channel); + } + + if(synth->voice != NULL) + { + for(i = 0; i < synth->nvoice; i++) + { + delete_fluid_voice(synth->voice[i]); + } + + FLUID_FREE(synth->voice); + } + + + /* free the tunings, if any */ + if(synth->tuning != NULL) + { + for(i = 0; i < 128; i++) + { + if(synth->tuning[i] != NULL) + { + for(k = 0; k < 128; k++) + { + delete_fluid_tuning(synth->tuning[i][k]); + } + + FLUID_FREE(synth->tuning[i]); + } + } + + FLUID_FREE(synth->tuning); + } + + fluid_private_free(synth->tuning_iter); + +#ifdef LADSPA + /* Release the LADSPA effects unit */ + delete_fluid_ladspa_fx(synth->ladspa_fx); +#endif + + /* delete all default modulators */ + delete_fluid_list_mod(synth->default_mod); + + FLUID_FREE(synth->overflow.important_channels); + + fluid_rec_mutex_destroy(synth->mutex); + + FLUID_FREE(synth); + +#if defined(LIBINSTPATCH_SUPPORT) + if(fluid_instpatch_supports_multi_init()) + { + fluid_instpatch_deinit(); + } +#endif +} + +/** + * Get a textual representation of the last error + * @param synth FluidSynth instance + * @return Pointer to string of last error message. Valid until the same + * calling thread calls another FluidSynth function which fails. String is + * internal and should not be modified or freed. + * @deprecated This function is not thread-safe and does not work with multiple synths. + * It has been deprecated. It may return "" in a future release and will eventually be removed. + */ +const char * +fluid_synth_error(fluid_synth_t *synth) +{ + return ""; +} + +/** + * Send a note-on event to a FluidSynth object. + * + * This function will take care of proper legato playing. If a note on channel @p chan is + * already playing at the given key @p key, it will be released (even if it is sustained). + * In other words, overlapping notes are not allowed. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param key MIDI note number (0-127) + * @param vel MIDI velocity (0-127, 0=noteoff) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_noteon(fluid_synth_t *synth, int chan, int key, int vel) +{ + int result; + fluid_return_val_if_fail(key >= 0 && key <= 127, FLUID_FAILED); + fluid_return_val_if_fail(vel >= 0 && vel <= 127, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + /* Allowed only on MIDI channel enabled */ + FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED); + + result = fluid_synth_noteon_LOCAL(synth, chan, key, vel); + FLUID_API_RETURN(result); +} + +/* Local synthesis thread variant of fluid_synth_noteon */ +static int +fluid_synth_noteon_LOCAL(fluid_synth_t *synth, int chan, int key, int vel) +{ + fluid_channel_t *channel ; + + /* notes with velocity zero go to noteoff */ + if(vel == 0) + { + return fluid_synth_noteoff_LOCAL(synth, chan, key); + } + + channel = synth->channel[chan]; + + /* makes sure this channel has a preset */ + if(channel->preset == NULL) + { + if(synth->verbose) + { + FLUID_LOG(FLUID_INFO, "noteon\t%d\t%d\t%d\t%05d\t%.3f\t%.3f\t%.3f\t%d\t%s", + chan, key, vel, 0, + fluid_synth_get_ticks(synth) / 44100.0f, + (fluid_curtime() - synth->start) / 1000.0f, + 0.0f, 0, "channel has no preset"); + } + + return FLUID_FAILED; + } + + if(fluid_channel_is_playing_mono(channel)) /* channel is mono or legato CC is On) */ + { + /* play the noteOn in monophonic */ + return fluid_synth_noteon_mono_LOCAL(synth, chan, key, vel); + } + else + { + /* channel is poly and legato CC is Off) */ + + /* plays the noteOn in polyphonic */ + /* Sets the note at first position in monophonic list */ + /* In the case where the musician intends to inter the channel in monophonic + (by depressing the CC legato on), the next noteOn mono could be played legato + with the previous note poly (if the musician choose this). + */ + fluid_channel_set_onenote_monolist(channel, (unsigned char) key, + (unsigned char) vel); + + /* If there is another voice process on the same channel and key, + advance it to the release phase. */ + fluid_synth_release_voice_on_same_note_LOCAL(synth, chan, key); + + /* a noteon poly is passed to fluid_synth_noteon_monopoly_legato(). + This allows an opportunity to get this note played legato with a previous + note if a CC PTC have been received before this noteon. This behavior is + a MIDI specification (see FluidPolymono-0004.pdf chapter 4.3-a ,3.4.11 + for details). + */ + return fluid_synth_noteon_monopoly_legato(synth, chan, INVALID_NOTE, key, vel); + } +} + +/** + * Sends a note-off event to a FluidSynth object. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param key MIDI note number (0-127) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise (may just mean that no + * voices matched the note off event) + */ +int +fluid_synth_noteoff(fluid_synth_t *synth, int chan, int key) +{ + int result; + fluid_return_val_if_fail(key >= 0 && key <= 127, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + /* Allowed only on MIDI channel enabled */ + FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED); + + result = fluid_synth_noteoff_LOCAL(synth, chan, key); + FLUID_API_RETURN(result); +} + +/* Local synthesis thread variant of fluid_synth_noteoff */ +static int +fluid_synth_noteoff_LOCAL(fluid_synth_t *synth, int chan, int key) +{ + int status; + fluid_channel_t *channel = synth->channel[chan]; + + if(fluid_channel_is_playing_mono(channel)) /* channel is mono or legato CC is On) */ + { + /* play the noteOff in monophonic */ + status = fluid_synth_noteoff_mono_LOCAL(synth, chan, key); + } + else + { + /* channel is poly and legato CC is Off) */ + /* removes the note from the monophonic list */ + if(channel->n_notes && key == fluid_channel_last_note(channel)) + { + fluid_channel_clear_monolist(channel); + } + + status = fluid_synth_noteoff_monopoly(synth, chan, key, 0); + } + + /* Changes the state (Valid/Invalid) of the most recent note played in a + staccato manner */ + fluid_channel_invalid_prev_note_staccato(channel); + return status; +} + +/* Damps voices on a channel (turn notes off), if they're sustained by + sustain pedal */ +static int +fluid_synth_damp_voices_by_sustain_LOCAL(fluid_synth_t *synth, int chan) +{ + fluid_channel_t *channel = synth->channel[chan]; + fluid_voice_t *voice; + int i; + + for(i = 0; i < synth->polyphony; i++) + { + voice = synth->voice[i]; + + if((fluid_voice_get_channel(voice) == chan) && fluid_voice_is_sustained(voice)) + { + if(voice->key == channel->key_mono_sustained) + { + /* key_mono_sustained is a possible mono note sustainted + (by sustain or sostenuto pedal). It must be marked released + (INVALID_NOTE) here because it is released only by sustain pedal */ + channel->key_mono_sustained = INVALID_NOTE; + } + + fluid_voice_release(voice); + } + } + + return FLUID_OK; +} + +/* Damps voices on a channel (turn notes off), if they're sustained by + sostenuto pedal */ +static int +fluid_synth_damp_voices_by_sostenuto_LOCAL(fluid_synth_t *synth, int chan) +{ + fluid_channel_t *channel = synth->channel[chan]; + fluid_voice_t *voice; + int i; + + for(i = 0; i < synth->polyphony; i++) + { + voice = synth->voice[i]; + + if((fluid_voice_get_channel(voice) == chan) && fluid_voice_is_sostenuto(voice)) + { + if(voice->key == channel->key_mono_sustained) + { + /* key_mono_sustained is a possible mono note sustainted + (by sustain or sostenuto pedal). It must be marked released + (INVALID_NOTE) here because it is released only by sostenuto pedal */ + channel->key_mono_sustained = INVALID_NOTE; + } + + fluid_voice_release(voice); + } + } + + return FLUID_OK; +} + +/** + * Adds the specified modulator \c mod as default modulator to the synth. \c mod will + * take effect for any subsequently created voice. + * @param synth FluidSynth instance + * @param mod Modulator info (values copied, passed in object can be freed immediately afterwards) + * @param mode Determines how to handle an existing identical modulator (#fluid_synth_add_mod) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * + * @note Not realtime safe (due to internal memory allocation) and therefore should not be called + * from synthesis context at the risk of stalling audio output. + */ +int +fluid_synth_add_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod, int mode) +{ + fluid_mod_t *default_mod; + fluid_mod_t *last_mod = NULL; + fluid_mod_t *new_mod; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail(mod != NULL, FLUID_FAILED); + fluid_return_val_if_fail((mode == FLUID_SYNTH_ADD) || (mode == FLUID_SYNTH_OVERWRITE) , FLUID_FAILED); + + /* Checks if modulators sources are valid */ + if(!fluid_mod_check_sources(mod, "api fluid_synth_add_default_mod mod")) + { + return FLUID_FAILED; + } + + fluid_synth_api_enter(synth); + + default_mod = synth->default_mod; + + while(default_mod != NULL) + { + if(fluid_mod_test_identity(default_mod, mod)) + { + if(mode == FLUID_SYNTH_ADD) + { + default_mod->amount += mod->amount; + } + else // mode == FLUID_SYNTH_OVERWRITE + { + default_mod->amount = mod->amount; + } + + FLUID_API_RETURN(FLUID_OK); + } + + last_mod = default_mod; + default_mod = default_mod->next; + } + + /* Add a new modulator (no existing modulator to add / overwrite). */ + new_mod = new_fluid_mod(); + + if(new_mod == NULL) + { + FLUID_API_RETURN(FLUID_FAILED); + } + + fluid_mod_clone(new_mod, mod); + new_mod->next = NULL; + + if(last_mod == NULL) + { + synth->default_mod = new_mod; + } + else + { + last_mod->next = new_mod; + } + + FLUID_API_RETURN(FLUID_OK); +} + +/** + * Removes the specified modulator \c mod from the synth's default modulator list. + * fluid_mod_test_identity() will be used to test modulator matching. + * @param synth synth instance + * @param mod The modulator to remove + * @return #FLUID_OK if a matching modulator was found and successfully removed, #FLUID_FAILED otherwise + * + * @note Not realtime safe (due to internal memory freeing) and therefore should not be called + * from synthesis context at the risk of stalling audio output. + */ +int +fluid_synth_remove_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod) +{ + fluid_mod_t *default_mod; + fluid_mod_t *last_mod; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail(mod != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + + last_mod = default_mod = synth->default_mod; + + while(default_mod != NULL) + { + if(fluid_mod_test_identity(default_mod, mod)) + { + if(synth->default_mod == default_mod) + { + synth->default_mod = default_mod->next; + } + else + { + last_mod->next = default_mod->next; + } + + delete_fluid_mod(default_mod); + FLUID_API_RETURN(FLUID_OK); + } + + last_mod = default_mod; + default_mod = default_mod->next; + } + + FLUID_API_RETURN(FLUID_FAILED); +} + + +/** + * Send a MIDI controller event on a MIDI channel. + * + * Most CCs are 7-bits wide in FluidSynth. There are a few exceptions which may be 14-bits wide as are documented here: + * https://github.com/FluidSynth/fluidsynth/wiki/FluidFeatures#midi-control-change-implementation-chart + * + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param num MIDI controller number (0-127) + * @param val MIDI controller value (0-127) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @note This function supports MIDI Global Controllers which will be sent to + * all channels of the basic channel if this basic channel is in mode OmniOff/Mono. + * This is accomplished by sending the CC one MIDI channel below the basic + * channel of the receiver. + * Examples: let a synthesizer with 16 MIDI channels: + * - Let a basic channel 7 in mode 3 (Omni Off, Mono). If MIDI channel 6 is disabled it + * could be used as CC global for all channels belonging to basic channel 7. + * - Let a basic channel 0 in mode 3. If MIDI channel 15 is disabled it could be used + * as CC global for all channels belonging to basic channel 0. + * @warning Contrary to the MIDI Standard, this function does not clear LSB controllers, + * when MSB controllers are received. + */ +int +fluid_synth_cc(fluid_synth_t *synth, int chan, int num, int val) +{ + int result = FLUID_FAILED; + fluid_channel_t *channel; + fluid_return_val_if_fail(num >= 0 && num <= 127, FLUID_FAILED); + fluid_return_val_if_fail(val >= 0 && val <= 127, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + channel = synth->channel[chan]; + + if(channel->mode & FLUID_CHANNEL_ENABLED) + { + /* chan is enabled */ + if(synth->verbose) + { + FLUID_LOG(FLUID_INFO, "cc\t%d\t%d\t%d", chan, num, val); + } + + fluid_channel_set_cc(channel, num, val); + result = fluid_synth_cc_LOCAL(synth, chan, num); + } + else /* chan is disabled so it is a candidate for global channel */ + { + /* looks for next basic channel */ + int n_chan = synth->midi_channels; /* MIDI Channels number */ + int basicchan ; + + if(chan < n_chan - 1) + { + basicchan = chan + 1; /* next channel */ + } + else + { + basicchan = 0; /* wrap to 0 */ + } + + channel = synth->channel[basicchan]; + + /* Channel must be a basicchan in mode OMNIOFF_MONO */ + if((channel->mode & FLUID_CHANNEL_BASIC) && + ((channel->mode & FLUID_CHANNEL_MODE_MASK) == FLUID_CHANNEL_MODE_OMNIOFF_MONO)) + { + /* sends cc to all channels in this basic channel */ + int i, nbr = channel->mode_val; + + for(i = basicchan; i < basicchan + nbr; i++) + { + if(synth->verbose) + { + FLUID_LOG(FLUID_INFO, "cc\t%d\t%d\t%d", i, num, val); + } + + fluid_channel_set_cc(synth->channel[i], num, val); + result = fluid_synth_cc_LOCAL(synth, i, num); + } + } + /* The channel chan is not a valid 'global channel' */ + else + { + result = FLUID_FAILED; + } + } + + FLUID_API_RETURN(result); +} + +/* Local synthesis thread variant of MIDI CC set function. + Most of CC are allowed to modulate but not all. A comment describes if CC num + isn't allowed to modulate. + Following explanations should help to understand both MIDI specifications and + Soundfont specifications in regard to MIDI specs. + + MIDI specs: + CC LSB (32 to 63) are LSB contributions to CC MSB (0 to 31). + It's up to the synthesizer to decide to take LSB values into account or not. + Actually Fluidsynth doesn't use CC LSB value inside fluid_voice_update_param() + (once fluid_voice_modulate() has been triggered). This is because actually + fluidsynth needs only 7 bits resolution (and not 14 bits) from these CCs. + So fluidsynth is using only 7 bit MSB (except for portamento time). + In regard to MIDI specs Fluidsynth behaves correctly. + + Soundfont specs 2.01 - 8.2.1: + To deal correctly with MIDI CC (regardless if any synth will use CC MSB alone (7 bit) + or both CCs MSB,LSB (14 bits) during synthesis), SF specs recommend not making use of + CC LSB (i.e only CC MSB) in modulator sources to trigger modulation (i.e modulators + with CC LSB connected to sources inputs should be ignored). + These specifics are particularly suited for synths that use 14 bits CCs. In this case, + the MIDI transmitter sends CC LSB first followed by CC MSB. The MIDI synth receives + both CC LSB and CC MSB but only CC MSB will trigger the modulation. + This will produce correct synthesis parameters update from a correct 14 bits CC. + If in SF specs, modulator sources with CC LSB had been accepted, both CC LSB and + CC MSB will triggers 2 modulations. This leads to incorrect synthesis parameters + update followed by correct synthesis parameters update. + + However, as long as fluidsynth will use only CC 7 bits resolution, it is safe to ignore + these SF recommendations on CC receive. +*/ +static int +fluid_synth_cc_LOCAL(fluid_synth_t *synth, int channum, int num) +{ + fluid_channel_t *chan = synth->channel[channum]; + int nrpn_select; + int value; + + value = fluid_channel_get_cc(chan, num); + + switch(num) + { + case LOCAL_CONTROL: /* not allowed to modulate (spec SF 2.01 - 8.2.1) */ + break; + + /* CC omnioff, omnion, mono, poly */ + /* not allowed to modulate (spec SF 2.01 - 8.2.1) */ + case POLY_OFF: + case POLY_ON: + case OMNI_OFF: + case OMNI_ON: + + /* allowed only if channum is a basic channel */ + if(chan->mode & FLUID_CHANNEL_BASIC) + { + /* Construction of new_mode from current channel mode and this CC mode */ + int new_mode = chan->mode & FLUID_CHANNEL_MODE_MASK; + + switch(num) + { + case POLY_OFF: + new_mode |= FLUID_CHANNEL_POLY_OFF; + break; + + case POLY_ON: + new_mode &= ~FLUID_CHANNEL_POLY_OFF; + break; + + case OMNI_OFF: + new_mode |= FLUID_CHANNEL_OMNI_OFF; + break; + + case OMNI_ON: + new_mode &= ~FLUID_CHANNEL_OMNI_OFF; + break; + + default: /* should never happen */ + return FLUID_FAILED; + } + + /* MIDI specs: if value is 0 it means all channels from channum to next + basic channel minus 1 (if any) or to MIDI channel count minus 1. + However, if value is > 0 (e.g. 4), the group of channels will be be + limited to 4. + value is ignored for #FLUID_CHANNEL_MODE_OMNIOFF_POLY as this mode + implies a group of only one channel. + */ + /* Checks value range and changes this existing basic channel group */ + value = fluid_synth_check_next_basic_channel(synth, channum, new_mode, value); + + if(value != FLUID_FAILED) + { + /* reset the current basic channel before changing it */ + fluid_synth_reset_basic_channel_LOCAL(synth, channum, chan->mode_val); + fluid_synth_set_basic_channel_LOCAL(synth, channum, new_mode, value); + break; /* FLUID_OK */ + } + } + + return FLUID_FAILED; + + case LEGATO_SWITCH: /* not allowed to modulate */ + /* handles Poly/mono commutation on Legato pedal On/Off.*/ + fluid_channel_cc_legato(chan, value); + break; + + case PORTAMENTO_SWITCH: /* not allowed to modulate */ + /* Special handling of the monophonic list */ + /* Invalids the most recent note played in a staccato manner */ + fluid_channel_invalid_prev_note_staccato(chan); + break; + + case SUSTAIN_SWITCH: /* not allowed to modulate */ + + /* Release voices if Sustain switch is released */ + if(value < 64) /* Sustain is released */ + { + fluid_synth_damp_voices_by_sustain_LOCAL(synth, channum); + } + + break; + + case SOSTENUTO_SWITCH: /* not allowed to modulate */ + + /* Release voices if Sostetuno switch is released */ + if(value < 64) /* Sostenuto is released */ + { + fluid_synth_damp_voices_by_sostenuto_LOCAL(synth, channum); + } + else /* Sostenuto is depressed */ + /* Update sostenuto order id when pedaling on Sostenuto */ + { + chan->sostenuto_orderid = synth->noteid; /* future voice id value */ + } + + break; + + case BANK_SELECT_MSB: /* not allowed to modulate (spec SF 2.01 - 8.2.1) */ + fluid_channel_set_bank_msb(chan, value & 0x7F); + break; + + case BANK_SELECT_LSB: /* not allowed to modulate (spec SF 2.01 - 8.2.1) */ + fluid_channel_set_bank_lsb(chan, value & 0x7F); + break; + + case ALL_NOTES_OFF: /* not allowed to modulate (spec SF 2.01 - 8.2.1) */ + fluid_synth_all_notes_off_LOCAL(synth, channum); + break; + + case ALL_SOUND_OFF: /* not allowed to modulate (spec SF 2.01 - 8.2.1) */ + fluid_synth_all_sounds_off_LOCAL(synth, channum); + break; + + case ALL_CTRL_OFF: /* not allowed to modulate (spec SF 2.01 - 8.2.1) */ + fluid_channel_init_ctrl(chan, 1); + // the hold pedals have been reset, we maybe need to release voices + fluid_synth_damp_voices_by_sustain_LOCAL(synth, channum); + fluid_synth_damp_voices_by_sostenuto_LOCAL(synth, channum); + fluid_synth_modulate_voices_all_LOCAL(synth, channum); + break; + + case DATA_ENTRY_LSB: /* not allowed to modulate (spec SF 2.01 - 8.2.1) */ + break; + + case DATA_ENTRY_MSB: /* not allowed to modulate (spec SF 2.01 - 8.2.1) */ + { + int data = (value << 7) + fluid_channel_get_cc(chan, DATA_ENTRY_LSB); + + if(chan->nrpn_active) /* NRPN is active? */ + { + /* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */ + if((fluid_channel_get_cc(chan, NRPN_MSB) == 120) + && (fluid_channel_get_cc(chan, NRPN_LSB) < 100)) + { + nrpn_select = chan->nrpn_select; + + if(nrpn_select < GEN_LAST) + { + float val = fluid_gen_scale_nrpn(nrpn_select, data); + fluid_synth_set_gen_LOCAL(synth, channum, nrpn_select, val); + } + + chan->nrpn_select = 0; /* Reset to 0 */ + } + } + else if(fluid_channel_get_cc(chan, RPN_MSB) == 0) /* RPN is active: MSB = 0? */ + { + switch(fluid_channel_get_cc(chan, RPN_LSB)) + { + case RPN_PITCH_BEND_RANGE: /* Set bend range in semitones */ + fluid_channel_set_pitch_wheel_sensitivity(synth->channel[channum], value); + fluid_synth_update_pitch_wheel_sens_LOCAL(synth, channum); /* Update bend range */ + /* FIXME - Handle LSB? (Fine bend range in cents) */ + break; + + case RPN_CHANNEL_FINE_TUNE: /* Fine tune is 14 bit over +/-1 semitone (+/- 100 cents, 8192 = center) */ + fluid_synth_set_gen_LOCAL(synth, channum, GEN_FINETUNE, + (float)(data - 8192) * (100.0f / 8192.0f)); + break; + + case RPN_CHANNEL_COARSE_TUNE: /* Coarse tune is 7 bit and in semitones (64 is center) */ + fluid_synth_set_gen_LOCAL(synth, channum, GEN_COARSETUNE, + value - 64); + break; + + case RPN_TUNING_PROGRAM_CHANGE: + fluid_channel_set_tuning_prog(chan, value); + fluid_synth_activate_tuning(synth, channum, + fluid_channel_get_tuning_bank(chan), + value, TRUE); + break; + + case RPN_TUNING_BANK_SELECT: + fluid_channel_set_tuning_bank(chan, value); + break; + + case RPN_MODULATION_DEPTH_RANGE: + break; + } + } + + break; + } + + case NRPN_MSB: /* not allowed to modulate (spec SF 2.01 - 8.2.1) */ + fluid_channel_set_cc(chan, NRPN_LSB, 0); + chan->nrpn_select = 0; + chan->nrpn_active = 1; + break; + + case NRPN_LSB: /* not allowed to modulate (spec SF 2.01 - 8.2.1) */ + + /* SontFont 2.01 NRPN Message (Sect. 9.6, p. 74) */ + if(fluid_channel_get_cc(chan, NRPN_MSB) == 120) + { + if(value == 100) + { + chan->nrpn_select += 100; + } + else if(value == 101) + { + chan->nrpn_select += 1000; + } + else if(value == 102) + { + chan->nrpn_select += 10000; + } + else if(value < 100) + { + chan->nrpn_select += value; + } + } + + chan->nrpn_active = 1; + break; + + case RPN_MSB: /* not allowed to modulate (spec SF 2.01 - 8.2.1) */ + case RPN_LSB: /* not allowed to modulate (spec SF 2.01 - 8.2.1) */ + chan->nrpn_active = 0; + break; + + case BREATH_MSB: + /* handles CC Breath On/Off noteOn/noteOff mode */ + fluid_channel_cc_breath_note_on_off(chan, value); + + /* fall-through */ + default: + /* CC lsb shouldn't allowed to modulate (spec SF 2.01 - 8.2.1) */ + /* However, as long fluidsynth will use only CC 7 bits resolution, it + is safe to ignore these SF recommendations on CC receive. See + explanations above */ + /* if (! (32 <= num && num <= 63)) */ + { + return fluid_synth_modulate_voices_LOCAL(synth, channum, 1, num); + } + } + + return FLUID_OK; +} + +/** + * Get current MIDI controller value on a MIDI channel. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param num MIDI controller number (0-127) + * @param pval Location to store MIDI controller value (0-127) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_get_cc(fluid_synth_t *synth, int chan, int num, int *pval) +{ + fluid_return_val_if_fail(num >= 0 && num < 128, FLUID_FAILED); + fluid_return_val_if_fail(pval != NULL, FLUID_FAILED); + + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + /* Allowed only on MIDI channel enabled */ + FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED); + + *pval = fluid_channel_get_cc(synth->channel[chan], num); + FLUID_API_RETURN(FLUID_OK); +} + +/* + * Handler for synth.device-id setting. + */ +static void +fluid_synth_handle_device_id(void *data, const char *name, int value) +{ + fluid_synth_t *synth = (fluid_synth_t *)data; + fluid_return_if_fail(synth != NULL); + + fluid_synth_api_enter(synth); + synth->device_id = value; + fluid_synth_api_exit(synth); +} + +/** + * Process a MIDI SYSEX (system exclusive) message. + * @param synth FluidSynth instance + * @param data Buffer containing SYSEX data (not including 0xF0 and 0xF7) + * @param len Length of data in buffer + * @param response Buffer to store response to or NULL to ignore + * @param response_len IN/OUT parameter, in: size of response buffer, out: + * amount of data written to response buffer (if #FLUID_FAILED is returned and + * this value is non-zero, it indicates the response buffer is too small) + * @param handled Optional location to store boolean value if message was + * recognized and handled or not (set to TRUE if it was handled) + * @param dryrun TRUE to just do a dry run but not actually execute the SYSEX + * command (useful for checking if a SYSEX message would be handled) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @since 1.1.0 + * @note When Fluidsynth receives an XG System Mode ON message, it compares the @p synth 's deviceID + * directly with the deviceID of the SysEx message. This is contrary to the XG spec (page 42), which + * requires to only compare the lower nibble. However, following the XG spec seems to break drum channels + * for a lot of MIDI files out there and therefore we've decided for this customization. If you rely on + * XG System Mode ON messages, make sure to set the setting \ref settings_synth_device-id to match the + * deviceID provided in the SysEx message (in most cases, this will be deviceID=16). + * + * @code + * SYSEX format (0xF0 and 0xF7 bytes shall not be passed to this function): + * Non-realtime: 0xF0 0x7E [BODY] 0xF7 + * Realtime: 0xF0 0x7F [BODY] 0xF7 + * Tuning messages: 0xF0 0x7E/0x7F 0x08 [BODY] 0xF7 + * GS DT1 messages: 0xF0 0x41 0x42 0x12 [ADDRESS (3 bytes)] [DATA] 0xF7 + * @endcode + */ +int +fluid_synth_sysex(fluid_synth_t *synth, const char *data, int len, + char *response, int *response_len, int *handled, int dryrun) +{ + int avail_response = 0; + + if(handled) + { + *handled = FALSE; + } + + if(response_len) + { + avail_response = *response_len; + *response_len = 0; + } + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail(data != NULL, FLUID_FAILED); + fluid_return_val_if_fail(len > 0, FLUID_FAILED); + fluid_return_val_if_fail(!response || response_len, FLUID_FAILED); + + if(len < 4) + { + return FLUID_OK; + } + + /* MIDI tuning SYSEX message? */ + if((data[0] == MIDI_SYSEX_UNIV_NON_REALTIME || data[0] == MIDI_SYSEX_UNIV_REALTIME) + && (data[1] == synth->device_id || data[1] == MIDI_SYSEX_DEVICE_ID_ALL || synth->device_id == MIDI_SYSEX_DEVICE_ID_ALL) + && data[2] == MIDI_SYSEX_MIDI_TUNING_ID) + { + int result; + fluid_synth_api_enter(synth); + result = fluid_synth_sysex_midi_tuning(synth, data, len, response, + response_len, avail_response, + handled, dryrun); + + FLUID_API_RETURN(result); + } + + /* GM or GM2 system on */ + if(data[0] == MIDI_SYSEX_UNIV_NON_REALTIME + && (data[1] == synth->device_id || data[1] == MIDI_SYSEX_DEVICE_ID_ALL || synth->device_id == MIDI_SYSEX_DEVICE_ID_ALL) + && data[2] == MIDI_SYSEX_GM_ID) + { + if(handled) + { + *handled = TRUE; + } + if(!dryrun && (data[3] == MIDI_SYSEX_GM_ON + || data[3] == MIDI_SYSEX_GM2_ON)) + { + int result; + synth->bank_select = FLUID_BANK_STYLE_GM; + fluid_synth_api_enter(synth); + result = fluid_synth_system_reset_LOCAL(synth); + FLUID_API_RETURN(result); + } + return FLUID_OK; + } + + /* GS DT1 message */ + if(data[0] == MIDI_SYSEX_MANUF_ROLAND + && (data[1] == synth->device_id || data[1] == MIDI_SYSEX_DEVICE_ID_ALL || synth->device_id == MIDI_SYSEX_DEVICE_ID_ALL) + && data[2] == MIDI_SYSEX_GS_ID + && data[3] == MIDI_SYSEX_GS_DT1) + { + int result; + fluid_synth_api_enter(synth); + result = fluid_synth_sysex_gs_dt1(synth, data, len, response, + response_len, avail_response, + handled, dryrun); + FLUID_API_RETURN(result); + } + + /* XG message */ + if(data[0] == MIDI_SYSEX_MANUF_YAMAHA + && (data[1] == synth->device_id || data[1] == MIDI_SYSEX_DEVICE_ID_ALL || synth->device_id == MIDI_SYSEX_DEVICE_ID_ALL) + && data[2] == MIDI_SYSEX_XG_ID) + { + int result; + fluid_synth_api_enter(synth); + result = fluid_synth_sysex_xg(synth, data, len, response, + response_len, avail_response, + handled, dryrun); + FLUID_API_RETURN(result); + } + + return FLUID_OK; +} + +/* Handler for MIDI tuning SYSEX messages */ +static int +fluid_synth_sysex_midi_tuning(fluid_synth_t *synth, const char *data, int len, + char *response, int *response_len, int avail_response, + int *handled, int dryrun) +{ + int realtime, msgid; + int bank = 0, prog, channels; + double tunedata[128]; + int keys[128]; + char name[17]={0}; + int note, frac, frac2; + uint8_t chksum; + int i, count, index; + const char *dataptr; + char *resptr; + + realtime = data[0] == MIDI_SYSEX_UNIV_REALTIME; + msgid = data[3]; + + switch(msgid) + { + case MIDI_SYSEX_TUNING_BULK_DUMP_REQ: + case MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK: + if(data[3] == MIDI_SYSEX_TUNING_BULK_DUMP_REQ) + { + if(len != 5 || data[4] & 0x80 || !response) + { + return FLUID_OK; + } + + *response_len = 406; + prog = data[4]; + } + else + { + if(len != 6 || data[4] & 0x80 || data[5] & 0x80 || !response) + { + return FLUID_OK; + } + + *response_len = 407; + bank = data[4]; + prog = data[5]; + } + + if(dryrun) + { + if(handled) + { + *handled = TRUE; + } + + return FLUID_OK; + } + + if(avail_response < *response_len) + { + return FLUID_FAILED; + } + + /* Get tuning data, return if tuning not found */ + if(fluid_synth_tuning_dump(synth, bank, prog, name, 17, tunedata) == FLUID_FAILED) + { + *response_len = 0; + return FLUID_OK; + } + + resptr = response; + + *resptr++ = MIDI_SYSEX_UNIV_NON_REALTIME; + *resptr++ = synth->device_id; + *resptr++ = MIDI_SYSEX_MIDI_TUNING_ID; + *resptr++ = MIDI_SYSEX_TUNING_BULK_DUMP; + + if(msgid == MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK) + { + *resptr++ = bank; + } + + *resptr++ = prog; + /* copy 16 ASCII characters (potentially not null terminated) to the sysex buffer */ + FLUID_MEMCPY(resptr, name, 16); + resptr += 16; + + for(i = 0; i < 128; i++) + { + note = tunedata[i] / 100.0; + fluid_clip(note, 0, 127); + + frac = ((tunedata[i] - note * 100.0) * 16384.0 + 50.0) / 100.0; + fluid_clip(frac, 0, 16383); + + *resptr++ = note; + *resptr++ = frac >> 7; + *resptr++ = frac & 0x7F; + } + + if(msgid == MIDI_SYSEX_TUNING_BULK_DUMP_REQ) + { + /* NOTE: Checksum is not as straight forward as the bank based messages */ + chksum = MIDI_SYSEX_UNIV_NON_REALTIME ^ MIDI_SYSEX_MIDI_TUNING_ID + ^ MIDI_SYSEX_TUNING_BULK_DUMP ^ prog; + + for(i = 21; i < 128 * 3 + 21; i++) + { + chksum ^= response[i]; + } + } + else + { + for(i = 1, chksum = 0; i < 406; i++) + { + chksum ^= response[i]; + } + } + + *resptr++ = chksum & 0x7F; + + if(handled) + { + *handled = TRUE; + } + + break; + + case MIDI_SYSEX_TUNING_NOTE_TUNE: + case MIDI_SYSEX_TUNING_NOTE_TUNE_BANK: + dataptr = data + 4; + + if(msgid == MIDI_SYSEX_TUNING_NOTE_TUNE) + { + if(len < 10 || data[4] & 0x80 || data[5] & 0x80 || len != data[5] * 4 + 6) + { + return FLUID_OK; + } + } + else + { + if(len < 11 || data[4] & 0x80 || data[5] & 0x80 || data[6] & 0x80 + || len != data[6] * 4 + 7) + { + return FLUID_OK; + } + + bank = *dataptr++; + } + + if(dryrun) + { + if(handled) + { + *handled = TRUE; + } + + return FLUID_OK; + } + + prog = *dataptr++; + count = *dataptr++; + + for(i = 0, index = 0; i < count; i++) + { + note = *dataptr++; + + if(note & 0x80) + { + return FLUID_OK; + } + + keys[index] = note; + + note = *dataptr++; + frac = *dataptr++; + frac2 = *dataptr++; + + if(note & 0x80 || frac & 0x80 || frac2 & 0x80) + { + return FLUID_OK; + } + + frac = frac << 7 | frac2; + + /* No change pitch value? Doesn't really make sense to send that, but.. */ + if(note == 0x7F && frac == 16383) + { + continue; + } + + tunedata[index] = note * 100.0 + (frac * 100.0 / 16384.0); + index++; + } + + if(index > 0) + { + if(fluid_synth_tune_notes(synth, bank, prog, index, keys, tunedata, + realtime) == FLUID_FAILED) + { + return FLUID_FAILED; + } + } + + if(handled) + { + *handled = TRUE; + } + + break; + + case MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE: + case MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE: + if((msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE && len != 19) + || (msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE && len != 31)) + { + return FLUID_OK; + } + + if(data[4] & 0x80 || data[5] & 0x80 || data[6] & 0x80) + { + return FLUID_OK; + } + + if(dryrun) + { + if(handled) + { + *handled = TRUE; + } + + return FLUID_OK; + } + + channels = (data[4] & 0x03) << 14 | data[5] << 7 | data[6]; + + if(msgid == MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE) + { + for(i = 0; i < 12; i++) + { + frac = data[i + 7]; + + if(frac & 0x80) + { + return FLUID_OK; + } + + tunedata[i] = (int)frac - 64; + } + } + else + { + for(i = 0; i < 12; i++) + { + frac = data[i * 2 + 7]; + frac2 = data[i * 2 + 8]; + + if(frac & 0x80 || frac2 & 0x80) + { + return FLUID_OK; + } + + tunedata[i] = (((int)frac << 7 | (int)frac2) - 8192) * (200.0 / 16384.0); + } + } + + if(fluid_synth_activate_octave_tuning(synth, 0, 0, "SYSEX", + tunedata, realtime) == FLUID_FAILED) + { + return FLUID_FAILED; + } + + if(channels) + { + for(i = 0; i < 16; i++) + { + if(channels & (1 << i)) + { + fluid_synth_activate_tuning(synth, i, 0, 0, realtime); + } + } + } + + if(handled) + { + *handled = TRUE; + } + + break; + } + + return FLUID_OK; +} + +/* Handler for GS DT1 messages */ +static int +fluid_synth_sysex_gs_dt1(fluid_synth_t *synth, const char *data, int len, + char *response, int *response_len, int avail_response, + int *handled, int dryrun) +{ + int addr; + int len_data; + int checksum = 0, i; + + if(len < 9) // at least one byte of data should be transmitted + { + FLUID_LOG(FLUID_INFO, "SysEx DT1: message too short, dropping it."); + return FLUID_FAILED; + } + len_data = len - 8; + addr = (data[4] << 16) | (data[5] << 8) | data[6]; + + for (i = 4; i < len - 1; ++i) + { + checksum += data[i]; + } + checksum = 0x80 - (checksum & 0x7F); + if (checksum != data[len - 1]) + { + FLUID_LOG(FLUID_INFO, "SysEx DT1: dropping message on addr 0x%x due to incorrect checksum 0x%x. Correct checksum: 0x%x", addr, (int)data[len - 1], checksum); + return FLUID_FAILED; + } + + if (addr == 0x40007F) // Mode set + { + if (len_data > 1 || (data[7] != 0 && data[7] != 0x7f)) + { + FLUID_LOG(FLUID_INFO, "SysEx DT1: dropping invalid mode set message"); + return FLUID_FAILED; + } + if (handled) + { + *handled = TRUE; + } + if (!dryrun) + { + if (data[7] == 0) + { + synth->bank_select = FLUID_BANK_STYLE_GS; + } + else + { + synth->bank_select = FLUID_BANK_STYLE_GM; + } + return fluid_synth_system_reset_LOCAL(synth); + } + return FLUID_OK; + } + + if (synth->bank_select != FLUID_BANK_STYLE_GS) + { + return FLUID_OK; // Silently ignore all other messages + } + + if ((addr & 0xFFF0FF) == 0x401015) // Use for rhythm part + { + if (len_data > 1 || data[7] > 0x02) + { + FLUID_LOG(FLUID_INFO, "SysEx DT1: dropping invalid rhythm part message"); + return FLUID_FAILED; + } + if (handled) + { + *handled = TRUE; + } + if (!dryrun) + { + int chan = (addr >> 8) & 0x0F; + //See the Patch Part parameters section in SC-88Pro/8850 owner's manual + chan = chan >= 0x0a ? chan : (chan == 0 ? 9 : chan - 1); + synth->channel[chan]->channel_type = + data[7] == 0x00 ? CHANNEL_TYPE_MELODIC : CHANNEL_TYPE_DRUM; + + FLUID_LOG(FLUID_DBG, "SysEx DT1: setting MIDI channel %d to type %d", chan, (int)synth->channel[chan]->channel_type); + //Roland synths seem to "remember" the last instrument a channel + //used in the selected mode. This behavior is not replicated here. + fluid_synth_program_change(synth, chan, 0); + } + return FLUID_OK; + } + + //silently ignore + return FLUID_OK; +} + +/* Handler for XG messages */ +static int +fluid_synth_sysex_xg(fluid_synth_t *synth, const char *data, int len, + char *response, int *response_len, int avail_response, + int *handled, int dryrun) +{ + int addr; + int len_data; + + if(len < 7) // at least one byte of data should be transmitted + { + return FLUID_FAILED; + } + len_data = len - 6; + addr = (data[3] << 16) | (data[4] << 8) | data[5]; + + if (addr == 0x00007E // Reset + || addr == 0x00007F) // Reset to factory + { + if (len_data > 1 || data[6] != 0) + { + return FLUID_FAILED; + } + if (handled) + { + *handled = TRUE; + } + if (!dryrun) + { + synth->bank_select = FLUID_BANK_STYLE_XG; + return fluid_synth_system_reset_LOCAL(synth); + } + return FLUID_OK; + } + + /* No other messages handled yet + if (synth->bank_select != FLUID_BANK_STYLE_XG) + { + return FLUID_OK; // Silently ignore all other messages + }*/ + + //silently ignore + return FLUID_OK; +} + +/** + * Turn off all voices that are playing on the given MIDI channel, by putting them into release phase. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1), (chan=-1 selects all channels) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @since 1.1.4 + */ +int +fluid_synth_all_notes_off(fluid_synth_t *synth, int chan) +{ + int result; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail(chan >= -1, FLUID_FAILED); + fluid_synth_api_enter(synth); + + if(chan >= synth->midi_channels) + { + result = FLUID_FAILED; + } + else + { + /* Allowed (even for channel disabled) as chan = -1 selects all channels */ + result = fluid_synth_all_notes_off_LOCAL(synth, chan); + } + + FLUID_API_RETURN(result); +} + +/* Local synthesis thread variant of all notes off, (chan=-1 selects all channels) */ +//static int +int +fluid_synth_all_notes_off_LOCAL(fluid_synth_t *synth, int chan) +{ + fluid_voice_t *voice; + int i; + + for(i = 0; i < synth->polyphony; i++) + { + voice = synth->voice[i]; + + if(fluid_voice_is_playing(voice) && ((-1 == chan) || (chan == fluid_voice_get_channel(voice)))) + { + fluid_voice_noteoff(voice); + } + } + + return FLUID_OK; +} + +/** + * Immediately stop all voices on the given MIDI channel (skips release phase). + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1), (chan=-1 selects all channels) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @since 1.1.4 + */ +int +fluid_synth_all_sounds_off(fluid_synth_t *synth, int chan) +{ + int result; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail(chan >= -1, FLUID_FAILED); + fluid_synth_api_enter(synth); + + if(chan >= synth->midi_channels) + { + result = FLUID_FAILED; + } + else + { + /* Allowed (even for channel disabled) as chan = -1 selects all channels */ + result = fluid_synth_all_sounds_off_LOCAL(synth, chan); + } + + FLUID_API_RETURN(result); +} + +/* Local synthesis thread variant of all sounds off, (chan=-1 selects all channels) */ +static int +fluid_synth_all_sounds_off_LOCAL(fluid_synth_t *synth, int chan) +{ + fluid_voice_t *voice; + int i; + + for(i = 0; i < synth->polyphony; i++) + { + voice = synth->voice[i]; + + if(fluid_voice_is_playing(voice) && ((-1 == chan) || (chan == fluid_voice_get_channel(voice)))) + { + fluid_voice_off(voice); + } + } + + return FLUID_OK; +} + +/** + * Reset reverb engine + * @param synth FluidSynth instance + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_reset_reverb(fluid_synth_t *synth) +{ + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + fluid_synth_update_mixer(synth, fluid_rvoice_mixer_reset_reverb, 0, 0.0f); + FLUID_API_RETURN(FLUID_OK); +} + +/** + * Reset chorus engine + * @param synth FluidSynth instance + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_reset_chorus(fluid_synth_t *synth) +{ + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + fluid_synth_update_mixer(synth, fluid_rvoice_mixer_reset_chorus, 0, 0.0f); + FLUID_API_RETURN(FLUID_OK); +} + + +/** + * Send MIDI system reset command (big red 'panic' button), turns off notes, resets + * controllers and restores initial basic channel configuration. + * @param synth FluidSynth instance + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_system_reset(fluid_synth_t *synth) +{ + int result; + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + result = fluid_synth_system_reset_LOCAL(synth); + FLUID_API_RETURN(result); +} + +/* Local variant of the system reset command */ +static int +fluid_synth_system_reset_LOCAL(fluid_synth_t *synth) +{ + int i; + + if(synth->verbose) + { + FLUID_LOG(FLUID_INFO, "=== systemreset ==="); + } + + fluid_synth_all_sounds_off_LOCAL(synth, -1); + + for(i = 0; i < synth->midi_channels; i++) + { + fluid_channel_reset(synth->channel[i]); + } + + /* Basic channel 0, Mode Omni On Poly */ + fluid_synth_set_basic_channel(synth, 0, FLUID_CHANNEL_MODE_OMNION_POLY, + synth->midi_channels); + + fluid_synth_update_mixer(synth, fluid_rvoice_mixer_reset_reverb, 0, 0.0f); + fluid_synth_update_mixer(synth, fluid_rvoice_mixer_reset_chorus, 0, 0.0f); + + return FLUID_OK; +} + +/** + * Update voices on a MIDI channel after a MIDI control change. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param is_cc Boolean value indicating if ctrl is a CC controller or not + * @param ctrl MIDI controller value + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +static int +fluid_synth_modulate_voices_LOCAL(fluid_synth_t *synth, int chan, int is_cc, int ctrl) +{ + fluid_voice_t *voice; + int i; + + for(i = 0; i < synth->polyphony; i++) + { + voice = synth->voice[i]; + + if(fluid_voice_get_channel(voice) == chan) + { + fluid_voice_modulate(voice, is_cc, ctrl); + } + } + + return FLUID_OK; +} + +/** + * Update voices on a MIDI channel after all MIDI controllers have been changed. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +static int +fluid_synth_modulate_voices_all_LOCAL(fluid_synth_t *synth, int chan) +{ + fluid_voice_t *voice; + int i; + + for(i = 0; i < synth->polyphony; i++) + { + voice = synth->voice[i]; + + if(fluid_voice_get_channel(voice) == chan) + { + fluid_voice_modulate_all(voice); + } + } + + return FLUID_OK; +} + +/** + * Set the MIDI channel pressure controller value. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param val MIDI channel pressure value (0-127) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_channel_pressure(fluid_synth_t *synth, int chan, int val) +{ + int result; + fluid_return_val_if_fail(val >= 0 && val <= 127, FLUID_FAILED); + + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + /* Allowed only on MIDI channel enabled */ + FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED); + + if(synth->verbose) + { + FLUID_LOG(FLUID_INFO, "channelpressure\t%d\t%d", chan, val); + } + + fluid_channel_set_channel_pressure(synth->channel[chan], val); + result = fluid_synth_update_channel_pressure_LOCAL(synth, chan); + + FLUID_API_RETURN(result); +} + +/* Updates channel pressure from within synthesis thread */ +static int +fluid_synth_update_channel_pressure_LOCAL(fluid_synth_t *synth, int chan) +{ + return fluid_synth_modulate_voices_LOCAL(synth, chan, 0, FLUID_MOD_CHANNELPRESSURE); +} + +/** + * Set the MIDI polyphonic key pressure controller value. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param key MIDI key number (0-127) + * @param val MIDI key pressure value (0-127) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @since 2.0.0 + */ +int +fluid_synth_key_pressure(fluid_synth_t *synth, int chan, int key, int val) +{ + int result; + fluid_return_val_if_fail(key >= 0 && key <= 127, FLUID_FAILED); + fluid_return_val_if_fail(val >= 0 && val <= 127, FLUID_FAILED); + + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + /* Allowed only on MIDI channel enabled */ + FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED); + + if(synth->verbose) + { + FLUID_LOG(FLUID_INFO, "keypressure\t%d\t%d\t%d", chan, key, val); + } + + fluid_channel_set_key_pressure(synth->channel[chan], key, val); + result = fluid_synth_update_key_pressure_LOCAL(synth, chan, key); + + FLUID_API_RETURN(result); +} + +/* Updates key pressure from within synthesis thread */ +static int +fluid_synth_update_key_pressure_LOCAL(fluid_synth_t *synth, int chan, int key) +{ + fluid_voice_t *voice; + int i; + int result = FLUID_OK; + + for(i = 0; i < synth->polyphony; i++) + { + voice = synth->voice[i]; + + if(voice->chan == chan && voice->key == key) + { + result = fluid_voice_modulate(voice, 0, FLUID_MOD_KEYPRESSURE); + + if(result != FLUID_OK) + { + return result; + } + } + } + + return result; +} + +/** + * Set the MIDI pitch bend controller value on a MIDI channel. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param val MIDI pitch bend value (0-16383 with 8192 being center) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_pitch_bend(fluid_synth_t *synth, int chan, int val) +{ + int result; + fluid_return_val_if_fail(val >= 0 && val <= 16383, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + /* Allowed only on MIDI channel enabled */ + FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED); + + if(synth->verbose) + { + FLUID_LOG(FLUID_INFO, "pitchb\t%d\t%d", chan, val); + } + + fluid_channel_set_pitch_bend(synth->channel[chan], val); + result = fluid_synth_update_pitch_bend_LOCAL(synth, chan); + + FLUID_API_RETURN(result); +} + +/* Local synthesis thread variant of pitch bend */ +static int +fluid_synth_update_pitch_bend_LOCAL(fluid_synth_t *synth, int chan) +{ + return fluid_synth_modulate_voices_LOCAL(synth, chan, 0, FLUID_MOD_PITCHWHEEL); +} + +/** + * Get the MIDI pitch bend controller value on a MIDI channel. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param ppitch_bend Location to store MIDI pitch bend value (0-16383 with + * 8192 being center) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_get_pitch_bend(fluid_synth_t *synth, int chan, int *ppitch_bend) +{ + int result; + fluid_return_val_if_fail(ppitch_bend != NULL, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + /* Allowed only on MIDI channel enabled */ + FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED); + + *ppitch_bend = fluid_channel_get_pitch_bend(synth->channel[chan]); + result = FLUID_OK; + + FLUID_API_RETURN(result); +} + +/** + * Set MIDI pitch wheel sensitivity on a MIDI channel. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param val Pitch wheel sensitivity value in semitones + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_pitch_wheel_sens(fluid_synth_t *synth, int chan, int val) +{ + int result; + fluid_return_val_if_fail(val >= 0 && val <= 72, FLUID_FAILED); /* 6 octaves!? Better than no limit.. */ + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + /* Allowed only on MIDI channel enabled */ + FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED); + + if(synth->verbose) + { + FLUID_LOG(FLUID_INFO, "pitchsens\t%d\t%d", chan, val); + } + + fluid_channel_set_pitch_wheel_sensitivity(synth->channel[chan], val); + result = fluid_synth_update_pitch_wheel_sens_LOCAL(synth, chan); + + FLUID_API_RETURN(result); +} + +/* Local synthesis thread variant of set pitch wheel sensitivity */ +static int +fluid_synth_update_pitch_wheel_sens_LOCAL(fluid_synth_t *synth, int chan) +{ + return fluid_synth_modulate_voices_LOCAL(synth, chan, 0, FLUID_MOD_PITCHWHEELSENS); +} + +/** + * Get MIDI pitch wheel sensitivity on a MIDI channel. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param pval Location to store pitch wheel sensitivity value in semitones + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @since Sometime AFTER v1.0 API freeze. + */ +int +fluid_synth_get_pitch_wheel_sens(fluid_synth_t *synth, int chan, int *pval) +{ + int result; + fluid_return_val_if_fail(pval != NULL, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + /* Allowed only on MIDI channel enabled */ + FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED); + + *pval = fluid_channel_get_pitch_wheel_sensitivity(synth->channel[chan]); + result = FLUID_OK; + + FLUID_API_RETURN(result); +} + +/** + * Assign a preset to a MIDI channel. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param preset Preset to assign to channel or NULL to clear (ownership is taken over) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +static int +fluid_synth_set_preset(fluid_synth_t *synth, int chan, fluid_preset_t *preset) +{ + fluid_channel_t *channel; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail(chan >= 0 && chan < synth->midi_channels, FLUID_FAILED); + + channel = synth->channel[chan]; + + return fluid_channel_set_preset(channel, preset); +} + +/* Get a preset by SoundFont, bank and program numbers. + * Returns preset pointer or NULL. + */ +static fluid_preset_t * +fluid_synth_get_preset(fluid_synth_t *synth, int sfontnum, + int banknum, int prognum) +{ + fluid_sfont_t *sfont; + fluid_list_t *list; + + /* 128 indicates an "unset" operation" */ + if(prognum == FLUID_UNSET_PROGRAM) + { + return NULL; + } + + for(list = synth->sfont; list; list = fluid_list_next(list)) + { + sfont = fluid_list_get(list); + + if(fluid_sfont_get_id(sfont) == sfontnum) + { + return fluid_sfont_get_preset(sfont, banknum - sfont->bankofs, prognum); + } + } + + return NULL; +} + +/* Get a preset by SoundFont name, bank and program. + * Returns preset pointer or NULL. + */ +static fluid_preset_t * +fluid_synth_get_preset_by_sfont_name(fluid_synth_t *synth, const char *sfontname, + int banknum, int prognum) +{ + fluid_sfont_t *sfont; + fluid_list_t *list; + + for(list = synth->sfont; list; list = fluid_list_next(list)) + { + sfont = fluid_list_get(list); + + if(FLUID_STRCMP(fluid_sfont_get_name(sfont), sfontname) == 0) + { + return fluid_sfont_get_preset(sfont, banknum - sfont->bankofs, prognum); + } + } + + return NULL; +} + +/* Find a preset by bank and program numbers. + * Returns preset pointer or NULL. + */ +fluid_preset_t * +fluid_synth_find_preset(fluid_synth_t *synth, int banknum, + int prognum) +{ + fluid_preset_t *preset; + fluid_sfont_t *sfont; + fluid_list_t *list; + + for(list = synth->sfont; list; list = fluid_list_next(list)) + { + sfont = fluid_list_get(list); + + preset = fluid_sfont_get_preset(sfont, banknum - sfont->bankofs, prognum); + + if(preset) + { + return preset; + } + } + + return NULL; +} + +/** + * Send a program change event on a MIDI channel. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param prognum MIDI program number (0-127) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +/* As of 1.1.1 prognum can be set to 128 to unset the preset. Not documented + * since fluid_synth_unset_program() should be used instead. */ +int +fluid_synth_program_change(fluid_synth_t *synth, int chan, int prognum) +{ + fluid_preset_t *preset = NULL; + fluid_channel_t *channel; + int subst_bank, subst_prog, banknum = 0, result = FLUID_FAILED; + + fluid_return_val_if_fail(prognum >= 0 && prognum <= 128, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + /* Allowed only on MIDI channel enabled */ + FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED); + + channel = synth->channel[chan]; + + if(channel->channel_type == CHANNEL_TYPE_DRUM) + { + banknum = DRUM_INST_BANK; + } + else + { + fluid_channel_get_sfont_bank_prog(channel, NULL, &banknum, NULL); + } + + if(synth->verbose) + { + FLUID_LOG(FLUID_INFO, "prog\t%d\t%d\t%d", chan, banknum, prognum); + } + + /* I think this is a hack for MIDI files that do bank changes in GM mode. + * Proper way to handle this would probably be to ignore bank changes when in + * GM mode. - JG + * This is now possible by setting synth.midi-bank-select=gm, but let the hack + * stay for the time being. - DH + */ + if(prognum != FLUID_UNSET_PROGRAM) + { + subst_bank = banknum; + subst_prog = prognum; + + preset = fluid_synth_find_preset(synth, subst_bank, subst_prog); + + /* Fallback to another preset if not found */ + if(!preset) + { + /* Percussion: Fallback to preset 0 in percussion bank */ + if(channel->channel_type == CHANNEL_TYPE_DRUM) + { + subst_prog = 0; + subst_bank = DRUM_INST_BANK; + preset = fluid_synth_find_preset(synth, subst_bank, subst_prog); + } + /* Melodic instrument */ + else + { + /* Fallback first to bank 0:prognum */ + subst_bank = 0; + preset = fluid_synth_find_preset(synth, subst_bank, subst_prog); + + /* Fallback to first preset in bank 0 (usually piano...) */ + if(!preset) + { + subst_prog = 0; + preset = fluid_synth_find_preset(synth, subst_bank, subst_prog); + } + } + + if(preset) + { + FLUID_LOG(FLUID_WARN, "Instrument not found on channel %d [bank=%d prog=%d], substituted [bank=%d prog=%d]", + chan, banknum, prognum, subst_bank, subst_prog); + } + else + { + FLUID_LOG(FLUID_WARN, "No preset found on channel %d [bank=%d prog=%d]", chan, banknum, prognum); + } + } + } + + /* Assign the SoundFont ID and program number to the channel */ + fluid_channel_set_sfont_bank_prog(channel, preset ? fluid_sfont_get_id(preset->sfont) : 0, + -1, prognum); + result = fluid_synth_set_preset(synth, chan, preset); + + FLUID_API_RETURN(result); +} + +/** + * Set instrument bank number on a MIDI channel. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param bank MIDI bank number + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @note This function does not change the instrument currently assigned to \c chan, + * as it is usually called prior to fluid_synth_program_change(). If you still want + * instrument changes to take effect immediately, call fluid_synth_program_reset() + * after having set up the bank configuration. + * + */ +int +fluid_synth_bank_select(fluid_synth_t *synth, int chan, int bank) +{ + int result; + fluid_return_val_if_fail(bank <= 16383, FLUID_FAILED); + fluid_return_val_if_fail(bank >= 0, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + /* Allowed only on MIDI channel enabled */ + FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED); + + fluid_channel_set_sfont_bank_prog(synth->channel[chan], -1, bank, -1); + result = FLUID_OK; + + FLUID_API_RETURN(result); +} + +/** + * Set SoundFont ID on a MIDI channel. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param sfont_id ID of a loaded SoundFont + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @note This function does not change the instrument currently assigned to \c chan, + * as it is usually called prior to fluid_synth_bank_select() or fluid_synth_program_change(). + * If you still want instrument changes to take effect immediately, call fluid_synth_program_reset() + * after having selected the soundfont. + */ +int +fluid_synth_sfont_select(fluid_synth_t *synth, int chan, int sfont_id) +{ + int result; + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + /* Allowed only on MIDI channel enabled */ + FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED); + + fluid_channel_set_sfont_bank_prog(synth->channel[chan], sfont_id, -1, -1); + result = FLUID_OK; + + FLUID_API_RETURN(result); +} + +/** + * Set the preset of a MIDI channel to an unassigned state. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @since 1.1.1 + * + * @note Channel retains its SoundFont ID and bank numbers, while the program + * number is set to an "unset" state. MIDI program changes may re-assign a + * preset if one matches. + */ +int +fluid_synth_unset_program(fluid_synth_t *synth, int chan) +{ + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + FLUID_API_RETURN(fluid_synth_program_change(synth, chan, FLUID_UNSET_PROGRAM)); +} + +/** + * Get current SoundFont ID, bank number and program number for a MIDI channel. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param sfont_id Location to store SoundFont ID + * @param bank_num Location to store MIDI bank number + * @param preset_num Location to store MIDI program number + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_get_program(fluid_synth_t *synth, int chan, int *sfont_id, + int *bank_num, int *preset_num) +{ + int result; + fluid_channel_t *channel; + + fluid_return_val_if_fail(sfont_id != NULL, FLUID_FAILED); + fluid_return_val_if_fail(bank_num != NULL, FLUID_FAILED); + fluid_return_val_if_fail(preset_num != NULL, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + /* Allowed only on MIDI channel enabled */ + FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED); + + channel = synth->channel[chan]; + fluid_channel_get_sfont_bank_prog(channel, sfont_id, bank_num, preset_num); + + /* 128 indicates that the preset is unset. Set to 0 to be backwards compatible. */ + if(*preset_num == FLUID_UNSET_PROGRAM) + { + *preset_num = 0; + } + + result = FLUID_OK; + + FLUID_API_RETURN(result); +} + +/** + * Select an instrument on a MIDI channel by SoundFont ID, bank and program numbers. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param sfont_id ID of a loaded SoundFont + * @param bank_num MIDI bank number + * @param preset_num MIDI program number + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_program_select(fluid_synth_t *synth, int chan, int sfont_id, + int bank_num, int preset_num) +{ + fluid_preset_t *preset = NULL; + fluid_channel_t *channel; + int result; + fluid_return_val_if_fail(bank_num >= 0, FLUID_FAILED); + fluid_return_val_if_fail(preset_num >= 0, FLUID_FAILED); + + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + /* Allowed only on MIDI channel enabled */ + FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED); + + channel = synth->channel[chan]; + + preset = fluid_synth_get_preset(synth, sfont_id, bank_num, preset_num); + + if(preset == NULL) + { + FLUID_LOG(FLUID_ERR, + "There is no preset with bank number %d and preset number %d in SoundFont %d", + bank_num, preset_num, sfont_id); + FLUID_API_RETURN(FLUID_FAILED); + } + + /* Assign the new SoundFont ID, bank and program number to the channel */ + fluid_channel_set_sfont_bank_prog(channel, sfont_id, bank_num, preset_num); + result = fluid_synth_set_preset(synth, chan, preset); + + FLUID_API_RETURN(result); +} + +/** + * Pins all samples of the given preset. + * + * @param synth FluidSynth instance + * @param sfont_id ID of a loaded SoundFont + * @param bank_num MIDI bank number + * @param preset_num MIDI program number + * @return #FLUID_OK if the preset was found, pinned and loaded + * into memory successfully. #FLUID_FAILED otherwise. Note that #FLUID_OK + * is returned, even if synth.dynamic-sample-loading is disabled or + * the preset doesn't support dynamic-sample-loading. + * + * This function will attempt to pin all samples of the given preset and + * load them into memory, if they are currently unloaded. "To pin" in this + * context means preventing them from being unloaded by an upcoming channel + * prog change. + * + * @note This function is only useful if \ref settings_synth_dynamic-sample-loading is enabled. + * By default, dynamic-sample-loading is disabled and all samples are kept in memory. + * Furthermore, this is only useful for presets which support dynamic-sample-loading (currently, + * only preset loaded with the default soundfont loader do). + * + * @since 2.2.0 + */ +int +fluid_synth_pin_preset(fluid_synth_t *synth, int sfont_id, int bank_num, int preset_num) +{ + int ret; + fluid_preset_t *preset; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail(bank_num >= 0, FLUID_FAILED); + fluid_return_val_if_fail(preset_num >= 0, FLUID_FAILED); + + fluid_synth_api_enter(synth); + + preset = fluid_synth_get_preset(synth, sfont_id, bank_num, preset_num); + + if(preset == NULL) + { + FLUID_LOG(FLUID_ERR, + "There is no preset with bank number %d and preset number %d in SoundFont %d", + bank_num, preset_num, sfont_id); + FLUID_API_RETURN(FLUID_FAILED); + } + + ret = fluid_preset_notify(preset, FLUID_PRESET_PIN, -1); // channel unused for pinning messages + + FLUID_API_RETURN(ret); +} + +/** + * Unpin all samples of the given preset. + * + * @param synth FluidSynth instance + * @param sfont_id ID of a loaded SoundFont + * @param bank_num MIDI bank number + * @param preset_num MIDI program number + * @return #FLUID_OK if preset was found, #FLUID_FAILED otherwise + * + * This function undoes the effect of fluid_synth_pin_preset(). If the preset is + * not currently used, its samples will be unloaded. + * + * @note Only useful for presets loaded with the default soundfont loader and + * only if \ref settings_synth_dynamic-sample-loading is enabled. + * + * @since 2.2.0 + */ +int +fluid_synth_unpin_preset(fluid_synth_t *synth, int sfont_id, int bank_num, int preset_num) +{ + int ret; + fluid_preset_t *preset; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail(bank_num >= 0, FLUID_FAILED); + fluid_return_val_if_fail(preset_num >= 0, FLUID_FAILED); + + fluid_synth_api_enter(synth); + + preset = fluid_synth_get_preset(synth, sfont_id, bank_num, preset_num); + + if(preset == NULL) + { + FLUID_LOG(FLUID_ERR, + "There is no preset with bank number %d and preset number %d in SoundFont %d", + bank_num, preset_num, sfont_id); + FLUID_API_RETURN(FLUID_FAILED); + } + + ret = fluid_preset_notify(preset, FLUID_PRESET_UNPIN, -1); // channel unused for pinning messages + + FLUID_API_RETURN(ret); +} + +/** + * Select an instrument on a MIDI channel by SoundFont name, bank and program numbers. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param sfont_name Name of a loaded SoundFont + * @param bank_num MIDI bank number + * @param preset_num MIDI program number + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @since 1.1.0 + */ +int +fluid_synth_program_select_by_sfont_name(fluid_synth_t *synth, int chan, + const char *sfont_name, int bank_num, + int preset_num) +{ + fluid_preset_t *preset = NULL; + fluid_channel_t *channel; + int result; + fluid_return_val_if_fail(sfont_name != NULL, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + /* Allowed only on MIDI channel enabled */ + FLUID_API_RETURN_IF_CHAN_DISABLED(FLUID_FAILED); + + channel = synth->channel[chan]; + + preset = fluid_synth_get_preset_by_sfont_name(synth, sfont_name, bank_num, + preset_num); + + if(preset == NULL) + { + FLUID_LOG(FLUID_ERR, + "There is no preset with bank number %d and preset number %d in SoundFont %s", + bank_num, preset_num, sfont_name); + FLUID_API_RETURN(FLUID_FAILED); + } + + /* Assign the new SoundFont ID, bank and program number to the channel */ + fluid_channel_set_sfont_bank_prog(channel, fluid_sfont_get_id(preset->sfont), + bank_num, preset_num); + result = fluid_synth_set_preset(synth, chan, preset); + + FLUID_API_RETURN(result); +} + +/* + * This function assures that every MIDI channel has a valid preset + * (NULL is okay). This function is called after a SoundFont is + * unloaded or reloaded. + */ +static void +fluid_synth_update_presets(fluid_synth_t *synth) +{ + fluid_channel_t *channel; + fluid_preset_t *preset; + int sfont, bank, prog; + int chan; + + for(chan = 0; chan < synth->midi_channels; chan++) + { + channel = synth->channel[chan]; + fluid_channel_get_sfont_bank_prog(channel, &sfont, &bank, &prog); + preset = fluid_synth_get_preset(synth, sfont, bank, prog); + fluid_synth_set_preset(synth, chan, preset); + } +} + +static void +fluid_synth_set_sample_rate_LOCAL(fluid_synth_t *synth, float sample_rate) +{ + int i; + fluid_clip(sample_rate, 8000.0f, 96000.0f); + synth->sample_rate = sample_rate; + + synth->min_note_length_ticks = fluid_synth_get_min_note_length_LOCAL(synth); + + for(i = 0; i < synth->polyphony; i++) + { + fluid_voice_set_output_rate(synth->voice[i], sample_rate); + } +} + +/** + * Set up an event to change the sample-rate of the synth during the next rendering call. + * @warning This function is broken-by-design! Don't use it! Instead, specify the sample-rate when creating the synth. + * @deprecated As of fluidsynth 2.1.0 this function has been deprecated. + * Changing the sample-rate is generally not considered to be a real-time use-case, as it always produces some audible artifact ("click", "pop") on the dry sound and effects (because LFOs for chorus and reverb need to be reinitialized). + * The sample-rate change may also require memory allocation deep down in the effect units. + * However, this memory allocation may fail and there is no way for the caller to know that, because the actual change of the sample-rate is executed during rendering. + * This function cannot (must not) do the sample-rate change itself, otherwise the synth needs to be locked down, causing rendering to block. + * Esp. do not use this function if this @p synth instance is used by an audio driver, because the audio driver cannot be notified by this sample-rate change. + * Long story short: don't use it. + * @code{.cpp} + fluid_synth_t* synth; // assume initialized + // [...] + // sample-rate change needed? Delete the audio driver, if any. + delete_fluid_audio_driver(adriver); + // then delete the synth + delete_fluid_synth(synth); + // update the sample-rate + fluid_settings_setnum(settings, "synth.sample-rate", 22050.0); + // and re-create objects + synth = new_fluid_synth(settings); + adriver = new_fluid_audio_driver(settings, synth); + * @endcode + * @param synth FluidSynth instance + * @param sample_rate New sample-rate (Hz) + * @since 1.1.2 + */ +void +fluid_synth_set_sample_rate(fluid_synth_t *synth, float sample_rate) +{ + fluid_return_if_fail(synth != NULL); + fluid_synth_api_enter(synth); + + fluid_synth_set_sample_rate_LOCAL(synth, sample_rate); + + fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_samplerate, + 0, synth->sample_rate); + fluid_synth_api_exit(synth); +} + +// internal sample rate change function for the jack driver +// executes immediately, therefore, make sure no rendering call is running! +void +fluid_synth_set_sample_rate_immediately(fluid_synth_t *synth, float sample_rate) +{ + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; + fluid_return_if_fail(synth != NULL); + fluid_synth_api_enter(synth); + + fluid_synth_set_sample_rate_LOCAL(synth, sample_rate); + + param[0].i = 0; + param[1].real = synth->sample_rate; + fluid_rvoice_mixer_set_samplerate(synth->eventhandler->mixer, param); + + fluid_synth_api_exit(synth); +} + + +/* Handler for synth.gain setting. */ +static void +fluid_synth_handle_gain(void *data, const char *name, double value) +{ + fluid_synth_t *synth = (fluid_synth_t *)data; + fluid_synth_set_gain(synth, (float) value); +} + +/** + * Set synth output gain value. + * @param synth FluidSynth instance + * @param gain Gain value (function clamps value to the range 0.0 to 10.0) + */ +void +fluid_synth_set_gain(fluid_synth_t *synth, float gain) +{ + fluid_return_if_fail(synth != NULL); + fluid_synth_api_enter(synth); + + fluid_clip(gain, 0.0f, 10.0f); + + synth->gain = gain; + fluid_synth_update_gain_LOCAL(synth); + fluid_synth_api_exit(synth); +} + +/* Called by synthesis thread to update the gain in all voices */ +static void +fluid_synth_update_gain_LOCAL(fluid_synth_t *synth) +{ + fluid_voice_t *voice; + float gain; + int i; + + gain = synth->gain; + + for(i = 0; i < synth->polyphony; i++) + { + voice = synth->voice[i]; + + if(fluid_voice_is_playing(voice)) + { + fluid_voice_set_gain(voice, gain); + } + } +} + +/** + * Get synth output gain value. + * @param synth FluidSynth instance + * @return Synth gain value (0.0 to 10.0) + */ +float +fluid_synth_get_gain(fluid_synth_t *synth) +{ + float result; + fluid_return_val_if_fail(synth != NULL, 0.0); + fluid_synth_api_enter(synth); + + result = synth->gain; + FLUID_API_RETURN(result); +} + +/* + * Handler for synth.polyphony setting. + */ +static void +fluid_synth_handle_polyphony(void *data, const char *name, int value) +{ + fluid_synth_t *synth = (fluid_synth_t *)data; + fluid_synth_set_polyphony(synth, value); +} + +/** + * Set synthesizer polyphony (max number of voices). + * @param synth FluidSynth instance + * @param polyphony Polyphony to assign + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @since 1.0.6 + */ +int +fluid_synth_set_polyphony(fluid_synth_t *synth, int polyphony) +{ + int result; + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail(polyphony >= 1 && polyphony <= 65535, FLUID_FAILED); + fluid_synth_api_enter(synth); + + result = fluid_synth_update_polyphony_LOCAL(synth, polyphony); + + FLUID_API_RETURN(result); +} + +/* Called by synthesis thread to update the polyphony value */ +static int +fluid_synth_update_polyphony_LOCAL(fluid_synth_t *synth, int new_polyphony) +{ + fluid_voice_t *voice; + int i; + + if(new_polyphony > synth->nvoice) + { + /* Create more voices */ + fluid_voice_t **new_voices = FLUID_REALLOC(synth->voice, + sizeof(fluid_voice_t *) * new_polyphony); + + if(new_voices == NULL) + { + return FLUID_FAILED; + } + + synth->voice = new_voices; + + for(i = synth->nvoice; i < new_polyphony; i++) + { + synth->voice[i] = new_fluid_voice(synth->eventhandler, synth->sample_rate); + + if(synth->voice[i] == NULL) + { + return FLUID_FAILED; + } + + fluid_voice_set_custom_filter(synth->voice[i], synth->custom_filter_type, synth->custom_filter_flags); + } + + synth->nvoice = new_polyphony; + } + + synth->polyphony = new_polyphony; + + /* turn off any voices above the new limit */ + for(i = synth->polyphony; i < synth->nvoice; i++) + { + voice = synth->voice[i]; + + if(fluid_voice_is_playing(voice)) + { + fluid_voice_off(voice); + } + } + + fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_polyphony, + synth->polyphony, 0.0f); + + return FLUID_OK; +} + +/** + * Get current synthesizer polyphony (max number of voices). + * @param synth FluidSynth instance + * @return Synth polyphony value. + * @since 1.0.6 + */ +int +fluid_synth_get_polyphony(fluid_synth_t *synth) +{ + int result; + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + + result = synth->polyphony; + FLUID_API_RETURN(result); +} + +/** + * @brief Get current number of active voices. + * + * I.e. the no. of voices that have been + * started and have not yet finished. Unless called from synthesis context, + * this number does not necessarily have to be equal to the number of voices + * currently processed by the DSP loop, see below. + * @param synth FluidSynth instance + * @return Number of currently active voices. + * @since 1.1.0 + * + * @note To generate accurate continuous statistics of the voice count, caller + * should ensure this function is called synchronously with the audio synthesis + * process. This can be done in the new_fluid_audio_driver2() audio callback + * function for example. Otherwise every call to this function may return different + * voice counts as it may change after any (concurrent) call to fluid_synth_write_*() made by + * e.g. an audio driver or the applications audio rendering thread. + */ +int +fluid_synth_get_active_voice_count(fluid_synth_t *synth) +{ + int result; + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + + result = synth->active_voice_count; + FLUID_API_RETURN(result); +} + +/** + * Get the internal synthesis buffer size value. + * @param synth FluidSynth instance + * @return Internal buffer size in audio frames. + * + * Audio is synthesized at this number of frames at a time. Defaults to 64 frames. I.e. the synth can only react to notes, + * control changes, and other audio affecting events after having processed 64 audio frames. + */ +int +fluid_synth_get_internal_bufsize(fluid_synth_t *synth) +{ + return FLUID_BUFSIZE; +} + +/** + * Resend a bank select and a program change for every channel and assign corresponding instruments. + * @param synth FluidSynth instance + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * + * This function is called mainly after a SoundFont has been loaded, + * unloaded or reloaded. + */ +int +fluid_synth_program_reset(fluid_synth_t *synth) +{ + int i, prog; + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + + /* try to set the correct presets */ + for(i = 0; i < synth->midi_channels; i++) + { + fluid_channel_get_sfont_bank_prog(synth->channel[i], NULL, NULL, &prog); + fluid_synth_program_change(synth, i, prog); + } + + FLUID_API_RETURN(FLUID_OK); +} + +/** + * Synthesize a block of floating point audio to separate audio buffers (multi-channel rendering). + * + * @param synth FluidSynth instance + * @param len Count of audio frames to synthesize + * @param left Array of float buffers to store left channel of planar audio (as many as \c synth.audio-channels buffers, each of \c len in size) + * @param right Array of float buffers to store right channel of planar audio (size: dito) + * @param fx_left Since 1.1.7: If not \c NULL, array of float buffers to store left effect channels (as many as \c synth.effects-channels buffers, each of \c len in size) + * @param fx_right Since 1.1.7: If not \c NULL, array of float buffers to store right effect channels (size: dito) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * + * First effect channel used by reverb, second for chorus. + * + * @note Should only be called from synthesis thread. + * + * @deprecated fluid_synth_nwrite_float() is deprecated and will be removed in a future release. + * It may continue to work or it may return #FLUID_FAILED in the future. Consider using the more + * powerful and flexible fluid_synth_process(). + * + * Usage example: + * @code{.cpp} + const int FramesToRender = 64; + int channels; + // retrieve number of stereo audio channels + fluid_settings_getint(settings, "synth.audio-channels", &channels); + + // we need twice as many (mono-)buffers + channels *= 2; + + // fluid_synth_nwrite_float renders planar audio, e.g. if synth.audio-channels==16: + // each midi channel gets rendered to its own stereo buffer, rather than having + // one buffer and interleaved PCM + float** mix_buf = new float*[channels]; + for(int i = 0; i < channels; i++) + { + mix_buf[i] = new float[FramesToRender]; + } + + // retrieve number of (stereo) effect channels (internally hardcoded to reverb (first chan) + // and chrous (second chan)) + fluid_settings_getint(settings, "synth.effects-channels", &channels); + channels *= 2; + + float** fx_buf = new float*[channels]; + for(int i = 0; i < channels; i++) + { + fx_buf[i] = new float[FramesToRender]; + } + + float** mix_buf_l = mix_buf; + float** mix_buf_r = &mix_buf[channels/2]; + + float** fx_buf_l = fx_buf; + float** fx_buf_r = &fx_buf[channels/2]; + + fluid_synth_nwrite_float(synth, FramesToRender, mix_buf_l, mix_buf_r, fx_buf_l, fx_buf_r) + * @endcode + */ +int +fluid_synth_nwrite_float(fluid_synth_t *synth, int len, + float **left, float **right, + float **fx_left, float **fx_right) +{ + fluid_real_t *left_in, *fx_left_in; + fluid_real_t *right_in, *fx_right_in; + double time = fluid_utime(); + int i, num, available, count; +#ifdef WITH_FLOAT + int bytes; +#endif + float cpu_load; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail(left != NULL, FLUID_FAILED); + fluid_return_val_if_fail(right != NULL, FLUID_FAILED); + fluid_return_val_if_fail(len >= 0, FLUID_FAILED); + fluid_return_val_if_fail(len != 0, FLUID_OK); // to avoid raising FE_DIVBYZERO below + + /* First, take what's still available in the buffer */ + count = 0; + num = synth->cur; + + if(synth->cur < FLUID_BUFSIZE) + { + available = FLUID_BUFSIZE - synth->cur; + fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in); + fluid_rvoice_mixer_get_fx_bufs(synth->eventhandler->mixer, &fx_left_in, &fx_right_in); + + num = (available > len) ? len : available; +#ifdef WITH_FLOAT + bytes = num * sizeof(float); +#endif + + for(i = 0; i < synth->audio_channels; i++) + { +#ifdef WITH_FLOAT + FLUID_MEMCPY(left[i], &left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + synth->cur], bytes); + FLUID_MEMCPY(right[i], &right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + synth->cur], bytes); +#else //WITH_FLOAT + int j; + + for(j = 0; j < num; j++) + { + left[i][j] = (float) left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j + synth->cur]; + right[i][j] = (float) right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j + synth->cur]; + } + +#endif //WITH_FLOAT + } + + for(i = 0; i < synth->effects_channels; i++) + { +#ifdef WITH_FLOAT + + if(fx_left != NULL) + { + FLUID_MEMCPY(fx_left[i], &fx_left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + synth->cur], bytes); + } + + if(fx_right != NULL) + { + FLUID_MEMCPY(fx_right[i], &fx_right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + synth->cur], bytes); + } + +#else //WITH_FLOAT + int j; + + if(fx_left != NULL) + { + for(j = 0; j < num; j++) + { + fx_left[i][j] = (float) fx_left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j + synth->cur]; + } + } + + if(fx_right != NULL) + { + for(j = 0; j < num; j++) + { + fx_right[i][j] = (float) fx_right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j + synth->cur]; + } + } + +#endif //WITH_FLOAT + } + + count += num; + num += synth->cur; /* if we're now done, num becomes the new synth->cur below */ + } + + /* Then, run one_block() and copy till we have 'len' samples */ + while(count < len) + { + fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, 0); + fluid_synth_render_blocks(synth, 1); // TODO: + fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in); + fluid_rvoice_mixer_get_fx_bufs(synth->eventhandler->mixer, &fx_left_in, &fx_right_in); + + num = (FLUID_BUFSIZE > len - count) ? len - count : FLUID_BUFSIZE; +#ifdef WITH_FLOAT + bytes = num * sizeof(float); +#endif + + for(i = 0; i < synth->audio_channels; i++) + { +#ifdef WITH_FLOAT + FLUID_MEMCPY(left[i] + count, &left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT], bytes); + FLUID_MEMCPY(right[i] + count, &right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT], bytes); +#else //WITH_FLOAT + int j; + + for(j = 0; j < num; j++) + { + left[i][j + count] = (float) left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j]; + right[i][j + count] = (float) right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j]; + } + +#endif //WITH_FLOAT + } + + for(i = 0; i < synth->effects_channels; i++) + { +#ifdef WITH_FLOAT + + if(fx_left != NULL) + { + FLUID_MEMCPY(fx_left[i] + count, &fx_left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT], bytes); + } + + if(fx_right != NULL) + { + FLUID_MEMCPY(fx_right[i] + count, &fx_right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT], bytes); + } + +#else //WITH_FLOAT + int j; + + if(fx_left != NULL) + { + for(j = 0; j < num; j++) + { + fx_left[i][j + count] = (float) fx_left_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j]; + } + } + + if(fx_right != NULL) + { + for(j = 0; j < num; j++) + { + fx_right[i][j + count] = (float) fx_right_in[i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j]; + } + } + +#endif //WITH_FLOAT + } + + count += num; + } + + synth->cur = num; + + time = fluid_utime() - time; + cpu_load = 0.5 * (fluid_atomic_float_get(&synth->cpu_load) + time * synth->sample_rate / len / 10000.0); + fluid_atomic_float_set(&synth->cpu_load, cpu_load); + + return FLUID_OK; +} + +/** + * mixes the samples of \p in to \p out + * + * @param out the output sample buffer to mix to + * @param ooff sample offset in \p out + * @param in the rvoice_mixer input sample buffer to mix from + * @param ioff sample offset in \p in + * @param buf_idx the sample buffer index of \p in to mix from + * @param num number of samples to mix + */ +static FLUID_INLINE void fluid_synth_mix_single_buffer(float *FLUID_RESTRICT out, + int ooff, + const fluid_real_t *FLUID_RESTRICT in, + int ioff, + int buf_idx, + int num) +{ + if(out != NULL) + { + int j; + + for(j = 0; j < num; j++) + { + out[j + ooff] += (float) in[buf_idx * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + j + ioff]; + } + } +} + +/** + * Synthesize floating point audio to stereo audio channels + * (implements the default interface #fluid_audio_func_t). + * + * @param synth FluidSynth instance + * + * @param len Count of audio frames to synthesize and store in every single buffer provided by \p out and \p fx. + * Zero value is permitted, the function does nothing and return FLUID_OK. + * + * @param nfx Count of arrays in \c fx. Must be a multiple of 2 (because of stereo) + * and in the range 0 <= nfx/2 <= (fluid_synth_count_effects_channels() * fluid_synth_count_effects_groups()). + * Note that zero value is valid and allows to skip mixing effects in all fx output buffers. + * + * @param fx Array of buffers to store effects audio to. Buffers may + * alias with buffers of \c out. Individual NULL buffers are permitted and will cause to skip mixing any audio into that buffer. + * + * @param nout Count of arrays in \c out. Must be a multiple of 2 + * (because of stereo) and in the range 0 <= nout/2 <= fluid_synth_count_audio_channels(). + * Note that zero value is valid and allows to skip mixing dry audio in all out output buffers. + * + * @param out Array of buffers to store (dry) audio to. Buffers may + * alias with buffers of \c fx. Individual NULL buffers are permitted and will cause to skip mixing any audio into that buffer. + * + * @return #FLUID_OK on success, + * #FLUID_FAILED otherwise, + * - fx == NULL while nfx > 0, or out == NULL while nout > 0. + * - \c nfx or \c nout not multiple of 2. + * - len < 0. + * - \c nfx or \c nout exceed the range explained above. + * + * Synthesize and mix audio to a given number of planar audio buffers. + * Therefore pass nout = N*2 float buffers to \p out in order to render + * the synthesized audio to \p N stereo channels. Each float buffer must be + * able to hold \p len elements. + * + * \p out contains an array of planar buffers for normal, dry, stereo + * audio (alternating left and right). Like: +@code{.cpp} +out[0] = left_buffer_audio_channel_0 +out[1] = right_buffer_audio_channel_0 +out[2] = left_buffer_audio_channel_1 +out[3] = right_buffer_audio_channel_1 +... +out[ (i * 2 + 0) % nout ] = left_buffer_audio_channel_i +out[ (i * 2 + 1) % nout ] = right_buffer_audio_channel_i +@endcode + * + * for zero-based channel index \p i. + * The buffer layout of \p fx used for storing effects + * like reverb and chorus looks similar: +@code{.cpp} +fx[0] = left_buffer_channel_of_reverb_unit_0 +fx[1] = right_buffer_channel_of_reverb_unit_0 +fx[2] = left_buffer_channel_of_chorus_unit_0 +fx[3] = right_buffer_channel_of_chorus_unit_0 +fx[4] = left_buffer_channel_of_reverb_unit_1 +fx[5] = right_buffer_channel_of_reverb_unit_1 +fx[6] = left_buffer_channel_of_chorus_unit_1 +fx[7] = right_buffer_channel_of_chorus_unit_1 +fx[8] = left_buffer_channel_of_reverb_unit_2 +... +fx[ ((k * fluid_synth_count_effects_channels() + j) * 2 + 0) % nfx ] = left_buffer_for_effect_channel_j_of_unit_k +fx[ ((k * fluid_synth_count_effects_channels() + j) * 2 + 1) % nfx ] = right_buffer_for_effect_channel_j_of_unit_k +@endcode + * where 0 <= k < fluid_synth_count_effects_groups() is a zero-based index denoting the effects unit and + * 0 <= j < fluid_synth_count_effects_channels() is a zero-based index denoting the effect channel within + * unit \p k. + * + * Any playing voice is assigned to audio channels based on the MIDI channel it's playing on: Let \p chan be the + * zero-based MIDI channel index an arbitrary voice is playing on. To determine the audio channel and effects unit it is + * going to be rendered to use: + * + * i = chan % fluid_synth_count_audio_groups() + * + * k = chan % fluid_synth_count_effects_groups() + * + * @parblock + * @note The owner of the sample buffers must zero them out before calling this + * function, because any synthesized audio is mixed (i.e. added) to the buffers. + * E.g. if fluid_synth_process() is called from a custom audio driver process function + * (see new_fluid_audio_driver2()), the audio driver takes care of zeroing the buffers. + * @endparblock + * + * @parblock + * @note No matter how many buffers you pass in, fluid_synth_process() + * will always render all audio channels to the + * buffers in \c out and all effects channels to the + * buffers in \c fx, provided that nout > 0 and nfx > 0 respectively. If + * nout/2 < fluid_synth_count_audio_channels() it will wrap around. Same + * is true for effects audio if nfx/2 < (fluid_synth_count_effects_channels() * fluid_synth_count_effects_groups()). + * See usage examples below. + * @endparblock + * + * @parblock + * @note Should only be called from synthesis thread. + * @endparblock + */ +int +fluid_synth_process(fluid_synth_t *synth, int len, int nfx, float *fx[], + int nout, float *out[]) +{ + return fluid_synth_process_LOCAL(synth, len, nfx, fx, nout, out, fluid_synth_render_blocks); +} + +/* declared public (instead of static) for testing purpose */ +int +fluid_synth_process_LOCAL(fluid_synth_t *synth, int len, int nfx, float *fx[], + int nout, float *out[], int (*block_render_func)(fluid_synth_t *, int)) +{ + fluid_real_t *left_in, *fx_left_in; + fluid_real_t *right_in, *fx_right_in; + int nfxchan, nfxunits, naudchan; + + double time = fluid_utime(); + int i, f, num, count, buffered_blocks; + + float cpu_load; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + + /* fx NULL while nfx > 0 is invalid */ + fluid_return_val_if_fail((fx != NULL) || (nfx == 0), FLUID_FAILED); + /* nfx must be multiple of 2. Note that 0 value is valid and + allows to skip mixing in fx output buffers + */ + fluid_return_val_if_fail(nfx % 2 == 0, FLUID_FAILED); + + /* out NULL while nout > 0 is invalid */ + fluid_return_val_if_fail((out != NULL) || (nout == 0), FLUID_FAILED); + /* nout must be multiple of 2. Note that 0 value is valid and + allows to skip mixing in out output buffers + */ + fluid_return_val_if_fail(nout % 2 == 0, FLUID_FAILED); + + /* check len value. Note that 0 value is valid, the function does nothing and returns FLUID_OK. + */ + fluid_return_val_if_fail(len >= 0, FLUID_FAILED); + fluid_return_val_if_fail(len != 0, FLUID_OK); // to avoid raising FE_DIVBYZERO below + + nfxchan = synth->effects_channels; + nfxunits = synth->effects_groups; + naudchan = synth->audio_channels; + + fluid_return_val_if_fail(0 <= nfx / 2 && nfx / 2 <= nfxchan * nfxunits, FLUID_FAILED); + fluid_return_val_if_fail(0 <= nout / 2 && nout / 2 <= naudchan, FLUID_FAILED); + + /* get internal mixer audio dry buffer's pointer (left and right channel) */ + fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in); + /* get internal mixer audio effect buffer's pointer (left and right channel) */ + fluid_rvoice_mixer_get_fx_bufs(synth->eventhandler->mixer, &fx_left_in, &fx_right_in); + + /* Conversely to fluid_synth_write_float(),fluid_synth_write_s16() (which handle only one + stereo output) we don't want rendered audio effect mixed in internal audio dry buffers. + FALSE instructs the mixer that internal audio effects will be mixed in respective internal + audio effects buffers. + */ + fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, FALSE); + + + /* First, take what's still available in the buffer */ + count = 0; + /* synth->cur indicates if available samples are still in internal mixer buffer */ + num = synth->cur; + + buffered_blocks = (synth->cur + FLUID_BUFSIZE - 1) / FLUID_BUFSIZE; + if(synth->cur < buffered_blocks * FLUID_BUFSIZE) + { + /* yes, available sample are in internal mixer buffer */ + int available = (buffered_blocks * FLUID_BUFSIZE) - synth->cur; + num = (available > len) ? len : available; + + /* mixing dry samples (or skip if requested by the caller) */ + if(nout != 0) + { + for(i = 0; i < naudchan; i++) + { + /* mix num left samples from input mixer buffer (left_in) at input offset + synth->cur to output buffer (out_buf) at offset 0 */ + float *out_buf = out[(i * 2) % nout]; + fluid_synth_mix_single_buffer(out_buf, 0, left_in, synth->cur, i, num); + + /* mix num right samples from input mixer buffer (right_in) at input offset + synth->cur to output buffer (out_buf) at offset 0 */ + out_buf = out[(i * 2 + 1) % nout]; + fluid_synth_mix_single_buffer(out_buf, 0, right_in, synth->cur, i, num); + } + } + + /* mixing effects samples (or skip if requested by the caller) */ + if(nfx != 0) + { + // loop over all effects units + for(f = 0; f < nfxunits; f++) + { + // write out all effects (i.e. reverb and chorus) + for(i = 0; i < nfxchan; i++) + { + int buf_idx = f * nfxchan + i; + + /* mix num left samples from input mixer buffer (fx_left_in) at input offset + synth->cur to output buffer (out_buf) at offset 0 */ + float *out_buf = fx[(buf_idx * 2) % nfx]; + fluid_synth_mix_single_buffer(out_buf, 0, fx_left_in, synth->cur, buf_idx, num); + + /* mix num right samples from input mixer buffer (fx_right_in) at input offset + synth->cur to output buffer (out_buf) at offset 0 */ + out_buf = fx[(buf_idx * 2 + 1) % nfx]; + fluid_synth_mix_single_buffer(out_buf, 0, fx_right_in, synth->cur, buf_idx, num); + } + } + } + + count += num; + num += synth->cur; /* if we're now done, num becomes the new synth->cur below */ + } + + /* Then, render blocks and copy till we have 'len' samples */ + while(count < len) + { + /* always render full bloc multiple of FLUID_BUFSIZE */ + int blocksleft = (len - count + FLUID_BUFSIZE - 1) / FLUID_BUFSIZE; + /* render audio (dry and effect) to respective internal dry and effect buffers */ + int blockcount = block_render_func(synth, blocksleft); + + num = (blockcount * FLUID_BUFSIZE > len - count) ? len - count : blockcount * FLUID_BUFSIZE; + + /* mixing dry samples (or skip if requested by the caller) */ + if(nout != 0) + { + for(i = 0; i < naudchan; i++) + { + /* mix num left samples from input mixer buffer (left_in) at input offset + 0 to output buffer (out_buf) at offset count */ + float *out_buf = out[(i * 2) % nout]; + fluid_synth_mix_single_buffer(out_buf, count, left_in, 0, i, num); + + /* mix num right samples from input mixer buffer (right_in) at input offset + 0 to output buffer (out_buf) at offset count */ + out_buf = out[(i * 2 + 1) % nout]; + fluid_synth_mix_single_buffer(out_buf, count, right_in, 0, i, num); + } + } + + /* mixing effects samples (or skip if requested by the caller) */ + if(nfx != 0) + { + // loop over all effects units + for(f = 0; f < nfxunits; f++) + { + // write out all effects (i.e. reverb and chorus) + for(i = 0; i < nfxchan; i++) + { + int buf_idx = f * nfxchan + i; + + /* mix num left samples from input mixer buffer (fx_left_in) at input offset + 0 to output buffer (out_buf) at offset count */ + float *out_buf = fx[(buf_idx * 2) % nfx]; + fluid_synth_mix_single_buffer(out_buf, count, fx_left_in, 0, buf_idx, num); + + /* mix num right samples from input mixer buffer (fx_right_in) at input offset + 0 to output buffer (out_buf) at offset count */ + out_buf = fx[(buf_idx * 2 + 1) % nfx]; + fluid_synth_mix_single_buffer(out_buf, count, fx_right_in, 0, buf_idx, num); + } + } + } + + count += num; + } + + synth->cur = num; + + time = fluid_utime() - time; + cpu_load = 0.5 * (fluid_atomic_float_get(&synth->cpu_load) + time * synth->sample_rate / len / 10000.0); + fluid_atomic_float_set(&synth->cpu_load, cpu_load); + + return FLUID_OK; +} + + +/** + * Synthesize a block of floating point audio samples to audio buffers. + * @param synth FluidSynth instance + * @param len Count of audio frames to synthesize + * @param lout Array of floats to store left channel of audio + * @param loff Offset index in 'lout' for first sample + * @param lincr Increment between samples stored to 'lout' + * @param rout Array of floats to store right channel of audio + * @param roff Offset index in 'rout' for first sample + * @param rincr Increment between samples stored to 'rout' + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * + * Useful for storing interleaved stereo (lout = rout, loff = 0, roff = 1, + * lincr = 2, rincr = 2). + * + * @note Should only be called from synthesis thread. + * @note Reverb and Chorus are mixed to \c lout resp. \c rout. + */ +int +fluid_synth_write_float(fluid_synth_t *synth, int len, + void *lout, int loff, int lincr, + void *rout, int roff, int rincr) +{ + void *channels_out[2] = {lout, rout}; + int channels_off[2] = {loff, roff }; + int channels_incr[2] = {lincr, rincr }; + + return fluid_synth_write_float_channels(synth, len, 2, channels_out, + channels_off, channels_incr); +} + +/** + * Synthesize a block of float audio samples channels to audio buffers. + * The function is convenient for audio driver to render multiple stereo + * channels pairs on multi channels audio cards (i.e 2, 4, 6, 8,.. channels). + * + * @param synth FluidSynth instance. + * @param len Count of audio frames to synthesize. + * @param channels_count Count of channels in a frame. + * must be multiple of 2 and channel_count/2 must not exceed the number + * of internal mixer buffers (synth->audio_groups) + * @param channels_out Array of channels_count pointers on 16 bit words to + * store sample channels. Modified on return. + * @param channels_off Array of channels_count offset index to add to respective pointer + * in channels_out for first sample. + * @param channels_incr Array of channels_count increment between consecutive + * samples channels. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + * + * Useful for storing: + * - interleaved channels in a unique buffer. + * - non interleaved channels in an unique buffer (or in distinct buffers). + * + * Example for interleaved 4 channels (c1, c2, c3, c4) and n samples (s1, s2,..sn) + * in a unique buffer: + * { s1:c1, s1:c2, s1:c3, s1:c4, s2:c1, s2:c2, s2:c3, s2:c4,... + * sn:c1, sn:c2, sn:c3, sn:c4 }. + * + * @note Should only be called from synthesis thread. + * @note Reverb and Chorus are mixed to \c lout resp. \c rout. + */ +int +fluid_synth_write_float_channels(fluid_synth_t *synth, int len, + int channels_count, + void *channels_out[], int channels_off[], + int channels_incr[]) +{ + return fluid_synth_write_float_channels_LOCAL(synth, len, channels_count, + channels_out, channels_off, channels_incr, + fluid_synth_render_blocks); +} + +int +fluid_synth_write_float_channels_LOCAL(fluid_synth_t *synth, int len, + int channels_count, + void *channels_out[], int channels_off[], + int channels_incr[], + int (*block_render_func)(fluid_synth_t *, int)) +{ + float **chan_out = (float **)channels_out; + int n, cur, size; + + /* pointers on first input mixer buffer */ + fluid_real_t *left_in; + fluid_real_t *right_in; + int bufs_in_count; /* number of stereo input buffers */ + int i; + + /* start average cpu load probe */ + double time = fluid_utime(); + float cpu_load; + + /* start profiling duration probe (if profiling is enabled) */ + fluid_profile_ref_var(prof_ref); + + /* check parameters */ + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + + fluid_return_val_if_fail(len >= 0, FLUID_FAILED); + fluid_return_val_if_fail(len != 0, FLUID_OK); // to avoid raising FE_DIVBYZERO below + + /* check for valid channel_count: must be multiple of 2 and + channel_count/2 must not exceed the number of internal mixer buffers + (synth->audio_groups) + */ + fluid_return_val_if_fail(!(channels_count & 1) /* must be multiple of 2 */ + && channels_count >= 2, FLUID_FAILED); + + bufs_in_count = (unsigned int)channels_count >> 1; /* channels_count/2 */ + fluid_return_val_if_fail(bufs_in_count <= synth->audio_groups, FLUID_FAILED); + + fluid_return_val_if_fail(channels_out != NULL, FLUID_FAILED); + fluid_return_val_if_fail(channels_off != NULL, FLUID_FAILED); + fluid_return_val_if_fail(channels_incr != NULL, FLUID_FAILED); + + /* initialize output channels buffers on first sample position */ + i = channels_count; + do + { + i--; + chan_out[i] += channels_off[i]; + } + while(i); + + /* Conversely to fluid_synth_process(), + we want rendered audio effect mixed in internal audio dry buffers. + TRUE instructs the mixer that internal audio effects will be mixed in internal + audio dry buffers. + */ + fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, TRUE); + + /* get first internal mixer audio dry buffer's pointer (left and right channel) */ + fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in); + + size = len; + + /* synth->cur indicates if available samples are still in internal mixer buffer */ + cur = synth->cur; /* get previous sample position in internal buffer (due to prvious call) */ + + do + { + /* fill up the buffers as needed */ + if(cur >= synth->curmax) + { + /* render audio (dry and effect) to internal dry buffers */ + /* always render full blocs multiple of FLUID_BUFSIZE */ + int blocksleft = (size + FLUID_BUFSIZE - 1) / FLUID_BUFSIZE; + synth->curmax = FLUID_BUFSIZE * block_render_func(synth, blocksleft); + + /* get first internal mixer audio dry buffer's pointer (left and right channel) */ + fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in); + cur = 0; + } + + /* calculate amount of available samples */ + n = synth->curmax - cur; + + /* keep track of emitted samples */ + if(n > size) + { + n = size; + } + + size -= n; + + /* update pointers to current position */ + left_in += cur + n; + right_in += cur + n; + + /* set final cursor position */ + cur += n; + + /* reverse index */ + n = 0 - n; + + do + { + i = bufs_in_count; + do + { + /* input sample index in stereo buffer i */ + int in_idx = --i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + n; + int c = i << 1; /* channel index c to write */ + + /* write left input sample to channel sample */ + *chan_out[c] = (float) left_in[in_idx]; + + /* write right input sample to next channel sample */ + *chan_out[c+1] = (float) right_in[in_idx]; + + /* advance output pointers */ + chan_out[c] += channels_incr[c]; + chan_out[c+1] += channels_incr[c+1]; + } + while(i); + } + while(++n < 0); + } + while(size); + + synth->cur = cur; /* save current sample position. It will be used on next call */ + + /* save average cpu load, use by API for real time cpu load meter */ + time = fluid_utime() - time; + cpu_load = 0.5 * (fluid_atomic_float_get(&synth->cpu_load) + time * synth->sample_rate / len / 10000.0); + fluid_atomic_float_set(&synth->cpu_load, cpu_load); + + /* stop duration probe and save performance measurement (if profiling is enabled) */ + fluid_profile_write(FLUID_PROF_WRITE, prof_ref, + fluid_rvoice_mixer_get_active_voices(synth->eventhandler->mixer), + len); + return FLUID_OK; +} + +/* for testing purpose */ +int +fluid_synth_write_float_LOCAL(fluid_synth_t *synth, int len, + void *lout, int loff, int lincr, + void *rout, int roff, int rincr, + int (*block_render_func)(fluid_synth_t *, int) + ) +{ + void *channels_out[2] = {lout, rout}; + int channels_off[2] = {loff, roff }; + int channels_incr[2] = {lincr, rincr }; + + return fluid_synth_write_float_channels_LOCAL(synth, len, 2, channels_out, + channels_off, channels_incr, + block_render_func); +} + + +#define DITHER_SIZE 48000 +#define DITHER_CHANNELS 2 + +static float rand_table[DITHER_CHANNELS][DITHER_SIZE]; + +/* Init dither table */ +static void +init_dither(void) +{ + float d, dp; + int c, i; + + for(c = 0; c < DITHER_CHANNELS; c++) + { + dp = 0; + + for(i = 0; i < DITHER_SIZE - 1; i++) + { + d = rand() / (float)RAND_MAX - 0.5f; + rand_table[c][i] = d - dp; + dp = d; + } + + rand_table[c][DITHER_SIZE - 1] = 0 - dp; + } +} + +/* A portable replacement for roundf(), seems it may actually be faster too! */ +static FLUID_INLINE int16_t +round_clip_to_i16(float x) +{ + long i; + + if(x >= 0.0f) + { + i = (long)(x + 0.5f); + + if(FLUID_UNLIKELY(i > 32767)) + { + i = 32767; + } + } + else + { + i = (long)(x - 0.5f); + + if(FLUID_UNLIKELY(i < -32768)) + { + i = -32768; + } + } + + return (int16_t)i; +} + +/** + * Synthesize a block of 16 bit audio samples to audio buffers. + * @param synth FluidSynth instance + * @param len Count of audio frames to synthesize + * @param lout Array of 16 bit words to store left channel of audio + * @param loff Offset index in 'lout' for first sample + * @param lincr Increment between samples stored to 'lout' + * @param rout Array of 16 bit words to store right channel of audio + * @param roff Offset index in 'rout' for first sample + * @param rincr Increment between samples stored to 'rout' + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * + * Useful for storing interleaved stereo (lout = rout, loff = 0, roff = 1, + * lincr = 2, rincr = 2). + * + * @note Should only be called from synthesis thread. + * @note Reverb and Chorus are mixed to \c lout resp. \c rout. + * @note Dithering is performed when converting from internal floating point to + * 16 bit audio. + */ +int +fluid_synth_write_s16(fluid_synth_t *synth, int len, + void *lout, int loff, int lincr, + void *rout, int roff, int rincr) +{ + void *channels_out[2] = {lout, rout}; + int channels_off[2] = {loff, roff }; + int channels_incr[2] = {lincr, rincr }; + + return fluid_synth_write_s16_channels(synth, len, 2, channels_out, + channels_off, channels_incr); +} + +/** + * Synthesize a block of 16 bit audio samples channels to audio buffers. + * The function is convenient for audio driver to render multiple stereo + * channels pairs on multi channels audio cards (i.e 2, 4, 6, 8,.. channels). + * + * @param synth FluidSynth instance. + * @param len Count of audio frames to synthesize. + * @param channels_count Count of channels in a frame. + * must be multiple of 2 and channel_count/2 must not exceed the number + * of internal mixer buffers (synth->audio_groups) + * @param channels_out Array of channels_count pointers on 16 bit words to + * store sample channels. Modified on return. + * @param channels_off Array of channels_count offset index to add to respective pointer + * in channels_out for first sample. + * @param channels_incr Array of channels_count increment between consecutive + * samples channels. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + * + * Useful for storing: + * - interleaved channels in a unique buffer. + * - non interleaved channels in an unique buffer (or in distinct buffers). + * + * Example for interleaved 4 channels (c1, c2, c3, c4) and n samples (s1, s2,..sn) + * in a unique buffer: + * { s1:c1, s1:c2, s1:c3, s1:c4, s2:c1, s2:c2, s2:c3, s2:c4, .... + * sn:c1, sn:c2, sn:c3, sn:c4 }. + * + * @note Should only be called from synthesis thread. + * @note Reverb and Chorus are mixed to \c lout resp. \c rout. + * @note Dithering is performed when converting from internal floating point to + * 16 bit audio. + */ +int +fluid_synth_write_s16_channels(fluid_synth_t *synth, int len, + int channels_count, + void *channels_out[], int channels_off[], + int channels_incr[]) +{ + int16_t **chan_out = (int16_t **)channels_out; + int di, n, cur, size; + + /* pointers on first input mixer buffer */ + fluid_real_t *left_in; + fluid_real_t *right_in; + int bufs_in_count; /* number of stereo input buffers */ + int i; + + /* start average cpu load probe */ + double time = fluid_utime(); + float cpu_load; + + /* start profiling duration probe (if profiling is enabled) */ + fluid_profile_ref_var(prof_ref); + + /* check parameters */ + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + + fluid_return_val_if_fail(len >= 0, FLUID_FAILED); + fluid_return_val_if_fail(len != 0, FLUID_OK); // to avoid raising FE_DIVBYZERO below + + /* check for valid channel_count: must be multiple of 2 and + channel_count/2 must not exceed the number of internal mixer buffers + (synth->audio_groups) + */ + fluid_return_val_if_fail(!(channels_count & 1) /* must be multiple of 2 */ + && channels_count >= 2, FLUID_FAILED); + + bufs_in_count = (unsigned int)channels_count >> 1; /* channels_count/2 */ + fluid_return_val_if_fail(bufs_in_count <= synth->audio_groups, FLUID_FAILED); + + fluid_return_val_if_fail(channels_out != NULL, FLUID_FAILED); + fluid_return_val_if_fail(channels_off != NULL, FLUID_FAILED); + fluid_return_val_if_fail(channels_incr != NULL, FLUID_FAILED); + + /* initialize output channels buffers on first sample position */ + i = channels_count; + do + { + i--; + chan_out[i] += channels_off[i]; + } + while(i); + + /* Conversely to fluid_synth_process(), + we want rendered audio effect mixed in internal audio dry buffers. + TRUE instructs the mixer that internal audio effects will be mixed in internal + audio dry buffers. + */ + fluid_rvoice_mixer_set_mix_fx(synth->eventhandler->mixer, TRUE); + /* get first internal mixer audio dry buffer's pointer (left and right channel) */ + fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in); + + size = len; + /* synth->cur indicates if available samples are still in internal mixer buffer */ + cur = synth->cur; /* get previous sample position in internal buffer (due to prvious call) */ + di = synth->dither_index; + + do + { + /* fill up the buffers as needed */ + if(cur >= synth->curmax) + { + /* render audio (dry and effect) to internal dry buffers */ + /* always render full blocs multiple of FLUID_BUFSIZE */ + int blocksleft = (size + FLUID_BUFSIZE - 1) / FLUID_BUFSIZE; + synth->curmax = FLUID_BUFSIZE * fluid_synth_render_blocks(synth, blocksleft); + + /* get first internal mixer audio dry buffer's pointer (left and right channel) */ + fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in); + cur = 0; + } + + /* calculate amount of available samples */ + n = synth->curmax - cur; + + /* keep track of emitted samples */ + if(n > size) + { + n = size; + } + + size -= n; + + /* update pointers to current position */ + left_in += cur + n; + right_in += cur + n; + + /* set final cursor position */ + cur += n; + + /* reverse index */ + n = 0 - n; + + do + { + i = bufs_in_count; + do + { + /* input sample index in stereo buffer i */ + int in_idx = --i * FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT + n; + int c = i << 1; /* channel index c to write */ + + /* write left input sample to channel sample */ + *chan_out[c] = round_clip_to_i16(left_in[in_idx] * 32766.0f + + rand_table[0][di]); + + /* write right input sample to next channel sample */ + *chan_out[c+1] = round_clip_to_i16(right_in[in_idx] * 32766.0f + + rand_table[1][di]); + /* advance output pointers */ + chan_out[c] += channels_incr[c]; + chan_out[c+1] += channels_incr[c+1]; + } + while(i); + + if(++di >= DITHER_SIZE) + { + di = 0; + } + } + while(++n < 0); + } + while(size); + + synth->cur = cur; /* save current sample position. It will be used on next call */ + synth->dither_index = di; /* keep dither buffer continuous */ + + /* save average cpu load, used by API for real time cpu load meter */ + time = fluid_utime() - time; + cpu_load = 0.5 * (fluid_atomic_float_get(&synth->cpu_load) + time * synth->sample_rate / len / 10000.0); + fluid_atomic_float_set(&synth->cpu_load, cpu_load); + + /* stop duration probe and save performance measurement (if profiling is enabled) */ + fluid_profile_write(FLUID_PROF_WRITE, prof_ref, + fluid_rvoice_mixer_get_active_voices(synth->eventhandler->mixer), + len); + return FLUID_OK; +} + +/** + * Converts stereo floating point sample data to signed 16 bit data with dithering. + * @param dither_index Pointer to an integer which should be initialized to 0 + * before the first call and passed unmodified to additional calls which are + * part of the same synthesis output. + * @param len Length in frames to convert + * @param lin Buffer of left audio samples to convert from + * @param rin Buffer of right audio samples to convert from + * @param lout Array of 16 bit words to store left channel of audio + * @param loff Offset index in 'lout' for first sample + * @param lincr Increment between samples stored to 'lout' + * @param rout Array of 16 bit words to store right channel of audio + * @param roff Offset index in 'rout' for first sample + * @param rincr Increment between samples stored to 'rout' + * + * @note Currently private to libfluidsynth. + */ +void +fluid_synth_dither_s16(int *dither_index, int len, const float *lin, const float *rin, + void *lout, int loff, int lincr, + void *rout, int roff, int rincr) +{ + int i, j, k; + int16_t *left_out = lout; + int16_t *right_out = rout; + int di = *dither_index; + fluid_profile_ref_var(prof_ref); + + for(i = 0, j = loff, k = roff; i < len; i++, j += lincr, k += rincr) + { + left_out[j] = round_clip_to_i16(lin[i] * 32766.0f + rand_table[0][di]); + right_out[k] = round_clip_to_i16(rin[i] * 32766.0f + rand_table[1][di]); + + if(++di >= DITHER_SIZE) + { + di = 0; + } + } + + *dither_index = di; /* keep dither buffer continuous */ + + fluid_profile(FLUID_PROF_WRITE, prof_ref, 0, len); +} + +static void +fluid_synth_check_finished_voices(fluid_synth_t *synth) +{ + int j; + fluid_rvoice_t *fv; + + while(NULL != (fv = fluid_rvoice_eventhandler_get_finished_voice(synth->eventhandler))) + { + for(j = 0; j < synth->polyphony; j++) + { + if(synth->voice[j]->rvoice == fv) + { + fluid_voice_unlock_rvoice(synth->voice[j]); + fluid_voice_stop(synth->voice[j]); + break; + } + else if(synth->voice[j]->overflow_rvoice == fv) + { + /* Unlock the overflow_rvoice of the voice. + Decrement the reference count of the sample owned by this + rvoice. + */ + fluid_voice_overflow_rvoice_finished(synth->voice[j]); + + /* Decrement synth active voice count. Must not be incorporated + in fluid_voice_overflow_rvoice_finished() because + fluid_voice_overflow_rvoice_finished() is called also + at synth destruction and in this case the variable should be + accessed via voice->channel->synth->active_voice_count. + And for certain voices which are not playing, the field + voice->channel is NULL. + */ + synth->active_voice_count--; + break; + } + } + } +} + +/** + * Process all waiting events in the rvoice queue. + * Make sure no (other) rendering is running in parallel when + * you call this function! + */ +void fluid_synth_process_event_queue(fluid_synth_t *synth) +{ + fluid_rvoice_eventhandler_dispatch_all(synth->eventhandler); +} + + +/** + * Process blocks (FLUID_BUFSIZE) of audio. + * Must be called from renderer thread only! + * @return number of blocks rendered. Might (often) return less than requested + */ +static int +fluid_synth_render_blocks(fluid_synth_t *synth, int blockcount) +{ + int i, maxblocks; + fluid_profile_ref_var(prof_ref); + + /* Assign ID of synthesis thread */ +// synth->synth_thread_id = fluid_thread_get_id (); + + fluid_check_fpe("??? Just starting up ???"); + + fluid_rvoice_eventhandler_dispatch_all(synth->eventhandler); + + /* do not render more blocks than we can store internally */ + maxblocks = fluid_rvoice_mixer_get_bufcount(synth->eventhandler->mixer); + + if(blockcount > maxblocks) + { + blockcount = maxblocks; + } + + for(i = 0; i < blockcount; i++) + { + fluid_sample_timer_process(synth); + fluid_synth_add_ticks(synth, FLUID_BUFSIZE); + + /* If events have been queued waiting for fluid_rvoice_eventhandler_dispatch_all() + * (should only happen with parallel render) stop processing and go for rendering + */ + if(fluid_rvoice_eventhandler_dispatch_count(synth->eventhandler)) + { + // Something has happened, we can't process more + blockcount = i + 1; + break; + } + } + + fluid_check_fpe("fluid_sample_timer_process"); + + blockcount = fluid_rvoice_mixer_render(synth->eventhandler->mixer, blockcount); + + /* Testcase, that provokes a denormal floating point error */ +#if 0 + { + float num = 1; + + while(num != 0) + { + num *= 0.5; + }; + }; +#endif + fluid_check_fpe("??? Remainder of synth_one_block ???"); + fluid_profile(FLUID_PROF_ONE_BLOCK, prof_ref, + fluid_rvoice_mixer_get_active_voices(synth->eventhandler->mixer), + blockcount * FLUID_BUFSIZE); + return blockcount; +} + +/* + * Handler for synth.reverb.* and synth.chorus.* double settings. + */ +static void fluid_synth_handle_reverb_chorus_num(void *data, const char *name, double value) +{ + fluid_synth_t *synth = (fluid_synth_t *)data; + fluid_return_if_fail(synth != NULL); + + if(FLUID_STRCMP(name, "synth.reverb.room-size") == 0) + { + fluid_synth_reverb_set_param(synth, -1, FLUID_REVERB_ROOMSIZE, value); + } + else if(FLUID_STRCMP(name, "synth.reverb.damp") == 0) + { + fluid_synth_reverb_set_param(synth, -1, FLUID_REVERB_DAMP, value); + } + else if(FLUID_STRCMP(name, "synth.reverb.width") == 0) + { + fluid_synth_reverb_set_param(synth, -1, FLUID_REVERB_WIDTH, value); + } + else if(FLUID_STRCMP(name, "synth.reverb.level") == 0) + { + fluid_synth_reverb_set_param(synth, -1, FLUID_REVERB_LEVEL, value); + } + else if(FLUID_STRCMP(name, "synth.chorus.depth") == 0) + { + fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_DEPTH, value); + } + else if(FLUID_STRCMP(name, "synth.chorus.speed") == 0) + { + fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_SPEED, value); + } + else if(FLUID_STRCMP(name, "synth.chorus.level") == 0) + { + fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_LEVEL, value); + } +} + +/* + * Handler for synth.reverb.* and synth.chorus.* integer settings. + */ +static void fluid_synth_handle_reverb_chorus_int(void *data, const char *name, int value) +{ + fluid_synth_t *synth = (fluid_synth_t *)data; + fluid_return_if_fail(synth != NULL); + + if(FLUID_STRCMP(name, "synth.reverb.active") == 0) + { + fluid_synth_reverb_on(synth, -1, value); + } + else if(FLUID_STRCMP(name, "synth.chorus.active") == 0) + { + fluid_synth_chorus_on(synth, -1, value); + } + else if(FLUID_STRCMP(name, "synth.chorus.nr") == 0) + { + fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_NR, (double)value); + } +} + +/* + * Handler for synth.overflow.* settings. + */ +static void fluid_synth_handle_overflow(void *data, const char *name, double value) +{ + fluid_synth_t *synth = (fluid_synth_t *)data; + fluid_return_if_fail(synth != NULL); + + fluid_synth_api_enter(synth); + + if(FLUID_STRCMP(name, "synth.overflow.percussion") == 0) + { + synth->overflow.percussion = value; + } + else if(FLUID_STRCMP(name, "synth.overflow.released") == 0) + { + synth->overflow.released = value; + } + else if(FLUID_STRCMP(name, "synth.overflow.sustained") == 0) + { + synth->overflow.sustained = value; + } + else if(FLUID_STRCMP(name, "synth.overflow.volume") == 0) + { + synth->overflow.volume = value; + } + else if(FLUID_STRCMP(name, "synth.overflow.age") == 0) + { + synth->overflow.age = value; + } + else if(FLUID_STRCMP(name, "synth.overflow.important") == 0) + { + synth->overflow.important = value; + } + + fluid_synth_api_exit(synth); +} + +/* Selects a voice for killing. */ +static fluid_voice_t * +fluid_synth_free_voice_by_kill_LOCAL(fluid_synth_t *synth) +{ + int i; + float best_prio = OVERFLOW_PRIO_CANNOT_KILL - 1; + float this_voice_prio; + fluid_voice_t *voice; + int best_voice_index = -1; + unsigned int ticks = fluid_synth_get_ticks(synth); + + for(i = 0; i < synth->polyphony; i++) + { + + voice = synth->voice[i]; + + /* safeguard against an available voice. */ + if(_AVAILABLE(voice)) + { + return voice; + } + + this_voice_prio = fluid_voice_get_overflow_prio(voice, &synth->overflow, + ticks); + + /* check if this voice has less priority than the previous candidate. */ + if(this_voice_prio < best_prio) + { + best_voice_index = i; + best_prio = this_voice_prio; + } + } + + if(best_voice_index < 0) + { + return NULL; + } + + voice = synth->voice[best_voice_index]; + FLUID_LOG(FLUID_DBG, "Killing voice %d, index %d, chan %d, key %d ", + fluid_voice_get_id(voice), best_voice_index, fluid_voice_get_channel(voice), fluid_voice_get_key(voice)); + fluid_voice_off(voice); + + return voice; +} + + +/** + * Allocate a synthesis voice. + * @param synth FluidSynth instance + * @param sample Sample to assign to the voice + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param key MIDI note number for the voice (0-127) + * @param vel MIDI velocity for the voice (0-127) + * @return Allocated synthesis voice or NULL on error + * + * This function is called by a SoundFont's preset in response to a noteon event. + * The returned voice comes with default modulators and generators. + * A single noteon event may create any number of voices, when the preset is layered. + * + * @note Should only be called from within synthesis thread, which includes + * SoundFont loader preset noteon method. + */ +fluid_voice_t * +fluid_synth_alloc_voice(fluid_synth_t *synth, fluid_sample_t *sample, + int chan, int key, int vel) +{ + fluid_return_val_if_fail(sample != NULL, NULL); + fluid_return_val_if_fail(sample->data != NULL, NULL); + FLUID_API_ENTRY_CHAN(NULL); + FLUID_API_RETURN(fluid_synth_alloc_voice_LOCAL(synth, sample, chan, key, vel, NULL)); + +} + +fluid_voice_t * +fluid_synth_alloc_voice_LOCAL(fluid_synth_t *synth, fluid_sample_t *sample, int chan, int key, int vel, fluid_zone_range_t *zone_range) +{ + int i, k; + fluid_voice_t *voice = NULL; + fluid_channel_t *channel = NULL; + unsigned int ticks; + + /* check if there's an available synthesis process */ + for(i = 0; i < synth->polyphony; i++) + { + if(_AVAILABLE(synth->voice[i])) + { + voice = synth->voice[i]; + break; + } + } + + /* No success yet? Then stop a running voice. */ + if(voice == NULL) + { + FLUID_LOG(FLUID_DBG, "Polyphony exceeded, trying to kill a voice"); + voice = fluid_synth_free_voice_by_kill_LOCAL(synth); + } + + if(voice == NULL) + { + FLUID_LOG(FLUID_WARN, "Failed to allocate a synthesis process. (chan=%d,key=%d)", chan, key); + return NULL; + } + + ticks = fluid_synth_get_ticks(synth); + + if(synth->verbose) + { + k = 0; + + for(i = 0; i < synth->polyphony; i++) + { + if(!_AVAILABLE(synth->voice[i])) + { + k++; + } + } + + FLUID_LOG(FLUID_INFO, "noteon\t%d\t%d\t%d\t%05d\t%.3f\t%.3f\t%.3f\t%d", + chan, key, vel, synth->storeid, + (float) ticks / 44100.0f, + (fluid_curtime() - synth->start) / 1000.0f, + 0.0f, + k); + } + + channel = synth->channel[chan]; + + if(fluid_voice_init(voice, sample, zone_range, channel, key, vel, + synth->storeid, ticks, synth->gain) != FLUID_OK) + { + FLUID_LOG(FLUID_WARN, "Failed to initialize voice"); + return NULL; + } + + /* add the default modulators to the synthesis process. */ + /* custom_breath2att_modulator is not a default modulator specified in SF + it is intended to replace default_vel2att_mod for this channel on demand using + API fluid_synth_set_breath_mode() or shell command setbreathmode for this channel. + */ + { + int mono = fluid_channel_is_playing_mono(channel); + fluid_mod_t *default_mod = synth->default_mod; + + while(default_mod != NULL) + { + if( + /* See if default_mod is the velocity_to_attenuation modulator */ + fluid_mod_test_identity(default_mod, &default_vel2att_mod) && + // See if a replacement by custom_breath2att_modulator has been demanded + // for this channel + ((!mono && (channel->mode & FLUID_CHANNEL_BREATH_POLY)) || + (mono && (channel->mode & FLUID_CHANNEL_BREATH_MONO))) + ) + { + // Replacement of default_vel2att modulator by custom_breath2att_modulator + fluid_voice_add_mod_local(voice, &custom_breath2att_mod, FLUID_VOICE_DEFAULT, 0); + } + else + { + fluid_voice_add_mod_local(voice, default_mod, FLUID_VOICE_DEFAULT, 0); + } + + // Next default modulator to add to the voice + default_mod = default_mod->next; + } + } + + return voice; +} + +/* Kill all voices on a given channel, which have the same exclusive class + * generator as new_voice. + */ +static void +fluid_synth_kill_by_exclusive_class_LOCAL(fluid_synth_t *synth, + fluid_voice_t *new_voice) +{ + int excl_class = fluid_voice_gen_value(new_voice, GEN_EXCLUSIVECLASS); + int i; + + /* Excl. class 0: No exclusive class */ + if(excl_class == 0) + { + return; + } + + /* Kill all notes on the same channel with the same exclusive class */ + for(i = 0; i < synth->polyphony; i++) + { + fluid_voice_t *existing_voice = synth->voice[i]; + + /* If voice is playing, on the same channel, has same exclusive + * class and is not part of the same noteon event (voice group), then kill it */ + + if(fluid_voice_is_playing(existing_voice) + && fluid_voice_get_channel(existing_voice) == fluid_voice_get_channel(new_voice) + && fluid_voice_gen_value(existing_voice, GEN_EXCLUSIVECLASS) == excl_class + && fluid_voice_get_id(existing_voice) != fluid_voice_get_id(new_voice)) + { + fluid_voice_kill_excl(existing_voice); + } + } +} + +/** + * Activate a voice previously allocated with fluid_synth_alloc_voice(). + * @param synth FluidSynth instance + * @param voice Voice to activate + * + * This function is called by a SoundFont's preset in response to a noteon + * event. Exclusive classes are processed here. + * + * @note Should only be called from within synthesis thread, which includes + * SoundFont loader preset noteon method. + */ +void +fluid_synth_start_voice(fluid_synth_t *synth, fluid_voice_t *voice) +{ + fluid_return_if_fail(synth != NULL); + fluid_return_if_fail(voice != NULL); +// fluid_return_if_fail (fluid_synth_is_synth_thread (synth)); + fluid_synth_api_enter(synth); + + /* Find the exclusive class of this voice. If set, kill all voices + * that match the exclusive class and are younger than the first + * voice process created by this noteon event. */ + fluid_synth_kill_by_exclusive_class_LOCAL(synth, voice); + + fluid_voice_start(voice); /* Start the new voice */ + fluid_voice_lock_rvoice(voice); + fluid_rvoice_eventhandler_add_rvoice(synth->eventhandler, voice->rvoice); + fluid_synth_api_exit(synth); +} + +/** + * Add a SoundFont loader to the synth. This function takes ownership of \c loader + * and frees it automatically upon \c synth destruction. + * @param synth FluidSynth instance + * @param loader Loader API structure + * + * SoundFont loaders are used to add custom instrument loading to FluidSynth. + * The caller supplied functions for loading files, allocating presets, + * retrieving information on them and synthesizing note-on events. Using this + * method even non SoundFont instruments can be synthesized, although limited + * to the SoundFont synthesis model. + * + * @note Should only be called before any SoundFont files are loaded. + */ +void +fluid_synth_add_sfloader(fluid_synth_t *synth, fluid_sfloader_t *loader) +{ + fluid_return_if_fail(synth != NULL); + fluid_return_if_fail(loader != NULL); + fluid_synth_api_enter(synth); + + /* Test if sfont is already loaded */ + if(synth->sfont == NULL) + { + synth->loaders = fluid_list_prepend(synth->loaders, loader); + } + + fluid_synth_api_exit(synth); +} + +/** + * Load a SoundFont file (filename is interpreted by SoundFont loaders). + * The newly loaded SoundFont will be put on top of the SoundFont + * stack. Presets are searched starting from the SoundFont on the + * top of the stack, working the way down the stack until a preset is found. + * + * @param synth FluidSynth instance + * @param filename File to load + * @param reset_presets TRUE to re-assign presets for all MIDI channels (equivalent to calling fluid_synth_program_reset()) + * @return SoundFont ID on success, #FLUID_FAILED on error + * + * @note Since FluidSynth 2.2.0 @c filename is treated as an UTF8 encoded string on Windows. FluidSynth will convert it + * to wide-char internally and then pass it to _wfopen(). Before FluidSynth 2.2.0, @c filename was treated as ANSI string + * on Windows. All other platforms directly pass it to fopen() without any conversion (usually, UTF8 is accepted). + */ +int +fluid_synth_sfload(fluid_synth_t *synth, const char *filename, int reset_presets) +{ + fluid_sfont_t *sfont; + fluid_list_t *list; + fluid_sfloader_t *loader; + int sfont_id; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail(filename != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + + sfont_id = synth->sfont_id; + + if(++sfont_id != FLUID_FAILED) + { + /* MT NOTE: Loaders list should not change. */ + + for(list = synth->loaders; list; list = fluid_list_next(list)) + { + loader = (fluid_sfloader_t *) fluid_list_get(list); + + sfont = fluid_sfloader_load(loader, filename); + + if(sfont != NULL) + { + sfont->refcount++; + synth->sfont_id = sfont->id = sfont_id; + + synth->sfont = fluid_list_prepend(synth->sfont, sfont); /* prepend to list */ + + /* reset the presets for all channels if requested */ + if(reset_presets) + { + fluid_synth_program_reset(synth); + } + + FLUID_API_RETURN(sfont_id); + } + } + } + + FLUID_LOG(FLUID_ERR, "Failed to load SoundFont \"%s\"", filename); + FLUID_API_RETURN(FLUID_FAILED); +} + +/** + * Schedule a SoundFont for unloading. + * + * If the SoundFont isn't used anymore by any playing voices, it will be unloaded immediately. + * + * If any samples of the given SoundFont are still required by active voices, + * the SoundFont will be unloaded in a lazy manner, once those voices have finished synthesizing. + * If you call delete_fluid_synth(), all voices will be destroyed and the SoundFont + * will be unloaded in any case. + * Once this function returned, fluid_synth_sfcount() and similar functions will behave as if + * the SoundFont has already been unloaded, even though the lazy-unloading is still pending. + * + * @note This lazy-unloading mechanism was broken between FluidSynth 1.1.4 and 2.1.5 . As a + * consequence, SoundFonts scheduled for lazy-unloading may be never freed under certain + * conditions. Calling delete_fluid_synth() does not recover this situation either. + * + * @param synth FluidSynth instance + * @param id ID of SoundFont to unload + * @param reset_presets TRUE to re-assign presets for all MIDI channels + * @return #FLUID_OK if the given @p id was found, #FLUID_FAILED otherwise. + */ +int +fluid_synth_sfunload(fluid_synth_t *synth, int id, int reset_presets) +{ + fluid_sfont_t *sfont = NULL; + fluid_list_t *list; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + + /* remove the SoundFont from the list */ + for(list = synth->sfont; list; list = fluid_list_next(list)) + { + sfont = fluid_list_get(list); + + if(fluid_sfont_get_id(sfont) == id) + { + synth->sfont = fluid_list_remove(synth->sfont, sfont); + break; + } + } + + if(!list) + { + FLUID_LOG(FLUID_ERR, "No SoundFont with id = %d", id); + FLUID_API_RETURN(FLUID_FAILED); + } + + /* reset the presets for all channels (SoundFont will be freed when there are no more references) */ + if(reset_presets) + { + fluid_synth_program_reset(synth); + } + else + { + fluid_synth_update_presets(synth); + } + + /* -- Remove synth->sfont list's reference to SoundFont */ + fluid_synth_sfont_unref(synth, sfont); + + FLUID_API_RETURN(FLUID_OK); +} + +/* Unref a SoundFont and destroy if no more references */ +void +fluid_synth_sfont_unref(fluid_synth_t *synth, fluid_sfont_t *sfont) +{ + fluid_return_if_fail(sfont != NULL); /* Shouldn't happen, programming error if so */ + + sfont->refcount--; /* -- Remove the sfont list's reference */ + + if(sfont->refcount == 0) /* No more references? - Attempt delete */ + { + if(fluid_sfont_delete_internal(sfont) == 0) /* SoundFont loader can block SoundFont unload */ + { + FLUID_LOG(FLUID_DBG, "Unloaded SoundFont"); + } /* spin off a timer thread to unload the sfont later (SoundFont loader blocked unload) */ + else + { + fluid_timer_t* timer = new_fluid_timer(100, fluid_synth_sfunload_callback, sfont, TRUE, FALSE, FALSE); + synth->fonts_to_be_unloaded = fluid_list_prepend(synth->fonts_to_be_unloaded, timer); + } + } +} + +/* Callback to continually attempt to unload a SoundFont, + * only if a SoundFont loader blocked the unload operation */ +static int +fluid_synth_sfunload_callback(void *data, unsigned int msec) +{ + fluid_sfont_t *sfont = data; + + if(fluid_sfont_delete_internal(sfont) == 0) + { + FLUID_LOG(FLUID_DBG, "Unloaded SoundFont"); + return FALSE; + } + else + { + return TRUE; + } +} + +/** + * Reload a SoundFont. The SoundFont retains its ID and index on the SoundFont stack. + * @param synth FluidSynth instance + * @param id ID of SoundFont to reload + * @return SoundFont ID on success, #FLUID_FAILED on error + */ +int +fluid_synth_sfreload(fluid_synth_t *synth, int id) +{ + char *filename = NULL; + fluid_sfont_t *sfont; + fluid_sfloader_t *loader; + fluid_list_t *list; + int index, ret = FLUID_FAILED; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + + /* Search for SoundFont and get its index */ + for(list = synth->sfont, index = 0; list; list = fluid_list_next(list), index++) + { + sfont = fluid_list_get(list); + + if(fluid_sfont_get_id(sfont) == id) + { + break; + } + } + + if(!list) + { + FLUID_LOG(FLUID_ERR, "No SoundFont with id = %d", id); + goto exit; + } + + /* keep a copy of the SoundFont's filename */ + filename = FLUID_STRDUP(fluid_sfont_get_name(sfont)); + + if(filename == NULL || fluid_synth_sfunload(synth, id, FALSE) != FLUID_OK) + { + goto exit; + } + + /* MT Note: SoundFont loader list will not change */ + + for(list = synth->loaders; list; list = fluid_list_next(list)) + { + loader = (fluid_sfloader_t *) fluid_list_get(list); + + sfont = fluid_sfloader_load(loader, filename); + + if(sfont != NULL) + { + sfont->id = id; + sfont->refcount++; + + synth->sfont = fluid_list_insert_at(synth->sfont, index, sfont); /* insert the sfont at the same index */ + + /* reset the presets for all channels */ + fluid_synth_update_presets(synth); + ret = id; + goto exit; + } + } + + FLUID_LOG(FLUID_ERR, "Failed to load SoundFont \"%s\"", filename); + +exit: + FLUID_FREE(filename); + FLUID_API_RETURN(ret); +} + +/** + * Add a SoundFont. The SoundFont will be added to the top of the SoundFont stack and ownership is transferred to @p synth. + * @param synth FluidSynth instance + * @param sfont SoundFont to add + * @return New assigned SoundFont ID or #FLUID_FAILED on error + */ +int +fluid_synth_add_sfont(fluid_synth_t *synth, fluid_sfont_t *sfont) +{ + int sfont_id; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail(sfont != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + + sfont_id = synth->sfont_id; + + if(++sfont_id != FLUID_FAILED) + { + synth->sfont_id = sfont->id = sfont_id; + synth->sfont = fluid_list_prepend(synth->sfont, sfont); /* prepend to list */ + + /* reset the presets for all channels */ + fluid_synth_program_reset(synth); + } + + FLUID_API_RETURN(sfont_id); +} + +/** + * Remove a SoundFont from the SoundFont stack without deleting it. + * @param synth FluidSynth instance + * @param sfont SoundFont to remove + * @return #FLUID_OK if \c sfont successfully removed, #FLUID_FAILED otherwise + * + * SoundFont is not freed and is left as the responsibility of the caller. + * + * @note The SoundFont should only be freed after there are no presets + * referencing it. This can only be ensured by the SoundFont loader and + * therefore this function should not normally be used. + */ +int +fluid_synth_remove_sfont(fluid_synth_t *synth, fluid_sfont_t *sfont) +{ + fluid_sfont_t *sfont_tmp; + fluid_list_t *list; + int ret = FLUID_FAILED; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail(sfont != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + + /* remove the SoundFont from the list */ + for(list = synth->sfont; list; list = fluid_list_next(list)) + { + sfont_tmp = fluid_list_get(list); + + if(sfont_tmp == sfont) + { + synth->sfont = fluid_list_remove(synth->sfont, sfont_tmp); + ret = FLUID_OK; + break; + } + } + + /* reset the presets for all channels */ + fluid_synth_program_reset(synth); + + FLUID_API_RETURN(ret); +} + +/** + * Count number of loaded SoundFont files. + * @param synth FluidSynth instance + * @return Count of loaded SoundFont files. + */ +int +fluid_synth_sfcount(fluid_synth_t *synth) +{ + int count; + + fluid_return_val_if_fail(synth != NULL, 0); + fluid_synth_api_enter(synth); + count = fluid_list_size(synth->sfont); + FLUID_API_RETURN(count); +} + +/** + * Get SoundFont by index. + * @param synth FluidSynth instance + * @param num SoundFont index on the stack (starting from 0 for top of stack). + * @return SoundFont instance or NULL if invalid index + * + * @note Caller should be certain that SoundFont is not deleted (unloaded) for + * the duration of use of the returned pointer. + */ +fluid_sfont_t * +fluid_synth_get_sfont(fluid_synth_t *synth, unsigned int num) +{ + fluid_sfont_t *sfont = NULL; + fluid_list_t *list; + + fluid_return_val_if_fail(synth != NULL, NULL); + fluid_synth_api_enter(synth); + list = fluid_list_nth(synth->sfont, num); + + if(list) + { + sfont = fluid_list_get(list); + } + + FLUID_API_RETURN(sfont); +} + +/** + * Get SoundFont by ID. + * @param synth FluidSynth instance + * @param id SoundFont ID + * @return SoundFont instance or NULL if invalid ID + * + * @note Caller should be certain that SoundFont is not deleted (unloaded) for + * the duration of use of the returned pointer. + */ +fluid_sfont_t * +fluid_synth_get_sfont_by_id(fluid_synth_t *synth, int id) +{ + fluid_sfont_t *sfont = NULL; + fluid_list_t *list; + + fluid_return_val_if_fail(synth != NULL, NULL); + fluid_synth_api_enter(synth); + + for(list = synth->sfont; list; list = fluid_list_next(list)) + { + sfont = fluid_list_get(list); + + if(fluid_sfont_get_id(sfont) == id) + { + break; + } + } + + FLUID_API_RETURN(list ? sfont : NULL); +} + +/** + * Get SoundFont by name. + * @param synth FluidSynth instance + * @param name Name of SoundFont + * @return SoundFont instance or NULL if invalid name + * @since 1.1.0 + * + * @note Caller should be certain that SoundFont is not deleted (unloaded) for + * the duration of use of the returned pointer. + */ +fluid_sfont_t * +fluid_synth_get_sfont_by_name(fluid_synth_t *synth, const char *name) +{ + fluid_sfont_t *sfont = NULL; + fluid_list_t *list; + + fluid_return_val_if_fail(synth != NULL, NULL); + fluid_return_val_if_fail(name != NULL, NULL); + fluid_synth_api_enter(synth); + + for(list = synth->sfont; list; list = fluid_list_next(list)) + { + sfont = fluid_list_get(list); + + if(FLUID_STRCMP(fluid_sfont_get_name(sfont), name) == 0) + { + break; + } + } + + FLUID_API_RETURN(list ? sfont : NULL); +} + +/** + * Get active preset on a MIDI channel. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @return Preset or NULL if no preset active on \c chan + * + * @note Should only be called from within synthesis thread, which includes + * SoundFont loader preset noteon methods. Not thread safe otherwise. + */ +fluid_preset_t * +fluid_synth_get_channel_preset(fluid_synth_t *synth, int chan) +{ + fluid_preset_t *result; + fluid_channel_t *channel; + FLUID_API_ENTRY_CHAN(NULL); + + channel = synth->channel[chan]; + result = channel->preset; + fluid_synth_api_exit(synth); + return result; +} + +/** + * Get list of currently playing voices. + * @param synth FluidSynth instance + * @param buf Array to store voices to (NULL terminated if not filled completely) + * @param bufsize Count of indexes in buf + * @param id Voice ID to search for or < 0 to return list of all playing voices + * + * @note Should only be called from within synthesis thread, which includes + * SoundFont loader preset noteon methods. Voices are only guaranteed to remain + * unchanged until next synthesis process iteration. + */ +void +fluid_synth_get_voicelist(fluid_synth_t *synth, fluid_voice_t *buf[], int bufsize, + int id) +{ + int count = 0; + int i; + + fluid_return_if_fail(synth != NULL); + fluid_return_if_fail(buf != NULL); + fluid_synth_api_enter(synth); + + for(i = 0; i < synth->polyphony && count < bufsize; i++) + { + fluid_voice_t *voice = synth->voice[i]; + + if(fluid_voice_is_playing(voice) && (id < 0 || (int)voice->id == id)) + { + buf[count++] = voice; + } + } + + if(count < bufsize) + { + buf[count] = NULL; + } + + fluid_synth_api_exit(synth); +} + +/** + * Enable or disable reverb effect. + * @param synth FluidSynth instance + * @param on TRUE to enable chorus, FALSE to disable + * @deprecated Use fluid_synth_reverb_on() instead. + */ +void +fluid_synth_set_reverb_on(fluid_synth_t *synth, int on) +{ + fluid_return_if_fail(synth != NULL); + fluid_synth_api_enter(synth); + + synth->with_reverb = (on != 0); + fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_reverb_enabled, + on != 0, 0.0f); + fluid_synth_api_exit(synth); +} + +/** + * Enable or disable reverb on one fx group unit. + * @param synth FluidSynth instance + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all fx groups. + * @param on TRUE to enable reverb, FALSE to disable + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_reverb_on(fluid_synth_t *synth, int fx_group, int on) +{ + int ret; + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + + fluid_synth_api_enter(synth); + + if(fx_group < -1 || fx_group >= synth->effects_groups) + { + FLUID_API_RETURN(FLUID_FAILED); + } + + if(fx_group < 0 ) + { + synth->with_reverb = (on != 0); + } + + param[0].i = fx_group; + param[1].i = on; + ret = fluid_rvoice_eventhandler_push(synth->eventhandler, + fluid_rvoice_mixer_reverb_enable, + synth->eventhandler->mixer, + param); + + FLUID_API_RETURN(ret); +} + +/** + * Activate a reverb preset. + * @param synth FluidSynth instance + * @param num Reverb preset number + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * + * @note Currently private to libfluidsynth. + */ +int +fluid_synth_set_reverb_preset(fluid_synth_t *synth, unsigned int num) +{ + double values[FLUID_REVERB_PARAM_LAST]; + + fluid_return_val_if_fail( + num < FLUID_N_ELEMENTS(revmodel_preset), + FLUID_FAILED + ); + + values[FLUID_REVERB_ROOMSIZE] = revmodel_preset[num].roomsize; + values[FLUID_REVERB_DAMP] = revmodel_preset[num].damp; + values[FLUID_REVERB_WIDTH] = revmodel_preset[num].width; + values[FLUID_REVERB_LEVEL] = revmodel_preset[num].level; + fluid_synth_set_reverb_full(synth, -1, FLUID_REVMODEL_SET_ALL, values); + return FLUID_OK; +} + +/** + * Set reverb parameters to all groups. + * + * @param synth FluidSynth instance + * @param roomsize Reverb room size value (0.0-1.0) + * @param damping Reverb damping value (0.0-1.0) + * @param width Reverb width value (0.0-100.0) + * @param level Reverb level value (0.0-1.0) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use the individual reverb setter functions in new code instead. + */ +int +fluid_synth_set_reverb(fluid_synth_t *synth, double roomsize, double damping, + double width, double level) +{ + double values[FLUID_REVERB_PARAM_LAST]; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + + values[FLUID_REVERB_ROOMSIZE] = roomsize; + values[FLUID_REVERB_DAMP] = damping; + values[FLUID_REVERB_WIDTH] = width; + values[FLUID_REVERB_LEVEL] = level; + return fluid_synth_set_reverb_full(synth, -1, FLUID_REVMODEL_SET_ALL, values); +} + +/** + * Set reverb roomsize of all groups. + * + * @param synth FluidSynth instance + * @param roomsize Reverb room size value (0.0-1.0) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_reverb_group_roomsize() in new code instead. + */ +int fluid_synth_set_reverb_roomsize(fluid_synth_t *synth, double roomsize) +{ + return fluid_synth_reverb_set_param(synth, -1, FLUID_REVERB_ROOMSIZE, roomsize); +} + +/** + * Set reverb damping of all groups. + * + * @param synth FluidSynth instance + * @param damping Reverb damping value (0.0-1.0) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_reverb_group_damp() in new code instead. + */ +int fluid_synth_set_reverb_damp(fluid_synth_t *synth, double damping) +{ + return fluid_synth_reverb_set_param(synth, -1, FLUID_REVERB_DAMP, damping); +} + +/** + * Set reverb width of all groups. + * + * @param synth FluidSynth instance + * @param width Reverb width value (0.0-100.0) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_reverb_group_width() in new code instead. + */ +int fluid_synth_set_reverb_width(fluid_synth_t *synth, double width) +{ + return fluid_synth_reverb_set_param(synth, -1, FLUID_REVERB_WIDTH, width); +} + +/** + * Set reverb level of all groups. + * + * @param synth FluidSynth instance + * @param level Reverb level value (0.0-1.0) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_reverb_group_level() in new code instead. + */ +int fluid_synth_set_reverb_level(fluid_synth_t *synth, double level) +{ + return fluid_synth_reverb_set_param(synth, -1, FLUID_REVERB_LEVEL, level); +} + +/** + * Set reverb roomsize to one or all fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all fx groups. + * @param roomsize roomsize value to set. Must be in the range indicated by + * synth.reverb.room-size setting. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int fluid_synth_set_reverb_group_roomsize(fluid_synth_t *synth, int fx_group, + double roomsize) +{ + return fluid_synth_reverb_set_param(synth, fx_group, FLUID_REVERB_ROOMSIZE, roomsize); +} + +/** + * Set reverb damp to one or all fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all fx groups. + * @param damping damping value to set. Must be in the range indicated by + * synth.reverb.damp setting. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int fluid_synth_set_reverb_group_damp(fluid_synth_t *synth, int fx_group, + double damping) +{ + return fluid_synth_reverb_set_param(synth, fx_group, FLUID_REVERB_DAMP, damping); +} + +/** + * Set reverb width to one or all fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all fx groups. + * @param width width value to set. Must be in the range indicated by + * synth.reverb.width setting. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int fluid_synth_set_reverb_group_width(fluid_synth_t *synth, int fx_group, + double width) +{ + return fluid_synth_reverb_set_param(synth, fx_group, FLUID_REVERB_WIDTH, width); +} + +/** + * Set reverb level to one or all fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all fx groups. + * @param level output level to set. Must be in the range indicated by + * synth.reverb.level setting. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int fluid_synth_set_reverb_group_level(fluid_synth_t *synth, int fx_group, + double level) +{ + return fluid_synth_reverb_set_param(synth, fx_group, FLUID_REVERB_LEVEL, level); +} + +/** + * Set one reverb parameter to one fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all fx groups. + * @param enum indicating the parameter to set (#fluid_reverb_param). + * FLUID_REVERB_ROOMSIZE, roomsize Reverb room size value (0.0-1.0) + * FLUID_REVERB_DAMP, reverb damping value (0.0-1.0) + * FLUID_REVERB_WIDTH, reverb width value (0.0-100.0) + * FLUID_REVERB_LEVEL, reverb level value (0.0-1.0) + * @param value, parameter value + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_reverb_set_param(fluid_synth_t *synth, int fx_group, + int param, double value) +{ + int ret; + double values[FLUID_REVERB_PARAM_LAST] = {0.0}; + static const char *name[FLUID_REVERB_PARAM_LAST] = + { + "synth.reverb.room-size", "synth.reverb.damp", + "synth.reverb.width", "synth.reverb.level" + }; + + double min; /* minimum value */ + double max; /* maximum value */ + + /* check parameters */ + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail((param >= 0) && (param < FLUID_REVERB_PARAM_LAST), FLUID_FAILED); + fluid_synth_api_enter(synth); + + if(fx_group < -1 || fx_group >= synth->effects_groups) + { + FLUID_API_RETURN(FLUID_FAILED); + } + + /* check if reverb value is in max min range */ + fluid_settings_getnum_range(synth->settings, name[param], &min, &max); + if(value < min || value > max) + { + FLUID_API_RETURN(FLUID_FAILED); + } + + /* set the value */ + values[param] = value; + ret = fluid_synth_set_reverb_full(synth, fx_group, FLUID_REVPARAM_TO_SETFLAG(param), values); + FLUID_API_RETURN(ret); +} + +int +fluid_synth_set_reverb_full(fluid_synth_t *synth, int fx_group, int set, + const double values[]) +{ + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; + + /* if non of the flags is set, fail */ + fluid_return_val_if_fail(set & FLUID_REVMODEL_SET_ALL, FLUID_FAILED); + + /* fx group shadow values are set here so that they will be returned if queried */ + fluid_rvoice_mixer_set_reverb_full(synth->eventhandler->mixer, fx_group, set, + values); + + /* Synth shadow values are set here so that they will be returned if queried */ + if (fx_group < 0) + { + int i; + for(i = 0; i < FLUID_REVERB_PARAM_LAST; i++) + { + if(set & FLUID_REVPARAM_TO_SETFLAG(i)) + { + synth->reverb_param[i] = values[i]; + } + } + } + + param[0].i = fx_group; + param[1].i = set; + param[2].real = values[FLUID_REVERB_ROOMSIZE]; + param[3].real = values[FLUID_REVERB_DAMP]; + param[4].real = values[FLUID_REVERB_WIDTH]; + param[5].real = values[FLUID_REVERB_LEVEL]; + /* finally enqueue an rvoice event to the mixer to actual update reverb */ + return fluid_rvoice_eventhandler_push(synth->eventhandler, + fluid_rvoice_mixer_set_reverb_params, + synth->eventhandler->mixer, + param); +} + +/** + * Get reverb room size of all fx groups. + * @param synth FluidSynth instance + * @return Reverb room size (0.0-1.2) + * @deprecated Use fluid_synth_get_reverb_group_roomsize() in new code instead. + */ +double +fluid_synth_get_reverb_roomsize(fluid_synth_t *synth) +{ + double roomsize = 0.0; + fluid_synth_reverb_get_param(synth, -1, FLUID_REVERB_ROOMSIZE, &roomsize); + return roomsize; +} + +/** + * Get reverb damping of all fx groups. + * @param synth FluidSynth instance + * @return Reverb damping value (0.0-1.0) + * @deprecated Use fluid_synth_get_reverb_group_damp() in new code instead. + */ +double +fluid_synth_get_reverb_damp(fluid_synth_t *synth) +{ + double damp = 0.0; + fluid_synth_reverb_get_param(synth, -1, FLUID_REVERB_DAMP, &damp); + return damp; +} + +/** + * Get reverb level of all fx groups. + * @param synth FluidSynth instance + * @return Reverb level value (0.0-1.0) + * @deprecated Use fluid_synth_get_reverb_group_level() in new code instead. + */ +double +fluid_synth_get_reverb_level(fluid_synth_t *synth) +{ + double level = 0.0; + fluid_synth_reverb_get_param(synth, -1, FLUID_REVERB_LEVEL, &level); + return level; +} + +/** + * Get reverb width of all fx groups. + * @param synth FluidSynth instance + * @return Reverb width value (0.0-100.0) + * @deprecated Use fluid_synth_get_reverb_group_width() in new code instead. + */ +double +fluid_synth_get_reverb_width(fluid_synth_t *synth) +{ + double width = 0.0; + fluid_synth_reverb_get_param(synth, -1, FLUID_REVERB_WIDTH, &width); + return width; +} + +/** + * get reverb roomsize of one or all groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param roomsize valid pointer on the value to return. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int fluid_synth_get_reverb_group_roomsize(fluid_synth_t *synth, int fx_group, + double *roomsize) +{ + return fluid_synth_reverb_get_param(synth, fx_group, FLUID_REVERB_ROOMSIZE, roomsize); +} + +/** + * get reverb damp of one or all groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param damping valid pointer on the value to return. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int fluid_synth_get_reverb_group_damp(fluid_synth_t *synth, int fx_group, + double *damping) +{ + return fluid_synth_reverb_get_param(synth, fx_group, FLUID_REVERB_DAMP, damping); +} + +/** + * get reverb width of one or all groups + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param width valid pointer on the value to return. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int fluid_synth_get_reverb_group_width(fluid_synth_t *synth, int fx_group, + double *width) +{ + return fluid_synth_reverb_get_param(synth, fx_group, FLUID_REVERB_WIDTH, width); +} + +/** + * get reverb level of one or all groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param level valid pointer on the value to return. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int fluid_synth_get_reverb_group_level(fluid_synth_t *synth, int fx_group, + double *level) +{ + return fluid_synth_reverb_get_param(synth, fx_group, FLUID_REVERB_LEVEL, level); +} + + +/** + * Get one reverb parameter value of one fx groups. + * @param synth FluidSynth instance + * @param fx_group index of the fx group to get parameter value from. + * Must be in the range -1 to synth->effects_groups-1. If -1 get the + * parameter common to all fx groups. + * @param enum indicating the parameter to get (#fluid_reverb_param). + * FLUID_REVERB_ROOMSIZE, reverb room size value. + * FLUID_REVERB_DAMP, reverb damping value. + * FLUID_REVERB_WIDTH, reverb width value. + * FLUID_REVERB_LEVEL, reverb level value. + * @param value pointer on the value to return. + * @return FLUID_OK if success, FLUID_FAILED otherwise. + */ +static int fluid_synth_reverb_get_param(fluid_synth_t *synth, int fx_group, + int param, double *value) +{ + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail((param >= 0) && (param < FLUID_REVERB_PARAM_LAST), FLUID_FAILED); + fluid_return_val_if_fail(value != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + + if(fx_group < -1 || fx_group >= synth->effects_groups) + { + FLUID_API_RETURN(FLUID_FAILED); + } + + if (fx_group < 0) + { + /* return reverb param common to all fx groups */ + *value = synth->reverb_param[param]; + } + else + { + /* return reverb param of fx group at index fx_group */ + *value = fluid_rvoice_mixer_reverb_get_param(synth->eventhandler->mixer, + fx_group, param); + } + + FLUID_API_RETURN(FLUID_OK); +} + +/** + * Enable or disable all chorus groups. + * @param synth FluidSynth instance + * @param on TRUE to enable chorus, FALSE to disable + * @deprecated Use fluid_synth_chorus_on() in new code instead. + */ +void +fluid_synth_set_chorus_on(fluid_synth_t *synth, int on) +{ + fluid_return_if_fail(synth != NULL); + fluid_synth_api_enter(synth); + + synth->with_chorus = (on != 0); + fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_chorus_enabled, + on != 0, 0.0f); + fluid_synth_api_exit(synth); +} + +/** + * Enable or disable chorus on one or all groups. + * @param synth FluidSynth instance + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all fx groups. + * @param on TRUE to enable chorus, FALSE to disable + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_chorus_on(fluid_synth_t *synth, int fx_group, int on) +{ + int ret; + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + + fluid_synth_api_enter(synth); + + if(fx_group < -1 || fx_group >= synth->effects_groups) + { + FLUID_API_RETURN(FLUID_FAILED); + } + + if(fx_group < 0 ) + { + synth->with_chorus = (on != 0); + } + + param[0].i = fx_group; + param[1].i = on; + ret = fluid_rvoice_eventhandler_push(synth->eventhandler, + fluid_rvoice_mixer_chorus_enable, + synth->eventhandler->mixer, + param); + + FLUID_API_RETURN(ret); +} + +/** + * Set chorus parameters to all fx groups. + * Keep in mind, that the needed CPU time is proportional to 'nr'. + * @param synth FluidSynth instance + * @param nr Chorus voice count (0-99, CPU time consumption proportional to + * this value) + * @param level Chorus level (0.0-10.0) + * @param speed Chorus speed in Hz (0.1-5.0) + * @param depth_ms Chorus depth (max value depends on synth sample-rate, + * 0.0-21.0 is safe for sample-rate values up to 96KHz) + * @param type Chorus waveform type (#fluid_chorus_mod) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use the individual chorus setter functions in new code instead. + * + * Keep in mind, that the needed CPU time is proportional to 'nr'. + */ +int fluid_synth_set_chorus(fluid_synth_t *synth, int nr, double level, + double speed, double depth_ms, int type) +{ + double values[FLUID_CHORUS_PARAM_LAST]; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + + values[FLUID_CHORUS_NR] = nr; + values[FLUID_CHORUS_LEVEL] = level; + values[FLUID_CHORUS_SPEED] = speed; + values[FLUID_CHORUS_DEPTH] = depth_ms; + values[FLUID_CHORUS_TYPE] = type; + return fluid_synth_set_chorus_full(synth, -1, FLUID_CHORUS_SET_ALL, values); +} + +/** + * Set the chorus voice count of all groups. + * + * @param synth FluidSynth instance + * @param nr Chorus voice count (0-99, CPU time consumption proportional to + * this value) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_chorus_group_nr() in new code instead. + */ +int fluid_synth_set_chorus_nr(fluid_synth_t *synth, int nr) +{ + return fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_NR, nr); +} + +/** + * Set the chorus level of all groups. + * + * @param synth FluidSynth instance + * @param level Chorus level (0.0-10.0) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_chorus_group_level() in new code instead. + */ +int fluid_synth_set_chorus_level(fluid_synth_t *synth, double level) +{ + return fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_LEVEL, level); +} + +/** + * Set the chorus speed of all groups. + * + * @param synth FluidSynth instance + * @param speed Chorus speed in Hz (0.1-5.0) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_chorus_group_speed() in new code instead. + */ +int fluid_synth_set_chorus_speed(fluid_synth_t *synth, double speed) +{ + return fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_SPEED, speed); +} + +/** + * Set the chorus depth of all groups. + * + * @param synth FluidSynth instance + * @param depth_ms Chorus depth (max value depends on synth sample-rate, + * 0.0-21.0 is safe for sample-rate values up to 96KHz) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_chorus_group_depth() in new code instead. + */ +int fluid_synth_set_chorus_depth(fluid_synth_t *synth, double depth_ms) +{ + return fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_DEPTH, depth_ms); +} + +/** + * Set the chorus type of all groups. + * + * @param synth FluidSynth instance + * @param type Chorus waveform type (#fluid_chorus_mod) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @deprecated Use fluid_synth_set_chorus_group_type() in new code instead. + */ +int fluid_synth_set_chorus_type(fluid_synth_t *synth, int type) +{ + return fluid_synth_chorus_set_param(synth, -1, FLUID_CHORUS_TYPE, type); +} + +/** + * Set chorus voice count nr to one or all chorus groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all groups. + * @param nr Voice count to set. Must be in the range indicated by \setting{synth_chorus_nr} + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_set_chorus_group_nr(fluid_synth_t *synth, int fx_group, int nr) +{ + return fluid_synth_chorus_set_param(synth, fx_group, FLUID_CHORUS_NR, (double)nr); +} + +/** + * Set chorus output level to one or all chorus groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all groups. + * @param level Output level to set. Must be in the range indicated by \setting{synth_chorus_level} + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_set_chorus_group_level(fluid_synth_t *synth, int fx_group, double level) +{ + return fluid_synth_chorus_set_param(synth, fx_group, FLUID_CHORUS_LEVEL, level); +} + +/** + * Set chorus lfo speed to one or all chorus groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all groups. + * @param speed Lfo speed to set. Must be in the range indicated by \setting{synth_chorus_speed} + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_set_chorus_group_speed(fluid_synth_t *synth, int fx_group, double speed) +{ + return fluid_synth_chorus_set_param(synth, fx_group, FLUID_CHORUS_SPEED, speed); +} + +/** + * Set chorus lfo depth to one or all chorus groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all groups. + * @param depth_ms lfo depth to set. Must be in the range indicated by \setting{synth_chorus_depth} + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_set_chorus_group_depth(fluid_synth_t *synth, int fx_group, double depth_ms) +{ + return fluid_synth_chorus_set_param(synth, fx_group, FLUID_CHORUS_DEPTH, depth_ms); +} + +/** + * Set chorus lfo waveform type to one or all chorus groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all groups. + * @param type Lfo waveform type to set. (#fluid_chorus_mod) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_set_chorus_group_type(fluid_synth_t *synth, int fx_group, int type) +{ + return fluid_synth_chorus_set_param(synth, fx_group, FLUID_CHORUS_TYPE, (double)type); +} + +/** + * Set one chorus parameter to one fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter will be applied to all groups. + * @param enum indicating the parameter to set (#fluid_chorus_param). + * FLUID_CHORUS_NR, chorus voice count (0-99, CPU time consumption proportional to + * this value). + * FLUID_CHORUS_LEVEL, chorus level (0.0-10.0). + * FLUID_CHORUS_SPEED, chorus speed in Hz (0.1-5.0). + * FLUID_CHORUS_DEPTH, chorus depth (max value depends on synth sample-rate, + * 0.0-21.0 is safe for sample-rate values up to 96KHz). + * FLUID_CHORUS_TYPE, chorus waveform type (#fluid_chorus_mod) + * @param value, parameter value + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_chorus_set_param(fluid_synth_t *synth, int fx_group, int param, + double value) +{ + int ret; + double values[FLUID_CHORUS_PARAM_LAST] = {0.0}; + + /* setting name (except lfo waveform type) */ + static const char *name[FLUID_CHORUS_PARAM_LAST-1] = + { + "synth.chorus.nr", "synth.chorus.level", + "synth.chorus.speed", "synth.chorus.depth" + }; + + /* check parameters */ + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail((param >= 0) && (param < FLUID_CHORUS_PARAM_LAST), FLUID_FAILED); + fluid_synth_api_enter(synth); + + if(fx_group < -1 || fx_group >= synth->effects_groups) + { + FLUID_API_RETURN(FLUID_FAILED); + } + + /* check if chorus value is in max min range */ + if(param == FLUID_CHORUS_TYPE || param == FLUID_CHORUS_NR) /* integer value */ + { + int min = FLUID_CHORUS_MOD_SINE; + int max = FLUID_CHORUS_MOD_TRIANGLE; + if(param == FLUID_CHORUS_NR) + { + fluid_settings_getint_range(synth->settings, name[param], &min, &max); + } + if((int)value < min || (int)value > max) + { + FLUID_API_RETURN(FLUID_FAILED); + } + } + else /* float value */ + { + double min; + double max; + fluid_settings_getnum_range(synth->settings, name[param], &min, &max); + if(value < min || value > max) + { + FLUID_API_RETURN(FLUID_FAILED); + } + } + + /* set the value */ + values[param] = value; + ret = fluid_synth_set_chorus_full(synth, fx_group, + FLUID_CHORPARAM_TO_SETFLAG(param), values); + FLUID_API_RETURN(ret); +} + +int +fluid_synth_set_chorus_full(fluid_synth_t *synth, int fx_group, int set, + const double values[]) +{ + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; + + /* if non of the flags is set, fail */ + fluid_return_val_if_fail(set & FLUID_CHORUS_SET_ALL, FLUID_FAILED); + + /* fx group shadow values are set here so that they will be returned if queried */ + fluid_rvoice_mixer_set_chorus_full(synth->eventhandler->mixer, fx_group, + set, values); + + /* Synth shadow values are set here so that they will be returned if queried */ + if (fx_group < 0) + { + int i; + for(i = 0; i < FLUID_CHORUS_PARAM_LAST; i++) + { + if(set & FLUID_CHORPARAM_TO_SETFLAG(i)) + { + synth->chorus_param[i] = values[i]; + } + } + } + + param[0].i = fx_group; + param[1].i = set; + param[2].i = (int)values[FLUID_CHORUS_NR]; + param[3].real = values[FLUID_CHORUS_LEVEL]; + param[4].real = values[FLUID_CHORUS_SPEED]; + param[5].real = values[FLUID_CHORUS_DEPTH]; + param[6].i = (int)values[FLUID_CHORUS_TYPE]; + return fluid_rvoice_eventhandler_push(synth->eventhandler, + fluid_rvoice_mixer_set_chorus_params, + synth->eventhandler->mixer, + param); +} + +/** + * Get chorus voice number (delay line count) value of all fx groups. + * @param synth FluidSynth instance + * @return Chorus voice count + * @deprecated Use fluid_synth_get_chorus_group_nr() in new code instead. + */ +int +fluid_synth_get_chorus_nr(fluid_synth_t *synth) +{ + double nr = 0.0; + fluid_synth_chorus_get_param(synth, -1, FLUID_CHORUS_NR, &nr); + return (int)nr; +} + +/** + * Get chorus level of all fx groups. + * @param synth FluidSynth instance + * @return Chorus level value + * @deprecated Use fluid_synth_get_chorus_group_level() in new code instead. + */ +double +fluid_synth_get_chorus_level(fluid_synth_t *synth) +{ + double level = 0.0; + fluid_synth_chorus_get_param(synth, -1, FLUID_CHORUS_LEVEL, &level); + return level; +} + +/** + * Get chorus speed in Hz of all fx groups. + * @param synth FluidSynth instance + * @return Chorus speed in Hz + * @deprecated Use fluid_synth_get_chorus_group_speed() in new code instead. + */ +double +fluid_synth_get_chorus_speed(fluid_synth_t *synth) +{ + double speed = 0.0; + fluid_synth_chorus_get_param(synth, -1, FLUID_CHORUS_SPEED, &speed); + return speed; +} + +/** + * Get chorus depth of all fx groups. + * @param synth FluidSynth instance + * @return Chorus depth + * @deprecated Use fluid_synth_get_chorus_group_depth() in new code instead. + */ +double +fluid_synth_get_chorus_depth(fluid_synth_t *synth) +{ + double depth = 0.0; + fluid_synth_chorus_get_param(synth, -1, FLUID_CHORUS_DEPTH, &depth); + return depth; +} + +/** + * Get chorus waveform type of all fx groups. + * @param synth FluidSynth instance + * @return Chorus waveform type (#fluid_chorus_mod) + * @deprecated Use fluid_synth_get_chorus_group_type() in new code instead. + */ +int +fluid_synth_get_chorus_type(fluid_synth_t *synth) +{ + double type = 0.0; + fluid_synth_chorus_get_param(synth, -1, FLUID_CHORUS_TYPE, &type); + return (int)type; +} + +/** + * Get chorus count nr of one or all fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group from which to fetch the chorus voice count. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param nr valid pointer on value to return. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_get_chorus_group_nr(fluid_synth_t *synth, int fx_group, int *nr) +{ + double num_nr = 0.0; + int status; + status = fluid_synth_chorus_get_param(synth, fx_group, FLUID_CHORUS_NR, &num_nr); + *nr = (int)num_nr; + return status; +} + +/** + * Get chorus output level of one or all fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group from which chorus level to fetch. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param level valid pointer on value to return. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_get_chorus_group_level(fluid_synth_t *synth, int fx_group, double *level) +{ + return fluid_synth_chorus_get_param(synth, fx_group, FLUID_CHORUS_LEVEL, level); +} + +/** + * Get chorus waveform lfo speed of one or all fx groups. + * @param synth FluidSynth instance. + * @param fx_group Index of the fx group from which lfo speed to fetch. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param speed valid pointer on value to return. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise. + */ +int +fluid_synth_get_chorus_group_speed(fluid_synth_t *synth, int fx_group, double *speed) +{ + return fluid_synth_chorus_get_param(synth, fx_group, FLUID_CHORUS_SPEED, speed); +} + +/** + * Get chorus lfo depth of one or all fx groups. + * @param synth FluidSynth instance + * @param fx_group Index of the fx group from which lfo depth to fetch. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param depth_ms valid pointer on value to return. + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_get_chorus_group_depth(fluid_synth_t *synth, int fx_group, double *depth_ms) +{ + return fluid_synth_chorus_get_param(synth, fx_group, FLUID_CHORUS_DEPTH, depth_ms); +} + +/** + * Get chorus waveform type of one or all fx groups. + * @param synth FluidSynth instance + * @param fx_group Index of the fx group from which to fetch the waveform type. + * Must be in the range -1 to (fluid_synth_count_effects_groups()-1). If -1 the + * parameter common to all fx groups is fetched. + * @param type valid pointer on waveform type to return (#fluid_chorus_mod) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_get_chorus_group_type(fluid_synth_t *synth, int fx_group, int *type) +{ + double num_type = 0.0; + int status; + status = fluid_synth_chorus_get_param(synth, fx_group, FLUID_CHORUS_TYPE, &num_type); + *type = (int)num_type; + return status; +} + +/** + * Get chorus parameter value of one or all fx groups. + * @param synth FluidSynth instance + * @param fx_group index of the fx group + * @param enum indicating the parameter to get. + * FLUID_CHORUS_NR, chorus voice count. + * FLUID_CHORUS_LEVEL, chorus level. + * FLUID_CHORUS_SPEED, chorus speed. + * FLUID_CHORUS_DEPTH, chorus depth. + * FLUID_CHORUS_TYPE, chorus waveform type. + * @param value pointer on the value to return. + * @return FLUID_OK if success, FLUID_FAILED otherwise. + */ +static int fluid_synth_chorus_get_param(fluid_synth_t *synth, int fx_group, + int param, double *value) +{ + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail((param >= 0) && (param < FLUID_CHORUS_PARAM_LAST), FLUID_FAILED); + fluid_return_val_if_fail(value != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + + if(fx_group < -1 || fx_group >= synth->effects_groups) + { + FLUID_API_RETURN(FLUID_FAILED); + } + + if (fx_group < 0) + { + /* return chorus param common to all fx groups */ + *value = synth->chorus_param[param]; + } + else + { + /* return chorus param of fx group at index group */ + *value = fluid_rvoice_mixer_chorus_get_param(synth->eventhandler->mixer, + fx_group, param); + } + + FLUID_API_RETURN(FLUID_OK); +} + +/* + * If the same note is hit twice on the same channel, then the older + * voice process is advanced to the release stage. Using a mechanical + * MIDI controller, the only way this can happen is when the sustain + * pedal is held. In this case the behaviour implemented here is + * natural for many instruments. Note: One noteon event can trigger + * several voice processes, for example a stereo sample. Don't + * release those... + */ +void +fluid_synth_release_voice_on_same_note_LOCAL(fluid_synth_t *synth, int chan, + int key) +{ + int i; + fluid_voice_t *voice; + + /* storeid is a parameter for fluid_voice_init() */ + synth->storeid = synth->noteid++; + + /* for "monophonic playing" key is the previous sustained note + if it exists (0 to 127) or INVALID_NOTE otherwise */ + if(key == INVALID_NOTE) + { + return; + } + + for(i = 0; i < synth->polyphony; i++) + { + voice = synth->voice[i]; + + if(fluid_voice_is_playing(voice) + && (fluid_voice_get_channel(voice) == chan) + && (fluid_voice_get_key(voice) == key) + && (fluid_voice_get_id(voice) != synth->noteid)) + { + /* Id of voices that was sustained by sostenuto */ + if(fluid_voice_is_sostenuto(voice)) + { + synth->storeid = fluid_voice_get_id(voice); + } + + /* Force the voice into release stage except if pedaling + (sostenuto or sustain) is active */ + fluid_voice_noteoff(voice); + } + } +} + +/** + * Set synthesis interpolation method on one or all MIDI channels. + * @param synth FluidSynth instance + * @param chan MIDI channel to set interpolation method on or -1 for all channels + * @param interp_method Interpolation method (#fluid_interp) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_set_interp_method(fluid_synth_t *synth, int chan, int interp_method) +{ + int i; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + + if(chan < -1 || chan >= synth->midi_channels) + { + FLUID_API_RETURN(FLUID_FAILED); + } + + if(synth->channel[0] == NULL) + { + FLUID_LOG(FLUID_ERR, "Channels don't exist (yet)!"); + FLUID_API_RETURN(FLUID_FAILED); + } + + for(i = 0; i < synth->midi_channels; i++) + { + if(chan < 0 || fluid_channel_get_num(synth->channel[i]) == chan) + { + fluid_channel_set_interp_method(synth->channel[i], interp_method); + } + } + + FLUID_API_RETURN(FLUID_OK); +}; + +/** + * Get the total count of MIDI channels. + * @param synth FluidSynth instance + * @return Count of MIDI channels + */ +int +fluid_synth_count_midi_channels(fluid_synth_t *synth) +{ + int result; + fluid_return_val_if_fail(synth != NULL, 0); + fluid_synth_api_enter(synth); + + result = synth->midi_channels; + FLUID_API_RETURN(result); +} + +/** + * Get the total count of audio channels. + * @param synth FluidSynth instance + * @return Count of audio channel stereo pairs (1 = 2 channels, 2 = 4, etc) + */ +int +fluid_synth_count_audio_channels(fluid_synth_t *synth) +{ + int result; + fluid_return_val_if_fail(synth != NULL, 0); + fluid_synth_api_enter(synth); + + result = synth->audio_channels; + FLUID_API_RETURN(result); +} + +/** + * Get the total number of allocated audio channels. Usually identical to the + * number of audio channels. Can be employed by LADSPA effects subsystem. + * + * @param synth FluidSynth instance + * @return Count of audio group stereo pairs (1 = 2 channels, 2 = 4, etc) + */ +int +fluid_synth_count_audio_groups(fluid_synth_t *synth) +{ + int result; + fluid_return_val_if_fail(synth != NULL, 0); + fluid_synth_api_enter(synth); + + result = synth->audio_groups; + FLUID_API_RETURN(result); +} + +/** + * Get the total number of allocated effects channels. + * @param synth FluidSynth instance + * @return Count of allocated effects channels + */ +int +fluid_synth_count_effects_channels(fluid_synth_t *synth) +{ + int result; + fluid_return_val_if_fail(synth != NULL, 0); + fluid_synth_api_enter(synth); + + result = synth->effects_channels; + FLUID_API_RETURN(result); +} + +/** + * Get the total number of allocated effects units. + * + * This is the same number as initially provided by the setting \setting{synth_effects-groups}. + * @param synth FluidSynth instance + * @return Count of allocated effects units + */ +int +fluid_synth_count_effects_groups(fluid_synth_t *synth) +{ + int result; + fluid_return_val_if_fail(synth != NULL, 0); + fluid_synth_api_enter(synth); + + result = synth->effects_groups; + FLUID_API_RETURN(result); +} + +/** + * Get the synth CPU load value. + * @param synth FluidSynth instance + * @return Estimated CPU load value in percent (0-100) + */ +double +fluid_synth_get_cpu_load(fluid_synth_t *synth) +{ + fluid_return_val_if_fail(synth != NULL, 0); + return fluid_atomic_float_get(&synth->cpu_load); +} + +/* Get tuning for a given bank:program */ +static fluid_tuning_t * +fluid_synth_get_tuning(fluid_synth_t *synth, int bank, int prog) +{ + + if((synth->tuning == NULL) || + (synth->tuning[bank] == NULL) || + (synth->tuning[bank][prog] == NULL)) + { + return NULL; + } + + return synth->tuning[bank][prog]; +} + +/* Replace tuning on a given bank:program (need not already exist). + * Synth mutex should already be locked by caller. */ +static int +fluid_synth_replace_tuning_LOCK(fluid_synth_t *synth, fluid_tuning_t *tuning, + int bank, int prog, int apply) +{ + fluid_tuning_t *old_tuning; + + if(synth->tuning == NULL) + { + synth->tuning = FLUID_ARRAY(fluid_tuning_t **, 128); + + if(synth->tuning == NULL) + { + FLUID_LOG(FLUID_PANIC, "Out of memory"); + return FLUID_FAILED; + } + + FLUID_MEMSET(synth->tuning, 0, 128 * sizeof(fluid_tuning_t **)); + } + + if(synth->tuning[bank] == NULL) + { + synth->tuning[bank] = FLUID_ARRAY(fluid_tuning_t *, 128); + + if(synth->tuning[bank] == NULL) + { + FLUID_LOG(FLUID_PANIC, "Out of memory"); + return FLUID_FAILED; + } + + FLUID_MEMSET(synth->tuning[bank], 0, 128 * sizeof(fluid_tuning_t *)); + } + + old_tuning = synth->tuning[bank][prog]; + synth->tuning[bank][prog] = tuning; + + if(old_tuning) + { + if(!fluid_tuning_unref(old_tuning, 1)) /* -- unref old tuning */ + { + /* Replace old tuning if present */ + fluid_synth_replace_tuning_LOCAL(synth, old_tuning, tuning, apply, FALSE); + } + } + + return FLUID_OK; +} + +/* Replace a tuning with a new one in all MIDI channels. new_tuning can be + * NULL, in which case channels are reset to default equal tempered scale. */ +static void +fluid_synth_replace_tuning_LOCAL(fluid_synth_t *synth, fluid_tuning_t *old_tuning, + fluid_tuning_t *new_tuning, int apply, int unref_new) +{ + fluid_channel_t *channel; + int old_tuning_unref = 0; + int i; + + for(i = 0; i < synth->midi_channels; i++) + { + channel = synth->channel[i]; + + if(fluid_channel_get_tuning(channel) == old_tuning) + { + old_tuning_unref++; + + if(new_tuning) + { + fluid_tuning_ref(new_tuning); /* ++ ref new tuning for channel */ + } + + fluid_channel_set_tuning(channel, new_tuning); + + if(apply) + { + fluid_synth_update_voice_tuning_LOCAL(synth, channel); + } + } + } + + /* Send unref old tuning event if any unrefs */ + if(old_tuning && old_tuning_unref) + { + fluid_tuning_unref(old_tuning, old_tuning_unref); + } + + if(!unref_new || !new_tuning) + { + return; + } + + fluid_tuning_unref(new_tuning, 1); +} + +/* Update voice tunings in realtime */ +static void +fluid_synth_update_voice_tuning_LOCAL(fluid_synth_t *synth, fluid_channel_t *channel) +{ + fluid_voice_t *voice; + int i; + + for(i = 0; i < synth->polyphony; i++) + { + voice = synth->voice[i]; + + if(fluid_voice_is_on(voice) && (voice->channel == channel)) + { + fluid_voice_calculate_gen_pitch(voice); + fluid_voice_update_param(voice, GEN_PITCH); + } + } +} + +/** + * Set the tuning of the entire MIDI note scale. + * @param synth FluidSynth instance + * @param bank Tuning bank number (0-127), not related to MIDI instrument bank + * @param prog Tuning preset number (0-127), not related to MIDI instrument program + * @param name Label name for this tuning + * @param pitch Array of pitch values (length of 128, each value is number of + * cents, for example normally note 0 is 0.0, 1 is 100.0, 60 is 6000.0, etc). + * Pass NULL to create a equal tempered (normal) scale. + * @param apply TRUE to apply new tuning in realtime to existing notes which + * are using the replaced tuning (if any), FALSE otherwise + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @since 1.1.0 + */ +int +fluid_synth_activate_key_tuning(fluid_synth_t *synth, int bank, int prog, + const char *name, const double *pitch, int apply) +{ + fluid_tuning_t *tuning; + int retval = FLUID_OK; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail(bank >= 0 && bank < 128, FLUID_FAILED); + fluid_return_val_if_fail(prog >= 0 && prog < 128, FLUID_FAILED); + fluid_return_val_if_fail(name != NULL, FLUID_FAILED); + + fluid_synth_api_enter(synth); + + tuning = new_fluid_tuning(name, bank, prog); + + if(tuning) + { + if(pitch) + { + fluid_tuning_set_all(tuning, pitch); + } + + retval = fluid_synth_replace_tuning_LOCK(synth, tuning, bank, prog, apply); + + if(retval == FLUID_FAILED) + { + fluid_tuning_unref(tuning, 1); + } + } + else + { + retval = FLUID_FAILED; + } + + FLUID_API_RETURN(retval); +} + +/** + * Activate an octave tuning on every octave in the MIDI note scale. + * @param synth FluidSynth instance + * @param bank Tuning bank number (0-127), not related to MIDI instrument bank + * @param prog Tuning preset number (0-127), not related to MIDI instrument program + * @param name Label name for this tuning + * @param pitch Array of pitch values (length of 12 for each note of an octave + * starting at note C, values are number of offset cents to add to the normal + * tuning amount) + * @param apply TRUE to apply new tuning in realtime to existing notes which + * are using the replaced tuning (if any), FALSE otherwise + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @since 1.1.0 + */ +int +fluid_synth_activate_octave_tuning(fluid_synth_t *synth, int bank, int prog, + const char *name, const double *pitch, int apply) +{ + fluid_tuning_t *tuning; + int retval = FLUID_OK; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail(bank >= 0 && bank < 128, FLUID_FAILED); + fluid_return_val_if_fail(prog >= 0 && prog < 128, FLUID_FAILED); + fluid_return_val_if_fail(name != NULL, FLUID_FAILED); + fluid_return_val_if_fail(pitch != NULL, FLUID_FAILED); + + fluid_synth_api_enter(synth); + tuning = new_fluid_tuning(name, bank, prog); + + if(tuning) + { + fluid_tuning_set_octave(tuning, pitch); + retval = fluid_synth_replace_tuning_LOCK(synth, tuning, bank, prog, apply); + + if(retval == FLUID_FAILED) + { + fluid_tuning_unref(tuning, 1); + } + } + else + { + retval = FLUID_FAILED; + } + + FLUID_API_RETURN(retval); +} + +/** + * Set tuning values for one or more MIDI notes for an existing tuning. + * @param synth FluidSynth instance + * @param bank Tuning bank number (0-127), not related to MIDI instrument bank + * @param prog Tuning preset number (0-127), not related to MIDI instrument program + * @param len Number of MIDI notes to assign + * @param key Array of MIDI key numbers (length of 'len', values 0-127) + * @param pitch Array of pitch values (length of 'len', values are number of + * cents from MIDI note 0) + * @param apply TRUE to apply tuning change in realtime to existing notes using + * the specified tuning, FALSE otherwise + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * + * @note Prior to version 1.1.0 it was an error to specify a tuning that didn't + * already exist. Starting with 1.1.0, the default equal tempered scale will be + * used as a basis, if no tuning exists for the given bank and prog. + */ +int +fluid_synth_tune_notes(fluid_synth_t *synth, int bank, int prog, + int len, const int *key, const double *pitch, int apply) +{ + fluid_tuning_t *old_tuning, *new_tuning; + int retval = FLUID_OK; + int i; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail(bank >= 0 && bank < 128, FLUID_FAILED); + fluid_return_val_if_fail(prog >= 0 && prog < 128, FLUID_FAILED); + fluid_return_val_if_fail(len > 0, FLUID_FAILED); + fluid_return_val_if_fail(key != NULL, FLUID_FAILED); + fluid_return_val_if_fail(pitch != NULL, FLUID_FAILED); + + fluid_synth_api_enter(synth); + + old_tuning = fluid_synth_get_tuning(synth, bank, prog); + + if(old_tuning) + { + new_tuning = fluid_tuning_duplicate(old_tuning); + } + else + { + new_tuning = new_fluid_tuning("Unnamed", bank, prog); + } + + if(new_tuning) + { + for(i = 0; i < len; i++) + { + fluid_tuning_set_pitch(new_tuning, key[i], pitch[i]); + } + + retval = fluid_synth_replace_tuning_LOCK(synth, new_tuning, bank, prog, apply); + + if(retval == FLUID_FAILED) + { + fluid_tuning_unref(new_tuning, 1); + } + } + else + { + retval = FLUID_FAILED; + } + + FLUID_API_RETURN(retval); +} + +/** + * Activate a tuning scale on a MIDI channel. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param bank Tuning bank number (0-127), not related to MIDI instrument bank + * @param prog Tuning preset number (0-127), not related to MIDI instrument program + * @param apply TRUE to apply tuning change to active notes, FALSE otherwise + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @since 1.1.0 + * + * @note A default equal tempered scale will be created, if no tuning exists + * on the given bank and prog. + */ +int +fluid_synth_activate_tuning(fluid_synth_t *synth, int chan, int bank, int prog, + int apply) +{ + fluid_tuning_t *tuning; + int retval = FLUID_OK; + + //fluid_return_val_if_fail (synth != NULL, FLUID_FAILED); + //fluid_return_val_if_fail (chan >= 0 && chan < synth->midi_channels, FLUID_FAILED); + fluid_return_val_if_fail(bank >= 0 && bank < 128, FLUID_FAILED); + fluid_return_val_if_fail(prog >= 0 && prog < 128, FLUID_FAILED); + + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + tuning = fluid_synth_get_tuning(synth, bank, prog); + + /* If no tuning exists, create a new default tuning. We do this, so that + * it can be replaced later, if any changes are made. */ + if(!tuning) + { + tuning = new_fluid_tuning("Unnamed", bank, prog); + + if(tuning) + { + fluid_synth_replace_tuning_LOCK(synth, tuning, bank, prog, FALSE); + } + } + + if(tuning) + { + fluid_tuning_ref(tuning); /* ++ ref for outside of lock */ + } + + if(!tuning) + { + FLUID_API_RETURN(FLUID_FAILED); + } + + fluid_tuning_ref(tuning); /* ++ ref new tuning for following function */ + retval = fluid_synth_set_tuning_LOCAL(synth, chan, tuning, apply); + + fluid_tuning_unref(tuning, 1); /* -- unref for outside of lock */ + + FLUID_API_RETURN(retval); +} + +/* Local synthesis thread set tuning function (takes over tuning reference) */ +static int +fluid_synth_set_tuning_LOCAL(fluid_synth_t *synth, int chan, + fluid_tuning_t *tuning, int apply) +{ + fluid_tuning_t *old_tuning; + fluid_channel_t *channel; + + channel = synth->channel[chan]; + + old_tuning = fluid_channel_get_tuning(channel); + fluid_channel_set_tuning(channel, tuning); /* !! Takes over callers reference */ + + if(apply) + { + fluid_synth_update_voice_tuning_LOCAL(synth, channel); + } + + /* Send unref old tuning event */ + if(old_tuning) + { + fluid_tuning_unref(old_tuning, 1); + } + + + return FLUID_OK; +} + +/** + * Clear tuning scale on a MIDI channel (use default equal tempered scale). + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param apply TRUE to apply tuning change to active notes, FALSE otherwise + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @since 1.1.0 + */ +int +fluid_synth_deactivate_tuning(fluid_synth_t *synth, int chan, int apply) +{ + int retval = FLUID_OK; + + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + retval = fluid_synth_set_tuning_LOCAL(synth, chan, NULL, apply); + + FLUID_API_RETURN(retval); +} + +/** + * Start tuning iteration. + * @param synth FluidSynth instance + */ +void +fluid_synth_tuning_iteration_start(fluid_synth_t *synth) +{ + fluid_return_if_fail(synth != NULL); + fluid_synth_api_enter(synth); + fluid_private_set(synth->tuning_iter, FLUID_INT_TO_POINTER(0)); + fluid_synth_api_exit(synth); +} + +/** + * Advance to next tuning. + * @param synth FluidSynth instance + * @param bank Location to store MIDI bank number of next tuning scale + * @param prog Location to store MIDI program number of next tuning scale + * @return 1 if tuning iteration advanced, 0 if no more tunings + */ +int +fluid_synth_tuning_iteration_next(fluid_synth_t *synth, int *bank, int *prog) +{ + void *pval; + int b = 0, p = 0; + + fluid_return_val_if_fail(synth != NULL, 0); + fluid_return_val_if_fail(bank != NULL, 0); + fluid_return_val_if_fail(prog != NULL, 0); + fluid_synth_api_enter(synth); + + /* Current tuning iteration stored as: bank << 8 | program */ + pval = fluid_private_get(synth->tuning_iter); + p = FLUID_POINTER_TO_INT(pval); + b = (p >> 8) & 0xFF; + p &= 0xFF; + + if(!synth->tuning) + { + FLUID_API_RETURN(0); + } + + for(; b < 128; b++, p = 0) + { + if(synth->tuning[b] == NULL) + { + continue; + } + + for(; p < 128; p++) + { + if(synth->tuning[b][p] == NULL) + { + continue; + } + + *bank = b; + *prog = p; + + if(p < 127) + { + fluid_private_set(synth->tuning_iter, + FLUID_INT_TO_POINTER(b << 8 | (p + 1))); + } + else + { + fluid_private_set(synth->tuning_iter, FLUID_INT_TO_POINTER((b + 1) << 8)); + } + + FLUID_API_RETURN(1); + } + } + + FLUID_API_RETURN(0); +} + +/** + * Get the entire note tuning for a given MIDI bank and program. + * @param synth FluidSynth instance + * @param bank MIDI bank number of tuning + * @param prog MIDI program number of tuning + * @param name Location to store tuning name or NULL to ignore + * @param len Maximum number of chars to store to 'name' (including NULL byte) + * @param pitch Array to store tuning scale to or NULL to ignore (len of 128) + * @return #FLUID_OK if matching tuning was found, #FLUID_FAILED otherwise + */ +int +fluid_synth_tuning_dump(fluid_synth_t *synth, int bank, int prog, + char *name, int len, double *pitch) +{ + fluid_tuning_t *tuning; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + + tuning = fluid_synth_get_tuning(synth, bank, prog); + + if(tuning) + { + if(name) + { + FLUID_SNPRINTF(name, len - 1, "%s", fluid_tuning_get_name(tuning)); + name[len - 1] = 0; /* make sure the string is null terminated */ + } + + if(pitch) + { + FLUID_MEMCPY(pitch, fluid_tuning_get_all(tuning), 128 * sizeof(double)); + } + } + + FLUID_API_RETURN(tuning ? FLUID_OK : FLUID_FAILED); +} + +/** + * Get settings assigned to a synth. + * @param synth FluidSynth instance + * @return FluidSynth settings which are assigned to the synth + */ +fluid_settings_t * +fluid_synth_get_settings(fluid_synth_t *synth) +{ + fluid_return_val_if_fail(synth != NULL, NULL); + + return synth->settings; +} + +/** + * Apply an offset to a SoundFont generator on a MIDI channel. + * + * This function allows to set an offset for the specified destination generator in real-time. + * The offset will be applied immediately to all voices that are currently and subsequently playing + * on the given MIDI channel. This functionality works equivalent to using NRPN MIDI messages to + * manipulate synthesis parameters. See SoundFont spec, paragraph 8.1.3, for details on SoundFont + * generator parameters and valid ranges, as well as paragraph 9.6 for details on NRPN messages. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param param SoundFont generator ID (#fluid_gen_type) + * @param value Offset value (in native units of the generator) to assign to the MIDI channel + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int fluid_synth_set_gen(fluid_synth_t *synth, int chan, int param, float value) +{ + fluid_return_val_if_fail(param >= 0 && param < GEN_LAST, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + fluid_synth_set_gen_LOCAL(synth, chan, param, value); + + FLUID_API_RETURN(FLUID_OK); +} + +/* Synthesis thread local set gen function */ +static void +fluid_synth_set_gen_LOCAL(fluid_synth_t *synth, int chan, int param, float value) +{ + fluid_voice_t *voice; + int i; + + fluid_channel_set_gen(synth->channel[chan], param, value); + + for(i = 0; i < synth->polyphony; i++) + { + voice = synth->voice[i]; + + if(fluid_voice_get_channel(voice) == chan) + { + fluid_voice_set_param(voice, param, value); + } + } +} + +/** + * Retrieve the generator NRPN offset assigned to a MIDI channel. + * + * The value returned is in native units of the generator. By default, the offset is zero. + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param param SoundFont generator ID (#fluid_gen_type) + * @return Current NRPN generator offset value assigned to the MIDI channel + */ +float +fluid_synth_get_gen(fluid_synth_t *synth, int chan, int param) +{ + float result; + fluid_return_val_if_fail(param >= 0 && param < GEN_LAST, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + result = fluid_channel_get_gen(synth->channel[chan], param); + FLUID_API_RETURN(result); +} + +/** + * Handle MIDI event from MIDI router, used as a callback function. + * @param data FluidSynth instance + * @param event MIDI event to handle + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + */ +int +fluid_synth_handle_midi_event(void *data, fluid_midi_event_t *event) +{ + fluid_synth_t *synth = (fluid_synth_t *) data; + int type = fluid_midi_event_get_type(event); + int chan = fluid_midi_event_get_channel(event); + + switch(type) + { + case NOTE_ON: + return fluid_synth_noteon(synth, chan, + fluid_midi_event_get_key(event), + fluid_midi_event_get_velocity(event)); + + case NOTE_OFF: + return fluid_synth_noteoff(synth, chan, fluid_midi_event_get_key(event)); + + case CONTROL_CHANGE: + return fluid_synth_cc(synth, chan, + fluid_midi_event_get_control(event), + fluid_midi_event_get_value(event)); + + case PROGRAM_CHANGE: + return fluid_synth_program_change(synth, chan, fluid_midi_event_get_program(event)); + + case CHANNEL_PRESSURE: + return fluid_synth_channel_pressure(synth, chan, fluid_midi_event_get_program(event)); + + case KEY_PRESSURE: + return fluid_synth_key_pressure(synth, chan, + fluid_midi_event_get_key(event), + fluid_midi_event_get_value(event)); + + case PITCH_BEND: + return fluid_synth_pitch_bend(synth, chan, fluid_midi_event_get_pitch(event)); + + case MIDI_SYSTEM_RESET: + return fluid_synth_system_reset(synth); + + case MIDI_SYSEX: + return fluid_synth_sysex(synth, event->paramptr, event->param1, NULL, NULL, NULL, FALSE); + + case MIDI_TEXT: + case MIDI_LYRIC: + case MIDI_SET_TEMPO: + return FLUID_OK; + } + + return FLUID_FAILED; +} + +/** + * Create and start voices using an arbitrary preset and a MIDI note on event. + * + * Using this function is only supported when the setting @c synth.dynamic-sample-loading is false! + * @param synth FluidSynth instance + * @param id Voice group ID to use (can be used with fluid_synth_stop()). + * @param preset Preset to synthesize + * @param audio_chan Unused currently, set to 0 + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param key MIDI note number (0-127) + * @param vel MIDI velocity number (1-127) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * + * @note Should only be called from within synthesis thread, which includes + * SoundFont loader preset noteon method. + */ +int +fluid_synth_start(fluid_synth_t *synth, unsigned int id, fluid_preset_t *preset, + int audio_chan, int chan, int key, int vel) +{ + int result, dynamic_samples; + fluid_return_val_if_fail(preset != NULL, FLUID_FAILED); + fluid_return_val_if_fail(key >= 0 && key <= 127, FLUID_FAILED); + fluid_return_val_if_fail(vel >= 1 && vel <= 127, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + fluid_settings_getint(fluid_synth_get_settings(synth), "synth.dynamic-sample-loading", &dynamic_samples); + if(dynamic_samples) + { + // The preset might not be currently used, thus its sample data may not be loaded. + // This guard is to avoid a NULL deref in rvoice_write(). + FLUID_LOG(FLUID_ERR, "Calling fluid_synth_start() while synth.dynamic-sample-loading is enabled is not supported."); + // Although we would be able to select the preset (and load it's samples) we have no way to + // unselect the preset again in fluid_synth_stop(). Also dynamic sample loading was intended + // to be used only when presets have been selected on a MIDI channel. + // Note that even if the preset is currently selected on a channel, it could be unselected at + // any time. And we would end up with a NULL sample->data again, because we are not referencing + // the preset here. Thus failure is our only option. + result = FLUID_FAILED; + } + else + { + synth->storeid = id; + result = fluid_preset_noteon(preset, synth, chan, key, vel); + } + + FLUID_API_RETURN(result); +} + +/** + * Stop notes for a given note event voice ID. + * @param synth FluidSynth instance + * @param id Voice note event ID + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * + * @note In FluidSynth versions prior to 1.1.0 #FLUID_FAILED would be returned + * if no matching voice note event ID was found. Versions after 1.1.0 only + * return #FLUID_FAILED if an error occurs. + */ +int +fluid_synth_stop(fluid_synth_t *synth, unsigned int id) +{ + int result; + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + fluid_synth_stop_LOCAL(synth, id); + result = FLUID_OK; + FLUID_API_RETURN(result); +} + +/* Local synthesis thread variant of fluid_synth_stop */ +static void +fluid_synth_stop_LOCAL(fluid_synth_t *synth, unsigned int id) +{ + fluid_voice_t *voice; + int i; + + for(i = 0; i < synth->polyphony; i++) + { + voice = synth->voice[i]; + + if(fluid_voice_is_on(voice) && (fluid_voice_get_id(voice) == id)) + { + fluid_voice_noteoff(voice); + } + } +} + +/** + * Offset the bank numbers of a loaded SoundFont, i.e.\ subtract + * \c offset from any bank number when assigning instruments. + * + * @param synth FluidSynth instance + * @param sfont_id ID of a loaded SoundFont + * @param offset Bank offset value to apply to all instruments + * @return #FLUID_OK if the offset was set successfully, #FLUID_FAILED otherwise + */ +int +fluid_synth_set_bank_offset(fluid_synth_t *synth, int sfont_id, int offset) +{ + fluid_sfont_t *sfont; + fluid_list_t *list; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + + for(list = synth->sfont; list; list = fluid_list_next(list)) + { + sfont = fluid_list_get(list); + + if(fluid_sfont_get_id(sfont) == sfont_id) + { + sfont->bankofs = offset; + break; + } + } + + if(!list) + { + FLUID_LOG(FLUID_ERR, "No SoundFont with id = %d", sfont_id); + FLUID_API_RETURN(FLUID_FAILED); + } + + FLUID_API_RETURN(FLUID_OK); +} + +/** + * Get bank offset of a loaded SoundFont. + * @param synth FluidSynth instance + * @param sfont_id ID of a loaded SoundFont + * @return SoundFont bank offset value + */ +int +fluid_synth_get_bank_offset(fluid_synth_t *synth, int sfont_id) +{ + fluid_sfont_t *sfont; + fluid_list_t *list; + int offset = 0; + + fluid_return_val_if_fail(synth != NULL, 0); + fluid_synth_api_enter(synth); + + for(list = synth->sfont; list; list = fluid_list_next(list)) + { + sfont = fluid_list_get(list); + + if(fluid_sfont_get_id(sfont) == sfont_id) + { + offset = sfont->bankofs; + break; + } + } + + if(!list) + { + FLUID_LOG(FLUID_ERR, "No SoundFont with id = %d", sfont_id); + FLUID_API_RETURN(0); + } + + FLUID_API_RETURN(offset); +} + +void +fluid_synth_api_enter(fluid_synth_t *synth) +{ + if(synth->use_mutex) + { + fluid_rec_mutex_lock(synth->mutex); + } + + if(!synth->public_api_count) + { + fluid_synth_check_finished_voices(synth); + } + + synth->public_api_count++; +} + +void fluid_synth_api_exit(fluid_synth_t *synth) +{ + synth->public_api_count--; + + if(!synth->public_api_count) + { + fluid_rvoice_eventhandler_flush(synth->eventhandler); + } + + if(synth->use_mutex) + { + fluid_rec_mutex_unlock(synth->mutex); + } + +} + +/** + * Set midi channel type + * @param synth FluidSynth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param type MIDI channel type (#fluid_midi_channel_type) + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * @since 1.1.4 + */ +int fluid_synth_set_channel_type(fluid_synth_t *synth, int chan, int type) +{ + fluid_return_val_if_fail((type >= CHANNEL_TYPE_MELODIC) && (type <= CHANNEL_TYPE_DRUM), FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + synth->channel[chan]->channel_type = type; + + FLUID_API_RETURN(FLUID_OK); +} + +/** + * Return the LADSPA effects instance used by FluidSynth + * + * @param synth FluidSynth instance + * @return pointer to LADSPA fx or NULL if compiled without LADSPA support or LADSPA is not active + */ +fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth) +{ + fluid_return_val_if_fail(synth != NULL, NULL); + + return synth->ladspa_fx; +} + +/** + * Configure a general-purpose IIR biquad filter. + * + * @param synth FluidSynth instance + * @param type Type of the IIR filter to use (see #fluid_iir_filter_type) + * @param flags Additional flags to customize this filter or zero to stay with the default (see #fluid_iir_filter_flags) + * @return #FLUID_OK if the settings have been successfully applied, otherwise #FLUID_FAILED + * + * This is an optional, additional filter that operates independently from the default low-pass filter required by the Soundfont2 standard. + * By default this filter is off (#FLUID_IIR_DISABLED). + */ +int fluid_synth_set_custom_filter(fluid_synth_t *synth, int type, int flags) +{ + int i; + fluid_voice_t *voice; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_return_val_if_fail(type >= FLUID_IIR_DISABLED && type < FLUID_IIR_LAST, FLUID_FAILED); + + fluid_synth_api_enter(synth); + + synth->custom_filter_type = type; + synth->custom_filter_flags = flags; + + for(i = 0; i < synth->polyphony; i++) + { + voice = synth->voice[i]; + + fluid_voice_set_custom_filter(voice, type, flags); + } + + FLUID_API_RETURN(FLUID_OK); +} + +/** + * Set the important channels for voice overflow priority calculation. + * + * @param synth FluidSynth instance + * @param channels comma-separated list of channel numbers + * @return #FLUID_OK on success, otherwise #FLUID_FAILED + */ +static int fluid_synth_set_important_channels(fluid_synth_t *synth, const char *channels) +{ + int i; + int retval = FLUID_FAILED; + int *values = NULL; + int num_values; + fluid_overflow_prio_t *scores; + + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + + scores = &synth->overflow; + + if(scores->num_important_channels < synth->midi_channels) + { + scores->important_channels = FLUID_REALLOC(scores->important_channels, + sizeof(*scores->important_channels) * synth->midi_channels); + + if(scores->important_channels == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + goto exit; + } + + scores->num_important_channels = synth->midi_channels; + } + + FLUID_MEMSET(scores->important_channels, FALSE, + sizeof(*scores->important_channels) * scores->num_important_channels); + + if(channels != NULL) + { + values = FLUID_ARRAY(int, synth->midi_channels); + + if(values == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + goto exit; + } + + /* Every channel given in the comma-separated list of channel numbers + * is set to TRUE, i.e. flagging it as "important". Channel numbers are + * 1-based. */ + num_values = fluid_settings_split_csv(channels, values, synth->midi_channels); + + for(i = 0; i < num_values; i++) + { + if(values[i] > 0 && values[i] <= synth->midi_channels) + { + scores->important_channels[values[i] - 1] = TRUE; + } + } + } + + retval = FLUID_OK; + +exit: + FLUID_FREE(values); + return retval; +} + +/* + * Handler for synth.overflow.important-channels setting. + */ +static void fluid_synth_handle_important_channels(void *data, const char *name, + const char *value) +{ + fluid_synth_t *synth = (fluid_synth_t *)data; + + fluid_synth_api_enter(synth); + fluid_synth_set_important_channels(synth, value); + fluid_synth_api_exit(synth); +} + + +/* API legato mode *********************************************************/ + +/** + * Sets the legato mode of a channel. + * + * @param synth the synth instance. + * @param chan MIDI channel number (0 to MIDI channel count - 1). + * @param legatomode The legato mode as indicated by #fluid_channel_legato_mode. + * + * @return + * - #FLUID_OK on success. + * - #FLUID_FAILED + * - \a synth is NULL. + * - \a chan is outside MIDI channel count. + * - \a legatomode is invalid. + */ +int fluid_synth_set_legato_mode(fluid_synth_t *synth, int chan, int legatomode) +{ + /* checks parameters first */ + fluid_return_val_if_fail(legatomode >= 0, FLUID_FAILED); + fluid_return_val_if_fail(legatomode < FLUID_CHANNEL_LEGATO_MODE_LAST, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + /**/ + synth->channel[chan]->legatomode = legatomode; + /**/ + FLUID_API_RETURN(FLUID_OK); +} + +/** + * Gets the legato mode of a channel. + * + * @param synth the synth instance. + * @param chan MIDI channel number (0 to MIDI channel count - 1). + * @param legatomode The legato mode as indicated by #fluid_channel_legato_mode. + * + * @return + * - #FLUID_OK on success. + * - #FLUID_FAILED + * - \a synth is NULL. + * - \a chan is outside MIDI channel count. + * - \a legatomode is NULL. + */ +int fluid_synth_get_legato_mode(fluid_synth_t *synth, int chan, int *legatomode) +{ + /* checks parameters first */ + fluid_return_val_if_fail(legatomode != NULL, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + /**/ + * legatomode = synth->channel[chan]->legatomode; + /**/ + FLUID_API_RETURN(FLUID_OK); +} + +/* API portamento mode *********************************************************/ + +/** + * Sets the portamento mode of a channel. + * + * @param synth the synth instance. + * @param chan MIDI channel number (0 to MIDI channel count - 1). + * @param portamentomode The portamento mode as indicated by #fluid_channel_portamento_mode. + * @return + * - #FLUID_OK on success. + * - #FLUID_FAILED + * - \a synth is NULL. + * - \a chan is outside MIDI channel count. + * - \a portamentomode is invalid. + */ +int fluid_synth_set_portamento_mode(fluid_synth_t *synth, int chan, + int portamentomode) +{ + /* checks parameters first */ + fluid_return_val_if_fail(portamentomode >= 0, FLUID_FAILED); + fluid_return_val_if_fail(portamentomode < FLUID_CHANNEL_PORTAMENTO_MODE_LAST, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + /**/ + synth->channel[chan]->portamentomode = portamentomode; + /**/ + FLUID_API_RETURN(FLUID_OK); +} + +/** + * Gets the portamento mode of a channel. + * + * @param synth the synth instance. + * @param chan MIDI channel number (0 to MIDI channel count - 1). + * @param portamentomode Pointer to the portamento mode as indicated by #fluid_channel_portamento_mode. + * @return + * - #FLUID_OK on success. + * - #FLUID_FAILED + * - \a synth is NULL. + * - \a chan is outside MIDI channel count. + * - \a portamentomode is NULL. + */ +int fluid_synth_get_portamento_mode(fluid_synth_t *synth, int chan, + int *portamentomode) +{ + /* checks parameters first */ + fluid_return_val_if_fail(portamentomode != NULL, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + /**/ + * portamentomode = synth->channel[chan]->portamentomode; + /**/ + FLUID_API_RETURN(FLUID_OK); +} + +/* API breath mode *********************************************************/ + +/** + * Sets the breath mode of a channel. + * + * @param synth the synth instance. + * @param chan MIDI channel number (0 to MIDI channel count - 1). + * @param breathmode The breath mode as indicated by #fluid_channel_breath_flags. + * + * @return + * - #FLUID_OK on success. + * - #FLUID_FAILED + * - \a synth is NULL. + * - \a chan is outside MIDI channel count. + */ +int fluid_synth_set_breath_mode(fluid_synth_t *synth, int chan, int breathmode) +{ + /* checks parameters first */ + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + /**/ + fluid_channel_set_breath_info(synth->channel[chan], breathmode); + /**/ + FLUID_API_RETURN(FLUID_OK); +} + +/** + * Gets the breath mode of a channel. + * + * @param synth the synth instance. + * @param chan MIDI channel number (0 to MIDI channel count - 1). + * @param breathmode Pointer to the returned breath mode as indicated by #fluid_channel_breath_flags. + * + * @return + * - #FLUID_OK on success. + * - #FLUID_FAILED + * - \a synth is NULL. + * - \a chan is outside MIDI channel count. + * - \a breathmode is NULL. + */ +int fluid_synth_get_breath_mode(fluid_synth_t *synth, int chan, int *breathmode) +{ + /* checks parameters first */ + fluid_return_val_if_fail(breathmode != NULL, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + /**/ + * breathmode = fluid_channel_get_breath_info(synth->channel[chan]); + /**/ + FLUID_API_RETURN(FLUID_OK); +} + +/** API Poly/mono mode ******************************************************/ + +/* + * Resets a basic channel group of MIDI channels. + * @param synth the synth instance. + * @param chan the beginning channel of the group. + * @param nbr_chan the number of channel in the group. +*/ +static void +fluid_synth_reset_basic_channel_LOCAL(fluid_synth_t *synth, int chan, int nbr_chan) +{ + int i; + + for(i = chan; i < chan + nbr_chan; i++) + { + fluid_channel_reset_basic_channel_info(synth->channel[i]); + synth->channel[i]->mode_val = 0; + } +} + +/** + * Disables and unassigns all channels from a basic channel group. + * + * @param synth The synth instance. + * @param chan The basic channel of the group to reset or -1 to reset all channels. + * @note By default (i.e. on creation after new_fluid_synth() and after fluid_synth_system_reset()) + * a synth instance has one basic channel at channel 0 in mode #FLUID_CHANNEL_MODE_OMNION_POLY. + * All other channels belong to this basic channel group. Make sure to call this function before + * setting any custom basic channel setup. + * + * @return + * - #FLUID_OK on success. + * - #FLUID_FAILED + * - \a synth is NULL. + * - \a chan is outside MIDI channel count. + * - \a chan isn't a basic channel. + */ +int fluid_synth_reset_basic_channel(fluid_synth_t *synth, int chan) +{ + int nbr_chan; + + /* checks parameters first */ + if(chan < 0) + { + fluid_return_val_if_fail(synth != NULL, FLUID_FAILED); + fluid_synth_api_enter(synth); + /* The range is all MIDI channels from 0 to MIDI channel count -1 */ + chan = 0; /* beginning chan */ + nbr_chan = synth->midi_channels; /* MIDI Channels number */ + } + else + { + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + /* checks if chan is a basic channel */ + if(!(synth->channel[chan]->mode & FLUID_CHANNEL_BASIC)) + { + FLUID_API_RETURN(FLUID_FAILED); + } + + /* The range is all MIDI channels in the group from chan */ + nbr_chan = synth->channel[chan]->mode_val; /* nbr of channels in the group */ + } + + /* resets the range of MIDI channels */ + fluid_synth_reset_basic_channel_LOCAL(synth, chan, nbr_chan); + FLUID_API_RETURN(FLUID_OK); +} + +/** + * Checks if a new basic channel group overlaps the next basic channel group. + * + * On success the function returns the possible number of channel for this + * new basic channel group. + * The function fails if the new group overlaps the next basic channel group. + * + * @param see fluid_synth_set_basic_channel. + * @return + * - On success, the effective number of channels for this new basic channel group, + * #FLUID_FAILED otherwise. + * - #FLUID_FAILED + * - \a val has a number of channels overlapping next basic channel group or been + * above MIDI channel count. + */ +static int +fluid_synth_check_next_basic_channel(fluid_synth_t *synth, int basicchan, int mode, int val) +{ + int i, n_chan = synth->midi_channels; /* MIDI Channels count */ + int real_val = val; /* real number of channels in the group */ + + /* adjusts val range */ + if(mode == FLUID_CHANNEL_MODE_OMNIOFF_POLY) + { + real_val = 1; /* mode poly omnioff implies a group of only one channel.*/ + } + else if(val == 0) + { + /* mode poly omnion (0), mono omnion (1), mono omni off (3) */ + /* value 0 means all possible channels from basicchan to MIDI channel count -1.*/ + real_val = n_chan - basicchan; + } + /* checks if val range is above MIDI channel count */ + else if(basicchan + val > n_chan) + { + return FLUID_FAILED; + } + + /* checks if this basic channel group overlaps next basic channel group */ + for(i = basicchan + 1; i < basicchan + real_val; i++) + { + if(synth->channel[i]->mode & FLUID_CHANNEL_BASIC) + { + /* A value of 0 for val means all possible channels from basicchan to + to the next basic channel -1 (if any). + When i reaches the next basic channel group, real_val will be + limited if it is possible */ + if(val == 0) + { + /* limitation of real_val */ + real_val = i - basicchan; + break; + } + + /* overlap with the next basic channel group */ + return FLUID_FAILED; + } + } + + return real_val; +} + +/** + * Sets a new basic channel group only. The function doesn't allow to change an + * existing basic channel. + * + * The function fails if any channel overlaps any existing basic channel group. + * To make room if necessary, basic channel groups can be cleared using + * fluid_synth_reset_basic_channel(). + * + * @param synth the synth instance. + * @param chan the basic Channel number (0 to MIDI channel count-1). + * @param mode the MIDI mode to use for chan (see #fluid_basic_channel_modes). + * @param val number of channels in the group. + * @note \a val is only relevant for mode #FLUID_CHANNEL_MODE_OMNION_POLY, + * #FLUID_CHANNEL_MODE_OMNION_MONO and #FLUID_CHANNEL_MODE_OMNIOFF_MONO. A value + * of 0 means all possible channels from \a chan to to next basic channel minus 1 (if any) + * or to MIDI channel count minus 1. Val is ignored for #FLUID_CHANNEL_MODE_OMNIOFF_POLY + * as this mode implies a group of only one channel. + * @return + * - #FLUID_OK on success. + * - #FLUID_FAILED + * - \a synth is NULL. + * - \a chan is outside MIDI channel count. + * - \a mode is invalid. + * - \a val has a number of channels overlapping another basic channel group or been + * above MIDI channel count. + * - When the function fails, any existing basic channels aren't modified. + */ +int fluid_synth_set_basic_channel(fluid_synth_t *synth, int chan, int mode, int val) +{ + /* check parameters */ + fluid_return_val_if_fail(mode >= 0, FLUID_FAILED); + fluid_return_val_if_fail(mode < FLUID_CHANNEL_MODE_LAST, FLUID_FAILED); + fluid_return_val_if_fail(val >= 0, FLUID_FAILED); + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + /**/ + if(val > 0 && chan + val > synth->midi_channels) + { + FLUID_API_RETURN(FLUID_FAILED); + } + + /* Checks if there is an overlap with the next basic channel */ + val = fluid_synth_check_next_basic_channel(synth, chan, mode, val); + + if(val == FLUID_FAILED || synth->channel[chan]->mode & FLUID_CHANNEL_ENABLED) + { + /* overlap with the next or previous channel group */ + FLUID_LOG(FLUID_INFO, "basic channel %d overlaps another group", chan); + FLUID_API_RETURN(FLUID_FAILED); + } + + /* sets a new basic channel group */ + fluid_synth_set_basic_channel_LOCAL(synth, chan, mode, val); + /**/ + FLUID_API_RETURN(FLUID_OK); +} + +/* + * Local version of fluid_synth_set_basic_channel(), called internally: + * - by fluid_synth_set_basic_channel() to set a new basic channel group. + * - during creation new_fluid_synth() or on CC reset to set a default basic channel group. + * - on CC ominoff, CC omnion, CC poly , CC mono to change an existing basic channel group. + * + * @param see fluid_synth_set_basic_channel() +*/ +static void +fluid_synth_set_basic_channel_LOCAL(fluid_synth_t *synth, int basicchan, int mode, int val) +{ + int i; + + /* sets the basic channel group */ + for(i = basicchan; i < basicchan + val; i++) + { + int new_mode = mode; /* OMNI_OFF/ON, MONO/POLY ,others bits are zero */ + int new_val; + /* MIDI specs: when mode is changed, channel must receive ALL_NOTES_OFF */ + fluid_synth_all_notes_off_LOCAL(synth, i); + + if(i == basicchan) + { + new_mode |= FLUID_CHANNEL_BASIC; /* First channel in the group */ + new_val = val; /* number of channels in the group */ + } + else + { + new_val = 0; /* val is 0 for other channel than basic channel */ + } + + /* Channel is enabled */ + new_mode |= FLUID_CHANNEL_ENABLED; + /* Now new_mode is OMNI OFF/ON,MONO/POLY, BASIC_CHANNEL or not and enabled */ + fluid_channel_set_basic_channel_info(synth->channel[i], new_mode); + synth->channel[i]->mode_val = new_val; + } +} + +/** + * Searches a previous basic channel starting from chan. + * + * @param synth the synth instance. + * @param chan starting index of the search (including chan). + * @return index of the basic channel if found , FLUID_FAILED otherwise. + */ +static int fluid_synth_get_previous_basic_channel(fluid_synth_t *synth, int chan) +{ + for(; chan >= 0; chan--) + { + /* searches previous basic channel */ + if(synth->channel[chan]->mode & FLUID_CHANNEL_BASIC) + { + /* chan is the previous basic channel */ + return chan; + } + } + + return FLUID_FAILED; +} + +/** + * Returns poly mono mode information of any MIDI channel. + * + * @param synth the synth instance + * @param chan MIDI channel number (0 to MIDI channel count - 1) + * @param basic_chan_out Buffer to store the basic channel \a chan belongs to or #FLUID_FAILED if \a chan is disabled. + * @param mode_out Buffer to store the mode of \a chan (see #fluid_basic_channel_modes) or #FLUID_FAILED if \a chan is disabled. + * @param val_out Buffer to store the total number of channels in this basic channel group or #FLUID_FAILED if \a chan is disabled. + * @note If any of \a basic_chan_out, \a mode_out, \a val_out pointer is NULL + * the corresponding information isn't returned. + * + * @return + * - #FLUID_OK on success. + * - #FLUID_FAILED + * - \a synth is NULL. + * - \a chan is outside MIDI channel count. + */ +int fluid_synth_get_basic_channel(fluid_synth_t *synth, int chan, + int *basic_chan_out, + int *mode_out, + int *val_out) +{ + int basic_chan = FLUID_FAILED; + int mode = FLUID_FAILED; + int val = FLUID_FAILED; + + /* checks parameters first */ + FLUID_API_ENTRY_CHAN(FLUID_FAILED); + + if((synth->channel[chan]->mode & FLUID_CHANNEL_ENABLED) && + /* chan is enabled , we search the basic channel chan belongs to */ + (basic_chan = fluid_synth_get_previous_basic_channel(synth, chan)) != FLUID_FAILED) + { + mode = synth->channel[chan]->mode & FLUID_CHANNEL_MODE_MASK; + val = synth->channel[basic_chan]->mode_val; + } + + /* returns the information if they are requested */ + if(basic_chan_out) + { + * basic_chan_out = basic_chan; + } + + if(mode_out) + { + * mode_out = mode; + } + + if(val_out) + { + * val_out = val; + } + + FLUID_API_RETURN(FLUID_OK); +} diff --git a/libs/fluidsynth/src/synth/fluid_synth.h b/libs/fluidsynth/src/synth/fluid_synth.h new file mode 100644 index 00000000000..cb838e92462 --- /dev/null +++ b/libs/fluidsynth/src/synth/fluid_synth.h @@ -0,0 +1,263 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#ifndef _FLUID_SYNTH_H +#define _FLUID_SYNTH_H + + +/*************************************************************** + * + * INCLUDES + */ + +#include "fluid_sys.h" +#include "fluid_list.h" +#include "fluid_rev.h" +#include "fluid_voice.h" +#include "fluid_chorus.h" +#include "fluid_ladspa.h" +#include "fluid_midi_router.h" +#include "fluid_rvoice_event.h" + +/*************************************************************** + * + * DEFINES + */ +#define FLUID_NUM_PROGRAMS 128 +#define DRUM_INST_BANK 128 + +#define FLUID_UNSET_PROGRAM 128 /* Program number used to unset a preset */ + +#define FLUID_REVERB_DEFAULT_ROOMSIZE 0.2f /**< Default reverb room size */ +#define FLUID_REVERB_DEFAULT_DAMP 0.0f /**< Default reverb damping */ +#define FLUID_REVERB_DEFAULT_WIDTH 0.5f /**< Default reverb width */ +#define FLUID_REVERB_DEFAULT_LEVEL 0.9f /**< Default reverb level */ + +#define FLUID_CHORUS_DEFAULT_N 3 /**< Default chorus voice count */ +#define FLUID_CHORUS_DEFAULT_LEVEL 2.0f /**< Default chorus level */ +#define FLUID_CHORUS_DEFAULT_SPEED 0.3f /**< Default chorus speed */ +#define FLUID_CHORUS_DEFAULT_DEPTH 8.0f /**< Default chorus depth */ +#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE /**< Default chorus waveform type */ + +/*************************************************************** + * + * ENUM + */ + +/** + * Bank Select MIDI message styles. Default style is GS. + */ +enum fluid_midi_bank_select +{ + FLUID_BANK_STYLE_GM, /**< GM style, bank = 0 always (CC0/MSB and CC32/LSB ignored) */ + FLUID_BANK_STYLE_GS, /**< GS style, bank = CC0/MSB (CC32/LSB ignored) */ + FLUID_BANK_STYLE_XG, /**< XG style, bank = CC32/LSB (CC0/MSB ignored) */ + FLUID_BANK_STYLE_MMA /**< MMA style bank = 128*MSB+LSB */ +}; + +enum fluid_synth_status +{ + FLUID_SYNTH_CLEAN, + FLUID_SYNTH_PLAYING, + FLUID_SYNTH_QUIET, + FLUID_SYNTH_STOPPED +}; + +#define SYNTH_REVERB_CHANNEL 0 +#define SYNTH_CHORUS_CHANNEL 1 + +/* + * fluid_synth_t + * + * Mutual exclusion notes (as of 1.1.2): + * + * All variables are considered belongning to the "public API" thread, + * which processes all MIDI, except for: + * + * ticks_since_start - atomic, set by rendering thread only + * cpu_load - atomic, set by rendering thread only + * cur, curmax, dither_index - used by rendering thread only + * ladspa_fx - same instance copied in rendering thread. Synchronising handled internally. + * + */ + +struct _fluid_synth_t +{ + fluid_rec_mutex_t mutex; /**< Lock for public API */ + int use_mutex; /**< Use mutex for all public API functions? */ + int public_api_count; /**< How many times the mutex is currently locked */ + + fluid_settings_t *settings; /**< the synthesizer settings */ + int device_id; /**< Device ID used for SYSEX messages */ + int polyphony; /**< Maximum polyphony */ + int with_reverb; /**< Should the synth use the built-in reverb unit? */ + int with_chorus; /**< Should the synth use the built-in chorus unit? */ + int verbose; /**< Turn verbose mode on? */ + double sample_rate; /**< The sample rate */ + int midi_channels; /**< the number of MIDI channels (>= 16) */ + int bank_select; /**< the style of Bank Select MIDI messages */ + int audio_channels; /**< the number of audio channels (1 channel=left+right) */ + int audio_groups; /**< the number of (stereo) 'sub'groups from the synth. + Typically equal to audio_channels. */ + int effects_channels; /**< the number of effects channels (>= 2) */ + int effects_groups; /**< the number of effects units (>= 1) */ + int state; /**< the synthesizer state */ + fluid_atomic_uint_t ticks_since_start; /**< the number of audio samples since the start */ + unsigned int start; /**< the start in msec, as returned by system clock */ + fluid_overflow_prio_t overflow; /**< parameters for overflow priority (aka voice-stealing) */ + + fluid_list_t *loaders; /**< the SoundFont loaders */ + fluid_list_t *sfont; /**< List of fluid_sfont_info_t for each loaded SoundFont (remains until SoundFont is unloaded) */ + int sfont_id; /**< Incrementing ID assigned to each loaded SoundFont */ + fluid_list_t *fonts_to_be_unloaded; /**< list of timers that try to unload a soundfont */ + + float gain; /**< master gain */ + fluid_channel_t **channel; /**< the channels */ + int nvoice; /**< the length of the synthesis process array (max polyphony allowed) */ + fluid_voice_t **voice; /**< the synthesis voices */ + int active_voice_count; /**< count of active voices */ + unsigned int noteid; /**< the id is incremented for every new note. it's used for noteoff's */ + unsigned int storeid; + int fromkey_portamento; /**< fromkey portamento */ + fluid_rvoice_eventhandler_t *eventhandler; + + /**< Shadow of reverb parameter: roomsize, damping, width, level */ + double reverb_param[FLUID_REVERB_PARAM_LAST]; + + /**< Shadow of chorus parameter: chorus number, level, speed, depth, type */ + double chorus_param[FLUID_CHORUS_PARAM_LAST]; + + int cur; /**< the current sample in the audio buffers to be output */ + int curmax; /**< current amount of samples present in the audio buffers */ + int dither_index; /**< current index in random dither value buffer: fluid_synth_(write_s16|dither_s16) */ + + fluid_atomic_float_t cpu_load; /**< CPU load in percent (CPU time required / audio synthesized time * 100) */ + + fluid_tuning_t ***tuning; /**< 128 banks of 128 programs for the tunings */ + fluid_private_t tuning_iter; /**< Tuning iterators per each thread */ + + fluid_sample_timer_t *sample_timers; /**< List of timers triggered before a block is processed */ + unsigned int min_note_length_ticks; /**< If note-offs are triggered just after a note-on, they will be delayed */ + + int cores; /**< Number of CPU cores (1 by default) */ + + fluid_mod_t *default_mod; /**< the (dynamic) list of default modulators */ + + fluid_ladspa_fx_t *ladspa_fx; /**< Effects unit for LADSPA support */ + enum fluid_iir_filter_type custom_filter_type; /**< filter type of the user-defined filter currently used for all voices */ + enum fluid_iir_filter_flags custom_filter_flags; /**< filter type of the user-defined filter currently used for all voices */ +}; + +/** + * Type definition of the synthesizer's audio callback function. + * @param synth FluidSynth instance + * @param len Count of audio frames to synthesize + * @param out1 Array to store left channel of audio to + * @param loff Offset index in 'out1' for first sample + * @param lincr Increment between samples stored to 'out1' + * @param out2 Array to store right channel of audio to + * @param roff Offset index in 'out2' for first sample + * @param rincr Increment between samples stored to 'out2' + */ +typedef int (*fluid_audio_callback_t)(fluid_synth_t *synth, int len, + void *out1, int loff, int lincr, + void *out2, int roff, int rincr); + +typedef int (*fluid_audio_channels_callback_t)(fluid_synth_t *synth, int len, + int channels_count, + void *channels_out[], int channels_off[], + int channels_incr[]); + +int +fluid_synth_write_float_channels_LOCAL(fluid_synth_t *synth, int len, + int channels_count, + void *channels_out[], int channels_off[], + int channels_incr[], + int (*block_render_func)(fluid_synth_t *, int)); + +int +fluid_synth_write_s16_channels(fluid_synth_t *synth, int len, + int channels_count, + void *channels_out[], int channels_off[], + int channels_incr[]); +int +fluid_synth_write_float_channels(fluid_synth_t *synth, int len, + int channels_count, + void *channels_out[], int channels_off[], + int channels_incr[]); + +fluid_preset_t *fluid_synth_find_preset(fluid_synth_t *synth, + int banknum, + int prognum); +void fluid_synth_sfont_unref(fluid_synth_t *synth, fluid_sfont_t *sfont); + +void fluid_synth_dither_s16(int *dither_index, int len, const float *lin, const float *rin, + void *lout, int loff, int lincr, + void *rout, int roff, int rincr); + +int fluid_synth_reset_reverb(fluid_synth_t *synth); +int fluid_synth_set_reverb_preset(fluid_synth_t *synth, unsigned int num); +int fluid_synth_reverb_set_param(fluid_synth_t *synth, int fx_group, + int param, + double value); +int fluid_synth_set_reverb_full(fluid_synth_t *synth, int fx_group, int set, + const double values[]); + +int fluid_synth_reset_chorus(fluid_synth_t *synth); +int fluid_synth_chorus_set_param(fluid_synth_t *synth, int fx_group, + int param, double value); +int fluid_synth_set_chorus_full(fluid_synth_t *synth, int fx_group, int set, + const double values[]); + +fluid_sample_timer_t *new_fluid_sample_timer(fluid_synth_t *synth, fluid_timer_callback_t callback, void *data); +void delete_fluid_sample_timer(fluid_synth_t *synth, fluid_sample_timer_t *timer); +void fluid_sample_timer_reset(fluid_synth_t *synth, fluid_sample_timer_t *timer); + +void fluid_synth_process_event_queue(fluid_synth_t *synth); + +int +fluid_synth_process_LOCAL(fluid_synth_t *synth, int len, int nfx, float *fx[], + int nout, float *out[], int (*block_render_func)(fluid_synth_t *, int)); +int +fluid_synth_write_float_LOCAL(fluid_synth_t *synth, int len, + void *lout, int loff, int lincr, + void *rout, int roff, int rincr, + int (*block_render_func)(fluid_synth_t *, int)); +/* + * misc + */ +void fluid_synth_settings(fluid_settings_t *settings); +void fluid_synth_set_sample_rate_immediately(fluid_synth_t *synth, float sample_rate); + + +/* extern declared in fluid_synth_monopoly.c */ + +int fluid_synth_noteon_mono_staccato(fluid_synth_t *synth, int chan, int key, int vel); +int fluid_synth_noteon_mono_LOCAL(fluid_synth_t *synth, int chan, int key, int vel); +int fluid_synth_noteoff_mono_LOCAL(fluid_synth_t *synth, int chan, int key); +int fluid_synth_noteon_monopoly_legato(fluid_synth_t *synth, int chan, int fromkey, int tokey, int vel); +int fluid_synth_noteoff_monopoly(fluid_synth_t *synth, int chan, int key, char Mono); + +fluid_voice_t * +fluid_synth_alloc_voice_LOCAL(fluid_synth_t *synth, fluid_sample_t *sample, int chan, int key, int vel, fluid_zone_range_t *zone_range); + +void fluid_synth_release_voice_on_same_note_LOCAL(fluid_synth_t *synth, int chan, int key); +#endif /* _FLUID_SYNTH_H */ diff --git a/libs/fluidsynth/src/synth/fluid_synth_monopoly.c b/libs/fluidsynth/src/synth/fluid_synth_monopoly.c new file mode 100644 index 00000000000..d1de13196ec --- /dev/null +++ b/libs/fluidsynth/src/synth/fluid_synth_monopoly.c @@ -0,0 +1,722 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include "fluid_synth.h" +#include "fluid_chan.h" +#include "fluid_defsfont.h" + + +/****************************************************************************** + The legato detector is composed as this, + variables: + - monolist: monophonic list variable. + - prev_note: to store the most recent note before adding on noteon or before + removing on noteoff. + - FLUID_CHANNEL_LEGATO_PLAYING: legato/staccato state bit that informs on + legato or staccato playing. + functions: + - fluid_channel_add_monolist(), for inserting a new note. + - fluid_channel_search_monolist(), for searching the position of a note + into the list. + - fluid_channel_remove_monolist(), for removing a note from the list. + + The monophonic list + +------------------------------------------------+ + | +----+ +----+ +----+ +----+ | + | |note| |note| |note| |note| | + +--->|vel |-->|vel |-->....-->|vel |-->|vel |----+ + +----+ +----+ +----+ +----+ + /|\ /|\ + | | + i_first i_last + + The list allows an easy automatic detection of a legato passage when it is + played on a MIDI keyboard input device. + It is useful also when the input device is an ewi (electronic wind instrument) + or evi (electronic valve instrument) and these instruments are unable to send + MIDI CC legato on/off. + + The list memorizes the notes in playing order. + - (a) On noteOn n2, if a previous note n1 exists, there is a legato + detection with n1 (with or without portamento from n1 to n2 See note below). + - (b) On noteOff of the running note n2, if a previous note n1 exists, + there is a legato detection from n2 to n1, allowing fast trills playing + (with or without portamento from n2 to n1. See note below). + + Notes in the list are inserted to the end of the list that works like a + circular buffer.The features are: + + 1) It is always possible to play an infinite legato passage in + direct order (n1_On,n2_On,n3_On,....). + + 2) Playing legato in the reverse order (n10_Off, n9_Off,,...) helps in + fast trills playing as the list memorizes 10 most recent notes. + + 3) Playing an infinite lagato passage in ascendant or descendant order, + without playing trills is always possible using the usual way like this: + First we begin with an ascendant passage, + n1On, (n2On,n1Off), (n3On,n2Off) , (n4On,n3Off), then + we continue with a descendant passage + (n3On,n4off), (n2On,n3off), (n1On,n2off), n1Off...and so on + + Each MIDI channel have a legato detector. + + Note: + Portamento is a feature independent of the legato detector. So + portamento isn't part of the lagato detector. However portamento + (when enabled) is triggered at noteOn (like legato). Like in legato + situation it is usual to have a portamento from a note 'fromkey' to another + note 'tokey'. Portamento fromkey note choice is determined at noteOn by + fluid_synth_get_fromkey_portamento_legato() (see below). + + More information in FluidPolyMono-0004.pdf chapter 4 (Appendices). +******************************************************************************/ + + +/***************************************************************************** + Portamento related functions in Poly or Mono mode +******************************************************************************/ + +/** + * fluid_synth_get_fromkey_portamento_legato returns two information: + * - fromkey note for portamento. + * - fromkey note for legato. + * +-----> fromkey_portamento + * ______|________ + * portamento modes >------->| | + * | get_fromkey | + * Porta.on/off >------------------------->|_______________| + * (PTC) | + * +-----> fromkey_legato + * + * The functions is intended to be call on noteOn mono + * see fluid_synth_noteon_mono_staccato(), fluid_synth_noteon_monopoly_legato() + * ------- + * 1)The function determines if a portamento must occur on next noteOn. + * The value returned is 'fromkey portamento' which is the pitchstart key + * of a portamento, as function of PTC or (default_fromkey, prev_note) both + * if Portamento On. By order of precedence the result is: + * 1.1) PTC have precedence over Portamento On. + * If CC PTC has been received, its value supersedes and any + * portamento pedal On, default_fromkey,prev_note or portamento mode. + * 1.2) Otherwise ,when Portamento On the function takes the following value: + * - default_fromkey if valid + * - otherwise prev_note(prev_note is the note prior the most recent + * note played). + * Then portamento mode is applied to validate the value chosen. + * Where portamento mode is: + * - each note, a portamento occurs on each note. + * - legato only, portamento only on notes played legato. + * - staccato only, portamento only on notes played staccato. + * 1.3) Otherwise, portamento is off,INVALID_NOTE is returned (portamento is disabled). + * ------ + * 2)The function determines if a legato playing must occur on next noteOn. + * 'fromkey legato note' is returned as a function of default_fromkey, PTC, + * current mono/poly mode,actual 'staccato/legato' playing state and prev_note. + * By order of precedence the result is: + * 2.1) If valid, default_fromkey have precedence over any others values. + * 2.2) Otherwise if CC PTC has been received its value is returned. + * 2.3) Otherwise fromkey legato is determined from the mono/poly mode, + * the actual 'staccato/legato' playing state (FLUID_CHANNEL_LEGATO_PLAYING) and prev_note + * as this: + * - in (poly/Mono) staccato , INVALID_NOTE is returned. + * - in poly legato , actually we don't want playing legato. So + * INVALID_NOTE is returned. + * - in mono legato , prev_note is returned. + * + * On input + * @param chan fluid_channel_t. + * @param defaultFromkey, the default 'fromkey portamento' note or 'fromkey legato' + * note (see description above). + * + * @return + * 1)'fromkey portamento' is returned in fluid_synth_t.fromkey_portamento. + * If valid,it means that portamento is enabled . + * + * 2)The 'fromkey legato' note is returned. + * + * Notes about usage: + * The function is intended to be called when the following event occurs: + * - On noteOn (Poly or Mono) after insertion in the monophonic list. + * - On noteOff(mono legato playing). In this case, default_fromkey must be valid. + * + * Typical calling usage: + * - In poly, default_fromkey must be INVALID_NOTE. + * - In mono staccato playing,default_fromkey must be INVALID_NOTE. + * - In mono legato playing,default_fromkey must be valid. + */ +static char fluid_synth_get_fromkey_portamento_legato(fluid_channel_t *chan, + int default_fromkey) +{ + unsigned char ptc = fluid_channel_get_cc(chan, PORTAMENTO_CTRL); + + if(fluid_channel_is_valid_note(ptc)) + { + /* CC PTC has been received */ + fluid_channel_clear_portamento(chan); /* clears the CC PTC receive */ + chan->synth->fromkey_portamento = ptc;/* returns fromkey portamento */ + + /* returns fromkey legato */ + if(!fluid_channel_is_valid_note(default_fromkey)) + { + default_fromkey = ptc; + } + } + else + { + /* determines and returns fromkey portamento */ + unsigned char fromkey_portamento = INVALID_NOTE; + + if(fluid_channel_portamento(chan)) + { + /* Portamento when Portamento pedal is On */ + /* 'fromkey portamento'is determined from the portamento mode + and the most recent note played (prev_note)*/ + enum fluid_channel_portamento_mode portamentomode = chan->portamentomode; + + if(fluid_channel_is_valid_note(default_fromkey)) + { + fromkey_portamento = default_fromkey; /* on each note */ + } + else + { + fromkey_portamento = fluid_channel_prev_note(chan); /* on each note */ + } + + if(portamentomode == FLUID_CHANNEL_PORTAMENTO_MODE_LEGATO_ONLY) + { + /* Mode portamento:legato only */ + if(!(chan->mode & FLUID_CHANNEL_LEGATO_PLAYING)) + { + fromkey_portamento = INVALID_NOTE; + } + } + else if(portamentomode == FLUID_CHANNEL_PORTAMENTO_MODE_STACCATO_ONLY) + { + /* Mode portamento:staccato only */ + if(chan->mode & FLUID_CHANNEL_LEGATO_PLAYING) + { + fromkey_portamento = INVALID_NOTE; + } + } + + /* else Mode portamento: on each note (staccato/legato) */ + } + + /* Returns fromkey portamento */ + chan->synth->fromkey_portamento = fromkey_portamento; + + /* Determines and returns fromkey legato */ + if(!fluid_channel_is_valid_note(default_fromkey)) + { + /* in staccato (poly/Mono) returns INVALID_NOTE */ + /* In mono mode legato playing returns the note prior most + recent note played */ + if(fluid_channel_is_playing_mono(chan) && (chan->mode & FLUID_CHANNEL_LEGATO_PLAYING)) + { + default_fromkey = fluid_channel_prev_note(chan); /* note prior last note */ + } + + /* In poly mode legato playing, actually we don't want playing legato. + So returns INVALID_NOTE */ + } + } + + return default_fromkey; /* Returns legato fromkey */ +} + +/***************************************************************************** + noteon - noteoff functions in Mono mode +******************************************************************************/ +/* + * noteon - noteoff on a channel in "monophonic playing". + * + * A channel needs to be played monophonic if this channel has been set in + * monophonic mode by basic channel API.(see fluid_synth_polymono.c). + * A channel needs also to be played monophonic if it has been set in + * polyphonic mode and legato pedal is On during the playing. + * When a channel is in "monophonic playing" state, only one note at a time can be + * played in a staccato or legato manner (with or without portamento). + * More information in FluidPolyMono-0004.pdf chapter 4 (Appendices). + * _______________ + * ________________ | noteon | + * | legato detector| O-->| mono_staccato |--*-> preset_noteon + * noteon_mono ->| (add_monolist) |--O-- |_______________| | (with or without) + * LOCAL |________________| O /|\ | (portamento) + * /|\ set_onenote | | fromkey | + * | | | portamento| + * noteOn poly >---*------------------* | | + * | | | + * | _____ |________ | + * portamento modes >--- | ->| | | + * | | get_fromkey | | + * Porta.on/off >--------------------- | ->|_______________| | + * (PTC) | | | + * | fromkey | fromkey | + * | legato | portamento| + * | _____\|/_______ | + * *-->| noteon |--/ + * | | monopoly | + * | | legato |----> voices + * legato modes >------- | ->|_______________| triggering + * | (with or without) + * | (portamento) + * | + * | + * noteOff poly >---*----------------- | ---------+ + * | clear | | + * _\|/_____________ | | + * | legato detector | O | + * noteoff_mono->|(search_monolist)|-O-- _____\|/_______ + * LOCAL |(remove_monolist)| O-->| noteoff | + * |_________________| | monopoly |----> noteoff + * Sust.on/off >------------------------->|_______________| + * Sost.on/off +------------------------------------------------------------------------------*/ + +/** + * Plays a noteon event for a Synth instance in "monophonic playing" state. + * Please see the description above about "monophonic playing". + * _______________ + * ________________ | noteon | + * | legato detector| O-->| mono_staccato |--->preset_noteon + * noteon_mono ->| (add_monolist) |--O-- |_______________| + * LOCAL |________________| O + * | + * | + * | + * | + * | + * | + * | + * | + * | + * | _______________ + * | | noteon | + * +-->| monopoly | + * | legato |---> voices + * |_______________| triggering + * + * The function uses the legato detector (see above) to determine if the note must + * be played staccato or legato. + * + * @param synth instance. + * @param chan MIDI channel number (0 to MIDI channel count - 1). + * @param key MIDI note number (0-127). + * @param vel MIDI velocity (0-127). + * @return FLUID_OK on success, FLUID_FAILED otherwise. + */ +int fluid_synth_noteon_mono_LOCAL(fluid_synth_t *synth, int chan, + int key, int vel) +{ + fluid_channel_t *channel = synth->channel[chan]; + + /* Adds the note into the monophonic list */ + fluid_channel_add_monolist(channel, key, vel, 0); + + /* in Breath Sync mode, the noteon triggering is postponed + until the musician starts blowing in the breath controller */ + if(!(channel->mode & FLUID_CHANNEL_BREATH_SYNC) || + fluid_channel_breath_msb(channel)) + { + /* legato/staccato playing detection */ + if(channel->mode & FLUID_CHANNEL_LEGATO_PLAYING) + { + /* legato playing */ + /* legato from prev_note to key */ + /* the voices from prev_note key number are to be used to play key number */ + /* fromkey must be valid */ + return fluid_synth_noteon_monopoly_legato(synth, chan, + fluid_channel_prev_note(channel), key, vel); + } + else + { + /* staccato playing */ + return fluid_synth_noteon_mono_staccato(synth, chan, key, vel); + } + } + else + { + return FLUID_OK; + } +} + +/** + * Plays a noteoff event for a Synth instance in "monophonic playing" state. + * Please see the description above about "monophonic playing" + * + * _______________ + * | noteon | + * +-->| monopoly | + * | | legato |----> voices + * | |_______________| triggering + * | (with or without) + * | (portamento) + * | + * | + * | + * | + * | + * | + * _________________ | + * | legato detector | O + * noteoff_mono->|(search_monolist)|-O-- _______________ + * LOCAL |(remove_monolist)| O-->| noteoff | + * |_________________| | monopoly |----> noteoff + * |_______________| + * + * The function uses the legato detector (see above) to determine if the noteoff must + * be played staccato or legato. + * + * @param synth instance. + * @param chan MIDI channel number (0 to MIDI channel count - 1). + * @param key MIDI note number (0-127). + * @return FLUID_OK on success, FLUID_FAILED otherwise. + */ +int fluid_synth_noteoff_mono_LOCAL(fluid_synth_t *synth, int chan, int key) +{ + int status; + int i, i_prev; + fluid_channel_t *channel = synth->channel[chan]; + /* searching the note in the monophonic list */ + i = fluid_channel_search_monolist(channel, key, &i_prev); + + if(i >= 0) + { + /* the note is in the monophonic list */ + /* Removes the note from the monophonic list */ + fluid_channel_remove_monolist(channel, i, &i_prev); + + /* in Breath Sync mode, the noteoff triggering is done + if the musician is blowing in the breath controller */ + if(!(channel->mode & FLUID_CHANNEL_BREATH_SYNC) || + fluid_channel_breath_msb(channel)) + { + /* legato playing detection */ + if(channel->mode & FLUID_CHANNEL_LEGATO_PLAYING) + { + /* the list contains others notes */ + if(i_prev >= 0) + { + /* legato playing detection on noteoff */ + /* legato from key to i_prev key */ + /* the voices from key number are to be used to + play i_prev key number. */ + status = fluid_synth_noteon_monopoly_legato(synth, chan, + key, channel->monolist[i_prev].note, + channel->monolist[i_prev].vel); + } + /* else the note doesn't need to be played off */ + else + { + status = FLUID_OK; + } + } + else + { + /* the monophonic list is empty */ + /* plays the monophonic note noteoff and eventually held + by sustain/sostenuto */ + status = fluid_synth_noteoff_monopoly(synth, chan, key, 1); + } + } + else + { + status = FLUID_OK; + } + } + else + { + /* the note is not found in the list so the note was + played On when the channel was in polyphonic playing */ + /* plays the noteoff as for polyphonic */ + status = fluid_synth_noteoff_monopoly(synth, chan, key, 0); + } + + return status; +} + +/*---------------------------------------------------------------------------- + staccato playing +-----------------------------------------------------------------------------*/ +/** + * Plays noteon for a monophonic note in staccato manner. + * Please see the description above about "monophonic playing". + * _______________ + * | noteon | + * noteon_mono >------------------------>| mono_staccato |----> preset_noteon + * |_______________| (with or without) + * LOCAL /|\ (portamento) + * | fromkey + * | portamento + * | + * | + * ______|________ + * portamento modes >----->| | + * | get_fromkey | + * Porta.on/off >----------------------->|_______________| + * Portamento + * (PTC) + * + * We are in staccato situation (where no previous note have been depressed). + * Before the note been passed to fluid_preset_noteon(), the function must determine + * the from_key_portamento parameter used by fluid_preset_noteon(). + * + * from_key_portamento is returned by fluid_synth_get_fromkey_portamento_legato() function. + * fromkey_portamento is set to valid/invalid key value depending of the portamento + * modes (see portamento mode API) , CC portamento On/Off , and CC portamento control + * (PTC). + * + * @param synth instance. + * @param chan MIDI channel number (0 to MIDI channel count - 1). + * @param key MIDI note number (0-127). + * @param vel MIDI velocity (0-127). + * @return FLUID_OK on success, FLUID_FAILED otherwise. + */ +int +fluid_synth_noteon_mono_staccato(fluid_synth_t *synth, int chan, int key, int vel) +{ + fluid_channel_t *channel = synth->channel[chan]; + + /* Before playing a new note, if a previous monophonic note is currently + sustained it needs to be released */ + fluid_synth_release_voice_on_same_note_LOCAL(synth, chan, channel->key_mono_sustained); + /* Get possible 'fromkey portamento' */ + fluid_synth_get_fromkey_portamento_legato(channel, INVALID_NOTE); + /* The note needs to be played by voices allocation */ + return fluid_preset_noteon(channel->preset, synth, chan, key, vel); +} + +/** + * Plays noteoff for a polyphonic or monophonic note + * Please see the description above about "monophonic playing". + * + * + * noteOff poly >---------------------------------+ + * | + * | + * | + * noteoff_mono _____\|/_______ + * LOCAL >------------------------->| noteoff | + * | monopoly |----> noteoff + * Sust.on/off >------------------------->|_______________| + * Sost.on/off + * + * The function has the same behaviour when the noteoff is poly of mono, except + * that for mono noteoff, if any pedal (sustain or sostenuto ) is depressed, the + * key is memorized. This is necessary when the next mono note will be played + * staccato, as any current mono note currently sustained will need to be released + * (see fluid_synth_noteon_mono_staccato()). + * Note also that for a monophonic legato passage, the function is called only when + * the last noteoff of the passage occurs. That means that if sustain or sostenuto + * is depressed, only the last note of a legato passage will be sustained. + * + * @param synth instance. + * @param chan MIDI channel number (0 to MIDI channel count - 1). + * @param key MIDI note number (0-127). + * @param Mono, 1 noteoff on monophonic note. + * 0 noteoff on polyphonic note. + * @return FLUID_OK on success, FLUID_FAILED otherwise. + * + * Note: On return, on monophonic, possible sustained note is memorized in + * key_mono_sustained. Memorization is done here on noteOff. + */ +int fluid_synth_noteoff_monopoly(fluid_synth_t *synth, int chan, int key, + char Mono) +{ + int status = FLUID_FAILED; + fluid_voice_t *voice; + int i; + fluid_channel_t *channel = synth->channel[chan]; + + /* Key_sustained is prepared to return no note sustained (INVALID_NOTE) */ + if(Mono) + { + channel->key_mono_sustained = INVALID_NOTE; /* no mono note sustained */ + } + + /* noteoff for all voices with same chan and same key */ + for(i = 0; i < synth->polyphony; i++) + { + voice = synth->voice[i]; + + if(fluid_voice_is_on(voice) && + fluid_voice_get_channel(voice) == chan && + fluid_voice_get_key(voice) == key) + { + if(synth->verbose) + { + int used_voices = 0; + int k; + + for(k = 0; k < synth->polyphony; k++) + { + if(!_AVAILABLE(synth->voice[k])) + { + used_voices++; + } + } + + FLUID_LOG(FLUID_INFO, "noteoff\t%d\t%d\t%d\t%05d\t%.3f\t%d", + fluid_voice_get_channel(voice), fluid_voice_get_key(voice), 0, + fluid_voice_get_id(voice), + (fluid_curtime() - synth->start) / 1000.0f, + used_voices); + } /* if verbose */ + + fluid_voice_noteoff(voice); + + /* noteoff on monophonic note */ + /* Key memorization if the note is sustained */ + if(Mono && + (fluid_voice_is_sustained(voice) || fluid_voice_is_sostenuto(voice))) + { + channel->key_mono_sustained = key; + } + + status = FLUID_OK; + } /* if voice on */ + } /* for all voices */ + + return status; +} + +/*---------------------------------------------------------------------------- + legato playing +-----------------------------------------------------------------------------*/ +/** + * Plays noteon for a monophonic note played legato. + * Please see the description above about "monophonic playing". + * + * + * _______________ + * portamento modes >----->| | + * | get_fromkey | + * Porta.on/off >----------------------->|_______________| + * Portamento | + * (PTC) | +-->preset_noteon + * fromkey | fromkey | (with or without) + * legato | portamento| (portamento) + * _____\|/_______ | + * | noteon |--+ + * noteon_mono >------------------------>| monopoly | + * LOCAL | legato |----->voices + * |_______________| triggering + * /|\ (with or without) + * | (portamento) + * legato modes >-----------------+ + * + * We are in legato situation (where a previous note has been depressed). + * The function must determine the from_key_portamento and from_key_legato parameters + * used respectively by fluid_preset_noteon() function and voices triggering functions. + * + * from_key_portamento and from_key_legato are returned by + * fluid_synth_get_fromkey_portamento_legato() function. + * fromkey_portamento is set to valid/invalid key value depending of the portamento + * modes (see portamento mode API), CC portamento On/Off, and CC portamento control + * (PTC). + * Then, depending of the legato modes (see legato mode API), the function will call + * the appropriate triggering functions. + * @param synth instance. + * @param chan MIDI channel number (0 to MIDI channel count - 1). + * @param fromkey MIDI note number (0-127). + * @param tokey MIDI note number (0-127). + * @param vel MIDI velocity (0-127). + * @return FLUID_OK on success, FLUID_FAILED otherwise. + * + * Note: The voices with key 'fromkey' are to be used to play key 'tokey'. + * The function is able to play legato through Preset Zone(s) (PZ) and + * Instrument Zone(s) (IZ) as far as possible. + * When key tokey is outside the current Instrument Zone, Preset Zone, + * current 'fromkey' voices are released. If necessary new voices + * are restarted when tokey enters inside new Instrument(s) Zones,Preset Zone(s). + * More information in FluidPolyMono-0004.pdf chapter 4.7 (Appendices). + */ +int fluid_synth_noteon_monopoly_legato(fluid_synth_t *synth, int chan, + int fromkey, int tokey, int vel) +{ + fluid_channel_t *channel = synth->channel[chan]; + enum fluid_channel_legato_mode legatomode = channel->legatomode; + fluid_voice_t *voice; + int i ; + /* Gets possible 'fromkey portamento' and possible 'fromkey legato' note */ + fromkey = fluid_synth_get_fromkey_portamento_legato(channel, fromkey); + + if(fluid_channel_is_valid_note(fromkey)) + { + for(i = 0; i < synth->polyphony; i++) + { + /* searching fromkey voices: only those who don't have 'note off' */ + voice = synth->voice[i]; + + if(fluid_voice_is_on(voice) && + fluid_voice_get_channel(voice) == chan && + fluid_voice_get_key(voice) == fromkey) + { + fluid_zone_range_t *zone_range = voice->zone_range; + + /* Ignores voice when there is no instrument zone (i.e no zone_range). Otherwise + checks if tokey is inside the range of the running voice */ + if(zone_range && fluid_zone_inside_range(zone_range, tokey, vel)) + { + switch(legatomode) + { + case FLUID_CHANNEL_LEGATO_MODE_RETRIGGER: /* mode 0 */ + fluid_voice_release(voice); /* normal release */ + break; + + case FLUID_CHANNEL_LEGATO_MODE_MULTI_RETRIGGER: /* mode 1 */ + /* Skip in attack section */ + fluid_voice_update_multi_retrigger_attack(voice, tokey, vel); + + /* Starts portamento if enabled */ + if(fluid_channel_is_valid_note(synth->fromkey_portamento)) + { + /* Sends portamento parameters to the voice dsp */ + fluid_voice_update_portamento(voice, + synth->fromkey_portamento, + tokey); + } + + /* The voice is now used to play tokey in legato manner */ + /* Marks this Instrument Zone to be ignored during next + fluid_preset_noteon() */ + zone_range->ignore = TRUE; + break; + + default: /* Invalid mode: this should never happen */ + FLUID_LOG(FLUID_WARN, "Failed to execute legato mode: %d", + legatomode); + return FLUID_FAILED; + } + } + else + { + /* tokey note is outside the voice range, so the voice is released */ + fluid_voice_release(voice); + } + } + } + } + + /* May be,tokey will enter in new others Insrument Zone(s),Preset Zone(s), in + this case it needs to be played by voices allocation */ + return fluid_preset_noteon(channel->preset, synth, chan, tokey, vel); +} diff --git a/libs/fluidsynth/src/synth/fluid_tuning.c b/libs/fluidsynth/src/synth/fluid_tuning.c new file mode 100644 index 00000000000..0df248b7bfb --- /dev/null +++ b/libs/fluidsynth/src/synth/fluid_tuning.c @@ -0,0 +1,190 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#include "fluid_tuning.h" +#include "fluid_sys.h" + + +fluid_tuning_t *new_fluid_tuning(const char *name, int bank, int prog) +{ + fluid_tuning_t *tuning; + int i; + + tuning = FLUID_NEW(fluid_tuning_t); + + if(tuning == NULL) + { + FLUID_LOG(FLUID_PANIC, "Out of memory"); + return NULL; + } + + FLUID_MEMSET(tuning, 0, sizeof(fluid_tuning_t)); + + if(fluid_tuning_set_name(tuning, name) != FLUID_OK) + { + delete_fluid_tuning(tuning); + return NULL; + } + + tuning->bank = bank; + tuning->prog = prog; + + for(i = 0; i < 128; i++) + { + tuning->pitch[i] = i * 100.0; + } + + fluid_atomic_int_set(&tuning->refcount, 1); /* Start with a refcount of 1 */ + + return tuning; +} + +/* Duplicate a tuning */ +fluid_tuning_t * +fluid_tuning_duplicate(fluid_tuning_t *tuning) +{ + fluid_tuning_t *new_tuning; + int i; + + new_tuning = FLUID_NEW(fluid_tuning_t); + + if(!new_tuning) + { + FLUID_LOG(FLUID_PANIC, "Out of memory"); + return NULL; + } + + FLUID_MEMSET(new_tuning, 0, sizeof(fluid_tuning_t)); + + if(fluid_tuning_set_name(new_tuning, tuning->name) != FLUID_OK) + { + delete_fluid_tuning(new_tuning); + return NULL; + } + + new_tuning->bank = tuning->bank; + new_tuning->prog = tuning->prog; + + for(i = 0; i < 128; i++) + { + new_tuning->pitch[i] = tuning->pitch[i]; + } + + fluid_atomic_int_set(&new_tuning->refcount, 1); /* Start with a refcount of 1 */ + + return new_tuning; +} + +void +delete_fluid_tuning(fluid_tuning_t *tuning) +{ + fluid_return_if_fail(tuning != NULL); + + FLUID_FREE(tuning->name); + FLUID_FREE(tuning); +} + +/* Add a reference to a tuning object */ +void +fluid_tuning_ref(fluid_tuning_t *tuning) +{ + fluid_return_if_fail(tuning != NULL); + + fluid_atomic_int_inc(&tuning->refcount); +} + +/* Unref a tuning object, when it reaches 0 it is deleted, returns TRUE if deleted */ +int +fluid_tuning_unref(fluid_tuning_t *tuning, int count) +{ + fluid_return_val_if_fail(tuning != NULL, FALSE); + + /* Add and compare are separate, but that is OK, since refcount will only + * reach 0 when there are no references and therefore no possibility of + * another thread adding a reference in between */ + fluid_atomic_int_add(&tuning->refcount, -count); + + /* Delete when refcount reaches 0 */ + if(!fluid_atomic_int_get(&tuning->refcount)) + { + delete_fluid_tuning(tuning); + return TRUE; + } + else + { + return FALSE; + } +} + +int fluid_tuning_set_name(fluid_tuning_t *tuning, const char *name) +{ + if(tuning->name != NULL) + { + FLUID_FREE(tuning->name); + tuning->name = NULL; + } + + if(name != NULL) + { + tuning->name = FLUID_STRDUP(name); + + if(tuning->name == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FLUID_FAILED; + } + } + + return FLUID_OK; +} + +char *fluid_tuning_get_name(fluid_tuning_t *tuning) +{ + return tuning->name; +} + +void fluid_tuning_set_octave(fluid_tuning_t *tuning, const double *pitch_deriv) +{ + int i; + + for(i = 0; i < 128; i++) + { + tuning->pitch[i] = i * 100.0 + pitch_deriv[i % 12]; + } +} + +void fluid_tuning_set_all(fluid_tuning_t *tuning, const double *pitch) +{ + int i; + + for(i = 0; i < 128; i++) + { + tuning->pitch[i] = pitch[i]; + } +} + +void fluid_tuning_set_pitch(fluid_tuning_t *tuning, int key, double pitch) +{ + if((key >= 0) && (key < 128)) + { + tuning->pitch[key] = pitch; + } +} diff --git a/libs/fluidsynth/src/synth/fluid_tuning.h b/libs/fluidsynth/src/synth/fluid_tuning.h new file mode 100644 index 00000000000..542d2ced68f --- /dev/null +++ b/libs/fluidsynth/src/synth/fluid_tuning.h @@ -0,0 +1,69 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +/* + + More information about micro tuning can be found at: + + https://www.midi.org/about-midi/tuning.htm + https://www.midi.org/about-midi/tuning-scale.htm + https://www.midi.org/about-midi/tuning_extens.htm + +*/ + +#ifndef _FLUID_TUNING_H +#define _FLUID_TUNING_H + +#include "fluidsynth_priv.h" + +struct _fluid_tuning_t +{ + char *name; + int bank; + int prog; + double pitch[128]; /* the pitch of every key, in cents */ + fluid_atomic_int_t refcount; /* Tuning reference count */ +}; + +fluid_tuning_t *new_fluid_tuning(const char *name, int bank, int prog); +void delete_fluid_tuning(fluid_tuning_t *tuning); +fluid_tuning_t *fluid_tuning_duplicate(fluid_tuning_t *tuning); +void fluid_tuning_ref(fluid_tuning_t *tuning); +int fluid_tuning_unref(fluid_tuning_t *tuning, int count); + +int fluid_tuning_set_name(fluid_tuning_t *tuning, const char *name); +char *fluid_tuning_get_name(fluid_tuning_t *tuning); + +#define fluid_tuning_get_bank(_t) ((_t)->bank) +#define fluid_tuning_get_prog(_t) ((_t)->prog) + +void fluid_tuning_set_pitch(fluid_tuning_t *tuning, int key, double pitch); +#define fluid_tuning_get_pitch(_t, _key) ((_t)->pitch[_key]) + +void fluid_tuning_set_octave(fluid_tuning_t *tuning, const double *pitch_deriv); + +void fluid_tuning_set_all(fluid_tuning_t *tuning, const double *pitch); +#define fluid_tuning_get_all(_t) (&(_t)->pitch[0]) + + + + +#endif /* _FLUID_TUNING_H */ diff --git a/libs/fluidsynth/src/synth/fluid_voice.c b/libs/fluidsynth/src/synth/fluid_voice.c new file mode 100644 index 00000000000..2361e78c18d --- /dev/null +++ b/libs/fluidsynth/src/synth/fluid_voice.c @@ -0,0 +1,2051 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include "fluid_sys.h" +#include "fluid_voice.h" +#include "fluid_mod.h" +#include "fluid_chan.h" +#include "fluid_conv.h" +#include "fluid_synth.h" +#include "fluid_sys.h" +#include "fluid_sfont.h" +#include "fluid_rvoice_event.h" +#include "fluid_defsfont.h" + +/* used for filter turn off optimization - if filter cutoff is above the + specified value and filter q is below the other value, turn filter off */ +#define FLUID_MAX_AUDIBLE_FILTER_FC 19000.0f +#define FLUID_MIN_AUDIBLE_FILTER_Q 1.2f + +/* min vol envelope release (to stop clicks) in SoundFont timecents */ +#define FLUID_MIN_VOLENVRELEASE -7200.0f /* ~16ms */ + + +static const int32_t INT24_MAX = (1 << (16 + 8 - 1)); + +static int fluid_voice_calculate_runtime_synthesis_parameters(fluid_voice_t *voice); +static int calculate_hold_decay_buffers(fluid_voice_t *voice, int gen_base, + int gen_key2base, int is_decay); +static fluid_real_t +fluid_voice_get_lower_boundary_for_attenuation(fluid_voice_t *voice); + +#define UPDATE_RVOICE0(proc) \ + do { \ + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; \ + fluid_rvoice_eventhandler_push(voice->eventhandler, proc, voice->rvoice, param); \ + } while (0) + +#define UPDATE_RVOICE_GENERIC_R1(proc, obj, rarg) \ + do { \ + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; \ + param[0].real = rarg; \ + fluid_rvoice_eventhandler_push(voice->eventhandler, proc, obj, param); \ + } while (0) + +#define UPDATE_RVOICE_GENERIC_I1(proc, obj, iarg) \ + do { \ + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; \ + param[0].i = iarg; \ + fluid_rvoice_eventhandler_push(voice->eventhandler, proc, obj, param); \ + } while (0) + +#define UPDATE_RVOICE_GENERIC_I2(proc, obj, iarg1, iarg2) \ + do { \ + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; \ + param[0].i = iarg1; \ + param[1].i = iarg2; \ + fluid_rvoice_eventhandler_push(voice->eventhandler, proc, obj, param); \ + } while (0) + +#define UPDATE_RVOICE_GENERIC_IR(proc, obj, iarg, rarg) \ + do { \ + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; \ + param[0].i = iarg; \ + param[1].real = rarg; \ + fluid_rvoice_eventhandler_push(voice->eventhandler, proc, obj, param); \ + } while (0) + + +#define UPDATE_RVOICE_R1(proc, arg1) UPDATE_RVOICE_GENERIC_R1(proc, voice->rvoice, arg1) +#define UPDATE_RVOICE_I1(proc, arg1) UPDATE_RVOICE_GENERIC_I1(proc, voice->rvoice, arg1) + +#define UPDATE_RVOICE_BUFFERS_AMP(proc, iarg, rarg) UPDATE_RVOICE_GENERIC_IR(proc, &voice->rvoice->buffers, iarg, rarg) +#define UPDATE_RVOICE_ENVLFO_R1(proc, envp, rarg) UPDATE_RVOICE_GENERIC_R1(proc, &voice->rvoice->envlfo.envp, rarg) +#define UPDATE_RVOICE_ENVLFO_I1(proc, envp, iarg) UPDATE_RVOICE_GENERIC_I1(proc, &voice->rvoice->envlfo.envp, iarg) + +static FLUID_INLINE void +fluid_voice_update_volenv(fluid_voice_t *voice, + int enqueue, + fluid_adsr_env_section_t section, + unsigned int count, + fluid_real_t coeff, + fluid_real_t increment, + fluid_real_t min, + fluid_real_t max) +{ + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; + + param[0].i = section; + param[1].i = count; + param[2].real = coeff; + param[3].real = increment; + param[4].real = min; + param[5].real = max; + + if(enqueue) + { + fluid_rvoice_eventhandler_push(voice->eventhandler, + fluid_adsr_env_set_data, + &voice->rvoice->envlfo.volenv, + param); + } + else + { + fluid_adsr_env_set_data(&voice->rvoice->envlfo.volenv, param); + } +} + +static FLUID_INLINE void +fluid_voice_update_modenv(fluid_voice_t *voice, + int enqueue, + fluid_adsr_env_section_t section, + unsigned int count, + fluid_real_t coeff, + fluid_real_t increment, + fluid_real_t min, + fluid_real_t max) +{ + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; + + param[0].i = section; + param[1].i = count; + param[2].real = coeff; + param[3].real = increment; + param[4].real = min; + param[5].real = max; + + if(enqueue) + { + fluid_rvoice_eventhandler_push(voice->eventhandler, + fluid_adsr_env_set_data, + &voice->rvoice->envlfo.modenv, + param); + } + else + { + fluid_adsr_env_set_data(&voice->rvoice->envlfo.modenv, param); + } +} + +static FLUID_INLINE void fluid_voice_sample_unref(fluid_sample_t **sample) +{ + if(*sample != NULL) + { + fluid_sample_decr_ref(*sample); + *sample = NULL; + } +} + +/* + * Swaps the current rvoice with the current overflow_rvoice + */ +static void fluid_voice_swap_rvoice(fluid_voice_t *voice) +{ + fluid_rvoice_t *rtemp = voice->rvoice; + int ctemp = voice->can_access_rvoice; + voice->rvoice = voice->overflow_rvoice; + voice->can_access_rvoice = voice->can_access_overflow_rvoice; + voice->overflow_rvoice = rtemp; + voice->can_access_overflow_rvoice = ctemp; + voice->overflow_sample = voice->sample; +} + +static void fluid_voice_initialize_rvoice(fluid_voice_t *voice, fluid_real_t output_rate) +{ + fluid_rvoice_param_t param[MAX_EVENT_PARAMS]; + + FLUID_MEMSET(voice->rvoice, 0, sizeof(fluid_rvoice_t)); + + /* The 'sustain' and 'finished' segments of the volume / modulation + * envelope are constant. They are never affected by any modulator + * or generator. Therefore it is enough to initialize them once + * during the lifetime of the synth. + */ + fluid_voice_update_volenv(voice, FALSE, FLUID_VOICE_ENVSUSTAIN, + 0xffffffff, 1.0f, 0.0f, -1.0f, 2.0f); + fluid_voice_update_volenv(voice, FALSE, FLUID_VOICE_ENVFINISHED, + 0xffffffff, 0.0f, 0.0f, -1.0f, 1.0f); + fluid_voice_update_modenv(voice, FALSE, FLUID_VOICE_ENVSUSTAIN, + 0xffffffff, 1.0f, 0.0f, -1.0f, 2.0f); + fluid_voice_update_modenv(voice, FALSE, FLUID_VOICE_ENVFINISHED, + 0xffffffff, 0.0f, 0.0f, -1.0f, 1.0f); + + param[0].i = FLUID_IIR_LOWPASS; + param[1].i = 0; + fluid_iir_filter_init(&voice->rvoice->resonant_filter, param); + + param[0].i = FLUID_IIR_DISABLED; + fluid_iir_filter_init(&voice->rvoice->resonant_custom_filter, param); + + param[0].real = output_rate; + fluid_rvoice_set_output_rate(voice->rvoice, param); +} + +/* + * new_fluid_voice + */ +fluid_voice_t * +new_fluid_voice(fluid_rvoice_eventhandler_t *handler, fluid_real_t output_rate) +{ + fluid_voice_t *voice; + voice = FLUID_NEW(fluid_voice_t); + + if(voice == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + voice->can_access_rvoice = TRUE; + voice->can_access_overflow_rvoice = TRUE; + + voice->rvoice = FLUID_NEW(fluid_rvoice_t); + voice->overflow_rvoice = FLUID_NEW(fluid_rvoice_t); + + if(voice->rvoice == NULL || voice->overflow_rvoice == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + delete_fluid_voice(voice); + return NULL; + } + + voice->status = FLUID_VOICE_CLEAN; + voice->chan = NO_CHANNEL; + voice->key = 0; + voice->vel = 0; + voice->eventhandler = handler; + voice->channel = NULL; + voice->sample = NULL; + voice->overflow_sample = NULL; + voice->output_rate = output_rate; + + /* Initialize both the rvoice and overflow_rvoice */ + fluid_voice_initialize_rvoice(voice, output_rate); + fluid_voice_swap_rvoice(voice); + fluid_voice_initialize_rvoice(voice, output_rate); + + return voice; +} + +/* + * delete_fluid_voice + */ +void +delete_fluid_voice(fluid_voice_t *voice) +{ + fluid_return_if_fail(voice != NULL); + + if(!voice->can_access_rvoice || !voice->can_access_overflow_rvoice) + { + FLUID_LOG(FLUID_WARN, "Deleting voice %u which has locked rvoices!", voice->id); + } + + FLUID_FREE(voice->overflow_rvoice); + FLUID_FREE(voice->rvoice); + FLUID_FREE(voice); +} + +/* fluid_voice_init + * + * Initialize the synthesis process + * inst_zone, the Instrument Zone contains the sample, Keyrange,Velrange + * of the voice. + * When playing legato (n1,n2) in mono mode, n2 will use n1 voices + * as far as n2 still enters in Keyrange,Velrange of n1. + */ +int +fluid_voice_init(fluid_voice_t *voice, fluid_sample_t *sample, + fluid_zone_range_t *inst_zone_range, + fluid_channel_t *channel, int key, int vel, unsigned int id, + unsigned int start_time, fluid_real_t gain) +{ + /* Note: The voice parameters will be initialized later, when the + * generators have been retrieved from the sound font. Here, only + * the 'working memory' of the voice (position in envelopes, history + * of IIR filters, position in sample etc) is initialized. */ + int i; + + if(!voice->can_access_rvoice) + { + if(voice->can_access_overflow_rvoice) + { + fluid_voice_swap_rvoice(voice); + } + else + { + FLUID_LOG(FLUID_ERR, "Internal error: Cannot access an rvoice in fluid_voice_init!"); + return FLUID_FAILED; + } + } + + /* We are now guaranteed to have access to the rvoice */ + + if(voice->sample) + { + fluid_voice_off(voice); + } + + voice->zone_range = inst_zone_range; /* Instrument zone range for legato */ + voice->id = id; + voice->chan = fluid_channel_get_num(channel); + voice->key = (unsigned char) key; + voice->vel = (unsigned char) vel; + voice->channel = channel; + voice->mod_count = 0; + voice->start_time = start_time; + voice->has_noteoff = 0; + UPDATE_RVOICE0(fluid_rvoice_reset); + + /* + We increment the reference count of the sample to indicate that this + sample is about to be owned by the rvoice. This will prevent the + unloading of the soundfont while this rvoice is playing. + */ + fluid_sample_incr_ref(sample); + fluid_rvoice_eventhandler_push_ptr(voice->eventhandler, fluid_rvoice_set_sample, voice->rvoice, sample); + voice->sample = sample; + + i = fluid_channel_get_interp_method(channel); + UPDATE_RVOICE_I1(fluid_rvoice_set_interp_method, i); + + /* Set all the generators to their default value, according to SF + * 2.01 section 8.1.3 (page 48). The value of NRPN messages are + * copied from the channel to the voice's generators. The sound font + * loader overwrites them. The generator values are later converted + * into voice parameters in + * fluid_voice_calculate_runtime_synthesis_parameters. */ + fluid_gen_init(&voice->gen[0], channel); + UPDATE_RVOICE_I1(fluid_rvoice_set_samplemode, _SAMPLEMODE(voice)); + + voice->synth_gain = gain; + + /* avoid division by zero later*/ + if(voice->synth_gain < 0.0000001f) + { + voice->synth_gain = 0.0000001f; + } + + UPDATE_RVOICE_R1(fluid_rvoice_set_synth_gain, voice->synth_gain); + + /* Set up buffer mapping, should be done more flexible in the future. */ + i = 2 * channel->synth->audio_groups; + i += (voice->chan % channel->synth->effects_groups) * channel->synth->effects_channels; + UPDATE_RVOICE_GENERIC_I2(fluid_rvoice_buffers_set_mapping, &voice->rvoice->buffers, 2, i + SYNTH_REVERB_CHANNEL); + UPDATE_RVOICE_GENERIC_I2(fluid_rvoice_buffers_set_mapping, &voice->rvoice->buffers, 3, i + SYNTH_CHORUS_CHANNEL); + + i = 2 * (voice->chan % channel->synth->audio_groups); + UPDATE_RVOICE_GENERIC_I2(fluid_rvoice_buffers_set_mapping, &voice->rvoice->buffers, 0, i); + UPDATE_RVOICE_GENERIC_I2(fluid_rvoice_buffers_set_mapping, &voice->rvoice->buffers, 1, i + 1); + + return FLUID_OK; +} + + +/** + * Update sample rate. + * + * @note If the voice is active, it will be turned off. + */ +void +fluid_voice_set_output_rate(fluid_voice_t *voice, fluid_real_t value) +{ + if(fluid_voice_is_playing(voice)) + { + fluid_voice_off(voice); + } + + voice->output_rate = value; + UPDATE_RVOICE_GENERIC_R1(fluid_rvoice_set_output_rate, voice->rvoice, value); + UPDATE_RVOICE_GENERIC_R1(fluid_rvoice_set_output_rate, voice->overflow_rvoice, value); +} + + +/** + * Set the value of a generator. + * + * @param voice Voice instance + * @param i Generator ID (#fluid_gen_type) + * @param val Generator value + */ +void +fluid_voice_gen_set(fluid_voice_t *voice, int i, float val) +{ + voice->gen[i].val = val; + voice->gen[i].flags = GEN_SET; + + if(i == GEN_SAMPLEMODE) + { + UPDATE_RVOICE_I1(fluid_rvoice_set_samplemode, (int) val); + } +} + +/** + * Offset the value of a generator. + * + * @param voice Voice instance + * @param i Generator ID (#fluid_gen_type) + * @param val Value to add to the existing value + */ +void +fluid_voice_gen_incr(fluid_voice_t *voice, int i, float val) +{ + voice->gen[i].val += val; + voice->gen[i].flags = GEN_SET; +} + +/** + * Get the value of a generator. + * + * @param voice Voice instance + * @param gen Generator ID (#fluid_gen_type) + * @return Current generator value + */ +float +fluid_voice_gen_get(fluid_voice_t *voice, int gen) +{ + return voice->gen[gen].val; +} + +fluid_real_t fluid_voice_gen_value(const fluid_voice_t *voice, int num) +{ + return (fluid_real_t)(voice->gen[num].val + voice->gen[num].mod + voice->gen[num].nrpn); +} + +/* + * fluid_voice_start + */ +void fluid_voice_start(fluid_voice_t *voice) +{ + /* The maximum volume of the loop is calculated and cached once for each + * sample with its nominal loop settings. This happens, when the sample is used + * for the first time.*/ + + fluid_voice_calculate_runtime_synthesis_parameters(voice); + +#ifdef WITH_PROFILING + voice->ref = fluid_profile_ref(); +#endif + + voice->status = FLUID_VOICE_ON; + + /* Increment voice count */ + voice->channel->synth->active_voice_count++; +} + +/** + * Calculate the amplitude of a voice. + * + * @param gain The gain value in the range [0.0 ; 1.0] + * @return An amplitude used by rvoice_mixer's buffers + */ +static FLUID_INLINE fluid_real_t +fluid_voice_calculate_gain_amplitude(const fluid_voice_t *voice, fluid_real_t gain) +{ + /* we use 24bit samples in fluid_rvoice_dsp. in order to normalize float + * samples to [0.0;1.0] divide samples by the max. value of an int24 and + * amplify them with the gain */ + return gain * voice->synth_gain / (INT24_MAX * 1.0f); +} + +/* Useful to return the nominal pitch of a key */ +/* The nominal pitch is dependent of voice->root_pitch,tuning, and + GEN_SCALETUNE generator. + This is useful to set the value of GEN_PITCH generator on noteOn. + This is useful to get the beginning/ending pitch for portamento. +*/ +fluid_real_t fluid_voice_calculate_pitch(fluid_voice_t *voice, int key) +{ + fluid_tuning_t *tuning; + fluid_real_t x, pitch; + + /* Now the nominal pitch of the key is returned. + * Note about SCALETUNE: SF2.01 8.1.3 says, that this generator is a + * non-realtime parameter. So we don't allow modulation (as opposed + * to fluid_voice_gen_value(voice, GEN_SCALETUNE) When the scale tuning is varied, + * one key remains fixed. Here C3 (MIDI number 60) is used. + */ + if(fluid_channel_has_tuning(voice->channel)) + { + tuning = fluid_channel_get_tuning(voice->channel); + x = fluid_tuning_get_pitch(tuning, (int)(voice->root_pitch / 100.0f)); + pitch = voice->gen[GEN_SCALETUNE].val / 100.0f * + (fluid_tuning_get_pitch(tuning, key) - x) + x; + } + else + { + pitch = voice->gen[GEN_SCALETUNE].val + * (key - voice->root_pitch / 100.0f) + voice->root_pitch; + } + + return pitch; +} + +void +fluid_voice_calculate_gen_pitch(fluid_voice_t *voice) +{ + voice->gen[GEN_PITCH].val = fluid_voice_calculate_pitch(voice, fluid_voice_get_actual_key(voice)); +} + +/* + * fluid_voice_calculate_runtime_synthesis_parameters + * + * in this function we calculate the values of all the parameters. the + * parameters are converted to their most useful unit for the DSP + * algorithm, for example, number of samples instead of + * timecents. Some parameters keep their "perceptual" unit and + * conversion will be done in the DSP function. This is the case, for + * example, for the pitch since it is modulated by the controllers in + * cents. */ +static int +fluid_voice_calculate_runtime_synthesis_parameters(fluid_voice_t *voice) +{ + int i; + unsigned int n; + + static int const list_of_generators_to_initialize[] = + { + GEN_STARTADDROFS, /* SF2.01 page 48 #0 */ + GEN_ENDADDROFS, /* #1 */ + GEN_STARTLOOPADDROFS, /* #2 */ + GEN_ENDLOOPADDROFS, /* #3 */ + /* GEN_STARTADDRCOARSEOFS see comment below [1] #4 */ + GEN_MODLFOTOPITCH, /* #5 */ + GEN_VIBLFOTOPITCH, /* #6 */ + GEN_MODENVTOPITCH, /* #7 */ + GEN_FILTERFC, /* #8 */ + GEN_FILTERQ, /* #9 */ + GEN_MODLFOTOFILTERFC, /* #10 */ + GEN_MODENVTOFILTERFC, /* #11 */ + /* GEN_ENDADDRCOARSEOFS [1] #12 */ + GEN_MODLFOTOVOL, /* #13 */ + /* not defined #14 */ + GEN_CHORUSSEND, /* #15 */ + GEN_REVERBSEND, /* #16 */ + GEN_PAN, /* #17 */ + /* not defined #18 */ + /* not defined #19 */ + /* not defined #20 */ + GEN_MODLFODELAY, /* #21 */ + GEN_MODLFOFREQ, /* #22 */ + GEN_VIBLFODELAY, /* #23 */ + GEN_VIBLFOFREQ, /* #24 */ + GEN_MODENVDELAY, /* #25 */ + GEN_MODENVATTACK, /* #26 */ + GEN_MODENVHOLD, /* #27 */ + GEN_MODENVDECAY, /* #28 */ + /* GEN_MODENVSUSTAIN [1] #29 */ + GEN_MODENVRELEASE, /* #30 */ + /* GEN_KEYTOMODENVHOLD [1] #31 */ + /* GEN_KEYTOMODENVDECAY [1] #32 */ + GEN_VOLENVDELAY, /* #33 */ + GEN_VOLENVATTACK, /* #34 */ + GEN_VOLENVHOLD, /* #35 */ + GEN_VOLENVDECAY, /* #36 */ + /* GEN_VOLENVSUSTAIN [1] #37 */ + GEN_VOLENVRELEASE, /* #38 */ + /* GEN_KEYTOVOLENVHOLD [1] #39 */ + /* GEN_KEYTOVOLENVDECAY [1] #40 */ + /* GEN_STARTLOOPADDRCOARSEOFS [1] #45 */ + GEN_KEYNUM, /* #46 */ + GEN_VELOCITY, /* #47 */ + GEN_ATTENUATION, /* #48 */ + /* GEN_ENDLOOPADDRCOARSEOFS [1] #50 */ + /* GEN_COARSETUNE [1] #51 */ + /* GEN_FINETUNE [1] #52 */ + GEN_OVERRIDEROOTKEY, /* #58 */ + GEN_PITCH, /* --- */ + GEN_CUSTOM_BALANCE, /* --- */ + GEN_CUSTOM_FILTERFC, /* --- */ + GEN_CUSTOM_FILTERQ /* --- */ + }; + + /* When the voice is made ready for the synthesis process, a lot of + * voice-internal parameters have to be calculated. + * + * At this point, the sound font has already set the -nominal- value + * for all generators (excluding GEN_PITCH). Most generators can be + * modulated - they include a nominal value and an offset (which + * changes with velocity, note number, channel parameters like + * aftertouch, mod wheel...) Now this offset will be calculated as + * follows: + * + * - Process each modulator once. + * - Calculate its output value. + * - Find the target generator. + * - Add the output value to the modulation value of the generator. + * + * Note: The generators have been initialized with + * fluid_gen_init(). + */ + + for(i = 0; i < voice->mod_count; i++) + { + fluid_mod_t *mod = &voice->mod[i]; + fluid_real_t modval = fluid_mod_get_value(mod, voice); + int dest_gen_index = mod->dest; + fluid_gen_t *dest_gen = &voice->gen[dest_gen_index]; + dest_gen->mod += modval; + /* fluid_dump_modulator(mod); */ + } + + /* Now the generators are initialized, nominal and modulation value. + * The voice parameters (which depend on generators) are calculated + * with fluid_voice_update_param. Processing the list of generator + * changes will calculate each voice parameter once. + * + * Note [1]: Some voice parameters depend on several generators. For + * example, the pitch depends on GEN_COARSETUNE, GEN_FINETUNE and + * GEN_PITCH. voice->pitch. Unnecessary recalculation is avoided + * by removing all but one generator from the list of voice + * parameters. Same with GEN_XXX and GEN_XXXCOARSE: the + * initialisation list contains only GEN_XXX. + */ + + /* Calculate the voice parameter(s) dependent on each generator. */ + for(n = 0; n < FLUID_N_ELEMENTS(list_of_generators_to_initialize); n++) + { + fluid_voice_update_param(voice, list_of_generators_to_initialize[n]); + } + + /* Start portamento if enabled */ + { + /* fromkey note comes from "GetFromKeyPortamentoLegato()" detector. + When fromkey is set to ValidNote , portamento is started */ + /* Return fromkey portamento */ + int fromkey = voice->channel->synth->fromkey_portamento; + + if(fluid_channel_is_valid_note(fromkey)) + { + /* Send portamento parameters to the voice dsp */ + fluid_voice_update_portamento(voice, fromkey, fluid_voice_get_actual_key(voice)); + } + } + + /* Make an estimate on how loud this voice can get at any time (attenuation). */ + UPDATE_RVOICE_R1(fluid_rvoice_set_min_attenuation_cB, + fluid_voice_get_lower_boundary_for_attenuation(voice)); + return FLUID_OK; +} + +/* + * calculate_hold_decay_buffers + */ +static int +calculate_hold_decay_buffers(fluid_voice_t *voice, int gen_base, + int gen_key2base, int is_decay) +{ + /* Purpose: + * + * Returns the number of DSP loops, that correspond to the hold + * (is_decay=0) or decay (is_decay=1) time. + * gen_base=GEN_VOLENVHOLD, GEN_VOLENVDECAY, GEN_MODENVHOLD, + * GEN_MODENVDECAY gen_key2base=GEN_KEYTOVOLENVHOLD, + * GEN_KEYTOVOLENVDECAY, GEN_KEYTOMODENVHOLD, GEN_KEYTOMODENVDECAY + */ + + fluid_real_t keysteps; + fluid_real_t timecents; + fluid_real_t seconds; + int buffers; + + /* SF2.01 section 8.4.3 # 31, 32, 39, 40 + * GEN_KEYTOxxxENVxxx uses key 60 as 'origin'. + * The unit of the generator is timecents per key number. + * If KEYTOxxxENVxxx is 100, a key one octave over key 60 (72) + * will cause (60-72)*100=-1200 timecents of time variation. + * The time is cut in half. + */ + + keysteps = 60.0f - fluid_channel_get_key_pitch(voice->channel, fluid_voice_get_actual_key(voice)) / 100.0f; + timecents = fluid_voice_gen_value(voice, gen_base) + fluid_voice_gen_value(voice, gen_key2base) * keysteps; + + /* Range checking */ + if(is_decay) + { + /* SF 2.01 section 8.1.3 # 28, 36 */ + if(timecents > 8000.f) + { + timecents = 8000.f; + } + } + else + { + /* SF 2.01 section 8.1.3 # 27, 35 */ + if(timecents > 5000.f) + { + timecents = 5000.f; + } + + /* SF 2.01 section 8.1.2 # 27, 35: + * The most negative number indicates no hold time + */ + if(timecents <= -32768.f) + { + return 0; + } + } + + /* SF 2.01 section 8.1.3 # 27, 28, 35, 36 */ + if(timecents < -12000.f) + { + timecents = -12000.f; + } + + seconds = fluid_tc2sec(timecents); + /* Each DSP loop processes FLUID_BUFSIZE samples. */ + + /* round to next full number of buffers */ + buffers = (int)(((fluid_real_t)voice->output_rate * seconds) + / (fluid_real_t)FLUID_BUFSIZE + + 0.5f); + + return buffers; +} + +/* + * The value of a generator (gen) has changed. (The different + * generators are listed in fluidsynth.h, or in SF2.01 page 48-49) + * Now the dependent 'voice' parameters are calculated. + * + * fluid_voice_update_param can be called during the setup of the + * voice (to calculate the initial value for a voice parameter), or + * during its operation (a generator has been changed due to + * real-time parameter modifications like pitch-bend). + * + * Note: The generator holds three values: The base value .val, an + * offset caused by modulators .mod, and an offset caused by the + * NRPN system. fluid_voice_gen_value(voice, generator_enumerator) returns the sum + * of all three. + */ + +/** + * Update all the synthesis parameters which depend on generator \a gen. + * + * @param voice Voice instance + * @param gen Generator id (#fluid_gen_type) + * + * Calling this function is only necessary after changing a generator of an already playing voice. + */ +void +fluid_voice_update_param(fluid_voice_t *voice, int gen) +{ + unsigned int count, z; + fluid_real_t x = fluid_voice_gen_value(voice, gen); + + switch(gen) + { + + case GEN_PAN: + case GEN_CUSTOM_BALANCE: + /* range checking is done in the fluid_pan and fluid_balance functions */ + voice->pan = fluid_voice_gen_value(voice, GEN_PAN); + voice->balance = fluid_voice_gen_value(voice, GEN_CUSTOM_BALANCE); + + /* left amp */ + UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 0, + fluid_voice_calculate_gain_amplitude(voice, + fluid_pan(voice->pan, 1) * fluid_balance(voice->balance, 1))); + + /* right amp */ + UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 1, + fluid_voice_calculate_gain_amplitude(voice, + fluid_pan(voice->pan, 0) * fluid_balance(voice->balance, 0))); + break; + + case GEN_ATTENUATION: + voice->attenuation = x; + + /* Range: SF2.01 section 8.1.3 # 48 + * Motivation for range checking: + * OHPiano.SF2 sets initial attenuation to a whooping -96 dB */ + fluid_clip(voice->attenuation, 0.f, 1440.f); + UPDATE_RVOICE_R1(fluid_rvoice_set_attenuation, voice->attenuation); + break; + + /* The pitch is calculated from three different generators. + * Read comment in fluidsynth.h about GEN_PITCH. + */ + case GEN_PITCH: + case GEN_COARSETUNE: + case GEN_FINETUNE: + /* The testing for allowed range is done in 'fluid_ct2hz' */ + voice->pitch = (fluid_voice_gen_value(voice, GEN_PITCH) + + 100.0f * fluid_voice_gen_value(voice, GEN_COARSETUNE) + + fluid_voice_gen_value(voice, GEN_FINETUNE)); + UPDATE_RVOICE_R1(fluid_rvoice_set_pitch, voice->pitch); + break; + + case GEN_REVERBSEND: + /* The generator unit is 'tenths of a percent'. */ + voice->reverb_send = x / 1000.0f; + fluid_clip(voice->reverb_send, 0.f, 1.f); + UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 2, fluid_voice_calculate_gain_amplitude(voice, voice->reverb_send)); + break; + + case GEN_CHORUSSEND: + /* The generator unit is 'tenths of a percent'. */ + voice->chorus_send = x / 1000.0f; + fluid_clip(voice->chorus_send, 0.f, 1.f); + UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 3, fluid_voice_calculate_gain_amplitude(voice, voice->chorus_send)); + break; + + case GEN_OVERRIDEROOTKEY: + + /* This is a non-realtime parameter. Therefore the .mod part of the generator + * can be neglected. + * NOTE: origpitch sets MIDI root note while pitchadj is a fine tuning amount + * which offsets the original rate. This means that the fine tuning is + * inverted with respect to the root note (so subtract it, not add). + */ + if(voice->sample != NULL) + { + if(voice->gen[GEN_OVERRIDEROOTKEY].val > -1) //FIXME: use flag instead of -1 + { + voice->root_pitch = voice->gen[GEN_OVERRIDEROOTKEY].val * 100.0f + - voice->sample->pitchadj; + } + else + { + voice->root_pitch = voice->sample->origpitch * 100.0f - voice->sample->pitchadj; + } + + x = (fluid_ct2hz_real(voice->root_pitch) * ((fluid_real_t) voice->output_rate / voice->sample->samplerate)); + } + else + { + if(voice->gen[GEN_OVERRIDEROOTKEY].val > -1) //FIXME: use flag instead of -1 + { + voice->root_pitch = voice->gen[GEN_OVERRIDEROOTKEY].val * 100.0f; + } + else + { + voice->root_pitch = 0; + } + + x = fluid_ct2hz_real(voice->root_pitch); + } + + /* voice->pitch depends on voice->root_pitch, so calculate voice->pitch now */ + fluid_voice_calculate_gen_pitch(voice); + UPDATE_RVOICE_R1(fluid_rvoice_set_root_pitch_hz, x); + + break; + + case GEN_FILTERFC: + /* The resonance frequency is converted from absolute cents to + * midicents .val and .mod are both used, this permits real-time + * modulation. The allowed range is tested in the 'fluid_ct2hz' + * function [PH,20021214] + */ + UPDATE_RVOICE_GENERIC_R1(fluid_iir_filter_set_fres, &voice->rvoice->resonant_filter, x); + break; + + case GEN_FILTERQ: + UPDATE_RVOICE_GENERIC_R1(fluid_iir_filter_set_q, &voice->rvoice->resonant_filter, x); + break; + + /* same as the two above, only for the custom filter */ + case GEN_CUSTOM_FILTERFC: + UPDATE_RVOICE_GENERIC_R1(fluid_iir_filter_set_fres, &voice->rvoice->resonant_custom_filter, x); + break; + + case GEN_CUSTOM_FILTERQ: + UPDATE_RVOICE_GENERIC_R1(fluid_iir_filter_set_q, &voice->rvoice->resonant_custom_filter, x); + break; + + case GEN_MODLFOTOPITCH: + fluid_clip(x, -12000.f, 12000.f); + UPDATE_RVOICE_R1(fluid_rvoice_set_modlfo_to_pitch, x); + break; + + case GEN_MODLFOTOVOL: + fluid_clip(x, -960.f, 960.f); + UPDATE_RVOICE_R1(fluid_rvoice_set_modlfo_to_vol, x); + break; + + case GEN_MODLFOTOFILTERFC: + fluid_clip(x, -12000.f, 12000.f); + UPDATE_RVOICE_R1(fluid_rvoice_set_modlfo_to_fc, x); + break; + + case GEN_MODLFODELAY: + fluid_clip(x, -12000.0f, 5000.0f); + z = (unsigned int)(voice->output_rate * fluid_tc2sec_delay(x)); + UPDATE_RVOICE_ENVLFO_I1(fluid_lfo_set_delay, modlfo, z); + break; + + case GEN_MODLFOFREQ: + /* - the frequency is converted into a delta value, per buffer of FLUID_BUFSIZE samples + * - the delay into a sample delay + */ + fluid_clip(x, -16000.0f, 4500.0f); + x = (4.0f * FLUID_BUFSIZE * fluid_ct2hz_real(x) / voice->output_rate); + UPDATE_RVOICE_ENVLFO_R1(fluid_lfo_set_incr, modlfo, x); + break; + + case GEN_VIBLFOFREQ: + /* vib lfo + * + * - the frequency is converted into a delta value, per buffer of FLUID_BUFSIZE samples + * - the delay into a sample delay + */ + fluid_clip(x, -16000.0f, 4500.0f); + x = 4.0f * FLUID_BUFSIZE * fluid_ct2hz_real(x) / voice->output_rate; + UPDATE_RVOICE_ENVLFO_R1(fluid_lfo_set_incr, viblfo, x); + break; + + case GEN_VIBLFODELAY: + fluid_clip(x, -12000.0f, 5000.0f); + z = (unsigned int)(voice->output_rate * fluid_tc2sec_delay(x)); + UPDATE_RVOICE_ENVLFO_I1(fluid_lfo_set_delay, viblfo, z); + break; + + case GEN_VIBLFOTOPITCH: + fluid_clip(x, -12000.f, 12000.f); + UPDATE_RVOICE_R1(fluid_rvoice_set_viblfo_to_pitch, x); + break; + + case GEN_KEYNUM: + /* GEN_KEYNUM: SF2.01 page 46, item 46 + * + * If this generator is active, it forces the key number to its + * value. Non-realtime controller. + * + * There is a flag, which should indicate, whether a generator is + * enabled or not. But here we rely on the default value of -1. + */ + + /* 2017-09-02: do not change the voice's key here, otherwise it will + * never be released on a noteoff event + */ +#if 0 + x = fluid_voice_gen_value(voice, GEN_KEYNUM); + + if(x >= 0) + { + voice->key = x; + } + +#endif + break; + + case GEN_VELOCITY: + /* GEN_VELOCITY: SF2.01 page 46, item 47 + * + * If this generator is active, it forces the velocity to its + * value. Non-realtime controller. + * + * There is a flag, which should indicate, whether a generator is + * enabled or not. But here we rely on the default value of -1. + */ + /* 2017-09-02: do not change the voice's velocity here, use + * fluid_voice_get_actual_velocity() to get the value of this generator + * if active. + */ +#if 0 + x = fluid_voice_gen_value(voice, GEN_VELOCITY); + + if(x > 0) + { + voice->vel = x; + } + +#endif + break; + + case GEN_MODENVTOPITCH: + fluid_clip(x, -12000.f, 12000.f); + UPDATE_RVOICE_R1(fluid_rvoice_set_modenv_to_pitch, x); + break; + + case GEN_MODENVTOFILTERFC: + /* Range: SF2.01 section 8.1.3 # 1 + * Motivation for range checking: + * Filter is reported to make funny noises now and then + */ + fluid_clip(x, -12000.f, 12000.f); + UPDATE_RVOICE_R1(fluid_rvoice_set_modenv_to_fc, x); + break; + + + /* sample start and ends points + * + * Range checking is initiated via the + * voice->check_sample_sanity flag, + * because it is impossible to check here: + * During the voice setup, all modulators are processed, while + * the voice is inactive. Therefore, illegal settings may + * occur during the setup (for example: First move the loop + * end point ahead of the loop start point => invalid, then + * move the loop start point forward => valid again. + */ + case GEN_STARTADDROFS: /* SF2.01 section 8.1.3 # 0 */ + case GEN_STARTADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 4 */ + if(voice->sample != NULL) + { + fluid_real_t start_fine = fluid_voice_gen_value(voice, GEN_STARTADDROFS); + fluid_real_t start_coar = fluid_voice_gen_value(voice, GEN_STARTADDRCOARSEOFS); + + z = voice->sample->start + (int)start_fine + 32768 * (int)start_coar; + UPDATE_RVOICE_I1(fluid_rvoice_set_start, z); + } + + break; + + case GEN_ENDADDROFS: /* SF2.01 section 8.1.3 # 1 */ + case GEN_ENDADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 12 */ + if(voice->sample != NULL) + { + fluid_real_t end_fine = fluid_voice_gen_value(voice, GEN_ENDADDROFS); + fluid_real_t end_coar = fluid_voice_gen_value(voice, GEN_ENDADDRCOARSEOFS); + + z = voice->sample->end + (int)end_fine + 32768 * (int)end_coar; + UPDATE_RVOICE_I1(fluid_rvoice_set_end, z); + } + + break; + + case GEN_STARTLOOPADDROFS: /* SF2.01 section 8.1.3 # 2 */ + case GEN_STARTLOOPADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 45 */ + if(voice->sample != NULL) + { + fluid_real_t lstart_fine = fluid_voice_gen_value(voice, GEN_STARTLOOPADDROFS); + fluid_real_t lstart_coar = fluid_voice_gen_value(voice, GEN_STARTLOOPADDRCOARSEOFS); + + z = voice->sample->loopstart + (int)lstart_fine + 32768 * (int)lstart_coar; + UPDATE_RVOICE_I1(fluid_rvoice_set_loopstart, z); + } + + break; + + case GEN_ENDLOOPADDROFS: /* SF2.01 section 8.1.3 # 3 */ + case GEN_ENDLOOPADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 50 */ + if(voice->sample != NULL) + { + fluid_real_t lend_fine = fluid_voice_gen_value(voice, GEN_ENDLOOPADDROFS); + fluid_real_t lend_coar = fluid_voice_gen_value(voice, GEN_ENDLOOPADDRCOARSEOFS); + + z = voice->sample->loopend + (int)lend_fine + 32768 * (int)lend_coar; + UPDATE_RVOICE_I1(fluid_rvoice_set_loopend, z); + } + + break; + + /* Conversion functions differ in range limit */ +#define NUM_BUFFERS_DELAY(_v) (unsigned int) (voice->output_rate * fluid_tc2sec_delay(_v) / FLUID_BUFSIZE) +#define NUM_BUFFERS_ATTACK(_v) (unsigned int) (voice->output_rate * fluid_tc2sec_attack(_v) / FLUID_BUFSIZE) +#define NUM_BUFFERS_RELEASE(_v) (unsigned int) (voice->output_rate * fluid_tc2sec_release(_v) / FLUID_BUFSIZE) + + /* volume envelope + * + * - delay and hold times are converted to absolute number of samples + * - sustain is converted to its absolute value + * - attack, decay and release are converted to their increment per sample + */ + case GEN_VOLENVDELAY: /* SF2.01 section 8.1.3 # 33 */ + fluid_clip(x, -12000.0f, 5000.0f); + count = NUM_BUFFERS_DELAY(x); + fluid_voice_update_volenv(voice, TRUE, FLUID_VOICE_ENVDELAY, + count, 0.0f, 0.0f, -1.0f, 1.0f); + break; + + case GEN_VOLENVATTACK: /* SF2.01 section 8.1.3 # 34 */ + fluid_clip(x, -12000.0f, 8000.0f); + count = 1 + NUM_BUFFERS_ATTACK(x); + fluid_voice_update_volenv(voice, TRUE, FLUID_VOICE_ENVATTACK, + count, 1.0f, 1.0f / count, -1.0f, 1.0f); + break; + + case GEN_VOLENVHOLD: /* SF2.01 section 8.1.3 # 35 */ + case GEN_KEYTOVOLENVHOLD: /* SF2.01 section 8.1.3 # 39 */ + count = calculate_hold_decay_buffers(voice, GEN_VOLENVHOLD, GEN_KEYTOVOLENVHOLD, 0); /* 0 means: hold */ + fluid_voice_update_volenv(voice, TRUE, FLUID_VOICE_ENVHOLD, + count, 1.0f, 0.0f, -1.0f, 2.0f); + break; + + case GEN_VOLENVDECAY: /* SF2.01 section 8.1.3 # 36 */ + case GEN_VOLENVSUSTAIN: /* SF2.01 section 8.1.3 # 37 */ + case GEN_KEYTOVOLENVDECAY: /* SF2.01 section 8.1.3 # 40 */ + x = 1.0f - 0.001f * fluid_voice_gen_value(voice, GEN_VOLENVSUSTAIN); + fluid_clip(x, 0.0f, 1.0f); + count = calculate_hold_decay_buffers(voice, GEN_VOLENVDECAY, GEN_KEYTOVOLENVDECAY, 1); /* 1 for decay */ + fluid_voice_update_volenv(voice, TRUE, FLUID_VOICE_ENVDECAY, + count, 1.0f, count ? -1.0f / count : 0.0f, x, 2.0f); + break; + + case GEN_VOLENVRELEASE: /* SF2.01 section 8.1.3 # 38 */ + fluid_clip(x, FLUID_MIN_VOLENVRELEASE, 8000.0f); + count = 1 + NUM_BUFFERS_RELEASE(x); + fluid_voice_update_volenv(voice, TRUE, FLUID_VOICE_ENVRELEASE, + count, 1.0f, -1.0f / count, 0.0f, 1.0f); + break; + + /* Modulation envelope */ + case GEN_MODENVDELAY: /* SF2.01 section 8.1.3 # 25 */ + fluid_clip(x, -12000.0f, 5000.0f); + count = NUM_BUFFERS_DELAY(x); + fluid_voice_update_modenv(voice, TRUE, FLUID_VOICE_ENVDELAY, + count, 0.0f, 0.0f, -1.0f, 1.0f); + break; + + case GEN_MODENVATTACK: /* SF2.01 section 8.1.3 # 26 */ + fluid_clip(x, -12000.0f, 8000.0f); + count = 1 + NUM_BUFFERS_ATTACK(x); + fluid_voice_update_modenv(voice, TRUE, FLUID_VOICE_ENVATTACK, + count, 1.0f, 1.0f / count, -1.0f, 1.0f); + break; + + case GEN_MODENVHOLD: /* SF2.01 section 8.1.3 # 27 */ + case GEN_KEYTOMODENVHOLD: /* SF2.01 section 8.1.3 # 31 */ + count = calculate_hold_decay_buffers(voice, GEN_MODENVHOLD, GEN_KEYTOMODENVHOLD, 0); /* 1 means: hold */ + fluid_voice_update_modenv(voice, TRUE, FLUID_VOICE_ENVHOLD, + count, 1.0f, 0.0f, -1.0f, 2.0f); + break; + + case GEN_MODENVDECAY: /* SF 2.01 section 8.1.3 # 28 */ + case GEN_MODENVSUSTAIN: /* SF 2.01 section 8.1.3 # 29 */ + case GEN_KEYTOMODENVDECAY: /* SF 2.01 section 8.1.3 # 32 */ + count = calculate_hold_decay_buffers(voice, GEN_MODENVDECAY, GEN_KEYTOMODENVDECAY, 1); /* 1 for decay */ + x = 1.0f - 0.001f * fluid_voice_gen_value(voice, GEN_MODENVSUSTAIN); + fluid_clip(x, 0.0f, 1.0f); + fluid_voice_update_modenv(voice, TRUE, FLUID_VOICE_ENVDECAY, + count, 1.0f, count ? -1.0f / count : 0.0f, x, 2.0f); + break; + + case GEN_MODENVRELEASE: /* SF 2.01 section 8.1.3 # 30 */ + fluid_clip(x, -12000.0f, 8000.0f); + count = 1 + NUM_BUFFERS_RELEASE(x); + fluid_voice_update_modenv(voice, TRUE, FLUID_VOICE_ENVRELEASE, + count, 1.0f, -1.0f / count, 0.0f, 2.0f); + + break; + + } /* switch gen */ +} + +/** + * Recalculate voice parameters for a given control. + * + * @param voice the synthesis voice + * @param cc flag to distinguish between a continuous control and a channel control (pitch bend, ...) + * @param ctrl the control number: + * when >=0, only modulators's destination having ctrl as source are updated. + * when -1, all modulators's destination are updated (regardless of ctrl). + * + * In this implementation, I want to make sure that all controllers + * are event based: the parameter values of the DSP algorithm should + * only be updates when a controller event arrived and not at every + * iteration of the audio cycle (which would probably be feasible if + * the synth was made in silicon). + * + * The update is done in two steps: + * + * - step 1: first, we look for all the modulators that have the changed + * controller as a source. This will yield a generator that will be changed + * because of the controller event. + * + * - step 2: For this generator, calculate its new value. This is the + * sum of its original value plus the values of all the attached modulators. + * The generator flag is set to indicate the parameters must be updated. + * This avoid the risk to call 'fluid_voice_update_param' several + * times for the same generator if several modulators have that generator as + * destination. So every changed generators are updated only once. + */ + + /* bit table for each generator being updated. The bits are packed in variables + Each variable have NBR_BIT_BY_VAR bits represented by NBR_BIT_BY_VAR_LN2. + The size of the table is the number of variables: SIZE_UPDATED_GEN_BIT. + + Note: In this implementation NBR_BIT_BY_VAR_LN2 is set to 5 (convenient for 32 bits cpu) + but this could be set to 6 for 64 bits cpu. + */ + +#define NBR_BIT_BY_VAR_LN2 5 /* for 32 bits variables */ +#define NBR_BIT_BY_VAR (1 << NBR_BIT_BY_VAR_LN2) +#define NBR_BIT_BY_VAR_ANDMASK (NBR_BIT_BY_VAR - 1) +#define SIZE_UPDATED_GEN_BIT ((GEN_LAST + NBR_BIT_BY_VAR_ANDMASK) / NBR_BIT_BY_VAR) + +#define is_gen_updated(bit,gen) (bit[gen >> NBR_BIT_BY_VAR_LN2] & (1 << (gen & NBR_BIT_BY_VAR_ANDMASK))) +#define set_gen_updated(bit,gen) (bit[gen >> NBR_BIT_BY_VAR_LN2] |= (1 << (gen & NBR_BIT_BY_VAR_ANDMASK))) + +int fluid_voice_modulate(fluid_voice_t *voice, int cc, int ctrl) +{ + int i, k; + fluid_mod_t *mod; + uint32_t gen; + fluid_real_t modval; + + /* Clears registered bits table of updated generators */ + uint32_t updated_gen_bit[SIZE_UPDATED_GEN_BIT] = {0}; + + /* printf("Chan=%d, CC=%d, Src=%d, Val=%d\n", voice->channel->channum, cc, ctrl, val); */ + + for(i = 0; i < voice->mod_count; i++) + { + mod = &voice->mod[i]; + + /* step 1: find all the modulators that have the changed controller + as input source. When ctrl is -1 all modulators destination + are updated */ + if(ctrl < 0 || fluid_mod_has_source(mod, cc, ctrl)) + { + gen = fluid_mod_get_dest(mod); + + /* Skip if this generator has already been updated */ + if(!is_gen_updated(updated_gen_bit, gen)) + { + modval = 0.0; + + /* step 2: for every attached modulator, calculate the modulation + * value for the generator gen */ + for(k = 0; k < voice->mod_count; k++) + { + if(fluid_mod_has_dest(&voice->mod[k], gen)) + { + modval += fluid_mod_get_value(&voice->mod[k], voice); + } + } + + fluid_gen_set_mod(&voice->gen[gen], modval); + + /* now recalculate the parameter values that are derived from the + generator */ + fluid_voice_update_param(voice, gen); + + /* set the bit that indicates this generator is updated */ + set_gen_updated(updated_gen_bit, gen); + } + } + } + + return FLUID_OK; +} + +/** + * Update all the modulators. + * + * This function is called after a ALL_CTRL_OFF MIDI message has been received (CC 121). + * All destinations of all modulators will be updated. + */ +int fluid_voice_modulate_all(fluid_voice_t *voice) +{ + return fluid_voice_modulate(voice, 0, -1); +} + +/* legato update functions --------------------------------------------------*/ + +/* Updates voice portamento parameters + * + * @voice voice the synthesis voice + * @fromkey the beginning pitch of portamento. + * @tokey the ending pitch of portamento. + * + * The function calculates pitch offset and increment, then these parameters + * are send to the dsp. +*/ +void fluid_voice_update_portamento(fluid_voice_t *voice, int fromkey, int tokey) + +{ + fluid_channel_t *channel = voice->channel; + + /* calculates pitch offset */ + fluid_real_t PitchBeg = fluid_voice_calculate_pitch(voice, fromkey); + fluid_real_t PitchEnd = fluid_voice_calculate_pitch(voice, tokey); + fluid_real_t pitchoffset = PitchBeg - PitchEnd; + + /* Calculates increment countinc */ + /* Increment is function of PortamentoTime (ms)*/ + unsigned int countinc = (unsigned int)(((fluid_real_t)voice->output_rate * + 0.001f * + (fluid_real_t)fluid_channel_portamentotime(channel)) / + (fluid_real_t)FLUID_BUFSIZE + 0.5f); + + /* Send portamento parameters to the voice dsp */ + UPDATE_RVOICE_GENERIC_IR(fluid_rvoice_set_portamento, voice->rvoice, countinc, pitchoffset); +} + +/*---------------------------------------------------------------*/ +/*legato mode 1: multi_retrigger + * + * Modulates all generators dependent of key,vel. + * Forces the voice envelopes in the attack section (legato mode 1). + * + * @voice voice the synthesis voice + * @tokey the new key to be applied to this voice. + * @vel the new velocity to be applied to this voice. + */ +void fluid_voice_update_multi_retrigger_attack(fluid_voice_t *voice, + int tokey, int vel) +{ + voice->key = tokey; /* new note */ + voice->vel = vel; /* new velocity */ + /* Updates generators dependent of velocity */ + /* Modulates GEN_ATTENUATION (and others ) before calling + fluid_rvoice_multi_retrigger_attack().*/ + fluid_voice_modulate(voice, FALSE, FLUID_MOD_VELOCITY); + + /* Updates generator dependent of voice->key */ + fluid_voice_update_param(voice, GEN_KEYTOMODENVHOLD); + fluid_voice_update_param(voice, GEN_KEYTOMODENVDECAY); + fluid_voice_update_param(voice, GEN_KEYTOVOLENVHOLD); + fluid_voice_update_param(voice, GEN_KEYTOVOLENVDECAY); + + /* Updates pitch generator */ + fluid_voice_calculate_gen_pitch(voice); + fluid_voice_update_param(voice, GEN_PITCH); + + /* updates adsr generator */ + UPDATE_RVOICE0(fluid_rvoice_multi_retrigger_attack); +} +/** end of legato update functions */ + +/* + Force the voice into release stage. Useful anywhere a voice + needs to be damped even if pedals (sustain sostenuto) are depressed. + See fluid_synth_damp_voices_by_sustain_LOCAL(), + fluid_synth_damp_voices_by_sostenuto_LOCAL, + fluid_voice_noteoff(). +*/ +void +fluid_voice_release(fluid_voice_t *voice) +{ + unsigned int at_tick = fluid_channel_get_min_note_length_ticks(voice->channel); + UPDATE_RVOICE_I1(fluid_rvoice_noteoff, at_tick); + voice->has_noteoff = 1; // voice is marked as noteoff occurred +} + +/* + * fluid_voice_noteoff + * + * Sending a noteoff event will advance the envelopes to section 5 (release). + * The function is convenient for polyphonic or monophonic note + */ +void +fluid_voice_noteoff(fluid_voice_t *voice) +{ + fluid_channel_t *channel; + + fluid_profile(FLUID_PROF_VOICE_NOTE, voice->ref, 0, 0); + + channel = voice->channel; + + /* Sustain a note under Sostenuto pedal */ + if(fluid_channel_sostenuto(channel) && + channel->sostenuto_orderid > voice->id) + { + // Sostenuto depressed after note + voice->status = FLUID_VOICE_HELD_BY_SOSTENUTO; + } + /* Or sustain a note under Sustain pedal */ + else if(fluid_channel_sustained(channel)) + { + voice->status = FLUID_VOICE_SUSTAINED; + } + /* Or force the voice to release stage */ + else + { + fluid_voice_release(voice); + } +} + +/* + * fluid_voice_kill_excl + * + * Percussion sounds can be mutually exclusive: for example, a 'closed + * hihat' sound will terminate an 'open hihat' sound ringing at the + * same time. This behaviour is modeled using 'exclusive classes', + * turning on a voice with an exclusive class other than 0 will kill + * all other voices having that exclusive class within the same preset + * or channel. fluid_voice_kill_excl gets called, when 'voice' is to + * be killed for that reason. + */ + +int +fluid_voice_kill_excl(fluid_voice_t *voice) +{ + + unsigned int at_tick; + + if(!fluid_voice_is_playing(voice)) + { + return FLUID_OK; + } + + /* Turn off the exclusive class information for this voice, + so that it doesn't get killed twice + */ + fluid_voice_gen_set(voice, GEN_EXCLUSIVECLASS, 0); + + /* Speed up the volume envelope */ + /* The value was found through listening tests with hi-hat samples. */ + fluid_voice_gen_set(voice, GEN_VOLENVRELEASE, -200); + fluid_voice_update_param(voice, GEN_VOLENVRELEASE); + + /* Speed up the modulation envelope */ + fluid_voice_gen_set(voice, GEN_MODENVRELEASE, -200); + fluid_voice_update_param(voice, GEN_MODENVRELEASE); + + at_tick = fluid_channel_get_min_note_length_ticks(voice->channel); + UPDATE_RVOICE_I1(fluid_rvoice_noteoff, at_tick); + + + return FLUID_OK; +} + +/* + * Unlock the overflow rvoice of the voice. + * Decrement the reference count of the sample owned by this rvoice. + * + * Called by fluid_synth when the overflow rvoice has finished by itself. + * Must be called also explicitly at synth destruction to ensure that + * the soundfont be unloaded successfully. + */ +void fluid_voice_overflow_rvoice_finished(fluid_voice_t *voice) +{ + voice->can_access_overflow_rvoice = 1; + + /* Decrement the reference count of the sample to indicate + that this sample isn't owned by the rvoice anymore */ + fluid_voice_sample_unref(&voice->overflow_sample); +} + +/* + * fluid_voice_off + * + * Force the voice into finished stage. Useful anywhere a voice + * needs to be cancelled from MIDI API. + */ +void fluid_voice_off(fluid_voice_t *voice) +{ + UPDATE_RVOICE0(fluid_rvoice_voiceoff); /* request to finish the voice */ +} + +/* + * fluid_voice_stop + * + * Purpose: + * Turns off a voice, meaning that it is not processed anymore by the + * DSP loop, i.e. contrary part to fluid_voice_start(). + */ +void +fluid_voice_stop(fluid_voice_t *voice) +{ + fluid_profile(FLUID_PROF_VOICE_RELEASE, voice->ref, 0, 0); + + voice->chan = NO_CHANNEL; + + /* Decrement the reference count of the sample, to indicate + that this sample isn't owned by the rvoice anymore. + */ + fluid_voice_sample_unref(&voice->sample); + + voice->status = FLUID_VOICE_OFF; + voice->has_noteoff = 1; + + /* Decrement voice count */ + voice->channel->synth->active_voice_count--; +} + +/** + * Adds a modulator to the voice if the modulator has valid sources. + * + * @param voice Voice instance. + * @param mod Modulator info (copied). + * @param mode Determines how to handle an existing identical modulator. + * #FLUID_VOICE_ADD to add (offset) the modulator amounts, + * #FLUID_VOICE_OVERWRITE to replace the modulator, + * #FLUID_VOICE_DEFAULT when adding a default modulator - no duplicate should + * exist so don't check. + */ +void +fluid_voice_add_mod(fluid_voice_t *voice, fluid_mod_t *mod, int mode) +{ + /* Ignore the modulator if its sources inputs are invalid */ + if(fluid_mod_check_sources(mod, "api fluid_voice_add_mod mod")) + { + fluid_voice_add_mod_local(voice, mod, mode, FLUID_NUM_MOD); + } +} + +/** + * Adds a modulator to the voice. + * local version of fluid_voice_add_mod function. Called at noteon time. + * @param voice, mod, mode, same as for fluid_voice_add_mod() (see above). + * @param check_limit_count is the modulator number limit to handle with existing + * identical modulator(i.e mode FLUID_VOICE_OVERWRITE, FLUID_VOICE_ADD). + * - When FLUID_NUM_MOD, all the voices modulators (since the previous call) + * are checked for identity. + * - When check_count_limit is below the actual number of voices modulators + * (voice->mod_count), this will restrict identity check to this number, + * This is useful when we know by advance that there is no duplicate with + * modulators at index above this limit. This avoid wasting cpu cycles at noteon. + */ +void +fluid_voice_add_mod_local(fluid_voice_t *voice, fluid_mod_t *mod, int mode, int check_limit_count) +{ + int i; + + /* check_limit_count cannot be above voice->mod_count */ + if(check_limit_count > voice->mod_count) + { + check_limit_count = voice->mod_count; + } + + if(mode == FLUID_VOICE_ADD) + { + + /* if identical modulator exists, add them */ + for(i = 0; i < check_limit_count; i++) + { + if(fluid_mod_test_identity(&voice->mod[i], mod)) + { + // printf("Adding modulator...\n"); + voice->mod[i].amount += mod->amount; + return; + } + } + + } + else if(mode == FLUID_VOICE_OVERWRITE) + { + + /* if identical modulator exists, replace it (only the amount has to be changed) */ + for(i = 0; i < check_limit_count; i++) + { + if(fluid_mod_test_identity(&voice->mod[i], mod)) + { + // printf("Replacing modulator...amount is %f\n",mod->amount); + voice->mod[i].amount = mod->amount; + return; + } + } + } + + /* Add a new modulator (No existing modulator to add / overwrite). + Also, default modulators (FLUID_VOICE_DEFAULT) are added without + checking, if the same modulator already exists. */ + if(voice->mod_count < FLUID_NUM_MOD) + { + fluid_mod_clone(&voice->mod[voice->mod_count++], mod); + } + else + { + FLUID_LOG(FLUID_WARN, "Voice %i has more modulators than supported, ignoring.", voice->id); + } +} + +/** + * Get the unique ID of the noteon-event. + * + * @param voice Voice instance + * @return Note on unique ID + * + * A SoundFont loader may store pointers to voices it has created for + * real-time control during the operation of a voice (for example: parameter + * changes in SoundFont editor). The synth uses a pool of voices internally which are + * 'recycled' and never deallocated. + * + * However, before modifying an existing voice, check + * - that its state is still 'playing' + * - that the ID is still the same + * + * Otherwise the voice has finished playing. + */ +unsigned int fluid_voice_get_id(const fluid_voice_t *voice) +{ + return voice->id; +} + +/** + * Check if a voice is producing sound. + * + * Like fluid_voice_is_on() this will return TRUE once a call to + * fluid_synth_start_voice() has been made. Contrary to fluid_voice_is_on(), + * this might also return TRUE after the voice received a noteoff event, as it may + * still be playing in release phase, or because it has been sustained or + * sostenuto'ed. + * + * @param voice Voice instance + * @return TRUE if playing, FALSE otherwise + */ +int fluid_voice_is_playing(const fluid_voice_t *voice) +{ + return (voice->status == FLUID_VOICE_ON) + || fluid_voice_is_sustained(voice) + || fluid_voice_is_sostenuto(voice); + +} + +/** + * Check if a voice is ON. + * + * A voice is in ON state as soon as a call to fluid_synth_start_voice() has been made + * (which is typically done in a fluid_preset_t's noteon function). + * A voice stays ON as long as it has not received a noteoff event. + * + * @param voice Voice instance + * @return TRUE if on, FALSE otherwise + * + * @since 1.1.7 + */ +int fluid_voice_is_on(const fluid_voice_t *voice) +{ + return (voice->status == FLUID_VOICE_ON && !voice->has_noteoff); +} + +/** + * Check if a voice keeps playing after it has received a noteoff due to being held by sustain. + * + * @param voice Voice instance + * @return TRUE if sustained, FALSE otherwise + * + * @since 1.1.7 + */ +int fluid_voice_is_sustained(const fluid_voice_t *voice) +{ + return (voice->status == FLUID_VOICE_SUSTAINED); +} + +/** + * Check if a voice keeps playing after it has received a noteoff due to being held by sostenuto. + * + * @param voice Voice instance + * @return TRUE if sostenuto, FALSE otherwise + * + * @since 1.1.7 + */ +int fluid_voice_is_sostenuto(const fluid_voice_t *voice) +{ + return (voice->status == FLUID_VOICE_HELD_BY_SOSTENUTO); +} + +/** + * Return the MIDI channel the voice is playing on. + * + * @param voice Voice instance + * @return The channel assigned to this voice + * + * @note The result of this function is only valid if the voice is playing. + * + * @since 1.1.7 + */ +int fluid_voice_get_channel(const fluid_voice_t *voice) +{ + return voice->chan; +} + +/** + * Return the effective MIDI key of the playing voice. + * + * @param voice Voice instance + * @return The MIDI key this voice is playing at + * + * If the voice was started from an instrument which uses a fixed key generator, it returns that. + * Otherwise returns the same value as \c fluid_voice_get_key. + * + * @note The result of this function is only valid if the voice is playing. + * + * @since 1.1.7 + */ +int fluid_voice_get_actual_key(const fluid_voice_t *voice) +{ + fluid_real_t x = fluid_voice_gen_value(voice, GEN_KEYNUM); + + if(x >= 0) + { + return (int)x; + } + else + { + return fluid_voice_get_key(voice); + } +} + +/** + * Return the MIDI key from the starting noteon event. + * + * @param voice Voice instance + * @return The MIDI key of the noteon event that originally turned on this voice + * + * @note The result of this function is only valid if the voice is playing. + * + * @since 1.1.7 + */ +int fluid_voice_get_key(const fluid_voice_t *voice) +{ + return voice->key; +} + +/** + * Return the effective MIDI velocity of the playing voice. + * + * @param voice Voice instance + * @return The MIDI velocity this voice is playing at + * + * If the voice was started from an instrument which uses a fixed velocity generator, it returns that. + * Otherwise it returns the same value as \c fluid_voice_get_velocity. + * + * @note The result of this function is only valid if the voice is playing. + * + * @since 1.1.7 + */ +int fluid_voice_get_actual_velocity(const fluid_voice_t *voice) +{ + fluid_real_t x = fluid_voice_gen_value(voice, GEN_VELOCITY); + + if(x > 0) + { + return (int)x; + } + else + { + return fluid_voice_get_velocity(voice); + } +} + +/** + * Return the MIDI velocity from the starting noteon event. + * + * @param voice Voice instance + * @return The MIDI velocity which originally turned on this voice + * + * @note The result of this function is only valid if the voice is playing. + * + * @since 1.1.7 + */ +int fluid_voice_get_velocity(const fluid_voice_t *voice) +{ + return voice->vel; +} + +/* + * fluid_voice_get_lower_boundary_for_attenuation + * + * Purpose: + * + * A lower boundary for the attenuation (as in 'the minimum + * attenuation of this voice, with volume pedals, modulators + * etc. resulting in minimum attenuation, cannot fall below x cB) is + * calculated. This has to be called during fluid_voice_start, after + * all modulators have been run on the voice once. Also, + * voice->attenuation has to be initialized. + * (see fluid_voice_calculate_runtime_synthesis_parameters()) + */ +static fluid_real_t +fluid_voice_get_lower_boundary_for_attenuation(fluid_voice_t *voice) +{ + int i; + fluid_mod_t *mod; + fluid_real_t possible_att_reduction_cB = 0; + fluid_real_t lower_bound; + + for(i = 0; i < voice->mod_count; i++) + { + mod = &voice->mod[i]; + + /* Modulator has attenuation as target and can change over time? */ + if((mod->dest == GEN_ATTENUATION) + && ((mod->flags1 & FLUID_MOD_CC) + || (mod->flags2 & FLUID_MOD_CC) + || (mod->src1 == FLUID_MOD_CHANNELPRESSURE) + || (mod->src1 == FLUID_MOD_KEYPRESSURE) + || (mod->src1 == FLUID_MOD_PITCHWHEEL) + || (mod->src2 == FLUID_MOD_CHANNELPRESSURE) + || (mod->src2 == FLUID_MOD_KEYPRESSURE) + || (mod->src2 == FLUID_MOD_PITCHWHEEL))) + { + + fluid_real_t current_val = fluid_mod_get_value(mod, voice); + /* min_val is the possible minimum value for this modulator. + it depends of 3 things : + 1)the minimum values of src1,src2 (i.e -1 if mapping is bipolar + or 0 if mapping is unipolar). + 2)the sign of amount. + 3)absolute value of amount. + + When at least one source mapping is bipolar: + min_val is -|amount| regardless the sign of amount. + When both sources mapping are unipolar: + min_val is -|amount|, if amount is negative. + min_val is 0, if amount is positive + */ + fluid_real_t min_val = fabs(mod->amount); + + /* Can this modulator produce a negative contribution? */ + if((mod->flags1 & FLUID_MOD_BIPOLAR) + || (mod->flags2 & FLUID_MOD_BIPOLAR) + || (mod->amount < 0)) + { + min_val = -min_val; /* min_val = - |amount|*/ + } + else + { + /* No negative value possible. But still, the minimum contribution is 0. */ + min_val = 0; + } + + /* For example: + * - current_val=100 + * - min_val=-4000 + * - possible reduction contribution of this modulator = current_val - min_val = 4100 + */ + if(current_val > min_val) + { + possible_att_reduction_cB += (current_val - min_val); + } + } + } + + lower_bound = voice->attenuation - possible_att_reduction_cB; + + /* SF2.01 specs do not allow negative attenuation */ + if(lower_bound < 0) + { + lower_bound = 0; + } + + return lower_bound; +} + + + + +int fluid_voice_set_param(fluid_voice_t *voice, int gen, fluid_real_t nrpn_value) +{ + voice->gen[gen].nrpn = nrpn_value; + voice->gen[gen].flags = GEN_SET; + fluid_voice_update_param(voice, gen); + return FLUID_OK; +} + +int fluid_voice_set_gain(fluid_voice_t *voice, fluid_real_t gain) +{ + fluid_real_t left, right, reverb, chorus; + + /* avoid division by zero*/ + if(gain < 0.0000001f) + { + gain = 0.0000001f; + } + + voice->synth_gain = gain; + left = fluid_voice_calculate_gain_amplitude(voice, + fluid_pan(voice->pan, 1) * fluid_balance(voice->balance, 1)); + right = fluid_voice_calculate_gain_amplitude(voice, + fluid_pan(voice->pan, 0) * fluid_balance(voice->balance, 0)); + reverb = fluid_voice_calculate_gain_amplitude(voice, voice->reverb_send); + chorus = fluid_voice_calculate_gain_amplitude(voice, voice->chorus_send); + + UPDATE_RVOICE_R1(fluid_rvoice_set_synth_gain, gain); + UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 0, left); + UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 1, right); + UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 2, reverb); + UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 3, chorus); + + return FLUID_OK; +} + +/* - Scan the loop + * - determine the peak level + * - Calculate, what factor will make the loop inaudible + * - Store in sample + */ + +/** + * Calculate the peak volume of a sample for voice off optimization. + * + * @param s Sample to optimize + * @return #FLUID_OK on success, #FLUID_FAILED otherwise + * + * If the peak volume during the loop is known, then the voice can + * be released earlier during the release phase. Otherwise, the + * voice will operate (inaudibly), until the envelope is at the + * nominal turnoff point. So it's a good idea to call + * fluid_voice_optimize_sample() on each sample once. + */ +int +fluid_voice_optimize_sample(fluid_sample_t *s) +{ + int32_t peak_max = 0; + int32_t peak_min = 0; + int32_t peak; + fluid_real_t normalized_amplitude_during_loop; + double result; + unsigned int i; + + /* ignore disabled samples */ + if(s->start == s->end) + { + return (FLUID_OK); + } + + if(!s->amplitude_that_reaches_noise_floor_is_valid) /* Only once */ + { + /* Scan the loop */ + for(i = s->loopstart; i < s->loopend; i++) + { + int32_t val = fluid_rvoice_get_sample(s->data, s->data24, i); + + if(val > peak_max) + { + peak_max = val; + } + else if(val < peak_min) + { + peak_min = val; + } + } + + /* Determine the peak level */ + if(peak_max > -peak_min) + { + peak = peak_max; + } + else + { + peak = -peak_min; + } + + if(peak == 0) + { + /* Avoid division by zero */ + peak = 1; + } + + /* Calculate what factor will make the loop inaudible + * For example: Take a peak of 3277 (10 % of 32768). The + * normalized amplitude is 0.1 (10 % of 32768). An amplitude + * factor of 0.0001 (as opposed to the default 0.00001) will + * drop this sample to the noise floor. + */ + + /* 16 bits => 96+4=100 dB dynamic range => 0.00001 */ + normalized_amplitude_during_loop = ((fluid_real_t)peak) / (INT24_MAX * 1.0f); + result = FLUID_NOISE_FLOOR / normalized_amplitude_during_loop; + + /* Store in sample */ + s->amplitude_that_reaches_noise_floor = (double)result; + s->amplitude_that_reaches_noise_floor_is_valid = 1; +#if 0 + printf("Sample peak detection: factor %f\n", (double)result); +#endif + } + + return FLUID_OK; +} + +float +fluid_voice_get_overflow_prio(fluid_voice_t *voice, + fluid_overflow_prio_t *score, + unsigned int cur_time) +{ + float this_voice_prio = 0; + int channel; + + /* Are we already overflowing? */ + if(!voice->can_access_overflow_rvoice) + { + return OVERFLOW_PRIO_CANNOT_KILL; + } + + /* Is this voice on the drum channel? + * Then it is very important. + * Also skip the released and sustained scores. + */ + if(voice->channel->channel_type == CHANNEL_TYPE_DRUM) + { + this_voice_prio += score->percussion; + } + else if(voice->has_noteoff) + { + /* Noteoff has */ + this_voice_prio += score->released; + } + else if(fluid_voice_is_sustained(voice) || fluid_voice_is_sostenuto(voice)) + { + /* This voice is still active, since the sustain pedal is held down. + * Consider it less important than non-sustained channels. + * This decision is somehow subjective. But usually the sustain pedal + * is used to play 'more-voices-than-fingers', so it shouldn't hurt + * if we kill one voice. + */ + this_voice_prio += score->sustained; + } + + /* We are not enthusiastic about releasing voices, which have just been started. + * Otherwise hitting a chord may result in killing notes belonging to that very same + * chord. So give newer voices a higher score. */ + if(score->age) + { + cur_time -= voice->start_time; + + if(cur_time < 1) + { + cur_time = 1; // Avoid div by zero + } + + this_voice_prio += (score->age * voice->output_rate) / cur_time; + } + + /* take a rough estimate of loudness into account. Louder voices are more important. */ + if(score->volume) + { + fluid_real_t a = voice->attenuation; + + if(voice->has_noteoff) + { + // FIXME: Should take into account where on the envelope we are...? + } + + if(a < 0.1f) + { + a = 0.1f; // Avoid div by zero + } + + this_voice_prio += score->volume / a; + } + + /* Check if this voice is on an important channel. If so, then add the + * score for important channels */ + channel = fluid_voice_get_channel(voice); + + if(channel < score->num_important_channels && score->important_channels[channel]) + { + this_voice_prio += score->important; + } + + return this_voice_prio; +} + + +void fluid_voice_set_custom_filter(fluid_voice_t *voice, enum fluid_iir_filter_type type, enum fluid_iir_filter_flags flags) +{ + UPDATE_RVOICE_GENERIC_I2(fluid_iir_filter_init, &voice->rvoice->resonant_custom_filter, type, flags); +} diff --git a/libs/fluidsynth/src/synth/fluid_voice.h b/libs/fluidsynth/src/synth/fluid_voice.h new file mode 100644 index 00000000000..4ce6c2b7ab5 --- /dev/null +++ b/libs/fluidsynth/src/synth/fluid_voice.h @@ -0,0 +1,198 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#ifndef _FLUID_VOICE_H +#define _FLUID_VOICE_H + +#include "fluid_phase.h" +#include "fluid_gen.h" +#include "fluid_mod.h" +#include "fluid_iir_filter.h" +#include "fluid_adsr_env.h" +#include "fluid_lfo.h" +#include "fluid_rvoice.h" +#include "fluid_rvoice_event.h" + +#define NO_CHANNEL 0xff + +typedef struct _fluid_overflow_prio_t fluid_overflow_prio_t; + +struct _fluid_overflow_prio_t +{ + float percussion; /**< Is this voice on the drum channel? Then add this score */ + float released; /**< Is this voice in release stage? Then add this score (usually negative) */ + float sustained; /**< Is this voice sustained? Then add this score (usually negative) */ + float volume; /**< Multiply current (or future) volume (a value between 0 and 1) */ + float age; /**< This score will be divided by the number of seconds the voice has lasted */ + float important; /**< This score will be added to all important channels */ + char *important_channels; /**< "important" flags indexed by MIDI channel number */ + int num_important_channels; /**< Number of elements in the important_channels array */ +}; + +enum fluid_voice_status +{ + FLUID_VOICE_CLEAN, + FLUID_VOICE_ON, + FLUID_VOICE_SUSTAINED, /* Sustained by Sustain pedal */ + FLUID_VOICE_HELD_BY_SOSTENUTO, /* Sustained by Sostenuto pedal */ + FLUID_VOICE_OFF +}; + + +/* + * fluid_voice_t + */ +struct _fluid_voice_t +{ + unsigned int id; /* the id is incremented for every new noteon. + it's used for noteoff's */ + unsigned char status; + unsigned char chan; /* the channel number, quick access for channel messages */ + unsigned char key; /* the key of the noteon event, quick access for noteoff */ + unsigned char vel; /* the velocity of the noteon event */ + fluid_channel_t *channel; + fluid_rvoice_eventhandler_t *eventhandler; + fluid_zone_range_t *zone_range; /* instrument zone range*/ + fluid_sample_t *sample; /* Pointer to sample (dupe in rvoice) */ + fluid_sample_t *overflow_sample; /* Pointer to sample (dupe in overflow_rvoice) */ + + unsigned int start_time; + int mod_count; + fluid_mod_t mod[FLUID_NUM_MOD]; + fluid_gen_t gen[GEN_LAST]; + + /* basic parameters */ + fluid_real_t output_rate; /* the sample rate of the synthesizer (dupe in rvoice) */ + + /* basic parameters */ + fluid_real_t pitch; /* the pitch in midicents (dupe in rvoice) */ + fluid_real_t attenuation; /* the attenuation in centibels (dupe in rvoice) */ + fluid_real_t root_pitch; + + /* master gain (dupe in rvoice) */ + fluid_real_t synth_gain; + + /* pan */ + fluid_real_t pan; + + /* balance */ + fluid_real_t balance; + + /* reverb */ + fluid_real_t reverb_send; + + /* chorus */ + fluid_real_t chorus_send; + + /* rvoice control */ + fluid_rvoice_t *rvoice; + fluid_rvoice_t *overflow_rvoice; /* Used temporarily and only in overflow situations */ + char can_access_rvoice; /* False if rvoice is being rendered in separate thread */ + char can_access_overflow_rvoice; /* False if overflow_rvoice is being rendered in separate thread */ + char has_noteoff; /* Flag set when noteoff has been sent */ + +#ifdef WITH_PROFILING + /* for debugging */ + double ref; +#endif +}; + + +fluid_voice_t *new_fluid_voice(fluid_rvoice_eventhandler_t *handler, fluid_real_t output_rate); +void delete_fluid_voice(fluid_voice_t *voice); + +void fluid_voice_start(fluid_voice_t *voice); +void fluid_voice_calculate_gen_pitch(fluid_voice_t *voice); + +int fluid_voice_init(fluid_voice_t *voice, fluid_sample_t *sample, + fluid_zone_range_t *inst_zone_range, + fluid_channel_t *channel, int key, int vel, + unsigned int id, unsigned int time, fluid_real_t gain); + +int fluid_voice_modulate(fluid_voice_t *voice, int cc, int ctrl); +int fluid_voice_modulate_all(fluid_voice_t *voice); + +/** Set the NRPN value of a generator. */ +int fluid_voice_set_param(fluid_voice_t *voice, int gen, fluid_real_t value); + + +/** Set the gain. */ +int fluid_voice_set_gain(fluid_voice_t *voice, fluid_real_t gain); + +void fluid_voice_set_output_rate(fluid_voice_t *voice, fluid_real_t value); + + +/** Update all the synthesis parameters, which depend on generator + 'gen'. This is only necessary after changing a generator of an + already operating voice. Most applications will not need this + function.*/ +void fluid_voice_update_param(fluid_voice_t *voice, int gen); + +/** legato modes */ +/* force in the attack section for legato mode multi_retrigger: 1 */ +void fluid_voice_update_multi_retrigger_attack(fluid_voice_t *voice, int tokey, int vel); +/* Update portamento parameter */ +void fluid_voice_update_portamento(fluid_voice_t *voice, int fromkey, int tokey); + + +void fluid_voice_release(fluid_voice_t *voice); +void fluid_voice_noteoff(fluid_voice_t *voice); +void fluid_voice_off(fluid_voice_t *voice); +void fluid_voice_stop(fluid_voice_t *voice); +void fluid_voice_add_mod_local(fluid_voice_t *voice, fluid_mod_t *mod, int mode, int check_limit_count); +void fluid_voice_overflow_rvoice_finished(fluid_voice_t *voice); + +int fluid_voice_kill_excl(fluid_voice_t *voice); +float fluid_voice_get_overflow_prio(fluid_voice_t *voice, + fluid_overflow_prio_t *score, + unsigned int cur_time); + +#define OVERFLOW_PRIO_CANNOT_KILL 999999. + +/** + * Locks the rvoice for rendering, so it can't be modified directly + */ +static FLUID_INLINE void +fluid_voice_lock_rvoice(fluid_voice_t *voice) +{ + voice->can_access_rvoice = 0; +} + +/** + * Unlocks the rvoice for rendering, so it can be modified directly + */ +static FLUID_INLINE void +fluid_voice_unlock_rvoice(fluid_voice_t *voice) +{ + voice->can_access_rvoice = 1; +} + +#define _AVAILABLE(voice) ((voice)->can_access_rvoice && \ + (((voice)->status == FLUID_VOICE_CLEAN) || ((voice)->status == FLUID_VOICE_OFF))) +//#define _RELEASED(voice) ((voice)->chan == NO_CHANNEL) +#define _SAMPLEMODE(voice) ((int)(voice)->gen[GEN_SAMPLEMODE].val) + + +fluid_real_t fluid_voice_gen_value(const fluid_voice_t *voice, int num); +void fluid_voice_set_custom_filter(fluid_voice_t *voice, enum fluid_iir_filter_type type, enum fluid_iir_filter_flags flags); + + +#endif /* _FLUID_VOICE_H */ diff --git a/libs/fluidsynth/src/utils/fluid_conv.c b/libs/fluidsynth/src/utils/fluid_conv.c new file mode 100644 index 00000000000..4a459ae0a2c --- /dev/null +++ b/libs/fluidsynth/src/utils/fluid_conv.c @@ -0,0 +1,333 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include "fluid_conv.h" +#include "fluid_sys.h" +#include "fluid_conv_tables.inc.h" + +/* + * Converts absolute cents to Hertz + * + * As per sfspec section 9.3: + * + * ABSOLUTE CENTS - An absolute logarithmic measure of frequency based on a + * reference of MIDI key number scaled by 100. + * A cent is 1/1200 of an octave [which is the twelve hundredth root of two], + * and value 6900 is 440 Hz (A-440). + * + * Implemented below basically is the following: + * 440 * 2^((cents-6900)/1200) + * = 440 * 2^((int)((cents-6900)/1200)) * 2^(((int)cents-6900)%1200)) + * = 2^((int)((cents-6900)/1200)) * (440 * 2^(((int)cents-6900)%1200))) + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * This second factor is stored in the lookup table. + * + * The first factor can be implemented with a fast shift when the exponent + * is always an int. This is the case when using 440/2^6 Hz rather than 440Hz + * reference. + */ +fluid_real_t +fluid_ct2hz_real(fluid_real_t cents) +{ + if(FLUID_UNLIKELY(cents < 0)) + { + return fluid_act2hz(cents); + } + else + { + unsigned int mult, fac, rem; + unsigned int icents = (unsigned int)cents; + icents += 300u; + + // don't use stdlib div() here, it turned out have poor performance + fac = icents / 1200u; + rem = icents % 1200u; + + // Think of "mult" as the factor that we multiply (440/2^6)Hz with, + // or in other words mult is the "first factor" of the above + // functions comment. + // + // Assuming sizeof(uint)==4 this will give us a maximum range of + // 32 * 1200cents - 300cents == 38100 cents == 29,527,900,160 Hz + // which is much more than ever needed. For bigger values, just + // safely wrap around (the & is just a replacement for the quick + // modulo operation % 32). + mult = 1u << (fac & (sizeof(mult)*8u - 1u)); + + // don't use ldexp() either (poor performance) + return mult * fluid_ct2hz_tab[rem]; + } +} + +/* + * fluid_ct2hz + */ +fluid_real_t +fluid_ct2hz(fluid_real_t cents) +{ + /* Filter fc limit: SF2.01 page 48 # 8 */ + if(cents >= 13500) + { + cents = 13500; /* 20 kHz */ + } + else if(cents < 1500) + { + cents = 1500; /* 20 Hz */ + } + + return fluid_ct2hz_real(cents); +} + +/* + * fluid_cb2amp + * + * in: a value between 0 and 1440, 0 is no attenuation + * out: a value between 1 and 0 + */ +fluid_real_t +fluid_cb2amp(fluid_real_t cb) +{ + /* + * cb: an attenuation in 'centibels' (1/10 dB) + * SF2.01 page 49 # 48 limits it to 144 dB. + * 96 dB is reasonable for 16 bit systems, 144 would make sense for 24 bit. + */ + + /* minimum attenuation: 0 dB */ + if(cb < 0) + { + return 1.0; + } + + if(cb >= FLUID_CB_AMP_SIZE) + { + return 0.0; + } + + return fluid_cb2amp_tab[(int) cb]; +} + +/* + * fluid_tc2sec_delay + */ +fluid_real_t +fluid_tc2sec_delay(fluid_real_t tc) +{ + /* SF2.01 section 8.1.2 items 21, 23, 25, 33 + * SF2.01 section 8.1.3 items 21, 23, 25, 33 + * + * The most negative number indicates a delay of 0. Range is limited + * from -12000 to 5000 */ + if(tc <= -32768.0f) + { + return (fluid_real_t) 0.0f; + }; + + if(tc < -12000.f) + { + tc = (fluid_real_t) -12000.0f; + } + + if(tc > 5000.0f) + { + tc = (fluid_real_t) 5000.0f; + } + + return FLUID_POW(2.f, tc / 1200.f); +} + +/* + * fluid_tc2sec_attack + */ +fluid_real_t +fluid_tc2sec_attack(fluid_real_t tc) +{ + /* SF2.01 section 8.1.2 items 26, 34 + * SF2.01 section 8.1.3 items 26, 34 + * The most negative number indicates a delay of 0 + * Range is limited from -12000 to 8000 */ + if(tc <= -32768.f) + { + return (fluid_real_t) 0.f; + }; + + if(tc < -12000.f) + { + tc = (fluid_real_t) -12000.f; + }; + + if(tc > 8000.f) + { + tc = (fluid_real_t) 8000.f; + }; + + return FLUID_POW(2.f, tc / 1200.f); +} + +/* + * fluid_tc2sec + */ +fluid_real_t +fluid_tc2sec(fluid_real_t tc) +{ + /* No range checking here! */ + return FLUID_POW(2.f, tc / 1200.f); +} + +/* + * fluid_tc2sec_release + */ +fluid_real_t +fluid_tc2sec_release(fluid_real_t tc) +{ + /* SF2.01 section 8.1.2 items 30, 38 + * SF2.01 section 8.1.3 items 30, 38 + * No 'most negative number' rule here! + * Range is limited from -12000 to 8000 */ + if(tc <= -32768.f) + { + return (fluid_real_t) 0.f; + }; + + if(tc < -12000.f) + { + tc = (fluid_real_t) -12000.f; + }; + + if(tc > 8000.f) + { + tc = (fluid_real_t) 8000.f; + }; + + return FLUID_POW(2.f, tc / 1200.f); +} + +/* + * fluid_act2hz + * + * Convert from absolute cents to Hertz + * + * The inverse operation, converting from Hertz to cents, was unused and implemented as + * +fluid_hz2ct(fluid_real_t f) +{ + return 6900.f + (1200.f / FLUID_M_LN2) * FLUID_LOGF(f / 440.0f)); +} + */ +double +fluid_act2hz(double c) +{ + // do not use FLUID_POW, otherwise the unit tests will fail when compiled in single precision + return 8.1757989156437073336828122976032719176391831357 * pow(2.f, c / 1200.f); +} + +/* + * fluid_pan + */ +fluid_real_t +fluid_pan(fluid_real_t c, int left) +{ + if(left) + { + c = -c; + } + + if(c <= -500.f) + { + return (fluid_real_t) 0.f; + } + else if(c >= 500.f) + { + return (fluid_real_t) 1.f; + } + else + { + return fluid_pan_tab[(int)(c) + 500]; + } +} + +/* + * Return the amount of attenuation based on the balance for the specified + * channel. If balance is negative (turned toward left channel, only the right + * channel is attenuated. If balance is positive, only the left channel is + * attenuated. + * + * @params balance left/right balance, range [-960;960] in absolute centibels + * @return amount of attenuation [0.0;1.0] + */ +fluid_real_t fluid_balance(fluid_real_t balance, int left) +{ + /* This is the most common case */ + if(balance == 0.f) + { + return 1.0f; + } + + if((left && balance < 0.f) || (!left && balance > 0.f)) + { + return 1.0f; + } + + if(balance < 0.f) + { + balance = -balance; + } + + return fluid_cb2amp(balance); +} + +/* + * fluid_concave + */ +fluid_real_t +fluid_concave(fluid_real_t val) +{ + int ival = (int)val; + if(val < 0.f) + { + return 0.f; + } + else if (ival >= FLUID_VEL_CB_SIZE - 1) + { + return fluid_concave_tab[FLUID_VEL_CB_SIZE - 1]; + } + + return fluid_concave_tab[ival] + (fluid_concave_tab[ival + 1] - fluid_concave_tab[ival]) * (val - ival); +} + +/* + * fluid_convex + */ +fluid_real_t +fluid_convex(fluid_real_t val) +{ + int ival = (int)val; + if(val < 0.f) + { + return 0.f; + } + else if (ival >= FLUID_VEL_CB_SIZE - 1) + { + return fluid_convex_tab[FLUID_VEL_CB_SIZE - 1]; + } + + // interpolation between convex steps: fixes bad sounds with modenv and filter cutoff + return fluid_convex_tab[ival] + (fluid_convex_tab[ival + 1] - fluid_convex_tab[ival]) * (val - ival); +} diff --git a/libs/fluidsynth/src/utils/fluid_conv.h b/libs/fluidsynth/src/utils/fluid_conv.h new file mode 100644 index 00000000000..985c02d0b38 --- /dev/null +++ b/libs/fluidsynth/src/utils/fluid_conv.h @@ -0,0 +1,40 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUID_CONV_H +#define _FLUID_CONV_H + +#include "fluidsynth_priv.h" +#include "utils/fluid_conv_tables.h" + +fluid_real_t fluid_ct2hz_real(fluid_real_t cents); +fluid_real_t fluid_ct2hz(fluid_real_t cents); +fluid_real_t fluid_cb2amp(fluid_real_t cb); +fluid_real_t fluid_tc2sec(fluid_real_t tc); +fluid_real_t fluid_tc2sec_delay(fluid_real_t tc); +fluid_real_t fluid_tc2sec_attack(fluid_real_t tc); +fluid_real_t fluid_tc2sec_release(fluid_real_t tc); +double fluid_act2hz(double c); +fluid_real_t fluid_pan(fluid_real_t c, int left); +fluid_real_t fluid_balance(fluid_real_t balance, int left); +fluid_real_t fluid_concave(fluid_real_t val); +fluid_real_t fluid_convex(fluid_real_t val); + +#endif /* _FLUID_CONV_H */ diff --git a/libs/fluidsynth/src/utils/fluid_conv_tables.h b/libs/fluidsynth/src/utils/fluid_conv_tables.h new file mode 100644 index 00000000000..8d1ae71540a --- /dev/null +++ b/libs/fluidsynth/src/utils/fluid_conv_tables.h @@ -0,0 +1,41 @@ + +#ifndef _FLUID_CONV_TABLES_H +#define _FLUID_CONV_TABLES_H + +/* + Attenuation range in centibels. + Attenuation range is the dynamic range of the volume envelope generator + from 0 to the end of attack segment. + fluidsynth is a 24 bit synth, it could (should??) be 144 dB of attenuation. + However the spec makes no distinction between 16 or 24 bit synths, so use + 96 dB here. + + Note about usefulness of 24 bits: + 1)Even fluidsynth is a 24 bit synth, this format is only relevant if + the sample format coming from the soundfont is 24 bits and the audio sample format + chosen by the application (audio.sample.format) is not 16 bits. + + 2)When the sample soundfont is 16 bits, the internal 24 bits number have + 16 bits msb and lsb to 0. Consequently, at the DAC output, the dynamic range of + this 24 bit sample is reduced to the the dynamic of a 16 bits sample (ie 90 db) + even if this sample is produced by the audio driver using an audio sample format + compatible for a 24 bit DAC. + + 3)When the audio sample format settings is 16 bits (audio.sample.format), the + audio driver will make use of a 16 bit DAC, and the dynamic will be reduced to 96 dB + even if the initial sample comes from a 24 bits soundfont. + + In both cases (2) or (3), the real dynamic range is only 96 dB. + + Other consideration for FLUID_NOISE_FLOOR related to case (1),(2,3): + - for case (1), FLUID_NOISE_FLOOR should be the noise floor for 24 bits (i.e -138 dB). + - for case (2) or (3), FLUID_NOISE_FLOOR should be the noise floor for 16 bits (i.e -90 dB). + */ +#define FLUID_PEAK_ATTENUATION 960.0f + +#define FLUID_CENTS_HZ_SIZE 1200 +#define FLUID_VEL_CB_SIZE 128 +#define FLUID_CB_AMP_SIZE 1441 +#define FLUID_PAN_SIZE 1002 + +#endif diff --git a/libs/fluidsynth/src/utils/fluid_hash.c b/libs/fluidsynth/src/utils/fluid_hash.c new file mode 100644 index 00000000000..7efd0deddad --- /dev/null +++ b/libs/fluidsynth/src/utils/fluid_hash.c @@ -0,0 +1,1407 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02110-1301, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GLib Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + * + * Adapted for FluidSynth use by Josh Green + * September 8, 2009 from glib 2.18.4 + */ + +/* + * MT safe + */ + +#include "fluid_sys.h" +#include "fluid_hash.h" +#include "fluid_list.h" + + +#define HASH_TABLE_MIN_SIZE 11 +#define HASH_TABLE_MAX_SIZE 13845163 + + +typedef struct +{ + fluid_hashtable_t *hashtable; + fluid_hashnode_t *prev_node; + fluid_hashnode_t *node; + int position; + int pre_advanced; // Boolean + int version; +} RealIter; + + +/* Excerpt from glib gprimes.c */ + +static const unsigned int primes[] = +{ + 11, + 19, + 37, + 73, + 109, + 163, + 251, + 367, + 557, + 823, + 1237, + 1861, + 2777, + 4177, + 6247, + 9371, + 14057, + 21089, + 31627, + 47431, + 71143, + 106721, + 160073, + 240101, + 360163, + 540217, + 810343, + 1215497, + 1823231, + 2734867, + 4102283, + 6153409, + 9230113, + 13845163, +}; + +static const unsigned int nprimes = FLUID_N_ELEMENTS(primes); + +static unsigned int +spaced_primes_closest(unsigned int num) +{ + unsigned int i; + + for(i = 0; i < nprimes; i++) + { + if(primes[i] > num) + { + return primes[i]; + } + } + + return primes[nprimes - 1]; +} + +/* End excerpt from glib gprimes.c */ + + +/* + * @hashtable: our #fluid_hashtable_t + * @key: the key to lookup against + * @hash_return: optional key hash return location + * Return value: a pointer to the described #fluid_hashnode_t pointer + * + * Performs a lookup in the hash table. Virtually all hash operations + * will use this function internally. + * + * This function first computes the hash value of the key using the + * user's hash function. + * + * If an entry in the table matching @key is found then this function + * returns a pointer to the pointer to that entry in the table. In + * the case that the entry is at the head of a chain, this pointer + * will be an item in the nodes[] array. In the case that the entry + * is not at the head of a chain, this pointer will be the ->next + * pointer on the node that precedes it. + * + * In the case that no matching entry exists in the table, a pointer + * to a %NULL pointer will be returned. To insert a item, this %NULL + * pointer should be updated to point to the new #fluid_hashnode_t. + * + * If @hash_return is a pass-by-reference parameter. If it is + * non-%NULL then the computed hash value is returned. This is to + * save insertions from having to compute the hash record again for + * the new record. + */ +static FLUID_INLINE fluid_hashnode_t ** +fluid_hashtable_lookup_node(fluid_hashtable_t *hashtable, const void *key, + unsigned int *hash_return) +{ + fluid_hashnode_t **node_ptr, *node; + unsigned int hash_value; + + hash_value = (* hashtable->hash_func)(key); + node_ptr = &hashtable->nodes[hash_value % hashtable->size]; + + if(hash_return) + { + *hash_return = hash_value; + } + + /* Hash table lookup needs to be fast. + * We therefore remove the extra conditional of testing + * whether to call the key_equal_func or not from + * the inner loop. + * + * Additional optimisation: first check if our full hash + * values are equal so we can avoid calling the full-blown + * key equality function in most cases. + */ + if(hashtable->key_equal_func) + { + while((node = *node_ptr)) + { + if(node->key_hash == hash_value && + hashtable->key_equal_func(node->key, key)) + { + break; + } + + node_ptr = &(*node_ptr)->next; + } + } + else + { + while((node = *node_ptr)) + { + if(node->key == key) + { + break; + } + + node_ptr = &(*node_ptr)->next; + } + } + + return node_ptr; +} + +/* + * @hashtable: our #fluid_hashtable_t + * @node_ptr_ptr: a pointer to the return value from + * fluid_hashtable_lookup_node() + * @notify: %TRUE if the destroy notify handlers are to be called + * + * Removes a node from the hash table and updates the node count. The + * node is freed. No table resize is performed. + * + * If @notify is %TRUE then the destroy notify functions are called + * for the key and value of the hash node. + * + * @node_ptr_ptr is a pass-by-reference in/out parameter. When the + * function is called, it should point to the pointer to the node to + * remove. This level of indirection is required so that the pointer + * may be updated appropriately once the node has been removed. + * + * Before the function returns, the pointer at @node_ptr_ptr will be + * updated to point to the position in the table that contains the + * pointer to the "next" node in the chain. This makes this function + * convenient to use from functions that iterate over the entire + * table. If there is no further item in the chain then the + * #fluid_hashnode_t pointer will be %NULL (ie: **node_ptr_ptr == %NULL). + * + * Since the pointer in the table to the removed node is replaced with + * either a pointer to the next node or a %NULL pointer as + * appropriate, the pointer at the end of @node_ptr_ptr will never be + * modified at all. Stay tuned. :) + */ +static void +fluid_hashtable_remove_node(fluid_hashtable_t *hashtable, + fluid_hashnode_t ***node_ptr_ptr, int notify) +{ + fluid_hashnode_t **node_ptr, *node; + + node_ptr = *node_ptr_ptr; + node = *node_ptr; + + *node_ptr = node->next; + + if(notify && hashtable->key_destroy_func) + { + hashtable->key_destroy_func(node->key); + } + + if(notify && hashtable->value_destroy_func) + { + hashtable->value_destroy_func(node->value); + } + + FLUID_FREE(node); + + hashtable->nnodes--; +} + +/* + * fluid_hashtable_remove_all_nodes: + * @hashtable: our #fluid_hashtable_t + * @notify: %TRUE if the destroy notify handlers are to be called + * + * Removes all nodes from the table. Since this may be a precursor to + * freeing the table entirely, no resize is performed. + * + * If @notify is %TRUE then the destroy notify functions are called + * for the key and value of the hash node. + */ +static void +fluid_hashtable_remove_all_nodes(fluid_hashtable_t *hashtable, int notify) +{ + fluid_hashnode_t **node_ptr; + int i; + + for(i = 0; i < hashtable->size; i++) + { + for(node_ptr = &hashtable->nodes[i]; *node_ptr != NULL;) + { + fluid_hashtable_remove_node(hashtable, &node_ptr, notify); + } + } + + hashtable->nnodes = 0; +} + +/* + * fluid_hashtable_resize: + * @hashtable: our #fluid_hashtable_t + * + * Resizes the hash table to the optimal size based on the number of + * nodes currently held. If you call this function then a resize will + * occur, even if one does not need to occur. Use + * fluid_hashtable_maybe_resize() instead. + */ +static void +fluid_hashtable_resize(fluid_hashtable_t *hashtable) +{ + fluid_hashnode_t **new_nodes; + fluid_hashnode_t *node; + fluid_hashnode_t *next; + unsigned int hash_val; + int new_size; + int i; + + new_size = spaced_primes_closest(hashtable->nnodes); + new_size = (new_size < HASH_TABLE_MIN_SIZE) ? HASH_TABLE_MIN_SIZE : + ((new_size > HASH_TABLE_MAX_SIZE) ? HASH_TABLE_MAX_SIZE : new_size); + + new_nodes = FLUID_ARRAY(fluid_hashnode_t *, new_size); + + if(!new_nodes) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return; + } + + FLUID_MEMSET(new_nodes, 0, new_size * sizeof(fluid_hashnode_t *)); + + for(i = 0; i < hashtable->size; i++) + { + for(node = hashtable->nodes[i]; node; node = next) + { + next = node->next; + + hash_val = node->key_hash % new_size; + + node->next = new_nodes[hash_val]; + new_nodes[hash_val] = node; + } + } + + FLUID_FREE(hashtable->nodes); + hashtable->nodes = new_nodes; + hashtable->size = new_size; +} + +/* + * fluid_hashtable_maybe_resize: + * @hashtable: our #fluid_hashtable_t + * + * Resizes the hash table, if needed. + * + * Essentially, calls fluid_hashtable_resize() if the table has strayed + * too far from its ideal size for its number of nodes. + */ +static FLUID_INLINE void +fluid_hashtable_maybe_resize(fluid_hashtable_t *hashtable) +{ + int nnodes = hashtable->nnodes; + int size = hashtable->size; + + if((size >= 3 * nnodes && size > HASH_TABLE_MIN_SIZE) || + (3 * size <= nnodes && size < HASH_TABLE_MAX_SIZE)) + { + fluid_hashtable_resize(hashtable); + } +} + +/** + * new_fluid_hashtable: + * @hash_func: a function to create a hash value from a key. + * Hash values are used to determine where keys are stored within the + * #fluid_hashtable_t data structure. The fluid_direct_hash(), fluid_int_hash() and + * fluid_str_hash() functions are provided for some common types of keys. + * If hash_func is %NULL, fluid_direct_hash() is used. + * @key_equal_func: a function to check two keys for equality. This is + * used when looking up keys in the #fluid_hashtable_t. The fluid_direct_equal(), + * fluid_int_equal() and fluid_str_equal() functions are provided for the most + * common types of keys. If @key_equal_func is %NULL, keys are compared + * directly in a similar fashion to fluid_direct_equal(), but without the + * overhead of a function call. + * + * Creates a new #fluid_hashtable_t with a reference count of 1. + * + * Return value: a new #fluid_hashtable_t. + **/ +fluid_hashtable_t * +new_fluid_hashtable(fluid_hash_func_t hash_func, fluid_equal_func_t key_equal_func) +{ + return new_fluid_hashtable_full(hash_func, key_equal_func, NULL, NULL); +} + + +/** + * new_fluid_hashtable_full: + * @hash_func: a function to create a hash value from a key. + * @key_equal_func: a function to check two keys for equality. + * @key_destroy_func: a function to free the memory allocated for the key + * used when removing the entry from the #fluid_hashtable_t or %NULL if you + * don't want to supply such a function. + * @value_destroy_func: a function to free the memory allocated for the + * value used when removing the entry from the #fluid_hashtable_t or %NULL if + * you don't want to supply such a function. + * + * Creates a new #fluid_hashtable_t like fluid_hashtable_new() with a reference count + * of 1 and allows to specify functions to free the memory allocated for the + * key and value that get called when removing the entry from the #fluid_hashtable_t. + * + * Return value: a new #fluid_hashtable_t. + **/ +fluid_hashtable_t * +new_fluid_hashtable_full(fluid_hash_func_t hash_func, + fluid_equal_func_t key_equal_func, + fluid_destroy_notify_t key_destroy_func, + fluid_destroy_notify_t value_destroy_func) +{ + fluid_hashtable_t *hashtable; + + hashtable = FLUID_NEW(fluid_hashtable_t); + + if(!hashtable) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + hashtable->size = HASH_TABLE_MIN_SIZE; + hashtable->nnodes = 0; + hashtable->hash_func = hash_func ? hash_func : fluid_direct_hash; + hashtable->key_equal_func = key_equal_func; + fluid_atomic_int_set(&hashtable->ref_count, 1); + hashtable->key_destroy_func = key_destroy_func; + hashtable->value_destroy_func = value_destroy_func; + hashtable->nodes = FLUID_ARRAY(fluid_hashnode_t *, hashtable->size); + if(hashtable->nodes == NULL) + { + delete_fluid_hashtable(hashtable); + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + FLUID_MEMSET(hashtable->nodes, 0, hashtable->size * sizeof(*hashtable->nodes)); + + return hashtable; +} + +/** + * fluid_hashtable_iter_init: + * @iter: an uninitialized #fluid_hashtable_iter_t. + * @hashtable: a #fluid_hashtable_t. + * + * Initializes a key/value pair iterator and associates it with + * @hashtable. Modifying the hash table after calling this function + * invalidates the returned iterator. + * |[ + * fluid_hashtable_iter_t iter; + * gpointer key, value; + * + * fluid_hashtable_iter_init (&iter, hashtable); + * while (fluid_hashtable_iter_next (&iter, &key, &value)) + * { + * /* do something with key and value */ + * } + * ]| + * + * Since: 2.16 + **/ +void +fluid_hashtable_iter_init(fluid_hashtable_iter_t *iter, + fluid_hashtable_t *hashtable) +{ + RealIter *ri = (RealIter *) iter; + + fluid_return_if_fail(iter != NULL); + fluid_return_if_fail(hashtable != NULL); + + ri->hashtable = hashtable; + ri->prev_node = NULL; + ri->node = NULL; + ri->position = -1; + ri->pre_advanced = FALSE; +} + +/** + * fluid_hashtable_iter_next: + * @iter: an initialized #fluid_hashtable_iter_t. + * @key: a location to store the key, or %NULL. + * @value: a location to store the value, or %NULL. + * + * Advances @iter and retrieves the key and/or value that are now + * pointed to as a result of this advancement. If %FALSE is returned, + * @key and @value are not set, and the iterator becomes invalid. + * + * Return value: %FALSE if the end of the #fluid_hashtable_t has been reached. + * + * Since: 2.16 + **/ +int +fluid_hashtable_iter_next(fluid_hashtable_iter_t *iter, void **key, + void **value) +{ + RealIter *ri = (RealIter *) iter; + + fluid_return_val_if_fail(iter != NULL, FALSE); + + if(ri->pre_advanced) + { + ri->pre_advanced = FALSE; + + if(ri->node == NULL) + { + return FALSE; + } + } + else + { + if(ri->node != NULL) + { + ri->prev_node = ri->node; + ri->node = ri->node->next; + } + + while(ri->node == NULL) + { + ri->position++; + + if(ri->position >= ri->hashtable->size) + { + return FALSE; + } + + ri->prev_node = NULL; + ri->node = ri->hashtable->nodes[ri->position]; + } + } + + if(key != NULL) + { + *key = ri->node->key; + } + + if(value != NULL) + { + *value = ri->node->value; + } + + return TRUE; +} + +/** + * fluid_hashtable_iter_get_hash_table: + * @iter: an initialized #fluid_hashtable_iter_t. + * + * Returns the #fluid_hashtable_t associated with @iter. + * + * Return value: the #fluid_hashtable_t associated with @iter. + * + * Since: 2.16 + **/ +fluid_hashtable_t * +fluid_hashtable_iter_get_hash_table(fluid_hashtable_iter_t *iter) +{ + fluid_return_val_if_fail(iter != NULL, NULL); + + return ((RealIter *) iter)->hashtable; +} + +static void +iter_remove_or_steal(RealIter *ri, int notify) +{ + fluid_hashnode_t *prev; + fluid_hashnode_t *node; + int position; + + fluid_return_if_fail(ri != NULL); + fluid_return_if_fail(ri->node != NULL); + + prev = ri->prev_node; + node = ri->node; + position = ri->position; + + /* pre-advance the iterator since we will remove the node */ + + ri->node = ri->node->next; + /* ri->prev_node is still the correct previous node */ + + while(ri->node == NULL) + { + ri->position++; + + if(ri->position >= ri->hashtable->size) + { + break; + } + + ri->prev_node = NULL; + ri->node = ri->hashtable->nodes[ri->position]; + } + + ri->pre_advanced = TRUE; + + /* remove the node */ + + if(prev != NULL) + { + prev->next = node->next; + } + else + { + ri->hashtable->nodes[position] = node->next; + } + + if(notify) + { + if(ri->hashtable->key_destroy_func) + { + ri->hashtable->key_destroy_func(node->key); + } + + if(ri->hashtable->value_destroy_func) + { + ri->hashtable->value_destroy_func(node->value); + } + } + + FLUID_FREE(node); + + ri->hashtable->nnodes--; +} + +/** + * fluid_hashtable_iter_remove(): + * @iter: an initialized #fluid_hashtable_iter_t. + * + * Removes the key/value pair currently pointed to by the iterator + * from its associated #fluid_hashtable_t. Can only be called after + * fluid_hashtable_iter_next() returned %TRUE, and cannot be called more + * than once for the same key/value pair. + * + * If the #fluid_hashtable_t was created using fluid_hashtable_new_full(), the + * key and value are freed using the supplied destroy functions, otherwise + * you have to make sure that any dynamically allocated values are freed + * yourself. + * + * Since: 2.16 + **/ +void +fluid_hashtable_iter_remove(fluid_hashtable_iter_t *iter) +{ + iter_remove_or_steal((RealIter *) iter, TRUE); +} + +/** + * fluid_hashtable_iter_steal(): + * @iter: an initialized #fluid_hashtable_iter_t. + * + * Removes the key/value pair currently pointed to by the iterator + * from its associated #fluid_hashtable_t, without calling the key and value + * destroy functions. Can only be called after + * fluid_hashtable_iter_next() returned %TRUE, and cannot be called more + * than once for the same key/value pair. + * + * Since: 2.16 + **/ +void +fluid_hashtable_iter_steal(fluid_hashtable_iter_t *iter) +{ + iter_remove_or_steal((RealIter *) iter, FALSE); +} + + +/** + * fluid_hashtable_ref: + * @hashtable: a valid #fluid_hashtable_t. + * + * Atomically increments the reference count of @hashtable by one. + * This function is MT-safe and may be called from any thread. + * + * Return value: the passed in #fluid_hashtable_t. + * + * Since: 2.10 + **/ +fluid_hashtable_t * +fluid_hashtable_ref(fluid_hashtable_t *hashtable) +{ + fluid_return_val_if_fail(hashtable != NULL, NULL); + fluid_return_val_if_fail(fluid_atomic_int_get(&hashtable->ref_count) > 0, hashtable); + + fluid_atomic_int_add(&hashtable->ref_count, 1); + return hashtable; +} + +/** + * fluid_hashtable_unref: + * @hashtable: a valid #fluid_hashtable_t. + * + * Atomically decrements the reference count of @hashtable by one. + * If the reference count drops to 0, all keys and values will be + * destroyed, and all memory allocated by the hash table is released. + * This function is MT-safe and may be called from any thread. + * + * Since: 2.10 + **/ +void +fluid_hashtable_unref(fluid_hashtable_t *hashtable) +{ + fluid_return_if_fail(hashtable != NULL); + fluid_return_if_fail(fluid_atomic_int_get(&hashtable->ref_count) > 0); + + if(fluid_atomic_int_exchange_and_add(&hashtable->ref_count, -1) - 1 == 0) + { + fluid_hashtable_remove_all_nodes(hashtable, TRUE); + FLUID_FREE(hashtable->nodes); + FLUID_FREE(hashtable); + } +} + +/** + * delete_fluid_hashtable: + * @hashtable: a #fluid_hashtable_t. + * + * Destroys all keys and values in the #fluid_hashtable_t and decrements its + * reference count by 1. If keys and/or values are dynamically allocated, + * you should either free them first or create the #fluid_hashtable_t with destroy + * notifiers using fluid_hashtable_new_full(). In the latter case the destroy + * functions you supplied will be called on all keys and values during the + * destruction phase. + **/ +void +delete_fluid_hashtable(fluid_hashtable_t *hashtable) +{ + fluid_return_if_fail(hashtable != NULL); + fluid_return_if_fail(fluid_atomic_int_get(&hashtable->ref_count) > 0); + + fluid_hashtable_remove_all(hashtable); + fluid_hashtable_unref(hashtable); +} + +/** + * fluid_hashtable_lookup: + * @hashtable: a #fluid_hashtable_t. + * @key: the key to look up. + * + * Looks up a key in a #fluid_hashtable_t. Note that this function cannot + * distinguish between a key that is not present and one which is present + * and has the value %NULL. If you need this distinction, use + * fluid_hashtable_lookup_extended(). + * + * Return value: the associated value, or %NULL if the key is not found. + **/ +void * +fluid_hashtable_lookup(fluid_hashtable_t *hashtable, const void *key) +{ + fluid_hashnode_t *node; + + fluid_return_val_if_fail(hashtable != NULL, NULL); + + node = *fluid_hashtable_lookup_node(hashtable, key, NULL); + + return node ? node->value : NULL; +} + +/** + * fluid_hashtable_lookup_extended: + * @hashtable: a #fluid_hashtable_t. + * @lookup_key: the key to look up. + * @orig_key: returns the original key. + * @value: returns the value associated with the key. + * + * Looks up a key in the #fluid_hashtable_t, returning the original key and the + * associated value and a #gboolean which is %TRUE if the key was found. This + * is useful if you need to free the memory allocated for the original key, + * for example before calling fluid_hashtable_remove(). + * + * Return value: %TRUE if the key was found in the #fluid_hashtable_t. + **/ +int +fluid_hashtable_lookup_extended(fluid_hashtable_t *hashtable, + const void *lookup_key, + void **orig_key, void **value) +{ + fluid_hashnode_t *node; + + fluid_return_val_if_fail(hashtable != NULL, FALSE); + + node = *fluid_hashtable_lookup_node(hashtable, lookup_key, NULL); + + if(node == NULL) + { + return FALSE; + } + + if(orig_key) + { + *orig_key = node->key; + } + + if(value) + { + *value = node->value; + } + + return TRUE; +} + +/* + * fluid_hashtable_insert_internal: + * @hashtable: our #fluid_hashtable_t + * @key: the key to insert + * @value: the value to insert + * @keep_new_key: if %TRUE and this key already exists in the table + * then call the destroy notify function on the old key. If %FALSE + * then call the destroy notify function on the new key. + * + * Implements the common logic for the fluid_hashtable_insert() and + * fluid_hashtable_replace() functions. + * + * Do a lookup of @key. If it is found, replace it with the new + * @value (and perhaps the new @key). If it is not found, create a + * new node. + */ +static void +fluid_hashtable_insert_internal(fluid_hashtable_t *hashtable, void *key, + void *value, int keep_new_key) +{ + fluid_hashnode_t **node_ptr, *node; + unsigned int key_hash; + + fluid_return_if_fail(hashtable != NULL); + fluid_return_if_fail(fluid_atomic_int_get(&hashtable->ref_count) > 0); + + node_ptr = fluid_hashtable_lookup_node(hashtable, key, &key_hash); + + if((node = *node_ptr)) + { + if(keep_new_key) + { + if(hashtable->key_destroy_func) + { + hashtable->key_destroy_func(node->key); + } + + node->key = key; + } + else + { + if(hashtable->key_destroy_func) + { + hashtable->key_destroy_func(key); + } + } + + if(hashtable->value_destroy_func) + { + hashtable->value_destroy_func(node->value); + } + + node->value = value; + } + else + { + node = FLUID_NEW(fluid_hashnode_t); + + if(!node) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return; + } + + node->key = key; + node->value = value; + node->key_hash = key_hash; + node->next = NULL; + + *node_ptr = node; + hashtable->nnodes++; + fluid_hashtable_maybe_resize(hashtable); + } +} + +/** + * fluid_hashtable_insert: + * @hashtable: a #fluid_hashtable_t. + * @key: a key to insert. + * @value: the value to associate with the key. + * + * Inserts a new key and value into a #fluid_hashtable_t. + * + * If the key already exists in the #fluid_hashtable_t its current value is replaced + * with the new value. If you supplied a @value_destroy_func when creating the + * #fluid_hashtable_t, the old value is freed using that function. If you supplied + * a @key_destroy_func when creating the #fluid_hashtable_t, the passed key is freed + * using that function. + **/ +void +fluid_hashtable_insert(fluid_hashtable_t *hashtable, void *key, void *value) +{ + fluid_hashtable_insert_internal(hashtable, key, value, FALSE); +} + +/** + * fluid_hashtable_replace: + * @hashtable: a #fluid_hashtable_t. + * @key: a key to insert. + * @value: the value to associate with the key. + * + * Inserts a new key and value into a #fluid_hashtable_t similar to + * fluid_hashtable_insert(). The difference is that if the key already exists + * in the #fluid_hashtable_t, it gets replaced by the new key. If you supplied a + * @value_destroy_func when creating the #fluid_hashtable_t, the old value is freed + * using that function. If you supplied a @key_destroy_func when creating the + * #fluid_hashtable_t, the old key is freed using that function. + **/ +void +fluid_hashtable_replace(fluid_hashtable_t *hashtable, void *key, void *value) +{ + fluid_hashtable_insert_internal(hashtable, key, value, TRUE); +} + +/* + * fluid_hashtable_remove_internal: + * @hashtable: our #fluid_hashtable_t + * @key: the key to remove + * @notify: %TRUE if the destroy notify handlers are to be called + * Return value: %TRUE if a node was found and removed, else %FALSE + * + * Implements the common logic for the fluid_hashtable_remove() and + * fluid_hashtable_steal() functions. + * + * Do a lookup of @key and remove it if it is found, calling the + * destroy notify handlers only if @notify is %TRUE. + */ +static int +fluid_hashtable_remove_internal(fluid_hashtable_t *hashtable, const void *key, + int notify) +{ + fluid_hashnode_t **node_ptr; + + fluid_return_val_if_fail(hashtable != NULL, FALSE); + + node_ptr = fluid_hashtable_lookup_node(hashtable, key, NULL); + + if(*node_ptr == NULL) + { + return FALSE; + } + + fluid_hashtable_remove_node(hashtable, &node_ptr, notify); + fluid_hashtable_maybe_resize(hashtable); + + return TRUE; +} + +/** + * fluid_hashtable_remove: + * @hashtable: a #fluid_hashtable_t. + * @key: the key to remove. + * + * Removes a key and its associated value from a #fluid_hashtable_t. + * + * If the #fluid_hashtable_t was created using fluid_hashtable_new_full(), the + * key and value are freed using the supplied destroy functions, otherwise + * you have to make sure that any dynamically allocated values are freed + * yourself. + * + * Return value: %TRUE if the key was found and removed from the #fluid_hashtable_t. + **/ +int +fluid_hashtable_remove(fluid_hashtable_t *hashtable, const void *key) +{ + return fluid_hashtable_remove_internal(hashtable, key, TRUE); +} + +/** + * fluid_hashtable_steal: + * @hashtable: a #fluid_hashtable_t. + * @key: the key to remove. + * + * Removes a key and its associated value from a #fluid_hashtable_t without + * calling the key and value destroy functions. + * + * Return value: %TRUE if the key was found and removed from the #fluid_hashtable_t. + **/ +int +fluid_hashtable_steal(fluid_hashtable_t *hashtable, const void *key) +{ + return fluid_hashtable_remove_internal(hashtable, key, FALSE); +} + +/** + * fluid_hashtable_remove_all: + * @hashtable: a #fluid_hashtable_t + * + * Removes all keys and their associated values from a #fluid_hashtable_t. + * + * If the #fluid_hashtable_t was created using fluid_hashtable_new_full(), the keys + * and values are freed using the supplied destroy functions, otherwise you + * have to make sure that any dynamically allocated values are freed + * yourself. + * + * Since: 2.12 + **/ +void +fluid_hashtable_remove_all(fluid_hashtable_t *hashtable) +{ + fluid_return_if_fail(hashtable != NULL); + + fluid_hashtable_remove_all_nodes(hashtable, TRUE); + fluid_hashtable_maybe_resize(hashtable); +} + +/** + * fluid_hashtable_steal_all: + * @hashtable: a #fluid_hashtable_t. + * + * Removes all keys and their associated values from a #fluid_hashtable_t + * without calling the key and value destroy functions. + * + * Since: 2.12 + **/ +void +fluid_hashtable_steal_all(fluid_hashtable_t *hashtable) +{ + fluid_return_if_fail(hashtable != NULL); + + fluid_hashtable_remove_all_nodes(hashtable, FALSE); + fluid_hashtable_maybe_resize(hashtable); +} + +/* + * fluid_hashtable_foreach_remove_or_steal: + * @hashtable: our #fluid_hashtable_t + * @func: the user's callback function + * @user_data: data for @func + * @notify: %TRUE if the destroy notify handlers are to be called + * + * Implements the common logic for fluid_hashtable_foreach_remove() and + * fluid_hashtable_foreach_steal(). + * + * Iterates over every node in the table, calling @func with the key + * and value of the node (and @user_data). If @func returns %TRUE the + * node is removed from the table. + * + * If @notify is true then the destroy notify handlers will be called + * for each removed node. + */ +static unsigned int +fluid_hashtable_foreach_remove_or_steal(fluid_hashtable_t *hashtable, + fluid_hr_func_t func, void *user_data, + int notify) +{ + fluid_hashnode_t *node, **node_ptr; + unsigned int deleted = 0; + int i; + + for(i = 0; i < hashtable->size; i++) + { + for(node_ptr = &hashtable->nodes[i]; (node = *node_ptr) != NULL;) + { + if((* func)(node->key, node->value, user_data)) + { + fluid_hashtable_remove_node(hashtable, &node_ptr, notify); + deleted++; + } + else + { + node_ptr = &node->next; + } + } + } + + fluid_hashtable_maybe_resize(hashtable); + + return deleted; +} + +#if 0 +/** + * fluid_hashtable_foreach_remove: + * @hashtable: a #fluid_hashtable_t. + * @func: the function to call for each key/value pair. + * @user_data: user data to pass to the function. + * + * Calls the given function for each key/value pair in the #fluid_hashtable_t. + * If the function returns %TRUE, then the key/value pair is removed from the + * #fluid_hashtable_t. If you supplied key or value destroy functions when creating + * the #fluid_hashtable_t, they are used to free the memory allocated for the removed + * keys and values. + * + * See #fluid_hashtable_iter_t for an alternative way to loop over the + * key/value pairs in the hash table. + * + * Return value: the number of key/value pairs removed. + **/ +static unsigned int +fluid_hashtable_foreach_remove(fluid_hashtable_t *hashtable, + fluid_hr_func_t func, void *user_data) +{ + fluid_return_val_if_fail(hashtable != NULL, 0); + fluid_return_val_if_fail(func != NULL, 0); + + return fluid_hashtable_foreach_remove_or_steal(hashtable, func, user_data, TRUE); +} +#endif + +/** + * fluid_hashtable_foreach_steal: + * @hashtable: a #fluid_hashtable_t. + * @func: the function to call for each key/value pair. + * @user_data: user data to pass to the function. + * + * Calls the given function for each key/value pair in the #fluid_hashtable_t. + * If the function returns %TRUE, then the key/value pair is removed from the + * #fluid_hashtable_t, but no key or value destroy functions are called. + * + * See #fluid_hashtable_iter_t for an alternative way to loop over the + * key/value pairs in the hash table. + * + * Return value: the number of key/value pairs removed. + **/ +unsigned int +fluid_hashtable_foreach_steal(fluid_hashtable_t *hashtable, + fluid_hr_func_t func, void *user_data) +{ + fluid_return_val_if_fail(hashtable != NULL, 0); + fluid_return_val_if_fail(func != NULL, 0); + + return fluid_hashtable_foreach_remove_or_steal(hashtable, func, user_data, FALSE); +} + +/** + * fluid_hashtable_foreach: + * @hashtable: a #fluid_hashtable_t. + * @func: the function to call for each key/value pair. + * @user_data: user data to pass to the function. + * + * Calls the given function for each of the key/value pairs in the + * #fluid_hashtable_t. The function is passed the key and value of each + * pair, and the given @user_data parameter. The hash table may not + * be modified while iterating over it (you can't add/remove + * items). To remove all items matching a predicate, use + * fluid_hashtable_foreach_remove(). + * + * See fluid_hashtable_find() for performance caveats for linear + * order searches in contrast to fluid_hashtable_lookup(). + **/ +void +fluid_hashtable_foreach(fluid_hashtable_t *hashtable, fluid_hr_func_t func, + void *user_data) +{ + fluid_hashnode_t *node; + int i; + + fluid_return_if_fail(hashtable != NULL); + fluid_return_if_fail(func != NULL); + + for(i = 0; i < hashtable->size; i++) + { + for(node = hashtable->nodes[i]; node; node = node->next) + { + (* func)(node->key, node->value, user_data); + } + } +} + +/** + * fluid_hashtable_find: + * @hashtable: a #fluid_hashtable_t. + * @predicate: function to test the key/value pairs for a certain property. + * @user_data: user data to pass to the function. + * + * Calls the given function for key/value pairs in the #fluid_hashtable_t until + * @predicate returns %TRUE. The function is passed the key and value of + * each pair, and the given @user_data parameter. The hash table may not + * be modified while iterating over it (you can't add/remove items). + * + * Note, that hash tables are really only optimized for forward lookups, + * i.e. fluid_hashtable_lookup(). + * So code that frequently issues fluid_hashtable_find() or + * fluid_hashtable_foreach() (e.g. in the order of once per every entry in a + * hash table) should probably be reworked to use additional or different + * data structures for reverse lookups (keep in mind that an O(n) find/foreach + * operation issued for all n values in a hash table ends up needing O(n*n) + * operations). + * + * Return value: The value of the first key/value pair is returned, for which + * func evaluates to %TRUE. If no pair with the requested property is found, + * %NULL is returned. + * + * Since: 2.4 + **/ +void * +fluid_hashtable_find(fluid_hashtable_t *hashtable, fluid_hr_func_t predicate, + void *user_data) +{ + fluid_hashnode_t *node; + int i; + + fluid_return_val_if_fail(hashtable != NULL, NULL); + fluid_return_val_if_fail(predicate != NULL, NULL); + + for(i = 0; i < hashtable->size; i++) + { + for(node = hashtable->nodes[i]; node; node = node->next) + { + if(predicate(node->key, node->value, user_data)) + { + return node->value; + } + } + } + + return NULL; +} + +/** + * fluid_hashtable_size: + * @hashtable: a #fluid_hashtable_t. + * + * Returns the number of elements contained in the #fluid_hashtable_t. + * + * Return value: the number of key/value pairs in the #fluid_hashtable_t. + **/ +unsigned int +fluid_hashtable_size(fluid_hashtable_t *hashtable) +{ + fluid_return_val_if_fail(hashtable != NULL, 0); + + return hashtable->nnodes; +} + +/** + * fluid_hashtable_get_keys: + * @hashtable: a #fluid_hashtable_t + * + * Retrieves every key inside @hashtable. The returned data is valid + * until @hashtable is modified. + * + * Return value: a #GList containing all the keys inside the hash + * table. The content of the list is owned by the hash table and + * should not be modified or freed. Use delete_fluid_list() when done + * using the list. + * + * Since: 2.14 + */ +fluid_list_t * +fluid_hashtable_get_keys(fluid_hashtable_t *hashtable) +{ + fluid_hashnode_t *node; + int i; + fluid_list_t *retval; + + fluid_return_val_if_fail(hashtable != NULL, NULL); + + retval = NULL; + + for(i = 0; i < hashtable->size; i++) + { + for(node = hashtable->nodes[i]; node; node = node->next) + { + retval = fluid_list_prepend(retval, node->key); + } + } + + return retval; +} + +/** + * fluid_hashtable_get_values: + * @hashtable: a #fluid_hashtable_t + * + * Retrieves every value inside @hashtable. The returned data is + * valid until @hashtable is modified. + * + * Return value: a #GList containing all the values inside the hash + * table. The content of the list is owned by the hash table and + * should not be modified or freed. Use delete_fluid_list() when done + * using the list. + * + * Since: 2.14 + */ +fluid_list_t * +fluid_hashtable_get_values(fluid_hashtable_t *hashtable) +{ + fluid_hashnode_t *node; + int i; + fluid_list_t *retval; + + fluid_return_val_if_fail(hashtable != NULL, NULL); + + retval = NULL; + + for(i = 0; i < hashtable->size; i++) + { + for(node = hashtable->nodes[i]; node; node = node->next) + { + retval = fluid_list_prepend(retval, node->value); + } + } + + return retval; +} + + +/* Extracted from glib/gstring.c */ + + +/** + * fluid_str_equal: + * @v1: a key + * @v2: a key to compare with @v1 + * + * Compares two strings for byte-by-byte equality and returns %TRUE + * if they are equal. It can be passed to new_fluid_hashtable() as the + * @key_equal_func parameter, when using strings as keys in a #Ghashtable. + * + * Returns: %TRUE if the two keys match + */ +int +fluid_str_equal(const void *v1, const void *v2) +{ + const char *string1 = v1; + const char *string2 = v2; + + return FLUID_STRCMP(string1, string2) == 0; +} + +/** + * fluid_str_hash: + * @v: a string key + * + * Converts a string to a hash value. + * It can be passed to new_fluid_hashtable() as the @hash_func + * parameter, when using strings as keys in a #fluid_hashtable_t. + * + * Returns: a hash value corresponding to the key + */ +unsigned int +fluid_str_hash(const void *v) +{ + /* 31 bit hash function */ + const signed char *p = v; + uint32_t h = *p; + + if(h) + { + for(p += 1; *p != '\0'; p++) + { + h = (h << 5) - h + *p; + } + } + + return h; +} + + +/* Extracted from glib/gutils.c */ + + +/** + * fluid_direct_equal: + * @v1: a key. + * @v2: a key to compare with @v1. + * + * Compares two #gpointer arguments and returns %TRUE if they are equal. + * It can be passed to new_fluid_hashtable() as the @key_equal_func + * parameter, when using pointers as keys in a #fluid_hashtable_t. + * + * Returns: %TRUE if the two keys match. + */ +int +fluid_direct_equal(const void *v1, const void *v2) +{ + return v1 == v2; +} + +/** + * fluid_direct_hash: + * @v: a void * key + * + * Converts a gpointer to a hash value. + * It can be passed to g_hashtable_new() as the @hash_func parameter, + * when using pointers as keys in a #fluid_hashtable_t. + * + * Returns: a hash value corresponding to the key. + */ +unsigned int +fluid_direct_hash(const void *v) +{ + return FLUID_POINTER_TO_UINT(v); +} + +/** + * fluid_int_equal: + * @v1: a pointer to a int key. + * @v2: a pointer to a int key to compare with @v1. + * + * Compares the two #gint values being pointed to and returns + * %TRUE if they are equal. + * It can be passed to g_hashtable_new() as the @key_equal_func + * parameter, when using pointers to integers as keys in a #fluid_hashtable_t. + * + * Returns: %TRUE if the two keys match. + */ +int +fluid_int_equal(const void *v1, const void *v2) +{ + return *((const int *) v1) == *((const int *) v2); +} + +/** + * fluid_int_hash: + * @v: a pointer to a int key + * + * Converts a pointer to a #gint to a hash value. + * It can be passed to g_hashtable_new() as the @hash_func parameter, + * when using pointers to integers values as keys in a #fluid_hashtable_t. + * + * Returns: a hash value corresponding to the key. + */ +unsigned int +fluid_int_hash(const void *v) +{ + return *(const int *) v; +} diff --git a/libs/fluidsynth/src/utils/fluid_hash.h b/libs/fluidsynth/src/utils/fluid_hash.h new file mode 100644 index 00000000000..b801876833a --- /dev/null +++ b/libs/fluidsynth/src/utils/fluid_hash.h @@ -0,0 +1,130 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02110-1301, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GLib Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +/* + * Adapted for FluidSynth use by Josh Green + * September 8, 2009 from glib 2.18.4 + * + * - Self contained (no dependencies on glib) + * - changed names to fluid_hashtable_... + */ + +#ifndef _FLUID_HASH_H +#define _FLUID_HASH_H + +#include "fluidsynth_priv.h" +#include "fluid_list.h" +#include "fluid_sys.h" + +/* Extracted from gtypes.h */ +typedef void (*fluid_destroy_notify_t)(void *data); +typedef unsigned int (*fluid_hash_func_t)(const void *key); +typedef int (*fluid_equal_func_t)(const void *a, const void *b); +/* End gtypes.h extraction */ + +typedef int (*fluid_hr_func_t)(void *key, void *value, void *user_data); +typedef struct _fluid_hashtable_iter_t fluid_hashtable_iter_t; + +typedef struct _fluid_hashnode_t fluid_hashnode_t; + +struct _fluid_hashnode_t +{ + void *key; + void *value; + fluid_hashnode_t *next; + unsigned int key_hash; +}; + +struct _fluid_hashtable_t +{ + int size; + int nnodes; + fluid_hashnode_t **nodes; + fluid_hash_func_t hash_func; + fluid_equal_func_t key_equal_func; + fluid_atomic_int_t ref_count; + fluid_destroy_notify_t key_destroy_func; + fluid_destroy_notify_t value_destroy_func; + fluid_rec_mutex_t mutex; // Optionally used in other modules (fluid_settings.c for example) +}; + +struct _fluid_hashtable_iter_t +{ + /*< private >*/ + void *dummy1; + void *dummy2; + void *dummy3; + int dummy4; + int dummy5; // Bool + void *dummy6; +}; + +fluid_hashtable_t *new_fluid_hashtable(fluid_hash_func_t hash_func, + fluid_equal_func_t key_equal_func); +fluid_hashtable_t *new_fluid_hashtable_full(fluid_hash_func_t hash_func, + fluid_equal_func_t key_equal_func, + fluid_destroy_notify_t key_destroy_func, + fluid_destroy_notify_t value_destroy_func); +void delete_fluid_hashtable(fluid_hashtable_t *hashtable); + +void fluid_hashtable_iter_init(fluid_hashtable_iter_t *iter, fluid_hashtable_t *hashtable); +int fluid_hashtable_iter_next(fluid_hashtable_iter_t *iter, void **key, void **value); +fluid_hashtable_t *fluid_hashtable_iter_get_hash_table(fluid_hashtable_iter_t *iter); +void fluid_hashtable_iter_remove(fluid_hashtable_iter_t *iter); +void fluid_hashtable_iter_steal(fluid_hashtable_iter_t *iter); + +fluid_hashtable_t *fluid_hashtable_ref(fluid_hashtable_t *hashtable); +void fluid_hashtable_unref(fluid_hashtable_t *hashtable); + +void *fluid_hashtable_lookup(fluid_hashtable_t *hashtable, const void *key); +int fluid_hashtable_lookup_extended(fluid_hashtable_t *hashtable, const void *lookup_key, + void **orig_key, void **value); + +void fluid_hashtable_insert(fluid_hashtable_t *hashtable, void *key, void *value); +void fluid_hashtable_replace(fluid_hashtable_t *hashtable, void *key, void *value); + +int fluid_hashtable_remove(fluid_hashtable_t *hashtable, const void *key); +int fluid_hashtable_steal(fluid_hashtable_t *hashtable, const void *key); +void fluid_hashtable_remove_all(fluid_hashtable_t *hashtable); +void fluid_hashtable_steal_all(fluid_hashtable_t *hashtable); +unsigned int fluid_hashtable_foreach_steal(fluid_hashtable_t *hashtable, + fluid_hr_func_t func, void *user_data); +void fluid_hashtable_foreach(fluid_hashtable_t *hashtable, fluid_hr_func_t func, + void *user_data); +void *fluid_hashtable_find(fluid_hashtable_t *hashtable, fluid_hr_func_t predicate, + void *user_data); +unsigned int fluid_hashtable_size(fluid_hashtable_t *hashtable); +fluid_list_t *fluid_hashtable_get_keys(fluid_hashtable_t *hashtable); +fluid_list_t *fluid_hashtable_get_values(fluid_hashtable_t *hashtable); + +int fluid_str_equal(const void *v1, const void *v2); +unsigned int fluid_str_hash(const void *v); +int fluid_direct_equal(const void *v1, const void *v2); +unsigned int fluid_direct_hash(const void *v); +int fluid_int_equal(const void *v1, const void *v2); +unsigned int fluid_int_hash(const void *v); + +#endif /* _FLUID_HASH_H */ diff --git a/libs/fluidsynth/src/utils/fluid_list.c b/libs/fluidsynth/src/utils/fluid_list.c new file mode 100644 index 00000000000..c88e2aec097 --- /dev/null +++ b/libs/fluidsynth/src/utils/fluid_list.c @@ -0,0 +1,337 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02110-1301, USA. + */ + +/* + * Modified by the GLib Team and others 1997-1999. See the AUTHORS + * file for a list of people on the GLib Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + + + +#include "fluid_sys.h" +#include "fluid_list.h" + + +fluid_list_t * +new_fluid_list(void) +{ + fluid_list_t *list; + list = (fluid_list_t *) FLUID_MALLOC(sizeof(fluid_list_t)); + list->data = NULL; + list->next = NULL; + return list; +} + +void +delete_fluid_list(fluid_list_t *list) +{ + fluid_list_t *next; + fluid_return_if_fail(list != NULL); + + while(list) + { + next = list->next; + FLUID_FREE(list); + list = next; + } +} + +void +delete1_fluid_list(fluid_list_t *list) +{ + FLUID_FREE(list); +} + +fluid_list_t * +fluid_list_append(fluid_list_t *list, void *data) +{ + fluid_list_t *new_list; + fluid_list_t *last; + + new_list = new_fluid_list(); + new_list->data = data; + + if(list) + { + last = fluid_list_last(list); + /* g_assert (last != NULL); */ + last->next = new_list; + + return list; + } + else + { + return new_list; + } +} + +fluid_list_t * +fluid_list_prepend(fluid_list_t *list, void *data) +{ + fluid_list_t *new_list; + + new_list = new_fluid_list(); + new_list->data = data; + new_list->next = list; + + return new_list; +} + +fluid_list_t * +fluid_list_nth(fluid_list_t *list, int n) +{ + while((n-- > 0) && list) + { + list = list->next; + } + + return list; +} + +fluid_list_t * +fluid_list_remove(fluid_list_t *list, void *data) +{ + fluid_list_t *tmp; + fluid_list_t *prev; + + prev = NULL; + tmp = list; + + while(tmp) + { + if(tmp->data == data) + { + if(prev) + { + prev->next = tmp->next; + } + + if(list == tmp) + { + list = list->next; + } + + tmp->next = NULL; + delete_fluid_list(tmp); + + break; + } + + prev = tmp; + tmp = tmp->next; + } + + return list; +} + +fluid_list_t * +fluid_list_remove_link(fluid_list_t *list, fluid_list_t *link) +{ + fluid_list_t *tmp; + fluid_list_t *prev; + + prev = NULL; + tmp = list; + + while(tmp) + { + if(tmp == link) + { + if(prev) + { + prev->next = tmp->next; + } + + if(list == tmp) + { + list = list->next; + } + + tmp->next = NULL; + break; + } + + prev = tmp; + tmp = tmp->next; + } + + return list; +} + +static fluid_list_t * +fluid_list_sort_merge(fluid_list_t *l1, fluid_list_t *l2, fluid_compare_func_t compare_func) +{ + fluid_list_t list, *l; + + l = &list; + + while(l1 && l2) + { + if(compare_func(l1->data, l2->data) < 0) + { + l = l->next = l1; + l1 = l1->next; + } + else + { + l = l->next = l2; + l2 = l2->next; + } + } + + l->next = l1 ? l1 : l2; + + return list.next; +} + +fluid_list_t * +fluid_list_sort(fluid_list_t *list, fluid_compare_func_t compare_func) +{ + fluid_list_t *l1, *l2; + + if(!list) + { + return NULL; + } + + if(!list->next) + { + return list; + } + + l1 = list; + l2 = list->next; + + while((l2 = l2->next) != NULL) + { + if((l2 = l2->next) == NULL) + { + break; + } + + l1 = l1->next; + } + + l2 = l1->next; + l1->next = NULL; + + return fluid_list_sort_merge(fluid_list_sort(list, compare_func), + fluid_list_sort(l2, compare_func), + compare_func); +} + + +fluid_list_t * +fluid_list_last(fluid_list_t *list) +{ + if(list) + { + while(list->next) + { + list = list->next; + } + } + + return list; +} + +int +fluid_list_size(fluid_list_t *list) +{ + int n = 0; + + while(list) + { + n++; + list = list->next; + } + + return n; +} + +fluid_list_t *fluid_list_insert_at(fluid_list_t *list, int n, void *data) +{ + fluid_list_t *new_list; + fluid_list_t *cur; + fluid_list_t *prev = NULL; + + new_list = new_fluid_list(); + new_list->data = data; + + cur = list; + + while((n-- > 0) && cur) + { + prev = cur; + cur = cur->next; + } + + new_list->next = cur; + + if(prev) + { + prev->next = new_list; + return list; + } + else + { + return new_list; + } +} + +/* Compare function to sort strings alphabetically, + * for use with fluid_list_sort(). */ +int +fluid_list_str_compare_func(const void *a, const void *b) +{ + if(a && b) + { + return FLUID_STRCMP(a, b); + } + + if(!a && !b) + { + return 0; + } + + if(a) + { + return -1; + } + + return 1; +} + +int fluid_list_idx(fluid_list_t *list, void *data) +{ + int i = 0; + + while(list) + { + if (list->data == data) + { + return i; + } + list = list->next; + } + + return -1; +} diff --git a/libs/fluidsynth/src/utils/fluid_list.h b/libs/fluidsynth/src/utils/fluid_list.h new file mode 100644 index 00000000000..a290135cec0 --- /dev/null +++ b/libs/fluidsynth/src/utils/fluid_list.h @@ -0,0 +1,63 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _FLUID_LIST_H +#define _FLUID_LIST_H + +#include "fluidsynth_priv.h" + +/* + * + * Lists + * + * A sound font loader has to pack the data from the .SF2 file into + * list structures of this type. + * + */ + +typedef struct _fluid_list_t fluid_list_t; + +typedef int (*fluid_compare_func_t)(const void *a, const void *b); + +struct _fluid_list_t +{ + void *data; + fluid_list_t *next; +}; + +fluid_list_t *new_fluid_list(void); +void delete_fluid_list(fluid_list_t *list); +void delete1_fluid_list(fluid_list_t *list); +fluid_list_t *fluid_list_sort(fluid_list_t *list, fluid_compare_func_t compare_func); +fluid_list_t *fluid_list_append(fluid_list_t *list, void *data); +fluid_list_t *fluid_list_prepend(fluid_list_t *list, void *data); +fluid_list_t *fluid_list_remove(fluid_list_t *list, void *data); +fluid_list_t *fluid_list_remove_link(fluid_list_t *list, fluid_list_t *llink); +fluid_list_t *fluid_list_nth(fluid_list_t *list, int n); +fluid_list_t *fluid_list_last(fluid_list_t *list); +fluid_list_t *fluid_list_insert_at(fluid_list_t *list, int n, void *data); +int fluid_list_idx(fluid_list_t *list, void *data); +int fluid_list_size(fluid_list_t *list); + +#define fluid_list_next(slist) ((slist) ? (((fluid_list_t *)(slist))->next) : NULL) +#define fluid_list_get(slist) ((slist) ? ((slist)->data) : NULL) + +int fluid_list_str_compare_func(const void *a, const void *b); + +#endif /* _FLUID_LIST_H */ diff --git a/libs/fluidsynth/src/utils/fluid_ringbuffer.c b/libs/fluidsynth/src/utils/fluid_ringbuffer.c new file mode 100644 index 00000000000..e9fc4ddd358 --- /dev/null +++ b/libs/fluidsynth/src/utils/fluid_ringbuffer.c @@ -0,0 +1,90 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +/* + * Josh Green + * 2009-05-28 + */ + +#include "fluid_ringbuffer.h" +#include "fluid_sys.h" + + +/** + * Create a lock free queue with a fixed maximum count and size of elements. + * @param count Count of elements in queue (fixed max number of queued elements) + * @return New lock free queue or NULL if out of memory (error message logged) + * + * Lockless FIFO queues don't use any locking mechanisms and can therefore be + * advantageous in certain situations, such as passing data between a lower + * priority thread and a higher "real time" thread, without potential lock + * contention which could stall the high priority thread. Note that there may + * only be one producer thread and one consumer thread. + */ +fluid_ringbuffer_t * +new_fluid_ringbuffer(int count, size_t elementsize) +{ + fluid_ringbuffer_t *queue; + + fluid_return_val_if_fail(count > 0, NULL); + + queue = FLUID_NEW(fluid_ringbuffer_t); + + if(!queue) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + queue->array = FLUID_MALLOC(elementsize * count); + + if(!queue->array) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + delete_fluid_ringbuffer(queue); + return NULL; + } + + /* Clear array, in case dynamic pointer reclaiming is being done */ + FLUID_MEMSET(queue->array, 0, elementsize * count); + + queue->totalcount = count; + queue->elementsize = elementsize; + fluid_atomic_int_set(&queue->count, 0); + queue->in = 0; + queue->out = 0; + + return (queue); +} + +/** + * Free an event queue. + * @param queue Lockless queue instance + * + * Care must be taken when freeing a queue, to ensure that the consumer and + * producer threads will no longer access it. + */ +void +delete_fluid_ringbuffer(fluid_ringbuffer_t *queue) +{ + fluid_return_if_fail(queue != NULL); + FLUID_FREE(queue->array); + FLUID_FREE(queue); +} diff --git a/libs/fluidsynth/src/utils/fluid_ringbuffer.h b/libs/fluidsynth/src/utils/fluid_ringbuffer.h new file mode 100644 index 00000000000..6b0a2df37dc --- /dev/null +++ b/libs/fluidsynth/src/utils/fluid_ringbuffer.h @@ -0,0 +1,133 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#ifndef _FLUID_RINGBUFFER_H +#define _FLUID_RINGBUFFER_H + +#include "fluid_sys.h" + +/* + * Lockless event queue instance. + */ +struct _fluid_ringbuffer_t +{ + char *array; /**< Queue array of arbitrary size elements */ + int totalcount; /**< Total count of elements in array */ + fluid_atomic_int_t count; /**< Current count of elements */ + int in; /**< Index in queue to store next pushed element */ + int out; /**< Index in queue of next popped element */ + size_t elementsize; /**< Size of each element */ + void *userdata; +}; + +typedef struct _fluid_ringbuffer_t fluid_ringbuffer_t; + + +fluid_ringbuffer_t *new_fluid_ringbuffer(int count, size_t elementsize); +void delete_fluid_ringbuffer(fluid_ringbuffer_t *queue); + +/** + * Get pointer to next input array element in queue. + * @param queue Lockless queue instance + * @param offset Normally zero, or more if you need to push several items at once + * @return Pointer to array element in queue to store data to or NULL if queue is full + * + * This function along with fluid_ringbuffer_next_inptr() form a queue "push" + * operation and is split into 2 functions to avoid an element copy. Note that + * the returned array element pointer may contain the data of a previous element + * if the queue has wrapped around. This can be used to reclaim pointers to + * allocated memory, etc. + */ +static FLUID_INLINE void * +fluid_ringbuffer_get_inptr(fluid_ringbuffer_t *queue, int offset) +{ + return fluid_atomic_int_get(&queue->count) + offset >= queue->totalcount ? NULL + : queue->array + queue->elementsize * ((queue->in + offset) % queue->totalcount); +} + +/** + * Advance the input queue index to complete a "push" operation. + * @param queue Lockless queue instance + * @param count Normally one, or more if you need to push several items at once + * + * This function along with fluid_ringbuffer_get_inptr() form a queue "push" + * operation and is split into 2 functions to avoid element copy. + */ +static FLUID_INLINE void +fluid_ringbuffer_next_inptr(fluid_ringbuffer_t *queue, int count) +{ + fluid_atomic_int_add(&queue->count, count); + + queue->in += count; + + if(queue->in >= queue->totalcount) + { + queue->in -= queue->totalcount; + } +} + +/** + * Get amount of items currently in queue + * @param queue Lockless queue instance + * @return amount of items currently in queue + */ +static FLUID_INLINE int +fluid_ringbuffer_get_count(fluid_ringbuffer_t *queue) +{ + return fluid_atomic_int_get(&queue->count); +} + + +/** + * Get pointer to next output array element in queue. + * @param queue Lockless queue instance + * @return Pointer to array element data in the queue or NULL if empty, can only + * be used up until fluid_ringbuffer_next_outptr() is called. + * + * This function along with fluid_ringbuffer_next_outptr() form a queue "pop" + * operation and is split into 2 functions to avoid an element copy. + */ +static FLUID_INLINE void * +fluid_ringbuffer_get_outptr(fluid_ringbuffer_t *queue) +{ + return fluid_ringbuffer_get_count(queue) == 0 ? NULL + : queue->array + queue->elementsize * queue->out; +} + + +/** + * Advance the output queue index to complete a "pop" operation. + * @param queue Lockless queue instance + * + * This function along with fluid_ringbuffer_get_outptr() form a queue "pop" + * operation and is split into 2 functions to avoid an element copy. + */ +static FLUID_INLINE void +fluid_ringbuffer_next_outptr(fluid_ringbuffer_t *queue) +{ + fluid_atomic_int_add(&queue->count, -1); + + if(++queue->out == queue->totalcount) + { + queue->out = 0; + } +} + +#endif /* _FLUID_ringbuffer_H */ diff --git a/libs/fluidsynth/src/utils/fluid_settings.c b/libs/fluidsynth/src/utils/fluid_settings.c new file mode 100644 index 00000000000..c657a0a0665 --- /dev/null +++ b/libs/fluidsynth/src/utils/fluid_settings.c @@ -0,0 +1,2004 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include "fluid_sys.h" +#include "fluid_hash.h" +#include "fluid_synth.h" +#if 0 /* unused in Wine */ +#include "fluid_cmd.h" +#include "fluid_adriver.h" +#include "fluid_mdriver.h" +#endif /* unused in Wine */ +#include "fluid_settings.h" +#include "fluid_midi.h" + +/* maximum allowed components of a settings variable (separated by '.') */ +#define MAX_SETTINGS_TOKENS 8 /* currently only a max of 3 are used */ +#define MAX_SETTINGS_LABEL 256 /* max length of a settings variable label */ + +static void fluid_settings_init(fluid_settings_t *settings); +static void fluid_settings_key_destroy_func(void *value); +static void fluid_settings_value_destroy_func(void *value); +static int fluid_settings_tokenize(const char *s, char *buf, char **ptr); + +/* Common structure to all settings nodes */ +typedef struct +{ + char *value; + char *def; + int hints; + fluid_list_t *options; + fluid_str_update_t update; + void *data; +} fluid_str_setting_t; + +typedef struct +{ + double value; + double def; + double min; + double max; + int hints; + fluid_num_update_t update; + void *data; +} fluid_num_setting_t; + +typedef struct +{ + int value; + int def; + int min; + int max; + int hints; + fluid_int_update_t update; + void *data; +} fluid_int_setting_t; + +typedef struct +{ + fluid_hashtable_t *hashtable; +} fluid_set_setting_t; + +typedef struct +{ + int type; /**< fluid_types_enum */ + + union + { + fluid_str_setting_t str; + fluid_num_setting_t num; + fluid_int_setting_t i; + fluid_set_setting_t set; + }; +} fluid_setting_node_t; + +static fluid_setting_node_t * +new_fluid_str_setting(const char *value, const char *def, int hints) +{ + fluid_setting_node_t *node; + fluid_str_setting_t *str; + + node = FLUID_NEW(fluid_setting_node_t); + + if(!node) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + node->type = FLUID_STR_TYPE; + + str = &node->str; + str->value = value ? FLUID_STRDUP(value) : NULL; + str->def = def ? FLUID_STRDUP(def) : NULL; + str->hints = hints; + str->options = NULL; + str->update = NULL; + str->data = NULL; + return node; +} + +static void +delete_fluid_str_setting(fluid_setting_node_t *node) +{ + fluid_return_if_fail(node != NULL); + + FLUID_ASSERT(node->type == FLUID_STR_TYPE); + + FLUID_FREE(node->str.value); + FLUID_FREE(node->str.def); + + if(node->str.options) + { + fluid_list_t *list = node->str.options; + + while(list) + { + FLUID_FREE(list->data); + list = fluid_list_next(list); + } + + delete_fluid_list(node->str.options); + } + + FLUID_FREE(node); +} + + +static fluid_setting_node_t * +new_fluid_num_setting(double min, double max, double def, int hints) +{ + fluid_setting_node_t *node; + fluid_num_setting_t *num; + + node = FLUID_NEW(fluid_setting_node_t); + + if(!node) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + node->type = FLUID_NUM_TYPE; + + num = &node->num; + num->value = def; + num->def = def; + num->min = min; + num->max = max; + num->hints = hints; + num->update = NULL; + num->data = NULL; + + return node; +} + +static void +delete_fluid_num_setting(fluid_setting_node_t *node) +{ + fluid_return_if_fail(node != NULL); + + FLUID_ASSERT(node->type == FLUID_NUM_TYPE); + FLUID_FREE(node); +} + +static fluid_setting_node_t * +new_fluid_int_setting(int min, int max, int def, int hints) +{ + fluid_setting_node_t *node; + fluid_int_setting_t *i; + + node = FLUID_NEW(fluid_setting_node_t); + + if(!node) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + node->type = FLUID_INT_TYPE; + + i = &node->i; + i->value = def; + i->def = def; + i->min = min; + i->max = max; + i->hints = hints; + i->update = NULL; + i->data = NULL; + return node; +} + +static void +delete_fluid_int_setting(fluid_setting_node_t *node) +{ + fluid_return_if_fail(node != NULL); + + FLUID_ASSERT(node->type == FLUID_INT_TYPE); + FLUID_FREE(node); +} + +static fluid_setting_node_t * +new_fluid_set_setting(void) +{ + fluid_setting_node_t *node; + fluid_set_setting_t *set; + + node = FLUID_NEW(fluid_setting_node_t); + + if(!node) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + node->type = FLUID_SET_TYPE; + set = &node->set; + + set->hashtable = new_fluid_hashtable_full(fluid_str_hash, fluid_str_equal, + fluid_settings_key_destroy_func, + fluid_settings_value_destroy_func); + + if(!set->hashtable) + { + FLUID_FREE(node); + return NULL; + } + + return node; +} + +static void +delete_fluid_set_setting(fluid_setting_node_t *node) +{ + fluid_return_if_fail(node != NULL); + + FLUID_ASSERT(node->type == FLUID_SET_TYPE); + delete_fluid_hashtable(node->set.hashtable); + FLUID_FREE(node); +} + +/** + * Create a new settings object + * + * @return the pointer to the settings object + */ +fluid_settings_t * +new_fluid_settings(void) +{ + fluid_settings_t *settings; + + settings = new_fluid_hashtable_full(fluid_str_hash, fluid_str_equal, + fluid_settings_key_destroy_func, + fluid_settings_value_destroy_func); + + if(settings == NULL) + { + return NULL; + } + + fluid_rec_mutex_init(settings->mutex); + fluid_settings_init(settings); + return settings; +} + +/** + * Delete the provided settings object + * + * @param settings a settings object + */ +void +delete_fluid_settings(fluid_settings_t *settings) +{ + fluid_return_if_fail(settings != NULL); + + fluid_rec_mutex_destroy(settings->mutex); + delete_fluid_hashtable(settings); +} + +/* Settings hash key destroy function */ +static void +fluid_settings_key_destroy_func(void *value) +{ + FLUID_FREE(value); /* Free the string key value */ +} + +/* Settings hash value destroy function */ +static void +fluid_settings_value_destroy_func(void *value) +{ + fluid_setting_node_t *node = value; + + switch(node->type) + { + case FLUID_NUM_TYPE: + delete_fluid_num_setting(node); + break; + + case FLUID_INT_TYPE: + delete_fluid_int_setting(node); + break; + + case FLUID_STR_TYPE: + delete_fluid_str_setting(node); + break; + + case FLUID_SET_TYPE: + delete_fluid_set_setting(node); + break; + } +} + +void +fluid_settings_init(fluid_settings_t *settings) +{ + fluid_return_if_fail(settings != NULL); + + fluid_synth_settings(settings); +#if 0 /* unused in Wine */ + fluid_shell_settings(settings); + fluid_player_settings(settings); + fluid_file_renderer_settings(settings); + fluid_audio_driver_settings(settings); + fluid_midi_driver_settings(settings); +#endif /* unused in Wine */ +} + +static int +fluid_settings_tokenize(const char *s, char *buf, char **ptr) +{ + char *tokstr, *tok; + int n = 0; + + if(FLUID_STRLEN(s) > MAX_SETTINGS_LABEL) + { + FLUID_LOG(FLUID_ERR, "Setting variable name exceeded max length of %d chars", + MAX_SETTINGS_LABEL); + return 0; + } + + FLUID_STRCPY(buf, s); /* copy string to buffer, since it gets modified */ + tokstr = buf; + + while((tok = fluid_strtok(&tokstr, "."))) + { + if(n >= MAX_SETTINGS_TOKENS) + { + FLUID_LOG(FLUID_ERR, "Setting variable name exceeded max token count of %d", + MAX_SETTINGS_TOKENS); + return 0; + } + else + { + ptr[n++] = tok; + } + } + + return n; +} + +/** + * Get a setting name, value and type + * + * @param settings a settings object + * @param name Settings name + * @param value Location to store setting node if found + * @return #FLUID_OK if the node exists, #FLUID_FAILED otherwise + */ +static int +fluid_settings_get(fluid_settings_t *settings, const char *name, + fluid_setting_node_t **value) +{ + fluid_hashtable_t *table = settings; + fluid_setting_node_t *node = NULL; + char *tokens[MAX_SETTINGS_TOKENS]; + char buf[MAX_SETTINGS_LABEL + 1]; + int ntokens; + int n; + + ntokens = fluid_settings_tokenize(name, buf, tokens); + + if(table == NULL || ntokens <= 0) + { + return FLUID_FAILED; + } + + for(n = 0; n < ntokens; n++) + { + + node = fluid_hashtable_lookup(table, tokens[n]); + + if(!node) + { + return FLUID_FAILED; + } + + table = (node->type == FLUID_SET_TYPE) ? node->set.hashtable : NULL; + } + + if(value) + { + *value = node; + } + + return FLUID_OK; +} + +/** + * Set a setting name, value and type, replacing it if already exists + * + * @param settings a settings object + * @param name Settings name + * @param value Node instance to assign (used directly) + * @return #FLUID_OK if the value has been set, #FLUID_FAILED otherwise + */ +static int +fluid_settings_set(fluid_settings_t *settings, const char *name, fluid_setting_node_t *value) +{ + fluid_hashtable_t *table = settings; + fluid_setting_node_t *node; + char *tokens[MAX_SETTINGS_TOKENS]; + char buf[MAX_SETTINGS_LABEL + 1]; + int n, num; + char *dupname; + + num = fluid_settings_tokenize(name, buf, tokens); + + if(num == 0) + { + return FLUID_FAILED; + } + + num--; + + for(n = 0; n < num; n++) + { + + node = fluid_hashtable_lookup(table, tokens[n]); + + if(node) + { + + if(node->type == FLUID_SET_TYPE) + { + table = node->set.hashtable; + } + else + { + /* path ends prematurely */ + FLUID_LOG(FLUID_ERR, "'%s' is not a node. Name of the setting was '%s'", tokens[n], name); + return FLUID_FAILED; + } + + } + else + { + /* create a new node */ + fluid_setting_node_t *setnode; + + dupname = FLUID_STRDUP(tokens[n]); + setnode = new_fluid_set_setting(); + + if(!dupname || !setnode) + { + if(dupname) + { + FLUID_FREE(dupname); + } + else + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + } + + if(setnode) + { + delete_fluid_set_setting(setnode); + } + + return FLUID_FAILED; + } + + fluid_hashtable_insert(table, dupname, setnode); + table = setnode->set.hashtable; + } + } + + dupname = FLUID_STRDUP(tokens[num]); + + if(!dupname) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return FLUID_FAILED; + } + + fluid_hashtable_insert(table, dupname, value); + + return FLUID_OK; +} + +/** + * Registers a new string value for the specified setting. + * + * @param settings a settings object + * @param name the setting's name + * @param def the default value for the setting + * @param hints the hints for the setting + * @return #FLUID_OK if the value has been register correctly, #FLUID_FAILED otherwise + */ +int +fluid_settings_register_str(fluid_settings_t *settings, const char *name, const char *def, int hints) +{ + fluid_setting_node_t *node; + int retval = FLUID_FAILED; + + fluid_return_val_if_fail(settings != NULL, retval); + fluid_return_val_if_fail(name != NULL, retval); + fluid_return_val_if_fail(name[0] != '\0', retval); + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) != FLUID_OK) + { + node = new_fluid_str_setting(def, def, hints); + retval = fluid_settings_set(settings, name, node); + + if(retval != FLUID_OK) + { + delete_fluid_str_setting(node); + } + } + else + { + /* if variable already exists, don't change its value. */ + if(node->type == FLUID_STR_TYPE) + { + fluid_str_setting_t *setting = &node->str; + FLUID_FREE(setting->def); + setting->def = def ? FLUID_STRDUP(def) : NULL; + setting->hints = hints; + retval = FLUID_OK; + } + else + { + FLUID_LOG(FLUID_ERR, "Failed to register string setting '%s' as it already exists with a different type", name); + } + } + + fluid_rec_mutex_unlock(settings->mutex); + + return retval; +} + +/** + * Registers a new float value for the specified setting. + * + * @param settings a settings object + * @param name the setting's name + * @param def the default value for the setting + * @param min the smallest allowed value for the setting + * @param max the largest allowed value for the setting + * @param hints the hints for the setting + * @return #FLUID_OK if the value has been register correctly, #FLUID_FAILED otherwise + */ +int +fluid_settings_register_num(fluid_settings_t *settings, const char *name, double def, + double min, double max, int hints) +{ + fluid_setting_node_t *node; + int retval = FLUID_FAILED; + + fluid_return_val_if_fail(settings != NULL, retval); + fluid_return_val_if_fail(name != NULL, retval); + fluid_return_val_if_fail(name[0] != '\0', retval); + + /* For now, all floating point settings are bounded below and above */ + hints |= FLUID_HINT_BOUNDED_BELOW | FLUID_HINT_BOUNDED_ABOVE; + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) != FLUID_OK) + { + /* insert a new setting */ + node = new_fluid_num_setting(min, max, def, hints); + retval = fluid_settings_set(settings, name, node); + + if(retval != FLUID_OK) + { + delete_fluid_num_setting(node); + } + } + else + { + if(node->type == FLUID_NUM_TYPE) + { + /* update the existing setting but don't change its value */ + fluid_num_setting_t *setting = &node->num; + setting->min = min; + setting->max = max; + setting->def = def; + setting->hints = hints; + retval = FLUID_OK; + } + else + { + /* type mismatch */ + FLUID_LOG(FLUID_ERR, "Failed to register numeric setting '%s' as it already exists with a different type", name); + } + } + + fluid_rec_mutex_unlock(settings->mutex); + + return retval; +} + +/** + * Registers a new integer value for the specified setting. + * + * @param settings a settings object + * @param name the setting's name + * @param def the default value for the setting + * @param min the smallest allowed value for the setting + * @param max the largest allowed value for the setting + * @param hints the hints for the setting + * @return #FLUID_OK if the value has been register correctly, #FLUID_FAILED otherwise + */ +int +fluid_settings_register_int(fluid_settings_t *settings, const char *name, int def, + int min, int max, int hints) +{ + fluid_setting_node_t *node; + int retval = FLUID_FAILED; + + fluid_return_val_if_fail(settings != NULL, retval); + fluid_return_val_if_fail(name != NULL, retval); + fluid_return_val_if_fail(name[0] != '\0', retval); + + /* For now, all integer settings are bounded below and above */ + hints |= FLUID_HINT_BOUNDED_BELOW | FLUID_HINT_BOUNDED_ABOVE; + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) != FLUID_OK) + { + /* insert a new setting */ + node = new_fluid_int_setting(min, max, def, hints); + retval = fluid_settings_set(settings, name, node); + + if(retval != FLUID_OK) + { + delete_fluid_int_setting(node); + } + } + else + { + if(node->type == FLUID_INT_TYPE) + { + /* update the existing setting but don't change its value */ + fluid_int_setting_t *setting = &node->i; + setting->min = min; + setting->max = max; + setting->def = def; + setting->hints = hints; + retval = FLUID_OK; + } + else + { + /* type mismatch */ + FLUID_LOG(FLUID_ERR, "Failed to register int setting '%s' as it already exists with a different type", name); + } + } + + fluid_rec_mutex_unlock(settings->mutex); + + return retval; +} + +/** + * Registers a callback for the specified string setting. + * + * @param settings a settings object + * @param name the setting's name + * @param callback an update function for the setting + * @param data user supplied data passed to the update function + * @return #FLUID_OK if the callback has been set, #FLUID_FAILED otherwise + */ +int fluid_settings_callback_str(fluid_settings_t *settings, const char *name, + fluid_str_update_t callback, void *data) +{ + fluid_setting_node_t *node; + fluid_str_setting_t *setting; + + fluid_return_val_if_fail(settings != NULL, FLUID_FAILED); + fluid_return_val_if_fail(name != NULL, FLUID_FAILED); + fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED); + + fluid_rec_mutex_lock(settings->mutex); + + if((fluid_settings_get(settings, name, &node) != FLUID_OK) + || node->type != FLUID_STR_TYPE) + { + fluid_rec_mutex_unlock(settings->mutex); + return FLUID_FAILED; + } + + setting = &node->str; + setting->update = callback; + setting->data = data; + + fluid_rec_mutex_unlock(settings->mutex); + return FLUID_OK; +} + +/** + * Registers a callback for the specified numeric setting. + * + * @param settings a settings object + * @param name the setting's name + * @param callback an update function for the setting + * @param data user supplied data passed to the update function + * @return #FLUID_OK if the callback has been set, #FLUID_FAILED otherwise + */ +int fluid_settings_callback_num(fluid_settings_t *settings, const char *name, + fluid_num_update_t callback, void *data) +{ + fluid_setting_node_t *node; + fluid_num_setting_t *setting; + + fluid_return_val_if_fail(settings != NULL, FLUID_FAILED); + fluid_return_val_if_fail(name != NULL, FLUID_FAILED); + fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED); + + fluid_rec_mutex_lock(settings->mutex); + + if((fluid_settings_get(settings, name, &node) != FLUID_OK) + || node->type != FLUID_NUM_TYPE) + { + fluid_rec_mutex_unlock(settings->mutex); + return FLUID_FAILED; + } + + setting = &node->num; + setting->update = callback; + setting->data = data; + + fluid_rec_mutex_unlock(settings->mutex); + return FLUID_OK; +} + +/** + * Registers a callback for the specified int setting. + * + * @param settings a settings object + * @param name the setting's name + * @param callback an update function for the setting + * @param data user supplied data passed to the update function + * @return #FLUID_OK if the callback has been set, #FLUID_FAILED otherwise + */ +int fluid_settings_callback_int(fluid_settings_t *settings, const char *name, + fluid_int_update_t callback, void *data) +{ + fluid_setting_node_t *node; + fluid_int_setting_t *setting; + + fluid_return_val_if_fail(settings != NULL, FLUID_FAILED); + fluid_return_val_if_fail(name != NULL, FLUID_FAILED); + fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED); + + fluid_rec_mutex_lock(settings->mutex); + + if((fluid_settings_get(settings, name, &node) != FLUID_OK) + || node->type != FLUID_INT_TYPE) + { + fluid_rec_mutex_unlock(settings->mutex); + return FLUID_FAILED; + } + + setting = &node->i; + setting->update = callback; + setting->data = data; + + fluid_rec_mutex_unlock(settings->mutex); + return FLUID_OK; +} + +void* fluid_settings_get_user_data(fluid_settings_t * settings, const char *name) +{ + fluid_setting_node_t *node; + void* retval = NULL; + + fluid_return_val_if_fail(settings != NULL, NULL); + fluid_return_val_if_fail(name != NULL, NULL); + fluid_return_val_if_fail(name[0] != '\0', NULL); + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) == FLUID_OK) + { + if(node->type == FLUID_NUM_TYPE) + { + fluid_num_setting_t *setting = &node->num; + retval = setting->data; + } + else if(node->type == FLUID_STR_TYPE) + { + fluid_str_setting_t *setting = &node->str; + retval = setting->data; + } + else if(node->type == FLUID_INT_TYPE) + { + fluid_int_setting_t *setting = &node->i; + retval = setting->data; + } + } + + fluid_rec_mutex_unlock(settings->mutex); + return retval; +} + +/** + * Get the type of the setting with the given name + * + * @param settings a settings object + * @param name a setting's name + * @return the type for the named setting (see #fluid_types_enum), or #FLUID_NO_TYPE when it does not exist + */ +int +fluid_settings_get_type(fluid_settings_t *settings, const char *name) +{ + fluid_setting_node_t *node; + int type = FLUID_NO_TYPE; + + fluid_return_val_if_fail(settings != NULL, type); + fluid_return_val_if_fail(name != NULL, type); + fluid_return_val_if_fail(name[0] != '\0', type); + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) == FLUID_OK) + { + type = node->type; + } + + fluid_rec_mutex_unlock(settings->mutex); + + return type; +} + +/** + * Get the hints for the named setting as an integer bitmap + * + * @param settings a settings object + * @param name a setting's name + * @param hints set to the hints associated to the setting if it exists + * @return #FLUID_OK if hints associated to the named setting exist, #FLUID_FAILED otherwise + */ +int +fluid_settings_get_hints(fluid_settings_t *settings, const char *name, int *hints) +{ + fluid_setting_node_t *node; + int retval = FLUID_FAILED; + + fluid_return_val_if_fail(settings != NULL, retval); + fluid_return_val_if_fail(name != NULL, retval); + fluid_return_val_if_fail(name[0] != '\0', retval); + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) == FLUID_OK) + { + if(node->type == FLUID_NUM_TYPE) + { + fluid_num_setting_t *setting = &node->num; + *hints = setting->hints; + retval = FLUID_OK; + } + else if(node->type == FLUID_STR_TYPE) + { + fluid_str_setting_t *setting = &node->str; + *hints = setting->hints; + retval = FLUID_OK; + } + else if(node->type == FLUID_INT_TYPE) + { + fluid_int_setting_t *setting = &node->i; + *hints = setting->hints; + retval = FLUID_OK; + } + } + + fluid_rec_mutex_unlock(settings->mutex); + + return retval; +} + +/** + * Ask whether the setting is changeable in real-time. + * + * @param settings a settings object + * @param name a setting's name + * @return TRUE if the setting is changeable in real-time, FALSE otherwise + * + * @note Before using this function, make sure the @p settings object has already been used to create + * a synthesizer, a MIDI driver, an audio driver, a MIDI player, or a command handler (depending on + * which settings you want to query). + */ +int +fluid_settings_is_realtime(fluid_settings_t *settings, const char *name) +{ + fluid_setting_node_t *node; + int isrealtime = FALSE; + + fluid_return_val_if_fail(settings != NULL, 0); + fluid_return_val_if_fail(name != NULL, 0); + fluid_return_val_if_fail(name[0] != '\0', 0); + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) == FLUID_OK) + { + if(node->type == FLUID_NUM_TYPE) + { + fluid_num_setting_t *setting = &node->num; + isrealtime = setting->update != NULL; + } + else if(node->type == FLUID_STR_TYPE) + { + fluid_str_setting_t *setting = &node->str; + isrealtime = setting->update != NULL; + } + else if(node->type == FLUID_INT_TYPE) + { + fluid_int_setting_t *setting = &node->i; + isrealtime = setting->update != NULL; + } + } + + fluid_rec_mutex_unlock(settings->mutex); + + return isrealtime; +} + +/** + * Set a string value for a named setting + * + * @param settings a settings object + * @param name a setting's name + * @param str new string value + * @return #FLUID_OK if the value has been set, #FLUID_FAILED otherwise + */ +int +fluid_settings_setstr(fluid_settings_t *settings, const char *name, const char *str) +{ + fluid_setting_node_t *node; + fluid_str_setting_t *setting; + char *new_value = NULL; + fluid_str_update_t callback = NULL; + void *data = NULL; + + fluid_return_val_if_fail(settings != NULL, FLUID_FAILED); + fluid_return_val_if_fail(name != NULL, FLUID_FAILED); + fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED); + + fluid_rec_mutex_lock(settings->mutex); + + if((fluid_settings_get(settings, name, &node) != FLUID_OK) + || (node->type != FLUID_STR_TYPE)) + { + FLUID_LOG(FLUID_ERR, "Unknown string setting '%s'", name); + goto error_recovery; + } + + setting = &node->str; + + if(setting->value) + { + FLUID_FREE(setting->value); + } + + if(str) + { + new_value = FLUID_STRDUP(str); + + if(new_value == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + goto error_recovery; + } + } + + setting->value = new_value; + + callback = setting->update; + data = setting->data; + + /* Release the mutex before calling the update callback, to avoid + * possible deadlocks with FluidSynths API lock */ + fluid_rec_mutex_unlock(settings->mutex); + + if(callback) + { + (*callback)(data, name, new_value); + } + + return FLUID_OK; + +error_recovery: + fluid_rec_mutex_unlock(settings->mutex); + return FLUID_FAILED; +} + +/** + * Copy the value of a string setting into the provided buffer (thread safe) + * + * @param settings a settings object + * @param name a setting's name + * @param str Caller supplied buffer to copy string value to + * @param len Size of 'str' buffer (no more than len bytes will be written, which + * will always include a zero terminator) + * @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise + * + * @note A size of 256 should be more than sufficient for the string buffer. + * + * @since 1.1.0 + */ +int +fluid_settings_copystr(fluid_settings_t *settings, const char *name, + char *str, int len) +{ + fluid_setting_node_t *node; + int retval = FLUID_FAILED; + + fluid_return_val_if_fail(settings != NULL, retval); + fluid_return_val_if_fail(name != NULL, retval); + fluid_return_val_if_fail(name[0] != '\0', retval); + fluid_return_val_if_fail(str != NULL, retval); + fluid_return_val_if_fail(len > 0, retval); + + str[0] = 0; + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) == FLUID_OK) + { + if(node->type == FLUID_STR_TYPE) + { + fluid_str_setting_t *setting = &node->str; + + if(setting->value) + { + FLUID_STRNCPY(str, setting->value, len); + } + + retval = FLUID_OK; + } + else if(node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */ + { + fluid_int_setting_t *setting = &node->i; + + if(setting->hints & FLUID_HINT_TOGGLED) + { + FLUID_STRNCPY(str, setting->value ? "yes" : "no", len); + + retval = FLUID_OK; + } + } + } + + fluid_rec_mutex_unlock(settings->mutex); + + return retval; +} + +/** + * Duplicate the value of a string setting + * + * @param settings a settings object + * @param name a setting's name + * @param str Location to store pointer to allocated duplicate string + * @return #FLUID_OK if the value exists and was successfully duplicated, #FLUID_FAILED otherwise + * + * Like fluid_settings_copystr() but allocates a new copy of the string. Caller + * owns the string and should free it with fluid_free() when done using it. + * + * @since 1.1.0 + */ +int +fluid_settings_dupstr(fluid_settings_t *settings, const char *name, char **str) +{ + fluid_setting_node_t *node; + int retval = FLUID_FAILED; + + fluid_return_val_if_fail(settings != NULL, retval); + fluid_return_val_if_fail(name != NULL, retval); + fluid_return_val_if_fail(name[0] != '\0', retval); + fluid_return_val_if_fail(str != NULL, retval); + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) == FLUID_OK) + { + if(node->type == FLUID_STR_TYPE) + { + fluid_str_setting_t *setting = &node->str; + + if(setting->value) + { + *str = FLUID_STRDUP(setting->value); + + if(!*str) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + } + } + + if(!setting->value || *str) + { + retval = FLUID_OK; /* Don't set to FLUID_OK if out of memory */ + } + } + else if(node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */ + { + fluid_int_setting_t *setting = &node->i; + + if(setting->hints & FLUID_HINT_TOGGLED) + { + *str = FLUID_STRDUP(setting->value ? "yes" : "no"); + + if(!*str) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + } + + if(!setting->value || *str) + { + retval = FLUID_OK; /* Don't set to FLUID_OK if out of memory */ + } + } + } + } + + fluid_rec_mutex_unlock(settings->mutex); + + return retval; +} + + +/** + * Test a string setting for some value. + * + * @param settings a settings object + * @param name a setting's name + * @param s a string to be tested + * @return TRUE if the value exists and is equal to \c s, FALSE otherwise + */ +int +fluid_settings_str_equal(fluid_settings_t *settings, const char *name, const char *s) +{ + fluid_setting_node_t *node; + int retval = FALSE; + + fluid_return_val_if_fail(settings != NULL, retval); + fluid_return_val_if_fail(name != NULL, retval); + fluid_return_val_if_fail(name[0] != '\0', retval); + fluid_return_val_if_fail(s != NULL, retval); + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) == FLUID_OK) + { + if(node->type == FLUID_STR_TYPE) + { + fluid_str_setting_t *setting = &node->str; + + if(setting->value) + { + retval = FLUID_STRCMP(setting->value, s) == 0; + } + } + else if(node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */ + { + fluid_int_setting_t *setting = &node->i; + + if(setting->hints & FLUID_HINT_TOGGLED) + { + retval = FLUID_STRCMP(setting->value ? "yes" : "no", s) == 0; + } + } + } + + fluid_rec_mutex_unlock(settings->mutex); + + return retval; +} + +/** + * Get the default value of a string setting. + * + * @param settings a settings object + * @param name a setting's name + * @param def the default string value of the setting if it exists + * @return FLUID_OK if a default value exists, FLUID_FAILED otherwise + * + * @note The returned string is not owned by the caller and should not be modified or freed. + */ +int +fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char **def) +{ + fluid_setting_node_t *node; + char *retval = NULL; + + fluid_return_val_if_fail(settings != NULL, FLUID_FAILED); + fluid_return_val_if_fail(name != NULL, FLUID_FAILED); + fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED); + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) == FLUID_OK) + { + if(node->type == FLUID_STR_TYPE) + { + fluid_str_setting_t *setting = &node->str; + retval = setting->def; + } + else if(node->type == FLUID_INT_TYPE) /* Handle boolean integers for backwards compatibility */ + { + fluid_int_setting_t *setting = &node->i; + + if(setting->hints & FLUID_HINT_TOGGLED) + { + retval = setting->def ? "yes" : "no"; + } + } + } + + *def = retval; + fluid_rec_mutex_unlock(settings->mutex); + + return retval != NULL ? FLUID_OK : FLUID_FAILED; +} + +/** + * Add an option to a string setting (like an enumeration value). + * + * @param settings a settings object + * @param name a setting's name + * @param s option string to add + * @return #FLUID_OK if the setting exists and option was added, #FLUID_FAILED otherwise + * + * Causes the setting's #FLUID_HINT_OPTIONLIST hint to be set. + */ +int +fluid_settings_add_option(fluid_settings_t *settings, const char *name, const char *s) +{ + fluid_setting_node_t *node; + int retval = FLUID_FAILED; + + fluid_return_val_if_fail(settings != NULL, retval); + fluid_return_val_if_fail(name != NULL, retval); + fluid_return_val_if_fail(name[0] != '\0', retval); + fluid_return_val_if_fail(s != NULL, retval); + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) == FLUID_OK + && (node->type == FLUID_STR_TYPE)) + { + fluid_str_setting_t *setting = &node->str; + char *copy = FLUID_STRDUP(s); + setting->options = fluid_list_append(setting->options, copy); + setting->hints |= FLUID_HINT_OPTIONLIST; + retval = FLUID_OK; + } + + fluid_rec_mutex_unlock(settings->mutex); + + return retval; +} + +/** + * Remove an option previously assigned by fluid_settings_add_option(). + * + * @param settings a settings object + * @param name a setting's name + * @param s option string to remove + * @return #FLUID_OK if the setting exists and option was removed, #FLUID_FAILED otherwise + */ +int +fluid_settings_remove_option(fluid_settings_t *settings, const char *name, const char *s) +{ + fluid_setting_node_t *node; + int retval = FLUID_FAILED; + + fluid_return_val_if_fail(settings != NULL, retval); + fluid_return_val_if_fail(name != NULL, retval); + fluid_return_val_if_fail(name[0] != '\0', retval); + fluid_return_val_if_fail(s != NULL, retval); + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) == FLUID_OK + && (node->type == FLUID_STR_TYPE)) + { + + fluid_str_setting_t *setting = &node->str; + fluid_list_t *list = setting->options; + + while(list) + { + char *option = (char *) fluid_list_get(list); + + if(FLUID_STRCMP(s, option) == 0) + { + FLUID_FREE(option); + setting->options = fluid_list_remove_link(setting->options, list); + retval = FLUID_OK; + break; + } + + list = fluid_list_next(list); + } + } + + fluid_rec_mutex_unlock(settings->mutex); + + return retval; +} + +/** + * Set a numeric value for a named setting. + * + * @param settings a settings object + * @param name a setting's name + * @param val new setting's value + * @return #FLUID_OK if the value has been set, #FLUID_FAILED otherwise + */ +int +fluid_settings_setnum(fluid_settings_t *settings, const char *name, double val) +{ + fluid_setting_node_t *node; + fluid_num_setting_t *setting; + fluid_num_update_t callback = NULL; + void *data = NULL; + + fluid_return_val_if_fail(settings != NULL, FLUID_FAILED); + fluid_return_val_if_fail(name != NULL, FLUID_FAILED); + fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED); + + fluid_rec_mutex_lock(settings->mutex); + + if((fluid_settings_get(settings, name, &node) != FLUID_OK) + || (node->type != FLUID_NUM_TYPE)) + { + FLUID_LOG(FLUID_ERR, "Unknown numeric setting '%s'", name); + goto error_recovery; + } + + setting = &node->num; + + if(val < setting->min || val > setting->max) + { + FLUID_LOG(FLUID_ERR, "requested set value for '%s' out of range", name); + goto error_recovery; + } + + setting->value = val; + + callback = setting->update; + data = setting->data; + + /* Release the mutex before calling the update callback, to avoid + * possible deadlocks with FluidSynths API lock */ + fluid_rec_mutex_unlock(settings->mutex); + + if(callback) + { + (*callback)(data, name, val); + } + + return FLUID_OK; + +error_recovery: + fluid_rec_mutex_unlock(settings->mutex); + return FLUID_FAILED; +} + +/** + * Get the numeric value of a named setting + * + * @param settings a settings object + * @param name a setting's name + * @param val variable pointer to receive the setting's numeric value + * @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise + */ +int +fluid_settings_getnum(fluid_settings_t *settings, const char *name, double *val) +{ + fluid_setting_node_t *node; + int retval = FLUID_FAILED; + + fluid_return_val_if_fail(settings != NULL, retval); + fluid_return_val_if_fail(name != NULL, retval); + fluid_return_val_if_fail(name[0] != '\0', retval); + fluid_return_val_if_fail(val != NULL, retval); + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) == FLUID_OK + && (node->type == FLUID_NUM_TYPE)) + { + fluid_num_setting_t *setting = &node->num; + *val = setting->value; + retval = FLUID_OK; + } + + fluid_rec_mutex_unlock(settings->mutex); + + return retval; +} + +/** + * float-typed wrapper for fluid_settings_getnum + * + * @param settings a settings object + * @param name a setting's name + * @param val variable pointer to receive the setting's float value + * @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise + */ +int fluid_settings_getnum_float(fluid_settings_t *settings, const char *name, float *val) +{ + double tmp; + + if(fluid_settings_getnum(settings, name, &tmp) == FLUID_OK) + { + *val = tmp; + return FLUID_OK; + } + + return FLUID_FAILED; +} + +/** + * Get the range of values of a numeric setting + * + * @param settings a settings object + * @param name a setting's name + * @param min setting's range lower limit + * @param max setting's range upper limit + * @return #FLUID_OK if the setting's range exists, #FLUID_FAILED otherwise + */ +int +fluid_settings_getnum_range(fluid_settings_t *settings, const char *name, + double *min, double *max) +{ + fluid_setting_node_t *node; + int retval = FLUID_FAILED; + + fluid_return_val_if_fail(settings != NULL, retval); + fluid_return_val_if_fail(name != NULL, retval); + fluid_return_val_if_fail(name[0] != '\0', retval); + fluid_return_val_if_fail(min != NULL, retval); + fluid_return_val_if_fail(max != NULL, retval); + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) == FLUID_OK + && (node->type == FLUID_NUM_TYPE)) + { + fluid_num_setting_t *setting = &node->num; + *min = setting->min; + *max = setting->max; + retval = FLUID_OK; + } + + fluid_rec_mutex_unlock(settings->mutex); + + return retval; +} + +/** + * Get the default value of a named numeric (double) setting + * + * @param settings a settings object + * @param name a setting's name + * @param val set to the default value if the named setting exists + * @return #FLUID_OK if the default value of the named setting exists, #FLUID_FAILED otherwise + */ +int +fluid_settings_getnum_default(fluid_settings_t *settings, const char *name, double *val) +{ + fluid_setting_node_t *node; + int retval = FLUID_FAILED; + + fluid_return_val_if_fail(settings != NULL, retval); + fluid_return_val_if_fail(name != NULL, retval); + fluid_return_val_if_fail(name[0] != '\0', retval); + fluid_return_val_if_fail(val != NULL, retval); + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) == FLUID_OK + && (node->type == FLUID_NUM_TYPE)) + { + fluid_num_setting_t *setting = &node->num; + *val = setting->def; + retval = FLUID_OK; + } + + fluid_rec_mutex_unlock(settings->mutex); + + return retval; +} + +/** + * Set an integer value for a setting + * + * @param settings a settings object + * @param name a setting's name + * @param val new setting's integer value + * @return #FLUID_OK if the value has been set, #FLUID_FAILED otherwise + */ +int +fluid_settings_setint(fluid_settings_t *settings, const char *name, int val) +{ + fluid_setting_node_t *node; + fluid_int_setting_t *setting; + fluid_int_update_t callback = NULL; + void *data = NULL; + + fluid_return_val_if_fail(settings != NULL, FLUID_FAILED); + fluid_return_val_if_fail(name != NULL, FLUID_FAILED); + fluid_return_val_if_fail(name[0] != '\0', FLUID_FAILED); + + fluid_rec_mutex_lock(settings->mutex); + + if((fluid_settings_get(settings, name, &node) != FLUID_OK) + || (node->type != FLUID_INT_TYPE)) + { + FLUID_LOG(FLUID_ERR, "Unknown integer parameter '%s'", name); + goto error_recovery; + } + + setting = &node->i; + + if(val < setting->min || val > setting->max) + { + FLUID_LOG(FLUID_ERR, "requested set value for setting '%s' out of range", name); + goto error_recovery; + } + + setting->value = val; + + callback = setting->update; + data = setting->data; + + /* Release the mutex before calling the update callback, to avoid + * possible deadlocks with FluidSynths API lock */ + fluid_rec_mutex_unlock(settings->mutex); + + if(callback) + { + (*callback)(data, name, val); + } + + return FLUID_OK; + +error_recovery: + fluid_rec_mutex_unlock(settings->mutex); + return FLUID_FAILED; +} + +/** + * Get an integer value setting. + * + * @param settings a settings object + * @param name a setting's name + * @param val pointer to a variable to receive the setting's integer value + * @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise + */ +int +fluid_settings_getint(fluid_settings_t *settings, const char *name, int *val) +{ + fluid_setting_node_t *node; + int retval = FLUID_FAILED; + + fluid_return_val_if_fail(settings != NULL, retval); + fluid_return_val_if_fail(name != NULL, retval); + fluid_return_val_if_fail(name[0] != '\0', retval); + fluid_return_val_if_fail(val != NULL, retval); + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) == FLUID_OK + && (node->type == FLUID_INT_TYPE)) + { + fluid_int_setting_t *setting = &node->i; + *val = setting->value; + retval = FLUID_OK; + } + + fluid_rec_mutex_unlock(settings->mutex); + + return retval; +} + +/** + * Get the range of values of an integer setting + * + * @param settings a settings object + * @param name a setting's name + * @param min setting's range lower limit + * @param max setting's range upper limit + * @return #FLUID_OK if the setting's range exists, #FLUID_FAILED otherwise + */ +int +fluid_settings_getint_range(fluid_settings_t *settings, const char *name, + int *min, int *max) +{ + fluid_setting_node_t *node; + int retval = FLUID_FAILED; + + fluid_return_val_if_fail(settings != NULL, retval); + fluid_return_val_if_fail(name != NULL, retval); + fluid_return_val_if_fail(name[0] != '\0', retval); + fluid_return_val_if_fail(min != NULL, retval); + fluid_return_val_if_fail(max != NULL, retval); + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) == FLUID_OK + && (node->type == FLUID_INT_TYPE)) + { + fluid_int_setting_t *setting = &node->i; + *min = setting->min; + *max = setting->max; + retval = FLUID_OK; + } + + fluid_rec_mutex_unlock(settings->mutex); + + return retval; +} + +/** + * Get the default value of an integer setting. + * + * @param settings a settings object + * @param name a setting's name + * @param val set to the setting's default integer value if it exists + * @return #FLUID_OK if the setting's default integer value exists, #FLUID_FAILED otherwise + */ +int fluid_settings_getint_default(fluid_settings_t *settings, const char *name, int *val) +{ + fluid_setting_node_t *node; + int retval = FLUID_FAILED; + + fluid_return_val_if_fail(settings != NULL, retval); + fluid_return_val_if_fail(name != NULL, retval); + fluid_return_val_if_fail(name[0] != '\0', retval); + fluid_return_val_if_fail(val != NULL, retval); + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) == FLUID_OK + && (node->type == FLUID_INT_TYPE)) + { + fluid_int_setting_t *setting = &node->i; + *val = setting->def; + retval = FLUID_OK; + } + + fluid_rec_mutex_unlock(settings->mutex); + + return retval; +} + +/** + * Iterate the available options for a named string setting, calling the provided + * callback function for each existing option. + * + * @param settings a settings object + * @param name a setting's name + * @param data any user provided pointer + * @param func callback function to be called on each iteration + * + * @note Starting with FluidSynth 1.1.0 the \p func callback is called for each + * option in alphabetical order. Sort order was undefined in previous versions. + */ +void +fluid_settings_foreach_option(fluid_settings_t *settings, const char *name, + void *data, fluid_settings_foreach_option_t func) +{ + fluid_setting_node_t *node; + fluid_str_setting_t *setting; + fluid_list_t *p, *newlist = NULL; + + fluid_return_if_fail(settings != NULL); + fluid_return_if_fail(name != NULL); + fluid_return_if_fail(name[0] != '\0'); + fluid_return_if_fail(func != NULL); + + fluid_rec_mutex_lock(settings->mutex); /* ++ lock */ + + if(fluid_settings_get(settings, name, &node) != FLUID_OK + || node->type != FLUID_STR_TYPE) + { + fluid_rec_mutex_unlock(settings->mutex); /* -- unlock */ + return; + } + + setting = &node->str; + + /* Duplicate option list */ + for(p = setting->options; p; p = p->next) + { + newlist = fluid_list_append(newlist, fluid_list_get(p)); + } + + /* Sort by name */ + newlist = fluid_list_sort(newlist, fluid_list_str_compare_func); + + for(p = newlist; p; p = p->next) + { + (*func)(data, name, (const char *)fluid_list_get(p)); + } + + fluid_rec_mutex_unlock(settings->mutex); /* -- unlock */ + + delete_fluid_list(newlist); +} + +/** + * Count option string values for a string setting. + * + * @param settings a settings object + * @param name Name of setting + * @return Count of options for this string setting (0 if none, -1 if not found + * or not a string setting) + * + * @since 1.1.0 + */ +int +fluid_settings_option_count(fluid_settings_t *settings, const char *name) +{ + fluid_setting_node_t *node; + int count = -1; + + fluid_return_val_if_fail(settings != NULL, -1); + fluid_return_val_if_fail(name != NULL, -1); + fluid_return_val_if_fail(name[0] != '\0', -1); + + fluid_rec_mutex_lock(settings->mutex); + + if(fluid_settings_get(settings, name, &node) == FLUID_OK + && node->type == FLUID_STR_TYPE) + { + count = fluid_list_size(node->str.options); + } + + fluid_rec_mutex_unlock(settings->mutex); + + return (count); +} + +/** + * Concatenate options for a string setting together with a separator between. + * + * @param settings Settings object + * @param name Settings name + * @param separator String to use between options (NULL to use ", ") + * @return Newly allocated string or NULL on error (out of memory, not a valid + * setting \p name or not a string setting). Free the string when finished with it by using fluid_free(). + * + * @since 1.1.0 + */ +char * +fluid_settings_option_concat(fluid_settings_t *settings, const char *name, + const char *separator) +{ + fluid_setting_node_t *node; + fluid_list_t *p, *newlist = NULL; + size_t count, len; + char *str, *option; + + fluid_return_val_if_fail(settings != NULL, NULL); + fluid_return_val_if_fail(name != NULL, NULL); + fluid_return_val_if_fail(name[0] != '\0', NULL); + + if(!separator) + { + separator = ", "; + } + + fluid_rec_mutex_lock(settings->mutex); /* ++ lock */ + + if(fluid_settings_get(settings, name, &node) != FLUID_OK + || node->type != FLUID_STR_TYPE) + { + fluid_rec_mutex_unlock(settings->mutex); /* -- unlock */ + return (NULL); + } + + /* Duplicate option list, count options and get total string length */ + for(p = node->str.options, count = 0, len = 0; p; p = p->next) + { + option = fluid_list_get(p); + + if(option) + { + newlist = fluid_list_append(newlist, option); + len += FLUID_STRLEN(option); + count++; + } + } + + if(count > 1) + { + len += (count - 1) * FLUID_STRLEN(separator); + } + + len++; /* For terminator */ + + /* Sort by name */ + newlist = fluid_list_sort(newlist, fluid_list_str_compare_func); + + str = FLUID_MALLOC(len); + + if(str) + { + str[0] = 0; + + for(p = newlist; p; p = p->next) + { + option = fluid_list_get(p); + strcat(str, option); + + if(p->next) + { + strcat(str, separator); + } + } + } + + fluid_rec_mutex_unlock(settings->mutex); /* -- unlock */ + + delete_fluid_list(newlist); + + if(!str) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + } + + return (str); +} + +/* Structure passed to fluid_settings_foreach_iter recursive function */ +typedef struct +{ + char path[MAX_SETTINGS_LABEL + 1]; /* Maximum settings label length */ + fluid_list_t *names; /* For fluid_settings_foreach() */ +} fluid_settings_foreach_bag_t; + +static int +fluid_settings_foreach_iter(void *key, void *value, void *data) +{ + fluid_settings_foreach_bag_t *bag = data; + char *keystr = key; + fluid_setting_node_t *node = value; + size_t pathlen; + char *s; + + pathlen = FLUID_STRLEN(bag->path); + + if(pathlen > 0) + { + bag->path[pathlen] = '.'; + bag->path[pathlen + 1] = 0; + } + + strcat(bag->path, keystr); + + switch(node->type) + { + case FLUID_NUM_TYPE: + case FLUID_INT_TYPE: + case FLUID_STR_TYPE: + s = FLUID_STRDUP(bag->path); + + if(s) + { + bag->names = fluid_list_append(bag->names, s); + } + + break; + + case FLUID_SET_TYPE: + fluid_hashtable_foreach(node->set.hashtable, + fluid_settings_foreach_iter, bag); + break; + } + + bag->path[pathlen] = 0; + + return 0; +} + +/** + * Iterate the existing settings defined in a settings object, calling the + * provided callback function for each setting. + * + * @param settings a settings object + * @param data any user provided pointer + * @param func callback function to be called on each iteration + * + * @note Starting with FluidSynth 1.1.0 the \p func callback is called for each + * setting in alphabetical order. Sort order was undefined in previous versions. + */ +void +fluid_settings_foreach(fluid_settings_t *settings, void *data, + fluid_settings_foreach_t func) +{ + fluid_settings_foreach_bag_t bag; + fluid_setting_node_t *node; + fluid_list_t *p; + + fluid_return_if_fail(settings != NULL); + fluid_return_if_fail(func != NULL); + + bag.path[0] = 0; + bag.names = NULL; + + fluid_rec_mutex_lock(settings->mutex); + + /* Add all node names to the bag.names list */ + fluid_hashtable_foreach(settings, fluid_settings_foreach_iter, &bag); + + /* Sort names */ + bag.names = fluid_list_sort(bag.names, fluid_list_str_compare_func); + + /* Loop over names and call the callback */ + for(p = bag.names; p; p = p->next) + { + if(fluid_settings_get(settings, (const char *)(p->data), &node) == FLUID_OK + && node) + { + (*func)(data, (const char *)(p->data), node->type); + } + + FLUID_FREE(p->data); /* -- Free name */ + } + + fluid_rec_mutex_unlock(settings->mutex); + + delete_fluid_list(bag.names); /* -- Free names list */ +} + +/** + * Split a comma-separated list of integers and fill the passed + * in buffer with the parsed values. + * + * @param str the comma-separated string to split + * @param buf user-supplied buffer to hold the parsed numbers + * @param buf_len length of user-supplied buffer + * @return number of parsed values or -1 on failure + */ +int fluid_settings_split_csv(const char *str, int *buf, int buf_len) +{ + char *s; + char *tok; + char *tokstr; + int n = 0; + + s = tokstr = FLUID_STRDUP(str); + + if(s == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return -1; + } + + while((tok = fluid_strtok(&tokstr, ",")) && n < buf_len) + { + buf[n++] = atoi(tok); + } + + FLUID_FREE(s); + + return n; +} diff --git a/libs/fluidsynth/src/utils/fluid_settings.h b/libs/fluidsynth/src/utils/fluid_settings.h new file mode 100644 index 00000000000..73a63e86db5 --- /dev/null +++ b/libs/fluidsynth/src/utils/fluid_settings.h @@ -0,0 +1,65 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +#ifndef _FLUID_SETTINGS_H +#define _FLUID_SETTINGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +int fluid_settings_add_option(fluid_settings_t *settings, const char *name, const char *s); +int fluid_settings_remove_option(fluid_settings_t *settings, const char *name, const char *s); + + +typedef void (*fluid_str_update_t)(void *data, const char *name, const char *value); + +int fluid_settings_register_str(fluid_settings_t *settings, const char *name, const char *def, int hints); +int fluid_settings_callback_str(fluid_settings_t *settings, const char *name, + fluid_str_update_t fun, void *data); + + +typedef void (*fluid_num_update_t)(void *data, const char *name, double value); + +int fluid_settings_register_num(fluid_settings_t *settings, const char *name, double def, + double min, double max, int hints); +int fluid_settings_callback_num(fluid_settings_t *settings, const char *name, + fluid_num_update_t fun, void *data); + +/* Type specific wrapper for fluid_settings_getnum */ +int fluid_settings_getnum_float(fluid_settings_t *settings, const char *name, float *val); + + +typedef void (*fluid_int_update_t)(void *data, const char *name, int value); +int fluid_settings_register_int(fluid_settings_t *settings, const char *name, int def, + int min, int max, int hints); +int fluid_settings_callback_int(fluid_settings_t *settings, const char *name, + fluid_int_update_t fun, void *data); + +int fluid_settings_split_csv(const char *str, int *buf, int buf_len); + +void* fluid_settings_get_user_data(fluid_settings_t * settings, const char *name); + +#ifdef __cplusplus +} +#endif + +#endif /* _FLUID_SETTINGS_H */ diff --git a/libs/fluidsynth/src/utils/fluid_sys.c b/libs/fluidsynth/src/utils/fluid_sys.c new file mode 100644 index 00000000000..e94123022b2 --- /dev/null +++ b/libs/fluidsynth/src/utils/fluid_sys.c @@ -0,0 +1,1803 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +#include "fluid_sys.h" + + +#if READLINE_SUPPORT +#include +#include +#endif + +#ifdef DBUS_SUPPORT +#include "fluid_rtkit.h" +#endif + +#if HAVE_PTHREAD_H && !defined(_WIN32) +// Do not include pthread on windows. It includes winsock.h, which collides with ws2tcpip.h from fluid_sys.h +// It isn't need on Windows anyway. +#include +#endif + +/* WIN32 HACK - Flag used to differentiate between a file descriptor and a socket. + * Should work, so long as no SOCKET or file descriptor ends up with this bit set. - JG */ +#ifdef _WIN32 +#define FLUID_SOCKET_FLAG 0x40000000 +#else +#define FLUID_SOCKET_FLAG 0x00000000 +#define SOCKET_ERROR -1 +#define INVALID_SOCKET -1 +#endif + +/* SCHED_FIFO priority for high priority timer threads */ +#define FLUID_SYS_TIMER_HIGH_PRIO_LEVEL 10 + + +typedef struct +{ + fluid_thread_func_t func; + void *data; + int prio_level; +} fluid_thread_info_t; + +struct _fluid_timer_t +{ + long msec; + + // Pointer to a function to be executed by the timer. + // This field is set to NULL once the timer is finished to indicate completion. + // This allows for timed waits, rather than waiting forever as fluid_timer_join() does. + fluid_timer_callback_t callback; + void *data; + fluid_thread_t *thread; + int cont; + int auto_destroy; +}; + +struct _fluid_server_socket_t +{ + fluid_socket_t socket; + fluid_thread_t *thread; + int cont; + fluid_server_func_t func; + void *data; +}; + + +static int fluid_istream_gets(fluid_istream_t in, char *buf, int len); + +static fluid_log_function_t fluid_log_function[LAST_LOG_LEVEL] = +{ + fluid_default_log_function, + fluid_default_log_function, + fluid_default_log_function, + fluid_default_log_function, +#ifdef DEBUG + fluid_default_log_function +#else + NULL +#endif +}; +static void *fluid_log_user_data[LAST_LOG_LEVEL] = { NULL }; + +static const char fluid_libname[] = "fluidsynth"; + +/** + * Installs a new log function for a specified log level. + * @param level Log level to install handler for. + * @param fun Callback function handler to call for logged messages + * @param data User supplied data pointer to pass to log function + * @return The previously installed function. + */ +fluid_log_function_t +fluid_set_log_function(int level, fluid_log_function_t fun, void *data) +{ + fluid_log_function_t old = NULL; + + if((level >= 0) && (level < LAST_LOG_LEVEL)) + { + old = fluid_log_function[level]; + fluid_log_function[level] = fun; + fluid_log_user_data[level] = data; + } + + return old; +} + +/** + * Default log function which prints to the stderr. + * @param level Log level + * @param message Log message + * @param data User supplied data (not used) + */ +void +fluid_default_log_function(int level, const char *message, void *data) +{ + FILE *out; + +#if defined(_WIN32) + out = stdout; +#else + out = stderr; +#endif + + switch(level) + { + case FLUID_PANIC: + FLUID_FPRINTF(out, "%s: panic: %s\n", fluid_libname, message); + break; + + case FLUID_ERR: + FLUID_FPRINTF(out, "%s: error: %s\n", fluid_libname, message); + break; + + case FLUID_WARN: + FLUID_FPRINTF(out, "%s: warning: %s\n", fluid_libname, message); + break; + + case FLUID_INFO: + FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message); + break; + + case FLUID_DBG: + FLUID_FPRINTF(out, "%s: debug: %s\n", fluid_libname, message); + break; + + default: + FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message); + break; + } + + fflush(out); +} + +/** + * Print a message to the log. + * @param level Log level (#fluid_log_level). + * @param fmt Printf style format string for log message + * @param ... Arguments for printf 'fmt' message string + * @return Always returns #FLUID_FAILED + */ +int +fluid_log(int level, const char *fmt, ...) +{ + if((level >= 0) && (level < LAST_LOG_LEVEL)) + { + fluid_log_function_t fun = fluid_log_function[level]; + + if(fun != NULL) + { + char errbuf[1024]; + + va_list args; + va_start(args, fmt); + FLUID_VSNPRINTF(errbuf, sizeof(errbuf), fmt, args); + va_end(args); + + (*fun)(level, errbuf, fluid_log_user_data[level]); + } + } + + return FLUID_FAILED; +} + +void* fluid_alloc(size_t len) +{ + void* ptr = malloc(len); + +#if defined(DEBUG) && !defined(_MSC_VER) + // garbage initialize allocated memory for debug builds to ease reproducing + // bugs like 44453ff23281b3318abbe432fda90888c373022b . + // + // MSVC++ already garbage initializes allocated memory by itself (debug-heap). + // + // 0xCC because + // * it makes pointers reliably crash when dereferencing them, + // * floating points are still some valid but insanely huge negative number, and + // * if for whatever reason this allocated memory is executed, it'll trigger + // INT3 (...at least on x86) + if(ptr != NULL) + { + memset(ptr, 0xCC, len); + } +#endif + return ptr; +} + +/** + * Open a file with a UTF-8 string, even in Windows + * @param filename The name of the file to open + * @param mode The mode to open the file in + */ +FILE *fluid_fopen(const char *filename, const char *mode) +{ +#if defined(_WIN32) + wchar_t *wpath = NULL, *wmode = NULL; + FILE *file = NULL; + int length; + if ((length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filename, -1, NULL, 0)) == 0) + { + FLUID_LOG(FLUID_ERR, "Unable to perform MultiByteToWideChar() conversion for filename '%s'. Error was: '%s'", filename, fluid_get_windows_error()); + errno = EINVAL; + goto error_recovery; + } + + wpath = FLUID_MALLOC(length * sizeof(wchar_t)); + if (wpath == NULL) + { + FLUID_LOG(FLUID_PANIC, "Out of memory."); + errno = EINVAL; + goto error_recovery; + } + + MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filename, -1, wpath, length); + + if ((length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, mode, -1, NULL, 0)) == 0) + { + FLUID_LOG(FLUID_ERR, "Unable to perform MultiByteToWideChar() conversion for mode '%s'. Error was: '%s'", mode, fluid_get_windows_error()); + errno = EINVAL; + goto error_recovery; + } + + wmode = FLUID_MALLOC(length * sizeof(wchar_t)); + if (wmode == NULL) + { + FLUID_LOG(FLUID_PANIC, "Out of memory."); + errno = EINVAL; + goto error_recovery; + } + + MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, mode, -1, wmode, length); + + file = _wfopen(wpath, wmode); + +error_recovery: + FLUID_FREE(wpath); + FLUID_FREE(wmode); + + return file; +#else + return fopen(filename, mode); +#endif +} + +/** + * Wrapper for free() that satisfies at least C90 requirements. + * + * @param ptr Pointer to memory region that should be freed + * + * @note Only use this function when the API documentation explicitly says so. Otherwise use + * adequate \c delete_fluid_* functions. + * + * @warning Calling ::free() on memory that is advised to be freed with fluid_free() results in undefined behaviour! + * (cf.: "Potential Errors Passing CRT Objects Across DLL Boundaries" found in MS Docs) + * + * @since 2.0.7 + */ +void fluid_free(void* ptr) +{ + free(ptr); +} + +/** + * An improved strtok, still trashes the input string, but is portable and + * thread safe. Also skips token chars at beginning of token string and never + * returns an empty token (will return NULL if source ends in token chars though). + * NOTE: NOT part of public API + * @internal + * @param str Pointer to a string pointer of source to tokenize. Pointer gets + * updated on each invocation to point to beginning of next token. Note that + * token char gets overwritten with a 0 byte. String pointer is set to NULL + * when final token is returned. + * @param delim String of delimiter chars. + * @return Pointer to the next token or NULL if no more tokens. + */ +char *fluid_strtok(char **str, char *delim) +{ + char *s, *d, *token; + char c; + + if(str == NULL || delim == NULL || !*delim) + { + FLUID_LOG(FLUID_ERR, "Null pointer"); + return NULL; + } + + s = *str; + + if(!s) + { + return NULL; /* str points to a NULL pointer? (tokenize already ended) */ + } + + /* skip delimiter chars at beginning of token */ + do + { + c = *s; + + if(!c) /* end of source string? */ + { + *str = NULL; + return NULL; + } + + for(d = delim; *d; d++) /* is source char a token char? */ + { + if(c == *d) /* token char match? */ + { + s++; /* advance to next source char */ + break; + } + } + } + while(*d); /* while token char match */ + + token = s; /* start of token found */ + + /* search for next token char or end of source string */ + for(s = s + 1; *s; s++) + { + c = *s; + + for(d = delim; *d; d++) /* is source char a token char? */ + { + if(c == *d) /* token char match? */ + { + *s = '\0'; /* overwrite token char with zero byte to terminate token */ + *str = s + 1; /* update str to point to beginning of next token */ + return token; + } + } + } + + /* we get here only if source string ended */ + *str = NULL; + return token; +} + +/** + * Suspend the execution of the current thread for the specified amount of time. + * @param milliseconds to wait. + */ +void fluid_msleep(unsigned int msecs) +{ + g_usleep(msecs * 1000); +} + +/** + * Get time in milliseconds to be used in relative timing operations. + * @return Monotonic time in milliseconds. + */ +unsigned int fluid_curtime(void) +{ + double now; + static double initial_time = 0; + + if(initial_time == 0) + { + initial_time = fluid_utime(); + } + + now = fluid_utime(); + + return (unsigned int)((now - initial_time) / 1000.0); +} + +/** + * Get time in microseconds to be used in relative timing operations. + * @return time in microseconds. + * Note: When used for profiling we need high precision clock given + * by g_get_monotonic_time()if available (glib version >= 2.53.3). + * If glib version is too old and in the case of Windows the function + * uses high precision performance counter instead of g_getmonotic_time(). + */ +double +fluid_utime(void) +{ + double utime; + +#if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 28 + /* use high precision monotonic clock if available (g_monotonic_time(). + * For Windows, if this clock is actually implemented as low prec. clock + * (i.e. in case glib is too old), high precision performance counter are + * used instead. + * see: https://bugzilla.gnome.org/show_bug.cgi?id=783340 + */ +#if defined(WITH_PROFILING) && defined(_WIN32) &&\ + /* glib < 2.53.3 */\ + (GLIB_MINOR_VERSION <= 53 && (GLIB_MINOR_VERSION < 53 || GLIB_MICRO_VERSION < 3)) + /* use high precision performance counter. */ + static LARGE_INTEGER freq_cache = {0, 0}; /* Performance Frequency */ + LARGE_INTEGER perf_cpt; + + if(! freq_cache.QuadPart) + { + QueryPerformanceFrequency(&freq_cache); /* Frequency value */ + } + + QueryPerformanceCounter(&perf_cpt); /* Counter value */ + utime = perf_cpt.QuadPart * 1000000.0 / freq_cache.QuadPart; /* time in micros */ +#else + utime = g_get_monotonic_time(); +#endif +#else + /* fallback to less precise clock */ + GTimeVal timeval; + g_get_current_time(&timeval); + utime = (timeval.tv_sec * 1000000.0 + timeval.tv_usec); +#endif + + return utime; +} + + + +#if defined(_WIN32) /* Windoze specific stuff */ + +void +fluid_thread_self_set_prio(int prio_level) +{ + if(prio_level > 0) + { + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); + } +} + + +#elif defined(__OS2__) /* OS/2 specific stuff */ + +void +fluid_thread_self_set_prio(int prio_level) +{ + if(prio_level > 0) + { + DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0); + } +} + +#else /* POSIX stuff.. Nice POSIX.. Good POSIX. */ + +void +fluid_thread_self_set_prio(int prio_level) +{ + struct sched_param priority; + + if(prio_level > 0) + { + + memset(&priority, 0, sizeof(priority)); + priority.sched_priority = prio_level; + + if(pthread_setschedparam(pthread_self(), SCHED_FIFO, &priority) == 0) + { + return; + } + +#ifdef DBUS_SUPPORT + /* Try to gain high priority via rtkit */ + + if(fluid_rtkit_make_realtime(0, prio_level) == 0) + { + return; + } + +#endif + FLUID_LOG(FLUID_WARN, "Failed to set thread to high priority"); + } +} + +#ifdef FPE_CHECK + +/*************************************************************** + * + * Floating point exceptions + * + * The floating point exception functions were taken from Ircam's + * jMax source code. https://www.ircam.fr/jmax + * + * FIXME: check in config for i386 machine + * + * Currently not used. I leave the code here in case we want to pick + * this up again some time later. + */ + +/* Exception flags */ +#define _FPU_STATUS_IE 0x001 /* Invalid Operation */ +#define _FPU_STATUS_DE 0x002 /* Denormalized Operand */ +#define _FPU_STATUS_ZE 0x004 /* Zero Divide */ +#define _FPU_STATUS_OE 0x008 /* Overflow */ +#define _FPU_STATUS_UE 0x010 /* Underflow */ +#define _FPU_STATUS_PE 0x020 /* Precision */ +#define _FPU_STATUS_SF 0x040 /* Stack Fault */ +#define _FPU_STATUS_ES 0x080 /* Error Summary Status */ + +/* Macros for accessing the FPU status word. */ + +/* get the FPU status */ +#define _FPU_GET_SW(sw) __asm__ ("fnstsw %0" : "=m" (*&sw)) + +/* clear the FPU status */ +#define _FPU_CLR_SW() __asm__ ("fnclex" : : ) + +/* Purpose: + * Checks, if the floating point unit has produced an exception, print a message + * if so and clear the exception. + */ +unsigned int fluid_check_fpe_i386(char *explanation) +{ + unsigned int s; + + _FPU_GET_SW(s); + _FPU_CLR_SW(); + + s &= _FPU_STATUS_IE | _FPU_STATUS_DE | _FPU_STATUS_ZE | _FPU_STATUS_OE | _FPU_STATUS_UE; + + if(s) + { + FLUID_LOG(FLUID_WARN, "FPE exception (before or in %s): %s%s%s%s%s", explanation, + (s & _FPU_STATUS_IE) ? "Invalid operation " : "", + (s & _FPU_STATUS_DE) ? "Denormal number " : "", + (s & _FPU_STATUS_ZE) ? "Zero divide " : "", + (s & _FPU_STATUS_OE) ? "Overflow " : "", + (s & _FPU_STATUS_UE) ? "Underflow " : ""); + } + + return s; +} + +/* Purpose: + * Clear floating point exception. + */ +void fluid_clear_fpe_i386(void) +{ + _FPU_CLR_SW(); +} + +#endif // ifdef FPE_CHECK + + +#endif // #else (its POSIX) + + +/*************************************************************** + * + * Profiling (Linux, i586 only) + * + */ + +#if WITH_PROFILING +/* Profiling interface between profiling command shell and audio rendering API + (FluidProfile_0004.pdf- 3.2.2). + Macros are in defined in fluid_sys.h. +*/ + +/* + ----------------------------------------------------------------------------- + Shell task side | Profiling interface | Audio task side + ----------------------------------------------------------------------------- + profiling | Internal | | | Audio + command <---> |<-- profiling -->| Data |<--macros -->| <--> rendering + shell | API | | | API + +*/ +/* default parameters for shell command "prof_start" in fluid_sys.c */ +unsigned short fluid_profile_notes = 0; /* number of generated notes */ +/* preset bank:0 prog:16 (organ) */ +unsigned char fluid_profile_bank = FLUID_PROFILE_DEFAULT_BANK; +unsigned char fluid_profile_prog = FLUID_PROFILE_DEFAULT_PROG; + +/* print mode */ +unsigned char fluid_profile_print = FLUID_PROFILE_DEFAULT_PRINT; +/* number of measures */ +unsigned short fluid_profile_n_prof = FLUID_PROFILE_DEFAULT_N_PROF; +/* measure duration in ms */ +unsigned short fluid_profile_dur = FLUID_PROFILE_DEFAULT_DURATION; +/* lock between multiple-shell */ +fluid_atomic_int_t fluid_profile_lock = 0; +/**/ + +/*---------------------------------------------- + Profiling Data +-----------------------------------------------*/ +unsigned char fluid_profile_status = PROFILE_STOP; /* command and status */ +unsigned int fluid_profile_end_ticks = 0; /* ending position (in ticks) */ +fluid_profile_data_t fluid_profile_data[] = /* Data duration */ +{ + {"synth_write_* ------------>", 1e10, 0.0, 0.0, 0, 0, 0}, + {"synth_one_block ---------->", 1e10, 0.0, 0.0, 0, 0, 0}, + {"synth_one_block:clear ---->", 1e10, 0.0, 0.0, 0, 0, 0}, + {"synth_one_block:one voice->", 1e10, 0.0, 0.0, 0, 0, 0}, + {"synth_one_block:all voices>", 1e10, 0.0, 0.0, 0, 0, 0}, + {"synth_one_block:reverb --->", 1e10, 0.0, 0.0, 0, 0, 0}, + {"synth_one_block:chorus --->", 1e10, 0.0, 0.0, 0, 0, 0}, + {"voice:note --------------->", 1e10, 0.0, 0.0, 0, 0, 0}, + {"voice:release ------------>", 1e10, 0.0, 0.0, 0, 0, 0} +}; + + +/*---------------------------------------------- + Internal profiling API +-----------------------------------------------*/ +/* logging profiling data (used on synthesizer instance deletion) */ +void fluid_profiling_print(void) +{ + int i; + + printf("fluid_profiling_print\n"); + + FLUID_LOG(FLUID_INFO, "Estimated times: min/avg/max (micro seconds)"); + + for(i = 0; i < FLUID_PROFILE_NBR; i++) + { + if(fluid_profile_data[i].count > 0) + { + FLUID_LOG(FLUID_INFO, "%s: %.3f/%.3f/%.3f", + fluid_profile_data[i].description, + fluid_profile_data[i].min, + fluid_profile_data[i].total / fluid_profile_data[i].count, + fluid_profile_data[i].max); + } + else + { + FLUID_LOG(FLUID_DBG, "%s: no profiling available", + fluid_profile_data[i].description); + } + } +} + +/* Macro that returns cpu load in percent (%) + * @dur: duration (micro second). + * @sample_rate: sample_rate used in audio driver (Hz). + * @n_amples: number of samples collected during 'dur' duration. +*/ +#define fluid_profile_load(dur,sample_rate,n_samples) \ + (dur * sample_rate / n_samples / 10000.0) + + +/* prints cpu loads only +* +* @param sample_rate the sample rate of audio output. +* @param out output stream device. +* +* ------------------------------------------------------------------------------ +* Cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond) and maximum voices +* ------------------------------------------------------------------------------ +* nVoices| total(%)|voices(%)| reverb(%)|chorus(%)| voice(%)|estimated maxVoices +* -------|---------|---------|----------|---------|---------|------------------- +* 250| 41.544| 41.544| 0.000| 0.000| 0.163| 612 +*/ +static void fluid_profiling_print_load(double sample_rate, fluid_ostream_t out) +{ + unsigned int n_voices; /* voices number */ + static const char max_voices_not_available[] = " not available"; + const char *pmax_voices; + char max_voices_available[20]; + + /* First computes data to be printed */ + double total, voices, reverb, chorus, all_voices, voice; + /* voices number */ + n_voices = fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count ? + fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].n_voices / + fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count : 0; + + /* total load (%) */ + total = fluid_profile_data[FLUID_PROF_WRITE].count ? + fluid_profile_load(fluid_profile_data[FLUID_PROF_WRITE].total, sample_rate, + fluid_profile_data[FLUID_PROF_WRITE].n_samples) : 0; + + /* reverb load (%) */ + reverb = fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].count ? + fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].total, + sample_rate, + fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].n_samples) : 0; + + /* chorus load (%) */ + chorus = fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].count ? + fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].total, + sample_rate, + fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].n_samples) : 0; + + /* total voices load: total - reverb - chorus (%) */ + voices = total - reverb - chorus; + + /* One voice load (%): all_voices / n_voices. */ + all_voices = fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count ? + fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].total, + sample_rate, + fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].n_samples) : 0; + + voice = n_voices ? all_voices / n_voices : 0; + + /* estimated maximum voices number */ + if(voice > 0) + { + FLUID_SNPRINTF(max_voices_available, sizeof(max_voices_available), + "%17d", (unsigned int)((100.0 - reverb - chorus) / voice)); + pmax_voices = max_voices_available; + } + else + { + pmax_voices = max_voices_not_available; + } + + /* Now prints data */ + fluid_ostream_printf(out, + " ------------------------------------------------------------------------------\n"); + fluid_ostream_printf(out, + " Cpu loads(%%) (sr:%6.0f Hz, sp:%6.2f microsecond) and maximum voices\n", + sample_rate, 1000000.0 / sample_rate); + fluid_ostream_printf(out, + " ------------------------------------------------------------------------------\n"); + fluid_ostream_printf(out, + " nVoices| total(%%)|voices(%%)| reverb(%%)|chorus(%%)| voice(%%)|estimated maxVoices\n"); + fluid_ostream_printf(out, + " -------|---------|---------|----------|---------|---------|-------------------\n"); + fluid_ostream_printf(out, + "%8d|%9.3f|%9.3f|%10.3f|%9.3f|%9.3f|%s\n", n_voices, total, voices, + reverb, chorus, voice, pmax_voices); +} + +/* +* prints profiling data (used by profile shell command: prof_start). +* The function is an internal profiling API between the "profile" command +* prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2). +* +* @param sample_rate the sample rate of audio output. +* @param out output stream device. +* +* When print mode is 1, the function prints all the information (see below). +* When print mode is 0, the function prints only the cpu loads. +* +* ------------------------------------------------------------------------------ +* Duration(microsecond) and cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond) +* ------------------------------------------------------------------------------ +* Code under profiling |Voices| Duration (microsecond) | Load(%) +* | nbr| min| avg| max| +* ---------------------------|------|--------------------------------|---------- +* synth_write_* ------------>| 250| 3.91| 2188.82| 3275.00| 41.544 +* synth_one_block ---------->| 250| 1150.70| 2273.56| 3241.47| 41.100 +* synth_one_block:clear ---->| 250| 3.07| 4.62| 61.18| 0.084 +* synth_one_block:one voice->| 1| 4.19| 9.02| 1044.27| 0.163 +* synth_one_block:all voices>| 250| 1138.41| 2259.11| 3217.73| 40.839 +* synth_one_block:reverb --->| no profiling available +* synth_one_block:chorus --->| no profiling available +* voice:note --------------->| no profiling available +* voice:release ------------>| no profiling available +* ------------------------------------------------------------------------------ +* Cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond) and maximum voices +* ------------------------------------------------------------------------------ +* nVoices| total(%)|voices(%)| reverb(%)|chorus(%)| voice(%)|estimated maxVoices +* -------|---------|---------|----------|---------|---------|------------------- +* 250| 41.544| 41.544| 0.000| 0.000| 0.163| 612 +*/ +void fluid_profiling_print_data(double sample_rate, fluid_ostream_t out) +{ + int i; + + if(fluid_profile_print) + { + /* print all details: Duration(microsecond) and cpu loads(%) */ + fluid_ostream_printf(out, + " ------------------------------------------------------------------------------\n"); + fluid_ostream_printf(out, + " Duration(microsecond) and cpu loads(%%) (sr:%6.0f Hz, sp:%6.2f microsecond)\n", + sample_rate, 1000000.0 / sample_rate); + fluid_ostream_printf(out, + " ------------------------------------------------------------------------------\n"); + fluid_ostream_printf(out, + " Code under profiling |Voices| Duration (microsecond) | Load(%%)\n"); + fluid_ostream_printf(out, + " | nbr| min| avg| max|\n"); + fluid_ostream_printf(out, + " ---------------------------|------|--------------------------------|----------\n"); + + for(i = 0; i < FLUID_PROFILE_NBR; i++) + { + unsigned int count = fluid_profile_data[i].count; + + if(count > 0) + { + /* data are available */ + + if(FLUID_PROF_WRITE <= i && i <= FLUID_PROF_ONE_BLOCK_CHORUS) + { + double load = fluid_profile_load(fluid_profile_data[i].total, sample_rate, + fluid_profile_data[i].n_samples); + fluid_ostream_printf(out, " %s|%6d|%10.2f|%10.2f|%10.2f|%8.3f\n", + fluid_profile_data[i].description, /* code under profiling */ + fluid_profile_data[i].n_voices / count, /* voices number */ + fluid_profile_data[i].min, /* minimum duration */ + fluid_profile_data[i].total / count, /* average duration */ + fluid_profile_data[i].max, /* maximum duration */ + load); /* cpu load */ + } + else + { + /* note and release duration */ + fluid_ostream_printf(out, " %s|%6d|%10.0f|%10.0f|%10.0f|\n", + fluid_profile_data[i].description, /* code under profiling */ + fluid_profile_data[i].n_voices / count, + fluid_profile_data[i].min, /* minimum duration */ + fluid_profile_data[i].total / count, /* average duration */ + fluid_profile_data[i].max); /* maximum duration */ + } + } + else + { + /* data aren't available */ + fluid_ostream_printf(out, + " %s| no profiling available\n", fluid_profile_data[i].description); + } + } + } + + /* prints cpu loads only */ + fluid_profiling_print_load(sample_rate, out);/* prints cpu loads */ +} + +/* + Returns true if the user cancels the current profiling measurement. + Actually this is implemented using the key. To add this functionality: + 1) Adds #define FLUID_PROFILE_CANCEL in fluid_sys.h. + 2) Adds the necessary code inside fluid_profile_is_cancel(). + + When FLUID_PROFILE_CANCEL is not defined, the function return FALSE. +*/ +int fluid_profile_is_cancel_req(void) +{ +#ifdef FLUID_PROFILE_CANCEL + +#if defined(_WIN32) /* Windows specific stuff */ + /* Profile cancellation is supported for Windows */ + /* returns TRUE if key is depressed */ + return(GetAsyncKeyState(VK_RETURN) & 0x1); + +#elif defined(__OS2__) /* OS/2 specific stuff */ + /* Profile cancellation isn't yet supported for OS2 */ + /* For OS2, replaces the following line with the function that returns + true when the keyboard key is depressed */ + return FALSE; /* default value */ + +#else /* POSIX stuff */ + /* Profile cancellation is supported for Linux */ + /* returns true is is depressed */ + { + /* Here select() is used to poll the standard input to see if an input + is ready. As the standard input is usually buffered, the user + needs to depress to set the input to a "ready" state. + */ + struct timeval tv; + fd_set fds; /* just one fds need to be polled */ + tv.tv_sec = 0; /* Setting both values to 0, means a 0 timeout */ + tv.tv_usec = 0; + FD_ZERO(&fds); /* reset fds */ + FD_SET(STDIN_FILENO, &fds); /* sets fds to poll standard input only */ + select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv); /* polling */ + return (FD_ISSET(0, &fds)); /* returns true if standard input is ready */ + } +#endif /* OS stuff */ + +#else /* FLUID_PROFILE_CANCEL not defined */ + return FALSE; /* default value */ +#endif /* FLUID_PROFILE_CANCEL */ +} + +/** +* Returns status used in shell command "prof_start". +* The function is an internal profiling API between the "profile" command +* prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2). +* +* @return status +* - PROFILE_READY profiling data are ready. +* - PROFILE_RUNNING, profiling data are still under acquisition. +* - PROFILE_CANCELED, acquisition has been cancelled by the user. +* - PROFILE_STOP, no acquisition in progress. +* +* When status is PROFILE_RUNNING, the caller can do passive waiting, or other +* work before recalling the function later. +*/ +int fluid_profile_get_status(void) +{ + /* Checks if user has requested to cancel the current measurement */ + /* Cancellation must have precedence over other status */ + if(fluid_profile_is_cancel_req()) + { + fluid_profile_start_stop(0, 0); /* stops the measurement */ + return PROFILE_CANCELED; + } + + switch(fluid_profile_status) + { + case PROFILE_READY: + return PROFILE_READY; /* profiling data are ready */ + + case PROFILE_START: + return PROFILE_RUNNING;/* profiling data are under acquisition */ + + default: + return PROFILE_STOP; + } +} + +/** +* Starts or stops profiling measurement. +* The function is an internal profiling API between the "profile" command +* prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2). +* +* @param end_tick end position of the measure (in ticks). +* - If end_tick is greater then 0, the function starts a measure if a measure +* isn't running. If a measure is already running, the function does nothing +* and returns. +* - If end_tick is 0, the function stops a measure. +* @param clear_data, +* - If clear_data is 0, the function clears fluid_profile_data before starting +* a measure, otherwise, the data from the started measure will be accumulated +* within fluid_profile_data. +*/ +void fluid_profile_start_stop(unsigned int end_ticks, short clear_data) +{ + if(end_ticks) /* This is a "start" request */ + { + /* Checks if a measure is already running */ + if(fluid_profile_status != PROFILE_START) + { + short i; + fluid_profile_end_ticks = end_ticks; + + /* Clears profile data */ + if(clear_data == 0) + { + for(i = 0; i < FLUID_PROFILE_NBR; i++) + { + fluid_profile_data[i].min = 1e10;/* min sets to max value */ + fluid_profile_data[i].max = 0; /* maximum sets to min value */ + fluid_profile_data[i].total = 0; /* total duration microsecond */ + fluid_profile_data[i].count = 0; /* data count */ + fluid_profile_data[i].n_voices = 0; /* voices number */ + fluid_profile_data[i].n_samples = 0;/* audio samples number */ + } + } + + fluid_profile_status = PROFILE_START; /* starts profiling */ + } + + /* else do nothing when profiling is already started */ + } + else /* This is a "stop" request */ + { + /* forces the current running profile (if any) to stop */ + fluid_profile_status = PROFILE_STOP; /* stops profiling */ + } +} + +#endif /* WITH_PROFILING */ + +/*************************************************************** + * + * Threads + * + */ + +#if OLD_GLIB_THREAD_API + +/* Rather than inline this one, we just declare it as a function, to prevent + * GCC warning about inline failure. */ +fluid_cond_t * +new_fluid_cond(void) +{ + if(!g_thread_supported()) + { + g_thread_init(NULL); + } + + return g_cond_new(); +} + +#endif + +static gpointer +fluid_thread_high_prio(gpointer data) +{ + fluid_thread_info_t *info = data; + + fluid_thread_self_set_prio(info->prio_level); + + info->func(info->data); + FLUID_FREE(info); + + return NULL; +} + +/** + * Create a new thread. + * @param func Function to execute in new thread context + * @param data User defined data to pass to func + * @param prio_level Priority level. If greater than 0 then high priority scheduling will + * be used, with the given priority level (used by pthreads only). 0 uses normal scheduling. + * @param detach If TRUE, 'join' does not work and the thread destroys itself when finished. + * @return New thread pointer or NULL on error + */ +fluid_thread_t * +new_fluid_thread(const char *name, fluid_thread_func_t func, void *data, int prio_level, int detach) +{ + GThread *thread; + fluid_thread_info_t *info = NULL; + GError *err = NULL; + + g_return_val_if_fail(func != NULL, NULL); + +#if OLD_GLIB_THREAD_API + + /* Make sure g_thread_init has been called. + * Probably not a good idea in a shared library, + * but what can we do *and* remain backwards compatible? */ + if(!g_thread_supported()) + { + g_thread_init(NULL); + } + +#endif + + if(prio_level > 0) + { + info = FLUID_NEW(fluid_thread_info_t); + + if(!info) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + info->func = func; + info->data = data; + info->prio_level = prio_level; +#if NEW_GLIB_THREAD_API + thread = g_thread_try_new(name, fluid_thread_high_prio, info, &err); +#else + thread = g_thread_create(fluid_thread_high_prio, info, detach == FALSE, &err); +#endif + } + + else + { +#if NEW_GLIB_THREAD_API + thread = g_thread_try_new(name, (GThreadFunc)func, data, &err); +#else + thread = g_thread_create((GThreadFunc)func, data, detach == FALSE, &err); +#endif + } + + if(!thread) + { + FLUID_LOG(FLUID_ERR, "Failed to create the thread: %s", + fluid_gerror_message(err)); + g_clear_error(&err); + FLUID_FREE(info); + return NULL; + } + +#if NEW_GLIB_THREAD_API + + if(detach) + { + g_thread_unref(thread); // Release thread reference, if caller wants to detach + } + +#endif + + return thread; +} + +/** + * Frees data associated with a thread (does not actually stop thread). + * @param thread Thread to free + */ +void +delete_fluid_thread(fluid_thread_t *thread) +{ + /* Threads free themselves when they quit, nothing to do */ +} + +/** + * Join a thread (wait for it to terminate). + * @param thread Thread to join + * @return FLUID_OK + */ +int +fluid_thread_join(fluid_thread_t *thread) +{ + g_thread_join(thread); + + return FLUID_OK; +} + + +static fluid_thread_return_t +fluid_timer_run(void *data) +{ + fluid_timer_t *timer; + int count = 0; + int cont; + long start; + long delay; + + timer = (fluid_timer_t *)data; + + /* keep track of the start time for absolute positioning */ + start = fluid_curtime(); + + while(timer->cont) + { + cont = (*timer->callback)(timer->data, fluid_curtime() - start); + + count++; + + if(!cont) + { + break; + } + + /* to avoid incremental time errors, calculate the delay between + two callbacks bringing in the "absolute" time (count * + timer->msec) */ + delay = (count * timer->msec) - (fluid_curtime() - start); + + if(delay > 0) + { + fluid_msleep(delay); + } + } + + FLUID_LOG(FLUID_DBG, "Timer thread finished"); + timer->callback = NULL; + + if(timer->auto_destroy) + { + FLUID_FREE(timer); + } + + return FLUID_THREAD_RETURN_VALUE; +} + +fluid_timer_t * +new_fluid_timer(int msec, fluid_timer_callback_t callback, void *data, + int new_thread, int auto_destroy, int high_priority) +{ + fluid_timer_t *timer; + + timer = FLUID_NEW(fluid_timer_t); + + if(timer == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + timer->msec = msec; + timer->callback = callback; + timer->data = data; + timer->cont = TRUE ; + timer->thread = NULL; + timer->auto_destroy = auto_destroy; + + if(new_thread) + { + timer->thread = new_fluid_thread("timer", fluid_timer_run, timer, high_priority + ? FLUID_SYS_TIMER_HIGH_PRIO_LEVEL : 0, FALSE); + + if(!timer->thread) + { + FLUID_FREE(timer); + return NULL; + } + } + else + { + fluid_timer_run(timer); /* Run directly, instead of as a separate thread */ + + if(auto_destroy) + { + /* do NOT return freed memory */ + return NULL; + } + } + + return timer; +} + +void +delete_fluid_timer(fluid_timer_t *timer) +{ + int auto_destroy; + fluid_return_if_fail(timer != NULL); + + auto_destroy = timer->auto_destroy; + + timer->cont = 0; + fluid_timer_join(timer); + + /* Shouldn't access timer now if auto_destroy enabled, since it has been destroyed */ + + if(!auto_destroy) + { + FLUID_FREE(timer); + } +} + +int +fluid_timer_join(fluid_timer_t *timer) +{ + int auto_destroy; + + if(timer->thread) + { + auto_destroy = timer->auto_destroy; + fluid_thread_join(timer->thread); + + if(!auto_destroy) + { + timer->thread = NULL; + } + } + + return FLUID_OK; +} + +int +fluid_timer_is_running(const fluid_timer_t *timer) +{ + // for unit test usage only + return timer->callback != NULL; +} + +long fluid_timer_get_interval(const fluid_timer_t * timer) +{ + // for unit test usage only + return timer->msec; +} + + +/*************************************************************** + * + * Sockets and I/O + * + */ + +/** + * Get standard in stream handle. + * @return Standard in stream. + */ +fluid_istream_t +fluid_get_stdin(void) +{ + return STDIN_FILENO; +} + +/** + * Get standard output stream handle. + * @return Standard out stream. + */ +fluid_ostream_t +fluid_get_stdout(void) +{ + return STDOUT_FILENO; +} + +/** + * Read a line from an input stream. + * @return 0 if end-of-stream, -1 if error, non zero otherwise + */ +int +fluid_istream_readline(fluid_istream_t in, fluid_ostream_t out, char *prompt, + char *buf, int len) +{ +#if READLINE_SUPPORT + + if(in == fluid_get_stdin()) + { + char *line; + + line = readline(prompt); + + if(line == NULL) + { + return -1; + } + + FLUID_SNPRINTF(buf, len, "%s", line); + buf[len - 1] = 0; + + if(buf[0] != '\0') + { + add_history(buf); + } + + free(line); + return 1; + } + else +#endif + { + fluid_ostream_printf(out, "%s", prompt); + return fluid_istream_gets(in, buf, len); + } +} + +/** + * Reads a line from an input stream (socket). + * @param in The input socket + * @param buf Buffer to store data to + * @param len Maximum length to store to buf + * @return 1 if a line was read, 0 on end of stream, -1 on error + */ +static int +fluid_istream_gets(fluid_istream_t in, char *buf, int len) +{ + char c; + int n; + + buf[len - 1] = 0; + + while(--len > 0) + { +#ifndef _WIN32 + n = read(in, &c, 1); + + if(n == -1) + { + return -1; + } + +#else + + /* Handle read differently depending on if its a socket or file descriptor */ + if(!(in & FLUID_SOCKET_FLAG)) + { + // usually read() is supposed to return '\n' as last valid character of the user input + // when compiled with compatibility for WinXP however, read() may return 0 (EOF) rather than '\n' + // this would cause the shell to exit early + n = read(in, &c, 1); + + if(n == -1) + { + return -1; + } + } + else + { +#ifdef NETWORK_SUPPORT + n = recv(in & ~FLUID_SOCKET_FLAG, &c, 1, 0); + if(n == SOCKET_ERROR) +#endif + { + return -1; + } + } + +#endif + + if(n == 0) + { + *buf = 0; + // return 1 if read from stdin, else 0, to fix early exit of shell + return (in == STDIN_FILENO); + } + + if(c == '\n') + { + *buf = 0; + return 1; + } + + /* Store all characters excluding CR */ + if(c != '\r') + { + *buf++ = c; + } + } + + return -1; +} + +/** + * Send a printf style string with arguments to an output stream (socket). + * @param out Output stream + * @param format printf style format string + * @param ... Arguments for the printf format string + * @return Number of bytes written or -1 on error + */ +int +fluid_ostream_printf(fluid_ostream_t out, const char *format, ...) +{ + char buf[4096]; + va_list args; + int len; + + va_start(args, format); + len = FLUID_VSNPRINTF(buf, 4095, format, args); + va_end(args); + + if(len == 0) + { + return 0; + } + + if(len < 0) + { + printf("fluid_ostream_printf: buffer overflow"); + return -1; + } + + buf[4095] = 0; + +#ifndef _WIN32 + return write(out, buf, FLUID_STRLEN(buf)); +#else + { + int retval; + + /* Handle write differently depending on if its a socket or file descriptor */ + if(!(out & FLUID_SOCKET_FLAG)) + { + return write(out, buf, (unsigned int)FLUID_STRLEN(buf)); + } + +#ifdef NETWORK_SUPPORT + /* Socket */ + retval = send(out & ~FLUID_SOCKET_FLAG, buf, (int)FLUID_STRLEN(buf), 0); + return retval != SOCKET_ERROR ? retval : -1; +#else + return -1; +#endif + } +#endif +} + +#ifdef NETWORK_SUPPORT + +int fluid_server_socket_join(fluid_server_socket_t *server_socket) +{ + return fluid_thread_join(server_socket->thread); +} + +static int fluid_socket_init(void) +{ +#ifdef _WIN32 + WSADATA wsaData; + int res = WSAStartup(MAKEWORD(2, 2), &wsaData); + + if(res != 0) + { + FLUID_LOG(FLUID_ERR, "Server socket creation error: WSAStartup failed: %d", res); + return FLUID_FAILED; + } + +#endif + + return FLUID_OK; +} + +static void fluid_socket_cleanup(void) +{ +#ifdef _WIN32 + WSACleanup(); +#endif +} + +static int fluid_socket_get_error(void) +{ +#ifdef _WIN32 + return (int)WSAGetLastError(); +#else + return errno; +#endif +} + +fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock) +{ + return sock | FLUID_SOCKET_FLAG; +} + +fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock) +{ + return sock | FLUID_SOCKET_FLAG; +} + +void fluid_socket_close(fluid_socket_t sock) +{ + if(sock != INVALID_SOCKET) + { +#ifdef _WIN32 + closesocket(sock); + +#else + close(sock); +#endif + } +} + +static fluid_thread_return_t fluid_server_socket_run(void *data) +{ + fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data; + fluid_socket_t client_socket; +#ifdef IPV6_SUPPORT + struct sockaddr_in6 addr; +#else + struct sockaddr_in addr; +#endif + +#ifdef HAVE_INETNTOP +#ifdef IPV6_SUPPORT + char straddr[INET6_ADDRSTRLEN]; +#else + char straddr[INET_ADDRSTRLEN]; +#endif /* IPV6_SUPPORT */ +#endif /* HAVE_INETNTOP */ + + socklen_t addrlen = sizeof(addr); + int r; + FLUID_MEMSET((char *)&addr, 0, sizeof(addr)); + + FLUID_LOG(FLUID_DBG, "Server listening for connections"); + + while(server_socket->cont) + { + client_socket = accept(server_socket->socket, (struct sockaddr *)&addr, &addrlen); + + FLUID_LOG(FLUID_DBG, "New client connection"); + + if(client_socket == INVALID_SOCKET) + { + if(server_socket->cont) + { + FLUID_LOG(FLUID_ERR, "Failed to accept connection: %d", fluid_socket_get_error()); + } + + server_socket->cont = 0; + return FLUID_THREAD_RETURN_VALUE; + } + else + { +#ifdef HAVE_INETNTOP + +#ifdef IPV6_SUPPORT + inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr)); +#else + inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr)); +#endif + + r = server_socket->func(server_socket->data, client_socket, + straddr); +#else + r = server_socket->func(server_socket->data, client_socket, + inet_ntoa(addr.sin_addr)); +#endif + + if(r != 0) + { + fluid_socket_close(client_socket); + } + } + } + + FLUID_LOG(FLUID_DBG, "Server closing"); + + return FLUID_THREAD_RETURN_VALUE; +} + +fluid_server_socket_t * +new_fluid_server_socket(int port, fluid_server_func_t func, void *data) +{ + fluid_server_socket_t *server_socket; +#ifdef IPV6_SUPPORT + struct sockaddr_in6 addr; +#else + struct sockaddr_in addr; +#endif + + fluid_socket_t sock; + + fluid_return_val_if_fail(func != NULL, NULL); + + if(fluid_socket_init() != FLUID_OK) + { + return NULL; + } + +#ifdef IPV6_SUPPORT + sock = socket(AF_INET6, SOCK_STREAM, 0); + + if(sock == INVALID_SOCKET) + { + FLUID_LOG(FLUID_ERR, "Failed to create server socket: %d", fluid_socket_get_error()); + fluid_socket_cleanup(); + return NULL; + } + + FLUID_MEMSET(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons((uint16_t)port); + addr.sin6_addr = in6addr_any; +#else + + sock = socket(AF_INET, SOCK_STREAM, 0); + + if(sock == INVALID_SOCKET) + { + FLUID_LOG(FLUID_ERR, "Failed to create server socket: %d", fluid_socket_get_error()); + fluid_socket_cleanup(); + return NULL; + } + + FLUID_MEMSET(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons((uint16_t)port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); +#endif + + if(bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) + { + FLUID_LOG(FLUID_ERR, "Failed to bind server socket: %d", fluid_socket_get_error()); + fluid_socket_close(sock); + fluid_socket_cleanup(); + return NULL; + } + + if(listen(sock, SOMAXCONN) == SOCKET_ERROR) + { + FLUID_LOG(FLUID_ERR, "Failed to listen on server socket: %d", fluid_socket_get_error()); + fluid_socket_close(sock); + fluid_socket_cleanup(); + return NULL; + } + + server_socket = FLUID_NEW(fluid_server_socket_t); + + if(server_socket == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + fluid_socket_close(sock); + fluid_socket_cleanup(); + return NULL; + } + + server_socket->socket = sock; + server_socket->func = func; + server_socket->data = data; + server_socket->cont = 1; + + server_socket->thread = new_fluid_thread("server", fluid_server_socket_run, server_socket, + 0, FALSE); + + if(server_socket->thread == NULL) + { + FLUID_FREE(server_socket); + fluid_socket_close(sock); + fluid_socket_cleanup(); + return NULL; + } + + return server_socket; +} + +void delete_fluid_server_socket(fluid_server_socket_t *server_socket) +{ + fluid_return_if_fail(server_socket != NULL); + + server_socket->cont = 0; + + if(server_socket->socket != INVALID_SOCKET) + { + fluid_socket_close(server_socket->socket); + } + + if(server_socket->thread) + { + fluid_thread_join(server_socket->thread); + delete_fluid_thread(server_socket->thread); + } + + FLUID_FREE(server_socket); + + // Should be called the same number of times as fluid_socket_init() + fluid_socket_cleanup(); +} + +#endif // NETWORK_SUPPORT + +FILE* fluid_file_open(const char* path, const char** errMsg) +{ + static const char ErrExist[] = "File does not exist."; + static const char ErrRegular[] = "File is not regular, refusing to open it."; + static const char ErrNull[] = "File does not exists or insufficient permissions to open it."; + + FILE* handle = NULL; + + if(!fluid_file_test(path, FLUID_FILE_TEST_EXISTS)) + { + if(errMsg != NULL) + { + *errMsg = ErrExist; + } + } + else if(!fluid_file_test(path, FLUID_FILE_TEST_IS_REGULAR)) + { + if(errMsg != NULL) + { + *errMsg = ErrRegular; + } + } + else if((handle = FLUID_FOPEN(path, "rb")) == NULL) + { + if(errMsg != NULL) + { + *errMsg = ErrNull; + } + } + + return handle; +} + +fluid_long_long_t fluid_file_tell(FILE* f) +{ +#ifdef _WIN32 + // On Windows, long is only a 32 bit integer. Thus ftell() does not support to handle files >2GiB. + // We should use _ftelli64() in this case, however its availability depends on MS CRT and might not be + // available on WindowsXP, Win98, etc. + // + // The web recommends to fallback to _telli64() in this case. However, it's return value differs from + // _ftelli64() on Win10: https://github.com/FluidSynth/fluidsynth/pull/629#issuecomment-602238436 + // + // Thus, we use fgetpos(). + fpos_t pos; + if(fgetpos(f, &pos) != 0) + { + return (fluid_long_long_t)-1L; + } + return pos; +#else + return ftell(f); +#endif +} + +#if defined(_WIN32) || defined(__CYGWIN__) +// not thread-safe! +char* fluid_get_windows_error(void) +{ + static TCHAR err[1024]; + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + err, + sizeof(err)/sizeof(err[0]), + NULL); + +#ifdef _UNICODE + static char ascii_err[sizeof(err)]; + + WideCharToMultiByte(CP_UTF8, 0, err, -1, ascii_err, sizeof(ascii_err)/sizeof(ascii_err[0]), 0, 0); + return ascii_err; +#else + return err; +#endif +} +#endif diff --git a/libs/fluidsynth/src/utils/fluid_sys.h b/libs/fluidsynth/src/utils/fluid_sys.h new file mode 100644 index 00000000000..15f3f57b756 --- /dev/null +++ b/libs/fluidsynth/src/utils/fluid_sys.h @@ -0,0 +1,794 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + + +/* + * @file fluid_sys.h + * + * This header contains a bunch of (mostly) system and machine + * dependent functions: + * + * - timers + * - current time in milliseconds and microseconds + * - debug logging + * - profiling + * - memory locking + * - checking for floating point exceptions + * + * fluidsynth's wrapper OSAL so to say; include it in .c files, be careful to include + * it in fluidsynth's private header files (see comment in fluid_coreaudio.c) + */ + +#ifndef _FLUID_SYS_H +#define _FLUID_SYS_H + +#include "fluidsynth_priv.h" + +#if HAVE_MATH_H +#include +#endif + +#if HAVE_ERRNO_H +#include +#endif + +#if HAVE_STDARG_H +#include +#endif + +#if HAVE_UNISTD_H +#include +#endif + +#if HAVE_FCNTL_H +#include +#endif + +#if HAVE_SYS_MMAN_H +#include +#endif + +#if HAVE_SYS_TYPES_H +#include +#endif + +#if HAVE_SYS_STAT_H +#include +#endif + +#if HAVE_SYS_TIME_H +#include +#endif + +#if HAVE_SYS_SOCKET_H +#include +#endif + +#if HAVE_NETINET_IN_H +#include +#endif + +#if HAVE_NETINET_TCP_H +#include +#endif + +#if HAVE_ARPA_INET_H +#include +#endif + +#if HAVE_LIMITS_H +#include +#endif + +#if HAVE_OPENMP +#include +#endif + +#if HAVE_IO_H +#include // _open(), _close(), read(), write() on windows +#endif + +#if HAVE_SIGNAL_H +#include +#endif + +/** Integer types */ +#if HAVE_STDINT_H +#include + +#else + +/* Assume GLIB types */ +typedef gint8 int8_t; +typedef guint8 uint8_t; +typedef gint16 int16_t; +typedef guint16 uint16_t; +typedef gint32 int32_t; +typedef guint32 uint32_t; +typedef gint64 int64_t; +typedef guint64 uint64_t; +typedef guintptr uintptr_t; +typedef gintptr intptr_t; + +#endif + +/* + * CYGWIN has its own version of , which can be + * safely included together with POSIX includes. + * Thanks to this, CYGWIN can also run audio output and MIDI + * input drivers from traditional interfaces of Windows. + */ +#if defined(__CYGWIN__) && HAVE_WINDOWS_H +#include +#include +#endif + +#if defined(_WIN32) && HAVE_WINDOWS_H +#include +#include /* Provides also socklen_t */ + +/* WIN32 special defines */ +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +#ifdef _MSC_VER +#pragma warning(disable : 4244) +#pragma warning(disable : 4101) +#pragma warning(disable : 4305) +#pragma warning(disable : 4996) +#endif + +#endif + +/* Darwin special defines (taken from config_macosx.h) */ +#ifdef DARWIN +# define MACINTOSH +# define __Types__ +#endif + +#ifdef LADSPA +#include +#endif + +/* #include */ + +/** + * Macro used for safely accessing a message from a GError and using a default + * message if it is NULL. + * @param err Pointer to a GError to access the message field of. + * @return Message string + */ +#define fluid_gerror_message(err) ((err) ? err->message : "No error details") + +#if defined(_WIN32) || defined(__CYGWIN__) +char* fluid_get_windows_error(void); +#endif + +#define FLUID_INLINE inline + +#define FLUID_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch)) + +/* Integer<->pointer conversion */ +#define FLUID_POINTER_TO_UINT(x) ((unsigned int)(uintptr_t)(x)) +#define FLUID_UINT_TO_POINTER(x) ((void *)(uintptr_t)(x)) +#define FLUID_POINTER_TO_INT(x) ((signed int)(intptr_t)(x)) +#define FLUID_INT_TO_POINTER(x) ((void *)(intptr_t)(x)) + +/* Endian detection */ +#define FLUID_IS_BIG_ENDIAN (G_BYTE_ORDER == G_BIG_ENDIAN) + +#define FLUID_LE32TOH(x) GINT32_FROM_LE(x) +#define FLUID_LE16TOH(x) GINT16_FROM_LE(x) + +#if FLUID_IS_BIG_ENDIAN +#define FLUID_FOURCC(_a, _b, _c, _d) \ + (uint32_t)(((uint32_t)(_a) << 24) | ((uint32_t)(_b) << 16) | ((uint32_t)(_c) << 8) | (uint32_t)(_d)) +#else +#define FLUID_FOURCC(_a, _b, _c, _d) \ + (uint32_t)(((uint32_t)(_d) << 24) | ((uint32_t)(_c) << 16) | ((uint32_t)(_b) << 8) | (uint32_t)(_a)) +#endif + +/* + * Utility functions + */ +char *fluid_strtok(char **str, char *delim); + +#define FLUID_FILE_TEST_EXISTS G_FILE_TEST_EXISTS +#define FLUID_FILE_TEST_IS_REGULAR G_FILE_TEST_IS_REGULAR +#define fluid_file_test(path, flags) g_file_test(path, flags) + +#define fluid_shell_parse_argv(command_line, argcp, argvp) g_shell_parse_argv(command_line, argcp, argvp, NULL) +#define fluid_strfreev g_strfreev + +#if defined(__OS2__) +#define INCL_DOS +#include + +/* Define socklen_t if not provided */ +#if !HAVE_SOCKLEN_T +typedef int socklen_t; +#endif +#endif + +/** + Time functions + + */ + +unsigned int fluid_curtime(void); +double fluid_utime(void); + + +/** + Timers + + */ + +/* if the callback function returns 1 the timer will continue; if it + returns 0 it will stop */ +typedef int (*fluid_timer_callback_t)(void *data, unsigned int msec); + +typedef struct _fluid_timer_t fluid_timer_t; + +fluid_timer_t *new_fluid_timer(int msec, fluid_timer_callback_t callback, + void *data, int new_thread, int auto_destroy, + int high_priority); + +void delete_fluid_timer(fluid_timer_t *timer); +int fluid_timer_join(fluid_timer_t *timer); +int fluid_timer_stop(fluid_timer_t *timer); +int fluid_timer_is_running(const fluid_timer_t *timer); +long fluid_timer_get_interval(const fluid_timer_t * timer); + +// Macros to use for pre-processor if statements to test which Glib thread API we have (pre or post 2.32) +#define NEW_GLIB_THREAD_API GLIB_CHECK_VERSION(2,32,0) +#define OLD_GLIB_THREAD_API !GLIB_CHECK_VERSION(2,32,0) + +/* Muteces */ + +#if NEW_GLIB_THREAD_API + +/* glib 2.32 and newer */ + +/* Regular mutex */ +typedef GMutex fluid_mutex_t; +#define FLUID_MUTEX_INIT { 0 } +#define fluid_mutex_init(_m) g_mutex_init (&(_m)) +#define fluid_mutex_destroy(_m) g_mutex_clear (&(_m)) +#define fluid_mutex_lock(_m) g_mutex_lock(&(_m)) +#define fluid_mutex_unlock(_m) g_mutex_unlock(&(_m)) + +/* Recursive lock capable mutex */ +typedef GRecMutex fluid_rec_mutex_t; +#define fluid_rec_mutex_init(_m) g_rec_mutex_init(&(_m)) +#define fluid_rec_mutex_destroy(_m) g_rec_mutex_clear(&(_m)) +#define fluid_rec_mutex_lock(_m) g_rec_mutex_lock(&(_m)) +#define fluid_rec_mutex_unlock(_m) g_rec_mutex_unlock(&(_m)) + +/* Dynamically allocated mutex suitable for fluid_cond_t use */ +typedef GMutex fluid_cond_mutex_t; +#define fluid_cond_mutex_lock(m) g_mutex_lock(m) +#define fluid_cond_mutex_unlock(m) g_mutex_unlock(m) + +static FLUID_INLINE fluid_cond_mutex_t * +new_fluid_cond_mutex(void) +{ + GMutex *mutex; + mutex = g_new(GMutex, 1); + g_mutex_init(mutex); + return (mutex); +} + +static FLUID_INLINE void +delete_fluid_cond_mutex(fluid_cond_mutex_t *m) +{ + fluid_return_if_fail(m != NULL); + g_mutex_clear(m); + g_free(m); +} + +/* Thread condition signaling */ +typedef GCond fluid_cond_t; +#define fluid_cond_signal(cond) g_cond_signal(cond) +#define fluid_cond_broadcast(cond) g_cond_broadcast(cond) +#define fluid_cond_wait(cond, mutex) g_cond_wait(cond, mutex) + +static FLUID_INLINE fluid_cond_t * +new_fluid_cond(void) +{ + GCond *cond; + cond = g_new(GCond, 1); + g_cond_init(cond); + return (cond); +} + +static FLUID_INLINE void +delete_fluid_cond(fluid_cond_t *cond) +{ + fluid_return_if_fail(cond != NULL); + g_cond_clear(cond); + g_free(cond); +} + +/* Thread private data */ + +#ifdef _WIN32 /* Wine-specific code */ + +typedef DWORD fluid_private_t; +#define fluid_private_init(_priv) (_priv = TlsAlloc()) +#define fluid_private_free(_priv) TlsFree(_priv); +#define fluid_private_get(_priv) TlsGetValue(_priv) +#define fluid_private_set(_priv, _data) TlsSetValue(_priv, _data) + +#else /* Wine-specific code */ + +typedef GPrivate fluid_private_t; +#define fluid_private_init(_priv) memset (&_priv, 0, sizeof (_priv)) +#define fluid_private_free(_priv) +#define fluid_private_get(_priv) g_private_get(&(_priv)) +#define fluid_private_set(_priv, _data) g_private_set(&(_priv), _data) + +#endif /* Wine-specific code */ + +#else + +/* glib prior to 2.32 */ + +/* Regular mutex */ +typedef GStaticMutex fluid_mutex_t; +#define FLUID_MUTEX_INIT G_STATIC_MUTEX_INIT +#define fluid_mutex_destroy(_m) g_static_mutex_free(&(_m)) +#define fluid_mutex_lock(_m) g_static_mutex_lock(&(_m)) +#define fluid_mutex_unlock(_m) g_static_mutex_unlock(&(_m)) + +#define fluid_mutex_init(_m) do { \ + if (!g_thread_supported ()) g_thread_init (NULL); \ + g_static_mutex_init (&(_m)); \ +} while(0) + +/* Recursive lock capable mutex */ +typedef GStaticRecMutex fluid_rec_mutex_t; +#define fluid_rec_mutex_destroy(_m) g_static_rec_mutex_free(&(_m)) +#define fluid_rec_mutex_lock(_m) g_static_rec_mutex_lock(&(_m)) +#define fluid_rec_mutex_unlock(_m) g_static_rec_mutex_unlock(&(_m)) + +#define fluid_rec_mutex_init(_m) do { \ + if (!g_thread_supported ()) g_thread_init (NULL); \ + g_static_rec_mutex_init (&(_m)); \ +} while(0) + +/* Dynamically allocated mutex suitable for fluid_cond_t use */ +typedef GMutex fluid_cond_mutex_t; +#define delete_fluid_cond_mutex(m) g_mutex_free(m) +#define fluid_cond_mutex_lock(m) g_mutex_lock(m) +#define fluid_cond_mutex_unlock(m) g_mutex_unlock(m) + +static FLUID_INLINE fluid_cond_mutex_t * +new_fluid_cond_mutex(void) +{ + if(!g_thread_supported()) + { + g_thread_init(NULL); + } + + return g_mutex_new(); +} + +/* Thread condition signaling */ +typedef GCond fluid_cond_t; +fluid_cond_t *new_fluid_cond(void); +#define delete_fluid_cond(cond) g_cond_free(cond) +#define fluid_cond_signal(cond) g_cond_signal(cond) +#define fluid_cond_broadcast(cond) g_cond_broadcast(cond) +#define fluid_cond_wait(cond, mutex) g_cond_wait(cond, mutex) + +/* Thread private data */ +typedef GStaticPrivate fluid_private_t; +#define fluid_private_get(_priv) g_static_private_get(&(_priv)) +#define fluid_private_set(_priv, _data) g_static_private_set(&(_priv), _data, NULL) +#define fluid_private_free(_priv) g_static_private_free(&(_priv)) + +#define fluid_private_init(_priv) do { \ + if (!g_thread_supported ()) g_thread_init (NULL); \ + g_static_private_init (&(_priv)); \ +} while(0) + +#endif + + +/* Atomic operations */ + +#define fluid_atomic_int_inc(_pi) g_atomic_int_inc(_pi) +#define fluid_atomic_int_get(_pi) g_atomic_int_get(_pi) +#define fluid_atomic_int_set(_pi, _val) g_atomic_int_set(_pi, _val) +#define fluid_atomic_int_dec_and_test(_pi) g_atomic_int_dec_and_test(_pi) +#define fluid_atomic_int_compare_and_exchange(_pi, _old, _new) \ + g_atomic_int_compare_and_exchange(_pi, _old, _new) + +#if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 30) +#define fluid_atomic_int_exchange_and_add(_pi, _add) \ + g_atomic_int_add(_pi, _add) +#define fluid_atomic_int_add(_pi, _add) \ + g_atomic_int_add(_pi, _add) +#else +#define fluid_atomic_int_exchange_and_add(_pi, _add) \ + g_atomic_int_exchange_and_add(_pi, _add) +#define fluid_atomic_int_add(_pi, _add) \ + g_atomic_int_exchange_and_add(_pi, _add) +#endif + +#define fluid_atomic_pointer_get(_pp) g_atomic_pointer_get(_pp) +#define fluid_atomic_pointer_set(_pp, val) g_atomic_pointer_set(_pp, val) +#define fluid_atomic_pointer_compare_and_exchange(_pp, _old, _new) \ + g_atomic_pointer_compare_and_exchange(_pp, _old, _new) + +static FLUID_INLINE void +fluid_atomic_float_set(fluid_atomic_float_t *fptr, float val) +{ + int32_t ival; + memcpy(&ival, &val, 4); + fluid_atomic_int_set((fluid_atomic_int_t *)fptr, ival); +} + +static FLUID_INLINE float +fluid_atomic_float_get(fluid_atomic_float_t *fptr) +{ + int32_t ival; + float fval; + ival = fluid_atomic_int_get((fluid_atomic_int_t *)fptr); + memcpy(&fval, &ival, 4); + return fval; +} + + +/* Threads */ + +/* other thread implementations might change this for their needs */ +typedef void *fluid_thread_return_t; +/* static return value for thread functions which requires a return value */ +#define FLUID_THREAD_RETURN_VALUE (NULL) + +typedef GThread fluid_thread_t; +typedef fluid_thread_return_t (*fluid_thread_func_t)(void *data); + +#define FLUID_THREAD_ID_NULL NULL /* A NULL "ID" value */ +#define fluid_thread_id_t GThread * /* Data type for a thread ID */ +#define fluid_thread_get_id() g_thread_self() /* Get unique "ID" for current thread */ + +fluid_thread_t *new_fluid_thread(const char *name, fluid_thread_func_t func, void *data, + int prio_level, int detach); +void delete_fluid_thread(fluid_thread_t *thread); +void fluid_thread_self_set_prio(int prio_level); +int fluid_thread_join(fluid_thread_t *thread); + +/* Dynamic Module Loading, currently only used by LADSPA subsystem */ +#ifdef LADSPA + +typedef GModule fluid_module_t; + +#define fluid_module_open(_name) g_module_open((_name), G_MODULE_BIND_LOCAL) +#define fluid_module_close(_mod) g_module_close(_mod) +#define fluid_module_error() g_module_error() +#define fluid_module_name(_mod) g_module_name(_mod) +#define fluid_module_symbol(_mod, _name, _ptr) g_module_symbol((_mod), (_name), (_ptr)) + +#endif /* LADSPA */ + +/* Sockets and I/O */ + +int fluid_istream_readline(fluid_istream_t in, fluid_ostream_t out, char *prompt, char *buf, int len); +int fluid_ostream_printf(fluid_ostream_t out, const char *format, ...); + +#if defined(_WIN32) +typedef SOCKET fluid_socket_t; +#else +typedef int fluid_socket_t; +#endif + +/* The function should return 0 if no error occurred, non-zero + otherwise. If the function return non-zero, the socket will be + closed by the server. */ +typedef int (*fluid_server_func_t)(void *data, fluid_socket_t client_socket, char *addr); + +fluid_server_socket_t *new_fluid_server_socket(int port, fluid_server_func_t func, void *data); +void delete_fluid_server_socket(fluid_server_socket_t *sock); +int fluid_server_socket_join(fluid_server_socket_t *sock); +void fluid_socket_close(fluid_socket_t sock); +fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock); +fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock); + +/* File access */ +#define fluid_stat(_filename, _statbuf) g_stat((_filename), (_statbuf)) +#if !GLIB_CHECK_VERSION(2, 26, 0) + /* GStatBuf has not been introduced yet, manually typedef to what they had at that time: + * https://github.com/GNOME/glib/blob/e7763678b56e3be073cc55d707a6e92fc2055ee0/glib/gstdio.h#L98-L115 + */ + #if defined(_WIN32) || HAVE_WINDOWS_H // somehow reliably mock G_OS_WIN32?? + // Any effort from our side to reliably mock GStatBuf on Windows is in vain. E.g. glib-2.16 is broken as it uses struct stat rather than struct _stat32 on Win x86. + // Disable it (the user has been warned by cmake). + #undef fluid_stat + #define fluid_stat(_filename, _statbuf) (-1) + typedef struct _fluid_stat_buf_t{int st_mtime;} fluid_stat_buf_t; + #else + /* posix, OS/2, etc. */ + typedef struct stat fluid_stat_buf_t; + #endif +#else +typedef GStatBuf fluid_stat_buf_t; +#endif + +FILE* fluid_file_open(const char* filename, const char** errMsg); +fluid_long_long_t fluid_file_tell(FILE* f); + + +/* Profiling */ +#if WITH_PROFILING +/** profiling interface between Profiling command shell and Audio + rendering API (FluidProfile_0004.pdf- 3.2.2) +*/ + +/* + ----------------------------------------------------------------------------- + Shell task side | Profiling interface | Audio task side + ----------------------------------------------------------------------------- + profiling | Internal | | | Audio + command <---> |<-- profiling -->| Data |<--macros -->| <--> rendering + shell | API | | | API + +*/ + +/* default parameters for shell command "prof_start" in fluid_sys.c */ +#define FLUID_PROFILE_DEFAULT_BANK 0 /* default bank */ +#define FLUID_PROFILE_DEFAULT_PROG 16 /* default prog (organ) */ +#define FLUID_PROFILE_FIRST_KEY 12 /* first key generated */ +#define FLUID_PROFILE_LAST_KEY 108 /* last key generated */ +#define FLUID_PROFILE_DEFAULT_VEL 64 /* default note velocity */ +#define FLUID_PROFILE_VOICE_ATTEN -0.04f /* gain attenuation per voice (dB) */ + + +#define FLUID_PROFILE_DEFAULT_PRINT 0 /* default print mode */ +#define FLUID_PROFILE_DEFAULT_N_PROF 1 /* default number of measures */ +#define FLUID_PROFILE_DEFAULT_DURATION 500 /* default duration (ms) */ + + +extern unsigned short fluid_profile_notes; /* number of generated notes */ +extern unsigned char fluid_profile_bank; /* bank,prog preset used by */ +extern unsigned char fluid_profile_prog; /* generated notes */ +extern unsigned char fluid_profile_print; /* print mode */ + +extern unsigned short fluid_profile_n_prof;/* number of measures */ +extern unsigned short fluid_profile_dur; /* measure duration in ms */ +extern fluid_atomic_int_t fluid_profile_lock ; /* lock between multiple shell */ +/**/ + +/*---------------------------------------------- + Internal profiling API (in fluid_sys.c) +-----------------------------------------------*/ +/* Starts a profiling measure used in shell command "prof_start" */ +void fluid_profile_start_stop(unsigned int end_ticks, short clear_data); + +/* Returns status used in shell command "prof_start" */ +int fluid_profile_get_status(void); + +/* Prints profiling data used in shell command "prof_start" */ +void fluid_profiling_print_data(double sample_rate, fluid_ostream_t out); + +/* Returns True if profiling cancellation has been requested */ +int fluid_profile_is_cancel_req(void); + +/* For OS that implement key for profile cancellation: + 1) Adds #define FLUID_PROFILE_CANCEL + 2) Adds the necessary code inside fluid_profile_is_cancel() see fluid_sys.c +*/ +#if defined(_WIN32) /* Profile cancellation is supported for Windows */ +#define FLUID_PROFILE_CANCEL + +#elif defined(__OS2__) /* OS/2 specific stuff */ +/* Profile cancellation isn't yet supported for OS2 */ + +#else /* POSIX stuff */ +#define FLUID_PROFILE_CANCEL /* Profile cancellation is supported for linux */ +#include /* STDIN_FILENO */ +#include /* select() */ +#endif /* posix */ + +/* logging profiling data (used on synthesizer instance deletion) */ +void fluid_profiling_print(void); + +/*---------------------------------------------- + Profiling Data (in fluid_sys.c) +-----------------------------------------------*/ +/** Profiling data. Keep track of min/avg/max values to profile a + piece of code. */ +typedef struct _fluid_profile_data_t +{ + const char *description; /* name of the piece of code under profiling */ + double min, max, total; /* duration (microsecond) */ + unsigned int count; /* total count */ + unsigned int n_voices; /* voices number */ + unsigned int n_samples; /* audio samples number */ +} fluid_profile_data_t; + +enum +{ + /* commands/status (profiling interface) */ + PROFILE_STOP, /* command to stop a profiling measure */ + PROFILE_START, /* command to start a profile measure */ + PROFILE_READY, /* status to signal that a profiling measure has finished + and ready to be printed */ + /*- State returned by fluid_profile_get_status() -*/ + /* between profiling commands and internal profiling API */ + PROFILE_RUNNING, /* a profiling measure is running */ + PROFILE_CANCELED,/* a profiling measure has been canceled */ +}; + +/* Data interface */ +extern unsigned char fluid_profile_status ; /* command and status */ +extern unsigned int fluid_profile_end_ticks; /* ending position (in ticks) */ +extern fluid_profile_data_t fluid_profile_data[]; /* Profiling data */ + +/*---------------------------------------------- + Probes macros +-----------------------------------------------*/ +/** Macro to obtain a time reference used for the profiling */ +#define fluid_profile_ref() fluid_utime() + +/** Macro to create a variable and assign the current reference time for profiling. + * So we don't get unused variable warnings when profiling is disabled. */ +#define fluid_profile_ref_var(name) double name = fluid_utime() + +/** + * Profile identifier numbers. List all the pieces of code you want to profile + * here. Be sure to add an entry in the fluid_profile_data table in + * fluid_sys.c + */ +enum +{ + FLUID_PROF_WRITE, + FLUID_PROF_ONE_BLOCK, + FLUID_PROF_ONE_BLOCK_CLEAR, + FLUID_PROF_ONE_BLOCK_VOICE, + FLUID_PROF_ONE_BLOCK_VOICES, + FLUID_PROF_ONE_BLOCK_REVERB, + FLUID_PROF_ONE_BLOCK_CHORUS, + FLUID_PROF_VOICE_NOTE, + FLUID_PROF_VOICE_RELEASE, + FLUID_PROFILE_NBR /* number of profile probes */ +}; +/** Those macros are used to calculate the min/avg/max. Needs a profile number, a + time reference, the voices and samples number. */ + +/* local macro : acquiere data */ +#define fluid_profile_data(_num, _ref, voices, samples)\ +{\ + double _now = fluid_utime();\ + double _delta = _now - _ref;\ + fluid_profile_data[_num].min = _delta < fluid_profile_data[_num].min ?\ + _delta : fluid_profile_data[_num].min; \ + fluid_profile_data[_num].max = _delta > fluid_profile_data[_num].max ?\ + _delta : fluid_profile_data[_num].max;\ + fluid_profile_data[_num].total += _delta;\ + fluid_profile_data[_num].count++;\ + fluid_profile_data[_num].n_voices += voices;\ + fluid_profile_data[_num].n_samples += samples;\ + _ref = _now;\ +} + +/** Macro to collect data, called from inner functions inside audio + rendering API */ +#define fluid_profile(_num, _ref, voices, samples)\ +{\ + if ( fluid_profile_status == PROFILE_START)\ + { /* acquires data */\ + fluid_profile_data(_num, _ref, voices, samples)\ + }\ +} + +/** Macro to collect data, called from audio rendering API (fluid_write_xxxx()). + This macro control profiling ending position (in ticks). +*/ +#define fluid_profile_write(_num, _ref, voices, samples)\ +{\ + if (fluid_profile_status == PROFILE_START)\ + {\ + /* acquires data first: must be done before checking that profile is + finished to ensure at least one valid data sample. + */\ + fluid_profile_data(_num, _ref, voices, samples)\ + if (fluid_synth_get_ticks(synth) >= fluid_profile_end_ticks)\ + {\ + /* profiling is finished */\ + fluid_profile_status = PROFILE_READY;\ + }\ + }\ +} + +#else + +/* No profiling */ +#define fluid_profiling_print() +#define fluid_profile_ref() 0 +#define fluid_profile_ref_var(name) +#define fluid_profile(_num,_ref,voices, samples) +#define fluid_profile_write(_num,_ref, voices, samples) +#endif /* WITH_PROFILING */ + +/** + + Memory locking + + Memory locking is used to avoid swapping of the large block of + sample data. + */ + +#if defined(HAVE_SYS_MMAN_H) && !defined(__OS2__) +#define fluid_mlock(_p,_n) mlock(_p, _n) +#define fluid_munlock(_p,_n) munlock(_p,_n) +#else +#define fluid_mlock(_p,_n) 0 +#define fluid_munlock(_p,_n) +#endif + + +/** + + Floating point exceptions + + fluid_check_fpe() checks for "unnormalized numbers" and other + exceptions of the floating point processor. +*/ +#ifdef FPE_CHECK +#define fluid_check_fpe(expl) fluid_check_fpe_i386(expl) +#define fluid_clear_fpe() fluid_clear_fpe_i386() +unsigned int fluid_check_fpe_i386(char *explanation_in_case_of_fpe); +void fluid_clear_fpe_i386(void); +#else +#define fluid_check_fpe(expl) +#define fluid_clear_fpe() +#endif + + +/* System control */ +void fluid_msleep(unsigned int msecs); + +/** + * Advances the given \c ptr to the next \c alignment byte boundary. + * Make sure you've allocated an extra of \c alignment bytes to avoid a buffer overflow. + * + * @note \c alignment must be a power of two + * @return Returned pointer is guaranteed to be aligned to \c alignment boundary and in range \f[ ptr <= returned_ptr < ptr + alignment \f]. + */ +static FLUID_INLINE void *fluid_align_ptr(const void *ptr, unsigned int alignment) +{ + uintptr_t ptr_int = (uintptr_t)ptr; + unsigned int offset = ptr_int & (alignment - 1); + unsigned int add = (alignment - offset) & (alignment - 1); // advance the pointer to the next alignment boundary + ptr_int += add; + + /* assert alignment is power of two */ + FLUID_ASSERT(!(alignment == 0) && !(alignment & (alignment - 1))); + + return (void *)ptr_int; +} + +#define FLUID_DEFAULT_ALIGNMENT (64U) + +#endif /* _FLUID_SYS_H */ diff --git a/libs/fluidsynth/src/utils/fluidsynth_priv.h b/libs/fluidsynth/src/utils/fluidsynth_priv.h new file mode 100644 index 00000000000..843c0143475 --- /dev/null +++ b/libs/fluidsynth/src/utils/fluidsynth_priv.h @@ -0,0 +1,331 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * + * 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 Street, Fifth Floor, Boston, MA + * 02110-1301, USA + */ + +/* + * @file fluidsynth_priv.h + * + * lightweight part of fluid_sys.h, containing forward declarations of fluidsynth's private types and private macros + * + * include this one file in fluidsynth's private header files + */ + +#ifndef _FLUIDSYNTH_PRIV_H +#define _FLUIDSYNTH_PRIV_H + +#include "config.h" + +#include + +#if HAVE_STDLIB_H +#include // malloc, free +#endif + +#if HAVE_STDIO_H +#include // printf +#endif + +#if HAVE_STRING_H +#include +#endif + +#if HAVE_STRINGS_H +#include +#endif + +#include "fluidsynth.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************** + * + * BASIC TYPES + */ + +#if defined(WITH_FLOAT) +typedef float fluid_real_t; +#else +typedef double fluid_real_t; +#endif + +#if defined(SUPPORTS_VLA) +# define FLUID_DECLARE_VLA(_type, _name, _len) \ + _type _name[_len] +#else +# define FLUID_DECLARE_VLA(_type, _name, _len) \ + _type* _name = g_newa(_type, (_len)) +#endif + + +/** Atomic types */ +typedef int fluid_atomic_int_t; +typedef unsigned int fluid_atomic_uint_t; +typedef float fluid_atomic_float_t; + + +/*************************************************************** + * + * FORWARD DECLARATIONS + */ +typedef struct _fluid_env_data_t fluid_env_data_t; +typedef struct _fluid_adriver_definition_t fluid_adriver_definition_t; +typedef struct _fluid_channel_t fluid_channel_t; +typedef struct _fluid_tuning_t fluid_tuning_t; +typedef struct _fluid_hashtable_t fluid_hashtable_t; +typedef struct _fluid_client_t fluid_client_t; +typedef struct _fluid_server_socket_t fluid_server_socket_t; +typedef struct _fluid_sample_timer_t fluid_sample_timer_t; +typedef struct _fluid_zone_range_t fluid_zone_range_t; +typedef struct _fluid_rvoice_eventhandler_t fluid_rvoice_eventhandler_t; + +/* Declare rvoice related typedefs here instead of fluid_rvoice.h, as it's needed + * in fluid_lfo.c and fluid_adsr.c as well */ +typedef union _fluid_rvoice_param_t +{ + void *ptr; + int i; + fluid_real_t real; +} fluid_rvoice_param_t; +enum { MAX_EVENT_PARAMS = 7 }; /**< Maximum number of #fluid_rvoice_param_t to be passed to an #fluid_rvoice_function_t */ +typedef void (*fluid_rvoice_function_t)(void *obj, const fluid_rvoice_param_t param[MAX_EVENT_PARAMS]); + +/* Macro for declaring an rvoice event function (#fluid_rvoice_function_t). The functions may only access + * those params that were previously set in fluid_voice.c + */ +#define DECLARE_FLUID_RVOICE_FUNCTION(name) void name(void* obj, const fluid_rvoice_param_t param[MAX_EVENT_PARAMS]) + + +/*************************************************************** + * + * CONSTANTS + */ + +#define FLUID_BUFSIZE 64 /**< FluidSynth internal buffer size (in samples) */ +#define FLUID_MIXER_MAX_BUFFERS_DEFAULT (8192/FLUID_BUFSIZE) /**< Number of buffers that can be processed in one rendering run */ +#define FLUID_MAX_EVENTS_PER_BUFSIZE 1024 /**< Maximum queued MIDI events per #FLUID_BUFSIZE */ +#define FLUID_MAX_RETURN_EVENTS 1024 /**< Maximum queued synthesis thread return events */ +#define FLUID_MAX_EVENT_QUEUES 16 /**< Maximum number of unique threads queuing events */ +#define FLUID_DEFAULT_AUDIO_RT_PRIO 60 /**< Default setting for audio.realtime-prio */ +#define FLUID_DEFAULT_MIDI_RT_PRIO 50 /**< Default setting for midi.realtime-prio */ +#define FLUID_NUM_MOD 64 /**< Maximum number of modulators in a voice */ + +/*************************************************************** + * + * SYSTEM INTERFACE + */ + +/* Math constants */ +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795 +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530941723212145818 +#endif + +#ifndef M_LN10 +#define M_LN10 2.3025850929940456840179914546844 +#endif + +#define FLUID_M_PI ((fluid_real_t)M_PI) +#define FLUID_M_LN2 ((fluid_real_t)M_LN2) +#define FLUID_M_LN10 ((fluid_real_t)M_LN10) + +/* Math functions */ +#if defined WITH_FLOAT && defined HAVE_SINF +#define FLUID_SIN sinf +#else +#define FLUID_SIN (fluid_real_t)sin +#endif + +#if defined WITH_FLOAT && defined HAVE_COSF +#define FLUID_COS cosf +#else +#define FLUID_COS (fluid_real_t)cos +#endif + +#if defined WITH_FLOAT && defined HAVE_FABSF +#define FLUID_FABS fabsf +#else +#define FLUID_FABS (fluid_real_t)fabs +#endif + +#if defined WITH_FLOAT && defined HAVE_POWF +#define FLUID_POW powf +#else +#define FLUID_POW (fluid_real_t)pow +#endif + +#if defined WITH_FLOAT && defined HAVE_SQRTF +#define FLUID_SQRT sqrtf +#else +#define FLUID_SQRT (fluid_real_t)sqrt +#endif + +#if defined WITH_FLOAT && defined HAVE_LOGF +#define FLUID_LOGF logf +#else +#define FLUID_LOGF (fluid_real_t)log +#endif + +/* Memory allocation */ +#define FLUID_MALLOC(_n) fluid_alloc(_n) +#define FLUID_REALLOC(_p,_n) realloc(_p,_n) +#define FLUID_FREE(_p) fluid_free(_p) +#define FLUID_NEW(_t) (_t*)FLUID_MALLOC(sizeof(_t)) +#define FLUID_ARRAY_ALIGNED(_t,_n,_a) (_t*)FLUID_MALLOC((_n)*sizeof(_t) + ((unsigned int)_a - 1u)) +#define FLUID_ARRAY(_t,_n) FLUID_ARRAY_ALIGNED(_t,_n,1u) + +void* fluid_alloc(size_t len); + +/* File access */ +#define FLUID_FOPEN(_f,_m) fluid_fopen(_f,_m) +#define FLUID_FCLOSE(_f) fclose(_f) +#define FLUID_FREAD(_p,_s,_n,_f) fread(_p,_s,_n,_f) + +FILE *fluid_fopen(const char *filename, const char *mode); + +#ifdef _WIN32 +#define FLUID_FSEEK(_f,_n,_set) _fseeki64(_f,_n,_set) +#else +#define FLUID_FSEEK(_f,_n,_set) fseek(_f,_n,_set) +#endif + +#define FLUID_FTELL(_f) fluid_file_tell(_f) + +/* Memory functions */ +#define FLUID_MEMCPY(_dst,_src,_n) memcpy(_dst,_src,_n) +#define FLUID_MEMSET(_s,_c,_n) memset(_s,_c,_n) + +/* String functions */ +#define FLUID_STRLEN(_s) strlen(_s) +#define FLUID_STRCMP(_s,_t) strcmp(_s,_t) +#define FLUID_STRNCMP(_s,_t,_n) strncmp(_s,_t,_n) +#define FLUID_STRCPY(_dst,_src) strcpy(_dst,_src) +#define FLUID_STRTOL(_s,_e,_b) strtol(_s,_e,_b) + +#define FLUID_STRNCPY(_dst,_src,_n) \ +do { strncpy(_dst,_src,_n-1); \ + (_dst)[(_n)-1]='\0'; \ +}while(0) + +#define FLUID_STRCHR(_s,_c) strchr(_s,_c) +#define FLUID_STRRCHR(_s,_c) strrchr(_s,_c) + +#ifdef strdup +#define FLUID_STRDUP(s) strdup(s) +#else +#define FLUID_STRDUP(s) FLUID_STRCPY(FLUID_MALLOC(FLUID_STRLEN(s) + 1), s) +#endif + +#define FLUID_SPRINTF sprintf +#define FLUID_FPRINTF fprintf + +#if (defined(_WIN32) && _MSC_VER < 1900) || defined(MINGW32) +/* need to make sure we use a C99 compliant implementation of (v)snprintf(), + * i.e. not microsofts non compliant extension _snprintf() as it doesn't + * reliably null-terminate the buffer + */ +#define FLUID_SNPRINTF g_snprintf +#else +#define FLUID_SNPRINTF snprintf +#endif + +#if (defined(_WIN32) && _MSC_VER < 1500) || defined(MINGW32) +#define FLUID_VSNPRINTF g_vsnprintf +#else +#define FLUID_VSNPRINTF vsnprintf +#endif + +#if defined(_WIN32) && !defined(MINGW32) +#define FLUID_STRCASECMP _stricmp +#else +#define FLUID_STRCASECMP strcasecmp +#endif + +#if defined(_WIN32) && !defined(MINGW32) +#define FLUID_STRNCASECMP _strnicmp +#else +#define FLUID_STRNCASECMP strncasecmp +#endif + + +#define fluid_clip(_val, _min, _max) \ +{ (_val) = ((_val) < (_min))? (_min) : (((_val) > (_max))? (_max) : (_val)); } + +#if WITH_FTS +#define FLUID_PRINTF post +#define FLUID_FLUSH() +#else +#define FLUID_PRINTF printf +#define FLUID_FLUSH() fflush(stdout) +#endif + +/* People who want to reduce the size of the may do this by entirely + * removing the logging system. This will cause all log messages to + * be discarded at compile time, allowing to save about 80 KiB for + * the compiled binary. + */ +#if 0 +#define FLUID_LOG (void)sizeof +#else +#define FLUID_LOG fluid_log +#endif + +#if defined(DEBUG) && !defined(NDEBUG) +#define FLUID_ASSERT(a) g_assert(a) +#else +#define FLUID_ASSERT(a) +#endif + +#define FLUID_LIKELY G_LIKELY +#define FLUID_UNLIKELY G_UNLIKELY + +/* Misc */ +#if defined(__INTEL_COMPILER) +#define FLUID_RESTRICT restrict +#elif defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) +#define FLUID_RESTRICT __restrict__ +#elif defined(_MSC_VER) && _MSC_VER >= 1400 +#define FLUID_RESTRICT __restrict +#else +#warning "Dont know how this compiler handles restrict pointers, refuse to use them." +#define FLUID_RESTRICT +#endif + +#define FLUID_N_ELEMENTS(struct) (sizeof (struct) / sizeof (struct[0])) +#define FLUID_MEMBER_SIZE(struct, member) ( sizeof (((struct *)0)->member) ) + + +#define fluid_return_if_fail(cond) \ +if(cond) \ + ; \ +else \ + return + +#define fluid_return_val_if_fail(cond, val) \ + fluid_return_if_fail(cond) (val) + +#ifdef __cplusplus +} +#endif + +#endif /* _FLUIDSYNTH_PRIV_H */ From 2fd034812504e632e393c4940f7c69a16886266a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 8 Sep 2023 10:05:28 +0200 Subject: [PATCH 2617/2777] fluidsynth: Use Wine debugging facility for traces. (cherry picked from commit b5903214ab6f564acadaee5c4c934f8a72e442c5) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- libs/fluidsynth/src/utils/fluid_sys.c | 2 +- libs/fluidsynth/src/utils/fluidsynth_priv.h | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/libs/fluidsynth/src/utils/fluid_sys.c b/libs/fluidsynth/src/utils/fluid_sys.c index e94123022b2..0f8e6a608fc 100644 --- a/libs/fluidsynth/src/utils/fluid_sys.c +++ b/libs/fluidsynth/src/utils/fluid_sys.c @@ -640,7 +640,7 @@ void fluid_profiling_print(void) { int i; - printf("fluid_profiling_print\n"); + FLUID_LOG(FLUID_INFO, "fluid_profiling_print\n"); FLUID_LOG(FLUID_INFO, "Estimated times: min/avg/max (micro seconds)"); diff --git a/libs/fluidsynth/src/utils/fluidsynth_priv.h b/libs/fluidsynth/src/utils/fluidsynth_priv.h index 843c0143475..1191ac59595 100644 --- a/libs/fluidsynth/src/utils/fluidsynth_priv.h +++ b/libs/fluidsynth/src/utils/fluidsynth_priv.h @@ -51,6 +51,10 @@ #include "fluidsynth.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(fluidsynth); + #ifdef __cplusplus extern "C" { #endif @@ -275,8 +279,8 @@ do { strncpy(_dst,_src,_n-1); \ #define FLUID_PRINTF post #define FLUID_FLUSH() #else -#define FLUID_PRINTF printf -#define FLUID_FLUSH() fflush(stdout) +#define FLUID_PRINTF WINE_TRACE +#define FLUID_FLUSH() #endif /* People who want to reduce the size of the may do this by entirely @@ -287,7 +291,12 @@ do { strncpy(_dst,_src,_n-1); \ #if 0 #define FLUID_LOG (void)sizeof #else -#define FLUID_LOG fluid_log +#define WINE_FLUID_DBG WINE_TRACE +#define WINE_FLUID_INFO WINE_TRACE +#define WINE_FLUID_WARN WINE_WARN +#define WINE_FLUID_ERR WINE_ERR +#define WINE_FLUID_PANIC WINE_ERR +#define FLUID_LOG( x, msg, ... ) do { WINE_ ## x( msg, ## __VA_ARGS__ ); WINE_ ## x( "\n" ); } while (0) #endif #if defined(DEBUG) && !defined(NDEBUG) From a1533ec39b116a498a2756f56f73710b628981b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 8 Sep 2023 09:10:04 +0200 Subject: [PATCH 2618/2777] dmsynth: Simplify IDirectMusicSynth8_Open checks. (cherry picked from commit fcc8a1be68d414ae037d555f77bb80de2d10a6b8) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 126 +++++++++++++++++++++---------------------- 1 file changed, 60 insertions(+), 66 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 2b5a0905685..6582a9931e9 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -316,85 +316,79 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) static HRESULT WINAPI synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *params) { struct synth *This = impl_from_IDirectMusicSynth8(iface); - BOOL modified = FALSE; - const DMUS_PORTPARAMS def = { - .dwValidParams = DMUS_PORTPARAMS_VOICES|DMUS_PORTPARAMS_CHANNELGROUPS| - DMUS_PORTPARAMS_AUDIOCHANNELS|DMUS_PORTPARAMS_SAMPLERATE|DMUS_PORTPARAMS_EFFECTS| - DMUS_PORTPARAMS_SHARE|DMUS_PORTPARAMS_FEATURES, - .dwSize = sizeof(def), .dwVoices = 32, .dwChannelGroups = 2, .dwAudioChannels = 2, - .dwSampleRate = 22050, .dwEffectFlags = DMUS_EFFECT_REVERB + DMUS_PORTPARAMS actual = + { + .dwSize = sizeof(DMUS_PORTPARAMS), + .dwValidParams = DMUS_PORTPARAMS_VOICES | DMUS_PORTPARAMS_CHANNELGROUPS + | DMUS_PORTPARAMS_AUDIOCHANNELS | DMUS_PORTPARAMS_SAMPLERATE + | DMUS_PORTPARAMS_EFFECTS | DMUS_PORTPARAMS_SHARE | DMUS_PORTPARAMS_FEATURES, + .dwVoices = 32, + .dwChannelGroups = 2, + .dwAudioChannels = 2, + .dwSampleRate = 22050, + .dwEffectFlags = DMUS_EFFECT_REVERB, }; + UINT size = sizeof(DMUS_PORTPARAMS); + BOOL modified = FALSE; TRACE("(%p, %p)\n", This, params); - if (This->open) - return DMUS_E_ALREADYOPEN; - if (params && params->dwSize < sizeof(DMUS_PORTPARAMS7)) - return E_INVALIDARG; + if (This->open) return DMUS_E_ALREADYOPEN; - This->open = TRUE; + if (params) + { + if (params->dwSize < sizeof(DMUS_PORTPARAMS7)) return E_INVALIDARG; + if (size > params->dwSize) size = params->dwSize; - if (!params) { - memcpy(&This->params, &def, sizeof(This->params)); - return S_OK; - } + if ((params->dwValidParams & DMUS_PORTPARAMS_VOICES) && params->dwVoices) + { + actual.dwVoices = min(params->dwVoices, This->caps.dwMaxVoices); + modified |= actual.dwVoices != params->dwVoices; + } - if (params->dwValidParams & DMUS_PORTPARAMS_VOICES && params->dwVoices) { - if (params->dwVoices > This->caps.dwMaxVoices) { - modified = TRUE; - params->dwVoices = This->caps.dwMaxVoices; + if ((params->dwValidParams & DMUS_PORTPARAMS_CHANNELGROUPS) && params->dwChannelGroups) + { + actual.dwChannelGroups = min(params->dwChannelGroups, This->caps.dwMaxChannelGroups); + modified |= actual.dwChannelGroups != params->dwChannelGroups; } - } else - params->dwVoices = def.dwVoices; - if (params->dwValidParams & DMUS_PORTPARAMS_CHANNELGROUPS && params->dwChannelGroups) { - if (params->dwChannelGroups > This->caps.dwMaxChannelGroups) { - modified = TRUE; - params->dwChannelGroups = This->caps.dwMaxChannelGroups; + if ((params->dwValidParams & DMUS_PORTPARAMS_AUDIOCHANNELS) && params->dwAudioChannels) + { + actual.dwAudioChannels = min(params->dwAudioChannels, This->caps.dwMaxAudioChannels); + modified |= actual.dwAudioChannels != params->dwAudioChannels; } - } else - params->dwChannelGroups = def.dwChannelGroups; - if (params->dwValidParams & DMUS_PORTPARAMS_AUDIOCHANNELS && params->dwAudioChannels) { - if (params->dwAudioChannels > This->caps.dwMaxAudioChannels) { - modified = TRUE; - params->dwAudioChannels = This->caps.dwMaxAudioChannels; + if ((params->dwValidParams & DMUS_PORTPARAMS_SAMPLERATE) && params->dwSampleRate) + { + actual.dwSampleRate = min(max(params->dwSampleRate, 11025), 96000); + modified |= actual.dwSampleRate != params->dwSampleRate; } - } else - params->dwAudioChannels = def.dwAudioChannels; - - if (params->dwValidParams & DMUS_PORTPARAMS_SAMPLERATE && params->dwSampleRate) { - if (params->dwSampleRate > 96000) { - modified = TRUE; - params->dwSampleRate = 96000; - } else if (params->dwSampleRate < 11025) { - modified = TRUE; - params->dwSampleRate = 11025; + + if (params->dwValidParams & DMUS_PORTPARAMS_EFFECTS) + { + actual.dwEffectFlags = DMUS_EFFECT_REVERB; + modified |= actual.dwEffectFlags != params->dwEffectFlags; + } + + if (params->dwValidParams & DMUS_PORTPARAMS_SHARE) + { + actual.fShare = FALSE; + modified |= actual.fShare != params->fShare; + } + + if (params->dwSize < sizeof(*params)) + actual.dwValidParams &= ~DMUS_PORTPARAMS_FEATURES; + else if ((params->dwValidParams & DMUS_PORTPARAMS_FEATURES) && params->dwFeatures) + { + actual.dwFeatures = params->dwFeatures & (DMUS_PORT_FEATURE_AUDIOPATH | DMUS_PORT_FEATURE_STREAMING); + modified |= actual.dwFeatures != params->dwFeatures; } - } else - params->dwSampleRate = def.dwSampleRate; - - if (params->dwValidParams & DMUS_PORTPARAMS_EFFECTS && params->dwEffectFlags != def.dwEffectFlags) - modified = TRUE; - params->dwEffectFlags = def.dwEffectFlags; - - if (params->dwValidParams & DMUS_PORTPARAMS_SHARE && params->fShare) - modified = TRUE; - params->fShare = FALSE; - - if (params->dwSize >= sizeof(*params)) { - if (params->dwValidParams & DMUS_PORTPARAMS_FEATURES && params->dwFeatures) { - if (params->dwFeatures & ~(DMUS_PORT_FEATURE_AUDIOPATH|DMUS_PORT_FEATURE_STREAMING)) { - modified = TRUE; - params->dwFeatures &= DMUS_PORT_FEATURE_AUDIOPATH|DMUS_PORT_FEATURE_STREAMING; - } - } else - params->dwFeatures = def.dwFeatures; - params->dwValidParams = def.dwValidParams; - } else - params->dwValidParams = def.dwValidParams & ~DMUS_PORTPARAMS_FEATURES; - - memcpy(&This->params, params, min(params->dwSize, sizeof(This->params))); + + memcpy(params, &actual, size); + } + + This->params = actual; + This->open = TRUE; return modified ? S_FALSE : S_OK; } From 4294729dfc27220cba879f61875221948d082b93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 2 Oct 2023 08:59:32 +0200 Subject: [PATCH 2619/2777] dmsynth: Create a fluid_synth instance on Open. (cherry picked from commit 3cfa740cd73200577fe8109aa02d2e17f0298fe5) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 9 ++++++++- dlls/dmsynth/tests/dmsynth.c | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 6582a9931e9..23ea57c3a0f 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -235,6 +235,7 @@ struct synth struct list waves; fluid_settings_t *fluid_settings; + fluid_synth_t *fluid_synth; }; static inline struct synth *impl_from_IDirectMusicSynth8(IDirectMusicSynth8 *iface) @@ -354,7 +355,8 @@ static HRESULT WINAPI synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *par if ((params->dwValidParams & DMUS_PORTPARAMS_AUDIOCHANNELS) && params->dwAudioChannels) { - actual.dwAudioChannels = min(params->dwAudioChannels, This->caps.dwMaxAudioChannels); + /* FluidSynth only works with stereo */ + actual.dwAudioChannels = 2; modified |= actual.dwAudioChannels != params->dwAudioChannels; } @@ -387,6 +389,9 @@ static HRESULT WINAPI synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *par memcpy(params, &actual, size); } + fluid_settings_setnum(This->fluid_settings, "synth.sample-rate", actual.dwSampleRate); + if (!(This->fluid_synth = new_fluid_synth(This->fluid_settings))) return E_OUTOFMEMORY; + This->params = actual; This->open = TRUE; @@ -402,6 +407,8 @@ static HRESULT WINAPI synth_Close(IDirectMusicSynth8 *iface) if (!This->open) return DMUS_E_ALREADYCLOSED; + delete_fluid_synth(This->fluid_synth); + This->fluid_synth = NULL; This->open = FALSE; return S_OK; diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index 51504d68a17..ad4bb5c0ad5 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -437,7 +437,7 @@ static void test_dmsynth(void) ok(params.dwValidParams == all_params, "dwValidParams: %#lx\n", params.dwValidParams); ok(params.dwVoices == 1, "dwVoices: %ld\n", params.dwVoices); ok(params.dwChannelGroups == 1, "dwChannelGroups: %ld\n", params.dwChannelGroups); - ok(params.dwAudioChannels == 1, "dwAudioChannels: %ld\n", params.dwAudioChannels); + todo_wine ok(params.dwAudioChannels == 1, "dwAudioChannels: %ld\n", params.dwAudioChannels); ok(params.dwSampleRate == 11025, "dwSampleRate: %ld\n", params.dwSampleRate); test_synth_getformat(dmsynth, ¶ms, "min"); IDirectMusicSynth_Close(dmsynth); @@ -525,7 +525,7 @@ static void test_dmsynth(void) params.dwValidParams = DMUS_PORTPARAMS_AUDIOCHANNELS; params.dwAudioChannels = 1; hr = IDirectMusicSynth_Open(dmsynth, ¶ms); - ok(hr == S_OK, "Open failed: %#lx\n", hr); + todo_wine_if(SUCCEEDED(hr)) ok(hr == S_OK, "Open failed: %#lx\n", hr); hr = IDirectMusicSynthSink_GetDesiredBufferSize(dmsynth_sink, &size); ok(hr == S_OK, "IDirectMusicSynthSink_GetDesiredBufferSize returned: %#lx\n", hr); ok(size == params.dwSampleRate * params.dwAudioChannels * 4, "size: %ld\n", size); From d6e6e63e9a3e440ecfe5f06b02315304d9910638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 11:40:01 +0200 Subject: [PATCH 2620/2777] dmsynth: Create and register a fluid_sfont instance. (cherry picked from commit 907c67ce3cfef4a2b69315c226d3995831f0c5c7) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 51 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 23ea57c3a0f..9bb1e884229 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -235,6 +235,7 @@ struct synth struct list waves; fluid_settings_t *fluid_settings; + fluid_sfont_t *fluid_sfont; fluid_synth_t *fluid_synth; }; @@ -307,6 +308,9 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) wave_release(wave); } + fluid_sfont_set_data(This->fluid_sfont, NULL); + delete_fluid_sfont(This->fluid_sfont); + This->fluid_sfont = NULL; delete_fluid_settings(This->fluid_settings); free(This); } @@ -331,6 +335,7 @@ static HRESULT WINAPI synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *par }; UINT size = sizeof(DMUS_PORTPARAMS); BOOL modified = FALSE; + UINT id; TRACE("(%p, %p)\n", This, params); @@ -391,6 +396,8 @@ static HRESULT WINAPI synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *par fluid_settings_setnum(This->fluid_settings, "synth.sample-rate", actual.dwSampleRate); if (!(This->fluid_synth = new_fluid_synth(This->fluid_settings))) return E_OUTOFMEMORY; + if ((id = fluid_synth_add_sfont(This->fluid_synth, This->fluid_sfont)) == FLUID_FAILED) + WARN("Failed to add fluid_sfont to fluid_synth\n"); This->params = actual; This->open = TRUE; @@ -407,6 +414,7 @@ static HRESULT WINAPI synth_Close(IDirectMusicSynth8 *iface) if (!This->open) return DMUS_E_ALREADYCLOSED; + fluid_synth_remove_sfont(This->fluid_synth, This->fluid_sfont); delete_fluid_synth(This->fluid_synth); This->fluid_synth = NULL; This->open = FALSE; @@ -1066,6 +1074,44 @@ static const IKsControlVtbl synth_control_vtbl = synth_control_KsEvent, }; +static const char *synth_sfont_get_name(fluid_sfont_t *fluid_sfont) +{ + return "DirectMusicSynth"; +} + +static fluid_preset_t *synth_sfont_get_preset(fluid_sfont_t *fluid_sfont, int bank, int patch) +{ + struct synth *synth = fluid_sfont_get_data(fluid_sfont); + struct instrument *instrument; + + TRACE("(%p, %d, %d)\n", fluid_sfont, bank, patch); + + if (!synth) return NULL; + + LIST_FOR_EACH_ENTRY(instrument, &synth->instruments, struct instrument, entry) + if (instrument->patch == patch) break; + if (&instrument->entry == &synth->instruments) return NULL; + + FIXME("Preset not implemented yet\n"); + return NULL; +} + +static void synth_sfont_iter_start(fluid_sfont_t *fluid_sfont) +{ + FIXME("(%p): stub\n", fluid_sfont); +} + +static fluid_preset_t *synth_sfont_iter_next(fluid_sfont_t *fluid_sfont) +{ + FIXME("(%p): stub\n", fluid_sfont); + return NULL; +} + +static int synth_sfont_free(fluid_sfont_t *fluid_sfont) +{ + return 0; +} + HRESULT synth_create(IUnknown **ret_iface) { struct synth *obj; @@ -1094,12 +1140,17 @@ HRESULT synth_create(IUnknown **ret_iface) list_init(&obj->waves); if (!(obj->fluid_settings = new_fluid_settings())) goto failed; + if (!(obj->fluid_sfont = new_fluid_sfont(synth_sfont_get_name, synth_sfont_get_preset, + synth_sfont_iter_start, synth_sfont_iter_next, synth_sfont_free))) + goto failed; + fluid_sfont_set_data(obj->fluid_sfont, obj); TRACE("Created DirectMusicSynth %p\n", obj); *ret_iface = (IUnknown *)&obj->IDirectMusicSynth8_iface; return S_OK; failed: + delete_fluid_settings(obj->fluid_settings); free(obj); return E_OUTOFMEMORY; } From a9243c3be5396fb2540034598a0f43411a9b38c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 9 Oct 2023 15:57:36 +0200 Subject: [PATCH 2621/2777] include: Avoid narrowing warning in wine_dbgstr_fourcc. (cherry picked from commit bc7e51b48c9919cbb71a8bc0a7cb821c1dcbb5ec) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- include/wine/debug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/wine/debug.h b/include/wine/debug.h index c282f52a3b6..52e072e1f2b 100644 --- a/include/wine/debug.h +++ b/include/wine/debug.h @@ -317,7 +317,7 @@ static inline const char *wine_dbgstr_guid( const GUID *id ) static inline const char *wine_dbgstr_fourcc( unsigned int fourcc ) { - char str[4] = { fourcc, fourcc >> 8, fourcc >> 16, fourcc >> 24 }; + char str[4] = { (char)fourcc, (char)(fourcc >> 8), (char)(fourcc >> 16), (char)(fourcc >> 24) }; if (!fourcc) return "''"; if (isprint( str[0] ) && isprint( str[1] ) && isprint( str[2] ) && isprint( str[3] )) From 62ed4586de9038f0a2e593f6d40a1d518f2ff1b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Sep 2023 10:48:59 +0200 Subject: [PATCH 2622/2777] dmime: Get rid of the IDirectMusicWaveTrack typedef. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=9027 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=34751 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45135 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48220 (cherry picked from commit 51c664b2275e93468d3e8c684f84c3939ac86fbc) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/wavetrack.c | 105 ++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c index 4150ea3bcd2..279cfb5c768 100644 --- a/dlls/dmime/wavetrack.c +++ b/dlls/dmime/wavetrack.c @@ -1,5 +1,4 @@ -/* IDirectMusicWaveTrack Implementation - * +/* * Copyright (C) 2003-2004 Rok Mandeljc * * This program is free software; you can redistribute it and/or @@ -22,9 +21,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmime); -/***************************************************************************** - * IDirectMusicWaveTrack implementation - */ struct wave_item { struct list entry; DMUS_IO_WAVE_ITEM_HEADER header; @@ -37,29 +33,30 @@ struct wave_part { struct list items; }; -typedef struct IDirectMusicWaveTrack { +struct wave_track +{ IDirectMusicTrack8 IDirectMusicTrack8_iface; struct dmobject dmobj; /* IPersistStream only */ LONG ref; DMUS_IO_WAVE_TRACK_HEADER header; struct list parts; -} IDirectMusicWaveTrack; +}; -/* IDirectMusicWaveTrack IDirectMusicTrack8 part: */ -static inline IDirectMusicWaveTrack *impl_from_IDirectMusicTrack8(IDirectMusicTrack8 *iface) +/* struct wave_track IDirectMusicTrack8 part: */ +static inline struct wave_track *impl_from_IDirectMusicTrack8(IDirectMusicTrack8 *iface) { - return CONTAINING_RECORD(iface, IDirectMusicWaveTrack, IDirectMusicTrack8_iface); + return CONTAINING_RECORD(iface, struct wave_track, IDirectMusicTrack8_iface); } -static inline IDirectMusicWaveTrack *impl_from_IPersistStream(IPersistStream *iface) +static inline struct wave_track *impl_from_IPersistStream(IPersistStream *iface) { - return CONTAINING_RECORD(iface, IDirectMusicWaveTrack, dmobj.IPersistStream_iface); + return CONTAINING_RECORD(iface, struct wave_track, dmobj.IPersistStream_iface); } static HRESULT WINAPI wave_track_QueryInterface(IDirectMusicTrack8 *iface, REFIID riid, void **ret_iface) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface); @@ -81,7 +78,7 @@ static HRESULT WINAPI wave_track_QueryInterface(IDirectMusicTrack8 *iface, REFII static ULONG WINAPI wave_track_AddRef(IDirectMusicTrack8 *iface) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); @@ -91,7 +88,7 @@ static ULONG WINAPI wave_track_AddRef(IDirectMusicTrack8 *iface) static ULONG WINAPI wave_track_Release(IDirectMusicTrack8 *iface) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); LONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref=%ld\n", This, ref); @@ -119,40 +116,42 @@ static ULONG WINAPI wave_track_Release(IDirectMusicTrack8 *iface) static HRESULT WINAPI wave_track_Init(IDirectMusicTrack8 *iface, IDirectMusicSegment *pSegment) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); - FIXME("(%p, %p): stub\n", This, pSegment); - return S_OK; + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); + FIXME("(%p, %p): stub\n", This, pSegment); + return S_OK; } static HRESULT WINAPI wave_track_InitPlay(IDirectMusicTrack8 *iface, IDirectMusicSegmentState *pSegmentState, IDirectMusicPerformance *pPerformance, void **ppStateData, DWORD dwVirtualTrack8ID, DWORD dwFlags) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); - FIXME("(%p, %p, %p, %p, %ld, %ld): stub\n", This, pSegmentState, pPerformance, ppStateData, dwVirtualTrack8ID, dwFlags); - return S_OK; + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); + FIXME("(%p, %p, %p, %p, %ld, %ld): stub\n", This, pSegmentState, pPerformance, ppStateData, + dwVirtualTrack8ID, dwFlags); + return S_OK; } static HRESULT WINAPI wave_track_EndPlay(IDirectMusicTrack8 *iface, void *pStateData) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); - FIXME("(%p, %p): stub\n", This, pStateData); - return S_OK; + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); + FIXME("(%p, %p): stub\n", This, pStateData); + return S_OK; } static HRESULT WINAPI wave_track_Play(IDirectMusicTrack8 *iface, void *pStateData, MUSIC_TIME mtStart, MUSIC_TIME mtEnd, MUSIC_TIME mtOffset, DWORD dwFlags, IDirectMusicPerformance *pPerf, IDirectMusicSegmentState *pSegSt, DWORD dwVirtualID) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); - FIXME("(%p, %p, %ld, %ld, %ld, %ld, %p, %p, %ld): stub\n", This, pStateData, mtStart, mtEnd, mtOffset, dwFlags, pPerf, pSegSt, dwVirtualID); - return S_OK; + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); + FIXME("(%p, %p, %ld, %ld, %ld, %ld, %p, %p, %ld): stub\n", This, pStateData, mtStart, mtEnd, + mtOffset, dwFlags, pPerf, pSegSt, dwVirtualID); + return S_OK; } static HRESULT WINAPI wave_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time, MUSIC_TIME *next, void *param) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s, %ld, %p, %p): not supported\n", This, debugstr_dmguid(type), time, next, param); return DMUS_E_GET_UNSUPPORTED; @@ -161,7 +160,7 @@ static HRESULT WINAPI wave_track_GetParam(IDirectMusicTrack8 *iface, REFGUID typ static HRESULT WINAPI wave_track_SetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time, void *param) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s, %ld, %p)\n", This, debugstr_dmguid(type), time, param); @@ -195,7 +194,7 @@ static HRESULT WINAPI wave_track_SetParam(IDirectMusicTrack8 *iface, REFGUID typ static HRESULT WINAPI wave_track_IsParamSupported(IDirectMusicTrack8 *iface, REFGUID type) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); static const GUID *valid[] = { &GUID_Disable_Auto_Download, &GUID_Download, @@ -218,7 +217,7 @@ static HRESULT WINAPI wave_track_IsParamSupported(IDirectMusicTrack8 *iface, REF static HRESULT WINAPI wave_track_AddNotificationType(IDirectMusicTrack8 *iface, REFGUID notiftype) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype)); return E_NOTIMPL; @@ -227,7 +226,7 @@ static HRESULT WINAPI wave_track_AddNotificationType(IDirectMusicTrack8 *iface, static HRESULT WINAPI wave_track_RemoveNotificationType(IDirectMusicTrack8 *iface, REFGUID notiftype) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %s): method not implemented\n", This, debugstr_dmguid(notiftype)); return E_NOTIMPL; @@ -236,44 +235,45 @@ static HRESULT WINAPI wave_track_RemoveNotificationType(IDirectMusicTrack8 *ifac static HRESULT WINAPI wave_track_Clone(IDirectMusicTrack8 *iface, MUSIC_TIME mtStart, MUSIC_TIME mtEnd, IDirectMusicTrack **ppTrack) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); - FIXME("(%p, %ld, %ld, %p): stub\n", This, mtStart, mtEnd, ppTrack); - return S_OK; + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); + FIXME("(%p, %ld, %ld, %p): stub\n", This, mtStart, mtEnd, ppTrack); + return S_OK; } static HRESULT WINAPI wave_track_PlayEx(IDirectMusicTrack8 *iface, void *pStateData, REFERENCE_TIME rtStart, REFERENCE_TIME rtEnd, REFERENCE_TIME rtOffset, DWORD dwFlags, IDirectMusicPerformance *pPerf, IDirectMusicSegmentState *pSegSt, DWORD dwVirtualID) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); - FIXME("(%p, %p, 0x%s, 0x%s, 0x%s, %ld, %p, %p, %ld): stub\n", This, pStateData, wine_dbgstr_longlong(rtStart), - wine_dbgstr_longlong(rtEnd), wine_dbgstr_longlong(rtOffset), dwFlags, pPerf, pSegSt, dwVirtualID); - return S_OK; + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); + FIXME("(%p, %p, 0x%s, 0x%s, 0x%s, %ld, %p, %p, %ld): stub\n", This, pStateData, + wine_dbgstr_longlong(rtStart), wine_dbgstr_longlong(rtEnd), + wine_dbgstr_longlong(rtOffset), dwFlags, pPerf, pSegSt, dwVirtualID); + return S_OK; } static HRESULT WINAPI wave_track_GetParamEx(IDirectMusicTrack8 *iface, REFGUID rguidType, REFERENCE_TIME rtTime, REFERENCE_TIME *prtNext, void *pParam, void *pStateData, DWORD dwFlags) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); - FIXME("(%p, %s, 0x%s, %p, %p, %p, %ld): stub\n", This, debugstr_dmguid(rguidType), - wine_dbgstr_longlong(rtTime), prtNext, pParam, pStateData, dwFlags); - return S_OK; + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); + FIXME("(%p, %s, 0x%s, %p, %p, %p, %ld): stub\n", This, debugstr_dmguid(rguidType), + wine_dbgstr_longlong(rtTime), prtNext, pParam, pStateData, dwFlags); + return S_OK; } static HRESULT WINAPI wave_track_SetParamEx(IDirectMusicTrack8 *iface, REFGUID rguidType, REFERENCE_TIME rtTime, void *pParam, void *pStateData, DWORD dwFlags) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); - FIXME("(%p, %s, 0x%s, %p, %p, %ld): stub\n", This, debugstr_dmguid(rguidType), - wine_dbgstr_longlong(rtTime), pParam, pStateData, dwFlags); - return S_OK; + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); + FIXME("(%p, %s, 0x%s, %p, %p, %ld): stub\n", This, debugstr_dmguid(rguidType), + wine_dbgstr_longlong(rtTime), pParam, pStateData, dwFlags); + return S_OK; } static HRESULT WINAPI wave_track_Compose(IDirectMusicTrack8 *iface, IUnknown *context, DWORD trackgroup, IDirectMusicTrack **track) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %p, %ld, %p): method not implemented\n", This, context, trackgroup, track); return E_NOTIMPL; @@ -282,7 +282,7 @@ static HRESULT WINAPI wave_track_Compose(IDirectMusicTrack8 *iface, IUnknown *co static HRESULT WINAPI wave_track_Join(IDirectMusicTrack8 *iface, IDirectMusicTrack *newtrack, MUSIC_TIME join, IUnknown *context, DWORD trackgroup, IDirectMusicTrack **resulttrack) { - IDirectMusicWaveTrack *This = impl_from_IDirectMusicTrack8(iface); + struct wave_track *This = impl_from_IDirectMusicTrack8(iface); TRACE("(%p, %p, %ld, %p, %ld, %p): method not implemented\n", This, newtrack, join, context, trackgroup, resulttrack); return E_NOTIMPL; @@ -368,8 +368,7 @@ static HRESULT parse_wave_item(struct wave_part *part, IStream *stream, struct c return hr; } -static HRESULT parse_wave_part(IDirectMusicWaveTrack *This, IStream *stream, - struct chunk_entry *wavp) +static HRESULT parse_wave_part(struct wave_track *This, IStream *stream, struct chunk_entry *wavp) { struct chunk_entry chunk = {.parent = wavp}; struct wave_part *part; @@ -417,7 +416,7 @@ static HRESULT parse_wave_part(IDirectMusicWaveTrack *This, IStream *stream, static HRESULT WINAPI wave_IPersistStream_Load(IPersistStream *iface, IStream *stream) { - IDirectMusicWaveTrack *This = impl_from_IPersistStream(iface); + struct wave_track *This = impl_from_IPersistStream(iface); struct chunk_entry wavt = {0}; struct chunk_entry chunk = {.parent = &wavt}; HRESULT hr; @@ -469,7 +468,7 @@ static const IPersistStreamVtbl persiststream_vtbl = { /* for ClassFactory */ HRESULT create_dmwavetrack(REFIID lpcGUID, void **ppobj) { - IDirectMusicWaveTrack *track; + struct wave_track *track; HRESULT hr; *ppobj = NULL; From 6f69b52737f5bdb8b0096a145745f17a8031bb2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 10 Oct 2023 23:01:41 +0200 Subject: [PATCH 2623/2777] dmime: Include dmobject.h in dmime_private.h. (cherry picked from commit 6c1bf1f3a95fdf1398cc21eb163873d9e41108e3) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/audiopath.c | 1 - dlls/dmime/dmime_main.c | 1 - dlls/dmime/dmime_private.h | 2 ++ dlls/dmime/graph.c | 1 - dlls/dmime/lyricstrack.c | 1 - dlls/dmime/markertrack.c | 1 - dlls/dmime/paramcontroltrack.c | 1 - dlls/dmime/performance.c | 1 - dlls/dmime/segment.c | 1 - dlls/dmime/segmentstate.c | 1 - dlls/dmime/segtriggertrack.c | 1 - dlls/dmime/seqtrack.c | 1 - dlls/dmime/sysextrack.c | 1 - dlls/dmime/tempotrack.c | 1 - dlls/dmime/timesigtrack.c | 1 - dlls/dmime/wavetrack.c | 1 - 16 files changed, 2 insertions(+), 15 deletions(-) diff --git a/dlls/dmime/audiopath.c b/dlls/dmime/audiopath.c index aef48a5d2db..3310624eb00 100644 --- a/dlls/dmime/audiopath.c +++ b/dlls/dmime/audiopath.c @@ -18,7 +18,6 @@ */ #include "dmime_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); diff --git a/dlls/dmime/dmime_main.c b/dlls/dmime/dmime_main.c index c0aa4e31cfb..89e70bcd1bd 100644 --- a/dlls/dmime/dmime_main.c +++ b/dlls/dmime/dmime_main.c @@ -34,7 +34,6 @@ #include "dmusici.h" #include "dmime_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index e67797def30..94e0efbe771 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -42,6 +42,8 @@ #include "dmusics.h" #include "dmusicc.h" +#include "dmobject.h" + /***************************************************************************** * Interfaces */ diff --git a/dlls/dmime/graph.c b/dlls/dmime/graph.c index d8f6bb88701..e0aa94833ae 100644 --- a/dlls/dmime/graph.c +++ b/dlls/dmime/graph.c @@ -18,7 +18,6 @@ */ #include "dmime_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); diff --git a/dlls/dmime/lyricstrack.c b/dlls/dmime/lyricstrack.c index a1b299e9a7c..f7da1132867 100644 --- a/dlls/dmime/lyricstrack.c +++ b/dlls/dmime/lyricstrack.c @@ -18,7 +18,6 @@ */ #include "dmime_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); diff --git a/dlls/dmime/markertrack.c b/dlls/dmime/markertrack.c index 460e708bc5d..8d36a4cdd01 100644 --- a/dlls/dmime/markertrack.c +++ b/dlls/dmime/markertrack.c @@ -18,7 +18,6 @@ */ #include "dmime_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); diff --git a/dlls/dmime/paramcontroltrack.c b/dlls/dmime/paramcontroltrack.c index 9d32484bfd7..4abcf614c3a 100644 --- a/dlls/dmime/paramcontroltrack.c +++ b/dlls/dmime/paramcontroltrack.c @@ -18,7 +18,6 @@ */ #include "dmime_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 7d077db16cb..327f7d88c3b 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -20,7 +20,6 @@ #include "dmime_private.h" #include "wine/rbtree.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index af7729f34b9..1194f81b09a 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -19,7 +19,6 @@ */ #include "dmime_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index de47d85e9b8..1cb9daac69a 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -17,7 +17,6 @@ */ #include "dmime_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); diff --git a/dlls/dmime/segtriggertrack.c b/dlls/dmime/segtriggertrack.c index dc29ede4963..3f8e628b259 100644 --- a/dlls/dmime/segtriggertrack.c +++ b/dlls/dmime/segtriggertrack.c @@ -19,7 +19,6 @@ */ #include "dmime_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); diff --git a/dlls/dmime/seqtrack.c b/dlls/dmime/seqtrack.c index ae2f002da92..21b78ff26cd 100644 --- a/dlls/dmime/seqtrack.c +++ b/dlls/dmime/seqtrack.c @@ -17,7 +17,6 @@ */ #include "dmime_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); diff --git a/dlls/dmime/sysextrack.c b/dlls/dmime/sysextrack.c index f9c71abf08a..2c55d0dbe07 100644 --- a/dlls/dmime/sysextrack.c +++ b/dlls/dmime/sysextrack.c @@ -18,7 +18,6 @@ */ #include "dmime_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); diff --git a/dlls/dmime/tempotrack.c b/dlls/dmime/tempotrack.c index 6704448b71e..07f410118fe 100644 --- a/dlls/dmime/tempotrack.c +++ b/dlls/dmime/tempotrack.c @@ -19,7 +19,6 @@ */ #include "dmime_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); WINE_DECLARE_DEBUG_CHANNEL(dmfile); diff --git a/dlls/dmime/timesigtrack.c b/dlls/dmime/timesigtrack.c index e98807b7503..0ebf5e4256e 100644 --- a/dlls/dmime/timesigtrack.c +++ b/dlls/dmime/timesigtrack.c @@ -18,7 +18,6 @@ */ #include "dmime_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c index 279cfb5c768..27e4d656163 100644 --- a/dlls/dmime/wavetrack.c +++ b/dlls/dmime/wavetrack.c @@ -17,7 +17,6 @@ */ #include "dmime_private.h" -#include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); From f70e220b3bfdb080540915fe9cc0e85398b2df39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 10 Oct 2023 22:59:32 +0200 Subject: [PATCH 2624/2777] dmusic: Split wave entry points to dmusic_wave.h. (cherry picked from commit 15c4c02eeba45d35c4c00dd5a2f8c16a2fe952e2) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/dmusic_private.h | 6 +----- dlls/dmusic/dmusic_wave.h | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 dlls/dmusic/dmusic_wave.h diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index f67bc5c4b2f..3efb69656c8 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -45,6 +45,7 @@ #include "dmksctrl.h" #include "dmobject.h" +#include "dmusic_wave.h" /***************************************************************************** * Interfaces @@ -94,7 +95,6 @@ extern HRESULT DMUSIC_CreateReferenceClockImpl (LPCGUID lpcGUID, LPVOID* ppobj, extern HRESULT download_create(DWORD size, IDirectMusicDownload **ret_iface); -struct soundfont; extern HRESULT instrument_create_from_soundfont(struct soundfont *soundfont, UINT index, struct collection *collection, DMUS_OBJECTDESC *desc, IDirectMusicInstrument **ret_iface); extern HRESULT instrument_create_from_chunk(IStream *stream, struct chunk_entry *parent, @@ -103,10 +103,6 @@ extern HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirec IDirectMusicDownloadedInstrument **downloaded); extern HRESULT instrument_unload_from_port(IDirectMusicDownloadedInstrument *iface, IDirectMusicPortDownload *port); -extern HRESULT wave_create_from_soundfont(struct soundfont *soundfont, UINT index, IUnknown **out); -extern HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnknown **out); -extern HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, DWORD *id); - /***************************************************************************** * IDirectMusic8Impl implementation structure */ diff --git a/dlls/dmusic/dmusic_wave.h b/dlls/dmusic/dmusic_wave.h new file mode 100644 index 00000000000..0db0134ae17 --- /dev/null +++ b/dlls/dmusic/dmusic_wave.h @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Rémi Bernon for CodeWeavers + * + * This program 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 program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" + +#include "objbase.h" +#include "dmusici.h" + +struct soundfont; +struct chunk_entry; + +extern HRESULT wave_create_from_soundfont(struct soundfont *soundfont, UINT index, IUnknown **out); +extern HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnknown **out); +extern HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, DWORD *id); From 934ce2212de842f652e97bacc5794bf30726edec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 10 Oct 2023 23:03:37 +0200 Subject: [PATCH 2625/2777] dmime: Create a wave track when loading a segment from a .wav. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=9027 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=34751 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45135 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48220 (cherry picked from commit 7bbd4be52a424e38495fa132885730bd4823a33e) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/Makefile.in | 1 + dlls/dmime/dmime_private.h | 3 + dlls/dmime/segment.c | 111 ++++++++++++++----------------------- dlls/dmime/tests/dmime.c | 2 +- dlls/dmime/wavetrack.c | 43 ++++++++++++-- dlls/dmusic/dmusic_wave.h | 1 + dlls/dmusic/wave.c | 7 +++ 7 files changed, 94 insertions(+), 74 deletions(-) diff --git a/dlls/dmime/Makefile.in b/dlls/dmime/Makefile.in index ef4d0b9bee4..eccf7815475 100644 --- a/dlls/dmime/Makefile.in +++ b/dlls/dmime/Makefile.in @@ -18,6 +18,7 @@ C_SRCS = \ sysextrack.c \ tempotrack.c \ timesigtrack.c \ + wave.c \ wavetrack.c IDL_SRCS = dmime.idl diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 94e0efbe771..636004aed84 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -77,6 +77,9 @@ extern HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME sta extern HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance *performance); extern HRESULT segment_state_end_play(IDirectMusicSegmentState *iface); +extern HRESULT wave_track_create_from_chunk(IStream *stream, struct chunk_entry *parent, + IDirectMusicTrack8 **ret_iface); + /***************************************************************************** * Auxiliary definitions */ diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index 1194f81b09a..fc277ba73f9 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -741,13 +741,17 @@ static inline void dump_segment_header(DMUS_IO_SEGMENT_HEADER *h, DWORD size) } } -static HRESULT parse_segment_form(struct segment *This, IStream *stream, const struct chunk_entry *riff) +static HRESULT parse_dmsg_chunk(struct segment *This, IStream *stream, const struct chunk_entry *riff) { struct chunk_entry chunk = {.parent = riff}; HRESULT hr; TRACE("Parsing segment form in %p: %s\n", stream, debugstr_chunk(riff)); + if (FAILED(hr = dmobj_parsedescriptor(stream, riff, &This->dmobj.desc, DMUS_OBJ_NAME | DMUS_OBJ_CATEGORY)) + || FAILED(hr = stream_reset_chunk_data(stream, riff))) + return hr; + while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { switch (chunk.id) { case DMUS_FOURCC_SEGMENT_CHUNK: @@ -786,89 +790,58 @@ static inline struct segment *impl_from_IPersistStream(IPersistStream *iface) return CONTAINING_RECORD(iface, struct segment, dmobj.IPersistStream_iface); } -static HRESULT parse_wave_form(struct segment *This, IStream *stream, const struct chunk_entry *riff) +static HRESULT WINAPI segment_persist_stream_Load(IPersistStream *iface, IStream *stream) { + struct segment *This = impl_from_IPersistStream(iface); + struct chunk_entry chunk = {0}; HRESULT hr; - struct chunk_entry chunk = {.parent = riff}; - TRACE("Parsing segment wave in %p: %s\n", stream, debugstr_chunk(riff)); + TRACE("(%p, %p): Loading\n", This, stream); - while ((hr = stream_next_chunk(stream, &chunk)) == S_OK) { - switch (chunk.id) { - case mmioFOURCC('f','m','t',' '): { - if (FAILED(hr = stream_chunk_get_data(stream, &chunk, &This->wave_format, - sizeof(This->wave_format))) ) - return hr; - TRACE("Wave Format tag %d\n", This->wave_format.wf.wFormatTag); - break; - } - case mmioFOURCC('d','a','t','a'): { - TRACE("Wave Data size %lu\n", chunk.size); - if (This->wave_data) - ERR("Multiple data streams detected\n"); - This->wave_data = malloc(chunk.size); - This->data_size = chunk.size; - if (!This->wave_data) - return E_OUTOFMEMORY; - if (FAILED(hr = stream_chunk_get_data(stream, &chunk, This->wave_data, chunk.size))) - return hr; - break; - } - case FOURCC_LIST: { - FIXME("Skipping LIST tag\n"); - break; - } - case mmioFOURCC('I','S','F','T'): { - FIXME("Skipping ISFT tag\n"); - break; - } - case mmioFOURCC('f','a','c','t'): { - FIXME("Skipping fact tag\n"); - break; - } - } - } + if (!stream) return E_POINTER; - return SUCCEEDED(hr) ? S_OK : hr; -} + if ((hr = stream_get_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case MAKE_IDTYPE(FOURCC_RIFF, DMUS_FOURCC_SEGMENT_FORM): + hr = parse_dmsg_chunk(This, stream, &chunk); + break; -static HRESULT WINAPI segment_persist_stream_Load(IPersistStream *iface, IStream *stream) -{ - struct segment *This = impl_from_IPersistStream(iface); - struct chunk_entry riff = {0}; - HRESULT hr; + case mmioFOURCC('M','T','h','d'): + FIXME("MIDI file loading not supported\n"); + break; - TRACE("(%p, %p): Loading\n", This, stream); + case MAKE_IDTYPE(FOURCC_RIFF, mmioFOURCC('W','A','V','E')): + { + IDirectMusicTrack8 *track; + HRESULT hr; - if (!stream) - return E_POINTER; + TRACE("Loading segment %p from wave file\n", This); - if (stream_get_chunk(stream, &riff) != S_OK || - (riff.id != FOURCC_RIFF && riff.id != mmioFOURCC('M','T','h','d'))) - return DMUS_E_UNSUPPORTED_STREAM; - stream_reset_chunk_start(stream, &riff); + This->header.mtLength = 1; + if (FAILED(hr = wave_track_create_from_chunk(stream, &chunk, &track))) break; + hr = segment_append_track(This, (IDirectMusicTrack *)track, 1, 0); + break; + } - if (riff.id == mmioFOURCC('M','T','h','d')) { - FIXME("MIDI file loading not supported\n"); - return S_OK; + default: + WARN("Invalid segment chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + hr = DMUS_E_UNSUPPORTED_STREAM; + break; + } } - hr = IDirectMusicObject_ParseDescriptor(&This->dmobj.IDirectMusicObject_iface, stream, - &This->dmobj.desc); if (FAILED(hr)) - return hr; - stream_reset_chunk_data(stream, &riff); - - if (riff.type == DMUS_FOURCC_SEGMENT_FORM) - hr = parse_segment_form(This, stream, &riff); - else if(riff.type == mmioFOURCC('W','A','V','E')) - hr = parse_wave_form(This, stream, &riff); - else { - FIXME("Unknown type %s\n", debugstr_chunk(&riff)); - hr = S_OK; + { + WARN("Failed to load segment from stream %p, hr %#lx\n", stream, hr); + return DMUS_E_UNSUPPORTED_STREAM; } - return hr; + This->dmobj.desc.guidClass = CLSID_DirectMusicSegment; + This->dmobj.desc.dwValidData |= DMUS_OBJ_CLASS; + + return S_OK; } static const IPersistStreamVtbl segment_persist_stream_vtbl = diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index e390f86f1bf..8c42398eadc 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3279,7 +3279,7 @@ static void test_wave_pmsg(void) length = 0xdeadbeef; hr = IDirectMusicSegment_GetLength(segment, &length); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(length == 1, "got %lu\n", length); + ok(length == 1, "got %lu\n", length); /* without Download, no DMUS_PMSGT_WAVE is sent */ diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c index 27e4d656163..d9d6334adad 100644 --- a/dlls/dmime/wavetrack.c +++ b/dlls/dmime/wavetrack.c @@ -17,13 +17,14 @@ */ #include "dmime_private.h" +#include "dmusic_wave.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); struct wave_item { struct list entry; DMUS_IO_WAVE_ITEM_HEADER header; - IDirectMusicObject *object; + IUnknown *object; }; struct wave_part { @@ -100,8 +101,7 @@ static ULONG WINAPI wave_track_Release(IDirectMusicTrack8 *iface) list_remove(&part->entry); LIST_FOR_EACH_ENTRY_SAFE(item, item2, &part->items, struct wave_item, entry) { list_remove(&item->entry); - if (item->object) - IDirectMusicObject_Release(item->object); + if (item->object) IUnknown_Release(item->object); free(item); } free(part); @@ -355,7 +355,7 @@ static HRESULT parse_wave_item(struct wave_part *part, IStream *stream, struct c hr = DMUS_E_UNSUPPORTED_STREAM; goto error; } - if (FAILED(hr = dmobj_parsereference(stream, &chunk, &item->object))) + if (FAILED(hr = dmobj_parsereference(stream, &chunk, (IDirectMusicObject **)&item->object))) goto error; list_add_tail(&part->items, &item->entry); @@ -484,3 +484,38 @@ HRESULT create_dmwavetrack(REFIID lpcGUID, void **ppobj) return hr; } + +HRESULT wave_track_create_from_chunk(IStream *stream, struct chunk_entry *parent, + IDirectMusicTrack8 **ret_iface) +{ + IDirectMusicTrack8 *iface; + struct wave_track *This; + struct wave_item *item; + struct wave_part *part; + HRESULT hr; + + if (FAILED(hr = create_dmwavetrack(&IID_IDirectMusicTrack8, (void **)&iface))) return hr; + This = impl_from_IDirectMusicTrack8(iface); + + if (!(part = calloc(1, sizeof(*part)))) + { + IDirectMusicTrack8_Release(iface); + return E_OUTOFMEMORY; + } + list_init(&part->items); + list_add_tail(&This->parts, &part->entry); + + if (!(item = calloc(1, sizeof(*item))) + || FAILED(hr = wave_create_from_chunk(stream, parent, &item->object))) + { + IDirectMusicTrack8_Release(iface); + free(item); + return hr; + } + if (FAILED(hr = wave_get_duration(item->object, &item->header.rtDuration))) + WARN("Failed to get wave duration, hr %#lx\n", hr); + list_add_tail(&part->items, &item->entry); + + *ret_iface = iface; + return S_OK; +} diff --git a/dlls/dmusic/dmusic_wave.h b/dlls/dmusic/dmusic_wave.h index 0db0134ae17..3f7209e250e 100644 --- a/dlls/dmusic/dmusic_wave.h +++ b/dlls/dmusic/dmusic_wave.h @@ -32,3 +32,4 @@ struct chunk_entry; extern HRESULT wave_create_from_soundfont(struct soundfont *soundfont, UINT index, IUnknown **out); extern HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnknown **out); extern HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, DWORD *id); +extern HRESULT wave_get_duration(IUnknown *iface, REFERENCE_TIME *duration); diff --git a/dlls/dmusic/wave.c b/dlls/dmusic/wave.c index 40a8c9e129f..2f5e1409106 100644 --- a/dlls/dmusic/wave.c +++ b/dlls/dmusic/wave.c @@ -338,3 +338,10 @@ HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, D IDirectMusicDownload_Release(download); return hr; } + +HRESULT wave_get_duration(IUnknown *iface, REFERENCE_TIME *duration) +{ + struct wave *This = impl_from_IUnknown(iface); + *duration = (REFERENCE_TIME)This->data_size * 10000000 / This->format->nAvgBytesPerSec; + return S_OK; +} From 2e83b39b7dcc38154256c3f00f395bd11d2a06a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Sep 2023 11:21:38 +0200 Subject: [PATCH 2626/2777] dmime: Implement GUID_(Download|Unload)FromAudioPath for wave track. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=9027 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=34751 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45135 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48220 (cherry picked from commit 4a7a8a7ecc8bc259da58470a7e4be64b9ba2cd8e) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/dmime_private.h | 2 ++ dlls/dmime/performance.c | 14 ++++++++ dlls/dmime/wavetrack.c | 70 +++++++++++++++++++++++++++++++++----- dlls/dmusic/dmusic_wave.h | 1 + dlls/dmusic/wave.c | 39 +++++++++++++++++++++ 5 files changed, 118 insertions(+), 8 deletions(-) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 636004aed84..c1f777f3949 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -80,6 +80,8 @@ extern HRESULT segment_state_end_play(IDirectMusicSegmentState *iface); extern HRESULT wave_track_create_from_chunk(IStream *stream, struct chunk_entry *parent, IDirectMusicTrack8 **ret_iface); +extern HRESULT performance_get_dsound(IDirectMusicPerformance8 *iface, IDirectSound **dsound); + /***************************************************************************** * Auxiliary definitions */ diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 327f7d88c3b..84b4b4b8575 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1731,3 +1731,17 @@ HRESULT create_dmperformance(REFIID iid, void **ret_iface) IDirectMusicPerformance_Release(&obj->IDirectMusicPerformance8_iface); return hr; } + +static inline struct performance *unsafe_impl_from_IDirectMusicPerformance8(IDirectMusicPerformance8 *iface) +{ + if (iface->lpVtbl != &performance_vtbl) return NULL; + return CONTAINING_RECORD(iface, struct performance, IDirectMusicPerformance8_iface); +} + +HRESULT performance_get_dsound(IDirectMusicPerformance8 *iface, IDirectSound **dsound) +{ + struct performance *This = unsafe_impl_from_IDirectMusicPerformance8(iface); + if (!This || !(*dsound = This->dsound)) return E_FAIL; + IDirectSound_AddRef(*dsound); + return S_OK; +} diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c index d9d6334adad..7c72065520a 100644 --- a/dlls/dmime/wavetrack.c +++ b/dlls/dmime/wavetrack.c @@ -25,6 +25,7 @@ struct wave_item { struct list entry; DMUS_IO_WAVE_ITEM_HEADER header; IUnknown *object; + IDirectSoundBuffer *buffer; }; struct wave_part { @@ -97,13 +98,18 @@ static ULONG WINAPI wave_track_Release(IDirectMusicTrack8 *iface) struct wave_item *item, *item2; struct wave_part *part, *part2; - LIST_FOR_EACH_ENTRY_SAFE(part, part2, &This->parts, struct wave_part, entry) { + LIST_FOR_EACH_ENTRY_SAFE(part, part2, &This->parts, struct wave_part, entry) + { list_remove(&part->entry); - LIST_FOR_EACH_ENTRY_SAFE(item, item2, &part->items, struct wave_item, entry) { + + LIST_FOR_EACH_ENTRY_SAFE(item, item2, &part->items, struct wave_item, entry) + { list_remove(&item->entry); + if (item->buffer) IDirectSoundBuffer_Release(item->buffer); if (item->object) IUnknown_Release(item->object); free(item); } + free(part); } @@ -171,9 +177,46 @@ static HRESULT WINAPI wave_track_SetParam(IDirectMusicTrack8 *iface, REFGUID typ FIXME("GUID_Download not handled yet\n"); return S_OK; } - if (IsEqualGUID(type, &GUID_DownloadToAudioPath)) { - FIXME("GUID_DownloadToAudioPath not handled yet\n"); - return S_OK; + if (IsEqualGUID(type, &GUID_DownloadToAudioPath)) + { + IDirectMusicPerformance8 *performance; + IDirectMusicAudioPath *audio_path; + IUnknown *object = param; + struct wave_part *part; + struct wave_item *item; + IDirectSound *dsound; + HRESULT hr; + + if (FAILED(hr = IDirectMusicAudioPath_QueryInterface(object, &IID_IDirectMusicPerformance8, (void **)&performance)) + && SUCCEEDED(hr = IDirectMusicAudioPath_QueryInterface(object, &IID_IDirectMusicAudioPath, (void **)&audio_path))) + { + hr = IDirectMusicAudioPath_GetObjectInPath(audio_path, DMUS_PCHANNEL_ALL, DMUS_PATH_PERFORMANCE, 0, + &GUID_All_Objects, 0, &IID_IDirectMusicPerformance8, (void **)&performance); + IDirectMusicAudioPath_Release(audio_path); + } + + if (SUCCEEDED(hr)) + hr = performance_get_dsound(performance, &dsound); + IDirectMusicPerformance_Release(performance); + + if (FAILED(hr)) + { + WARN("Failed to get direct sound from param %p, hr %#lx\n", param, hr); + return hr; + } + + LIST_FOR_EACH_ENTRY(part, &This->parts, struct wave_part, entry) + { + LIST_FOR_EACH_ENTRY(item, &part->items, struct wave_item, entry) + { + if (item->buffer) continue; + if (FAILED(hr = wave_download_to_dsound(item->object, dsound, &item->buffer))) + { + WARN("Failed to download wave %p to direct sound, hr %#lx\n", item->object, hr); + return hr; + } + } + } } if (IsEqualGUID(type, &GUID_Enable_Auto_Download)) { FIXME("GUID_Enable_Auto_Download not handled yet\n"); @@ -183,9 +226,20 @@ static HRESULT WINAPI wave_track_SetParam(IDirectMusicTrack8 *iface, REFGUID typ FIXME("GUID_Unload not handled yet\n"); return S_OK; } - if (IsEqualGUID(type, &GUID_UnloadFromAudioPath)) { - FIXME("GUID_UnloadFromAudioPath not handled yet\n"); - return S_OK; + if (IsEqualGUID(type, &GUID_UnloadFromAudioPath)) + { + struct wave_part *part; + struct wave_item *item; + + LIST_FOR_EACH_ENTRY(part, &This->parts, struct wave_part, entry) + { + LIST_FOR_EACH_ENTRY(item, &part->items, struct wave_item, entry) + { + if (!item->buffer) continue; + IDirectSoundBuffer_Release(item->buffer); + item->buffer = NULL; + } + } } return DMUS_E_TYPE_UNSUPPORTED; diff --git a/dlls/dmusic/dmusic_wave.h b/dlls/dmusic/dmusic_wave.h index 3f7209e250e..43396250261 100644 --- a/dlls/dmusic/dmusic_wave.h +++ b/dlls/dmusic/dmusic_wave.h @@ -32,4 +32,5 @@ struct chunk_entry; extern HRESULT wave_create_from_soundfont(struct soundfont *soundfont, UINT index, IUnknown **out); extern HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnknown **out); extern HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, DWORD *id); +extern HRESULT wave_download_to_dsound(IUnknown *iface, IDirectSound *dsound, IDirectSoundBuffer **ret_iface); extern HRESULT wave_get_duration(IUnknown *iface, REFERENCE_TIME *duration); diff --git a/dlls/dmusic/wave.c b/dlls/dmusic/wave.c index 2f5e1409106..ef1cd2990ff 100644 --- a/dlls/dmusic/wave.c +++ b/dlls/dmusic/wave.c @@ -339,6 +339,45 @@ HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, D return hr; } +HRESULT wave_download_to_dsound(IUnknown *iface, IDirectSound *dsound, IDirectSoundBuffer **ret_iface) +{ + struct wave *This = impl_from_IUnknown(iface); + DSBUFFERDESC desc = + { + .dwSize = sizeof(desc), + .dwBufferBytes = This->data_size, + .lpwfxFormat = This->format, + }; + IDirectSoundBuffer *buffer; + HRESULT hr; + void *data; + DWORD size; + + TRACE("%p, %p, %p\n", This, dsound, ret_iface); + + if (FAILED(hr = IDirectSound_CreateSoundBuffer(dsound, &desc, &buffer, NULL))) + { + WARN("Failed to create direct sound buffer, hr %#lx\n", hr); + return hr; + } + + if (SUCCEEDED(hr = IDirectSoundBuffer_Lock(buffer, 0, This->data_size, &data, &size, NULL, 0, 0))) + { + memcpy(data, This->data, This->data_size); + hr = IDirectSoundBuffer_Unlock(buffer, data, This->data_size, NULL, 0); + } + + if (FAILED(hr)) + { + WARN("Failed to download wave to dsound, hr %#lx\n", hr); + IDirectSoundBuffer_Release(buffer); + return hr; + } + + *ret_iface = buffer; + return S_OK; +} + HRESULT wave_get_duration(IUnknown *iface, REFERENCE_TIME *duration) { struct wave *This = impl_from_IUnknown(iface); From 9783f295071931f6f4d340dad97a9dc4db45ad52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Sep 2023 11:28:51 +0200 Subject: [PATCH 2627/2777] dmime: Implement IDirectMusicTrack_Play for the wave track. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=9027 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=34751 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45135 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48220 (cherry picked from commit edad7809227642fadc187a00b2df5f3326c567c8) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 8 +---- dlls/dmime/wavetrack.c | 68 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 8c42398eadc..412cccce781 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3320,8 +3320,6 @@ static void test_wave_pmsg(void) ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&wave); ok(!ret, "got %#lx\n", ret); - if (wave->dwType == DMUS_PMSGT_WAVE) - { ok(wave->dwType == DMUS_PMSGT_WAVE, "got %p\n", wave); ok(!!wave->punkUser, "got %p\n", wave->punkUser); ok(wave->rtStartOffset == 0, "got %I64d\n", wave->rtStartOffset); @@ -3330,18 +3328,14 @@ static void test_wave_pmsg(void) ok(wave->lVolume == 0, "got %lu\n", wave->lVolume); ok(wave->lPitch == 0, "got %lu\n", wave->lPitch); ok(wave->bFlags == 0, "got %#x\n", wave->bFlags); - } hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)wave); ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 500, &msg); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %p\n", msg); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); - } hr = IDirectMusicSegment8_Unload((IDirectMusicSegment8 *)segment, (IUnknown *)performance); ok(hr == S_OK, "got %#lx\n", hr); diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c index 7c72065520a..def1e59fb23 100644 --- a/dlls/dmime/wavetrack.c +++ b/dlls/dmime/wavetrack.c @@ -143,14 +143,70 @@ static HRESULT WINAPI wave_track_EndPlay(IDirectMusicTrack8 *iface, void *pState return S_OK; } -static HRESULT WINAPI wave_track_Play(IDirectMusicTrack8 *iface, void *pStateData, - MUSIC_TIME mtStart, MUSIC_TIME mtEnd, MUSIC_TIME mtOffset, DWORD dwFlags, - IDirectMusicPerformance *pPerf, IDirectMusicSegmentState *pSegSt, DWORD dwVirtualID) +static HRESULT WINAPI wave_track_Play(IDirectMusicTrack8 *iface, void *state_data, + MUSIC_TIME start_time, MUSIC_TIME end_time, MUSIC_TIME time_offset, DWORD segment_flags, + IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state, DWORD track_id) { struct wave_track *This = impl_from_IDirectMusicTrack8(iface); - FIXME("(%p, %p, %ld, %ld, %ld, %ld, %p, %p, %ld): stub\n", This, pStateData, mtStart, mtEnd, - mtOffset, dwFlags, pPerf, pSegSt, dwVirtualID); - return S_OK; + LONG volume = This->header.lVolume; + IDirectMusicGraph *graph; + struct wave_part *part; + struct wave_item *item; + HRESULT hr; + + TRACE("(%p, %p, %ld, %ld, %ld, %#lx, %p, %p, %ld)\n", This, state_data, start_time, end_time, + time_offset, segment_flags, performance, segment_state, track_id); + + if (start_time != 0) FIXME("start_time %ld not implemented\n", start_time); + if (end_time != -1) FIXME("end_time %ld not implemented\n", end_time); + if (time_offset != 0) FIXME("time_offset %ld not implemented\n", time_offset); + if (segment_flags) FIXME("segment_flags %#lx not implemented\n", segment_flags); + if (segment_state) FIXME("segment_state %p not implemented\n", segment_state); + + if (FAILED(hr = IDirectMusicPerformance_QueryInterface(performance, + &IID_IDirectMusicGraph, (void **)&graph))) + return hr; + + LIST_FOR_EACH_ENTRY(part, &This->parts, struct wave_part, entry) + { + volume += part->header.lVolume; + + LIST_FOR_EACH_ENTRY(item, &part->items, struct wave_item, entry) + { + DMUS_WAVE_PMSG *msg; + + if (!item->buffer) continue; + + if (FAILED(hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(*msg), + (DMUS_PMSG **)&msg))) + break; + + msg->mtTime = item->header.rtTime; + msg->dwFlags = DMUS_PMSGF_MUSICTIME; + msg->dwPChannel = part->header.dwPChannel; + msg->dwVirtualTrackID = track_id; + msg->dwType = DMUS_PMSGT_WAVE; + msg->punkUser = (IUnknown *)item->buffer; + IDirectSoundBuffer_AddRef(item->buffer); + + msg->rtStartOffset = item->header.rtStartOffset; + msg->rtDuration = item->header.rtDuration; + msg->lVolume = volume + item->header.lVolume; + msg->lPitch = item->header.lPitch; + + if (FAILED(hr = IDirectMusicGraph_StampPMsg(graph, (DMUS_PMSG *)msg)) + || FAILED(hr = IDirectMusicPerformance_SendPMsg(performance, (DMUS_PMSG *)msg))) + { + IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)msg); + break; + } + } + + volume -= part->header.lVolume; + } + + IDirectMusicGraph_Release(graph); + return hr; } static HRESULT WINAPI wave_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time, From 2b9fbcb3190e14a0bda12f99c3dd40509278ba78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 25 Sep 2023 11:30:42 +0200 Subject: [PATCH 2628/2777] dmime: Play direct sound buffer from DMUS_PMSGT_WAVE message. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=9027 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=34751 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45135 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48220 (cherry picked from commit 16f9bfd23f3ca245a73722e9ab0028bf7d1b311d) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 84b4b4b8575..2018fa013de 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1631,6 +1631,7 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, { struct performance *This = impl_from_IDirectMusicTool(iface); struct message *message = message_from_DMUS_PMSG(msg); + HRESULT hr; FIXME("(%p, %p, %p): semi-stub\n", This, performance, msg); @@ -1641,7 +1642,6 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, DMUS_NOTIFICATION_PMSG *notif = (DMUS_NOTIFICATION_PMSG *)msg; struct message *previous; BOOL enabled = FALSE; - HRESULT hr; if (IsEqualGUID(¬if->guidNotificationType, &GUID_NOTIFICATION_SEGMENT) && notif->dwNotificationOption == DMUS_NOTIFICATION_SEGEND) @@ -1671,6 +1671,11 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, return S_OK; } + case DMUS_PMSGT_WAVE: + if (FAILED(hr = IDirectSoundBuffer_Play((IDirectSoundBuffer *)msg->punkUser, 0, 0, 0))) + WARN("Failed to play wave buffer, hr %#lx\n", hr); + break; + default: FIXME("Unhandled message type %#lx\n", msg->dwType); break; From bd8cee88f8d3c0ed79a74b9e365ee283ebff8a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sat, 23 Sep 2023 13:47:39 +0200 Subject: [PATCH 2629/2777] dmsynth: Fix synth download of articulations list. (cherry picked from commit a1e8352f54153a76b6e2759b58f2f3a15d1b9ca1) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 9bb1e884229..4640b871d93 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -445,7 +445,7 @@ static HRESULT synth_download_articulation2(struct synth *This, ULONG *offsets, { articulation_info = (DMUS_ARTICULATION2 *)(data + offsets[index]); list = (CONNECTIONLIST *)(data + offsets[articulation_info->ulArtIdx]); - connections = (CONNECTION *)list + 1; + connections = (CONNECTION *)(list + 1); if (TRACE_ON(dmsynth)) dump_connectionlist(list); if (articulation_info->ulFirstExtCkIdx) FIXME("Articulation extensions not implemented\n"); From 8cf80e80c5a21fb70063f9b71c082a91f84518a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 8 Sep 2023 09:49:06 +0200 Subject: [PATCH 2630/2777] dmsynth: Improve debug traces of DLS2 connections. (cherry picked from commit 456ba9925525162deba07869e6dc6b599667d244) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 91 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 8 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 4640b871d93..0c85e3cf6b3 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -28,11 +28,93 @@ #include "dmksctrl.h" #include "dmsynth_private.h" +#include "dls2.h" #include WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); +#define CONN_SRC_CC2 0x0082 +#define CONN_SRC_RPN0 0x0100 + +static const char *debugstr_conn_src(UINT src) +{ + switch (src) + { + case CONN_SRC_NONE: return "SRC_NONE"; + case CONN_SRC_LFO: return "SRC_LFO"; + case CONN_SRC_KEYONVELOCITY: return "SRC_KEYONVELOCITY"; + case CONN_SRC_KEYNUMBER: return "SRC_KEYNUMBER"; + case CONN_SRC_EG1: return "SRC_EG1"; + case CONN_SRC_EG2: return "SRC_EG2"; + case CONN_SRC_PITCHWHEEL: return "SRC_PITCHWHEEL"; + case CONN_SRC_CC1: return "SRC_CC1"; + case CONN_SRC_CC7: return "SRC_CC7"; + case CONN_SRC_CC10: return "SRC_CC10"; + case CONN_SRC_CC11: return "SRC_CC11"; + case CONN_SRC_POLYPRESSURE: return "SRC_POLYPRESSURE"; + case CONN_SRC_CHANNELPRESSURE: return "SRC_CHANNELPRESSURE"; + case CONN_SRC_VIBRATO: return "SRC_VIBRATO"; + case CONN_SRC_MONOPRESSURE: return "SRC_MONOPRESSURE"; + case CONN_SRC_CC91: return "SRC_CC91"; + case CONN_SRC_CC93: return "SRC_CC93"; + + case CONN_SRC_CC2: return "SRC_CC2"; + case CONN_SRC_RPN0: return "SRC_RPN0"; + } + + return wine_dbg_sprintf("%#x", src); +} + +static const char *debugstr_conn_dst(UINT dst) +{ + switch (dst) + { + case CONN_DST_NONE: return "DST_NONE"; + /* case CONN_DST_ATTENUATION: return "DST_ATTENUATION"; Same as CONN_DST_GAIN */ + case CONN_DST_PITCH: return "DST_PITCH"; + case CONN_DST_PAN: return "DST_PAN"; + case CONN_DST_LFO_FREQUENCY: return "DST_LFO_FREQUENCY"; + case CONN_DST_LFO_STARTDELAY: return "DST_LFO_STARTDELAY"; + case CONN_DST_EG1_ATTACKTIME: return "DST_EG1_ATTACKTIME"; + case CONN_DST_EG1_DECAYTIME: return "DST_EG1_DECAYTIME"; + case CONN_DST_EG1_RELEASETIME: return "DST_EG1_RELEASETIME"; + case CONN_DST_EG1_SUSTAINLEVEL: return "DST_EG1_SUSTAINLEVEL"; + case CONN_DST_EG2_ATTACKTIME: return "DST_EG2_ATTACKTIME"; + case CONN_DST_EG2_DECAYTIME: return "DST_EG2_DECAYTIME"; + case CONN_DST_EG2_RELEASETIME: return "DST_EG2_RELEASETIME"; + case CONN_DST_EG2_SUSTAINLEVEL: return "DST_EG2_SUSTAINLEVEL"; + case CONN_DST_GAIN: return "DST_GAIN"; + case CONN_DST_KEYNUMBER: return "DST_KEYNUMBER"; + case CONN_DST_LEFT: return "DST_LEFT"; + case CONN_DST_RIGHT: return "DST_RIGHT"; + case CONN_DST_CENTER: return "DST_CENTER"; + case CONN_DST_LEFTREAR: return "DST_LEFTREAR"; + case CONN_DST_RIGHTREAR: return "DST_RIGHTREAR"; + case CONN_DST_LFE_CHANNEL: return "DST_LFE_CHANNEL"; + case CONN_DST_CHORUS: return "DST_CHORUS"; + case CONN_DST_REVERB: return "DST_REVERB"; + case CONN_DST_VIB_FREQUENCY: return "DST_VIB_FREQUENCY"; + case CONN_DST_VIB_STARTDELAY: return "DST_VIB_STARTDELAY"; + case CONN_DST_EG1_DELAYTIME: return "DST_EG1_DELAYTIME"; + case CONN_DST_EG1_HOLDTIME: return "DST_EG1_HOLDTIME"; + case CONN_DST_EG1_SHUTDOWNTIME: return "DST_EG1_SHUTDOWNTIME"; + case CONN_DST_EG2_DELAYTIME: return "DST_EG2_DELAYTIME"; + case CONN_DST_EG2_HOLDTIME: return "DST_EG2_HOLDTIME"; + case CONN_DST_FILTER_CUTOFF: return "DST_FILTER_CUTOFF"; + case CONN_DST_FILTER_Q: return "DST_FILTER_Q"; + } + + return wine_dbg_sprintf("%#x", dst); +} + +static const char *debugstr_connection(const CONNECTION *conn) +{ + return wine_dbg_sprintf("%s (%#x) x %s (%#x) -> %s (%#x): %ld", debugstr_conn_src(conn->usSource), + (conn->usTransform >> 10) & 0x3f, debugstr_conn_src(conn->usControl), (conn->usTransform >> 4) & 0x3f, + debugstr_conn_dst(conn->usDestination), (conn->usTransform & 0xf), conn->lScale); +} + static void dump_dmus_instrument(DMUS_INSTRUMENT *instrument) { TRACE("DMUS_INSTRUMENT:\n"); @@ -88,14 +170,7 @@ static void dump_connectionlist(CONNECTIONLIST *list) TRACE(" - cConnections = %lu\n", list->cConnections); for (i = 0; i < list->cConnections; i++) - { - TRACE("- CONNECTION[%u]:\n", i); - TRACE(" - usSource = %u\n", connections[i].usSource); - TRACE(" - usControl = %u\n", connections[i].usControl); - TRACE(" - usDestination = %u\n", connections[i].usDestination); - TRACE(" - usTransform = %u\n", connections[i].usTransform); - TRACE(" - lScale = %lu\n", connections[i].lScale); - } + TRACE("- CONNECTION[%u]: %s\n", i, debugstr_connection(connections + i)); } static void dump_dmus_wave(DMUS_WAVE *wave) From 1170289e360f8be6a4f22a04e94d2c2a6522c25a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 11 Oct 2023 14:19:24 +0200 Subject: [PATCH 2631/2777] dmsynth: Guard synth members with a CS. (cherry picked from commit a4e933a3abebd1e4022d14f0aa1b812cc153897b) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 45 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 0c85e3cf6b3..52a2143fe73 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -306,6 +306,7 @@ struct synth BOOL open; IDirectMusicSynthSink *sink; + CRITICAL_SECTION cs; struct list instruments; struct list waves; @@ -387,6 +388,10 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) delete_fluid_sfont(This->fluid_sfont); This->fluid_sfont = NULL; delete_fluid_settings(This->fluid_settings); + + This->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->cs); + free(This); } @@ -414,11 +419,21 @@ static HRESULT WINAPI synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *par TRACE("(%p, %p)\n", This, params); - if (This->open) return DMUS_E_ALREADYOPEN; + EnterCriticalSection(&This->cs); + if (This->open) + { + LeaveCriticalSection(&This->cs); + return DMUS_E_ALREADYOPEN; + } if (params) { - if (params->dwSize < sizeof(DMUS_PORTPARAMS7)) return E_INVALIDARG; + if (params->dwSize < sizeof(DMUS_PORTPARAMS7)) + { + LeaveCriticalSection(&This->cs); + return E_INVALIDARG; + } + if (size > params->dwSize) size = params->dwSize; if ((params->dwValidParams & DMUS_PORTPARAMS_VOICES) && params->dwVoices) @@ -476,6 +491,7 @@ static HRESULT WINAPI synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *par This->params = actual; This->open = TRUE; + LeaveCriticalSection(&This->cs); return modified ? S_FALSE : S_OK; } @@ -486,13 +502,18 @@ static HRESULT WINAPI synth_Close(IDirectMusicSynth8 *iface) TRACE("(%p)\n", This); + EnterCriticalSection(&This->cs); if (!This->open) + { + LeaveCriticalSection(&This->cs); return DMUS_E_ALREADYCLOSED; + } fluid_synth_remove_sfont(This->fluid_synth, This->fluid_sfont); delete_fluid_synth(This->fluid_synth); This->fluid_synth = NULL; This->open = FALSE; + LeaveCriticalSection(&This->cs); return S_OK; } @@ -552,14 +573,17 @@ static struct wave *synth_find_wave_from_id(struct synth *This, DWORD id) { struct wave *wave; + EnterCriticalSection(&This->cs); LIST_FOR_EACH_ENTRY(wave, &This->waves, struct wave, entry) { if (wave->id == id) { wave_addref(wave); + LeaveCriticalSection(&This->cs); return wave; } } + LeaveCriticalSection(&This->cs); WARN("Failed to find wave with id %#lx\n", id); return NULL; @@ -630,9 +654,11 @@ static HRESULT synth_download_instrument(struct synth *This, DMUS_DOWNLOADINFO * instrument_info->ulGlobalArtIdx, &instrument->articulations))) goto error; + EnterCriticalSection(&This->cs); list_add_tail(&This->instruments, &instrument->entry); - *ret_handle = instrument; + LeaveCriticalSection(&This->cs); + *ret_handle = instrument; return S_OK; error: @@ -696,9 +722,11 @@ static HRESULT synth_download_wave(struct synth *This, DMUS_DOWNLOADINFO *info, } } + EnterCriticalSection(&This->cs); list_add_tail(&This->waves, &wave->entry); - *ret_handle = wave; + LeaveCriticalSection(&This->cs); + *ret_handle = wave; return S_OK; } @@ -760,11 +788,14 @@ static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE handle, TRACE("(%p)->(%p, %p, %p)\n", This, handle, callback, user_data); if (callback) FIXME("Unload callbacks not implemented\n"); + EnterCriticalSection(&This->cs); LIST_FOR_EACH_ENTRY(instrument, &This->instruments, struct instrument, entry) { if (instrument == handle) { list_remove(&instrument->entry); + LeaveCriticalSection(&This->cs); + instrument_release(instrument); return S_OK; } @@ -775,10 +806,13 @@ static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE handle, if (wave == handle) { list_remove(&wave->entry); + LeaveCriticalSection(&This->cs); + wave_release(wave); return S_OK; } } + LeaveCriticalSection(&This->cs); return E_FAIL; } @@ -1220,6 +1254,9 @@ HRESULT synth_create(IUnknown **ret_iface) goto failed; fluid_sfont_set_data(obj->fluid_sfont, obj); + InitializeCriticalSection(&obj->cs); + obj->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs"); + TRACE("Created DirectMusicSynth %p\n", obj); *ret_iface = (IUnknown *)&obj->IDirectMusicSynth8_iface; return S_OK; From 9ad91bc283275902c9e9850154d33e01d1f5c64b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 11:40:15 +0200 Subject: [PATCH 2632/2777] dmsynth: Parse MIDI events in IDirectMusicSynth_PlayBuffer. (cherry picked from commit d3b5c6bb29e17ab638842be096a6c7b5be93a938) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 56 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 52a2143fe73..d830b2619b8 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -34,6 +34,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); +#define ROUND_ADDR(addr, mask) ((void *)((UINT_PTR)(addr) & ~(UINT_PTR)(mask))) + #define CONN_SRC_CC2 0x0082 #define CONN_SRC_RPN0 0x0100 @@ -294,6 +296,13 @@ static void instrument_release(struct instrument *instrument) } } +struct event +{ + struct list entry; + LONGLONG position; + BYTE midi[3]; +}; + struct synth { IDirectMusicSynth8 IDirectMusicSynth8_iface; @@ -309,6 +318,7 @@ struct synth CRITICAL_SECTION cs; struct list instruments; struct list waves; + struct list events; fluid_settings_t *fluid_settings; fluid_sfont_t *fluid_sfont; @@ -369,6 +379,7 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) if (!ref) { struct instrument *instrument; + struct event *event; struct wave *wave; void *next; @@ -384,6 +395,12 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) wave_release(wave); } + LIST_FOR_EACH_ENTRY_SAFE(event, next, &This->events, struct event, entry) + { + list_remove(&event->entry); + free(event); + } + fluid_sfont_set_data(This->fluid_sfont, NULL); delete_fluid_sfont(This->fluid_sfont); This->fluid_sfont = NULL; @@ -818,11 +835,45 @@ static HRESULT WINAPI synth_Unload(IDirectMusicSynth8 *iface, HANDLE handle, } static HRESULT WINAPI synth_PlayBuffer(IDirectMusicSynth8 *iface, - REFERENCE_TIME rt, BYTE *buffer, DWORD size) + REFERENCE_TIME time, BYTE *buffer, DWORD size) { struct synth *This = impl_from_IDirectMusicSynth8(iface); + DMUS_EVENTHEADER *head = (DMUS_EVENTHEADER *)buffer; + BYTE *end = buffer + size, *data; + HRESULT hr; + + TRACE("(%p, %I64d, %p, %lu)\n", This, time, buffer, size); + + while ((data = (BYTE *)(head + 1)) < end) + { + DMUS_EVENTHEADER *next = ROUND_ADDR(data + head->cbEvent + 7, 7); + struct event *event, *next_event; + LONGLONG position; + + if ((BYTE *)next > end) return E_INVALIDARG; + if (FAILED(hr = IDirectMusicSynthSink_RefTimeToSample(This->sink, + time + head->rtDelta, &position))) + return hr; + + if (!(head->dwFlags & DMUS_EVENT_STRUCTURED)) + FIXME("Unstructured events not implemeted\n"); + else if (head->cbEvent > 3) + FIXME("Unexpected MIDI event size %lu\n", head->cbEvent); + else + { + if (!(event = calloc(1, sizeof(*event)))) return E_OUTOFMEMORY; + memcpy(event->midi, data, head->cbEvent); + event->position = position; + + EnterCriticalSection(&This->cs); + LIST_FOR_EACH_ENTRY(next_event, &This->events, struct event, entry) + if (next_event->position >= event->position) break; + list_add_before(&next_event->entry, &event->entry); + LeaveCriticalSection(&This->cs); + } - FIXME("(%p, 0x%s, %p, %lu): stub\n", This, wine_dbgstr_longlong(rt), buffer, size); + head = next; + } return S_OK; } @@ -1247,6 +1298,7 @@ HRESULT synth_create(IUnknown **ret_iface) list_init(&obj->instruments); list_init(&obj->waves); + list_init(&obj->events); if (!(obj->fluid_settings = new_fluid_settings())) goto failed; if (!(obj->fluid_sfont = new_fluid_sfont(synth_sfont_get_name, synth_sfont_get_preset, From f31ba9870e74f1a532eec70c00c31ab37223bb59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 11:40:15 +0200 Subject: [PATCH 2633/2777] dmsynth: Play some MIDI events in IDirectMusicSynth_Render. (cherry picked from commit 07aa6b5dcbfc29d95c3ba0f37249c9432f216c26) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 45 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index d830b2619b8..6516d3ceeeb 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -982,9 +982,52 @@ static HRESULT WINAPI synth_Render(IDirectMusicSynth8 *iface, short *buffer, DWORD length, LONGLONG position) { struct synth *This = impl_from_IDirectMusicSynth8(iface); + struct event *event, *next; - FIXME("(%p, %p, %ld, 0x%s): stub\n", This, buffer, length, wine_dbgstr_longlong(position)); + TRACE("(%p, %p, %ld, %I64d)\n", This, buffer, length, position); + EnterCriticalSection(&This->cs); + LIST_FOR_EACH_ENTRY_SAFE(event, next, &This->events, struct event, entry) + { + BYTE status = event->midi[0] & 0xf0, chan = event->midi[0] & 0x0f; + LONGLONG offset = event->position - position; + + if (offset >= length) break; + if (offset > 0) + { + fluid_synth_write_s16(This->fluid_synth, offset, buffer, 0, 2, buffer, 1, 2); + buffer += offset * 2; + position += offset; + length -= offset; + } + + TRACE("status %#x chan %#x midi %#x %#x\n", status, chan, event->midi[1], event->midi[2]); + + switch (status) + { + case 0x80: + fluid_synth_noteoff(This->fluid_synth, chan, event->midi[1]); + break; + case 0x90: + fluid_synth_noteon(This->fluid_synth, chan, event->midi[1], event->midi[2]); + break; + case 0xb0: + fluid_synth_cc(This->fluid_synth, chan, event->midi[1], event->midi[2]); + break; + case 0xc0: + fluid_synth_program_change(This->fluid_synth, chan, event->midi[1]); + break; + default: + FIXME("MIDI event not implemented: %#x %#x %#x\n", event->midi[0], event->midi[1], event->midi[2]); + break; + } + + list_remove(&event->entry); + free(event); + } + LeaveCriticalSection(&This->cs); + + if (length) fluid_synth_write_s16(This->fluid_synth, length, buffer, 0, 2, buffer, 1, 2); return S_OK; } From ca279ff3479f33b278d2f8d1171fb554b6525bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 8 Sep 2023 09:49:06 +0200 Subject: [PATCH 2634/2777] dmsynth: Create fluid_preset and fluid_voice from instrument. (cherry picked from commit ccc5af8bf893c81a624a4d6f78a3b8e2ac5e7bbf) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 302 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 299 insertions(+), 3 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 6516d3ceeeb..af578610c16 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -39,6 +39,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); #define CONN_SRC_CC2 0x0082 #define CONN_SRC_RPN0 0x0100 +#define CONN_TRN_BIPOLAR (1<<4) +#define CONN_TRN_INVERT (1<<5) + static const char *debugstr_conn_src(UINT src) { switch (src) @@ -270,6 +273,11 @@ struct instrument struct synth *synth; }; +static void instrument_addref(struct instrument *instrument) +{ + InterlockedIncrement(&instrument->ref); +} + static void instrument_release(struct instrument *instrument) { ULONG ref = InterlockedDecrement(&instrument->ref); @@ -1277,6 +1285,277 @@ static const IKsControlVtbl synth_control_vtbl = synth_control_KsEvent, }; +static const char *synth_preset_get_name(fluid_preset_t *fluid_preset) +{ + return "DirectMusicSynth"; +} + +static int synth_preset_get_bank(fluid_preset_t *fluid_preset) +{ + TRACE("(%p)\n", fluid_preset); + return 0; +} + +static int synth_preset_get_num(fluid_preset_t *fluid_preset) +{ + struct instrument *instrument = fluid_preset_get_data(fluid_preset); + + TRACE("(%p)\n", fluid_preset); + + if (!instrument) return 0; + return instrument->patch; +} + +static BOOL fluid_gen_from_connection(CONNECTION *conn, UINT *gen) +{ + switch (conn->usDestination) + { + case CONN_DST_FILTER_CUTOFF: *gen = GEN_FILTERFC; return TRUE; + case CONN_DST_FILTER_Q: *gen = GEN_FILTERQ; return TRUE; + case CONN_DST_CHORUS: *gen = GEN_CHORUSSEND; return TRUE; + case CONN_DST_REVERB: *gen = GEN_REVERBSEND; return TRUE; + case CONN_DST_PAN: *gen = GEN_PAN; return TRUE; + case CONN_DST_LFO_STARTDELAY: *gen = GEN_MODLFODELAY; return TRUE; + case CONN_DST_LFO_FREQUENCY: *gen = GEN_MODLFOFREQ; return TRUE; + case CONN_DST_VIB_STARTDELAY: *gen = GEN_VIBLFODELAY; return TRUE; + case CONN_DST_VIB_FREQUENCY: *gen = GEN_VIBLFOFREQ; return TRUE; + case CONN_DST_EG2_DELAYTIME: *gen = GEN_MODENVDELAY; return TRUE; + case CONN_DST_EG2_ATTACKTIME: *gen = GEN_MODENVATTACK; return TRUE; + case CONN_DST_EG2_HOLDTIME: *gen = GEN_MODENVHOLD; return TRUE; + case CONN_DST_EG2_DECAYTIME: *gen = GEN_MODENVDECAY; return TRUE; + case CONN_DST_EG2_SUSTAINLEVEL: *gen = GEN_MODENVSUSTAIN; return TRUE; + case CONN_DST_EG2_RELEASETIME: *gen = GEN_MODENVRELEASE; return TRUE; + case CONN_DST_EG1_DELAYTIME: *gen = GEN_VOLENVDELAY; return TRUE; + case CONN_DST_EG1_ATTACKTIME: *gen = GEN_VOLENVATTACK; return TRUE; + case CONN_DST_EG1_HOLDTIME: *gen = GEN_VOLENVHOLD; return TRUE; + case CONN_DST_EG1_DECAYTIME: *gen = GEN_VOLENVDECAY; return TRUE; + case CONN_DST_EG1_SUSTAINLEVEL: *gen = GEN_VOLENVSUSTAIN; return TRUE; + case CONN_DST_EG1_RELEASETIME: *gen = GEN_VOLENVRELEASE; return TRUE; + case CONN_DST_GAIN: *gen = GEN_ATTENUATION; return TRUE; + case CONN_DST_PITCH: *gen = GEN_PITCH; return TRUE; + default: FIXME("Unsupported connection %s\n", debugstr_connection(conn)); return FALSE; + } +} + +static BOOL set_gen_from_connection(fluid_voice_t *fluid_voice, CONNECTION *conn) +{ + UINT gen; + + if (conn->usControl != CONN_SRC_NONE) return FALSE; + if (conn->usTransform != CONN_TRN_NONE) return FALSE; + + if (conn->usSource == CONN_SRC_NONE) + { + if (!fluid_gen_from_connection(conn, &gen)) return FALSE; + } + if (conn->usSource == CONN_SRC_KEYNUMBER) + { + switch (conn->usDestination) + { + case CONN_DST_EG2_HOLDTIME: gen = GEN_KEYTOMODENVHOLD; break; + case CONN_DST_EG2_DECAYTIME: gen = GEN_KEYTOMODENVDECAY; break; + case CONN_DST_EG1_HOLDTIME: gen = GEN_KEYTOVOLENVHOLD; break; + case CONN_DST_EG1_DECAYTIME: gen = GEN_KEYTOVOLENVDECAY; break; + default: return FALSE; + } + } + else if (conn->usSource == CONN_SRC_LFO) + { + switch (conn->usDestination) + { + case CONN_DST_PITCH: gen = GEN_MODLFOTOPITCH; break; + case CONN_DST_FILTER_CUTOFF: gen = GEN_MODLFOTOFILTERFC; break; + case CONN_DST_GAIN: gen = GEN_MODLFOTOVOL; break; + default: return FALSE; + } + } + else if (conn->usSource == CONN_SRC_EG2) + { + switch (conn->usDestination) + { + case CONN_DST_PITCH: gen = GEN_MODENVTOPITCH; break; + case CONN_DST_FILTER_CUTOFF: gen = GEN_MODENVTOFILTERFC; break; + default: return FALSE; + } + } + else if (conn->usSource == CONN_SRC_VIBRATO) + { + switch (conn->usDestination) + { + case CONN_DST_PITCH: gen = GEN_VIBLFOTOPITCH; break; + default: return FALSE; + } + } + else + { + return FALSE; + } + + fluid_voice_gen_set(fluid_voice, gen, conn->lScale); + return TRUE; +} + +static BOOL fluid_source_from_connection(USHORT source, USHORT transform, UINT *fluid_source, UINT *fluid_flags) +{ + UINT flags = FLUID_MOD_GC; + if (source >= CONN_SRC_CC1 && source <= CONN_SRC_CC1 + 0x7f) + { + *fluid_source = source; + flags = FLUID_MOD_CC; + } + else switch (source) + { + case CONN_SRC_NONE: *fluid_source = FLUID_MOD_NONE; break; + case CONN_SRC_KEYONVELOCITY: *fluid_source = FLUID_MOD_VELOCITY; break; + case CONN_SRC_KEYNUMBER: *fluid_source = FLUID_MOD_KEY; break; + case CONN_SRC_PITCHWHEEL: *fluid_source = FLUID_MOD_PITCHWHEEL; break; + case CONN_SRC_POLYPRESSURE: *fluid_source = FLUID_MOD_KEYPRESSURE; break; + case CONN_SRC_CHANNELPRESSURE: *fluid_source = FLUID_MOD_CHANNELPRESSURE; break; + case CONN_SRC_RPN0: *fluid_source = FLUID_MOD_PITCHWHEELSENS; break; + default: return FALSE; + } + + if (transform & CONN_TRN_INVERT) flags |= FLUID_MOD_NEGATIVE; + if (transform & CONN_TRN_BIPOLAR) flags |= FLUID_MOD_BIPOLAR; + switch (transform & CONN_TRN_SWITCH) + { + case CONN_TRN_NONE: flags |= FLUID_MOD_LINEAR; break; + case CONN_TRN_CONCAVE: flags |= FLUID_MOD_CONCAVE; break; + case CONN_TRN_CONVEX: flags |= FLUID_MOD_CONVEX; break; + case CONN_TRN_SWITCH: flags |= FLUID_MOD_SWITCH; break; + } + + *fluid_flags = flags; + return TRUE; +} + +static BOOL add_mod_from_connection(fluid_voice_t *fluid_voice, CONNECTION *conn, UINT src1, UINT flags1, + UINT src2, UINT flags2) +{ + fluid_mod_t *mod; + UINT gen = -1; + + switch (MAKELONG(conn->usSource, conn->usDestination)) + { + case MAKELONG(CONN_SRC_LFO, CONN_DST_PITCH): gen = GEN_MODLFOTOPITCH; break; + case MAKELONG(CONN_SRC_VIBRATO, CONN_DST_PITCH): gen = GEN_VIBLFOTOPITCH; break; + case MAKELONG(CONN_SRC_EG2, CONN_DST_PITCH): gen = GEN_MODENVTOPITCH; break; + case MAKELONG(CONN_SRC_LFO, CONN_DST_FILTER_CUTOFF): gen = GEN_MODLFOTOFILTERFC; break; + case MAKELONG(CONN_SRC_EG2, CONN_DST_FILTER_CUTOFF): gen = GEN_MODENVTOFILTERFC; break; + case MAKELONG(CONN_SRC_LFO, CONN_DST_GAIN): gen = GEN_MODLFOTOVOL; break; + case MAKELONG(CONN_SRC_KEYNUMBER, CONN_DST_EG2_HOLDTIME): gen = GEN_KEYTOMODENVHOLD; break; + case MAKELONG(CONN_SRC_KEYNUMBER, CONN_DST_EG2_DECAYTIME): gen = GEN_KEYTOMODENVDECAY; break; + case MAKELONG(CONN_SRC_KEYNUMBER, CONN_DST_EG1_HOLDTIME): gen = GEN_KEYTOVOLENVHOLD; break; + case MAKELONG(CONN_SRC_KEYNUMBER, CONN_DST_EG1_DECAYTIME): gen = GEN_KEYTOVOLENVDECAY; break; + } + + if (conn->usControl != CONN_SRC_NONE && gen != -1) + { + src1 = src2; + flags1 = flags2; + src2 = 0; + flags2 = 0; + } + + if (gen == -1 && !fluid_gen_from_connection(conn, &gen)) return FALSE; + + if (!(mod = new_fluid_mod())) return FALSE; + fluid_mod_set_source1(mod, src1, flags1); + fluid_mod_set_source2(mod, src2, flags2); + fluid_mod_set_dest(mod, gen); + fluid_mod_set_amount(mod, conn->lScale); + fluid_voice_add_mod(fluid_voice, mod, FLUID_VOICE_OVERWRITE); + + return TRUE; +} + +static void fluid_voice_add_articulation(fluid_voice_t *fluid_voice, struct articulation *articulation) +{ + UINT i; + + for (i = 0; i < articulation->list.cConnections; i++) + { + UINT src1 = FLUID_MOD_NONE, flags1 = 0, src2 = FLUID_MOD_NONE, flags2 = 0; + CONNECTION *conn = articulation->connections + i; + + if (set_gen_from_connection(fluid_voice, conn)) continue; + + if (!fluid_source_from_connection(conn->usSource, (conn->usTransform >> 10) & 0x3f, + &src1, &flags1)) + continue; + if (!fluid_source_from_connection(conn->usControl, (conn->usControl >> 4) & 0x3f, + &src2, &flags2)) + continue; + add_mod_from_connection(fluid_voice, conn, src1, flags1, src2, flags2); + } +} + +static void fluid_voice_add_articulations(fluid_voice_t *fluid_voice, struct list *list) +{ + struct articulation *articulation; + + LIST_FOR_EACH_ENTRY(articulation, list, struct articulation, entry) + fluid_voice_add_articulation(fluid_voice, articulation); +} + +static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *fluid_synth, int chan, int key, int vel) +{ + struct instrument *instrument = fluid_preset_get_data(fluid_preset); + struct synth *synth = instrument->synth; + fluid_sample_t *fluid_sample; + fluid_voice_t *fluid_voice; + struct region *region; + + TRACE("(%p, %p, %u, %u, %u)\n", fluid_preset, fluid_synth, chan, key, vel); + + if (!instrument) return FLUID_FAILED; + + LIST_FOR_EACH_ENTRY(region, &instrument->regions, struct region, entry) + { + struct wave *wave = region->wave; + + if (key < region->key_range.usLow || key > region->key_range.usHigh) continue; + if (vel < region->vel_range.usLow || vel > region->vel_range.usHigh) continue; + + if (!(fluid_sample = new_fluid_sample())) + { + WARN("Failed to allocate FluidSynth sample\n"); + return FLUID_FAILED; + } + + fluid_sample_set_sound_data(fluid_sample, wave->samples, NULL, wave->sample_count, + wave->format.nSamplesPerSec, TRUE); + if (region->wave_sample.cSampleLoops) + { + WLOOP *loop = region->wave_loops; + fluid_sample_set_loop(fluid_sample, loop->ulStart, loop->ulStart + loop->ulLength); + } + fluid_sample_set_pitch(fluid_sample, region->wave_sample.usUnityNote, region->wave_sample.sFineTune); + + if (!(fluid_voice = fluid_synth_alloc_voice(synth->fluid_synth, fluid_sample, chan, key, vel))) + { + WARN("Failed to allocate FluidSynth voice\n"); + delete_fluid_sample(fluid_sample); + return FLUID_FAILED; + } + + fluid_voice_add_articulations(fluid_voice, &instrument->articulations); + fluid_voice_add_articulations(fluid_voice, ®ion->articulations); + fluid_synth_start_voice(synth->fluid_synth, fluid_voice); + return FLUID_OK; + } + + WARN("Failed to find instrument matching note / velocity\n"); + return FLUID_FAILED; +} + +static void synth_preset_free(fluid_preset_t *fluid_preset) +{ + struct instrument *instrument = fluid_preset_get_data(fluid_preset); + fluid_preset_set_data(fluid_preset, NULL); + if (instrument) instrument_release(instrument); +} + static const char *synth_sfont_get_name(fluid_sfont_t *fluid_sfont) { return "DirectMusicSynth"; @@ -1286,17 +1565,34 @@ static fluid_preset_t *synth_sfont_get_preset(fluid_sfont_t *fluid_sfont, int ba { struct synth *synth = fluid_sfont_get_data(fluid_sfont); struct instrument *instrument; + fluid_preset_t *fluid_preset; TRACE("(%p, %d, %d)\n", fluid_sfont, bank, patch); if (!synth) return NULL; + EnterCriticalSection(&synth->cs); + LIST_FOR_EACH_ENTRY(instrument, &synth->instruments, struct instrument, entry) if (instrument->patch == patch) break; - if (&instrument->entry == &synth->instruments) return NULL; - FIXME("Preset not implemented yet\n"); - return NULL; + if (&instrument->entry == &synth->instruments) + { + fluid_preset = NULL; + WARN("Could not find instrument with patch %#x\n", patch); + } + else if ((fluid_preset = new_fluid_preset(fluid_sfont, synth_preset_get_name, synth_preset_get_bank, + synth_preset_get_num, synth_preset_noteon, synth_preset_free))) + { + fluid_preset_set_data(fluid_preset, instrument); + instrument_addref(instrument); + + TRACE("Created fluid_preset %p for instrument %p\n", fluid_preset, instrument); + } + + LeaveCriticalSection(&synth->cs); + + return fluid_preset; } static void synth_sfont_iter_start(fluid_sfont_t *fluid_sfont) From f16356faf43f7de40af5f3d7669d21a873736bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 10 Sep 2023 14:41:51 +0200 Subject: [PATCH 2635/2777] dmband: Download / unload bands when initializing / ending band track. (cherry picked from commit b0573f9dc3aab086069a16b97dc1d04ae2709cb9) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/bandtrack.c | 39 +++++++++++++++++++++++++++++++++----- dlls/dmband/tests/dmband.c | 2 -- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index 845345a9fa2..6233d39b9c0 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -104,10 +104,13 @@ static ULONG WINAPI band_track_Release(IDirectMusicTrack8 *iface) return ref; } -static HRESULT WINAPI band_track_Init(IDirectMusicTrack8 *iface, IDirectMusicSegment *pSegment) +static HRESULT WINAPI band_track_Init(IDirectMusicTrack8 *iface, IDirectMusicSegment *segment) { struct band_track *This = impl_from_IDirectMusicTrack8(iface); - FIXME("(%p, %p): stub\n", This, pSegment); + + FIXME("(%p, %p): stub\n", This, segment); + + if (!segment) return E_POINTER; return S_OK; } @@ -116,16 +119,42 @@ static HRESULT WINAPI band_track_InitPlay(IDirectMusicTrack8 *iface, void **state_data, DWORD virtual_track8id, DWORD flags) { struct band_track *This = impl_from_IDirectMusicTrack8(iface); + struct band_entry *entry; + HRESULT hr; + + FIXME("(%p, %p, %p, %p, %ld, %lx): semi-stub\n", This, segment_state, performance, state_data, virtual_track8id, flags); + + if (!performance) return E_POINTER; - FIXME("(%p, %p, %p, %p, %ld, %lx): stub\n", This, segment_state, performance, state_data, virtual_track8id, flags); + if (This->header.bAutoDownload) + { + LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry) + { + if (FAILED(hr = IDirectMusicBand_Download(entry->band, performance))) + return hr; + } + } return S_OK; } -static HRESULT WINAPI band_track_EndPlay(IDirectMusicTrack8 *iface, void *pStateData) +static HRESULT WINAPI band_track_EndPlay(IDirectMusicTrack8 *iface, void *state_data) { struct band_track *This = impl_from_IDirectMusicTrack8(iface); - FIXME("(%p, %p): stub\n", This, pStateData); + struct band_entry *entry; + HRESULT hr; + + FIXME("(%p, %p): semi-stub\n", This, state_data); + + if (This->header.bAutoDownload) + { + LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry) + { + if (FAILED(hr = IDirectMusicBand_Unload(entry->band, NULL))) + return hr; + } + } + return S_OK; } diff --git a/dlls/dmband/tests/dmband.c b/dlls/dmband/tests/dmband.c index 07ffcf4e7fe..ee45ca33714 100644 --- a/dlls/dmband/tests/dmband.c +++ b/dlls/dmband/tests/dmband.c @@ -226,12 +226,10 @@ static void test_bandtrack(void) ok(hr == S_OK, "DirectMusicBandTrack create failed: %#lx, expected S_OK\n", hr); /* IDirectMusicTrack8 */ - todo_wine { hr = IDirectMusicTrack8_Init(dmt8, NULL); ok(hr == E_POINTER, "IDirectMusicTrack8_Init failed: %#lx\n", hr); hr = IDirectMusicTrack8_InitPlay(dmt8, NULL, NULL, NULL, 0, 0); ok(hr == E_POINTER, "IDirectMusicTrack8_InitPlay failed: %#lx\n", hr); - } hr = IDirectMusicTrack8_EndPlay(dmt8, NULL); ok(hr == S_OK, "IDirectMusicTrack8_EndPlay failed: %#lx\n", hr); hr = IDirectMusicTrack8_Play(dmt8, NULL, 0, 0, 0, 0, NULL, NULL, 0); From 87a5a594822c9370707d046fd4531206cfaa14f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 11 Sep 2023 00:04:46 +0200 Subject: [PATCH 2636/2777] dmime: Implement sequence track IDirectMusicTrack_Play. (cherry picked from commit fd68076c36555d97593213a024d6ab6246de6e52) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/seqtrack.c | 95 +++++++++++++++++++++++++++++++++++++--- dlls/dmime/tests/dmime.c | 13 +----- 2 files changed, 91 insertions(+), 17 deletions(-) diff --git a/dlls/dmime/seqtrack.c b/dlls/dmime/seqtrack.c index 21b78ff26cd..a6043cb4a89 100644 --- a/dlls/dmime/seqtrack.c +++ b/dlls/dmime/seqtrack.c @@ -108,13 +108,96 @@ static HRESULT WINAPI sequence_track_EndPlay(IDirectMusicTrack8 *iface, void *pS return S_OK; } -static HRESULT WINAPI sequence_track_Play(IDirectMusicTrack8 *iface, void *pStateData, - MUSIC_TIME mtStart, MUSIC_TIME mtEnd, MUSIC_TIME mtOffset, DWORD dwFlags, - IDirectMusicPerformance *pPerf, IDirectMusicSegmentState *pSegSt, DWORD dwVirtualID) +static HRESULT WINAPI sequence_track_Play(IDirectMusicTrack8 *iface, void *state_data, + MUSIC_TIME start_time, MUSIC_TIME end_time, MUSIC_TIME time_offset, DWORD segment_flags, + IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state, DWORD track_id) { - struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); - FIXME("(%p, %p, %ld, %ld, %ld, %ld, %p, %p, %ld): stub\n", This, pStateData, mtStart, mtEnd, mtOffset, dwFlags, pPerf, pSegSt, dwVirtualID); - return S_OK; + struct sequence_track *This = impl_from_IDirectMusicTrack8(iface); + IDirectMusicGraph *graph; + HRESULT hr; + UINT i; + + TRACE("(%p, %p, %ld, %ld, %ld, %#lx, %p, %p, %ld)\n", This, state_data, start_time, end_time, + time_offset, segment_flags, performance, segment_state, track_id); + + if (start_time != 0) FIXME("start_time %ld not implemented\n", start_time); + if (end_time != -1) FIXME("end_time %ld not implemented\n", end_time); + if (time_offset != 0) FIXME("time_offset %ld not implemented\n", time_offset); + if (segment_flags) FIXME("segment_flags %#lx not implemented\n", segment_flags); + if (segment_state) FIXME("segment_state %p not implemented\n", segment_state); + + if (FAILED(hr = IDirectMusicPerformance_QueryInterface(performance, + &IID_IDirectMusicGraph, (void **)&graph))) + return hr; + + for (i = 0; SUCCEEDED(hr) &&i < This->count; i++) + { + DMUS_IO_SEQ_ITEM *item = This->items + i; + DMUS_NOTE_PMSG *msg; + + if (FAILED(hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(*msg), + (DMUS_PMSG **)&msg))) + break; + + msg->mtTime = item->mtTime; + msg->dwFlags = DMUS_PMSGF_MUSICTIME; + msg->dwPChannel = item->dwPChannel; + msg->dwVirtualTrackID = track_id; + msg->dwType = DMUS_PMSGT_NOTE; + msg->dwGroupID = 1; + msg->mtDuration = item->mtDuration; + msg->wMusicValue = item->bByte1; + msg->nOffset = item->nOffset; + msg->bVelocity = item->bByte2; + msg->bFlags = 1; + msg->bMidiValue = item->bByte1; + + if (FAILED(hr = IDirectMusicGraph_StampPMsg(graph, (DMUS_PMSG *)msg)) + || FAILED(hr = IDirectMusicPerformance_SendPMsg(performance, (DMUS_PMSG *)msg))) + { + IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)msg); + break; + } + } + + for (i = 0; SUCCEEDED(hr) &&i < This->curve_count; i++) + { + DMUS_IO_CURVE_ITEM *item = This->curve_items + i; + DMUS_CURVE_PMSG *msg; + + if (FAILED(hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(*msg), + (DMUS_PMSG **)&msg))) + break; + + msg->mtTime = item->mtStart; + msg->dwFlags = DMUS_PMSGF_MUSICTIME; + msg->dwPChannel = item->dwPChannel; + msg->dwVirtualTrackID = track_id; + msg->dwType = DMUS_PMSGT_CURVE; + msg->mtDuration = item->mtDuration; + msg->mtOriginalStart = item->mtStart; + msg->mtResetDuration = item->mtResetDuration; + msg->nStartValue = item->nStartValue; + msg->nEndValue = item->nEndValue; + msg->nResetValue = item->nResetValue; + msg->nOffset = item->nOffset; + msg->bType = item->bType; + msg->bCurveShape = item->bCurveShape; + msg->bCCData = item->bCCData; + msg->bFlags = item->bFlags; + msg->wParamType = item->wParamType; + msg->wMergeIndex = item->wMergeIndex; + + if (FAILED(hr = IDirectMusicGraph_StampPMsg(graph, (DMUS_PMSG *)msg)) + || FAILED(hr = IDirectMusicPerformance_SendPMsg(performance, (DMUS_PMSG *)msg))) + { + IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)msg); + break; + } + } + + IDirectMusicGraph_Release(graph); + return hr; } static HRESULT WINAPI sequence_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 412cccce781..6881eac80c6 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3502,30 +3502,21 @@ static void test_sequence_track(void) ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬e); ok(!ret, "got %#lx\n", ret); - if (note->dwType == DMUS_PMSGT_NOTE) - { check_dmus_note_pmsg(note, 0, 0, 500, 60, 120); - } hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)note); ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬e); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); check_dmus_note_pmsg(note, 1000, 1, 200, 50, 100); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)note); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, &msg); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); - } IDirectMusicSegment_Release(segment); From 5142de0278b1439499ca4a4652463fea741eaffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 12 Oct 2023 09:02:05 +0200 Subject: [PATCH 2637/2777] dmime: Implement band track IDirectMusicTrack_Play. (cherry picked from commit e3b23cb66eaf0f63ce9ab351c1d7da1af0017225) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/band.c | 34 ++++++++++++++++++++++++++++++++ dlls/dmband/bandtrack.c | 38 +++++++++++++++++++++++++----------- dlls/dmband/dmband_private.h | 2 ++ dlls/dmband/tests/dmband.c | 1 - dlls/dmime/tests/dmime.c | 18 +++-------------- 5 files changed, 66 insertions(+), 27 deletions(-) diff --git a/dlls/dmband/band.c b/dlls/dmband/band.c index 4b3c053c586..456bb20143e 100644 --- a/dlls/dmband/band.c +++ b/dlls/dmband/band.c @@ -486,3 +486,37 @@ HRESULT band_connect_to_collection(IDirectMusicBand *iface, IDirectMusicCollecti return S_OK; } + +HRESULT band_send_messages(IDirectMusicBand *iface, IDirectMusicPerformance *performance, + IDirectMusicGraph *graph, MUSIC_TIME time, DWORD track_id) +{ + struct band *This = impl_from_IDirectMusicBand(iface); + struct instrument_entry *entry; + HRESULT hr = S_OK; + + LIST_FOR_EACH_ENTRY_REV(entry, &This->instruments, struct instrument_entry, entry) + { + DMUS_PATCH_PMSG *msg; + + if (FAILED(hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(*msg), + (DMUS_PMSG **)&msg))) + break; + + msg->mtTime = time; + msg->dwFlags = DMUS_PMSGF_MUSICTIME; + msg->dwPChannel = entry->instrument.dwPChannel; + msg->dwVirtualTrackID = track_id; + msg->dwType = DMUS_PMSGT_PATCH; + msg->dwGroupID = 1; + msg->byInstrument = entry->instrument.dwPatch; + + if (FAILED(hr = IDirectMusicGraph_StampPMsg(graph, (DMUS_PMSG *)msg)) + || FAILED(hr = IDirectMusicPerformance_SendPMsg(performance, (DMUS_PMSG *)msg))) + { + IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)msg); + break; + } + } + + return hr; +} diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index 6233d39b9c0..e0acb6ff62d 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -159,22 +159,38 @@ static HRESULT WINAPI band_track_EndPlay(IDirectMusicTrack8 *iface, void *state_ } static HRESULT WINAPI band_track_Play(IDirectMusicTrack8 *iface, void *state_data, - MUSIC_TIME mtStart, MUSIC_TIME mtEnd, MUSIC_TIME mtOffset, DWORD flags, - IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state, - DWORD virtual_id) + MUSIC_TIME start_time, MUSIC_TIME end_time, MUSIC_TIME time_offset, DWORD segment_flags, + IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state, DWORD track_id) { struct band_track *This = impl_from_IDirectMusicTrack8(iface); + IDirectMusicGraph *graph; + struct band_entry *entry; + HRESULT hr; - FIXME("(%p, %p, %ld, %ld, %ld, %lx, %p, %p, %ld): semi-stub\n", This, state_data, mtStart, mtEnd, mtOffset, flags, performance, segment_state, virtual_id); + TRACE("(%p, %p, %ld, %ld, %ld, %#lx, %p, %p, %ld)\n", This, state_data, start_time, end_time, + time_offset, segment_flags, performance, segment_state, track_id); - /* Sends following pMSG: - - DMUS_PATCH_PMSG - - DMUS_TRANSPOSE_PMSG - - DMUS_CHANNEL_PRIORITY_PMSG - - DMUS_MIDI_PMSG - */ + if (!performance) return DMUS_S_END; - return S_OK; + if (start_time != 0) FIXME("start_time %ld not implemented\n", start_time); + if (end_time != -1) FIXME("end_time %ld not implemented\n", end_time); + if (time_offset != 0) FIXME("time_offset %ld not implemented\n", time_offset); + if (segment_flags) FIXME("segment_flags %#lx not implemented\n", segment_flags); + if (segment_state) FIXME("segment_state %p not implemented\n", segment_state); + + if (FAILED(hr = IDirectMusicPerformance_QueryInterface(performance, + &IID_IDirectMusicGraph, (void **)&graph))) + return hr; + + LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry) + { + if (FAILED(hr = band_send_messages(entry->band, performance, graph, + entry->head.lBandTimeLogical, track_id))) + break; + } + + IDirectMusicGraph_Release(graph); + return hr; } static HRESULT WINAPI band_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time, diff --git a/dlls/dmband/dmband_private.h b/dlls/dmband/dmband_private.h index a12b9f8cc82..48c5ec02aeb 100644 --- a/dlls/dmband/dmband_private.h +++ b/dlls/dmband/dmband_private.h @@ -48,5 +48,7 @@ extern HRESULT create_dmband(REFIID riid, void **ret_iface); extern HRESULT create_dmbandtrack(REFIID riid, void **ret_iface); extern HRESULT band_connect_to_collection(IDirectMusicBand *iface, IDirectMusicCollection *collection); +extern HRESULT band_send_messages(IDirectMusicBand *iface, IDirectMusicPerformance *performance, + IDirectMusicGraph *graph, MUSIC_TIME time, DWORD track_id); #endif /* __WINE_DMBAND_PRIVATE_H */ diff --git a/dlls/dmband/tests/dmband.c b/dlls/dmband/tests/dmband.c index ee45ca33714..d88606976e4 100644 --- a/dlls/dmband/tests/dmband.c +++ b/dlls/dmband/tests/dmband.c @@ -233,7 +233,6 @@ static void test_bandtrack(void) hr = IDirectMusicTrack8_EndPlay(dmt8, NULL); ok(hr == S_OK, "IDirectMusicTrack8_EndPlay failed: %#lx\n", hr); hr = IDirectMusicTrack8_Play(dmt8, NULL, 0, 0, 0, 0, NULL, NULL, 0); - todo_wine ok(hr == DMUS_S_END, "IDirectMusicTrack8_Play failed: %#lx\n", hr); hr = IDirectMusicTrack8_GetParam(dmt8, NULL, 0, NULL, NULL); ok(hr == E_POINTER, "IDirectMusicTrack8_GetParam failed: %#lx\n", hr); diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 6881eac80c6..6dc9d8e0f5e 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3756,39 +3756,27 @@ static void test_band_track_play(void) ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&patch); ok(!ret, "got %#lx\n", ret); - if (patch->dwType == DMUS_PMSGT_PATCH) - { check_dmus_patch_pmsg(patch, 0, 1, 0, 1); - } hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)patch); ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&patch); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); check_dmus_patch_pmsg(patch, 1000, 2, 0, 3); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)patch); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&patch); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); check_dmus_patch_pmsg(patch, 1000, 1, 0, 2); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)patch); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, &msg); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); - } IDirectMusicSegment_Release(segment); From 2752e137788720d70abedc70007d1a39797f62d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 6 Sep 2023 09:44:26 +0200 Subject: [PATCH 2638/2777] dmime: Output DMUS_MIDI_PMSG into a music buffer on the port. (cherry picked from commit a4b006e723528036822f241911533bd6e8f67062) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 2018fa013de..782f300eb4b 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1637,6 +1637,39 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, switch (msg->dwType) { + case DMUS_PMSGT_MIDI: + { + static const UINT event_size = sizeof(DMUS_EVENTHEADER) + sizeof(DWORD); + DMUS_BUFFERDESC desc = {.dwSize = sizeof(desc), .cbBuffer = 2 * event_size}; + DMUS_MIDI_PMSG *midi = (DMUS_MIDI_PMSG *)msg; + IDirectMusicBuffer *buffer; + IDirectMusicPort *port; + DWORD group, channel; + UINT value = 0; + + if (FAILED(hr = IDirectMusicPerformance_PChannelInfo(performance, msg->dwPChannel, + &port, &group, &channel))) + { + WARN("Failed to get message port, hr %#lx\n", hr); + return DMUS_S_FREE; + } + + value |= channel; + value |= (UINT)midi->bStatus; + value |= (UINT)midi->bByte1 << 8; + value |= (UINT)midi->bByte2 << 16; + + if (SUCCEEDED(hr = IDirectMusic_CreateMusicBuffer(This->dmusic, &desc, &buffer, NULL))) + { + hr = IDirectMusicBuffer_PackStructured(buffer, msg->rtTime, group, value); + if (SUCCEEDED(hr)) hr = IDirectMusicPort_PlayBuffer(port, buffer); + IDirectMusicBuffer_Release(buffer); + } + + IDirectMusicPort_Release(port); + break; + } + case DMUS_PMSGT_NOTIFICATION: { DMUS_NOTIFICATION_PMSG *notif = (DMUS_NOTIFICATION_PMSG *)msg; From 9f36d033245164d5dfb72d2b9e66580d5233a631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 21 Sep 2023 15:54:22 +0200 Subject: [PATCH 2639/2777] dmime: Translate DMUS_PMSGT_NOTE to DMUS_PMSGT_MIDI messages. (cherry picked from commit f74fe2e26b45f8f557eb121be260a3a81b1f6f29) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 45 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 782f300eb4b..b12a8315330 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1626,6 +1626,35 @@ static HRESULT WINAPI performance_tool_GetMediaTypes(IDirectMusicTool *iface, DW return E_NOTIMPL; } +static HRESULT performance_send_midi_pmsg(struct performance *This, DMUS_PMSG *msg, UINT flags, + BYTE status, BYTE byte1, BYTE byte2) +{ + IDirectMusicPerformance8 *performance = &This->IDirectMusicPerformance8_iface; + DMUS_MIDI_PMSG *midi; + HRESULT hr; + + if (FAILED(hr = IDirectMusicPerformance8_AllocPMsg(performance, sizeof(*midi), + (DMUS_PMSG **)&midi))) + return hr; + + if (flags & DMUS_PMSGF_REFTIME) midi->rtTime = msg->rtTime; + if (flags & DMUS_PMSGF_MUSICTIME) midi->mtTime = msg->mtTime; + midi->dwFlags = flags; + midi->dwPChannel = msg->dwPChannel; + midi->dwVirtualTrackID = msg->dwVirtualTrackID; + midi->dwVoiceID = msg->dwVoiceID; + midi->dwGroupID = msg->dwGroupID; + midi->dwType = DMUS_PMSGT_MIDI; + midi->bStatus = status; + midi->bByte1 = byte1; + midi->bByte2 = byte2; + + if (FAILED(hr = IDirectMusicPerformance8_SendPMsg(performance, (DMUS_PMSG *)midi))) + IDirectMusicPerformance8_FreePMsg(performance, (DMUS_PMSG *)midi); + + return hr; +} + static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, IDirectMusicPerformance *performance, DMUS_PMSG *msg) { @@ -1670,6 +1699,22 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, break; } + case DMUS_PMSGT_NOTE: + { + DMUS_NOTE_PMSG *note = (DMUS_NOTE_PMSG *)msg; + + if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_REFTIME | DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, + 0x90 /* NOTE_ON */, note->bMidiValue, note->bVelocity))) + WARN("Failed to translate message to MIDI, hr %#lx\n", hr); + + msg->mtTime += note->mtDuration; + if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_QUEUE, + 0x80 /* NOTE_OFF */, note->bMidiValue, 0))) + WARN("Failed to translate message to MIDI, hr %#lx\n", hr); + + break; + } + case DMUS_PMSGT_NOTIFICATION: { DMUS_NOTIFICATION_PMSG *notif = (DMUS_NOTIFICATION_PMSG *)msg; From b68bca844dcabcf97647b2848e9faaef8b51a287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 19 Sep 2023 09:10:48 +0200 Subject: [PATCH 2640/2777] dmime: Translate DMUS_PMSGT_PATCH to DMUS_PMSGT_MIDI messages. (cherry picked from commit a6710afc26f599c5e3e592e452032f1d3a0ab4c8) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index b12a8315330..63429023da2 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1715,6 +1715,25 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, break; } + case DMUS_PMSGT_PATCH: + { + DMUS_PATCH_PMSG *patch = (DMUS_PATCH_PMSG *)msg; + + if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_REFTIME | DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, + 0xb0 /* Control Change */, 0x00 /* CC: Bank MSB */, patch->byMSB))) + WARN("Failed to translate message to MIDI, hr %#lx\n", hr); + + if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_REFTIME | DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, + 0xb0 /* Control Change */, 0x20 /* CC: Bank LSB */, patch->byLSB))) + WARN("Failed to translate message to MIDI, hr %#lx\n", hr); + + if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_REFTIME | DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, + 0xc0 /* Program Change */, patch->byInstrument, 0))) + WARN("Failed to translate message to MIDI, hr %#lx\n", hr); + + break; + } + case DMUS_PMSGT_NOTIFICATION: { DMUS_NOTIFICATION_PMSG *notif = (DMUS_NOTIFICATION_PMSG *)msg; From 4a7237e901998781b021f8a83045194b30f96e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 16 Oct 2023 10:31:04 +0200 Subject: [PATCH 2641/2777] include: Fix debugstr_fourcc printf format to print at most 4 chars. (cherry picked from commit df75c9ed3c313e7e3760faa1b478f180ab10f505) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- include/wine/debug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/wine/debug.h b/include/wine/debug.h index 52e072e1f2b..40da1385950 100644 --- a/include/wine/debug.h +++ b/include/wine/debug.h @@ -321,7 +321,7 @@ static inline const char *wine_dbgstr_fourcc( unsigned int fourcc ) if (!fourcc) return "''"; if (isprint( str[0] ) && isprint( str[1] ) && isprint( str[2] ) && isprint( str[3] )) - return wine_dbg_sprintf( "'%4s'", str ); + return wine_dbg_sprintf( "'%.4s'", str ); return wine_dbg_sprintf( "0x%08x", fourcc ); } From ebcadafed729c8b4bd4db93fe6554b544832fcd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 16 Oct 2023 15:14:11 +0200 Subject: [PATCH 2642/2777] dmime: Rewrite message thread with a condition variable. (cherry picked from commit d5e156fa7fc9ff47c1c99af342047319f0f23bfa) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 105 ++++++++++++--------------------------- 1 file changed, 33 insertions(+), 72 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 63429023da2..14e290658e0 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -54,11 +54,10 @@ struct performance REFERENCE_TIME rtLatencyTime; DWORD dwBumperLength; DWORD dwPrepareTime; - /** Message Processing */ - HANDLE procThread; - DWORD procThreadId; - BOOL procThreadTicStarted; + + HANDLE message_thread; CRITICAL_SECTION safe; + CONDITION_VARIABLE cond; IReferenceClock *master_clock; REFERENCE_TIME init_time; @@ -124,25 +123,20 @@ static HRESULT performance_process_message(struct performance *This, DMUS_PMSG * return hr; } -#define PROCESSMSG_START (WM_APP + 0) -#define PROCESSMSG_EXIT (WM_APP + 1) -#define PROCESSMSG_REMOVE (WM_APP + 2) -#define PROCESSMSG_ADD (WM_APP + 4) - -static DWORD WINAPI ProcessMsgThread(LPVOID lpParam) +static DWORD WINAPI message_thread_proc(void *args) { - struct performance *This = lpParam; - DWORD timeout = INFINITE; - MSG msg; - HRESULT hr; + struct performance *This = args; struct message *message, *next; + HRESULT hr; - while (TRUE) - { - if (timeout > 0) MsgWaitForMultipleObjects(0, NULL, FALSE, timeout, QS_POSTMESSAGE | QS_SENDMESSAGE | QS_TIMER); - timeout = INFINITE; + TRACE("performance %p message thread\n", This); + SetThreadDescription(GetCurrentThread(), L"wine_dmime_message"); - EnterCriticalSection(&This->safe); + EnterCriticalSection(&This->safe); + + while (This->message_thread) + { + DWORD timeout = INFINITE; LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->messages, struct message, entry) { @@ -154,59 +148,15 @@ static DWORD WINAPI ProcessMsgThread(LPVOID lpParam) if (hr != S_OK) break; } - LeaveCriticalSection(&This->safe); - - while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) - { - /** if hwnd we suppose that is a windows event ... */ - if (NULL != msg.hwnd) - { - TranslateMessage(&msg); - DispatchMessageA(&msg); - } - else - { - switch (msg.message) - { - case WM_QUIT: - case PROCESSMSG_EXIT: goto outofthread; - case PROCESSMSG_START: break; - case PROCESSMSG_ADD: break; - case PROCESSMSG_REMOVE: break; - default: ERR("Unhandled message %u. Critical Path\n", msg.message); break; - } - } - } - - /** here we should run a little of current AudioPath */ + SleepConditionVariableCS(&This->cond, &This->safe, timeout); } -outofthread: - TRACE("(%p): Exiting\n", This); + LeaveCriticalSection(&This->safe); + TRACE("(%p): Exiting\n", This); return 0; } -static BOOL PostMessageToProcessMsgThread(struct performance *This, UINT iMsg) { - if (FALSE == This->procThreadTicStarted && PROCESSMSG_EXIT != iMsg) { - BOOL res; - This->procThread = CreateThread(NULL, 0, ProcessMsgThread, This, 0, &This->procThreadId); - if (NULL == This->procThread) return FALSE; - SetThreadPriority(This->procThread, THREAD_PRIORITY_TIME_CRITICAL); - This->procThreadTicStarted = TRUE; - while(1) { - res = PostThreadMessageA(This->procThreadId, iMsg, 0, 0); - /* Let the thread creates its message queue (with MsgWaitForMultipleObjects call) by yielding and retrying */ - if (!res && (GetLastError() == ERROR_INVALID_THREAD_ID)) - Sleep(0); - else - break; - } - return res; - } - return PostThreadMessageA(This->procThreadId, iMsg, 0, 0); -} - static HRESULT performance_send_dirty_pmsg(struct performance *This, MUSIC_TIME music_time) { IDirectMusicPerformance8 *performance = &This->IDirectMusicPerformance8_iface; @@ -424,7 +374,12 @@ static HRESULT WINAPI performance_Init(IDirectMusicPerformance8 *iface, IDirectM return hr; } - PostMessageToProcessMsgThread(This, PROCESSMSG_START); + if (!(This->message_thread = CreateThread(NULL, 0, message_thread_proc, This, 0, NULL))) + { + ERR("Failed to start performance message thread, error %lu\n", GetLastError()); + IDirectMusicPerformance_CloseDown(iface); + return HRESULT_FROM_WIN32(GetLastError()); + } if (dmusic && !*dmusic) { @@ -549,13 +504,13 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS LIST_FOR_EACH_ENTRY(next, &This->messages, struct message, entry) if (next->msg.rtTime > message->msg.rtTime) break; list_add_before(&next->entry, &message->entry); - PostThreadMessageW(This->procThreadId, PROCESSMSG_ADD, 0, 0); hr = S_OK; } done: LeaveCriticalSection(&This->safe); + if (SUCCEEDED(hr)) WakeConditionVariable(&This->cond); return hr; } @@ -1033,14 +988,20 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); struct message *message, *next; + HANDLE message_thread; HRESULT hr; FIXME("(%p): semi-stub\n", This); - if (PostMessageToProcessMsgThread(This, PROCESSMSG_EXIT)) { - WaitForSingleObject(This->procThread, INFINITE); - This->procThreadTicStarted = FALSE; - CloseHandle(This->procThread); + if ((message_thread = This->message_thread)) + { + EnterCriticalSection(&This->safe); + This->message_thread = NULL; + LeaveCriticalSection(&This->safe); + WakeConditionVariable(&This->cond); + + WaitForSingleObject(message_thread, INFINITE); + CloseHandle(message_thread); } This->notification_performance = FALSE; From 0250d6a53eb547b427b7306b8e0c131845cb4292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 4 Sep 2023 16:20:57 +0200 Subject: [PATCH 2643/2777] dmusic: Set synth sink master clock when creating port. (cherry picked from commit f00d8639e6f34f81d0acd16a8a0e6f05f210fda8) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/port.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index 0eff1c5cb02..de5b701663d 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -714,6 +714,9 @@ HRESULT synth_port_create(IDirectMusic8Impl *parent, DMUS_PORTPARAMS *port_param if (SUCCEEDED(hr)) hr = IDirectMusicSynth_SetMasterClock(obj->synth, obj->parent->master_clock); + if (SUCCEEDED(hr)) + hr = IDirectMusicSynthSink_SetMasterClock(obj->synth_sink, obj->parent->master_clock); + if (SUCCEEDED(hr)) hr = IDirectMusicSynth_Open(obj->synth, port_params); From 7810855523cc3deba40793d021bcfce16a6f85df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 29 Aug 2023 14:40:05 +0200 Subject: [PATCH 2644/2777] dmsynth: Do nothing in IDirectMusicSynth_SetMasterClock. (cherry picked from commit 29a76fb5d1b022c1c460b694238c6be1a4c211a5) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 7 +++---- dlls/dmsynth/tests/dmsynth.c | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index af578610c16..6a780dcbb59 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -918,10 +918,9 @@ static HRESULT WINAPI synth_SetMasterClock(IDirectMusicSynth8 *iface, TRACE("(%p)->(%p)\n", This, clock); - if (!This->sink) - return DMUS_E_NOSYNTHSINK; - - return IDirectMusicSynthSink_SetMasterClock(This->sink, clock); + if (!clock) + return E_POINTER; + return S_OK; } static HRESULT WINAPI synth_GetLatencyClock(IDirectMusicSynth8 *iface, diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index ad4bb5c0ad5..0deaa161a3b 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -1036,19 +1036,19 @@ static void test_IDirectMusicSynth(void) /* SetMasterClock does nothing */ hr = IDirectMusicSynth_SetMasterClock(synth, NULL); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); hr = IDirectMusicSynth_SetMasterClock(synth, clock); ok(hr == S_OK, "got %#lx\n", hr); ref = get_refcount(clock); todo_wine ok(ref == 1, "got %lu\n", ref); hr = IDirectMusicSynth_Activate(synth, TRUE); - todo_wine ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); + ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); /* SetMasterClock needs to be called on the sink */ hr = IDirectMusicSynthSink_SetMasterClock(sink, clock); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicSynth_Activate(synth, TRUE); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicSynth_Activate(synth, TRUE); ok(hr == S_FALSE, "got %#lx\n", hr); From 49f990d780f691f9a7465c27b021d227aa8f999f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 12 Oct 2023 11:13:33 +0200 Subject: [PATCH 2645/2777] dmusic: Forward IDirectMusicPort_Activate to synth and sink. (cherry picked from commit 72165fc8ec2cfb86ff641ed817b1fb7cace24dfe) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/port.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/dlls/dmusic/port.c b/dlls/dmusic/port.c index de5b701663d..812fb8c94e3 100644 --- a/dlls/dmusic/port.c +++ b/dlls/dmusic/port.c @@ -274,30 +274,36 @@ static HRESULT WINAPI synth_port_GetNumChannelGroups(IDirectMusicPort *iface, DW static HRESULT WINAPI synth_port_Activate(IDirectMusicPort *iface, BOOL active) { struct synth_port *This = synth_from_IDirectMusicPort(iface); + HRESULT hr; - FIXME("(%p/%p)->(%d): semi-stub\n", iface, This, active); + TRACE("(%p/%p)->(%d)\n", iface, This, active); - if (This->active == active) - return S_FALSE; + if (This->active == active) return S_FALSE; - if (active) { - /* Acquire the dsound */ - if (!This->dsound) { - IDirectSound_AddRef(This->parent->dsound); - This->dsound = This->parent->dsound; - } - IDirectSound_AddRef(This->dsound); - } else { - /* Release the dsound */ - IDirectSound_Release(This->dsound); - IDirectSound_Release(This->parent->dsound); - if (This->dsound == This->parent->dsound) - This->dsound = NULL; + if (active) + { + if (!This->dsound && FAILED(hr = IDirectMusicPort_SetDirectSound(iface, + This->parent->dsound, NULL))) + return hr; + if (FAILED(hr = IDirectMusicSynthSink_SetDirectSound(This->synth_sink, + This->dsound, This->dsbuffer))) + return hr; + + if (FAILED(hr = IDirectMusicSynth_Activate(This->synth, active))) + return hr; + This->active = TRUE; } + else + { + if (FAILED(hr = IDirectMusicSynth_Activate(This->synth, FALSE))) return hr; + This->active = FALSE; - This->active = active; + if (FAILED(hr = IDirectMusicSynthSink_SetDirectSound(This->synth_sink, NULL, NULL))) + return hr; + hr = IDirectMusicPort_SetDirectSound(iface, NULL, NULL); + } - return S_OK; + return hr; } static HRESULT WINAPI synth_port_SetChannelPriority(IDirectMusicPort *iface, DWORD channel_group, From ba1b2412a0207413210e51fe6e727e69d0c97311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 16 Oct 2023 11:52:37 +0200 Subject: [PATCH 2646/2777] dmime: Use port latency time for messages with -1 time. (cherry picked from commit a8763aab6fbcab804282a3d909e16e93ead2a867) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 14e290658e0..4dffadb405d 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -490,7 +490,7 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS if (!(msg->dwFlags & DMUS_PMSGF_REFTIME)) { if (FAILED(hr = IDirectMusicPerformance8_MusicToReferenceTime(iface, - msg->mtTime, &msg->rtTime))) + msg->mtTime == -1 ? 0 : msg->mtTime, &msg->rtTime))) goto done; msg->dwFlags |= DMUS_PMSGF_REFTIME; } @@ -1632,6 +1632,8 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, static const UINT event_size = sizeof(DMUS_EVENTHEADER) + sizeof(DWORD); DMUS_BUFFERDESC desc = {.dwSize = sizeof(desc), .cbBuffer = 2 * event_size}; DMUS_MIDI_PMSG *midi = (DMUS_MIDI_PMSG *)msg; + IReferenceClock *latency_clock; + REFERENCE_TIME latency_time; IDirectMusicBuffer *buffer; IDirectMusicPort *port; DWORD group, channel; @@ -1644,6 +1646,13 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, return DMUS_S_FREE; } + if (SUCCEEDED(hr = IDirectMusicPort_GetLatencyClock(port, &latency_clock))) + { + if (FAILED(hr = IReferenceClock_GetTime(latency_clock, &latency_time))) + ERR("Failed to get port latency time, hr %#lx\n", hr); + IReferenceClock_Release(latency_clock); + } + value |= channel; value |= (UINT)midi->bStatus; value |= (UINT)midi->bByte1 << 8; @@ -1651,6 +1660,7 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, if (SUCCEEDED(hr = IDirectMusic_CreateMusicBuffer(This->dmusic, &desc, &buffer, NULL))) { + if (msg->rtTime == -1) msg->rtTime = latency_time; hr = IDirectMusicBuffer_PackStructured(buffer, msg->rtTime, group, value); if (SUCCEEDED(hr)) hr = IDirectMusicPort_PlayBuffer(port, buffer); IDirectMusicBuffer_Release(buffer); From 493fc4123fbda402a6fc411fe96cdd2c9724e973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 16 Oct 2023 11:32:58 +0200 Subject: [PATCH 2647/2777] dmime: Update performance latency time with port latency. (cherry picked from commit d0f544669615fd3672c88504fa39822f070dfdfa) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 56 +++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 4dffadb405d..a56a35a2f45 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -51,7 +51,7 @@ struct performance BOOL audio_paths_enabled; IDirectMusicAudioPath *pDefaultPath; - REFERENCE_TIME rtLatencyTime; + REFERENCE_TIME latency_offset; DWORD dwBumperLength; DWORD dwPrepareTime; @@ -737,6 +737,31 @@ static HRESULT WINAPI performance_RemoveNotificationType(IDirectMusicPerformance return hr; } +static void performance_update_latency_time(struct performance *This, IDirectMusicPort *port, + REFERENCE_TIME *ret_time) +{ + IDirectMusicPerformance8 *iface = &This->IDirectMusicPerformance8_iface; + REFERENCE_TIME latency_time, current_time; + IReferenceClock *latency_clock; + HRESULT hr; + + if (!ret_time) ret_time = &latency_time; + if (SUCCEEDED(hr = IDirectMusicPort_GetLatencyClock(port, &latency_clock))) + { + hr = IReferenceClock_GetTime(latency_clock, ret_time); + if (SUCCEEDED(hr)) hr = IDirectMusicPerformance8_GetTime(iface, ¤t_time, NULL); + if (SUCCEEDED(hr) && This->latency_offset < (*ret_time - current_time)) + { + TRACE("Updating performance %p latency %I64d -> %I64d\n", This, + This->latency_offset, *ret_time - current_time); + This->latency_offset = *ret_time - current_time; + } + IReferenceClock_Release(latency_clock); + } + + if (FAILED(hr)) ERR("Failed to update performance %p latency, hr %#lx\n", This, hr); +} + static HRESULT perf_dmport_create(struct performance *perf, DMUS_PORTPARAMS *params) { IDirectMusicPort *port; @@ -760,6 +785,7 @@ static HRESULT perf_dmport_create(struct performance *perf, DMUS_PORTPARAMS *par for (i = 0; i < params->dwChannelGroups; i++) pchannel_block_set(&perf->pchannels, i, port, i + 1, FALSE); + performance_update_latency_time(perf, port, NULL); return S_OK; } @@ -787,6 +813,8 @@ static HRESULT WINAPI performance_AddPort(IDirectMusicPerformance8 *iface, IDire * We should remember added Ports (for example using a list) * and control if Port is registered for each api who use ports */ + + performance_update_latency_time(This, port, NULL); return S_OK; } @@ -958,13 +986,18 @@ static HRESULT WINAPI performance_SetGlobalParam(IDirectMusicPerformance8 *iface return S_OK; } -static HRESULT WINAPI performance_GetLatencyTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME *prtTime) +static HRESULT WINAPI performance_GetLatencyTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME *ret_time) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + REFERENCE_TIME current_time; + HRESULT hr; - TRACE("(%p, %p): stub\n", This, prtTime); - *prtTime = This->rtLatencyTime; - return S_OK; + TRACE("(%p, %p)\n", This, ret_time); + + if (SUCCEEDED(hr = IDirectMusicPerformance8_GetTime(iface, ¤t_time, NULL))) + *ret_time = current_time + This->latency_offset; + + return hr; } static HRESULT WINAPI performance_GetQueueTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME *prtTime) @@ -1632,7 +1665,6 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, static const UINT event_size = sizeof(DMUS_EVENTHEADER) + sizeof(DWORD); DMUS_BUFFERDESC desc = {.dwSize = sizeof(desc), .cbBuffer = 2 * event_size}; DMUS_MIDI_PMSG *midi = (DMUS_MIDI_PMSG *)msg; - IReferenceClock *latency_clock; REFERENCE_TIME latency_time; IDirectMusicBuffer *buffer; IDirectMusicPort *port; @@ -1645,13 +1677,7 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, WARN("Failed to get message port, hr %#lx\n", hr); return DMUS_S_FREE; } - - if (SUCCEEDED(hr = IDirectMusicPort_GetLatencyClock(port, &latency_clock))) - { - if (FAILED(hr = IReferenceClock_GetTime(latency_clock, &latency_time))) - ERR("Failed to get port latency time, hr %#lx\n", hr); - IReferenceClock_Release(latency_clock); - } + performance_update_latency_time(This, port, &latency_time); value |= channel; value |= (UINT)midi->bStatus; @@ -1796,7 +1822,7 @@ HRESULT create_dmperformance(REFIID iid, void **ret_iface) list_init(&obj->messages); list_init(&obj->notifications); - obj->rtLatencyTime = 100; /* 100 ms TO FIX */ + obj->latency_offset = 50; obj->dwBumperLength = 50; /* 50 ms default */ obj->dwPrepareTime = 1000; /* 1000 ms default */ From 992b169079e7ee6582c553d9d9976b049387b5e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 16 Oct 2023 11:41:34 +0200 Subject: [PATCH 2648/2777] dmime: Use latency time to decide when to process messages. (cherry picked from commit 1014bab951f89a51226a17ec1d6d8d1225c46c5c) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index a56a35a2f45..dc6ef575713 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -89,10 +89,10 @@ static HRESULT performance_process_message(struct performance *This, DMUS_PMSG * do { - REFERENCE_TIME current, offset = 0; + REFERENCE_TIME latency, offset = 0; IDirectMusicTool *tool; - if (FAILED(hr = IDirectMusicPerformance_GetTime(performance, ¤t, NULL))) return hr; + if (FAILED(hr = IDirectMusicPerformance_GetLatencyTime(performance, &latency))) return hr; if (!(tool = msg->pTool)) tool = &This->IDirectMusicTool_iface; switch (msg->dwFlags & delivery_flags) @@ -107,9 +107,9 @@ static HRESULT performance_process_message(struct performance *This, DMUS_PMSG * offset = This->dwBumperLength * 10000; /* fallthrough */ case DMUS_PMSGF_TOOL_ATTIME: - if (msg->rtTime >= offset && msg->rtTime - offset >= current) + if (msg->rtTime >= offset && msg->rtTime - offset >= latency) { - if (timeout) *timeout = (msg->rtTime - offset - current) / 10000; + if (timeout) *timeout = (msg->rtTime - offset - latency) / 10000; return DMUS_S_REQUEUE; } From 8794a12e7df128e1b7320f683d674d56717ee1de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 5 Sep 2023 13:43:07 +0200 Subject: [PATCH 2649/2777] dmsynth: Create a render thread on sink activation. (cherry picked from commit 0d56c54d8b5d754ab71576232b04df39b5e46414) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synthsink.c | 153 ++++++++++++++++++++++++++++++++++- dlls/dmsynth/tests/dmsynth.c | 4 +- 2 files changed, 154 insertions(+), 3 deletions(-) diff --git a/dlls/dmsynth/synthsink.c b/dlls/dmsynth/synthsink.c index db1fecb8d48..906e37e8959 100644 --- a/dlls/dmsynth/synthsink.c +++ b/dlls/dmsynth/synthsink.c @@ -27,6 +27,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); +#define BUFFER_SUBDIVISIONS 8 + struct synth_sink { IDirectMusicSynthSink IDirectMusicSynthSink_iface; @@ -37,10 +39,17 @@ struct synth_sink IReferenceClock *master_clock; IDirectMusicSynth *synth; /* No reference hold! */ IDirectSound *dsound; + IDirectSoundBuffer *dsound_buffer; BOOL active; REFERENCE_TIME activate_time; + + CRITICAL_SECTION cs; REFERENCE_TIME latency_time; + + DWORD written; /* number of bytes written out */ + HANDLE stop_event; + HANDLE render_thread; }; static inline struct synth_sink *impl_from_IDirectMusicSynthSink(IDirectMusicSynthSink *iface) @@ -67,8 +76,93 @@ static void synth_sink_get_format(struct synth_sink *This, WAVEFORMATEX *format) } } +struct render_thread_params +{ + struct synth_sink *sink; + IDirectMusicSynth *synth; + IDirectSoundBuffer *buffer; + HANDLE started_event; +}; + +static DWORD CALLBACK synth_sink_render_thread(void *args) +{ + struct render_thread_params *params = args; + DSBCAPS caps = {.dwSize = sizeof(DSBCAPS)}; + IDirectSoundBuffer *buffer = params->buffer; + IDirectMusicSynth *synth = params->synth; + struct synth_sink *sink = params->sink; + IDirectSoundNotify *notify; + HANDLE buffer_event; + HRESULT hr; + + TRACE("Starting thread, args %p\n", args); + SetThreadDescription(GetCurrentThread(), L"wine_dmsynth_sink"); + + if (FAILED(hr = IDirectSoundBuffer_Stop(buffer))) + ERR("Failed to stop sound buffer, hr %#lx.\n", hr); + + if (!(buffer_event = CreateEventW(NULL, FALSE, FALSE, NULL))) + ERR("Failed to create buffer event, error %lu\n", GetLastError()); + else if (FAILED(hr = IDirectSoundBuffer_GetCaps(buffer, &caps))) + ERR("Failed to query sound buffer caps, hr %#lx.\n", hr); + else if (FAILED(hr = IDirectSoundBuffer_QueryInterface(buffer, &IID_IDirectSoundNotify, + (void **)¬ify))) + ERR("Failed to query IDirectSoundNotify iface, hr %#lx.\n", hr); + else + { + DSBPOSITIONNOTIFY positions[BUFFER_SUBDIVISIONS] = {{.dwOffset = 0, .hEventNotify = buffer_event}}; + int i; + + for (i = 1; i < ARRAY_SIZE(positions); ++i) + { + positions[i] = positions[i - 1]; + positions[i].dwOffset += caps.dwBufferBytes / ARRAY_SIZE(positions); + } + + if (FAILED(hr = IDirectSoundNotify_SetNotificationPositions(notify, + ARRAY_SIZE(positions), positions))) + ERR("Failed to set notification positions, hr %#lx\n", hr); + + IDirectSoundNotify_Release(notify); + } + + if (FAILED(hr = IDirectSoundBuffer_Play(buffer, 0, 0, DSBPLAY_LOOPING))) + ERR("Failed to start sound buffer, hr %#lx.\n", hr); + SetEvent(params->started_event); + + while (hr == S_OK) + { + HANDLE handles[] = {sink->stop_event, buffer_event}; + DWORD ret; + + if (!(ret = WaitForMultipleObjects(ARRAY_SIZE(handles), handles, FALSE, INFINITE)) + || ret >= ARRAY_SIZE(handles)) + { + ERR("WaitForMultipleObjects returned %lu\n", ret); + hr = HRESULT_FROM_WIN32(ret); + break; + } + } + + if (FAILED(hr)) + { + ERR("Thread unexpected termination, hr %#lx\n", hr); + return hr; + } + + IDirectSoundBuffer_Release(buffer); + IDirectMusicSynth_Release(synth); + CloseHandle(buffer_event); + + return 0; +} + static HRESULT synth_sink_activate(struct synth_sink *This) { + IDirectMusicSynthSink *iface = &This->IDirectMusicSynthSink_iface; + DSBUFFERDESC desc = {.dwSize = sizeof(DSBUFFERDESC)}; + struct render_thread_params params; + WAVEFORMATEX format; HRESULT hr; if (!This->synth) return DMUS_E_SYNTHNOTCONFIGURED; @@ -79,13 +173,54 @@ static HRESULT synth_sink_activate(struct synth_sink *This) if (FAILED(hr = IReferenceClock_GetTime(This->master_clock, &This->activate_time))) return hr; This->latency_time = This->activate_time; + if ((params.buffer = This->dsound_buffer)) + IDirectMusicBuffer_AddRef(params.buffer); + else + { + synth_sink_get_format(This, &format); + desc.lpwfxFormat = (WAVEFORMATEX *)&format; + desc.dwBufferBytes = format.nAvgBytesPerSec; + if (FAILED(hr = IDirectMusicSynthSink_GetDesiredBufferSize(iface, &desc.dwBufferBytes))) + ERR("Failed to get desired buffer size, hr %#lx\n", hr); + + desc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY; + if (FAILED(hr = IDirectSound8_CreateSoundBuffer(This->dsound, &desc, ¶ms.buffer, NULL))) + { + ERR("Failed to create sound buffer, hr %#lx.\n", hr); + return hr; + } + } + + params.sink = This; + params.synth = This->synth; + IDirectMusicSynth_AddRef(This->synth); + + if (!(params.started_event = CreateEventW(NULL, FALSE, FALSE, NULL)) + || !(This->render_thread = CreateThread(NULL, 0, synth_sink_render_thread, ¶ms, 0, NULL))) + { + ERR("Failed to create render thread, error %lu\n", GetLastError()); + hr = HRESULT_FROM_WIN32(GetLastError()); + IDirectSoundBuffer_Release(params.buffer); + IDirectMusicSynth_Release(params.synth); + CloseHandle(params.started_event); + return hr; + } + + WaitForSingleObject(params.started_event, INFINITE); + CloseHandle(params.started_event); This->active = TRUE; return S_OK; } static HRESULT synth_sink_deactivate(struct synth_sink *This) { + if (!This->active) return S_OK; + + SetEvent(This->stop_event); + WaitForSingleObject(This->render_thread, INFINITE); + This->render_thread = NULL; This->active = FALSE; + return S_OK; } @@ -135,8 +270,15 @@ static ULONG WINAPI synth_sink_Release(IDirectMusicSynthSink *iface) TRACE("(%p): new ref = %lu\n", This, ref); if (!ref) { + if (This->active) + IDirectMusicSynthSink_Activate(iface, FALSE); if (This->master_clock) IReferenceClock_Release(This->master_clock); + + This->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->cs); + CloseHandle(This->stop_event); + free(This); } @@ -240,15 +382,17 @@ static HRESULT WINAPI synth_sink_SetDirectSound(IDirectMusicSynthSink *iface, TRACE("(%p)->(%p, %p)\n", This, dsound, dsound_buffer); - if (dsound_buffer) FIXME("Ignoring IDirectSoundBuffer parameter.\n"); if (This->active) return DMUS_E_SYNTHACTIVE; if (This->dsound) IDirectSound_Release(This->dsound); This->dsound = NULL; + if (This->dsound_buffer) IDirectSoundBuffer_Release(This->dsound_buffer); + This->dsound_buffer = NULL; if (!dsound) return S_OK; if (!This->synth) return DMUS_E_SYNTHNOTCONFIGURED; if ((This->dsound = dsound)) IDirectSound_AddRef(This->dsound); + if ((This->dsound_buffer = dsound_buffer)) IDirectSoundBuffer_AddRef(This->dsound_buffer); return S_OK; } @@ -415,7 +559,10 @@ static HRESULT WINAPI latency_clock_GetTime(IReferenceClock *iface, REFERENCE_TI if (!time) return E_INVALIDARG; if (!This->active) return E_FAIL; + + EnterCriticalSection(&This->cs); *time = This->latency_time; + LeaveCriticalSection(&This->cs); return S_OK; } @@ -464,6 +611,10 @@ HRESULT synth_sink_create(IUnknown **ret_iface) obj->IReferenceClock_iface.lpVtbl = &latency_clock_vtbl; obj->ref = 1; + obj->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL); + InitializeCriticalSection(&obj->cs); + obj->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs"); + TRACE("Created DirectMusicSynthSink %p\n", obj); *ret_iface = (IUnknown *)&obj->IDirectMusicSynthSink_iface; return S_OK; diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index 0deaa161a3b..c25150ed9f6 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -1294,7 +1294,7 @@ static void test_IDirectMusicSynthSink(void) hr = IDirectMusicSynthSink_Activate(sink, TRUE); ok(hr == DMUS_E_SYNTHACTIVE, "got %#lx\n", hr); ref = get_refcount(synth); - ok(ref == 1, "got %#lx\n", ref); + todo_wine ok(ref == 1, "got %#lx\n", ref); hr = IDirectMusicSynthSink_GetDesiredBufferSize(sink, &size); ok(hr == S_OK, "got %#lx\n", hr); @@ -1328,7 +1328,7 @@ static void test_IDirectMusicSynthSink(void) hr = IDirectMusicSynthSink_Init(sink, NULL); ok(hr == S_OK, "got %#lx\n", hr); ref = get_refcount(synth); - ok(ref == 1, "got %#lx\n", ref); + todo_wine ok(ref == 1, "got %#lx\n", ref); hr = IDirectMusicSynthSink_Activate(sink, TRUE); ok(hr == DMUS_E_SYNTHNOTCONFIGURED, "got %#lx\n", hr); From 087bc17cf8987b22e8b76cacbfda4411593e9779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 12 Oct 2023 11:59:36 +0200 Subject: [PATCH 2650/2777] dmsynth: Implement sink rendering to DirectSound buffer. (cherry picked from commit 7274902a3bd79824a43dfa8d11bbfd8c2cead0e4) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synthsink.c | 148 ++++++++++++++++++++++++++++++++++- dlls/dmsynth/tests/dmsynth.c | 2 +- 2 files changed, 147 insertions(+), 3 deletions(-) diff --git a/dlls/dmsynth/synthsink.c b/dlls/dmsynth/synthsink.c index 906e37e8959..bb77323a70c 100644 --- a/dlls/dmsynth/synthsink.c +++ b/dlls/dmsynth/synthsink.c @@ -27,7 +27,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); -#define BUFFER_SUBDIVISIONS 8 +#define BUFFER_SUBDIVISIONS 100 struct synth_sink { @@ -76,6 +76,128 @@ static void synth_sink_get_format(struct synth_sink *This, WAVEFORMATEX *format) } } +static HRESULT synth_sink_write_data(struct synth_sink *sink, IDirectSoundBuffer *buffer, + DSBCAPS *caps, WAVEFORMATEX *format, const void *data, DWORD size) +{ + DWORD write_end, size1, size2, current_pos; + void *data1, *data2; + HRESULT hr; + + TRACE("sink %p, data %p, size %#lx\n", sink, data, size); + + current_pos = sink->written % caps->dwBufferBytes; + + if (sink->written) + { + DWORD play_pos, write_pos; + + if (FAILED(hr = IDirectSoundBuffer_GetCurrentPosition(buffer, &play_pos, &write_pos))) return hr; + + if (current_pos - play_pos <= write_pos - play_pos) + { + ERR("Underrun detected, sink %p, play pos %#lx, write pos %#lx, current pos %#lx!\n", + buffer, play_pos, write_pos, current_pos); + current_pos = write_pos; + } + + write_end = (current_pos + size) % caps->dwBufferBytes; + if (write_end - current_pos >= play_pos - current_pos) return S_FALSE; + } + + if (FAILED(hr = IDirectSoundBuffer_Lock(buffer, current_pos, size, + &data1, &size1, &data2, &size2, 0))) + { + ERR("IDirectSoundBuffer_Lock failed, hr %#lx\n", hr); + return hr; + } + + if (!data) + { + memset(data1, format->wBitsPerSample == 8 ? 128 : 0, size1); + memset(data2, format->wBitsPerSample == 8 ? 128 : 0, size2); + } + else + { + memcpy(data1, data, size1); + data = (char *)data + size1; + memcpy(data2, data, size2); + } + + if (FAILED(hr = IDirectSoundBuffer_Unlock(buffer, data1, size1, data2, size2))) + { + ERR("IDirectSoundBuffer_Unlock failed, hr %#lx\n", hr); + return hr; + } + + sink->written += size; + TRACE("Written size %#lx, total %#lx\n", size, sink->written); + return S_OK; +} + +static HRESULT synth_sink_wait_play_end(struct synth_sink *sink, IDirectSoundBuffer *buffer, + DSBCAPS *caps, WAVEFORMATEX *format, HANDLE buffer_event) +{ + DWORD current_pos, start_pos, play_pos, written, played = 0; + HRESULT hr; + + if (FAILED(hr = IDirectSoundBuffer_GetCurrentPosition(buffer, &start_pos, NULL))) + { + ERR("IDirectSoundBuffer_GetCurrentPosition failed, hr %#lx\n", hr); + return hr; + } + + current_pos = sink->written % caps->dwBufferBytes; + written = current_pos - start_pos + (current_pos < start_pos ? caps->dwBufferBytes : 0); + if (FAILED(hr = synth_sink_write_data(sink, buffer, caps, format, NULL, caps->dwBufferBytes / 2))) return hr; + + for (;;) + { + DWORD ret; + + if (FAILED(hr = IDirectSoundBuffer_GetCurrentPosition(buffer, &play_pos, NULL))) + { + ERR("IDirectSoundBuffer_GetCurrentPosition failed, hr %#lx\n", hr); + return hr; + } + + played += play_pos - start_pos + (play_pos < start_pos ? caps->dwBufferBytes : 0); + if (played >= written) break; + + TRACE("Waiting for EOS, start_pos %#lx, play_pos %#lx, written %#lx, played %#lx\n", + start_pos, play_pos, written, played); + if ((ret = WaitForMultipleObjects(1, &buffer_event, FALSE, INFINITE))) + { + ERR("WaitForMultipleObjects returned %#lx\n", ret); + break; + } + + start_pos = play_pos; + } + + return S_OK; +} + +static HRESULT synth_sink_render_data(struct synth_sink *sink, IDirectMusicSynth *synth, + IDirectSoundBuffer *buffer, WAVEFORMATEX *format, short *samples, DWORD samples_size) +{ + REFERENCE_TIME sample_time; + HRESULT hr; + + if (FAILED(hr = IDirectMusicSynth_Render(synth, samples, samples_size / format->nBlockAlign, + sink->written / format->nBlockAlign))) + ERR("Failed to render synthesizer samples, hr %#lx\n", hr); + + if (FAILED(hr = IDirectMusicSynthSink_SampleToRefTime(&sink->IDirectMusicSynthSink_iface, + (sink->written + samples_size) / format->nBlockAlign, &sample_time))) + ERR("Failed to convert sample position to time, hr %#lx\n", hr); + + EnterCriticalSection(&sink->cs); + sink->latency_time = sample_time; + LeaveCriticalSection(&sink->cs); + + return hr; +} + struct render_thread_params { struct synth_sink *sink; @@ -92,7 +214,10 @@ static DWORD CALLBACK synth_sink_render_thread(void *args) IDirectMusicSynth *synth = params->synth; struct synth_sink *sink = params->sink; IDirectSoundNotify *notify; + WAVEFORMATEX format; HANDLE buffer_event; + DWORD samples_size; + short *samples; HRESULT hr; TRACE("Starting thread, args %p\n", args); @@ -105,6 +230,8 @@ static DWORD CALLBACK synth_sink_render_thread(void *args) ERR("Failed to create buffer event, error %lu\n", GetLastError()); else if (FAILED(hr = IDirectSoundBuffer_GetCaps(buffer, &caps))) ERR("Failed to query sound buffer caps, hr %#lx.\n", hr); + else if (FAILED(hr = IDirectSoundBuffer_GetFormat(buffer, &format, sizeof(format), NULL))) + ERR("Failed to query sound buffer format, hr %#lx.\n", hr); else if (FAILED(hr = IDirectSoundBuffer_QueryInterface(buffer, &IID_IDirectSoundNotify, (void **)¬ify))) ERR("Failed to query IDirectSoundNotify iface, hr %#lx.\n", hr); @@ -126,15 +253,28 @@ static DWORD CALLBACK synth_sink_render_thread(void *args) IDirectSoundNotify_Release(notify); } + samples_size = caps.dwBufferBytes / BUFFER_SUBDIVISIONS; + if (!(samples = malloc(samples_size))) + { + ERR("Failed to allocate memory for samples\n"); + goto done; + } + + if (FAILED(hr = synth_sink_render_data(sink, synth, buffer, &format, samples, samples_size))) + ERR("Failed to render initial buffer data, hr %#lx.\n", hr); if (FAILED(hr = IDirectSoundBuffer_Play(buffer, 0, 0, DSBPLAY_LOOPING))) ERR("Failed to start sound buffer, hr %#lx.\n", hr); SetEvent(params->started_event); - while (hr == S_OK) + while (SUCCEEDED(hr) && SUCCEEDED(hr = synth_sink_write_data(sink, buffer, + &caps, &format, samples, samples_size))) { HANDLE handles[] = {sink->stop_event, buffer_event}; DWORD ret; + if (hr == S_OK) /* if successfully written, render more data */ + hr = synth_sink_render_data(sink, synth, buffer, &format, samples, samples_size); + if (!(ret = WaitForMultipleObjects(ARRAY_SIZE(handles), handles, FALSE, INFINITE)) || ret >= ARRAY_SIZE(handles)) { @@ -150,6 +290,10 @@ static DWORD CALLBACK synth_sink_render_thread(void *args) return hr; } + synth_sink_wait_play_end(sink, buffer, &caps, &format, buffer_event); + free(samples); + +done: IDirectSoundBuffer_Release(buffer); IDirectMusicSynth_Release(synth); CloseHandle(buffer_event); diff --git a/dlls/dmsynth/tests/dmsynth.c b/dlls/dmsynth/tests/dmsynth.c index c25150ed9f6..518ea2363e5 100644 --- a/dlls/dmsynth/tests/dmsynth.c +++ b/dlls/dmsynth/tests/dmsynth.c @@ -1317,7 +1317,7 @@ static void test_IDirectMusicSynthSink(void) tmp_time = time; hr = IReferenceClock_GetTime(latency_clock, &tmp_time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(tmp_time > time, "got %I64d\n", tmp_time - time); + ok(tmp_time > time, "got %I64d\n", tmp_time - time); ok(tmp_time - time <= 2000000, "got %I64d\n", tmp_time - time); /* setting the clock while active is fine */ From c2e6c3c33cdfdf6d556c73475e253fdd7bec37fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 16 Oct 2023 19:07:07 +0200 Subject: [PATCH 2651/2777] dmsynth: Correctly lookup instrument from the default drum bank. (cherry picked from commit 1728f82a2af115bb72aab8ce676ceb6fa491cc95) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 6a780dcbb59..d5b1cb64198 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -1573,7 +1573,10 @@ static fluid_preset_t *synth_sfont_get_preset(fluid_sfont_t *fluid_sfont, int ba EnterCriticalSection(&synth->cs); LIST_FOR_EACH_ENTRY(instrument, &synth->instruments, struct instrument, entry) - if (instrument->patch == patch) break; + { + if (bank == 128 && instrument->patch == (0x80000000 | patch)) break; + else if (instrument->patch == ((bank << 8) | patch)) break; + } if (&instrument->entry == &synth->instruments) { From a66c5328ced15b84e0e7b6981ec3f2ecb52203ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 16 Oct 2023 17:17:37 +0200 Subject: [PATCH 2652/2777] dmsynth: Avoid using fluid_ prefix for internal helpers. (cherry picked from commit 832a2127cda368a1435863c0262ffe3416195191) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index d5b1cb64198..0c4ae68c66a 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -1305,7 +1305,7 @@ static int synth_preset_get_num(fluid_preset_t *fluid_preset) return instrument->patch; } -static BOOL fluid_gen_from_connection(CONNECTION *conn, UINT *gen) +static BOOL gen_from_connection(const CONNECTION *conn, UINT *gen) { switch (conn->usDestination) { @@ -1336,7 +1336,7 @@ static BOOL fluid_gen_from_connection(CONNECTION *conn, UINT *gen) } } -static BOOL set_gen_from_connection(fluid_voice_t *fluid_voice, CONNECTION *conn) +static BOOL set_gen_from_connection(fluid_voice_t *fluid_voice, const CONNECTION *conn) { UINT gen; @@ -1345,7 +1345,7 @@ static BOOL set_gen_from_connection(fluid_voice_t *fluid_voice, CONNECTION *conn if (conn->usSource == CONN_SRC_NONE) { - if (!fluid_gen_from_connection(conn, &gen)) return FALSE; + if (!gen_from_connection(conn, &gen)) return FALSE; } if (conn->usSource == CONN_SRC_KEYNUMBER) { @@ -1394,7 +1394,7 @@ static BOOL set_gen_from_connection(fluid_voice_t *fluid_voice, CONNECTION *conn return TRUE; } -static BOOL fluid_source_from_connection(USHORT source, USHORT transform, UINT *fluid_source, UINT *fluid_flags) +static BOOL mod_from_connection(USHORT source, USHORT transform, UINT *fluid_source, UINT *fluid_flags) { UINT flags = FLUID_MOD_GC; if (source >= CONN_SRC_CC1 && source <= CONN_SRC_CC1 + 0x7f) @@ -1428,8 +1428,8 @@ static BOOL fluid_source_from_connection(USHORT source, USHORT transform, UINT * return TRUE; } -static BOOL add_mod_from_connection(fluid_voice_t *fluid_voice, CONNECTION *conn, UINT src1, UINT flags1, - UINT src2, UINT flags2) +static BOOL add_mod_from_connection(fluid_voice_t *fluid_voice, const CONNECTION *conn, + UINT src1, UINT flags1, UINT src2, UINT flags2) { fluid_mod_t *mod; UINT gen = -1; @@ -1456,7 +1456,7 @@ static BOOL add_mod_from_connection(fluid_voice_t *fluid_voice, CONNECTION *conn flags2 = 0; } - if (gen == -1 && !fluid_gen_from_connection(conn, &gen)) return FALSE; + if (gen == -1 && !gen_from_connection(conn, &gen)) return FALSE; if (!(mod = new_fluid_mod())) return FALSE; fluid_mod_set_source1(mod, src1, flags1); @@ -1468,35 +1468,28 @@ static BOOL add_mod_from_connection(fluid_voice_t *fluid_voice, CONNECTION *conn return TRUE; } -static void fluid_voice_add_articulation(fluid_voice_t *fluid_voice, struct articulation *articulation) +static void add_voice_connections(fluid_voice_t *fluid_voice, const CONNECTIONLIST *list, + const CONNECTION *connections) { UINT i; - for (i = 0; i < articulation->list.cConnections; i++) + for (i = 0; i < list->cConnections; i++) { UINT src1 = FLUID_MOD_NONE, flags1 = 0, src2 = FLUID_MOD_NONE, flags2 = 0; - CONNECTION *conn = articulation->connections + i; + const CONNECTION *conn = connections + i; if (set_gen_from_connection(fluid_voice, conn)) continue; - if (!fluid_source_from_connection(conn->usSource, (conn->usTransform >> 10) & 0x3f, + if (!mod_from_connection(conn->usSource, (conn->usTransform >> 10) & 0x3f, &src1, &flags1)) continue; - if (!fluid_source_from_connection(conn->usControl, (conn->usControl >> 4) & 0x3f, + if (!mod_from_connection(conn->usControl, (conn->usControl >> 4) & 0x3f, &src2, &flags2)) continue; add_mod_from_connection(fluid_voice, conn, src1, flags1, src2, flags2); } } -static void fluid_voice_add_articulations(fluid_voice_t *fluid_voice, struct list *list) -{ - struct articulation *articulation; - - LIST_FOR_EACH_ENTRY(articulation, list, struct articulation, entry) - fluid_voice_add_articulation(fluid_voice, articulation); -} - static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *fluid_synth, int chan, int key, int vel) { struct instrument *instrument = fluid_preset_get_data(fluid_preset); @@ -1511,6 +1504,7 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui LIST_FOR_EACH_ENTRY(region, &instrument->regions, struct region, entry) { + struct articulation *articulation; struct wave *wave = region->wave; if (key < region->key_range.usLow || key > region->key_range.usHigh) continue; @@ -1538,8 +1532,10 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui return FLUID_FAILED; } - fluid_voice_add_articulations(fluid_voice, &instrument->articulations); - fluid_voice_add_articulations(fluid_voice, ®ion->articulations); + LIST_FOR_EACH_ENTRY(articulation, &instrument->articulations, struct articulation, entry) + add_voice_connections(fluid_voice, &articulation->list, articulation->connections); + LIST_FOR_EACH_ENTRY(articulation, ®ion->articulations, struct articulation, entry) + add_voice_connections(fluid_voice, &articulation->list, articulation->connections); fluid_synth_start_voice(synth->fluid_synth, fluid_voice); return FLUID_OK; } From 4859b2c99f9e1a36819fd2029ac90af3462f737d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 18 Oct 2023 11:54:01 +0200 Subject: [PATCH 2653/2777] dmsynth: Fix DLS2 to FluidSynth conversion for CONN_SRC_CCx. (cherry picked from commit 0eaa06b51d9acee7a7fdf2ccb4ad63a6ac35f156) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 0c4ae68c66a..d37d095d206 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -36,6 +36,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); #define ROUND_ADDR(addr, mask) ((void *)((UINT_PTR)(addr) & ~(UINT_PTR)(mask))) +#define CONN_SRC_CC 0x0080 #define CONN_SRC_CC2 0x0082 #define CONN_SRC_RPN0 0x0100 @@ -1397,9 +1398,9 @@ static BOOL set_gen_from_connection(fluid_voice_t *fluid_voice, const CONNECTION static BOOL mod_from_connection(USHORT source, USHORT transform, UINT *fluid_source, UINT *fluid_flags) { UINT flags = FLUID_MOD_GC; - if (source >= CONN_SRC_CC1 && source <= CONN_SRC_CC1 + 0x7f) + if (source >= CONN_SRC_CC && source <= CONN_SRC_CC + 0x7f) { - *fluid_source = source; + *fluid_source = source - CONN_SRC_CC; flags = FLUID_MOD_CC; } else switch (source) From 68c129313377d85d5e4a093acfdd522ecaec5cd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 18 Oct 2023 11:54:39 +0200 Subject: [PATCH 2654/2777] dmsynth: Fix FluidSynth generators for direct connections. (cherry picked from commit c7ca1643f752f2f5f85b52ede9c4cda8e959b564) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index d37d095d206..2faa6149617 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -1348,7 +1348,7 @@ static BOOL set_gen_from_connection(fluid_voice_t *fluid_voice, const CONNECTION { if (!gen_from_connection(conn, &gen)) return FALSE; } - if (conn->usSource == CONN_SRC_KEYNUMBER) + else if (conn->usSource == CONN_SRC_KEYNUMBER) { switch (conn->usDestination) { From 6909f86942adaaf367380153fc9cc8f4b51ea8f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 16 Oct 2023 19:44:37 +0200 Subject: [PATCH 2655/2777] dmsynth: Convert modulator values from DLS2 to SF2 convention. (cherry picked from commit 7f629f7f542a14cdd0a58ac2af8bb26d7d0d2d32) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 2faa6149617..12dda640de4 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -1339,6 +1339,7 @@ static BOOL gen_from_connection(const CONNECTION *conn, UINT *gen) static BOOL set_gen_from_connection(fluid_voice_t *fluid_voice, const CONNECTION *conn) { + double value; UINT gen; if (conn->usControl != CONN_SRC_NONE) return FALSE; @@ -1391,7 +1392,16 @@ static BOOL set_gen_from_connection(fluid_voice_t *fluid_voice, const CONNECTION return FALSE; } - fluid_voice_gen_set(fluid_voice, gen, conn->lScale); + /* SF2 / FluidSynth use 0.1% as "Sustain Level" unit, DLS2 uses percent, meaning is also reversed */ + if (gen == GEN_MODENVSUSTAIN || gen == GEN_VOLENVSUSTAIN) value = 1000 - conn->lScale * 10 / 65536.; + /* FIXME: SF2 and FluidSynth use 1200 * log2(f / 8.176) for absolute freqs, + * whereas DLS2 uses (1200 * log2(f / 440.) + 6900) * 65536. The values + * are very close but not strictly identical and we may need a conversion. + */ + else if (conn->lScale == 0x80000000) value = -32768; + else value = conn->lScale / 65536.; + fluid_voice_gen_set(fluid_voice, gen, value); + return TRUE; } @@ -1434,6 +1444,7 @@ static BOOL add_mod_from_connection(fluid_voice_t *fluid_voice, const CONNECTION { fluid_mod_t *mod; UINT gen = -1; + double value; switch (MAKELONG(conn->usSource, conn->usDestination)) { @@ -1463,7 +1474,17 @@ static BOOL add_mod_from_connection(fluid_voice_t *fluid_voice, const CONNECTION fluid_mod_set_source1(mod, src1, flags1); fluid_mod_set_source2(mod, src2, flags2); fluid_mod_set_dest(mod, gen); - fluid_mod_set_amount(mod, conn->lScale); + + /* SF2 / FluidSynth use 0.1% as "Sustain Level" unit, DLS2 uses percent, meaning is also reversed */ + if (gen == GEN_MODENVSUSTAIN || gen == GEN_VOLENVSUSTAIN) value = 1000 - conn->lScale * 10 / 65536.; + /* FIXME: SF2 and FluidSynth use 1200 * log2(f / 8.176) for absolute freqs, + * whereas DLS2 uses (1200 * log2(f / 440.) + 6900) * 65536. The values + * are very close but not strictly identical and we may need a conversion. + */ + else if (conn->lScale == 0x80000000) value = -32768; + else value = conn->lScale / 65536.; + fluid_mod_set_amount(mod, value); + fluid_voice_add_mod(fluid_voice, mod, FLUID_VOICE_OVERWRITE); return TRUE; From e4df1b494706f3f021a3be8ce60437d0a4e967a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 16 Oct 2023 19:44:37 +0200 Subject: [PATCH 2656/2777] dmsynth: Set default modulators according to the DLS2 spec. (cherry picked from commit 4106217718248369943932a7e048c2bfe281b27b) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 210 ++++++++++++++++++++++++ libs/fluidsynth/src/synth/fluid_gen.c | 4 + libs/fluidsynth/src/synth/fluid_synth.c | 2 + 3 files changed, 216 insertions(+) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 12dda640de4..c6e5786c6a9 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -31,6 +31,7 @@ #include "dls2.h" #include +#include WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); @@ -39,10 +40,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); #define CONN_SRC_CC 0x0080 #define CONN_SRC_CC2 0x0082 #define CONN_SRC_RPN0 0x0100 +#define CONN_SRC_RPN1 0x0101 +#define CONN_SRC_RPN2 0x0102 #define CONN_TRN_BIPOLAR (1<<4) #define CONN_TRN_INVERT (1<<5) +#define CONN_TRANSFORM(src, ctrl, dst) (((src) & 0x3f) << 10) | (((ctrl) & 0x3f) << 4) | ((dst) & 0xf) + static const char *debugstr_conn_src(UINT src) { switch (src) @@ -67,6 +72,7 @@ static const char *debugstr_conn_src(UINT src) case CONN_SRC_CC2: return "SRC_CC2"; case CONN_SRC_RPN0: return "SRC_RPN0"; + case CONN_SRC_RPN2: return "SRC_RPN2"; } return wine_dbg_sprintf("%#x", src); @@ -424,6 +430,52 @@ static ULONG WINAPI synth_Release(IDirectMusicSynth8 *iface) return ref; } +static void synth_reset_default_values(struct synth *This) +{ + BYTE chan; + + fluid_synth_system_reset(This->fluid_synth); + + for (chan = 0; chan < 0x10; chan++) + { + fluid_synth_cc(This->fluid_synth, chan | 0xe0 /* PITCH_BEND */, 0, 0); + fluid_synth_cc(This->fluid_synth, chan | 0xd0 /* CHANNEL_PRESSURE */, 0, 0); + + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x01 /* MODULATION_MSB */, 0); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x21 /* MODULATION_LSB */, 0); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x07 /* VOLUME_MSB */, 0); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x27 /* VOLUME_LSB */, 100); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x0a /* PAN_MSB */, 0); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x0a /* PAN_LSB */, 64); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x0b /* EXPRESSION_MSB */, 0); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x2b /* EXPRESSION_LSB */, 127); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x40 /* SUSTAIN_SWITCH */, 0); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x5b /* EFFECTS_DEPTH1 / Reverb Send */, 40); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x5d /* EFFECTS_DEPTH3 / Chorus Send */, 0); + + /* RPN0 Pitch Bend Range */ + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x64 /* RPN_LSB */, 0); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x65 /* RPN_MSB */, 0); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x06 /* DATA_ENTRY_MSB */, 0); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x26 /* DATA_ENTRY_LSB */, 2); + + /* RPN1 Fine Tuning */ + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x64 /* RPN_LSB */, 0); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x65 /* RPN_MSB */, 1); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x06 /* DATA_ENTRY_MSB */, 0); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x26 /* DATA_ENTRY_LSB */, 0); + + /* RPN2 Coarse Tuning */ + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x64 /* RPN_LSB */, 0); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x65 /* RPN_MSB */, 1); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x06 /* DATA_ENTRY_MSB */, 0); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x26 /* DATA_ENTRY_LSB */, 0); + + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x64 /* RPN_LSB */, 127); + fluid_synth_cc(This->fluid_synth, chan | 0xb0 /* CONTROL_CHANGE */, 0x65 /* RPN_MSB */, 127); + } +} + static HRESULT WINAPI synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *params) { struct synth *This = impl_from_IDirectMusicSynth8(iface); @@ -514,6 +566,7 @@ static HRESULT WINAPI synth_Open(IDirectMusicSynth8 *iface, DMUS_PORTPARAMS *par if (!(This->fluid_synth = new_fluid_synth(This->fluid_settings))) return E_OUTOFMEMORY; if ((id = fluid_synth_add_sfont(This->fluid_synth, This->fluid_sfont)) == FLUID_FAILED) WARN("Failed to add fluid_sfont to fluid_synth\n"); + synth_reset_default_values(This); This->params = actual; This->open = TRUE; @@ -1512,6 +1565,162 @@ static void add_voice_connections(fluid_voice_t *fluid_voice, const CONNECTIONLI } } +static void set_default_voice_connections(fluid_voice_t *fluid_voice) +{ + const CONNECTION connections[] = + { +#define ABS_PITCH_HZ(f) (LONG)((1200 * log2((f) / 440.) + 6900) * 65536) +#define ABS_TIME_MS(x) ((x) ? (LONG)(1200 * log2((x) / 1000.) * 65536) : 0x80000000) +#define REL_PITCH_CTS(x) ((x) * 65536) +#define REL_GAIN_DB(x) ((-x) * 10 * 65536) + + /* Modulator LFO */ + {.usDestination = CONN_DST_LFO_FREQUENCY, .lScale = ABS_PITCH_HZ(5)}, + {.usDestination = CONN_DST_LFO_STARTDELAY, .lScale = ABS_TIME_MS(10)}, + + /* Vibrato LFO */ + {.usDestination = CONN_DST_VIB_FREQUENCY, .lScale = ABS_PITCH_HZ(5)}, + {.usDestination = CONN_DST_VIB_STARTDELAY, .lScale = ABS_TIME_MS(10)}, + /* Vol EG */ + {.usDestination = CONN_DST_EG1_DELAYTIME, .lScale = ABS_TIME_MS(0)}, + {.usDestination = CONN_DST_EG1_ATTACKTIME, .lScale = ABS_TIME_MS(0)}, + {.usDestination = CONN_DST_EG1_HOLDTIME, .lScale = ABS_TIME_MS(0)}, + {.usDestination = CONN_DST_EG1_DECAYTIME, .lScale = ABS_TIME_MS(0)}, + {.usDestination = CONN_DST_EG1_SUSTAINLEVEL, .lScale = 100 * 65536}, + {.usDestination = CONN_DST_EG1_RELEASETIME, .lScale = ABS_TIME_MS(0)}, + /* FIXME: {.usDestination = CONN_DST_EG1_SHUTDOWNTIME, .lScale = ABS_TIME_MS(15)}, */ + {.usSource = CONN_SRC_KEYONVELOCITY, .usDestination = CONN_DST_EG1_ATTACKTIME, .lScale = 0}, + {.usSource = CONN_SRC_KEYNUMBER, .usDestination = CONN_DST_EG1_DECAYTIME, .lScale = 0}, + {.usSource = CONN_SRC_KEYNUMBER, .usDestination = CONN_DST_EG1_HOLDTIME, .lScale = 0}, + + /* Modulator EG */ + {.usDestination = CONN_DST_EG2_DELAYTIME, .lScale = ABS_TIME_MS(0)}, + {.usDestination = CONN_DST_EG2_ATTACKTIME, .lScale = ABS_TIME_MS(0)}, + {.usDestination = CONN_DST_EG2_HOLDTIME, .lScale = ABS_TIME_MS(0)}, + {.usDestination = CONN_DST_EG2_DECAYTIME, .lScale = ABS_TIME_MS(0)}, + {.usDestination = CONN_DST_EG2_SUSTAINLEVEL, .lScale = 100 * 65536}, + {.usDestination = CONN_DST_EG2_RELEASETIME, .lScale = ABS_TIME_MS(0)}, + {.usSource = CONN_SRC_KEYONVELOCITY, .usDestination = CONN_DST_EG2_ATTACKTIME, .lScale = 0}, + {.usSource = CONN_SRC_KEYNUMBER, .usDestination = CONN_DST_EG2_DECAYTIME, .lScale = 0}, + {.usSource = CONN_SRC_KEYNUMBER, .usDestination = CONN_DST_EG2_HOLDTIME, .lScale = 0}, + + /* Key number generator */ + /* FIXME: This doesn't seem to be supported by FluidSynth, there's also no MIDINOTE source */ + /* {.usSource = CONN_SRC_MIDINOTE?, .usDestination = CONN_DST_KEYNUMBER, .lScale = REL_PITCH_CTS(12800)}, */ + { + .usSource = CONN_SRC_RPN2, .usDestination = CONN_DST_KEYNUMBER, .lScale = REL_PITCH_CTS(6400), + .usTransform = CONN_TRANSFORM(CONN_TRN_BIPOLAR, CONN_TRN_NONE, CONN_TRN_NONE), + }, + + /* Filter */ + {.usDestination = CONN_DST_FILTER_CUTOFF, .lScale = 0x7fffffff}, + {.usDestination = CONN_DST_FILTER_Q, .lScale = 0}, + { + .usSource = CONN_SRC_LFO, .usDestination = CONN_DST_FILTER_CUTOFF, .lScale = 0, + .usTransform = CONN_TRANSFORM(CONN_TRN_BIPOLAR, CONN_TRN_NONE, CONN_TRN_NONE), + }, + { + .usSource = CONN_SRC_LFO, .usControl = CONN_SRC_CC1, .usDestination = CONN_DST_FILTER_CUTOFF, .lScale = 0, + .usTransform = CONN_TRANSFORM(CONN_TRN_BIPOLAR, CONN_TRN_NONE, CONN_TRN_NONE), + }, + { + .usSource = CONN_SRC_LFO, .usControl = CONN_SRC_CHANNELPRESSURE, .usDestination = CONN_DST_FILTER_CUTOFF, .lScale = 0, + .usTransform = CONN_TRANSFORM(CONN_TRN_BIPOLAR, CONN_TRN_NONE, CONN_TRN_NONE), + }, + {.usSource = CONN_SRC_EG2, .usDestination = CONN_DST_FILTER_CUTOFF, .lScale = 0}, + {.usSource = CONN_SRC_KEYONVELOCITY, .usDestination = CONN_DST_FILTER_CUTOFF, .lScale = 0}, + {.usSource = CONN_SRC_KEYNUMBER, .usDestination = CONN_DST_FILTER_CUTOFF, .lScale = 0}, + + /* Gain */ + { + .usSource = CONN_SRC_LFO, .usDestination = CONN_DST_GAIN, .lScale = REL_GAIN_DB(0), + .usTransform = CONN_TRANSFORM(CONN_TRN_BIPOLAR, CONN_TRN_NONE, CONN_TRN_NONE), + }, + { + .usSource = CONN_SRC_LFO, .usControl = CONN_SRC_CC1, .usDestination = CONN_DST_GAIN, .lScale = REL_GAIN_DB(0), + .usTransform = CONN_TRANSFORM(CONN_TRN_BIPOLAR, CONN_TRN_NONE, CONN_TRN_NONE), + }, + { + .usSource = CONN_SRC_LFO, .usControl = CONN_SRC_CHANNELPRESSURE, .usDestination = CONN_DST_GAIN, .lScale = REL_GAIN_DB(0), + .usTransform = CONN_TRANSFORM(CONN_TRN_BIPOLAR, CONN_TRN_NONE, CONN_TRN_NONE), + }, + { + .usSource = CONN_SRC_KEYONVELOCITY, .usDestination = CONN_DST_GAIN, .lScale = REL_GAIN_DB(-96), + .usTransform = CONN_TRANSFORM(CONN_TRN_CONCAVE | CONN_TRN_INVERT, CONN_TRN_NONE, CONN_TRN_NONE), + }, + { + .usSource = CONN_SRC_CC7, .usDestination = CONN_DST_GAIN, .lScale = REL_GAIN_DB(-96), + .usTransform = CONN_TRANSFORM(CONN_TRN_CONCAVE | CONN_TRN_INVERT, CONN_TRN_NONE, CONN_TRN_NONE), + }, + { + .usSource = CONN_SRC_CC11, .usDestination = CONN_DST_GAIN, .lScale = REL_GAIN_DB(-96), + .usTransform = CONN_TRANSFORM(CONN_TRN_CONCAVE | CONN_TRN_INVERT, CONN_TRN_NONE, CONN_TRN_NONE), + }, + + /* Pitch */ + {.usDestination = CONN_DST_PITCH, .lScale = REL_PITCH_CTS(0)}, + { + .usSource = CONN_SRC_PITCHWHEEL, .usControl = CONN_SRC_RPN0, .usDestination = CONN_DST_PITCH, .lScale = REL_PITCH_CTS(12800), + .usTransform = CONN_TRANSFORM(CONN_TRN_BIPOLAR, CONN_TRN_NONE, CONN_TRN_NONE), + }, + /* FIXME: key to pitch default should be 12800 but FluidSynth GEN_PITCH modulator doesn't work as expected */ + {.usSource = CONN_SRC_KEYNUMBER, .usDestination = CONN_DST_PITCH, .lScale = REL_PITCH_CTS(0)}, + { + .usSource = CONN_SRC_RPN1, .usDestination = CONN_DST_PITCH, .lScale = REL_PITCH_CTS(100), + .usTransform = CONN_TRANSFORM(CONN_TRN_BIPOLAR, CONN_TRN_NONE, CONN_TRN_NONE), + }, + { + .usSource = CONN_SRC_VIBRATO, .usDestination = CONN_DST_PITCH, .lScale = REL_PITCH_CTS(0), + .usTransform = CONN_TRANSFORM(CONN_TRN_BIPOLAR, CONN_TRN_NONE, CONN_TRN_NONE), + }, + { + .usSource = CONN_SRC_VIBRATO, .usControl = CONN_SRC_CC1, .usDestination = CONN_DST_PITCH, .lScale = REL_PITCH_CTS(0), + .usTransform = CONN_TRANSFORM(CONN_TRN_BIPOLAR, CONN_TRN_NONE, CONN_TRN_NONE), + }, + { + .usSource = CONN_SRC_VIBRATO, .usControl = CONN_SRC_CHANNELPRESSURE, .usDestination = CONN_DST_PITCH, .lScale = REL_PITCH_CTS(0), + .usTransform = CONN_TRANSFORM(CONN_TRN_BIPOLAR, CONN_TRN_NONE, CONN_TRN_NONE), + }, + { + .usSource = CONN_SRC_LFO, .usDestination = CONN_DST_PITCH, .lScale = REL_PITCH_CTS(0), + .usTransform = CONN_TRANSFORM(CONN_TRN_BIPOLAR, CONN_TRN_NONE, CONN_TRN_NONE), + }, + { + .usSource = CONN_SRC_LFO, .usControl = CONN_SRC_CC1, .usDestination = CONN_DST_PITCH, .lScale = REL_PITCH_CTS(0), + .usTransform = CONN_TRANSFORM(CONN_TRN_BIPOLAR, CONN_TRN_NONE, CONN_TRN_NONE), + }, + { + .usSource = CONN_SRC_LFO, .usControl = CONN_SRC_CHANNELPRESSURE, .usDestination = CONN_DST_PITCH, .lScale = REL_PITCH_CTS(0), + .usTransform = CONN_TRANSFORM(CONN_TRN_BIPOLAR, CONN_TRN_NONE, CONN_TRN_NONE), + }, + {.usSource = CONN_SRC_EG2, .usDestination = CONN_DST_PITCH, .lScale = REL_PITCH_CTS(0)}, + + /* Output */ + {.usDestination = CONN_DST_PAN, .lScale = 0}, + { + .usSource = CONN_SRC_CC10, .usDestination = CONN_DST_PAN, .lScale = 508 * 65536, + .usTransform = CONN_TRANSFORM(CONN_TRN_BIPOLAR, CONN_TRN_NONE, CONN_TRN_NONE), + }, + {.usSource = CONN_SRC_CC91, .usDestination = CONN_DST_REVERB, .lScale = 1000 * 65536}, + {.usDestination = CONN_DST_REVERB, .lScale = 0}, + {.usSource = CONN_SRC_CC93, .usDestination = CONN_DST_CHORUS, .lScale = 1000 * 65536}, + {.usDestination = CONN_DST_CHORUS, .lScale = 0}, + +#undef ABS_PITCH_HZ +#undef ABS_TIME_MS +#undef REL_PITCH_CTS +#undef REL_GAIN_DB + }; + CONNECTIONLIST list = {.cbSize = sizeof(CONNECTIONLIST), .cConnections = ARRAY_SIZE(connections)}; + + fluid_voice_gen_set(fluid_voice, GEN_KEYNUM, -1.); + fluid_voice_gen_set(fluid_voice, GEN_VELOCITY, -1.); + fluid_voice_gen_set(fluid_voice, GEN_SCALETUNE, 100.0); + fluid_voice_gen_set(fluid_voice, GEN_OVERRIDEROOTKEY, -1.); + + add_voice_connections(fluid_voice, &list, connections); +} + static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *fluid_synth, int chan, int key, int vel) { struct instrument *instrument = fluid_preset_get_data(fluid_preset); @@ -1554,6 +1763,7 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui return FLUID_FAILED; } + set_default_voice_connections(fluid_voice); LIST_FOR_EACH_ENTRY(articulation, &instrument->articulations, struct articulation, entry) add_voice_connections(fluid_voice, &articulation->list, articulation->connections); LIST_FOR_EACH_ENTRY(articulation, ®ion->articulations, struct articulation, entry) diff --git a/libs/fluidsynth/src/synth/fluid_gen.c b/libs/fluidsynth/src/synth/fluid_gen.c index 2ce2b0f74b5..232ea294fd9 100644 --- a/libs/fluidsynth/src/synth/fluid_gen.c +++ b/libs/fluidsynth/src/synth/fluid_gen.c @@ -109,7 +109,11 @@ fluid_gen_init(fluid_gen_t *gen, fluid_channel_t *channel) gen[i].flags = GEN_UNUSED; gen[i].mod = 0.0; gen[i].nrpn = (channel == NULL) ? 0.0 : fluid_channel_get_gen(channel, i); +#if 0 /* unused in Wine */ gen[i].val = fluid_gen_info[i].def; +#else + gen[i].val = 0.0; +#endif } } diff --git a/libs/fluidsynth/src/synth/fluid_synth.c b/libs/fluidsynth/src/synth/fluid_synth.c index 3b83e3d8b73..0580ed271f6 100644 --- a/libs/fluidsynth/src/synth/fluid_synth.c +++ b/libs/fluidsynth/src/synth/fluid_synth.c @@ -300,6 +300,7 @@ fluid_synth_init(void) init_dither(); +#if 0 /* unused in Wine */ /* custom_breath2att_mod is not a default modulator specified in SF2.01. it is intended to replace default_vel2att_mod on demand using API fluid_set_breath_mode() or command shell setbreathmode. @@ -480,6 +481,7 @@ fluid_synth_init(void) fluid_mod_set_dest(&custom_balance_mod, GEN_CUSTOM_BALANCE); /* Destination: stereo balance */ /* Amount: 96 dB of attenuation (on the opposite channel) */ fluid_mod_set_amount(&custom_balance_mod, FLUID_PEAK_ATTENUATION); /* Amount: 960 */ +#endif /* unused in Wine */ #if defined(LIBINSTPATCH_SUPPORT) /* defer libinstpatch init to fluid_instpatch.c to avoid #include "libinstpatch.h" */ From 621bcbccab63ad5c6b1c00f8371c6d17250f93f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 12 Oct 2023 22:18:06 +0200 Subject: [PATCH 2657/2777] dmband: Download segment tracks if performance auto-download is set. (cherry picked from commit 10a1e533c3de65ae29078be607148531a22e654c) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/bandtrack.c | 4 ++-- dlls/dmime/dmime_private.h | 2 +- dlls/dmime/performance.c | 2 +- dlls/dmime/segmentstate.c | 17 ++++++++++++++--- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index e0acb6ff62d..5229204b284 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -234,7 +234,7 @@ static HRESULT WINAPI band_track_SetParam(IDirectMusicTrack8 *iface, REFGUID typ band_connect_to_collection(entry->band, param); } else if (IsEqualGUID(type, &GUID_Disable_Auto_Download)) - FIXME("GUID_Disable_Auto_Download not handled yet\n"); + This->header.bAutoDownload = FALSE; else if (IsEqualGUID(type, &GUID_Download)) FIXME("GUID_Download not handled yet\n"); else if (IsEqualGUID(type, &GUID_DownloadToAudioPath)) @@ -265,7 +265,7 @@ static HRESULT WINAPI band_track_SetParam(IDirectMusicTrack8 *iface, REFGUID typ IDirectMusicPerformance_Release(performance); } else if (IsEqualGUID(type, &GUID_Enable_Auto_Download)) - FIXME("GUID_Enable_Auto_Download not handled yet\n"); + This->header.bAutoDownload = TRUE; else if (IsEqualGUID(type, &GUID_IDirectMusicBand)) FIXME("GUID_IDirectMusicBand not handled yet\n"); else if (IsEqualGUID(type, &GUID_StandardMIDIFile)) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index c1f777f3949..7f1937eaa0f 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -75,7 +75,7 @@ extern void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath*,IDirectSo extern HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, IDirectMusicPerformance *performance, IDirectMusicSegmentState **ret_iface); extern HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance *performance); -extern HRESULT segment_state_end_play(IDirectMusicSegmentState *iface); +extern HRESULT segment_state_end_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance *performance); extern HRESULT wave_track_create_from_chunk(IStream *stream, struct chunk_entry *parent, IDirectMusicTrack8 **ret_iface); diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index dc6ef575713..ea2a3cc52dd 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1740,7 +1740,7 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, if (IsEqualGUID(¬if->guidNotificationType, &GUID_NOTIFICATION_SEGMENT) && notif->dwNotificationOption == DMUS_NOTIFICATION_SEGEND) { - if (FAILED(hr = segment_state_end_play((IDirectMusicSegmentState *)notif->punkUser))) + if (FAILED(hr = segment_state_end_play((IDirectMusicSegmentState *)notif->punkUser, performance))) WARN("Failed to end segment state %p, hr %#lx\n", notif->punkUser, hr); } diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index 1cb9daac69a..c43d833fedd 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -51,6 +51,7 @@ struct segment_state MUSIC_TIME start_time; MUSIC_TIME start_point; MUSIC_TIME end_point; + BOOL auto_download; struct list tracks; }; @@ -103,7 +104,7 @@ static ULONG WINAPI segment_state_Release(IDirectMusicSegmentState8 *iface) if (!ref) { - segment_state_end_play((IDirectMusicSegmentState *)iface); + segment_state_end_play((IDirectMusicSegmentState *)iface, NULL); if (This->segment) IDirectMusicSegment_Release(This->segment); free(This); } @@ -224,8 +225,13 @@ HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time This->segment = segment; IDirectMusicSegment_AddRef(This->segment); + if (SUCCEEDED(hr = IDirectMusicPerformance_GetGlobalParam(performance, &GUID_PerfAutoDownload, + &This->auto_download, sizeof(This->auto_download))) && This->auto_download) + hr = IDirectMusicSegment_SetParam(segment, &GUID_DownloadToAudioPath, -1, + DMUS_SEG_ALLTRACKS, 0, performance); + This->start_time = start_time; - hr = IDirectMusicSegment_GetStartPoint(segment, &This->start_point); + if (SUCCEEDED(hr)) hr = IDirectMusicSegment_GetStartPoint(segment, &This->start_point); if (SUCCEEDED(hr)) hr = IDirectMusicSegment_GetLength(segment, &This->end_point); for (i = 0; SUCCEEDED(hr); i++) @@ -283,10 +289,11 @@ HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerforma return hr; } -HRESULT segment_state_end_play(IDirectMusicSegmentState *iface) +HRESULT segment_state_end_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance *performance) { struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); struct track_entry *entry, *next; + HRESULT hr; LIST_FOR_EACH_ENTRY_SAFE(entry, next, &This->tracks, struct track_entry, entry) { @@ -294,5 +301,9 @@ HRESULT segment_state_end_play(IDirectMusicSegmentState *iface) track_entry_destroy(entry); } + if (performance && This->auto_download && FAILED(hr = IDirectMusicSegment_SetParam(This->segment, + &GUID_UnloadFromAudioPath, -1, DMUS_SEG_ALLTRACKS, 0, performance))) + ERR("Failed to unload segment from performance, hr %#lx\n", hr); + return S_OK; } From 125621d3e288f6be2ea1f8bd5c8e869459a3f5a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 16 Oct 2023 19:06:34 +0200 Subject: [PATCH 2658/2777] dmband: Set DMUS_PATCH_PMSG bank LSB/MSB from instrument patch. (cherry picked from commit e9fdbe4d5524db1748bc4e7222ba41477aaa918e) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/band.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dlls/dmband/band.c b/dlls/dmband/band.c index 456bb20143e..4c593741516 100644 --- a/dlls/dmband/band.c +++ b/dlls/dmband/band.c @@ -496,6 +496,7 @@ HRESULT band_send_messages(IDirectMusicBand *iface, IDirectMusicPerformance *per LIST_FOR_EACH_ENTRY_REV(entry, &This->instruments, struct instrument_entry, entry) { + DWORD patch = entry->instrument.dwPatch; DMUS_PATCH_PMSG *msg; if (FAILED(hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(*msg), @@ -510,6 +511,13 @@ HRESULT band_send_messages(IDirectMusicBand *iface, IDirectMusicPerformance *per msg->dwGroupID = 1; msg->byInstrument = entry->instrument.dwPatch; + msg->byInstrument = patch & 0x7F; + patch >>= 8; + msg->byLSB = patch & 0x7f; + patch >>= 8; + msg->byMSB = patch & 0x7f; + patch >>= 8; + if (FAILED(hr = IDirectMusicGraph_StampPMsg(graph, (DMUS_PMSG *)msg)) || FAILED(hr = IDirectMusicPerformance_SendPMsg(performance, (DMUS_PMSG *)msg))) { From a4ca3a4655c0c0e16677a61b299e49c16d2beddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 12 Oct 2023 22:18:06 +0200 Subject: [PATCH 2659/2777] dmime: Only use index if group is set in IDirectMusicSegment_SetParam. (cherry picked from commit 12d3ccb495dbe9f95625ba84a21be655744c6269) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segment.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index fc277ba73f9..280abaa004c 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -403,8 +403,11 @@ static HRESULT WINAPI segment_SetParam(IDirectMusicSegment8 *iface, REFGUID type LIST_FOR_EACH_ENTRY(entry, &This->tracks, struct track_entry, entry) { - if (group != -1 && !(group & entry->dwGroupBits)) continue; - if (index != DMUS_SEG_ALLTRACKS && index--) continue; + if (group != -1) + { + if (!(group & entry->dwGroupBits)) continue; + if (index != DMUS_SEG_ALLTRACKS && index--) continue; + } hr = IDirectMusicTrack_IsParamSupported(entry->pTrack, type); if (hr == DMUS_E_TYPE_UNSUPPORTED) continue; From 238720b17321fb1e9d0aeeb0829554d55c445b5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 12 Oct 2023 22:46:06 +0200 Subject: [PATCH 2660/2777] dmime: Don't interrupt track iteration if SetParam failed. (cherry picked from commit 5a66857fb483e9bc5c2171364554d3731e09de67) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segment.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index 280abaa004c..d7402911f00 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -409,11 +409,9 @@ static HRESULT WINAPI segment_SetParam(IDirectMusicSegment8 *iface, REFGUID type if (index != DMUS_SEG_ALLTRACKS && index--) continue; } - hr = IDirectMusicTrack_IsParamSupported(entry->pTrack, type); - if (hr == DMUS_E_TYPE_UNSUPPORTED) continue; - - hr = IDirectMusicTrack_SetParam(entry->pTrack, type, music_time, param); - if (FAILED(hr)) break; + if (SUCCEEDED(hr = IDirectMusicTrack_IsParamSupported(entry->pTrack, type)) + && FAILED(hr = IDirectMusicTrack_SetParam(entry->pTrack, type, music_time, param))) + WARN("SetParam for track %p failed, hr %#lx\n", entry->pTrack, hr); } return S_OK; From aac7f71f6a6ab5e8b7b27b2af07a3e63348395be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 16 Oct 2023 20:12:03 +0200 Subject: [PATCH 2661/2777] dmime: Adjust MIDI message time with DMUS_NOTE_PMSG nOffset. (cherry picked from commit 65e388137c6117aaf8f99cef808d32afa29c7639) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index ea2a3cc52dd..8ea01b168d7 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1700,6 +1700,7 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, { DMUS_NOTE_PMSG *note = (DMUS_NOTE_PMSG *)msg; + msg->mtTime += note->nOffset; if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_REFTIME | DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, 0x90 /* NOTE_ON */, note->bMidiValue, note->bVelocity))) WARN("Failed to translate message to MIDI, hr %#lx\n", hr); From c1b23e5d3818b4e8f106f07f910df4e7051e3e63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 16 Oct 2023 20:03:19 +0200 Subject: [PATCH 2662/2777] dmusic: Use a dmusic_midi.h header for MIDI messages. (cherry picked from commit 2c4fc0adcf66e47455e01651e464b71c8d244b0c) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 11 ++++++----- dlls/dmsynth/Makefile.in | 1 + dlls/dmsynth/synth.c | 9 +++++---- dlls/dmusic/dmusic_midi.h | 40 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 dlls/dmusic/dmusic_midi.h diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 8ea01b168d7..f120cc6f0a9 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -19,6 +19,7 @@ */ #include "dmime_private.h" +#include "dmusic_midi.h" #include "wine/rbtree.h" WINE_DEFAULT_DEBUG_CHANNEL(dmime); @@ -1702,12 +1703,12 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, msg->mtTime += note->nOffset; if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_REFTIME | DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, - 0x90 /* NOTE_ON */, note->bMidiValue, note->bVelocity))) + MIDI_NOTE_ON, note->bMidiValue, note->bVelocity))) WARN("Failed to translate message to MIDI, hr %#lx\n", hr); msg->mtTime += note->mtDuration; if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_QUEUE, - 0x80 /* NOTE_OFF */, note->bMidiValue, 0))) + MIDI_NOTE_OFF, note->bMidiValue, 0))) WARN("Failed to translate message to MIDI, hr %#lx\n", hr); break; @@ -1718,15 +1719,15 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, DMUS_PATCH_PMSG *patch = (DMUS_PATCH_PMSG *)msg; if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_REFTIME | DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, - 0xb0 /* Control Change */, 0x00 /* CC: Bank MSB */, patch->byMSB))) + MIDI_CONTROL_CHANGE, MIDI_CC_BANK_MSB, patch->byMSB))) WARN("Failed to translate message to MIDI, hr %#lx\n", hr); if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_REFTIME | DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, - 0xb0 /* Control Change */, 0x20 /* CC: Bank LSB */, patch->byLSB))) + MIDI_CONTROL_CHANGE, MIDI_CC_BANK_LSB, patch->byLSB))) WARN("Failed to translate message to MIDI, hr %#lx\n", hr); if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_REFTIME | DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, - 0xc0 /* Program Change */, patch->byInstrument, 0))) + MIDI_PROGRAM_CHANGE, patch->byInstrument, 0))) WARN("Failed to translate message to MIDI, hr %#lx\n", hr); break; diff --git a/dlls/dmsynth/Makefile.in b/dlls/dmsynth/Makefile.in index 7c6d2db721b..85cac5912ac 100644 --- a/dlls/dmsynth/Makefile.in +++ b/dlls/dmsynth/Makefile.in @@ -1,6 +1,7 @@ MODULE = dmsynth.dll IMPORTS = $(FLUIDSYNTH_PE_LIBS) dxguid uuid ole32 advapi32 user32 EXTRAINCL = $(FLUIDSYNTH_PE_CFLAGS) +PARENTSRC = ../dmusic C_SRCS = \ dmsynth_main.c \ diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index c6e5786c6a9..c3e0c90880e 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -28,6 +28,7 @@ #include "dmksctrl.h" #include "dmsynth_private.h" +#include "dmusic_midi.h" #include "dls2.h" #include @@ -1066,16 +1067,16 @@ static HRESULT WINAPI synth_Render(IDirectMusicSynth8 *iface, short *buffer, switch (status) { - case 0x80: + case MIDI_NOTE_OFF: fluid_synth_noteoff(This->fluid_synth, chan, event->midi[1]); break; - case 0x90: + case MIDI_NOTE_ON: fluid_synth_noteon(This->fluid_synth, chan, event->midi[1], event->midi[2]); break; - case 0xb0: + case MIDI_CONTROL_CHANGE: fluid_synth_cc(This->fluid_synth, chan, event->midi[1], event->midi[2]); break; - case 0xc0: + case MIDI_PROGRAM_CHANGE: fluid_synth_program_change(This->fluid_synth, chan, event->midi[1]); break; default: diff --git a/dlls/dmusic/dmusic_midi.h b/dlls/dmusic/dmusic_midi.h new file mode 100644 index 00000000000..e545bcaf8cb --- /dev/null +++ b/dlls/dmusic/dmusic_midi.h @@ -0,0 +1,40 @@ +/* + * Copyright 2023 Rémi Bernon for CodeWeavers + * + * This program 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 program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "stdarg.h" +#include "stddef.h" + +#include "windef.h" +#include "winbase.h" + +enum midi_message +{ + MIDI_NOTE_OFF = 0x80, + MIDI_NOTE_ON = 0x90, + MIDI_KEY_PRESSURE = 0xa0, + MIDI_CONTROL_CHANGE = 0xb0, + MIDI_PROGRAM_CHANGE = 0xc0, + MIDI_CHANNEL_PRESSURE = 0xd0, + MIDI_PITCH_BEND_CHANGE = 0xe0, +}; + +enum midi_control +{ + MIDI_CC_BANK_MSB = 0x00, + MIDI_CC_BANK_LSB = 0x20, +}; From 0b67f352fe3a958c1aafbc0244d26061a90eb622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 16 Oct 2023 19:07:48 +0200 Subject: [PATCH 2663/2777] dmime: Translate some DMUS_CURVE_PMSG messages to MIDI. (cherry picked from commit 8a4989f3a63827a56ac03f34c31762e3689f9ddf) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index f120cc6f0a9..815e8295ed8 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1714,6 +1714,27 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, break; } + case DMUS_PMSGT_CURVE: + { + DMUS_CURVE_PMSG *curve = (DMUS_CURVE_PMSG *)msg; + + msg->mtTime += curve->nOffset; + switch (curve->dwType) + { + case DMUS_CURVET_CCCURVE: + if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, + MIDI_CONTROL_CHANGE, curve->bCCData, curve->nStartValue))) + WARN("Failed to translate message to MIDI, hr %#lx\n", hr); + break; + case DMUS_CURVET_RPNCURVE: + case DMUS_CURVET_NRPNCURVE: + FIXME("Unhandled curve type %#lx\n", curve->dwType); + break; + } + + break; + } + case DMUS_PMSGT_PATCH: { DMUS_PATCH_PMSG *patch = (DMUS_PATCH_PMSG *)msg; From 71a67adf7e99552f5c6e45d5b573a128df0ab764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 16 Oct 2023 20:16:20 +0200 Subject: [PATCH 2664/2777] dmime: Remove FIXME from methods now mostly implemented. (cherry picked from commit 6631e6bc2d4a0639824f8ca563b827ff952c3488) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 815e8295ed8..a8fcd869331 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -468,7 +468,7 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS struct message *message, *next; HRESULT hr; - FIXME("(%p, %p): semi-stub\n", This, msg); + TRACE("(%p, %p)\n", This, msg); if (!(message = message_from_DMUS_PMSG(msg))) return E_POINTER; if (!This->dmusic) return DMUS_E_NO_MASTER_CLOCK; @@ -519,9 +519,11 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS static HRESULT WINAPI performance_MusicToReferenceTime(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, REFERENCE_TIME *time) { + static int once; struct performance *This = impl_from_IDirectMusicPerformance8(iface); - FIXME("(%p, %ld, %p): semi-stub\n", This, music_time, time); + if (!once++) FIXME("(%p, %ld, %p): semi-stub\n", This, music_time, time); + else TRACE("(%p, %ld, %p)\n", This, music_time, time); if (!time) return E_POINTER; *time = 0; @@ -538,9 +540,11 @@ static HRESULT WINAPI performance_MusicToReferenceTime(IDirectMusicPerformance8 static HRESULT WINAPI performance_ReferenceToMusicTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME time, MUSIC_TIME *music_time) { + static int once; struct performance *This = impl_from_IDirectMusicPerformance8(iface); - FIXME("(%p, %I64d, %p): semi-stub\n", This, time, music_time); + if (!once++) FIXME("(%p, %I64d, %p): semi-stub\n", This, time, music_time); + else TRACE("(%p, %I64d, %p)\n", This, time, music_time); if (!music_time) return E_POINTER; *music_time = 0; @@ -1657,7 +1661,7 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, struct message *message = message_from_DMUS_PMSG(msg); HRESULT hr; - FIXME("(%p, %p, %p): semi-stub\n", This, performance, msg); + TRACE("(%p, %p, %p)\n", This, performance, msg); switch (msg->dwType) { From e3935b5b0256a48c87d744a746dbd0cf8850aaef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 17 Oct 2023 11:23:16 +0200 Subject: [PATCH 2665/2777] dmime: Avoid crashing when purging notification messages. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55792 (cherry picked from commit 4d0c3d89a46029697cbc5414fc882cae3136b3d4) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index a8fcd869331..a2e611523a6 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1783,6 +1783,7 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, do { previous = LIST_ENTRY(list_head(&This->notifications), struct message, entry); + if (This->notification_timeout <= 0) break; /* negative values may be used to keep everything */ if (message->msg.rtTime - previous->msg.rtTime <= This->notification_timeout) break; list_remove(&previous->entry); list_init(&previous->entry); From 047c3fdae558650d5053f8c0e8e77512244e526c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 17 Oct 2023 11:28:42 +0200 Subject: [PATCH 2666/2777] dmime: Return S_OK from wave track SetParam GUID_UnloadFromAudioPath. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55792 (cherry picked from commit 0431c88a9dffce2bd9360fc412e26ef913f8f974) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/wavetrack.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c index def1e59fb23..79169a2a6fa 100644 --- a/dlls/dmime/wavetrack.c +++ b/dlls/dmime/wavetrack.c @@ -296,6 +296,8 @@ static HRESULT WINAPI wave_track_SetParam(IDirectMusicTrack8 *iface, REFGUID typ item->buffer = NULL; } } + + return S_OK; } return DMUS_E_TYPE_UNSUPPORTED; From bb30262e449a37f9cc0dd0a5454e59a0584106c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 17 Oct 2023 11:29:18 +0200 Subject: [PATCH 2667/2777] dmime: Return hr from wave track SetParam GUID_DownloadToAudioPath. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55792 (cherry picked from commit b1bfc52676cbb41e3fbc0f114588acc486028c7d) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/wavetrack.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c index 79169a2a6fa..fcf57c1148d 100644 --- a/dlls/dmime/wavetrack.c +++ b/dlls/dmime/wavetrack.c @@ -273,6 +273,8 @@ static HRESULT WINAPI wave_track_SetParam(IDirectMusicTrack8 *iface, REFGUID typ } } } + + return hr; } if (IsEqualGUID(type, &GUID_Enable_Auto_Download)) { FIXME("GUID_Enable_Auto_Download not handled yet\n"); From 7dd8837004c320cdf833cb193f96c2884d1038c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 17 Oct 2023 11:46:17 +0200 Subject: [PATCH 2668/2777] dmusic: Implement IDirectMusicObject interface on wave objects. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55792 (cherry picked from commit dc0431b8190b09aefa9991810c28f658802cd730) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/wave.c | 131 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 119 insertions(+), 12 deletions(-) diff --git a/dlls/dmusic/wave.c b/dlls/dmusic/wave.c index ef1cd2990ff..e5e7c4dc2a0 100644 --- a/dlls/dmusic/wave.c +++ b/dlls/dmusic/wave.c @@ -32,6 +32,7 @@ C_ASSERT(sizeof(struct sample) == offsetof(struct sample, loops[0])); struct wave { IUnknown IUnknown_iface; + struct dmobject dmobj; LONG ref; struct sample *sample; @@ -58,6 +59,20 @@ static HRESULT WINAPI wave_QueryInterface(IUnknown *iface, REFIID riid, void **r return S_OK; } + if (IsEqualIID(riid, &IID_IDirectMusicObject)) + { + *ret_iface = &This->dmobj.IDirectMusicObject_iface; + IDirectMusicObject_AddRef(&This->dmobj.IDirectMusicObject_iface); + return S_OK; + } + + if (IsEqualIID(riid, &IID_IPersistStream)) + { + *ret_iface = &This->dmobj.IPersistStream_iface; + IDirectMusicObject_AddRef(&This->dmobj.IPersistStream_iface); + return S_OK; + } + WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ret_iface); *ret_iface = NULL; return E_NOINTERFACE; @@ -96,18 +111,6 @@ static const IUnknownVtbl unknown_vtbl = wave_Release, }; -static HRESULT wave_create(IUnknown **ret_iface) -{ - struct wave *obj; - - if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; - obj->IUnknown_iface.lpVtbl = &unknown_vtbl; - obj->ref = 1; - - *ret_iface = &obj->IUnknown_iface; - return S_OK; -} - static HRESULT parse_wsmp_chunk(struct wave *This, IStream *stream, struct chunk_entry *chunk) { struct sample *sample; @@ -167,6 +170,110 @@ static HRESULT parse_wave_chunk(struct wave *This, IStream *stream, struct chunk return hr; } +static HRESULT WINAPI wave_object_ParseDescriptor(IDirectMusicObject *iface, + IStream *stream, DMUS_OBJECTDESC *desc) +{ + struct chunk_entry chunk = {0}; + HRESULT hr; + + TRACE("(%p, %p, %p)\n", iface, stream, desc); + + if (!stream || !desc) return E_POINTER; + + if ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case MAKE_IDTYPE(FOURCC_RIFF, mmioFOURCC('W','A','V','E')): + hr = dmobj_parsedescriptor(stream, &chunk, desc, + DMUS_OBJ_NAME_INFO | DMUS_OBJ_OBJECT | DMUS_OBJ_VERSION); + break; + + default: + WARN("Invalid wave chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + hr = DMUS_E_CHUNKNOTFOUND; + break; + } + } + + if (FAILED(hr)) return hr; + + TRACE("returning descriptor:\n"); + dump_DMUS_OBJECTDESC(desc); + return S_OK; +} + +static const IDirectMusicObjectVtbl wave_object_vtbl = +{ + dmobj_IDirectMusicObject_QueryInterface, + dmobj_IDirectMusicObject_AddRef, + dmobj_IDirectMusicObject_Release, + dmobj_IDirectMusicObject_GetDescriptor, + dmobj_IDirectMusicObject_SetDescriptor, + wave_object_ParseDescriptor, +}; + +static inline struct wave *impl_from_IPersistStream(IPersistStream *iface) +{ + return CONTAINING_RECORD(iface, struct wave, dmobj.IPersistStream_iface); +} + +static HRESULT WINAPI wave_persist_stream_Load(IPersistStream *iface, IStream *stream) +{ + struct wave *This = impl_from_IPersistStream(iface); + struct chunk_entry chunk = {0}; + HRESULT hr; + + TRACE("(%p, %p)\n", This, stream); + + if (!stream) return E_POINTER; + + if ((hr = stream_next_chunk(stream, &chunk)) == S_OK) + { + switch (MAKE_IDTYPE(chunk.id, chunk.type)) + { + case MAKE_IDTYPE(FOURCC_RIFF, mmioFOURCC('W','A','V','E')): + hr = parse_wave_chunk(This, stream, &chunk); + break; + + default: + WARN("Invalid wave chunk %s %s\n", debugstr_fourcc(chunk.id), debugstr_fourcc(chunk.type)); + hr = DMUS_E_UNSUPPORTED_STREAM; + break; + } + } + + stream_skip_chunk(stream, &chunk); + return hr; +} + +static const IPersistStreamVtbl wave_persist_stream_vtbl = +{ + dmobj_IPersistStream_QueryInterface, + dmobj_IPersistStream_AddRef, + dmobj_IPersistStream_Release, + dmobj_IPersistStream_GetClassID, + unimpl_IPersistStream_IsDirty, + wave_persist_stream_Load, + unimpl_IPersistStream_Save, + unimpl_IPersistStream_GetSizeMax, +}; + +static HRESULT wave_create(IUnknown **ret_iface) +{ + struct wave *obj; + + if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; + obj->IUnknown_iface.lpVtbl = &unknown_vtbl; + obj->ref = 1; + dmobject_init(&obj->dmobj, &CLSID_DirectSoundWave, &obj->IUnknown_iface); + obj->dmobj.IDirectMusicObject_iface.lpVtbl = &wave_object_vtbl; + obj->dmobj.IPersistStream_iface.lpVtbl = &wave_persist_stream_vtbl; + + *ret_iface = &obj->IUnknown_iface; + return S_OK; +} + HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnknown **ret_iface) { struct wave *This; From 6868d455291065f66d198616d8a5d85a3cc3a40c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 17 Oct 2023 13:08:38 +0200 Subject: [PATCH 2669/2777] dmusic: Use the IDirectMusicObject interface for waves. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55792 (cherry picked from commit 80e6310a884f59c1faeccc441aa808888ab0898b) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/wavetrack.c | 6 +++--- dlls/dmusic/collection.c | 8 ++++---- dlls/dmusic/dmusic_private.h | 2 +- dlls/dmusic/dmusic_wave.h | 11 ++++++----- dlls/dmusic/instrument.c | 4 ++-- dlls/dmusic/wave.c | 35 ++++++++++++++++++++--------------- 6 files changed, 36 insertions(+), 30 deletions(-) diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c index fcf57c1148d..5ba9fb675f5 100644 --- a/dlls/dmime/wavetrack.c +++ b/dlls/dmime/wavetrack.c @@ -24,7 +24,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmime); struct wave_item { struct list entry; DMUS_IO_WAVE_ITEM_HEADER header; - IUnknown *object; + IDirectMusicObject *object; IDirectSoundBuffer *buffer; }; @@ -106,7 +106,7 @@ static ULONG WINAPI wave_track_Release(IDirectMusicTrack8 *iface) { list_remove(&item->entry); if (item->buffer) IDirectSoundBuffer_Release(item->buffer); - if (item->object) IUnknown_Release(item->object); + if (item->object) IDirectMusicObject_Release(item->object); free(item); } @@ -469,7 +469,7 @@ static HRESULT parse_wave_item(struct wave_part *part, IStream *stream, struct c hr = DMUS_E_UNSUPPORTED_STREAM; goto error; } - if (FAILED(hr = dmobj_parsereference(stream, &chunk, (IDirectMusicObject **)&item->object))) + if (FAILED(hr = dmobj_parsereference(stream, &chunk, &item->object))) goto error; list_add_tail(&part->items, &item->entry); diff --git a/dlls/dmusic/collection.c b/dlls/dmusic/collection.c index bf21d3148e3..5cf129cfdd1 100644 --- a/dlls/dmusic/collection.c +++ b/dlls/dmusic/collection.c @@ -42,7 +42,7 @@ C_ASSERT(sizeof(struct pool) == offsetof(struct pool, cues[0])); struct wave_entry { struct list entry; - IUnknown *wave; + IDirectMusicObject *wave; DWORD offset; }; @@ -59,13 +59,13 @@ struct collection struct list waves; }; -extern void collection_internal_addref(struct collection *collection) +void collection_internal_addref(struct collection *collection) { ULONG ref = InterlockedIncrement( &collection->internal_ref ); TRACE( "collection %p, internal ref %lu.\n", collection, ref ); } -extern void collection_internal_release(struct collection *collection) +void collection_internal_release(struct collection *collection) { ULONG ref = InterlockedDecrement( &collection->internal_ref ); TRACE( "collection %p, internal ref %lu.\n", collection, ref ); @@ -74,7 +74,7 @@ extern void collection_internal_release(struct collection *collection) free(collection); } -extern HRESULT collection_get_wave(struct collection *collection, DWORD index, IUnknown **out) +HRESULT collection_get_wave(struct collection *collection, DWORD index, IDirectMusicObject **out) { struct wave_entry *wave_entry; DWORD offset; diff --git a/dlls/dmusic/dmusic_private.h b/dlls/dmusic/dmusic_private.h index 3efb69656c8..9ef9557407e 100644 --- a/dlls/dmusic/dmusic_private.h +++ b/dlls/dmusic/dmusic_private.h @@ -83,7 +83,7 @@ typedef struct port_info { struct collection; extern void collection_internal_addref(struct collection *collection); extern void collection_internal_release(struct collection *collection); -extern HRESULT collection_get_wave(struct collection *collection, DWORD index, IUnknown **out); +extern HRESULT collection_get_wave(struct collection *collection, DWORD index, IDirectMusicObject **out); /* CLSID */ extern HRESULT music_create(IUnknown **ret_iface); diff --git a/dlls/dmusic/dmusic_wave.h b/dlls/dmusic/dmusic_wave.h index 43396250261..f5ebaed2892 100644 --- a/dlls/dmusic/dmusic_wave.h +++ b/dlls/dmusic/dmusic_wave.h @@ -29,8 +29,9 @@ struct soundfont; struct chunk_entry; -extern HRESULT wave_create_from_soundfont(struct soundfont *soundfont, UINT index, IUnknown **out); -extern HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnknown **out); -extern HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, DWORD *id); -extern HRESULT wave_download_to_dsound(IUnknown *iface, IDirectSound *dsound, IDirectSoundBuffer **ret_iface); -extern HRESULT wave_get_duration(IUnknown *iface, REFERENCE_TIME *duration); +extern HRESULT wave_create_from_soundfont(struct soundfont *soundfont, UINT index, IDirectMusicObject **out); +extern HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IDirectMusicObject **out); +extern HRESULT wave_download_to_port(IDirectMusicObject *iface, IDirectMusicPortDownload *port, DWORD *id); +extern HRESULT wave_download_to_dsound(IDirectMusicObject *iface, IDirectSound *dsound, + IDirectSoundBuffer **ret_iface); +extern HRESULT wave_get_duration(IDirectMusicObject *iface, REFERENCE_TIME *duration); diff --git a/dlls/dmusic/instrument.c b/dlls/dmusic/instrument.c index 7a0f8a2f1eb..8311c690877 100644 --- a/dlls/dmusic/instrument.c +++ b/dlls/dmusic/instrument.c @@ -747,7 +747,7 @@ HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicP IDirectMusicDownload *download; DWORD size, offset_count; struct region *region; - IUnknown *wave; + IDirectMusicObject *wave; HRESULT hr; if (This->download) goto done; @@ -827,7 +827,7 @@ HRESULT instrument_download_to_port(IDirectMusicInstrument *iface, IDirectMusicP if (SUCCEEDED(hr = collection_get_wave(This->collection, region->wave_link.ulTableIndex, &wave))) { hr = wave_download_to_port(wave, port, &dmus_region->WaveLink.ulTableIndex); - IUnknown_Release(wave); + IDirectMusicObject_Release(wave); } if (FAILED(hr)) goto failed; diff --git a/dlls/dmusic/wave.c b/dlls/dmusic/wave.c index e5e7c4dc2a0..0db895f2038 100644 --- a/dlls/dmusic/wave.c +++ b/dlls/dmusic/wave.c @@ -170,6 +170,11 @@ static HRESULT parse_wave_chunk(struct wave *This, IStream *stream, struct chunk return hr; } +static inline struct wave *impl_from_IDirectMusicObject(IDirectMusicObject *iface) +{ + return CONTAINING_RECORD(iface, struct wave, dmobj.IDirectMusicObject_iface); +} + static HRESULT WINAPI wave_object_ParseDescriptor(IDirectMusicObject *iface, IStream *stream, DMUS_OBJECTDESC *desc) { @@ -259,7 +264,7 @@ static const IPersistStreamVtbl wave_persist_stream_vtbl = unimpl_IPersistStream_GetSizeMax, }; -static HRESULT wave_create(IUnknown **ret_iface) +static HRESULT wave_create(IDirectMusicObject **ret_iface) { struct wave *obj; @@ -270,24 +275,24 @@ static HRESULT wave_create(IUnknown **ret_iface) obj->dmobj.IDirectMusicObject_iface.lpVtbl = &wave_object_vtbl; obj->dmobj.IPersistStream_iface.lpVtbl = &wave_persist_stream_vtbl; - *ret_iface = &obj->IUnknown_iface; + *ret_iface = &obj->dmobj.IDirectMusicObject_iface; return S_OK; } -HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnknown **ret_iface) +HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IDirectMusicObject **ret_iface) { struct wave *This; - IUnknown *iface; + IDirectMusicObject *iface; HRESULT hr; TRACE("(%p, %p, %p)\n", stream, parent, ret_iface); if (FAILED(hr = wave_create(&iface))) return hr; - This = impl_from_IUnknown(iface); + This = impl_from_IDirectMusicObject(iface); if (FAILED(hr = parse_wave_chunk(This, stream, parent))) { - IUnknown_Release(iface); + IDirectMusicObject_Release(iface); return DMUS_E_UNSUPPORTED_STREAM; } @@ -324,7 +329,7 @@ HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IUnk return S_OK; } -HRESULT wave_create_from_soundfont(struct soundfont *soundfont, UINT index, IUnknown **ret_iface) +HRESULT wave_create_from_soundfont(struct soundfont *soundfont, UINT index, IDirectMusicObject **ret_iface) { struct sf_sample *sf_sample = soundfont->shdr + index; struct sample *sample = NULL; @@ -333,7 +338,7 @@ HRESULT wave_create_from_soundfont(struct soundfont *soundfont, UINT index, IUnk UINT data_size, offset; struct wave *This; void *data = NULL; - IUnknown *iface; + IDirectMusicObject *iface; TRACE("(%p, %u, %p)\n", soundfont, index, ret_iface); @@ -360,7 +365,7 @@ HRESULT wave_create_from_soundfont(struct soundfont *soundfont, UINT index, IUnk if (FAILED(hr = wave_create(&iface))) goto failed; - This = impl_from_IUnknown(iface); + This = impl_from_IDirectMusicObject(iface); This->format = format; This->sample = sample; This->data_size = data_size; @@ -403,7 +408,7 @@ HRESULT wave_create_from_soundfont(struct soundfont *soundfont, UINT index, IUnk return hr; } -HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, DWORD *id) +HRESULT wave_download_to_port(IDirectMusicObject *iface, IDirectMusicPortDownload *port, DWORD *id) { struct download_buffer { @@ -413,7 +418,7 @@ HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, D DMUS_WAVEDATA data; } *buffer; - struct wave *This = impl_from_IUnknown(iface); + struct wave *This = impl_from_IDirectMusicObject(iface); DWORD size = offsetof(struct download_buffer, data.byData[This->data_size]); IDirectMusicDownload *download; HRESULT hr; @@ -446,9 +451,9 @@ HRESULT wave_download_to_port(IUnknown *iface, IDirectMusicPortDownload *port, D return hr; } -HRESULT wave_download_to_dsound(IUnknown *iface, IDirectSound *dsound, IDirectSoundBuffer **ret_iface) +HRESULT wave_download_to_dsound(IDirectMusicObject *iface, IDirectSound *dsound, IDirectSoundBuffer **ret_iface) { - struct wave *This = impl_from_IUnknown(iface); + struct wave *This = impl_from_IDirectMusicObject(iface); DSBUFFERDESC desc = { .dwSize = sizeof(desc), @@ -485,9 +490,9 @@ HRESULT wave_download_to_dsound(IUnknown *iface, IDirectSound *dsound, IDirectSo return S_OK; } -HRESULT wave_get_duration(IUnknown *iface, REFERENCE_TIME *duration) +HRESULT wave_get_duration(IDirectMusicObject *iface, REFERENCE_TIME *duration) { - struct wave *This = impl_from_IUnknown(iface); + struct wave *This = impl_from_IDirectMusicObject(iface); *duration = (REFERENCE_TIME)This->data_size * 10000000 / This->format->nAvgBytesPerSec; return S_OK; } From 06ede00b99fa6ed525e0629e685e865387936e35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 17 Oct 2023 11:46:17 +0200 Subject: [PATCH 2670/2777] dswave: Use the dmusic wave object implementation. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55792 (cherry picked from commit 7c9e8b9c4e4e9e375b6bd6e14d5b98bfec61f8d0) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/dmusic_wave.h | 1 + dlls/dmusic/wave.c | 2 +- dlls/dswave/Makefile.in | 4 +- dlls/dswave/dswave.c | 191 ----------------------------------- dlls/dswave/dswave_main.c | 16 +-- dlls/dswave/dswave_private.h | 5 - 6 files changed, 14 insertions(+), 205 deletions(-) delete mode 100644 dlls/dswave/dswave.c diff --git a/dlls/dmusic/dmusic_wave.h b/dlls/dmusic/dmusic_wave.h index f5ebaed2892..bdad8ca9605 100644 --- a/dlls/dmusic/dmusic_wave.h +++ b/dlls/dmusic/dmusic_wave.h @@ -29,6 +29,7 @@ struct soundfont; struct chunk_entry; +extern HRESULT wave_create(IDirectMusicObject **ret_iface); extern HRESULT wave_create_from_soundfont(struct soundfont *soundfont, UINT index, IDirectMusicObject **out); extern HRESULT wave_create_from_chunk(IStream *stream, struct chunk_entry *parent, IDirectMusicObject **out); extern HRESULT wave_download_to_port(IDirectMusicObject *iface, IDirectMusicPortDownload *port, DWORD *id); diff --git a/dlls/dmusic/wave.c b/dlls/dmusic/wave.c index 0db895f2038..dd0b8a44779 100644 --- a/dlls/dmusic/wave.c +++ b/dlls/dmusic/wave.c @@ -264,7 +264,7 @@ static const IPersistStreamVtbl wave_persist_stream_vtbl = unimpl_IPersistStream_GetSizeMax, }; -static HRESULT wave_create(IDirectMusicObject **ret_iface) +HRESULT wave_create(IDirectMusicObject **ret_iface) { struct wave *obj; diff --git a/dlls/dswave/Makefile.in b/dlls/dswave/Makefile.in index 99b1e3ff9dc..8535e8fc27b 100644 --- a/dlls/dswave/Makefile.in +++ b/dlls/dswave/Makefile.in @@ -4,8 +4,8 @@ PARENTSRC = ../dmusic C_SRCS = \ dmobject.c \ - dswave.c \ - dswave_main.c + dswave_main.c \ + wave.c IDL_SRCS = dswave.idl diff --git a/dlls/dswave/dswave.c b/dlls/dswave/dswave.c deleted file mode 100644 index 5bdd83dfa2c..00000000000 --- a/dlls/dswave/dswave.c +++ /dev/null @@ -1,191 +0,0 @@ -/* IDirectMusicWave Implementation - * - * Copyright (C) 2003-2004 Rok Mandeljc - * - * This program 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 program 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 program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "dswave_private.h" -#include "dmobject.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dswave); - -/* an interface that is, according to my tests, obtained by loader after loading object; is it acting - as some sort of bridge between object and loader? */ -static const GUID IID_IDirectMusicWavePRIVATE = {0x69e934e4,0x97f1,0x4f1d,{0x88,0xe8,0xf2,0xac,0x88,0x67,0x13,0x27}}; - -/***************************************************************************** - * IDirectMusicWaveImpl implementation - */ -typedef struct IDirectMusicWaveImpl { - IUnknown IUnknown_iface; - struct dmobject dmobj; - LONG ref; -} IDirectMusicWaveImpl; - -/* IDirectMusicWaveImpl IUnknown part: */ -static inline IDirectMusicWaveImpl *impl_from_IUnknown(IUnknown *iface) -{ - return CONTAINING_RECORD(iface, IDirectMusicWaveImpl, IUnknown_iface); -} - -static HRESULT WINAPI IUnknownImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ret_iface) -{ - IDirectMusicWaveImpl *This = impl_from_IUnknown(iface); - - TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ret_iface); - - *ret_iface = NULL; - - if (IsEqualIID(riid, &IID_IUnknown)) - *ret_iface = iface; - else if (IsEqualIID(riid, &IID_IDirectMusicObject)) - *ret_iface = &This->dmobj.IDirectMusicObject_iface; - else if (IsEqualIID(riid, &IID_IPersistStream)) - *ret_iface = &This->dmobj.IPersistStream_iface; - else if (IsEqualIID(riid, &IID_IDirectMusicWavePRIVATE)) { - FIXME("(%p, %s, %p): Unsupported private interface\n", This, debugstr_guid(riid), ret_iface); - return E_NOINTERFACE; - } else { - WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ret_iface); - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown*)*ret_iface); - return S_OK; -} - -static ULONG WINAPI IUnknownImpl_AddRef(IUnknown *iface) -{ - IDirectMusicWaveImpl *This = impl_from_IUnknown(iface); - LONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p) ref=%ld\n", This, ref); - - return ref; -} - -static ULONG WINAPI IUnknownImpl_Release(IUnknown *iface) -{ - IDirectMusicWaveImpl *This = impl_from_IUnknown(iface); - LONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p) ref=%ld\n", This, ref); - - if (!ref) free(This); - - return ref; -} - -static const IUnknownVtbl unknown_vtbl = { - IUnknownImpl_QueryInterface, - IUnknownImpl_AddRef, - IUnknownImpl_Release -}; - -/* IDirectMusicWaveImpl IDirectMusicObject part: */ -static HRESULT WINAPI wave_IDirectMusicObject_ParseDescriptor(IDirectMusicObject *iface, - IStream *stream, DMUS_OBJECTDESC *desc) -{ - struct chunk_entry riff = {0}; - HRESULT hr; - - TRACE("(%p, %p, %p)\n", iface, stream, desc); - - if (!stream || !desc) - return E_POINTER; - - if ((hr = stream_get_chunk(stream, &riff)) != S_OK) - return hr; - if (riff.id != FOURCC_RIFF || riff.type != mmioFOURCC('W','A','V','E')) { - TRACE("loading failed: unexpected %s\n", debugstr_chunk(&riff)); - stream_skip_chunk(stream, &riff); - return DMUS_E_CHUNKNOTFOUND; - } - - hr = dmobj_parsedescriptor(stream, &riff, desc, - DMUS_OBJ_NAME_INFO | DMUS_OBJ_OBJECT | DMUS_OBJ_VERSION); - if (FAILED(hr)) - return hr; - - TRACE("returning descriptor:\n"); - dump_DMUS_OBJECTDESC(desc); - return S_OK; -} - -static const IDirectMusicObjectVtbl dmobject_vtbl = { - dmobj_IDirectMusicObject_QueryInterface, - dmobj_IDirectMusicObject_AddRef, - dmobj_IDirectMusicObject_Release, - dmobj_IDirectMusicObject_GetDescriptor, - dmobj_IDirectMusicObject_SetDescriptor, - wave_IDirectMusicObject_ParseDescriptor -}; - -/* IDirectMusicWaveImpl IPersistStream part: */ -static inline IDirectMusicWaveImpl *impl_from_IPersistStream(IPersistStream *iface) -{ - return CONTAINING_RECORD(iface, IDirectMusicWaveImpl, dmobj.IPersistStream_iface); -} - -static HRESULT WINAPI wave_IPersistStream_Load(IPersistStream *iface, IStream *stream) -{ - IDirectMusicWaveImpl *This = impl_from_IPersistStream(iface); - struct chunk_entry riff = {0}; - - /* Without the private interface the implementation should go to dmime/segment.c */ - FIXME("(%p, %p): loading not implemented (only descriptor is loaded)\n", This, stream); - - if (!stream) - return E_POINTER; - - if (stream_get_chunk(stream, &riff) != S_OK || riff.id != FOURCC_RIFF || - riff.type != mmioFOURCC('W','A','V','E')) - return DMUS_E_UNSUPPORTED_STREAM; - stream_reset_chunk_start(stream, &riff); - - return IDirectMusicObject_ParseDescriptor(&This->dmobj.IDirectMusicObject_iface, stream, - &This->dmobj.desc); -} - -static const IPersistStreamVtbl persiststream_vtbl = { - dmobj_IPersistStream_QueryInterface, - dmobj_IPersistStream_AddRef, - dmobj_IPersistStream_Release, - dmobj_IPersistStream_GetClassID, - unimpl_IPersistStream_IsDirty, - wave_IPersistStream_Load, - unimpl_IPersistStream_Save, - unimpl_IPersistStream_GetSizeMax -}; - -/* for ClassFactory */ -HRESULT create_dswave(REFIID lpcGUID, void **ppobj) -{ - IDirectMusicWaveImpl *obj; - HRESULT hr; - - *ppobj = NULL; - if (!(obj = calloc(1, sizeof(*obj)))) return E_OUTOFMEMORY; - obj->IUnknown_iface.lpVtbl = &unknown_vtbl; - obj->ref = 1; - dmobject_init(&obj->dmobj, &CLSID_DirectSoundWave, &obj->IUnknown_iface); - obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl; - obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; - - hr = IUnknown_QueryInterface(&obj->IUnknown_iface, lpcGUID, ppobj); - IUnknown_Release(&obj->IUnknown_iface); - return hr; -} diff --git a/dlls/dswave/dswave_main.c b/dlls/dswave/dswave_main.c index f2ce7bb950f..100d5cf8fc9 100644 --- a/dlls/dswave/dswave_main.c +++ b/dlls/dswave/dswave_main.c @@ -35,6 +35,7 @@ #include "dmusici.h" #include "dswave_private.h" +#include "dmusic_wave.h" #include "dmobject.h" WINE_DEFAULT_DEBUG_CHANNEL(dswave); @@ -79,14 +80,17 @@ static ULONG WINAPI WaveCF_Release(IClassFactory * iface) static HRESULT WINAPI WaveCF_CreateInstance(IClassFactory * iface, IUnknown *outer_unk, REFIID riid, void **ret_iface) { - TRACE ("(%p, %s, %p)\n", outer_unk, debugstr_dmguid(riid), ret_iface); + IDirectMusicObject *object; + HRESULT hr; - if (outer_unk) { - *ret_iface = NULL; - return CLASS_E_NOAGGREGATION; - } + TRACE("(%p, %s, %p)\n", outer_unk, debugstr_dmguid(riid), ret_iface); - return create_dswave(riid, ret_iface); + *ret_iface = NULL; + if (outer_unk) return CLASS_E_NOAGGREGATION; + if (FAILED(hr = wave_create(&object))) return hr; + hr = IDirectMusicObject_QueryInterface(object, riid, ret_iface); + IDirectMusicObject_Release(object); + return hr; } static HRESULT WINAPI WaveCF_LockServer(IClassFactory * iface, BOOL dolock) diff --git a/dlls/dswave/dswave_private.h b/dlls/dswave/dswave_private.h index 50406c676c1..080bb961e94 100644 --- a/dlls/dswave/dswave_private.h +++ b/dlls/dswave/dswave_private.h @@ -39,9 +39,4 @@ #include "dmusicf.h" #include "dmusics.h" -/***************************************************************************** - * ClassFactory - */ -extern HRESULT create_dswave(REFIID lpcGUID, void **ret_iface); - #endif /* __WINE_DSWAVE_PRIVATE_H */ From de4d3f50dafc63f99667ee92aa653622a5eaff00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 17 Oct 2023 12:41:40 +0200 Subject: [PATCH 2671/2777] dmime: Avoid releasing the newly created graph twice. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55790 (cherry picked from commit 231dd330cf281a5f33eba25d1d562368bb176229) CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/audiopath.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dlls/dmime/audiopath.c b/dlls/dmime/audiopath.c index 3310624eb00..65691f4705f 100644 --- a/dlls/dmime/audiopath.c +++ b/dlls/dmime/audiopath.c @@ -195,8 +195,6 @@ static HRESULT WINAPI IDirectMusicAudioPathImpl_GetObjectInPath (IDirectMusicAud if (FAILED(hr)) return hr; IDirectMusicPerformance8_SetGraph(This->pPerf, pGraph); - /* we need release as SetGraph do an AddRef */ - IDirectMusicGraph_Release(pGraph); pPerfoGraph = pGraph; } *ppObject = pPerfoGraph; From b0d870066b6d2d5138254d1060f8f3505a4ec628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 23 Oct 2023 22:49:46 +0200 Subject: [PATCH 2672/2777] dmime/tests: Remove flaky track playing state test. This fails regularly on Win7. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 6dc9d8e0f5e..151dbead3c1 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3971,11 +3971,6 @@ static void test_segment_state(void) ok(hr == S_OK, "got %#lx\n", hr); - /* This might be timing dependent and if PlaySegment is already - * late, the tracks are played synchronously and right away. - */ - todo_wine check_track_state(track, playing, FALSE); - ret = test_track_wait_playing(track, 50); ok(ret == 0, "got %#lx\n", ret); From db6384f117f0dc7c23ee0b12dd3b56fcbaca840c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 25 Oct 2023 14:19:31 +0200 Subject: [PATCH 2673/2777] dmime/tests: Avoid checking message segment state reference count. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 151dbead3c1..7ed6568ecd4 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -38,8 +38,8 @@ static ULONG get_refcount(void *iface) return IUnknown_Release(unknown); } -#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c) -static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported) +#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c, FALSE) +static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported, BOOL check_refs) { ULONG expect_ref = get_refcount(iface_ptr); IUnknown *iface = iface_ptr; @@ -52,10 +52,10 @@ static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOO if (SUCCEEDED(hr)) { LONG ref = get_refcount(unk); - ok_(__FILE__, line)(ref == expect_ref + 1, "got %ld\n", ref); + if (check_refs) ok_(__FILE__, line)(ref == expect_ref + 1, "got %ld\n", ref); IUnknown_Release(unk); ref = get_refcount(iface_ptr); - ok_(__FILE__, line)(ref == expect_ref, "got %ld\n", ref); + if (check_refs) ok_(__FILE__, line)(ref == expect_ref, "got %ld\n", ref); } } @@ -3024,8 +3024,8 @@ static void check_dmus_notification_pmsg_(int line, DMUS_NOTIFICATION_PMSG *msg, ok_(__FILE__, line)(!msg->punkUser, "got punkUser %p\n", msg->punkUser); else { - check_interface_(line, msg->punkUser, &IID_IDirectMusicSegmentState, TRUE); - check_interface_(line, msg->punkUser, &IID_IDirectMusicSegmentState8, TRUE); + check_interface_(line, msg->punkUser, &IID_IDirectMusicSegmentState, TRUE, FALSE); + check_interface_(line, msg->punkUser, &IID_IDirectMusicSegmentState8, TRUE, FALSE); } } From ee83a689c142f86ed9c0938f8c0c8dfa718b89f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 23 Oct 2023 22:53:41 +0200 Subject: [PATCH 2674/2777] dmime/tests: Ignore failure on missing gm.dls in test_band_track_play. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55722 CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 7ed6568ecd4..85ea8fcfeff 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3722,7 +3722,10 @@ static void test_band_track_play(void) &IID_IDirectMusicLoader8, (void **)&loader); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicLoader_SetObject(loader, &desc); - ok(hr == S_OK, "got %#lx\n", hr); + if (hr == DMUS_E_LOADER_FAILEDOPEN) + skip("Failed to open gm.dls, missing system SoundFont?\n"); + else + ok(hr == S_OK, "got %#lx\n", hr); hr = test_loader_stream_create(stream, loader, &loader_stream); ok(hr == S_OK, "got %#lx\n", hr); From 0efdd51681600962223780d946f3eab28d3f78a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 23 Oct 2023 22:57:25 +0200 Subject: [PATCH 2675/2777] dmusic/tests: Skip test_default_gm_collection if gm.dls is missing. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55688 CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/tests/dmusic.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/dmusic/tests/dmusic.c b/dlls/dmusic/tests/dmusic.c index 51a6b0d8774..f71c0600366 100644 --- a/dlls/dmusic/tests/dmusic.c +++ b/dlls/dmusic/tests/dmusic.c @@ -1608,6 +1608,11 @@ static void test_default_gm_collection(void) ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicLoader_GetObject(loader, &desc, &IID_IDirectMusicCollection, (void **)&collection); + if (hr == DMUS_E_LOADER_NOFILENAME) + { + skip("Failed to open default GM collection, skipping tests. Missing system SoundFont?\n"); + goto skip_tests; + } ok(hr == S_OK, "got %#lx\n", hr); for (i = 0; hr == S_OK && i < ARRAY_SIZE(results); i++) @@ -1635,6 +1640,8 @@ static void test_default_gm_collection(void) } IDirectMusicCollection_Release(collection); + +skip_tests: IDirectMusicLoader_Release(loader); } From b15482692c014814224b44102cd6b212bc977ea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 22 Oct 2023 16:21:41 +0200 Subject: [PATCH 2676/2777] dmsynth: Set loop and sample generators on the fluid_voice. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index c3e0c90880e..379d80f7346 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -49,6 +49,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmsynth); #define CONN_TRANSFORM(src, ctrl, dst) (((src) & 0x3f) << 10) | (((ctrl) & 0x3f) << 4) | ((dst) & 0xf) +/* from src/rvoice/fluid_rvoice.h */ +#define FLUID_LOOP_DURING_RELEASE 1 +#define FLUID_LOOP_UNTIL_RELEASE 3 + static const char *debugstr_conn_src(UINT src) { switch (src) @@ -1750,11 +1754,6 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui fluid_sample_set_sound_data(fluid_sample, wave->samples, NULL, wave->sample_count, wave->format.nSamplesPerSec, TRUE); - if (region->wave_sample.cSampleLoops) - { - WLOOP *loop = region->wave_loops; - fluid_sample_set_loop(fluid_sample, loop->ulStart, loop->ulStart + loop->ulLength); - } fluid_sample_set_pitch(fluid_sample, region->wave_sample.usUnityNote, region->wave_sample.sFineTune); if (!(fluid_voice = fluid_synth_alloc_voice(synth->fluid_synth, fluid_sample, chan, key, vel))) @@ -1765,6 +1764,20 @@ static int synth_preset_noteon(fluid_preset_t *fluid_preset, fluid_synth_t *flui } set_default_voice_connections(fluid_voice); + if (region->wave_sample.cSampleLoops) + { + WLOOP *loop = region->wave_loops; + + if (loop->ulType == WLOOP_TYPE_FORWARD) + fluid_voice_gen_set(fluid_voice, GEN_SAMPLEMODE, FLUID_LOOP_DURING_RELEASE); + else if (loop->ulType == WLOOP_TYPE_RELEASE) + fluid_voice_gen_set(fluid_voice, GEN_SAMPLEMODE, FLUID_LOOP_UNTIL_RELEASE); + else + FIXME("Unsupported loop type %lu\n", loop->ulType); + + fluid_voice_gen_set(fluid_voice, GEN_STARTLOOPADDROFS, loop->ulStart); + fluid_voice_gen_set(fluid_voice, GEN_ENDLOOPADDROFS, loop->ulStart + loop->ulLength); + } LIST_FOR_EACH_ENTRY(articulation, &instrument->articulations, struct articulation, entry) add_voice_connections(fluid_voice, &articulation->list, articulation->connections); LIST_FOR_EACH_ENTRY(articulation, ®ion->articulations, struct articulation, entry) From 4490f3c8138e665136987b9e2d6ffa81b9819c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Sun, 22 Oct 2023 15:51:05 +0200 Subject: [PATCH 2677/2777] dmime: Force recompute MIDI message reference time. Fixes 65e388137c6117aaf8f99cef808d32afa29c7639, which is otherwise no-op without this change. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index a2e611523a6..e0da0516c79 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1706,7 +1706,7 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, DMUS_NOTE_PMSG *note = (DMUS_NOTE_PMSG *)msg; msg->mtTime += note->nOffset; - if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_REFTIME | DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, + if (FAILED(hr = performance_send_midi_pmsg(This, msg, DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, MIDI_NOTE_ON, note->bMidiValue, note->bVelocity))) WARN("Failed to translate message to MIDI, hr %#lx\n", hr); From c1b5cad81b6d760ed246b160e2b0a20a85c80a20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Oct 2023 14:25:07 +0200 Subject: [PATCH 2678/2777] dmime: Pass IDirectMusicPerformance8 to segment state functions. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/dmime_private.h | 6 +++--- dlls/dmime/performance.c | 7 ++++--- dlls/dmime/segmentstate.c | 12 ++++++------ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 7f1937eaa0f..860b4ef385c 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -73,9 +73,9 @@ extern void set_audiopath_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffe extern void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*); extern HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, - IDirectMusicPerformance *performance, IDirectMusicSegmentState **ret_iface); -extern HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance *performance); -extern HRESULT segment_state_end_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance *performance); + IDirectMusicPerformance8 *performance, IDirectMusicSegmentState **ret_iface); +extern HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); +extern HRESULT segment_state_end_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); extern HRESULT wave_track_create_from_chunk(IStream *stream, struct chunk_entry *parent, IDirectMusicTrack8 **ret_iface); diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index e0da0516c79..8459de00b3f 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1196,7 +1196,7 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, if (FAILED(hr = IUnknown_QueryInterface(source, &IID_IDirectMusicSegment, (void **)&segment))) return hr; - if (FAILED(hr = segment_state_create(segment, start_time, (IDirectMusicPerformance *)iface, &state))) + if (FAILED(hr = segment_state_create(segment, start_time, iface, &state))) { IDirectMusicSegment_Release(segment); return hr; @@ -1213,7 +1213,7 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, hr = performance_send_dirty_pmsg(This, start_time); if (SUCCEEDED(hr)) - hr = segment_state_play(state, (IDirectMusicPerformance *)iface); + hr = segment_state_play(state, iface); if (SUCCEEDED(hr)) hr = performance_send_notification_pmsg(This, start_time + length, This->notification_segment, @@ -1767,7 +1767,8 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, if (IsEqualGUID(¬if->guidNotificationType, &GUID_NOTIFICATION_SEGMENT) && notif->dwNotificationOption == DMUS_NOTIFICATION_SEGEND) { - if (FAILED(hr = segment_state_end_play((IDirectMusicSegmentState *)notif->punkUser, performance))) + if (FAILED(hr = segment_state_end_play((IDirectMusicSegmentState *)notif->punkUser, + (IDirectMusicPerformance8 *)performance))) WARN("Failed to end segment state %p, hr %#lx\n", notif->punkUser, hr); } diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index c43d833fedd..89534f7342d 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -209,7 +209,7 @@ HRESULT create_dmsegmentstate(REFIID riid, void **ret_iface) } HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, - IDirectMusicPerformance *performance, IDirectMusicSegmentState **ret_iface) + IDirectMusicPerformance8 *performance, IDirectMusicSegmentState **ret_iface) { IDirectMusicSegmentState *iface; struct segment_state *This; @@ -225,7 +225,7 @@ HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time This->segment = segment; IDirectMusicSegment_AddRef(This->segment); - if (SUCCEEDED(hr = IDirectMusicPerformance_GetGlobalParam(performance, &GUID_PerfAutoDownload, + if (SUCCEEDED(hr = IDirectMusicPerformance8_GetGlobalParam(performance, &GUID_PerfAutoDownload, &This->auto_download, sizeof(This->auto_download))) && This->auto_download) hr = IDirectMusicSegment_SetParam(segment, &GUID_DownloadToAudioPath, -1, DMUS_SEG_ALLTRACKS, 0, performance); @@ -247,7 +247,7 @@ HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time if (!(entry = malloc(sizeof(*entry)))) hr = E_OUTOFMEMORY; - else if (SUCCEEDED(hr = IDirectMusicTrack_InitPlay(track, iface, performance, + else if (SUCCEEDED(hr = IDirectMusicTrack_InitPlay(track, iface, (IDirectMusicPerformance *)performance, &entry->state_data, track_id, 0))) { entry->track = track; @@ -268,7 +268,7 @@ HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time return hr; } -HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance *performance) +HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance) { struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); DWORD track_flags = DMUS_TRACKF_DIRTY | DMUS_TRACKF_START | DMUS_TRACKF_SEEK; @@ -279,7 +279,7 @@ HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerforma LIST_FOR_EACH_ENTRY(entry, &This->tracks, struct track_entry, entry) { if (FAILED(hr = IDirectMusicTrack_Play(entry->track, entry->state_data, start_time, - end_time, 0, track_flags, performance, iface, entry->track_id))) + end_time, 0, track_flags, (IDirectMusicPerformance *)performance, iface, entry->track_id))) { WARN("Failed to play track %p, hr %#lx\n", entry->track, hr); break; @@ -289,7 +289,7 @@ HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerforma return hr; } -HRESULT segment_state_end_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance *performance) +HRESULT segment_state_end_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance) { struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); struct track_entry *entry, *next; From 73bc9f6150dda86c03ec645dc71db1a37e58c1b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Oct 2023 14:05:52 +0200 Subject: [PATCH 2679/2777] dmime: Pass segment start time as track time offset. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segmentstate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index 89534f7342d..b4bb784de0d 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -278,8 +278,8 @@ HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerforma LIST_FOR_EACH_ENTRY(entry, &This->tracks, struct track_entry, entry) { - if (FAILED(hr = IDirectMusicTrack_Play(entry->track, entry->state_data, start_time, - end_time, 0, track_flags, (IDirectMusicPerformance *)performance, iface, entry->track_id))) + if (FAILED(hr = IDirectMusicTrack_Play(entry->track, entry->state_data, start_time, end_time, + This->start_time, track_flags, (IDirectMusicPerformance *)performance, iface, entry->track_id))) { WARN("Failed to play track %p, hr %#lx\n", entry->track, hr); break; From 6b3cfa9968a2bdb70a0162d228b1119b673daa71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 23 Oct 2023 11:55:24 +0200 Subject: [PATCH 2680/2777] dmband: Use time_offset to align track start with music time. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/bandtrack.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index 5229204b284..0c6aa81dd5f 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -174,7 +174,6 @@ static HRESULT WINAPI band_track_Play(IDirectMusicTrack8 *iface, void *state_dat if (start_time != 0) FIXME("start_time %ld not implemented\n", start_time); if (end_time != -1) FIXME("end_time %ld not implemented\n", end_time); - if (time_offset != 0) FIXME("time_offset %ld not implemented\n", time_offset); if (segment_flags) FIXME("segment_flags %#lx not implemented\n", segment_flags); if (segment_state) FIXME("segment_state %p not implemented\n", segment_state); @@ -184,8 +183,9 @@ static HRESULT WINAPI band_track_Play(IDirectMusicTrack8 *iface, void *state_dat LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry) { - if (FAILED(hr = band_send_messages(entry->band, performance, graph, - entry->head.lBandTimeLogical, track_id))) + MUSIC_TIME music_time = entry->head.lBandTimeLogical; + if (music_time != -1) music_time += time_offset; + if (FAILED(hr = band_send_messages(entry->band, performance, graph, music_time, track_id))) break; } From 2428539f6d3d0e178a549c930028b010dc9ddff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 23 Oct 2023 11:55:24 +0200 Subject: [PATCH 2681/2777] dmime: Use time_offset to align track start with music time. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/seqtrack.c | 5 ++--- dlls/dmime/wavetrack.c | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/dlls/dmime/seqtrack.c b/dlls/dmime/seqtrack.c index a6043cb4a89..997bff241d8 100644 --- a/dlls/dmime/seqtrack.c +++ b/dlls/dmime/seqtrack.c @@ -122,7 +122,6 @@ static HRESULT WINAPI sequence_track_Play(IDirectMusicTrack8 *iface, void *state if (start_time != 0) FIXME("start_time %ld not implemented\n", start_time); if (end_time != -1) FIXME("end_time %ld not implemented\n", end_time); - if (time_offset != 0) FIXME("time_offset %ld not implemented\n", time_offset); if (segment_flags) FIXME("segment_flags %#lx not implemented\n", segment_flags); if (segment_state) FIXME("segment_state %p not implemented\n", segment_state); @@ -139,7 +138,7 @@ static HRESULT WINAPI sequence_track_Play(IDirectMusicTrack8 *iface, void *state (DMUS_PMSG **)&msg))) break; - msg->mtTime = item->mtTime; + msg->mtTime = item->mtTime + time_offset; msg->dwFlags = DMUS_PMSGF_MUSICTIME; msg->dwPChannel = item->dwPChannel; msg->dwVirtualTrackID = track_id; @@ -169,7 +168,7 @@ static HRESULT WINAPI sequence_track_Play(IDirectMusicTrack8 *iface, void *state (DMUS_PMSG **)&msg))) break; - msg->mtTime = item->mtStart; + msg->mtTime = item->mtStart + time_offset; msg->dwFlags = DMUS_PMSGF_MUSICTIME; msg->dwPChannel = item->dwPChannel; msg->dwVirtualTrackID = track_id; diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c index 5ba9fb675f5..974e656cfe5 100644 --- a/dlls/dmime/wavetrack.c +++ b/dlls/dmime/wavetrack.c @@ -159,7 +159,6 @@ static HRESULT WINAPI wave_track_Play(IDirectMusicTrack8 *iface, void *state_dat if (start_time != 0) FIXME("start_time %ld not implemented\n", start_time); if (end_time != -1) FIXME("end_time %ld not implemented\n", end_time); - if (time_offset != 0) FIXME("time_offset %ld not implemented\n", time_offset); if (segment_flags) FIXME("segment_flags %#lx not implemented\n", segment_flags); if (segment_state) FIXME("segment_state %p not implemented\n", segment_state); @@ -181,7 +180,7 @@ static HRESULT WINAPI wave_track_Play(IDirectMusicTrack8 *iface, void *state_dat (DMUS_PMSG **)&msg))) break; - msg->mtTime = item->header.rtTime; + msg->mtTime = item->header.rtTime + time_offset; msg->dwFlags = DMUS_PMSGF_MUSICTIME; msg->dwPChannel = part->header.dwPChannel; msg->dwVirtualTrackID = track_id; From d30a56289e9564822d7fd3d3e2663e649cd44504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 25 Oct 2023 09:34:12 +0200 Subject: [PATCH 2682/2777] dmime: Use an internal performance message for segment end. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/dmime_private.h | 2 ++ dlls/dmime/performance.c | 50 ++++++++++++++++++++++++++------------ dlls/dmime/segmentstate.c | 5 +++- 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 860b4ef385c..28836694ed9 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -81,6 +81,8 @@ extern HRESULT wave_track_create_from_chunk(IStream *stream, struct chunk_entry IDirectMusicTrack8 **ret_iface); extern HRESULT performance_get_dsound(IDirectMusicPerformance8 *iface, IDirectSound **dsound); +extern HRESULT performance_send_segment_end(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, + IDirectMusicSegmentState *state); /***************************************************************************** * Auxiliary definitions diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 8459de00b3f..942452d353e 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -24,6 +24,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmime); +enum dmus_internal_message_type +{ + DMUS_PMSGT_INTERNAL_FIRST = 0x10, + DMUS_PMSGT_INTERNAL_SEGMENT_END = DMUS_PMSGT_INTERNAL_FIRST, +}; + struct pchannel_block { DWORD block_num; /* Block 0 is PChannels 0-15, Block 1 is PChannels 16-31, etc */ struct { @@ -158,7 +164,8 @@ static DWORD WINAPI message_thread_proc(void *args) return 0; } -static HRESULT performance_send_dirty_pmsg(struct performance *This, MUSIC_TIME music_time) +static HRESULT performance_send_pmsg(struct performance *This, MUSIC_TIME music_time, DWORD flags, + DWORD type, IUnknown *object) { IDirectMusicPerformance8 *performance = &This->IDirectMusicPerformance8_iface; IDirectMusicGraph *graph = &This->IDirectMusicGraph_iface; @@ -169,10 +176,11 @@ static HRESULT performance_send_dirty_pmsg(struct performance *This, MUSIC_TIME return hr; msg->mtTime = music_time; - msg->dwFlags = DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_QUEUE; - msg->dwType = DMUS_PMSGT_DIRTY; + msg->dwFlags = DMUS_PMSGF_MUSICTIME | flags; + msg->dwType = type; + if ((msg->punkUser = object)) IUnknown_AddRef(object); - if (FAILED(hr = IDirectMusicGraph_StampPMsg(graph, msg)) + if ((type < DMUS_PMSGT_INTERNAL_FIRST && FAILED(hr = IDirectMusicGraph_StampPMsg(graph, msg))) || FAILED(hr = IDirectMusicPerformance8_SendPMsg(performance, msg))) IDirectMusicPerformance8_FreePMsg(performance, msg); @@ -252,6 +260,19 @@ static inline struct performance *impl_from_IDirectMusicPerformance8(IDirectMusi return CONTAINING_RECORD(iface, struct performance, IDirectMusicPerformance8_iface); } +HRESULT performance_send_segment_end(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, + IDirectMusicSegmentState *state) +{ + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + HRESULT hr; + + if (FAILED(hr = performance_send_pmsg(This, music_time, DMUS_PMSGF_TOOL_ATTIME, + DMUS_PMSGT_INTERNAL_SEGMENT_END, (IUnknown *)state))) + return hr; + + return S_OK; +} + /* IDirectMusicPerformance8 IUnknown part: */ static HRESULT WINAPI performance_QueryInterface(IDirectMusicPerformance8 *iface, REFIID riid, void **ret_iface) { @@ -1050,8 +1071,7 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) list_remove(&message->entry); list_init(&message->entry); - /* process notifications to end any pending segment states */ - if (message->msg.dwType == DMUS_PMSGT_NOTIFICATION) + if (message->msg.dwType == DMUS_PMSGT_INTERNAL_SEGMENT_END) hr = IDirectMusicTool_ProcessPMsg(&This->IDirectMusicTool_iface, (IDirectMusicPerformance *)iface, &message->msg); else @@ -1210,7 +1230,7 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, hr = performance_send_notification_pmsg(This, start_time, This->notification_segment, GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART, (IUnknown *)state); if (SUCCEEDED(hr)) - hr = performance_send_dirty_pmsg(This, start_time); + hr = performance_send_pmsg(This, start_time, DMUS_PMSGF_TOOL_QUEUE, DMUS_PMSGT_DIRTY, NULL); if (SUCCEEDED(hr)) hr = segment_state_play(state, iface); @@ -1222,7 +1242,7 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, hr = performance_send_notification_pmsg(This, start_time + length, This->notification_segment, GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND, (IUnknown *)state); if (SUCCEEDED(hr)) - hr = performance_send_dirty_pmsg(This, start_time + length); + hr = performance_send_pmsg(This, start_time + length, DMUS_PMSGF_TOOL_QUEUE, DMUS_PMSGT_DIRTY, NULL); if (SUCCEEDED(hr)) hr = performance_send_notification_pmsg(This, start_time + length, This->notification_performance, GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTOPPED, NULL); @@ -1764,14 +1784,6 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, struct message *previous; BOOL enabled = FALSE; - if (IsEqualGUID(¬if->guidNotificationType, &GUID_NOTIFICATION_SEGMENT) - && notif->dwNotificationOption == DMUS_NOTIFICATION_SEGEND) - { - if (FAILED(hr = segment_state_end_play((IDirectMusicSegmentState *)notif->punkUser, - (IDirectMusicPerformance8 *)performance))) - WARN("Failed to end segment state %p, hr %#lx\n", notif->punkUser, hr); - } - if (IsEqualGUID(¬if->guidNotificationType, &GUID_NOTIFICATION_PERFORMANCE)) enabled = This->notification_performance; if (IsEqualGUID(¬if->guidNotificationType, &GUID_NOTIFICATION_SEGMENT)) @@ -1799,6 +1811,12 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, WARN("Failed to play wave buffer, hr %#lx\n", hr); break; + case DMUS_PMSGT_INTERNAL_SEGMENT_END: + if (FAILED(hr = segment_state_end_play((IDirectMusicSegmentState *)msg->punkUser, + (IDirectMusicPerformance8 *)performance))) + WARN("Failed to end segment state %p, hr %#lx\n", msg->punkUser, hr); + break; + default: FIXME("Unhandled message type %#lx\n", msg->dwType); break; diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index b4bb784de0d..21b98ccc14c 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -214,8 +214,8 @@ HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time IDirectMusicSegmentState *iface; struct segment_state *This; IDirectMusicTrack *track; + UINT i, duration; HRESULT hr; - UINT i; TRACE("(%p, %lu, %p)\n", segment, start_time, ret_iface); @@ -263,6 +263,9 @@ HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time } } + duration = This->end_point - This->start_point; + if (SUCCEEDED(hr)) hr = performance_send_segment_end(performance, start_time + duration, iface); + if (SUCCEEDED(hr)) *ret_iface = iface; else IDirectMusicSegmentState_Release(iface); return hr; From 1503baebe142ebd5c7c6b81afc94a36e9875bdad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 25 Oct 2023 10:13:17 +0200 Subject: [PATCH 2683/2777] dmime: Send notification messages with DMUS_PMSGF_TOOL_IMMEDIATE. Then send them again with DMUS_PMSGF_TOOL_ATTIME for the notification queue. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 942452d353e..b58a7d9cd18 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -199,7 +199,7 @@ static HRESULT performance_send_notification_pmsg(struct performance *This, MUSI return hr; msg->mtTime = music_time; - msg->dwFlags = DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_QUEUE; + msg->dwFlags = DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE; msg->dwType = DMUS_PMSGT_NOTIFICATION; if ((msg->punkUser = object)) IUnknown_AddRef(object); msg->guidNotificationType = type; @@ -1230,7 +1230,7 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, hr = performance_send_notification_pmsg(This, start_time, This->notification_segment, GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART, (IUnknown *)state); if (SUCCEEDED(hr)) - hr = performance_send_pmsg(This, start_time, DMUS_PMSGF_TOOL_QUEUE, DMUS_PMSGT_DIRTY, NULL); + hr = performance_send_pmsg(This, start_time, DMUS_PMSGF_TOOL_IMMEDIATE, DMUS_PMSGT_DIRTY, NULL); if (SUCCEEDED(hr)) hr = segment_state_play(state, iface); @@ -1242,7 +1242,7 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, hr = performance_send_notification_pmsg(This, start_time + length, This->notification_segment, GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND, (IUnknown *)state); if (SUCCEEDED(hr)) - hr = performance_send_pmsg(This, start_time + length, DMUS_PMSGF_TOOL_QUEUE, DMUS_PMSGT_DIRTY, NULL); + hr = performance_send_pmsg(This, start_time + length, DMUS_PMSGF_TOOL_IMMEDIATE, DMUS_PMSGT_DIRTY, NULL); if (SUCCEEDED(hr)) hr = performance_send_notification_pmsg(This, start_time + length, This->notification_performance, GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTOPPED, NULL); @@ -1790,6 +1790,21 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, enabled = This->notification_segment; if (!enabled) return DMUS_S_FREE; + if (msg->dwFlags & DMUS_PMSGF_TOOL_IMMEDIATE) + { + /* re-send the message for queueing at the expected time */ + msg->dwFlags &= ~DMUS_PMSGF_TOOL_IMMEDIATE; + msg->dwFlags |= DMUS_PMSGF_TOOL_ATTIME; + + if (FAILED(hr = IDirectMusicPerformance8_SendPMsg(performance, (DMUS_PMSG *)msg))) + { + ERR("Failed to send notification message, hr %#lx\n", hr); + return DMUS_S_FREE; + } + + return S_OK; + } + list_add_tail(&This->notifications, &message->entry); /* discard old notification messages */ From 8c04f165fbbb4c4f336b2c285fb152382ea8056e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Oct 2023 10:09:23 +0200 Subject: [PATCH 2684/2777] dmime/tests: Add a track and longer segment to notifications tests. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 105 +++++++++++++++++++++++++++++---------- 1 file changed, 78 insertions(+), 27 deletions(-) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 85ea8fcfeff..35a6fbc98f4 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -566,6 +566,7 @@ struct test_track BOOL initialized; BOOL downloaded; BOOL playing; + BOOL test_play; HANDLE playing_event; }; @@ -659,6 +660,8 @@ static HRESULT WINAPI test_track_Play(IDirectMusicTrack *iface, void *state_data { struct test_track *This = impl_from_IDirectMusicTrack(iface); + if (!This->test_play) return S_OK; + ok(state_data == &This->data, "got %p\n", state_data); ok(start_time == 50, "got %lu\n", start_time); ok(end_time == 100, "got %lu\n", end_time); @@ -718,15 +721,15 @@ static HRESULT WINAPI test_track_IsParamSupported(IDirectMusicTrack *iface, REFG static HRESULT WINAPI test_track_AddNotificationType(IDirectMusicTrack *iface, REFGUID type) { - struct test_track *This = impl_from_IDirectMusicTrack(iface); - ok(0, "unexpected %s %p\n", __func__, This); + ok(IsEqualGUID(type, &GUID_NOTIFICATION_SEGMENT) || IsEqualGUID(type, &GUID_NOTIFICATION_PERFORMANCE), + "got %s\n", debugstr_guid(type)); return E_NOTIMPL; } static HRESULT WINAPI test_track_RemoveNotificationType(IDirectMusicTrack *iface, REFGUID type) { - struct test_track *This = impl_from_IDirectMusicTrack(iface); - ok(0, "unexpected %s %p\n", __func__, This); + ok(IsEqualGUID(type, &GUID_NOTIFICATION_SEGMENT) || IsEqualGUID(type, &GUID_NOTIFICATION_PERFORMANCE), + "got %s\n", debugstr_guid(type)); return E_NOTIMPL; } @@ -755,7 +758,7 @@ static const IDirectMusicTrackVtbl test_track_vtbl = test_track_Clone, }; -static HRESULT test_track_create(IDirectMusicTrack **ret_iface) +static HRESULT test_track_create(IDirectMusicTrack **ret_iface, BOOL test_play) { struct test_track *track; @@ -763,6 +766,7 @@ static HRESULT test_track_create(IDirectMusicTrack **ret_iface) if (!(track = calloc(1, sizeof(*track)))) return E_OUTOFMEMORY; track->IDirectMusicTrack_iface.lpVtbl = &test_track_vtbl; track->ref = 1; + track->test_play = test_play; track->playing_event = CreateEventW(NULL, FALSE, FALSE, NULL); ok(!!track->playing_event, "CreateEventW failed, error %lu\n", GetLastError()); @@ -3015,6 +3019,8 @@ static void check_dmus_notification_pmsg_(int line, DMUS_NOTIFICATION_PMSG *msg, "got dwType %#lx\n", msg->dwType); ok_(__FILE__, line)(IsEqualGUID(&msg->guidNotificationType, type), "got guidNotificationType %s\n", debugstr_guid(&msg->guidNotificationType)); + todo_wine_if(IsEqualGUID(type, &GUID_NOTIFICATION_SEGMENT) && + (option == DMUS_NOTIFICATION_SEGALMOSTEND || option == DMUS_NOTIFICATION_SEGEND)) ok_(__FILE__, line)(msg->dwNotificationOption == option, "got dwNotificationOption %#lx\n", msg->dwNotificationOption); ok_(__FILE__, line)(!msg->dwField1, "got dwField1 %lu\n", msg->dwField1); @@ -3038,8 +3044,11 @@ static void test_notification_pmsg(void) DMUS_PMSGT_WAVE, }; IDirectMusicPerformance *performance; + IDirectMusicSegmentState *state; DMUS_NOTIFICATION_PMSG *notif; + MUSIC_TIME music_time, length; IDirectMusicSegment *segment; + IDirectMusicTrack *track; IDirectMusicGraph *graph; IDirectMusicTool *tool; DMUS_PMSG *msg; @@ -3070,6 +3079,21 @@ static void test_notification_pmsg(void) &IID_IDirectMusicSegment, (void **)&segment); ok(hr == S_OK, "got %#lx\n", hr); + + /* native needs a track or the segment will end immediately */ + + hr = test_track_create(&track, FALSE); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSegment_InsertTrack(segment, track, 1); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicTrack_Release(track); + + /* native sends dirty / notification by batch of 1s, shorter length + * will cause all messages to be received immediately */ + length = 10005870 / 6510; + hr = IDirectMusicSegment_SetLength(segment, length); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicSegment8_Download((IDirectMusicSegment8 *)segment, (IUnknown *)performance); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicSegment8_Unload((IDirectMusicSegment8 *)segment, (IUnknown *)performance); @@ -3077,14 +3101,18 @@ static void test_notification_pmsg(void) hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, NULL); ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_GetTime(performance, NULL, &music_time); + ok(hr == S_OK, "got %#lx\n", hr); - ret = test_tool_wait_message(tool, 500, &msg); + ret = test_tool_wait_message(tool, 50, &msg); ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); - ret = test_tool_wait_message(tool, 500, &msg); + ret = test_tool_wait_message(tool, 50, &msg); + todo_wine ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); + if (ret == WAIT_TIMEOUT) ret = test_tool_wait_message(tool, 500, &msg); ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); hr = IDirectMusicPerformance_FreePMsg(performance, msg); @@ -3104,22 +3132,24 @@ static void test_notification_pmsg(void) hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); ok(hr == S_FALSE, "got %#lx\n", hr); - hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, NULL); + hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, &state); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_GetTime(performance, NULL, &music_time); ok(hr == S_OK, "got %#lx\n", hr); - ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); + ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if); ok(!ret, "got %#lx\n", ret); check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTARTED); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); + ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if); ok(!ret, "got %#lx\n", ret); check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - ret = test_tool_wait_message(tool, 500, &msg); + ret = test_tool_wait_message(tool, 50, &msg); ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); hr = IDirectMusicPerformance_FreePMsg(performance, msg); @@ -3127,37 +3157,35 @@ static void test_notification_pmsg(void) ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); ok(!ret, "got %#lx\n", ret); - check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND); + check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); + ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if); ok(!ret, "got %#lx\n", ret); - check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND); + check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - ret = test_tool_wait_message(tool, 500, &msg); + ret = test_tool_wait_message(tool, 50, &msg); ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); - ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); + ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if); ok(!ret, "got %#lx\n", ret); check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTOPPED); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - ret = test_tool_wait_message(tool, 100, &msg); + + /* wait enough time for notifications to be delivered */ + + ret = test_tool_wait_message(tool, 2000, &msg); ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); ok(!msg, "got %p\n", msg); - hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_PERFORMANCE); - ok(hr == S_OK, "got %#lx\n", hr); - hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); - ok(hr == S_OK, "got %#lx\n", hr); - /* notification messages are also queued for direct access */ @@ -3175,13 +3203,13 @@ static void test_notification_pmsg(void) hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); ok(hr == S_OK, "got %#lx\n", hr); - check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND); + check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); ok(hr == S_OK, "got %#lx\n", hr); - check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND); + check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); @@ -3194,6 +3222,13 @@ static void test_notification_pmsg(void) hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); ok(hr == S_FALSE, "got %#lx\n", hr); + IDirectMusicSegmentState_Release(state); + + hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_PERFORMANCE); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); + ok(hr == S_OK, "got %#lx\n", hr); + /* RemoveNotificationType returns S_FALSE if already removed */ @@ -3205,10 +3240,12 @@ static void test_notification_pmsg(void) hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); ok(hr == S_OK, "got %#lx\n", hr); - hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, NULL); + hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, &state); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_GetTime(performance, NULL, &music_time); ok(hr == S_OK, "got %#lx\n", hr); - ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); + ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if); ok(!ret, "got %#lx\n", ret); check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); @@ -3216,8 +3253,22 @@ static void test_notification_pmsg(void) hr = IDirectMusicPerformance_CloseDown(performance); ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); + ok(hr == S_FALSE, "got %#lx\n", hr); hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); ok(hr == S_FALSE, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 50, &msg); + ok(!ret, "got %#lx\n", ret); + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 500, &msg); + todo_wine ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); + if (!ret) IDirectMusicPerformance_FreePMsg(performance, msg); + + IDirectMusicSegmentState_Release(state); IDirectMusicSegment_Release(segment); @@ -3856,7 +3907,7 @@ static void test_segment_state(void) hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool); ok(hr == S_OK, "got %#lx\n", hr); - hr = test_track_create(&track); + hr = test_track_create(&track, TRUE); ok(hr == S_OK, "got %#lx\n", hr); hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, From a741b94661e274de49ba3a73d2ac3f0173981218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Oct 2023 10:09:23 +0200 Subject: [PATCH 2685/2777] dmime: Use the current time if PlaySegmentEx start_time is 0. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index b58a7d9cd18..3fc5df80b58 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1203,8 +1203,8 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, { struct performance *This = impl_from_IDirectMusicPerformance8(iface); IDirectMusicSegmentState *state; + MUSIC_TIME length, music_time; IDirectMusicSegment *segment; - MUSIC_TIME length; HRESULT hr; FIXME("(%p, %p, %s, %p, %#lx, %I64d, %p, %p, %p): stub\n", This, source, debugstr_w(segment_name), @@ -1216,7 +1216,8 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, if (FAILED(hr = IUnknown_QueryInterface(source, &IID_IDirectMusicSegment, (void **)&segment))) return hr; - if (FAILED(hr = segment_state_create(segment, start_time, iface, &state))) + if ((!(music_time = start_time) && FAILED(hr = IDirectMusicPerformance8_GetTime(iface, NULL, &music_time))) + || FAILED(hr = segment_state_create(segment, music_time, iface, &state))) { IDirectMusicSegment_Release(segment); return hr; @@ -1224,27 +1225,27 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, hr = IDirectMusicSegment_GetLength(segment, &length); if (SUCCEEDED(hr)) - hr = performance_send_notification_pmsg(This, start_time, This->notification_performance, + hr = performance_send_notification_pmsg(This, music_time, This->notification_performance, GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTARTED, NULL); if (SUCCEEDED(hr)) - hr = performance_send_notification_pmsg(This, start_time, This->notification_segment, + hr = performance_send_notification_pmsg(This, music_time, This->notification_segment, GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART, (IUnknown *)state); if (SUCCEEDED(hr)) - hr = performance_send_pmsg(This, start_time, DMUS_PMSGF_TOOL_IMMEDIATE, DMUS_PMSGT_DIRTY, NULL); + hr = performance_send_pmsg(This, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, DMUS_PMSGT_DIRTY, NULL); if (SUCCEEDED(hr)) hr = segment_state_play(state, iface); if (SUCCEEDED(hr)) - hr = performance_send_notification_pmsg(This, start_time + length, This->notification_segment, + hr = performance_send_notification_pmsg(This, music_time + length, This->notification_segment, GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND, (IUnknown *)state); if (SUCCEEDED(hr)) - hr = performance_send_notification_pmsg(This, start_time + length, This->notification_segment, + hr = performance_send_notification_pmsg(This, music_time + length, This->notification_segment, GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND, (IUnknown *)state); if (SUCCEEDED(hr)) - hr = performance_send_pmsg(This, start_time + length, DMUS_PMSGF_TOOL_IMMEDIATE, DMUS_PMSGT_DIRTY, NULL); + hr = performance_send_pmsg(This, music_time + length, DMUS_PMSGF_TOOL_IMMEDIATE, DMUS_PMSGT_DIRTY, NULL); if (SUCCEEDED(hr)) - hr = performance_send_notification_pmsg(This, start_time + length, This->notification_performance, + hr = performance_send_notification_pmsg(This, music_time + length, This->notification_performance, GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTOPPED, NULL); if (SUCCEEDED(hr) && segment_state) From 8028bc15838c434d410a70498e2ae9c655858206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 25 Oct 2023 10:04:00 +0200 Subject: [PATCH 2686/2777] dmime: Send DMUS_NOTIFICATION_SEGALMOSTEND before DMUS_NOTIFICATION_SEGEND. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 6 +++--- dlls/dmime/tests/dmime.c | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 3fc5df80b58..83c2401c083 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1237,11 +1237,11 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, hr = segment_state_play(state, iface); if (SUCCEEDED(hr)) - hr = performance_send_notification_pmsg(This, music_time + length, This->notification_segment, - GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND, (IUnknown *)state); + hr = performance_send_notification_pmsg(This, music_time + length - 1450, This->notification_segment, + GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND, (IUnknown *)state); if (SUCCEEDED(hr)) hr = performance_send_notification_pmsg(This, music_time + length, This->notification_segment, - GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND, (IUnknown *)state); + GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND, (IUnknown *)state); if (SUCCEEDED(hr)) hr = performance_send_pmsg(This, music_time + length, DMUS_PMSGF_TOOL_IMMEDIATE, DMUS_PMSGT_DIRTY, NULL); if (SUCCEEDED(hr)) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 35a6fbc98f4..dc9e98aab0f 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3019,8 +3019,6 @@ static void check_dmus_notification_pmsg_(int line, DMUS_NOTIFICATION_PMSG *msg, "got dwType %#lx\n", msg->dwType); ok_(__FILE__, line)(IsEqualGUID(&msg->guidNotificationType, type), "got guidNotificationType %s\n", debugstr_guid(&msg->guidNotificationType)); - todo_wine_if(IsEqualGUID(type, &GUID_NOTIFICATION_SEGMENT) && - (option == DMUS_NOTIFICATION_SEGALMOSTEND || option == DMUS_NOTIFICATION_SEGEND)) ok_(__FILE__, line)(msg->dwNotificationOption == option, "got dwNotificationOption %#lx\n", msg->dwNotificationOption); ok_(__FILE__, line)(!msg->dwField1, "got dwField1 %lu\n", msg->dwField1); From 7da868dcadb8b42e8927d12a1d99b9d88fb08743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Oct 2023 10:09:23 +0200 Subject: [PATCH 2687/2777] dmime/tests: Check more notification / dirty messages fields. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 91 ++++++++++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 21 deletions(-) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index dc9e98aab0f..05dc653a935 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3011,12 +3011,50 @@ static void test_performance_pmsg(void) IDirectMusicTool_Release(tool); } -#define check_dmus_notification_pmsg(a, b, c) check_dmus_notification_pmsg_(__LINE__, a, b, c) -static void check_dmus_notification_pmsg_(int line, DMUS_NOTIFICATION_PMSG *msg, - const GUID *type, DWORD option) +#define check_dmus_dirty_pmsg(a, b) check_dmus_dirty_pmsg_(__LINE__, a, b) +static void check_dmus_dirty_pmsg_(int line, DMUS_PMSG *msg, MUSIC_TIME music_time) { - ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_NOTIFICATION, - "got dwType %#lx\n", msg->dwType); + ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %#lx\n", msg->dwSize); + ok_(__FILE__, line)(abs(msg->mtTime - music_time) <= 100, "got mtTime %ld\n", msg->mtTime); + ok_(__FILE__, line)(msg->dwFlags == (DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_REFTIME | DMUS_PMSGF_TOOL_IMMEDIATE), + "got dwFlags %#lx\n", msg->dwFlags); + ok_(__FILE__, line)(msg->dwPChannel == 0, "got dwPChannel %#lx\n", msg->dwPChannel); + ok_(__FILE__, line)(msg->dwVirtualTrackID == 0, "got dwVirtualTrackID %#lx\n", msg->dwVirtualTrackID); + ok_(__FILE__, line)(msg->pTool != 0, "got pTool %p\n", msg->pTool); + ok_(__FILE__, line)(msg->pGraph != 0, "got pGraph %p\n", msg->pGraph); + ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_DIRTY, "got dwType %#lx\n", msg->dwType); + ok_(__FILE__, line)(msg->dwVoiceID == 0, "got dwVoiceID %#lx\n", msg->dwVoiceID); + todo_wine ok_(__FILE__, line)(msg->dwGroupID == -1, "got dwGroupID %#lx\n", msg->dwGroupID); + ok_(__FILE__, line)(msg->punkUser == 0, "got punkUser %p\n", msg->punkUser); +} + +#define check_dmus_notification_pmsg(a, b, c, d, e, f) check_dmus_notification_pmsg_(__LINE__, a, b, c, d, e, f) +static void check_dmus_notification_pmsg_(int line, DMUS_NOTIFICATION_PMSG *msg, MUSIC_TIME music_time, DWORD flags, + const GUID *type, DWORD option, void *user) +{ + ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %#lx\n", msg->dwSize); + ok_(__FILE__, line)(msg->rtTime > 0, "got rtTime %I64d\n", msg->rtTime); + ok_(__FILE__, line)(abs(msg->mtTime - music_time) <= 100, "got mtTime %ld\n", msg->mtTime); + todo_wine_if(flags == DMUS_PMSGF_TOOL_ATTIME) + ok_(__FILE__, line)(msg->dwFlags == (DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_REFTIME | flags), + "got dwFlags %#lx\n", msg->dwFlags); + ok_(__FILE__, line)(msg->dwPChannel == 0, "got dwPChannel %#lx\n", msg->dwPChannel); + ok_(__FILE__, line)(msg->dwVirtualTrackID == 0, "got dwVirtualTrackID %#lx\n", msg->dwVirtualTrackID); + if (flags == DMUS_PMSGF_TOOL_ATTIME) + { + todo_wine ok_(__FILE__, line)(msg->pTool == 0, "got pTool %p\n", msg->pTool); + ok_(__FILE__, line)(msg->pGraph == 0, "got pGraph %p\n", msg->pGraph); + } + else + { + ok_(__FILE__, line)(msg->pTool != 0, "got pTool %p\n", msg->pTool); + ok_(__FILE__, line)(msg->pGraph != 0, "got pGraph %p\n", msg->pGraph); + } + ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_NOTIFICATION, "got dwType %#lx\n", msg->dwType); + ok_(__FILE__, line)(msg->dwVoiceID == 0, "got dwVoiceID %#lx\n", msg->dwVoiceID); + todo_wine ok_(__FILE__, line)(msg->dwGroupID == -1, "got dwGroupID %#lx\n", msg->dwGroupID); + ok_(__FILE__, line)(msg->punkUser == (IUnknown *)user, "got punkUser %p\n", msg->punkUser); + ok_(__FILE__, line)(IsEqualGUID(&msg->guidNotificationType, type), "got guidNotificationType %s\n", debugstr_guid(&msg->guidNotificationType)); ok_(__FILE__, line)(msg->dwNotificationOption == option, @@ -3104,7 +3142,7 @@ static void test_notification_pmsg(void) ret = test_tool_wait_message(tool, 50, &msg); ok(!ret, "got %#lx\n", ret); - ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + check_dmus_dirty_pmsg(msg, music_time); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); @@ -3112,7 +3150,7 @@ static void test_notification_pmsg(void) todo_wine ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); if (ret == WAIT_TIMEOUT) ret = test_tool_wait_message(tool, 500, &msg); ok(!ret, "got %#lx\n", ret); - ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + check_dmus_dirty_pmsg(msg, music_time + length); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); @@ -3137,43 +3175,48 @@ static void test_notification_pmsg(void) ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if); ok(!ret, "got %#lx\n", ret); - check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTARTED); + check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_PERFORMANCE, + DMUS_NOTIFICATION_MUSICSTARTED, NULL); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if); ok(!ret, "got %#lx\n", ret); - check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART); + check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT, + DMUS_NOTIFICATION_SEGSTART, state); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 50, &msg); ok(!ret, "got %#lx\n", ret); - ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + check_dmus_dirty_pmsg(msg, music_time); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)¬if); ok(!ret, "got %#lx\n", ret); - check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND); + check_dmus_notification_pmsg(notif, music_time + length - 1450, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT, + DMUS_NOTIFICATION_SEGALMOSTEND, state); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if); ok(!ret, "got %#lx\n", ret); - check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND); + check_dmus_notification_pmsg(notif, music_time + length, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT, + DMUS_NOTIFICATION_SEGEND, state); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 50, &msg); ok(!ret, "got %#lx\n", ret); - ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + check_dmus_dirty_pmsg(msg, music_time + length); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if); ok(!ret, "got %#lx\n", ret); - check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTOPPED); + check_dmus_notification_pmsg(notif, music_time + length, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_PERFORMANCE, + DMUS_NOTIFICATION_MUSICSTOPPED, NULL); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); @@ -3189,31 +3232,36 @@ static void test_notification_pmsg(void) hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); ok(hr == S_OK, "got %#lx\n", hr); - check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTARTED); + check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_ATTIME, &GUID_NOTIFICATION_PERFORMANCE, + DMUS_NOTIFICATION_MUSICSTARTED, NULL); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); ok(hr == S_OK, "got %#lx\n", hr); - check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART); + check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_ATTIME, &GUID_NOTIFICATION_SEGMENT, + DMUS_NOTIFICATION_SEGSTART, state); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); ok(hr == S_OK, "got %#lx\n", hr); - check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND); + check_dmus_notification_pmsg(notif, music_time + length - 1450, DMUS_PMSGF_TOOL_ATTIME, &GUID_NOTIFICATION_SEGMENT, + DMUS_NOTIFICATION_SEGALMOSTEND, state); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); ok(hr == S_OK, "got %#lx\n", hr); - check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND); + check_dmus_notification_pmsg(notif, music_time + length, DMUS_PMSGF_TOOL_ATTIME, &GUID_NOTIFICATION_SEGMENT, + DMUS_NOTIFICATION_SEGEND, state); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); hr = IDirectMusicPerformance_GetNotificationPMsg(performance, ¬if); ok(hr == S_OK, "got %#lx\n", hr); - check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTOPPED); + check_dmus_notification_pmsg(notif, music_time + length, DMUS_PMSGF_TOOL_ATTIME, &GUID_NOTIFICATION_PERFORMANCE, + DMUS_NOTIFICATION_MUSICSTOPPED, NULL); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); @@ -3245,7 +3293,8 @@ static void test_notification_pmsg(void) ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if); ok(!ret, "got %#lx\n", ret); - check_dmus_notification_pmsg(notif, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART); + check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT, + DMUS_NOTIFICATION_SEGSTART, state); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); @@ -3258,7 +3307,7 @@ static void test_notification_pmsg(void) ret = test_tool_wait_message(tool, 50, &msg); ok(!ret, "got %#lx\n", ret); - ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + check_dmus_dirty_pmsg(msg, music_time); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); From 3400cde05800fc8b5d4b473659c5aa9a7fea2674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Oct 2023 14:53:48 +0200 Subject: [PATCH 2688/2777] dmband: Support start_time and end_time Play parameters. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/bandtrack.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index 0c6aa81dd5f..e8ebc234f73 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -159,7 +159,7 @@ static HRESULT WINAPI band_track_EndPlay(IDirectMusicTrack8 *iface, void *state_ } static HRESULT WINAPI band_track_Play(IDirectMusicTrack8 *iface, void *state_data, - MUSIC_TIME start_time, MUSIC_TIME end_time, MUSIC_TIME time_offset, DWORD segment_flags, + MUSIC_TIME start_time, MUSIC_TIME end_time, MUSIC_TIME time_offset, DWORD track_flags, IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state, DWORD track_id) { struct band_track *This = impl_from_IDirectMusicTrack8(iface); @@ -168,13 +168,11 @@ static HRESULT WINAPI band_track_Play(IDirectMusicTrack8 *iface, void *state_dat HRESULT hr; TRACE("(%p, %p, %ld, %ld, %ld, %#lx, %p, %p, %ld)\n", This, state_data, start_time, end_time, - time_offset, segment_flags, performance, segment_state, track_id); + time_offset, track_flags, performance, segment_state, track_id); if (!performance) return DMUS_S_END; - if (start_time != 0) FIXME("start_time %ld not implemented\n", start_time); - if (end_time != -1) FIXME("end_time %ld not implemented\n", end_time); - if (segment_flags) FIXME("segment_flags %#lx not implemented\n", segment_flags); + if (track_flags) FIXME("track_flags %#lx not implemented\n", track_flags); if (segment_state) FIXME("segment_state %p not implemented\n", segment_state); if (FAILED(hr = IDirectMusicPerformance_QueryInterface(performance, @@ -184,7 +182,13 @@ static HRESULT WINAPI band_track_Play(IDirectMusicTrack8 *iface, void *state_dat LIST_FOR_EACH_ENTRY(entry, &This->bands, struct band_entry, entry) { MUSIC_TIME music_time = entry->head.lBandTimeLogical; - if (music_time != -1) music_time += time_offset; + if (music_time == -1 && !(track_flags & DMUS_TRACKF_START)) continue; + else if (music_time != -1) + { + if (music_time < start_time || music_time >= end_time) continue; + music_time += time_offset; + } + if (FAILED(hr = band_send_messages(entry->band, performance, graph, music_time, track_id))) break; } From e413a3591c0d0efefda1b1e38b5f2e867e3664a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Oct 2023 14:54:23 +0200 Subject: [PATCH 2689/2777] dmime: Support start_time and end_time Play parameters. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/seqtrack.c | 8 ++++++-- dlls/dmime/wavetrack.c | 11 ++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/dlls/dmime/seqtrack.c b/dlls/dmime/seqtrack.c index 997bff241d8..586bc742472 100644 --- a/dlls/dmime/seqtrack.c +++ b/dlls/dmime/seqtrack.c @@ -120,8 +120,6 @@ static HRESULT WINAPI sequence_track_Play(IDirectMusicTrack8 *iface, void *state TRACE("(%p, %p, %ld, %ld, %ld, %#lx, %p, %p, %ld)\n", This, state_data, start_time, end_time, time_offset, segment_flags, performance, segment_state, track_id); - if (start_time != 0) FIXME("start_time %ld not implemented\n", start_time); - if (end_time != -1) FIXME("end_time %ld not implemented\n", end_time); if (segment_flags) FIXME("segment_flags %#lx not implemented\n", segment_flags); if (segment_state) FIXME("segment_state %p not implemented\n", segment_state); @@ -134,6 +132,9 @@ static HRESULT WINAPI sequence_track_Play(IDirectMusicTrack8 *iface, void *state DMUS_IO_SEQ_ITEM *item = This->items + i; DMUS_NOTE_PMSG *msg; + if (item->mtTime < start_time) continue; + if (item->mtTime >= end_time) continue; + if (FAILED(hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(*msg), (DMUS_PMSG **)&msg))) break; @@ -164,6 +165,9 @@ static HRESULT WINAPI sequence_track_Play(IDirectMusicTrack8 *iface, void *state DMUS_IO_CURVE_ITEM *item = This->curve_items + i; DMUS_CURVE_PMSG *msg; + if (item->mtStart < start_time) continue; + if (item->mtStart >= end_time) continue; + if (FAILED(hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(*msg), (DMUS_PMSG **)&msg))) break; diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c index 974e656cfe5..7f2fe4a8e5f 100644 --- a/dlls/dmime/wavetrack.c +++ b/dlls/dmime/wavetrack.c @@ -144,7 +144,7 @@ static HRESULT WINAPI wave_track_EndPlay(IDirectMusicTrack8 *iface, void *pState } static HRESULT WINAPI wave_track_Play(IDirectMusicTrack8 *iface, void *state_data, - MUSIC_TIME start_time, MUSIC_TIME end_time, MUSIC_TIME time_offset, DWORD segment_flags, + MUSIC_TIME start_time, MUSIC_TIME end_time, MUSIC_TIME time_offset, DWORD track_flags, IDirectMusicPerformance *performance, IDirectMusicSegmentState *segment_state, DWORD track_id) { struct wave_track *This = impl_from_IDirectMusicTrack8(iface); @@ -155,12 +155,11 @@ static HRESULT WINAPI wave_track_Play(IDirectMusicTrack8 *iface, void *state_dat HRESULT hr; TRACE("(%p, %p, %ld, %ld, %ld, %#lx, %p, %p, %ld)\n", This, state_data, start_time, end_time, - time_offset, segment_flags, performance, segment_state, track_id); + time_offset, track_flags, performance, segment_state, track_id); - if (start_time != 0) FIXME("start_time %ld not implemented\n", start_time); - if (end_time != -1) FIXME("end_time %ld not implemented\n", end_time); - if (segment_flags) FIXME("segment_flags %#lx not implemented\n", segment_flags); + if (track_flags) FIXME("track_flags %#lx not implemented\n", track_flags); if (segment_state) FIXME("segment_state %p not implemented\n", segment_state); + if (!(track_flags & DMUS_TRACKF_START)) return S_OK; if (FAILED(hr = IDirectMusicPerformance_QueryInterface(performance, &IID_IDirectMusicGraph, (void **)&graph))) @@ -175,6 +174,8 @@ static HRESULT WINAPI wave_track_Play(IDirectMusicTrack8 *iface, void *state_dat DMUS_WAVE_PMSG *msg; if (!item->buffer) continue; + if (item->header.rtTime < start_time) continue; + if (item->header.rtTime >= end_time) continue; if (FAILED(hr = IDirectMusicPerformance_AllocPMsg(performance, sizeof(*msg), (DMUS_PMSG **)&msg))) From 7d2ca4479f45c87b0277651ae88164e517993d98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Oct 2023 14:31:42 +0200 Subject: [PATCH 2690/2777] dmime: Fix performance message requeue-ing from the message thread. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 83c2401c083..7ab11773314 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -88,6 +88,19 @@ static inline struct message *message_from_DMUS_PMSG(DMUS_PMSG *msg) return msg ? CONTAINING_RECORD(msg, struct message, msg) : NULL; } +static void performance_queue_message(struct performance *This, struct message *message, struct list *hint) +{ + struct message *prev; + + LIST_FOR_EACH_ENTRY_REV(prev, hint ? hint : &This->messages, struct message, entry) + { + if (&prev->entry == &This->messages) break; + if (prev->msg.rtTime <= message->msg.rtTime) break; + } + + list_add_after(&prev->entry, &message->entry); +} + static HRESULT performance_process_message(struct performance *This, DMUS_PMSG *msg, DWORD *timeout) { static const DWORD delivery_flags = DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME; @@ -133,8 +146,8 @@ static HRESULT performance_process_message(struct performance *This, DMUS_PMSG * static DWORD WINAPI message_thread_proc(void *args) { struct performance *This = args; - struct message *message, *next; - HRESULT hr; + HRESULT hr = DMUS_S_REQUEUE; + struct list *ptr; TRACE("performance %p message thread\n", This); SetThreadDescription(GetCurrentThread(), L"wine_dmime_message"); @@ -145,13 +158,15 @@ static DWORD WINAPI message_thread_proc(void *args) { DWORD timeout = INFINITE; - LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->messages, struct message, entry) + while ((ptr = list_head(&This->messages))) { + struct message *message = LIST_ENTRY(ptr, struct message, entry); + struct list *next = ptr->next; list_remove(&message->entry); list_init(&message->entry); hr = performance_process_message(This, &message->msg, &timeout); - if (hr == DMUS_S_REQUEUE) list_add_before(&next->entry, &message->entry); + if (hr == DMUS_S_REQUEUE) performance_queue_message(This, message, next); if (hr != S_OK) break; } @@ -486,7 +501,7 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS { const DWORD delivery_flags = DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME; struct performance *This = impl_from_IDirectMusicPerformance8(iface); - struct message *message, *next; + struct message *message; HRESULT hr; TRACE("(%p, %p)\n", This, msg); @@ -523,10 +538,7 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS if (hr != DMUS_S_REQUEUE) goto done; } - LIST_FOR_EACH_ENTRY(next, &This->messages, struct message, entry) - if (next->msg.rtTime > message->msg.rtTime) break; - list_add_before(&next->entry, &message->entry); - + performance_queue_message(This, message, NULL); hr = S_OK; } From 1d5f8c1268926f654bb210c744f7d10f1b95c5b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 25 Oct 2023 09:37:24 +0200 Subject: [PATCH 2691/2777] dmime: Implement segment state chunked playback. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/dmime_private.h | 3 ++ dlls/dmime/performance.c | 66 +++++++++++++++++++++++++++++++++----- dlls/dmime/segmentstate.c | 53 ++++++++++++++++++++++++++---- 3 files changed, 107 insertions(+), 15 deletions(-) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 28836694ed9..212ee254192 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -75,12 +75,15 @@ extern void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath*,IDirectSo extern HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, IDirectMusicPerformance8 *performance, IDirectMusicSegmentState **ret_iface); extern HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); +extern HRESULT segment_state_tick(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); extern HRESULT segment_state_end_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); extern HRESULT wave_track_create_from_chunk(IStream *stream, struct chunk_entry *parent, IDirectMusicTrack8 **ret_iface); extern HRESULT performance_get_dsound(IDirectMusicPerformance8 *iface, IDirectSound **dsound); +extern HRESULT performance_send_segment_tick(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, + IDirectMusicSegmentState *state); extern HRESULT performance_send_segment_end(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, IDirectMusicSegmentState *state); diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 7ab11773314..6f77f8677ba 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -28,6 +28,7 @@ enum dmus_internal_message_type { DMUS_PMSGT_INTERNAL_FIRST = 0x10, DMUS_PMSGT_INTERNAL_SEGMENT_END = DMUS_PMSGT_INTERNAL_FIRST, + DMUS_PMSGT_INTERNAL_SEGMENT_TICK, }; struct pchannel_block { @@ -275,6 +276,43 @@ static inline struct performance *impl_from_IDirectMusicPerformance8(IDirectMusi return CONTAINING_RECORD(iface, struct performance, IDirectMusicPerformance8_iface); } +static HRESULT performance_send_segment_start(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, + IDirectMusicSegmentState *state) +{ + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + HRESULT hr; + + if (FAILED(hr = performance_send_notification_pmsg(This, music_time, This->notification_performance, + GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTARTED, NULL))) + return hr; + if (FAILED(hr = performance_send_notification_pmsg(This, music_time, This->notification_segment, + GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART, (IUnknown *)state))) + return hr; + if (FAILED(hr = performance_send_pmsg(This, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, + DMUS_PMSGT_DIRTY, NULL))) + return hr; + + return S_OK; +} + +HRESULT performance_send_segment_tick(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, + IDirectMusicSegmentState *state) +{ + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + REFERENCE_TIME time; + HRESULT hr; + + if (FAILED(hr = IDirectMusicPerformance8_MusicToReferenceTime(iface, music_time, &time))) + return hr; + if (FAILED(hr = IDirectMusicPerformance8_ReferenceToMusicTime(iface, time + 2000000, &music_time))) + return hr; + if (FAILED(hr = performance_send_pmsg(This, music_time, DMUS_PMSGF_TOOL_QUEUE, + DMUS_PMSGT_INTERNAL_SEGMENT_TICK, (IUnknown *)state))) + return hr; + + return S_OK; +} + HRESULT performance_send_segment_end(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, IDirectMusicSegmentState *state) { @@ -1235,16 +1273,11 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, return hr; } + EnterCriticalSection(&This->safe); + hr = IDirectMusicSegment_GetLength(segment, &length); if (SUCCEEDED(hr)) - hr = performance_send_notification_pmsg(This, music_time, This->notification_performance, - GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTARTED, NULL); - if (SUCCEEDED(hr)) - hr = performance_send_notification_pmsg(This, music_time, This->notification_segment, - GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGSTART, (IUnknown *)state); - if (SUCCEEDED(hr)) - hr = performance_send_pmsg(This, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, DMUS_PMSGT_DIRTY, NULL); - + hr = performance_send_segment_start(iface, music_time, state); if (SUCCEEDED(hr)) hr = segment_state_play(state, iface); @@ -1266,6 +1299,8 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, IDirectMusicSegmentState_AddRef(state); } + LeaveCriticalSection(&This->safe); + IDirectMusicSegmentState_Release(state); IDirectMusicSegment_Release(segment); return hr; @@ -1839,6 +1874,21 @@ static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, WARN("Failed to play wave buffer, hr %#lx\n", hr); break; + case DMUS_PMSGT_INTERNAL_SEGMENT_TICK: + msg->rtTime += 10000000; + msg->dwFlags &= ~DMUS_PMSGF_MUSICTIME; + + /* re-send the tick message until segment_state_tick returns S_FALSE */ + if (FAILED(hr = segment_state_tick((IDirectMusicSegmentState *)msg->punkUser, + (IDirectMusicPerformance8 *)performance))) + ERR("Failed to tick segment state %p, hr %#lx\n", msg->punkUser, hr); + else if (hr == S_FALSE) + return DMUS_S_FREE; /* done ticking */ + else if (FAILED(hr = IDirectMusicPerformance_SendPMsg(performance, msg))) + ERR("Failed to queue tick for segment state %p, hr %#lx\n", msg->punkUser, hr); + + return S_OK; + case DMUS_PMSGT_INTERNAL_SEGMENT_END: if (FAILED(hr = segment_state_end_play((IDirectMusicSegmentState *)msg->punkUser, (IDirectMusicPerformance8 *)performance))) diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index 21b98ccc14c..fa49d06836b 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -51,6 +51,7 @@ struct segment_state MUSIC_TIME start_time; MUSIC_TIME start_point; MUSIC_TIME end_point; + MUSIC_TIME played; BOOL auto_download; struct list tracks; @@ -271,25 +272,63 @@ HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time return hr; } -HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance) +static HRESULT segment_state_play_chunk(struct segment_state *This, IDirectMusicPerformance8 *performance, + REFERENCE_TIME duration, DWORD track_flags) { - struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); - DWORD track_flags = DMUS_TRACKF_DIRTY | DMUS_TRACKF_START | DMUS_TRACKF_SEEK; - MUSIC_TIME start_time = This->start_point, end_time = This->end_point; + IDirectMusicSegmentState *iface = (IDirectMusicSegmentState *)&This->IDirectMusicSegmentState8_iface; + MUSIC_TIME next_time, played; struct track_entry *entry; + REFERENCE_TIME time; HRESULT hr = S_OK; + if (FAILED(hr = IDirectMusicPerformance8_MusicToReferenceTime(performance, + This->start_time + This->played, &time))) + return hr; + if (FAILED(hr = IDirectMusicPerformance8_ReferenceToMusicTime(performance, + time + duration, &next_time))) + return hr; + played = min(next_time - This->start_time, This->end_point - This->start_point); + LIST_FOR_EACH_ENTRY(entry, &This->tracks, struct track_entry, entry) { - if (FAILED(hr = IDirectMusicTrack_Play(entry->track, entry->state_data, start_time, end_time, - This->start_time, track_flags, (IDirectMusicPerformance *)performance, iface, entry->track_id))) + if (FAILED(hr = IDirectMusicTrack_Play(entry->track, entry->state_data, + This->start_point + This->played, This->start_point + played, + This->start_time, track_flags, (IDirectMusicPerformance *)performance, + iface, entry->track_id))) { WARN("Failed to play track %p, hr %#lx\n", entry->track, hr); break; } } - return hr; + This->played = played; + if (This->start_point + This->played >= This->end_point) + return S_FALSE; + return S_OK; +} + +HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance) +{ + struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); + HRESULT hr; + + TRACE("%p %p\n", iface, performance); + + if (FAILED(hr = segment_state_play_chunk(This, performance, 10000000, + DMUS_TRACKF_START | DMUS_TRACKF_SEEK | DMUS_TRACKF_DIRTY))) + return hr; + + if (hr == S_FALSE) return S_OK; + return performance_send_segment_tick(performance, This->start_time, iface); +} + +HRESULT segment_state_tick(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance) +{ + struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); + + TRACE("%p %p\n", iface, performance); + + return segment_state_play_chunk(This, performance, 10000000, 0); } HRESULT segment_state_end_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance) From 9ee93c7779d3d887141c651dfd272217ca67f679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 25 Oct 2023 09:47:48 +0200 Subject: [PATCH 2692/2777] dmime: Send notification messages from segment_play_chunk. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/dmime_private.h | 2 ++ dlls/dmime/performance.c | 38 +++++++++++++++++--------------------- dlls/dmime/segmentstate.c | 22 ++++++++++++++++++---- dlls/dmime/tests/dmime.c | 7 +++---- 4 files changed, 40 insertions(+), 29 deletions(-) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 212ee254192..e1a2374facf 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -82,6 +82,8 @@ extern HRESULT wave_track_create_from_chunk(IStream *stream, struct chunk_entry IDirectMusicTrack8 **ret_iface); extern HRESULT performance_get_dsound(IDirectMusicPerformance8 *iface, IDirectSound **dsound); +extern HRESULT performance_send_segment_start(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, + IDirectMusicSegmentState *state); extern HRESULT performance_send_segment_tick(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, IDirectMusicSegmentState *state); extern HRESULT performance_send_segment_end(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 6f77f8677ba..a08c00502d9 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -276,7 +276,7 @@ static inline struct performance *impl_from_IDirectMusicPerformance8(IDirectMusi return CONTAINING_RECORD(iface, struct performance, IDirectMusicPerformance8_iface); } -static HRESULT performance_send_segment_start(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, +HRESULT performance_send_segment_start(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, IDirectMusicSegmentState *state) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); @@ -319,6 +319,18 @@ HRESULT performance_send_segment_end(IDirectMusicPerformance8 *iface, MUSIC_TIME struct performance *This = impl_from_IDirectMusicPerformance8(iface); HRESULT hr; + if (FAILED(hr = performance_send_notification_pmsg(This, music_time - 1450, This->notification_segment, + GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND, (IUnknown *)state))) + return hr; + if (FAILED(hr = performance_send_notification_pmsg(This, music_time, This->notification_segment, + GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND, (IUnknown *)state))) + return hr; + if (FAILED(hr = performance_send_pmsg(This, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, + DMUS_PMSGT_DIRTY, NULL))) + return hr; + if (FAILED(hr = performance_send_notification_pmsg(This, music_time, This->notification_performance, + GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTOPPED, NULL))) + return hr; if (FAILED(hr = performance_send_pmsg(This, music_time, DMUS_PMSGF_TOOL_ATTIME, DMUS_PMSGT_INTERNAL_SEGMENT_END, (IUnknown *)state))) return hr; @@ -1253,8 +1265,8 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, { struct performance *This = impl_from_IDirectMusicPerformance8(iface); IDirectMusicSegmentState *state; - MUSIC_TIME length, music_time; IDirectMusicSegment *segment; + MUSIC_TIME music_time; HRESULT hr; FIXME("(%p, %p, %s, %p, %#lx, %I64d, %p, %p, %p): stub\n", This, source, debugstr_w(segment_name), @@ -1275,25 +1287,9 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, EnterCriticalSection(&This->safe); - hr = IDirectMusicSegment_GetLength(segment, &length); - if (SUCCEEDED(hr)) - hr = performance_send_segment_start(iface, music_time, state); - if (SUCCEEDED(hr)) - hr = segment_state_play(state, iface); - - if (SUCCEEDED(hr)) - hr = performance_send_notification_pmsg(This, music_time + length - 1450, This->notification_segment, - GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND, (IUnknown *)state); - if (SUCCEEDED(hr)) - hr = performance_send_notification_pmsg(This, music_time + length, This->notification_segment, - GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND, (IUnknown *)state); - if (SUCCEEDED(hr)) - hr = performance_send_pmsg(This, music_time + length, DMUS_PMSGF_TOOL_IMMEDIATE, DMUS_PMSGT_DIRTY, NULL); - if (SUCCEEDED(hr)) - hr = performance_send_notification_pmsg(This, music_time + length, This->notification_performance, - GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTOPPED, NULL); - - if (SUCCEEDED(hr) && segment_state) + if (FAILED(hr = segment_state_play(state, iface))) + ERR("Failed to play segment state, hr %#lx\n", hr); + else if (segment_state) { *segment_state = state; IDirectMusicSegmentState_AddRef(state); diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index fa49d06836b..f2f895de881 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -215,8 +215,8 @@ HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time IDirectMusicSegmentState *iface; struct segment_state *This; IDirectMusicTrack *track; - UINT i, duration; HRESULT hr; + UINT i; TRACE("(%p, %lu, %p)\n", segment, start_time, ret_iface); @@ -264,9 +264,6 @@ HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time } } - duration = This->end_point - This->start_point; - if (SUCCEEDED(hr)) hr = performance_send_segment_end(performance, start_time + duration, iface); - if (SUCCEEDED(hr)) *ret_iface = iface; else IDirectMusicSegmentState_Release(iface); return hr; @@ -303,7 +300,18 @@ static HRESULT segment_state_play_chunk(struct segment_state *This, IDirectMusic This->played = played; if (This->start_point + This->played >= This->end_point) + { + MUSIC_TIME end_time = This->start_time + This->played; + + if (FAILED(hr = performance_send_segment_end(performance, end_time, iface))) + { + ERR("Failed to send segment end, hr %#lx\n", hr); + return hr; + } + return S_FALSE; + } + return S_OK; } @@ -314,6 +322,12 @@ HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerforma TRACE("%p %p\n", iface, performance); + if (FAILED(hr = performance_send_segment_start(performance, This->start_time, iface))) + { + ERR("Failed to send segment start, hr %#lx\n", hr); + return hr; + } + if (FAILED(hr = segment_state_play_chunk(This, performance, 10000000, DMUS_TRACKF_START | DMUS_TRACKF_SEEK | DMUS_TRACKF_DIRTY))) return hr; diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 05dc653a935..79fbb902868 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3147,8 +3147,8 @@ static void test_notification_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 50, &msg); - todo_wine ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); - if (ret == WAIT_TIMEOUT) ret = test_tool_wait_message(tool, 500, &msg); + ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); + ret = test_tool_wait_message(tool, 500, &msg); ok(!ret, "got %#lx\n", ret); check_dmus_dirty_pmsg(msg, music_time + length); hr = IDirectMusicPerformance_FreePMsg(performance, msg); @@ -3312,8 +3312,7 @@ static void test_notification_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 500, &msg); - todo_wine ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); - if (!ret) IDirectMusicPerformance_FreePMsg(performance, msg); + ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); IDirectMusicSegmentState_Release(state); IDirectMusicSegment_Release(segment); From 5c2c98e034d1946d26677d54dcea16c847a83100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 23 Oct 2023 23:59:27 +0200 Subject: [PATCH 2693/2777] dmime/tests: Test IDirectMusicPerformance_GetSegmentState. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 79fbb902868..b15c3a1ac37 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -4053,6 +4053,12 @@ static void test_segment_state(void) check_track_state(track, initialized, FALSE); check_track_state(track, playing, FALSE); + hr = IDirectMusicPerformance_GetSegmentState(performance, NULL, 0); + todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 0); + todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); + + tmp_state = state; state = (void *)0xdeadbeef; hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 20, &state); @@ -4062,6 +4068,22 @@ static void test_segment_state(void) ok(state != tmp_state, "got %p\n", state); IDirectMusicSegmentState_Release(tmp_state); + tmp_state = (void *)0xdeadbeef; + hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 0); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(state == tmp_state, "got %p\n", state); + if (tmp_state != (void *)0xdeadbeef) IDirectMusicSegmentState_Release(tmp_state); + + tmp_state = (void *)0xdeadbeef; + hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 69); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(state == tmp_state, "got %p\n", state); + if (tmp_state != (void *)0xdeadbeef) IDirectMusicSegmentState_Release(tmp_state); + + hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 70); + todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); + + check_track_state(track, downloaded, FALSE); check_track_state(track, initialized, TRUE); @@ -4074,6 +4096,9 @@ static void test_segment_state(void) ret = test_track_wait_playing(track, 50); ok(ret == 0, "got %#lx\n", ret); + hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 0); + todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); + tmp_segment = (void *)0xdeadbeef; hr = IDirectMusicSegmentState_GetSegment(state, &tmp_segment); From 2224d6d34387b6b99ee79a24db835cd967e47ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Oct 2023 23:27:57 +0200 Subject: [PATCH 2694/2777] dmime: Implement IDirectMusicPerformance_GetSegmentState semi-stub. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/dmime_private.h | 1 + dlls/dmime/performance.c | 91 +++++++++++++++++++++++++++++++++++--- dlls/dmime/segmentstate.c | 6 +++ dlls/dmime/tests/dmime.c | 12 ++--- 4 files changed, 98 insertions(+), 12 deletions(-) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index e1a2374facf..3c7fc1e332b 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -77,6 +77,7 @@ extern HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME sta extern HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); extern HRESULT segment_state_tick(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); extern HRESULT segment_state_end_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); +extern BOOL segment_state_has_segment(IDirectMusicSegmentState *iface, IDirectMusicSegment *segment); extern HRESULT wave_track_create_from_chunk(IStream *stream, struct chunk_entry *parent, IDirectMusicTrack8 **ret_iface); diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index a08c00502d9..17fbe772f5b 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -76,6 +76,8 @@ struct performance HANDLE notification_event; BOOL notification_performance; BOOL notification_segment; + + IDirectMusicSegment *primary_segment; }; struct message @@ -338,6 +340,12 @@ HRESULT performance_send_segment_end(IDirectMusicPerformance8 *iface, MUSIC_TIME return S_OK; } +static void performance_set_primary_segment(struct performance *This, IDirectMusicSegment *segment) +{ + if (This->primary_segment) IDirectMusicSegment_Release(This->primary_segment); + if ((This->primary_segment = segment)) IDirectMusicSegment_AddRef(This->primary_segment); +} + /* IDirectMusicPerformance8 IUnknown part: */ static HRESULT WINAPI performance_QueryInterface(IDirectMusicPerformance8 *iface, REFIID riid, void **ret_iface) { @@ -487,6 +495,42 @@ static HRESULT WINAPI performance_PlaySegment(IDirectMusicPerformance8 *iface, I segment_flags, start_time, ret_state, NULL, NULL); } +struct state_entry +{ + struct list entry; + IDirectMusicSegmentState *state; +}; + +static void state_entry_destroy(struct state_entry *entry) +{ + list_remove(&entry->entry); + IDirectMusicSegmentState_Release(entry->state); + free(entry); +} + +static void enum_segment_states(struct performance *This, IDirectMusicSegment *segment, struct list *list) +{ + struct state_entry *entry; + struct message *message; + + LIST_FOR_EACH_ENTRY(message, &This->messages, struct message, entry) + { + IDirectMusicSegmentState *message_state; + + if (message->msg.dwType != DMUS_PMSGT_INTERNAL_SEGMENT_TICK + && message->msg.dwType != DMUS_PMSGT_INTERNAL_SEGMENT_END) + continue; + + message_state = (IDirectMusicSegmentState *)message->msg.punkUser; + if (segment && !segment_state_has_segment(message_state, segment)) continue; + + if (!(entry = malloc(sizeof(*entry)))) return; + entry->state = message_state; + IDirectMusicSegmentState_AddRef(entry->state); + list_add_tail(list, &entry->entry); + } +} + static HRESULT WINAPI performance_Stop(IDirectMusicPerformance8 *iface, IDirectMusicSegment *pSegment, IDirectMusicSegmentState *pSegmentState, MUSIC_TIME mtTime, DWORD dwFlags) { @@ -497,12 +541,36 @@ static HRESULT WINAPI performance_Stop(IDirectMusicPerformance8 *iface, IDirectM } static HRESULT WINAPI performance_GetSegmentState(IDirectMusicPerformance8 *iface, - IDirectMusicSegmentState **ppSegmentState, MUSIC_TIME mtTime) + IDirectMusicSegmentState **state, MUSIC_TIME time) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct list *ptr, states = LIST_INIT(states); + struct state_entry *entry, *next; + HRESULT hr = S_OK; - FIXME("(%p,%p, %ld): stub\n", This, ppSegmentState, mtTime); - return S_OK; + TRACE("(%p, %p, %ld)\n", This, state, time); + + if (!state) return E_POINTER; + + EnterCriticalSection(&This->safe); + + enum_segment_states(This, This->primary_segment, &states); + + if (!(ptr = list_head(&states))) hr = DMUS_E_NOT_FOUND; + else + { + entry = LIST_ENTRY(ptr, struct state_entry, entry); + + *state = entry->state; + IDirectMusicSegmentState_AddRef(entry->state); + + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &states, struct state_entry, entry) + state_entry_destroy(entry); + } + + LeaveCriticalSection(&This->safe); + + return hr; } static HRESULT WINAPI performance_SetPrepareTime(IDirectMusicPerformance8 *iface, DWORD dwMilliSeconds) @@ -1152,6 +1220,8 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) WARN("Failed to free message %p, hr %#lx\n", message, hr); } + performance_set_primary_segment(This, NULL); + if (This->master_clock) { IReferenceClock_Release(This->master_clock); @@ -1278,17 +1348,26 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, if (FAILED(hr = IUnknown_QueryInterface(source, &IID_IDirectMusicSegment, (void **)&segment))) return hr; + + EnterCriticalSection(&This->safe); + + performance_set_primary_segment(This, segment); + if ((!(music_time = start_time) && FAILED(hr = IDirectMusicPerformance8_GetTime(iface, NULL, &music_time))) || FAILED(hr = segment_state_create(segment, music_time, iface, &state))) { + performance_set_primary_segment(This, NULL); + LeaveCriticalSection(&This->safe); + IDirectMusicSegment_Release(segment); return hr; } - EnterCriticalSection(&This->safe); - if (FAILED(hr = segment_state_play(state, iface))) + { ERR("Failed to play segment state, hr %#lx\n", hr); + performance_set_primary_segment(This, NULL); + } else if (segment_state) { *segment_state = state; diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index f2f895de881..3e13687254e 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -363,3 +363,9 @@ HRESULT segment_state_end_play(IDirectMusicSegmentState *iface, IDirectMusicPerf return S_OK; } + +BOOL segment_state_has_segment(IDirectMusicSegmentState *iface, IDirectMusicSegment *segment) +{ + struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); + return !segment || This->segment == segment; +} diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index b15c3a1ac37..7d2dd912237 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -4054,9 +4054,9 @@ static void test_segment_state(void) check_track_state(track, playing, FALSE); hr = IDirectMusicPerformance_GetSegmentState(performance, NULL, 0); - todo_wine ok(hr == E_POINTER, "got %#lx\n", hr); + ok(hr == E_POINTER, "got %#lx\n", hr); hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 0); - todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); + ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); tmp_state = state; @@ -4071,14 +4071,14 @@ static void test_segment_state(void) tmp_state = (void *)0xdeadbeef; hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 0); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(state == tmp_state, "got %p\n", state); - if (tmp_state != (void *)0xdeadbeef) IDirectMusicSegmentState_Release(tmp_state); + ok(state == tmp_state, "got %p\n", state); + IDirectMusicSegmentState_Release(tmp_state); tmp_state = (void *)0xdeadbeef; hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 69); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(state == tmp_state, "got %p\n", state); - if (tmp_state != (void *)0xdeadbeef) IDirectMusicSegmentState_Release(tmp_state); + ok(state == tmp_state, "got %p\n", state); + IDirectMusicSegmentState_Release(tmp_state); hr = IDirectMusicPerformance_GetSegmentState(performance, &tmp_state, 70); todo_wine ok(hr == DMUS_E_NOT_FOUND, "got %#lx\n", hr); From 93afd7a88854581aeee09e78f57669e8af289070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 23 Oct 2023 19:52:40 +0200 Subject: [PATCH 2695/2777] dmime/tests: Test tempo track Play and DMUS_PMSGT_TEMPO messages. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 174 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 7d2dd912237..344571d2801 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3888,6 +3888,179 @@ static void test_band_track_play(void) IDirectMusicTool_Release(tool); } +#define check_dmus_tempo_pmsg(a, b, c) check_dmus_tempo_pmsg_(__LINE__, a, b, c) +static void check_dmus_tempo_pmsg_(int line, DMUS_TEMPO_PMSG *msg, MUSIC_TIME time, double tempo) +{ + ok_(__FILE__, line)(msg->dwSize == sizeof(*msg), "got dwSize %lu\n", msg->dwSize); + ok_(__FILE__, line)(msg->rtTime != 0, "got rtTime %I64u\n", msg->rtTime); + ok_(__FILE__, line)(abs(msg->mtTime - time) < 10, "got mtTime %lu\n", msg->mtTime); + ok_(__FILE__, line)(!msg->dwPChannel, "got dwPChannel %lu\n", msg->dwPChannel); + ok_(__FILE__, line)(!!msg->dwVirtualTrackID, "got dwVirtualTrackID %lu\n", msg->dwVirtualTrackID); + ok_(__FILE__, line)(msg->dwType == DMUS_PMSGT_TEMPO, "got dwType %#lx\n", msg->dwType); + ok_(__FILE__, line)(!msg->dwVoiceID, "got dwVoiceID %lu\n", msg->dwVoiceID); + ok_(__FILE__, line)(msg->dwGroupID == -1, "got dwGroupID %lu\n", msg->dwGroupID); + ok_(__FILE__, line)(!msg->punkUser, "got punkUser %p\n", msg->punkUser); + ok_(__FILE__, line)(msg->dblTempo == tempo, "got tempo %f\n", msg->dblTempo); +} + +static void test_tempo_track_play(void) +{ + static const DWORD message_types[] = + { + DMUS_PMSGT_MIDI, + DMUS_PMSGT_NOTE, + DMUS_PMSGT_SYSEX, + DMUS_PMSGT_NOTIFICATION, + DMUS_PMSGT_TEMPO, + DMUS_PMSGT_CURVE, + DMUS_PMSGT_TIMESIG, + DMUS_PMSGT_PATCH, + DMUS_PMSGT_TRANSPOSE, + DMUS_PMSGT_CHANNEL_PRIORITY, + DMUS_PMSGT_STOP, + DMUS_PMSGT_DIRTY, + DMUS_PMSGT_WAVE, + DMUS_PMSGT_LYRIC, + DMUS_PMSGT_SCRIPTLYRIC, + DMUS_PMSGT_USER, + }; + static const LARGE_INTEGER zero = {0}; + DMUS_IO_TEMPO_ITEM tempo_items[] = + { + {.lTime = 100, .dblTempo = 80}, + {.lTime = 300, .dblTempo = 60}, + {.lTime = 200, .dblTempo = 20}, + {.lTime = 4000, .dblTempo = 50}, + }; + IDirectMusicPerformance *performance; + IDirectMusicSegment *segment; + IDirectMusicGraph *graph; + IDirectMusicTrack *track; + IPersistStream *persist; + IDirectMusicTool *tool; + DMUS_TEMPO_PMSG *tempo; + DMUS_TEMPO_PARAM param; + IStream *stream; + DMUS_PMSG *msg; + HRESULT hr; + DWORD ret; + + hr = test_tool_create(message_types, ARRAY_SIZE(message_types), &tool); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicPerformance, (void **)&performance); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = CoCreateInstance(&CLSID_DirectMusicGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicGraph, (void **)&graph); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicGraph_InsertTool(graph, (IDirectMusicTool *)tool, NULL, 0, -1); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_SetGraph(performance, graph); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicGraph_Release(graph); + + + /* create a segment and load a simple RIFF stream */ + + hr = CoCreateInstance(&CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicSegment, (void **)&segment); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicSegment_QueryInterface(segment, &IID_IPersistStream, (void **)&persist); + ok(hr == S_OK, "got %#lx\n", hr); + hr = CreateStreamOnHGlobal(0, TRUE, &stream); + ok(hr == S_OK, "got %#lx\n", hr); + + CHUNK_RIFF(stream, "DMSG") + { + /* set a non-zero segment length, or nothing will be played */ + DMUS_IO_SEGMENT_HEADER head = {.mtLength = 1000}; + CHUNK_DATA(stream, "segh", head); + CHUNK_DATA(stream, "guid", CLSID_DirectMusicSegment); + } + CHUNK_END; + + hr = IStream_Seek(stream, zero, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IPersistStream_Load(persist, stream); + ok(hr == S_OK, "got %#lx\n", hr); + IPersistStream_Release(persist); + IStream_Release(stream); + + + /* add a tempo track to our segment */ + + hr = CoCreateInstance(&CLSID_DirectMusicTempoTrack, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectMusicTrack, (void **)&track); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicSegment_QueryInterface(track, &IID_IPersistStream, (void **)&persist); + ok(hr == S_OK, "got %#lx\n", hr); + hr = CreateStreamOnHGlobal(0, TRUE, &stream); + ok(hr == S_OK, "got %#lx\n", hr); + CHUNK_ARRAY(stream, "tetr", tempo_items); + hr = IStream_Seek(stream, zero, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IPersistStream_Load(persist, stream); + ok(hr == S_OK, "got %#lx\n", hr); + IPersistStream_Release(persist); + IStream_Release(stream); + + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, NULL, ¶m); + ok(hr == DMUS_E_TRACK_NOT_FOUND, "got %#lx\n", hr); + + hr = IDirectMusicSegment_InsertTrack(segment, (IDirectMusicTrack *)track, 1); + ok(hr == S_OK, "got %#lx\n", hr); + IDirectMusicTrack_Release(track); + + + /* now play the segment, and check produced messages */ + + hr = IDirectMusicPerformance_Init(performance, NULL, 0, 0); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0x800, 0, NULL); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 500, &msg); + ok(!ret, "got %#lx\n", ret); + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&tempo); + ok(!ret, "got %#lx\n", ret); + todo_wine ok(tempo->dwType == DMUS_PMSGT_TEMPO, "got %#lx\n", tempo->dwType); + if (tempo->dwType != DMUS_PMSGT_TEMPO) goto skip_tests; + check_dmus_tempo_pmsg(tempo, 100, 80); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)tempo); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&tempo); + todo_wine ok(!ret, "got %#lx\n", ret); + check_dmus_tempo_pmsg(tempo, 300, 60); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)tempo); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 500, &msg); + todo_wine ok(!ret, "got %#lx\n", ret); + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + +skip_tests: + IDirectMusicSegment_Release(segment); + + + hr = IDirectMusicPerformance_CloseDown(performance); + ok(hr == S_OK, "got %#lx\n", hr); + + IDirectMusicPerformance_Release(performance); + IDirectMusicTool_Release(tool); +} + static void test_connect_to_collection(void) { IDirectMusicCollection *collection; @@ -4208,6 +4381,7 @@ START_TEST(dmime) test_wave_pmsg(); test_sequence_track(); test_band_track_play(); + test_tempo_track_play(); test_connect_to_collection(); test_segment_state(); From f931c8eed283d76b52223a04c9326ed17d45e7e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 23 Oct 2023 20:01:36 +0200 Subject: [PATCH 2696/2777] dmime/tests: Test tempo track GetParam with GUID_TempoParam. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 344571d2801..2f2592da6fe 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3933,6 +3933,7 @@ static void test_tempo_track_play(void) {.lTime = 4000, .dblTempo = 50}, }; IDirectMusicPerformance *performance; + MUSIC_TIME next_time; IDirectMusicSegment *segment; IDirectMusicGraph *graph; IDirectMusicTrack *track; @@ -4015,6 +4016,49 @@ static void test_tempo_track_play(void) ok(hr == S_OK, "got %#lx\n", hr); IDirectMusicTrack_Release(track); + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, NULL, NULL); + ok(hr == E_POINTER, "got %#lx\n", hr); + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, NULL, ¶m); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + + memset(¶m, 0xcd, sizeof(param)); + next_time = 0xdeadbeef; + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, &next_time, ¶m); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(next_time == 100, "got next_time %lu\n", next_time); + todo_wine ok(param.mtTime == 100, "got mtTime %ld\n", param.mtTime); + todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 100, &next_time, ¶m); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(next_time == 200, "got next_time %lu\n", next_time); + ok(param.mtTime == 0, "got mtTime %ld\n", param.mtTime); + todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 199, &next_time, ¶m); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(next_time == 101, "got next_time %lu\n", next_time); + todo_wine ok(param.mtTime == -99, "got mtTime %ld\n", param.mtTime); + todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 200, &next_time, ¶m); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(next_time == 100, "got next_time %lu\n", next_time); + todo_wine ok(param.mtTime == -100, "got mtTime %ld\n", param.mtTime); + todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 299, &next_time, ¶m); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(next_time == 1, "got next_time %lu\n", next_time); + todo_wine ok(param.mtTime == -199, "got mtTime %ld\n", param.mtTime); + todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 300, &next_time, ¶m); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(next_time == 3700, "got next_time %lu\n", next_time); + todo_wine ok(param.mtTime == -100, "got mtTime %ld\n", param.mtTime); + todo_wine ok(param.dblTempo == 20, "got dblTempo %f\n", param.dblTempo); + hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 5000, &next_time, ¶m); + todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(next_time == 0, "got next_time %lu\n", next_time); + todo_wine ok(param.mtTime == -1000, "got mtTime %ld\n", param.mtTime); + todo_wine ok(param.dblTempo == 50, "got dblTempo %f\n", param.dblTempo); + /* now play the segment, and check produced messages */ From b2e6601c9ae89e277b5a8d8c958475a30f41a8b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 23 Oct 2023 16:51:31 +0200 Subject: [PATCH 2697/2777] dmime: Fix tempo track GetParam with GUID_TempoParam implementation. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tempotrack.c | 46 ++++++++++++++-------------------- dlls/dmime/tests/dmime.c | 54 ++++++++++++++++++++-------------------- 2 files changed, 45 insertions(+), 55 deletions(-) diff --git a/dlls/dmime/tempotrack.c b/dlls/dmime/tempotrack.c index 07f410118fe..028ebc8879c 100644 --- a/dlls/dmime/tempotrack.c +++ b/dlls/dmime/tempotrack.c @@ -140,42 +140,32 @@ static HRESULT WINAPI tempo_track_Play(IDirectMusicTrack8 *iface, void *pStateDa return S_OK; } -static HRESULT WINAPI tempo_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME time, - MUSIC_TIME *next, void *param) +static HRESULT WINAPI tempo_track_GetParam(IDirectMusicTrack8 *iface, REFGUID type, MUSIC_TIME music_time, + MUSIC_TIME *next_time, void *param) { IDirectMusicTempoTrack *This = impl_from_IDirectMusicTrack8(iface); - DMUS_TEMPO_PARAM *prm = param; - unsigned int i; - - TRACE("(%p, %s, %ld, %p, %p)\n", This, debugstr_dmguid(type), time, next, param); + DMUS_IO_TEMPO_ITEM *item = This->items, *end = item + This->count; + DMUS_TEMPO_PARAM *tempo = param; - if (!param) - return E_POINTER; - if (!IsEqualGUID(type, &GUID_TempoParam)) - return DMUS_E_GET_UNSUPPORTED; + TRACE("(%p, %s, %ld, %p, %p)\n", This, debugstr_dmguid(type), music_time, next_time, param); - FIXME("Partial support for GUID_TempoParam\n"); + if (!param) return E_POINTER; + if (!IsEqualGUID(type, &GUID_TempoParam)) return DMUS_E_GET_UNSUPPORTED; + if (item == end) return DMUS_E_NOT_FOUND; - if (next) - *next = 0; - prm->mtTime = 0; - prm->dblTempo = 0.123456; + tempo->mtTime = item->lTime - music_time; + tempo->dblTempo = item->dblTempo; - for (i = 0; i < This->count; i++) { - if (This->items[i].lTime <= time) { - MUSIC_TIME ofs = This->items[i].lTime - time; - if (ofs > prm->mtTime) { - prm->mtTime = ofs; - prm->dblTempo = This->items[i].dblTempo; - } - if (next && This->items[i].lTime > time && This->items[i].lTime < *next) - *next = This->items[i].lTime; - } + for (; item < end; item++) + { + MUSIC_TIME time = item->lTime - music_time; + if (next_time) *next_time = item->lTime - music_time; + if (time > 0) break; + tempo->mtTime = time; + tempo->dblTempo = item->dblTempo; } - if (0.123456 == prm->dblTempo) - return DMUS_E_NOT_FOUND; - + if (next_time && item == end) *next_time = 0; return S_OK; } diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 2f2592da6fe..8be73d93b54 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -4019,45 +4019,45 @@ static void test_tempo_track_play(void) hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, NULL, NULL); ok(hr == E_POINTER, "got %#lx\n", hr); hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, NULL, ¶m); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); memset(¶m, 0xcd, sizeof(param)); next_time = 0xdeadbeef; hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 0, &next_time, ¶m); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(next_time == 100, "got next_time %lu\n", next_time); - todo_wine ok(param.mtTime == 100, "got mtTime %ld\n", param.mtTime); - todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + ok(hr == S_OK, "got %#lx\n", hr); + ok(next_time == 100, "got next_time %lu\n", next_time); + ok(param.mtTime == 100, "got mtTime %ld\n", param.mtTime); + ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 100, &next_time, ¶m); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(next_time == 200, "got next_time %lu\n", next_time); + ok(hr == S_OK, "got %#lx\n", hr); + ok(next_time == 200, "got next_time %lu\n", next_time); ok(param.mtTime == 0, "got mtTime %ld\n", param.mtTime); - todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 199, &next_time, ¶m); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(next_time == 101, "got next_time %lu\n", next_time); - todo_wine ok(param.mtTime == -99, "got mtTime %ld\n", param.mtTime); - todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + ok(hr == S_OK, "got %#lx\n", hr); + ok(next_time == 101, "got next_time %lu\n", next_time); + ok(param.mtTime == -99, "got mtTime %ld\n", param.mtTime); + ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 200, &next_time, ¶m); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(next_time == 100, "got next_time %lu\n", next_time); - todo_wine ok(param.mtTime == -100, "got mtTime %ld\n", param.mtTime); - todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + ok(hr == S_OK, "got %#lx\n", hr); + ok(next_time == 100, "got next_time %lu\n", next_time); + ok(param.mtTime == -100, "got mtTime %ld\n", param.mtTime); + ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 299, &next_time, ¶m); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(next_time == 1, "got next_time %lu\n", next_time); - todo_wine ok(param.mtTime == -199, "got mtTime %ld\n", param.mtTime); - todo_wine ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); + ok(hr == S_OK, "got %#lx\n", hr); + ok(next_time == 1, "got next_time %lu\n", next_time); + ok(param.mtTime == -199, "got mtTime %ld\n", param.mtTime); + ok(param.dblTempo == 80, "got dblTempo %f\n", param.dblTempo); hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 300, &next_time, ¶m); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(next_time == 3700, "got next_time %lu\n", next_time); - todo_wine ok(param.mtTime == -100, "got mtTime %ld\n", param.mtTime); - todo_wine ok(param.dblTempo == 20, "got dblTempo %f\n", param.dblTempo); + ok(hr == S_OK, "got %#lx\n", hr); + ok(next_time == 3700, "got next_time %lu\n", next_time); + ok(param.mtTime == -100, "got mtTime %ld\n", param.mtTime); + ok(param.dblTempo == 20, "got dblTempo %f\n", param.dblTempo); hr = IDirectMusicSegment_GetParam(segment, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, 5000, &next_time, ¶m); - todo_wine ok(hr == S_OK, "got %#lx\n", hr); + ok(hr == S_OK, "got %#lx\n", hr); ok(next_time == 0, "got next_time %lu\n", next_time); - todo_wine ok(param.mtTime == -1000, "got mtTime %ld\n", param.mtTime); - todo_wine ok(param.dblTempo == 50, "got dblTempo %f\n", param.dblTempo); + ok(param.mtTime == -1000, "got mtTime %ld\n", param.mtTime); + ok(param.dblTempo == 50, "got dblTempo %f\n", param.dblTempo); /* now play the segment, and check produced messages */ From 1a43a415ed010488a772ce0a2e667367bd87a2b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 23 Oct 2023 19:51:49 +0200 Subject: [PATCH 2698/2777] dmime/tests: Add helpers to scale and check music time with tempo. Be flexible on the comparison to ignore rounding errors. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 8be73d93b54..953dac5ed2e 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -2671,6 +2671,17 @@ static void test_performance_graph(void) IDirectMusicTool_Release(tool); } +static double scale_music_time(MUSIC_TIME time, double tempo) +{ + return (600000000. * time) / (tempo * 768.); +} + +#define check_music_time(a, b) check_music_time_(__LINE__, a, b) +static void check_music_time_(int line, MUSIC_TIME time, MUSIC_TIME expect) +{ + ok_(__FILE__, line)(abs(time - expect) <= 1, "got %ld, expected %ld\n", time, expect); +} + static void test_performance_time(void) { IDirectMusicPerformance *performance; @@ -2720,29 +2731,26 @@ static void test_performance_time(void) time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1, &time); ok(hr == S_OK, "got %#lx\n", hr); - ok(time - init_time >= 6505, "got %I64d\n", time - init_time); - ok(time - init_time <= 6515, "got %I64d\n", time - init_time); + check_music_time(time - init_time, scale_music_time(1, 120)); time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1000, &time); ok(hr == S_OK, "got %#lx\n", hr); - ok(time - init_time >= 1000 * 6505, "got %I64d\n", time - init_time); - ok(time - init_time <= 1000 * 6515, "got %I64d\n", time - init_time); + todo_wine check_music_time(time - init_time, scale_music_time(1000, 120)); time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 2000, &time); ok(hr == S_OK, "got %#lx\n", hr); - ok(time - init_time >= 2000 * 6505, "got %I64d\n", time - init_time); - ok(time - init_time <= 2000 * 6515, "got %I64d\n", time - init_time); + todo_wine check_music_time(time - init_time, scale_music_time(2000, 120)); music_time = 0xdeadbeef; hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time, &music_time); ok(hr == S_OK, "got %#lx\n", hr); ok(music_time == 0, "got %ld\n", music_time); music_time = 0xdeadbeef; - hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + 1000 * 6510, &music_time); + hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + scale_music_time(1000, 120), &music_time); ok(hr == S_OK, "got %#lx\n", hr); ok(music_time == 1000, "got %ld\n", music_time); music_time = 0xdeadbeef; - hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + 2000 * 6510, &music_time); + hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + scale_music_time(2000, 120), &music_time); ok(hr == S_OK, "got %#lx\n", hr); ok(music_time == 2000, "got %ld\n", music_time); From da3313e7b8a5b68e59853403ea9a12c730ce3b9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 23 Oct 2023 19:53:37 +0200 Subject: [PATCH 2699/2777] dmime/tests: Test playing tempo track effect on performance times. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 48 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 953dac5ed2e..5dbc7ece8d7 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3941,7 +3941,8 @@ static void test_tempo_track_play(void) {.lTime = 4000, .dblTempo = 50}, }; IDirectMusicPerformance *performance; - MUSIC_TIME next_time; + MUSIC_TIME music_time, next_time; + REFERENCE_TIME init_time, time; IDirectMusicSegment *segment; IDirectMusicGraph *graph; IDirectMusicTrack *track; @@ -4076,12 +4077,57 @@ static void test_tempo_track_play(void) hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0x800, 0, NULL); ok(hr == S_OK, "got %#lx\n", hr); + /* the tempo track only takes effect after DMUS_PMSGT_DIRTY */ + ret = test_tool_wait_message(tool, 500, &msg); ok(!ret, "got %#lx\n", ret); ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); hr = IDirectMusicPerformance_FreePMsg(performance, msg); ok(hr == S_OK, "got %#lx\n", hr); + + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 0, &time); + ok(hr == S_OK, "got %#lx\n", hr); + init_time = time; + + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1, &time); + ok(hr == S_OK, "got %#lx\n", hr); + check_music_time(time - init_time, scale_music_time(1, 120)); + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 100, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine check_music_time(time - init_time, scale_music_time(100, 120)); + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 150, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(50, 80)); + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 200, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(100, 80)); + time = 0xdeadbeef; + hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 400, &time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(200, 80) + scale_music_time(100, 20)); + + music_time = 0xdeadbeef; + hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time, &music_time); + ok(hr == S_OK, "got %#lx\n", hr); + ok(music_time == 0, "got %ld\n", music_time); + music_time = 0xdeadbeef; + time = scale_music_time(100, 120) + scale_music_time(50, 80); + hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + time, &music_time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(music_time == 150, "got %ld\n", music_time); + music_time = 0xdeadbeef; + time = scale_music_time(100, 120) + scale_music_time(200, 80) + scale_music_time(100, 20); + hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + time, &music_time); + ok(hr == S_OK, "got %#lx\n", hr); + todo_wine ok(music_time == 400, "got %ld\n", music_time); + + ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&tempo); ok(!ret, "got %#lx\n", ret); todo_wine ok(tempo->dwType == DMUS_PMSGT_TEMPO, "got %#lx\n", tempo->dwType); From 3bc57984ed46f9436517deb817ea0cd8282979d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Oct 2023 13:21:14 +0200 Subject: [PATCH 2700/2777] dmime: Support playing secondary and control segments. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 17fbe772f5b..06d541efb7e 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -78,6 +78,7 @@ struct performance BOOL notification_segment; IDirectMusicSegment *primary_segment; + IDirectMusicSegment *control_segment; }; struct message @@ -346,6 +347,12 @@ static void performance_set_primary_segment(struct performance *This, IDirectMus if ((This->primary_segment = segment)) IDirectMusicSegment_AddRef(This->primary_segment); } +static void performance_set_control_segment(struct performance *This, IDirectMusicSegment *segment) +{ + if (This->control_segment) IDirectMusicSegment_Release(This->control_segment); + if ((This->control_segment = segment)) IDirectMusicSegment_AddRef(This->control_segment); +} + /* IDirectMusicPerformance8 IUnknown part: */ static HRESULT WINAPI performance_QueryInterface(IDirectMusicPerformance8 *iface, REFIID riid, void **ret_iface) { @@ -1221,6 +1228,7 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) } performance_set_primary_segment(This, NULL); + performance_set_control_segment(This, NULL); if (This->master_clock) { @@ -1333,6 +1341,7 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, WCHAR *segment_name, IUnknown *transition, DWORD segment_flags, INT64 start_time, IDirectMusicSegmentState **segment_state, IUnknown *from, IUnknown *audio_path) { + BOOL primary = !(segment_flags & DMUS_SEGF_SECONDARY), control = (segment_flags & DMUS_SEGF_CONTROL); struct performance *This = impl_from_IDirectMusicPerformance8(iface); IDirectMusicSegmentState *state; IDirectMusicSegment *segment; @@ -1351,12 +1360,14 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, EnterCriticalSection(&This->safe); - performance_set_primary_segment(This, segment); + if (primary) performance_set_primary_segment(This, segment); + if (control) performance_set_control_segment(This, segment); if ((!(music_time = start_time) && FAILED(hr = IDirectMusicPerformance8_GetTime(iface, NULL, &music_time))) || FAILED(hr = segment_state_create(segment, music_time, iface, &state))) { - performance_set_primary_segment(This, NULL); + if (primary) performance_set_primary_segment(This, NULL); + if (control) performance_set_control_segment(This, NULL); LeaveCriticalSection(&This->safe); IDirectMusicSegment_Release(segment); @@ -1366,7 +1377,8 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, if (FAILED(hr = segment_state_play(state, iface))) { ERR("Failed to play segment state, hr %#lx\n", hr); - performance_set_primary_segment(This, NULL); + if (primary) performance_set_primary_segment(This, NULL); + if (control) performance_set_control_segment(This, NULL); } else if (segment_state) { From 716565bd07d3f430ee09de7fa7a897088fbfafc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 23 Oct 2023 15:25:40 +0200 Subject: [PATCH 2701/2777] dmime: Better implement performance times with tempo track. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 85 ++++++++++++++++++++++++++++++++-------- dlls/dmime/tests/dmime.c | 18 ++++----- 2 files changed, 77 insertions(+), 26 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 06d541efb7e..624b7e6bf70 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -21,6 +21,7 @@ #include "dmime_private.h" #include "dmusic_midi.h" #include "wine/rbtree.h" +#include WINE_DEFAULT_DEBUG_CHANNEL(dmime); @@ -677,20 +678,39 @@ static HRESULT WINAPI performance_SendPMsg(IDirectMusicPerformance8 *iface, DMUS static HRESULT WINAPI performance_MusicToReferenceTime(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, REFERENCE_TIME *time) { - static int once; struct performance *This = impl_from_IDirectMusicPerformance8(iface); + MUSIC_TIME tempo_time, next = 0; + DMUS_TEMPO_PARAM param; + double tempo, duration; + HRESULT hr; - if (!once++) FIXME("(%p, %ld, %p): semi-stub\n", This, music_time, time); - else TRACE("(%p, %ld, %p)\n", This, music_time, time); + TRACE("(%p, %ld, %p)\n", This, music_time, time); if (!time) return E_POINTER; *time = 0; if (!This->master_clock) return DMUS_E_NO_MASTER_CLOCK; - /* FIXME: This should be (music_time * 60) / (DMUS_PPQ * tempo) - * but it gives innacurate results */ - *time = This->init_time + (music_time * 6510); + EnterCriticalSection(&This->safe); + + for (tempo = 120., duration = tempo_time = 0; music_time > 0; tempo_time += next) + { + if (FAILED(hr = IDirectMusicPerformance_GetParam(iface, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, + tempo_time, &next, ¶m))) + break; + + if (!next) next = music_time; + else next = min(next, music_time); + + if (param.mtTime <= 0) tempo = param.dblTempo; + duration += (600000000. * next) / (tempo * DMUS_PPQ); + music_time -= next; + } + + duration += (600000000. * music_time) / (tempo * DMUS_PPQ); + *time = This->init_time + duration; + + LeaveCriticalSection(&This->safe); return S_OK; } @@ -698,20 +718,38 @@ static HRESULT WINAPI performance_MusicToReferenceTime(IDirectMusicPerformance8 static HRESULT WINAPI performance_ReferenceToMusicTime(IDirectMusicPerformance8 *iface, REFERENCE_TIME time, MUSIC_TIME *music_time) { - static int once; struct performance *This = impl_from_IDirectMusicPerformance8(iface); + MUSIC_TIME tempo_time, next = 0; + double tempo, duration, step; + DMUS_TEMPO_PARAM param; + HRESULT hr; - if (!once++) FIXME("(%p, %I64d, %p): semi-stub\n", This, time, music_time); - else TRACE("(%p, %I64d, %p)\n", This, time, music_time); + TRACE("(%p, %I64d, %p)\n", This, time, music_time); if (!music_time) return E_POINTER; *music_time = 0; if (!This->master_clock) return DMUS_E_NO_MASTER_CLOCK; - /* FIXME: This should be (time * DMUS_PPQ * tempo) / 60 - * but it gives innacurate results */ - *music_time = (time - This->init_time) / 6510; + EnterCriticalSection(&This->safe); + + duration = time - This->init_time; + + for (tempo = 120., tempo_time = 0; duration > 0; tempo_time += next, duration -= step) + { + if (FAILED(hr = IDirectMusicPerformance_GetParam(iface, &GUID_TempoParam, -1, DMUS_SEG_ALLTRACKS, + tempo_time, &next, ¶m))) + break; + + if (param.mtTime <= 0) tempo = param.dblTempo; + step = (600000000. * next) / (tempo * DMUS_PPQ); + if (!next || duration < step) break; + *music_time = *music_time + next; + } + + *music_time = *music_time + round((duration * tempo * DMUS_PPQ) / 600000000.); + + LeaveCriticalSection(&This->safe); return S_OK; } @@ -1085,13 +1123,26 @@ static HRESULT WINAPI performance_Invalidate(IDirectMusicPerformance8 *iface, MU return S_OK; } -static HRESULT WINAPI performance_GetParam(IDirectMusicPerformance8 *iface, REFGUID rguidType, - DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, MUSIC_TIME *pmtNext, void *pParam) +static HRESULT WINAPI performance_GetParam(IDirectMusicPerformance8 *iface, REFGUID type, + DWORD group, DWORD index, MUSIC_TIME music_time, MUSIC_TIME *next_time, void *param) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + HRESULT hr; - FIXME("(%p, %s, %ld, %ld, %ld, %p, %p): stub\n", This, debugstr_dmguid(rguidType), dwGroupBits, dwIndex, mtTime, pmtNext, pParam); - return S_OK; + TRACE("(%p, %s, %ld, %ld, %ld, %p, %p)\n", This, debugstr_dmguid(type), group, index, music_time, next_time, param); + + if (next_time) *next_time = 0; + + if (!This->control_segment) hr = DMUS_E_NOT_FOUND; + else hr = IDirectMusicSegment_GetParam(This->control_segment, type, group, index, music_time, next_time, param); + + if (FAILED(hr)) + { + if (!This->primary_segment) hr = DMUS_E_NOT_FOUND; + else hr = IDirectMusicSegment_GetParam(This->primary_segment, type, group, index, music_time, next_time, param); + } + + return hr; } static HRESULT WINAPI performance_SetParam(IDirectMusicPerformance8 *iface, REFGUID rguidType, diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 5dbc7ece8d7..2745fd94db9 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -2735,11 +2735,11 @@ static void test_performance_time(void) time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 1000, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine check_music_time(time - init_time, scale_music_time(1000, 120)); + check_music_time(time - init_time, scale_music_time(1000, 120)); time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 2000, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine check_music_time(time - init_time, scale_music_time(2000, 120)); + check_music_time(time - init_time, scale_music_time(2000, 120)); music_time = 0xdeadbeef; hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time, &music_time); @@ -4098,19 +4098,19 @@ static void test_tempo_track_play(void) time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 100, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine check_music_time(time - init_time, scale_music_time(100, 120)); + check_music_time(time - init_time, scale_music_time(100, 120)); time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 150, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(50, 80)); + check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(50, 80)); time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 200, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(100, 80)); + check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(100, 80)); time = 0xdeadbeef; hr = IDirectMusicPerformance_MusicToReferenceTime(performance, 400, &time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(200, 80) + scale_music_time(100, 20)); + check_music_time(time - init_time, scale_music_time(100, 120) + scale_music_time(200, 80) + scale_music_time(100, 20)); music_time = 0xdeadbeef; hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time, &music_time); @@ -4120,15 +4120,15 @@ static void test_tempo_track_play(void) time = scale_music_time(100, 120) + scale_music_time(50, 80); hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + time, &music_time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(music_time == 150, "got %ld\n", music_time); + ok(music_time == 150, "got %ld\n", music_time); music_time = 0xdeadbeef; time = scale_music_time(100, 120) + scale_music_time(200, 80) + scale_music_time(100, 20); hr = IDirectMusicPerformance_ReferenceToMusicTime(performance, init_time + time, &music_time); ok(hr == S_OK, "got %#lx\n", hr); - todo_wine ok(music_time == 400, "got %ld\n", music_time); + ok(music_time == 400, "got %ld\n", music_time); - ret = test_tool_wait_message(tool, 500, (DMUS_PMSG **)&tempo); + ret = test_tool_wait_message(tool, 2000, (DMUS_PMSG **)&tempo); ok(!ret, "got %#lx\n", ret); todo_wine ok(tempo->dwType == DMUS_PMSGT_TEMPO, "got %#lx\n", tempo->dwType); if (tempo->dwType != DMUS_PMSGT_TEMPO) goto skip_tests; From b837cdf0e3c9b950c2b6d3a809573395e63ad67f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 24 Oct 2023 09:18:32 +0200 Subject: [PATCH 2702/2777] dmime/tests: Test that IDirectMusicPerformance_Stop clears messages. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/tests/dmime.c | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 2745fd94db9..0268bd954ef 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3290,6 +3290,55 @@ static void test_notification_pmsg(void) ok(hr == S_FALSE, "got %#lx\n", hr); + /* Stop finishes segment immediately and skips notification messages */ + + hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_PlaySegment(performance, segment, 0, 0, &state); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_GetTime(performance, NULL, &music_time); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if); + ok(!ret, "got %#lx\n", ret); + check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT, + DMUS_NOTIFICATION_SEGSTART, state); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); + ok(hr == S_OK, "got %#lx\n", hr); + + hr = IDirectMusicPerformance_Stop(performance, NULL, NULL, 0, DMUS_SEGF_DEFAULT); + ok(hr == S_OK, "got %#lx\n", hr); + hr = IDirectMusicPerformance_RemoveNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 50, &msg); + ok(!ret, "got %#lx\n", ret); + ok(msg->dwType == DMUS_PMSGT_DIRTY, "got %#lx\n", msg->dwType); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if); + todo_wine ok(!ret, "got %#lx\n", ret); + if (!ret) + { + check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT, + DMUS_NOTIFICATION_SEGABORT, state); + hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); + ok(hr == S_OK, "got %#lx\n", hr); + } + + ret = test_tool_wait_message(tool, 500, &msg); + ok(!ret, "got %#lx\n", ret); + check_dmus_dirty_pmsg(msg, music_time + length); + hr = IDirectMusicPerformance_FreePMsg(performance, msg); + ok(hr == S_OK, "got %#lx\n", hr); + + ret = test_tool_wait_message(tool, 100, &msg); + ok(ret == WAIT_TIMEOUT, "got %#lx\n", ret); + + IDirectMusicSegmentState_Release(state); + + /* CloseDown removes all notifications and notification messages */ hr = IDirectMusicPerformance_AddNotificationType(performance, &GUID_NOTIFICATION_SEGMENT); From 0bfcb71520755e1515bc8e65ff8649e8710faa9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 25 Oct 2023 17:24:56 +0200 Subject: [PATCH 2703/2777] dmime: Implement IDirectMusicTrack_EndPlay for wave track. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/wavetrack.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dlls/dmime/wavetrack.c b/dlls/dmime/wavetrack.c index 7f2fe4a8e5f..3dabbc645e6 100644 --- a/dlls/dmime/wavetrack.c +++ b/dlls/dmime/wavetrack.c @@ -139,7 +139,20 @@ static HRESULT WINAPI wave_track_InitPlay(IDirectMusicTrack8 *iface, static HRESULT WINAPI wave_track_EndPlay(IDirectMusicTrack8 *iface, void *pStateData) { struct wave_track *This = impl_from_IDirectMusicTrack8(iface); + struct wave_part *part; + struct wave_item *item; + FIXME("(%p, %p): stub\n", This, pStateData); + + LIST_FOR_EACH_ENTRY(part, &This->parts, struct wave_part, entry) + { + LIST_FOR_EACH_ENTRY(item, &part->items, struct wave_item, entry) + { + if (!item->buffer) continue; + IDirectSoundBuffer_Stop(item->buffer); + } + } + return S_OK; } From c94d93b841574092cf2e9e21983820309ce42b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Oct 2023 12:55:43 +0200 Subject: [PATCH 2704/2777] dmime: Clear all pending messages in IDirectMusicPerformance_Stop. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/dmime_private.h | 4 +- dlls/dmime/performance.c | 165 +++++++++++++++++++++++++++++-------- dlls/dmime/segmentstate.c | 23 +++++- dlls/dmime/tests/dmime.c | 5 +- 4 files changed, 158 insertions(+), 39 deletions(-) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 3c7fc1e332b..ed1589ece1a 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -76,8 +76,10 @@ extern HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME sta IDirectMusicPerformance8 *performance, IDirectMusicSegmentState **ret_iface); extern HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); extern HRESULT segment_state_tick(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); +extern HRESULT segment_state_stop(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); extern HRESULT segment_state_end_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); extern BOOL segment_state_has_segment(IDirectMusicSegmentState *iface, IDirectMusicSegment *segment); +extern BOOL segment_state_has_track(IDirectMusicSegmentState *iface, DWORD track_id); extern HRESULT wave_track_create_from_chunk(IStream *stream, struct chunk_entry *parent, IDirectMusicTrack8 **ret_iface); @@ -88,7 +90,7 @@ extern HRESULT performance_send_segment_start(IDirectMusicPerformance8 *iface, M extern HRESULT performance_send_segment_tick(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, IDirectMusicSegmentState *state); extern HRESULT performance_send_segment_end(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, - IDirectMusicSegmentState *state); + IDirectMusicSegmentState *state, BOOL abort); /***************************************************************************** * Auxiliary definitions diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 624b7e6bf70..7b7a1d8959e 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -318,24 +318,28 @@ HRESULT performance_send_segment_tick(IDirectMusicPerformance8 *iface, MUSIC_TIM } HRESULT performance_send_segment_end(IDirectMusicPerformance8 *iface, MUSIC_TIME music_time, - IDirectMusicSegmentState *state) + IDirectMusicSegmentState *state, BOOL abort) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); HRESULT hr; - if (FAILED(hr = performance_send_notification_pmsg(This, music_time - 1450, This->notification_segment, - GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND, (IUnknown *)state))) - return hr; - if (FAILED(hr = performance_send_notification_pmsg(This, music_time, This->notification_segment, - GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND, (IUnknown *)state))) - return hr; + if (!abort) + { + if (FAILED(hr = performance_send_notification_pmsg(This, music_time - 1450, This->notification_segment, + GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGALMOSTEND, (IUnknown *)state))) + return hr; + if (FAILED(hr = performance_send_notification_pmsg(This, music_time, This->notification_segment, + GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGEND, (IUnknown *)state))) + return hr; + } + if (FAILED(hr = performance_send_pmsg(This, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, DMUS_PMSGT_DIRTY, NULL))) return hr; if (FAILED(hr = performance_send_notification_pmsg(This, music_time, This->notification_performance, GUID_NOTIFICATION_PERFORMANCE, DMUS_NOTIFICATION_MUSICSTOPPED, NULL))) return hr; - if (FAILED(hr = performance_send_pmsg(This, music_time, DMUS_PMSGF_TOOL_ATTIME, + if (FAILED(hr = performance_send_pmsg(This, music_time, abort ? DMUS_PMSGF_TOOL_IMMEDIATE : DMUS_PMSGF_TOOL_ATTIME, DMUS_PMSGT_INTERNAL_SEGMENT_END, (IUnknown *)state))) return hr; @@ -539,13 +543,118 @@ static void enum_segment_states(struct performance *This, IDirectMusicSegment *s } } -static HRESULT WINAPI performance_Stop(IDirectMusicPerformance8 *iface, IDirectMusicSegment *pSegment, - IDirectMusicSegmentState *pSegmentState, MUSIC_TIME mtTime, DWORD dwFlags) +static BOOL message_needs_flushing(struct message *message, IDirectMusicSegmentState *state) { - struct performance *This = impl_from_IDirectMusicPerformance8(iface); + if (!state) return TRUE; - FIXME("(%p, %p, %p, %ld, %ld): stub\n", This, pSegment, pSegmentState, mtTime, dwFlags); - return S_OK; + switch (message->msg.dwType) + { + case DMUS_PMSGT_MIDI: + case DMUS_PMSGT_NOTE: + case DMUS_PMSGT_CURVE: + case DMUS_PMSGT_PATCH: + case DMUS_PMSGT_WAVE: + if (!segment_state_has_track(state, message->msg.dwVirtualTrackID)) return FALSE; + break; + + case DMUS_PMSGT_NOTIFICATION: + { + DMUS_NOTIFICATION_PMSG *notif = (DMUS_NOTIFICATION_PMSG *)&message->msg; + if (!IsEqualGUID(¬if->guidNotificationType, &GUID_NOTIFICATION_SEGMENT)) return FALSE; + if ((IDirectMusicSegmentState *)message->msg.punkUser != state) return FALSE; + break; + } + + case DMUS_PMSGT_INTERNAL_SEGMENT_TICK: + case DMUS_PMSGT_INTERNAL_SEGMENT_END: + if ((IDirectMusicSegmentState *)message->msg.punkUser != state) return FALSE; + break; + + default: + FIXME("Unhandled message type %#lx\n", message->msg.dwType); + break; + } + + return TRUE; +} + +static void performance_flush_messages(struct performance *This, IDirectMusicSegmentState *state) +{ + IDirectMusicPerformance *iface = (IDirectMusicPerformance *)&This->IDirectMusicPerformance8_iface; + struct message *message, *next; + HRESULT hr; + + LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->messages, struct message, entry) + { + if (!message_needs_flushing(message, state)) continue; + + list_remove(&message->entry); + list_init(&message->entry); + + if (FAILED(hr = IDirectMusicPerformance8_FreePMsg(iface, &message->msg))) + ERR("Failed to free message %p, hr %#lx\n", message, hr); + } + + LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->notifications, struct message, entry) + { + if (!message_needs_flushing(message, state)) continue; + + list_remove(&message->entry); + list_init(&message->entry); + + if (FAILED(hr = IDirectMusicPerformance8_FreePMsg(iface, &message->msg))) + ERR("Failed to free message %p, hr %#lx\n", message, hr); + } +} + +static HRESULT WINAPI performance_Stop(IDirectMusicPerformance8 *iface, IDirectMusicSegment *segment, + IDirectMusicSegmentState *state, MUSIC_TIME music_time, DWORD flags) +{ + struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct list states = LIST_INIT(states); + struct state_entry *entry, *next; + HRESULT hr; + + FIXME("(%p, %p, %p, %ld, %ld): semi-stub\n", This, segment, state, music_time, flags); + + if (music_time) FIXME("time parameter %lu not implemented\n", music_time); + if (flags != DMUS_SEGF_DEFAULT) FIXME("flags parameter %#lx not implemented\n", flags); + + if (!music_time && FAILED(hr = IDirectMusicPerformance8_GetTime(iface, NULL, &music_time))) + return hr; + + EnterCriticalSection(&This->safe); + + if (!state) + enum_segment_states(This, segment, &states); + else if ((entry = malloc(sizeof(*entry)))) + { + entry->state = state; + IDirectMusicSegmentState_AddRef(entry->state); + list_add_tail(&states, &entry->entry); + } + + if (!segment && !state) + performance_flush_messages(This, NULL); + else LIST_FOR_EACH_ENTRY(entry, &states, struct state_entry, entry) + performance_flush_messages(This, entry->state); + + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &states, struct state_entry, entry) + { + if (FAILED(hr = performance_send_notification_pmsg(This, music_time, This->notification_segment, + GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGABORT, (IUnknown *)entry->state))) + ERR("Failed to send DMUS_NOTIFICATION_SEGABORT, hr %#lx\n", hr); + if (FAILED(hr = segment_state_stop(entry->state, iface))) + ERR("Failed to stop segment state, hr %#lx\n", hr); + + IDirectMusicSegmentState_Release(entry->state); + list_remove(&entry->entry); + free(entry); + } + + LeaveCriticalSection(&This->safe); + + return S_OK; } static HRESULT WINAPI performance_GetSegmentState(IDirectMusicPerformance8 *iface, @@ -1234,7 +1343,8 @@ static HRESULT WINAPI performance_AdjustTime(IDirectMusicPerformance8 *iface, RE static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); - struct message *message, *next; + struct list states = LIST_INIT(states); + struct state_entry *entry, *next; HANDLE message_thread; HRESULT hr; @@ -1254,28 +1364,17 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) This->notification_performance = FALSE; This->notification_segment = FALSE; - LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->messages, struct message, entry) - { - list_remove(&message->entry); - list_init(&message->entry); - - if (message->msg.dwType == DMUS_PMSGT_INTERNAL_SEGMENT_END) - hr = IDirectMusicTool_ProcessPMsg(&This->IDirectMusicTool_iface, - (IDirectMusicPerformance *)iface, &message->msg); - else - hr = DMUS_S_FREE; + enum_segment_states(This, NULL, &states); + performance_flush_messages(This, NULL); - if (hr == DMUS_S_FREE && FAILED(hr = IDirectMusicPerformance8_FreePMsg(iface, &message->msg))) - WARN("Failed to free message %p, hr %#lx\n", message, hr); - } - - LIST_FOR_EACH_ENTRY_SAFE(message, next, &This->notifications, struct message, entry) + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &states, struct state_entry, entry) { - list_remove(&message->entry); - list_init(&message->entry); + if (FAILED(hr = segment_state_end_play(entry->state, iface))) + ERR("Failed to stop segment state, hr %#lx\n", hr); - if (FAILED(hr = IDirectMusicPerformance8_FreePMsg(iface, &message->msg))) - WARN("Failed to free message %p, hr %#lx\n", message, hr); + IDirectMusicSegmentState_Release(entry->state); + list_remove(&entry->entry); + free(entry); } performance_set_primary_segment(This, NULL); diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index 3e13687254e..544620b0045 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -303,7 +303,7 @@ static HRESULT segment_state_play_chunk(struct segment_state *This, IDirectMusic { MUSIC_TIME end_time = This->start_time + This->played; - if (FAILED(hr = performance_send_segment_end(performance, end_time, iface))) + if (FAILED(hr = performance_send_segment_end(performance, end_time, iface, FALSE))) { ERR("Failed to send segment end, hr %#lx\n", hr); return hr; @@ -345,6 +345,16 @@ HRESULT segment_state_tick(IDirectMusicSegmentState *iface, IDirectMusicPerforma return segment_state_play_chunk(This, performance, 10000000, 0); } +HRESULT segment_state_stop(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance) +{ + struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); + + TRACE("%p %p\n", iface, performance); + + This->played = This->end_point - This->start_point; + return performance_send_segment_end(performance, This->start_time + This->played, iface, TRUE); +} + HRESULT segment_state_end_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance) { struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); @@ -369,3 +379,14 @@ BOOL segment_state_has_segment(IDirectMusicSegmentState *iface, IDirectMusicSegm struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); return !segment || This->segment == segment; } + +BOOL segment_state_has_track(IDirectMusicSegmentState *iface, DWORD track_id) +{ + struct segment_state *This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); + struct track_entry *entry; + + LIST_FOR_EACH_ENTRY(entry, &This->tracks, struct track_entry, entry) + if (entry->track_id == track_id) return TRUE; + + return FALSE; +} diff --git a/dlls/dmime/tests/dmime.c b/dlls/dmime/tests/dmime.c index 0268bd954ef..07cd3b34516 100644 --- a/dlls/dmime/tests/dmime.c +++ b/dlls/dmime/tests/dmime.c @@ -3318,14 +3318,11 @@ static void test_notification_pmsg(void) ok(hr == S_OK, "got %#lx\n", hr); ret = test_tool_wait_message(tool, 50, (DMUS_PMSG **)¬if); - todo_wine ok(!ret, "got %#lx\n", ret); - if (!ret) - { + ok(!ret, "got %#lx\n", ret); check_dmus_notification_pmsg(notif, music_time, DMUS_PMSGF_TOOL_IMMEDIATE, &GUID_NOTIFICATION_SEGMENT, DMUS_NOTIFICATION_SEGABORT, state); hr = IDirectMusicPerformance_FreePMsg(performance, (DMUS_PMSG *)notif); ok(hr == S_OK, "got %#lx\n", hr); - } ret = test_tool_wait_message(tool, 500, &msg); ok(!ret, "got %#lx\n", ret); From 804b853aabd8c1308d6cf08b48deda9b1912bbf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Oct 2023 12:55:43 +0200 Subject: [PATCH 2705/2777] dmime: Send MIDI_SYSTEM_RESET message on performance reset. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 71 +++++++++++++++++++++++---------------- dlls/dmusic/dmusic_midi.h | 1 + 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 7b7a1d8959e..a808ce3b358 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -454,6 +454,35 @@ static HRESULT performance_init_dmusic(struct performance *This, IDirectSound *d return hr; } +static HRESULT performance_send_midi_pmsg(struct performance *This, DMUS_PMSG *msg, UINT flags, + BYTE status, BYTE byte1, BYTE byte2) +{ + IDirectMusicPerformance8 *performance = &This->IDirectMusicPerformance8_iface; + DMUS_MIDI_PMSG *midi; + HRESULT hr; + + if (FAILED(hr = IDirectMusicPerformance8_AllocPMsg(performance, sizeof(*midi), + (DMUS_PMSG **)&midi))) + return hr; + + if (flags & DMUS_PMSGF_REFTIME) midi->rtTime = msg->rtTime; + if (flags & DMUS_PMSGF_MUSICTIME) midi->mtTime = msg->mtTime; + midi->dwFlags = flags; + midi->dwPChannel = msg->dwPChannel; + midi->dwVirtualTrackID = msg->dwVirtualTrackID; + midi->dwVoiceID = msg->dwVoiceID; + midi->dwGroupID = msg->dwGroupID; + midi->dwType = DMUS_PMSGT_MIDI; + midi->bStatus = status; + midi->bByte1 = byte1; + midi->bByte2 = byte2; + + if (FAILED(hr = IDirectMusicPerformance8_SendPMsg(performance, (DMUS_PMSG *)midi))) + IDirectMusicPerformance8_FreePMsg(performance, (DMUS_PMSG *)midi); + + return hr; +} + static HRESULT WINAPI performance_Init(IDirectMusicPerformance8 *iface, IDirectMusic **dmusic, IDirectSound *dsound, HWND hwnd) { @@ -613,6 +642,7 @@ static HRESULT WINAPI performance_Stop(IDirectMusicPerformance8 *iface, IDirectM struct performance *This = impl_from_IDirectMusicPerformance8(iface); struct list states = LIST_INIT(states); struct state_entry *entry, *next; + DMUS_PMSG msg = {.mtTime = -1}; HRESULT hr; FIXME("(%p, %p, %p, %ld, %ld): semi-stub\n", This, segment, state, music_time, flags); @@ -652,6 +682,13 @@ static HRESULT WINAPI performance_Stop(IDirectMusicPerformance8 *iface, IDirectM free(entry); } + if (!state && !segment) + { + if (FAILED(hr = performance_send_midi_pmsg(This, &msg, DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, + MIDI_SYSTEM_RESET, 0, 0))) + ERR("Failed to send MIDI_SYSTEM_RESET message, hr %#lx\n", hr); + } + LeaveCriticalSection(&This->safe); return S_OK; @@ -1345,6 +1382,7 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) struct performance *This = impl_from_IDirectMusicPerformance8(iface); struct list states = LIST_INIT(states); struct state_entry *entry, *next; + DMUS_PMSG msg = {.mtTime = -1}; HANDLE message_thread; HRESULT hr; @@ -1377,6 +1415,10 @@ static HRESULT WINAPI performance_CloseDown(IDirectMusicPerformance8 *iface) free(entry); } + if (FAILED(hr = performance_send_midi_pmsg(This, &msg, DMUS_PMSGF_MUSICTIME | DMUS_PMSGF_TOOL_IMMEDIATE, + MIDI_SYSTEM_RESET, 0, 0))) + ERR("Failed to send MIDI_SYSTEM_RESET message, hr %#lx\n", hr); + performance_set_primary_segment(This, NULL); performance_set_control_segment(This, NULL); @@ -1930,35 +1972,6 @@ static HRESULT WINAPI performance_tool_GetMediaTypes(IDirectMusicTool *iface, DW return E_NOTIMPL; } -static HRESULT performance_send_midi_pmsg(struct performance *This, DMUS_PMSG *msg, UINT flags, - BYTE status, BYTE byte1, BYTE byte2) -{ - IDirectMusicPerformance8 *performance = &This->IDirectMusicPerformance8_iface; - DMUS_MIDI_PMSG *midi; - HRESULT hr; - - if (FAILED(hr = IDirectMusicPerformance8_AllocPMsg(performance, sizeof(*midi), - (DMUS_PMSG **)&midi))) - return hr; - - if (flags & DMUS_PMSGF_REFTIME) midi->rtTime = msg->rtTime; - if (flags & DMUS_PMSGF_MUSICTIME) midi->mtTime = msg->mtTime; - midi->dwFlags = flags; - midi->dwPChannel = msg->dwPChannel; - midi->dwVirtualTrackID = msg->dwVirtualTrackID; - midi->dwVoiceID = msg->dwVoiceID; - midi->dwGroupID = msg->dwGroupID; - midi->dwType = DMUS_PMSGT_MIDI; - midi->bStatus = status; - midi->bByte1 = byte1; - midi->bByte2 = byte2; - - if (FAILED(hr = IDirectMusicPerformance8_SendPMsg(performance, (DMUS_PMSG *)midi))) - IDirectMusicPerformance8_FreePMsg(performance, (DMUS_PMSG *)midi); - - return hr; -} - static HRESULT WINAPI performance_tool_ProcessPMsg(IDirectMusicTool *iface, IDirectMusicPerformance *performance, DMUS_PMSG *msg) { diff --git a/dlls/dmusic/dmusic_midi.h b/dlls/dmusic/dmusic_midi.h index e545bcaf8cb..574961c12d0 100644 --- a/dlls/dmusic/dmusic_midi.h +++ b/dlls/dmusic/dmusic_midi.h @@ -31,6 +31,7 @@ enum midi_message MIDI_PROGRAM_CHANGE = 0xc0, MIDI_CHANNEL_PRESSURE = 0xd0, MIDI_PITCH_BEND_CHANGE = 0xe0, + MIDI_SYSTEM_RESET = 0xff, }; enum midi_control From e692b7638a51a197074217b87fdb458b78df92e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 25 Oct 2023 10:57:54 +0200 Subject: [PATCH 2706/2777] dmsynth: Reset synthesizer defaults on MIDI_SYSTEM_RESET. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmsynth/synth.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/dmsynth/synth.c b/dlls/dmsynth/synth.c index 379d80f7346..b8d1b3be7be 100644 --- a/dlls/dmsynth/synth.c +++ b/dlls/dmsynth/synth.c @@ -1069,7 +1069,9 @@ static HRESULT WINAPI synth_Render(IDirectMusicSynth8 *iface, short *buffer, TRACE("status %#x chan %#x midi %#x %#x\n", status, chan, event->midi[1], event->midi[2]); - switch (status) + if (event->midi[0] == MIDI_SYSTEM_RESET) + synth_reset_default_values(This); + else switch (status) { case MIDI_NOTE_OFF: fluid_synth_noteoff(This->fluid_synth, chan, event->midi[1]); From 5319d38626fee56bffd68b5b10218668c836a57f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 25 Oct 2023 09:28:59 +0200 Subject: [PATCH 2707/2777] dmime: Implement segment state repeat and looping. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segmentstate.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index 544620b0045..39a8874c724 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -53,6 +53,7 @@ struct segment_state MUSIC_TIME end_point; MUSIC_TIME played; BOOL auto_download; + DWORD repeats; struct list tracks; }; @@ -234,6 +235,7 @@ HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time This->start_time = start_time; if (SUCCEEDED(hr)) hr = IDirectMusicSegment_GetStartPoint(segment, &This->start_point); if (SUCCEEDED(hr)) hr = IDirectMusicSegment_GetLength(segment, &This->end_point); + if (SUCCEEDED(hr)) hr = IDirectMusicSegment_GetRepeats(segment, &This->repeats); for (i = 0; SUCCEEDED(hr); i++) { @@ -284,6 +286,7 @@ static HRESULT segment_state_play_chunk(struct segment_state *This, IDirectMusic if (FAILED(hr = IDirectMusicPerformance8_ReferenceToMusicTime(performance, time + duration, &next_time))) return hr; +play_more: played = min(next_time - This->start_time, This->end_point - This->start_point); LIST_FOR_EACH_ENTRY(entry, &This->tracks, struct track_entry, entry) @@ -303,6 +306,21 @@ static HRESULT segment_state_play_chunk(struct segment_state *This, IDirectMusic { MUSIC_TIME end_time = This->start_time + This->played; + if (This->repeats) + { + if (FAILED(hr = IDirectMusicSegment_GetLoopPoints(This->segment, + &This->played, &This->end_point))) + { + ERR("Failed to get segment loop points, hr %#lx\n", hr); + return hr; + } + This->start_time += This->end_point - This->start_point; + This->repeats--; + + if (next_time - This->start_time > 0 && This->end_point - This->start_point > 0) goto play_more; + return S_OK; + } + if (FAILED(hr = performance_send_segment_end(performance, end_time, iface, FALSE))) { ERR("Failed to send segment end, hr %#lx\n", hr); From 88aa8d6efb0f6392126a98e1a6f6ac23f10046aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Oct 2023 14:19:31 +0200 Subject: [PATCH 2708/2777] dmime: Stop previously playing primary segment in PlaySegmentEx. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index a808ce3b358..55c65daa5a1 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1550,6 +1550,13 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, if (FAILED(hr = IUnknown_QueryInterface(source, &IID_IDirectMusicSegment, (void **)&segment))) return hr; + if (primary && SUCCEEDED(hr = IDirectMusicPerformance8_GetSegmentState(iface, &state, start_time))) + { + if (FAILED(hr = IDirectMusicPerformance_Stop(&This->IDirectMusicPerformance8_iface, NULL, state, start_time, 0))) + ERR("Failed to stop current previous segment, hr %#lx\n", hr); + IDirectMusicSegmentState_Release(state); + } + EnterCriticalSection(&This->safe); if (primary) performance_set_primary_segment(This, segment); From 42e8559dde16751536dd64236bfbe9dc15eaca8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Oct 2023 14:26:41 +0200 Subject: [PATCH 2709/2777] HACK: dmime: Don't send segment end message for secondary segments. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/dmime_private.h | 2 +- dlls/dmime/performance.c | 2 +- dlls/dmime/segmentstate.c | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index ed1589ece1a..4644e060828 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -72,7 +72,7 @@ extern void set_audiopath_perf_pointer(IDirectMusicAudioPath*,IDirectMusicPerfor extern void set_audiopath_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*); extern void set_audiopath_primary_dsound_buffer(IDirectMusicAudioPath*,IDirectSoundBuffer*); -extern HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, +extern HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, DWORD segment_flags, IDirectMusicPerformance8 *performance, IDirectMusicSegmentState **ret_iface); extern HRESULT segment_state_play(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); extern HRESULT segment_state_tick(IDirectMusicSegmentState *iface, IDirectMusicPerformance8 *performance); diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 55c65daa5a1..92ee72a8759 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1563,7 +1563,7 @@ static HRESULT WINAPI performance_PlaySegmentEx(IDirectMusicPerformance8 *iface, if (control) performance_set_control_segment(This, segment); if ((!(music_time = start_time) && FAILED(hr = IDirectMusicPerformance8_GetTime(iface, NULL, &music_time))) - || FAILED(hr = segment_state_create(segment, music_time, iface, &state))) + || FAILED(hr = segment_state_create(segment, music_time, segment_flags, iface, &state))) { if (primary) performance_set_primary_segment(This, NULL); if (control) performance_set_control_segment(This, NULL); diff --git a/dlls/dmime/segmentstate.c b/dlls/dmime/segmentstate.c index 39a8874c724..60e6bef701e 100644 --- a/dlls/dmime/segmentstate.c +++ b/dlls/dmime/segmentstate.c @@ -54,6 +54,7 @@ struct segment_state MUSIC_TIME played; BOOL auto_download; DWORD repeats; + DWORD flags; struct list tracks; }; @@ -106,7 +107,7 @@ static ULONG WINAPI segment_state_Release(IDirectMusicSegmentState8 *iface) if (!ref) { - segment_state_end_play((IDirectMusicSegmentState *)iface, NULL); + if (!(This->flags & DMUS_SEGF_SECONDARY)) segment_state_end_play((IDirectMusicSegmentState *)iface, NULL); if (This->segment) IDirectMusicSegment_Release(This->segment); free(This); } @@ -210,7 +211,7 @@ HRESULT create_dmsegmentstate(REFIID riid, void **ret_iface) return hr; } -HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, +HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time, DWORD segment_flags, IDirectMusicPerformance8 *performance, IDirectMusicSegmentState **ret_iface) { IDirectMusicSegmentState *iface; @@ -224,6 +225,7 @@ HRESULT segment_state_create(IDirectMusicSegment *segment, MUSIC_TIME start_time if (FAILED(hr = create_dmsegmentstate(&IID_IDirectMusicSegmentState, (void **)&iface))) return hr; This = impl_from_IDirectMusicSegmentState8((IDirectMusicSegmentState8 *)iface); + This->flags = segment_flags; This->segment = segment; IDirectMusicSegment_AddRef(This->segment); @@ -321,6 +323,7 @@ static HRESULT segment_state_play_chunk(struct segment_state *This, IDirectMusic return S_OK; } + if (This->flags & DMUS_SEGF_SECONDARY) return S_OK; if (FAILED(hr = performance_send_segment_end(performance, end_time, iface, FALSE))) { ERR("Failed to send segment end, hr %#lx\n", hr); From c663f9fd67a5e07f3dc7c1c6044024618f2e8d59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Oct 2023 14:36:33 +0200 Subject: [PATCH 2710/2777] dmband: Skip band / band track chunk on parsing failure. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmband/band.c | 2 +- dlls/dmband/bandtrack.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/dmband/band.c b/dlls/dmband/band.c index 4c593741516..78ec68ae035 100644 --- a/dlls/dmband/band.c +++ b/dlls/dmband/band.c @@ -422,6 +422,7 @@ static HRESULT WINAPI band_persist_stream_Load(IPersistStream *iface, IStream *s } } + stream_skip_chunk(stream, &chunk); if (FAILED(hr)) return hr; if (TRACE_ON(dmband)) @@ -439,7 +440,6 @@ static HRESULT WINAPI band_persist_stream_Load(IPersistStream *iface, IStream *s } } - stream_skip_chunk(stream, &chunk); return S_OK; } diff --git a/dlls/dmband/bandtrack.c b/dlls/dmband/bandtrack.c index e8ebc234f73..4756ed194ef 100644 --- a/dlls/dmband/bandtrack.c +++ b/dlls/dmband/bandtrack.c @@ -572,6 +572,7 @@ static HRESULT WINAPI band_track_persist_stream_Load(IPersistStream *iface, IStr } } + stream_skip_chunk(stream, &chunk); if (FAILED(hr)) return hr; if (TRACE_ON(dmband)) @@ -594,7 +595,6 @@ static HRESULT WINAPI band_track_persist_stream_Load(IPersistStream *iface, IStr } } - stream_skip_chunk(stream, &chunk); return S_OK; } From 4f70bb1d9cd3f79d263936fc26bc6ac003f8e067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Oct 2023 14:37:40 +0200 Subject: [PATCH 2711/2777] dmime: Skip sequence track chunk on parsing failure. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/seqtrack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/dmime/seqtrack.c b/dlls/dmime/seqtrack.c index 586bc742472..3252580afb6 100644 --- a/dlls/dmime/seqtrack.c +++ b/dlls/dmime/seqtrack.c @@ -407,6 +407,7 @@ static HRESULT WINAPI track_IPersistStream_Load(IPersistStream *iface, IStream * } } + stream_skip_chunk(stream, &chunk); if (FAILED(hr)) return hr; if (TRACE_ON(dmime)) @@ -449,7 +450,6 @@ static HRESULT WINAPI track_IPersistStream_Load(IPersistStream *iface, IStream * } } - stream_skip_chunk(stream, &chunk); return S_OK; } From 63a2a89f3841db6a2d3794abf1cc28523048f522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Oct 2023 14:38:06 +0200 Subject: [PATCH 2712/2777] dmime: Ignore badly formed wave if format and data have been found. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmusic/wave.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/dmusic/wave.c b/dlls/dmusic/wave.c index dd0b8a44779..8ee713bd4f0 100644 --- a/dlls/dmusic/wave.c +++ b/dlls/dmusic/wave.c @@ -167,6 +167,7 @@ static HRESULT parse_wave_chunk(struct wave *This, IStream *stream, struct chunk if (FAILED(hr)) break; } + if (This->format && This->data) return S_OK; return hr; } From b29e4f3020e915d9b22a8f29bb3f005aeb90b74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Oct 2023 14:38:43 +0200 Subject: [PATCH 2713/2777] dmime: Remove shadowing local hr variable. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segment.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index d7402911f00..552a3e2fcfa 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -816,7 +816,6 @@ static HRESULT WINAPI segment_persist_stream_Load(IPersistStream *iface, IStream case MAKE_IDTYPE(FOURCC_RIFF, mmioFOURCC('W','A','V','E')): { IDirectMusicTrack8 *track; - HRESULT hr; TRACE("Loading segment %p from wave file\n", This); From 9b449e04c52a030b56e91b974c75c38b731b4bc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Oct 2023 14:39:03 +0200 Subject: [PATCH 2714/2777] dmime: Skip segment chunk on parsing failure (or success). CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/segment.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/dmime/segment.c b/dlls/dmime/segment.c index 552a3e2fcfa..126bc44335d 100644 --- a/dlls/dmime/segment.c +++ b/dlls/dmime/segment.c @@ -832,6 +832,7 @@ static HRESULT WINAPI segment_persist_stream_Load(IPersistStream *iface, IStream } } + stream_skip_chunk(stream, &chunk); if (FAILED(hr)) { WARN("Failed to load segment from stream %p, hr %#lx\n", stream, hr); From 95af8970a0ae11c7e9a60477007b76c7198a12d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Oct 2023 15:32:29 +0200 Subject: [PATCH 2715/2777] dmime: Rename struct pchannel_block to struct channel_block. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 92ee72a8759..11b4ad58e75 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -32,7 +32,8 @@ enum dmus_internal_message_type DMUS_PMSGT_INTERNAL_SEGMENT_TICK, }; -struct pchannel_block { +struct channel_block +{ DWORD block_num; /* Block 0 is PChannels 0-15, Block 1 is PChannels 16-31, etc */ struct { DWORD channel; /* MIDI channel */ @@ -56,7 +57,7 @@ struct performance float fMasterTempo; long lMasterVolume; /* performance channels */ - struct wine_rb_tree pchannels; + struct wine_rb_tree channel_blocks; BOOL audio_paths_enabled; IDirectMusicAudioPath *pDefaultPath; @@ -233,30 +234,28 @@ static HRESULT performance_send_notification_pmsg(struct performance *This, MUSI return hr; } -static int pchannel_block_compare(const void *key, const struct wine_rb_entry *entry) +static int channel_block_compare(const void *key, const struct wine_rb_entry *entry) { - const struct pchannel_block *b = WINE_RB_ENTRY_VALUE(entry, const struct pchannel_block, entry); - + const struct channel_block *b = WINE_RB_ENTRY_VALUE(entry, const struct channel_block, entry); return *(DWORD *)key - b->block_num; } -static void pchannel_block_free(struct wine_rb_entry *entry, void *context) +static void channel_block_free(struct wine_rb_entry *entry, void *context) { - struct pchannel_block *b = WINE_RB_ENTRY_VALUE(entry, struct pchannel_block, entry); - + struct channel_block *b = WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry); free(b); } -static struct pchannel_block *pchannel_block_set(struct wine_rb_tree *tree, DWORD block_num, +static struct channel_block *channel_block_set(struct wine_rb_tree *tree, DWORD block_num, IDirectMusicPort *port, DWORD group, BOOL only_set_new) { - struct pchannel_block *block; + struct channel_block *block; struct wine_rb_entry *entry; unsigned int i; entry = wine_rb_get(tree, &block_num); if (entry) { - block = WINE_RB_ENTRY_VALUE(entry, struct pchannel_block, entry); + block = WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry); if (only_set_new) return block; } else { @@ -412,7 +411,7 @@ static ULONG WINAPI performance_Release(IDirectMusicPerformance8 *iface) TRACE("(%p): ref=%ld\n", This, ref); if (ref == 0) { - wine_rb_destroy(&This->pchannels, pchannel_block_free, NULL); + wine_rb_destroy(&This->channel_blocks, channel_block_free, NULL); This->safe.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->safe); free(This); @@ -1130,7 +1129,7 @@ static HRESULT perf_dmport_create(struct performance *perf, DMUS_PORTPARAMS *par } for (i = 0; i < params->dwChannelGroups; i++) - pchannel_block_set(&perf->pchannels, i, port, i + 1, FALSE); + channel_block_set(&perf->channel_blocks, i, port, i + 1, FALSE); performance_update_latency_time(perf, port, NULL); return S_OK; @@ -1187,7 +1186,7 @@ static HRESULT WINAPI performance_AssignPChannelBlock(IDirectMusicPerformance8 * if (block_num > MAXDWORD / 16) return E_INVALIDARG; if (This->audio_paths_enabled) return DMUS_E_AUDIOPATHS_IN_USE; - pchannel_block_set(&This->pchannels, block_num, port, group, FALSE); + channel_block_set(&This->channel_blocks, block_num, port, group, FALSE); return S_OK; } @@ -1196,14 +1195,14 @@ static HRESULT WINAPI performance_AssignPChannel(IDirectMusicPerformance8 *iface IDirectMusicPort *port, DWORD group, DWORD channel) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); - struct pchannel_block *block; + struct channel_block *block; FIXME("(%p)->(%ld, %p, %ld, %ld) semi-stub\n", This, pchannel, port, group, channel); if (!port) return E_POINTER; if (This->audio_paths_enabled) return DMUS_E_AUDIOPATHS_IN_USE; - block = pchannel_block_set(&This->pchannels, pchannel / 16, port, 0, TRUE); + block = channel_block_set(&This->channel_blocks, pchannel / 16, port, 0, TRUE); if (block) { block->pchannel[pchannel % 16].group = group; block->pchannel[pchannel % 16].channel = channel; @@ -1216,17 +1215,17 @@ static HRESULT WINAPI performance_PChannelInfo(IDirectMusicPerformance8 *iface, IDirectMusicPort **port, DWORD *group, DWORD *channel) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); - struct pchannel_block *block; + struct channel_block *block; struct wine_rb_entry *entry; DWORD block_num = pchannel / 16; unsigned int index = pchannel % 16; TRACE("(%p)->(%ld, %p, %p, %p)\n", This, pchannel, port, group, channel); - entry = wine_rb_get(&This->pchannels, &block_num); + entry = wine_rb_get(&This->channel_blocks, &block_num); if (!entry) return E_INVALIDARG; - block = WINE_RB_ENTRY_VALUE(entry, struct pchannel_block, entry); + block = WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry); if (port) { *port = block->pchannel[index].port; @@ -2199,7 +2198,7 @@ HRESULT create_dmperformance(REFIID iid, void **ret_iface) obj->pDefaultPath = NULL; InitializeCriticalSection(&obj->safe); obj->safe.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": performance->safe"); - wine_rb_init(&obj->pchannels, pchannel_block_compare); + wine_rb_init(&obj->channel_blocks, channel_block_compare); list_init(&obj->messages); list_init(&obj->notifications); From 2205e43504acbef8152bcbb736d59d651907e1b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Oct 2023 15:34:09 +0200 Subject: [PATCH 2716/2777] dmime: Use a dedicated struct channel to hold performance channels. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 57 ++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 11b4ad58e75..c70b4096cfe 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -32,14 +32,17 @@ enum dmus_internal_message_type DMUS_PMSGT_INTERNAL_SEGMENT_TICK, }; +struct channel +{ + DWORD midi_group; + DWORD midi_channel; + IDirectMusicPort *port; +}; + struct channel_block { DWORD block_num; /* Block 0 is PChannels 0-15, Block 1 is PChannels 16-31, etc */ - struct { - DWORD channel; /* MIDI channel */ - DWORD group; /* MIDI group */ - IDirectMusicPort *port; - } pchannel[16]; + struct channel channels[16]; struct wine_rb_entry entry; }; @@ -247,7 +250,7 @@ static void channel_block_free(struct wine_rb_entry *entry, void *context) } static struct channel_block *channel_block_set(struct wine_rb_tree *tree, DWORD block_num, - IDirectMusicPort *port, DWORD group, BOOL only_set_new) + IDirectMusicPort *port, DWORD midi_group, BOOL only_set_new) { struct channel_block *block; struct wine_rb_entry *entry; @@ -264,9 +267,9 @@ static struct channel_block *channel_block_set(struct wine_rb_tree *tree, DWORD } for (i = 0; i < 16; ++i) { - block->pchannel[i].port = port; - block->pchannel[i].group = group; - block->pchannel[i].channel = i; + block->channels[i].port = port; + block->channels[i].midi_group = midi_group; + block->channels[i].midi_channel = i; } if (!entry) wine_rb_put(tree, &block->block_num, &block->entry); @@ -1176,51 +1179,51 @@ static HRESULT WINAPI performance_RemovePort(IDirectMusicPerformance8 *iface, ID } static HRESULT WINAPI performance_AssignPChannelBlock(IDirectMusicPerformance8 *iface, - DWORD block_num, IDirectMusicPort *port, DWORD group) + DWORD block_num, IDirectMusicPort *port, DWORD midi_group) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); - FIXME("(%p, %ld, %p, %ld): semi-stub\n", This, block_num, port, group); + FIXME("(%p, %ld, %p, %ld): semi-stub\n", This, block_num, port, midi_group); if (!port) return E_POINTER; if (block_num > MAXDWORD / 16) return E_INVALIDARG; if (This->audio_paths_enabled) return DMUS_E_AUDIOPATHS_IN_USE; - channel_block_set(&This->channel_blocks, block_num, port, group, FALSE); + channel_block_set(&This->channel_blocks, block_num, port, midi_group, FALSE); return S_OK; } -static HRESULT WINAPI performance_AssignPChannel(IDirectMusicPerformance8 *iface, DWORD pchannel, - IDirectMusicPort *port, DWORD group, DWORD channel) +static HRESULT WINAPI performance_AssignPChannel(IDirectMusicPerformance8 *iface, DWORD channel_num, + IDirectMusicPort *port, DWORD midi_group, DWORD midi_channel) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); struct channel_block *block; - FIXME("(%p)->(%ld, %p, %ld, %ld) semi-stub\n", This, pchannel, port, group, channel); + FIXME("(%p)->(%ld, %p, %ld, %ld) semi-stub\n", This, channel_num, port, midi_group, midi_channel); if (!port) return E_POINTER; if (This->audio_paths_enabled) return DMUS_E_AUDIOPATHS_IN_USE; - block = channel_block_set(&This->channel_blocks, pchannel / 16, port, 0, TRUE); + block = channel_block_set(&This->channel_blocks, channel_num / 16, port, 0, TRUE); if (block) { - block->pchannel[pchannel % 16].group = group; - block->pchannel[pchannel % 16].channel = channel; + block->channels[channel_num % 16].midi_group = midi_group; + block->channels[channel_num % 16].midi_channel = midi_channel; } return S_OK; } -static HRESULT WINAPI performance_PChannelInfo(IDirectMusicPerformance8 *iface, DWORD pchannel, - IDirectMusicPort **port, DWORD *group, DWORD *channel) +static HRESULT WINAPI performance_PChannelInfo(IDirectMusicPerformance8 *iface, DWORD channel_num, + IDirectMusicPort **port, DWORD *midi_group, DWORD *midi_channel) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); struct channel_block *block; struct wine_rb_entry *entry; - DWORD block_num = pchannel / 16; - unsigned int index = pchannel % 16; + DWORD block_num = channel_num / 16; + unsigned int index = channel_num % 16; - TRACE("(%p)->(%ld, %p, %p, %p)\n", This, pchannel, port, group, channel); + TRACE("(%p)->(%ld, %p, %p, %p)\n", This, channel_num, port, midi_group, midi_channel); entry = wine_rb_get(&This->channel_blocks, &block_num); if (!entry) @@ -1228,13 +1231,11 @@ static HRESULT WINAPI performance_PChannelInfo(IDirectMusicPerformance8 *iface, block = WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry); if (port) { - *port = block->pchannel[index].port; + *port = block->channels[index].port; IDirectMusicPort_AddRef(*port); } - if (group) - *group = block->pchannel[index].group; - if (channel) - *channel = block->pchannel[index].channel; + if (midi_group) *midi_group = block->channels[index].midi_group; + if (midi_channel) *midi_channel = block->channels[index].midi_channel; return S_OK; } From 422cbfb123a1bf4fbc70b14007f297494541dda6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Oct 2023 15:25:13 +0200 Subject: [PATCH 2717/2777] dmime: Introduce a new performance_get_channel helper. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index c70b4096cfe..5418bc04236 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -249,6 +249,14 @@ static void channel_block_free(struct wine_rb_entry *entry, void *context) free(b); } +static struct channel *performance_get_channel(struct performance *This, DWORD channel_num) +{ + DWORD block_num = channel_num / 16; + struct wine_rb_entry *entry; + if (!(entry = wine_rb_get(&This->channel_blocks, &block_num))) return NULL; + return WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry)->channels + channel_num % 16; +} + static struct channel_block *channel_block_set(struct wine_rb_tree *tree, DWORD block_num, IDirectMusicPort *port, DWORD midi_group, BOOL only_set_new) { @@ -1198,18 +1206,17 @@ static HRESULT WINAPI performance_AssignPChannel(IDirectMusicPerformance8 *iface IDirectMusicPort *port, DWORD midi_group, DWORD midi_channel) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); - struct channel_block *block; + struct channel *channel; FIXME("(%p)->(%ld, %p, %ld, %ld) semi-stub\n", This, channel_num, port, midi_group, midi_channel); if (!port) return E_POINTER; if (This->audio_paths_enabled) return DMUS_E_AUDIOPATHS_IN_USE; - block = channel_block_set(&This->channel_blocks, channel_num / 16, port, 0, TRUE); - if (block) { - block->channels[channel_num % 16].midi_group = midi_group; - block->channels[channel_num % 16].midi_channel = midi_channel; - } + if (!(channel = performance_get_channel(This, channel_num))) return DMUS_E_NOT_FOUND; + channel->midi_group = midi_group; + channel->midi_channel = midi_channel; + channel->port = port; return S_OK; } @@ -1218,24 +1225,18 @@ static HRESULT WINAPI performance_PChannelInfo(IDirectMusicPerformance8 *iface, IDirectMusicPort **port, DWORD *midi_group, DWORD *midi_channel) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); - struct channel_block *block; - struct wine_rb_entry *entry; - DWORD block_num = channel_num / 16; - unsigned int index = channel_num % 16; + struct channel *channel; TRACE("(%p)->(%ld, %p, %p, %p)\n", This, channel_num, port, midi_group, midi_channel); - entry = wine_rb_get(&This->channel_blocks, &block_num); - if (!entry) - return E_INVALIDARG; - block = WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry); - - if (port) { - *port = block->channels[index].port; + if (!(channel = performance_get_channel(This, channel_num))) return E_INVALIDARG; + if (port) + { + *port = channel->port; IDirectMusicPort_AddRef(*port); } - if (midi_group) *midi_group = block->channels[index].midi_group; - if (midi_channel) *midi_channel = block->channels[index].midi_channel; + if (midi_group) *midi_group = channel->midi_group; + if (midi_channel) *midi_channel = channel->midi_channel; return S_OK; } From 6247e5fbc8eefda9ef2414b78586d7d863ce6a56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Oct 2023 15:38:12 +0200 Subject: [PATCH 2718/2777] dmime: Set channel block info using IDirectMusicPerformance8_AssignPChannelBlock. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index 5418bc04236..e284c61fdf6 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -257,31 +257,19 @@ static struct channel *performance_get_channel(struct performance *This, DWORD c return WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry)->channels + channel_num % 16; } -static struct channel_block *channel_block_set(struct wine_rb_tree *tree, DWORD block_num, - IDirectMusicPort *port, DWORD midi_group, BOOL only_set_new) +static struct channel_block *performance_get_channel_block(struct performance *This, DWORD block_num) { struct channel_block *block; struct wine_rb_entry *entry; - unsigned int i; - entry = wine_rb_get(tree, &block_num); - if (entry) { + if ((entry = wine_rb_get(&This->channel_blocks, &block_num))) block = WINE_RB_ENTRY_VALUE(entry, struct channel_block, entry); - if (only_set_new) - return block; - } else { - if (!(block = malloc(sizeof(*block)))) return NULL; + else if ((block = malloc(sizeof(*block)))) + { block->block_num = block_num; + wine_rb_put(&This->channel_blocks, &block->block_num, &block->entry); } - for (i = 0; i < 16; ++i) { - block->channels[i].port = port; - block->channels[i].midi_group = midi_group; - block->channels[i].midi_channel = i; - } - if (!entry) - wine_rb_put(tree, &block->block_num, &block->entry); - return block; } @@ -1121,6 +1109,7 @@ static void performance_update_latency_time(struct performance *This, IDirectMus static HRESULT perf_dmport_create(struct performance *perf, DMUS_PORTPARAMS *params) { + IDirectMusicPerformance8 *iface = &perf->IDirectMusicPerformance8_iface; IDirectMusicPort *port; GUID guid; unsigned int i; @@ -1140,7 +1129,10 @@ static HRESULT perf_dmport_create(struct performance *perf, DMUS_PORTPARAMS *par } for (i = 0; i < params->dwChannelGroups; i++) - channel_block_set(&perf->channel_blocks, i, port, i + 1, FALSE); + { + if (FAILED(hr = IDirectMusicPerformance8_AssignPChannelBlock(iface, i, port, i + 1))) + ERR("Failed to set performance channel block info, hr %#lx\n", hr); + } performance_update_latency_time(perf, port, NULL); return S_OK; @@ -1190,6 +1182,8 @@ static HRESULT WINAPI performance_AssignPChannelBlock(IDirectMusicPerformance8 * DWORD block_num, IDirectMusicPort *port, DWORD midi_group) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct channel_block *block; + UINT i; FIXME("(%p, %ld, %p, %ld): semi-stub\n", This, block_num, port, midi_group); @@ -1197,7 +1191,14 @@ static HRESULT WINAPI performance_AssignPChannelBlock(IDirectMusicPerformance8 * if (block_num > MAXDWORD / 16) return E_INVALIDARG; if (This->audio_paths_enabled) return DMUS_E_AUDIOPATHS_IN_USE; - channel_block_set(&This->channel_blocks, block_num, port, midi_group, FALSE); + if (!(block = performance_get_channel_block(This, block_num))) return E_OUTOFMEMORY; + for (i = 0; i < ARRAY_SIZE(block->channels); ++i) + { + struct channel *channel = block->channels + i; + channel->midi_group = midi_group; + channel->midi_channel = i; + channel->port = port; + } return S_OK; } From 9c5c67a07f0bb6c13b2571e88cf92ab85b24037e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 26 Oct 2023 15:25:13 +0200 Subject: [PATCH 2719/2777] dmime: Avoid leaking performance channel block ports. CW-Bug-Id: #16680 CW-Bug-Id: #20424 CW-Bug-Id: #22409 --- dlls/dmime/performance.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index e284c61fdf6..c19efe022bf 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1135,6 +1135,7 @@ static HRESULT perf_dmport_create(struct performance *perf, DMUS_PORTPARAMS *par } performance_update_latency_time(perf, port, NULL); + IDirectMusicPort_Release(port); return S_OK; } @@ -1198,6 +1199,8 @@ static HRESULT WINAPI performance_AssignPChannelBlock(IDirectMusicPerformance8 * channel->midi_group = midi_group; channel->midi_channel = i; channel->port = port; + if (channel->port) IDirectMusicPort_Release(channel->port); + if ((channel->port = port)) IDirectMusicPort_AddRef(channel->port); } return S_OK; @@ -1218,6 +1221,7 @@ static HRESULT WINAPI performance_AssignPChannel(IDirectMusicPerformance8 *iface channel->midi_group = midi_group; channel->midi_channel = midi_channel; channel->port = port; + IDirectMusicPort_AddRef(port); return S_OK; } From 44fbee72d2d9e0ae095f87d01bf179a18f1b3ea3 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Wed, 1 Nov 2023 01:55:28 +0000 Subject: [PATCH 2720/2777] rtworkq: Avoid use-after-free. queue_release_pending_item releases the work_item reference but later accesses `item->queue`, which is a potential use-after-free. --- dlls/rtworkq/queue.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dlls/rtworkq/queue.c b/dlls/rtworkq/queue.c index c088d892f39..b748768de7d 100644 --- a/dlls/rtworkq/queue.c +++ b/dlls/rtworkq/queue.c @@ -734,14 +734,16 @@ static HRESULT invoke_async_callback(IRtwqAsyncResult *result) static void queue_release_pending_item(struct work_item *item) { - EnterCriticalSection(&item->queue->cs); + struct queue *queue = item->queue; + EnterCriticalSection(&queue->cs); if (item->key) { list_remove(&item->entry); item->key = 0; IUnknown_Release(&item->IUnknown_iface); } - LeaveCriticalSection(&item->queue->cs); + LeaveCriticalSection(&queue->cs); + } static void CALLBACK waiting_item_callback(TP_CALLBACK_INSTANCE *instance, void *context, TP_WAIT *wait, From 5efa97e4722f5b7b933908c2d5b79c3ec386d4b5 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Wed, 1 Nov 2023 02:23:20 +0000 Subject: [PATCH 2721/2777] mfplat: tests: Validate MFCancelWorkItem releases the callback. --- dlls/mfplat/tests/mfplat.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 7264db7f79b..a3b39ccec57 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -3200,6 +3200,7 @@ static void test_scheduled_items(void) IMFAsyncResult *result; MFWORKITEM_KEY key, key2; HRESULT hr; + ULONG refcount; callback = create_test_callback(NULL); @@ -3212,6 +3213,9 @@ static void test_scheduled_items(void) hr = MFCancelWorkItem(key); ok(hr == S_OK, "Failed to cancel item, hr %#lx.\n", hr); + refcount = IMFAsyncCallback_Release(&callback->IMFAsyncCallback_iface); + ok(refcount == 0, "Unexpected refcount %lu.\n", refcount); + hr = MFCancelWorkItem(key); ok(hr == MF_E_NOT_FOUND || broken(hr == S_OK) /* < win10 */, "Unexpected hr %#lx.\n", hr); @@ -3221,6 +3225,8 @@ static void test_scheduled_items(void) return; } + callback = create_test_callback(NULL); + hr = MFCreateAsyncResult(NULL, &callback->IMFAsyncCallback_iface, NULL, &result); ok(hr == S_OK, "Failed to create result, hr %#lx.\n", hr); From 3f088c2df1302aca0fcb03147388dffc9a0b90c9 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Wed, 1 Nov 2023 02:05:38 +0000 Subject: [PATCH 2722/2777] rtworkq: Release cancelled work items. And avoiding race condition while doing so. Usually the threadpool holds a reference to the work_item, which is released when the work_item's callback is invoked. However queue_cancel_item closes the threadpool object without releasing it, leading to a leak. The fix is not as simple as adding a IUnknown_Release, because the work_item's callback can still be called after CloseThreadpoolTimer/Wait has returned. In fact its callback might currently be running. In which case we would double release the reference. We have to stop any further callbacks to be queued, wait for any currently running callbacks to finish, then finally we can close the threadpool object. After that, if the callback wasn't called, we can safely release the work_item reference. --- dlls/rtworkq/queue.c | 73 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/dlls/rtworkq/queue.c b/dlls/rtworkq/queue.c index b748768de7d..c5a269c2402 100644 --- a/dlls/rtworkq/queue.c +++ b/dlls/rtworkq/queue.c @@ -880,32 +880,87 @@ static HRESULT queue_submit_timer(struct queue *queue, IRtwqAsyncResult *result, return S_OK; } -static HRESULT queue_cancel_item(struct queue *queue, RTWQWORKITEM_KEY key) +static HRESULT queue_cancel_item(struct queue *queue, const RTWQWORKITEM_KEY key) { HRESULT hr = RTWQ_E_NOT_FOUND; + union { TP_WAIT *wait_object; TP_TIMER *timer_object; } work_object; + enum work_item_type work_object_type; struct work_item *item; + const UINT64 mask = key >> 32; EnterCriticalSection(&queue->cs); LIST_FOR_EACH_ENTRY(item, &queue->pending_items, struct work_item, entry) { if (item->key == key) { - key >>= 32; - if ((key & WAIT_ITEM_KEY_MASK) == WAIT_ITEM_KEY_MASK) + hr = S_OK; + if ((mask & WAIT_ITEM_KEY_MASK) == WAIT_ITEM_KEY_MASK) + { + if (item->type != WORK_ITEM_WAIT) + WARN("Item %p is not a wait item, but its key has wait item mask.\n", item); + + work_object_type = WORK_ITEM_WAIT; + work_object.wait_object = item->u.wait_object; + item->u.wait_object = NULL; + } + else if ((mask & SCHEDULED_ITEM_KEY_MASK) == SCHEDULED_ITEM_KEY_MASK) + { + if (item->type != WORK_ITEM_TIMER) + WARN("Item %p is not a timer item, but its key has timer item mask.\n", item); + + work_object_type = WORK_ITEM_TIMER; + work_object.timer_object = item->u.timer_object; + item->u.timer_object = NULL; + } + else + { + WARN("Unknown item key mask %#I64x.\n", mask); + queue_release_pending_item(item); + goto out; + } + break; + } + } + + if (FAILED(hr)) + goto out; + + LeaveCriticalSection(&queue->cs); + + // Safely either stop the thread pool object, or if the callback is already running, wait for it to finish. + // This way, we can safely release the reference to the work item. + if (work_object_type == WORK_ITEM_WAIT) + { + SetThreadpoolWait(work_object.wait_object, NULL, NULL); + WaitForThreadpoolWaitCallbacks(work_object.wait_object, TRUE); + CloseThreadpoolWait(work_object.wait_object); + } + else if (work_object_type == WORK_ITEM_TIMER) + { + SetThreadpoolTimer(work_object.timer_object, NULL, 0, 0); + WaitForThreadpoolTimerCallbacks(work_object.timer_object, TRUE); + CloseThreadpoolTimer(work_object.timer_object); + } + + // If the work item is still in pending items, its callback hasn't been invoked yet; + // we remove it. Otherwise its callback would have already released it. + EnterCriticalSection(&queue->cs); + LIST_FOR_EACH_ENTRY(item, &queue->pending_items, struct work_item, entry) + { + if (item->key == key) + { + if (work_object_type == WORK_ITEM_WAIT) { IRtwqAsyncResult_SetStatus(item->result, RTWQ_E_OPERATION_CANCELLED); invoke_async_callback(item->result); - CloseThreadpoolWait(item->u.wait_object); } - else if ((key & SCHEDULED_ITEM_KEY_MASK) == SCHEDULED_ITEM_KEY_MASK) - CloseThreadpoolTimer(item->u.timer_object); - else - WARN("Unknown item key mask %#I64x.\n", key); queue_release_pending_item(item); - hr = S_OK; + IUnknown_Release(&item->IUnknown_iface); break; } } + +out: LeaveCriticalSection(&queue->cs); return hr; From 78c3b5f46d38969a66a0ad023761fd087f4ef41e Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Mon, 6 Nov 2023 17:18:42 +0200 Subject: [PATCH 2723/2777] Revert "win32u: Ignore emulated mouse messages on touch-enabled windows." This reverts commit ea2ee1a6e991d98a00a402ee656fe0b03cad3b9a. --- dlls/win32u/message.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 6284f0452b9..6a9e77f796c 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1639,12 +1639,6 @@ static BOOL process_mouse_message( MSG *msg, UINT hw_id, ULONG_PTR extra_info, H msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt ); SetThreadDpiAwarenessContext( get_window_dpi_awareness_context( msg->hwnd )); - if ((extra_info & 0xffffff00) == 0xff515700 && NtUserIsTouchWindow( msg->hwnd, NULL )) - { - accept_hardware_message( hw_id ); - return FALSE; - } - if ((extra_info & 0xffffff00) != 0xff515700 && enable_mouse_in_pointer) { WORD flags = POINTER_MESSAGE_FLAG_PRIMARY; From 271b699bf7357ebdce993f615b134d69d5e7c6bd Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 7 Nov 2023 15:10:52 -0600 Subject: [PATCH 2724/2777] fixup! fshack: winex11: Support opengl scaling according to fake resolution. NULL get_win_data() may happen if the window is from the other process. CW-Bug-Id: #22950 --- dlls/winex11.drv/opengl.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 0380aa4cc63..ba1a42855aa 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1530,10 +1530,12 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel gl->window = create_client_window( hwnd, visual ); if (gl->window) gl->drawable = pglXCreateWindow( gdi_display, gl->format->fbconfig, gl->window, NULL ); - data = get_win_data( hwnd ); - gl->fs_hack = data->fs_hack || fs_hack_get_gamma_ramp( NULL ); - if (gl->fs_hack) TRACE( "Window %p has the fullscreen hack enabled\n", hwnd ); - release_win_data( data ); + if ((data = get_win_data( hwnd ))) + { + gl->fs_hack = data->fs_hack || fs_hack_get_gamma_ramp( NULL ); + if (gl->fs_hack) TRACE( "Window %p has the fullscreen hack enabled\n", hwnd ); + release_win_data( data ); + } TRACE( "%p created client %lx drawable %lx\n", hwnd, gl->window, gl->drawable ); } #ifdef SONAME_LIBXCOMPOSITE From 4a2cac9b1a197ae550a7f8530333eacd3d034da7 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 7 Nov 2023 15:17:51 -0600 Subject: [PATCH 2725/2777] fixup! winex11.drv: fshack/GL: Support fshack on offscreen drawables. CW-Bug-Id: #22950 --- dlls/winex11.drv/opengl.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index ba1a42855aa..4455f9464e9 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -1550,10 +1550,12 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel gl->drawable = pglXCreateWindow( gdi_display, gl->format->fbconfig, gl->window, NULL ); pXCompositeRedirectWindow( gdi_display, gl->window, CompositeRedirectManual ); } - data = get_win_data( hwnd ); - gl->fs_hack = data->fs_hack || fs_hack_get_gamma_ramp( NULL ); - if (gl->fs_hack) TRACE( "Window %p has the fullscreen hack enabled\n", hwnd ); - release_win_data( data ); + if ((data = get_win_data( hwnd ))) + { + gl->fs_hack = data->fs_hack || fs_hack_get_gamma_ramp( NULL ); + if (gl->fs_hack) TRACE( "Window %p has the fullscreen hack enabled\n", hwnd ); + release_win_data( data ); + } if (gl->layered_type) detach_client_window( hwnd, 0 ); TRACE( "%p created child %lx drawable %lx\n", hwnd, gl->window, gl->drawable ); } From 05383dc54ff0b16bf0878b44d32264f92ed486af Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 8 Nov 2023 12:43:13 -0600 Subject: [PATCH 2726/2777] wine.inf: Enable builtin amd_ags_x64 for Assassin's Creed Mirage. CW-Bug-Id: #22962 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index f0395ecc4ca..90a1ec682c9 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2854,6 +2854,7 @@ HKCU,Software\Wine\AppDefaults\u4.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\tll.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\SOPFFO.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\RiftApart.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" +HKCU,Software\Wine\AppDefaults\ACMirage.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" ;;App-specific overrides for atiadlxx.dll. HKCU,Software\Wine\AppDefaults\s2_sp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\s2_mp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" From 71e696cb7d01ceb8f4eae18bcab1bd8f9152b596 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 8 Nov 2023 17:32:04 -0600 Subject: [PATCH 2727/2777] user32: Return empty string from LoadStringW() if resource is not found. CW-Bug-Id: #22967 --- dlls/user32/resource.c | 9 +++++++-- dlls/user32/tests/resource.c | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/dlls/user32/resource.c b/dlls/user32/resource.c index 3714b05ce8d..a634d79948b 100644 --- a/dlls/user32/resource.c +++ b/dlls/user32/resource.c @@ -164,9 +164,9 @@ INT WINAPI DECLSPEC_HOTPATCH LoadStringW( HINSTANCE instance, UINT resource_id, /* Use loword (incremented by 1) as resourceid */ hrsrc = FindResourceW( instance, MAKEINTRESOURCEW((LOWORD(resource_id) >> 4) + 1), (LPWSTR)RT_STRING ); - if (!hrsrc) return 0; + if (!hrsrc) goto error; hmem = LoadResource( instance, hrsrc ); - if (!hmem) return 0; + if (!hmem) goto error; p = LockResource(hmem); string_num = resource_id & 0x000f; @@ -196,6 +196,11 @@ INT WINAPI DECLSPEC_HOTPATCH LoadStringW( HINSTANCE instance, UINT resource_id, TRACE("%s loaded !\n", debugstr_w(buffer)); return i; + +error: + TRACE( "Failed to load string.\n" ); + if (buflen > 0) buffer[0] = 0; + return 0; } /********************************************************************** diff --git a/dlls/user32/tests/resource.c b/dlls/user32/tests/resource.c index fff962b955c..9c2b9eba0a2 100644 --- a/dlls/user32/tests/resource.c +++ b/dlls/user32/tests/resource.c @@ -50,6 +50,7 @@ static void test_LoadStringW(void) win_skip( "LoadStringW does not return a pointer to the resource\n" ); return; } + length2 = LoadStringW(hInst, 2, returnedstringw, ARRAY_SIZE(returnedstringw)); /* get resource string */ ok(length2 > 0, "LoadStringW failed to load resource 2, ret %d, err %ld\n", length2, GetLastError()); ok(length1 == length2, "LoadStringW returned different values dependent on buflen. ret1 %d, ret2 %d\n", @@ -75,6 +76,30 @@ static void test_LoadStringW(void) /* check again, with a different buflen value, that calling LoadStringW with buffer = NULL returns zero */ retvalue = LoadStringW(hInst, 2, NULL, 128); ok(!retvalue, "LoadStringW returned a non-zero value when called with buffer = NULL, retvalue = %d\n", retvalue); + + /* Test missing resource. */ + SetLastError(0xdeadbeef); + memset(returnedstringw, 0xcc, sizeof(returnedstringw)); + length1 = LoadStringW(hInst, 0xdeadbeef, returnedstringw, ARRAY_SIZE(returnedstringw)); + ok(!length1, "got %d.\n", length1); + ok(GetLastError() == ERROR_RESOURCE_NAME_NOT_FOUND, "got %lu.\n", GetLastError()); + ok(!returnedstringw[0], "got %#x.\n", returnedstringw[0]); + ok(returnedstringw[1] == 0xcccc, "got %#x.\n", returnedstringw[1]); + + SetLastError(0xdeadbeef); + memset(returnedstringw, 0xcc, sizeof(returnedstringw)); + length1 = LoadStringW(hInst, 0xdeadbeef, returnedstringw, 0); + ok(!length1, "got %d.\n", length1); + ok(GetLastError() == ERROR_RESOURCE_NAME_NOT_FOUND, "got %lu.\n", GetLastError()); + ok(returnedstringw[0] == 0xcccc, "got %#x.\n", returnedstringw[1]); + + SetLastError(0xdeadbeef); + memset(returnedstringw, 0xcc, sizeof(returnedstringw)); + length1 = LoadStringW(hInst, 0xdeadbeef, returnedstringw, 1); + ok(!length1, "got %d.\n", length1); + ok(GetLastError() == ERROR_RESOURCE_NAME_NOT_FOUND, "got %lu.\n", GetLastError()); + ok(!returnedstringw[0], "got %#x.\n", returnedstringw[0]); + ok(returnedstringw[1] == 0xcccc, "got %#x.\n", returnedstringw[1]); } static void test_LoadStringA (void) From f3fcbdc3809723a11ee451ea83e028c962aaa0bd Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 8 Nov 2023 17:56:17 -0600 Subject: [PATCH 2728/2777] user32: Put 0 to output string even for 1 char buffer in LoadStringW(). CW-Bug-Id: #22967 --- dlls/user32/resource.c | 6 +----- dlls/user32/tests/resource.c | 9 +++++++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/dlls/user32/resource.c b/dlls/user32/resource.c index a634d79948b..c09ee9bb65c 100644 --- a/dlls/user32/resource.c +++ b/dlls/user32/resource.c @@ -187,12 +187,8 @@ INT WINAPI DECLSPEC_HOTPATCH LoadStringW( HINSTANCE instance, UINT resource_id, if (i > 0) { memcpy(buffer, p + 1, i * sizeof (WCHAR)); buffer[i] = 0; - } else { - if (buflen > 1) { - buffer[0] = 0; - return 0; - } } + else goto error; TRACE("%s loaded !\n", debugstr_w(buffer)); return i; diff --git a/dlls/user32/tests/resource.c b/dlls/user32/tests/resource.c index 9c2b9eba0a2..9379b5c7732 100644 --- a/dlls/user32/tests/resource.c +++ b/dlls/user32/tests/resource.c @@ -100,6 +100,15 @@ static void test_LoadStringW(void) ok(GetLastError() == ERROR_RESOURCE_NAME_NOT_FOUND, "got %lu.\n", GetLastError()); ok(!returnedstringw[0], "got %#x.\n", returnedstringw[0]); ok(returnedstringw[1] == 0xcccc, "got %#x.\n", returnedstringw[1]); + + /* Test short buffer */ + SetLastError(0xdeadbeef); + memset(returnedstringw, 0xcc, sizeof(returnedstringw)); + length1 = LoadStringW(hInst, 2, returnedstringw, 1); /* get resource string */ + ok(!length1, "got %d.\n", length1); + ok(GetLastError() == 0xdeadbeef, "got %lu.\n", GetLastError()); + ok(!returnedstringw[0], "got %#x.\n", returnedstringw[0]); + ok(returnedstringw[1] == 0xcccc, "got %#x.\n", returnedstringw[1]); } static void test_LoadStringA (void) From ddb9b1e2ffed7cd795fef688b9d4cf9fac9e2aab Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 8 Nov 2023 17:38:10 -0600 Subject: [PATCH 2729/2777] kernelbase: Return empty string from LoadStringW() if resource is not found. CW-Bug-Id: #22967 --- dlls/kernelbase/string.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dlls/kernelbase/string.c b/dlls/kernelbase/string.c index 798bc1f3d63..1a792dcadb1 100644 --- a/dlls/kernelbase/string.c +++ b/dlls/kernelbase/string.c @@ -1231,9 +1231,9 @@ INT WINAPI DECLSPEC_HOTPATCH LoadStringW(HINSTANCE instance, UINT resource_id, L /* Use loword (incremented by 1) as resourceid */ hrsrc = FindResourceW(instance, MAKEINTRESOURCEW((LOWORD(resource_id) >> 4) + 1), (LPWSTR)RT_STRING); - if (!hrsrc) return 0; + if (!hrsrc) goto error; hmem = LoadResource(instance, hrsrc); - if (!hmem) return 0; + if (!hmem) goto error; p = LockResource(hmem); string_num = resource_id & 0x000f; @@ -1267,6 +1267,11 @@ INT WINAPI DECLSPEC_HOTPATCH LoadStringW(HINSTANCE instance, UINT resource_id, L TRACE("returning %s\n", debugstr_w(buffer)); return i; + +error: + TRACE( "Failed to load string.\n" ); + if (buflen > 0) buffer[0] = 0; + return 0; } INT WINAPI DECLSPEC_HOTPATCH LoadStringA(HINSTANCE instance, UINT resource_id, LPSTR buffer, INT buflen) From 939fe522ecad9b81f7157ad2426fa092a96c771e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 8 Nov 2023 17:58:41 -0600 Subject: [PATCH 2730/2777] kernelbase: Put 0 to output string even for 1 char buffer in LoadStringW(). CW-Bug-Id: #22967 --- dlls/kernelbase/string.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/dlls/kernelbase/string.c b/dlls/kernelbase/string.c index 1a792dcadb1..1df1f54aafd 100644 --- a/dlls/kernelbase/string.c +++ b/dlls/kernelbase/string.c @@ -1256,14 +1256,7 @@ INT WINAPI DECLSPEC_HOTPATCH LoadStringW(HINSTANCE instance, UINT resource_id, L memcpy(buffer, p + 1, i * sizeof (WCHAR)); buffer[i] = 0; } - else - { - if (buflen > 1) - { - buffer[0] = 0; - return 0; - } - } + else goto error; TRACE("returning %s\n", debugstr_w(buffer)); return i; From 1d57f07242f5dc0b1ec9fded5a65f239dcf9687b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 9 Nov 2023 10:59:27 +0100 Subject: [PATCH 2731/2777] windows.gaming.input: Fix inverted start / select gamepad buttons. CW-Bug-Id: #22968 --- dlls/windows.gaming.input/gamepad.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/windows.gaming.input/gamepad.c b/dlls/windows.gaming.input/gamepad.c index 112ec49a1d3..0d7cd690821 100644 --- a/dlls/windows.gaming.input/gamepad.c +++ b/dlls/windows.gaming.input/gamepad.c @@ -273,8 +273,8 @@ static HRESULT WINAPI gamepad_GetCurrentReading( IGamepad *iface, struct Gamepad if (state.buttons[3]) value->Buttons |= GamepadButtons_Y; if (state.buttons[4]) value->Buttons |= GamepadButtons_LeftShoulder; if (state.buttons[5]) value->Buttons |= GamepadButtons_RightShoulder; - if (state.buttons[6]) value->Buttons |= GamepadButtons_Menu; - if (state.buttons[7]) value->Buttons |= GamepadButtons_View; + if (state.buttons[6]) value->Buttons |= GamepadButtons_View; + if (state.buttons[7]) value->Buttons |= GamepadButtons_Menu; if (state.buttons[8]) value->Buttons |= GamepadButtons_LeftThumbstick; if (state.buttons[9]) value->Buttons |= GamepadButtons_RightThumbstick; From e1f28ec731ce08c2ef7157baca7eec4f569c6255 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 9 Nov 2023 16:06:37 -0600 Subject: [PATCH 2732/2777] amd_ags_x64: Implement agsDriverExtensionsDX11_DeInit(). CW-Bug-Id: #22976 --- dlls/amd_ags_x64/amd_ags_x64.spec | 2 +- dlls/amd_ags_x64/amd_ags_x64_main.c | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec index a825a450cfa..d8126fa961a 100644 --- a/dlls/amd_ags_x64/amd_ags_x64.spec +++ b/dlls/amd_ags_x64/amd_ags_x64.spec @@ -8,7 +8,7 @@ @ stub agsDriverExtensionsDX11_CreateTexture1D @ stub agsDriverExtensionsDX11_CreateTexture2D @ stub agsDriverExtensionsDX11_CreateTexture3D -@ stub agsDriverExtensionsDX11_DeInit +@ stdcall agsDriverExtensionsDX11_DeInit(ptr) @ stub agsDriverExtensionsDX11_Destroy @ stdcall -norelay -arch=win64 agsDriverExtensionsDX11_DestroyDevice() @ stdcall -norelay -arch=win64 agsDriverExtensionsDX11_EndUAVOverlap() DX11_EndUAVOverlap_impl diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 1ee87f77a1e..3a9f99c1bc4 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -1078,6 +1078,19 @@ AGSReturnCode WINAPI agsDriverExtensionsDX11_Init( AGSContext *context, ID3D11De return AGS_SUCCESS; } +AGSReturnCode WINAPI agsDriverExtensionsDX11_DeInit( AGSContext* context ) +{ + TRACE("context %p.\n", context); + + if (context->d3d11_context) + { + ID3D11DeviceContext_Release(context->d3d11_context); + context->d3d11_context = NULL; + } + + return AGS_SUCCESS; +} + BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) { TRACE("%p, %u, %p.\n", instance, reason, reserved); From a381bee7fea437914e7e419e8033e07f89663cd6 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 9 Nov 2023 16:22:26 -0600 Subject: [PATCH 2733/2777] amd_ags_x64: Factor out get_version_number(). CW-Bug-Id: #22976 --- dlls/amd_ags_x64/amd_ags_x64_main.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 3a9f99c1bc4..96f952aed96 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -251,6 +251,20 @@ static AGSReturnCode vk_get_physical_device_properties(unsigned int *out_count, return ret; } +static enum amd_ags_version get_version_number(int ags_version) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(amd_ags_info); i++) + if (AGS_MAKE_VERSION(amd_ags_info[i].major, amd_ags_info[i].minor, amd_ags_info[i].patch) == ags_version) + { + TRACE("Found AGS v%d.%d.%d.\n", amd_ags_info[i].major, amd_ags_info[i].minor, amd_ags_info[i].patch); + return i; + } + ERR("Unknown ags_version %#x, using 5.4.1.\n", ags_version); + return AMD_AGS_VERSION_5_4_1; +} + static enum amd_ags_version determine_ags_version(void) { /* AMD AGS is not binary compatible between versions (even minor versions), and the game @@ -265,7 +279,7 @@ static enum amd_ags_version determine_ags_version(void) DWORD infosize; void *infobuf = NULL; void *val; - UINT vallen, i; + UINT vallen; VS_FIXEDFILEINFO *info; UINT16 major, minor, patch; WCHAR dllname[MAX_PATH], temp_path[MAX_PATH], temp_name[MAX_PATH]; @@ -318,17 +332,7 @@ static enum amd_ags_version determine_ags_version(void) minor = info->dwFileVersionMS; patch = info->dwFileVersionLS >> 16; TRACE("Found amd_ags_x64.dll v%d.%d.%d\n", major, minor, patch); - - for (i = 0; i < ARRAY_SIZE(amd_ags_info); i++) - { - if ((major == amd_ags_info[i].major) && - (minor == amd_ags_info[i].minor) && - (patch == amd_ags_info[i].patch)) - { - ret = i; - break; - } - } + ret = get_version_number(AGS_MAKE_VERSION(major, minor, patch)); done: if (*temp_name) From e3e5b48d9e943929e887b61037dc3220a83d524d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 27 Sep 2023 20:32:35 -0600 Subject: [PATCH 2734/2777] amd_ags_x64: Use version provided for agsInitialize(). CW-Bug-Id: #22976 --- dlls/amd_ags_x64/amd_ags_x64_main.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 96f952aed96..1d31494b986 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -265,7 +265,7 @@ static enum amd_ags_version get_version_number(int ags_version) return AMD_AGS_VERSION_5_4_1; } -static enum amd_ags_version determine_ags_version(void) +static enum amd_ags_version determine_ags_version(int ags_version) { /* AMD AGS is not binary compatible between versions (even minor versions), and the game * does not request a specific version when calling agsInit(). @@ -284,6 +284,11 @@ static enum amd_ags_version determine_ags_version(void) UINT16 major, minor, patch; WCHAR dllname[MAX_PATH], temp_path[MAX_PATH], temp_name[MAX_PATH]; + TRACE("ags_version %#x.\n", ags_version); + + if (ags_version) + return get_version_number(ags_version); + *temp_name = 0; if (!(infosize = GetModuleFileNameW(GetModuleHandleW(L"amd_ags_x64.dll"), dllname, ARRAY_SIZE(dllname))) || infosize == ARRAY_SIZE(dllname)) @@ -581,7 +586,7 @@ static void init_device_displays_511(const char *adapter_name, AGSDisplayInfo_51 } -static AGSReturnCode init_ags_context(AGSContext *context) +static AGSReturnCode init_ags_context(AGSContext *context, int ags_version) { AGSReturnCode ret; unsigned int i, j; @@ -589,7 +594,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) memset(context, 0, sizeof(*context)); - context->version = determine_ags_version(); + context->version = determine_ags_version(ags_version); ret = vk_get_physical_device_properties(&context->device_count, &context->properties, &context->memory_properties); if (ret != AGS_SUCCESS || !context->device_count) @@ -690,7 +695,7 @@ AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *confi if (!(object = heap_alloc(sizeof(*object)))) return AGS_OUT_OF_MEMORY; - if ((ret = init_ags_context(object)) != AGS_SUCCESS) + if ((ret = init_ags_context(object, 0)) != AGS_SUCCESS) { heap_free(object); return ret; @@ -728,7 +733,7 @@ AGSReturnCode WINAPI agsInitialize(int ags_version, const AGSConfiguration *conf if (!(object = heap_alloc(sizeof(*object)))) return AGS_OUT_OF_MEMORY; - if ((ret = init_ags_context(object)) != AGS_SUCCESS) + if ((ret = init_ags_context(object, ags_version)) != AGS_SUCCESS) { heap_free(object); return ret; @@ -1051,7 +1056,7 @@ AGSDriverVersionResult WINAPI agsCheckDriverVersion(const char* version_reported int WINAPI agsGetVersionNumber(void) { - enum amd_ags_version version = determine_ags_version(); + enum amd_ags_version version = determine_ags_version(0); TRACE("version %d.\n", version); From 7f2e6bc27710c80cf33b86de2d809cf1cd026221 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 9 Nov 2023 16:57:24 -0600 Subject: [PATCH 2735/2777] amd_ags_x64: Factor out get_ags_version_from_resource(). CW-Bug-Id: #22976 --- dlls/amd_ags_x64/amd_ags_x64_main.c | 90 ++++++++++++++++------------- 1 file changed, 50 insertions(+), 40 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 1d31494b986..c2a94703285 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -265,6 +265,52 @@ static enum amd_ags_version get_version_number(int ags_version) return AMD_AGS_VERSION_5_4_1; } +static BOOL get_ags_version_from_resource(const WCHAR *filename, enum amd_ags_version *ret) +{ + DWORD infosize; + void *infobuf; + void *val; + UINT vallen; + VS_FIXEDFILEINFO *info; + UINT16 major, minor, patch; + + infosize = GetFileVersionInfoSizeW(filename, NULL); + if (!infosize) + { + ERR("File version info not found, err %u.\n", GetLastError()); + return FALSE; + } + + if (!(infobuf = heap_alloc(infosize))) + { + ERR("Failed to allocate memory.\n"); + return FALSE; + } + + if (!GetFileVersionInfoW(filename, 0, infosize, infobuf)) + { + ERR("GetFileVersionInfoW failed, err %u.\n", GetLastError()); + heap_free(infobuf); + return FALSE; + } + + if (!VerQueryValueW(infobuf, L"\\", &val, &vallen) || (vallen != sizeof(VS_FIXEDFILEINFO))) + { + ERR("Version value not found, err %u.\n", GetLastError()); + heap_free(infobuf); + return FALSE; + } + + info = val; + major = info->dwFileVersionMS >> 16; + minor = info->dwFileVersionMS; + patch = info->dwFileVersionLS >> 16; + TRACE("Found amd_ags_x64.dll v%d.%d.%d\n", major, minor, patch); + *ret = get_version_number(AGS_MAKE_VERSION(major, minor, patch)); + heap_free(infobuf); + return TRUE; +} + static enum amd_ags_version determine_ags_version(int ags_version) { /* AMD AGS is not binary compatible between versions (even minor versions), and the game @@ -276,13 +322,8 @@ static enum amd_ags_version determine_ags_version(int ags_version) * In case of an error, assume it's that version. */ enum amd_ags_version ret = AMD_AGS_VERSION_5_4_1; - DWORD infosize; - void *infobuf = NULL; - void *val; - UINT vallen; - VS_FIXEDFILEINFO *info; - UINT16 major, minor, patch; WCHAR dllname[MAX_PATH], temp_path[MAX_PATH], temp_name[MAX_PATH]; + DWORD size; TRACE("ags_version %#x.\n", ags_version); @@ -290,8 +331,8 @@ static enum amd_ags_version determine_ags_version(int ags_version) return get_version_number(ags_version); *temp_name = 0; - if (!(infosize = GetModuleFileNameW(GetModuleHandleW(L"amd_ags_x64.dll"), dllname, ARRAY_SIZE(dllname))) - || infosize == ARRAY_SIZE(dllname)) + if (!(size = GetModuleFileNameW(GetModuleHandleW(L"amd_ags_x64.dll"), dllname, ARRAY_SIZE(dllname))) + || size == ARRAY_SIZE(dllname)) { ERR("GetModuleFileNameW failed.\n"); goto done; @@ -307,43 +348,12 @@ static enum amd_ags_version determine_ags_version(int ags_version) goto done; } - infosize = GetFileVersionInfoSizeW(temp_name, NULL); - if (!infosize) - { - ERR("Unable to determine desired version of amd_ags_x64.dll.\n"); - goto done; - } - - if (!(infobuf = heap_alloc(infosize))) - { - ERR("Failed to allocate memory.\n"); - goto done; - } - - if (!GetFileVersionInfoW(temp_name, 0, infosize, infobuf)) - { - ERR("Unable to determine desired version of amd_ags_x64.dll.\n"); - goto done; - } - - if (!VerQueryValueW(infobuf, L"\\", &val, &vallen) || (vallen != sizeof(VS_FIXEDFILEINFO))) - { - ERR("Unable to determine desired version of amd_ags_x64.dll.\n"); - goto done; - } - - info = val; - major = info->dwFileVersionMS >> 16; - minor = info->dwFileVersionMS; - patch = info->dwFileVersionLS >> 16; - TRACE("Found amd_ags_x64.dll v%d.%d.%d\n", major, minor, patch); - ret = get_version_number(AGS_MAKE_VERSION(major, minor, patch)); + get_ags_version_from_resource(temp_name, &ret); done: if (*temp_name) DeleteFileW(temp_name); - heap_free(infobuf); TRACE("Using AGS v%d.%d.%d interface\n", amd_ags_info[ret].major, amd_ags_info[ret].minor, amd_ags_info[ret].patch); return ret; From fa07dce0be65031d07fe3a5034b064ba42ad6046 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 9 Nov 2023 17:08:32 -0600 Subject: [PATCH 2736/2777] amd_ags_x64: Try to get version from agsGetVersionNumber() if there is no version resource. CW-Bug-Id: #22976 --- dlls/amd_ags_x64/amd_ags_x64_main.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index c2a94703285..c51ec4b2507 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -323,6 +323,8 @@ static enum amd_ags_version determine_ags_version(int ags_version) */ enum amd_ags_version ret = AMD_AGS_VERSION_5_4_1; WCHAR dllname[MAX_PATH], temp_path[MAX_PATH], temp_name[MAX_PATH]; + int (WINAPI *pagsGetVersionNumber)(void); + HMODULE hnative = NULL; DWORD size; TRACE("ags_version %#x.\n", ags_version); @@ -348,9 +350,26 @@ static enum amd_ags_version determine_ags_version(int ags_version) goto done; } - get_ags_version_from_resource(temp_name, &ret); + if (get_ags_version_from_resource(temp_name, &ret)) + goto done; + + if (!(hnative = LoadLibraryW(temp_name))) + { + ERR("LoadLibraryW failed for %s.\n", debugstr_w(temp_name)); + goto done; + } + + if ((pagsGetVersionNumber = (void *)GetProcAddress(hnative, "agsGetVersionNumber"))) + { + ags_version = pagsGetVersionNumber(); + ret = get_version_number(ags_version); + TRACE("Got version %#x (%d) from agsGetVersionNumber.\n", ags_version, ret); + } done: + if (hnative) + FreeLibrary(hnative); + if (*temp_name) DeleteFileW(temp_name); From 5b058903f7747a0dea6d7d0bc92131424a6003dc Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 9 Nov 2023 17:19:25 -0600 Subject: [PATCH 2737/2777] amd_ags_x64: Distinguish some versions through available exports if other methods failed. CW-Bug-Id: #22976 --- dlls/amd_ags_x64/amd_ags_x64_main.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index c51ec4b2507..ad1681b9abc 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -311,15 +311,29 @@ static BOOL get_ags_version_from_resource(const WCHAR *filename, enum amd_ags_ve return TRUE; } +static enum amd_ags_version guess_version_from_exports(HMODULE hnative) +{ + /* Known DLL versions without version info: + * - An update to AGS 5.4.1 included an amd_ags_x64.dll with no file version info; + * - CoD: Modern Warfare Remastered (2017) ships dll without version info which is version 5.0.1 + * (not tagged in AGSSDK history), compatible with 5.0.5. + */ + if (GetProcAddress(hnative, "agsDriverExtensionsDX11_Init")) + { + /* agsDriverExtensionsDX11_Init was deprecated in 5.3.0 */ + TRACE("agsDriverExtensionsDX11_Init found.\n"); + return AMD_AGS_VERSION_5_0_5; + } + TRACE("Returning 5.4.1.\n"); + return AMD_AGS_VERSION_5_4_1; +} + static enum amd_ags_version determine_ags_version(int ags_version) { /* AMD AGS is not binary compatible between versions (even minor versions), and the game * does not request a specific version when calling agsInit(). * Checking the version of amd_ags_x64.dll shipped with the game is the only way to * determine what version the game was built against. - * - * An update to AGS 5.4.1 included an amd_ags_x64.dll with no file version info. - * In case of an error, assume it's that version. */ enum amd_ags_version ret = AMD_AGS_VERSION_5_4_1; WCHAR dllname[MAX_PATH], temp_path[MAX_PATH], temp_name[MAX_PATH]; @@ -364,8 +378,11 @@ static enum amd_ags_version determine_ags_version(int ags_version) ags_version = pagsGetVersionNumber(); ret = get_version_number(ags_version); TRACE("Got version %#x (%d) from agsGetVersionNumber.\n", ags_version, ret); + goto done; } + ret = guess_version_from_exports(hnative); + done: if (hnative) FreeLibrary(hnative); From 4b9b6a471b4fd50734205329ba8b1797b1dd8bf5 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 9 Nov 2023 17:53:47 -0600 Subject: [PATCH 2738/2777] amd_ags_x64: Recognize version 6.2.0. CW-Bug-Id: #22976 --- dlls/amd_ags_x64/amd_ags.h | 14 ++++++++------ dlls/amd_ags_x64/amd_ags_x64_main.c | 12 +++++++----- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h index 52276cc1935..aac9fb1413c 100644 --- a/dlls/amd_ags_x64/amd_ags.h +++ b/dlls/amd_ags_x64/amd_ags.h @@ -207,7 +207,8 @@ typedef enum AGSReturnCode AGS_NO_AMD_DRIVER_INSTALLED, ///< Returned if the AMD GPU driver does not appear to be installed AGS_EXTENSION_NOT_SUPPORTED, ///< Returned if the driver does not support the requested driver extension AGS_ADL_FAILURE, ///< Failure in ADL (the AMD Display Library) - AGS_DX_FAILURE ///< Failure from DirectX runtime + AGS_DX_FAILURE, ///< Failure from DirectX runtime + AGS_D3DDEVICE_NOT_CREATED, ///< Failure due to not creating the D3D device successfully via AGS. } AGSReturnCode; /// The DirectX11 extension support bits @@ -268,7 +269,7 @@ typedef enum AGSDriverExtensionDX12 } AGSDriverExtensionDX12; /// The space id for DirectX12 intrinsic support -const unsigned int AGS_DX12_SHADER_INSTRINSICS_SPACE_ID = 0x7FFF0ADE; // 2147420894 +const unsigned int AGS_DX12_SHADER_INTRINSICS_SPACE_ID = 0x7FFF0ADE; // 2147420894 /// The display flags describing various properties of the display. typedef enum AGSDisplayFlags @@ -942,7 +943,8 @@ typedef struct AGSDX12ReturnedParams unsigned int floatConversion : 1; ///< Supported in Radeon Software Version 20.5.1 onwards. unsigned int readLaneAt : 1; ///< Supported in Radeon Software Version 20.11.2 onwards. unsigned int rayHitToken : 1; ///< Supported in Radeon Software Version 20.11.2 onwards. - unsigned int padding : 20; ///< Reserved + unsigned int shaderClock : 1; ///< Supported in Radeon Software Version 23.1.1 onwards. + unsigned int padding : 19; ///< Reserved } ExtensionsSupported; ExtensionsSupported extensionsSupported; ///< List of supported extensions */ @@ -960,16 +962,16 @@ typedef struct AGSDX12ReturnedParams /// * The intrinsic instructions require a 5.1 shader model. /// * The Root Signature will need to reserve an extra UAV resource slot. This is not a real resource that requires allocating, it is just used to encode the intrinsic instructions. /// -/// The easiest way to set up the reserved UAV slot is to specify it at u0. The register space id will automatically be assumed to be \ref AGS_DX12_SHADER_INSTRINSICS_SPACE_ID. +/// The easiest way to set up the reserved UAV slot is to specify it at u0. The register space id will automatically be assumed to be \ref AGS_DX12_SHADER_INTRINSICS_SPACE_ID. /// The HLSL expects this as default and the set up code would look similar to this: /// \code{.cpp} /// CD3DX12_DESCRIPTOR_RANGE range[]; /// ... -/// range[ 0 ].Init( D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0, AGS_DX12_SHADER_INSTRINSICS_SPACE_ID ); // u0 at driver-reserved space id +/// range[ 0 ].Init( D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0, AGS_DX12_SHADER_INTRINSICS_SPACE_ID ); // u0 at driver-reserved space id /// \endcode /// /// Newer drivers also support a user-specified slot in which case the register space id is assumed to be 0. It is important that the \ref AGSDX12ReturnedParams::ExtensionsSupported::UAVBindSlot bit is set. -/// to ensure the driver can support this. If not, then u0 and \ref AGS_DX12_SHADER_INSTRINSICS_SPACE_ID must be used. +/// to ensure the driver can support this. If not, then u0 and \ref AGS_DX12_SHADER_INTRINSICS_SPACE_ID must be used. /// If the driver does support this feature and a non zero slot is required, then the HLSL must also define AMD_EXT_SHADER_INTRINSIC_UAV_OVERRIDE as the matching slot value. /// /// \param [in] context Pointer to a context. This is generated by \ref agsInitialize diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index ad1681b9abc..154e74cf1d6 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -39,6 +39,7 @@ enum amd_ags_version AMD_AGS_VERSION_6_0_0, AMD_AGS_VERSION_6_0_1, AMD_AGS_VERSION_6_1_0, + AMD_AGS_VERSION_6_2_0, AMD_AGS_VERSION_COUNT }; @@ -64,27 +65,28 @@ amd_ags_info[AMD_AGS_VERSION_COUNT] = {6, 0, 0, sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600)}, {6, 0, 1, sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600)}, {6, 1, 0, sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600)}, + {6, 2, 0, sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600)}, }; #define DEF_FIELD(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name), \ - offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name)}} + offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name)}} #define DEF_FIELD_520_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), -1, \ - -1, -1, -1, -1, -1}} + -1, -1, -1, -1, -1, -1}} #define DEF_FIELD_540_UP(name) {DEVICE_FIELD_##name, {-1, -1, -1, \ -1, -1, offsetof(AGSDeviceInfo_540, name), \ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name), \ - offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name)}} + offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name)}} #define DEF_FIELD_540_600(name) {DEVICE_FIELD_##name, {-1, -1, -1, \ -1, -1, offsetof(AGSDeviceInfo_540, name), \ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), \ - -1, -1, -1}} + -1, -1, -1, -1}} #define DEF_FIELD_600_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), -1, \ - -1, -1}} + -1, -1, -1}} #define DEVICE_FIELD_adapterString 0 #define DEVICE_FIELD_architectureVersion 1 From fc98a09ed758c6947436bb5a084ace1f337d0c0c Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Mon, 14 Aug 2023 17:17:05 +0800 Subject: [PATCH 2739/2777] winex11.drv: Set _NET_WM_FULLSCREEN_MONITORS only when necessary. If _NET_WM_FULLSCREEN_MONITORS is set then the property needs to be updated because it can't be deleted by sending a _NET_WM_FULLSCREEN_MONITORS client message to the root window according to the wm-spec version 1.4. Having the window spanning more than two monitors also needs the property set. In other cases, _NET_WM_FULLSCREEN_MONITORS doesn't need to be set. What's more, setting _NET_WM_FULLSCREEN_MONITORS adds a constraint on Mutter so that such a window can't be moved to another monitor by using the Shift+Super+Up/Down/Left/Right shortcut. So the property should be added only when necessary. CW-Bug-Id: #22540 --- dlls/winex11.drv/window.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 4aa9878ad76..a65fa46cde9 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1216,6 +1216,38 @@ static void update_net_wm_fullscreen_monitors( struct x11drv_win_data *data ) return; } + /* If _NET_WM_FULLSCREEN_MONITORS is not set and the fullscreen monitors are spanning only one + * monitor then do not set _NET_WM_FULLSCREEN_MONITORS. + * + * If _NET_WM_FULLSCREEN_MONITORS is set then the property needs to be updated because it can't + * be deleted by sending a _NET_WM_FULLSCREEN_MONITORS client message to the root window + * according to the wm-spec version 1.4. Having the window spanning more than two monitors also + * needs the property set. In other cases, _NET_WM_FULLSCREEN_MONITORS doesn't need to be set. + * What's more, setting _NET_WM_FULLSCREEN_MONITORS adds a constraint on Mutter so that such a + * window can't be moved to another monitor by using the Shift+Super+Up/Down/Left/Right + * shortcut. So the property should be added only when necessary. */ + if (monitors[0] == monitors[1] && monitors[1] == monitors[2] && monitors[2] == monitors[3]) + { + unsigned long count, remaining; + BOOL prop_found = FALSE; + long *prop_data; + int format; + Atom type; + + if (!XGetWindowProperty( data->display, data->whole_window, + x11drv_atom(_NET_WM_FULLSCREEN_MONITORS), 0, ~0, False, + XA_CARDINAL, &type, &format, &count, &remaining, + (unsigned char **)&prop_data )) + { + if (type == XA_CARDINAL && format == 32 && count == 4) + prop_found = TRUE; + XFree(prop_data); + } + + if (!prop_found) + return; + } + if (!data->mapped) { XChangeProperty( data->display, data->whole_window, x11drv_atom(_NET_WM_FULLSCREEN_MONITORS), From 793404ff4dcc709f5597bd6d3bc0aaae4c8a4a51 Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Tue, 22 Aug 2023 15:26:05 +0800 Subject: [PATCH 2740/2777] fixup! fshack: winex11: Implement _NET_FULLSCREEN_MONITOR support. Obviously, xinerama_get_fullscreen_monitors() won't be able to find multiple monitors with a single monitor rectangle from fs_hack_real_mode(). Fix a regression from 01dad2c92a56e141225a992ba09599c444e4a586. Restore Project Cars 3 triple-monitor support. CW-Bug-Id: #22609 --- dlls/winex11.drv/window.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index a65fa46cde9..46411d9dba3 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1180,8 +1180,6 @@ void update_user_time( Time time ) * windows spanning multiple monitors */ static void update_net_wm_fullscreen_monitors( struct x11drv_win_data *data ) { - RECT window_rect = data->whole_rect, monitor_rect; - HMONITOR hmonitor; long monitors[4]; XEvent xev; @@ -1194,25 +1192,9 @@ static void update_net_wm_fullscreen_monitors( struct x11drv_win_data *data ) if (!X11DRV_DisplayDevices_SupportEventHandlers()) return; - if (!(hmonitor = fs_hack_monitor_from_hwnd( data->hwnd ))) + if (!xinerama_get_fullscreen_monitors( &data->whole_rect, monitors )) { - ERR( "Failed to find monitor for %p at %s\n", data->hwnd, wine_dbgstr_rect(&data->whole_rect) ); - return; - } - - monitor_rect = fs_hack_current_mode( hmonitor ); - intersect_rect( &window_rect, &monitor_rect, &window_rect ); - if (!EqualRect( &window_rect, &data->whole_rect )) - { - ERR( "hwnd %p at %s is outside of monitor %p at %s, ignoring\n", data->hwnd, - wine_dbgstr_rect(&data->whole_rect), hmonitor, wine_dbgstr_rect(&monitor_rect) ); - return; - } - - monitor_rect = fs_hack_real_mode( hmonitor ); - if (!xinerama_get_fullscreen_monitors( &monitor_rect, monitors )) - { - ERR( "Failed to find xinerama monitors for %p at %s\n", hmonitor, wine_dbgstr_rect(&monitor_rect) ); + ERR( "Failed to find xinerama monitors at %s\n", wine_dbgstr_rect(&data->whole_rect) ); return; } From a351a90e3927f0bf9eff70f5a49ccd8556f4435f Mon Sep 17 00:00:00 2001 From: Zhiyi Zhang Date: Sat, 4 Nov 2023 16:09:02 +0800 Subject: [PATCH 2741/2777] fshack: winex11.drv: Use fs_hack_monitor_from_rect() in X11DRV_ShowWindow(). fs_hack_monitor_from_hwnd() returns the primary monitor when the window is minimized. So a fullscreen window on the secondary monitor that later gets minimized may be moved to the primary monitor when fs_hack_monitor_from_hwnd() returns the primary monitor. Instead, we should use fs_hack_monitor_from_rect() and use the updated window rectangle to retrieve the monitor a window should be fullscreen on. fs_hack_monitor_from_hwnd() should only be used when not expecting window position changes. --- dlls/winex11.drv/window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 46411d9dba3..ffcd91cc1db 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -3410,7 +3410,7 @@ UINT X11DRV_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp ) &root, &x, &y, &width, &height, &border, &depth ); XTranslateCoordinates( thread_data->display, data->whole_window, root, 0, 0, &x, &y, &top ); pos = root_to_virtual_screen( x, y ); - monitor = fs_hack_monitor_from_hwnd( hwnd ); + monitor = fs_hack_monitor_from_rect( rect ); if (data->fs_hack || (fs_hack_enabled( monitor ) && fs_hack_matches_current_mode( monitor, rect->right - rect->left, rect->bottom - rect->top ))) From 1d2deeeccf3113a57c8815c1639fce3b64954806 Mon Sep 17 00:00:00 2001 From: Santino Mazza Date: Tue, 29 Aug 2023 13:33:32 -0300 Subject: [PATCH 2742/2777] mf: Handle errors with source event generator in session. (cherry picked from commit 0170cd3a4c67bd99291234dd8e0d638a824d7715) --- dlls/mf/session.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 2b7b4361c61..837782f829a 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -3691,7 +3691,9 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM if (FAILED(hr = IMFMediaEventGenerator_EndGetEvent(event_source, result, &event))) { WARN("Failed to get event from %p, hr %#lx.\n", event_source, hr); - goto failed; + IMFMediaEventQueue_QueueEventParamVar(session->event_queue, MEError, &GUID_NULL, hr, NULL); + IMFMediaEventGenerator_Release(event_source); + return hr; } if (FAILED(hr = IMFMediaEvent_GetType(event, &event_type))) @@ -3884,11 +3886,15 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM PropVariantClear(&value); failed: - if (event) - IMFMediaEvent_Release(event); if (FAILED(hr = IMFMediaEventGenerator_BeginGetEvent(event_source, iface, (IUnknown *)event_source))) + { WARN("Failed to re-subscribe, hr %#lx.\n", hr); + IMFMediaEventQueue_QueueEvent(session->event_queue, event); + } + + if (event) + IMFMediaEvent_Release(event); IMFMediaEventGenerator_Release(event_source); From 15815c8c55cf79e8b7d538889062f523c2f229df Mon Sep 17 00:00:00 2001 From: Santino Mazza Date: Tue, 31 Oct 2023 20:44:53 -0300 Subject: [PATCH 2743/2777] mf: Signal event_cond in wg_parser_stream_disable. A workaround to fix a hang in media_source_Shutdown in old media source, because the wg_parser receives an EOS signal after media_source_Shutdown disabled the streams, and event_cond never gets signaled so it never stops being busy. --- 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 3e5afe49bf0..456112affe7 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -243,6 +243,7 @@ static NTSTATUS wg_parser_stream_disable(void *args) stream->enabled = false; stream->current_format.major_type = WG_MAJOR_TYPE_UNKNOWN; pthread_mutex_unlock(&parser->mutex); + pthread_cond_signal(&stream->event_cond); pthread_cond_signal(&stream->event_empty_cond); return S_OK; } From 0ebbd573f302708010d954330d24a0149b106e18 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 8 Nov 2023 13:36:20 -0600 Subject: [PATCH 2744/2777] winex11.drv: Don't call XIconifyWindow() on Gamescope. CW-Bug-Id: #22953 --- dlls/winex11.drv/window.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index ffcd91cc1db..fab1cd93879 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1450,7 +1450,7 @@ static void map_window( HWND hwnd, DWORD new_style ) sync_window_style( data ); XMapWindow( data->display, data->whole_window ); /* Mutter always unminimizes windows when handling map requests. Restore iconic state */ - if (new_style & WS_MINIMIZE) + if (new_style & WS_MINIMIZE && !wm_is_steamcompmgr( data->display )) XIconifyWindow( data->display, data->whole_window, data->vis.screen ); XFlush( data->display ); if (data->surface && data->vis.visualid != default_visual.visualid) @@ -3319,7 +3319,16 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, TRACE( "changing win %p iconic state to %u\n", data->hwnd, data->iconic ); if (data->iconic) { - XIconifyWindow( data->display, data->whole_window, data->vis.screen ); + if (!wm_is_steamcompmgr( data->display )) + { + /* XIconifyWindow is essentially a no-op on Gamescope but has an undesirable side effect. + * Gamescope handles wm state change to iconic and immediately changes it back to normal. + * Upon that change back we would receive WM_STATE change notification and kick the window + * out of minimized state even if the window is not focused by Gamescope. Upon focusing the + * window Gamescope will change WM_STATE regardless and we will get the window out of + * minimized state correctly. */ + XIconifyWindow( data->display, data->whole_window, data->vis.screen ); + } } else if (is_window_rect_mapped( rectWindow )) { From 96bec82e3b819bd65bd32a53f053e9c0ea1aa1e8 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 15 Nov 2023 19:03:11 -0600 Subject: [PATCH 2745/2777] win32u: Store effective AA flags in gdi_font. CW-Bug-Id: #22992 --- dlls/win32u/font.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/win32u/font.c b/dlls/win32u/font.c index d079c41f35a..8d2a44abbfd 100644 --- a/dlls/win32u/font.c +++ b/dlls/win32u/font.c @@ -4689,6 +4689,7 @@ static HFONT CDECL font_SelectFont( PHYSDEV dev, HFONT hfont, UINT *aa_flags ) *aa_flags = font_smoothing; } *aa_flags = font_funcs->get_aa_flags( font, *aa_flags, antialias_fakes ); + font->aa_flags = *aa_flags; } TRACE( "%p %s %d aa %x\n", hfont, debugstr_w(lf.lfFaceName), (int)lf.lfHeight, *aa_flags ); pthread_mutex_unlock( &font_lock ); From 47cf83e0446074c9f83076013080bc391fa8ee69 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 15 Nov 2023 21:37:09 -0600 Subject: [PATCH 2746/2777] win32u: Set all glyph load flags in get_load_flags(). CW-Bug-Id: #22992 --- dlls/win32u/freetype.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/dlls/win32u/freetype.c b/dlls/win32u/freetype.c index 416927c3a67..e0dd8aaf03d 100644 --- a/dlls/win32u/freetype.c +++ b/dlls/win32u/freetype.c @@ -3418,10 +3418,13 @@ static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int b return needed; } -static FT_Int get_load_flags( UINT format ) +static FT_Int get_load_flags( UINT format, BOOL vertical_metrics, BOOL force_no_bitmap ) { FT_Int load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; + if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT; + if (force_no_bitmap || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP; + if (format & GGO_UNHINTED) return load_flags | FT_LOAD_NO_HINTING; @@ -3461,7 +3464,7 @@ static UINT freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT FT_Glyph_Metrics metrics; FT_Error err; FT_BBox bbox; - FT_Int load_flags = get_load_flags(format); + FT_Int load_flags; FT_Matrix transform_matrices[3], *matrices = NULL; BOOL vertical_metrics; @@ -3471,8 +3474,6 @@ static UINT freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT font->matrix.eM11, font->matrix.eM12, font->matrix.eM21, font->matrix.eM22); - format &= ~GGO_UNHINTED; - matrices = get_transform_matrices( font, tategaki, lpmat, transform_matrices ); vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face)); @@ -3480,9 +3481,7 @@ static UINT freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT properly scaled and correct in 2.4.0 or greater */ if (vertical_metrics && FT_SimpleVersion < FT_VERSION_VALUE(2, 4, 0)) vertical_metrics = FALSE; - - if (matrices || format != GGO_BITMAP) load_flags |= FT_LOAD_NO_BITMAP; - if (vertical_metrics) load_flags |= FT_LOAD_VERTICAL_LAYOUT; + load_flags = get_load_flags(format, vertical_metrics, !!matrices); err = pFT_Load_Glyph(ft_face, glyph, load_flags); if (err && !(load_flags & FT_LOAD_NO_HINTING)) @@ -3497,6 +3496,8 @@ static UINT freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT return GDI_ERROR; } + format &= ~GGO_UNHINTED; + metrics = ft_face->glyph->metrics; if(font->fake_bold) { if (!get_bold_glyph_outline(ft_face->glyph, font->ppem, &metrics) && metrics.width) From 61198d90ab21a583074bda3b31a8c244886dc3f6 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 15 Nov 2023 21:30:12 -0600 Subject: [PATCH 2747/2777] win32u: Use font AA flags when querying glyph outline with GGO_METRICS. CW-Bug-Id: #22992 --- dlls/win32u/freetype.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/freetype.c b/dlls/win32u/freetype.c index e0dd8aaf03d..2c8249e9c1f 100644 --- a/dlls/win32u/freetype.c +++ b/dlls/win32u/freetype.c @@ -3467,6 +3467,7 @@ static UINT freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT FT_Int load_flags; FT_Matrix transform_matrices[3], *matrices = NULL; BOOL vertical_metrics; + UINT effective_format = format; TRACE("%p, %04x, %08x, %p, %08x, %p, %p\n", font, glyph, format, lpgm, buflen, buf, lpmat); @@ -3476,14 +3477,22 @@ static UINT freetype_get_glyph_outline( struct gdi_font *font, UINT glyph, UINT matrices = get_transform_matrices( font, tategaki, lpmat, transform_matrices ); + if ((format & ~GGO_GLYPH_INDEX) == GGO_METRICS) + effective_format = font->aa_flags | (format & GGO_GLYPH_INDEX); vertical_metrics = (tategaki && FT_HAS_VERTICAL(ft_face)); /* there is a freetype bug where vertical metrics are only properly scaled and correct in 2.4.0 or greater */ if (vertical_metrics && FT_SimpleVersion < FT_VERSION_VALUE(2, 4, 0)) vertical_metrics = FALSE; - load_flags = get_load_flags(format, vertical_metrics, !!matrices); + load_flags = get_load_flags(effective_format, vertical_metrics, !!matrices); err = pFT_Load_Glyph(ft_face, glyph, load_flags); + if (err && format != effective_format) + { + WARN("Failed to load glyph %#x, retrying with GGO_METRICS. Error %#x.\n", glyph, err); + load_flags = get_load_flags(effective_format, vertical_metrics, !!matrices); + err = pFT_Load_Glyph(ft_face, glyph, load_flags); + } if (err && !(load_flags & FT_LOAD_NO_HINTING)) { WARN("Failed to load glyph %#x, retrying without hinting. Error %#x.\n", glyph, err); From bf2a7bc93b727f0138aceaab99ebb2fa558a3fd6 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 16 Nov 2023 17:23:07 -0600 Subject: [PATCH 2748/2777] Revert "dsound: Get rid of the global device GUID arrays." This reverts commit 39b8fe1a353b715c1d580fe0334257846a744005. CW-Bug-Id: #23002 --- dlls/dsound/dsound_main.c | 31 ++++++++++++++++++++----------- dlls/dsound/dsound_private.h | 5 ++++- dlls/dsound/propset.c | 12 ++++++++---- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/dlls/dsound/dsound_main.c b/dlls/dsound/dsound_main.c index d18733294d0..3347f0243ab 100644 --- a/dlls/dsound/dsound_main.c +++ b/dlls/dsound/dsound_main.c @@ -76,6 +76,9 @@ static CRITICAL_SECTION_DEBUG DSOUND_renderers_lock_debug = }; CRITICAL_SECTION DSOUND_renderers_lock = { &DSOUND_renderers_lock_debug, -1, 0, 0, 0, 0 }; +GUID DSOUND_renderer_guids[MAXWAVEDRIVERS]; +GUID DSOUND_capture_guids[MAXWAVEDRIVERS]; + const WCHAR wine_vxd_drv[] = L"winemm.vxd"; /* All default settings, you most likely don't want to touch these, see wiki on UsefulRegistryKeys */ @@ -388,13 +391,13 @@ HRESULT get_mmdevice(EDataFlow flow, const GUID *tgt, IMMDevice **device) return DSERR_INVALIDPARAM; } -static BOOL send_device(IMMDevice *device, LPDSENUMCALLBACKW cb, void *user) +static BOOL send_device(IMMDevice *device, GUID *guid, + LPDSENUMCALLBACKW cb, void *user) { IPropertyStore *ps; PROPVARIANT pv; BOOL keep_going; HRESULT hr; - GUID guid; PropVariantInit(&pv); @@ -404,7 +407,7 @@ static BOOL send_device(IMMDevice *device, LPDSENUMCALLBACKW cb, void *user) return TRUE; } - hr = get_mmdevice_guid(device, ps, &guid); + hr = get_mmdevice_guid(device, ps, guid); if(FAILED(hr)){ IPropertyStore_Release(ps); return TRUE; @@ -418,10 +421,10 @@ static BOOL send_device(IMMDevice *device, LPDSENUMCALLBACKW cb, void *user) return TRUE; } - TRACE("Calling back with %s (%s)\n", wine_dbgstr_guid(&guid), + TRACE("Calling back with %s (%s)\n", wine_dbgstr_guid(guid), wine_dbgstr_w(pv.pwszVal)); - keep_going = cb(&guid, pv.pwszVal, wine_vxd_drv, user); + keep_going = cb(guid, pv.pwszVal, wine_vxd_drv, user); PropVariantClear(&pv); IPropertyStore_Release(ps); @@ -431,12 +434,13 @@ static BOOL send_device(IMMDevice *device, LPDSENUMCALLBACKW cb, void *user) /* S_FALSE means the callback returned FALSE at some point * S_OK means the callback always returned TRUE */ -HRESULT enumerate_mmdevices(EDataFlow flow, LPDSENUMCALLBACKW cb, void *user) +HRESULT enumerate_mmdevices(EDataFlow flow, GUID *guids, + LPDSENUMCALLBACKW cb, void *user) { IMMDeviceEnumerator *devenum; IMMDeviceCollection *coll; IMMDevice *defdev = NULL; - UINT count, i; + UINT count, i, n; BOOL keep_going; HRESULT hr, init_hr; @@ -475,8 +479,10 @@ HRESULT enumerate_mmdevices(EDataFlow flow, LPDSENUMCALLBACKW cb, void *user) eMultimedia, &defdev); if(FAILED(hr)){ defdev = NULL; + n = 0; }else{ - keep_going = send_device(defdev, cb, user); + keep_going = send_device(defdev, &guids[0], cb, user); + n = 1; } } @@ -490,7 +496,8 @@ HRESULT enumerate_mmdevices(EDataFlow flow, LPDSENUMCALLBACKW cb, void *user) } if(device != defdev){ - keep_going = send_device(device, cb, user); + keep_going = send_device(device, &guids[n], cb, user); + ++n; } IMMDevice_Release(device); @@ -533,7 +540,8 @@ HRESULT WINAPI DirectSoundEnumerateW( setup_dsound_options(); - hr = enumerate_mmdevices(eRender, lpDSEnumCallback, lpContext); + hr = enumerate_mmdevices(eRender, DSOUND_renderer_guids, + lpDSEnumCallback, lpContext); return SUCCEEDED(hr) ? DS_OK : hr; } @@ -596,7 +604,8 @@ DirectSoundCaptureEnumerateW( setup_dsound_options(); - hr = enumerate_mmdevices(eCapture, lpDSEnumCallback, lpContext); + hr = enumerate_mmdevices(eCapture, DSOUND_capture_guids, + lpDSEnumCallback, lpContext); return SUCCEEDED(hr) ? DS_OK : hr; } diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index 081a56b2ee7..09fa219ecca 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -254,6 +254,8 @@ HRESULT IDirectSoundCaptureImpl_Create(IUnknown *outer_unk, REFIID riid, void ** extern CRITICAL_SECTION DSOUND_renderers_lock DECLSPEC_HIDDEN; extern struct list DSOUND_renderers DECLSPEC_HIDDEN; +extern GUID DSOUND_renderer_guids[MAXWAVEDRIVERS] DECLSPEC_HIDDEN; +extern GUID DSOUND_capture_guids[MAXWAVEDRIVERS] DECLSPEC_HIDDEN; extern const WCHAR wine_vxd_drv[] DECLSPEC_HIDDEN; @@ -263,7 +265,8 @@ HRESULT get_mmdevice(EDataFlow flow, const GUID *tgt, IMMDevice **device) DECLSP BOOL DSOUND_check_supported(IAudioClient *client, DWORD rate, DWORD depth, WORD channels) DECLSPEC_HIDDEN; -HRESULT enumerate_mmdevices(EDataFlow flow, LPDSENUMCALLBACKW cb, void *user) DECLSPEC_HIDDEN; +HRESULT enumerate_mmdevices(EDataFlow flow, GUID *guids, + LPDSENUMCALLBACKW cb, void *user) DECLSPEC_HIDDEN; static inline WCHAR *strdupW( const WCHAR *str ) { diff --git a/dlls/dsound/propset.c b/dlls/dsound/propset.c index e72757bdb4b..f42cfbf4163 100644 --- a/dlls/dsound/propset.c +++ b/dlls/dsound/propset.c @@ -136,9 +136,11 @@ static HRESULT DSPROPERTY_WaveDeviceMappingW( search.found_guid = &ppd->DeviceId; if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER) - hr = enumerate_mmdevices(eRender, search_callback, &search); + hr = enumerate_mmdevices(eRender, DSOUND_renderer_guids, + search_callback, &search); else if (ppd->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE) - hr = enumerate_mmdevices(eCapture, search_callback, &search); + hr = enumerate_mmdevices(eCapture, DSOUND_capture_guids, + search_callback, &search); else return DSERR_INVALIDPARAM; @@ -316,10 +318,12 @@ static HRESULT DSPROPERTY_EnumerateW( return E_PROP_ID_UNSUPPORTED; } - hr = enumerate_mmdevices(eRender, enum_callback, ppd); + hr = enumerate_mmdevices(eRender, DSOUND_renderer_guids, + enum_callback, ppd); if(hr == S_OK) - hr = enumerate_mmdevices(eCapture, enum_callback, ppd); + hr = enumerate_mmdevices(eCapture, DSOUND_capture_guids, + enum_callback, ppd); return SUCCEEDED(hr) ? DS_OK : hr; } From 8cb26d47157232e2ac4cc637d5a12b458055099a Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Thu, 19 Oct 2023 22:39:07 -0600 Subject: [PATCH 2749/2777] dsound: Dynamically allocate the global device GUID arrays. This removes the arbitrary limit on the number of renderers and capturers while satisfying applications that expect the GUIDs to remain valid after DirectSoundCaptureEnumerate returns. (cherry picked from commit 5a81b6ac43e1057c0c6f9953fd5cbb1bc5d0f11bi) CW-Bug-Id: #23002 --- dlls/dsound/dsound_main.c | 15 +++++++++++++-- dlls/dsound/dsound_private.h | 4 ++-- include/mmsystem.h | 6 ------ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/dlls/dsound/dsound_main.c b/dlls/dsound/dsound_main.c index 3347f0243ab..0f566139a65 100644 --- a/dlls/dsound/dsound_main.c +++ b/dlls/dsound/dsound_main.c @@ -76,8 +76,11 @@ static CRITICAL_SECTION_DEBUG DSOUND_renderers_lock_debug = }; CRITICAL_SECTION DSOUND_renderers_lock = { &DSOUND_renderers_lock_debug, -1, 0, 0, 0, 0 }; -GUID DSOUND_renderer_guids[MAXWAVEDRIVERS]; -GUID DSOUND_capture_guids[MAXWAVEDRIVERS]; +/* Some applications expect the GUID pointers emitted from DirectSoundCaptureEnumerate to remain + * valid at least until the next time DirectSoundCaptureEnumerate is called, so we store them in + * these dynamically allocated arrays. */ +GUID *DSOUND_renderer_guids; +GUID *DSOUND_capture_guids; const WCHAR wine_vxd_drv[] = L"winemm.vxd"; @@ -464,11 +467,19 @@ HRESULT enumerate_mmdevices(EDataFlow flow, GUID *guids, return DS_OK; } + free(guids); if(count == 0){ IMMDeviceCollection_Release(coll); release_mmdevenum(devenum, init_hr); + guids = NULL; return DS_OK; } + guids = malloc((count + 1) * sizeof(GUID)); + if(!guids){ + IMMDeviceCollection_Release(coll); + release_mmdevenum(devenum, init_hr); + return E_OUTOFMEMORY; + } TRACE("Calling back with NULL (Primary Sound Driver)\n"); keep_going = cb(NULL, L"Primary Sound Driver", L"", user); diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index 09fa219ecca..6f8051f6f25 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -254,8 +254,8 @@ HRESULT IDirectSoundCaptureImpl_Create(IUnknown *outer_unk, REFIID riid, void ** extern CRITICAL_SECTION DSOUND_renderers_lock DECLSPEC_HIDDEN; extern struct list DSOUND_renderers DECLSPEC_HIDDEN; -extern GUID DSOUND_renderer_guids[MAXWAVEDRIVERS] DECLSPEC_HIDDEN; -extern GUID DSOUND_capture_guids[MAXWAVEDRIVERS] DECLSPEC_HIDDEN; +extern GUID *DSOUND_renderer_guids; +extern GUID *DSOUND_capture_guids; extern const WCHAR wine_vxd_drv[] DECLSPEC_HIDDEN; diff --git a/include/mmsystem.h b/include/mmsystem.h index 5684ff20683..04864cf5f63 100644 --- a/include/mmsystem.h +++ b/include/mmsystem.h @@ -54,12 +54,6 @@ typedef HWAVEOUT *LPHWAVEOUT; typedef LRESULT (CALLBACK *DRIVERPROC)(DWORD_PTR,HDRVR,UINT,LPARAM,LPARAM); -#define MAXWAVEDRIVERS 10 -#define MAXMIDIDRIVERS 10 -#define MAXAUXDRIVERS 10 -#define MAXMCIDRIVERS 32 -#define MAXMIXERDRIVERS 10 - #define MAXPNAMELEN 32 /* max product name length (including NULL) */ #define MAXERRORLENGTH 256 /* max error text length (including NULL) */ #define MAX_JOYSTICKOEMVXDNAME 260 From 9a04c16d326da7b7396936d7415e1ac07e1c83c9 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 16 Nov 2023 21:37:15 -0600 Subject: [PATCH 2750/2777] gdiplus: Round width and height in gdip_format_string(). CW-Bug-Id: #23002 --- dlls/gdiplus/graphics.c | 4 ++-- dlls/gdiplus/tests/graphics.c | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index fca66c8654b..ea6a6ba3874 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -5195,8 +5195,8 @@ GpStatus gdip_format_string(HDC hdc, if (!format) format = &default_drawstring_format; - nwidth = rect->Width; - nheight = rect->Height; + nwidth = (int)(rect->Width + 0.005f); + nheight = (int)(rect->Height + 0.005f); if (ignore_empty_clip) { if (!nwidth) nwidth = INT_MAX; diff --git a/dlls/gdiplus/tests/graphics.c b/dlls/gdiplus/tests/graphics.c index 0ee2b73c413..76d18433f41 100644 --- a/dlls/gdiplus/tests/graphics.c +++ b/dlls/gdiplus/tests/graphics.c @@ -4672,7 +4672,7 @@ static void test_measure_string(void) set_rect_empty(&rect); rect.Height = height; - rect.Width = width_2 - 0.05; + rect.Width = width_2 - 0.006; set_rect_empty(&bounds); status = GdipMeasureString(graphics, string, -1, font, &rect, format, &bounds, &glyphs, &lines); expect(Ok, status); @@ -4683,6 +4683,19 @@ static void test_measure_string(void) expectf_(width_1, bounds.Width, 0.01); expectf(height, bounds.Height); + set_rect_empty(&rect); + rect.Height = height; + rect.Width = width_2 - 0.004; + set_rect_empty(&bounds); + status = GdipMeasureString(graphics, string, -1, font, &rect, format, &bounds, &glyphs, &lines); + expect(Ok, status); + expect(2, glyphs); + expect(1, lines); + expectf(0.0, bounds.X); + expectf(0.0, bounds.Y); + expectf_(width_2, bounds.Width, 0.01); + expectf(height, bounds.Height); + /* Default (Near) alignment */ rect.X = 5.0; rect.Y = 5.0; From 790e189738602cb056423e6e1bb6be4b9dbd64c5 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 17 Nov 2023 09:06:37 -0600 Subject: [PATCH 2751/2777] fixup! wine.inf: Enable builtin amd_ags_x64 for Assassin's Creed Mirage. CW-Bug-Id: #22962 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 90a1ec682c9..4709eb28154 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2855,6 +2855,7 @@ HKCU,Software\Wine\AppDefaults\tll.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\SOPFFO.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\RiftApart.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" HKCU,Software\Wine\AppDefaults\ACMirage.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" +HKCU,Software\Wine\AppDefaults\ACMirage_plus.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" ;;App-specific overrides for atiadlxx.dll. HKCU,Software\Wine\AppDefaults\s2_sp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\s2_mp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" From f000f115c00596fd5a170283acbbe27145c9a82b Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 18 Feb 2023 01:15:01 +0000 Subject: [PATCH 2752/2777] bcryptprimitives: ProcessPrng stub. ProcessPrng is the only publicly documented function exported by bcryptprimitives. This stub simply forwards it to RtlGenRandom in advapi32. (cherry picked from commit 83d4075202ea595f6beb4a39ced54dbabc6a2e21) CW-Bug-Id: #23012 --- configure.ac | 1 + dlls/bcryptprimitives/Makefile.in | 5 ++++ dlls/bcryptprimitives/bcryptprimitives.spec | 1 + dlls/bcryptprimitives/main.c | 27 +++++++++++++++++++++ 4 files changed, 34 insertions(+) create mode 100644 dlls/bcryptprimitives/Makefile.in create mode 100644 dlls/bcryptprimitives/bcryptprimitives.spec create mode 100644 dlls/bcryptprimitives/main.c diff --git a/configure.ac b/configure.ac index 360d4ec5e25..0cf68772deb 100644 --- a/configure.ac +++ b/configure.ac @@ -2442,6 +2442,7 @@ WINE_CONFIG_MAKEFILE(dlls/avifile.dll16,enable_win16) WINE_CONFIG_MAKEFILE(dlls/avrt) WINE_CONFIG_MAKEFILE(dlls/bcrypt) WINE_CONFIG_MAKEFILE(dlls/bcrypt/tests) +WINE_CONFIG_MAKEFILE(dlls/bcryptprimitives) WINE_CONFIG_MAKEFILE(dlls/bluetoothapis) WINE_CONFIG_MAKEFILE(dlls/browseui) WINE_CONFIG_MAKEFILE(dlls/browseui/tests) diff --git a/dlls/bcryptprimitives/Makefile.in b/dlls/bcryptprimitives/Makefile.in new file mode 100644 index 00000000000..537383ba530 --- /dev/null +++ b/dlls/bcryptprimitives/Makefile.in @@ -0,0 +1,5 @@ +MODULE = bcryptprimitives.dll +IMPORTS = advapi32 + +C_SRCS = \ + main.c diff --git a/dlls/bcryptprimitives/bcryptprimitives.spec b/dlls/bcryptprimitives/bcryptprimitives.spec new file mode 100644 index 00000000000..928cb06afcd --- /dev/null +++ b/dlls/bcryptprimitives/bcryptprimitives.spec @@ -0,0 +1 @@ +@ stdcall ProcessPrng(ptr long) diff --git a/dlls/bcryptprimitives/main.c b/dlls/bcryptprimitives/main.c new file mode 100644 index 00000000000..6562d672389 --- /dev/null +++ b/dlls/bcryptprimitives/main.c @@ -0,0 +1,27 @@ +/* + * Copyright 2023 Christopher S. Denton + * + * 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 + */ + +#include +#include "windef.h" +#include "winbase.h" +#include "ntsecapi.h" + +BOOL WINAPI ProcessPrng(BYTE *data, SIZE_T size) +{ + return RtlGenRandom(data, size); +} From bcc1b140acd55bbc3e97db8de5892a517c4443c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 17 Nov 2023 21:28:10 +0100 Subject: [PATCH 2753/2777] evr: Set last presented sample atomically. Fixes a race condition and crashes in Secret of Mana. The queue critical section is held in video_presenter_sample_present while GetCurrentImage only locks the presenter CS. Double locking is tricky and atomic operation is appropriate to swap the sample pointer. CW-Bug-Id: #21713 --- dlls/evr/presenter.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index 2dc01608caf..eed6a84c83d 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -530,12 +530,9 @@ static void video_presenter_sample_present(struct video_presenter *presenter, IM WARN("Failed to get a backbuffer, hr %#lx.\n", hr); } - EnterCriticalSection(&queue->cs); - if (queue->last_presented) - IMFSample_Release(queue->last_presented); - queue->last_presented = sample; - IMFSample_AddRef(queue->last_presented); - LeaveCriticalSection(&queue->cs); + IMFSample_AddRef(sample); + if ((sample = InterlockedExchangePointer((void **)&queue->last_presented, sample))) + IMFSample_Release(sample); IDirect3DSurface9_Release(surface); } @@ -752,6 +749,9 @@ static HRESULT video_presenter_start_streaming(struct video_presenter *presenter static HRESULT video_presenter_end_streaming(struct video_presenter *presenter) { + struct sample_queue *queue = &presenter->thread.queue; + IMFSample *sample; + if (!presenter->thread.hthread) return S_OK; @@ -762,8 +762,9 @@ static HRESULT video_presenter_end_streaming(struct video_presenter *presenter) TRACE("Terminated streaming thread tid %#lx.\n", presenter->thread.tid); - if (presenter->thread.queue.last_presented) - IMFSample_Release(presenter->thread.queue.last_presented); + if ((sample = InterlockedExchangePointer((void **)&queue->last_presented, NULL))) + IMFSample_Release(sample); + video_presenter_sample_queue_free(presenter); memset(&presenter->thread, 0, sizeof(presenter->thread)); video_presenter_set_allocator_callback(presenter, NULL); @@ -1488,6 +1489,7 @@ static HRESULT WINAPI video_presenter_control_GetCurrentImage(IMFVideoDisplayCon BYTE **dib, DWORD *dib_size, LONGLONG *timestamp) { struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface); + struct sample_queue *queue = &presenter->thread.queue; IDirect3DSurface9 *readback = NULL, *surface; D3DSURFACE_DESC surface_desc; D3DLOCKED_RECT mapped_rect; @@ -1500,10 +1502,7 @@ static HRESULT WINAPI video_presenter_control_GetCurrentImage(IMFVideoDisplayCon EnterCriticalSection(&presenter->cs); - sample = presenter->thread.queue.last_presented; - presenter->thread.queue.last_presented = NULL; - - if (!sample) + if (!(sample = InterlockedExchangePointer((void **)&queue->last_presented, NULL))) { hr = MF_E_INVALIDREQUEST; } From cfdebd96a531cb2131cc03fd455a5c764a2928b2 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Tue, 21 Nov 2023 11:25:17 +0200 Subject: [PATCH 2754/2777] fixup! HACK: winegstreamer: Do not report live latency for some games. --- dlls/winegstreamer/h264_decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 6a686b93381..54d5c4f6685 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -119,7 +119,7 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) { const char *sgi; - if ((sgi = getenv("SteamGameId")) && (!strcmp(sgi, "2009100"))) + if ((sgi = getenv("SteamGameId")) && ((!strcmp(sgi, "2009100")) || (!strcmp(sgi, "2555360")))) attrs.low_latency = FALSE; } From ed69f61a8d4b595f82acf7aed4173c587b01655e Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Tue, 21 Nov 2023 11:25:54 +0200 Subject: [PATCH 2755/2777] fixup! HACK: winegstreamer: Don't add unnecessary and slow? videoflip for some games. --- dlls/winegstreamer/wg_transform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index a6df4a4d0e0..b89eb54ff28 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -403,7 +403,7 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_VIDEO: { const char *sgi; - if ((sgi = getenv("SteamGameId")) && (!strcmp(sgi, "2009100"))) + if ((sgi = getenv("SteamGameId")) && ((!strcmp(sgi, "2009100")) || (!strcmp(sgi, "2555360")))) { if (!(element = create_element("videoconvert", "base")) || !append_element(transform->container, element, &first, &last)) From b242e938b8d84d47a066e84a0815a92104533fac Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Tue, 21 Nov 2023 11:26:10 +0200 Subject: [PATCH 2756/2777] fixup! HACK: winegstreamer: Disable MF_SA_D3D11_AWARE for some games. --- dlls/winegstreamer/h264_decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index 54d5c4f6685..c5733c69acb 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -896,7 +896,7 @@ HRESULT h264_decoder_create(REFIID riid, void **ret) { const char *sgi; - if ((sgi = getenv("SteamGameId")) && (!strcmp(sgi, "2009100"))) + if ((sgi = getenv("SteamGameId")) && ((!strcmp(sgi, "2009100")) || (!strcmp(sgi, "2555360")))) IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, FALSE); } From 4b6ba2abe0034a92651b1293c31fc22b3e8456bb Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 17 Nov 2023 16:15:32 -0600 Subject: [PATCH 2757/2777] windowscodecs: Enable WICPixelFormat32bppBGRA in BMP encoder. (cherry picked from commit f27dd7740cdc1290debe1f4806bb7907c54b7847) CW-Bug-Id: #23002 --- dlls/windowscodecs/bmpencode.c | 3 -- dlls/windowscodecs/tests/bmpformat.c | 69 ++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/dlls/windowscodecs/bmpencode.c b/dlls/windowscodecs/bmpencode.c index cd981ee9d3b..80737eff899 100644 --- a/dlls/windowscodecs/bmpencode.c +++ b/dlls/windowscodecs/bmpencode.c @@ -54,10 +54,7 @@ static const struct bmp_pixelformat formats[] = { {&GUID_WICPixelFormat16bppBGR555, 16, 0, BI_RGB}, {&GUID_WICPixelFormat16bppBGR565, 16, 0, BI_BITFIELDS, 0xf800, 0x7e0, 0x1f, 0}, {&GUID_WICPixelFormat32bppBGR, 32, 0, BI_RGB}, -#if 0 - /* Windows doesn't seem to support this one. */ {&GUID_WICPixelFormat32bppBGRA, 32, 0, BI_BITFIELDS, 0xff0000, 0xff00, 0xff, 0xff000000}, -#endif {NULL} }; diff --git a/dlls/windowscodecs/tests/bmpformat.c b/dlls/windowscodecs/tests/bmpformat.c index e21fa1ee035..39a576d6c69 100644 --- a/dlls/windowscodecs/tests/bmpformat.c +++ b/dlls/windowscodecs/tests/bmpformat.c @@ -1263,6 +1263,74 @@ static void test_writesource_palette(void) IWICImagingFactory_Release(factory); } +static void test_encoder_formats(void) +{ + static const struct + { + const GUID *format; + BOOL supported; + const char *name; + } + tests[] = + { + {&GUID_WICPixelFormat24bppBGR, TRUE, "WICPixelFormat24bppBGR"}, + {&GUID_WICPixelFormatBlackWhite, FALSE, "WICPixelFormatBlackWhite"}, + {&GUID_WICPixelFormat1bppIndexed, TRUE, "WICPixelFormat1bppIndexed"}, + {&GUID_WICPixelFormat2bppIndexed, FALSE, "WICPixelFormat2bppIndexed"}, + {&GUID_WICPixelFormat4bppIndexed, TRUE, "WICPixelFormat4bppIndexed"}, + {&GUID_WICPixelFormat8bppIndexed, TRUE, "WICPixelFormat8bppIndexed"}, + {&GUID_WICPixelFormat16bppBGR555, TRUE, "WICPixelFormat16bppBGR555"}, + {&GUID_WICPixelFormat16bppBGR565, TRUE, "WICPixelFormat16bppBGR565"}, + {&GUID_WICPixelFormat32bppBGR, TRUE, "WICPixelFormat32bppBGR"}, + {&GUID_WICPixelFormat32bppBGRA, TRUE, "WICPixelFormat32bppBGRA"}, + {&GUID_WICPixelFormat8bppGray, FALSE, "WICPixelFormat8bppGray"}, + }; + + IWICImagingFactory *factory; + HRESULT hr; + IStream *stream; + IWICBitmapEncoder *encoder; + IWICBitmapFrameEncode *frame_encode; + GUID pixelformat; + LONG refcount; + unsigned int i; + BOOL supported; + + hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, + &IID_IWICImagingFactory, (void **)&factory); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = IWICImagingFactory_CreateEncoder(factory, &GUID_ContainerFormatBmp, &GUID_VendorMicrosoft, &encoder); + ok(hr == S_OK, "got %#lx.\n", hr); + + hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frame_encode, NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IWICBitmapFrameEncode_Initialize(frame_encode, NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context(tests[i].name); + pixelformat = *tests[i].format; + hr = IWICBitmapFrameEncode_SetPixelFormat(frame_encode, &pixelformat); + ok(hr == S_OK, "got %#lx.\n", hr); + supported = !memcmp(&pixelformat, tests[i].format, sizeof(pixelformat)); + ok(supported == tests[i].supported, "got %d.\n", supported); + winetest_pop_context(); + } + + IWICBitmapFrameEncode_Release(frame_encode); + refcount = IWICBitmapEncoder_Release(encoder); + ok(!refcount, "got %ld.\n", refcount); + IStream_Release(stream); + IWICImagingFactory_Release(factory); +} + START_TEST(bmpformat) { CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); @@ -1276,6 +1344,7 @@ START_TEST(bmpformat) test_createfromstream(); test_create_decoder(); test_writesource_palette(); + test_encoder_formats(); CoUninitialize(); } From d8f4c3a734d5bd79f85dd9a1a14c30181758ba33 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 20 Nov 2023 12:27:02 -0600 Subject: [PATCH 2758/2777] msvcp110: Implement std::_Xbad_function_call(). (cherry picked from commit a2d3b27b6c90101729299314da9cae534a3c11ba) CW-Bug-Id: #23002 --- dlls/msvcp110/msvcp110.spec | 2 +- dlls/msvcp120/msvcp120.spec | 2 +- dlls/msvcp120_app/msvcp120_app.spec | 2 +- dlls/msvcp140/msvcp140.spec | 2 +- dlls/msvcp90/exception.c | 50 +++++++++++++++++++++++++++++ dlls/msvcp_win/msvcp_win.spec | 2 +- 6 files changed, 55 insertions(+), 5 deletions(-) diff --git a/dlls/msvcp110/msvcp110.spec b/dlls/msvcp110/msvcp110.spec index 2de95bf94ef..3a9192b3706 100644 --- a/dlls/msvcp110/msvcp110.spec +++ b/dlls/msvcp110/msvcp110.spec @@ -1833,7 +1833,7 @@ @ cdecl ?_XLgamma@std@@YANN@Z(double) std__XLgamma_double @ cdecl ?_XLgamma@std@@YAOO@Z(double) std__XLgamma_double @ cdecl ?_Xbad_alloc@std@@YAXXZ() _Xmem -@ stub ?_Xbad_function_call@std@@YAXXZ +@ cdecl ?_Xbad_function_call@std@@YAXXZ() _Xbad_function_call @ cdecl -arch=win32 ?_Xinvalid_argument@std@@YAXPBD@Z(str) _Xinvalid_argument @ cdecl -arch=win64 ?_Xinvalid_argument@std@@YAXPEBD@Z(str) _Xinvalid_argument @ cdecl -arch=win32 ?_Xlength_error@std@@YAXPBD@Z(str) _Xlength_error diff --git a/dlls/msvcp120/msvcp120.spec b/dlls/msvcp120/msvcp120.spec index e0adc83113f..c720710349d 100644 --- a/dlls/msvcp120/msvcp120.spec +++ b/dlls/msvcp120/msvcp120.spec @@ -1794,7 +1794,7 @@ @ cdecl ?_XLgamma@std@@YANN@Z(double) std__XLgamma_double @ cdecl ?_XLgamma@std@@YAOO@Z(double) std__XLgamma_double @ cdecl ?_Xbad_alloc@std@@YAXXZ() _Xmem -@ stub ?_Xbad_function_call@std@@YAXXZ +@ cdecl ?_Xbad_function_call@std@@YAXXZ() _Xbad_function_call @ cdecl -arch=win32 ?_Xinvalid_argument@std@@YAXPBD@Z(str) _Xinvalid_argument @ cdecl -arch=win64 ?_Xinvalid_argument@std@@YAXPEBD@Z(str) _Xinvalid_argument @ cdecl -arch=win32 ?_Xlength_error@std@@YAXPBD@Z(str) _Xlength_error diff --git a/dlls/msvcp120_app/msvcp120_app.spec b/dlls/msvcp120_app/msvcp120_app.spec index dd8e3ebf173..59b989ba2d9 100644 --- a/dlls/msvcp120_app/msvcp120_app.spec +++ b/dlls/msvcp120_app/msvcp120_app.spec @@ -1794,7 +1794,7 @@ @ cdecl ?_XLgamma@std@@YANN@Z(double) msvcp120.?_XLgamma@std@@YANN@Z @ cdecl ?_XLgamma@std@@YAOO@Z(double) msvcp120.?_XLgamma@std@@YAOO@Z @ cdecl ?_Xbad_alloc@std@@YAXXZ() msvcp120.?_Xbad_alloc@std@@YAXXZ -@ stub ?_Xbad_function_call@std@@YAXXZ +@ cdecl ?_Xbad_function_call@std@@YAXXZ() msvcp120.?_Xbad_function_call@std@@YAXXZ @ cdecl -arch=win32 ?_Xinvalid_argument@std@@YAXPBD@Z(str) msvcp120.?_Xinvalid_argument@std@@YAXPBD@Z @ cdecl -arch=win64 ?_Xinvalid_argument@std@@YAXPEBD@Z(str) msvcp120.?_Xinvalid_argument@std@@YAXPEBD@Z @ cdecl -arch=win32 ?_Xlength_error@std@@YAXPBD@Z(str) msvcp120.?_Xlength_error@std@@YAXPBD@Z diff --git a/dlls/msvcp140/msvcp140.spec b/dlls/msvcp140/msvcp140.spec index dd619c637e1..8b4e44c494d 100644 --- a/dlls/msvcp140/msvcp140.spec +++ b/dlls/msvcp140/msvcp140.spec @@ -1677,7 +1677,7 @@ @ cdecl ?_XLgamma@std@@YANN@Z(double) std__XLgamma_double @ cdecl ?_XLgamma@std@@YAOO@Z(double) std__XLgamma_double @ cdecl ?_Xbad_alloc@std@@YAXXZ() _Xmem -@ stub ?_Xbad_function_call@std@@YAXXZ +@ cdecl ?_Xbad_function_call@std@@YAXXZ() _Xbad_function_call @ cdecl -arch=win32 ?_Xinvalid_argument@std@@YAXPBD@Z(str) _Xinvalid_argument @ cdecl -arch=win64 ?_Xinvalid_argument@std@@YAXPEBD@Z(str) _Xinvalid_argument @ cdecl -arch=win32 ?_Xlength_error@std@@YAXPBD@Z(str) _Xlength_error diff --git a/dlls/msvcp90/exception.c b/dlls/msvcp90/exception.c index 8ceaa91e884..1149cc8ee5d 100644 --- a/dlls/msvcp90/exception.c +++ b/dlls/msvcp90/exception.c @@ -67,6 +67,8 @@ extern const vtable_ptr failure_vtable; extern const vtable_ptr bad_cast_vtable; /* ??_7range_error@std@@6B@ */ extern const vtable_ptr range_error_vtable; +/* ??_7bad_function_call@std@@6B@ */ +extern const vtable_ptr bad_function_call_vtable; /* ??0exception@@QAE@ABQBD@Z */ /* ??0exception@@QEAA@AEBQEBD@Z */ @@ -867,6 +869,33 @@ range_error* __thiscall MSVCP_range_error_assign(range_error *this, const range_ DEFINE_RTTI_DATA2(range_error, 0, &runtime_error_rtti_base_descriptor, &exception_rtti_base_descriptor, ".?AVrange_error@std@@") DEFINE_CXX_DATA2(range_error, &runtime_error_cxx_type_info, &exception_cxx_type_info, MSVCP_runtime_error_dtor) +#if _MSVCP_VER > 90 +/* bad_function_call class data */ +typedef exception bad_function_call; + +static bad_function_call* MSVCP_bad_function_call_ctor(bad_function_call *this) +{ + static const char *name = "bad function call"; + + TRACE("%p\n", this); + MSVCP_exception_ctor(this, EXCEPTION_NAME(name)); + this->vtable = &bad_function_call_vtable; + return this; +} + +DEFINE_THISCALL_WRAPPER(bad_function_call_copy_ctor, 8) +bad_function_call* __thiscall bad_function_call_copy_ctor(bad_function_call *this, const bad_function_call *rhs) +{ + TRACE("%p %p\n", this, rhs); + exception_copy_ctor(this, rhs); + this->vtable = &bad_function_call_vtable; + return this; +} + +DEFINE_RTTI_DATA1(bad_function_call, 0, &exception_rtti_base_descriptor, ".?AVbad_function_call@std@@") +DEFINE_CXX_DATA1(bad_function_call, &exception_cxx_type_info, MSVCP_exception_dtor) +#endif + /* ?_Nomemory@std@@YAXXZ */ void __cdecl DECLSPEC_NORETURN _Nomemory(void) { @@ -941,6 +970,19 @@ void __cdecl DECLSPEC_NORETURN _Xruntime_error(const char *str) _CxxThrowException(&e, &runtime_error_cxx_type); } +#if _MSVCP_VER > 90 +/* ?_Xbad_function_call@std@@YAXXZ() */ +void __cdecl _Xbad_function_call(void) +{ + exception e; + + TRACE("()\n"); + + MSVCP_bad_function_call_ctor(&e); + _CxxThrowException(&e, &bad_function_call_cxx_type); +} +#endif + /* ?uncaught_exception@std@@YA_NXZ */ bool __cdecl MSVCP__uncaught_exception(void) { @@ -1356,6 +1398,9 @@ __ASM_BLOCK_BEGIN(exception_vtables) EXCEPTION_VTABLE(system_error, VTABLE_ADD_FUNC(MSVCP_failure_vector_dtor) VTABLE_ADD_FUNC(MSVCP_failure_what)); + EXCEPTION_VTABLE(bad_function_call, + VTABLE_ADD_FUNC(MSVCP_exception_vector_dtor) + VTABLE_ADD_FUNC(MSVCP_exception_what)); #endif EXCEPTION_VTABLE(failure, VTABLE_ADD_FUNC(MSVCP_failure_vector_dtor) @@ -1366,6 +1411,7 @@ __ASM_BLOCK_BEGIN(exception_vtables) EXCEPTION_VTABLE(range_error, VTABLE_ADD_FUNC(MSVCP_runtime_error_vector_dtor) VTABLE_ADD_FUNC(MSVCP_runtime_error_what)); + __ASM_BLOCK_END /* Internal: throws exception */ @@ -1414,6 +1460,7 @@ void init_exception(void *base) #endif #if _MSVCP_VER > 90 init_system_error_rtti(base); + init_bad_function_call_rtti(base); #endif init_failure_rtti(base); init_bad_cast_rtti(base); @@ -1431,6 +1478,9 @@ void init_exception(void *base) #endif #if _MSVCP_VER > 90 init_system_error_cxx_type_info(base); +#endif +#if _MSVCP_VER > 90 + init_bad_function_call_cxx(base); #endif init_failure_cxx(base); init_range_error_cxx(base); diff --git a/dlls/msvcp_win/msvcp_win.spec b/dlls/msvcp_win/msvcp_win.spec index d2fae9f1e14..975da98631b 100644 --- a/dlls/msvcp_win/msvcp_win.spec +++ b/dlls/msvcp_win/msvcp_win.spec @@ -1677,7 +1677,7 @@ @ cdecl ?_XLgamma@std@@YANN@Z(double) msvcp140.?_XLgamma@std@@YANN@Z @ cdecl ?_XLgamma@std@@YAOO@Z(double) msvcp140.?_XLgamma@std@@YAOO@Z @ cdecl ?_Xbad_alloc@std@@YAXXZ() msvcp140.?_Xbad_alloc@std@@YAXXZ -@ stub ?_Xbad_function_call@std@@YAXXZ +@ cdecl ?_Xbad_function_call@std@@YAXXZ() msvcp140.?_Xbad_function_call@std@@YAXXZ @ cdecl -arch=win32 ?_Xinvalid_argument@std@@YAXPBD@Z(str) msvcp140.?_Xinvalid_argument@std@@YAXPBD@Z @ cdecl -arch=win64 ?_Xinvalid_argument@std@@YAXPEBD@Z(str) msvcp140.?_Xinvalid_argument@std@@YAXPEBD@Z @ cdecl -arch=win32 ?_Xlength_error@std@@YAXPBD@Z(str) msvcp140.?_Xlength_error@std@@YAXPBD@Z From 30c64cfaaaa4640d95089c228a2a85b8157cc298 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 28 Sep 2023 12:35:29 +1000 Subject: [PATCH 2759/2777] d3dx9: Support empty mesh in D3DXLoadMeshHierarchyFromXInMemory(). (cherry picked from commit 21e91690b1688289a3b06951cd2152274998c5ba) CW-Bug-Id: #23002 --- dlls/d3dx9_36/mesh.c | 51 ++++++++++++++++++++++++++++++-------- dlls/d3dx9_36/tests/mesh.c | 43 ++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 10 deletions(-) diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index 47a0cadde67..d380ca61415 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -3506,6 +3506,19 @@ HRESULT WINAPI D3DXLoadSkinMeshFromXof(struct ID3DXFileData *filedata, DWORD opt hr = parse_mesh(filedata, &mesh_data, provide_flags); if (FAILED(hr)) goto cleanup; + if (!mesh_data.num_vertices) + { + if (adjacency_out) + *adjacency_out = NULL; + if (materials_out) + *materials_out = NULL; + if (effects_out) + *effects_out = NULL; + *mesh_out = NULL; + hr = D3D_OK; + goto cleanup; + } + total_vertices = mesh_data.num_vertices; if (mesh_data.fvf & D3DFVF_NORMAL) { /* duplicate vertices with multiple normals */ @@ -3815,12 +3828,15 @@ static HRESULT load_mesh_container(struct ID3DXFileData *filedata, DWORD options hr = filedata_get_name(filedata, &name); if (FAILED(hr)) goto cleanup; - hr = alloc_hier->lpVtbl->CreateMeshContainer(alloc_hier, name, &mesh_data, - materials ? ID3DXBuffer_GetBufferPointer(materials) : NULL, - effects ? ID3DXBuffer_GetBufferPointer(effects) : NULL, - num_materials, - adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL, - skin_info, mesh_container); + if (mesh_data.pMesh) + { + hr = alloc_hier->lpVtbl->CreateMeshContainer(alloc_hier, name, &mesh_data, + materials ? ID3DXBuffer_GetBufferPointer(materials) : NULL, + effects ? ID3DXBuffer_GetBufferPointer(effects) : NULL, + num_materials, + adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL, + skin_info, mesh_container); + } cleanup: if (materials) ID3DXBuffer_Release(materials); @@ -4200,13 +4216,21 @@ static HRESULT parse_frame(struct ID3DXFileData *filedata, DWORD options, struct hr = E_OUTOFMEMORY; goto err; } - list_add_tail(container_list, &container->entry); - container->transform = transform; hr = D3DXLoadSkinMeshFromXof(child, options, device, (provide_flags & PROVIDE_ADJACENCY) ? &container->adjacency : NULL, (provide_flags & PROVIDE_MATERIALS) ? &container->materials : NULL, NULL, &container->num_materials, NULL, &container->mesh); + + if (container->mesh) + { + list_add_tail(container_list, &container->entry); + container->transform = transform; + } + else + { + HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, container); + } } else if (IsEqualGUID(&type, &TID_D3DRMFrameTransformMatrix)) { D3DXMATRIX new_transform; hr = parse_transform_matrix(child, &new_transform); @@ -4294,13 +4318,20 @@ HRESULT WINAPI D3DXLoadMeshFromXInMemory(const void *memory, DWORD memory_size, hr = E_OUTOFMEMORY; goto cleanup; } - list_add_tail(&container_list, &container_ptr->entry); - D3DXMatrixIdentity(&container_ptr->transform); hr = D3DXLoadSkinMeshFromXof(filedata, options, device, (provide_flags & PROVIDE_ADJACENCY) ? &container_ptr->adjacency : NULL, (provide_flags & PROVIDE_MATERIALS) ? &container_ptr->materials : NULL, NULL, &container_ptr->num_materials, NULL, &container_ptr->mesh); + if (container_ptr->mesh) + { + list_add_tail(&container_list, &container_ptr->entry); + D3DXMatrixIdentity(&container_ptr->transform); + } + else + { + HeapFree(GetProcessHeap(), 0, container_ptr); + } } else if (IsEqualGUID(&guid, &TID_D3DRMFrame)) { hr = parse_frame(filedata, options, device, &identity, &container_list, provide_flags); } diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c index c988c368382..97586e1e419 100644 --- a/dlls/d3dx9_36/tests/mesh.c +++ b/dlls/d3dx9_36/tests/mesh.c @@ -2068,6 +2068,14 @@ static void D3DXLoadMeshTest(void) "}" "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 3.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }" "}"; + static const char framed_xfile_empty[] = + "xof 0303txt 0032" + "Frame Box01 {" + " Mesh { 0;; 0;;" + " MeshNormals { 0;; 0;; }" + " }" + "}"; + static const WORD framed_index_buffer[] = { 0, 1, 2 }; static const D3DXVECTOR3 framed_vertex_buffers[3][3] = { {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.0, 0.0}}, @@ -2513,6 +2521,16 @@ static void D3DXLoadMeshTest(void) frame_hier = NULL; } + hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile_empty, sizeof(framed_xfile_empty) - 1, + D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + container = frame_hier->pMeshContainer; + ok(!strcmp(frame_hier->Name, "Box01"), "Unexpected name %s.\n", debugstr_a(frame_hier->Name)); + ok(!container, "Unexpected container %p.\n", container); + + hr = D3DXFrameDestroy(frame_hier, &alloc_hier); + ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); + frame_hier = NULL; hr = D3DXLoadMeshFromXInMemory(NULL, 0, D3DXMESH_MANAGED, device, NULL, NULL, NULL, NULL, &mesh); @@ -11323,6 +11341,9 @@ static void test_load_skin_mesh_from_xof(void) "1;" "3; 0, 1, 2;;" "}"; + static const char simple_xfile_empty[] = + "xof 0303txt 0032" + "Mesh { 0;; 0;; }"; static const D3DVERTEXELEMENT9 expected_declaration[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, @@ -11434,6 +11455,28 @@ static void test_load_skin_mesh_from_xof(void) mesh->lpVtbl->Release(mesh); adjacency->lpVtbl->Release(adjacency); file_data->lpVtbl->Release(file_data); + + /* Empty Mesh Test */ + file_data = get_mesh_data(simple_xfile_empty, sizeof(simple_xfile_empty) - 1); + ok(!!file_data, "Failed to load mesh data.\n"); + + adjacency = materials = effects = (void *)0xdeadbeef; + count = 0xdeadbeefu; + skin_info = (void *)0xdeadbeef; + mesh = (void *)0xdeadbeef; + + hr = D3DXLoadSkinMeshFromXof(file_data, 0, device, &adjacency, &materials, &effects, &count, + &skin_info, &mesh); + todo_wine ok(hr == D3DXERR_LOADEDMESHASNODATA, "Unexpected hr %#lx.\n", hr); + ok(!adjacency, "Unexpected adjacency %p.\n", adjacency); + ok(!materials, "Unexpected materials %p.\n", materials); + ok(!effects, "Unexpected effects %p.\n", effects); + ok(count == 0xdeadbeefu, "Unexpected count %lu.\n", count); + ok(skin_info == (void *)0xdeadbeef, "Unexpected skin_info %p.\n", skin_info); + ok(!mesh, "Unexpected mesh %p.\n", mesh); + + file_data->lpVtbl->Release(file_data); + refcount = IDirect3DDevice9_Release(device); ok(!refcount, "Device has %lu references left.\n", refcount); DestroyWindow(hwnd); From 8e7dfbb43f6a962db7977e74d5d342bbe285f85a Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Fri, 17 Nov 2023 17:27:21 -0600 Subject: [PATCH 2760/2777] d3dx9: Implement D3DXComputeTangent CW-Bug-Id: #23002 --- dlls/d3dx9_24/d3dx9_24.spec | 2 +- dlls/d3dx9_25/d3dx9_25.spec | 2 +- dlls/d3dx9_26/d3dx9_26.spec | 2 +- dlls/d3dx9_27/d3dx9_27.spec | 2 +- dlls/d3dx9_28/d3dx9_28.spec | 2 +- dlls/d3dx9_29/d3dx9_29.spec | 2 +- dlls/d3dx9_30/d3dx9_30.spec | 2 +- dlls/d3dx9_31/d3dx9_31.spec | 2 +- dlls/d3dx9_32/d3dx9_32.spec | 2 +- dlls/d3dx9_33/d3dx9_33.spec | 2 +- dlls/d3dx9_34/d3dx9_34.spec | 2 +- dlls/d3dx9_35/d3dx9_35.spec | 2 +- dlls/d3dx9_36/d3dx9_36.spec | 2 +- dlls/d3dx9_36/mesh.c | 18 ++++++++++++++++++ dlls/d3dx9_37/d3dx9_37.spec | 2 +- dlls/d3dx9_38/d3dx9_38.spec | 2 +- dlls/d3dx9_39/d3dx9_39.spec | 2 +- dlls/d3dx9_40/d3dx9_40.spec | 2 +- dlls/d3dx9_41/d3dx9_41.spec | 2 +- dlls/d3dx9_42/d3dx9_42.spec | 2 +- dlls/d3dx9_43/d3dx9_43.spec | 2 +- 21 files changed, 38 insertions(+), 20 deletions(-) diff --git a/dlls/d3dx9_24/d3dx9_24.spec b/dlls/d3dx9_24/d3dx9_24.spec index 8791e4ec044..b3cb0bf2382 100644 --- a/dlls/d3dx9_24/d3dx9_24.spec +++ b/dlls/d3dx9_24/d3dx9_24.spec @@ -20,7 +20,7 @@ @ stdcall D3DXComputeBoundingSphere(ptr long long ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_25/d3dx9_25.spec b/dlls/d3dx9_25/d3dx9_25.spec index 0431a9f7f75..41e0235c00d 100644 --- a/dlls/d3dx9_25/d3dx9_25.spec +++ b/dlls/d3dx9_25/d3dx9_25.spec @@ -20,7 +20,7 @@ @ stdcall D3DXComputeBoundingSphere(ptr long long ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_26/d3dx9_26.spec b/dlls/d3dx9_26/d3dx9_26.spec index 5ab0a1d9fea..095a0cb4695 100644 --- a/dlls/d3dx9_26/d3dx9_26.spec +++ b/dlls/d3dx9_26/d3dx9_26.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_27/d3dx9_27.spec b/dlls/d3dx9_27/d3dx9_27.spec index 5ab0a1d9fea..095a0cb4695 100644 --- a/dlls/d3dx9_27/d3dx9_27.spec +++ b/dlls/d3dx9_27/d3dx9_27.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_28/d3dx9_28.spec b/dlls/d3dx9_28/d3dx9_28.spec index af5b6077202..bbd47d69fcf 100644 --- a/dlls/d3dx9_28/d3dx9_28.spec +++ b/dlls/d3dx9_28/d3dx9_28.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_29/d3dx9_29.spec b/dlls/d3dx9_29/d3dx9_29.spec index af5b6077202..bbd47d69fcf 100644 --- a/dlls/d3dx9_29/d3dx9_29.spec +++ b/dlls/d3dx9_29/d3dx9_29.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_30/d3dx9_30.spec b/dlls/d3dx9_30/d3dx9_30.spec index af5b6077202..bbd47d69fcf 100644 --- a/dlls/d3dx9_30/d3dx9_30.spec +++ b/dlls/d3dx9_30/d3dx9_30.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_31/d3dx9_31.spec b/dlls/d3dx9_31/d3dx9_31.spec index 8f77dc666a2..1250de7843d 100644 --- a/dlls/d3dx9_31/d3dx9_31.spec +++ b/dlls/d3dx9_31/d3dx9_31.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_32/d3dx9_32.spec b/dlls/d3dx9_32/d3dx9_32.spec index 2fdd2a00615..0691d18995b 100644 --- a/dlls/d3dx9_32/d3dx9_32.spec +++ b/dlls/d3dx9_32/d3dx9_32.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_33/d3dx9_33.spec b/dlls/d3dx9_33/d3dx9_33.spec index 2fdd2a00615..0691d18995b 100644 --- a/dlls/d3dx9_33/d3dx9_33.spec +++ b/dlls/d3dx9_33/d3dx9_33.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_34/d3dx9_34.spec b/dlls/d3dx9_34/d3dx9_34.spec index 2fdd2a00615..0691d18995b 100644 --- a/dlls/d3dx9_34/d3dx9_34.spec +++ b/dlls/d3dx9_34/d3dx9_34.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_35/d3dx9_35.spec b/dlls/d3dx9_35/d3dx9_35.spec index 2fdd2a00615..0691d18995b 100644 --- a/dlls/d3dx9_35/d3dx9_35.spec +++ b/dlls/d3dx9_35/d3dx9_35.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_36/d3dx9_36.spec b/dlls/d3dx9_36/d3dx9_36.spec index 5b7070145de..e2ea5b6cc0c 100644 --- a/dlls/d3dx9_36/d3dx9_36.spec +++ b/dlls/d3dx9_36/d3dx9_36.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index d380ca61415..d024f54ba05 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -7579,6 +7579,24 @@ HRESULT WINAPI D3DXComputeTangentFrameEx(ID3DXMesh *mesh, DWORD texture_in_seman return hr; } +/************************************************************************* + * D3DXComputeTangent (D3DX9_36.@) + */ +HRESULT WINAPI D3DXComputeTangent(ID3DXMesh *mesh, DWORD stage_idx, DWORD tangent_idx, + DWORD binorm_idx, DWORD wrap, const DWORD *adjacency) +{ + TRACE("mesh %p, stage_idx %ld, tangent_idx %ld, binorm_idx %ld, wrap %ld, adjacency %p.\n", + mesh, stage_idx, tangent_idx, binorm_idx, wrap, adjacency); + + return D3DXComputeTangentFrameEx( mesh, D3DDECLUSAGE_TEXCOORD, stage_idx, + ( binorm_idx == D3DX_DEFAULT ) ? D3DX_DEFAULT : D3DDECLUSAGE_BINORMAL, + binorm_idx, + ( tangent_idx == D3DX_DEFAULT ) ? D3DX_DEFAULT : D3DDECLUSAGE_TANGENT, + tangent_idx, D3DX_DEFAULT, 0, + ( wrap ? D3DXTANGENT_WRAP_UV : 0 ) | D3DXTANGENT_GENERATE_IN_PLACE | D3DXTANGENT_ORTHOGONALIZE_FROM_U, + adjacency, -1.01f, -0.01f, -1.01f, NULL, NULL); +} + /************************************************************************* * D3DXComputeNormals (D3DX9_36.@) */ diff --git a/dlls/d3dx9_37/d3dx9_37.spec b/dlls/d3dx9_37/d3dx9_37.spec index 5b7070145de..e2ea5b6cc0c 100644 --- a/dlls/d3dx9_37/d3dx9_37.spec +++ b/dlls/d3dx9_37/d3dx9_37.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_38/d3dx9_38.spec b/dlls/d3dx9_38/d3dx9_38.spec index 5b7070145de..e2ea5b6cc0c 100644 --- a/dlls/d3dx9_38/d3dx9_38.spec +++ b/dlls/d3dx9_38/d3dx9_38.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_39/d3dx9_39.spec b/dlls/d3dx9_39/d3dx9_39.spec index 5b7070145de..e2ea5b6cc0c 100644 --- a/dlls/d3dx9_39/d3dx9_39.spec +++ b/dlls/d3dx9_39/d3dx9_39.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_40/d3dx9_40.spec b/dlls/d3dx9_40/d3dx9_40.spec index 5b7070145de..e2ea5b6cc0c 100644 --- a/dlls/d3dx9_40/d3dx9_40.spec +++ b/dlls/d3dx9_40/d3dx9_40.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_41/d3dx9_41.spec b/dlls/d3dx9_41/d3dx9_41.spec index 5b7070145de..e2ea5b6cc0c 100644 --- a/dlls/d3dx9_41/d3dx9_41.spec +++ b/dlls/d3dx9_41/d3dx9_41.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_42/d3dx9_42.spec b/dlls/d3dx9_42/d3dx9_42.spec index 4a418d1508a..1792886d9ac 100644 --- a/dlls/d3dx9_42/d3dx9_42.spec +++ b/dlls/d3dx9_42/d3dx9_42.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) diff --git a/dlls/d3dx9_43/d3dx9_43.spec b/dlls/d3dx9_43/d3dx9_43.spec index 4a418d1508a..1792886d9ac 100644 --- a/dlls/d3dx9_43/d3dx9_43.spec +++ b/dlls/d3dx9_43/d3dx9_43.spec @@ -24,7 +24,7 @@ @ stub D3DXComputeIMTFromTexture(ptr ptr long long ptr ptr ptr) @ stdcall D3DXComputeNormalMap(ptr ptr ptr long long float) @ stdcall D3DXComputeNormals(ptr ptr) -@ stub D3DXComputeTangent(ptr long long long long ptr) +@ stdcall D3DXComputeTangent(ptr long long long long ptr) @ stub D3DXComputeTangentFrame(ptr long) @ stdcall D3DXComputeTangentFrameEx(ptr long long long long long long long long long ptr float float float ptr ptr) @ stub D3DXConcatenateMeshes(ptr long long ptr ptr ptr ptr ptr) From 74a03fce7f3cadae096996f645337b3895ae3776 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 21 Nov 2023 10:01:08 -0600 Subject: [PATCH 2761/2777] include: Fix ID3DXLoadUserData definition. CW-Bug-Id: #23002 --- include/d3dx9anim.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/d3dx9anim.h b/include/d3dx9anim.h index 81b8e2f6b2c..741ed5a3a56 100644 --- a/include/d3dx9anim.h +++ b/include/d3dx9anim.h @@ -183,9 +183,9 @@ DECLARE_INTERFACE(ID3DXAllocateHierarchy) #define INTERFACE ID3DXLoadUserData DECLARE_INTERFACE(ID3DXLoadUserData) { - STDMETHOD(LoadTopLevelData)(ID3DXFileData *child_data) PURE; - STDMETHOD(LoadFrameChildData)(D3DXFRAME *frame, ID3DXFileData *child_data) PURE; - STDMETHOD(LoadMeshChildData)(D3DXMESHCONTAINER *mesh_container, ID3DXFileData *child_data) PURE; + STDMETHOD(LoadTopLevelData)(ID3DXLoadUserData *user_data, ID3DXFileData *child_data) PURE; + STDMETHOD(LoadFrameChildData)(ID3DXLoadUserData *user_data, D3DXFRAME *frame, ID3DXFileData *child_data) PURE; + STDMETHOD(LoadMeshChildData)(ID3DXLoadUserData *user_data, D3DXMESHCONTAINER *mesh_container, ID3DXFileData *child_data) PURE; }; #undef INTERFACE From 528e12d4fc11b10a6f74dd98582a4802222f9220 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 21 Nov 2023 09:02:32 -0600 Subject: [PATCH 2762/2777] d3dx9/tests: Add test for user data in D3DXLoadMeshHierarchyFromXInMemory(). CW-Bug-Id: #23002 --- dlls/d3dx9_36/tests/mesh.c | 202 ++++++++++++++++++++++++++++++++++++- 1 file changed, 201 insertions(+), 1 deletion(-) diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c index 97586e1e419..aad05217d20 100644 --- a/dlls/d3dx9_36/tests/mesh.c +++ b/dlls/d3dx9_36/tests/mesh.c @@ -2030,6 +2030,132 @@ static void test_LoadMeshFromX_(int line, IDirect3DDevice9 *device, const char * } } +#define MAX_USER_DATA_COUNT 32 +enum user_data_type +{ + USER_DATA_TYPE_TOP, + USER_DATA_TYPE_FRAME_CHILD, + USER_DATA_TYPE_MESH_CHILD, +}; + +struct test_user_data +{ + enum user_data_type data_type; + GUID type; + SIZE_T size; + unsigned int value; + BOOL mesh_container; + unsigned int num_materials; +}; + +struct test_load_user_data +{ + ID3DXLoadUserData iface; + + unsigned int data_count; + struct test_user_data data[MAX_USER_DATA_COUNT]; +}; + +static void record_common_user_data(struct test_load_user_data *data, ID3DXFileData *filedata, + enum user_data_type data_type) +{ + struct test_user_data *d = &data->data[data->data_count]; + const void *ptr; + HRESULT hr; + SIZE_T sz; + + ok(data->data_count < MAX_USER_DATA_COUNT, "got %u.\n", data->data_count); + + d->data_type = data_type; + hr = filedata->lpVtbl->GetType(filedata, &d->type); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = filedata->lpVtbl->Lock(filedata, &sz, &ptr); + ok(hr == S_OK, "got %#lx.\n", hr); + d->size = sz; + ok(sz >= sizeof(int), "got %Iu.\n", sz); + d->value = *(unsigned int *)ptr; + hr = filedata->lpVtbl->Unlock(filedata); + ok(hr == S_OK, "got %#lx.\n", hr); + ++data->data_count; +} + +static struct test_load_user_data *impl_from_ID3DXLoadUserData(ID3DXLoadUserData *iface) +{ + return CONTAINING_RECORD(iface, struct test_load_user_data, iface); +} + +static HRESULT STDMETHODCALLTYPE load_top_level_data(ID3DXLoadUserData *iface, ID3DXFileData *filedata) +{ + struct test_load_user_data *user_data = impl_from_ID3DXLoadUserData(iface); + + record_common_user_data(user_data, filedata, USER_DATA_TYPE_TOP); + return S_OK; +} +static HRESULT STDMETHODCALLTYPE load_frame_child_data(ID3DXLoadUserData *iface, D3DXFRAME *frame, + ID3DXFileData *filedata) +{ + struct test_load_user_data *user_data = impl_from_ID3DXLoadUserData(iface); + + ok(!frame->pFrameSibling, "got %p.\n", frame->pFrameSibling); + ok(!frame->pFrameFirstChild, "got %p.\n", frame->pFrameFirstChild); + + user_data->data[user_data->data_count].mesh_container = !!frame->pMeshContainer; + record_common_user_data(user_data, filedata, USER_DATA_TYPE_FRAME_CHILD); + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE load_mesh_child_data(ID3DXLoadUserData *iface, D3DXMESHCONTAINER *mesh_container, + ID3DXFileData *filedata) +{ + struct test_load_user_data *user_data = impl_from_ID3DXLoadUserData(iface); + + user_data->data[user_data->data_count].num_materials = mesh_container->NumMaterials; + + record_common_user_data(user_data, filedata, USER_DATA_TYPE_MESH_CHILD); + return S_OK; +} + +static const struct ID3DXLoadUserDataVtbl load_user_data_vtbl = +{ + load_top_level_data, + load_frame_child_data, + load_mesh_child_data, +}; + +static void init_load_user_data(struct test_load_user_data *data) +{ + memset(data, 0, sizeof(*data)); + data->iface.lpVtbl = &load_user_data_vtbl; +} + +static void check_user_data(struct test_load_user_data *user_data, unsigned int expected_count, + struct test_user_data *expected) +{ + unsigned int i; + + ok(user_data->data_count == expected_count, "got %u, expected %u.\n", user_data->data_count, expected_count); + expected_count = min(expected_count, user_data->data_count); + for (i = 0; i < expected_count; ++i) + { + winetest_push_context("i %u", i); + ok(user_data->data[i].data_type == expected[i].data_type, "got %u, expected %u.\n", + user_data->data[i].data_type, expected[i].data_type); + ok(IsEqualGUID(&user_data->data[i].type, &expected[i].type), "got %s, expected %s.\n", + debugstr_guid(&user_data->data[i].type), debugstr_guid(&expected[i].type)); + ok(user_data->data[i].size == expected[i].size, "got %Iu, expected %Iu.\n", + user_data->data[i].size, expected[i].size); + ok(user_data->data[i].value == expected[i].value, "got %u, expected %u.\n", + user_data->data[i].value, expected[i].value); + ok(user_data->data[i].mesh_container == expected[i].mesh_container, "got %u, expected %u.\n", + user_data->data[i].mesh_container, expected[i].mesh_container); + ok(user_data->data[i].num_materials == expected[i].num_materials, "got %u, expected %u.\n", + user_data->data[i].num_materials, expected[i].num_materials); + winetest_pop_context(); + } +} + +DEFINE_GUID(TID_TestDataGuid, 0x12345678, 0x1234, 0x1234, 0x12, 0x34, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11); + static void D3DXLoadMeshTest(void) { static const char empty_xfile[] = "xof 0303txt 0032"; @@ -2051,14 +2177,42 @@ static void D3DXLoadMeshTest(void) const DWORD simple_fvf = D3DFVF_XYZ; static const char framed_xfile[] = "xof 0303txt 0032" + "template TestData {" + "<12345678-1234-1234-1234-111111111111>" + "DWORD value;" + "}" + "TestData {" + "1;;" + "}" + "Material {" + /* ColorRGBA faceColor; */ + "0.0; 0.0; 1.0; 1.0;;" + /* FLOAT power; */ + "0.5;" + /* ColorRGB specularColor; */ + "1.0; 1.0; 1.0;;" + /* ColorRGB emissiveColor; */ + "0.0; 0.0; 0.0;;" + "}" + "Frame {" - "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 1.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }" + "TestData {" + "2;;" + "}" + "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 1.0; 1.0; 0.0;; 1; 3; 0, 1, 2;;" + "TestData {" + "3;;" + "}" + "}" "FrameTransformMatrix {" /* translation (0.0, 0.0, 2.0) */ "1.0, 0.0, 0.0, 0.0," "0.0, 1.0, 0.0, 0.0," "0.0, 0.0, 1.0, 0.0," "0.0, 0.0, 2.0, 1.0;;" "}" + "TestData {" + "4;;" + "}" "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 2.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }" "FrameTransformMatrix {" /* translation (0.0, 0.0, 3.0) */ "1.0, 0.0, 0.0, 0.0," @@ -2068,6 +2222,16 @@ static void D3DXLoadMeshTest(void) "}" "Mesh { 3; 0.0; 0.0; 0.0;, 0.0; 1.0; 0.0;, 3.0; 1.0; 0.0;; 1; 3; 0, 1, 2;; }" "}"; + + struct test_user_data framed_xfile_expected_user_data[] = + { + { USER_DATA_TYPE_TOP, TID_TestDataGuid, 4, 1, 0, 0}, + { USER_DATA_TYPE_TOP, TID_D3DRMMaterial, 44, 0, 0, 0}, + { USER_DATA_TYPE_FRAME_CHILD, TID_TestDataGuid, 4, 2, 0, 0}, + { USER_DATA_TYPE_MESH_CHILD, TID_TestDataGuid, 4, 3, 0, 0}, + { USER_DATA_TYPE_FRAME_CHILD, TID_TestDataGuid, 4, 4, 1, 0}, + }; + static const char framed_xfile_empty[] = "xof 0303txt 0032" "Frame Box01 {" @@ -2093,6 +2257,10 @@ static void D3DXLoadMeshTest(void) /*________________________*/ static const char box_xfile[] = "xof 0303txt 0032" + "template TestData {" + "<12345678-1234-1234-1234-111111111111>" + "DWORD value;" + "}" "Mesh {" "8;" /* DWORD nVertices; */ /* array Vector vertices[nVertices]; */ @@ -2130,6 +2298,9 @@ static void D3DXLoadMeshTest(void) "4; 4, 4, 4, 4;," "4; 5, 5, 5, 5;;" "}" + "TestData {" + "1;;" + "}" "MeshMaterialList materials {" "2;" /* DWORD nMaterials; */ "6;" /* DWORD nFaceIndexes; */ @@ -2157,6 +2328,10 @@ static void D3DXLoadMeshTest(void) "TextureFilename { \"texture.jpg\"; }" "}" "}" + "TestData {" + "2;;" + "}" + "MeshVertexColors {" "8;" /* DWORD nVertexColors; */ /* array IndexedColor vertexColors[nVertexColors]; */ @@ -2182,6 +2357,12 @@ static void D3DXLoadMeshTest(void) "0.0; 0.0;;" "}" "}"; + struct test_user_data box_xfile_expected_user_data[] = + { + { USER_DATA_TYPE_MESH_CHILD, TID_TestDataGuid, 4, 1, 0, 2}, + { USER_DATA_TYPE_MESH_CHILD, TID_TestDataGuid, 4, 2, 0, 2}, + }; + static const WORD box_index_buffer[] = { 0, 1, 3, 0, 3, 2, @@ -2391,6 +2572,7 @@ static void D3DXLoadMeshTest(void) D3DXMATRIX transform; struct test_context *test_context; ID3DXAnimationController *controller; + struct test_load_user_data load_user_data; if (!(test_context = new_test_context())) { @@ -2490,6 +2672,20 @@ static void D3DXLoadMeshTest(void) frame_hier = NULL; } + init_load_user_data(&load_user_data); + hr = D3DXLoadMeshHierarchyFromXInMemory(box_xfile, sizeof(box_xfile) - 1, + D3DXMESH_MANAGED, device, &alloc_hier, &load_user_data.iface, &frame_hier, &controller); + todo_wine ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); + if (SUCCEEDED(hr)) + { + winetest_push_context("box_xfile"); + check_user_data(&load_user_data, ARRAY_SIZE(box_xfile_expected_user_data), box_xfile_expected_user_data); + winetest_pop_context(); + hr = D3DXFrameDestroy(frame_hier, &alloc_hier); + ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); + } + frame_hier = NULL; + hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1, D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL); ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); @@ -2520,6 +2716,10 @@ static void D3DXLoadMeshTest(void) ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); frame_hier = NULL; } + ok(container == NULL, "Expected NULL, got %p\n", container); + hr = D3DXFrameDestroy(frame_hier, &alloc_hier); + ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); + frame_hier = NULL; hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile_empty, sizeof(framed_xfile_empty) - 1, D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL); From 7b301f307668b2af37d5160b300209cf5154d5a5 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 21 Nov 2023 14:42:15 -0600 Subject: [PATCH 2763/2777] d3dx9: Implement loading top and frame user data in D3DXLoadMeshHierarchyFromXInMemory(). CW-Bug-Id: #23002 --- dlls/d3dx9_36/mesh.c | 17 ++++++++++------- dlls/d3dx9_36/tests/mesh.c | 34 +++++++++++++++++++++------------- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index d024f54ba05..05e4a6e17e9 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -3880,7 +3880,7 @@ static HRESULT parse_transform_matrix(ID3DXFileData *filedata, D3DXMATRIX *trans } static HRESULT load_frame(struct ID3DXFileData *filedata, DWORD options, struct IDirect3DDevice9 *device, - struct ID3DXAllocateHierarchy *alloc_hier, D3DXFRAME **frame_out) + struct ID3DXAllocateHierarchy *alloc_hier, D3DXFRAME **frame_out, struct ID3DXLoadUserData *load_user_data) { HRESULT hr; GUID type; @@ -3923,9 +3923,12 @@ static HRESULT load_frame(struct ID3DXFileData *filedata, DWORD options, struct } else if (IsEqualGUID(&type, &TID_D3DRMFrameTransformMatrix)) { hr = parse_transform_matrix(child, &frame->TransformationMatrix); } else if (IsEqualGUID(&type, &TID_D3DRMFrame)) { - hr = load_frame(child, options, device, alloc_hier, next_child); + hr = load_frame(child, options, device, alloc_hier, next_child, load_user_data); if (SUCCEEDED(hr)) next_child = &(*next_child)->pFrameSibling; + } else if (load_user_data) { + TRACE("Loading %s as user data.\n", debugstr_guid(&type)); + hr = load_user_data->lpVtbl->LoadFrameChildData(load_user_data, frame, child); } if (FAILED(hr)) goto err; @@ -3961,10 +3964,7 @@ HRESULT WINAPI D3DXLoadMeshHierarchyFromXInMemory(const void *memory, DWORD memo if (!memory || !memory_size || !device || !frame_hierarchy || !alloc_hier) return D3DERR_INVALIDCALL; if (load_user_data) - { - FIXME("Loading user data not implemented.\n"); - return E_NOTIMPL; - } + FIXME("Loading mesh user data not implemented for mesh.\n"); hr = D3DXFileCreate(&d3dxfile); if (FAILED(hr)) goto cleanup; @@ -4001,8 +4001,11 @@ HRESULT WINAPI D3DXLoadMeshHierarchyFromXInMemory(const void *memory, DWORD memo hr = load_mesh_container(filedata, options, device, alloc_hier, &(*next_frame)->pMeshContainer); if (FAILED(hr)) goto cleanup; } else if (IsEqualGUID(&guid, &TID_D3DRMFrame)) { - hr = load_frame(filedata, options, device, alloc_hier, next_frame); + hr = load_frame(filedata, options, device, alloc_hier, next_frame, load_user_data); if (FAILED(hr)) goto cleanup; + } else if (load_user_data) { + TRACE("Loading %s as user data.\n", debugstr_guid(&guid)); + hr = load_user_data->lpVtbl->LoadTopLevelData(load_user_data, filedata); } while (*next_frame) next_frame = &(*next_frame)->pFrameSibling; diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c index aad05217d20..59cef8a6879 100644 --- a/dlls/d3dx9_36/tests/mesh.c +++ b/dlls/d3dx9_36/tests/mesh.c @@ -2133,20 +2133,20 @@ static void check_user_data(struct test_load_user_data *user_data, unsigned int { unsigned int i; - ok(user_data->data_count == expected_count, "got %u, expected %u.\n", user_data->data_count, expected_count); + todo_wine ok(user_data->data_count == expected_count, "got %u, expected %u.\n", user_data->data_count, expected_count); expected_count = min(expected_count, user_data->data_count); for (i = 0; i < expected_count; ++i) { winetest_push_context("i %u", i); - ok(user_data->data[i].data_type == expected[i].data_type, "got %u, expected %u.\n", + todo_wine_if(i == 3) ok(user_data->data[i].data_type == expected[i].data_type, "got %u, expected %u.\n", user_data->data[i].data_type, expected[i].data_type); ok(IsEqualGUID(&user_data->data[i].type, &expected[i].type), "got %s, expected %s.\n", debugstr_guid(&user_data->data[i].type), debugstr_guid(&expected[i].type)); ok(user_data->data[i].size == expected[i].size, "got %Iu, expected %Iu.\n", user_data->data[i].size, expected[i].size); - ok(user_data->data[i].value == expected[i].value, "got %u, expected %u.\n", + todo_wine_if(i == 3) ok(user_data->data[i].value == expected[i].value, "got %u, expected %u.\n", user_data->data[i].value, expected[i].value); - ok(user_data->data[i].mesh_container == expected[i].mesh_container, "got %u, expected %u.\n", + todo_wine_if(i == 3) ok(user_data->data[i].mesh_container == expected[i].mesh_container, "got %u, expected %u.\n", user_data->data[i].mesh_container, expected[i].mesh_container); ok(user_data->data[i].num_materials == expected[i].num_materials, "got %u, expected %u.\n", user_data->data[i].num_materials, expected[i].num_materials); @@ -2675,15 +2675,12 @@ static void D3DXLoadMeshTest(void) init_load_user_data(&load_user_data); hr = D3DXLoadMeshHierarchyFromXInMemory(box_xfile, sizeof(box_xfile) - 1, D3DXMESH_MANAGED, device, &alloc_hier, &load_user_data.iface, &frame_hier, &controller); - todo_wine ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); - if (SUCCEEDED(hr)) - { - winetest_push_context("box_xfile"); - check_user_data(&load_user_data, ARRAY_SIZE(box_xfile_expected_user_data), box_xfile_expected_user_data); - winetest_pop_context(); - hr = D3DXFrameDestroy(frame_hier, &alloc_hier); - ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); - } + ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); + winetest_push_context("box_xfile"); + check_user_data(&load_user_data, ARRAY_SIZE(box_xfile_expected_user_data), box_xfile_expected_user_data); + winetest_pop_context(); + hr = D3DXFrameDestroy(frame_hier, &alloc_hier); + ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); frame_hier = NULL; hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1, @@ -2721,6 +2718,17 @@ static void D3DXLoadMeshTest(void) ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); frame_hier = NULL; + init_load_user_data(&load_user_data); + hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile, sizeof(framed_xfile) - 1, + D3DXMESH_MANAGED, device, &alloc_hier, &load_user_data.iface, &frame_hier, NULL); + ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); + hr = D3DXFrameDestroy(frame_hier, &alloc_hier); + ok(hr == D3D_OK, "Expected D3D_OK, got %#lx\n", hr); + winetest_push_context("framed_xfile"); + check_user_data(&load_user_data, ARRAY_SIZE(framed_xfile_expected_user_data), framed_xfile_expected_user_data); + winetest_pop_context(); + frame_hier = NULL; + hr = D3DXLoadMeshHierarchyFromXInMemory(framed_xfile_empty, sizeof(framed_xfile_empty) - 1, D3DXMESH_MANAGED, device, &alloc_hier, NULL, &frame_hier, NULL); ok(hr == D3D_OK, "Unexpected hr %#lx.\n", hr); From e0f3c313eb337202498eaff4d157d74b873e284b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 21 Nov 2023 15:00:45 -0600 Subject: [PATCH 2764/2777] d3dx9: Unify calling parse_mesh helper functions. CW-Bug-Id: #23002 --- dlls/d3dx9_36/mesh.c | 92 ++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 42 deletions(-) diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index 05e4a6e17e9..ff08b1df5f1 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -37,6 +37,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3dx); +/* for provide_flags parameters */ +#define PROVIDE_MATERIALS 0x1 +#define PROVIDE_SKININFO 0x2 +#define PROVIDE_ADJACENCY 0x4 + struct d3dx9_mesh { ID3DXMesh ID3DXMesh_iface; @@ -2611,6 +2616,7 @@ struct mesh_data { struct ID3DXSkinInfo *skin_info; unsigned int bone_count; + unsigned int skin_weights_info_count; }; static HRESULT parse_texture_filename(ID3DXFileData *filedata, char **filename_out) @@ -2752,7 +2758,7 @@ static void destroy_materials(struct mesh_data *mesh) mesh->material_indices = NULL; } -static HRESULT parse_material_list(ID3DXFileData *filedata, struct mesh_data *mesh) +static HRESULT parse_material_list(ID3DXFileData *filedata, struct mesh_data *mesh, DWORD flags) { ID3DXFileData *child = NULL; unsigned int material_count; @@ -2764,6 +2770,9 @@ static HRESULT parse_material_list(ID3DXFileData *filedata, struct mesh_data *me HRESULT hr; GUID type; + if (!(flags & PROVIDE_MATERIALS)) + return S_OK; + destroy_materials(mesh); hr = filedata->lpVtbl->Lock(filedata, &data_size, &data); @@ -2867,7 +2876,7 @@ static HRESULT parse_material_list(ID3DXFileData *filedata, struct mesh_data *me return hr; } -static HRESULT parse_texture_coords(ID3DXFileData *filedata, struct mesh_data *mesh) +static HRESULT parse_texture_coords(ID3DXFileData *filedata, struct mesh_data *mesh, DWORD flags) { const uint32_t *data; SIZE_T data_size; @@ -2925,7 +2934,7 @@ static HRESULT parse_texture_coords(ID3DXFileData *filedata, struct mesh_data *m return hr; } -static HRESULT parse_vertex_colors(ID3DXFileData *filedata, struct mesh_data *mesh) +static HRESULT parse_vertex_colors(ID3DXFileData *filedata, struct mesh_data *mesh, DWORD flags) { unsigned int color_count, i; const uint32_t *data; @@ -3004,7 +3013,7 @@ static HRESULT parse_vertex_colors(ID3DXFileData *filedata, struct mesh_data *me return hr; } -static HRESULT parse_normals(ID3DXFileData *filedata, struct mesh_data *mesh) +static HRESULT parse_normals(ID3DXFileData *filedata, struct mesh_data *mesh, DWORD flags) { unsigned int num_face_indices = mesh->num_poly_faces * 2 + mesh->num_tri_faces; DWORD *index_out_ptr; @@ -3110,7 +3119,7 @@ static HRESULT parse_normals(ID3DXFileData *filedata, struct mesh_data *mesh) return hr; } -static HRESULT parse_skin_mesh_header(ID3DXFileData *filedata, struct mesh_data *mesh_data) +static HRESULT parse_skin_mesh_header(ID3DXFileData *filedata, struct mesh_data *mesh_data, DWORD flags) { const BYTE *data; SIZE_T data_size; @@ -3118,6 +3127,15 @@ static HRESULT parse_skin_mesh_header(ID3DXFileData *filedata, struct mesh_data TRACE("filedata %p, mesh_data %p.\n", filedata, mesh_data); + if (!(flags & PROVIDE_SKININFO)) + return S_OK; + + if (mesh_data->skin_info) + { + WARN("Skin mesh header already encountered\n"); + return E_FAIL; + } + if (FAILED(hr = filedata->lpVtbl->Lock(filedata, &data_size, (const void **)&data))) return hr; @@ -3136,8 +3154,9 @@ static HRESULT parse_skin_mesh_header(ID3DXFileData *filedata, struct mesh_data return hr; } -static HRESULT parse_skin_weights_info(ID3DXFileData *filedata, struct mesh_data *mesh_data, unsigned int index) +static HRESULT parse_skin_weights_info(ID3DXFileData *filedata, struct mesh_data *mesh_data, DWORD flags) { + unsigned int index = mesh_data->skin_weights_info_count; unsigned int influence_count; const char *name; const BYTE *data; @@ -3146,6 +3165,15 @@ static HRESULT parse_skin_weights_info(ID3DXFileData *filedata, struct mesh_data TRACE("filedata %p, mesh_data %p, index %u.\n", filedata, mesh_data, index); + if (!(flags & PROVIDE_SKININFO)) + return S_OK; + + if (!mesh_data->skin_info) + { + WARN("Skin weights found but skin mesh header not encountered yet.\n"); + return E_FAIL; + } + if (FAILED(hr = filedata->lpVtbl->Lock(filedata, &data_size, (const void **)&data))) return hr; @@ -3173,17 +3201,13 @@ static HRESULT parse_skin_weights_info(ID3DXFileData *filedata, struct mesh_data hr = mesh_data->skin_info->lpVtbl->SetBoneOffsetMatrix(mesh_data->skin_info, index, (const D3DMATRIX *)(data + influence_count * (sizeof(uint32_t) + sizeof(float)))); + if (SUCCEEDED(hr)) + ++mesh_data->skin_weights_info_count; return hr; } -/* for provide_flags parameters */ -#define PROVIDE_MATERIALS 0x1 -#define PROVIDE_SKININFO 0x2 -#define PROVIDE_ADJACENCY 0x4 - static HRESULT parse_mesh(ID3DXFileData *filedata, struct mesh_data *mesh_data, DWORD provide_flags) { - unsigned int skin_weights_info_count = 0; ID3DXFileData *child = NULL; const BYTE *data, *in_ptr; DWORD *index_out_ptr; @@ -3203,6 +3227,8 @@ static HRESULT parse_mesh(ID3DXFileData *filedata, struct mesh_data *mesh_data, * } */ + mesh_data->skin_weights_info_count = 0; + hr = filedata->lpVtbl->Lock(filedata, &data_size, (const void **)&data); if (FAILED(hr)) return hr; @@ -3308,37 +3334,19 @@ static HRESULT parse_mesh(ID3DXFileData *filedata, struct mesh_data *mesh_data, goto end; if (IsEqualGUID(&type, &TID_D3DRMMeshNormals)) { - hr = parse_normals(child, mesh_data); + hr = parse_normals(child, mesh_data, provide_flags); } else if (IsEqualGUID(&type, &TID_D3DRMMeshVertexColors)) { - hr = parse_vertex_colors(child, mesh_data); + hr = parse_vertex_colors(child, mesh_data, provide_flags); } else if (IsEqualGUID(&type, &TID_D3DRMMeshTextureCoords)) { - hr = parse_texture_coords(child, mesh_data); - } else if (IsEqualGUID(&type, &TID_D3DRMMeshMaterialList) && - (provide_flags & PROVIDE_MATERIALS)) - { - hr = parse_material_list(child, mesh_data); - } else if (provide_flags & PROVIDE_SKININFO) { - if (IsEqualGUID(&type, &DXFILEOBJ_XSkinMeshHeader)) { - if (mesh_data->skin_info) { - WARN("Skin mesh header already encountered\n"); - hr = E_FAIL; - goto end; - } - hr = parse_skin_mesh_header(child, mesh_data); - if (FAILED(hr)) - goto end; - } else if (IsEqualGUID(&type, &DXFILEOBJ_SkinWeights)) { - if (!mesh_data->skin_info) { - WARN("Skin weights found but skin mesh header not encountered yet\n"); - hr = E_FAIL; - goto end; - } - hr = parse_skin_weights_info(child, mesh_data, skin_weights_info_count); - if (FAILED(hr)) - goto end; - skin_weights_info_count++; - } + hr = parse_texture_coords(child, mesh_data, provide_flags); + } else if (IsEqualGUID(&type, &TID_D3DRMMeshMaterialList)) { + hr = parse_material_list(child, mesh_data, provide_flags); + } else if (IsEqualGUID(&type, &DXFILEOBJ_XSkinMeshHeader)) { + hr = parse_skin_mesh_header(child, mesh_data, provide_flags); + } else if (IsEqualGUID(&type, &DXFILEOBJ_SkinWeights)) { + hr = parse_skin_weights_info(child, mesh_data, provide_flags); } + if (FAILED(hr)) goto end; @@ -3346,10 +3354,10 @@ static HRESULT parse_mesh(ID3DXFileData *filedata, struct mesh_data *mesh_data, child = NULL; } - if (mesh_data->skin_info && (skin_weights_info_count != mesh_data->bone_count)) + if (mesh_data->skin_info && (mesh_data->skin_weights_info_count != mesh_data->bone_count)) { WARN("Mismatch between skin weights info count %u and bones count %u from skin mesh header.\n", - skin_weights_info_count, mesh_data->bone_count); + mesh_data->skin_weights_info_count, mesh_data->bone_count); hr = E_FAIL; goto end; } From b66053a57f4e8e4216b3b813ce3a6991fafd68e4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 21 Nov 2023 15:09:34 -0600 Subject: [PATCH 2765/2777] d3dx9: Factor out mesh_get_parse_func(). CW-Bug-Id: #23002 --- dlls/d3dx9_36/mesh.c | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index ff08b1df5f1..459c60082c1 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -3206,9 +3206,37 @@ static HRESULT parse_skin_weights_info(ID3DXFileData *filedata, struct mesh_data return hr; } +typedef HRESULT (*mesh_parse_func)(ID3DXFileData *, struct mesh_data *, DWORD); + +static mesh_parse_func mesh_get_parse_func(const GUID *type) +{ + static const struct + { + const GUID *type; + mesh_parse_func func; + } + funcs[] = + { + {&TID_D3DRMMeshNormals, parse_normals}, + {&TID_D3DRMMeshVertexColors, parse_vertex_colors}, + {&TID_D3DRMMeshTextureCoords, parse_texture_coords}, + {&TID_D3DRMMeshMaterialList, parse_material_list}, + {&DXFILEOBJ_XSkinMeshHeader, parse_skin_mesh_header}, + {&DXFILEOBJ_SkinWeights, parse_skin_weights_info}, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(funcs); ++i) + if (IsEqualGUID(type, funcs[i].type)) + return funcs[i].func; + + return NULL; +} + static HRESULT parse_mesh(ID3DXFileData *filedata, struct mesh_data *mesh_data, DWORD provide_flags) { ID3DXFileData *child = NULL; + mesh_parse_func parse_func; const BYTE *data, *in_ptr; DWORD *index_out_ptr; SIZE_T child_count; @@ -3333,20 +3361,8 @@ static HRESULT parse_mesh(ID3DXFileData *filedata, struct mesh_data *mesh_data, if (FAILED(hr)) goto end; - if (IsEqualGUID(&type, &TID_D3DRMMeshNormals)) { - hr = parse_normals(child, mesh_data, provide_flags); - } else if (IsEqualGUID(&type, &TID_D3DRMMeshVertexColors)) { - hr = parse_vertex_colors(child, mesh_data, provide_flags); - } else if (IsEqualGUID(&type, &TID_D3DRMMeshTextureCoords)) { - hr = parse_texture_coords(child, mesh_data, provide_flags); - } else if (IsEqualGUID(&type, &TID_D3DRMMeshMaterialList)) { - hr = parse_material_list(child, mesh_data, provide_flags); - } else if (IsEqualGUID(&type, &DXFILEOBJ_XSkinMeshHeader)) { - hr = parse_skin_mesh_header(child, mesh_data, provide_flags); - } else if (IsEqualGUID(&type, &DXFILEOBJ_SkinWeights)) { - hr = parse_skin_weights_info(child, mesh_data, provide_flags); - } - + if ((parse_func = mesh_get_parse_func(&type))) + hr = parse_func(child, mesh_data, provide_flags); if (FAILED(hr)) goto end; From 314da8d8924e9c2ffa030f1054f35721dd7dba87 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 21 Nov 2023 12:35:35 -0600 Subject: [PATCH 2766/2777] d3dx9: Support loading mesh user data in D3DXLoadMeshHierarchyFromXInMemory(). CW-Bug-Id: #23002 --- dlls/d3dx9_36/mesh.c | 49 ++++++++++++++++++++++++++++---------- dlls/d3dx9_36/tests/mesh.c | 8 +++---- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index 459c60082c1..789ab76532c 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -3830,7 +3830,8 @@ static HRESULT filedata_get_name(ID3DXFileData *filedata, char **name) } static HRESULT load_mesh_container(struct ID3DXFileData *filedata, DWORD options, struct IDirect3DDevice9 *device, - struct ID3DXAllocateHierarchy *alloc_hier, D3DXMESHCONTAINER **mesh_container) + struct ID3DXAllocateHierarchy *alloc_hier, D3DXMESHCONTAINER **mesh_container, + struct ID3DXLoadUserData *load_user_data) { HRESULT hr; ID3DXBuffer *adjacency = NULL; @@ -3840,6 +3841,10 @@ static HRESULT load_mesh_container(struct ID3DXFileData *filedata, DWORD options D3DXMESHDATA mesh_data; DWORD num_materials = 0; char *name = NULL; + SIZE_T child_count; + ID3DXFileData *child = NULL; + GUID type; + unsigned int i; mesh_data.Type = D3DXMESHTYPE_MESH; mesh_data.pMesh = NULL; @@ -3852,17 +3857,38 @@ static HRESULT load_mesh_container(struct ID3DXFileData *filedata, DWORD options hr = filedata_get_name(filedata, &name); if (FAILED(hr)) goto cleanup; - if (mesh_data.pMesh) + if (!mesh_data.pMesh) + goto cleanup; + hr = alloc_hier->lpVtbl->CreateMeshContainer(alloc_hier, name, &mesh_data, + materials ? ID3DXBuffer_GetBufferPointer(materials) : NULL, + effects ? ID3DXBuffer_GetBufferPointer(effects) : NULL, + num_materials, + adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL, + skin_info, mesh_container); + if (FAILED(hr) || !load_user_data) + goto cleanup; + + hr = filedata->lpVtbl->GetChildren(filedata, &child_count); + if (FAILED(hr)) + goto cleanup; + + for (i = 0; i < child_count; i++) { - hr = alloc_hier->lpVtbl->CreateMeshContainer(alloc_hier, name, &mesh_data, - materials ? ID3DXBuffer_GetBufferPointer(materials) : NULL, - effects ? ID3DXBuffer_GetBufferPointer(effects) : NULL, - num_materials, - adjacency ? ID3DXBuffer_GetBufferPointer(adjacency) : NULL, - skin_info, mesh_container); + if (FAILED(hr = filedata->lpVtbl->GetChild(filedata, i, &child))) + goto cleanup; + if (FAILED(hr = child->lpVtbl->GetType(child, &type))) + goto cleanup; + + if (!mesh_get_parse_func(&type) + && FAILED(hr = load_user_data->lpVtbl->LoadMeshChildData(load_user_data, *mesh_container, child))) + goto cleanup; + + IUnknown_Release(child); + child = NULL; } cleanup: + if (child) IUnknown_Release(child); if (materials) ID3DXBuffer_Release(materials); if (effects) ID3DXBuffer_Release(effects); if (adjacency) ID3DXBuffer_Release(adjacency); @@ -3941,7 +3967,7 @@ static HRESULT load_frame(struct ID3DXFileData *filedata, DWORD options, struct goto err; if (IsEqualGUID(&type, &TID_D3DRMMesh)) { - hr = load_mesh_container(child, options, device, alloc_hier, next_container); + hr = load_mesh_container(child, options, device, alloc_hier, next_container, load_user_data); if (SUCCEEDED(hr)) next_container = &(*next_container)->pNextMeshContainer; } else if (IsEqualGUID(&type, &TID_D3DRMFrameTransformMatrix)) { @@ -3987,8 +4013,6 @@ HRESULT WINAPI D3DXLoadMeshHierarchyFromXInMemory(const void *memory, DWORD memo if (!memory || !memory_size || !device || !frame_hierarchy || !alloc_hier) return D3DERR_INVALIDCALL; - if (load_user_data) - FIXME("Loading mesh user data not implemented for mesh.\n"); hr = D3DXFileCreate(&d3dxfile); if (FAILED(hr)) goto cleanup; @@ -4022,7 +4046,8 @@ HRESULT WINAPI D3DXLoadMeshHierarchyFromXInMemory(const void *memory, DWORD memo D3DXMatrixIdentity(&(*next_frame)->TransformationMatrix); - hr = load_mesh_container(filedata, options, device, alloc_hier, &(*next_frame)->pMeshContainer); + hr = load_mesh_container(filedata, options, device, alloc_hier, &(*next_frame)->pMeshContainer, + load_user_data); if (FAILED(hr)) goto cleanup; } else if (IsEqualGUID(&guid, &TID_D3DRMFrame)) { hr = load_frame(filedata, options, device, alloc_hier, next_frame, load_user_data); diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c index 59cef8a6879..d567417145a 100644 --- a/dlls/d3dx9_36/tests/mesh.c +++ b/dlls/d3dx9_36/tests/mesh.c @@ -2133,20 +2133,20 @@ static void check_user_data(struct test_load_user_data *user_data, unsigned int { unsigned int i; - todo_wine ok(user_data->data_count == expected_count, "got %u, expected %u.\n", user_data->data_count, expected_count); + ok(user_data->data_count == expected_count, "got %u, expected %u.\n", user_data->data_count, expected_count); expected_count = min(expected_count, user_data->data_count); for (i = 0; i < expected_count; ++i) { winetest_push_context("i %u", i); - todo_wine_if(i == 3) ok(user_data->data[i].data_type == expected[i].data_type, "got %u, expected %u.\n", + ok(user_data->data[i].data_type == expected[i].data_type, "got %u, expected %u.\n", user_data->data[i].data_type, expected[i].data_type); ok(IsEqualGUID(&user_data->data[i].type, &expected[i].type), "got %s, expected %s.\n", debugstr_guid(&user_data->data[i].type), debugstr_guid(&expected[i].type)); ok(user_data->data[i].size == expected[i].size, "got %Iu, expected %Iu.\n", user_data->data[i].size, expected[i].size); - todo_wine_if(i == 3) ok(user_data->data[i].value == expected[i].value, "got %u, expected %u.\n", + ok(user_data->data[i].value == expected[i].value, "got %u, expected %u.\n", user_data->data[i].value, expected[i].value); - todo_wine_if(i == 3) ok(user_data->data[i].mesh_container == expected[i].mesh_container, "got %u, expected %u.\n", + ok(user_data->data[i].mesh_container == expected[i].mesh_container, "got %u, expected %u.\n", user_data->data[i].mesh_container, expected[i].mesh_container); ok(user_data->data[i].num_materials == expected[i].num_materials, "got %u, expected %u.\n", user_data->data[i].num_materials, expected[i].num_materials); From bd282d2df354a0625a3ab01e39bf69d8414611ae Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 21 Nov 2023 18:06:59 -0600 Subject: [PATCH 2767/2777] ntdll: HACK: Enable fsync_yield_to_waiters for LIGHTNING RETURNS: FFXIII. CW-Bug-Id: #23021 --- dlls/ntdll/unix/loader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index b9b6f66c52f..5500bd75e50 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2351,7 +2351,7 @@ static void hacks_init(void) env_str = getenv("WINE_FSYNC_YIELD_TO_WAITERS"); if (env_str) fsync_yield_to_waiters = !!atoi(env_str); - else if (sgi) fsync_yield_to_waiters = !strcmp(sgi, "292120"); + else if (sgi) fsync_yield_to_waiters = !strcmp(sgi, "292120") || !strcmp(sgi, "345350"); if (fsync_yield_to_waiters) ERR("HACK: fsync: yield to waiters.\n"); From 154ef96f01291644992bbe5058eff3e3d122361d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 23 Nov 2023 14:30:36 -0600 Subject: [PATCH 2768/2777] amd_ags_x64: Add Unix library. CW-Bug-Id: #22976 --- configure.ac | 9 +++++ dlls/amd_ags_x64/Makefile.in | 6 +++- dlls/amd_ags_x64/amd_ags_x64_main.c | 24 +++++++++++++ dlls/amd_ags_x64/unixlib.c | 54 +++++++++++++++++++++++++++++ dlls/amd_ags_x64/unixlib.h | 26 ++++++++++++++ 5 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 dlls/amd_ags_x64/unixlib.c create mode 100644 dlls/amd_ags_x64/unixlib.h diff --git a/configure.ac b/configure.ac index 0cf68772deb..f2dfbb2f2b4 100644 --- a/configure.ac +++ b/configure.ac @@ -1434,6 +1434,15 @@ then [WINE_CHECK_SONAME(gmp,__gmpz_init,,[GMP_CFLAGS=""],[$GMP_LIBS],[[libgmp-*]])])]) fi +dnl **** Check for libdrm **** +WINE_PACKAGE_FLAGS(DRM,[libdrm],,,, + [AC_CHECK_HEADERS([xf86drm.h], + [WINE_CHECK_SONAME(drm,drmOpen,,,[$DRM_LIBS])])]) + +WINE_PACKAGE_FLAGS(DRMAMDGPU,[libdrm_amdgpu],,,, + [AC_CHECK_HEADERS([amdgpu_drm.h], + [WINE_CHECK_SONAME(drm_amdgpu,amdgpu_query_info,,,[$DRMAMDGPU_LIBS])])]) + dnl **** Check for SANE **** if test "x$with_sane" != "xno" then diff --git a/dlls/amd_ags_x64/Makefile.in b/dlls/amd_ags_x64/Makefile.in index 5efcc5e0ffc..e167498caae 100644 --- a/dlls/amd_ags_x64/Makefile.in +++ b/dlls/amd_ags_x64/Makefile.in @@ -1,12 +1,16 @@ EXTRADEFS = -DWINE_NO_LONG_TYPES MODULE = amd_ags_x64.dll +UNIXLIB = amd_ags_x64.so +UNIX_CFLAGS = $(DRM_CFLAGS) +UNIX_LIBS = $(DRM_LIBS) $(DRMAMDGPU_LIBS) IMPORTS = version vulkan-1 user32 IMPORTLIB = amd_ags_x64 EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native C_SRCS = \ - amd_ags_x64_main.c + amd_ags_x64_main.c \ + unixlib.c IDL_SRCS = \ dxvk_interfaces.idl diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 154e74cf1d6..e4abe1abf0c 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -2,8 +2,11 @@ #include #include +#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" +#include "winternl.h" #include "wine/debug.h" #include "wine/heap.h" @@ -21,8 +24,27 @@ #include "amd_ags.h" +#include "unixlib.h" + WINE_DEFAULT_DEBUG_CHANNEL(amd_ags); +#define AMD_AGS_CALL(func, args) WINE_UNIX_CALL( unix_ ## func, args ) + +static INIT_ONCE unix_init_once = INIT_ONCE_STATIC_INIT; +static BOOL unix_lib_initialized; + +static BOOL WINAPI init_unix_lib_once( INIT_ONCE *once, void *param, void **context ) +{ + unix_lib_initialized = !__wine_init_unix_call() && !AMD_AGS_CALL( init, NULL ); + return TRUE; +} + +static BOOL init_unix_lib(void) +{ + InitOnceExecuteOnce( &unix_init_once, init_unix_lib_once, NULL, NULL ); + return unix_lib_initialized; +} + static const char driver_version[] = "23.19.02-230831a-396538C-AMD-Software-Adrenalin-Edition"; static const char radeon_version[] = "23.10.2"; @@ -684,6 +706,8 @@ static AGSReturnCode init_ags_context(AGSContext *context, int ags_version) SET_DEVICE_FIELD(device, deviceId, int, context->version, vk_properties->deviceID); if (vk_properties->vendorID == 0x1002) { + if (!init_unix_lib()) + ERR("Failed to load unix lib.\n"); SET_DEVICE_FIELD(device, architectureVersion, ArchitectureVersion, context->version, ArchitectureVersion_GCN); SET_DEVICE_FIELD(device, asicFamily, AsicFamily, context->version, AsicFamily_GCN4); if (vk_properties->deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) diff --git a/dlls/amd_ags_x64/unixlib.c b/dlls/amd_ags_x64/unixlib.c new file mode 100644 index 00000000000..513c1903e4f --- /dev/null +++ b/dlls/amd_ags_x64/unixlib.c @@ -0,0 +1,54 @@ +/* + * Unix library for amd_ags_x64 functions + * + * Copyright 2023 Paul Gofman 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 + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include +#include +#include + +#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winternl.h" + +#include "wine/debug.h" + +#include "unixlib.h" + +WINE_DEFAULT_DEBUG_CHANNEL(amd_ags); + +static NTSTATUS init( void *args ) +{ + TRACE(".\n"); + return STATUS_SUCCESS; +} + +const unixlib_entry_t __wine_unix_call_funcs[] = +{ + init, +}; diff --git a/dlls/amd_ags_x64/unixlib.h b/dlls/amd_ags_x64/unixlib.h new file mode 100644 index 00000000000..d3427519867 --- /dev/null +++ b/dlls/amd_ags_x64/unixlib.h @@ -0,0 +1,26 @@ +/* + * Unix library interface + * + * Copyright 2023 Paul Gofman 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 + */ + +#include "wine/unixlib.h" + +enum amd_ags_funcs +{ + unix_init, +}; From c7df0b6740c75de1b01854499f2f348d5f5df34d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 23 Nov 2023 15:27:38 -0600 Subject: [PATCH 2769/2777] amd_ags_x64: Load libdrm amdgpu info. CW-Bug-Id: #22976 --- dlls/amd_ags_x64/unixlib.c | 58 +++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/dlls/amd_ags_x64/unixlib.c b/dlls/amd_ags_x64/unixlib.c index 513c1903e4f..47a14a615c8 100644 --- a/dlls/amd_ags_x64/unixlib.c +++ b/dlls/amd_ags_x64/unixlib.c @@ -27,9 +27,13 @@ #include #include #include +#include +#include +#include #include #include +#include #include "ntstatus.h" #define WIN32_NO_STATUS @@ -42,9 +46,61 @@ WINE_DEFAULT_DEBUG_CHANNEL(amd_ags); +#define MAX_DEVICE_COUNT 64 + +static unsigned int device_count; +static struct drm_amdgpu_info_device *amd_info; + static NTSTATUS init( void *args ) { - TRACE(".\n"); + drmDevicePtr devices[MAX_DEVICE_COUNT]; + amdgpu_device_handle h; + uint32_t major, minor; + int i, count, fd, ret; + + device_count = 0; + + if ((count = drmGetDevices(devices, MAX_DEVICE_COUNT)) <= 0) + { + ERR("drmGetDevices failed, err %d.\n", count); + return STATUS_UNSUCCESSFUL; + } + TRACE("Got %d devices.\n", count); + for (i = 0; i < count; ++i) + { + if (!devices[i] || !devices[i]->nodes[DRM_NODE_RENDER]) + { + TRACE("No render node, skipping.\n"); + continue; + } + if ((fd = open(devices[i]->nodes[DRM_NODE_RENDER], O_RDONLY | O_CLOEXEC)) < 0) + { + ERR("Failed to open device %s, errno %d.\n", devices[i]->nodes[DRM_NODE_RENDER], errno); + continue; + } + if ((ret = amdgpu_device_initialize(fd, &major, &minor, &h))) + { + WARN("Failed to initialize amdgpu device bustype %d, %04x:%04x, err %d.\n", devices[i]->bustype, + devices[i]->deviceinfo.pci->vendor_id, devices[i]->deviceinfo.pci->device_id, ret); + close(fd); + continue; + } + amd_info = realloc(amd_info, (device_count + 1) * sizeof(*amd_info)); + if (!(ret = amdgpu_query_info(h, AMDGPU_INFO_DEV_INFO, sizeof(*amd_info), &amd_info[device_count]))) + { + TRACE("Got amdgpu info for device id %04x, family %#x, external_rev %#x, chip_rev %#x.\n", + amd_info[device_count].device_id, amd_info[device_count].family, amd_info[device_count].external_rev, + amd_info[device_count].chip_rev); + ++device_count; + } + else + { + ERR("amdgpu_query_info failed, ret %d.\n", ret); + } + amdgpu_device_deinitialize(h); + close(fd); + } + drmFreeDevices(devices, count); return STATUS_SUCCESS; } From d2baf1bc17ad9a4c3d718b415278a310ac7eecfa Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 23 Nov 2023 15:41:50 -0600 Subject: [PATCH 2770/2777] amd_ags_x64: Try to guess asicFamily from amdgpu info. CW-Bug-Id: #22976 --- dlls/amd_ags_x64/amd_ags_x64_main.c | 42 +++++++---- dlls/amd_ags_x64/unixlib.c | 106 ++++++++++++++++++++++++++++ dlls/amd_ags_x64/unixlib.h | 9 +++ 3 files changed, 142 insertions(+), 15 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index e4abe1abf0c..7a485a6cf61 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -73,21 +73,22 @@ static const struct int patch; unsigned int device_size; unsigned int dx11_returned_params_size; + int max_asicFamily; } amd_ags_info[AMD_AGS_VERSION_COUNT] = { - {5, 0, 5, sizeof(AGSDeviceInfo_511), sizeof(AGSDX11ReturnedParams_511)}, - {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)}, - {6, 1, 0, sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600)}, - {6, 2, 0, sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600)}, + {5, 0, 5, sizeof(AGSDeviceInfo_511), sizeof(AGSDX11ReturnedParams_511), 0}, + {5, 1, 1, sizeof(AGSDeviceInfo_511), sizeof(AGSDX11ReturnedParams_511), 0}, + {5, 2, 0, sizeof(AGSDeviceInfo_520), sizeof(AGSDX11ReturnedParams_520), 0}, + {5, 2, 1, sizeof(AGSDeviceInfo_520), sizeof(AGSDX11ReturnedParams_520), 0}, + {5, 3, 0, sizeof(AGSDeviceInfo_520), sizeof(AGSDX11ReturnedParams_520), 0}, + {5, 4, 0, sizeof(AGSDeviceInfo_540), sizeof(AGSDX11ReturnedParams_520), AsicFamily_RDNA}, + {5, 4, 1, sizeof(AGSDeviceInfo_541), sizeof(AGSDX11ReturnedParams_520), AsicFamily_RDNA}, + {5, 4, 2, sizeof(AGSDeviceInfo_542), sizeof(AGSDX11ReturnedParams_520), AsicFamily_RDNA}, + {6, 0, 0, sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600), AsicFamily_RDNA2}, + {6, 0, 1, sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600), AsicFamily_RDNA2}, + {6, 1, 0, sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600), AsicFamily_RDNA3}, + {6, 2, 0, sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600), AsicFamily_RDNA3}, }; #define DEF_FIELD(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ @@ -706,10 +707,21 @@ static AGSReturnCode init_ags_context(AGSContext *context, int ags_version) SET_DEVICE_FIELD(device, deviceId, int, context->version, vk_properties->deviceID); if (vk_properties->vendorID == 0x1002) { - if (!init_unix_lib()) - ERR("Failed to load unix lib.\n"); + struct get_device_info_params params = + { + .device_id = vk_properties->deviceID, + }; + SET_DEVICE_FIELD(device, architectureVersion, ArchitectureVersion, context->version, ArchitectureVersion_GCN); - SET_DEVICE_FIELD(device, asicFamily, AsicFamily, context->version, AsicFamily_GCN4); + if (init_unix_lib() && !AMD_AGS_CALL(get_device_info, ¶ms)) + { + SET_DEVICE_FIELD(device, asicFamily, AsicFamily, context->version, + min(params.asic_family, amd_ags_info[context->version].max_asicFamily)); + } + else + { + SET_DEVICE_FIELD(device, asicFamily, AsicFamily, context->version, AsicFamily_GCN4); + } if (vk_properties->deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) { if (context->version >= AMD_AGS_VERSION_6_0_0) diff --git a/dlls/amd_ags_x64/unixlib.c b/dlls/amd_ags_x64/unixlib.c index 47a14a615c8..72d2f5d2efb 100644 --- a/dlls/amd_ags_x64/unixlib.c +++ b/dlls/amd_ags_x64/unixlib.c @@ -104,7 +104,113 @@ static NTSTATUS init( void *args ) return STATUS_SUCCESS; } +typedef enum AsicFamily +{ + AsicFamily_Unknown, ///< Unknown architecture, potentially from another IHV. Check \ref AGSDeviceInfo::vendorId + AsicFamily_PreGCN, ///< Pre GCN architecture. + AsicFamily_GCN1, ///< AMD GCN 1 architecture: Oland, Cape Verde, Pitcairn & Tahiti. + AsicFamily_GCN2, ///< AMD GCN 2 architecture: Hawaii & Bonaire. This also includes APUs Kaveri and Carrizo. + AsicFamily_GCN3, ///< AMD GCN 3 architecture: Tonga & Fiji. + AsicFamily_GCN4, ///< AMD GCN 4 architecture: Polaris. + AsicFamily_Vega, ///< AMD Vega architecture, including Raven Ridge (ie AMD Ryzen CPU + AMD Vega GPU). + AsicFamily_RDNA, ///< AMD RDNA architecture + AsicFamily_RDNA2, ///< AMD RDNA2 architecture + AsicFamily_RDNA3, ///< AMD RDNA3 architecture +} AsicFamily; + +/* Constants from Mesa source. */ +#define FAMILY_UNKNOWN 0x00 +#define FAMILY_TN 0x69 /* # 105 / Trinity APUs */ +#define FAMILY_SI 0x6E /* # 110 / Southern Islands: Tahiti, Pitcairn, CapeVerde, Oland, Hainan */ +#define FAMILY_CI 0x78 /* # 120 / Sea Islands: Bonaire, Hawaii */ +#define FAMILY_KV 0x7D /* # 125 / Kaveri APUs: Spectre, Spooky, Kalindi, Godavari */ +#define FAMILY_VI 0x82 /* # 130 / Volcanic Islands: Iceland, Tonga, Fiji */ +#define FAMILY_POLARIS 0x82 /* # 130 / Polaris: 10, 11, 12 */ +#define FAMILY_CZ 0x87 /* # 135 / Carrizo APUs: Carrizo, Stoney */ +#define FAMILY_AI 0x8D /* # 141 / Vega: 10, 20 */ +#define FAMILY_RV 0x8E /* # 142 / Raven */ +#define FAMILY_NV 0x8F /* # 143 / Navi: 10 */ +#define FAMILY_VGH 0x90 /* # 144 / Van Gogh */ +#define FAMILY_NV3 0x91 /* # 145 / Navi: 3x */ +#define FAMILY_RMB 0x92 /* # 146 / Rembrandt */ +#define FAMILY_RPL 0x95 /* # 149 / Raphael */ +#define FAMILY_GFX1103 0x94 +#define FAMILY_GFX1150 0x96 +#define FAMILY_MDN 0x97 /* # 151 / Mendocino */ + +static void fill_device_info(struct drm_amdgpu_info_device *info, struct get_device_info_params *out) +{ + uint32_t erev = info->external_rev; + + out->asic_family = AsicFamily_Unknown; + switch (info->family) + { + case FAMILY_AI: + case FAMILY_RV: + out->asic_family = AsicFamily_Vega; + break; + + /* Treat pre-Polaris cards as Polaris. */ + case FAMILY_CZ: + case FAMILY_SI: + case FAMILY_CI: + case FAMILY_KV: + case FAMILY_POLARIS: + out->asic_family = AsicFamily_GCN4; + break; + + case FAMILY_NV: + if (erev >= 0x01 && erev < 0x28) + out->asic_family = AsicFamily_RDNA; + else if (erev >= 0x28 && erev < 0x50) + out->asic_family = AsicFamily_RDNA2; + break; + + case FAMILY_RMB: + case FAMILY_RPL: + case FAMILY_MDN: + case FAMILY_VGH: + out->asic_family = AsicFamily_RDNA2; + break; + + case FAMILY_NV3: + case FAMILY_GFX1103: + case FAMILY_GFX1150: + out->asic_family = AsicFamily_RDNA3; + break; + } + TRACE("family %u, erev %#x -> asicFamily %d.\n", info->family, erev, out->asic_family); + if (out->asic_family == AsicFamily_Unknown && info->family != FAMILY_UNKNOWN) + { + if (info->family > FAMILY_GFX1150) + out->asic_family = AsicFamily_RDNA3; + else + out->asic_family = AsicFamily_GCN4; + + FIXME("Unrecognized family %u, erev %#x -> defaulting to %d.\n", info->family, erev, + out->asic_family); + } +} + +static NTSTATUS get_device_info( void *args ) +{ + struct get_device_info_params *params = args; + unsigned int i; + + for (i = 0; i < device_count; ++i) + { + if (amd_info[i].device_id != params->device_id) + continue; + TRACE("device %04x found.\n", params->device_id); + fill_device_info(&amd_info[i], params); + return STATUS_SUCCESS; + } + TRACE("Device %04x not found.\n", params->device_id); + return STATUS_NOT_FOUND; +} + const unixlib_entry_t __wine_unix_call_funcs[] = { init, + get_device_info, }; diff --git a/dlls/amd_ags_x64/unixlib.h b/dlls/amd_ags_x64/unixlib.h index d3427519867..c895a0499fc 100644 --- a/dlls/amd_ags_x64/unixlib.h +++ b/dlls/amd_ags_x64/unixlib.h @@ -23,4 +23,13 @@ enum amd_ags_funcs { unix_init, + unix_get_device_info, +}; + +struct get_device_info_params +{ + uint32_t device_id; + uint32_t _pad; + /* Output parameters. */ + uint32_t asic_family; }; From 34aa2bb571a0cddf01b752449b4829e1a76cb755 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 23 Nov 2023 18:11:41 -0600 Subject: [PATCH 2771/2777] amd_ags_x64: Fill more device info fields. CW-Bug-Id: #22976 --- dlls/amd_ags_x64/amd_ags_x64_main.c | 26 +++++++++++++++ dlls/amd_ags_x64/unixlib.c | 51 +++++++++++++++++++++++++++++ dlls/amd_ags_x64/unixlib.h | 7 ++++ 3 files changed, 84 insertions(+) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 7a485a6cf61..a6cc83d6699 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -98,6 +98,10 @@ amd_ags_info[AMD_AGS_VERSION_COUNT] = #define DEF_FIELD_520_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), -1, \ -1, -1, -1, -1, -1, -1}} +#define DEF_FIELD_520_UP(name) {DEVICE_FIELD_##name, {-1, -1, offsetof(AGSDeviceInfo_520, name), \ + offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ + offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name), \ + offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name), offsetof(AGSDeviceInfo_600, name)}} #define DEF_FIELD_540_UP(name) {DEVICE_FIELD_##name, {-1, -1, -1, \ -1, -1, offsetof(AGSDeviceInfo_540, name), \ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name), \ @@ -122,6 +126,14 @@ amd_ags_info[AMD_AGS_VERSION_COUNT] = #define DEVICE_FIELD_displays 8 #define DEVICE_FIELD_isAPU 9 +#define DEVICE_FIELD_numCUs 10 +#define DEVICE_FIELD_coreClock 11 +#define DEVICE_FIELD_memoryClock 12 +#define DEVICE_FIELD_teraFlops 13 +#define DEVICE_FIELD_numWGPs 14 +#define DEVICE_FIELD_numROPs 15 +#define DEVICE_FIELD_memoryBandwidth 16 + static const struct { unsigned int field_index; @@ -139,6 +151,13 @@ device_struct_fields[] = DEF_FIELD(numDisplays), DEF_FIELD(displays), DEF_FIELD_540_600(isAPU), + DEF_FIELD(numCUs), + DEF_FIELD(coreClock), + DEF_FIELD(memoryClock), + DEF_FIELD(teraFlops), + DEF_FIELD_540_UP(numWGPs), + DEF_FIELD_520_UP(numROPs), + DEF_FIELD_520_UP(memoryBandwidth), }; #undef DEF_FIELD @@ -717,6 +736,13 @@ static AGSReturnCode init_ags_context(AGSContext *context, int ags_version) { SET_DEVICE_FIELD(device, asicFamily, AsicFamily, context->version, min(params.asic_family, amd_ags_info[context->version].max_asicFamily)); + SET_DEVICE_FIELD(device, numCUs, int, context->version, params.num_cu); + SET_DEVICE_FIELD(device, numWGPs, int, context->version, params.num_wgp); + SET_DEVICE_FIELD(device, numROPs, int, context->version, params.num_rops); + SET_DEVICE_FIELD(device, coreClock, int, context->version, params.core_clock); + SET_DEVICE_FIELD(device, memoryClock, int, context->version, params.memory_clock); + SET_DEVICE_FIELD(device, memoryBandwidth, int, context->version, params.memory_bandwidth); + SET_DEVICE_FIELD(device, teraFlops, float, context->version, params.teraflops); } else { diff --git a/dlls/amd_ags_x64/unixlib.c b/dlls/amd_ags_x64/unixlib.c index 72d2f5d2efb..479ce8258a5 100644 --- a/dlls/amd_ags_x64/unixlib.c +++ b/dlls/amd_ags_x64/unixlib.c @@ -104,6 +104,42 @@ static NTSTATUS init( void *args ) return STATUS_SUCCESS; } +#ifndef AMDGPU_VRAM_TYPE_DDR5 +# define AMDGPU_VRAM_TYPE_DDR5 10 +#endif +#ifndef AMDGPU_VRAM_TYPE_LPDDR4 +# define AMDGPU_VRAM_TYPE_LPDDR4 11 +#endif +#ifndef AMDGPU_VRAM_TYPE_LPDDR5 +# define AMDGPU_VRAM_TYPE_LPDDR5 12 +#endif + +/* From Mesa source. */ +static uint32_t memory_ops_per_clock(uint32_t vram_type) +{ + /* Based on MemoryOpsPerClockTable from PAL. */ + switch (vram_type) { + case AMDGPU_VRAM_TYPE_GDDR1: + case AMDGPU_VRAM_TYPE_GDDR3: /* last in low-end Evergreen */ + case AMDGPU_VRAM_TYPE_GDDR4: /* last in R7xx, not used much */ + case AMDGPU_VRAM_TYPE_UNKNOWN: + default: + return 0; + case AMDGPU_VRAM_TYPE_DDR2: + case AMDGPU_VRAM_TYPE_DDR3: + case AMDGPU_VRAM_TYPE_DDR4: + case AMDGPU_VRAM_TYPE_LPDDR4: + case AMDGPU_VRAM_TYPE_HBM: /* same for HBM2 and HBM3 */ + return 2; + case AMDGPU_VRAM_TYPE_DDR5: + case AMDGPU_VRAM_TYPE_LPDDR5: + case AMDGPU_VRAM_TYPE_GDDR5: /* last in Polaris and low-end Navi14 */ + return 4; + case AMDGPU_VRAM_TYPE_GDDR6: + return 16; + } +} + typedef enum AsicFamily { AsicFamily_Unknown, ///< Unknown architecture, potentially from another IHV. Check \ref AGSDeviceInfo::vendorId @@ -138,6 +174,8 @@ typedef enum AsicFamily #define FAMILY_GFX1150 0x96 #define FAMILY_MDN 0x97 /* # 151 / Mendocino */ +#define ROUND_DIV(value, div) (((value) + (div) / 2) / (div)) + static void fill_device_info(struct drm_amdgpu_info_device *info, struct get_device_info_params *out) { uint32_t erev = info->external_rev; @@ -190,6 +228,19 @@ static void fill_device_info(struct drm_amdgpu_info_device *info, struct get_dev FIXME("Unrecognized family %u, erev %#x -> defaulting to %d.\n", info->family, erev, out->asic_family); } + + out->num_cu = info->cu_active_number; + out->num_wgp = out->asic_family >= AsicFamily_RDNA ? out->num_cu / 2 : 0; + out->num_rops = info->num_rb_pipes * 4; + TRACE("num_cu %d, num_wgp %d, num_rops %d.\n", out->num_cu, out->num_wgp, out->num_rops); + out->core_clock = ROUND_DIV(info->max_engine_clock, 1000); + out->memory_clock = ROUND_DIV(info->max_memory_clock, 1000); + out->memory_bandwidth = ROUND_DIV(info->max_memory_clock * memory_ops_per_clock(info->vram_type) + * info->vram_bit_width / 8, 1000); + TRACE("core_clock %uMHz, memory_clock %uMHz, memory_bandwidth %u.\n", + out->core_clock, out->memory_clock, out->memory_bandwidth); + out->teraflops = 1e-9f * info->max_engine_clock * info->cu_active_number * 64 * 2; + TRACE("teraflops %.2f.\n", out->teraflops); } static NTSTATUS get_device_info( void *args ) diff --git a/dlls/amd_ags_x64/unixlib.h b/dlls/amd_ags_x64/unixlib.h index c895a0499fc..72422e1535c 100644 --- a/dlls/amd_ags_x64/unixlib.h +++ b/dlls/amd_ags_x64/unixlib.h @@ -32,4 +32,11 @@ struct get_device_info_params uint32_t _pad; /* Output parameters. */ uint32_t asic_family; + uint32_t num_cu; + uint32_t num_wgp; + uint32_t num_rops; + uint32_t core_clock; + uint32_t memory_clock; + uint32_t memory_bandwidth; + float teraflops; }; From a58b925768fd6b21fdd06a9ee924d3139517743d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 23 Nov 2023 18:53:03 -0600 Subject: [PATCH 2772/2777] amd_ags_x64: Downgrade agsCheckDriverVersion() message to WARN. CW-Bug-Id: #22976 --- dlls/amd_ags_x64/amd_ags_x64_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index a6cc83d6699..cbd60af6af3 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -1159,7 +1159,7 @@ AGSReturnCode WINAPI agsDriverExtensionsDX12_DestroyDevice(AGSContext* context, AGSDriverVersionResult WINAPI agsCheckDriverVersion(const char* version_reported, unsigned int version_required) { - FIXME("version_reported %s, version_required %d semi-stub.\n", debugstr_a(version_reported), version_required); + WARN("version_reported %s, version_required %d semi-stub.\n", debugstr_a(version_reported), version_required); return AGS_SOFTWAREVERSIONCHECK_OK; } From 4a69ec68673889c1bf5444051f63577e945a3a69 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Fri, 24 Nov 2023 14:36:47 +0000 Subject: [PATCH 2773/2777] amend! mfmediaengine: Be a bit more conservative with locks in engine Shutdown. mfmediaengine: Be a bit more conservative with locks in engine Shutdown. During engine shutdown we acquire engine lock first, then locks of its constituents (e.g. sample grabbers); whereas normally the order is the other way around (e.g. timer callback -> acquire sample grabber lock -> OnProcessSample callback -> engine lock). This is deadlock prone. With this commit, engine lock is released before we shutdown the inner media session. --- dlls/mfmediaengine/main.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dlls/mfmediaengine/main.c b/dlls/mfmediaengine/main.c index ed9bd75f797..1138a7c9734 100644 --- a/dlls/mfmediaengine/main.c +++ b/dlls/mfmediaengine/main.c @@ -2201,7 +2201,7 @@ static HRESULT WINAPI media_engine_GetVideoAspectRatio(IMFMediaEngineEx *iface, static HRESULT WINAPI media_engine_Shutdown(IMFMediaEngineEx *iface) { struct media_engine *engine = impl_from_IMFMediaEngineEx(iface); - IMFMediaSession *session; + IMFMediaSession *session = NULL; HRESULT hr = S_OK; TRACE("%p.\n", iface); @@ -2218,8 +2218,11 @@ static HRESULT WINAPI media_engine_Shutdown(IMFMediaEngineEx *iface) } LeaveCriticalSection(&engine->cs); - IMFMediaSession_Shutdown(session); - IMFMediaSession_Release(session); + if (SUCCEEDED(hr)) + { + IMFMediaSession_Shutdown(session); + IMFMediaSession_Release(session); + } return hr; } From c724349a01855b82355507ecbadd3bc5b4cfc2ad Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 24 Nov 2023 11:16:34 -0600 Subject: [PATCH 2774/2777] fixup! amd_ags_x64: Load libdrm amdgpu info. CW-Bug-Id: #22976 --- dlls/amd_ags_x64/unixlib.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/amd_ags_x64/unixlib.c b/dlls/amd_ags_x64/unixlib.c index 479ce8258a5..be94b75eab9 100644 --- a/dlls/amd_ags_x64/unixlib.c +++ b/dlls/amd_ags_x64/unixlib.c @@ -86,6 +86,9 @@ static NTSTATUS init( void *args ) continue; } amd_info = realloc(amd_info, (device_count + 1) * sizeof(*amd_info)); + /* amdgpu_query_info() doesn't fail on short buffer (filling in the available buffer size). So older or + * newer DRM version should be fine but zero init the structure to avoid random values. */ + memset(&amd_info[device_count], 0, sizeof(*amd_info)); if (!(ret = amdgpu_query_info(h, AMDGPU_INFO_DEV_INFO, sizeof(*amd_info), &amd_info[device_count]))) { TRACE("Got amdgpu info for device id %04x, family %#x, external_rev %#x, chip_rev %#x.\n", From 92810f4a145b17067a851c3940cee6f04f466fc5 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 24 Nov 2023 11:24:03 -0600 Subject: [PATCH 2775/2777] amd_ags_x64: Workaround zero clock reporting on Vangogh GPU. CW-Bug-Id: #22976 --- dlls/amd_ags_x64/unixlib.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/dlls/amd_ags_x64/unixlib.c b/dlls/amd_ags_x64/unixlib.c index be94b75eab9..7e5bc5bf4d6 100644 --- a/dlls/amd_ags_x64/unixlib.c +++ b/dlls/amd_ags_x64/unixlib.c @@ -182,6 +182,7 @@ typedef enum AsicFamily static void fill_device_info(struct drm_amdgpu_info_device *info, struct get_device_info_params *out) { uint32_t erev = info->external_rev; + uint64_t max_engine_clock_khz, max_memory_clock_khz; out->asic_family = AsicFamily_Unknown; switch (info->family) @@ -236,13 +237,19 @@ static void fill_device_info(struct drm_amdgpu_info_device *info, struct get_dev out->num_wgp = out->asic_family >= AsicFamily_RDNA ? out->num_cu / 2 : 0; out->num_rops = info->num_rb_pipes * 4; TRACE("num_cu %d, num_wgp %d, num_rops %d.\n", out->num_cu, out->num_wgp, out->num_rops); - out->core_clock = ROUND_DIV(info->max_engine_clock, 1000); - out->memory_clock = ROUND_DIV(info->max_memory_clock, 1000); - out->memory_bandwidth = ROUND_DIV(info->max_memory_clock * memory_ops_per_clock(info->vram_type) + /* These numbers are zero on Vangogh, workaround that (similar to how it is currently done + * in Mesa src/amd/common/ac_rgp.c. */ + if (!(max_engine_clock_khz = info->max_engine_clock)) + max_engine_clock_khz = 1300000; + if (!(max_memory_clock_khz = info->max_memory_clock)) + max_memory_clock_khz = 687000; + out->core_clock = ROUND_DIV(max_engine_clock_khz, 1000); + out->memory_clock = ROUND_DIV(max_memory_clock_khz, 1000); + out->memory_bandwidth = ROUND_DIV(max_memory_clock_khz * memory_ops_per_clock(info->vram_type) * info->vram_bit_width / 8, 1000); TRACE("core_clock %uMHz, memory_clock %uMHz, memory_bandwidth %u.\n", out->core_clock, out->memory_clock, out->memory_bandwidth); - out->teraflops = 1e-9f * info->max_engine_clock * info->cu_active_number * 64 * 2; + out->teraflops = 1e-9f * max_engine_clock_khz * info->cu_active_number * 64 * 2; TRACE("teraflops %.2f.\n", out->teraflops); } From 34e4e3bcacbb2682ceb1b9d09553e99e84dc82cf Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 24 Nov 2023 15:39:13 -0600 Subject: [PATCH 2776/2777] setupapi: Add stubs for SetupDiGetCustomDeviceProperty{A|W}(). CW-Bug-Id: #23045 --- dlls/setupapi/devinst.c | 20 ++++++++++++++++++++ dlls/setupapi/setupapi.spec | 2 ++ 2 files changed, 22 insertions(+) diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c index 93d7c849ee5..09928788c8c 100644 --- a/dlls/setupapi/devinst.c +++ b/dlls/setupapi/devinst.c @@ -5368,3 +5368,23 @@ BOOL WINAPI SetupDiInstallDevice(HDEVINFO devinfo, SP_DEVINFO_DATA *device_data) return TRUE; } + +BOOL WINAPI SetupDiGetCustomDevicePropertyA(HDEVINFO devinfo, SP_DEVINFO_DATA *data, const char *name, DWORD flags, + DWORD *reg_type, BYTE *buffer, DWORD bufsize, DWORD *required) +{ + FIXME("devinfo %p, data %p, name %s, flags %#lx, reg_type %p, buffer %p, bufsize %lu, required %p stub.\n", + devinfo, data, debugstr_a(name), flags, reg_type, buffer, bufsize, required); + + SetLastError(ERROR_INVALID_DATA); + return FALSE; +} + +BOOL WINAPI SetupDiGetCustomDevicePropertyW(HDEVINFO devinfo, SP_DEVINFO_DATA *data, const WCHAR *name, DWORD flags, + DWORD *reg_type, BYTE *buffer, DWORD bufsize, DWORD *required) +{ + FIXME("devinfo %p, data %p, name %s, flags %#lx, reg_type %p, buffer %p, bufsize %lu, required %p stub.\n", + devinfo, data, debugstr_w(name), flags, reg_type, buffer, bufsize, required); + + SetLastError(ERROR_INVALID_DATA); + return FALSE; +} diff --git a/dlls/setupapi/setupapi.spec b/dlls/setupapi/setupapi.spec index 7578fb25c9c..4d144fe739b 100644 --- a/dlls/setupapi/setupapi.spec +++ b/dlls/setupapi/setupapi.spec @@ -337,6 +337,8 @@ @ stub SetupDiGetClassInstallParamsA @ stub SetupDiGetClassInstallParamsW @ stdcall SetupDiGetClassRegistryPropertyW(ptr long ptr ptr long ptr wstr ptr) +@ stdcall SetupDiGetCustomDevicePropertyA(ptr ptr str long ptr ptr long ptr) +@ stdcall SetupDiGetCustomDevicePropertyW(ptr ptr wstr long ptr ptr long ptr) @ stub SetupDiGetDeviceInfoListClass @ stdcall SetupDiGetDeviceInfoListDetailA(ptr ptr) @ stdcall SetupDiGetDeviceInfoListDetailW(ptr ptr) From 9d7b32dad459c85bbbd5fb9e447dcd1ad19655d2 Mon Sep 17 00:00:00 2001 From: Tyson Whitehead Date: Sat, 25 Nov 2023 09:48:44 -0500 Subject: [PATCH 2777/2777] winebus.sys: Only apply hidraw disable hacks to hidraw subsystem Due to the location of the if check, PROTON_ENABLE_HIDRAW, SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD, SDL_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT, and SDL_GAMECONTROLLER_IGNORE_DEVICES apply to the input subsystem too. The logged messages are "hidraw %s: deferring %s to a different backend" and "hidraw %s: ignoring %s, in SDL blacklist", so this was probably not intended. It was likely not noticed though as the input subsystem is disabled by default due to commit e69c9b1. Because the input subsystem is disabled by default, this change only affects those who deliberately enabling it by explicity setting "DisableInput" to 0 in their registry). With this change it then works. Without it, they need to also whitelist the devices with PROTON_ENABLE_HIDRAW and remove any /dev/hidrawXX permissions to block the raw subsytem from gabbing the devices first. --- dlls/winebus.sys/bus_udev.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 5da979c6c5a..96b226711fd 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -1701,28 +1701,27 @@ static void udev_add_device(struct udev_device *dev, int fd) memcpy(desc.serialnumber, zeros, sizeof(zeros)); } - if (!is_hidraw_enabled(desc.vid, desc.pid, axes, buttons)) - { - TRACE("hidraw %s: deferring %s to a different backend\n", debugstr_a(devnode), debugstr_device_desc(&desc)); - close(fd); - return; - } - if (is_sdl_blacklisted(desc.vid, desc.pid)) - { - /* this device is blacklisted */ - TRACE("hidraw %s: ignoring %s, in SDL blacklist\n", debugstr_a(devnode), debugstr_device_desc(&desc)); - close(fd); - return; - } #ifdef HAS_PROPER_INPUT_HEADER - else - desc.is_gamepad = (axes == 6 && buttons >= 14); + desc.is_gamepad = (axes == 6 && buttons >= 14); #endif TRACE("dev %p, node %s, desc %s.\n", dev, debugstr_a(devnode), debugstr_device_desc(&desc)); if (strcmp(subsystem, "hidraw") == 0) { + if (!is_hidraw_enabled(desc.vid, desc.pid, axes, buttons)) + { + TRACE("hidraw %s: deferring %s to a different backend\n", debugstr_a(devnode), debugstr_device_desc(&desc)); + close(fd); + return; + } + if (is_sdl_blacklisted(desc.vid, desc.pid)) + { + /* this device is blacklisted */ + TRACE("hidraw %s: ignoring %s, in SDL blacklist\n", debugstr_a(devnode), debugstr_device_desc(&desc)); + close(fd); + return; + } if (!(impl = raw_device_create(&hidraw_device_vtbl, sizeof(struct hidraw_device)))) return; list_add_tail(&device_list, &impl->unix_device.entry); impl->read_report = hidraw_device_read_report;